ldc-1.1.0-beta3-src/0000755000175000017500000000000012776214734012143 5ustar kaikaildc-1.1.0-beta3-src/.clang-tidy0000664000175000017500000000071312776214734014202 0ustar kaikaiChecks: -*,modernize-*,-modernize-redundant-void-arg,google-readability-braces-around-statements,google-explicit-constructor,google-readability-casting,misc-assert-side-effect,misc-assign-operator-signature,misc-inefficient-algorithm,misc-move-constructor-init,misc-non-copyable-objects,misc-sizeof-container,misc-undelegated-constructor,misc-unused-alias-decls,readability-container-size-empty,readability-else-after-return,readability-redundant-string-cstr ldc-1.1.0-beta3-src/ldc2.conf.in0000664000175000017500000000103112776214734014240 0ustar kaikai// This configuration file uses libconfig. // See http://www.hyperrealm.com/libconfig/ for syntax details. // The default group is required default: { // 'switches' holds array of string that are appends to the command line // arguments before they are parsed. switches = [ "-I@RUNTIME_DIR@/src", "-L-L@PROJECT_BINARY_DIR@/../lib@LIB_SUFFIX@", @MULTILIB_ADDITIONAL_PATH@@SHARED_LIBS_RPATH@ "-defaultlib=druntime-ldc", "-debuglib=druntime-ldc-debug"@ADDITIONAL_DEFAULT_LDC_SWITCHES@ ]; }; ldc-1.1.0-beta3-src/CMakeCPack.cmake0000664000175000017500000000061612776214734015034 0ustar kaikai# # Common CPack configuration # set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME}) set(CPACK_PACKAGE_VERSION ${LDC_VERSION}) set(CPACK_PACKAGE_CONTACT "public@dicebot.lv") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LDC: LLVM D Compiler") # # Debian specifics # execute_process(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE) set(CPACK_DEBIAN_PACKAGE_SECTION "devel") ldc-1.1.0-beta3-src/ir/0000775000175000017500000000000012776214734012557 5ustar kaikaildc-1.1.0-beta3-src/ir/irtype.h0000664000175000017500000001127412776214734014251 0ustar kaikai//===-- ir/irtype.h - IrType base and primitive types -----------*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // The types derived from IrType are used to attach LLVM type information and // other codegen metadata (e.g. for vtbl resolution) to frontend Types. // //===----------------------------------------------------------------------===// #ifndef __LDC_IR_IRTYPE_H__ #define __LDC_IR_IRTYPE_H__ #include "ir/irfuncty.h" ////////////////////////////////////////////////////////////////////////////// // forward declarations namespace llvm { class LLVMContext; class Type; } class Type; class IrTypeAggr; class IrTypeArray; class IrTypeBasic; class IrTypeClass; class IrTypeDelegate; class IrTypeFunction; class IrTypePointer; class IrTypeSArray; class IrTypeStruct; class IrTypeVector; ////////////////////////////////////////////////////////////////////////////// /// Code generation state/metadata for D types. The mapping from IrType to /// Type is injective but not surjective. /// /// Derived classes should be created using their static get() methods, which /// makes sure that uniqueness is preserved in the face of forward references. /// /// Note that the get() methods expect the IrType of the passed type/symbol not /// to be set yet. Another option would be to just return the existing IrType /// in such cases. This would bring the API more in line with the llvm::Type /// get() functions. Currently all clients use the DtoType() wrapper anyway /// instead of directly handling IrType instances, so keeping the assertions /// allows us to check for any uniqueness violations that might have slipped /// through. // TODO: Implement the described changes (now that the forward reference // handling logic seems to work correctly) and get rid of the "no-op" DtoType // calls in IrAggr, ... that only exist for their side effect. class IrType { public: virtual ~IrType() = default; /// virtual IrTypeAggr *isAggr() { return nullptr; } /// virtual IrTypeArray *isArray() { return nullptr; } /// virtual IrTypeBasic *isBasic() { return nullptr; } /// virtual IrTypeClass *isClass() { return nullptr; } /// virtual IrTypeDelegate *isDelegate() { return nullptr; } /// virtual IrTypeFunction *isFunction() { return nullptr; } /// virtual IrTypePointer *isPointer() { return nullptr; } /// virtual IrTypeSArray *isSArray() { return nullptr; } /// virtual IrTypeStruct *isStruct() { return nullptr; } /// virtual IrTypeVector *isVector() { return nullptr; } /// Type *getDType() { return dtype; } /// virtual llvm::Type *getLLType() { return type; } /// virtual IrFuncTy &getIrFuncTy(); protected: /// IrType(Type *dt, llvm::Type *lt); /// Type *dtype = nullptr; /// LLVM type. llvm::Type *type = nullptr; }; ////////////////////////////////////////////////////////////////////////////// /// IrType for basic D types. class IrTypeBasic : public IrType { public: /// static IrTypeBasic *get(Type *dt); /// IrTypeBasic *isBasic() override { return this; } protected: /// explicit IrTypeBasic(Type *dt); /// static llvm::Type *getComplexType(llvm::LLVMContext &ctx, llvm::Type *type); /// static llvm::Type *basic2llvm(Type *t); }; ////////////////////////////////////////////////////////////////////////////// /// IrType from pointers. class IrTypePointer : public IrType { public: /// static IrTypePointer *get(Type *dt); /// IrTypePointer *isPointer() override { return this; } protected: /// IrTypePointer(Type *dt, llvm::Type *lt); }; ////////////////////////////////////////////////////////////////////////////// /// IrType for static arrays class IrTypeSArray : public IrType { public: /// static IrTypeSArray *get(Type *dt); /// IrTypeSArray *isSArray() override { return this; } protected: /// IrTypeSArray(Type *dt, LLType *lt); }; ////////////////////////////////////////////////////////////////////////////// /// IrType for dynamic arrays class IrTypeArray : public IrType { public: /// static IrTypeArray *get(Type *dt); /// IrTypeArray *isArray() override { return this; } protected: /// IrTypeArray(Type *dt, llvm::Type *lt); }; ////////////////////////////////////////////////////////////////////////////// /// IrType for vectors class IrTypeVector : public IrType { public: /// static IrTypeVector *get(Type *dt); /// IrTypeVector *isVector() override { return this; } protected: /// explicit IrTypeVector(Type *dt, llvm::Type *lt); static llvm::Type *vector2llvm(Type *dt); }; #endif ldc-1.1.0-beta3-src/ir/irmodule.h0000664000175000017500000000230712776214734014552 0ustar kaikai//===-- ir/irmodule.h - Codegen state for top-level D modules ---*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Represents the state of a D module on its way through code generation. // //===----------------------------------------------------------------------===// #ifndef LDC_IR_IRMODULE_H #define LDC_IR_IRMODULE_H #include class FuncDeclaration; class VarDeclaration; class Module; namespace llvm { class GlobalVariable; } struct IrModule { IrModule(Module *module); virtual ~IrModule() = default; Module *const M = nullptr; llvm::GlobalVariable *moduleInfoSymbol(); // static ctors/dtors/unittests using FuncDeclList = std::list; using GatesList = std::list; FuncDeclList ctors; FuncDeclList dtors; FuncDeclList sharedCtors; FuncDeclList sharedDtors; GatesList gates; GatesList sharedGates; FuncDeclList unitTests; private: llvm::GlobalVariable *moduleInfoVar = nullptr; }; IrModule *getIrModule(Module *m); #endif ldc-1.1.0-beta3-src/ir/irdsymbol.h0000664000175000017500000000467312776214734014746 0ustar kaikai//===-- ir/irdsymbol.h - Codegen state for D symbols ------------*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Represents the status of a D symbol on its way though the codegen process. // //===----------------------------------------------------------------------===// #ifndef LDC_IR_IRDSYMBOL_H #define LDC_IR_IRDSYMBOL_H #include struct IrModule; struct IrFunction; struct IrAggr; struct IrGlobal; struct IrLocal; struct IrParameter; struct IrField; struct IrVar; class Dsymbol; class AggregateDeclaration; class FuncDeclaration; class VarDeclaration; class Module; namespace llvm { class Value; } struct IrDsymbol { enum Type { NotSet, ModuleType, AggrType, FuncType, GlobalType, LocalType, ParamterType, FieldType }; enum State { Initial, Resolved, Declared, Initialized, Defined }; static std::vector list; static void resetAll(); // overload all of these to make sure // the static list is up to date IrDsymbol(); IrDsymbol(const IrDsymbol &s); ~IrDsymbol(); void reset(); Type type() const { return m_type; } State state() const { return m_state; } bool isResolved() const { return m_state >= Resolved; } bool isDeclared() const { return m_state >= Declared; } bool isInitialized() const { return m_state >= Initialized; } bool isDefined() const { return m_state >= Defined; } void setResolved(); void setDeclared(); void setInitialized(); void setDefined(); private: friend IrModule *getIrModule(Module *m); friend IrAggr *getIrAggr(AggregateDeclaration *decl, bool create); friend IrFunction *getIrFunc(FuncDeclaration *decl, bool create); friend IrVar *getIrVar(VarDeclaration *decl); friend IrGlobal *getIrGlobal(VarDeclaration *decl, bool create); friend IrLocal *getIrLocal(VarDeclaration *decl, bool create); friend IrParameter *getIrParameter(VarDeclaration *decl, bool create); friend IrField *getIrField(VarDeclaration *decl, bool create); union { void *irData; IrModule *irModule; IrAggr *irAggr; IrFunction *irFunc; IrVar *irVar; IrGlobal *irGlobal; IrLocal *irLocal; IrParameter *irParam; IrField *irField; }; Type m_type = Type::NotSet; State m_state = State::Initial; }; #endif ldc-1.1.0-beta3-src/ir/irtypestruct.cpp0000664000175000017500000000347112776214734016051 0ustar kaikai//===-- irtypestruct.cpp --------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "ir/irtypestruct.h" #include "llvm/IR/DerivedTypes.h" #include "aggregate.h" #include "declaration.h" #include "init.h" #include "mtype.h" #include "gen/irstate.h" #include "gen/tollvm.h" #include "gen/logger.h" #include "gen/llvmhelpers.h" ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// IrTypeStruct::IrTypeStruct(StructDeclaration *sd) : IrTypeAggr(sd), sd(sd), ts(static_cast(sd->type)) {} ////////////////////////////////////////////////////////////////////////////// IrTypeStruct *IrTypeStruct::get(StructDeclaration *sd) { auto t = new IrTypeStruct(sd); sd->type->ctype = t; IF_LOG Logger::println("Building struct type %s @ %s", sd->toPrettyChars(), sd->loc.toChars()); LOG_SCOPE; // if it's a forward declaration, all bets are off, stick with the opaque if (sd->sizeok != SIZEOKdone) { return t; } t->packed = sd->alignment == 1; if (!t->packed) { // Unfortunately, the previous check is not enough in case the struct // contains an align declaration. See issue 726. t->packed = isPacked(sd); } AggrTypeBuilder builder(t->packed); builder.addAggregate(sd); builder.addTailPadding(sd->structsize); isaStruct(t->type)->setBody(builder.defaultTypes(), t->packed); t->varGEPIndices = builder.varGEPIndices(); IF_LOG Logger::cout() << "final struct type: " << *t->type << std::endl; return t; } ldc-1.1.0-beta3-src/ir/irtypeaggr.h0000664000175000017500000000567612776214734015123 0ustar kaikai//===-- ir/irtypeaggr.h - IrType subclasses for aggregates ------*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #ifndef LDC_IR_IRTYPEAGGR_H #define LDC_IR_IRTYPEAGGR_H #include "ir/irtype.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/IR/DebugInfo.h" #include #include namespace llvm { class Constant; class StructType; } class AggregateDeclaration; class VarDeclaration; using VarGEPIndices = std::map; class AggrTypeBuilder { public: explicit AggrTypeBuilder(bool packed); void addType(llvm::Type *type, unsigned size); void addAggregate(AggregateDeclaration *ad); void alignCurrentOffset(unsigned alignment); void addTailPadding(unsigned aggregateSize); unsigned currentFieldIndex() const { return m_fieldIndex; } std::vector defaultTypes() const { return m_defaultTypes; } VarGEPIndices varGEPIndices() const { return m_varGEPIndices; } unsigned overallAlignment() const { return m_overallAlignment; } protected: std::vector m_defaultTypes; VarGEPIndices m_varGEPIndices; unsigned m_offset = 0; unsigned m_fieldIndex = 0; unsigned m_overallAlignment = 0; bool m_packed = false; }; /// Base class of IrTypes for aggregate types. class IrTypeAggr : public IrType { public: /// IrTypeAggr *isAggr() override { return this; } /// Returns the index of the field in the LLVM struct type that corresponds /// to the given member variable, plus the offset to the actual field start /// due to overlapping (union) fields, if any. void getMemberLocation(VarDeclaration *var, unsigned &fieldIndex, unsigned &byteOffset) const; /// Composite type debug description. This is not only to cache, but also /// used for resolving forward references. #if LDC_LLVM_VER >= 307 llvm::DIType *diCompositeType = nullptr; #else llvm::DIType diCompositeType; #endif /// true, if the LLVM struct type for the aggregate is declared as packed bool packed = false; protected: /// explicit IrTypeAggr(AggregateDeclaration *ad); /// Returns true, if the LLVM struct type for the aggregate must be declared /// as packed. static bool isPacked(AggregateDeclaration *ad); /// AggregateDeclaration this type represents. AggregateDeclaration *aggr = nullptr; /// Stores the mapping from member variables to field indices in the actual /// LLVM type. If a member variable is not present, this means that it does /// not resolve to a "clean" GEP but extra offsetting due to overlapping /// members is needed (i.e., a union). /// /// We need to keep track of this separately, because there is no way to get /// the field index of a variable in the frontend, it only stores the byte /// offset. VarGEPIndices varGEPIndices; }; #endif ldc-1.1.0-beta3-src/ir/irdsymbol.cpp0000664000175000017500000000335212776214734015272 0ustar kaikai//===-- irdsymbol.cpp -----------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "gen/llvm.h" #include "gen/logger.h" #include "ir/irdsymbol.h" #include "ir/irvar.h" // Callbacks for constructing/destructing Dsymbol.ir member. void* newIrDsymbol() { return static_cast(new IrDsymbol()); } void deleteIrDsymbol(void* sym) { delete static_cast(sym); } std::vector IrDsymbol::list; void IrDsymbol::resetAll() { Logger::println("resetting %llu Dsymbols", static_cast(list.size())); for (auto s : list) { s->reset(); } } IrDsymbol::IrDsymbol() : irData(nullptr) { list.push_back(this); } IrDsymbol::IrDsymbol(const IrDsymbol &s) { list.push_back(this); irData = s.irData; m_type = s.m_type; m_state = s.m_state; } IrDsymbol::~IrDsymbol() { if (this == list.back()) { list.pop_back(); return; } auto it = std::find(list.rbegin(), list.rend(), this).base(); // base() returns the iterator _after_ the found position list.erase(--it); } void IrDsymbol::reset() { irData = nullptr; m_type = Type::NotSet; m_state = State::Initial; } void IrDsymbol::setResolved() { if (m_state < Resolved) { m_state = Resolved; } } void IrDsymbol::setDeclared() { if (m_state < Declared) { m_state = Declared; } } void IrDsymbol::setInitialized() { if (m_state < Initialized) { m_state = Initialized; } } void IrDsymbol::setDefined() { if (m_state < Defined) { m_state = Defined; } } ldc-1.1.0-beta3-src/ir/irtypeclass.cpp0000664000175000017500000001542712776214734015636 0ustar kaikai//===-- irtypeclass.cpp ---------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "llvm/IR/DerivedTypes.h" #include "aggregate.h" #include "declaration.h" #include "dsymbol.h" #include "mtype.h" #include "target.h" #include "template.h" #include "gen/irstate.h" #include "gen/logger.h" #include "gen/tollvm.h" #include "gen/llvmhelpers.h" #include "gen/functions.h" #include "ir/irtypeclass.h" IrTypeClass::IrTypeClass(ClassDeclaration *cd) : IrTypeAggr(cd), cd(cd), tc(static_cast(cd->type)) { std::string vtbl_name(cd->toPrettyChars()); vtbl_name.append(".__vtbl"); vtbl_type = LLStructType::create(gIR->context(), vtbl_name); vtbl_size = cd->vtbl.dim; } void IrTypeClass::addClassData(AggrTypeBuilder &builder, ClassDeclaration *currCd) { // First, recursively add the fields for our base class and interfaces, if // any. if (currCd->baseClass) { addClassData(builder, currCd->baseClass); } if (currCd->vtblInterfaces && currCd->vtblInterfaces->dim > 0) { // KLUDGE: The first pointer in the vtbl will be of type object.Interface; // extract that from the "well-known" object.TypeInfo_Class definition. // For C++ interfaces, this vtbl entry has to be omitted const auto interfaceArrayType = Type::typeinfoclass->fields[3]->type; const auto interfacePtrType = interfaceArrayType->nextOf()->pointerTo(); builder.alignCurrentOffset(Target::ptrsize); for (auto b : *currCd->vtblInterfaces) { IF_LOG Logger::println("Adding interface vtbl for %s", b->sym->toPrettyChars()); FuncDeclarations arr; b->fillVtbl(cd, &arr, currCd == cd); // add to the interface map addInterfaceToMap(b->sym, builder.currentFieldIndex()); Type* first = b->sym->isCPPinterface() ? nullptr : interfacePtrType; const auto ivtblType = llvm::StructType::get(gIR->context(), buildVtblType(first, &arr)); builder.addType(llvm::PointerType::get(ivtblType, 0), Target::ptrsize); ++num_interface_vtbls; } } // Finally, the data members for this class. builder.addAggregate(currCd); } IrTypeClass *IrTypeClass::get(ClassDeclaration *cd) { const auto t = new IrTypeClass(cd); cd->type->ctype = t; IF_LOG Logger::println("Building class type %s @ %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; IF_LOG Logger::println("Instance size: %u", cd->structsize); // This class may contain an align declaration. See GitHub #726. t->packed = false; for (auto base = cd; base != nullptr && !t->packed; base = base->baseClass) { t->packed = isPacked(base); } AggrTypeBuilder builder(t->packed); // add vtbl builder.addType(llvm::PointerType::get(t->vtbl_type, 0), Target::ptrsize); if (cd->isInterfaceDeclaration()) { // interfaces are just a vtable t->num_interface_vtbls = cd->vtblInterfaces ? cd->vtblInterfaces->dim : 0; } else { // classes have monitor and fields if (!cd->isCPPclass() && !cd->isCPPinterface()) { // add monitor builder.addType( llvm::PointerType::get(llvm::Type::getInt8Ty(gIR->context()), 0), Target::ptrsize); } // add data members recursively t->addClassData(builder, cd); // add tail padding builder.addTailPadding(cd->structsize); } if (global.errors) { fatal(); } // set struct body and copy GEP indices isaStruct(t->type)->setBody(builder.defaultTypes(), t->packed); t->varGEPIndices = builder.varGEPIndices(); // set vtbl type body FuncDeclarations vtbl; vtbl.reserve(cd->vtbl.dim); if (!cd->isCPPclass()) vtbl.push(nullptr); for (size_t i = cd->vtblOffset(); i < cd->vtbl.dim; ++i) { FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration(); assert(fd); vtbl.push(fd); } Type* first = cd->isCPPclass() ? nullptr : Type::typeinfoclass->type; t->vtbl_type->setBody(t->buildVtblType(first, &vtbl)); IF_LOG Logger::cout() << "class type: " << *t->type << std::endl; return t; } std::vector IrTypeClass::buildVtblType(Type *first, FuncDeclarations *vtbl_array) { IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars()); LOG_SCOPE; std::vector types; types.reserve(vtbl_array->dim); auto I = vtbl_array->begin(); // first comes the classinfo for D interfaces if (first) { types.push_back(DtoType(first)); ++I; } // then come the functions for (auto E = vtbl_array->end(); I != E; ++I) { FuncDeclaration *fd = *I; if (fd == nullptr) { // FIXME: This stems from the ancient D1 days – can it still happen? types.push_back(getVoidPtrType()); continue; } IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); // If inferring return type and semantic3 has not been run, do it now. // This pops up in some other places in the frontend as well, however // it is probably a bug that it still occurs that late. if (!fd->type->nextOf() && fd->inferRetType) { Logger::println("Running late functionSemantic to infer return type."); TemplateInstance *spec = fd->isSpeculative(); unsigned int olderrs = global.errors; fd->functionSemantic(); if (spec && global.errors != olderrs) { spec->errors = global.errors - olderrs; } } if (!fd->type->nextOf()) { // Return type of the function has not been inferred. This seems to // happen with virtual functions and is probably a frontend bug. IF_LOG Logger::println("Broken function type, semanticRun: %d", fd->semanticRun); types.push_back(getVoidPtrType()); continue; } types.push_back(getPtrToType(DtoFunctionType(fd))); } return types; } llvm::Type *IrTypeClass::getLLType() { return llvm::PointerType::get(type, 0); } llvm::Type *IrTypeClass::getMemoryLLType() { return type; } size_t IrTypeClass::getInterfaceIndex(ClassDeclaration *inter) { auto it = interfaceMap.find(inter); if (it == interfaceMap.end()) { return ~0UL; } return it->second; } void IrTypeClass::addInterfaceToMap(ClassDeclaration *inter, size_t index) { // don't duplicate work or overwrite indices if (interfaceMap.find(inter) != interfaceMap.end()) { return; } // add this interface interfaceMap.insert(std::make_pair(inter, index)); // add the direct base interfaces recursively - they // are accessed through the same index if (inter->interfaces.length > 0) { BaseClass *b = inter->interfaces.ptr[0]; addInterfaceToMap(b->sym, index); } } ldc-1.1.0-beta3-src/ir/irfunction.cpp0000664000175000017500000000342412776214734015446 0ustar kaikai//===-- irfunction.cpp ----------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "ir/irfunction.h" #include "gen/llvm.h" #include "gen/llvmhelpers.h" #include "gen/irstate.h" #include "gen/tollvm.h" #include "ir/irdsymbol.h" IrFunction::IrFunction(FuncDeclaration *fd) : FMF() { decl = fd; Type *t = fd->type->toBasetype(); assert(t->ty == Tfunction); type = static_cast(t); } void IrFunction::setNeverInline() { assert(!func->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::AlwaysInline) && "function can't be never- and always-inline at the same time"); func->addFnAttr(llvm::Attribute::NoInline); } void IrFunction::setAlwaysInline() { assert(!func->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoInline) && "function can't be never- and always-inline at the same time"); func->addFnAttr(llvm::Attribute::AlwaysInline); } IrFunction *getIrFunc(FuncDeclaration *decl, bool create) { if (!isIrFuncCreated(decl) && create) { assert(decl->ir->irFunc == NULL); decl->ir->irFunc = new IrFunction(decl); decl->ir->m_type = IrDsymbol::FuncType; } assert(decl->ir->irFunc != NULL); return decl->ir->irFunc; } bool isIrFuncCreated(FuncDeclaration *decl) { assert(decl); assert(decl->ir); IrDsymbol::Type t = decl->ir->type(); assert(t == IrDsymbol::FuncType || t == IrDsymbol::NotSet); return t == IrDsymbol::FuncType; } ldc-1.1.0-beta3-src/ir/irtypeaggr.cpp0000664000175000017500000001515212776214734015444 0ustar kaikai//===-- irtypeaggr.cpp ----------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "ir/irtypeaggr.h" #include "llvm/IR/DerivedTypes.h" #include "aggregate.h" #include "init.h" #include "gen/irstate.h" #include "gen/logger.h" #include "gen/llvmhelpers.h" ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // FIXME A similar function is in ir/iraggr.cpp and RTTIBuilder::push(). static inline size_t add_zeros(std::vector &defaultTypes, size_t startOffset, size_t endOffset) { assert(startOffset <= endOffset); const size_t paddingSize = endOffset - startOffset; if (paddingSize) { llvm::ArrayType *pad = llvm::ArrayType::get( llvm::Type::getInt8Ty(gIR->context()), paddingSize); defaultTypes.push_back(pad); } return paddingSize ? 1 : 0; } bool var_offset_sort_cb(const VarDeclaration *v1, const VarDeclaration *v2) { if (v1 && v2) { return v1->offset < v2->offset; } // sort NULL pointers towards the end return v1 && !v2; } AggrTypeBuilder::AggrTypeBuilder(bool packed) : m_packed(packed) { m_defaultTypes.reserve(32); } void AggrTypeBuilder::addType(llvm::Type *type, unsigned size) { m_defaultTypes.push_back(type); m_offset += size; m_fieldIndex++; } void AggrTypeBuilder::addAggregate(AggregateDeclaration *ad) { // mirror the ad->fields array but only fill in contributors const size_t n = ad->fields.dim; LLSmallVector data(n, nullptr); unsigned int errors = global.errors; // first fill in the fields with explicit initializers for (size_t index = 0; index < n; ++index) { VarDeclaration *field = ad->fields[index]; // _init is !null for explicit inits if (field->_init != nullptr && !field->_init->isVoidInitializer()) { IF_LOG Logger::println("adding explicit initializer for struct field %s", field->toChars()); size_t f_size = field->type->size(); size_t f_begin = field->offset; size_t f_end = f_begin + f_size; if (f_size == 0) { continue; } data[index] = field; // make sure there is no overlap for (size_t i = 0; i < index; i++) { if (data[i] != nullptr) { VarDeclaration *vd = data[i]; size_t v_begin = vd->offset; size_t v_end = v_begin + vd->type->size(); if (v_begin >= f_end || v_end <= f_begin) { continue; } ad->error(vd->loc, "has overlapping initialization for %s and %s", field->toChars(), vd->toChars()); } } } } if (errors != global.errors) { // There was an overlapping initialization. // Return if errors are gagged otherwise abort. if (global.gag) { return; } fatal(); } // fill in default initializers for (size_t index = 0; index < n; ++index) { if (data[index]) { continue; } VarDeclaration *field = ad->fields[index]; size_t f_size = field->type->size(); size_t f_begin = field->offset; size_t f_end = f_begin + f_size; if (f_size == 0) { continue; } // make sure it doesn't overlap anything explicit bool overlaps = false; for (size_t i = 0; i < n; i++) { if (data[i]) { size_t v_begin = data[i]->offset; size_t v_end = v_begin + data[i]->type->size(); if (v_begin >= f_end || v_end <= f_begin) { continue; } overlaps = true; break; } } // if no overlap was found, add the default initializer if (!overlaps) { IF_LOG Logger::println("adding default initializer for struct field %s", field->toChars()); data[index] = field; } } // // ok. now we can build a list of llvm types. and make sure zeros are inserted // if necessary. // // first we sort the list by offset std::sort(data.begin(), data.end(), var_offset_sort_cb); // add types to list for (size_t i = 0; i < n; i++) { VarDeclaration *vd = data[i]; if (vd == nullptr) { continue; } assert(vd->offset >= m_offset && "Variable overlaps previous field."); // Add an explicit field for any padding so we can zero it, as per TDPL // §7.1.1. if (m_offset < vd->offset) { m_fieldIndex += add_zeros(m_defaultTypes, m_offset, vd->offset); m_offset = vd->offset; } // add default type m_defaultTypes.push_back(DtoMemType(vd->type)); // advance offset to right past this field m_offset += getMemberSize(vd->type); // set the field index m_varGEPIndices[vd] = m_fieldIndex; ++m_fieldIndex; } } void AggrTypeBuilder::alignCurrentOffset(unsigned alignment) { m_overallAlignment = std::max(alignment, m_overallAlignment); unsigned aligned = (m_offset + alignment - 1) & ~(alignment - 1); if (m_offset < aligned) { m_fieldIndex += add_zeros(m_defaultTypes, m_offset, aligned); m_offset = aligned; } } void AggrTypeBuilder::addTailPadding(unsigned aggregateSize) { // tail padding? if (m_offset < aggregateSize) { add_zeros(m_defaultTypes, m_offset, aggregateSize); } } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// IrTypeAggr::IrTypeAggr(AggregateDeclaration *ad) : IrType(ad->type, LLStructType::create(gIR->context(), ad->toPrettyChars())), aggr(ad) {} bool IrTypeAggr::isPacked(AggregateDeclaration *ad) { if (ad->isUnionDeclaration()) { return true; } for (unsigned i = 0; i < ad->fields.dim; i++) { VarDeclaration *vd = static_cast(ad->fields.data[i]); unsigned a = vd->type->alignsize() - 1; if (((vd->offset + a) & ~a) != vd->offset) { return true; } } return false; } void IrTypeAggr::getMemberLocation(VarDeclaration *var, unsigned &fieldIndex, unsigned &byteOffset) const { // Note: The interface is a bit more general than what we actually return. // Specifically, the frontend offset information we use for overlapping // fields is always based at the object start. auto it = varGEPIndices.find(var); if (it != varGEPIndices.end()) { fieldIndex = it->second; byteOffset = 0; } else { fieldIndex = 0; byteOffset = var->offset; } } ldc-1.1.0-beta3-src/ir/irtypefunction.cpp0000664000175000017500000000346412776214734016354 0ustar kaikai//===-- irtypefunction.cpp ------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "llvm/IR/DerivedTypes.h" #include "mtype.h" #include "gen/irstate.h" #include "gen/tollvm.h" #include "gen/functions.h" #include "ir/irtypefunction.h" IrTypeFunction::IrTypeFunction(Type *dt, llvm::Type *lt, IrFuncTy irFty_) : IrType(dt, lt), irFty(std::move(irFty_)) {} IrTypeFunction *IrTypeFunction::get(Type *dt) { assert(!dt->ctype); assert(dt->ty == Tfunction); IrFuncTy irFty; llvm::Type *lt = DtoFunctionType(dt, irFty, nullptr, nullptr); // Could have already built the type as part of a struct forward reference, // just as for pointers and arrays. if (!dt->ctype) { dt->ctype = new IrTypeFunction(dt, lt, irFty); } return dt->ctype->isFunction(); } ////////////////////////////////////////////////////////////////////////////// IrTypeDelegate::IrTypeDelegate(Type *dt, llvm::Type *lt, IrFuncTy irFty_) : IrType(dt, lt), irFty(std::move(irFty_)) {} IrTypeDelegate *IrTypeDelegate::get(Type *t) { assert(!t->ctype); assert(t->ty == Tdelegate); assert(t->nextOf()->ty == Tfunction); IrFuncTy irFty; llvm::Type *ltf = DtoFunctionType(t->nextOf(), irFty, nullptr, Type::tvoid->pointerTo()); llvm::Type *types[] = {getVoidPtrType(), getPtrToType(ltf)}; LLStructType *lt = LLStructType::get(gIR->context(), types, false); // Could have already built the type as part of a struct forward reference, // just as for pointers and arrays. if (!t->ctype) { t->ctype = new IrTypeDelegate(t, lt, irFty); } return t->ctype->isDelegate(); } ldc-1.1.0-beta3-src/ir/irvar.h0000664000175000017500000000510212776214734014051 0ustar kaikai//===-- ir/irdsymbol.h - Codegen state for D vars/fields/params -*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Classes for representing the status of D variables on their way though the // codegen process. // //===----------------------------------------------------------------------===// #ifndef LDC_IR_IRVAR_H #define LDC_IR_IRVAR_H #include "llvm/IR/Type.h" #include "llvm/IR/DebugInfo.h" struct IrFuncTyArg; class VarDeclaration; struct IrVar { explicit IrVar(VarDeclaration *var) : V(var) {} IrVar(VarDeclaration *var, llvm::Value *value) : V(var), value(value) {} VarDeclaration *V = nullptr; llvm::Value *value = nullptr; }; // represents a global variable struct IrGlobal : IrVar { explicit IrGlobal(VarDeclaration *v) : IrVar(v) {} IrGlobal(VarDeclaration *v, llvm::Type *type, llvm::Constant *constInit = nullptr) : IrVar(v), type(type), constInit(constInit) {} llvm::Type *type = nullptr; llvm::Constant *constInit = nullptr; // This var is used by a naked function. bool nakedUse = false; }; // represents a local variable variable struct IrLocal : IrVar { explicit IrLocal(VarDeclaration *v) : IrVar(v) {} IrLocal(VarDeclaration *v, llvm::Value *value) : IrVar(v, value) {} IrLocal(VarDeclaration *v, int nestedDepth, int nestedIndex) : IrVar(v), nestedDepth(nestedDepth), nestedIndex(nestedIndex) {} // Used for hybrid nested context creation. int nestedDepth = 0; int nestedIndex = -1; }; // represents a function parameter struct IrParameter : IrLocal { explicit IrParameter(VarDeclaration *v) : IrLocal(v) {} IrFuncTyArg *arg = nullptr; bool isVthis = false; // true, if it is the 'this' parameter }; // represents an aggregate field variable struct IrField : IrVar { explicit IrField(VarDeclaration *v) : IrVar(v){}; }; IrVar *getIrVar(VarDeclaration *decl); llvm::Value *getIrValue(VarDeclaration *decl); bool isIrVarCreated(VarDeclaration *decl); IrGlobal *getIrGlobal(VarDeclaration *decl, bool create = false); bool isIrGlobalCreated(VarDeclaration *decl); IrLocal *getIrLocal(VarDeclaration *decl, bool create = false); bool isIrLocalCreated(VarDeclaration *decl); IrParameter *getIrParameter(VarDeclaration *decl, bool create = false); bool isIrParameterCreated(VarDeclaration *decl); IrField *getIrField(VarDeclaration *decl, bool create = false); bool isIrFieldCreated(VarDeclaration *decl); #endif ldc-1.1.0-beta3-src/ir/irvar.cpp0000664000175000017500000000663712776214734014422 0ustar kaikai//===-- irvar.cpp ---------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "gen/llvm.h" #include "declaration.h" #include "gen/irstate.h" #include "ir/irdsymbol.h" #include "ir/irvar.h" ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// IrVar *getIrVar(VarDeclaration *decl) { assert(isIrVarCreated(decl)); assert(decl->ir->irVar != NULL); return decl->ir->irVar; } llvm::Value *getIrValue(VarDeclaration *decl) { return getIrVar(decl)->value; } bool isIrVarCreated(VarDeclaration *decl) { int t = decl->ir->type(); bool isIrVar = t == IrDsymbol::GlobalType || t == IrDsymbol::LocalType || t == IrDsymbol::ParamterType || t == IrDsymbol::FieldType; assert(isIrVar || t == IrDsymbol::NotSet); return isIrVar; } ////////////////////////////////////////////////////////////////////////////// IrGlobal *getIrGlobal(VarDeclaration *decl, bool create) { if (!isIrGlobalCreated(decl) && create) { assert(decl->ir->irGlobal == NULL); decl->ir->irGlobal = new IrGlobal(decl); decl->ir->m_type = IrDsymbol::GlobalType; } assert(decl->ir->irGlobal != NULL); return decl->ir->irGlobal; } bool isIrGlobalCreated(VarDeclaration *decl) { int t = decl->ir->type(); assert(t == IrDsymbol::GlobalType || t == IrDsymbol::NotSet); return t == IrDsymbol::GlobalType; } ////////////////////////////////////////////////////////////////////////////// IrLocal *getIrLocal(VarDeclaration *decl, bool create) { if (!isIrLocalCreated(decl) && create) { assert(decl->ir->irLocal == NULL); decl->ir->irLocal = new IrLocal(decl); decl->ir->m_type = IrDsymbol::LocalType; } assert(decl->ir->irLocal != NULL); return decl->ir->irLocal; } bool isIrLocalCreated(VarDeclaration *decl) { int t = decl->ir->type(); assert(t == IrDsymbol::LocalType || t == IrDsymbol::ParamterType || t == IrDsymbol::NotSet); return t == IrDsymbol::LocalType || t == IrDsymbol::ParamterType; } ////////////////////////////////////////////////////////////////////////////// IrParameter *getIrParameter(VarDeclaration *decl, bool create) { if (!isIrParameterCreated(decl) && create) { assert(decl->ir->irParam == NULL); decl->ir->irParam = new IrParameter(decl); decl->ir->m_type = IrDsymbol::ParamterType; } return decl->ir->irParam; } bool isIrParameterCreated(VarDeclaration *decl) { int t = decl->ir->type(); assert(t == IrDsymbol::ParamterType || t == IrDsymbol::NotSet); return t == IrDsymbol::ParamterType; } ////////////////////////////////////////////////////////////////////////////// IrField *getIrField(VarDeclaration *decl, bool create) { if (!isIrFieldCreated(decl) && create) { assert(decl->ir->irField == NULL); decl->ir->irField = new IrField(decl); decl->ir->m_type = IrDsymbol::FieldType; } assert(decl->ir->irField != NULL); return decl->ir->irField; } bool isIrFieldCreated(VarDeclaration *decl) { int t = decl->ir->type(); assert(t == IrDsymbol::FieldType || t == IrDsymbol::NotSet); return t == IrDsymbol::FieldType; } ldc-1.1.0-beta3-src/ir/iraggr.cpp0000664000175000017500000003052512776214734014543 0ustar kaikai//===-- iraggr.cpp --------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "gen/llvm.h" #include "aggregate.h" #include "declaration.h" #include "init.h" #include "mtype.h" #include "target.h" #include "gen/irstate.h" #include "gen/llvmhelpers.h" #include "gen/logger.h" #include "gen/mangling.h" #include "gen/tollvm.h" #include "ir/iraggr.h" #include "irdsymbol.h" #include "ir/irtypeclass.h" #include "ir/irtypestruct.h" #include ////////////////////////////////////////////////////////////////////////////// IrAggr::IrAggr(AggregateDeclaration *aggr) : aggrdecl(aggr), type(aggr->type), // above still need to be looked at init_type(LLStructType::create( gIR->context(), std::string(aggr->toPrettyChars()) + "_init")) {} ////////////////////////////////////////////////////////////////////////////// LLGlobalVariable *IrAggr::getInitSymbol() { if (init) { return init; } // create the initZ symbol auto initname = getMangledInitSymbolName(aggrdecl); init = getOrCreateGlobal(aggrdecl->loc, gIR->module, init_type, true, llvm::GlobalValue::ExternalLinkage, nullptr, initname); // set alignment init->setAlignment(DtoAlignment(type)); return init; } ////////////////////////////////////////////////////////////////////////////// llvm::Constant *IrAggr::getDefaultInit() { if (constInit) { return constInit; } IF_LOG Logger::println("Building default initializer for %s", aggrdecl->toPrettyChars()); LOG_SCOPE; DtoType(type); VarInitMap noExplicitInitializers; constInit = createInitializerConstant(noExplicitInitializers, init_type); return constInit; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // helper function that adds zero bytes to a vector of constants // FIXME A similar function is in ir/irtypeaggr.cpp static inline size_t add_zeros(llvm::SmallVectorImpl &constants, size_t startOffset, size_t endOffset) { assert(startOffset <= endOffset); const size_t paddingSize = endOffset - startOffset; if (paddingSize) { llvm::ArrayType *pad = llvm::ArrayType::get( llvm::Type::getInt8Ty(gIR->context()), paddingSize); constants.push_back(llvm::Constant::getNullValue(pad)); } return paddingSize ? 1 : 0; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// typedef std::pair VarInitConst; static bool struct_init_data_sort(const VarInitConst &a, const VarInitConst &b) { return (a.first && b.first) ? a.first->offset < b.first->offset : false; } // helper function that returns the static default initializer of a variable LLConstant *get_default_initializer(VarDeclaration *vd) { if (vd->_init) { // Issue 9057 workaround caused by issue 14666 fix, see DMD upstream // commit 069f570005. if (vd->sem < Semantic2Done && vd->_scope) { vd->semantic2(vd->_scope); } return DtoConstInitializer(vd->_init->loc, vd->type, vd->_init); } if (vd->type->size(vd->loc) == 0) { // We need to be able to handle void[0] struct members even if void has // no default initializer. return llvm::ConstantPointerNull::get(DtoPtrToType(vd->type)); } return DtoConstExpInit(vd->loc, vd->type, vd->type->defaultInit(vd->loc)); } // return a constant array of type arrTypeD initialized with a constant value, // or that constant value static llvm::Constant *FillSArrayDims(Type *arrTypeD, llvm::Constant *init) { // Check whether we actually need to expand anything. // KLUDGE: We don't have the initializer type here, so we can only check // the size without doing an expensive recursive D <-> LLVM type comparison. // The better way to solve this would be to just fix the initializer // codegen in any place where a scalar initializer might still be generated. if (gDataLayout->getTypeStoreSize(init->getType()) >= arrTypeD->size()) { return init; } if (arrTypeD->ty == Tsarray) { init = FillSArrayDims(arrTypeD->nextOf(), init); size_t dim = static_cast(arrTypeD)->dim->toUInteger(); llvm::ArrayType *arrty = llvm::ArrayType::get(init->getType(), dim); return llvm::ConstantArray::get(arrty, std::vector(dim, init)); } return init; } llvm::Constant * IrAggr::createInitializerConstant(const VarInitMap &explicitInitializers, llvm::StructType *initializerType) { IF_LOG Logger::println("Creating initializer constant for %s", aggrdecl->toChars()); LOG_SCOPE; llvm::SmallVector constants; unsigned offset = 0; if (type->ty == Tclass) { // add vtbl constants.push_back(getVtblSymbol()); offset += Target::ptrsize; // add monitor (except for C++ classes) if (!aggrdecl->isClassDeclaration()->isCPPclass()) { constants.push_back(getNullValue(getVoidPtrType())); offset += Target::ptrsize; } } // Add the initializers for the member fields. While we are traversing the // class hierarchy, use the opportunity to populate interfacesWithVtbls if // we haven't done so previously (due to e.g. ClassReferenceExp, we can // have multiple initializer constants for a single class). addFieldInitializers(constants, explicitInitializers, aggrdecl, offset, interfacesWithVtbls.empty()); // tail padding? const size_t structsize = aggrdecl->size(Loc()); if (offset < structsize) { add_zeros(constants, offset, structsize); } // get initializer type if (!initializerType || initializerType->isOpaque()) { llvm::SmallVector types; types.reserve(constants.size()); for (auto c : constants) { types.push_back(c->getType()); } if (!initializerType) { initializerType = LLStructType::get(gIR->context(), types, isPacked()); } else { initializerType->setBody(types, isPacked()); } } // build constant assert(!constants.empty()); llvm::Constant *c = LLConstantStruct::get(initializerType, constants); IF_LOG Logger::cout() << "final initializer: " << *c << std::endl; return c; } void IrAggr::addFieldInitializers( llvm::SmallVectorImpl &constants, const VarInitMap &explicitInitializers, AggregateDeclaration *decl, unsigned &offset, bool populateInterfacesWithVtbls) { if (ClassDeclaration *cd = decl->isClassDeclaration()) { if (cd->baseClass) { addFieldInitializers(constants, explicitInitializers, cd->baseClass, offset, populateInterfacesWithVtbls); } // has interface vtbls? if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) { // Align interface infos to pointer size. unsigned aligned = (offset + Target::ptrsize - 1) & ~(Target::ptrsize - 1); if (offset < aligned) { add_zeros(constants, offset, aligned); offset = aligned; } // false when it's not okay to use functions from super classes bool newinsts = (cd == aggrdecl->isClassDeclaration()); size_t inter_idx = interfacesWithVtbls.size(); offset = (offset + Target::ptrsize - 1) & ~(Target::ptrsize - 1); for (auto bc : *cd->vtblInterfaces) { constants.push_back(getInterfaceVtbl(bc, newinsts, inter_idx)); offset += Target::ptrsize; inter_idx++; if (populateInterfacesWithVtbls) { interfacesWithVtbls.push_back(bc); } } } } // Build up vector with one-to-one mapping to field indices. const size_t n = decl->fields.dim; llvm::SmallVector data(n); // Fill in explicit initializers. for (size_t i = 0; i < n; ++i) { VarDeclaration *vd = decl->fields[i]; auto expl = explicitInitializers.find(vd); if (expl != explicitInitializers.end()) { const unsigned vd_begin = vd->offset; const unsigned vd_end = vd_begin + vd->type->size(); // Make sure it doesn't overlap any prior initializers (needed for // unions). This effectively initializes only the first member with an // explicit initializer of a union. // Only classes and structs can contain unions / overlapping fields. if (type->ty == Tstruct || type->ty == Tclass) { bool overlaps = false; for (size_t j = 0; j < i; ++j) { if (!data[j].first) { continue; } const unsigned f_begin = decl->fields[j]->offset; const unsigned f_end = f_begin + decl->fields[j]->type->size(); if (vd_begin >= f_end || vd_end <= f_begin) { continue; } overlaps = true; break; } if (overlaps) continue; } data[i] = *expl; } } // Fill in implicit initializers for (size_t i = 0; i < n; i++) { if (data[i].first) { continue; } VarDeclaration *vd = decl->fields[i]; /* Skip void initializers for unions. DMD bug 3991: union X { int a = void; dchar b = 'a'; } */ // FIXME: decl->isUnionDeclaration() is always false, the FE lowers // UnionDeclarations. if (decl->isUnionDeclaration() && vd->_init && vd->_init->isVoidInitializer()) { continue; } unsigned vd_begin = vd->offset; unsigned vd_end = vd_begin + vd->type->size(); /* Skip zero size fields like zero-length static arrays, LDC issue 812: class B { ubyte[0] test; } */ if (vd_begin == vd_end) { continue; } // make sure it doesn't overlap any explicit initializers. bool overlaps = false; if (type->ty == Tstruct || type->ty == Tclass) { // Only classes and structs can have overlapping fields. for (size_t j = 0; j < n; ++j) { if (i == j || !data[j].first) { continue; } VarDeclaration *it = decl->fields[j]; unsigned f_begin = it->offset; unsigned f_end = f_begin + it->type->size(); if (vd_begin >= f_end || vd_end <= f_begin) { continue; } overlaps = true; break; } } // add if no overlap found if (!overlaps) { IF_LOG Logger::println("Implicit initializer: %s @+%u", vd->toChars(), vd->offset); LOG_SCOPE; data[i].first = vd; data[i].second = get_default_initializer(vd); } } // Sort data array by offset. // TODO: Figure out whether this is really necessary, fields should already // be in offset order. Not having do do this would mean we could use a plain // llvm::Constant* vector for initializers and avoid all the VarInitConst // business. std::sort(data.begin(), data.end(), struct_init_data_sort); // build array of constants and make sure explicit zero padding is inserted // when necessary. for (size_t i = 0; i < n; i++) { VarDeclaration *vd = data[i].first; if (vd == nullptr) { continue; } // Explicitly zero the padding as per TDPL §7.1.1. Otherwise, it would // be left uninitialized by LLVM. if (offset < vd->offset) { add_zeros(constants, offset, vd->offset); offset = vd->offset; } IF_LOG Logger::println("adding field %s", vd->toChars()); constants.push_back(FillSArrayDims(vd->type, data[i].second)); offset += getMemberSize(vd->type); } } IrAggr *getIrAggr(AggregateDeclaration *decl, bool create) { if (!isIrAggrCreated(decl) && create) { assert(decl->ir->irAggr == NULL); decl->ir->irAggr = new IrAggr(decl); decl->ir->m_type = IrDsymbol::AggrType; } assert(decl->ir->irAggr != NULL); return decl->ir->irAggr; } bool isIrAggrCreated(AggregateDeclaration *decl) { int t = decl->ir->type(); assert(t == IrDsymbol::AggrType || t == IrDsymbol::NotSet); return t == IrDsymbol::AggrType; } ldc-1.1.0-beta3-src/ir/irtype.cpp0000664000175000017500000001405312776214734014602 0ustar kaikai//===-- irtype.cpp --------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/LLVMContext.h" #include "mars.h" #include "mtype.h" #include "gen/irstate.h" #include "gen/logger.h" #include "gen/llvmhelpers.h" #include "gen/tollvm.h" #include "ir/irtype.h" // These functions use getGlobalContext() as they are invoked before gIR // is set. IrType::IrType(Type *dt, LLType *lt) : dtype(dt), type(lt) { assert(dt && "null D Type"); assert(lt && "null LLVM Type"); assert(!dt->ctype && "already has IrType"); } IrFuncTy &IrType::getIrFuncTy() { llvm_unreachable("cannot get IrFuncTy from non lazy/function/delegate"); } ////////////////////////////////////////////////////////////////////////////// IrTypeBasic::IrTypeBasic(Type *dt) : IrType(dt, basic2llvm(dt)) {} IrTypeBasic *IrTypeBasic::get(Type *dt) { auto t = new IrTypeBasic(dt); dt->ctype = t; return t; } LLType *IrTypeBasic::getComplexType(llvm::LLVMContext &ctx, LLType *type) { llvm::Type *types[] = {type, type}; return llvm::StructType::get(ctx, types, false); } namespace { llvm::Type *getReal80Type(llvm::LLVMContext &ctx) { llvm::Triple::ArchType const a = global.params.targetTriple->getArch(); bool const anyX86 = (a == llvm::Triple::x86) || (a == llvm::Triple::x86_64); bool const anyAarch64 = (a == llvm::Triple::aarch64) || (a == llvm::Triple::aarch64_be) #if LDC_LLVM_VER == 305 || (a == llvm::Triple::arm64) || (a == llvm::Triple::arm64_be) #endif ; // only x86 has 80bit float - but no support with MS C Runtime! if (anyX86 && !global.params.targetTriple->isWindowsMSVCEnvironment()) { return llvm::Type::getX86_FP80Ty(ctx); } if (anyAarch64) { return llvm::Type::getFP128Ty(ctx); } return llvm::Type::getDoubleTy(ctx); } } llvm::Type *IrTypeBasic::basic2llvm(Type *t) { llvm::LLVMContext &ctx = getGlobalContext(); switch (t->ty) { case Tvoid: return llvm::Type::getVoidTy(ctx); case Tint8: case Tuns8: case Tchar: return llvm::Type::getInt8Ty(ctx); case Tint16: case Tuns16: case Twchar: return llvm::Type::getInt16Ty(ctx); case Tint32: case Tuns32: case Tdchar: return llvm::Type::getInt32Ty(ctx); case Tint64: case Tuns64: return llvm::Type::getInt64Ty(ctx); case Tint128: case Tuns128: return llvm::IntegerType::get(ctx, 128); case Tfloat32: case Timaginary32: return llvm::Type::getFloatTy(ctx); case Tfloat64: case Timaginary64: return llvm::Type::getDoubleTy(ctx); case Tfloat80: case Timaginary80: return getReal80Type(ctx); case Tcomplex32: return getComplexType(ctx, llvm::Type::getFloatTy(ctx)); case Tcomplex64: return getComplexType(ctx, llvm::Type::getDoubleTy(ctx)); case Tcomplex80: return getComplexType(ctx, getReal80Type(ctx)); case Tbool: return llvm::Type::getInt1Ty(ctx); default: llvm_unreachable("Unknown basic type."); } } ////////////////////////////////////////////////////////////////////////////// IrTypePointer::IrTypePointer(Type *dt, LLType *lt) : IrType(dt, lt) {} IrTypePointer *IrTypePointer::get(Type *dt) { assert(!dt->ctype); assert((dt->ty == Tpointer || dt->ty == Tnull) && "not pointer/null type"); LLType *elemType; if (dt->ty == Tnull) { elemType = llvm::Type::getInt8Ty(getGlobalContext()); } else { elemType = DtoMemType(dt->nextOf()); // DtoType could have already created the same type, e.g. for // dt == Node* in struct Node { Node* n; }. if (dt->ctype) { return dt->ctype->isPointer(); } } auto t = new IrTypePointer(dt, llvm::PointerType::get(elemType, 0)); dt->ctype = t; return t; } ////////////////////////////////////////////////////////////////////////////// IrTypeSArray::IrTypeSArray(Type *dt, LLType *lt) : IrType(dt, lt) {} IrTypeSArray *IrTypeSArray::get(Type *dt) { assert(!dt->ctype); assert(dt->ty == Tsarray && "not static array type"); LLType *elemType = DtoMemType(dt->nextOf()); // We might have already built the type during DtoMemType e.g. as part of a // forward reference in a struct. if (!dt->ctype) { TypeSArray *tsa = static_cast(dt); uint64_t dim = static_cast(tsa->dim->toUInteger()); dt->ctype = new IrTypeSArray(dt, llvm::ArrayType::get(elemType, dim)); } return dt->ctype->isSArray(); } ////////////////////////////////////////////////////////////////////////////// IrTypeArray::IrTypeArray(Type *dt, LLType *lt) : IrType(dt, lt) {} IrTypeArray *IrTypeArray::get(Type *dt) { assert(!dt->ctype); assert(dt->ty == Tarray && "not dynamic array type"); LLType *elemType = DtoMemType(dt->nextOf()); // Could have already built the type as part of a struct forward reference, // just as for pointers. if (!dt->ctype) { llvm::Type *types[] = {DtoSize_t(), llvm::PointerType::get(elemType, 0)}; LLType *at = llvm::StructType::get(getGlobalContext(), types, false); dt->ctype = new IrTypeArray(dt, at); } return dt->ctype->isArray(); } ////////////////////////////////////////////////////////////////////////////// IrTypeVector::IrTypeVector(Type *dt, llvm::Type *lt) : IrType(dt, lt) {} IrTypeVector *IrTypeVector::get(Type *dt) { LLType *lt = vector2llvm(dt); // Could have already built the type as part of a struct forward reference, // just as for pointers and arrays. if (!dt->ctype) { dt->ctype = new IrTypeVector(dt, lt); } return dt->ctype->isVector(); } llvm::Type *IrTypeVector::vector2llvm(Type *dt) { assert(dt->ty == Tvector && "not vector type"); TypeVector *tv = static_cast(dt); assert(tv->basetype->ty == Tsarray); TypeSArray *tsa = static_cast(tv->basetype); uint64_t dim = static_cast(tsa->dim->toUInteger()); LLType *elemType = DtoMemType(tsa->next); return llvm::VectorType::get(elemType, dim); } ldc-1.1.0-beta3-src/ir/iraggr.h0000664000175000017500000001311012776214734014177 0ustar kaikai//===-- ir/iraggr.h - Codegen state for D aggregates ------------*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Represents the state of a D aggregate (struct/class) on its way through // codegen, also managing the associated init and RTTI symbols. // //===----------------------------------------------------------------------===// #ifndef LDC_IR_IRAGGR_H #define LDC_IR_IRAGGR_H #include "llvm/ADT/SmallVector.h" #include #include // DMD forward declarations class StructInitializer; namespace llvm { class Constant; class StructType; } ////////////////////////////////////////////////////////////////////////////// // represents a struct or class // it is used during codegen to hold all the vital info we need struct IrAggr { /// Constructor. explicit IrAggr(AggregateDeclaration *agg); ////////////////////////////////////////////////////////////////////////// // public fields, // FIXME this is basically stuff I just haven't gotten around to yet. /// The D aggregate. AggregateDeclaration *aggrdecl = nullptr; /// Aggregate D type. Type *type = nullptr; ////////////////////////////////////////////////////////////////////////// /// Create the __initZ symbol lazily. llvm::GlobalVariable *getInitSymbol(); /// Builds the __initZ initializer constant lazily. llvm::Constant *getDefaultInit(); /// Create the __vtblZ symbol lazily. llvm::GlobalVariable *getVtblSymbol(); /// Builds the __vtblZ initializer constant lazily. llvm::Constant *getVtblInit(); /// Create the __ClassZ/__InterfaceZ symbol lazily. llvm::GlobalVariable *getClassInfoSymbol(); /// Builds the __ClassZ/__InterfaceZ initializer constant lazily. llvm::Constant *getClassInfoInit(); /// Create the __interfaceInfos symbol lazily. llvm::GlobalVariable *getInterfaceArraySymbol(); ////////////////////////////////////////////////////////////////////////// /// Initialize interface. void initializeInterface(); ////////////////////////////////////////////////////////////////////////// using VarInitMap = std::map; /// Creates an initializer constant for the struct type with the given /// fields set to the provided constants. The remaining space (not /// explicitly specified fields, padding) is default-initialized. /// /// The optional initializerType parmeter can be used to specify the exact /// LLVM type to use for the initializer. If non-null and non-opaque, the /// type must exactly match the generated constant. This parameter is used /// mainly for supporting legacy code. /// /// Note that in the general case (if e.g. unions are involved), the /// returned type is not necessarily the same as getLLType(). llvm::Constant * createInitializerConstant(const VarInitMap &explicitInitializers, llvm::StructType *initializerType = nullptr); protected: /// Static default initializer global. llvm::GlobalVariable *init = nullptr; /// Static default initializer constant. llvm::Constant *constInit = nullptr; /// Static default initialier type. llvm::StructType *init_type = nullptr; /// Vtbl global. llvm::GlobalVariable *vtbl = nullptr; /// Vtbl initializer constant. llvm::Constant *constVtbl = nullptr; /// ClassInfo global. llvm::GlobalVariable *classInfo = nullptr; /// ClassInfo initializer constant. llvm::Constant *constClassInfo = nullptr; using ClassGlobalMap = std::map, llvm::GlobalVariable *>; /// Map from pairs of to global variable, implemented /// by this class. The same interface can appear multiple times, so index is /// another way to specify the thunk offset ClassGlobalMap interfaceVtblMap; /// Interface info array global. /// Basically: static object.Interface[num_interfaces] llvm::GlobalVariable *classInterfacesArray = nullptr; /// std::vector of BaseClass* using BaseClassVector = std::vector; /// Array of all interface vtbl implementations - in order - implemented /// by this class. /// Corresponds to the Interface instances needed to be output. BaseClassVector interfacesWithVtbls; ////////////////////////////////////////////////////////////////////////// /// Returns vtbl for interface implementation, creates it if not already /// built. llvm::GlobalVariable *getInterfaceVtbl(BaseClass *b, bool new_inst, size_t interfaces_index); // FIXME make this a member instead friend llvm::Constant *DtoDefineClassInfo(ClassDeclaration *cd); /// Create the Interface[] interfaces ClassInfo field initializer. llvm::Constant *getClassInfoInterfaces(); /// Returns true, if the LLVM struct type for the aggregate is declared as /// packed bool isPacked() const; private: /// Recursively adds all the initializers for the given aggregate and, in /// case of a class type, all its base classes. void addFieldInitializers(llvm::SmallVectorImpl &constants, const VarInitMap &explicitInitializers, AggregateDeclaration *decl, unsigned &offset, bool populateInterfacesWithVtbls); }; ////////////////////////////////////////////////////////////////////////////// IrAggr *getIrAggr(AggregateDeclaration *decl, bool create = false); bool isIrAggrCreated(AggregateDeclaration *decl); #endif ldc-1.1.0-beta3-src/ir/irtypestruct.h0000664000175000017500000000156212776214734015515 0ustar kaikai//===-- ir/irtypestruct.h - IrType for structs and unions -------*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #ifndef LDC_IR_IRTYPESTRUCT_H #define LDC_IR_IRTYPESTRUCT_H #include "ir/irtypeaggr.h" class StructDeclaration; class TypeStruct; /// IrType for struct/union types. class IrTypeStruct : public IrTypeAggr { public: /// static IrTypeStruct *get(StructDeclaration *sd); /// IrTypeStruct *isStruct() override { return this; } protected: /// explicit IrTypeStruct(StructDeclaration *sd); /// StructDeclaration this type represents. StructDeclaration *sd = nullptr; /// DMD TypeStruct of this type. TypeStruct *ts = nullptr; }; #endif ldc-1.1.0-beta3-src/ir/irfuncty.h0000664000175000017500000000722712776214734014603 0ustar kaikai//===-- ir/irfuncty.h - Function type codegen metadata ----------*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Additional information attached to a function type during codegen. Handles // LLVM attributes attached to a function and its parameters, etc. // //===----------------------------------------------------------------------===// #ifndef LDC_IR_IRFUNCTY_H #define LDC_IR_IRFUNCTY_H #include "llvm/ADT/SmallVector.h" #include "gen/attributes.h" #if defined(_MSC_VER) #include "array.h" #endif #include class DValue; class Type; struct ABIRewrite; namespace llvm { class Type; class Value; class Instruction; class Function; class FunctionType; } /// Represents a function type argument (both explicit and implicit as well as /// return values). /// /// Instances of this only exist for arguments that are actually lowered to an /// LLVM parameter (e.g. not for empty structs). struct IrFuncTyArg { /** This is the original D type as the frontend knows it * May NOT be rewritten!!! */ Type *const type = nullptr; /// The index of the declaration in the FuncDeclaration::parameters array /// corresponding to this argument. size_t parametersIdx = 0; /// This is the final LLVM Type used for the parameter/return value type llvm::Type *ltype = nullptr; /** These are the final LLVM attributes used for the function. * Must be valid for the LLVM Type and byref setting */ AttrBuilder attrs; /** 'true' if the final LLVM argument is a LLVM reference type. * Must be true when the D Type is a value type, but the final * LLVM Type is a reference type! */ bool byref = false; /** Pointer to the ABIRewrite structure needed to rewrite LLVM ValueS * to match the final LLVM Type when passing arguments and getting * return values */ ABIRewrite *rewrite = nullptr; /// Helper to check if the 'inreg' attribute is set bool isInReg() const; /// Helper to check if the 'sret' attribute is set bool isSRet() const; /// Helper to check if the 'byval' attribute is set bool isByVal() const; /** @param t D type of argument/return value as known by the frontend * @param byref Initial value for the 'byref' field. If true the initial * LLVM Type will be of DtoType(type->pointerTo()), instead * of just DtoType(type) */ IrFuncTyArg(Type *t, bool byref, AttrBuilder attrs = AttrBuilder()); }; // represents a function type struct IrFuncTy { // The final LLVM type llvm::FunctionType *funcType = nullptr; // return value IrFuncTyArg *ret = nullptr; // null if not applicable IrFuncTyArg *arg_sret = nullptr; IrFuncTyArg *arg_this = nullptr; IrFuncTyArg *arg_objcSelector = nullptr; IrFuncTyArg *arg_nest = nullptr; IrFuncTyArg *arg_arguments = nullptr; // normal explicit arguments // typedef llvm::SmallVector ArgList; using ArgList = std::vector; ArgList args; // C varargs bool c_vararg = false; // range of normal parameters to reverse bool reverseParams = false; // reserved for ABI-specific data void *tag = nullptr; llvm::Value *putRet(DValue *dval); llvm::Value *getRetRVal(Type *dty, llvm::Value *val); llvm::Value *getRetLVal(Type *dty, llvm::Value *val); llvm::Value *putParam(size_t idx, DValue *dval); llvm::Value *putParam(const IrFuncTyArg &arg, DValue *dval); llvm::Value *getParamLVal(Type *dty, size_t idx, llvm::Value *val); AttrSet getParamAttrs(bool passThisBeforeSret); }; #endif ldc-1.1.0-beta3-src/ir/irtypeclass.h0000664000175000017500000000571712776214734015304 0ustar kaikai//===-- ir/irtypeclass.h - IrType implementation for D classes --*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Provides the IrType subclass used to represent D classes. // //===----------------------------------------------------------------------===// #ifndef __LDC_IR_IRTYPECLASS_H__ #define __LDC_IR_IRTYPECLASS_H__ #include "ir/irtypeaggr.h" #include "llvm/IR/DerivedTypes.h" template struct Array; using FuncDeclarations = Array; /// class IrTypeClass : public IrTypeAggr { public: /// static IrTypeClass *get(ClassDeclaration *cd); /// IrTypeClass *isClass() override { return this; } /// llvm::Type *getLLType() override; /// Returns the actual storage type, i.e. without the indirection /// for the class reference. llvm::Type *getMemoryLLType(); /// Returns the vtable type for this class. llvm::Type *getVtbl() { return vtbl_type; } /// Get index to interface implementation. /// Returns the index of a specific interface implementation in this /// class or ~0 if not found. size_t getInterfaceIndex(ClassDeclaration *inter); /// Returns the total number of pointers in the vtable. unsigned getVtblSize() { return vtbl_size; } /// Returns the number of interface implementations (vtables) in this /// class. unsigned getNumInterfaceVtbls() { return num_interface_vtbls; } protected: /// explicit IrTypeClass(ClassDeclaration *cd); /// ClassDeclaration *cd = nullptr; /// TypeClass *tc = nullptr; /// Vtable type. llvm::StructType *vtbl_type = nullptr; /// Number of pointers in vtable. unsigned vtbl_size = 0; /// Number of interface implementations (vtables) in this class. unsigned num_interface_vtbls = 0; /// std::map type mapping ClassDeclaration* to size_t. using ClassIndexMap = std::map; /// Map for mapping the index of a specific interface implementation /// in this class to its ClassDeclaration. ClassIndexMap interfaceMap; ////////////////////////////////////////////////////////////////////////// /// Builds a vtable type given the type of the first entry and an array /// of all entries. /// If first is nullptr for C++ interfaces, the vtbl_array will be added /// as is without replacing the first entry. std::vector buildVtblType(Type *first, FuncDeclarations *vtbl_array); /// Adds the data members for the given class to the type builder, including /// those inherited from base classes/interfaces. void addClassData(AggrTypeBuilder &builder, ClassDeclaration *currCd); /// Adds the interface and all it's base interface to the interface /// to index map. void addInterfaceToMap(ClassDeclaration *inter, size_t index); }; #endif ldc-1.1.0-beta3-src/ir/irfuncty.cpp0000664000175000017500000000647512776214734015142 0ustar kaikai//===-- irfuncty.cpp ------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "ir/irfuncty.h" #include "mtype.h" #include "gen/abi.h" #include "gen/dvalue.h" #include "gen/llvm.h" #include "gen/llvmhelpers.h" #include "gen/logger.h" #include "gen/tollvm.h" IrFuncTyArg::IrFuncTyArg(Type *t, bool bref, AttrBuilder a) : type(t), ltype(t != Type::tvoid && bref ? DtoType(t->pointerTo()) : DtoType(t)), attrs(std::move(a)), byref(bref) {} bool IrFuncTyArg::isInReg() const { return attrs.contains(LLAttribute::InReg); } bool IrFuncTyArg::isSRet() const { return attrs.contains(LLAttribute::StructRet); } bool IrFuncTyArg::isByVal() const { return attrs.contains(LLAttribute::ByVal); } llvm::Value *IrFuncTy::putRet(DValue *dval) { assert(!arg_sret); if (ret->rewrite) { Logger::println("Rewrite: putRet"); LOG_SCOPE return ret->rewrite->put(dval); } if (ret->byref || DtoIsInMemoryOnly(dval->type)) return DtoLVal(dval); return DtoRVal(dval); } llvm::Value *IrFuncTy::getRetRVal(Type *dty, LLValue *val) { assert(!arg_sret); if (ret->rewrite) { Logger::println("Rewrite: getRetRVal"); LOG_SCOPE return ret->rewrite->getRVal(dty, val); } return val; } llvm::Value *IrFuncTy::getRetLVal(Type *dty, LLValue *val) { assert(!arg_sret); if (ret->rewrite) { Logger::println("Rewrite: getRetLVal"); LOG_SCOPE return ret->rewrite->getLVal(dty, val); } return DtoAllocaDump(val, dty); } llvm::Value *IrFuncTy::putParam(size_t idx, DValue *dval) { assert(idx < args.size() && "invalid putParam"); return putParam(*args[idx], dval); } llvm::Value *IrFuncTy::putParam(const IrFuncTyArg &arg, DValue *dval) { if (arg.rewrite) { Logger::println("Rewrite: putParam"); LOG_SCOPE return arg.rewrite->put(dval); } if (arg.byref || DtoIsInMemoryOnly(dval->type)) return DtoLVal(dval); return DtoRVal(dval); } LLValue *IrFuncTy::getParamLVal(Type *dty, size_t idx, LLValue *val) { assert(idx < args.size() && "invalid getParam"); if (args[idx]->rewrite) { Logger::println("Rewrite: getParamLVal"); LOG_SCOPE return args[idx]->rewrite->getLVal(dty, val); } return DtoAllocaDump(val, dty); } AttrSet IrFuncTy::getParamAttrs(bool passThisBeforeSret) { AttrSet newAttrs; int idx = 0; // handle implicit args #define ADD_PA(X) \ if (X) { \ newAttrs.add(idx, (X)->attrs); \ idx++; \ } ADD_PA(ret) if (arg_sret && arg_this && passThisBeforeSret) { ADD_PA(arg_this) ADD_PA(arg_sret) } else { ADD_PA(arg_sret) ADD_PA(arg_this) } ADD_PA(arg_nest) ADD_PA(arg_arguments) #undef ADD_PA // Set attributes on the explicit parameters. const size_t n = args.size(); for (size_t k = 0; k < n; k++) { const size_t i = idx + (reverseParams ? (n - k - 1) : k); newAttrs.add(i, args[k]->attrs); } return newAttrs; } ldc-1.1.0-beta3-src/ir/irforw.h0000664000175000017500000000231412776214734014240 0ustar kaikai//===-- ir/irforw.h - Forward declarations used in ir/ code ----*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Some common forward declarations for use in ir/ headers. // //===----------------------------------------------------------------------===// #ifndef LDC_IR_IRFORW_H #define LDC_IR_IRFORW_H // dmd forward declarations class Module; class Dsymbol; struct Declaration; class VarDeclaration; class FuncDeclaration; struct AggregateDeclaration; class StructDeclaration; class ClassDeclaration; struct InterfaceDeclaration; struct Expression; struct BaseClass; struct Array; struct Argument; class Type; class TypeStruct; class TypeClass; struct TypeEnum; struct TypeArray; class TypeFunction; // llvm forward declarations namespace llvm { class Value; class GlobalValue; class GlobalVariable; class Function; class Constant; class ConstantStruct; class ConstantArray; class DataLayout; class Type; class StructType; class ArrayType; class PointerType; class BasicBlock; class Instruction; } #endif ldc-1.1.0-beta3-src/ir/irclass.cpp0000664000175000017500000004626612776214734014741 0ustar kaikai//===-- irclass.cpp -------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/ADT/SmallString.h" #ifndef NDEBUG #include "llvm/Support/raw_ostream.h" #endif #include "aggregate.h" #include "declaration.h" #include "hdrgen.h" // for parametersTypeToChars() #include "mtype.h" #include "target.h" #include "gen/funcgenstate.h" #include "gen/irstate.h" #include "gen/logger.h" #include "gen/tollvm.h" #include "gen/llvmhelpers.h" #include "gen/arrays.h" #include "gen/metadata.h" #include "gen/runtime.h" #include "gen/functions.h" #include "gen/abi.h" #include "gen/mangling.h" #include "ir/iraggr.h" #include "ir/irfunction.h" #include "ir/irtypeclass.h" ////////////////////////////////////////////////////////////////////////////// extern LLConstant *DtoDefineClassInfo(ClassDeclaration *cd); ////////////////////////////////////////////////////////////////////////////// LLGlobalVariable *IrAggr::getVtblSymbol() { if (vtbl) { return vtbl; } // create the vtblZ symbol auto initname = getMangledVTableSymbolName(aggrdecl); LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtbl(); vtbl = getOrCreateGlobal(aggrdecl->loc, gIR->module, vtblTy, true, llvm::GlobalValue::ExternalLinkage, nullptr, initname); return vtbl; } ////////////////////////////////////////////////////////////////////////////// LLGlobalVariable *IrAggr::getClassInfoSymbol() { if (classInfo) { return classInfo; } // create the ClassZ / InterfaceZ symbol std::string initname = getMangledClassInfoSymbolName(aggrdecl); // The type is also ClassInfo for interfaces – the actual TypeInfo for them // is a TypeInfo_Interface instance that references __ClassZ in its "base" // member. ClassDeclaration *cinfo = Type::typeinfoclass; DtoType(cinfo->type); IrTypeClass *tc = stripModifiers(cinfo->type)->ctype->isClass(); assert(tc && "invalid ClassInfo type"); // classinfos cannot be constants since they're used as locks for synchronized classInfo = getOrCreateGlobal( aggrdecl->loc, gIR->module, tc->getMemoryLLType(), false, llvm::GlobalValue::ExternalLinkage, nullptr, initname); // Generate some metadata on this ClassInfo if it's for a class. ClassDeclaration *classdecl = aggrdecl->isClassDeclaration(); if (classdecl && !aggrdecl->isInterfaceDeclaration()) { // Gather information LLType *type = DtoType(aggrdecl->type); LLType *bodyType = llvm::cast(type)->getElementType(); bool hasDestructor = (classdecl->dtor != nullptr); bool hasCustomDelete = (classdecl->aggDelete != nullptr); // Construct the fields #if LDC_LLVM_VER >= 306 llvm::Metadata *mdVals[CD_NumFields]; mdVals[CD_BodyType] = llvm::ConstantAsMetadata::get(llvm::UndefValue::get(bodyType)); mdVals[CD_Finalize] = llvm::ConstantAsMetadata::get( LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasDestructor)); mdVals[CD_CustomDelete] = llvm::ConstantAsMetadata::get( LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasCustomDelete)); #else MDNodeField *mdVals[CD_NumFields]; mdVals[CD_BodyType] = llvm::UndefValue::get(bodyType); mdVals[CD_Finalize] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasDestructor); mdVals[CD_CustomDelete] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasCustomDelete); #endif // Construct the metadata and insert it into the module. llvm::SmallString<64> name; llvm::NamedMDNode *node = gIR->module.getOrInsertNamedMetadata( llvm::Twine(CD_PREFIX, initname).toStringRef(name)); node->addOperand(llvm::MDNode::get( gIR->context(), llvm::makeArrayRef(mdVals, CD_NumFields))); } return classInfo; } ////////////////////////////////////////////////////////////////////////////// LLGlobalVariable *IrAggr::getInterfaceArraySymbol() { if (classInterfacesArray) { return classInterfacesArray; } ClassDeclaration *cd = aggrdecl->isClassDeclaration(); size_t n = stripModifiers(type)->ctype->isClass()->getNumInterfaceVtbls(); assert(n > 0 && "getting ClassInfo.interfaces storage symbol, but we " "don't implement any interfaces"); LLType *InterfaceTy = DtoType(Type::typeinfoclass->fields[3]->type->nextOf()); // create Interface[N] LLArrayType *array_type = llvm::ArrayType::get(InterfaceTy, n); // put it in a global std::string name("_D"); name.append(mangle(cd)); name.append("16__interfaceInfosZ"); // We keep this as external for now and only consider template linkage if // we emit the initializer later. classInterfacesArray = getOrCreateGlobal(cd->loc, gIR->module, array_type, true, llvm::GlobalValue::ExternalLinkage, nullptr, name); return classInterfacesArray; } ////////////////////////////////////////////////////////////////////////////// LLConstant *IrAggr::getVtblInit() { if (constVtbl) { return constVtbl; } IF_LOG Logger::println("Building vtbl initializer"); LOG_SCOPE; ClassDeclaration *cd = aggrdecl->isClassDeclaration(); assert(cd && "not class"); std::vector constants; constants.reserve(cd->vtbl.dim); // start with the classinfo llvm::Constant *c; if (!cd->isCPPclass()) { c = getClassInfoSymbol(); c = DtoBitCast(c, DtoType(Type::typeinfoclass->type)); constants.push_back(c); } // add virtual function pointers size_t n = cd->vtbl.dim; for (size_t i = cd->vtblOffset(); i < n; i++) { Dsymbol *dsym = static_cast(cd->vtbl.data[i]); assert(dsym && "null vtbl member"); FuncDeclaration *fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); if (cd->isAbstract() || (fd->isAbstract() && !fd->fbody)) { c = getNullValue(getPtrToType(DtoFunctionType(fd))); } else { DtoResolveFunction(fd); assert(isIrFuncCreated(fd) && "invalid vtbl function"); c = getIrFunc(fd)->func; if (cd->isFuncHidden(fd)) { // fd is hidden from the view of this class. If fd overlaps with any // function in the vtbl[], issue error. for (size_t j = 1; j < n; j++) { if (j == i) { continue; } auto fd2 = static_cast(cd->vtbl.data[j])->isFuncDeclaration(); if (!fd2->ident->equals(fd->ident)) { continue; } if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd)) { TypeFunction *tf = static_cast(fd->type); if (tf->ty == Tfunction) { cd->error("use of %s%s is hidden by %s; use 'alias %s = %s.%s;' " "to introduce base class overload set", fd->toPrettyChars(), parametersTypeToChars(tf->parameters, tf->varargs), cd->toChars(), fd->toChars(), fd->parent->toChars(), fd->toChars()); } else { cd->error("use of %s is hidden by %s", fd->toPrettyChars(), cd->toChars()); } fatal(); break; } } } } constants.push_back(c); } // build the constant struct LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtbl(); #ifndef NDEBUG size_t nc = constants.size(); for (size_t i = 0; i < nc; ++i) { if (constants[i]->getType() != vtblTy->getContainedType(i)) { llvm::errs() << "type mismatch for entry # " << i << " in vtbl initializer\n"; constants[i]->getType()->dump(); vtblTy->getContainedType(i)->dump(); } } #endif constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants); assert(constVtbl->getType() == stripModifiers(type)->ctype->isClass()->getVtbl() && "vtbl initializer type mismatch"); return constVtbl; } ////////////////////////////////////////////////////////////////////////////// LLConstant *IrAggr::getClassInfoInit() { if (constClassInfo) { return constClassInfo; } constClassInfo = DtoDefineClassInfo(aggrdecl->isClassDeclaration()); return constClassInfo; } ////////////////////////////////////////////////////////////////////////////// llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance, size_t interfaces_index) { auto it = interfaceVtblMap.find({b->sym, interfaces_index}); if (it != interfaceVtblMap.end()) { return it->second; } IF_LOG Logger::println( "Building vtbl for implementation of interface %s in class %s", b->sym->toPrettyChars(), aggrdecl->toPrettyChars()); LOG_SCOPE; ClassDeclaration *cd = aggrdecl->isClassDeclaration(); assert(cd && "not a class aggregate"); FuncDeclarations vtbl_array; b->fillVtbl(cd, &vtbl_array, new_instance); std::vector constants; constants.reserve(vtbl_array.dim); if (!b->sym->isCPPinterface()) { // skip interface info for CPP interfaces // index into the interfaces array llvm::Constant *idxs[2] = {DtoConstSize_t(0), DtoConstSize_t(interfaces_index)}; llvm::GlobalVariable *interfaceInfosZ = getInterfaceArraySymbol(); llvm::Constant *c = llvm::ConstantExpr::getGetElementPtr( #if LDC_LLVM_VER >= 307 isaPointer(interfaceInfosZ)->getElementType(), #endif interfaceInfosZ, idxs, true); constants.push_back(c); } // Thunk prefix char thunkPrefix[16]; int thunkLen = sprintf(thunkPrefix, "Thn%d_", b->offset); char thunkPrefixLen[16]; sprintf(thunkPrefixLen, "%d", thunkLen); // add virtual function pointers size_t n = vtbl_array.dim; for (size_t i = b->sym->vtblOffset(); i < n; i++) { Dsymbol *dsym = static_cast(vtbl_array.data[i]); if (dsym == nullptr) { // FIXME // why is this null? // happens for mini/s.d constants.push_back(getNullValue(getVoidPtrType())); continue; } FuncDeclaration *fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); assert((!fd->isAbstract() || fd->fbody) && "null symbol in interface implementation vtable"); DtoResolveFunction(fd); assert(isIrFuncCreated(fd) && "invalid vtbl function"); IrFunction *irFunc = getIrFunc(fd); assert(irFunc->irFty.arg_this); int thunkOffset = b->offset; if (fd->interfaceVirtual) thunkOffset -= fd->interfaceVirtual->offset; if (thunkOffset == 0) { constants.push_back(irFunc->func); continue; } // Create the thunk function if it does not already exist in this // module. OutBuffer nameBuf; const auto mangledTargetName = mangleExact(fd); nameBuf.write(mangledTargetName, 2); nameBuf.writestring(thunkPrefix); nameBuf.writestring(mangledTargetName + 2); const char *thunkName = nameBuf.extractString(); llvm::Function *thunk = gIR->module.getFunction(thunkName); if (!thunk) { const LinkageWithCOMDAT lwc(LLGlobalValue::LinkOnceODRLinkage, supportsCOMDAT()); thunk = LLFunction::Create( isaFunction(irFunc->func->getType()->getContainedType(0)), lwc.first, thunkName, &gIR->module); setLinkage(lwc, thunk); thunk->copyAttributesFrom(irFunc->func); // Thunks themselves don't have an identity, only the target // function has. #if LDC_LLVM_VER >= 309 thunk->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); #else thunk->setUnnamedAddr(true); #endif #if LDC_LLVM_VER >= 307 // thunks don't need exception handling themselves thunk->setPersonalityFn(nullptr); #endif // It is necessary to add debug information to the thunk in case it is // subject to inlining. See https://llvm.org/bugs/show_bug.cgi?id=26833 IF_LOG Logger::println("Doing function body for thunk to: %s", fd->toChars()); // Create a dummy FuncDeclaration with enough information to satisfy the // DIBuilder FuncDeclaration *thunkFd = reinterpret_cast( memcpy(new char[sizeof(FuncDeclaration)], (void *)fd, sizeof(FuncDeclaration))); thunkFd->ir = new IrDsymbol(); auto thunkFunc = getIrFunc(thunkFd, true); // create the IrFunction thunkFunc->func = thunk; thunkFunc->type = irFunc->type; gIR->funcGenStates.emplace_back(new FuncGenState(*thunkFunc, *gIR)); // debug info thunkFunc->diSubprogram = gIR->DBuilder.EmitThunk(thunk, thunkFd); // create entry and end blocks llvm::BasicBlock *beginbb = llvm::BasicBlock::Create(gIR->context(), "", thunk); gIR->scopes.push_back(IRScope(beginbb)); gIR->DBuilder.EmitFuncStart(thunkFd); // Copy the function parameters, so later we can pass them to the // real function and set their names from the original function (the // latter being just for IR readablilty). std::vector args; llvm::Function::arg_iterator thunkArg = thunk->arg_begin(); llvm::Function::arg_iterator origArg = irFunc->func->arg_begin(); for (; thunkArg != thunk->arg_end(); ++thunkArg, ++origArg) { thunkArg->setName(origArg->getName()); args.push_back(&(*thunkArg)); } // cast 'this' to Object const int thisArgIndex = (!irFunc->irFty.arg_sret || gABI->passThisBeforeSret(irFunc->type)) ? 0 : 1; LLValue *&thisArg = args[thisArgIndex]; LLType *targetThisType = thisArg->getType(); thisArg = DtoBitCast(thisArg, getVoidPtrType()); thisArg = DtoGEP1(thisArg, DtoConstInt(-thunkOffset), true); thisArg = DtoBitCast(thisArg, targetThisType); // all calls that might be subject to inlining into a caller with debug // info should have debug info, too gIR->DBuilder.EmitStopPoint(fd->loc); // call the real vtbl function. llvm::CallInst *call = gIR->ir->CreateCall(irFunc->func, args); call->setCallingConv(irFunc->func->getCallingConv()); call->setTailCallKind(llvm::CallInst::TCK_Tail); // return from the thunk if (thunk->getReturnType() == LLType::getVoidTy(gIR->context())) { llvm::ReturnInst::Create(gIR->context(), beginbb); } else { llvm::ReturnInst::Create(gIR->context(), call, beginbb); } gIR->DBuilder.EmitFuncEnd(thunkFd); // clean up gIR->scopes.pop_back(); gIR->funcGenStates.pop_back(); } constants.push_back(thunk); } // build the vtbl constant llvm::Constant *vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false); std::string mangledName("_D"); mangledName.append(mangle(cd)); mangledName.append("11__interface"); mangledName.append(mangle(b->sym)); mangledName.append(thunkPrefixLen); mangledName.append(thunkPrefix); mangledName.append("6__vtblZ"); const auto lwc = DtoLinkage(cd); LLGlobalVariable *GV = getOrCreateGlobal(cd->loc, gIR->module, vtbl_constant->getType(), true, lwc.first, vtbl_constant, mangledName); setLinkage(lwc, GV); // insert into the vtbl map interfaceVtblMap.insert({{b->sym, interfaces_index}, GV}); return GV; } bool IrAggr::isPacked() const { return static_cast(type->ctype)->packed; } ////////////////////////////////////////////////////////////////////////////// LLConstant *IrAggr::getClassInfoInterfaces() { IF_LOG Logger::println("Building ClassInfo.interfaces"); LOG_SCOPE; ClassDeclaration *cd = aggrdecl->isClassDeclaration(); assert(cd); size_t n = interfacesWithVtbls.size(); assert(stripModifiers(type)->ctype->isClass()->getNumInterfaceVtbls() == n && "inconsistent number of interface vtables in this class"); VarDeclaration *interfaces_idx = Type::typeinfoclass->fields[3]; if (n == 0) { return getNullValue(DtoType(interfaces_idx->type)); } // Build array of: // // struct Interface // { // ClassInfo classinfo; // void*[] vtbl; // ptrdiff_t offset; // } LLSmallVector constants; constants.reserve(cd->vtblInterfaces->dim); LLType *classinfo_type = DtoType(Type::typeinfoclass->type); LLType *voidptrptr_type = DtoType(Type::tvoid->pointerTo()->pointerTo()); VarDeclaration *idx = Type::typeinfoclass->fields[3]; LLStructType *interface_type = isaStruct(DtoType(idx->type->nextOf())); assert(interface_type); for (size_t i = 0; i < n; ++i) { BaseClass *it = interfacesWithVtbls[i]; IF_LOG Logger::println("Adding interface %s", it->sym->toPrettyChars()); IrAggr *irinter = getIrAggr(it->sym); assert(irinter && "interface has null IrStruct"); IrTypeClass *itc = stripModifiers(irinter->type)->ctype->isClass(); assert(itc && "null interface IrTypeClass"); // classinfo LLConstant *ci = irinter->getClassInfoSymbol(); ci = DtoBitCast(ci, classinfo_type); // vtbl LLConstant *vtb; // interface get a null if (cd->isInterfaceDeclaration()) { vtb = DtoConstSlice(DtoConstSize_t(0), getNullValue(voidptrptr_type)); } else { auto itv = interfaceVtblMap.find({it->sym, i}); assert(itv != interfaceVtblMap.end() && "interface vtbl not found"); vtb = itv->second; vtb = DtoBitCast(vtb, voidptrptr_type); vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb); } // offset LLConstant *off = DtoConstSize_t(it->offset); // create Interface struct LLConstant *inits[3] = {ci, vtb, off}; LLConstant *entry = LLConstantStruct::get(interface_type, llvm::makeArrayRef(inits, 3)); constants.push_back(entry); } // create Interface[N] LLArrayType *array_type = llvm::ArrayType::get(interface_type, n); // create and apply initializer LLConstant *arr = LLConstantArray::get(array_type, constants); auto ciarr = getInterfaceArraySymbol(); ciarr->setInitializer(arr); setLinkage(cd, ciarr); // return null, only baseclass provide interfaces if (cd->vtblInterfaces->dim == 0) { return getNullValue(DtoType(interfaces_idx->type)); } // only the interface explicitly implemented by this class // (not super classes) should show in ClassInfo LLConstant *idxs[2] = {DtoConstSize_t(0), DtoConstSize_t(n - cd->vtblInterfaces->dim)}; LLConstant *ptr = llvm::ConstantExpr::getGetElementPtr( #if LDC_LLVM_VER >= 307 isaPointer(ciarr)->getElementType(), #endif ciarr, idxs, true); // return as a slice return DtoConstSlice(DtoConstSize_t(cd->vtblInterfaces->dim), ptr); } ////////////////////////////////////////////////////////////////////////////// void IrAggr::initializeInterface() { InterfaceDeclaration *base = aggrdecl->isInterfaceDeclaration(); assert(base && "not interface"); // has interface vtbls? if (!base->vtblInterfaces) { return; } for (auto bc : *base->vtblInterfaces) { // add to the interface list interfacesWithVtbls.push_back(bc); } } ////////////////////////////////////////////////////////////////////////////// ldc-1.1.0-beta3-src/ir/irfunction.h0000664000175000017500000000464012776214734015114 0ustar kaikai//===-- ir/irfunction.h - Codegen state for D functions ---------*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Represents the state of a D function/method/... on its way through the // codegen process. // //===----------------------------------------------------------------------===// #ifndef LDC_IR_IRFUNCTION_H #define LDC_IR_IRFUNCTION_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" #include "gen/llvm.h" #include "ir/irfuncty.h" #include class FuncDeclaration; class TypeFunction; class VarDeclaration; // represents a function struct IrFunction { // constructor explicit IrFunction(FuncDeclaration *fd); // annotations void setNeverInline(); void setAlwaysInline(); llvm::Function *func = nullptr; FuncDeclaration *decl = nullptr; TypeFunction *type = nullptr; llvm::Value *sretArg = nullptr; // sret pointer arg llvm::Value *thisArg = nullptr; // class/struct 'this' arg llvm::Value *nestArg = nullptr; // nested function 'this' arg llvm::StructType *frameType = nullptr; // type of nested context unsigned frameTypeAlignment = 0; // its alignment // number of enclosing functions with variables accessed by nested functions // (-1 if neither this function nor any enclosing ones access variables from // enclosing functions) int depth = -1; bool nestedContextCreated = false; // holds whether nested context is created // TODO: Move to FuncGenState? llvm::Value *_arguments = nullptr; llvm::Value *_argptr = nullptr; #if LDC_LLVM_VER >= 307 llvm::DISubprogram *diSubprogram = nullptr; std::stack diLexicalBlocks; using VariableMap = llvm::DenseMap; #else llvm::DISubprogram diSubprogram; std::stack diLexicalBlocks; using VariableMap = llvm::DenseMap; #endif // Debug info for all variables VariableMap variableMap; IrFuncTy irFty; /// Stores the FastMath options for this functions. /// These are set e.g. by math related UDA's from ldc.attributes. llvm::FastMathFlags FMF; }; IrFunction *getIrFunc(FuncDeclaration *decl, bool create = false); bool isIrFuncCreated(FuncDeclaration *decl); #endif ldc-1.1.0-beta3-src/ir/irmodule.cpp0000664000175000017500000000236412776214734015110 0ustar kaikai//===-- irmodule.cpp ------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "ir/irmodule.h" #include "module.h" #include "gen/llvm.h" #include "gen/irstate.h" #include "gen/tollvm.h" #include "ir/irdsymbol.h" #include "ir/irfunction.h" IrModule::IrModule(Module *module) : M(module) {} llvm::GlobalVariable *IrModule::moduleInfoSymbol() { if (moduleInfoVar) { return moduleInfoVar; } std::string name("_D"); name.append(mangle(M)); name.append("12__ModuleInfoZ"); moduleInfoVar = new llvm::GlobalVariable( gIR->module, llvm::StructType::create(gIR->context()), false, llvm::GlobalValue::ExternalLinkage, nullptr, name); return moduleInfoVar; } IrModule *getIrModule(Module *m) { if (!m) { m = gIR->func()->decl->getModule(); } assert(m && "null module"); if (m->ir->m_type == IrDsymbol::NotSet) { m->ir->irModule = new IrModule(m); m->ir->m_type = IrDsymbol::ModuleType; } assert(m->ir->m_type == IrDsymbol::ModuleType); return m->ir->irModule; } ldc-1.1.0-beta3-src/ir/irtypefunction.h0000664000175000017500000000235712776214734016021 0ustar kaikai//===-- ir/irtypefunction.h - IrType subclasses for callables ---*- C++ -*-===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Provides the IrType subclasses used to represent D function/delegate types. // //===----------------------------------------------------------------------===// #ifndef __LDC_IR_IRTYPEFUNCTION_H__ #define __LDC_IR_IRTYPEFUNCTION_H__ #include "ir/irtype.h" struct IrFuncTy; /// class IrTypeFunction : public IrType { public: /// static IrTypeFunction *get(Type *dt); /// IrTypeFunction *isFunction() override { return this; } /// IrFuncTy &getIrFuncTy() override { return irFty; } protected: /// IrTypeFunction(Type *dt, llvm::Type *lt, IrFuncTy irFty); /// IrFuncTy irFty; }; /// class IrTypeDelegate : public IrType { public: /// static IrTypeDelegate *get(Type *dt); /// IrTypeDelegate *isDelegate() override { return this; } /// IrFuncTy &getIrFuncTy() override { return irFty; } protected: /// IrTypeDelegate(Type *dt, LLType *lt, IrFuncTy irFty); /// IrFuncTy irFty; }; #endif ldc-1.1.0-beta3-src/runtime/0000775000175000017500000000000012776214734013630 5ustar kaikaildc-1.1.0-beta3-src/runtime/profile-rt/0000775000175000017500000000000012776214734015713 5ustar kaikaildc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/0000775000175000017500000000000012776214734020226 5ustar kaikaildc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfData.inc0000664000175000017500000007001612776214734023445 0ustar kaikai/*===-- InstrProfData.inc - instr profiling runtime structures -*- C++ -*-=== *\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ /* * This is the master file that defines all the data structure, signature, * constant literals that are shared across profiling runtime library, * compiler (instrumentation), and host tools (reader/writer). The entities * defined in this file affect the profile runtime ABI, the raw profile format, * or both. * * The file has two identical copies. The master copy lives in LLVM and * the other one sits in compiler-rt/lib/profile directory. To make changes * in this file, first modify the master copy and copy it over to compiler-rt. * Testing of any change in this file can start only after the two copies are * synced up. * * The first part of the file includes macros that defines types, names, and * initializers for the member fields of the core data structures. The field * declarations for one structure is enabled by defining the field activation * macro associated with that structure. Only one field activation record * can be defined at one time and the rest definitions will be filtered out by * the preprocessor. * * Examples of how the template is used to instantiate structure definition: * 1. To declare a structure: * * struct ProfData { * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \ * Type Name; * #include "llvm/ProfileData/InstrProfData.inc" * }; * * 2. To construct LLVM type arrays for the struct type: * * Type *DataTypes[] = { * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \ * LLVMType, * #include "llvm/ProfileData/InstrProfData.inc" * }; * * 4. To construct constant array for the initializers: * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \ * Initializer, * Constant *ConstantVals[] = { * #include "llvm/ProfileData/InstrProfData.inc" * }; * * * The second part of the file includes definitions all other entities that * are related to runtime ABI and format. When no field activation macro is * defined, this file can be included to introduce the definitions. * \*===----------------------------------------------------------------------===*/ /* INSTR_PROF_DATA start. */ /* Definition of member fields of the per-function control structure. */ #ifndef INSTR_PROF_DATA #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), \ NamePtr->getType()->getPointerElementType()->getArrayNumElements())) INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters)) INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ Inc->getHash()->getZExtValue())) INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), NamePtr, \ ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx))) INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \ ConstantExpr::getBitCast(CounterPtr, \ llvm::Type::getInt64PtrTy(Ctx))) INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \ FunctionAddr) INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \ ConstantPointerNull::get(Int8PtrTy)) INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \ ConstantArray::get(Int16ArrayTy, Int16ArrayVals)) #undef INSTR_PROF_DATA /* INSTR_PROF_DATA end. */ /* INSTR_PROF_RAW_HEADER start */ /* Definition of member fields of the raw profile header data structure. */ #ifndef INSTR_PROF_RAW_HEADER #define INSTR_PROF_RAW_HEADER(Type, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic()) INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version()) INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize) INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize) INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize) INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin) INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin) INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last) INSTR_PROF_RAW_HEADER(uint64_t, ValueDataSize, ValueDataSize) INSTR_PROF_RAW_HEADER(uint64_t, ValueDataDelta, (uintptr_t)ValueDataBegin) #undef INSTR_PROF_RAW_HEADER /* INSTR_PROF_RAW_HEADER end */ /* VALUE_PROF_FUNC_PARAM start */ /* Definition of parameter types of the runtime API used to do value profiling * for a given value site. */ #ifndef VALUE_PROF_FUNC_PARAM #define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType) #define INSTR_PROF_COMMA #else #define INSTR_PROF_DATA_DEFINED #define INSTR_PROF_COMMA , #endif VALUE_PROF_FUNC_PARAM(uint64_t, TargetValue, Type::getInt64Ty(Ctx)) \ INSTR_PROF_COMMA VALUE_PROF_FUNC_PARAM(void *, Data, Type::getInt8PtrTy(Ctx)) INSTR_PROF_COMMA VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) #undef VALUE_PROF_FUNC_PARAM #undef INSTR_PROF_COMMA /* VALUE_PROF_FUNC_PARAM end */ /* VALUE_PROF_KIND start */ #ifndef VALUE_PROF_KIND #define VALUE_PROF_KIND(Enumerator, Value) #else #define INSTR_PROF_DATA_DEFINED #endif VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0) /* These two kinds must be the last to be * declared. This is to make sure the string * array created with the template can be * indexed with the kind value. */ VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget) VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget) #undef VALUE_PROF_KIND /* VALUE_PROF_KIND end */ /* COVMAP_FUNC_RECORD start */ /* Definition of member fields of the function record structure in coverage * map. */ #ifndef COVMAP_FUNC_RECORD #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \ NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \ llvm::Type::getInt8PtrTy(Ctx))) COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\ NameValue.size())) COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), DataSize, \ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\ CoverageMapping.size())) COVMAP_FUNC_RECORD(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \ llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), FuncHash)) #undef COVMAP_FUNC_RECORD /* COVMAP_FUNC_RECORD end. */ /* COVMAP_HEADER start */ /* Definition of member fields of coverage map header. */ #ifndef COVMAP_HEADER #define COVMAP_HEADER(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif COVMAP_HEADER(uint32_t, Int32Ty, NRecords, \ llvm::ConstantInt::get(Int32Ty, FunctionRecords.size())) COVMAP_HEADER(uint32_t, Int32Ty, FilenamesSize, \ llvm::ConstantInt::get(Int32Ty, FilenamesSize)) COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \ llvm::ConstantInt::get(Int32Ty, CoverageMappingSize)) COVMAP_HEADER(uint32_t, Int32Ty, Version, \ llvm::ConstantInt::get(Int32Ty, CoverageMappingCurrentVersion)) #undef COVMAP_HEADER /* COVMAP_HEADER end. */ #ifdef INSTR_PROF_VALUE_PROF_DATA #define INSTR_PROF_DATA_DEFINED #define INSTR_PROF_MAX_NUM_VAL_PER_SITE 255 /*! * This is the header of the data structure that defines the on-disk * layout of the value profile data of a particular kind for one function. */ typedef struct ValueProfRecord { /* The kind of the value profile record. */ uint32_t Kind; /* * The number of value profile sites. It is guaranteed to be non-zero; * otherwise the record for this kind won't be emitted. */ uint32_t NumValueSites; /* * The first element of the array that stores the number of profiled * values for each value site. The size of the array is NumValueSites. * Since NumValueSites is greater than zero, there is at least one * element in the array. */ uint8_t SiteCountArray[1]; /* * The fake declaration is for documentation purpose only. * Align the start of next field to be on 8 byte boundaries. uint8_t Padding[X]; */ /* The array of value profile data. The size of the array is the sum * of all elements in SiteCountArray[]. InstrProfValueData ValueData[]; */ #ifdef __cplusplus /*! * \brief Return the number of value sites. */ uint32_t getNumValueSites() const { return NumValueSites; } /*! * \brief Read data from this record and save it to Record. */ void deserializeTo(InstrProfRecord &Record, InstrProfRecord::ValueMapType *VMap); /* * In-place byte swap: * Do byte swap for this instance. \c Old is the original order before * the swap, and \c New is the New byte order. */ void swapBytes(support::endianness Old, support::endianness New); #endif } ValueProfRecord; /*! * Per-function header/control data structure for value profiling * data in indexed format. */ typedef struct ValueProfData { /* * Total size in bytes including this field. It must be a multiple * of sizeof(uint64_t). */ uint32_t TotalSize; /* *The number of value profile kinds that has value profile data. * In this implementation, a value profile kind is considered to * have profile data if the number of value profile sites for the * kind is not zero. More aggressively, the implementation can * choose to check the actual data value: if none of the value sites * has any profiled values, the kind can be skipped. */ uint32_t NumValueKinds; /* * Following are a sequence of variable length records. The prefix/header * of each record is defined by ValueProfRecord type. The number of * records is NumValueKinds. * ValueProfRecord Record_1; * ValueProfRecord Record_N; */ #if __cplusplus /*! * Return the total size in bytes of the on-disk value profile data * given the data stored in Record. */ static uint32_t getSize(const InstrProfRecord &Record); /*! * Return a pointer to \c ValueProfData instance ready to be streamed. */ static std::unique_ptr serializeFrom(const InstrProfRecord &Record); /*! * Check the integrity of the record. Return the error code when * an error is detected, otherwise return instrprof_error::success. */ instrprof_error checkIntegrity(); /*! * Return a pointer to \c ValueProfileData instance ready to be read. * All data in the instance are properly byte swapped. The input * data is assumed to be in little endian order. */ static ErrorOr> getValueProfData(const unsigned char *SrcBuffer, const unsigned char *const SrcBufferEnd, support::endianness SrcDataEndianness); /*! * Swap byte order from \c Endianness order to host byte order. */ void swapBytesToHost(support::endianness Endianness); /*! * Swap byte order from host byte order to \c Endianness order. */ void swapBytesFromHost(support::endianness Endianness); /*! * Return the total size of \c ValueProfileData. */ uint32_t getSize() const { return TotalSize; } /*! * Read data from this data and save it to \c Record. */ void deserializeTo(InstrProfRecord &Record, InstrProfRecord::ValueMapType *VMap); void operator delete(void *ptr) { ::operator delete(ptr); } #endif } ValueProfData; /* * The closure is designed to abstact away two types of value profile data: * - InstrProfRecord which is the primary data structure used to * represent profile data in host tools (reader, writer, and profile-use) * - value profile runtime data structure suitable to be used by C * runtime library. * * Both sources of data need to serialize to disk/memory-buffer in common * format: ValueProfData. The abstraction allows compiler-rt's raw profiler * writer to share the same format and code with indexed profile writer. * * For documentation of the member methods below, refer to corresponding methods * in class InstrProfRecord. */ typedef struct ValueProfRecordClosure { const void *Record; uint32_t (*GetNumValueKinds)(const void *Record); uint32_t (*GetNumValueSites)(const void *Record, uint32_t VKind); uint32_t (*GetNumValueData)(const void *Record, uint32_t VKind); uint32_t (*GetNumValueDataForSite)(const void *R, uint32_t VK, uint32_t S); /* * After extracting the value profile data from the value profile record, * this method is used to map the in-memory value to on-disk value. If * the method is null, value will be written out untranslated. */ uint64_t (*RemapValueData)(uint32_t, uint64_t Value); void (*GetValueForSite)(const void *R, InstrProfValueData *Dst, uint32_t K, uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t)); ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes); } ValueProfRecordClosure; /* * A wrapper struct that represents value profile runtime data. * Like InstrProfRecord class which is used by profiling host tools, * ValueProfRuntimeRecord also implements the abstract intefaces defined in * ValueProfRecordClosure so that the runtime data can be serialized using * shared C implementation. In this structure, NumValueSites and Nodes * members are the primary fields while other fields hold the derived * information for fast implementation of closure interfaces. */ typedef struct ValueProfRuntimeRecord { /* Number of sites for each value profile kind. */ const uint16_t *NumValueSites; /* An array of linked-list headers. The size of of the array is the * total number of value profile sites : sum(NumValueSites[*])). Each * linked-list stores the values profiled for a value profile site. */ ValueProfNode **Nodes; /* Total number of value profile kinds which have at least one * value profile sites. */ uint32_t NumValueKinds; /* An array recording the number of values tracked at each site. * The size of the array is TotalNumValueSites. */ uint8_t *SiteCountArray[IPVK_Last + 1]; ValueProfNode **NodesKind[IPVK_Last + 1]; } ValueProfRuntimeRecord; /* Forward declarations of C interfaces. */ int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord, const uint16_t *NumValueSites, ValueProfNode **Nodes); void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord); uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record); ValueProfData * serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, ValueProfData *Dst); uint32_t getNumValueKindsRT(const void *R); #undef INSTR_PROF_VALUE_PROF_DATA #endif /* INSTR_PROF_VALUE_PROF_DATA */ #ifdef INSTR_PROF_COMMON_API_IMPL #define INSTR_PROF_DATA_DEFINED #ifdef __cplusplus #define INSTR_PROF_INLINE inline #else #define INSTR_PROF_INLINE #endif #ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif /*! * \brief Return the \c ValueProfRecord header size including the * padding bytes. */ INSTR_PROF_INLINE uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) + sizeof(uint8_t) * NumValueSites; /* Round the size to multiple of 8 bytes. */ Size = (Size + 7) & ~7; return Size; } /*! * \brief Return the total size of the value profile record including the * header and the value data. */ INSTR_PROF_INLINE uint32_t getValueProfRecordSize(uint32_t NumValueSites, uint32_t NumValueData) { return getValueProfRecordHeaderSize(NumValueSites) + sizeof(InstrProfValueData) * NumValueData; } /*! * \brief Return the pointer to the start of value data array. */ INSTR_PROF_INLINE InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize( This->NumValueSites)); } /*! * \brief Return the total number of value data for \c This record. */ INSTR_PROF_INLINE uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { uint32_t NumValueData = 0; uint32_t I; for (I = 0; I < This->NumValueSites; I++) NumValueData += This->SiteCountArray[I]; return NumValueData; } /*! * \brief Use this method to advance to the next \c This \c ValueProfRecord. */ INSTR_PROF_INLINE ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { uint32_t NumValueData = getValueProfRecordNumValueData(This); return (ValueProfRecord *)((char *)This + getValueProfRecordSize(This->NumValueSites, NumValueData)); } /*! * \brief Return the first \c ValueProfRecord instance. */ INSTR_PROF_INLINE ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) { return (ValueProfRecord *)((char *)This + sizeof(ValueProfData)); } /* Closure based interfaces. */ /*! * Return the total size in bytes of the on-disk value profile data * given the data stored in Record. */ uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) { uint32_t Kind; uint32_t TotalSize = sizeof(ValueProfData); const void *Record = Closure->Record; uint32_t NumValueKinds = Closure->GetNumValueKinds(Record); if (NumValueKinds == 0) return TotalSize; for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { uint32_t NumValueSites = Closure->GetNumValueSites(Record, Kind); if (!NumValueSites) continue; TotalSize += getValueProfRecordSize(NumValueSites, Closure->GetNumValueData(Record, Kind)); } return TotalSize; } /*! * Extract value profile data of a function for the profile kind \c ValueKind * from the \c Closure and serialize the data into \c This record instance. */ void serializeValueProfRecordFrom(ValueProfRecord *This, ValueProfRecordClosure *Closure, uint32_t ValueKind, uint32_t NumValueSites) { uint32_t S; const void *Record = Closure->Record; This->Kind = ValueKind; This->NumValueSites = NumValueSites; InstrProfValueData *DstVD = getValueProfRecordValueData(This); for (S = 0; S < NumValueSites; S++) { uint32_t ND = Closure->GetNumValueDataForSite(Record, ValueKind, S); This->SiteCountArray[S] = ND; Closure->GetValueForSite(Record, DstVD, ValueKind, S, Closure->RemapValueData); DstVD += ND; } } /*! * Extract value profile data of a function from the \c Closure * and serialize the data into \c DstData if it is not NULL or heap * memory allocated by the \c Closure's allocator method. */ ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure, ValueProfData *DstData) { uint32_t Kind; uint32_t TotalSize = getValueProfDataSize(Closure); ValueProfData *VPD = DstData ? DstData : Closure->AllocValueProfData(TotalSize); VPD->TotalSize = TotalSize; VPD->NumValueKinds = Closure->GetNumValueKinds(Closure->Record); ValueProfRecord *VR = getFirstValueProfRecord(VPD); for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { uint32_t NumValueSites = Closure->GetNumValueSites(Closure->Record, Kind); if (!NumValueSites) continue; serializeValueProfRecordFrom(VR, Closure, Kind, NumValueSites); VR = getValueProfRecordNext(VR); } return VPD; } /* * The value profiler runtime library stores the value profile data * for a given function in \c NumValueSites and \c Nodes structures. * \c ValueProfRuntimeRecord class is used to encapsulate the runtime * profile data and provides fast interfaces to retrieve the profile * information. This interface is used to initialize the runtime record * and pre-compute the information needed for efficient implementation * of callbacks required by ValueProfRecordClosure class. */ int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord, const uint16_t *NumValueSites, ValueProfNode **Nodes) { unsigned I, J, S = 0, NumValueKinds = 0; RuntimeRecord->NumValueSites = NumValueSites; RuntimeRecord->Nodes = Nodes; for (I = 0; I <= IPVK_Last; I++) { uint16_t N = NumValueSites[I]; if (!N) { RuntimeRecord->SiteCountArray[I] = 0; continue; } NumValueKinds++; RuntimeRecord->SiteCountArray[I] = (uint8_t *)calloc(N, 1); if (!RuntimeRecord->SiteCountArray[I]) return 1; RuntimeRecord->NodesKind[I] = Nodes ? &Nodes[S] : NULL; for (J = 0; J < N; J++) { /* Compute value count for each site. */ uint32_t C = 0; ValueProfNode *Site = Nodes ? RuntimeRecord->NodesKind[I][J] : NULL; while (Site) { C++; Site = Site->Next; } if (C > UCHAR_MAX) C = UCHAR_MAX; RuntimeRecord->SiteCountArray[I][J] = C; } S += N; } RuntimeRecord->NumValueKinds = NumValueKinds; return 0; } void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord) { unsigned I; for (I = 0; I <= IPVK_Last; I++) { if (RuntimeRecord->SiteCountArray[I]) free(RuntimeRecord->SiteCountArray[I]); } } /* ValueProfRecordClosure Interface implementation for * ValueProfDataRuntimeRecord. */ uint32_t getNumValueKindsRT(const void *R) { return ((const ValueProfRuntimeRecord *)R)->NumValueKinds; } uint32_t getNumValueSitesRT(const void *R, uint32_t VK) { return ((const ValueProfRuntimeRecord *)R)->NumValueSites[VK]; } uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK, uint32_t S) { const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; return Record->SiteCountArray[VK][S]; } uint32_t getNumValueDataRT(const void *R, uint32_t VK) { unsigned I, S = 0; const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; if (Record->SiteCountArray[VK] == 0) return 0; for (I = 0; I < Record->NumValueSites[VK]; I++) S += Record->SiteCountArray[VK][I]; return S; } void getValueForSiteRT(const void *R, InstrProfValueData *Dst, uint32_t VK, uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t)) { unsigned I, N = 0; const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; N = getNumValueDataForSiteRT(R, VK, S); if (N == 0) return; ValueProfNode *VNode = Record->NodesKind[VK][S]; for (I = 0; I < N; I++) { Dst[I] = VNode->VData; VNode = VNode->Next; } } ValueProfData *allocValueProfDataRT(size_t TotalSizeInBytes) { return (ValueProfData *)calloc(TotalSizeInBytes, 1); } static ValueProfRecordClosure RTRecordClosure = {0, getNumValueKindsRT, getNumValueSitesRT, getNumValueDataRT, getNumValueDataForSiteRT, 0, getValueForSiteRT, allocValueProfDataRT}; /* * Return the size of ValueProfData structure to store data * recorded in the runtime record. */ uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record) { RTRecordClosure.Record = Record; return getValueProfDataSize(&RTRecordClosure); } /* * Return a ValueProfData instance that stores the data collected * from runtime. If \c DstData is provided by the caller, the value * profile data will be store in *DstData and DstData is returned, * otherwise the method will allocate space for the value data and * return pointer to the newly allocated space. */ ValueProfData * serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, ValueProfData *DstData) { RTRecordClosure.Record = Record; return serializeValueProfDataFrom(&RTRecordClosure, DstData); } #undef INSTR_PROF_COMMON_API_IMPL #endif /* INSTR_PROF_COMMON_API_IMPL */ /*============================================================================*/ #ifndef INSTR_PROF_DATA_DEFINED #ifndef INSTR_PROF_DATA_INC_ #define INSTR_PROF_DATA_INC_ /* Helper macros. */ #define INSTR_PROF_SIMPLE_QUOTE(x) #x #define INSTR_PROF_QUOTE(x) INSTR_PROF_SIMPLE_QUOTE(x) #define INSTR_PROF_SIMPLE_CONCAT(x,y) x ## y #define INSTR_PROF_CONCAT(x,y) INSTR_PROF_SIMPLE_CONCAT(x,y) /* Magic number to detect file format and endianness. * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0, * so that utilities, like strings, don't grab it as a string. 129 is also * invalid UTF-8, and high enough to be interesting. * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR" * for 32-bit platforms. */ #define INSTR_PROF_RAW_MAGIC_64 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \ (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129 #define INSTR_PROF_RAW_MAGIC_32 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \ (uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129 /* Raw profile format version. */ #define INSTR_PROF_RAW_VERSION 2 #define INSTR_PROF_INDEX_VERSION 3 #define INSTR_PROF_COVMAP_VERSION 0 /* Profile version is always of type uint_64_t. Reserve the upper 8 bits in the * version for other variants of profile. We set the lowest bit of the upper 8 * bits (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentaiton * generated profile, and 0 if this is a Clang FE generated profile. */ #define VARIANT_MASKS_ALL 0xff00000000000000ULL #define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL) /* Runtime section names and name strings. */ #define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data #define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names #define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts #define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap #define INSTR_PROF_DATA_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME) #define INSTR_PROF_NAME_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME) #define INSTR_PROF_CNTS_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME) #define INSTR_PROF_COVMAP_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME) /* Macros to define start/stop section symbol for a given * section on Linux. For instance * INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) will * expand to __start___llvm_prof_data */ #define INSTR_PROF_SECT_START(Sect) \ INSTR_PROF_CONCAT(__start_,Sect) #define INSTR_PROF_SECT_STOP(Sect) \ INSTR_PROF_CONCAT(__stop_,Sect) /* Value Profiling API linkage name. */ #define INSTR_PROF_VALUE_PROF_FUNC __llvm_profile_instrument_target #define INSTR_PROF_VALUE_PROF_FUNC_STR \ INSTR_PROF_QUOTE(INSTR_PROF_VALUE_PROF_FUNC) /* InstrProfile per-function control data alignment. */ #define INSTR_PROF_DATA_ALIGNMENT 8 /* The data structure that represents a tracked value by the * value profiler. */ typedef struct InstrProfValueData { /* Profiled value. */ uint64_t Value; /* Number of times the value appears in the training run. */ uint64_t Count; } InstrProfValueData; /* This is an internal data structure used by value profiler. It * is defined here to allow serialization code sharing by LLVM * to be used in unit test. */ typedef struct ValueProfNode { InstrProfValueData VData; struct ValueProfNode *Next; } ValueProfNode; #endif /* INSTR_PROF_DATA_INC_ */ #else #undef INSTR_PROF_DATA_DEFINED #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/GCDAProfiling.c0000664000175000017500000003515712776214734022755 0ustar kaikai/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* |*===----------------------------------------------------------------------===*| |* |* This file implements the call back routines for the gcov profiling |* instrumentation pass. Link against this library when running code through |* the -insert-gcov-profiling LLVM pass. |* |* We emit files in a corrupt version of GCOV's "gcda" file format. These files |* are only close enough that LCOV will happily parse them. Anything that lcov |* ignores is missing. |* |* TODO: gcov is multi-process safe by having each exit open the existing file |* and append to it. We'd like to achieve that and be thread-safe too. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfilingUtil.h" #include #include #include #include #include #if defined(_WIN32) #include "WindowsMMap.h" #else #include #include #endif #define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__)) #if !defined(_MSC_VER) && !I386_FREEBSD #include #endif #if defined(_MSC_VER) typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #elif I386_FREEBSD /* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to * FreeBSD 10, r232261) when compiled in 32-bit mode. */ typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #endif /* #define DEBUG_GCDAPROFILING */ /* * --- GCOV file format I/O primitives --- */ /* * The current file name we're outputting. Used primarily for error logging. */ static char *filename = NULL; /* * The current file we're outputting. */ static FILE *output_file = NULL; /* * Buffer that we write things into. */ #define WRITE_BUFFER_SIZE (128 * 1024) static char *write_buffer = NULL; static uint64_t cur_buffer_size = 0; static uint64_t cur_pos = 0; static uint64_t file_size = 0; static int new_file = 0; static int fd = -1; /* * A list of functions to write out the data. */ typedef void (*writeout_fn)(); struct writeout_fn_node { writeout_fn fn; struct writeout_fn_node *next; }; static struct writeout_fn_node *writeout_fn_head = NULL; static struct writeout_fn_node *writeout_fn_tail = NULL; /* * A list of flush functions that our __gcov_flush() function should call. */ typedef void (*flush_fn)(); struct flush_fn_node { flush_fn fn; struct flush_fn_node *next; }; static struct flush_fn_node *flush_fn_head = NULL; static struct flush_fn_node *flush_fn_tail = NULL; static void resize_write_buffer(uint64_t size) { if (!new_file) return; size += cur_pos; if (size <= cur_buffer_size) return; size = (size - 1) / WRITE_BUFFER_SIZE + 1; size *= WRITE_BUFFER_SIZE; write_buffer = realloc(write_buffer, size); cur_buffer_size = size; } static void write_bytes(const char *s, size_t len) { resize_write_buffer(len); memcpy(&write_buffer[cur_pos], s, len); cur_pos += len; } static void write_32bit_value(uint32_t i) { write_bytes((char*)&i, 4); } static void write_64bit_value(uint64_t i) { write_bytes((char*)&i, 8); } static uint32_t length_of_string(const char *s) { return (strlen(s) / 4) + 1; } static void write_string(const char *s) { uint32_t len = length_of_string(s); write_32bit_value(len); write_bytes(s, strlen(s)); write_bytes("\0\0\0\0", 4 - (strlen(s) % 4)); } static uint32_t read_32bit_value() { uint32_t val; if (new_file) return (uint32_t)-1; val = *(uint32_t*)&write_buffer[cur_pos]; cur_pos += 4; return val; } static uint64_t read_64bit_value() { uint64_t val; if (new_file) return (uint64_t)-1; val = *(uint64_t*)&write_buffer[cur_pos]; cur_pos += 8; return val; } static char *mangle_filename(const char *orig_filename) { char *new_filename; size_t filename_len, prefix_len; int prefix_strip; int level = 0; const char *fname, *ptr; const char *prefix = getenv("GCOV_PREFIX"); const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP"); if (prefix == NULL || prefix[0] == '\0') return strdup(orig_filename); if (prefix_strip_str) { prefix_strip = atoi(prefix_strip_str); /* Negative GCOV_PREFIX_STRIP values are ignored */ if (prefix_strip < 0) prefix_strip = 0; } else { prefix_strip = 0; } fname = orig_filename; for (level = 0, ptr = fname + 1; level < prefix_strip; ++ptr) { if (*ptr == '\0') break; if (*ptr != '/') continue; fname = ptr; ++level; } filename_len = strlen(fname); prefix_len = strlen(prefix); new_filename = malloc(prefix_len + 1 + filename_len + 1); memcpy(new_filename, prefix, prefix_len); if (prefix[prefix_len - 1] != '/') new_filename[prefix_len++] = '/'; memcpy(new_filename + prefix_len, fname, filename_len + 1); return new_filename; } static int map_file() { fseek(output_file, 0L, SEEK_END); file_size = ftell(output_file); /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an * error message because it should "just work" for the user. */ if (file_size == 0) return -1; write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); if (write_buffer == (void *)-1) { int errnum = errno; fprintf(stderr, "profiling: %s: cannot map: %s\n", filename, strerror(errnum)); return -1; } return 0; } static void unmap_file() { if (msync(write_buffer, file_size, MS_SYNC) == -1) { int errnum = errno; fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename, strerror(errnum)); } /* We explicitly ignore errors from unmapping because at this point the data * is written and we don't care. */ (void)munmap(write_buffer, file_size); write_buffer = NULL; file_size = 0; } /* * --- LLVM line counter API --- */ /* A file in this case is a translation unit. Each .o file built with line * profiling enabled will emit to a different file. Only one file may be * started at a time. */ void llvm_gcda_start_file(const char *orig_filename, const char version[4], uint32_t checksum) { const char *mode = "r+b"; filename = mangle_filename(orig_filename); /* Try just opening the file. */ new_file = 0; fd = open(filename, O_RDWR); if (fd == -1) { /* Try opening the file, creating it if necessary. */ new_file = 1; mode = "w+b"; fd = open(filename, O_RDWR | O_CREAT, 0644); if (fd == -1) { /* Try creating the directories first then opening the file. */ __llvm_profile_recursive_mkdir(filename); fd = open(filename, O_RDWR | O_CREAT, 0644); if (fd == -1) { /* Bah! It's hopeless. */ int errnum = errno; fprintf(stderr, "profiling: %s: cannot open: %s\n", filename, strerror(errnum)); return; } } } /* Try to flock the file to serialize concurrent processes writing out to the * same GCDA. This can fail if the filesystem doesn't support it, but in that * case we'll just carry on with the old racy behaviour and hope for the best. */ flock(fd, LOCK_EX); output_file = fdopen(fd, mode); /* Initialize the write buffer. */ write_buffer = NULL; cur_buffer_size = 0; cur_pos = 0; if (new_file) { resize_write_buffer(WRITE_BUFFER_SIZE); memset(write_buffer, 0, WRITE_BUFFER_SIZE); } else { if (map_file() == -1) { /* mmap failed, try to recover by clobbering */ new_file = 1; write_buffer = NULL; cur_buffer_size = 0; resize_write_buffer(WRITE_BUFFER_SIZE); memset(write_buffer, 0, WRITE_BUFFER_SIZE); } } /* gcda file, version, stamp checksum. */ write_bytes("adcg", 4); write_bytes(version, 4); write_32bit_value(checksum); #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: [%s]\n", orig_filename); #endif } /* Given an array of pointers to counters (counters), increment the n-th one, * where we're also given a pointer to n (predecessor). */ void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, uint64_t **counters) { uint64_t *counter; uint32_t pred; pred = *predecessor; if (pred == 0xffffffff) return; counter = counters[pred]; /* Don't crash if the pred# is out of sync. This can happen due to threads, or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ if (counter) ++*counter; #ifdef DEBUG_GCDAPROFILING else fprintf(stderr, "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n", *counter, *predecessor); #endif } void llvm_gcda_emit_function(uint32_t ident, const char *function_name, uint32_t func_checksum, uint8_t use_extra_checksum, uint32_t cfg_checksum) { uint32_t len = 2; if (use_extra_checksum) len++; #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident, function_name ? function_name : "NULL"); #endif if (!output_file) return; /* function tag */ write_bytes("\0\0\0\1", 4); if (function_name) len += 1 + length_of_string(function_name); write_32bit_value(len); write_32bit_value(ident); write_32bit_value(func_checksum); if (use_extra_checksum) write_32bit_value(cfg_checksum); if (function_name) write_string(function_name); } void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { uint32_t i; uint64_t *old_ctrs = NULL; uint32_t val = 0; uint64_t save_cur_pos = cur_pos; if (!output_file) return; val = read_32bit_value(); if (val != (uint32_t)-1) { /* There are counters present in the file. Merge them. */ if (val != 0x01a10000) { fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " "corrupt arc tag (0x%08x)\n", filename, val); return; } val = read_32bit_value(); if (val == (uint32_t)-1 || val / 2 != num_counters) { fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " "mismatched number of counters (%d)\n", filename, val); return; } old_ctrs = malloc(sizeof(uint64_t) * num_counters); for (i = 0; i < num_counters; ++i) old_ctrs[i] = read_64bit_value(); } cur_pos = save_cur_pos; /* Counter #1 (arcs) tag */ write_bytes("\0\0\xa1\1", 4); write_32bit_value(num_counters * 2); for (i = 0; i < num_counters; ++i) { counters[i] += (old_ctrs ? old_ctrs[i] : 0); write_64bit_value(counters[i]); } free(old_ctrs); #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: %u arcs\n", num_counters); for (i = 0; i < num_counters; ++i) fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]); #endif } void llvm_gcda_summary_info() { const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */ uint32_t i; uint32_t runs = 1; uint32_t val = 0; uint64_t save_cur_pos = cur_pos; if (!output_file) return; val = read_32bit_value(); if (val != (uint32_t)-1) { /* There are counters present in the file. Merge them. */ if (val != 0xa1000000) { fprintf(stderr, "profiling: %s: cannot merge previous run count: " "corrupt object tag (0x%08x)\n", filename, val); return; } val = read_32bit_value(); /* length */ if (val != obj_summary_len) { fprintf(stderr, "profiling: %s: cannot merge previous run count: " "mismatched object length (%d)\n", filename, val); return; } read_32bit_value(); /* checksum, unused */ read_32bit_value(); /* num, unused */ runs += read_32bit_value(); /* Add previous run count to new counter. */ } cur_pos = save_cur_pos; /* Object summary tag */ write_bytes("\0\0\0\xa1", 4); write_32bit_value(obj_summary_len); write_32bit_value(0); /* checksum, unused */ write_32bit_value(0); /* num, unused */ write_32bit_value(runs); for (i = 3; i < obj_summary_len; ++i) write_32bit_value(0); /* Program summary tag */ write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */ write_32bit_value(0); /* 0 length */ #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: %u runs\n", runs); #endif } void llvm_gcda_end_file() { /* Write out EOF record. */ if (output_file) { write_bytes("\0\0\0\0\0\0\0\0", 8); if (new_file) { fwrite(write_buffer, cur_pos, 1, output_file); free(write_buffer); } else { unmap_file(); } fclose(output_file); flock(fd, LOCK_UN); output_file = NULL; write_buffer = NULL; } free(filename); #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: -----\n"); #endif } void llvm_register_writeout_function(writeout_fn fn) { struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); new_node->fn = fn; new_node->next = NULL; if (!writeout_fn_head) { writeout_fn_head = writeout_fn_tail = new_node; } else { writeout_fn_tail->next = new_node; writeout_fn_tail = new_node; } } void llvm_writeout_files() { struct writeout_fn_node *curr = writeout_fn_head; while (curr) { curr->fn(); curr = curr->next; } } void llvm_delete_writeout_function_list() { while (writeout_fn_head) { struct writeout_fn_node *node = writeout_fn_head; writeout_fn_head = writeout_fn_head->next; free(node); } writeout_fn_head = writeout_fn_tail = NULL; } void llvm_register_flush_function(flush_fn fn) { struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); new_node->fn = fn; new_node->next = NULL; if (!flush_fn_head) { flush_fn_head = flush_fn_tail = new_node; } else { flush_fn_tail->next = new_node; flush_fn_tail = new_node; } } void __gcov_flush() { struct flush_fn_node *curr = flush_fn_head; while (curr) { curr->fn(); curr = curr->next; } } void llvm_delete_flush_function_list() { while (flush_fn_head) { struct flush_fn_node *node = flush_fn_head; flush_fn_head = flush_fn_head->next; free(node); } flush_fn_head = flush_fn_tail = NULL; } void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) { static int atexit_ran = 0; if (wfn) llvm_register_writeout_function(wfn); if (ffn) llvm_register_flush_function(ffn); if (atexit_ran == 0) { atexit_ran = 1; /* Make sure we write out the data and delete the data structures. */ atexit(llvm_delete_flush_function_list); atexit(llvm_delete_writeout_function_list); atexit(llvm_writeout_files); } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/WindowsMMap.h0000664000175000017500000000316012776214734022604 0ustar kaikai/*===- WindowsMMap.h - Support library for PGO instrumentation ------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_WINDOWS_MMAP_H #define PROFILE_INSTRPROFILING_WINDOWS_MMAP_H #if defined(_WIN32) #include #include #include /* * mmap() flags */ #define PROT_READ 0x1 #define PROT_WRITE 0x2 /* This flag is only available in WinXP+ */ #ifdef FILE_MAP_EXECUTE #define PROT_EXEC 0x4 #else #define PROT_EXEC 0x0 #define FILE_MAP_EXECUTE 0 #endif #define MAP_FILE 0x00 #define MAP_SHARED 0x01 #define MAP_PRIVATE 0x02 #define MAP_ANONYMOUS 0x20 #define MAP_ANON MAP_ANONYMOUS #define MAP_FAILED ((void *) -1) /* * msync() flags */ #define MS_ASYNC 0x0001 /* return immediately */ #define MS_INVALIDATE 0x0002 /* invalidate all cached data */ #define MS_SYNC 0x0010 /* msync synchronously */ /* * flock() operations */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ #define LOCK_NB 4 /* don't block when locking */ #define LOCK_UN 8 /* unlock */ void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); void munmap(void *addr, size_t length); int msync(void *addr, size_t length, int flags); int flock(int fd, int operation); #endif /* _WIN32 */ #endif /* PROFILE_INSTRPROFILING_WINDOWS_MMAP_H */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingWriter.c0000664000175000017500000001413112776214734024540 0ustar kaikai/*===- InstrProfilingWriter.c - Write instrumentation to a file or buffer -===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" void (*FreeHook)(void *) = NULL; void* (*CallocHook)(size_t, size_t) = NULL; uint32_t VPBufferSize = 0; /* The buffer writer is reponsponsible in keeping writer state * across the call. */ COMPILER_RT_VISIBILITY uint32_t llvmBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx) { uint32_t I; char **Buffer = (char **)WriterCtx; for (I = 0; I < NumIOVecs; I++) { size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm; memcpy(*Buffer, IOVecs[I].Data, Length); *Buffer += Length; } return 0; } static void llvmInitBufferIO(ProfBufferIO *BufferIO, WriterCallback FileWriter, void *File, uint8_t *Buffer, uint32_t BufferSz) { BufferIO->File = File; BufferIO->FileWriter = FileWriter; BufferIO->BufferStart = Buffer; BufferIO->BufferSz = BufferSz; BufferIO->CurOffset = 0; } COMPILER_RT_VISIBILITY ProfBufferIO * llvmCreateBufferIO(WriterCallback FileWriter, void *File, uint32_t BufferSz) { ProfBufferIO *BufferIO = (ProfBufferIO *)CallocHook(1, sizeof(ProfBufferIO)); uint8_t *Buffer = (uint8_t *)CallocHook(1, BufferSz); if (!Buffer) { FreeHook(BufferIO); return 0; } llvmInitBufferIO(BufferIO, FileWriter, File, Buffer, BufferSz); return BufferIO; } COMPILER_RT_VISIBILITY void llvmDeleteBufferIO(ProfBufferIO *BufferIO) { FreeHook(BufferIO->BufferStart); FreeHook(BufferIO); } COMPILER_RT_VISIBILITY int llvmBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) { /* Buffer is not large enough, it is time to flush. */ if (Size + BufferIO->CurOffset > BufferIO->BufferSz) { if (llvmBufferIOFlush(BufferIO) != 0) return -1; } /* Special case, bypass the buffer completely. */ ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}}; if (Size > BufferIO->BufferSz) { if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) return -1; } else { /* Write the data to buffer */ uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset; llvmBufferWriter(IO, 1, (void **)&Buffer); BufferIO->CurOffset = Buffer - BufferIO->BufferStart; } return 0; } COMPILER_RT_VISIBILITY int llvmBufferIOFlush(ProfBufferIO *BufferIO) { if (BufferIO->CurOffset) { ProfDataIOVec IO[] = { {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}}; if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) return -1; BufferIO->CurOffset = 0; } return 0; } COMPILER_RT_VISIBILITY int llvmWriteProfData(WriterCallback Writer, void *WriterCtx, ValueProfData **ValueDataArray, const uint64_t ValueDataSize) { /* Match logic in __llvm_profile_write_buffer(). */ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); return llvmWriteProfDataImpl(Writer, WriterCtx, DataBegin, DataEnd, CountersBegin, CountersEnd, ValueDataArray, ValueDataSize, NamesBegin, NamesEnd); } #define VP_BUFFER_SIZE 8 * 1024 static int writeValueProfData(WriterCallback Writer, void *WriterCtx, ValueProfData **ValueDataBegin, uint64_t NumVData) { ProfBufferIO *BufferIO; uint32_t I = 0, BufferSz; if (!ValueDataBegin) return 0; BufferSz = VPBufferSize ? VPBufferSize : VP_BUFFER_SIZE; BufferIO = llvmCreateBufferIO(Writer, WriterCtx, BufferSz); for (I = 0; I < NumVData; I++) { ValueProfData *CurVData = ValueDataBegin[I]; if (!CurVData) continue; if (llvmBufferIOWrite(BufferIO, (const uint8_t *)CurVData, CurVData->TotalSize) != 0) return -1; } if (llvmBufferIOFlush(BufferIO) != 0) return -1; llvmDeleteBufferIO(BufferIO); return 0; } COMPILER_RT_VISIBILITY int llvmWriteProfDataImpl( WriterCallback Writer, void *WriterCtx, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, ValueProfData **ValueDataBegin, const uint64_t ValueDataSize, const char *NamesBegin, const char *NamesEnd) { /* Calculate size of sections. */ const uint64_t DataSize = DataEnd - DataBegin; const uint64_t CountersSize = CountersEnd - CountersBegin; const uint64_t NamesSize = NamesEnd - NamesBegin; const uint64_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize); /* Enough zeroes for padding. */ const char Zeroes[sizeof(uint64_t)] = {0}; /* Create the header. */ __llvm_profile_header Header; if (!DataSize) return 0; /* Initialize header struture. */ #define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init; #include "InstrProfData.inc" /* Write the data. */ ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1}, {DataBegin, sizeof(__llvm_profile_data), DataSize}, {CountersBegin, sizeof(uint64_t), CountersSize}, {NamesBegin, sizeof(uint8_t), NamesSize}, {Zeroes, sizeof(uint8_t), Padding}}; if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx)) return -1; return writeValueProfData(Writer, WriterCtx, ValueDataBegin, DataSize); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfiling.h0000664000175000017500000001030412776214734023346 0ustar kaikai/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_H_ #define PROFILE_INSTRPROFILING_H_ #include "InstrProfilingPort.h" #include "InstrProfData.inc" enum ValueKind { #define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value, #include "InstrProfData.inc" }; typedef void *IntPtrT; typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT) __llvm_profile_data { #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) Type Name; #include "InstrProfData.inc" } __llvm_profile_data; typedef struct __llvm_profile_header { #define INSTR_PROF_RAW_HEADER(Type, Name, Initializer) Type Name; #include "InstrProfData.inc" } __llvm_profile_header; /*! * \brief Get number of bytes necessary to pad the argument to eight * byte boundary. */ uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes); /*! * \brief Get required size for profile buffer. */ uint64_t __llvm_profile_get_size_for_buffer(void); /*! * \brief Write instrumentation data to the given buffer. * * \pre \c Buffer is the start of a buffer at least as big as \a * __llvm_profile_get_size_for_buffer(). */ int __llvm_profile_write_buffer(char *Buffer); const __llvm_profile_data *__llvm_profile_begin_data(void); const __llvm_profile_data *__llvm_profile_end_data(void); const char *__llvm_profile_begin_names(void); const char *__llvm_profile_end_names(void); uint64_t *__llvm_profile_begin_counters(void); uint64_t *__llvm_profile_end_counters(void); /*! * \brief Clear profile counters to zero. * */ void __llvm_profile_reset_counters(void); /*! * \brief Counts the number of times a target value is seen. * * Records the target value for the CounterIndex if not seen before. Otherwise, * increments the counter associated w/ the target value. * void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data, * uint32_t CounterIndex); */ void INSTR_PROF_VALUE_PROF_FUNC( #define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType) ArgType ArgName #include "InstrProfData.inc" ); /*! * \brief Prepares the value profiling data for output. * * Returns an array of pointers to value profile data. */ struct ValueProfData; struct ValueProfData **__llvm_profile_gather_value_data(uint64_t *Size); /*! * \brief Write instrumentation data to the current file. * * Writes to the file with the last name given to \a * * __llvm_profile_set_filename(), * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable, * or if that's not set, the last name given to * \a __llvm_profile_override_default_filename(), or if that's not set, * \c "default.profraw". */ int __llvm_profile_write_file(void); /*! * \brief Set the filename for writing instrumentation data. * * Sets the filename to be used for subsequent calls to * \a __llvm_profile_write_file(). * * \c Name is not copied, so it must remain valid. Passing NULL resets the * filename logic to the default behaviour. */ void __llvm_profile_set_filename(const char *Name); /*! * \brief Set the filename for writing instrumentation data, unless the * \c LLVM_PROFILE_FILE environment variable was set. * * Unless overridden, sets the filename to be used for subsequent calls to * \a __llvm_profile_write_file(). * * \c Name is not copied, so it must remain valid. Passing NULL resets the * filename logic to the default behaviour (unless the \c LLVM_PROFILE_FILE * was set in which case it has no effect). */ void __llvm_profile_override_default_filename(const char *Name); /*! \brief Register to write instrumentation data to file at exit. */ int __llvm_profile_register_write_file_atexit(void); /*! \brief Initialize file handling. */ void __llvm_profile_initialize_file(void); /*! \brief Get the magic token for the file format. */ uint64_t __llvm_profile_get_magic(void); /*! \brief Get the version of the file format. */ uint64_t __llvm_profile_get_version(void); #endif /* PROFILE_INSTRPROFILING_H_ */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/WindowsMMap.c0000664000175000017500000000604512776214734022604 0ustar kaikai/* * This code is derived from uClibc (original license follows). * https://git.uclibc.org/uClibc/tree/utils/mmap-windows.c */ /* mmap() replacement for Windows * * Author: Mike Frysinger * Placed into the public domain */ /* References: * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx */ #if defined(_WIN32) #include "WindowsMMap.h" #include "InstrProfiling.h" #ifdef __USE_FILE_OFFSET64 # define DWORD_HI(x) (x >> 32) # define DWORD_LO(x) ((x) & 0xffffffff) #else # define DWORD_HI(x) (0) # define DWORD_LO(x) (x) #endif COMPILER_RT_VISIBILITY void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) { if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) return MAP_FAILED; if (fd == -1) { if (!(flags & MAP_ANON) || offset) return MAP_FAILED; } else if (flags & MAP_ANON) return MAP_FAILED; DWORD flProtect; if (prot & PROT_WRITE) { if (prot & PROT_EXEC) flProtect = PAGE_EXECUTE_READWRITE; else flProtect = PAGE_READWRITE; } else if (prot & PROT_EXEC) { if (prot & PROT_READ) flProtect = PAGE_EXECUTE_READ; else if (prot & PROT_EXEC) flProtect = PAGE_EXECUTE; } else flProtect = PAGE_READONLY; off_t end = length + offset; HANDLE mmap_fd, h; if (fd == -1) mmap_fd = INVALID_HANDLE_VALUE; else mmap_fd = (HANDLE)_get_osfhandle(fd); h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL); if (h == NULL) return MAP_FAILED; DWORD dwDesiredAccess; if (prot & PROT_WRITE) dwDesiredAccess = FILE_MAP_WRITE; else dwDesiredAccess = FILE_MAP_READ; if (prot & PROT_EXEC) dwDesiredAccess |= FILE_MAP_EXECUTE; if (flags & MAP_PRIVATE) dwDesiredAccess |= FILE_MAP_COPY; void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); if (ret == NULL) { CloseHandle(h); ret = MAP_FAILED; } return ret; } COMPILER_RT_VISIBILITY void munmap(void *addr, size_t length) { UnmapViewOfFile(addr); /* ruh-ro, we leaked handle from CreateFileMapping() ... */ } COMPILER_RT_VISIBILITY int msync(void *addr, size_t length, int flags) { if (flags & MS_INVALIDATE) return -1; /* Not supported. */ /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */ switch (flags & (MS_ASYNC | MS_SYNC)) { case MS_SYNC: case MS_ASYNC: break; default: return -1; } if (!FlushViewOfFile(addr, length)) return -1; if (flags & MS_SYNC) { /* FIXME: No longer have access to handle from CreateFileMapping(). */ /* * if (!FlushFileBuffers(h)) * return -1; */ } return 0; } COMPILER_RT_VISIBILITY int flock(int fd, int operation) { return -1; /* Not supported. */ } #undef DWORD_HI #undef DWORD_LO #endif /* _WIN32 */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingValue.c0000664000175000017500000001247012776214734024344 0ustar kaikai/*===- InstrProfilingValue.c - Support library for PGO instrumentation ----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include #include #include #include #define INSTR_PROF_VALUE_PROF_DATA #define INSTR_PROF_COMMON_API_IMPL #include "InstrProfData.inc" #define PROF_OOM(Msg) PROF_ERR(Msg ":%s\n", "Out of memory"); #define PROF_OOM_RETURN(Msg) \ { \ PROF_OOM(Msg) \ free(ValueDataArray); \ return NULL; \ } #if COMPILER_RT_HAS_ATOMICS != 1 COMPILER_RT_VISIBILITY uint32_t BoolCmpXchg(void **Ptr, void *OldV, void *NewV) { void *R = *Ptr; if (R == OldV) { *Ptr = NewV; return 1; } return 0; } #endif /* This method is only used in value profiler mock testing. */ COMPILER_RT_VISIBILITY void __llvm_profile_set_num_value_sites(__llvm_profile_data *Data, uint32_t ValueKind, uint16_t NumValueSites) { *((uint16_t *)&Data->NumValueSites[ValueKind]) = NumValueSites; } /* This method is only used in value profiler mock testing. */ COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_iterate_data(const __llvm_profile_data *Data) { return Data + 1; } /* This method is only used in value profiler mock testing. */ COMPILER_RT_VISIBILITY void * __llvm_get_function_addr(const __llvm_profile_data *Data) { return Data->FunctionPointer; } /* Allocate an array that holds the pointers to the linked lists of * value profile counter nodes. The number of element of the array * is the total number of value profile sites instrumented. Returns * 0 if allocation fails. */ static int allocateValueProfileCounters(__llvm_profile_data *Data) { uint64_t NumVSites = 0; uint32_t VKI; for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI) NumVSites += Data->NumValueSites[VKI]; ValueProfNode **Mem = (ValueProfNode **)calloc(NumVSites, sizeof(ValueProfNode *)); if (!Mem) return 0; if (!COMPILER_RT_BOOL_CMPXCHG(&Data->Values, 0, Mem)) { free(Mem); return 0; } return 1; } COMPILER_RT_VISIBILITY void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data, uint32_t CounterIndex) { __llvm_profile_data *PData = (__llvm_profile_data *)Data; if (!PData) return; if (!PData->Values) { if (!allocateValueProfileCounters(PData)) return; } ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values; ValueProfNode *PrevVNode = NULL; ValueProfNode *CurrentVNode = ValueCounters[CounterIndex]; uint8_t VDataCount = 0; while (CurrentVNode) { if (TargetValue == CurrentVNode->VData.Value) { CurrentVNode->VData.Count++; return; } PrevVNode = CurrentVNode; CurrentVNode = CurrentVNode->Next; ++VDataCount; } if (VDataCount >= INSTR_PROF_MAX_NUM_VAL_PER_SITE) return; CurrentVNode = (ValueProfNode *)calloc(1, sizeof(ValueProfNode)); if (!CurrentVNode) return; CurrentVNode->VData.Value = TargetValue; CurrentVNode->VData.Count++; uint32_t Success = 0; if (!ValueCounters[CounterIndex]) Success = COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurrentVNode); else if (PrevVNode && !PrevVNode->Next) Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurrentVNode); if (!Success) { free(CurrentVNode); return; } } COMPILER_RT_VISIBILITY ValueProfData ** __llvm_profile_gather_value_data(uint64_t *ValueDataSize) { size_t S = 0; __llvm_profile_data *I; ValueProfData **ValueDataArray; const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); if (!ValueDataSize) return NULL; ValueDataArray = (ValueProfData **)calloc(DataEnd - DataBegin, sizeof(void *)); if (!ValueDataArray) PROF_OOM_RETURN("Failed to write value profile data "); /* * Compute the total Size of the buffer to hold ValueProfData * structures for functions with value profile data. */ for (I = (__llvm_profile_data *)DataBegin; I != DataEnd; ++I) { ValueProfRuntimeRecord R; if (initializeValueProfRuntimeRecord(&R, I->NumValueSites, I->Values)) PROF_OOM_RETURN("Failed to write value profile data "); /* Compute the size of ValueProfData from this runtime record. */ if (getNumValueKindsRT(&R) != 0) { ValueProfData *VD = NULL; uint32_t VS = getValueProfDataSizeRT(&R); VD = (ValueProfData *)calloc(VS, sizeof(uint8_t)); if (!VD) PROF_OOM_RETURN("Failed to write value profile data "); serializeValueProfDataFromRT(&R, VD); ValueDataArray[I - DataBegin] = VD; S += VS; } finalizeValueProfRuntimeRecord(&R); } if (!S) { free(ValueDataArray); ValueDataArray = NULL; } *ValueDataSize = S; return ValueDataArray; } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingPlatformOther.c0000664000175000017500000000501312776214734026051 0ustar kaikai/*===- InstrProfilingPlatformOther.c - Profile data default platform ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) #include static const __llvm_profile_data *DataFirst = NULL; static const __llvm_profile_data *DataLast = NULL; static const char *NamesFirst = NULL; static const char *NamesLast = NULL; static uint64_t *CountersFirst = NULL; static uint64_t *CountersLast = NULL; /*! * \brief Register an instrumented function. * * Calls to this are emitted by clang with -fprofile-instr-generate. Such * calls are only required (and only emitted) on targets where we haven't * implemented linker magic to find the bounds of the sections. */ COMPILER_RT_VISIBILITY void __llvm_profile_register_function(void *Data_) { /* TODO: Only emit this function if we can't use linker magic. */ const __llvm_profile_data *Data = (__llvm_profile_data *)Data_; if (!DataFirst) { DataFirst = Data; DataLast = Data + 1; NamesFirst = Data->NamePtr; NamesLast = (const char *)Data->NamePtr + Data->NameSize; CountersFirst = Data->CounterPtr; CountersLast = (uint64_t *)Data->CounterPtr + Data->NumCounters; return; } #define UPDATE_FIRST(First, New) First = New < First ? New : First UPDATE_FIRST(DataFirst, Data); UPDATE_FIRST(NamesFirst, (const char *)Data->NamePtr); UPDATE_FIRST(CountersFirst, (uint64_t *)Data->CounterPtr); #undef UPDATE_FIRST #define UPDATE_LAST(Last, New) Last = New > Last ? New : Last UPDATE_LAST(DataLast, Data + 1); UPDATE_LAST(NamesLast, (const char *)Data->NamePtr + Data->NameSize); UPDATE_LAST(CountersLast, (uint64_t *)Data->CounterPtr + Data->NumCounters); #undef UPDATE_LAST } COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_begin_data(void) { return DataFirst; } COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_end_data(void) { return DataLast; } COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) { return NamesFirst; } COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) { return NamesLast; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return CountersLast; } #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingBuffer.c0000664000175000017500000000442212776214734024477 0ustar kaikai/*===- InstrProfilingBuffer.c - Write instrumentation to a memory buffer --===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_size_for_buffer(void) { const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); return __llvm_profile_get_size_for_buffer_internal( DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd); } #define PROFILE_RANGE_SIZE(Range) (Range##End - Range##Begin) COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { /* Match logic in __llvm_profile_write_buffer(). */ const uint64_t NamesSize = PROFILE_RANGE_SIZE(Names) * sizeof(char); const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize); return sizeof(__llvm_profile_header) + PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) + PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) + NamesSize + Padding; } COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) { return llvmWriteProfData(llvmBufferWriter, Buffer, 0, 0); } COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { return llvmWriteProfDataImpl(llvmBufferWriter, Buffer, DataBegin, DataEnd, CountersBegin, CountersEnd, 0, 0, NamesBegin, NamesEnd); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfiling.c0000664000175000017500000000420312776214734023342 0ustar kaikai/*===- InstrProfiling.c - Support library for PGO instrumentation ---------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include #include #include #include #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" char *(*GetEnvHook)(const char *) = 0; COMPILER_RT_WEAK uint64_t __llvm_profile_raw_version = INSTR_PROF_RAW_VERSION; COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) { return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64) : (INSTR_PROF_RAW_MAGIC_32); } /* Return the number of bytes needed to add to SizeInBytes to make it * the result a multiple of 8. */ COMPILER_RT_VISIBILITY uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes) { return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t)); } COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_version(void) { return __llvm_profile_raw_version; } COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) { uint64_t *I = __llvm_profile_begin_counters(); uint64_t *E = __llvm_profile_end_counters(); memset(I, 0, sizeof(uint64_t) * (E - I)); const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const __llvm_profile_data *DI; for (DI = DataBegin; DI != DataEnd; ++DI) { uint64_t CurrentVSiteCount = 0; uint32_t VKI, i; if (!DI->Values) continue; ValueProfNode **ValueCounters = (ValueProfNode **)DI->Values; for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI) CurrentVSiteCount += DI->NumValueSites[VKI]; for (i = 0; i < CurrentVSiteCount; ++i) { ValueProfNode *CurrentVNode = ValueCounters[i]; while (CurrentVNode) { CurrentVNode->VData.Count = 0; CurrentVNode = CurrentVNode->Next; } } } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingUtil.h0000664000175000017500000000105112776214734024203 0ustar kaikai/*===- InstrProfilingUtil.h - Support library for PGO instrumentation -----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILINGUTIL_H #define PROFILE_INSTRPROFILINGUTIL_H /*! \brief Create a directory tree. */ void __llvm_profile_recursive_mkdir(char *Pathname); #endif /* PROFILE_INSTRPROFILINGUTIL_H */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingFile.c0000664000175000017500000001520112776214734024142 0ustar kaikai/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include "InstrProfilingUtil.h" #include #include #include #include #define UNCONST(ptr) ((void *)(uintptr_t)(ptr)) #ifdef _MSC_VER #define snprintf _snprintf #endif /* Return 1 if there is an error, otherwise return 0. */ static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx) { uint32_t I; FILE *File = (FILE *)*WriterCtx; for (I = 0; I < NumIOVecs; I++) { if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != IOVecs[I].NumElm) return 1; } return 0; } COMPILER_RT_VISIBILITY ProfBufferIO * llvmCreateBufferIOInternal(void *File, uint32_t BufferSz) { CallocHook = calloc; FreeHook = free; return llvmCreateBufferIO(fileWriter, File, BufferSz); } static int writeFile(FILE *File) { const char *BufferSzStr = 0; uint64_t ValueDataSize = 0; struct ValueProfData **ValueDataArray = __llvm_profile_gather_value_data(&ValueDataSize); FreeHook = &free; CallocHook = &calloc; BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); if (BufferSzStr && BufferSzStr[0]) VPBufferSize = atoi(BufferSzStr); return llvmWriteProfData(fileWriter, File, ValueDataArray, ValueDataSize); } static int writeFileWithName(const char *OutputName) { int RetVal; FILE *OutputFile; if (!OutputName || !OutputName[0]) return -1; /* Append to the file to support profiling multiple shared objects. */ OutputFile = fopen(OutputName, "ab"); if (!OutputFile) return -1; RetVal = writeFile(OutputFile); fclose(OutputFile); return RetVal; } COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0; COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL; static void truncateCurrentFile(void) { const char *Filename; FILE *File; Filename = __llvm_profile_CurrentFilename; if (!Filename || !Filename[0]) return; /* Create the directory holding the file, if needed. */ if (strchr(Filename, '/')) { char *Copy = malloc(strlen(Filename) + 1); strcpy(Copy, Filename); __llvm_profile_recursive_mkdir(Copy); free(Copy); } /* Truncate the file. Later we'll reopen and append. */ File = fopen(Filename, "w"); if (!File) return; fclose(File); } static void setFilename(const char *Filename, int OwnsFilename) { /* Check if this is a new filename and therefore needs truncation. */ int NewFile = !__llvm_profile_CurrentFilename || (Filename && strcmp(Filename, __llvm_profile_CurrentFilename)); if (__llvm_profile_OwnsFilename) free(UNCONST(__llvm_profile_CurrentFilename)); __llvm_profile_CurrentFilename = Filename; __llvm_profile_OwnsFilename = OwnsFilename; /* If not a new file, append to support profiling multiple shared objects. */ if (NewFile) truncateCurrentFile(); } static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); } int getpid(void); static int setFilenamePossiblyWithPid(const char *Filename) { #define MAX_PID_SIZE 16 char PidChars[MAX_PID_SIZE] = {0}; int NumPids = 0, PidLength = 0; char *Allocated; int I, J; /* Reset filename on NULL, except with env var which is checked by caller. */ if (!Filename) { resetFilenameToDefault(); return 0; } /* Check the filename for "%p", which indicates a pid-substitution. */ for (I = 0; Filename[I]; ++I) if (Filename[I] == '%' && Filename[++I] == 'p') if (!NumPids++) { PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()); if (PidLength <= 0) return -1; } if (!NumPids) { setFilename(Filename, 0); return 0; } /* Allocate enough space for the substituted filename. */ Allocated = malloc(I + NumPids*(PidLength - 2) + 1); if (!Allocated) return -1; /* Construct the new filename. */ for (I = 0, J = 0; Filename[I]; ++I) if (Filename[I] == '%') { if (Filename[++I] == 'p') { memcpy(Allocated + J, PidChars, PidLength); J += PidLength; } /* Drop any unknown substitutions. */ } else Allocated[J++] = Filename[I]; Allocated[J] = 0; /* Use the computed name. */ setFilename(Allocated, 1); return 0; } static int setFilenameFromEnvironment(void) { const char *Filename = getenv("LLVM_PROFILE_FILE"); if (!Filename || !Filename[0]) return -1; return setFilenamePossiblyWithPid(Filename); } static void setFilenameAutomatically(void) { if (!setFilenameFromEnvironment()) return; resetFilenameToDefault(); } COMPILER_RT_VISIBILITY void __llvm_profile_initialize_file(void) { /* Check if the filename has been initialized. */ if (__llvm_profile_CurrentFilename) return; /* Detect the filename and truncate. */ setFilenameAutomatically(); } COMPILER_RT_VISIBILITY void __llvm_profile_set_filename(const char *Filename) { setFilenamePossiblyWithPid(Filename); } COMPILER_RT_VISIBILITY void __llvm_profile_override_default_filename(const char *Filename) { /* If the env var is set, skip setting filename from argument. */ const char *Env_Filename = getenv("LLVM_PROFILE_FILE"); if (Env_Filename && Env_Filename[0]) return; setFilenamePossiblyWithPid(Filename); } COMPILER_RT_VISIBILITY int __llvm_profile_write_file(void) { int rc; GetEnvHook = &getenv; /* Check the filename. */ if (!__llvm_profile_CurrentFilename) { PROF_ERR("LLVM Profile: Failed to write file : %s\n", "Filename not set"); return -1; } /* Check if there is llvm/runtime version mismatch. */ if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { PROF_ERR("LLVM Profile: runtime and instrumentation version mismatch : " "expected %d, but get %d\n", INSTR_PROF_RAW_VERSION, (int)GET_VERSION(__llvm_profile_get_version())); return -1; } /* Write the file. */ rc = writeFileWithName(__llvm_profile_CurrentFilename); if (rc) PROF_ERR("LLVM Profile: Failed to write file \"%s\": %s\n", __llvm_profile_CurrentFilename, strerror(errno)); return rc; } static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } COMPILER_RT_VISIBILITY int __llvm_profile_register_write_file_atexit(void) { static int HasBeenRegistered = 0; if (HasBeenRegistered) return 0; HasBeenRegistered = 1; return atexit(writeFileWithoutReturn); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingRuntime.cc0000664000175000017500000000117212776214734025053 0ustar kaikai//===- InstrProfilingRuntime.cpp - PGO runtime initialization -------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// extern "C" { #include "InstrProfiling.h" COMPILER_RT_VISIBILITY int __llvm_profile_runtime; } namespace { class RegisterRuntime { public: RegisterRuntime() { __llvm_profile_register_write_file_atexit(); __llvm_profile_initialize_file(); } }; RegisterRuntime Registration; } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingInternal.h0000664000175000017500000001044212776214734025046 0ustar kaikai/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_INTERNALH_ #define PROFILE_INSTRPROFILING_INTERNALH_ #include "InstrProfiling.h" #include "stddef.h" /*! * \brief Write instrumentation data to the given buffer, given explicit * pointers to the live data in memory. This function is probably not what you * want. Use __llvm_profile_get_size_for_buffer instead. Use this function if * your program has a custom memory layout. */ uint64_t __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); /*! * \brief Write instrumentation data to the given buffer, given explicit * pointers to the live data in memory. This function is probably not what you * want. Use __llvm_profile_write_buffer instead. Use this function if your * program has a custom memory layout. * * \pre \c Buffer is the start of a buffer at least as big as \a * __llvm_profile_get_size_for_buffer_internal(). */ int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); /*! * The data structure describing the data to be written by the * low level writer callback function. */ typedef struct ProfDataIOVec { const void *Data; size_t ElmSize; size_t NumElm; } ProfDataIOVec; typedef uint32_t (*WriterCallback)(ProfDataIOVec *, uint32_t NumIOVecs, void **WriterCtx); /*! * The data structure for buffered IO of profile data. */ typedef struct ProfBufferIO { /* File handle. */ void *File; /* Low level IO callback. */ WriterCallback FileWriter; /* The start of the buffer. */ uint8_t *BufferStart; /* Total size of the buffer. */ uint32_t BufferSz; /* Current byte offset from the start of the buffer. */ uint32_t CurOffset; } ProfBufferIO; /* The creator interface used by testing. */ ProfBufferIO *llvmCreateBufferIOInternal(void *File, uint32_t DefaultBufferSz); /*! * This is the interface to create a handle for buffered IO. */ ProfBufferIO *llvmCreateBufferIO(WriterCallback FileWriter, void *File, uint32_t DefaultBufferSz); /*! * The interface to destroy the bufferIO handle and reclaim * the memory. */ void llvmDeleteBufferIO(ProfBufferIO *BufferIO); /*! * This is the interface to write \c Data of \c Size bytes through * \c BufferIO. Returns 0 if successful, otherwise return -1. */ int llvmBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size); /*! * The interface to flush the remaining data in the buffer. * through the low level writer callback. */ int llvmBufferIOFlush(ProfBufferIO *BufferIO); /* The low level interface to write data into a buffer. It is used as the * callback by other high level writer methods such as buffered IO writer * and profile data writer. */ uint32_t llvmBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx); int llvmWriteProfData(WriterCallback Writer, void *WriterCtx, struct ValueProfData **ValueDataArray, const uint64_t ValueDataSize); int llvmWriteProfDataImpl(WriterCallback Writer, void *WriterCtx, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, struct ValueProfData **ValueDataBeginArray, const uint64_t ValueDataSize, const char *NamesBegin, const char *NamesEnd); extern char *(*GetEnvHook)(const char *); extern void (*FreeHook)(void *); extern void* (*CallocHook)(size_t, size_t); extern uint32_t VPBufferSize; #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingPort.h0000664000175000017500000000415212776214734024217 0ustar kaikai/*===- InstrProfilingPort.h- Support library for PGO instrumentation ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_PORT_H_ #define PROFILE_INSTRPROFILING_PORT_H_ #ifdef _MSC_VER #define COMPILER_RT_ALIGNAS(x) __declspec(align(x)) #define COMPILER_RT_VISIBILITY #define COMPILER_RT_WEAK __declspec(selectany) #elif __GNUC__ #define COMPILER_RT_ALIGNAS(x) __attribute__((aligned(x))) #define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden"))) #define COMPILER_RT_WEAK __attribute__((weak)) #endif #define COMPILER_RT_SECTION(Sect) __attribute__((section(Sect))) #if COMPILER_RT_HAS_ATOMICS == 1 #ifdef _MSC_VER #include #if defined(_WIN64) #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ (InterlockedCompareExchange64((LONGLONG volatile *)Ptr, (LONGLONG)NewV, \ (LONGLONG)OldV) == (LONGLONG)OldV) #else /* !defined(_WIN64) */ #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ (InterlockedCompareExchange((LONG volatile *)Ptr, (LONG)NewV, (LONG)OldV) == \ (LONG)OldV) #endif #else /* !defined(_MSC_VER) */ #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ __sync_bool_compare_and_swap(Ptr, OldV, NewV) #endif #else /* COMPILER_RT_HAS_ATOMICS != 1 */ #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ BoolCmpXchg((void **)Ptr, OldV, NewV) #endif #define PROF_ERR(Format, ...) \ if (GetEnvHook && GetEnvHook("LLVM_PROFILE_VERBOSE_ERRORS")) \ fprintf(stderr, Format, __VA_ARGS__); #if defined(__FreeBSD__) #include #include #else /* defined(__FreeBSD__) */ #include #include #endif /* defined(__FreeBSD__) && defined(__i386__) */ #endif /* PROFILE_INSTRPROFILING_PORT_H_ */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingPlatformLinux.c0000664000175000017500000000435612776214734026100 0ustar kaikai/*===- InstrProfilingPlatformLinux.c - Profile data Linux platform ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if defined(__linux__) || defined(__FreeBSD__) #include #define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) #define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_SECT_NAME) #define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_SECT_NAME) #define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_SECT_NAME) #define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_SECT_NAME) #define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_SECT_NAME) /* Declare section start and stop symbols for various sections * generated by compiler instrumentation. */ extern __llvm_profile_data PROF_DATA_START COMPILER_RT_VISIBILITY; extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY; extern uint64_t PROF_CNTS_START COMPILER_RT_VISIBILITY; extern uint64_t PROF_CNTS_STOP COMPILER_RT_VISIBILITY; extern char PROF_NAME_START COMPILER_RT_VISIBILITY; extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY; /* Add dummy data to ensure the section is always created. */ __llvm_profile_data __prof_data_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_DATA_SECT_NAME_STR); uint64_t __prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME_STR); char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME_STR); COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_begin_data(void) { return &PROF_DATA_START; } COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_end_data(void) { return &PROF_DATA_STOP; } COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) { return &PROF_NAME_START; } COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) { return &PROF_NAME_STOP; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return &PROF_CNTS_START; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return &PROF_CNTS_STOP; } #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingPlatformDarwin.c0000664000175000017500000000331312776214734026215 0ustar kaikai/*===- InstrProfilingPlatformDarwin.c - Profile data on Darwin ------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if defined(__APPLE__) /* Use linker magic to find the bounds of the Data section. */ COMPILER_RT_VISIBILITY extern __llvm_profile_data DataStart __asm("section$start$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern __llvm_profile_data DataEnd __asm("section$end$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern char NamesStart __asm("section$start$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern char NamesEnd __asm("section$end$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern uint64_t CountersStart __asm("section$start$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern uint64_t CountersEnd __asm("section$end$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR); COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_begin_data(void) { return &DataStart; } COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_end_data(void) { return &DataEnd; } COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) { return &NamesStart; } COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) { return &NamesEnd; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; } #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-38/InstrProfilingUtil.c0000664000175000017500000000154212776214734024203 0ustar kaikai/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfilingUtil.h" #include "InstrProfiling.h" #ifdef _WIN32 #include #elif I386_FREEBSD int mkdir(const char*, unsigned short); #else #include #include #endif COMPILER_RT_VISIBILITY void __llvm_profile_recursive_mkdir(char *path) { int i; for (i = 1; path[i] != '\0'; ++i) { if (path[i] != '/') continue; path[i] = '\0'; #ifdef _WIN32 _mkdir(path); #else mkdir(path, 0755); /* Some of these will fail, ignore it. */ #endif path[i] = '/'; } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/0000775000175000017500000000000012776214734020227 5ustar kaikaildc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfData.inc0000664000175000017500000006054512776214734023454 0ustar kaikai/*===-- InstrProfData.inc - instr profiling runtime structures -*- C++ -*-=== *\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ /* * This is the master file that defines all the data structure, signature, * constant literals that are shared across profiling runtime library, * compiler (instrumentation), and host tools (reader/writer). The entities * defined in this file affect the profile runtime ABI, the raw profile format, * or both. * * The file has two identical copies. The master copy lives in LLVM and * the other one sits in compiler-rt/lib/profile directory. To make changes * in this file, first modify the master copy and copy it over to compiler-rt. * Testing of any change in this file can start only after the two copies are * synced up. * * The first part of the file includes macros that defines types, names, and * initializers for the member fields of the core data structures. The field * declarations for one structure is enabled by defining the field activation * macro associated with that structure. Only one field activation record * can be defined at one time and the rest definitions will be filtered out by * the preprocessor. * * Examples of how the template is used to instantiate structure definition: * 1. To declare a structure: * * struct ProfData { * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \ * Type Name; * #include "llvm/ProfileData/InstrProfData.inc" * }; * * 2. To construct LLVM type arrays for the struct type: * * Type *DataTypes[] = { * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \ * LLVMType, * #include "llvm/ProfileData/InstrProfData.inc" * }; * * 4. To construct constant array for the initializers: * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \ * Initializer, * Constant *ConstantVals[] = { * #include "llvm/ProfileData/InstrProfData.inc" * }; * * * The second part of the file includes definitions all other entities that * are related to runtime ABI and format. When no field activation macro is * defined, this file can be included to introduce the definitions. * \*===----------------------------------------------------------------------===*/ /* Functions marked with INSTR_PROF_VISIBILITY must have hidden visibility in * the compiler runtime. */ #ifndef INSTR_PROF_VISIBILITY #define INSTR_PROF_VISIBILITY #endif /* INSTR_PROF_DATA start. */ /* Definition of member fields of the per-function control structure. */ #ifndef INSTR_PROF_DATA #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), NameRef, \ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ IndexedInstrProf::ComputeHash(getPGOFuncNameVarInitializer(Inc->getName())))) INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ Inc->getHash()->getZExtValue())) INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \ ConstantExpr::getBitCast(CounterPtr, \ llvm::Type::getInt64PtrTy(Ctx))) /* This is used to map function pointers for the indirect call targets to * function name hashes during the conversion from raw to merged profile * data. */ INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \ FunctionAddr) INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \ ValuesPtrExpr) INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters)) INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \ ConstantArray::get(Int16ArrayTy, Int16ArrayVals)) #undef INSTR_PROF_DATA /* INSTR_PROF_DATA end. */ /* This is an internal data structure used by value profiler. It * is defined here to allow serialization code sharing by LLVM * to be used in unit test. * * typedef struct ValueProfNode { * // InstrProfValueData VData; * uint64_t Value; * uint64_t Count; * struct ValueProfNode *Next; * } ValueProfNode; */ /* INSTR_PROF_VALUE_NODE start. */ #ifndef INSTR_PROF_VALUE_NODE #define INSTR_PROF_VALUE_NODE(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif INSTR_PROF_VALUE_NODE(uint64_t, llvm::Type::getInt64Ty(Ctx), Value, \ ConstantInt::get(llvm::Type::GetInt64Ty(Ctx), 0)) INSTR_PROF_VALUE_NODE(uint64_t, llvm::Type::getInt64Ty(Ctx), Count, \ ConstantInt::get(llvm::Type::GetInt64Ty(Ctx), 0)) INSTR_PROF_VALUE_NODE(PtrToNodeT, llvm::Type::getInt8PtrTy(Ctx), Next, \ ConstantInt::get(llvm::Type::GetInt8PtrTy(Ctx), 0)) #undef INSTR_PROF_VALUE_NODE /* INSTR_PROF_VALUE_NODE end. */ /* INSTR_PROF_RAW_HEADER start */ /* Definition of member fields of the raw profile header data structure. */ #ifndef INSTR_PROF_RAW_HEADER #define INSTR_PROF_RAW_HEADER(Type, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic()) INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version()) INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize) INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize) INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize) INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin) INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin) INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last) #undef INSTR_PROF_RAW_HEADER /* INSTR_PROF_RAW_HEADER end */ /* VALUE_PROF_FUNC_PARAM start */ /* Definition of parameter types of the runtime API used to do value profiling * for a given value site. */ #ifndef VALUE_PROF_FUNC_PARAM #define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType) #define INSTR_PROF_COMMA #else #define INSTR_PROF_DATA_DEFINED #define INSTR_PROF_COMMA , #endif VALUE_PROF_FUNC_PARAM(uint64_t, TargetValue, Type::getInt64Ty(Ctx)) \ INSTR_PROF_COMMA VALUE_PROF_FUNC_PARAM(void *, Data, Type::getInt8PtrTy(Ctx)) INSTR_PROF_COMMA VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) #undef VALUE_PROF_FUNC_PARAM #undef INSTR_PROF_COMMA /* VALUE_PROF_FUNC_PARAM end */ /* VALUE_PROF_KIND start */ #ifndef VALUE_PROF_KIND #define VALUE_PROF_KIND(Enumerator, Value) #else #define INSTR_PROF_DATA_DEFINED #endif /* For indirect function call value profiling, the addresses of the target * functions are profiled by the instrumented code. The target addresses are * written in the raw profile data and converted to target function name's MD5 * hash by the profile reader during deserialization. Typically, this happens * when the the raw profile data is read during profile merging. * * For this remapping the ProfData is used. ProfData contains both the function * name hash and the function address. */ VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0) /* These two kinds must be the last to be * declared. This is to make sure the string * array created with the template can be * indexed with the kind value. */ VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget) VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget) #undef VALUE_PROF_KIND /* VALUE_PROF_KIND end */ /* COVMAP_FUNC_RECORD start */ /* Definition of member fields of the function record structure in coverage * map. */ #ifndef COVMAP_FUNC_RECORD #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif #ifdef COVMAP_V1 COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \ NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \ llvm::Type::getInt8PtrTy(Ctx))) COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), \ NameValue.size())) #else COVMAP_FUNC_RECORD(const int64_t, llvm::Type::getInt64Ty(Ctx), NameRef, \ llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ llvm::IndexedInstrProf::ComputeHash(NameValue))) #endif COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), DataSize, \ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\ CoverageMapping.size())) COVMAP_FUNC_RECORD(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \ llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), FuncHash)) #undef COVMAP_FUNC_RECORD /* COVMAP_FUNC_RECORD end. */ /* COVMAP_HEADER start */ /* Definition of member fields of coverage map header. */ #ifndef COVMAP_HEADER #define COVMAP_HEADER(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif COVMAP_HEADER(uint32_t, Int32Ty, NRecords, \ llvm::ConstantInt::get(Int32Ty, FunctionRecords.size())) COVMAP_HEADER(uint32_t, Int32Ty, FilenamesSize, \ llvm::ConstantInt::get(Int32Ty, FilenamesSize)) COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \ llvm::ConstantInt::get(Int32Ty, CoverageMappingSize)) COVMAP_HEADER(uint32_t, Int32Ty, Version, \ llvm::ConstantInt::get(Int32Ty, CovMapVersion::CurrentVersion)) #undef COVMAP_HEADER /* COVMAP_HEADER end. */ #ifdef INSTR_PROF_VALUE_PROF_DATA #define INSTR_PROF_DATA_DEFINED #define INSTR_PROF_MAX_NUM_VAL_PER_SITE 255 /*! * This is the header of the data structure that defines the on-disk * layout of the value profile data of a particular kind for one function. */ typedef struct ValueProfRecord { /* The kind of the value profile record. */ uint32_t Kind; /* * The number of value profile sites. It is guaranteed to be non-zero; * otherwise the record for this kind won't be emitted. */ uint32_t NumValueSites; /* * The first element of the array that stores the number of profiled * values for each value site. The size of the array is NumValueSites. * Since NumValueSites is greater than zero, there is at least one * element in the array. */ uint8_t SiteCountArray[1]; /* * The fake declaration is for documentation purpose only. * Align the start of next field to be on 8 byte boundaries. uint8_t Padding[X]; */ /* The array of value profile data. The size of the array is the sum * of all elements in SiteCountArray[]. InstrProfValueData ValueData[]; */ #ifdef __cplusplus /*! * \brief Return the number of value sites. */ uint32_t getNumValueSites() const { return NumValueSites; } /*! * \brief Read data from this record and save it to Record. */ void deserializeTo(InstrProfRecord &Record, InstrProfRecord::ValueMapType *VMap); /* * In-place byte swap: * Do byte swap for this instance. \c Old is the original order before * the swap, and \c New is the New byte order. */ void swapBytes(support::endianness Old, support::endianness New); #endif } ValueProfRecord; /*! * Per-function header/control data structure for value profiling * data in indexed format. */ typedef struct ValueProfData { /* * Total size in bytes including this field. It must be a multiple * of sizeof(uint64_t). */ uint32_t TotalSize; /* *The number of value profile kinds that has value profile data. * In this implementation, a value profile kind is considered to * have profile data if the number of value profile sites for the * kind is not zero. More aggressively, the implementation can * choose to check the actual data value: if none of the value sites * has any profiled values, the kind can be skipped. */ uint32_t NumValueKinds; /* * Following are a sequence of variable length records. The prefix/header * of each record is defined by ValueProfRecord type. The number of * records is NumValueKinds. * ValueProfRecord Record_1; * ValueProfRecord Record_N; */ #if __cplusplus /*! * Return the total size in bytes of the on-disk value profile data * given the data stored in Record. */ static uint32_t getSize(const InstrProfRecord &Record); /*! * Return a pointer to \c ValueProfData instance ready to be streamed. */ static std::unique_ptr serializeFrom(const InstrProfRecord &Record); /*! * Check the integrity of the record. */ Error checkIntegrity(); /*! * Return a pointer to \c ValueProfileData instance ready to be read. * All data in the instance are properly byte swapped. The input * data is assumed to be in little endian order. */ static Expected> getValueProfData(const unsigned char *SrcBuffer, const unsigned char *const SrcBufferEnd, support::endianness SrcDataEndianness); /*! * Swap byte order from \c Endianness order to host byte order. */ void swapBytesToHost(support::endianness Endianness); /*! * Swap byte order from host byte order to \c Endianness order. */ void swapBytesFromHost(support::endianness Endianness); /*! * Return the total size of \c ValueProfileData. */ uint32_t getSize() const { return TotalSize; } /*! * Read data from this data and save it to \c Record. */ void deserializeTo(InstrProfRecord &Record, InstrProfRecord::ValueMapType *VMap); void operator delete(void *ptr) { ::operator delete(ptr); } #endif } ValueProfData; /* * The closure is designed to abstact away two types of value profile data: * - InstrProfRecord which is the primary data structure used to * represent profile data in host tools (reader, writer, and profile-use) * - value profile runtime data structure suitable to be used by C * runtime library. * * Both sources of data need to serialize to disk/memory-buffer in common * format: ValueProfData. The abstraction allows compiler-rt's raw profiler * writer to share the same format and code with indexed profile writer. * * For documentation of the member methods below, refer to corresponding methods * in class InstrProfRecord. */ typedef struct ValueProfRecordClosure { const void *Record; uint32_t (*GetNumValueKinds)(const void *Record); uint32_t (*GetNumValueSites)(const void *Record, uint32_t VKind); uint32_t (*GetNumValueData)(const void *Record, uint32_t VKind); uint32_t (*GetNumValueDataForSite)(const void *R, uint32_t VK, uint32_t S); /* * After extracting the value profile data from the value profile record, * this method is used to map the in-memory value to on-disk value. If * the method is null, value will be written out untranslated. */ uint64_t (*RemapValueData)(uint32_t, uint64_t Value); void (*GetValueForSite)(const void *R, InstrProfValueData *Dst, uint32_t K, uint32_t S); ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes); } ValueProfRecordClosure; INSTR_PROF_VISIBILITY ValueProfRecord * getFirstValueProfRecord(ValueProfData *VPD); INSTR_PROF_VISIBILITY ValueProfRecord * getValueProfRecordNext(ValueProfRecord *VPR); INSTR_PROF_VISIBILITY InstrProfValueData * getValueProfRecordValueData(ValueProfRecord *VPR); INSTR_PROF_VISIBILITY uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites); #undef INSTR_PROF_VALUE_PROF_DATA #endif /* INSTR_PROF_VALUE_PROF_DATA */ #ifdef INSTR_PROF_COMMON_API_IMPL #define INSTR_PROF_DATA_DEFINED #ifdef __cplusplus #define INSTR_PROF_INLINE inline #define INSTR_PROF_NULLPTR nullptr #else #define INSTR_PROF_INLINE #define INSTR_PROF_NULLPTR NULL #endif #ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif /*! * \brief Return the \c ValueProfRecord header size including the * padding bytes. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) + sizeof(uint8_t) * NumValueSites; /* Round the size to multiple of 8 bytes. */ Size = (Size + 7) & ~7; return Size; } /*! * \brief Return the total size of the value profile record including the * header and the value data. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordSize(uint32_t NumValueSites, uint32_t NumValueData) { return getValueProfRecordHeaderSize(NumValueSites) + sizeof(InstrProfValueData) * NumValueData; } /*! * \brief Return the pointer to the start of value data array. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize( This->NumValueSites)); } /*! * \brief Return the total number of value data for \c This record. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { uint32_t NumValueData = 0; uint32_t I; for (I = 0; I < This->NumValueSites; I++) NumValueData += This->SiteCountArray[I]; return NumValueData; } /*! * \brief Use this method to advance to the next \c This \c ValueProfRecord. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { uint32_t NumValueData = getValueProfRecordNumValueData(This); return (ValueProfRecord *)((char *)This + getValueProfRecordSize(This->NumValueSites, NumValueData)); } /*! * \brief Return the first \c ValueProfRecord instance. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) { return (ValueProfRecord *)((char *)This + sizeof(ValueProfData)); } /* Closure based interfaces. */ /*! * Return the total size in bytes of the on-disk value profile data * given the data stored in Record. */ INSTR_PROF_VISIBILITY uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) { uint32_t Kind; uint32_t TotalSize = sizeof(ValueProfData); const void *Record = Closure->Record; for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { uint32_t NumValueSites = Closure->GetNumValueSites(Record, Kind); if (!NumValueSites) continue; TotalSize += getValueProfRecordSize(NumValueSites, Closure->GetNumValueData(Record, Kind)); } return TotalSize; } /*! * Extract value profile data of a function for the profile kind \c ValueKind * from the \c Closure and serialize the data into \c This record instance. */ INSTR_PROF_VISIBILITY void serializeValueProfRecordFrom(ValueProfRecord *This, ValueProfRecordClosure *Closure, uint32_t ValueKind, uint32_t NumValueSites) { uint32_t S; const void *Record = Closure->Record; This->Kind = ValueKind; This->NumValueSites = NumValueSites; InstrProfValueData *DstVD = getValueProfRecordValueData(This); for (S = 0; S < NumValueSites; S++) { uint32_t ND = Closure->GetNumValueDataForSite(Record, ValueKind, S); This->SiteCountArray[S] = ND; Closure->GetValueForSite(Record, DstVD, ValueKind, S); DstVD += ND; } } /*! * Extract value profile data of a function from the \c Closure * and serialize the data into \c DstData if it is not NULL or heap * memory allocated by the \c Closure's allocator method. If \c * DstData is not null, the caller is expected to set the TotalSize * in DstData. */ INSTR_PROF_VISIBILITY ValueProfData * serializeValueProfDataFrom(ValueProfRecordClosure *Closure, ValueProfData *DstData) { uint32_t Kind; uint32_t TotalSize = DstData ? DstData->TotalSize : getValueProfDataSize(Closure); ValueProfData *VPD = DstData ? DstData : Closure->AllocValueProfData(TotalSize); VPD->TotalSize = TotalSize; VPD->NumValueKinds = Closure->GetNumValueKinds(Closure->Record); ValueProfRecord *VR = getFirstValueProfRecord(VPD); for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { uint32_t NumValueSites = Closure->GetNumValueSites(Closure->Record, Kind); if (!NumValueSites) continue; serializeValueProfRecordFrom(VR, Closure, Kind, NumValueSites); VR = getValueProfRecordNext(VR); } return VPD; } #undef INSTR_PROF_COMMON_API_IMPL #endif /* INSTR_PROF_COMMON_API_IMPL */ /*============================================================================*/ #ifndef INSTR_PROF_DATA_DEFINED #ifndef INSTR_PROF_DATA_INC #define INSTR_PROF_DATA_INC /* Helper macros. */ #define INSTR_PROF_SIMPLE_QUOTE(x) #x #define INSTR_PROF_QUOTE(x) INSTR_PROF_SIMPLE_QUOTE(x) #define INSTR_PROF_SIMPLE_CONCAT(x,y) x ## y #define INSTR_PROF_CONCAT(x,y) INSTR_PROF_SIMPLE_CONCAT(x,y) /* Magic number to detect file format and endianness. * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0, * so that utilities, like strings, don't grab it as a string. 129 is also * invalid UTF-8, and high enough to be interesting. * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR" * for 32-bit platforms. */ #define INSTR_PROF_RAW_MAGIC_64 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \ (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129 #define INSTR_PROF_RAW_MAGIC_32 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \ (uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129 /* Raw profile format version (start from 1). */ #define INSTR_PROF_RAW_VERSION 4 /* Indexed profile format version (start from 1). */ #define INSTR_PROF_INDEX_VERSION 4 /* Coverage mapping format vresion (start from 0). */ #define INSTR_PROF_COVMAP_VERSION 1 /* Profile version is always of type uint64_t. Reserve the upper 8 bits in the * version for other variants of profile. We set the lowest bit of the upper 8 * bits (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentaiton * generated profile, and 0 if this is a Clang FE generated profile. */ #define VARIANT_MASKS_ALL 0xff00000000000000ULL #define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL) #define VARIANT_MASK_IR_PROF (0x1ULL << 56) #define IR_LEVEL_PROF_VERSION_VAR __llvm_profile_raw_version /* Runtime section names and name strings. */ #define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data #define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names #define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts /* Array of pointers. Each pointer points to a list * of value nodes associated with one value site. */ #define INSTR_PROF_VALS_SECT_NAME __llvm_prf_vals /* Value profile nodes section. */ #define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds #define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap #define INSTR_PROF_DATA_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME) #define INSTR_PROF_NAME_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME) #define INSTR_PROF_CNTS_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME) #define INSTR_PROF_COVMAP_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME) #define INSTR_PROF_VALS_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_VALS_SECT_NAME) #define INSTR_PROF_VNODES_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_VNODES_SECT_NAME) /* Macros to define start/stop section symbol for a given * section on Linux. For instance * INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) will * expand to __start___llvm_prof_data */ #define INSTR_PROF_SECT_START(Sect) \ INSTR_PROF_CONCAT(__start_,Sect) #define INSTR_PROF_SECT_STOP(Sect) \ INSTR_PROF_CONCAT(__stop_,Sect) /* Value Profiling API linkage name. */ #define INSTR_PROF_VALUE_PROF_FUNC __llvm_profile_instrument_target #define INSTR_PROF_VALUE_PROF_FUNC_STR \ INSTR_PROF_QUOTE(INSTR_PROF_VALUE_PROF_FUNC) /* InstrProfile per-function control data alignment. */ #define INSTR_PROF_DATA_ALIGNMENT 8 /* The data structure that represents a tracked value by the * value profiler. */ typedef struct InstrProfValueData { /* Profiled value. */ uint64_t Value; /* Number of times the value appears in the training run. */ uint64_t Count; } InstrProfValueData; #endif /* INSTR_PROF_DATA_INC */ #else #undef INSTR_PROF_DATA_DEFINED #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/GCDAProfiling.c0000664000175000017500000003524312776214734022752 0ustar kaikai/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* |*===----------------------------------------------------------------------===*| |* |* This file implements the call back routines for the gcov profiling |* instrumentation pass. Link against this library when running code through |* the -insert-gcov-profiling LLVM pass. |* |* We emit files in a corrupt version of GCOV's "gcda" file format. These files |* are only close enough that LCOV will happily parse them. Anything that lcov |* ignores is missing. |* |* TODO: gcov is multi-process safe by having each exit open the existing file |* and append to it. We'd like to achieve that and be thread-safe too. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfilingUtil.h" #include #include #include #include #include #if defined(_WIN32) #include "WindowsMMap.h" #else #include #include #endif #if defined(__FreeBSD__) && defined(__i386__) #define I386_FREEBSD 1 #else #define I386_FREEBSD 0 #endif #if !defined(_MSC_VER) && !I386_FREEBSD #include #endif #if defined(_MSC_VER) typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #elif I386_FREEBSD /* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to * FreeBSD 10, r232261) when compiled in 32-bit mode. */ typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #endif /* #define DEBUG_GCDAPROFILING */ /* * --- GCOV file format I/O primitives --- */ /* * The current file name we're outputting. Used primarily for error logging. */ static char *filename = NULL; /* * The current file we're outputting. */ static FILE *output_file = NULL; /* * Buffer that we write things into. */ #define WRITE_BUFFER_SIZE (128 * 1024) static char *write_buffer = NULL; static uint64_t cur_buffer_size = 0; static uint64_t cur_pos = 0; static uint64_t file_size = 0; static int new_file = 0; static int fd = -1; /* * A list of functions to write out the data. */ typedef void (*writeout_fn)(); struct writeout_fn_node { writeout_fn fn; struct writeout_fn_node *next; }; static struct writeout_fn_node *writeout_fn_head = NULL; static struct writeout_fn_node *writeout_fn_tail = NULL; /* * A list of flush functions that our __gcov_flush() function should call. */ typedef void (*flush_fn)(); struct flush_fn_node { flush_fn fn; struct flush_fn_node *next; }; static struct flush_fn_node *flush_fn_head = NULL; static struct flush_fn_node *flush_fn_tail = NULL; static void resize_write_buffer(uint64_t size) { if (!new_file) return; size += cur_pos; if (size <= cur_buffer_size) return; size = (size - 1) / WRITE_BUFFER_SIZE + 1; size *= WRITE_BUFFER_SIZE; write_buffer = realloc(write_buffer, size); cur_buffer_size = size; } static void write_bytes(const char *s, size_t len) { resize_write_buffer(len); memcpy(&write_buffer[cur_pos], s, len); cur_pos += len; } static void write_32bit_value(uint32_t i) { write_bytes((char*)&i, 4); } static void write_64bit_value(uint64_t i) { write_bytes((char*)&i, 8); } static uint32_t length_of_string(const char *s) { return (strlen(s) / 4) + 1; } static void write_string(const char *s) { uint32_t len = length_of_string(s); write_32bit_value(len); write_bytes(s, strlen(s)); write_bytes("\0\0\0\0", 4 - (strlen(s) % 4)); } static uint32_t read_32bit_value() { uint32_t val; if (new_file) return (uint32_t)-1; val = *(uint32_t*)&write_buffer[cur_pos]; cur_pos += 4; return val; } static uint64_t read_64bit_value() { uint64_t val; if (new_file) return (uint64_t)-1; val = *(uint64_t*)&write_buffer[cur_pos]; cur_pos += 8; return val; } static char *mangle_filename(const char *orig_filename) { char *new_filename; size_t filename_len, prefix_len; int prefix_strip; int level = 0; const char *fname, *ptr; const char *prefix = getenv("GCOV_PREFIX"); const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP"); if (prefix == NULL || prefix[0] == '\0') return strdup(orig_filename); if (prefix_strip_str) { prefix_strip = atoi(prefix_strip_str); /* Negative GCOV_PREFIX_STRIP values are ignored */ if (prefix_strip < 0) prefix_strip = 0; } else { prefix_strip = 0; } fname = orig_filename; for (level = 0, ptr = fname + 1; level < prefix_strip; ++ptr) { if (*ptr == '\0') break; if (*ptr != '/') continue; fname = ptr; ++level; } filename_len = strlen(fname); prefix_len = strlen(prefix); new_filename = malloc(prefix_len + 1 + filename_len + 1); memcpy(new_filename, prefix, prefix_len); if (prefix[prefix_len - 1] != '/') new_filename[prefix_len++] = '/'; memcpy(new_filename + prefix_len, fname, filename_len + 1); return new_filename; } static int map_file() { fseek(output_file, 0L, SEEK_END); file_size = ftell(output_file); /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an * error message because it should "just work" for the user. */ if (file_size == 0) return -1; write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); if (write_buffer == (void *)-1) { int errnum = errno; fprintf(stderr, "profiling: %s: cannot map: %s\n", filename, strerror(errnum)); return -1; } return 0; } static void unmap_file() { if (msync(write_buffer, file_size, MS_SYNC) == -1) { int errnum = errno; fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename, strerror(errnum)); } /* We explicitly ignore errors from unmapping because at this point the data * is written and we don't care. */ (void)munmap(write_buffer, file_size); write_buffer = NULL; file_size = 0; } /* * --- LLVM line counter API --- */ /* A file in this case is a translation unit. Each .o file built with line * profiling enabled will emit to a different file. Only one file may be * started at a time. */ void llvm_gcda_start_file(const char *orig_filename, const char version[4], uint32_t checksum) { const char *mode = "r+b"; filename = mangle_filename(orig_filename); /* Try just opening the file. */ new_file = 0; fd = open(filename, O_RDWR); if (fd == -1) { /* Try opening the file, creating it if necessary. */ new_file = 1; mode = "w+b"; fd = open(filename, O_RDWR | O_CREAT, 0644); if (fd == -1) { /* Try creating the directories first then opening the file. */ __llvm_profile_recursive_mkdir(filename); fd = open(filename, O_RDWR | O_CREAT, 0644); if (fd == -1) { /* Bah! It's hopeless. */ int errnum = errno; fprintf(stderr, "profiling: %s: cannot open: %s\n", filename, strerror(errnum)); return; } } } /* Try to flock the file to serialize concurrent processes writing out to the * same GCDA. This can fail if the filesystem doesn't support it, but in that * case we'll just carry on with the old racy behaviour and hope for the best. */ flock(fd, LOCK_EX); output_file = fdopen(fd, mode); /* Initialize the write buffer. */ write_buffer = NULL; cur_buffer_size = 0; cur_pos = 0; if (new_file) { resize_write_buffer(WRITE_BUFFER_SIZE); memset(write_buffer, 0, WRITE_BUFFER_SIZE); } else { if (map_file() == -1) { /* mmap failed, try to recover by clobbering */ new_file = 1; write_buffer = NULL; cur_buffer_size = 0; resize_write_buffer(WRITE_BUFFER_SIZE); memset(write_buffer, 0, WRITE_BUFFER_SIZE); } } /* gcda file, version, stamp checksum. */ write_bytes("adcg", 4); write_bytes(version, 4); write_32bit_value(checksum); #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: [%s]\n", orig_filename); #endif } /* Given an array of pointers to counters (counters), increment the n-th one, * where we're also given a pointer to n (predecessor). */ void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, uint64_t **counters) { uint64_t *counter; uint32_t pred; pred = *predecessor; if (pred == 0xffffffff) return; counter = counters[pred]; /* Don't crash if the pred# is out of sync. This can happen due to threads, or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ if (counter) ++*counter; #ifdef DEBUG_GCDAPROFILING else fprintf(stderr, "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n", *counter, *predecessor); #endif } void llvm_gcda_emit_function(uint32_t ident, const char *function_name, uint32_t func_checksum, uint8_t use_extra_checksum, uint32_t cfg_checksum) { uint32_t len = 2; if (use_extra_checksum) len++; #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident, function_name ? function_name : "NULL"); #endif if (!output_file) return; /* function tag */ write_bytes("\0\0\0\1", 4); if (function_name) len += 1 + length_of_string(function_name); write_32bit_value(len); write_32bit_value(ident); write_32bit_value(func_checksum); if (use_extra_checksum) write_32bit_value(cfg_checksum); if (function_name) write_string(function_name); } void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { uint32_t i; uint64_t *old_ctrs = NULL; uint32_t val = 0; uint64_t save_cur_pos = cur_pos; if (!output_file) return; val = read_32bit_value(); if (val != (uint32_t)-1) { /* There are counters present in the file. Merge them. */ if (val != 0x01a10000) { fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " "corrupt arc tag (0x%08x)\n", filename, val); return; } val = read_32bit_value(); if (val == (uint32_t)-1 || val / 2 != num_counters) { fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " "mismatched number of counters (%d)\n", filename, val); return; } old_ctrs = malloc(sizeof(uint64_t) * num_counters); for (i = 0; i < num_counters; ++i) old_ctrs[i] = read_64bit_value(); } cur_pos = save_cur_pos; /* Counter #1 (arcs) tag */ write_bytes("\0\0\xa1\1", 4); write_32bit_value(num_counters * 2); for (i = 0; i < num_counters; ++i) { counters[i] += (old_ctrs ? old_ctrs[i] : 0); write_64bit_value(counters[i]); } free(old_ctrs); #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: %u arcs\n", num_counters); for (i = 0; i < num_counters; ++i) fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]); #endif } void llvm_gcda_summary_info() { const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */ uint32_t i; uint32_t runs = 1; uint32_t val = 0; uint64_t save_cur_pos = cur_pos; if (!output_file) return; val = read_32bit_value(); if (val != (uint32_t)-1) { /* There are counters present in the file. Merge them. */ if (val != 0xa1000000) { fprintf(stderr, "profiling: %s: cannot merge previous run count: " "corrupt object tag (0x%08x)\n", filename, val); return; } val = read_32bit_value(); /* length */ if (val != obj_summary_len) { fprintf(stderr, "profiling: %s: cannot merge previous run count: " "mismatched object length (%d)\n", filename, val); return; } read_32bit_value(); /* checksum, unused */ read_32bit_value(); /* num, unused */ runs += read_32bit_value(); /* Add previous run count to new counter. */ } cur_pos = save_cur_pos; /* Object summary tag */ write_bytes("\0\0\0\xa1", 4); write_32bit_value(obj_summary_len); write_32bit_value(0); /* checksum, unused */ write_32bit_value(0); /* num, unused */ write_32bit_value(runs); for (i = 3; i < obj_summary_len; ++i) write_32bit_value(0); /* Program summary tag */ write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */ write_32bit_value(0); /* 0 length */ #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: %u runs\n", runs); #endif } void llvm_gcda_end_file() { /* Write out EOF record. */ if (output_file) { write_bytes("\0\0\0\0\0\0\0\0", 8); if (new_file) { fwrite(write_buffer, cur_pos, 1, output_file); free(write_buffer); } else { unmap_file(); } flock(fd, LOCK_UN); fclose(output_file); output_file = NULL; write_buffer = NULL; } free(filename); #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: -----\n"); #endif } void llvm_register_writeout_function(writeout_fn fn) { struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); new_node->fn = fn; new_node->next = NULL; if (!writeout_fn_head) { writeout_fn_head = writeout_fn_tail = new_node; } else { writeout_fn_tail->next = new_node; writeout_fn_tail = new_node; } } void llvm_writeout_files(void) { struct writeout_fn_node *curr = writeout_fn_head; while (curr) { curr->fn(); curr = curr->next; } } void llvm_delete_writeout_function_list(void) { while (writeout_fn_head) { struct writeout_fn_node *node = writeout_fn_head; writeout_fn_head = writeout_fn_head->next; free(node); } writeout_fn_head = writeout_fn_tail = NULL; } void llvm_register_flush_function(flush_fn fn) { struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); new_node->fn = fn; new_node->next = NULL; if (!flush_fn_head) { flush_fn_head = flush_fn_tail = new_node; } else { flush_fn_tail->next = new_node; flush_fn_tail = new_node; } } void __gcov_flush() { struct flush_fn_node *curr = flush_fn_head; while (curr) { curr->fn(); curr = curr->next; } } void llvm_delete_flush_function_list(void) { while (flush_fn_head) { struct flush_fn_node *node = flush_fn_head; flush_fn_head = flush_fn_head->next; free(node); } flush_fn_head = flush_fn_tail = NULL; } void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) { static int atexit_ran = 0; if (wfn) llvm_register_writeout_function(wfn); if (ffn) llvm_register_flush_function(ffn); if (atexit_ran == 0) { atexit_ran = 1; /* Make sure we write out the data and delete the data structures. */ atexit(llvm_delete_flush_function_list); atexit(llvm_delete_writeout_function_list); atexit(llvm_writeout_files); } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/WindowsMMap.h0000664000175000017500000000274712776214734022617 0ustar kaikai/*===- WindowsMMap.h - Support library for PGO instrumentation ------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_WINDOWS_MMAP_H #define PROFILE_INSTRPROFILING_WINDOWS_MMAP_H #if defined(_WIN32) #include #include #include /* * mmap() flags */ #define PROT_READ 0x1 #define PROT_WRITE 0x2 #define PROT_EXEC 0x0 #define MAP_FILE 0x00 #define MAP_SHARED 0x01 #define MAP_PRIVATE 0x02 #define MAP_ANONYMOUS 0x20 #define MAP_ANON MAP_ANONYMOUS #define MAP_FAILED ((void *) -1) /* * msync() flags */ #define MS_ASYNC 0x0001 /* return immediately */ #define MS_INVALIDATE 0x0002 /* invalidate all cached data */ #define MS_SYNC 0x0010 /* msync synchronously */ /* * flock() operations */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ #define LOCK_NB 4 /* don't block when locking */ #define LOCK_UN 8 /* unlock */ void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); void munmap(void *addr, size_t length); int msync(void *addr, size_t length, int flags); int flock(int fd, int operation); #endif /* _WIN32 */ #endif /* PROFILE_INSTRPROFILING_WINDOWS_MMAP_H */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingMergeFile.c0000664000175000017500000000302112776214734025120 0ustar kaikai/*===- InstrProfilingMergeFile.c - Profile in-process Merging ------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* |*===----------------------------------------------------------------------=== |* This file defines APIs needed to support in-process merging for profile data |* stored in files. \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include "InstrProfilingUtil.h" #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *) = &lprofMergeValueProfData; /* Merge value profile data pointed to by SrcValueProfData into * in-memory profile counters pointed by to DstData. */ void lprofMergeValueProfData(ValueProfData *SrcValueProfData, __llvm_profile_data *DstData) { unsigned I, S, V, C; InstrProfValueData *VData; ValueProfRecord *VR = getFirstValueProfRecord(SrcValueProfData); for (I = 0; I < SrcValueProfData->NumValueKinds; I++) { VData = getValueProfRecordValueData(VR); for (S = 0; S < VR->NumValueSites; S++) { uint8_t NV = VR->SiteCountArray[S]; for (V = 0; V < NV; V++) { for (C = 0; C < VData[V].Count; C++) __llvm_profile_instrument_target(VData[V].Value, DstData, S); } } VR = getValueProfRecordNext(VR); } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingWriter.c0000664000175000017500000002366312776214734024553 0ustar kaikai/*===- InstrProfilingWriter.c - Write instrumentation to a file or buffer -===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #ifdef _MSC_VER /* For _alloca */ #include #endif #include #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" COMPILER_RT_VISIBILITY void (*FreeHook)(void *) = NULL; static ProfBufferIO TheBufferIO; #define VP_BUFFER_SIZE 8 * 1024 static uint8_t BufferIOBuffer[VP_BUFFER_SIZE]; static InstrProfValueData VPDataArray[16]; static uint32_t VPDataArraySize = sizeof(VPDataArray) / sizeof(*VPDataArray); COMPILER_RT_VISIBILITY uint8_t *DynamicBufferIOBuffer = 0; COMPILER_RT_VISIBILITY uint32_t VPBufferSize = 0; /* The buffer writer is reponsponsible in keeping writer state * across the call. */ COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx) { uint32_t I; char **Buffer = (char **)WriterCtx; for (I = 0; I < NumIOVecs; I++) { size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm; memcpy(*Buffer, IOVecs[I].Data, Length); *Buffer += Length; } return 0; } static void llvmInitBufferIO(ProfBufferIO *BufferIO, WriterCallback FileWriter, void *File, uint8_t *Buffer, uint32_t BufferSz) { BufferIO->File = File; BufferIO->FileWriter = FileWriter; BufferIO->BufferStart = Buffer; BufferIO->BufferSz = BufferSz; BufferIO->CurOffset = 0; } COMPILER_RT_VISIBILITY ProfBufferIO * lprofCreateBufferIO(WriterCallback FileWriter, void *File) { uint8_t *Buffer = DynamicBufferIOBuffer; uint32_t BufferSize = VPBufferSize; if (!Buffer) { Buffer = &BufferIOBuffer[0]; BufferSize = sizeof(BufferIOBuffer); } llvmInitBufferIO(&TheBufferIO, FileWriter, File, Buffer, BufferSize); return &TheBufferIO; } COMPILER_RT_VISIBILITY void lprofDeleteBufferIO(ProfBufferIO *BufferIO) { if (DynamicBufferIOBuffer) { FreeHook(DynamicBufferIOBuffer); DynamicBufferIOBuffer = 0; VPBufferSize = 0; } } COMPILER_RT_VISIBILITY int lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) { /* Buffer is not large enough, it is time to flush. */ if (Size + BufferIO->CurOffset > BufferIO->BufferSz) { if (lprofBufferIOFlush(BufferIO) != 0) return -1; } /* Special case, bypass the buffer completely. */ ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}}; if (Size > BufferIO->BufferSz) { if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) return -1; } else { /* Write the data to buffer */ uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset; lprofBufferWriter(IO, 1, (void **)&Buffer); BufferIO->CurOffset = Buffer - BufferIO->BufferStart; } return 0; } COMPILER_RT_VISIBILITY int lprofBufferIOFlush(ProfBufferIO *BufferIO) { if (BufferIO->CurOffset) { ProfDataIOVec IO[] = { {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}}; if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) return -1; BufferIO->CurOffset = 0; } return 0; } /* Write out value profile data for function specified with \c Data. * The implementation does not use the method \c serializeValueProfData * which depends on dynamic memory allocation. In this implementation, * value profile data is written out to \c BufferIO piecemeal. */ static int writeOneValueProfData(ProfBufferIO *BufferIO, VPDataReaderType *VPDataReader, const __llvm_profile_data *Data) { unsigned I, NumValueKinds = 0; ValueProfData VPHeader; uint8_t *SiteCountArray[IPVK_Last + 1]; for (I = 0; I <= IPVK_Last; I++) { if (!Data->NumValueSites[I]) SiteCountArray[I] = 0; else { uint32_t Sz = VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) - offsetof(ValueProfRecord, SiteCountArray); /* Only use alloca for this small byte array to avoid excessive * stack growth. */ SiteCountArray[I] = (uint8_t *)COMPILER_RT_ALLOCA(Sz); memset(SiteCountArray[I], 0, Sz); } } /* If NumValueKinds returned is 0, there is nothing to write, report success and return. This should match the raw profile reader's behavior. */ if (!(NumValueKinds = VPDataReader->InitRTRecord(Data, SiteCountArray))) return 0; /* First write the header structure. */ VPHeader.TotalSize = VPDataReader->GetValueProfDataSize(); VPHeader.NumValueKinds = NumValueKinds; if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPHeader, sizeof(ValueProfData))) return -1; /* Make sure nothing else needs to be written before value profile * records. */ if ((void *)VPDataReader->GetFirstValueProfRecord(&VPHeader) != (void *)(&VPHeader + 1)) return -1; /* Write out the value profile record for each value kind * one by one. */ for (I = 0; I <= IPVK_Last; I++) { uint32_t J; ValueProfRecord RecordHeader; /* The size of the value prof record header without counting the * site count array .*/ uint32_t RecordHeaderSize = offsetof(ValueProfRecord, SiteCountArray); uint32_t SiteCountArraySize; if (!Data->NumValueSites[I]) continue; /* Write out the record header. */ RecordHeader.Kind = I; RecordHeader.NumValueSites = Data->NumValueSites[I]; if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&RecordHeader, RecordHeaderSize)) return -1; /* Write out the site value count array including padding space. */ SiteCountArraySize = VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) - RecordHeaderSize; if (lprofBufferIOWrite(BufferIO, SiteCountArray[I], SiteCountArraySize)) return -1; /* Write out the value profile data for each value site. */ for (J = 0; J < Data->NumValueSites[I]; J++) { uint32_t NRead, NRemain; ValueProfNode *NextStartNode = 0; NRemain = VPDataReader->GetNumValueDataForSite(I, J); if (!NRemain) continue; /* Read and write out value data in small chunks till it is done. */ do { NRead = (NRemain > VPDataArraySize ? VPDataArraySize : NRemain); NextStartNode = VPDataReader->GetValueData(I, /* ValueKind */ J, /* Site */ &VPDataArray[0], NextStartNode, NRead); if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPDataArray[0], NRead * sizeof(InstrProfValueData))) return -1; NRemain -= NRead; } while (NRemain != 0); } } /* All done report success. */ return 0; } static int writeValueProfData(WriterCallback Writer, void *WriterCtx, VPDataReaderType *VPDataReader, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd) { ProfBufferIO *BufferIO; const __llvm_profile_data *DI = 0; if (!VPDataReader) return 0; BufferIO = lprofCreateBufferIO(Writer, WriterCtx); for (DI = DataBegin; DI < DataEnd; DI++) { if (writeOneValueProfData(BufferIO, VPDataReader, DI)) return -1; } if (lprofBufferIOFlush(BufferIO) != 0) return -1; lprofDeleteBufferIO(BufferIO); return 0; } COMPILER_RT_VISIBILITY int lprofWriteData(WriterCallback Writer, void *WriterCtx, VPDataReaderType *VPDataReader) { /* Match logic in __llvm_profile_write_buffer(). */ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); return lprofWriteDataImpl(Writer, WriterCtx, DataBegin, DataEnd, CountersBegin, CountersEnd, VPDataReader, NamesBegin, NamesEnd); } COMPILER_RT_VISIBILITY int lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, VPDataReaderType *VPDataReader, const char *NamesBegin, const char *NamesEnd) { /* Calculate size of sections. */ const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); const uint64_t CountersSize = CountersEnd - CountersBegin; const uint64_t NamesSize = NamesEnd - NamesBegin; const uint64_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize); /* Enough zeroes for padding. */ const char Zeroes[sizeof(uint64_t)] = {0}; /* Create the header. */ __llvm_profile_header Header; if (!DataSize) return 0; /* Initialize header structure. */ #define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init; #include "InstrProfData.inc" /* Write the data. */ ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1}, {DataBegin, sizeof(__llvm_profile_data), DataSize}, {CountersBegin, sizeof(uint64_t), CountersSize}, {NamesBegin, sizeof(uint8_t), NamesSize}, {Zeroes, sizeof(uint8_t), Padding}}; if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx)) return -1; return writeValueProfData(Writer, WriterCtx, VPDataReader, DataBegin, DataEnd); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfiling.h0000664000175000017500000001475712776214734023367 0ustar kaikai/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_H_ #define PROFILE_INSTRPROFILING_H_ #include "InstrProfilingPort.h" #define INSTR_PROF_VISIBILITY COMPILER_RT_VISIBILITY #include "InstrProfData.inc" enum ValueKind { #define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value, #include "InstrProfData.inc" }; typedef void *IntPtrT; typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT) __llvm_profile_data { #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) Type Name; #include "InstrProfData.inc" } __llvm_profile_data; typedef struct __llvm_profile_header { #define INSTR_PROF_RAW_HEADER(Type, Name, Initializer) Type Name; #include "InstrProfData.inc" } __llvm_profile_header; typedef struct ValueProfNode * PtrToNodeT; typedef struct ValueProfNode { #define INSTR_PROF_VALUE_NODE(Type, LLVMType, Name, Initializer) Type Name; #include "InstrProfData.inc" } ValueProfNode; /*! * \brief Get number of bytes necessary to pad the argument to eight * byte boundary. */ uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes); /*! * \brief Get required size for profile buffer. */ uint64_t __llvm_profile_get_size_for_buffer(void); /*! * \brief Write instrumentation data to the given buffer. * * \pre \c Buffer is the start of a buffer at least as big as \a * __llvm_profile_get_size_for_buffer(). */ int __llvm_profile_write_buffer(char *Buffer); const __llvm_profile_data *__llvm_profile_begin_data(void); const __llvm_profile_data *__llvm_profile_end_data(void); const char *__llvm_profile_begin_names(void); const char *__llvm_profile_end_names(void); uint64_t *__llvm_profile_begin_counters(void); uint64_t *__llvm_profile_end_counters(void); ValueProfNode *__llvm_profile_begin_vnodes(); ValueProfNode *__llvm_profile_end_vnodes(); /*! * \brief Clear profile counters to zero. * */ void __llvm_profile_reset_counters(void); /*! * \brief Merge profile data from buffer. * * Read profile data form buffer \p Profile and merge with * in-process profile counters. The client is expected to * have checked or already knows the profile data in the * buffer matches the in-process counter structure before * calling it. */ void __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size); /*! \brief Check if profile in buffer matches the current binary. * * Returns 0 (success) if the profile data in buffer \p Profile with size * \p Size was generated by the same binary and therefore matches * structurally the in-process counters. If the profile data in buffer is * not compatible, the interface returns 1 (failure). */ int __llvm_profile_check_compatibility(const char *Profile, uint64_t Size); /*! * \brief Counts the number of times a target value is seen. * * Records the target value for the CounterIndex if not seen before. Otherwise, * increments the counter associated w/ the target value. * void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data, * uint32_t CounterIndex); */ void INSTR_PROF_VALUE_PROF_FUNC( #define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType) ArgType ArgName #include "InstrProfData.inc" ); /*! * \brief Write instrumentation data to the current file. * * Writes to the file with the last name given to \a * * __llvm_profile_set_filename(), * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable, * or if that's not set, the last name given to * \a __llvm_profile_override_default_filename(), or if that's not set, * \c "default.profraw". */ int __llvm_profile_write_file(void); /*! * \brief Set the filename for writing instrumentation data. * * Sets the filename to be used for subsequent calls to * \a __llvm_profile_write_file(). * * \c Name is not copied, so it must remain valid. Passing NULL resets the * filename logic to the default behaviour. */ void __llvm_profile_set_filename(const char *Name); /*! * \brief Set the filename for writing instrumentation data, unless the * \c LLVM_PROFILE_FILE environment variable was set. * * Unless overridden, sets the filename to be used for subsequent calls to * \a __llvm_profile_write_file(). * * \c Name is not copied, so it must remain valid. Passing NULL resets the * filename logic to the default behaviour (unless the \c LLVM_PROFILE_FILE * was set in which case it has no effect). */ void __llvm_profile_override_default_filename(const char *Name); /*! \brief Register to write instrumentation data to file at exit. */ int __llvm_profile_register_write_file_atexit(void); /*! \brief Initialize file handling. */ void __llvm_profile_initialize_file(void); /*! \brief Get the magic token for the file format. */ uint64_t __llvm_profile_get_magic(void); /*! \brief Get the version of the file format. */ uint64_t __llvm_profile_get_version(void); /*! \brief Get the number of entries in the profile data section. */ uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin, const __llvm_profile_data *End); /*! * This variable is defined in InstrProfilingRuntime.cc as a hidden * symbol. Its main purpose is to enable profile runtime user to * bypass runtime initialization code -- if the client code explicitly * define this variable, then InstProfileRuntime.o won't be linked in. * Note that this variable's visibility needs to be hidden so that the * definition of this variable in an instrumented shared library won't * affect runtime initialization decision of the main program. */ COMPILER_RT_VISIBILITY extern int __llvm_profile_runtime; /*! * This variable is defined in InstrProfiling.c. Its main purpose is to * encode the raw profile version value and other format related information * such as whether the profile is from IR based instrumentation. The variable * is defined as weak so that compiler can emit an overriding definition * depending on user option. Since we don't support mixing FE and IR based * data in the same raw profile data file (in other words, shared libs and * main program are expected to be instrumented in the same way), there is * no need for this variable to be hidden. */ extern uint64_t __llvm_profile_raw_version; #endif /* PROFILE_INSTRPROFILING_H_ */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/WindowsMMap.c0000664000175000017500000000604512776214734022605 0ustar kaikai/* * This code is derived from uClibc (original license follows). * https://git.uclibc.org/uClibc/tree/utils/mmap-windows.c */ /* mmap() replacement for Windows * * Author: Mike Frysinger * Placed into the public domain */ /* References: * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx */ #if defined(_WIN32) #include "WindowsMMap.h" #include "InstrProfiling.h" #ifdef __USE_FILE_OFFSET64 # define DWORD_HI(x) (x >> 32) # define DWORD_LO(x) ((x) & 0xffffffff) #else # define DWORD_HI(x) (0) # define DWORD_LO(x) (x) #endif COMPILER_RT_VISIBILITY void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) { if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) return MAP_FAILED; if (fd == -1) { if (!(flags & MAP_ANON) || offset) return MAP_FAILED; } else if (flags & MAP_ANON) return MAP_FAILED; DWORD flProtect; if (prot & PROT_WRITE) { if (prot & PROT_EXEC) flProtect = PAGE_EXECUTE_READWRITE; else flProtect = PAGE_READWRITE; } else if (prot & PROT_EXEC) { if (prot & PROT_READ) flProtect = PAGE_EXECUTE_READ; else if (prot & PROT_EXEC) flProtect = PAGE_EXECUTE; } else flProtect = PAGE_READONLY; off_t end = length + offset; HANDLE mmap_fd, h; if (fd == -1) mmap_fd = INVALID_HANDLE_VALUE; else mmap_fd = (HANDLE)_get_osfhandle(fd); h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL); if (h == NULL) return MAP_FAILED; DWORD dwDesiredAccess; if (prot & PROT_WRITE) dwDesiredAccess = FILE_MAP_WRITE; else dwDesiredAccess = FILE_MAP_READ; if (prot & PROT_EXEC) dwDesiredAccess |= FILE_MAP_EXECUTE; if (flags & MAP_PRIVATE) dwDesiredAccess |= FILE_MAP_COPY; void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); if (ret == NULL) { CloseHandle(h); ret = MAP_FAILED; } return ret; } COMPILER_RT_VISIBILITY void munmap(void *addr, size_t length) { UnmapViewOfFile(addr); /* ruh-ro, we leaked handle from CreateFileMapping() ... */ } COMPILER_RT_VISIBILITY int msync(void *addr, size_t length, int flags) { if (flags & MS_INVALIDATE) return -1; /* Not supported. */ /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */ switch (flags & (MS_ASYNC | MS_SYNC)) { case MS_SYNC: case MS_ASYNC: break; default: return -1; } if (!FlushViewOfFile(addr, length)) return -1; if (flags & MS_SYNC) { /* FIXME: No longer have access to handle from CreateFileMapping(). */ /* * if (!FlushFileBuffers(h)) * return -1; */ } return 0; } COMPILER_RT_VISIBILITY int flock(int fd, int operation) { return -1; /* Not supported. */ } #undef DWORD_HI #undef DWORD_LO #endif /* _WIN32 */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingValue.c0000664000175000017500000002576612776214734024361 0ustar kaikai/*===- InstrProfilingValue.c - Support library for PGO instrumentation ----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include "InstrProfilingUtil.h" /* For PS4 getenv shim. */ #include #include #include #include #define INSTR_PROF_VALUE_PROF_DATA #define INSTR_PROF_COMMON_API_IMPL #include "InstrProfData.inc" static int hasStaticCounters = 1; static int OutOfNodesWarnings = 0; static int hasNonDefaultValsPerSite = 0; #define INSTR_PROF_MAX_VP_WARNS 10 #define INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE 8 #define INSTR_PROF_VNODE_POOL_SIZE 1024 #ifndef _MSC_VER /* A shared static pool in addition to the vnodes statically * allocated by the compiler. */ COMPILER_RT_VISIBILITY ValueProfNode lprofValueProfNodes[INSTR_PROF_VNODE_POOL_SIZE] COMPILER_RT_SECTION( COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME_STR); #endif COMPILER_RT_VISIBILITY uint32_t VPMaxNumValsPerSite = INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE; COMPILER_RT_VISIBILITY void lprofSetupValueProfiler() { const char *Str = 0; Str = getenv("LLVM_VP_MAX_NUM_VALS_PER_SITE"); if (Str && Str[0]) { VPMaxNumValsPerSite = atoi(Str); hasNonDefaultValsPerSite = 1; } if (VPMaxNumValsPerSite > INSTR_PROF_MAX_NUM_VAL_PER_SITE) VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE; } COMPILER_RT_VISIBILITY void lprofSetMaxValsPerSite(uint32_t MaxVals) { VPMaxNumValsPerSite = MaxVals; hasNonDefaultValsPerSite = 1; } /* This method is only used in value profiler mock testing. */ COMPILER_RT_VISIBILITY void __llvm_profile_set_num_value_sites(__llvm_profile_data *Data, uint32_t ValueKind, uint16_t NumValueSites) { *((uint16_t *)&Data->NumValueSites[ValueKind]) = NumValueSites; } /* This method is only used in value profiler mock testing. */ COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_iterate_data(const __llvm_profile_data *Data) { return Data + 1; } /* This method is only used in value profiler mock testing. */ COMPILER_RT_VISIBILITY void * __llvm_get_function_addr(const __llvm_profile_data *Data) { return Data->FunctionPointer; } /* Allocate an array that holds the pointers to the linked lists of * value profile counter nodes. The number of element of the array * is the total number of value profile sites instrumented. Returns * 0 if allocation fails. */ static int allocateValueProfileCounters(__llvm_profile_data *Data) { uint64_t NumVSites = 0; uint32_t VKI; /* This function will never be called when value site array is allocated statically at compile time. */ hasStaticCounters = 0; /* When dynamic allocation is enabled, allow tracking the max number of * values allowd. */ if (!hasNonDefaultValsPerSite) VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE; for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI) NumVSites += Data->NumValueSites[VKI]; ValueProfNode **Mem = (ValueProfNode **)calloc(NumVSites, sizeof(ValueProfNode *)); if (!Mem) return 0; if (!COMPILER_RT_BOOL_CMPXCHG(&Data->Values, 0, Mem)) { free(Mem); return 0; } return 1; } static ValueProfNode *allocateOneNode(__llvm_profile_data *Data, uint32_t Index, uint64_t Value) { ValueProfNode *Node; if (!hasStaticCounters) return (ValueProfNode *)calloc(1, sizeof(ValueProfNode)); /* Early check to avoid value wrapping around. */ if (CurrentVNode + 1 > EndVNode) { if (OutOfNodesWarnings++ < INSTR_PROF_MAX_VP_WARNS) { PROF_WARN("Unable to track new values: %s. " " Consider using option -mllvm -vp-counters-per-site= to " "allocate more" " value profile counters at compile time. \n", "Running out of static counters"); } return 0; } Node = COMPILER_RT_PTR_FETCH_ADD(ValueProfNode, CurrentVNode, 1); /* Due to section padding, EndVNode point to a byte which is one pass * an incomplete VNode, so we need to skip the last incomplete node. */ if (Node + 1 > EndVNode) return 0; return Node; } COMPILER_RT_VISIBILITY void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data, uint32_t CounterIndex) { __llvm_profile_data *PData = (__llvm_profile_data *)Data; if (!PData) return; if (!PData->Values) { if (!allocateValueProfileCounters(PData)) return; } ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values; ValueProfNode *PrevVNode = NULL; ValueProfNode *MinCountVNode = NULL; ValueProfNode *CurVNode = ValueCounters[CounterIndex]; uint64_t MinCount = UINT64_MAX; uint8_t VDataCount = 0; while (CurVNode) { if (TargetValue == CurVNode->Value) { CurVNode->Count++; return; } if (CurVNode->Count < MinCount) { MinCount = CurVNode->Count; MinCountVNode = CurVNode; } PrevVNode = CurVNode; CurVNode = CurVNode->Next; ++VDataCount; } if (VDataCount >= VPMaxNumValsPerSite) { /* Bump down the min count node's count. If it reaches 0, * evict it. This eviction/replacement policy makes hot * targets more sticky while cold targets less so. In other * words, it makes it less likely for the hot targets to be * prematurally evicted during warmup/establishment period, * when their counts are still low. In a special case when * the number of values tracked is reduced to only one, this * policy will guarantee that the dominating target with >50% * total count will survive in the end. Note that this scheme * allows the runtime to track the min count node in an adaptive * manner. It can correct previous mistakes and eventually * lock on a cold target that is alread in stable state. * * In very rare cases, this replacement scheme may still lead * to target loss. For instance, out of \c N value slots, \c N-1 * slots are occupied by luke warm targets during the warmup * period and the remaining one slot is competed by two or more * very hot targets. If those hot targets occur in an interleaved * way, none of them will survive (gain enough weight to throw out * other established entries) due to the ping-pong effect. * To handle this situation, user can choose to increase the max * number of tracked values per value site. Alternatively, a more * expensive eviction mechanism can be implemented. It requires * the runtime to track the total number of evictions per-site. * When the total number of evictions reaches certain threshold, * the runtime can wipe out more than one lowest count entries * to give space for hot targets. */ if (!(--MinCountVNode->Count)) { CurVNode = MinCountVNode; CurVNode->Value = TargetValue; CurVNode->Count++; } return; } CurVNode = allocateOneNode(PData, CounterIndex, TargetValue); if (!CurVNode) return; CurVNode->Value = TargetValue; CurVNode->Count++; uint32_t Success = 0; if (!ValueCounters[CounterIndex]) Success = COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurVNode); else if (PrevVNode && !PrevVNode->Next) Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurVNode); if (!Success && !hasStaticCounters) { free(CurVNode); return; } } /* * A wrapper struct that represents value profile runtime data. * Like InstrProfRecord class which is used by profiling host tools, * ValueProfRuntimeRecord also implements the abstract intefaces defined in * ValueProfRecordClosure so that the runtime data can be serialized using * shared C implementation. */ typedef struct ValueProfRuntimeRecord { const __llvm_profile_data *Data; ValueProfNode **NodesKind[IPVK_Last + 1]; uint8_t **SiteCountArray; } ValueProfRuntimeRecord; /* ValueProfRecordClosure Interface implementation. */ static uint32_t getNumValueSitesRT(const void *R, uint32_t VK) { return ((const ValueProfRuntimeRecord *)R)->Data->NumValueSites[VK]; } static uint32_t getNumValueDataRT(const void *R, uint32_t VK) { uint32_t S = 0, I; const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; if (Record->SiteCountArray[VK] == INSTR_PROF_NULLPTR) return 0; for (I = 0; I < Record->Data->NumValueSites[VK]; I++) S += Record->SiteCountArray[VK][I]; return S; } static uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK, uint32_t S) { const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; return Record->SiteCountArray[VK][S]; } static ValueProfRuntimeRecord RTRecord; static ValueProfRecordClosure RTRecordClosure = { &RTRecord, INSTR_PROF_NULLPTR, /* GetNumValueKinds */ getNumValueSitesRT, getNumValueDataRT, getNumValueDataForSiteRT, INSTR_PROF_NULLPTR, /* RemapValueData */ INSTR_PROF_NULLPTR, /* GetValueForSite, */ INSTR_PROF_NULLPTR /* AllocValueProfData */ }; static uint32_t initializeValueProfRuntimeRecord(const __llvm_profile_data *Data, uint8_t *SiteCountArray[]) { unsigned I, J, S = 0, NumValueKinds = 0; ValueProfNode **Nodes = (ValueProfNode **)Data->Values; RTRecord.Data = Data; RTRecord.SiteCountArray = SiteCountArray; for (I = 0; I <= IPVK_Last; I++) { uint16_t N = Data->NumValueSites[I]; if (!N) continue; NumValueKinds++; RTRecord.NodesKind[I] = Nodes ? &Nodes[S] : INSTR_PROF_NULLPTR; for (J = 0; J < N; J++) { /* Compute value count for each site. */ uint32_t C = 0; ValueProfNode *Site = Nodes ? RTRecord.NodesKind[I][J] : INSTR_PROF_NULLPTR; while (Site) { C++; Site = Site->Next; } if (C > UCHAR_MAX) C = UCHAR_MAX; RTRecord.SiteCountArray[I][J] = C; } S += N; } return NumValueKinds; } static ValueProfNode *getNextNValueData(uint32_t VK, uint32_t Site, InstrProfValueData *Dst, ValueProfNode *StartNode, uint32_t N) { unsigned I; ValueProfNode *VNode = StartNode ? StartNode : RTRecord.NodesKind[VK][Site]; for (I = 0; I < N; I++) { Dst[I].Value = VNode->Value; Dst[I].Count = VNode->Count; VNode = VNode->Next; } return VNode; } static uint32_t getValueProfDataSizeWrapper(void) { return getValueProfDataSize(&RTRecordClosure); } static uint32_t getNumValueDataForSiteWrapper(uint32_t VK, uint32_t S) { return getNumValueDataForSiteRT(&RTRecord, VK, S); } static VPDataReaderType TheVPDataReader = { initializeValueProfRuntimeRecord, getValueProfRecordHeaderSize, getFirstValueProfRecord, getNumValueDataForSiteWrapper, getValueProfDataSizeWrapper, getNextNValueData}; COMPILER_RT_VISIBILITY VPDataReaderType *lprofGetVPDataReader() { return &TheVPDataReader; } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingPlatformOther.c0000664000175000017500000000623312776214734026057 0ustar kaikai/*===- InstrProfilingPlatformOther.c - Profile data default platform ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) #include static const __llvm_profile_data *DataFirst = NULL; static const __llvm_profile_data *DataLast = NULL; static const char *NamesFirst = NULL; static const char *NamesLast = NULL; static uint64_t *CountersFirst = NULL; static uint64_t *CountersLast = NULL; static const void *getMinAddr(const void *A1, const void *A2) { return A1 < A2 ? A1 : A2; } static const void *getMaxAddr(const void *A1, const void *A2) { return A1 > A2 ? A1 : A2; } /*! * \brief Register an instrumented function. * * Calls to this are emitted by clang with -fprofile-instr-generate. Such * calls are only required (and only emitted) on targets where we haven't * implemented linker magic to find the bounds of the sections. */ COMPILER_RT_VISIBILITY void __llvm_profile_register_function(void *Data_) { /* TODO: Only emit this function if we can't use linker magic. */ const __llvm_profile_data *Data = (__llvm_profile_data *)Data_; if (!DataFirst) { DataFirst = Data; DataLast = Data + 1; CountersFirst = Data->CounterPtr; CountersLast = (uint64_t *)Data->CounterPtr + Data->NumCounters; return; } DataFirst = (const __llvm_profile_data *)getMinAddr(DataFirst, Data); CountersFirst = (uint64_t *)getMinAddr(CountersFirst, Data->CounterPtr); DataLast = (const __llvm_profile_data *)getMaxAddr(DataLast, Data + 1); CountersLast = (uint64_t *)getMaxAddr( CountersLast, (uint64_t *)Data->CounterPtr + Data->NumCounters); } COMPILER_RT_VISIBILITY void __llvm_profile_register_names_function(void *NamesStart, uint64_t NamesSize) { if (!NamesFirst) { NamesFirst = (const char *)NamesStart; NamesLast = (const char *)NamesStart + NamesSize; return; } NamesFirst = (const char *)getMinAddr(NamesFirst, NamesStart); NamesLast = (const char *)getMaxAddr(NamesLast, (const char *)NamesStart + NamesSize); } COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_begin_data(void) { return DataFirst; } COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_end_data(void) { return DataLast; } COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) { return NamesFirst; } COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) { return NamesLast; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return CountersLast; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_begin_vnodes(void) { return 0; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) { return 0; } COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = 0; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = 0; #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingBuffer.c0000664000175000017500000000506012776214734024477 0ustar kaikai/*===- InstrProfilingBuffer.c - Write instrumentation to a memory buffer --===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_size_for_buffer(void) { const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); return __llvm_profile_get_size_for_buffer_internal( DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd); } COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin, const __llvm_profile_data *End) { intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End; return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) / sizeof(__llvm_profile_data); } COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { /* Match logic in __llvm_profile_write_buffer(). */ const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char); const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize); return sizeof(__llvm_profile_header) + (__llvm_profile_get_data_size(DataBegin, DataEnd) * sizeof(__llvm_profile_data)) + (CountersEnd - CountersBegin) * sizeof(uint64_t) + NamesSize + Padding; } COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) { return lprofWriteData(lprofBufferWriter, Buffer, 0); } COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { return lprofWriteDataImpl(lprofBufferWriter, Buffer, DataBegin, DataEnd, CountersBegin, CountersEnd, 0, NamesBegin, NamesEnd); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfiling.c0000664000175000017500000000422312776214734023345 0ustar kaikai/*===- InstrProfiling.c - Support library for PGO instrumentation ---------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include #include #include #include #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" COMPILER_RT_VISIBILITY char *(*GetEnvHook)(const char *) = 0; COMPILER_RT_WEAK uint64_t __llvm_profile_raw_version = INSTR_PROF_RAW_VERSION; COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) { return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64) : (INSTR_PROF_RAW_MAGIC_32); } /* Return the number of bytes needed to add to SizeInBytes to make it * the result a multiple of 8. */ COMPILER_RT_VISIBILITY uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes) { return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t)); } COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_version(void) { return __llvm_profile_raw_version; } COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) { uint64_t *I = __llvm_profile_begin_counters(); uint64_t *E = __llvm_profile_end_counters(); memset(I, 0, sizeof(uint64_t) * (E - I)); const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const __llvm_profile_data *DI; for (DI = DataBegin; DI < DataEnd; ++DI) { uint64_t CurrentVSiteCount = 0; uint32_t VKI, i; if (!DI->Values) continue; ValueProfNode **ValueCounters = (ValueProfNode **)DI->Values; for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI) CurrentVSiteCount += DI->NumValueSites[VKI]; for (i = 0; i < CurrentVSiteCount; ++i) { ValueProfNode *CurrentVNode = ValueCounters[i]; while (CurrentVNode) { CurrentVNode->Count = 0; CurrentVNode = CurrentVNode->Next; } } } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingUtil.h0000664000175000017500000000212012776214734024202 0ustar kaikai/*===- InstrProfilingUtil.h - Support library for PGO instrumentation -----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILINGUTIL_H #define PROFILE_INSTRPROFILINGUTIL_H #include #include /*! \brief Create a directory tree. */ void __llvm_profile_recursive_mkdir(char *Pathname); /*! Open file \c Filename for read+write with write * lock for exclusive access. The caller will block * if the lock is already held by another process. */ FILE *lprofOpenFileEx(const char *Filename); /* PS4 doesn't have getenv. Define a shim. */ #if __ORBIS__ static inline char *getenv(const char *name) { return NULL; } #endif /* #if __ORBIS__ */ int lprofGetHostName(char *Name, int Len); unsigned lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV); void *lprofPtrFetchAdd(void **Mem, long ByteIncr); #endif /* PROFILE_INSTRPROFILINGUTIL_H */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingFile.c0000664000175000017500000004013012776214734024142 0ustar kaikai/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include "InstrProfilingUtil.h" #include #include #include #include #ifdef _MSC_VER /* For _alloca. */ #include #endif #if defined(_WIN32) #include "WindowsMMap.h" /* For _chsize_s */ #include #else #include #include #include #if defined(__linux__) #include #endif #endif /* From where is profile name specified. * The order the enumerators define their * precedence. Re-order them may lead to * runtime behavior change. */ typedef enum ProfileNameSpecifier { PNS_unknown = 0, PNS_default, PNS_command_line, PNS_environment, PNS_runtime_api } ProfileNameSpecifier; static const char *getPNSStr(ProfileNameSpecifier PNS) { switch (PNS) { case PNS_default: return "default setting"; case PNS_command_line: return "command line"; case PNS_environment: return "environment variable"; case PNS_runtime_api: return "runtime API"; default: return "Unknown"; } } #define MAX_PID_SIZE 16 /* Data structure holding the result of parsed filename pattern. */ typedef struct lprofFilename { /* File name string possibly with %p or %h specifiers. */ const char *FilenamePat; char PidChars[MAX_PID_SIZE]; char Hostname[COMPILER_RT_MAX_HOSTLEN]; unsigned NumPids; unsigned NumHosts; /* When in-process merging is enabled, this parameter specifies * the total number of profile data files shared by all the processes * spawned from the same binary. By default the value is 1. If merging * is not enabled, its value should be 0. This parameter is specified * by the %[0-9]m specifier. For instance %2m enables merging using * 2 profile data files. %1m is equivalent to %m. Also %m specifier * can only appear once at the end of the name pattern. */ unsigned MergePoolSize; ProfileNameSpecifier PNS; } lprofFilename; lprofFilename lprofCurFilename = {0, {0}, {0}, 0, 0, 0, PNS_unknown}; int getpid(void); static int getCurFilenameLength(); static const char *getCurFilename(char *FilenameBuf); static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } /* Return 1 if there is an error, otherwise return 0. */ static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx) { uint32_t I; FILE *File = (FILE *)*WriterCtx; for (I = 0; I < NumIOVecs; I++) { if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != IOVecs[I].NumElm) return 1; } return 0; } COMPILER_RT_VISIBILITY ProfBufferIO * lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { FreeHook = &free; DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); VPBufferSize = BufferSz; return lprofCreateBufferIO(fileWriter, File); } static void setupIOBuffer() { const char *BufferSzStr = 0; BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); if (BufferSzStr && BufferSzStr[0]) { VPBufferSize = atoi(BufferSzStr); DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); } } /* Read profile data in \c ProfileFile and merge with in-memory profile counters. Returns -1 if there is fatal error, otheriwse 0 is returned. */ static int doProfileMerging(FILE *ProfileFile) { uint64_t ProfileFileSize; char *ProfileBuffer; if (fseek(ProfileFile, 0L, SEEK_END) == -1) { PROF_ERR("Unable to merge profile data, unable to get size: %s\n", strerror(errno)); return -1; } ProfileFileSize = ftell(ProfileFile); /* Restore file offset. */ if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", strerror(errno)); return -1; } /* Nothing to merge. */ if (ProfileFileSize < sizeof(__llvm_profile_header)) { if (ProfileFileSize) PROF_WARN("Unable to merge profile data: %s\n", "source profile file is too small."); return 0; } ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, fileno(ProfileFile), 0); if (ProfileBuffer == MAP_FAILED) { PROF_ERR("Unable to merge profile data, mmap failed: %s\n", strerror(errno)); return -1; } if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) { (void)munmap(ProfileBuffer, ProfileFileSize); PROF_WARN("Unable to merge profile data: %s\n", "source profile file is not compatible."); return 0; } /* Now start merging */ __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); (void)munmap(ProfileBuffer, ProfileFileSize); return 0; } /* Open the profile data for merging. It opens the file in r+b mode with * file locking. If the file has content which is compatible with the * current process, it also reads in the profile data in the file and merge * it with in-memory counters. After the profile data is merged in memory, * the original profile data is truncated and gets ready for the profile * dumper. With profile merging enabled, each executable as well as any of * its instrumented shared libraries dump profile data into their own data file. */ static FILE *openFileForMerging(const char *ProfileFileName) { FILE *ProfileFile; int rc; ProfileFile = lprofOpenFileEx(ProfileFileName); if (!ProfileFile) return NULL; rc = doProfileMerging(ProfileFile); if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) || fseek(ProfileFile, 0L, SEEK_SET) == -1) { PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, strerror(errno)); fclose(ProfileFile); return NULL; } fseek(ProfileFile, 0L, SEEK_SET); return ProfileFile; } /* Write profile data to file \c OutputName. */ static int writeFile(const char *OutputName) { int RetVal; FILE *OutputFile; if (!doMerging()) OutputFile = fopen(OutputName, "ab"); else OutputFile = openFileForMerging(OutputName); if (!OutputFile) return -1; FreeHook = &free; setupIOBuffer(); RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader()); fclose(OutputFile); return RetVal; } static void truncateCurrentFile(void) { const char *Filename; char *FilenameBuf; FILE *File; int Length; Length = getCurFilenameLength(); FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); Filename = getCurFilename(FilenameBuf); if (!Filename) return; /* Create the directory holding the file, if needed. */ if (strchr(Filename, '/') || strchr(Filename, '\\')) { char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); strncpy(Copy, Filename, Length + 1); __llvm_profile_recursive_mkdir(Copy); } /* Truncate the file. Later we'll reopen and append. */ File = fopen(Filename, "w"); if (!File) return; fclose(File); } static const char *DefaultProfileName = "default.profraw"; static void resetFilenameToDefault(void) { memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); lprofCurFilename.FilenamePat = DefaultProfileName; lprofCurFilename.PNS = PNS_default; } static int containsMergeSpecifier(const char *FilenamePat, int I) { return (FilenamePat[I] == 'm' || (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' && /* If FilenamePat[I] is not '\0', the next byte is guaranteed * to be in-bound as the string is null terminated. */ FilenamePat[I + 1] == 'm')); } /* Parses the pattern string \p FilenamePat and stores the result to * lprofcurFilename structure. */ static int parseFilenamePattern(const char *FilenamePat) { int NumPids = 0, NumHosts = 0, I; char *PidChars = &lprofCurFilename.PidChars[0]; char *Hostname = &lprofCurFilename.Hostname[0]; int MergingEnabled = 0; lprofCurFilename.FilenamePat = FilenamePat; /* Check the filename for "%p", which indicates a pid-substitution. */ for (I = 0; FilenamePat[I]; ++I) if (FilenamePat[I] == '%') { if (FilenamePat[++I] == 'p') { if (!NumPids++) { if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) { PROF_WARN( "Unable to parse filename pattern %s. Using the default name.", FilenamePat); return -1; } } } else if (FilenamePat[I] == 'h') { if (!NumHosts++) if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { PROF_WARN( "Unable to parse filename pattern %s. Using the default name.", FilenamePat); return -1; } } else if (containsMergeSpecifier(FilenamePat, I)) { if (MergingEnabled) { PROF_WARN("%%m specifier can only be specified once in %s.\n", FilenamePat); return -1; } MergingEnabled = 1; if (FilenamePat[I] == 'm') lprofCurFilename.MergePoolSize = 1; else { lprofCurFilename.MergePoolSize = FilenamePat[I] - '0'; I++; /* advance to 'm' */ } } } lprofCurFilename.NumPids = NumPids; lprofCurFilename.NumHosts = NumHosts; return 0; } static void parseAndSetFilename(const char *FilenamePat, ProfileNameSpecifier PNS) { const char *OldFilenamePat = lprofCurFilename.FilenamePat; ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; if (PNS < OldPNS) return; if (!FilenamePat) FilenamePat = DefaultProfileName; /* When -fprofile-instr-generate= is specified on the * command line, each module will be instrumented with runtime * init call to __llvm_profile_init function which calls * __llvm_profile_override_default_filename. In most of the cases, * the path will be identical, so bypass the parsing completely. */ if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { lprofCurFilename.PNS = PNS; return; } /* When PNS >= OldPNS, the last one wins. */ if (!FilenamePat || parseFilenamePattern(FilenamePat)) resetFilenameToDefault(); lprofCurFilename.PNS = PNS; if (!OldFilenamePat) { PROF_NOTE("Set profile file path to \"%s\" via %s.\n", lprofCurFilename.FilenamePat, getPNSStr(PNS)); } else { PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, getPNSStr(PNS)); } if (!lprofCurFilename.MergePoolSize) truncateCurrentFile(); } /* Return buffer length that is required to store the current profile * filename with PID and hostname substitutions. */ /* The length to hold uint64_t followed by 2 digit pool id including '_' */ #define SIGLEN 24 static int getCurFilenameLength() { int Len; if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) return 0; if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || lprofCurFilename.MergePoolSize)) return strlen(lprofCurFilename.FilenamePat); Len = strlen(lprofCurFilename.FilenamePat) + lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); if (lprofCurFilename.MergePoolSize) Len += SIGLEN; return Len; } /* Return the pointer to the current profile file name (after substituting * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer * to store the resulting filename. If no substitution is needed, the * current filename pattern string is directly returned. */ static const char *getCurFilename(char *FilenameBuf) { int I, J, PidLength, HostNameLength; const char *FilenamePat = lprofCurFilename.FilenamePat; if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) return 0; if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || lprofCurFilename.MergePoolSize)) return lprofCurFilename.FilenamePat; PidLength = strlen(lprofCurFilename.PidChars); HostNameLength = strlen(lprofCurFilename.Hostname); /* Construct the new filename. */ for (I = 0, J = 0; FilenamePat[I]; ++I) if (FilenamePat[I] == '%') { if (FilenamePat[++I] == 'p') { memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); J += PidLength; } else if (FilenamePat[I] == 'h') { memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); J += HostNameLength; } else if (containsMergeSpecifier(FilenamePat, I)) { char LoadModuleSignature[SIGLEN]; int S; int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d", lprofGetLoadModuleSignature(), ProfilePoolId); if (S == -1 || S > SIGLEN) S = SIGLEN; memcpy(FilenameBuf + J, LoadModuleSignature, S); J += S; if (FilenamePat[I] != 'm') I++; } /* Drop any unknown substitutions. */ } else FilenameBuf[J++] = FilenamePat[I]; FilenameBuf[J] = 0; return FilenameBuf; } /* Returns the pointer to the environment variable * string. Returns null if the env var is not set. */ static const char *getFilenamePatFromEnv(void) { const char *Filename = getenv("LLVM_PROFILE_FILE"); if (!Filename || !Filename[0]) return 0; return Filename; } /* This method is invoked by the runtime initialization hook * InstrProfilingRuntime.o if it is linked in. Both user specified * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE * environment variable can override this default value. */ COMPILER_RT_VISIBILITY void __llvm_profile_initialize_file(void) { const char *FilenamePat; FilenamePat = getFilenamePatFromEnv(); parseAndSetFilename(FilenamePat, FilenamePat ? PNS_environment : PNS_default); } /* This API is directly called by the user application code. It has the * highest precedence compared with LLVM_PROFILE_FILE environment variable * and command line option -fprofile-instr-generate=. */ COMPILER_RT_VISIBILITY void __llvm_profile_set_filename(const char *FilenamePat) { parseAndSetFilename(FilenamePat, PNS_runtime_api); } /* * This API is invoked by the global initializers emitted by Clang/LLVM when * -fprofile-instr-generate=<..> is specified (vs -fprofile-instr-generate * without an argument). This option has lower precedence than the * LLVM_PROFILE_FILE environment variable. */ COMPILER_RT_VISIBILITY void __llvm_profile_override_default_filename(const char *FilenamePat) { parseAndSetFilename(FilenamePat, PNS_command_line); } /* The public API for writing profile data into the file with name * set by previous calls to __llvm_profile_set_filename or * __llvm_profile_override_default_filename or * __llvm_profile_initialize_file. */ COMPILER_RT_VISIBILITY int __llvm_profile_write_file(void) { int rc, Length; const char *Filename; char *FilenameBuf; Length = getCurFilenameLength(); FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); Filename = getCurFilename(FilenameBuf); /* Check the filename. */ if (!Filename) { PROF_ERR("Failed to write file : %s\n", "Filename not set"); return -1; } /* Check if there is llvm/runtime version mismatch. */ if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { PROF_ERR("Runtime and instrumentation version mismatch : " "expected %d, but get %d\n", INSTR_PROF_RAW_VERSION, (int)GET_VERSION(__llvm_profile_get_version())); return -1; } /* Write profile data to the file. */ rc = writeFile(Filename); if (rc) PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); return rc; } static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } COMPILER_RT_VISIBILITY int __llvm_profile_register_write_file_atexit(void) { static int HasBeenRegistered = 0; if (HasBeenRegistered) return 0; lprofSetupValueProfiler(); HasBeenRegistered = 1; return atexit(writeFileWithoutReturn); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingRuntime.cc0000664000175000017500000000117212776214734025054 0ustar kaikai//===- InstrProfilingRuntime.cpp - PGO runtime initialization -------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// extern "C" { #include "InstrProfiling.h" COMPILER_RT_VISIBILITY int __llvm_profile_runtime; } namespace { class RegisterRuntime { public: RegisterRuntime() { __llvm_profile_register_write_file_atexit(); __llvm_profile_initialize_file(); } }; RegisterRuntime Registration; } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingMerge.c0000664000175000017500000001223012776214734024322 0ustar kaikai/*===- InstrProfilingMerge.c - Profile in-process Merging ---------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* |*===----------------------------------------------------------------------===* |* This file defines the API needed for in-process merging of profile data |* stored in memory buffer. \*===---------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include "InstrProfilingUtil.h" #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" COMPILER_RT_WEAK void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *) = NULL; COMPILER_RT_VISIBILITY uint64_t lprofGetLoadModuleSignature() { /* A very fast way to compute a module signature. */ uint64_t CounterSize = (uint64_t)(__llvm_profile_end_counters() - __llvm_profile_begin_counters()); uint64_t DataSize = __llvm_profile_get_data_size(__llvm_profile_begin_data(), __llvm_profile_end_data()); uint64_t NamesSize = (uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names()); uint64_t NumVnodes = (uint64_t)(__llvm_profile_end_vnodes() - __llvm_profile_begin_vnodes()); const __llvm_profile_data *FirstD = __llvm_profile_begin_data(); return (NamesSize << 40) + (CounterSize << 30) + (DataSize << 20) + (NumVnodes << 10) + (DataSize > 0 ? FirstD->NameRef : 0); } /* Returns 1 if profile is not structurally compatible. */ COMPILER_RT_VISIBILITY int __llvm_profile_check_compatibility(const char *ProfileData, uint64_t ProfileSize) { /* Check profile header only for now */ __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData; __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData; SrcDataStart = (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header)); SrcDataEnd = SrcDataStart + Header->DataSize; if (ProfileSize < sizeof(__llvm_profile_header)) return 1; /* Check the header first. */ if (Header->Magic != __llvm_profile_get_magic() || Header->Version != __llvm_profile_get_version() || Header->DataSize != __llvm_profile_get_data_size(__llvm_profile_begin_data(), __llvm_profile_end_data()) || Header->CountersSize != (uint64_t)(__llvm_profile_end_counters() - __llvm_profile_begin_counters()) || Header->NamesSize != (uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names()) || Header->ValueKindLast != IPVK_Last) return 1; if (ProfileSize < sizeof(__llvm_profile_header) + Header->DataSize * sizeof(__llvm_profile_data) + Header->NamesSize + Header->CountersSize) return 1; for (SrcData = SrcDataStart, DstData = (__llvm_profile_data *)__llvm_profile_begin_data(); SrcData < SrcDataEnd; ++SrcData, ++DstData) { if (SrcData->NameRef != DstData->NameRef || SrcData->FuncHash != DstData->FuncHash || SrcData->NumCounters != DstData->NumCounters) return 1; } /* Matched! */ return 0; } COMPILER_RT_VISIBILITY void __llvm_profile_merge_from_buffer(const char *ProfileData, uint64_t ProfileSize) { __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData; __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData; uint64_t *SrcCountersStart; const char *SrcNameStart; ValueProfData *SrcValueProfDataStart, *SrcValueProfData; SrcDataStart = (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header)); SrcDataEnd = SrcDataStart + Header->DataSize; SrcCountersStart = (uint64_t *)SrcDataEnd; SrcNameStart = (const char *)(SrcCountersStart + Header->CountersSize); SrcValueProfDataStart = (ValueProfData *)(SrcNameStart + Header->NamesSize + __llvm_profile_get_num_padding_bytes( Header->NamesSize)); for (SrcData = SrcDataStart, DstData = (__llvm_profile_data *)__llvm_profile_begin_data(), SrcValueProfData = SrcValueProfDataStart; SrcData < SrcDataEnd; ++SrcData, ++DstData) { uint64_t *SrcCounters; uint64_t *DstCounters = (uint64_t *)DstData->CounterPtr; unsigned I, NC, NVK = 0; NC = SrcData->NumCounters; SrcCounters = SrcCountersStart + ((size_t)SrcData->CounterPtr - Header->CountersDelta) / sizeof(uint64_t); for (I = 0; I < NC; I++) DstCounters[I] += SrcCounters[I]; /* Now merge value profile data. */ if (!VPMergeHook) continue; for (I = 0; I <= IPVK_Last; I++) NVK += (SrcData->NumValueSites[I] != 0); if (!NVK) continue; VPMergeHook(SrcValueProfData, DstData); SrcValueProfData = (ValueProfData *)((char *)SrcValueProfData + SrcValueProfData->TotalSize); } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingInternal.h0000664000175000017500000001555212776214734025056 0ustar kaikai/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_INTERNALH_ #define PROFILE_INSTRPROFILING_INTERNALH_ #include "InstrProfiling.h" #include "stddef.h" /*! * \brief Write instrumentation data to the given buffer, given explicit * pointers to the live data in memory. This function is probably not what you * want. Use __llvm_profile_get_size_for_buffer instead. Use this function if * your program has a custom memory layout. */ uint64_t __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); /*! * \brief Write instrumentation data to the given buffer, given explicit * pointers to the live data in memory. This function is probably not what you * want. Use __llvm_profile_write_buffer instead. Use this function if your * program has a custom memory layout. * * \pre \c Buffer is the start of a buffer at least as big as \a * __llvm_profile_get_size_for_buffer_internal(). */ int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); /*! * The data structure describing the data to be written by the * low level writer callback function. */ typedef struct ProfDataIOVec { const void *Data; size_t ElmSize; size_t NumElm; } ProfDataIOVec; typedef uint32_t (*WriterCallback)(ProfDataIOVec *, uint32_t NumIOVecs, void **WriterCtx); /*! * The data structure for buffered IO of profile data. */ typedef struct ProfBufferIO { /* File handle. */ void *File; /* Low level IO callback. */ WriterCallback FileWriter; /* The start of the buffer. */ uint8_t *BufferStart; /* Total size of the buffer. */ uint32_t BufferSz; /* Current byte offset from the start of the buffer. */ uint32_t CurOffset; } ProfBufferIO; /* The creator interface used by testing. */ ProfBufferIO *lprofCreateBufferIOInternal(void *File, uint32_t BufferSz); /*! * This is the interface to create a handle for buffered IO. */ ProfBufferIO *lprofCreateBufferIO(WriterCallback FileWriter, void *File); /*! * The interface to destroy the bufferIO handle and reclaim * the memory. */ void lprofDeleteBufferIO(ProfBufferIO *BufferIO); /*! * This is the interface to write \c Data of \c Size bytes through * \c BufferIO. Returns 0 if successful, otherwise return -1. */ int lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size); /*! * The interface to flush the remaining data in the buffer. * through the low level writer callback. */ int lprofBufferIOFlush(ProfBufferIO *BufferIO); /* The low level interface to write data into a buffer. It is used as the * callback by other high level writer methods such as buffered IO writer * and profile data writer. */ uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx); struct ValueProfData; struct ValueProfRecord; struct InstrProfValueData; struct ValueProfNode; /*! * The class that defines a set of methods to read value profile * data for streaming/serialization from the instrumentation runtime. */ typedef struct VPDataReaderType { uint32_t (*InitRTRecord)(const __llvm_profile_data *Data, uint8_t *SiteCountArray[]); /* Function pointer to getValueProfRecordHeader method. */ uint32_t (*GetValueProfRecordHeaderSize)(uint32_t NumSites); /* Function pointer to getFristValueProfRecord method. */ struct ValueProfRecord *(*GetFirstValueProfRecord)(struct ValueProfData *); /* Return the number of value data for site \p Site. */ uint32_t (*GetNumValueDataForSite)(uint32_t VK, uint32_t Site); /* Return the total size of the value profile data of the * current function. */ uint32_t (*GetValueProfDataSize)(void); /*! * Read the next \p N value data for site \p Site and store the data * in \p Dst. \p StartNode is the first value node to start with if * it is not null. The function returns the pointer to the value * node pointer to be used as the \p StartNode of the next batch reading. * If there is nothing left, it returns NULL. */ struct ValueProfNode *(*GetValueData)(uint32_t ValueKind, uint32_t Site, struct InstrProfValueData *Dst, struct ValueProfNode *StartNode, uint32_t N); } VPDataReaderType; int lprofWriteData(WriterCallback Writer, void *WriterCtx, VPDataReaderType *VPDataReader); int lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, VPDataReaderType *VPDataReader, const char *NamesBegin, const char *NamesEnd); /* Merge value profile data pointed to by SrcValueProfData into * in-memory profile counters pointed by to DstData. */ void lprofMergeValueProfData(struct ValueProfData *SrcValueProfData, __llvm_profile_data *DstData); VPDataReaderType *lprofGetVPDataReader(); /* Internal interface used by test to reset the max number of * tracked values per value site to be \p MaxVals. */ void lprofSetMaxValsPerSite(uint32_t MaxVals); void lprofSetupValueProfiler(); /* Return the profile header 'signature' value associated with the current * executable or shared library. The signature value can be used to for * a profile name that is unique to this load module so that it does not * collide with profiles from other binaries. It also allows shared libraries * to dump merged profile data into its own profile file. */ uint64_t lprofGetLoadModuleSignature(); COMPILER_RT_VISIBILITY extern char *(*GetEnvHook)(const char *); COMPILER_RT_VISIBILITY extern void (*FreeHook)(void *); COMPILER_RT_VISIBILITY extern uint8_t *DynamicBufferIOBuffer; COMPILER_RT_VISIBILITY extern uint32_t VPBufferSize; COMPILER_RT_VISIBILITY extern uint32_t VPMaxNumValsPerSite; /* Pointer to the start of static value counters to be allocted. */ COMPILER_RT_VISIBILITY extern ValueProfNode *CurrentVNode; COMPILER_RT_VISIBILITY extern ValueProfNode *EndVNode; extern void (*VPMergeHook)(struct ValueProfData *, __llvm_profile_data *); #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingPort.h0000664000175000017500000001003012776214734024210 0ustar kaikai/*===- InstrProfilingPort.h- Support library for PGO instrumentation ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_PORT_H_ #define PROFILE_INSTRPROFILING_PORT_H_ #ifdef _MSC_VER #define COMPILER_RT_ALIGNAS(x) __declspec(align(x)) #define COMPILER_RT_VISIBILITY /* FIXME: selectany does not have the same semantics as weak. */ #define COMPILER_RT_WEAK __declspec(selectany) /* Need to include */ #define COMPILER_RT_ALLOCA _alloca /* Need to include and */ #define COMPILER_RT_FTRUNCATE(f,l) _chsize(_fileno(f),l) #elif __GNUC__ #define COMPILER_RT_ALIGNAS(x) __attribute__((aligned(x))) #define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden"))) #define COMPILER_RT_WEAK __attribute__((weak)) #define COMPILER_RT_ALLOCA __builtin_alloca #define COMPILER_RT_FTRUNCATE(f,l) ftruncate(fileno(f),l) #endif #if defined(__APPLE__) #define COMPILER_RT_SEG "__DATA," #else #define COMPILER_RT_SEG "" #endif #ifdef _MSC_VER #define COMPILER_RT_SECTION(Sect) __declspec(allocate(Sect)) #else #define COMPILER_RT_SECTION(Sect) __attribute__((section(Sect))) #endif #define COMPILER_RT_MAX_HOSTLEN 128 #ifdef _MSC_VER #define COMPILER_RT_GETHOSTNAME(Name, Len) gethostname(Name, Len) #elif defined(__ORBIS__) #define COMPILER_RT_GETHOSTNAME(Name, Len) ((void)(Name), (void)(Len), (-1)) #else #define COMPILER_RT_GETHOSTNAME(Name, Len) lprofGetHostName(Name, Len) #define COMPILER_RT_HAS_UNAME 1 #endif #if COMPILER_RT_HAS_ATOMICS == 1 #ifdef _MSC_VER #include #if _MSC_VER < 1900 #define snprintf _snprintf #endif #if defined(_WIN64) #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ (InterlockedCompareExchange64((LONGLONG volatile *)Ptr, (LONGLONG)NewV, \ (LONGLONG)OldV) == (LONGLONG)OldV) #define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \ (DomType *)InterlockedExchangeAdd64((LONGLONG volatile *)&PtrVar, \ (LONGLONG)sizeof(DomType) * PtrIncr) #else /* !defined(_WIN64) */ #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ (InterlockedCompareExchange((LONG volatile *)Ptr, (LONG)NewV, (LONG)OldV) == \ (LONG)OldV) #define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \ (DomType *)InterlockedExchangeAdd((LONG volatile *)&PtrVar, \ (LONG)sizeof(DomType) * PtrIncr) #endif #else /* !defined(_MSC_VER) */ #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ __sync_bool_compare_and_swap(Ptr, OldV, NewV) #define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \ (DomType *)__sync_fetch_and_add((long *)&PtrVar, sizeof(DomType) * PtrIncr) #endif #else /* COMPILER_RT_HAS_ATOMICS != 1 */ #include "InstrProfilingUtil.h" #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ lprofBoolCmpXchg((void **)Ptr, OldV, NewV) #define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \ (DomType *)lprofPtrFetchAdd((void **)&PtrVar, sizeof(DomType) * PtrIncr) #endif #define PROF_ERR(Format, ...) \ fprintf(stderr, "LLVM Profile Error: " Format, __VA_ARGS__); #define PROF_WARN(Format, ...) \ fprintf(stderr, "LLVM Profile Warning: " Format, __VA_ARGS__); #define PROF_NOTE(Format, ...) \ fprintf(stderr, "LLVM Profile Note: " Format, __VA_ARGS__); #if defined(__FreeBSD__) #include #include #else /* defined(__FreeBSD__) */ #include #include #endif /* defined(__FreeBSD__) && defined(__i386__) */ #endif /* PROFILE_INSTRPROFILING_PORT_H_ */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingPlatformLinux.c0000664000175000017500000000570112776214734026074 0ustar kaikai/*===- InstrProfilingPlatformLinux.c - Profile data Linux platform ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if defined(__linux__) || defined(__FreeBSD__) #include #define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) #define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_SECT_NAME) #define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_SECT_NAME) #define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_SECT_NAME) #define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_SECT_NAME) #define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_SECT_NAME) #define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_SECT_NAME) #define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_SECT_NAME) /* Declare section start and stop symbols for various sections * generated by compiler instrumentation. */ extern __llvm_profile_data PROF_DATA_START COMPILER_RT_VISIBILITY; extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY; extern uint64_t PROF_CNTS_START COMPILER_RT_VISIBILITY; extern uint64_t PROF_CNTS_STOP COMPILER_RT_VISIBILITY; extern char PROF_NAME_START COMPILER_RT_VISIBILITY; extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY; extern ValueProfNode PROF_VNODES_START COMPILER_RT_VISIBILITY; extern ValueProfNode PROF_VNODES_STOP COMPILER_RT_VISIBILITY; /* Add dummy data to ensure the section is always created. */ __llvm_profile_data __prof_data_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_DATA_SECT_NAME_STR); uint64_t __prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME_STR); char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME_STR); ValueProfNode __prof_vnodes_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_VNODES_SECT_NAME_STR); COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_begin_data(void) { return &PROF_DATA_START; } COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_end_data(void) { return &PROF_DATA_STOP; } COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) { return &PROF_NAME_START; } COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) { return &PROF_NAME_STOP; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return &PROF_CNTS_START; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return &PROF_CNTS_STOP; } COMPILER_RT_VISIBILITY ValueProfNode * __llvm_profile_begin_vnodes(void) { return &PROF_VNODES_START; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) { return &PROF_VNODES_STOP; } COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP; #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingPlatformDarwin.c0000664000175000017500000000440212776214734026216 0ustar kaikai/*===- InstrProfilingPlatformDarwin.c - Profile data on Darwin ------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if defined(__APPLE__) /* Use linker magic to find the bounds of the Data section. */ COMPILER_RT_VISIBILITY extern __llvm_profile_data DataStart __asm("section$start$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern __llvm_profile_data DataEnd __asm("section$end$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern char NamesStart __asm("section$start$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern char NamesEnd __asm("section$end$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern uint64_t CountersStart __asm("section$start$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern uint64_t CountersEnd __asm("section$end$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern ValueProfNode VNodesStart __asm("section$start$__DATA$" INSTR_PROF_VNODES_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern ValueProfNode VNodesEnd __asm("section$end$__DATA$" INSTR_PROF_VNODES_SECT_NAME_STR); COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_begin_data(void) { return &DataStart; } COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_end_data(void) { return &DataEnd; } COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) { return &NamesStart; } COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) { return &NamesEnd; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_begin_vnodes(void) { return &VNodesStart; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) { return &VNodesEnd; } COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &VNodesStart; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &VNodesEnd; #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-39/InstrProfilingUtil.c0000664000175000017500000000560612776214734024211 0ustar kaikai/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfilingUtil.h" #include "InstrProfiling.h" #ifdef _WIN32 #include #include #include #else #include #include #include #include #include #endif #ifdef COMPILER_RT_HAS_UNAME #include #endif #include COMPILER_RT_VISIBILITY void __llvm_profile_recursive_mkdir(char *path) { int i; for (i = 1; path[i] != '\0'; ++i) { char save = path[i]; if (!(path[i] == '/' || path[i] == '\\')) continue; path[i] = '\0'; #ifdef _WIN32 _mkdir(path); #else mkdir(path, 0755); /* Some of these will fail, ignore it. */ #endif path[i] = save; } } #if COMPILER_RT_HAS_ATOMICS != 1 COMPILER_RT_VISIBILITY uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) { void *R = *Ptr; if (R == OldV) { *Ptr = NewV; return 1; } return 0; } COMPILER_RT_VISIBILITY void *lprofPtrFetchAdd(void **Mem, long ByteIncr) { void *Old = *Mem; *((char **)Mem) += ByteIncr; return Old; } #endif #ifdef COMPILER_RT_HAS_UNAME COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) { struct utsname N; int R; if (!(R = uname(&N))) strncpy(Name, N.nodename, Len); return R; } #endif COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) { FILE *f; int fd; #ifdef COMPILER_RT_HAS_FCNTL_LCK struct flock s_flock; s_flock.l_whence = SEEK_SET; s_flock.l_start = 0; s_flock.l_len = 0; /* Until EOF. */ s_flock.l_pid = getpid(); s_flock.l_type = F_WRLCK; fd = open(ProfileName, O_RDWR | O_CREAT, 0666); if (fd < 0) return NULL; while (fcntl(fd, F_SETLKW, &s_flock) == -1) { if (errno != EINTR) { if (errno == ENOLCK) { PROF_WARN("Data may be corrupted during profile merging : %s\n", "Fail to obtain file lock due to system limit."); } break; } } f = fdopen(fd, "r+b"); #elif defined(_WIN32) HANDLE h = CreateFile(ProfileName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (h == INVALID_HANDLE_VALUE) return NULL; fd = _open_osfhandle((intptr_t)h, 0); if (fd == -1) { CloseHandle(h); return NULL; } f = _fdopen(fd, "r+b"); if (f == 0) { CloseHandle(h); return NULL; } #else /* Worst case no locking applied. */ PROF_WARN("Concurrent file access is not supported : %s\n", "lack file locking"); fd = open(ProfileName, O_RDWR | O_CREAT, 0666); if (fd < 0) return NULL; f = fdopen(fd, "r+b"); #endif return f; } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/0000775000175000017500000000000012776214734020217 5ustar kaikaildc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfData.inc0000664000175000017500000006112012776214734023432 0ustar kaikai/*===-- InstrProfData.inc - instr profiling runtime structures -*- C++ -*-=== *\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ /* * This is the master file that defines all the data structure, signature, * constant literals that are shared across profiling runtime library, * compiler (instrumentation), and host tools (reader/writer). The entities * defined in this file affect the profile runtime ABI, the raw profile format, * or both. * * The file has two identical copies. The master copy lives in LLVM and * the other one sits in compiler-rt/lib/profile directory. To make changes * in this file, first modify the master copy and copy it over to compiler-rt. * Testing of any change in this file can start only after the two copies are * synced up. * * The first part of the file includes macros that defines types, names, and * initializers for the member fields of the core data structures. The field * declarations for one structure is enabled by defining the field activation * macro associated with that structure. Only one field activation record * can be defined at one time and the rest definitions will be filtered out by * the preprocessor. * * Examples of how the template is used to instantiate structure definition: * 1. To declare a structure: * * struct ProfData { * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \ * Type Name; * #include "llvm/ProfileData/InstrProfData.inc" * }; * * 2. To construct LLVM type arrays for the struct type: * * Type *DataTypes[] = { * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \ * LLVMType, * #include "llvm/ProfileData/InstrProfData.inc" * }; * * 4. To construct constant array for the initializers: * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \ * Initializer, * Constant *ConstantVals[] = { * #include "llvm/ProfileData/InstrProfData.inc" * }; * * * The second part of the file includes definitions all other entities that * are related to runtime ABI and format. When no field activation macro is * defined, this file can be included to introduce the definitions. * \*===----------------------------------------------------------------------===*/ /* Functions marked with INSTR_PROF_VISIBILITY must have hidden visibility in * the compiler runtime. */ #ifndef INSTR_PROF_VISIBILITY #define INSTR_PROF_VISIBILITY #endif /* INSTR_PROF_DATA start. */ /* Definition of member fields of the per-function control structure. */ #ifndef INSTR_PROF_DATA #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), NameRef, \ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ IndexedInstrProf::ComputeHash(getPGOFuncNameVarInitializer(Inc->getName())))) INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ Inc->getHash()->getZExtValue())) INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \ ConstantExpr::getBitCast(CounterPtr, \ llvm::Type::getInt64PtrTy(Ctx))) /* This is used to map function pointers for the indirect call targets to * function name hashes during the conversion from raw to merged profile * data. */ INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \ FunctionAddr) INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \ ValuesPtrExpr) INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters)) INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \ ConstantArray::get(Int16ArrayTy, Int16ArrayVals)) #undef INSTR_PROF_DATA /* INSTR_PROF_DATA end. */ /* This is an internal data structure used by value profiler. It * is defined here to allow serialization code sharing by LLVM * to be used in unit test. * * typedef struct ValueProfNode { * // InstrProfValueData VData; * uint64_t Value; * uint64_t Count; * struct ValueProfNode *Next; * } ValueProfNode; */ /* INSTR_PROF_VALUE_NODE start. */ #ifndef INSTR_PROF_VALUE_NODE #define INSTR_PROF_VALUE_NODE(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif INSTR_PROF_VALUE_NODE(uint64_t, llvm::Type::getInt64Ty(Ctx), Value, \ ConstantInt::get(llvm::Type::GetInt64Ty(Ctx), 0)) INSTR_PROF_VALUE_NODE(uint64_t, llvm::Type::getInt64Ty(Ctx), Count, \ ConstantInt::get(llvm::Type::GetInt64Ty(Ctx), 0)) INSTR_PROF_VALUE_NODE(PtrToNodeT, llvm::Type::getInt8PtrTy(Ctx), Next, \ ConstantInt::get(llvm::Type::GetInt8PtrTy(Ctx), 0)) #undef INSTR_PROF_VALUE_NODE /* INSTR_PROF_VALUE_NODE end. */ /* INSTR_PROF_RAW_HEADER start */ /* Definition of member fields of the raw profile header data structure. */ #ifndef INSTR_PROF_RAW_HEADER #define INSTR_PROF_RAW_HEADER(Type, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic()) INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version()) INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize) INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize) INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize) INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin) INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin) INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last) #undef INSTR_PROF_RAW_HEADER /* INSTR_PROF_RAW_HEADER end */ /* VALUE_PROF_FUNC_PARAM start */ /* Definition of parameter types of the runtime API used to do value profiling * for a given value site. */ #ifndef VALUE_PROF_FUNC_PARAM #define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType) #define INSTR_PROF_COMMA #else #define INSTR_PROF_DATA_DEFINED #define INSTR_PROF_COMMA , #endif VALUE_PROF_FUNC_PARAM(uint64_t, TargetValue, Type::getInt64Ty(Ctx)) \ INSTR_PROF_COMMA VALUE_PROF_FUNC_PARAM(void *, Data, Type::getInt8PtrTy(Ctx)) INSTR_PROF_COMMA VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) #undef VALUE_PROF_FUNC_PARAM #undef INSTR_PROF_COMMA /* VALUE_PROF_FUNC_PARAM end */ /* VALUE_PROF_KIND start */ #ifndef VALUE_PROF_KIND #define VALUE_PROF_KIND(Enumerator, Value) #else #define INSTR_PROF_DATA_DEFINED #endif /* For indirect function call value profiling, the addresses of the target * functions are profiled by the instrumented code. The target addresses are * written in the raw profile data and converted to target function name's MD5 * hash by the profile reader during deserialization. Typically, this happens * when the the raw profile data is read during profile merging. * * For this remapping the ProfData is used. ProfData contains both the function * name hash and the function address. */ VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0) /* These two kinds must be the last to be * declared. This is to make sure the string * array created with the template can be * indexed with the kind value. */ VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget) VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget) #undef VALUE_PROF_KIND /* VALUE_PROF_KIND end */ /* COVMAP_FUNC_RECORD start */ /* Definition of member fields of the function record structure in coverage * map. */ #ifndef COVMAP_FUNC_RECORD #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif #ifdef COVMAP_V1 COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \ NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \ llvm::Type::getInt8PtrTy(Ctx))) COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), \ NameValue.size())) #else COVMAP_FUNC_RECORD(const int64_t, llvm::Type::getInt64Ty(Ctx), NameRef, \ llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ llvm::IndexedInstrProf::ComputeHash(NameValue))) #endif COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), DataSize, \ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\ CoverageMapping.size())) COVMAP_FUNC_RECORD(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \ llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), FuncHash)) #undef COVMAP_FUNC_RECORD /* COVMAP_FUNC_RECORD end. */ /* COVMAP_HEADER start */ /* Definition of member fields of coverage map header. */ #ifndef COVMAP_HEADER #define COVMAP_HEADER(Type, LLVMType, Name, Initializer) #else #define INSTR_PROF_DATA_DEFINED #endif COVMAP_HEADER(uint32_t, Int32Ty, NRecords, \ llvm::ConstantInt::get(Int32Ty, FunctionRecords.size())) COVMAP_HEADER(uint32_t, Int32Ty, FilenamesSize, \ llvm::ConstantInt::get(Int32Ty, FilenamesSize)) COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \ llvm::ConstantInt::get(Int32Ty, CoverageMappingSize)) COVMAP_HEADER(uint32_t, Int32Ty, Version, \ llvm::ConstantInt::get(Int32Ty, CovMapVersion::CurrentVersion)) #undef COVMAP_HEADER /* COVMAP_HEADER end. */ #ifdef INSTR_PROF_VALUE_PROF_DATA #define INSTR_PROF_DATA_DEFINED #define INSTR_PROF_MAX_NUM_VAL_PER_SITE 255 /*! * This is the header of the data structure that defines the on-disk * layout of the value profile data of a particular kind for one function. */ typedef struct ValueProfRecord { /* The kind of the value profile record. */ uint32_t Kind; /* * The number of value profile sites. It is guaranteed to be non-zero; * otherwise the record for this kind won't be emitted. */ uint32_t NumValueSites; /* * The first element of the array that stores the number of profiled * values for each value site. The size of the array is NumValueSites. * Since NumValueSites is greater than zero, there is at least one * element in the array. */ uint8_t SiteCountArray[1]; /* * The fake declaration is for documentation purpose only. * Align the start of next field to be on 8 byte boundaries. uint8_t Padding[X]; */ /* The array of value profile data. The size of the array is the sum * of all elements in SiteCountArray[]. InstrProfValueData ValueData[]; */ #ifdef __cplusplus /*! * \brief Return the number of value sites. */ uint32_t getNumValueSites() const { return NumValueSites; } /*! * \brief Read data from this record and save it to Record. */ void deserializeTo(InstrProfRecord &Record, InstrProfRecord::ValueMapType *VMap); /* * In-place byte swap: * Do byte swap for this instance. \c Old is the original order before * the swap, and \c New is the New byte order. */ void swapBytes(support::endianness Old, support::endianness New); #endif } ValueProfRecord; /*! * Per-function header/control data structure for value profiling * data in indexed format. */ typedef struct ValueProfData { /* * Total size in bytes including this field. It must be a multiple * of sizeof(uint64_t). */ uint32_t TotalSize; /* *The number of value profile kinds that has value profile data. * In this implementation, a value profile kind is considered to * have profile data if the number of value profile sites for the * kind is not zero. More aggressively, the implementation can * choose to check the actual data value: if none of the value sites * has any profiled values, the kind can be skipped. */ uint32_t NumValueKinds; /* * Following are a sequence of variable length records. The prefix/header * of each record is defined by ValueProfRecord type. The number of * records is NumValueKinds. * ValueProfRecord Record_1; * ValueProfRecord Record_N; */ #if __cplusplus /*! * Return the total size in bytes of the on-disk value profile data * given the data stored in Record. */ static uint32_t getSize(const InstrProfRecord &Record); /*! * Return a pointer to \c ValueProfData instance ready to be streamed. */ static std::unique_ptr serializeFrom(const InstrProfRecord &Record); /*! * Check the integrity of the record. */ Error checkIntegrity(); /*! * Return a pointer to \c ValueProfileData instance ready to be read. * All data in the instance are properly byte swapped. The input * data is assumed to be in little endian order. */ static Expected> getValueProfData(const unsigned char *SrcBuffer, const unsigned char *const SrcBufferEnd, support::endianness SrcDataEndianness); /*! * Swap byte order from \c Endianness order to host byte order. */ void swapBytesToHost(support::endianness Endianness); /*! * Swap byte order from host byte order to \c Endianness order. */ void swapBytesFromHost(support::endianness Endianness); /*! * Return the total size of \c ValueProfileData. */ uint32_t getSize() const { return TotalSize; } /*! * Read data from this data and save it to \c Record. */ void deserializeTo(InstrProfRecord &Record, InstrProfRecord::ValueMapType *VMap); void operator delete(void *ptr) { ::operator delete(ptr); } #endif } ValueProfData; /* * The closure is designed to abstact away two types of value profile data: * - InstrProfRecord which is the primary data structure used to * represent profile data in host tools (reader, writer, and profile-use) * - value profile runtime data structure suitable to be used by C * runtime library. * * Both sources of data need to serialize to disk/memory-buffer in common * format: ValueProfData. The abstraction allows compiler-rt's raw profiler * writer to share the same format and code with indexed profile writer. * * For documentation of the member methods below, refer to corresponding methods * in class InstrProfRecord. */ typedef struct ValueProfRecordClosure { const void *Record; uint32_t (*GetNumValueKinds)(const void *Record); uint32_t (*GetNumValueSites)(const void *Record, uint32_t VKind); uint32_t (*GetNumValueData)(const void *Record, uint32_t VKind); uint32_t (*GetNumValueDataForSite)(const void *R, uint32_t VK, uint32_t S); /* * After extracting the value profile data from the value profile record, * this method is used to map the in-memory value to on-disk value. If * the method is null, value will be written out untranslated. */ uint64_t (*RemapValueData)(uint32_t, uint64_t Value); void (*GetValueForSite)(const void *R, InstrProfValueData *Dst, uint32_t K, uint32_t S); ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes); } ValueProfRecordClosure; INSTR_PROF_VISIBILITY ValueProfRecord * getFirstValueProfRecord(ValueProfData *VPD); INSTR_PROF_VISIBILITY ValueProfRecord * getValueProfRecordNext(ValueProfRecord *VPR); INSTR_PROF_VISIBILITY InstrProfValueData * getValueProfRecordValueData(ValueProfRecord *VPR); INSTR_PROF_VISIBILITY uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites); #undef INSTR_PROF_VALUE_PROF_DATA #endif /* INSTR_PROF_VALUE_PROF_DATA */ #ifdef INSTR_PROF_COMMON_API_IMPL #define INSTR_PROF_DATA_DEFINED #ifdef __cplusplus #define INSTR_PROF_INLINE inline #define INSTR_PROF_NULLPTR nullptr #else #define INSTR_PROF_INLINE #define INSTR_PROF_NULLPTR NULL #endif #ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif /*! * \brief Return the \c ValueProfRecord header size including the * padding bytes. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) + sizeof(uint8_t) * NumValueSites; /* Round the size to multiple of 8 bytes. */ Size = (Size + 7) & ~7; return Size; } /*! * \brief Return the total size of the value profile record including the * header and the value data. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordSize(uint32_t NumValueSites, uint32_t NumValueData) { return getValueProfRecordHeaderSize(NumValueSites) + sizeof(InstrProfValueData) * NumValueData; } /*! * \brief Return the pointer to the start of value data array. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize( This->NumValueSites)); } /*! * \brief Return the total number of value data for \c This record. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { uint32_t NumValueData = 0; uint32_t I; for (I = 0; I < This->NumValueSites; I++) NumValueData += This->SiteCountArray[I]; return NumValueData; } /*! * \brief Use this method to advance to the next \c This \c ValueProfRecord. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { uint32_t NumValueData = getValueProfRecordNumValueData(This); return (ValueProfRecord *)((char *)This + getValueProfRecordSize(This->NumValueSites, NumValueData)); } /*! * \brief Return the first \c ValueProfRecord instance. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) { return (ValueProfRecord *)((char *)This + sizeof(ValueProfData)); } /* Closure based interfaces. */ /*! * Return the total size in bytes of the on-disk value profile data * given the data stored in Record. */ INSTR_PROF_VISIBILITY uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) { uint32_t Kind; uint32_t TotalSize = sizeof(ValueProfData); const void *Record = Closure->Record; for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { uint32_t NumValueSites = Closure->GetNumValueSites(Record, Kind); if (!NumValueSites) continue; TotalSize += getValueProfRecordSize(NumValueSites, Closure->GetNumValueData(Record, Kind)); } return TotalSize; } /*! * Extract value profile data of a function for the profile kind \c ValueKind * from the \c Closure and serialize the data into \c This record instance. */ INSTR_PROF_VISIBILITY void serializeValueProfRecordFrom(ValueProfRecord *This, ValueProfRecordClosure *Closure, uint32_t ValueKind, uint32_t NumValueSites) { uint32_t S; const void *Record = Closure->Record; This->Kind = ValueKind; This->NumValueSites = NumValueSites; InstrProfValueData *DstVD = getValueProfRecordValueData(This); for (S = 0; S < NumValueSites; S++) { uint32_t ND = Closure->GetNumValueDataForSite(Record, ValueKind, S); This->SiteCountArray[S] = ND; Closure->GetValueForSite(Record, DstVD, ValueKind, S); DstVD += ND; } } /*! * Extract value profile data of a function from the \c Closure * and serialize the data into \c DstData if it is not NULL or heap * memory allocated by the \c Closure's allocator method. If \c * DstData is not null, the caller is expected to set the TotalSize * in DstData. */ INSTR_PROF_VISIBILITY ValueProfData * serializeValueProfDataFrom(ValueProfRecordClosure *Closure, ValueProfData *DstData) { uint32_t Kind; uint32_t TotalSize = DstData ? DstData->TotalSize : getValueProfDataSize(Closure); ValueProfData *VPD = DstData ? DstData : Closure->AllocValueProfData(TotalSize); VPD->TotalSize = TotalSize; VPD->NumValueKinds = Closure->GetNumValueKinds(Closure->Record); ValueProfRecord *VR = getFirstValueProfRecord(VPD); for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { uint32_t NumValueSites = Closure->GetNumValueSites(Closure->Record, Kind); if (!NumValueSites) continue; serializeValueProfRecordFrom(VR, Closure, Kind, NumValueSites); VR = getValueProfRecordNext(VR); } return VPD; } #undef INSTR_PROF_COMMON_API_IMPL #endif /* INSTR_PROF_COMMON_API_IMPL */ /*============================================================================*/ #ifndef INSTR_PROF_DATA_DEFINED #ifndef INSTR_PROF_DATA_INC #define INSTR_PROF_DATA_INC /* Helper macros. */ #define INSTR_PROF_SIMPLE_QUOTE(x) #x #define INSTR_PROF_QUOTE(x) INSTR_PROF_SIMPLE_QUOTE(x) #define INSTR_PROF_SIMPLE_CONCAT(x,y) x ## y #define INSTR_PROF_CONCAT(x,y) INSTR_PROF_SIMPLE_CONCAT(x,y) /* Magic number to detect file format and endianness. * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0, * so that utilities, like strings, don't grab it as a string. 129 is also * invalid UTF-8, and high enough to be interesting. * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR" * for 32-bit platforms. */ #define INSTR_PROF_RAW_MAGIC_64 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \ (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129 #define INSTR_PROF_RAW_MAGIC_32 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \ (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | \ (uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129 /* Raw profile format version (start from 1). */ #define INSTR_PROF_RAW_VERSION 4 /* Indexed profile format version (start from 1). */ #define INSTR_PROF_INDEX_VERSION 4 /* Coverage mapping format vresion (start from 0). */ #define INSTR_PROF_COVMAP_VERSION 1 /* Profile version is always of type uint64_t. Reserve the upper 8 bits in the * version for other variants of profile. We set the lowest bit of the upper 8 * bits (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentaiton * generated profile, and 0 if this is a Clang FE generated profile. */ #define VARIANT_MASKS_ALL 0xff00000000000000ULL #define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL) #define VARIANT_MASK_IR_PROF (0x1ULL << 56) #define INSTR_PROF_RAW_VERSION_VAR __llvm_profile_raw_version #define INSTR_PROF_PROFILE_RUNTIME_VAR __llvm_profile_runtime /* The variable that holds the name of the profile data * specified via command line. */ #define INSTR_PROF_PROFILE_NAME_VAR __llvm_profile_filename /* Runtime section names and name strings. */ #define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data #define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names #define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts /* Array of pointers. Each pointer points to a list * of value nodes associated with one value site. */ #define INSTR_PROF_VALS_SECT_NAME __llvm_prf_vals /* Value profile nodes section. */ #define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds #define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap #define INSTR_PROF_DATA_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME) #define INSTR_PROF_NAME_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME) #define INSTR_PROF_CNTS_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME) #define INSTR_PROF_COVMAP_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME) #define INSTR_PROF_VALS_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_VALS_SECT_NAME) #define INSTR_PROF_VNODES_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_VNODES_SECT_NAME) /* Macros to define start/stop section symbol for a given * section on Linux. For instance * INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) will * expand to __start___llvm_prof_data */ #define INSTR_PROF_SECT_START(Sect) \ INSTR_PROF_CONCAT(__start_,Sect) #define INSTR_PROF_SECT_STOP(Sect) \ INSTR_PROF_CONCAT(__stop_,Sect) /* Value Profiling API linkage name. */ #define INSTR_PROF_VALUE_PROF_FUNC __llvm_profile_instrument_target #define INSTR_PROF_VALUE_PROF_FUNC_STR \ INSTR_PROF_QUOTE(INSTR_PROF_VALUE_PROF_FUNC) /* InstrProfile per-function control data alignment. */ #define INSTR_PROF_DATA_ALIGNMENT 8 /* The data structure that represents a tracked value by the * value profiler. */ typedef struct InstrProfValueData { /* Profiled value. */ uint64_t Value; /* Number of times the value appears in the training run. */ uint64_t Count; } InstrProfValueData; #endif /* INSTR_PROF_DATA_INC */ #else #undef INSTR_PROF_DATA_DEFINED #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/GCDAProfiling.c0000664000175000017500000003414012776214734022735 0ustar kaikai/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* |*===----------------------------------------------------------------------===*| |* |* This file implements the call back routines for the gcov profiling |* instrumentation pass. Link against this library when running code through |* the -insert-gcov-profiling LLVM pass. |* |* We emit files in a corrupt version of GCOV's "gcda" file format. These files |* are only close enough that LCOV will happily parse them. Anything that lcov |* ignores is missing. |* |* TODO: gcov is multi-process safe by having each exit open the existing file |* and append to it. We'd like to achieve that and be thread-safe too. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfilingPort.h" #include "InstrProfilingUtil.h" #include #include #include #include #include #if defined(_WIN32) #include "WindowsMMap.h" #else #include #include #ifndef MAP_FILE #define MAP_FILE 0 #endif #endif #if defined(__FreeBSD__) && defined(__i386__) #define I386_FREEBSD 1 #else #define I386_FREEBSD 0 #endif #if !defined(_MSC_VER) && !I386_FREEBSD #include #endif #if defined(_MSC_VER) typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #elif I386_FREEBSD /* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to * FreeBSD 10, r232261) when compiled in 32-bit mode. */ typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #endif /* #define DEBUG_GCDAPROFILING */ /* * --- GCOV file format I/O primitives --- */ /* * The current file name we're outputting. Used primarily for error logging. */ static char *filename = NULL; /* * The current file we're outputting. */ static FILE *output_file = NULL; /* * Buffer that we write things into. */ #define WRITE_BUFFER_SIZE (128 * 1024) static char *write_buffer = NULL; static uint64_t cur_buffer_size = 0; static uint64_t cur_pos = 0; static uint64_t file_size = 0; static int new_file = 0; static int fd = -1; /* * A list of functions to write out the data. */ typedef void (*writeout_fn)(); struct writeout_fn_node { writeout_fn fn; struct writeout_fn_node *next; }; static struct writeout_fn_node *writeout_fn_head = NULL; static struct writeout_fn_node *writeout_fn_tail = NULL; /* * A list of flush functions that our __gcov_flush() function should call. */ typedef void (*flush_fn)(); struct flush_fn_node { flush_fn fn; struct flush_fn_node *next; }; static struct flush_fn_node *flush_fn_head = NULL; static struct flush_fn_node *flush_fn_tail = NULL; static void resize_write_buffer(uint64_t size) { if (!new_file) return; size += cur_pos; if (size <= cur_buffer_size) return; size = (size - 1) / WRITE_BUFFER_SIZE + 1; size *= WRITE_BUFFER_SIZE; write_buffer = realloc(write_buffer, size); cur_buffer_size = size; } static void write_bytes(const char *s, size_t len) { resize_write_buffer(len); memcpy(&write_buffer[cur_pos], s, len); cur_pos += len; } static void write_32bit_value(uint32_t i) { write_bytes((char*)&i, 4); } static void write_64bit_value(uint64_t i) { write_bytes((char*)&i, 8); } static uint32_t length_of_string(const char *s) { return (strlen(s) / 4) + 1; } static void write_string(const char *s) { uint32_t len = length_of_string(s); write_32bit_value(len); write_bytes(s, strlen(s)); write_bytes("\0\0\0\0", 4 - (strlen(s) % 4)); } static uint32_t read_32bit_value() { uint32_t val; if (new_file) return (uint32_t)-1; val = *(uint32_t*)&write_buffer[cur_pos]; cur_pos += 4; return val; } static uint64_t read_64bit_value() { uint64_t val; if (new_file) return (uint64_t)-1; val = *(uint64_t*)&write_buffer[cur_pos]; cur_pos += 8; return val; } static char *mangle_filename(const char *orig_filename) { char *new_filename; size_t prefix_len; int prefix_strip; const char *prefix = lprofGetPathPrefix(&prefix_strip, &prefix_len); if (prefix == NULL) return strdup(orig_filename); new_filename = malloc(prefix_len + 1 + strlen(orig_filename) + 1); lprofApplyPathPrefix(new_filename, orig_filename, prefix, prefix_len, prefix_strip); return new_filename; } static int map_file() { fseek(output_file, 0L, SEEK_END); file_size = ftell(output_file); /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an * error message because it should "just work" for the user. */ if (file_size == 0) return -1; write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); if (write_buffer == (void *)-1) { int errnum = errno; fprintf(stderr, "profiling: %s: cannot map: %s\n", filename, strerror(errnum)); return -1; } return 0; } static void unmap_file() { if (msync(write_buffer, file_size, MS_SYNC) == -1) { int errnum = errno; fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename, strerror(errnum)); } /* We explicitly ignore errors from unmapping because at this point the data * is written and we don't care. */ (void)munmap(write_buffer, file_size); write_buffer = NULL; file_size = 0; } /* * --- LLVM line counter API --- */ /* A file in this case is a translation unit. Each .o file built with line * profiling enabled will emit to a different file. Only one file may be * started at a time. */ void llvm_gcda_start_file(const char *orig_filename, const char version[4], uint32_t checksum) { const char *mode = "r+b"; filename = mangle_filename(orig_filename); /* Try just opening the file. */ new_file = 0; fd = open(filename, O_RDWR); if (fd == -1) { /* Try opening the file, creating it if necessary. */ new_file = 1; mode = "w+b"; fd = open(filename, O_RDWR | O_CREAT, 0644); if (fd == -1) { /* Try creating the directories first then opening the file. */ __llvm_profile_recursive_mkdir(filename); fd = open(filename, O_RDWR | O_CREAT, 0644); if (fd == -1) { /* Bah! It's hopeless. */ int errnum = errno; fprintf(stderr, "profiling: %s: cannot open: %s\n", filename, strerror(errnum)); return; } } } /* Try to flock the file to serialize concurrent processes writing out to the * same GCDA. This can fail if the filesystem doesn't support it, but in that * case we'll just carry on with the old racy behaviour and hope for the best. */ flock(fd, LOCK_EX); output_file = fdopen(fd, mode); /* Initialize the write buffer. */ write_buffer = NULL; cur_buffer_size = 0; cur_pos = 0; if (new_file) { resize_write_buffer(WRITE_BUFFER_SIZE); memset(write_buffer, 0, WRITE_BUFFER_SIZE); } else { if (map_file() == -1) { /* mmap failed, try to recover by clobbering */ new_file = 1; write_buffer = NULL; cur_buffer_size = 0; resize_write_buffer(WRITE_BUFFER_SIZE); memset(write_buffer, 0, WRITE_BUFFER_SIZE); } } /* gcda file, version, stamp checksum. */ write_bytes("adcg", 4); write_bytes(version, 4); write_32bit_value(checksum); #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: [%s]\n", orig_filename); #endif } /* Given an array of pointers to counters (counters), increment the n-th one, * where we're also given a pointer to n (predecessor). */ void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, uint64_t **counters) { uint64_t *counter; uint32_t pred; pred = *predecessor; if (pred == 0xffffffff) return; counter = counters[pred]; /* Don't crash if the pred# is out of sync. This can happen due to threads, or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ if (counter) ++*counter; #ifdef DEBUG_GCDAPROFILING else fprintf(stderr, "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n", *counter, *predecessor); #endif } void llvm_gcda_emit_function(uint32_t ident, const char *function_name, uint32_t func_checksum, uint8_t use_extra_checksum, uint32_t cfg_checksum) { uint32_t len = 2; if (use_extra_checksum) len++; #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident, function_name ? function_name : "NULL"); #endif if (!output_file) return; /* function tag */ write_bytes("\0\0\0\1", 4); if (function_name) len += 1 + length_of_string(function_name); write_32bit_value(len); write_32bit_value(ident); write_32bit_value(func_checksum); if (use_extra_checksum) write_32bit_value(cfg_checksum); if (function_name) write_string(function_name); } void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { uint32_t i; uint64_t *old_ctrs = NULL; uint32_t val = 0; uint64_t save_cur_pos = cur_pos; if (!output_file) return; val = read_32bit_value(); if (val != (uint32_t)-1) { /* There are counters present in the file. Merge them. */ if (val != 0x01a10000) { fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " "corrupt arc tag (0x%08x)\n", filename, val); return; } val = read_32bit_value(); if (val == (uint32_t)-1 || val / 2 != num_counters) { fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " "mismatched number of counters (%d)\n", filename, val); return; } old_ctrs = malloc(sizeof(uint64_t) * num_counters); for (i = 0; i < num_counters; ++i) old_ctrs[i] = read_64bit_value(); } cur_pos = save_cur_pos; /* Counter #1 (arcs) tag */ write_bytes("\0\0\xa1\1", 4); write_32bit_value(num_counters * 2); for (i = 0; i < num_counters; ++i) { counters[i] += (old_ctrs ? old_ctrs[i] : 0); write_64bit_value(counters[i]); } free(old_ctrs); #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: %u arcs\n", num_counters); for (i = 0; i < num_counters; ++i) fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]); #endif } void llvm_gcda_summary_info() { const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */ uint32_t i; uint32_t runs = 1; uint32_t val = 0; uint64_t save_cur_pos = cur_pos; if (!output_file) return; val = read_32bit_value(); if (val != (uint32_t)-1) { /* There are counters present in the file. Merge them. */ if (val != 0xa1000000) { fprintf(stderr, "profiling: %s: cannot merge previous run count: " "corrupt object tag (0x%08x)\n", filename, val); return; } val = read_32bit_value(); /* length */ if (val != obj_summary_len) { fprintf(stderr, "profiling: %s: cannot merge previous run count: " "mismatched object length (%d)\n", filename, val); return; } read_32bit_value(); /* checksum, unused */ read_32bit_value(); /* num, unused */ runs += read_32bit_value(); /* Add previous run count to new counter. */ } cur_pos = save_cur_pos; /* Object summary tag */ write_bytes("\0\0\0\xa1", 4); write_32bit_value(obj_summary_len); write_32bit_value(0); /* checksum, unused */ write_32bit_value(0); /* num, unused */ write_32bit_value(runs); for (i = 3; i < obj_summary_len; ++i) write_32bit_value(0); /* Program summary tag */ write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */ write_32bit_value(0); /* 0 length */ #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: %u runs\n", runs); #endif } void llvm_gcda_end_file() { /* Write out EOF record. */ if (output_file) { write_bytes("\0\0\0\0\0\0\0\0", 8); if (new_file) { fwrite(write_buffer, cur_pos, 1, output_file); free(write_buffer); } else { unmap_file(); } flock(fd, LOCK_UN); fclose(output_file); output_file = NULL; write_buffer = NULL; } free(filename); #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: -----\n"); #endif } void llvm_register_writeout_function(writeout_fn fn) { struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); new_node->fn = fn; new_node->next = NULL; if (!writeout_fn_head) { writeout_fn_head = writeout_fn_tail = new_node; } else { writeout_fn_tail->next = new_node; writeout_fn_tail = new_node; } } void llvm_writeout_files(void) { struct writeout_fn_node *curr = writeout_fn_head; while (curr) { curr->fn(); curr = curr->next; } } void llvm_delete_writeout_function_list(void) { while (writeout_fn_head) { struct writeout_fn_node *node = writeout_fn_head; writeout_fn_head = writeout_fn_head->next; free(node); } writeout_fn_head = writeout_fn_tail = NULL; } void llvm_register_flush_function(flush_fn fn) { struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); new_node->fn = fn; new_node->next = NULL; if (!flush_fn_head) { flush_fn_head = flush_fn_tail = new_node; } else { flush_fn_tail->next = new_node; flush_fn_tail = new_node; } } void __gcov_flush() { struct flush_fn_node *curr = flush_fn_head; while (curr) { curr->fn(); curr = curr->next; } } void llvm_delete_flush_function_list(void) { while (flush_fn_head) { struct flush_fn_node *node = flush_fn_head; flush_fn_head = flush_fn_head->next; free(node); } flush_fn_head = flush_fn_tail = NULL; } void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) { static int atexit_ran = 0; if (wfn) llvm_register_writeout_function(wfn); if (ffn) llvm_register_flush_function(ffn); if (atexit_ran == 0) { atexit_ran = 1; /* Make sure we write out the data and delete the data structures. */ atexit(llvm_delete_flush_function_list); atexit(llvm_delete_writeout_function_list); atexit(llvm_writeout_files); } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/WindowsMMap.h0000664000175000017500000000274712776214734022607 0ustar kaikai/*===- WindowsMMap.h - Support library for PGO instrumentation ------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_WINDOWS_MMAP_H #define PROFILE_INSTRPROFILING_WINDOWS_MMAP_H #if defined(_WIN32) #include #include #include /* * mmap() flags */ #define PROT_READ 0x1 #define PROT_WRITE 0x2 #define PROT_EXEC 0x0 #define MAP_FILE 0x00 #define MAP_SHARED 0x01 #define MAP_PRIVATE 0x02 #define MAP_ANONYMOUS 0x20 #define MAP_ANON MAP_ANONYMOUS #define MAP_FAILED ((void *) -1) /* * msync() flags */ #define MS_ASYNC 0x0001 /* return immediately */ #define MS_INVALIDATE 0x0002 /* invalidate all cached data */ #define MS_SYNC 0x0010 /* msync synchronously */ /* * flock() operations */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ #define LOCK_NB 4 /* don't block when locking */ #define LOCK_UN 8 /* unlock */ void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); void munmap(void *addr, size_t length); int msync(void *addr, size_t length, int flags); int flock(int fd, int operation); #endif /* _WIN32 */ #endif /* PROFILE_INSTRPROFILING_WINDOWS_MMAP_H */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingMergeFile.c0000664000175000017500000000302112776214734025110 0ustar kaikai/*===- InstrProfilingMergeFile.c - Profile in-process Merging ------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* |*===----------------------------------------------------------------------=== |* This file defines APIs needed to support in-process merging for profile data |* stored in files. \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include "InstrProfilingUtil.h" #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *) = &lprofMergeValueProfData; /* Merge value profile data pointed to by SrcValueProfData into * in-memory profile counters pointed by to DstData. */ void lprofMergeValueProfData(ValueProfData *SrcValueProfData, __llvm_profile_data *DstData) { unsigned I, S, V, C; InstrProfValueData *VData; ValueProfRecord *VR = getFirstValueProfRecord(SrcValueProfData); for (I = 0; I < SrcValueProfData->NumValueKinds; I++) { VData = getValueProfRecordValueData(VR); for (S = 0; S < VR->NumValueSites; S++) { uint8_t NV = VR->SiteCountArray[S]; for (V = 0; V < NV; V++) { for (C = 0; C < VData[V].Count; C++) __llvm_profile_instrument_target(VData[V].Value, DstData, S); } } VR = getValueProfRecordNext(VR); } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingWriter.c0000664000175000017500000002366312776214734024543 0ustar kaikai/*===- InstrProfilingWriter.c - Write instrumentation to a file or buffer -===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #ifdef _MSC_VER /* For _alloca */ #include #endif #include #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" COMPILER_RT_VISIBILITY void (*FreeHook)(void *) = NULL; static ProfBufferIO TheBufferIO; #define VP_BUFFER_SIZE 8 * 1024 static uint8_t BufferIOBuffer[VP_BUFFER_SIZE]; static InstrProfValueData VPDataArray[16]; static uint32_t VPDataArraySize = sizeof(VPDataArray) / sizeof(*VPDataArray); COMPILER_RT_VISIBILITY uint8_t *DynamicBufferIOBuffer = 0; COMPILER_RT_VISIBILITY uint32_t VPBufferSize = 0; /* The buffer writer is reponsponsible in keeping writer state * across the call. */ COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx) { uint32_t I; char **Buffer = (char **)WriterCtx; for (I = 0; I < NumIOVecs; I++) { size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm; memcpy(*Buffer, IOVecs[I].Data, Length); *Buffer += Length; } return 0; } static void llvmInitBufferIO(ProfBufferIO *BufferIO, WriterCallback FileWriter, void *File, uint8_t *Buffer, uint32_t BufferSz) { BufferIO->File = File; BufferIO->FileWriter = FileWriter; BufferIO->BufferStart = Buffer; BufferIO->BufferSz = BufferSz; BufferIO->CurOffset = 0; } COMPILER_RT_VISIBILITY ProfBufferIO * lprofCreateBufferIO(WriterCallback FileWriter, void *File) { uint8_t *Buffer = DynamicBufferIOBuffer; uint32_t BufferSize = VPBufferSize; if (!Buffer) { Buffer = &BufferIOBuffer[0]; BufferSize = sizeof(BufferIOBuffer); } llvmInitBufferIO(&TheBufferIO, FileWriter, File, Buffer, BufferSize); return &TheBufferIO; } COMPILER_RT_VISIBILITY void lprofDeleteBufferIO(ProfBufferIO *BufferIO) { if (DynamicBufferIOBuffer) { FreeHook(DynamicBufferIOBuffer); DynamicBufferIOBuffer = 0; VPBufferSize = 0; } } COMPILER_RT_VISIBILITY int lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) { /* Buffer is not large enough, it is time to flush. */ if (Size + BufferIO->CurOffset > BufferIO->BufferSz) { if (lprofBufferIOFlush(BufferIO) != 0) return -1; } /* Special case, bypass the buffer completely. */ ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}}; if (Size > BufferIO->BufferSz) { if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) return -1; } else { /* Write the data to buffer */ uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset; lprofBufferWriter(IO, 1, (void **)&Buffer); BufferIO->CurOffset = Buffer - BufferIO->BufferStart; } return 0; } COMPILER_RT_VISIBILITY int lprofBufferIOFlush(ProfBufferIO *BufferIO) { if (BufferIO->CurOffset) { ProfDataIOVec IO[] = { {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}}; if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) return -1; BufferIO->CurOffset = 0; } return 0; } /* Write out value profile data for function specified with \c Data. * The implementation does not use the method \c serializeValueProfData * which depends on dynamic memory allocation. In this implementation, * value profile data is written out to \c BufferIO piecemeal. */ static int writeOneValueProfData(ProfBufferIO *BufferIO, VPDataReaderType *VPDataReader, const __llvm_profile_data *Data) { unsigned I, NumValueKinds = 0; ValueProfData VPHeader; uint8_t *SiteCountArray[IPVK_Last + 1]; for (I = 0; I <= IPVK_Last; I++) { if (!Data->NumValueSites[I]) SiteCountArray[I] = 0; else { uint32_t Sz = VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) - offsetof(ValueProfRecord, SiteCountArray); /* Only use alloca for this small byte array to avoid excessive * stack growth. */ SiteCountArray[I] = (uint8_t *)COMPILER_RT_ALLOCA(Sz); memset(SiteCountArray[I], 0, Sz); } } /* If NumValueKinds returned is 0, there is nothing to write, report success and return. This should match the raw profile reader's behavior. */ if (!(NumValueKinds = VPDataReader->InitRTRecord(Data, SiteCountArray))) return 0; /* First write the header structure. */ VPHeader.TotalSize = VPDataReader->GetValueProfDataSize(); VPHeader.NumValueKinds = NumValueKinds; if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPHeader, sizeof(ValueProfData))) return -1; /* Make sure nothing else needs to be written before value profile * records. */ if ((void *)VPDataReader->GetFirstValueProfRecord(&VPHeader) != (void *)(&VPHeader + 1)) return -1; /* Write out the value profile record for each value kind * one by one. */ for (I = 0; I <= IPVK_Last; I++) { uint32_t J; ValueProfRecord RecordHeader; /* The size of the value prof record header without counting the * site count array .*/ uint32_t RecordHeaderSize = offsetof(ValueProfRecord, SiteCountArray); uint32_t SiteCountArraySize; if (!Data->NumValueSites[I]) continue; /* Write out the record header. */ RecordHeader.Kind = I; RecordHeader.NumValueSites = Data->NumValueSites[I]; if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&RecordHeader, RecordHeaderSize)) return -1; /* Write out the site value count array including padding space. */ SiteCountArraySize = VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) - RecordHeaderSize; if (lprofBufferIOWrite(BufferIO, SiteCountArray[I], SiteCountArraySize)) return -1; /* Write out the value profile data for each value site. */ for (J = 0; J < Data->NumValueSites[I]; J++) { uint32_t NRead, NRemain; ValueProfNode *NextStartNode = 0; NRemain = VPDataReader->GetNumValueDataForSite(I, J); if (!NRemain) continue; /* Read and write out value data in small chunks till it is done. */ do { NRead = (NRemain > VPDataArraySize ? VPDataArraySize : NRemain); NextStartNode = VPDataReader->GetValueData(I, /* ValueKind */ J, /* Site */ &VPDataArray[0], NextStartNode, NRead); if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPDataArray[0], NRead * sizeof(InstrProfValueData))) return -1; NRemain -= NRead; } while (NRemain != 0); } } /* All done report success. */ return 0; } static int writeValueProfData(WriterCallback Writer, void *WriterCtx, VPDataReaderType *VPDataReader, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd) { ProfBufferIO *BufferIO; const __llvm_profile_data *DI = 0; if (!VPDataReader) return 0; BufferIO = lprofCreateBufferIO(Writer, WriterCtx); for (DI = DataBegin; DI < DataEnd; DI++) { if (writeOneValueProfData(BufferIO, VPDataReader, DI)) return -1; } if (lprofBufferIOFlush(BufferIO) != 0) return -1; lprofDeleteBufferIO(BufferIO); return 0; } COMPILER_RT_VISIBILITY int lprofWriteData(WriterCallback Writer, void *WriterCtx, VPDataReaderType *VPDataReader) { /* Match logic in __llvm_profile_write_buffer(). */ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); return lprofWriteDataImpl(Writer, WriterCtx, DataBegin, DataEnd, CountersBegin, CountersEnd, VPDataReader, NamesBegin, NamesEnd); } COMPILER_RT_VISIBILITY int lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, VPDataReaderType *VPDataReader, const char *NamesBegin, const char *NamesEnd) { /* Calculate size of sections. */ const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); const uint64_t CountersSize = CountersEnd - CountersBegin; const uint64_t NamesSize = NamesEnd - NamesBegin; const uint64_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize); /* Enough zeroes for padding. */ const char Zeroes[sizeof(uint64_t)] = {0}; /* Create the header. */ __llvm_profile_header Header; if (!DataSize) return 0; /* Initialize header structure. */ #define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init; #include "InstrProfData.inc" /* Write the data. */ ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1}, {DataBegin, sizeof(__llvm_profile_data), DataSize}, {CountersBegin, sizeof(uint64_t), CountersSize}, {NamesBegin, sizeof(uint8_t), NamesSize}, {Zeroes, sizeof(uint8_t), Padding}}; if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx)) return -1; return writeValueProfData(Writer, WriterCtx, VPDataReader, DataBegin, DataEnd); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfiling.h0000664000175000017500000001552312776214734023347 0ustar kaikai/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_H_ #define PROFILE_INSTRPROFILING_H_ #include "InstrProfilingPort.h" #define INSTR_PROF_VISIBILITY COMPILER_RT_VISIBILITY #include "InstrProfData.inc" enum ValueKind { #define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value, #include "InstrProfData.inc" }; typedef void *IntPtrT; typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT) __llvm_profile_data { #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) Type Name; #include "InstrProfData.inc" } __llvm_profile_data; typedef struct __llvm_profile_header { #define INSTR_PROF_RAW_HEADER(Type, Name, Initializer) Type Name; #include "InstrProfData.inc" } __llvm_profile_header; typedef struct ValueProfNode * PtrToNodeT; typedef struct ValueProfNode { #define INSTR_PROF_VALUE_NODE(Type, LLVMType, Name, Initializer) Type Name; #include "InstrProfData.inc" } ValueProfNode; /*! * \brief Get number of bytes necessary to pad the argument to eight * byte boundary. */ uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes); /*! * \brief Get required size for profile buffer. */ uint64_t __llvm_profile_get_size_for_buffer(void); /*! * \brief Write instrumentation data to the given buffer. * * \pre \c Buffer is the start of a buffer at least as big as \a * __llvm_profile_get_size_for_buffer(). */ int __llvm_profile_write_buffer(char *Buffer); const __llvm_profile_data *__llvm_profile_begin_data(void); const __llvm_profile_data *__llvm_profile_end_data(void); const char *__llvm_profile_begin_names(void); const char *__llvm_profile_end_names(void); uint64_t *__llvm_profile_begin_counters(void); uint64_t *__llvm_profile_end_counters(void); ValueProfNode *__llvm_profile_begin_vnodes(); ValueProfNode *__llvm_profile_end_vnodes(); /*! * \brief Clear profile counters to zero. * */ void __llvm_profile_reset_counters(void); /*! * \brief Merge profile data from buffer. * * Read profile data form buffer \p Profile and merge with * in-process profile counters. The client is expected to * have checked or already knows the profile data in the * buffer matches the in-process counter structure before * calling it. */ void __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size); /*! \brief Check if profile in buffer matches the current binary. * * Returns 0 (success) if the profile data in buffer \p Profile with size * \p Size was generated by the same binary and therefore matches * structurally the in-process counters. If the profile data in buffer is * not compatible, the interface returns 1 (failure). */ int __llvm_profile_check_compatibility(const char *Profile, uint64_t Size); /*! * \brief Counts the number of times a target value is seen. * * Records the target value for the CounterIndex if not seen before. Otherwise, * increments the counter associated w/ the target value. * void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data, * uint32_t CounterIndex); */ void INSTR_PROF_VALUE_PROF_FUNC( #define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType) ArgType ArgName #include "InstrProfData.inc" ); /*! * \brief Write instrumentation data to the current file. * * Writes to the file with the last name given to \a * * __llvm_profile_set_filename(), * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable, * or if that's not set, the last name set to INSTR_PROF_PROFILE_NAME_VAR, * or if that's not set, \c "default.profraw". */ int __llvm_profile_write_file(void); /*! * \brief Set the filename for writing instrumentation data. * * Sets the filename to be used for subsequent calls to * \a __llvm_profile_write_file(). * * \c Name is not copied, so it must remain valid. Passing NULL resets the * filename logic to the default behaviour. */ void __llvm_profile_set_filename(const char *Name); /*! \brief Register to write instrumentation data to file at exit. */ int __llvm_profile_register_write_file_atexit(void); /*! \brief Initialize file handling. */ void __llvm_profile_initialize_file(void); /*! * \brief Return path prefix (excluding the base filename) of the profile data. * This is useful for users using \c -fprofile-generate=./path_prefix who do * not care about the default raw profile name. It is also useful to collect * more than more profile data files dumped in the same directory (Online * merge mode is turned on for instrumented programs with shared libs). * Side-effect: this API call will invoke malloc with dynamic memory allocation. */ const char *__llvm_profile_get_path_prefix(); /*! \brief Get the magic token for the file format. */ uint64_t __llvm_profile_get_magic(void); /*! \brief Get the version of the file format. */ uint64_t __llvm_profile_get_version(void); /*! \brief Get the number of entries in the profile data section. */ uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin, const __llvm_profile_data *End); /*! * This variable is defined in InstrProfilingRuntime.cc as a hidden * symbol. Its main purpose is to enable profile runtime user to * bypass runtime initialization code -- if the client code explicitly * define this variable, then InstProfileRuntime.o won't be linked in. * Note that this variable's visibility needs to be hidden so that the * definition of this variable in an instrumented shared library won't * affect runtime initialization decision of the main program. * __llvm_profile_profile_runtime. */ COMPILER_RT_VISIBILITY extern int INSTR_PROF_PROFILE_RUNTIME_VAR; /*! * This variable is defined in InstrProfiling.c. Its main purpose is to * encode the raw profile version value and other format related information * such as whether the profile is from IR based instrumentation. The variable * is defined as weak so that compiler can emit an overriding definition * depending on user option. Since we don't support mixing FE and IR based * data in the same raw profile data file (in other words, shared libs and * main program are expected to be instrumented in the same way), there is * no need for this variable to be hidden. */ extern uint64_t INSTR_PROF_RAW_VERSION_VAR; /* __llvm_profile_raw_version */ /*! * This variable is a weak symbol defined in InstrProfiling.c. It allows * compiler instrumentation to provide overriding definition with value * from compiler command line. This variable has default visibility. */ extern char INSTR_PROF_PROFILE_NAME_VAR[1]; /* __llvm_profile_filename. */ #endif /* PROFILE_INSTRPROFILING_H_ */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/WindowsMMap.c0000664000175000017500000000604512776214734022575 0ustar kaikai/* * This code is derived from uClibc (original license follows). * https://git.uclibc.org/uClibc/tree/utils/mmap-windows.c */ /* mmap() replacement for Windows * * Author: Mike Frysinger * Placed into the public domain */ /* References: * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx */ #if defined(_WIN32) #include "WindowsMMap.h" #include "InstrProfiling.h" #ifdef __USE_FILE_OFFSET64 # define DWORD_HI(x) (x >> 32) # define DWORD_LO(x) ((x) & 0xffffffff) #else # define DWORD_HI(x) (0) # define DWORD_LO(x) (x) #endif COMPILER_RT_VISIBILITY void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) { if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) return MAP_FAILED; if (fd == -1) { if (!(flags & MAP_ANON) || offset) return MAP_FAILED; } else if (flags & MAP_ANON) return MAP_FAILED; DWORD flProtect; if (prot & PROT_WRITE) { if (prot & PROT_EXEC) flProtect = PAGE_EXECUTE_READWRITE; else flProtect = PAGE_READWRITE; } else if (prot & PROT_EXEC) { if (prot & PROT_READ) flProtect = PAGE_EXECUTE_READ; else if (prot & PROT_EXEC) flProtect = PAGE_EXECUTE; } else flProtect = PAGE_READONLY; off_t end = length + offset; HANDLE mmap_fd, h; if (fd == -1) mmap_fd = INVALID_HANDLE_VALUE; else mmap_fd = (HANDLE)_get_osfhandle(fd); h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL); if (h == NULL) return MAP_FAILED; DWORD dwDesiredAccess; if (prot & PROT_WRITE) dwDesiredAccess = FILE_MAP_WRITE; else dwDesiredAccess = FILE_MAP_READ; if (prot & PROT_EXEC) dwDesiredAccess |= FILE_MAP_EXECUTE; if (flags & MAP_PRIVATE) dwDesiredAccess |= FILE_MAP_COPY; void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); if (ret == NULL) { CloseHandle(h); ret = MAP_FAILED; } return ret; } COMPILER_RT_VISIBILITY void munmap(void *addr, size_t length) { UnmapViewOfFile(addr); /* ruh-ro, we leaked handle from CreateFileMapping() ... */ } COMPILER_RT_VISIBILITY int msync(void *addr, size_t length, int flags) { if (flags & MS_INVALIDATE) return -1; /* Not supported. */ /* Exactly one of MS_ASYNC or MS_SYNC must be specified. */ switch (flags & (MS_ASYNC | MS_SYNC)) { case MS_SYNC: case MS_ASYNC: break; default: return -1; } if (!FlushViewOfFile(addr, length)) return -1; if (flags & MS_SYNC) { /* FIXME: No longer have access to handle from CreateFileMapping(). */ /* * if (!FlushFileBuffers(h)) * return -1; */ } return 0; } COMPILER_RT_VISIBILITY int flock(int fd, int operation) { return -1; /* Not supported. */ } #undef DWORD_HI #undef DWORD_LO #endif /* _WIN32 */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingValue.c0000664000175000017500000002576612776214734024351 0ustar kaikai/*===- InstrProfilingValue.c - Support library for PGO instrumentation ----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include "InstrProfilingUtil.h" /* For PS4 getenv shim. */ #include #include #include #include #define INSTR_PROF_VALUE_PROF_DATA #define INSTR_PROF_COMMON_API_IMPL #include "InstrProfData.inc" static int hasStaticCounters = 1; static int OutOfNodesWarnings = 0; static int hasNonDefaultValsPerSite = 0; #define INSTR_PROF_MAX_VP_WARNS 10 #define INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE 8 #define INSTR_PROF_VNODE_POOL_SIZE 1024 #ifndef _MSC_VER /* A shared static pool in addition to the vnodes statically * allocated by the compiler. */ COMPILER_RT_VISIBILITY ValueProfNode lprofValueProfNodes[INSTR_PROF_VNODE_POOL_SIZE] COMPILER_RT_SECTION( COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME_STR); #endif COMPILER_RT_VISIBILITY uint32_t VPMaxNumValsPerSite = INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE; COMPILER_RT_VISIBILITY void lprofSetupValueProfiler() { const char *Str = 0; Str = getenv("LLVM_VP_MAX_NUM_VALS_PER_SITE"); if (Str && Str[0]) { VPMaxNumValsPerSite = atoi(Str); hasNonDefaultValsPerSite = 1; } if (VPMaxNumValsPerSite > INSTR_PROF_MAX_NUM_VAL_PER_SITE) VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE; } COMPILER_RT_VISIBILITY void lprofSetMaxValsPerSite(uint32_t MaxVals) { VPMaxNumValsPerSite = MaxVals; hasNonDefaultValsPerSite = 1; } /* This method is only used in value profiler mock testing. */ COMPILER_RT_VISIBILITY void __llvm_profile_set_num_value_sites(__llvm_profile_data *Data, uint32_t ValueKind, uint16_t NumValueSites) { *((uint16_t *)&Data->NumValueSites[ValueKind]) = NumValueSites; } /* This method is only used in value profiler mock testing. */ COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_iterate_data(const __llvm_profile_data *Data) { return Data + 1; } /* This method is only used in value profiler mock testing. */ COMPILER_RT_VISIBILITY void * __llvm_get_function_addr(const __llvm_profile_data *Data) { return Data->FunctionPointer; } /* Allocate an array that holds the pointers to the linked lists of * value profile counter nodes. The number of element of the array * is the total number of value profile sites instrumented. Returns * 0 if allocation fails. */ static int allocateValueProfileCounters(__llvm_profile_data *Data) { uint64_t NumVSites = 0; uint32_t VKI; /* This function will never be called when value site array is allocated statically at compile time. */ hasStaticCounters = 0; /* When dynamic allocation is enabled, allow tracking the max number of * values allowd. */ if (!hasNonDefaultValsPerSite) VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE; for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI) NumVSites += Data->NumValueSites[VKI]; ValueProfNode **Mem = (ValueProfNode **)calloc(NumVSites, sizeof(ValueProfNode *)); if (!Mem) return 0; if (!COMPILER_RT_BOOL_CMPXCHG(&Data->Values, 0, Mem)) { free(Mem); return 0; } return 1; } static ValueProfNode *allocateOneNode(__llvm_profile_data *Data, uint32_t Index, uint64_t Value) { ValueProfNode *Node; if (!hasStaticCounters) return (ValueProfNode *)calloc(1, sizeof(ValueProfNode)); /* Early check to avoid value wrapping around. */ if (CurrentVNode + 1 > EndVNode) { if (OutOfNodesWarnings++ < INSTR_PROF_MAX_VP_WARNS) { PROF_WARN("Unable to track new values: %s. " " Consider using option -mllvm -vp-counters-per-site= to " "allocate more" " value profile counters at compile time. \n", "Running out of static counters"); } return 0; } Node = COMPILER_RT_PTR_FETCH_ADD(ValueProfNode, CurrentVNode, 1); /* Due to section padding, EndVNode point to a byte which is one pass * an incomplete VNode, so we need to skip the last incomplete node. */ if (Node + 1 > EndVNode) return 0; return Node; } COMPILER_RT_VISIBILITY void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data, uint32_t CounterIndex) { __llvm_profile_data *PData = (__llvm_profile_data *)Data; if (!PData) return; if (!PData->Values) { if (!allocateValueProfileCounters(PData)) return; } ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values; ValueProfNode *PrevVNode = NULL; ValueProfNode *MinCountVNode = NULL; ValueProfNode *CurVNode = ValueCounters[CounterIndex]; uint64_t MinCount = UINT64_MAX; uint8_t VDataCount = 0; while (CurVNode) { if (TargetValue == CurVNode->Value) { CurVNode->Count++; return; } if (CurVNode->Count < MinCount) { MinCount = CurVNode->Count; MinCountVNode = CurVNode; } PrevVNode = CurVNode; CurVNode = CurVNode->Next; ++VDataCount; } if (VDataCount >= VPMaxNumValsPerSite) { /* Bump down the min count node's count. If it reaches 0, * evict it. This eviction/replacement policy makes hot * targets more sticky while cold targets less so. In other * words, it makes it less likely for the hot targets to be * prematurally evicted during warmup/establishment period, * when their counts are still low. In a special case when * the number of values tracked is reduced to only one, this * policy will guarantee that the dominating target with >50% * total count will survive in the end. Note that this scheme * allows the runtime to track the min count node in an adaptive * manner. It can correct previous mistakes and eventually * lock on a cold target that is alread in stable state. * * In very rare cases, this replacement scheme may still lead * to target loss. For instance, out of \c N value slots, \c N-1 * slots are occupied by luke warm targets during the warmup * period and the remaining one slot is competed by two or more * very hot targets. If those hot targets occur in an interleaved * way, none of them will survive (gain enough weight to throw out * other established entries) due to the ping-pong effect. * To handle this situation, user can choose to increase the max * number of tracked values per value site. Alternatively, a more * expensive eviction mechanism can be implemented. It requires * the runtime to track the total number of evictions per-site. * When the total number of evictions reaches certain threshold, * the runtime can wipe out more than one lowest count entries * to give space for hot targets. */ if (!(--MinCountVNode->Count)) { CurVNode = MinCountVNode; CurVNode->Value = TargetValue; CurVNode->Count++; } return; } CurVNode = allocateOneNode(PData, CounterIndex, TargetValue); if (!CurVNode) return; CurVNode->Value = TargetValue; CurVNode->Count++; uint32_t Success = 0; if (!ValueCounters[CounterIndex]) Success = COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurVNode); else if (PrevVNode && !PrevVNode->Next) Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurVNode); if (!Success && !hasStaticCounters) { free(CurVNode); return; } } /* * A wrapper struct that represents value profile runtime data. * Like InstrProfRecord class which is used by profiling host tools, * ValueProfRuntimeRecord also implements the abstract intefaces defined in * ValueProfRecordClosure so that the runtime data can be serialized using * shared C implementation. */ typedef struct ValueProfRuntimeRecord { const __llvm_profile_data *Data; ValueProfNode **NodesKind[IPVK_Last + 1]; uint8_t **SiteCountArray; } ValueProfRuntimeRecord; /* ValueProfRecordClosure Interface implementation. */ static uint32_t getNumValueSitesRT(const void *R, uint32_t VK) { return ((const ValueProfRuntimeRecord *)R)->Data->NumValueSites[VK]; } static uint32_t getNumValueDataRT(const void *R, uint32_t VK) { uint32_t S = 0, I; const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; if (Record->SiteCountArray[VK] == INSTR_PROF_NULLPTR) return 0; for (I = 0; I < Record->Data->NumValueSites[VK]; I++) S += Record->SiteCountArray[VK][I]; return S; } static uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK, uint32_t S) { const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; return Record->SiteCountArray[VK][S]; } static ValueProfRuntimeRecord RTRecord; static ValueProfRecordClosure RTRecordClosure = { &RTRecord, INSTR_PROF_NULLPTR, /* GetNumValueKinds */ getNumValueSitesRT, getNumValueDataRT, getNumValueDataForSiteRT, INSTR_PROF_NULLPTR, /* RemapValueData */ INSTR_PROF_NULLPTR, /* GetValueForSite, */ INSTR_PROF_NULLPTR /* AllocValueProfData */ }; static uint32_t initializeValueProfRuntimeRecord(const __llvm_profile_data *Data, uint8_t *SiteCountArray[]) { unsigned I, J, S = 0, NumValueKinds = 0; ValueProfNode **Nodes = (ValueProfNode **)Data->Values; RTRecord.Data = Data; RTRecord.SiteCountArray = SiteCountArray; for (I = 0; I <= IPVK_Last; I++) { uint16_t N = Data->NumValueSites[I]; if (!N) continue; NumValueKinds++; RTRecord.NodesKind[I] = Nodes ? &Nodes[S] : INSTR_PROF_NULLPTR; for (J = 0; J < N; J++) { /* Compute value count for each site. */ uint32_t C = 0; ValueProfNode *Site = Nodes ? RTRecord.NodesKind[I][J] : INSTR_PROF_NULLPTR; while (Site) { C++; Site = Site->Next; } if (C > UCHAR_MAX) C = UCHAR_MAX; RTRecord.SiteCountArray[I][J] = C; } S += N; } return NumValueKinds; } static ValueProfNode *getNextNValueData(uint32_t VK, uint32_t Site, InstrProfValueData *Dst, ValueProfNode *StartNode, uint32_t N) { unsigned I; ValueProfNode *VNode = StartNode ? StartNode : RTRecord.NodesKind[VK][Site]; for (I = 0; I < N; I++) { Dst[I].Value = VNode->Value; Dst[I].Count = VNode->Count; VNode = VNode->Next; } return VNode; } static uint32_t getValueProfDataSizeWrapper(void) { return getValueProfDataSize(&RTRecordClosure); } static uint32_t getNumValueDataForSiteWrapper(uint32_t VK, uint32_t S) { return getNumValueDataForSiteRT(&RTRecord, VK, S); } static VPDataReaderType TheVPDataReader = { initializeValueProfRuntimeRecord, getValueProfRecordHeaderSize, getFirstValueProfRecord, getNumValueDataForSiteWrapper, getValueProfDataSizeWrapper, getNextNValueData}; COMPILER_RT_VISIBILITY VPDataReaderType *lprofGetVPDataReader() { return &TheVPDataReader; } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingPlatformOther.c0000664000175000017500000000623312776214734026047 0ustar kaikai/*===- InstrProfilingPlatformOther.c - Profile data default platform ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) #include static const __llvm_profile_data *DataFirst = NULL; static const __llvm_profile_data *DataLast = NULL; static const char *NamesFirst = NULL; static const char *NamesLast = NULL; static uint64_t *CountersFirst = NULL; static uint64_t *CountersLast = NULL; static const void *getMinAddr(const void *A1, const void *A2) { return A1 < A2 ? A1 : A2; } static const void *getMaxAddr(const void *A1, const void *A2) { return A1 > A2 ? A1 : A2; } /*! * \brief Register an instrumented function. * * Calls to this are emitted by clang with -fprofile-instr-generate. Such * calls are only required (and only emitted) on targets where we haven't * implemented linker magic to find the bounds of the sections. */ COMPILER_RT_VISIBILITY void __llvm_profile_register_function(void *Data_) { /* TODO: Only emit this function if we can't use linker magic. */ const __llvm_profile_data *Data = (__llvm_profile_data *)Data_; if (!DataFirst) { DataFirst = Data; DataLast = Data + 1; CountersFirst = Data->CounterPtr; CountersLast = (uint64_t *)Data->CounterPtr + Data->NumCounters; return; } DataFirst = (const __llvm_profile_data *)getMinAddr(DataFirst, Data); CountersFirst = (uint64_t *)getMinAddr(CountersFirst, Data->CounterPtr); DataLast = (const __llvm_profile_data *)getMaxAddr(DataLast, Data + 1); CountersLast = (uint64_t *)getMaxAddr( CountersLast, (uint64_t *)Data->CounterPtr + Data->NumCounters); } COMPILER_RT_VISIBILITY void __llvm_profile_register_names_function(void *NamesStart, uint64_t NamesSize) { if (!NamesFirst) { NamesFirst = (const char *)NamesStart; NamesLast = (const char *)NamesStart + NamesSize; return; } NamesFirst = (const char *)getMinAddr(NamesFirst, NamesStart); NamesLast = (const char *)getMaxAddr(NamesLast, (const char *)NamesStart + NamesSize); } COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_begin_data(void) { return DataFirst; } COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_end_data(void) { return DataLast; } COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) { return NamesFirst; } COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) { return NamesLast; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return CountersLast; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_begin_vnodes(void) { return 0; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) { return 0; } COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = 0; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = 0; #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingBuffer.c0000664000175000017500000000506012776214734024467 0ustar kaikai/*===- InstrProfilingBuffer.c - Write instrumentation to a memory buffer --===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_size_for_buffer(void) { const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); return __llvm_profile_get_size_for_buffer_internal( DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd); } COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin, const __llvm_profile_data *End) { intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End; return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) / sizeof(__llvm_profile_data); } COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { /* Match logic in __llvm_profile_write_buffer(). */ const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char); const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize); return sizeof(__llvm_profile_header) + (__llvm_profile_get_data_size(DataBegin, DataEnd) * sizeof(__llvm_profile_data)) + (CountersEnd - CountersBegin) * sizeof(uint64_t) + NamesSize + Padding; } COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) { return lprofWriteData(lprofBufferWriter, Buffer, 0); } COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { return lprofWriteDataImpl(lprofBufferWriter, Buffer, DataBegin, DataEnd, CountersBegin, CountersEnd, 0, NamesBegin, NamesEnd); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfiling.c0000664000175000017500000000432012776214734023333 0ustar kaikai/*===- InstrProfiling.c - Support library for PGO instrumentation ---------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include #include #include #include #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" COMPILER_RT_VISIBILITY char *(*GetEnvHook)(const char *) = 0; COMPILER_RT_WEAK uint64_t INSTR_PROF_RAW_VERSION_VAR = INSTR_PROF_RAW_VERSION; COMPILER_RT_WEAK char INSTR_PROF_PROFILE_NAME_VAR[1] = {0}; COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) { return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64) : (INSTR_PROF_RAW_MAGIC_32); } /* Return the number of bytes needed to add to SizeInBytes to make it * the result a multiple of 8. */ COMPILER_RT_VISIBILITY uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes) { return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t)); } COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_version(void) { return __llvm_profile_raw_version; } COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) { uint64_t *I = __llvm_profile_begin_counters(); uint64_t *E = __llvm_profile_end_counters(); memset(I, 0, sizeof(uint64_t) * (E - I)); const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const __llvm_profile_data *DI; for (DI = DataBegin; DI < DataEnd; ++DI) { uint64_t CurrentVSiteCount = 0; uint32_t VKI, i; if (!DI->Values) continue; ValueProfNode **ValueCounters = (ValueProfNode **)DI->Values; for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI) CurrentVSiteCount += DI->NumValueSites[VKI]; for (i = 0; i < CurrentVSiteCount; ++i) { ValueProfNode *CurrentVNode = ValueCounters[i]; while (CurrentVNode) { CurrentVNode->Count = 0; CurrentVNode = CurrentVNode->Next; } } } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingUtil.h0000664000175000017500000000434712776214734024207 0ustar kaikai/*===- InstrProfilingUtil.h - Support library for PGO instrumentation -----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILINGUTIL_H #define PROFILE_INSTRPROFILINGUTIL_H #include #include /*! \brief Create a directory tree. */ void __llvm_profile_recursive_mkdir(char *Pathname); /*! Open file \c Filename for read+write with write * lock for exclusive access. The caller will block * if the lock is already held by another process. */ FILE *lprofOpenFileEx(const char *Filename); /* PS4 doesn't have getenv. Define a shim. */ #if __ORBIS__ static inline char *getenv(const char *name) { return NULL; } #endif /* #if __ORBIS__ */ /* GCOV_PREFIX and GCOV_PREFIX_STRIP support */ /* Return the path prefix specified by GCOV_PREFIX environment variable. * If GCOV_PREFIX_STRIP is also specified, the strip level (integer value) * is returned via \c *PrefixStrip. The prefix length is stored in *PrefixLen. */ const char *lprofGetPathPrefix(int *PrefixStrip, size_t *PrefixLen); /* Apply the path prefix specified in \c Prefix to path string in \c PathStr, * and store the result to buffer pointed to by \c Buffer. If \c PrefixStrip * is not zero, path prefixes are stripped from \c PathStr (the level of * stripping is specified by \c PrefixStrip) before \c Prefix is added. */ void lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix, size_t PrefixLen, int PrefixStrip); /* Returns a pointer to the first occurrence of \c DIR_SEPARATOR char in * the string \c Path, or NULL if the char is not found. */ const char *lprofFindFirstDirSeparator(const char *Path); /* Returns a pointer to the last occurrence of \c DIR_SEPARATOR char in * the string \c Path, or NULL if the char is not found. */ const char *lprofFindLastDirSeparator(const char *Path); int lprofGetHostName(char *Name, int Len); unsigned lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV); void *lprofPtrFetchAdd(void **Mem, long ByteIncr); #endif /* PROFILE_INSTRPROFILINGUTIL_H */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingFile.c0000664000175000017500000004144312776214734024142 0ustar kaikai/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include "InstrProfilingUtil.h" #include #include #include #include #ifdef _MSC_VER /* For _alloca. */ #include #endif #if defined(_WIN32) #include "WindowsMMap.h" /* For _chsize_s */ #include #else #include #include #include #if defined(__linux__) #include #endif #endif /* From where is profile name specified. * The order the enumerators define their * precedence. Re-order them may lead to * runtime behavior change. */ typedef enum ProfileNameSpecifier { PNS_unknown = 0, PNS_default, PNS_command_line, PNS_environment, PNS_runtime_api } ProfileNameSpecifier; static const char *getPNSStr(ProfileNameSpecifier PNS) { switch (PNS) { case PNS_default: return "default setting"; case PNS_command_line: return "command line"; case PNS_environment: return "environment variable"; case PNS_runtime_api: return "runtime API"; default: return "Unknown"; } } #define MAX_PID_SIZE 16 /* Data structure holding the result of parsed filename pattern. */ typedef struct lprofFilename { /* File name string possibly with %p or %h specifiers. */ const char *FilenamePat; const char *ProfilePathPrefix; char PidChars[MAX_PID_SIZE]; char Hostname[COMPILER_RT_MAX_HOSTLEN]; unsigned NumPids; unsigned NumHosts; /* When in-process merging is enabled, this parameter specifies * the total number of profile data files shared by all the processes * spawned from the same binary. By default the value is 1. If merging * is not enabled, its value should be 0. This parameter is specified * by the %[0-9]m specifier. For instance %2m enables merging using * 2 profile data files. %1m is equivalent to %m. Also %m specifier * can only appear once at the end of the name pattern. */ unsigned MergePoolSize; ProfileNameSpecifier PNS; } lprofFilename; lprofFilename lprofCurFilename = {0, 0, {0}, {0}, 0, 0, 0, PNS_unknown}; int getpid(void); static int getCurFilenameLength(); static const char *getCurFilename(char *FilenameBuf); static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } /* Return 1 if there is an error, otherwise return 0. */ static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx) { uint32_t I; FILE *File = (FILE *)*WriterCtx; for (I = 0; I < NumIOVecs; I++) { if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != IOVecs[I].NumElm) return 1; } return 0; } COMPILER_RT_VISIBILITY ProfBufferIO * lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { FreeHook = &free; DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); VPBufferSize = BufferSz; return lprofCreateBufferIO(fileWriter, File); } static void setupIOBuffer() { const char *BufferSzStr = 0; BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); if (BufferSzStr && BufferSzStr[0]) { VPBufferSize = atoi(BufferSzStr); DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); } } /* Read profile data in \c ProfileFile and merge with in-memory profile counters. Returns -1 if there is fatal error, otheriwse 0 is returned. */ static int doProfileMerging(FILE *ProfileFile) { uint64_t ProfileFileSize; char *ProfileBuffer; if (fseek(ProfileFile, 0L, SEEK_END) == -1) { PROF_ERR("Unable to merge profile data, unable to get size: %s\n", strerror(errno)); return -1; } ProfileFileSize = ftell(ProfileFile); /* Restore file offset. */ if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", strerror(errno)); return -1; } /* Nothing to merge. */ if (ProfileFileSize < sizeof(__llvm_profile_header)) { if (ProfileFileSize) PROF_WARN("Unable to merge profile data: %s\n", "source profile file is too small."); return 0; } ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, fileno(ProfileFile), 0); if (ProfileBuffer == MAP_FAILED) { PROF_ERR("Unable to merge profile data, mmap failed: %s\n", strerror(errno)); return -1; } if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) { (void)munmap(ProfileBuffer, ProfileFileSize); PROF_WARN("Unable to merge profile data: %s\n", "source profile file is not compatible."); return 0; } /* Now start merging */ __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); (void)munmap(ProfileBuffer, ProfileFileSize); return 0; } /* Open the profile data for merging. It opens the file in r+b mode with * file locking. If the file has content which is compatible with the * current process, it also reads in the profile data in the file and merge * it with in-memory counters. After the profile data is merged in memory, * the original profile data is truncated and gets ready for the profile * dumper. With profile merging enabled, each executable as well as any of * its instrumented shared libraries dump profile data into their own data file. */ static FILE *openFileForMerging(const char *ProfileFileName) { FILE *ProfileFile; int rc; ProfileFile = lprofOpenFileEx(ProfileFileName); if (!ProfileFile) return NULL; rc = doProfileMerging(ProfileFile); if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) || fseek(ProfileFile, 0L, SEEK_SET) == -1) { PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, strerror(errno)); fclose(ProfileFile); return NULL; } fseek(ProfileFile, 0L, SEEK_SET); return ProfileFile; } /* Write profile data to file \c OutputName. */ static int writeFile(const char *OutputName) { int RetVal; FILE *OutputFile; if (!doMerging()) OutputFile = fopen(OutputName, "ab"); else OutputFile = openFileForMerging(OutputName); if (!OutputFile) return -1; FreeHook = &free; setupIOBuffer(); RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader()); fclose(OutputFile); return RetVal; } static void truncateCurrentFile(void) { const char *Filename; char *FilenameBuf; FILE *File; int Length; Length = getCurFilenameLength(); FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); Filename = getCurFilename(FilenameBuf); if (!Filename) return; /* Create the directory holding the file, if needed. */ if (lprofFindFirstDirSeparator(Filename)) { char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); strncpy(Copy, Filename, Length + 1); __llvm_profile_recursive_mkdir(Copy); } /* By pass file truncation to allow online raw profile * merging. */ if (lprofCurFilename.MergePoolSize) return; /* Truncate the file. Later we'll reopen and append. */ File = fopen(Filename, "w"); if (!File) return; fclose(File); } static const char *DefaultProfileName = "default.profraw"; static void resetFilenameToDefault(void) { memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); lprofCurFilename.FilenamePat = DefaultProfileName; lprofCurFilename.PNS = PNS_default; } static int containsMergeSpecifier(const char *FilenamePat, int I) { return (FilenamePat[I] == 'm' || (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' && /* If FilenamePat[I] is not '\0', the next byte is guaranteed * to be in-bound as the string is null terminated. */ FilenamePat[I + 1] == 'm')); } /* Parses the pattern string \p FilenamePat and stores the result to * lprofcurFilename structure. */ static int parseFilenamePattern(const char *FilenamePat) { int NumPids = 0, NumHosts = 0, I; char *PidChars = &lprofCurFilename.PidChars[0]; char *Hostname = &lprofCurFilename.Hostname[0]; int MergingEnabled = 0; /* Clean up cached prefix. */ if (lprofCurFilename.ProfilePathPrefix) free((void *)lprofCurFilename.ProfilePathPrefix); memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); lprofCurFilename.FilenamePat = FilenamePat; /* Check the filename for "%p", which indicates a pid-substitution. */ for (I = 0; FilenamePat[I]; ++I) if (FilenamePat[I] == '%') { if (FilenamePat[++I] == 'p') { if (!NumPids++) { if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) { PROF_WARN( "Unable to parse filename pattern %s. Using the default name.", FilenamePat); return -1; } } } else if (FilenamePat[I] == 'h') { if (!NumHosts++) if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { PROF_WARN( "Unable to parse filename pattern %s. Using the default name.", FilenamePat); return -1; } } else if (containsMergeSpecifier(FilenamePat, I)) { if (MergingEnabled) { PROF_WARN("%%m specifier can only be specified once in %s.\n", FilenamePat); return -1; } MergingEnabled = 1; if (FilenamePat[I] == 'm') lprofCurFilename.MergePoolSize = 1; else { lprofCurFilename.MergePoolSize = FilenamePat[I] - '0'; I++; /* advance to 'm' */ } } } lprofCurFilename.NumPids = NumPids; lprofCurFilename.NumHosts = NumHosts; return 0; } static void parseAndSetFilename(const char *FilenamePat, ProfileNameSpecifier PNS) { const char *OldFilenamePat = lprofCurFilename.FilenamePat; ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; if (PNS < OldPNS) return; if (!FilenamePat) FilenamePat = DefaultProfileName; if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { lprofCurFilename.PNS = PNS; return; } /* When PNS >= OldPNS, the last one wins. */ if (!FilenamePat || parseFilenamePattern(FilenamePat)) resetFilenameToDefault(); lprofCurFilename.PNS = PNS; if (!OldFilenamePat) { PROF_NOTE("Set profile file path to \"%s\" via %s.\n", lprofCurFilename.FilenamePat, getPNSStr(PNS)); } else { PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, getPNSStr(PNS)); } truncateCurrentFile(); } /* Return buffer length that is required to store the current profile * filename with PID and hostname substitutions. */ /* The length to hold uint64_t followed by 2 digit pool id including '_' */ #define SIGLEN 24 static int getCurFilenameLength() { int Len; if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) return 0; if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || lprofCurFilename.MergePoolSize)) return strlen(lprofCurFilename.FilenamePat); Len = strlen(lprofCurFilename.FilenamePat) + lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); if (lprofCurFilename.MergePoolSize) Len += SIGLEN; return Len; } /* Return the pointer to the current profile file name (after substituting * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer * to store the resulting filename. If no substitution is needed, the * current filename pattern string is directly returned. */ static const char *getCurFilename(char *FilenameBuf) { int I, J, PidLength, HostNameLength; const char *FilenamePat = lprofCurFilename.FilenamePat; if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) return 0; if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || lprofCurFilename.MergePoolSize)) return lprofCurFilename.FilenamePat; PidLength = strlen(lprofCurFilename.PidChars); HostNameLength = strlen(lprofCurFilename.Hostname); /* Construct the new filename. */ for (I = 0, J = 0; FilenamePat[I]; ++I) if (FilenamePat[I] == '%') { if (FilenamePat[++I] == 'p') { memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); J += PidLength; } else if (FilenamePat[I] == 'h') { memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); J += HostNameLength; } else if (containsMergeSpecifier(FilenamePat, I)) { char LoadModuleSignature[SIGLEN]; int S; int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d", lprofGetLoadModuleSignature(), ProfilePoolId); if (S == -1 || S > SIGLEN) S = SIGLEN; memcpy(FilenameBuf + J, LoadModuleSignature, S); J += S; if (FilenamePat[I] != 'm') I++; } /* Drop any unknown substitutions. */ } else FilenameBuf[J++] = FilenamePat[I]; FilenameBuf[J] = 0; return FilenameBuf; } /* Returns the pointer to the environment variable * string. Returns null if the env var is not set. */ static const char *getFilenamePatFromEnv(void) { const char *Filename = getenv("LLVM_PROFILE_FILE"); if (!Filename || !Filename[0]) return 0; return Filename; } COMPILER_RT_VISIBILITY const char *__llvm_profile_get_path_prefix(void) { int Length; char *FilenameBuf, *Prefix; const char *Filename, *PrefixEnd; if (lprofCurFilename.ProfilePathPrefix) return lprofCurFilename.ProfilePathPrefix; Length = getCurFilenameLength(); FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); Filename = getCurFilename(FilenameBuf); if (!Filename) return "\0"; PrefixEnd = lprofFindLastDirSeparator(Filename); if (!PrefixEnd) return "\0"; Length = PrefixEnd - Filename + 1; Prefix = (char *)malloc(Length + 1); if (!Prefix) { PROF_ERR("Failed to %s\n", "allocate memory."); return "\0"; } memcpy(Prefix, Filename, Length); Prefix[Length] = '\0'; lprofCurFilename.ProfilePathPrefix = Prefix; return Prefix; } /* This method is invoked by the runtime initialization hook * InstrProfilingRuntime.o if it is linked in. Both user specified * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE * environment variable can override this default value. */ COMPILER_RT_VISIBILITY void __llvm_profile_initialize_file(void) { const char *EnvFilenamePat; const char *SelectedPat = NULL; ProfileNameSpecifier PNS = PNS_unknown; int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); EnvFilenamePat = getFilenamePatFromEnv(); if (EnvFilenamePat) { SelectedPat = EnvFilenamePat; PNS = PNS_environment; } else if (hasCommandLineOverrider) { SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; PNS = PNS_command_line; } else { SelectedPat = NULL; PNS = PNS_default; } parseAndSetFilename(SelectedPat, PNS); } /* This API is directly called by the user application code. It has the * highest precedence compared with LLVM_PROFILE_FILE environment variable * and command line option -fprofile-instr-generate=. */ COMPILER_RT_VISIBILITY void __llvm_profile_set_filename(const char *FilenamePat) { parseAndSetFilename(FilenamePat, PNS_runtime_api); } /* The public API for writing profile data into the file with name * set by previous calls to __llvm_profile_set_filename or * __llvm_profile_override_default_filename or * __llvm_profile_initialize_file. */ COMPILER_RT_VISIBILITY int __llvm_profile_write_file(void) { int rc, Length; const char *Filename; char *FilenameBuf; Length = getCurFilenameLength(); FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); Filename = getCurFilename(FilenameBuf); /* Check the filename. */ if (!Filename) { PROF_ERR("Failed to write file : %s\n", "Filename not set"); return -1; } /* Check if there is llvm/runtime version mismatch. */ if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { PROF_ERR("Runtime and instrumentation version mismatch : " "expected %d, but get %d\n", INSTR_PROF_RAW_VERSION, (int)GET_VERSION(__llvm_profile_get_version())); return -1; } /* Write profile data to the file. */ rc = writeFile(Filename); if (rc) PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); return rc; } static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } COMPILER_RT_VISIBILITY int __llvm_profile_register_write_file_atexit(void) { static int HasBeenRegistered = 0; if (HasBeenRegistered) return 0; lprofSetupValueProfiler(); HasBeenRegistered = 1; return atexit(writeFileWithoutReturn); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingRuntime.cc0000664000175000017500000000124412776214734025044 0ustar kaikai//===- InstrProfilingRuntime.cpp - PGO runtime initialization -------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// extern "C" { #include "InstrProfiling.h" /* int __llvm_profile_runtime */ COMPILER_RT_VISIBILITY int INSTR_PROF_PROFILE_RUNTIME_VAR; } namespace { class RegisterRuntime { public: RegisterRuntime() { __llvm_profile_register_write_file_atexit(); __llvm_profile_initialize_file(); } }; RegisterRuntime Registration; } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingMerge.c0000664000175000017500000001223012776214734024312 0ustar kaikai/*===- InstrProfilingMerge.c - Profile in-process Merging ---------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* |*===----------------------------------------------------------------------===* |* This file defines the API needed for in-process merging of profile data |* stored in memory buffer. \*===---------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include "InstrProfilingUtil.h" #define INSTR_PROF_VALUE_PROF_DATA #include "InstrProfData.inc" COMPILER_RT_WEAK void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *) = NULL; COMPILER_RT_VISIBILITY uint64_t lprofGetLoadModuleSignature() { /* A very fast way to compute a module signature. */ uint64_t CounterSize = (uint64_t)(__llvm_profile_end_counters() - __llvm_profile_begin_counters()); uint64_t DataSize = __llvm_profile_get_data_size(__llvm_profile_begin_data(), __llvm_profile_end_data()); uint64_t NamesSize = (uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names()); uint64_t NumVnodes = (uint64_t)(__llvm_profile_end_vnodes() - __llvm_profile_begin_vnodes()); const __llvm_profile_data *FirstD = __llvm_profile_begin_data(); return (NamesSize << 40) + (CounterSize << 30) + (DataSize << 20) + (NumVnodes << 10) + (DataSize > 0 ? FirstD->NameRef : 0); } /* Returns 1 if profile is not structurally compatible. */ COMPILER_RT_VISIBILITY int __llvm_profile_check_compatibility(const char *ProfileData, uint64_t ProfileSize) { /* Check profile header only for now */ __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData; __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData; SrcDataStart = (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header)); SrcDataEnd = SrcDataStart + Header->DataSize; if (ProfileSize < sizeof(__llvm_profile_header)) return 1; /* Check the header first. */ if (Header->Magic != __llvm_profile_get_magic() || Header->Version != __llvm_profile_get_version() || Header->DataSize != __llvm_profile_get_data_size(__llvm_profile_begin_data(), __llvm_profile_end_data()) || Header->CountersSize != (uint64_t)(__llvm_profile_end_counters() - __llvm_profile_begin_counters()) || Header->NamesSize != (uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names()) || Header->ValueKindLast != IPVK_Last) return 1; if (ProfileSize < sizeof(__llvm_profile_header) + Header->DataSize * sizeof(__llvm_profile_data) + Header->NamesSize + Header->CountersSize) return 1; for (SrcData = SrcDataStart, DstData = (__llvm_profile_data *)__llvm_profile_begin_data(); SrcData < SrcDataEnd; ++SrcData, ++DstData) { if (SrcData->NameRef != DstData->NameRef || SrcData->FuncHash != DstData->FuncHash || SrcData->NumCounters != DstData->NumCounters) return 1; } /* Matched! */ return 0; } COMPILER_RT_VISIBILITY void __llvm_profile_merge_from_buffer(const char *ProfileData, uint64_t ProfileSize) { __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData; __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData; uint64_t *SrcCountersStart; const char *SrcNameStart; ValueProfData *SrcValueProfDataStart, *SrcValueProfData; SrcDataStart = (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header)); SrcDataEnd = SrcDataStart + Header->DataSize; SrcCountersStart = (uint64_t *)SrcDataEnd; SrcNameStart = (const char *)(SrcCountersStart + Header->CountersSize); SrcValueProfDataStart = (ValueProfData *)(SrcNameStart + Header->NamesSize + __llvm_profile_get_num_padding_bytes( Header->NamesSize)); for (SrcData = SrcDataStart, DstData = (__llvm_profile_data *)__llvm_profile_begin_data(), SrcValueProfData = SrcValueProfDataStart; SrcData < SrcDataEnd; ++SrcData, ++DstData) { uint64_t *SrcCounters; uint64_t *DstCounters = (uint64_t *)DstData->CounterPtr; unsigned I, NC, NVK = 0; NC = SrcData->NumCounters; SrcCounters = SrcCountersStart + ((size_t)SrcData->CounterPtr - Header->CountersDelta) / sizeof(uint64_t); for (I = 0; I < NC; I++) DstCounters[I] += SrcCounters[I]; /* Now merge value profile data. */ if (!VPMergeHook) continue; for (I = 0; I <= IPVK_Last; I++) NVK += (SrcData->NumValueSites[I] != 0); if (!NVK) continue; VPMergeHook(SrcValueProfData, DstData); SrcValueProfData = (ValueProfData *)((char *)SrcValueProfData + SrcValueProfData->TotalSize); } } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingInternal.h0000664000175000017500000001555212776214734025046 0ustar kaikai/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_INTERNALH_ #define PROFILE_INSTRPROFILING_INTERNALH_ #include "InstrProfiling.h" #include "stddef.h" /*! * \brief Write instrumentation data to the given buffer, given explicit * pointers to the live data in memory. This function is probably not what you * want. Use __llvm_profile_get_size_for_buffer instead. Use this function if * your program has a custom memory layout. */ uint64_t __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); /*! * \brief Write instrumentation data to the given buffer, given explicit * pointers to the live data in memory. This function is probably not what you * want. Use __llvm_profile_write_buffer instead. Use this function if your * program has a custom memory layout. * * \pre \c Buffer is the start of a buffer at least as big as \a * __llvm_profile_get_size_for_buffer_internal(). */ int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); /*! * The data structure describing the data to be written by the * low level writer callback function. */ typedef struct ProfDataIOVec { const void *Data; size_t ElmSize; size_t NumElm; } ProfDataIOVec; typedef uint32_t (*WriterCallback)(ProfDataIOVec *, uint32_t NumIOVecs, void **WriterCtx); /*! * The data structure for buffered IO of profile data. */ typedef struct ProfBufferIO { /* File handle. */ void *File; /* Low level IO callback. */ WriterCallback FileWriter; /* The start of the buffer. */ uint8_t *BufferStart; /* Total size of the buffer. */ uint32_t BufferSz; /* Current byte offset from the start of the buffer. */ uint32_t CurOffset; } ProfBufferIO; /* The creator interface used by testing. */ ProfBufferIO *lprofCreateBufferIOInternal(void *File, uint32_t BufferSz); /*! * This is the interface to create a handle for buffered IO. */ ProfBufferIO *lprofCreateBufferIO(WriterCallback FileWriter, void *File); /*! * The interface to destroy the bufferIO handle and reclaim * the memory. */ void lprofDeleteBufferIO(ProfBufferIO *BufferIO); /*! * This is the interface to write \c Data of \c Size bytes through * \c BufferIO. Returns 0 if successful, otherwise return -1. */ int lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size); /*! * The interface to flush the remaining data in the buffer. * through the low level writer callback. */ int lprofBufferIOFlush(ProfBufferIO *BufferIO); /* The low level interface to write data into a buffer. It is used as the * callback by other high level writer methods such as buffered IO writer * and profile data writer. */ uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx); struct ValueProfData; struct ValueProfRecord; struct InstrProfValueData; struct ValueProfNode; /*! * The class that defines a set of methods to read value profile * data for streaming/serialization from the instrumentation runtime. */ typedef struct VPDataReaderType { uint32_t (*InitRTRecord)(const __llvm_profile_data *Data, uint8_t *SiteCountArray[]); /* Function pointer to getValueProfRecordHeader method. */ uint32_t (*GetValueProfRecordHeaderSize)(uint32_t NumSites); /* Function pointer to getFristValueProfRecord method. */ struct ValueProfRecord *(*GetFirstValueProfRecord)(struct ValueProfData *); /* Return the number of value data for site \p Site. */ uint32_t (*GetNumValueDataForSite)(uint32_t VK, uint32_t Site); /* Return the total size of the value profile data of the * current function. */ uint32_t (*GetValueProfDataSize)(void); /*! * Read the next \p N value data for site \p Site and store the data * in \p Dst. \p StartNode is the first value node to start with if * it is not null. The function returns the pointer to the value * node pointer to be used as the \p StartNode of the next batch reading. * If there is nothing left, it returns NULL. */ struct ValueProfNode *(*GetValueData)(uint32_t ValueKind, uint32_t Site, struct InstrProfValueData *Dst, struct ValueProfNode *StartNode, uint32_t N); } VPDataReaderType; int lprofWriteData(WriterCallback Writer, void *WriterCtx, VPDataReaderType *VPDataReader); int lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, VPDataReaderType *VPDataReader, const char *NamesBegin, const char *NamesEnd); /* Merge value profile data pointed to by SrcValueProfData into * in-memory profile counters pointed by to DstData. */ void lprofMergeValueProfData(struct ValueProfData *SrcValueProfData, __llvm_profile_data *DstData); VPDataReaderType *lprofGetVPDataReader(); /* Internal interface used by test to reset the max number of * tracked values per value site to be \p MaxVals. */ void lprofSetMaxValsPerSite(uint32_t MaxVals); void lprofSetupValueProfiler(); /* Return the profile header 'signature' value associated with the current * executable or shared library. The signature value can be used to for * a profile name that is unique to this load module so that it does not * collide with profiles from other binaries. It also allows shared libraries * to dump merged profile data into its own profile file. */ uint64_t lprofGetLoadModuleSignature(); COMPILER_RT_VISIBILITY extern char *(*GetEnvHook)(const char *); COMPILER_RT_VISIBILITY extern void (*FreeHook)(void *); COMPILER_RT_VISIBILITY extern uint8_t *DynamicBufferIOBuffer; COMPILER_RT_VISIBILITY extern uint32_t VPBufferSize; COMPILER_RT_VISIBILITY extern uint32_t VPMaxNumValsPerSite; /* Pointer to the start of static value counters to be allocted. */ COMPILER_RT_VISIBILITY extern ValueProfNode *CurrentVNode; COMPILER_RT_VISIBILITY extern ValueProfNode *EndVNode; extern void (*VPMergeHook)(struct ValueProfData *, __llvm_profile_data *); #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingPort.h0000664000175000017500000001063412776214734024212 0ustar kaikai/*===- InstrProfilingPort.h- Support library for PGO instrumentation ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_PORT_H_ #define PROFILE_INSTRPROFILING_PORT_H_ #ifdef _MSC_VER #define COMPILER_RT_ALIGNAS(x) __declspec(align(x)) #define COMPILER_RT_VISIBILITY /* FIXME: selectany does not have the same semantics as weak. */ #define COMPILER_RT_WEAK __declspec(selectany) /* Need to include */ #define COMPILER_RT_ALLOCA _alloca /* Need to include and */ #define COMPILER_RT_FTRUNCATE(f,l) _chsize(_fileno(f),l) #elif __GNUC__ #define COMPILER_RT_ALIGNAS(x) __attribute__((aligned(x))) #define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden"))) #define COMPILER_RT_WEAK __attribute__((weak)) #define COMPILER_RT_ALLOCA __builtin_alloca #define COMPILER_RT_FTRUNCATE(f,l) ftruncate(fileno(f),l) #endif #if defined(__APPLE__) #define COMPILER_RT_SEG "__DATA," #else #define COMPILER_RT_SEG "" #endif #ifdef _MSC_VER #define COMPILER_RT_SECTION(Sect) __declspec(allocate(Sect)) #else #define COMPILER_RT_SECTION(Sect) __attribute__((section(Sect))) #endif #define COMPILER_RT_MAX_HOSTLEN 128 #ifdef _MSC_VER #define COMPILER_RT_GETHOSTNAME(Name, Len) gethostname(Name, Len) #elif defined(__ORBIS__) #define COMPILER_RT_GETHOSTNAME(Name, Len) ((void)(Name), (void)(Len), (-1)) #else #define COMPILER_RT_GETHOSTNAME(Name, Len) lprofGetHostName(Name, Len) #define COMPILER_RT_HAS_UNAME 1 #endif #if COMPILER_RT_HAS_ATOMICS == 1 #ifdef _MSC_VER #include #if _MSC_VER < 1900 #define snprintf _snprintf #endif #if defined(_WIN64) #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ (InterlockedCompareExchange64((LONGLONG volatile *)Ptr, (LONGLONG)NewV, \ (LONGLONG)OldV) == (LONGLONG)OldV) #define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \ (DomType *)InterlockedExchangeAdd64((LONGLONG volatile *)&PtrVar, \ (LONGLONG)sizeof(DomType) * PtrIncr) #else /* !defined(_WIN64) */ #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ (InterlockedCompareExchange((LONG volatile *)Ptr, (LONG)NewV, (LONG)OldV) == \ (LONG)OldV) #define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \ (DomType *)InterlockedExchangeAdd((LONG volatile *)&PtrVar, \ (LONG)sizeof(DomType) * PtrIncr) #endif #else /* !defined(_MSC_VER) */ #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ __sync_bool_compare_and_swap(Ptr, OldV, NewV) #define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \ (DomType *)__sync_fetch_and_add((long *)&PtrVar, sizeof(DomType) * PtrIncr) #endif #else /* COMPILER_RT_HAS_ATOMICS != 1 */ #include "InstrProfilingUtil.h" #define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \ lprofBoolCmpXchg((void **)Ptr, OldV, NewV) #define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \ (DomType *)lprofPtrFetchAdd((void **)&PtrVar, sizeof(DomType) * PtrIncr) #endif #if defined(_WIN32) #define DIR_SEPARATOR '\\' #define DIR_SEPARATOR_2 '/' #else #define DIR_SEPARATOR '/' #endif #ifndef DIR_SEPARATOR_2 #define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ #define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #define PROF_ERR(Format, ...) \ fprintf(stderr, "LLVM Profile Error: " Format, __VA_ARGS__); #define PROF_WARN(Format, ...) \ fprintf(stderr, "LLVM Profile Warning: " Format, __VA_ARGS__); #define PROF_NOTE(Format, ...) \ fprintf(stderr, "LLVM Profile Note: " Format, __VA_ARGS__); #if defined(__FreeBSD__) #include #include #else /* defined(__FreeBSD__) */ #include #include #endif /* defined(__FreeBSD__) && defined(__i386__) */ #endif /* PROFILE_INSTRPROFILING_PORT_H_ */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingPlatformLinux.c0000664000175000017500000000570112776214734026064 0ustar kaikai/*===- InstrProfilingPlatformLinux.c - Profile data Linux platform ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if defined(__linux__) || defined(__FreeBSD__) #include #define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) #define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_SECT_NAME) #define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_SECT_NAME) #define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_SECT_NAME) #define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_SECT_NAME) #define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_SECT_NAME) #define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_SECT_NAME) #define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_SECT_NAME) /* Declare section start and stop symbols for various sections * generated by compiler instrumentation. */ extern __llvm_profile_data PROF_DATA_START COMPILER_RT_VISIBILITY; extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY; extern uint64_t PROF_CNTS_START COMPILER_RT_VISIBILITY; extern uint64_t PROF_CNTS_STOP COMPILER_RT_VISIBILITY; extern char PROF_NAME_START COMPILER_RT_VISIBILITY; extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY; extern ValueProfNode PROF_VNODES_START COMPILER_RT_VISIBILITY; extern ValueProfNode PROF_VNODES_STOP COMPILER_RT_VISIBILITY; /* Add dummy data to ensure the section is always created. */ __llvm_profile_data __prof_data_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_DATA_SECT_NAME_STR); uint64_t __prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME_STR); char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME_STR); ValueProfNode __prof_vnodes_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_VNODES_SECT_NAME_STR); COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_begin_data(void) { return &PROF_DATA_START; } COMPILER_RT_VISIBILITY const __llvm_profile_data * __llvm_profile_end_data(void) { return &PROF_DATA_STOP; } COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) { return &PROF_NAME_START; } COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) { return &PROF_NAME_STOP; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return &PROF_CNTS_START; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return &PROF_CNTS_STOP; } COMPILER_RT_VISIBILITY ValueProfNode * __llvm_profile_begin_vnodes(void) { return &PROF_VNODES_START; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) { return &PROF_VNODES_STOP; } COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP; #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingPlatformDarwin.c0000664000175000017500000000440212776214734026206 0ustar kaikai/*===- InstrProfilingPlatformDarwin.c - Profile data on Darwin ------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if defined(__APPLE__) /* Use linker magic to find the bounds of the Data section. */ COMPILER_RT_VISIBILITY extern __llvm_profile_data DataStart __asm("section$start$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern __llvm_profile_data DataEnd __asm("section$end$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern char NamesStart __asm("section$start$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern char NamesEnd __asm("section$end$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern uint64_t CountersStart __asm("section$start$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern uint64_t CountersEnd __asm("section$end$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern ValueProfNode VNodesStart __asm("section$start$__DATA$" INSTR_PROF_VNODES_SECT_NAME_STR); COMPILER_RT_VISIBILITY extern ValueProfNode VNodesEnd __asm("section$end$__DATA$" INSTR_PROF_VNODES_SECT_NAME_STR); COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_begin_data(void) { return &DataStart; } COMPILER_RT_VISIBILITY const __llvm_profile_data *__llvm_profile_end_data(void) { return &DataEnd; } COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) { return &NamesStart; } COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) { return &NamesEnd; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; } COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_begin_vnodes(void) { return &VNodesStart; } COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) { return &VNodesEnd; } COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &VNodesStart; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &VNodesEnd; #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-40/InstrProfilingUtil.c0000664000175000017500000001126512776214734024177 0ustar kaikai/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfilingUtil.h" #include "InstrProfiling.h" #ifdef _WIN32 #include #include #include #else #include #include #include #include #include #endif #ifdef COMPILER_RT_HAS_UNAME #include #endif #include #include COMPILER_RT_VISIBILITY void __llvm_profile_recursive_mkdir(char *path) { int i; for (i = 1; path[i] != '\0'; ++i) { char save = path[i]; if (!IS_DIR_SEPARATOR(path[i])) continue; path[i] = '\0'; #ifdef _WIN32 _mkdir(path); #else mkdir(path, 0755); /* Some of these will fail, ignore it. */ #endif path[i] = save; } } #if COMPILER_RT_HAS_ATOMICS != 1 COMPILER_RT_VISIBILITY uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) { void *R = *Ptr; if (R == OldV) { *Ptr = NewV; return 1; } return 0; } COMPILER_RT_VISIBILITY void *lprofPtrFetchAdd(void **Mem, long ByteIncr) { void *Old = *Mem; *((char **)Mem) += ByteIncr; return Old; } #endif #ifdef COMPILER_RT_HAS_UNAME COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) { struct utsname N; int R; if (!(R = uname(&N))) strncpy(Name, N.nodename, Len); return R; } #endif COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) { FILE *f; int fd; #ifdef COMPILER_RT_HAS_FCNTL_LCK struct flock s_flock; s_flock.l_whence = SEEK_SET; s_flock.l_start = 0; s_flock.l_len = 0; /* Until EOF. */ s_flock.l_pid = getpid(); s_flock.l_type = F_WRLCK; fd = open(ProfileName, O_RDWR | O_CREAT, 0666); if (fd < 0) return NULL; while (fcntl(fd, F_SETLKW, &s_flock) == -1) { if (errno != EINTR) { if (errno == ENOLCK) { PROF_WARN("Data may be corrupted during profile merging : %s\n", "Fail to obtain file lock due to system limit."); } break; } } f = fdopen(fd, "r+b"); #elif defined(_WIN32) // FIXME: Use the wide variants to handle Unicode filenames. HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (h == INVALID_HANDLE_VALUE) return NULL; fd = _open_osfhandle((intptr_t)h, 0); if (fd == -1) { CloseHandle(h); return NULL; } f = _fdopen(fd, "r+b"); if (f == 0) { CloseHandle(h); return NULL; } #else /* Worst case no locking applied. */ PROF_WARN("Concurrent file access is not supported : %s\n", "lack file locking"); fd = open(ProfileName, O_RDWR | O_CREAT, 0666); if (fd < 0) return NULL; f = fdopen(fd, "r+b"); #endif return f; } COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip, size_t *PrefixLen) { const char *Prefix = getenv("GCOV_PREFIX"); const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP"); *PrefixLen = 0; *PrefixStrip = 0; if (Prefix == NULL || Prefix[0] == '\0') return NULL; if (PrefixStripStr) { *PrefixStrip = atoi(PrefixStripStr); /* Negative GCOV_PREFIX_STRIP values are ignored */ if (*PrefixStrip < 0) *PrefixStrip = 0; } else { *PrefixStrip = 0; } *PrefixLen = strlen(Prefix); return Prefix; } COMPILER_RT_VISIBILITY void lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix, size_t PrefixLen, int PrefixStrip) { const char *Ptr; int Level; const char *StrippedPathStr = PathStr; for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) { if (*Ptr == '\0') break; if (!IS_DIR_SEPARATOR(*Ptr)) continue; StrippedPathStr = Ptr; ++Level; } memcpy(Dest, Prefix, PrefixLen); if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1])) Dest[PrefixLen++] = DIR_SEPARATOR; memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1); } COMPILER_RT_VISIBILITY const char * lprofFindFirstDirSeparator(const char *Path) { const char *Sep; Sep = strchr(Path, DIR_SEPARATOR); if (Sep) return Sep; #if defined(DIR_SEPARATOR_2) Sep = strchr(Path, DIR_SEPARATOR_2); #endif return Sep; } COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) { const char *Sep; Sep = strrchr(Path, DIR_SEPARATOR); if (Sep) return Sep; #if defined(DIR_SEPARATOR_2) Sep = strrchr(Path, DIR_SEPARATOR_2); #endif return Sep; } ldc-1.1.0-beta3-src/runtime/profile-rt/DefineBuildProfileRT.cmake0000664000175000017500000001021212776214734022652 0ustar kaikai# Add LLVM Profile runtime if LDC is built with PGO enabled if (LDC_WITH_PGO) file(GLOB LDC_PROFRT_D ${PROFILERT_DIR}/d/ldc/*.d) # Choose the correct subfolder depending on the LLVM version set(PROFILERT_LIBSRC_DIR "${PROFILERT_DIR}/profile-rt-${LLVM_VERSION_MAJOR}${LLVM_VERSION_MINOR}") file(GLOB LDC_PROFRT_C ${PROFILERT_LIBSRC_DIR}/*.c) file(GLOB LDC_PROFRT_CXX ${PROFILERT_LIBSRC_DIR}/*.cc) # Set compiler-dependent flags if(MSVC) # Omit Default Library Name from the library, so it will work with both release and debug builds set(PROFRT_EXTRA_FLAGS "/Zl") # Add library needed for `gethostname` set(PROFRT_EXTRA_LDFLAGS "Ws2_32.lib") else() set(PROFRT_EXTRA_FLAGS "-fPIC -O3") endif() CHECK_CXX_SOURCE_COMPILES(" #ifdef _MSC_VER #include /* Workaround for PR19898. */ #include #endif int main() { #ifdef _MSC_VER volatile LONG val = 1; MemoryBarrier(); InterlockedCompareExchange(&val, 0, 1); InterlockedIncrement(&val); InterlockedDecrement(&val); #else volatile unsigned long val = 1; __sync_synchronize(); __sync_val_compare_and_swap(&val, 1, 0); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1); #endif return 0; } " COMPILER_RT_TARGET_HAS_ATOMICS) if(COMPILER_RT_TARGET_HAS_ATOMICS) set(PROFRT_EXTRA_FLAGS "${PROFRT_EXTRA_FLAGS} -DCOMPILER_RT_HAS_ATOMICS=1") endif() CHECK_CXX_SOURCE_COMPILES(" #if defined(__linux__) #include #endif #include int fd; int main() { struct flock s_flock; s_flock.l_type = F_WRLCK; fcntl(fd, F_SETLKW, &s_flock); return 0; } " COMPILER_RT_TARGET_HAS_FCNTL_LCK) if(COMPILER_RT_TARGET_HAS_FCNTL_LCK) set(PROFRT_EXTRA_FLAGS "${PROFRT_EXTRA_FLAGS} -DCOMPILER_RT_HAS_FCNTL_LCK=1") endif() # Sets up the targets for building the D-source profile-rt object files, # appending the names of the (bitcode) files to link into the library to # outlist_o (outlist_bc). macro(compile_profilert_D d_flags lib_suffix path_suffix outlist_o outlist_bc) get_target_suffix("${lib_suffix}" "${path_suffix}" target_suffix) if(BUILD_SHARED_LIBS) set(shared ";-d-version=Shared") else() set(shared) endif() foreach(f ${LDC_PROFRT_D}) dc( ${f} "${d_flags}${shared}" "${PROFILERT_DIR}" "${target_suffix}" ${outlist_o} ${outlist_bc} ) endforeach() endmacro() macro(build_profile_runtime d_flags c_flags ld_flags path_suffix outlist_targets) get_target_suffix("" "${path_suffix}" target_suffix) set(output_path ${CMAKE_BINARY_DIR}/lib${path_suffix}) set(profilert_d_o "") set(profilert_d_bc "") compile_profilert_D("${d_flags}" "" "${path_suffix}" profilert_d_o profilert_d_bc) add_library(ldc-profile-rt${target_suffix} STATIC ${profilert_d_o} ${LDC_PROFRT_C} ${LDC_PROFRT_CXX}) set_target_properties( ldc-profile-rt${target_suffix} PROPERTIES OUTPUT_NAME ldc-profile-rt VERSION ${LDC_VERSION} LINKER_LANGUAGE C ARCHIVE_OUTPUT_DIRECTORY ${output_path} LIBRARY_OUTPUT_DIRECTORY ${output_path} RUNTIME_OUTPUT_DIRECTORY ${output_path} COMPILE_FLAGS "${c_flags} ${PROFRT_EXTRA_FLAGS}" LINK_FLAGS "${ld_flags} ${PROFRT_EXTRA_LDFLAGS}" ) list(APPEND ${outlist_targets} "ldc-profile-rt${target_suffix}") endmacro() # Install D interface files to profile-rt. install(DIRECTORY ${PROFILERT_DIR}/d/ldc DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.d") else() # No profiling supported, define NOP macro macro(build_profile_runtime c_flags ld_flags path_suffix outlist_targets) endmacro() endif()ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/0000775000175000017500000000000012776214734020225 5ustar kaikaildc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfiling.h0000664000175000017500000000740012776214734023350 0ustar kaikai/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_H_ #define PROFILE_INSTRPROFILING_H_ #ifdef _MSC_VER # define LLVM_LIBRARY_VISIBILITY # define LLVM_LIBRARY_WEAK __declspec(selectany) # define LLVM_ALIGNAS(x) __declspec(align(x)) #elif __GNUC__ # define LLVM_LIBRARY_VISIBILITY __attribute__((visibility("hidden"))) # define LLVM_LIBRARY_WEAK __attribute__((weak)) # define LLVM_ALIGNAS(x) __attribute__((aligned(x))) #endif #define LLVM_SECTION(Sect) __attribute__((section(Sect))) #if defined(__FreeBSD__) && defined(__i386__) /* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to * FreeBSD 10, r232261) when compiled in 32-bit mode. */ #define PRIu64 "llu" typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef uint32_t uintptr_t; #else /* defined(__FreeBSD__) && defined(__i386__) */ #include #include #endif /* defined(__FreeBSD__) && defined(__i386__) */ #define PROFILE_HEADER_SIZE 7 LLVM_ALIGNAS(8) typedef struct __llvm_profile_data { const uint32_t NameSize; const uint32_t NumCounters; const uint64_t FuncHash; const char *const Name; uint64_t *const Counters; } __llvm_profile_data; /*! * \brief Get required size for profile buffer. */ uint64_t __llvm_profile_get_size_for_buffer(void); /*! * \brief Write instrumentation data to the given buffer. * * \pre \c Buffer is the start of a buffer at least as big as \a * __llvm_profile_get_size_for_buffer(). */ int __llvm_profile_write_buffer(char *Buffer); const __llvm_profile_data *__llvm_profile_begin_data(void); const __llvm_profile_data *__llvm_profile_end_data(void); const char *__llvm_profile_begin_names(void); const char *__llvm_profile_end_names(void); uint64_t *__llvm_profile_begin_counters(void); uint64_t *__llvm_profile_end_counters(void); /*! * \brief Write instrumentation data to the current file. * * Writes to the file with the last name given to \a __llvm_profile_set_filename(), * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable, * or if that's not set, the last name given to * \a __llvm_profile_override_default_filename(), or if that's not set, * \c "default.profraw". */ int __llvm_profile_write_file(void); /*! * \brief Set the filename for writing instrumentation data. * * Sets the filename to be used for subsequent calls to * \a __llvm_profile_write_file(). * * \c Name is not copied, so it must remain valid. Passing NULL resets the * filename logic to the default behaviour. */ void __llvm_profile_set_filename(const char *Name); /*! * \brief Set the filename for writing instrumentation data, unless the * \c LLVM_PROFILE_FILE environment variable was set. * * Unless overridden, sets the filename to be used for subsequent calls to * \a __llvm_profile_write_file(). * * \c Name is not copied, so it must remain valid. Passing NULL resets the * filename logic to the default behaviour (unless the \c LLVM_PROFILE_FILE * was set in which case it has no effect). */ void __llvm_profile_override_default_filename(const char *Name); /*! \brief Register to write instrumentation data to file at exit. */ int __llvm_profile_register_write_file_atexit(void); /*! \brief Initialize file handling. */ void __llvm_profile_initialize_file(void); /*! \brief Get the magic token for the file format. */ uint64_t __llvm_profile_get_magic(void); /*! \brief Get the version of the file format. */ uint64_t __llvm_profile_get_version(void); #endif /* PROFILE_INSTRPROFILING_H_ */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfilingPlatformOther.c0000664000175000017500000000461312776214734026055 0ustar kaikai/*===- InstrProfilingPlatformOther.c - Profile data default platform ------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if !defined(__APPLE__) #include static const __llvm_profile_data *DataFirst = NULL; static const __llvm_profile_data *DataLast = NULL; static const char *NamesFirst = NULL; static const char *NamesLast = NULL; static uint64_t *CountersFirst = NULL; static uint64_t *CountersLast = NULL; /*! * \brief Register an instrumented function. * * Calls to this are emitted by clang with -fprofile-instr-generate. Such * calls are only required (and only emitted) on targets where we haven't * implemented linker magic to find the bounds of the sections. */ LLVM_LIBRARY_VISIBILITY void __llvm_profile_register_function(void *Data_) { /* TODO: Only emit this function if we can't use linker magic. */ const __llvm_profile_data *Data = (__llvm_profile_data*)Data_; if (!DataFirst) { DataFirst = Data; DataLast = Data + 1; NamesFirst = Data->Name; NamesLast = Data->Name + Data->NameSize; CountersFirst = Data->Counters; CountersLast = Data->Counters + Data->NumCounters; return; } #define UPDATE_FIRST(First, New) \ First = New < First ? New : First UPDATE_FIRST(DataFirst, Data); UPDATE_FIRST(NamesFirst, Data->Name); UPDATE_FIRST(CountersFirst, Data->Counters); #undef UPDATE_FIRST #define UPDATE_LAST(Last, New) \ Last = New > Last ? New : Last UPDATE_LAST(DataLast, Data + 1); UPDATE_LAST(NamesLast, Data->Name + Data->NameSize); UPDATE_LAST(CountersLast, Data->Counters + Data->NumCounters); #undef UPDATE_LAST } LLVM_LIBRARY_VISIBILITY const __llvm_profile_data *__llvm_profile_begin_data(void) { return DataFirst; } LLVM_LIBRARY_VISIBILITY const __llvm_profile_data *__llvm_profile_end_data(void) { return DataLast; } LLVM_LIBRARY_VISIBILITY const char *__llvm_profile_begin_names(void) { return NamesFirst; } LLVM_LIBRARY_VISIBILITY const char *__llvm_profile_end_names(void) { return NamesLast; } LLVM_LIBRARY_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; } LLVM_LIBRARY_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return CountersLast; } #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfilingBuffer.c0000664000175000017500000001007712776214734024501 0ustar kaikai/*===- InstrProfilingBuffer.c - Write instrumentation to a memory buffer --===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" #include LLVM_LIBRARY_VISIBILITY uint64_t __llvm_profile_get_size_for_buffer(void) { const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); return __llvm_profile_get_size_for_buffer_internal( DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd); } #define PROFILE_RANGE_SIZE(Range) (Range##End - Range##Begin) LLVM_LIBRARY_VISIBILITY uint64_t __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { /* Match logic in __llvm_profile_write_buffer(). */ const uint64_t NamesSize = PROFILE_RANGE_SIZE(Names) * sizeof(char); const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t); return sizeof(uint64_t) * PROFILE_HEADER_SIZE + PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) + PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) + NamesSize + Padding; } LLVM_LIBRARY_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) { /* Match logic in __llvm_profile_get_size_for_buffer(). * Match logic in __llvm_profile_write_file(). */ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); return __llvm_profile_write_buffer_internal(Buffer, DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd); } LLVM_LIBRARY_VISIBILITY int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) { /* Match logic in __llvm_profile_get_size_for_buffer(). * Match logic in __llvm_profile_write_file(). */ /* Calculate size of sections. */ const uint64_t DataSize = DataEnd - DataBegin; const uint64_t CountersSize = CountersEnd - CountersBegin; const uint64_t NamesSize = NamesEnd - NamesBegin; const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t); /* Enough zeroes for padding. */ const char Zeroes[sizeof(uint64_t)] = {0}; /* Create the header. */ uint64_t Header[PROFILE_HEADER_SIZE]; Header[0] = __llvm_profile_get_magic(); Header[1] = __llvm_profile_get_version(); Header[2] = DataSize; Header[3] = CountersSize; Header[4] = NamesSize; Header[5] = (uintptr_t)CountersBegin; Header[6] = (uintptr_t)NamesBegin; /* Write the data. */ #define UPDATE_memcpy(Data, Size) \ do { \ memcpy(Buffer, Data, Size); \ Buffer += Size; \ } while (0) UPDATE_memcpy(Header, PROFILE_HEADER_SIZE * sizeof(uint64_t)); UPDATE_memcpy(DataBegin, DataSize * sizeof(__llvm_profile_data)); UPDATE_memcpy(CountersBegin, CountersSize * sizeof(uint64_t)); UPDATE_memcpy(NamesBegin, NamesSize * sizeof(char)); UPDATE_memcpy(Zeroes, Padding * sizeof(char)); #undef UPDATE_memcpy return 0; } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfiling.c0000664000175000017500000000271312776214734023345 0ustar kaikai/*===- InstrProfiling.c - Support library for PGO instrumentation ---------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include LLVM_LIBRARY_VISIBILITY uint64_t __llvm_profile_get_magic(void) { /* Magic number to detect file format and endianness. * * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0, * so that utilities, like strings, don't grab it as a string. 129 is also * invalid UTF-8, and high enough to be interesting. * * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR" * for 32-bit platforms. */ unsigned char R = sizeof(void *) == sizeof(uint64_t) ? 'r' : 'R'; return (uint64_t)255 << 56 | (uint64_t)'l' << 48 | (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t) R << 8 | (uint64_t)129; } LLVM_LIBRARY_VISIBILITY uint64_t __llvm_profile_get_version(void) { /* This should be bumped any time the output format changes. */ return 1; } LLVM_LIBRARY_VISIBILITY void __llvm_profile_reset_counters(void) { uint64_t *I = __llvm_profile_begin_counters(); uint64_t *E = __llvm_profile_end_counters(); memset(I, 0, sizeof(uint64_t)*(E - I)); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfilingUtil.h0000664000175000017500000000105112776214734024202 0ustar kaikai/*===- InstrProfilingUtil.h - Support library for PGO instrumentation -----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILINGUTIL_H #define PROFILE_INSTRPROFILINGUTIL_H /*! \brief Create a directory tree. */ void __llvm_profile_recursive_mkdir(char *Pathname); #endif /* PROFILE_INSTRPROFILINGUTIL_H */ ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfilingFile.c0000664000175000017500000001536212776214734024151 0ustar kaikai/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #include "InstrProfilingUtil.h" #include #include #include #include #define UNCONST(ptr) ((void *)(uintptr_t)(ptr)) static int writeFile(FILE *File) { /* Match logic in __llvm_profile_write_buffer(). */ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); const uint64_t *CountersBegin = __llvm_profile_begin_counters(); const uint64_t *CountersEnd = __llvm_profile_end_counters(); const char *NamesBegin = __llvm_profile_begin_names(); const char *NamesEnd = __llvm_profile_end_names(); /* Calculate size of sections. */ const uint64_t DataSize = DataEnd - DataBegin; const uint64_t CountersSize = CountersEnd - CountersBegin; const uint64_t NamesSize = NamesEnd - NamesBegin; const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t); /* Enough zeroes for padding. */ const char Zeroes[sizeof(uint64_t)] = {0}; /* Create the header. */ uint64_t Header[PROFILE_HEADER_SIZE]; Header[0] = __llvm_profile_get_magic(); Header[1] = __llvm_profile_get_version(); Header[2] = DataSize; Header[3] = CountersSize; Header[4] = NamesSize; Header[5] = (uintptr_t)CountersBegin; Header[6] = (uintptr_t)NamesBegin; /* Write the data. */ #define CHECK_fwrite(Data, Size, Length, File) \ do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0) CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File); CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File); CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File); CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File); CHECK_fwrite(Zeroes, sizeof(char), Padding, File); #undef CHECK_fwrite return 0; } static int writeFileWithName(const char *OutputName) { int RetVal; FILE *OutputFile; if (!OutputName || !OutputName[0]) return -1; /* Append to the file to support profiling multiple shared objects. */ OutputFile = fopen(OutputName, "ab"); if (!OutputFile) return -1; RetVal = writeFile(OutputFile); fclose(OutputFile); return RetVal; } LLVM_LIBRARY_WEAK int __llvm_profile_OwnsFilename = 0; LLVM_LIBRARY_WEAK const char *__llvm_profile_CurrentFilename = NULL; static void truncateCurrentFile(void) { const char *Filename; FILE *File; Filename = __llvm_profile_CurrentFilename; if (!Filename || !Filename[0]) return; /* Create the directory holding the file, if needed. */ if (strchr(Filename, '/')) { char *Copy = malloc(strlen(Filename) + 1); strcpy(Copy, Filename); __llvm_profile_recursive_mkdir(Copy); free(Copy); } /* Truncate the file. Later we'll reopen and append. */ File = fopen(Filename, "w"); if (!File) return; fclose(File); } static void setFilename(const char *Filename, int OwnsFilename) { /* Check if this is a new filename and therefore needs truncation. */ int NewFile = !__llvm_profile_CurrentFilename || (Filename && strcmp(Filename, __llvm_profile_CurrentFilename)); if (__llvm_profile_OwnsFilename) free(UNCONST(__llvm_profile_CurrentFilename)); __llvm_profile_CurrentFilename = Filename; __llvm_profile_OwnsFilename = OwnsFilename; /* If not a new file, append to support profiling multiple shared objects. */ if (NewFile) truncateCurrentFile(); } static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); } int getpid(void); static int setFilenamePossiblyWithPid(const char *Filename) { #define MAX_PID_SIZE 16 char PidChars[MAX_PID_SIZE] = {0}; int NumPids = 0, PidLength = 0; char *Allocated; int I, J; /* Reset filename on NULL, except with env var which is checked by caller. */ if (!Filename) { resetFilenameToDefault(); return 0; } /* Check the filename for "%p", which indicates a pid-substitution. */ for (I = 0; Filename[I]; ++I) if (Filename[I] == '%' && Filename[++I] == 'p') if (!NumPids++) { PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()); if (PidLength <= 0) return -1; } if (!NumPids) { setFilename(Filename, 0); return 0; } /* Allocate enough space for the substituted filename. */ Allocated = malloc(I + NumPids*(PidLength - 2) + 1); if (!Allocated) return -1; /* Construct the new filename. */ for (I = 0, J = 0; Filename[I]; ++I) if (Filename[I] == '%') { if (Filename[++I] == 'p') { memcpy(Allocated + J, PidChars, PidLength); J += PidLength; } /* Drop any unknown substitutions. */ } else Allocated[J++] = Filename[I]; Allocated[J] = 0; /* Use the computed name. */ setFilename(Allocated, 1); return 0; } static int setFilenameFromEnvironment(void) { const char *Filename = getenv("LLVM_PROFILE_FILE"); if (!Filename || !Filename[0]) return -1; return setFilenamePossiblyWithPid(Filename); } static void setFilenameAutomatically(void) { if (!setFilenameFromEnvironment()) return; resetFilenameToDefault(); } LLVM_LIBRARY_VISIBILITY void __llvm_profile_initialize_file(void) { /* Check if the filename has been initialized. */ if (__llvm_profile_CurrentFilename) return; /* Detect the filename and truncate. */ setFilenameAutomatically(); } LLVM_LIBRARY_VISIBILITY void __llvm_profile_set_filename(const char *Filename) { setFilenamePossiblyWithPid(Filename); } LLVM_LIBRARY_VISIBILITY void __llvm_profile_override_default_filename(const char *Filename) { /* If the env var is set, skip setting filename from argument. */ const char *Env_Filename = getenv("LLVM_PROFILE_FILE"); if (Env_Filename && Env_Filename[0]) return; setFilenamePossiblyWithPid(Filename); } LLVM_LIBRARY_VISIBILITY int __llvm_profile_write_file(void) { int rc; /* Check the filename. */ if (!__llvm_profile_CurrentFilename) return -1; /* Write the file. */ rc = writeFileWithName(__llvm_profile_CurrentFilename); if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS")) fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n", __llvm_profile_CurrentFilename, strerror(errno)); return rc; } static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } LLVM_LIBRARY_VISIBILITY int __llvm_profile_register_write_file_atexit(void) { static int HasBeenRegistered = 0; if (HasBeenRegistered) return 0; HasBeenRegistered = 1; return atexit(writeFileWithoutReturn); } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfilingRuntime.cc0000664000175000017500000000117412776214734025054 0ustar kaikai//===- InstrProfilingRuntime.cpp - PGO runtime initialization -------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// extern "C" { #include "InstrProfiling.h" LLVM_LIBRARY_VISIBILITY int __llvm_profile_runtime; } namespace { class RegisterRuntime { public: RegisterRuntime() { __llvm_profile_register_write_file_atexit(); __llvm_profile_initialize_file(); } }; RegisterRuntime Registration; } ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfilingInternal.h0000664000175000017500000000315212776214734025045 0ustar kaikai/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #ifndef PROFILE_INSTRPROFILING_INTERNALH_ #define PROFILE_INSTRPROFILING_INTERNALH_ #include "InstrProfiling.h" /*! * \brief Write instrumentation data to the given buffer, given explicit * pointers to the live data in memory. This function is probably not what you * want. Use __llvm_profile_get_size_for_buffer instead. Use this function if * your program has a custom memory layout. */ uint64_t __llvm_profile_get_size_for_buffer_internal( const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); /*! * \brief Write instrumentation data to the given buffer, given explicit * pointers to the live data in memory. This function is probably not what you * want. Use __llvm_profile_write_buffer instead. Use this function if your * program has a custom memory layout. * * \pre \c Buffer is the start of a buffer at least as big as \a * __llvm_profile_get_size_for_buffer_internal(). */ int __llvm_profile_write_buffer_internal( char *Buffer, const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin, const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfilingPlatformDarwin.c0000664000175000017500000000316312776214734026217 0ustar kaikai/*===- InstrProfilingPlatformDarwin.c - Profile data on Darwin ------------===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" #if defined(__APPLE__) /* Use linker magic to find the bounds of the Data section. */ LLVM_LIBRARY_VISIBILITY extern __llvm_profile_data DataStart __asm("section$start$__DATA$__llvm_prf_data"); LLVM_LIBRARY_VISIBILITY extern __llvm_profile_data DataEnd __asm("section$end$__DATA$__llvm_prf_data"); LLVM_LIBRARY_VISIBILITY extern char NamesStart __asm("section$start$__DATA$__llvm_prf_names"); LLVM_LIBRARY_VISIBILITY extern char NamesEnd __asm("section$end$__DATA$__llvm_prf_names"); LLVM_LIBRARY_VISIBILITY extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts"); LLVM_LIBRARY_VISIBILITY extern uint64_t CountersEnd __asm("section$end$__DATA$__llvm_prf_cnts"); LLVM_LIBRARY_VISIBILITY const __llvm_profile_data *__llvm_profile_begin_data(void) { return &DataStart; } LLVM_LIBRARY_VISIBILITY const __llvm_profile_data *__llvm_profile_end_data(void) { return &DataEnd; } LLVM_LIBRARY_VISIBILITY const char *__llvm_profile_begin_names(void) { return &NamesStart; } LLVM_LIBRARY_VISIBILITY const char *__llvm_profile_end_names(void) { return &NamesEnd; } LLVM_LIBRARY_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; } LLVM_LIBRARY_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; } #endif ldc-1.1.0-beta3-src/runtime/profile-rt/profile-rt-37/InstrProfilingUtil.c0000664000175000017500000000154412776214734024204 0ustar kaikai/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\ |* |* The LLVM Compiler Infrastructure |* |* This file is distributed under the University of Illinois Open Source |* License. See LICENSE.TXT for details. |* \*===----------------------------------------------------------------------===*/ #include "InstrProfilingUtil.h" #include "InstrProfiling.h" #ifdef _WIN32 #include #elif I386_FREEBSD int mkdir(const char*, unsigned short); #else #include #include #endif LLVM_LIBRARY_VISIBILITY void __llvm_profile_recursive_mkdir(char *path) { int i; for (i = 1; path[i] != '\0'; ++i) { if (path[i] != '/') continue; path[i] = '\0'; #ifdef _WIN32 _mkdir(path); #else mkdir(path, 0755); /* Some of these will fail, ignore it. */ #endif path[i] = '/'; } } ldc-1.1.0-beta3-src/runtime/profile-rt/d/0000775000175000017500000000000012776214734016136 5ustar kaikaildc-1.1.0-beta3-src/runtime/profile-rt/d/ldc/0000775000175000017500000000000012776214734016700 5ustar kaikaildc-1.1.0-beta3-src/runtime/profile-rt/d/ldc/profile.d0000664000175000017500000001354512776214734020515 0ustar kaikai/** * Contains funtions to control and query profiling information for profile * instrumented programs (compiled with -fprofile-instr-generate). * It provides an interface to the profile-rt runtime library. * * Note that this only works for instrumented binaries. * * Copyright: Authors 2016-2016 * License: University of Illinois Open Source License and MIT License. See LDC's LICENSE for details. * Authors: Johan B C Engelen */ module ldc.profile; version(LDC_LLVM_309) version = HASHED_FUNC_NAMES; version(LDC_LLVM_400) version = HASHED_FUNC_NAMES; @nogc: nothrow: /** * Data structure for profile data per instrumented function */ extern(C++) struct ProfileData { // This has to match INSTR_PROF_DATA in profile-rt/InstrProfData.inc version(LDC_LLVM_307) { uint NameSize; uint NumCounters; ulong FuncHash; immutable(char)* Name; ulong* Counters; } else version(LDC_LLVM_308) { uint NameSize; uint NumCounters; ulong FuncHash; immutable(char)* Name; ulong* Counters; void* FunctionPointer; void* Values; ushort NumValueSites; } else version(LDC_LLVM_309) { ulong NameRef; ulong FuncHash; ulong* Counters; void* FunctionPointer; void* Values; uint NumCounters; ushort NumValueSites; } else version(LDC_LLVM_400) { ulong NameRef; ulong FuncHash; ulong* Counters; void* FunctionPointer; void* Values; uint NumCounters; ushort NumValueSites; } else { static assert(0, "unsupported LLVM version"); } } // Symbols provided by profile-rt lib private { extern(C) { alias uint64_t = ulong; alias __llvm_profile_data = ProfileData; const(__llvm_profile_data)* __llvm_profile_begin_data(); const(__llvm_profile_data)* __llvm_profile_end_data(); immutable(char)* __llvm_profile_begin_names(); immutable(char)* __llvm_profile_end_names(); uint64_t* __llvm_profile_begin_counters(); uint64_t* __llvm_profile_end_counters(); void __llvm_profile_reset_counters(); uint64_t __llvm_profile_get_magic(); uint64_t __llvm_profile_get_version(); }} /** * Reset all profiling information of the whole program. * This can be used for example to remove transient start-up behavior from the * profile. */ void resetAll() { __llvm_profile_reset_counters(); } /** * Reset profile counter values for a function. * * The function does nothing if no profile data is found for ($D F). * * Params: * F = The function to set the profile data of. */ void resetCounts(alias F)() // TODO: add constraint on F { auto data = getData!F; if (data && ((*data).NumCounters > 0)) { cast(ulong[])(*data).Counters[0..(*data).NumCounters] = 0; } } /** * Get profile data struct for a given (mangled) function name. * * Params: * funcname = Mangled function name. * Returns: * Pointer to the profile data for ($D funcname), or null if no profile data * was found for ($D funcname). */ const(ProfileData)* getData(string funcname) { version(HASHED_FUNC_NAMES) { import std.digest.md; import std.bitmanip; auto md5hash = md5Of(funcname); auto nameref = peek!(ulong, Endian.littleEndian)(md5hash[0..8]); } for (auto data = __llvm_profile_begin_data(), e = __llvm_profile_end_data(); data < e; ++data) { version(HASHED_FUNC_NAMES) { if (nameref == (*data).NameRef) return data; } else { if (funcname == (*data).Name[0..(*data).NameSize]) return data; } } return null; } /** * Get profile data struct for a given function. * * Params: * F = The function to get the profile data of. * Returns: * Pointer to the profile data for ($D F), or null if no profile data was found * for ($D F). */ const(ProfileData)* getData(alias F)() // TODO: add constraint on F { enum mangledName = F.mangleof; version(Win32) { import std.traits : functionLinkage; static if (functionLinkage!F == "D") return getData("_" ~ mangledName); else return getData(mangledName); } else { return getData(mangledName); } } /** * Get the current number of times function ($D F) has been called. * * Params: * F = The function to get the call count of. * * Returns: * The call count of function ($D F). If no profile data * is found for ($D F), ulong.max is returned. */ ulong getCallCount(alias F)() // TODO: add constraint on F { auto data = getData!F; if (data && ((*data).NumCounters > 0)) { return (*data).Counters[0]; } else { return ulong.max; } } /** * Get current counter value. * * Params: * F = The function to get the profile data of. * idx = Counter index. * * Returns: * Value of the counter with index ($D idx) for function ($D F). If no profile data * is found for ($D F), or if ($D idx) is out of range for ($D F), ulong.max is returned. */ ulong getCount(alias F)(uint idx) // TODO: add constraint on F { auto data = getData!F; if (data && (idx < (*data).NumCounters)) { return (*data).Counters[idx]; } else { return ulong.max; } } /** * Set profile counter value. * * The function does nothing if no profile data is found for ($D F), or if ($D * idx) is out of range for ($D F). * * Params: * F = The function to set the profile data of. * idx = Counter index. * count = The new counter value. * */ void setCount(alias F)(uint idx, ulong count) // TODO: add constraint on F { auto data = getData!F; if (data && (idx < (*data).NumCounters)) { cast(ulong)(*data).Counters[idx] = count; } } ldc-1.1.0-beta3-src/runtime/profile-rt/README.md0000664000175000017500000000230512776214734017172 0ustar kaikaiLDC – profile-rt =============================== `profile-rt` is the runtime library for writing profiling instrumentation files. It is linked with instrumented executables (`-fprofile-instr-generate`). `profile-rt` consists of two parts: a part from LLVM (C/C++, `profile-rt/profile-rt-3*`), and a D interface to the lib (`profile-rt/d`). See the source files and LDC's LICENSE file for licensing details. The sources in `profile-rt/profile-rt-3*` are exact copies of the `lib/profile` part of LLVM's `compiler-rt` project (`compiler-rt/lib/profile/*`) and its version has to be exactly in-sync with the LLVM version used to build LDC. Because of this, we carry a version of compiler-rt/lib/profile for each LLVM version supported for PGO. LLVM's llvm-profdata tool of the corresponding LLVM version (!) can interpret the raw profile data file output by profile-rt, and can convert it into a stable format that can be interpreted by future LLVM version profiling data readers (2nd compile pass). See `ldc-profdata` in the `tools` directory. The "d" folder contains the D bindings and helper functions to interface with profile-rt. The code in the "d" folder should be compatible with all supported LLVM versions. ldc-1.1.0-beta3-src/runtime/phobos/0000775000175000017500000000000012776215007015114 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/win32.mak0000664000175000017500000013346312776215007016562 0ustar kaikai# Makefile to build D runtime library phobos.lib for Win32 # Prerequisites: # Digital Mars dmc, lib, and make that are unzipped from Digital Mars C: # http://ftp.digitalmars.com/Digital_Mars_C++/Patch/dm850c.zip # and are in the \dm\bin directory. # Targets: # make # Same as make unittest # make phobos.lib # Build phobos.lib # make clean # Delete unneeded files created by build process # make unittest # Build phobos.lib, build and run unit tests # make cov # Build for coverage tests, run coverage tests # make html # Build documentation # Notes: # minit.obj requires Microsoft MASM386.EXE to build from minit.asm, # or just use the supplied minit.obj ## Memory model (32 or 64) MODEL=32 ## Copy command CP=cp ## Directory where dmd has been installed DIR=\dmd2 ## Flags for dmc C compiler CFLAGS=-mn -6 -r #CFLAGS=-g -mn -6 -r ## Location of druntime tree DRUNTIME=..\druntime DRUNTIMELIB=$(DRUNTIME)\lib\druntime.lib ## Flags for dmd D compiler DFLAGS=-conf= -O -release -w -dip25 -I$(DRUNTIME)\import #DFLAGS=-unittest -g #DFLAGS=-unittest -cov -g ## Flags for compiling unittests UDFLAGS=-conf= -O -w -dip25 -I$(DRUNTIME)\import ## C compiler CC=dmc AR=lib MAKE=make ## D compiler DMD=$(DIR)\bin\dmd #DMD=..\dmd DMD=dmd ## Location of where to write the html documentation files DOCSRC = ../dlang.org STDDOC = $(DOCSRC)/html.ddoc $(DOCSRC)/dlang.org.ddoc $(DOCSRC)/std.ddoc $(DOCSRC)/macros.ddoc $(DOCSRC)/std_navbar-prerelease.ddoc project.ddoc DOC=..\..\html\d\phobos #DOC=..\doc\phobos ## Zlib library ZLIB=etc\c\zlib\zlib.lib .c.obj: $(CC) -c $(CFLAGS) $* .cpp.obj: $(CC) -c $(CFLAGS) $* .d.obj: $(DMD) -c $(DFLAGS) $* .asm.obj: $(CC) -c $* LIB=phobos.lib targets : $(LIB) test : test.exe test.obj : test.d $(DMD) -conf= -c test -g -unittest test.exe : test.obj $(LIB) $(DMD) -conf= test.obj -g -L/map # ti_bit.obj ti_Abit.obj # The separation is a workaround for bug 4904 (optlink bug 3372). # SRCS_1 is the heavyweight modules which are most likely to trigger the bug. # Do not add any more modules to SRCS_1. SRC_STD_1_HEAVY= std\stdio.d std\stdiobase.d \ std\string.d std\format.d \ std\file.d SRC_STD_2a_HEAVY= std\array.d std\functional.d std\path.d std\outbuffer.d std\utf.d SRC_STD_3= std\csv.d std\math.d std\complex.d std\numeric.d std\bigint.d \ std\bitmanip.d std\typecons.d \ std\uni.d std\base64.d std\ascii.d \ std\demangle.d std\uri.d std\mmfile.d std\getopt.d SRC_STD_3a= std\signals.d std\meta.d std\typetuple.d std\traits.d \ std\encoding.d std\xml.d \ std\random.d \ std\exception.d \ std\compiler.d \ std\system.d std\concurrency.d std\concurrencybase.d SRC_STD_3b= std\datetime.d #can't place SRC_STD_DIGEST in SRC_STD_REST because of out-of-memory issues SRC_STD_DIGEST= std\digest\crc.d std\digest\sha.d std\digest\md.d \ std\digest\ripemd.d std\digest\digest.d std\digest\hmac.d SRC_STD_CONTAINER= std\container\array.d std\container\binaryheap.d \ std\container\dlist.d std\container\rbtree.d std\container\slist.d \ std\container\util.d std\container\package.d SRC_STD_4= std\uuid.d $(SRC_STD_DIGEST) SRC_STD_ALGO= std\algorithm\package.d std\algorithm\comparison.d \ std\algorithm\iteration.d std\algorithm\mutation.d \ std\algorithm\searching.d std\algorithm\setops.d \ std\algorithm\sorting.d std\algorithm\internal.d SRC_STD_5_HEAVY= $(SRC_STD_ALGO) SRC_STD_LOGGER= std\experimental\logger\core.d std\experimental\logger\filelogger.d \ std\experimental\logger\multilogger.d std\experimental\logger\nulllogger.d \ std\experimental\logger\package.d SRC_STD_ALLOC_BB= std\experimental\allocator\building_blocks\affix_allocator.d \ std\experimental\allocator\building_blocks\allocator_list.d \ std\experimental\allocator\building_blocks\bitmapped_block.d \ std\experimental\allocator\building_blocks\bucketizer.d \ std\experimental\allocator\building_blocks\fallback_allocator.d \ std\experimental\allocator\building_blocks\free_list.d \ std\experimental\allocator\building_blocks\free_tree.d \ std\experimental\allocator\building_blocks\kernighan_ritchie.d \ std\experimental\allocator\building_blocks\null_allocator.d \ std\experimental\allocator\building_blocks\quantizer.d \ std\experimental\allocator\building_blocks\region.d \ std\experimental\allocator\building_blocks\scoped_allocator.d \ std\experimental\allocator\building_blocks\segregator.d \ std\experimental\allocator\building_blocks\stats_collector.d \ std\experimental\allocator\building_blocks\package.d SRC_STD_ALLOC= std\experimental\allocator\common.d std\experimental\allocator\gc_allocator.d \ std\experimental\allocator\mallocator.d std\experimental\allocator\mmap_allocator.d \ std\experimental\allocator\showcase.d std\experimental\allocator\typed.d \ std\experimental\allocator\package.d \ $(SRC_STD_ALLOC_BB) SRC_STD_6= std\variant.d std\zlib.d \ std\stream.d std\socket.d std\socketstream.d \ std\conv.d std\zip.d std\cstream.d \ $(SRC_STD_CONTAINER) $(SRC_STD_LOGGER) $(SRC_STD_ALLOC) SRC_STD_REST= std\stdint.d \ std\json.d \ std\parallelism.d \ std\mathspecial.d \ std\process.d SRC_STD_ALL= $(SRC_STD_1_HEAVY) $(SRC_STD_2a_HEAVY) \ $(SRC_STD_3) $(SRC_STD_3a) $(SRC_STD_3b) $(SRC_STD_4) \ $(SRC_STD_6) $(SRC_STD_REST) SRC= unittest.d index.d SRC_STD= std\zlib.d std\zip.d std\stdint.d std\conv.d std\utf.d std\uri.d \ std\math.d std\string.d std\path.d std\datetime.d \ std\csv.d std\file.d std\compiler.d std\system.d \ std\outbuffer.d std\base64.d \ std\meta.d std\mmfile.d \ std\random.d std\stream.d std\process.d \ std\socket.d std\socketstream.d std\format.d \ std\stdio.d std\uni.d std\uuid.d \ std\cstream.d std\demangle.d \ std\signals.d std\typetuple.d std\traits.d \ std\getopt.d \ std\variant.d std\numeric.d std\bitmanip.d std\complex.d std\mathspecial.d \ std\functional.d std\array.d std\typecons.d \ std\json.d std\xml.d std\encoding.d std\bigint.d std\concurrency.d \ std\concurrencybase.d std\stdiobase.d std\parallelism.d \ std\exception.d std\ascii.d SRC_STD_REGEX= std\regex\internal\ir.d std\regex\package.d std\regex\internal\parser.d \ std\regex\internal\tests.d std\regex\internal\backtracking.d \ std\regex\internal\thompson.d std\regex\internal\kickstart.d \ std\regex\internal\generator.d SRC_STD_RANGE= std\range\package.d std\range\primitives.d \ std\range\interfaces.d SRC_STD_NDSLICE= std\experimental\ndslice\package.d \ std\experimental\ndslice\iteration.d \ std\experimental\ndslice\selection.d \ std\experimental\ndslice\slice.d \ std\experimental\ndslice\internal.d SRC_STD_NET= std\net\isemail.d std\net\curl.d SRC_STD_C= std\c\process.d std\c\stdlib.d std\c\time.d std\c\stdio.d \ std\c\math.d std\c\stdarg.d std\c\stddef.d std\c\fenv.d std\c\string.d \ std\c\locale.d std\c\wcharh.d SRC_STD_WIN= std\windows\registry.d \ std\windows\iunknown.d std\windows\syserror.d std\windows\charset.d SRC_STD_C_WIN= std\c\windows\windows.d std\c\windows\com.d \ std\c\windows\winsock.d std\c\windows\stat.d SRC_STD_C_LINUX= std\c\linux\linux.d \ std\c\linux\socket.d std\c\linux\pthread.d std\c\linux\termios.d \ std\c\linux\tipc.d SRC_STD_C_OSX= std\c\osx\socket.d SRC_STD_C_FREEBSD= std\c\freebsd\socket.d SRC_STD_INTERNAL= std\internal\cstring.d std\internal\processinit.d \ std\internal\unicode_tables.d std\internal\unicode_comp.d std\internal\unicode_decomp.d \ std\internal\unicode_grapheme.d std\internal\unicode_norm.d std\internal\scopebuffer.d \ std\internal\test\dummyrange.d SRC_STD_INTERNAL_DIGEST= std\internal\digest\sha_SSSE3.d SRC_STD_INTERNAL_MATH= std\internal\math\biguintcore.d \ std\internal\math\biguintnoasm.d std\internal\math\biguintx86.d \ std\internal\math\gammafunction.d std\internal\math\errorfunction.d SRC_STD_INTERNAL_WINDOWS= std\internal\windows\advapi32.d SRC_ETC= SRC_ETC_C= etc\c\zlib.d etc\c\curl.d etc\c\sqlite3.d \ etc\c\odbc\sql.d etc\c\odbc\sqlext.d etc\c\odbc\sqltypes.d etc\c\odbc\sqlucode.d SRC_TO_COMPILE_NOT_STD= \ $(SRC_STD_REGEX) \ $(SRC_STD_NET) \ $(SRC_STD_C) \ $(SRC_STD_WIN) \ $(SRC_STD_C_WIN) \ $(SRC_STD_INTERNAL) \ $(SRC_STD_INTERNAL_DIGEST) \ $(SRC_STD_INTERNAL_MATH) \ $(SRC_STD_INTERNAL_WINDOWS) \ $(SRC_ETC) \ $(SRC_ETC_C) SRC_TO_COMPILE= $(SRC_STD_ALL) \ $(SRC_STD_ALGO) \ $(SRC_STD_RANGE) \ $(SRC_STD_NDSLICE) \ $(SRC_TO_COMPILE_NOT_STD) SRC_ZLIB= \ etc\c\zlib\crc32.h \ etc\c\zlib\deflate.h \ etc\c\zlib\gzguts.h \ etc\c\zlib\inffixed.h \ etc\c\zlib\inffast.h \ etc\c\zlib\inftrees.h \ etc\c\zlib\inflate.h \ etc\c\zlib\trees.h \ etc\c\zlib\zconf.h \ etc\c\zlib\zlib.h \ etc\c\zlib\zutil.h \ etc\c\zlib\adler32.c \ etc\c\zlib\compress.c \ etc\c\zlib\crc32.c \ etc\c\zlib\deflate.c \ etc\c\zlib\example.c \ etc\c\zlib\gzclose.c \ etc\c\zlib\gzlib.c \ etc\c\zlib\gzread.c \ etc\c\zlib\gzwrite.c \ etc\c\zlib\infback.c \ etc\c\zlib\inffast.c \ etc\c\zlib\inflate.c \ etc\c\zlib\inftrees.c \ etc\c\zlib\minigzip.c \ etc\c\zlib\trees.c \ etc\c\zlib\uncompr.c \ etc\c\zlib\zutil.c \ etc\c\zlib\algorithm.txt \ etc\c\zlib\zlib.3 \ etc\c\zlib\ChangeLog \ etc\c\zlib\README \ etc\c\zlib\win32.mak \ etc\c\zlib\win64.mak \ etc\c\zlib\linux.mak \ etc\c\zlib\osx.mak DOCS= $(DOC)\object.html \ $(DOC)\core_atomic.html \ $(DOC)\core_bitop.html \ $(DOC)\core_exception.html \ $(DOC)\core_memory.html \ $(DOC)\core_runtime.html \ $(DOC)\core_simd.html \ $(DOC)\core_time.html \ $(DOC)\core_thread.html \ $(DOC)\core_vararg.html \ $(DOC)\core_sync_barrier.html \ $(DOC)\core_sync_condition.html \ $(DOC)\core_sync_config.html \ $(DOC)\core_sync_exception.html \ $(DOC)\core_sync_mutex.html \ $(DOC)\core_sync_rwmutex.html \ $(DOC)\core_sync_semaphore.html \ $(DOC)\std_algorithm.html \ $(DOC)\std_algorithm_comparison.html \ $(DOC)\std_algorithm_iteration.html \ $(DOC)\std_algorithm_mutation.html \ $(DOC)\std_algorithm_searching.html \ $(DOC)\std_algorithm_setops.html \ $(DOC)\std_algorithm_sorting.html \ $(DOC)\std_array.html \ $(DOC)\std_ascii.html \ $(DOC)\std_base64.html \ $(DOC)\std_bigint.html \ $(DOC)\std_bitmanip.html \ $(DOC)\std_concurrency.html \ $(DOC)\std_compiler.html \ $(DOC)\std_complex.html \ $(DOC)\std_container_array.html \ $(DOC)\std_container_binaryheap.html \ $(DOC)\std_container_dlist.html \ $(DOC)\std_container_rbtree.html \ $(DOC)\std_container_slist.html \ $(DOC)\std_container.html \ $(DOC)\std_container_util.html \ $(DOC)\std_conv.html \ $(DOC)\std_digest_crc.html \ $(DOC)\std_digest_sha.html \ $(DOC)\std_digest_md.html \ $(DOC)\std_digest_ripemd.html \ $(DOC)\std_digest_hmac.html \ $(DOC)\std_digest_digest.html \ $(DOC)\std_digest_hmac.html \ $(DOC)\std_cstream.html \ $(DOC)\std_csv.html \ $(DOC)\std_datetime.html \ $(DOC)\std_demangle.html \ $(DOC)\std_encoding.html \ $(DOC)\std_exception.html \ $(DOC)\std_file.html \ $(DOC)\std_format.html \ $(DOC)\std_functional.html \ $(DOC)\std_getopt.html \ $(DOC)\std_json.html \ $(DOC)\std_math.html \ $(DOC)\std_mathspecial.html \ $(DOC)\std_meta.html \ $(DOC)\std_mmfile.html \ $(DOC)\std_numeric.html \ $(DOC)\std_outbuffer.html \ $(DOC)\std_parallelism.html \ $(DOC)\std_path.html \ $(DOC)\std_process.html \ $(DOC)\std_random.html \ $(DOC)\std_range.html \ $(DOC)\std_range_primitives.html \ $(DOC)\std_range_interfaces.html \ $(DOC)\std_regex.html \ $(DOC)\std_signals.html \ $(DOC)\std_socket.html \ $(DOC)\std_socketstream.html \ $(DOC)\std_stdint.html \ $(DOC)\std_stdio.html \ $(DOC)\std_stream.html \ $(DOC)\std_string.html \ $(DOC)\std_system.html \ $(DOC)\std_traits.html \ $(DOC)\std_typecons.html \ $(DOC)\std_typetuple.html \ $(DOC)\std_uni.html \ $(DOC)\std_uri.html \ $(DOC)\std_utf.html \ $(DOC)\std_uuid.html \ $(DOC)\std_variant.html \ $(DOC)\std_xml.html \ $(DOC)\std_zip.html \ $(DOC)\std_zlib.html \ $(DOC)\std_net_isemail.html \ $(DOC)\std_net_curl.html \ $(DOC)\std_experimental_logger_core.html \ $(DOC)\std_experimental_logger_filelogger.html \ $(DOC)\std_experimental_logger_multilogger.html \ $(DOC)\std_experimental_logger_nulllogger.html \ $(DOC)\std_experimental_logger.html \ $(DOC)\std_experimental_allocator_building_blocks_affix_allocator.html \ $(DOC)\std_experimental_allocator_building_blocks_allocator_list.html \ $(DOC)\std_experimental_allocator_building_blocks_bitmapped_block.html \ $(DOC)\std_experimental_allocator_building_blocks_bucketizer.html \ $(DOC)\std_experimental_allocator_building_blocks_fallback_allocator.html \ $(DOC)\std_experimental_allocator_building_blocks_free_list.html \ $(DOC)\std_experimental_allocator_building_blocks_free_tree.html \ $(DOC)\std_experimental_allocator_building_blocks_kernighan_ritchie.html \ $(DOC)\std_experimental_allocator_building_blocks_null_allocator.html \ $(DOC)\std_experimental_allocator_building_blocks_quantizer.html \ $(DOC)\std_experimental_allocator_building_blocks_region.html \ $(DOC)\std_experimental_allocator_building_blocks_scoped_allocator.html \ $(DOC)\std_experimental_allocator_building_blocks_segregator.html \ $(DOC)\std_experimental_allocator_building_blocks_stats_collector.html \ $(DOC)\std_experimental_allocator_building_blocks.html \ $(DOC)\std_experimental_allocator_common.html \ $(DOC)\std_experimental_allocator_gc_allocator.html \ $(DOC)\std_experimental_allocator_mmap_allocator.html \ $(DOC)\std_experimental_allocator_showcase.html \ $(DOC)\std_experimental_allocator_typed.html \ $(DOC)\std_experimental_allocator.html \ $(DOC)\std_experimental_ndslice_iteration.html \ $(DOC)\std_experimental_ndslice_selection.html \ $(DOC)\std_experimental_ndslice_slice.html \ $(DOC)\std_experimental_ndslice.html \ $(DOC)\std_windows_charset.html \ $(DOC)\std_windows_registry.html \ $(DOC)\std_c_fenv.html \ $(DOC)\std_c_locale.html \ $(DOC)\std_c_math.html \ $(DOC)\std_c_process.html \ $(DOC)\std_c_stdarg.html \ $(DOC)\std_c_stddef.html \ $(DOC)\std_c_stdio.html \ $(DOC)\std_c_stdlib.html \ $(DOC)\std_c_string.html \ $(DOC)\std_c_time.html \ $(DOC)\std_c_wcharh.html \ $(DOC)\etc_c_curl.html \ $(DOC)\etc_c_sqlite3.html \ $(DOC)\etc_c_zlib.html \ $(DOC)\etc_c_odbc_sql.html \ $(DOC)\etc_c_odbc_sqlext.html \ $(DOC)\etc_c_odbc_sqltypes.html \ $(DOC)\etc_c_odbc_sqlucode.html \ $(DOC)\index.html $(LIB) : $(SRC_TO_COMPILE) \ $(ZLIB) $(DRUNTIMELIB) win32.mak win64.mak $(DMD) -lib -of$(LIB) -Xfphobos.json $(DFLAGS) $(SRC_TO_COMPILE) \ $(ZLIB) $(DRUNTIMELIB) UNITTEST_OBJS= \ unittest1.obj \ unittest2.obj \ unittest2a.obj \ unittest3.obj \ unittest3a.obj \ unittest3b.obj \ unittest4.obj \ unittest5.obj \ unittest6.obj \ unittest7.obj \ unittest8.obj unittest : $(LIB) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest1.obj $(SRC_STD_1_HEAVY) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest2.obj $(SRC_STD_RANGE) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest2.obj $(SRC_STD_NDSLICE) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest2a.obj $(SRC_STD_2a_HEAVY) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest3.obj $(SRC_STD_3) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest3a.obj $(SRC_STD_3a) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest3b.obj $(SRC_STD_3b) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest4.obj $(SRC_STD_4) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest5.obj $(SRC_STD_5_HEAVY) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest6.obj $(SRC_STD_6) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest7.obj $(SRC_STD_REST) $(DMD) $(UDFLAGS) -L/co -c -unittest -ofunittest8.obj $(SRC_TO_COMPILE_NOT_STD) $(DMD) $(UDFLAGS) -L/co -unittest unittest.d $(UNITTEST_OBJS) \ $(ZLIB) $(DRUNTIMELIB) .\unittest.exe #unittest : unittest.exe # unittest # #unittest.exe : unittest.d $(LIB) # $(DMD) -conf= unittest -g # dmc unittest.obj -g cov : $(SRC_TO_COMPILE) $(LIB) # $(DMD) -conf= -cov -unittest -ofcov.exe -main $(SRC_TO_COMPILE) $(LIB) # cov del *.lst $(DMD) -conf= -cov=83 -unittest -main -run std\stdio.d $(DMD) -conf= -cov=100 -unittest -main -run std\stdiobase.d $(DMD) -conf= -cov=95 -unittest -main -run std\string.d $(DMD) -conf= -cov=71 -unittest -main -run std\format.d $(DMD) -conf= -cov=83 -unittest -main -run std\file.d $(DMD) -conf= -cov=86 -unittest -main -run std\range\package.d $(DMD) -conf= -cov=95 -unittest -main -run std\array.d $(DMD) -conf= -cov=100 -unittest -main -run std\functional.d $(DMD) -conf= -cov=96 -unittest -main -run std\path.d $(DMD) -conf= -cov=41 -unittest -main -run std\outbuffer.d $(DMD) -conf= -cov=89 -unittest -main -run std\utf.d $(DMD) -conf= -cov=93 -unittest -main -run std\csv.d $(DMD) -conf= -cov=91 -unittest -main -run std\math.d $(DMD) -conf= -cov=95 -unittest -main -run std\complex.d $(DMD) -conf= -cov=70 -unittest -main -run std\numeric.d $(DMD) -conf= -cov=94 -unittest -main -run std\bigint.d $(DMD) -conf= -cov=95 -unittest -main -run std\bitmanip.d $(DMD) -conf= -cov=82 -unittest -main -run std\typecons.d $(DMD) -conf= -cov=44 -unittest -main -run std\uni.d $(DMD) -conf= -cov=91 -unittest -main -run std\base64.d $(DMD) -conf= -cov=100 -unittest -main -run std\ascii.d $(DMD) -conf= -cov=0 -unittest -main -run std\demangle.d $(DMD) -conf= -cov=57 -unittest -main -run std\uri.d $(DMD) -conf= -cov=51 -unittest -main -run std\mmfile.d $(DMD) -conf= -cov=95 -unittest -main -run std\getopt.d $(DMD) -conf= -cov=92 -unittest -main -run std\signals.d $(DMD) -conf= -cov=100 -unittest -main -run std\meta.d $(DMD) -conf= -cov=100 -unittest -main -run std\typetuple.d $(DMD) -conf= -cov=85 -unittest -main -run std\traits.d $(DMD) -conf= -cov=62 -unittest -main -run std\encoding.d $(DMD) -conf= -cov=61 -unittest -main -run std\xml.d $(DMD) -conf= -cov=79 -unittest -main -run std\random.d $(DMD) -conf= -cov=92 -unittest -main -run std\exception.d $(DMD) -conf= -cov=73 -unittest -main -run std\concurrency.d $(DMD) -conf= -cov=100 -unittest -main -run std\concurrencybase.d $(DMD) -conf= -cov=95 -unittest -main -run std\datetime.d $(DMD) -conf= -cov=96 -unittest -main -run std\uuid.d $(DMD) -conf= -cov=100 -unittest -main -run std\digest\crc.d $(DMD) -conf= -cov=55 -unittest -main -run std\digest\sha.d $(DMD) -conf= -cov=100 -unittest -main -run std\digest\md.d $(DMD) -conf= -cov=100 -unittest -main -run std\digest\ripemd.d $(DMD) -conf= -cov=75 -unittest -main -run std\digest\digest.d $(DMD) -conf= -cov=100 -unittest -main -run std\digest\hmac.d $(DMD) -conf= -cov=95 -unittest -main -run std\algorithm\package.d $(DMD) -conf= -cov=95 -unittest -main -run std\algorithm\comparison.d $(DMD) -conf= -cov=95 -unittest -main -run std\algorithm\iteration.d $(DMD) -conf= -cov=95 -unittest -main -run std\algorithm\mutation.d $(DMD) -conf= -cov=95 -unittest -main -run std\algorithm\searching.d $(DMD) -conf= -cov=95 -unittest -main -run std\algorithm\setops.d $(DMD) -conf= -cov=95 -unittest -main -run std\algorithm\sorting.d $(DMD) -conf= -cov=83 -unittest -main -run std\variant.d $(DMD) -conf= -cov=58 -unittest -main -run std\zlib.d $(DMD) -conf= -cov=54 -unittest -main -run std\stream.d $(DMD) -conf= -cov=53 -unittest -main -run std\socket.d $(DMD) -conf= -cov=0 -unittest -main -run std\socketstream.d $(DMD) -conf= -cov=95 -unittest -main -run std\container\array.d $(DMD) -conf= -cov=68 -unittest -main -run std\container\binaryheap.d $(DMD) -conf= -cov=91 -unittest -main -run std\container\dlist.d $(DMD) -conf= -cov=93 -unittest -main -run std\container\rbtree.d $(DMD) -conf= -cov=92 -unittest -main -run std\container\slist.d $(DMD) -conf= -cov=100 -unittest -main -run std\container\util.d $(DMD) -conf= -cov=100 -unittest -main -run std\container\package.d $(DMD) -conf= -cov=90 -unittest -main -run std\conv.d $(DMD) -conf= -cov=0 -unittest -main -run std\zip.d $(DMD) -conf= -cov=92 -unittest -main -run std\cstream.d $(DMD) -conf= -cov=77 -unittest -main -run std\regex\tests.d $(DMD) -conf= -cov=92 -unittest -main -run std\json.d $(DMD) -conf= -cov=87 -unittest -main -run std\parallelism.d $(DMD) -conf= -cov=50 -unittest -main -run std\mathspecial.d $(DMD) -conf= -cov=71 -unittest -main -run std\process.d $(DMD) -conf= -cov=70 -unittest -main -run std\net\isemail.d $(DMD) -conf= -cov=2 -unittest -main -run std\net\curl.d $(DMD) -conf= -cov=60 -unittest -main -run std\windows\registry.d $(DMD) -conf= -cov=0 -unittest -main -run std\internal\digest\sha_SSSE3.d $(DMD) -conf= -cov=50 -unittest -main -run std\internal\math\biguintcore.d $(DMD) -conf= -cov=75 -unittest -main -run std\internal\math\biguintnoasm.d # $(DMD) -conf= -cov -unittest -main -run std\internal\math\biguintx86.d $(DMD) -conf= -cov=94 -unittest -main -run std\internal\math\gammafunction.d $(DMD) -conf= -cov=92 -unittest -main -run std\internal\math\errorfunction.d $(DMD) -conf= -cov=31 -unittest -main -run std\internal\windows\advapi32.d $(DMD) -conf= -cov=58 -unittest -main -run etc\c\zlib.d html : $(DOCS) changelog.html: changelog.dd $(DMD) -Dfchangelog.html changelog.dd ###################################################### $(ZLIB): $(SRC_ZLIB) cd etc\c\zlib $(MAKE) -f win$(MODEL).mak zlib.lib CC=$(CC) LIB=$(AR) cd ..\..\.. ################## DOCS #################################### DDOCFLAGS=$(DFLAGS) -version=StdDdoc $(DOC)\object.html : $(STDDOC) $(DRUNTIME)\src\object.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\object.html $(STDDOC) $(DRUNTIME)\src\object.d -I$(DRUNTIME)\src\ $(DOC)\index.html : $(STDDOC) index.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\index.html $(STDDOC) index.d $(DOC)\core_atomic.html : $(STDDOC) $(DRUNTIME)\src\core\atomic.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_atomic.html $(STDDOC) $(DRUNTIME)\src\core\atomic.d -I$(DRUNTIME)\src\ $(DOC)\core_bitop.html : $(STDDOC) $(DRUNTIME)\src\core\bitop.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_bitop.html $(STDDOC) $(DRUNTIME)\src\core\bitop.d -I$(DRUNTIME)\src\ $(DOC)\core_exception.html : $(STDDOC) $(DRUNTIME)\src\core\exception.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_exception.html $(STDDOC) $(DRUNTIME)\src\core\exception.d -I$(DRUNTIME)\src\ $(DOC)\core_memory.html : $(STDDOC) $(DRUNTIME)\src\core\memory.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_memory.html $(STDDOC) $(DRUNTIME)\src\core\memory.d -I$(DRUNTIME)\src\ $(DOC)\core_runtime.html : $(STDDOC) $(DRUNTIME)\src\core\runtime.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_runtime.html $(STDDOC) $(DRUNTIME)\src\core\runtime.d -I$(DRUNTIME)\src\ $(DOC)\core_simd.html : $(STDDOC) $(DRUNTIME)\src\core\simd.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_simd.html $(STDDOC) $(DRUNTIME)\src\core\simd.d -I$(DRUNTIME)\src\ $(DOC)\core_time.html : $(STDDOC) $(DRUNTIME)\src\core\time.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_time.html $(STDDOC) $(DRUNTIME)\src\core\time.d -I$(DRUNTIME)\src\ $(DOC)\core_thread.html : $(STDDOC) $(DRUNTIME)\src\core\thread.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_thread.html $(STDDOC) $(DRUNTIME)\src\core\thread.d -I$(DRUNTIME)\src\ $(DOC)\core_vararg.html : $(STDDOC) $(DRUNTIME)\src\core\vararg.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_vararg.html $(STDDOC) $(DRUNTIME)\src\core\vararg.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_barrier.html : $(STDDOC) $(DRUNTIME)\src\core\sync\barrier.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_barrier.html $(STDDOC) $(DRUNTIME)\src\core\sync\barrier.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_condition.html : $(STDDOC) $(DRUNTIME)\src\core\sync\condition.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_condition.html $(STDDOC) $(DRUNTIME)\src\core\sync\condition.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_config.html : $(STDDOC) $(DRUNTIME)\src\core\sync\config.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_config.html $(STDDOC) $(DRUNTIME)\src\core\sync\config.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_exception.html : $(STDDOC) $(DRUNTIME)\src\core\sync\exception.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_exception.html $(STDDOC) $(DRUNTIME)\src\core\sync\exception.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_mutex.html : $(STDDOC) $(DRUNTIME)\src\core\sync\mutex.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_mutex.html $(STDDOC) $(DRUNTIME)\src\core\sync\mutex.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_rwmutex.html : $(STDDOC) $(DRUNTIME)\src\core\sync\rwmutex.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_rwmutex.html $(STDDOC) $(DRUNTIME)\src\core\sync\rwmutex.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_semaphore.html : $(STDDOC) $(DRUNTIME)\src\core\sync\semaphore.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_semaphore.html $(STDDOC) $(DRUNTIME)\src\core\sync\semaphore.d -I$(DRUNTIME)\src\ $(DOC)\std_algorithm.html : $(STDDOC) std\algorithm\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm.html $(STDDOC) std\algorithm\package.d $(DOC)\std_algorithm_comparison.html : $(STDDOC) std\algorithm\comparison.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_comparison.html $(STDDOC) std\algorithm\comparison.d $(DOC)\std_algorithm_iteration.html : $(STDDOC) std\algorithm\iteration.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_iteration.html $(STDDOC) std\algorithm\iteration.d $(DOC)\std_algorithm_mutation.html : $(STDDOC) std\algorithm\mutation.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_mutation.html $(STDDOC) std\algorithm\mutation.d $(DOC)\std_algorithm_searching.html : $(STDDOC) std\algorithm\searching.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_searching.html $(STDDOC) std\algorithm\searching.d $(DOC)\std_algorithm_setops.html : $(STDDOC) std\algorithm\setops.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_setops.html $(STDDOC) std\algorithm\setops.d $(DOC)\std_algorithm_sorting.html : $(STDDOC) std\algorithm\sorting.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_sorting.html $(STDDOC) std\algorithm\sorting.d $(DOC)\std_array.html : $(STDDOC) std\array.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_array.html $(STDDOC) std\array.d $(DOC)\std_ascii.html : $(STDDOC) std\ascii.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_ascii.html $(STDDOC) std\ascii.d $(DOC)\std_base64.html : $(STDDOC) std\base64.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_base64.html $(STDDOC) std\base64.d $(DOC)\std_bigint.html : $(STDDOC) std\bigint.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_bigint.html $(STDDOC) std\bigint.d $(DOC)\std_bitmanip.html : $(STDDOC) std\bitmanip.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_bitmanip.html $(STDDOC) std\bitmanip.d $(DOC)\std_concurrency.html : $(STDDOC) std\concurrency.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_concurrency.html $(STDDOC) std\concurrency.d $(DOC)\std_compiler.html : $(STDDOC) std\compiler.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_compiler.html $(STDDOC) std\compiler.d $(DOC)\std_complex.html : $(STDDOC) std\complex.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_complex.html $(STDDOC) std\complex.d $(DOC)\std_conv.html : $(STDDOC) std\conv.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_conv.html $(STDDOC) std\conv.d $(DOC)\std_container_array.html : $(STDDOC) std\container\array.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_array.html $(STDDOC) std\container\array.d $(DOC)\std_container_binaryheap.html : $(STDDOC) std\container\binaryheap.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_binaryheap.html $(STDDOC) std\container\binaryheap.d $(DOC)\std_container_dlist.html : $(STDDOC) std\container\dlist.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_dlist.html $(STDDOC) std\container\dlist.d $(DOC)\std_container_rbtree.html : $(STDDOC) std\container\rbtree.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_rbtree.html $(STDDOC) std\container\rbtree.d $(DOC)\std_container_slist.html : $(STDDOC) std\container\slist.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_slist.html $(STDDOC) std\container\slist.d $(DOC)\std_container_util.html : $(STDDOC) std\container\util.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_util.html $(STDDOC) std\container\util.d $(DOC)\std_container.html : $(STDDOC) std\container\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container.html $(STDDOC) std\container\package.d $(DOC)\std_range.html : $(STDDOC) std\range\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_range.html $(STDDOC) std\range\package.d $(DOC)\std_range_primitives.html : $(STDDOC) std\range\primitives.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_range_primitives.html $(STDDOC) std\range\primitives.d $(DOC)\std_range_interfaces.html : $(STDDOC) std\range\interfaces.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_range_interfaces.html $(STDDOC) std\range\interfaces.d $(DOC)\std_cstream.html : $(STDDOC) std\cstream.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_cstream.html $(STDDOC) std\cstream.d $(DOC)\std_csv.html : $(STDDOC) std\csv.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_csv.html $(STDDOC) std\csv.d $(DOC)\std_datetime.html : $(STDDOC) std\datetime.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_datetime.html $(STDDOC) std\datetime.d $(DOC)\std_demangle.html : $(STDDOC) std\demangle.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_demangle.html $(STDDOC) std\demangle.d $(DOC)\std_exception.html : $(STDDOC) std\exception.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_exception.html $(STDDOC) std\exception.d $(DOC)\std_file.html : $(STDDOC) std\file.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_file.html $(STDDOC) std\file.d $(DOC)\std_format.html : $(STDDOC) std\format.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_format.html $(STDDOC) std\format.d $(DOC)\std_functional.html : $(STDDOC) std\functional.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_functional.html $(STDDOC) std\functional.d $(DOC)\std_getopt.html : $(STDDOC) std\getopt.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_getopt.html $(STDDOC) std\getopt.d $(DOC)\std_json.html : $(STDDOC) std\json.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_json.html $(STDDOC) std\json.d $(DOC)\std_math.html : $(STDDOC) std\math.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_math.html $(STDDOC) std\math.d $(DOC)\std_meta.html : $(STDDOC) std\meta.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_meta.html $(STDDOC) std\meta.d $(DOC)\std_mathspecial.html : $(STDDOC) std\mathspecial.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_mathspecial.html $(STDDOC) std\mathspecial.d $(DOC)\std_mmfile.html : $(STDDOC) std\mmfile.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_mmfile.html $(STDDOC) std\mmfile.d $(DOC)\std_numeric.html : $(STDDOC) std\numeric.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_numeric.html $(STDDOC) std\numeric.d $(DOC)\std_outbuffer.html : $(STDDOC) std\outbuffer.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_outbuffer.html $(STDDOC) std\outbuffer.d $(DOC)\std_parallelism.html : $(STDDOC) std\parallelism.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_parallelism.html $(STDDOC) std\parallelism.d $(DOC)\std_path.html : $(STDDOC) std\path.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_path.html $(STDDOC) std\path.d $(DOC)\std_process.html : $(STDDOC) std\process.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_process.html $(STDDOC) std\process.d $(DOC)\std_random.html : $(STDDOC) std\random.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_random.html $(STDDOC) std\random.d $(DOC)\std_range.html : $(STDDOC) std\range\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_range.html $(STDDOC) std\range\package.d $(DOC)\std_regex.html : $(STDDOC) std\regex\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_regex.html $(STDDOC) std\regex\package.d $(DOC)\std_signals.html : $(STDDOC) std\signals.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_signals.html $(STDDOC) std\signals.d $(DOC)\std_socket.html : $(STDDOC) std\socket.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_socket.html $(STDDOC) std\socket.d $(DOC)\std_socketstream.html : $(STDDOC) std\socketstream.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_socketstream.html $(STDDOC) std\socketstream.d $(DOC)\std_stdint.html : $(STDDOC) std\stdint.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_stdint.html $(STDDOC) std\stdint.d $(DOC)\std_stdio.html : $(STDDOC) std\stdio.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_stdio.html $(STDDOC) std\stdio.d $(DOC)\std_stream.html : $(STDDOC) std\stream.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_stream.html $(STDDOC) std\stream.d $(DOC)\std_string.html : $(STDDOC) std\string.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_string.html $(STDDOC) std\string.d $(DOC)\std_system.html : $(STDDOC) std\system.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_system.html $(STDDOC) std\system.d $(DOC)\std_traits.html : $(STDDOC) std\traits.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_traits.html $(STDDOC) std\traits.d $(DOC)\std_typecons.html : $(STDDOC) std\typecons.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_typecons.html $(STDDOC) std\typecons.d $(DOC)\std_typetuple.html : $(STDDOC) std\typetuple.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_typetuple.html $(STDDOC) std\typetuple.d $(DOC)\std_uni.html : $(STDDOC) std\uni.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_uni.html $(STDDOC) std\uni.d $(DOC)\std_uri.html : $(STDDOC) std\uri.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_uri.html $(STDDOC) std\uri.d $(DOC)\std_utf.html : $(STDDOC) std\utf.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_utf.html $(STDDOC) std\utf.d $(DOC)\std_uuid.html : $(STDDOC) std\uuid.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_uuid.html $(STDDOC) std\uuid.d $(DOC)\std_variant.html : $(STDDOC) std\variant.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_variant.html $(STDDOC) std\variant.d $(DOC)\std_xml.html : $(STDDOC) std\xml.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_xml.html $(STDDOC) std\xml.d $(DOC)\std_encoding.html : $(STDDOC) std\encoding.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_encoding.html $(STDDOC) std\encoding.d $(DOC)\std_zip.html : $(STDDOC) std\zip.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_zip.html $(STDDOC) std\zip.d $(DOC)\std_zlib.html : $(STDDOC) std\zlib.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_zlib.html $(STDDOC) std\zlib.d $(DOC)\std_net_isemail.html : $(STDDOC) std\net\isemail.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_net_isemail.html $(STDDOC) std\net\isemail.d $(DOC)\std_net_curl.html : $(STDDOC) std\net\curl.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_net_curl.html $(STDDOC) std\net\curl.d $(DOC)\std_experimental_logger_core.html : $(STDDOC) std\experimental\logger\core.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger_core.html $(STDDOC) std\experimental\logger\core.d $(DOC)\std_experimental_logger_multilogger.html : $(STDDOC) std\experimental\logger\multilogger.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger_multilogger.html $(STDDOC) std\experimental\logger\multilogger.d $(DOC)\std_experimental_logger_filelogger.html : $(STDDOC) std\experimental\logger\filelogger.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger_filelogger.html $(STDDOC) std\experimental\logger\filelogger.d $(DOC)\std_experimental_logger_nulllogger.html : $(STDDOC) std\experimental\logger\nulllogger.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger_nulllogger.html $(STDDOC) std\experimental\logger\nulllogger.d $(DOC)\std_experimental_logger.html : $(STDDOC) std\experimental\logger\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger.html $(STDDOC) std\experimental\logger\package.d $(DOC)\std_experimental_allocator_building_blocks_affix_allocator.html : $(STDDOC) std\experimental\allocator\building_blocks\affix_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_affix_allocator.html \ $(STDDOC) std\experimental\allocator\building_blocks\affix_allocator.d $(DOC)\std_experimental_allocator_building_blocks_allocator_list.html : $(STDDOC) std\experimental\allocator\building_blocks\allocator_list.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_allocator_list.html \ $(STDDOC) std\experimental\allocator\building_blocks\allocator_list.d $(DOC)\std_experimental_allocator_building_blocks_bitmapped_block.html : $(STDDOC) std\experimental\allocator\building_blocks\bitmapped_block.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_bitmapped_block.html \ $(STDDOC) std\experimental\allocator\building_blocks\bitmapped_block.d $(DOC)\std_experimental_allocator_building_blocks_bucketizer.html : $(STDDOC) std\experimental\allocator\building_blocks\bucketizer.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_bucketizer.html \ $(STDDOC) std\experimental\allocator\building_blocks\bucketizer.d $(DOC)\std_experimental_allocator_building_blocks_fallback_allocator.html : $(STDDOC) std\experimental\allocator\building_blocks\fallback_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_fallback_allocator.html \ $(STDDOC) std\experimental\allocator\building_blocks\fallback_allocator.d $(DOC)\std_experimental_allocator_building_blocks_free_list.html : $(STDDOC) std\experimental\allocator\building_blocks\free_list.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_free_list.html \ $(STDDOC) std\experimental\allocator\building_blocks\free_list.d $(DOC)\std_experimental_allocator_building_blocks_free_tree.html : $(STDDOC) std\experimental\allocator\building_blocks\free_tree.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_free_tree.html \ $(STDDOC) std\experimental\allocator\building_blocks\free_tree.d $(DOC)\std_experimental_allocator_building_blocks_kernighan_ritchie.html : $(STDDOC) std\experimental\allocator\building_blocks\kernighan_ritchie.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_kernighan_ritchie.html \ $(STDDOC) std\experimental\allocator\building_blocks\kernighan_ritchie.d $(DOC)\std_experimental_allocator_building_blocks_null_allocator.html : $(STDDOC) std\experimental\allocator\building_blocks\null_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_null_allocator.html \ $(STDDOC) std\experimental\allocator\building_blocks\null_allocator.d $(DOC)\std_experimental_allocator_building_blocks_quantizer.html : $(STDDOC) std\experimental\allocator\building_blocks\quantizer.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_quantizer.html \ $(STDDOC) std\experimental\allocator\building_blocks\quantizer.d $(DOC)\std_experimental_allocator_building_blocks_region.html : $(STDDOC) std\experimental\allocator\building_blocks\region.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_region.html \ $(STDDOC) std\experimental\allocator\building_blocks\region.d $(DOC)\std_experimental_allocator_building_blocks_scoped_allocator.html : $(STDDOC) std\experimental\allocator\building_blocks\scoped_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_scoped_allocator.html \ $(STDDOC) std\experimental\allocator\building_blocks\scoped_allocator.d $(DOC)\std_experimental_allocator_building_blocks_segregator.html : $(STDDOC) std\experimental\allocator\building_blocks\segregator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_segregator.html \ $(STDDOC) std\experimental\allocator\building_blocks\segregator.d $(DOC)\std_experimental_allocator_building_blocks_stats_collector.html : $(STDDOC) std\experimental\allocator\building_blocks\stats_collector.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_stats_collector.html \ $(STDDOC) std\experimental\allocator\building_blocks\stats_collector.d $(DOC)\std_experimental_allocator_building_blocks.html : $(STDDOC) std\experimental\allocator\building_blocks\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks.html \ $(STDDOC) std\experimental\allocator\building_blocks\package.d $(DOC)\std_experimental_allocator_common.html : $(STDDOC) std\experimental\allocator\common.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_common.html $(STDDOC) std\experimental\allocator\common.d $(DOC)\std_experimental_allocator_gc_allocator.html : $(STDDOC) std\experimental\allocator\gc_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_gc_allocator.html $(STDDOC) std\experimental\allocator\gc_allocator.d $(DOC)\std_experimental_allocator_mallocator.html : $(STDDOC) std\experimental\allocator\mallocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_mallocator.html $(STDDOC) std\experimental\allocator\mallocator.d $(DOC)\std_experimental_allocator_mmap_allocator.html : $(STDDOC) std\experimental\allocator\mmap_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_mmap_allocator.html $(STDDOC) std\experimental\allocator\mmap_allocator.d $(DOC)\std_experimental_allocator_showcase.html : $(STDDOC) std\experimental\allocator\showcase.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_showcase.html $(STDDOC) std\experimental\allocator\showcase.d $(DOC)\std_experimental_allocator_typed.html : $(STDDOC) std\experimental\allocator\typed.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_typed.html $(STDDOC) std\experimental\allocator\typed.d $(DOC)\std_experimental_allocator.html : $(STDDOC) std\experimental\allocator\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator.html $(STDDOC) std\experimental\allocator\package.d $(DOC)\std_experimental_ndslice_iteration.html : $(STDDOC) std\experimental\ndslice\iteration.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_ndslice_iteration.html $(STDDOC) std\experimental\ndslice\iteration.d $(DOC)\std_experimental_ndslice_selection.html : $(STDDOC) std\experimental\ndslice\selection.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_ndslice_selection.html $(STDDOC) std\experimental\ndslice\selection.d $(DOC)\std_experimental_ndslice_slice.html : $(STDDOC) std\experimental\ndslice\slice.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_ndslice_slice.html $(STDDOC) std\experimental\ndslice\slice.d $(DOC)\std_experimental_ndslice.html : $(STDDOC) std\experimental\ndslice\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_ndslice.html $(STDDOC) std\experimental\ndslice\package.d $(DOC)\std_digest_crc.html : $(STDDOC) std\digest\crc.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_crc.html $(STDDOC) std\digest\crc.d $(DOC)\std_digest_sha.html : $(STDDOC) std\digest\sha.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_sha.html $(STDDOC) std\digest\sha.d $(DOC)\std_digest_md.html : $(STDDOC) std\digest\md.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_md.html $(STDDOC) std\digest\md.d $(DOC)\std_digest_ripemd.html : $(STDDOC) std\digest\ripemd.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_ripemd.html $(STDDOC) std\digest\ripemd.d $(DOC)\std_digest_digest.html : $(STDDOC) std\digest\digest.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_digest.html $(STDDOC) std\digest\digest.d $(DOC)\std_digest_hmac.html : $(STDDOC) std\digest\hmac.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_hmac.html $(STDDOC) std\digest\hmac.d $(DOC)\std_windows_charset.html : $(STDDOC) std\windows\charset.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_windows_charset.html $(STDDOC) std\windows\charset.d $(DOC)\std_windows_registry.html : $(STDDOC) std\windows\registry.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_windows_registry.html $(STDDOC) std\windows\registry.d $(DOC)\std_c_fenv.html : $(STDDOC) std\c\fenv.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_fenv.html $(STDDOC) std\c\fenv.d $(DOC)\std_c_locale.html : $(STDDOC) std\c\locale.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_locale.html $(STDDOC) std\c\locale.d $(DOC)\std_c_math.html : $(STDDOC) std\c\math.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_math.html $(STDDOC) std\c\math.d $(DOC)\std_c_process.html : $(STDDOC) std\c\process.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_process.html $(STDDOC) std\c\process.d $(DOC)\std_c_stdarg.html : $(STDDOC) std\c\stdarg.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_stdarg.html $(STDDOC) std\c\stdarg.d $(DOC)\std_c_stddef.html : $(STDDOC) std\c\stddef.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_stddef.html $(STDDOC) std\c\stddef.d $(DOC)\std_c_stdio.html : $(STDDOC) std\c\stdio.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_stdio.html $(STDDOC) std\c\stdio.d $(DOC)\std_c_stdlib.html : $(STDDOC) std\c\stdlib.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_stdlib.html $(STDDOC) std\c\stdlib.d $(DOC)\std_c_string.html : $(STDDOC) std\c\string.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_string.html $(STDDOC) std\c\string.d $(DOC)\std_c_time.html : $(STDDOC) std\c\time.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_time.html $(STDDOC) std\c\time.d $(DOC)\std_c_wcharh.html : $(STDDOC) std\c\wcharh.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_wcharh.html $(STDDOC) std\c\wcharh.d $(DOC)\etc_c_curl.html : $(STDDOC) etc\c\curl.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_curl.html $(STDDOC) etc\c\curl.d $(DOC)\etc_c_sqlite3.html : $(STDDOC) etc\c\sqlite3.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_sqlite3.html $(STDDOC) etc\c\sqlite3.d $(DOC)\etc_c_zlib.html : $(STDDOC) etc\c\zlib.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_zlib.html $(STDDOC) etc\c\zlib.d $(DOC)\etc_c_odbc_sql.html : $(STDDOC) etc\c\odbc\sql.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sql.html $(STDDOC) etc\c\odbc\sql.d $(DOC)\etc_c_odbc_sqlext.html : $(STDDOC) etc\c\odbc\sqlext.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sqlext.html $(STDDOC) etc\c\odbc\sqlext.d $(DOC)\etc_c_odbc_sqltypes.html : $(STDDOC) etc\c\odbc\sqltypes.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sqltypes.html $(STDDOC) etc\c\odbc\sqltypes.d $(DOC)\etc_c_odbc_sqlucode.html : $(STDDOC) etc\c\odbc\sqlucode.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sqlucode.html $(STDDOC) etc\c\odbc\sqlucode.d $(DOC)\etc_c_odbc_sql.html : $(STDDOC) etc\c\odbc\sql.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sql.html $(STDDOC) etc\c\odbc\sql.d ###################################################### zip: del phobos.zip zip32 -r phobos.zip . -x .git\* -x \*.lib -x \*.obj phobos.zip : zip clean: cd etc\c\zlib $(MAKE) -f win$(MODEL).mak clean cd ..\..\.. del $(DOCS) del $(UNITTEST_OBJS) unittest.obj unittest.exe del $(LIB) del phobos.json cleanhtml: del $(DOCS) install: phobos.zip $(CP) phobos.lib phobos64.lib $(DIR)\windows\lib $(CP) $(DRUNTIME)\lib\gcstub.obj $(DRUNTIME)\lib\gcstub64.obj $(DIR)\windows\lib +rd/s/q $(DIR)\html\d\phobos +md $(DIR)\html\d\phobos $(CP) $(DOCS) $(DIR)\html\d\phobos $(CP) $(DOC)\index.html $(DIR)\html\d\phobos\index.html +rd/s/q $(DIR)\src\phobos unzip -o phobos.zip -d $(DIR)\src\phobos auto-tester-build: targets auto-tester-test: unittest ldc-1.1.0-beta3-src/runtime/phobos/unittest.d0000664000175000017500000000734312776215007017147 0ustar kaikai// Written in the D programming language. /** * This test program pulls in all the library modules in order to run the unit * tests on them. Then, it prints out the arguments passed to main(). * * Copyright: Copyright Digital Mars 2000 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * * Copyright Digital Mars 2000 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ public import std.base64; public import std.compiler; public import std.concurrency; public import std.conv; public import std.container; public import std.cstream; public import std.datetime; public import std.demangle; public import std.file; public import std.format; public import std.getopt; public import std.math; public import std.mathspecial; public import std.mmfile; public import std.outbuffer; public import std.parallelism; public import std.path; public import std.process; public import std.random; public import std.regex; public import std.signals; //public import std.slist; public import std.socket; public import std.socketstream; public import std.stdint; public import std.stdio; public import std.stream; public import std.string; public import std.system; public import std.traits; public import std.typetuple; public import std.uni; public import std.uri; public import std.utf; public import std.uuid; public import std.variant; public import std.zip; public import std.zlib; public import std.net.isemail; public import std.net.curl; public import std.digest.digest; public import std.digest.crc; public import std.digest.sha; public import std.digest.md; public import std.digest.hmac; int main(string[] args) { // Bring in unit test for module by referencing function in it cast(void)cmp("foo", "bar"); // string cast(void)filenameCharCmp('a', 'b'); // path cast(void)isNaN(1.0); // math std.conv.to!double("1.0"); // std.conv OutBuffer b = new OutBuffer(); // outbuffer auto r = regex(""); // regex uint ranseed = std.random.unpredictableSeed; thisTid; int[] a; import std.algorithm : sort, reverse; reverse(a); // adi sort(a); // qsort Clock.currTime(); // datetime Exception e = new ReadException(""); // stream din.eof(); // cstream cast(void)isValidDchar(cast(dchar)0); // utf std.uri.ascii2hex(0); // uri std.zlib.adler32(0,null); // D.zlib auto t = task!cmp("foo", "bar"); // parallelism creal c = 3.0 + 4.0i; c = sqrt(c); assert(c.re == 2); assert(c.im == 1); printf("args.length = %d\n", args.length); for (int i = 0; i < args.length; i++) printf("args[%d] = '%.*s'\n", i, args[i].length, args[i].ptr); int[3] x; x[0] = 3; x[1] = 45; x[2] = -1; sort(x[]); assert(x[0] == -1); assert(x[1] == 3); assert(x[2] == 45); cast(void)std.math.sin(3.0); cast(void)std.mathspecial.gamma(6.2); std.demangle.demangle("hello"); cast(void)std.uni.isAlpha('A'); std.file.exists("foo"); foreach_reverse (dchar d; "hello"c) { } foreach_reverse (k, dchar d; "hello"c) { } std.signals.linkin(); bool isEmail = std.net.isemail.isEmail("abc"); auto http = std.net.curl.HTTP("dlang.org"); auto uuid = randomUUID(); auto md5 = md5Of("hello"); auto sha1 = sha1Of("hello"); auto crc = crc32Of("hello"); auto string = toHexString(crc); puts("Success!"); return 0; } ldc-1.1.0-beta3-src/runtime/phobos/project.ddoc0000664000175000017500000000001712776215007017413 0ustar kaikaiPROJECT=phobos ldc-1.1.0-beta3-src/runtime/phobos/CONTRIBUTING.md0000664000175000017500000000114612776215007017347 0ustar kaikaiGuidelines for Contributing =========================== Welcome to the D community and thanks for your interest in contributing! To get started, please read the [Starting as a Contributor](http://wiki.dlang.org/Starting_as_a_Contributor) article on the D Wiki. More Links ---------- * Fork [on Github](https://github.com/D-Programming-Language/phobos) * Use our [Bugzilla bug tracker](http://d.puremagic.com/issues/) * Follow the [Styleguide](http://dlang.org/dstyle.html) * Participate in [our forum](http://forum.dlang.org/) * Review Phobos additions in the [Review Queue](http://wiki.dlang.org/Review_Queue).ldc-1.1.0-beta3-src/runtime/phobos/etc/0000775000175000017500000000000012776215007015667 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/etc/c/0000775000175000017500000000000012776215007016111 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/0000775000175000017500000000000012776215007017051 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/win32.mak0000664000175000017500000000374212776215007020513 0ustar kaikai# Makefile for zlib CC=dmc LD=link LIB=lib CFLAGS=-o -DNO_snprintf LDFLAGS= O=.obj # variables OBJS = adler32$(O) compress$(O) crc32$(O) deflate$(O) gzclose$(O) gzlib$(O) gzread$(O) \ gzwrite$(O) infback$(O) inffast$(O) inflate$(O) inftrees$(O) trees$(O) uncompr$(O) zutil$(O) all: zlib.lib example.exe minigzip.exe adler32.obj: zutil.h zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c zutil.obj: zutil.h zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c gzclose.obj: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c gzlib.obj: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c gzread.obj: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c gzwrite.obj: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c compress.obj: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c example.obj: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c minigzip.obj: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c uncompr.obj: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c crc32.obj: zutil.h zlib.h zconf.h crc32.h $(CC) -c $(CFLAGS) $*.c deflate.obj: deflate.h zutil.h zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c infback.obj: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h $(CC) -c $(CFLAGS) $*.c inflate.obj: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h $(CC) -c $(CFLAGS) $*.c inffast.obj: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h $(CC) -c $(CFLAGS) $*.c inftrees.obj: zutil.h zlib.h zconf.h inftrees.h $(CC) -c $(CFLAGS) $*.c trees.obj: deflate.h zutil.h zlib.h zconf.h trees.h $(CC) -c $(CFLAGS) $*.c example.obj: example.c zlib.h zconf.h $(CC) -c $(cvarsdll) $(CFLAGS) $*.c minigzip.obj: minigzip.c zlib.h zconf.h $(CC) -c $(cvarsdll) $(CFLAGS) $*.c zlib.lib: $(OBJS) $(LIB) -c zlib.lib $(OBJS) example.exe: example.obj zlib.lib $(LD) $(LDFLAGS) example.obj zlib.lib minigzip.exe: minigzip.obj zlib.lib $(LD) $(LDFLAGS) minigzip.obj zlib.lib test: example.exe minigzip.exe example echo hello world | minigzip | minigzip -d clean: del *.obj del *.exe del *.dll del *.lib del *.lst del foo.gz ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/compress.c0000664000175000017500000000474112776215007021056 0ustar kaikai/* compress.c -- compress a memory buffer * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; int level; { z_stream stream; int err; stream.next_in = (z_const Bytef *)source; stream.avail_in = (uInt)sourceLen; #ifdef MAXSEG_64K /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; #endif stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = deflateInit(&stream, level); if (err != Z_OK) return err; err = deflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { deflateEnd(&stream); return err == Z_OK ? Z_BUF_ERROR : err; } *destLen = stream.total_out; err = deflateEnd(&stream); return err; } /* =========================================================================== */ int ZEXPORT compress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } /* =========================================================================== If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ uLong ZEXPORT compressBound (sourceLen) uLong sourceLen; { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/inflate.c0000664000175000017500000015041012776215007020640 0ustar kaikai/* inflate.c -- zlib decompression * Copyright (C) 1995-2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 * - First version -- complete rewrite of inflate to simplify code, avoid * creation of window when not needed, minimize use of window when it is * needed, make inffast.c even faster, implement gzip decoding, and to * improve code readability and style over the previous zlib inflate code * * 1.2.beta1 25 Nov 2002 * - Use pointers for available input and output checking in inffast.c * - Remove input and output counters in inffast.c * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 * - Remove unnecessary second byte pull from length extra in inffast.c * - Unroll direct copy to three copies per loop in inffast.c * * 1.2.beta2 4 Dec 2002 * - Change external routine names to reduce potential conflicts * - Correct filename to inffixed.h for fixed tables in inflate.c * - Make hbuf[] unsigned char to match parameter type in inflate.c * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) * to avoid negation problem on Alphas (64 bit) in inflate.c * * 1.2.beta3 22 Dec 2002 * - Add comments on state->bits assertion in inffast.c * - Add comments on op field in inftrees.h * - Fix bug in reuse of allocated window after inflateReset() * - Remove bit fields--back to byte structure for speed * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths * - Change post-increments to pre-increments in inflate_fast(), PPC biased? * - Add compile time option, POSTINC, to use post-increments instead (Intel?) * - Make MATCH copy in inflate() much faster for when inflate_fast() not used * - Use local copies of stream next and avail values, as well as local bit * buffer and bit count in inflate()--for speed when inflate_fast() not used * * 1.2.beta4 1 Jan 2003 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings * - Move a comment on output buffer sizes from inffast.c to inflate.c * - Add comments in inffast.c to introduce the inflate_fast() routine * - Rearrange window copies in inflate_fast() for speed and simplification * - Unroll last copy for window match in inflate_fast() * - Use local copies of window variables in inflate_fast() for speed * - Pull out common wnext == 0 case for speed in inflate_fast() * - Make op and len in inflate_fast() unsigned for consistency * - Add FAR to lcode and dcode declarations in inflate_fast() * - Simplified bad distance check in inflate_fast() * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new * source file infback.c to provide a call-back interface to inflate for * programs like gzip and unzip -- uses window as output buffer to avoid * window copying * * 1.2.beta5 1 Jan 2003 * - Improved inflateBack() interface to allow the caller to provide initial * input in strm. * - Fixed stored blocks bug in inflateBack() * * 1.2.beta6 4 Jan 2003 * - Added comments in inffast.c on effectiveness of POSTINC * - Typecasting all around to reduce compiler warnings * - Changed loops from while (1) or do {} while (1) to for (;;), again to * make compilers happy * - Changed type of window in inflateBackInit() to unsigned char * * * 1.2.beta7 27 Jan 2003 * - Changed many types to unsigned or unsigned short to avoid warnings * - Added inflateCopy() function * * 1.2.0 9 Mar 2003 * - Changed inflateBack() interface to provide separate opaque descriptors * for the in() and out() functions * - Changed inflateBack() argument and in_func typedef to swap the length * and buffer address return values for the input function * - Check next_in and next_out for Z_NULL on entry to inflate() * * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, unsigned copy)); #ifdef BUILDFIXED void makefixed OF((void)); #endif local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); int ZEXPORT inflateResetKeep(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; if (state->wrap) /* to support ill-conceived Java test suite */ strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int ZEXPORT inflateReset(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; state->wnext = 0; return inflateResetKeep(strm); } int ZEXPORT inflateReset2(strm, windowBits) z_streamp strm; int windowBits; { int wrap; struct inflate_state FAR *state; /* get the state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 1; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; #endif } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE(strm, state->window); state->window = Z_NULL; } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) z_streamp strm; int windowBits; const char *version; int stream_size; { int ret; struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->window = Z_NULL; ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int ZEXPORT inflateInit_(strm, version, stream_size) z_streamp strm; const char *version; int stream_size; { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int ZEXPORT inflatePrime(strm, bits, value) z_streamp strm; int bits; int value; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += value << state->bits; state->bits += bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } #ifdef MAKEFIXED #include /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also defines BUILDFIXED, so the tables are built on the fly. makefixed() writes those tables to stdout, which would be piped to inffixed.h. A small program can simply call makefixed to do this: void makefixed(void); int main(void) { makefixed(); return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed() { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); puts(" */"); puts(""); puts(" /* WARNING: this file should *not* be used by applications."); puts(" It is part of the implementation of this library and is"); puts(" subject to change. Applications should only use zlib.h."); puts(" */"); puts(""); size = 1U << 9; printf(" static const code lenfix[%u] = {", size); low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); size = 1U << 5; printf("\n static const code distfix[%u] = {", size); low = 0; for (;;) { if ((low % 6) == 0) printf("\n "); printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); } #endif /* MAKEFIXED */ /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ local int updatewindow(strm, end, copy) z_streamp strm; const Bytef *end; unsigned copy; { struct inflate_state FAR *state; unsigned dist; state = (struct inflate_state FAR *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { state->window = (unsigned char FAR *) ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (state->window == Z_NULL) return 1; } /* if window not in use yet, initialize */ if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; } /* copy state->wsize or less output bytes into the circular window */ if (copy >= state->wsize) { zmemcpy(state->window, end - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; zmemcpy(state->window + state->wnext, end - copy, dist); copy -= dist; if (copy) { zmemcpy(state->window, end - copy, copy); state->wnext = copy; state->whave = state->wsize; } else { state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist; } } return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ check = crc32(check, hbuf, 2); \ } while (0) # define CRC4(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ hbuf[2] = (unsigned char)((word) >> 16); \ hbuf[3] = (unsigned char)((word) >> 24); \ check = crc32(check, hbuf, 4); \ } while (0) #endif /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflate(). */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is structured roughly as follows: for (;;) switch (state) { ... case STATEn: if (not enough input data or output space to make progress) return; ... make progress ... state = STATEm; break; ... } so when inflate() is called again, the same case is attempted again, and if the appropriate resources are provided, the machine proceeds to the next state. The NEEDBITS() macro is usually the way the state evaluates whether it can proceed or should return. NEEDBITS() does the return if the requested bits are not available. The typical use of the BITS macros is: NEEDBITS(n); ... do something with BITS(n) ... DROPBITS(n); where NEEDBITS(n) either returns from inflate() if there isn't enough input left to load n bits into the accumulator, or it continues. BITS(n) gives the low n bits in the accumulator. When done, DROPBITS(n) drops the low n bits off the accumulator. INITBITS() clears the accumulator and sets the number of available bits to zero. BYTEBITS() discards just enough bits to put the accumulator on a byte boundary. After BYTEBITS() and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return if there is no input available. The decoding of variable length codes uses PULLBYTE() directly in order to pull just enough bytes to decode the next code, and no more. Some states loop until they get enough input, making sure that enough state information is maintained to continue the loop where it left off if NEEDBITS() returns in the loop. For example, want, need, and keep would all have to actually be part of the saved state in case NEEDBITS() returns: case STATEw: while (want < need) { NEEDBITS(n); keep[want++] = BITS(n); DROPBITS(n); } state = STATEx; case STATEx: As shown above, if the next state is also the next case, then the break is omitted. A state may also return if there is not enough output space available to complete that state. Those states are copying stored data, writing a literal byte, and copying a matching string. When returning, a "goto inf_leave" is used to update the total counters, update the check value, and determine whether any progress has been made during that inflate() call in order to return the proper return code. Progress is defined as a change in either strm->avail_in or strm->avail_out. When there is a window, goto inf_leave will update the window with the last output written. If a goto inf_leave occurs in the middle of decompression and there is no window currently, goto inf_leave will create one and copy output to the window for the next call of inflate(). In this implementation, the flush parameter of inflate() only affects the return code (per zlib.h). inflate() always writes as much as possible to strm->next_out, given the space available and the provided input--the effect documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int ZEXPORT inflate(strm, flush) z_streamp strm; int flush; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ #ifdef GUNZIP unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ #endif static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; ret = Z_OK; for (;;) switch (state->mode) { case HEAD: if (state->wrap == 0) { state->mode = TYPEDO; break; } NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { strm->msg = (char *)"incorrect header check"; state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; else if (len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } if (state->flags & 0xe000) { strm->msg = (char *)"unknown header flags set"; state->mode = BAD; break; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if (state->flags & 0x0200) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL) { len = state->head->extra_len - state->length; zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) state->head->name[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if (hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; } INITBITS(); } if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; case COPY_: state->mode = COPY; case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; break; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (const code FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; case LEN_: state->mode = LEN; case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val; if ((int)(here.op) == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; if (copy > state->length) copy = state->length; if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); if (state->length == 0) state->mode = LEN; break; #endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); } else from = state->window + (state->wnext - copy); if (copy > state->length) copy = state->length; } else { /* copy from output */ from = put - state->offset; copy = state->length; } if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = *from++; } while (--copy); if (state->length == 0) state->mode = LEN; break; case LIT: if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if (out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if (( #ifdef GUNZIP state->flags ? hold : #endif ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if (hold != (state->total & 0xffffffffUL)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); if (state->wsize || (out != strm->avail_out && state->mode < BAD && (state->mode < CHECK || flush != Z_FINISH))) if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if (state->wrap && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int ZEXPORT inflateEnd(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; { struct inflate_state FAR *state; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ if (state->whave && dictionary != Z_NULL) { zmemcpy(dictionary, state->window + state->wnext, state->whave - state->wnext); zmemcpy(dictionary + state->whave - state->wnext, state->window, state->wnext); } if (dictLength != Z_NULL) *dictLength = state->whave; return Z_OK; } int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { struct inflate_state FAR *state; unsigned long dictid; int ret; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary identifier */ if (state->mode == DICT) { dictid = adler32(0L, Z_NULL, 0); dictid = adler32(dictid, dictionary, dictLength); if (dictid != state->check) return Z_DATA_ERROR; } /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ ret = updatewindow(strm, dictionary + dictLength, dictLength); if (ret) { state->mode = MEM; return Z_MEM_ERROR; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int ZEXPORT inflateGetHeader(strm, head) z_streamp strm; gz_headerp head; { struct inflate_state FAR *state; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; head->done = 0; return Z_OK; } /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes found in order so far, in 0..3. On return *have is updated to the new state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ local unsigned syncsearch(have, buf, len) unsigned FAR *have; const unsigned char FAR *buf; unsigned len; { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int ZEXPORT inflateSync(strm) z_streamp strm; { unsigned len; /* number of bytes to look at or looked at */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; /* check parameters */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int ZEXPORT inflateSyncPoint(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } int ZEXPORT inflateCopy(dest, source) z_streamp dest; z_streamp source; { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; unsigned wsize; /* check input */ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; /* allocate space */ copy = (struct inflate_state FAR *) ZALLOC(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); if (window == Z_NULL) { ZFREE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { wsize = 1U << state->wbits; zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } int ZEXPORT inflateUndermine(strm, subvert) z_streamp strm; int subvert; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->sane = !subvert; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR return Z_OK; #else state->sane = 1; return Z_DATA_ERROR; #endif } long ZEXPORT inflateMark(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; state = (struct inflate_state FAR *)strm->state; return ((long)(state->back) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/trees.c0000664000175000017500000012633712776215007020353 0ustar kaikai/* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2012 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process uses several Huffman trees. The more * common source values are represented by shorter bit sequences. * * Each code tree is stored in a compressed form which is itself * a Huffman encoding of the lengths of all the code strings (in * ascending order by source values). The actual code strings are * reconstructed from the lengths in the inflate process, as described * in the deflate specification. * * REFERENCES * * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc * * Storer, James A. * Data Compression: Methods and Theory, pp. 49-50. * Computer Science Press, 1988. ISBN 0-7167-8156-5. * * Sedgewick, R. * Algorithms, p290. * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ /* @(#) $Id$ */ /* #define GEN_TREES_H */ #include "deflate.h" #ifdef DEBUG # include #endif /* =========================================================================== * Constants */ #define MAX_BL_BITS 7 /* Bit length codes must not exceed MAX_BL_BITS bits */ #define END_BLOCK 256 /* end of block literal code */ #define REP_3_6 16 /* repeat previous bit length 3-6 times (2 bits of repeat count) */ #define REPZ_3_10 17 /* repeat a zero length 3-10 times (3 bits of repeat count) */ #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; local const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; local const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ /* =========================================================================== * Local data. These are initialized only once. */ #define DIST_CODE_LEN 512 /* see definition of array dist_code below */ #if defined(GEN_TREES_H) || !defined(STDC) /* non ANSI compilers may not accept trees.h */ local ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see _tr_init * below). */ local ct_data static_dtree[D_CODES]; /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ uch _dist_code[DIST_CODE_LEN]; /* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ uch _length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ local int base_length[LENGTH_CODES]; /* First normalized length for each code (0 = MIN_MATCH) */ local int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ #else # include "trees.h" #endif /* GEN_TREES_H */ struct static_tree_desc_s { const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; local static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ local void tr_static_init OF((void)); local void init_block OF((deflate_state *s)); local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); local void build_tree OF((deflate_state *s, tree_desc *desc)); local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); local int build_bl_tree OF((deflate_state *s)); local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, int blcodes)); local void compress_block OF((deflate_state *s, const ct_data *ltree, const ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned value, int length)); local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); local void copy_block OF((deflate_state *s, charf *buf, unsigned len, int header)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif #ifndef DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef DEBUG local void send_bits OF((deflate_state *s, int value, int length)); local void send_bits(s, value, length) deflate_state *s; int value; /* value to send */ int length; /* number of bits */ { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { s->bi_buf |= (ush)value << s->bi_valid; s->bi_valid += length; } } #else /* !DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ int val = value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ s->bi_valid += len - Buf_size;\ } else {\ s->bi_buf |= (ush)(value) << s->bi_valid;\ s->bi_valid += len;\ }\ } #endif /* DEBUG */ /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ local void tr_static_init() { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ if (static_init_done) return; /* For some embedded targets, global variables are not initialized: */ #ifdef NO_INIT_GLOBAL_POINTERS static_l_desc.static_tree = static_ltree; static_l_desc.extra_bits = extra_lbits; static_d_desc.static_tree = static_dtree; static_d_desc.extra_bits = extra_dbits; static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { _dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse((unsigned)n, 5); } static_init_done = 1; # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) || !defined(STDC) */ } /* =========================================================================== * Genererate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef DEBUG # include # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width)-1 ? ",\n" : ", ")) void gen_trees_header() { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { fprintf(header, "%2u%s", _dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); } fprintf(header, "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { fprintf(header, "%2u%s", _length_code[i], SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { fprintf(header, "%1u%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "local const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "%5u%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ void ZLIB_INTERNAL _tr_init(s) deflate_state *s; { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; s->bl_desc.dyn_tree = s->bl_tree; s->bl_desc.stat_desc = &static_bl_desc; s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } /* =========================================================================== * Initialize a new block. */ local void init_block(s) deflate_state *s; { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->last_lit = s->matches = 0; } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with * one less element. Updates heap and heap_len. */ #define pqremove(s, tree, top) \ {\ top = s->heap[SMALLEST]; \ s->heap[SMALLEST] = s->heap[s->heap_len--]; \ pqdownheap(s, tree, SMALLEST); \ } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m, depth) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ local void pqdownheap(s, tree, k) deflate_state *s; ct_data *tree; /* the tree to restore */ int k; /* node to move down */ { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s->heap[k] = v; } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ local void gen_bitlen(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; const intf *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max+1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; s->opt_len += (ulg)f * (bits + xbits); if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); } if (overflow == 0) return; Trace((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length-1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((long)bits - (long)tree[m].Len) *(long)tree[m].Freq; tree[m].Len = (ush)bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ local void gen_codes (tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ ush code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { next_code[bits] = code = (code + bl_count[bits-1]) << 1; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; s->depth[n] = 0; } else { tree[n].Len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s->heap_len < 2) { node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ node = elems; /* next internal node of the tree */ do { pqremove(s, tree, n); /* n = node of least frequency */ m = s->heap[SMALLEST]; /* m = node of next least frequency */ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ s->heap[--(s->heap_max)] = m; /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); } #endif /* and insert the new node in the heap */ s->heap[SMALLEST] = node++; pqdownheap(s, tree, SMALLEST); } while (s->heap_len >= 2); s->heap[--(s->heap_max)] = s->heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, (tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ local void scan_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ local void send_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ local int build_bl_tree(s) deflate_state *s; { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*(max_blindex+1) + 5+5+4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ local void send_all_trees(s, lcodes, dcodes, blcodes) deflate_state *s; int lcodes, dcodes, blcodes; /* number of codes for each tree */ { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes-1, 5); send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ #ifdef DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; #endif copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ void ZLIB_INTERNAL _tr_flush_bits(s) deflate_state *s; { bi_flush(s); } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ void ZLIB_INTERNAL _tr_align(s) deflate_state *s; { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and output the encoded block to the zip file. */ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block, or NULL if too old */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { /* Check if the file is binary or text */ if (s->strm->data_type == Z_UNKNOWN) s->strm->data_type = detect_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, s->static_len)); build_tree(s, (tree_desc *)(&(s->d_desc))); Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = (s->opt_len+3+7)>>3; static_lenb = (s->static_len+3+7)>>3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->last_lit)); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else if (stored_len+4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef DEBUG s->compressed_len += 3 + s->static_len; #endif } else { send_bits(s, (DYN_TREES<<1)+last, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef DEBUG s->compressed_len += 3 + s->opt_len; #endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); #ifdef DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally (s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ { s->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } #ifdef TRUNCATE_BLOCK /* Try to guess if it is profitable to stop the current block here */ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)((long)s->strstart - s->block_start); int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L+extra_dbits[dcode]); } out_length >>= 3; Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", s->last_lit, in_length, out_length, 100L - out_length*100L/in_length)); if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } #endif return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ local void compress_block(s, ltree, dtree) deflate_state *s; const ct_data *ltree; /* literal tree */ const ct_data *dtree; /* distance tree */ { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned lx = 0; /* running index in l_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->last_lit != 0) do { dist = s->d_buf[lx]; lc = s->l_buf[lx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, "pendingBuf overflow"); } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree); } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "black list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ local int detect_data_type(s) deflate_state *s; { /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ unsigned long black_mask = 0xf3ffc07fUL; int n; /* Check for non-textual ("black-listed") bytes. */ for (n = 0; n <= 31; n++, black_mask >>= 1) if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; /* Check for textual ("white-listed") bytes. */ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; /* There are no "black-listed" or "white-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ local unsigned bi_reverse(code, len) unsigned code; /* the value to invert */ int len; /* its bit length */ { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ local void bi_flush(s) deflate_state *s; { if (s->bi_valid == 16) { put_short(s, s->bi_buf); s->bi_buf = 0; s->bi_valid = 0; } else if (s->bi_valid >= 8) { put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ local void bi_windup(s) deflate_state *s; { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } /* =========================================================================== * Copy a stored block, storing first the length and its * one's complement if requested. */ local void copy_block(s, buf, len, header) deflate_state *s; charf *buf; /* the input data */ unsigned len; /* its length */ int header; /* true if block header must be written */ { bi_windup(s); /* align on byte boundary */ if (header) { put_short(s, (ush)len); put_short(s, (ush)~len); #ifdef DEBUG s->bits_sent += 2*16; #endif } #ifdef DEBUG s->bits_sent += (ulg)len<<3; #endif while (len--) { put_byte(s, *buf++); } } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/trees.h0000664000175000017500000002043012776215007020343 0ustar kaikai/* header created automatically with -DGEN_TREES_H */ local const ct_data static_ltree[L_CODES+2] = { {{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, {{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, {{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, {{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, {{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, {{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, {{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, {{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, {{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, {{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, {{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, {{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, {{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, {{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, {{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, {{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, {{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, {{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, {{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, {{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, {{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, {{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, {{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, {{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, {{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, {{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, {{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, {{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, {{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, {{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, {{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, {{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, {{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, {{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, {{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, {{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, {{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, {{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, {{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, {{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, {{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, {{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, {{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, {{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, {{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, {{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, {{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, {{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, {{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, {{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, {{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, {{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, {{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, {{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, {{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, {{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, {{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, {{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} }; local const ct_data static_dtree[D_CODES] = { {{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, {{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, {{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, {{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, {{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, {{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} }; const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; local const int base_length[LENGTH_CODES] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 }; local const int base_dist[D_CODES] = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 }; ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/example.c0000664000175000017500000004072712776215007020662 0ustar kaikai/* example.c -- usage example of the zlib compression library * Copyright (C) 1995-2006, 2011 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zlib.h" #include #ifdef STDC # include # include #endif #if defined(VMS) || defined(RISCOS) # define TESTFILE "foo-gz" #else # define TESTFILE "foo.gz" #endif #define CHECK_ERR(err, msg) { \ if (err != Z_OK) { \ fprintf(stderr, "%s error: %d\n", msg, err); \ exit(1); \ } \ } z_const char hello[] = "hello, hello!"; /* "hello world" would be more standard, but the repeated "hello" * stresses the compression code better, sorry... */ const char dictionary[] = "hello"; uLong dictId; /* Adler32 value of the dictionary */ void test_deflate OF((Byte *compr, uLong comprLen)); void test_inflate OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_large_deflate OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_large_inflate OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_flush OF((Byte *compr, uLong *comprLen)); void test_sync OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_dict_deflate OF((Byte *compr, uLong comprLen)); void test_dict_inflate OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); int main OF((int argc, char *argv[])); #ifdef Z_SOLO void *myalloc OF((void *, unsigned, unsigned)); void myfree OF((void *, void *)); void *myalloc(q, n, m) void *q; unsigned n, m; { q = Z_NULL; return calloc(n, m); } void myfree(void *q, void *p) { q = Z_NULL; free(p); } static alloc_func zalloc = myalloc; static free_func zfree = myfree; #else /* !Z_SOLO */ static alloc_func zalloc = (alloc_func)0; static free_func zfree = (free_func)0; void test_compress OF((Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)); void test_gzio OF((const char *fname, Byte *uncompr, uLong uncomprLen)); /* =========================================================================== * Test compress() and uncompress() */ void test_compress(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; uLong len = (uLong)strlen(hello)+1; err = compress(compr, &comprLen, (const Bytef*)hello, len); CHECK_ERR(err, "compress"); strcpy((char*)uncompr, "garbage"); err = uncompress(uncompr, &uncomprLen, compr, comprLen); CHECK_ERR(err, "uncompress"); if (strcmp((char*)uncompr, hello)) { fprintf(stderr, "bad uncompress\n"); exit(1); } else { printf("uncompress(): %s\n", (char *)uncompr); } } /* =========================================================================== * Test read/write of .gz files */ void test_gzio(fname, uncompr, uncomprLen) const char *fname; /* compressed file name */ Byte *uncompr; uLong uncomprLen; { #ifdef NO_GZCOMPRESS fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); #else int err; int len = (int)strlen(hello)+1; gzFile file; z_off_t pos; file = gzopen(fname, "wb"); if (file == NULL) { fprintf(stderr, "gzopen error\n"); exit(1); } gzputc(file, 'h'); if (gzputs(file, "ello") != 4) { fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); exit(1); } if (gzprintf(file, ", %s!", "hello") != 8) { fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); exit(1); } gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ gzclose(file); file = gzopen(fname, "rb"); if (file == NULL) { fprintf(stderr, "gzopen error\n"); exit(1); } strcpy((char*)uncompr, "garbage"); if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); exit(1); } if (strcmp((char*)uncompr, hello)) { fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); exit(1); } else { printf("gzread(): %s\n", (char*)uncompr); } pos = gzseek(file, -8L, SEEK_CUR); if (pos != 6 || gztell(file) != pos) { fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", (long)pos, (long)gztell(file)); exit(1); } if (gzgetc(file) != ' ') { fprintf(stderr, "gzgetc error\n"); exit(1); } if (gzungetc(' ', file) != ' ') { fprintf(stderr, "gzungetc error\n"); exit(1); } gzgets(file, (char*)uncompr, (int)uncomprLen); if (strlen((char*)uncompr) != 7) { /* " hello!" */ fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); exit(1); } if (strcmp((char*)uncompr, hello + 6)) { fprintf(stderr, "bad gzgets after gzseek\n"); exit(1); } else { printf("gzgets() after gzseek: %s\n", (char*)uncompr); } gzclose(file); #endif } #endif /* Z_SOLO */ /* =========================================================================== * Test deflate() with small buffers */ void test_deflate(compr, comprLen) Byte *compr; uLong comprLen; { z_stream c_stream; /* compression stream */ int err; uLong len = (uLong)strlen(hello)+1; c_stream.zalloc = zalloc; c_stream.zfree = zfree; c_stream.opaque = (voidpf)0; err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); CHECK_ERR(err, "deflateInit"); c_stream.next_in = (z_const unsigned char *)hello; c_stream.next_out = compr; while (c_stream.total_in != len && c_stream.total_out < comprLen) { c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ err = deflate(&c_stream, Z_NO_FLUSH); CHECK_ERR(err, "deflate"); } /* Finish the stream, still forcing small buffers: */ for (;;) { c_stream.avail_out = 1; err = deflate(&c_stream, Z_FINISH); if (err == Z_STREAM_END) break; CHECK_ERR(err, "deflate"); } err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); } /* =========================================================================== * Test inflate() with small buffers */ void test_inflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; z_stream d_stream; /* decompression stream */ strcpy((char*)uncompr, "garbage"); d_stream.zalloc = zalloc; d_stream.zfree = zfree; d_stream.opaque = (voidpf)0; d_stream.next_in = compr; d_stream.avail_in = 0; d_stream.next_out = uncompr; err = inflateInit(&d_stream); CHECK_ERR(err, "inflateInit"); while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ err = inflate(&d_stream, Z_NO_FLUSH); if (err == Z_STREAM_END) break; CHECK_ERR(err, "inflate"); } err = inflateEnd(&d_stream); CHECK_ERR(err, "inflateEnd"); if (strcmp((char*)uncompr, hello)) { fprintf(stderr, "bad inflate\n"); exit(1); } else { printf("inflate(): %s\n", (char *)uncompr); } } /* =========================================================================== * Test deflate() with large buffers and dynamic change of compression level */ void test_large_deflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { z_stream c_stream; /* compression stream */ int err; c_stream.zalloc = zalloc; c_stream.zfree = zfree; c_stream.opaque = (voidpf)0; err = deflateInit(&c_stream, Z_BEST_SPEED); CHECK_ERR(err, "deflateInit"); c_stream.next_out = compr; c_stream.avail_out = (uInt)comprLen; /* At this point, uncompr is still mostly zeroes, so it should compress * very well: */ c_stream.next_in = uncompr; c_stream.avail_in = (uInt)uncomprLen; err = deflate(&c_stream, Z_NO_FLUSH); CHECK_ERR(err, "deflate"); if (c_stream.avail_in != 0) { fprintf(stderr, "deflate not greedy\n"); exit(1); } /* Feed in already compressed data and switch to no compression: */ deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); c_stream.next_in = compr; c_stream.avail_in = (uInt)comprLen/2; err = deflate(&c_stream, Z_NO_FLUSH); CHECK_ERR(err, "deflate"); /* Switch back to compressing mode: */ deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); c_stream.next_in = uncompr; c_stream.avail_in = (uInt)uncomprLen; err = deflate(&c_stream, Z_NO_FLUSH); CHECK_ERR(err, "deflate"); err = deflate(&c_stream, Z_FINISH); if (err != Z_STREAM_END) { fprintf(stderr, "deflate should report Z_STREAM_END\n"); exit(1); } err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); } /* =========================================================================== * Test inflate() with large buffers */ void test_large_inflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; z_stream d_stream; /* decompression stream */ strcpy((char*)uncompr, "garbage"); d_stream.zalloc = zalloc; d_stream.zfree = zfree; d_stream.opaque = (voidpf)0; d_stream.next_in = compr; d_stream.avail_in = (uInt)comprLen; err = inflateInit(&d_stream); CHECK_ERR(err, "inflateInit"); for (;;) { d_stream.next_out = uncompr; /* discard the output */ d_stream.avail_out = (uInt)uncomprLen; err = inflate(&d_stream, Z_NO_FLUSH); if (err == Z_STREAM_END) break; CHECK_ERR(err, "large inflate"); } err = inflateEnd(&d_stream); CHECK_ERR(err, "inflateEnd"); if (d_stream.total_out != 2*uncomprLen + comprLen/2) { fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); exit(1); } else { printf("large_inflate(): OK\n"); } } /* =========================================================================== * Test deflate() with full flush */ void test_flush(compr, comprLen) Byte *compr; uLong *comprLen; { z_stream c_stream; /* compression stream */ int err; uInt len = (uInt)strlen(hello)+1; c_stream.zalloc = zalloc; c_stream.zfree = zfree; c_stream.opaque = (voidpf)0; err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); CHECK_ERR(err, "deflateInit"); c_stream.next_in = (z_const unsigned char *)hello; c_stream.next_out = compr; c_stream.avail_in = 3; c_stream.avail_out = (uInt)*comprLen; err = deflate(&c_stream, Z_FULL_FLUSH); CHECK_ERR(err, "deflate"); compr[3]++; /* force an error in first compressed block */ c_stream.avail_in = len - 3; err = deflate(&c_stream, Z_FINISH); if (err != Z_STREAM_END) { CHECK_ERR(err, "deflate"); } err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); *comprLen = c_stream.total_out; } /* =========================================================================== * Test inflateSync() */ void test_sync(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; z_stream d_stream; /* decompression stream */ strcpy((char*)uncompr, "garbage"); d_stream.zalloc = zalloc; d_stream.zfree = zfree; d_stream.opaque = (voidpf)0; d_stream.next_in = compr; d_stream.avail_in = 2; /* just read the zlib header */ err = inflateInit(&d_stream); CHECK_ERR(err, "inflateInit"); d_stream.next_out = uncompr; d_stream.avail_out = (uInt)uncomprLen; inflate(&d_stream, Z_NO_FLUSH); CHECK_ERR(err, "inflate"); d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ err = inflateSync(&d_stream); /* but skip the damaged part */ CHECK_ERR(err, "inflateSync"); err = inflate(&d_stream, Z_FINISH); if (err != Z_DATA_ERROR) { fprintf(stderr, "inflate should report DATA_ERROR\n"); /* Because of incorrect adler32 */ exit(1); } err = inflateEnd(&d_stream); CHECK_ERR(err, "inflateEnd"); printf("after inflateSync(): hel%s\n", (char *)uncompr); } /* =========================================================================== * Test deflate() with preset dictionary */ void test_dict_deflate(compr, comprLen) Byte *compr; uLong comprLen; { z_stream c_stream; /* compression stream */ int err; c_stream.zalloc = zalloc; c_stream.zfree = zfree; c_stream.opaque = (voidpf)0; err = deflateInit(&c_stream, Z_BEST_COMPRESSION); CHECK_ERR(err, "deflateInit"); err = deflateSetDictionary(&c_stream, (const Bytef*)dictionary, (int)sizeof(dictionary)); CHECK_ERR(err, "deflateSetDictionary"); dictId = c_stream.adler; c_stream.next_out = compr; c_stream.avail_out = (uInt)comprLen; c_stream.next_in = (z_const unsigned char *)hello; c_stream.avail_in = (uInt)strlen(hello)+1; err = deflate(&c_stream, Z_FINISH); if (err != Z_STREAM_END) { fprintf(stderr, "deflate should report Z_STREAM_END\n"); exit(1); } err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); } /* =========================================================================== * Test inflate() with a preset dictionary */ void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { int err; z_stream d_stream; /* decompression stream */ strcpy((char*)uncompr, "garbage"); d_stream.zalloc = zalloc; d_stream.zfree = zfree; d_stream.opaque = (voidpf)0; d_stream.next_in = compr; d_stream.avail_in = (uInt)comprLen; err = inflateInit(&d_stream); CHECK_ERR(err, "inflateInit"); d_stream.next_out = uncompr; d_stream.avail_out = (uInt)uncomprLen; for (;;) { err = inflate(&d_stream, Z_NO_FLUSH); if (err == Z_STREAM_END) break; if (err == Z_NEED_DICT) { if (d_stream.adler != dictId) { fprintf(stderr, "unexpected dictionary"); exit(1); } err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, (int)sizeof(dictionary)); } CHECK_ERR(err, "inflate with dict"); } err = inflateEnd(&d_stream); CHECK_ERR(err, "inflateEnd"); if (strcmp((char*)uncompr, hello)) { fprintf(stderr, "bad inflate with dict\n"); exit(1); } else { printf("inflate with dictionary: %s\n", (char *)uncompr); } } /* =========================================================================== * Usage: example [output.gz [input.gz]] */ int main(argc, argv) int argc; char *argv[]; { Byte *compr, *uncompr; uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ uLong uncomprLen = comprLen; static const char* myVersion = ZLIB_VERSION; if (zlibVersion()[0] != myVersion[0]) { fprintf(stderr, "incompatible zlib version\n"); exit(1); } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { fprintf(stderr, "warning: different zlib version\n"); } printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); compr = (Byte*)calloc((uInt)comprLen, 1); uncompr = (Byte*)calloc((uInt)uncomprLen, 1); /* compr and uncompr are cleared to avoid reading uninitialized * data and to ensure that uncompr compresses well. */ if (compr == Z_NULL || uncompr == Z_NULL) { printf("out of memory\n"); exit(1); } #ifdef Z_SOLO argc = strlen(argv[0]); #else test_compress(compr, comprLen, uncompr, uncomprLen); test_gzio((argc > 1 ? argv[1] : TESTFILE), uncompr, uncomprLen); #endif test_deflate(compr, comprLen); test_inflate(compr, comprLen, uncompr, uncomprLen); test_large_deflate(compr, comprLen, uncompr, uncomprLen); test_large_inflate(compr, comprLen, uncompr, uncomprLen); test_flush(compr, &comprLen); test_sync(compr, comprLen, uncompr, uncomprLen); comprLen = uncomprLen; test_dict_deflate(compr, comprLen); test_dict_inflate(compr, comprLen, uncompr, uncomprLen); free(compr); free(uncompr); return 0; } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/gzclose.c0000664000175000017500000000124612776215007020666 0ustar kaikai/* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ int ZEXPORT gzclose(file) gzFile file; { #ifndef NO_GZCOMPRESS gz_statep state; if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); #else return gzclose_r(file); #endif } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/gzwrite.c0000664000175000017500000003750712776215007020724 0ustar kaikai/* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_init OF((gz_statep)); local int gz_comp OF((gz_statep, int)); local int gz_zero OF((gz_statep, z_off64_t)); /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on failure or 0 on success. */ local int gz_init(state) gz_statep state; { int ret; z_streamp strm = &(state->strm); /* allocate input buffer */ state->in = (unsigned char *)malloc(state->want); if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* only need output buffer and deflate state if compressing */ if (!state->direct) { /* allocate output buffer */ state->out = (unsigned char *)malloc(state->want); if (state->out == NULL) { free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* allocate deflate memory, set up for gzip compression */ strm->zalloc = Z_NULL; strm->zfree = Z_NULL; strm->opaque = Z_NULL; ret = deflateInit2(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); if (ret != Z_OK) { free(state->out); free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* mark state as initialized */ state->size = state->want; /* initialize write buffer if compressing */ if (!state->direct) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = strm->next_out; } return 0; } /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ local int gz_comp(state, flush) gz_statep state; int flush; { int ret, got; unsigned have; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return -1; /* write directly if requested */ if (state->direct) { got = write(state->fd, strm->next_in, strm->avail_in); if (got < 0 || (unsigned)got != strm->avail_in) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } strm->avail_in = 0; return 0; } /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { /* write out current buffer contents if full, or if flushing, but if doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { have = (unsigned)(strm->next_out - state->x.next); if (have && ((got = write(state->fd, state->x.next, have)) < 0 || (unsigned)got != have)) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; } state->x.next = strm->next_out; } /* compress */ have = strm->avail_out; ret = deflate(strm, flush); if (ret == Z_STREAM_ERROR) { gz_error(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt"); return -1; } have -= strm->avail_out; } while (have); /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) deflateReset(strm); /* all done, no errors */ return 0; } /* Compress len zeros to output. Return -1 on error, 0 on success. */ local int gz_zero(state, len) gz_statep state; z_off64_t len; { int first; unsigned n; z_streamp strm = &(state->strm); /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return -1; /* compress len zeros (len guaranteed > 0) */ first = 1; while (len) { n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size; if (first) { memset(state->in, 0, n); first = 0; } strm->avail_in = n; strm->next_in = state->in; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return -1; len -= n; } return 0; } /* -- see zlib.h -- */ int ZEXPORT gzwrite(file, buf, len) gzFile file; voidpc buf; unsigned len; { unsigned put = len; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return 0; } /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* for small len, copy to input buffer, otherwise compress directly */ if (len < state->size) { /* copy to input buffer, compress when full */ do { unsigned have, copy; if (strm->avail_in == 0) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); copy = state->size - have; if (copy > len) copy = len; memcpy(state->in + have, buf, copy); strm->avail_in += copy; state->x.pos += copy; buf = (const char *)buf + copy; len -= copy; if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); } else { /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ strm->avail_in = len; strm->next_in = (z_const Bytef *)buf; state->x.pos += len; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; } /* input was all buffered or compressed (put will fit in int) */ return (int)put; } /* -- see zlib.h -- */ int ZEXPORT gzputc(file, c) gzFile file; int c; { unsigned have; unsigned char buf[1]; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* try writing to input buffer for speed (state->size == 0 if buffer not initialized) */ if (state->size) { if (strm->avail_in == 0) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); if (have < state->size) { state->in[have] = c; strm->avail_in++; state->x.pos++; return c & 0xff; } } /* no room in buffer or not initialized, use gz_write() */ buf[0] = c; if (gzwrite(file, buf, 1) != 1) return -1; return c & 0xff; } /* -- see zlib.h -- */ int ZEXPORT gzputs(file, str) gzFile file; const char *str; { int ret; unsigned len; /* write string */ len = (unsigned)strlen(str); ret = gzwrite(file, str, len); return ret == 0 && len != 0 ? -1 : ret; } #if defined(STDC) || defined(Z_HAVE_STDARG_H) #include /* -- see zlib.h -- */ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { int size, len; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void (void)vsprintf((char *)(state->in), format, va); for (len = 0; len < size; len++) if (state->in[len] == 0) break; # else len = vsprintf((char *)(state->in), format, va); # endif #else # ifdef HAS_vsnprintf_void (void)vsnprintf((char *)(state->in), size, format, va); len = strlen((char *)(state->in)); # else len = vsnprintf((char *)(state->in), size, format, va); # endif #endif /* check that printf() results fit in buffer */ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) return 0; /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; state->x.pos += len; return len; } int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { va_list va; int ret; va_start(va, format); ret = gzvprintf(file, format, va); va_end(va); return ret; } #else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) gzFile file; const char *format; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; { int size, len; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that can really pass pointer in ints */ if (sizeof(int) != sizeof(void *)) return 0; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < size; len++) if (state->in[len] == 0) break; # else len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); len = strlen((char *)(state->in)); # else len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #endif /* check that printf() results fit in buffer */ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) return 0; /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; state->x.pos += len; return len; } #endif /* -- see zlib.h -- */ int ZEXPORT gzflush(file, flush) gzFile file; int flush; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* check flush parameter */ if (flush < 0 || flush > Z_FINISH) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* compress remaining data with requested flush */ gz_comp(state, flush); return state->err; } /* -- see zlib.h -- */ int ZEXPORT gzsetparams(file, level, strategy) gzFile file; int level; int strategy; { gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ if (level == state->level && strategy == state->strategy) return Z_OK; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* change compression parameters for subsequent input */ if (state->size) { /* flush previous input with previous parameters before changing */ if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) return state->err; deflateParams(strm, level, strategy); } state->level = level; state->strategy = strategy; return Z_OK; } /* -- see zlib.h -- */ int ZEXPORT gzclose_w(file) gzFile file; { int ret = Z_OK; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing */ if (state->mode != GZ_WRITE) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) ret = state->err; } /* flush, free memory, and close file */ if (gz_comp(state, Z_FINISH) == -1) ret = state->err; if (state->size) { if (!state->direct) { (void)deflateEnd(&(state->strm)); free(state->out); } free(state->in); } gz_error(state, Z_OK, NULL); free(state->path); if (close(state->fd) == -1) ret = Z_ERRNO; free(state); return ret; } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/zutil.h0000664000175000017500000001515612776215007020401 0ustar kaikai/* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef ZUTIL_H #define ZUTIL_H #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include "zlib.h" #if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include # endif # include # include #endif #ifdef Z_SOLO typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ typedef unsigned char uch; typedef uch FAR uchf; typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ #ifndef DEF_WBITS # define DEF_WBITS MAX_WBITS #endif /* default windowBits for decompression. MAX_WBITS is for compression only */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default memLevel */ #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 /* The three kinds of block type */ #define MIN_MATCH 3 #define MAX_MATCH 258 /* The minimum and maximum match lengths */ #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ /* target dependencies */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 # ifndef Z_SOLO # if defined(__TURBOC__) || defined(__BORLANDC__) # if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) /* Allow compilation with ANSI keywords only enabled */ void _Cdecl farfree( void *block ); void *_Cdecl farmalloc( unsigned long nbytes ); # else # include # endif # else /* MSC or DJGPP */ # include # endif # endif #endif #ifdef AMIGA # define OS_CODE 0x01 #endif #if defined(VAXC) || defined(VMS) # define OS_CODE 0x02 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif #if defined(ATARI) || defined(atarist) # define OS_CODE 0x05 #endif #ifdef OS2 # define OS_CODE 0x06 # if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 0x07 # ifndef Z_SOLO # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include /* for fdopen */ # else # ifndef fdopen # define fdopen(fd,mode) NULL /* No fdopen() */ # endif # endif # endif #endif #ifdef TOPS20 # define OS_CODE 0x0a #endif #ifdef WIN32 # ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ # define OS_CODE 0x0b # endif #endif #ifdef __50SERIES /* Prime/PRIMOS */ # define OS_CODE 0x0f #endif #if defined(_BEOS_) || defined(RISCOS) # define fdopen(fd,mode) NULL /* No fdopen() */ #endif #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX # if defined(_WIN32_WCE) # define fdopen(fd,mode) NULL /* No fdopen() */ # ifndef _PTRDIFF_T_DEFINED typedef int ptrdiff_t; # define _PTRDIFF_T_DEFINED # endif # else # define fdopen(fd,type) _fdopen(fd,type) # endif #endif #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); #endif /* common defaults */ #ifndef OS_CODE # define OS_CODE 0x03 /* assume Unix */ #endif #ifndef F_OPEN # define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ #if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) /* Use our own functions for small and medium model with MSC <= 5.0. * You may have to use the same strategy for Borland C (untested). * The __SC__ check is for Symantec. */ # define NO_MEMCPY #endif #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) # define HAVE_MEMCPY #endif #ifdef HAVE_MEMCPY # ifdef SMALL_MEDIUM /* MSDOS small or medium model */ # define zmemcpy _fmemcpy # define zmemcmp _fmemcmp # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); #endif /* Diagnostic functions */ #ifdef DEBUG # include extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error OF((char *m)); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracevv(x) {if (z_verbose>1) fprintf x ;} # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif #ifndef Z_SOLO voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, unsigned size)); void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); #endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} /* Reverse the bytes in a 32-bit value */ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) #endif /* ZUTIL_H */ ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/inffast.c0000664000175000017500000003221712776215007020654 0ustar kaikai/* inffast.c -- fast decoding * Copyright (C) 1995-2008, 2010, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifndef ASMINF /* Allow machine dependent optimization for post-increment or pre-increment. Based on testing to date, Pre-increment preferred for: - PowerPC G3 (Adler) - MIPS R5000 (Randers-Pehrson) Post-increment preferred for: - none No measurable difference: - Pentium III (Anderson) - M68060 (Nikl) */ #ifdef POSTINC # define OFF 0 # define PUP(a) *(a)++ #else # define OFF 1 # define PUP(a) *++(a) #endif /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void ZLIB_INTERNAL inflate_fast(strm, start) z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const FAR *lcode; /* local strm->lencode */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char FAR *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; in = strm->next_in - OFF; last = in + (strm->avail_in - 5); out = strm->next_out - OFF; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT dmax = state->dmax; #endif wsize = state->wsize; whave = state->whave; wnext = state->wnext; window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; dcode = state->distcode; lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = lcode[hold & lmask]; dolen: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op == 0) { /* literal */ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); PUP(out) = (unsigned char)(here.val); } else if (op & 16) { /* length base */ len = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = dcode[hold & dmask]; dodist: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op & 16) { /* distance base */ dist = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } } dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); op = (unsigned)(out - beg); /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { PUP(out) = 0; } while (--len); continue; } len -= op - whave; do { PUP(out) = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { PUP(out) = PUP(from); } while (--len); continue; } #endif } from = window - OFF; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = window - OFF; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } while (len > 2); if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode[here.val + (hold & ((1U << op) - 1))]; goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode[here.val + (hold & ((1U << op) - 1))]; goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } else { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in -= len; bits -= len << 3; hold &= (1U << bits) - 1; /* update state and return */ strm->next_in = in + OFF; strm->next_out = out + OFF; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; return; } /* inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - Using bit fields for code structure - Different op definition to avoid & for extra bits (do & for table bits) - Three separate decoding do-loops for direct, window, and wnext == 0 - Special case for distance > 1 copies to do overlapped load and store copy - Explicit branch predictions (based on measured branch probabilities) - Deferring match copy and interspersed it with decoding subsequent codes - Swapping literal/length else - Swapping window/direct else - Larger unrolled copy loops (three is about right) - Moving len -= 3 statement into middle of loop */ #endif /* !ASMINF */ ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/ChangeLog0000664000175000017500000022516212776215007020633 0ustar kaikai ChangeLog file for zlib Changes in 1.2.8 (28 Apr 2013) - Update contrib/minizip/iowin32.c for Windows RT [Vollant] - Do not force Z_CONST for C++ - Clean up contrib/vstudio [Ro] - Correct spelling error in zlib.h - Fix mixed line endings in contrib/vstudio Changes in 1.2.7.3 (13 Apr 2013) - Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc Changes in 1.2.7.2 (13 Apr 2013) - Change check for a four-byte type back to hexadecimal - Fix typo in win32/Makefile.msc - Add casts in gzwrite.c for pointer differences Changes in 1.2.7.1 (24 Mar 2013) - Replace use of unsafe string functions with snprintf if available - Avoid including stddef.h on Windows for Z_SOLO compile [Niessink] - Fix gzgetc undefine when Z_PREFIX set [Turk] - Eliminate use of mktemp in Makefile (not always available) - Fix bug in 'F' mode for gzopen() - Add inflateGetDictionary() function - Correct comment in deflate.h - Use _snprintf for snprintf in Microsoft C - On Darwin, only use /usr/bin/libtool if libtool is not Apple - Delete "--version" file if created by "ar --version" [Richard G.] - Fix configure check for veracity of compiler error return codes - Fix CMake compilation of static lib for MSVC2010 x64 - Remove unused variable in infback9.c - Fix argument checks in gzlog_compress() and gzlog_write() - Clean up the usage of z_const and respect const usage within zlib - Clean up examples/gzlog.[ch] comparisons of different types - Avoid shift equal to bits in type (caused endless loop) - Fix unintialized value bug in gzputc() introduced by const patches - Fix memory allocation error in examples/zran.c [Nor] - Fix bug where gzopen(), gzclose() would write an empty file - Fix bug in gzclose() when gzwrite() runs out of memory - Check for input buffer malloc failure in examples/gzappend.c - Add note to contrib/blast to use binary mode in stdio - Fix comparisons of differently signed integers in contrib/blast - Check for invalid code length codes in contrib/puff - Fix serious but very rare decompression bug in inftrees.c - Update inflateBack() comments, since inflate() can be faster - Use underscored I/O function names for WINAPI_FAMILY - Add _tr_flush_bits to the external symbols prefixed by --zprefix - Add contrib/vstudio/vc10 pre-build step for static only - Quote --version-script argument in CMakeLists.txt - Don't specify --version-script on Apple platforms in CMakeLists.txt - Fix casting error in contrib/testzlib/testzlib.c - Fix types in contrib/minizip to match result of get_crc_table() - Simplify contrib/vstudio/vc10 with 'd' suffix - Add TOP support to win32/Makefile.msc - Suport i686 and amd64 assembler builds in CMakeLists.txt - Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h - Add vc11 and vc12 build files to contrib/vstudio - Add gzvprintf() as an undocumented function in zlib - Fix configure for Sun shell - Remove runtime check in configure for four-byte integer type - Add casts and consts to ease user conversion to C++ - Add man pages for minizip and miniunzip - In Makefile uninstall, don't rm if preceding cd fails - Do not return Z_BUF_ERROR if deflateParam() has nothing to write Changes in 1.2.7 (2 May 2012) - Replace use of memmove() with a simple copy for portability - Test for existence of strerror - Restore gzgetc_ for backward compatibility with 1.2.6 - Fix build with non-GNU make on Solaris - Require gcc 4.0 or later on Mac OS X to use the hidden attribute - Include unistd.h for Watcom C - Use __WATCOMC__ instead of __WATCOM__ - Do not use the visibility attribute if NO_VIZ defined - Improve the detection of no hidden visibility attribute - Avoid using __int64 for gcc or solo compilation - Cast to char * in gzprintf to avoid warnings [Zinser] - Fix make_vms.com for VAX [Zinser] - Don't use library or built-in byte swaps - Simplify test and use of gcc hidden attribute - Fix bug in gzclose_w() when gzwrite() fails to allocate memory - Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen() - Fix bug in test/minigzip.c for configure --solo - Fix contrib/vstudio project link errors [Mohanathas] - Add ability to choose the builder in make_vms.com [Schweda] - Add DESTDIR support to mingw32 win32/Makefile.gcc - Fix comments in win32/Makefile.gcc for proper usage - Allow overriding the default install locations for cmake - Generate and install the pkg-config file with cmake - Build both a static and a shared version of zlib with cmake - Include version symbols for cmake builds - If using cmake with MSVC, add the source directory to the includes - Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta] - Move obsolete emx makefile to old [Truta] - Allow the use of -Wundef when compiling or using zlib - Avoid the use of the -u option with mktemp - Improve inflate() documentation on the use of Z_FINISH - Recognize clang as gcc - Add gzopen_w() in Windows for wide character path names - Rename zconf.h in CMakeLists.txt to move it out of the way - Add source directory in CMakeLists.txt for building examples - Look in build directory for zlib.pc in CMakeLists.txt - Remove gzflags from zlibvc.def in vc9 and vc10 - Fix contrib/minizip compilation in the MinGW environment - Update ./configure for Solaris, support --64 [Mooney] - Remove -R. from Solaris shared build (possible security issue) - Avoid race condition for parallel make (-j) running example - Fix type mismatch between get_crc_table() and crc_table - Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler] - Fix the path to zlib.map in CMakeLists.txt - Force the native libtool in Mac OS X to avoid GNU libtool [Beebe] - Add instructions to win32/Makefile.gcc for shared install [Torri] Changes in 1.2.6.1 (12 Feb 2012) - Avoid the use of the Objective-C reserved name "id" - Include io.h in gzguts.h for Microsoft compilers - Fix problem with ./configure --prefix and gzgetc macro - Include gz_header definition when compiling zlib solo - Put gzflags() functionality back in zutil.c - Avoid library header include in crc32.c for Z_SOLO - Use name in GCC_CLASSIC as C compiler for coverage testing, if set - Minor cleanup in contrib/minizip/zip.c [Vollant] - Update make_vms.com [Zinser] - Remove unnecessary gzgetc_ function - Use optimized byte swap operations for Microsoft and GNU [Snyder] - Fix minor typo in zlib.h comments [Rzesniowiecki] Changes in 1.2.6 (29 Jan 2012) - Update the Pascal interface in contrib/pascal - Fix function numbers for gzgetc_ in zlibvc.def files - Fix configure.ac for contrib/minizip [Schiffer] - Fix large-entry detection in minizip on 64-bit systems [Schiffer] - Have ./configure use the compiler return code for error indication - Fix CMakeLists.txt for cross compilation [McClure] - Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes] - Fix compilation of contrib/minizip on FreeBSD [Marquez] - Correct suggested usages in win32/Makefile.msc [Shachar, Horvath] - Include io.h for Turbo C / Borland C on all platforms [Truta] - Make version explicit in contrib/minizip/configure.ac [Bosmans] - Avoid warning for no encryption in contrib/minizip/zip.c [Vollant] - Minor cleanup up contrib/minizip/unzip.c [Vollant] - Fix bug when compiling minizip with C++ [Vollant] - Protect for long name and extra fields in contrib/minizip [Vollant] - Avoid some warnings in contrib/minizip [Vollant] - Add -I../.. -L../.. to CFLAGS for minizip and miniunzip - Add missing libs to minizip linker command - Add support for VPATH builds in contrib/minizip - Add an --enable-demos option to contrib/minizip/configure - Add the generation of configure.log by ./configure - Exit when required parameters not provided to win32/Makefile.gcc - Have gzputc return the character written instead of the argument - Use the -m option on ldconfig for BSD systems [Tobias] - Correct in zlib.map when deflateResetKeep was added Changes in 1.2.5.3 (15 Jan 2012) - Restore gzgetc function for binary compatibility - Do not use _lseeki64 under Borland C++ [Truta] - Update win32/Makefile.msc to build test/*.c [Truta] - Remove old/visualc6 given CMakefile and other alternatives - Update AS400 build files and documentation [Monnerat] - Update win32/Makefile.gcc to build test/*.c [Truta] - Permit stronger flushes after Z_BLOCK flushes - Avoid extraneous empty blocks when doing empty flushes - Permit Z_NULL arguments to deflatePending - Allow deflatePrime() to insert bits in the middle of a stream - Remove second empty static block for Z_PARTIAL_FLUSH - Write out all of the available bits when using Z_BLOCK - Insert the first two strings in the hash table after a flush Changes in 1.2.5.2 (17 Dec 2011) - fix ld error: unable to find version dependency 'ZLIB_1.2.5' - use relative symlinks for shared libs - Avoid searching past window for Z_RLE strategy - Assure that high-water mark initialization is always applied in deflate - Add assertions to fill_window() in deflate.c to match comments - Update python link in README - Correct spelling error in gzread.c - Fix bug in gzgets() for a concatenated empty gzip stream - Correct error in comment for gz_make() - Change gzread() and related to ignore junk after gzip streams - Allow gzread() and related to continue after gzclearerr() - Allow gzrewind() and gzseek() after a premature end-of-file - Simplify gzseek() now that raw after gzip is ignored - Change gzgetc() to a macro for speed (~40% speedup in testing) - Fix gzclose() to return the actual error last encountered - Always add large file support for windows - Include zconf.h for windows large file support - Include zconf.h.cmakein for windows large file support - Update zconf.h.cmakein on make distclean - Merge vestigial vsnprintf determination from zutil.h to gzguts.h - Clarify how gzopen() appends in zlib.h comments - Correct documentation of gzdirect() since junk at end now ignored - Add a transparent write mode to gzopen() when 'T' is in the mode - Update python link in zlib man page - Get inffixed.h and MAKEFIXED result to match - Add a ./config --solo option to make zlib subset with no libary use - Add undocumented inflateResetKeep() function for CAB file decoding - Add --cover option to ./configure for gcc coverage testing - Add #define ZLIB_CONST option to use const in the z_stream interface - Add comment to gzdopen() in zlib.h to use dup() when using fileno() - Note behavior of uncompress() to provide as much data as it can - Add files in contrib/minizip to aid in building libminizip - Split off AR options in Makefile.in and configure - Change ON macro to Z_ARG to avoid application conflicts - Facilitate compilation with Borland C++ for pragmas and vsnprintf - Include io.h for Turbo C / Borland C++ - Move example.c and minigzip.c to test/ - Simplify incomplete code table filling in inflate_table() - Remove code from inflate.c and infback.c that is impossible to execute - Test the inflate code with full coverage - Allow deflateSetDictionary, inflateSetDictionary at any time (in raw) - Add deflateResetKeep and fix inflateResetKeep to retain dictionary - Fix gzwrite.c to accommodate reduced memory zlib compilation - Have inflate() with Z_FINISH avoid the allocation of a window - Do not set strm->adler when doing raw inflate - Fix gzeof() to behave just like feof() when read is not past end of file - Fix bug in gzread.c when end-of-file is reached - Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF - Document gzread() capability to read concurrently written files - Remove hard-coding of resource compiler in CMakeLists.txt [Blammo] Changes in 1.2.5.1 (10 Sep 2011) - Update FAQ entry on shared builds (#13) - Avoid symbolic argument to chmod in Makefile.in - Fix bug and add consts in contrib/puff [Oberhumer] - Update contrib/puff/zeros.raw test file to have all block types - Add full coverage test for puff in contrib/puff/Makefile - Fix static-only-build install in Makefile.in - Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno] - Add libz.a dependency to shared in Makefile.in for parallel builds - Spell out "number" (instead of "nb") in zlib.h for total_in, total_out - Replace $(...) with `...` in configure for non-bash sh [Bowler] - Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen] - Add solaris* to Linux* in configure to allow gcc use [Groffen] - Add *bsd* to Linux* case in configure [Bar-Lev] - Add inffast.obj to dependencies in win32/Makefile.msc - Correct spelling error in deflate.h [Kohler] - Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc - Add test to configure for GNU C looking for gcc in output of $cc -v - Add zlib.pc generation to win32/Makefile.gcc [Weigelt] - Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not - Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense - Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser) - Make stronger test in zconf.h to include unistd.h for LFS - Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack] - Fix zlib.h LFS support when Z_PREFIX used - Add updated as400 support (removed from old) [Monnerat] - Avoid deflate sensitivity to volatile input data - Avoid division in adler32_combine for NO_DIVIDE - Clarify the use of Z_FINISH with deflateBound() amount of space - Set binary for output file in puff.c - Use u4 type for crc_table to avoid conversion warnings - Apply casts in zlib.h to avoid conversion warnings - Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] - Improve inflateSync() documentation to note indeterminancy - Add deflatePending() function to return the amount of pending output - Correct the spelling of "specification" in FAQ [Randers-Pehrson] - Add a check in configure for stdarg.h, use for gzprintf() - Check that pointers fit in ints when gzprint() compiled old style - Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] - Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] - Add debug records in assmebler code [Londer] - Update RFC references to use http://tools.ietf.org/html/... [Li] - Add --archs option, use of libtool to configure for Mac OS X [Borstel] Changes in 1.2.5 (19 Apr 2010) - Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] - Default to libdir as sharedlibdir in configure [Nieder] - Update copyright dates on modified source files - Update trees.c to be able to generate modified trees.h - Exit configure for MinGW, suggesting win32/Makefile.gcc - Check for NULL path in gz_open [Homurlu] Changes in 1.2.4.5 (18 Apr 2010) - Set sharedlibdir in configure [Torok] - Set LDFLAGS in Makefile.in [Bar-Lev] - Avoid mkdir objs race condition in Makefile.in [Bowler] - Add ZLIB_INTERNAL in front of internal inter-module functions and arrays - Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C - Don't use hidden attribute when it is a warning generator (e.g. Solaris) Changes in 1.2.4.4 (18 Apr 2010) - Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok] - Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty - Try to use bash or ksh regardless of functionality of /bin/sh - Fix configure incompatibility with NetBSD sh - Remove attempt to run under bash or ksh since have better NetBSD fix - Fix win32/Makefile.gcc for MinGW [Bar-Lev] - Add diagnostic messages when using CROSS_PREFIX in configure - Added --sharedlibdir option to configure [Weigelt] - Use hidden visibility attribute when available [Frysinger] Changes in 1.2.4.3 (10 Apr 2010) - Only use CROSS_PREFIX in configure for ar and ranlib if they exist - Use CROSS_PREFIX for nm [Bar-Lev] - Assume _LARGEFILE64_SOURCE defined is equivalent to true - Avoid use of undefined symbols in #if with && and || - Make *64 prototypes in gzguts.h consistent with functions - Add -shared load option for MinGW in configure [Bowler] - Move z_off64_t to public interface, use instead of off64_t - Remove ! from shell test in configure (not portable to Solaris) - Change +0 macro tests to -0 for possibly increased portability Changes in 1.2.4.2 (9 Apr 2010) - Add consistent carriage returns to readme.txt's in masmx86 and masmx64 - Really provide prototypes for *64 functions when building without LFS - Only define unlink() in minigzip.c if unistd.h not included - Update README to point to contrib/vstudio project files - Move projects/vc6 to old/ and remove projects/ - Include stdlib.h in minigzip.c for setmode() definition under WinCE - Clean up assembler builds in win32/Makefile.msc [Rowe] - Include sys/types.h for Microsoft for off_t definition - Fix memory leak on error in gz_open() - Symbolize nm as $NM in configure [Weigelt] - Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt] - Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined - Fix bug in gzeof() to take into account unused input data - Avoid initialization of structures with variables in puff.c - Updated win32/README-WIN32.txt [Rowe] Changes in 1.2.4.1 (28 Mar 2010) - Remove the use of [a-z] constructs for sed in configure [gentoo 310225] - Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech] - Restore "for debugging" comment on sprintf() in gzlib.c - Remove fdopen for MVS from gzguts.h - Put new README-WIN32.txt in win32 [Rowe] - Add check for shell to configure and invoke another shell if needed - Fix big fat stinking bug in gzseek() on uncompressed files - Remove vestigial F_OPEN64 define in zutil.h - Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE - Avoid errors on non-LFS systems when applications define LFS macros - Set EXE to ".exe" in configure for MINGW [Kahle] - Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill] - Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev] - Add DLL install in win32/makefile.gcc [Bar-Lev] - Allow Linux* or linux* from uname in configure [Bar-Lev] - Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev] - Add cross-compilation prefixes to configure [Bar-Lev] - Match type exactly in gz_load() invocation in gzread.c - Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func - Provide prototypes for *64 functions when building zlib without LFS - Don't use -lc when linking shared library on MinGW - Remove errno.h check in configure and vestigial errno code in zutil.h Changes in 1.2.4 (14 Mar 2010) - Fix VER3 extraction in configure for no fourth subversion - Update zlib.3, add docs to Makefile.in to make .pdf out of it - Add zlib.3.pdf to distribution - Don't set error code in gzerror() if passed pointer is NULL - Apply destination directory fixes to CMakeLists.txt [Lowman] - Move #cmakedefine's to a new zconf.in.cmakein - Restore zconf.h for builds that don't use configure or cmake - Add distclean to dummy Makefile for convenience - Update and improve INDEX, README, and FAQ - Update CMakeLists.txt for the return of zconf.h [Lowman] - Update contrib/vstudio/vc9 and vc10 [Vollant] - Change libz.dll.a back to libzdll.a in win32/Makefile.gcc - Apply license and readme changes to contrib/asm686 [Raiter] - Check file name lengths and add -c option in minigzip.c [Li] - Update contrib/amd64 and contrib/masmx86/ [Vollant] - Avoid use of "eof" parameter in trees.c to not shadow library variable - Update make_vms.com for removal of zlibdefs.h [Zinser] - Update assembler code and vstudio projects in contrib [Vollant] - Remove outdated assembler code contrib/masm686 and contrib/asm586 - Remove old vc7 and vc8 from contrib/vstudio - Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe] - Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open() - Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant] - Remove *64 functions from win32/zlib.def (they're not 64-bit yet) - Fix bug in void-returning vsprintf() case in gzwrite.c - Fix name change from inflate.h in contrib/inflate86/inffas86.c - Check if temporary file exists before removing in make_vms.com [Zinser] - Fix make install and uninstall for --static option - Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta] - Update readme.txt in contrib/masmx64 and masmx86 to assemble Changes in 1.2.3.9 (21 Feb 2010) - Expunge gzio.c - Move as400 build information to old - Fix updates in contrib/minizip and contrib/vstudio - Add const to vsnprintf test in configure to avoid warnings [Weigelt] - Delete zconf.h (made by configure) [Weigelt] - Change zconf.in.h to zconf.h.in per convention [Weigelt] - Check for NULL buf in gzgets() - Return empty string for gzgets() with len == 1 (like fgets()) - Fix description of gzgets() in zlib.h for end-of-file, NULL return - Update minizip to 1.1 [Vollant] - Avoid MSVC loss of data warnings in gzread.c, gzwrite.c - Note in zlib.h that gzerror() should be used to distinguish from EOF - Remove use of snprintf() from gzlib.c - Fix bug in gzseek() - Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant] - Fix zconf.h generation in CMakeLists.txt [Lowman] - Improve comments in zconf.h where modified by configure Changes in 1.2.3.8 (13 Feb 2010) - Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer] - Use z_off64_t in gz_zero() and gz_skip() to match state->skip - Avoid comparison problem when sizeof(int) == sizeof(z_off64_t) - Revert to Makefile.in from 1.2.3.6 (live with the clutter) - Fix missing error return in gzflush(), add zlib.h note - Add *64 functions to zlib.map [Levin] - Fix signed/unsigned comparison in gz_comp() - Use SFLAGS when testing shared linking in configure - Add --64 option to ./configure to use -m64 with gcc - Fix ./configure --help to correctly name options - Have make fail if a test fails [Levin] - Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson] - Remove assembler object files from contrib Changes in 1.2.3.7 (24 Jan 2010) - Always gzopen() with O_LARGEFILE if available - Fix gzdirect() to work immediately after gzopen() or gzdopen() - Make gzdirect() more precise when the state changes while reading - Improve zlib.h documentation in many places - Catch memory allocation failure in gz_open() - Complete close operation if seek forward in gzclose_w() fails - Return Z_ERRNO from gzclose_r() if close() fails - Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL - Return zero for gzwrite() errors to match zlib.h description - Return -1 on gzputs() error to match zlib.h description - Add zconf.in.h to allow recovery from configure modification [Weigelt] - Fix static library permissions in Makefile.in [Weigelt] - Avoid warnings in configure tests that hide functionality [Weigelt] - Add *BSD and DragonFly to Linux case in configure [gentoo 123571] - Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212] - Avoid access of uninitialized data for first inflateReset2 call [Gomes] - Keep object files in subdirectories to reduce the clutter somewhat - Remove default Makefile and zlibdefs.h, add dummy Makefile - Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_ - Remove zlibdefs.h completely -- modify zconf.h instead Changes in 1.2.3.6 (17 Jan 2010) - Avoid void * arithmetic in gzread.c and gzwrite.c - Make compilers happier with const char * for gz_error message - Avoid unused parameter warning in inflate.c - Avoid signed-unsigned comparison warning in inflate.c - Indent #pragma's for traditional C - Fix usage of strwinerror() in glib.c, change to gz_strwinerror() - Correct email address in configure for system options - Update make_vms.com and add make_vms.com to contrib/minizip [Zinser] - Update zlib.map [Brown] - Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok] - Apply various fixes to CMakeLists.txt [Lowman] - Add checks on len in gzread() and gzwrite() - Add error message for no more room for gzungetc() - Remove zlib version check in gzwrite() - Defer compression of gzprintf() result until need to - Use snprintf() in gzdopen() if available - Remove USE_MMAP configuration determination (only used by minigzip) - Remove examples/pigz.c (available separately) - Update examples/gun.c to 1.6 Changes in 1.2.3.5 (8 Jan 2010) - Add space after #if in zutil.h for some compilers - Fix relatively harmless bug in deflate_fast() [Exarevsky] - Fix same problem in deflate_slow() - Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown] - Add deflate_rle() for faster Z_RLE strategy run-length encoding - Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding - Change name of "write" variable in inffast.c to avoid library collisions - Fix premature EOF from gzread() in gzio.c [Brown] - Use zlib header window size if windowBits is 0 in inflateInit2() - Remove compressBound() call in deflate.c to avoid linking compress.o - Replace use of errno in gz* with functions, support WinCE [Alves] - Provide alternative to perror() in minigzip.c for WinCE [Alves] - Don't use _vsnprintf on later versions of MSVC [Lowman] - Add CMake build script and input file [Lowman] - Update contrib/minizip to 1.1 [Svensson, Vollant] - Moved nintendods directory from contrib to . - Replace gzio.c with a new set of routines with the same functionality - Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above - Update contrib/minizip to 1.1b - Change gzeof() to return 0 on error instead of -1 to agree with zlib.h Changes in 1.2.3.4 (21 Dec 2009) - Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility - Update comments in configure and Makefile.in for default --shared - Fix test -z's in configure [Marquess] - Build examplesh and minigzipsh when not testing - Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h - Import LDFLAGS from the environment in configure - Fix configure to populate SFLAGS with discovered CFLAGS options - Adapt make_vms.com to the new Makefile.in [Zinser] - Add zlib2ansi script for C++ compilation [Marquess] - Add _FILE_OFFSET_BITS=64 test to make test (when applicable) - Add AMD64 assembler code for longest match to contrib [Teterin] - Include options from $SFLAGS when doing $LDSHARED - Simplify 64-bit file support by introducing z_off64_t type - Make shared object files in objs directory to work around old Sun cc - Use only three-part version number for Darwin shared compiles - Add rc option to ar in Makefile.in for when ./configure not run - Add -WI,-rpath,. to LDFLAGS for OSF 1 V4* - Set LD_LIBRARYN32_PATH for SGI IRIX shared compile - Protect against _FILE_OFFSET_BITS being defined when compiling zlib - Rename Makefile.in targets allstatic to static and allshared to shared - Fix static and shared Makefile.in targets to be independent - Correct error return bug in gz_open() by setting state [Brown] - Put spaces before ;;'s in configure for better sh compatibility - Add pigz.c (parallel implementation of gzip) to examples/ - Correct constant in crc32.c to UL [Leventhal] - Reject negative lengths in crc32_combine() - Add inflateReset2() function to work like inflateEnd()/inflateInit2() - Include sys/types.h for _LARGEFILE64_SOURCE [Brown] - Correct typo in doc/algorithm.txt [Janik] - Fix bug in adler32_combine() [Zhu] - Catch missing-end-of-block-code error in all inflates and in puff Assures that random input to inflate eventually results in an error - Added enough.c (calculation of ENOUGH for inftrees.h) to examples/ - Update ENOUGH and its usage to reflect discovered bounds - Fix gzerror() error report on empty input file [Brown] - Add ush casts in trees.c to avoid pedantic runtime errors - Fix typo in zlib.h uncompress() description [Reiss] - Correct inflate() comments with regard to automatic header detection - Remove deprecation comment on Z_PARTIAL_FLUSH (it stays) - Put new version of gzlog (2.0) in examples with interruption recovery - Add puff compile option to permit invalid distance-too-far streams - Add puff TEST command options, ability to read piped input - Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but _LARGEFILE64_SOURCE not defined - Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart - Fix deflateSetDictionary() to use all 32K for output consistency - Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h) - Clear bytes after deflate lookahead to avoid use of uninitialized data - Change a limit in inftrees.c to be more transparent to Coverity Prevent - Update win32/zlib.def with exported symbols from zlib.h - Correct spelling errors in zlib.h [Willem, Sobrado] - Allow Z_BLOCK for deflate() to force a new block - Allow negative bits in inflatePrime() to delete existing bit buffer - Add Z_TREES flush option to inflate() to return at end of trees - Add inflateMark() to return current state information for random access - Add Makefile for NintendoDS to contrib [Costa] - Add -w in configure compile tests to avoid spurious warnings [Beucler] - Fix typos in zlib.h comments for deflateSetDictionary() - Fix EOF detection in transparent gzread() [Maier] Changes in 1.2.3.3 (2 October 2006) - Make --shared the default for configure, add a --static option - Add compile option to permit invalid distance-too-far streams - Add inflateUndermine() function which is required to enable above - Remove use of "this" variable name for C++ compatibility [Marquess] - Add testing of shared library in make test, if shared library built - Use ftello() and fseeko() if available instead of ftell() and fseek() - Provide two versions of all functions that use the z_off_t type for binary compatibility -- a normal version and a 64-bit offset version, per the Large File Support Extension when _LARGEFILE64_SOURCE is defined; use the 64-bit versions by default when _FILE_OFFSET_BITS is defined to be 64 - Add a --uname= option to configure to perhaps help with cross-compiling Changes in 1.2.3.2 (3 September 2006) - Turn off silly Borland warnings [Hay] - Use off64_t and define _LARGEFILE64_SOURCE when present - Fix missing dependency on inffixed.h in Makefile.in - Rig configure --shared to build both shared and static [Teredesai, Truta] - Remove zconf.in.h and instead create a new zlibdefs.h file - Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant] - Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt] Changes in 1.2.3.1 (16 August 2006) - Add watcom directory with OpenWatcom make files [Daniel] - Remove #undef of FAR in zconf.in.h for MVS [Fedtke] - Update make_vms.com [Zinser] - Use -fPIC for shared build in configure [Teredesai, Nicholson] - Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen] - Use fdopen() (not _fdopen()) for Interix in zutil.h [Bck] - Add some FAQ entries about the contrib directory - Update the MVS question in the FAQ - Avoid extraneous reads after EOF in gzio.c [Brown] - Correct spelling of "successfully" in gzio.c [Randers-Pehrson] - Add comments to zlib.h about gzerror() usage [Brown] - Set extra flags in gzip header in gzopen() like deflate() does - Make configure options more compatible with double-dash conventions [Weigelt] - Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen] - Fix uninstall target in Makefile.in [Truta] - Add pkgconfig support [Weigelt] - Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt] - Replace set_data_type() with a more accurate detect_data_type() in trees.c, according to the txtvsbin.txt document [Truta] - Swap the order of #include and #include "zlib.h" in gzio.c, example.c and minigzip.c [Truta] - Shut up annoying VS2005 warnings about standard C deprecation [Rowe, Truta] (where?) - Fix target "clean" from win32/Makefile.bor [Truta] - Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe] - Update zlib www home address in win32/DLL_FAQ.txt [Truta] - Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove] - Enable browse info in the "Debug" and "ASM Debug" configurations in the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta] - Add pkgconfig support [Weigelt] - Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h, for use in win32/zlib1.rc [Polushin, Rowe, Truta] - Add a document that explains the new text detection scheme to doc/txtvsbin.txt [Truta] - Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta] - Move algorithm.txt into doc/ [Truta] - Synchronize FAQ with website - Fix compressBound(), was low for some pathological cases [Fearnley] - Take into account wrapper variations in deflateBound() - Set examples/zpipe.c input and output to binary mode for Windows - Update examples/zlib_how.html with new zpipe.c (also web site) - Fix some warnings in examples/gzlog.c and examples/zran.c (it seems that gcc became pickier in 4.0) - Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain un-versioned, the patch adds versioning only for symbols introduced in zlib-1.2.0 or later. It also declares as local those symbols which are not designed to be exported." [Levin] - Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure - Do not initialize global static by default in trees.c, add a response NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess] - Don't use strerror() in gzio.c under WinCE [Yakimov] - Don't use errno.h in zutil.h under WinCE [Yakimov] - Move arguments for AR to its usage to allow replacing ar [Marot] - Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson] - Improve inflateInit() and inflateInit2() documentation - Fix structure size comment in inflate.h - Change configure help option from --h* to --help [Santos] Changes in 1.2.3 (18 July 2005) - Apply security vulnerability fixes to contrib/infback9 as well - Clean up some text files (carriage returns, trailing space) - Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] Changes in 1.2.2.4 (11 July 2005) - Add inflatePrime() function for starting inflation at bit boundary - Avoid some Visual C warnings in deflate.c - Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit compile - Fix some spelling errors in comments [Betts] - Correct inflateInit2() error return documentation in zlib.h - Add zran.c example of compressed data random access to examples directory, shows use of inflatePrime() - Fix cast for assignments to strm->state in inflate.c and infback.c - Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] - Move declarations of gf2 functions to right place in crc32.c [Oberhumer] - Add cast in trees.c t avoid a warning [Oberhumer] - Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] - Update make_vms.com [Zinser] - Initialize state->write in inflateReset() since copied in inflate_fast() - Be more strict on incomplete code sets in inflate_table() and increase ENOUGH and MAXD -- this repairs a possible security vulnerability for invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for discovering the vulnerability and providing test cases. - Add ia64 support to configure for HP-UX [Smith] - Add error return to gzread() for format or i/o error [Levin] - Use malloc.h for OS/2 [Necasek] Changes in 1.2.2.3 (27 May 2005) - Replace 1U constants in inflate.c and inftrees.c for 64-bit compile - Typecast fread() return values in gzio.c [Vollant] - Remove trailing space in minigzip.c outmode (VC++ can't deal with it) - Fix crc check bug in gzread() after gzungetc() [Heiner] - Add the deflateTune() function to adjust internal compression parameters - Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) - Remove an incorrect assertion in examples/zpipe.c - Add C++ wrapper in infback9.h [Donais] - Fix bug in inflateCopy() when decoding fixed codes - Note in zlib.h how much deflateSetDictionary() actually uses - Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) - Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] - Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] - Add gzdirect() function to indicate transparent reads - Update contrib/minizip [Vollant] - Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] - Add casts in crc32.c to avoid warnings [Oberhumer] - Add contrib/masmx64 [Vollant] - Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] Changes in 1.2.2.2 (30 December 2004) - Replace structure assignments in deflate.c and inflate.c with zmemcpy to avoid implicit memcpy calls (portability for no-library compilation) - Increase sprintf() buffer size in gzdopen() to allow for large numbers - Add INFLATE_STRICT to check distances against zlib header - Improve WinCE errno handling and comments [Chang] - Remove comment about no gzip header processing in FAQ - Add Z_FIXED strategy option to deflateInit2() to force fixed trees - Add updated make_vms.com [Coghlan], update README - Create a new "examples" directory, move gzappend.c there, add zpipe.c, fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. - Add FAQ entry and comments in deflate.c on uninitialized memory access - Add Solaris 9 make options in configure [Gilbert] - Allow strerror() usage in gzio.c for STDC - Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] - Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] - Use z_off_t for adler32_combine() and crc32_combine() lengths - Make adler32() much faster for small len - Use OS_CODE in deflate() default gzip header Changes in 1.2.2.1 (31 October 2004) - Allow inflateSetDictionary() call for raw inflate - Fix inflate header crc check bug for file names and comments - Add deflateSetHeader() and gz_header structure for custom gzip headers - Add inflateGetheader() to retrieve gzip headers - Add crc32_combine() and adler32_combine() functions - Add alloc_func, free_func, in_func, out_func to Z_PREFIX list - Use zstreamp consistently in zlib.h (inflate_back functions) - Remove GUNZIP condition from definition of inflate_mode in inflate.h and in contrib/inflate86/inffast.S [Truta, Anderson] - Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] - Update projects/README.projects and projects/visualc6 [Truta] - Update win32/DLL_FAQ.txt [Truta] - Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] - Deprecate Z_ASCII; use Z_TEXT instead [Truta] - Use a new algorithm for setting strm->data_type in trees.c [Truta] - Do not define an exit() prototype in zutil.c unless DEBUG defined - Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] - Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() - Fix Darwin build version identification [Peterson] Changes in 1.2.2 (3 October 2004) - Update zlib.h comments on gzip in-memory processing - Set adler to 1 in inflateReset() to support Java test suite [Walles] - Add contrib/dotzlib [Ravn] - Update win32/DLL_FAQ.txt [Truta] - Update contrib/minizip [Vollant] - Move contrib/visual-basic.txt to old/ [Truta] - Fix assembler builds in projects/visualc6/ [Truta] Changes in 1.2.1.2 (9 September 2004) - Update INDEX file - Fix trees.c to update strm->data_type (no one ever noticed!) - Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] - Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) - Add limited multitasking protection to DYNAMIC_CRC_TABLE - Add NO_vsnprintf for VMS in zutil.h [Mozilla] - Don't declare strerror() under VMS [Mozilla] - Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize - Update contrib/ada [Anisimkov] - Update contrib/minizip [Vollant] - Fix configure to not hardcode directories for Darwin [Peterson] - Fix gzio.c to not return error on empty files [Brown] - Fix indentation; update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas [Truta] - Update mkasm.bat in contrib/masmx86 [Truta] - Update contrib/untgz [Truta] - Add projects/README.projects [Truta] - Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] - Update win32/DLL_FAQ.txt [Truta] - Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] - Remove an unnecessary assignment to curr in inftrees.c [Truta] - Add OS/2 to exe builds in configure [Poltorak] - Remove err dummy parameter in zlib.h [Kientzle] Changes in 1.2.1.1 (9 January 2004) - Update email address in README - Several FAQ updates - Fix a big fat bug in inftrees.c that prevented decoding valid dynamic blocks with only literals and no distance codes -- Thanks to "Hot Emu" for the bug report and sample file - Add a note to puff.c on no distance codes case. Changes in 1.2.1 (17 November 2003) - Remove a tab in contrib/gzappend/gzappend.c - Update some interfaces in contrib for new zlib functions - Update zlib version number in some contrib entries - Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] - Support shared libraries on Hurd and KFreeBSD [Brown] - Fix error in NO_DIVIDE option of adler32.c Changes in 1.2.0.8 (4 November 2003) - Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas - Add experimental NO_DIVIDE #define in adler32.c - Possibly faster on some processors (let me know if it is) - Correct Z_BLOCK to not return on first inflate call if no wrap - Fix strm->data_type on inflate() return to correctly indicate EOB - Add deflatePrime() function for appending in the middle of a byte - Add contrib/gzappend for an example of appending to a stream - Update win32/DLL_FAQ.txt [Truta] - Delete Turbo C comment in README [Truta] - Improve some indentation in zconf.h [Truta] - Fix infinite loop on bad input in configure script [Church] - Fix gzeof() for concatenated gzip files [Johnson] - Add example to contrib/visual-basic.txt [Michael B.] - Add -p to mkdir's in Makefile.in [vda] - Fix configure to properly detect presence or lack of printf functions - Add AS400 support [Monnerat] - Add a little Cygwin support [Wilson] Changes in 1.2.0.7 (21 September 2003) - Correct some debug formats in contrib/infback9 - Cast a type in a debug statement in trees.c - Change search and replace delimiter in configure from % to # [Beebe] - Update contrib/untgz to 0.2 with various fixes [Truta] - Add build support for Amiga [Nikl] - Remove some directories in old that have been updated to 1.2 - Add dylib building for Mac OS X in configure and Makefile.in - Remove old distribution stuff from Makefile - Update README to point to DLL_FAQ.txt, and add comment on Mac OS X - Update links in README Changes in 1.2.0.6 (13 September 2003) - Minor FAQ updates - Update contrib/minizip to 1.00 [Vollant] - Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] - Update POSTINC comment for 68060 [Nikl] - Add contrib/infback9 with deflate64 decoding (unsupported) - For MVS define NO_vsnprintf and undefine FAR [van Burik] - Add pragma for fdopen on MVS [van Burik] Changes in 1.2.0.5 (8 September 2003) - Add OF to inflateBackEnd() declaration in zlib.h - Remember start when using gzdopen in the middle of a file - Use internal off_t counters in gz* functions to properly handle seeks - Perform more rigorous check for distance-too-far in inffast.c - Add Z_BLOCK flush option to return from inflate at block boundary - Set strm->data_type on return from inflate - Indicate bits unused, if at block boundary, and if in last block - Replace size_t with ptrdiff_t in crc32.c, and check for correct size - Add condition so old NO_DEFLATE define still works for compatibility - FAQ update regarding the Windows DLL [Truta] - INDEX update: add qnx entry, remove aix entry [Truta] - Install zlib.3 into mandir [Wilson] - Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] - Adapt the zlib interface to the new DLL convention guidelines [Truta] - Introduce ZLIB_WINAPI macro to allow the export of functions using the WINAPI calling convention, for Visual Basic [Vollant, Truta] - Update msdos and win32 scripts and makefiles [Truta] - Export symbols by name, not by ordinal, in win32/zlib.def [Truta] - Add contrib/ada [Anisimkov] - Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] - Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] - Add contrib/masm686 [Truta] - Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm [Truta, Vollant] - Update contrib/delphi; rename to contrib/pascal; add example [Truta] - Remove contrib/delphi2; add a new contrib/delphi [Truta] - Avoid inclusion of the nonstandard in contrib/iostream, and fix some method prototypes [Truta] - Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip [Truta] - Avoid the use of backslash (\) in contrib/minizip [Vollant] - Fix file time handling in contrib/untgz; update makefiles [Truta] - Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines [Vollant] - Remove contrib/vstudio/vc15_16 [Vollant] - Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] - Update README.contrib [Truta] - Invert the assignment order of match_head and s->prev[...] in INSERT_STRING [Truta] - Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings [Truta] - Compare function pointers with 0, not with NULL or Z_NULL [Truta] - Fix prototype of syncsearch in inflate.c [Truta] - Introduce ASMINF macro to be enabled when using an ASM implementation of inflate_fast [Truta] - Change NO_DEFLATE to NO_GZCOMPRESS [Truta] - Modify test_gzio in example.c to take a single file name as a parameter [Truta] - Exit the example.c program if gzopen fails [Truta] - Add type casts around strlen in example.c [Truta] - Remove casting to sizeof in minigzip.c; give a proper type to the variable compared with SUFFIX_LEN [Truta] - Update definitions of STDC and STDC99 in zconf.h [Truta] - Synchronize zconf.h with the new Windows DLL interface [Truta] - Use SYS16BIT instead of __32BIT__ to distinguish between 16- and 32-bit platforms [Truta] - Use far memory allocators in small 16-bit memory models for Turbo C [Truta] - Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in zlibCompileFlags [Truta] - Cygwin has vsnprintf [Wilson] - In Windows16, OS_CODE is 0, as in MSDOS [Truta] - In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] Changes in 1.2.0.4 (10 August 2003) - Minor FAQ updates - Be more strict when checking inflateInit2's windowBits parameter - Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well - Add gzip wrapper option to deflateInit2 using windowBits - Add updated QNX rule in configure and qnx directory [Bonnefoy] - Make inflate distance-too-far checks more rigorous - Clean up FAR usage in inflate - Add casting to sizeof() in gzio.c and minigzip.c Changes in 1.2.0.3 (19 July 2003) - Fix silly error in gzungetc() implementation [Vollant] - Update contrib/minizip and contrib/vstudio [Vollant] - Fix printf format in example.c - Correct cdecl support in zconf.in.h [Anisimkov] - Minor FAQ updates Changes in 1.2.0.2 (13 July 2003) - Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons - Attempt to avoid warnings in crc32.c for pointer-int conversion - Add AIX to configure, remove aix directory [Bakker] - Add some casts to minigzip.c - Improve checking after insecure sprintf() or vsprintf() calls - Remove #elif's from crc32.c - Change leave label to inf_leave in inflate.c and infback.c to avoid library conflicts - Remove inflate gzip decoding by default--only enable gzip decoding by special request for stricter backward compatibility - Add zlibCompileFlags() function to return compilation information - More typecasting in deflate.c to avoid warnings - Remove leading underscore from _Capital #defines [Truta] - Fix configure to link shared library when testing - Add some Windows CE target adjustments [Mai] - Remove #define ZLIB_DLL in zconf.h [Vollant] - Add zlib.3 [Rodgers] - Update RFC URL in deflate.c and algorithm.txt [Mai] - Add zlib_dll_FAQ.txt to contrib [Truta] - Add UL to some constants [Truta] - Update minizip and vstudio [Vollant] - Remove vestigial NEED_DUMMY_RETURN from zconf.in.h - Expand use of NO_DUMMY_DECL to avoid all dummy structures - Added iostream3 to contrib [Schwardt] - Replace rewind() with fseek() for WinCE [Truta] - Improve setting of zlib format compression level flags - Report 0 for huffman and rle strategies and for level == 0 or 1 - Report 2 only for level == 6 - Only deal with 64K limit when necessary at compile time [Truta] - Allow TOO_FAR check to be turned off at compile time [Truta] - Add gzclearerr() function [Souza] - Add gzungetc() function Changes in 1.2.0.1 (17 March 2003) - Add Z_RLE strategy for run-length encoding [Truta] - When Z_RLE requested, restrict matches to distance one - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE - Correct FASTEST compilation to allow level == 0 - Clean up what gets compiled for FASTEST - Incorporate changes to zconf.in.h [Vollant] - Refine detection of Turbo C need for dummy returns - Refine ZLIB_DLL compilation - Include additional header file on VMS for off_t typedef - Try to use _vsnprintf where it supplants vsprintf [Vollant] - Add some casts in inffast.c - Enchance comments in zlib.h on what happens if gzprintf() tries to write more than 4095 bytes before compression - Remove unused state from inflateBackEnd() - Remove exit(0) from minigzip.c, example.c - Get rid of all those darn tabs - Add "check" target to Makefile.in that does the same thing as "test" - Add "mostlyclean" and "maintainer-clean" targets to Makefile.in - Update contrib/inflate86 [Anderson] - Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] - Add msdos and win32 directories with makefiles [Truta] - More additions and improvements to the FAQ Changes in 1.2.0 (9 March 2003) - New and improved inflate code - About 20% faster - Does not allocate 32K window unless and until needed - Automatically detects and decompresses gzip streams - Raw inflate no longer needs an extra dummy byte at end - Added inflateBack functions using a callback interface--even faster than inflate, useful for file utilities (gzip, zip) - Added inflateCopy() function to record state for random access on externally generated deflate streams (e.g. in gzip files) - More readable code (I hope) - New and improved crc32() - About 50% faster, thanks to suggestions from Rodney Brown - Add deflateBound() and compressBound() functions - Fix memory leak in deflateInit2() - Permit setting dictionary for raw deflate (for parallel deflate) - Fix const declaration for gzwrite() - Check for some malloc() failures in gzio.c - Fix bug in gzopen() on single-byte file 0x1f - Fix bug in gzread() on concatenated file with 0x1f at end of buffer and next buffer doesn't start with 0x8b - Fix uncompress() to return Z_DATA_ERROR on truncated input - Free memory at end of example.c - Remove MAX #define in trees.c (conflicted with some libraries) - Fix static const's in deflate.c, gzio.c, and zutil.[ch] - Declare malloc() and free() in gzio.c if STDC not defined - Use malloc() instead of calloc() in zutil.c if int big enough - Define STDC for AIX - Add aix/ with approach for compiling shared library on AIX - Add HP-UX support for shared libraries in configure - Add OpenUNIX support for shared libraries in configure - Use $cc instead of gcc to build shared library - Make prefix directory if needed when installing - Correct Macintosh avoidance of typedef Byte in zconf.h - Correct Turbo C memory allocation when under Linux - Use libz.a instead of -lz in Makefile (assure use of compiled library) - Update configure to check for snprintf or vsnprintf functions and their return value, warn during make if using an insecure function - Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that is lost when library is used--resolution is to build new zconf.h - Documentation improvements (in zlib.h): - Document raw deflate and inflate - Update RFCs URL - Point out that zlib and gzip formats are different - Note that Z_BUF_ERROR is not fatal - Document string limit for gzprintf() and possible buffer overflow - Note requirement on avail_out when flushing - Note permitted values of flush parameter of inflate() - Add some FAQs (and even answers) to the FAQ - Add contrib/inflate86/ for x86 faster inflate - Add contrib/blast/ for PKWare Data Compression Library decompression - Add contrib/puff/ simple inflate for deflate format description Changes in 1.1.4 (11 March 2002) - ZFREE was repeated on same allocation on some error conditions. This creates a security problem described in http://www.zlib.org/advisory-2002-03-11.txt - Returned incorrect error (Z_MEM_ERROR) on some invalid data - Avoid accesses before window for invalid distances with inflate window less than 32K. - force windowBits > 8 to avoid a bug in the encoder for a window size of 256 bytes. (A complete fix will be available in 1.1.5). Changes in 1.1.3 (9 July 1998) - fix "an inflate input buffer bug that shows up on rare but persistent occasions" (Mark) - fix gzread and gztell for concatenated .gz files (Didier Le Botlan) - fix gzseek(..., SEEK_SET) in write mode - fix crc check after a gzeek (Frank Faubert) - fix miniunzip when the last entry in a zip file is itself a zip file (J Lillge) - add contrib/asm586 and contrib/asm686 (Brian Raiter) See http://www.muppetlabs.com/~breadbox/software/assembly.html - add support for Delphi 3 in contrib/delphi (Bob Dellaca) - add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) - do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) - use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) - added a FAQ file - Support gzdopen on Mac with Metrowerks (Jason Linhart) - Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) - define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) - avoid some warnings with Borland C (Tom Tanner) - fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) - emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) - allow several arguments to configure (Tim Mooney, Frodo Looijaard) - use libdir and includedir in Makefile.in (Tim Mooney) - support shared libraries on OSF1 V4 (Tim Mooney) - remove so_locations in "make clean" (Tim Mooney) - fix maketree.c compilation error (Glenn, Mark) - Python interface to zlib now in Python 1.5 (Jeremy Hylton) - new Makefile.riscos (Rich Walker) - initialize static descriptors in trees.c for embedded targets (Nick Smith) - use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) - add the OS/2 files in Makefile.in too (Andrew Zabolotny) - fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) - fix maketree.c to allow clean compilation of inffixed.h (Mark) - fix parameter check in deflateCopy (Gunther Nikl) - cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) - Many portability patches by Christian Spieler: . zutil.c, zutil.h: added "const" for zmem* . Make_vms.com: fixed some typos . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists . msdos/Makefile.msc: remove "default rtl link library" info from obj files . msdos/Makefile.*: use model-dependent name for the built zlib library . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) - use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) - replace __far with _far for better portability (Christian Spieler, Tom Lane) - fix test for errno.h in configure (Tim Newsham) Changes in 1.1.2 (19 March 98) - added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) See http://www.winimage.com/zLibDll/unzip.html - preinitialize the inflate tables for fixed codes, to make the code completely thread safe (Mark) - some simplifications and slight speed-up to the inflate code (Mark) - fix gzeof on non-compressed files (Allan Schrum) - add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) - use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) - added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) - add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) - do not wrap extern "C" around system includes (Tom Lane) - mention zlib binding for TCL in README (Andreas Kupries) - added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) - allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) - allow "configure --prefix $HOME" (Tim Mooney) - remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) - move Makefile.sas to amiga/Makefile.sas Changes in 1.1.1 (27 Feb 98) - fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) - remove block truncation heuristic which had very marginal effect for zlib (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the compression ratio on some files. This also allows inlining _tr_tally for matches in deflate_slow. - added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) Changes in 1.1.0 (24 Feb 98) - do not return STREAM_END prematurely in inflate (John Bowler) - revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) - compile with -DFASTEST to get compression code optimized for speed only - in minigzip, try mmap'ing the input file first (Miguel Albrecht) - increase size of I/O buffers in minigzip.c and gzio.c (not a big gain on Sun but significant on HP) - add a pointer to experimental unzip library in README (Gilles Vollant) - initialize variable gcc in configure (Chris Herborth) Changes in 1.0.9 (17 Feb 1998) - added gzputs and gzgets functions - do not clear eof flag in gzseek (Mark Diekhans) - fix gzseek for files in transparent mode (Mark Diekhans) - do not assume that vsprintf returns the number of bytes written (Jens Krinke) - replace EXPORT with ZEXPORT to avoid conflict with other programs - added compress2 in zconf.h, zlib.def, zlib.dnt - new asm code from Gilles Vollant in contrib/asm386 - simplify the inflate code (Mark): . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() . ZALLOC the length list in inflate_trees_fixed() instead of using stack . ZALLOC the value area for huft_build() instead of using stack . Simplify Z_FINISH check in inflate() - Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 - in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) - in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with the declaration of FAR (Gilles VOllant) - install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) - read_buf buf parameter of type Bytef* instead of charf* - zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) - do not redeclare unlink in minigzip.c for WIN32 (John Bowler) - fix check for presence of directories in "make install" (Ian Willis) Changes in 1.0.8 (27 Jan 1998) - fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) - fix gzgetc and gzputc for big endian systems (Markus Oberhumer) - added compress2() to allow setting the compression level - include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) - use constant arrays for the static trees in trees.c instead of computing them at run time (thanks to Ken Raeburn for this suggestion). To create trees.h, compile with GEN_TREES_H and run "make test". - check return code of example in "make test" and display result - pass minigzip command line options to file_compress - simplifying code of inflateSync to avoid gcc 2.8 bug - support CC="gcc -Wall" in configure -s (QingLong) - avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) - fix test for shared library support to avoid compiler warnings - zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) - check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) - do not use fdopen for Metrowerks on Mac (Brad Pettit)) - add checks for gzputc and gzputc in example.c - avoid warnings in gzio.c and deflate.c (Andreas Kleinert) - use const for the CRC table (Ken Raeburn) - fixed "make uninstall" for shared libraries - use Tracev instead of Trace in infblock.c - in example.c use correct compressed length for test_sync - suppress +vnocompatwarnings in configure for HPUX (not always supported) Changes in 1.0.7 (20 Jan 1998) - fix gzseek which was broken in write mode - return error for gzseek to negative absolute position - fix configure for Linux (Chun-Chung Chen) - increase stack space for MSC (Tim Wegner) - get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) - define EXPORTVA for gzprintf (Gilles Vollant) - added man page zlib.3 (Rick Rodgers) - for contrib/untgz, fix makedir() and improve Makefile - check gzseek in write mode in example.c - allocate extra buffer for seeks only if gzseek is actually called - avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) - add inflateSyncPoint in zconf.h - fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def Changes in 1.0.6 (19 Jan 1998) - add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) - Fix a deflate bug occurring only with compression level 0 (thanks to Andy Buckler for finding this one). - In minigzip, pass transparently also the first byte for .Z files. - return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() - check Z_FINISH in inflate (thanks to Marc Schluper) - Implement deflateCopy (thanks to Adam Costello) - make static libraries by default in configure, add --shared option. - move MSDOS or Windows specific files to directory msdos - suppress the notion of partial flush to simplify the interface (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) - suppress history buffer provided by application to simplify the interface (this feature was not implemented anyway in 1.0.4) - next_in and avail_in must be initialized before calling inflateInit or inflateInit2 - add EXPORT in all exported functions (for Windows DLL) - added Makefile.nt (thanks to Stephen Williams) - added the unsupported "contrib" directory: contrib/asm386/ by Gilles Vollant 386 asm code replacing longest_match(). contrib/iostream/ by Kevin Ruland A C++ I/O streams interface to the zlib gz* functions contrib/iostream2/ by Tyge Lvset Another C++ I/O streams interface contrib/untgz/ by "Pedro A. Aranda Guti\irrez" A very simple tar.gz file extractor using zlib contrib/visual-basic.txt by Carlos Rios How to use compress(), uncompress() and the gz* functions from VB. - pass params -f (filtered data), -h (huffman only), -1 to -9 (compression level) in minigzip (thanks to Tom Lane) - use const for rommable constants in deflate - added test for gzseek and gztell in example.c - add undocumented function inflateSyncPoint() (hack for Paul Mackerras) - add undocumented function zError to convert error code to string (for Tim Smithers) - Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. - Use default memcpy for Symantec MSDOS compiler. - Add EXPORT keyword for check_func (needed for Windows DLL) - add current directory to LD_LIBRARY_PATH for "make test" - create also a link for libz.so.1 - added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) - use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) - added -soname for Linux in configure (Chun-Chung Chen, - assign numbers to the exported functions in zlib.def (for Windows DLL) - add advice in zlib.h for best usage of deflateSetDictionary - work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) - allow compilation with ANSI keywords only enabled for TurboC in large model - avoid "versionString"[0] (Borland bug) - add NEED_DUMMY_RETURN for Borland - use variable z_verbose for tracing in debug mode (L. Peter Deutsch). - allow compilation with CC - defined STDC for OS/2 (David Charlap) - limit external names to 8 chars for MVS (Thomas Lund) - in minigzip.c, use static buffers only for 16-bit systems - fix suffix check for "minigzip -d foo.gz" - do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) - use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) - added makelcc.bat for lcc-win32 (Tom St Denis) - in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) - Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. - check for unistd.h in configure (for off_t) - remove useless check parameter in inflate_blocks_free - avoid useless assignment of s->check to itself in inflate_blocks_new - do not flush twice in gzclose (thanks to Ken Raeburn) - rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h - use NO_ERRNO_H instead of enumeration of operating systems with errno.h - work around buggy fclose on pipes for HP/UX - support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) - fix configure if CC is already equal to gcc Changes in 1.0.5 (3 Jan 98) - Fix inflate to terminate gracefully when fed corrupted or invalid data - Use const for rommable constants in inflate - Eliminate memory leaks on error conditions in inflate - Removed some vestigial code in inflate - Update web address in README Changes in 1.0.4 (24 Jul 96) - In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF bit, so the decompressor could decompress all the correct data but went on to attempt decompressing extra garbage data. This affected minigzip too. - zlibVersion and gzerror return const char* (needed for DLL) - port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) - use z_error only for DEBUG (avoid problem with DLLs) Changes in 1.0.3 (2 Jul 96) - use z_streamp instead of z_stream *, which is now a far pointer in MSDOS small and medium models; this makes the library incompatible with previous versions for these models. (No effect in large model or on other systems.) - return OK instead of BUF_ERROR if previous deflate call returned with avail_out as zero but there is nothing to do - added memcmp for non STDC compilers - define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) - define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) - better check for 16-bit mode MSC (avoids problem with Symantec) Changes in 1.0.2 (23 May 96) - added Windows DLL support - added a function zlibVersion (for the DLL support) - fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) - Bytef is define's instead of typedef'd only for Borland C - avoid reading uninitialized memory in example.c - mention in README that the zlib format is now RFC1950 - updated Makefile.dj2 - added algorithm.doc Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] - fix array overlay in deflate.c which sometimes caused bad compressed data - fix inflate bug with empty stored block - fix MSDOS medium model which was broken in 0.99 - fix deflateParams() which could generated bad compressed data. - Bytef is define'd instead of typedef'ed (work around Borland bug) - added an INDEX file - new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) - speed up adler32 for modern machines without auto-increment - added -ansi for IRIX in configure - static_init_done in trees.c is an int - define unlink as delete for VMS - fix configure for QNX - add configure branch for SCO and HPUX - avoid many warnings (unused variables, dead assignments, etc...) - no fdopen for BeOS - fix the Watcom fix for 32 bit mode (define FAR as empty) - removed redefinition of Byte for MKWERKS - work around an MWKERKS bug (incorrect merge of all .h files) Changes in 0.99 (27 Jan 96) - allow preset dictionary shared between compressor and decompressor - allow compression level 0 (no compression) - add deflateParams in zlib.h: allow dynamic change of compression level and compression strategy. - test large buffers and deflateParams in example.c - add optional "configure" to build zlib as a shared library - suppress Makefile.qnx, use configure instead - fixed deflate for 64-bit systems (detected on Cray) - fixed inflate_blocks for 64-bit systems (detected on Alpha) - declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) - always return Z_BUF_ERROR when deflate() has nothing to do - deflateInit and inflateInit are now macros to allow version checking - prefix all global functions and types with z_ with -DZ_PREFIX - make falloc completely reentrant (inftrees.c) - fixed very unlikely race condition in ct_static_init - free in reverse order of allocation to help memory manager - use zlib-1.0/* instead of zlib/* inside the tar.gz - make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion -Wstrict-prototypes -Wmissing-prototypes" - allow gzread on concatenated .gz files - deflateEnd now returns Z_DATA_ERROR if it was premature - deflate is finally (?) fully deterministic (no matches beyond end of input) - Document Z_SYNC_FLUSH - add uninstall in Makefile - Check for __cpluplus in zlib.h - Better test in ct_align for partial flush - avoid harmless warnings for Borland C++ - initialize hash_head in deflate.c - avoid warning on fdopen (gzio.c) for HP cc -Aa - include stdlib.h for STDC compilers - include errno.h for Cray - ignore error if ranlib doesn't exist - call ranlib twice for NeXTSTEP - use exec_prefix instead of prefix for libz.a - renamed ct_* as _tr_* to avoid conflict with applications - clear z->msg in inflateInit2 before any error return - initialize opaque in example.c, gzio.c, deflate.c and inflate.c - fixed typo in zconf.h (_GNUC__ => __GNUC__) - check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) - fix typo in Make_vms.com (f$trnlnm -> f$getsyi) - in fcalloc, normalize pointer if size > 65520 bytes - don't use special fcalloc for 32 bit Borland C++ - use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... - use Z_BINARY instead of BINARY - document that gzclose after gzdopen will close the file - allow "a" as mode in gzopen. - fix error checking in gzread - allow skipping .gz extra-field on pipes - added reference to Perl interface in README - put the crc table in FAR data (I dislike more and more the medium model :) - added get_crc_table - added a dimension to all arrays (Borland C can't count). - workaround Borland C bug in declaration of inflate_codes_new & inflate_fast - guard against multiple inclusion of *.h (for precompiled header on Mac) - Watcom C pretends to be Microsoft C small model even in 32 bit mode. - don't use unsized arrays to avoid silly warnings by Visual C++: warning C4746: 'inflate_mask' : unsized array treated as '__far' (what's wrong with far data in far model?). - define enum out of inflate_blocks_state to allow compilation with C++ Changes in 0.95 (16 Aug 95) - fix MSDOS small and medium model (now easier to adapt to any compiler) - inlined send_bits - fix the final (:-) bug for deflate with flush (output was correct but not completely flushed in rare occasions). - default window size is same for compression and decompression (it's now sufficient to set MAX_WBITS in zconf.h). - voidp -> voidpf and voidnp -> voidp (for consistency with other typedefs and because voidnp was not near in large model). Changes in 0.94 (13 Aug 95) - support MSDOS medium model - fix deflate with flush (could sometimes generate bad output) - fix deflateReset (zlib header was incorrectly suppressed) - added support for VMS - allow a compression level in gzopen() - gzflush now calls fflush - For deflate with flush, flush even if no more input is provided. - rename libgz.a as libz.a - avoid complex expression in infcodes.c triggering Turbo C bug - work around a problem with gcc on Alpha (in INSERT_STRING) - don't use inline functions (problem with some gcc versions) - allow renaming of Byte, uInt, etc... with #define. - avoid warning about (unused) pointer before start of array in deflate.c - avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c - avoid reserved word 'new' in trees.c Changes in 0.93 (25 June 95) - temporarily disable inline functions - make deflate deterministic - give enough lookahead for PARTIAL_FLUSH - Set binary mode for stdin/stdout in minigzip.c for OS/2 - don't even use signed char in inflate (not portable enough) - fix inflate memory leak for segmented architectures Changes in 0.92 (3 May 95) - don't assume that char is signed (problem on SGI) - Clear bit buffer when starting a stored block - no memcpy on Pyramid - suppressed inftest.c - optimized fill_window, put longest_match inline for gcc - optimized inflate on stored blocks. - untabify all sources to simplify patches Changes in 0.91 (2 May 95) - Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h - Document the memory requirements in zconf.h - added "make install" - fix sync search logic in inflateSync - deflate(Z_FULL_FLUSH) now works even if output buffer too short - after inflateSync, don't scare people with just "lo world" - added support for DJGPP Changes in 0.9 (1 May 95) - don't assume that zalloc clears the allocated memory (the TurboC bug was Mark's bug after all :) - let again gzread copy uncompressed data unchanged (was working in 0.71) - deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented - added a test of inflateSync in example.c - moved MAX_WBITS to zconf.h because users might want to change that. - document explicitly that zalloc(64K) on MSDOS must return a normalized pointer (zero offset) - added Makefiles for Microsoft C, Turbo C, Borland C++ - faster crc32() Changes in 0.8 (29 April 95) - added fast inflate (inffast.c) - deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this is incompatible with previous versions of zlib which returned Z_OK. - work around a TurboC compiler bug (bad code for b << 0, see infutil.h) (actually that was not a compiler bug, see 0.81 above) - gzread no longer reads one extra byte in certain cases - In gzio destroy(), don't reference a freed structure - avoid many warnings for MSDOS - avoid the ERROR symbol which is used by MS Windows Changes in 0.71 (14 April 95) - Fixed more MSDOS compilation problems :( There is still a bug with TurboC large model. Changes in 0.7 (14 April 95) - Added full inflate support. - Simplified the crc32() interface. The pre- and post-conditioning (one's complement) is now done inside crc32(). WARNING: this is incompatible with previous versions; see zlib.h for the new usage. Changes in 0.61 (12 April 95) - workaround for a bug in TurboC. example and minigzip now work on MSDOS. Changes in 0.6 (11 April 95) - added minigzip.c - added gzdopen to reopen a file descriptor as gzFile - added transparent reading of non-gziped files in gzread. - fixed bug in gzread (don't read crc as data) - fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). - don't allocate big arrays in the stack (for MSDOS) - fix some MSDOS compilation problems Changes in 0.5: - do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but not yet Z_FULL_FLUSH. - support decompression but only in a single step (forced Z_FINISH) - added opaque object for zalloc and zfree. - added deflateReset and inflateReset - added a variable zlib_version for consistency checking. - renamed the 'filter' parameter of deflateInit2 as 'strategy'. Added Z_FILTERED and Z_HUFFMAN_ONLY constants. Changes in 0.4: - avoid "zip" everywhere, use zlib instead of ziplib. - suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush if compression method == 8. - added adler32 and crc32 - renamed deflateOptions as deflateInit2, call one or the other but not both - added the method parameter for deflateInit2. - added inflateInit2 - simplied considerably deflateInit and inflateInit by not supporting user-provided history buffer. This is supported only in deflateInit2 and inflateInit2. Changes in 0.3: - prefix all macro names with Z_ - use Z_FINISH instead of deflateEnd to finish compression. - added Z_HUFFMAN_ONLY - added gzerror() ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/deflate.c0000664000175000017500000021346412776215007020633 0ustar kaikai/* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions * of the input text which are identical to earlier input (within a * sliding window trailing behind the input currently being processed). * * The most straightforward technique turns out to be the fastest for * most input files: try all possible matches and select the longest. * The key feature of this algorithm is that insertions into the string * dictionary are very simple and thus fast, and deletions are avoided * completely. Insertions are performed at each input character, whereas * string matches are performed only when the previous match ends. So it * is preferable to spend more time in matches to allow very fast string * insertions and avoid deletions. The matching algorithm for small * strings is inspired from that of Rabin & Karp. A brute force approach * is used to find longer strings when a small match has been found. * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze * (by Leonid Broukhis). * A previous version of this file used a more sophisticated algorithm * (by Fiala and Greene) which is guaranteed to run in linear amortized * time, but has a larger average cost, uses more memory and is patented. * However the F&G algorithm may be faster for some highly redundant * files if the parameter max_chain_length (described below) is too large. * * ACKNOWLEDGEMENTS * * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and * I found it in 'freeze' written by Leonid Broukhis. * Thanks to many people for bug reports and testing. * * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. * * Fiala,E.R., and Greene,D.H. * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 * */ /* @(#) $Id$ */ #include "deflate.h" const char deflate_copyright[] = " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* =========================================================================== * Function prototypes. */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ finish_started, /* finish started, need only more output at next deflate */ finish_done /* finish done, accept no more input or output */ } block_state; typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); #ifndef FASTEST local block_state deflate_slow OF((deflate_state *s, int flush)); #endif local block_state deflate_rle OF((deflate_state *s, int flush)); local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); #else local uInt longest_match OF((deflate_state *s, IPos cur_match)); #endif #ifdef DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, int length)); #endif /* =========================================================================== * Local data */ #define NIL 0 /* Tail of hash chains */ #ifndef TOO_FAR # define TOO_FAR 4096 #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ typedef struct config_s { ush good_length; /* reduce lazy search above this match length */ ush max_lazy; /* do not perform lazy search above this match length */ ush nice_length; /* quit search above this match length */ ush max_chain; compress_func func; } config; #ifdef FASTEST local const config configuration_table[2] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ #else local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ #endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ #define EQUAL 0 /* result of memcmp for equal strings */ #ifndef NO_DUMMY_DECL struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #endif /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ #define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to to UPDATE_HASH are made with consecutive * input characters, so that a running hash key can be computed from the * previous key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. * IN assertion: all calls to to INSERT_STRING are made with consecutive * input characters and the first MIN_MATCH bytes of str are valid * (except for the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ s->head[s->hash_size-1] = NIL; \ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* ========================================================================= */ int ZEXPORT deflateInit_(strm, level, version, stream_size) z_streamp strm; int level; const char *version; int stream_size; { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, version, stream_size) z_streamp strm; int level; int method; int windowBits; int memLevel; int strategy; const char *version; int stream_size; { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 24 bits. */ if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; windowBits = -windowBits; } #ifdef GZIP else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; s->wrap = wrap; s->gzhead = Z_NULL; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); s->pending_buf = (uchf *) overlay; s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; strm->msg = ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } s->d_buf = overlay + s->lit_bufsize/sizeof(ush); s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } /* ========================================================================= */ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { deflate_state *s; uInt str, n; int wrap; unsigned avail; z_const unsigned char *next; if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) return Z_STREAM_ERROR; s = strm->state; wrap = s->wrap; if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) return Z_STREAM_ERROR; /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength); s->wrap = 0; /* avoid computing Adler-32 in read_buf */ /* if dictionary would fill window, just replace the history */ if (dictLength >= s->w_size) { if (wrap == 0) { /* already empty otherwise */ CLEAR_HASH(s); s->strstart = 0; s->block_start = 0L; s->insert = 0; } dictionary += dictLength - s->w_size; /* use the tail */ dictLength = s->w_size; } /* insert dictionary into window and hash */ avail = strm->avail_in; next = strm->next_in; strm->avail_in = dictLength; strm->next_in = (z_const Bytef *)dictionary; fill_window(s); while (s->lookahead >= MIN_MATCH) { str = s->strstart; n = s->lookahead - (MIN_MATCH-1); do { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; } while (--n); s->strstart = str; s->lookahead = MIN_MATCH-1; fill_window(s); } s->strstart += s->lookahead; s->block_start = (long)s->strstart; s->insert = s->lookahead; s->lookahead = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; strm->next_in = next; strm->avail_in = avail; s->wrap = wrap; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateResetKeep (strm) z_streamp strm; { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { return Z_STREAM_ERROR; } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = s->wrap ? INIT_STATE : BUSY_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); s->last_flush = Z_NO_FLUSH; _tr_init(s); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateReset (strm) z_streamp strm; { int ret; ret = deflateResetKeep(strm); if (ret == Z_OK) lm_init(strm->state); return ret; } /* ========================================================================= */ int ZEXPORT deflateSetHeader (strm, head) z_streamp strm; gz_headerp head; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePending (strm, pending, bits) unsigned *pending; int *bits; z_streamp strm; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; if (bits != Z_NULL) *bits = strm->state->bi_valid; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePrime (strm, bits, value) z_streamp strm; int bits; int value; { deflate_state *s; int put; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; do { put = Buf_size - s->bi_valid; if (put > bits) put = bits; s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); s->bi_valid += put; _tr_flush_bits(s); value >>= put; bits -= put; } while (bits); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateParams(strm, level, strategy) z_streamp strm; int level; int strategy; { deflate_state *s; compress_func func; int err = Z_OK; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && strm->total_in != 0) { /* Flush the last buffer: */ err = deflate(strm, Z_BLOCK); if (err == Z_BUF_ERROR && s->pending == 0) err = Z_OK; } if (s->level != level) { s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; s->nice_match = configuration_table[level].nice_length; s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return err; } /* ========================================================================= */ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) z_streamp strm; int good_length; int max_lazy; int nice_length; int max_chain; { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; s->good_match = good_length; s->max_lazy_match = max_lazy; s->nice_match = nice_length; s->max_chain_length = max_chain; return Z_OK; } /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns * a close to exact, as well as small, upper bound on the compressed size. * They are coded as constants here for a reason--if the #define's are * changed, then this function needs to be changed as well. The return * value for 15 and 8 only works for those exact settings. * * For any setting other than those defaults for windowBits and memLevel, * the value returned is a conservative worst case for the maximum expansion * resulting from using fixed blocks instead of stored blocks, which deflate * can emit on compressed data for some combinations of the parameters. * * This function could be more sophisticated to provide closer upper bounds for * every combination of windowBits and memLevel. But even the conservative * upper bound of about 14% expansion does not seem onerous for output buffer * allocation. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; uLong complen, wraplen; Bytef *str; /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ if (strm == Z_NULL || strm->state == Z_NULL) return complen + 6; /* compute wrapper length */ s = strm->state; switch (s->wrap) { case 0: /* raw deflate */ wraplen = 0; break; case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; if (str != Z_NULL) do { wraplen++; } while (*str++); str = s->gzhead->comment; if (str != Z_NULL) do { wraplen++; } while (*str++); if (s->gzhead->hcrc) wraplen += 2; } break; default: /* for compiler happiness */ wraplen = 6; } /* if not default parameters, return conservative bound */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; /* default settings: return tight bound for that case */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ local void putShortMSB (s, b) deflate_state *s; uInt b; { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } /* ========================================================================= * Flush as much pending output as possible. All deflate() output goes * through this function so some applications may wish to modify it * to avoid allocating a large strm->next_out buffer and copying into it. * (See also read_buf()). */ local void flush_pending(strm) z_streamp strm; { unsigned len; deflate_state *s = strm->state; _tr_flush_bits(s); len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; zmemcpy(strm->next_out, s->pending_out, len); strm->next_out += len; s->pending_out += len; strm->total_out += len; strm->avail_out -= len; s->pending -= len; if (s->pending == 0) { s->pending_out = s->pending_buf; } } /* ========================================================================= */ int ZEXPORT deflate (strm, flush) z_streamp strm; int flush; { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); s->strm = strm; /* just in case */ old_flush = s->last_flush; s->last_flush = flush; /* Write the header */ if (s->status == INIT_STATE) { #ifdef GZIP if (s->wrap == 2) { strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); if (s->gzhead == Z_NULL) { put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, OS_CODE); s->status = BUSY_STATE; } else { put_byte(s, (s->gzhead->text ? 1 : 0) + (s->gzhead->hcrc ? 2 : 0) + (s->gzhead->extra == Z_NULL ? 0 : 4) + (s->gzhead->name == Z_NULL ? 0 : 8) + (s->gzhead->comment == Z_NULL ? 0 : 16) ); put_byte(s, (Byte)(s->gzhead->time & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, s->gzhead->os & 0xff); if (s->gzhead->extra != Z_NULL) { put_byte(s, s->gzhead->extra_len & 0xff); put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); } if (s->gzhead->hcrc) strm->adler = crc32(strm->adler, s->pending_buf, s->pending); s->gzindex = 0; s->status = EXTRA_STATE; } } else #endif { uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; else if (s->level < 6) level_flags = 1; else if (s->level == 6) level_flags = 2; else level_flags = 3; header |= (level_flags << 6); if (s->strstart != 0) header |= PRESET_DICT; header += 31 - (header % 31); s->status = BUSY_STATE; putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ if (s->strstart != 0) { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } strm->adler = adler32(0L, Z_NULL, 0); } } #ifdef GZIP if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) break; } put_byte(s, s->gzhead->extra[s->gzindex]); s->gzindex++; } if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (s->gzindex == s->gzhead->extra_len) { s->gzindex = 0; s->status = NAME_STATE; } } else s->status = NAME_STATE; } if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->name[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) { s->gzindex = 0; s->status = COMMENT_STATE; } } else s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->comment[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) s->status = HCRC_STATE; } else s->status = HCRC_STATE; } if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) flush_pending(strm); if (s->pending + 2 <= s->pending_buf_size) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); strm->adler = crc32(0L, Z_NULL, 0); s->status = BUSY_STATE; } } else s->status = BUSY_STATE; } #endif /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and * avail_in equal to zero. There won't be anything to do, * but this is not an error situation so make sure we * return OK instead of BUF_ERROR at next call of deflate: */ s->last_flush = -1; return Z_OK; } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : (s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush)); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ } return Z_OK; /* If flush != Z_NO_FLUSH && avail_out == 0, the next call * of deflate should use the same flush parameter to make sure * that the flush is complete. So we don't have to output an * empty block here, this will be done at next call. This also * ensures that for a very small output buffer, we emit at most * one empty block. */ } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush == Z_FULL_FLUSH) { CLEAR_HASH(s); /* forget history */ if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L; s->insert = 0; } } } flush_pending(strm); if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ return Z_OK; } } } Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP if (s->wrap == 2) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); put_byte(s, (Byte)(strm->total_in & 0xff)); put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); } else #endif { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ int ZEXPORT deflateEnd (strm) z_streamp strm; { int status; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; status = strm->state->status; if (status != INIT_STATE && status != EXTRA_STATE && status != NAME_STATE && status != COMMENT_STATE && status != HCRC_STATE && status != BUSY_STATE && status != FINISH_STATE) { return Z_STREAM_ERROR; } /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); TRY_FREE(strm, strm->state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ int ZEXPORT deflateCopy (dest, source) z_streamp dest; z_streamp source; { #ifdef MAXSEG_64K return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; ushf *overlay; if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); ds->pending_buf = (uchf *) overlay; if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { deflateEnd (dest); return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; #endif /* MAXSEG_64K */ } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ local int read_buf(strm, buf, size) z_streamp strm; Bytef *buf; unsigned size; { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; zmemcpy(buf, strm->next_in, len); if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP else if (strm->state->wrap == 2) { strm->adler = crc32(strm->adler, buf, len); } #endif strm->next_in += len; strm->total_in += len; return (int)len; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ local void lm_init (s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->insert = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; #ifndef FASTEST #ifdef ASMV match_init(); /* initialize the asm code */ #endif #endif } #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ #ifndef ASMV /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ int best_len = s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ Posf *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; register ush scan_end = *(ushf*)(scan+best_len-1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len-1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ushf*)(match+best_len-1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart+3, +5, ... up to strstart+257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window+strstart+257 */ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ushf*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } #endif /* ASMV */ #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Return failure if the match length is less than 2: */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match += 2; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } #endif /* FASTEST */ #ifdef DEBUG /* =========================================================================== * Check that the match at match_start is indeed a match. */ local void check_match(s, start, match, length) deflate_state *s; IPos start, match; int length; { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); } while (--length != 0); z_error("invalid match"); } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start-match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) #endif /* DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ local void fill_window(s) deflate_state *s; { register unsigned n, m; register Posf *p; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = wsize; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if * strstart == 0 && lookahead == 1 (input done a byte at time) */ more--; } } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize+MAX_DIST(s)) { zmemcpy(s->window, s->window+wsize, (unsigned)wsize); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; /* Slide the hash table (could be avoided with 32 bit values at the expense of memory usage). We slide even when level == 0 to keep the hash table consistent if we switch back to level > 0 later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ n = s->hash_size; p = &s->head[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); } while (--n); n = wsize; #ifndef FASTEST p = &s->prev[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif more += wsize; } if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ if (s->lookahead + s->insert >= MIN_MATCH) { uInt str = s->strstart - s->insert; s->ins_h = s->window[str]; UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif while (s->insert) { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; s->insert--; if (s->lookahead + s->insert < MIN_MATCH) break; } } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { ulg curr = s->strstart + (ulg)(s->lookahead); ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT * bytes or up to end of window, whichever is less. */ init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; } else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "not enough room for search"); } /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ (ulg)((long)s->strstart - s->block_start), \ (last)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ } /* Same but force premature exit if necessary. */ #define FLUSH_BLOCK(s, last) { \ FLUSH_BLOCK_ONLY(s, last); \ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * This function does not insert new strings in the dictionary since * uncompressible data is probably not useful. This function is used * only for the level=0 compression option. * NOTE: this function should be optimized to avoid extra copying from * window to pending_buf. */ local block_state deflate_stored(s, flush) deflate_state *s; int flush; { /* Stored blocks are limited to 0xffff bytes, pending_buf is limited * to pending_buf_size, and each stored block has a 5 byte header: */ ulg max_block_size = 0xffff; ulg max_start; if (max_block_size > s->pending_buf_size - 5) { max_block_size = s->pending_buf_size - 5; } /* Copy as much as possible from input to output: */ for (;;) { /* Fill the window as much as possible: */ if (s->lookahead <= 1) { Assert(s->strstart < s->w_size+MAX_DIST(s) || s->block_start >= (long)s->w_size, "slide too late"); fill_window(s); if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; if (s->lookahead == 0) break; /* flush the current block */ } Assert(s->block_start >= 0L, "block gone"); s->strstart += s->lookahead; s->lookahead = 0; /* Emit a stored block if pending_buf will be full: */ max_start = s->block_start + max_block_size; if (s->strstart == 0 || (ulg)s->strstart >= max_start) { /* strstart == 0 is possible when wraparound on 16-bit machine */ s->lookahead = (uInt)(s->strstart - max_start); s->strstart = (uInt)max_start; FLUSH_BLOCK(s, 0); } /* Flush if we may have to slide, otherwise block_start may become * negative and the data will be gone: */ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { FLUSH_BLOCK(s, 0); } } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if ((long)s->strstart > s->block_start) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ local block_state deflate_fast(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ local block_state deflate_slow(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. */ s->prev_length = s->match_length, s->prev_match = s->match_start; s->match_length = MIN_MATCH-1; if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ if (s->match_length <= 5 && (s->strategy == Z_FILTERED #if TOO_FAR <= 32767 || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) #endif )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s->match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ check_match(s, s->strstart-1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s->lookahead -= s->prev_length-1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { INSERT_STRING(s, s->strstart, hash_head); } } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return need_more; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #endif /* FASTEST */ /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ local block_state deflate_rle(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the longest run, plus one for the unrolled loop. */ if (s->lookahead <= MAX_MATCH) { fill_window(s); if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* See how many times the previous byte repeats */ s->match_length = 0; if (s->lookahead >= MIN_MATCH && s->strstart > 0) { scan = s->window + s->strstart - 1; prev = *scan; if (prev == *++scan && prev == *++scan && prev == *++scan) { strend = s->window + s->strstart + MAX_MATCH; do { } while (prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (int)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->strstart - 1, s->match_length); _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; s->strstart += s->match_length; s->match_length = 0; } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ local block_state deflate_huff(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) { fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */ } } /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/linux.mak0000664000175000017500000000372412776215007020710 0ustar kaikai# Makefile for zlib MODEL=32 CC=gcc LD=link CFLAGS=-O -m$(MODEL) LDFLAGS= O=.o .c.o: $(CC) -c $(CFLAGS) $* .d.o: $(DMD) -c $(DFLAGS) $* # variables OBJS = adler32$(O) compress$(O) crc32$(O) deflate$(O) gzclose$(O) gzlib$(O) gzread$(O) \ gzwrite$(O) infback$(O) inffast$(O) inflate$(O) inftrees$(O) trees$(O) uncompr$(O) zutil$(O) all: zlib.a example minigzip adler32.o: zutil.h zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c zutil.o: zutil.h zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c gzclose.o: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c gzlib.o: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c gzread.o: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c gzwrite.o: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c compress.o: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c example.o: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c minigzip.o: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c uncompr.o: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c crc32.o: zutil.h zlib.h zconf.h crc32.h $(CC) -c $(CFLAGS) $*.c deflate.o: deflate.h zutil.h zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h $(CC) -c $(CFLAGS) $*.c inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h $(CC) -c $(CFLAGS) $*.c inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h $(CC) -c $(CFLAGS) $*.c inftrees.o: zutil.h zlib.h zconf.h inftrees.h $(CC) -c $(CFLAGS) $*.c trees.o: deflate.h zutil.h zlib.h zconf.h trees.h $(CC) -c $(CFLAGS) $*.c example.o: example.c zlib.h zconf.h $(CC) -c $(cvarsdll) $(CFLAGS) $*.c minigzip.o: minigzip.c zlib.h zconf.h $(CC) -c $(cvarsdll) $(CFLAGS) $*.c zlib.a: $(OBJS) ar -r $@ $(OBJS) example: example.o zlib.a $(CC) $(CFLAGS) -o $@ example.o zlib.a -g minigzip: minigzip.o zlib.a $(CC) $(CFLAGS) -o $@ minigzip.o zlib.a -g test: example minigzip ./example echo hello world | minigzip | minigzip -d clean: $(RM) $(OBJS) zlib.a example.o example minigzip minigzip.o test foo.gz ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/deflate.h0000664000175000017500000003074612776215007020640 0ustar kaikai/* deflate.h -- internal compression state * Copyright (C) 1995-2012 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef DEFLATE_H #define DEFLATE_H #include "zutil.h" /* define NO_GZIP when compiling if you want to disable gzip header and trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif /* =========================================================================== * Internal compression state. */ #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */ #define LITERALS 256 /* number of literal bytes 0..255 */ #define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK code */ #define D_CODES 30 /* number of distance codes */ #define BL_CODES 19 /* number of codes used to transfer the bit lengths */ #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ #define Buf_size 16 /* size of bit buffer in bi_buf */ #define INIT_STATE 42 #define EXTRA_STATE 69 #define NAME_STATE 73 #define COMMENT_STATE 91 #define HCRC_STATE 103 #define BUSY_STATE 113 #define FINISH_STATE 666 /* Stream status */ /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { ush freq; /* frequency count */ ush code; /* bit string */ } fc; union { ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; } FAR ct_data; #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; typedef Pos FAR Posf; typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to * save space in the various tables. IPos is used only for parameter passing. */ typedef struct internal_state { z_streamp strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ uInt pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ uInt gzindex; /* where in extra, name, or comment */ Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ uInt w_size; /* LZ77 window size (32K by default) */ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ Bytef *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ ulg window_size; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ Posf *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ Posf *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ uInt hash_bits; /* log2(hash_size) */ uInt hash_mask; /* hash_size-1 */ uInt hash_shift; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ long block_start; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ uInt match_length; /* length of best match */ IPos prev_match; /* previous match */ int match_available; /* set if previous match exists */ uInt strstart; /* start of string to insert */ uInt match_start; /* start of matching string */ uInt lookahead; /* number of valid bytes ahead in window */ uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ uInt max_chain_length; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ uInt max_lazy_match; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ int level; /* compression level (1..9) */ int strategy; /* favor or force Huffman coding*/ uInt good_match; /* Use a faster search when the previous match is longer than this */ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ struct tree_desc_s l_desc; /* desc. for literal tree */ struct tree_desc_s d_desc; /* desc. for distance tree */ struct tree_desc_s bl_desc; /* desc. for bit length tree */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ int heap_len; /* number of elements in the heap */ int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ uchf *l_buf; /* buffer for literals or lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt last_lit; /* running index in l_buf */ ushf *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ uInt insert; /* bytes at end of window left to insert */ #ifdef DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif ush bi_buf; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ ulg high_water; /* High water mark offset in window for initialized bytes -- bytes above * this are set to zero in order to avoid memory check warnings when * longest match routines access bytes past the input. This is then * updated to the new high water mark. */ } FAR deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ #define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the input file. * See deflate.c for comments about the MIN_MATCH+1. */ #define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) /* In order to simplify the code, particularly on 16 bit machines, match * distances are limited to MAX_DIST instead of WSIZE. */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ #ifndef DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) extern uch ZLIB_INTERNAL _length_code[]; extern uch ZLIB_INTERNAL _dist_code[]; #else extern const uch ZLIB_INTERNAL _length_code[]; extern const uch ZLIB_INTERNAL _dist_code[]; #endif # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->d_buf[s->last_lit] = 0; \ s->l_buf[s->last_lit++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (length); \ ush dist = (distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ flush = _tr_tally(s, distance, length) #endif #endif /* DEFLATE_H */ ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/inffast.h0000664000175000017500000000065312776215007020660 0ustar kaikai/* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/adler32.c0000664000175000017500000001155012776215007020453 0ustar kaikai/* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #define local static local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #define BASE 65521 /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); /* use NO_DIVIDE if your processor does not do division in hardware -- try it both ways to see which is faster */ #ifdef NO_DIVIDE /* note that this assumes BASE is 65521, where 65536 % 65521 == 15 (thank you to John Reiser for pointing this out) */ # define CHOP(a) \ do { \ unsigned long tmp = a >> 16; \ a &= 0xffffUL; \ a += (tmp << 4) - tmp; \ } while (0) # define MOD28(a) \ do { \ CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0) # define MOD(a) \ do { \ CHOP(a); \ MOD28(a); \ } while (0) # define MOD63(a) \ do { /* this assumes a is not negative */ \ z_off64_t tmp = a >> 32; \ a &= 0xffffffffL; \ a += (tmp << 8) - (tmp << 5) + tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ uLong ZEXPORT adler32(adler, buf, len) uLong adler; const Bytef *buf; uInt len; { unsigned long sum2; unsigned n; /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ if (len == 1) { adler += buf[0]; if (adler >= BASE) adler -= BASE; sum2 += adler; if (sum2 >= BASE) sum2 -= BASE; return adler | (sum2 << 16); } /* initial Adler-32 value (deferred check for len == 1 speed) */ if (buf == Z_NULL) return 1L; /* in case short lengths are provided, keep it somewhat fast */ if (len < 16) { while (len--) { adler += *buf++; sum2 += adler; } if (adler >= BASE) adler -= BASE; MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } /* do length NMAX blocks -- requires just one modulo operation */ while (len >= NMAX) { len -= NMAX; n = NMAX / 16; /* NMAX is divisible by 16 */ do { DO16(buf); /* 16 sums unrolled */ buf += 16; } while (--n); MOD(adler); MOD(sum2); } /* do remaining bytes (less than NMAX, still just one modulo) */ if (len) { /* avoid modulos if none remaining */ while (len >= 16) { len -= 16; DO16(buf); buf += 16; } while (len--) { adler += *buf++; sum2 += adler; } MOD(adler); MOD(sum2); } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ local uLong adler32_combine_(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { unsigned long sum1; unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) return 0xffffffffUL; /* the derivation of this formula is left as an exercise for the reader */ MOD63(len2); /* assumes len2 >= 0 */ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32_combine(adler1, adler2, len2) uLong adler1; uLong adler2; z_off_t len2; { return adler32_combine_(adler1, adler2, len2); } uLong ZEXPORT adler32_combine64(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { return adler32_combine_(adler1, adler2, len2); } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/inflate.h0000664000175000017500000001437712776215007020660 0ustar kaikai/* inflate.h -- internal inflate state definition * Copyright (C) 1995-2009 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip decoding should be left enabled. */ #ifndef NO_GZIP # define GUNZIP #endif /* Possible inflate modes between inflate() calls */ typedef enum { HEAD, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ EXLEN, /* i: waiting for extra length (gzip) */ EXTRA, /* i: waiting for extra bytes (gzip) */ NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ TYPEDO, /* i: same, but skip check to exit inflate on new block */ STORED, /* i: waiting for stored size (length and complement) */ COPY_, /* i/o: same as COPY below, but only first time in */ COPY, /* i/o: waiting for input or output to copy stored block */ TABLE, /* i: waiting for dynamic block table lengths */ LENLENS, /* i: waiting for code length code lengths */ CODELENS, /* i: waiting for length/lit and distance code lengths */ LEN_, /* i: same as LEN below, but only first time in */ LEN, /* i: waiting for length/lit/eob code */ LENEXT, /* i: waiting for length extra bits */ DIST, /* i: waiting for distance code */ DISTEXT, /* i: waiting for distance extra bits */ MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ LENGTH, /* i: waiting for 32-bit length (gzip) */ DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ SYNC /* looking for synchronization bytes to restart inflate() */ } inflate_mode; /* State transitions between above modes - (most modes can go to BAD or MEM on error -- not shown for clarity) Process header: HEAD -> (gzip) or (zlib) or (raw) (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> HCRC -> TYPE (zlib) -> DICTID or TYPE DICTID -> DICT -> TYPE (raw) -> TYPEDO Read deflate blocks: TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK STORED -> COPY_ -> COPY -> TYPE TABLE -> LENLENS -> CODELENS -> LEN_ LEN_ -> LEN Read deflate codes in fixed or dynamic block: LEN -> LENEXT or LIT or TYPE LENEXT -> DIST -> DISTEXT -> MATCH -> LEN LIT -> LEN Process trailer: CHECK -> LENGTH -> DONE */ /* state maintained between inflate() calls. Approximately 10K bytes. */ struct inflate_state { inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if needed */ /* bit accumulator */ unsigned long hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ /* for string and stored block copying */ unsigned length; /* literal or length of data to copy */ unsigned offset; /* distance back to copy string from */ /* for table and code decoding */ unsigned extra; /* extra bits needed */ /* fixed and dynamic code tables */ code const FAR *lencode; /* starting table for length/literal codes */ code const FAR *distcode; /* starting table for distance codes */ unsigned lenbits; /* index bits for lencode */ unsigned distbits; /* index bits for distcode */ /* dynamic table building */ unsigned ncode; /* number of code length code lengths */ unsigned nlen; /* number of length code lengths */ unsigned ndist; /* number of distance code lengths */ unsigned have; /* number of code lengths in lens[] */ code FAR *next; /* next available space in codes[] */ unsigned short lens[320]; /* temporary storage for code lengths */ unsigned short work[288]; /* work area for code table building */ code codes[ENOUGH]; /* space for code tables */ int sane; /* if false, allow invalid distance too far */ int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/inffixed.h0000664000175000017500000001427412776215007021026 0ustar kaikai /* inffixed.h -- table for decoding fixed codes * Generated automatically by makefixed(). */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of this library and is subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = { {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, {0,9,255} }; static const code distfix[32] = { {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, {22,5,193},{64,5,0} }; ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/zconf.h0000664000175000017500000003622412776215007020350 0ustar kaikai/* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. * Even better than compiling with -DZ_PREFIX would be to use configure to set * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET /* all linked symbols */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align # define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block # define _tr_tally z__tr_tally # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams # define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset # define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table # ifndef Z_SOLO # define gz_error z_gz_error # define gz_intmax z_gz_intmax # define gz_strwinerror z_gz_strwinerror # define gzbuffer z_gzbuffer # define gzclearerr z_gzclearerr # define gzclose z_gzclose # define gzclose_r z_gzclose_r # define gzclose_w z_gzclose_w # define gzdirect z_gzdirect # define gzdopen z_gzdopen # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets # define gzoffset z_gzoffset # define gzoffset64 z_gzoffset64 # define gzopen z_gzopen # define gzopen64 z_gzopen64 # ifdef _WIN32 # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf # define gzvprintf z_gzvprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread # define gzrewind z_gzrewind # define gzseek z_gzseek # define gzseek64 z_gzseek64 # define gzsetparams z_gzsetparams # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd # define inflateBackInit_ z_inflateBackInit_ # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd # define inflateGetHeader z_inflateGetHeader # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateSetDictionary z_inflateSetDictionary # define inflateGetDictionary z_inflateGetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine # define inflateResetKeep z_inflateResetKeep # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress # endif # define zError z_zError # ifndef Z_SOLO # define zcalloc z_zcalloc # define zcfree z_zcfree # endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion /* all zlib typedefs in zlib.h and zconf.h */ # define Byte z_Byte # define Bytef z_Bytef # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func # ifndef Z_SOLO # define gzFile z_gzFile # endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func # define intf z_intf # define out_func z_out_func # define uInt z_uInt # define uIntf z_uIntf # define uLong z_uLong # define uLongf z_uLongf # define voidp z_voidp # define voidpc z_voidpc # define voidpf z_voidpf /* all zlib structs in zlib.h and zconf.h */ # define gz_header_s z_gz_header_s # define internal_state z_internal_state #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) # define OS2 #endif #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) # ifndef WIN32 # define WIN32 # endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) # ifndef SYS16BIT # define SYS16BIT # endif # endif #endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ #ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif #ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif # if __STDC_VERSION__ >= 199901L # ifndef STDC99 # define STDC99 # endif # endif #endif #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) # define STDC #endif #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) # define STDC #endif #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) # define STDC #endif #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) # define STDC #endif #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ # define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ # define const /* note: need a more gentle solution here */ # endif #endif #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif /* Some Mac compilers merge all .h files incorrectly: */ #if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) # define NO_DUMMY_DECL #endif /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K # define MAX_MEM_LEVEL 8 # else # define MAX_MEM_LEVEL 9 # endif #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits that is, 32K for windowBits=15 (default value) plus a few kilobytes for small objects. */ /* Type declarations */ #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ #ifdef SYS16BIT # if defined(M_I86SM) || defined(M_I86MM) /* MSC small or medium model */ # define SMALL_MEDIUM # ifdef _MSC_VER # define FAR _far # else # define FAR far # endif # endif # if (defined(__SMALL__) || defined(__MEDIUM__)) /* Turbo C small or medium model */ # define SMALL_MEDIUM # ifdef __BORLANDC__ # define FAR _far # else # define FAR far # endif # endif #endif #if defined(WINDOWS) || defined(WIN32) /* If building or using zlib as a DLL, define ZLIB_DLL. * This is not mandatory, but it offers a little performance increase. */ # ifdef ZLIB_DLL # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) # ifdef ZLIB_INTERNAL # define ZEXTERN extern __declspec(dllexport) # else # define ZEXTERN extern __declspec(dllimport) # endif # endif # endif /* ZLIB_DLL */ /* If building or using zlib with the WINAPI/WINAPIV calling convention, * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else # define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) # ifdef ZLIB_DLL # ifdef ZLIB_INTERNAL # define ZEXPORT __declspec(dllexport) # define ZEXPORTVA __declspec(dllexport) # else # define ZEXPORT __declspec(dllimport) # define ZEXPORTVA __declspec(dllimport) # endif # endif #endif #ifndef ZEXTERN # define ZEXTERN extern #endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif #ifndef FAR # define FAR #endif #if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ #ifdef SMALL_MEDIUM /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; #endif typedef char FAR charf; typedef int FAR intf; typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC typedef void const *voidpc; typedef void FAR *voidpf; typedef void *voidp; #else typedef Byte const *voidpc; typedef Byte FAR *voidpf; typedef Byte *voidp; #endif #if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) # include # if (UINT_MAX == 0xffffffffUL) # define Z_U4 unsigned # elif (ULONG_MAX == 0xffffffffUL) # define Z_U4 unsigned long # elif (USHRT_MAX == 0xffffffffUL) # define Z_U4 unsigned short # endif #endif #ifdef Z_U4 typedef Z_U4 z_crc_t; #else typedef unsigned long z_crc_t; #endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif #ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_STDARG_H #endif #ifdef STDC # ifndef Z_SOLO # include /* for off_t */ # endif #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO # include /* for va_list */ # endif #endif #ifdef _WIN32 # ifndef Z_SOLO # include /* for wchar_t */ # endif #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even * though the former does not conform to the LFS document), but considering * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) # define Z_HAVE_UNISTD_H #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif # endif #endif #if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 # define Z_LFS64 #endif #if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) # define Z_LARGE64 #endif #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) # define Z_WANT64 #endif #if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) #pragma map(deflateInit_,"DEIN") #pragma map(deflateInit2_,"DEIN2") #pragma map(deflateEnd,"DEEND") #pragma map(deflateBound,"DEBND") #pragma map(inflateInit_,"ININ") #pragma map(inflateInit2_,"ININ2") #pragma map(inflateEnd,"INEND") #pragma map(inflateSync,"INSY") #pragma map(inflateSetDictionary,"INSEDI") #pragma map(compressBound,"CMBND") #pragma map(inflate_table,"INTABL") #pragma map(inflate_fast,"INFA") #pragma map(inflate_copyright,"INCOPY") #endif #endif /* ZCONF_H */ ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/README0000664000175000017500000001210112776215007017724 0ustar kaikaiZLIB DATA COMPRESSION LIBRARY zlib 1.2.8 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). All functions of the compression library are documented in the file zlib.h (volunteer to write man pages welcome, contact zlib@gzip.org). A usage example of the library is given in the file test/example.c which also tests that the library is working correctly. Another example is given in the file test/minigzip.c. The compression library itself is composed of all source files in the root directory. To compile all files and run the test program, follow the instructions given at the top of Makefile.in. In short "./configure; make test", and if that goes well, "make install" should work for most flavors of Unix. For Windows, use one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use make_vms.com. Questions about zlib should be sent to , or to Gilles Vollant for the Windows DLL version. The zlib home page is http://zlib.net/ . Before reporting a problem, please check this site to verify that you have the latest version of zlib; otherwise get the latest version and check whether the problem still exists or not. PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Mark Nelson wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at http://marknelson.us/1997/01/01/zlib-engine/ . The changes made in version 1.2.8 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory contrib/ . zlib is available in Java using the java.util.zip package, documented at http://java.sun.com/developer/technicalArticles/Programming/compression/ . A Perl interface to zlib written by Paul Marquess is available at CPAN (Comprehensive Perl Archive Network) sites, including http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . A Python interface to zlib written by A.M. Kuchling is available in Python 1.5 and later versions, see http://docs.python.org/library/zlib.html . zlib is built into tcl: http://wiki.tcl.tk/4610 . An experimental package to read and write files in .zip format, written on top of zlib by Gilles Vollant , is available in the contrib/minizip directory of zlib. Notes for some targets: - For Windows DLL versions, please see win32/DLL_FAQ.txt - For 64-bit Irix, deflate.c must be compiled without any optimization. With -O, one libpng test fails. The test works in 32 bit mode (with the -n32 compiler flag). The compiler bug has been reported to SGI. - zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works when compiled with cc. - On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is necessary to get gzprintf working correctly. This is done by configure. - zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with other compilers. Use "make test" to check your compiler. - gzdopen is not supported on RISCOS or BEOS. - For PalmOs, see http://palmzlib.sourceforge.net/ Acknowledgments: The deflate format used by zlib was defined by Phil Katz. The deflate and zlib specifications were written by L. Peter Deutsch. Thanks to all the people who reported problems and suggested various improvements in zlib; they are too numerous to cite here. Copyright notice: (C) 1995-2013 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. 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. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu If you use the zlib library in a product, we would appreciate *not* receiving lengthy legal documents to sign. The sources are provided for free but without warranty of any kind. The library has been entirely written by Jean-loup Gailly and Mark Adler; it does not include third-party code. If you redistribute modified sources, we would appreciate that you include in the file ChangeLog history information documenting your changes. Please read the FAQ for more information on the distribution of modified source versions. ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/gzguts.h0000664000175000017500000001463012776215007020551 0ustar kaikai/* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #ifdef _LARGEFILE64_SOURCE # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif # ifdef _FILE_OFFSET_BITS # undef _FILE_OFFSET_BITS # endif #endif #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include #include "zlib.h" #ifdef STDC # include # include # include #endif #include #ifdef _WIN32 # include #endif #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include #endif #ifdef WINAPI_FAMILY # define open _open # define read _read # define write _write # define close _close #endif #ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif #if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(__CYGWIN__) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #ifndef HAVE_VSNPRINTF # ifdef MSDOS /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), but for now we just assume it doesn't. */ # define NO_vsnprintf # endif # ifdef __TURBOC__ # define NO_vsnprintf # endif # ifdef WIN32 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ # if !defined(vsnprintf) && !defined(NO_vsnprintf) # if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) # define vsnprintf _vsnprintf # endif # endif # endif # ifdef __SASC # define NO_vsnprintf # endif # ifdef VMS # define NO_vsnprintf # endif # ifdef __OS400__ # define NO_vsnprintf # endif # ifdef __MVS__ # define NO_vsnprintf # endif #endif /* unlike snprintf (which is required in C99, yet still not supported by Microsoft more than a decade later!), _snprintf does not guarantee null termination of the result -- however this is only used in gzlib.c where the result is assured to fit in the space provided */ #ifdef _MSC_VER # define snprintf _snprintf #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ /* gz* functions always use library allocation functions */ #ifndef STDC extern voidp malloc OF((uInt size)); extern void free OF((voidpf ptr)); #endif /* get errno and strerror definition */ #if defined UNDER_CE # include # define zstrerror() gz_strwinerror((DWORD)GetLastError()) #else # ifndef NO_STRERROR # include # define zstrerror() strerror(errno) # else # define zstrerror() "stdio error (consult errno)" # endif #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); #endif /* default memLevel */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default i/o buffer size -- double this for output when reading (this and twice this must be able to fit in an unsigned type) */ #define GZBUFSIZE 8192 /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 #define GZ_READ 7247 #define GZ_WRITE 31153 #define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ /* values for gz_state how */ #define LOOK 0 /* look for a gzip header */ #define COPY 1 /* copy input directly */ #define GZIP 2 /* decompress a gzip stream */ /* internal gzip file state data structure */ typedef struct { /* exposed contents for gzgetc() macro */ struct gzFile_s x; /* "x" for exposed */ /* x.have: number of bytes available at x.next */ /* x.next: next output data to deliver or write */ /* x.pos: current position in uncompressed data */ /* used for both reading and writing */ int mode; /* see gzip modes above */ int fd; /* file descriptor */ char *path; /* path or fd for error messages */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned char *in; /* input buffer */ unsigned char *out; /* output buffer (double-sized when reading) */ int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ int how; /* 0: get header, 1: copy, 2: decompress */ z_off64_t start; /* where the gzip data started, for rewinding */ int eof; /* true if end of input file reached */ int past; /* true if read requested past end */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ /* error information */ int err; /* error code */ char *msg; /* error message */ /* zlib inflate or deflate stream */ z_stream strm; /* stream structure in-place (not a pointer) */ } gz_state; typedef gz_state FAR *gz_statep; /* shared functions */ void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); #if defined UNDER_CE char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ #ifdef INT_MAX # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #else unsigned ZLIB_INTERNAL gz_intmax OF((void)); # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) #endif ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/minigzip.c0000664000175000017500000003662412776215007021056 0ustar kaikai/* minigzip.c -- simulate gzip using the zlib compression library * Copyright (C) 1995-2006, 2010, 2011 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* * minigzip is a minimal implementation of the gzip utility. This is * only an example of using zlib and isn't meant to replace the * full-featured gzip. No attempt is made to deal with file systems * limiting names to 14 or 8+3 characters, etc... Error checking is * very limited. So use minigzip only for testing; use gzip for the * real thing. On MSDOS, use only on file names without extension * or in pipe mode. */ /* @(#) $Id$ */ #include "zlib.h" #include #ifdef STDC # include # include #endif #ifdef USE_MMAP # include # include # include #endif #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) # include # include # ifdef UNDER_CE # include # endif # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) #else # define SET_BINARY_MODE(file) #endif #ifdef _MSC_VER # define snprintf _snprintf #endif #ifdef VMS # define unlink delete # define GZ_SUFFIX "-gz" #endif #ifdef RISCOS # define unlink remove # define GZ_SUFFIX "-gz" # define fileno(file) file->__file #endif #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include /* for fileno */ #endif #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) #ifndef WIN32 /* unlink already in stdio.h for WIN32 */ extern int unlink OF((const char *)); #endif #endif #if defined(UNDER_CE) # include # define perror(s) pwinerror(s) /* Map the Windows error number in ERROR to a locale-dependent error message string and return a pointer to it. Typically, the values for ERROR come from GetLastError. The string pointed to shall not be modified by the application, but may be overwritten by a subsequent call to strwinerror The strwinerror function does not change the current setting of GetLastError. */ static char *strwinerror (error) DWORD error; { static char buf[1024]; wchar_t *msgbuf; DWORD lasterr = GetLastError(); DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, 0, /* Default language */ (LPVOID)&msgbuf, 0, NULL); if (chars != 0) { /* If there is an \r\n appended, zap it. */ if (chars >= 2 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { chars -= 2; msgbuf[chars] = 0; } if (chars > sizeof (buf) - 1) { chars = sizeof (buf) - 1; msgbuf[chars] = 0; } wcstombs(buf, msgbuf, chars + 1); LocalFree(msgbuf); } else { sprintf(buf, "unknown win32 error (%ld)", error); } SetLastError(lasterr); return buf; } static void pwinerror (s) const char *s; { if (s && *s) fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); else fprintf(stderr, "%s\n", strwinerror(GetLastError ())); } #endif /* UNDER_CE */ #ifndef GZ_SUFFIX # define GZ_SUFFIX ".gz" #endif #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) #define BUFLEN 16384 #define MAX_NAME_LEN 1024 #ifdef MAXSEG_64K # define local static /* Needed for systems with limitation on stack size. */ #else # define local #endif #ifdef Z_SOLO /* for Z_SOLO, create simplified gz* functions using deflate and inflate */ #if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE) # include /* for unlink() */ #endif void *myalloc OF((void *, unsigned, unsigned)); void myfree OF((void *, void *)); void *myalloc(q, n, m) void *q; unsigned n, m; { q = Z_NULL; return calloc(n, m); } void myfree(q, p) void *q, *p; { q = Z_NULL; free(p); } typedef struct gzFile_s { FILE *file; int write; int err; char *msg; z_stream strm; } *gzFile; gzFile gzopen OF((const char *, const char *)); gzFile gzdopen OF((int, const char *)); gzFile gz_open OF((const char *, int, const char *)); gzFile gzopen(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } gzFile gzdopen(fd, mode) int fd; const char *mode; { return gz_open(NULL, fd, mode); } gzFile gz_open(path, fd, mode) const char *path; int fd; const char *mode; { gzFile gz; int ret; gz = malloc(sizeof(struct gzFile_s)); if (gz == NULL) return NULL; gz->write = strchr(mode, 'w') != NULL; gz->strm.zalloc = myalloc; gz->strm.zfree = myfree; gz->strm.opaque = Z_NULL; if (gz->write) ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0); else { gz->strm.next_in = 0; gz->strm.avail_in = Z_NULL; ret = inflateInit2(&(gz->strm), 15 + 16); } if (ret != Z_OK) { free(gz); return NULL; } gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") : fopen(path, gz->write ? "wb" : "rb"); if (gz->file == NULL) { gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm)); free(gz); return NULL; } gz->err = 0; gz->msg = ""; return gz; } int gzwrite OF((gzFile, const void *, unsigned)); int gzwrite(gz, buf, len) gzFile gz; const void *buf; unsigned len; { z_stream *strm; unsigned char out[BUFLEN]; if (gz == NULL || !gz->write) return 0; strm = &(gz->strm); strm->next_in = (void *)buf; strm->avail_in = len; do { strm->next_out = out; strm->avail_out = BUFLEN; (void)deflate(strm, Z_NO_FLUSH); fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); } while (strm->avail_out == 0); return len; } int gzread OF((gzFile, void *, unsigned)); int gzread(gz, buf, len) gzFile gz; void *buf; unsigned len; { int ret; unsigned got; unsigned char in[1]; z_stream *strm; if (gz == NULL || gz->write) return 0; if (gz->err) return 0; strm = &(gz->strm); strm->next_out = (void *)buf; strm->avail_out = len; do { got = fread(in, 1, 1, gz->file); if (got == 0) break; strm->next_in = in; strm->avail_in = 1; ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_DATA_ERROR) { gz->err = Z_DATA_ERROR; gz->msg = strm->msg; return 0; } if (ret == Z_STREAM_END) inflateReset(strm); } while (strm->avail_out); return len - strm->avail_out; } int gzclose OF((gzFile)); int gzclose(gz) gzFile gz; { z_stream *strm; unsigned char out[BUFLEN]; if (gz == NULL) return Z_STREAM_ERROR; strm = &(gz->strm); if (gz->write) { strm->next_in = Z_NULL; strm->avail_in = 0; do { strm->next_out = out; strm->avail_out = BUFLEN; (void)deflate(strm, Z_FINISH); fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); } while (strm->avail_out == 0); deflateEnd(strm); } else inflateEnd(strm); fclose(gz->file); free(gz); return Z_OK; } const char *gzerror OF((gzFile, int *)); const char *gzerror(gz, err) gzFile gz; int *err; { *err = gz->err; return gz->msg; } #endif char *prog; void error OF((const char *msg)); void gz_compress OF((FILE *in, gzFile out)); #ifdef USE_MMAP int gz_compress_mmap OF((FILE *in, gzFile out)); #endif void gz_uncompress OF((gzFile in, FILE *out)); void file_compress OF((char *file, char *mode)); void file_uncompress OF((char *file)); int main OF((int argc, char *argv[])); /* =========================================================================== * Display error message and exit */ void error(msg) const char *msg; { fprintf(stderr, "%s: %s\n", prog, msg); exit(1); } /* =========================================================================== * Compress input to output then close both files. */ void gz_compress(in, out) FILE *in; gzFile out; { local char buf[BUFLEN]; int len; int err; #ifdef USE_MMAP /* Try first compressing with mmap. If mmap fails (minigzip used in a * pipe), use the normal fread loop. */ if (gz_compress_mmap(in, out) == Z_OK) return; #endif for (;;) { len = (int)fread(buf, 1, sizeof(buf), in); if (ferror(in)) { perror("fread"); exit(1); } if (len == 0) break; if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); } fclose(in); if (gzclose(out) != Z_OK) error("failed gzclose"); } #ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ /* Try compressing the input file at once using mmap. Return Z_OK if * if success, Z_ERRNO otherwise. */ int gz_compress_mmap(in, out) FILE *in; gzFile out; { int len; int err; int ifd = fileno(in); caddr_t buf; /* mmap'ed buffer for the entire input file */ off_t buf_len; /* length of the input file */ struct stat sb; /* Determine the size of the file, needed for mmap: */ if (fstat(ifd, &sb) < 0) return Z_ERRNO; buf_len = sb.st_size; if (buf_len <= 0) return Z_ERRNO; /* Now do the actual mmap: */ buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); if (buf == (caddr_t)(-1)) return Z_ERRNO; /* Compress the whole file at once: */ len = gzwrite(out, (char *)buf, (unsigned)buf_len); if (len != (int)buf_len) error(gzerror(out, &err)); munmap(buf, buf_len); fclose(in); if (gzclose(out) != Z_OK) error("failed gzclose"); return Z_OK; } #endif /* USE_MMAP */ /* =========================================================================== * Uncompress input to output then close both files. */ void gz_uncompress(in, out) gzFile in; FILE *out; { local char buf[BUFLEN]; int len; int err; for (;;) { len = gzread(in, buf, sizeof(buf)); if (len < 0) error (gzerror(in, &err)); if (len == 0) break; if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { error("failed fwrite"); } } if (fclose(out)) error("failed fclose"); if (gzclose(in) != Z_OK) error("failed gzclose"); } /* =========================================================================== * Compress the given file: create a corresponding .gz file and remove the * original. */ void file_compress(file, mode) char *file; char *mode; { local char outfile[MAX_NAME_LEN]; FILE *in; gzFile out; if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { fprintf(stderr, "%s: filename too long\n", prog); exit(1); } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX); #else strcpy(outfile, file); strcat(outfile, GZ_SUFFIX); #endif in = fopen(file, "rb"); if (in == NULL) { perror(file); exit(1); } out = gzopen(outfile, mode); if (out == NULL) { fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); exit(1); } gz_compress(in, out); unlink(file); } /* =========================================================================== * Uncompress the given file and remove the original. */ void file_uncompress(file) char *file; { local char buf[MAX_NAME_LEN]; char *infile, *outfile; FILE *out; gzFile in; size_t len = strlen(file); if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { fprintf(stderr, "%s: filename too long\n", prog); exit(1); } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(buf, sizeof(buf), "%s", file); #else strcpy(buf, file); #endif if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { infile = file; outfile = buf; outfile[len-3] = '\0'; } else { outfile = file; infile = buf; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX); #else strcat(infile, GZ_SUFFIX); #endif } in = gzopen(infile, "rb"); if (in == NULL) { fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); exit(1); } out = fopen(outfile, "wb"); if (out == NULL) { perror(file); exit(1); } gz_uncompress(in, out); unlink(infile); } /* =========================================================================== * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...] * -c : write to standard output * -d : decompress * -f : compress with Z_FILTERED * -h : compress with Z_HUFFMAN_ONLY * -r : compress with Z_RLE * -1 to -9 : compression level */ int main(argc, argv) int argc; char *argv[]; { int copyout = 0; int uncompr = 0; gzFile file; char *bname, outmode[20]; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(outmode, sizeof(outmode), "%s", "wb6 "); #else strcpy(outmode, "wb6 "); #endif prog = argv[0]; bname = strrchr(argv[0], '/'); if (bname) bname++; else bname = argv[0]; argc--, argv++; if (!strcmp(bname, "gunzip")) uncompr = 1; else if (!strcmp(bname, "zcat")) copyout = uncompr = 1; while (argc > 0) { if (strcmp(*argv, "-c") == 0) copyout = 1; else if (strcmp(*argv, "-d") == 0) uncompr = 1; else if (strcmp(*argv, "-f") == 0) outmode[3] = 'f'; else if (strcmp(*argv, "-h") == 0) outmode[3] = 'h'; else if (strcmp(*argv, "-r") == 0) outmode[3] = 'R'; else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && (*argv)[2] == 0) outmode[2] = (*argv)[1]; else break; argc--, argv++; } if (outmode[3] == ' ') outmode[3] = 0; if (argc == 0) { SET_BINARY_MODE(stdin); SET_BINARY_MODE(stdout); if (uncompr) { file = gzdopen(fileno(stdin), "rb"); if (file == NULL) error("can't gzdopen stdin"); gz_uncompress(file, stdout); } else { file = gzdopen(fileno(stdout), outmode); if (file == NULL) error("can't gzdopen stdout"); gz_compress(stdin, file); } } else { if (copyout) { SET_BINARY_MODE(stdout); } do { if (uncompr) { if (copyout) { file = gzopen(*argv, "rb"); if (file == NULL) fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv); else gz_uncompress(file, stdout); } else { file_uncompress(*argv); } } else { if (copyout) { FILE * in = fopen(*argv, "rb"); if (in == NULL) { perror(*argv); } else { file = gzdopen(fileno(stdout), outmode); if (file == NULL) error("can't gzdopen stdout"); gz_compress(in, file); } } else { file_compress(*argv, outmode); } } } while (argv++, --argc); } return 0; } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/gzread.c0000664000175000017500000004440612776215007020501 0ustar kaikai/* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); local int gz_avail OF((gz_statep)); local int gz_look OF((gz_statep)); local int gz_decomp OF((gz_statep)); local int gz_fetch OF((gz_statep)); local int gz_skip OF((gz_statep, z_off64_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ local int gz_load(state, buf, len, have) gz_statep state; unsigned char *buf; unsigned len; unsigned *have; { int ret; *have = 0; do { ret = read(state->fd, buf + *have, len - *have); if (ret <= 0) break; *have += ret; } while (*have < len); if (ret < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (ret == 0) state->eof = 1; return 0; } /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ local int gz_avail(state) gz_statep state; { unsigned got; z_streamp strm = &(state->strm); if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; if (state->eof == 0) { if (strm->avail_in) { /* copy what's there to the start */ unsigned char *p = state->in; unsigned const char *q = strm->next_in; unsigned n = strm->avail_in; do { *p++ = *q++; } while (--n); } if (gz_load(state, state->in + strm->avail_in, state->size - strm->avail_in, &got) == -1) return -1; strm->avail_in += got; strm->next_in = state->in; } return 0; } /* Look for gzip header, set up for inflate or copy. state->x.have must be 0. If this is the first time in, allocate required memory. state->how will be left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ local int gz_look(state) gz_statep state; { z_streamp strm = &(state->strm); /* allocate read buffers and inflate memory */ if (state->size == 0) { /* allocate buffers */ state->in = (unsigned char *)malloc(state->want); state->out = (unsigned char *)malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { if (state->out != NULL) free(state->out); if (state->in != NULL) free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } state->size = state->want; /* allocate inflate memory */ state->strm.zalloc = Z_NULL; state->strm.zfree = Z_NULL; state->strm.opaque = Z_NULL; state->strm.avail_in = 0; state->strm.next_in = Z_NULL; if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ free(state->out); free(state->in); state->size = 0; gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* get at least the magic bytes in the input buffer */ if (strm->avail_in < 2) { if (gz_avail(state) == -1) return -1; if (strm->avail_in == 0) return 0; } /* look for gzip magic bytes -- if there, do gzip decoding (note: there is a logical dilemma here when considering the case of a partially written gzip file, to wit, if a single 31 byte is written, then we cannot tell whether this is a single-byte file, or just a partially written gzip file -- for here we assume that if a gzip file is being written, then the header will be written in a single operation, so that reading a single byte is sufficient indication that it is not a gzip file) */ if (strm->avail_in > 1 && strm->next_in[0] == 31 && strm->next_in[1] == 139) { inflateReset(strm); state->how = GZIP; state->direct = 0; return 0; } /* no gzip header -- if we were decoding gzip before, then this is trailing garbage. Ignore the trailing garbage and finish. */ if (state->direct == 0) { strm->avail_in = 0; state->eof = 1; state->x.have = 0; return 0; } /* doing raw i/o, copy any leftover input to output -- this assumes that the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; if (strm->avail_in) { memcpy(state->x.next, strm->next_in, strm->avail_in); state->x.have = strm->avail_in; strm->avail_in = 0; } state->how = COPY; state->direct = 1; return 0; } /* Decompress from input to the provided next_out and avail_out in the state. On return, state->x.have and state->x.next point to the just decompressed data. If the gzip stream completes, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->x.have is depleted. Returns 0 on success, -1 on failure. */ local int gz_decomp(state) gz_statep state; { int ret = Z_OK; unsigned had; z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ had = strm->avail_out; do { /* get more input for inflate() */ if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in == 0) { gz_error(state, Z_BUF_ERROR, "unexpected end of file"); break; } /* decompress and handle errors */ ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { gz_error(state, Z_STREAM_ERROR, "internal error: inflate stream corrupt"); return -1; } if (ret == Z_MEM_ERROR) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ gz_error(state, Z_DATA_ERROR, strm->msg == NULL ? "compressed data error" : strm->msg); return -1; } } while (strm->avail_out && ret != Z_STREAM_END); /* update available output */ state->x.have = had - strm->avail_out; state->x.next = strm->next_out - state->x.have; /* if the gzip stream completed successfully, look for another */ if (ret == Z_STREAM_END) state->how = LOOK; /* good decompression */ return 0; } /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ local int gz_fetch(state) gz_statep state; { z_streamp strm = &(state->strm); do { switch(state->how) { case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ if (gz_look(state) == -1) return -1; if (state->how == LOOK) return 0; break; case COPY: /* -> COPY */ if (gz_load(state, state->out, state->size << 1, &(state->x.have)) == -1) return -1; state->x.next = state->out; return 0; case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ strm->avail_out = state->size << 1; strm->next_out = state->out; if (gz_decomp(state) == -1) return -1; } } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ local int gz_skip(state, len) gz_statep state; z_off64_t len; { unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ while (len) /* skip over whatever is in output buffer */ if (state->x.have) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? (unsigned)len : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; len -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) break; /* need more data to skip -- load up output buffer */ else { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; } return 0; } /* -- see zlib.h -- */ int ZEXPORT gzread(file, buf, len) gzFile file; voidp buf; unsigned len; { unsigned got, n; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return -1; } /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { /* first just try copying data from the output buffer */ if (state->x.have) { n = state->x.have > len ? len : state->x.have; memcpy(buf, state->x.next, n); state->x.next += n; state->x.have -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && strm->avail_in == 0) { state->past = 1; /* tried to read past end */ break; } /* need output data -- for small len or new stream load up our output buffer */ else if (state->how == LOOK || len < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; continue; /* no progress yet -- go back to copy above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ } /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ if (gz_load(state, (unsigned char *)buf, len, &n) == -1) return -1; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ strm->avail_out = len; strm->next_out = (unsigned char *)buf; if (gz_decomp(state) == -1) return -1; n = state->x.have; state->x.have = 0; } /* update progress */ len -= n; buf = (char *)buf + n; got += n; state->x.pos += n; } while (len); /* return number of bytes read into user buffer (will fit in int) */ return (int)got; } /* -- see zlib.h -- */ #ifdef Z_PREFIX_SET # undef z_gzgetc #else # undef gzgetc #endif int ZEXPORT gzgetc(file) gzFile file; { int ret; unsigned char buf[1]; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* try output buffer (no need to check for skip request) */ if (state->x.have) { state->x.have--; state->x.pos++; return *(state->x.next)++; } /* nothing there -- try gzread() */ ret = gzread(file, buf, 1); return ret < 1 ? -1 : buf[0]; } int ZEXPORT gzgetc_(file) gzFile file; { return gzgetc(file); } /* -- see zlib.h -- */ int ZEXPORT gzungetc(c, file) int c; gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* can't push EOF */ if (c < 0) return -1; /* if output buffer empty, put byte at end (allows more pushing) */ if (state->x.have == 0) { state->x.have = 1; state->x.next = state->out + (state->size << 1) - 1; state->x.next[0] = c; state->x.pos--; state->past = 0; return c; } /* if no room, give up (must have already done a gzungetc()) */ if (state->x.have == (state->size << 1)) { gz_error(state, Z_DATA_ERROR, "out of room to push characters"); return -1; } /* slide output data if needed and insert byte before existing data */ if (state->x.next == state->out) { unsigned char *src = state->out + state->x.have; unsigned char *dest = state->out + (state->size << 1); while (src > state->out) *--dest = *--src; state->x.next = dest; } state->x.have++; state->x.next--; state->x.next[0] = c; state->x.pos--; state->past = 0; return c; } /* -- see zlib.h -- */ char * ZEXPORT gzgets(file, buf, len) gzFile file; char *buf; int len; { unsigned left, n; char *str; unsigned char *eol; gz_statep state; /* check parameters and get internal structure */ if (file == NULL || buf == NULL || len < 1) return NULL; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return NULL; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return NULL; } /* copy output bytes up to new line or len - 1, whichever comes first -- append a terminating zero to the string (we don't check for a zero in the contents, let the user worry about that) */ str = buf; left = (unsigned)len - 1; if (left) do { /* assure that something is in the output buffer */ if (state->x.have == 0 && gz_fetch(state) == -1) return NULL; /* error */ if (state->x.have == 0) { /* end of file */ state->past = 1; /* read past end */ break; /* return what we have */ } /* look for end-of-line in current output buffer */ n = state->x.have > left ? left : state->x.have; eol = (unsigned char *)memchr(state->x.next, '\n', n); if (eol != NULL) n = (unsigned)(eol - state->x.next) + 1; /* copy through end-of-line, or remainder if not found */ memcpy(buf, state->x.next, n); state->x.have -= n; state->x.next += n; state->x.pos += n; left -= n; buf += n; } while (left && eol == NULL); /* return terminated string, or if nothing, end of file */ if (buf == str) return NULL; buf[0] = 0; return str; } /* -- see zlib.h -- */ int ZEXPORT gzdirect(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) (void)gz_look(state); /* return 1 if transparent, 0 if processing a gzip stream */ return state->direct; } /* -- see zlib.h -- */ int ZEXPORT gzclose_r(file) gzFile file; { int ret, err; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're reading */ if (state->mode != GZ_READ) return Z_STREAM_ERROR; /* free memory and close file */ if (state->size) { inflateEnd(&(state->strm)); free(state->out); free(state->in); } err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; gz_error(state, Z_OK, NULL); free(state->path); ret = close(state->fd); free(state); return ret ? Z_ERRNO : err; } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/crc32.h0000664000175000017500000007354212776215007020151 0ustar kaikai/* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const z_crc_t FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL #ifdef BYFOUR }, { 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, 0x9324fd72UL }, { 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, 0xbe9834edUL }, { 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, 0xde0506f1UL }, { 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, 0x8def022dUL }, { 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, 0x72fd2493UL }, { 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, 0xed3498beUL }, { 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, 0xf10605deUL #endif } }; ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/uncompr.c0000664000175000017500000000372312776215007020705 0ustar kaikai/* uncompr.c -- decompress a memory buffer * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the compressed buffer. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted. */ int ZEXPORT uncompress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { z_stream stream; int err; stream.next_in = (z_const Bytef *)source; stream.avail_in = (uInt)sourceLen; /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; err = inflateInit(&stream); if (err != Z_OK) return err; err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&stream); if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) return Z_DATA_ERROR; return err; } *destLen = stream.total_out; err = inflateEnd(&stream); return err; } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/osx.mak0000664000175000017500000000372412776215007020362 0ustar kaikai# Makefile for zlib MODEL=32 CC=gcc LD=link CFLAGS=-O -m$(MODEL) LDFLAGS= O=.o .c.o: $(CC) -c $(CFLAGS) $* .d.o: $(DMD) -c $(DFLAGS) $* # variables OBJS = adler32$(O) compress$(O) crc32$(O) deflate$(O) gzclose$(O) gzlib$(O) gzread$(O) \ gzwrite$(O) infback$(O) inffast$(O) inflate$(O) inftrees$(O) trees$(O) uncompr$(O) zutil$(O) all: zlib.a example minigzip adler32.o: zutil.h zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c zutil.o: zutil.h zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c gzclose.o: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c gzlib.o: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c gzread.o: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c gzwrite.o: zlib.h zconf.h gzguts.h $(CC) -c $(CFLAGS) $*.c compress.o: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c example.o: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c minigzip.o: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c uncompr.o: zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c crc32.o: zutil.h zlib.h zconf.h crc32.h $(CC) -c $(CFLAGS) $*.c deflate.o: deflate.h zutil.h zlib.h zconf.h $(CC) -c $(CFLAGS) $*.c infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h $(CC) -c $(CFLAGS) $*.c inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h $(CC) -c $(CFLAGS) $*.c inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h $(CC) -c $(CFLAGS) $*.c inftrees.o: zutil.h zlib.h zconf.h inftrees.h $(CC) -c $(CFLAGS) $*.c trees.o: deflate.h zutil.h zlib.h zconf.h trees.h $(CC) -c $(CFLAGS) $*.c example.o: example.c zlib.h zconf.h $(CC) -c $(cvarsdll) $(CFLAGS) $*.c minigzip.o: minigzip.c zlib.h zconf.h $(CC) -c $(cvarsdll) $(CFLAGS) $*.c zlib.a: $(OBJS) ar -r $@ $(OBJS) example: example.o zlib.a $(CC) $(CFLAGS) -o $@ example.o zlib.a -g minigzip: minigzip.o zlib.a $(CC) $(CFLAGS) -o $@ minigzip.o zlib.a -g test: example minigzip ./example echo hello world | minigzip | minigzip -d clean: $(RM) $(OBJS) zlib.a example.o example minigzip minigzip.o test foo.gz ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/inftrees.c0000664000175000017500000003134412776215007021041 0ustar kaikai/* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.2.8 Copyright 1995-2013 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) codetype type; unsigned short FAR *lens; unsigned codes; code FAR * FAR *table; unsigned FAR *bits; unsigned short FAR *work; { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ int end; /* use base and extra for symbol > end */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) count[len] = 0; for (sym = 0; sym < codes; sym++) count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; if (root > max) root = max; if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) if (count[min] != 0) break; if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ } if (left > 0 && (type == CODES || max != 1)) return -1; /* incomplete set */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ switch (type) { case CODES: base = extra = work; /* dummy value--not used */ end = 19; break; case LENS: base = lbase; base -= 257; extra = lext; extra -= 257; end = 256; break; default: /* DISTS */ base = dbase; extra = dext; end = -1; } /* initialize state for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = *table; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = (unsigned)(-1); /* trigger new sub-table when len > root */ used = 1U << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); if ((int)(work[sym]) < end) { here.op = (unsigned char)0; here.val = work[sym]; } else if ((int)(work[sym]) > end) { here.op = (unsigned char)(extra[work[sym]]); here.val = base[work[sym]]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = here; } while (fill != 0); /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { if (len == max) break; len = lens[work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) != low) { /* if first time, transition to sub-tables */ if (drop == 0) drop = root; /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; (*table)[low].val = (unsigned short)(next - *table); } } /* fill in remaining table entry if code is incomplete (guaranteed to have at most one remaining entry, since if the code is incomplete, the maximum code length that was allowed to get this far is one bit) */ if (huff != 0) { here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); here.val = (unsigned short)0; next[huff] = here; } /* set return parameters */ *table += used; *bits = root; return 0; } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/gzlib.c0000664000175000017500000004003712776215007020330 0ustar kaikai/* gzlib.c -- zlib functions common to reading and writing gzip files * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" #if defined(_WIN32) && !defined(__BORLANDC__) # define LSEEK _lseeki64 #else #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define LSEEK lseek64 #else # define LSEEK lseek #endif #endif /* Local functions */ local void gz_reset OF((gz_statep)); local gzFile gz_open OF((const void *, int, const char *)); #if defined UNDER_CE /* Map the Windows error number in ERROR to a locale-dependent error message string and return a pointer to it. Typically, the values for ERROR come from GetLastError. The string pointed to shall not be modified by the application, but may be overwritten by a subsequent call to gz_strwinerror The gz_strwinerror function does not change the current setting of GetLastError. */ char ZLIB_INTERNAL *gz_strwinerror (error) DWORD error; { static char buf[1024]; wchar_t *msgbuf; DWORD lasterr = GetLastError(); DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, 0, /* Default language */ (LPVOID)&msgbuf, 0, NULL); if (chars != 0) { /* If there is an \r\n appended, zap it. */ if (chars >= 2 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { chars -= 2; msgbuf[chars] = 0; } if (chars > sizeof (buf) - 1) { chars = sizeof (buf) - 1; msgbuf[chars] = 0; } wcstombs(buf, msgbuf, chars + 1); LocalFree(msgbuf); } else { sprintf(buf, "unknown win32 error (%ld)", error); } SetLastError(lasterr); return buf; } #endif /* UNDER_CE */ /* Reset gzip file state */ local void gz_reset(state) gz_statep state; { state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ state->eof = 0; /* not at end of file */ state->past = 0; /* have not read past end yet */ state->how = LOOK; /* look for gzip header */ } state->seek = 0; /* no seek request pending */ gz_error(state, Z_OK, NULL); /* clear error */ state->x.pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } /* Open a gzip file either by name or file descriptor. */ local gzFile gz_open(path, fd, mode) const void *path; int fd; const char *mode; { gz_statep state; size_t len; int oflag; #ifdef O_CLOEXEC int cloexec = 0; #endif #ifdef O_EXCL int exclusive = 0; #endif /* check input */ if (path == NULL) return NULL; /* allocate gzFile structure to return */ state = (gz_statep)malloc(sizeof(gz_state)); if (state == NULL) return NULL; state->size = 0; /* no buffers allocated yet */ state->want = GZBUFSIZE; /* requested buffer size */ state->msg = NULL; /* no error message yet */ /* interpret mode */ state->mode = GZ_NONE; state->level = Z_DEFAULT_COMPRESSION; state->strategy = Z_DEFAULT_STRATEGY; state->direct = 0; while (*mode) { if (*mode >= '0' && *mode <= '9') state->level = *mode - '0'; else switch (*mode) { case 'r': state->mode = GZ_READ; break; #ifndef NO_GZCOMPRESS case 'w': state->mode = GZ_WRITE; break; case 'a': state->mode = GZ_APPEND; break; #endif case '+': /* can't read and write at the same time */ free(state); return NULL; case 'b': /* ignore -- will request binary anyway */ break; #ifdef O_CLOEXEC case 'e': cloexec = 1; break; #endif #ifdef O_EXCL case 'x': exclusive = 1; break; #endif case 'f': state->strategy = Z_FILTERED; break; case 'h': state->strategy = Z_HUFFMAN_ONLY; break; case 'R': state->strategy = Z_RLE; break; case 'F': state->strategy = Z_FIXED; break; case 'T': state->direct = 1; break; default: /* could consider as an error, but just ignore */ ; } mode++; } /* must provide an "r", "w", or "a" */ if (state->mode == GZ_NONE) { free(state); return NULL; } /* can't force transparent read */ if (state->mode == GZ_READ) { if (state->direct) { free(state); return NULL; } state->direct = 1; /* for empty file */ } /* save the path name for error messages */ #ifdef _WIN32 if (fd == -2) { len = wcstombs(NULL, path, 0); if (len == (size_t)-1) len = 0; } else #endif len = strlen((const char *)path); state->path = (char *)malloc(len + 1); if (state->path == NULL) { free(state); return NULL; } #ifdef _WIN32 if (fd == -2) if (len) wcstombs(state->path, path, len + 1); else *(state->path) = 0; else #endif #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(state->path, len + 1, "%s", (const char *)path); #else strcpy(state->path, path); #endif /* compute the flags for open() */ oflag = #ifdef O_LARGEFILE O_LARGEFILE | #endif #ifdef O_BINARY O_BINARY | #endif #ifdef O_CLOEXEC (cloexec ? O_CLOEXEC : 0) | #endif (state->mode == GZ_READ ? O_RDONLY : (O_WRONLY | O_CREAT | #ifdef O_EXCL (exclusive ? O_EXCL : 0) | #endif (state->mode == GZ_WRITE ? O_TRUNC : O_APPEND))); /* open the file with the appropriate flags (or just use fd) */ state->fd = fd > -1 ? fd : ( #ifdef _WIN32 fd == -2 ? _wopen(path, oflag, 0666) : #endif open((const char *)path, oflag, 0666)); if (state->fd == -1) { free(state->path); free(state); return NULL; } if (state->mode == GZ_APPEND) state->mode = GZ_WRITE; /* simplify later checks */ /* save the current position for rewinding (only if reading) */ if (state->mode == GZ_READ) { state->start = LSEEK(state->fd, 0, SEEK_CUR); if (state->start == -1) state->start = 0; } /* initialize stream */ gz_reset(state); /* return stream */ return (gzFile)state; } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen64(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzdopen(fd, mode) int fd; const char *mode; { char *path; /* identifier for error messages */ gzFile gz; if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ #else sprintf(path, "", fd); /* for debugging */ #endif gz = gz_open(path, fd, mode); free(path); return gz; } /* -- see zlib.h -- */ #ifdef _WIN32 gzFile ZEXPORT gzopen_w(path, mode) const wchar_t *path; const char *mode; { return gz_open(path, -2, mode); } #endif /* -- see zlib.h -- */ int ZEXPORT gzbuffer(file, size) gzFile file; unsigned size; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* make sure we haven't already allocated memory */ if (state->size != 0) return -1; /* check and set requested size */ if (size < 2) size = 2; /* need two bytes to check magic header */ state->want = size; return 0; } /* -- see zlib.h -- */ int ZEXPORT gzrewind(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* back up and start over */ if (LSEEK(state->fd, state->start, SEEK_SET) == -1) return -1; gz_reset(state); return 0; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzseek64(file, offset, whence) gzFile file; z_off64_t offset; int whence; { unsigned n; z_off64_t ret; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* check that there's no error */ if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* can only seek from start or relative to current position */ if (whence != SEEK_SET && whence != SEEK_CUR) return -1; /* normalize offset to a SEEK_CUR specification */ if (whence == SEEK_SET) offset -= state->x.pos; else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); if (ret == -1) return -1; state->x.have = 0; state->eof = 0; state->past = 0; state->seek = 0; gz_error(state, Z_OK, NULL); state->strm.avail_in = 0; state->x.pos += offset; return state->x.pos; } /* calculate skip amount, rewinding if needed for back seek when reading */ if (offset < 0) { if (state->mode != GZ_READ) /* writing -- can't go backwards */ return -1; offset += state->x.pos; if (offset < 0) /* before start of file! */ return -1; if (gzrewind(file) == -1) /* rewind, then skip to offset */ return -1; } /* if reading, skip what's in output buffer (one less gzgetc() check) */ if (state->mode == GZ_READ) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; offset -= n; } /* request skip (if not zero) */ if (offset) { state->seek = 1; state->skip = offset; } return state->x.pos + offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzseek(file, offset, whence) gzFile file; z_off_t offset; int whence; { z_off64_t ret; ret = gzseek64(file, (z_off64_t)offset, whence); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gztell64(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* return position */ return state->x.pos + (state->seek ? state->skip : 0); } /* -- see zlib.h -- */ z_off_t ZEXPORT gztell(file) gzFile file; { z_off64_t ret; ret = gztell64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzoffset64(file) gzFile file; { z_off64_t offset; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* compute and return effective offset in file */ offset = LSEEK(state->fd, 0, SEEK_CUR); if (offset == -1) return -1; if (state->mode == GZ_READ) /* reading */ offset -= state->strm.avail_in; /* don't count buffered input */ return offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzoffset(file) gzFile file; { z_off64_t ret; ret = gzoffset64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ int ZEXPORT gzeof(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return 0; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return 0; /* return end-of-file state */ return state->mode == GZ_READ ? state->past : 0; } /* -- see zlib.h -- */ const char * ZEXPORT gzerror(file, errnum) gzFile file; int *errnum; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return NULL; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return NULL; /* return error information */ if (errnum != NULL) *errnum = state->err; return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); } /* -- see zlib.h -- */ void ZEXPORT gzclearerr(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return; /* clear error and end-of-file */ if (state->mode == GZ_READ) { state->eof = 0; state->past = 0; } gz_error(state, Z_OK, NULL); } /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ void ZLIB_INTERNAL gz_error(state, err, msg) gz_statep state; int err; const char *msg; { /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) free(state->msg); state->msg = NULL; } /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ if (err != Z_OK && err != Z_BUF_ERROR) state->x.have = 0; /* set error code, and if no message, then done */ state->err = err; if (msg == NULL) return; /* for an out of memory error, return literal string when requested */ if (err == Z_MEM_ERROR) return; /* construct error message with path */ if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { state->err = Z_MEM_ERROR; return; } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg); #else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); #endif return; } #ifndef INT_MAX /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ unsigned ZLIB_INTERNAL gz_intmax() { unsigned p, q; p = 1; do { q = p; p <<= 1; p++; } while (p > q); return q >> 1; } #endif ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/inftrees.h0000664000175000017500000000556012776215007021047 0ustar kaikai/* inftrees.h -- header to use inftrees.c * Copyright (C) 1995-2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* Structure for decoding tables. Each entry provides either the information needed to do the operation requested by the code that indexed that table entry, or it provides a pointer to another table that indexes more bits of the code. op indicates whether the entry is a pointer to another table, a literal, a length or distance, an end-of-block, or an invalid code. For a table pointer, the low four bits of op is the number of index bits of that table. For a length or distance, the low four bits of op is the number of extra bits to get after the code. bits is the number of bits in this code or part of the code to drop off of the bit buffer. val is the actual byte to output in the case of a literal, the base length or distance, or the offset from the current table to the next table. Each entry is four bytes. */ typedef struct { unsigned char op; /* operation, extra bits, table bits */ unsigned char bits; /* bits in this part of the code */ unsigned short val; /* offset in table or code value */ } code; /* op values as set by inflate_table(): 00000000 - literal 0000tttt - table link, tttt != 0 is the number of table index bits 0001eeee - length or distance, eeee is the number of extra bits 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribtution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table() */ typedef enum { CODES, LENS, DISTS } codetype; int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work)); ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/algorithm.txt0000664000175000017500000002216712776215007021610 0ustar kaikai1. Compression algorithm (deflate) The deflation algorithm used by gzip (also zip and zlib) is a variation of LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in the input data. The second occurrence of a string is replaced by a pointer to the previous string, in the form of a pair (distance, length). Distances are limited to 32K bytes, and lengths are limited to 258 bytes. When a string does not occur anywhere in the previous 32K bytes, it is emitted as a sequence of literal bytes. (In this description, `string' must be taken as an arbitrary sequence of bytes, and is not restricted to printable characters.) Literals or match lengths are compressed with one Huffman tree, and match distances are compressed with another tree. The trees are stored in a compact form at the start of each block. The blocks can have any size (except that the compressed data for one block must fit in available memory). A block is terminated when deflate() determines that it would be useful to start another block with fresh trees. (This is somewhat similar to the behavior of LZW-based _compress_.) Duplicated strings are found using a hash table. All input strings of length 3 are inserted in the hash table. A hash index is computed for the next 3 bytes. If the hash chain for this index is not empty, all strings in the chain are compared with the current input string, and the longest match is selected. The hash chains are searched starting with the most recent strings, to favor small distances and thus take advantage of the Huffman encoding. The hash chains are singly linked. There are no deletions from the hash chains, the algorithm simply discards matches that are too old. To avoid a worst-case situation, very long hash chains are arbitrarily truncated at a certain length, determined by a runtime option (level parameter of deflateInit). So deflate() does not always find the longest possible match but generally finds a match which is long enough. deflate() also defers the selection of matches with a lazy evaluation mechanism. After a match of length N has been found, deflate() searches for a longer match at the next input byte. If a longer match is found, the previous match is truncated to a length of one (thus producing a single literal byte) and the process of lazy evaluation begins again. Otherwise, the original match is kept, and the next match search is attempted only N steps later. The lazy match evaluation is also subject to a runtime parameter. If the current match is long enough, deflate() reduces the search for a longer match, thus speeding up the whole process. If compression ratio is more important than speed, deflate() attempts a complete second search even if the first match is already long enough. The lazy match evaluation is not performed for the fastest compression modes (level parameter 1 to 3). For these fast modes, new strings are inserted in the hash table only when no match was found, or when the match is not too long. This degrades the compression ratio but saves time since there are both fewer insertions and fewer searches. 2. Decompression algorithm (inflate) 2.1 Introduction The key question is how to represent a Huffman code (or any prefix code) so that you can decode fast. The most important characteristic is that shorter codes are much more common than longer codes, so pay attention to decoding the short codes fast, and let the long codes take longer to decode. inflate() sets up a first level table that covers some number of bits of input less than the length of longest code. It gets that many bits from the stream, and looks it up in the table. The table will tell if the next code is that many bits or less and how many, and if it is, it will tell the value, else it will point to the next level table for which inflate() grabs more bits and tries to decode a longer code. How many bits to make the first lookup is a tradeoff between the time it takes to decode and the time it takes to build the table. If building the table took no time (and if you had infinite memory), then there would only be a first level table to cover all the way to the longest code. However, building the table ends up taking a lot longer for more bits since short codes are replicated many times in such a table. What inflate() does is simply to make the number of bits in the first table a variable, and then to set that variable for the maximum speed. For inflate, which has 286 possible codes for the literal/length tree, the size of the first table is nine bits. Also the distance trees have 30 possible values, and the size of the first table is six bits. Note that for each of those cases, the table ended up one bit longer than the ``average'' code length, i.e. the code length of an approximately flat code which would be a little more than eight bits for 286 symbols and a little less than five bits for 30 symbols. 2.2 More details on the inflate table lookup Ok, you want to know what this cleverly obfuscated inflate tree actually looks like. You are correct that it's not a Huffman tree. It is simply a lookup table for the first, let's say, nine bits of a Huffman symbol. The symbol could be as short as one bit or as long as 15 bits. If a particular symbol is shorter than nine bits, then that symbol's translation is duplicated in all those entries that start with that symbol's bits. For example, if the symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a symbol is nine bits long, it appears in the table once. If the symbol is longer than nine bits, then that entry in the table points to another similar table for the remaining bits. Again, there are duplicated entries as needed. The idea is that most of the time the symbol will be short and there will only be one table look up. (That's whole idea behind data compression in the first place.) For the less frequent long symbols, there will be two lookups. If you had a compression method with really long symbols, you could have as many levels of lookups as is efficient. For inflate, two is enough. So a table entry either points to another table (in which case nine bits in the above example are gobbled), or it contains the translation for the symbol and the number of bits to gobble. Then you start again with the next ungobbled bit. You may wonder: why not just have one lookup table for how ever many bits the longest symbol is? The reason is that if you do that, you end up spending more time filling in duplicate symbol entries than you do actually decoding. At least for deflate's output that generates new trees every several 10's of kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code would take too long if you're only decoding several thousand symbols. At the other extreme, you could make a new table for every bit in the code. In fact, that's essentially a Huffman tree. But then you spend too much time traversing the tree while decoding, even for short symbols. So the number of bits for the first lookup table is a trade of the time to fill out the table vs. the time spent looking at the second level and above of the table. Here is an example, scaled down: The code being decoded, with 10 symbols, from 1 to 6 bits long: A: 0 B: 10 C: 1100 D: 11010 E: 11011 F: 11100 G: 11101 H: 11110 I: 111110 J: 111111 Let's make the first table three bits long (eight entries): 000: A,1 001: A,1 010: A,1 011: A,1 100: B,2 101: B,2 110: -> table X (gobble 3 bits) 111: -> table Y (gobble 3 bits) Each entry is what the bits decode as and how many bits that is, i.e. how many bits to gobble. Or the entry points to another table, with the number of bits to gobble implicit in the size of the table. Table X is two bits long since the longest code starting with 110 is five bits long: 00: C,1 01: C,1 10: D,2 11: E,2 Table Y is three bits long since the longest code starting with 111 is six bits long: 000: F,2 001: F,2 010: G,2 011: G,2 100: H,2 101: H,2 110: I,3 111: J,3 So what we have here are three tables with a total of 20 entries that had to be constructed. That's compared to 64 entries for a single table. Or compared to 16 entries for a Huffman tree (six two entry tables and one four entry table). Assuming that the code ideally represents the probability of the symbols, it takes on the average 1.25 lookups per symbol. That's compared to one lookup for the single table, or 1.66 lookups per symbol for the Huffman tree. There, I think that gives you a picture of what's going on. For inflate, the meaning of a particular symbol is often more than just a letter. It can be a byte (a "literal"), or it can be either a length or a distance which indicates a base value and a number of bits to fetch after the code that is added to the base value. Or it might be the special end-of-block code. The data structures created in inftrees.c try to encode all that information compactly in the tables. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu References: [LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, pp. 337-343. ``DEFLATE Compressed Data Format Specification'' available in http://tools.ietf.org/html/rfc1951 ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/crc32.c0000664000175000017500000003156612776215007020144 0ustar kaikai/* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors * instead of four steps with four exclusive-ors. This results in about a * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. */ #ifdef MAKECRCH # include # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "zutil.h" /* for STDC and FAR definitions */ #define local static /* Definitions for doing the crc four data bytes at a time. */ #if !defined(NOBYFOUR) && defined(Z_U4) # define BYFOUR #endif #ifdef BYFOUR local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, unsigned)); local unsigned long crc32_big OF((unsigned long, const unsigned char FAR *, unsigned)); # define TBLS 8 #else # define TBLS 1 #endif /* BYFOUR */ /* Local functions for crc concatenation */ local unsigned long gf2_matrix_times OF((unsigned long *mat, unsigned long vec)); local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; local z_crc_t FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const z_crc_t FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The first table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. The remaining tables allow for word-at-a-time CRC calculation for both big-endian and little- endian machines, where a word is four bytes. */ local void make_crc_table() { z_crc_t c; int n, k; z_crc_t poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* See if another task is already doing this (not thread-safe, but better than nothing -- significantly reduces duration of vulnerability in case the advice about DYNAMIC_CRC_TABLE is ignored) */ if (first) { first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ poly = 0; for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) poly |= (z_crc_t)1 << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { c = (z_crc_t)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; } #ifdef BYFOUR /* generate crc for each value followed by one, two, and three zeros, and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; crc_table[4][n] = ZSWAP32(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; crc_table[k + 4][n] = ZSWAP32(c); } } #endif /* BYFOUR */ crc_table_empty = 0; } else { /* not first */ /* wait for the other guy to finish (not efficient, but rare) */ while (crc_table_empty) ; } #ifdef MAKECRCH /* write out CRC tables to crc32.h */ { FILE *out; out = fopen("crc32.h", "w"); if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); fprintf(out, "local const z_crc_t FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR fprintf(out, "#ifdef BYFOUR\n"); for (k = 1; k < 8; k++) { fprintf(out, " },\n {\n"); write_table(out, crc_table[k]); } fprintf(out, "#endif\n"); # endif /* BYFOUR */ fprintf(out, " }\n};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH local void write_table(out, table) FILE *out; const z_crc_t FAR *table; { int n; for (n = 0; n < 256; n++) fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", (unsigned long)(table[n]), n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ #include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32() */ const z_crc_t FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ return (const z_crc_t FAR *)crc_table; } /* ========================================================================= */ #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ unsigned long ZEXPORT crc32(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; uInt len; { if (buf == Z_NULL) return 0UL; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { z_crc_t endian; endian = 1; if (*((unsigned char *)(&endian))) return crc32_little(crc, buf, len); else return crc32_big(crc, buf, len); } #endif /* BYFOUR */ crc = crc ^ 0xffffffffUL; while (len >= 8) { DO8; len -= 8; } if (len) do { DO1; } while (--len); return crc ^ 0xffffffffUL; } #ifdef BYFOUR /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 /* ========================================================================= */ local unsigned long crc32_little(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = (z_crc_t)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; } while (len >= 4) { DOLIT4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); } while (--len); c = ~c; return (unsigned long)c; } /* ========================================================================= */ #define DOBIG4 c ^= *++buf4; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 /* ========================================================================= */ local unsigned long crc32_big(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = ZSWAP32((z_crc_t)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; buf4--; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf4++; buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; return (unsigned long)(ZSWAP32(c)); } #endif /* BYFOUR */ #define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ /* ========================================================================= */ local unsigned long gf2_matrix_times(mat, vec) unsigned long *mat; unsigned long vec; { unsigned long sum; sum = 0; while (vec) { if (vec & 1) sum ^= *mat; vec >>= 1; mat++; } return sum; } /* ========================================================================= */ local void gf2_matrix_square(square, mat) unsigned long *square; unsigned long *mat; { int n; for (n = 0; n < GF2_DIM; n++) square[n] = gf2_matrix_times(mat, mat[n]); } /* ========================================================================= */ local uLong crc32_combine_(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { int n; unsigned long row; unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ /* degenerate case (also disallow negative lengths) */ if (len2 <= 0) return crc1; /* put operator for one zero bit in odd */ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ row = 1; for (n = 1; n < GF2_DIM; n++) { odd[n] = row; row <<= 1; } /* put operator for two zero bits in even */ gf2_matrix_square(even, odd); /* put operator for four zero bits in odd */ gf2_matrix_square(odd, even); /* apply len2 zeros to crc1 (first square will put the operator for one zero byte, eight zero bits, in even) */ do { /* apply zeros operator for this bit of len2 */ gf2_matrix_square(even, odd); if (len2 & 1) crc1 = gf2_matrix_times(even, crc1); len2 >>= 1; /* if no more bits set, then done */ if (len2 == 0) break; /* another iteration of the loop with odd and even swapped */ gf2_matrix_square(odd, even); if (len2 & 1) crc1 = gf2_matrix_times(odd, crc1); len2 >>= 1; /* if no more bits set, then done */ } while (len2 != 0); /* return combined crc */ crc1 ^= crc2; return crc1; } /* ========================================================================= */ uLong ZEXPORT crc32_combine(crc1, crc2, len2) uLong crc1; uLong crc2; z_off_t len2; { return crc32_combine_(crc1, crc2, len2); } uLong ZEXPORT crc32_combine64(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { return crc32_combine_(crc1, crc2, len2); } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/zlib.30000664000175000017500000001021412776215007020073 0ustar kaikai.TH ZLIB 3 "28 Apr 2013" .SH NAME zlib \- compression/decompression library .SH SYNOPSIS [see .I zlib.h for full description] .SH DESCRIPTION The .I zlib library is a general purpose data compression library. The code is thread safe, assuming that the standard library functions used are thread safe, such as memory allocation routines. It provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms may be added later with the same stream interface. .LP Compression can be done in a single step if the buffers are large enough or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. .LP The library also supports reading and writing files in .IR gzip (1) (.gz) format with an interface similar to that of stdio. .LP The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in the case of corrupted input. .LP All functions of the compression library are documented in the file .IR zlib.h . The distribution source includes examples of use of the library in the files .I test/example.c and .IR test/minigzip.c, as well as other examples in the .IR examples/ directory. .LP Changes to this version are documented in the file .I ChangeLog that accompanies the source. .LP .I zlib is available in Java using the java.util.zip package: .IP http://java.sun.com/developer/technicalArticles/Programming/compression/ .LP A Perl interface to .IR zlib , written by Paul Marquess (pmqs@cpan.org), is available at CPAN (Comprehensive Perl Archive Network) sites, including: .IP http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .LP A Python interface to .IR zlib , written by A.M. Kuchling (amk@magnet.com), is available in Python 1.5 and later versions: .IP http://docs.python.org/library/zlib.html .LP .I zlib is built into .IR tcl: .IP http://wiki.tcl.tk/4610 .LP An experimental package to read and write files in .zip format, written on top of .I zlib by Gilles Vollant (info@winimage.com), is available at: .IP http://www.winimage.com/zLibDll/minizip.html and also in the .I contrib/minizip directory of the main .I zlib source distribution. .SH "SEE ALSO" The .I zlib web site can be found at: .IP http://zlib.net/ .LP The data format used by the zlib library is described by RFC (Request for Comments) 1950 to 1952 in the files: .IP http://tools.ietf.org/html/rfc1950 (for the zlib header and trailer format) .br http://tools.ietf.org/html/rfc1951 (for the deflate compressed data format) .br http://tools.ietf.org/html/rfc1952 (for the gzip header and trailer format) .LP Mark Nelson wrote an article about .I zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at: .IP http://marknelson.us/1997/01/01/zlib-engine/ .SH "REPORTING PROBLEMS" Before reporting a problem, please check the .I zlib web site to verify that you have the latest version of .IR zlib ; otherwise, obtain the latest version and see if the problem still exists. Please read the .I zlib FAQ at: .IP http://zlib.net/zlib_faq.html .LP before asking for help. Send questions and/or comments to zlib@gzip.org, or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). .SH AUTHORS Version 1.2.8 Copyright (C) 1995-2013 Jean-loup Gailly (jloup@gzip.org) and Mark Adler (madler@alumni.caltech.edu). .LP 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. See the distribution directory with respect to requirements governing redistribution. The deflate format used by .I zlib was defined by Phil Katz. The deflate and .I zlib specifications were written by L. Peter Deutsch. Thanks to all the people who reported problems and suggested various improvements in .IR zlib ; who are too numerous to cite here. .LP UNIX manual page by R. P. C. Rodgers, U.S. National Library of Medicine (rodgers@nlm.nih.gov). .\" end of man page ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/zutil.c0000664000175000017500000001636612776215007020400 0ustar kaikai/* zutil.c -- target dependent utility functions for the compression library * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #ifndef Z_SOLO # include "gzguts.h" #endif #ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ #endif z_const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */ "file error", /* Z_ERRNO (-1) */ "stream error", /* Z_STREAM_ERROR (-2) */ "data error", /* Z_DATA_ERROR (-3) */ "insufficient memory", /* Z_MEM_ERROR (-4) */ "buffer error", /* Z_BUF_ERROR (-5) */ "incompatible version",/* Z_VERSION_ERROR (-6) */ ""}; const char * ZEXPORT zlibVersion() { return ZLIB_VERSION; } uLong ZEXPORT zlibCompileFlags() { uLong flags; flags = 0; switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; default: flags += 3; } switch ((int)(sizeof(uLong))) { case 2: break; case 4: flags += 1 << 2; break; case 8: flags += 2 << 2; break; default: flags += 3 << 2; } switch ((int)(sizeof(voidpf))) { case 2: break; case 4: flags += 1 << 4; break; case 8: flags += 2 << 4; break; default: flags += 3 << 4; } switch ((int)(sizeof(z_off_t))) { case 2: break; case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef DEBUG flags += 1 << 8; #endif #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif #ifdef ZLIB_WINAPI flags += 1 << 10; #endif #ifdef BUILDFIXED flags += 1 << 12; #endif #ifdef DYNAMIC_CRC_TABLE flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS flags += 1L << 16; #endif #ifdef NO_GZIP flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND flags += 1L << 20; #endif #ifdef FASTEST flags += 1L << 21; #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifdef NO_vsnprintf flags += 1L << 25; # ifdef HAS_vsprintf_void flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void flags += 1L << 26; # endif # endif #else flags += 1L << 24; # ifdef NO_snprintf flags += 1L << 25; # ifdef HAS_sprintf_void flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void flags += 1L << 26; # endif # endif #endif return flags; } #ifdef DEBUG # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; void ZLIB_INTERNAL z_error (m) char *m; { fprintf(stderr, "%s\n", m); exit(1); } #endif /* exported to allow conversion of error code to string for compress() and * uncompress() */ const char * ZEXPORT zError(err) int err; { return ERR_MSG(err); } #if defined(_WIN32_WCE) /* The Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ int errno = 0; #endif #ifndef HAVE_MEMCPY void ZLIB_INTERNAL zmemcpy(dest, source, len) Bytef* dest; const Bytef* source; uInt len; { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } int ZLIB_INTERNAL zmemcmp(s1, s2, len) const Bytef* s1; const Bytef* s2; uInt len; { uInt j; for (j = 0; j < len; j++) { if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; } return 0; } void ZLIB_INTERNAL zmemzero(dest, len) Bytef* dest; uInt len; { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ } while (--len != 0); } #endif #ifndef Z_SOLO #ifdef SYS16BIT #ifdef __TURBOC__ /* Turbo C in 16-bit mode */ # define MY_ZCALLOC /* Turbo C malloc() does not allow dynamic allocation of 64K bytes * and farmalloc(64K) returns a pointer with an offset of 8, so we * must fix the pointer. Warning: the pointer must be put back to its * original form in order to free it, use zcfree(). */ #define MAX_PTR 10 /* 10*64K = 640K */ local int next_ptr = 0; typedef struct ptr_table_s { voidpf org_ptr; voidpf new_ptr; } ptr_table; local ptr_table table[MAX_PTR]; /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) { voidpf buf = opaque; /* just to make some compilers happy */ ulg bsize = (ulg)items*size; /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ if (bsize < 65520L) { buf = farmalloc(bsize); if (*(ush*)&buf != 0) return buf; } else { buf = farmalloc(bsize + 16L); } if (buf == NULL || next_ptr >= MAX_PTR) return NULL; table[next_ptr].org_ptr = buf; /* Normalize the pointer to seg:0 */ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; *(ush*)&buf = 0; table[next_ptr++].new_ptr = buf; return buf; } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { int n; if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; } /* Find the original pointer */ for (n = 0; n < next_ptr; n++) { if (ptr != table[n].new_ptr) continue; farfree(table[n].org_ptr); while (++n < next_ptr) { table[n-1] = table[n]; } next_ptr--; return; } ptr = opaque; /* just to make some compilers happy */ Assert(0, "zcfree: ptr not found"); } #endif /* __TURBOC__ */ #ifdef M_I86 /* Microsoft C in 16-bit mode */ # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) { if (opaque) opaque = 0; /* to make compiler happy */ return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { if (opaque) opaque = 0; /* to make compiler happy */ _hfree(ptr); } #endif /* M_I86 */ #endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC extern voidp malloc OF((uInt size)); extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) voidpf opaque; unsigned items; unsigned size; { if (opaque) items += size - size; /* make compiler happy */ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void ZLIB_INTERNAL zcfree (opaque, ptr) voidpf opaque; voidpf ptr; { free(ptr); if (opaque) return; /* make compiler happy */ } #endif /* MY_ZCALLOC */ #endif /* !Z_SOLO */ ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/zlib.h0000664000175000017500000025351312776215007020173 0ustar kaikai/* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.8, April 28th, 2013 Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. 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. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H #define ZLIB_H #include "zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.2.8" #define ZLIB_VERNUM 0x1280 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 8 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough, or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text */ uLong adler; /* adler32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ typedef struct gz_header_s { int text; /* true if compressed data believed to be text */ uLong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ Bytef *extra; /* pointer to extra field or Z_NULL if none */ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ uInt extra_max; /* space at extra (only when reading header) */ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ uInt name_max; /* space at name (only when reading header) */ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ uInt comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } gz_header; typedef gz_header FAR *gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use in the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 #define Z_BLOCK 5 #define Z_TREES 6 /* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field (though see inflate()) */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary (in interactive applications). Some output may be provided even if flush is not set. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. This completes the current deflate block and follows it with an empty stored block that is three bits plus filler bits to the next byte, followed by four bytes (00 00 ff ff). If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the output buffer, but the output is not aligned to a byte boundary. All of the input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output in order for the decompressor to finish the block before the empty fixed code block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to seven bits of the current block are held to be written as the next byte after the next deflate block is completed. In this case, the decompressor may not be provided enough bits at this point in order to complete decompression of the data provided so far to the compressor. It may need to wait for the next block to be emitted. This is for advanced applications that need to control the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space; if deflate returns with Z_OK, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least the value returned by deflateBound (see below). Then deflate is guaranteed to return Z_STREAM_END. If not enough output space is provided, deflate will not return Z_STREAM_END, and it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. If next_in is not Z_NULL and avail_in is large enough (the exact value depends on the compression method), inflateInit determines the compression method from the zlib header and allocates all data structures accordingly; otherwise the allocation will be deferred to the first call of inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in is updated and processing will resume at this point for the next call of inflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. Also to assist in this, on return inflate() will set strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. data_type is set as noted here every time inflate() returns for all flush options, and so can be used to determine the amount of currently consumed input in bits. The Z_TREES option behaves as Z_BLOCK does, but it also returns when the end of each deflate block header is reached, before any actual data in that block is decoded. This allows the caller to determine the length of the deflate block header for later use in random access within a deflate block. 256 is added to the value of strm->data_type when inflate() returns immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all of the uncompressed data for the operation to complete. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The use of Z_FINISH is not required to perform an inflation in one step. However it may be used to inform inflate that a faster approach can be used for the single inflate() call. Z_FINISH also informs inflate to not maintain a sliding window if the stream completes, which reduces inflate's memory footprint. If the stream does not complete, either because not all of the stream is provided or not enough output space is provided, then a sliding window will be allocated and inflate() can be called again to continue the operation as if Z_NO_FLUSH had been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the effects of the flush parameter in this implementation are on the return value of inflate() as noted below, when inflate() returns early when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the Adler-32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and perform their own processing of the gzip header and trailer. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output producted so far. The CRC-32 is checked against the gzip trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress is possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is desired. */ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent. In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy)); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute an adler32 check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to 255 (unknown). If a gzip stream is being written, strm->adler is a crc32 instead of an adler32. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this function must be called immediately after deflateInit, deflateInit2 or deflateReset, and before any call of deflate. When doing raw deflate, this function must be called either before any call of deflate, or immediately after the completion of a deflate block, i.e. after all input has been consumed and all output has been delivered when using any of the flush options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size provided in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The adler32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the adler32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. The stream will keep the same compression level and any other attributes that may have been set by deflateInit2. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int level, int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2. This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression level is changed, the input available so far is compressed with the old level (and may be flushed); the new level will take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to be compressed and flushed. In particular, strm->avail_out must be non-zero. deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if strm->avail_out was zero. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain)); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). If that first deflate() call is provided the sourceLen input bytes, an output buffer allocated to the size returned by deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed to return Z_STREAM_END. Note that it is possible for the compressed size to be larger than the value returned by deflateBound() if flush options other than Z_FINISH or Z_NO_FLUSH are used. */ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, unsigned *pending, int *bits)); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not provided would be due to the available output space having being consumed. The number of bits of output not provided are between 0 and 7, where they await more bits to join them in order to fill out a full byte. If pending or bits are Z_NULL, then those values are not set. deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gz_headerp head)); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be zero to request that inflate use the window size in the zlib header of the compressed stream. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an adler32 or a crc32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a crc32 instead of an adler32. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similary, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync searches for a 00 00 FF FF pattern in the compressed data. All full flush points have this pattern, but not all occurrences of this pattern are full flush points. inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, int windowBits)); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, int bits, int value)); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy. If the upper value is not -1, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code. A code is being processed if inflate is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data. inflateMark() is used to mark locations in the input data for random access, which may be at bit positions, and to note those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above or -1 << 16 if the provided source stream state was inconsistent. */ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, gz_headerp head)); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func) OF((void FAR *, z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than inflate() for file i/o applications, in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. inflate() can be faster on modern CPUs when used with large buffers. inflateBack() trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the normal behavior of inflate(), which expects either a zlib or gzip header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero--buf is ignored in that case--and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ #ifndef Z_SOLO /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed buffer. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In the case where there is not enough room, uncompress() will fill the output buffer with the uncompressed data up to that point. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) 'T' will request transparent writing or appending with no compression and not using the gzip format. "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. The addition of "x" when writing will create the file exclusively, which fails if the file already exists. On systems that support it, the addition of "e" when reading or writing will set the flag to close the file on an execve() call. These functions, as well as gzip, will read and decode a sequence of gzip streams in a file. The append function of gzopen() can be used to create such a file. (Also see gzflush() for another way to do this.) When appending, gzopen does not test whether the file begins with a gzip stream, nor does it look for the end of the gzip streams to begin appending. gzopen will simply append a gzip stream to the existing file. gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. When reading, this will be detected automatically by looking for the magic two- byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); /* gzdopen associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. If you are using fileno() to get the file descriptor from a FILE *, then you will have to use dup() to avoid double-close()ing the file descriptor. Both gzclose() and fclose() will close the associated file descriptor, so they need to have different file descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); /* Set the internal buffer size used by this library's functions. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Two buffers are allocated, either both of the specified size when writing, or one of the specified size and the other twice that size when reading. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not opened for writing. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If the input file is not in gzip format, gzread copies the given number of bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream. Any number of gzip streams may be concatenated in the input file, and will all be decompressed by gzread(). If something other than a gzip stream is encountered after a gzip stream, that remaining trailing garbage is ignored (and no error is returned). gzread can be used to read a gzip file that is being concurrently written. Upon reaching the end of the input, gzread will return with the available data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then gzclearerr can be used to clear the end of file indicator in order to permit gzread to be tried again. Z_OK indicates that a gzip stream was completed on the last gzread. Z_BUF_ERROR indicates that the input file ended in the middle of a gzip stream. Note that gzread does not return -1 in the event of an incomplete gzip stream. This error is deferred until gzclose(), which will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip stream. Alternatively, gzerror can be used before gzclose to detect this case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or 0 in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf() because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len == 1, the string is terminated with a null character. If no characters are read due to an end-of-file or len < 1, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. As such, it does not do all of the checking the other functions do. I.e. it does not check to see if file is NULL, nor whether the structure file points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); /* Push one character back onto the stream to be read as the first character on the next read. At least one character of push-back is allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatented gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, z_off_t offset, int whence)); Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ /* ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); Returns the current offset in the file being read or written. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* Returns true (1) if the end-of-file indicator has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). When writing, gzdirect() returns true (1) if transparent writing was requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: gzdirect() is not needed when writing. Transparent writing must be explicitly requested, so the application already knows the answer. When linking statically, using gzdirect() will include all of the zlib code for gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file and deallocates the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); /* Clears the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ #endif /* !Z_SOLO */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note that the z_off_t type (like off_t) is a signed integer. If len2 is negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required initial value for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); #define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) #define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #ifndef Z_SOLO /* gzgetc() macro and its supporting function and exposed data structure. Note * that the real internal state is much larger than the exposed structure. * This abbreviated structure exposes just enough for the gzgetc() macro. The * user should not mess with these exposed elements, since their names or * behavior could change in the future, perhaps even capriciously. They can * only be used by the gzgetc() macro. You have been warned. */ struct gzFile_s { unsigned have; unsigned char *next; z_off64_t pos; }; ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) #else # define gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) #endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) # ifdef Z_PREFIX_SET # define z_gzopen z_gzopen64 # define z_gzseek z_gzseek64 # define z_gztell z_gztell64 # define z_gzoffset z_gzoffset64 # define z_adler32_combine z_adler32_combine64 # define z_crc32_combine z_crc32_combine64 # else # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # endif # ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); # endif #else ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif #else /* Z_SOLO */ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif /* !Z_SOLO */ /* hack for buggy compilers */ #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; #endif /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if defined(_WIN32) && !defined(Z_SOLO) ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, const char *mode)); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, const char *format, va_list va)); # endif #endif #ifdef __cplusplus } #endif #endif /* ZLIB_H */ ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/infback.c0000664000175000017500000005426512776215007020626 0ustar kaikai/* infback.c -- inflate using a call-back interface * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* This code is largely copied from inflate.c. Normally either infback.o or inflate.o would be linked into an application--not both. The interface with inffast.c is retained so that optimized assembler-coded versions of inflate_fast() can be used with either inflate.c or infback.c. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) z_streamp strm; int windowBits; unsigned char FAR *window; const char *version; int stream_size; { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL || window == Z_NULL || windowBits < 8 || windowBits > 15) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; state->wbits = windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; state->whave = 0; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } /* Macros for inflateBack(): */ /* Load returned state from inflate_fast() */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Set state from registers for inflate_fast() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Assure that some input is available. If input is requested, but denied, then return a Z_BUF_ERROR from inflateBack(). */ #define PULL() \ do { \ if (have == 0) { \ have = in(in_desc, &next); \ if (have == 0) { \ next = Z_NULL; \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflateBack() with an error if there is no input available. */ #define PULLBYTE() \ do { \ PULL(); \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflateBack() with an error. */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* Assure that some output space is available, by writing out the window if it's full. If the write fails, return from inflateBack() with a Z_BUF_ERROR. */ #define ROOM() \ do { \ if (left == 0) { \ put = state->window; \ left = state->wsize; \ state->whave = left; \ if (out(out_desc, put, left)) { \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* strm provides the memory allocation functions and window buffer on input, and provides information on the unused input on return. For Z_DATA_ERROR returns, strm will also provide an error message. in() and out() are the call-back input and output functions. When inflateBack() needs more input, it calls in(). When inflateBack() has filled the window with output, or when it completes with data in the window, it calls out() to write out the data. The application must not change the provided input until in() is called again or inflateBack() returns. The application must not change the window/output buffer until inflateBack() returns. in() and out() are called with a descriptor parameter provided in the inflateBack() call. This parameter can be a structure that provides the information required to do the read or write, as well as accumulated information on the input and output such as totals and check values. in() should return zero on failure. out() should return non-zero on failure. If either in() or out() fails, than inflateBack() returns a Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) z_streamp strm; in_func in; void FAR *in_desc; out_func out; void FAR *out_desc; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* Check that the strm exists and that the state was initialized */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* Reset the state */ strm->msg = Z_NULL; state->mode = TYPE; state->last = 0; state->whave = 0; next = strm->next_in; have = next != Z_NULL ? strm->avail_in : 0; hold = 0; bits = 0; put = state->window; left = state->wsize; /* Inflate until end of block marked as last */ for (;;) switch (state->mode) { case TYPE: /* determine and dispatch block type */ if (state->last) { BYTEBITS(); state->mode = DONE; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN; /* decode codes */ break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: /* get and verify stored block length */ BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); /* copy stored block from input to output */ while (state->length != 0) { copy = state->length; PULL(); ROOM(); if (copy > have) copy = have; if (copy > left) copy = left; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: /* get dynamic table entries descriptor */ NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); /* get code length code lengths (not a typo) */ state->have = 0; while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); /* get length and distance code code lengths */ state->have = 0; while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = (unsigned)(state->lens[state->have - 1]); copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (code const FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; case LEN: /* use inflate_fast() if we have enough input and output */ if (have >= 6 && left >= 258) { RESTORE(); if (state->whave < state->wsize) state->whave = state->wsize - left; inflate_fast(strm, state->wsize); LOAD(); break; } /* get a literal, length, or end-of-block code */ for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); state->length = (unsigned)here.val; /* process literal */ if (here.op == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); ROOM(); *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; } /* process end of block */ if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } /* invalid code */ if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } /* length code -- get extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); } Tracevv((stderr, "inflate: length %u\n", state->length)); /* get distance code */ for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; /* get distance extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); } if (state->offset > state->wsize - (state->whave < state->wsize ? left : 0)) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } Tracevv((stderr, "inflate: distance %u\n", state->offset)); /* copy match from window to output */ do { ROOM(); copy = state->wsize - state->offset; if (copy < left) { from = put + copy; copy = left - copy; } else { from = put - state->offset; copy = left; } if (copy > state->length) copy = state->length; state->length -= copy; left -= copy; do { *put++ = *from++; } while (--copy); } while (state->length != 0); break; case DONE: /* inflate stream terminated properly -- write leftover output */ ret = Z_STREAM_END; if (left < state->wsize) { if (out(out_desc, state->window, state->wsize - left)) ret = Z_BUF_ERROR; } goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; default: /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } /* Return unused input */ inf_leave: strm->next_in = next; strm->avail_in = have; return ret; } int ZEXPORT inflateBackEnd(strm) z_streamp strm; { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib/win64.mak0000664000175000017500000000432012776215007020511 0ustar kaikai# Makefile for zlib64 MODEL=64 VCDIR=\Program Files (x86)\Microsoft Visual Studio 10.0\VC CC="$(VCDIR)\bin\amd64\cl" LD="$(VCDIR)\bin\amd64\link" LIB="$(VCDIR)\bin\amd64\lib" CFLAGS=/O2 /nologo /I"$(VCDIR)\INCLUDE" LIBFLAGS=/nologo LDFLAGS=/nologo O=.obj # variables OBJS = adler32$(O) compress$(O) crc32$(O) deflate$(O) gzclose$(O) gzlib$(O) gzread$(O) \ gzwrite$(O) infback$(O) inffast$(O) inflate$(O) inftrees$(O) trees$(O) uncompr$(O) zutil$(O) all: zlib64.lib example.exe minigzip.exe adler32.obj: zutil.h zlib.h zconf.h $(CC) /c $(CFLAGS) $*.c zutil.obj: zutil.h zlib.h zconf.h $(CC) /c $(CFLAGS) $*.c gzclose.obj: zlib.h zconf.h gzguts.h $(CC) /c $(CFLAGS) $*.c gzlib.obj: zlib.h zconf.h gzguts.h $(CC) /c $(CFLAGS) $*.c gzread.obj: zlib.h zconf.h gzguts.h $(CC) /c $(CFLAGS) $*.c gzwrite.obj: zlib.h zconf.h gzguts.h $(CC) /c $(CFLAGS) $*.c compress.obj: zlib.h zconf.h $(CC) /c $(CFLAGS) $*.c example.obj: zlib.h zconf.h $(CC) /c $(CFLAGS) $*.c minigzip.obj: zlib.h zconf.h $(CC) /c $(CFLAGS) $*.c uncompr.obj: zlib.h zconf.h $(CC) /c $(CFLAGS) $*.c crc32.obj: zutil.h zlib.h zconf.h crc32.h $(CC) /c $(CFLAGS) $*.c deflate.obj: deflate.h zutil.h zlib.h zconf.h $(CC) /c $(CFLAGS) $*.c infback.obj: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h $(CC) /c $(CFLAGS) $*.c inflate.obj: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h $(CC) /c $(CFLAGS) $*.c inffast.obj: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h $(CC) /c $(CFLAGS) $*.c inftrees.obj: zutil.h zlib.h zconf.h inftrees.h $(CC) /c $(CFLAGS) $*.c trees.obj: deflate.h zutil.h zlib.h zconf.h trees.h $(CC) /c $(CFLAGS) $*.c example.obj: example.c zlib.h zconf.h $(CC) /c $(cvarsdll) $(CFLAGS) $*.c minigzip.obj: minigzip.c zlib.h zconf.h $(CC) /c $(cvarsdll) $(CFLAGS) $*.c zlib$(MODEL).lib: $(OBJS) $(LIB) $(LIBFLAGS) /OUT:zlib$(MODEL).lib $(OBJS) example.exe: example.obj zlib$(MODEL).lib $(LD) $(LDFLAGS) example.obj zlib$(MODEL).lib minigzip.exe: minigzip.obj zlib$(MODEL).lib $(LD) $(LDFLAGS) minigzip.obj zlib$(MODEL).lib test: example.exe minigzip.exe example echo hello world | minigzip | minigzip -d clean: del *.obj del *.exe del *.dll del *.lib del *.lst del foo.gz ldc-1.1.0-beta3-src/runtime/phobos/etc/c/zlib.d0000664000175000017500000017363412776215007017234 0ustar kaikai/* zlib.d: modified from zlib.h by Walter Bright */ /* updated from 1.2.1 to 1.2.3 by Thomas Kuehne */ /* updated from 1.2.3 to 1.2.8 by Dmitry Atamanov */ module etc.c.zlib; import core.stdc.config; /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.3, July 18th, 2005 Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. 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. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). */ extern (C): const char[] ZLIB_VERSION = "1.2.8"; const ZLIB_VERNUM = 0x1280; /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough (for example if an input file is mmap'ed), or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in case of corrupted input. */ alias void* function (void* opaque, uint items, uint size) alloc_func; alias void function (void* opaque, void* address) free_func; struct z_stream { const(ubyte)* next_in; /* next input byte */ uint avail_in; /* number of bytes available at next_in */ c_ulong total_in; /* total nb of input bytes read so far */ ubyte* next_out; /* next output byte should be put there */ uint avail_out; /* remaining free space at next_out */ c_ulong total_out; /* total nb of bytes output so far */ const(char)* msg; /* last error message, NULL if no error */ void* state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ void* opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text */ c_ulong adler; /* adler32 value of the uncompressed data */ c_ulong reserved; /* reserved for future use */ } alias z_stream* z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ struct gz_header { int text; /* true if compressed data believed to be text */ c_ulong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ byte *extra; /* pointer to extra field or Z_NULL if none */ uint extra_len; /* extra field length (valid if extra != Z_NULL) */ uint extra_max; /* space at extra (only when reading header) */ byte* name; /* pointer to zero-terminated file name or Z_NULL */ uint name_max; /* space at name (only when reading header) */ byte* comment; /* pointer to zero-terminated comment or Z_NULL */ uint comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } alias gz_header* gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use in the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ enum { Z_NO_FLUSH = 0, Z_PARTIAL_FLUSH = 1, /* will be removed, use Z_SYNC_FLUSH instead */ Z_SYNC_FLUSH = 2, Z_FULL_FLUSH = 3, Z_FINISH = 4, Z_BLOCK = 5, Z_TREES = 6, } /* Allowed flush values; see deflate() and inflate() below for details */ enum { Z_OK = 0, Z_STREAM_END = 1, Z_NEED_DICT = 2, Z_ERRNO = -1, Z_STREAM_ERROR = -2, Z_DATA_ERROR = -3, Z_MEM_ERROR = -4, Z_BUF_ERROR = -5, Z_VERSION_ERROR = -6, } /* Return codes for the compression/decompression functions. Negative * values are errors, positive values are used for special but normal events. */ enum { Z_NO_COMPRESSION = 0, Z_BEST_SPEED = 1, Z_BEST_COMPRESSION = 9, Z_DEFAULT_COMPRESSION = -1, } /* compression levels */ enum { Z_FILTERED = 1, Z_HUFFMAN_ONLY = 2, Z_RLE = 3, Z_FIXED = 4, Z_DEFAULT_STRATEGY = 0, } /* compression strategy; see deflateInit2() below for details */ enum { Z_BINARY = 0, Z_TEXT = 1, Z_UNKNOWN = 2, Z_ASCII = Z_TEXT } /* Possible values of the data_type field (though see inflate()) */ enum { Z_DEFLATED = 8, } /* The deflate compression method (the only one supported in this version) */ const int Z_NULL = 0; /* for initializing zalloc, zfree, opaque */ /* basic functions */ const(char)* zlibVersion(); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ int deflateInit(z_streamp strm, int level) { return deflateInit_(strm, level, ZLIB_VERSION.ptr, z_stream.sizeof); } /* Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ int deflate(z_streamp strm, int flush); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary (in interactive applications). Some output may be provided even if flush is not set. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumualte before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space; if deflate returns with Z_OK, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least the value returned by deflateBound (see below). If deflate does not return Z_STREAM_END, then it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ int deflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ int inflateInit(z_streamp strm) { return inflateInit_(strm, ZLIB_VERSION.ptr, z_stream.sizeof); } /* Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. If next_in is not Z_NULL and avail_in is large enough (the exact value depends on the compression method), inflateInit determines the compression method from the zlib header and allocates all data structures accordingly; otherwise the allocation will be deferred to the first call of inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller. msg is set to null if there is no error message. inflateInit does not perform any decompression apart from reading the zlib header if present: this will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unchanged.) */ int inflate(z_streamp strm, int flush); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in is updated and processing will resume at this point for the next call of inflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. Also to assist in this, on return inflate() will set strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all the uncompressed data. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The next operation on this stream must be inflateEnd to deallocate the decompression state. The use of Z_FINISH is never required, but can be used to inform inflate that a faster approach may be used for the single inflate() call. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the only effect of the flush parameter in this implementation is on the return value of inflate(), as noted below, or when it returns early because Z_BLOCK is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the adler32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the adler32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() will decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically. Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and perform their own processing of the gzip header and trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value), Z_STREAM_ERROR if the stream structure was inconsistent (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress is possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is desired. */ int inflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent. In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ int deflateInit2(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy) { return deflateInit2_(strm, level, method, windowBits, memLevel, strategy, ZLIB_VERSION.ptr, z_stream.sizeof); } /* This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute an adler32 check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to 255 (unknown). If a gzip stream is being written, strm->adler is a crc32 instead of an adler32. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid method). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ int deflateSetDictionary(z_streamp strm, const(ubyte)* dictionary, uint dictLength); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. This function must be called immediately after deflateInit, deflateInit2 or deflateReset, before any call of deflate. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size in deflate or deflate2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The adler32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the adler32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent (for example if deflate has already been called for this stream or if the compression method is bsort). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ int deflateCopy(z_streamp dest, z_streamp source); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being NULL). msg is left unchanged in both source and destination. */ int deflateReset(z_streamp strm); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. The stream will keep the same compression level and any other attributes that may have been set by deflateInit2. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being NULL). */ int inflatePrime(z_streamp strm, int bits, int value); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ int inflateGetHeader(z_streamp strm, gz_headerp head); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ int deflateParams(z_streamp strm, int level, int strategy); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2. This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression level is changed, the input available so far is compressed with the old level (and may be flushed); the new level will take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to be compressed and flushed. In particular, strm->avail_out must be non-zero. deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if strm->avail_out was zero. */ int deflateTune(z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ int deflateBound(z_streamp strm, size_t sourceLen); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(). This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). */ int deflatePrime(z_streamp strm, int bits, int value); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ int deflateSetHeader(z_streamp strm, gz_headerp head); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ int inflateInit2(z_streamp strm, int windowBits) { return inflateInit2_(strm, windowBits, ZLIB_VERSION.ptr, z_stream.sizeof); } /* This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an adler32 or a crc32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a crc32 instead of an adler32. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from reading the zlib header if present: this will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unchanged.) / int inflateSetDictionary(z_streamp strm, const(ubyte)* dictionary, uint dictLength); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called immediately after inflateInit2() or inflateReset() and before any call of inflate() to set the dictionary. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ int inflateSync(z_streamp strm); /* Skips invalid compressed data until a full flush point (see above the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ int inflateCopy (z_streamp dest, z_streamp source); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being NULL). msg is left unchanged in both source and destination. */ int inflateReset(z_streamp strm); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being NULL). */ int inflateBackInit(z_stream* strm, int windowBits, ubyte* window) { return inflateBackInit_(strm, windowBits, window, ZLIB_VERSION.ptr, z_stream.sizeof); } /* Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the paramaters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ alias uint function(void*, ubyte**) in_func; alias int function(void*, ubyte*, uint) out_func; int inflateBack(z_stream* strm, in_func f_in, void* in_desc, out_func f_out, void* out_desc); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is more efficient than inflate() for file i/o applications in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. This function trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the normal behavior of inflate(), which expects either a zlib or gzip header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero--buf is ignored in that case--and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ int inflateBackEnd(z_stream* strm); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ uint zlibCompileFlags(); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can easily be modified if you need special options. */ int compress(ubyte* dest, size_t* destLen, const(ubyte)* source, size_t sourceLen); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. This function can be used to compress a whole file at once if the input file is mmap'ed. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ int compress2(ubyte* dest, size_t* destLen, const(ubyte)* source, size_t sourceLen, int level); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ size_t compressBound(size_t sourceLen); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ int uncompress(ubyte* dest, size_t* destLen, const(ubyte)* source, size_t sourceLen); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the compressed buffer. This function can be used to decompress a whole file at once if the input file is mmap'ed. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. */ alias void* gzFile; alias int z_off_t; // file offset gzFile gzopen(const(char)* path, const(char)* mode); /* Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman only compression as in "wb1h", or 'R' for run-length encoding as in "wb1R". (See the description of deflateInit2 for more information about the strategy parameter.) gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. gzopen returns NULL if the file could not be opened or if there was insufficient memory to allocate the (de)compression state; errno can be checked to distinguish the two cases (if errno is zero, the zlib error is Z_MEM_ERROR). */ gzFile gzdopen(int fd, const(char)* mode); /* gzdopen() associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (in the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd), mode) closes the file descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). gzdopen returns NULL if there was insufficient memory to allocate the (de)compression state. */ int gzsetparams(gzFile file, int level, int strategy); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not opened for writing. */ int gzread(gzFile file, void* buf, uint len); /* Reads the given number of uncompressed bytes from the compressed file. If the input file was not in gzip format, gzread copies the given number of bytes into the buffer. gzread returns the number of uncompressed bytes actually read (0 for end of file, -1 for error). */ int gzwrite(gzFile file, void* buf, uint len); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes actually written (0 in case of error). */ int gzprintf(gzFile file, const(char)* format, ...); /* Converts, formats, and writes the args to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written (0 in case of error). The number of uncompressed bytes written is limited to 4095. The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf() because the secure snprintf() or vsnprintf() functions were not available. */ int gzputs(gzFile file, const(char)* s); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ const(char)* gzgets(gzFile file, const(char)* buf, int len); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. The string is then terminated with a null character. gzgets returns buf, or Z_NULL in case of error. */ int gzputc(gzFile file, int c); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ int gzgetc(gzFile file); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. */ int gzungetc(int c, gzFile file); /* Push one character back onto the stream to be read again later. Only one character of push-back is allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if a character has been pushed but not read yet, or if c is -1. The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ int gzflush(gzFile file, int flush); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush returns Z_OK if the flush parameter is Z_FINISH and all output could be flushed. gzflush should be called only when strictly necessary because it can degrade compression. */ z_off_t gzseek(gzFile file, z_off_t offset, int whence); /* Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ int gzrewind(gzFile file); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ z_off_t gztell(gzFile file); /* Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream. gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ int gzeof(gzFile file); /* Returns 1 when EOF has previously been detected reading the given input stream, otherwise zero. */ int gzdirect(gzFile file); /* Returns 1 if file is being read directly without decompression, otherwise zero. */ int gzclose(gzFile file); /* Flushes all pending output if necessary, closes the compressed file and deallocates all the (de)compression state. The return value is the zlib error number (see function gzerror below). */ const(char)* gzerror(gzFile file, int* errnum); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. */ void gzclearerr (gzFile file); /* Clears the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ uint adler32 (uint adler, ubyte* buf, uint len); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. Usage example: uint adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ uint adler32_combine(uint adler1, uint adler2, z_off_t len2); /* Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. */ uint crc32(uint crc, ubyte* buf, uint len); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is NULL, this function returns the required initial value for the for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uint crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ uint crc32_combine (uint crc1, uint crc2, z_off_t len2); /* Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ int deflateInit_(z_streamp strm, int level, const(char)* versionx, int stream_size); int inflateInit_(z_streamp strm, const(char)* versionx, int stream_size); int deflateInit2_(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const(char)* versionx, int stream_size); int inflateBackInit_(z_stream* strm, int windowBits, ubyte* window, const(char)* z_version, int stream_size); int inflateInit2_(z_streamp strm, int windowBits, const(char)* versionx, int stream_size); const(char)* zError(int err); int inflateSyncPoint(z_streamp z); const(uint)* get_crc_table(); ldc-1.1.0-beta3-src/runtime/phobos/etc/c/odbc/0000775000175000017500000000000012776215007017020 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/etc/c/odbc/sqlucode.d0000664000175000017500000002450712776215007021014 0ustar kaikai/** Declarations for interfacing with the ODBC library. Adapted with minimal changes from the work of David L. Davis (refer to the $(WEB forum.dlang.org/post/cfk7ql$(DOLLAR)1p4n$(DOLLAR)1@digitaldaemon.com, original announcement)). `etc.c.odbc.sqlucode` corresponds to the `sqlucode.h` C include file. See_Also: $(LUCKY ODBC API Reference on MSN Online) */ /+ sqlucode.d - This is the the unicode include for ODBC v3.0+ Core functions. +/ module etc.c.odbc.sqlucode; import etc.c.odbc.sqlext; import etc.c.odbc.sqltypes; extern (Windows): enum { SQL_WCHAR = (-8), SQL_WVARCHAR = (-9), SQL_WLONGVARCHAR = (-10), SQL_C_WCHAR = SQL_WCHAR, SQL_C_TCHAR = SQL_C_WCHAR } enum int SQL_SQLSTATE_SIZEW = 10; /* size of SQLSTATE for unicode */ // UNICODE versions SQLRETURN SQLColAttributeW ( SQLHSTMT hstmt, SQLUSMALLINT iCol, SQLUSMALLINT iField, SQLPOINTER pCharAttr, SQLSMALLINT cbCharAttrMax, SQLSMALLINT *pcbCharAttr, SQLPOINTER pNumAttr ); SQLRETURN SQLColAttributesW ( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT *pcbDesc, SQLINTEGER *pfDesc ); SQLRETURN SQLConnectW ( SQLHDBC hdbc, SQLWCHAR *szDSN, SQLSMALLINT cbDSN, SQLWCHAR *szUID, SQLSMALLINT cbUID, SQLWCHAR *szAuthStr, SQLSMALLINT cbAuthStr ); SQLRETURN SQLDescribeColW ( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLWCHAR *szColName, SQLSMALLINT cbColNameMax, SQLSMALLINT *pcbColName, SQLSMALLINT *pfSqlType, SQLUINTEGER *pcbColDef, SQLSMALLINT *pibScale, SQLSMALLINT *pfNullable ); SQLRETURN SQLErrorW ( SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLWCHAR *szSqlState, SQLINTEGER *pfNativeError, SQLWCHAR *szErrorMsg, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT *pcbErrorMsg ); SQLRETURN SQLExecDirectW ( SQLHSTMT hstmt, SQLWCHAR *szSqlStr, SQLINTEGER cbSqlStr ); SQLRETURN SQLGetConnectAttrW ( SQLHDBC hdbc, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER *pcbValue ); SQLRETURN SQLGetCursorNameW ( SQLHSTMT hstmt, SQLWCHAR *szCursor, SQLSMALLINT cbCursorMax, SQLSMALLINT *pcbCursor ); SQLRETURN SQLSetDescFieldW ( SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, SQLPOINTER Value, SQLINTEGER BufferLength ); SQLRETURN SQLGetDescFieldW ( SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER *pcbValue ); SQLRETURN SQLGetDescRecW ( SQLHDESC hdesc, SQLSMALLINT iRecord, SQLWCHAR *szName, SQLSMALLINT cbNameMax, SQLSMALLINT *pcbName, SQLSMALLINT *pfType, SQLSMALLINT *pfSubType, SQLINTEGER *pLength, SQLSMALLINT *pPrecision, SQLSMALLINT *pScale, SQLSMALLINT *pNullable ); SQLRETURN SQLGetDiagFieldW ( SQLSMALLINT fHandleType, SQLHANDLE handle, SQLSMALLINT iRecord, SQLSMALLINT fDiagField, SQLPOINTER rgbDiagInfo, SQLSMALLINT cbDiagInfoMax, SQLSMALLINT *pcbDiagInfo ); SQLRETURN SQLGetDiagRecW ( SQLSMALLINT fHandleType, SQLHANDLE handle, SQLSMALLINT iRecord, SQLWCHAR *szSqlState, SQLINTEGER *pfNativeError, SQLWCHAR *szErrorMsg, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT *pcbErrorMsg ); SQLRETURN SQLPrepareW ( SQLHSTMT hstmt, SQLWCHAR *szSqlStr, SQLINTEGER cbSqlStr ); SQLRETURN SQLSetConnectAttrW ( SQLHDBC hdbc, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValue ); SQLRETURN SQLSetCursorNameW ( SQLHSTMT hstmt, SQLWCHAR *szCursor, SQLSMALLINT cbCursor ); SQLRETURN SQLColumnsW ( SQLHSTMT hstmt, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szTableName, SQLSMALLINT cbTableName, SQLWCHAR *szColumnName, SQLSMALLINT cbColumnName ); SQLRETURN SQLGetConnectOptionW ( SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam ); SQLRETURN SQLGetInfoW ( SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT *pcbInfoValue ); SQLRETURN SQLGetTypeInfoW ( SQLHSTMT StatementHandle, SQLSMALLINT DataType ); SQLRETURN SQLSetConnectOptionW ( SQLHDBC hdbc, SQLUSMALLINT fOption, SQLUINTEGER vParam ); SQLRETURN SQLSpecialColumnsW ( SQLHSTMT hstmt, SQLUSMALLINT fColType, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szTableName, SQLSMALLINT cbTableName, SQLUSMALLINT fScope, SQLUSMALLINT fNullable ); SQLRETURN SQLStatisticsW ( SQLHSTMT hstmt, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szTableName, SQLSMALLINT cbTableName, SQLUSMALLINT fUnique, SQLUSMALLINT fAccuracy ); SQLRETURN SQLTablesW ( SQLHSTMT hstmt, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szTableName, SQLSMALLINT cbTableName, SQLWCHAR *szTableType, SQLSMALLINT cbTableType ); SQLRETURN SQLDataSourcesW ( SQLHENV henv, SQLUSMALLINT fDirection, SQLWCHAR *szDSN, SQLSMALLINT cbDSNMax, SQLSMALLINT *pcbDSN, SQLWCHAR *szDescription, SQLSMALLINT cbDescriptionMax, SQLSMALLINT *pcbDescription ); SQLRETURN SQLDriverConnectW ( SQLHDBC hdbc, SQLHWND hwnd, SQLWCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn, SQLWCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT *pcbConnStrOut, SQLUSMALLINT fDriverCompletion ); SQLRETURN SQLBrowseConnectW ( SQLHDBC hdbc, SQLWCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn, SQLWCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT *pcbConnStrOut ); SQLRETURN SQLColumnPrivilegesW ( SQLHSTMT hstmt, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szTableName, SQLSMALLINT cbTableName, SQLWCHAR *szColumnName, SQLSMALLINT cbColumnName ); SQLRETURN SQLGetStmtAttrW ( SQLHSTMT hstmt, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER *pcbValue ); SQLRETURN SQLSetStmtAttrW ( SQLHSTMT hstmt, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValueMax ); SQLRETURN SQLForeignKeysW ( SQLHSTMT hstmt, SQLWCHAR *szPkCatalogName, SQLSMALLINT cbPkCatalogName, SQLWCHAR *szPkSchemaName, SQLSMALLINT cbPkSchemaName, SQLWCHAR *szPkTableName, SQLSMALLINT cbPkTableName, SQLWCHAR *szFkCatalogName, SQLSMALLINT cbFkCatalogName, SQLWCHAR *szFkSchemaName, SQLSMALLINT cbFkSchemaName, SQLWCHAR *szFkTableName, SQLSMALLINT cbFkTableName ); SQLRETURN SQLNativeSqlW ( SQLHDBC hdbc, SQLWCHAR *szSqlStrIn, SQLINTEGER cbSqlStrIn, SQLWCHAR *szSqlStr, SQLINTEGER cbSqlStrMax, SQLINTEGER *pcbSqlStr ); SQLRETURN SQLPrimaryKeysW ( SQLHSTMT hstmt, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szTableName, SQLSMALLINT cbTableName ); SQLRETURN SQLProcedureColumnsW ( SQLHSTMT hstmt, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szProcName, SQLSMALLINT cbProcName, SQLWCHAR *szColumnName, SQLSMALLINT cbColumnName ); SQLRETURN SQLProceduresW ( SQLHSTMT hstmt, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szProcName, SQLSMALLINT cbProcName ); SQLRETURN SQLTablePrivilegesW ( SQLHSTMT hstmt, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szTableName, SQLSMALLINT cbTableName ); SQLRETURN SQLDriversW ( SQLHENV henv, SQLUSMALLINT fDirection, SQLWCHAR *szDriverDesc, SQLSMALLINT cbDriverDescMax, SQLSMALLINT *pcbDriverDesc, SQLWCHAR *szDriverAttributes, SQLSMALLINT cbDrvrAttrMax, SQLSMALLINT *pcbDrvrAttr ); //--------------------------------------------- // Mapping Unicode Functions //--------------------------------------------- /+ alias SQLColAttributeW SQLColAttribute; alias SQLColAttributesW SQLColAttributes; alias SQLConnectW SQLConnect; alias SQLDescribeColW SQLDescribeCol; alias SQLErrorW SQLError; alias SQLExecDirectW SQLExecDirect; alias SQLGetConnectAttrW SQLGetConnectAttr; alias SQLGetCursorNameW SQLGetCursorName; alias SQLGetDescFieldW SQLGetDescField; alias SQLGetDescRecW SQLGetDescRec; alias SQLGetDiagFieldW SQLGetDiagField; alias SQLGetDiagRecW SQLGetDiagRec; alias SQLPrepareW SQLPrepare; alias SQLSetConnectAttrW SQLSetConnectAttr; alias SQLSetCursorNameW SQLSetCursorName; alias SQLSetDescFieldW SQLSetDescField; alias SQLSetStmtAttrW SQLSetStmtAttr; alias SQLColumnsW SQLColumns; alias SQLGetConnectOptionW SQLGetConnectOption; alias SQLGetInfoW SQLGetInfo; alias SQLGetTypeInfoW SQLGetTypeInfo; alias SQLSetConnectOptionW SQLSetConnectOption; alias SQLSpecialColumnsW SQLSpecialColumns; alias SQLStatisticsW SQLStatistics; alias SQLTablesW SQLTables; alias SQLDataSourcesW SQLDataSources; alias SQLDriverConnectW SQLDriverConnect; alias SQLBrowseConnectW SQLBrowseConnect; alias SQLColumnPrivilegesW SQLColumnPrivileges; alias SQLForeignKeysW SQLForeignKeys; alias SQLNativeSqlW SQLNativeSql; alias SQLPrimaryKeysW SQLPrimaryKeys; alias SQLProcedureColumnsW SQLProcedureColumns; alias SQLProceduresW SQLProcedures; alias SQLTablePrivilegesW SQLTablePrivileges; alias SQLDriversW SQLDrivers; +/ ldc-1.1.0-beta3-src/runtime/phobos/etc/c/odbc/sqlext.d0000664000175000017500000020705012776215007020511 0ustar kaikai/** Declarations for interfacing with the ODBC library. Adapted with minimal changes from the work of David L. Davis (refer to the $(WEB forum.dlang.org/post/cfk7ql$(DOLLAR)1p4n$(DOLLAR)1@digitaldaemon.com, original announcement)). `etc.c.odbc.sqlext` corresponds to the `sqlext.h` C header file. See_Also: $(LUCKY ODBC API Reference on MSN Online) */ module etc.c.odbc.sqlext; private import etc.c.odbc.sql; private import etc.c.odbc.sqltypes; extern (Windows): // * generally useful constants * enum int SQL_SPEC_MAJOR = 3; /* Major version of specification */ enum int SQL_SPEC_MINOR = 51; /* Minor version of specification */ immutable char[] SQL_SPEC_STRING = "03.51"; /* String constant for version */ enum int SQL_SQLSTATE_SIZE = 5; /* size of SQLSTATE */ enum int SQL_MAX_DSN_LENGTH = 32; /* maximum data source name size */ enum int SQL_MAX_OPTION_STRING_LENGTH = 256; // * return code SQL_NO_DATA_FOUND is the same as SQL_NO_DATA * //enum int SQL_NO_DATA_FOUND = 100; enum int SQL_NO_DATA_FOUND = SQL_NO_DATA; // * an end handle type * enum int SQL_HANDLE_SENV = 5; // * env attribute * enum : uint { SQL_ATTR_ODBC_VERSION = 200, SQL_ATTR_CONNECTION_POOLING = 201, SQL_ATTR_CP_MATCH = 202, // * values for SQL_ATTR_CONNECTION_POOLING * SQL_CP_OFF = 0UL, SQL_CP_ONE_PER_DRIVER = 1UL, SQL_CP_ONE_PER_HENV = 2UL, SQL_CP_DEFAULT = SQL_CP_OFF, // * values for SQL_ATTR_CP_MATCH * SQL_CP_STRICT_MATCH = 0UL, SQL_CP_RELAXED_MATCH = 1UL, SQL_CP_MATCH_DEFAULT = SQL_CP_STRICT_MATCH, // * values for SQL_ATTR_ODBC_VERSION * SQL_OV_ODBC2 = 2UL, SQL_OV_ODBC3 = 3UL } // * connection attributes * enum { SQL_ACCESS_MODE = 101, SQL_AUTOCOMMIT = 102, SQL_LOGIN_TIMEOUT = 103, SQL_OPT_TRACE = 104, SQL_OPT_TRACEFILE = 105, SQL_TRANSLATE_DLL = 106, SQL_TRANSLATE_OPTION = 107, SQL_TXN_ISOLATION = 108, SQL_CURRENT_QUALIFIER = 109, SQL_ODBC_CURSORS = 110, SQL_QUIET_MODE = 111, SQL_PACKET_SIZE = 112 } // * connection attributes with new names * enum { SQL_ATTR_ACCESS_MODE = SQL_ACCESS_MODE, SQL_ATTR_AUTOCOMMIT = SQL_AUTOCOMMIT, SQL_ATTR_CONNECTION_TIMEOUT = 113, SQL_ATTR_CURRENT_CATALOG = SQL_CURRENT_QUALIFIER, SQL_ATTR_DISCONNECT_BEHAVIOR = 114, SQL_ATTR_ENLIST_IN_DTC = 1207, SQL_ATTR_ENLIST_IN_XA = 1208, SQL_ATTR_LOGIN_TIMEOUT = SQL_LOGIN_TIMEOUT, SQL_ATTR_ODBC_CURSORS = SQL_ODBC_CURSORS, SQL_ATTR_PACKET_SIZE = SQL_PACKET_SIZE, SQL_ATTR_QUIET_MODE = SQL_QUIET_MODE, SQL_ATTR_TRACE = SQL_OPT_TRACE, SQL_ATTR_TRACEFILE = SQL_OPT_TRACEFILE, SQL_ATTR_TRANSLATE_LIB = SQL_TRANSLATE_DLL, SQL_ATTR_TRANSLATE_OPTION = SQL_TRANSLATE_OPTION, SQL_ATTR_TXN_ISOLATION = SQL_TXN_ISOLATION } // * GetConnectAttr only * enum int SQL_ATTR_CONNECTION_DEAD = 1209; /+ ' ODBC Driver Manager sets this connection attribute to a unicode driver ' (which supports SQLConnectW) when the application is an ANSI application ' (which calls SQLConnect, SQLDriverConnect, or SQLBrowseConnect). ' This is SetConnectAttr only and application does not set this attribute ' This attribute was introduced because some unicode driver's some APIs may ' need to behave differently on ANSI or Unicode applications. A unicode ' driver, which has same behavior for both ANSI or Unicode applications, ' should return SQL_ERROR when the driver manager sets this connection ' attribute. When a unicode driver returns SQL_SUCCESS on this attribute, ' the driver manager treates ANSI and Unicode connections differently in ' connection pooling. +/ enum int SQL_ATTR_ANSI_APP = 115; // * SQL_ACCESS_MODE options * enum : uint { SQL_MODE_READ_WRITE = 0UL, SQL_MODE_READ_ONLY = 1UL, SQL_MODE_DEFAULT = SQL_MODE_READ_WRITE } // * SQL_AUTOCOMMIT options * enum : uint { SQL_AUTOCOMMIT_OFF = 0UL, SQL_AUTOCOMMIT_ON = 1UL, SQL_AUTOCOMMIT_DEFAULT = SQL_AUTOCOMMIT_ON } // * SQL_LOGIN_TIMEOUT options * enum uint SQL_LOGIN_TIMEOUT_DEFAULT = 15UL; // * SQL_OPT_TRACE options * enum : uint { SQL_OPT_TRACE_OFF = 0UL, SQL_OPT_TRACE_ON = 1UL, SQL_OPT_TRACE_DEFAULT = SQL_OPT_TRACE_OFF } immutable char[] SQL_OPT_TRACE_FILE_DEFAULT = r"\SQL.LOG"; // * SQL_ODBC_CURSORS options * enum : uint { SQL_CUR_USE_IF_NEEDED = 0UL, SQL_CUR_USE_ODBC = 1UL, SQL_CUR_USE_DRIVER = 2UL, SQL_CUR_DEFAULT = SQL_CUR_USE_DRIVER } enum { // * values for SQL_ATTR_DISCONNECT_BEHAVIOR * SQL_DB_RETURN_TO_POOL = 0UL, SQL_DB_DISCONNECT = 1UL, SQL_DB_DEFAULT = SQL_DB_RETURN_TO_POOL, // * values for SQL_ATTR_ENLIST_IN_DTC * SQL_DTC_DONE = 0L } // * values for SQL_ATTR_CONNECTION_DEAD * enum int SQL_CD_TRUE = 1L; // * Connection is closed/dead * enum int SQL_CD_FALSE = 0L; // * Connection is open/available * // * values for SQL_ATTR_ANSI_APP ( ODBC v3.51 ) * enum int SQL_AA_TRUE = 1L; // * the application is an ANSI app * enum int SQL_AA_FALSE = 0L; // * the application is a Unicode app * // * statement attributes * enum { SQL_QUERY_TIMEOUT = 0, SQL_MAX_ROWS = 1, SQL_NOSCAN = 2, SQL_MAX_LENGTH = 3, SQL_ASYNC_ENABLE = 4, // * same as SQL_ATTR_ASYNC_ENABLE * SQL_BIND_TYPE = 5, SQL_CURSOR_TYPE = 6, SQL_CONCURRENCY = 7, SQL_KEYSET_SIZE = 8, SQL_ROWSET_SIZE = 9, SQL_SIMULATE_CURSOR = 10, SQL_RETRIEVE_DATA = 11, SQL_USE_BOOKMARKS = 12, SQL_GET_BOOKMARK = 13, // * GetStmtOption Only * SQL_ROW_NUMBER = 14 // * GetStmtOption Only * } // * statement attributes for ODBC 3.0 * enum { SQL_ATTR_ASYNC_ENABLE = 4, SQL_ATTR_CONCURRENCY = SQL_CONCURRENCY, SQL_ATTR_CURSOR_TYPE = SQL_CURSOR_TYPE, SQL_ATTR_ENABLE_AUTO_IPD = 15, SQL_ATTR_FETCH_BOOKMARK_PTR = 16, SQL_ATTR_KEYSET_SIZE = SQL_KEYSET_SIZE, SQL_ATTR_MAX_LENGTH = SQL_MAX_LENGTH, SQL_ATTR_MAX_ROWS = SQL_MAX_ROWS, SQL_ATTR_NOSCAN = SQL_NOSCAN, SQL_ATTR_PARAM_BIND_OFFSET_PTR = 17, SQL_ATTR_PARAM_BIND_TYPE = 18, SQL_ATTR_PARAM_OPERATION_PTR = 19, SQL_ATTR_PARAM_STATUS_PTR = 20, SQL_ATTR_PARAMS_PROCESSED_PTR = 21, SQL_ATTR_PARAMSET_SIZE = 22, SQL_ATTR_QUERY_TIMEOUT = SQL_QUERY_TIMEOUT, SQL_ATTR_RETRIEVE_DATA = SQL_RETRIEVE_DATA, SQL_ATTR_ROW_BIND_OFFSET_PTR = 23, SQL_ATTR_ROW_BIND_TYPE = SQL_BIND_TYPE, SQL_ATTR_ROW_NUMBER = SQL_ROW_NUMBER, // * GetStmtAttr * SQL_ATTR_ROW_OPERATION_PTR = 24, SQL_ATTR_ROW_STATUS_PTR = 25, SQL_ATTR_ROWS_FETCHED_PTR = 26, SQL_ATTR_ROW_ARRAY_SIZE = 27, SQL_ATTR_SIMULATE_CURSOR = SQL_SIMULATE_CURSOR, SQL_ATTR_USE_BOOKMARKS = SQL_USE_BOOKMARKS } // * whether an attribute is a pointer or not * enum { SQL_IS_POINTER = (-4), SQL_IS_UINTEGER = (-5), SQL_IS_INTEGER = (-6), SQL_IS_USMALLINT = (-7), SQL_IS_SMALLINT = (-8) } // * the value of SQL_ATTR_PARAM_BIND_TYPE * enum : uint { SQL_PARAM_BIND_BY_COLUMN = 0UL, SQL_PARAM_BIND_TYPE_DEFAULT = SQL_PARAM_BIND_BY_COLUMN } // * SQL_QUERY_TIMEOUT options * enum uint SQL_QUERY_TIMEOUT_DEFAULT = 0UL; // * SQL_MAX_ROWS options * enum uint SQL_MAX_ROWS_DEFAULT = 0UL; // * SQL_NOSCAN options * enum : uint { SQL_NOSCAN_OFF = 0UL, /* 1.0 FALSE */ SQL_NOSCAN_ON = 1UL, /* 1.0 TRUE */ SQL_NOSCAN_DEFAULT = SQL_NOSCAN_OFF } // * SQL_MAX_LENGTH options * enum uint SQL_MAX_LENGTH_DEFAULT = 0UL; // * values for SQL_ATTR_ASYNC_ENABLE * enum : uint { SQL_ASYNC_ENABLE_OFF = 0UL, SQL_ASYNC_ENABLE_ON = 1UL, SQL_ASYNC_ENABLE_DEFAULT = SQL_ASYNC_ENABLE_OFF } // * SQL_BIND_TYPE options * enum : uint { SQL_BIND_BY_COLUMN = 0UL, SQL_BIND_TYPE_DEFAULT = SQL_BIND_BY_COLUMN /* Default value */ } // * SQL_CONCURRENCY options * enum { SQL_CONCUR_READ_ONLY = 1, SQL_CONCUR_LOCK = 2, SQL_CONCUR_ROWVER = 3, SQL_CONCUR_VALUES = 4, SQL_CONCUR_DEFAULT = SQL_CONCUR_READ_ONLY /* Default value */ } // * SQL_CURSOR_TYPE options * enum : uint { SQL_CURSOR_FORWARD_ONLY = 0UL, SQL_CURSOR_KEYSET_DRIVEN = 1UL, SQL_CURSOR_DYNAMIC = 2UL, SQL_CURSOR_STATIC = 3UL, SQL_CURSOR_TYPE_DEFAULT = SQL_CURSOR_FORWARD_ONLY /* Default value */ } // * SQL_ROWSET_SIZE options * enum uint SQL_ROWSET_SIZE_DEFAULT = 1UL; // * SQL_KEYSET_SIZE options * enum uint SQL_KEYSET_SIZE_DEFAULT = 0UL; // * SQL_SIMULATE_CURSOR options * enum : uint { SQL_SC_NON_UNIQUE = 0UL, SQL_SC_TRY_UNIQUE = 1UL, SQL_SC_UNIQUE = 2UL } // * SQL_RETRIEVE_DATA options * enum : uint { SQL_RD_OFF = 0UL, SQL_RD_ON = 1UL, SQL_RD_DEFAULT = SQL_RD_ON } // * SQL_USE_BOOKMARKS options * enum : uint { SQL_UB_OFF = 0UL, SQL_UB_ON = 01UL, SQL_UB_DEFAULT = SQL_UB_OFF } // * New values for SQL_USE_BOOKMARKS attribute * enum : uint { SQL_UB_FIXED = SQL_UB_ON, SQL_UB_VARIABLE = 2UL } /* SQLColAttributes defines */ enum { SQL_COLUMN_COUNT = 0, SQL_COLUMN_NAME = 1, SQL_COLUMN_TYPE = 2, SQL_COLUMN_LENGTH = 3, SQL_COLUMN_PRECISION = 4, SQL_COLUMN_SCALE = 5, SQL_COLUMN_DISPLAY_SIZE = 6, SQL_COLUMN_NULLABLE = 7, SQL_COLUMN_UNSIGNED = 8, SQL_COLUMN_MONEY = 9, SQL_COLUMN_UPDATABLE = 10, SQL_COLUMN_AUTO_INCREMENT = 11, SQL_COLUMN_CASE_SENSITIVE = 12, SQL_COLUMN_SEARCHABLE = 13, SQL_COLUMN_TYPE_NAME = 14, SQL_COLUMN_TABLE_NAME = 15, SQL_COLUMN_OWNER_NAME = 16, SQL_COLUMN_QUALIFIER_NAME = 17, SQL_COLUMN_LABEL = 18, SQL_COLATT_OPT_MAX = SQL_COLUMN_LABEL } // * extended descriptor field * enum { SQL_DESC_ARRAY_SIZE = 20, SQL_DESC_ARRAY_STATUS_PTR = 21, SQL_DESC_AUTO_UNIQUE_VALUE = SQL_COLUMN_AUTO_INCREMENT, SQL_DESC_BASE_COLUMN_NAME = 22, SQL_DESC_BASE_TABLE_NAME = 23, SQL_DESC_BIND_OFFSET_PTR = 24, SQL_DESC_BIND_TYPE = 25, SQL_DESC_CASE_SENSITIVE = SQL_COLUMN_CASE_SENSITIVE, SQL_DESC_CATALOG_NAME = SQL_COLUMN_QUALIFIER_NAME, SQL_DESC_CONCISE_TYPE = SQL_COLUMN_TYPE, SQL_DESC_DATETIME_INTERVAL_PRECISION = 26, SQL_DESC_DISPLAY_SIZE = SQL_COLUMN_DISPLAY_SIZE, SQL_DESC_FIXED_PREC_SCALE = SQL_COLUMN_MONEY, SQL_DESC_LABEL = SQL_COLUMN_LABEL, SQL_DESC_LITERAL_PREFIX = 27, SQL_DESC_LITERAL_SUFFIX = 28, SQL_DESC_LOCAL_TYPE_NAME = 29, SQL_DESC_MAXIMUM_SCALE = 30, SQL_DESC_MINIMUM_SCALE = 31, SQL_DESC_NUM_PREC_RADIX = 32, SQL_DESC_PARAMETER_TYPE = 33, SQL_DESC_ROWS_PROCESSED_PTR = 34, SQL_DESC_SCHEMA_NAME = SQL_COLUMN_OWNER_NAME, SQL_DESC_SEARCHABLE = SQL_COLUMN_SEARCHABLE, SQL_DESC_TYPE_NAME = SQL_COLUMN_TYPE_NAME, SQL_DESC_TABLE_NAME = SQL_COLUMN_TABLE_NAME, SQL_DESC_UNSIGNED = SQL_COLUMN_UNSIGNED, SQL_DESC_UPDATABLE = SQL_COLUMN_UPDATABLE } // ODBCVER >= 0x0350 enum int SQL_DESC_ROWVER = 35; // * defines for diagnostics fields * enum { SQL_DIAG_CURSOR_ROW_COUNT = (-1249), SQL_DIAG_ROW_NUMBER = (-1248), SQL_DIAG_COLUMN_NUMBER = (-1247) } // * SQL extended datatypes * enum { SQL_DATE = 9, SQL_INTERVAL = 10, SQL_TIME = 10, SQL_TIMESTAMP = 11, SQL_LONGVARCHAR = (-1), SQL_BINARY = (-2), SQL_VARBINARY = (-3), SQL_LONGVARBINARY = (-4), SQL_BIGINT = (-5), SQL_TINYINT = (-6), SQL_BIT = (-7), // ODBCVER >= 0x0350 SQL_GUID = (-11) } enum { // * interval code * SQL_CODE_YEAR = 1, SQL_CODE_MONTH = 2, SQL_CODE_DAY = 3, SQL_CODE_HOUR = 4, SQL_CODE_MINUTE = 5, SQL_CODE_SECOND = 6, SQL_CODE_YEAR_TO_MONTH = 7, SQL_CODE_DAY_TO_HOUR = 8, SQL_CODE_DAY_TO_MINUTE = 9, SQL_CODE_DAY_TO_SECOND = 10, SQL_CODE_HOUR_TO_MINUTE = 11, SQL_CODE_HOUR_TO_SECOND = 12, SQL_CODE_MINUTE_TO_SECOND = 13, SQL_INTERVAL_YEAR = (100 + SQL_CODE_YEAR), SQL_INTERVAL_MONTH = (100 + SQL_CODE_MONTH), SQL_INTERVAL_DAY = (100 + SQL_CODE_DAY), SQL_INTERVAL_HOUR = (100 + SQL_CODE_HOUR), SQL_INTERVAL_MINUTE = (100 + SQL_CODE_MINUTE), SQL_INTERVAL_SECOND = (100 + SQL_CODE_SECOND), SQL_INTERVAL_YEAR_TO_MONTH = (100 + SQL_CODE_YEAR_TO_MONTH), SQL_INTERVAL_DAY_TO_HOUR = (100 + SQL_CODE_DAY_TO_HOUR), SQL_INTERVAL_DAY_TO_MINUTE = (100 + SQL_CODE_DAY_TO_MINUTE), SQL_INTERVAL_DAY_TO_SECOND = (100 + SQL_CODE_DAY_TO_SECOND), SQL_INTERVAL_HOUR_TO_MINUTE = (100 + SQL_CODE_HOUR_TO_MINUTE), SQL_INTERVAL_HOUR_TO_SECOND = (100 + SQL_CODE_HOUR_TO_SECOND), SQL_INTERVAL_MINUTE_TO_SECOND = (100 + SQL_CODE_MINUTE_TO_SECOND), } // * The previous definitions for SQL_UNICODE_ are historical and obsolete * enum { SQL_WCHAR = (-8), SQL_WVARCHAR = (-9), SQL_WLONGVARCHAR = (-10), SQL_C_WCHAR = SQL_WCHAR, SQL_UNICODE = SQL_WCHAR, SQL_UNICODE_VARCHAR = SQL_WVARCHAR, SQL_UNICODE_LONGVARCHAR = SQL_WLONGVARCHAR, SQL_UNICODE_CHAR = SQL_WCHAR } // * C datatype to SQL datatype mapping SQL types * enum { /* ------------------------------- */ SQL_C_CHAR = SQL_CHAR, /* CHAR, VARCHAR, DECIMAL, NUMERIC */ SQL_C_LONG = SQL_INTEGER, /* INTEGER */ SQL_C_SHORT = SQL_SMALLINT, /* SMALLINT */ SQL_C_FLOAT = SQL_REAL, /* REAL */ SQL_C_DOUBLE = SQL_DOUBLE, /* FLOAT, DOUBLE */ SQL_C_NUMERIC = SQL_NUMERIC, SQL_C_DEFAULT = 99, SQL_SIGNED_OFFSET = (-20), SQL_UNSIGNED_OFFSET = (-22) } // * C datatype to SQL datatype mapping * enum { SQL_C_DATE = SQL_DATE, SQL_C_TIME = SQL_TIME, SQL_C_TIMESTAMP = SQL_TIMESTAMP } enum { SQL_C_TYPE_DATE = SQL_TYPE_DATE, SQL_C_TYPE_TIME = SQL_TYPE_TIME, SQL_C_TYPE_TIMESTAMP = SQL_TYPE_TIMESTAMP, SQL_C_INTERVAL_YEAR = SQL_INTERVAL_YEAR, SQL_C_INTERVAL_MONTH = SQL_INTERVAL_MONTH, SQL_C_INTERVAL_DAY = SQL_INTERVAL_DAY, SQL_C_INTERVAL_HOUR = SQL_INTERVAL_HOUR, SQL_C_INTERVAL_MINUTE = SQL_INTERVAL_MINUTE, SQL_C_INTERVAL_SECOND = SQL_INTERVAL_SECOND, SQL_C_INTERVAL_YEAR_TO_MONTH = SQL_INTERVAL_YEAR_TO_MONTH, SQL_C_INTERVAL_DAY_TO_HOUR = SQL_INTERVAL_DAY_TO_HOUR, SQL_C_INTERVAL_DAY_TO_MINUTE = SQL_INTERVAL_DAY_TO_MINUTE, SQL_C_INTERVAL_DAY_TO_SECOND = SQL_INTERVAL_DAY_TO_SECOND, SQL_C_INTERVAL_HOUR_TO_MINUTE = SQL_INTERVAL_HOUR_TO_MINUTE, SQL_C_INTERVAL_HOUR_TO_SECOND = SQL_INTERVAL_HOUR_TO_SECOND, SQL_C_INTERVAL_MINUTE_TO_SECOND = SQL_INTERVAL_MINUTE_TO_SECOND } enum { SQL_C_BINARY = SQL_BINARY, SQL_C_BIT = SQL_BIT, SQL_C_SBIGINT = (SQL_BIGINT+SQL_SIGNED_OFFSET), /* SIGNED BIGINT */ SQL_C_UBIGINT = (SQL_BIGINT+SQL_UNSIGNED_OFFSET), /* UNSIGNED BIGINT */ SQL_C_TINYINT = SQL_TINYINT, SQL_C_SLONG = (SQL_C_LONG + SQL_SIGNED_OFFSET), /* SIGNED INTEGER */ SQL_C_SSHORT = (SQL_C_SHORT + SQL_SIGNED_OFFSET), /* SIGNED SMALLINT */ SQL_C_STINYINT = (SQL_TINYINT + SQL_SIGNED_OFFSET), /* SIGNED TINYINT */ SQL_C_ULONG = (SQL_C_LONG + SQL_UNSIGNED_OFFSET), /* UNSIGNED INTEGER */ SQL_C_USHORT = (SQL_C_SHORT + SQL_UNSIGNED_OFFSET), /* UNSIGNED SMALLINT */ SQL_C_UTINYINT = (SQL_TINYINT + SQL_UNSIGNED_OFFSET), /* UNSIGNED TINYINT */ SQL_C_BOOKMARK = SQL_C_ULONG, /* BOOKMARK */ SQL_C_VARBOOKMARK = SQL_C_BINARY, // ODBCVER >= 0x0350 SQL_C_GUID = SQL_GUID /* GUID */ } enum int SQL_TYPE_NULL = 0; // * define for SQL_DIAG_ROW_NUMBER and SQL_DIAG_COLUMN_NUMBER * enum : uint { SQL_NO_ROW_NUMBER = (-1), SQL_NO_COLUMN_NUMBER = (-1), SQL_ROW_NUMBER_UNKNOWN = (-2), SQL_COLUMN_NUMBER_UNKNOWN = (-2) } // * SQLBindParameter extensions * enum uint SQL_DEFAULT_PARAM = (-5); enum uint SQL_IGNORE = (-6); enum uint SQL_COLUMN_IGNORE = SQL_IGNORE; enum : uint { SQL_LEN_DATA_AT_EXEC_OFFSET = (-100), } uint SQL_LEN_DATA_AT_EXEC() ( uint length ) { return ( ( -1 * length ) + cast(uint)SQL_LEN_DATA_AT_EXEC_OFFSET ); } // * binary length for driver specific attributes * enum uint SQL_LEN_BINARY_ATTR_OFFSET = (-100); uint SQL_LEN_BINARY_ATTR() ( uint length ) { return ( ( -1 * length ) + cast(uint)SQL_LEN_BINARY_ATTR_OFFSET ); } // * Defines used by Driver Manager when mapping SQLSetParam to SQLBindParameter * enum int SQL_PARAM_TYPE_DEFAULT = SQL_PARAM_INPUT_OUTPUT; enum int SQL_SETPARAM_VALUE_MAX = (-1L); // ODBCVER < 0x0300 enum int SQL_COLUMN_DRIVER_START = 1000; enum int SQL_COLATT_OPT_MIN = SQL_COLUMN_COUNT; // * SQLColAttributes subdefines for SQL_COLUMN_UPDATABLE * enum { SQL_ATTR_READONLY = 0, SQL_ATTR_WRITE = 1, SQL_ATTR_READWRITE_UNKNOWN = 2 } // * SQLColAttributes subdefines for SQL_COLUMN_SEARCHABLE * // * These are also used by SQLGetInfo * enum { SQL_UNSEARCHABLE = 0, SQL_LIKE_ONLY = 1, SQL_ALL_EXCEPT_LIKE = 2, SQL_SEARCHABLE = 3, SQL_PRED_SEARCHABLE = SQL_SEARCHABLE } // * New defines for SEARCHABLE column in SQLGetTypeInfo * enum { SQL_COL_PRED_CHAR = SQL_LIKE_ONLY, SQL_COL_PRED_BASIC = SQL_ALL_EXCEPT_LIKE } // * Special return values for SQLGetData * enum uint SQL_NO_TOTAL = (-4); /********************************************/ /* SQLGetFunctions: additional values for */ /* fFunction to represent functions that */ /* are not in the X/Open spec. */ /********************************************/ enum { SQL_API_SQLALLOCHANDLESTD = 73, SQL_API_SQLBULKOPERATIONS = 24, SQL_API_SQLBINDPARAMETER = 72, SQL_API_SQLBROWSECONNECT = 55, SQL_API_SQLCOLATTRIBUTES = 6, SQL_API_SQLCOLUMNPRIVILEGES = 56, SQL_API_SQLDESCRIBEPARAM = 58, SQL_API_SQLDRIVERCONNECT = 41, SQL_API_SQLDRIVERS = 71, SQL_API_SQLEXTENDEDFETCH = 59, SQL_API_SQLFOREIGNKEYS = 60, SQL_API_SQLMORERESULTS = 61, SQL_API_SQLNATIVESQL = 62, SQL_API_SQLNUMPARAMS = 63, SQL_API_SQLPARAMOPTIONS = 64, SQL_API_SQLPRIMARYKEYS = 65, SQL_API_SQLPROCEDURECOLUMNS = 66, SQL_API_SQLPROCEDURES = 67, SQL_API_SQLSETPOS = 68, SQL_API_SQLSETSCROLLOPTIONS = 69, SQL_API_SQLTABLEPRIVILEGES = 70 } /+----------------------------------------------+ ' SQL_API_ODBC3_ALL_FUNCTIONS ' ' This returns a bitmap, which allows us to ' ' handle the higher-valued function numbers. ' ' Use SQL_FUNC_EXISTS(bitmap,function_number) ' ' to determine if the function exists. ' +----------------------------------------------+/ enum { SQL_API_ODBC3_ALL_FUNCTIONS = 999, SQL_API_ODBC3_ALL_FUNCTIONS_SIZE = 250, /* array of 250 words */ } //SQL_FUNC_EXISTS(pfExists, uwAPI) ((*(((UWORD*) (pfExists)) + ((uwAPI) >> 4)) // & (1 << ((uwAPI) & 0x000F)) ) ? SQL_TRUE : SQL_FALSE ) /+-----------------------------------------------+ ' ODBC 3.0 SQLGetInfo values that are not part ' ' of the X/Open standard at this time. X/Open ' ' standard values are in sql.h. ' +-----------------------------------------------+/ enum { SQL_ACTIVE_ENVIRONMENTS = 116, SQL_ALTER_DOMAIN = 117, SQL_SQL_CONFORMANCE = 118, SQL_DATETIME_LITERALS = 119, SQL_ASYNC_MODE = 10021, /* new X/Open spec */ SQL_BATCH_ROW_COUNT = 120, SQL_BATCH_SUPPORT = 121, SQL_QUALIFIER_LOCATION = 114, SQL_QUALIFIER_NAME_SEPARATOR = 41, SQL_QUALIFIER_TERM = 42, SQL_QUALIFIER_USAGE = 92, SQL_CATALOG_LOCATION = SQL_QUALIFIER_LOCATION, SQL_CATALOG_NAME_SEPARATOR = SQL_QUALIFIER_NAME_SEPARATOR, SQL_CATALOG_TERM = SQL_QUALIFIER_TERM, SQL_CATALOG_USAGE = SQL_QUALIFIER_USAGE, SQL_CONVERT_WCHAR = 122, SQL_CONVERT_INTERVAL_DAY_TIME = 123, SQL_CONVERT_INTERVAL_YEAR_MONTH = 124, SQL_CONVERT_WLONGVARCHAR = 125, SQL_CONVERT_WVARCHAR = 126, SQL_CREATE_ASSERTION = 127, SQL_CREATE_CHARACTER_SET = 128, SQL_CREATE_COLLATION = 129, SQL_CREATE_DOMAIN = 130, SQL_CREATE_SCHEMA = 131, SQL_CREATE_TABLE = 132, SQL_CREATE_TRANSLATION = 133, SQL_CREATE_VIEW = 134, SQL_DRIVER_HDESC = 135, SQL_DROP_ASSERTION = 136, SQL_DROP_CHARACTER_SET = 137, SQL_DROP_COLLATION = 138, SQL_DROP_DOMAIN = 139, SQL_DROP_SCHEMA = 140, SQL_DROP_TABLE = 141, SQL_DROP_TRANSLATION = 142, SQL_DROP_VIEW = 143, SQL_DYNAMIC_CURSOR_ATTRIBUTES1 = 144, SQL_DYNAMIC_CURSOR_ATTRIBUTES2 = 145, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 = 146, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 = 147, SQL_INDEX_KEYWORDS = 148, SQL_INFO_SCHEMA_VIEWS = 149, SQL_KEYSET_CURSOR_ATTRIBUTES1 = 150, SQL_KEYSET_CURSOR_ATTRIBUTES2 = 151, SQL_MAX_ASYNC_CONCURRENT_STATEMENTS = 10022, /* new X/Open spec */ SQL_ODBC_INTERFACE_CONFORMANCE = 152, SQL_PARAM_ARRAY_ROW_COUNTS = 153, SQL_PARAM_ARRAY_SELECTS = 154, SQL_OWNER_TERM = 39, SQL_OWNER_USAGE = 91, SQL_SCHEMA_TERM = SQL_OWNER_TERM, SQL_SCHEMA_USAGE = SQL_OWNER_USAGE, SQL_SQL92_DATETIME_FUNCTIONS = 155, SQL_SQL92_FOREIGN_KEY_DELETE_RULE = 156, SQL_SQL92_FOREIGN_KEY_UPDATE_RULE = 157, SQL_SQL92_GRANT = 158, SQL_SQL92_NUMERIC_VALUE_FUNCTIONS = 159, SQL_SQL92_PREDICATES = 160, SQL_SQL92_RELATIONAL_JOIN_OPERATORS = 161, SQL_SQL92_REVOKE = 162, SQL_SQL92_ROW_VALUE_enumRUCTOR = 163, SQL_SQL92_STRING_FUNCTIONS = 164, SQL_SQL92_VALUE_EXPRESSIONS = 165, SQL_STANDARD_CLI_CONFORMANCE = 166, SQL_STATIC_CURSOR_ATTRIBUTES1 = 167, SQL_STATIC_CURSOR_ATTRIBUTES2 = 168, SQL_AGGREGATE_FUNCTIONS = 169, SQL_DDL_INDEX = 170, SQL_DM_VER = 171, SQL_INSERT_STATEMENT = 172, SQL_UNION = 96, SQL_UNION_STATEMENT = SQL_UNION } enum int SQL_DTC_TRANSITION_COST = 1750; /+ ' -- SQL_ALTER_TABLE bitmasks -- ' the following 5 bitmasks are defined in sql.d ' enum int SQL_AT_ADD_COLUMN = 0x00000001L ' enum int SQL_AT_DROP_COLUMN = 0x00000002L ' enum int SQL_AT_ADD_CONSTRAINT = 0x00000008L ' +/ enum { SQL_AT_ADD_COLUMN_SINGLE = 0x00000020L, SQL_AT_ADD_COLUMN_DEFAULT = 0x00000040L, SQL_AT_ADD_COLUMN_COLLATION = 0x00000080L, SQL_AT_SET_COLUMN_DEFAULT = 0x00000100L, SQL_AT_DROP_COLUMN_DEFAULT = 0x00000200L, SQL_AT_DROP_COLUMN_CASCADE = 0x00000400L, SQL_AT_DROP_COLUMN_RESTRICT = 0x00000800L, SQL_AT_ADD_TABLE_CONSTRAINT = 0x00001000L, SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE = 0x00002000L, SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT = 0x00004000L, SQL_AT_CONSTRAINT_NAME_DEFINITION = 0x00008000L, SQL_AT_CONSTRAINT_INITIALLY_DEFERRED = 0x00010000L, SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00020000L, SQL_AT_CONSTRAINT_DEFERRABLE = 0x00040000L, SQL_AT_CONSTRAINT_NON_DEFERRABLE = 0x00080000L } // * SQL_CONVERT_* return value bitmasks * enum { SQL_CVT_CHAR = 0x00000001L, SQL_CVT_NUMERIC = 0x00000002L, SQL_CVT_DECIMAL = 0x00000004L, SQL_CVT_INTEGER = 0x00000008L, SQL_CVT_SMALLINT = 0x00000010L, SQL_CVT_FLOAT = 0x00000020L, SQL_CVT_REAL = 0x00000040L, SQL_CVT_DOUBLE = 0x00000080L, SQL_CVT_VARCHAR = 0x00000100L, SQL_CVT_LONGVARCHAR = 0x00000200L, SQL_CVT_BINARY = 0x00000400L, SQL_CVT_VARBINARY = 0x00000800L, SQL_CVT_BIT = 0x00001000L, SQL_CVT_TINYINT = 0x00002000L, SQL_CVT_BIGINT = 0x00004000L, SQL_CVT_DATE = 0x00008000L, SQL_CVT_TIME = 0x00010000L, SQL_CVT_TIMESTAMP = 0x00020000L, SQL_CVT_LONGVARBINARY = 0x00040000L } enum { SQL_CVT_INTERVAL_YEAR_MONTH = 0x00080000L, SQL_CVT_INTERVAL_DAY_TIME = 0x00100000L, SQL_CVT_WCHAR = 0x00200000L, SQL_CVT_WLONGVARCHAR = 0x00400000L, SQL_CVT_WVARCHAR = 0x00800000L } // * SQL_CONVERT_FUNCTIONS functions * enum { SQL_FN_CVT_CONVERT = 0x00000001L, SQL_FN_CVT_CAST = 0x00000002L } // * SQL_STRING_FUNCTIONS functions * enum { SQL_FN_STR_CONCAT = 0x00000001L, SQL_FN_STR_INSERT = 0x00000002L, SQL_FN_STR_LEFT = 0x00000004L, SQL_FN_STR_LTRIM = 0x00000008L, SQL_FN_STR_LENGTH = 0x00000010L, SQL_FN_STR_LOCATE = 0x00000020L, SQL_FN_STR_LCASE = 0x00000040L, SQL_FN_STR_REPEAT = 0x00000080L, SQL_FN_STR_REPLACE = 0x00000100L, SQL_FN_STR_RIGHT = 0x00000200L, SQL_FN_STR_RTRIM = 0x00000400L, SQL_FN_STR_SUBSTRING = 0x00000800L, SQL_FN_STR_UCASE = 0x00001000L, SQL_FN_STR_ASCII = 0x00002000L, SQL_FN_STR_CHAR = 0x00004000L, SQL_FN_STR_DIFFERENCE = 0x00008000L, SQL_FN_STR_LOCATE_2 = 0x00010000L, SQL_FN_STR_SOUNDEX = 0x00020000L, SQL_FN_STR_SPACE = 0x00040000L } enum { SQL_FN_STR_BIT_LENGTH = 0x00080000L, SQL_FN_STR_CHAR_LENGTH = 0x00100000L, SQL_FN_STR_CHARACTER_LENGTH = 0x00200000L, SQL_FN_STR_OCTET_LENGTH = 0x00400000L, SQL_FN_STR_POSITION = 0x00800000L } // * SQL_SQL92_STRING_FUNCTIONS * enum { SQL_SSF_CONVERT = 0x00000001L, SQL_SSF_LOWER = 0x00000002L, SQL_SSF_UPPER = 0x00000004L, SQL_SSF_SUBSTRING = 0x00000008L, SQL_SSF_TRANSLATE = 0x00000010L, SQL_SSF_TRIM_BOTH = 0x00000020L, SQL_SSF_TRIM_LEADING = 0x00000040L, SQL_SSF_TRIM_TRAILING = 0x00000080L } // * SQL_NUMERIC_FUNCTIONS functions * enum { SQL_FN_NUM_ABS = 0x00000001L, SQL_FN_NUM_ACOS = 0x00000002L, SQL_FN_NUM_ASIN = 0x00000004L, SQL_FN_NUM_ATAN = 0x00000008L, SQL_FN_NUM_ATAN2 = 0x00000010L, SQL_FN_NUM_CEILING = 0x00000020L, SQL_FN_NUM_COS = 0x00000040L, SQL_FN_NUM_COT = 0x00000080L, SQL_FN_NUM_EXP = 0x00000100L, SQL_FN_NUM_FLOOR = 0x00000200L, SQL_FN_NUM_LOG = 0x00000400L, SQL_FN_NUM_MOD = 0x00000800L, SQL_FN_NUM_SIGN = 0x00001000L, SQL_FN_NUM_SIN = 0x00002000L, SQL_FN_NUM_SQRT = 0x00004000L, SQL_FN_NUM_TAN = 0x00008000L, SQL_FN_NUM_PI = 0x00010000L, SQL_FN_NUM_RAND = 0x00020000L, SQL_FN_NUM_DEGREES = 0x00040000L, SQL_FN_NUM_LOG10 = 0x00080000L, SQL_FN_NUM_POWER = 0x00100000L, SQL_FN_NUM_RADIANS = 0x00200000L, SQL_FN_NUM_ROUND = 0x00400000L, SQL_FN_NUM_TRUNCATE = 0x00800000L } // * SQL_SQL92_NUMERIC_VALUE_FUNCTIONS * enum { SQL_SNVF_BIT_LENGTH = 0x00000001L, SQL_SNVF_CHAR_LENGTH = 0x00000002L, SQL_SNVF_CHARACTER_LENGTH = 0x00000004L, SQL_SNVF_EXTRACT = 0x00000008L, SQL_SNVF_OCTET_LENGTH = 0x00000010L, SQL_SNVF_POSITION = 0x00000020L } // * SQL_TIMEDATE_FUNCTIONS functions * enum { SQL_FN_TD_NOW = 0x00000001L, SQL_FN_TD_CURDATE = 0x00000002L, SQL_FN_TD_DAYOFMONTH = 0x00000004L, SQL_FN_TD_DAYOFWEEK = 0x00000008L, SQL_FN_TD_DAYOFYEAR = 0x00000010L, SQL_FN_TD_MONTH = 0x00000020L, SQL_FN_TD_QUARTER = 0x00000040L, SQL_FN_TD_WEEK = 0x00000080L, SQL_FN_TD_YEAR = 0x00000100L, SQL_FN_TD_CURTIME = 0x00000200L, SQL_FN_TD_HOUR = 0x00000400L, SQL_FN_TD_MINUTE = 0x00000800L, SQL_FN_TD_SECOND = 0x00001000L, SQL_FN_TD_TIMESTAMPADD = 0x00002000L, SQL_FN_TD_TIMESTAMPDIFF = 0x00004000L, SQL_FN_TD_DAYNAME = 0x00008000L, SQL_FN_TD_MONTHNAME = 0x00010000L } enum { SQL_FN_TD_CURRENT_DATE = 0x00020000L, SQL_FN_TD_CURRENT_TIME = 0x00040000L, SQL_FN_TD_CURRENT_TIMESTAMP = 0x00080000L, SQL_FN_TD_EXTRACT = 0x00100000L } // * SQL_SQL92_DATETIME_FUNCTIONS * enum { SQL_SDF_CURRENT_DATE = 0x00000001L, SQL_SDF_CURRENT_TIME = 0x00000002L, SQL_SDF_CURRENT_TIMESTAMP = 0x00000004L } // * SQL_SYSTEM_FUNCTIONS functions * enum { SQL_FN_SYS_USERNAME = 0x00000001L, SQL_FN_SYS_DBNAME = 0x00000002L, SQL_FN_SYS_IFNULL = 0x00000004L } // * SQL_TIMEDATE_ADD_INTERVALS and SQL_TIMEDATE_DIFF_INTERVALS functions * enum { SQL_FN_TSI_FRAC_SECOND = 0x00000001L, SQL_FN_TSI_SECOND = 0x00000002L, SQL_FN_TSI_MINUTE = 0x00000004L, SQL_FN_TSI_HOUR = 0x00000008L, SQL_FN_TSI_DAY = 0x00000010L, SQL_FN_TSI_WEEK = 0x00000020L, SQL_FN_TSI_MONTH = 0x00000040L, SQL_FN_TSI_QUARTER = 0x00000080L, SQL_FN_TSI_YEAR = 0x00000100L } /+ ' bitmasks for SQL_DYNAMIC_CURSOR_ATTRIBUTES1, ' SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1, ' SQL_KEYSET_CURSOR_ATTRIBUTES1, and SQL_STATIC_CURSOR_ATTRIBUTES1 ' +/ enum { // * supported SQLFetchScroll FetchOrientation's * SQL_CA1_NEXT = 0x00000001L, SQL_CA1_ABSOLUTE = 0x00000002L, SQL_CA1_RELATIVE = 0x00000004L, SQL_CA1_BOOKMARK = 0x00000008L, // * supported SQLSetPos LockType's * SQL_CA1_LOCK_NO_CHANGE = 0x00000040L, SQL_CA1_LOCK_EXCLUSIVE = 0x00000080L, SQL_CA1_LOCK_UNLOCK = 0x00000100L, // * supported SQLSetPos Operations * SQL_CA1_POS_POSITION = 0x00000200L, SQL_CA1_POS_UPDATE = 0x00000400L, SQL_CA1_POS_DELETE = 0x00000800L, SQL_CA1_POS_REFRESH = 0x00001000L, // * positioned updates and deletes * SQL_CA1_POSITIONED_UPDATE = 0x00002000L, SQL_CA1_POSITIONED_DELETE = 0x00004000L, SQL_CA1_SELECT_FOR_UPDATE = 0x00008000L, // * supported SQLBulkOperations operations * SQL_CA1_BULK_ADD = 0x00010000L, SQL_CA1_BULK_UPDATE_BY_BOOKMARK = 0x00020000L, SQL_CA1_BULK_DELETE_BY_BOOKMARK = 0x00040000L, SQL_CA1_BULK_FETCH_BY_BOOKMARK = 0x00080000L } /+ ' bitmasks for SQL_DYNAMIC_CURSOR_ATTRIBUTES2, ' SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2, ' SQL_KEYSET_CURSOR_ATTRIBUTES2, and SQL_STATIC_CURSOR_ATTRIBUTES2 ' +/ enum { // * supported values for SQL_ATTR_SCROLL_CONCURRENCY * SQL_CA2_READ_ONLY_CONCURRENCY = 0x00000001L, SQL_CA2_LOCK_CONCURRENCY = 0x00000002L, SQL_CA2_OPT_ROWVER_CONCURRENCY = 0x00000004L, SQL_CA2_OPT_VALUES_CONCURRENCY = 0x00000008L, // * sensitivity of the cursor to its own inserts, deletes, and updates * SQL_CA2_SENSITIVITY_ADDITIONS = 0x00000010L, SQL_CA2_SENSITIVITY_DELETIONS = 0x00000020L, SQL_CA2_SENSITIVITY_UPDATES = 0x00000040L, // * semantics of SQL_ATTR_MAX_ROWS * SQL_CA2_MAX_ROWS_SELECT = 0x00000080L, SQL_CA2_MAX_ROWS_INSERT = 0x00000100L, SQL_CA2_MAX_ROWS_DELETE = 0x00000200L, SQL_CA2_MAX_ROWS_UPDATE = 0x00000400L, SQL_CA2_MAX_ROWS_CATALOG = 0x00000800L, SQL_CA2_MAX_ROWS_AFFECTS_ALL = (SQL_CA2_MAX_ROWS_SELECT | SQL_CA2_MAX_ROWS_INSERT | SQL_CA2_MAX_ROWS_DELETE | SQL_CA2_MAX_ROWS_UPDATE | SQL_CA2_MAX_ROWS_CATALOG), // * semantics of SQL_DIAG_CURSOR_ROW_COUNT * SQL_CA2_CRC_EXACT = 0x00001000L, SQL_CA2_CRC_APPROXIMATE = 0x00002000L, // * the kinds of positioned statements that can be simulated * SQL_CA2_SIMULATE_NON_UNIQUE = 0x00004000L, SQL_CA2_SIMULATE_TRY_UNIQUE = 0x00008000L, SQL_CA2_SIMULATE_UNIQUE = 0x00010000L } // * SQL_ODBC_API_CONFORMANCE values * enum { SQL_OAC_NONE = 0x0000, SQL_OAC_LEVEL1 = 0x0001, SQL_OAC_LEVEL2 = 0x0002 } // * SQL_ODBC_SAG_CLI_CONFORMANCE values * enum { SQL_OSCC_NOT_COMPLIANT = 0x0000, SQL_OSCC_COMPLIANT = 0x0001 } // * SQL_ODBC_SQL_CONFORMANCE values * enum { SQL_OSC_MINIMUM = 0x0000, SQL_OSC_CORE = 0x0001, SQL_OSC_EXTENDED = 0x0002 } // * SQL_CONCAT_NULL_BEHAVIOR values * enum { SQL_CB_NULL = 0x0000, SQL_CB_NON_NULL = 0x0001 } // * SQL_SCROLL_OPTIONS masks * enum { SQL_SO_FORWARD_ONLY = 0x00000001L, SQL_SO_KEYSET_DRIVEN = 0x00000002L, SQL_SO_DYNAMIC = 0x00000004L, SQL_SO_MIXED = 0x00000008L, SQL_SO_STATIC = 0x00000010L } // * SQL_FETCH_DIRECTION masks * enum { SQL_FD_FETCH_BOOKMARK = 0x00000080L } // * SQL_CORRELATION_NAME values * enum { SQL_CN_NONE = 0x0000, SQL_CN_DIFFERENT = 0x0001, SQL_CN_ANY = 0x0002 } enum { // * SQL_NON_NULLABLE_COLUMNS values * SQL_NNC_NULL = 0x0000, SQL_NNC_NON_NULL = 0x0001, // * SQL_NULL_COLLATION values * SQL_NC_START = 0x0002, SQL_NC_END = 0x0004 } // * SQL_FILE_USAGE values * enum { SQL_FILE_NOT_SUPPORTED = 0x0000, SQL_FILE_TABLE = 0x0001, SQL_FILE_QUALIFIER = 0x0002, SQL_FILE_CATALOG = SQL_FILE_QUALIFIER } // * SQL_GETDATA_EXTENSIONS values * enum { SQL_GD_BLOCK = 0x00000004L, SQL_GD_BOUND = 0x00000008L } // * SQL_POSITIONED_STATEMENTS masks * enum { SQL_PS_POSITIONED_DELETE = 0x00000001L, SQL_PS_POSITIONED_UPDATE = 0x00000002L, SQL_PS_SELECT_FOR_UPDATE = 0x00000004L } // * SQL_GROUP_BY values * enum { SQL_GB_NOT_SUPPORTED = 0x0000, SQL_GB_GROUP_BY_EQUALS_SELECT = 0x0001, SQL_GB_GROUP_BY_CONTAINS_SELECT = 0x0002, SQL_GB_NO_RELATION = 0x0003, SQL_GB_COLLATE = 0x0004 } // * SQL_OWNER_USAGE masks * enum { SQL_OU_DML_STATEMENTS = 0x00000001L, SQL_OU_PROCEDURE_INVOCATION = 0x00000002L, SQL_OU_TABLE_DEFINITION = 0x00000004L, SQL_OU_INDEX_DEFINITION = 0x00000008L, SQL_OU_PRIVILEGE_DEFINITION = 0x00000010L } // * SQL_SCHEMA_USAGE masks * enum { SQL_SU_DML_STATEMENTS = SQL_OU_DML_STATEMENTS, SQL_SU_PROCEDURE_INVOCATION = SQL_OU_PROCEDURE_INVOCATION, SQL_SU_TABLE_DEFINITION = SQL_OU_TABLE_DEFINITION, SQL_SU_INDEX_DEFINITION = SQL_OU_INDEX_DEFINITION, SQL_SU_PRIVILEGE_DEFINITION = SQL_OU_PRIVILEGE_DEFINITION } // * SQL_QUALIFIER_USAGE masks * enum { SQL_QU_DML_STATEMENTS = 0x00000001L, SQL_QU_PROCEDURE_INVOCATION = 0x00000002L, SQL_QU_TABLE_DEFINITION = 0x00000004L, SQL_QU_INDEX_DEFINITION = 0x00000008L, SQL_QU_PRIVILEGE_DEFINITION = 0x00000010L } enum { // * SQL_CATALOG_USAGE masks * SQL_CU_DML_STATEMENTS = SQL_QU_DML_STATEMENTS, SQL_CU_PROCEDURE_INVOCATION = SQL_QU_PROCEDURE_INVOCATION, SQL_CU_TABLE_DEFINITION = SQL_QU_TABLE_DEFINITION, SQL_CU_INDEX_DEFINITION = SQL_QU_INDEX_DEFINITION, SQL_CU_PRIVILEGE_DEFINITION = SQL_QU_PRIVILEGE_DEFINITION } enum { // * SQL_SUBQUERIES masks * SQL_SQ_COMPARISON = 0x00000001L, SQL_SQ_EXISTS = 0x00000002L, SQL_SQ_IN = 0x00000004L, SQL_SQ_QUANTIFIED = 0x00000008L, SQL_SQ_CORRELATED_SUBQUERIES = 0x00000010L, // * SQL_UNION masks * SQL_U_UNION = 0x00000001L, SQL_U_UNION_ALL = 0x00000002L, // * SQL_BOOKMARK_PERSISTENCE values * SQL_BP_CLOSE = 0x00000001L, SQL_BP_DELETE = 0x00000002L, SQL_BP_DROP = 0x00000004L, SQL_BP_TRANSACTION = 0x00000008L, SQL_BP_UPDATE = 0x00000010L, SQL_BP_OTHER_HSTMT = 0x00000020L, SQL_BP_SCROLL = 0x00000040L, // * SQL_STATIC_SENSITIVITY values * SQL_SS_ADDITIONS = 0x00000001L, SQL_SS_DELETIONS = 0x00000002L, SQL_SS_UPDATES = 0x00000004L, // * SQL_VIEW values * SQL_CV_CREATE_VIEW = 0x00000001L, SQL_CV_CHECK_OPTION = 0x00000002L, SQL_CV_CASCADED = 0x00000004L, SQL_CV_LOCAL = 0x00000008L, // * SQL_LOCK_TYPES masks * SQL_LCK_NO_CHANGE = 0x00000001L, SQL_LCK_EXCLUSIVE = 0x00000002L, SQL_LCK_UNLOCK = 0x00000004L, // * SQL_POS_OPERATIONS masks * SQL_POS_POSITION = 0x00000001L, SQL_POS_REFRESH = 0x00000002L, SQL_POS_UPDATE = 0x00000004L, SQL_POS_DELETE = 0x00000008L, SQL_POS_ADD = 0x00000010L, // * SQL_QUALIFIER_LOCATION values * SQL_QL_START = 0x0001, SQL_QL_END = 0x0002 } // * Here start return values for ODBC 3.0 SQLGetInfo * enum { // * SQL_AGGREGATE_FUNCTIONS bitmasks * SQL_AF_AVG = 0x00000001L, SQL_AF_COUNT = 0x00000002L, SQL_AF_MAX = 0x00000004L, SQL_AF_MIN = 0x00000008L, SQL_AF_SUM = 0x00000010L, SQL_AF_DISTINCT = 0x00000020L, SQL_AF_ALL = 0x00000040L, // * SQL_SQL_CONFORMANCE bit masks * SQL_SC_SQL92_ENTRY = 0x00000001L, SQL_SC_FIPS127_2_TRANSITIONAL = 0x00000002L, SQL_SC_SQL92_INTERMEDIATE = 0x00000004L, SQL_SC_SQL92_FULL = 0x00000008L, // * SQL_DATETIME_LITERALS masks * SQL_DL_SQL92_DATE = 0x00000001L, SQL_DL_SQL92_TIME = 0x00000002L, SQL_DL_SQL92_TIMESTAMP = 0x00000004L, SQL_DL_SQL92_INTERVAL_YEAR = 0x00000008L, SQL_DL_SQL92_INTERVAL_MONTH = 0x00000010L, SQL_DL_SQL92_INTERVAL_DAY = 0x00000020L, SQL_DL_SQL92_INTERVAL_HOUR = 0x00000040L, SQL_DL_SQL92_INTERVAL_MINUTE = 0x00000080L, SQL_DL_SQL92_INTERVAL_SECOND = 0x00000100L, SQL_DL_SQL92_INTERVAL_YEAR_TO_MONTH = 0x00000200L, SQL_DL_SQL92_INTERVAL_DAY_TO_HOUR = 0x00000400L, SQL_DL_SQL92_INTERVAL_DAY_TO_MINUTE = 0x00000800L, SQL_DL_SQL92_INTERVAL_DAY_TO_SECOND = 0x00001000L, SQL_DL_SQL92_INTERVAL_HOUR_TO_MINUTE = 0x00002000L, SQL_DL_SQL92_INTERVAL_HOUR_TO_SECOND = 0x00004000L, SQL_DL_SQL92_INTERVAL_MINUTE_TO_SECOND = 0x00008000L, // * SQL_CATALOG_LOCATION values * SQL_CL_START = SQL_QL_START, SQL_CL_END = SQL_QL_END, // * values for SQL_BATCH_ROW_COUNT * SQL_BRC_PROCEDURES = 0x0000001, SQL_BRC_EXPLICIT = 0x0000002, SQL_BRC_ROLLED_UP = 0x0000004, // * bitmasks for SQL_BATCH_SUPPORT * SQL_BS_SELECT_EXPLICIT = 0x00000001L, SQL_BS_ROW_COUNT_EXPLICIT = 0x00000002L, SQL_BS_SELECT_PROC = 0x00000004L, SQL_BS_ROW_COUNT_PROC = 0x00000008L, // * Values for SQL_PARAM_ARRAY_ROW_COUNTS getinfo */ SQL_PARC_BATCH = 1, SQL_PARC_NO_BATCH = 2, // * values for SQL_PARAM_ARRAY_SELECTS * SQL_PAS_BATCH = 1, SQL_PAS_NO_BATCH = 2, SQL_PAS_NO_SELECT = 3, // * Bitmasks for SQL_INDEX_KEYWORDS * SQL_IK_NONE = 0x00000000L, SQL_IK_ASC = 0x00000001L, SQL_IK_DESC = 0x00000002L, SQL_IK_ALL = (SQL_IK_ASC | SQL_IK_DESC), // * Bitmasks for SQL_INFO_SCHEMA_VIEWS * SQL_ISV_ASSERTIONS = 0x00000001L, SQL_ISV_CHARACTER_SETS = 0x00000002L, SQL_ISV_CHECK_CONSTRAINTS = 0x00000004L, SQL_ISV_COLLATIONS = 0x00000008L, SQL_ISV_COLUMN_DOMAIN_USAGE = 0x00000010L, SQL_ISV_COLUMN_PRIVILEGES = 0x00000020L, SQL_ISV_COLUMNS = 0x00000040L, SQL_ISV_CONSTRAINT_COLUMN_USAGE = 0x00000080L, SQL_ISV_CONSTRAINT_TABLE_USAGE = 0x00000100L, SQL_ISV_DOMAIN_CONSTRAINTS = 0x00000200L, SQL_ISV_DOMAINS = 0x00000400L, SQL_ISV_KEY_COLUMN_USAGE = 0x00000800L, SQL_ISV_REFERENTIAL_CONSTRAINTS = 0x00001000L, SQL_ISV_SCHEMATA = 0x00002000L, SQL_ISV_SQL_LANGUAGES = 0x00004000L, SQL_ISV_TABLE_CONSTRAINTS = 0x00008000L, SQL_ISV_TABLE_PRIVILEGES = 0x00010000L, SQL_ISV_TABLES = 0x00020000L, SQL_ISV_TRANSLATIONS = 0x00040000L, SQL_ISV_USAGE_PRIVILEGES = 0x00080000L, SQL_ISV_VIEW_COLUMN_USAGE = 0x00100000L, SQL_ISV_VIEW_TABLE_USAGE = 0x00200000L, SQL_ISV_VIEWS = 0x00400000L, // * Bitmasks for SQL_ASYNC_MODE * SQL_AM_NONE = 0, SQL_AM_CONNECTION = 1, SQL_AM_STATEMENT = 2, // * Bitmasks for SQL_ALTER_DOMAIN * SQL_AD_CONSTRAINT_NAME_DEFINITION = 0x00000001L, SQL_AD_ADD_DOMAIN_CONSTRAINT = 0x00000002L, SQL_AD_DROP_DOMAIN_CONSTRAINT = 0x00000004L, SQL_AD_ADD_DOMAIN_DEFAULT = 0x00000008L, SQL_AD_DROP_DOMAIN_DEFAULT = 0x00000010L, SQL_AD_ADD_CONSTRAINT_INITIALLY_DEFERRED = 0x00000020L, SQL_AD_ADD_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00000040L, SQL_AD_ADD_CONSTRAINT_DEFERRABLE = 0x00000080L, SQL_AD_ADD_CONSTRAINT_NON_DEFERRABLE = 0x00000100L, // * SQL_CREATE_SCHEMA bitmasks * SQL_CS_CREATE_SCHEMA = 0x00000001L, SQL_CS_AUTHORIZATION = 0x00000002L, SQL_CS_DEFAULT_CHARACTER_SET = 0x00000004L, // * SQL_CREATE_TRANSLATION bitmasks * SQL_CTR_CREATE_TRANSLATION = 0x00000001L, // * SQL_CREATE_ASSERTION bitmasks * SQL_CA_CREATE_ASSERTION = 0x00000001L, SQL_CA_CONSTRAINT_INITIALLY_DEFERRED = 0x00000010L, SQL_CA_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00000020L, SQL_CA_CONSTRAINT_DEFERRABLE = 0x00000040L, SQL_CA_CONSTRAINT_NON_DEFERRABLE = 0x00000080L, // * SQL_CREATE_CHARACTER_SET bitmasks * SQL_CCS_CREATE_CHARACTER_SET = 0x00000001L, SQL_CCS_COLLATE_CLAUSE = 0x00000002L, SQL_CCS_LIMITED_COLLATION = 0x00000004L, // * SQL_CREATE_COLLATION bitmasks * SQL_CCOL_CREATE_COLLATION = 0x00000001L, // * SQL_CREATE_DOMAIN bitmasks * SQL_CDO_CREATE_DOMAIN = 0x00000001L, SQL_CDO_DEFAULT = 0x00000002L, SQL_CDO_CONSTRAINT = 0x00000004L, SQL_CDO_COLLATION = 0x00000008L, SQL_CDO_CONSTRAINT_NAME_DEFINITION = 0x00000010L, SQL_CDO_CONSTRAINT_INITIALLY_DEFERRED = 0x00000020L, SQL_CDO_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00000040L, SQL_CDO_CONSTRAINT_DEFERRABLE = 0x00000080L, SQL_CDO_CONSTRAINT_NON_DEFERRABLE = 0x00000100L, // * SQL_CREATE_TABLE bitmasks * SQL_CT_CREATE_TABLE = 0x00000001L, SQL_CT_COMMIT_PRESERVE = 0x00000002L, SQL_CT_COMMIT_DELETE = 0x00000004L, SQL_CT_GLOBAL_TEMPORARY = 0x00000008L, SQL_CT_LOCAL_TEMPORARY = 0x00000010L, SQL_CT_CONSTRAINT_INITIALLY_DEFERRED = 0x00000020L, SQL_CT_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00000040L, SQL_CT_CONSTRAINT_DEFERRABLE = 0x00000080L, SQL_CT_CONSTRAINT_NON_DEFERRABLE = 0x00000100L, SQL_CT_COLUMN_CONSTRAINT = 0x00000200L, SQL_CT_COLUMN_DEFAULT = 0x00000400L, SQL_CT_COLUMN_COLLATION = 0x00000800L, SQL_CT_TABLE_CONSTRAINT = 0x00001000L, SQL_CT_CONSTRAINT_NAME_DEFINITION = 0x00002000L, // * SQL_DDL_INDEX bitmasks * SQL_DI_CREATE_INDEX = 0x00000001L, SQL_DI_DROP_INDEX = 0x00000002L, // * SQL_DROP_COLLATION bitmasks * SQL_DC_DROP_COLLATION = 0x00000001L, // * SQL_DROP_DOMAIN bitmasks * SQL_DD_DROP_DOMAIN = 0x00000001L, SQL_DD_RESTRICT = 0x00000002L, SQL_DD_CASCADE = 0x00000004L, // * SQL_DROP_SCHEMA bitmasks * SQL_DS_DROP_SCHEMA = 0x00000001L, SQL_DS_RESTRICT = 0x00000002L, SQL_DS_CASCADE = 0x00000004L, // * SQL_DROP_CHARACTER_SET bitmasks * SQL_DCS_DROP_CHARACTER_SET = 0x00000001L, // * SQL_DROP_ASSERTION bitmasks * SQL_DA_DROP_ASSERTION = 0x00000001L, // * SQL_DROP_TABLE bitmasks * SQL_DT_DROP_TABLE = 0x00000001L, SQL_DT_RESTRICT = 0x00000002L, SQL_DT_CASCADE = 0x00000004L, // * SQL_DROP_TRANSLATION bitmasks * SQL_DTR_DROP_TRANSLATION = 0x00000001L, // * SQL_DROP_VIEW bitmasks * SQL_DV_DROP_VIEW = 0x00000001L, SQL_DV_RESTRICT = 0x00000002L, SQL_DV_CASCADE = 0x00000004L, // * SQL_INSERT_STATEMENT bitmasks * SQL_IS_INSERT_LITERALS = 0x00000001L, SQL_IS_INSERT_SEARCHED = 0x00000002L, SQL_IS_SELECT_INTO = 0x00000004L, // * SQL_ODBC_INTERFACE_CONFORMANCE values * SQL_OIC_CORE = 1UL, SQL_OIC_LEVEL1 = 2UL, SQL_OIC_LEVEL2 = 3UL, // * SQL_SQL92_FOREIGN_KEY_DELETE_RULE bitmasks * SQL_SFKD_CASCADE = 0x00000001L, SQL_SFKD_NO_ACTION = 0x00000002L, SQL_SFKD_SET_DEFAULT = 0x00000004L, SQL_SFKD_SET_NULL = 0x00000008L, // * SQL_SQL92_FOREIGN_KEY_UPDATE_RULE bitmasks * SQL_SFKU_CASCADE = 0x00000001L, SQL_SFKU_NO_ACTION = 0x00000002L, SQL_SFKU_SET_DEFAULT = 0x00000004L, SQL_SFKU_SET_NULL = 0x00000008L, // * SQL_SQL92_GRANT bitmasks * SQL_SG_USAGE_ON_DOMAIN = 0x00000001L, SQL_SG_USAGE_ON_CHARACTER_SET = 0x00000002L, SQL_SG_USAGE_ON_COLLATION = 0x00000004L, SQL_SG_USAGE_ON_TRANSLATION = 0x00000008L, SQL_SG_WITH_GRANT_OPTION = 0x00000010L, SQL_SG_DELETE_TABLE = 0x00000020L, SQL_SG_INSERT_TABLE = 0x00000040L, SQL_SG_INSERT_COLUMN = 0x00000080L, SQL_SG_REFERENCES_TABLE = 0x00000100L, SQL_SG_REFERENCES_COLUMN = 0x00000200L, SQL_SG_SELECT_TABLE = 0x00000400L, SQL_SG_UPDATE_TABLE = 0x00000800L, SQL_SG_UPDATE_COLUMN = 0x00001000L, // * SQL_SQL92_PREDICATES bitmasks * SQL_SP_EXISTS = 0x00000001L, SQL_SP_ISNOTNULL = 0x00000002L, SQL_SP_ISNULL = 0x00000004L, SQL_SP_MATCH_FULL = 0x00000008L, SQL_SP_MATCH_PARTIAL = 0x00000010L, SQL_SP_MATCH_UNIQUE_FULL = 0x00000020L, SQL_SP_MATCH_UNIQUE_PARTIAL = 0x00000040L, SQL_SP_OVERLAPS = 0x00000080L, SQL_SP_UNIQUE = 0x00000100L, SQL_SP_LIKE = 0x00000200L, SQL_SP_IN = 0x00000400L, SQL_SP_BETWEEN = 0x00000800L, SQL_SP_COMPARISON = 0x00001000L, SQL_SP_QUANTIFIED_COMPARISON = 0x00002000L, // * SQL_SQL92_RELATIONAL_JOIN_OPERATORS bitmasks * SQL_SRJO_CORRESPONDING_CLAUSE = 0x00000001L, SQL_SRJO_CROSS_JOIN = 0x00000002L, SQL_SRJO_EXCEPT_JOIN = 0x00000004L, SQL_SRJO_FULL_OUTER_JOIN = 0x00000008L, SQL_SRJO_INNER_JOIN = 0x00000010L, SQL_SRJO_INTERSECT_JOIN = 0x00000020L, SQL_SRJO_LEFT_OUTER_JOIN = 0x00000040L, SQL_SRJO_NATURAL_JOIN = 0x00000080L, SQL_SRJO_RIGHT_OUTER_JOIN = 0x00000100L, SQL_SRJO_UNION_JOIN = 0x00000200L, // * SQL_SQL92_REVOKE bitmasks * SQL_SR_USAGE_ON_DOMAIN = 0x00000001L, SQL_SR_USAGE_ON_CHARACTER_SET = 0x00000002L, SQL_SR_USAGE_ON_COLLATION = 0x00000004L, SQL_SR_USAGE_ON_TRANSLATION = 0x00000008L, SQL_SR_GRANT_OPTION_FOR = 0x00000010L, SQL_SR_CASCADE = 0x00000020L, SQL_SR_RESTRICT = 0x00000040L, SQL_SR_DELETE_TABLE = 0x00000080L, SQL_SR_INSERT_TABLE = 0x00000100L, SQL_SR_INSERT_COLUMN = 0x00000200L, SQL_SR_REFERENCES_TABLE = 0x00000400L, SQL_SR_REFERENCES_COLUMN = 0x00000800L, SQL_SR_SELECT_TABLE = 0x00001000L, SQL_SR_UPDATE_TABLE = 0x00002000L, SQL_SR_UPDATE_COLUMN = 0x00004000L, // * SQL_SQL92_ROW_VALUE_CONSTRUCTOR bitmasks * SQL_SRVC_VALUE_EXPRESSION = 0x00000001L, SQL_SRVC_NULL = 0x00000002L, SQL_SRVC_DEFAULT = 0x00000004L, SQL_SRVC_ROW_SUBQUERY = 0x00000008L, // * SQL_SQL92_VALUE_EXPRESSIONS bitmasks * SQL_SVE_CASE = 0x00000001L, SQL_SVE_CAST = 0x00000002L, SQL_SVE_COALESCE = 0x00000004L, SQL_SVE_NULLIF = 0x00000008L, // * SQL_STANDARD_CLI_CONFORMANCE bitmasks * SQL_SCC_XOPEN_CLI_VERSION1 = 0x00000001L, SQL_SCC_ISO92_CLI = 0x00000002L, // * SQL_UNION_STATEMENT bitmasks * SQL_US_UNION = SQL_U_UNION, SQL_US_UNION_ALL = SQL_U_UNION_ALL } // * SQL_DTC_TRANSITION_COST bitmasks * enum { SQL_DTC_ENLIST_EXPENSIVE = 0x00000001L, SQL_DTC_UNENLIST_EXPENSIVE = 0x00000002L } // * additional SQLDataSources fetch directions * enum { SQL_FETCH_FIRST_USER = 31, SQL_FETCH_FIRST_SYSTEM = 32 } enum { // * Defines for SQLSetPos * SQL_ENTIRE_ROWSET = 0, // * Operations in SQLSetPos * SQL_POSITION = 0, /* 1.0 FALSE */ SQL_REFRESH = 1, /* 1.0 TRUE */ SQL_UPDATE = 2, SQL_DELETE = 3, // * Operations in SQLBulkOperations * SQL_ADD = 4, SQL_SETPOS_MAX_OPTION_VALUE = SQL_ADD } enum { SQL_UPDATE_BY_BOOKMARK = 5, SQL_DELETE_BY_BOOKMARK = 6, SQL_FETCH_BY_BOOKMARK = 7 } // * Lock options in SQLSetPos * enum { SQL_LOCK_NO_CHANGE = 0, /* 1.0 FALSE */ SQL_LOCK_EXCLUSIVE = 1, /* 1.0 TRUE */ SQL_LOCK_UNLOCK = 2, SQL_SETPOS_MAX_LOCK_VALUE = SQL_LOCK_UNLOCK } //************************ /+ Macros for SQLSetPos. They're templates so they don't link in. +/ //************************ int SQL_POSITION_TO() ( SQLHSTMT hstmt, ushort irow ) { return SQLSetPos( hstmt, irow, SQL_POSITION, SQL_LOCK_NO_CHANGE ); }; int SQL_LOCK_RECORD() ( SQLHSTMT hstmt, ushort irow, bool fLock ) { return SQLSetPos( hstmt, irow, SQL_POSITION, fLock ); } int SQL_REFRESH_RECORD() ( SQLHSTMT hstmt, ushort irow, bool fLock ) { return SQLSetPos( hstmt, irow, SQL_REFRESH, fLock ); } int SQL_UPDATE_RECORD() ( SQLHSTMT hstmt, ushort irow ) { return SQLSetPos( hstmt, irow, SQL_UPDATE, SQL_LOCK_NO_CHANGE ); } int SQL_DELETE_RECORD() ( SQLHSTMT hstmt, ushort irow ) { return SQLSetPos( hstmt, irow, SQL_DELETE, SQL_LOCK_NO_CHANGE ); } int SQL_ADD_RECORD() ( SQLHSTMT hstmt, ushort irow ) { return SQLSetPos( hstmt, irow, SQL_ADD,SQL_LOCK_NO_CHANGE ); } // * Column types and scopes in SQLSpecialColumns. * enum { SQL_BEST_ROWID = 1, SQL_ROWVER = 2 } /+ ' Defines for SQLSpecialColumns (returned in the result set) ' SQL_PC_UNKNOWN and SQL_PC_PSEUDO are defined in sql.d ' +/ enum int SQL_PC_NOT_PSEUDO = 1; // * Defines for SQLStatistics * enum { SQL_QUICK = 0, SQL_ENSURE = 1 } /+ ' Defines for SQLStatistics (returned in the result set) ' SQL_INDEX_CLUSTERED, SQL_INDEX_HASHED, and SQL_INDEX_OTHER are ' defined in sql.d ' +/ enum int SQL_TABLE_STAT = 0; // * Defines for SQLTables * immutable char[] SQL_ALL_CATALOGS = "%"; immutable char[] SQL_ALL_SCHEMAS = "%"; immutable char[] SQL_ALL_TABLE_TYPES = "%"; // * Options for SQLDriverConnect - fDriverCompletion * enum { SQL_DRIVER_NOPROMPT = 0, SQL_DRIVER_COMPLETE = 1, SQL_DRIVER_PROMPT = 2, SQL_DRIVER_COMPLETE_REQUIRED = 3 } /+ ' ODBC v1.0+ ODBC ' Is an alternative to SQLConnect. It supports data sources that require more ' connection information than the three arguments in SQLConnect, dialog boxes ' to prompt the user for all connection information, and data sources that are ' not defined in the system information. ' ' SQLDriverConnect provides the following connection attributes: ' ' 1) Establish a connection using a connection string that contains the data ' source name, one or more user IDs, one or more passwords, and other information ' required by the data source. ' ' 2) Establish a connection using a partial connection string or no additional ' information; in this case, the Driver Manager and the driver can each prompt ' the user for connection information. ' ' 3) Establish a connection to a data source that is not defined in the system ' information. If the application supplies a partial connection string, the ' driver can prompt the user for connection information. ' ' 4) Establish a connection to a data source using a connection string ' constructed from the information in a .dsn file. ' +/ SQLRETURN SQLDriverConnect ( /+ IN +/ SQLHDBC hdbc, /+ IN +/ SQLHWND hwnd, /+ IN +/ SQLCHAR *szConnStrIn, /+ IN +/ SQLSMALLINT cbConnStrIn, /+ OUT +/ SQLCHAR *szConnStrOut, /+ IN +/ SQLSMALLINT cbConnStrOutMax, /+ OUT +/ SQLSMALLINT *pcbConnStrOut, /+ IN +/ SQLUSMALLINT fDriverCompletion ); // * Level 2 Functions * // * SQLExtendedFetch "fFetchType" values * enum int SQL_FETCH_BOOKMARK = 8; // * SQLExtendedFetch "rgfRowStatus" element values * enum { SQL_ROW_SUCCESS = 0, SQL_ROW_DELETED = 1, SQL_ROW_UPDATED = 2, SQL_ROW_NOROW = 3, SQL_ROW_ADDED = 4, SQL_ROW_ERROR = 5 } enum { SQL_ROW_SUCCESS_WITH_INFO = 6, SQL_ROW_PROCEED = 0, SQL_ROW_IGNORE = 1 } // * value for SQL_DESC_ARRAY_STATUS_PTR * enum { SQL_PARAM_SUCCESS = 0, SQL_PARAM_SUCCESS_WITH_INFO = 6, SQL_PARAM_ERROR = 5, SQL_PARAM_UNUSED = 7, SQL_PARAM_DIAG_UNAVAILABLE = 1, SQL_PARAM_PROCEED = 0, SQL_PARAM_IGNORE = 1 } // * Defines for SQLForeignKeys (UPDATE_RULE and DELETE_RULE) * enum { SQL_CASCADE = 0, SQL_RESTRICT = 1, SQL_SET_NULL = 2, SQL_NO_ACTION = 3, SQL_SET_DEFAULT = 4 } /+ ' Note that the following are in a different column of SQLForeignKeys than ' the previous ones above. These are for DEFERRABILITY. ' +/ enum { SQL_INITIALLY_DEFERRED = 5, SQL_INITIALLY_IMMEDIATE = 6, SQL_NOT_DEFERRABLE = 7 } /* Defines for SQLBindParameter and SQLProcedureColumns (returned in the result set) */ enum { SQL_PARAM_TYPE_UNKNOWN = 0, SQL_PARAM_INPUT = 1, SQL_PARAM_INPUT_OUTPUT = 2, SQL_RESULT_COL = 3, SQL_PARAM_OUTPUT = 4, SQL_RETURN_VALUE = 5, /* Defines for SQLProcedures (returned in the result set) */ SQL_PT_UNKNOWN = 0, SQL_PT_PROCEDURE = 1, SQL_PT_FUNCTION = 2 } // * This define is too large for RC * static immutable char[] SQL_ODBC_KEYWORDS = "ABSOLUTE,ACTION,ADA,ADD,ALL,ALLOCATE,ALTER,AND,ANY,ARE,AS," ~ "ASC,ASSERTION,AT,AUTHORIZATION,AVG," ~ "BEGIN,BETWEEN,BIT,BIT_LENGTH,BOTH,BY,CASCADE,CASCADED,CASE,CAST,CATALOG," ~ "CHAR,CHAR_LENGTH,CHARACTER,CHARACTER_LENGTH,CHECK,CLOSE,COALESCE," ~ "COLLATE,COLLATION,COLUMN,COMMIT,CONNECT,CONNECTION,CONSTRAINT," ~ "CONSTRAINTS,CONTINUE,CONVERT,CORRESPONDING,COUNT,CREATE,CROSS,CURRENT," ~ "CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,CURRENT_USER,CURSOR," ~ "DATE,DAY,DEALLOCATE,DEC,DECIMAL,DECLARE,DEFAULT,DEFERRABLE," ~ "DEFERRED,DELETE,DESC,DESCRIBE,DESCRIPTOR,DIAGNOSTICS,DISCONNECT," ~ "DISTINCT,DOMAIN,DOUBLE,DROP," ~ "ELSE,END,END-EXEC,ESCAPE,EXCEPT,EXCEPTION,EXEC,EXECUTE," ~ "EXISTS,EXTERNAL,EXTRACT," ~ "FALSE,FETCH,FIRST,FLOAT,FOR,FOREIGN,FORTRAN,FOUND,FROM,FULL," ~ "GET,GLOBAL,GO,GOTO,GRANT,GROUP,HAVING,HOUR," ~ "IDENTITY,IMMEDIATE,IN,INCLUDE,INDEX,INDICATOR,INITIALLY,INNER," ~ "INPUT,INSENSITIVE,INSERT,INT,INTEGER,INTERSECT,INTERVAL,INTO,IS,ISOLATION," ~ "JOIN,KEY,LANGUAGE,LAST,LEADING,LEFT,LEVEL,LIKE,LOCAL,LOWER," ~ "MATCH,MAX,MIN,MINUTE,MODULE,MONTH," ~ "NAMES,NATIONAL,NATURAL,NCHAR,NEXT,NO,NONE,NOT,NULL,NULLIF,NUMERIC," ~ "OCTET_LENGTH,OF,ON,ONLY,OPEN,OPTION,OR,ORDER,OUTER,OUTPUT,OVERLAPS," ~ "PAD,PARTIAL,PASCAL,PLI,POSITION,PRECISION,PREPARE,PRESERVE," ~ "PRIMARY,PRIOR,PRIVILEGES,PROCEDURE,PUBLIC," ~ "READ,REAL,REFERENCES,RELATIVE,RESTRICT,REVOKE,RIGHT,ROLLBACK,ROWS" ~ "SCHEMA,SCROLL,SECOND,SECTION,SELECT,SESSION,SESSION_USER,SET,SIZE," ~ "SMALLINT,SOME,SPACE,SQL,SQLCA,SQLCODE,SQLERROR,SQLSTATE,SQLWARNING," ~ "SUBSTRING,SUM,SYSTEM_USER," ~ "TABLE,TEMPORARY,THEN,TIME,TIMESTAMP,TIMEZONE_HOUR,TIMEZONE_MINUTE," ~ "TO,TRAILING,TRANSACTION,TRANSLATE,TRANSLATION,TRIM,TRUE," ~ "UNION,UNIQUE,UNKNOWN,UPDATE,UPPER,USAGE,USER,USING," ~ "VALUE,VALUES,VARCHAR,VARYING,VIEW,WHEN,WHENEVER,WHERE,WITH,WORK,WRITE," ~ "YEAR,ZONE"; /+ ' ODBC v1.0+ ODBC ' Supports an iterative method of discovering and enumerating the attributes ' and attribute values required to connect to a data source. Each call to ' SQLBrowseConnect returns successive levels of attributes and attribute values. ' When all levels have been enumerated, a connection to the data source is ' completed and a complete connection string is returned by SQLBrowseConnect. ' A return code of SQL_SUCCESS or SQL_SUCCESS_WITH_INFO indicates that all ' connection information has been specified and the application is now connected ' to the data source. ' +/ SQLRETURN SQLBrowseConnect ( /+ IN +/ SQLHDBC hdbc, /+ IN +/ SQLCHAR *szConnStrIn, /+ IN +/ SQLSMALLINT cbConnStrIn, /+ OUT +/ SQLCHAR *szConnStrOut, /+ IN +/ SQLSMALLINT cbConnStrOutMax, /+ OUT +/ SQLSMALLINT *pcbConnStrOut ); /+ ' ODBC v3.0+ ODBC ' Performs bulk insertions and bulk bookmark operations, ' including update, delete, and fetch by bookmark. ' ' -- Operation -- ' Operation to perform: ' SQL_ADD ' SQL_UPDATE_BY_BOOKMARK ' SQL_DELETE_BY_BOOKMARK ' SQL_FETCH_BY_BOOKMARK ' +/ SQLRETURN SQLBulkOperations ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLSMALLINT Operation ); /+ ' ODBC v1.0+ ODBC ' Returns a list of columns and associated privileges for the ' specified table. The driver returns the information as a ' result set on the specified StatementHandle. ' +/ SQLRETURN SQLColumnPrivileges ( /+ IN +/ SQLHSTMT hstmt, /+ IN +/ SQLCHAR *szCatalogName, /+ IN +/ SQLSMALLINT cbCatalogName, /+ IN +/ SQLCHAR *szSchemaName, /+ IN +/ SQLSMALLINT cbSchemaName, /+ IN +/ SQLCHAR *szTableName, /+ IN +/ SQLSMALLINT cbTableName, /+ IN +/ SQLCHAR *szColumnName, /+ IN +/ SQLSMALLINT cbColumnName ); /+ ' ODBC v1.0+ ODBC ' Returns the description of a parameter marker associated ' with a prepared SQL statement. This information is also ' available in the fields of the IPD. ' ' -- pfNullable -- ' Pointer to a buffer in which to return a value that indicates ' whether the parameter allows NULL values. This value is read ' from the SQL_DESC_NULLABLE field of the IPD. One of the following: ' ' SQL_NO_NULLS: The parameter does not allow NULL values (this is the default value). ' SQL_NULLABLE: The parameter allows NULL values. ' SQL_NULLABLE_UNKNOWN: The driver cannot determine if the parameter allows NULL values. ' +/ SQLRETURN SQLDescribeParam ( /+ IN +/ SQLHSTMT hstmt, /+ IN +/ SQLUSMALLINT ipar, /+ OUT +/ SQLSMALLINT *pfSqlType, /+ OUT +/ SQLUINTEGER *pcbParamDef, /+ OUT +/ SQLSMALLINT *pibScale, /+ OUT +/ SQLSMALLINT *pfNullable ); /+ ' ODBC v1.0+ ODBC ' SQLForeignKeys can return: ' A list of foreign keys in the specified table (columns in the ' specified table that refer to primary keys in other tables). ' A list of foreign keys in other tables that refer to the primary ' key in the specified table. The driver returns each list as a ' result set on the specified statement. ' +/ SQLRETURN SQLForeignKeys ( /+ IN +/ SQLHSTMT hstmt, /+ IN +/ SQLCHAR *szPkCatalogName, /+ IN +/ SQLSMALLINT cbPkCatalogName, /+ IN +/ SQLCHAR *szPkSchemaName, /+ IN +/ SQLSMALLINT cbPkSchemaName, /+ IN +/ SQLCHAR *szPkTableName, /+ IN +/ SQLSMALLINT cbPkTableName, /+ IN +/ SQLCHAR *szFkCatalogName, /+ IN +/ SQLSMALLINT cbFkCatalogName, /+ IN +/ SQLCHAR *szFkSchemaName, /+ IN +/ SQLSMALLINT cbFkSchemaName, /+ IN +/ SQLCHAR *szFkTableName, /+ IN +/ SQLSMALLINT cbFkTableName ); /+ ' ODBC v1.0+ ODBC ' Determines whether more results are available on a statement ' containing SELECT, UPDATE, INSERT, or DELETE statements and, ' if so, initializes processing for those results. ' +/ SQLRETURN SQLMoreResults ( /+ IN +/ SQLHSTMT hstmt ); /+ ' ODBC v1.0+ ODBC ' Returns the SQL string as modified by the driver. ' SQLNativeSql does not execute the SQL statement. ' +/ SQLRETURN SQLNativeSql ( /+ IN +/ SQLHDBC hdbc, /+ IN +/ SQLCHAR *szSqlStrIn, /+ IN +/ SQLINTEGER cbSqlStrIn, /+ OUT +/ SQLCHAR *szSqlStr, /+ IN +/ SQLINTEGER cbSqlStrMax, /+ OUT +/ SQLINTEGER *pcbSqlStr ); /+ ' ODBC v1.0+ ISO 92 ' Returns the number of parameters in an SQL statement. ' +/ SQLRETURN SQLNumParams ( /+ IN +/ SQLHSTMT hstmt, /+ OUT +/ SQLSMALLINT *pcpar ); /+ ' ODBC v1.0+ ODBC ' Returns the column names that make up the primary key ' for a table. The driver returns the information as a ' result set. This function does not support returning ' primary keys from multiple tables in a single call. ' +/ SQLRETURN SQLPrimaryKeys ( /+ IN +/ SQLHSTMT hstmt, /+ IN +/ SQLCHAR *szCatalogName, /+ IN +/ SQLSMALLINT cbCatalogName, /+ IN +/ SQLCHAR *szSchemaName, /+ IN +/ SQLSMALLINT cbSchemaName, /+ IN +/ SQLCHAR *szTableName, /+ IN +/ SQLSMALLINT cbTableName ); /+ ' ODBC v1.0+ ODBC ' Returns the list of input and output parameters, as ' well as the columns that make up the result set for ' the specified procedures. The driver returns the ' information as a result set on the specified statement. ' +/ SQLRETURN SQLProcedureColumns ( /+ IN +/ SQLHSTMT hstmt, /+ IN +/ SQLCHAR *szCatalogName, /+ IN +/ SQLSMALLINT cbCatalogName, /+ IN +/ SQLCHAR *szSchemaName, /+ IN +/ SQLSMALLINT cbSchemaName, /+ IN +/ SQLCHAR *szProcName, /+ IN +/ SQLSMALLINT cbProcName, /+ IN +/ SQLCHAR *szColumnName, /+ IN +/ SQLSMALLINT cbColumnName ); /+ ' ODBC v1.0+ ODBC ' Returns the list of procedure names stored in a specific ' data source. Procedure is a generic term used to describe ' an executable object, or a named entity that can be invoked ' using input and output parameters. ' +/ SQLRETURN SQLProcedures ( /+ IN +/ SQLHSTMT hstmt, /+ IN +/ SQLCHAR *szCatalogName, /+ IN +/ SQLSMALLINT cbCatalogName, /+ IN +/ SQLCHAR *szSchemaName, /+ IN +/ SQLSMALLINT cbSchemaName, /+ IN +/ SQLCHAR *szProcName, /+ IN +/ SQLSMALLINT cbProcName ); /+ ' ODBC v1.0+ ODBC ' Sets the cursor position in a rowset and allows an ' application to refresh data in the rowset or to ' update or delete data in the result set. ' ' -- fOperation -- ' Operation to perform: ' SQL_POSITION ' SQL_REFRESH ' SQL_UPDATE ' SQL_DELETE ' ' -- fLockType -- ' Specifies how to lock the row after performing the ' operation specified in the Operation argument. ' SQL_LOCK_NO_CHANGE ' SQL_LOCK_EXCLUSIVE ' SQL_LOCK_UNLOCK ' +/ SQLRETURN SQLSetPos ( /+ IN +/ SQLHSTMT hstmt, /+ IN +/ SQLUSMALLINT irow, /+ IN +/ SQLUSMALLINT fOperation, /+ IN +/ SQLUSMALLINT fLockType ); /+ ' ODBC v1.0+ ODBC ' Returns a list of tables and the privileges associated ' with each table. The driver returns the information as ' a result set on the specified statement. ' +/ SQLRETURN SQLTablePrivileges ( /+ IN +/ SQLHSTMT hstmt, /+ IN +/ SQLCHAR *szCatalogName, /+ IN +/ SQLSMALLINT cbCatalogName, /+ IN +/ SQLCHAR *szSchemaName, /+ IN +/ SQLSMALLINT cbSchemaName, /+ IN +/ SQLCHAR *szTableName, /+ IN +/ SQLSMALLINT cbTableName ); /+ ' ODBC v2.0 ODBC ' Lists driver descriptions and driver attribute keywords. ' This function is implemented solely by the Driver Manager. ' ' -- fDirection -- ' Determines whether the Driver Manager fetches the next driver ' description in the list (SQL_FETCH_NEXT) or whether the search ' starts from the beginning of the list (SQL_FETCH_FIRST). ' +/ SQLRETURN SQLDrivers ( /+ IN +/ SQLHENV henv, /+ IN +/ SQLUSMALLINT fDirection, /+ OUT +/ SQLCHAR *szDriverDesc, /+ IN +/ SQLSMALLINT cbDriverDescMax, /+ OUT +/ SQLSMALLINT *pcbDriverDesc, /+ OUT +/ SQLCHAR *szDriverAttributes, /+ IN +/ SQLSMALLINT cbDrvrAttrMax, /+ OUT +/ SQLSMALLINT *pcbDrvrAttr ); /+ ' ODBC v2.0+ ODBC ' Binds a buffer to a parameter marker in an SQL statement. ' SQLBindParameter supports binding to a Unicode C data type, ' even if the underlying driver does not support Unicode data. ' +/ SQLRETURN SQLBindParameter ( /+ IN +/ SQLHSTMT hstmt, /+ IN +/ SQLUSMALLINT ipar, /+ IN +/ SQLSMALLINT fParamType, /+ IN +/ SQLSMALLINT fCType, /+ IN +/ SQLSMALLINT fSqlType, /+ IN +/ SQLUINTEGER cbColDef, /+ IN +/ SQLSMALLINT ibScale, /+ IN +/ SQLPOINTER rgbValue, /+ INOUT +/ SQLINTEGER cbValueMax, /+ IN +/ SQLINTEGER *pcbValue ); /+----------------------+ | Deprecated Functions | +----------------------+/ /+ ' In ODBC 3.x, the ODBC 2.0 function SQLColAttributes has ' been replaced by SQLColAttribute. ' +/ SQLRETURN SQLColAttributes ( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT *pcbDesc, SQLINTEGER *pfDesc ); /+ ' In ODBC 3.x, SQLExtendedFetch has been replaced by ' SQLFetchScroll. ODBC 3.x applications should not ' call SQLExtendedFetch; instead they should call ' SQLFetchScroll. ' +/ SQLRETURN SQLExtendedFetch ( SQLHSTMT hstmt, SQLUSMALLINT fFetchType, SQLINTEGER irow, SQLUINTEGER *pcrow, SQLUSMALLINT *rgfRowStatus ); /+ ' SQLParamOptions has been replaced in ODBC 3.x by calls to SQLSetStmtAttr. ' +/ SQLRETURN SQLParamOptions ( SQLHSTMT hstmt, SQLUINTEGER crow, SQLUINTEGER *pirow ); // end Deprecated Functions ldc-1.1.0-beta3-src/runtime/phobos/etc/c/odbc/sqltypes.d0000664000175000017500000000740712776215007021061 0ustar kaikai/** Declarations for interfacing with the ODBC library. Adapted with minimal changes from the work of David L. Davis (refer to the $(WEB forum.dlang.org/post/cfk7ql$(DOLLAR)1p4n$(DOLLAR)1@digitaldaemon.com, original announcement)). `etc.c.odbc.sqlext.d` corresponds to the `sqlext.h` C header file. See_Also: $(LUCKY ODBC API Reference on MSN Online) */ module etc.c.odbc.sqltypes; extern (Windows): // * API declaration data types * //alias void *HANDLE; //alias ubyte SQLCHAR; alias char SQLCHAR; alias byte SQLSCHAR; alias ubyte SQLDATE; alias ubyte SQLDECIMAL; alias double SQLDOUBLE; alias double SQLFLOAT; alias int SQLINTEGER; alias ushort SQLUINTEGER; alias ubyte SQLNUMERIC; alias float SQLREAL; alias ubyte SQLTIME; alias ubyte SQLTIMESTAMP; alias ubyte SQLVARCHAR; alias void * SQLPOINTER; alias short SQLSMALLINT; alias ushort SQLUSMALLINT; // * function return type * alias SQLSMALLINT SQLRETURN; // * generic data structures * alias void * SQLHANDLE; alias SQLHANDLE SQLHENV; alias SQLHANDLE SQLHDBC; alias SQLHANDLE SQLHSTMT; alias SQLHANDLE SQLHDESC; // * SQL portable types for C * //alias ubyte UCHAR; // std.c.windows.windows has this alias //alias char UCHAR; alias byte SCHAR; //alias SCHAR SQLSCHAR; alias uint DWORD; alias int SDWORD; alias short SWORD; alias uint UDWORD; alias ushort UWORD; alias short WORD; //alias UDWORD SQLUINTEGER; alias long SLONG; alias short SSHORT; alias ulong ULONG; alias ushort USHORT; alias double SDOUBLE; alias double LDOUBLE; alias float SFLOAT; alias void* PTR; alias void* HENV; alias void* HDBC; alias void* HSTMT; alias short RETCODE; alias SQLPOINTER HWND; alias HWND SQLHWND; // * transfer types for DATE, TIME, TIMESTAMP * struct DATE_STRUCT { SQLSMALLINT year; SQLUSMALLINT month; SQLUSMALLINT day; }; alias DATE_STRUCT SQL_DATE_STRUCT; struct TIME_STRUCT { SQLUSMALLINT hour; SQLUSMALLINT minute; SQLUSMALLINT second; }; alias TIME_STRUCT SQL_TIME_STRUCT; struct TIMESTAMP_STRUCT { SQLSMALLINT year; SQLUSMALLINT month; SQLUSMALLINT day; SQLUSMALLINT hour; SQLUSMALLINT minute; SQLUSMALLINT second; SQLUINTEGER fraction; }; alias TIMESTAMP_STRUCT SQL_TIMESTAMP_STRUCT; /+ ' enumerations for DATETIME_INTERVAL_SUBCODE values for interval data types ' these values are from SQL-92 +/ enum SQLINTERVAL { SQL_IS_YEAR = 1, SQL_IS_MONTH = 2, SQL_IS_DAY = 3, SQL_IS_HOUR = 4, SQL_IS_MINUTE = 5, SQL_IS_SECOND = 6, SQL_IS_YEAR_TO_MONTH = 7, SQL_IS_DAY_TO_HOUR = 8, SQL_IS_DAY_TO_MINUTE = 9, SQL_IS_DAY_TO_SECOND = 10, SQL_IS_HOUR_TO_MINUTE = 11, SQL_IS_HOUR_TO_SECOND = 12, SQL_IS_MINUTE_TO_SECOND = 13 } struct SQL_YEAR_MONTH_STRUCT { SQLUINTEGER year; SQLUINTEGER month; }; struct SQL_DAY_SECOND_STRUCT { SQLUINTEGER day; SQLUINTEGER hour; SQLUINTEGER minute; SQLUINTEGER second; SQLUINTEGER fraction; }; struct SQL_INTERVAL_STRUCT { SQLINTERVAL interval_type; SQLSMALLINT interval_sign; union intval { SQL_YEAR_MONTH_STRUCT year_month; SQL_DAY_SECOND_STRUCT day_second; }; }; // * internal representation of numeric data type * const int SQL_MAX_NUMERIC_LEN = 16; struct SQL_NUMERIC_STRUCT { SQLCHAR precision; SQLSCHAR scale; SQLCHAR sign; /* 1 if positive, 0 if negative */ SQLCHAR[ SQL_MAX_NUMERIC_LEN ] val; }; /* size is 16 */ struct SQLGUID { DWORD Data1; WORD Data2; WORD Data3; ubyte[ 8 ] Data4; }; alias SQLGUID GUID; alias uint BOOKMARK; alias ushort SQLWCHAR; version( UNICODE ) { alias SQLWCHAR SQLTCHAR; } else { alias SQLCHAR SQLTCHAR; } // end version( UNICODE ) ldc-1.1.0-beta3-src/runtime/phobos/etc/c/odbc/sql.d0000664000175000017500000011401212776215007017763 0ustar kaikai/** Declarations for interfacing with the ODBC library. Adapted with minimal changes from the work of David L. Davis (refer to the $(WEB forum.dlang.org/post/cfk7ql$(DOLLAR)1p4n$(DOLLAR)1@digitaldaemon.com, original announcement)). `etc.c.odbc.sql` is the the main include for ODBC v3.0+ Core functions, corresponding to the `sql.h` C header file. It `import`s `public`ly `etc.c.odbc.sqltypes` for conformity with the C header. Note: The ODBC library itself not a part of the `dmd` distribution (and typically not a part of the distribution packages of other compilers such as `gdc` and `ldc`). To use ODBC, install it per the vendor- and platform-specific instructions and then use the appropriate command-line flags (e.g. for dmd, `-L-lodbc` on Posix and `-Lodbc32.lib` on Windows) to link with the ODBC library. On Windows, using $(D pragma(lib, "odbc32")) in D code at top level is also appropriate. See_Also: $(LUCKY ODBC API Reference on MSN Online) */ module etc.c.odbc.sql; public import etc.c.odbc.sqltypes; extern (Windows): // * special length/indicator values * enum int SQL_NULL_DATA = (-1); enum int SQL_DATA_AT_EXEC = (-2); // * return values from functions * enum { SQL_SUCCESS = 0, SQL_SUCCESS_WITH_INFO = 1, SQL_NO_DATA = 100, SQL_ERROR = (-1), SQL_INVALID_HANDLE = (-2), SQL_STILL_EXECUTING = 2, SQL_NEED_DATA = 99 } /* test for SQL_SUCCESS or SQL_SUCCESS_WITH_INFO */ bool SQL_SUCCEEDED()(uint rc) { return (rc & ~1U) == 0; } enum { // * flags for null-terminated string * SQL_NTS = (-3), SQL_NTSL = (-3L), // * maximum message length * SQL_MAX_MESSAGE_LENGTH = 512, // * date/time length constants * SQL_DATE_LEN = 10, SQL_TIME_LEN = 8, /* add P+1 if precision is nonzero */ SQL_TIMESTAMP_LEN = 19, /* add P+1 if precision is nonzero */ // * handle type identifiers * SQL_HANDLE_ENV = 1, SQL_HANDLE_DBC = 2, SQL_HANDLE_STMT = 3, SQL_HANDLE_DESC = 4, // * environment attribute * SQL_ATTR_OUTPUT_NTS = 10001, // * connection attributes * SQL_ATTR_AUTO_IPD = 10001, SQL_ATTR_METADATA_ID = 10014, // * statement attributes * SQL_ATTR_APP_ROW_DESC = 10010, SQL_ATTR_APP_PARAM_DESC = 10011, SQL_ATTR_IMP_ROW_DESC = 10012, SQL_ATTR_IMP_PARAM_DESC = 10013, SQL_ATTR_CURSOR_SCROLLABLE = (-1), SQL_ATTR_CURSOR_SENSITIVITY = (-2), // * SQL_ATTR_CURSOR_SCROLLABLE values * SQL_NONSCROLLABLE = 0, SQL_SCROLLABLE = 1, // * identifiers of fields in the SQL descriptor * SQL_DESC_COUNT = 1001, SQL_DESC_TYPE = 1002, SQL_DESC_LENGTH = 1003, SQL_DESC_OCTET_LENGTH_PTR = 1004, SQL_DESC_PRECISION = 1005, SQL_DESC_SCALE = 1006, SQL_DESC_DATETIME_INTERVAL_CODE = 1007, SQL_DESC_NULLABLE = 1008, SQL_DESC_INDICATOR_PTR = 1009, SQL_DESC_DATA_PTR = 1010, SQL_DESC_NAME = 1011, SQL_DESC_UNNAMED = 1012, SQL_DESC_OCTET_LENGTH = 1013, SQL_DESC_ALLOC_TYPE = 1099 } // * identifiers of fields in the diagnostics area * enum { SQL_DIAG_RETURNCODE = 1, SQL_DIAG_NUMBER = 2, SQL_DIAG_ROW_COUNT = 3, SQL_DIAG_SQLSTATE = 4, SQL_DIAG_NATIVE = 5, SQL_DIAG_MESSAGE_TEXT = 6, SQL_DIAG_DYNAMIC_FUNCTION = 7, SQL_DIAG_CLASS_ORIGIN = 8, SQL_DIAG_SUBCLASS_ORIGIN = 9, SQL_DIAG_CONNECTION_NAME = 10, SQL_DIAG_SERVER_NAME = 11, SQL_DIAG_DYNAMIC_FUNCTION_CODE = 12 } // * dynamic function codes * enum { SQL_DIAG_ALTER_DOMAIN = 3, SQL_DIAG_ALTER_TABLE = 4, SQL_DIAG_CALL = 7, SQL_DIAG_CREATE_ASSERTION = 6, SQL_DIAG_CREATE_CHARACTER_SET = 8, SQL_DIAG_CREATE_COLLATION = 10, SQL_DIAG_CREATE_DOMAIN = 23, SQL_DIAG_CREATE_INDEX = (-1), SQL_DIAG_CREATE_SCHEMA = 64, SQL_DIAG_CREATE_TABLE = 77, SQL_DIAG_CREATE_TRANSLATION = 79, SQL_DIAG_CREATE_VIEW = 84, SQL_DIAG_DELETE_WHERE = 19, SQL_DIAG_DROP_ASSERTION = 24, SQL_DIAG_DROP_CHARACTER_SET = 25, SQL_DIAG_DROP_COLLATION = 26, SQL_DIAG_DROP_DOMAIN = 27, SQL_DIAG_DROP_INDEX = (-2), SQL_DIAG_DROP_SCHEMA = 31, SQL_DIAG_DROP_TABLE = 32, SQL_DIAG_DROP_TRANSLATION = 33, SQL_DIAG_DROP_VIEW = 36, SQL_DIAG_DYNAMIC_DELETE_CURSOR = 38, SQL_DIAG_DYNAMIC_UPDATE_CURSOR = 81, SQL_DIAG_GRANT = 48, SQL_DIAG_INSERT = 50, SQL_DIAG_REVOKE = 59, SQL_DIAG_SELECT_CURSOR = 85, SQL_DIAG_UNKNOWN_STATEMENT = 0, SQL_DIAG_UPDATE_WHERE = 82 } enum { // * SQL data type codes * SQL_UNKNOWN_TYPE = 0, SQL_CHAR = 1, SQL_NUMERIC = 2, SQL_DECIMAL = 3, SQL_INTEGER = 4, SQL_SMALLINT = 5, SQL_FLOAT = 6, SQL_REAL = 7, SQL_DOUBLE = 8, SQL_DATETIME = 9, SQL_VARCHAR = 12, // * One-parameter shortcuts for date/time data types * SQL_TYPE_DATE = 91, SQL_TYPE_TIME = 92, SQL_TYPE_TIMESTAMP = 93 } // * Statement attribute values for cursor sensitivity * enum { SQL_UNSPECIFIED = 0, SQL_INSENSITIVE = 1, SQL_SENSITIVE = 2 } // * GetTypeInfo() request for all data types * enum { SQL_ALL_TYPES = 0 } // * Default conversion code for SQLBindCol(), SQLBindParam() and SQLGetData() * enum { SQL_DEFAULT = 99 } /+ SQLGetData() code indicating that the application row descriptor ' specifies the data type +/ enum { SQL_ARD_TYPE = (-99) } // * SQL date/time type subcodes * enum { SQL_CODE_DATE = 1, SQL_CODE_TIME = 2, SQL_CODE_TIMESTAMP = 3 } // * CLI option values * enum { SQL_FALSE = 0, SQL_TRUE = 1 } // * values of NULLABLE field in descriptor * enum { SQL_NO_NULLS = 0, SQL_NULLABLE = 1 } /+ Value returned by SQLGetTypeInfo() to denote that it is ' not known whether or not a data type supports null values. +/ enum { SQL_NULLABLE_UNKNOWN = 2 } /+ Values returned by SQLGetTypeInfo() to show WHERE clause ' supported +/ enum { SQL_PRED_NONE = 0, SQL_PRED_CHAR = 1, SQL_PRED_BASIC = 2 } // * values of UNNAMED field in descriptor * enum { SQL_NAMED = 0, SQL_UNNAMED = 1 } // * values of ALLOC_TYPE field in descriptor * enum { SQL_DESC_ALLOC_AUTO = 1, SQL_DESC_ALLOC_USER = 2 } // * FreeStmt() options * enum { SQL_CLOSE = 0, SQL_DROP = 1, SQL_UNBIND = 2, SQL_RESET_PARAMS = 3 } // * Codes used for FetchOrientation in SQLFetchScroll(), and in SQLDataSources() * enum { SQL_FETCH_NEXT = 1, SQL_FETCH_FIRST = 2 } // * Other codes used for FetchOrientation in SQLFetchScroll() * enum { SQL_FETCH_LAST = 3, SQL_FETCH_PRIOR = 4, SQL_FETCH_ABSOLUTE = 5, SQL_FETCH_RELATIVE = 6 } // * SQLEndTran() options * enum { SQL_COMMIT = 0, SQL_ROLLBACK = 1 } // * null handles returned by SQLAllocHandle() * enum SQLHANDLE SQL_NULL_HENV = cast(SQLHANDLE)0; enum SQLHANDLE SQL_NULL_HDBC = cast(SQLHANDLE)0; enum SQLHANDLE SQL_NULL_HSTMT = cast(SQLHANDLE)0; enum SQLHANDLE SQL_NULL_HDESC = cast(SQLHANDLE)0; // * null handle used in place of parent handle when allocating HENV * enum SQLHANDLE SQL_NULL_HANDLE = cast(SQLHANDLE)0L; // * Values that may appear in the result set of SQLSpecialColumns() * enum { SQL_SCOPE_CURROW = 0, SQL_SCOPE_TRANSACTION = 1, SQL_SCOPE_SESSION = 2 } enum { SQL_PC_UNKNOWN = 0, SQL_PC_NON_PSEUDO = 1, SQL_PC_PSEUDO = 2 } // * Reserved value for the IdentifierType argument of SQLSpecialColumns() * enum { SQL_ROW_IDENTIFIER = 1 } // * Reserved values for UNIQUE argument of SQLStatistics() * enum { SQL_INDEX_UNIQUE = 0, SQL_INDEX_ALL = 1, // * Values that may appear in the result set of SQLStatistics() * SQL_INDEX_CLUSTERED = 1, SQL_INDEX_HASHED = 2, SQL_INDEX_OTHER = 3 } // * SQLGetFunctions() values to identify ODBC APIs * enum { SQL_API_SQLALLOCCONNECT = 1, SQL_API_SQLALLOCENV = 2, SQL_API_SQLALLOCHANDLE = 1001, SQL_API_SQLALLOCSTMT = 3, SQL_API_SQLBINDCOL = 4, SQL_API_SQLBINDPARAM = 1002, SQL_API_SQLCANCEL = 5, SQL_API_SQLCLOSECURSOR = 1003, SQL_API_SQLCOLATTRIBUTE = 6, SQL_API_SQLCOLUMNS = 40, SQL_API_SQLCONNECT = 7, SQL_API_SQLCOPYDESC = 1004, SQL_API_SQLDATASOURCES = 57, SQL_API_SQLDESCRIBECOL = 8, SQL_API_SQLDISCONNECT = 9, SQL_API_SQLENDTRAN = 1005, SQL_API_SQLERROR = 10, SQL_API_SQLEXECDIRECT = 11, SQL_API_SQLEXECUTE = 12, SQL_API_SQLFETCH = 13, SQL_API_SQLFETCHSCROLL = 1021, SQL_API_SQLFREECONNECT = 14, SQL_API_SQLFREEENV = 15, SQL_API_SQLFREEHANDLE = 1006, SQL_API_SQLFREESTMT = 16, SQL_API_SQLGETCONNECTATTR = 1007, SQL_API_SQLGETCONNECTOPTION = 42, SQL_API_SQLGETCURSORNAME = 17, SQL_API_SQLGETDATA = 43, SQL_API_SQLGETDESCFIELD = 1008, SQL_API_SQLGETDESCREC = 1009, SQL_API_SQLGETDIAGFIELD = 1010, SQL_API_SQLGETDIAGREC = 1011, SQL_API_SQLGETENVATTR = 1012, SQL_API_SQLGETFUNCTIONS = 44, SQL_API_SQLGETINFO = 45, SQL_API_SQLGETSTMTATTR = 1014, SQL_API_SQLGETSTMTOPTION = 46, SQL_API_SQLGETTYPEINFO = 47, SQL_API_SQLNUMRESULTCOLS = 18, SQL_API_SQLPARAMDATA = 48, SQL_API_SQLPREPARE = 19, SQL_API_SQLPUTDATA = 49, SQL_API_SQLROWCOUNT = 20, SQL_API_SQLSETCONNECTATTR = 1016, SQL_API_SQLSETCONNECTOPTION = 50, SQL_API_SQLSETCURSORNAME = 21, SQL_API_SQLSETDESCFIELD = 1017, SQL_API_SQLSETDESCREC = 1018, SQL_API_SQLSETENVATTR = 1019, SQL_API_SQLSETPARAM = 22, SQL_API_SQLSETSTMTATTR = 1020, SQL_API_SQLSETSTMTOPTION = 51, SQL_API_SQLSPECIALCOLUMNS = 52, SQL_API_SQLSTATISTICS = 53, SQL_API_SQLTABLES = 54, SQL_API_SQLTRANSACT = 23 } // * Information requested by SQLGetInfo() * enum { SQL_MAX_DRIVER_CONNECTIONS = 0, SQL_MAXIMUM_DRIVER_CONNECTIONS = SQL_MAX_DRIVER_CONNECTIONS, SQL_MAX_CONCURRENT_ACTIVITIES = 1, SQL_MAXIMUM_CONCURRENT_ACTIVITIES = SQL_MAX_CONCURRENT_ACTIVITIES, SQL_DATA_SOURCE_NAME = 2, SQL_FETCH_DIRECTION = 8, SQL_SERVER_NAME = 13, SQL_SEARCH_PATTERN_ESCAPE = 14, SQL_DBMS_NAME = 17, SQL_DBMS_VER = 18, SQL_ACCESSIBLE_TABLES = 19, SQL_ACCESSIBLE_PROCEDURES = 20, SQL_CURSOR_COMMIT_BEHAVIOR = 23, SQL_DATA_SOURCE_READ_ONLY = 25, SQL_DEFAULT_TXN_ISOLATION = 26, SQL_IDENTIFIER_CASE = 28, SQL_IDENTIFIER_QUOTE_CHAR = 29, SQL_MAX_COLUMN_NAME_LEN = 30, SQL_MAXIMUM_COLUMN_NAME_LENGTH = SQL_MAX_COLUMN_NAME_LEN, SQL_MAX_CURSOR_NAME_LEN = 31, SQL_MAXIMUM_CURSOR_NAME_LENGTH = SQL_MAX_CURSOR_NAME_LEN, SQL_MAX_SCHEMA_NAME_LEN = 32, SQL_MAXIMUM_SCHEMA_NAME_LENGTH = SQL_MAX_SCHEMA_NAME_LEN, SQL_MAX_CATALOG_NAME_LEN = 34, SQL_MAXIMUM_CATALOG_NAME_LENGTH = SQL_MAX_CATALOG_NAME_LEN, SQL_MAX_TABLE_NAME_LEN = 35, SQL_SCROLL_CONCURRENCY = 43, SQL_TXN_CAPABLE = 46, SQL_TRANSACTION_CAPABLE = SQL_TXN_CAPABLE, SQL_USER_NAME = 47, SQL_TXN_ISOLATION_OPTION = 72, SQL_TRANSACTION_ISOLATION_OPTION = SQL_TXN_ISOLATION_OPTION, SQL_INTEGRITY = 73, SQL_GETDATA_EXTENSIONS = 81, SQL_NULL_COLLATION = 85, SQL_ALTER_TABLE = 86, SQL_ORDER_BY_COLUMNS_IN_SELECT = 90, SQL_SPECIAL_CHARACTERS = 94, SQL_MAX_COLUMNS_IN_GROUP_BY = 97, SQL_MAXIMUM_COLUMNS_IN_GROUP_BY = SQL_MAX_COLUMNS_IN_GROUP_BY, SQL_MAX_COLUMNS_IN_INDEX = 98, SQL_MAXIMUM_COLUMNS_IN_INDEX = SQL_MAX_COLUMNS_IN_INDEX, SQL_MAX_COLUMNS_IN_ORDER_BY = 99, SQL_MAXIMUM_COLUMNS_IN_ORDER_BY = SQL_MAX_COLUMNS_IN_ORDER_BY, SQL_MAX_COLUMNS_IN_SELECT = 100, SQL_MAXIMUM_COLUMNS_IN_SELECT = SQL_MAX_COLUMNS_IN_SELECT, SQL_MAX_COLUMNS_IN_TABLE = 101, SQL_MAX_INDEX_SIZE = 102, SQL_MAXIMUM_INDEX_SIZE = SQL_MAX_INDEX_SIZE, SQL_MAX_ROW_SIZE = 104, SQL_MAXIMUM_ROW_SIZE = SQL_MAX_ROW_SIZE, SQL_MAX_STATEMENT_LEN = 105, SQL_MAXIMUM_STATEMENT_LENGTH = SQL_MAX_STATEMENT_LEN, SQL_MAX_TABLES_IN_SELECT = 106, SQL_MAXIMUM_TABLES_IN_SELECT = SQL_MAX_TABLES_IN_SELECT, SQL_MAX_USER_NAME_LEN = 107, SQL_MAXIMUM_USER_NAME_LENGTH = SQL_MAX_USER_NAME_LEN, SQL_OJ_CAPABILITIES = 115, SQL_OUTER_JOIN_CAPABILITIES = SQL_OJ_CAPABILITIES } enum { SQL_XOPEN_CLI_YEAR = 10000, SQL_CURSOR_SENSITIVITY = 10001, SQL_DESCRIBE_PARAMETER = 10002, SQL_CATALOG_NAME = 10003, SQL_COLLATION_SEQ = 10004, SQL_MAX_IDENTIFIER_LEN = 10005, SQL_MAXIMUM_IDENTIFIER_LENGTH = SQL_MAX_IDENTIFIER_LEN } // * SQL_ALTER_TABLE bitmasks * enum { SQL_AT_ADD_COLUMN = 0x00000001L, SQL_AT_DROP_COLUMN = 0x00000002L, SQL_AT_ADD_CONSTRAINT = 0x00000008L } /+ The following bitmasks are ODBC extensions and defined in sqlext.d enum : ulong { SQL_AT_COLUMN_SINGLE = 0x00000020L, SQL_AT_ADD_COLUMN_DEFAULT = 0x00000040L, SQL_AT_ADD_COLUMN_COLLATION = 0x00000080L, SQL_AT_SET_COLUMN_DEFAULT = 0x00000100L, SQL_AT_DROP_COLUMN_DEFAULT = 0x00000200L, SQL_AT_DROP_COLUMN_CASCADE = 0x00000400L, SQL_AT_DROP_COLUMN_RESTRICT = 0x00000800L, SQL_AT_ADD_TABLE_CONSTRAINT = 0x00001000L, SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE = 0x00002000L, SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT = 0x00004000L, SQL_AT_CONSTRAINT_NAME_DEFINITION = 0x00008000L, SQL_AT_CONSTRAINT_INITIALLY_DEFERRED = 0x00010000L, SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00020000L, SQL_AT_CONSTRAINT_DEFERRABLE = 0x00040000L, SQL_AT_CONSTRAINT_NON_DEFERRABLE = 0x00080000L } +/ // * SQL_ASYNC_MODE values * enum { SQL_AM_NONE = 0, SQL_AM_CONNECTION = 1, SQL_AM_STATEMENT = 2 } // * SQL_CURSOR_COMMIT_BEHAVIOR values * enum { SQL_CB_DELETE = 0, SQL_CB_CLOSE = 1, SQL_CB_PRESERVE = 2 } // * SQL_FETCH_DIRECTION bitmasks * enum { SQL_FD_FETCH_NEXT = 0x00000001L, SQL_FD_FETCH_FIRST = 0x00000002L, SQL_FD_FETCH_LAST = 0x00000004L, SQL_FD_FETCH_PRIOR = 0x00000008L, SQL_FD_FETCH_ABSOLUTE = 0x00000010L, SQL_FD_FETCH_RELATIVE = 0x00000020L } // * SQL_GETDATA_EXTENSIONS bitmasks * enum { SQL_GD_ANY_COLUMN = 0x00000001L, SQL_GD_ANY_ORDER = 0x00000002L } // * SQL_IDENTIFIER_CASE values * enum { SQL_IC_UPPER = 1, SQL_IC_LOWER = 2, SQL_IC_SENSITIVE = 3, SQL_IC_MIXED = 4 } // * SQL_OJ_CAPABILITIES bitmasks * // * OJ means 'outer join' * enum { SQL_OJ_LEFT = 0x00000001L, SQL_OJ_RIGHT = 0x00000002L, SQL_OJ_FULL = 0x00000004L, SQL_OJ_NESTED = 0x00000008L, SQL_OJ_NOT_ORDERED = 0x00000010L, SQL_OJ_INNER = 0x00000020L, SQL_OJ_ALL_COMPARISON_OPS = 0x00000040L } // * SQL_SCROLL_CONCURRENCY bitmasks * enum { SQL_SCCO_READ_ONLY = 0x00000001L, SQL_SCCO_LOCK = 0x00000002L, SQL_SCCO_OPT_ROWVER = 0x00000004L, SQL_SCCO_OPT_VALUES = 0x00000008L } // * SQL_TXN_CAPABLE values * enum { SQL_TC_NONE = 0, SQL_TC_DML = 1, SQL_TC_ALL = 2, SQL_TC_DDL_COMMIT = 3, SQL_TC_DDL_IGNORE = 4 } // * SQL_TXN_ISOLATION_OPTION bitmasks * enum { SQL_TXN_READ_UNCOMMITTED = 0x00000001L, SQL_TRANSACTION_READ_UNCOMMITTED = SQL_TXN_READ_UNCOMMITTED, SQL_TXN_READ_COMMITTED = 0x00000002L, SQL_TRANSACTION_READ_COMMITTED = SQL_TXN_READ_COMMITTED, SQL_TXN_REPEATABLE_READ = 0x00000004L, SQL_TRANSACTION_REPEATABLE_READ = SQL_TXN_REPEATABLE_READ, SQL_TXN_SERIALIZABLE = 0x00000008L, SQL_TRANSACTION_SERIALIZABLE = SQL_TXN_SERIALIZABLE } // * SQL_NULL_COLLATION values * enum { SQL_NC_HIGH = 0, SQL_NC_LOW = 1 } /+ ' ODBC v3.0+ ISO 92 ' Allocates an environment, connection, statement, or descriptor handle. ' ' -- HandleTypes -- ' SQL_HANDLE_ENV ' SQL_HANDLE_DBC ' SQL_HANDLE_DESC ' SQL_HANDLE_STMT ' ' -- InputHandle -- ' The input handle in whose context the new handle is to be allocated. ' If HandleType is SQL_HANDLE_ENV, this is SQL_NULL_HANDLE. If HandleType ' is SQL_HANDLE_DBC, this must be an environment handle, and if it is ' SQL_HANDLE_STMT or SQL_HANDLE_DESC, it must be a connection handle. ' +/ SQLRETURN SQLAllocHandle ( /+ IN +/ SQLSMALLINT HandleType, /+ IN +/ SQLHANDLE InputHandle, /+ OUT +/ SQLHANDLE *OutputHandle ); /+ ' ODBC v1.0+ ISO 92 ' Binds application data buffers to columns in the result set. ' +/ SQLRETURN SQLBindCol ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLUSMALLINT ColumnNumber, /+ IN +/ SQLSMALLINT TargetType, /+ INOUT +/ SQLPOINTER TargetValue, /+ IN +/ SQLINTEGER BufferLength, /+ INOUT +/ SQLINTEGER *StrLen_or_Ind ); SQLRETURN SQLBindParam ( SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType, SQLSMALLINT ParameterType, SQLUINTEGER LengthPrecision, SQLSMALLINT ParameterScale, SQLPOINTER ParameterValue, SQLINTEGER *StrLen_or_Ind ); /+ ' ODBC v1.0+ ISO 92 ' Cancels the processing on a statement. ' +/ SQLRETURN SQLCancel ( /+ IN +/ SQLHSTMT StatementHandle ); /+ ' ODBC v3.0+ ISO 92 ' Closes a cursor that has been opened on a statement and discards pending results. ' +/ SQLRETURN SQLCloseCursor ( SQLHSTMT StatementHandle ); /+ ' ODBC v3.0+ ISO 92 ' Returns descriptor information for a column in a result set. ' Descriptor information is returned as a character string, a 32-bit ' descriptor-dependent value, or an integer value. ' +/ SQLRETURN SQLColAttribute ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLUSMALLINT ColumnNumber, /+ IN +/ SQLUSMALLINT FieldIdentifier, /+ OUT +/ SQLPOINTER CharacterAttribute, /+ IN +/ SQLSMALLINT BufferLength, /+ OUT +/ SQLSMALLINT *StringLength, /+ OUT +/ SQLPOINTER NumericAttribute ); /+ ' ODBC v1.0+ X/Open ' Returns the list of column names in specified tables. The driver ' returns this information as a result set on the specified StatementHandle. ' +/ SQLRETURN SQLColumns ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLCHAR *CatalogName, /+ IN +/ SQLSMALLINT NameLength1, /+ IN +/ SQLCHAR *SchemaName, /+ IN +/ SQLSMALLINT NameLength2, /+ IN +/ SQLCHAR *TableName, /+ IN +/ SQLSMALLINT NameLength3, /+ IN +/ SQLCHAR *ColumnName, /+ IN +/ SQLSMALLINT NameLength4 ); /+ ' ODBC v1.0+ ISO 92 ' Establishes connections to a driver and a data source. The connection ' handle references storage of all information about the connection to ' the data source, including status, transaction state, and error information. ' +/ SQLRETURN SQLConnect ( /+ IN +/ SQLHDBC ConnectionHandle, /+ IN +/ SQLCHAR *ServerName, /+ IN +/ SQLSMALLINT NameLength1, /+ IN +/ SQLCHAR *UserName, /+ IN +/ SQLSMALLINT NameLength2, /+ IN +/ SQLCHAR *Authentication, /+ IN +/ SQLSMALLINT NameLength3 ); /+ ' ODBC v3.0+ ISO 92 ' Copies descriptor information from one descriptor handle to another. ' +/ SQLRETURN SQLCopyDesc ( /+ IN +/ SQLHDESC SourceDescHandle, /+ IN +/ SQLHDESC TargetDescHandle ); /+ ' ODBC v1.0+ ISO 92 ' Returns information about a data source. This function is implemented ' solely by the Driver Manager. ' +/ SQLRETURN SQLDataSources ( /+ IN +/ SQLHENV EnvironmentHandle, /+ IN +/ SQLUSMALLINT Direction, /+ OUT +/ SQLCHAR *ServerName, /+ IN +/ SQLSMALLINT BufferLength1, /+ OUT +/ SQLSMALLINT *NameLength1, /+ OUT +/ SQLCHAR *Description, /+ IN +/ SQLSMALLINT BufferLength2, /+ OUT +/ SQLSMALLINT *NameLength2 ); /+ ' ODBC v1.0+ ISO 92 ' Returns the result descriptor column name, type, column size, ' decimal digits, and nullability for one column in the result set. ' This information also is available in the fields of the IRD. ' +/ SQLRETURN SQLDescribeCol ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLUSMALLINT ColumnNumber, /+ OUT +/ SQLCHAR *ColumnName, /+ IN +/ SQLSMALLINT BufferLength, /+ OUT +/ SQLSMALLINT *NameLength, /+ OUT +/ SQLSMALLINT *DataType, /+ OUT +/ SQLUINTEGER *ColumnSize, /+ OUT +/ SQLSMALLINT *DecimalDigits, /+ OUT +/ SQLSMALLINT *Nullable ); /+ ' ODBC v1.0+ ISO 92 ' Closes the connection associated with a specific connection handle. ' +/ SQLRETURN SQLDisconnect ( /+ IN +/ SQLHDBC ConnectionHandle ); /+ ' ODBC v3.0+ ISO 92 ' Requests a commit or rollback operation for all active operations on all ' statements associated with a connection. SQLEndTran can also request that ' a commit or rollback operation be performed for all connections associated ' with an environment. ' ' -- HandleType -- ' Contains either SQL_HANDLE_ENV (if Handle is an environment handle) ' or SQL_HANDLE_DBC (if Handle is a connection handle). ' ' -- Handle -- ' The handle, of the type indicated by HandleType, indicating the scope of the transaction. ' ' -- CompletionType -- ' One of the following two values: ' SQL_COMMIT ' SQL_ROLLBACK ' +/ SQLRETURN SQLEndTran ( /+ IN +/ SQLSMALLINT HandleType, /+ IN +/ SQLHANDLE Handle, /+ IN +/ SQLSMALLINT CompletionType ); /+ ' ODBC v1.0+ ISO 92 ' Executes a preparable statement, using the current values of the ' parameter marker variables if any parameters exist in the statement. ' SQLExecDirect is the fastest way to submit an SQL statement for ' one-time execution. ' +/ SQLRETURN SQLExecDirect ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLCHAR *StatementText, /+ IN +/ SQLINTEGER TextLength ); /+ ' ODBC v1.0+ ISO 92 ' Executes a prepared statement, using the current values of the parameter ' marker variables if any parameter markers exist in the statement. ' +/ SQLRETURN SQLExecute ( /+ IN +/ SQLHSTMT StatementHandle ); /+ ' ODBC v1.0+ ISO 92 ' Fetches the next rowset of data from the result set and returns ' data for all bound columns. ' +/ SQLRETURN SQLFetch ( /+ IN +/ SQLHSTMT StatementHandle ); /+ ' ODBC v3.0+ ISO 92 ' Fetches the specified rowset of data from the result set and ' returns data for all bound columns. Rowsets can be specified ' at an absolute or relative position or by bookmark. ' ' -- FetchOrientation -- ' Type of fetch: ' SQL_FETCH_NEXT ' SQL_FETCH_PRIOR ' SQL_FETCH_FIRST ' SQL_FETCH_LAST ' SQL_FETCH_ABSOLUTE ' SQL_FETCH_RELATIVE ' SQL_FETCH_BOOKMARK ' ' -- FetchOffset -- ' Number of the row to fetch based on the type above. ' +/ SQLRETURN SQLFetchScroll ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLSMALLINT FetchOrientation, /+ IN +/ SQLINTEGER FetchOffset ); /+ ' ODBC v3.0+ ISO 92 ' Frees resources associated with a specific environment, connection, ' statement, or descriptor handle. ' ' -- HandleType -- ' Must be one of the following values: ' SQL_HANDLE_ENV ' SQL_HANDLE_DBC ' SQL_HANDLE_STMT ' SQL_HANDLE_DESC ' +/ SQLRETURN SQLFreeHandle ( /+ IN +/ SQLSMALLINT HandleType, /+ IN +/ SQLHANDLE Handle ); /+ ' ODBC v1.0+ ISO 92 ' Stops processing associated with a specific statement, ' closes any open cursors associated with the statement, ' discards pending results, or, optionally, frees all ' resources associated with the statement handle. ' +/ SQLRETURN SQLFreeStmt ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLUSMALLINT Option ); /+ ' ODBC v3.0+ ISO 92 ' Returns the current setting of a connection attribute. ' +/ SQLRETURN SQLGetConnectAttr ( /+ IN +/ SQLHDBC ConnectionHandle, /+ IN +/ SQLINTEGER Attribute, /+ OUT +/ SQLPOINTER Value, /+ IN +/ SQLINTEGER BufferLength, /+ OUT +/ SQLINTEGER *StringLength ); /+ ' ODBC v1.+ ISO 92 ' Returns the cursor name associated with a specified statement. ' +/ SQLRETURN SQLGetCursorName ( /+ IN +/ SQLHSTMT StatementHandle, /+ OUT +/ SQLCHAR *CursorName, /+ IN +/ SQLSMALLINT BufferLength, /+ OUT +/ SQLSMALLINT *NameLength ); /+ ' ODBC v1.0+ ISO 92 ' Retrieves data for a single column in the result set. It can be called ' multiple times to retrieve variable-length data in parts. ' +/ SQLRETURN SQLGetData ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLUSMALLINT ColumnNumber, /+ IN +/ SQLSMALLINT TargetType, /+ OUT +/ SQLPOINTER TargetValue, /+ IN +/ SQLINTEGER BufferLength, /+ OUT +/ SQLINTEGER *StrLen_or_Ind ); /+ ' ODBC v3.0+ ISO 92 ' Returns the current setting or value of a single field of a descriptor record. ' +/ SQLRETURN SQLGetDescField ( /+ IN +/ SQLHDESC DescriptorHandle, /+ IN +/ SQLSMALLINT RecNumber, /+ IN +/ SQLSMALLINT FieldIdentifier, /+ OUT +/ SQLPOINTER Value, /+ IN +/ SQLINTEGER BufferLength, /+ OUT +/ SQLINTEGER *StringLength ); /+ ' ODBC v3.0+ ISO 92 ' Returns the current settings or values of multiple fields of a descriptor ' record. The fields returned describe the name, data type, and storage of ' column or parameter data. ' +/ SQLRETURN SQLGetDescRec ( /+ IN +/ SQLHDESC DescriptorHandle, /+ IN +/ SQLSMALLINT RecNumber, /+ OUT +/ SQLCHAR *Name, // SQLGetDescField( DescriptorHandle = SQL_DESC_NAME ) /+ IN +/ SQLSMALLINT BufferLength, /+ OUT +/ SQLSMALLINT *StringLength, /+ OUT +/ SQLSMALLINT *Type, // SQLGetDescField( DescriptorHandle = SQL_DESC_TYPE ) /+ OUT +/ SQLSMALLINT *SubType, // SQLGetDescField( DescriptorHandle = SQL_DESC_DATETIME_INTERVAL_CODE ) /+ OUT +/ SQLINTEGER *Length, // SQLGetDescField( DescriptorHandle = SQL_DESC_OCTET_LENGTH ) /+ OUT +/ SQLSMALLINT *Precision, // SQLGetDescField( DescriptorHandle = SQL_DESC_PRECISION ) /+ OUT +/ SQLSMALLINT *Scale, // SQLGetDescField( DescriptorHandle = SQL_DESC_SCALE ) /+ OUT +/ SQLSMALLINT *Nullable // SQLGetDescField( DescriptorHandle = SQL_DESC_NULLABLE ) ); /+ ' ODBC v3.0+ ISO 92 ' Returns the current value of a field of a record of the diagnostic ' data structure (associated with a specified handle) that contains ' error, warning, and status information. ' ' -- HandleType -- ' Must be one of the following: ' SQL_HANDLE_ENV ' SQL_HANDLE_DBC ' SQL_HANDLE_STMT ' SQL_HANDLE_DESC ' +/ SQLRETURN SQLGetDiagField ( /+ IN +/ SQLSMALLINT HandleType, /+ IN +/ SQLHANDLE Handle, /+ IN +/ SQLSMALLINT RecNumber, /+ IN +/ SQLSMALLINT DiagIdentifier, /+ OUT +/ SQLPOINTER DiagInfo, /+ IN +/ SQLSMALLINT BufferLength, /+ OUT +/ SQLSMALLINT *StringLength ); /+ ' ODBC v3.0+ ISO 92 ' Returns the current values of multiple fields of a diagnostic record that ' contains error, warning, and status information. Unlike SQLGetDiagField, ' which returns one diagnostic field per call, SQLGetDiagRec returns several ' commonly used fields of a diagnostic record, including the SQLSTATE, the ' native error code, and the diagnostic message text. ' ' -- HandleType -- ' Must be one of the following: ' SQL_HANDLE_ENV ' SQL_HANDLE_DBC ' SQL_HANDLE_STMT ' SQL_HANDLE_DESC ' +/ SQLRETURN SQLGetDiagRec ( /+ IN +/ SQLSMALLINT HandleType, /+ IN +/ SQLHANDLE Handle, /+ IN +/ SQLSMALLINT RecNumber, /+ OUT +/ SQLCHAR *Sqlstate, /+ OUT +/ SQLINTEGER *NativeError, /+ OUT +/ SQLCHAR *MessageText, /+ IN +/ SQLSMALLINT BufferLength, /+ OUT +/ SQLSMALLINT *TextLength ); /+ ' ODBC v3.0+ ISO 92 ' Returns the current setting of an environment attribute. ' +/ SQLRETURN SQLGetEnvAttr ( /+ IN +/ SQLHENV EnvironmentHandle, /+ IN +/ SQLINTEGER Attribute, /+ OUT +/ SQLPOINTER Value, /+ IN +/ SQLINTEGER BufferLength, /+ OUT +/ SQLINTEGER *StringLength ); /+ ' ODBC v1.0+ ISO 92 ' returns information about whether a driver supports a specific ODBC ' function. This function is implemented in the Driver Manager; it can ' also be implemented in drivers. If a driver implements SQLGetFunctions, ' the Driver Manager calls the function in the driver. Otherwise, ' it executes the function itself. ' +/ SQLRETURN SQLGetFunctions ( /+ IN +/ SQLHDBC ConnectionHandle, /+ IN +/ SQLUSMALLINT FunctionId, /+ OUT +/ SQLUSMALLINT *Supported ); /+ ' ODBC v1.0+ ISO 92 ' Returns general information about the driver and data ' source associated with a connection. ' +/ SQLRETURN SQLGetInfo ( /+ IN +/ SQLHDBC ConnectionHandle, /+ IN +/ SQLUSMALLINT InfoType, /+ OUT +/ SQLPOINTER InfoValue, /+ IN +/ SQLSMALLINT BufferLength, /+ OUT +/ SQLSMALLINT *StringLength ); /+ ' ODBC v3.0+ ISO 92 ' Returns the current setting of a statement attribute. ' +/ SQLRETURN SQLGetStmtAttr ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLINTEGER Attribute, /+ OUT +/ SQLPOINTER Value, /+ IN +/ SQLINTEGER BufferLength, /+ OUT +/ SQLINTEGER *StringLength ); /+ ' ODBC v1.0+ ISO 92 ' Returns information about data types supported by the data source. ' The driver returns the information in the form of an SQL result set. ' The data types are intended for use in Data Definition Language (DDL) statements. ' +/ SQLRETURN SQLGetTypeInfo ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLSMALLINT DataType ); /+ ' ODBC v1.0+ ISO 92 ' Returns the number of columns in a result set. ' +/ SQLRETURN SQLNumResultCols ( /+ IN +/ SQLHSTMT StatementHandle, /+ OUT +/ SQLSMALLINT *ColumnCount ); /+ ' ODBC v1.0+ ISO 92 ' Is used in conjunction with SQLPutData to supply parameter data at statement execution time. ' +/ SQLRETURN SQLParamData ( /+ IN +/ SQLHSTMT StatementHandle, /+ OUT +/ SQLPOINTER *Value ); /+ ' ODBC v1.0+ ISO 92 ' Prepares an SQL string for execution. ' +/ SQLRETURN SQLPrepare ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLCHAR *StatementText, /+ IN +/ SQLINTEGER TextLength ); /+ ' ODBC v1.0+ ISO 92 ' Allows an application to send data for a parameter or column to the driver ' at statement execution time. This function can be used to send character or ' binary data values in parts to a column with a character, binary, or data ' source specific data type (for example, parameters of the SQL_LONGVARBINARY ' or SQL_LONGVARCHAR types). SQLPutData supports binding to a Unicode C data ' type, even if the underlying driver does not support Unicode data. ' +/ SQLRETURN SQLPutData ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLPOINTER Data, /+ IN +/ SQLINTEGER StrLen_or_Ind ); /+ ' ODBC v1.+ ISO 92 ' Returns the number of rows affected by an UPDATE, INSERT, or DELETE statement; ' an SQL_ADD, SQL_UPDATE_BY_BOOKMARK, or SQL_DELETE_BY_BOOKMARK operation in ' SQLBulkOperations; or an SQL_UPDATE or SQL_DELETE operation in SQLSetPos. ' +/ SQLRETURN SQLRowCount ( /+ IN +/ SQLHSTMT StatementHandle, /+ OUT +/ SQLINTEGER *RowCount ); /+ ' ODBC v3.0+ ISO 92 ' Sets attributes that govern aspects of connections. ' +/ SQLRETURN SQLSetConnectAttr ( /+ IN +/ SQLHDBC ConnectionHandle, /+ IN +/ SQLINTEGER Attribute, /+ IN +/ SQLPOINTER Value, /+ IN +/ SQLINTEGER StringLength ); /+ ' ODBC v1.0+ ISO 92 ' Associates a cursor name with an active statement. If an application ' does not call SQLSetCursorName, the driver generates cursor names as ' needed for SQL statement processing. ' +/ SQLRETURN SQLSetCursorName ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLCHAR *CursorName, /+ IN +/ SQLSMALLINT NameLength ); /+ ' ODBC v3.0+ ISO 92 ' Sets the value of a single field of a descriptor record. ' +/ SQLRETURN SQLSetDescField ( /+ IN +/ SQLHDESC DescriptorHandle, /+ IN +/ SQLSMALLINT RecNumber, /+ IN +/ SQLSMALLINT FieldIdentifier, /+ IN +/ SQLPOINTER Value, /+ IN +/ SQLINTEGER BufferLength ); /+ ' ODBC v3.0+ ISO 92 ' Function sets multiple descriptor fields that affect the data ' type and buffer bound to a column or parameter data. ' +/ SQLRETURN SQLSetDescRec ( /+ IN +/ SQLHDESC DescriptorHandle, /+ IN +/ SQLSMALLINT RecNumber, /+ IN +/ SQLSMALLINT Type, /+ IN +/ SQLSMALLINT SubType, /+ IN +/ SQLINTEGER Length, /+ IN +/ SQLSMALLINT Precision, /+ IN +/ SQLSMALLINT Scale, /+ INOUT +/ SQLPOINTER Data, /+ INOUT +/ SQLINTEGER *StringLength, /+ INOUT +/ SQLINTEGER *Indicator ); /+ ' ODBC v3.0+ ISO 92 ' Sets attributes that govern aspects of environments. ' +/ SQLRETURN SQLSetEnvAttr ( /+ IN +/ SQLHENV EnvironmentHandle, /+ IN +/ SQLINTEGER Attribute, /+ IN +/ SQLPOINTER Value, /+ IN +/ SQLINTEGER StringLength ); /+ ' ODBC v3.0+ ISO 92 ' Sets attributes related to a statement. ' +/ SQLRETURN SQLSetStmtAttr ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLINTEGER Attribute, /+ IN +/ SQLPOINTER Value, /+ IN +/ SQLINTEGER StringLength ); /+ ' ODBC v1.0+ X/Open ' Retrieves the following information about columns within a specified table: ' ' 1) The optimal set of columns that uniquely identifies a row in the table. ' 2) Columns that are automatically updated when any value in the row is updated by a transaction. ' ' +/ SQLRETURN SQLSpecialColumns ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLUSMALLINT IdentifierType, /+ IN +/ SQLCHAR *CatalogName, /+ IN +/ SQLSMALLINT NameLength1, /+ IN +/ SQLCHAR *SchemaName, /+ IN +/ SQLSMALLINT NameLength2, /+ IN +/ SQLCHAR *TableName, /+ IN +/ SQLSMALLINT NameLength3, /+ IN +/ SQLUSMALLINT Scope, /+ IN +/ SQLUSMALLINT Nullable ); /+ ' ODBC v1.0+ ISO 92 ' Retrieves a list of statistics about a single table and the ' indexes associated with the table. The driver returns the ' information as a result set. ' ' -- Unique -- ' Type of index: SQL_INDEX_UNIQUE or SQL_INDEX_ALL. ' +/ SQLRETURN SQLStatistics ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLCHAR *CatalogName, /+ IN +/ SQLSMALLINT NameLength1, /+ IN +/ SQLCHAR *SchemaName, /+ IN +/ SQLSMALLINT NameLength2, /+ IN +/ SQLCHAR *TableName, /+ IN +/ SQLSMALLINT NameLength3, /+ IN +/ SQLUSMALLINT Unique, /+ IN +/ SQLUSMALLINT Reserved ); /+ ' OBDC v1.0+ X/Open ' Returns the list of table, catalog, or schema names, and table ' types, stored in a specific data source. The driver returns the ' information as a result set. ' +/ SQLRETURN SQLTables ( /+ IN +/ SQLHSTMT StatementHandle, /+ IN +/ SQLCHAR *CatalogName, /+ IN +/ SQLSMALLINT NameLength1, /+ IN +/ SQLCHAR *SchemaName, /+ IN +/ SQLSMALLINT NameLength2, /+ IN +/ SQLCHAR *TableName, /+ IN +/ SQLSMALLINT NameLength3, /+ IN +/ SQLCHAR *TableType, /+ IN +/ SQLSMALLINT NameLength4 ); /+---------------------------+ | * Deprecated Functions * | +---------------------------+/ /+ ' In ODBC 3.x, the ODBC 2.x function SQLAllocConnect has been ' replaced by SQLAllocHandle. ' +/ SQLRETURN SQLAllocConnect ( SQLHENV EnvironmentHandle, SQLHDBC *ConnectionHandle ); /+ ' In ODBC 3.x, the ODBC 2.x function SQLAllocEnv has been replaced by SQLAllocHandle. ' +/ SQLRETURN SQLAllocEnv ( SQLHENV *EnvironmentHandle ); /+ ' In ODBC 3.x, the ODBC 2.x function SQLAllocStmt has been replaced by SQLAllocHandle. ' +/ SQLRETURN SQLAllocStmt ( SQLHDBC ConnectionHandle, SQLHSTMT *StatementHandle ); SQLRETURN SQLError ( SQLHENV EnvironmentHandle, SQLHDBC ConnectionHandle, SQLHSTMT StatementHandle, SQLCHAR *Sqlstate, SQLINTEGER *NativeError, SQLCHAR *MessageText, SQLSMALLINT BufferLength, SQLSMALLINT *TextLength ); SQLRETURN SQLFreeConnect ( SQLHDBC ConnectionHandle ); SQLRETURN SQLFreeEnv ( SQLHENV EnvironmentHandle ); SQLRETURN SQLGetConnectOption ( SQLHDBC ConnectionHandle, SQLUSMALLINT Option, SQLPOINTER Value ); SQLRETURN SQLGetStmtOption ( SQLHSTMT StatementHandle, SQLUSMALLINT Option, SQLPOINTER Value ); SQLRETURN SQLSetConnectOption ( SQLHDBC ConnectionHandle, SQLUSMALLINT Option, SQLUINTEGER Value ); SQLRETURN SQLSetParam ( SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType, SQLSMALLINT ParameterType, SQLUINTEGER LengthPrecision, SQLSMALLINT ParameterScale, SQLPOINTER ParameterValue, SQLINTEGER *StrLen_or_Ind ); SQLRETURN SQLSetStmtOption ( SQLHSTMT StatementHandle, SQLUSMALLINT Option, SQLUINTEGER Value ); SQLRETURN SQLTransact ( SQLHENV EnvironmentHandle, SQLHDBC ConnectionHandle, SQLUSMALLINT CompletionType ); // end Deprecated Functions ldc-1.1.0-beta3-src/runtime/phobos/etc/c/curl.d0000664000175000017500000024150212776215007017227 0ustar kaikai/** This is an interface to the libcurl library. Converted to D from curl headers by $(LINK2 http://www.digitalmars.com/d/2.0/htod.html, htod) and cleaned up by Jonas Drewsen (jdrewsen) Windows x86 note: A DMD compatible libcurl static library can be downloaded from the dlang.org $(LINK2 http://dlang.org/download.html, download page). */ /* ************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| */ /** * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at $(LINK http://curl.haxx.se/docs/copyright.html). * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ module etc.c.curl; import core.stdc.time; import core.stdc.config; import std.socket; // linux import core.sys.posix.sys.socket; // // LICENSE FROM CURL HEADERS // /** This is the global package copyright */ enum LIBCURL_COPYRIGHT = "1996 - 2010 Daniel Stenberg, ."; /** This is the version number of the libcurl package from which this header file origins: */ enum LIBCURL_VERSION = "7.21.4"; /** The numeric version number is also available "in parts" by using these constants */ enum LIBCURL_VERSION_MAJOR = 7; /// ditto enum LIBCURL_VERSION_MINOR = 21; /// ditto enum LIBCURL_VERSION_PATCH = 4; /** This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will always follow this syntax: 0xXXYYZZ Where XX, YY and ZZ are the main version, release and patch numbers in hexadecimal (using 8 bits each). All three numbers are always represented using two digits. 1.2 would appear as "0x010200" while version 9.11.7 appears as "0x090b07". This 6-digit (24 bits) hexadecimal number does not show pre-release number, and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. */ enum LIBCURL_VERSION_NUM = 0x071504; /** * This is the date and time when the full source package was created. The * timestamp is not stored in git, as the timestamp is properly set in the * tarballs by the maketgz script. * * The format of the date should follow this template: * * "Mon Feb 12 11:35:33 UTC 2007" */ enum LIBCURL_TIMESTAMP = "Thu Feb 17 12:19:40 UTC 2011"; /** Data type definition of curl_off_t. * * jdrewsen - Always 64bit signed and that is what long is in D. * * Comment below is from curlbuild.h: * * NOTE 2: * * For any given platform/compiler curl_off_t must be typedef'ed to a * 64-bit wide signed integral data type. The width of this data type * must remain constant and independent of any possible large file * support settings. * * As an exception to the above, curl_off_t shall be typedef'ed to a * 32-bit wide signed integral data type if there is no 64-bit type. */ alias long curl_off_t; /// alias void CURL; /// jdrewsen - Get socket alias from std.socket alias socket_t curl_socket_t; /// jdrewsen - Would like to get socket error constant from std.socket by it is private atm. version(Windows) { private import core.sys.windows.windows, core.sys.windows.winsock2; enum CURL_SOCKET_BAD = SOCKET_ERROR; } version(Posix) enum CURL_SOCKET_BAD = -1; /// extern (C) struct curl_httppost { curl_httppost *next; /** next entry in the list */ char *name; /** pointer to allocated name */ c_long namelength; /** length of name length */ char *contents; /** pointer to allocated data contents */ c_long contentslength; /** length of contents field */ char *buffer; /** pointer to allocated buffer contents */ c_long bufferlength; /** length of buffer field */ char *contenttype; /** Content-Type */ curl_slist *contentheader; /** list of extra headers for this form */ curl_httppost *more; /** if one field name has more than one file, this link should link to following files */ c_long flags; /** as defined below */ char *showfilename; /** The file name to show. If not set, the actual file name will be used (if this is a file part) */ void *userp; /** custom pointer used for HTTPPOST_CALLBACK posts */ } enum HTTPPOST_FILENAME = 1; /** specified content is a file name */ enum HTTPPOST_READFILE = 2; /** specified content is a file name */ enum HTTPPOST_PTRNAME = 4; /** name is only stored pointer do not free in formfree */ enum HTTPPOST_PTRCONTENTS = 8; /** contents is only stored pointer do not free in formfree */ enum HTTPPOST_BUFFER = 16; /** upload file from buffer */ enum HTTPPOST_PTRBUFFER = 32; /** upload file from pointer contents */ enum HTTPPOST_CALLBACK = 64; /** upload file contents by using the regular read callback to get the data and pass the given pointer as custom pointer */ /// alias int function(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) curl_progress_callback; /** Tests have proven that 20K is a very bad buffer size for uploads on Windows, while 16K for some odd reason performed a lot better. We do the ifndef check to allow this value to easier be changed at build time for those who feel adventurous. The practical minimum is about 400 bytes since libcurl uses a buffer of this size as a scratch area (unrelated to network send operations). */ enum CURL_MAX_WRITE_SIZE = 16384; /** The only reason to have a max limit for this is to avoid the risk of a bad server feeding libcurl with a never-ending header that will cause reallocs infinitely */ enum CURL_MAX_HTTP_HEADER = (100*1024); /** This is a magic return code for the write callback that, when returned, will signal libcurl to pause receiving on the current transfer. */ enum CURL_WRITEFUNC_PAUSE = 0x10000001; /// alias size_t function(char *buffer, size_t size, size_t nitems, void *outstream)curl_write_callback; /** enumeration of file types */ enum CurlFileType { file, /// directory, /// symlink, /// device_block, /// device_char, /// namedpipe, /// socket, /// door, /// unknown /** is possible only on Sun Solaris now */ } /// alias int curlfiletype; /// enum CurlFInfoFlagKnown { filename = 1, /// filetype = 2, /// time = 4, /// perm = 8, /// uid = 16, /// gid = 32, /// size = 64, /// hlinkcount = 128 /// } /** Content of this structure depends on information which is known and is achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man page for callbacks returning this structure -- some fields are mandatory, some others are optional. The FLAG field has special meaning. */ /** If some of these fields is not NULL, it is a pointer to b_data. */ extern (C) struct _N2 { char *time; /// char *perm; /// char *user; /// char *group; /// char *target; /** pointer to the target filename of a symlink */ } /** Content of this structure depends on information which is known and is achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man page for callbacks returning this structure -- some fields are mandatory, some others are optional. The FLAG field has special meaning. */ extern (C) struct curl_fileinfo { char *filename; /// curlfiletype filetype; /// time_t time; /// uint perm; /// int uid; /// int gid; /// curl_off_t size; /// c_long hardlinks; /// _N2 strings; /// uint flags; /// char *b_data; /// size_t b_size; /// size_t b_used; /// } /** return codes for CURLOPT_CHUNK_BGN_FUNCTION */ enum CurlChunkBgnFunc { ok = 0, /// fail = 1, /** tell the lib to end the task */ skip = 2 /** skip this chunk over */ } /** if splitting of data transfer is enabled, this callback is called before download of an individual chunk started. Note that parameter "remains" works only for FTP wildcard downloading (for now), otherwise is not used */ alias c_long function(void *transfer_info, void *ptr, int remains)curl_chunk_bgn_callback; /** return codes for CURLOPT_CHUNK_END_FUNCTION */ enum CurlChunkEndFunc { ok = 0, /// fail = 1, /// } /** If splitting of data transfer is enabled this callback is called after download of an individual chunk finished. Note! After this callback was set then it have to be called FOR ALL chunks. Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. This is the reason why we don't need "transfer_info" parameter in this callback and we are not interested in "remains" parameter too. */ alias c_long function(void *ptr)curl_chunk_end_callback; /** return codes for FNMATCHFUNCTION */ enum CurlFnMAtchFunc { match = 0, /// nomatch = 1, /// fail = 2 /// } /** callback type for wildcard downloading pattern matching. If the string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ alias int function(void *ptr, in char *pattern, in char *string)curl_fnmatch_callback; /// seek whence... enum CurlSeekPos { set, /// current, /// end /// } /** These are the return codes for the seek callbacks */ enum CurlSeek { ok, /// fail, /** fail the entire transfer */ cantseek /** tell libcurl seeking can't be done, so libcurl might try other means instead */ } /// alias int function(void *instream, curl_off_t offset, int origin)curl_seek_callback; /// enum CurlReadFunc { /** This is a return code for the read callback that, when returned, will signal libcurl to immediately abort the current transfer. */ abort = 0x10000000, /** This is a return code for the read callback that, when returned, will const signal libcurl to pause sending data on the current transfer. */ pause = 0x10000001 } /// alias size_t function(char *buffer, size_t size, size_t nitems, void *instream)curl_read_callback; /// enum CurlSockType { ipcxn, /** socket created for a specific IP connection */ last /** never use */ } /// alias int curlsocktype; /// alias int function(void *clientp, curl_socket_t curlfd, curlsocktype purpose)curl_sockopt_callback; /** addrlen was a socklen_t type before 7.18.0 but it turned really ugly and painful on the systems that lack this type */ extern (C) struct curl_sockaddr { int family; /// int socktype; /// int protocol; /// uint addrlen; /** addrlen was a socklen_t type before 7.18.0 but it turned really ugly and painful on the systems that lack this type */ sockaddr addr; /// } /// alias curl_socket_t function(void *clientp, curlsocktype purpose, curl_sockaddr *address)curl_opensocket_callback; /// enum CurlIoError { ok, /** I/O operation successful */ unknowncmd, /** command was unknown to callback */ failrestart, /** failed to restart the read */ last /** never use */ } /// alias int curlioerr; /// enum CurlIoCmd { nop, /** command was unknown to callback */ restartread, /** failed to restart the read */ last, /** never use */ } /// alias int curliocmd; /// alias curlioerr function(CURL *handle, int cmd, void *clientp)curl_ioctl_callback; /** * The following typedef's are signatures of malloc, free, realloc, strdup and * calloc respectively. Function pointers of these types can be passed to the * curl_global_init_mem() function to set user defined memory management * callback routines. */ alias void * function(size_t size)curl_malloc_callback; /// ditto alias void function(void *ptr)curl_free_callback; /// ditto alias void * function(void *ptr, size_t size)curl_realloc_callback; /// ditto alias char * function(in char *str)curl_strdup_callback; /// ditto alias void * function(size_t nmemb, size_t size)curl_calloc_callback; /** the kind of data that is passed to information_callback*/ enum CurlCallbackInfo { text, /// header_in, /// header_out, /// data_in, /// data_out, /// ssl_data_in, /// ssl_data_out, /// end /// } /// alias int curl_infotype; /// alias int function(CURL *handle, /** the handle/transfer this concerns */ curl_infotype type, /** what kind of data */ char *data, /** points to the data */ size_t size, /** size of the data pointed to */ void *userptr /** whatever the user please */ )curl_debug_callback; /** All possible error codes from all sorts of curl functions. Future versions may return other values, stay prepared. Always add new return codes last. Never *EVER* remove any. The return codes must remain the same! */ enum CurlError { ok, /// unsupported_protocol, /** 1 */ failed_init, /** 2 */ url_malformat, /** 3 */ not_built_in, /** 4 - [was obsoleted in August 2007 for 7.17.0, reused in April 2011 for 7.21.5] */ couldnt_resolve_proxy, /** 5 */ couldnt_resolve_host, /** 6 */ couldnt_connect, /** 7 */ ftp_weird_server_reply, /** 8 */ remote_access_denied, /** 9 a service was denied by the server due to lack of access - when login fails this is not returned. */ obsolete10, /** 10 - NOT USED */ ftp_weird_pass_reply, /** 11 */ obsolete12, /** 12 - NOT USED */ ftp_weird_pasv_reply, /** 13 */ ftp_weird_227_format, /** 14 */ ftp_cant_get_host, /** 15 */ obsolete16, /** 16 - NOT USED */ ftp_couldnt_set_type, /** 17 */ partial_file, /** 18 */ ftp_couldnt_retr_file, /** 19 */ obsolete20, /** 20 - NOT USED */ quote_error, /** 21 - quote command failure */ http_returned_error, /** 22 */ write_error, /** 23 */ obsolete24, /** 24 - NOT USED */ upload_failed, /** 25 - failed upload "command" */ read_error, /** 26 - couldn't open/read from file */ out_of_memory, /** 27 */ /** Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error instead of a memory allocation error if CURL_DOES_CONVERSIONS is defined */ operation_timedout, /** 28 - the timeout time was reached */ obsolete29, /** 29 - NOT USED */ ftp_port_failed, /** 30 - FTP PORT operation failed */ ftp_couldnt_use_rest, /** 31 - the REST command failed */ obsolete32, /** 32 - NOT USED */ range_error, /** 33 - RANGE "command" didn't work */ http_post_error, /** 34 */ ssl_connect_error, /** 35 - wrong when connecting with SSL */ bad_download_resume, /** 36 - couldn't resume download */ file_couldnt_read_file, /** 37 */ ldap_cannot_bind, /** 38 */ ldap_search_failed, /** 39 */ obsolete40, /** 40 - NOT USED */ function_not_found, /** 41 */ aborted_by_callback, /** 42 */ bad_function_argument, /** 43 */ obsolete44, /** 44 - NOT USED */ interface_failed, /** 45 - CURLOPT_INTERFACE failed */ obsolete46, /** 46 - NOT USED */ too_many_redirects, /** 47 - catch endless re-direct loops */ unknown_option, /** 48 - User specified an unknown option */ telnet_option_syntax, /** 49 - Malformed telnet option */ obsolete50, /** 50 - NOT USED */ peer_failed_verification, /** 51 - peer's certificate or fingerprint wasn't verified fine */ got_nothing, /** 52 - when this is a specific error */ ssl_engine_notfound, /** 53 - SSL crypto engine not found */ ssl_engine_setfailed, /** 54 - can not set SSL crypto engine as default */ send_error, /** 55 - failed sending network data */ recv_error, /** 56 - failure in receiving network data */ obsolete57, /** 57 - NOT IN USE */ ssl_certproblem, /** 58 - problem with the local certificate */ ssl_cipher, /** 59 - couldn't use specified cipher */ ssl_cacert, /** 60 - problem with the CA cert (path?) */ bad_content_encoding, /** 61 - Unrecognized transfer encoding */ ldap_invalid_url, /** 62 - Invalid LDAP URL */ filesize_exceeded, /** 63 - Maximum file size exceeded */ use_ssl_failed, /** 64 - Requested FTP SSL level failed */ send_fail_rewind, /** 65 - Sending the data requires a rewind that failed */ ssl_engine_initfailed, /** 66 - failed to initialise ENGINE */ login_denied, /** 67 - user, password or similar was not accepted and we failed to login */ tftp_notfound, /** 68 - file not found on server */ tftp_perm, /** 69 - permission problem on server */ remote_disk_full, /** 70 - out of disk space on server */ tftp_illegal, /** 71 - Illegal TFTP operation */ tftp_unknownid, /** 72 - Unknown transfer ID */ remote_file_exists, /** 73 - File already exists */ tftp_nosuchuser, /** 74 - No such user */ conv_failed, /** 75 - conversion failed */ conv_reqd, /** 76 - caller must register conversion callbacks using curl_easy_setopt options CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPT_CONV_TO_NETWORK_FUNCTION, and CURLOPT_CONV_FROM_UTF8_FUNCTION */ ssl_cacert_badfile, /** 77 - could not load CACERT file, missing or wrong format */ remote_file_not_found, /** 78 - remote file not found */ ssh, /** 79 - error from the SSH layer, somewhat generic so the error message will be of interest when this has happened */ ssl_shutdown_failed, /** 80 - Failed to shut down the SSL connection */ again, /** 81 - socket is not ready for send/recv, wait till it's ready and try again (Added in 7.18.2) */ ssl_crl_badfile, /** 82 - could not load CRL file, missing or wrong format (Added in 7.19.0) */ ssl_issuer_error, /** 83 - Issuer check failed. (Added in 7.19.0) */ ftp_pret_failed, /** 84 - a PRET command failed */ rtsp_cseq_error, /** 85 - mismatch of RTSP CSeq numbers */ rtsp_session_error, /** 86 - mismatch of RTSP Session Identifiers */ ftp_bad_file_list, /** 87 - unable to parse FTP file list */ chunk_failed, /** 88 - chunk callback reported error */ curl_last /** never use! */ } /// alias int CURLcode; /** This prototype applies to all conversion callbacks */ alias CURLcode function(char *buffer, size_t length)curl_conv_callback; /** actually an OpenSSL SSL_CTX */ alias CURLcode function(CURL *curl, /** easy handle */ void *ssl_ctx, /** actually an OpenSSL SSL_CTX */ void *userptr )curl_ssl_ctx_callback; /// enum CurlProxy { http, /** added in 7.10, new in 7.19.4 default is to use CONNECT HTTP/1.1 */ http_1_0, /** added in 7.19.4, force to use CONNECT HTTP/1.0 */ socks4 = 4, /** support added in 7.15.2, enum existed already in 7.10 */ socks5 = 5, /** added in 7.10 */ socks4a = 6, /** added in 7.18.0 */ socks5_hostname =7 /** Use the SOCKS5 protocol but pass along the host name rather than the IP address. added in 7.18.0 */ } /// alias int curl_proxytype; /// enum CurlAuth : long { none = 0, basic = 1, /** Basic (default) */ digest = 2, /** Digest */ gssnegotiate = 4, /** GSS-Negotiate */ ntlm = 8, /** NTLM */ digest_ie = 16, /** Digest with IE flavour */ only = 2147483648, /** used together with a single other type to force no auth or just that single type */ any = -17, /* (~CURLAUTH_DIGEST_IE) */ /** all fine types set */ anysafe = -18 /* (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) */ /// } /// enum CurlSshAuth { any = -1, /** all types supported by the server */ none = 0, /** none allowed, silly but complete */ publickey = 1, /** public/private key files */ password = 2, /** password */ host = 4, /** host key files */ keyboard = 8, /** keyboard interactive */ default_ = -1 // CURLSSH_AUTH_ANY; } /// enum CURL_ERROR_SIZE = 256; /** points to a zero-terminated string encoded with base64 if len is zero, otherwise to the "raw" data */ enum CurlKHType { unknown, /// rsa1, /// rsa, /// dss /// } /// extern (C) struct curl_khkey { const(char) *key; /** points to a zero-terminated string encoded with base64 if len is zero, otherwise to the "raw" data */ size_t len; /// CurlKHType keytype; /// } /** this is the set of return values expected from the curl_sshkeycallback callback */ enum CurlKHStat { fine_add_to_file, /// fine, /// reject, /** reject the connection, return an error */ defer, /** do not accept it, but we can't answer right now so this causes a CURLE_DEFER error but otherwise the connection will be left intact etc */ last /** not for use, only a marker for last-in-list */ } /** this is the set of status codes pass in to the callback */ enum CurlKHMatch { ok, /** match */ mismatch, /** host found, key mismatch! */ missing, /** no matching host/key found */ last /** not for use, only a marker for last-in-list */ } /// alias int function(CURL *easy, /** easy handle */ curl_khkey *knownkey, /** known */ curl_khkey *foundkey, /** found */ CurlKHMatch m, /** libcurl's view on the keys */ void *clientp /** custom pointer passed from app */ )curl_sshkeycallback; /** parameter for the CURLOPT_USE_SSL option */ enum CurlUseSSL { none, /** do not attempt to use SSL */ tryssl, /** try using SSL, proceed anyway otherwise */ control, /** SSL for the control connection or fail */ all, /** SSL for all communication or fail */ last /** not an option, never use */ } /// alias int curl_usessl; /** parameter for the CURLOPT_FTP_SSL_CCC option */ enum CurlFtpSSL { ccc_none, /** do not send CCC */ ccc_passive, /** Let the server initiate the shutdown */ ccc_active, /** Initiate the shutdown */ ccc_last /** not an option, never use */ } /// alias int curl_ftpccc; /** parameter for the CURLOPT_FTPSSLAUTH option */ enum CurlFtpAuth { defaultauth, /** let libcurl decide */ ssl, /** use "AUTH SSL" */ tls, /** use "AUTH TLS" */ last /** not an option, never use */ } /// alias int curl_ftpauth; /** parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ enum CurlFtp { create_dir_none, /** do NOT create missing dirs! */ create_dir, /** (FTP/SFTP) if CWD fails, try MKD and then CWD again if MKD succeeded, for SFTP this does similar magic */ create_dir_retry, /** (FTP only) if CWD fails, try MKD and then CWD again even if MKD failed! */ create_dir_last /** not an option, never use */ } /// alias int curl_ftpcreatedir; /** parameter for the CURLOPT_FTP_FILEMETHOD option */ enum CurlFtpMethod { defaultmethod, /** let libcurl pick */ multicwd, /** single CWD operation for each path part */ nocwd, /** no CWD at all */ singlecwd, /** one CWD to full dir, then work on file */ last /** not an option, never use */ } /// alias int curl_ftpmethod; /** CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ enum CurlProto { http = 1, /// https = 2, /// ftp = 4, /// ftps = 8, /// scp = 16, /// sftp = 32, /// telnet = 64, /// ldap = 128, /// ldaps = 256, /// dict = 512, /// file = 1024, /// tftp = 2048, /// imap = 4096, /// imaps = 8192, /// pop3 = 16384, /// pop3s = 32768, /// smtp = 65536, /// smtps = 131072, /// rtsp = 262144, /// rtmp = 524288, /// rtmpt = 1048576, /// rtmpe = 2097152, /// rtmpte = 4194304, /// rtmps = 8388608, /// rtmpts = 16777216, /// gopher = 33554432, /// all = -1 /** enable everything */ } /** long may be 32 or 64 bits, but we should never depend on anything else but 32 */ enum CURLOPTTYPE_LONG = 0; /// ditto enum CURLOPTTYPE_OBJECTPOINT = 10000; /// ditto enum CURLOPTTYPE_FUNCTIONPOINT = 20000; /// ditto enum CURLOPTTYPE_OFF_T = 30000; /** name is uppercase CURLOPT_$(LT)name$(GT), type is one of the defined CURLOPTTYPE_$(LT)type$(GT) number is unique identifier */ /** The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ alias CURLOPTTYPE_LONG LONG; /// ditto alias CURLOPTTYPE_OBJECTPOINT OBJECTPOINT; /// ditto alias CURLOPTTYPE_FUNCTIONPOINT FUNCTIONPOINT; /// ditto alias CURLOPTTYPE_OFF_T OFF_T; /// enum CurlOption { /** This is the FILE * or void * the regular output should be written to. */ file = 10001, /** The full URL to get/put */ url, /** Port number to connect to, if other than default. */ port = 3, /** Name of proxy to use. */ proxy = 10004, /** "name:password" to use when fetching. */ userpwd, /** "name:password" to use with proxy. */ proxyuserpwd, /** Range to get, specified as an ASCII string. */ range, /** not used */ /** Specified file stream to upload from (use as input): */ infile = 10009, /** Buffer to receive error messages in, must be at least CURL_ERROR_SIZE * bytes big. If this is not used, error messages go to stderr instead: */ errorbuffer, /** Function that will be called to store the output (instead of fwrite). The * parameters will use fwrite() syntax, make sure to follow them. */ writefunction = 20011, /** Function that will be called to read the input (instead of fread). The * parameters will use fread() syntax, make sure to follow them. */ readfunction, /** Time-out the read operation after this amount of seconds */ timeout = 13, /** If the CURLOPT_INFILE is used, this can be used to inform libcurl about * how large the file being sent really is. That allows better error * checking and better verifies that the upload was successful. -1 means * unknown size. * * For large file support, there is also a _LARGE version of the key * which takes an off_t type, allowing platforms with larger off_t * sizes to handle larger files. See below for INFILESIZE_LARGE. */ infilesize, /** POST static input fields. */ postfields = 10015, /** Set the referrer page (needed by some CGIs) */ referer, /** Set the FTP PORT string (interface name, named or numerical IP address) Use i.e '-' to use default address. */ ftpport, /** Set the User-Agent string (examined by some CGIs) */ useragent, /** If the download receives less than "low speed limit" bytes/second * during "low speed time" seconds, the operations is aborted. * You could i.e if you have a pretty high speed connection, abort if * it is less than 2000 bytes/sec during 20 seconds. */ /** Set the "low speed limit" */ low_speed_limit = 19, /** Set the "low speed time" */ low_speed_time, /** Set the continuation offset. * * Note there is also a _LARGE version of this key which uses * off_t types, allowing for large file offsets on platforms which * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. */ resume_from, /** Set cookie in request: */ cookie = 10022, /** This points to a linked list of headers, struct curl_slist kind */ httpheader, /** This points to a linked list of post entries, struct curl_httppost */ httppost, /** name of the file keeping your private SSL-certificate */ sslcert, /** password for the SSL or SSH private key */ keypasswd, /** send TYPE parameter? */ crlf = 27, /** send linked-list of QUOTE commands */ quote = 10028, /** send FILE * or void * to store headers to, if you use a callback it is simply passed to the callback unmodified */ writeheader, /** point to a file to read the initial cookies from, also enables "cookie awareness" */ cookiefile = 10031, /** What version to specifically try to use. See CURL_SSLVERSION defines below. */ sslversion = 32, /** What kind of HTTP time condition to use, see defines */ timecondition, /** Time to use with the above condition. Specified in number of seconds since 1 Jan 1970 */ timevalue, /* 35 = OBSOLETE */ /** Custom request, for customizing the get command like HTTP: DELETE, TRACE and others FTP: to use a different list command */ customrequest = 10036, /** HTTP request, for odd commands like DELETE, TRACE and others */ stderr, /* 38 is not used */ /** send linked-list of post-transfer QUOTE commands */ postquote = 10039, /** Pass a pointer to string of the output using full variable-replacement as described elsewhere. */ writeinfo, verbose = 41, /** talk a lot */ header, /** throw the header out too */ noprogress, /** shut off the progress meter */ nobody, /** use HEAD to get http document */ failonerror, /** no output on http error codes >= 300 */ upload, /** this is an upload */ post, /** HTTP POST method */ dirlistonly, /** return bare names when listing directories */ append = 50, /** Append instead of overwrite on upload! */ /** Specify whether to read the user+password from the .netrc or the URL. * This must be one of the CURL_NETRC_* enums below. */ netrc, followlocation, /** use Location: Luke! */ transfertext, /** transfer data in text/ASCII format */ put, /** HTTP PUT */ /* 55 = OBSOLETE */ /** Function that will be called instead of the internal progress display * function. This function should be defined as the curl_progress_callback * prototype defines. */ progressfunction = 20056, /** Data passed to the progress callback */ progressdata = 10057, /** We want the referrer field set automatically when following locations */ autoreferer = 58, /** Port of the proxy, can be set in the proxy string as well with: "[host]:[port]" */ proxyport, /** size of the POST input data, if strlen() is not good to use */ postfieldsize, /** tunnel non-http operations through a HTTP proxy */ httpproxytunnel, /** Set the interface string to use as outgoing network interface */ intrface = 10062, /** Set the krb4/5 security level, this also enables krb4/5 awareness. This * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string * is set but doesn't match one of these, 'private' will be used. */ krblevel, /** Set if we should verify the peer in ssl handshake, set 1 to verify. */ ssl_verifypeer = 64, /** The CApath or CAfile used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ cainfo = 10065, /* 66 = OBSOLETE */ /* 67 = OBSOLETE */ /** Maximum number of http redirects to follow */ maxredirs = 68, /** Pass a long set to 1 to get the date of the requested document (if possible)! Pass a zero to shut it off. */ filetime, /** This points to a linked list of telnet options */ telnetoptions = 10070, /** Max amount of cached alive connections */ maxconnects = 71, /** What policy to use when closing connections when the cache is filled up */ closepolicy, /* 73 = OBSOLETE */ /** Set to explicitly use a new connection for the upcoming transfer. Do not use this unless you're absolutely sure of this, as it makes the operation slower and is less friendly for the network. */ fresh_connect = 74, /** Set to explicitly forbid the upcoming transfer's connection to be re-used when done. Do not use this unless you're absolutely sure of this, as it makes the operation slower and is less friendly for the network. */ forbid_reuse, /** Set to a file name that contains random data for libcurl to use to seed the random engine when doing SSL connects. */ random_file = 10076, /** Set to the Entropy Gathering Daemon socket pathname */ egdsocket, /** Time-out connect operations after this amount of seconds, if connects are OK within this time, then fine... This only aborts the connect phase. [Only works on unix-style/SIGALRM operating systems] */ connecttimeout = 78, /** Function that will be called to store headers (instead of fwrite). The * parameters will use fwrite() syntax, make sure to follow them. */ headerfunction = 20079, /** Set this to force the HTTP request to get back to GET. Only really usable if POST, PUT or a custom request have been used first. */ httpget = 80, /** Set if we should verify the Common name from the peer certificate in ssl * handshake, set 1 to check existence, 2 to ensure that it matches the * provided hostname. */ ssl_verifyhost, /** Specify which file name to write all known cookies in after completed operation. Set file name to "-" (dash) to make it go to stdout. */ cookiejar = 10082, /** Specify which SSL ciphers to use */ ssl_cipher_list, /** Specify which HTTP version to use! This must be set to one of the CURL_HTTP_VERSION* enums set below. */ http_version = 84, /** Specifically switch on or off the FTP engine's use of the EPSV command. By default, that one will always be attempted before the more traditional PASV command. */ ftp_use_epsv, /** type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ sslcerttype = 10086, /** name of the file keeping your private SSL-key */ sslkey, /** type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ sslkeytype, /** crypto engine for the SSL-sub system */ sslengine, /** set the crypto engine for the SSL-sub system as default the param has no meaning... */ sslengine_default = 90, /** Non-zero value means to use the global dns cache */ dns_use_global_cache, /** DNS cache timeout */ dns_cache_timeout, /** send linked-list of pre-transfer QUOTE commands */ prequote = 10093, /** set the debug function */ debugfunction = 20094, /** set the data for the debug function */ debugdata = 10095, /** mark this as start of a cookie session */ cookiesession = 96, /** The CApath directory used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ capath = 10097, /** Instruct libcurl to use a smaller receive buffer */ buffersize = 98, /** Instruct libcurl to not use any signal/alarm handlers, even when using timeouts. This option is useful for multi-threaded applications. See libcurl-the-guide for more background information. */ nosignal, /** Provide a CURLShare for mutexing non-ts data */ share = 10100, /** indicates type of proxy. accepted values are CURLPROXY_HTTP (default), CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ proxytype = 101, /** Set the Accept-Encoding string. Use this to tell a server you would like the response to be compressed. */ encoding = 10102, /** Set pointer to private data */ private_opt, /** Set aliases for HTTP 200 in the HTTP Response header */ http200aliases, /** Continue to send authentication (user+password) when following locations, even when hostname changed. This can potentially send off the name and password to whatever host the server decides. */ unrestricted_auth = 105, /** Specifically switch on or off the FTP engine's use of the EPRT command ( it also disables the LPRT attempt). By default, those ones will always be attempted before the good old traditional PORT command. */ ftp_use_eprt, /** Set this to a bitmask value to enable the particular authentications methods you like. Use this in combination with CURLOPT_USERPWD. Note that setting multiple bits may cause extra network round-trips. */ httpauth, /** Set the ssl context callback function, currently only for OpenSSL ssl_ctx in second argument. The function must be matching the curl_ssl_ctx_callback proto. */ ssl_ctx_function = 20108, /** Set the userdata for the ssl context callback function's third argument */ ssl_ctx_data = 10109, /** FTP Option that causes missing dirs to be created on the remote server. In 7.19.4 we introduced the convenience enums for this option using the CURLFTP_CREATE_DIR prefix. */ ftp_create_missing_dirs = 110, /** Set this to a bitmask value to enable the particular authentications methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. Note that setting multiple bits may cause extra network round-trips. */ proxyauth, /** FTP option that changes the timeout, in seconds, associated with getting a response. This is different from transfer timeout time and essentially places a demand on the FTP server to acknowledge commands in a timely manner. */ ftp_response_timeout, /** Set this option to one of the CURL_IPRESOLVE_* defines (see below) to tell libcurl to resolve names to those IP versions only. This only has affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ ipresolve, /** Set this option to limit the size of a file that will be downloaded from an HTTP or FTP server. Note there is also _LARGE version which adds large file support for platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ maxfilesize, /** See the comment for INFILESIZE above, but in short, specifies * the size of the file being uploaded. -1 means unknown. */ infilesize_large = 30115, /** Sets the continuation offset. There is also a LONG version of this; * look above for RESUME_FROM. */ resume_from_large, /** Sets the maximum size of data that will be downloaded from * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. */ maxfilesize_large, /** Set this option to the file name of your .netrc file you want libcurl to parse (using the CURLOPT_NETRC option). If not set, libcurl will do a poor attempt to find the user's home directory and check for a .netrc file in there. */ netrc_file = 10118, /** Enable SSL/TLS for FTP, pick one of: CURLFTPSSL_TRY - try using SSL, proceed anyway otherwise CURLFTPSSL_CONTROL - SSL for the control connection or fail CURLFTPSSL_ALL - SSL for all communication or fail */ use_ssl = 119, /** The _LARGE version of the standard POSTFIELDSIZE option */ postfieldsize_large = 30120, /** Enable/disable the TCP Nagle algorithm */ tcp_nodelay = 121, /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 123 OBSOLETE. Gone in 7.16.0 */ /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 127 OBSOLETE. Gone in 7.16.0 */ /* 128 OBSOLETE. Gone in 7.16.0 */ /** When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option can be used to change libcurl's default action which is to first try "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK response has been received. Available parameters are: CURLFTPAUTH_DEFAULT - let libcurl decide CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL */ ftpsslauth = 129, ioctlfunction = 20130, /// ioctldata = 10131, /// /* 132 OBSOLETE. Gone in 7.16.0 */ /* 133 OBSOLETE. Gone in 7.16.0 */ /** zero terminated string for pass on to the FTP server when asked for "account" info */ ftp_account = 10134, /** feed cookies into cookie engine */ cookielist, /** ignore Content-Length */ ignore_content_length = 136, /** Set to non-zero to skip the IP address received in a 227 PASV FTP server response. Typically used for FTP-SSL purposes but is not restricted to that. libcurl will then instead use the same IP address it used for the control connection. */ ftp_skip_pasv_ip, /** Select "file method" to use when doing FTP, see the curl_ftpmethod above. */ ftp_filemethod, /** Local port number to bind the socket to */ localport, /** Number of ports to try, including the first one set with LOCALPORT. Thus, setting it to 1 will make no additional attempts but the first. */ localportrange, /** no transfer, set up connection and let application use the socket by extracting it with CURLINFO_LASTSOCKET */ connect_only, /** Function that will be called to convert from the network encoding (instead of using the iconv calls in libcurl) */ conv_from_network_function = 20142, /** Function that will be called to convert to the network encoding (instead of using the iconv calls in libcurl) */ conv_to_network_function, /** Function that will be called to convert from UTF8 (instead of using the iconv calls in libcurl) Note that this is used only for SSL certificate processing */ conv_from_utf8_function, /** If the connection proceeds too quickly then need to slow it down */ /** */ /** limit-rate: maximum number of bytes per second to send or receive */ max_send_speed_large = 30145, max_recv_speed_large, /// ditto /** Pointer to command string to send if USER/PASS fails. */ ftp_alternative_to_user = 10147, /** callback function for setting socket options */ sockoptfunction = 20148, sockoptdata = 10149, /** set to 0 to disable session ID re-use for this transfer, default is enabled (== 1) */ ssl_sessionid_cache = 150, /** allowed SSH authentication methods */ ssh_auth_types, /** Used by scp/sftp to do public/private key authentication */ ssh_public_keyfile = 10152, ssh_private_keyfile, /** Send CCC (Clear Command Channel) after authentication */ ftp_ssl_ccc = 154, /** Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ timeout_ms, connecttimeout_ms, /** set to zero to disable the libcurl's decoding and thus pass the raw body data to the application even when it is encoded/compressed */ http_transfer_decoding, http_content_decoding, /// ditto /** Permission used when creating new files and directories on the remote server for protocols that support it, SFTP/SCP/FILE */ new_file_perms, new_directory_perms, /// ditto /** Set the behaviour of POST when redirecting. Values must be set to one of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ postredir, /** used by scp/sftp to verify the host's public key */ ssh_host_public_key_md5 = 10162, /** Callback function for opening socket (instead of socket(2)). Optionally, callback is able change the address or refuse to connect returning CURL_SOCKET_BAD. The callback should have type curl_opensocket_callback */ opensocketfunction = 20163, opensocketdata = 10164, /// ditto /** POST volatile input fields. */ copypostfields, /** set transfer mode (;type=$(LT)a|i$(GT)) when doing FTP via an HTTP proxy */ proxy_transfer_mode = 166, /** Callback function for seeking in the input stream */ seekfunction = 20167, seekdata = 10168, /// ditto /** CRL file */ crlfile, /** Issuer certificate */ issuercert, /** (IPv6) Address scope */ address_scope = 171, /** Collect certificate chain info and allow it to get retrievable with CURLINFO_CERTINFO after the transfer is complete. (Unfortunately) only working with OpenSSL-powered builds. */ certinfo, /** "name" and "pwd" to use when fetching. */ username = 10173, password, /// ditto /** "name" and "pwd" to use with Proxy when fetching. */ proxyusername, proxypassword, /// ditto /** Comma separated list of hostnames defining no-proxy zones. These should match both hostnames directly, and hostnames within a domain. For example, local.com will match local.com and www.local.com, but NOT notlocal.com or www.notlocal.com. For compatibility with other implementations of this, .local.com will be considered to be the same as local.com. A single * is the only valid wildcard, and effectively disables the use of proxy. */ noproxy, /** block size for TFTP transfers */ tftp_blksize = 178, /** Socks Service */ socks5_gssapi_service = 10179, /** Socks Service */ socks5_gssapi_nec = 180, /** set the bitmask for the protocols that are allowed to be used for the transfer, which thus helps the app which takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to CURLPROTO_ALL. */ protocols, /** set the bitmask for the protocols that libcurl is allowed to follow to, as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs to be set in both bitmasks to be allowed to get redirected to. Defaults to all protocols except FILE and SCP. */ redir_protocols, /** set the SSH knownhost file name to use */ ssh_knownhosts = 10183, /** set the SSH host key callback, must point to a curl_sshkeycallback function */ ssh_keyfunction = 20184, /** set the SSH host key callback custom pointer */ ssh_keydata = 10185, /** set the SMTP mail originator */ mail_from, /** set the SMTP mail receiver(s) */ mail_rcpt, /** FTP: send PRET before PASV */ ftp_use_pret = 188, /** RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ rtsp_request, /** The RTSP session identifier */ rtsp_session_id = 10190, /** The RTSP stream URI */ rtsp_stream_uri, /** The Transport: header to use in RTSP requests */ rtsp_transport, /** Manually initialize the client RTSP CSeq for this handle */ rtsp_client_cseq = 193, /** Manually initialize the server RTSP CSeq for this handle */ rtsp_server_cseq, /** The stream to pass to INTERLEAVEFUNCTION. */ interleavedata = 10195, /** Let the application define a custom write method for RTP data */ interleavefunction = 20196, /** Turn on wildcard matching */ wildcardmatch = 197, /** Directory matching callback called before downloading of an individual file (chunk) started */ chunk_bgn_function = 20198, /** Directory matching callback called after the file (chunk) was downloaded, or skipped */ chunk_end_function, /** Change match (fnmatch-like) callback for wildcard matching */ fnmatch_function, /** Let the application define custom chunk data pointer */ chunk_data = 10201, /** FNMATCH_FUNCTION user pointer */ fnmatch_data, /** send linked-list of name:port:address sets */ resolve, /** Set a username for authenticated TLS */ tlsauth_username, /** Set a password for authenticated TLS */ tlsauth_password, /** Set authentication type for authenticated TLS */ tlsauth_type, /** the last unused */ lastentry, writedata = file, /// convenient alias readdata = infile, /// ditto headerdata = writeheader, /// ditto rtspheader = httpheader, /// ditto } /// alias int CURLoption; /// enum CURLOPT_SERVER_RESPONSE_TIMEOUT = CurlOption.ftp_response_timeout; /** Below here follows defines for the CURLOPT_IPRESOLVE option. If a host name resolves addresses using more than one IP protocol version, this option might be handy to force libcurl to use a specific IP version. */ enum CurlIpResolve { whatever = 0, /** default, resolves addresses to all IP versions that your system allows */ v4 = 1, /** resolve to ipv4 addresses */ v6 = 2 /** resolve to ipv6 addresses */ } /** three convenient "aliases" that follow the name scheme better */ enum CURLOPT_WRITEDATA = CurlOption.file; /// ditto enum CURLOPT_READDATA = CurlOption.infile; /// ditto enum CURLOPT_HEADERDATA = CurlOption.writeheader; /// ditto enum CURLOPT_RTSPHEADER = CurlOption.httpheader; /** These enums are for use with the CURLOPT_HTTP_VERSION option. */ enum CurlHttpVersion { none, /** setting this means we don't care, and that we'd like the library to choose the best possible for us! */ v1_0, /** please use HTTP 1.0 in the request */ v1_1, /** please use HTTP 1.1 in the request */ last /** *ILLEGAL* http version */ } /** * Public API enums for RTSP requests */ enum CurlRtspReq { none, /// options, /// describe, /// announce, /// setup, /// play, /// pause, /// teardown, /// get_parameter, /// set_parameter, /// record, /// receive, /// last /// } /** These enums are for use with the CURLOPT_NETRC option. */ enum CurlNetRcOption { ignored, /** The .netrc will never be read. This is the default. */ optional /** A user:password in the URL will be preferred to one in the .netrc. */, required, /** A user:password in the URL will be ignored. * Unless one is set programmatically, the .netrc * will be queried. */ last /// } /// enum CurlSslVersion { default_version, /// tlsv1, /// sslv2, /// sslv3, /// last /** never use */ } /// enum CurlTlsAuth { none, /// srp, /// last /** never use */ } /** symbols to use with CURLOPT_POSTREDIR. CURL_REDIR_POST_301 and CURL_REDIR_POST_302 can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 == CURL_REDIR_POST_ALL */ enum CurlRedir { get_all = 0, /// post_301 = 1, /// post_302 = 2, /// /// post_all = (1 | 2) // (CURL_REDIR_POST_301|CURL_REDIR_POST_302); } /// enum CurlTimeCond { none, /// ifmodsince, /// ifunmodsince, /// lastmod, /// last /// } /// alias int curl_TimeCond; /** curl_strequal() and curl_strnequal() are subject for removal in a future libcurl, see lib/README.curlx for details */ extern (C) { int curl_strequal(in char *s1, in char *s2); /// ditto int curl_strnequal(in char *s1, in char *s2, size_t n); } enum CurlForm { nothing, /********** the first one is unused ************/ copyname, ptrname, namelength, copycontents, ptrcontents, contentslength, filecontent, array, obsolete, file, buffer, bufferptr, bufferlength, contenttype, contentheader, filename, end, obsolete2, stream, lastentry /** the last unused */ } alias int CURLformoption; /** structure to be used as parameter for CURLFORM_ARRAY */ extern (C) struct curl_forms { CURLformoption option; /// const(char) *value; /// } /** Use this for multipart formpost building * * Returns code for curl_formadd() * * Returns: * * $(UL * $(LI CURL_FORMADD_OK on success ) * $(LI CURL_FORMADD_MEMORY if the FormInfo allocation fails ) * $(LI CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form ) * $(LI CURL_FORMADD_NULL if a null pointer was given for a char ) * $(LI CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed ) * $(LI CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used ) * $(LI CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) ) * $(LI CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated ) * $(LI CURL_FORMADD_MEMORY if some allocation for string copying failed. ) * $(LI CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array ) * ) * ***************************************************************************/ enum CurlFormAdd { ok, /** first, no error */ memory, /// option_twice, /// null_ptr, /// unknown_option, /// incomplete, /// illegal_array, /// disabled, /** libcurl was built with this disabled */ last /// } /// alias int CURLFORMcode; extern (C) { /** * Name: curl_formadd() * * Description: * * Pretty advanced function for building multi-part formposts. Each invoke * adds one part that together construct a full post. Then use * CURLOPT_HTTPPOST to send it off to libcurl. */ CURLFORMcode curl_formadd(curl_httppost **httppost, curl_httppost **last_post,...); /** * callback function for curl_formget() * The void *arg pointer will be the one passed as second argument to * curl_formget(). * The character buffer passed to it must not be freed. * Should return the buffer length passed to it as the argument "len" on * success. */ alias size_t function(void *arg, in char *buf, size_t len)curl_formget_callback; /** * Name: curl_formget() * * Description: * * Serialize a curl_httppost struct built with curl_formadd(). * Accepts a void pointer as second argument which will be passed to * the curl_formget_callback function. * Returns 0 on success. */ int curl_formget(curl_httppost *form, void *arg, curl_formget_callback append); /** * Name: curl_formfree() * * Description: * * Free a multipart formpost previously built with curl_formadd(). */ void curl_formfree(curl_httppost *form); /** * Name: curl_getenv() * * Description: * * Returns a malloc()'ed string that MUST be curl_free()ed after usage is * complete. DEPRECATED - see lib/README.curlx */ char * curl_getenv(in char *variable); /** * Name: curl_version() * * Description: * * Returns a static ascii string of the libcurl version. */ char * curl_version(); /** * Name: curl_easy_escape() * * Description: * * Escapes URL strings (converts all letters consider illegal in URLs to their * %XX versions). This function returns a new allocated string or NULL if an * error occurred. */ char * curl_easy_escape(CURL *handle, in char *string, int length) @trusted; /** the previous version: */ char * curl_escape(in char *string, int length) @trusted; /** * Name: curl_easy_unescape() * * Description: * * Unescapes URL encoding in strings (converts all %XX codes to their 8bit * versions). This function returns a new allocated string or NULL if an error * occurred. * Conversion Note: On non-ASCII platforms the ASCII %XX codes are * converted into the host encoding. */ char * curl_easy_unescape(CURL *handle, in char *string, int length, int *outlength) @trusted; /** the previous version */ char * curl_unescape(in char *string, int length) @trusted; /** * Name: curl_free() * * Description: * * Provided for de-allocation in the same translation unit that did the * allocation. Added in libcurl 7.10 */ void curl_free(void *p); /** * Name: curl_global_init() * * Description: * * curl_global_init() should be invoked exactly once for each application that * uses libcurl and before any call of other libcurl functions. * * This function is not thread-safe! */ CURLcode curl_global_init(c_long flags); /** * Name: curl_global_init_mem() * * Description: * * curl_global_init() or curl_global_init_mem() should be invoked exactly once * for each application that uses libcurl. This function can be used to * initialize libcurl and set user defined memory management callback * functions. Users can implement memory management routines to check for * memory leaks, check for mis-use of the curl library etc. User registered * callback routines with be invoked by this library instead of the system * memory management routines like malloc, free etc. */ CURLcode curl_global_init_mem(c_long flags, curl_malloc_callback m, curl_free_callback f, curl_realloc_callback r, curl_strdup_callback s, curl_calloc_callback c); /** * Name: curl_global_cleanup() * * Description: * * curl_global_cleanup() should be invoked exactly once for each application * that uses libcurl */ void curl_global_cleanup(); } /** linked-list structure for the CURLOPT_QUOTE option (and other) */ extern (C) { struct curl_slist { char *data; curl_slist *next; } /** * Name: curl_slist_append() * * Description: * * Appends a string to a linked list. If no list exists, it will be created * first. Returns the new list, after appending. */ curl_slist * curl_slist_append(curl_slist *, in char *); /** * Name: curl_slist_free_all() * * Description: * * free a previously built curl_slist. */ void curl_slist_free_all(curl_slist *); /** * Name: curl_getdate() * * Description: * * Returns the time, in seconds since 1 Jan 1970 of the time string given in * the first argument. The time argument in the second parameter is unused * and should be set to NULL. */ time_t curl_getdate(char *p, time_t *unused); /** info about the certificate chain, only for OpenSSL builds. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ struct curl_certinfo { int num_of_certs; /** number of certificates with information */ curl_slist **certinfo; /** for each index in this array, there's a linked list with textual information in the format "name: value" */ } } // extern (C) end /// enum CURLINFO_STRING = 0x100000; /// enum CURLINFO_LONG = 0x200000; /// enum CURLINFO_DOUBLE = 0x300000; /// enum CURLINFO_SLIST = 0x400000; /// enum CURLINFO_MASK = 0x0fffff; /// enum CURLINFO_TYPEMASK = 0xf00000; /// enum CurlInfo { none, /// effective_url = 1048577, /// response_code = 2097154, /// total_time = 3145731, /// namelookup_time, /// connect_time, /// pretransfer_time, /// size_upload, /// size_download, /// speed_download, /// speed_upload, /// header_size = 2097163, /// request_size, /// ssl_verifyresult, /// filetime, /// content_length_download = 3145743, /// content_length_upload, /// starttransfer_time, /// content_type = 1048594, /// redirect_time = 3145747, /// redirect_count = 2097172, /// private_info = 1048597, /// http_connectcode = 2097174, /// httpauth_avail, /// proxyauth_avail, /// os_errno, /// num_connects, /// ssl_engines = 4194331, /// cookielist, /// lastsocket = 2097181, /// ftp_entry_path = 1048606, /// redirect_url, /// primary_ip, /// appconnect_time = 3145761, /// certinfo = 4194338, /// condition_unmet = 2097187, /// rtsp_session_id = 1048612, /// rtsp_client_cseq = 2097189, /// rtsp_server_cseq, /// rtsp_cseq_recv, /// primary_port, /// local_ip = 1048617, /// local_port = 2097194, /// /** Fill in new entries below here! */ lastone = 42 } /// alias int CURLINFO; /** CURLINFO_RESPONSE_CODE is the new name for the option previously known as CURLINFO_HTTP_CODE */ enum CURLINFO_HTTP_CODE = CurlInfo.response_code; /// enum CurlClosePolicy { none, /// oldest, /// least_recently_used, /// least_traffic, /// slowest, /// callback, /// last /// } /// alias int curl_closepolicy; /// enum CurlGlobal { ssl = 1, /// win32 = 2, /// /// all = (1 | 2), // (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); nothing = 0, /// default_ = (1 | 2) /// all } /****************************************************************************** * Setup defines, protos etc for the sharing stuff. */ /** Different data locks for a single share */ enum CurlLockData { none, /// /** CURL_LOCK_DATA_SHARE is used internally to say that * the locking is just made to change the internal state of the share * itself. */ share, cookie, /// dns, /// ssl_session, /// connect, /// last /// } /// alias int curl_lock_data; /** Different lock access types */ enum CurlLockAccess { none, /** unspecified action */ shared_access, /** for read perhaps */ single, /** for write perhaps */ last /** never use */ } /// alias int curl_lock_access; /// alias void function(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)curl_lock_function; /// alias void function(CURL *handle, curl_lock_data data, void *userptr)curl_unlock_function; /// alias void CURLSH; /// enum CurlShError { ok, /** all is fine */ bad_option, /** 1 */ in_use, /** 2 */ invalid, /** 3 */ nomem, /** out of memory */ last /** never use */ } /// alias int CURLSHcode; /** pass in a user data pointer used in the lock/unlock callback functions */ enum CurlShOption { none, /** don't use */ share, /** specify a data type to share */ unshare, /** specify which data type to stop sharing */ lockfunc, /** pass in a 'curl_lock_function' pointer */ unlockfunc, /** pass in a 'curl_unlock_function' pointer */ userdata, /** pass in a user data pointer used in the lock/unlock callback functions */ last /** never use */ } /// alias int CURLSHoption; extern (C) { /// CURLSH * curl_share_init(); /// CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option,...); /// CURLSHcode curl_share_cleanup(CURLSH *); } /***************************************************************************** * Structures for querying information about the curl library at runtime. */ // CURLVERSION_* enum CurlVer { first, /// second, /// third, /// fourth, /// last /// } /// alias int CURLversion; /** The 'CURLVERSION_NOW' is the symbolic name meant to be used by basically all programs ever that want to get version information. It is meant to be a built-in version number for what kind of struct the caller expects. If the struct ever changes, we redefine the NOW to another enum from above. */ enum CURLVERSION_NOW = CurlVer.fourth; /// extern (C) struct _N28 { CURLversion age; /** age of the returned struct */ const(char) *version_; /** LIBCURL_VERSION */ uint version_num; /** LIBCURL_VERSION_NUM */ const(char) *host; /** OS/host/cpu/machine when configured */ int features; /** bitmask, see defines below */ const(char) *ssl_version; /** human readable string */ c_long ssl_version_num; /** not used anymore, always 0 */ const(char) *libz_version; /** human readable string */ /** protocols is terminated by an entry with a NULL protoname */ const(char) **protocols; /** The fields below this were added in CURLVERSION_SECOND */ const(char) *ares; int ares_num; /** This field was added in CURLVERSION_THIRD */ const(char) *libidn; /** These field were added in CURLVERSION_FOURTH. */ /** Same as '_libiconv_version' if built with HAVE_ICONV */ int iconv_ver_num; const(char) *libssh_version; /** human readable string */ } /// alias _N28 curl_version_info_data; /// // CURL_VERSION_* enum CurlVersion { ipv6 = 1, /** IPv6-enabled */ kerberos4 = 2, /** kerberos auth is supported */ ssl = 4, /** SSL options are present */ libz = 8, /** libz features are present */ ntlm = 16, /** NTLM auth is supported */ gssnegotiate = 32, /** Negotiate auth support */ dbg = 64, /** built with debug capabilities */ asynchdns = 128, /** asynchronous dns resolves */ spnego = 256, /** SPNEGO auth */ largefile = 512, /** supports files bigger than 2GB */ idn = 1024, /** International Domain Names support */ sspi = 2048, /** SSPI is supported */ conv = 4096, /** character conversions supported */ curldebug = 8192, /** debug memory tracking supported */ tlsauth_srp = 16384 /** TLS-SRP auth is supported */ } extern (C) { /** * Name: curl_version_info() * * Description: * * This function returns a pointer to a static copy of the version info * struct. See above. */ curl_version_info_data * curl_version_info(CURLversion ); /** * Name: curl_easy_strerror() * * Description: * * The curl_easy_strerror function may be used to turn a CURLcode value * into the equivalent human readable error string. This is useful * for printing meaningful error messages. */ const(char)* curl_easy_strerror(CURLcode ); /** * Name: curl_share_strerror() * * Description: * * The curl_share_strerror function may be used to turn a CURLSHcode value * into the equivalent human readable error string. This is useful * for printing meaningful error messages. */ const(char)* curl_share_strerror(CURLSHcode ); /** * Name: curl_easy_pause() * * Description: * * The curl_easy_pause function pauses or unpauses transfers. Select the new * state by setting the bitmask, use the convenience defines below. * */ CURLcode curl_easy_pause(CURL *handle, int bitmask); } /// enum CurlPause { recv = 1, /// recv_cont = 0, /// send = 4, /// send_cont = 0, /// /// all = (1 | 4), // CURLPAUSE_RECV | CURLPAUSE_SEND /// cont = (0 | 0), // CURLPAUSE_RECV_CONT | CURLPAUSE_SEND_CONT } /* unfortunately, the easy.h and multi.h include files need options and info stuff before they can be included! */ /* *************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ extern (C) { /// CURL * curl_easy_init(); /// CURLcode curl_easy_setopt(CURL *curl, CURLoption option,...); /// CURLcode curl_easy_perform(CURL *curl); /// void curl_easy_cleanup(CURL *curl); } /** * Name: curl_easy_getinfo() * * Description: * * Request internal information from the curl session with this function. The * third argument MUST be a pointer to a long, a pointer to a char * or a * pointer to a double (as the documentation describes elsewhere). The data * pointed to will be filled in accordingly and can be relied upon only if the * function returns CURLE_OK. This function is intended to get used *AFTER* a * performed transfer, all results from this function are undefined until the * transfer is completed. */ extern (C) CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info,...); /** * Name: curl_easy_duphandle() * * Description: * * Creates a new curl session handle with the same options set for the handle * passed in. Duplicating a handle could only be a matter of cloning data and * options, internal state info and things like persistant connections cannot * be transfered. It is useful in multithreaded applications when you can run * curl_easy_duphandle() for each new thread to avoid a series of identical * curl_easy_setopt() invokes in every thread. */ extern (C) CURL * curl_easy_duphandle(CURL *curl); /** * Name: curl_easy_reset() * * Description: * * Re-initializes a CURL handle to the default values. This puts back the * handle to the same state as it was in when it was just created. * * It does keep: live connections, the Session ID cache, the DNS cache and the * cookies. */ extern (C) void curl_easy_reset(CURL *curl); /** * Name: curl_easy_recv() * * Description: * * Receives data from the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ extern (C) CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n); /** * Name: curl_easy_send() * * Description: * * Sends data over the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ extern (C) CURLcode curl_easy_send(CURL *curl, void *buffer, size_t buflen, size_t *n); /* * This header file should not really need to include "curl.h" since curl.h * itself includes this file and we expect user applications to do #include * without the need for especially including multi.h. * * For some reason we added this include here at one point, and rather than to * break existing (wrongly written) libcurl applications, we leave it as-is * but with this warning attached. */ /* *************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /// alias void CURLM; /// enum CurlM { call_multi_perform = -1, /** please call curl_multi_perform() or curl_multi_socket*() soon */ ok, /// bad_handle, /** the passed-in handle is not a valid CURLM handle */ bad_easy_handle, /** an easy handle was not good/valid */ out_of_memory, /** if you ever get this, you're in deep sh*t */ internal_error, /** this is a libcurl bug */ bad_socket, /** the passed in socket argument did not match */ unknown_option, /** curl_multi_setopt() with unsupported option */ last, /// } /// alias int CURLMcode; /** just to make code nicer when using curl_multi_socket() you can now check for CURLM_CALL_MULTI_SOCKET too in the same style it works for curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ enum CURLM_CALL_MULTI_SOCKET = CurlM.call_multi_perform; /// enum CurlMsg { none, /// done, /** This easy handle has completed. 'result' contains the CURLcode of the transfer */ last, /** no used */ } /// alias int CURLMSG; /// extern (C) union _N31 { void *whatever; /** message-specific data */ CURLcode result; /** return code for transfer */ } /// extern (C) struct CURLMsg { CURLMSG msg; /** what this message means */ CURL *easy_handle; /** the handle it concerns */ _N31 data; /// } /** * Name: curl_multi_init() * * Desc: inititalize multi-style curl usage * * Returns: a new CURLM handle to use in all 'curl_multi' functions. */ extern (C) CURLM * curl_multi_init(); /** * Name: curl_multi_add_handle() * * Desc: add a standard curl handle to the multi stack * * Returns: CURLMcode type, general multi error code. */ extern (C) CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *curl_handle); /** * Name: curl_multi_remove_handle() * * Desc: removes a curl handle from the multi stack again * * Returns: CURLMcode type, general multi error code. */ extern (C) CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *curl_handle); /** * Name: curl_multi_fdset() * * Desc: Ask curl for its fd_set sets. The app can use these to select() or * poll() on. We want curl_multi_perform() called as soon as one of * them are ready. * * Returns: CURLMcode type, general multi error code. */ /** tmp decl */ alias int fd_set; /// extern (C) CURLMcode curl_multi_fdset(CURLM *multi_handle, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd); /** * Name: curl_multi_perform() * * Desc: When the app thinks there's data available for curl it calls this * function to read/write whatever there is right now. This returns * as soon as the reads and writes are done. This function does not * require that there actually is data available for reading or that * data can be written, it can be called just in case. It returns * the number of handles that still transfer data in the second * argument's integer-pointer. * * Returns: CURLMcode type, general multi error code. *NOTE* that this only * returns errors etc regarding the whole multi stack. There might * still have occurred problems on invidual transfers even when this * returns OK. */ extern (C) CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles); /** * Name: curl_multi_cleanup() * * Desc: Cleans up and removes a whole multi stack. It does not free or * touch any individual easy handles in any way. We need to define * in what state those handles will be if this function is called * in the middle of a transfer. * * Returns: CURLMcode type, general multi error code. */ extern (C) CURLMcode curl_multi_cleanup(CURLM *multi_handle); /** * Name: curl_multi_info_read() * * Desc: Ask the multi handle if there's any messages/informationals from * the individual transfers. Messages include informationals such as * error code from the transfer or just the fact that a transfer is * completed. More details on these should be written down as well. * * Repeated calls to this function will return a new struct each * time, until a special "end of msgs" struct is returned as a signal * that there is no more to get at this point. * * The data the returned pointer points to will not survive calling * curl_multi_cleanup(). * * The 'CURLMsg' struct is meant to be very simple and only contain * very basic informations. If more involved information is wanted, * we will provide the particular "transfer handle" in that struct * and that should/could/would be used in subsequent * curl_easy_getinfo() calls (or similar). The point being that we * must never expose complex structs to applications, as then we'll * undoubtably get backwards compatibility problems in the future. * * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out * of structs. It also writes the number of messages left in the * queue (after this read) in the integer the second argument points * to. */ extern (C) CURLMsg * curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue); /** * Name: curl_multi_strerror() * * Desc: The curl_multi_strerror function may be used to turn a CURLMcode * value into the equivalent human readable error string. This is * useful for printing meaningful error messages. * * Returns: A pointer to a zero-terminated error message. */ extern (C) const(char)* curl_multi_strerror(CURLMcode ); /** * Name: curl_multi_socket() and * curl_multi_socket_all() * * Desc: An alternative version of curl_multi_perform() that allows the * application to pass in one of the file descriptors that have been * detected to have "action" on them and let libcurl perform. * See man page for details. */ enum CurlPoll { none_ = 0, /** jdrewsen - underscored in order not to clash with reserved D symbols */ in_ = 1, /// out_ = 2, /// inout_ = 3, /// remove_ = 4 /// } /// alias CURL_SOCKET_BAD CURL_SOCKET_TIMEOUT; /// enum CurlCSelect { in_ = 0x01, /** jdrewsen - underscored in order not to clash with reserved D symbols */ out_ = 0x02, /// err_ = 0x04 /// } extern (C) { /// alias int function(CURL *easy, /** easy handle */ curl_socket_t s, /** socket */ int what, /** see above */ void *userp, /** private callback pointer */ void *socketp)curl_socket_callback; /** private socket pointer */ } /** * Name: curl_multi_timer_callback * * Desc: Called by libcurl whenever the library detects a change in the * maximum number of milliseconds the app is allowed to wait before * curl_multi_socket() or curl_multi_perform() must be called * (to allow libcurl's timed events to take place). * * Returns: The callback should return zero. */ extern (C) { alias int function(CURLM *multi, /** multi handle */ c_long timeout_ms, /** see above */ void *userp) curl_multi_timer_callback; /** private callback pointer */ /// ditto CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, int *running_handles); /// ditto CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s, int ev_bitmask, int *running_handles); /// ditto CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles); } /** This macro below was added in 7.16.3 to push users who recompile to use the new curl_multi_socket_action() instead of the old curl_multi_socket() */ /** * Name: curl_multi_timeout() * * Desc: Returns the maximum number of milliseconds the app is allowed to * wait before curl_multi_socket() or curl_multi_perform() must be * called (to allow libcurl's timed events to take place). * * Returns: CURLM error code. */ extern (C) CURLMcode curl_multi_timeout(CURLM *multi_handle, c_long *milliseconds); /// enum CurlMOption { socketfunction = 20001, /** This is the socket callback function pointer */ socketdata = 10002, /** This is the argument passed to the socket callback */ pipelining = 3, /** set to 1 to enable pipelining for this multi handle */ timerfunction = 20004, /** This is the timer callback function pointer */ timerdata = 10005, /** This is the argument passed to the timer callback */ maxconnects = 6, /** maximum number of entries in the connection cache */ lastentry /// } /// alias int CURLMoption; /** * Name: curl_multi_setopt() * * Desc: Sets options for the multi handle. * * Returns: CURLM error code. */ extern (C) CURLMcode curl_multi_setopt(CURLM *multi_handle, CURLMoption option,...); /** * Name: curl_multi_assign() * * Desc: This function sets an association in the multi handle between the * given socket and a private pointer of the application. This is * (only) useful for curl_multi_socket uses. * * Returns: CURLM error code. */ extern (C) CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd, void *sockp); ldc-1.1.0-beta3-src/runtime/phobos/etc/c/sqlite3.d0000664000175000017500000020533712776215007017654 0ustar kaikaimodule etc.c.sqlite3; /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. If a C-function, structure, datatype, ** or constant definition does not appear in this file, then it is ** not a published API of SQLite, is subject to change without ** notice, and should not be referenced by programs that use SQLite. ** ** Some of the definitions that are in this file are marked as ** "experimental". Experimental interfaces are normally new ** features recently added to SQLite. We do not anticipate changes ** to experimental interfaces but reserve the right to make minor changes ** if experience from use "in the wild" suggest such changes are prudent. ** ** The official C-language API documentation for SQLite is derived ** from comments in this file. This file is the authoritative source ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ import core.stdc.stdarg : va_list; extern (C) __gshared nothrow: /** ** CAPI3REF: Compile-Time Library Version Numbers */ enum SQLITE_VERSION = "3.10.2"; /// Ditto enum SQLITE_VERSION_NUMBER = 3010002; /// Ditto enum SQLITE_SOURCE_ID = "2016-01-20 15:27:19 17efb4209f97fb4971656086b138599a91a75ff9"; /** ** CAPI3REF: Run-Time Library Version Numbers */ extern immutable(char)* sqlite3_version; /// Ditto immutable(char)* sqlite3_libversion(); /// Ditto immutable(char)* sqlite3_sourceid(); /// Ditto int sqlite3_libversion_number(); /** ** CAPI3REF: Run-Time Library Compilation Options Diagnostics */ int sqlite3_compileoption_used(const char *zOptName); /// Ditto immutable(char)* sqlite3_compileoption_get(int N); /** ** CAPI3REF: Test To See If The Library Is Threadsafe */ int sqlite3_threadsafe(); /** ** CAPI3REF: Database Connection Handle */ struct sqlite3; /// alias long sqlite3_int64; /// alias ulong sqlite3_uint64; /** ** CAPI3REF: Closing A Database Connection ** */ int sqlite3_close(sqlite3 *); int sqlite3_close_v2(sqlite3*); /** ** The type for a callback function. ** This is legacy and deprecated. It is included for historical ** compatibility and is not documented. */ alias sqlite3_callback = int function (void*,int,char**, char**); /** ** CAPI3REF: One-Step Query Execution Interface */ int sqlite3_exec( sqlite3*, /** An open database */ const(char)*sql, /** SQL to be evaluated */ int function (void*,int,char**,char**) callback, /** Callback function */ void *, /** 1st argument to callback */ char **errmsg /** Error msg written here */ ); /** ** CAPI3REF: Result Codes */ enum { SQLITE_OK = 0, /** Successful result */ /* beginning-of-error-codes */ /// Ditto SQLITE_ERROR = 1, /** SQL error or missing database */ SQLITE_INTERNAL = 2, /** Internal logic error in SQLite */ SQLITE_PERM = 3, /** Access permission denied */ SQLITE_ABORT = 4, /** Callback routine requested an abort */ SQLITE_BUSY = 5, /** The database file is locked */ SQLITE_LOCKED = 6, /** A table in the database is locked */ SQLITE_NOMEM = 7, /** A malloc() failed */ SQLITE_READONLY = 8, /** Attempt to write a readonly database */ SQLITE_INTERRUPT = 9, /** Operation terminated by sqlite3_interrupt()*/ SQLITE_IOERR = 10, /** Some kind of disk I/O error occurred */ SQLITE_CORRUPT = 11, /** The database disk image is malformed */ SQLITE_NOTFOUND = 12, /** Unknown opcode in sqlite3_file_control() */ SQLITE_FULL = 13, /** Insertion failed because database is full */ SQLITE_CANTOPEN = 14, /** Unable to open the database file */ SQLITE_PROTOCOL = 15, /** Database lock protocol error */ SQLITE_EMPTY = 16, /** Database is empty */ SQLITE_SCHEMA = 17, /** The database schema changed */ SQLITE_TOOBIG = 18, /** String or BLOB exceeds size limit */ SQLITE_CONSTRAINT = 19, /** Abort due to constraint violation */ SQLITE_MISMATCH = 20, /** Data type mismatch */ SQLITE_MISUSE = 21, /** Library used incorrectly */ SQLITE_NOLFS = 22, /** Uses OS features not supported on host */ SQLITE_AUTH = 23, /** Authorization denied */ SQLITE_FORMAT = 24, /** Auxiliary database format error */ SQLITE_RANGE = 25, /** 2nd parameter to sqlite3_bind out of range */ SQLITE_NOTADB = 26, /** File opened that is not a database file */ SQLITE_NOTICE = 27, SQLITE_WARNING = 28, SQLITE_ROW = 100, /** sqlite3_step() has another row ready */ SQLITE_DONE = 101 /** sqlite3_step() has finished executing */ } /* end-of-error-codes */ /** ** CAPI3REF: Extended Result Codes */ enum { SQLITE_IOERR_READ = (SQLITE_IOERR | (1<<8)), SQLITE_IOERR_SHORT_READ = (SQLITE_IOERR | (2<<8)), SQLITE_IOERR_WRITE = (SQLITE_IOERR | (3<<8)), SQLITE_IOERR_FSYNC = (SQLITE_IOERR | (4<<8)), SQLITE_IOERR_DIR_FSYNC = (SQLITE_IOERR | (5<<8)), SQLITE_IOERR_TRUNCATE = (SQLITE_IOERR | (6<<8)), SQLITE_IOERR_FSTAT = (SQLITE_IOERR | (7<<8)), SQLITE_IOERR_UNLOCK = (SQLITE_IOERR | (8<<8)), SQLITE_IOERR_RDLOCK = (SQLITE_IOERR | (9<<8)), SQLITE_IOERR_DELETE = (SQLITE_IOERR | (10<<8)), SQLITE_IOERR_BLOCKED = (SQLITE_IOERR | (11<<8)), SQLITE_IOERR_NOMEM = (SQLITE_IOERR | (12<<8)), SQLITE_IOERR_ACCESS = (SQLITE_IOERR | (13<<8)), SQLITE_IOERR_CHECKRESERVEDLOCK = (SQLITE_IOERR | (14<<8)), SQLITE_IOERR_LOCK = (SQLITE_IOERR | (15<<8)), SQLITE_IOERR_CLOSE = (SQLITE_IOERR | (16<<8)), SQLITE_IOERR_DIR_CLOSE = (SQLITE_IOERR | (17<<8)), SQLITE_IOERR_SHMOPEN = (SQLITE_IOERR | (18<<8)), SQLITE_IOERR_SHMSIZE = (SQLITE_IOERR | (19<<8)), SQLITE_IOERR_SHMLOCK = (SQLITE_IOERR | (20<<8)), SQLITE_IOERR_SHMMAP = (SQLITE_IOERR | (21<<8)), SQLITE_IOERR_SEEK = (SQLITE_IOERR | (22<<8)), SQLITE_IOERR_DELETE_NOENT = (SQLITE_IOERR | (23<<8)), SQLITE_IOERR_MMAP = (SQLITE_IOERR | (24<<8)), SQLITE_LOCKED_SHAREDCACHE = (SQLITE_LOCKED | (1<<8)), SQLITE_BUSY_RECOVERY = (SQLITE_BUSY | (1<<8)), SQLITE_CANTOPEN_NOTEMPDIR = (SQLITE_CANTOPEN | (1<<8)), SQLITE_IOERR_GETTEMPPATH = (SQLITE_IOERR | (25<<8)), SQLITE_IOERR_CONVPATH = (SQLITE_IOERR | (26<<8)), SQLITE_BUSY_SNAPSHOT = (SQLITE_BUSY | (2<<8)), SQLITE_CANTOPEN_ISDIR = (SQLITE_CANTOPEN | (2<<8)), SQLITE_CANTOPEN_FULLPATH = (SQLITE_CANTOPEN | (3<<8)), SQLITE_CANTOPEN_CONVPATH = (SQLITE_CANTOPEN | (4<<8)), SQLITE_CORRUPT_VTAB = (SQLITE_CORRUPT | (1<<8)), SQLITE_READONLY_RECOVERY = (SQLITE_READONLY | (1<<8)), SQLITE_READONLY_CANTLOCK = (SQLITE_READONLY | (2<<8)), SQLITE_READONLY_ROLLBACK = (SQLITE_READONLY | (3<<8)), SQLITE_READONLY_DBMOVED = (SQLITE_READONLY | (4<<8)), SQLITE_ABORT_ROLLBACK = (SQLITE_ABORT | (2<<8)), SQLITE_CONSTRAINT_CHECK = (SQLITE_CONSTRAINT | (1<<8)), SQLITE_CONSTRAINT_COMMITHOOK = (SQLITE_CONSTRAINT | (2<<8)), SQLITE_CONSTRAINT_FOREIGNKEY = (SQLITE_CONSTRAINT | (3<<8)), SQLITE_CONSTRAINT_FUNCTION = (SQLITE_CONSTRAINT | (4<<8)), SQLITE_CONSTRAINT_NOTNULL = (SQLITE_CONSTRAINT | (5<<8)), SQLITE_CONSTRAINT_PRIMARYKEY = (SQLITE_CONSTRAINT | (6<<8)), SQLITE_CONSTRAINT_TRIGGER = (SQLITE_CONSTRAINT | (7<<8)), SQLITE_CONSTRAINT_UNIQUE = (SQLITE_CONSTRAINT | (8<<8)), SQLITE_CONSTRAINT_VTAB = (SQLITE_CONSTRAINT | (9<<8)), SQLITE_CONSTRAINT_ROWID = (SQLITE_CONSTRAINT |(10<<8)), SQLITE_NOTICE_RECOVER_WAL = (SQLITE_NOTICE | (1<<8)), SQLITE_NOTICE_RECOVER_ROLLBACK = (SQLITE_NOTICE | (2<<8)), SQLITE_WARNING_AUTOINDEX = (SQLITE_WARNING | (1<<8)), SQLITE_AUTH_USER = (SQLITE_AUTH | (1<<8)) } /** ** CAPI3REF: Flags For File Open Operations */ enum { SQLITE_OPEN_READONLY = 0x00000001, /** Ok for sqlite3_open_v2() */ SQLITE_OPEN_READWRITE = 0x00000002, /** Ok for sqlite3_open_v2() */ SQLITE_OPEN_CREATE = 0x00000004, /** Ok for sqlite3_open_v2() */ SQLITE_OPEN_DELETEONCLOSE = 0x00000008, /** VFS only */ SQLITE_OPEN_EXCLUSIVE = 0x00000010, /** VFS only */ SQLITE_OPEN_AUTOPROXY = 0x00000020, /** VFS only */ SQLITE_OPEN_URI = 0x00000040, /** Ok for sqlite3_open_v2() */ SQLITE_OPEN_MEMORY = 0x00000080, /** Ok for sqlite3_open_v2() */ SQLITE_OPEN_MAIN_DB = 0x00000100, /** VFS only */ SQLITE_OPEN_TEMP_DB = 0x00000200, /** VFS only */ SQLITE_OPEN_TRANSIENT_DB = 0x00000400, /** VFS only */ SQLITE_OPEN_MAIN_JOURNAL = 0x00000800, /** VFS only */ SQLITE_OPEN_TEMP_JOURNAL = 0x00001000, /** VFS only */ SQLITE_OPEN_SUBJOURNAL = 0x00002000, /** VFS only */ SQLITE_OPEN_MASTER_JOURNAL = 0x00004000, /** VFS only */ SQLITE_OPEN_NOMUTEX = 0x00008000, /** Ok for sqlite3_open_v2() */ SQLITE_OPEN_FULLMUTEX = 0x00010000, /** Ok for sqlite3_open_v2() */ SQLITE_OPEN_SHAREDCACHE = 0x00020000, /** Ok for sqlite3_open_v2() */ SQLITE_OPEN_PRIVATECACHE = 0x00040000, /** Ok for sqlite3_open_v2() */ SQLITE_OPEN_WAL = 0x00080000 /** VFS only */ } /** ** CAPI3REF: Device Characteristics */ enum { SQLITE_IOCAP_ATOMIC = 0x00000001, SQLITE_IOCAP_ATOMIC512 = 0x00000002, SQLITE_IOCAP_ATOMIC1K = 0x00000004, SQLITE_IOCAP_ATOMIC2K = 0x00000008, SQLITE_IOCAP_ATOMIC4K = 0x00000010, SQLITE_IOCAP_ATOMIC8K = 0x00000020, SQLITE_IOCAP_ATOMIC16K = 0x00000040, SQLITE_IOCAP_ATOMIC32K = 0x00000080, SQLITE_IOCAP_ATOMIC64K = 0x00000100, SQLITE_IOCAP_SAFE_APPEND = 0x00000200, SQLITE_IOCAP_SEQUENTIAL = 0x00000400, SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN = 0x00000800, SQLITE_IOCAP_POWERSAFE_OVERWRITE = 0x00001000, SQLITE_IOCAP_IMMUTABLE = 0x00002000 } /** ** CAPI3REF: File Locking Levels */ enum { SQLITE_LOCK_NONE = 0, SQLITE_LOCK_SHARED = 1, SQLITE_LOCK_RESERVED = 2, SQLITE_LOCK_PENDING = 3, SQLITE_LOCK_EXCLUSIVE = 4 } /** ** CAPI3REF: Synchronization Type Flags */ enum { SQLITE_SYNC_NORMAL = 0x00002, SQLITE_SYNC_FULL = 0x00003, SQLITE_SYNC_DATAONLY = 0x00010 } /** ** CAPI3REF: OS Interface Open File Handle */ struct sqlite3_file { const(sqlite3_io_methods)*pMethods; /* Methods for an open file */ } /** ** CAPI3REF: OS Interface File Virtual Methods Object */ struct sqlite3_io_methods { int iVersion; int function (sqlite3_file*) xClose; int function (sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst) xRead; int function (sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst) xWrite; int function (sqlite3_file*, sqlite3_int64 size) xTruncate; int function (sqlite3_file*, int flags) xSync; int function (sqlite3_file*, sqlite3_int64 *pSize) xFileSize; int function (sqlite3_file*, int) xLock; int function (sqlite3_file*, int) xUnlock; int function (sqlite3_file*, int *pResOut) xCheckReservedLock; int function (sqlite3_file*, int op, void *pArg) xFileControl; int function (sqlite3_file*) xSectorSize; int function (sqlite3_file*) xDeviceCharacteristics; /* Methods above are valid for version 1 */ int function (sqlite3_file*, int iPg, int pgsz, int, void **) xShmMap; int function (sqlite3_file*, int offset, int n, int flags) xShmLock; void function (sqlite3_file*) xShmBarrier; int function (sqlite3_file*, int deleteFlag) xShmUnmap; /* Methods above are valid for version 2 */ /* Additional methods may be added in future releases */ int function (sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp) xFetch; int function (sqlite3_file*, sqlite3_int64 iOfst, void *p) xUnfetch; } /** ** CAPI3REF: Standard File Control Opcodes */ enum { SQLITE_FCNTL_LOCKSTATE = 1, SQLITE_GET_LOCKPROXYFILE = 2, SQLITE_SET_LOCKPROXYFILE = 3, SQLITE_LAST_ERRNO = 4, SQLITE_FCNTL_SIZE_HINT = 5, SQLITE_FCNTL_CHUNK_SIZE = 6, SQLITE_FCNTL_FILE_POINTER = 7, SQLITE_FCNTL_SYNC_OMITTED = 8, SQLITE_FCNTL_WIN32_AV_RETRY = 9, SQLITE_FCNTL_PERSIST_WAL = 10, SQLITE_FCNTL_OVERWRITE = 11, SQLITE_FCNTL_VFSNAME = 12, SQLITE_FCNTL_POWERSAFE_OVERWRITE = 13, SQLITE_FCNTL_PRAGMA = 14, SQLITE_FCNTL_BUSYHANDLER = 15, SQLITE_FCNTL_TEMPFILENAME = 16, SQLITE_FCNTL_MMAP_SIZE = 18, SQLITE_FCNTL_TRACE = 19, SQLITE_FCNTL_HAS_MOVED = 20, SQLITE_FCNTL_SYNC = 21, SQLITE_FCNTL_COMMIT_PHASETWO = 22, SQLITE_FCNTL_WIN32_SET_HANDLE = 23, SQLITE_FCNTL_WAL_BLOCK = 24, SQLITE_FCNTL_ZIPVFS = 25, SQLITE_FCNTL_RBU = 26, SQLITE_FCNTL_VFS_POINTER = 27, } /** ** CAPI3REF: Mutex Handle */ struct sqlite3_mutex; /** ** CAPI3REF: OS Interface Object */ alias void * function() xDlSymReturn; /// Ditto alias void function() sqlite3_syscall_ptr; struct sqlite3_vfs { int iVersion; /** Structure version number (currently 2) */ int szOsFile; /** Size of subclassed sqlite3_file */ int mxPathname; /** Maximum file pathname length */ sqlite3_vfs *pNext; /** Next registered VFS */ const(char)*zName; /** Name of this virtual file system */ void *pAppData; /** Pointer to application-specific data */ int function (sqlite3_vfs*, const char *zName, sqlite3_file*, int flags, int *pOutFlags) xOpen; int function (sqlite3_vfs*, const char *zName, int syncDir) xDelete; int function (sqlite3_vfs*, const char *zName, int flags, int *pResOut) xAccess; int function (sqlite3_vfs*, const char *zName, int nOut, char *zOut) xFullPathname; void* function (sqlite3_vfs*, const char *zFilename) xDlOpen; void function (sqlite3_vfs*, int nByte, char *zErrMsg) xDlError; xDlSymReturn function (sqlite3_vfs*,void*, const char *zSymbol) *xDlSym; void function (sqlite3_vfs*, void*) xDlClose; int function (sqlite3_vfs*, int nByte, char *zOut) xRandomness; int function (sqlite3_vfs*, int microseconds) xSleep; int function (sqlite3_vfs*, double*) xCurrentTime; int function (sqlite3_vfs*, int, char *) xGetLastError; /* ** The methods above are in version 1 of the sqlite_vfs object ** definition. Those that follow are added in version 2 or later */ int function (sqlite3_vfs*, sqlite3_int64*) xCurrentTimeInt64; /* ** The methods above are in versions 1 and 2 of the sqlite_vfs object. ** Those below are for version 3 and greater. */ int function(sqlite3_vfs*, const char * zName, sqlite3_syscall_ptr) xSetSystemCall; sqlite3_syscall_ptr function(sqlite3_vfs*, const char * zName) xGetSystemCall; const(char)* function(sqlite3_vfs*, const char * zName) xNextSystemCall; /* ** The methods above are in versions 1 through 3 of the sqlite_vfs object. ** New fields may be appended in figure versions. The iVersion ** value will increment whenever this happens. */ } /** ** CAPI3REF: Flags for the xAccess VFS method */ enum { SQLITE_ACCESS_EXISTS = 0, SQLITE_ACCESS_READWRITE = 1, /** Used by PRAGMA temp_store_directory */ SQLITE_ACCESS_READ = 2 /** Unused */ } /** ** CAPI3REF: Flags for the xShmLock VFS method */ enum { SQLITE_SHM_UNLOCK = 1, SQLITE_SHM_LOCK = 2, SQLITE_SHM_SHARED = 4, SQLITE_SHM_EXCLUSIVE = 8 } /** ** CAPI3REF: Maximum xShmLock index */ enum SQLITE_SHM_NLOCK = 8; /** ** CAPI3REF: Initialize The SQLite Library */ int sqlite3_initialize(); /// Ditto int sqlite3_shutdown(); /// Ditto int sqlite3_os_init(); /// Ditto int sqlite3_os_end(); /** ** CAPI3REF: Configuring The SQLite Library */ int sqlite3_config(int, ...); /** ** CAPI3REF: Configure database connections */ int sqlite3_db_config(sqlite3*, int op, ...); /** ** CAPI3REF: Memory Allocation Routines */ struct sqlite3_mem_methods { void* function (int) xMalloc; /** Memory allocation function */ void function (void*) xFree; /** Free a prior allocation */ void* function (void*,int) xRealloc; /** Resize an allocation */ int function (void*) xSize; /** Return the size of an allocation */ int function (int) xRoundup; /** Round up request size to allocation size */ int function (void*) xInit; /** Initialize the memory allocator */ void function (void*) xShutdown; /** Deinitialize the memory allocator */ void *pAppData; /** Argument to xInit() and xShutdown() */ } /** ** CAPI3REF: Configuration Options */ enum { SQLITE_CONFIG_SINGLETHREAD = 1, /** nil */ SQLITE_CONFIG_MULTITHREAD = 2, /** nil */ SQLITE_CONFIG_SERIALIZED = 3, /** nil */ SQLITE_CONFIG_MALLOC = 4, /** sqlite3_mem_methods* */ SQLITE_CONFIG_GETMALLOC = 5, /** sqlite3_mem_methods* */ SQLITE_CONFIG_SCRATCH = 6, /** void*, int sz, int N */ SQLITE_CONFIG_PAGECACHE = 7, /** void*, int sz, int N */ SQLITE_CONFIG_HEAP = 8, /** void*, int nByte, int min */ SQLITE_CONFIG_MEMSTATUS = 9, /** boolean */ SQLITE_CONFIG_MUTEX = 10, /** sqlite3_mutex_methods* */ SQLITE_CONFIG_GETMUTEX = 11, /** sqlite3_mutex_methods* */ /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ SQLITE_CONFIG_LOOKASIDE = 13, /** int int */ SQLITE_CONFIG_PCACHE = 14, /** sqlite3_pcache_methods* */ SQLITE_CONFIG_GETPCACHE = 15, /** sqlite3_pcache_methods* */ SQLITE_CONFIG_LOG = 16, /** xFunc, void* */ SQLITE_CONFIG_URI = 17, SQLITE_CONFIG_PCACHE2 = 18, SQLITE_CONFIG_GETPCACHE2 = 19, SQLITE_CONFIG_COVERING_INDEX_SCAN = 20, SQLITE_CONFIG_SQLLOG = 21, SQLITE_CONFIG_MMAP_SIZE = 22, SQLITE_CONFIG_WIN32_HEAPSIZE = 23, SQLITE_CONFIG_PCACHE_HDRSZ = 24, SQLITE_CONFIG_PMASZ = 25, } /** ** CAPI3REF: Database Connection Configuration Options */ enum { SQLITE_DBCONFIG_LOOKASIDE = 1001, /** void* int int */ SQLITE_DBCONFIG_ENABLE_FKEY = 1002, /** int int* */ SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003 /** int int* */ } /** ** CAPI3REF: Enable Or Disable Extended Result Codes */ int sqlite3_extended_result_codes(sqlite3*, int onoff); /** ** CAPI3REF: Last Insert Rowid */ sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); /** ** CAPI3REF: Count The Number Of Rows Modified */ int sqlite3_changes(sqlite3*); /** ** CAPI3REF: Total Number Of Rows Modified */ int sqlite3_total_changes(sqlite3*); /** ** CAPI3REF: Interrupt A Long-Running Query */ void sqlite3_interrupt(sqlite3*); /** ** CAPI3REF: Determine If An SQL Statement Is Complete */ int sqlite3_complete(const char *sql); /// Ditto int sqlite3_complete16(const void *sql); /** ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors */ int sqlite3_busy_handler(sqlite3*, int function (void*,int), void*); /** ** CAPI3REF: Set A Busy Timeout */ int sqlite3_busy_timeout(sqlite3*, int ms); /** ** CAPI3REF: Convenience Routines For Running Queries */ int sqlite3_get_table( sqlite3 *db, /** An open database */ const(char)*zSql, /** SQL to be evaluated */ char ***pazResult, /** Results of the query */ int *pnRow, /** Number of result rows written here */ int *pnColumn, /** Number of result columns written here */ char **pzErrmsg /** Error msg written here */ ); /// void sqlite3_free_table(char **result); /** ** CAPI3REF: Formatted String Printing Functions */ char *sqlite3_mprintf(const char*,...); char *sqlite3_vmprintf(const char*, va_list); char *sqlite3_snprintf(int,char*,const char*, ...); char *sqlite3_vsnprintf(int,char*,const char*, va_list); /** ** CAPI3REF: Memory Allocation Subsystem */ void *sqlite3_malloc(int); /// Ditto void *sqlite3_malloc64(sqlite3_uint64); /// Ditto void *sqlite3_realloc(void*, int); /// Ditto void *sqlite3_realloc64(void*, sqlite3_uint64); /// Ditto void sqlite3_free(void*); /// Ditto sqlite3_uint64 sqlite3_msize(void*); /** ** CAPI3REF: Memory Allocator Statistics */ sqlite3_int64 sqlite3_memory_used(); sqlite3_int64 sqlite3_memory_highwater(int resetFlag); /** ** CAPI3REF: Pseudo-Random Number Generator */ void sqlite3_randomness(int N, void *P); /** ** CAPI3REF: Compile-Time Authorization Callbacks */ int sqlite3_set_authorizer( sqlite3*, int function (void*,int,const char*,const char*,const char*,const char*) xAuth, void *pUserData ); /** ** CAPI3REF: Authorizer Return Codes */ enum { SQLITE_DENY = 1, /** Abort the SQL statement with an error */ SQLITE_IGNORE = 2 /** Don't allow access, but don't generate an error */ } /** ** CAPI3REF: Authorizer Action Codes */ /******************************************* 3rd ************ 4th ***********/ enum { SQLITE_CREATE_INDEX = 1, /** Index Name Table Name */ SQLITE_CREATE_TABLE = 2, /** Table Name NULL */ SQLITE_CREATE_TEMP_INDEX = 3, /** Index Name Table Name */ SQLITE_CREATE_TEMP_TABLE = 4, /** Table Name NULL */ SQLITE_CREATE_TEMP_TRIGGER = 5, /** Trigger Name Table Name */ SQLITE_CREATE_TEMP_VIEW = 6, /** View Name NULL */ SQLITE_CREATE_TRIGGER = 7, /** Trigger Name Table Name */ SQLITE_CREATE_VIEW = 8, /** View Name NULL */ SQLITE_DELETE = 9, /** Table Name NULL */ SQLITE_DROP_INDEX = 10, /** Index Name Table Name */ SQLITE_DROP_TABLE = 11, /** Table Name NULL */ SQLITE_DROP_TEMP_INDEX = 12, /** Index Name Table Name */ SQLITE_DROP_TEMP_TABLE = 13, /** Table Name NULL */ SQLITE_DROP_TEMP_TRIGGER = 14, /** Trigger Name Table Name */ SQLITE_DROP_TEMP_VIEW = 15, /** View Name NULL */ SQLITE_DROP_TRIGGER = 16, /** Trigger Name Table Name */ SQLITE_DROP_VIEW = 17, /** View Name NULL */ SQLITE_INSERT = 18, /** Table Name NULL */ SQLITE_PRAGMA = 19, /** Pragma Name 1st arg or NULL */ SQLITE_READ = 20, /** Table Name Column Name */ SQLITE_SELECT = 21, /** NULL NULL */ SQLITE_TRANSACTION = 22, /** Operation NULL */ SQLITE_UPDATE = 23, /** Table Name Column Name */ SQLITE_ATTACH = 24, /** Filename NULL */ SQLITE_DETACH = 25, /** Database Name NULL */ SQLITE_ALTER_TABLE = 26, /** Database Name Table Name */ SQLITE_REINDEX = 27, /** Index Name NULL */ SQLITE_ANALYZE = 28, /** Table Name NULL */ SQLITE_CREATE_VTABLE = 29, /** Table Name Module Name */ SQLITE_DROP_VTABLE = 30, /** Table Name Module Name */ SQLITE_FUNCTION = 31, /** NULL Function Name */ SQLITE_SAVEPOINT = 32, /** Operation Savepoint Name */ SQLITE_COPY = 0, /** No longer used */ SQLITE_RECURSIVE = 33 } /** ** CAPI3REF: Tracing And Profiling Functions */ void *sqlite3_trace(sqlite3*, void function (void*,const char*) xTrace, void*); /// Ditto void *sqlite3_profile(sqlite3*, void function (void*,const char*,sqlite3_uint64) xProfile, void*); /** ** CAPI3REF: Query Progress Callbacks */ void sqlite3_progress_handler(sqlite3*, int, int function (void*), void*); /** ** CAPI3REF: Opening A New Database Connection */ int sqlite3_open( const(char)*filename, /** Database filename (UTF-8) */ sqlite3 **ppDb /** OUT: SQLite db handle */ ); /// Ditto int sqlite3_open16( const(void)*filename, /** Database filename (UTF-16) */ sqlite3 **ppDb /** OUT: SQLite db handle */ ); /// Ditto int sqlite3_open_v2( const(char)*filename, /** Database filename (UTF-8) */ sqlite3 **ppDb, /** OUT: SQLite db handle */ int flags, /** Flags */ const(char)*zVfs /** Name of VFS module to use */ ); /* ** CAPI3REF: Obtain Values For URI Parameters */ const(char)* sqlite3_uri_parameter(const(char)* zFilename, const(char)* zParam); /// Ditto int sqlite3_uri_boolean(const(char)* zFile, const(char)* zParam, int bDefault); /// Ditto sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); /** ** CAPI3REF: Error Codes And Messages */ int sqlite3_errcode(sqlite3 *db); /// Ditto int sqlite3_extended_errcode(sqlite3 *db); /// Ditto const(char)* sqlite3_errmsg(sqlite3*); /// Ditto const(void)* sqlite3_errmsg16(sqlite3*); /// Ditto const(char)* sqlite3_errstr(int); /** ** CAPI3REF: SQL Statement Object */ struct sqlite3_stmt; /** ** CAPI3REF: Run-time Limits */ int sqlite3_limit(sqlite3*, int id, int newVal); /** ** CAPI3REF: Run-Time Limit Categories */ enum { SQLITE_LIMIT_LENGTH = 0, SQLITE_LIMIT_SQL_LENGTH = 1, SQLITE_LIMIT_COLUMN = 2, SQLITE_LIMIT_EXPR_DEPTH = 3, SQLITE_LIMIT_COMPOUND_SELECT = 4, SQLITE_LIMIT_VDBE_OP = 5, SQLITE_LIMIT_FUNCTION_ARG = 6, SQLITE_LIMIT_ATTACHED = 7, SQLITE_LIMIT_LIKE_PATTERN_LENGTH = 8, SQLITE_LIMIT_VARIABLE_NUMBER = 9, SQLITE_LIMIT_TRIGGER_DEPTH = 10, SQLITE_LIMIT_WORKER_THREADS = 11, } /** ** CAPI3REF: Compiling An SQL Statement */ int sqlite3_prepare( sqlite3 *db, /** Database handle */ const(char)*zSql, /** SQL statement, UTF-8 encoded */ int nByte, /** Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /** OUT: Statement handle */ const(char*)*pzTail /** OUT: Pointer to unused portion of zSql */ ); /// Ditto int sqlite3_prepare_v2( sqlite3 *db, /** Database handle */ const(char)*zSql, /** SQL statement, UTF-8 encoded */ int nByte, /** Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /** OUT: Statement handle */ const(char*)*pzTail /** OUT: Pointer to unused portion of zSql */ ); /// Ditto int sqlite3_prepare16( sqlite3 *db, /** Database handle */ const(void)*zSql, /** SQL statement, UTF-16 encoded */ int nByte, /** Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /** OUT: Statement handle */ const(void*)*pzTail /** OUT: Pointer to unused portion of zSql */ ); /// Ditto int sqlite3_prepare16_v2( sqlite3 *db, /** Database handle */ const(void)*zSql, /** SQL statement, UTF-16 encoded */ int nByte, /** Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /** OUT: Statement handle */ const(void*)*pzTail /** OUT: Pointer to unused portion of zSql */ ); /** ** CAPI3REF: Retrieving Statement SQL */ const(char)* sqlite3_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database */ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /** ** CAPI3REF: Determine If A Prepared Statement Has Been Reset */ int sqlite3_stmt_busy(sqlite3_stmt*); /** ** CAPI3REF: Dynamically Typed Value Object */ struct sqlite3_value; /** ** CAPI3REF: SQL Function Context Object */ struct sqlite3_context; /** ** CAPI3REF: Binding Values To Prepared Statements */ int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void function (void*)); /// Ditto int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,void function (void*)); /// Ditto int sqlite3_bind_double(sqlite3_stmt*, int, double); /// Ditto int sqlite3_bind_int(sqlite3_stmt*, int, int); /// Ditto int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); /// Ditto int sqlite3_bind_null(sqlite3_stmt*, int); /// Ditto int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void function (void*)); /// Ditto int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void function (void*)); /// Ditto int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,void function (void*), ubyte encoding); /// Ditto int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); /// Ditto int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); /// Ditto int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64 n); /** ** CAPI3REF: Number Of SQL Parameters */ int sqlite3_bind_parameter_count(sqlite3_stmt*); /** ** CAPI3REF: Name Of A Host Parameter */ const(char)* sqlite3_bind_parameter_name(sqlite3_stmt*, int); /** ** CAPI3REF: Index Of A Parameter With A Given Name */ int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); /** ** CAPI3REF: Reset All Bindings On A Prepared Statement */ int sqlite3_clear_bindings(sqlite3_stmt*); /** ** CAPI3REF: Number Of Columns In A Result Set */ int sqlite3_column_count(sqlite3_stmt *pStmt); /** ** CAPI3REF: Column Names In A Result Set */ const(char)* sqlite3_column_name(sqlite3_stmt*, int N); /// Ditto const(void)* sqlite3_column_name16(sqlite3_stmt*, int N); /** ** CAPI3REF: Source Of Data In A Query Result */ const(char)* sqlite3_column_database_name(sqlite3_stmt*,int); /// Ditto const(void)* sqlite3_column_database_name16(sqlite3_stmt*,int); /// Ditto const(char)* sqlite3_column_table_name(sqlite3_stmt*,int); /// Ditto const (void)* sqlite3_column_table_name16(sqlite3_stmt*,int); /// Ditto const (char)* sqlite3_column_origin_name(sqlite3_stmt*,int); /// Ditto const (void)* sqlite3_column_origin_name16(sqlite3_stmt*,int); /** ** CAPI3REF: Declared Datatype Of A Query Result */ const (char)* sqlite3_column_decltype(sqlite3_stmt*,int); /// Ditto const (void)* sqlite3_column_decltype16(sqlite3_stmt*,int); /** ** CAPI3REF: Evaluate An SQL Statement */ int sqlite3_step(sqlite3_stmt*); /** ** CAPI3REF: Number of columns in a result set */ int sqlite3_data_count(sqlite3_stmt *pStmt); /** ** CAPI3REF: Fundamental Datatypes */ enum { SQLITE_INTEGER = 1, SQLITE_FLOAT = 2, SQLITE_BLOB = 4, SQLITE_NULL = 5, SQLITE3_TEXT = 3 } /** ** CAPI3REF: Result Values From A Query */ const (void)* sqlite3_column_blob(sqlite3_stmt*, int iCol); /// Ditto int sqlite3_column_bytes(sqlite3_stmt*, int iCol); /// Ditto int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); /// Ditto double sqlite3_column_double(sqlite3_stmt*, int iCol); /// Ditto int sqlite3_column_int(sqlite3_stmt*, int iCol); /// Ditto sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); /// Ditto const (char)* sqlite3_column_text(sqlite3_stmt*, int iCol); /// Ditto const (void)* sqlite3_column_text16(sqlite3_stmt*, int iCol); /// Ditto int sqlite3_column_type(sqlite3_stmt*, int iCol); /// Ditto sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); /** ** CAPI3REF: Destroy A Prepared Statement Object */ int sqlite3_finalize(sqlite3_stmt *pStmt); /** ** CAPI3REF: Reset A Prepared Statement Object */ int sqlite3_reset(sqlite3_stmt *pStmt); /** ** CAPI3REF: Create Or Redefine SQL Functions */ int sqlite3_create_function( sqlite3 *db, const(char)*zFunctionName, int nArg, int eTextRep, void *pApp, void function (sqlite3_context*,int,sqlite3_value**) xFunc, void function (sqlite3_context*,int,sqlite3_value**) xStep, void function (sqlite3_context*) xFinal ); /// Ditto int sqlite3_create_function16( sqlite3 *db, const(void)*zFunctionName, int nArg, int eTextRep, void *pApp, void function (sqlite3_context*,int,sqlite3_value**) xFunc, void function (sqlite3_context*,int,sqlite3_value**) xStep, void function (sqlite3_context*) xFinal ); /// Ditto int sqlite3_create_function_v2( sqlite3 *db, const(char)*zFunctionName, int nArg, int eTextRep, void *pApp, void function (sqlite3_context*,int,sqlite3_value**) xFunc, void function (sqlite3_context*,int,sqlite3_value**) xStep, void function (sqlite3_context*) xFinal, void function (void*) xDestroy ); /** ** CAPI3REF: Text Encodings ** ** These constant define integer codes that represent the various ** text encodings supported by SQLite. */ enum { SQLITE_UTF8 = 1, SQLITE_UTF16LE = 2, SQLITE_UTF16BE = 3 } /// Ditto enum { SQLITE_UTF16 = 4, /** Use native byte order */ SQLITE_ANY = 5, /** sqlite3_create_function only */ SQLITE_UTF16_ALIGNED = 8 /** sqlite3_create_collation only */ } /** ** CAPI3REF: Function Flags */ enum SQLITE_DETERMINISTIC = 0x800; /** ** CAPI3REF: Deprecated Functions */ deprecated int sqlite3_aggregate_count(sqlite3_context*); deprecated int sqlite3_expired(sqlite3_stmt*); deprecated int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); deprecated int sqlite3_global_recover(); deprecated void sqlite3_thread_cleanup(); deprecated int sqlite3_memory_alarm(void function(void*,sqlite3_int64,int),void*,sqlite3_int64); /** ** CAPI3REF: Obtaining SQL Function Parameter Values */ const (void)* sqlite3_value_blob(sqlite3_value*); /// Ditto int sqlite3_value_bytes(sqlite3_value*); /// Ditto int sqlite3_value_bytes16(sqlite3_value*); /// Ditto double sqlite3_value_double(sqlite3_value*); /// Ditto int sqlite3_value_int(sqlite3_value*); /// Ditto sqlite3_int64 sqlite3_value_int64(sqlite3_value*); /// Ditto const (char)* sqlite3_value_text(sqlite3_value*); /// Ditto const (void)* sqlite3_value_text16(sqlite3_value*); /// Ditto const (void)* sqlite3_value_text16le(sqlite3_value*); /// Ditto const (void)* sqlite3_value_text16be(sqlite3_value*); /// Ditto int sqlite3_value_type(sqlite3_value*); /// Ditto int sqlite3_value_numeric_type(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values */ uint sqlite3_value_subtype(sqlite3_value*); /* ** CAPI3REF: Copy And Free SQL Values */ sqlite3_value* sqlite3_value_dup(const sqlite3_value*); void sqlite3_value_free(sqlite3_value*); /** ** CAPI3REF: Obtain Aggregate Function Context */ void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); /** ** CAPI3REF: User Data For Functions */ void *sqlite3_user_data(sqlite3_context*); /** ** CAPI3REF: Database Connection For Functions */ sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /** ** CAPI3REF: Function Auxiliary Data */ void *sqlite3_get_auxdata(sqlite3_context*, int N); /// Ditto void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void function (void*)); /** ** CAPI3REF: Constants Defining Special Destructor Behavior */ alias void function (void*) sqlite3_destructor_type; /// Ditto enum { SQLITE_STATIC = (cast(sqlite3_destructor_type) 0), SQLITE_TRANSIENT = (cast (sqlite3_destructor_type) -1) } /** ** CAPI3REF: Setting The Result Of An SQL Function */ void sqlite3_result_blob(sqlite3_context*, const void*, int, void function(void*)); /// Ditto void sqlite3_result_blob64(sqlite3_context*,const void*,sqlite3_uint64,void function(void*)); /// Ditto void sqlite3_result_double(sqlite3_context*, double); /// Ditto void sqlite3_result_error(sqlite3_context*, const char*, int); /// Ditto void sqlite3_result_error16(sqlite3_context*, const void*, int); /// Ditto void sqlite3_result_error_toobig(sqlite3_context*); /// Ditto void sqlite3_result_error_nomem(sqlite3_context*); /// Ditto void sqlite3_result_error_code(sqlite3_context*, int); /// Ditto void sqlite3_result_int(sqlite3_context*, int); /// Ditto void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); /// Ditto void sqlite3_result_null(sqlite3_context*); /// Ditto void sqlite3_result_text(sqlite3_context*, const char*, int, void function(void*)); /// Ditto void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,void function(void*), ubyte encoding); /// Ditto void sqlite3_result_text16(sqlite3_context*, const void*, int, void function(void*)); /// Ditto void sqlite3_result_text16le(sqlite3_context*, const void*, int, void function(void*)); /// Ditto void sqlite3_result_text16be(sqlite3_context*, const void*, int, void function(void*)); /// Ditto void sqlite3_result_value(sqlite3_context*, sqlite3_value*); /// Ditto void sqlite3_result_zeroblob(sqlite3_context*, int n); /// Ditto int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); /* ** CAPI3REF: Setting The Subtype Of An SQL Function */ void sqlite3_result_subtype(sqlite3_context*,uint); /** ** CAPI3REF: Define New Collating Sequences */ int sqlite3_create_collation( sqlite3*, const(char)*zName, int eTextRep, void *pArg, int function (void*,int,const void*,int,const void*) xCompare ); /// Ditto int sqlite3_create_collation_v2( sqlite3*, const(char)*zName, int eTextRep, void *pArg, int function (void*,int,const void*,int,const void*) xCompare, void function (void*) xDestroy ); /// Ditto int sqlite3_create_collation16( sqlite3*, const(void)*zName, int eTextRep, void *pArg, int function (void*,int,const void*,int,const void*) xCompare ); /** ** CAPI3REF: Collation Needed Callbacks */ int sqlite3_collation_needed( sqlite3*, void*, void function (void*,sqlite3*,int eTextRep,const char*) ); /// Ditto int sqlite3_collation_needed16( sqlite3*, void*, void function (void*,sqlite3*,int eTextRep,const void*) ); /// int sqlite3_key( sqlite3 *db, /** Database to be rekeyed */ const(void)*pKey, int nKey /** The key */ ); /// Ditto int sqlite3_key_v2( sqlite3 *db, /* Database to be rekeyed */ const(char)* zDbName, /* Name of the database */ const(void)* pKey, int nKey /* The key */ ); /** ** Change the key on an open database. If the current database is not ** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the ** database is decrypted. ** ** The code to implement this API is not available in the public release ** of SQLite. */ int sqlite3_rekey( sqlite3 *db, /** Database to be rekeyed */ const(void)*pKey, int nKey /** The new key */ ); int sqlite3_rekey_v2( sqlite3 *db, /* Database to be rekeyed */ const(char)* zDbName, /* Name of the database */ const(void)* pKey, int nKey /* The new key */ ); /** ** Specify the activation key for a SEE database. Unless ** activated, none of the SEE routines will work. */ void sqlite3_activate_see( const(char)*zPassPhrase /** Activation phrase */ ); /** ** Specify the activation key for a CEROD database. Unless ** activated, none of the CEROD routines will work. */ void sqlite3_activate_cerod( const(char)*zPassPhrase /** Activation phrase */ ); /** ** CAPI3REF: Suspend Execution For A Short Time */ int sqlite3_sleep(int); /** ** CAPI3REF: Name Of The Folder Holding Temporary Files */ extern char *sqlite3_temp_directory; /** ** CAPI3REF: Name Of The Folder Holding Database Files */ extern char *sqlite3_data_directory; /** ** CAPI3REF: Test For Auto-Commit Mode */ int sqlite3_get_autocommit(sqlite3*); /** ** CAPI3REF: Find The Database Handle Of A Prepared Statement */ sqlite3 *sqlite3_db_handle(sqlite3_stmt*); /** ** CAPI3REF: Return The Filename For A Database Connection */ const(char)* sqlite3_db_filename(sqlite3 *db, const char* zDbName); /** ** CAPI3REF: Determine if a database is read-only */ int sqlite3_db_readonly(sqlite3 *db, const char * zDbName); /* ** CAPI3REF: Find the next prepared statement */ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); /** ** CAPI3REF: Commit And Rollback Notification Callbacks */ void *sqlite3_commit_hook(sqlite3*, int function (void*), void*); /// Ditto void *sqlite3_rollback_hook(sqlite3*, void function (void *), void*); /** ** CAPI3REF: Data Change Notification Callbacks */ void *sqlite3_update_hook( sqlite3*, void function (void *,int ,char *, char *, sqlite3_int64), void* ); /** ** CAPI3REF: Enable Or Disable Shared Pager Cache */ int sqlite3_enable_shared_cache(int); /** ** CAPI3REF: Attempt To Free Heap Memory */ int sqlite3_release_memory(int); /** ** CAPI3REF: Free Memory Used By A Database Connection */ int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size */ sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); /** ** CAPI3REF: Deprecated Soft Heap Limit Interface */ deprecated void sqlite3_soft_heap_limit(int N); /** ** CAPI3REF: Extract Metadata About A Column Of A Table */ int sqlite3_table_column_metadata( sqlite3 *db, /** Connection handle */ const(char)*zDbName, /** Database name or NULL */ const(char)*zTableName, /** Table name */ const(char)*zColumnName, /** Column name */ char **pzDataType, /** OUTPUT: Declared data type */ char **pzCollSeq, /** OUTPUT: Collation sequence name */ int *pNotNull, /** OUTPUT: True if NOT NULL constraint exists */ int *pPrimaryKey, /** OUTPUT: True if column part of PK */ int *pAutoinc /** OUTPUT: True if column is auto-increment */ ); /** ** CAPI3REF: Load An Extension */ int sqlite3_load_extension( sqlite3 *db, /** Load the extension into this database connection */ const(char)*zFile, /** Name of the shared library containing extension */ const(char)*zProc, /** Entry point. Derived from zFile if 0 */ char **pzErrMsg /** Put error message here if not 0 */ ); /** ** CAPI3REF: Enable Or Disable Extension Loading */ int sqlite3_enable_load_extension(sqlite3 *db, int onoff); /** ** CAPI3REF: Automatically Load Statically Linked Extensions */ int sqlite3_auto_extension(void function () xEntryPoint); /** ** CAPI3REF: Cancel Automatic Extension Loading */ int sqlite3_cancel_auto_extension(void function() xEntryPoint); /** ** CAPI3REF: Reset Automatic Extension Loading */ void sqlite3_reset_auto_extension(); /** ** The interface to the virtual-table mechanism is currently considered ** to be experimental. The interface might change in incompatible ways. ** If this is a problem for you, do not use the interface at this time. ** ** When the virtual-table mechanism stabilizes, we will declare the ** interface fixed, support it indefinitely, and remove this comment. */ /** ** CAPI3REF: Virtual Table Object */ alias void function (sqlite3_context*,int,sqlite3_value**) mapFunction; /// Ditto struct sqlite3_module { int iVersion; int function (sqlite3*, void *pAux, int argc, const char **argv, sqlite3_vtab **ppVTab, char**) xCreate; int function (sqlite3*, void *pAux, int argc, const char **argv, sqlite3_vtab **ppVTab, char**) xConnect; int function (sqlite3_vtab *pVTab, sqlite3_index_info*) xBestIndex; int function (sqlite3_vtab *pVTab) xDisconnect; int function (sqlite3_vtab *pVTab) xDestroy; int function (sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) xOpen; int function (sqlite3_vtab_cursor*) xClose; int function (sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) xFilter; int function (sqlite3_vtab_cursor*) xNext; int function (sqlite3_vtab_cursor*) xEof; int function (sqlite3_vtab_cursor*, sqlite3_context*, int) xColumn; int function (sqlite3_vtab_cursor*, sqlite3_int64 *pRowid) xRowid; int function (sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *) xUpdate; int function (sqlite3_vtab *pVTab) xBegin; int function (sqlite3_vtab *pVTab) xSync; int function (sqlite3_vtab *pVTab) xCommit; int function (sqlite3_vtab *pVTab) xRollback; int function (sqlite3_vtab *pVtab, int nArg, const char *zName, mapFunction*, void **ppArg) xFindFunction; int function (sqlite3_vtab *pVtab, const char *zNew) xRename; int function (sqlite3_vtab *pVTab, int) xSavepoint; int function (sqlite3_vtab *pVTab, int) xRelease; int function (sqlite3_vtab *pVTab, int) xRollbackTo; } /** ** CAPI3REF: Virtual Table Indexing Information */ struct sqlite3_index_info { struct sqlite3_index_constraint { int iColumn; /** Column on left-hand side of constraint */ char op; /** Constraint operator */ char usable; /** True if this constraint is usable */ int iTermOffset; /** Used internally - xBestIndex should ignore */ } struct sqlite3_index_orderby { int iColumn; /** Column number */ char desc; /** True for DESC. False for ASC. */ } struct sqlite3_index_constraint_usage { int argvIndex; /** if >0, constraint is part of argv to xFilter */ char omit; /** Do not code a test for this constraint */ } /* Inputs */ int nConstraint; /** Number of entries in aConstraint */ sqlite3_index_constraint* aConstraint; /** Table of WHERE clause constraints */ int nOrderBy; /** Number of terms in the ORDER BY clause */ sqlite3_index_orderby *aOrderBy; /** The ORDER BY clause */ /* Outputs */ sqlite3_index_constraint_usage *aConstraintUsage; int idxNum; /** Number used to identify the index */ char *idxStr; /** String, possibly obtained from sqlite3_malloc */ int needToFreeIdxStr; /** Free idxStr using sqlite3_free() if true */ int orderByConsumed; /** True if output is already ordered */ double estimatedCost; /** Estimated cost of using this index */ sqlite3_int64 estimatedRows; int idxFlags; sqlite3_uint64 colUsed; } /** ** CAPI3REF: Virtual Table Constraint Operator Codes */ enum { SQLITE_INDEX_SCAN_UNIQUE = 1, SQLITE_INDEX_CONSTRAINT_EQ = 2, SQLITE_INDEX_CONSTRAINT_GT = 4, SQLITE_INDEX_CONSTRAINT_LE = 8, SQLITE_INDEX_CONSTRAINT_LT = 16, SQLITE_INDEX_CONSTRAINT_GE = 32, SQLITE_INDEX_CONSTRAINT_MATCH = 64, SQLITE_INDEX_CONSTRAINT_LIKE = 65, SQLITE_INDEX_CONSTRAINT_GLOB = 66, SQLITE_INDEX_CONSTRAINT_REGEXP = 67, } /** ** CAPI3REF: Register A Virtual Table Implementation */ int sqlite3_create_module( sqlite3 *db, /* SQLite connection to register module with */ const(char)*zName, /* Name of the module */ const(sqlite3_module)*p, /* Methods for the module */ void *pClientData /* Client data for xCreate/xConnect */ ); /// Ditto int sqlite3_create_module_v2( sqlite3 *db, /* SQLite connection to register module with */ const(char)*zName, /* Name of the module */ const(sqlite3_module)*p, /* Methods for the module */ void *pClientData, /* Client data for xCreate/xConnect */ void function (void*) xDestroy /* Module destructor function */ ); /** ** CAPI3REF: Virtual Table Instance Object */ struct sqlite3_vtab { const(sqlite3_module)*pModule; /** The module for this virtual table */ int nRef; /** NO LONGER USED */ char *zErrMsg; /** Error message from sqlite3_mprintf() */ /* Virtual table implementations will typically add additional fields */ } /** ** CAPI3REF: Virtual Table Cursor Object */ struct sqlite3_vtab_cursor { sqlite3_vtab *pVtab; /** Virtual table of this cursor */ /* Virtual table implementations will typically add additional fields */ } /** ** CAPI3REF: Declare The Schema Of A Virtual Table */ int sqlite3_declare_vtab(sqlite3*, const char *zSQL); /** ** CAPI3REF: Overload A Function For A Virtual Table */ int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); /** ** The interface to the virtual-table mechanism defined above (back up ** to a comment remarkably similar to this one) is currently considered ** to be experimental. The interface might change in incompatible ways. ** If this is a problem for you, do not use the interface at this time. ** ** When the virtual-table mechanism stabilizes, we will declare the ** interface fixed, support it indefinitely, and remove this comment. */ /* ** CAPI3REF: A Handle To An Open BLOB */ struct sqlite3_blob; /** ** CAPI3REF: Open A BLOB For Incremental I/O */ int sqlite3_blob_open( sqlite3*, const(char)* zDb, const(char)* zTable, const(char)* zColumn, sqlite3_int64 iRow, int flags, sqlite3_blob **ppBlob ); /** ** CAPI3REF: Move a BLOB Handle to a New Row */ int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); /** ** CAPI3REF: Close A BLOB Handle */ int sqlite3_blob_close(sqlite3_blob *); /** ** CAPI3REF: Return The Size Of An Open BLOB */ int sqlite3_blob_bytes(sqlite3_blob *); /** ** CAPI3REF: Read Data From A BLOB Incrementally */ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); /** ** CAPI3REF: Write Data Into A BLOB Incrementally */ int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); /** ** CAPI3REF: Virtual File System Objects */ sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); /// Ditto int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); /// Ditto int sqlite3_vfs_unregister(sqlite3_vfs*); /** ** CAPI3REF: Mutexes */ sqlite3_mutex *sqlite3_mutex_alloc(int); /// Ditto void sqlite3_mutex_free(sqlite3_mutex*); /// Ditto void sqlite3_mutex_enter(sqlite3_mutex*); /// Ditto int sqlite3_mutex_try(sqlite3_mutex*); /// Ditto void sqlite3_mutex_leave(sqlite3_mutex*); /** ** CAPI3REF: Mutex Methods Object */ struct sqlite3_mutex_methods { int function () xMutexInit; int function () xMutexEnd; sqlite3_mutex* function (int) xMutexAlloc; void function (sqlite3_mutex *) xMutexFree; void function (sqlite3_mutex *) xMutexEnter; int function (sqlite3_mutex *) xMutexTry; void function (sqlite3_mutex *) xMutexLeave; int function (sqlite3_mutex *) xMutexHeld; int function (sqlite3_mutex *) xMutexNotheld; } /** ** CAPI3REF: Mutex Verification Routines */ //#ifndef NDEBUG int sqlite3_mutex_held(sqlite3_mutex*); /// Ditto int sqlite3_mutex_notheld(sqlite3_mutex*); //#endif /** ** CAPI3REF: Mutex Types */ enum { SQLITE_MUTEX_FAST = 0, SQLITE_MUTEX_RECURSIVE = 1, SQLITE_MUTEX_STATIC_MASTER = 2, SQLITE_MUTEX_STATIC_MEM = 3, /** sqlite3_malloc() */ SQLITE_MUTEX_STATIC_MEM2 = 4, /** NOT USED */ SQLITE_MUTEX_STATIC_OPEN = 4, /** sqlite3BtreeOpen() */ SQLITE_MUTEX_STATIC_PRNG = 5, /** sqlite3_random() */ SQLITE_MUTEX_STATIC_LRU = 6, /** lru page list */ SQLITE_MUTEX_STATIC_LRU2 = 7, /** NOT USED */ SQLITE_MUTEX_STATIC_PMEM = 7, /** sqlite3PageMalloc() */ SQLITE_MUTEX_STATIC_APP1 = 8, /** For use by application */ SQLITE_MUTEX_STATIC_APP2 = 9, /** For use by application */ SQLITE_MUTEX_STATIC_APP3 = 10, /** For use by application */ SQLITE_MUTEX_STATIC_VFS1 = 11, /** For use by built-in VFS */ SQLITE_MUTEX_STATIC_VFS2 = 12, /** For use by extension VFS */ SQLITE_MUTEX_STATIC_VFS3 = 13, /** For use by application VFS */ } /** ** CAPI3REF: Retrieve the mutex for a database connection */ sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /** ** CAPI3REF: Low-Level Control Of Database Files */ int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); /** ** CAPI3REF: Testing Interface */ int sqlite3_test_control(int op, ...); /** ** CAPI3REF: Testing Interface Operation Codes */ enum { SQLITE_TESTCTRL_FIRST = 5, SQLITE_TESTCTRL_PRNG_SAVE = 5, SQLITE_TESTCTRL_PRNG_RESTORE = 6, SQLITE_TESTCTRL_PRNG_RESET = 7, SQLITE_TESTCTRL_BITVEC_TEST = 8, SQLITE_TESTCTRL_FAULT_INSTALL = 9, SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS = 10, SQLITE_TESTCTRL_PENDING_BYTE = 11, SQLITE_TESTCTRL_ASSERT = 12, SQLITE_TESTCTRL_ALWAYS = 13, SQLITE_TESTCTRL_RESERVE = 14, SQLITE_TESTCTRL_OPTIMIZATIONS = 15, SQLITE_TESTCTRL_ISKEYWORD = 16, SQLITE_TESTCTRL_SCRATCHMALLOC = 17, SQLITE_TESTCTRL_LOCALTIME_FAULT = 18, SQLITE_TESTCTRL_EXPLAIN_STMT = 19, SQLITE_TESTCTRL_NEVER_CORRUPT = 20, SQLITE_TESTCTRL_VDBE_COVERAGE = 21, SQLITE_TESTCTRL_BYTEORDER = 22, SQLITE_TESTCTRL_ISINIT = 23, SQLITE_TESTCTRL_SORTER_MMAP = 24, SQLITE_TESTCTRL_IMPOSTER = 25, SQLITE_TESTCTRL_LAST = 25, } /** ** CAPI3REF: SQLite Runtime Status */ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); /// Ditto int sqlite3_status64(int op, long *pCurrent, long *pHighwater, int resetFlag); /** ** CAPI3REF: Status Parameters */ enum { SQLITE_STATUS_MEMORY_USED = 0, SQLITE_STATUS_PAGECACHE_USED = 1, SQLITE_STATUS_PAGECACHE_OVERFLOW = 2, SQLITE_STATUS_SCRATCH_USED = 3, SQLITE_STATUS_SCRATCH_OVERFLOW = 4, SQLITE_STATUS_MALLOC_SIZE = 5, SQLITE_STATUS_PARSER_STACK = 6, SQLITE_STATUS_PAGECACHE_SIZE = 7, SQLITE_STATUS_SCRATCH_SIZE = 8, SQLITE_STATUS_MALLOC_COUNT = 9 } /** ** CAPI3REF: Database Connection Status */ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /** ** CAPI3REF: Status Parameters for database connections */ enum { SQLITE_DBSTATUS_LOOKASIDE_USED = 0, SQLITE_DBSTATUS_CACHE_USED = 1, SQLITE_DBSTATUS_SCHEMA_USED = 2, SQLITE_DBSTATUS_STMT_USED = 3, SQLITE_DBSTATUS_LOOKASIDE_HIT = 4, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE = 5, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL = 6, SQLITE_DBSTATUS_CACHE_HIT = 7, SQLITE_DBSTATUS_CACHE_MISS = 8, SQLITE_DBSTATUS_CACHE_WRITE = 9, SQLITE_DBSTATUS_DEFERRED_FKS = 10, SQLITE_DBSTATUS_MAX = 10 /** Largest defined DBSTATUS */ } /** ** CAPI3REF: Prepared Statement Status */ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); /** ** CAPI3REF: Status Parameters for prepared statements */ enum { SQLITE_STMTSTATUS_FULLSCAN_STEP = 1, SQLITE_STMTSTATUS_SORT = 2, SQLITE_STMTSTATUS_AUTOINDEX = 3, SQLITE_STMTSTATUS_VM_STEP = 4 } /** ** CAPI3REF: Custom Page Cache Object */ struct sqlite3_pcache; /** ** CAPI3REF: Custom Page Cache Object */ struct sqlite3_pcache_page { void *pBuf; /* The content of the page */ void *pExtra; /* Extra information associated with the page */ } /** ** CAPI3REF: Application Defined Page Cache. */ struct sqlite3_pcache_methods2 { int iVersion; void *pArg; int function(void*) xInit; void function(void*) xShutdown; sqlite3_pcache * function(int szPage, int szExtra, int bPurgeable) xCreate; void function(sqlite3_pcache*, int nCachesize) xCachesize; int function(sqlite3_pcache*) xPagecount; sqlite3_pcache_page * function(sqlite3_pcache*, uint key, int createFlag) xFetch; void function(sqlite3_pcache*, sqlite3_pcache_page*, int discard) xUnpin; void function(sqlite3_pcache*, sqlite3_pcache_page*, uint oldKey, uint newKey) xRekey; void function(sqlite3_pcache*, uint iLimit) xTruncate; void function(sqlite3_pcache*) xDestroy; void function(sqlite3_pcache*) xShrink; } struct sqlite3_pcache_methods { void *pArg; int function (void*) xInit; void function (void*) xShutdown; sqlite3_pcache* function (int szPage, int bPurgeable) xCreate; void function (sqlite3_pcache*, int nCachesize) xCachesize; int function (sqlite3_pcache*) xPagecount; void* function (sqlite3_pcache*, uint key, int createFlag) xFetch; void function (sqlite3_pcache*, void*, int discard) xUnpin; void function (sqlite3_pcache*, void*, uint oldKey, uint newKey) xRekey; void function (sqlite3_pcache*, uint iLimit) xTruncate; void function (sqlite3_pcache*) xDestroy; } /** ** CAPI3REF: Online Backup Object */ struct sqlite3_backup; /** ** CAPI3REF: Online Backup API. */ sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /** Destination database handle */ const(char)*zDestName, /** Destination database name */ sqlite3 *pSource, /** Source database handle */ const(char)*zSourceName /** Source database name */ ); /// Ditto int sqlite3_backup_step(sqlite3_backup *p, int nPage); /// Ditto int sqlite3_backup_finish(sqlite3_backup *p); /// Ditto int sqlite3_backup_remaining(sqlite3_backup *p); /// Ditto int sqlite3_backup_pagecount(sqlite3_backup *p); /** ** CAPI3REF: Unlock Notification */ int sqlite3_unlock_notify( sqlite3 *pBlocked, /** Waiting connection */ void function (void **apArg, int nArg) xNotify, /** Callback function to invoke */ void *pNotifyArg /** Argument to pass to xNotify */ ); /** ** CAPI3REF: String Comparison */ int sqlite3_stricmp(const char * , const char * ); int sqlite3_strnicmp(const char * , const char * , int); /* ** CAPI3REF: String Globbing * */ int sqlite3_strglob(const(char)* zGlob, const(char)* zStr); /* ** CAPI3REF: String LIKE Matching */ int sqlite3_strlike(const(char)* zGlob, const(char)* zStr, uint cEsc); /** ** CAPI3REF: Error Logging Interface */ void sqlite3_log(int iErrCode, const char *zFormat, ...); /** ** CAPI3REF: Write-Ahead Log Commit Hook */ void *sqlite3_wal_hook( sqlite3*, int function (void *,sqlite3*,const char*,int), void* ); /** ** CAPI3REF: Configure an auto-checkpoint */ int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /** ** CAPI3REF: Checkpoint a database */ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); /** ** CAPI3REF: Checkpoint a database */ int sqlite3_wal_checkpoint_v2( sqlite3 *db, /** Database handle */ const(char)*zDb, /** Name of attached database (or NULL) */ int eMode, /** SQLITE_CHECKPOINT_* value */ int *pnLog, /** OUT: Size of WAL log in frames */ int *pnCkpt /** OUT: Total number of frames checkpointed */ ); /** ** CAPI3REF: Checkpoint operation parameters */ enum { SQLITE_CHECKPOINT_PASSIVE = 0, SQLITE_CHECKPOINT_FULL = 1, SQLITE_CHECKPOINT_RESTART = 2, SQLITE_CHECKPOINT_TRUNCATE = 3, } /* ** CAPI3REF: Virtual Table Interface Configuration */ int sqlite3_vtab_config(sqlite3*, int op, ...); /** ** CAPI3REF: Virtual Table Configuration Options */ enum SQLITE_VTAB_CONSTRAINT_SUPPORT = 1; /* ** 2010 August 30 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* */ //#ifndef _SQLITE3RTREE_H_ //#define _SQLITE3RTREE_H_ /* ** CAPI3REF: Determine The Virtual Table Conflict Policy */ int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Conflict resolution modes */ enum { SQLITE_ROLLBACK = 1, SQLITE_FAIL = 3, SQLITE_REPLACE = 5 } /* ** CAPI3REF: Prepared Statement Scan Status Opcodes */ enum { SQLITE_SCANSTAT_NLOOP = 0, SQLITE_SCANSTAT_NVISIT = 1, SQLITE_SCANSTAT_EST = 2, SQLITE_SCANSTAT_NAME = 3, SQLITE_SCANSTAT_EXPLAIN = 4, SQLITE_SCANSTAT_SELECTID = 5, } /* ** CAPI3REF: Prepared Statement Scan Status */ int sqlite3_stmt_scanstatus(sqlite3_stmt *pStmt, int idx, int iScanStatusOp, void *pOut); /* ** CAPI3REF: Zero Scan-Status Counters */ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *); /* ** CAPI3REF: Flush caches to disk mid-transaction */ int sqlite3_db_cacheflush(sqlite3 *); struct sqlite3_snapshot; /* ** CAPI3REF: Record A Database Snapshot */ int sqlite3_snapshot_get(sqlite3 *db, char *zSchema, sqlite3_snapshot **ppSnapshot); /* ** CAPI3REF: Start a read transaction on an historical snapshot */ int sqlite3_snapshot_open(sqlite3 *db, char *zSchema, sqlite3_snapshot *pSnapshot); /* ** CAPI3REF: Destroy a snapshot */ void sqlite3_snapshot_free(sqlite3_snapshot *); /** ** Register a geometry callback named zGeom that can be used as part of an ** R-Tree geometry query as follows: ** ** SELECT ... FROM $(LT)rtree$(GT) WHERE $(LT)rtree col$(GT) MATCH $zGeom(... params ...) */ int sqlite3_rtree_geometry_callback( sqlite3 *db, const(char)*zGeom, int function (sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes) xGeom, void *pContext ); /** ** A pointer to a structure of the following type is passed as the first ** argument to callbacks registered using rtree_geometry_callback(). */ struct sqlite3_rtree_geometry { void *pContext; /** Copy of pContext passed to s_r_g_c() */ int nParam; /** Size of array aParam[] */ double *aParam; /** Parameters passed to SQL geom function */ void *pUser; /** Callback implementation user data */ void function (void *) xDelUser; /** Called by SQLite to clean up pUser */ } int sqlite3_rtree_query_callback( sqlite3 *db, const(char)* zQueryFunc, int function(sqlite3_rtree_query_info*) xQueryFunc, void *pContext, void function(void*) xDestructor ); struct sqlite3_rtree_query_info { void *pContext; /* pContext from when function registered */ int nParam; /* Number of function parameters */ double*aParam; /* value of function parameters */ void *pUser; /* callback can use this, if desired */ void function(void*) xDelUser; /* function to free pUser */ double*aCoord; /* Coordinates of node or entry to check */ uint *anQueue; /* Number of pending entries in the queue */ int nCoord; /* Number of coordinates */ int iLevel; /* Level of current node or entry */ int mxLevel; /* The largest iLevel value in the tree */ sqlite3_int64 iRowid; /* Rowid for current entry */ double rParentScore; /* Score of parent node */ int eParentWithin; /* Visibility of parent node */ int eWithin; /* OUT: Visiblity */ double rScore; /* OUT: Write the score here */ sqlite3_value **apSqlParam; /* Original SQL values of parameters */ } enum { NOT_WITHIN = 0, PARTLY_WITHIN = 1, FULLY_WITHIN = 2 } /****************************************************************************** ** Interfaces to extend FTS5. */ struct Fts5Context; /// Ditto alias fts5_extension_function = void function( const Fts5ExtensionApi *pApi, Fts5Context *pFts, sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ); /// Ditto struct Fts5PhraseIter { const(ubyte) *a; const(ubyte) *b; } /// Ditto struct Fts5ExtensionApi { int iVersion; void* function(Fts5Context*) xUserData; int function(Fts5Context*) xColumnCount; int function(Fts5Context*, sqlite3_int64 *pnRow) xRowCount; int function(Fts5Context*, int iCol, sqlite3_int64 *pnToken) xColumnTotalSize; int function(Fts5Context*, const char *pText, int nText, void *pCtx, int function(void*, int, const char*, int, int, int) xToken ) xTokenize; int function(Fts5Context*) xPhraseCount; int function(Fts5Context*, int iPhrase) xPhraseSize; int function(Fts5Context*, int *pnInst) xInstCount; int function(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff) xInst; sqlite3_int64 function(Fts5Context*) xRowid; int function(Fts5Context*, int iCol, const char **pz, int *pn) xColumnText; int function(Fts5Context*, int iCol, int *pnToken) xColumnSize; int function(Fts5Context*, int iPhrase, void *pUserData, int function(const Fts5ExtensionApi*,Fts5Context*,void*) ) xQueryPhrase; int function(Fts5Context*, void *pAux, void function(void*) xDelete) xSetAuxdata; void* function(Fts5Context*, int bClear) xGetAuxdata; void function(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*) xPhraseFirst; void function(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff) xPhraseNext; } /// Ditto struct Fts5Tokenizer; struct fts5_tokenizer { int function(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut) xCreate; void function(Fts5Tokenizer*) xDelete; int function(Fts5Tokenizer*, void *pCtx, int flags, const char *pText, int nText, int function( void *pCtx, int tflags, const char *pToken, int nToken, int iStart, int iEnd ) xToken ) xTokenize; } /// Ditto enum FTS5_TOKENIZE_QUERY = 0x0001; /// Ditto enum FTS5_TOKENIZE_PREFIX = 0x0002; /// Ditto enum FTS5_TOKENIZE_DOCUMENT = 0x0004; /// Ditto enum FTS5_TOKENIZE_AUX = 0x0008; /// Ditto enum FTS5_TOKEN_COLOCATED = 0x0001; /// Ditto struct fts5_api { int iVersion; int function( fts5_api *pApi, const char *zName, void *pContext, fts5_tokenizer *pTokenizer, void function(void*) xDestroy ) xCreateTokenizer; int function( fts5_api *pApi, const char *zName, void **ppContext, fts5_tokenizer *pTokenizer ) xFindTokenizer; int function( fts5_api *pApi, const char *zName, void *pContext, fts5_extension_function xFunction, void function(void*) xDestroy ) xCreateFunction; } ldc-1.1.0-beta3-src/runtime/phobos/osmodel.mak0000664000175000017500000000216312776215007017252 0ustar kaikai# This Makefile snippet detects the OS and the architecture MODEL # Keep this file in sync between druntime, phobos, and dmd repositories! ifeq (,$(OS)) uname_S:=$(shell uname -s) ifeq (Darwin,$(uname_S)) OS:=osx endif ifeq (Linux,$(uname_S)) OS:=linux endif ifeq (FreeBSD,$(uname_S)) OS:=freebsd endif ifeq (NetBSD,$(uname_S)) OS:=netbsd endif ifeq (OpenBSD,$(uname_S)) OS:=openbsd endif ifeq (Solaris,$(uname_S)) OS:=solaris endif ifeq (SunOS,$(uname_S)) OS:=solaris endif ifeq (,$(OS)) $(error Unrecognized or unsupported OS for uname: $(uname_S)) endif endif # When running make from XCode it may set environment var OS=MACOS. # Adjust it here: ifeq (MACOS,$(OS)) OS:=osx endif ifeq (,$(MODEL)) ifeq ($(OS), solaris) uname_M:=$(shell isainfo -n) else uname_M:=$(shell uname -m) endif ifneq (,$(findstring $(uname_M),x86_64 amd64)) MODEL:=64 endif ifneq (,$(findstring $(uname_M),i386 i586 i686)) MODEL:=32 endif ifeq (,$(MODEL)) $(error Cannot figure 32/64 model from uname -m: $(uname_M)) endif endif MODEL_FLAG:=-m$(MODEL) ldc-1.1.0-beta3-src/runtime/phobos/README.md0000664000175000017500000000161312776215007016374 0ustar kaikai![D Logo](http://dlang.org/images/dlogo.png) Phobos Standard Library =================================================================== Phobos is the standard library that comes with the [D Programming Language](http://dlang.org) Compiler. * [Bugzilla bug tracker](http://d.puremagic.com/issues/) * [Forum](http://forum.dlang.org/) * [API Documentation](http://dlang.org/phobos/) * [Wiki](http://wiki.dlang.org/) Download -------- Phobos is packaged together with the compiler. You should [download the whole precompiled package](http://dlang.org/download.html). To [build everything yourself](http://wiki.dlang.org/Building_DMD), there is a [description in the wiki](http://wiki.dlang.org/Building_DMD). Phobos is distributed under Boost Software Licence. See the [licence file](LICENSE_1_0.txt). I Want to Contribute -------------------- Great! See the [CONTRIBUTING.md file](CONTRIBUTING.md). ldc-1.1.0-beta3-src/runtime/phobos/posix.mak0000664000175000017500000003721612776215007016761 0ustar kaikai# Makefile to build linux D runtime library libphobos2.a and its unit test # # make => makes release build of the library # # make clean => removes all targets built by the makefile # # make zip => creates a zip file of all the sources (not targets) # referred to by the makefile, including the makefile # # make BUILD=debug => makes debug build of the library # # make unittest => builds all unittests (for debug AND release) and runs them # # make BUILD=debug unittest => builds all unittests (for debug) and runs them # # make html => makes html documentation # # make install => copies library to /usr/lib # # make std/somemodule.test => only builds and unittests std.somemodule # ################################################################################ # Configurable stuff, usually from the command line # # OS can be linux, win32, win32wine, osx, or freebsd. The system will be # determined by using uname QUIET:= include osmodel.mak # Default to a release built, override with BUILD=debug ifeq (,$(BUILD)) BUILD_WAS_SPECIFIED=0 BUILD=release else BUILD_WAS_SPECIFIED=1 endif ifneq ($(BUILD),release) ifneq ($(BUILD),debug) $(error Unrecognized BUILD=$(BUILD), must be 'debug' or 'release') endif endif override PIC:=$(if $(PIC),-fPIC,) # Configurable stuff that's rarely edited INSTALL_DIR = ../install DRUNTIME_PATH = ../druntime ZIPFILE = phobos.zip ROOT_OF_THEM_ALL = generated ROOT = $(ROOT_OF_THEM_ALL)/$(OS)/$(BUILD)/$(MODEL) # Documentation-related stuff DOCSRC = ../dlang.org WEBSITE_DIR = ../web DOC_OUTPUT_DIR = $(WEBSITE_DIR)/phobos-prerelease BIGDOC_OUTPUT_DIR = /tmp SRC_DOCUMENTABLES = index.d $(addsuffix .d,$(STD_MODULES) \ $(EXTRA_DOCUMENTABLES)) STDDOC = $(DOCSRC)/html.ddoc $(DOCSRC)/dlang.org.ddoc $(DOCSRC)/std_navbar-prerelease.ddoc $(DOCSRC)/std.ddoc $(DOCSRC)/macros.ddoc $(DOCSRC)/.generated/modlist-prerelease.ddoc BIGSTDDOC = $(DOCSRC)/std_consolidated.ddoc $(DOCSRC)/macros.ddoc # Set DDOC, the documentation generator DDOC=$(DMD) -conf= $(MODEL_FLAG) -w -c -o- -version=StdDdoc \ -I$(DRUNTIME_PATH)/import $(DMDEXTRAFLAGS) # Set DRUNTIME name and full path ifneq (,$(DRUNTIME)) CUSTOM_DRUNTIME=1 endif ifeq (,$(findstring win,$(OS))) DRUNTIME = $(DRUNTIME_PATH)/generated/$(OS)/$(BUILD)/$(MODEL)/libdruntime.a DRUNTIMESO = $(basename $(DRUNTIME)).so.a else DRUNTIME = $(DRUNTIME_PATH)/lib/druntime.lib endif # Set CC and DMD ifeq ($(OS),win32wine) CC = wine dmc.exe DMD = wine dmd.exe RUN = wine else DMD = ../dmd/src/dmd ifeq ($(OS),win32) CC = dmc else CC = cc endif RUN = endif # Set CFLAGS CFLAGS=$(MODEL_FLAG) -fPIC -DHAVE_UNISTD_H ifeq ($(BUILD),debug) CFLAGS += -g else CFLAGS += -O3 endif # Set DFLAGS DFLAGS=-conf= -I$(DRUNTIME_PATH)/import $(DMDEXTRAFLAGS) -w -dip25 $(MODEL_FLAG) $(PIC) ifeq ($(BUILD),debug) DFLAGS += -g -debug else DFLAGS += -O -release endif # Set DOTOBJ and DOTEXE ifeq (,$(findstring win,$(OS))) DOTOBJ:=.o DOTEXE:= PATHSEP:=/ else DOTOBJ:=.obj DOTEXE:=.exe PATHSEP:=$(shell echo "\\") endif LINKDL:=$(if $(findstring $(OS),linux),-L-ldl,) # use timelimit to avoid deadlocks if available TIMELIMIT:=$(if $(shell which timelimit 2>/dev/null || true),timelimit -t 60 ,) # Set VERSION, where the file is that contains the version string VERSION=../dmd/VERSION # Set LIB, the ultimate target ifeq (,$(findstring win,$(OS))) LIB:=$(ROOT)/libphobos2.a # 2.064.2 => libphobos2.so.0.64.2 # 2.065 => libphobos2.so.0.65.0 # MAJOR version is 0 for now, which means the ABI is still unstable MAJOR:=0 MINOR:=$(shell awk -F. '{ print int($$2) }' $(VERSION)) PATCH:=$(shell awk -F. '{ print int($$3) }' $(VERSION)) # SONAME doesn't use patch level (ABI compatible) SONAME:=libphobos2.so.$(MAJOR).$(MINOR) LIBSO:=$(ROOT)/$(SONAME).$(PATCH) else LIB:=$(ROOT)/phobos.lib endif ################################################################################ MAIN = $(ROOT)/emptymain.d # Given one or more packages, returns their respective libraries P2LIB=$(addprefix $(ROOT)/libphobos2_,$(addsuffix $(DOTLIB),$(subst /,_,$1))) # Given one or more packages, returns the modules they contain P2MODULES=$(foreach P,$1,$(addprefix $P/,$(PACKAGE_$(subst /,_,$P)))) # Packages in std. Just mention the package name here. The contents of package # xy/zz is in variable PACKAGE_xy_zz. This allows automation in iterating # packages and their modules. STD_PACKAGES = std $(addprefix std/,\ algorithm container digest experimental/allocator \ experimental/allocator/building_blocks experimental/logger \ experimental/ndslice \ net \ range regex) # Modules broken down per package PACKAGE_std = array ascii base64 bigint bitmanip compiler complex concurrency \ concurrencybase conv cstream csv datetime demangle encoding exception file format \ functional getopt json math mathspecial meta mmfile numeric \ outbuffer parallelism path process random signals socket socketstream stdint \ stdio stdiobase stream string system traits typecons typetuple uni \ uri utf uuid variant xml zip zlib PACKAGE_std_algorithm = comparison iteration mutation package searching setops \ sorting PACKAGE_std_container = array binaryheap dlist package rbtree slist util PACKAGE_std_digest = crc digest hmac md ripemd sha PACKAGE_std_experimental_logger = core filelogger \ nulllogger multilogger package PACKAGE_std_experimental_allocator = \ common gc_allocator mallocator mmap_allocator package showcase typed PACKAGE_std_experimental_allocator_building_blocks = \ affix_allocator allocator_list bucketizer \ fallback_allocator free_list free_tree bitmapped_block \ kernighan_ritchie null_allocator package quantizer \ region scoped_allocator segregator stats_collector PACKAGE_std_experimental_ndslice = package iteration selection slice PACKAGE_std_net = curl isemail PACKAGE_std_range = interfaces package primitives PACKAGE_std_regex = package $(addprefix internal/,generator ir parser \ backtracking kickstart tests thompson) # Modules in std (including those in packages) STD_MODULES=$(call P2MODULES,$(STD_PACKAGES)) # OS-specific D modules EXTRA_MODULES_LINUX := $(addprefix std/c/linux/, linux socket) EXTRA_MODULES_OSX := $(addprefix std/c/osx/, socket) EXTRA_MODULES_FREEBSD := $(addprefix std/c/freebsd/, socket) EXTRA_MODULES_WIN32 := $(addprefix std/c/windows/, com stat windows \ winsock) $(addprefix std/windows/, charset iunknown syserror) # Other D modules that aren't under std/ EXTRA_MODULES_COMMON := $(addprefix etc/c/,curl odbc/sql odbc/sqlext \ odbc/sqltypes odbc/sqlucode sqlite3 zlib) $(addprefix std/c/,fenv locale \ math process stdarg stddef stdio stdlib string time wcharh) EXTRA_DOCUMENTABLES := $(EXTRA_MODULES_LINUX) $(EXTRA_MODULES_WIN32) $(EXTRA_MODULES_COMMON) EXTRA_MODULES_INTERNAL := $(addprefix \ std/internal/digest/, sha_SSSE3 ) $(addprefix \ std/internal/math/, biguintcore biguintnoasm biguintx86 \ gammafunction errorfunction) $(addprefix std/internal/, \ cstring processinit unicode_tables scopebuffer\ unicode_comp unicode_decomp unicode_grapheme unicode_norm) \ $(addprefix std/internal/test/, dummyrange) \ $(addprefix std/experimental/ndslice/, internal) \ $(addprefix std/algorithm/, internal) EXTRA_MODULES += $(EXTRA_DOCUMENTABLES) $(EXTRA_MODULES_INTERNAL) # Aggregate all D modules relevant to this build D_MODULES = $(STD_MODULES) $(EXTRA_MODULES) # Add the .d suffix to the module names D_FILES = $(addsuffix .d,$(D_MODULES)) # Aggregate all D modules over all OSs (this is for the zip file) ALL_D_FILES = $(addsuffix .d, $(STD_MODULES) $(EXTRA_MODULES_COMMON) \ $(EXTRA_MODULES_LINUX) $(EXTRA_MODULES_OSX) $(EXTRA_MODULES_FREEBSD) \ $(EXTRA_MODULES_WIN32) $(EXTRA_MODULES_INTERNAL)) \ std/internal/windows/advapi32.d \ std/windows/registry.d std/c/linux/pthread.d std/c/linux/termios.d \ std/c/linux/tipc.d # C files to be part of the build C_MODULES = $(addprefix etc/c/zlib/, adler32 compress crc32 deflate \ gzclose gzlib gzread gzwrite infback inffast inflate inftrees trees uncompr zutil) OBJS = $(addsuffix $(DOTOBJ),$(addprefix $(ROOT)/,$(C_MODULES))) MAKEFILE = $(firstword $(MAKEFILE_LIST)) # build with shared library support (defaults to true on supported platforms) SHARED=$(if $(findstring $(OS),linux freebsd),1,) ################################################################################ # Rules begin here ################################################################################ # Main target (builds the dll on linux, too) ifeq (1,$(SHARED)) all : lib dll else all : lib endif install : $(MAKE) -f $(MAKEFILE) OS=$(OS) MODEL=$(MODEL) BUILD=release INSTALL_DIR=$(INSTALL_DIR) \ DMD=$(DMD) install2 .PHONY : unittest ifeq (1,$(BUILD_WAS_SPECIFIED)) unittest : $(addsuffix .run,$(addprefix unittest/,$(D_MODULES))) else unittest : unittest-debug unittest-release unittest-%: $(MAKE) -f $(MAKEFILE) unittest OS=$(OS) MODEL=$(MODEL) DMD=$(DMD) BUILD=$* endif depend: $(addprefix $(ROOT)/unittest/,$(addsuffix .deps,$(D_MODULES))) -include $(addprefix $(ROOT)/unittest/,$(addsuffix .deps,$(D_MODULES))) ################################################################################ # Patterns begin here ################################################################################ .PHONY: lib dll lib: $(LIB) dll: $(ROOT)/libphobos2.so $(ROOT)/%$(DOTOBJ): %.c @[ -d $(dir $@) ] || mkdir -p $(dir $@) || [ -d $(dir $@) ] $(CC) -c $(CFLAGS) $< -o$@ $(LIB): $(OBJS) $(ALL_D_FILES) $(DRUNTIME) $(DMD) $(DFLAGS) -lib -of$@ $(DRUNTIME) $(D_FILES) $(OBJS) $(ROOT)/libphobos2.so: $(ROOT)/$(SONAME) ln -sf $(notdir $(LIBSO)) $@ $(ROOT)/$(SONAME): $(LIBSO) ln -sf $(notdir $(LIBSO)) $@ $(LIBSO): override PIC:=-fPIC $(LIBSO): $(OBJS) $(ALL_D_FILES) $(DRUNTIMESO) $(DMD) $(DFLAGS) -shared -debuglib= -defaultlib= -of$@ -L-soname=$(SONAME) $(DRUNTIMESO) $(LINKDL) $(D_FILES) $(OBJS) ifeq (osx,$(OS)) # Build fat library that combines the 32 bit and the 64 bit libraries libphobos2.a: $(ROOT_OF_THEM_ALL)/osx/release/libphobos2.a $(ROOT_OF_THEM_ALL)/osx/release/libphobos2.a: $(MAKE) -f $(MAKEFILE) OS=$(OS) MODEL=32 BUILD=release $(MAKE) -f $(MAKEFILE) OS=$(OS) MODEL=64 BUILD=release lipo $(ROOT_OF_THEM_ALL)/osx/release/32/libphobos2.a \ $(ROOT_OF_THEM_ALL)/osx/release/64/libphobos2.a \ -create -output $@ endif ################################################################################ # Unittests ################################################################################ $(addprefix $(ROOT)/unittest/,$(DISABLED_TESTS)) : @echo Testing $@ - disabled UT_D_OBJS:=$(addprefix $(ROOT)/unittest/,$(addsuffix .o,$(D_MODULES))) $(UT_D_OBJS): $(ROOT)/unittest/%.o: %.d @mkdir -p $(dir $@) $(DMD) $(DFLAGS) -unittest -c -of$@ -deps=$(@:.o=.deps.tmp) $< @echo $@: `sed 's|.*(\(.*\)).*|\1|' $(@:.o=.deps.tmp) | sort | uniq` \ >$(@:.o=.deps) @rm $(@:.o=.deps.tmp) # $(DMD) $(DFLAGS) -unittest -c -of$@ $*.d ifneq (1,$(SHARED)) $(UT_D_OBJS): $(DRUNTIME) $(ROOT)/unittest/test_runner: $(DRUNTIME_PATH)/src/test_runner.d $(UT_D_OBJS) $(OBJS) $(DRUNTIME) $(DMD) $(DFLAGS) -unittest -of$@ $(DRUNTIME_PATH)/src/test_runner.d $(UT_D_OBJS) $(OBJS) $(DRUNTIME) $(LINKDL) -defaultlib= -debuglib= else UT_LIBSO:=$(ROOT)/unittest/libphobos2-ut.so $(UT_D_OBJS): $(DRUNTIMESO) $(UT_LIBSO): override PIC:=-fPIC $(UT_LIBSO): $(UT_D_OBJS) $(OBJS) $(DRUNTIMESO) $(DMD) $(DFLAGS) -shared -unittest -of$@ $(UT_D_OBJS) $(OBJS) $(DRUNTIMESO) $(LINKDL) -defaultlib= -debuglib= $(ROOT)/unittest/test_runner: $(DRUNTIME_PATH)/src/test_runner.d $(UT_LIBSO) $(DMD) $(DFLAGS) -of$@ $< -L$(UT_LIBSO) -defaultlib= -debuglib= endif # macro that returns the module name given the src path moduleName=$(subst /,.,$(1)) # target for batch unittests (using shared phobos library and test_runner) unittest/%.run : $(ROOT)/unittest/test_runner $(QUIET)$(TIMELIMIT)$(RUN) $< $(call moduleName,$*) # Target for quickly running a single unittest (using static phobos library). # For example: "make std/algorithm/mutation.test" # The mktemp business is needed so .o files don't clash in concurrent unittesting. %.test : %.d $(LIB) T=`mktemp -d /tmp/.dmd-run-test.XXXXXX` && \ $(DMD) -od$$T $(DFLAGS) -main -unittest $(LIB) -defaultlib= -debuglib= $(LINKDL) -cov -run $< && \ rm -rf $$T # Target for quickly unittesting all modules and packages within a package, # transitively. For example: "make std/algorithm.test" %.test : $(LIB) $(MAKE) -f $(MAKEFILE) $(addsuffix .test,$(patsubst %.d,%,$(wildcard $*/*))) ################################################################################ # More stuff ################################################################################ # Disable implicit rule %$(DOTEXE) : %$(DOTOBJ) %/.directory : mkdir -p $* || exists $* touch $@ clean : rm -rf $(ROOT_OF_THEM_ALL) $(ZIPFILE) $(DOC_OUTPUT_DIR) zip : -rm -f $(ZIPFILE) zip -r $(ZIPFILE) . -x .git\* -x generated\* install2 : all $(eval lib_dir=$(if $(filter $(OS),osx), lib, lib$(MODEL))) mkdir -p $(INSTALL_DIR)/$(OS)/$(lib_dir) cp $(LIB) $(INSTALL_DIR)/$(OS)/$(lib_dir)/ ifeq (1,$(SHARED)) cp -P $(LIBSO) $(INSTALL_DIR)/$(OS)/$(lib_dir)/ ln -sf $(notdir $(LIBSO)) $(INSTALL_DIR)/$(OS)/$(lib_dir)/libphobos2.so endif mkdir -p $(INSTALL_DIR)/src/phobos/etc mkdir -p $(INSTALL_DIR)/src/phobos/std cp -r std/* $(INSTALL_DIR)/src/phobos/std/ cp -r etc/* $(INSTALL_DIR)/src/phobos/etc/ cp LICENSE_1_0.txt $(INSTALL_DIR)/phobos-LICENSE.txt ifeq (1,$(CUSTOM_DRUNTIME)) # We consider a custom-set DRUNTIME a sign they build druntime themselves else # This rule additionally produces $(DRUNTIMESO). Add a fake dependency # to always invoke druntime's make. Use FORCE instead of .PHONY to # avoid rebuilding phobos when $(DRUNTIME) didn't change. $(DRUNTIME): FORCE $(MAKE) -C $(DRUNTIME_PATH) -f posix.mak MODEL=$(MODEL) DMD=$(DMD) OS=$(OS) BUILD=$(BUILD) ifeq (,$(findstring win,$(OS))) $(DRUNTIMESO): $(DRUNTIME) endif FORCE: endif ########################################################### # html documentation # D file to html, e.g. std/conv.d -> std_conv.html # But "package.d" is special cased: std/range/package.d -> std_range.html D2HTML=$(foreach p,$1,$(if $(subst package.d,,$(notdir $p)),$(subst /,_,$(subst .d,.html,$p)),$(subst /,_,$(subst /package.d,.html,$p)))) HTMLS=$(addprefix $(DOC_OUTPUT_DIR)/, \ $(call D2HTML, $(SRC_DOCUMENTABLES))) BIGHTMLS=$(addprefix $(BIGDOC_OUTPUT_DIR)/, \ $(call D2HTML, $(SRC_DOCUMENTABLES))) $(DOC_OUTPUT_DIR)/. : mkdir -p $@ # For each module, define a rule e.g.: # ../web/phobos/std_conv.html : std/conv.d $(STDDOC) ; ... $(foreach p,$(SRC_DOCUMENTABLES),$(eval \ $(DOC_OUTPUT_DIR)/$(call D2HTML,$p) : $p $(STDDOC) ;\ $(DDOC) project.ddoc $(STDDOC) -Df$$@ $$<)) html : $(DOC_OUTPUT_DIR)/. $(HTMLS) $(STYLECSS_TGT) allmod : @echo $(SRC_DOCUMENTABLES) rsync-prerelease : html rsync -avz $(DOC_OUTPUT_DIR)/ d-programming@digitalmars.com:data/phobos-prerelease/ rsync -avz $(WEBSITE_DIR)/ d-programming@digitalmars.com:data/phobos-prerelase/ html_consolidated : $(DDOC) -Df$(DOCSRC)/std_consolidated_header.html $(DOCSRC)/std_consolidated_header.dd $(DDOC) -Df$(DOCSRC)/std_consolidated_footer.html $(DOCSRC)/std_consolidated_footer.dd $(MAKE) -f $(MAKEFILE) DOC_OUTPUT_DIR=$(BIGDOC_OUTPUT_DIR) STDDOC=$(BIGSTDDOC) html -j 8 cat $(DOCSRC)/std_consolidated_header.html $(BIGHTMLS) \ $(DOCSRC)/std_consolidated_footer.html > $(DOC_OUTPUT_DIR)/std_consolidated.html changelog.html: changelog.dd $(DMD) -Df$@ $< #################### test for undesired white spaces ########################## CWS_TOCHECK = posix.mak win32.mak win64.mak osmodel.mak CWS_TOCHECK += $(ALL_D_FILES) index.d checkwhitespace: $(LIB) $(DMD) $(DFLAGS) -defaultlib= -debuglib= $(LIB) -run ../dmd/src/checkwhitespace.d $(CWS_TOCHECK) ############################# .PHONY : auto-tester-build auto-tester-build: all checkwhitespace .PHONY : auto-tester-test auto-tester-test: unittest .DELETE_ON_ERROR: # GNU Make directive (delete output files on error) ldc-1.1.0-beta3-src/runtime/phobos/LICENSE_1_0.txt0000664000175000017500000000247212776215007017403 0ustar kaikaiBoost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ldc-1.1.0-beta3-src/runtime/phobos/.editorconfig0000664000175000017500000000024112776215007017566 0ustar kaikairoot = true [*.{c,h,d,di,dd}] end_of_line = lf insert_final_newline = true indent_style = space indent_size = 4 trim_trailing_whitespace = true charset = utf-8 ldc-1.1.0-beta3-src/runtime/phobos/changelog.dd0000664000175000017500000000617512776215007017365 0ustar kaikaiDdoc $(COMMENT Pending changelog for 2.071. This will get copied to dlang.org and cleared when master gets merged into stable prior to 2.071. ) $(BUGSTITLE Library Changes, $(LI $(NXREF experimental_allocator_gc_allocator, GCAllocator.goodAllocSize) was added.) $(LI High-level API of $(STDMODREF net_curl, std.net.curl) now uses $(XREF array, Appender) for received content. Which generally makes all calls slightly faster. Up to 200ms for large amounts of data.) $(LI $(XREF meta, Repeat) was added to obtain a repeating $(XREF meta, AliasSeq) consisting of template arguments.) $(LI $(XREF algorithm_iteration, fold) was added as an alternative to $(XREF algorithm_iteration, reduce) with argument order swapped.) $(LI $(RELATIVE_LINK2 nextPow2, Added nextPow2 and truncPow2 to std.math.)) $(LI $(CXREF bitop, bsf), $(CXREF bitop, bsr), and $(CXREF bitop, popcnt) now work with ulongs on 32 bit systems.) $(LI $(XREF algorithm_sorting, topN) is now 5% - 7% faster.) $(LI $(RELATIVE_LINK2 unary, Unary overloads of `startsWith` and `endsWith` were added.)) $(LI $(RELATIVE_LINK2 maxCount, $(XREF algorithm_searching, maxCount) and $(XREF algorithm_searching, maxPos) were added.)) $(LI Range support for the convenience wrapper $(XREF container_rbtree, redBlackTree) was added.) ) $(BUGSTITLE Library Changes, $(LI $(LNAME2 nextPow2, Added nextPow2 and truncPow2 to std.math.) $(P $(XREF math, nextPow2) and $(XREF math, truncPow2) are functions for rounding numbers to powers of two. ) ------ import std.math; assert(nextPow2(10) == 16); assert(nextPow2(4000) == 4096); assert(truncPow2(10) == 8); assert(truncPow2(4000) == 2048); ------ ) $(LI $(LNAME2 unary, Unary overloads of `startsWith` and `endsWith` were added.) $(P $(XREF algorithm_searching, startsWith) and $(XREF algorithm_searching, endsWith) can now be used just with a predicate. ) ------ import std.algorithm.searching; import std.ascii : isAlpha; assert("abc".endsWith!isAlpha); assert(!"ab1".endsWith!(a => a.isAlpha)); assert("abc".startsWith!isAlpha); assert(!"1ab".startsWith!isAlpha); ------ ) $(LI $(LNAME2 maxPos, $(XREF algorithm_searching, maxCount) and $(XREF algorithm_searching, maxPos) were added.) $(P Previous to this addition, in order to get the number of the greatest elements, you had to use `minCount!"a > b"`, which was very confusing. This change adds convenience functions to fix this issue.) ) ) Macros: TITLE=Change Log BUGSTITLE =
$(H4 $1) $(OL $2 )
RELATIVE_LINK2=$+ LNAME2=$+ STDMODREF = $2 XREF = $2 CXREF = $2 OXREF = $2 NXREF = $2 NCXREF = $2 NOXREF = $2 BOOKTABLE = $+
$1
ldc-1.1.0-beta3-src/runtime/phobos/std/0000775000175000017500000000000012776215007015706 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/outbuffer.d0000664000175000017500000002570512776215007020065 0ustar kaikai// Written in the D programming language. /** Serialize data to $(D ubyte) arrays. * Macros: * WIKI = Phobos/StdOutbuffer * * Copyright: Copyright Digital Mars 2000 - 2015. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * Source: $(PHOBOSSRC std/_outbuffer.d) */ module std.outbuffer; private { import core.memory; import core.stdc.stdarg; import core.stdc.stdio; import core.stdc.stdlib; import std.algorithm; import std.string; } /********************************************* * OutBuffer provides a way to build up an array of bytes out * of raw data. It is useful for things like preparing an * array of bytes to write out to a file. * OutBuffer's byte order is the format native to the computer. * To control the byte order (endianness), use a class derived * from OutBuffer. * OutBuffer's internal buffer is allocated with the GC. Pointers * stored into the buffer are scanned by the GC, but you have to * ensure proper alignment, e.g. by using alignSize((void*).sizeof). */ class OutBuffer { ubyte[] data; size_t offset; invariant() { //printf("this = %p, offset = %x, data.length = %u\n", this, offset, data.length); assert(offset <= data.length); } pure nothrow @safe { this() { //printf("in OutBuffer constructor\n"); } /********************************* * Convert to array of bytes. */ ubyte[] toBytes() { return data[0 .. offset]; } /*********************************** * Preallocate nbytes more to the size of the internal buffer. * * This is a * speed optimization, a good guess at the maximum size of the resulting * buffer will improve performance by eliminating reallocations and copying. */ void reserve(size_t nbytes) @trusted in { assert(offset + nbytes >= offset); } out { assert(offset + nbytes <= data.length); } body { //c.stdio.printf("OutBuffer.reserve: length = %d, offset = %d, nbytes = %d\n", data.length, offset, nbytes); if (data.length < offset + nbytes) { void[] vdata = data; vdata.length = (offset + nbytes + 7) * 2; // allocates as void[] to not set BlkAttr.NO_SCAN data = cast(ubyte[])vdata; } } /********************************** * put enables OutBuffer to be used as an OutputRange. */ alias put = write; /************************************* * Append data to the internal buffer. */ void write(const(ubyte)[] bytes) { reserve(bytes.length); data[offset .. offset + bytes.length] = bytes[]; offset += bytes.length; } void write(in wchar[] chars) @trusted { write(cast(ubyte[]) chars); } void write(const(dchar)[] chars) @trusted { write(cast(ubyte[]) chars); } void write(ubyte b) /// ditto { reserve(ubyte.sizeof); this.data[offset] = b; offset += ubyte.sizeof; } void write(byte b) { write(cast(ubyte)b); } /// ditto void write(char c) { write(cast(ubyte)c); } /// ditto void write(dchar c) { write(cast(uint)c); } /// ditto void write(ushort w) @trusted /// ditto { reserve(ushort.sizeof); *cast(ushort *)&data[offset] = w; offset += ushort.sizeof; } void write(short s) { write(cast(ushort)s); } /// ditto void write(wchar c) @trusted /// ditto { reserve(wchar.sizeof); *cast(wchar *)&data[offset] = c; offset += wchar.sizeof; } void write(uint w) @trusted /// ditto { reserve(uint.sizeof); *cast(uint *)&data[offset] = w; offset += uint.sizeof; } void write(int i) { write(cast(uint)i); } /// ditto void write(ulong l) @trusted /// ditto { reserve(ulong.sizeof); *cast(ulong *)&data[offset] = l; offset += ulong.sizeof; } void write(long l) { write(cast(ulong)l); } /// ditto void write(float f) @trusted /// ditto { reserve(float.sizeof); *cast(float *)&data[offset] = f; offset += float.sizeof; } void write(double f) @trusted /// ditto { reserve(double.sizeof); *cast(double *)&data[offset] = f; offset += double.sizeof; } void write(real f) @trusted /// ditto { reserve(real.sizeof); *cast(real *)&data[offset] = f; offset += real.sizeof; } void write(in char[] s) @trusted /// ditto { write(cast(ubyte[])s); } void write(OutBuffer buf) /// ditto { write(buf.toBytes()); } /**************************************** * Append nbytes of 0 to the internal buffer. */ void fill0(size_t nbytes) { reserve(nbytes); data[offset .. offset + nbytes] = 0; offset += nbytes; } /********************************** * 0-fill to align on power of 2 boundary. */ void alignSize(size_t alignsize) in { assert(alignsize && (alignsize & (alignsize - 1)) == 0); } out { assert((offset & (alignsize - 1)) == 0); } body { auto nbytes = offset & (alignsize - 1); if (nbytes) fill0(alignsize - nbytes); } /**************************************** * Optimize common special case alignSize(2) */ void align2() { if (offset & 1) write(cast(byte)0); } /**************************************** * Optimize common special case alignSize(4) */ void align4() { if (offset & 3) { auto nbytes = (4 - offset) & 3; fill0(nbytes); } } /************************************** * Convert internal buffer to array of chars. */ override string toString() const { //printf("OutBuffer.toString()\n"); return cast(string) data[0 .. offset].idup; } } /***************************************** * Append output of C's vprintf() to internal buffer. */ void vprintf(string format, va_list args) @trusted nothrow { char[128] buffer; int count; // Can't use `tempCString()` here as it will result in compilation error: // "cannot mix core.std.stdlib.alloca() and exception handling". auto f = toStringz(format); auto p = buffer.ptr; auto psize = buffer.length; for (;;) { version(Windows) { count = vsnprintf(p,psize,f,args); if (count != -1) break; psize *= 2; p = cast(char *) alloca(psize); // buffer too small, try again with larger size } else version(Posix) { count = vsnprintf(p,psize,f,args); if (count == -1) psize *= 2; else if (count >= psize) psize = count + 1; else break; /+ if (p != buffer) c.stdlib.free(p); p = (char *) c.stdlib.malloc(psize); // buffer too small, try again with larger size +/ p = cast(char *) alloca(psize); // buffer too small, try again with larger size } else { static assert(0); } } write(cast(ubyte[]) p[0 .. count]); /+ version (Posix) { if (p != buffer) c.stdlib.free(p); } +/ } /***************************************** * Append output of C's printf() to internal buffer. */ void printf(string format, ...) @trusted { va_list ap; va_start(ap, format); vprintf(format, ap); va_end(ap); } /** * Formats and writes its arguments in text format to the OutBuffer. * * Params: * fmt = format string as described in $(XREF format, formattedWrite) * args = arguments to be formatted * * See_Also: * $(XREF stdio, _writef); * $(XREF format, formattedWrite); */ void writef(Char, A...)(in Char[] fmt, A args) { import std.format : formattedWrite; formattedWrite(this, fmt, args); } /// unittest { OutBuffer b = new OutBuffer(); b.writef("a%sb", 16); assert(b.toString() == "a16b"); } /** * Formats and writes its arguments in text format to the OutBuffer, * followed by a newline. * * Params: * fmt = format string as described in $(XREF format, formattedWrite) * args = arguments to be formatted * * See_Also: * $(XREF stdio, _writefln); * $(XREF format, formattedWrite); */ void writefln(Char, A...)(in Char[] fmt, A args) { import std.format : formattedWrite; formattedWrite(this, fmt, args); put('\n'); } /// unittest { OutBuffer b = new OutBuffer(); b.writefln("a%sb", 16); assert(b.toString() == "a16b\n"); } /***************************************** * At offset index into buffer, create nbytes of space by shifting upwards * all data past index. */ void spread(size_t index, size_t nbytes) pure nothrow @safe in { assert(index <= offset); } body { reserve(nbytes); // This is an overlapping copy - should use memmove() for (size_t i = offset; i > index; ) { --i; data[i + nbytes] = data[i]; } offset += nbytes; } } unittest { //printf("Starting OutBuffer test\n"); OutBuffer buf = new OutBuffer(); //printf("buf = %p\n", buf); //printf("buf.offset = %x\n", buf.offset); assert(buf.offset == 0); buf.write("hello"[]); buf.write(cast(byte)0x20); buf.write("world"[]); buf.printf(" %d", 6); //auto s = buf.toString(); //printf("buf = '%.*s'\n", s.length, s.ptr); assert(cmp(buf.toString(), "hello world 6") == 0); } unittest { import std.range; static assert(isOutputRange!(OutBuffer, char)); import std.algorithm; { OutBuffer buf = new OutBuffer(); "hello".copy(buf); assert(buf.toBytes() == "hello"); } { OutBuffer buf = new OutBuffer(); "hello"w.copy(buf); assert(buf.toBytes() == "h\x00e\x00l\x00l\x00o\x00"); } { OutBuffer buf = new OutBuffer(); "hello"d.copy(buf); assert(buf.toBytes() == "h\x00\x00\x00e\x00\x00\x00l\x00\x00\x00l\x00\x00\x00o\x00\x00\x00"); } } ldc-1.1.0-beta3-src/runtime/phobos/std/zip.d0000664000175000017500000007520412776215007016665 0ustar kaikai// Written in the D programming language. /** * Read/write data in the $(LINK2 http://www.info-_zip.org, zip archive) format. * Makes use of the etc.c.zlib compression library. * * Bugs: * $(UL * $(LI Multi-disk zips not supported.) * $(LI Only Zip version 20 formats are supported.) * $(LI Only supports compression modes 0 (no compression) and 8 (deflate).) * $(LI Does not support encryption.) * $(LI $(BUGZILLA 592)) * $(LI $(BUGZILLA 2137)) * ) * * Macros: * WIKI = Phobos/StdZip * * Example: * --- // Read existing zip file. import std.digest.crc, std.file, std.stdio, std.zip; void main(string[] args) { // read a zip file into memory auto zip = new ZipArchive(read(args[1])); writeln("Archive: ", args[1]); writefln("%-10s %-8s Name", "Length", "CRC-32"); // iterate over all zip members foreach (name, am; zip.directory) { // print some data about each member writefln("%10s %08x %s", am.expandedSize, am.crc32, name); assert(am.expandedData.length == 0); // decompress the archive member zip.expand(am); assert(am.expandedData.length == am.expandedSize); } } // Create and write new zip file. import std.file: write; import std.string: representation; void main() { char[] data = "Test data.\n".dup; // Create an ArchiveMember for the test file. ArchiveMember am = new ArchiveMember(); am.name = "test.txt"; am.expandedData(data.representation); // Create an archive and add the member. ZipArchive zip = new ZipArchive(); zip.addMember(am); // Build the archive void[] compressed_data = zip.build(); // Write to a file write("test.zip", compressed_data); } * --- * * Copyright: Copyright Digital Mars 2000 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * Source: $(PHOBOSSRC std/_zip.d) */ /* Copyright Digital Mars 2000 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.zip; //debug=print; /** Thrown on error. */ class ZipException : Exception { this(string msg) { super("ZipException: " ~ msg); } } /** * Compression method used by ArchiveMember */ enum CompressionMethod : ushort { none = 0, /// No compression, just archiving deflate = 8 /// Deflate algorithm. Use zlib library to compress } /** * A member of the ZipArchive. */ final class ArchiveMember { import std.conv : to, octal; import std.datetime : DosFileTime, SysTime, SysTimeToDosFileTime; /** * Read/Write: Usually the file name of the archive member; it is used to * index the archive directory for the member. Each member must have a unique * name[]. Do not change without removing member from the directory first. */ string name; ubyte[] extra; /// Read/Write: extra data for this member. string comment; /// Read/Write: comment associated with this member. private ubyte[] _compressedData; private ubyte[] _expandedData; private uint offset; private uint _crc32; private uint _compressedSize; private uint _expandedSize; private CompressionMethod _compressionMethod; private ushort _madeVersion = 20; private ushort _extractVersion = 20; private ushort _diskNumber; private uint _externalAttributes; private DosFileTime _time; ushort flags; /// Read/Write: normally set to 0 ushort internalAttributes; /// Read/Write @property ushort extractVersion() { return _extractVersion; } /// Read Only @property uint crc32() { return _crc32; } /// Read Only: cyclic redundancy check (CRC) value /// Read Only: size of data of member in compressed form. @property uint compressedSize() { return _compressedSize; } /// Read Only: size of data of member in expanded form. @property uint expandedSize() { return _expandedSize; } @property ushort diskNumber() { return _diskNumber; } /// Read Only: should be 0. /// Read Only: data of member in compressed form. @property ubyte[] compressedData() { return _compressedData; } /// Read data of member in uncompressed form. @property ubyte[] expandedData() { return _expandedData; } /// Write data of member in uncompressed form. @property void expandedData(ubyte[] ed) { _expandedData = ed; _expandedSize = to!uint(_expandedData.length); // Clean old compressed data, if any _compressedData.length = 0; _compressedSize = 0; } /** * Set the OS specific file attributes, as obtained by * $(XREF file,getAttributes) or $(XREF file,DirEntry.attributes), for this archive member. */ @property void fileAttributes(uint attr) { version (Posix) { _externalAttributes = (attr & 0xFFFF) << 16; _madeVersion &= 0x00FF; _madeVersion |= 0x0300; // attributes are in UNIX format } else version (Windows) { _externalAttributes = attr; _madeVersion &= 0x00FF; // attributes are in MS-DOS and OS/2 format } else { static assert(0, "Unimplemented platform"); } } version (Posix) unittest { auto am = new ArchiveMember(); am.fileAttributes = octal!100644; assert(am._externalAttributes == octal!100644 << 16); assert((am._madeVersion & 0xFF00) == 0x0300); } /** * Get the OS specific file attributes for the archive member. * * Returns: The file attributes or 0 if the file attributes were * encoded for an incompatible OS (Windows vs. Posix). * */ @property uint fileAttributes() const { version (Posix) { if ((_madeVersion & 0xFF00) == 0x0300) return _externalAttributes >> 16; return 0; } else version (Windows) { if ((_madeVersion & 0xFF00) == 0x0000) return _externalAttributes; return 0; } else { static assert(0, "Unimplemented platform"); } } /// Set the last modification time for this member. @property void time(SysTime time) { _time = SysTimeToDosFileTime(time); } /// ditto @property void time(DosFileTime time) { _time = time; } /// Get the last modification time for this member. @property DosFileTime time() const { return _time; } /** * Read compression method used for this member * See_Also: * CompressionMethod **/ @property CompressionMethod compressionMethod() { return _compressionMethod; } /** * Write compression method used for this member * See_Also: * CompressionMethod **/ @property void compressionMethod(CompressionMethod cm) { if (cm == _compressionMethod) return; if (_compressedSize > 0) throw new ZipException("Can't change compression method for a compressed element"); _compressionMethod = cm; } debug(print) { void print() { printf("name = '%.*s'\n", name.length, name.ptr); printf("\tcomment = '%.*s'\n", comment.length, comment.ptr); printf("\tmadeVersion = x%04x\n", _madeVersion); printf("\textractVersion = x%04x\n", extractVersion); printf("\tflags = x%04x\n", flags); printf("\tcompressionMethod = %d\n", compressionMethod); printf("\ttime = %d\n", time); printf("\tcrc32 = x%08x\n", crc32); printf("\texpandedSize = %d\n", expandedSize); printf("\tcompressedSize = %d\n", compressedSize); printf("\tinternalAttributes = x%04x\n", internalAttributes); printf("\texternalAttributes = x%08x\n", externalAttributes); } } } /** * Object representing the entire archive. * ZipArchives are collections of ArchiveMembers. */ final class ZipArchive { import std.bitmanip : littleEndianToNative, nativeToLittleEndian; import std.algorithm : max; import std.conv : to; import std.datetime : DosFileTime; string comment; /// Read/Write: the archive comment. Must be less than 65536 bytes in length. private ubyte[] _data; private uint endrecOffset; private uint _diskNumber; private uint _diskStartDir; private uint _numEntries; private uint _totalEntries; private bool _isZip64; static const ushort zip64ExtractVersion = 45; static const int digiSignLength = 6; static const int eocd64LocLength = 20; static const int eocd64Length = 56; /// Read Only: array representing the entire contents of the archive. @property ubyte[] data() { return _data; } /// Read Only: 0 since multi-disk zip archives are not supported. @property uint diskNumber() { return _diskNumber; } /// Read Only: 0 since multi-disk zip archives are not supported @property uint diskStartDir() { return _diskStartDir; } /// Read Only: number of ArchiveMembers in the directory. @property uint numEntries() { return _numEntries; } @property uint totalEntries() { return _totalEntries; } /// ditto /// True when the archive is in Zip64 format. @property bool isZip64() { return _isZip64; } /// Set this to true to force building a Zip64 archive. @property void isZip64(bool value) { _isZip64 = value; } /** * Read Only: array indexed by the name of each member of the archive. * All the members of the archive can be accessed with a foreach loop: * Example: * -------------------- * ZipArchive archive = new ZipArchive(data); * foreach (ArchiveMember am; archive.directory) * { * writefln("member name is '%s'", am.name); * } * -------------------- */ @property ArchiveMember[string] directory() { return _directory; } private ArchiveMember[string] _directory; debug (print) { void print() { printf("\tdiskNumber = %u\n", diskNumber); printf("\tdiskStartDir = %u\n", diskStartDir); printf("\tnumEntries = %u\n", numEntries); printf("\ttotalEntries = %u\n", totalEntries); printf("\tcomment = '%.*s'\n", comment.length, comment.ptr); } } /* ============ Creating a new archive =================== */ /** Constructor to use when creating a new archive. */ this() { } /** Add de to the archive. */ void addMember(ArchiveMember de) { _directory[de.name] = de; } /** Delete de from the archive. */ void deleteMember(ArchiveMember de) { _directory.remove(de.name); } /** * Construct an archive out of the current members of the archive. * * Fills in the properties data[], diskNumber, diskStartDir, numEntries, * totalEntries, and directory[]. * For each ArchiveMember, fills in properties crc32, compressedSize, * compressedData[]. * * Returns: array representing the entire archive. */ void[] build() { uint i; uint directoryOffset; if (comment.length > 0xFFFF) throw new ZipException("archive comment longer than 65535"); // Compress each member; compute size uint archiveSize = 0; uint directorySize = 0; foreach (ArchiveMember de; _directory) { if (!de._compressedData.length) { switch (de.compressionMethod) { case CompressionMethod.none: de._compressedData = de._expandedData; break; case CompressionMethod.deflate: import std.zlib : compress; de._compressedData = cast(ubyte[])compress(cast(void[])de._expandedData); de._compressedData = de._compressedData[2 .. de._compressedData.length - 4]; break; default: throw new ZipException("unsupported compression method"); } de._compressedSize = to!uint(de._compressedData.length); import std.zlib : crc32; de._crc32 = crc32(0, cast(void[])de._expandedData); } assert(de._compressedData.length == de._compressedSize); if (to!ulong(archiveSize) + 30 + de.name.length + de.extra.length + de.compressedSize + directorySize + 46 + de.name.length + de.extra.length + de.comment.length + 22 + comment.length + eocd64LocLength + eocd64Length > uint.max) throw new ZipException("zip files bigger than 4 GB are unsupported"); archiveSize += 30 + de.name.length + de.extra.length + de.compressedSize; directorySize += 46 + de.name.length + de.extra.length + de.comment.length; } if (!isZip64 && _directory.length > ushort.max) _isZip64 = true; uint dataSize = archiveSize + directorySize + 22 + cast(uint)comment.length; if (isZip64) dataSize += eocd64LocLength + eocd64Length; _data = new ubyte[dataSize]; // Populate the data[] // Store each archive member i = 0; foreach (ArchiveMember de; _directory) { de.offset = i; _data[i .. i + 4] = cast(ubyte[])"PK\x03\x04"; putUshort(i + 4, de.extractVersion); putUshort(i + 6, de.flags); putUshort(i + 8, de._compressionMethod); putUint (i + 10, cast(uint)de.time); putUint (i + 14, de.crc32); putUint (i + 18, de.compressedSize); putUint (i + 22, to!uint(de.expandedSize)); putUshort(i + 26, cast(ushort)de.name.length); putUshort(i + 28, cast(ushort)de.extra.length); i += 30; _data[i .. i + de.name.length] = (cast(ubyte[])de.name)[]; i += de.name.length; _data[i .. i + de.extra.length] = (cast(ubyte[])de.extra)[]; i += de.extra.length; _data[i .. i + de.compressedSize] = de.compressedData[]; i += de.compressedSize; } // Write directory directoryOffset = i; _numEntries = 0; foreach (ArchiveMember de; _directory) { _data[i .. i + 4] = cast(ubyte[])"PK\x01\x02"; putUshort(i + 4, de._madeVersion); putUshort(i + 6, de.extractVersion); putUshort(i + 8, de.flags); putUshort(i + 10, de._compressionMethod); putUint (i + 12, cast(uint)de.time); putUint (i + 16, de.crc32); putUint (i + 20, de.compressedSize); putUint (i + 24, de.expandedSize); putUshort(i + 28, cast(ushort)de.name.length); putUshort(i + 30, cast(ushort)de.extra.length); putUshort(i + 32, cast(ushort)de.comment.length); putUshort(i + 34, de.diskNumber); putUshort(i + 36, de.internalAttributes); putUint (i + 38, de._externalAttributes); putUint (i + 42, de.offset); i += 46; _data[i .. i + de.name.length] = (cast(ubyte[])de.name)[]; i += de.name.length; _data[i .. i + de.extra.length] = (cast(ubyte[])de.extra)[]; i += de.extra.length; _data[i .. i + de.comment.length] = (cast(ubyte[])de.comment)[]; i += de.comment.length; _numEntries++; } _totalEntries = numEntries; if (isZip64) { // Write zip64 end of central directory record uint eocd64Offset = i; _data[i .. i + 4] = cast(ubyte[])"PK\x06\x06"; putUlong (i + 4, eocd64Length - 12); putUshort(i + 12, zip64ExtractVersion); putUshort(i + 14, zip64ExtractVersion); putUint (i + 16, diskNumber); putUint (i + 20, diskStartDir); putUlong (i + 24, numEntries); putUlong (i + 32, totalEntries); putUlong (i + 40, directorySize); putUlong (i + 48, directoryOffset); i += eocd64Length; // Write zip64 end of central directory record locator _data[i .. i + 4] = cast(ubyte[])"PK\x06\x07"; putUint (i + 4, diskNumber); putUlong (i + 8, eocd64Offset); putUint (i + 16, 1); i += eocd64LocLength; } // Write end record endrecOffset = i; _data[i .. i + 4] = cast(ubyte[])"PK\x05\x06"; putUshort(i + 4, cast(ushort)diskNumber); putUshort(i + 6, cast(ushort)diskStartDir); putUshort(i + 8, (numEntries > ushort.max ? ushort.max : cast(ushort)numEntries)); putUshort(i + 10, (totalEntries > ushort.max ? ushort.max : cast(ushort)totalEntries)); putUint (i + 12, directorySize); putUint (i + 16, directoryOffset); putUshort(i + 20, cast(ushort)comment.length); i += 22; // Write archive comment assert(i + comment.length == data.length); _data[i .. data.length] = (cast(ubyte[])comment)[]; return cast(void[])data; } /* ============ Reading an existing archive =================== */ /** * Constructor to use when reading an existing archive. * * Fills in the properties data[], diskNumber, diskStartDir, numEntries, * totalEntries, comment[], and directory[]. * For each ArchiveMember, fills in * properties madeVersion, extractVersion, flags, compressionMethod, time, * crc32, compressedSize, expandedSize, compressedData[], diskNumber, * internalAttributes, externalAttributes, name[], extra[], comment[]. * Use expand() to get the expanded data for each ArchiveMember. * * Params: * buffer = the entire contents of the archive. */ this(void[] buffer) { uint iend; uint i; int endcommentlength; uint directorySize; uint directoryOffset; this._data = cast(ubyte[]) buffer; if (data.length > uint.max - 2) throw new ZipException("zip files bigger than 4 GB are unsupported"); // Find 'end record index' by searching backwards for signature iend = (data.length > 66000 ? to!uint(data.length - 66000) : 0); for (i = to!uint(data.length) - 22; 1; i--) { if (i < iend || i >= data.length) throw new ZipException("no end record"); if (_data[i .. i + 4] == cast(ubyte[])"PK\x05\x06") { endcommentlength = getUshort(i + 20); if (i + 22 + endcommentlength > data.length || i + 22 + endcommentlength < i) continue; comment = cast(string)(_data[i + 22 .. i + 22 + endcommentlength]); endrecOffset = i; uint k = i - eocd64LocLength; if (k < i && _data[k .. k + 4] == cast(ubyte[])"PK\x06\x07") { _isZip64 = true; i = k; } break; } } if (isZip64) { // Read Zip64 record data uint eocd64LocStart = i; ulong eocdOffset = getUlong(i + 8); if (eocdOffset + eocd64Length > _data.length) throw new ZipException("corrupted directory"); i = to!uint(eocdOffset); if (_data[i .. i + 4] != cast(ubyte[])"PK\x06\x06") throw new ZipException("invalid Zip EOCD64 signature"); ulong eocd64Size = getUlong(i + 4); if (eocd64Size + i - 12 > data.length) throw new ZipException("invalid Zip EOCD64 size"); _diskNumber = getUint(i + 16); _diskStartDir = getUint(i + 20); ulong numEntriesUlong = getUlong(i + 24); ulong totalEntriesUlong = getUlong(i + 32); ulong directorySizeUlong = getUlong(i + 40); ulong directoryOffsetUlong = getUlong(i + 48); if (numEntriesUlong > uint.max) throw new ZipException("supposedly more than 4294967296 files in archive"); if (numEntriesUlong != totalEntriesUlong) throw new ZipException("multiple disk zips not supported"); if (directorySizeUlong > i || directoryOffsetUlong > i || directorySizeUlong + directoryOffsetUlong > i) throw new ZipException("corrupted directory"); _numEntries = to!uint(numEntriesUlong); _totalEntries = to!uint(totalEntriesUlong); directorySize = to!uint(directorySizeUlong); directoryOffset = to!uint(directoryOffsetUlong); } else { // Read end record data _diskNumber = getUshort(i + 4); _diskStartDir = getUshort(i + 6); _numEntries = getUshort(i + 8); _totalEntries = getUshort(i + 10); if (numEntries != totalEntries) throw new ZipException("multiple disk zips not supported"); directorySize = getUint(i + 12); directoryOffset = getUint(i + 16); if (directoryOffset + directorySize > i) throw new ZipException("corrupted directory"); } i = directoryOffset; for (int n = 0; n < numEntries; n++) { /* The format of an entry is: * 'PK' 1, 2 * directory info * path * extra data * comment */ uint offset; uint namelen; uint extralen; uint commentlen; if (_data[i .. i + 4] != cast(ubyte[])"PK\x01\x02") throw new ZipException("invalid directory entry 1"); ArchiveMember de = new ArchiveMember(); de._madeVersion = getUshort(i + 4); de._extractVersion = getUshort(i + 6); de.flags = getUshort(i + 8); de._compressionMethod = cast(CompressionMethod)getUshort(i + 10); de.time = cast(DosFileTime)getUint(i + 12); de._crc32 = getUint(i + 16); de._compressedSize = getUint(i + 20); de._expandedSize = getUint(i + 24); namelen = getUshort(i + 28); extralen = getUshort(i + 30); commentlen = getUshort(i + 32); de._diskNumber = getUshort(i + 34); de.internalAttributes = getUshort(i + 36); de._externalAttributes = getUint(i + 38); de.offset = getUint(i + 42); i += 46; if (i + namelen + extralen + commentlen > directoryOffset + directorySize) throw new ZipException("invalid directory entry 2"); de.name = cast(string)(_data[i .. i + namelen]); i += namelen; de.extra = _data[i .. i + extralen]; i += extralen; de.comment = cast(string)(_data[i .. i + commentlen]); i += commentlen; immutable uint dataOffset = de.offset + 30 + namelen + extralen; if (dataOffset + de.compressedSize > endrecOffset) throw new ZipException("Invalid directory entry offset or size."); de._compressedData = _data[dataOffset .. dataOffset + de.compressedSize]; _directory[de.name] = de; } if (i != directoryOffset + directorySize) throw new ZipException("invalid directory entry 3"); } /***** * Decompress the contents of archive member de and return the expanded * data. * * Fills in properties extractVersion, flags, compressionMethod, time, * crc32, compressedSize, expandedSize, expandedData[], name[], extra[]. */ ubyte[] expand(ArchiveMember de) { uint namelen; uint extralen; if (_data[de.offset .. de.offset + 4] != cast(ubyte[])"PK\x03\x04") throw new ZipException("invalid directory entry 4"); // These values should match what is in the main zip archive directory de._extractVersion = getUshort(de.offset + 4); de.flags = getUshort(de.offset + 6); de._compressionMethod = cast(CompressionMethod)getUshort(de.offset + 8); de.time = cast(DosFileTime)getUint(de.offset + 10); de._crc32 = getUint(de.offset + 14); de._compressedSize = max(getUint(de.offset + 18), de.compressedSize); de._expandedSize = max(getUint(de.offset + 22), de.expandedSize); namelen = getUshort(de.offset + 26); extralen = getUshort(de.offset + 28); debug(print) { printf("\t\texpandedSize = %d\n", de.expandedSize); printf("\t\tcompressedSize = %d\n", de.compressedSize); printf("\t\tnamelen = %d\n", namelen); printf("\t\textralen = %d\n", extralen); } if (de.flags & 1) throw new ZipException("encryption not supported"); int i; i = de.offset + 30 + namelen + extralen; if (i + de.compressedSize > endrecOffset) throw new ZipException("invalid directory entry 5"); de._compressedData = _data[i .. i + de.compressedSize]; debug(print) arrayPrint(de.compressedData); switch (de.compressionMethod) { case CompressionMethod.none: de._expandedData = de.compressedData; return de.expandedData; case CompressionMethod.deflate: // -15 is a magic value used to decompress zip files. // It has the effect of not requiring the 2 byte header // and 4 byte trailer. import std.zlib : uncompress; de._expandedData = cast(ubyte[])uncompress(cast(void[])de.compressedData, de.expandedSize, -15); return de.expandedData; default: throw new ZipException("unsupported compression method"); } } /* ============ Utility =================== */ ushort getUshort(int i) { ubyte[2] result = data[i .. i + 2]; return littleEndianToNative!ushort(result); } uint getUint(int i) { ubyte[4] result = data[i .. i + 4]; return littleEndianToNative!uint(result); } ulong getUlong(int i) { ubyte[8] result = data[i .. i + 8]; return littleEndianToNative!ulong(result); } void putUshort(int i, ushort us) { data[i .. i + 2] = nativeToLittleEndian(us); } void putUint(int i, uint ui) { data[i .. i + 4] = nativeToLittleEndian(ui); } void putUlong(int i, ulong ul) { data[i .. i + 8] = nativeToLittleEndian(ul); } } debug(print) { void arrayPrint(ubyte[] array) { printf("array %p,%d\n", cast(void*)array, array.length); for (int i = 0; i < array.length; i++) { printf("%02x ", array[i]); if (((i + 1) & 15) == 0) printf("\n"); } printf("\n"); } } unittest { auto zip1 = new ZipArchive(); auto zip2 = new ZipArchive(); auto am1 = new ArchiveMember(); am1.name = "foo"; am1.expandedData = new ubyte[](1024); zip1.addMember(am1); auto data1 = zip1.build(); zip2.addMember(zip1.directory["foo"]); zip2.build(); auto am2 = zip2.directory["foo"]; zip2.expand(am2); assert(am1.expandedData == am2.expandedData); auto zip3 = new ZipArchive(data1); zip3.build(); assert(zip3.directory["foo"].compressedSize == am1.compressedSize); // Test if packing and unpacking produces the original data import std.random : uniform, MinstdRand0; import std.stdio, std.conv; MinstdRand0 gen; const uint itemCount = 20, minSize = 10, maxSize = 500; foreach (variant; 0..2) { bool useZip64 = !!variant; zip1 = new ZipArchive(); zip1.isZip64 = useZip64; ArchiveMember[itemCount] ams; foreach (i; 0..itemCount) { ams[i] = new ArchiveMember(); ams[i].name = to!string(i); ams[i].expandedData = new ubyte[](uniform(minSize, maxSize)); foreach (ref ubyte c; ams[i].expandedData) c = cast(ubyte)(uniform(0, 256)); ams[i].compressionMethod = CompressionMethod.deflate; zip1.addMember(ams[i]); } auto zippedData = zip1.build(); zip2 = new ZipArchive(zippedData); assert(zip2.isZip64 == useZip64); foreach (am; ams) { am2 = zip2.directory[am.name]; zip2.expand(am2); assert(am.crc32 == am2.crc32); assert(am.expandedData == am2.expandedData); } } } unittest { import std.zlib; ubyte[] src = cast(ubyte[]) "the quick brown fox jumps over the lazy dog\r the quick brown fox jumps over the lazy dog\r "; auto dst = cast(ubyte[])compress(cast(void[])src); auto after = cast(ubyte[])uncompress(cast(void[])dst); assert(src == after); } unittest { import std.datetime; ubyte[] buf = [1, 2, 3, 4, 5, 0, 7, 8, 9]; auto ar = new ZipArchive; auto am = new ArchiveMember; // 10 am.name = "buf"; am.expandedData = buf; am.compressionMethod = CompressionMethod.deflate; am.time = SysTimeToDosFileTime(Clock.currTime()); ar.addMember(am); // 15 auto zip1 = ar.build(); auto arAfter = new ZipArchive(zip1); assert(arAfter.directory.length == 1); auto amAfter = arAfter.directory["buf"]; arAfter.expand(amAfter); assert(amAfter.name == am.name); assert(amAfter.expandedData == am.expandedData); assert(amAfter.time == am.time); } // Non-Android Posix-only, because we can't rely on the unzip command being // available on Android or Windows version(Android) {} else version(Posix) unittest { import std.datetime, std.file, std.format, std.path, std.process, std.stdio; auto zr = new ZipArchive(); auto am = new ArchiveMember(); am.compressionMethod = CompressionMethod.deflate; am.name = "foo.bar"; am.time = SysTimeToDosFileTime(Clock.currTime()); am.expandedData = cast(ubyte[])"We all live in a yellow submarine, a yellow submarine"; zr.addMember(am); auto data2 = zr.build(); mkdirRecurse(deleteme); scope(exit) rmdirRecurse(deleteme); string zipFile = buildPath(deleteme, "foo.zip"); std.file.write(zipFile, cast(byte[])data2); auto result = executeShell(format("unzip -l %s", zipFile)); scope(failure) writeln(result.output); assert(result.status == 0); } ldc-1.1.0-beta3-src/runtime/phobos/std/csv.d0000664000175000017500000013423112776215007016652 0ustar kaikai//Written in the D programming language /** * Implements functionality to read Comma Separated Values and its variants * from a input range of $(D dchar). * * Comma Separated Values provide a simple means to transfer and store * tabular data. It has been common for programs to use their own * variant of the CSV format. This parser will loosely follow the * $(WEB tools.ietf.org/html/rfc4180, RFC-4180). CSV input should adhered * to the following criteria, differences from RFC-4180 in parentheses. * * $(UL * $(LI A record is separated by a new line (CRLF,LF,CR)) * $(LI A final record may end with a new line) * $(LI A header may be provided as the first record in input) * $(LI A record has fields separated by a comma (customizable)) * $(LI A field containing new lines, commas, or double quotes * should be enclosed in double quotes (customizable)) * $(LI Double quotes in a field are escaped with a double quote) * $(LI Each record should contain the same number of fields) * ) * * Example: * * ------- * import std.algorithm; * import std.array; * import std.csv; * import std.stdio; * import std.typecons; * * void main() * { * auto text = "Joe,Carpenter,300000\nFred,Blacksmith,400000\r\n"; * * foreach(record; csvReader!(Tuple!(string, string, int))(text)) * { * writefln("%s works as a %s and earns $%d per year", * record[0], record[1], record[2]); * } * * // To read the same string from the file "filename.csv": * * auto file = File("filename.csv", "r"); * foreach(record; * file.byLine.joiner("\n").csvReader!(Tuple!(string, string, int))) * { * writefln("%s works as a %s and earns $%d per year", * record[0], record[1], record[2]); * } } * } * ------- * * When an input contains a header the $(D Contents) can be specified as an * associative array. Passing null to signify that a header is present. * * ------- * auto text = "Name,Occupation,Salary\r" * "Joe,Carpenter,300000\nFred,Blacksmith,400000\r\n"; * * foreach(record; csvReader!(string[string]) * (text, null)) * { * writefln("%s works as a %s and earns $%s per year.", * record["Name"], record["Occupation"], * record["Salary"]); * } * ------- * * This module allows content to be iterated by record stored in a struct, * class, associative array, or as a range of fields. Upon detection of an * error an CSVException is thrown (can be disabled). csvNextToken has been * made public to allow for attempted recovery. * * Disabling exceptions will lift many restrictions specified above. A quote * can appear in a field if the field was not quoted. If in a quoted field any * quote by itself, not at the end of a field, will end processing for that * field. The field is ended when there is no input, even if the quote was not * closed. * * See_Also: * $(WEB en.wikipedia.org/wiki/Comma-separated_values, Wikipedia * Comma-separated values) * * Copyright: Copyright 2011 * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Jesse Phillips * Source: $(PHOBOSSRC std/_csv.d) */ module std.csv; import std.conv; import std.range.primitives; import std.traits; import std.exception; // basicExceptionCtors /** * Exception containing the row and column for when an exception was thrown. * * Numbering of both row and col start at one and corresponds to the location * in the file rather than any specified header. Special consideration should * be made when there is failure to match the header see $(LREF * HeaderMismatchException) for details. * * When performing type conversions, $(XREF ConvException) is stored in the $(D * next) field. */ class CSVException : Exception { /// size_t row, col; // FIXME: Use std.exception.basicExceptionCtors here once bug #11500 is fixed this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @nogc @safe pure nothrow { super(msg, file, line, next); } this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @nogc @safe pure nothrow { super(msg, file, line, next); } this(string msg, size_t row, size_t col, Throwable next = null, string file = __FILE__, size_t line = __LINE__) @nogc @safe pure nothrow { super(msg, next, file, line); this.row = row; this.col = col; } override string toString() @safe pure { return "(Row: " ~ to!string(row) ~ ", Col: " ~ to!string(col) ~ ") " ~ msg; } } @safe pure unittest { import std.string; auto e1 = new Exception("Foobar"); auto e2 = new CSVException("args", e1); assert(e2.next is e1); size_t r = 13; size_t c = 37; auto e3 = new CSVException("argv", r, c); assert(e3.row == r); assert(e3.col == c); auto em = e3.toString(); assert(em.indexOf("13") != -1); assert(em.indexOf("37") != -1); } /** * Exception thrown when a Token is identified to not be completed: a quote is * found in an unquoted field, data continues after a closing quote, or the * quoted field was not closed before data was empty. */ class IncompleteCellException : CSVException { /// Data pulled from input before finding a problem /// /// This field is populated when using $(LREF csvReader) /// but not by $(LREF csvNextToken) as this data will have /// already been fed to the output range. dstring partialData; mixin basicExceptionCtors; } @safe pure unittest { auto e1 = new Exception("Foobar"); auto e2 = new IncompleteCellException("args", e1); assert(e2.next is e1); } /** * Exception thrown under different conditions based on the type of $(D * Contents). * * Structure, Class, and Associative Array * $(UL * $(LI When a header is provided but a matching column is not found) * ) * * Other * $(UL * $(LI When a header is provided but a matching column is not found) * $(LI Order did not match that found in the input) * ) * * Since a row and column is not meaningful when a column specified by the * header is not found in the data, both row and col will be zero. Otherwise * row is always one and col is the first instance found in header that * occurred before the previous starting at one. */ class HeaderMismatchException : CSVException { mixin basicExceptionCtors; } @safe pure unittest { auto e1 = new Exception("Foobar"); auto e2 = new HeaderMismatchException("args", e1); assert(e2.next is e1); } /** * Determines the behavior for when an error is detected. * * Disabling exception will follow these rules: * $(UL * $(LI A quote can appear in a field if the field was not quoted.) * $(LI If in a quoted field any quote by itself, not at the end of a * field, will end processing for that field.) * $(LI The field is ended when there is no input, even if the quote was * not closed.) * $(LI If the given header does not match the order in the input, the * content will return as it is found in the input.) * $(LI If the given header contains columns not found in the input they * will be ignored.) * ) */ enum Malformed { /// No exceptions are thrown due to incorrect CSV. ignore, /// Use exceptions when input has incorrect CSV. throwException } /** * Returns an input range for iterating over records found in $(D * input). * * The $(D Contents) of the input can be provided if all the records are the * same type such as all integer data: * * ------- * string str = `76,26,22`; * int[] ans = [76,26,22]; * auto records = csvReader!int(str); * * foreach(record; records) * { * assert(equal(record, ans)); * } * ------- * * Example using a struct with modified delimiter: * * ------- * string str = "Hello;65;63.63\nWorld;123;3673.562"; * struct Layout * { * string name; * int value; * double other; * } * * auto records = csvReader!Layout(str,';'); * * foreach(record; records) * { * writeln(record.name); * writeln(record.value); * writeln(record.other); * } * ------- * * Specifying $(D ErrorLevel) as Malformed.ignore will lift restrictions * on the format. This example shows that an exception is not thrown when * finding a quote in a field not quoted. * * ------- * string str = "A \" is now part of the data"; * auto records = csvReader!(string,Malformed.ignore)(str); * auto record = records.front; * * assert(record.front == str); * ------- * * Returns: * An input range R as defined by * $(XREF_PACK range,primitives,isInputRange). When $(D Contents) is a * struct, class, or an associative array, the element type of R is * $(D Contents), otherwise the element type of R is itself a range with * element type $(D Contents). * * Throws: * $(LREF CSVException) When a quote is found in an unquoted field, * data continues after a closing quote, the quoted field was not * closed before data was empty, a conversion failed, or when the row's * length does not match the previous length. * * $(LREF HeaderMismatchException) when a header is provided but a * matching column is not found or the order did not match that found in * the input. Read the exception documentation for specific details of * when the exception is thrown for different types of $(D Contents). */ auto csvReader(Contents = string,Malformed ErrorLevel = Malformed.throwException, Range, Separator = char)(Range input, Separator delimiter = ',', Separator quote = '"') if (isInputRange!Range && is(Unqual!(ElementType!Range) == dchar) && isSomeChar!(Separator) && !is(Contents T : T[U], U : string)) { return CsvReader!(Contents,ErrorLevel,Range, Unqual!(ElementType!Range),string[]) (input, delimiter, quote); } /** * An optional $(D header) can be provided. The first record will be read in * as the header. If $(D Contents) is a struct then the header provided is * expected to correspond to the fields in the struct. When $(D Contents) is * not a type which can contain the entire record, the $(D header) must be * provided in the same order as the input or an exception is thrown. * * Read only column "b": * * ------- * string str = "a,b,c\nHello,65,63.63\nWorld,123,3673.562"; * auto records = csvReader!int(str, ["b"]); * * auto ans = [[65],[123]]; * foreach(record; records) * { * assert(equal(record, ans.front)); * ans.popFront(); * } * ------- * * Read from header of different order: * * ------- * string str = "a,b,c\nHello,65,63.63\nWorld,123,3673.562"; * struct Layout * { * int value; * double other; * string name; * } * * auto records = csvReader!Layout(str, ["b","c","a"]); * ------- * * The header can also be left empty if the input contains a header but * all columns should be iterated. The header from the input can always * be accessed from the header field. * * ------- * string str = "a,b,c\nHello,65,63.63\nWorld,123,3673.562"; * auto records = csvReader(str, null); * * assert(records.header == ["a","b","c"]); * ------- * * Returns: * An input range R as defined by * $(XREF_PACK range,primitives,isInputRange). When $(D Contents) is a * struct, class, or an associative array, the element type of R is * $(D Contents), otherwise the element type of R is itself a range with * element type $(D Contents). * * The returned range provides a header field for accessing the header * from the input in array form. * * ------- * string str = "a,b,c\nHello,65,63.63"; * auto records = csvReader(str, ["a"]); * * assert(records.header == ["a","b","c"]); * ------- * * Throws: * $(LREF CSVException) When a quote is found in an unquoted field, * data continues after a closing quote, the quoted field was not * closed before data was empty, a conversion failed, or when the row's * length does not match the previous length. * * $(LREF HeaderMismatchException) when a header is provided but a * matching column is not found or the order did not match that found in * the input. Read the exception documentation for specific details of * when the exception is thrown for different types of $(D Contents). */ auto csvReader(Contents = string, Malformed ErrorLevel = Malformed.throwException, Range, Header, Separator = char) (Range input, Header header, Separator delimiter = ',', Separator quote = '"') if (isInputRange!Range && is(Unqual!(ElementType!Range) == dchar) && isSomeChar!(Separator) && isForwardRange!Header && isSomeString!(ElementType!Header)) { return CsvReader!(Contents,ErrorLevel,Range, Unqual!(ElementType!Range),Header) (input, header, delimiter, quote); } /// auto csvReader(Contents = string, Malformed ErrorLevel = Malformed.throwException, Range, Header, Separator = char) (Range input, Header header, Separator delimiter = ',', Separator quote = '"') if (isInputRange!Range && is(Unqual!(ElementType!Range) == dchar) && isSomeChar!(Separator) && is(Header : typeof(null))) { return CsvReader!(Contents,ErrorLevel,Range, Unqual!(ElementType!Range),string[]) (input, cast(string[])null, delimiter, quote); } // Test standard iteration over input. @safe pure unittest { string str = `one,"two ""quoted"""` ~ "\n\"three\nnew line\",\nfive,six"; auto records = csvReader(str); int count; foreach(record; records) { foreach(cell; record) { count++; } } assert(count == 6); } // Test newline on last record @safe pure unittest { string str = "one,two\nthree,four\n"; auto records = csvReader(str); records.popFront(); records.popFront(); assert(records.empty); } // Test shorter row length @safe pure unittest { wstring str = "one,1\ntwo\nthree"w; struct Layout { string name; int value; } Layout[3] ans; ans[0].name = "one"; ans[0].value = 1; ans[1].name = "two"; ans[1].value = 0; ans[2].name = "three"; ans[2].value = 0; auto records = csvReader!(Layout,Malformed.ignore)(str); int count; foreach(record; records) { assert(ans[count].name == record.name); assert(ans[count].value == record.value); count++; } } // Test shorter row length exception @safe pure unittest { import std.exception; struct A { string a,b,c; } auto strs = ["one,1\ntwo", "one\ntwo,2,二\nthree,3,三", "one\ntwo,2\nthree,3", "one,1\ntwo\nthree,3"]; foreach(str; strs) { auto records = csvReader!A(str); assertThrown!CSVException((){foreach(record; records) { }}()); } } // Test structure conversion interface with unicode. @safe pure unittest { import std.math : abs; wstring str = "\U00010143Hello,65,63.63\nWorld,123,3673.562"w; struct Layout { string name; int value; double other; } Layout[2] ans; ans[0].name = "\U00010143Hello"; ans[0].value = 65; ans[0].other = 63.63; ans[1].name = "World"; ans[1].value = 123; ans[1].other = 3673.562; auto records = csvReader!Layout(str); int count; foreach(record; records) { assert(ans[count].name == record.name); assert(ans[count].value == record.value); assert(abs(ans[count].other - record.other) < 0.00001); count++; } assert(count == ans.length); } // Test input conversion interface @safe pure unittest { import std.algorithm; string str = `76,26,22`; int[] ans = [76,26,22]; auto records = csvReader!int(str); foreach(record; records) { assert(equal(record, ans)); } } // Test struct & header interface and same unicode unittest { import std.math : abs; string str = "a,b,c\nHello,65,63.63\n➊➋➂❹,123,3673.562"; struct Layout { int value; double other; string name; } auto records = csvReader!Layout(str, ["b","c","a"]); Layout[2] ans; ans[0].name = "Hello"; ans[0].value = 65; ans[0].other = 63.63; ans[1].name = "➊➋➂❹"; ans[1].value = 123; ans[1].other = 3673.562; int count; foreach (record; records) { assert(ans[count].name == record.name); assert(ans[count].value == record.value); assert(abs(ans[count].other - record.other) < 0.00001); count++; } assert(count == ans.length); } // Test header interface unittest { import std.algorithm; string str = "a,b,c\nHello,65,63.63\nWorld,123,3673.562"; auto records = csvReader!int(str, ["b"]); auto ans = [[65],[123]]; foreach(record; records) { assert(equal(record, ans.front)); ans.popFront(); } try { csvReader(str, ["c","b"]); assert(0); } catch(HeaderMismatchException e) { assert(e.col == 2); } auto records2 = csvReader!(string,Malformed.ignore) (str, ["b","a"], ',', '"'); auto ans2 = [["Hello","65"],["World","123"]]; foreach(record; records2) { assert(equal(record, ans2.front)); ans2.popFront(); } str = "a,c,e\nJoe,Carpenter,300000\nFred,Fly,4"; records2 = csvReader!(string,Malformed.ignore) (str, ["a","b","c","d"], ',', '"'); ans2 = [["Joe","Carpenter"],["Fred","Fly"]]; foreach(record; records2) { assert(equal(record, ans2.front)); ans2.popFront(); } } // Test null header interface unittest { string str = "a,b,c\nHello,65,63.63\nWorld,123,3673.562"; auto records = csvReader(str, ["a"]); assert(records.header == ["a","b","c"]); } // Test unchecked read @safe pure unittest { string str = "one \"quoted\""; foreach(record; csvReader!(string,Malformed.ignore)(str)) { foreach(cell; record) { assert(cell == "one \"quoted\""); } } str = "one \"quoted\",two \"quoted\" end"; struct Ans { string a,b; } foreach(record; csvReader!(Ans,Malformed.ignore)(str)) { assert(record.a == "one \"quoted\""); assert(record.b == "two \"quoted\" end"); } } // Test partial data returned @safe pure unittest { string str = "\"one\nnew line"; try { foreach(record; csvReader(str)) {} assert(0); } catch (IncompleteCellException ice) { assert(ice.partialData == "one\nnew line"); } } // Test Windows line break @safe pure unittest { string str = "one,two\r\nthree"; auto records = csvReader(str); auto record = records.front; assert(record.front == "one"); record.popFront(); assert(record.front == "two"); records.popFront(); record = records.front; assert(record.front == "three"); } // Test associative array support with unicode separator unittest { string str = "1❁2❁3\n34❁65❁63\n34❁65❁63"; auto records = csvReader!(string[string])(str,["3","1"],'❁'); int count; foreach(record; records) { count++; assert(record["1"] == "34"); assert(record["3"] == "63"); } assert(count == 2); } // Test restricted range unittest { import std.typecons; struct InputRange { dstring text; this(dstring txt) { text = txt; } @property auto empty() { return text.empty; } auto popFront() { text.popFront(); } @property dchar front() { return text[0]; } } auto ir = InputRange("Name,Occupation,Salary\r"d~ "Joe,Carpenter,300000\nFred,Blacksmith,400000\r\n"d); foreach(record; csvReader(ir, cast(string[])null)) foreach(cell; record) {} foreach(record; csvReader!(Tuple!(string, string, int)) (ir,cast(string[])null)) {} foreach(record; csvReader!(string[string]) (ir,cast(string[])null)) {} } unittest // const/immutable dchars { import std.algorithm: map; import std.array: array; const(dchar)[] c = "foo,bar\n"; assert(csvReader(c).map!array.array == [["foo", "bar"]]); immutable(dchar)[] i = "foo,bar\n"; assert(csvReader(i).map!array.array == [["foo", "bar"]]); } /* * This struct is stored on the heap for when the structures * are passed around. */ private pure struct Input(Range, Malformed ErrorLevel) { Range range; size_t row, col; static if (ErrorLevel == Malformed.throwException) size_t rowLength; } /* * Range for iterating CSV records. * * This range is returned by the $(LREF csvReader) functions. It can be * created in a similar manner to allow $(D ErrorLevel) be set to $(LREF * Malformed).ignore if best guess processing should take place. */ private struct CsvReader(Contents, Malformed ErrorLevel, Range, Separator, Header) if (isSomeChar!Separator && isInputRange!Range && is(Unqual!(ElementType!Range) == dchar) && isForwardRange!Header && isSomeString!(ElementType!Header)) { private: Input!(Range, ErrorLevel)* _input; Separator _separator; Separator _quote; size_t[] indices; bool _empty; static if (is(Contents == struct) || is(Contents == class)) { Contents recordContent; CsvRecord!(string, ErrorLevel, Range, Separator) recordRange; } else static if (is(Contents T : T[U], U : string)) { Contents recordContent; CsvRecord!(T, ErrorLevel, Range, Separator) recordRange; } else CsvRecord!(Contents, ErrorLevel, Range, Separator) recordRange; public: /** * Header from the input in array form. * * ------- * string str = "a,b,c\nHello,65,63.63"; * auto records = csvReader(str, ["a"]); * * assert(records.header == ["a","b","c"]); * ------- */ string[] header; /** * Constructor to initialize the input, delimiter and quote for input * without a header. * * ------- * string str = `76;^26^;22`; * int[] ans = [76,26,22]; * auto records = CsvReader!(int,Malformed.ignore,string,char,string[]) * (str, ';', '^'); * * foreach(record; records) { * assert(equal(record, ans)); * } * ------- */ this(Range input, Separator delimiter, Separator quote) { _input = new Input!(Range, ErrorLevel)(input); _separator = delimiter; _quote = quote; prime(); } /** * Constructor to initialize the input, delimiter and quote for input * with a header. * * ------- * string str = `high;mean;low\n76;^26^;22`; * auto records = CsvReader!(int,Malformed.ignore,string,char,string[]) * (str, ["high","low"], ';', '^'); * * int[] ans = [76,22]; * foreach(record; records) { * assert(equal(record, ans)); * } * ------- * * Throws: * $(LREF HeaderMismatchException) when a header is provided but a * matching column is not found or the order did not match that found * in the input (non-struct). */ this(Range input, Header colHeaders, Separator delimiter, Separator quote) { _input = new Input!(Range, ErrorLevel)(input); _separator = delimiter; _quote = quote; size_t[string] colToIndex; foreach(h; colHeaders) { colToIndex[h] = size_t.max; } auto r = CsvRecord!(string, ErrorLevel, Range, Separator) (_input, _separator, _quote, indices); size_t colIndex; foreach(col; r) { header ~= col; auto ptr = col in colToIndex; if (ptr) *ptr = colIndex; colIndex++; } // The above loop empties the header row. recordRange._empty = true; indices.length = colToIndex.length; int i; foreach(h; colHeaders) { immutable index = colToIndex[h]; static if (ErrorLevel != Malformed.ignore) if (index == size_t.max) throw new HeaderMismatchException ("Header not found: " ~ to!string(h)); indices[i++] = index; } static if (!is(Contents == struct) && !is(Contents == class)) { static if (is(Contents T : T[U], U : string)) { import std.algorithm : sort; sort(indices); } else static if (ErrorLevel == Malformed.ignore) { import std.algorithm : sort; sort(indices); } else { import std.algorithm : isSorted, findAdjacent; if (!isSorted(indices)) { auto ex = new HeaderMismatchException ("Header in input does not match specified header."); findAdjacent!"a > b"(indices); ex.row = 1; ex.col = indices.front; throw ex; } } } popFront(); } /** * Part of an input range as defined by * $(XREF_PACK range,primitives,isInputRange). * * Returns: * If $(D Contents) is a struct, will be filled with record data. * * If $(D Contents) is a class, will be filled with record data. * * If $(D Contents) is a associative array, will be filled * with record data. * * If $(D Contents) is non-struct, a $(LREF CsvRecord) will be * returned. */ @property auto front() { assert(!empty); static if (is(Contents == struct) || is(Contents == class)) { return recordContent; } else static if (is(Contents T : T[U], U : string)) { return recordContent; } else { return recordRange; } } /** * Part of an input range as defined by * $(XREF_PACK range,primitives,isInputRange). */ @property bool empty() @safe @nogc pure nothrow const { return _empty; } /** * Part of an input range as defined by * $(XREF_PACK range,primitives,isInputRange). * * Throws: * $(LREF CSVException) When a quote is found in an unquoted field, * data continues after a closing quote, the quoted field was not * closed before data was empty, a conversion failed, or when the * row's length does not match the previous length. */ void popFront() { while(!recordRange.empty) { recordRange.popFront(); } static if (ErrorLevel == Malformed.throwException) if (_input.rowLength == 0) _input.rowLength = _input.col; _input.col = 0; if (!_input.range.empty) { if (_input.range.front == '\r') { _input.range.popFront(); if (!_input.range.empty && _input.range.front == '\n') _input.range.popFront(); } else if (_input.range.front == '\n') _input.range.popFront(); } if (_input.range.empty) { _empty = true; return; } prime(); } private void prime() { if (_empty) return; _input.row++; static if (is(Contents == struct) || is(Contents == class)) { recordRange = typeof(recordRange) (_input, _separator, _quote, null); } else { recordRange = typeof(recordRange) (_input, _separator, _quote, indices); } static if (is(Contents T : T[U], U : string)) { T[U] aa; try { for(; !recordRange.empty; recordRange.popFront()) { aa[header[_input.col-1]] = recordRange.front; } } catch(ConvException e) { throw new CSVException(e.msg, _input.row, _input.col, e); } recordContent = aa; } else static if (is(Contents == struct) || is(Contents == class)) { static if (is(Contents == class)) recordContent = new typeof(recordContent)(); else recordContent = typeof(recordContent).init; size_t colIndex; try { for(; !recordRange.empty;) { auto colData = recordRange.front; scope(exit) colIndex++; if (indices.length > 0) { foreach(ti, ToType; Fields!(Contents)) { if (indices[ti] == colIndex) { static if (!isSomeString!ToType) skipWS(colData); recordContent.tupleof[ti] = to!ToType(colData); } } } else { foreach(ti, ToType; Fields!(Contents)) { if (ti == colIndex) { static if (!isSomeString!ToType) skipWS(colData); recordContent.tupleof[ti] = to!ToType(colData); } } } recordRange.popFront(); } } catch(ConvException e) { throw new CSVException(e.msg, _input.row, colIndex, e); } } } } /// @safe pure unittest { import std.algorithm; string str = `76;^26^;22`; int[] ans = [76,26,22]; auto records = CsvReader!(int,Malformed.ignore,string,char,string[]) (str, ';', '^'); foreach(record; records) { assert(equal(record, ans)); } } // Bugzilla 15545 pure unittest { enum failData = "name, surname, age Joe, Joker, 99\r"; bool pass = true; auto r = csvReader(failData); try foreach(entry; r){} catch pass = false; assert(pass); } /* * This input range is accessible through $(LREF CsvReader) when the * requested $(D Contents) type is neither a structure or an associative array. */ private struct CsvRecord(Contents, Malformed ErrorLevel, Range, Separator) if (!is(Contents == class) && !is(Contents == struct)) { import std.array : appender; private: Input!(Range, ErrorLevel)* _input; Separator _separator; Separator _quote; Contents curContentsoken; typeof(appender!(dchar[])()) _front; bool _empty; size_t[] _popCount; public: /* * params: * input = Pointer to a character input range * delimiter = Separator for each column * quote = Character used for quotation * indices = An array containing which columns will be returned. * If empty, all columns are returned. List must be in order. */ this(Input!(Range, ErrorLevel)* input, Separator delimiter, Separator quote, size_t[] indices) { _input = input; _separator = delimiter; _quote = quote; _front = appender!(dchar[])(); _popCount = indices.dup; // If a header was given, each call to popFront will need // to eliminate so many tokens. This calculates // how many will be skipped to get to the next header column size_t normalizer; foreach(ref c; _popCount) { static if (ErrorLevel == Malformed.ignore) { // If we are not throwing exceptions // a header may not exist, indices are sorted // and will be size_t.max if not found. if (c == size_t.max) break; } c -= normalizer; normalizer += c + 1; } prime(); } /** * Part of an input range as defined by * $(XREF_PACK range,primitives,isInputRange). */ @property Contents front() @safe pure { assert(!empty); return curContentsoken; } /** * Part of an input range as defined by * $(XREF_PACK range,primitives,isInputRange). */ @property bool empty() @safe pure nothrow @nogc const { return _empty; } /* * CsvRecord is complete when input * is empty or starts with record break */ private bool recordEnd() { if (_input.range.empty || _input.range.front == '\n' || _input.range.front == '\r') { return true; } return false; } /** * Part of an input range as defined by * $(XREF_PACK range,primitives,isInputRange). * * Throws: * $(LREF CSVException) When a quote is found in an unquoted field, * data continues after a closing quote, the quoted field was not * closed before data was empty, a conversion failed, or when the * row's length does not match the previous length. */ void popFront() { static if (ErrorLevel == Malformed.throwException) import std.format : format; // Skip last of record when header is depleted. if (_popCount.ptr && _popCount.empty) while(!recordEnd()) { prime(1); } if (recordEnd()) { _empty = true; static if (ErrorLevel == Malformed.throwException) if (_input.rowLength != 0) if (_input.col != _input.rowLength) throw new CSVException( format("Row %s's length %s does not match "~ "previous length of %s.", _input.row, _input.col, _input.rowLength)); return; } else { static if (ErrorLevel == Malformed.throwException) if (_input.rowLength != 0) if (_input.col > _input.rowLength) throw new CSVException( format("Row %s's length %s does not match "~ "previous length of %s.", _input.row, _input.col, _input.rowLength)); } // Separator is left on the end of input from the last call. // This cannot be moved to after the call to csvNextToken as // there may be an empty record after it. if (_input.range.front == _separator) _input.range.popFront(); _front.shrinkTo(0); prime(); } /* * Handles moving to the next skipNum token. */ private void prime(size_t skipNum) { foreach(i; 0..skipNum) { _input.col++; _front.shrinkTo(0); if (_input.range.front == _separator) _input.range.popFront(); try csvNextToken!(Range, ErrorLevel, Separator) (_input.range, _front, _separator, _quote,false); catch(IncompleteCellException ice) { ice.row = _input.row; ice.col = _input.col; ice.partialData = _front.data.idup; throw ice; } catch(ConvException e) { throw new CSVException(e.msg, _input.row, _input.col, e); } } } private void prime() { try { _input.col++; csvNextToken!(Range, ErrorLevel, Separator) (_input.range, _front, _separator, _quote,false); } catch(IncompleteCellException ice) { ice.row = _input.row; ice.col = _input.col; ice.partialData = _front.data.idup; throw ice; } auto skipNum = _popCount.empty ? 0 : _popCount.front; if (!_popCount.empty) _popCount.popFront(); if (skipNum == size_t.max) { while(!recordEnd()) prime(1); _empty = true; return; } if (skipNum) prime(skipNum); auto data = _front.data; static if (!isSomeString!Contents) skipWS(data); try curContentsoken = to!Contents(data); catch(ConvException e) { throw new CSVException(e.msg, _input.row, _input.col, e); } } } /** * Lower level control over parsing CSV * * This function consumes the input. After each call the input will * start with either a delimiter or record break (\n, \r\n, \r) which * must be removed for subsequent calls. * * params: * input = Any CSV input * ans = The first field in the input * sep = The character to represent a comma in the specification * quote = The character to represent a quote in the specification * startQuoted = Whether the input should be considered to already be in * quotes * * Throws: * $(LREF IncompleteCellException) When a quote is found in an unquoted * field, data continues after a closing quote, or the quoted field was * not closed before data was empty. */ void csvNextToken(Range, Malformed ErrorLevel = Malformed.throwException, Separator, Output) (ref Range input, ref Output ans, Separator sep, Separator quote, bool startQuoted = false) if (isSomeChar!Separator && isInputRange!Range && is(Unqual!(ElementType!Range) == dchar) && isOutputRange!(Output, dchar)) { bool quoted = startQuoted; bool escQuote; if (input.empty) return; if (input.front == '\n') return; if (input.front == '\r') return; if (input.front == quote) { quoted = true; input.popFront(); } while(!input.empty) { assert(!(quoted && escQuote)); if (!quoted) { // When not quoted the token ends at sep if (input.front == sep) break; if (input.front == '\r') break; if (input.front == '\n') break; } if (!quoted && !escQuote) { if (input.front == quote) { // Not quoted, but quote found static if (ErrorLevel == Malformed.throwException) throw new IncompleteCellException( "Quote located in unquoted token"); else static if (ErrorLevel == Malformed.ignore) ans.put(quote); } else { // Not quoted, non-quote character ans.put(input.front); } } else { if (input.front == quote) { // Quoted, quote found // By turning off quoted and turning on escQuote // I can tell when to add a quote to the string // escQuote is turned to false when it escapes a // quote or is followed by a non-quote (see outside else). // They are mutually exclusive, but provide different // information. if (escQuote) { escQuote = false; quoted = true; ans.put(quote); } else { escQuote = true; quoted = false; } } else { // Quoted, non-quote character if (escQuote) { static if (ErrorLevel == Malformed.throwException) throw new IncompleteCellException( "Content continues after end quote, " ~ "or needs to be escaped."); else static if (ErrorLevel == Malformed.ignore) break; } ans.put(input.front); } } input.popFront(); } static if (ErrorLevel == Malformed.throwException) if (quoted && (input.empty || input.front == '\n' || input.front == '\r')) throw new IncompleteCellException( "Data continues on future lines or trailing quote"); } /// unittest { import std.array : appender; string str = "65,63\n123,3673"; auto a = appender!(char[])(); csvNextToken(str,a,',','"'); assert(a.data == "65"); assert(str == ",63\n123,3673"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "63"); assert(str == "\n123,3673"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "123"); assert(str == ",3673"); } // Test csvNextToken on simplest form and correct format. @safe pure unittest { import std.array; string str = "\U00010143Hello,65,63.63\nWorld,123,3673.562"; auto a = appender!(dchar[])(); csvNextToken!string(str,a,',','"'); assert(a.data == "\U00010143Hello"); assert(str == ",65,63.63\nWorld,123,3673.562"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "65"); assert(str == ",63.63\nWorld,123,3673.562"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "63.63"); assert(str == "\nWorld,123,3673.562"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "World"); assert(str == ",123,3673.562"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "123"); assert(str == ",3673.562"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "3673.562"); assert(str == ""); } // Test quoted tokens @safe pure unittest { import std.array; string str = `one,two,"three ""quoted""","",` ~ "\"five\nnew line\"\nsix"; auto a = appender!(dchar[])(); csvNextToken!string(str,a,',','"'); assert(a.data == "one"); assert(str == `,two,"three ""quoted""","",` ~ "\"five\nnew line\"\nsix"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "two"); assert(str == `,"three ""quoted""","",` ~ "\"five\nnew line\"\nsix"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "three \"quoted\""); assert(str == `,"",` ~ "\"five\nnew line\"\nsix"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == ""); assert(str == ",\"five\nnew line\"\nsix"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "five\nnew line"); assert(str == "\nsix"); str.popFront(); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == "six"); assert(str == ""); } // Test empty data is pulled at end of record. @safe pure unittest { import std.array; string str = "one,"; auto a = appender!(dchar[])(); csvNextToken(str,a,',','"'); assert(a.data == "one"); assert(str == ","); a.shrinkTo(0); csvNextToken(str,a,',','"'); assert(a.data == ""); } // Test exceptions @safe pure unittest { import std.array; string str = "\"one\nnew line"; typeof(appender!(dchar[])()) a; try { a = appender!(dchar[])(); csvNextToken(str,a,',','"'); assert(0); } catch (IncompleteCellException ice) { assert(a.data == "one\nnew line"); assert(str == ""); } str = "Hello world\""; try { a = appender!(dchar[])(); csvNextToken(str,a,',','"'); assert(0); } catch (IncompleteCellException ice) { assert(a.data == "Hello world"); assert(str == "\""); } str = "one, two \"quoted\" end"; a = appender!(dchar[])(); csvNextToken!(string,Malformed.ignore)(str,a,',','"'); assert(a.data == "one"); str.popFront(); a.shrinkTo(0); csvNextToken!(string,Malformed.ignore)(str,a,',','"'); assert(a.data == " two \"quoted\" end"); } // Test modifying token delimiter @safe pure unittest { import std.array; string str = `one|two|/three "quoted"/|//`; auto a = appender!(dchar[])(); csvNextToken(str,a, '|','/'); assert(a.data == "one"d); assert(str == `|two|/three "quoted"/|//`); str.popFront(); a.shrinkTo(0); csvNextToken(str,a, '|','/'); assert(a.data == "two"d); assert(str == `|/three "quoted"/|//`); str.popFront(); a.shrinkTo(0); csvNextToken(str,a, '|','/'); assert(a.data == `three "quoted"`); assert(str == `|//`); str.popFront(); a.shrinkTo(0); csvNextToken(str,a, '|','/'); assert(a.data == ""d); } // Bugzilla 8908 @safe pure unittest { string csv = ` 1.0, 2.0, 3.0 4.0, 5.0, 6.0`; static struct Data { real a, b, c; } size_t i = 0; foreach (data; csvReader!Data(csv)) with (data) { int[] row = [cast(int)a, cast(int)b, cast(int)c]; if (i == 0) assert(row == [1, 2, 3]); else assert(row == [4, 5, 6]); ++i; } i = 0; foreach (data; csvReader!real(csv)) { auto a = data.front; data.popFront(); auto b = data.front; data.popFront(); auto c = data.front; int[] row = [cast(int)a, cast(int)b, cast(int)c]; if (i == 0) assert(row == [1, 2, 3]); else assert(row == [4, 5, 6]); ++i; } } ldc-1.1.0-beta3-src/runtime/phobos/std/array.d0000664000175000017500000031327012776215007017177 0ustar kaikai// Written in the D programming language. /** Functions and types that manipulate built-in arrays and associative arrays. This module provides all kinds of functions to create, manipulate or convert arrays: $(BOOKTABLE , $(TR $(TH Function Name) $(TH Description) ) $(TR $(TD $(D $(LREF _array))) $(TD Returns a copy of the input in a newly allocated dynamic _array. )) $(TR $(TD $(D $(LREF appender))) $(TD Returns a new Appender initialized with a given _array. )) $(TR $(TD $(D $(LREF assocArray))) $(TD Returns a newly allocated associative _array from a range of key/value tuples. )) $(TR $(TD $(D $(LREF byPair))) $(TD Construct a range iterating over an associative _array by key/value tuples. )) $(TR $(TD $(D $(LREF insertInPlace))) $(TD Inserts into an existing _array at a given position. )) $(TR $(TD $(D $(LREF join))) $(TD Concatenates a range of ranges into one _array. )) $(TR $(TD $(D $(LREF minimallyInitializedArray))) $(TD Returns a new _array of type $(D T). )) $(TR $(TD $(D $(LREF replace))) $(TD Returns a new _array with all occurrences of a certain subrange replaced. )) $(TR $(TD $(D $(LREF replaceFirst))) $(TD Returns a new _array with the first occurrence of a certain subrange replaced. )) $(TR $(TD $(D $(LREF replaceInPlace))) $(TD Replaces all occurrences of a certain subrange and puts the result into a given _array. )) $(TR $(TD $(D $(LREF replaceInto))) $(TD Replaces all occurrences of a certain subrange and puts the result into an output range. )) $(TR $(TD $(D $(LREF replaceLast))) $(TD Returns a new _array with the last occurrence of a certain subrange replaced. )) $(TR $(TD $(D $(LREF replaceSlice))) $(TD Returns a new _array with a given slice replaced. )) $(TR $(TD $(D $(LREF replicate))) $(TD Creates a new _array out of several copies of an input _array or range. )) $(TR $(TD $(D $(LREF sameHead))) $(TD Checks if the initial segments of two arrays refer to the same place in memory. )) $(TR $(TD $(D $(LREF sameTail))) $(TD Checks if the final segments of two arrays refer to the same place in memory. )) $(TR $(TD $(D $(LREF split))) $(TD Eagerly split a range or string into an _array. )) $(TR $(TD $(D $(LREF uninitializedArray))) $(TD Returns a new _array of type $(D T) without initializing its elements. )) ) Copyright: Copyright Andrei Alexandrescu 2008- and Jonathan M Davis 2011-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.org, Andrei Alexandrescu) and Jonathan M Davis Source: $(PHOBOSSRC std/_array.d) */ module std.array; import std.meta; import std.traits; import std.functional; static import std.algorithm; // FIXME, remove with alias of splitter import std.range.primitives; public import std.range.primitives : save, empty, popFront, popBack, front, back; /** * Allocates an array and initializes it with copies of the elements * of range $(D r). * * Narrow strings are handled as a special case in an overload. * * Params: * r = range (or aggregate with $(D opApply) function) whose elements are copied into the allocated array * Returns: * allocated and initialized array */ ForeachType!Range[] array(Range)(Range r) if (isIterable!Range && !isNarrowString!Range && !isInfinite!Range) { if (__ctfe) { // Compile-time version to avoid memcpy calls. // Also used to infer attributes of array(). typeof(return) result; foreach (e; r) result ~= e; return result; } alias E = ForeachType!Range; static if (hasLength!Range) { auto length = r.length; if (length == 0) return null; import std.conv : emplaceRef; auto result = (() @trusted => uninitializedArray!(Unqual!E[])(length))(); // Every element of the uninitialized array must be initialized size_t i; foreach (e; r) { emplaceRef!E(result[i], e); ++i; } return (() @trusted => cast(E[])result)(); } else { auto a = appender!(E[])(); foreach (e; r) { a.put(e); } return a.data; } } /// @safe pure nothrow unittest { auto a = array([1, 2, 3, 4, 5][]); assert(a == [ 1, 2, 3, 4, 5 ]); } @safe pure nothrow unittest { import std.algorithm : equal; struct Foo { int a; } auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]); assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)])); } @system unittest { import std.algorithm : equal; struct Foo { int a; auto opAssign(Foo foo) { assert(0); } auto opEquals(Foo foo) { return a == foo.a; } } auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]); assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)])); } unittest { // Issue 12315 static struct Bug12315 { immutable int i; } enum bug12315 = [Bug12315(123456789)].array(); static assert(bug12315[0].i == 123456789); } unittest { import std.range; static struct S{int* p;} auto a = array(immutable(S).init.repeat(5)); } /** Convert a narrow string to an array type that fully supports random access. This is handled as a special case and always returns a $(D dchar[]), $(D const(dchar)[]), or $(D immutable(dchar)[]) depending on the constness of the input. */ ElementType!String[] array(String)(String str) if (isNarrowString!String) { import std.utf : toUTF32; return cast(typeof(return)) str.toUTF32; } unittest { import std.conv : to; static struct TestArray { int x; string toString() { return to!string(x); } } static struct OpAssign { uint num; this(uint num) { this.num = num; } // Templating opAssign to make sure the bugs with opAssign being // templated are fixed. void opAssign(T)(T rhs) { this.num = rhs.num; } } static struct OpApply { int opApply(int delegate(ref int) dg) { int res; foreach(i; 0..10) { res = dg(i); if(res) break; } return res; } } auto a = array([1, 2, 3, 4, 5][]); //writeln(a); assert(a == [ 1, 2, 3, 4, 5 ]); auto b = array([TestArray(1), TestArray(2)][]); //writeln(b); class C { int x; this(int y) { x = y; } override string toString() const { return to!string(x); } } auto c = array([new C(1), new C(2)][]); //writeln(c); auto d = array([1.0, 2.2, 3][]); assert(is(typeof(d) == double[])); //writeln(d); auto e = [OpAssign(1), OpAssign(2)]; auto f = array(e); assert(e == f); assert(array(OpApply.init) == [0,1,2,3,4,5,6,7,8,9]); assert(array("ABC") == "ABC"d); assert(array("ABC".dup) == "ABC"d.dup); } //Bug# 8233 unittest { assert(array("hello world"d) == "hello world"d); immutable a = [1, 2, 3, 4, 5]; assert(array(a) == a); const b = a; assert(array(b) == a); //To verify that the opAssign branch doesn't get screwed up by using Unqual. //EDIT: array no longer calls opAssign. struct S { ref S opAssign(S)(const ref S rhs) { assert(0); } int i; } foreach(T; AliasSeq!(S, const S, immutable S)) { auto arr = [T(1), T(2), T(3), T(4)]; assert(array(arr) == arr); } } unittest { //9824 static struct S { @disable void opAssign(S); int i; } auto arr = [S(0), S(1), S(2)]; arr.array(); } // Bugzilla 10220 unittest { import std.exception; import std.algorithm : equal; import std.range : repeat; static struct S { int val; @disable this(); this(int v) { val = v; } } assertCTFEable!( { auto r = S(1).repeat(2).array(); assert(equal(r, [S(1), S(1)])); }); } unittest { //Turn down infinity: static assert(!is(typeof( repeat(1).array() ))); } /** Returns a newly allocated associative _array from a range of key/value tuples. Params: r = An input range of tuples of keys and values. Returns: A newly allocated associative array out of elements of the input range, which must be a range of tuples (Key, Value). Returns a null associative array reference when given an empty range. Duplicates: Associative arrays have unique keys. If r contains duplicate keys, then the result will contain the value of the last pair for that key in r. See_Also: $(XREF typecons, Tuple) */ auto assocArray(Range)(Range r) if (isInputRange!Range) { import std.typecons : isTuple; alias E = ElementType!Range; static assert(isTuple!E, "assocArray: argument must be a range of tuples"); static assert(E.length == 2, "assocArray: tuple dimension must be 2"); alias KeyType = E.Types[0]; alias ValueType = E.Types[1]; static assert(isMutable!ValueType, "assocArray: value type must be mutable"); ValueType[KeyType] aa; foreach (t; r) aa[t[0]] = t[1]; return aa; } /// /*@safe*/ pure /*nothrow*/ unittest { import std.range; import std.typecons; auto a = assocArray(zip([0, 1, 2], ["a", "b", "c"])); assert(is(typeof(a) == string[int])); assert(a == [0:"a", 1:"b", 2:"c"]); auto b = assocArray([ tuple("foo", "bar"), tuple("baz", "quux") ]); assert(is(typeof(b) == string[string])); assert(b == ["foo":"bar", "baz":"quux"]); } // @@@11053@@@ - Cannot be version(unittest) - recursive instantiation error unittest { import std.typecons; static assert(!__traits(compiles, [ tuple("foo", "bar", "baz") ].assocArray())); static assert(!__traits(compiles, [ tuple("foo") ].assocArray())); assert([ tuple("foo", "bar") ].assocArray() == ["foo": "bar"]); } // Issue 13909 unittest { import std.typecons; auto a = [tuple!(const string, string)("foo", "bar")]; auto b = [tuple!(string, const string)("foo", "bar")]; assert(assocArray(a) == [cast(const(string)) "foo": "bar"]); static assert(!__traits(compiles, assocArray(b))); } /** Construct a range iterating over an associative array by key/value tuples. Params: aa = The associative array to iterate over. Returns: A forward range of Tuple's of key and value pairs from the given associative array. */ auto byPair(Key, Value)(Value[Key] aa) { import std.typecons : tuple; import std.algorithm : map; return aa.byKeyValue.map!(pair => tuple(pair.key, pair.value)); } /// unittest { import std.typecons : tuple, Tuple; import std.algorithm : sort; auto aa = ["a": 1, "b": 2, "c": 3]; Tuple!(string, int)[] pairs; // Iteration over key/value pairs. foreach (pair; aa.byPair) { pairs ~= pair; } // Iteration order is implementation-dependent, so we should sort it to get // a fixed order. sort(pairs); assert(pairs == [ tuple("a", 1), tuple("b", 2), tuple("c", 3) ]); } unittest { import std.typecons : tuple, Tuple; auto aa = ["a":2]; auto pairs = aa.byPair(); static assert(is(typeof(pairs.front) == Tuple!(string,int))); static assert(isForwardRange!(typeof(pairs))); assert(!pairs.empty); assert(pairs.front == tuple("a", 2)); auto savedPairs = pairs.save; pairs.popFront(); assert(pairs.empty); assert(!savedPairs.empty); assert(savedPairs.front == tuple("a", 2)); } private template blockAttribute(T) { import core.memory; static if (hasIndirections!(T) || is(T == void)) { enum blockAttribute = 0; } else { enum blockAttribute = GC.BlkAttr.NO_SCAN; } } version(unittest) { import core.memory : UGC = GC; static assert(!(blockAttribute!void & UGC.BlkAttr.NO_SCAN)); } // Returns the number of dimensions in an array T. private template nDimensions(T) { static if(isArray!T) { enum nDimensions = 1 + nDimensions!(typeof(T.init[0])); } else { enum nDimensions = 0; } } version(unittest) { static assert(nDimensions!(uint[]) == 1); static assert(nDimensions!(float[][]) == 2); } /++ Returns a new array of type $(D T) allocated on the garbage collected heap without initializing its elements. This can be a useful optimization if every element will be immediately initialized. $(D T) may be a multidimensional array. In this case sizes may be specified for any number of dimensions from 0 to the number in $(D T). uninitializedArray is nothrow and weakly pure. uninitializedArray is @system if the uninitialized element type has pointers. +/ auto uninitializedArray(T, I...)(I sizes) nothrow @system if (isDynamicArray!T && allSatisfy!(isIntegral, I) && hasIndirections!(ElementEncodingType!T)) { enum isSize_t(E) = is (E : size_t); alias toSize_t(E) = size_t; static assert(allSatisfy!(isSize_t, I), "Argument types in "~I.stringof~" are not all convertible to size_t: " ~Filter!(templateNot!(isSize_t), I).stringof); //Eagerlly transform non-size_t into size_t to avoid template bloat alias ST = staticMap!(toSize_t, I); return arrayAllocImpl!(false, T, ST)(sizes); } /// auto uninitializedArray(T, I...)(I sizes) nothrow @trusted if (isDynamicArray!T && allSatisfy!(isIntegral, I) && !hasIndirections!(ElementEncodingType!T)) { enum isSize_t(E) = is (E : size_t); alias toSize_t(E) = size_t; static assert(allSatisfy!(isSize_t, I), "Argument types in "~I.stringof~" are not all convertible to size_t: " ~Filter!(templateNot!(isSize_t), I).stringof); //Eagerlly transform non-size_t into size_t to avoid template bloat alias ST = staticMap!(toSize_t, I); return arrayAllocImpl!(false, T, ST)(sizes); } /// @system nothrow pure unittest { double[] arr = uninitializedArray!(double[])(100); assert(arr.length == 100); double[][] matrix = uninitializedArray!(double[][])(42, 31); assert(matrix.length == 42); assert(matrix[0].length == 31); char*[] ptrs = uninitializedArray!(char*[])(100); assert(ptrs.length == 100); } /++ Returns a new array of type $(D T) allocated on the garbage collected heap. Partial initialization is done for types with indirections, for preservation of memory safety. Note that elements will only be initialized to 0, but not necessarily the element type's $(D .init). minimallyInitializedArray is nothrow and weakly pure. +/ auto minimallyInitializedArray(T, I...)(I sizes) nothrow @trusted if (isDynamicArray!T && allSatisfy!(isIntegral, I)) { enum isSize_t(E) = is (E : size_t); alias toSize_t(E) = size_t; static assert(allSatisfy!(isSize_t, I), "Argument types in "~I.stringof~" are not all convertible to size_t: " ~Filter!(templateNot!(isSize_t), I).stringof); //Eagerlly transform non-size_t into size_t to avoid template bloat alias ST = staticMap!(toSize_t, I); return arrayAllocImpl!(true, T, ST)(sizes); } @safe pure nothrow unittest { cast(void)minimallyInitializedArray!(int[][][][][])(); double[] arr = minimallyInitializedArray!(double[])(100); assert(arr.length == 100); double[][] matrix = minimallyInitializedArray!(double[][])(42); assert(matrix.length == 42); foreach(elem; matrix) { assert(elem.ptr is null); } } private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow { static assert(I.length <= nDimensions!T, I.length.stringof~"dimensions specified for a "~nDimensions!T.stringof~" dimensional array."); alias E = ElementEncodingType!T; E[] ret; static if (I.length != 0) { static assert (is(I[0] == size_t)); alias size = sizes[0]; } static if (I.length == 1) { if (__ctfe) { static if (__traits(compiles, new E[](size))) ret = new E[](size); else static if (__traits(compiles, ret ~= E.init)) { try { //Issue: if E has an impure postblit, then all of arrayAllocImpl //Will be impure, even during non CTFE. foreach (i; 0 .. size) ret ~= E.init; } catch (Exception e) throw new Error(e.msg); } else assert(0, "No postblit nor default init on " ~ E.stringof ~ ": At least one is required for CTFE."); } else { import core.stdc.string : memset; import core.memory; auto ptr = cast(E*) GC.malloc(sizes[0] * E.sizeof, blockAttribute!E); static if (minimallyInitialized && hasIndirections!E) memset(ptr, 0, size * E.sizeof); ret = ptr[0 .. size]; } } else static if (I.length > 1) { ret = arrayAllocImpl!(false, E[])(size); foreach(ref elem; ret) elem = arrayAllocImpl!(minimallyInitialized, E)(sizes[1..$]); } return ret; } nothrow pure unittest { auto s1 = uninitializedArray!(int[])(); auto s2 = minimallyInitializedArray!(int[])(); assert(s1.length == 0); assert(s2.length == 0); } nothrow pure unittest //@@@9803@@@ { auto a = minimallyInitializedArray!(int*[])(1); assert(a[0] == null); auto b = minimallyInitializedArray!(int[][])(1); assert(b[0].empty); auto c = minimallyInitializedArray!(int*[][])(1, 1); assert(c[0][0] == null); } unittest //@@@10637@@@ { static struct S { static struct I{int i; alias i this;} int* p; this() @disable; this(int i) { p = &(new I(i)).i; } this(this) { p = &(new I(*p)).i; } ~this() { assert(p != null); } } auto a = minimallyInitializedArray!(S[])(1); assert(a[0].p == null); enum b = minimallyInitializedArray!(S[])(1); } nothrow unittest { static struct S1 { this() @disable; this(this) @disable; } auto a1 = minimallyInitializedArray!(S1[][])(2, 2); //enum b1 = minimallyInitializedArray!(S1[][])(2, 2); static struct S2 { this() @disable; //this(this) @disable; } auto a2 = minimallyInitializedArray!(S2[][])(2, 2); enum b2 = minimallyInitializedArray!(S2[][])(2, 2); static struct S3 { //this() @disable; this(this) @disable; } auto a3 = minimallyInitializedArray!(S3[][])(2, 2); enum b3 = minimallyInitializedArray!(S3[][])(2, 2); } // overlap /* NOTE: Undocumented for now, overlap does not yet work with ctfe. Returns the overlapping portion, if any, of two arrays. Unlike $(D equal), $(D overlap) only compares the pointers in the ranges, not the values referred by them. If $(D r1) and $(D r2) have an overlapping slice, returns that slice. Otherwise, returns the null slice. */ inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) @trusted pure nothrow { alias U = inout(T); static U* max(U* a, U* b) nothrow { return a > b ? a : b; } static U* min(U* a, U* b) nothrow { return a < b ? a : b; } auto b = max(r1.ptr, r2.ptr); auto e = min(r1.ptr + r1.length, r2.ptr + r2.length); return b < e ? b[0 .. e - b] : null; } /// @safe pure /*nothrow*/ unittest { int[] a = [ 10, 11, 12, 13, 14 ]; int[] b = a[1 .. 3]; assert(overlap(a, b) == [ 11, 12 ]); b = b.dup; // overlap disappears even though the content is the same assert(overlap(a, b).empty); } /*@safe nothrow*/ unittest { static void test(L, R)(L l, R r) { import std.stdio; scope(failure) writeln("Types: L %s R %s", L.stringof, R.stringof); assert(overlap(l, r) == [ 100, 12 ]); assert(overlap(l, l[0 .. 2]) is l[0 .. 2]); assert(overlap(l, l[3 .. 5]) is l[3 .. 5]); assert(overlap(l[0 .. 2], l) is l[0 .. 2]); assert(overlap(l[3 .. 5], l) is l[3 .. 5]); } int[] a = [ 10, 11, 12, 13, 14 ]; int[] b = a[1 .. 3]; a[1] = 100; immutable int[] c = a.idup; immutable int[] d = c[1 .. 3]; test(a, b); assert(overlap(a, b.dup).empty); test(c, d); assert(overlap(c, d.idup).empty); } @safe pure nothrow unittest // bugzilla 9836 { // range primitives for array should work with alias this types struct Wrapper { int[] data; alias data this; @property Wrapper save() { return this; } } auto w = Wrapper([1,2,3,4]); std.array.popFront(w); // should work static assert(isInputRange!Wrapper); static assert(isForwardRange!Wrapper); static assert(isBidirectionalRange!Wrapper); static assert(isRandomAccessRange!Wrapper); } private void copyBackwards(T)(T[] src, T[] dest) { import core.stdc.string; assert(src.length == dest.length); if (!__ctfe || hasElaborateCopyConstructor!T) { /* insertInPlace relies on dest being uninitialized, so no postblits allowed, * as this is a MOVE that overwrites the destination, not a COPY. * BUG: insertInPlace will not work with ctfe and postblits */ memmove(dest.ptr, src.ptr, src.length * T.sizeof); } else { immutable len = src.length; for (size_t i = len; i-- > 0;) { dest[i] = src[i]; } } } /++ Inserts $(D stuff) (which must be an input range or any number of implicitly convertible items) in $(D array) at position $(D pos). +/ void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff) if(!isSomeString!(T[]) && allSatisfy!(isInputRangeOrConvertible!T, U) && U.length > 0) { static if(allSatisfy!(isInputRangeWithLengthOrConvertible!T, U)) { import std.conv : emplaceRef; immutable oldLen = array.length; size_t to_insert = 0; foreach (i, E; U) { static if (is(E : T)) //a single convertible value, not a range to_insert += 1; else to_insert += stuff[i].length; } if (to_insert) { array.length += to_insert; // Takes arguments array, pos, stuff // Spread apart array[] at pos by moving elements (() @trusted { copyBackwards(array[pos..oldLen], array[pos+to_insert..$]); })(); // Initialize array[pos .. pos+to_insert] with stuff[] auto j = 0; foreach (i, E; U) { static if (is(E : T)) { emplaceRef!T(array[pos + j++], stuff[i]); } else { foreach (v; stuff[i]) { emplaceRef!T(array[pos + j++], v); } } } } } else { // stuff has some InputRanges in it that don't have length // assume that stuff to be inserted is typically shorter // then the array that can be arbitrary big // TODO: needs a better implementation as there is no need to build an _array_ // a singly-linked list of memory blocks (rope, etc.) will do auto app = appender!(T[])(); foreach (i, E; U) app.put(stuff[i]); insertInPlace(array, pos, app.data); } } /// Ditto void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff) if(isSomeString!(T[]) && allSatisfy!(isCharOrStringOrDcharRange, U)) { static if(is(Unqual!T == T) && allSatisfy!(isInputRangeWithLengthOrConvertible!dchar, U)) { import std.utf : codeLength; // mutable, can do in place //helper function: re-encode dchar to Ts and store at *ptr static T* putDChar(T* ptr, dchar ch) { static if(is(T == dchar)) { *ptr++ = ch; return ptr; } else { import std.utf : encode; T[dchar.sizeof/T.sizeof] buf; size_t len = encode(buf, ch); final switch(len) { static if(T.sizeof == char.sizeof) { case 4: ptr[3] = buf[3]; goto case; case 3: ptr[2] = buf[2]; goto case; } case 2: ptr[1] = buf[1]; goto case; case 1: ptr[0] = buf[0]; } ptr += len; return ptr; } } immutable oldLen = array.length; size_t to_insert = 0; //count up the number of *codeunits* to insert foreach (i, E; U) to_insert += codeLength!T(stuff[i]); array.length += to_insert; @trusted static void moveToRight(T[] arr, size_t gap) { static assert(!hasElaborateCopyConstructor!T); import core.stdc.string; if (__ctfe) { for (size_t i = arr.length - gap; i; --i) arr[gap + i - 1] = arr[i - 1]; } else memmove(arr.ptr + gap, arr.ptr, (arr.length - gap) * T.sizeof); } moveToRight(array[pos .. $], to_insert); auto ptr = array.ptr + pos; foreach (i, E; U) { static if(is(E : dchar)) { ptr = putDChar(ptr, stuff[i]); } else { foreach (dchar ch; stuff[i]) ptr = putDChar(ptr, ch); } } assert(ptr == array.ptr + pos + to_insert, "(ptr == array.ptr + pos + to_insert) is false"); } else { // immutable/const, just construct a new array auto app = appender!(T[])(); app.put(array[0..pos]); foreach (i, E; U) app.put(stuff[i]); app.put(array[pos..$]); array = app.data; } } /// @safe pure unittest { int[] a = [ 1, 2, 3, 4 ]; a.insertInPlace(2, [ 1, 2 ]); assert(a == [ 1, 2, 1, 2, 3, 4 ]); a.insertInPlace(3, 10u, 11); assert(a == [ 1, 2, 1, 10, 11, 2, 3, 4]); } //constraint helpers private template isInputRangeWithLengthOrConvertible(E) { template isInputRangeWithLengthOrConvertible(R) { //hasLength not defined for char[], wchar[] and dchar[] enum isInputRangeWithLengthOrConvertible = (isInputRange!R && is(typeof(R.init.length)) && is(ElementType!R : E)) || is(R : E); } } //ditto private template isCharOrStringOrDcharRange(T) { enum isCharOrStringOrDcharRange = isSomeString!T || isSomeChar!T || (isInputRange!T && is(ElementType!T : dchar)); } //ditto private template isInputRangeOrConvertible(E) { template isInputRangeOrConvertible(R) { enum isInputRangeOrConvertible = (isInputRange!R && is(ElementType!R : E)) || is(R : E); } } unittest { import core.exception; import std.conv : to; import std.exception; import std.algorithm; bool test(T, U, V)(T orig, size_t pos, U toInsert, V result, string file = __FILE__, size_t line = __LINE__) { { static if(is(T == typeof(T.init.dup))) auto a = orig.dup; else auto a = orig.idup; a.insertInPlace(pos, toInsert); if(!std.algorithm.equal(a, result)) return false; } static if(isInputRange!U) { orig.insertInPlace(pos, filter!"true"(toInsert)); return std.algorithm.equal(orig, result); } else return true; } assert(test([1, 2, 3, 4], 0, [6, 7], [6, 7, 1, 2, 3, 4])); assert(test([1, 2, 3, 4], 2, [8, 9], [1, 2, 8, 9, 3, 4])); assert(test([1, 2, 3, 4], 4, [10, 11], [1, 2, 3, 4, 10, 11])); assert(test([1, 2, 3, 4], 0, 22, [22, 1, 2, 3, 4])); assert(test([1, 2, 3, 4], 2, 23, [1, 2, 23, 3, 4])); assert(test([1, 2, 3, 4], 4, 24, [1, 2, 3, 4, 24])); auto testStr(T, U)(string file = __FILE__, size_t line = __LINE__) { auto l = to!T("hello"); auto r = to!U(" વિશ્વ"); enforce(test(l, 0, r, " વિશ્વhello"), new AssertError("testStr failure 1", file, line)); enforce(test(l, 3, r, "hel વિશ્વlo"), new AssertError("testStr failure 2", file, line)); enforce(test(l, l.length, r, "hello વિશ્વ"), new AssertError("testStr failure 3", file, line)); } foreach (T; AliasSeq!(char, wchar, dchar, immutable(char), immutable(wchar), immutable(dchar))) { foreach (U; AliasSeq!(char, wchar, dchar, immutable(char), immutable(wchar), immutable(dchar))) { testStr!(T[], U[])(); } } // variadic version bool testVar(T, U...)(T orig, size_t pos, U args) { static if(is(T == typeof(T.init.dup))) auto a = orig.dup; else auto a = orig.idup; auto result = args[$-1]; a.insertInPlace(pos, args[0..$-1]); if (!std.algorithm.equal(a, result)) return false; return true; } assert(testVar([1, 2, 3, 4], 0, 6, 7u, [6, 7, 1, 2, 3, 4])); assert(testVar([1L, 2, 3, 4], 2, 8, 9L, [1, 2, 8, 9, 3, 4])); assert(testVar([1L, 2, 3, 4], 4, 10L, 11, [1, 2, 3, 4, 10, 11])); assert(testVar([1L, 2, 3, 4], 4, [10, 11], 40L, 42L, [1, 2, 3, 4, 10, 11, 40, 42])); assert(testVar([1L, 2, 3, 4], 4, 10, 11, [40L, 42], [1, 2, 3, 4, 10, 11, 40, 42])); assert(testVar("t".idup, 1, 'e', 's', 't', "test")); assert(testVar("!!"w.idup, 1, "\u00e9ll\u00f4", 'x', "TTT"w, 'y', "!\u00e9ll\u00f4xTTTy!")); assert(testVar("flipflop"d.idup, 4, '_', "xyz"w, '\U00010143', '_', "abc"d, "__", "flip_xyz\U00010143_abc__flop")); } unittest { import std.algorithm : equal; // insertInPlace interop with postblit static struct Int { int* payload; this(int k) { payload = new int; *payload = k; } this(this) { int* np = new int; *np = *payload; payload = np; } ~this() { if (payload) *payload = 0; //'destroy' it } @property int getPayload(){ return *payload; } alias getPayload this; } Int[] arr = [Int(1), Int(4), Int(5)]; assert(arr[0] == 1); insertInPlace(arr, 1, Int(2), Int(3)); assert(equal(arr, [1, 2, 3, 4, 5])); //check it works with postblit version (none) // illustrates that insertInPlace() will not work with CTFE and postblit { static bool testctfe() { Int[] arr = [Int(1), Int(4), Int(5)]; assert(arr[0] == 1); insertInPlace(arr, 1, Int(2), Int(3)); return equal(arr, [1, 2, 3, 4, 5]); //check it works with postblit } enum E = testctfe(); } } @safe unittest { import std.exception; assertCTFEable!( { int[] a = [1, 2]; a.insertInPlace(2, 3); a.insertInPlace(0, -1, 0); return a == [-1, 0, 1, 2, 3]; }); } unittest // bugzilla 6874 { import core.memory; // allocate some space byte[] a; a.length = 1; // fill it a.length = a.capacity; // write beyond byte[] b = a[$ .. $]; b.insertInPlace(0, a); // make sure that reallocation has happened assert(GC.addrOf(&b[0]) == GC.addrOf(&b[$-1])); } /++ Returns whether the $(D front)s of $(D lhs) and $(D rhs) both refer to the same place in memory, making one of the arrays a slice of the other which starts at index $(D 0). +/ @safe pure nothrow bool sameHead(T)(in T[] lhs, in T[] rhs) { return lhs.ptr == rhs.ptr; } /// @safe pure nothrow unittest { auto a = [1, 2, 3, 4, 5]; auto b = a[0..2]; assert(a.sameHead(b)); } /++ Returns whether the $(D back)s of $(D lhs) and $(D rhs) both refer to the same place in memory, making one of the arrays a slice of the other which end at index $(D $). +/ @trusted pure nothrow bool sameTail(T)(in T[] lhs, in T[] rhs) { return lhs.ptr + lhs.length == rhs.ptr + rhs.length; } /// @safe pure nothrow unittest { auto a = [1, 2, 3, 4, 5]; auto b = a[3..$]; assert(a.sameTail(b)); } @safe pure nothrow unittest { foreach(T; AliasSeq!(int[], const(int)[], immutable(int)[], const int[], immutable int[])) { T a = [1, 2, 3, 4, 5]; T b = a; T c = a[1 .. $]; T d = a[0 .. 1]; T e = null; assert(sameHead(a, a)); assert(sameHead(a, b)); assert(!sameHead(a, c)); assert(sameHead(a, d)); assert(!sameHead(a, e)); assert(sameTail(a, a)); assert(sameTail(a, b)); assert(sameTail(a, c)); assert(!sameTail(a, d)); assert(!sameTail(a, e)); //verifies R-value compatibilty assert(a.sameHead(a[0 .. 0])); assert(a.sameTail(a[$ .. $])); } } /******************************************** Returns an array that consists of $(D s) (which must be an input range) repeated $(D n) times. This function allocates, fills, and returns a new array. For a lazy version, refer to $(XREF range, repeat). */ ElementEncodingType!S[] replicate(S)(S s, size_t n) if (isDynamicArray!S) { alias RetType = ElementEncodingType!S[]; // Optimization for return join(std.range.repeat(s, n)); if (n == 0) return RetType.init; if (n == 1) return cast(RetType) s; auto r = new Unqual!(typeof(s[0]))[n * s.length]; if (s.length == 1) r[] = s[0]; else { immutable len = s.length, nlen = n * len; for (size_t i = 0; i < nlen; i += len) { r[i .. i + len] = s[]; } } return r; } /// ditto ElementType!S[] replicate(S)(S s, size_t n) if (isInputRange!S && !isDynamicArray!S) { import std.range : repeat; return join(std.range.repeat(s, n)); } /// unittest { auto a = "abc"; auto s = replicate(a, 3); assert(s == "abcabcabc"); auto b = [1, 2, 3]; auto c = replicate(b, 3); assert(c == [1, 2, 3, 1, 2, 3, 1, 2, 3]); auto d = replicate(b, 0); assert(d == []); } unittest { import std.conv : to; debug(std_array) printf("array.replicate.unittest\n"); foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[])) { S s; immutable S t = "abc"; assert(replicate(to!S("1234"), 0) is null); assert(replicate(to!S("1234"), 0) is null); assert(replicate(to!S("1234"), 1) == "1234"); assert(replicate(to!S("1234"), 2) == "12341234"); assert(replicate(to!S("1"), 4) == "1111"); assert(replicate(t, 3) == "abcabcabc"); assert(replicate(cast(S) null, 4) is null); } } /++ Eagerly split the string $(D s) into an array of words, using whitespace as delimiter. Runs of whitespace are merged together (no empty words are produced). $(D @safe), $(D pure) and $(D CTFE)-able. See_Also: $(XREF_PACK algorithm,iteration,splitter) for a version that splits using any separator. $(XREF regex, splitter) for a version that splits using a regular expression defined separator. +/ S[] split(S)(S s) @safe pure if (isSomeString!S) { size_t istart; bool inword = false; S[] result; foreach (i, dchar c ; s) { import std.uni : isWhite; if (isWhite(c)) { if (inword) { result ~= s[istart .. i]; inword = false; } } else { if (!inword) { istart = i; inword = true; } } } if (inword) result ~= s[istart .. $]; return result; } unittest { import std.conv : to; import std.format; import std.typecons; static auto makeEntry(S)(string l, string[] r) {return tuple(l.to!S(), r.to!(S[])());} foreach (S; AliasSeq!(string, wstring, dstring,)) { auto entries = [ makeEntry!S("", []), makeEntry!S(" ", []), makeEntry!S("hello", ["hello"]), makeEntry!S(" hello ", ["hello"]), makeEntry!S(" h e l l o ", ["h", "e", "l", "l", "o"]), makeEntry!S("peter\t\npaul\rjerry", ["peter", "paul", "jerry"]), makeEntry!S(" \t\npeter paul\tjerry \n", ["peter", "paul", "jerry"]), makeEntry!S("\u2000日\u202F本\u205F語\u3000", ["日", "本", "語"]), makeEntry!S("  哈・郎博尔德}    ___一个", ["哈・郎博尔德}", "___一个"]) ]; foreach (entry; entries) assert(entry[0].split() == entry[1], format("got: %s, expected: %s.", entry[0].split(), entry[1])); } //Just to test that an immutable is split-able immutable string s = " \t\npeter paul\tjerry \n"; assert(split(s) == ["peter", "paul", "jerry"]); } unittest //safety, purity, ctfe ... { import std.exception; void dg() @safe pure { assert(split("hello world"c) == ["hello"c, "world"c]); assert(split("hello world"w) == ["hello"w, "world"w]); assert(split("hello world"d) == ["hello"d, "world"d]); } dg(); assertCTFEable!dg; } /// unittest { assert(split("hello world") == ["hello","world"]); assert(split("192.168.0.1", ".") == ["192", "168", "0", "1"]); auto a = split([1, 2, 3, 4, 5, 1, 2, 3, 4, 5], [2, 3]); assert(a == [[1], [4, 5, 1], [4, 5]]); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. Use $(XREF_PACK algorithm,iteration,_splitter) instead. This will be removed in January 2017.) Alias for $(XREF_PACK algorithm,iteration,_splitter). +/ deprecated("Please use std.algorithm.iteration.splitter instead.") alias splitter = std.algorithm.iteration.splitter; /++ Eagerly splits $(D range) into an array, using $(D sep) as the delimiter. The _range must be a $(XREF_PACK_NAMED _range,primitives,isForwardRange,forward _range). The separator can be a value of the same type as the elements in $(D range) or it can be another forward _range. Example: If $(D range) is a $(D string), $(D sep) can be a $(D char) or another $(D string). The return type will be an array of strings. If $(D range) is an $(D int) array, $(D sep) can be an $(D int) or another $(D int) array. The return type will be an array of $(D int) arrays. Params: range = a forward _range. sep = a value of the same type as the elements of $(D range) or another forward range. Returns: An array containing the divided parts of $(D range). See_Also: $(XREF_PACK algorithm,iteration,splitter) for the lazy version of this function. +/ auto split(Range, Separator)(Range range, Separator sep) if (isForwardRange!Range && is(typeof(ElementType!Range.init == Separator.init))) { import std.algorithm : splitter; return range.splitter(sep).array; } ///ditto auto split(Range, Separator)(Range range, Separator sep) if (isForwardRange!Range && isForwardRange!Separator && is(typeof(ElementType!Range.init == ElementType!Separator.init))) { import std.algorithm : splitter; return range.splitter(sep).array; } ///ditto auto split(alias isTerminator, Range)(Range range) if (isForwardRange!Range && is(typeof(unaryFun!isTerminator(range.front)))) { import std.algorithm : splitter; return range.splitter!isTerminator.array; } unittest { import std.conv; import std.algorithm : cmp; debug(std_array) printf("array.split\n"); foreach (S; AliasSeq!(string, wstring, dstring, immutable(string), immutable(wstring), immutable(dstring), char[], wchar[], dchar[], const(char)[], const(wchar)[], const(dchar)[], const(char[]), immutable(char[]))) { S s = to!S(",peter,paul,jerry,"); auto words = split(s, ","); assert(words.length == 5, text(words.length)); assert(cmp(words[0], "") == 0); assert(cmp(words[1], "peter") == 0); assert(cmp(words[2], "paul") == 0); assert(cmp(words[3], "jerry") == 0); assert(cmp(words[4], "") == 0); auto s1 = s[0 .. s.length - 1]; // lop off trailing ',' words = split(s1, ","); assert(words.length == 4); assert(cmp(words[3], "jerry") == 0); auto s2 = s1[1 .. s1.length]; // lop off leading ',' words = split(s2, ","); assert(words.length == 3); assert(cmp(words[0], "peter") == 0); auto s3 = to!S(",,peter,,paul,,jerry,,"); words = split(s3, ",,"); assert(words.length == 5); assert(cmp(words[0], "") == 0); assert(cmp(words[1], "peter") == 0); assert(cmp(words[2], "paul") == 0); assert(cmp(words[3], "jerry") == 0); assert(cmp(words[4], "") == 0); auto s4 = s3[0 .. s3.length - 2]; // lop off trailing ',,' words = split(s4, ",,"); assert(words.length == 4); assert(cmp(words[3], "jerry") == 0); auto s5 = s4[2 .. s4.length]; // lop off leading ',,' words = split(s5, ",,"); assert(words.length == 3); assert(cmp(words[0], "peter") == 0); } } /++ Conservative heuristic to determine if a range can be iterated cheaply. Used by $(D join) in decision to do an extra iteration of the range to compute the resultant length. If iteration is not cheap then precomputing length could be more expensive than using $(D Appender). For now, we only assume arrays are cheap to iterate. +/ private enum bool hasCheapIteration(R) = isArray!R; /++ Concatenates all of the ranges in $(D ror) together into one array using $(D sep) as the separator if present. Params: ror = Range of Ranges of Elements sep = Range of Elements Returns: an allocated array of Elements See_Also: $(XREF_PACK algorithm,iteration,joiner) +/ ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, R sep) if(isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && isInputRange!R && is(Unqual!(ElementType!(ElementType!RoR)) == Unqual!(ElementType!R))) { alias RetType = typeof(return); alias RetTypeElement = Unqual!(ElementEncodingType!RetType); alias RoRElem = ElementType!RoR; if (ror.empty) return RetType.init; // Constraint only requires input range for sep. // This converts sep to an array (forward range) if it isn't one, // and makes sure it has the same string encoding for string types. static if (isSomeString!RetType && !is(RetTypeElement == Unqual!(ElementEncodingType!R))) { import std.conv : to; auto sepArr = to!RetType(sep); } else static if (!isArray!R) auto sepArr = array(sep); else alias sepArr = sep; static if(hasCheapIteration!RoR && (hasLength!RoRElem || isNarrowString!RoRElem)) { import std.conv : emplaceRef; size_t length; // length of result array size_t rorLength; // length of range ror foreach(r; ror.save) { length += r.length; ++rorLength; } if (!rorLength) return null; length += (rorLength - 1) * sepArr.length; auto result = (() @trusted => uninitializedArray!(RetTypeElement[])(length))(); size_t len; foreach(e; ror.front) emplaceRef(result[len++], e); ror.popFront(); foreach(r; ror) { foreach(e; sepArr) emplaceRef(result[len++], e); foreach(e; r) emplaceRef(result[len++], e); } assert(len == result.length); return (() @trusted => cast(RetType) result)(); } else { auto result = appender!RetType(); put(result, ror.front); ror.popFront(); for (; !ror.empty; ror.popFront()) { put(result, sep); put(result, ror.front); } return result.data; } } unittest // Issue 14230 { string[] ary = ["","aa","bb","cc"]; // leaded by _empty_ element assert(ary.join(" @") == " @aa @bb @cc"); // OK in 2.067b1 and olders } /// Ditto ElementEncodingType!(ElementType!RoR)[] join(RoR, E)(RoR ror, E sep) if(isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && is(E : ElementType!(ElementType!RoR))) { alias RetType = typeof(return); alias RetTypeElement = Unqual!(ElementEncodingType!RetType); alias RoRElem = ElementType!RoR; if (ror.empty) return RetType.init; static if(hasCheapIteration!RoR && (hasLength!RoRElem || isNarrowString!RoRElem)) { static if (isSomeChar!E && isSomeChar!RetTypeElement && E.sizeof > RetTypeElement.sizeof) { import std.utf : encode; RetTypeElement[4 / RetTypeElement.sizeof] encodeSpace; immutable size_t sepArrLength = encode(encodeSpace, sep); return join(ror, encodeSpace[0..sepArrLength]); } else { import std.conv : emplaceRef; size_t length; size_t rorLength; foreach(r; ror.save) { length += r.length; ++rorLength; } if (!rorLength) return null; length += rorLength - 1; auto result = uninitializedArray!(RetTypeElement[])(length); size_t len; foreach(e; ror.front) emplaceRef(result[len++], e); ror.popFront(); foreach(r; ror) { emplaceRef(result[len++], sep); foreach(e; r) emplaceRef(result[len++], e); } assert(len == result.length); return (() @trusted => cast(RetType) result)(); } } else { auto result = appender!RetType(); put(result, ror.front); ror.popFront(); for (; !ror.empty; ror.popFront()) { put(result, sep); put(result, ror.front); } return result.data; } } unittest // Issue 10895 { class A { string name; alias name this; this(string name) { this.name = name; } } auto a = [new A(`foo`)]; assert(a[0].length == 3); auto temp = join(a, " "); assert(a[0].length == 3); } unittest // Issue 14230 { string[] ary = ["","aa","bb","cc"]; assert(ary.join('@') == "@aa@bb@cc"); } /// Ditto ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror) if(isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR))) { alias RetType = typeof(return); alias RetTypeElement = Unqual!(ElementEncodingType!RetType); alias RoRElem = ElementType!RoR; if (ror.empty) return RetType.init; static if(hasCheapIteration!RoR && (hasLength!RoRElem || isNarrowString!RoRElem)) { import std.conv : emplaceRef; size_t length; foreach(r; ror.save) length += r.length; auto result = (() @trusted => uninitializedArray!(RetTypeElement[])(length))(); size_t len; foreach(r; ror) foreach(e; r) emplaceRef(result[len++], e); assert(len == result.length); return (() @trusted => cast(RetType)result)(); } else { auto result = appender!RetType(); for (; !ror.empty; ror.popFront()) put(result, ror.front); return result.data; } } /// @safe pure nothrow unittest { assert(join(["hello", "silly", "world"], " ") == "hello silly world"); assert(join(["hello", "silly", "world"]) == "hellosillyworld"); assert(join([[1, 2, 3], [4, 5]], [72, 73]) == [1, 2, 3, 72, 73, 4, 5]); assert(join([[1, 2, 3], [4, 5]]) == [1, 2, 3, 4, 5]); const string[] arr = ["apple", "banana"]; assert(arr.join(",") == "apple,banana"); assert(arr.join() == "applebanana"); } @safe pure unittest { import std.conv : to; foreach (T; AliasSeq!(string,wstring,dstring)) { auto arr2 = "Здравствуй Мир Unicode".to!(T); auto arr = ["Здравствуй", "Мир", "Unicode"].to!(T[]); assert(join(arr) == "ЗдравствуйМирUnicode"); foreach (S; AliasSeq!(char,wchar,dchar)) { auto jarr = arr.join(to!S(' ')); static assert(is(typeof(jarr) == T)); assert(jarr == arr2); } foreach (S; AliasSeq!(string,wstring,dstring)) { auto jarr = arr.join(to!S(" ")); static assert(is(typeof(jarr) == T)); assert(jarr == arr2); } } foreach (T; AliasSeq!(string,wstring,dstring)) { auto arr2 = "Здравствуй\u047CМир\u047CUnicode".to!(T); auto arr = ["Здравствуй", "Мир", "Unicode"].to!(T[]); foreach (S; AliasSeq!(wchar,dchar)) { auto jarr = arr.join(to!S('\u047C')); static assert(is(typeof(jarr) == T)); assert(jarr == arr2); } } const string[] arr = ["apple", "banana"]; assert(arr.join(',') == "apple,banana"); } unittest { import std.conv : to; import std.algorithm; import std.range; debug(std_array) printf("array.join.unittest\n"); foreach(R; AliasSeq!(string, wstring, dstring)) { R word1 = "日本語"; R word2 = "paul"; R word3 = "jerry"; R[] words = [word1, word2, word3]; auto filteredWord1 = filter!"true"(word1); auto filteredLenWord1 = takeExactly(filteredWord1, word1.walkLength()); auto filteredWord2 = filter!"true"(word2); auto filteredLenWord2 = takeExactly(filteredWord2, word2.walkLength()); auto filteredWord3 = filter!"true"(word3); auto filteredLenWord3 = takeExactly(filteredWord3, word3.walkLength()); auto filteredWordsArr = [filteredWord1, filteredWord2, filteredWord3]; auto filteredLenWordsArr = [filteredLenWord1, filteredLenWord2, filteredLenWord3]; auto filteredWords = filter!"true"(filteredWordsArr); foreach(S; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(join(filteredWords, to!S(", ")) == "日本語, paul, jerry"); assert(join(filteredWords, to!(ElementType!S)(',')) == "日本語,paul,jerry"); assert(join(filteredWordsArr, to!(ElementType!(S))(',')) == "日本語,paul,jerry"); assert(join(filteredWordsArr, to!S(", ")) == "日本語, paul, jerry"); assert(join(filteredWordsArr, to!(ElementType!(S))(',')) == "日本語,paul,jerry"); assert(join(filteredLenWordsArr, to!S(", ")) == "日本語, paul, jerry"); assert(join(filter!"true"(words), to!S(", ")) == "日本語, paul, jerry"); assert(join(words, to!S(", ")) == "日本語, paul, jerry"); assert(join(filteredWords, to!S("")) == "日本語pauljerry"); assert(join(filteredWordsArr, to!S("")) == "日本語pauljerry"); assert(join(filteredLenWordsArr, to!S("")) == "日本語pauljerry"); assert(join(filter!"true"(words), to!S("")) == "日本語pauljerry"); assert(join(words, to!S("")) == "日本語pauljerry"); assert(join(filter!"true"([word1]), to!S(", ")) == "日本語"); assert(join([filteredWord1], to!S(", ")) == "日本語"); assert(join([filteredLenWord1], to!S(", ")) == "日本語"); assert(join(filter!"true"([filteredWord1]), to!S(", ")) == "日本語"); assert(join([word1], to!S(", ")) == "日本語"); assert(join(filteredWords, to!S(word1)) == "日本語日本語paul日本語jerry"); assert(join(filteredWordsArr, to!S(word1)) == "日本語日本語paul日本語jerry"); assert(join(filteredLenWordsArr, to!S(word1)) == "日本語日本語paul日本語jerry"); assert(join(filter!"true"(words), to!S(word1)) == "日本語日本語paul日本語jerry"); assert(join(words, to!S(word1)) == "日本語日本語paul日本語jerry"); auto filterComma = filter!"true"(to!S(", ")); assert(join(filteredWords, filterComma) == "日本語, paul, jerry"); assert(join(filteredWordsArr, filterComma) == "日本語, paul, jerry"); assert(join(filteredLenWordsArr, filterComma) == "日本語, paul, jerry"); assert(join(filter!"true"(words), filterComma) == "日本語, paul, jerry"); assert(join(words, filterComma) == "日本語, paul, jerry"); }(); assert(join(filteredWords) == "日本語pauljerry"); assert(join(filteredWordsArr) == "日本語pauljerry"); assert(join(filteredLenWordsArr) == "日本語pauljerry"); assert(join(filter!"true"(words)) == "日本語pauljerry"); assert(join(words) == "日本語pauljerry"); assert(join(filteredWords, filter!"true"(", ")) == "日本語, paul, jerry"); assert(join(filteredWordsArr, filter!"true"(", ")) == "日本語, paul, jerry"); assert(join(filteredLenWordsArr, filter!"true"(", ")) == "日本語, paul, jerry"); assert(join(filter!"true"(words), filter!"true"(", ")) == "日本語, paul, jerry"); assert(join(words, filter!"true"(", ")) == "日本語, paul, jerry"); assert(join(filter!"true"(cast(typeof(filteredWordsArr))[]), ", ").empty); assert(join(cast(typeof(filteredWordsArr))[], ", ").empty); assert(join(cast(typeof(filteredLenWordsArr))[], ", ").empty); assert(join(filter!"true"(cast(R[])[]), ", ").empty); assert(join(cast(R[])[], ", ").empty); assert(join(filter!"true"(cast(typeof(filteredWordsArr))[])).empty); assert(join(cast(typeof(filteredWordsArr))[]).empty); assert(join(cast(typeof(filteredLenWordsArr))[]).empty); assert(join(filter!"true"(cast(R[])[])).empty); assert(join(cast(R[])[]).empty); } assert(join([[1, 2], [41, 42]], [5, 6]) == [1, 2, 5, 6, 41, 42]); assert(join([[1, 2], [41, 42]], cast(int[])[]) == [1, 2, 41, 42]); assert(join([[1, 2]], [5, 6]) == [1, 2]); assert(join(cast(int[][])[], [5, 6]).empty); assert(join([[1, 2], [41, 42]]) == [1, 2, 41, 42]); assert(join(cast(int[][])[]).empty); alias f = filter!"true"; assert(join([[1, 2], [41, 42]], [5, 6]) == [1, 2, 5, 6, 41, 42]); assert(join(f([[1, 2], [41, 42]]), [5, 6]) == [1, 2, 5, 6, 41, 42]); assert(join([f([1, 2]), f([41, 42])], [5, 6]) == [1, 2, 5, 6, 41, 42]); assert(join(f([f([1, 2]), f([41, 42])]), [5, 6]) == [1, 2, 5, 6, 41, 42]); assert(join([[1, 2], [41, 42]], f([5, 6])) == [1, 2, 5, 6, 41, 42]); assert(join(f([[1, 2], [41, 42]]), f([5, 6])) == [1, 2, 5, 6, 41, 42]); assert(join([f([1, 2]), f([41, 42])], f([5, 6])) == [1, 2, 5, 6, 41, 42]); assert(join(f([f([1, 2]), f([41, 42])]), f([5, 6])) == [1, 2, 5, 6, 41, 42]); } // Issue 10683 unittest { import std.range : join; import std.typecons : tuple; assert([[tuple(1)]].join == [tuple(1)]); assert([[tuple("x")]].join == [tuple("x")]); } // Issue 13877 unittest { // Test that the range is iterated only once. import std.algorithm : map; int c = 0; auto j1 = [1, 2, 3].map!(_ => [c++]).join; assert(c == 3); assert(j1 == [0, 1, 2]); c = 0; auto j2 = [1, 2, 3].map!(_ => [c++]).join(9); assert(c == 3); assert(j2 == [0, 9, 1, 9, 2]); c = 0; auto j3 = [1, 2, 3].map!(_ => [c++]).join([9]); assert(c == 3); assert(j3 == [0, 9, 1, 9, 2]); } /++ Replace occurrences of $(D from) with $(D to) in $(D subject). Returns a new array without changing the contents of $(D subject), or the original array if no match is found. +/ E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to) if (isDynamicArray!(E[]) && isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) { if (from.empty) return subject; auto balance = std.algorithm.find(subject, from.save); if (balance.empty) return subject; auto app = appender!(E[])(); app.put(subject[0 .. subject.length - balance.length]); app.put(to.save); replaceInto(app, balance[from.length .. $], from, to); return app.data; } /// unittest { assert("Hello Wörld".replace("o Wö", "o Wo") == "Hello World"); assert("Hello Wörld".replace("l", "h") == "Hehho Wörhd"); } /++ Same as above, but outputs the result via OutputRange $(D sink). If no match is found the original array is transferred to $(D sink) as is. +/ void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to) if (isOutputRange!(Sink, E) && isDynamicArray!(E[]) && isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) { if (from.empty) { sink.put(subject); return; } for (;;) { auto balance = std.algorithm.find(subject, from.save); if (balance.empty) { sink.put(subject); break; } sink.put(subject[0 .. subject.length - balance.length]); sink.put(to.save); subject = balance[from.length .. $]; } } /// unittest { auto arr = [1, 2, 3, 4, 5]; auto from = [2, 3]; auto into = [4, 6]; auto sink = appender!(int[])(); replaceInto(sink, arr, from, into); assert(sink.data == [1, 4, 6, 4, 5]); } unittest { import std.conv : to; import std.algorithm : cmp; debug(std_array) printf("array.replace.unittest\n"); foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[])) { foreach (T; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[])) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 auto s = to!S("This is a foo foo list"); auto from = to!T("foo"); auto into = to!S("silly"); S r; int i; r = replace(s, from, into); i = cmp(r, "This is a silly silly list"); assert(i == 0); r = replace(s, to!S(""), into); i = cmp(r, "This is a foo foo list"); assert(i == 0); assert(replace(r, to!S("won't find this"), to!S("whatever")) is r); }(); } immutable s = "This is a foo foo list"; assert(replace(s, "foo", "silly") == "This is a silly silly list"); } unittest { import std.conv : to; import std.algorithm : skipOver; struct CheckOutput(C) { C[] desired; this(C[] arr){ desired = arr; } void put(C[] part){ assert(skipOver(desired, part)); } } foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[])) { alias Char = ElementEncodingType!S; S s = to!S("yet another dummy text, yet another ..."); S from = to!S("yet another"); S into = to!S("some"); replaceInto(CheckOutput!(Char)(to!S("some dummy text, some ...")) , s, from, into); } } /++ Replaces elements from $(D array) with indices ranging from $(D from) (inclusive) to $(D to) (exclusive) with the range $(D stuff). Returns a new array without changing the contents of $(D subject). +/ T[] replace(T, Range)(T[] subject, size_t from, size_t to, Range stuff) if(isInputRange!Range && (is(ElementType!Range : T) || isSomeString!(T[]) && is(ElementType!Range : dchar))) { static if(hasLength!Range && is(ElementEncodingType!Range : T)) { import std.algorithm : copy; assert(from <= to); immutable sliceLen = to - from; auto retval = new Unqual!(T)[](subject.length - sliceLen + stuff.length); retval[0 .. from] = subject[0 .. from]; if(!stuff.empty) copy(stuff, retval[from .. from + stuff.length]); retval[from + stuff.length .. $] = subject[to .. $]; return cast(T[])retval; } else { auto app = appender!(T[])(); app.put(subject[0 .. from]); app.put(stuff); app.put(subject[to .. $]); return app.data; } } /// unittest { auto a = [ 1, 2, 3, 4 ]; auto b = a.replace(1, 3, [ 9, 9, 9 ]); assert(a == [ 1, 2, 3, 4 ]); assert(b == [ 1, 9, 9, 9, 4 ]); } unittest { import core.exception; import std.conv : to; import std.exception; import std.algorithm; auto a = [ 1, 2, 3, 4 ]; assert(replace(a, 0, 0, [5, 6, 7]) == [5, 6, 7, 1, 2, 3, 4]); assert(replace(a, 0, 2, cast(int[])[]) == [3, 4]); assert(replace(a, 0, 4, [5, 6, 7]) == [5, 6, 7]); assert(replace(a, 0, 2, [5, 6, 7]) == [5, 6, 7, 3, 4]); assert(replace(a, 2, 4, [5, 6, 7]) == [1, 2, 5, 6, 7]); assert(replace(a, 0, 0, filter!"true"([5, 6, 7])) == [5, 6, 7, 1, 2, 3, 4]); assert(replace(a, 0, 2, filter!"true"(cast(int[])[])) == [3, 4]); assert(replace(a, 0, 4, filter!"true"([5, 6, 7])) == [5, 6, 7]); assert(replace(a, 0, 2, filter!"true"([5, 6, 7])) == [5, 6, 7, 3, 4]); assert(replace(a, 2, 4, filter!"true"([5, 6, 7])) == [1, 2, 5, 6, 7]); assert(a == [ 1, 2, 3, 4 ]); auto testStr(T, U)(string file = __FILE__, size_t line = __LINE__) { auto l = to!T("hello"); auto r = to!U(" world"); enforce(replace(l, 0, 0, r) == " worldhello", new AssertError("testStr failure 1", file, line)); enforce(replace(l, 0, 3, r) == " worldlo", new AssertError("testStr failure 2", file, line)); enforce(replace(l, 3, l.length, r) == "hel world", new AssertError("testStr failure 3", file, line)); enforce(replace(l, 0, l.length, r) == " world", new AssertError("testStr failure 4", file, line)); enforce(replace(l, l.length, l.length, r) == "hello world", new AssertError("testStr failure 5", file, line)); } testStr!(string, string)(); testStr!(string, wstring)(); testStr!(string, dstring)(); testStr!(wstring, string)(); testStr!(wstring, wstring)(); testStr!(wstring, dstring)(); testStr!(dstring, string)(); testStr!(dstring, wstring)(); testStr!(dstring, dstring)(); enum s = "0123456789"; enum w = "⁰¹²³⁴⁵⁶⁷⁸⁹"w; enum d = "⁰¹²³⁴⁵⁶⁷⁸⁹"d; assert(replace(s, 0, 0, "***") == "***0123456789"); assert(replace(s, 10, 10, "***") == "0123456789***"); assert(replace(s, 3, 8, "1012") == "012101289"); assert(replace(s, 0, 5, "43210") == "4321056789"); assert(replace(s, 5, 10, "43210") == "0123443210"); assert(replace(w, 0, 0, "***"w) == "***⁰¹²³⁴⁵⁶⁷⁸⁹"w); assert(replace(w, 10, 10, "***"w) == "⁰¹²³⁴⁵⁶⁷⁸⁹***"w); assert(replace(w, 3, 8, "¹⁰¹²"w) == "⁰¹²¹⁰¹²⁸⁹"w); assert(replace(w, 0, 5, "⁴³²¹⁰"w) == "⁴³²¹⁰⁵⁶⁷⁸⁹"w); assert(replace(w, 5, 10, "⁴³²¹⁰"w) == "⁰¹²³⁴⁴³²¹⁰"w); assert(replace(d, 0, 0, "***"d) == "***⁰¹²³⁴⁵⁶⁷⁸⁹"d); assert(replace(d, 10, 10, "***"d) == "⁰¹²³⁴⁵⁶⁷⁸⁹***"d); assert(replace(d, 3, 8, "¹⁰¹²"d) == "⁰¹²¹⁰¹²⁸⁹"d); assert(replace(d, 0, 5, "⁴³²¹⁰"d) == "⁴³²¹⁰⁵⁶⁷⁸⁹"d); assert(replace(d, 5, 10, "⁴³²¹⁰"d) == "⁰¹²³⁴⁴³²¹⁰"d); } /++ Replaces elements from $(D array) with indices ranging from $(D from) (inclusive) to $(D to) (exclusive) with the range $(D stuff). Expands or shrinks the array as needed. +/ void replaceInPlace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff) if(is(typeof(replace(array, from, to, stuff)))) { static if(isDynamicArray!Range && is(Unqual!(ElementEncodingType!Range) == T) && !isNarrowString!(T[])) { // optimized for homogeneous arrays that can be overwritten. import std.algorithm : remove; import std.typecons : tuple; if (overlap(array, stuff).length) { // use slower/conservative method array = array[0 .. from] ~ stuff ~ array[to .. $]; } else if (stuff.length <= to - from) { // replacement reduces length immutable stuffEnd = from + stuff.length; array[from .. stuffEnd] = stuff[]; if (stuffEnd < to) array = remove(array, tuple(stuffEnd, to)); } else { // replacement increases length // @@@TODO@@@: optimize this immutable replaceLen = to - from; array[from .. to] = stuff[0 .. replaceLen]; insertInPlace(array, to, stuff[replaceLen .. $]); } } else { // default implementation, just do what replace does. array = replace(array, from, to, stuff); } } /// unittest { int[] a = [1, 4, 5]; replaceInPlace(a, 1u, 2u, [2, 3, 4]); assert(a == [1, 2, 3, 4, 5]); replaceInPlace(a, 1u, 2u, cast(int[])[]); assert(a == [1, 3, 4, 5]); replaceInPlace(a, 1u, 3u, a[2 .. 4]); assert(a == [1, 4, 5, 5]); } unittest { // Bug# 12889 int[1][] arr = [[0], [1], [2], [3], [4], [5], [6]]; int[1][] stuff = [[0], [1]]; replaceInPlace(arr, 4, 6, stuff); assert(arr == [[0], [1], [2], [3], [0], [1], [6]]); } unittest { // Bug# 14925 char[] a = "mon texte 1".dup; char[] b = "abc".dup; replaceInPlace(a, 4, 9, b); assert(a == "mon abc 1"); // ensure we can replace in place with different encodings string unicoded = "\U00010437"; string unicodedLong = "\U00010437aaaaa"; string base = "abcXXXxyz"; string result = "abc\U00010437xyz"; string resultLong = "abc\U00010437aaaaaxyz"; size_t repstart = 3; size_t repend = 3 + 3; void testStringReplaceInPlace(T, U)() { import std.conv; import std.algorithm : equal; auto a = unicoded.to!(U[]); auto b = unicodedLong.to!(U[]); auto test = base.to!(T[]); test.replaceInPlace(repstart, repend, a); assert(equal(test, result), "Failed for types " ~ T.stringof ~ " and " ~ U.stringof); test = base.to!(T[]); test.replaceInPlace(repstart, repend, b); assert(equal(test, resultLong), "Failed for types " ~ T.stringof ~ " and " ~ U.stringof); } import std.meta : AliasSeq; alias allChars = AliasSeq!(char, immutable(char), const(char), wchar, immutable(wchar), const(wchar), dchar, immutable(dchar), const(dchar)); foreach(T; allChars) foreach(U; allChars) testStringReplaceInPlace!(T, U)(); void testInout(inout(int)[] a) { // will be transferred to the 'replace' function replaceInPlace(a, 1, 2, [1,2,3]); } } unittest { // the constraint for the first overload used to match this, which wouldn't compile. import std.algorithm : equal; long[] a = [1L, 2, 3]; int[] b = [4, 5, 6]; a.replaceInPlace(1, 2, b); assert(equal(a, [1L, 4, 5, 6, 3])); } unittest { import core.exception; import std.conv : to; import std.exception; import std.algorithm; bool test(T, U, V)(T orig, size_t from, size_t to, U toReplace, V result, string file = __FILE__, size_t line = __LINE__) { { static if(is(T == typeof(T.init.dup))) auto a = orig.dup; else auto a = orig.idup; a.replaceInPlace(from, to, toReplace); if(!std.algorithm.equal(a, result)) return false; } static if(isInputRange!U) { orig.replaceInPlace(from, to, filter!"true"(toReplace)); return std.algorithm.equal(orig, result); } else return true; } assert(test([1, 2, 3, 4], 0, 0, [5, 6, 7], [5, 6, 7, 1, 2, 3, 4])); assert(test([1, 2, 3, 4], 0, 2, cast(int[])[], [3, 4])); assert(test([1, 2, 3, 4], 0, 4, [5, 6, 7], [5, 6, 7])); assert(test([1, 2, 3, 4], 0, 2, [5, 6, 7], [5, 6, 7, 3, 4])); assert(test([1, 2, 3, 4], 2, 4, [5, 6, 7], [1, 2, 5, 6, 7])); assert(test([1, 2, 3, 4], 0, 0, filter!"true"([5, 6, 7]), [5, 6, 7, 1, 2, 3, 4])); assert(test([1, 2, 3, 4], 0, 2, filter!"true"(cast(int[])[]), [3, 4])); assert(test([1, 2, 3, 4], 0, 4, filter!"true"([5, 6, 7]), [5, 6, 7])); assert(test([1, 2, 3, 4], 0, 2, filter!"true"([5, 6, 7]), [5, 6, 7, 3, 4])); assert(test([1, 2, 3, 4], 2, 4, filter!"true"([5, 6, 7]), [1, 2, 5, 6, 7])); auto testStr(T, U)(string file = __FILE__, size_t line = __LINE__) { auto l = to!T("hello"); auto r = to!U(" world"); enforce(test(l, 0, 0, r, " worldhello"), new AssertError("testStr failure 1", file, line)); enforce(test(l, 0, 3, r, " worldlo"), new AssertError("testStr failure 2", file, line)); enforce(test(l, 3, l.length, r, "hel world"), new AssertError("testStr failure 3", file, line)); enforce(test(l, 0, l.length, r, " world"), new AssertError("testStr failure 4", file, line)); enforce(test(l, l.length, l.length, r, "hello world"), new AssertError("testStr failure 5", file, line)); } testStr!(string, string)(); testStr!(string, wstring)(); testStr!(string, dstring)(); testStr!(wstring, string)(); testStr!(wstring, wstring)(); testStr!(wstring, dstring)(); testStr!(dstring, string)(); testStr!(dstring, wstring)(); testStr!(dstring, dstring)(); } /++ Replaces the first occurrence of $(D from) with $(D to) in $(D a). Returns a new array without changing the contents of $(D subject), or the original array if no match is found. +/ E[] replaceFirst(E, R1, R2)(E[] subject, R1 from, R2 to) if (isDynamicArray!(E[]) && isForwardRange!R1 && is(typeof(appender!(E[])().put(from[0 .. 1]))) && isForwardRange!R2 && is(typeof(appender!(E[])().put(to[0 .. 1])))) { import std.algorithm : countUntil; if (from.empty) return subject; static if (isSomeString!(E[])) { import std.string : indexOf; immutable idx = subject.indexOf(from); } else { import std.algorithm : countUntil; immutable idx = subject.countUntil(from); } if (idx == -1) return subject; auto app = appender!(E[])(); app.put(subject[0 .. idx]); app.put(to); static if (isSomeString!(E[]) && isSomeString!R1) { import std.utf : codeLength; immutable fromLength = codeLength!(Unqual!E, R1)(from); } else immutable fromLength = from.length; app.put(subject[idx + fromLength .. $]); return app.data; } /// unittest { auto a = [1, 2, 2, 3, 4, 5]; auto b = a.replaceFirst([2], [1337]); assert(b == [1, 1337, 2, 3, 4, 5]); auto s = "This is a foo foo list"; auto r = s.replaceFirst("foo", "silly"); assert(r == "This is a silly foo list"); } unittest { import std.conv : to; import std.algorithm : cmp; debug(std_array) printf("array.replaceFirst.unittest\n"); foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[], const(char[]), immutable(char[]))) { foreach (T; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[], const(char[]), immutable(char[]))) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 auto s = to!S("This is a foo foo list"); auto s2 = to!S("Thüs is a ßöö foo list"); auto from = to!T("foo"); auto from2 = to!T("ßöö"); auto into = to!T("silly"); auto into2 = to!T("sälly"); S r1 = replaceFirst(s, from, into); assert(cmp(r1, "This is a silly foo list") == 0); S r11 = replaceFirst(s2, from2, into2); assert(cmp(r11, "Thüs is a sälly foo list") == 0, to!string(r11) ~ " : " ~ S.stringof ~ " " ~ T.stringof); S r2 = replaceFirst(r1, from, into); assert(cmp(r2, "This is a silly silly list") == 0); S r3 = replaceFirst(s, to!T(""), into); assert(cmp(r3, "This is a foo foo list") == 0); assert(replaceFirst(r3, to!T("won't find"), to!T("whatever")) is r3); }(); } } //Bug# 8187 unittest { auto res = ["a", "a"]; assert(replace(res, "a", "b") == ["b", "b"]); assert(replaceFirst(res, "a", "b") == ["b", "a"]); } /++ Replaces the last occurrence of $(D from) with $(D to) in $(D a). Returns a new array without changing the contents of $(D subject), or the original array if no match is found. +/ E[] replaceLast(E, R1, R2)(E[] subject, R1 from , R2 to) if (isDynamicArray!(E[]) && isForwardRange!R1 && is(typeof(appender!(E[])().put(from[0 .. 1]))) && isForwardRange!R2 && is(typeof(appender!(E[])().put(to[0 .. 1])))) { import std.range : retro; if (from.empty) return subject; static if (isSomeString!(E[])) { import std.string : lastIndexOf; auto idx = subject.lastIndexOf(from); } else { import std.algorithm : countUntil; auto idx = retro(subject).countUntil(retro(from)); } if (idx == -1) return subject; static if (isSomeString!(E[]) && isSomeString!R1) { import std.utf : codeLength; auto fromLength = codeLength!(Unqual!E, R1)(from); } else auto fromLength = from.length; auto app = appender!(E[])(); static if (isSomeString!(E[])) app.put(subject[0 .. idx]); else app.put(subject[0 .. $ - idx - fromLength]); app.put(to); static if (isSomeString!(E[])) app.put(subject[idx+fromLength .. $]); else app.put(subject[$ - idx .. $]); return app.data; } /// unittest { auto a = [1, 2, 2, 3, 4, 5]; auto b = a.replaceLast([2], [1337]); assert(b == [1, 2, 1337, 3, 4, 5]); auto s = "This is a foo foo list"; auto r = s.replaceLast("foo", "silly"); assert(r == "This is a foo silly list", r); } unittest { import std.conv : to; import std.algorithm : cmp; debug(std_array) printf("array.replaceLast.unittest\n"); foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[], const(char[]), immutable(char[]))) { foreach (T; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[], const(char[]), immutable(char[]))) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 auto s = to!S("This is a foo foo list"); auto s2 = to!S("Thüs is a ßöö ßöö list"); auto from = to!T("foo"); auto from2 = to!T("ßöö"); auto into = to!T("silly"); auto into2 = to!T("sälly"); S r1 = replaceLast(s, from, into); assert(cmp(r1, "This is a foo silly list") == 0, to!string(r1)); S r11 = replaceLast(s2, from2, into2); assert(cmp(r11, "Thüs is a ßöö sälly list") == 0, to!string(r11) ~ " : " ~ S.stringof ~ " " ~ T.stringof); S r2 = replaceLast(r1, from, into); assert(cmp(r2, "This is a silly silly list") == 0); S r3 = replaceLast(s, to!T(""), into); assert(cmp(r3, "This is a foo foo list") == 0); assert(replaceLast(r3, to!T("won't find"), to!T("whatever")) is r3); }(); } } /++ Returns a new array that is $(D s) with $(D slice) replaced by $(D replacement[]). +/ inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement) in { // Verify that slice[] really is a slice of s[] assert(overlap(s, slice) is slice); } body { auto result = new T[s.length - slice.length + replacement.length]; immutable so = slice.ptr - s.ptr; result[0 .. so] = s[0 .. so]; result[so .. so + replacement.length] = replacement[]; result[so + replacement.length .. result.length] = s[so + slice.length .. s.length]; return cast(inout(T)[]) result; } /// unittest { auto a = [1, 2, 3, 4, 5]; auto b = replaceSlice(a, a[1..4], [0, 0, 0]); assert(b == [1, 0, 0, 0, 5]); } unittest { import std.algorithm : cmp; debug(std_array) printf("array.replaceSlice.unittest\n"); string s = "hello"; string slice = s[2 .. 4]; auto r = replaceSlice(s, slice, "bar"); int i; i = cmp(r, "hebaro"); assert(i == 0); } /** Implements an output range that appends data to an array. This is recommended over $(D a ~= data) when appending many elements because it is more efficient. */ struct Appender(A) if (isDynamicArray!A) { import core.memory; private alias T = ElementEncodingType!A; private struct Data { size_t capacity; Unqual!T[] arr; bool canExtend = false; } private Data* _data; /** * Construct an appender with a given array. Note that this does not copy the * data. If the array has a larger capacity as determined by arr.capacity, * it will be used by the appender. After initializing an appender on an array, * appending to the original array will reallocate. */ this(T[] arr) @trusted pure nothrow { // initialize to a given array. _data = new Data; _data.arr = cast(Unqual!T[])arr; //trusted if (__ctfe) return; // We want to use up as much of the block the array is in as possible. // if we consume all the block that we can, then array appending is // safe WRT built-in append, and we can use the entire block. // We only do this for mutable types that can be extended. static if (isMutable!T && is(typeof(arr.length = size_t.max))) { auto cap = arr.capacity; //trusted // Replace with "GC.setAttr( Not Appendable )" once pure (and fixed) if (cap > arr.length) arr.length = cap; } _data.capacity = arr.length; } //Broken function. To be removed. static if (is(T == immutable)) { // Explicitly undocumented. It will be removed in March 2016. @@@DEPRECATED_2016-03@@@ deprecated ("Using this constructor will break the type system. Please fix your code to use `Appender!(T[]).this(T[] arr)' directly.") this(Unqual!T[] arr) pure nothrow { this(cast(T[]) arr); } //temporary: For resolving ambiguity: this(typeof(null)) { this(cast(T[]) null); } } /** * Reserve at least newCapacity elements for appending. Note that more elements * may be reserved than requested. If newCapacity <= capacity, then nothing is * done. */ void reserve(size_t newCapacity) @safe pure nothrow { if (_data) { if (newCapacity > _data.capacity) ensureAddable(newCapacity - _data.arr.length); } else { ensureAddable(newCapacity); } } /** * Returns the capacity of the array (the maximum number of elements the * managed array can accommodate before triggering a reallocation). If any * appending will reallocate, $(D capacity) returns $(D 0). */ @property size_t capacity() const @safe pure nothrow { return _data ? _data.capacity : 0; } /** * Returns the managed array. */ @property inout(T)[] data() inout @trusted pure nothrow { /* @trusted operation: * casting Unqual!T[] to inout(T)[] */ return cast(typeof(return))(_data ? _data.arr : null); } // ensure we can add nelems elements, resizing as necessary private void ensureAddable(size_t nelems) @trusted pure nothrow { if (!_data) _data = new Data; immutable len = _data.arr.length; immutable reqlen = len + nelems; if (_data.capacity >= reqlen) return; // need to increase capacity if (__ctfe) { static if (__traits(compiles, new Unqual!T[1])) { _data.arr.length = reqlen; } else { // avoid restriction of @disable this() _data.arr = _data.arr[0 .. _data.capacity]; foreach (i; _data.capacity .. reqlen) _data.arr ~= Unqual!T.init; } _data.arr = _data.arr[0 .. len]; _data.capacity = reqlen; } else { // Time to reallocate. // We need to almost duplicate what's in druntime, except we // have better access to the capacity field. auto newlen = appenderNewCapacity!(T.sizeof)(_data.capacity, reqlen); // first, try extending the current block if (_data.canExtend) { auto u = GC.extend(_data.arr.ptr, nelems * T.sizeof, (newlen - len) * T.sizeof); if (u) { // extend worked, update the capacity _data.capacity = u / T.sizeof; return; } } // didn't work, must reallocate auto bi = GC.qalloc(newlen * T.sizeof, blockAttribute!T); _data.capacity = bi.size / T.sizeof; import core.stdc.string : memcpy; if (len) memcpy(bi.base, _data.arr.ptr, len * T.sizeof); _data.arr = (cast(Unqual!T*)bi.base)[0 .. len]; _data.canExtend = true; // leave the old data, for safety reasons } } private template canPutItem(U) { enum bool canPutItem = isImplicitlyConvertible!(U, T) || isSomeChar!T && isSomeChar!U; } private template canPutConstRange(Range) { enum bool canPutConstRange = isInputRange!(Unqual!Range) && !isInputRange!Range; } private template canPutRange(Range) { enum bool canPutRange = isInputRange!Range && is(typeof(Appender.init.put(Range.init.front))); } /** * Appends one item to the managed array. */ void put(U)(U item) if (canPutItem!U) { static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof) { /* may throwable operation: * - std.utf.encode */ // must do some transcoding around here import std.utf : encode; Unqual!T[T.sizeof == 1 ? 4 : 2] encoded; auto len = encode(encoded, item); put(encoded[0 .. len]); } else { import std.conv : emplaceRef; ensureAddable(1); immutable len = _data.arr.length; auto bigData = (() @trusted => _data.arr.ptr[0 .. len + 1])(); emplaceRef!(Unqual!T)(bigData[len], cast(Unqual!T)item); //We do this at the end, in case of exceptions _data.arr = bigData; } } // Const fixing hack. void put(Range)(Range items) if (canPutConstRange!Range) { alias p = put!(Unqual!Range); p(items); } /** * Appends an entire range to the managed array. */ void put(Range)(Range items) if (canPutRange!Range) { // note, we disable this branch for appending one type of char to // another because we can't trust the length portion. static if (!(isSomeChar!T && isSomeChar!(ElementType!Range) && !is(immutable Range == immutable T[])) && is(typeof(items.length) == size_t)) { // optimization -- if this type is something other than a string, // and we are adding exactly one element, call the version for one // element. static if (!isSomeChar!T) { if (items.length == 1) { put(items.front); return; } } // make sure we have enough space, then add the items @trusted auto bigDataFun(size_t extra) { ensureAddable(extra); return _data.arr.ptr[0 .. _data.arr.length + extra]; } auto bigData = bigDataFun(items.length); immutable len = _data.arr.length; immutable newlen = bigData.length; alias UT = Unqual!T; static if (is(typeof(_data.arr[] = items[])) && !hasElaborateAssign!(Unqual!T) && isAssignable!(UT, ElementEncodingType!Range)) { bigData[len .. newlen] = items[]; } else { import std.conv : emplaceRef; foreach (ref it ; bigData[len .. newlen]) { emplaceRef!T(it, items.front); items.popFront(); } } //We do this at the end, in case of exceptions _data.arr = bigData; } else { //pragma(msg, Range.stringof); // Generic input range for (; !items.empty; items.popFront()) { put(items.front); } } } /** * Appends one item to the managed array. */ void opOpAssign(string op : "~", U)(U item) if (canPutItem!U) { put(item); } // Const fixing hack. void opOpAssign(string op : "~", Range)(Range items) if (canPutConstRange!Range) { put(items); } /** * Appends an entire range to the managed array. */ void opOpAssign(string op : "~", Range)(Range items) if (canPutRange!Range) { put(items); } // only allow overwriting data on non-immutable and non-const data static if (isMutable!T) { /** * Clears the managed array. This allows the elements of the array to be reused * for appending. * * Note that clear is disabled for immutable or const element types, due to the * possibility that $(D Appender) might overwrite immutable data. */ void clear() @trusted pure nothrow { if (_data) { _data.arr = _data.arr.ptr[0 .. 0]; } } /** * Shrinks the managed array to the given length. * * Throws: $(D Exception) if newlength is greater than the current array length. */ void shrinkTo(size_t newlength) @trusted pure { import std.exception : enforce; if (_data) { enforce(newlength <= _data.arr.length, "Attempting to shrink Appender with newlength > length"); _data.arr = _data.arr.ptr[0 .. newlength]; } else enforce(newlength == 0, "Attempting to shrink empty Appender with non-zero newlength"); } } void toString()(scope void delegate(const(char)[]) sink) { import std.format : formattedWrite; sink.formattedWrite(typeof(this).stringof ~ "(%s)", data); } } /// unittest{ auto app = appender!string(); string b = "abcdefg"; foreach (char c; b) app.put(c); assert(app.data == "abcdefg"); int[] a = [ 1, 2 ]; auto app2 = appender(a); app2.put(3); app2.put([ 4, 5, 6 ]); assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); } unittest { import std.format : format; auto app = appender!(int[])(); app.put(1); app.put(2); app.put(3); assert("%s".format(app) == "Appender!(int[])(%s)".format([1,2,3])); } //Calculates an efficient growth scheme based on the old capacity //of data, and the minimum requested capacity. //arg curLen: The current length //arg reqLen: The length as requested by the user //ret sugLen: A suggested growth. private size_t appenderNewCapacity(size_t TSizeOf)(size_t curLen, size_t reqLen) @safe pure nothrow { import core.bitop : bsr; import std.algorithm : max; if(curLen == 0) return max(reqLen,8); ulong mult = 100 + (1000UL) / (bsr(curLen * TSizeOf) + 1); // limit to doubling the length, we don't want to grow too much if(mult > 200) mult = 200; auto sugLen = cast(size_t)((curLen * mult + 99) / 100); return max(reqLen, sugLen); } /** * An appender that can update an array in-place. It forwards all calls to an * underlying appender implementation. Any calls made to the appender also update * the pointer to the original array passed in. */ struct RefAppender(A) if (isDynamicArray!A) { private { alias T = ElementEncodingType!A; Appender!A impl; T[] *arr; } /** * Construct a ref appender with a given array reference. This does not copy the * data. If the array has a larger capacity as determined by arr.capacity, it * will be used by the appender. $(D RefAppender) assumes that arr is a non-null * value. * * Note, do not use builtin appending (i.e. ~=) on the original array passed in * until you are done with the appender, because calls to the appender override * those appends. */ this(T[] *arr) { impl = Appender!A(*arr); this.arr = arr; } auto opDispatch(string fn, Args...)(Args args) if (is(typeof(mixin("impl." ~ fn ~ "(args)")))) { // we do it this way because we can't cache a void return scope(exit) *this.arr = impl.data; mixin("return impl." ~ fn ~ "(args);"); } private alias AppenderType = Appender!A; /** * Appends one item to the managed array. */ void opOpAssign(string op : "~", U)(U item) if (AppenderType.canPutItem!U) { scope(exit) *this.arr = impl.data; impl.put(item); } // Const fixing hack. void opOpAssign(string op : "~", Range)(Range items) if (AppenderType.canPutConstRange!Range) { scope(exit) *this.arr = impl.data; impl.put(items); } /** * Appends an entire range to the managed array. */ void opOpAssign(string op : "~", Range)(Range items) if (AppenderType.canPutRange!Range) { scope(exit) *this.arr = impl.data; impl.put(items); } /** * Returns the capacity of the array (the maximum number of elements the * managed array can accommodate before triggering a reallocation). If any * appending will reallocate, $(D capacity) returns $(D 0). */ @property size_t capacity() const { return impl.capacity; } /** * Returns the managed array. */ @property inout(T)[] data() inout { return impl.data; } } /++ Convenience function that returns an $(D Appender!A) object initialized with $(D array). +/ Appender!A appender(A)() if (isDynamicArray!A) { return Appender!A(null); } /// ditto Appender!(E[]) appender(A : E[], E)(auto ref A array) { static assert (!isStaticArray!A || __traits(isRef, array), "Cannot create Appender from an rvalue static array"); return Appender!(E[])(array); } @safe pure nothrow unittest { import std.exception; { auto app = appender!(char[])(); string b = "abcdefg"; foreach (char c; b) app.put(c); assert(app.data == "abcdefg"); } { auto app = appender!(char[])(); string b = "abcdefg"; foreach (char c; b) app ~= c; assert(app.data == "abcdefg"); } { int[] a = [ 1, 2 ]; auto app2 = appender(a); assert(app2.data == [ 1, 2 ]); app2.put(3); app2.put([ 4, 5, 6 ][]); assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); app2.put([ 7 ]); assert(app2.data == [ 1, 2, 3, 4, 5, 6, 7 ]); } int[] a = [ 1, 2 ]; auto app2 = appender(a); assert(app2.data == [ 1, 2 ]); app2 ~= 3; app2 ~= [ 4, 5, 6 ][]; assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); app2 ~= [ 7 ]; assert(app2.data == [ 1, 2, 3, 4, 5, 6, 7 ]); app2.reserve(5); assert(app2.capacity >= 5); try // shrinkTo may throw { app2.shrinkTo(3); } catch (Exception) assert(0); assert(app2.data == [ 1, 2, 3 ]); assertThrown(app2.shrinkTo(5)); const app3 = app2; assert(app3.capacity >= 3); assert(app3.data == [1, 2, 3]); auto app4 = appender([]); try // shrinkTo may throw { app4.shrinkTo(0); } catch (Exception) assert(0); // Issue 5663 & 9725 tests foreach (S; AliasSeq!(char[], const(char)[], string)) { { Appender!S app5663i; assertNotThrown(app5663i.put("\xE3")); assert(app5663i.data == "\xE3"); Appender!S app5663c; assertNotThrown(app5663c.put(cast(const(char)[])"\xE3")); assert(app5663c.data == "\xE3"); Appender!S app5663m; assertNotThrown(app5663m.put("\xE3".dup)); assert(app5663m.data == "\xE3"); } // ditto for ~= { Appender!S app5663i; assertNotThrown(app5663i ~= "\xE3"); assert(app5663i.data == "\xE3"); Appender!S app5663c; assertNotThrown(app5663c ~= cast(const(char)[])"\xE3"); assert(app5663c.data == "\xE3"); Appender!S app5663m; assertNotThrown(app5663m ~= "\xE3".dup); assert(app5663m.data == "\xE3"); } } static struct S10122 { int val; @disable this(); this(int v) @safe pure nothrow { val = v; } } assertCTFEable!( { auto w = appender!(S10122[])(); w.put(S10122(1)); assert(w.data.length == 1 && w.data[0].val == 1); }); } @safe pure nothrow unittest { { auto w = appender!string(); w.reserve(4); cast(void)w.capacity; cast(void)w.data; try { wchar wc = 'a'; dchar dc = 'a'; w.put(wc); // decoding may throw w.put(dc); // decoding may throw } catch (Exception) assert(0); } { auto w = appender!(int[])(); w.reserve(4); cast(void)w.capacity; cast(void)w.data; w.put(10); w.put([10]); w.clear(); try { w.shrinkTo(0); } catch (Exception) assert(0); struct N { int payload; alias payload this; } w.put(N(1)); w.put([N(2)]); struct S(T) { @property bool empty() { return true; } @property T front() { return T.init; } void popFront() {} } S!int r; w.put(r); } } unittest { import std.typecons; import std.algorithm; //10690 [tuple(1)].filter!(t => true).array; // No error [tuple("A")].filter!(t => true).array; // error } unittest { import std.range; //Coverage for put(Range) struct S1 { } struct S2 { void opAssign(S2){} } auto a1 = Appender!(S1[])(); auto a2 = Appender!(S2[])(); auto au1 = Appender!(const(S1)[])(); auto au2 = Appender!(const(S2)[])(); a1.put(S1().repeat().take(10)); a2.put(S2().repeat().take(10)); auto sc1 = const(S1)(); auto sc2 = const(S2)(); au1.put(sc1.repeat().take(10)); au2.put(sc2.repeat().take(10)); } unittest { struct S { int* p; } auto a0 = Appender!(S[])(); auto a1 = Appender!(const(S)[])(); auto a2 = Appender!(immutable(S)[])(); auto s0 = S(null); auto s1 = const(S)(null); auto s2 = immutable(S)(null); a1.put(s0); a1.put(s1); a1.put(s2); a1.put([s0]); a1.put([s1]); a1.put([s2]); a0.put(s0); static assert(!is(typeof(a0.put(a1)))); static assert(!is(typeof(a0.put(a2)))); a0.put([s0]); static assert(!is(typeof(a0.put([a1])))); static assert(!is(typeof(a0.put([a2])))); static assert(!is(typeof(a2.put(a0)))); static assert(!is(typeof(a2.put(a1)))); a2.put(s2); static assert(!is(typeof(a2.put([a0])))); static assert(!is(typeof(a2.put([a1])))); a2.put([s2]); } unittest { //9528 const(E)[] fastCopy(E)(E[] src) { auto app = appender!(const(E)[])(); foreach (i, e; src) app.put(e); return app.data; } class C {} struct S { const(C) c; } S[] s = [ S(new C) ]; auto t = fastCopy(s); // Does not compile } unittest { import std.algorithm : map; //10753 struct Foo { immutable dchar d; } struct Bar { immutable int x; } "12".map!Foo.array; [1, 2].map!Bar.array; } unittest { //New appender signature tests alias mutARR = int[]; alias conARR = const(int)[]; alias immARR = immutable(int)[]; mutARR mut; conARR con; immARR imm; {auto app = Appender!mutARR(mut);} //Always worked. Should work. Should not create a warning. static assert(!is(typeof(Appender!mutARR(con)))); //Never worked. Should not work. static assert(!is(typeof(Appender!mutARR(imm)))); //Never worked. Should not work. {auto app = Appender!conARR(mut);} //Always worked. Should work. Should not create a warning. {auto app = Appender!conARR(con);} //Didn't work. Now works. Should not create a warning. {auto app = Appender!conARR(imm);} //Didn't work. Now works. Should not create a warning. //{auto app = Appender!immARR(mut);} //Worked. Will cease to work. Creates warning. //static assert(!is(typeof(Appender!immARR(mut)))); //Worked. Will cease to work. Uncomment me after full deprecation. static assert(!is(typeof(Appender!immARR(con)))); //Never worked. Should not work. {auto app = Appender!immARR(imm);} //Didn't work. Now works. Should not create a warning. //Deprecated. Please uncomment and make sure this doesn't work: //char[] cc; //static assert(!is(typeof(Appender!string(cc)))); //This should always work: {auto app = appender!string(null);} {auto app = appender!(const(char)[])(null);} {auto app = appender!(char[])(null);} } unittest //Test large allocations (for GC.extend) { import std.range; import std.algorithm : equal; Appender!(char[]) app; app.reserve(1); //cover reserve on non-initialized foreach(_; 0 .. 100_000) app.put('a'); assert(equal(app.data, 'a'.repeat(100_000))); } unittest { auto reference = new ubyte[](2048 + 1); //a number big enough to have a full page (EG: the GC extends) auto arr = reference.dup; auto app = appender(arr[0 .. 0]); app.reserve(1); //This should not trigger a call to extend app.put(ubyte(1)); //Don't clobber arr assert(reference[] == arr[]); } unittest // clear method is supported only for mutable element types { Appender!string app; static assert(!__traits(compiles, app.clear())); } unittest { static struct D//dynamic { int[] i; alias i this; } static struct S//static { int[5] i; alias i this; } static assert(!is(Appender!(char[5]))); static assert(!is(Appender!D)); static assert(!is(Appender!S)); enum int[5] a = []; int[5] b; D d; S s; int[5] foo(){return a;} static assert(!is(typeof(appender(a)))); static assert( is(typeof(appender(b)))); static assert( is(typeof(appender(d)))); static assert( is(typeof(appender(s)))); static assert(!is(typeof(appender(foo())))); } unittest { // Issue 13077 static class A {} // reduced case auto w = appender!(shared(A)[])(); w.put(new shared A()); // original case import std.range; InputRange!(shared A) foo() { return [new shared A].inputRangeObject; } auto res = foo.array; } /++ Convenience function that returns a $(D RefAppender!A) object initialized with $(D array). Don't use null for the $(D array) pointer, use the other version of $(D appender) instead. +/ RefAppender!(E[]) appender(A : E[]*, E)(A array) { return RefAppender!(E[])(array); } unittest { import std.exception; { auto arr = new char[0]; auto app = appender(&arr); string b = "abcdefg"; foreach (char c; b) app.put(c); assert(app.data == "abcdefg"); assert(arr == "abcdefg"); } { auto arr = new char[0]; auto app = appender(&arr); string b = "abcdefg"; foreach (char c; b) app ~= c; assert(app.data == "abcdefg"); assert(arr == "abcdefg"); } { int[] a = [ 1, 2 ]; auto app2 = appender(&a); assert(app2.data == [ 1, 2 ]); assert(a == [ 1, 2 ]); app2.put(3); app2.put([ 4, 5, 6 ][]); assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); assert(a == [ 1, 2, 3, 4, 5, 6 ]); } int[] a = [ 1, 2 ]; auto app2 = appender(&a); assert(app2.data == [ 1, 2 ]); assert(a == [ 1, 2 ]); app2 ~= 3; app2 ~= [ 4, 5, 6 ][]; assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); assert(a == [ 1, 2, 3, 4, 5, 6 ]); app2.reserve(5); assert(app2.capacity >= 5); try // shrinkTo may throw { app2.shrinkTo(3); } catch (Exception) assert(0); assert(app2.data == [ 1, 2, 3 ]); assertThrown(app2.shrinkTo(5)); const app3 = app2; assert(app3.capacity >= 3); assert(app3.data == [1, 2, 3]); } unittest // issue 14605 { static assert(isOutputRange!(Appender!(int[]), int)); static assert(isOutputRange!(RefAppender!(int[]), int)); } unittest { Appender!(int[]) app; short[] range = [1, 2, 3]; app.put(range); assert(app.data == [1, 2, 3]); } unittest { string s = "hello".idup; char[] a = "hello".dup; auto appS = appender(s); auto appA = appender(a); put(appS, 'w'); put(appA, 'w'); s ~= 'a'; //Clobbers here? a ~= 'a'; //Clobbers here? assert(appS.data == "hellow"); assert(appA.data == "hellow"); } ldc-1.1.0-beta3-src/runtime/phobos/std/variant.d0000664000175000017500000022260012776215007017521 0ustar kaikai// Written in the D programming language. /** This module implements a $(WEB erdani.org/publications/cuj-04-2002.html,discriminated union) type (a.k.a. $(WEB en.wikipedia.org/wiki/Tagged_union,tagged union), $(WEB en.wikipedia.org/wiki/Algebraic_data_type,algebraic type)). Such types are useful for type-uniform binary interfaces, interfacing with scripting languages, and comfortable exploratory programming. Macros: WIKI = Phobos/StdVariant Synopsis: ---- Variant a; // Must assign before use, otherwise exception ensues // Initialize with an integer; make the type int Variant b = 42; assert(b.type == typeid(int)); // Peek at the value assert(b.peek!(int) !is null && *b.peek!(int) == 42); // Automatically convert per language rules auto x = b.get!(real); // Assign any other type, including other variants a = b; a = 3.14; assert(a.type == typeid(double)); // Implicit conversions work just as with built-in types assert(a < b); // Check for convertibility assert(!a.convertsTo!(int)); // double not convertible to int // Strings and all other arrays are supported a = "now I'm a string"; assert(a == "now I'm a string"); a = new int[42]; // can also assign arrays assert(a.length == 42); a[5] = 7; assert(a[5] == 7); // Can also assign class values class Foo {} auto foo = new Foo; a = foo; assert(*a.peek!(Foo) == foo); // and full type information is preserved ---- A $(LREF Variant) object can hold a value of any type, with very few restrictions (such as `shared` types and noncopyable types). Setting the value is as immediate as assigning to the `Variant` object. To read back the value of the appropriate type `T`, use the $(LREF get!T) call. To query whether a `Variant` currently holds a value of type `T`, use $(LREF peek!T). To fetch the exact type currently held, call $(LREF type), which returns the `TypeInfo` of the current value. In addition to $(LREF Variant), this module also defines the $(LREF Algebraic) type constructor. Unlike `Variant`, `Algebraic` only allows a finite set of types, which are specified in the instantiation (e.g. $(D Algebraic!(int, string)) may only hold an `int` or a `string`). Credits: Reviewed by Brad Roberts. Daniel Keep provided a detailed code review prompting the following improvements: (1) better support for arrays; (2) support for associative arrays; (3) friendlier behavior towards the garbage collector. Copyright: Copyright Andrei Alexandrescu 2007 - 2015. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.org, Andrei Alexandrescu) Source: $(PHOBOSSRC std/_variant.d) */ module std.variant; import core.stdc.string, std.conv, std.exception, std.meta, std.traits, std.typecons; /++ Gives the $(D sizeof) the largest type given. +/ template maxSize(T...) { static if (T.length == 1) { enum size_t maxSize = T[0].sizeof; } else { import std.algorithm.comparison : max; enum size_t maxSize = max(T[0].sizeof, maxSize!(T[1 .. $])); } } struct This; private alias This2Variant(V, T...) = AliasSeq!(ReplaceType!(This, V, T)); /** * $(D VariantN) is a back-end type seldom used directly by user * code. Two commonly-used types using $(D VariantN) as * back-end are: * * $(OL $(LI $(B Algebraic): A closed discriminated union with a * limited type universe (e.g., $(D Algebraic!(int, double, * string)) only accepts these three types and rejects anything * else).) $(LI $(B Variant): An open discriminated union allowing an * unbounded set of types. If any of the types in the $(D Variant) * are larger than the largest built-in type, they will automatically * be boxed. This means that even large types will only be the size * of a pointer within the $(D Variant), but this also implies some * overhead. $(D Variant) can accommodate all primitive types and * all user-defined types.)) * * Both $(D Algebraic) and $(D Variant) share $(D * VariantN)'s interface. (See their respective documentations below.) * * $(D VariantN) is a discriminated union type parameterized * with the largest size of the types stored ($(D maxDataSize)) * and with the list of allowed types ($(D AllowedTypes)). If * the list is empty, then any type up of size up to $(D * maxDataSize) (rounded up for alignment) can be stored in a * $(D VariantN) object without being boxed (types larger * than this will be boxed). * */ struct VariantN(size_t maxDataSize, AllowedTypesParam...) { /** The list of allowed types. If empty, any type is allowed. */ alias AllowedTypes = This2Variant!(VariantN, AllowedTypesParam); private: // Compute the largest practical size from maxDataSize struct SizeChecker { int function() fptr; ubyte[maxDataSize] data; } enum size = SizeChecker.sizeof - (int function()).sizeof; /** Tells whether a type $(D T) is statically allowed for * storage inside a $(D VariantN) object by looking * $(D T) up in $(D AllowedTypes). */ public template allowed(T) { enum bool allowed = is(T == VariantN) || //T.sizeof <= size && (AllowedTypes.length == 0 || staticIndexOf!(T, AllowedTypes) >= 0); } // Each internal operation is encoded with an identifier. See // the "handler" function below. enum OpID { getTypeInfo, get, compare, equals, testConversion, toString, index, indexAssign, catAssign, copyOut, length, apply, postblit, destruct } // state ptrdiff_t function(OpID selector, ubyte[size]* store, void* data) fptr = &handler!(void); union { ubyte[size] store; // conservatively mark the region as pointers static if (size >= (void*).sizeof) void*[size / (void*).sizeof] p; } // internals // Handler for an uninitialized value static ptrdiff_t handler(A : void)(OpID selector, ubyte[size]*, void* parm) { switch (selector) { case OpID.getTypeInfo: *cast(TypeInfo *) parm = typeid(A); break; case OpID.copyOut: auto target = cast(VariantN *) parm; target.fptr = &handler!(A); // no need to copy the data (it's garbage) break; case OpID.compare: case OpID.equals: auto rhs = cast(const VariantN *) parm; return rhs.peek!(A) ? 0 // all uninitialized are equal : ptrdiff_t.min; // uninitialized variant is not comparable otherwise case OpID.toString: string * target = cast(string*) parm; *target = ""; break; case OpID.postblit: case OpID.destruct: break; case OpID.get: case OpID.testConversion: case OpID.index: case OpID.indexAssign: case OpID.catAssign: case OpID.length: throw new VariantException( "Attempt to use an uninitialized VariantN"); default: assert(false, "Invalid OpID"); } return 0; } // Handler for all of a type's operations static ptrdiff_t handler(A)(OpID selector, ubyte[size]* pStore, void* parm) { static A* getPtr(void* untyped) { if (untyped) { static if (A.sizeof <= size) return cast(A*) untyped; else return *cast(A**) untyped; } return null; } static ptrdiff_t compare(A* rhsPA, A* zis, OpID selector) { static if (is(typeof(*rhsPA == *zis))) { if (*rhsPA == *zis) { return 0; } static if (is(typeof(*zis < *rhsPA))) { // Many types (such as any using the default Object opCmp) // will throw on an invalid opCmp, so do it only // if the caller requests it. if (selector == OpID.compare) return *zis < *rhsPA ? -1 : 1; else return ptrdiff_t.min; } else { // Not equal, and type does not support ordering // comparisons. return ptrdiff_t.min; } } else { // Type does not support comparisons at all. return ptrdiff_t.min; } } auto zis = getPtr(pStore); // Input: TypeInfo object // Output: target points to a copy of *me, if me was not null // Returns: true iff the A can be converted to the type represented // by the incoming TypeInfo static bool tryPutting(A* src, TypeInfo targetType, void* target) { alias UA = Unqual!A; alias MutaTypes = AliasSeq!(UA, ImplicitConversionTargets!UA); alias ConstTypes = staticMap!(ConstOf, MutaTypes); alias SharedTypes = staticMap!(SharedOf, MutaTypes); alias SharedConstTypes = staticMap!(SharedConstOf, MutaTypes); alias ImmuTypes = staticMap!(ImmutableOf, MutaTypes); static if (is(A == immutable)) alias AllTypes = AliasSeq!(ImmuTypes, ConstTypes, SharedConstTypes); else static if (is(A == shared)) { static if (is(A == const)) alias AllTypes = SharedConstTypes; else alias AllTypes = AliasSeq!(SharedTypes, SharedConstTypes); } else { static if (is(A == const)) alias AllTypes = ConstTypes; else alias AllTypes = AliasSeq!(MutaTypes, ConstTypes); } foreach (T ; AllTypes) { if (targetType != typeid(T)) { continue; } static if (is(typeof(*cast(T*) target = *src))) { auto zat = cast(T*) target; if (src) { static if (T.sizeof > 0) assert(target, "target must be non-null"); *zat = *src; } } else static if (is(T == const(U), U) || is(T == shared(U), U) || is(T == shared const(U), U) || is(T == immutable(U), U)) { auto zat = cast(U*) target; if (src) { static if (U.sizeof > 0) assert(target, "target must be non-null"); *zat = *(cast(UA*) (src)); } } else { // type is not assignable if (src) assert(false, A.stringof); } return true; } return false; } switch (selector) { case OpID.getTypeInfo: *cast(TypeInfo *) parm = typeid(A); break; case OpID.copyOut: auto target = cast(VariantN *) parm; assert(target); static if (target.size < A.sizeof) { if (target.type.tsize < A.sizeof) *cast(A**)&target.store = new A; } tryPutting(zis, typeid(A), cast(void*) getPtr(&target.store)) || assert(false); target.fptr = &handler!(A); break; case OpID.get: auto t = * cast(Tuple!(TypeInfo, void*)*) parm; return !tryPutting(zis, t[0], t[1]); case OpID.testConversion: return !tryPutting(null, *cast(TypeInfo*) parm, null); case OpID.compare: case OpID.equals: auto rhsP = cast(VariantN *) parm; auto rhsType = rhsP.type; // Are we the same? if (rhsType == typeid(A)) { // cool! Same type! auto rhsPA = getPtr(&rhsP.store); return compare(rhsPA, zis, selector); } else if (rhsType == typeid(void)) { // No support for ordering comparisons with // uninitialized vars return ptrdiff_t.min; } VariantN temp; // Do I convert to rhs? if (tryPutting(zis, rhsType, &temp.store)) { // cool, I do; temp's store contains my data in rhs's type! // also fix up its fptr temp.fptr = rhsP.fptr; // now lhsWithRhsType is a full-blown VariantN of rhs's type if (selector == OpID.compare) return temp.opCmp(*rhsP); else return temp.opEquals(*rhsP) ? 0 : 1; } // Does rhs convert to zis? auto t = tuple(typeid(A), &temp.store); if (rhsP.fptr(OpID.get, &rhsP.store, &t) == 0) { // cool! Now temp has rhs in my type! auto rhsPA = getPtr(&temp.store); return compare(rhsPA, zis, selector); } return ptrdiff_t.min; // dunno case OpID.toString: auto target = cast(string*) parm; static if (is(typeof(to!(string)(*zis)))) { *target = to!(string)(*zis); break; } // TODO: The following test evaluates to true for shared objects. // Use __traits for now until this is sorted out. // else static if (is(typeof((*zis).toString))) else static if (__traits(compiles, {(*zis).toString();})) { *target = (*zis).toString(); break; } else { throw new VariantException(typeid(A), typeid(string)); } case OpID.index: auto result = cast(Variant*) parm; static if (isArray!(A) && !is(Unqual!(typeof(A.init[0])) == void)) { // array type; input and output are the same VariantN size_t index = result.convertsTo!(int) ? result.get!(int) : result.get!(size_t); *result = (*zis)[index]; break; } else static if (isAssociativeArray!(A)) { *result = (*zis)[result.get!(typeof(A.init.keys[0]))]; break; } else { throw new VariantException(typeid(A), result[0].type); } case OpID.indexAssign: // array type; result comes first, index comes second auto args = cast(Variant*) parm; static if (isArray!(A) && is(typeof((*zis)[0] = (*zis)[0]))) { size_t index = args[1].convertsTo!(int) ? args[1].get!(int) : args[1].get!(size_t); (*zis)[index] = args[0].get!(typeof((*zis)[0])); break; } else static if (isAssociativeArray!(A)) { (*zis)[args[1].get!(typeof(A.init.keys[0]))] = args[0].get!(typeof(A.init.values[0])); break; } else { throw new VariantException(typeid(A), args[0].type); } case OpID.catAssign: static if (!is(Unqual!(typeof((*zis)[0])) == void) && is(typeof((*zis)[0])) && is(typeof((*zis) ~= *zis))) { // array type; parm is the element to append auto arg = cast(Variant*) parm; alias E = typeof((*zis)[0]); if (arg[0].convertsTo!(E)) { // append one element to the array (*zis) ~= [ arg[0].get!(E) ]; } else { // append a whole array to the array (*zis) ~= arg[0].get!(A); } break; } else { throw new VariantException(typeid(A), typeid(void[])); } case OpID.length: static if (isArray!(A) || isAssociativeArray!(A)) { return zis.length; } else { throw new VariantException(typeid(A), typeid(void[])); } case OpID.apply: static if (!isFunctionPointer!A && !isDelegate!A) { enforce(0, text("Cannot apply `()' to a value of type `", A.stringof, "'.")); } else { alias ParamTypes = Parameters!A; auto p = cast(Variant*) parm; auto argCount = p.get!size_t; // To assign the tuple we need to use the unqualified version, // otherwise we run into issues such as with const values. // We still get the actual type from the Variant though // to ensure that we retain const correctness. Tuple!(staticMap!(Unqual, ParamTypes)) t; enforce(t.length == argCount, text("Argument count mismatch: ", A.stringof, " expects ", t.length, " argument(s), not ", argCount, ".")); auto variantArgs = p[1 .. argCount + 1]; foreach (i, T; ParamTypes) { t[i] = cast()variantArgs[i].get!T; } auto args = cast(Tuple!(ParamTypes))t; static if(is(ReturnType!A == void)) { (*zis)(args.expand); *p = Variant.init; // void returns uninitialized Variant. } else { *p = (*zis)(args.expand); } } break; case OpID.postblit: static if (hasElaborateCopyConstructor!A) { typeid(A).postblit(zis); } break; case OpID.destruct: static if (hasElaborateDestructor!A) { typeid(A).destroy(zis); } break; default: assert(false); } return 0; } public: /** Constructs a $(D VariantN) value given an argument of a * generic type. Statically rejects disallowed types. */ this(T)(T value) { static assert(allowed!(T), "Cannot store a " ~ T.stringof ~ " in a " ~ VariantN.stringof); opAssign(value); } /// Allows assignment from a subset algebraic type this(T : VariantN!(tsize, Types), size_t tsize, Types...)(T value) if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types)) { opAssign(value); } static if (!AllowedTypes.length || anySatisfy!(hasElaborateCopyConstructor, AllowedTypes)) { this(this) { fptr(OpID.postblit, &store, null); } } static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes)) { ~this() { fptr(OpID.destruct, &store, null); } } /** Assigns a $(D VariantN) from a generic * argument. Statically rejects disallowed types. */ VariantN opAssign(T)(T rhs) { //writeln(typeid(rhs)); static assert(allowed!(T), "Cannot store a " ~ T.stringof ~ " in a " ~ VariantN.stringof ~ ". Valid types are " ~ AllowedTypes.stringof); static if (is(T : VariantN)) { rhs.fptr(OpID.copyOut, &rhs.store, &this); } else static if (is(T : const(VariantN))) { static assert(false, "Assigning Variant objects from const Variant"~ " objects is currently not supported."); } else { static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes)) { // Assignment should destruct previous value fptr(OpID.destruct, &store, null); } static if (T.sizeof <= size) { // If T is a class we're only copying the reference, so it // should be safe to cast away shared so the memcpy will work. // // TODO: If a shared class has an atomic reference then using // an atomic load may be more correct. Just make sure // to use the fastest approach for the load op. static if (is(T == class) && is(T == shared)) memcpy(&store, cast(const(void*)) &rhs, rhs.sizeof); else memcpy(&store, &rhs, rhs.sizeof); static if (hasElaborateCopyConstructor!T) { typeid(T).postblit(&store); } } else { static if (__traits(compiles, {new T(rhs);})) { auto p = new T(rhs); } else { auto p = new T; *p = rhs; } memcpy(&store, &p, p.sizeof); } fptr = &handler!(T); } return this; } // Allow assignment from another variant which is a subset of this one VariantN opAssign(T : VariantN!(tsize, Types), size_t tsize, Types...)(T rhs) if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types)) { // discover which type rhs is actually storing foreach (V; T.AllowedTypes) if (rhs.type == typeid(V)) return this = rhs.get!V; assert(0, T.AllowedTypes.stringof); } Variant opCall(P...)(auto ref P params) { Variant[P.length + 1] pack; pack[0] = P.length; foreach (i, _; params) { pack[i + 1] = params[i]; } fptr(OpID.apply, &store, &pack); return pack[0]; } /** Returns true if and only if the $(D VariantN) object * holds a valid value (has been initialized with, or assigned * from, a valid value). */ @property bool hasValue() const pure nothrow { // @@@BUG@@@ in compiler, the cast shouldn't be needed return cast(typeof(&handler!(void))) fptr != &handler!(void); } /// unittest { Variant a; assert(!a.hasValue); Variant b; a = b; assert(!a.hasValue); // still no value a = 5; assert(a.hasValue); } /** * If the $(D VariantN) object holds a value of the * $(I exact) type $(D T), returns a pointer to that * value. Otherwise, returns $(D null). In cases * where $(D T) is statically disallowed, $(D * peek) will not compile. */ @property inout(T)* peek(T)() inout { static if (!is(T == void)) static assert(allowed!(T), "Cannot store a " ~ T.stringof ~ " in a " ~ VariantN.stringof); if (type != typeid(T)) return null; static if (T.sizeof <= size) return cast(inout T*)&store; else return *cast(inout T**)&store; } /// unittest { Variant a = 5; auto b = a.peek!(int); assert(b !is null); *b = 6; assert(a == 6); } /** * Returns the $(D typeid) of the currently held value. */ @property TypeInfo type() const nothrow @trusted { scope(failure) assert(0); TypeInfo result; fptr(OpID.getTypeInfo, null, &result); return result; } /** * Returns $(D true) if and only if the $(D VariantN) * object holds an object implicitly convertible to type $(D * U). Implicit convertibility is defined as per * $(LINK2 std_traits.html#ImplicitConversionTargets,ImplicitConversionTargets). */ @property bool convertsTo(T)() const { TypeInfo info = typeid(T); return fptr(OpID.testConversion, null, &info) == 0; } /** Returns the value stored in the `VariantN` object, either by specifying the needed type or the index in the list of allowed types. The latter overload only applies to bounded variants (e.g. $(LREF Algebraic)). Params: T = The requested type. The currently stored value must implicitly convert to the requested type, in fact `DecayStaticToDynamicArray!T`. If an implicit conversion is not possible, throws a `VariantException`. index = The index of the type among `AllowedTypesParam`, zero-based. */ @property inout(T) get(T)() inout { static if (is(T == shared)) shared Unqual!T result; else Unqual!T result; auto buf = tuple(typeid(T), &result); if (fptr(OpID.get, cast(ubyte[size]*) &store, &buf)) { throw new VariantException(type, typeid(T)); } return * cast(inout T*) &result; } /// Ditto @property auto get(uint index)() inout if (index < AllowedTypes.length) { foreach (i, T; AllowedTypes) { static if (index == i) return get!T; } assert(0); } /** * Returns the value stored in the $(D VariantN) object, * explicitly converted (coerced) to the requested type $(D * T). If $(D T) is a string type, the value is formatted as * a string. If the $(D VariantN) object is a string, a * parse of the string to type $(D T) is attempted. If a * conversion is not possible, throws a $(D * VariantException). */ @property T coerce(T)() { static if (isNumeric!T || isBoolean!T) { if (convertsTo!real) { // maybe optimize this fella; handle ints separately return to!T(get!real); } else if (convertsTo!(const(char)[])) { return to!T(get!(const(char)[])); } // I'm not sure why this doesn't convert to const(char), // but apparently it doesn't (probably a deeper bug). // // Until that is fixed, this quick addition keeps a common // function working. "10".coerce!int ought to work. else if (convertsTo!(immutable(char)[])) { return to!T(get!(immutable(char)[])); } else { enforce(false, text("Type ", type, " does not convert to ", typeid(T))); assert(0); } } else static if (is(T : Object)) { return to!(T)(get!(Object)); } else static if (isSomeString!(T)) { return to!(T)(toString()); } else { // Fix for bug 1649 static assert(false, "unsupported type for coercion"); } } /** * Formats the stored value as a string. */ string toString() { string result; fptr(OpID.toString, &store, &result) == 0 || assert(false); return result; } /** * Comparison for equality used by the "==" and "!=" operators. */ // returns 1 if the two are equal bool opEquals(T)(auto ref T rhs) const { static if (is(Unqual!T == VariantN)) alias temp = rhs; else auto temp = VariantN(rhs); return !fptr(OpID.equals, cast(ubyte[size]*) &store, cast(void*) &temp); } // workaround for bug 10567 fix int opCmp(ref const VariantN rhs) const { return (cast()this).opCmp!(VariantN)(cast()rhs); } /** * Ordering comparison used by the "<", "<=", ">", and ">=" * operators. In case comparison is not sensible between the held * value and $(D rhs), an exception is thrown. */ int opCmp(T)(T rhs) { static if (is(T == VariantN)) alias temp = rhs; else auto temp = VariantN(rhs); auto result = fptr(OpID.compare, &store, &temp); if (result == ptrdiff_t.min) { throw new VariantException(type, temp.type); } assert(result >= -1 && result <= 1); // Should be true for opCmp. return cast(int) result; } /** * Computes the hash of the held value. */ size_t toHash() const nothrow @safe { return type.getHash(&store); } private VariantN opArithmetic(T, string op)(T other) { static if (isInstanceOf!(.VariantN, T)) { string tryUseType(string tp) { import std.format : format; return q{ static if (allowed!%1$s && T.allowed!%1$s) if (convertsTo!%1$s && other.convertsTo!%1$s) return VariantN(get!%1$s %2$s other.get!%1$s); }.format(tp, op); } mixin(tryUseType("uint")); mixin(tryUseType("int")); mixin(tryUseType("ulong")); mixin(tryUseType("long")); mixin(tryUseType("float")); mixin(tryUseType("double")); mixin(tryUseType("real")); } else { static if (allowed!T) if (auto pv = peek!T) return VariantN(mixin("*pv " ~ op ~ " other")); static if (allowed!uint && is(typeof(T.max) : uint) && isUnsigned!T) if (convertsTo!uint) return VariantN(mixin("get!(uint) " ~ op ~ " other")); static if (allowed!int && is(typeof(T.max) : int) && !isUnsigned!T) if (convertsTo!int) return VariantN(mixin("get!(int) " ~ op ~ " other")); static if (allowed!ulong && is(typeof(T.max) : ulong) && isUnsigned!T) if (convertsTo!ulong) return VariantN(mixin("get!(ulong) " ~ op ~ " other")); static if (allowed!long && is(typeof(T.max) : long) && !isUnsigned!T) if (convertsTo!long) return VariantN(mixin("get!(long) " ~ op ~ " other")); static if (allowed!float && is(T : float)) if (convertsTo!float) return VariantN(mixin("get!(float) " ~ op ~ " other")); static if (allowed!double && is(T : double)) if (convertsTo!double) return VariantN(mixin("get!(double) " ~ op ~ " other")); static if (allowed!real && is (T : real)) if (convertsTo!real) return VariantN(mixin("get!(real) " ~ op ~ " other")); } throw new VariantException("No possible match found for VariantN "~op~" "~T.stringof); } private VariantN opLogic(T, string op)(T other) { VariantN result; static if (is(T == VariantN)) { if (convertsTo!(uint) && other.convertsTo!(uint)) result = mixin("get!(uint) " ~ op ~ " other.get!(uint)"); else if (convertsTo!(int) && other.convertsTo!(int)) result = mixin("get!(int) " ~ op ~ " other.get!(int)"); else if (convertsTo!(ulong) && other.convertsTo!(ulong)) result = mixin("get!(ulong) " ~ op ~ " other.get!(ulong)"); else result = mixin("get!(long) " ~ op ~ " other.get!(long)"); } else { if (is(typeof(T.max) : uint) && T.min == 0 && convertsTo!(uint)) result = mixin("get!(uint) " ~ op ~ " other"); else if (is(typeof(T.max) : int) && T.min < 0 && convertsTo!(int)) result = mixin("get!(int) " ~ op ~ " other"); else if (is(typeof(T.max) : ulong) && T.min == 0 && convertsTo!(ulong)) result = mixin("get!(ulong) " ~ op ~ " other"); else result = mixin("get!(long) " ~ op ~ " other"); } return result; } /** * Arithmetic between $(D VariantN) objects and numeric * values. All arithmetic operations return a $(D VariantN) * object typed depending on the types of both values * involved. The conversion rules mimic D's built-in rules for * arithmetic conversions. */ // Adapted from http://www.prowiki.org/wiki4d/wiki.cgi?DanielKeep/Variant // arithmetic VariantN opAdd(T)(T rhs) { return opArithmetic!(T, "+")(rhs); } ///ditto VariantN opSub(T)(T rhs) { return opArithmetic!(T, "-")(rhs); } // Commenteed all _r versions for now because of ambiguities // arising when two Variants are used // ///ditto // VariantN opSub_r(T)(T lhs) // { // return VariantN(lhs).opArithmetic!(VariantN, "-")(this); // } ///ditto VariantN opMul(T)(T rhs) { return opArithmetic!(T, "*")(rhs); } ///ditto VariantN opDiv(T)(T rhs) { return opArithmetic!(T, "/")(rhs); } // ///ditto // VariantN opDiv_r(T)(T lhs) // { // return VariantN(lhs).opArithmetic!(VariantN, "/")(this); // } ///ditto VariantN opMod(T)(T rhs) { return opArithmetic!(T, "%")(rhs); } // ///ditto // VariantN opMod_r(T)(T lhs) // { // return VariantN(lhs).opArithmetic!(VariantN, "%")(this); // } ///ditto VariantN opAnd(T)(T rhs) { return opLogic!(T, "&")(rhs); } ///ditto VariantN opOr(T)(T rhs) { return opLogic!(T, "|")(rhs); } ///ditto VariantN opXor(T)(T rhs) { return opLogic!(T, "^")(rhs); } ///ditto VariantN opShl(T)(T rhs) { return opLogic!(T, "<<")(rhs); } // ///ditto // VariantN opShl_r(T)(T lhs) // { // return VariantN(lhs).opLogic!(VariantN, "<<")(this); // } ///ditto VariantN opShr(T)(T rhs) { return opLogic!(T, ">>")(rhs); } // ///ditto // VariantN opShr_r(T)(T lhs) // { // return VariantN(lhs).opLogic!(VariantN, ">>")(this); // } ///ditto VariantN opUShr(T)(T rhs) { return opLogic!(T, ">>>")(rhs); } // ///ditto // VariantN opUShr_r(T)(T lhs) // { // return VariantN(lhs).opLogic!(VariantN, ">>>")(this); // } ///ditto VariantN opCat(T)(T rhs) { auto temp = this; temp ~= rhs; return temp; } // ///ditto // VariantN opCat_r(T)(T rhs) // { // VariantN temp = rhs; // temp ~= this; // return temp; // } ///ditto VariantN opAddAssign(T)(T rhs) { return this = this + rhs; } ///ditto VariantN opSubAssign(T)(T rhs) { return this = this - rhs; } ///ditto VariantN opMulAssign(T)(T rhs) { return this = this * rhs; } ///ditto VariantN opDivAssign(T)(T rhs) { return this = this / rhs; } ///ditto VariantN opModAssign(T)(T rhs) { return this = this % rhs; } ///ditto VariantN opAndAssign(T)(T rhs) { return this = this & rhs; } ///ditto VariantN opOrAssign(T)(T rhs) { return this = this | rhs; } ///ditto VariantN opXorAssign(T)(T rhs) { return this = this ^ rhs; } ///ditto VariantN opShlAssign(T)(T rhs) { return this = this << rhs; } ///ditto VariantN opShrAssign(T)(T rhs) { return this = this >> rhs; } ///ditto VariantN opUShrAssign(T)(T rhs) { return this = this >>> rhs; } ///ditto VariantN opCatAssign(T)(T rhs) { auto toAppend = Variant(rhs); fptr(OpID.catAssign, &store, &toAppend) == 0 || assert(false); return this; } /** * Array and associative array operations. If a $(D * VariantN) contains an (associative) array, it can be indexed * into. Otherwise, an exception is thrown. */ Variant opIndex(K)(K i) { auto result = Variant(i); fptr(OpID.index, &store, &result) == 0 || assert(false); return result; } /// unittest { auto a = Variant(new int[10]); a[5] = 42; assert(a[5] == 42); int[int] hash = [ 42:24 ]; a = hash; assert(a[42] == 24); } /** Caveat: Due to limitations in current language, read-modify-write operations $(D op=) will not work properly: */ unittest { Variant a = new int[10]; a[5] = 42; a[5] += 8; //assert(a[5] == 50); // will fail, a[5] is still 42 } unittest { int[int] hash = [ 42:24 ]; Variant v = hash; assert(v[42] == 24); v[42] = 5; assert(v[42] == 5); } /// ditto Variant opIndexAssign(T, N)(T value, N i) { Variant[2] args = [ Variant(value), Variant(i) ]; fptr(OpID.indexAssign, &store, &args) == 0 || assert(false); return args[0]; } /** If the $(D VariantN) contains an (associative) array, * returns the length of that array. Otherwise, throws an * exception. */ @property size_t length() { return cast(size_t) fptr(OpID.length, &store, null); } /** If the $(D VariantN) contains an array, applies $(D dg) to each element of the array in turn. Otherwise, throws an exception. */ int opApply(Delegate)(scope Delegate dg) if (is(Delegate == delegate)) { alias A = Parameters!(Delegate)[0]; if (type == typeid(A[])) { auto arr = get!(A[]); foreach (ref e; arr) { if (dg(e)) return 1; } } else static if (is(A == VariantN)) { foreach (i; 0 .. length) { // @@@TODO@@@: find a better way to not confuse // clients who think they change values stored in the // Variant when in fact they are only changing tmp. auto tmp = this[i]; debug scope(exit) assert(tmp == this[i]); if (dg(tmp)) return 1; } } else { enforce(false, text("Variant type ", type, " not iterable with values of type ", A.stringof)); } return 0; } } unittest { Variant v; int foo() { return 42; } v = &foo; assert(v() == 42); static int bar(string s) { return to!int(s); } v = &bar; assert(v("43") == 43); } // opIndex with static arrays, issue 12771 unittest { int[4] elements = [0, 1, 2, 3]; Variant v = elements; assert(v == elements); assert(v[2] == 2); assert(v[3] == 3); v[2] = 6; assert(v[2] == 6); assert(v != elements); } //Issue# 8195 unittest { struct S { int a; long b; string c; real d = 0.0; bool e; } static assert(S.sizeof >= Variant.sizeof); alias Types = AliasSeq!(string, int, S); alias MyVariant = VariantN!(maxSize!Types, Types); auto v = MyVariant(S.init); assert(v == S.init); } // Issue #10961 unittest { // Primarily test that we can assign a void[] to a Variant. void[] elements = cast(void[])[1, 2, 3]; Variant v = elements; void[] returned = v.get!(void[]); assert(returned == elements); } // Issue #13352 unittest { alias TP = Algebraic!(long); auto a = TP(1L); auto b = TP(2L); assert(!TP.allowed!ulong); assert(a + b == 3L); assert(a + 2 == 3L); assert(1 + b == 3L); alias TP2 = Algebraic!(long, string); auto c = TP2(3L); assert(a + c == 4L); } // Issue #13354 unittest { alias A = Algebraic!(string[]); A a = ["a", "b"]; assert(a[0] == "a"); assert(a[1] == "b"); a[1] = "c"; assert(a[1] == "c"); alias AA = Algebraic!(int[string]); AA aa = ["a": 1, "b": 2]; assert(aa["a"] == 1); assert(aa["b"] == 2); aa["b"] = 3; assert(aa["b"] == 3); } // Issue #14198 unittest { Variant a = true; assert(a.type == typeid(bool)); } // Issue #14233 unittest { alias Atom = Algebraic!(string, This[]); Atom[] values = []; auto a = Atom(values); } pure nothrow @nogc unittest { Algebraic!(int, double) a; a = 100; a = 1.0; } // Issue 14457 unittest { alias A = Algebraic!(int, float, double); alias B = Algebraic!(int, float); A a = 1; B b = 6f; a = b; assert(a.type == typeid(float)); assert(a.get!float == 6f); } // Issue 14585 unittest { static struct S { int x = 42; ~this() {assert(x == 42);} } Variant(S()).get!S; } // Issue 14586 unittest { const Variant v = new immutable Object; v.get!(immutable Object); } unittest { static struct S { T opCast(T)() {assert(false);} } Variant v = S(); v.get!S; } /** Algebraic data type restricted to a closed set of possible types. It's an alias for a $(LREF VariantN) with an appropriately-constructed maximum size. `Algebraic` is useful when it is desirable to restrict what a discriminated type could hold to the end of defining simpler and more efficient manipulation. */ template Algebraic(T...) { alias Algebraic = VariantN!(maxSize!T, T); } /// unittest { auto v = Algebraic!(int, double, string)(5); assert(v.peek!(int)); v = 3.14; assert(v.peek!(double)); // auto x = v.peek!(long); // won't compile, type long not allowed // v = '1'; // won't compile, type char not allowed } /** $(H4 Self-Referential Types) A useful and popular use of algebraic data structures is for defining $(LUCKY self-referential data structures), i.e. structures that embed references to values of their own type within. This is achieved with `Algebraic` by using `This` as a placeholder whenever a reference to the type being defined is needed. The `Algebraic` instantiation will perform $(LUCKY alpha renaming) on its constituent types, replacing `This` with the self-referenced type. The structure of the type involving `This` may be arbitrarily complex. */ unittest { // A tree is either a leaf or a branch of two other trees alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*)); Tree!int tree = tuple(new Tree!int(42), new Tree!int(43)); Tree!int* right = tree.get!1[1]; assert(*right == 43); // An object is a double, a string, or a hash of objects alias Obj = Algebraic!(double, string, This[string]); Obj obj = "hello"; assert(obj.get!1 == "hello"); obj = 42.0; assert(obj.get!0 == 42); obj = ["customer": Obj("John"), "paid": Obj(23.95)]; assert(obj.get!2["customer"] == "John"); } /** `Variant` is an alias for `VariantN` instantiated with the largest of `creal`, `char[]`, and `void delegate()`. This ensures that `Variant` is large enough to hold all of D's predefined types unboxed, including all numeric types, pointers, delegates, and class references. You may want to use $(D VariantN) directly with a different maximum size either for storing larger types unboxed, or for saving memory. */ alias Variant = VariantN!(maxSize!(creal, char[], void delegate())); /** * Returns an array of variants constructed from $(D args). * * This is by design. During construction the $(D Variant) needs * static type information about the type being held, so as to store a * pointer to function for fast retrieval. */ Variant[] variantArray(T...)(T args) { Variant[] result; foreach (arg; args) { result ~= Variant(arg); } return result; } /// unittest { auto a = variantArray(1, 3.14, "Hi!"); assert(a[1] == 3.14); auto b = Variant(a); // variant array as variant assert(b[1] == 3.14); } /** Code that needs functionality similar to the $(D boxArray) function in the $(D std.boxer) module can achieve it like this: */ unittest { Variant[] fun(T...)(T args) { // ... return variantArray(args); } } /** /** * Thrown in three cases: * * $(OL $(LI An uninitialized Variant is used in any way except * assignment and $(D hasValue);) $(LI A $(D get) or * $(D coerce) is attempted with an incompatible target type;) * $(LI A comparison between $(D Variant) objects of * incompatible types is attempted.)) * */ // @@@ BUG IN COMPILER. THE 'STATIC' BELOW SHOULD NOT COMPILE static class VariantException : Exception { /// The source type in the conversion or comparison TypeInfo source; /// The target type in the conversion or comparison TypeInfo target; this(string s) { super(s); } this(TypeInfo source, TypeInfo target) { super("Variant: attempting to use incompatible types " ~ source.toString() ~ " and " ~ target.toString()); this.source = source; this.target = target; } } unittest { alias W1 = This2Variant!(char, int, This[int]); alias W2 = AliasSeq!(int, char[int]); static assert(is(W1 == W2)); alias var_t = Algebraic!(void, string); var_t foo = "quux"; } unittest { alias A = Algebraic!(real, This[], This[int], This[This]); A v1, v2, v3; v2 = 5.0L; v3 = 42.0L; //v1 = [ v2 ][]; auto v = v1.peek!(A[]); //writeln(v[0]); v1 = [ 9 : v3 ]; //writeln(v1); v1 = [ v3 : v3 ]; //writeln(v1); } unittest { // try it with an oddly small size VariantN!(1) test; assert(test.size > 1); // variantArray tests auto heterogeneous = variantArray(1, 4.5, "hi"); assert(heterogeneous.length == 3); auto variantArrayAsVariant = Variant(heterogeneous); assert(variantArrayAsVariant[0] == 1); assert(variantArrayAsVariant.length == 3); // array tests auto arr = Variant([1.2].dup); auto e = arr[0]; assert(e == 1.2); arr[0] = 2.0; assert(arr[0] == 2); arr ~= 4.5; assert(arr[1] == 4.5); // general tests Variant a; auto b = Variant(5); assert(!b.peek!(real) && b.peek!(int)); // assign a = *b.peek!(int); // comparison assert(a == b, a.type.toString() ~ " " ~ b.type.toString()); auto c = Variant("this is a string"); assert(a != c); // comparison via implicit conversions a = 42; b = 42.0; assert(a == b); // try failing conversions bool failed = false; try { auto d = c.get!(int); } catch (Exception e) { //writeln(stderr, e.toString); failed = true; } assert(failed); // :o) // toString tests a = Variant(42); assert(a.toString() == "42"); a = Variant(42.22); assert(a.toString() == "42.22"); // coerce tests a = Variant(42.22); assert(a.coerce!(int) == 42); a = cast(short) 5; assert(a.coerce!(double) == 5); a = Variant("10"); assert(a.coerce!int == 10); a = Variant(1); assert(a.coerce!bool); a = Variant(0); assert(!a.coerce!bool); a = Variant(1.0); assert(a.coerce!bool); a = Variant(0.0); assert(!a.coerce!bool); a = Variant(float.init); assertThrown!ConvException(a.coerce!bool); a = Variant("true"); assert(a.coerce!bool); a = Variant("false"); assert(!a.coerce!bool); a = Variant(""); assertThrown!ConvException(a.coerce!bool); // Object tests class B1 {} class B2 : B1 {} a = new B2; assert(a.coerce!(B1) !is null); a = new B1; assert(collectException(a.coerce!(B2) is null)); a = cast(Object) new B2; // lose static type info; should still work assert(a.coerce!(B2) !is null); // struct Big { int a[45]; } // a = Big.init; // hash assert(a.toHash() != 0); } // tests adapted from // http://www.dsource.org/projects/tango/browser/trunk/tango/core/Variant.d?rev=2601 unittest { Variant v; assert(!v.hasValue); v = 42; assert( v.peek!(int) ); assert( v.convertsTo!(long) ); assert( v.get!(int) == 42 ); assert( v.get!(long) == 42L ); assert( v.get!(ulong) == 42uL ); v = "Hello, World!"; assert( v.peek!(string) ); assert( v.get!(string) == "Hello, World!" ); assert(!is(char[] : wchar[])); assert( !v.convertsTo!(wchar[]) ); assert( v.get!(string) == "Hello, World!" ); // Literal arrays are dynamically-typed v = cast(int[4]) [1,2,3,4]; assert( v.peek!(int[4]) ); assert( v.get!(int[4]) == [1,2,3,4] ); { v = [1,2,3,4,5]; assert( v.peek!(int[]) ); assert( v.get!(int[]) == [1,2,3,4,5] ); } v = 3.1413; assert( v.peek!(double) ); assert( v.convertsTo!(real) ); //@@@ BUG IN COMPILER: DOUBLE SHOULD NOT IMPLICITLY CONVERT TO FLOAT assert( !v.convertsTo!(float) ); assert( *v.peek!(double) == 3.1413 ); auto u = Variant(v); assert( u.peek!(double) ); assert( *u.peek!(double) == 3.1413 ); // operators v = 38; assert( v + 4 == 42 ); assert( 4 + v == 42 ); assert( v - 4 == 34 ); assert( Variant(4) - v == -34 ); assert( v * 2 == 76 ); assert( 2 * v == 76 ); assert( v / 2 == 19 ); assert( Variant(2) / v == 0 ); assert( v % 2 == 0 ); assert( Variant(2) % v == 2 ); assert( (v & 6) == 6 ); assert( (6 & v) == 6 ); assert( (v | 9) == 47 ); assert( (9 | v) == 47 ); assert( (v ^ 5) == 35 ); assert( (5 ^ v) == 35 ); assert( v << 1 == 76 ); assert( Variant(1) << Variant(2) == 4 ); assert( v >> 1 == 19 ); assert( Variant(4) >> Variant(2) == 1 ); assert( Variant("abc") ~ "def" == "abcdef" ); assert( Variant("abc") ~ Variant("def") == "abcdef" ); v = 38; v += 4; assert( v == 42 ); v = 38; v -= 4; assert( v == 34 ); v = 38; v *= 2; assert( v == 76 ); v = 38; v /= 2; assert( v == 19 ); v = 38; v %= 2; assert( v == 0 ); v = 38; v &= 6; assert( v == 6 ); v = 38; v |= 9; assert( v == 47 ); v = 38; v ^= 5; assert( v == 35 ); v = 38; v <<= 1; assert( v == 76 ); v = 38; v >>= 1; assert( v == 19 ); v = 38; v += 1; assert( v < 40 ); v = "abc"; v ~= "def"; assert( v == "abcdef", *v.peek!(char[]) ); assert( Variant(0) < Variant(42) ); assert( Variant(42) > Variant(0) ); assert( Variant(42) > Variant(0.1) ); assert( Variant(42.1) > Variant(1) ); assert( Variant(21) == Variant(21) ); assert( Variant(0) != Variant(42) ); assert( Variant("bar") == Variant("bar") ); assert( Variant("foo") != Variant("bar") ); { auto v1 = Variant(42); auto v2 = Variant("foo"); auto v3 = Variant(1+2.0i); int[Variant] hash; hash[v1] = 0; hash[v2] = 1; hash[v3] = 2; assert( hash[v1] == 0 ); assert( hash[v2] == 1 ); assert( hash[v3] == 2 ); } { int[char[]] hash; hash["a"] = 1; hash["b"] = 2; hash["c"] = 3; Variant vhash = hash; assert( vhash.get!(int[char[]])["a"] == 1 ); assert( vhash.get!(int[char[]])["b"] == 2 ); assert( vhash.get!(int[char[]])["c"] == 3 ); } } unittest { // bug 1558 Variant va=1; Variant vb=-2; assert((va+vb).get!(int) == -1); assert((va-vb).get!(int) == 3); } unittest { Variant a; a=5; Variant b; b=a; Variant[] c; c = variantArray(1, 2, 3.0, "hello", 4); assert(c[3] == "hello"); } unittest { Variant v = 5; assert (!__traits(compiles, v.coerce!(bool delegate()))); } unittest { struct Huge { real a, b, c, d, e, f, g; } Huge huge; huge.e = 42; Variant v; v = huge; // Compile time error. assert(v.get!(Huge).e == 42); } unittest { const x = Variant(42); auto y1 = x.get!(const int); // @@@BUG@@@ //auto y2 = x.get!(immutable int)(); } // test iteration unittest { auto v = Variant([ 1, 2, 3, 4 ][]); auto j = 0; foreach (int i; v) { assert(i == ++j); } assert(j == 4); } // test convertibility unittest { auto v = Variant("abc".dup); assert(v.convertsTo!(char[])); } // http://d.puremagic.com/issues/show_bug.cgi?id=5424 unittest { interface A { void func1(); } static class AC: A { void func1() { } } A a = new AC(); a.func1(); Variant b = Variant(a); } unittest { // bug 7070 Variant v; v = null; } // Class and interface opEquals, issue 12157 unittest { class Foo { } class DerivedFoo : Foo { } Foo f1 = new Foo(); Foo f2 = new DerivedFoo(); Variant v1 = f1, v2 = f2; assert(v1 == f1); assert(v1 != new Foo()); assert(v1 != f2); assert(v2 != v1); assert(v2 == f2); } // Const parameters with opCall, issue 11361. unittest { static string t1(string c) { return c ~ "a"; } static const(char)[] t2(const(char)[] p) { return p ~ "b"; } static char[] t3(int p) { return p.text.dup; } Variant v1 = &t1; Variant v2 = &t2; Variant v3 = &t3; assert(v1("abc") == "abca"); assert(v1("abc").type == typeid(string)); assert(v2("abc") == "abcb"); assert(v2(cast(char[])("abc".dup)) == "abcb"); assert(v2("abc").type == typeid(const(char)[])); assert(v3(4) == ['4']); assert(v3(4).type == typeid(char[])); } // issue 12071 unittest { static struct Structure { int data; } alias VariantTest = Algebraic!(Structure delegate()); bool called = false; Structure example() { called = true; return Structure.init; } auto m = VariantTest(&example); m(); assert(called); } // Ordering comparisons of incompatible types, e.g. issue 7990. unittest { assertThrown!VariantException(Variant(3) < "a"); assertThrown!VariantException("a" < Variant(3)); assertThrown!VariantException(Variant(3) < Variant("a")); assertThrown!VariantException(Variant.init < Variant(3)); assertThrown!VariantException(Variant(3) < Variant.init); } // Handling of unordered types, e.g. issue 9043. unittest { static struct A { int a; } assert(Variant(A(3)) != A(4)); assertThrown!VariantException(Variant(A(3)) < A(4)); assertThrown!VariantException(A(3) < Variant(A(4))); assertThrown!VariantException(Variant(A(3)) < Variant(A(4))); } // Handling of empty types and arrays, e.g. issue 10958 unittest { class EmptyClass { } struct EmptyStruct { } alias EmptyArray = void[0]; alias Alg = Algebraic!(EmptyClass, EmptyStruct, EmptyArray); Variant testEmpty(T)() { T inst; Variant v = inst; assert(v.get!T == inst); assert(v.peek!T !is null); assert(*v.peek!T == inst); Alg alg = inst; assert(alg.get!T == inst); return v; } testEmpty!EmptyClass(); testEmpty!EmptyStruct(); testEmpty!EmptyArray(); // EmptyClass/EmptyStruct sizeof is 1, so we have this to test just size 0. EmptyArray arr = EmptyArray.init; Algebraic!(EmptyArray) a = arr; assert(a.length == 0); assert(a.get!EmptyArray == arr); } // Handling of void function pointers / delegates, e.g. issue 11360 unittest { static void t1() { } Variant v = &t1; assert(v() == Variant.init); static int t2() { return 3; } Variant v2 = &t2; assert(v2() == 3); } // Using peek for large structs, issue 8580 unittest { struct TestStruct(bool pad) { int val1; static if (pad) ubyte[Variant.size] padding; int val2; } void testPeekWith(T)() { T inst; inst.val1 = 3; inst.val2 = 4; Variant v = inst; T* original = v.peek!T; assert(original.val1 == 3); assert(original.val2 == 4); original.val1 = 6; original.val2 = 8; T modified = v.get!T; assert(modified.val1 == 6); assert(modified.val2 == 8); } testPeekWith!(TestStruct!false)(); testPeekWith!(TestStruct!true)(); } /** * Applies a delegate or function to the given Algebraic depending on the held type, * ensuring that all types are handled by the visiting functions. * * The delegate or function having the currently held value as parameter is called * with $(D variant)'s current value. Visiting handlers are passed * in the template parameter list. * It is statically ensured that all types of * $(D variant) are handled across all handlers. * $(D visit) allows delegates and static functions to be passed * as parameters. * * If a function without parameters is specified, this function is called * when variant doesn't hold a value. Exactly one parameter-less function * is allowed. * * Duplicate overloads matching the same type in one of the visitors are disallowed. * * Returns: The return type of visit is deduced from the visiting functions and must be * the same across all overloads. * Throws: If no parameter-less, error function is specified: * $(D VariantException) if $(D variant) doesn't hold a value. */ template visit(Handler ...) if (Handler.length > 0) { auto visit(VariantType)(VariantType variant) if (isAlgebraic!VariantType) { return visitImpl!(true, VariantType, Handler)(variant); } } /// unittest { Algebraic!(int, string) variant; variant = 10; assert(variant.visit!((string s) => cast(int)s.length, (int i) => i)() == 10); variant = "string"; assert(variant.visit!((int i) => i, (string s) => cast(int)s.length)() == 6); // Error function usage Algebraic!(int, string) emptyVar; auto rslt = emptyVar.visit!((string s) => cast(int)s.length, (int i) => i, () => -1)(); assert(rslt == -1); } unittest { Algebraic!(size_t, string) variant; // not all handled check static assert(!__traits(compiles, variant.visit!((size_t i){ })() )); variant = cast(size_t)10; auto which = 0; variant.visit!( (string s) => which = 1, (size_t i) => which = 0 )(); // integer overload was called assert(which == 0); // mustn't compile as generic Variant not supported Variant v; static assert(!__traits(compiles, v.visit!((string s) => which = 1, (size_t i) => which = 0 )() )); static size_t func(string s) { return s.length; } variant = "test"; assert( 4 == variant.visit!(func, (size_t i) => i )()); Algebraic!(int, float, string) variant2 = 5.0f; // Shouldn' t compile as float not handled by visitor. static assert(!__traits(compiles, variant2.visit!( (int) {}, (string) {})())); Algebraic!(size_t, string, float) variant3; variant3 = 10.0f; auto floatVisited = false; assert(variant3.visit!( (float f) { floatVisited = true; return cast(size_t)f; }, func, (size_t i) { return i; } )() == 10); assert(floatVisited == true); Algebraic!(float, string) variant4; assert(variant4.visit!(func, (float f) => cast(size_t)f, () => size_t.max)() == size_t.max); // double error func check static assert(!__traits(compiles, visit!(() => size_t.max, func, (float f) => cast(size_t)f, () => size_t.max)(variant4)) ); } /** * Behaves as $(D visit) but doesn't enforce that all types are handled * by the visiting functions. * * If a parameter-less function is specified it is called when * either $(D variant) doesn't hold a value or holds a type * which isn't handled by the visiting functions. * * Returns: The return type of tryVisit is deduced from the visiting functions and must be * the same across all overloads. * Throws: If no parameter-less, error function is specified: $(D VariantException) if * $(D variant) doesn't hold a value or * if $(D variant) holds a value which isn't handled by the visiting * functions. */ template tryVisit(Handler ...) if (Handler.length > 0) { auto tryVisit(VariantType)(VariantType variant) if (isAlgebraic!VariantType) { return visitImpl!(false, VariantType, Handler)(variant); } } /// unittest { Algebraic!(int, string) variant; variant = 10; auto which = -1; variant.tryVisit!((int i) { which = 0; })(); assert(which == 0); // Error function usage variant = "test"; variant.tryVisit!((int i) { which = 0; }, () { which = -100; })(); assert(which == -100); } unittest { Algebraic!(int, string) variant; variant = 10; auto which = -1; variant.tryVisit!((int i){ which = 0; })(); assert(which == 0); variant = "test"; assertThrown!VariantException(variant.tryVisit!((int i) { which = 0; })()); void errorfunc() { which = -1; } variant.tryVisit!((int i) { which = 0; }, errorfunc)(); assert(which == -1); } private template isAlgebraic(Type) { static if (is(Type _ == VariantN!T, T...)) enum isAlgebraic = T.length >= 2; // T[0] == maxDataSize, T[1..$] == AllowedTypesParam else enum isAlgebraic = false; } unittest { static assert(!isAlgebraic!(Variant)); static assert( isAlgebraic!(Algebraic!(string))); static assert( isAlgebraic!(Algebraic!(int, int[]))); } private auto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant) if (isAlgebraic!VariantType && Handler.length > 0) { alias AllowedTypes = VariantType.AllowedTypes; /** * Returns: Struct where $(D indices) is an array which * contains at the n-th position the index in Handler which takes the * n-th type of AllowedTypes. If an Handler doesn't match an * AllowedType, -1 is set. If a function in the delegates doesn't * have parameters, the field $(D exceptionFuncIdx) is set; * otherwise it's -1. */ auto visitGetOverloadMap() { struct Result { int[AllowedTypes.length] indices; int exceptionFuncIdx = -1; } Result result; foreach(tidx, T; AllowedTypes) { bool added = false; foreach(dgidx, dg; Handler) { // Handle normal function objects static if (isSomeFunction!dg) { alias Params = Parameters!dg; static if (Params.length == 0) { // Just check exception functions in the first // inner iteration (over delegates) if (tidx > 0) continue; else { if (result.exceptionFuncIdx != -1) assert(false, "duplicate parameter-less (error-)function specified"); result.exceptionFuncIdx = dgidx; } } else if (is(Unqual!(Params[0]) == T)) { if (added) assert(false, "duplicate overload specified for type '" ~ T.stringof ~ "'"); added = true; result.indices[tidx] = dgidx; } } // Handle composite visitors with opCall overloads else { static assert(false, dg.stringof ~ " is not a function or delegate"); } } if (!added) result.indices[tidx] = -1; } return result; } enum HandlerOverloadMap = visitGetOverloadMap(); if (!variant.hasValue) { // Call the exception function. The HandlerOverloadMap // will have its exceptionFuncIdx field set to value != -1 if an // exception function has been specified; otherwise we just through an exception. static if (HandlerOverloadMap.exceptionFuncIdx != -1) return Handler[ HandlerOverloadMap.exceptionFuncIdx ](); else throw new VariantException("variant must hold a value before being visited."); } foreach(idx, T; AllowedTypes) { if (auto ptr = variant.peek!T) { enum dgIdx = HandlerOverloadMap.indices[idx]; static if (dgIdx == -1) { static if (Strict) static assert(false, "overload for type '" ~ T.stringof ~ "' hasn't been specified"); else { static if (HandlerOverloadMap.exceptionFuncIdx != -1) return Handler[ HandlerOverloadMap.exceptionFuncIdx ](); else throw new VariantException("variant holds value of type '" ~ T.stringof ~ "' but no visitor has been provided"); } } else { return Handler[ dgIdx ](*ptr); } } } assert(false); } unittest { // validate that visit can be called with a const type struct Foo { int depth; } struct Bar { int depth; } alias FooBar = Algebraic!(Foo, Bar); int depth(in FooBar fb) { return fb.visit!((Foo foo) => foo.depth, (Bar bar) => bar.depth); } FooBar fb = Foo(3); assert(depth(fb) == 3); } unittest { // http://d.puremagic.com/issues/show_bug.cgi?id=5310 const Variant a; assert(a == a); Variant b; assert(a == b); assert(b == a); } unittest { // http://d.puremagic.com/issues/show_bug.cgi?id=10017 static struct S { ubyte[Variant.size + 1] s; } Variant v1, v2; v1 = S(); // the payload is allocated on the heap v2 = v1; // AssertError: target must be non-null assert(v1 == v2); } unittest { // http://d.puremagic.com/issues/show_bug.cgi?id=7069 Variant v; int i = 10; v = i; foreach (qual; AliasSeq!(MutableOf, ConstOf)) { assert(v.get!(qual!int) == 10); assert(v.get!(qual!float) == 10.0f); } foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf)) { assertThrown!VariantException(v.get!(qual!int)); } const(int) ci = 20; v = ci; foreach (qual; AliasSeq!(ConstOf)) { assert(v.get!(qual!int) == 20); assert(v.get!(qual!float) == 20.0f); } foreach (qual; AliasSeq!(MutableOf, ImmutableOf, SharedOf, SharedConstOf)) { assertThrown!VariantException(v.get!(qual!int)); assertThrown!VariantException(v.get!(qual!float)); } immutable(int) ii = ci; v = ii; foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf)) { assert(v.get!(qual!int) == 20); assert(v.get!(qual!float) == 20.0f); } foreach (qual; AliasSeq!(MutableOf, SharedOf)) { assertThrown!VariantException(v.get!(qual!int)); assertThrown!VariantException(v.get!(qual!float)); } int[] ai = [1,2,3]; v = ai; foreach (qual; AliasSeq!(MutableOf, ConstOf)) { assert(v.get!(qual!(int[])) == [1,2,3]); assert(v.get!(qual!(int)[]) == [1,2,3]); } foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf)) { assertThrown!VariantException(v.get!(qual!(int[]))); assertThrown!VariantException(v.get!(qual!(int)[])); } const(int[]) cai = [4,5,6]; v = cai; foreach (qual; AliasSeq!(ConstOf)) { assert(v.get!(qual!(int[])) == [4,5,6]); assert(v.get!(qual!(int)[]) == [4,5,6]); } foreach (qual; AliasSeq!(MutableOf, ImmutableOf, SharedOf, SharedConstOf)) { assertThrown!VariantException(v.get!(qual!(int[]))); assertThrown!VariantException(v.get!(qual!(int)[])); } immutable(int[]) iai = [7,8,9]; v = iai; //assert(v.get!(immutable(int[])) == [7,8,9]); // Bug ??? runtime error assert(v.get!(immutable(int)[]) == [7,8,9]); assert(v.get!(const(int[])) == [7,8,9]); assert(v.get!(const(int)[]) == [7,8,9]); //assert(v.get!(shared(const(int[]))) == cast(shared const)[7,8,9]); // Bug ??? runtime error //assert(v.get!(shared(const(int))[]) == cast(shared const)[7,8,9]); // Bug ??? runtime error foreach (qual; AliasSeq!(MutableOf)) { assertThrown!VariantException(v.get!(qual!(int[]))); assertThrown!VariantException(v.get!(qual!(int)[])); } class A {} class B : A {} B b = new B(); v = b; foreach (qual; AliasSeq!(MutableOf, ConstOf)) { assert(v.get!(qual!B) is b); assert(v.get!(qual!A) is b); assert(v.get!(qual!Object) is b); } foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf)) { assertThrown!VariantException(v.get!(qual!B)); assertThrown!VariantException(v.get!(qual!A)); assertThrown!VariantException(v.get!(qual!Object)); } const(B) cb = new B(); v = cb; foreach (qual; AliasSeq!(ConstOf)) { assert(v.get!(qual!B) is cb); assert(v.get!(qual!A) is cb); assert(v.get!(qual!Object) is cb); } foreach (qual; AliasSeq!(MutableOf, ImmutableOf, SharedOf, SharedConstOf)) { assertThrown!VariantException(v.get!(qual!B)); assertThrown!VariantException(v.get!(qual!A)); assertThrown!VariantException(v.get!(qual!Object)); } immutable(B) ib = new immutable(B)(); v = ib; foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf)) { assert(v.get!(qual!B) is ib); assert(v.get!(qual!A) is ib); assert(v.get!(qual!Object) is ib); } foreach (qual; AliasSeq!(MutableOf, SharedOf)) { assertThrown!VariantException(v.get!(qual!B)); assertThrown!VariantException(v.get!(qual!A)); assertThrown!VariantException(v.get!(qual!Object)); } shared(B) sb = new shared B(); v = sb; foreach (qual; AliasSeq!(SharedOf, SharedConstOf)) { assert(v.get!(qual!B) is sb); assert(v.get!(qual!A) is sb); assert(v.get!(qual!Object) is sb); } foreach (qual; AliasSeq!(MutableOf, ImmutableOf, ConstOf)) { assertThrown!VariantException(v.get!(qual!B)); assertThrown!VariantException(v.get!(qual!A)); assertThrown!VariantException(v.get!(qual!Object)); } shared(const(B)) scb = new shared const B(); v = scb; foreach (qual; AliasSeq!(SharedConstOf)) { assert(v.get!(qual!B) is scb); assert(v.get!(qual!A) is scb); assert(v.get!(qual!Object) is scb); } foreach (qual; AliasSeq!(MutableOf, ConstOf, ImmutableOf, SharedOf)) { assertThrown!VariantException(v.get!(qual!B)); assertThrown!VariantException(v.get!(qual!A)); assertThrown!VariantException(v.get!(qual!Object)); } } unittest { static struct DummyScope { // https://d.puremagic.com/issues/show_bug.cgi?id=12540 alias Alias12540 = Algebraic!Class12540; static class Class12540 { Alias12540 entity; } } } unittest { // https://issues.dlang.org/show_bug.cgi?id=10194 // Also test for elaborate copying static struct S { @disable this(); this(int dummy) { ++cnt; } this(this) { ++cnt; } @disable S opAssign(); ~this() { --cnt; assert(cnt >= 0); } static int cnt = 0; } { Variant v; { v = S(0); assert(S.cnt == 1); } assert(S.cnt == 1); // assigning a new value should destroy the existing one v = 0; assert(S.cnt == 0); // destroying the variant should destroy it's current value v = S(0); assert(S.cnt == 1); } assert(S.cnt == 0); } unittest { // Bugzilla 13300 static struct S { this(this) {} ~this() {} } static assert( hasElaborateCopyConstructor!(Variant)); static assert(!hasElaborateCopyConstructor!(Algebraic!bool)); static assert( hasElaborateCopyConstructor!(Algebraic!S)); static assert( hasElaborateCopyConstructor!(Algebraic!(bool, S))); static assert( hasElaborateDestructor!(Variant)); static assert(!hasElaborateDestructor!(Algebraic!bool)); static assert( hasElaborateDestructor!(Algebraic!S)); static assert( hasElaborateDestructor!(Algebraic!(bool, S))); import std.array; alias Value = Algebraic!bool; static struct T { Value value; @disable this(); } auto a = appender!(T[]); } unittest { // Bugzilla 13871 alias A = Algebraic!(int, typeof(null)); static struct B { A value; } alias C = std.variant.Algebraic!B; C var; var = C(B()); } unittest { // Make sure Variant can handle types with opDispatch but no length field. struct SWithNoLength { void opDispatch(string s)() { } } struct SWithLength { @property int opDispatch(string s)() { // Assume that s == "length" return 5; // Any value is OK for test. } } SWithNoLength sWithNoLength; Variant v = sWithNoLength; assertThrown!VariantException(v.length); SWithLength sWithLength; v = sWithLength; assertNotThrown!VariantException(v.get!SWithLength.length); assertThrown!VariantException(v.length); } unittest { // Bugzilla 13534 static assert(!__traits(compiles, () @safe { auto foo() @system { return 3; } auto v = Variant(&foo); v(); // foo is called in safe code!? })); } unittest { // Bugzilla 15039 import std.variant; import std.typecons; alias IntTypedef = Typedef!int; alias Obj = Algebraic!(int, IntTypedef, This[]); Obj obj = 1; obj.visit!( (int x) => {}, (IntTypedef x) => {}, (Obj[] x) => {}, ); } ldc-1.1.0-beta3-src/runtime/phobos/std/xml.d0000664000175000017500000024441612776215007016666 0ustar kaikai// Written in the D programming language. /** $(RED Warning: This module is considered out-dated and not up to Phobos' current standards. It will remain until we have a suitable replacement, but be aware that it will not remain long term.) Classes and functions for creating and parsing XML The basic architecture of this module is that there are standalone functions, classes for constructing an XML document from scratch (Tag, Element and Document), and also classes for parsing a pre-existing XML file (ElementParser and DocumentParser). The parsing classes may be used to build a Document, but that is not their primary purpose. The handling capabilities of DocumentParser and ElementParser are sufficiently customizable that you can make them do pretty much whatever you want. Example: This example creates a DOM (Document Object Model) tree from an XML file. ------------------------------------------------------------------------------ import std.xml; import std.stdio; import std.string; import std.file; // books.xml is used in various samples throughout the Microsoft XML Core // Services (MSXML) SDK. // // See http://msdn2.microsoft.com/en-us/library/ms762271(VS.85).aspx void main() { string s = cast(string)std.file.read("books.xml"); // Check for well-formedness check(s); // Make a DOM tree auto doc = new Document(s); // Plain-print it writeln(doc); } ------------------------------------------------------------------------------ Example: This example does much the same thing, except that the file is deconstructed and reconstructed by hand. This is more work, but the techniques involved offer vastly more power. ------------------------------------------------------------------------------ import std.xml; import std.stdio; import std.string; struct Book { string id; string author; string title; string genre; string price; string pubDate; string description; } void main() { string s = cast(string)std.file.read("books.xml"); // Check for well-formedness check(s); // Take it apart Book[] books; auto xml = new DocumentParser(s); xml.onStartTag["book"] = (ElementParser xml) { Book book; book.id = xml.tag.attr["id"]; xml.onEndTag["author"] = (in Element e) { book.author = e.text(); }; xml.onEndTag["title"] = (in Element e) { book.title = e.text(); }; xml.onEndTag["genre"] = (in Element e) { book.genre = e.text(); }; xml.onEndTag["price"] = (in Element e) { book.price = e.text(); }; xml.onEndTag["publish-date"] = (in Element e) { book.pubDate = e.text(); }; xml.onEndTag["description"] = (in Element e) { book.description = e.text(); }; xml.parse(); books ~= book; }; xml.parse(); // Put it back together again; auto doc = new Document(new Tag("catalog")); foreach(book;books) { auto element = new Element("book"); element.tag.attr["id"] = book.id; element ~= new Element("author", book.author); element ~= new Element("title", book.title); element ~= new Element("genre", book.genre); element ~= new Element("price", book.price); element ~= new Element("publish-date",book.pubDate); element ~= new Element("description", book.description); doc ~= element; } // Pretty-print it writefln(join(doc.pretty(3),"\n")); } ------------------------------------------------------------------------------- Macros: WIKI=Phobos/StdXml Copyright: Copyright Janice Caron 2008 - 2009. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Janice Caron Source: $(PHOBOSSRC std/_xml.d) */ /* Copyright Janice Caron 2008 - 2009. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.xml; import std.algorithm : count, startsWith; import std.array; import std.ascii; import std.string; import std.encoding; enum cdata = "= 0x20) return true; switch(c) { case 0xA: case 0x9: case 0xD: return true; default: return false; } } else if (0xE000 <= c && c <= 0x10FFFF) { if ((c & 0x1FFFFE) != 0xFFFE) // U+FFFE and U+FFFF return true; } return false; } unittest { // const CharTable=[0x9,0x9,0xA,0xA,0xD,0xD,0x20,0xD7FF,0xE000,0xFFFD, // 0x10000,0x10FFFF]; assert(!isChar(cast(dchar)0x8)); assert( isChar(cast(dchar)0x9)); assert( isChar(cast(dchar)0xA)); assert(!isChar(cast(dchar)0xB)); assert(!isChar(cast(dchar)0xC)); assert( isChar(cast(dchar)0xD)); assert(!isChar(cast(dchar)0xE)); assert(!isChar(cast(dchar)0x1F)); assert( isChar(cast(dchar)0x20)); assert( isChar('J')); assert( isChar(cast(dchar)0xD7FF)); assert(!isChar(cast(dchar)0xD800)); assert(!isChar(cast(dchar)0xDFFF)); assert( isChar(cast(dchar)0xE000)); assert( isChar(cast(dchar)0xFFFD)); assert(!isChar(cast(dchar)0xFFFE)); assert(!isChar(cast(dchar)0xFFFF)); assert( isChar(cast(dchar)0x10000)); assert( isChar(cast(dchar)0x10FFFF)); assert(!isChar(cast(dchar)0x110000)); debug (stdxml_TestHardcodedChecks) { foreach (c; 0 .. dchar.max + 1) assert(isChar(c) == lookup(CharTable, c)); } } /** * Returns true if the character is whitespace according to the XML standard * * Only the following characters are considered whitespace in XML - space, tab, * carriage return and linefeed * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Params: * c = the character to be tested */ bool isSpace(dchar c) { return c == '\u0020' || c == '\u0009' || c == '\u000A' || c == '\u000D'; } /** * Returns true if the character is a digit according to the XML standard * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Params: * c = the character to be tested */ bool isDigit(dchar c) { if (c <= 0x0039 && c >= 0x0030) return true; else return lookup(DigitTable,c); } unittest { debug (stdxml_TestHardcodedChecks) { foreach (c; 0 .. dchar.max + 1) assert(isDigit(c) == lookup(DigitTable, c)); } } /** * Returns true if the character is a letter according to the XML standard * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Params: * c = the character to be tested */ bool isLetter(dchar c) // rule 84 { return isIdeographic(c) || isBaseChar(c); } /** * Returns true if the character is an ideographic character according to the * XML standard * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Params: * c = the character to be tested */ bool isIdeographic(dchar c) { if (c == 0x3007) return true; if (c <= 0x3029 && c >= 0x3021 ) return true; if (c <= 0x9FA5 && c >= 0x4E00) return true; return false; } unittest { assert(isIdeographic('\u4E00')); assert(isIdeographic('\u9FA5')); assert(isIdeographic('\u3007')); assert(isIdeographic('\u3021')); assert(isIdeographic('\u3029')); debug (stdxml_TestHardcodedChecks) { foreach (c; 0 .. dchar.max + 1) assert(isIdeographic(c) == lookup(IdeographicTable, c)); } } /** * Returns true if the character is a base character according to the XML * standard * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Params: * c = the character to be tested */ bool isBaseChar(dchar c) { return lookup(BaseCharTable,c); } /** * Returns true if the character is a combining character according to the * XML standard * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Params: * c = the character to be tested */ bool isCombiningChar(dchar c) { return lookup(CombiningCharTable,c); } /** * Returns true if the character is an extender according to the XML standard * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Params: * c = the character to be tested */ bool isExtender(dchar c) { return lookup(ExtenderTable,c); } /** * Encodes a string by replacing all characters which need to be escaped with * appropriate predefined XML entities. * * encode() escapes certain characters (ampersand, quote, apostrophe, less-than * and greater-than), and similarly, decode() unescapes them. These functions * are provided for convenience only. You do not need to use them when using * the std.xml classes, because then all the encoding and decoding will be done * for you automatically. * * If the string is not modified, the original will be returned. * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Params: * s = The string to be encoded * * Returns: The encoded string * * Example: * -------------- * writefln(encode("a > b")); // writes "a > b" * -------------- */ S encode(S)(S s) { string r; size_t lastI; auto result = appender!S(); foreach (i, c; s) { switch (c) { case '&': r = "&"; break; case '"': r = """; break; case '\'': r = "'"; break; case '<': r = "<"; break; case '>': r = ">"; break; default: continue; } // Replace with r result.put(s[lastI .. i]); result.put(r); lastI = i + 1; } if (!result.data.ptr) return s; result.put(s[lastI .. $]); return result.data; } unittest { auto s = "hello"; assert(encode(s) is s); assert(encode("a > b") == "a > b", encode("a > b")); assert(encode("a < b") == "a < b"); assert(encode("don't") == "don't"); assert(encode("\"hi\"") == ""hi"", encode("\"hi\"")); assert(encode("cat & dog") == "cat & dog"); } /** * Mode to use for decoding. * * $(DDOC_ENUM_MEMBERS NONE) Do not decode * $(DDOC_ENUM_MEMBERS LOOSE) Decode, but ignore errors * $(DDOC_ENUM_MEMBERS STRICT) Decode, and throw exception on error */ enum DecodeMode { NONE, LOOSE, STRICT } /** * Decodes a string by unescaping all predefined XML entities. * * encode() escapes certain characters (ampersand, quote, apostrophe, less-than * and greater-than), and similarly, decode() unescapes them. These functions * are provided for convenience only. You do not need to use them when using * the std.xml classes, because then all the encoding and decoding will be done * for you automatically. * * This function decodes the entities &amp;, &quot;, &apos;, * &lt; and &gt, * as well as decimal and hexadecimal entities such as &#x20AC; * * If the string does not contain an ampersand, the original will be returned. * * Note that the "mode" parameter can be one of DecodeMode.NONE (do not * decode), DecodeMode.LOOSE (decode, but ignore errors), or DecodeMode.STRICT * (decode, and throw a DecodeException in the event of an error). * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Params: * s = The string to be decoded * mode = (optional) Mode to use for decoding. (Defaults to LOOSE). * * Throws: DecodeException if mode == DecodeMode.STRICT and decode fails * * Returns: The decoded string * * Example: * -------------- * writefln(decode("a > b")); // writes "a > b" * -------------- */ string decode(string s, DecodeMode mode=DecodeMode.LOOSE) { if (mode == DecodeMode.NONE) return s; char[] buffer; foreach (ref i; 0 .. s.length) { char c = s[i]; if (c != '&') { if (buffer.length != 0) buffer ~= c; } else { if (buffer.length == 0) { buffer = s[0 .. i].dup; } if (startsWith(s[i..$],"&#")) { try { dchar d; string t = s[i..$]; checkCharRef(t, d); char[4] temp; import std.utf : encode; buffer ~= temp[0 .. encode(temp, d)]; i = s.length - t.length - 1; } catch(Err e) { if (mode == DecodeMode.STRICT) throw new DecodeException("Unescaped &"); buffer ~= '&'; } } else if (startsWith(s[i..$],"&" )) { buffer ~= '&'; i += 4; } else if (startsWith(s[i..$],""")) { buffer ~= '"'; i += 5; } else if (startsWith(s[i..$],"'")) { buffer ~= '\''; i += 5; } else if (startsWith(s[i..$],"<" )) { buffer ~= '<'; i += 3; } else if (startsWith(s[i..$],">" )) { buffer ~= '>'; i += 3; } else { if (mode == DecodeMode.STRICT) throw new DecodeException("Unescaped &"); buffer ~= '&'; } } } return (buffer.length == 0) ? s : cast(string)buffer; } unittest { void assertNot(string s) { bool b = false; try { decode(s,DecodeMode.STRICT); } catch (DecodeException e) { b = true; } assert(b,s); } // Assert that things that should work, do auto s = "hello"; assert(decode(s, DecodeMode.STRICT) is s); assert(decode("a > b", DecodeMode.STRICT) == "a > b"); assert(decode("a < b", DecodeMode.STRICT) == "a < b"); assert(decode("don't", DecodeMode.STRICT) == "don't"); assert(decode(""hi"", DecodeMode.STRICT) == "\"hi\""); assert(decode("cat & dog", DecodeMode.STRICT) == "cat & dog"); assert(decode("*", DecodeMode.STRICT) == "*"); assert(decode("*", DecodeMode.STRICT) == "*"); assert(decode("cat & dog", DecodeMode.LOOSE) == "cat & dog"); assert(decode("a > b", DecodeMode.LOOSE) == "a > b"); assert(decode("&#;", DecodeMode.LOOSE) == "&#;"); assert(decode("&#x;", DecodeMode.LOOSE) == "&#x;"); assert(decode("G;", DecodeMode.LOOSE) == "G;"); assert(decode("G;", DecodeMode.LOOSE) == "G;"); // Assert that things that shouldn't work, don't assertNot("cat & dog"); assertNot("a > b"); assertNot("&#;"); assertNot("&#x;"); assertNot("G;"); assertNot("G;"); } /** * Class representing an XML document. * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * */ class Document : Element { /** * Contains all text which occurs before the root element. * Defaults to <?xml version="1.0"?> */ string prolog = ""; /** * Contains all text which occurs after the root element. * Defaults to the empty string */ string epilog; /** * Constructs a Document by parsing XML text. * * This function creates a complete DOM (Document Object Model) tree. * * The input to this function MUST be valid XML. * This is enforced by DocumentParser's in contract. * * Params: * s = the complete XML text. */ this(string s) in { assert(s.length != 0); } body { auto xml = new DocumentParser(s); string tagString = xml.tag.tagString; this(xml.tag); prolog = s[0 .. tagString.ptr - s.ptr]; parse(xml); epilog = *xml.s; } /** * Constructs a Document from a Tag. * * Params: * tag = the start tag of the document. */ this(const(Tag) tag) { super(tag); } const { /** * Compares two Documents for equality * * Example: * -------------- * Document d1,d2; * if (d1 == d2) { } * -------------- */ override bool opEquals(Object o) { const doc = toType!(const Document)(o); return (prolog != doc.prolog ) ? false : ( (super != cast(const Element)doc) ? false : ( (epilog != doc.epilog ) ? false : ( true ))); } /** * Compares two Documents * * You should rarely need to call this function. It exists so that * Documents can be used as associative array keys. * * Example: * -------------- * Document d1,d2; * if (d1 < d2) { } * -------------- */ override int opCmp(Object o) { const doc = toType!(const Document)(o); return ((prolog != doc.prolog ) ? ( prolog < doc.prolog ? -1 : 1 ) : ((super != cast(const Element)doc) ? ( cast()super < cast()cast(const Element)doc ? -1 : 1 ) : ((epilog != doc.epilog ) ? ( epilog < doc.epilog ? -1 : 1 ) : 0 ))); } /** * Returns the hash of a Document * * You should rarely need to call this function. It exists so that * Documents can be used as associative array keys. */ override size_t toHash() @trusted { return hash(prolog, hash(epilog, (cast()super).toHash())); } /** * Returns the string representation of a Document. (That is, the * complete XML of a document). */ override string toString() { return prolog ~ super.toString() ~ epilog; } } } /** * Class representing an XML element. * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) */ class Element : Item { Tag tag; /// The start tag of the element Item[] items; /// The element's items Text[] texts; /// The element's text items CData[] cdatas; /// The element's CData items Comment[] comments; /// The element's comments ProcessingInstruction[] pis; /// The element's processing instructions Element[] elements; /// The element's child elements /** * Constructs an Element given a name and a string to be used as a Text * interior. * * Params: * name = the name of the element. * interior = (optional) the string interior. * * Example: * ------------------------------------------------------- * auto element = new Element("title","Serenity") * // constructs the element Serenity * ------------------------------------------------------- */ this(string name, string interior=null) { this(new Tag(name)); if (interior.length != 0) opCatAssign(new Text(interior)); } /** * Constructs an Element from a Tag. * * Params: * tag_ = the start or empty tag of the element. */ this(const(Tag) tag_) { this.tag = new Tag(tag_.name); tag.type = TagType.EMPTY; foreach(k,v;tag_.attr) tag.attr[k] = v; tag.tagString = tag_.tagString; } /** * Append a text item to the interior of this element * * Params: * item = the item you wish to append. * * Example: * -------------- * Element element; * element ~= new Text("hello"); * -------------- */ void opCatAssign(Text item) { texts ~= item; appendItem(item); } /** * Append a CData item to the interior of this element * * Params: * item = the item you wish to append. * * Example: * -------------- * Element element; * element ~= new CData("hello"); * -------------- */ void opCatAssign(CData item) { cdatas ~= item; appendItem(item); } /** * Append a comment to the interior of this element * * Params: * item = the item you wish to append. * * Example: * -------------- * Element element; * element ~= new Comment("hello"); * -------------- */ void opCatAssign(Comment item) { comments ~= item; appendItem(item); } /** * Append a processing instruction to the interior of this element * * Params: * item = the item you wish to append. * * Example: * -------------- * Element element; * element ~= new ProcessingInstruction("hello"); * -------------- */ void opCatAssign(ProcessingInstruction item) { pis ~= item; appendItem(item); } /** * Append a complete element to the interior of this element * * Params: * item = the item you wish to append. * * Example: * -------------- * Element element; * Element other = new Element("br"); * element ~= other; * // appends element representing
* -------------- */ void opCatAssign(Element item) { elements ~= item; appendItem(item); } private void appendItem(Item item) { items ~= item; if (tag.type == TagType.EMPTY && !item.isEmptyXML) tag.type = TagType.START; } private void parse(ElementParser xml) { xml.onText = (string s) { opCatAssign(new Text(s)); }; xml.onCData = (string s) { opCatAssign(new CData(s)); }; xml.onComment = (string s) { opCatAssign(new Comment(s)); }; xml.onPI = (string s) { opCatAssign(new ProcessingInstruction(s)); }; xml.onStartTag[null] = (ElementParser xml) { auto e = new Element(xml.tag); e.parse(xml); opCatAssign(e); }; xml.parse(); } /** * Compares two Elements for equality * * Example: * -------------- * Element e1,e2; * if (e1 == e2) { } * -------------- */ override bool opEquals(Object o) { const element = toType!(const Element)(o); auto len = items.length; if (len != element.items.length) return false; foreach (i; 0 .. len) { if (!items[i].opEquals(cast()element.items[i])) return false; } return true; } /** * Compares two Elements * * You should rarely need to call this function. It exists so that Elements * can be used as associative array keys. * * Example: * -------------- * Element e1,e2; * if (e1 < e2) { } * -------------- */ override int opCmp(Object o) { const element = toType!(const Element)(o); for (uint i=0; ; ++i) { if (i == items.length && i == element.items.length) return 0; if (i == items.length) return -1; if (i == element.items.length) return 1; if (items[i] != element.items[i]) return items[i].opCmp(cast()element.items[i]); } } /** * Returns the hash of an Element * * You should rarely need to call this function. It exists so that Elements * can be used as associative array keys. */ override size_t toHash() const { size_t hash = tag.toHash(); foreach(item;items) hash += item.toHash(); return hash; } const { /** * Returns the decoded interior of an element. * * The element is assumed to contain text only. So, for * example, given XML such as "<title>Good &amp; * Bad</title>", will return "Good & Bad". * * Params: * mode = (optional) Mode to use for decoding. (Defaults to LOOSE). * * Throws: DecodeException if decode fails */ string text(DecodeMode mode=DecodeMode.LOOSE) { string buffer; foreach(item;items) { Text t = cast(Text)item; if (t is null) throw new DecodeException(item.toString()); buffer ~= decode(t.toString(),mode); } return buffer; } /** * Returns an indented string representation of this item * * Params: * indent = (optional) number of spaces by which to indent this * element. Defaults to 2. */ override string[] pretty(uint indent=2) { if (isEmptyXML) return [ tag.toEmptyString() ]; if (items.length == 1) { Text t = cast(Text)(items[0]); if (t !is null) { return [tag.toStartString() ~ t.toString() ~ tag.toEndString()]; } } string[] a = [ tag.toStartString() ]; foreach(item;items) { string[] b = item.pretty(indent); foreach(s;b) { a ~= rightJustify(s,count(s) + indent); } } a ~= tag.toEndString(); return a; } /** * Returns the string representation of an Element * * Example: * -------------- * auto element = new Element("br"); * writefln(element.toString()); // writes "
" * -------------- */ override string toString() { if (isEmptyXML) return tag.toEmptyString(); string buffer = tag.toStartString(); foreach (item;items) { buffer ~= item.toString(); } buffer ~= tag.toEndString(); return buffer; } override @property bool isEmptyXML() { return items.length == 0; } } } /** * Tag types. * * $(DDOC_ENUM_MEMBERS START) Used for start tags * $(DDOC_ENUM_MEMBERS END) Used for end tags * $(DDOC_ENUM_MEMBERS EMPTY) Used for empty tags * */ enum TagType { START, END, EMPTY } /** * Class representing an XML tag. * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * The class invariant guarantees *
    *
  • that $(B type) is a valid enum TagType value
  • *
  • that $(B name) consists of valid characters
  • *
  • that each attribute name consists of valid characters
  • *
*/ class Tag { TagType type = TagType.START; /// Type of tag string name; /// Tag name string[string] attr; /// Associative array of attributes private string tagString; invariant() { string s; string t; assert(type == TagType.START || type == TagType.END || type == TagType.EMPTY); s = name; try { checkName(s,t); } catch(Err e) { assert(false,"Invalid tag name:" ~ e.toString()); } foreach(k,v;attr) { s = k; try { checkName(s,t); } catch(Err e) { assert(false,"Invalid atrribute name:" ~ e.toString()); } } } /** * Constructs an instance of Tag with a specified name and type * * The constructor does not initialize the attributes. To initialize the * attributes, you access the $(B attr) member variable. * * Params: * name = the Tag's name * type = (optional) the Tag's type. If omitted, defaults to * TagType.START. * * Example: * -------------- * auto tag = new Tag("img",Tag.EMPTY); * tag.attr["src"] = "http://example.com/example.jpg"; * -------------- */ this(string name, TagType type=TagType.START) { this.name = name; this.type = type; } /* Private constructor (so don't ddoc this!) * * Constructs a Tag by parsing the string representation, e.g. "". * * The string is passed by reference, and is advanced over all characters * consumed. * * The second parameter is a dummy parameter only, required solely to * distinguish this constructor from the public one. */ private this(ref string s, bool dummy) { tagString = s; try { reqc(s,'<'); if (optc(s,'/')) type = TagType.END; name = munch(s,"^/>"~whitespace); munch(s,whitespace); while(s.length > 0 && s[0] != '>' && s[0] != '/') { string key = munch(s,"^="~whitespace); munch(s,whitespace); reqc(s,'='); munch(s,whitespace); reqc(s,'"'); string val = decode(munch(s,"^\""), DecodeMode.LOOSE); reqc(s,'"'); munch(s,whitespace); attr[key] = val; } if (optc(s,'/')) { if (type == TagType.END) throw new TagException(""); type = TagType.EMPTY; } reqc(s,'>'); tagString.length = (s.ptr - tagString.ptr); } catch(XMLException e) { tagString.length = (s.ptr - tagString.ptr); throw new TagException(tagString); } } const { /** * Compares two Tags for equality * * You should rarely need to call this function. It exists so that Tags * can be used as associative array keys. * * Example: * -------------- * Tag tag1,tag2 * if (tag1 == tag2) { } * -------------- */ override bool opEquals(Object o) { const tag = toType!(const Tag)(o); return (name != tag.name) ? false : ( (attr != tag.attr) ? false : ( (type != tag.type) ? false : ( true ))); } /** * Compares two Tags * * Example: * -------------- * Tag tag1,tag2 * if (tag1 < tag2) { } * -------------- */ override int opCmp(Object o) { const tag = toType!(const Tag)(o); // Note that attr is an AA, so the comparison is nonsensical (bug 10381) return ((name != tag.name) ? ( name < tag.name ? -1 : 1 ) : ((attr != tag.attr) ? ( cast(void *)attr < cast(void*)tag.attr ? -1 : 1 ) : ((type != tag.type) ? ( type < tag.type ? -1 : 1 ) : 0 ))); } /** * Returns the hash of a Tag * * You should rarely need to call this function. It exists so that Tags * can be used as associative array keys. */ override size_t toHash() { return typeid(name).getHash(&name); } /** * Returns the string representation of a Tag * * Example: * -------------- * auto tag = new Tag("book",TagType.START); * writefln(tag.toString()); // writes "" * -------------- */ override string toString() { if (isEmpty) return toEmptyString(); return (isEnd) ? toEndString() : toStartString(); } private { string toNonEndString() { string s = "<" ~ name; foreach(key,val;attr) s ~= format(" %s=\"%s\"",key,encode(val)); return s; } string toStartString() { return toNonEndString() ~ ">"; } string toEndString() { return ""; } string toEmptyString() { return toNonEndString() ~ " />"; } } /** * Returns true if the Tag is a start tag * * Example: * -------------- * if (tag.isStart) { } * -------------- */ @property bool isStart() { return type == TagType.START; } /** * Returns true if the Tag is an end tag * * Example: * -------------- * if (tag.isEnd) { } * -------------- */ @property bool isEnd() { return type == TagType.END; } /** * Returns true if the Tag is an empty tag * * Example: * -------------- * if (tag.isEmpty) { } * -------------- */ @property bool isEmpty() { return type == TagType.EMPTY; } } } /** * Class representing a comment */ class Comment : Item { private string content; /** * Construct a comment * * Params: * content = the body of the comment * * Throws: CommentException if the comment body is illegal (contains "--" * or exactly equals "-") * * Example: * -------------- * auto item = new Comment("This is a comment"); * // constructs * -------------- */ this(string content) { if (content == "-" || content.indexOf("==") != -1) throw new CommentException(content); this.content = content; } /** * Compares two comments for equality * * Example: * -------------- * Comment item1,item2; * if (item1 == item2) { } * -------------- */ override bool opEquals(Object o) { const item = toType!(const Item)(o); const t = cast(Comment)item; return t !is null && content == t.content; } /** * Compares two comments * * You should rarely need to call this function. It exists so that Comments * can be used as associative array keys. * * Example: * -------------- * Comment item1,item2; * if (item1 < item2) { } * -------------- */ override int opCmp(Object o) { const item = toType!(const Item)(o); const t = cast(Comment)item; return t !is null && (content != t.content ? (content < t.content ? -1 : 1 ) : 0 ); } /** * Returns the hash of a Comment * * You should rarely need to call this function. It exists so that Comments * can be used as associative array keys. */ override size_t toHash() const { return hash(content); } /** * Returns a string representation of this comment */ override string toString() const { return ""; } override @property bool isEmptyXML() const { return false; } /// Returns false always } /** * Class representing a Character Data section */ class CData : Item { private string content; /** * Construct a character data section * * Params: * content = the body of the character data segment * * Throws: CDataException if the segment body is illegal (contains "]]>") * * Example: * -------------- * auto item = new CData("hello"); * // constructs hello]]> * -------------- */ this(string content) { if (content.indexOf("]]>") != -1) throw new CDataException(content); this.content = content; } /** * Compares two CDatas for equality * * Example: * -------------- * CData item1,item2; * if (item1 == item2) { } * -------------- */ override bool opEquals(Object o) { const item = toType!(const Item)(o); const t = cast(CData)item; return t !is null && content == t.content; } /** * Compares two CDatas * * You should rarely need to call this function. It exists so that CDatas * can be used as associative array keys. * * Example: * -------------- * CData item1,item2; * if (item1 < item2) { } * -------------- */ override int opCmp(Object o) { const item = toType!(const Item)(o); const t = cast(CData)item; return t !is null && (content != t.content ? (content < t.content ? -1 : 1 ) : 0 ); } /** * Returns the hash of a CData * * You should rarely need to call this function. It exists so that CDatas * can be used as associative array keys. */ override size_t toHash() const { return hash(content); } /** * Returns a string representation of this CData section */ override string toString() const { return cdata ~ content ~ "]]>"; } override @property bool isEmptyXML() const { return false; } /// Returns false always } /** * Class representing a text (aka Parsed Character Data) section */ class Text : Item { private string content; /** * Construct a text (aka PCData) section * * Params: * content = the text. This function encodes the text before * insertion, so it is safe to insert any text * * Example: * -------------- * auto Text = new CData("a < b"); * // constructs a < b * -------------- */ this(string content) { this.content = encode(content); } /** * Compares two text sections for equality * * Example: * -------------- * Text item1,item2; * if (item1 == item2) { } * -------------- */ override bool opEquals(Object o) { const item = toType!(const Item)(o); const t = cast(Text)item; return t !is null && content == t.content; } /** * Compares two text sections * * You should rarely need to call this function. It exists so that Texts * can be used as associative array keys. * * Example: * -------------- * Text item1,item2; * if (item1 < item2) { } * -------------- */ override int opCmp(Object o) { const item = toType!(const Item)(o); const t = cast(Text)item; return t !is null && (content != t.content ? (content < t.content ? -1 : 1 ) : 0 ); } /** * Returns the hash of a text section * * You should rarely need to call this function. It exists so that Texts * can be used as associative array keys. */ override size_t toHash() const { return hash(content); } /** * Returns a string representation of this Text section */ override string toString() const { return content; } /** * Returns true if the content is the empty string */ override @property bool isEmptyXML() const { return content.length == 0; } } /** * Class representing an XML Instruction section */ class XMLInstruction : Item { private string content; /** * Construct an XML Instruction section * * Params: * content = the body of the instruction segment * * Throws: XIException if the segment body is illegal (contains ">") * * Example: * -------------- * auto item = new XMLInstruction("ATTLIST"); * // constructs * -------------- */ this(string content) { if (content.indexOf(">") != -1) throw new XIException(content); this.content = content; } /** * Compares two XML instructions for equality * * Example: * -------------- * XMLInstruction item1,item2; * if (item1 == item2) { } * -------------- */ override bool opEquals(Object o) { const item = toType!(const Item)(o); const t = cast(XMLInstruction)item; return t !is null && content == t.content; } /** * Compares two XML instructions * * You should rarely need to call this function. It exists so that * XmlInstructions can be used as associative array keys. * * Example: * -------------- * XMLInstruction item1,item2; * if (item1 < item2) { } * -------------- */ override int opCmp(Object o) { const item = toType!(const Item)(o); const t = cast(XMLInstruction)item; return t !is null && (content != t.content ? (content < t.content ? -1 : 1 ) : 0 ); } /** * Returns the hash of an XMLInstruction * * You should rarely need to call this function. It exists so that * XmlInstructions can be used as associative array keys. */ override size_t toHash() const { return hash(content); } /** * Returns a string representation of this XmlInstruction */ override string toString() const { return ""; } override @property bool isEmptyXML() const { return false; } /// Returns false always } /** * Class representing a Processing Instruction section */ class ProcessingInstruction : Item { private string content; /** * Construct a Processing Instruction section * * Params: * content = the body of the instruction segment * * Throws: PIException if the segment body is illegal (contains "?>") * * Example: * -------------- * auto item = new ProcessingInstruction("php"); * // constructs * -------------- */ this(string content) { if (content.indexOf("?>") != -1) throw new PIException(content); this.content = content; } /** * Compares two processing instructions for equality * * Example: * -------------- * ProcessingInstruction item1,item2; * if (item1 == item2) { } * -------------- */ override bool opEquals(Object o) { const item = toType!(const Item)(o); const t = cast(ProcessingInstruction)item; return t !is null && content == t.content; } /** * Compares two processing instructions * * You should rarely need to call this function. It exists so that * ProcessingInstructions can be used as associative array keys. * * Example: * -------------- * ProcessingInstruction item1,item2; * if (item1 < item2) { } * -------------- */ override int opCmp(Object o) { const item = toType!(const Item)(o); const t = cast(ProcessingInstruction)item; return t !is null && (content != t.content ? (content < t.content ? -1 : 1 ) : 0 ); } /** * Returns the hash of a ProcessingInstruction * * You should rarely need to call this function. It exists so that * ProcessingInstructions can be used as associative array keys. */ override size_t toHash() const { return hash(content); } /** * Returns a string representation of this ProcessingInstruction */ override string toString() const { return ""; } override @property bool isEmptyXML() const { return false; } /// Returns false always } /** * Abstract base class for XML items */ abstract class Item { /// Compares with another Item of same type for equality abstract override bool opEquals(Object o); /// Compares with another Item of same type abstract override int opCmp(Object o); /// Returns the hash of this item abstract override size_t toHash() const; /// Returns a string representation of this item abstract override string toString() const; /** * Returns an indented string representation of this item * * Params: * indent = number of spaces by which to indent child elements */ string[] pretty(uint indent) const { string s = strip(toString()); return s.length == 0 ? [] : [ s ]; } /// Returns true if the item represents empty XML text abstract @property bool isEmptyXML() const; } /** * Class for parsing an XML Document. * * This is a subclass of ElementParser. Most of the useful functions are * documented there. * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Bugs: * Currently only supports UTF documents. * * If there is an encoding attribute in the prolog, it is ignored. * */ class DocumentParser : ElementParser { string xmlText; /** * Constructs a DocumentParser. * * The input to this function MUST be valid XML. * This is enforced by the function's in contract. * * Params: * xmlText_ = the entire XML document as text * */ this(string xmlText_) in { assert(xmlText_.length != 0); try { // Confirm that the input is valid XML check(xmlText_); } catch (CheckException e) { // And if it's not, tell the user why not assert(false, "\n" ~ e.toString()); } } body { xmlText = xmlText_; s = &xmlText; super(); // Initialize everything parse(); // Parse through the root tag (but not beyond) } } /** * Class for parsing an XML element. * * Standards: $(LINK2 http://www.w3.org/TR/1998/REC-xml-19980210, XML 1.0) * * Note that you cannot construct instances of this class directly. You can * construct a DocumentParser (which is a subclass of ElementParser), but * otherwise, Instances of ElementParser will be created for you by the * library, and passed your way via onStartTag handlers. * */ class ElementParser { alias Handler = void delegate(string); alias ElementHandler = void delegate(in Element element); alias ParserHandler = void delegate(ElementParser parser); private { Tag tag_; string elementStart; string* s; Handler commentHandler = null; Handler cdataHandler = null; Handler xiHandler = null; Handler piHandler = null; Handler rawTextHandler = null; Handler textHandler = null; // Private constructor for start tags this(ElementParser parent) { s = parent.s; this(); tag_ = parent.tag_; } // Private constructor for empty tags this(Tag tag, string* t) { s = t; this(); tag_ = tag; } } /** * The Tag at the start of the element being parsed. You can read this to * determine the tag's name and attributes. */ @property const(Tag) tag() const { return tag_; } /** * Register a handler which will be called whenever a start tag is * encountered which matches the specified name. You can also pass null as * the name, in which case the handler will be called for any unmatched * start tag. * * Example: * -------------- * // Call this function whenever a start tag is encountered * onStartTag["podcast"] = (ElementParser xml) * { * // Your code here * // * // This is a a closure, so code here may reference * // variables which are outside of this scope * }; * * // call myEpisodeStartHandler (defined elsewhere) whenever an * // start tag is encountered * onStartTag["episode"] = &myEpisodeStartHandler; * * // call delegate dg for all other start tags * onStartTag[null] = dg; * -------------- * * This library will supply your function with a new instance of * ElementHandler, which may be used to parse inside the element whose * start tag was just found, or to identify the tag attributes of the * element, etc. * * Note that your function will be called for both start tags and empty * tags. That is, we make no distinction between <br></br> * and <br/>. */ ParserHandler[string] onStartTag; /** * Register a handler which will be called whenever an end tag is * encountered which matches the specified name. You can also pass null as * the name, in which case the handler will be called for any unmatched * end tag. * * Example: * -------------- * // Call this function whenever a end tag is encountered * onEndTag["podcast"] = (in Element e) * { * // Your code here * // * // This is a a closure, so code here may reference * // variables which are outside of this scope * }; * * // call myEpisodeEndHandler (defined elsewhere) whenever an * // end tag is encountered * onEndTag["episode"] = &myEpisodeEndHandler; * * // call delegate dg for all other end tags * onEndTag[null] = dg; * -------------- * * Note that your function will be called for both start tags and empty * tags. That is, we make no distinction between <br></br> * and <br/>. */ ElementHandler[string] onEndTag; protected this() { elementStart = *s; } /** * Register a handler which will be called whenever text is encountered. * * Example: * -------------- * // Call this function whenever text is encountered * onText = (string s) * { * // Your code here * * // The passed parameter s will have been decoded by the time you see * // it, and so may contain any character. * // * // This is a a closure, so code here may reference * // variables which are outside of this scope * }; * -------------- */ @property void onText(Handler handler) { textHandler = handler; } /** * Register an alternative handler which will be called whenever text * is encountered. This differs from onText in that onText will decode * the text, whereas onTextRaw will not. This allows you to make design * choices, since onText will be more accurate, but slower, while * onTextRaw will be faster, but less accurate. Of course, you can * still call decode() within your handler, if you want, but you'd * probably want to use onTextRaw only in circumstances where you * know that decoding is unnecessary. * * Example: * -------------- * // Call this function whenever text is encountered * onText = (string s) * { * // Your code here * * // The passed parameter s will NOT have been decoded. * // * // This is a a closure, so code here may reference * // variables which are outside of this scope * }; * -------------- */ void onTextRaw(Handler handler) { rawTextHandler = handler; } /** * Register a handler which will be called whenever a character data * segment is encountered. * * Example: * -------------- * // Call this function whenever a CData section is encountered * onCData = (string s) * { * // Your code here * * // The passed parameter s does not include the opening * // * // This is a a closure, so code here may reference * // variables which are outside of this scope * }; * -------------- */ @property void onCData(Handler handler) { cdataHandler = handler; } /** * Register a handler which will be called whenever a comment is * encountered. * * Example: * -------------- * // Call this function whenever a comment is encountered * onComment = (string s) * { * // Your code here * * // The passed parameter s does not include the opening * // * // This is a a closure, so code here may reference * // variables which are outside of this scope * }; * -------------- */ @property void onComment(Handler handler) { commentHandler = handler; } /** * Register a handler which will be called whenever a processing * instruction is encountered. * * Example: * -------------- * // Call this function whenever a processing instruction is encountered * onPI = (string s) * { * // Your code here * * // The passed parameter s does not include the opening * // * // This is a a closure, so code here may reference * // variables which are outside of this scope * }; * -------------- */ @property void onPI(Handler handler) { piHandler = handler; } /** * Register a handler which will be called whenever an XML instruction is * encountered. * * Example: * -------------- * // Call this function whenever an XML instruction is encountered * // (Note: XML instructions may only occur preceding the root tag of a * // document). * onPI = (string s) * { * // Your code here * * // The passed parameter s does not include the opening * // * // This is a a closure, so code here may reference * // variables which are outside of this scope * }; * -------------- */ @property void onXI(Handler handler) { xiHandler = handler; } /** * Parse an XML element. * * Parsing will continue until the end of the current element. Any items * encountered for which a handler has been registered will invoke that * handler. * * Throws: various kinds of XMLException */ void parse() { string t; Tag root = tag_; Tag[string] startTags; if (tag_ !is null) startTags[tag_.name] = tag_; while(s.length != 0) { if (startsWith(*s,"")); if (commentHandler.funcptr !is null) commentHandler(t); chop(*s,3); } else if (startsWith(*s,"")); if (cdataHandler.funcptr !is null) cdataHandler(t); chop(*s,3); } else if (startsWith(*s,"")); if (xiHandler.funcptr !is null) xiHandler(t); chop(*s,1); } else if (startsWith(*s,"")); if (piHandler.funcptr !is null) piHandler(t); chop(*s,2); } else if (startsWith(*s,"<")) { tag_ = new Tag(*s,true); if (root is null) return; // Return to constructor of derived class if (tag_.isStart) { startTags[tag_.name] = tag_; auto parser = new ElementParser(this); auto handler = tag_.name in onStartTag; if (handler !is null) (*handler)(parser); else { handler = null in onStartTag; if (handler !is null) (*handler)(parser); } } else if (tag_.isEnd) { auto startTag = startTags[tag_.name]; string text; immutable(char)* p = startTag.tagString.ptr + startTag.tagString.length; immutable(char)* q = tag_.tagString.ptr; text = decode(p[0..(q-p)], DecodeMode.LOOSE); auto element = new Element(startTag); if (text.length != 0) element ~= new Text(text); auto handler = tag_.name in onEndTag; if (handler !is null) (*handler)(element); else { handler = null in onEndTag; if (handler !is null) (*handler)(element); } if (tag_.name == root.name) return; } else if (tag_.isEmpty) { Tag startTag = new Tag(tag_.name); // FIX by hed010gy, for bug 2979 // http://d.puremagic.com/issues/show_bug.cgi?id=2979 if (tag_.attr.length > 0) foreach(tn,tv; tag_.attr) startTag.attr[tn]=tv; // END FIX // Handle the pretend start tag string s2; auto parser = new ElementParser(startTag,&s2); auto handler1 = startTag.name in onStartTag; if (handler1 !is null) (*handler1)(parser); else { handler1 = null in onStartTag; if (handler1 !is null) (*handler1)(parser); } // Handle the pretend end tag auto element = new Element(startTag); auto handler2 = tag_.name in onEndTag; if (handler2 !is null) (*handler2)(element); else { handler2 = null in onEndTag; if (handler2 !is null) (*handler2)(element); } } } else { t = chop(*s,indexOf(*s,"<")); if (rawTextHandler.funcptr !is null) rawTextHandler(t); else if (textHandler.funcptr !is null) textHandler(decode(t,DecodeMode.LOOSE)); } } } /** * Returns that part of the element which has already been parsed */ override string toString() const { assert(elementStart.length >= s.length); return elementStart[0 .. elementStart.length - s.length]; } } private { template Check(string msg) { string old = s; void fail() { s = old; throw new Err(s,msg); } void fail(Err e) { s = old; throw new Err(s,msg,e); } void fail(string msg2) { fail(new Err(s,msg2)); } } void checkMisc(ref string s) // rule 27 { mixin Check!("Misc"); try { if (s.startsWith("",s); } catch(Err e) { fail(e); } } void checkPI(ref string s) // rule 16 { mixin Check!("PI"); try { checkLiteral("",s); } catch(Err e) { fail(e); } } void checkCDSect(ref string s) // rule 18 { mixin Check!("CDSect"); try { checkLiteral(cdata,s); checkEnd("]]>",s); } catch(Err e) { fail(e); } } void checkProlog(ref string s) // rule 22 { mixin Check!("Prolog"); try { /* The XML declaration is optional * http://www.w3.org/TR/2008/REC-xml-20081126/#NT-prolog */ opt!(checkXMLDecl)(s); star!(checkMisc)(s); opt!(seq!(checkDocTypeDecl,star!(checkMisc)))(s); } catch(Err e) { fail(e); } } void checkXMLDecl(ref string s) // rule 23 { mixin Check!("XMLDecl"); try { checkLiteral("",s); } catch(Err e) { fail(e); } } void checkVersionInfo(ref string s) // rule 24 { mixin Check!("VersionInfo"); try { checkSpace(s); checkLiteral("version",s); checkEq(s); quoted!(checkVersionNum)(s); } catch(Err e) { fail(e); } } void checkEq(ref string s) // rule 25 { mixin Check!("Eq"); try { opt!(checkSpace)(s); checkLiteral("=",s); opt!(checkSpace)(s); } catch(Err e) { fail(e); } } void checkVersionNum(ref string s) // rule 26 { mixin Check!("VersionNum"); munch(s,"a-zA-Z0-9_.:-"); if (s is old) fail(); } void checkDocTypeDecl(ref string s) // rule 28 { mixin Check!("DocTypeDecl"); try { checkLiteral("",s); } catch(Err e) { fail(e); } } void checkSDDecl(ref string s) // rule 32 { mixin Check!("SDDecl"); try { checkSpace(s); checkLiteral("standalone",s); checkEq(s); } catch(Err e) { fail(e); } int n = 0; if (s.startsWith("'yes'") || s.startsWith("\"yes\"")) n = 5; else if (s.startsWith("'no'" ) || s.startsWith("\"no\"" )) n = 4; else fail("standalone attribute value must be 'yes', \"yes\","~ " 'no' or \"no\""); s = s[n..$]; } void checkElement(ref string s) // rule 39 { mixin Check!("Element"); string sname,ename,t; try { checkTag(s,t,sname); } catch(Err e) { fail(e); } if (t == "STag") { try { checkContent(s); t = s; checkETag(s,ename); } catch(Err e) { fail(e); } if (sname != ename) { s = t; fail("end tag name \"" ~ ename ~ "\" differs from start tag name \""~sname~"\""); } } } // rules 40 and 44 void checkTag(ref string s, out string type, out string name) { mixin Check!("Tag"); try { type = "STag"; checkLiteral("<",s); checkName(s,name); star!(seq!(checkSpace,checkAttribute))(s); opt!(checkSpace)(s); if (s.length != 0 && s[0] == '/') { s = s[1..$]; type = "ETag"; } checkLiteral(">",s); } catch(Err e) { fail(e); } } void checkAttribute(ref string s) // rule 41 { mixin Check!("Attribute"); try { string name; checkName(s,name); checkEq(s); checkAttValue(s); } catch(Err e) { fail(e); } } void checkETag(ref string s, out string name) // rule 42 { mixin Check!("ETag"); try { checkLiteral("",s); } catch(Err e) { fail(e); } } void checkContent(ref string s) // rule 43 { mixin Check!("Content"); try { while (s.length != 0) { old = s; if (s.startsWith("&")) { checkReference(s); } else if (s.startsWith(" B EOS"; try { check(s); } catch (CheckException e) { assert(0, e.toString()); } } unittest { string s = q"EOS What & Up Second EOS"; auto xml = new DocumentParser(s); xml.onStartTag["Test"] = (ElementParser xml) { assert(xml.tag.attr["thing"] == "What & Up"); }; xml.onEndTag["Test"] = (in Element e) { assert(e.text() == "What & Up Second"); }; xml.parse(); } unittest { string s = ``; auto doc = new Document(s); assert(doc.toString() == s); } /** The base class for exceptions thrown by this module */ class XMLException : Exception { this(string msg) { super(msg); } } // Other exceptions /// Thrown during Comment constructor class CommentException : XMLException { private this(string msg) { super(msg); } } /// Thrown during CData constructor class CDataException : XMLException { private this(string msg) { super(msg); } } /// Thrown during XMLInstruction constructor class XIException : XMLException { private this(string msg) { super(msg); } } /// Thrown during ProcessingInstruction constructor class PIException : XMLException { private this(string msg) { super(msg); } } /// Thrown during Text constructor class TextException : XMLException { private this(string msg) { super(msg); } } /// Thrown during decode() class DecodeException : XMLException { private this(string msg) { super(msg); } } /// Thrown if comparing with wrong type class InvalidTypeException : XMLException { private this(string msg) { super(msg); } } /// Thrown when parsing for Tags class TagException : XMLException { private this(string msg) { super(msg); } } /** * Thrown during check() */ class CheckException : XMLException { CheckException err; /// Parent in hierarchy private string tail; /** * Name of production rule which failed to parse, * or specific error message */ string msg; size_t line = 0; /// Line number at which parse failure occurred size_t column = 0; /// Column number at which parse failure occurred private this(string tail,string msg,Err err=null) { super(null); this.tail = tail; this.msg = msg; this.err = err; } private void complete(string entire) { string head = entire[0..$-tail.length]; ptrdiff_t n = head.lastIndexOf('\n') + 1; line = head.count("\n") + 1; dstring t; transcode(head[n..$],t); column = t.length + 1; if (err !is null) err.complete(entire); } override string toString() const { string s; if (line != 0) s = format("Line %d, column %d: ",line,column); s ~= msg; s ~= '\n'; if (err !is null) s = err.toString() ~ s; return s; } } private alias Err = CheckException; // Private helper functions private { T toType(T)(Object o) { T t = cast(T)(o); if (t is null) { throw new InvalidTypeException("Attempt to compare a " ~ T.stringof ~ " with an instance of another type"); } return t; } string chop(ref string s, size_t n) { if (n == -1) n = s.length; string t = s[0..n]; s = s[n..$]; return t; } bool optc(ref string s, char c) { bool b = s.length != 0 && s[0] == c; if (b) s = s[1..$]; return b; } void reqc(ref string s, char c) { if (s.length == 0 || s[0] != c) throw new TagException(""); s = s[1..$]; } size_t hash(string s,size_t h=0) @trusted nothrow { return typeid(s).getHash(&s) + h; } // Definitions from the XML specification immutable CharTable=[0x9,0x9,0xA,0xA,0xD,0xD,0x20,0xD7FF,0xE000,0xFFFD, 0x10000,0x10FFFF]; immutable BaseCharTable=[0x0041,0x005A,0x0061,0x007A,0x00C0,0x00D6,0x00D8, 0x00F6,0x00F8,0x00FF,0x0100,0x0131,0x0134,0x013E,0x0141,0x0148,0x014A, 0x017E,0x0180,0x01C3,0x01CD,0x01F0,0x01F4,0x01F5,0x01FA,0x0217,0x0250, 0x02A8,0x02BB,0x02C1,0x0386,0x0386,0x0388,0x038A,0x038C,0x038C,0x038E, 0x03A1,0x03A3,0x03CE,0x03D0,0x03D6,0x03DA,0x03DA,0x03DC,0x03DC,0x03DE, 0x03DE,0x03E0,0x03E0,0x03E2,0x03F3,0x0401,0x040C,0x040E,0x044F,0x0451, 0x045C,0x045E,0x0481,0x0490,0x04C4,0x04C7,0x04C8,0x04CB,0x04CC,0x04D0, 0x04EB,0x04EE,0x04F5,0x04F8,0x04F9,0x0531,0x0556,0x0559,0x0559,0x0561, 0x0586,0x05D0,0x05EA,0x05F0,0x05F2,0x0621,0x063A,0x0641,0x064A,0x0671, 0x06B7,0x06BA,0x06BE,0x06C0,0x06CE,0x06D0,0x06D3,0x06D5,0x06D5,0x06E5, 0x06E6,0x0905,0x0939,0x093D,0x093D,0x0958,0x0961,0x0985,0x098C,0x098F, 0x0990,0x0993,0x09A8,0x09AA,0x09B0,0x09B2,0x09B2,0x09B6,0x09B9,0x09DC, 0x09DD,0x09DF,0x09E1,0x09F0,0x09F1,0x0A05,0x0A0A,0x0A0F,0x0A10,0x0A13, 0x0A28,0x0A2A,0x0A30,0x0A32,0x0A33,0x0A35,0x0A36,0x0A38,0x0A39,0x0A59, 0x0A5C,0x0A5E,0x0A5E,0x0A72,0x0A74,0x0A85,0x0A8B,0x0A8D,0x0A8D,0x0A8F, 0x0A91,0x0A93,0x0AA8,0x0AAA,0x0AB0,0x0AB2,0x0AB3,0x0AB5,0x0AB9,0x0ABD, 0x0ABD,0x0AE0,0x0AE0,0x0B05,0x0B0C,0x0B0F,0x0B10,0x0B13,0x0B28,0x0B2A, 0x0B30,0x0B32,0x0B33,0x0B36,0x0B39,0x0B3D,0x0B3D,0x0B5C,0x0B5D,0x0B5F, 0x0B61,0x0B85,0x0B8A,0x0B8E,0x0B90,0x0B92,0x0B95,0x0B99,0x0B9A,0x0B9C, 0x0B9C,0x0B9E,0x0B9F,0x0BA3,0x0BA4,0x0BA8,0x0BAA,0x0BAE,0x0BB5,0x0BB7, 0x0BB9,0x0C05,0x0C0C,0x0C0E,0x0C10,0x0C12,0x0C28,0x0C2A,0x0C33,0x0C35, 0x0C39,0x0C60,0x0C61,0x0C85,0x0C8C,0x0C8E,0x0C90,0x0C92,0x0CA8,0x0CAA, 0x0CB3,0x0CB5,0x0CB9,0x0CDE,0x0CDE,0x0CE0,0x0CE1,0x0D05,0x0D0C,0x0D0E, 0x0D10,0x0D12,0x0D28,0x0D2A,0x0D39,0x0D60,0x0D61,0x0E01,0x0E2E,0x0E30, 0x0E30,0x0E32,0x0E33,0x0E40,0x0E45,0x0E81,0x0E82,0x0E84,0x0E84,0x0E87, 0x0E88,0x0E8A,0x0E8A,0x0E8D,0x0E8D,0x0E94,0x0E97,0x0E99,0x0E9F,0x0EA1, 0x0EA3,0x0EA5,0x0EA5,0x0EA7,0x0EA7,0x0EAA,0x0EAB,0x0EAD,0x0EAE,0x0EB0, 0x0EB0,0x0EB2,0x0EB3,0x0EBD,0x0EBD,0x0EC0,0x0EC4,0x0F40,0x0F47,0x0F49, 0x0F69,0x10A0,0x10C5,0x10D0,0x10F6,0x1100,0x1100,0x1102,0x1103,0x1105, 0x1107,0x1109,0x1109,0x110B,0x110C,0x110E,0x1112,0x113C,0x113C,0x113E, 0x113E,0x1140,0x1140,0x114C,0x114C,0x114E,0x114E,0x1150,0x1150,0x1154, 0x1155,0x1159,0x1159,0x115F,0x1161,0x1163,0x1163,0x1165,0x1165,0x1167, 0x1167,0x1169,0x1169,0x116D,0x116E,0x1172,0x1173,0x1175,0x1175,0x119E, 0x119E,0x11A8,0x11A8,0x11AB,0x11AB,0x11AE,0x11AF,0x11B7,0x11B8,0x11BA, 0x11BA,0x11BC,0x11C2,0x11EB,0x11EB,0x11F0,0x11F0,0x11F9,0x11F9,0x1E00, 0x1E9B,0x1EA0,0x1EF9,0x1F00,0x1F15,0x1F18,0x1F1D,0x1F20,0x1F45,0x1F48, 0x1F4D,0x1F50,0x1F57,0x1F59,0x1F59,0x1F5B,0x1F5B,0x1F5D,0x1F5D,0x1F5F, 0x1F7D,0x1F80,0x1FB4,0x1FB6,0x1FBC,0x1FBE,0x1FBE,0x1FC2,0x1FC4,0x1FC6, 0x1FCC,0x1FD0,0x1FD3,0x1FD6,0x1FDB,0x1FE0,0x1FEC,0x1FF2,0x1FF4,0x1FF6, 0x1FFC,0x2126,0x2126,0x212A,0x212B,0x212E,0x212E,0x2180,0x2182,0x3041, 0x3094,0x30A1,0x30FA,0x3105,0x312C,0xAC00,0xD7A3]; immutable IdeographicTable=[0x3007,0x3007,0x3021,0x3029,0x4E00,0x9FA5]; immutable CombiningCharTable=[0x0300,0x0345,0x0360,0x0361,0x0483,0x0486, 0x0591,0x05A1,0x05A3,0x05B9,0x05BB,0x05BD,0x05BF,0x05BF,0x05C1,0x05C2, 0x05C4,0x05C4,0x064B,0x0652,0x0670,0x0670,0x06D6,0x06DC,0x06DD,0x06DF, 0x06E0,0x06E4,0x06E7,0x06E8,0x06EA,0x06ED,0x0901,0x0903,0x093C,0x093C, 0x093E,0x094C,0x094D,0x094D,0x0951,0x0954,0x0962,0x0963,0x0981,0x0983, 0x09BC,0x09BC,0x09BE,0x09BE,0x09BF,0x09BF,0x09C0,0x09C4,0x09C7,0x09C8, 0x09CB,0x09CD,0x09D7,0x09D7,0x09E2,0x09E3,0x0A02,0x0A02,0x0A3C,0x0A3C, 0x0A3E,0x0A3E,0x0A3F,0x0A3F,0x0A40,0x0A42,0x0A47,0x0A48,0x0A4B,0x0A4D, 0x0A70,0x0A71,0x0A81,0x0A83,0x0ABC,0x0ABC,0x0ABE,0x0AC5,0x0AC7,0x0AC9, 0x0ACB,0x0ACD,0x0B01,0x0B03,0x0B3C,0x0B3C,0x0B3E,0x0B43,0x0B47,0x0B48, 0x0B4B,0x0B4D,0x0B56,0x0B57,0x0B82,0x0B83,0x0BBE,0x0BC2,0x0BC6,0x0BC8, 0x0BCA,0x0BCD,0x0BD7,0x0BD7,0x0C01,0x0C03,0x0C3E,0x0C44,0x0C46,0x0C48, 0x0C4A,0x0C4D,0x0C55,0x0C56,0x0C82,0x0C83,0x0CBE,0x0CC4,0x0CC6,0x0CC8, 0x0CCA,0x0CCD,0x0CD5,0x0CD6,0x0D02,0x0D03,0x0D3E,0x0D43,0x0D46,0x0D48, 0x0D4A,0x0D4D,0x0D57,0x0D57,0x0E31,0x0E31,0x0E34,0x0E3A,0x0E47,0x0E4E, 0x0EB1,0x0EB1,0x0EB4,0x0EB9,0x0EBB,0x0EBC,0x0EC8,0x0ECD,0x0F18,0x0F19, 0x0F35,0x0F35,0x0F37,0x0F37,0x0F39,0x0F39,0x0F3E,0x0F3E,0x0F3F,0x0F3F, 0x0F71,0x0F84,0x0F86,0x0F8B,0x0F90,0x0F95,0x0F97,0x0F97,0x0F99,0x0FAD, 0x0FB1,0x0FB7,0x0FB9,0x0FB9,0x20D0,0x20DC,0x20E1,0x20E1,0x302A,0x302F, 0x3099,0x3099,0x309A,0x309A]; immutable DigitTable=[0x0030,0x0039,0x0660,0x0669,0x06F0,0x06F9,0x0966, 0x096F,0x09E6,0x09EF,0x0A66,0x0A6F,0x0AE6,0x0AEF,0x0B66,0x0B6F,0x0BE7, 0x0BEF,0x0C66,0x0C6F,0x0CE6,0x0CEF,0x0D66,0x0D6F,0x0E50,0x0E59,0x0ED0, 0x0ED9,0x0F20,0x0F29]; immutable ExtenderTable=[0x00B7,0x00B7,0x02D0,0x02D0,0x02D1,0x02D1,0x0387, 0x0387,0x0640,0x0640,0x0E46,0x0E46,0x0EC6,0x0EC6,0x3005,0x3005,0x3031, 0x3035,0x309D,0x309E,0x30FC,0x30FE]; bool lookup(const(int)[] table, int c) { while (table.length != 0) { auto m = (table.length >> 1) & ~1; if (c < table[m]) { table = table[0..m]; } else if (c > table[m+1]) { table = table[m+2..$]; } else return true; } return false; } string startOf(string s) { string r; foreach(char c;s) { r ~= (c < 0x20 || c > 0x7F) ? '.' : c; if (r.length >= 40) { r ~= "___"; break; } } return r; } void exit(string s=null) { throw new XMLException(s); } } ldc-1.1.0-beta3-src/runtime/phobos/std/stdio.d0000664000175000017500000040103412776215007017177 0ustar kaikai// Written in the D programming language. /** Standard I/O functions that extend $(B core.stdc.stdio). $(B core.stdc.stdio) is $(D_PARAM public)ally imported when importing $(B std.stdio). Source: $(PHOBOSSRC std/_stdio.d) Macros: WIKI=Phobos/StdStdio Copyright: Copyright Digital Mars 2007-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei Alexandrescu), Alex Rønne Petersen */ module std.stdio; public import core.stdc.stdio; import std.typecons;// Flag import std.stdiobase; import core.stdc.stddef;// wchar_t import std.range.primitives;// empty, front, isBidirectionalRange import std.traits;// Unqual, isSomeChar, isSomeString /++ If flag $(D KeepTerminator) is set to $(D KeepTerminator.yes), then the delimiter is included in the strings returned. +/ alias KeepTerminator = Flag!"keepTerminator"; version (CRuntime_Microsoft) { version = MICROSOFT_STDIO; } else version (CRuntime_DigitalMars) { // Specific to the way Digital Mars C does stdio version = DIGITAL_MARS_STDIO; } version (LDC) { version (MinGW) { version = MINGW_IO; version = NO_GETDELIM; } } version (CRuntime_Glibc) { // Specific to the way Gnu C does stdio version = GCC_IO; version = HAS_GETDELIM; } version (OSX) { version = GENERIC_IO; version = HAS_GETDELIM; } version (FreeBSD) { version = GENERIC_IO; version = HAS_GETDELIM; } version (NetBSD) { version = GENERIC_IO; version = HAS_GETDELIM; } version (Solaris) { version = GENERIC_IO; version = NO_GETDELIM; } version (CRuntime_Bionic) { version = GENERIC_IO; version = NO_GETDELIM; } // Character type used for operating system filesystem APIs version (Windows) { private alias FSChar = wchar; } else version (Posix) { private alias FSChar = char; } else static assert(0); version(Windows) { // core.stdc.stdio.fopen expects file names to be // encoded in CP_ACP on Windows instead of UTF-8. /+ Waiting for druntime pull 299 +/ extern (C) nothrow @nogc FILE* _wfopen(in wchar* filename, in wchar* mode); import core.sys.windows.windows : HANDLE; } version (DIGITAL_MARS_STDIO) { extern (C) { /* ** * Digital Mars under-the-hood C I/O functions. * Use _iobuf* for the unshared version of FILE*, * usable when the FILE is locked. */ nothrow: @nogc: int _fputc_nlock(int, _iobuf*); int _fputwc_nlock(int, _iobuf*); int _fgetc_nlock(_iobuf*); int _fgetwc_nlock(_iobuf*); int __fp_lock(FILE*); void __fp_unlock(FILE*); int setmode(int, int); } alias FPUTC = _fputc_nlock; alias FPUTWC = _fputwc_nlock; alias FGETC = _fgetc_nlock; alias FGETWC = _fgetwc_nlock; alias FLOCK = __fp_lock; alias FUNLOCK = __fp_unlock; alias _setmode = setmode; enum _O_BINARY = 0x8000; int _fileno(FILE* f) { return f._file; } alias fileno = _fileno; } else version (MICROSOFT_STDIO) { extern (C) { /* ** * Microsoft under-the-hood C I/O functions */ nothrow: @nogc: int _fputc_nolock(int, _iobuf*); int _fputwc_nolock(int, _iobuf*); int _fgetc_nolock(_iobuf*); int _fgetwc_nolock(_iobuf*); void _lock_file(FILE*); void _unlock_file(FILE*); int _setmode(int, int); int _fileno(FILE*); FILE* _fdopen(int, const (char)*); int _fseeki64(FILE*, long, int); long _ftelli64(FILE*); } alias FPUTC = _fputc_nolock; alias FPUTWC = _fputwc_nolock; alias FGETC = _fgetc_nolock; alias FGETWC = _fgetwc_nolock; alias FLOCK = _lock_file; alias FUNLOCK = _unlock_file; enum { _O_RDONLY = 0x0000, _O_APPEND = 0x0004, _O_TEXT = 0x4000, _O_BINARY = 0x8000, } } else version (GCC_IO) { /* ** * Gnu under-the-hood C I/O functions; see * http://gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html */ extern (C) { nothrow: @nogc: int fputc_unlocked(int, _iobuf*); int fputwc_unlocked(wchar_t, _iobuf*); int fgetc_unlocked(_iobuf*); int fgetwc_unlocked(_iobuf*); void flockfile(FILE*); void funlockfile(FILE*); private size_t fwrite_unlocked(const(void)* ptr, size_t size, size_t n, _iobuf *stream); } alias FPUTC = fputc_unlocked; alias FPUTWC = fputwc_unlocked; alias FGETC = fgetc_unlocked; alias FGETWC = fgetwc_unlocked; alias FLOCK = flockfile; alias FUNLOCK = funlockfile; } else version (MINGW_IO) { extern (C) { int setmode(int, int); } import core.sync.mutex; __gshared Mutex lockMutex; __gshared Mutex[uint] fileLocks; void flockfile(FILE* fp) { Mutex mutex; if (lockMutex is null) lockMutex = new Mutex; lockMutex.lock(); if (fp._file in fileLocks) { mutex = fileLocks[fp._file]; } else { mutex = new Mutex(); fileLocks[fp._file] = mutex; } mutex.lock(); lockMutex.unlock(); } void funlockfile(FILE* fp) { Mutex mutex; if (lockMutex is null) lockMutex = new Mutex; lockMutex.lock(); if (fp._file in fileLocks) { mutex = fileLocks[fp._file]; mutex.unlock(); } else { /* Should this be an error */ } lockMutex.unlock(); } int fputc_unlocked(int c, _iobuf* fp) { return fputc(c, cast(shared) fp); } int fputwc_unlocked(int c, _iobuf* fp) { return fputwc(cast(wchar_t)c, cast(shared) fp); } int fgetc_unlocked(_iobuf* fp) { return fgetc(cast(shared) fp); } int fgetwc_unlocked(_iobuf* fp) { return fgetwc(cast(shared) fp); } extern (C) { nothrow: @nogc: FILE* _fdopen(int, const (char)*); } alias fputc_unlocked FPUTC; alias fputwc_unlocked FPUTWC; alias fgetc_unlocked FGETC; alias fgetwc_unlocked FGETWC; alias flockfile FLOCK; alias funlockfile FUNLOCK; alias setmode _setmode; int _fileno(FILE* f) { return f._file; } alias _fileno fileno; enum { _O_RDONLY = 0x0000, _O_APPEND = 0x0008, _O_TEXT = 0x4000, _O_BINARY = 0x8000, } } else version (GENERIC_IO) { nothrow: @nogc: extern (C) { void flockfile(FILE*); void funlockfile(FILE*); } int fputc_unlocked(int c, _iobuf* fp) { return fputc(c, cast(shared) fp); } int fputwc_unlocked(wchar_t c, _iobuf* fp) { import core.stdc.wchar_ : fputwc; return fputwc(c, cast(shared) fp); } int fgetc_unlocked(_iobuf* fp) { return fgetc(cast(shared) fp); } int fgetwc_unlocked(_iobuf* fp) { import core.stdc.wchar_ : fgetwc; return fgetwc(cast(shared) fp); } alias FPUTC = fputc_unlocked; alias FPUTWC = fputwc_unlocked; alias FGETC = fgetc_unlocked; alias FGETWC = fgetwc_unlocked; alias FLOCK = flockfile; alias FUNLOCK = funlockfile; } else { static assert(0, "unsupported C I/O system"); } version(HAS_GETDELIM) extern(C) nothrow @nogc { ptrdiff_t getdelim(char**, size_t*, int, FILE*); // getline() always comes together with getdelim() ptrdiff_t getline(char**, size_t*, FILE*); } //------------------------------------------------------------------------------ struct ByRecord(Fields...) { private: import std.typecons : Tuple; File file; char[] line; Tuple!(Fields) current; string format; public: this(File f, string format) { assert(f.isOpen); file = f; this.format = format; popFront(); // prime the range } /// Range primitive implementations. @property bool empty() { return !file.isOpen; } /// Ditto @property ref Tuple!(Fields) front() { return current; } /// Ditto void popFront() { import std.conv : text; import std.exception : enforce; import std.format : formattedRead; import std.string : chomp; enforce(file.isOpen, "ByRecord: File must be open"); file.readln(line); if (!line.length) { file.detach(); } else { line = chomp(line); formattedRead(line, format, ¤t); enforce(line.empty, text("Leftover characters in record: `", line, "'")); } } } template byRecord(Fields...) { ByRecord!(Fields) byRecord(File f, string format) { return typeof(return)(f, format); } } /** Encapsulates a $(D FILE*). Generally D does not attempt to provide thin wrappers over equivalent functions in the C standard library, but manipulating $(D FILE*) values directly is unsafe and error-prone in many ways. The $(D File) type ensures safe manipulation, automatic file closing, and a lot of convenience. The underlying $(D FILE*) handle is maintained in a reference-counted manner, such that as soon as the last $(D File) variable bound to a given $(D FILE*) goes out of scope, the underlying $(D FILE*) is automatically closed. Example: ---- // test.d void main(string[] args) { auto f = File("test.txt", "w"); // open for writing f.write("Hello"); if (args.length > 1) { auto g = f; // now g and f write to the same file // internal reference count is 2 g.write(", ", args[1]); // g exits scope, reference count decreases to 1 } f.writeln("!"); // f exits scope, reference count falls to zero, // underlying $(D FILE*) is closed. } ---- $(CONSOLE % rdmd test.d Jimmy % cat test.txt Hello, Jimmy! % __ ) */ struct File { import std.traits : isScalarType, isArray; import std.range.primitives : ElementEncodingType; enum Orientation { unknown, narrow, wide } private struct Impl { FILE * handle = null; // Is null iff this Impl is closed by another File uint refs = uint.max / 2; bool isPopened; // true iff the stream has been created by popen() Orientation orientation; } private Impl* _p; private string _name; package this(FILE* handle, string name, uint refs = 1, bool isPopened = false) @trusted { import core.stdc.stdlib : malloc; import std.exception : enforce; assert(!_p); _p = cast(Impl*) enforce(malloc(Impl.sizeof), "Out of memory"); _p.handle = handle; _p.refs = refs; _p.isPopened = isPopened; _p.orientation = Orientation.unknown; _name = name; } /** Constructor taking the name of the file to open and the open mode. Copying one $(D File) object to another results in the two $(D File) objects referring to the same underlying file. The destructor automatically closes the file as soon as no $(D File) object refers to it anymore. Params: name = range or string representing the file _name stdioOpenmode = range or string represting the open mode (with the same semantics as in the C standard library $(WEB cplusplus.com/reference/clibrary/cstdio/fopen.html, fopen) function) Throws: $(D ErrnoException) if the file could not be opened. */ this(string name, in char[] stdioOpenmode = "rb") @safe { import std.conv : text; import std.exception : errnoEnforce; this(errnoEnforce(.fopen(name, stdioOpenmode), text("Cannot open file `", name, "' in mode `", stdioOpenmode, "'")), name); // MSVCRT workaround (issue 14422) version (MICROSOFT_STDIO) { bool append, update; foreach (c; stdioOpenmode) if (c == 'a') append = true; else if (c == '+') update = true; if (append && !update) seek(size); } } /// ditto this(R1, R2)(R1 name) if (isInputRange!R1 && isSomeChar!(ElementEncodingType!R1)) { import std.conv : to; this(name.to!string, "rb"); } /// ditto this(R1, R2)(R1 name, R2 mode) if (isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) && isInputRange!R2 && isSomeChar!(ElementEncodingType!R2)) { import std.conv : to; this(name.to!string, mode.to!string); } @safe unittest { static import std.file; import std.utf : byChar; auto deleteme = testFilename(); auto f = File(deleteme.byChar, "w".byChar); f.close(); std.file.remove(deleteme); } ~this() @safe { detach(); } this(this) @safe nothrow { if (!_p) return; assert(_p.refs); ++_p.refs; } /** Assigns a file to another. The target of the assignment gets detached from whatever file it was attached to, and attaches itself to the new file. */ void opAssign(File rhs) @safe { import std.algorithm : swap; swap(this, rhs); } /** First calls $(D detach) (throwing on failure), and then attempts to _open file $(D name) with mode $(D stdioOpenmode). The mode has the same semantics as in the C standard library $(WEB cplusplus.com/reference/clibrary/cstdio/fopen.html, fopen) function. Throws: $(D ErrnoException) in case of error. */ void open(string name, in char[] stdioOpenmode = "rb") @safe { detach(); this = File(name, stdioOpenmode); } /** First calls $(D detach) (throwing on failure), and then runs a command by calling the C standard library function $(WEB opengroup.org/onlinepubs/007908799/xsh/_popen.html, _popen). Throws: $(D ErrnoException) in case of error. */ version(Posix) void popen(string command, in char[] stdioOpenmode = "r") @safe { import std.exception : errnoEnforce; detach(); this = File(errnoEnforce(.popen(command, stdioOpenmode), "Cannot run command `"~command~"'"), command, 1, true); } /** First calls $(D detach) (throwing on failure), and then attempts to associate the given file descriptor with the $(D File). The mode must be compatible with the mode of the file descriptor. Throws: $(D ErrnoException) in case of error. */ void fdopen(int fd, in char[] stdioOpenmode = "rb") @safe { fdopen(fd, stdioOpenmode, null); } package void fdopen(int fd, in char[] stdioOpenmode, string name) @trusted { import std.internal.cstring : tempCString; import std.exception : errnoEnforce; auto modez = stdioOpenmode.tempCString(); detach(); version (DIGITAL_MARS_STDIO) { // This is a re-implementation of DMC's fdopen, but without the // mucking with the file descriptor. POSIX standard requires the // new fdopen'd file to retain the given file descriptor's // position. import core.stdc.stdio : fopen; auto fp = fopen("NUL", modez); errnoEnforce(fp, "Cannot open placeholder NUL stream"); FLOCK(fp); auto iob = cast(_iobuf*)fp; .close(iob._file); iob._file = fd; iob._flag &= ~_IOTRAN; FUNLOCK(fp); } else { version (Windows) // MSVCRT auto fp = _fdopen(fd, modez); else version (Posix) { import core.sys.posix.stdio : fdopen; auto fp = fdopen(fd, modez); } errnoEnforce(fp); } this = File(fp, name); } // Declare a dummy HANDLE to allow generating documentation // for Windows-only methods. version(StdDdoc) { version(Windows) {} else alias HANDLE = int; } /** First calls $(D detach) (throwing on failure), and then attempts to associate the given Windows $(D HANDLE) with the $(D File). The mode must be compatible with the access attributes of the handle. Windows only. Throws: $(D ErrnoException) in case of error. */ version(StdDdoc) void windowsHandleOpen(HANDLE handle, in char[] stdioOpenmode); version(Windows) void windowsHandleOpen(HANDLE handle, in char[] stdioOpenmode) { import std.exception : errnoEnforce; import std.format : format; // Create file descriptors from the handles version (DIGITAL_MARS_STDIO) auto fd = _handleToFD(handle, FHND_DEVICE); else // MSVCRT { int mode; modeLoop: foreach (c; stdioOpenmode) switch (c) { case 'r': mode |= _O_RDONLY; break; case '+': mode &=~_O_RDONLY; break; case 'a': mode |= _O_APPEND; break; case 'b': mode |= _O_BINARY; break; case 't': mode |= _O_TEXT; break; case ',': break modeLoop; default: break; } auto fd = _open_osfhandle(cast(intptr_t)handle, mode); } errnoEnforce(fd >= 0, "Cannot open Windows HANDLE"); fdopen(fd, stdioOpenmode, "HANDLE(%s)".format(handle)); } /** Returns $(D true) if the file is opened. */ @property bool isOpen() const @safe pure nothrow { return _p !is null && _p.handle; } /** Returns $(D true) if the file is at end (see $(WEB cplusplus.com/reference/clibrary/cstdio/feof.html, feof)). Throws: $(D Exception) if the file is not opened. */ @property bool eof() const @trusted pure { import std.exception : enforce; enforce(_p && _p.handle, "Calling eof() against an unopened file."); return .feof(cast(FILE*) _p.handle) != 0; } /** Returns the name of the last opened file, if any. If a $(D File) was created with $(LREF tmpfile) and $(LREF wrapFile) it has no name.*/ @property string name() const @safe pure nothrow { return _name; } /** If the file is not opened, returns $(D true). Otherwise, returns $(WEB cplusplus.com/reference/clibrary/cstdio/ferror.html, ferror) for the file handle. */ @property bool error() const @trusted pure nothrow { return !isOpen || .ferror(cast(FILE*) _p.handle); } @safe unittest { // Issue 12349 static import std.file; auto deleteme = testFilename(); auto f = File(deleteme, "w"); scope(exit) std.file.remove(deleteme); f.close(); assert(f.error); } /** Detaches from the underlying file. If the sole owner, calls $(D close). Throws: $(D ErrnoException) on failure if closing the file. */ void detach() @safe { if (!_p) return; if (_p.refs == 1) close(); else { assert(_p.refs); --_p.refs; _p = null; } } @safe unittest { static import std.file; auto deleteme = testFilename(); scope(exit) std.file.remove(deleteme); auto f = File(deleteme, "w"); { auto f2 = f; f2.detach(); } assert(f._p.refs == 1); f.close(); } /** If the file was unopened, succeeds vacuously. Otherwise closes the file (by calling $(WEB cplusplus.com/reference/clibrary/cstdio/fclose.html, fclose)), throwing on error. Even if an exception is thrown, afterwards the $(D File) object is empty. This is different from $(D detach) in that it always closes the file; consequently, all other $(D File) objects referring to the same handle will see a closed file henceforth. Throws: $(D ErrnoException) on error. */ void close() @trusted { import core.stdc.stdlib : free; import std.exception : errnoEnforce; if (!_p) return; // succeed vacuously scope(exit) { assert(_p.refs); if(!--_p.refs) free(_p); _p = null; // start a new life } if (!_p.handle) return; // Impl is closed by another File scope(exit) _p.handle = null; // nullify the handle anyway version (Posix) { import std.format : format; import core.sys.posix.stdio : pclose; if (_p.isPopened) { auto res = pclose(_p.handle); errnoEnforce(res != -1, "Could not close pipe `"~_name~"'"); errnoEnforce(res == 0, format("Command returned %d", res)); return; } } //fprintf(core.stdc.stdio.stderr, ("Closing file `"~name~"`.\n\0").ptr); errnoEnforce(.fclose(_p.handle) == 0, "Could not close file `"~_name~"'"); } /** If the file is not opened, succeeds vacuously. Otherwise, returns $(WEB cplusplus.com/reference/clibrary/cstdio/_clearerr.html, _clearerr) for the file handle. */ void clearerr() @safe pure nothrow { _p is null || _p.handle is null || .clearerr(_p.handle); } /** Flushes the C $(D FILE) buffers. Calls $(WEB cplusplus.com/reference/clibrary/cstdio/_fflush.html, _fflush) for the file handle. Throws: $(D Exception) if the file is not opened or if the call to $(D fflush) fails. */ void flush() @trusted { import std.exception : enforce, errnoEnforce; enforce(isOpen, "Attempting to flush() in an unopened file"); errnoEnforce(.fflush(_p.handle) == 0); } @safe unittest { // Issue 12349 static import std.file; import std.exception: assertThrown; auto deleteme = testFilename(); auto f = File(deleteme, "w"); scope(exit) std.file.remove(deleteme); f.close(); assertThrown(f.flush()); } /** Forces any data buffered by the OS to be written to disk. Call $(LREF flush) before calling this function to flush the C $(D FILE) buffers first. This function calls $(WEB msdn.microsoft.com/en-us/library/windows/desktop/aa364439%28v=vs.85%29.aspx, $(D FlushFileBuffers)) on Windows and $(WEB pubs.opengroup.org/onlinepubs/7908799/xsh/fsync.html, $(D fsync)) on POSIX for the file handle. Throws: $(D Exception) if the file is not opened or if the OS call fails. */ void sync() @trusted { import std.exception : enforce, errnoEnforce; enforce(isOpen, "Attempting to sync() an unopened file"); version (Windows) wenforce(FlushFileBuffers(windowsHandle), "FlushFileBuffers failed"); else { import core.sys.posix.unistd : fsync; errnoEnforce(fsync(fileno) == 0, "fsync failed"); } } /** Calls $(WEB cplusplus.com/reference/clibrary/cstdio/fread.html, fread) for the file handle. The number of items to read and the size of each item is inferred from the size and type of the input array, respectively. Returns: The slice of $(D buffer) containing the data that was actually read. This will be shorter than $(D buffer) if EOF was reached before the buffer could be filled. Throws: $(D Exception) if $(D buffer) is empty. $(D ErrnoException) if the file is not opened or the call to $(D fread) fails. $(D rawRead) always reads in binary mode on Windows. */ T[] rawRead(T)(T[] buffer) { import std.exception : errnoEnforce; if (!buffer.length) throw new Exception("rawRead must take a non-empty buffer"); version(Windows) { immutable fd = ._fileno(_p.handle); immutable mode = ._setmode(fd, _O_BINARY); scope(exit) ._setmode(fd, mode); version(DIGITAL_MARS_STDIO) { import core.atomic; // @@@BUG@@@ 4243 immutable info = __fhnd_info[fd]; atomicOp!"&="(__fhnd_info[fd], ~FHND_TEXT); scope(exit) __fhnd_info[fd] = info; } } immutable freadResult = fread(buffer.ptr, T.sizeof, buffer.length, _p.handle); assert (freadResult <= buffer.length); // fread return guarantee if (freadResult != buffer.length) // error or eof { errnoEnforce(!error); return buffer[0 .. freadResult]; } return buffer; } /// unittest { static import std.file; auto testFile = testFilename(); std.file.write(testFile, "\r\n\n\r\n"); scope(exit) std.file.remove(testFile); auto f = File(testFile, "r"); auto buf = f.rawRead(new char[5]); f.close(); assert(buf == "\r\n\n\r\n"); } /** Calls $(WEB cplusplus.com/reference/clibrary/cstdio/fwrite.html, fwrite) for the file handle. The number of items to write and the size of each item is inferred from the size and type of the input array, respectively. An error is thrown if the buffer could not be written in its entirety. $(D rawWrite) always writes in binary mode on Windows. Throws: $(D ErrnoException) if the file is not opened or if the call to $(D fwrite) fails. */ void rawWrite(T)(in T[] buffer) { import std.conv : text; import std.exception : errnoEnforce; version(Windows) { flush(); // before changing translation mode immutable fd = ._fileno(_p.handle); immutable mode = ._setmode(fd, _O_BINARY); scope(exit) ._setmode(fd, mode); version(DIGITAL_MARS_STDIO) { import core.atomic; // @@@BUG@@@ 4243 immutable info = __fhnd_info[fd]; atomicOp!"&="(__fhnd_info[fd], ~FHND_TEXT); scope(exit) __fhnd_info[fd] = info; } scope(exit) flush(); // before restoring translation mode } auto result = .fwrite(buffer.ptr, T.sizeof, buffer.length, _p.handle); if (result == result.max) result = 0; errnoEnforce(result == buffer.length, text("Wrote ", result, " instead of ", buffer.length, " objects of type ", T.stringof, " to file `", _name, "'")); } /// unittest { static import std.file; auto testFile = testFilename(); auto f = File(testFile, "w"); scope(exit) std.file.remove(testFile); f.rawWrite("\r\n\n\r\n"); f.close(); assert(std.file.read(testFile) == "\r\n\n\r\n"); } /** Calls $(WEB cplusplus.com/reference/clibrary/cstdio/fseek.html, fseek) for the file handle. Throws: $(D Exception) if the file is not opened. $(D ErrnoException) if the call to $(D fseek) fails. */ void seek(long offset, int origin = SEEK_SET) @trusted { import std.exception : enforce, errnoEnforce; import std.conv : to, text; enforce(isOpen, "Attempting to seek() in an unopened file"); version (Windows) { version (CRuntime_Microsoft) { alias fseekFun = _fseeki64; alias off_t = long; } else { alias fseekFun = fseek; alias off_t = int; } } else version (Posix) { import core.sys.posix.stdio : fseeko, off_t; alias fseekFun = fseeko; } errnoEnforce(fseekFun(_p.handle, to!off_t(offset), origin) == 0, "Could not seek in file `"~_name~"'"); } unittest { static import std.file; auto deleteme = testFilename(); auto f = File(deleteme, "w+"); scope(exit) { f.close(); std.file.remove(deleteme); } f.rawWrite("abcdefghijklmnopqrstuvwxyz"); f.seek(7); assert(f.readln() == "hijklmnopqrstuvwxyz"); import std.conv : text; version (CRuntime_DigitalMars) auto bigOffset = int.max - 100; else version (CRuntime_Bionic) auto bigOffset = int.max - 100; else auto bigOffset = cast(ulong) int.max + 100; f.seek(bigOffset); assert(f.tell == bigOffset, text(f.tell)); // Uncomment the tests below only if you want to wait for // a long time // f.rawWrite("abcdefghijklmnopqrstuvwxyz"); // f.seek(-3, SEEK_END); // assert(f.readln() == "xyz"); } /** Calls $(WEB cplusplus.com/reference/clibrary/cstdio/ftell.html, ftell) for the managed file handle. Throws: $(D Exception) if the file is not opened. $(D ErrnoException) if the call to $(D ftell) fails. */ @property ulong tell() const @trusted { import std.exception : enforce, errnoEnforce; enforce(isOpen, "Attempting to tell() in an unopened file"); version (Windows) { version (CRuntime_Microsoft) immutable result = _ftelli64(cast(FILE*) _p.handle); else immutable result = ftell(cast(FILE*) _p.handle); } else version (Posix) { import core.sys.posix.stdio : ftello; immutable result = ftello(cast(FILE*) _p.handle); } errnoEnforce(result != -1, "Query ftell() failed for file `"~_name~"'"); return result; } /// unittest { static import std.file; import std.conv : text; auto testFile = testFilename(); std.file.write(testFile, "abcdefghijklmnopqrstuvwqxyz"); scope(exit) { std.file.remove(testFile); } auto f = File(testFile); auto a = new ubyte[4]; f.rawRead(a); assert(f.tell == 4, text(f.tell)); } /** Calls $(WEB cplusplus.com/reference/clibrary/cstdio/_rewind.html, _rewind) for the file handle. Throws: $(D Exception) if the file is not opened. */ void rewind() @safe { import std.exception : enforce; enforce(isOpen, "Attempting to rewind() an unopened file"); .rewind(_p.handle); } /** Calls $(WEB cplusplus.com/reference/clibrary/cstdio/_setvbuf.html, _setvbuf) for the file handle. Throws: $(D Exception) if the file is not opened. $(D ErrnoException) if the call to $(D setvbuf) fails. */ void setvbuf(size_t size, int mode = _IOFBF) @trusted { import std.exception : enforce, errnoEnforce; enforce(isOpen, "Attempting to call setvbuf() on an unopened file"); errnoEnforce(.setvbuf(_p.handle, null, mode, size) == 0, "Could not set buffering for file `"~_name~"'"); } /** Calls $(WEB cplusplus.com/reference/clibrary/cstdio/_setvbuf.html, _setvbuf) for the file handle. Throws: $(D Exception) if the file is not opened. $(D ErrnoException) if the call to $(D setvbuf) fails. */ void setvbuf(void[] buf, int mode = _IOFBF) @trusted { import std.exception : enforce, errnoEnforce; enforce(isOpen, "Attempting to call setvbuf() on an unopened file"); errnoEnforce(.setvbuf(_p.handle, cast(char*) buf.ptr, mode, buf.length) == 0, "Could not set buffering for file `"~_name~"'"); } version(Windows) { import core.sys.windows.windows; private BOOL lockImpl(alias F, Flags...)(ulong start, ulong length, Flags flags) { if (!start && !length) length = ulong.max; ULARGE_INTEGER liStart = void, liLength = void; liStart.QuadPart = start; liLength.QuadPart = length; OVERLAPPED overlapped; overlapped.Offset = liStart.LowPart; overlapped.OffsetHigh = liStart.HighPart; overlapped.hEvent = null; return F(windowsHandle, flags, 0, liLength.LowPart, liLength.HighPart, &overlapped); } private static T wenforce(T)(T cond, string str) { import std.windows.syserror; if (cond) return cond; throw new Exception(str ~ ": " ~ sysErrorString(GetLastError())); } } version(Posix) { private int lockImpl(int operation, short l_type, ulong start, ulong length) { import std.conv : to; import core.sys.posix.fcntl : fcntl, flock, off_t; import core.sys.posix.unistd : getpid; flock fl = void; fl.l_type = l_type; fl.l_whence = SEEK_SET; fl.l_start = to!off_t(start); fl.l_len = to!off_t(length); fl.l_pid = getpid(); return fcntl(fileno, operation, &fl); } } /** Locks the specified file segment. If the file segment is already locked by another process, waits until the existing lock is released. If both $(D start) and $(D length) are zero, the entire file is locked. Locks created using $(D lock) and $(D tryLock) have the following properties: $(UL $(LI All locks are automatically released when the process terminates.) $(LI Locks are not inherited by child processes.) $(LI Closing a file will release all locks associated with the file. On POSIX, even locks acquired via a different $(D File) will be released as well.) $(LI Not all NFS implementations correctly implement file locking.) ) */ void lock(LockType lockType = LockType.readWrite, ulong start = 0, ulong length = 0) { import std.exception : enforce, errnoEnforce; enforce(isOpen, "Attempting to call lock() on an unopened file"); version (Posix) { import core.sys.posix.fcntl : F_RDLCK, F_SETLKW, F_WRLCK; immutable short type = lockType == LockType.readWrite ? F_WRLCK : F_RDLCK; errnoEnforce(lockImpl(F_SETLKW, type, start, length) != -1, "Could not set lock for file `"~_name~"'"); } else version(Windows) { immutable type = lockType == LockType.readWrite ? LOCKFILE_EXCLUSIVE_LOCK : 0; wenforce(lockImpl!LockFileEx(start, length, type), "Could not set lock for file `"~_name~"'"); } else static assert(false); } /** Attempts to lock the specified file segment. If both $(D start) and $(D length) are zero, the entire file is locked. Returns: $(D true) if the lock was successful, and $(D false) if the specified file segment was already locked. */ bool tryLock(LockType lockType = LockType.readWrite, ulong start = 0, ulong length = 0) { import std.exception : enforce, errnoEnforce; enforce(isOpen, "Attempting to call tryLock() on an unopened file"); version (Posix) { import core.stdc.errno : EACCES, EAGAIN, errno; import core.sys.posix.fcntl : F_RDLCK, F_SETLK, F_WRLCK; immutable short type = lockType == LockType.readWrite ? F_WRLCK : F_RDLCK; immutable res = lockImpl(F_SETLK, type, start, length); if (res == -1 && (errno == EACCES || errno == EAGAIN)) return false; errnoEnforce(res != -1, "Could not set lock for file `"~_name~"'"); return true; } else version(Windows) { immutable type = lockType == LockType.readWrite ? LOCKFILE_EXCLUSIVE_LOCK : 0; immutable res = lockImpl!LockFileEx(start, length, type | LOCKFILE_FAIL_IMMEDIATELY); if (!res && (GetLastError() == ERROR_IO_PENDING || GetLastError() == ERROR_LOCK_VIOLATION)) return false; wenforce(res, "Could not set lock for file `"~_name~"'"); return true; } else static assert(false); } /** Removes the lock over the specified file segment. */ void unlock(ulong start = 0, ulong length = 0) { import std.exception : enforce, errnoEnforce; enforce(isOpen, "Attempting to call unlock() on an unopened file"); version (Posix) { import core.sys.posix.fcntl : F_SETLK, F_UNLCK; errnoEnforce(lockImpl(F_SETLK, F_UNLCK, start, length) != -1, "Could not remove lock for file `"~_name~"'"); } else version(Windows) { wenforce(lockImpl!UnlockFileEx(start, length), "Could not remove lock for file `"~_name~"'"); } else static assert(false); } version(Windows) unittest { static import std.file; auto deleteme = testFilename(); scope(exit) std.file.remove(deleteme); auto f = File(deleteme, "wb"); assert(f.tryLock()); auto g = File(deleteme, "wb"); assert(!g.tryLock()); assert(!g.tryLock(LockType.read)); f.unlock(); f.lock(LockType.read); assert(!g.tryLock()); assert(g.tryLock(LockType.read)); f.unlock(); g.unlock(); } version(Posix) unittest { static import std.file; auto deleteme = testFilename(); scope(exit) std.file.remove(deleteme); // Since locks are per-process, we cannot test lock failures within // the same process. fork() is used to create a second process. static void runForked(void delegate() code) { import core.stdc.stdlib : exit; import core.sys.posix.unistd; import core.sys.posix.sys.wait; int child, status; if ((child = fork()) == 0) { code(); exit(0); } else { assert(wait(&status) != -1); assert(status == 0, "Fork crashed"); } } auto f = File(deleteme, "w+b"); runForked ({ auto g = File(deleteme, "a+b"); assert(g.tryLock()); g.unlock(); assert(g.tryLock(LockType.read)); }); assert(f.tryLock()); runForked ({ auto g = File(deleteme, "a+b"); assert(!g.tryLock()); assert(!g.tryLock(LockType.read)); }); f.unlock(); f.lock(LockType.read); runForked ({ auto g = File(deleteme, "a+b"); assert(!g.tryLock()); assert(g.tryLock(LockType.read)); g.unlock(); }); f.unlock(); } /** Writes its arguments in text format to the file. Throws: $(D Exception) if the file is not opened. $(D ErrnoException) on an error writing to the file. */ void write(S...)(S args) { import std.traits : isBoolean, isIntegral, isAggregateType; auto w = lockingTextWriter(); foreach (arg; args) { alias A = typeof(arg); static if (isAggregateType!A || is(A == enum)) { import std.format : formattedWrite; formattedWrite(w, "%s", arg); } else static if (isSomeString!A) { import std.range.primitives : put; put(w, arg); } else static if (isIntegral!A) { import std.conv : toTextRange; toTextRange(arg, w); } else static if (isBoolean!A) { put(w, arg ? "true" : "false"); } else static if (isSomeChar!A) { import std.range.primitives : put; put(w, arg); } else { import std.format : formattedWrite; // Most general case formattedWrite(w, "%s", arg); } } } /** Writes its arguments in text format to the file, followed by a newline. Throws: $(D Exception) if the file is not opened. $(D ErrnoException) on an error writing to the file. */ void writeln(S...)(S args) { write(args, '\n'); } /** Writes its arguments in text format to the file, according to the format in the first argument. Throws: $(D Exception) if the file is not opened. $(D ErrnoException) on an error writing to the file. */ void writef(Char, A...)(in Char[] fmt, A args) { import std.format : formattedWrite; formattedWrite(lockingTextWriter(), fmt, args); } /** Writes its arguments in text format to the file, according to the format in the first argument, followed by a newline. Throws: $(D Exception) if the file is not opened. $(D ErrnoException) on an error writing to the file. */ void writefln(Char, A...)(in Char[] fmt, A args) { import std.format : formattedWrite; auto w = lockingTextWriter(); formattedWrite(w, fmt, args); w.put('\n'); } /** Read line from the file handle and return it as a specified type. This version manages its own read buffer, which means one memory allocation per call. If you are not retaining a reference to the read data, consider the $(D File.readln(buf)) version, which may offer better performance as it can reuse its read buffer. Params: S = Template parameter; the type of the allocated buffer, and the type returned. Defaults to $(D string). terminator = Line terminator (by default, $(D '\n')). Note: String terminators are not supported due to ambiguity with readln(buf) below. Returns: The line that was read, including the line terminator character. Throws: $(D StdioException) on I/O error, or $(D UnicodeException) on Unicode conversion error. Example: --- // Reads $(D stdin) and writes it to $(D stdout). import std.stdio; void main() { string line; while ((line = stdin.readln()) !is null) write(line); } --- */ S readln(S = string)(dchar terminator = '\n') if (isSomeString!S) { Unqual!(ElementEncodingType!S)[] buf; readln(buf, terminator); return cast(S)buf; } unittest { static import std.file; import std.algorithm : equal; import std.meta : AliasSeq; auto deleteme = testFilename(); std.file.write(deleteme, "hello\nworld\n"); scope(exit) std.file.remove(deleteme); foreach (String; AliasSeq!(string, char[], wstring, wchar[], dstring, dchar[])) { auto witness = [ "hello\n", "world\n" ]; auto f = File(deleteme); uint i = 0; String buf; while ((buf = f.readln!String()).length) { assert(i < witness.length); assert(equal(buf, witness[i++])); } assert(i == witness.length); } } unittest { static import std.file; import std.typecons : Tuple; auto deleteme = testFilename(); std.file.write(deleteme, "cześć \U0002000D"); scope(exit) std.file.remove(deleteme); uint[] lengths = [12,8,7]; foreach (uint i, C; Tuple!(char, wchar, dchar).Types) { immutable(C)[] witness = "cześć \U0002000D"; auto buf = File(deleteme).readln!(immutable(C)[])(); assert(buf.length == lengths[i]); assert(buf == witness); } } /** Read line from the file handle and write it to $(D buf[]), including terminating character. This can be faster than $(D line = File.readln()) because you can reuse the buffer for each call. Note that reusing the buffer means that you must copy the previous contents if you wish to retain them. Params: buf = Buffer used to store the resulting line data. buf is resized as necessary. terminator = Line terminator (by default, $(D '\n')). Use $(XREF ascii, newline) for portability (unless the file was opened in text mode). Returns: 0 for end of file, otherwise number of characters read Throws: $(D StdioException) on I/O error, or $(D UnicodeException) on Unicode conversion error. Example: --- // Read lines from $(D stdin) into a string // Ignore lines starting with '#' // Write the string to $(D stdout) void main() { string output; char[] buf; while (stdin.readln(buf)) { if (buf[0] == '#') continue; output ~= buf; } write(output); } --- This method can be more efficient than the one in the previous example because $(D stdin.readln(buf)) reuses (if possible) memory allocated for $(D buf), whereas $(D line = stdin.readln()) makes a new memory allocation for every line. For even better performance you can help $(D readln) by passing in a large buffer to avoid memory reallocations. This can be done by reusing the largest buffer returned by $(D readln): Example: --- // Read lines from $(D stdin) and count words void main() { char[] buf; size_t words = 0; while (!stdin.eof) { char[] line = buf; stdin.readln(line); if (line.length > buf.length) buf = line; words += line.split.length; } writeln(words); } --- This is actually what $(LREF byLine) does internally, so its usage is recommended if you want to process a complete file. */ size_t readln(C)(ref C[] buf, dchar terminator = '\n') if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum)) { import std.exception : enforce; static if (is(C == char)) { enforce(_p && _p.handle, "Attempt to read from an unopened file."); if (_p.orientation == Orientation.unknown) { import core.stdc.wchar_ : fwide; auto w = fwide(_p.handle, 0); if (w < 0) _p.orientation = Orientation.narrow; else if (w > 0) _p.orientation = Orientation.wide; } return readlnImpl(_p.handle, buf, terminator, _p.orientation); } else { // TODO: optimize this string s = readln(terminator); buf.length = 0; if (!s.length) return 0; foreach (C c; s) { buf ~= c; } return buf.length; } } unittest { static import std.file; auto deleteme = testFilename(); std.file.write(deleteme, "123\n456789"); scope(exit) std.file.remove(deleteme); auto file = File(deleteme); char[] buffer = new char[10]; char[] line = buffer; file.readln(line); auto beyond = line.length; buffer[beyond] = 'a'; file.readln(line); // should not write buffer beyond line assert(buffer[beyond] == 'a'); } unittest // bugzilla 15293 { static import std.file; auto deleteme = testFilename(); std.file.write(deleteme, "a\n\naa"); scope(exit) std.file.remove(deleteme); auto file = File(deleteme); char[] buffer; char[] line; file.readln(buffer, '\n'); line = buffer; file.readln(line, '\n'); line = buffer; file.readln(line, '\n'); assert(line[0 .. 1].capacity == 0); } /** ditto */ size_t readln(C, R)(ref C[] buf, R terminator) if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) && isBidirectionalRange!R && is(typeof(terminator.front == dchar.init))) { import std.algorithm : endsWith, swap; import std.range.primitives : back; auto last = terminator.back; C[] buf2; swap(buf, buf2); for (;;) { if (!readln(buf2, last) || endsWith(buf2, terminator)) { if (buf.empty) { buf = buf2; } else { buf ~= buf2; } break; } buf ~= buf2; } return buf.length; } unittest { static import std.file; import std.typecons : Tuple; auto deleteme = testFilename(); std.file.write(deleteme, "hello\n\rworld\nhow\n\rare ya"); scope(exit) std.file.remove(deleteme); foreach (C; Tuple!(char, wchar, dchar).Types) { immutable(C)[][] witness = [ "hello\n\r", "world\nhow\n\r", "are ya" ]; auto f = File(deleteme); uint i = 0; C[] buf; while (f.readln(buf, "\n\r")) { assert(i < witness.length); assert(buf == witness[i++]); } assert(buf.length==0); } } /** * Read data from the file according to the specified * $(LINK2 std_format.html#_format-string, format specifier) using * $(XREF _format,formattedRead). */ uint readf(Data...)(in char[] format, Data data) { import std.format : formattedRead; assert(isOpen); auto input = LockingTextReader(this); return formattedRead(input, format, data); } /// unittest { static import std.file; auto deleteme = testFilename(); std.file.write(deleteme, "hello\nworld\ntrue\nfalse\n"); scope(exit) std.file.remove(deleteme); string s; auto f = File(deleteme); f.readf("%s\n", &s); assert(s == "hello", "["~s~"]"); f.readf("%s\n", &s); assert(s == "world", "["~s~"]"); // Issue 11698 bool b1, b2; f.readf("%s\n%s\n", &b1, &b2); assert(b1 == true && b2 == false); } /** Returns a temporary file by calling $(WEB cplusplus.com/reference/clibrary/cstdio/_tmpfile.html, _tmpfile). Note that the created file has no $(LREF name).*/ static File tmpfile() @safe { import std.exception : errnoEnforce; return File(errnoEnforce(.tmpfile(), "Could not create temporary file with tmpfile()"), null); } /** Unsafe function that wraps an existing $(D FILE*). The resulting $(D File) never takes the initiative in closing the file. Note that the created file has no $(LREF name)*/ /*private*/ static File wrapFile(FILE* f) @safe { import std.exception : enforce; return File(enforce(f, "Could not wrap null FILE*"), null, /*uint.max / 2*/ 9999); } /** Returns the $(D FILE*) corresponding to this object. */ FILE* getFP() @safe pure { import std.exception : enforce; enforce(_p && _p.handle, "Attempting to call getFP() on an unopened file"); return _p.handle; } unittest { static import core.stdc.stdio; assert(stdout.getFP() == core.stdc.stdio.stdout); } /** Returns the file number corresponding to this object. */ /*version(Posix) */@property int fileno() const @trusted { import std.exception : enforce; enforce(isOpen, "Attempting to call fileno() on an unopened file"); return .fileno(cast(FILE*) _p.handle); } /** Returns the underlying operating system $(D HANDLE) (Windows only). */ version(StdDdoc) @property HANDLE windowsHandle(); version(Windows) @property HANDLE windowsHandle() { version (DIGITAL_MARS_STDIO) return _fdToHandle(fileno); else return cast(HANDLE)_get_osfhandle(fileno); } // Note: This was documented until 2013/08 /* Range that reads one line at a time. Returned by $(LREF byLine). Allows to directly use range operations on lines of a file. */ struct ByLine(Char, Terminator) { private: import std.typecons; /* Ref-counting stops the source range's Impl * from getting out of sync after the range is copied, e.g. * when accessing range.front, then using std.range.take, * then accessing range.front again. */ alias PImpl = RefCounted!(Impl, RefCountedAutoInitialize.no); PImpl impl; static if (isScalarType!Terminator) enum defTerm = '\n'; else enum defTerm = cast(Terminator)"\n"; public: this(File f, KeepTerminator kt = KeepTerminator.no, Terminator terminator = defTerm) { impl = PImpl(f, kt, terminator); } @property bool empty() { return impl.refCountedPayload.empty; } @property Char[] front() { return impl.refCountedPayload.front; } void popFront() { impl.refCountedPayload.popFront(); } private: struct Impl { private: File file; Char[] line; Char[] buffer; Terminator terminator; KeepTerminator keepTerminator; public: this(File f, KeepTerminator kt, Terminator terminator) { file = f; this.terminator = terminator; keepTerminator = kt; popFront(); } // Range primitive implementations. @property bool empty() { return line is null; } @property Char[] front() { return line; } void popFront() { import std.algorithm : endsWith; assert(file.isOpen); line = buffer; file.readln(line, terminator); if (line.length > buffer.length) { buffer = line; } if (line.empty) { file.detach(); line = null; } else if (keepTerminator == KeepTerminator.no && endsWith(line, terminator)) { static if (isScalarType!Terminator) enum tlen = 1; else static if (isArray!Terminator) { static assert( is(Unqual!(ElementEncodingType!Terminator) == Char)); const tlen = terminator.length; } else static assert(false); line = line.ptr[0 .. line.length - tlen]; } } } } /** Returns an input range set up to read from the file handle one line at a time. The element type for the range will be $(D Char[]). Range primitives may throw $(D StdioException) on I/O error. Note: Each $(D front) will not persist after $(D popFront) is called, so the caller must copy its contents (e.g. by calling $(D to!string)) when retention is needed. If the caller needs to retain a copy of every line, use the $(LREF byLineCopy) function instead. Params: Char = Character type for each line, defaulting to $(D char). keepTerminator = Use $(D KeepTerminator.yes) to include the terminator at the end of each line. terminator = Line separator ($(D '\n') by default). Use $(XREF ascii, newline) for portability (unless the file was opened in text mode). Example: ---- import std.algorithm, std.stdio, std.string; // Count words in a file using ranges. void main() { auto file = File("file.txt"); // Open for reading const wordCount = file.byLine() // Read lines .map!split // Split into words .map!(a => a.length) // Count words per line .sum(); // Total word count writeln(wordCount); } ---- Example: ---- import std.range, std.stdio; // Read lines using foreach. void main() { auto file = File("file.txt"); // Open for reading auto range = file.byLine(); // Print first three lines foreach (line; range.take(3)) writeln(line); // Print remaining lines beginning with '#' foreach (line; range) { if (!line.empty && line[0] == '#') writeln(line); } } ---- Notice that neither example accesses the line data returned by $(D front) after the corresponding $(D popFront) call is made (because the contents may well have changed). */ auto byLine(Terminator = char, Char = char) (KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\n') if (isScalarType!Terminator) { return ByLine!(Char, Terminator)(this, keepTerminator, terminator); } /// ditto auto byLine(Terminator, Char = char) (KeepTerminator keepTerminator, Terminator terminator) if (is(Unqual!(ElementEncodingType!Terminator) == Char)) { return ByLine!(Char, Terminator)(this, keepTerminator, terminator); } unittest { static import std.file; auto deleteme = testFilename(); std.file.write(deleteme, "hi"); scope(success) std.file.remove(deleteme); import std.meta : AliasSeq; foreach (T; AliasSeq!(char, wchar, dchar)) { auto blc = File(deleteme).byLine!(T, T); assert(blc.front == "hi"); // check front is cached assert(blc.front is blc.front); } } private struct ByLineCopy(Char, Terminator) { private: import std.typecons; /* Ref-counting stops the source range's ByLineCopyImpl * from getting out of sync after the range is copied, e.g. * when accessing range.front, then using std.range.take, * then accessing range.front again. */ alias Impl = RefCounted!(ByLineCopyImpl!(Char, Terminator), RefCountedAutoInitialize.no); Impl impl; public: this(File f, KeepTerminator kt, Terminator terminator) { impl = Impl(f, kt, terminator); } @property bool empty() { return impl.refCountedPayload.empty; } @property Char[] front() { return impl.refCountedPayload.front; } void popFront() { impl.refCountedPayload.popFront(); } } private struct ByLineCopyImpl(Char, Terminator) { ByLine!(Unqual!Char, Terminator).Impl impl; bool gotFront; Char[] line; public: this(File f, KeepTerminator kt, Terminator terminator) { impl = ByLine!(Unqual!Char, Terminator).Impl(f, kt, terminator); } @property bool empty() { return impl.empty; } @property front() { if (!gotFront) { line = impl.front.dup; gotFront = true; } return line; } void popFront() { impl.popFront(); gotFront = false; } } /** Returns an input range set up to read from the file handle one line at a time. Each line will be newly allocated. $(D front) will cache its value to allow repeated calls without unnecessary allocations. Note: Due to caching byLineCopy can be more memory-efficient than $(D File.byLine.map!idup). The element type for the range will be $(D Char[]). Range primitives may throw $(D StdioException) on I/O error. Params: Char = Character type for each line, defaulting to $(D immutable char). keepTerminator = Use $(D KeepTerminator.yes) to include the terminator at the end of each line. terminator = Line separator ($(D '\n') by default). Use $(XREF ascii, newline) for portability (unless the file was opened in text mode). Example: ---- import std.algorithm, std.array, std.stdio; // Print sorted lines of a file. void main() { auto sortedLines = File("file.txt") // Open for reading .byLineCopy() // Read persistent lines .array() // into an array .sort(); // then sort them foreach (line; sortedLines) writeln(line); } ---- See_Also: $(XREF file,readText) */ auto byLineCopy(Terminator = char, Char = immutable char) (KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\n') if (isScalarType!Terminator) { return ByLineCopy!(Char, Terminator)(this, keepTerminator, terminator); } /// ditto auto byLineCopy(Terminator, Char = immutable char) (KeepTerminator keepTerminator, Terminator terminator) if (is(Unqual!(ElementEncodingType!Terminator) == Unqual!Char)) { return ByLineCopy!(Char, Terminator)(this, keepTerminator, terminator); } unittest { static assert(is(typeof(File("").byLine.front) == char[])); static assert(is(typeof(File("").byLineCopy.front) == string)); static assert( is(typeof(File("").byLineCopy!(char, char).front) == char[])); } unittest { static import std.file; import std.algorithm : equal; import std.range; //printf("Entering test at line %d\n", __LINE__); scope(failure) printf("Failed test at line %d\n", __LINE__); auto deleteme = testFilename(); std.file.write(deleteme, ""); scope(success) std.file.remove(deleteme); // Test empty file auto f = File(deleteme); foreach (line; f.byLine()) { assert(false); } f.detach(); assert(!f.isOpen); void test(Terminator)(string txt, in string[] witness, KeepTerminator kt, Terminator term, bool popFirstLine = false) { import std.conv : text; import std.algorithm : sort; import std.range.primitives : walkLength; uint i; std.file.write(deleteme, txt); auto f = File(deleteme); scope(exit) { f.close(); assert(!f.isOpen); } auto lines = f.byLine(kt, term); if (popFirstLine) { lines.popFront(); i = 1; } assert(lines.empty || lines.front is lines.front); foreach (line; lines) { assert(line == witness[i++]); } assert(i == witness.length, text(i, " != ", witness.length)); // Issue 11830 auto walkedLength = File(deleteme).byLine(kt, term).walkLength; assert(walkedLength == witness.length, text(walkedLength, " != ", witness.length)); // test persistent lines assert(File(deleteme).byLineCopy(kt, term).array.sort() == witness.dup.sort()); } KeepTerminator kt = KeepTerminator.no; test("", null, kt, '\n'); test("\n", [ "" ], kt, '\n'); test("asd\ndef\nasdf", [ "asd", "def", "asdf" ], kt, '\n'); test("asd\ndef\nasdf", [ "asd", "def", "asdf" ], kt, '\n', true); test("asd\ndef\nasdf\n", [ "asd", "def", "asdf" ], kt, '\n'); test("foo", [ "foo" ], kt, '\n', true); test("bob\r\nmarge\r\nsteve\r\n", ["bob", "marge", "steve"], kt, "\r\n"); test("sue\r", ["sue"], kt, '\r'); kt = KeepTerminator.yes; test("", null, kt, '\n'); test("\n", [ "\n" ], kt, '\n'); test("asd\ndef\nasdf", [ "asd\n", "def\n", "asdf" ], kt, '\n'); test("asd\ndef\nasdf\n", [ "asd\n", "def\n", "asdf\n" ], kt, '\n'); test("asd\ndef\nasdf\n", [ "asd\n", "def\n", "asdf\n" ], kt, '\n', true); test("foo", [ "foo" ], kt, '\n'); test("bob\r\nmarge\r\nsteve\r\n", ["bob\r\n", "marge\r\n", "steve\r\n"], kt, "\r\n"); test("sue\r", ["sue\r"], kt, '\r'); } unittest { import std.algorithm : equal; import std.range; version(Win64) { static import std.file; /* the C function tmpfile doesn't seem to work, even when called from C */ auto deleteme = testFilename(); auto file = File(deleteme, "w+"); scope(success) std.file.remove(deleteme); } else version(CRuntime_Bionic) { static import std.file; /* the C function tmpfile doesn't work when called from a shared library apk: https://code.google.com/p/android/issues/detail?id=66815 */ auto deleteme = testFilename(); auto file = File(deleteme, "w+"); scope(success) std.file.remove(deleteme); } else auto file = File.tmpfile(); file.write("1\n2\n3\n"); // bug 9599 file.rewind(); File.ByLine!(char, char) fbl = file.byLine(); auto fbl2 = fbl; assert(fbl.front == "1"); assert(fbl.front is fbl2.front); assert(fbl.take(1).equal(["1"])); assert(fbl.equal(["2", "3"])); assert(fbl.empty); assert(file.isOpen); // we still have a valid reference file.rewind(); fbl = file.byLine(); assert(!fbl.drop(2).empty); assert(fbl.equal(["3"])); assert(fbl.empty); assert(file.isOpen); file.detach(); assert(!file.isOpen); } unittest { static import std.file; auto deleteme = testFilename(); std.file.write(deleteme, "hi"); scope(success) std.file.remove(deleteme); auto blc = File(deleteme).byLineCopy; assert(!blc.empty); // check front is cached assert(blc.front is blc.front); } template byRecord(Fields...) { ByRecord!(Fields) byRecord(string format) { return typeof(return)(this, format); } } unittest { // static import std.file; // // auto deleteme = testFilename(); // rndGen.popFront(); // scope(failure) printf("Failed test at line %d\n", __LINE__); // std.file.write(deleteme, "1 2\n4 1\n5 100"); // scope(exit) std.file.remove(deleteme); // File f = File(deleteme); // scope(exit) f.close(); // auto t = [ tuple(1, 2), tuple(4, 1), tuple(5, 100) ]; // uint i; // foreach (e; f.byRecord!(int, int)("%s %s")) // { // //.writeln(e); // assert(e == t[i++]); // } } // Note: This was documented until 2013/08 /* * Range that reads a chunk at a time. */ struct ByChunk { private: File file_; ubyte[] chunk_; void prime() { chunk_ = file_.rawRead(chunk_); if (chunk_.length == 0) file_.detach(); } public: this(File file, size_t size) { this(file, new ubyte[](size)); } this(File file, ubyte[] buffer) { import std.exception; enforce(buffer.length, "size must be larger than 0"); file_ = file; chunk_ = buffer; prime(); } // $(D ByChunk)'s input range primitive operations. @property nothrow bool empty() const { return !file_.isOpen; } /// Ditto @property nothrow ubyte[] front() { version(assert) { import core.exception : RangeError; if (empty) throw new RangeError(); } return chunk_; } /// Ditto void popFront() { version(assert) { import core.exception : RangeError; if (empty) throw new RangeError(); } prime(); } } /** Returns an input range set up to read from the file handle a chunk at a time. The element type for the range will be $(D ubyte[]). Range primitives may throw $(D StdioException) on I/O error. Example: --------- void main() { // Read standard input 4KB at a time foreach (ubyte[] buffer; stdin.byChunk(4096)) { ... use buffer ... } } --------- The parameter may be a number (as shown in the example above) dictating the size of each chunk. Alternatively, $(D byChunk) accepts a user-provided buffer that it uses directly. Example: --------- void main() { // Read standard input 4KB at a time foreach (ubyte[] buffer; stdin.byChunk(new ubyte[4096])) { ... use buffer ... } } --------- In either case, the content of the buffer is reused across calls. That means $(D front) will not persist after $(D popFront) is called, so if retention is needed, the caller must copy its contents (e.g. by calling $(D buffer.dup)). In the example above, $(D buffer.length) is 4096 for all iterations, except for the last one, in which case $(D buffer.length) may be less than 4096 (but always greater than zero). With the mentioned limitations, $(D byChunks) works with any algorithm compatible with input ranges. Example: --- // Efficient file copy, 1MB at a time. import std.algorithm, std.stdio; void main() { stdin.byChunk(1024 * 1024).copy(stdout.lockingTextWriter()); } --- $(XREF_PACK algorithm,iteration,joiner) can be used to join chunks together into a single range lazily. Example: --- import std.algorithm, std.stdio; void main() { //Range of ranges static assert(is(typeof(stdin.byChunk(4096).front) == ubyte[])); //Range of elements static assert(is(typeof(stdin.byChunk(4096).joiner.front) == ubyte)); } --- Returns: A call to $(D byChunk) returns a range initialized with the $(D File) object and the appropriate buffer. Throws: If the user-provided size is zero or the user-provided buffer is empty, throws an $(D Exception). In case of an I/O error throws $(D StdioException). */ auto byChunk(size_t chunkSize) { return ByChunk(this, chunkSize); } /// Ditto ByChunk byChunk(ubyte[] buffer) { return ByChunk(this, buffer); } unittest { static import std.file; scope(failure) printf("Failed test at line %d\n", __LINE__); auto deleteme = testFilename(); std.file.write(deleteme, "asd\ndef\nasdf"); auto witness = ["asd\n", "def\n", "asdf" ]; auto f = File(deleteme); scope(exit) { f.close(); assert(!f.isOpen); std.file.remove(deleteme); } uint i; foreach (chunk; f.byChunk(4)) assert(chunk == cast(ubyte[])witness[i++]); assert(i == witness.length); } unittest { static import std.file; scope(failure) printf("Failed test at line %d\n", __LINE__); auto deleteme = testFilename(); std.file.write(deleteme, "asd\ndef\nasdf"); auto witness = ["asd\n", "def\n", "asdf" ]; auto f = File(deleteme); scope(exit) { f.close(); assert(!f.isOpen); std.file.remove(deleteme); } uint i; foreach (chunk; f.byChunk(new ubyte[4])) assert(chunk == cast(ubyte[])witness[i++]); assert(i == witness.length); } // Note: This was documented until 2013/08 /* $(D Range) that locks the file and allows fast writing to it. */ struct LockingTextWriter { private: import std.range.primitives : ElementType, isInfinite, isInputRange; FILE* fps_; // the shared file handle _iobuf* handle_; // the unshared version of fps int orientation_; public: this(ref File f) @trusted { import core.stdc.wchar_ : fwide; import std.exception : enforce; enforce(f._p && f._p.handle, "Attempting to write to closed File"); fps_ = f._p.handle; orientation_ = fwide(fps_, 0); FLOCK(fps_); handle_ = cast(_iobuf*)fps_; } ~this() @trusted { if(fps_) { FUNLOCK(fps_); fps_ = null; handle_ = null; } } this(this) @trusted { if(fps_) { FLOCK(fps_); } } /// Range primitive implementations. void put(A)(A writeme) if (is(ElementType!A : const(dchar)) && isInputRange!A && !isInfinite!A) { import std.exception : errnoEnforce; alias C = ElementEncodingType!A; static assert(!is(C == void)); static if (isSomeString!A && C.sizeof == 1) { if (orientation_ <= 0) { //file.write(writeme); causes infinite recursion!!! //file.rawWrite(writeme); static auto trustedFwrite(in void* ptr, size_t size, size_t nmemb, FILE* stream) @trusted { return .fwrite(ptr, size, nmemb, stream); } auto result = trustedFwrite(writeme.ptr, C.sizeof, writeme.length, fps_); if (result != writeme.length) errnoEnforce(0); return; } } // put each character in turn foreach (dchar c; writeme) { put(c); } } // @@@BUG@@@ 2340 //void front(C)(C c) if (is(C : dchar)) { /// ditto void put(C)(C c) @safe if (is(C : const(dchar))) { import std.traits : Parameters; static auto trustedFPUTC(int ch, _iobuf* h) @trusted { return FPUTC(ch, h); } static auto trustedFPUTWC(Parameters!FPUTWC[0] ch, _iobuf* h) @trusted { return FPUTWC(ch, h); } static if (c.sizeof == 1) { // simple char if (orientation_ <= 0) trustedFPUTC(c, handle_); else trustedFPUTWC(c, handle_); } else static if (c.sizeof == 2) { import std.utf : toUTF8; if (orientation_ <= 0) { if (c <= 0x7F) { trustedFPUTC(c, handle_); } else { char[4] buf; auto b = toUTF8(buf, c); foreach (i ; 0 .. b.length) trustedFPUTC(b[i], handle_); } } else { trustedFPUTWC(c, handle_); } } else // 32-bit characters { import std.utf : toUTF8; if (orientation_ <= 0) { if (c <= 0x7F) { trustedFPUTC(c, handle_); } else { char[4] buf = void; auto b = toUTF8(buf, c); foreach (i ; 0 .. b.length) trustedFPUTC(b[i], handle_); } } else { version (Windows) { import std.utf : isValidDchar; assert(isValidDchar(c)); if (c <= 0xFFFF) { trustedFPUTWC(c, handle_); } else { trustedFPUTWC(cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800), handle_); trustedFPUTWC(cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00), handle_); } } else version (Posix) { trustedFPUTWC(c, handle_); } else { static assert(0); } } } } } /** Returns an output range that locks the file and allows fast writing to it. See $(LREF byChunk) for an example. */ auto lockingTextWriter() @safe { return LockingTextWriter(this); } /// Get the size of the file, ulong.max if file is not searchable, but still throws if an actual error occurs. @property ulong size() @safe { import std.exception : collectException; ulong pos = void; if (collectException(pos = tell)) return ulong.max; scope(exit) seek(pos); seek(0, SEEK_END); return tell; } } unittest { @system struct SystemToString { string toString() { return "system"; } } @trusted struct TrustedToString { string toString() { return "trusted"; } } @safe struct SafeToString { string toString() { return "safe"; } } @system void systemTests() { //system code can write to files/stdout with anything! if(false) { auto f = File(); f.write("just a string"); f.write("string with arg: ", 47); f.write(SystemToString()); f.write(TrustedToString()); f.write(SafeToString()); write("just a string"); write("string with arg: ", 47); write(SystemToString()); write(TrustedToString()); write(SafeToString()); f.writeln("just a string"); f.writeln("string with arg: ", 47); f.writeln(SystemToString()); f.writeln(TrustedToString()); f.writeln(SafeToString()); writeln("just a string"); writeln("string with arg: ", 47); writeln(SystemToString()); writeln(TrustedToString()); writeln(SafeToString()); f.writef("string with arg: %s", 47); f.writef("%s", SystemToString()); f.writef("%s", TrustedToString()); f.writef("%s", SafeToString()); writef("string with arg: %s", 47); writef("%s", SystemToString()); writef("%s", TrustedToString()); writef("%s", SafeToString()); f.writefln("string with arg: %s", 47); f.writefln("%s", SystemToString()); f.writefln("%s", TrustedToString()); f.writefln("%s", SafeToString()); writefln("string with arg: %s", 47); writefln("%s", SystemToString()); writefln("%s", TrustedToString()); writefln("%s", SafeToString()); } } @safe void safeTests() { auto f = File(); //safe code can write to files only with @safe and @trusted code... if(false) { f.write("just a string"); f.write("string with arg: ", 47); f.write(TrustedToString()); f.write(SafeToString()); write("just a string"); write("string with arg: ", 47); write(TrustedToString()); write(SafeToString()); f.writeln("just a string"); f.writeln("string with arg: ", 47); f.writeln(TrustedToString()); f.writeln(SafeToString()); writeln("just a string"); writeln("string with arg: ", 47); writeln(TrustedToString()); writeln(SafeToString()); f.writef("string with arg: %s", 47); f.writef("%s", TrustedToString()); f.writef("%s", SafeToString()); writef("string with arg: %s", 47); writef("%s", TrustedToString()); writef("%s", SafeToString()); f.writefln("string with arg: %s", 47); f.writefln("%s", TrustedToString()); f.writefln("%s", SafeToString()); writefln("string with arg: %s", 47); writefln("%s", TrustedToString()); writefln("%s", SafeToString()); } static assert(!__traits(compiles, f.write(SystemToString().toString()))); static assert(!__traits(compiles, f.writeln(SystemToString()))); static assert(!__traits(compiles, f.writef("%s", SystemToString()))); static assert(!__traits(compiles, f.writefln("%s", SystemToString()))); static assert(!__traits(compiles, write(SystemToString().toString()))); static assert(!__traits(compiles, writeln(SystemToString()))); static assert(!__traits(compiles, writef("%s", SystemToString()))); static assert(!__traits(compiles, writefln("%s", SystemToString()))); } systemTests(); safeTests(); } unittest { static import std.file; import std.exception : collectException; auto deleteme = testFilename(); scope(exit) collectException(std.file.remove(deleteme)); std.file.write(deleteme, "1 2 3"); auto f = File(deleteme); assert(f.size == 5); assert(f.tell == 0); } unittest { static import std.file; import std.range; auto deleteme = testFilename(); scope(exit) std.file.remove(deleteme); { File f = File(deleteme, "w"); auto writer = f.lockingTextWriter(); static assert(isOutputRange!(typeof(writer), dchar)); writer.put("日本語"); writer.put("日本語"w); writer.put("日本語"d); writer.put('日'); writer.put(chain(only('本'), only('語'))); writer.put(repeat('#', 12)); // BUG 11945 } assert(File(deleteme).readln() == "日本語日本語日本語日本語############"); } @safe unittest { import std.exception: collectException; auto e = collectException({ File f; f.writeln("Hello!"); }()); assert(e && e.msg == "Attempting to write to closed File"); } /// Used to specify the lock type for $(D File.lock) and $(D File.tryLock). enum LockType { /// Specifies a _read (shared) lock. A _read lock denies all processes /// write access to the specified region of the file, including the /// process that first locks the region. All processes can _read the /// locked region. Multiple simultaneous _read locks are allowed, as /// long as there are no exclusive locks. read, /// Specifies a read/write (exclusive) lock. A read/write lock denies all /// other processes both read and write access to the locked file region. /// If a segment has an exclusive lock, it may not have any shared locks /// or other exclusive locks. readWrite } struct LockingTextReader { private File _f; private char _front; private bool _hasChar; this(File f) { import std.exception : enforce; enforce(f.isOpen, "LockingTextReader: File must be open"); _f = f; FLOCK(_f._p.handle); } this(this) { FLOCK(_f._p.handle); } ~this() { if (_hasChar) ungetc(_front, cast(FILE*)_f._p.handle); // File locking has its own reference count if (_f.isOpen) FUNLOCK(_f._p.handle); } void opAssign(LockingTextReader r) { import std.algorithm : swap; swap(this, r); } @property bool empty() { if (!_hasChar) { if (!_f.isOpen || _f.eof) return true; immutable int c = FGETC(cast(_iobuf*) _f._p.handle); if (c == EOF) { .destroy(_f); return true; } _front = cast(char)c; _hasChar = true; } return false; } @property char front() { if (!_hasChar) { version(assert) { import core.exception : RangeError; if (empty) throw new RangeError(); } else { empty; } } return _front; } void popFront() { if (!_hasChar) empty; _hasChar = false; } } unittest { static import std.file; import std.range.primitives : isInputRange; static assert(isInputRange!LockingTextReader); auto deleteme = testFilename(); std.file.write(deleteme, "1 2 3"); scope(exit) std.file.remove(deleteme); int x, y; auto f = File(deleteme); f.readf("%s ", &x); assert(x == 1); f.readf("%d ", &x); assert(x == 2); f.readf("%d ", &x); assert(x == 3); //pragma(msg, "--- todo: readf ---"); } unittest // bugzilla 13686 { static import std.file; import std.algorithm : equal; auto deleteme = testFilename(); std.file.write(deleteme, "Тест"); scope(exit) std.file.remove(deleteme); string s; File(deleteme).readf("%s", &s); assert(s == "Тест"); import std.utf; auto ltr = LockingTextReader(File(deleteme)).byDchar; assert(equal(ltr, "Тест".byDchar)); } unittest // bugzilla 12320 { static import std.file; auto deleteme = testFilename(); std.file.write(deleteme, "ab"); scope(exit) std.file.remove(deleteme); auto ltr = LockingTextReader(File(deleteme)); assert(ltr.front == 'a'); ltr.popFront(); assert(ltr.front == 'b'); ltr.popFront(); assert(ltr.empty); } unittest // bugzilla 14861 { static import std.file; auto deleteme = testFilename(); File fw = File(deleteme, "w"); for(int i; i != 5000; i++) fw.writeln(i, ";", "Иванов;Пётр;Петрович"); fw.close(); scope(exit) std.file.remove(deleteme); // Test read File fr = File(deleteme, "r"); scope (exit) fr.close(); int nom; string fam, nam, ot; // Error format read while(!fr.eof) fr.readf("%s;%s;%s;%s\n", &nom, &fam, &nam, &ot); } /** * Indicates whether $(D T) is a file handle of some kind. */ template isFileHandle(T) { enum isFileHandle = is(T : FILE*) || is(T : File); } unittest { static assert(isFileHandle!(FILE*)); static assert(isFileHandle!(File)); } /** * Property used by writeln/etc. so it can infer @safe since stdout is __gshared */ private @property File trustedStdout() @trusted { return stdout; } /*********************************** For each argument $(D arg) in $(D args), format the argument (as per $(LINK2 std_conv.html, to!(string)(arg))) and write the resulting string to $(D args[0]). A call without any arguments will fail to compile. Throws: In case of an I/O error, throws an $(D StdioException). */ void write(T...)(T args) if (!is(T[0] : File)) { trustedStdout.write(args); } unittest { static import std.file; //printf("Entering test at line %d\n", __LINE__); scope(failure) printf("Failed test at line %d\n", __LINE__); void[] buf; if (false) write(buf); // test write auto deleteme = testFilename(); auto f = File(deleteme, "w"); f.write("Hello, ", "world number ", 42, "!"); f.close(); scope(exit) { std.file.remove(deleteme); } assert(cast(char[]) std.file.read(deleteme) == "Hello, world number 42!"); // // test write on stdout //auto saveStdout = stdout; //scope(exit) stdout = saveStdout; //stdout.open(file, "w"); Object obj; //write("Hello, ", "world number ", 42, "! ", obj); //stdout.close(); // auto result = cast(char[]) std.file.read(file); // assert(result == "Hello, world number 42! null", result); } /*********************************** * Equivalent to $(D write(args, '\n')). Calling $(D writeln) without * arguments is valid and just prints a newline to the standard * output. */ void writeln(T...)(T args) { import std.traits : isAggregateType; static if (T.length == 0) { import std.exception : enforce; enforce(fputc('\n', .trustedStdout._p.handle) == '\n', "fputc failed"); } else static if (T.length == 1 && is(typeof(args[0]) : const(char)[]) && !is(typeof(args[0]) == enum) && !is(Unqual!(typeof(args[0])) == typeof(null)) && !isAggregateType!(typeof(args[0]))) { import std.exception : enforce; // Specialization for strings - a very frequent case auto w = .trustedStdout.lockingTextWriter(); static if (isStaticArray!(typeof(args[0]))) { w.put(args[0][]); } else { w.put(args[0]); } w.put('\n'); } else { // Most general instance trustedStdout.write(args, '\n'); } } @safe unittest { // Just make sure the call compiles if (false) writeln(); if (false) writeln("wyda"); // bug 8040 if (false) writeln(null); if (false) writeln(">", null, "<"); // Bugzilla 14041 if (false) { char[8] a; writeln(a); } } unittest { static import std.file; //printf("Entering test at line %d\n", __LINE__); scope(failure) printf("Failed test at line %d\n", __LINE__); // test writeln auto deleteme = testFilename(); auto f = File(deleteme, "w"); scope(exit) { std.file.remove(deleteme); } f.writeln("Hello, ", "world number ", 42, "!"); f.close(); version (Windows) assert(cast(char[]) std.file.read(deleteme) == "Hello, world number 42!\r\n"); else assert(cast(char[]) std.file.read(deleteme) == "Hello, world number 42!\n"); // test writeln on stdout auto saveStdout = stdout; scope(exit) stdout = saveStdout; stdout.open(deleteme, "w"); writeln("Hello, ", "world number ", 42, "!"); stdout.close(); version (Windows) assert(cast(char[]) std.file.read(deleteme) == "Hello, world number 42!\r\n"); else assert(cast(char[]) std.file.read(deleteme) == "Hello, world number 42!\n"); stdout.open(deleteme, "w"); writeln("Hello!"c); writeln("Hello!"w); // bug 8386 writeln("Hello!"d); // bug 8386 writeln("embedded\0null"c); // bug 8730 stdout.close(); version (Windows) assert(cast(char[]) std.file.read(deleteme) == "Hello!\r\nHello!\r\nHello!\r\nembedded\0null\r\n"); else assert(cast(char[]) std.file.read(deleteme) == "Hello!\nHello!\nHello!\nembedded\0null\n"); } unittest { static import std.file; auto deleteme = testFilename(); auto f = File(deleteme, "w"); scope(exit) { std.file.remove(deleteme); } enum EI : int { A, B } enum ED : double { A, B } enum EC : char { A, B } enum ES : string { A = "aaa", B = "bbb" } f.writeln(EI.A); // false, but A on 2.058 f.writeln(EI.B); // true, but B on 2.058 f.writeln(ED.A); // A f.writeln(ED.B); // B f.writeln(EC.A); // A f.writeln(EC.B); // B f.writeln(ES.A); // A f.writeln(ES.B); // B f.close(); version (Windows) assert(cast(char[]) std.file.read(deleteme) == "A\r\nB\r\nA\r\nB\r\nA\r\nB\r\nA\r\nB\r\n"); else assert(cast(char[]) std.file.read(deleteme) == "A\nB\nA\nB\nA\nB\nA\nB\n"); } unittest { static auto useInit(T)(T ltw) { T val; val = ltw; val = T.init; return val; } useInit(stdout.lockingTextWriter()); } /*********************************** Writes formatted data to standard output (without a trailing newline). Params: args = The first argument $(D args[0]) should be the format string, specifying how to format the rest of the arguments. For a full description of the syntax of the format string and how it controls the formatting of the rest of the arguments, please refer to the documentation for $(XREF format, formattedWrite). Note: In older versions of Phobos, it used to be possible to write: ------ writef(stderr, "%s", "message"); ------ to print a message to $(D stderr). This syntax is no longer supported, and has been superceded by: ------ stderr.writef("%s", "message"); ------ */ void writef(T...)(T args) { trustedStdout.writef(args); } unittest { static import std.file; //printf("Entering test at line %d\n", __LINE__); scope(failure) printf("Failed test at line %d\n", __LINE__); // test writef auto deleteme = testFilename(); auto f = File(deleteme, "w"); scope(exit) { std.file.remove(deleteme); } f.writef("Hello, %s world number %s!", "nice", 42); f.close(); assert(cast(char[]) std.file.read(deleteme) == "Hello, nice world number 42!"); // test write on stdout auto saveStdout = stdout; scope(exit) stdout = saveStdout; stdout.open(deleteme, "w"); writef("Hello, %s world number %s!", "nice", 42); stdout.close(); assert(cast(char[]) std.file.read(deleteme) == "Hello, nice world number 42!"); } /*********************************** * Equivalent to $(D writef(args, '\n')). */ void writefln(T...)(T args) { trustedStdout.writefln(args); } unittest { static import std.file; //printf("Entering test at line %d\n", __LINE__); scope(failure) printf("Failed test at line %d\n", __LINE__); // test writefln auto deleteme = testFilename(); auto f = File(deleteme, "w"); scope(exit) { std.file.remove(deleteme); } f.writefln("Hello, %s world number %s!", "nice", 42); f.close(); version (Windows) assert(cast(char[]) std.file.read(deleteme) == "Hello, nice world number 42!\r\n"); else assert(cast(char[]) std.file.read(deleteme) == "Hello, nice world number 42!\n", cast(char[]) std.file.read(deleteme)); // test write on stdout // auto saveStdout = stdout; // scope(exit) stdout = saveStdout; // stdout.open(file, "w"); // assert(stdout.isOpen); // writefln("Hello, %s world number %s!", "nice", 42); // foreach (F ; AliasSeq!(ifloat, idouble, ireal)) // { // F a = 5i; // F b = a % 2; // writeln(b); // } // stdout.close(); // auto read = cast(char[]) std.file.read(file); // version (Windows) // assert(read == "Hello, nice world number 42!\r\n1\r\n1\r\n1\r\n", read); // else // assert(read == "Hello, nice world number 42!\n1\n1\n1\n", "["~read~"]"); } /** * Read data from $(D stdin) according to the specified * $(LINK2 std_format.html#format-string, format specifier) using * $(XREF format,formattedRead). */ uint readf(A...)(in char[] format, A args) { return stdin.readf(format, args); } unittest { float f; if (false) uint x = readf("%s", &f); char a; wchar b; dchar c; if (false) readf("%s %s %s", &a,&b,&c); } /********************************** * Read line from $(D stdin). * * This version manages its own read buffer, which means one memory allocation per call. If you are not * retaining a reference to the read data, consider the $(D readln(buf)) version, which may offer * better performance as it can reuse its read buffer. * * Returns: * The line that was read, including the line terminator character. * Params: * S = Template parameter; the type of the allocated buffer, and the type returned. Defaults to $(D string). * terminator = Line terminator (by default, $(D '\n')). * Note: * String terminators are not supported due to ambiguity with readln(buf) below. * Throws: * $(D StdioException) on I/O error, or $(D UnicodeException) on Unicode conversion error. * Example: * Reads $(D stdin) and writes it to $(D stdout). --- import std.stdio; void main() { string line; while ((line = readln()) !is null) write(line); } --- */ S readln(S = string)(dchar terminator = '\n') if (isSomeString!S) { return stdin.readln!S(terminator); } /********************************** * Read line from $(D stdin) and write it to buf[], including terminating character. * * This can be faster than $(D line = readln()) because you can reuse * the buffer for each call. Note that reusing the buffer means that you * must copy the previous contents if you wish to retain them. * * Returns: * $(D size_t) 0 for end of file, otherwise number of characters read * Params: * buf = Buffer used to store the resulting line data. buf is resized as necessary. * terminator = Line terminator (by default, $(D '\n')). Use $(XREF ascii, newline) * for portability (unless the file was opened in text mode). * Throws: * $(D StdioException) on I/O error, or $(D UnicodeException) on Unicode conversion error. * Example: * Reads $(D stdin) and writes it to $(D stdout). --- import std.stdio; void main() { char[] buf; while (readln(buf)) write(buf); } --- */ size_t readln(C)(ref C[] buf, dchar terminator = '\n') if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum)) { return stdin.readln(buf, terminator); } /** ditto */ size_t readln(C, R)(ref C[] buf, R terminator) if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) && isBidirectionalRange!R && is(typeof(terminator.front == dchar.init))) { return stdin.readln(buf, terminator); } unittest { import std.meta : AliasSeq; //we can't actually test readln, so at the very least, //we test compilability void foo() { readln(); readln('\t'); foreach (String; AliasSeq!(string, char[], wstring, wchar[], dstring, dchar[])) { readln!String(); readln!String('\t'); } foreach (String; AliasSeq!(char[], wchar[], dchar[])) { String buf; readln(buf); readln(buf, '\t'); readln(buf, "
"); } } } /* * Convenience function that forwards to $(D core.sys.posix.stdio.fopen) * (to $(D _wfopen) on Windows) * with appropriately-constructed C-style strings. */ private FILE* fopen(R1, R2)(R1 name, R2 mode = "r") if ((isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) || isSomeString!R1) && (isInputRange!R2 && isSomeChar!(ElementEncodingType!R2) || isSomeString!R2)) { import std.internal.cstring : tempCString; auto namez = name.tempCString!FSChar(); auto modez = mode.tempCString!FSChar(); static fopenImpl(const(FSChar)* namez, const(FSChar)* modez) @trusted nothrow @nogc { version(Windows) { return _wfopen(namez, modez); } else version(Posix) { /* * The new opengroup large file support API is transparently * included in the normal C bindings. http://opengroup.org/platform/lfs.html#1.0 * if _FILE_OFFSET_BITS in druntime is 64, off_t is 64 bit and * the normal functions work fine. If not, then large file support * probably isn't available. Do not use the old transitional API * (the native extern(C) fopen64, http://www.unix.org/version2/whatsnew/lfs20mar.html#3.0) */ import core.sys.posix.stdio : fopen; return fopen(namez, modez); } else { return .fopen(namez, modez); } } return fopenImpl(namez, modez); } version (Posix) { /*********************************** * Convenience function that forwards to $(D core.sys.posix.stdio.popen) * with appropriately-constructed C-style strings. */ FILE* popen(R1, R2)(R1 name, R2 mode = "r") @trusted nothrow @nogc if ((isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) || isSomeString!R1) && (isInputRange!R2 && isSomeChar!(ElementEncodingType!R2) || isSomeString!R2)) { import std.internal.cstring : tempCString; auto namez = name.tempCString!FSChar(); auto modez = mode.tempCString!FSChar(); static popenImpl(const(FSChar)* namez, const(FSChar)* modez) @trusted nothrow @nogc { import core.sys.posix.stdio : popen; return popen(namez, modez); } return popenImpl(namez, modez); } } /* * Convenience function that forwards to $(D core.stdc.stdio.fwrite) * and throws an exception upon error */ private void binaryWrite(T)(FILE* f, T obj) { immutable result = fwrite(obj.ptr, obj[0].sizeof, obj.length, f); if (result != obj.length) StdioException(); } /** * Iterates through the lines of a file by using $(D foreach). * * Example: * --------- void main() { foreach (string line; lines(stdin)) { ... use line ... } } --------- The line terminator ($(D '\n') by default) is part of the string read (it could be missing in the last line of the file). Several types are supported for $(D line), and the behavior of $(D lines) changes accordingly: $(OL $(LI If $(D line) has type $(D string), $(D wstring), or $(D dstring), a new string of the respective type is allocated every read.) $(LI If $(D line) has type $(D char[]), $(D wchar[]), $(D dchar[]), the line's content will be reused (overwritten) across reads.) $(LI If $(D line) has type $(D immutable(ubyte)[]), the behavior is similar to case (1), except that no UTF checking is attempted upon input.) $(LI If $(D line) has type $(D ubyte[]), the behavior is similar to case (2), except that no UTF checking is attempted upon input.)) In all cases, a two-symbols versions is also accepted, in which case the first symbol (of integral type, e.g. $(D ulong) or $(D uint)) tracks the zero-based number of the current line. Example: ---- foreach (ulong i, string line; lines(stdin)) { ... use line ... } ---- In case of an I/O error, an $(D StdioException) is thrown. See_Also: $(LREF byLine) */ struct lines { private File f; private dchar terminator = '\n'; // private string fileName; // Curretly, no use /** Constructor. Params: f = File to read lines from. terminator = Line separator ($(D '\n') by default). */ this(File f, dchar terminator = '\n') { this.f = f; this.terminator = terminator; } // Keep these commented lines for later, when Walter fixes the // exception model. // static lines opCall(string fName, dchar terminator = '\n') // { // auto f = enforce(fopen(fName), // new StdioException("Cannot open file `"~fName~"' for reading")); // auto result = lines(f, terminator); // result.fileName = fName; // return result; // } int opApply(D)(scope D dg) { // scope(exit) { // if (fileName.length && fclose(f)) // StdioException("Could not close file `"~fileName~"'"); // } import std.traits : Parameters; alias Parms = Parameters!(dg); static if (isSomeString!(Parms[$ - 1])) { enum bool duplicate = is(Parms[$ - 1] == string) || is(Parms[$ - 1] == wstring) || is(Parms[$ - 1] == dstring); int result = 0; static if (is(Parms[$ - 1] : const(char)[])) alias C = char; else static if (is(Parms[$ - 1] : const(wchar)[])) alias C = wchar; else static if (is(Parms[$ - 1] : const(dchar)[])) alias C = dchar; C[] line; static if (Parms.length == 2) Parms[0] i = 0; for (;;) { import std.conv : to; if (!f.readln(line, terminator)) break; auto copy = to!(Parms[$ - 1])(line); static if (Parms.length == 2) { result = dg(i, copy); ++i; } else { result = dg(copy); } if (result != 0) break; } return result; } else { // raw read return opApplyRaw(dg); } } // no UTF checking int opApplyRaw(D)(scope D dg) { import std.exception : assumeUnique; import std.conv : to; import std.traits : Parameters; alias Parms = Parameters!(dg); enum duplicate = is(Parms[$ - 1] : immutable(ubyte)[]); int result = 1; int c = void; FLOCK(f._p.handle); scope(exit) FUNLOCK(f._p.handle); ubyte[] buffer; static if (Parms.length == 2) Parms[0] line = 0; while ((c = FGETC(cast(_iobuf*)f._p.handle)) != -1) { buffer ~= to!(ubyte)(c); if (c == terminator) { static if (duplicate) auto arg = assumeUnique(buffer); else alias arg = buffer; // unlock the file while calling the delegate FUNLOCK(f._p.handle); scope(exit) FLOCK(f._p.handle); static if (Parms.length == 1) { result = dg(arg); } else { result = dg(line, arg); ++line; } if (result) break; static if (!duplicate) buffer.length = 0; } } // can only reach when FGETC returned -1 if (!f.eof) throw new StdioException("Error in reading file"); // error occured return result; } } unittest { static import std.file; import std.meta : AliasSeq; //printf("Entering test at line %d\n", __LINE__); scope(failure) printf("Failed test at line %d\n", __LINE__); auto deleteme = testFilename(); scope(exit) { std.file.remove(deleteme); } alias TestedWith = AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[]); foreach (T; TestedWith) { // test looping with an empty file std.file.write(deleteme, ""); auto f = File(deleteme, "r"); foreach (T line; lines(f)) { assert(false); } f.close(); // test looping with a file with three lines std.file.write(deleteme, "Line one\nline two\nline three\n"); f.open(deleteme, "r"); uint i = 0; foreach (T line; lines(f)) { if (i == 0) assert(line == "Line one\n"); else if (i == 1) assert(line == "line two\n"); else if (i == 2) assert(line == "line three\n"); else assert(false); ++i; } f.close(); // test looping with a file with three lines, last without a newline std.file.write(deleteme, "Line one\nline two\nline three"); f.open(deleteme, "r"); i = 0; foreach (T line; lines(f)) { if (i == 0) assert(line == "Line one\n"); else if (i == 1) assert(line == "line two\n"); else if (i == 2) assert(line == "line three"); else assert(false); ++i; } f.close(); } // test with ubyte[] inputs alias TestedWith2 = AliasSeq!(immutable(ubyte)[], ubyte[]); foreach (T; TestedWith2) { // test looping with an empty file std.file.write(deleteme, ""); auto f = File(deleteme, "r"); foreach (T line; lines(f)) { assert(false); } f.close(); // test looping with a file with three lines std.file.write(deleteme, "Line one\nline two\nline three\n"); f.open(deleteme, "r"); uint i = 0; foreach (T line; lines(f)) { if (i == 0) assert(cast(char[]) line == "Line one\n"); else if (i == 1) assert(cast(char[]) line == "line two\n", T.stringof ~ " " ~ cast(char[]) line); else if (i == 2) assert(cast(char[]) line == "line three\n"); else assert(false); ++i; } f.close(); // test looping with a file with three lines, last without a newline std.file.write(deleteme, "Line one\nline two\nline three"); f.open(deleteme, "r"); i = 0; foreach (T line; lines(f)) { if (i == 0) assert(cast(char[]) line == "Line one\n"); else if (i == 1) assert(cast(char[]) line == "line two\n"); else if (i == 2) assert(cast(char[]) line == "line three"); else assert(false); ++i; } f.close(); } foreach (T; AliasSeq!(ubyte[])) { // test looping with a file with three lines, last without a newline // using a counter too this time std.file.write(deleteme, "Line one\nline two\nline three"); auto f = File(deleteme, "r"); uint i = 0; foreach (ulong j, T line; lines(f)) { if (i == 0) assert(cast(char[]) line == "Line one\n"); else if (i == 1) assert(cast(char[]) line == "line two\n"); else if (i == 2) assert(cast(char[]) line == "line three"); else assert(false); ++i; } f.close(); } } /** Iterates through a file a chunk at a time by using $(D foreach). Example: --------- void main() { foreach (ubyte[] buffer; chunks(stdin, 4096)) { ... use buffer ... } } --------- The content of $(D buffer) is reused across calls. In the example above, $(D buffer.length) is 4096 for all iterations, except for the last one, in which case $(D buffer.length) may be less than 4096 (but always greater than zero). In case of an I/O error, an $(D StdioException) is thrown. */ auto chunks(File f, size_t size) { return ChunksImpl(f, size); } private struct ChunksImpl { private File f; private size_t size; // private string fileName; // Currently, no use this(File f, size_t size) in { assert(size, "size must be larger than 0"); } body { this.f = f; this.size = size; } // static chunks opCall(string fName, size_t size) // { // auto f = enforce(fopen(fName), // new StdioException("Cannot open file `"~fName~"' for reading")); // auto result = chunks(f, size); // result.fileName = fName; // return result; // } int opApply(D)(scope D dg) { import core.stdc.stdlib : alloca; enum maxStackSize = 1024 * 16; ubyte[] buffer = void; if (size < maxStackSize) buffer = (cast(ubyte*) alloca(size))[0 .. size]; else buffer = new ubyte[size]; size_t r = void; int result = 1; uint tally = 0; while ((r = fread(buffer.ptr, buffer[0].sizeof, size, f._p.handle)) > 0) { assert(r <= size); if (r != size) { // error occured if (!f.eof) throw new StdioException(null); buffer.length = r; } static if (is(typeof(dg(tally, buffer)))) { if ((result = dg(tally, buffer)) != 0) break; } else { if ((result = dg(buffer)) != 0) break; } ++tally; } return result; } } unittest { static import std.file; //printf("Entering test at line %d\n", __LINE__); scope(failure) printf("Failed test at line %d\n", __LINE__); auto deleteme = testFilename(); scope(exit) { std.file.remove(deleteme); } // test looping with an empty file std.file.write(deleteme, ""); auto f = File(deleteme, "r"); foreach (ubyte[] line; chunks(f, 4)) { assert(false); } f.close(); // test looping with a file with three lines std.file.write(deleteme, "Line one\nline two\nline three\n"); f = File(deleteme, "r"); uint i = 0; foreach (ubyte[] line; chunks(f, 3)) { if (i == 0) assert(cast(char[]) line == "Lin"); else if (i == 1) assert(cast(char[]) line == "e o"); else if (i == 2) assert(cast(char[]) line == "ne\n"); else break; ++i; } f.close(); } /********************* * Thrown if I/O errors happen. */ class StdioException : Exception { static import core.stdc.errno; /// Operating system error code. uint errno; /** Initialize with a message and an error code. */ this(string message, uint e = core.stdc.errno.errno) { import std.conv : to; errno = e; version (Posix) { import core.stdc.string : strerror_r; char[256] buf = void; version (CRuntime_Glibc) { auto s = strerror_r(errno, buf.ptr, buf.length); } else { strerror_r(errno, buf.ptr, buf.length); auto s = buf.ptr; } } else { import core.stdc.string : strerror; auto s = core.stdc.string.strerror(errno); } auto sysmsg = to!string(s); // If e is 0, we don't use the system error message. (The message // is "Success", which is rather pointless for an exception.) super(e == 0 ? message : (message.ptr ? message ~ " (" ~ sysmsg ~ ")" : sysmsg)); } /** Convenience functions that throw an $(D StdioException). */ static void opCall(string msg) { throw new StdioException(msg); } /// ditto static void opCall() { throw new StdioException(null, core.stdc.errno.errno); } } extern(C) void std_stdio_static_this() { static import core.stdc.stdio; //Bind stdin, stdout, stderr __gshared File.Impl stdinImpl; stdinImpl.handle = core.stdc.stdio.stdin; .stdin._p = &stdinImpl; // stdout __gshared File.Impl stdoutImpl; stdoutImpl.handle = core.stdc.stdio.stdout; .stdout._p = &stdoutImpl; // stderr __gshared File.Impl stderrImpl; stderrImpl.handle = core.stdc.stdio.stderr; .stderr._p = &stderrImpl; } //--------- __gshared { /** The standard input stream. Bugs: Due to $(WEB https://issues.dlang.org/show_bug.cgi?id=15768, bug 15768), it is thread un-safe to reassign `stdin` to a different `File` instance than the default. */ File stdin; /// unittest { // Read stdin, sort lines, write to stdout import std.stdio, std.array, std.algorithm : sort, copy; void main() { stdin // read from stdin .byLineCopy(KeepTerminator.yes) // copying each line .array() // convert to array of lines .sort() // sort the lines .copy( // copy output of .sort to an OutputRange stdout.lockingTextWriter()); // the OutputRange } } /** The standard output stream. Bugs: Due to $(WEB https://issues.dlang.org/show_bug.cgi?id=15768, bug 15768), it is thread un-safe to reassign `stdout` to a different `File` instance than the default. */ File stdout; /** The standard error stream. Bugs: Due to $(WEB https://issues.dlang.org/show_bug.cgi?id=15768, bug 15768), it is thread un-safe to reassign `stderr` to a different `File` instance than the default. */ File stderr; } unittest { static import std.file; import std.typecons : tuple; scope(failure) printf("Failed test at line %d\n", __LINE__); auto deleteme = testFilename(); std.file.write(deleteme, "1 2\n4 1\n5 100"); scope(exit) std.file.remove(deleteme); { File f = File(deleteme); scope(exit) f.close(); auto t = [ tuple(1, 2), tuple(4, 1), tuple(5, 100) ]; uint i; foreach (e; f.byRecord!(int, int)("%s %s")) { //writeln(e); assert(e == t[i++]); } assert(i == 3); } } // roll our own appender, but with "safe" arrays private struct ReadlnAppender { import core.stdc.string; char[] buf; size_t pos; bool safeAppend = false; void initialize(char[] b) { buf = b; pos = 0; } @property char[] data() { if (safeAppend) assumeSafeAppend(buf.ptr[0..pos]); return buf.ptr[0..pos]; } bool reserveWithoutAllocating(size_t n) { if (buf.length >= pos + n) // buf is already large enough return true; immutable curCap = buf.capacity; if (curCap >= pos + n) { buf.length = curCap; /* Any extra capacity we end up not using can safely be claimed by someone else. */ safeAppend = true; return true; } return false; } void reserve(size_t n) { if (!reserveWithoutAllocating(n)) { size_t ncap = buf.length * 2 + 128 + n; char[] nbuf = new char[ncap]; memcpy(nbuf.ptr, buf.ptr, pos); buf = nbuf; // Allocated a new buffer. No one else knows about it. safeAppend = true; } } void putchar(char c) { reserve(1); buf.ptr[pos++] = c; } void putdchar(dchar dc) { import std.utf : toUTF8; char[4] ubuf; char[] u = toUTF8(ubuf, dc); reserve(u.length); foreach(c; u) buf.ptr[pos++] = c; } void putonly(char[] b) { assert(pos == 0); // assume this is the only put call if (reserveWithoutAllocating(b.length)) memcpy(buf.ptr + pos, b.ptr, b.length); else buf = b.dup; pos = b.length; } } // Private implementation of readln version (DIGITAL_MARS_STDIO) private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation /*ignored*/) { FLOCK(fps); scope(exit) FUNLOCK(fps); /* Since fps is now locked, we can create an "unshared" version * of fp. */ auto fp = cast(_iobuf*)fps; ReadlnAppender app; app.initialize(buf); if (__fhnd_info[fp._file] & FHND_WCHAR) { /* Stream is in wide characters. * Read them and convert to chars. */ static assert(wchar_t.sizeof == 2); for (int c = void; (c = FGETWC(fp)) != -1; ) { if ((c & ~0x7F) == 0) { app.putchar(cast(char) c); if (c == terminator) break; } else { if (c >= 0xD800 && c <= 0xDBFF) { int c2 = void; if ((c2 = FGETWC(fp)) != -1 || c2 < 0xDC00 && c2 > 0xDFFF) { StdioException("unpaired UTF-16 surrogate"); } c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00); } app.putdchar(cast(dchar)c); } } if (ferror(fps)) StdioException(); } else if (fp._flag & _IONBF) { /* Use this for unbuffered I/O, when running * across buffer boundaries, or for any but the common * cases. */ L1: int c; while((c = FGETC(fp)) != -1) { app.putchar(cast(char) c); if(c == terminator) { buf = app.data; return buf.length; } } if (ferror(fps)) StdioException(); } else { int u = fp._cnt; char* p = fp._ptr; int i; if (fp._flag & _IOTRAN) { /* Translated mode ignores \r and treats ^Z as end-of-file */ char c; while (1) { if (i == u) // if end of buffer goto L1; // give up c = p[i]; i++; if (c != '\r') { if (c == terminator) break; if (c != 0x1A) continue; goto L1; } else { if (i != u && p[i] == terminator) break; goto L1; } } app.putonly(p[0..i]); app.buf.ptr[i - 1] = cast(char)terminator; if (terminator == '\n' && c == '\r') i++; } else { while (1) { if (i == u) // if end of buffer goto L1; // give up auto c = p[i]; i++; if (c == terminator) break; } app.putonly(p[0..i]); } fp._cnt -= i; fp._ptr += i; } buf = app.data; return buf.length; } version (MICROSOFT_STDIO) private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation /*ignored*/) { import core.memory; FLOCK(fps); scope(exit) FUNLOCK(fps); /* Since fps is now locked, we can create an "unshared" version * of fp. */ auto fp = cast(_iobuf*)fps; ReadlnAppender app; app.initialize(buf); int c; while((c = FGETC(fp)) != -1) { app.putchar(cast(char) c); if(c == terminator) { buf = app.data; return buf.length; } } if (ferror(fps)) StdioException(); buf = app.data; return buf.length; } version (HAS_GETDELIM) private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation) { import core.memory; import core.stdc.stdlib : free; import core.stdc.wchar_ : fwide; if (orientation == File.Orientation.wide) { /* Stream is in wide characters. * Read them and convert to chars. */ FLOCK(fps); scope(exit) FUNLOCK(fps); auto fp = cast(_iobuf*)fps; version (Windows) { buf.length = 0; for (int c = void; (c = FGETWC(fp)) != -1; ) { if ((c & ~0x7F) == 0) { buf ~= c; if (c == terminator) break; } else { if (c >= 0xD800 && c <= 0xDBFF) { int c2 = void; if ((c2 = FGETWC(fp)) != -1 || c2 < 0xDC00 && c2 > 0xDFFF) { StdioException("unpaired UTF-16 surrogate"); } c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00); } import std.utf : encode; encode(buf, c); } } if (ferror(fp)) StdioException(); return buf.length; } else version (Posix) { buf.length = 0; for (int c; (c = FGETWC(fp)) != -1; ) { import std.utf : encode; if ((c & ~0x7F) == 0) buf ~= cast(char)c; else encode(buf, cast(dchar)c); if (c == terminator) break; } if (ferror(fps)) StdioException(); return buf.length; } else { static assert(0); } } static char *lineptr = null; static size_t n = 0; scope(exit) { if (n > 128 * 1024) { // Bound memory used by readln free(lineptr); lineptr = null; n = 0; } } auto s = getdelim(&lineptr, &n, terminator, fps); if (s < 0) { if (ferror(fps)) StdioException(); buf.length = 0; // end of file return 0; } if (s <= buf.length) { buf = buf.ptr[0 .. s]; buf[] = lineptr[0 .. s]; } else { buf = lineptr[0 .. s].dup; } return s; } version (NO_GETDELIM) private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation) { import core.stdc.wchar_ : fwide; FLOCK(fps); scope(exit) FUNLOCK(fps); auto fp = cast(_iobuf*)fps; if (orientation == File.Orientation.wide) { /* Stream is in wide characters. * Read them and convert to chars. */ version (Windows) { buf.length = 0; for (int c; (c = FGETWC(fp)) != -1; ) { if ((c & ~0x7F) == 0) { buf ~= c; if (c == terminator) break; } else { if (c >= 0xD800 && c <= 0xDBFF) { int c2 = void; if ((c2 = FGETWC(fp)) != -1 || c2 < 0xDC00 && c2 > 0xDFFF) { StdioException("unpaired UTF-16 surrogate"); } c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00); } import std.utf : encode; encode(buf, c); } } if (ferror(fp)) StdioException(); return buf.length; } else version (Posix) { buf.length = 0; for (int c; (c = FGETWC(fp)) != -1; ) { if ((c & ~0x7F) == 0) buf ~= cast(char)c; else std.utf.encode(buf, cast(dchar)c); if (c == terminator) break; } if (ferror(fps)) StdioException(); return buf.length; } else { static assert(0); } } // Narrow stream // First, fill the existing buffer for (size_t bufPos = 0; bufPos < buf.length; ) { immutable c = FGETC(fp); if (c == -1) { buf.length = bufPos; goto endGame; } buf.ptr[bufPos++] = cast(char) c; if (c == terminator) { // No need to test for errors in file buf.length = bufPos; return bufPos; } } // Then, append to it for (int c; (c = FGETC(fp)) != -1; ) { buf ~= cast(char)c; if (c == terminator) { // No need to test for errors in file return buf.length; } } endGame: if (ferror(fps)) StdioException(); return buf.length; } unittest { static import std.file; auto deleteme = testFilename(); scope(exit) std.file.remove(deleteme); std.file.write(deleteme, "abcd\n0123456789abcde\n1234\n"); File f = File(deleteme, "rb"); char[] ln = new char[2]; //assert(ln.capacity > 5); char* lnptr = ln.ptr; f.readln(ln); assert(ln == "abcd\n"); //assert(lnptr == ln.ptr); // should not reallocate char[] t = ln[0..2]; t ~= 't'; assert(t == "abt"); assert(ln == "abcd\n"); // bug 13856: ln stomped to "abtd" // it can also stomp the array length ln = new char[4]; //assert(ln.capacity < 16); lnptr = ln.ptr; f.readln(ln); assert(ln == "0123456789abcde\n"); //assert(ln.ptr != lnptr); // used to write to ln, overwriting allocation length byte char[100] buf; ln = buf[]; f.readln(ln); assert(ln == "1234\n"); assert(ln.ptr == buf.ptr); // avoid allocation, buffer is good enough } /** Experimental network access via the File interface Opens a TCP connection to the given host and port, then returns a File struct with read and write access through the same interface as any other file (meaning writef and the byLine ranges work!). Authors: Adam D. Ruppe Bugs: Only works on Linux */ version(linux) { File openNetwork(string host, ushort port) { static import sock = core.sys.posix.sys.socket; static import core.sys.posix.unistd; import core.stdc.string : memcpy; import core.sys.posix.arpa.inet : htons; import core.sys.posix.netdb : gethostbyname; import core.sys.posix.netinet.in_ : sockaddr_in; import std.conv : to; import std.exception : enforce; import std.internal.cstring : tempCString; auto h = enforce( gethostbyname(host.tempCString()), new StdioException("gethostbyname")); int s = sock.socket(sock.AF_INET, sock.SOCK_STREAM, 0); enforce(s != -1, new StdioException("socket")); scope(failure) { // want to make sure it doesn't dangle if something throws. Upon // normal exit, the File struct's reference counting takes care of // closing, so we don't need to worry about success core.sys.posix.unistd.close(s); } sockaddr_in addr; addr.sin_family = sock.AF_INET; addr.sin_port = htons(port); memcpy(&addr.sin_addr.s_addr, h.h_addr, h.h_length); enforce(sock.connect(s, cast(sock.sockaddr*) &addr, addr.sizeof) != -1, new StdioException("Connect failed")); File f; f.fdopen(s, "w+", host ~ ":" ~ to!string(port)); return f; } } version(unittest) string testFilename(string file = __FILE__, size_t line = __LINE__) @safe { import std.conv : text; import std.file : deleteme; import std.path : baseName; // filename intentionally contains non-ASCII (Russian) characters for test Issue 7648 return text(deleteme, "-детка.", baseName(file), ".", line); } ldc-1.1.0-beta3-src/runtime/phobos/std/container/0000775000175000017500000000000012776215007017670 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/container/array.d0000664000175000017500000015617612776215007021173 0ustar kaikai/** This module provides an $(D Array) type with deterministic memory usage not reliant on the GC, as an alternative to the built-in arrays. This module is a submodule of $(LINK2 std_container.html, std.container). Source: $(PHOBOSSRC std/container/_array.d) Macros: WIKI = Phobos/StdContainer TEXTWITHCOMMAS = $0 Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. License: Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at $(WEB boost.org/LICENSE_1_0.txt)). Authors: Steven Schveighoffer, $(WEB erdani.com, Andrei Alexandrescu) */ module std.container.array; import std.range.primitives; import std.traits; import core.exception : RangeError; import std.algorithm : move; public import std.container.util; private struct RangeT(A) { /* Workaround for Issue 13629 at https://issues.dlang.org/show_bug.cgi?id=13629 See also: http://forum.dlang.org/post/vbmwhzvawhnkoxrhbnyb@forum.dlang.org */ private A[1] _outer_; private @property ref inout(A) _outer() inout { return _outer_[0]; } private size_t _a, _b; /* E is different from T when A is more restrictively qualified than T: immutable(Array!int) => T == int, E = immutable(int) */ alias E = typeof(_outer_[0]._data._payload[0]); private this(ref A data, size_t a, size_t b) { _outer_ = data; _a = a; _b = b; } @property RangeT save() { return this; } @property bool empty() @safe pure nothrow const { return _a >= _b; } @property size_t length() @safe pure nothrow const { return _b - _a; } alias opDollar = length; @property ref inout(E) front() inout { version (assert) if (empty) throw new RangeError(); return _outer[_a]; } @property ref inout(E) back() inout { version (assert) if (empty) throw new RangeError(); return _outer[_b - 1]; } void popFront() @safe pure nothrow { version (assert) if (empty) throw new RangeError(); ++_a; } void popBack() @safe pure nothrow { version (assert) if (empty) throw new RangeError(); --_b; } static if (isMutable!A) { E moveFront() { version (assert) if (empty || _a >= _outer.length) throw new RangeError(); return move(_outer._data._payload[_a]); } E moveBack() { version (assert) if (empty || _b > _outer.length) throw new RangeError(); return move(_outer._data._payload[_b - 1]); } E moveAt(size_t i) { version (assert) if (_a + i >= _b || _a + i >= _outer.length) throw new RangeError(); return move(_outer._data._payload[_a + i]); } } ref inout(E) opIndex(size_t i) inout { version (assert) if (_a + i >= _b) throw new RangeError(); return _outer[_a + i]; } RangeT opSlice() { return typeof(return)(_outer, _a, _b); } RangeT opSlice(size_t i, size_t j) { version (assert) if (i > j || _a + j > _b) throw new RangeError(); return typeof(return)(_outer, _a + i, _a + j); } RangeT!(const(A)) opSlice() const { return typeof(return)(_outer, _a, _b); } RangeT!(const(A)) opSlice(size_t i, size_t j) const { version (assert) if (i > j || _a + j > _b) throw new RangeError(); return typeof(return)(_outer, _a + i, _a + j); } static if (isMutable!A) { void opSliceAssign(E value) { version (assert) if (_b > _outer.length) throw new RangeError(); _outer[_a .. _b] = value; } void opSliceAssign(E value, size_t i, size_t j) { version (assert) if (_a + j > _b) throw new RangeError(); _outer[_a + i .. _a + j] = value; } void opSliceUnary(string op)() if (op == "++" || op == "--") { version (assert) if (_b > _outer.length) throw new RangeError(); mixin(op~"_outer[_a .. _b];"); } void opSliceUnary(string op)(size_t i, size_t j) if (op == "++" || op == "--") { version (assert) if (_a + j > _b) throw new RangeError(); mixin(op~"_outer[_a + i .. _a + j];"); } void opSliceOpAssign(string op)(E value) { version (assert) if (_b > _outer.length) throw new RangeError(); mixin("_outer[_a .. _b] "~op~"= value;"); } void opSliceOpAssign(string op)(E value, size_t i, size_t j) { version (assert) if (_a + j > _b) throw new RangeError(); mixin("_outer[_a + i .. _a + j] "~op~"= value;"); } } } /** Array type with deterministic control of memory. The memory allocated for the array is reclaimed as soon as possible; there is no reliance on the garbage collector. $(D Array) uses $(D malloc) and $(D free) for managing its own memory. This means that pointers to elements of an $(D Array) will become dangling as soon as the element is removed from the $(D Array). On the other hand the memory allocated by an $(D Array) will be scanned by the GC and GC managed objects referenced from an $(D Array) will be kept alive. Note: When using $(D Array) with range-based functions like those in $(D std.algorithm), $(D Array) must be sliced to get a range (for example, use $(D array[].map!) instead of $(D array.map!)). The container itself is not a range. */ struct Array(T) if (!is(Unqual!T == bool)) { import core.stdc.stdlib; import core.stdc.string; import core.memory; import std.algorithm : initializeAll, copy; import std.exception : enforce; import std.typecons : RefCounted, RefCountedAutoInitialize; // This structure is not copyable. private struct Payload { size_t _capacity; T[] _payload; // Convenience constructor this(T[] p) { _capacity = p.length; _payload = p; } // Destructor releases array memory ~this() { //Warning: destroy will also destroy class instances. //The hasElaborateDestructor protects us here. static if (hasElaborateDestructor!T) foreach (ref e; _payload) .destroy(e); static if (hasIndirections!T) GC.removeRange(_payload.ptr); free(_payload.ptr); } this(this) { assert(0); } void opAssign(Payload rhs) { assert(false); } // Duplicate data // @property Payload dup() // { // Payload result; // result._payload = _payload.dup; // // Conservatively assume initial capacity == length // result._capacity = result._payload.length; // return result; // } // length @property size_t length() const { return _payload.length; } // length @property void length(size_t newLength) { if (length >= newLength) { // shorten static if (hasElaborateDestructor!T) foreach (ref e; _payload.ptr[newLength .. _payload.length]) .destroy(e); _payload = _payload.ptr[0 .. newLength]; return; } // enlarge auto startEmplace = length; _payload = (cast(T*) realloc(_payload.ptr, T.sizeof * newLength))[0 .. newLength]; initializeAll(_payload.ptr[startEmplace .. length]); } // capacity @property size_t capacity() const { return _capacity; } // reserve void reserve(size_t elements) { if (elements <= capacity) return; immutable sz = elements * T.sizeof; static if (hasIndirections!T) // should use hasPointers instead { /* Because of the transactional nature of this * relative to the garbage collector, ensure no * threading bugs by using malloc/copy/free rather * than realloc. */ immutable oldLength = length; auto newPayload = enforce(cast(T*) malloc(sz))[0 .. oldLength]; // copy old data over to new array memcpy(newPayload.ptr, _payload.ptr, T.sizeof * oldLength); // Zero out unused capacity to prevent gc from seeing // false pointers memset(newPayload.ptr + oldLength, 0, (elements - oldLength) * T.sizeof); GC.addRange(newPayload.ptr, sz); GC.removeRange(_payload.ptr); free(_payload.ptr); _payload = newPayload; } else { /* These can't have pointers, so no need to zero * unused region */ auto newPayload = enforce(cast(T*) realloc(_payload.ptr, sz))[0 .. length]; _payload = newPayload; } _capacity = elements; } // Insert one item size_t insertBack(Stuff)(Stuff stuff) if (isImplicitlyConvertible!(Stuff, T)) { import std.conv : emplace; if (_capacity == length) { reserve(1 + capacity * 3 / 2); } assert(capacity > length && _payload.ptr); emplace(_payload.ptr + _payload.length, stuff); _payload = _payload.ptr[0 .. _payload.length + 1]; return 1; } /// Insert a range of items size_t insertBack(Stuff)(Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) { static if (hasLength!Stuff) { immutable oldLength = length; reserve(oldLength + stuff.length); } size_t result; foreach (item; stuff) { insertBack(item); ++result; } static if (hasLength!Stuff) { assert(length == oldLength + stuff.length); } return result; } } private alias Data = RefCounted!(Payload, RefCountedAutoInitialize.no); private Data _data; /** Constructor taking a number of items */ this(U)(U[] values...) if (isImplicitlyConvertible!(U, T)) { import std.conv : emplace; auto p = cast(T*) malloc(T.sizeof * values.length); static if (hasIndirections!T) { if (p) GC.addRange(p, T.sizeof * values.length); } foreach (i, e; values) { emplace(p + i, e); assert(p[i] == e); } _data = Data(p[0 .. values.length]); } /** Constructor taking an input range */ this(Stuff)(Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T) && !is(Stuff == T[])) { insertBack(stuff); } /** Comparison for equality. */ bool opEquals(const Array rhs) const { return opEquals(rhs); } /// ditto bool opEquals(ref const Array rhs) const { if (empty) return rhs.empty; if (rhs.empty) return false; return _data._payload == rhs._data._payload; } /** Defines the container's primary range, which is a random-access range. ConstRange is a variant with const elements. ImmutableRange is a variant with immutable elements. */ alias Range = RangeT!Array; alias ConstRange = RangeT!(const Array); /// ditto alias ImmutableRange = RangeT!(immutable Array); /// ditto /** Duplicates the container. The elements themselves are not transitively duplicated. Complexity: $(BIGOH n). */ @property Array dup() { if (!_data.refCountedStore.isInitialized) return this; return Array(_data._payload); } /** Property returning $(D true) if and only if the container has no elements. Complexity: $(BIGOH 1) */ @property bool empty() const { return !_data.refCountedStore.isInitialized || _data._payload.empty; } /** Returns the number of elements in the container. Complexity: $(BIGOH 1). */ @property size_t length() const { return _data.refCountedStore.isInitialized ? _data._payload.length : 0; } /// ditto size_t opDollar() const { return length; } /** Returns the maximum number of elements the container can store without (a) allocating memory, (b) invalidating iterators upon insertion. Complexity: $(BIGOH 1) */ @property size_t capacity() { return _data.refCountedStore.isInitialized ? _data._capacity : 0; } /** Ensures sufficient capacity to accommodate $(D e) elements. Postcondition: $(D capacity >= e) Complexity: $(BIGOH 1) */ void reserve(size_t elements) { if (!_data.refCountedStore.isInitialized) { if (!elements) return; immutable sz = elements * T.sizeof; auto p = enforce(malloc(sz)); static if (hasIndirections!T) { GC.addRange(p, sz); } _data = Data(cast(T[]) p[0 .. 0]); _data._capacity = elements; } else { _data.reserve(elements); } } /** Returns a range that iterates over elements of the container, in forward order. Complexity: $(BIGOH 1) */ Range opSlice() { return typeof(return)(this, 0, length); } ConstRange opSlice() const { return typeof(return)(this, 0, length); } ImmutableRange opSlice() immutable { return typeof(return)(this, 0, length); } /** Returns a range that iterates over elements of the container from index $(D a) up to (excluding) index $(D b). Precondition: $(D a <= b && b <= length) Complexity: $(BIGOH 1) */ Range opSlice(size_t i, size_t j) { version (assert) if (i > j || j > length) throw new RangeError(); return typeof(return)(this, i, j); } ConstRange opSlice(size_t i, size_t j) const { version (assert) if (i > j || j > length) throw new RangeError(); return typeof(return)(this, i, j); } ImmutableRange opSlice(size_t i, size_t j) immutable { version (assert) if (i > j || j > length) throw new RangeError(); return typeof(return)(this, i, j); } /** Forward to $(D opSlice().front) and $(D opSlice().back), respectively. Precondition: $(D !empty) Complexity: $(BIGOH 1) */ @property ref inout(T) front() inout { version (assert) if (!_data.refCountedStore.isInitialized) throw new RangeError(); return _data._payload[0]; } /// ditto @property ref inout(T) back() inout { version (assert) if (!_data.refCountedStore.isInitialized) throw new RangeError(); return _data._payload[$ - 1]; } /** Indexing operators yield or modify the value at a specified index. Precondition: $(D i < length) Complexity: $(BIGOH 1) */ ref inout(T) opIndex(size_t i) inout { version (assert) if (!_data.refCountedStore.isInitialized) throw new RangeError(); return _data._payload[i]; } /** Slicing operations execute an operation on an entire slice. Precondition: $(D i < j && j < length) Complexity: $(BIGOH slice.length) */ void opSliceAssign(T value) { if (!_data.refCountedStore.isInitialized) return; _data._payload[] = value; } /// ditto void opSliceAssign(T value, size_t i, size_t j) { auto slice = _data.refCountedStore.isInitialized ? _data._payload : T[].init; slice[i .. j] = value; } /// ditto void opSliceUnary(string op)() if (op == "++" || op == "--") { if (!_data.refCountedStore.isInitialized) return; mixin(op~"_data._payload[];"); } /// ditto void opSliceUnary(string op)(size_t i, size_t j) if (op == "++" || op == "--") { auto slice = _data.refCountedStore.isInitialized ? _data._payload : T[].init; mixin(op~"slice[i .. j];"); } /// ditto void opSliceOpAssign(string op)(T value) { if (!_data.refCountedStore.isInitialized) return; mixin("_data._payload[] "~op~"= value;"); } /// ditto void opSliceOpAssign(string op)(T value, size_t i, size_t j) { auto slice = _data.refCountedStore.isInitialized ? _data._payload : T[].init; mixin("slice[i .. j] "~op~"= value;"); } /** Returns a new container that's the concatenation of $(D this) and its argument. $(D opBinaryRight) is only defined if $(D Stuff) does not define $(D opBinary). Complexity: $(BIGOH n + m), where m is the number of elements in $(D stuff) */ Array opBinary(string op, Stuff)(Stuff stuff) if (op == "~") { // TODO: optimize Array result; result ~= this[]; assert(result.length == length); result ~= stuff[]; return result; } /** Forwards to $(D insertBack(stuff)). */ void opOpAssign(string op, Stuff)(Stuff stuff) if (op == "~") { static if (is(typeof(stuff[]))) { insertBack(stuff[]); } else { insertBack(stuff); } } /** Removes all contents from the container. The container decides how $(D capacity) is affected. Postcondition: $(D empty) Complexity: $(BIGOH n) */ void clear() { _data = Data.init; } /** Sets the number of elements in the container to $(D newSize). If $(D newSize) is greater than $(D length), the added elements are added to unspecified positions in the container and initialized with $(D T.init). Complexity: $(BIGOH abs(n - newLength)) Postcondition: $(D length == newLength) */ @property void length(size_t newLength) { _data.refCountedStore.ensureInitialized(); _data.length = newLength; } /** Picks one value in an unspecified position in the container, removes it from the container, and returns it. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Precondition: $(D !empty) Returns: The element removed. Complexity: $(BIGOH log(n)). */ T removeAny() { auto result = back; removeBack(); return result; } /// ditto alias stableRemoveAny = removeAny; /** Inserts $(D value) to the front or back of the container. $(D stuff) can be a value convertible to $(D T) or a range of objects convertible to $(D T). The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements inserted Complexity: $(BIGOH m * log(n)), where $(D m) is the number of elements in $(D stuff) */ size_t insertBack(Stuff)(Stuff stuff) if (isImplicitlyConvertible!(Stuff, T) || isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) { _data.refCountedStore.ensureInitialized(); return _data.insertBack(stuff); } /// ditto alias insert = insertBack; /** Removes the value at the back of the container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Precondition: $(D !empty) Complexity: $(BIGOH log(n)). */ void removeBack() { enforce(!empty); static if (hasElaborateDestructor!T) .destroy(_data._payload[$ - 1]); _data._payload = _data._payload[0 .. $ - 1]; } /// ditto alias stableRemoveBack = removeBack; /** Removes $(D howMany) values at the front or back of the container. Unlike the unparameterized versions above, these functions do not throw if they could not remove $(D howMany) elements. Instead, if $(D howMany > n), all elements are removed. The returned value is the effective number of elements removed. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements removed Complexity: $(BIGOH howMany). */ size_t removeBack(size_t howMany) { if (howMany > length) howMany = length; static if (hasElaborateDestructor!T) foreach (ref e; _data._payload[$ - howMany .. $]) .destroy(e); _data._payload = _data._payload[0 .. $ - howMany]; return howMany; } /// ditto alias stableRemoveBack = removeBack; /** Inserts $(D stuff) before, after, or instead range $(D r), which must be a valid range previously extracted from this container. $(D stuff) can be a value convertible to $(D T) or a range of objects convertible to $(D T). The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of values inserted. Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff) */ size_t insertBefore(Stuff)(Range r, Stuff stuff) if (isImplicitlyConvertible!(Stuff, T)) { import std.conv : emplace; enforce(r._outer._data is _data && r._a <= length); reserve(length + 1); assert(_data.refCountedStore.isInitialized); // Move elements over by one slot memmove(_data._payload.ptr + r._a + 1, _data._payload.ptr + r._a, T.sizeof * (length - r._a)); emplace(_data._payload.ptr + r._a, stuff); _data._payload = _data._payload.ptr[0 .. _data._payload.length + 1]; return 1; } /// ditto size_t insertBefore(Stuff)(Range r, Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) { import std.conv : emplace; enforce(r._outer._data is _data && r._a <= length); static if (isForwardRange!Stuff) { // Can find the length in advance auto extra = walkLength(stuff); if (!extra) return 0; reserve(length + extra); assert(_data.refCountedStore.isInitialized); // Move elements over by extra slots memmove(_data._payload.ptr + r._a + extra, _data._payload.ptr + r._a, T.sizeof * (length - r._a)); foreach (p; _data._payload.ptr + r._a .. _data._payload.ptr + r._a + extra) { emplace(p, stuff.front); stuff.popFront(); } _data._payload = _data._payload.ptr[0 .. _data._payload.length + extra]; return extra; } else { import std.algorithm : bringToFront; enforce(_data); immutable offset = r._a; enforce(offset <= length); auto result = insertBack(stuff); bringToFront(this[offset .. length - result], this[length - result .. length]); return result; } } /// ditto size_t insertAfter(Stuff)(Range r, Stuff stuff) { import std.algorithm : bringToFront; enforce(r._outer._data is _data); // TODO: optimize immutable offset = r._b; enforce(offset <= length); auto result = insertBack(stuff); bringToFront(this[offset .. length - result], this[length - result .. length]); return result; } /// ditto size_t replace(Stuff)(Range r, Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) { enforce(r._outer._data is _data); size_t result; for (; !stuff.empty; stuff.popFront()) { if (r.empty) { // insert the rest return result + insertBefore(r, stuff); } r.front = stuff.front; r.popFront(); ++result; } // Remove remaining stuff in r linearRemove(r); return result; } /// ditto size_t replace(Stuff)(Range r, Stuff stuff) if (isImplicitlyConvertible!(Stuff, T)) { enforce(r._outer._data is _data); if (r.empty) { insertBefore(r, stuff); } else { r.front = stuff; r.popFront(); linearRemove(r); } return 1; } /** Removes all elements belonging to $(D r), which must be a range obtained originally from this container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: A range spanning the remaining elements in the container that initially were right after $(D r). Complexity: $(BIGOH n - m), where $(D m) is the number of elements in $(D r) */ Range linearRemove(Range r) { enforce(r._outer._data is _data); enforce(_data.refCountedStore.isInitialized); enforce(r._a <= r._b && r._b <= length); immutable offset1 = r._a; immutable offset2 = r._b; immutable tailLength = length - offset2; // Use copy here, not a[] = b[] because the ranges may overlap copy(this[offset2 .. length], this[offset1 .. offset1 + tailLength]); length = offset1 + tailLength; return this[length - tailLength .. length]; } } unittest { Array!int a; assert(a.empty); } unittest { Array!int a = Array!int(1, 2, 3); //a._data._refCountedDebug = true; auto b = a.dup; assert(b == Array!int(1, 2, 3)); b.front = 42; assert(b == Array!int(42, 2, 3)); assert(a == Array!int(1, 2, 3)); } unittest { auto a = Array!int(1, 2, 3); assert(a.length == 3); } unittest { const Array!int a = [1, 2]; assert(a[0] == 1); assert(a.front == 1); assert(a.back == 2); static assert(!__traits(compiles, { a[0] = 1; })); static assert(!__traits(compiles, { a.front = 1; })); static assert(!__traits(compiles, { a.back = 1; })); auto r = a[]; size_t i; foreach (e; r) { assert(e == i + 1); i++; } } unittest { // REG https://issues.dlang.org/show_bug.cgi?id=13621 import std.container : Array, BinaryHeap; alias Heap = BinaryHeap!(Array!int); } unittest { Array!int a; a.reserve(1000); assert(a.length == 0); assert(a.empty); assert(a.capacity >= 1000); auto p = a._data._payload.ptr; foreach (i; 0 .. 1000) { a.insertBack(i); } assert(p == a._data._payload.ptr); } unittest { auto a = Array!int(1, 2, 3); a[1] *= 42; assert(a[1] == 84); } unittest { auto a = Array!int(1, 2, 3); auto b = Array!int(11, 12, 13); auto c = a ~ b; assert(c == Array!int(1, 2, 3, 11, 12, 13)); assert(a ~ b[] == Array!int(1, 2, 3, 11, 12, 13)); assert(a ~ [4,5] == Array!int(1,2,3,4,5)); } unittest { auto a = Array!int(1, 2, 3); auto b = Array!int(11, 12, 13); a ~= b; assert(a == Array!int(1, 2, 3, 11, 12, 13)); } unittest { auto a = Array!int(1, 2, 3, 4); assert(a.removeAny() == 4); assert(a == Array!int(1, 2, 3)); } unittest { auto a = Array!int(1, 2, 3, 4, 5); auto r = a[2 .. a.length]; assert(a.insertBefore(r, 42) == 1); assert(a == Array!int(1, 2, 42, 3, 4, 5)); r = a[2 .. 2]; assert(a.insertBefore(r, [8, 9]) == 2); assert(a == Array!int(1, 2, 8, 9, 42, 3, 4, 5)); } unittest { auto a = Array!int(0, 1, 2, 3, 4, 5, 6, 7, 8); a.linearRemove(a[4 .. 6]); assert(a == Array!int(0, 1, 2, 3, 6, 7, 8)); } // Give the Range object some testing. unittest { import std.algorithm : equal; import std.range : retro; auto a = Array!int(0, 1, 2, 3, 4, 5, 6)[]; auto b = Array!int(6, 5, 4, 3, 2, 1, 0)[]; alias A = typeof(a); static assert(isRandomAccessRange!A); static assert(hasSlicing!A); static assert(hasAssignableElements!A); static assert(hasMobileElements!A); assert(equal(retro(b), a)); assert(a.length == 7); assert(equal(a[1..4], [1, 2, 3])); } // Test issue 5920 unittest { struct structBug5920 { int order; uint* pDestructionMask; ~this() { if (pDestructionMask) *pDestructionMask += 1 << order; } } alias S = structBug5920; uint dMask; auto arr = Array!S(cast(S[])[]); foreach (i; 0..8) arr.insertBack(S(i, &dMask)); // don't check dMask now as S may be copied multiple times (it's ok?) { assert(arr.length == 8); dMask = 0; arr.length = 6; assert(arr.length == 6); // make sure shrinking calls the d'tor assert(dMask == 0b1100_0000); arr.removeBack(); assert(arr.length == 5); // make sure removeBack() calls the d'tor assert(dMask == 0b1110_0000); arr.removeBack(3); assert(arr.length == 2); // ditto assert(dMask == 0b1111_1100); arr.clear(); assert(arr.length == 0); // make sure clear() calls the d'tor assert(dMask == 0b1111_1111); } assert(dMask == 0b1111_1111); // make sure the d'tor is called once only. } // Test issue 5792 (mainly just to check if this piece of code is compilable) unittest { auto a = Array!(int[])([[1,2],[3,4]]); a.reserve(4); assert(a.capacity >= 4); assert(a.length == 2); assert(a[0] == [1,2]); assert(a[1] == [3,4]); a.reserve(16); assert(a.capacity >= 16); assert(a.length == 2); assert(a[0] == [1,2]); assert(a[1] == [3,4]); } // test replace!Stuff with range Stuff unittest { import std.algorithm : equal; auto a = Array!int([1, 42, 5]); a.replace(a[1 .. 2], [2, 3, 4]); assert(equal(a[], [1, 2, 3, 4, 5])); } // test insertBefore and replace with empty Arrays unittest { import std.algorithm : equal; auto a = Array!int(); a.insertBefore(a[], 1); assert(equal(a[], [1])); } unittest { import std.algorithm : equal; auto a = Array!int(); a.insertBefore(a[], [1, 2]); assert(equal(a[], [1, 2])); } unittest { import std.algorithm : equal; auto a = Array!int(); a.replace(a[], [1, 2]); assert(equal(a[], [1, 2])); } unittest { import std.algorithm : equal; auto a = Array!int(); a.replace(a[], 1); assert(equal(a[], [1])); } // make sure that Array instances refuse ranges that don't belong to them unittest { import std.exception; Array!int a = [1, 2, 3]; auto r = a.dup[]; assertThrown(a.insertBefore(r, 42)); assertThrown(a.insertBefore(r, [42])); assertThrown(a.insertAfter(r, 42)); assertThrown(a.replace(r, 42)); assertThrown(a.replace(r, [42])); assertThrown(a.linearRemove(r)); } unittest { auto a = Array!int([1, 1]); a[1] = 0; //Check Array.opIndexAssign assert(a[1] == 0); a[1] += 1; //Check Array.opIndexOpAssign assert(a[1] == 1); //Check Array.opIndexUnary ++a[0]; //a[0]++ //op++ doesn't return, so this shouldn't work, even with 5044 fixed assert(a[0] == 2); assert(+a[0] == +2); assert(-a[0] == -2); assert(~a[0] == ~2); auto r = a[]; r[1] = 0; //Check Array.Range.opIndexAssign assert(r[1] == 0); r[1] += 1; //Check Array.Range.opIndexOpAssign assert(r[1] == 1); //Check Array.Range.opIndexUnary ++r[0]; //r[0]++ //op++ doesn't return, so this shouldn't work, even with 5044 fixed assert(r[0] == 3); assert(+r[0] == +3); assert(-r[0] == -3); assert(~r[0] == ~3); } unittest { import std.algorithm : equal; //Test "array-wide" operations auto a = Array!int([0, 1, 2]); //Array a[] += 5; assert(a[].equal([5, 6, 7])); ++a[]; assert(a[].equal([6, 7, 8])); a[1 .. 3] *= 5; assert(a[].equal([6, 35, 40])); a[0 .. 2] = 0; assert(a[].equal([0, 0, 40])); //Test empty array auto a2 = Array!int.init; ++a2[]; ++a2[0 .. 0]; a2[] = 0; a2[0 .. 0] = 0; a2[] += 0; a2[0 .. 0] += 0; //Test "range-wide" operations auto r = Array!int([0, 1, 2])[]; //Array.Range r[] += 5; assert(r.equal([5, 6, 7])); ++r[]; assert(r.equal([6, 7, 8])); r[1 .. 3] *= 5; assert(r.equal([6, 35, 40])); r[0 .. 2] = 0; assert(r.equal([0, 0, 40])); //Test empty Range auto r2 = Array!int.init[]; ++r2[]; ++r2[0 .. 0]; r2[] = 0; r2[0 .. 0] = 0; r2[] += 0; r2[0 .. 0] += 0; } // Test issue 11194 unittest { static struct S { int i = 1337; void* p; this(this) { assert(i == 1337); } ~this() { assert(i == 1337); } } Array!S arr; S s; arr ~= s; arr ~= s; } unittest //11459 { static struct S { bool b; alias b this; } alias A = Array!S; alias B = Array!(shared bool); } unittest //11884 { import std.algorithm : filter; auto a = Array!int([1, 2, 2].filter!"true"()); } unittest //8282 { auto arr = new Array!int; } unittest //6998 { static int i = 0; class C { int dummy = 1; this(){++i;} ~this(){--i;} } assert(i == 0); auto c = new C(); assert(i == 1); //scope { auto arr = Array!C(c); assert(i == 1); } //Array should not have destroyed the class instance assert(i == 1); //Just to make sure the GC doesn't collect before the above test. assert(c.dummy ==1); } unittest //6998-2 { static class C {int i;} auto c = new C; c.i = 42; Array!C a; a ~= c; a.clear; assert(c.i == 42); //fails } unittest { static assert(is(Array!int.Range)); static assert(is(Array!int.ConstRange)); } unittest // const/immutable Array and Ranges { static void test(A, R, E, S)() { A a; R r = a[]; assert(r.empty); assert(r.length == 0); static assert(is(typeof(r.front) == E)); static assert(is(typeof(r.back) == E)); static assert(is(typeof(r[0]) == E)); static assert(is(typeof(r[]) == S)); static assert(is(typeof(r[0 .. 0]) == S)); } alias A = Array!int; test!(A, A.Range, int, A.Range); test!(A, const A.Range, const int, A.ConstRange); test!(const A, A.ConstRange, const int, A.ConstRange); test!(const A, const A.ConstRange, const int, A.ConstRange); test!(immutable A, A.ImmutableRange, immutable int, A.ImmutableRange); test!(immutable A, const A.ImmutableRange, immutable int, A.ImmutableRange); test!(immutable A, immutable A.ImmutableRange, immutable int, A.ImmutableRange); } //////////////////////////////////////////////////////////////////////////////// // Array!bool //////////////////////////////////////////////////////////////////////////////// /** _Array specialized for $(D bool). Packs together values efficiently by allocating one bit per element. */ struct Array(T) if (is(Unqual!T == bool)) { import std.exception : enforce; import std.typecons : RefCounted, RefCountedAutoInitialize; static immutable uint bitsPerWord = size_t.sizeof * 8; private static struct Data { Array!size_t.Payload _backend; size_t _length; } private RefCounted!(Data, RefCountedAutoInitialize.no) _store; private @property ref size_t[] data() { assert(_store.refCountedStore.isInitialized); return _store._backend._payload; } /** Defines the container's primary range. */ struct Range { private Array _outer; private size_t _a, _b; /// Range primitives @property Range save() { version (bug4437) { return this; } else { auto copy = this; return copy; } } /// Ditto @property bool empty() { return _a >= _b || _outer.length < _b; } /// Ditto @property T front() { enforce(!empty); return _outer[_a]; } /// Ditto @property void front(bool value) { enforce(!empty); _outer[_a] = value; } /// Ditto T moveFront() { enforce(!empty); return _outer.moveAt(_a); } /// Ditto void popFront() { enforce(!empty); ++_a; } /// Ditto @property T back() { enforce(!empty); return _outer[_b - 1]; } /// Ditto @property void back(bool value) { enforce(!empty); _outer[_b - 1] = value; } /// Ditto T moveBack() { enforce(!empty); return _outer.moveAt(_b - 1); } /// Ditto void popBack() { enforce(!empty); --_b; } /// Ditto T opIndex(size_t i) { return _outer[_a + i]; } /// Ditto void opIndexAssign(T value, size_t i) { _outer[_a + i] = value; } /// Ditto T moveAt(size_t i) { return _outer.moveAt(_a + i); } /// Ditto @property size_t length() const { assert(_a <= _b); return _b - _a; } alias opDollar = length; /// ditto Range opSlice(size_t low, size_t high) { assert(_a <= low && low <= high && high <= _b); return Range(_outer, _a + low, _a + high); } } /** Property returning $(D true) if and only if the container has no elements. Complexity: $(BIGOH 1) */ @property bool empty() { return !length; } unittest { Array!bool a; //a._store._refCountedDebug = true; assert(a.empty); a.insertBack(false); assert(!a.empty); } /** Returns a duplicate of the container. The elements themselves are not transitively duplicated. Complexity: $(BIGOH n). */ @property Array dup() { Array result; result.insertBack(this[]); return result; } unittest { Array!bool a; assert(a.empty); auto b = a.dup; assert(b.empty); a.insertBack(true); assert(b.empty); } /** Returns the number of elements in the container. Complexity: $(BIGOH log(n)). */ @property size_t length() const { return _store.refCountedStore.isInitialized ? _store._length : 0; } size_t opDollar() const { return length; } unittest { import std.conv : to; Array!bool a; assert(a.length == 0); a.insert(true); assert(a.length == 1, to!string(a.length)); } /** Returns the maximum number of elements the container can store without (a) allocating memory, (b) invalidating iterators upon insertion. Complexity: $(BIGOH log(n)). */ @property size_t capacity() { return _store.refCountedStore.isInitialized ? cast(size_t) bitsPerWord * _store._backend.capacity : 0; } unittest { import std.conv : to; Array!bool a; assert(a.capacity == 0); foreach (i; 0 .. 100) { a.insert(true); assert(a.capacity >= a.length, to!string(a.capacity)); } } /** Ensures sufficient capacity to accommodate $(D n) elements. Postcondition: $(D capacity >= n) Complexity: $(BIGOH log(e - capacity)) if $(D e > capacity), otherwise $(BIGOH 1). */ void reserve(size_t e) { import std.conv : to; _store.refCountedStore.ensureInitialized(); _store._backend.reserve(to!size_t((e + bitsPerWord - 1) / bitsPerWord)); } unittest { Array!bool a; assert(a.capacity == 0); a.reserve(15657); assert(a.capacity >= 15657); } /** Returns a range that iterates over all elements of the container, in a container-defined order. The container should choose the most convenient and fast method of iteration for $(D opSlice()). Complexity: $(BIGOH log(n)) */ Range opSlice() { return Range(this, 0, length); } unittest { Array!bool a; a.insertBack([true, false, true, true]); assert(a[].length == 4); } /** Returns a range that iterates the container between two specified positions. Complexity: $(BIGOH log(n)) */ Range opSlice(size_t a, size_t b) { enforce(a <= b && b <= length); return Range(this, a, b); } unittest { Array!bool a; a.insertBack([true, false, true, true]); assert(a[0 .. 2].length == 2); } /** Equivalent to $(D opSlice().front) and $(D opSlice().back), respectively. Complexity: $(BIGOH log(n)) */ @property bool front() { enforce(!empty); return data.ptr[0] & 1; } /// Ditto @property void front(bool value) { enforce(!empty); if (value) data.ptr[0] |= 1; else data.ptr[0] &= ~cast(size_t) 1; } unittest { Array!bool a; a.insertBack([true, false, true, true]); assert(a.front); a.front = false; assert(!a.front); } /// Ditto @property bool back() { enforce(!empty); return cast(bool)(data.back & (cast(size_t)1 << ((_store._length - 1) % bitsPerWord))); } /// Ditto @property void back(bool value) { enforce(!empty); if (value) { data.back |= (cast(size_t)1 << ((_store._length - 1) % bitsPerWord)); } else { data.back &= ~(cast(size_t)1 << ((_store._length - 1) % bitsPerWord)); } } unittest { Array!bool a; a.insertBack([true, false, true, true]); assert(a.back); a.back = false; assert(!a.back); } /** Indexing operators yield or modify the value at a specified index. */ bool opIndex(size_t i) { auto div = cast(size_t) (i / bitsPerWord); auto rem = i % bitsPerWord; enforce(div < data.length); return cast(bool)(data.ptr[div] & (cast(size_t)1 << rem)); } /// ditto void opIndexAssign(bool value, size_t i) { auto div = cast(size_t) (i / bitsPerWord); auto rem = i % bitsPerWord; enforce(div < data.length); if (value) data.ptr[div] |= (cast(size_t)1 << rem); else data.ptr[div] &= ~(cast(size_t)1 << rem); } /// ditto void opIndexOpAssign(string op)(bool value, size_t i) { auto div = cast(size_t) (i / bitsPerWord); auto rem = i % bitsPerWord; enforce(div < data.length); auto oldValue = cast(bool) (data.ptr[div] & (cast(size_t)1 << rem)); // Do the deed auto newValue = mixin("oldValue "~op~" value"); // Write back the value if (newValue != oldValue) { if (newValue) data.ptr[div] |= (cast(size_t)1 << rem); else data.ptr[div] &= ~(cast(size_t)1 << rem); } } /// Ditto T moveAt(size_t i) { return this[i]; } unittest { Array!bool a; a.insertBack([true, false, true, true]); assert(a[0] && !a[1]); a[0] &= a[1]; assert(!a[0]); } /** Returns a new container that's the concatenation of $(D this) and its argument. Complexity: $(BIGOH n + m), where m is the number of elements in $(D stuff) */ Array!bool opBinary(string op, Stuff)(Stuff rhs) if (op == "~") { auto result = this; return result ~= rhs; } unittest { import std.algorithm : equal; Array!bool a; a.insertBack([true, false, true, true]); Array!bool b; b.insertBack([true, true, false, true]); assert(equal((a ~ b)[], [true, false, true, true, true, true, false, true])); } // /// ditto // TotalContainer opBinaryRight(Stuff, string op)(Stuff lhs) if (op == "~") // { // assert(0); // } /** Forwards to $(D insertAfter(this[], stuff)). */ // @@@BUG@@@ //ref Array!bool opOpAssign(string op, Stuff)(Stuff stuff) if (op == "~") Array!bool opOpAssign(string op, Stuff)(Stuff stuff) if (op == "~") { static if (is(typeof(stuff[]))) insertBack(stuff[]); else insertBack(stuff); return this; } unittest { import std.algorithm : equal; Array!bool a; a.insertBack([true, false, true, true]); Array!bool b; a.insertBack([false, true, false, true, true]); a ~= b; assert(equal( a[], [true, false, true, true, false, true, false, true, true])); } /** Removes all contents from the container. The container decides how $(D capacity) is affected. Postcondition: $(D empty) Complexity: $(BIGOH n) */ void clear() { this = Array(); } unittest { Array!bool a; a.insertBack([true, false, true, true]); a.clear(); assert(a.capacity == 0); } /** Sets the number of elements in the container to $(D newSize). If $(D newSize) is greater than $(D length), the added elements are added to the container and initialized with $(D ElementType.init). Complexity: $(BIGOH abs(n - newLength)) Postcondition: $(D _length == newLength) */ @property void length(size_t newLength) { import std.conv : to; _store.refCountedStore.ensureInitialized(); auto newDataLength = to!size_t((newLength + bitsPerWord - 1) / bitsPerWord); _store._backend.length = newDataLength; _store._length = newLength; } unittest { Array!bool a; a.length = 1057; assert(a.length == 1057); foreach (e; a) { assert(!e); } } /** Inserts $(D stuff) in the container. $(D stuff) can be a value convertible to $(D ElementType) or a range of objects convertible to $(D ElementType). The $(D stable) version guarantees that ranges iterating over the container are never invalidated. Client code that counts on non-invalidating insertion should use $(D stableInsert). Returns: The number of elements added. Complexity: $(BIGOH m * log(n)), where $(D m) is the number of elements in $(D stuff) */ alias insert = insertBack; ///ditto alias stableInsert = insertBack; /** Same as $(D insert(stuff)) and $(D stableInsert(stuff)) respectively, but relax the complexity constraint to linear. */ alias linearInsert = insertBack; ///ditto alias stableLinearInsert = insertBack; /** Picks one value in the container, removes it from the container, and returns it. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Precondition: $(D !empty) Returns: The element removed. Complexity: $(BIGOH log(n)) */ T removeAny() { auto result = back; removeBack(); return result; } /// ditto alias stableRemoveAny = removeAny; unittest { Array!bool a; a.length = 1057; assert(!a.removeAny()); assert(a.length == 1056); foreach (e; a) { assert(!e); } } /** Inserts $(D value) to the back of the container. $(D stuff) can be a value convertible to $(D ElementType) or a range of objects convertible to $(D ElementType). The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements inserted Complexity: $(BIGOH log(n)) */ size_t insertBack(Stuff)(Stuff stuff) if (is(Stuff : bool)) { _store.refCountedStore.ensureInitialized(); auto rem = _store._length % bitsPerWord; if (rem) { // Fits within the current array if (stuff) { data[$ - 1] |= (cast(size_t)1 << rem); } else { data[$ - 1] &= ~(cast(size_t)1 << rem); } } else { // Need to add more data _store._backend.insertBack(stuff); } ++_store._length; return 1; } /// Ditto size_t insertBack(Stuff)(Stuff stuff) if (isInputRange!Stuff && is(ElementType!Stuff : bool)) { static if (!hasLength!Stuff) size_t result; for (; !stuff.empty; stuff.popFront()) { insertBack(stuff.front); static if (!hasLength!Stuff) ++result; } static if (!hasLength!Stuff) return result; else return stuff.length; } /// ditto alias stableInsertBack = insertBack; unittest { Array!bool a; for (int i = 0; i < 100; ++i) a.insertBack(true); foreach (e; a) assert(e); } /** Removes the value at the front or back of the container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. The optional parameter $(D howMany) instructs removal of that many elements. If $(D howMany > n), all elements are removed and no exception is thrown. Precondition: $(D !empty) Complexity: $(BIGOH log(n)). */ void removeBack() { enforce(_store._length); if (_store._length % bitsPerWord) { // Cool, just decrease the length --_store._length; } else { // Reduce the allocated space --_store._length; _store._backend.length = _store._backend.length - 1; } } /// ditto alias stableRemoveBack = removeBack; /** Removes $(D howMany) values at the front or back of the container. Unlike the unparameterized versions above, these functions do not throw if they could not remove $(D howMany) elements. Instead, if $(D howMany > n), all elements are removed. The returned value is the effective number of elements removed. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements removed Complexity: $(BIGOH howMany * log(n)). */ /// ditto size_t removeBack(size_t howMany) { if (howMany >= length) { howMany = length; clear(); } else { length = length - howMany; } return howMany; } unittest { Array!bool a; a.length = 1057; assert(a.removeBack(1000) == 1000); assert(a.length == 57); foreach (e; a) { assert(!e); } } /** Inserts $(D stuff) before, after, or instead range $(D r), which must be a valid range previously extracted from this container. $(D stuff) can be a value convertible to $(D ElementType) or a range of objects convertible to $(D ElementType). The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of values inserted. Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff) */ size_t insertBefore(Stuff)(Range r, Stuff stuff) { import std.algorithm : bringToFront; // TODO: make this faster, it moves one bit at a time immutable inserted = stableInsertBack(stuff); immutable tailLength = length - inserted; bringToFront( this[r._a .. tailLength], this[tailLength .. length]); return inserted; } /// ditto alias stableInsertBefore = insertBefore; unittest { import std.conv : to; Array!bool a; version (bugxxxx) { a._store.refCountedDebug = true; } a.insertBefore(a[], true); assert(a.length == 1, to!string(a.length)); a.insertBefore(a[], false); assert(a.length == 2, to!string(a.length)); } /// ditto size_t insertAfter(Stuff)(Range r, Stuff stuff) { import std.algorithm : bringToFront; // TODO: make this faster, it moves one bit at a time immutable inserted = stableInsertBack(stuff); immutable tailLength = length - inserted; bringToFront( this[r._b .. tailLength], this[tailLength .. length]); return inserted; } /// ditto alias stableInsertAfter = insertAfter; unittest { import std.conv : to; Array!bool a; a.length = 10; a.insertAfter(a[0 .. 5], true); assert(a.length == 11, to!string(a.length)); assert(a[5]); } /// ditto size_t replace(Stuff)(Range r, Stuff stuff) if (is(Stuff : bool)) { if (!r.empty) { // There is room r.front = stuff; r.popFront(); linearRemove(r); } else { // No room, must insert insertBefore(r, stuff); } return 1; } /// ditto alias stableReplace = replace; unittest { import std.conv : to; Array!bool a; a.length = 10; a.replace(a[3 .. 5], true); assert(a.length == 9, to!string(a.length)); assert(a[3]); } /** Removes all elements belonging to $(D r), which must be a range obtained originally from this container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: A range spanning the remaining elements in the container that initially were right after $(D r). Complexity: $(BIGOH n) */ Range linearRemove(Range r) { import std.algorithm : copy; copy(this[r._b .. length], this[r._a .. length]); length = length - r.length; return this[r._a .. length]; } } unittest { Array!bool a; assert(a.empty); } unittest { Array!bool arr; arr.insert([false, false, false, false]); assert(arr.front == false); assert(arr.back == false); assert(arr[1] == false); auto slice = arr[]; slice = arr[0 .. $]; slice = slice[1 .. $]; slice.front = true; slice.back = true; slice[1] = true; assert(slice.front == true); assert(slice.back == true); assert(slice[1] == true); assert(slice.moveFront == true); assert(slice.moveBack == true); assert(slice.moveAt(1) == true); } ldc-1.1.0-beta3-src/runtime/phobos/std/container/slist.d0000664000175000017500000004531612776215007021204 0ustar kaikai/** This module implements a singly-linked list container. It can be used as a stack. This module is a submodule of $(LINK2 std_container.html, std.container). Source: $(PHOBOSSRC std/container/_slist.d) Macros: WIKI = Phobos/StdContainer TEXTWITHCOMMAS = $0 Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. License: Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at $(WEB boost.org/LICENSE_1_0.txt)). Authors: Steven Schveighoffer, $(WEB erdani.com, Andrei Alexandrescu) */ module std.container.slist; /// unittest { import std.container: SList; import std.algorithm: equal; auto s = SList!int(1, 2, 3); assert(equal(s[], [1, 2, 3])); s.removeFront(); assert(equal(s[], [2, 3])); s.insertFront([5, 6]); assert(equal(s[], [5, 6, 2, 3])); // If you want to apply range operations, simply slice it. import std.algorithm: countUntil; import std.range: popFrontN, walkLength; auto sl = SList!int(1, 2, 3, 4, 5); assert(countUntil(sl[], 2) == 1); auto r = sl[]; popFrontN(r, 2); assert(walkLength(r) == 3); } public import std.container.util; /** Implements a simple and fast singly-linked list. It can be used as a stack. $(D SList) uses reference semantics. */ struct SList(T) { import std.exception : enforce; import std.range : Take; import std.range.primitives; import std.traits; private struct Node { Node * _next; T _payload; } private struct NodeWithoutPayload { Node* _next; } static assert(NodeWithoutPayload._next.offsetof == Node._next.offsetof); private Node * _root; private void initialize() @trusted nothrow pure { if (_root) return; _root = cast (Node*) new NodeWithoutPayload(); } private ref inout(Node*) _first() @property @safe nothrow pure inout { assert(_root); return _root._next; } private static Node * findLastNode(Node * n) { assert(n); auto ahead = n._next; while (ahead) { n = ahead; ahead = n._next; } return n; } private static Node * findLastNode(Node * n, size_t limit) { assert(n && limit); auto ahead = n._next; while (ahead) { if (!--limit) break; n = ahead; ahead = n._next; } return n; } private static Node * findNode(Node * n, Node * findMe) { assert(n); auto ahead = n._next; while (ahead != findMe) { n = ahead; enforce(n); ahead = n._next; } return n; } /** Constructor taking a number of nodes */ this(U)(U[] values...) if (isImplicitlyConvertible!(U, T)) { insertFront(values); } /** Constructor taking an input range */ this(Stuff)(Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T) && !is(Stuff == T[])) { insertFront(stuff); } /** Comparison for equality. Complexity: $(BIGOH min(n, n1)) where $(D n1) is the number of elements in $(D rhs). */ bool opEquals(const SList rhs) const { return opEquals(rhs); } /// ditto bool opEquals(ref const SList rhs) const { if (_root is rhs._root) return true; if (_root is null) return rhs._root is null || rhs._first is null; if (rhs._root is null) return _root is null || _first is null; const(Node) * n1 = _first, n2 = rhs._first; for (;; n1 = n1._next, n2 = n2._next) { if (!n1) return !n2; if (!n2 || n1._payload != n2._payload) return false; } } /** Defines the container's primary range, which embodies a forward range. */ struct Range { private Node * _head; private this(Node * p) { _head = p; } /// Input range primitives. @property bool empty() const { return !_head; } /// ditto @property ref T front() { assert(!empty, "SList.Range.front: Range is empty"); return _head._payload; } /// ditto void popFront() { assert(!empty, "SList.Range.popFront: Range is empty"); _head = _head._next; } /// Forward range primitive. @property Range save() { return this; } T moveFront() { import std.algorithm : move; assert(!empty, "SList.Range.moveFront: Range is empty"); return move(_head._payload); } bool sameHead(Range rhs) { return _head && _head == rhs._head; } } unittest { static assert(isForwardRange!Range); } /** Property returning $(D true) if and only if the container has no elements. Complexity: $(BIGOH 1) */ @property bool empty() const { return _root is null || _first is null; } /** Duplicates the container. The elements themselves are not transitively duplicated. Complexity: $(BIGOH n). */ @property SList dup() { return SList(this[]); } /** Returns a range that iterates over all elements of the container, in forward order. Complexity: $(BIGOH 1) */ Range opSlice() { if (empty) return Range(null); else return Range(_first); } /** Forward to $(D opSlice().front). Complexity: $(BIGOH 1) */ @property ref T front() { assert(!empty, "SList.front: List is empty"); return _first._payload; } unittest { auto s = SList!int(1, 2, 3); s.front = 42; assert(s == SList!int(42, 2, 3)); } /** Returns a new $(D SList) that's the concatenation of $(D this) and its argument. $(D opBinaryRight) is only defined if $(D Stuff) does not define $(D opBinary). */ SList opBinary(string op, Stuff)(Stuff rhs) if (op == "~" && is(typeof(SList(rhs)))) { auto toAdd = SList(rhs); if (empty) return toAdd; // TODO: optimize auto result = dup; auto n = findLastNode(result._first); n._next = toAdd._first; return result; } /// ditto SList opBinaryRight(string op, Stuff)(Stuff lhs) if (op == "~" && !is(typeof(lhs.opBinary!"~"(this))) && is(typeof(SList(lhs)))) { auto toAdd = SList(lhs); if (empty) return toAdd; auto result = dup; result.insertFront(toAdd[]); return result; } /** Removes all contents from the $(D SList). Postcondition: $(D empty) Complexity: $(BIGOH 1) */ void clear() { if (_root) _first = null; } /** Reverses SList in-place. Performs no memory allocation. Complexity: $(BIGOH n) */ void reverse() { if (!empty) { Node* prev; while (_first) { auto next = _first._next; _first._next = prev; prev = _first; _first = next; } _first = prev; } } /** Inserts $(D stuff) to the front of the container. $(D stuff) can be a value convertible to $(D T) or a range of objects convertible to $(D T). The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements inserted Complexity: $(BIGOH m), where $(D m) is the length of $(D stuff) */ size_t insertFront(Stuff)(Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) { initialize(); size_t result; Node * n, newRoot; foreach (item; stuff) { auto newNode = new Node(null, item); (newRoot ? n._next : newRoot) = newNode; n = newNode; ++result; } if (!n) return 0; // Last node points to the old root n._next = _first; _first = newRoot; return result; } /// ditto size_t insertFront(Stuff)(Stuff stuff) if (isImplicitlyConvertible!(Stuff, T)) { initialize(); auto newRoot = new Node(_first, stuff); _first = newRoot; return 1; } /// ditto alias insert = insertFront; /// ditto alias stableInsert = insert; /// ditto alias stableInsertFront = insertFront; /** Picks one value in an unspecified position in the container, removes it from the container, and returns it. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Precondition: $(D !empty) Returns: The element removed. Complexity: $(BIGOH 1). */ T removeAny() { import std.algorithm : move; assert(!empty, "SList.removeAny: List is empty"); auto result = move(_first._payload); _first = _first._next; return result; } /// ditto alias stableRemoveAny = removeAny; /** Removes the value at the front of the container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Precondition: $(D !empty) Complexity: $(BIGOH 1). */ void removeFront() { assert(!empty, "SList.removeFront: List is empty"); _first = _first._next; } /// ditto alias stableRemoveFront = removeFront; /** Removes $(D howMany) values at the front or back of the container. Unlike the unparameterized versions above, these functions do not throw if they could not remove $(D howMany) elements. Instead, if $(D howMany > n), all elements are removed. The returned value is the effective number of elements removed. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements removed Complexity: $(BIGOH howMany * log(n)). */ size_t removeFront(size_t howMany) { size_t result; while (_first && result < howMany) { _first = _first._next; ++result; } return result; } /// ditto alias stableRemoveFront = removeFront; /** Inserts $(D stuff) after range $(D r), which must be a range previously extracted from this container. Given that all ranges for a list end at the end of the list, this function essentially appends to the list and uses $(D r) as a potentially fast way to reach the last node in the list. Ideally $(D r) is positioned near or at the last element of the list. $(D stuff) can be a value convertible to $(D T) or a range of objects convertible to $(D T). The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of values inserted. Complexity: $(BIGOH k + m), where $(D k) is the number of elements in $(D r) and $(D m) is the length of $(D stuff). Example: -------------------- auto sl = SList!string(["a", "b", "d"]); sl.insertAfter(sl[], "e"); // insert at the end (slowest) assert(std.algorithm.equal(sl[], ["a", "b", "d", "e"])); sl.insertAfter(std.range.take(sl[], 2), "c"); // insert after "b" assert(std.algorithm.equal(sl[], ["a", "b", "c", "d", "e"])); -------------------- */ size_t insertAfter(Stuff)(Range r, Stuff stuff) { initialize(); if (!_first) { enforce(!r._head); return insertFront(stuff); } enforce(r._head); auto n = findLastNode(r._head); SList tmp; auto result = tmp.insertFront(stuff); n._next = tmp._first; return result; } /** Similar to $(D insertAfter) above, but accepts a range bounded in count. This is important for ensuring fast insertions in the middle of the list. For fast insertions after a specified position $(D r), use $(D insertAfter(take(r, 1), stuff)). The complexity of that operation only depends on the number of elements in $(D stuff). Precondition: $(D r.original.empty || r.maxLength > 0) Returns: The number of values inserted. Complexity: $(BIGOH k + m), where $(D k) is the number of elements in $(D r) and $(D m) is the length of $(D stuff). */ size_t insertAfter(Stuff)(Take!Range r, Stuff stuff) { auto orig = r.source; if (!orig._head) { // Inserting after a null range counts as insertion to the // front return insertFront(stuff); } enforce(!r.empty); // Find the last valid element in the range foreach (i; 1 .. r.maxLength) { if (!orig._head._next) break; orig.popFront(); } // insert here SList tmp; tmp.initialize(); tmp._first = orig._head._next; auto result = tmp.insertFront(stuff); orig._head._next = tmp._first; return result; } /// ditto alias stableInsertAfter = insertAfter; /** Removes a range from the list in linear time. Returns: An empty range. Complexity: $(BIGOH n) */ Range linearRemove(Range r) { if (!_first) { enforce(!r._head); return this[]; } auto n = findNode(_root, r._head); n._next = null; return Range(null); } /** Removes a $(D Take!Range) from the list in linear time. Returns: A range comprehending the elements after the removed range. Complexity: $(BIGOH n) */ Range linearRemove(Take!Range r) { auto orig = r.source; // We have something to remove here if (orig._head == _first) { // remove straight from the head of the list for (; !r.empty; r.popFront()) { removeFront(); } return this[]; } if (!r.maxLength) { // Nothing to remove, return the range itself return orig; } // Remove from somewhere in the middle of the list enforce(_first); auto n1 = findNode(_root, orig._head); auto n2 = findLastNode(orig._head, r.maxLength); n1._next = n2._next; return Range(n1._next); } /// ditto alias stableLinearRemove = linearRemove; } unittest { import std.algorithm : equal; auto a = SList!int(5); auto b = a; auto r = a[]; a.insertFront(1); b.insertFront(2); assert(equal(a[], [2, 1, 5])); assert(equal(b[], [2, 1, 5])); r.front = 9; assert(equal(a[], [2, 1, 9])); assert(equal(b[], [2, 1, 9])); } unittest { auto s = SList!int(1, 2, 3); auto n = s.findLastNode(s._root); assert(n && n._payload == 3); } unittest { import std.range.primitives; auto s = SList!int(1, 2, 5, 10); assert(walkLength(s[]) == 4); } unittest { import std.range : take; auto src = take([0, 1, 2, 3], 3); auto s = SList!int(src); assert(s == SList!int(0, 1, 2)); } unittest { auto a = SList!int(); auto b = SList!int(); auto c = a ~ b[]; assert(c.empty); } unittest { auto a = SList!int(1, 2, 3); auto b = SList!int(4, 5, 6); auto c = a ~ b[]; assert(c == SList!int(1, 2, 3, 4, 5, 6)); } unittest { auto a = SList!int(1, 2, 3); auto b = [4, 5, 6]; auto c = a ~ b; assert(c == SList!int(1, 2, 3, 4, 5, 6)); } unittest { auto a = SList!int(1, 2, 3); auto c = a ~ 4; assert(c == SList!int(1, 2, 3, 4)); } unittest { auto a = SList!int(2, 3, 4); auto b = 1 ~ a; assert(b == SList!int(1, 2, 3, 4)); } unittest { auto a = [1, 2, 3]; auto b = SList!int(4, 5, 6); auto c = a ~ b; assert(c == SList!int(1, 2, 3, 4, 5, 6)); } unittest { auto s = SList!int(1, 2, 3, 4); s.insertFront([ 42, 43 ]); assert(s == SList!int(42, 43, 1, 2, 3, 4)); } unittest { auto s = SList!int(1, 2, 3); assert(s.removeAny() == 1); assert(s == SList!int(2, 3)); assert(s.stableRemoveAny() == 2); assert(s == SList!int(3)); } unittest { import std.algorithm : equal; auto s = SList!int(1, 2, 3); s.removeFront(); assert(equal(s[], [2, 3])); s.stableRemoveFront(); assert(equal(s[], [3])); } unittest { auto s = SList!int(1, 2, 3, 4, 5, 6, 7); assert(s.removeFront(3) == 3); assert(s == SList!int(4, 5, 6, 7)); } unittest { auto a = SList!int(1, 2, 3); auto b = SList!int(1, 2, 3); assert(a.insertAfter(a[], b[]) == 3); } unittest { import std.range : take; auto s = SList!int(1, 2, 3, 4); auto r = take(s[], 2); assert(s.insertAfter(r, 5) == 1); assert(s == SList!int(1, 2, 5, 3, 4)); } unittest { static import std.algorithm; import std.range: take; // insertAfter documentation example auto sl = SList!string(["a", "b", "d"]); sl.insertAfter(sl[], "e"); // insert at the end (slowest) assert(std.algorithm.equal(sl[], ["a", "b", "d", "e"])); sl.insertAfter(take(sl[], 2), "c"); // insert after "b" assert(std.algorithm.equal(sl[], ["a", "b", "c", "d", "e"])); } unittest { import std.range.primitives; auto s = SList!int(1, 2, 3, 4, 5); auto r = s[]; popFrontN(r, 3); auto r1 = s.linearRemove(r); assert(s == SList!int(1, 2, 3)); assert(r1.empty); } unittest { auto s = SList!int(1, 2, 3, 4, 5); auto r = s[]; auto r1 = s.linearRemove(r); assert(s == SList!int()); assert(r1.empty); } unittest { import std.algorithm : equal; import std.range; auto s = SList!int(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); auto r = s[]; popFrontN(r, 3); auto r1 = take(r, 4); assert(equal(r1, [4, 5, 6, 7])); auto r2 = s.linearRemove(r1); assert(s == SList!int(1, 2, 3, 8, 9, 10)); assert(equal(r2, [8, 9, 10])); } unittest { import std.range.primitives; auto lst = SList!int(1, 5, 42, 9); assert(!lst.empty); assert(lst.front == 1); assert(walkLength(lst[]) == 4); auto lst2 = lst ~ [ 1, 2, 3 ]; assert(walkLength(lst2[]) == 7); auto lst3 = lst ~ [ 7 ]; assert(walkLength(lst3[]) == 5); } unittest { auto s = make!(SList!int)(1, 2, 3); } unittest { // 5193 static struct Data { const int val; } SList!Data list; } unittest { auto s = SList!int([1, 2, 3]); s.front = 5; //test frontAssign assert(s.front == 5); auto r = s[]; r.front = 1; //test frontAssign assert(r.front == 1); } unittest { // issue 14920 SList!int s; s.insertAfter(s[], 1); assert(s.front == 1); } unittest { // issue 15659 SList!int s; s.clear(); } unittest { SList!int s; s.reverse(); } unittest { import std.algorithm : equal; auto s = SList!int([1, 2, 3]); assert(s[].equal([1, 2, 3])); s.reverse(); assert(s[].equal([3, 2, 1])); } ldc-1.1.0-beta3-src/runtime/phobos/std/container/package.d0000664000175000017500000007361212776215007021441 0ustar kaikai// Written in the D programming language. /** This module defines generic containers. Construction: To implement the different containers both struct and class based approaches have been used. $(XREF_PACK _container,util,make) allows for uniform construction with either approach. --- import std.container; // Construct a red-black tree and an array both containing the values 1, 2, 3. // RedBlackTree should typically be allocated using `new` RedBlackTree!int rbTree = new RedBlackTree!int(1, 2, 3); // But `new` should not be used with Array Array!int array = Array!int(1, 2, 3); // `make` hides the differences RedBlackTree!int rbTree2 = make!(RedBlackTree!int)(1, 2, 3); Array!int array2 = make!(Array!int)(1, 2, 3); --- Note that $(D make) can infer the element type from the given arguments. --- import std.container; auto rbTree = make!RedBlackTree(1, 2, 3); // RedBlackTree!int auto array = make!Array("1", "2", "3"); // Array!string --- Reference_semantics: All containers have reference semantics, which means that after assignment both variables refer to the same underlying data. To make a copy of a _container, use the $(D c._dup) _container primitive. --- import std.container, std.range; Array!int originalArray = make!(Array!int)(1, 2, 3); Array!int secondArray = originalArray; assert(equal(originalArray[], secondArray[])); // changing one instance changes the other one as well! originalArray[0] = 12; assert(secondArray[0] == 12); // secondArray now refers to an independent copy of originalArray secondArray = originalArray.dup; secondArray[0] = 1; // assert that originalArray has not been affected assert(originalArray[0] == 12); --- $(B Attention:) If the _container is implemented as a class, using an uninitialized instance can cause a null pointer dereference. --- import std.container; RedBlackTree!int rbTree; rbTree.insert(5); // null pointer dereference --- Using an uninitialized struct-based _container will work, because the struct intializes itself upon use; however, up to this point the _container will not have an identity and assignment does not create two references to the same data. --- import std.container; // create an uninitialized array Array!int array1; // array2 does _not_ refer to array1 Array!int array2 = array1; array2.insertBack(42); // thus array1 will not be affected assert(array1.empty); // after initialization reference semantics work as expected array1 = array2; // now affects array2 as well array1.removeBack(); assert(array2.empty); --- It is therefore recommended to always construct containers using $(XREF_PACK _container,util,make). This is in fact necessary to put containers into another _container. For example, to construct an $(D Array) of ten empty $(D Array)s, use the following that calls $(D make) ten times. --- import std.container, std.range; auto arrOfArrs = make!Array(generate!(() => make!(Array!int)).take(10)); --- Submodules: This module consists of the following submodules: $(UL $(LI The $(LINK2 std_container_array.html, std._container.array) module provides an array type with deterministic control of memory, not reliant on the GC unlike built-in arrays. ) $(LI The $(LINK2 std_container_binaryheap.html, std._container.binaryheap) module provides a binary heap implementation that can be applied to any user-provided random-access range. ) $(LI The $(LINK2 std_container_dlist.html, std._container.dlist) module provides a doubly-linked list implementation. ) $(LI The $(LINK2 std_container_rbtree.html, std._container.rbtree) module implements red-black trees. ) $(LI The $(LINK2 std_container_slist.html, std._container.slist) module implements singly-linked lists. ) $(LI The $(LINK2 std_container_util.html, std._container.util) module contains some generic tools commonly used by _container implementations. ) ) The_primary_range_of_a_container: While some _containers offer direct access to their elements e.g. via $(D opIndex), $(D c.front) or $(D c.back), access and modification of a _container's contents is generally done through its primary $(LINK2 std_range.html, range) type, which is aliased as $(D C.Range). For example, the primary range type of $(D Array!int) is $(D Array!int.Range). If the documentation of a member function of a _container takes a parameter of type $(D Range), then it refers to the primary range type of this _container. Oftentimes $(D Take!Range) will be used, in which case the range refers to a span of the elements in the _container. Arguments to these parameters $(B must) be obtained from the same _container instance as the one being worked with. It is important to note that many generic range algorithms return the same range type as their input range. --- import std.algorithm : equal, find; import std.container; import std.range : take; auto array = make!Array(1, 2, 3); // `find` returns an Array!int.Range advanced to the element "2" array.linearRemove(array[].find(2)); assert(array[].equal([1])); array = make!Array(1, 2, 3); // the range given to `linearRemove` is a Take!(Array!int.Range) // spanning just the element "2" array.linearRemove(array[].find(2).take(1)); assert(array[].equal([1, 3])); --- When any $(LINK2 std_range.html, range) can be passed as an argument to a member function, the documention usually refers to the parameter's templated type as $(D Stuff). --- import std.algorithm : equal; import std.container; import std.range : iota; auto array = make!Array(1, 2); // the range type returned by `iota` is completely unrelated to Array, // which is fine for Array.insertBack: array.insertBack(iota(3, 10)); assert(array[].equal([1, 2, 3, 4, 5, 6, 7, 8, 9])); --- Container_primitives: Containers do not form a class hierarchy, instead they implement a common set of primitives (see table below). These primitives each guarantee a specific worst case complexity and thus allow generic code to be written independently of the _container implementation. For example the primitives $(D c.remove(r)) and $(D c.linearRemove(r)) both remove the sequence of elements in range $(D r) from the _container $(D c). The primitive $(D c.remove(r)) guarantees $(BIGOH n$(SUBSCRIPT r) log n$(SUBSCRIPT c)) complexity in the worst case and $(D c.linearRemove(r)) relaxes this guarantee to $(BIGOH n$(SUBSCRIPT c)). Since a sequence of elements can be removed from a $(LINK2 std_container_dlist.html, doubly linked list) in constant time, $(D DList) provides the primitive $(D c.remove(r)) as well as $(D c.linearRemove(r)). On the other hand $(LINK2 std_container_array.html, Array) only offers $(D c.linearRemove(r)). The following table describes the common set of primitives that containers implement. A _container need not implement all primitives, but if a primitive is implemented, it must support the syntax described in the $(B syntax) column with the semantics described in the $(B description) column, and it must not have a worst-case complexity worse than denoted in big-O notation in the $(BIGOH ·) column. Below, $(D C) means a _container type, $(D c) is a value of _container type, $(D n$(SUBSCRIPT x)) represents the effective length of value $(D x), which could be a single element (in which case $(D n$(SUBSCRIPT x)) is $(D 1)), a _container, or a range. $(BOOKTABLE Container primitives, $(TR $(TH Syntax) $(TH $(BIGOH ·)) $(TH Description)) $(TR $(TDNW $(D C(x))) $(TDNW $(D n$(SUBSCRIPT x))) $(TD Creates a _container of type $(D C) from either another _container or a range. The created _container must not be a null reference even if x is empty.)) $(TR $(TDNW $(D c.dup)) $(TDNW $(D n$(SUBSCRIPT c))) $(TD Returns a duplicate of the _container.)) $(TR $(TDNW $(D c ~ x)) $(TDNW $(D n$(SUBSCRIPT c) + n$(SUBSCRIPT x))) $(TD Returns the concatenation of $(D c) and $(D r). $(D x) may be a single element or an input range.)) $(TR $(TDNW $(D x ~ c)) $(TDNW $(D n$(SUBSCRIPT c) + n$(SUBSCRIPT x))) $(TD Returns the concatenation of $(D x) and $(D c). $(D x) may be a single element or an input range type.)) $(LEADINGROWN 3, Iteration) $(TR $(TD $(D c.Range)) $(TD) $(TD The primary range type associated with the _container.)) $(TR $(TD $(D c[])) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Returns a range iterating over the entire _container, in a _container-defined order.)) $(TR $(TDNW $(D c[a .. b])) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Fetches a portion of the _container from key $(D a) to key $(D b).)) $(LEADINGROWN 3, Capacity) $(TR $(TD $(D c.empty)) $(TD $(D 1)) $(TD Returns $(D true) if the _container has no elements, $(D false) otherwise.)) $(TR $(TD $(D c.length)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Returns the number of elements in the _container.)) $(TR $(TDNW $(D c.length = n)) $(TDNW $(D n$(SUBSCRIPT c) + n)) $(TD Forces the number of elements in the _container to $(D n). If the _container ends up growing, the added elements are initialized in a _container-dependent manner (usually with $(D T.init)).)) $(TR $(TD $(D c.capacity)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Returns the maximum number of elements that can be stored in the _container without triggering a reallocation.)) $(TR $(TD $(D c.reserve(x))) $(TD $(D n$(SUBSCRIPT c))) $(TD Forces $(D capacity) to at least $(D x) without reducing it.)) $(LEADINGROWN 3, Access) $(TR $(TDNW $(D c.front)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Returns the first element of the _container, in a _container-defined order.)) $(TR $(TDNW $(D c.moveFront)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Destructively reads and returns the first element of the _container. The slot is not removed from the _container; it is left initialized with $(D T.init). This routine need not be defined if $(D front) returns a $(D ref).)) $(TR $(TDNW $(D c.front = v)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Assigns $(D v) to the first element of the _container.)) $(TR $(TDNW $(D c.back)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Returns the last element of the _container, in a _container-defined order.)) $(TR $(TDNW $(D c.moveBack)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Destructively reads and returns the last element of the _container. The slot is not removed from the _container; it is left initialized with $(D T.init). This routine need not be defined if $(D front) returns a $(D ref).)) $(TR $(TDNW $(D c.back = v)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Assigns $(D v) to the last element of the _container.)) $(TR $(TDNW $(D c[x])) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Provides indexed access into the _container. The index type is _container-defined. A _container may define several index types (and consequently overloaded indexing).)) $(TR $(TDNW $(D c.moveAt(x))) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Destructively reads and returns the value at position $(D x). The slot is not removed from the _container; it is left initialized with $(D T.init).)) $(TR $(TDNW $(D c[x] = v)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Sets element at specified index into the _container.)) $(TR $(TDNW $(D c[x] $(I op)= v)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Performs read-modify-write operation at specified index into the _container.)) $(LEADINGROWN 3, Operations) $(TR $(TDNW $(D e in c)) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Returns nonzero if e is found in $(D c).)) $(TR $(TDNW $(D c.lowerBound(v))) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Returns a range of all elements strictly less than $(D v).)) $(TR $(TDNW $(D c.upperBound(v))) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Returns a range of all elements strictly greater than $(D v).)) $(TR $(TDNW $(D c.equalRange(v))) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Returns a range of all elements in $(D c) that are equal to $(D v).)) $(LEADINGROWN 3, Modifiers) $(TR $(TDNW $(D c ~= x)) $(TDNW $(D n$(SUBSCRIPT c) + n$(SUBSCRIPT x))) $(TD Appends $(D x) to $(D c). $(D x) may be a single element or an input range type.)) $(TR $(TDNW $(D c.clear())) $(TDNW $(D n$(SUBSCRIPT c))) $(TD Removes all elements in $(D c).)) $(TR $(TDNW $(D c.insert(x))) $(TDNW $(D n$(SUBSCRIPT x) * log n$(SUBSCRIPT c))) $(TD Inserts $(D x) in $(D c) at a position (or positions) chosen by $(D c).)) $(TR $(TDNW $(D c.stableInsert(x))) $(TDNW $(D n$(SUBSCRIPT x) * log n$(SUBSCRIPT c))) $(TD Same as $(D c.insert(x)), but is guaranteed to not invalidate any ranges.)) $(TR $(TDNW $(D c.linearInsert(v))) $(TDNW $(D n$(SUBSCRIPT c))) $(TD Same as $(D c.insert(v)) but relaxes complexity to linear.)) $(TR $(TDNW $(D c.stableLinearInsert(v))) $(TDNW $(D n$(SUBSCRIPT c))) $(TD Same as $(D c.stableInsert(v)) but relaxes complexity to linear.)) $(TR $(TDNW $(D c.removeAny())) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Removes some element from $(D c) and returns it.)) $(TR $(TDNW $(D c.stableRemoveAny())) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Same as $(D c.removeAny()), but is guaranteed to not invalidate any iterators.)) $(TR $(TDNW $(D c.insertFront(v))) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Inserts $(D v) at the front of $(D c).)) $(TR $(TDNW $(D c.stableInsertFront(v))) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Same as $(D c.insertFront(v)), but guarantees no ranges will be invalidated.)) $(TR $(TDNW $(D c.insertBack(v))) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Inserts $(D v) at the back of $(D c).)) $(TR $(TDNW $(D c.stableInsertBack(v))) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Same as $(D c.insertBack(v)), but guarantees no ranges will be invalidated.)) $(TR $(TDNW $(D c.removeFront())) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Removes the element at the front of $(D c).)) $(TR $(TDNW $(D c.stableRemoveFront())) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Same as $(D c.removeFront()), but guarantees no ranges will be invalidated.)) $(TR $(TDNW $(D c.removeBack())) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Removes the value at the back of $(D c).)) $(TR $(TDNW $(D c.stableRemoveBack())) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Same as $(D c.removeBack()), but guarantees no ranges will be invalidated.)) $(TR $(TDNW $(D c.remove(r))) $(TDNW $(D n$(SUBSCRIPT r) * log n$(SUBSCRIPT c))) $(TD Removes range $(D r) from $(D c).)) $(TR $(TDNW $(D c.stableRemove(r))) $(TDNW $(D n$(SUBSCRIPT r) * log n$(SUBSCRIPT c))) $(TD Same as $(D c.remove(r)), but guarantees iterators are not invalidated.)) $(TR $(TDNW $(D c.linearRemove(r))) $(TDNW $(D n$(SUBSCRIPT c))) $(TD Removes range $(D r) from $(D c).)) $(TR $(TDNW $(D c.stableLinearRemove(r))) $(TDNW $(D n$(SUBSCRIPT c))) $(TD Same as $(D c.linearRemove(r)), but guarantees iterators are not invalidated.)) $(TR $(TDNW $(D c.removeKey(k))) $(TDNW $(D log n$(SUBSCRIPT c))) $(TD Removes an element from $(D c) by using its key $(D k). The key's type is defined by the _container.)) $(TR $(TDNW $(D )) $(TDNW $(D )) $(TD )) ) Source: $(PHOBOSSRC std/_container/package.d) Macros: WIKI = Phobos/StdContainer TEXTWITHCOMMAS = $0 Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. License: Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at $(WEB boost.org/LICENSE_1_0.txt)). Authors: Steven Schveighoffer, $(WEB erdani.com, Andrei Alexandrescu) */ module std.container; public import std.container.array; public import std.container.binaryheap; public import std.container.dlist; public import std.container.rbtree; public import std.container.slist; import std.meta; /* The following documentation and type $(D TotalContainer) are intended for developers only. $(D TotalContainer) is an unimplemented container that illustrates a host of primitives that a container may define. It is to some extent the bottom of the conceptual container hierarchy. A given container most often will choose to only implement a subset of these primitives, and define its own additional ones. Adhering to the standard primitive names below allows generic code to work independently of containers. Things to remember: any container must be a reference type, whether implemented as a $(D class) or $(D struct). No primitive below requires the container to escape addresses of elements, which means that compliant containers can be defined to use reference counting or other deterministic memory management techniques. A container may choose to define additional specific operations. The only requirement is that those operations bear different names than the ones below, lest user code gets confused. Complexity of operations should be interpreted as "at least as good as". If an operation is required to have $(BIGOH n) complexity, it could have anything lower than that, e.g. $(BIGOH log(n)). Unless specified otherwise, $(D n) inside a $(BIGOH) expression stands for the number of elements in the container. */ struct TotalContainer(T) { /** If the container has a notion of key-value mapping, $(D KeyType) defines the type of the key of the container. */ alias KeyType = T; /** If the container has a notion of multikey-value mapping, $(D KeyTypes[k]), where $(D k) is a zero-based unsigned number, defines the type of the $(D k)th key of the container. A container may define both $(D KeyType) and $(D KeyTypes), e.g. in the case it has the notion of primary/preferred key. */ alias KeyTypes = AliasSeq!T; /** If the container has a notion of key-value mapping, $(D ValueType) defines the type of the value of the container. Typically, a map-style container mapping values of type $(D K) to values of type $(D V) defines $(D KeyType) to be $(D K) and $(D ValueType) to be $(D V). */ alias ValueType = T; /** Defines the container's primary range, which embodies one of the ranges defined in $(XREFMODULE range). Generally a container may define several types of ranges. */ struct Range { /++ Range primitives. +/ @property bool empty() { assert(0); } /// Ditto @property ref T front() //ref return optional { assert(0); } /// Ditto @property void front(T value) //Only when front does not return by ref { assert(0); } /// Ditto T moveFront() { assert(0); } /// Ditto void popFront() { assert(0); } /// Ditto @property ref T back() //ref return optional { assert(0); } /// Ditto @property void back(T value) //Only when front does not return by ref { assert(0); } /// Ditto T moveBack() { assert(0); } /// Ditto void popBack() { assert(0); } /// Ditto T opIndex(size_t i) //ref return optional { assert(0); } /// Ditto void opIndexAssign(size_t i, T value) //Only when front does not return by ref { assert(0); } /// Ditto T opIndexUnary(string op)(size_t i) //Only when front does not return by ref { assert(0); } /// Ditto void opIndexOpAssign(string op)(size_t i, T value) //Only when front does not return by ref { assert(0); } /// Ditto T moveAt(size_t i) { assert(0); } /// Ditto @property size_t length() { assert(0); } } /** Property returning $(D true) if and only if the container has no elements. Complexity: $(BIGOH 1) */ @property bool empty() { assert(0); } /** Returns a duplicate of the container. The elements themselves are not transitively duplicated. Complexity: $(BIGOH n). */ @property TotalContainer dup() { assert(0); } /** Returns the number of elements in the container. Complexity: $(BIGOH log(n)). */ @property size_t length() { assert(0); } /** Returns the maximum number of elements the container can store without (a) allocating memory, (b) invalidating iterators upon insertion. Complexity: $(BIGOH log(n)). */ @property size_t capacity() { assert(0); } /** Ensures sufficient capacity to accommodate $(D n) elements. Postcondition: $(D capacity >= n) Complexity: $(BIGOH log(e - capacity)) if $(D e > capacity), otherwise $(BIGOH 1). */ void reserve(size_t e) { assert(0); } /** Returns a range that iterates over all elements of the container, in a container-defined order. The container should choose the most convenient and fast method of iteration for $(D opSlice()). Complexity: $(BIGOH log(n)) */ Range opSlice() { assert(0); } /** Returns a range that iterates the container between two specified positions. Complexity: $(BIGOH log(n)) */ Range opSlice(size_t a, size_t b) { assert(0); } /** Forward to $(D opSlice().front) and $(D opSlice().back), respectively. Complexity: $(BIGOH log(n)) */ @property ref T front() //ref return optional { assert(0); } /// Ditto @property void front(T value) //Only when front does not return by ref { assert(0); } /// Ditto T moveFront() { assert(0); } /// Ditto @property ref T back() //ref return optional { assert(0); } /// Ditto @property void back(T value) //Only when front does not return by ref { assert(0); } /// Ditto T moveBack() { assert(0); } /** Indexing operators yield or modify the value at a specified index. */ ref T opIndex(KeyType) //ref return optional { assert(0); } /// ditto void opIndexAssign(KeyType i, T value) //Only when front does not return by ref { assert(0); } /// ditto T opIndexUnary(string op)(KeyType i) //Only when front does not return by ref { assert(0); } /// ditto void opIndexOpAssign(string op)(KeyType i, T value) //Only when front does not return by ref { assert(0); } /// ditto T moveAt(KeyType i) { assert(0); } /** $(D k in container) returns true if the given key is in the container. */ bool opBinaryRight(string op)(KeyType k) if (op == "in") { assert(0); } /** Returns a range of all elements containing $(D k) (could be empty or a singleton range). */ Range equalRange(KeyType k) { assert(0); } /** Returns a range of all elements with keys less than $(D k) (could be empty or a singleton range). Only defined by containers that store data sorted at all times. */ Range lowerBound(KeyType k) { assert(0); } /** Returns a range of all elements with keys larger than $(D k) (could be empty or a singleton range). Only defined by containers that store data sorted at all times. */ Range upperBound(KeyType k) { assert(0); } /** Returns a new container that's the concatenation of $(D this) and its argument. $(D opBinaryRight) is only defined if $(D Stuff) does not define $(D opBinary). Complexity: $(BIGOH n + m), where m is the number of elements in $(D stuff) */ TotalContainer opBinary(string op)(Stuff rhs) if (op == "~") { assert(0); } /// ditto TotalContainer opBinaryRight(string op)(Stuff lhs) if (op == "~") { assert(0); } /** Forwards to $(D insertAfter(this[], stuff)). */ void opOpAssign(string op)(Stuff stuff) if (op == "~") { assert(0); } /** Removes all contents from the container. The container decides how $(D capacity) is affected. Postcondition: $(D empty) Complexity: $(BIGOH n) */ void clear() { assert(0); } /** Sets the number of elements in the container to $(D newSize). If $(D newSize) is greater than $(D length), the added elements are added to unspecified positions in the container and initialized with $(D .init). Complexity: $(BIGOH abs(n - newLength)) Postcondition: $(D _length == newLength) */ @property void length(size_t newLength) { assert(0); } /** Inserts $(D stuff) in an unspecified position in the container. Implementations should choose whichever insertion means is the most advantageous for the container, but document the exact behavior. $(D stuff) can be a value convertible to the element type of the container, or a range of values convertible to it. The $(D stable) version guarantees that ranges iterating over the container are never invalidated. Client code that counts on non-invalidating insertion should use $(D stableInsert). Such code would not compile against containers that don't support it. Returns: The number of elements added. Complexity: $(BIGOH m * log(n)), where $(D m) is the number of elements in $(D stuff) */ size_t insert(Stuff)(Stuff stuff) { assert(0); } ///ditto size_t stableInsert(Stuff)(Stuff stuff) { assert(0); } /** Same as $(D insert(stuff)) and $(D stableInsert(stuff)) respectively, but relax the complexity constraint to linear. */ size_t linearInsert(Stuff)(Stuff stuff) { assert(0); } ///ditto size_t stableLinearInsert(Stuff)(Stuff stuff) { assert(0); } /** Picks one value in an unspecified position in the container, removes it from the container, and returns it. Implementations should pick the value that's the most advantageous for the container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Precondition: $(D !empty) Returns: The element removed. Complexity: $(BIGOH log(n)). */ T removeAny() { assert(0); } /// ditto T stableRemoveAny() { assert(0); } /** Inserts $(D value) to the front or back of the container. $(D stuff) can be a value convertible to the container's element type or a range of values convertible to it. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements inserted Complexity: $(BIGOH log(n)). */ size_t insertFront(Stuff)(Stuff stuff) { assert(0); } /// ditto size_t stableInsertFront(Stuff)(Stuff stuff) { assert(0); } /// ditto size_t insertBack(Stuff)(Stuff stuff) { assert(0); } /// ditto size_t stableInsertBack(T value) { assert(0); } /** Removes the value at the front or back of the container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. The optional parameter $(D howMany) instructs removal of that many elements. If $(D howMany > n), all elements are removed and no exception is thrown. Precondition: $(D !empty) Complexity: $(BIGOH log(n)). */ void removeFront() { assert(0); } /// ditto void stableRemoveFront() { assert(0); } /// ditto void removeBack() { assert(0); } /// ditto void stableRemoveBack() { assert(0); } /** Removes $(D howMany) values at the front or back of the container. Unlike the unparameterized versions above, these functions do not throw if they could not remove $(D howMany) elements. Instead, if $(D howMany > n), all elements are removed. The returned value is the effective number of elements removed. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements removed Complexity: $(BIGOH howMany * log(n)). */ size_t removeFront(size_t howMany) { assert(0); } /// ditto size_t stableRemoveFront(size_t howMany) { assert(0); } /// ditto size_t removeBack(size_t howMany) { assert(0); } /// ditto size_t stableRemoveBack(size_t howMany) { assert(0); } /** Removes all values corresponding to key $(D k). Complexity: $(BIGOH m * log(n)), where $(D m) is the number of elements with the same key. Returns: The number of elements removed. */ size_t removeKey(KeyType k) { assert(0); } /** Inserts $(D stuff) before, after, or instead range $(D r), which must be a valid range previously extracted from this container. $(D stuff) can be a value convertible to the container's element type or a range of objects convertible to it. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of values inserted. Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff) */ size_t insertBefore(Stuff)(Range r, Stuff stuff) { assert(0); } /// ditto size_t stableInsertBefore(Stuff)(Range r, Stuff stuff) { assert(0); } /// ditto size_t insertAfter(Stuff)(Range r, Stuff stuff) { assert(0); } /// ditto size_t stableInsertAfter(Stuff)(Range r, Stuff stuff) { assert(0); } /// ditto size_t replace(Stuff)(Range r, Stuff stuff) { assert(0); } /// ditto size_t stableReplace(Stuff)(Range r, Stuff stuff) { assert(0); } /** Removes all elements belonging to $(D r), which must be a range obtained originally from this container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: A range spanning the remaining elements in the container that initially were right after $(D r). Complexity: $(BIGOH m * log(n)), where $(D m) is the number of elements in $(D r) */ Range remove(Range r) { assert(0); } /// ditto Range stableRemove(Range r) { assert(0); } /** Same as $(D remove) above, but has complexity relaxed to linear. Returns: A range spanning the remaining elements in the container that initially were right after $(D r). Complexity: $(BIGOH n) */ Range linearRemove(Range r) { assert(0); } /// ditto Range stableLinearRemove(Range r) { assert(0); } } unittest { TotalContainer!int test; } ldc-1.1.0-beta3-src/runtime/phobos/std/container/util.d0000664000175000017500000001106212776215007021012 0ustar kaikai/** This module contains some common utilities used by containers. This module is a submodule of $(LINK2 std_container.html, std.container). Source: $(PHOBOSSRC std/container/_util.d) Macros: WIKI = Phobos/StdContainer TEXTWITHCOMMAS = $0 Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. License: Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at $(WEB boost.org/LICENSE_1_0.txt)). Authors: Steven Schveighoffer, $(WEB erdani.com, Andrei Alexandrescu) */ module std.container.util; /** Returns an initialized object. This function is mainly for eliminating construction differences between structs and classes. It allows code to not worry about whether the type it's constructing is a struct or a class. */ template make(T) if (is(T == struct) || is(T == class)) { T make(Args...)(Args arguments) if (is(T == struct) && __traits(compiles, T(arguments))) { // constructing an std.container.Array without arguments, // does not initialize its payload and is equivalent // to a null reference. We therefore construct an empty container // by passing an empty array to its constructor. // Issue #13872. static if(arguments.length == 0) { import std.range; alias ET = ElementType!(T.Range); return T(ET[].init); } else return T(arguments); } T make(Args...)(Args arguments) if (is(T == class) && __traits(compiles, new T(arguments))) { return new T(arguments); } } /// unittest { import std.container; import std.algorithm : equal; import std.algorithm : equal; auto arr = make!(Array!int)([4, 2, 3, 1]); assert(equal(arr[], [4, 2, 3, 1])); auto rbt = make!(RedBlackTree!(int, "a > b"))([4, 2, 3, 1]); assert(equal(rbt[], [4, 3, 2, 1])); alias makeList = make!(SList!int); auto slist = makeList(1, 2, 3); assert(equal(slist[], [1, 2, 3])); } unittest { import std.container; import std.algorithm : equal; auto arr1 = make!(Array!dchar)(); assert(arr1.empty); auto arr2 = make!(Array!dchar)("hello"d); assert(equal(arr2[], "hello"d)); auto rtb1 = make!(RedBlackTree!dchar)(); assert(rtb1.empty); auto rtb2 = make!(RedBlackTree!dchar)('h', 'e', 'l', 'l', 'o'); assert(equal(rtb2[], "ehlo"d)); } // Issue 8895 unittest { import std.container; import std.algorithm : equal; auto a = make!(DList!int)(1,2,3,4); auto b = make!(DList!int)(1,2,3,4); auto c = make!(DList!int)(1,2,3,5); auto d = make!(DList!int)(1,2,3,4,5); assert(a == b); // this better terminate! assert(a != c); assert(a != d); } /** * Convenience function for constructing a generic container. */ template make(alias Container, Args...) if(!is(Container)) { import std.range : isInputRange; import std.traits : isDynamicArray; auto make(Range)(Range range) if(!isDynamicArray!Range && isInputRange!Range) { import std.range : ElementType; return .make!(Container!(ElementType!Range, Args))(range); } auto make(T)(T[] items...) { return .make!(Container!(T, Args))(items); } } /// unittest { import std.container.array, std.container.rbtree, std.container.slist; import std.range : iota; import std.algorithm : equal; auto arr = make!Array(iota(5)); assert(equal(arr[], [0, 1, 2, 3, 4])); auto rbtmax = make!(RedBlackTree, "a > b")(iota(5)); assert(equal(rbtmax[], [4, 3, 2, 1, 0])); auto rbtmin = make!RedBlackTree(4, 1, 3, 2); assert(equal(rbtmin[], [1, 2, 3, 4])); alias makeList = make!SList; auto list = makeList(1, 7, 42); assert(equal(list[], [1, 7, 42])); } unittest { import std.container.rbtree; import std.algorithm : equal; auto rbtmin = make!(RedBlackTree, "a < b", false)(3, 2, 2, 1); assert(equal(rbtmin[], [1, 2, 3])); } // Issue 13872 unittest { import std.container; auto tree1 = make!(RedBlackTree!int)(); auto refToTree1 = tree1; refToTree1.insert(1); assert(1 in tree1); auto array1 = make!(Array!int)(); auto refToArray1 = array1; refToArray1.insertBack(1); assert(!array1.empty); auto slist = make!(SList!int)(); auto refToSlist = slist; refToSlist.insert(1); assert(!slist.empty); auto dlist = make!(DList!int)(); auto refToDList = dlist; refToDList.insert(1); assert(!dlist.empty); } ldc-1.1.0-beta3-src/runtime/phobos/std/container/dlist.d0000664000175000017500000005646712776215007021176 0ustar kaikai/** This module implements a generic doubly-linked list container. It can be used as a queue, dequeue or stack. This module is a submodule of $(LINK2 std_container.html, std.container). Source: $(PHOBOSSRC std/container/_dlist.d) Macros: WIKI = Phobos/StdContainer TEXTWITHCOMMAS = $0 Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. License: Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at $(WEB boost.org/LICENSE_1_0.txt)). Authors: Steven Schveighoffer, $(WEB erdani.com, Andrei Alexandrescu) */ module std.container.dlist; /// unittest { import std.container: DList; import std.algorithm: equal; auto s = DList!int(1, 2, 3); assert(equal(s[], [1, 2, 3])); s.removeFront(); assert(equal(s[], [2, 3])); s.removeBack(); assert(equal(s[], [2])); s.insertFront([4, 5]); assert(equal(s[], [4, 5, 2])); s.insertBack([6, 7]); assert(equal(s[], [4, 5, 2, 6, 7])); // If you want to apply range operations, simply slice it. import std.algorithm: countUntil; import std.range: popFrontN, popBackN, walkLength; auto sl = DList!int([1, 2, 3, 4, 5]); assert(countUntil(sl[], 2) == 1); auto r = sl[]; popFrontN(r, 2); popBackN(r, 2); assert(r.equal([3])); assert(walkLength(r) == 1); } import std.range.primitives; import std.traits; public import std.container.util; /+ A DList Node without payload. Used to handle the sentinel node (henceforth "sentinode"). Also used for parts of the code that don't depend on the payload type. +/ private struct BaseNode { private BaseNode* _prev = null; private BaseNode* _next = null; /+ Gets the payload associated with this node. This is trusted because all nodes are associated with a payload, even the sentinel node. It is also not possible to mix Nodes in DLists of different types. This function is implemented as a member function here, as UFCS does not work with pointers. +/ ref inout(T) getPayload(T)() inout @trusted { return (cast(inout(DList!T.PayNode)*)&this)._payload; } // Helper: Given nodes p and n, connects them. static void connect(BaseNode* p, BaseNode* n) @safe nothrow pure { p._next = n; n._prev = p; } } /+ The base DList Range. Contains Range primitives that don't depend on payload type. +/ private struct DRange { unittest { static assert(isBidirectionalRange!DRange); static assert(is(ElementType!DRange == BaseNode*)); } nothrow @safe pure: private BaseNode* _first; private BaseNode* _last; private this(BaseNode* first, BaseNode* last) { assert((first is null) == (last is null), "Dlist.Range.this: Invalid arguments"); _first = first; _last = last; } private this(BaseNode* n) { this(n, n); } @property bool empty() const { assert((_first is null) == (_last is null), "DList.Range: Invalidated state"); return !_first; } @property BaseNode* front() { assert(!empty, "DList.Range.front: Range is empty"); return _first; } void popFront() { assert(!empty, "DList.Range.popFront: Range is empty"); if (_first is _last) { _first = _last = null; } else { assert(_first._next && _first is _first._next._prev, "DList.Range: Invalidated state"); _first = _first._next; } } @property BaseNode* back() { assert(!empty, "DList.Range.front: Range is empty"); return _last; } void popBack() { assert(!empty, "DList.Range.popBack: Range is empty"); if (_first is _last) { _first = _last = null; } else { assert(_last._prev && _last is _last._prev._next, "DList.Range: Invalidated state"); _last = _last._prev; } } /// Forward range primitive. @property DRange save() { return this; } } /** Implements a doubly-linked list. $(D DList) uses reference semantics. */ struct DList(T) { import std.range : Take; /* A Node with a Payload. A PayNode. */ struct PayNode { BaseNode _base; alias _base this; T _payload = T.init; inout(BaseNode)* asBaseNode() inout @trusted { return &_base; } } //The sentinel node private BaseNode* _root; private { //Construct as new PayNode, and returns it as a BaseNode. static BaseNode* createNode(Stuff)(auto ref Stuff arg, BaseNode* prev = null, BaseNode* next = null) { return (new PayNode(BaseNode(prev, next), arg)).asBaseNode(); } void initialize() nothrow @safe pure { if (_root) return; //Note: We allocate a PayNode for safety reasons. _root = (new PayNode()).asBaseNode(); _root._next = _root._prev = _root; } ref inout(BaseNode*) _first() @property @safe nothrow pure inout { assert(_root); return _root._next; } ref inout(BaseNode*) _last() @property @safe nothrow pure inout { assert(_root); return _root._prev; } } //end private /** Constructor taking a number of nodes */ this(U)(U[] values...) if (isImplicitlyConvertible!(U, T)) { insertBack(values); } /** Constructor taking an input range */ this(Stuff)(Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) { insertBack(stuff); } /** Comparison for equality. Complexity: $(BIGOH min(n, n1)) where $(D n1) is the number of elements in $(D rhs). */ bool opEquals()(ref const DList rhs) const if (is(typeof(front == front))) { const lhs = this; const lroot = lhs._root; const rroot = rhs._root; if (lroot is rroot) return true; if (lroot is null) return rroot is rroot._next; if (rroot is null) return lroot is lroot._next; const(BaseNode)* pl = lhs._first; const(BaseNode)* pr = rhs._first; while (true) { if (pl is lroot) return pr is rroot; if (pr is rroot) return false; // !== because of NaN if (!(pl.getPayload!T() == pr.getPayload!T())) return false; pl = pl._next; pr = pr._next; } } /** Defines the container's primary range, which embodies a bidirectional range. */ struct Range { static assert(isBidirectionalRange!Range); DRange _base; alias _base this; private this(BaseNode* first, BaseNode* last) { _base = DRange(first, last); } private this(BaseNode* n) { this(n, n); } @property ref T front() { return _base.front.getPayload!T(); } @property ref T back() { return _base.back.getPayload!T(); } //Note: shadows base DRange.save. //Necessary for static covariance. @property Range save() { return this; } } /** Property returning $(D true) if and only if the container has no elements. Complexity: $(BIGOH 1) */ bool empty() @property const nothrow { return _root is null || _root is _first; } /** Removes all contents from the $(D DList). Postcondition: $(D empty) Complexity: $(BIGOH 1) */ void clear() { //remove actual elements. remove(this[]); } /** Duplicates the container. The elements themselves are not transitively duplicated. Complexity: $(BIGOH n). */ @property DList dup() { return DList(this[]); } /** Returns a range that iterates over all elements of the container, in forward order. Complexity: $(BIGOH 1) */ Range opSlice() { if (empty) return Range(null, null); else return Range(_first, _last); } /** Forward to $(D opSlice().front). Complexity: $(BIGOH 1) */ @property ref inout(T) front() inout { assert(!empty, "DList.front: List is empty"); return _first.getPayload!T(); } /** Forward to $(D opSlice().back). Complexity: $(BIGOH 1) */ @property ref inout(T) back() inout { assert(!empty, "DList.back: List is empty"); return _last.getPayload!T(); } /+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/ /+ BEGIN CONCAT FUNCTIONS HERE +/ /+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/ /** Returns a new $(D DList) that's the concatenation of $(D this) and its argument $(D rhs). */ DList opBinary(string op, Stuff)(Stuff rhs) if (op == "~" && is(typeof(insertBack(rhs)))) { auto ret = this.dup; ret.insertBack(rhs); return ret; } /** Returns a new $(D DList) that's the concatenation of the argument $(D lhs) and $(D this). */ DList opBinaryRight(string op, Stuff)(Stuff lhs) if (op == "~" && is(typeof(insertFront(lhs)))) { auto ret = this.dup; ret.insertFront(lhs); return ret; } /** Appends the contents of the argument $(D rhs) into $(D this). */ DList opOpAssign(string op, Stuff)(Stuff rhs) if (op == "~" && is(typeof(insertBack(rhs)))) { insertBack(rhs); return this; } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Please, use `dlist ~= dlist[];` instead.") DList opOpAssign(string op)(DList rhs) if (op == "~") { return this ~= rhs[]; } /+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/ /+ BEGIN INSERT FUNCTIONS HERE +/ /+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/ /** Inserts $(D stuff) to the front/back of the container. $(D stuff) can be a value convertible to $(D T) or a range of objects convertible to $(D T). The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements inserted Complexity: $(BIGOH log(n)) */ size_t insertFront(Stuff)(Stuff stuff) { initialize(); return insertAfterNode(_root, stuff); } /// ditto size_t insertBack(Stuff)(Stuff stuff) { initialize(); return insertBeforeNode(_root, stuff); } /// ditto alias insert = insertBack; /// ditto alias stableInsert = insert; /// ditto alias stableInsertFront = insertFront; /// ditto alias stableInsertBack = insertBack; /** Inserts $(D stuff) after range $(D r), which must be a non-empty range previously extracted from this container. $(D stuff) can be a value convertible to $(D T) or a range of objects convertible to $(D T). The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of values inserted. Complexity: $(BIGOH k + m), where $(D k) is the number of elements in $(D r) and $(D m) is the length of $(D stuff). */ size_t insertBefore(Stuff)(Range r, Stuff stuff) { if (r._first) return insertBeforeNode(r._first, stuff); else { initialize(); return insertAfterNode(_root, stuff); } } /// ditto alias stableInsertBefore = insertBefore; /// ditto size_t insertAfter(Stuff)(Range r, Stuff stuff) { if (r._last) return insertAfterNode(r._last, stuff); else { initialize(); return insertBeforeNode(_root, stuff); } } /// ditto alias stableInsertAfter = insertAfter; /+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/ /+ BEGIN REMOVE FUNCTIONS HERE +/ /+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/ /** Picks one value in an unspecified position in the container, removes it from the container, and returns it. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Precondition: $(D !empty) Returns: The element removed. Complexity: $(BIGOH 1). */ T removeAny() { import std.algorithm : move; assert(!empty, "DList.removeAny: List is empty"); auto result = move(back); removeBack(); return result; } /// ditto alias stableRemoveAny = removeAny; /** Removes the value at the front/back of the container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Precondition: $(D !empty) Complexity: $(BIGOH 1). */ void removeFront() { assert(!empty, "DList.removeFront: List is empty"); assert(_root is _first._prev, "DList: Inconsistent state"); BaseNode.connect(_root, _first._next); } /// ditto alias stableRemoveFront = removeFront; /// ditto void removeBack() { assert(!empty, "DList.removeBack: List is empty"); assert(_last._next is _root, "DList: Inconsistent state"); BaseNode.connect(_last._prev, _root); } /// ditto alias stableRemoveBack = removeBack; /** Removes $(D howMany) values at the front or back of the container. Unlike the unparameterized versions above, these functions do not throw if they could not remove $(D howMany) elements. Instead, if $(D howMany > n), all elements are removed. The returned value is the effective number of elements removed. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. Returns: The number of elements removed Complexity: $(BIGOH howMany). */ size_t removeFront(size_t howMany) { if (!_root) return 0; size_t result; auto p = _first; while (p !is _root && result < howMany) { p = p._next; ++result; } BaseNode.connect(_root, p); return result; } /// ditto alias stableRemoveFront = removeFront; /// ditto size_t removeBack(size_t howMany) { if (!_root) return 0; size_t result; auto p = _last; while (p !is _root && result < howMany) { p = p._prev; ++result; } BaseNode.connect(p, _root); return result; } /// ditto alias stableRemoveBack = removeBack; /** Removes all elements belonging to $(D r), which must be a range obtained originally from this container. Returns: A range spanning the remaining elements in the container that initially were right after $(D r). Complexity: $(BIGOH 1) */ Range remove(Range r) { if (r.empty) return r; assert(_root !is null, "Cannot remove from an un-initialized List"); assert(r._first, "Remove: Range is empty"); BaseNode.connect(r._first._prev, r._last._next); auto after = r._last._next; if (after is _root) return Range(null, null); else return Range(after, _last); } /// ditto Range linearRemove(Range r) { return remove(r); } /** $(D linearRemove) functions as $(D remove), but also accepts ranges that are result the of a $(D take) operation. This is a convenient way to remove a fixed amount of elements from the range. Complexity: $(BIGOH r.walkLength) */ Range linearRemove(Take!Range r) { assert(_root !is null, "Cannot remove from an un-initialized List"); assert(r.source._first, "Remove: Range is empty"); BaseNode* first = r.source._first; BaseNode* last = null; do { last = r.source._first; r.popFront(); } while ( !r.empty ); return remove(Range(first, last)); } /// ditto alias stableRemove = remove; /// ditto alias stableLinearRemove = linearRemove; private: // Helper: Inserts stuff before the node n. size_t insertBeforeNode(Stuff)(BaseNode* n, ref Stuff stuff) if (isImplicitlyConvertible!(Stuff, T)) { auto p = createNode(stuff, n._prev, n); n._prev._next = p; n._prev = p; return 1; } // ditto size_t insertBeforeNode(Stuff)(BaseNode* n, ref Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) { if (stuff.empty) return 0; size_t result; Range r = createRange(stuff, result); BaseNode.connect(n._prev, r._first); BaseNode.connect(r._last, n); return result; } // Helper: Inserts stuff after the node n. size_t insertAfterNode(Stuff)(BaseNode* n, ref Stuff stuff) if (isImplicitlyConvertible!(Stuff, T)) { auto p = createNode(stuff, n, n._next); n._next._prev = p; n._next = p; return 1; } // ditto size_t insertAfterNode(Stuff)(BaseNode* n, ref Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) { if (stuff.empty) return 0; size_t result; Range r = createRange(stuff, result); BaseNode.connect(r._last, n._next); BaseNode.connect(n, r._first); return result; } // Helper: Creates a chain of nodes from the range stuff. Range createRange(Stuff)(ref Stuff stuff, ref size_t result) { BaseNode* first = createNode(stuff.front); BaseNode* last = first; ++result; for ( stuff.popFront() ; !stuff.empty ; stuff.popFront() ) { auto p = createNode(stuff.front, last); last = last._next = p; ++result; } return Range(first, last); } } @safe unittest { import std.algorithm : equal; //Tests construction signatures alias IntList = DList!int; auto a0 = IntList(); auto a1 = IntList(0); auto a2 = IntList(0, 1); auto a3 = IntList([0]); auto a4 = IntList([0, 1]); assert(a0[].empty); assert(equal(a1[], [0])); assert(equal(a2[], [0, 1])); assert(equal(a3[], [0])); assert(equal(a4[], [0, 1])); } @safe unittest { import std.algorithm : equal; alias IntList = DList!int; IntList list = IntList([0,1,2,3]); assert(equal(list[],[0,1,2,3])); list.insertBack([4,5,6,7]); assert(equal(list[],[0,1,2,3,4,5,6,7])); list = IntList(); list.insertFront([0,1,2,3]); assert(equal(list[],[0,1,2,3])); list.insertFront([4,5,6,7]); assert(equal(list[],[4,5,6,7,0,1,2,3])); } @safe unittest { import std.algorithm : equal; import std.range : take; alias IntList = DList!int; IntList list = IntList([0,1,2,3]); auto range = list[]; for( ; !range.empty; range.popFront()) { int item = range.front; if (item == 2) { list.stableLinearRemove(take(range, 1)); break; } } assert(equal(list[],[0,1,3])); list = IntList([0,1,2,3]); range = list[]; for( ; !range.empty; range.popFront()) { int item = range.front; if (item == 2) { list.stableLinearRemove(take(range,2)); break; } } assert(equal(list[],[0,1])); list = IntList([0,1,2,3]); range = list[]; for( ; !range.empty; range.popFront()) { int item = range.front; if (item == 0) { list.stableLinearRemove(take(range,2)); break; } } assert(equal(list[],[2,3])); list = IntList([0,1,2,3]); range = list[]; for( ; !range.empty; range.popFront()) { int item = range.front; if (item == 1) { list.stableLinearRemove(take(range,2)); break; } } assert(equal(list[],[0,3])); } @safe unittest { import std.algorithm : equal; auto dl = DList!string(["a", "b", "d"]); dl.insertAfter(dl[], "e"); // insert at the end assert(equal(dl[], ["a", "b", "d", "e"])); auto dlr = dl[]; dlr.popBack(); dlr.popBack(); dl.insertAfter(dlr, "c"); // insert after "b" assert(equal(dl[], ["a", "b", "c", "d", "e"])); } @safe unittest { import std.algorithm : equal; auto dl = DList!string(["a", "b", "d"]); dl.insertBefore(dl[], "e"); // insert at the front assert(equal(dl[], ["e", "a", "b", "d"])); auto dlr = dl[]; dlr.popFront(); dlr.popFront(); dl.insertBefore(dlr, "c"); // insert before "b" assert(equal(dl[], ["e", "a", "c", "b", "d"])); } @safe unittest { auto d = DList!int([1, 2, 3]); d.front = 5; //test frontAssign assert(d.front == 5); auto r = d[]; r.back = 1; assert(r.back == 1); } // Issue 8895 @safe unittest { auto a = make!(DList!int)(1,2,3,4); auto b = make!(DList!int)(1,2,3,4); auto c = make!(DList!int)(1,2,3,5); auto d = make!(DList!int)(1,2,3,4,5); assert(a == b); // this better terminate! assert(!(a == c)); assert(!(a == d)); } @safe unittest { auto d = DList!int([1, 2, 3]); d.front = 5; //test frontAssign assert(d.front == 5); auto r = d[]; r.back = 1; assert(r.back == 1); } @safe unittest { auto a = DList!int(); assert(a.removeFront(10) == 0); a.insert([1, 2, 3]); assert(a.removeFront(10) == 3); assert(a[].empty); } @safe unittest { import std.algorithm : equal; //Verify all flavors of ~ auto a = DList!int(); auto b = DList!int(); auto c = DList!int([1, 2, 3]); auto d = DList!int([4, 5, 6]); assert((a ~ b[])[].empty); assert((c ~ d[])[].equal([1, 2, 3, 4, 5, 6])); assert(c[].equal([1, 2, 3])); assert(d[].equal([4, 5, 6])); assert((c[] ~ d)[].equal([1, 2, 3, 4, 5, 6])); assert(c[].equal([1, 2, 3])); assert(d[].equal([4, 5, 6])); a~=c[]; assert(a[].equal([1, 2, 3])); assert(c[].equal([1, 2, 3])); a~=d[]; assert(a[].equal([1, 2, 3, 4, 5, 6])); assert(d[].equal([4, 5, 6])); a~=[7, 8, 9]; assert(a[].equal([1, 2, 3, 4, 5, 6, 7, 8, 9])); //trick test: auto r = c[]; c.removeFront(); c.removeBack(); } @safe unittest { import std.algorithm : equal; //8905 auto a = DList!int([1, 2, 3, 4]); auto r = a[]; a.stableRemoveBack(); a.stableInsertBack(7); assert(a[].equal([1, 2, 3, 7])); } @safe unittest //12566 { auto dl2 = DList!int([2,7]); dl2.removeFront(); assert(dl2[].walkLength == 1); dl2.removeBack(); assert(dl2.empty, "not empty?!"); } @safe unittest //13076 { DList!int list; assert(list.empty); list.clear(); } @safe unittest //13425 { import std.range : drop, take; auto list = DList!int([1,2,3,4,5]); auto r = list[].drop(4); // r is a view of the last element of list assert(r.front == 5 && r.walkLength == 1); r = list.linearRemove(r.take(1)); assert(r.empty); // fails } @safe unittest //14300 { interface ITest {} static class Test : ITest {} DList!ITest().insertBack(new Test()); } @safe unittest //15263 { import std.range : iota; auto a = DList!int(); a.insertFront(iota(0, 5)); // can insert range with non-ref front assert(a.front == 0 && a.back == 4); } ldc-1.1.0-beta3-src/runtime/phobos/std/container/binaryheap.d0000664000175000017500000003137312776215007022166 0ustar kaikai/** This module provides a $(D BinaryHeap) (aka priority queue) adaptor that makes a binary heap out of any user-provided random-access range. This module is a submodule of $(LINK2 std_container.html, std.container). Source: $(PHOBOSSRC std/container/_binaryheap.d) Macros: WIKI = Phobos/StdContainer TEXTWITHCOMMAS = $0 Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. License: Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at $(WEB boost.org/LICENSE_1_0.txt)). Authors: Steven Schveighoffer, $(WEB erdani.com, Andrei Alexandrescu) */ module std.container.binaryheap; import std.range.primitives; import std.traits; public import std.container.util; // BinaryHeap /** Implements a $(WEB en.wikipedia.org/wiki/Binary_heap, binary heap) container on top of a given random-access range type (usually $(D T[])) or a random-access container type (usually $(D Array!T)). The documentation of $(D BinaryHeap) will refer to the underlying range or container as the $(I store) of the heap. The binary heap induces structure over the underlying store such that accessing the largest element (by using the $(D front) property) is a $(BIGOH 1) operation and extracting it (by using the $(D removeFront()) method) is done fast in $(BIGOH log n) time. If $(D less) is the less-than operator, which is the default option, then $(D BinaryHeap) defines a so-called max-heap that optimizes extraction of the $(I largest) elements. To define a min-heap, instantiate BinaryHeap with $(D "a > b") as its predicate. Simply extracting elements from a $(D BinaryHeap) container is tantamount to lazily fetching elements of $(D Store) in descending order. Extracting elements from the $(D BinaryHeap) to completion leaves the underlying store sorted in ascending order but, again, yields elements in descending order. If $(D Store) is a range, the $(D BinaryHeap) cannot grow beyond the size of that range. If $(D Store) is a container that supports $(D insertBack), the $(D BinaryHeap) may grow by adding elements to the container. */ struct BinaryHeap(Store, alias less = "a < b") if (isRandomAccessRange!(Store) || isRandomAccessRange!(typeof(Store.init[]))) { import std.functional : binaryFun; import std.exception : enforce; import std.algorithm : move, min, HeapOps, swapAt; import std.typecons : RefCounted, RefCountedAutoInitialize; static if(isRandomAccessRange!Store) alias Range = Store; else alias Range = typeof(Store.init[]); alias percolate = HeapOps!(less, Range).percolate; alias buildHeap = HeapOps!(less, Range).buildHeap; // Really weird @@BUG@@: if you comment out the "private:" label below, // std.algorithm can't unittest anymore //private: // The payload includes the support store and the effective length private static struct Data { Store _store; size_t _length; } private RefCounted!(Data, RefCountedAutoInitialize.no) _payload; // Comparison predicate private alias comp = binaryFun!(less); // Convenience accessors private @property ref Store _store() { assert(_payload.refCountedStore.isInitialized); return _payload._store; } private @property ref size_t _length() { assert(_payload.refCountedStore.isInitialized); return _payload._length; } // Asserts that the heap property is respected. private void assertValid() { debug { import std.conv : to; if (!_payload.refCountedStore.isInitialized) return; if (_length < 2) return; for (size_t n = _length - 1; n >= 1; --n) { auto parentIdx = (n - 1) / 2; assert(!comp(_store[parentIdx], _store[n]), to!string(n)); } } } // @@@BUG@@@: add private here, std.algorithm doesn't unittest anymore /*private*/ void pop(Store store) { assert(!store.empty, "Cannot pop an empty store."); if (store.length == 1) return; auto t1 = moveFront(store[]); auto t2 = moveBack(store[]); store.front = move(t2); store.back = move(t1); percolate(store[], 0, store.length - 1); } public: /** Converts the store $(D s) into a heap. If $(D initialSize) is specified, only the first $(D initialSize) elements in $(D s) are transformed into a heap, after which the heap can grow up to $(D r.length) (if $(D Store) is a range) or indefinitely (if $(D Store) is a container with $(D insertBack)). Performs $(BIGOH min(r.length, initialSize)) evaluations of $(D less). */ this(Store s, size_t initialSize = size_t.max) { acquire(s, initialSize); } /** Takes ownership of a store. After this, manipulating $(D s) may make the heap work incorrectly. */ void acquire(Store s, size_t initialSize = size_t.max) { _payload.refCountedStore.ensureInitialized(); _store = move(s); _length = min(_store.length, initialSize); if (_length < 2) return; buildHeap(_store[]); assertValid(); } /** Takes ownership of a store assuming it already was organized as a heap. */ void assume(Store s, size_t initialSize = size_t.max) { _payload.refCountedStore.ensureInitialized(); _store = s; _length = min(_store.length, initialSize); assertValid(); } /** Clears the heap. Returns the portion of the store from $(D 0) up to $(D length), which satisfies the $(LUCKY heap property). */ auto release() { if (!_payload.refCountedStore.isInitialized) { return typeof(_store[0 .. _length]).init; } assertValid(); auto result = _store[0 .. _length]; _payload = _payload.init; return result; } /** Returns $(D true) if the heap is _empty, $(D false) otherwise. */ @property bool empty() { return !length; } /** Returns a duplicate of the heap. The underlying store must also support a $(D dup) method. */ @property BinaryHeap dup() { BinaryHeap result; if (!_payload.refCountedStore.isInitialized) return result; result.assume(_store.dup, length); return result; } /** Returns the _length of the heap. */ @property size_t length() { return _payload.refCountedStore.isInitialized ? _length : 0; } /** Returns the _capacity of the heap, which is the length of the underlying store (if the store is a range) or the _capacity of the underlying store (if the store is a container). */ @property size_t capacity() { if (!_payload.refCountedStore.isInitialized) return 0; static if (is(typeof(_store.capacity) : size_t)) { return _store.capacity; } else { return _store.length; } } /** Returns a copy of the _front of the heap, which is the largest element according to $(D less). */ @property ElementType!Store front() { enforce(!empty, "Cannot call front on an empty heap."); return _store.front; } /** Clears the heap by detaching it from the underlying store. */ void clear() { _payload = _payload.init; } /** Inserts $(D value) into the store. If the underlying store is a range and $(D length == capacity), throws an exception. */ size_t insert(ElementType!Store value) { static if (is(typeof(_store.insertBack(value)))) { _payload.refCountedStore.ensureInitialized(); if (length == _store.length) { // reallocate _store.insertBack(value); } else { // no reallocation _store[_length] = value; } } else { // can't grow enforce(length < _store.length, "Cannot grow a heap created over a range"); _store[_length] = value; } // sink down the element for (size_t n = _length; n; ) { auto parentIdx = (n - 1) / 2; if (!comp(_store[parentIdx], _store[n])) break; // done! // must swap and continue swapAt(_store, parentIdx, n); n = parentIdx; } ++_length; debug(BinaryHeap) assertValid(); return 1; } /** Removes the largest element from the heap. */ void removeFront() { enforce(!empty, "Cannot call removeFront on an empty heap."); if (_length > 1) { auto t1 = moveFront(_store[]); auto t2 = moveAt(_store[], _length - 1); _store.front = move(t2); _store[_length - 1] = move(t1); } --_length; percolate(_store[], 0, _length); } /// ditto alias popFront = removeFront; /** Removes the largest element from the heap and returns a copy of it. The element still resides in the heap's store. For performance reasons you may want to use $(D removeFront) with heaps of objects that are expensive to copy. */ ElementType!Store removeAny() { removeFront(); return _store[_length]; } /** Replaces the largest element in the store with $(D value). */ void replaceFront(ElementType!Store value) { // must replace the top assert(!empty, "Cannot call replaceFront on an empty heap."); _store.front = value; percolate(_store[], 0, _length); debug(BinaryHeap) assertValid(); } /** If the heap has room to grow, inserts $(D value) into the store and returns $(D true). Otherwise, if $(D less(value, front)), calls $(D replaceFront(value)) and returns again $(D true). Otherwise, leaves the heap unaffected and returns $(D false). This method is useful in scenarios where the smallest $(D k) elements of a set of candidates must be collected. */ bool conditionalInsert(ElementType!Store value) { _payload.refCountedStore.ensureInitialized(); if (_length < _store.length) { insert(value); return true; } // must replace the top assert(!_store.empty, "Cannot replace front of an empty heap."); if (!comp(value, _store.front)) return false; // value >= largest _store.front = value; percolate(_store[], 0, _length); debug(BinaryHeap) assertValid(); return true; } } /// Example from "Introduction to Algorithms" Cormen et al, p 146 unittest { import std.algorithm : equal; int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; auto h = heapify(a); // largest element assert(h.front == 16); // a has the heap property assert(equal(a, [ 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 ])); } /// $(D BinaryHeap) implements the standard input range interface, allowing /// lazy iteration of the underlying range in descending order. unittest { import std.algorithm : equal; import std.range : take; int[] a = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]; auto top5 = heapify(a).take(5); assert(top5.equal([16, 14, 10, 9, 8])); } /** Convenience function that returns a $(D BinaryHeap!Store) object initialized with $(D s) and $(D initialSize). */ BinaryHeap!(Store, less) heapify(alias less = "a < b", Store)(Store s, size_t initialSize = size_t.max) { return BinaryHeap!(Store, less)(s, initialSize); } unittest { import std.conv : to; { // example from "Introduction to Algorithms" Cormen et al., p 146 int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; auto h = heapify(a); h = heapify!"a < b"(a); assert(h.front == 16); assert(a == [ 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 ]); auto witness = [ 16, 14, 10, 9, 8, 7, 4, 3, 2, 1 ]; for (; !h.empty; h.removeFront(), witness.popFront()) { assert(!witness.empty); assert(witness.front == h.front); } assert(witness.empty); } { int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; int[] b = new int[a.length]; BinaryHeap!(int[]) h = BinaryHeap!(int[])(b, 0); foreach (e; a) { h.insert(e); } assert(b == [ 16, 14, 10, 8, 7, 3, 9, 1, 4, 2 ], to!string(b)); } } unittest { // Test range interface. import std.algorithm : equal; int[] a = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]; auto h = heapify(a); static assert(isInputRange!(typeof(h))); assert(h.equal([16, 14, 10, 9, 8, 7, 4, 3, 2, 1])); } unittest // 15675 { import std.container.array : Array; Array!int elements = [1, 2, 10, 12]; auto heap = heapify(elements); assert(heap.front == 12); } ldc-1.1.0-beta3-src/runtime/phobos/std/container/rbtree.d0000664000175000017500000015745012776215007021334 0ustar kaikai/** This module implements a red-black tree container. This module is a submodule of $(LINK2 std_container.html, std.container). Source: $(PHOBOSSRC std/container/_rbtree.d) Macros: WIKI = Phobos/StdContainer TEXTWITHCOMMAS = $0 Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. License: Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at $(WEB boost.org/LICENSE_1_0.txt)). Authors: Steven Schveighoffer, $(WEB erdani.com, Andrei Alexandrescu) */ module std.container.rbtree; /// unittest { import std.container.rbtree; import std.algorithm: equal; auto rbt = redBlackTree(3, 1, 4, 2, 5); assert(rbt.front == 1); assert(equal(rbt[], [1, 2, 3, 4, 5])); rbt.removeKey(1, 4); assert(equal(rbt[], [2, 3, 5])); rbt.removeFront(); assert(equal(rbt[], [3, 5])); rbt.insert([1, 2, 4]); assert(equal(rbt[], [1, 2, 3, 4, 5])); // Query bounds in O(log(n)) assert(rbt.lowerBound(3).equal([1, 2])); assert(rbt.equalRange(3).equal([3])); assert(rbt.upperBound(3).equal([4, 5])); // A Red Black tree with the highest element at front: import std.range: iota; auto maxTree = redBlackTree!"a > b"(iota(5)); assert(equal(maxTree[], [4, 3, 2, 1, 0])); // adding duplicates will not add them, but return 0 auto rbt2 = redBlackTree(1, 3); assert(rbt2.insert(1) == 0); assert(equal(rbt2[], [1, 3])); assert(rbt2.insert(2) == 1); // however you can allow duplicates auto ubt = redBlackTree!true([0, 1, 0, 1]); assert(equal(ubt[], [0, 0, 1, 1])); } import std.functional : binaryFun; import std.format; public import std.container.util; version(unittest) debug = RBDoChecks; //debug = RBDoChecks; /* * Implementation for a Red Black node for use in a Red Black Tree (see below) * * this implementation assumes we have a marker Node that is the parent of the * root Node. This marker Node is not a valid Node, but marks the end of the * collection. The root is the left child of the marker Node, so it is always * last in the collection. The marker Node is passed in to the setColor * function, and the Node which has this Node as its parent is assumed to be * the root Node. * * A Red Black tree should have O(lg(n)) insertion, removal, and search time. */ struct RBNode(V) { /* * Convenience alias */ alias Node = RBNode*; private Node _left; private Node _right; private Node _parent; /** * The value held by this node */ V value; /** * Enumeration determining what color the node is. Null nodes are assumed * to be black. */ enum Color : byte { Red, Black } /** * The color of the node. */ Color color; /** * Get the left child */ @property inout(RBNode)* left() inout { return _left; } /** * Get the right child */ @property inout(RBNode)* right() inout { return _right; } /** * Get the parent */ @property inout(RBNode)* parent() inout { return _parent; } /** * Set the left child. Also updates the new child's parent node. This * does not update the previous child. * * Returns newNode */ @property Node left(Node newNode) { _left = newNode; if(newNode !is null) newNode._parent = &this; return newNode; } /** * Set the right child. Also updates the new child's parent node. This * does not update the previous child. * * Returns newNode */ @property Node right(Node newNode) { _right = newNode; if(newNode !is null) newNode._parent = &this; return newNode; } // assume _left is not null // // performs rotate-right operation, where this is T, _right is R, _left is // L, _parent is P: // // P P // | -> | // T L // / \ / \ // L R a T // / \ / \ // a b b R // /** * Rotate right. This performs the following operations: * - The left child becomes the parent of this node. * - This node becomes the new parent's right child. * - The old right child of the new parent becomes the left child of this * node. */ Node rotateR() in { assert(_left !is null); } body { // sets _left._parent also if(isLeftNode) parent.left = _left; else parent.right = _left; Node tmp = _left._right; // sets _parent also _left.right = &this; // sets tmp._parent also left = tmp; return &this; } // assumes _right is non null // // performs rotate-left operation, where this is T, _right is R, _left is // L, _parent is P: // // P P // | -> | // T R // / \ / \ // L R T b // / \ / \ // a b L a // /** * Rotate left. This performs the following operations: * - The right child becomes the parent of this node. * - This node becomes the new parent's left child. * - The old left child of the new parent becomes the right child of this * node. */ Node rotateL() in { assert(_right !is null); } body { // sets _right._parent also if(isLeftNode) parent.left = _right; else parent.right = _right; Node tmp = _right._left; // sets _parent also _right.left = &this; // sets tmp._parent also right = tmp; return &this; } /** * Returns true if this node is a left child. * * Note that this should always return a value because the root has a * parent which is the marker node. */ @property bool isLeftNode() const in { assert(_parent !is null); } body { return _parent._left is &this; } /** * Set the color of the node after it is inserted. This performs an * update to the whole tree, possibly rotating nodes to keep the Red-Black * properties correct. This is an O(lg(n)) operation, where n is the * number of nodes in the tree. * * end is the marker node, which is the parent of the topmost valid node. */ void setColor(Node end) { // test against the marker node if(_parent !is end) { if(_parent.color == Color.Red) { Node cur = &this; while(true) { // because root is always black, _parent._parent always exists if(cur._parent.isLeftNode) { // parent is left node, y is 'uncle', could be null Node y = cur._parent._parent._right; if(y !is null && y.color == Color.Red) { cur._parent.color = Color.Black; y.color = Color.Black; cur = cur._parent._parent; if(cur._parent is end) { // root node cur.color = Color.Black; break; } else { // not root node cur.color = Color.Red; if(cur._parent.color == Color.Black) // satisfied, exit the loop break; } } else { if(!cur.isLeftNode) cur = cur._parent.rotateL(); cur._parent.color = Color.Black; cur = cur._parent._parent.rotateR(); cur.color = Color.Red; // tree should be satisfied now break; } } else { // parent is right node, y is 'uncle' Node y = cur._parent._parent._left; if(y !is null && y.color == Color.Red) { cur._parent.color = Color.Black; y.color = Color.Black; cur = cur._parent._parent; if(cur._parent is end) { // root node cur.color = Color.Black; break; } else { // not root node cur.color = Color.Red; if(cur._parent.color == Color.Black) // satisfied, exit the loop break; } } else { if(cur.isLeftNode) cur = cur._parent.rotateR(); cur._parent.color = Color.Black; cur = cur._parent._parent.rotateL(); cur.color = Color.Red; // tree should be satisfied now break; } } } } } else { // // this is the root node, color it black // color = Color.Black; } } /** * Remove this node from the tree. The 'end' node is used as the marker * which is root's parent. Note that this cannot be null! * * Returns the next highest valued node in the tree after this one, or end * if this was the highest-valued node. */ Node remove(Node end) { // // remove this node from the tree, fixing the color if necessary. // Node x; Node ret = next; // if this node has 2 children if (_left !is null && _right !is null) { // // normally, we can just swap this node's and y's value, but // because an iterator could be pointing to y and we don't want to // disturb it, we swap this node and y's structure instead. This // can also be a benefit if the value of the tree is a large // struct, which takes a long time to copy. // Node yp, yl, yr; Node y = ret; // y = next yp = y._parent; yl = y._left; yr = y._right; auto yc = y.color; auto isyleft = y.isLeftNode; // // replace y's structure with structure of this node. // if(isLeftNode) _parent.left = y; else _parent.right = y; // // need special case so y doesn't point back to itself // y.left = _left; if(_right is y) y.right = &this; else y.right = _right; y.color = color; // // replace this node's structure with structure of y. // left = yl; right = yr; if(_parent !is y) { if(isyleft) yp.left = &this; else yp.right = &this; } color = yc; } // if this has less than 2 children, remove it if(_left !is null) x = _left; else x = _right; bool deferedUnlink = false; if(x is null) { // pretend this is a null node, defer unlinking the node x = &this; deferedUnlink = true; } else if(isLeftNode) _parent.left = x; else _parent.right = x; // if the color of this is black, then it needs to be fixed if(color == color.Black) { // need to recolor the tree. while(x._parent !is end && x.color == Node.Color.Black) { if(x.isLeftNode) { // left node Node w = x._parent._right; if(w.color == Node.Color.Red) { w.color = Node.Color.Black; x._parent.color = Node.Color.Red; x._parent.rotateL(); w = x._parent._right; } Node wl = w.left; Node wr = w.right; if((wl is null || wl.color == Node.Color.Black) && (wr is null || wr.color == Node.Color.Black)) { w.color = Node.Color.Red; x = x._parent; } else { if(wr is null || wr.color == Node.Color.Black) { // wl cannot be null here wl.color = Node.Color.Black; w.color = Node.Color.Red; w.rotateR(); w = x._parent._right; } w.color = x._parent.color; x._parent.color = Node.Color.Black; w._right.color = Node.Color.Black; x._parent.rotateL(); x = end.left; // x = root } } else { // right node Node w = x._parent._left; if(w.color == Node.Color.Red) { w.color = Node.Color.Black; x._parent.color = Node.Color.Red; x._parent.rotateR(); w = x._parent._left; } Node wl = w.left; Node wr = w.right; if((wl is null || wl.color == Node.Color.Black) && (wr is null || wr.color == Node.Color.Black)) { w.color = Node.Color.Red; x = x._parent; } else { if(wl is null || wl.color == Node.Color.Black) { // wr cannot be null here wr.color = Node.Color.Black; w.color = Node.Color.Red; w.rotateL(); w = x._parent._left; } w.color = x._parent.color; x._parent.color = Node.Color.Black; w._left.color = Node.Color.Black; x._parent.rotateR(); x = end.left; // x = root } } } x.color = Node.Color.Black; } if(deferedUnlink) { // // unlink this node from the tree // if(isLeftNode) _parent.left = null; else _parent.right = null; } // clean references to help GC - Bugzilla 12915 _left = _right = _parent = null; return ret; } /** * Return the leftmost descendant of this node. */ @property inout(RBNode)* leftmost() inout { inout(RBNode)* result = &this; while(result._left !is null) result = result._left; return result; } /** * Return the rightmost descendant of this node */ @property inout(RBNode)* rightmost() inout { inout(RBNode)* result = &this; while(result._right !is null) result = result._right; return result; } /** * Returns the next valued node in the tree. * * You should never call this on the marker node, as it is assumed that * there is a valid next node. */ @property inout(RBNode)* next() inout { inout(RBNode)* n = &this; if(n.right is null) { while(!n.isLeftNode) n = n._parent; return n._parent; } else return n.right.leftmost; } /** * Returns the previous valued node in the tree. * * You should never call this on the leftmost node of the tree as it is * assumed that there is a valid previous node. */ @property inout(RBNode)* prev() inout { inout(RBNode)* n = &this; if(n.left is null) { while(n.isLeftNode) n = n._parent; return n._parent; } else return n.left.rightmost; } Node dup(scope Node delegate(V v) alloc) { // // duplicate this and all child nodes // // The recursion should be lg(n), so we shouldn't have to worry about // stack size. // Node copy = alloc(value); copy.color = color; if(_left !is null) copy.left = _left.dup(alloc); if(_right !is null) copy.right = _right.dup(alloc); return copy; } Node dup() { Node copy = new RBNode!V; copy.value = value; copy.color = color; if(_left !is null) copy.left = _left.dup(); if(_right !is null) copy.right = _right.dup(); return copy; } } //constness checks unittest { const RBNode!int n; static assert(is(typeof(n.leftmost))); static assert(is(typeof(n.rightmost))); static assert(is(typeof(n.next))); static assert(is(typeof(n.prev))); } private struct RBRange(N) { alias Node = N; alias Elem = typeof(Node.value); private Node _begin; private Node _end; private this(Node b, Node e) { _begin = b; _end = e; } /** * Returns $(D true) if the range is _empty */ @property bool empty() const { return _begin is _end; } /** * Returns the first element in the range */ @property Elem front() { return _begin.value; } /** * Returns the last element in the range */ @property Elem back() { return _end.prev.value; } /** * pop the front element from the range * * complexity: amortized $(BIGOH 1) */ void popFront() { _begin = _begin.next; } /** * pop the back element from the range * * complexity: amortized $(BIGOH 1) */ void popBack() { _end = _end.prev; } /** * Trivial _save implementation, needed for $(D isForwardRange). */ @property RBRange save() { return this; } } /** * Implementation of a $(LUCKY red-black tree) container. * * All inserts, removes, searches, and any function in general has complexity * of $(BIGOH lg(n)). * * To use a different comparison than $(D "a < b"), pass a different operator string * that can be used by $(XREF functional, binaryFun), or pass in a * function, delegate, functor, or any type where $(D less(a, b)) results in a $(D bool) * value. * * Note that less should produce a strict ordering. That is, for two unequal * elements $(D a) and $(D b), $(D less(a, b) == !less(b, a)). $(D less(a, a)) should * always equal $(D false). * * If $(D allowDuplicates) is set to $(D true), then inserting the same element more than * once continues to add more elements. If it is $(D false), duplicate elements are * ignored on insertion. If duplicates are allowed, then new elements are * inserted after all existing duplicate elements. */ final class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false) if(is(typeof(binaryFun!less(T.init, T.init)))) { import std.meta : allSatisfy; import std.range.primitives; import std.range : Take; import std.traits; alias _less = binaryFun!less; version(unittest) { static if(is(typeof(less) == string)) { private enum doUnittest = isIntegral!T && (less == "a < b" || less == "a > b"); } else enum doUnittest = false; // note, this must be final so it does not affect the vtable layout final bool arrayEqual(T[] arr) { if(walkLength(this[]) == arr.length) { foreach(v; arr) { if(!(v in this)) return false; } return true; } return false; } } else { private enum doUnittest = false; } /** * Element type for the tree */ alias Elem = T; // used for convenience private alias RBNode = .RBNode!Elem; private alias Node = RBNode.Node; private Node _end; private Node _begin; private size_t _length; private void _setup() { assert(!_end); //Make sure that _setup isn't run more than once. _begin = _end = allocate(); } static private Node allocate() { return new RBNode; } static private Node allocate(Elem v) { auto result = allocate(); result.value = v; return result; } /** * The range types for $(D RedBlackTree) */ alias Range = RBRange!(RBNode*); alias ConstRange = RBRange!(const(RBNode)*); /// Ditto alias ImmutableRange = RBRange!(immutable(RBNode)*); /// Ditto static if(doUnittest) unittest { import std.algorithm : equal; import std.range.primitives; auto ts = new RedBlackTree(1, 2, 3, 4, 5); assert(ts.length == 5); auto r = ts[]; static if(less == "a < b") auto vals = [1, 2, 3, 4, 5]; else auto vals = [5, 4, 3, 2, 1]; assert(equal(r, vals)); assert(r.front == vals.front); assert(r.back != r.front); auto oldfront = r.front; auto oldback = r.back; r.popFront(); r.popBack(); assert(r.front != r.back); assert(r.front != oldfront); assert(r.back != oldback); assert(ts.length == 5); } // find a node based on an element value private inout(RBNode)* _find(Elem e) inout { static if(allowDuplicates) { inout(RBNode)* cur = _end.left; inout(RBNode)* result = null; while(cur) { if(_less(cur.value, e)) cur = cur.right; else if(_less(e, cur.value)) cur = cur.left; else { // want to find the left-most element result = cur; cur = cur.left; } } return result; } else { inout(RBNode)* cur = _end.left; while(cur) { if(_less(cur.value, e)) cur = cur.right; else if(_less(e, cur.value)) cur = cur.left; else return cur; } return null; } } // add an element to the tree, returns the node added, or the existing node // if it has already been added and allowDuplicates is false private auto _add(Elem n) { Node result; static if(!allowDuplicates) bool added = true; if(!_end.left) { _end.left = _begin = result = allocate(n); } else { Node newParent = _end.left; Node nxt = void; while(true) { if(_less(n, newParent.value)) { nxt = newParent.left; if(nxt is null) { // // add to right of new parent // newParent.left = result = allocate(n); break; } } else { static if(!allowDuplicates) { if(!_less(newParent.value, n)) { result = newParent; added = false; break; } } nxt = newParent.right; if(nxt is null) { // // add to right of new parent // newParent.right = result = allocate(n); break; } } newParent = nxt; } if(_begin.left) _begin = _begin.left; } static if(allowDuplicates) { result.setColor(_end); debug(RBDoChecks) check(); ++_length; return result; } else { import std.typecons : Tuple; if(added) { ++_length; result.setColor(_end); } debug(RBDoChecks) check(); return Tuple!(bool, "added", Node, "n")(added, result); } } /** * Check if any elements exist in the container. Returns $(D false) if at least * one element exists. */ @property bool empty() { return _end.left is null; } /++ Returns the number of elements in the container. Complexity: $(BIGOH 1). +/ @property size_t length() const { return _length; } /** * Duplicate this container. The resulting container contains a shallow * copy of the elements. * * Complexity: $(BIGOH n) */ @property RedBlackTree dup() { return new RedBlackTree(_end.dup(), _length); } static if(doUnittest) unittest { import std.algorithm : equal; auto ts = new RedBlackTree(1, 2, 3, 4, 5); assert(ts.length == 5); auto ts2 = ts.dup; assert(ts2.length == 5); assert(equal(ts[], ts2[])); ts2.insert(cast(Elem)6); assert(!equal(ts[], ts2[])); assert(ts.length == 5 && ts2.length == 6); } /** * Fetch a range that spans all the elements in the container. * * Complexity: $(BIGOH 1) */ Range opSlice() { return Range(_begin, _end); } /// Ditto ConstRange opSlice() const { return ConstRange(_begin, _end); } /// Ditto ImmutableRange opSlice() immutable { return ImmutableRange(_begin, _end); } /** * The front element in the container * * Complexity: $(BIGOH 1) */ Elem front() { return _begin.value; } /** * The last element in the container * * Complexity: $(BIGOH log(n)) */ Elem back() { return _end.prev.value; } /++ $(D in) operator. Check to see if the given element exists in the container. Complexity: $(BIGOH log(n)) +/ bool opBinaryRight(string op)(Elem e) const if (op == "in") { return _find(e) !is null; } static if(doUnittest) unittest { auto ts = new RedBlackTree(1, 2, 3, 4, 5); assert(cast(Elem)3 in ts); assert(cast(Elem)6 !in ts); } /** * Compares two trees for equality. * * Complexity: $(BIGOH n) */ override bool opEquals(Object rhs) { import std.algorithm : equal; RedBlackTree that = cast(RedBlackTree)rhs; if (that is null) return false; // If there aren't the same number of nodes, we can't be equal. if (this._length != that._length) return false; auto thisRange = this[]; auto thatRange = that[]; return equal!(function(Elem a, Elem b) => !_less(a,b) && !_less(b,a)) (thisRange, thatRange); } static if(doUnittest) unittest { auto t1 = new RedBlackTree(1,2,3,4); auto t2 = new RedBlackTree(1,2,3,4); auto t3 = new RedBlackTree(1,2,3,5); auto t4 = new RedBlackTree(1,2,3,4,5); auto o = new Object(); assert(t1 == t1); assert(t1 == t2); assert(t1 != t3); assert(t1 != t4); assert(t1 != o); // pathological case, must not crash } /** * Removes all elements from the container. * * Complexity: $(BIGOH 1) */ void clear() { _end.left = null; _begin = _end; _length = 0; } static if(doUnittest) unittest { auto ts = new RedBlackTree(1,2,3,4,5); assert(ts.length == 5); ts.clear(); assert(ts.empty && ts.length == 0); } /** * Insert a single element in the container. Note that this does not * invalidate any ranges currently iterating the container. * * Returns: The number of elements inserted. * * Complexity: $(BIGOH log(n)) */ size_t stableInsert(Stuff)(Stuff stuff) if (isImplicitlyConvertible!(Stuff, Elem)) { static if(allowDuplicates) { _add(stuff); return 1; } else { return(_add(stuff).added ? 1 : 0); } } /** * Insert a range of elements in the container. Note that this does not * invalidate any ranges currently iterating the container. * * Returns: The number of elements inserted. * * Complexity: $(BIGOH m * log(n)) */ size_t stableInsert(Stuff)(Stuff stuff) if(isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, Elem)) { size_t result = 0; static if(allowDuplicates) { foreach(e; stuff) { ++result; _add(e); } } else { foreach(e; stuff) { if(_add(e).added) ++result; } } return result; } /// ditto alias insert = stableInsert; static if(doUnittest) unittest { auto ts = new RedBlackTree(2,1,3,4,5,2,5); static if(allowDuplicates) { assert(ts.length == 7); assert(ts.stableInsert(cast(Elem[])[7, 8, 6, 9, 10, 8]) == 6); assert(ts.length == 13); assert(ts.stableInsert(cast(Elem)11) == 1 && ts.length == 14); assert(ts.stableInsert(cast(Elem)7) == 1 && ts.length == 15); static if(less == "a < b") assert(ts.arrayEqual([1,2,2,3,4,5,5,6,7,7,8,8,9,10,11])); else assert(ts.arrayEqual([11,10,9,8,8,7,7,6,5,5,4,3,2,2,1])); } else { assert(ts.length == 5); assert(ts.stableInsert(cast(Elem[])[7, 8, 6, 9, 10, 8]) == 5); assert(ts.length == 10); assert(ts.stableInsert(cast(Elem)11) == 1 && ts.length == 11); assert(ts.stableInsert(cast(Elem)7) == 0 && ts.length == 11); static if(less == "a < b") assert(ts.arrayEqual([1,2,3,4,5,6,7,8,9,10,11])); else assert(ts.arrayEqual([11,10,9,8,7,6,5,4,3,2,1])); } } /** * Remove an element from the container and return its value. * * Complexity: $(BIGOH log(n)) */ Elem removeAny() { scope(success) --_length; auto n = _begin; auto result = n.value; _begin = n.remove(_end); debug(RBDoChecks) check(); return result; } static if(doUnittest) unittest { auto ts = new RedBlackTree(1,2,3,4,5); assert(ts.length == 5); auto x = ts.removeAny(); assert(ts.length == 4); Elem[] arr; foreach(Elem i; 1..6) if(i != x) arr ~= i; assert(ts.arrayEqual(arr)); } /** * Remove the front element from the container. * * Complexity: $(BIGOH log(n)) */ void removeFront() { scope(success) --_length; _begin = _begin.remove(_end); debug(RBDoChecks) check(); } /** * Remove the back element from the container. * * Complexity: $(BIGOH log(n)) */ void removeBack() { scope(success) --_length; auto lastnode = _end.prev; if(lastnode is _begin) _begin = _begin.remove(_end); else lastnode.remove(_end); debug(RBDoChecks) check(); } static if(doUnittest) unittest { auto ts = new RedBlackTree(1,2,3,4,5); assert(ts.length == 5); ts.removeBack(); assert(ts.length == 4); static if(less == "a < b") assert(ts.arrayEqual([1,2,3,4])); else assert(ts.arrayEqual([2,3,4,5])); ts.removeFront(); assert(ts.arrayEqual([2,3,4]) && ts.length == 3); } /++ Removes the given range from the container. Returns: A range containing all of the elements that were after the given range. Complexity: $(BIGOH m * log(n)) (where m is the number of elements in the range) +/ Range remove(Range r) { auto b = r._begin; auto e = r._end; if(_begin is b) _begin = e; while(b !is e) { b = b.remove(_end); --_length; } debug(RBDoChecks) check(); return Range(e, _end); } static if(doUnittest) unittest { import std.algorithm : equal; auto ts = new RedBlackTree(1,2,3,4,5); assert(ts.length == 5); auto r = ts[]; r.popFront(); r.popBack(); assert(ts.length == 5); auto r2 = ts.remove(r); assert(ts.length == 2); assert(ts.arrayEqual([1,5])); static if(less == "a < b") assert(equal(r2, [5])); else assert(equal(r2, [1])); } /++ Removes the given $(D Take!Range) from the container Returns: A range containing all of the elements that were after the given range. Complexity: $(BIGOH m * log(n)) (where m is the number of elements in the range) +/ Range remove(Take!Range r) { immutable isBegin = (r.source._begin is _begin); auto b = r.source._begin; while(!r.empty) { r.popFront(); b = b.remove(_end); --_length; } if(isBegin) _begin = b; return Range(b, _end); } static if(doUnittest) unittest { import std.algorithm : equal; import std.range : take; auto ts = new RedBlackTree(1,2,3,4,5); auto r = ts[]; r.popFront(); assert(ts.length == 5); auto r2 = ts.remove(take(r, 0)); static if(less == "a < b") { assert(equal(r2, [2,3,4,5])); auto r3 = ts.remove(take(r, 2)); assert(ts.arrayEqual([1,4,5]) && ts.length == 3); assert(equal(r3, [4,5])); } else { assert(equal(r2, [4,3,2,1])); auto r3 = ts.remove(take(r, 2)); assert(ts.arrayEqual([5,2,1]) && ts.length == 3); assert(equal(r3, [2,1])); } } /++ Removes elements from the container that are equal to the given values according to the less comparator. One element is removed for each value given which is in the container. If $(D allowDuplicates) is true, duplicates are removed only if duplicate values are given. Returns: The number of elements removed. Complexity: $(BIGOH m log(n)) (where m is the number of elements to remove) Example: -------------------- auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7); rbt.removeKey(1, 4, 7); assert(equal(rbt[], [0, 1, 1, 5])); rbt.removeKey(1, 1, 0); assert(equal(rbt[], [5])); -------------------- +/ size_t removeKey(U...)(U elems) if(allSatisfy!(isImplicitlyConvertibleToElem, U)) { Elem[U.length] toRemove; foreach(i, e; elems) toRemove[i] = e; return removeKey(toRemove[]); } /++ Ditto +/ size_t removeKey(U)(U[] elems) if(isImplicitlyConvertible!(U, Elem)) { immutable lenBefore = length; foreach(e; elems) { auto beg = _firstGreaterEqual(e); if(beg is _end || _less(e, beg.value)) // no values are equal continue; immutable isBegin = (beg is _begin); beg = beg.remove(_end); if(isBegin) _begin = beg; --_length; } return lenBefore - length; } /++ Ditto +/ size_t removeKey(Stuff)(Stuff stuff) if(isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, Elem) && !isDynamicArray!Stuff) { import std.array : array; //We use array in case stuff is a Range from this RedBlackTree - either //directly or indirectly. return removeKey(array(stuff)); } //Helper for removeKey. private template isImplicitlyConvertibleToElem(U) { enum isImplicitlyConvertibleToElem = isImplicitlyConvertible!(U, Elem); } static if(doUnittest) unittest { import std.algorithm : equal; import std.range : take; auto rbt = new RedBlackTree(5, 4, 3, 7, 2, 1, 7, 6, 2, 19, 45); //The cast(Elem) is because these tests are instantiated with a variety //of numeric types, and the literals are all int, which is not always //implicitly convertible to Elem (e.g. short). static if(allowDuplicates) { assert(rbt.length == 11); assert(rbt.removeKey(cast(Elem)4) == 1 && rbt.length == 10); assert(rbt.arrayEqual([1,2,2,3,5,6,7,7,19,45]) && rbt.length == 10); assert(rbt.removeKey(cast(Elem)6, cast(Elem)2, cast(Elem)1) == 3); assert(rbt.arrayEqual([2,3,5,7,7,19,45]) && rbt.length == 7); assert(rbt.removeKey(cast(Elem)(42)) == 0 && rbt.length == 7); assert(rbt.removeKey(take(rbt[], 3)) == 3 && rbt.length == 4); static if(less == "a < b") assert(equal(rbt[], [7,7,19,45])); else assert(equal(rbt[], [7,5,3,2])); } else { assert(rbt.length == 9); assert(rbt.removeKey(cast(Elem)4) == 1 && rbt.length == 8); assert(rbt.arrayEqual([1,2,3,5,6,7,19,45])); assert(rbt.removeKey(cast(Elem)6, cast(Elem)2, cast(Elem)1) == 3); assert(rbt.arrayEqual([3,5,7,19,45]) && rbt.length == 5); assert(rbt.removeKey(cast(Elem)(42)) == 0 && rbt.length == 5); assert(rbt.removeKey(take(rbt[], 3)) == 3 && rbt.length == 2); static if(less == "a < b") assert(equal(rbt[], [19,45])); else assert(equal(rbt[], [5,3])); } } // find the first node where the value is > e private inout(RBNode)* _firstGreater(Elem e) inout { // can't use _find, because we cannot return null auto cur = _end.left; inout(RBNode)* result = _end; while(cur) { if(_less(e, cur.value)) { result = cur; cur = cur.left; } else cur = cur.right; } return result; } // find the first node where the value is >= e private inout(RBNode)* _firstGreaterEqual(Elem e) inout { // can't use _find, because we cannot return null. auto cur = _end.left; inout(RBNode)* result = _end; while(cur) { if(_less(cur.value, e)) cur = cur.right; else { result = cur; cur = cur.left; } } return result; } /** * Get a range from the container with all elements that are > e according * to the less comparator * * Complexity: $(BIGOH log(n)) */ Range upperBound(Elem e) { return Range(_firstGreater(e), _end); } /// Ditto ConstRange upperBound(Elem e) const { return ConstRange(_firstGreater(e), _end); } /// Ditto ImmutableRange upperBound(Elem e) immutable { return ImmutableRange(_firstGreater(e), _end); } /** * Get a range from the container with all elements that are < e according * to the less comparator * * Complexity: $(BIGOH log(n)) */ Range lowerBound(Elem e) { return Range(_begin, _firstGreaterEqual(e)); } /// Ditto ConstRange lowerBound(Elem e) const { return ConstRange(_begin, _firstGreaterEqual(e)); } /// Ditto ImmutableRange lowerBound(Elem e) immutable { return ImmutableRange(_begin, _firstGreaterEqual(e)); } /** * Get a range from the container with all elements that are == e according * to the less comparator * * Complexity: $(BIGOH log(n)) */ auto equalRange(this This)(Elem e) { auto beg = _firstGreaterEqual(e); alias RangeType = RBRange!(typeof(beg)); if(beg is _end || _less(e, beg.value)) // no values are equal return RangeType(beg, beg); static if(allowDuplicates) { return RangeType(beg, _firstGreater(e)); } else { // no sense in doing a full search, no duplicates are allowed, // so we just get the next node. return RangeType(beg, beg.next); } } static if(doUnittest) unittest { import std.algorithm : equal; auto ts = new RedBlackTree(1, 2, 3, 4, 5); auto rl = ts.lowerBound(3); auto ru = ts.upperBound(3); auto re = ts.equalRange(3); static if(less == "a < b") { assert(equal(rl, [1,2])); assert(equal(ru, [4,5])); } else { assert(equal(rl, [5,4])); assert(equal(ru, [2,1])); } assert(equal(re, [3])); } debug(RBDoChecks) { /* * Print the tree. This prints a sideways view of the tree in ASCII form, * with the number of indentations representing the level of the nodes. * It does not print values, only the tree structure and color of nodes. */ void printTree(Node n, int indent = 0) { import std.stdio; if(n !is null) { printTree(n.right, indent + 2); for(int i = 0; i < indent; i++) write("."); writeln(n.color == n.color.Black ? "B" : "R"); printTree(n.left, indent + 2); } else { for(int i = 0; i < indent; i++) write("."); writeln("N"); } if(indent is 0) writeln(); } /* * Check the tree for validity. This is called after every add or remove. * This should only be enabled to debug the implementation of the RB Tree. */ void check() { // // check implementation of the tree // int recurse(Node n, string path) { import std.stdio; if(n is null) return 1; if(n.parent.left !is n && n.parent.right !is n) throw new Exception("Node at path " ~ path ~ " has inconsistent pointers"); Node next = n.next; static if(allowDuplicates) { if(next !is _end && _less(next.value, n.value)) throw new Exception("ordering invalid at path " ~ path); } else { if(next !is _end && !_less(n.value, next.value)) throw new Exception("ordering invalid at path " ~ path); } if(n.color == n.color.Red) { if((n.left !is null && n.left.color == n.color.Red) || (n.right !is null && n.right.color == n.color.Red)) throw new Exception("Node at path " ~ path ~ " is red with a red child"); } int l = recurse(n.left, path ~ "L"); int r = recurse(n.right, path ~ "R"); if(l != r) { writeln("bad tree at:"); debug printTree(n); throw new Exception("Node at path " ~ path ~ " has different number of black nodes on left and right paths"); } return l + (n.color == n.color.Black ? 1 : 0); } try { recurse(_end.left, ""); } catch(Exception e) { debug printTree(_end.left, 0); throw e; } } } /** Formats the RedBlackTree into a sink function. For more info see $(D std.format.formatValue). Note that this only is available when the element type can be formatted. Otherwise, the default toString from Object is used. */ static if(is(typeof((){FormatSpec!(char) fmt; formatValue((const(char)[]) {}, ConstRange.init, fmt);}))) { void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) const { sink("RedBlackTree("); sink.formatValue(this[], fmt); sink(")"); } } /** * Constructor. Pass in an array of elements, or individual elements to * initialize the tree with. */ this(Elem[] elems...) { _setup(); stableInsert(elems); } /** * Constructor. Pass in a range of elements to initialize the tree with. */ this(Stuff)(Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, Elem)) { _setup(); stableInsert(stuff); } /// this() { _setup(); } private this(Node end, size_t length) { _end = end; _begin = end.leftmost; _length = length; } } //Verify Example for removeKey. pure unittest { import std.algorithm : equal; auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7); rbt.removeKey(1, 4, 7); assert(equal(rbt[], [0, 1, 1, 5])); rbt.removeKey(1, 1, 0); assert(equal(rbt[], [5])); } //Tests for removeKey pure unittest { import std.algorithm : equal; { auto rbt = redBlackTree(["hello", "world", "foo", "bar"]); assert(equal(rbt[], ["bar", "foo", "hello", "world"])); assert(rbt.removeKey("hello") == 1); assert(equal(rbt[], ["bar", "foo", "world"])); assert(rbt.removeKey("hello") == 0); assert(equal(rbt[], ["bar", "foo", "world"])); assert(rbt.removeKey("hello", "foo", "bar") == 2); assert(equal(rbt[], ["world"])); assert(rbt.removeKey(["", "world", "hello"]) == 1); assert(rbt.empty); } { auto rbt = redBlackTree([1, 2, 12, 27, 4, 500]); assert(equal(rbt[], [1, 2, 4, 12, 27, 500])); assert(rbt.removeKey(1u) == 1); assert(equal(rbt[], [2, 4, 12, 27, 500])); assert(rbt.removeKey(cast(byte)1) == 0); assert(equal(rbt[], [2, 4, 12, 27, 500])); assert(rbt.removeKey(1, 12u, cast(byte)27) == 2); assert(equal(rbt[], [2, 4, 500])); assert(rbt.removeKey([cast(short)0, cast(short)500, cast(short)1]) == 1); assert(equal(rbt[], [2, 4])); } } pure unittest { void test(T)() { auto rt1 = new RedBlackTree!(T, "a < b", false)(); auto rt2 = new RedBlackTree!(T, "a < b", true)(); auto rt3 = new RedBlackTree!(T, "a > b", false)(); auto rt4 = new RedBlackTree!(T, "a > b", true)(); } test!long(); test!ulong(); test!int(); test!uint(); test!short(); test!ushort(); test!byte(); test!byte(); } /++ Convenience function for creating a $(D RedBlackTree!E) from a list of values. Params: allowDuplicates = Whether duplicates should be allowed (optional, default: false) less = predicate to sort by (optional) elems = elements to insert into the rbtree (variadic arguments) range = range elements to insert into the rbtree (alternative to elems) +/ auto redBlackTree(E)(E[] elems...) { return new RedBlackTree!E(elems); } /++ Ditto +/ auto redBlackTree(bool allowDuplicates, E)(E[] elems...) { return new RedBlackTree!(E, "a < b", allowDuplicates)(elems); } /++ Ditto +/ auto redBlackTree(alias less, E)(E[] elems...) if(is(typeof(binaryFun!less(E.init, E.init)))) { return new RedBlackTree!(E, less)(elems); } /++ Ditto +/ auto redBlackTree(alias less, bool allowDuplicates, E)(E[] elems...) if(is(typeof(binaryFun!less(E.init, E.init)))) { //We shouldn't need to instantiate less here, but for some reason, //dmd can't handle it if we don't (even though the template which //takes less but not allowDuplicates works just fine). return new RedBlackTree!(E, binaryFun!less, allowDuplicates)(elems); } import std.range.primitives: isInputRange, isSomeString, ElementType; import std.traits: isArray; /++ Ditto +/ auto redBlackTree(Stuff)(Stuff range) if (isInputRange!Stuff && !isArray!(Stuff)) { return new RedBlackTree!(ElementType!Stuff)(range); } /++ Ditto +/ auto redBlackTree(bool allowDuplicates, Stuff)(Stuff range) if (isInputRange!Stuff && !isArray!(Stuff)) { return new RedBlackTree!(ElementType!Stuff, "a < b", allowDuplicates)(range); } /++ Ditto +/ auto redBlackTree(alias less, Stuff)(Stuff range) if( is(typeof(binaryFun!less((ElementType!Stuff).init, (ElementType!Stuff).init))) && isInputRange!Stuff && !isArray!(Stuff)) { return new RedBlackTree!(ElementType!Stuff, less)(range); } /++ Ditto +/ auto redBlackTree(alias less, bool allowDuplicates, Stuff)(Stuff range) if( is(typeof(binaryFun!less((ElementType!Stuff).init, (ElementType!Stuff).init))) && isInputRange!Stuff && !isArray!(Stuff)) { //We shouldn't need to instantiate less here, but for some reason, //dmd can't handle it if we don't (even though the template which //takes less but not allowDuplicates works just fine). return new RedBlackTree!(ElementType!Stuff, binaryFun!less, allowDuplicates)(range); } /// pure unittest { import std.range : iota; auto rbt1 = redBlackTree(0, 1, 5, 7); auto rbt2 = redBlackTree!string("hello", "world"); auto rbt3 = redBlackTree!true(0, 1, 5, 7, 5); auto rbt4 = redBlackTree!"a > b"(0, 1, 5, 7); auto rbt5 = redBlackTree!("a > b", true)(0.1, 1.3, 5.9, 7.2, 5.9); // also works with ranges auto rbt6 = redBlackTree(iota(3)); auto rbt7 = redBlackTree!true(iota(3)); auto rbt8 = redBlackTree!"a > b"(iota(3)); auto rbt9 = redBlackTree!("a > b", true)(iota(3)); } //Combinations not in examples. pure unittest { auto rbt1 = redBlackTree!(true, string)("hello", "hello"); auto rbt2 = redBlackTree!((a, b){return a < b;}, double)(5.1, 2.3); auto rbt3 = redBlackTree!("a > b", true, string)("hello", "world"); } //Range construction. pure unittest { import std.algorithm : equal; import std.range : iota; auto rbt = new RedBlackTree!(int, "a > b")(iota(5)); assert(equal(rbt[], [4, 3, 2, 1, 0])); } // construction with arrays pure unittest { import std.algorithm : equal; auto rbt = redBlackTree!"a > b"([0, 1, 2, 3, 4]); assert(equal(rbt[], [4, 3, 2, 1, 0])); auto rbt2 = redBlackTree!"a > b"(["a", "b"]); assert(equal(rbt2[], ["b", "a"])); auto rbt3 = redBlackTree!"a > b"([1, 2]); assert(equal(rbt3[], [2, 1])); auto rbt4 = redBlackTree([0, 1, 7, 5]); assert(equal(rbt4[], [0, 1, 5, 7])); auto rbt5 = redBlackTree(["hello", "world"]); assert(equal(rbt5[], ["hello", "world"])); auto rbt6 = redBlackTree!true([0, 1, 5, 7, 5]); assert(equal(rbt6[], [0, 1, 5, 5, 7])); auto rbt7 = redBlackTree!"a > b"([0, 1, 5, 7]); assert(equal(rbt7[], [7, 5, 1, 0])); auto rbt8 = redBlackTree!("a > b", true)([0.1, 1.3, 5.9, 7.2, 5.9]); assert(equal(rbt8[], [7.2, 5.9, 5.9, 1.3, 0.1])); } // convenience wrapper range construction pure unittest { import std.algorithm : equal; import std.range : chain, iota; auto rbt = redBlackTree(iota(3)); assert(equal(rbt[], [0, 1, 2])); auto rbt2 = redBlackTree!"a > b"(iota(2)); assert(equal(rbt2[], [1, 0])); auto rbt3 = redBlackTree(chain([0, 1], [7, 5])); assert(equal(rbt3[], [0, 1, 5, 7])); auto rbt4 = redBlackTree(chain(["hello"], ["world"])); assert(equal(rbt4[], ["hello", "world"])); auto rbt5 = redBlackTree!true(chain([0, 1], [5, 7, 5])); assert(equal(rbt5[], [0, 1, 5, 5, 7])); auto rbt6 = redBlackTree!("a > b", true)(chain([0.1, 1.3], [5.9, 7.2, 5.9])); assert(equal(rbt6[], [7.2, 5.9, 5.9, 1.3, 0.1])); } pure unittest { import std.array : array; auto rt1 = redBlackTree(5, 4, 3, 2, 1); assert(rt1.length == 5); assert(array(rt1[]) == [1, 2, 3, 4, 5]); auto rt2 = redBlackTree!"a > b"(1.1, 2.1); assert(rt2.length == 2); assert(array(rt2[]) == [2.1, 1.1]); auto rt3 = redBlackTree!true(5, 5, 4); assert(rt3.length == 3); assert(array(rt3[]) == [4, 5, 5]); auto rt4 = redBlackTree!string("hello", "hello"); assert(rt4.length == 1); assert(array(rt4[]) == ["hello"]); } unittest { import std.conv : to; auto rt1 = redBlackTree!string(); assert(rt1.to!string == "RedBlackTree([])"); auto rt2 = redBlackTree!string("hello"); assert(rt2.to!string == "RedBlackTree([\"hello\"])"); auto rt3 = redBlackTree!string("hello", "world", "!"); assert(rt3.to!string == "RedBlackTree([\"!\", \"hello\", \"world\"])"); // type deduction can be done automatically auto rt4 = redBlackTree(["hello"]); assert(rt4.to!string == "RedBlackTree([\"hello\"])"); } //constness checks unittest { const rt1 = redBlackTree(5,4,3,2,1); static assert(is(typeof(rt1.length))); static assert(is(typeof(5 in rt1))); static assert(is(typeof(rt1.upperBound(3).front) == const(int))); import std.algorithm : equal; assert(rt1.upperBound(3).equal([4, 5])); assert(rt1.lowerBound(3).equal([1, 2])); assert(rt1.equalRange(3).equal([3])); assert(rt1[].equal([1, 2, 3, 4, 5])); } //immutable checks unittest { immutable rt1 = redBlackTree(5,4,3,2,1); static assert(is(typeof(rt1.length))); static assert(is(typeof(rt1.upperBound(3).front) == immutable(int))); import std.algorithm : equal; assert(rt1.upperBound(2).equal([3, 4, 5])); } // issue 15941 unittest { class C {} RedBlackTree!(C, "cast(void*)a < cast(void*)b") tree; } ldc-1.1.0-beta3-src/runtime/phobos/std/file.d0000664000175000017500000034111112776215007016773 0ustar kaikai// Written in the D programming language. /** Utilities for manipulating files and scanning directories. Functions in this module handle files as a unit, e.g., read or write one _file at a time. For opening files and manipulating them via handles refer to module $(LINK2 std_stdio.html,$(D std.stdio)). Macros: WIKI = Phobos/StdFile Copyright: Copyright Digital Mars 2007 - 2011. See_Also: The $(WEB ddili.org/ders/d.en/files.html, official tutorial) for an introduction to working with files in D, module $(LINK2 std_stdio.html,$(D std.stdio)) for opening files and manipulating them via handles, and module $(LINK2 std_path.html,$(D std.path)) for manipulating path strings. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei Alexandrescu), Jonathan M Davis Source: $(PHOBOSSRC std/_file.d) */ module std.file; import core.stdc.stdlib, core.stdc.string, core.stdc.errno; import std.conv; import std.datetime; import std.exception; import std.meta; import std.path; import std.range.primitives; import std.traits; import std.typecons; import std.internal.cstring; version (Windows) { import core.sys.windows.windows, std.windows.syserror; } else version (Posix) { import core.sys.posix.dirent, core.sys.posix.fcntl, core.sys.posix.sys.stat, core.sys.posix.sys.time, core.sys.posix.unistd, core.sys.posix.utime; } else static assert(false, "Module " ~ .stringof ~ " not implemented for this OS."); // Character type used for operating system filesystem APIs version (Windows) { private alias FSChar = wchar; } else version (Posix) { private alias FSChar = char; } else static assert(0); package @property string deleteme() @safe { import std.process : thisProcessID; static _deleteme = "deleteme.dmd.unittest.pid"; static _first = true; if(_first) { _deleteme = buildPath(tempDir(), _deleteme) ~ to!string(thisProcessID); _first = false; } return _deleteme; } version (unittest) private struct TestAliasedString { string get() @safe @nogc pure nothrow { return _s; } alias get this; @disable this(this); string _s; } version(Android) { package enum system_directory = "/system/etc"; package enum system_file = "/system/etc/hosts"; } else version(Posix) { package enum system_directory = "/usr/include"; package enum system_file = "/usr/include/assert.h"; } /++ Exception thrown for file I/O errors. +/ class FileException : Exception { /++ OS error code. +/ immutable uint errno; /++ Constructor which takes an error message. Params: name = Name of file for which the error occurred. msg = Message describing the error. file = The file where the error occurred. line = The line where the error occurred. +/ this(in char[] name, in char[] msg, string file = __FILE__, size_t line = __LINE__) @safe pure { if(msg.empty) super(name.idup, file, line); else super(text(name, ": ", msg), file, line); errno = 0; } /++ Constructor which takes the error number ($(LUCKY GetLastError) in Windows, $(D_PARAM errno) in Posix). Params: name = Name of file for which the error occurred. errno = The error number. file = The file where the error occurred. Defaults to $(D __FILE__). line = The line where the error occurred. Defaults to $(D __LINE__). +/ version(Windows) this(in char[] name, uint errno = .GetLastError(), string file = __FILE__, size_t line = __LINE__) @safe { this(name, sysErrorString(errno), file, line); this.errno = errno; } else version(Posix) this(in char[] name, uint errno = .errno, string file = __FILE__, size_t line = __LINE__) @trusted { auto s = strerror(errno); this(name, to!string(s), file, line); this.errno = errno; } } private T cenforce(T)(T condition, lazy const(char)[] name, string file = __FILE__, size_t line = __LINE__) { if (condition) return condition; version (Windows) { throw new FileException(name, .GetLastError(), file, line); } else version (Posix) { throw new FileException(name, .errno, file, line); } } version (Windows) @trusted private T cenforce(T)(T condition, const(char)[] name, const(FSChar)* namez, string file = __FILE__, size_t line = __LINE__) { if (condition) return condition; if (!name) { import core.stdc.wchar_ : wcslen; import std.conv : to; auto len = wcslen(namez); name = to!string(namez[0 .. len]); } throw new FileException(name, .GetLastError(), file, line); } version (Posix) @trusted private T cenforce(T)(T condition, const(char)[] name, const(FSChar)* namez, string file = __FILE__, size_t line = __LINE__) { if (condition) return condition; if (!name) { import core.stdc.string : strlen; auto len = strlen(namez); name = namez[0 .. len].idup; } throw new FileException(name, .errno, file, line); } /* ********************************** * Basic File operations. */ /******************************************** Read entire contents of file $(D name) and returns it as an untyped array. If the file size is larger than $(D upTo), only $(D upTo) bytes are read. Params: name = string or range of characters representing the file _name upTo = if present, the maximum number of bytes to read Returns: Untyped array of bytes _read. Throws: $(LREF FileException) on error. */ void[] read(R)(R name, size_t upTo = size_t.max) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) return readImpl(name, name.tempCString!FSChar(), upTo); else return readImpl(null, name.tempCString!FSChar(), upTo); } /// @safe unittest { import std.utf : byChar; scope(exit) { assert(exists(deleteme)); remove(deleteme); } write(deleteme, "1234"); // deleteme is the name of a temporary file assert(read(deleteme, 2) == "12"); assert(read(deleteme.byChar) == "1234"); assert((cast(ubyte[])read(deleteme)).length == 4); } void[] read(R)(auto ref R name, size_t upTo = size_t.max) if (isConvertibleToString!R) { return read!(StringTypeOf!R)(name, upTo); } unittest { static assert(__traits(compiles, read(TestAliasedString(null)))); } version (Posix) private void[] readImpl(const(char)[] name, const(FSChar)* namez, size_t upTo = size_t.max) @trusted { import std.algorithm : min; import std.array : uninitializedArray; import core.memory : GC; // A few internal configuration parameters { enum size_t minInitialAlloc = 1024 * 4, maxInitialAlloc = size_t.max / 2, sizeIncrement = 1024 * 16, maxSlackMemoryAllowed = 1024; // } immutable fd = core.sys.posix.fcntl.open(namez, core.sys.posix.fcntl.O_RDONLY); cenforce(fd != -1, name); scope(exit) core.sys.posix.unistd.close(fd); stat_t statbuf = void; cenforce(fstat(fd, &statbuf) == 0, name, namez); immutable initialAlloc = to!size_t(statbuf.st_size ? min(statbuf.st_size + 1, maxInitialAlloc) : minInitialAlloc); void[] result = uninitializedArray!(ubyte[])(initialAlloc); scope(failure) delete result; size_t size = 0; for (;;) { immutable actual = core.sys.posix.unistd.read(fd, result.ptr + size, min(result.length, upTo) - size); cenforce(actual != -1, name, namez); if (actual == 0) break; size += actual; if (size < result.length) continue; immutable newAlloc = size + sizeIncrement; result = GC.realloc(result.ptr, newAlloc, GC.BlkAttr.NO_SCAN)[0 .. newAlloc]; } return result.length - size >= maxSlackMemoryAllowed ? GC.realloc(result.ptr, size, GC.BlkAttr.NO_SCAN)[0 .. size] : result[0 .. size]; } version (Windows) private void[] readImpl(const(char)[] name, const(FSChar)* namez, size_t upTo = size_t.max) @safe { import std.algorithm : min; import std.array : uninitializedArray; static trustedCreateFileW(const(wchar)* namez, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) @trusted { return CreateFileW(namez, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } static trustedCloseHandle(HANDLE hObject) @trusted { return CloseHandle(hObject); } static trustedGetFileSize(HANDLE hFile, out ulong fileSize) @trusted { DWORD sizeHigh; DWORD sizeLow = GetFileSize(hFile, &sizeHigh); bool result = sizeLow != INVALID_FILE_SIZE; if (result) fileSize = makeUlong(sizeLow, sizeHigh); return result; } static trustedReadFile(HANDLE hFile, void *lpBuffer, ulong nNumberOfBytesToRead) @trusted { // Read by chunks of size < 4GB (Windows API limit) ulong totalNumRead = 0; while (totalNumRead != nNumberOfBytesToRead) { uint chunkSize = min(nNumberOfBytesToRead - totalNumRead, 0xffff_0000); DWORD numRead = void; auto result = ReadFile(hFile, lpBuffer + totalNumRead, chunkSize, &numRead, null); if (result == 0 || numRead != chunkSize) return false; totalNumRead += chunkSize; } return true; } alias defaults = AliasSeq!(GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, (SECURITY_ATTRIBUTES*).init, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init); auto h = trustedCreateFileW(namez, defaults); cenforce(h != INVALID_HANDLE_VALUE, name, namez); scope(exit) cenforce(trustedCloseHandle(h), name, namez); ulong fileSize = void; cenforce(trustedGetFileSize(h, fileSize), name, namez); size_t size = min(upTo, fileSize); auto buf = uninitializedArray!(ubyte[])(size); scope(failure) delete buf; cenforce(trustedReadFile(h, buf.ptr, size), name, namez); return buf[0 .. size]; } version (linux) @safe unittest { // A file with "zero" length that doesn't have 0 length at all auto s = std.file.readText("/proc/sys/kernel/osrelease"); assert(s.length > 0); //writefln("'%s'", s); } @safe unittest { scope(exit) if (exists(deleteme)) remove(deleteme); import std.stdio; auto f = File(deleteme, "w"); f.write("abcd"); f.flush(); assert(read(deleteme) == "abcd"); } /******************************************** Read and validates (using $(XREF utf, validate)) a text file. $(D S) can be a type of array of characters of any width and constancy. No width conversion is performed; if the width of the characters in file $(D name) is different from the width of elements of $(D S), validation will fail. Params: name = string or range of characters representing the file _name Returns: Array of characters read. Throws: $(D FileException) on file error, $(D UTFException) on UTF decoding error. */ S readText(S = string, R)(R name) if (isSomeString!S && (isInputRange!R && isSomeChar!(ElementEncodingType!R) || isSomeString!R) && !isConvertibleToString!R) { import std.utf : validate; static auto trustedCast(void[] buf) @trusted { return cast(S)buf; } auto result = trustedCast(read(name)); validate(result); return result; } /// @safe unittest { import std.string; write(deleteme, "abc\n"); // deleteme is the name of a temporary file scope(exit) { assert(exists(deleteme)); remove(deleteme); } enforce(chomp(readText(deleteme)) == "abc"); } S readText(S = string, R)(auto ref R name) if (isConvertibleToString!R) { return readText!(S, StringTypeOf!R)(name); } unittest { static assert(__traits(compiles, readText(TestAliasedString(null)))); } /********************************************* Write $(D buffer) to file $(D name). Params: name = string or range of characters representing the file _name buffer = data to be written to file Throws: $(D FileException) on error. */ void write(R)(R name, const void[] buffer) if ((isInputRange!R && isSomeChar!(ElementEncodingType!R) || isSomeString!R) && !isConvertibleToString!R) { static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) writeImpl(name, name.tempCString!FSChar(), buffer, false); else writeImpl(null, name.tempCString!FSChar(), buffer, false); } /// unittest { scope(exit) { assert(exists(deleteme)); remove(deleteme); } int[] a = [ 0, 1, 1, 2, 3, 5, 8 ]; write(deleteme, a); // deleteme is the name of a temporary file assert(cast(int[]) read(deleteme) == a); } void write(R)(auto ref R name, const void[] buffer) if (isConvertibleToString!R) { write!(StringTypeOf!R)(name, buffer); } unittest { static assert(__traits(compiles, write(TestAliasedString(null), null))); } /********************************************* Appends $(D buffer) to file $(D name). Params: name = string or range of characters representing the file _name buffer = data to be appended to file Throws: $(D FileException) on error. */ void append(R)(R name, const void[] buffer) if ((isInputRange!R && isSomeChar!(ElementEncodingType!R) || isSomeString!R) && !isConvertibleToString!R) { static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) writeImpl(name, name.tempCString!FSChar(), buffer, true); else writeImpl(null, name.tempCString!FSChar(), buffer, true); } /// unittest { scope(exit) { assert(exists(deleteme)); remove(deleteme); } int[] a = [ 0, 1, 1, 2, 3, 5, 8 ]; write(deleteme, a); // deleteme is the name of a temporary file int[] b = [ 13, 21 ]; append(deleteme, b); assert(cast(int[]) read(deleteme) == a ~ b); } void append(R)(auto ref R name, const void[] buffer) if (isConvertibleToString!R) { append!(StringTypeOf!R)(name, buffer); } unittest { static assert(__traits(compiles, append(TestAliasedString("foo"), [0, 1, 2, 3]))); } // Posix implementation helper for write and append version(Posix) private void writeImpl(const(char)[] name, const(FSChar)* namez, in void[] buffer, bool append) @trusted { // append or write auto mode = append ? O_CREAT | O_WRONLY | O_APPEND : O_CREAT | O_WRONLY | O_TRUNC; immutable fd = core.sys.posix.fcntl.open(namez, mode, octal!666); cenforce(fd != -1, name, namez); { scope(failure) core.sys.posix.unistd.close(fd); immutable size = buffer.length; cenforce( core.sys.posix.unistd.write(fd, buffer.ptr, size) == size, name, namez); } cenforce(core.sys.posix.unistd.close(fd) == 0, name, namez); } // Windows implementation helper for write and append version(Windows) private void writeImpl(const(char)[] name, const(FSChar)* namez, in void[] buffer, bool append) @trusted { if (append) { alias defaults = AliasSeq!(GENERIC_WRITE, 0, null, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init); auto h = CreateFileW(namez, defaults); cenforce(h != INVALID_HANDLE_VALUE, name, namez); scope(exit) cenforce(CloseHandle(h), name, namez); DWORD numwritten; cenforce(SetFilePointer(h, 0, null, FILE_END) != INVALID_SET_FILE_POINTER && WriteFile(h,buffer.ptr,to!DWORD(buffer.length),&numwritten,null) != 0 && buffer.length == numwritten, name, namez); } else // write { alias defaults = AliasSeq!(GENERIC_WRITE, 0, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init); auto h = CreateFileW(namez, defaults); cenforce(h != INVALID_HANDLE_VALUE, name, namez); scope(exit) cenforce(CloseHandle(h), name, namez); DWORD numwritten; cenforce(WriteFile(h, buffer.ptr, to!DWORD(buffer.length), &numwritten, null) != 0 && buffer.length == numwritten, name, namez); } } /*************************************************** * Rename file $(D from) to $(D to). * If the target file exists, it is overwritten. * Params: * from = string or range of characters representing the existing file name * to = string or range of characters representing the target file name * Throws: $(D FileException) on error. */ void rename(RF, RT)(RF from, RT to) if ((isInputRange!RF && isSomeChar!(ElementEncodingType!RF) || isSomeString!RF) && !isConvertibleToString!RF && (isInputRange!RT && isSomeChar!(ElementEncodingType!RT) || isSomeString!RT) && !isConvertibleToString!RT) { // Place outside of @trusted block auto fromz = from.tempCString!FSChar(); auto toz = to.tempCString!FSChar(); static if (isNarrowString!RF && is(Unqual!(ElementEncodingType!RF) == char)) alias f = from; else enum string f = null; static if (isNarrowString!RT && is(Unqual!(ElementEncodingType!RT) == char)) alias t = to; else enum string t = null; renameImpl(f, t, fromz, toz); } void rename(RF, RT)(auto ref RF from, auto ref RT to) if (isConvertibleToString!RF || isConvertibleToString!RT) { import std.meta : staticMap; alias Types = staticMap!(convertToString, RF, RT); rename!Types(from, to); } unittest { static assert(__traits(compiles, rename(TestAliasedString(null), TestAliasedString(null)))); static assert(__traits(compiles, rename("", TestAliasedString(null)))); static assert(__traits(compiles, rename(TestAliasedString(null), ""))); import std.utf : byChar; static assert(__traits(compiles, rename(TestAliasedString(null), "".byChar))); } private void renameImpl(const(char)[] f, const(char)[] t, const(FSChar)* fromz, const(FSChar)* toz) @trusted { version(Windows) { auto result = MoveFileExW(fromz, toz, MOVEFILE_REPLACE_EXISTING); if (!result) { import core.stdc.wchar_ : wcslen; import std.conv : to; if (!f) f = to!(typeof(f))(fromz[0 .. wcslen(fromz)]); if (!t) t = to!(typeof(t))(toz[0 .. wcslen(toz)]); enforce(false, new FileException( text("Attempting to rename file ", f, " to ", t))); } } else version(Posix) { import core.stdc.stdio; cenforce(core.stdc.stdio.rename(fromz, toz) == 0, t, toz); } } @safe unittest { import std.utf : byWchar; auto t1 = deleteme, t2 = deleteme~"2"; scope(exit) foreach (t; [t1, t2]) if (t.exists) t.remove(); write(t1, "1"); rename(t1, t2); assert(readText(t2) == "1"); write(t1, "2"); rename(t1, t2.byWchar); assert(readText(t2) == "2"); } /*************************************************** Delete file $(D name). Params: name = string or range of characters representing the file name Throws: $(D FileException) on error. */ void remove(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) removeImpl(name, name.tempCString!FSChar()); else removeImpl(null, name.tempCString!FSChar()); } void remove(R)(auto ref R name) if (isConvertibleToString!R) { remove!(StringTypeOf!R)(name); } unittest { static assert(__traits(compiles, remove(TestAliasedString("foo")))); } private void removeImpl(const(char)[] name, const(FSChar)* namez) @trusted { version(Windows) { cenforce(DeleteFileW(namez), name, namez); } else version(Posix) { import core.stdc.stdio; if (!name) { import core.stdc.string : strlen; auto len = strlen(namez); name = namez[0 .. len]; } cenforce(core.stdc.stdio.remove(namez) == 0, "Failed to remove file " ~ name); } } version(Windows) private WIN32_FILE_ATTRIBUTE_DATA getFileAttributesWin(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R)) { auto namez = name.tempCString!FSChar(); WIN32_FILE_ATTRIBUTE_DATA fad = void; static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) { static void getFA(const(char)[] name, const(FSChar)* namez, out WIN32_FILE_ATTRIBUTE_DATA fad) @trusted { enforce(GetFileAttributesExW(namez, GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, &fad), new FileException(name.idup)); } getFA(name, namez, fad); } else { static void getFA(const(FSChar)* namez, out WIN32_FILE_ATTRIBUTE_DATA fad) @trusted { import core.stdc.wchar_ : wcslen; import std.conv : to; enforce(GetFileAttributesExW(namez, GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, &fad), new FileException(namez[0 .. wcslen(namez)].to!string)); } getFA(namez, fad); } return fad; } version(Windows) private ulong makeUlong(DWORD dwLow, DWORD dwHigh) @safe pure nothrow @nogc { ULARGE_INTEGER li; li.LowPart = dwLow; li.HighPart = dwHigh; return li.QuadPart; } /*************************************************** Get size of file $(D name) in bytes. Params: name = string or range of characters representing the file name Throws: $(D FileException) on error (e.g., file not found). */ ulong getSize(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version(Windows) { with (getFileAttributesWin(name)) return makeUlong(nFileSizeLow, nFileSizeHigh); } else version(Posix) { auto namez = name.tempCString(); static trustedStat(const(FSChar)* namez, out stat_t buf) @trusted { return stat(namez, &buf); } static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; stat_t statbuf = void; cenforce(trustedStat(namez, statbuf) == 0, names, namez); return statbuf.st_size; } } ulong getSize(R)(auto ref R name) if (isConvertibleToString!R) { return getSize!(StringTypeOf!R)(name); } unittest { static assert(__traits(compiles, getSize(TestAliasedString("foo")))); } @safe unittest { // create a file of size 1 write(deleteme, "a"); scope(exit) { assert(exists(deleteme)); remove(deleteme); } assert(getSize(deleteme) == 1); // create a file of size 3 write(deleteme, "abc"); import std.utf : byChar; assert(getSize(deleteme.byChar) == 3); } /++ Get the access and modified times of file or folder $(D name). Params: name = File/Folder name to get times for. accessTime = Time the file/folder was last accessed. modificationTime = Time the file/folder was last modified. Throws: $(D FileException) on error. +/ void getTimes(R)(R name, out SysTime accessTime, out SysTime modificationTime) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version(Windows) { with (getFileAttributesWin(name)) { accessTime = FILETIMEToSysTime(&ftLastAccessTime); modificationTime = FILETIMEToSysTime(&ftLastWriteTime); } } else version(Posix) { auto namez = name.tempCString(); static auto trustedStat(const(FSChar)* namez, ref stat_t buf) @trusted { return stat(namez, &buf); } stat_t statbuf = void; static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; cenforce(trustedStat(namez, statbuf) == 0, names, namez); accessTime = SysTime(unixTimeToStdTime(statbuf.st_atime)); modificationTime = SysTime(unixTimeToStdTime(statbuf.st_mtime)); } } void getTimes(R)(auto ref R name, out SysTime accessTime, out SysTime modificationTime) if (isConvertibleToString!R) { return getTimes!(StringTypeOf!R)(name, accessTime, modificationTime); } unittest { SysTime atime, mtime; static assert(__traits(compiles, getTimes(TestAliasedString("foo"), atime, mtime))); } unittest { import std.stdio : writefln; auto currTime = Clock.currTime(); write(deleteme, "a"); scope(exit) { assert(exists(deleteme)); remove(deleteme); } SysTime accessTime1 = void; SysTime modificationTime1 = void; getTimes(deleteme, accessTime1, modificationTime1); enum leeway = dur!"seconds"(5); { auto diffa = accessTime1 - currTime; auto diffm = modificationTime1 - currTime; scope(failure) writefln("[%s] [%s] [%s] [%s] [%s]", accessTime1, modificationTime1, currTime, diffa, diffm); assert(abs(diffa) <= leeway); assert(abs(diffm) <= leeway); } version(fullFileTests) { import core.thread; enum sleepTime = dur!"seconds"(2); Thread.sleep(sleepTime); currTime = Clock.currTime(); write(deleteme, "b"); SysTime accessTime2 = void; SysTime modificationTime2 = void; getTimes(deleteme, accessTime2, modificationTime2); { auto diffa = accessTime2 - currTime; auto diffm = modificationTime2 - currTime; scope(failure) writefln("[%s] [%s] [%s] [%s] [%s]", accessTime2, modificationTime2, currTime, diffa, diffm); //There is no guarantee that the access time will be updated. assert(abs(diffa) <= leeway + sleepTime); assert(abs(diffm) <= leeway); } assert(accessTime1 <= accessTime2); assert(modificationTime1 <= modificationTime2); } } version(StdDdoc) { /++ $(BLUE This function is Windows-Only.) Get creation/access/modified times of file $(D name). This is the same as $(D getTimes) except that it also gives you the file creation time - which isn't possible on Posix systems. Params: name = File name to get times for. fileCreationTime = Time the file was created. fileAccessTime = Time the file was last accessed. fileModificationTime = Time the file was last modified. Throws: $(D FileException) on error. +/ void getTimesWin(R)(R name, out SysTime fileCreationTime, out SysTime fileAccessTime, out SysTime fileModificationTime) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R); } else version(Windows) { void getTimesWin(R)(R name, out SysTime fileCreationTime, out SysTime fileAccessTime, out SysTime fileModificationTime) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { with (getFileAttributesWin(name)) { fileCreationTime = std.datetime.FILETIMEToSysTime(&ftCreationTime); fileAccessTime = std.datetime.FILETIMEToSysTime(&ftLastAccessTime); fileModificationTime = std.datetime.FILETIMEToSysTime(&ftLastWriteTime); } } void getTimesWin(R)(auto ref R name, out SysTime fileCreationTime, out SysTime fileAccessTime, out SysTime fileModificationTime) if (isConvertibleToString!R) { getTimesWin!(StringTypeOf!R)(name, fileCreationTime, fileAccessTime, fileModificationTime); } } version(Windows) unittest { import std.stdio : writefln; auto currTime = Clock.currTime(); write(deleteme, "a"); scope(exit) { assert(exists(deleteme)); remove(deleteme); } SysTime creationTime1 = void; SysTime accessTime1 = void; SysTime modificationTime1 = void; getTimesWin(deleteme, creationTime1, accessTime1, modificationTime1); enum leeway = dur!"seconds"(5); { auto diffc = creationTime1 - currTime; auto diffa = accessTime1 - currTime; auto diffm = modificationTime1 - currTime; scope(failure) { writefln("[%s] [%s] [%s] [%s] [%s] [%s] [%s]", creationTime1, accessTime1, modificationTime1, currTime, diffc, diffa, diffm); } // Deleting and recreating a file doesn't seem to always reset the "file creation time" //assert(abs(diffc) <= leeway); assert(abs(diffa) <= leeway); assert(abs(diffm) <= leeway); } version(fullFileTests) { import core.thread; Thread.sleep(dur!"seconds"(2)); currTime = Clock.currTime(); write(deleteme, "b"); SysTime creationTime2 = void; SysTime accessTime2 = void; SysTime modificationTime2 = void; getTimesWin(deleteme, creationTime2, accessTime2, modificationTime2); { auto diffa = accessTime2 - currTime; auto diffm = modificationTime2 - currTime; scope(failure) { writefln("[%s] [%s] [%s] [%s] [%s]", accessTime2, modificationTime2, currTime, diffa, diffm); } assert(abs(diffa) <= leeway); assert(abs(diffm) <= leeway); } assert(creationTime1 == creationTime2); assert(accessTime1 <= accessTime2); assert(modificationTime1 <= modificationTime2); } { SysTime ctime, atime, mtime; static assert(__traits(compiles, getTimesWin(TestAliasedString("foo"), ctime, atime, mtime))); } } /++ Set access/modified times of file or folder $(D name). Params: name = File/Folder name to get times for. accessTime = Time the file/folder was last accessed. modificationTime = Time the file/folder was last modified. Throws: $(D FileException) on error. +/ void setTimes(R)(R name, SysTime accessTime, SysTime modificationTime) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version(Windows) { auto namez = name.tempCString!FSChar(); static auto trustedCreateFileW(const(FSChar)* namez, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) @trusted { return CreateFileW(namez, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } static auto trustedCloseHandle(HANDLE hObject) @trusted { return CloseHandle(hObject); } static auto trustedSetFileTime(HANDLE hFile, in FILETIME *lpCreationTime, in ref FILETIME lpLastAccessTime, in ref FILETIME lpLastWriteTime) @trusted { return SetFileTime(hFile, lpCreationTime, &lpLastAccessTime, &lpLastWriteTime); } const ta = SysTimeToFILETIME(accessTime); const tm = SysTimeToFILETIME(modificationTime); alias defaults = AliasSeq!(GENERIC_WRITE, 0, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY | FILE_FLAG_BACKUP_SEMANTICS, HANDLE.init); auto h = trustedCreateFileW(namez, defaults); static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; cenforce(h != INVALID_HANDLE_VALUE, names, namez); scope(exit) cenforce(trustedCloseHandle(h), names, namez); cenforce(trustedSetFileTime(h, null, ta, tm), names, namez); } else version(Posix) { auto namez = name.tempCString!FSChar(); static auto trustedUtimes(const(FSChar)* namez, const ref timeval[2] times) @trusted { return utimes(namez, times); } timeval[2] t = void; t[0] = accessTime.toTimeVal(); t[1] = modificationTime.toTimeVal(); static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; cenforce(trustedUtimes(namez, t) == 0, names, namez); } } void setTimes(R)(auto ref R name, SysTime accessTime, SysTime modificationTime) if (isConvertibleToString!R) { setTimes!(StringTypeOf!R)(name, accessTime, modificationTime); } @safe unittest { static assert(__traits(compiles, setTimes(TestAliasedString("foo"), SysTime.init, SysTime.init))); } unittest { import std.stdio : File; string newdir = deleteme ~ r".dir"; string dir = newdir ~ r"/a/b/c"; string file = dir ~ "/file"; if (!exists(dir)) mkdirRecurse(dir); { auto f = File(file, "w"); } foreach (path; [file, dir]) // test file and dir { SysTime atime = SysTime(DateTime(2010, 10, 4, 0, 0, 30)); SysTime mtime = SysTime(DateTime(2011, 10, 4, 0, 0, 30)); setTimes(path, atime, mtime); SysTime atime_res; SysTime mtime_res; getTimes(path, atime_res, mtime_res); assert(atime == atime_res); assert(mtime == mtime_res); } rmdirRecurse(newdir); } /++ Returns the time that the given file was last modified. Throws: $(D FileException) if the given file does not exist. +/ SysTime timeLastModified(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version(Windows) { SysTime dummy; SysTime ftm; getTimesWin(name, dummy, dummy, ftm); return ftm; } else version(Posix) { auto namez = name.tempCString!FSChar(); static auto trustedStat(const(FSChar)* namez, ref stat_t buf) @trusted { return stat(namez, &buf); } stat_t statbuf = void; static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; cenforce(trustedStat(namez, statbuf) == 0, names, namez); return SysTime(unixTimeToStdTime(statbuf.st_mtime)); } } SysTime timeLastModified(R)(auto ref R name) if (isConvertibleToString!R) { return timeLastModified!(StringTypeOf!R)(name); } unittest { static assert(__traits(compiles, timeLastModified(TestAliasedString("foo")))); } /++ Returns the time that the given file was last modified. If the file does not exist, returns $(D returnIfMissing). A frequent usage pattern occurs in build automation tools such as $(WEB gnu.org/software/make, make) or $(WEB en.wikipedia.org/wiki/Apache_Ant, ant). To check whether file $(D target) must be rebuilt from file $(D source) (i.e., $(D target) is older than $(D source) or does not exist), use the comparison below. The code throws a $(D FileException) if $(D source) does not exist (as it should). On the other hand, the $(D SysTime.min) default makes a non-existing $(D target) seem infinitely old so the test correctly prompts building it. Params: name = The name of the file to get the modification time for. returnIfMissing = The time to return if the given file does not exist. Example: -------------------- if(timeLastModified(source) >= timeLastModified(target, SysTime.min)) { // must (re)build } else { // target is up-to-date } -------------------- +/ SysTime timeLastModified(R)(R name, SysTime returnIfMissing) if (isInputRange!R && isSomeChar!(ElementEncodingType!R)) { version(Windows) { if (!exists(name)) return returnIfMissing; SysTime dummy; SysTime ftm; getTimesWin(name, dummy, dummy, ftm); return ftm; } else version(Posix) { auto namez = name.tempCString!FSChar(); static auto trustedStat(const(FSChar)* namez, ref stat_t buf) @trusted { return stat(namez, &buf); } stat_t statbuf = void; return trustedStat(namez, statbuf) != 0 ? returnIfMissing : SysTime(unixTimeToStdTime(statbuf.st_mtime)); } } unittest { //std.process.system("echo a > deleteme") == 0 || assert(false); if(exists(deleteme)) remove(deleteme); write(deleteme, "a\n"); scope(exit) { assert(exists(deleteme)); remove(deleteme); } // assert(lastModified("deleteme") > // lastModified("this file does not exist", SysTime.min)); //assert(lastModified("deleteme") > lastModified(__FILE__)); } /** * Determine whether the given file (or directory) exists. * Params: * name = string or range of characters representing the file name * Returns: * true if the filename specified as input exists */ bool exists(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { return existsImpl(name.tempCString!FSChar()); } bool exists(R)(auto ref R name) if (isConvertibleToString!R) { return exists!(StringTypeOf!R)(name); } private bool existsImpl(const(FSChar)* namez) @trusted nothrow @nogc { version(Windows) { // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ // fileio/base/getfileattributes.asp return GetFileAttributesW(namez) != 0xFFFFFFFF; } else version(Posix) { /* The reason why we use stat (and not access) here is the quirky behavior of access for SUID programs: if we used access, a file may not appear to "exist", despite that the program would be able to open it just fine. The behavior in question is described as follows in the access man page: > The check is done using the calling process's real > UID and GID, rather than the effective IDs as is > done when actually attempting an operation (e.g., > open(2)) on the file. This allows set-user-ID > programs to easily determine the invoking user's > authority. While various operating systems provide eaccess or euidaccess functions, these are not part of POSIX - so it's safer to use stat instead. */ stat_t statbuf = void; return lstat(namez, &statbuf) == 0; } else static assert(0); } @safe unittest { assert(exists(".")); assert(!exists("this file does not exist")); write(deleteme, "a\n"); scope(exit) { assert(exists(deleteme)); remove(deleteme); } assert(exists(deleteme)); } /++ Returns the attributes of the given file. Note that the file attributes on Windows and Posix systems are completely different. On Windows, they're what is returned by $(WEB msdn.microsoft.com/en-us/library/aa364944(v=vs.85).aspx, GetFileAttributes), whereas on Posix systems, they're the $(LUCKY st_mode) value which is part of the $(D stat struct) gotten by calling the $(WEB en.wikipedia.org/wiki/Stat_%28Unix%29, $(D stat)) function. On Posix systems, if the given file is a symbolic link, then attributes are the attributes of the file pointed to by the symbolic link. Params: name = The file to get the attributes of. Throws: $(D FileException) on error. +/ uint getAttributes(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version(Windows) { auto namez = name.tempCString!FSChar(); static auto trustedGetFileAttributesW(const(FSChar)* namez) @trusted { return GetFileAttributesW(namez); } immutable result = trustedGetFileAttributesW(namez); static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; cenforce(result != INVALID_FILE_ATTRIBUTES, names, namez); return result; } else version(Posix) { auto namez = name.tempCString!FSChar(); static auto trustedStat(const(FSChar)* namez, ref stat_t buf) @trusted { return stat(namez, &buf); } stat_t statbuf = void; static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; cenforce(trustedStat(namez, statbuf) == 0, names, namez); return statbuf.st_mode; } } uint getAttributes(R)(auto ref R name) if (isConvertibleToString!R) { return getAttributes!(StringTypeOf!R)(name); } unittest { static assert(__traits(compiles, getAttributes(TestAliasedString(null)))); } /++ If the given file is a symbolic link, then this returns the attributes of the symbolic link itself rather than file that it points to. If the given file is $(I not) a symbolic link, then this function returns the same result as getAttributes. On Windows, getLinkAttributes is identical to getAttributes. It exists on Windows so that you don't have to special-case code for Windows when dealing with symbolic links. Params: name = The file to get the symbolic link attributes of. Returns: the attributes Throws: $(D FileException) on error. +/ uint getLinkAttributes(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version(Windows) { return getAttributes(name); } else version(Posix) { auto namez = name.tempCString!FSChar(); static auto trustedLstat(const(FSChar)* namez, ref stat_t buf) @trusted { return lstat(namez, &buf); } stat_t lstatbuf = void; static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; cenforce(trustedLstat(namez, lstatbuf) == 0, names, namez); return lstatbuf.st_mode; } } uint getLinkAttributes(R)(auto ref R name) if (isConvertibleToString!R) { return getLinkAttributes!(StringTypeOf!R)(name); } unittest { static assert(__traits(compiles, getLinkAttributes(TestAliasedString(null)))); } /++ Set the attributes of the given file. Params: name = the file name attributes = the attributes to set the file to Throws: $(D FileException) if the given file does not exist. +/ void setAttributes(R)(R name, uint attributes) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version (Windows) { auto namez = name.tempCString!FSChar(); static auto trustedSetFileAttributesW(const(FSChar)* namez, uint dwFileAttributes) @trusted { return SetFileAttributesW(namez, dwFileAttributes); } static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; cenforce(trustedSetFileAttributesW(namez, attributes), names, namez); } else version (Posix) { auto namez = name.tempCString!FSChar(); static auto trustedChmod(const(FSChar)* namez, mode_t mode) @trusted { return chmod(namez, mode); } assert(attributes <= mode_t.max); static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias names = name; else string names = null; cenforce(!trustedChmod(namez, cast(mode_t)attributes), names, namez); } } void setAttributes(R)(auto ref R name, uint attributes) if (isConvertibleToString!R) { return setAttributes!(StringTypeOf!R)(name, attributes); } unittest { static assert(__traits(compiles, setAttributes(TestAliasedString(null), 0))); } /++ Returns whether the given file is a directory. Params: name = The path to the file. Returns: true if the name specifies a directory Throws: $(D FileException) if the given file does not exist. Example: -------------------- assert(!"/etc/fonts/fonts.conf".isDir); assert("/usr/share/include".isDir); -------------------- +/ @property bool isDir(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version(Windows) { return (getAttributes(name) & FILE_ATTRIBUTE_DIRECTORY) != 0; } else version(Posix) { return (getAttributes(name) & S_IFMT) == S_IFDIR; } } @property bool isDir(R)(auto ref R name) if (isConvertibleToString!R) { return name.isDir!(StringTypeOf!R); } unittest { static assert(__traits(compiles, TestAliasedString(null).isDir)); } @safe unittest { version(Windows) { if("C:\\Program Files\\".exists) assert("C:\\Program Files\\".isDir); if("C:\\Windows\\system.ini".exists) assert(!"C:\\Windows\\system.ini".isDir); } else version(Posix) { if(system_directory.exists) assert(system_directory.isDir); if(system_file.exists) assert(!system_file.isDir); } } unittest { version(Windows) enum dir = "C:\\Program Files\\"; else version(Posix) enum dir = system_directory; if (dir.exists) { DirEntry de = DirEntry(dir); assert(de.isDir); assert(DirEntry(dir).isDir); } } /++ Returns whether the given file attributes are for a directory. Params: attributes = The file attributes. Returns: true if attibutes specifies a directory Example: -------------------- assert(!attrIsDir(getAttributes("/etc/fonts/fonts.conf"))); assert(!attrIsDir(getLinkAttributes("/etc/fonts/fonts.conf"))); -------------------- +/ bool attrIsDir(uint attributes) @safe pure nothrow @nogc { version(Windows) { return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } else version(Posix) { return (attributes & S_IFMT) == S_IFDIR; } } @safe unittest { version(Windows) { if("C:\\Program Files\\".exists) { assert(attrIsDir(getAttributes("C:\\Program Files\\"))); assert(attrIsDir(getLinkAttributes("C:\\Program Files\\"))); } if("C:\\Windows\\system.ini".exists) { assert(!attrIsDir(getAttributes("C:\\Windows\\system.ini"))); assert(!attrIsDir(getLinkAttributes("C:\\Windows\\system.ini"))); } } else version(Posix) { if(system_directory.exists) { assert(attrIsDir(getAttributes(system_directory))); assert(attrIsDir(getLinkAttributes(system_directory))); } if(system_file.exists) { assert(!attrIsDir(getAttributes(system_file))); assert(!attrIsDir(getLinkAttributes(system_file))); } } } /++ Returns whether the given file (or directory) is a file. On Windows, if a file is not a directory, then it's a file. So, either $(D isFile) or $(D isDir) will return true for any given file. On Posix systems, if $(D isFile) is $(D true), that indicates that the file is a regular file (e.g. not a block not device). So, on Posix systems, it's possible for both $(D isFile) and $(D isDir) to be $(D false) for a particular file (in which case, it's a special file). You can use $(D getAttributes) to get the attributes to figure out what type of special it is, or you can use $(D DirEntry) to get at its $(D statBuf), which is the result from $(D stat). In either case, see the man page for $(D stat) for more information. Params: name = The path to the file. Returns: true if name specifies a file Throws: $(D FileException) if the given file does not exist. Example: -------------------- assert("/etc/fonts/fonts.conf".isFile); assert(!"/usr/share/include".isFile); -------------------- +/ @property bool isFile(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version(Windows) return !name.isDir; else version(Posix) return (getAttributes(name) & S_IFMT) == S_IFREG; } @property bool isFile(R)(auto ref R name) if (isConvertibleToString!R) { return name.isFile!(StringTypeOf!R); } unittest { static assert(__traits(compiles, TestAliasedString(null).isFile)); } @safe unittest { version(Windows) { if("C:\\Program Files\\".exists) assert(!"C:\\Program Files\\".isFile); if("C:\\Windows\\system.ini".exists) assert("C:\\Windows\\system.ini".isFile); } else version(Posix) { if(system_directory.exists) assert(!system_directory.isFile); if(system_file.exists) assert(system_file.isFile); } } /++ Returns whether the given file attributes are for a file. On Windows, if a file is not a directory, it's a file. So, either $(D attrIsFile) or $(D attrIsDir) will return $(D true) for the attributes of any given file. On Posix systems, if $(D attrIsFile) is $(D true), that indicates that the file is a regular file (e.g. not a block not device). So, on Posix systems, it's possible for both $(D attrIsFile) and $(D attrIsDir) to be $(D false) for a particular file (in which case, it's a special file). If a file is a special file, you can use the attributes to check what type of special file it is (see the man page for $(D stat) for more information). Params: attributes = The file attributes. Returns: true if the given file attributes are for a file Example: -------------------- assert(attrIsFile(getAttributes("/etc/fonts/fonts.conf"))); assert(attrIsFile(getLinkAttributes("/etc/fonts/fonts.conf"))); -------------------- +/ bool attrIsFile(uint attributes) @safe pure nothrow @nogc { version(Windows) { return (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0; } else version(Posix) { return (attributes & S_IFMT) == S_IFREG; } } @safe unittest { version(Windows) { if("C:\\Program Files\\".exists) { assert(!attrIsFile(getAttributes("C:\\Program Files\\"))); assert(!attrIsFile(getLinkAttributes("C:\\Program Files\\"))); } if("C:\\Windows\\system.ini".exists) { assert(attrIsFile(getAttributes("C:\\Windows\\system.ini"))); assert(attrIsFile(getLinkAttributes("C:\\Windows\\system.ini"))); } } else version(Posix) { if(system_directory.exists) { assert(!attrIsFile(getAttributes(system_directory))); assert(!attrIsFile(getLinkAttributes(system_directory))); } if(system_file.exists) { assert(attrIsFile(getAttributes(system_file))); assert(attrIsFile(getLinkAttributes(system_file))); } } } /++ Returns whether the given file is a symbolic link. On Windows, returns $(D true) when the file is either a symbolic link or a junction point. Params: name = The path to the file. Returns: true if name is a symbolic link Throws: $(D FileException) if the given file does not exist. +/ @property bool isSymlink(R)(R name) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { version(Windows) return (getAttributes(name) & FILE_ATTRIBUTE_REPARSE_POINT) != 0; else version(Posix) return (getLinkAttributes(name) & S_IFMT) == S_IFLNK; } @property bool isSymlink(R)(auto ref R name) if (isConvertibleToString!R) { return name.isSymlink!(StringTypeOf!R); } unittest { static assert(__traits(compiles, TestAliasedString(null).isSymlink)); } unittest { version(Windows) { if("C:\\Program Files\\".exists) assert(!"C:\\Program Files\\".isSymlink); if("C:\\Users\\".exists && "C:\\Documents and Settings\\".exists) assert("C:\\Documents and Settings\\".isSymlink); enum fakeSymFile = "C:\\Windows\\system.ini"; if(fakeSymFile.exists) { assert(!fakeSymFile.isSymlink); assert(!fakeSymFile.isSymlink); assert(!attrIsSymlink(getAttributes(fakeSymFile))); assert(!attrIsSymlink(getLinkAttributes(fakeSymFile))); assert(attrIsFile(getAttributes(fakeSymFile))); assert(attrIsFile(getLinkAttributes(fakeSymFile))); assert(!attrIsDir(getAttributes(fakeSymFile))); assert(!attrIsDir(getLinkAttributes(fakeSymFile))); assert(getAttributes(fakeSymFile) == getLinkAttributes(fakeSymFile)); } } else version(Posix) { if(system_directory.exists) { assert(!system_directory.isSymlink); immutable symfile = deleteme ~ "_slink\0"; scope(exit) if(symfile.exists) symfile.remove(); core.sys.posix.unistd.symlink(system_directory, symfile.ptr); assert(symfile.isSymlink); assert(!attrIsSymlink(getAttributes(symfile))); assert(attrIsSymlink(getLinkAttributes(symfile))); assert(attrIsDir(getAttributes(symfile))); assert(!attrIsDir(getLinkAttributes(symfile))); assert(!attrIsFile(getAttributes(symfile))); assert(!attrIsFile(getLinkAttributes(symfile))); } if(system_file.exists) { assert(!system_file.isSymlink); immutable symfile = deleteme ~ "_slink\0"; scope(exit) if(symfile.exists) symfile.remove(); core.sys.posix.unistd.symlink(system_file, symfile.ptr); assert(symfile.isSymlink); assert(!attrIsSymlink(getAttributes(symfile))); assert(attrIsSymlink(getLinkAttributes(symfile))); assert(!attrIsDir(getAttributes(symfile))); assert(!attrIsDir(getLinkAttributes(symfile))); assert(attrIsFile(getAttributes(symfile))); assert(!attrIsFile(getLinkAttributes(symfile))); } } static assert(__traits(compiles, () @safe { return "dummy".isSymlink; })); } /++ Returns whether the given file attributes are for a symbolic link. On Windows, return $(D true) when the file is either a symbolic link or a junction point. Params: attributes = The file attributes. Returns: true if attributes are for a symbolic link Example: -------------------- core.sys.posix.unistd.symlink("/etc/fonts/fonts.conf", "/tmp/alink"); assert(!getAttributes("/tmp/alink").isSymlink); assert(getLinkAttributes("/tmp/alink").isSymlink); -------------------- +/ bool attrIsSymlink(uint attributes) @safe pure nothrow @nogc { version(Windows) return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; else version(Posix) return (attributes & S_IFMT) == S_IFLNK; } /**************************************************** * Change directory to $(D pathname). * Throws: $(D FileException) on error. */ void chdir(R)(R pathname) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { // Place outside of @trusted block auto pathz = pathname.tempCString!FSChar(); version(Windows) { static auto trustedChdir(const(FSChar)* pathz) @trusted { return SetCurrentDirectoryW(pathz); } } else version(Posix) { static auto trustedChdir(const(FSChar)* pathz) @trusted { return core.sys.posix.unistd.chdir(pathz) == 0; } } static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias pathStr = pathname; else string pathStr = null; cenforce(trustedChdir(pathz), pathStr, pathz); } void chdir(R)(auto ref R pathname) if (isConvertibleToString!R) { return chdir!(StringTypeOf!R)(pathname); } unittest { static assert(__traits(compiles, chdir(TestAliasedString(null)))); } /**************************************************** Make directory $(D pathname). Throws: $(D FileException) on Posix or $(D WindowsException) on Windows if an error occured. */ void mkdir(R)(R pathname) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { // Place outside of @trusted block auto pathz = pathname.tempCString!FSChar(); version(Windows) { static auto trustedCreateDirectoryW(const(FSChar)* pathz) @trusted { return CreateDirectoryW(pathz, null); } static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias pathStr = pathname; else string pathStr = null; wenforce(trustedCreateDirectoryW(pathz), pathStr, pathz); } else version(Posix) { static auto trustedMkdir(const(FSChar)* pathz, mode_t mode) @trusted { return core.sys.posix.sys.stat.mkdir(pathz, mode); } static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias pathStr = pathname; else string pathStr = null; cenforce(trustedMkdir(pathz, octal!777) == 0, pathStr, pathz); } } void mkdir(R)(auto ref R pathname) if (isConvertibleToString!R) { return mkdir!(StringTypeOf!R)(pathname); } unittest { static assert(__traits(compiles, mkdir(TestAliasedString(null)))); } // Same as mkdir but ignores "already exists" errors. // Returns: "true" if the directory was created, // "false" if it already existed. private bool ensureDirExists(in char[] pathname) { version(Windows) { if (CreateDirectoryW(pathname.tempCStringW(), null)) return true; cenforce(GetLastError() == ERROR_ALREADY_EXISTS, pathname.idup); } else version(Posix) { if (core.sys.posix.sys.stat.mkdir(pathname.tempCString(), octal!777) == 0) return true; cenforce(errno == EEXIST || errno == EISDIR, pathname); } enforce(pathname.isDir, new FileException(pathname.idup)); return false; } /**************************************************** * Make directory and all parent directories as needed. * * Throws: $(D FileException) on error. */ void mkdirRecurse(in char[] pathname) { const left = dirName(pathname); if (left.length != pathname.length && !exists(left)) { mkdirRecurse(left); } if (!baseName(pathname).empty) { ensureDirExists(pathname); } } unittest { { immutable basepath = deleteme ~ "_dir"; scope(exit) rmdirRecurse(basepath); auto path = buildPath(basepath, "a", "..", "b"); mkdirRecurse(path); path = path.buildNormalizedPath; assert(path.isDir); path = buildPath(basepath, "c"); write(path, ""); assertThrown!FileException(mkdirRecurse(path)); path = buildPath(basepath, "d"); mkdirRecurse(path); mkdirRecurse(path); // should not throw } version(Windows) { assertThrown!FileException(mkdirRecurse(`1:\foobar`)); } // bug3570 { immutable basepath = deleteme ~ "_dir"; version (Windows) { immutable path = basepath ~ "\\fake\\here\\"; } else version (Posix) { immutable path = basepath ~ `/fake/here/`; } mkdirRecurse(path); assert(basepath.exists && basepath.isDir); scope(exit) rmdirRecurse(basepath); assert(path.exists && path.isDir); } } /**************************************************** Remove directory $(D pathname). Params: pathname = Range or string specifying the directory name Throws: $(D FileException) on error. */ void rmdir(R)(R pathname) if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R) { // Place outside of @trusted block auto pathz = pathname.tempCString!FSChar(); version(Windows) { static auto trustedRmdir(const(FSChar)* pathz) @trusted { return RemoveDirectoryW(pathz); } } else version(Posix) { static auto trustedRmdir(const(FSChar)* pathz) @trusted { return core.sys.posix.unistd.rmdir(pathz) == 0; } } static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias pathStr = pathname; else string pathStr = null; cenforce(trustedRmdir(pathz), pathStr, pathz); } void rmdir(R)(auto ref R pathname) if (isConvertibleToString!R) { rmdir!(StringTypeOf!R)(pathname); } unittest { static assert(__traits(compiles, rmdir(TestAliasedString(null)))); } /++ $(BLUE This function is Posix-Only.) Creates a symbolic _link (_symlink). Params: original = The file that is being linked. This is the target path that's stored in the _symlink. A relative path is relative to the created _symlink. link = The _symlink to create. A relative path is relative to the current working directory. Throws: $(D FileException) on error (which includes if the _symlink already exists). +/ version(StdDdoc) void symlink(C1, C2)(const(C1)[] original, const(C2)[] link) @safe; else version(Posix) void symlink(C1, C2)(const(C1)[] original, const(C2)[] link) @safe { static auto trustedSymlink(const(C1)[] path1, const(C2)[] path2) @trusted { return core.sys.posix.unistd.symlink(path1.tempCString(), path2.tempCString()); } cenforce(trustedSymlink(original, link) == 0, link); } version(Posix) @safe unittest { if(system_directory.exists) { immutable symfile = deleteme ~ "_slink\0"; scope(exit) if(symfile.exists) symfile.remove(); symlink(system_directory, symfile); assert(symfile.exists); assert(symfile.isSymlink); assert(!attrIsSymlink(getAttributes(symfile))); assert(attrIsSymlink(getLinkAttributes(symfile))); assert(attrIsDir(getAttributes(symfile))); assert(!attrIsDir(getLinkAttributes(symfile))); assert(!attrIsFile(getAttributes(symfile))); assert(!attrIsFile(getLinkAttributes(symfile))); } if(system_file.exists) { assert(!system_file.isSymlink); immutable symfile = deleteme ~ "_slink\0"; scope(exit) if(symfile.exists) symfile.remove(); symlink(system_file, symfile); assert(symfile.exists); assert(symfile.isSymlink); assert(!attrIsSymlink(getAttributes(symfile))); assert(attrIsSymlink(getLinkAttributes(symfile))); assert(!attrIsDir(getAttributes(symfile))); assert(!attrIsDir(getLinkAttributes(symfile))); assert(attrIsFile(getAttributes(symfile))); assert(!attrIsFile(getLinkAttributes(symfile))); } } /++ $(BLUE This function is Posix-Only.) Returns the path to the file pointed to by a symlink. Note that the path could be either relative or absolute depending on the symlink. If the path is relative, it's relative to the symlink, not the current working directory. Throws: $(D FileException) on error. +/ version(StdDdoc) string readLink(C)(const(C)[] link) @safe; else version(Posix) string readLink(C)(const(C)[] link) @safe { static auto trustedReadlink(const(C)[] path, char[] buf) @trusted { return core.sys.posix.unistd.readlink(path.tempCString(), buf.ptr, buf.length); } static auto trustedAssumeUnique(ref C[] array) @trusted { return assumeUnique(array); } enum bufferLen = 2048; enum maxCodeUnits = 6; char[bufferLen] buffer; auto size = trustedReadlink(link, buffer); cenforce(size != -1, link); if(size <= bufferLen - maxCodeUnits) return to!string(buffer[0 .. size]); auto dynamicBuffer = new char[](bufferLen * 3 / 2); foreach(i; 0 .. 10) { size = trustedReadlink(link, dynamicBuffer); cenforce(size != -1, link); if(size <= dynamicBuffer.length - maxCodeUnits) { dynamicBuffer.length = size; return trustedAssumeUnique(dynamicBuffer); } dynamicBuffer.length = dynamicBuffer.length * 3 / 2; } throw new FileException(to!string(link), "Path is too long to read."); } version(Posix) @safe unittest { import std.string; foreach(file; [system_directory, system_file]) { if(file.exists) { immutable symfile = deleteme ~ "_slink\0"; scope(exit) if(symfile.exists) symfile.remove(); symlink(file, symfile); assert(readLink(symfile) == file, format("Failed file: %s", file)); } } assertThrown!FileException(readLink("/doesnotexist")); } /**************************************************** * Get the current working directory. * Throws: $(D FileException) on error. */ version(Windows) string getcwd() { import std.utf : toUTF8; /* GetCurrentDirectory's return value: 1. function succeeds: the number of characters that are written to the buffer, not including the terminating null character. 2. function fails: zero 3. the buffer (lpBuffer) is not large enough: the required size of the buffer, in characters, including the null-terminating character. */ wchar[4096] buffW = void; //enough for most common case immutable n = cenforce(GetCurrentDirectoryW(to!DWORD(buffW.length), buffW.ptr), "getcwd"); // we can do it because toUTFX always produces a fresh string if(n < buffW.length) { return toUTF8(buffW[0 .. n]); } else //staticBuff isn't enough { auto ptr = cast(wchar*) malloc(wchar.sizeof * n); scope(exit) free(ptr); immutable n2 = GetCurrentDirectoryW(n, ptr); cenforce(n2 && n2 < n, "getcwd"); return toUTF8(ptr[0 .. n2]); } } else version (Solaris) string getcwd() { /* BUF_SIZE >= PATH_MAX */ enum BUF_SIZE = 4096; /* The user should be able to specify any size buffer > 0 */ auto p = cenforce(core.sys.posix.unistd.getcwd(null, BUF_SIZE), "cannot get cwd"); scope(exit) core.stdc.stdlib.free(p); return p[0 .. core.stdc.string.strlen(p)].idup; } else version (Posix) string getcwd() { auto p = cenforce(core.sys.posix.unistd.getcwd(null, 0), "cannot get cwd"); scope(exit) core.stdc.stdlib.free(p); return p[0 .. core.stdc.string.strlen(p)].idup; } unittest { auto s = getcwd(); assert(s.length); } version (OSX) private extern (C) int _NSGetExecutablePath(char* buf, uint* bufsize); else version (FreeBSD) private extern (C) int sysctl (const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen); else version (NetBSD) private extern (C) int sysctl (const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen); /** * Returns the full path of the current executable. * * Throws: * $(XREF object, Exception) */ @trusted string thisExePath () { version (OSX) { import core.sys.posix.stdlib : realpath; uint size; _NSGetExecutablePath(null, &size); // get the length of the path auto buffer = new char[size]; _NSGetExecutablePath(buffer.ptr, &size); auto absolutePath = realpath(buffer.ptr, null); // let the function allocate scope (exit) { if (absolutePath) free(absolutePath); } errnoEnforce(absolutePath); return to!(string)(absolutePath); } else version (linux) { return readLink("/proc/self/exe"); } else version (Windows) { wchar[MAX_PATH] buf; wchar[] buffer = buf[]; while (true) { auto len = GetModuleFileNameW(null, buffer.ptr, cast(DWORD) buffer.length); enforce(len, sysErrorString(GetLastError())); if (len != buffer.length) return to!(string)(buffer[0 .. len]); buffer.length *= 2; } } else version (FreeBSD) { enum { CTL_KERN = 1, KERN_PROC = 14, KERN_PROC_PATHNAME = 12 } int[4] mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1]; size_t len; auto result = sysctl(mib.ptr, mib.length, null, &len, null, 0); // get the length of the path errnoEnforce(result == 0); auto buffer = new char[len - 1]; result = sysctl(mib.ptr, mib.length, buffer.ptr, &len, null, 0); errnoEnforce(result == 0); return buffer.assumeUnique; } else version (NetBSD) { return readLink("/proc/self/exe"); } else version (Solaris) { import core.sys.posix.unistd : getpid; import std.string : format; // Only Solaris 10 and later return readLink(format("/proc/%d/path/a.out", getpid())); } else static assert(0, "thisExePath is not supported on this platform"); } @safe unittest { auto path = thisExePath(); assert(path.exists); assert(path.isAbsolute); assert(path.isFile); } version(StdDdoc) { /++ Info on a file, similar to what you'd get from stat on a Posix system. +/ struct DirEntry { /++ Constructs a DirEntry for the given file (or directory). Params: path = The file (or directory) to get a DirEntry for. Throws: $(D FileException) if the file does not exist. +/ this(string path); version (Windows) { private this(string path, in WIN32_FIND_DATAW *fd); } else version (Posix) { private this(string path, core.sys.posix.dirent.dirent* fd); } /++ Returns the path to the file represented by this $(D DirEntry). Example: -------------------- auto de1 = DirEntry("/etc/fonts/fonts.conf"); assert(de1.name == "/etc/fonts/fonts.conf"); auto de2 = DirEntry("/usr/share/include"); assert(de2.name == "/usr/share/include"); -------------------- +/ @property string name() const; /++ Returns whether the file represented by this $(D DirEntry) is a directory. Example: -------------------- auto de1 = DirEntry("/etc/fonts/fonts.conf"); assert(!de1.isDir); auto de2 = DirEntry("/usr/share/include"); assert(de2.isDir); -------------------- +/ @property bool isDir(); /++ Returns whether the file represented by this $(D DirEntry) is a file. On Windows, if a file is not a directory, then it's a file. So, either $(D isFile) or $(D isDir) will return $(D true). On Posix systems, if $(D isFile) is $(D true), that indicates that the file is a regular file (e.g. not a block not device). So, on Posix systems, it's possible for both $(D isFile) and $(D isDir) to be $(D false) for a particular file (in which case, it's a special file). You can use $(D attributes) or $(D statBuf) to get more information about a special file (see the stat man page for more details). Example: -------------------- auto de1 = DirEntry("/etc/fonts/fonts.conf"); assert(de1.isFile); auto de2 = DirEntry("/usr/share/include"); assert(!de2.isFile); -------------------- +/ @property bool isFile(); /++ Returns whether the file represented by this $(D DirEntry) is a symbolic link. On Windows, return $(D true) when the file is either a symbolic link or a junction point. +/ @property bool isSymlink(); /++ Returns the size of the the file represented by this $(D DirEntry) in bytes. +/ @property ulong size(); /++ $(BLUE This function is Windows-Only.) Returns the creation time of the file represented by this $(D DirEntry). +/ @property SysTime timeCreated() const; /++ Returns the time that the file represented by this $(D DirEntry) was last accessed. Note that many file systems do not update the access time for files (generally for performance reasons), so there's a good chance that $(D timeLastAccessed) will return the same value as $(D timeLastModified). +/ @property SysTime timeLastAccessed(); /++ Returns the time that the file represented by this $(D DirEntry) was last modified. +/ @property SysTime timeLastModified(); /++ Returns the attributes of the file represented by this $(D DirEntry). Note that the file attributes on Windows and Posix systems are completely different. On, Windows, they're what is returned by $(D GetFileAttributes) $(WEB msdn.microsoft.com/en-us/library/aa364944(v=vs.85).aspx, GetFileAttributes) Whereas, an Posix systems, they're the $(D st_mode) value which is part of the $(D stat) struct gotten by calling $(D stat). On Posix systems, if the file represented by this $(D DirEntry) is a symbolic link, then attributes are the attributes of the file pointed to by the symbolic link. +/ @property uint attributes(); /++ On Posix systems, if the file represented by this $(D DirEntry) is a symbolic link, then $(D linkAttributes) are the attributes of the symbolic link itself. Otherwise, $(D linkAttributes) is identical to $(D attributes). On Windows, $(D linkAttributes) is identical to $(D attributes). It exists on Windows so that you don't have to special-case code for Windows when dealing with symbolic links. +/ @property uint linkAttributes(); version(Windows) alias stat_t = void*; /++ $(BLUE This function is Posix-Only.) The $(D stat) struct gotten from calling $(D stat). +/ @property stat_t statBuf(); } } else version(Windows) { struct DirEntry { import std.utf : toUTF8; public: alias name this; this(string path) { if(!path.exists()) throw new FileException(path, "File does not exist"); _name = path; with (getFileAttributesWin(path)) { _size = makeUlong(nFileSizeLow, nFileSizeHigh); _timeCreated = std.datetime.FILETIMEToSysTime(&ftCreationTime); _timeLastAccessed = std.datetime.FILETIMEToSysTime(&ftLastAccessTime); _timeLastModified = std.datetime.FILETIMEToSysTime(&ftLastWriteTime); _attributes = dwFileAttributes; } } private this(string path, in WIN32_FIND_DATAW *fd) { import core.stdc.wchar_ : wcslen; size_t clength = wcslen(fd.cFileName.ptr); _name = toUTF8(fd.cFileName[0 .. clength]); _name = buildPath(path, toUTF8(fd.cFileName[0 .. clength])); _size = (cast(ulong)fd.nFileSizeHigh << 32) | fd.nFileSizeLow; _timeCreated = std.datetime.FILETIMEToSysTime(&fd.ftCreationTime); _timeLastAccessed = std.datetime.FILETIMEToSysTime(&fd.ftLastAccessTime); _timeLastModified = std.datetime.FILETIMEToSysTime(&fd.ftLastWriteTime); _attributes = fd.dwFileAttributes; } @property string name() const pure nothrow { return _name; } @property bool isDir() const pure nothrow { return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } @property bool isFile() const pure nothrow { //Are there no options in Windows other than directory and file? //If there are, then this probably isn't the best way to determine //whether this DirEntry is a file or not. return !isDir; } @property bool isSymlink() const pure nothrow { return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } @property ulong size() const pure nothrow { return _size; } @property SysTime timeCreated() const pure nothrow { return cast(SysTime)_timeCreated; } @property SysTime timeLastAccessed() const pure nothrow { return cast(SysTime)_timeLastAccessed; } @property SysTime timeLastModified() const pure nothrow { return cast(SysTime)_timeLastModified; } @property uint attributes() const pure nothrow { return _attributes; } @property uint linkAttributes() const pure nothrow { return _attributes; } private: string _name; /// The file or directory represented by this DirEntry. SysTime _timeCreated; /// The time when the file was created. SysTime _timeLastAccessed; /// The time when the file was last accessed. SysTime _timeLastModified; /// The time when the file was last modified. ulong _size; /// The size of the file in bytes. uint _attributes; /// The file attributes from WIN32_FIND_DATAW. } } else version(Posix) { struct DirEntry { public: alias name this; this(string path) { if(!path.exists) throw new FileException(path, "File does not exist"); _name = path; _didLStat = false; _didStat = false; _dTypeSet = false; } private this(string path, core.sys.posix.dirent.dirent* fd) { immutable len = core.stdc.string.strlen(fd.d_name.ptr); _name = buildPath(path, fd.d_name[0 .. len]); _didLStat = false; _didStat = false; //fd_d_type doesn't work for all file systems, //in which case the result is DT_UNKOWN. But we //can determine the correct type from lstat, so //we'll only set the dtype here if we could //correctly determine it (not lstat in the case //of DT_UNKNOWN in case we don't ever actually //need the dtype, thus potentially avoiding the //cost of calling lstat). static if (__traits(compiles, fd.d_type != DT_UNKNOWN)) { if(fd.d_type != DT_UNKNOWN) { _dType = fd.d_type; _dTypeSet = true; } else _dTypeSet = false; } else { // e.g. Solaris does not have the d_type member _dTypeSet = false; } } @property string name() const pure nothrow { return _name; } @property bool isDir() { _ensureStatOrLStatDone(); return (_statBuf.st_mode & S_IFMT) == S_IFDIR; } @property bool isFile() { _ensureStatOrLStatDone(); return (_statBuf.st_mode & S_IFMT) == S_IFREG; } @property bool isSymlink() { _ensureLStatDone(); return (_lstatMode & S_IFMT) == S_IFLNK; } @property ulong size() { _ensureStatDone(); return _statBuf.st_size; } @property SysTime timeStatusChanged() { _ensureStatDone(); return SysTime(unixTimeToStdTime(_statBuf.st_ctime)); } @property SysTime timeLastAccessed() { _ensureStatDone(); return SysTime(unixTimeToStdTime(_statBuf.st_ctime)); } @property SysTime timeLastModified() { _ensureStatDone(); return SysTime(unixTimeToStdTime(_statBuf.st_mtime)); } @property uint attributes() { _ensureStatDone(); return _statBuf.st_mode; } @property uint linkAttributes() { _ensureLStatDone(); return _lstatMode; } @property stat_t statBuf() { _ensureStatDone(); return _statBuf; } private: /++ This is to support lazy evaluation, because doing stat's is expensive and not always needed. +/ void _ensureStatDone() @safe { static auto trustedStat(in char[] path, stat_t* buf) @trusted { return stat(path.tempCString(), buf); } if(_didStat) return; enforce(trustedStat(_name, &_statBuf) == 0, "Failed to stat file `" ~ _name ~ "'"); _didStat = true; } /++ This is to support lazy evaluation, because doing stat's is expensive and not always needed. Try both stat and lstat for isFile and isDir to detect broken symlinks. +/ void _ensureStatOrLStatDone() { if(_didStat) return; if( stat(_name.tempCString(), &_statBuf) != 0 ) { _ensureLStatDone(); _statBuf = stat_t.init; _statBuf.st_mode = S_IFLNK; } else { _didStat = true; } } /++ This is to support lazy evaluation, because doing stat's is expensive and not always needed. +/ void _ensureLStatDone() { if(_didLStat) return; stat_t statbuf = void; enforce(lstat(_name.tempCString(), &statbuf) == 0, "Failed to stat file `" ~ _name ~ "'"); _lstatMode = statbuf.st_mode; _dTypeSet = true; _didLStat = true; } string _name; /// The file or directory represented by this DirEntry. stat_t _statBuf = void; /// The result of stat(). uint _lstatMode; /// The stat mode from lstat(). ubyte _dType; /// The type of the file. bool _didLStat = false; /// Whether lstat() has been called for this DirEntry. bool _didStat = false; /// Whether stat() has been called for this DirEntry. bool _dTypeSet = false; /// Whether the dType of the file has been set. } } unittest { version(Windows) { if("C:\\Program Files\\".exists) { auto de = DirEntry("C:\\Program Files\\"); assert(!de.isFile); assert(de.isDir); assert(!de.isSymlink); } if("C:\\Users\\".exists && "C:\\Documents and Settings\\".exists) { auto de = DirEntry("C:\\Documents and Settings\\"); assert(de.isSymlink); } if("C:\\Windows\\system.ini".exists) { auto de = DirEntry("C:\\Windows\\system.ini"); assert(de.isFile); assert(!de.isDir); assert(!de.isSymlink); } } else version(Posix) { if(system_directory.exists) { { auto de = DirEntry(system_directory); assert(!de.isFile); assert(de.isDir); assert(!de.isSymlink); } immutable symfile = deleteme ~ "_slink\0"; scope(exit) if(symfile.exists) symfile.remove(); core.sys.posix.unistd.symlink(system_directory, symfile.ptr); { auto de = DirEntry(symfile); assert(!de.isFile); assert(de.isDir); assert(de.isSymlink); } symfile.remove(); core.sys.posix.unistd.symlink((deleteme ~ "_broken_symlink\0").ptr, symfile.ptr); { //Issue 8298 DirEntry de = DirEntry(symfile); assert(!de.isFile); assert(!de.isDir); assert(de.isSymlink); assertThrown(de.size); assertThrown(de.timeStatusChanged); assertThrown(de.timeLastAccessed); assertThrown(de.timeLastModified); assertThrown(de.attributes); assertThrown(de.statBuf); assert(symfile.exists); symfile.remove(); } } if(system_file.exists) { auto de = DirEntry(system_file); assert(de.isFile); assert(!de.isDir); assert(!de.isSymlink); } } } alias PreserveAttributes = Flag!"preserveAttributes"; version (StdDdoc) { /// Defaults to PreserveAttributes.yes on Windows, and the opposite on all other platforms. PreserveAttributes preserveAttributesDefault; } else version(Windows) { enum preserveAttributesDefault = PreserveAttributes.yes; } else { enum preserveAttributesDefault = PreserveAttributes.no; } /*************************************************** Copy file $(D from) to file $(D to). File timestamps are preserved. File attributes are preserved, if $(D preserve) equals $(D PreserveAttributes.yes). On Windows only $(D PreserveAttributes.yes) (the default on Windows) is supported. If the target file exists, it is overwritten. Params: from = string or range of characters representing the existing file name to = string or range of characters representing the target file name preserve = whether to preserve the file attributes Throws: $(D FileException) on error. */ void copy(RF, RT)(RF from, RT to, PreserveAttributes preserve = preserveAttributesDefault) if (isInputRange!RF && isSomeChar!(ElementEncodingType!RF) && !isConvertibleToString!RF && isInputRange!RT && isSomeChar!(ElementEncodingType!RT) && !isConvertibleToString!RT) { // Place outside of @trusted block auto fromz = from.tempCString!FSChar(); auto toz = to.tempCString!FSChar(); static if (isNarrowString!RF && is(Unqual!(ElementEncodingType!RF) == char)) alias f = from; else enum string f = null; static if (isNarrowString!RT && is(Unqual!(ElementEncodingType!RT) == char)) alias t = to; else enum string t = null; copyImpl(f, t, fromz, toz, preserve); } void copy(RF, RT)(auto ref RF from, auto ref RT to, PreserveAttributes preserve = preserveAttributesDefault) if (isConvertibleToString!RF || isConvertibleToString!RT) { import std.meta : staticMap; alias Types = staticMap!(convertToString, RF, RT); copy!Types(from, to, preserve); } unittest // issue 15319 { import std.file : dirEntries; auto fs = dirEntries(tempDir(), SpanMode.depth); assert(__traits(compiles, copy(fs.front, fs.front))); } private void copyImpl(const(char)[] f, const(char)[] t, const(FSChar)* fromz, const(FSChar)* toz, PreserveAttributes preserve) @trusted { version(Windows) { assert(preserve == Yes.preserve); immutable result = CopyFileW(fromz, toz, false); if (!result) { import core.stdc.wchar_ : wcslen; import std.conv : to; if (!t) t = to!(typeof(t))(toz[0 .. wcslen(toz)]); throw new FileException(t); } } else version(Posix) { import core.stdc.stdio; static import std.conv; immutable fd = core.sys.posix.fcntl.open(fromz, O_RDONLY); cenforce(fd != -1, f, fromz); scope(exit) core.sys.posix.unistd.close(fd); stat_t statbuf = void; cenforce(fstat(fd, &statbuf) == 0, f, fromz); //cenforce(core.sys.posix.sys.stat.fstat(fd, &statbuf) == 0, f, fromz); immutable fdw = core.sys.posix.fcntl.open(toz, O_CREAT | O_WRONLY | O_TRUNC, octal!666); cenforce(fdw != -1, t, toz); scope(failure) core.stdc.stdio.remove(toz); { scope(failure) core.sys.posix.unistd.close(fdw); auto BUFSIZ = 4096u * 16; auto buf = core.stdc.stdlib.malloc(BUFSIZ); if (!buf) { BUFSIZ = 4096; buf = core.stdc.stdlib.malloc(BUFSIZ); if (!buf) { import core.exception : onOutOfMemoryError; onOutOfMemoryError(); } } scope(exit) core.stdc.stdlib.free(buf); for (auto size = statbuf.st_size; size; ) { immutable toxfer = (size > BUFSIZ) ? BUFSIZ : cast(size_t) size; cenforce( core.sys.posix.unistd.read(fd, buf, toxfer) == toxfer && core.sys.posix.unistd.write(fdw, buf, toxfer) == toxfer, f, fromz); assert(size >= toxfer); size -= toxfer; } if (preserve) cenforce(fchmod(fdw, std.conv.to!mode_t(statbuf.st_mode)) == 0, f, fromz); } cenforce(core.sys.posix.unistd.close(fdw) != -1, f, fromz); utimbuf utim = void; utim.actime = cast(time_t)statbuf.st_atime; utim.modtime = cast(time_t)statbuf.st_mtime; cenforce(utime(toz, &utim) != -1, f, fromz); } } unittest { import std.algorithm, std.file; // issue 14817 auto t1 = deleteme, t2 = deleteme~"2"; scope(exit) foreach (t; [t1, t2]) if (t.exists) t.remove(); write(t1, "1"); copy(t1, t2); assert(readText(t2) == "1"); write(t1, "2"); copy(t1, t2); assert(readText(t2) == "2"); import std.utf : byChar; copy(t1.byChar, t2.byChar); assert(readText(t2.byChar) == "2"); } version(Posix) unittest //issue 11434 { auto t1 = deleteme, t2 = deleteme~"2"; scope(exit) foreach (t; [t1, t2]) if (t.exists) t.remove(); write(t1, "1"); setAttributes(t1, octal!767); copy(t1, t2, Yes.preserveAttributes); assert(readText(t2) == "1"); assert(getAttributes(t2) == octal!100767); } /++ Remove directory and all of its content and subdirectories, recursively. Throws: $(D FileException) if there is an error (including if the given file is not a directory). +/ void rmdirRecurse(in char[] pathname) { //No references to pathname will be kept after rmdirRecurse, //so the cast is safe rmdirRecurse(DirEntry(cast(string)pathname)); } /++ Remove directory and all of its content and subdirectories, recursively. Throws: $(D FileException) if there is an error (including if the given file is not a directory). +/ void rmdirRecurse(ref DirEntry de) { if(!de.isDir) throw new FileException(de.name, "Not a directory"); if (de.isSymlink) { version (Windows) rmdir(de.name); else remove(de.name); } else { // all children, recursively depth-first foreach(DirEntry e; dirEntries(de.name, SpanMode.depth, false)) { attrIsDir(e.linkAttributes) ? rmdir(e.name) : remove(e.name); } // the dir itself rmdir(de.name); } } ///ditto //Note, without this overload, passing an RValue DirEntry still works, but //actually fully reconstructs a DirEntry inside the //"rmdirRecurse(in char[] pathname)" implementation. That is needlessly //expensive. //A DirEntry is a bit big (72B), so keeping the "by ref" signature is desirable. void rmdirRecurse(DirEntry de) { rmdirRecurse(de); } version(Windows) unittest { auto d = deleteme ~ r".dir\a\b\c\d\e\f\g"; mkdirRecurse(d); rmdirRecurse(deleteme ~ ".dir"); enforce(!exists(deleteme ~ ".dir")); } version(Posix) unittest { import std.process: executeShell; collectException(rmdirRecurse(deleteme)); auto d = deleteme~"/a/b/c/d/e/f/g"; enforce(collectException(mkdir(d))); mkdirRecurse(d); core.sys.posix.unistd.symlink((deleteme~"/a/b/c\0").ptr, (deleteme~"/link\0").ptr); rmdirRecurse(deleteme~"/link"); enforce(exists(d)); rmdirRecurse(deleteme); enforce(!exists(deleteme)); d = deleteme~"/a/b/c/d/e/f/g"; mkdirRecurse(d); version(Android) string link_cmd = "ln -s "; else string link_cmd = "ln -sf "; executeShell(link_cmd~deleteme~"/a/b/c "~deleteme~"/link"); rmdirRecurse(deleteme); enforce(!exists(deleteme)); } unittest { void[] buf; buf = new void[10]; (cast(byte[])buf)[] = 3; string unit_file = deleteme ~ "-unittest_write.tmp"; if (exists(unit_file)) remove(unit_file); write(unit_file, buf); void[] buf2 = read(unit_file); assert(buf == buf2); string unit2_file = deleteme ~ "-unittest_write2.tmp"; copy(unit_file, unit2_file); buf2 = read(unit2_file); assert(buf == buf2); remove(unit_file); assert(!exists(unit_file)); remove(unit2_file); assert(!exists(unit2_file)); } /** * Dictates directory spanning policy for $(D_PARAM dirEntries) (see below). */ enum SpanMode { /** Only spans one directory. */ shallow, /** Spans the directory depth-first, i.e. the content of any subdirectory is spanned before that subdirectory itself. Useful e.g. when recursively deleting files. */ depth, /** Spans the directory breadth-first, i.e. the content of any subdirectory is spanned right after that subdirectory itself. */ breadth, } private struct DirIteratorImpl { import std.array : Appender, appender; SpanMode _mode; // Whether we should follow symlinked directories while iterating. // It also indicates whether we should avoid functions which call // stat (since we should only need lstat in this case and it would // be more efficient to not call stat in addition to lstat). bool _followSymlink; DirEntry _cur; Appender!(DirHandle[]) _stack; Appender!(DirEntry[]) _stashed; //used in depth first mode //stack helpers void pushExtra(DirEntry de){ _stashed.put(de); } //ditto bool hasExtra(){ return !_stashed.data.empty; } //ditto DirEntry popExtra() { DirEntry de; de = _stashed.data[$-1]; _stashed.shrinkTo(_stashed.data.length - 1); return de; } version(Windows) { struct DirHandle { string dirpath; HANDLE h; } bool stepIn(string directory) { auto search_pattern = chainPath(directory, "*.*"); WIN32_FIND_DATAW findinfo; HANDLE h = FindFirstFileW(search_pattern.tempCString!FSChar(), &findinfo); cenforce(h != INVALID_HANDLE_VALUE, directory); _stack.put(DirHandle(directory, h)); return toNext(false, &findinfo); } bool next() { if(_stack.data.empty) return false; WIN32_FIND_DATAW findinfo; return toNext(true, &findinfo); } bool toNext(bool fetch, WIN32_FIND_DATAW* findinfo) { import core.stdc.wchar_ : wcscmp; if(fetch) { if(FindNextFileW(_stack.data[$-1].h, findinfo) == FALSE) { popDirStack(); return false; } } while( wcscmp(findinfo.cFileName.ptr, ".") == 0 || wcscmp(findinfo.cFileName.ptr, "..") == 0) if(FindNextFileW(_stack.data[$-1].h, findinfo) == FALSE) { popDirStack(); return false; } _cur = DirEntry(_stack.data[$-1].dirpath, findinfo); return true; } void popDirStack() { assert(!_stack.data.empty); FindClose(_stack.data[$-1].h); _stack.shrinkTo(_stack.data.length-1); } void releaseDirStack() { foreach( d; _stack.data) FindClose(d.h); } bool mayStepIn() { return _followSymlink ? _cur.isDir : _cur.isDir && !_cur.isSymlink; } } else version(Posix) { struct DirHandle { string dirpath; DIR* h; } bool stepIn(string directory) { auto h = directory.length ? opendir(directory.tempCString()) : opendir("."); cenforce(h, directory); _stack.put(DirHandle(directory, h)); return next(); } bool next() { if(_stack.data.empty) return false; for(dirent* fdata; (fdata = readdir(_stack.data[$-1].h)) != null; ) { // Skip "." and ".." if(core.stdc.string.strcmp(fdata.d_name.ptr, ".") && core.stdc.string.strcmp(fdata.d_name.ptr, "..") ) { _cur = DirEntry(_stack.data[$-1].dirpath, fdata); return true; } } popDirStack(); return false; } void popDirStack() { assert(!_stack.data.empty); closedir(_stack.data[$-1].h); _stack.shrinkTo(_stack.data.length-1); } void releaseDirStack() { foreach( d; _stack.data) closedir(d.h); } bool mayStepIn() { return _followSymlink ? _cur.isDir : attrIsDir(_cur.linkAttributes); } } this(R)(R pathname, SpanMode mode, bool followSymlink) if (isInputRange!R && isSomeChar!(ElementEncodingType!R)) { _mode = mode; _followSymlink = followSymlink; _stack = appender(cast(DirHandle[])[]); if (_mode == SpanMode.depth) _stashed = appender(cast(DirEntry[])[]); static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char)) alias pathnameStr = pathname; else { import std.array; string pathnameStr = pathname.array; } if (stepIn(pathnameStr)) { if(_mode == SpanMode.depth) while(mayStepIn()) { auto thisDir = _cur; if(stepIn(_cur.name)) { pushExtra(thisDir); } else break; } } } @property bool empty(){ return _stashed.data.empty && _stack.data.empty; } @property DirEntry front(){ return _cur; } void popFront() { switch(_mode) { case SpanMode.depth: if(next()) { while(mayStepIn()) { auto thisDir = _cur; if(stepIn(_cur.name)) { pushExtra(thisDir); } else break; } } else if(hasExtra()) _cur = popExtra(); break; case SpanMode.breadth: if(mayStepIn()) { if(!stepIn(_cur.name)) while(!empty && !next()){} } else while(!empty && !next()){} break; default: next(); } } ~this() { releaseDirStack(); } } struct DirIterator { private: RefCounted!(DirIteratorImpl, RefCountedAutoInitialize.no) impl; this(string pathname, SpanMode mode, bool followSymlink) { impl = typeof(impl)(pathname, mode, followSymlink); } public: @property bool empty(){ return impl.empty; } @property DirEntry front(){ return impl.front; } void popFront(){ impl.popFront(); } } /++ Returns an input range of DirEntry that lazily iterates a given directory, also provides two ways of foreach iteration. The iteration variable can be of type $(D_PARAM string) if only the name is needed, or $(D_PARAM DirEntry) if additional details are needed. The span mode dictates the how the directory is traversed. The name of the each directory entry iterated contains the absolute path. Params: path = The directory to iterate over. If empty, the current directory will be iterated. mode = Whether the directory's sub-directories should be iterated over depth-first ($(D_PARAM depth)), breadth-first ($(D_PARAM breadth)), or not at all ($(D_PARAM shallow)). followSymlink = Whether symbolic links which point to directories should be treated as directories and their contents iterated over. Throws: $(D FileException) if the directory does not exist. Example: -------------------- // Iterate a directory in depth foreach (string name; dirEntries("destroy/me", SpanMode.depth)) { remove(name); } // Iterate the current directory in breadth foreach (string name; dirEntries("", SpanMode.breadth)) { writeln(name); } // Iterate a directory and get detailed info about it foreach (DirEntry e; dirEntries("dmd-testing", SpanMode.breadth)) { writeln(e.name, "\t", e.size); } // Iterate over all *.d files in current directory and all its subdirectories auto dFiles = dirEntries("", SpanMode.depth).filter!(f => f.name.endsWith(".d")); foreach(d; dFiles) writeln(d.name); // Hook it up with std.parallelism to compile them all in parallel: foreach(d; parallel(dFiles, 1)) //passes by 1 file to each thread { string cmd = "dmd -c " ~ d.name; writeln(cmd); std.process.system(cmd); } -------------------- +/ auto dirEntries(string path, SpanMode mode, bool followSymlink = true) { return DirIterator(path, mode, followSymlink); } /// Duplicate functionality of D1's $(D std.file.listdir()): unittest { string[] listdir(string pathname) { import std.file; import std.path; import std.algorithm; import std.array; return std.file.dirEntries(pathname, SpanMode.shallow) .filter!(a => a.isFile) .map!(a => std.path.baseName(a.name)) .array; } void main(string[] args) { import std.stdio; string[] files = listdir(args[1]); writefln("%s", files); } } unittest { import std.algorithm; import std.range; import std.process; version(Android) string testdir = deleteme; // This has to be an absolute path when // called from a shared library on Android, // ie an apk else string testdir = "deleteme.dmd.unittest.std.file" ~ to!string(thisProcessID); // needs to be relative mkdirRecurse(buildPath(testdir, "somedir")); scope(exit) rmdirRecurse(testdir); write(buildPath(testdir, "somefile"), null); write(buildPath(testdir, "somedir", "somedeepfile"), null); // testing range interface size_t equalEntries(string relpath, SpanMode mode) { auto len = enforce(walkLength(dirEntries(absolutePath(relpath), mode))); assert(walkLength(dirEntries(relpath, mode)) == len); assert(equal( map!(a => std.path.absolutePath(a.name))(dirEntries(relpath, mode)), map!(a => a.name)(dirEntries(absolutePath(relpath), mode)))); return len; } assert(equalEntries(testdir, SpanMode.shallow) == 2); assert(equalEntries(testdir, SpanMode.depth) == 3); assert(equalEntries(testdir, SpanMode.breadth) == 3); // testing opApply foreach (string name; dirEntries(testdir, SpanMode.breadth)) { //writeln(name); assert(name.startsWith(testdir)); } foreach (DirEntry e; dirEntries(absolutePath(testdir), SpanMode.breadth)) { //writeln(name); assert(e.isFile || e.isDir, e.name); } //issue 7264 foreach (string name; dirEntries(testdir, "*.d", SpanMode.breadth)) { } foreach (entry; dirEntries(testdir, SpanMode.breadth)) { static assert(is(typeof(entry) == DirEntry)); } //issue 7138 auto a = array(dirEntries(testdir, SpanMode.shallow)); // issue 11392 auto dFiles = dirEntries(testdir, SpanMode.shallow); foreach(d; dFiles){} // issue 15146 dirEntries("", SpanMode.shallow).walkLength(); } /++ Convenience wrapper for filtering file names with a glob pattern. Params: path = The directory to iterate over. pattern = String with wildcards, such as $(RED "*.d"). The supported wildcard strings are described under $(XREF _path, globMatch). mode = Whether the directory's sub-directories should be iterated over depth-first ($(D_PARAM depth)), breadth-first ($(D_PARAM breadth)), or not at all ($(D_PARAM shallow)). followSymlink = Whether symbolic links which point to directories should be treated as directories and their contents iterated over. Throws: $(D FileException) if the directory does not exist. Example: -------------------- // Iterate over all D source files in current directory and all its // subdirectories auto dFiles = dirEntries("","*.{d,di}",SpanMode.depth); foreach(d; dFiles) writeln(d.name); -------------------- +/ auto dirEntries(string path, string pattern, SpanMode mode, bool followSymlink = true) { import std.algorithm : filter; bool f(DirEntry de) { return globMatch(baseName(de.name), pattern); } return filter!f(DirIterator(path, mode, followSymlink)); } unittest { import std.stdio : writefln; immutable dpath = deleteme ~ "_dir"; immutable fpath = deleteme ~ "_file"; immutable sdpath = deleteme ~ "_sdir"; immutable sfpath = deleteme ~ "_sfile"; scope(exit) { if (dpath.exists) rmdirRecurse(dpath); if (fpath.exists) remove(fpath); if (sdpath.exists) remove(sdpath); if (sfpath.exists) remove(sfpath); } mkdir(dpath); write(fpath, "hello world"); version (Posix) { core.sys.posix.unistd.symlink((dpath ~ '\0').ptr, (sdpath ~ '\0').ptr); core.sys.posix.unistd.symlink((fpath ~ '\0').ptr, (sfpath ~ '\0').ptr); } static struct Flags { bool dir, file, link; } auto tests = [dpath : Flags(true), fpath : Flags(false, true)]; version (Posix) { tests[sdpath] = Flags(true, false, true); tests[sfpath] = Flags(false, true, true); } auto past = Clock.currTime() - 2.seconds; auto future = past + 4.seconds; foreach (path, flags; tests) { auto de = DirEntry(path); assert(de.name == path); assert(de.isDir == flags.dir); assert(de.isFile == flags.file); assert(de.isSymlink == flags.link); assert(de.isDir == path.isDir); assert(de.isFile == path.isFile); assert(de.isSymlink == path.isSymlink); assert(de.size == path.getSize()); assert(de.attributes == getAttributes(path)); assert(de.linkAttributes == getLinkAttributes(path)); scope(failure) writefln("[%s] [%s] [%s] [%s]", past, de.timeLastAccessed, de.timeLastModified, future); assert(de.timeLastAccessed > past); assert(de.timeLastAccessed < future); assert(de.timeLastModified > past); assert(de.timeLastModified < future); assert(attrIsDir(de.attributes) == flags.dir); assert(attrIsDir(de.linkAttributes) == (flags.dir && !flags.link)); assert(attrIsFile(de.attributes) == flags.file); assert(attrIsFile(de.linkAttributes) == (flags.file && !flags.link)); assert(!attrIsSymlink(de.attributes)); assert(attrIsSymlink(de.linkAttributes) == flags.link); version(Windows) { assert(de.timeCreated > past); assert(de.timeCreated < future); } else version(Posix) { assert(de.timeStatusChanged > past); assert(de.timeStatusChanged < future); assert(de.attributes == de.statBuf.st_mode); } } } /** Reads an entire file into an array. */ Select!(Types.length == 1, Types[0][], Tuple!(Types)[]) slurp(Types...)(string filename, in char[] format) { import std.stdio : File; import std.format : formattedRead; import std.array : appender; typeof(return) result; auto app = appender!(typeof(return))(); ElementType!(typeof(return)) toAdd; auto f = File(filename); scope(exit) f.close(); foreach (line; f.byLine()) { formattedRead(line, format, &toAdd); enforce(line.empty, text("Trailing characters at the end of line: `", line, "'")); app.put(toAdd); } return app.data; } /// unittest { scope(exit) { assert(exists(deleteme)); remove(deleteme); } write(deleteme, "12 12.25\n345 1.125"); // deleteme is the name of a temporary file // Load file; each line is an int followed by comma, whitespace and a // double. auto a = slurp!(int, double)(deleteme, "%s %s"); assert(a.length == 2); assert(a[0] == tuple(12, 12.25)); assert(a[1] == tuple(345, 1.125)); } /** Returns the path to a directory for temporary files. On Windows, this function returns the result of calling the Windows API function $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/aa364992.aspx, $(D GetTempPath)). On POSIX platforms, it searches through the following list of directories and returns the first one which is found to exist: $(OL $(LI The directory given by the $(D TMPDIR) environment variable.) $(LI The directory given by the $(D TEMP) environment variable.) $(LI The directory given by the $(D TMP) environment variable.) $(LI $(D /tmp)) $(LI $(D /var/tmp)) $(LI $(D /usr/tmp)) ) On all platforms, $(D tempDir) returns $(D ".") on failure, representing the current working directory. The return value of the function is cached, so the procedures described above will only be performed the first time the function is called. All subsequent runs will return the same string, regardless of whether environment variables and directory structures have changed in the meantime. The POSIX $(D tempDir) algorithm is inspired by Python's $(LINK2 http://docs.python.org/library/tempfile.html#tempfile.tempdir, $(D tempfile.tempdir)). */ string tempDir() @trusted { static string cache; if (cache is null) { version(Windows) { import std.utf : toUTF8; // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx wchar[MAX_PATH + 2] buf; DWORD len = GetTempPathW(buf.length, buf.ptr); if (len) cache = toUTF8(buf[0 .. len]); } else version(Android) { // Don't check for a global temporary directory as // Android doesn't have one. } else version(Posix) { import std.process : environment; // This function looks through the list of alternative directories // and returns the first one which exists and is a directory. static string findExistingDir(T...)(lazy T alternatives) { foreach (dir; alternatives) if (!dir.empty && exists(dir)) return dir; return null; } cache = findExistingDir(environment.get("TMPDIR"), environment.get("TEMP"), environment.get("TMP"), "/tmp", "/var/tmp", "/usr/tmp"); } else static assert (false, "Unsupported platform"); if (cache is null) cache = getcwd(); } return cache; } ldc-1.1.0-beta3-src/runtime/phobos/std/range/0000775000175000017500000000000012776215007017002 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/range/package.d0000664000175000017500000077446612776215007020572 0ustar kaikai// Written in the D programming language. /** This module defines the notion of a range. Ranges generalize the concept of arrays, lists, or anything that involves sequential access. This abstraction enables the same set of algorithms (see $(LINK2 std_algorithm.html, std.algorithm)) to be used with a vast variety of different concrete types. For example, a linear search algorithm such as $(LINK2 std_algorithm.html#find, std.algorithm.find) works not just for arrays, but for linked-lists, input files, incoming network data, etc. See also Ali Çehreli's $(WEB ddili.org/ders/d.en/ranges.html, tutorial on ranges) for the basics of working with and creating range-based code. For more detailed information about the conceptual aspect of ranges and the motivation behind them, see Andrei Alexandrescu's article $(LINK2 http://www.informit.com/articles/printerfriendly.aspx?p=1407357$(AMP)rll=1, $(I On Iteration)). Submodules: This module has two submodules: The $(LINK2 std_range_primitives.html, $(D std._range.primitives)) submodule provides basic _range functionality. It defines several templates for testing whether a given object is a _range, what kind of _range it is, and provides some common _range operations. The $(LINK2 std_range_interfaces.html, $(D std._range.interfaces)) submodule provides object-based interfaces for working with ranges via runtime polymorphism. The remainder of this module provides a rich set of _range creation and composition templates that let you construct new ranges out of existing ranges: $(BOOKTABLE , $(TR $(TD $(D $(LREF chain))) $(TD Concatenates several ranges into a single _range. )) $(TR $(TD $(D $(LREF choose))) $(TD Chooses one of two ranges at runtime based on a boolean condition. )) $(TR $(TD $(D $(LREF chooseAmong))) $(TD Chooses one of several ranges at runtime based on an index. )) $(TR $(TD $(D $(LREF chunks))) $(TD Creates a _range that returns fixed-size chunks of the original _range. )) $(TR $(TD $(D $(LREF cycle))) $(TD Creates an infinite _range that repeats the given forward _range indefinitely. Good for implementing circular buffers. )) $(TR $(TD $(D $(LREF drop))) $(TD Creates the _range that results from discarding the first $(I n) elements from the given _range. )) $(TR $(TD $(D $(LREF dropExactly))) $(TD Creates the _range that results from discarding exactly $(I n) of the first elements from the given _range. )) $(TR $(TD $(D $(LREF dropOne))) $(TD Creates the _range that results from discarding the first elements from the given _range. )) $(TR $(TD $(D $(LREF enumerate))) $(TD Iterates a _range with an attached index variable. )) $(TR $(TD $(D $(LREF evenChunks))) $(TD Creates a _range that returns a number of chunks of approximately equal length from the original _range. )) $(TR $(TD $(D $(LREF frontTransversal))) $(TD Creates a _range that iterates over the first elements of the given ranges. )) $(TR $(TD $(D $(LREF indexed))) $(TD Creates a _range that offers a view of a given _range as though its elements were reordered according to a given _range of indices. )) $(TR $(TD $(D $(LREF iota))) $(TD Creates a _range consisting of numbers between a starting point and ending point, spaced apart by a given interval. )) $(TR $(TD $(D $(LREF lockstep))) $(TD Iterates $(I n) _ranges in lockstep, for use in a $(D foreach) loop. Similar to $(D zip), except that $(D lockstep) is designed especially for $(D foreach) loops. )) $(TR $(TD $(D $(LREF NullSink))) $(TD An output _range that discards the data it receives. )) $(TR $(TD $(D $(LREF only))) $(TD Creates a _range that iterates over the given arguments. )) $(TR $(TD $(D $(LREF radial))) $(TD Given a random-access _range and a starting point, creates a _range that alternately returns the next left and next right element to the starting point. )) $(TR $(TD $(D $(LREF recurrence))) $(TD Creates a forward _range whose values are defined by a mathematical recurrence relation. )) $(TR $(TD $(D $(LREF repeat))) $(TD Creates a _range that consists of a single element repeated $(I n) times, or an infinite _range repeating that element indefinitely. )) $(TR $(TD $(D $(LREF retro))) $(TD Iterates a bidirectional _range backwards. )) $(TR $(TD $(D $(LREF roundRobin))) $(TD Given $(I n) ranges, creates a new _range that return the $(I n) first elements of each _range, in turn, then the second element of each _range, and so on, in a round-robin fashion. )) $(TR $(TD $(D $(LREF sequence))) $(TD Similar to $(D recurrence), except that a random-access _range is created. )) $(TR $(TD $(D $(LREF stride))) $(TD Iterates a _range with stride $(I n). )) $(TR $(TD $(D $(LREF tail))) $(TD Return a _range advanced to within $(D n) elements of the end of the given _range. )) $(TR $(TD $(D $(LREF take))) $(TD Creates a sub-_range consisting of only up to the first $(I n) elements of the given _range. )) $(TR $(TD $(D $(LREF takeExactly))) $(TD Like $(D take), but assumes the given _range actually has $(I n) elements, and therefore also defines the $(D length) property. )) $(TR $(TD $(D $(LREF takeNone))) $(TD Creates a random-access _range consisting of zero elements of the given _range. )) $(TR $(TD $(D $(LREF takeOne))) $(TD Creates a random-access _range consisting of exactly the first element of the given _range. )) $(TR $(TD $(D $(LREF tee))) $(TD Creates a _range that wraps a given _range, forwarding along its elements while also calling a provided function with each element. )) $(TR $(TD $(D $(LREF transposed))) $(TD Transposes a _range of ranges. )) $(TR $(TD $(D $(LREF transversal))) $(TD Creates a _range that iterates over the $(I n)'th elements of the given random-access ranges. )) $(TR $(TD $(D $(LREF zip))) $(TD Given $(I n) _ranges, creates a _range that successively returns a tuple of all the first elements, a tuple of all the second elements, etc. )) ) Ranges whose elements are sorted afford better efficiency with certain operations. For this, the $(D $(LREF assumeSorted)) function can be used to construct a $(D $(LREF SortedRange)) from a pre-sorted _range. The $(LINK2 std_algorithm.html#sort, $(D std.algorithm.sort)) function also conveniently returns a $(D SortedRange). $(D SortedRange) objects provide some additional _range operations that take advantage of the fact that the _range is sorted. Source: $(PHOBOSSRC std/_range/_package.d) Macros: WIKI = Phobos/StdRange Copyright: Copyright by authors 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu), David Simcha, and Jonathan M Davis. Credit for some of the ideas in building this module goes to $(WEB fantascienza.net/leonardo/so/, Leonardo Maffi). */ module std.range; public import std.range.primitives; public import std.range.interfaces; public import std.array; public import std.typecons : Flag, Yes, No; import std.meta; import std.traits; /** Iterates a bidirectional range backwards. The original range can be accessed by using the $(D source) property. Applying retro twice to the same range yields the original range. */ auto retro(Range)(Range r) if (isBidirectionalRange!(Unqual!Range)) { // Check for retro(retro(r)) and just return r in that case static if (is(typeof(retro(r.source)) == Range)) { return r.source; } else { static struct Result() { private alias R = Unqual!Range; // User code can get and set source, too R source; static if (hasLength!R) { private alias IndexType = CommonType!(size_t, typeof(source.length)); IndexType retroIndex(IndexType n) { return source.length - n - 1; } } public: alias Source = R; @property bool empty() { return source.empty; } @property auto save() { return Result(source.save); } @property auto ref front() { return source.back; } void popFront() { source.popBack(); } @property auto ref back() { return source.front; } void popBack() { source.popFront(); } static if(is(typeof(.moveBack(source)))) { ElementType!R moveFront() { return .moveBack(source); } } static if(is(typeof(.moveFront(source)))) { ElementType!R moveBack() { return .moveFront(source); } } static if (hasAssignableElements!R) { @property auto front(ElementType!R val) { source.back = val; } @property auto back(ElementType!R val) { source.front = val; } } static if (isRandomAccessRange!(R) && hasLength!(R)) { auto ref opIndex(IndexType n) { return source[retroIndex(n)]; } static if (hasAssignableElements!R) { void opIndexAssign(ElementType!R val, IndexType n) { source[retroIndex(n)] = val; } } static if (is(typeof(.moveAt(source, 0)))) { ElementType!R moveAt(IndexType index) { return .moveAt(source, retroIndex(index)); } } static if (hasSlicing!R) typeof(this) opSlice(IndexType a, IndexType b) { return typeof(this)(source[source.length - b .. source.length - a]); } } static if (hasLength!R) { @property auto length() { return source.length; } alias opDollar = length; } } return Result!()(r); } } /// @safe unittest { import std.algorithm : equal; int[] a = [ 1, 2, 3, 4, 5 ]; assert(equal(retro(a), [ 5, 4, 3, 2, 1 ][])); assert(retro(a).source is a); assert(retro(retro(a)) is a); } @safe unittest { import std.algorithm : equal; static assert(isBidirectionalRange!(typeof(retro("hello")))); int[] a; static assert(is(typeof(a) == typeof(retro(retro(a))))); assert(retro(retro(a)) is a); static assert(isRandomAccessRange!(typeof(retro([1, 2, 3])))); void test(int[] input, int[] witness) { auto r = retro(input); assert(r.front == witness.front); assert(r.back == witness.back); assert(equal(r, witness)); } test([ 1 ], [ 1 ]); test([ 1, 2 ], [ 2, 1 ]); test([ 1, 2, 3 ], [ 3, 2, 1 ]); test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]); test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]); test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]); immutable foo = [1,2,3].idup; auto r = retro(foo); } @safe unittest { import std.internal.test.dummyrange; foreach(DummyType; AllDummyRanges) { static if (!isBidirectionalRange!DummyType) { static assert(!__traits(compiles, Retro!DummyType)); } else { DummyType dummyRange; dummyRange.reinit(); auto myRetro = retro(dummyRange); static assert(propagatesRangeType!(typeof(myRetro), DummyType)); assert(myRetro.front == 10); assert(myRetro.back == 1); assert(myRetro.moveFront() == 10); assert(myRetro.moveBack() == 1); static if (isRandomAccessRange!DummyType && hasLength!DummyType) { assert(myRetro[0] == myRetro.front); assert(myRetro.moveAt(2) == 8); static if (DummyType.r == ReturnBy.Reference) { { myRetro[9]++; scope(exit) myRetro[9]--; assert(dummyRange[0] == 2); myRetro.front++; scope(exit) myRetro.front--; assert(myRetro.front == 11); myRetro.back++; scope(exit) myRetro.back--; assert(myRetro.back == 3); } { myRetro.front = 0xFF; scope(exit) myRetro.front = 10; assert(dummyRange.back == 0xFF); myRetro.back = 0xBB; scope(exit) myRetro.back = 1; assert(dummyRange.front == 0xBB); myRetro[1] = 11; scope(exit) myRetro[1] = 8; assert(dummyRange[8] == 11); } } } } } } @safe unittest { import std.algorithm : equal; auto LL = iota(1L, 4L); auto r = retro(LL); assert(equal(r, [3L, 2L, 1L])); } // Issue 12662 @safe @nogc unittest { int[3] src = [1,2,3]; int[] data = src[]; foreach_reverse (x; data) {} foreach (x; data.retro) {} } /** Iterates range $(D r) with stride $(D n). If the range is a random-access range, moves by indexing into the range; otherwise, moves by successive calls to $(D popFront). Applying stride twice to the same range results in a stride with a step that is the product of the two applications. It is an error for $(D n) to be 0. */ auto stride(Range)(Range r, size_t n) if (isInputRange!(Unqual!Range)) in { assert(n != 0, "stride cannot have step zero."); } body { import std.algorithm : min; static if (is(typeof(stride(r.source, n)) == Range)) { // stride(stride(r, n1), n2) is stride(r, n1 * n2) return stride(r.source, r._n * n); } else { static struct Result { private alias R = Unqual!Range; public R source; private size_t _n; // Chop off the slack elements at the end static if (hasLength!R && (isRandomAccessRange!R && hasSlicing!R || isBidirectionalRange!R)) private void eliminateSlackElements() { auto slack = source.length % _n; if (slack) { slack--; } else if (!source.empty) { slack = min(_n, source.length) - 1; } else { slack = 0; } if (!slack) return; static if (isRandomAccessRange!R && hasSlicing!R) { source = source[0 .. source.length - slack]; } else static if (isBidirectionalRange!R) { foreach (i; 0 .. slack) { source.popBack(); } } } static if (isForwardRange!R) { @property auto save() { return Result(source.save, _n); } } static if (isInfinite!R) { enum bool empty = false; } else { @property bool empty() { return source.empty; } } @property auto ref front() { return source.front; } static if (is(typeof(.moveFront(source)))) { ElementType!R moveFront() { return .moveFront(source); } } static if (hasAssignableElements!R) { @property auto front(ElementType!R val) { source.front = val; } } void popFront() { static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R) { source = source[min(_n, source.length) .. source.length]; } else { static if (hasLength!R) { foreach (i; 0 .. min(source.length, _n)) { source.popFront(); } } else { foreach (i; 0 .. _n) { source.popFront(); if (source.empty) break; } } } } static if (isBidirectionalRange!R && hasLength!R) { void popBack() { popBackN(source, _n); } @property auto ref back() { eliminateSlackElements(); return source.back; } static if (is(typeof(.moveBack(source)))) { ElementType!R moveBack() { eliminateSlackElements(); return .moveBack(source); } } static if (hasAssignableElements!R) { @property auto back(ElementType!R val) { eliminateSlackElements(); source.back = val; } } } static if (isRandomAccessRange!R && hasLength!R) { auto ref opIndex(size_t n) { return source[_n * n]; } /** Forwards to $(D moveAt(source, n)). */ static if (is(typeof(.moveAt(source, 0)))) { ElementType!R moveAt(size_t n) { return .moveAt(source, _n * n); } } static if (hasAssignableElements!R) { void opIndexAssign(ElementType!R val, size_t n) { source[_n * n] = val; } } } static if (hasSlicing!R && hasLength!R) typeof(this) opSlice(size_t lower, size_t upper) { assert(upper >= lower && upper <= length); immutable translatedUpper = (upper == 0) ? 0 : (upper * _n - (_n - 1)); immutable translatedLower = min(lower * _n, translatedUpper); assert(translatedLower <= translatedUpper); return typeof(this)(source[translatedLower..translatedUpper], _n); } static if (hasLength!R) { @property auto length() { return (source.length + _n - 1) / _n; } alias opDollar = length; } } return Result(r, n); } } /// unittest { import std.algorithm : equal; int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]; assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][])); assert(stride(stride(a, 2), 3) == stride(a, 6)); } nothrow @nogc unittest { int[4] testArr = [1,2,3,4]; //just checking it compiles auto s = testArr[].stride(2); } debug unittest {//check the contract int[4] testArr = [1,2,3,4]; import std.exception : assertThrown; import core.exception : AssertError; assertThrown!AssertError(testArr[].stride(0)); } @safe unittest { import std.internal.test.dummyrange; import std.algorithm : equal; static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2)))); void test(size_t n, int[] input, int[] witness) { assert(equal(stride(input, n), witness)); } test(1, [], []); int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(stride(stride(arr, 2), 3) is stride(arr, 6)); test(1, arr, arr); test(2, arr, [1, 3, 5, 7, 9]); test(3, arr, [1, 4, 7, 10]); test(4, arr, [1, 5, 9]); // Test slicing. auto s1 = stride(arr, 1); assert(equal(s1[1..4], [2, 3, 4])); assert(s1[1..4].length == 3); assert(equal(s1[1..5], [2, 3, 4, 5])); assert(s1[1..5].length == 4); assert(s1[0..0].empty); assert(s1[3..3].empty); // assert(s1[$ .. $].empty); assert(s1[s1.opDollar .. s1.opDollar].empty); auto s2 = stride(arr, 2); assert(equal(s2[0..2], [1,3])); assert(s2[0..2].length == 2); assert(equal(s2[1..5], [3, 5, 7, 9])); assert(s2[1..5].length == 4); assert(s2[0..0].empty); assert(s2[3..3].empty); // assert(s2[$ .. $].empty); assert(s2[s2.opDollar .. s2.opDollar].empty); // Test fix for Bug 5035 auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns auto col = stride(m, 4); assert(equal(col, [1, 1, 1])); assert(equal(retro(col), [1, 1, 1])); immutable int[] immi = [ 1, 2, 3 ]; static assert(isRandomAccessRange!(typeof(stride(immi, 1)))); // Check for infiniteness propagation. static assert(isInfinite!(typeof(stride(repeat(1), 3)))); foreach(DummyType; AllDummyRanges) { DummyType dummyRange; dummyRange.reinit(); auto myStride = stride(dummyRange, 4); // Should fail if no length and bidirectional b/c there's no way // to know how much slack we have. static if (hasLength!DummyType || !isBidirectionalRange!DummyType) { static assert(propagatesRangeType!(typeof(myStride), DummyType)); } assert(myStride.front == 1); assert(myStride.moveFront() == 1); assert(equal(myStride, [1, 5, 9])); static if (hasLength!DummyType) { assert(myStride.length == 3); } static if (isBidirectionalRange!DummyType && hasLength!DummyType) { assert(myStride.back == 9); assert(myStride.moveBack() == 9); } static if (isRandomAccessRange!DummyType && hasLength!DummyType) { assert(myStride[0] == 1); assert(myStride[1] == 5); assert(myStride.moveAt(1) == 5); assert(myStride[2] == 9); static assert(hasSlicing!(typeof(myStride))); } static if (DummyType.r == ReturnBy.Reference) { // Make sure reference is propagated. { myStride.front++; scope(exit) myStride.front--; assert(dummyRange.front == 2); } { myStride.front = 4; scope(exit) myStride.front = 1; assert(dummyRange.front == 4); } static if (isBidirectionalRange!DummyType && hasLength!DummyType) { { myStride.back++; scope(exit) myStride.back--; assert(myStride.back == 10); } { myStride.back = 111; scope(exit) myStride.back = 9; assert(myStride.back == 111); } static if (isRandomAccessRange!DummyType) { { myStride[1]++; scope(exit) myStride[1]--; assert(dummyRange[4] == 6); } { myStride[1] = 55; scope(exit) myStride[1] = 5; assert(dummyRange[4] == 55); } } } } } } @safe unittest { import std.algorithm : equal; auto LL = iota(1L, 10L); auto s = stride(LL, 3); assert(equal(s, [1L, 4L, 7L])); } /** Spans multiple ranges in sequence. The function $(D chain) takes any number of ranges and returns a $(D Chain!(R1, R2,...)) object. The ranges may be different, but they must have the same element type. The result is a range that offers the $(D front), $(D popFront), and $(D empty) primitives. If all input ranges offer random access and $(D length), $(D Chain) offers them as well. If only one range is offered to $(D Chain) or $(D chain), the $(D Chain) type exits the picture by aliasing itself directly to that range's type. */ auto chain(Ranges...)(Ranges rs) if (Ranges.length > 0 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void)) { static if (Ranges.length == 1) { return rs[0]; } else { static struct Result { private: alias R = staticMap!(Unqual, Ranges); alias RvalueElementType = CommonType!(staticMap!(.ElementType, R)); private template sameET(A) { enum sameET = is(.ElementType!A == RvalueElementType); } enum bool allSameType = allSatisfy!(sameET, R); // This doesn't work yet static if (allSameType) { alias ref RvalueElementType ElementType; } else { alias ElementType = RvalueElementType; } static if (allSameType && allSatisfy!(hasLvalueElements, R)) { static ref RvalueElementType fixRef(ref RvalueElementType val) { return val; } } else { static RvalueElementType fixRef(RvalueElementType val) { return val; } } // This is the entire state R source; // TODO: use a vtable (or more) instead of linear iteration public: this(R input) { foreach (i, v; input) { source[i] = v; } } import std.meta : anySatisfy; static if (anySatisfy!(isInfinite, R)) { // Propagate infiniteness. enum bool empty = false; } else { @property bool empty() { foreach (i, Unused; R) { if (!source[i].empty) return false; } return true; } } static if (allSatisfy!(isForwardRange, R)) @property auto save() { typeof(this) result = this; foreach (i, Unused; R) { result.source[i] = result.source[i].save; } return result; } void popFront() { foreach (i, Unused; R) { if (source[i].empty) continue; source[i].popFront(); return; } } @property auto ref front() { foreach (i, Unused; R) { if (source[i].empty) continue; return fixRef(source[i].front); } assert(false); } static if (allSameType && allSatisfy!(hasAssignableElements, R)) { // @@@BUG@@@ //@property void front(T)(T v) if (is(T : RvalueElementType)) @property void front(RvalueElementType v) { foreach (i, Unused; R) { if (source[i].empty) continue; source[i].front = v; return; } assert(false); } } static if (allSatisfy!(hasMobileElements, R)) { RvalueElementType moveFront() { foreach (i, Unused; R) { if (source[i].empty) continue; return .moveFront(source[i]); } assert(false); } } static if (allSatisfy!(isBidirectionalRange, R)) { @property auto ref back() { foreach_reverse (i, Unused; R) { if (source[i].empty) continue; return fixRef(source[i].back); } assert(false); } void popBack() { foreach_reverse (i, Unused; R) { if (source[i].empty) continue; source[i].popBack(); return; } } static if (allSatisfy!(hasMobileElements, R)) { RvalueElementType moveBack() { foreach_reverse (i, Unused; R) { if (source[i].empty) continue; return .moveBack(source[i]); } assert(false); } } static if (allSameType && allSatisfy!(hasAssignableElements, R)) { @property void back(RvalueElementType v) { foreach_reverse (i, Unused; R) { if (source[i].empty) continue; source[i].back = v; return; } assert(false); } } } static if (allSatisfy!(hasLength, R)) { @property size_t length() { size_t result; foreach (i, Unused; R) { result += source[i].length; } return result; } alias opDollar = length; } static if (allSatisfy!(isRandomAccessRange, R)) { auto ref opIndex(size_t index) { foreach (i, Range; R) { static if (isInfinite!(Range)) { return source[i][index]; } else { immutable length = source[i].length; if (index < length) return fixRef(source[i][index]); index -= length; } } assert(false); } static if (allSatisfy!(hasMobileElements, R)) { RvalueElementType moveAt(size_t index) { foreach (i, Range; R) { static if (isInfinite!(Range)) { return .moveAt(source[i], index); } else { immutable length = source[i].length; if (index < length) return .moveAt(source[i], index); index -= length; } } assert(false); } } static if (allSameType && allSatisfy!(hasAssignableElements, R)) void opIndexAssign(ElementType v, size_t index) { foreach (i, Range; R) { static if (isInfinite!(Range)) { source[i][index] = v; } else { immutable length = source[i].length; if (index < length) { source[i][index] = v; return; } index -= length; } } assert(false); } } static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R)) auto opSlice(size_t begin, size_t end) { auto result = this; foreach (i, Unused; R) { immutable len = result.source[i].length; if (len < begin) { result.source[i] = result.source[i] [len .. len]; begin -= len; } else { result.source[i] = result.source[i] [begin .. len]; break; } } auto cut = length; cut = cut <= end ? 0 : cut - end; foreach_reverse (i, Unused; R) { immutable len = result.source[i].length; if (cut > len) { result.source[i] = result.source[i] [0 .. 0]; cut -= len; } else { result.source[i] = result.source[i] [0 .. len - cut]; break; } } return result; } } return Result(rs); } } /// unittest { import std.algorithm : equal; int[] arr1 = [ 1, 2, 3, 4 ]; int[] arr2 = [ 5, 6 ]; int[] arr3 = [ 7 ]; auto s = chain(arr1, arr2, arr3); assert(s.length == 7); assert(s[5] == 6); assert(equal(s, [1, 2, 3, 4, 5, 6, 7][])); } @safe unittest { import std.internal.test.dummyrange; import std.algorithm : equal; { int[] arr1 = [ 1, 2, 3, 4 ]; int[] arr2 = [ 5, 6 ]; int[] arr3 = [ 7 ]; int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ]; auto s1 = chain(arr1); static assert(isRandomAccessRange!(typeof(s1))); auto s2 = chain(arr1, arr2); static assert(isBidirectionalRange!(typeof(s2))); static assert(isRandomAccessRange!(typeof(s2))); s2.front = 1; auto s = chain(arr1, arr2, arr3); assert(s[5] == 6); assert(equal(s, witness)); assert(s[5] == 6); } { int[] arr1 = [ 1, 2, 3, 4 ]; int[] witness = [ 1, 2, 3, 4 ]; assert(equal(chain(arr1), witness)); } { uint[] foo = [1,2,3,4,5]; uint[] bar = [1,2,3,4,5]; auto c = chain(foo, bar); c[3] = 42; assert(c[3] == 42); assert(c.moveFront() == 1); assert(c.moveBack() == 5); assert(c.moveAt(4) == 5); assert(c.moveAt(5) == 1); } // Make sure bug 3311 is fixed. ChainImpl should compile even if not all // elements are mutable. auto c = chain( iota(0, 10), iota(0, 10) ); // Test the case where infinite ranges are present. auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range assert(inf[0] == 0); assert(inf[3] == 4); assert(inf[6] == 4); assert(inf[7] == 5); static assert(isInfinite!(typeof(inf))); immutable int[] immi = [ 1, 2, 3 ]; immutable float[] immf = [ 1, 2, 3 ]; static assert(is(typeof(chain(immi, immf)))); // Check that chain at least instantiates and compiles with every possible // pair of DummyRange types, in either order. foreach(DummyType1; AllDummyRanges) { DummyType1 dummy1; foreach(DummyType2; AllDummyRanges) { DummyType2 dummy2; auto myChain = chain(dummy1, dummy2); static assert( propagatesRangeType!(typeof(myChain), DummyType1, DummyType2) ); assert(myChain.front == 1); foreach(i; 0..dummyLength) { myChain.popFront(); } assert(myChain.front == 1); static if (isBidirectionalRange!DummyType1 && isBidirectionalRange!DummyType2) { assert(myChain.back == 10); } static if (isRandomAccessRange!DummyType1 && isRandomAccessRange!DummyType2) { assert(myChain[0] == 1); } static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2) { static assert(hasLvalueElements!(typeof(myChain))); } else { static assert(!hasLvalueElements!(typeof(myChain))); } } } } @safe unittest { class Foo{} immutable(Foo)[] a; immutable(Foo)[] b; auto c = chain(a, b); } /** Choose one of two ranges at runtime depending on a Boolean condition. The ranges may be different, but they must have compatible element types (i.e. $(D CommonType) must exist for the two element types). The result is a range that offers the weakest capabilities of the two (e.g. $(D ForwardRange) if $(D R1) is a random-access range and $(D R2) is a forward range). Params: condition = which range to choose: $(D r1) if $(D true), $(D r2) otherwise r1 = the "true" range r2 = the "false" range Returns: A range type dependent on $(D R1) and $(D R2). Bugs: $(BUGZILLA 14660) */ auto choose(R1, R2)(bool condition, R1 r1, R2 r2) if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) && !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void)) { static struct Result { import std.algorithm : max; import std.algorithm.internal : addressOf; private union { void[max(R1.sizeof, R2.sizeof)] buffer = void; void* forAlignmentOnly = void; } private bool condition; private @property ref R1 r1() { assert(condition); return *cast(R1*) buffer.ptr; } private @property ref R2 r2() { assert(!condition); return *cast(R2*) buffer.ptr; } this(bool condition, R1 r1, R2 r2) { this.condition = condition; import std.conv : emplace; if (condition) emplace(addressOf(this.r1), r1); else emplace(addressOf(this.r2), r2); } // Carefully defined postblit to postblit the appropriate range static if (hasElaborateCopyConstructor!R1 || hasElaborateCopyConstructor!R2) this(this) { if (condition) { static if (hasElaborateCopyConstructor!R1) r1.__postblit(); } else { static if (hasElaborateCopyConstructor!R2) r2.__postblit(); } } static if (hasElaborateDestructor!R1 || hasElaborateDestructor!R2) ~this() { if (condition) destroy(r1); else destroy(r2); } static if (isInfinite!R1 && isInfinite!R2) // Propagate infiniteness. enum bool empty = false; else @property bool empty() { return condition ? r1.empty : r2.empty; } @property auto ref front() { return condition ? r1.front : r2.front; } void popFront() { return condition ? r1.popFront : r2.popFront; } static if (isForwardRange!R1 && isForwardRange!R2) @property auto save() { auto result = this; if (condition) r1 = r1.save; else r2 = r2.save; return result; } @property void front(T)(T v) if (is(typeof({ r1.front = v; r2.front = v; }))) { if (condition) r1.front = v; else r2.front = v; } static if (hasMobileElements!R1 && hasMobileElements!R2) auto moveFront() { return condition ? r1.moveFront : r2.moveFront; } static if (isBidirectionalRange!R1 && isBidirectionalRange!R2) { @property auto ref back() { return condition ? r1.back : r2.back; } void popBack() { return condition ? r1.popBack : r2.popBack; } static if (hasMobileElements!R1 && hasMobileElements!R2) auto moveBack() { return condition ? r1.moveBack : r2.moveBack; } @property void back(T)(T v) if (is(typeof({ r1.back = v; r2.back = v; }))) { if (condition) r1.back = v; else r2.back = v; } } static if (hasLength!R1 && hasLength!R2) { @property size_t length() { return condition ? r1.length : r2.length; } alias opDollar = length; } static if (isRandomAccessRange!R1 && isRandomAccessRange!R2) { auto ref opIndex(size_t index) { return condition ? r1[index] : r2[index]; } static if (hasMobileElements!R1 && hasMobileElements!R2) auto moveAt(size_t index) { return condition ? r1.moveAt(index) : r2.moveAt(index); } void opIndexAssign(T)(T v, size_t index) if (is(typeof({ r1[1] = v; r2[1] = v; }))) { if (condition) r1[index] = v; else r2[index] = v; } } // BUG: this should work for infinite ranges, too static if (hasSlicing!R1 && hasSlicing!R2 && !isInfinite!R2 && !isInfinite!R2) auto opSlice(size_t begin, size_t end) { auto result = this; if (condition) result.r1 = result.r1[begin .. end]; else result.r2 = result.r2[begin .. end]; return result; } } return Result(condition, r1, r2); } /// unittest { import std.algorithm.iteration : filter, map; import std.algorithm.comparison : equal; auto data1 = [ 1, 2, 3, 4 ].filter!(a => a != 3); auto data2 = [ 5, 6, 7, 8 ].map!(a => a + 1); // choose() is primarily useful when you need to select one of two ranges // with different types at runtime. static assert(!is(typeof(data1) == typeof(data2))); auto chooseRange(bool pickFirst) { // The returned range is a common wrapper type that can be used for // returning or storing either range without running into a type error. return choose(pickFirst, data1, data2); // Simply returning the chosen range without using choose() does not // work, because map() and filter() return different types. //return pickFirst ? data1 : data2; // does not compile } auto result = chooseRange(true); assert(result.equal([ 1, 2, 4 ])); result = chooseRange(false); assert(result.equal([ 6, 7, 8, 9 ])); } /** Choose one of multiple ranges at runtime. The ranges may be different, but they must have compatible element types. The result is a range that offers the weakest capabilities of all $(D Ranges). Params: index = which range to choose, must be less than the number of ranges rs = two or more ranges Returns: The indexed range. If rs consists of only one range, the return type is an alias of that range's type. */ auto chooseAmong(Ranges...)(size_t index, Ranges rs) if (Ranges.length > 2 && is(typeof(choose(true, rs[0], rs[1]))) && is(typeof(chooseAmong(0, rs[1 .. $])))) { return choose(index == 0, rs[0], chooseAmong(index - 1, rs[1 .. $])); } /// ditto auto chooseAmong(Ranges...)(size_t index, Ranges rs) if (Ranges.length == 2 && is(typeof(choose(true, rs[0], rs[1])))) { return choose(index == 0, rs[0], rs[1]); } /// unittest { import std.algorithm : equal; int[] arr1 = [ 1, 2, 3, 4 ]; int[] arr2 = [ 5, 6 ]; int[] arr3 = [ 7 ]; { auto s = chooseAmong(0, arr1, arr2, arr3); auto t = s.save; assert(s.length == 4); assert(s[2] == 3); s.popFront(); assert(equal(t, [1, 2, 3, 4][])); } { auto s = chooseAmong(1, arr1, arr2, arr3); assert(s.length == 2); s.front = 8; assert(equal(s, [8, 6][])); } { auto s = chooseAmong(1, arr1, arr2, arr3); assert(s.length == 2); s[1] = 9; assert(equal(s, [8, 9][])); } { auto s = chooseAmong(1, arr2, arr1, arr3)[1..3]; assert(s.length == 2); assert(equal(s, [2, 3][])); } { auto s = chooseAmong(0, arr1, arr2, arr3); assert(s.length == 4); assert(s.back == 4); s.popBack(); s.back = 5; assert(equal(s, [1, 2, 5][])); s.back = 3; assert(equal(s, [1, 2, 3][])); } { uint[] foo = [1,2,3,4,5]; uint[] bar = [6,7,8,9,10]; auto c = chooseAmong(1,foo, bar); assert(c[3] == 9); c[3] = 42; assert(c[3] == 42); assert(c.moveFront() == 6); assert(c.moveBack() == 10); assert(c.moveAt(4) == 10); } { import std.range : cycle; auto s = chooseAmong(1, cycle(arr2), cycle(arr3)); assert(isInfinite!(typeof(s))); assert(!s.empty); assert(s[100] == 7); } } unittest { int[] a = [1, 2, 3]; long[] b = [4, 5, 6]; auto c = chooseAmong(0, a, b); c[0] = 42; assert(c[0] == 42); } /** $(D roundRobin(r1, r2, r3)) yields $(D r1.front), then $(D r2.front), then $(D r3.front), after which it pops off one element from each and continues again from $(D r1). For example, if two ranges are involved, it alternately yields elements off the two ranges. $(D roundRobin) stops after it has consumed all ranges (skipping over the ones that finish early). */ auto roundRobin(Rs...)(Rs rs) if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs))) { struct Result { import std.conv : to; public Rs source; private size_t _current = size_t.max; @property bool empty() { foreach (i, Unused; Rs) { if (!source[i].empty) return false; } return true; } @property auto ref front() { final switch (_current) { foreach (i, R; Rs) { case i: assert(!source[i].empty); return source[i].front; } } assert(0); } void popFront() { final switch (_current) { foreach (i, R; Rs) { case i: source[i].popFront(); break; } } auto next = _current == (Rs.length - 1) ? 0 : (_current + 1); final switch (next) { foreach (i, R; Rs) { case i: if (!source[i].empty) { _current = i; return; } if (i == _current) { _current = _current.max; return; } goto case (i + 1) % Rs.length; } } } static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs))) @property auto save() { Result result = this; foreach (i, Unused; Rs) { result.source[i] = result.source[i].save; } return result; } static if (allSatisfy!(hasLength, Rs)) { @property size_t length() { size_t result; foreach (i, R; Rs) { result += source[i].length; } return result; } alias opDollar = length; } } return Result(rs, 0); } /// @safe unittest { import std.algorithm : equal; int[] a = [ 1, 2, 3 ]; int[] b = [ 10, 20, 30, 40 ]; auto r = roundRobin(a, b); assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ])); } /** Iterates a random-access range starting from a given point and progressively extending left and right from that point. If no initial point is given, iteration starts from the middle of the range. Iteration spans the entire range. */ auto radial(Range, I)(Range r, I startingIndex) if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && isIntegral!I) { if (!r.empty) ++startingIndex; return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]); } /// Ditto auto radial(R)(R r) if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R)) { return .radial(r, (r.length - !r.empty) / 2); } /// @safe unittest { import std.algorithm : equal; int[] a = [ 1, 2, 3, 4, 5 ]; assert(equal(radial(a), [ 3, 4, 2, 5, 1 ])); a = [ 1, 2, 3, 4 ]; assert(equal(radial(a), [ 2, 3, 1, 4 ])); // If the left end is reached first, the remaining elements on the right // are concatenated in order: a = [ 0, 1, 2, 3, 4, 5 ]; assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ])); // If the right end is reached first, the remaining elements on the left // are concatenated in reverse order: assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ])); } @safe unittest { import std.conv : text; import std.exception : enforce; import std.algorithm : equal; import std.internal.test.dummyrange; void test(int[] input, int[] witness) { enforce(equal(radial(input), witness), text(radial(input), " vs. ", witness)); } test([], []); test([ 1 ], [ 1 ]); test([ 1, 2 ], [ 1, 2 ]); test([ 1, 2, 3 ], [ 2, 3, 1 ]); test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]); test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]); test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]); int[] a = [ 1, 2, 3, 4, 5 ]; assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ][])); static assert(isForwardRange!(typeof(radial(a, 1)))); auto r = radial([1,2,3,4,5]); for(auto rr = r.save; !rr.empty; rr.popFront()) { assert(rr.front == moveFront(rr)); } r.front = 5; assert(r.front == 5); // Test instantiation without lvalue elements. DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy; assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10])); // immutable int[] immi = [ 1, 2 ]; // static assert(is(typeof(radial(immi)))); } @safe unittest { import std.algorithm : equal; auto LL = iota(1L, 6L); auto r = radial(LL); assert(equal(r, [3L, 4L, 2L, 5L, 1L])); } /** Lazily takes only up to $(D n) elements of a range. This is particularly useful when using with infinite ranges. If the range offers random access and $(D length), $(D Take) offers them as well. */ struct Take(Range) if (isInputRange!(Unqual!Range) && //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses //take for slicing infinite ranges. !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T))) { private alias R = Unqual!Range; // User accessible in read and write public R source; private size_t _maxAvailable; alias Source = R; @property bool empty() { return _maxAvailable == 0 || source.empty; } @property auto ref front() { assert(!empty, "Attempting to fetch the front of an empty " ~ Take.stringof); return source.front; } void popFront() { assert(!empty, "Attempting to popFront() past the end of a " ~ Take.stringof); source.popFront(); --_maxAvailable; } static if (isForwardRange!R) @property Take save() { return Take(source.save, _maxAvailable); } static if (hasAssignableElements!R) @property auto front(ElementType!R v) { assert(!empty, "Attempting to assign to the front of an empty " ~ Take.stringof); // This has to return auto instead of void because of Bug 4706. source.front = v; } static if (hasMobileElements!R) { auto moveFront() { assert(!empty, "Attempting to move the front of an empty " ~ Take.stringof); return .moveFront(source); } } static if (isInfinite!R) { @property size_t length() const { return _maxAvailable; } alias opDollar = length; //Note: Due to Take/hasSlicing circular dependency, //This needs to be a restrained template. auto opSlice()(size_t i, size_t j) if (hasSlicing!R) { assert(i <= j, "Invalid slice bounds"); assert(j - i <= length, "Attempting to slice past the end of a " ~ Take.stringof); return source[i .. j - i]; } } else static if (hasLength!R) { @property size_t length() { import std.algorithm : min; return min(_maxAvailable, source.length); } alias opDollar = length; } static if (isRandomAccessRange!R) { void popBack() { assert(!empty, "Attempting to popBack() past the beginning of a " ~ Take.stringof); --_maxAvailable; } @property auto ref back() { assert(!empty, "Attempting to fetch the back of an empty " ~ Take.stringof); return source[this.length - 1]; } auto ref opIndex(size_t index) { assert(index < length, "Attempting to index out of the bounds of a " ~ Take.stringof); return source[index]; } static if (hasAssignableElements!R) { @property auto back(ElementType!R v) { // This has to return auto instead of void because of Bug 4706. assert(!empty, "Attempting to assign to the back of an empty " ~ Take.stringof); source[this.length - 1] = v; } void opIndexAssign(ElementType!R v, size_t index) { assert(index < length, "Attempting to index out of the bounds of a " ~ Take.stringof); source[index] = v; } } static if (hasMobileElements!R) { auto moveBack() { assert(!empty, "Attempting to move the back of an empty " ~ Take.stringof); return .moveAt(source, this.length - 1); } auto moveAt(size_t index) { assert(index < length, "Attempting to index out of the bounds of a " ~ Take.stringof); return .moveAt(source, index); } } } // Nonstandard @property size_t maxLength() const { return _maxAvailable; } } // This template simply aliases itself to R and is useful for consistency in // generic code. template Take(R) if (isInputRange!(Unqual!R) && ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T))) { alias Take = R; } // take for finite ranges with slicing /// ditto Take!R take(R)(R input, size_t n) if (isInputRange!(Unqual!R) && !isInfinite!(Unqual!R) && hasSlicing!(Unqual!R) && !is(R T == Take!T)) { // @@@BUG@@@ //return input[0 .. min(n, $)]; import std.algorithm : min; return input[0 .. min(n, input.length)]; } /// @safe unittest { import std.algorithm : equal; int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; auto s = take(arr1, 5); assert(s.length == 5); assert(s[4] == 5); assert(equal(s, [ 1, 2, 3, 4, 5 ][])); } /** * If the range runs out before `n` elements, `take` simply returns the entire * range (unlike $(LREF takeExactly), which will cause an assertion failure if * the range ends prematurely): */ @safe unittest { import std.algorithm : equal; int[] arr2 = [ 1, 2, 3 ]; auto t = take(arr2, 5); assert(t.length == 3); assert(equal(t, [ 1, 2, 3 ])); } // take(take(r, n1), n2) Take!R take(R)(R input, size_t n) if (is(R T == Take!T)) { import std.algorithm : min; return R(input.source, min(n, input._maxAvailable)); } // Regular take for input ranges Take!(R) take(R)(R input, size_t n) if (isInputRange!(Unqual!R) && (isInfinite!(Unqual!R) || !hasSlicing!(Unqual!R) && !is(R T == Take!T))) { return Take!R(input, n); } @safe unittest { import std.internal.test.dummyrange; import std.algorithm : equal; int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; auto s = take(arr1, 5); assert(s.length == 5); assert(s[4] == 5); assert(equal(s, [ 1, 2, 3, 4, 5 ][])); assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][])); // Test fix for bug 4464. static assert(is(typeof(s) == Take!(int[]))); static assert(is(typeof(s) == int[])); // Test using narrow strings. auto myStr = "This is a string."; auto takeMyStr = take(myStr, 7); assert(equal(takeMyStr, "This is")); // Test fix for bug 5052. auto takeMyStrAgain = take(takeMyStr, 4); assert(equal(takeMyStrAgain, "This")); static assert (is (typeof(takeMyStrAgain) == typeof(takeMyStr))); takeMyStrAgain = take(takeMyStr, 10); assert(equal(takeMyStrAgain, "This is")); foreach(DummyType; AllDummyRanges) { DummyType dummy; auto t = take(dummy, 5); alias T = typeof(t); static if (isRandomAccessRange!DummyType) { static assert(isRandomAccessRange!T); assert(t[4] == 5); assert(moveAt(t, 1) == t[1]); assert(t.back == moveBack(t)); } else static if (isForwardRange!DummyType) { static assert(isForwardRange!T); } for(auto tt = t; !tt.empty; tt.popFront()) { assert(tt.front == moveFront(tt)); } // Bidirectional ranges can't be propagated properly if they don't // also have random access. assert(equal(t, [1,2,3,4,5])); //Test that take doesn't wrap the result of take. assert(take(t, 4) == take(dummy, 4)); } immutable myRepeat = repeat(1); static assert(is(Take!(typeof(myRepeat)))); } @safe unittest { // Check that one can declare variables of all Take types, // and that they match the return type of the corresponding // take(). (See issue 4464.) int[] r1; Take!(int[]) t1; t1 = take(r1, 1); string r2; Take!string t2; t2 = take(r2, 1); Take!(Take!string) t3; t3 = take(t2, 1); } @safe unittest { alias R1 = typeof(repeat(1)); alias R2 = typeof(cycle([1])); alias TR1 = Take!R1; alias TR2 = Take!R2; static assert(isBidirectionalRange!TR1); static assert(isBidirectionalRange!TR2); } @safe unittest //12731 { auto a = repeat(1); auto s = a[1 .. 5]; s = s[1 .. 3]; } @safe unittest //13151 { import std.algorithm : equal; auto r = take(repeat(1, 4), 3); assert(r.take(2).equal(repeat(1, 2))); } /** Similar to $(LREF take), but assumes that $(D range) has at least $(D n) elements. Consequently, the result of $(D takeExactly(range, n)) always defines the $(D length) property (and initializes it to $(D n)) even when $(D range) itself does not define $(D length). The result of $(D takeExactly) is identical to that of $(LREF take) in cases where the original range defines $(D length) or is infinite. Unlike $(LREF take), however, it is illegal to pass a range with less than $(D n) elements to $(D takeExactly); this will cause an assertion failure. */ auto takeExactly(R)(R range, size_t n) if (isInputRange!R) { static if (is(typeof(takeExactly(range._input, n)) == R)) { assert(n <= range._n, "Attempted to take more than the length of the range with takeExactly."); // takeExactly(takeExactly(r, n1), n2) has the same type as // takeExactly(r, n1) and simply returns takeExactly(r, n2) range._n = n; return range; } //Also covers hasSlicing!R for finite ranges. else static if (hasLength!R) { assert(n <= range.length, "Attempted to take more than the length of the range with takeExactly."); return take(range, n); } else static if (isInfinite!R) return Take!R(range, n); else { static struct Result { R _input; private size_t _n; @property bool empty() const { return !_n; } @property auto ref front() { assert(_n > 0, "front() on an empty " ~ Result.stringof); return _input.front; } void popFront() { _input.popFront(); --_n; } @property size_t length() const { return _n; } alias opDollar = length; @property Take!R _takeExactly_Result_asTake() { return typeof(return)(_input, _n); } alias _takeExactly_Result_asTake this; static if (isForwardRange!R) @property auto save() { return Result(_input.save, _n); } static if (hasMobileElements!R) { auto moveFront() { assert(!empty, "Attempting to move the front of an empty " ~ typeof(this).stringof); return .moveFront(_input); } } static if (hasAssignableElements!R) { @property auto ref front(ElementType!R v) { assert(!empty, "Attempting to assign to the front of an empty " ~ typeof(this).stringof); return _input.front = v; } } } return Result(range, n); } } /// @safe unittest { import std.algorithm : equal; auto a = [ 1, 2, 3, 4, 5 ]; auto b = takeExactly(a, 3); assert(equal(b, [1, 2, 3])); static assert(is(typeof(b.length) == size_t)); assert(b.length == 3); assert(b.front == 1); assert(b.back == 3); } @safe unittest { import std.algorithm : equal, filter; auto a = [ 1, 2, 3, 4, 5 ]; auto b = takeExactly(a, 3); auto c = takeExactly(b, 2); auto d = filter!"a > 0"(a); auto e = takeExactly(d, 3); assert(equal(e, [1, 2, 3])); static assert(is(typeof(e.length) == size_t)); assert(e.length == 3); assert(e.front == 1); assert(equal(takeExactly(e, 3), [1, 2, 3])); } @safe unittest { import std.algorithm : equal; import std.internal.test.dummyrange; auto a = [ 1, 2, 3, 4, 5 ]; //Test that take and takeExactly are the same for ranges which define length //but aren't sliceable. struct L { @property auto front() { return _arr[0]; } @property bool empty() { return _arr.empty; } void popFront() { _arr.popFront(); } @property size_t length() { return _arr.length; } int[] _arr; } static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3)))); assert(take(L(a), 3) == takeExactly(L(a), 3)); //Test that take and takeExactly are the same for ranges which are sliceable. static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3)))); assert(take(a, 3) == takeExactly(a, 3)); //Test that take and takeExactly are the same for infinite ranges. auto inf = repeat(1); static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf)))); assert(take(inf, 5) == takeExactly(inf, 5)); //Test that take and takeExactly are _not_ the same for ranges which don't //define length. static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3)))); foreach(DummyType; AllDummyRanges) { { DummyType dummy; auto t = takeExactly(dummy, 5); //Test that takeExactly doesn't wrap the result of takeExactly. assert(takeExactly(t, 4) == takeExactly(dummy, 4)); } static if(hasMobileElements!DummyType) { { auto t = takeExactly(DummyType.init, 4); assert(t.moveFront() == 1); assert(equal(t, [1, 2, 3, 4])); } } static if(hasAssignableElements!DummyType) { { auto t = takeExactly(DummyType.init, 4); t.front = 9; assert(equal(t, [9, 2, 3, 4])); } } } } @safe unittest { import std.algorithm : equal; import std.internal.test.dummyrange; alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward); auto te = takeExactly(DummyType(), 5); Take!DummyType t = te; assert(equal(t, [1, 2, 3, 4, 5])); assert(equal(t, te)); } /** Returns a range with at most one element; for example, $(D takeOne([42, 43, 44])) returns a range consisting of the integer $(D 42). Calling $(D popFront()) off that range renders it empty. In effect $(D takeOne(r)) is somewhat equivalent to $(D take(r, 1)) but in certain interfaces it is important to know statically that the range may only have at most one element. The type returned by $(D takeOne) is a random-access range with length regardless of $(D R)'s capabilities (another feature that distinguishes $(D takeOne) from $(D take)). */ auto takeOne(R)(R source) if (isInputRange!R) { static if (hasSlicing!R) { return source[0 .. !source.empty]; } else { static struct Result { private R _source; private bool _empty = true; @property bool empty() const { return _empty; } @property auto ref front() { assert(!empty); return _source.front; } void popFront() { assert(!empty); _empty = true; } void popBack() { assert(!empty); _empty = true; } static if (isForwardRange!(Unqual!R)) { @property auto save() { return Result(_source.save, empty); } } @property auto ref back() { assert(!empty); return _source.front; } @property size_t length() const { return !empty; } alias opDollar = length; auto ref opIndex(size_t n) { assert(n < length); return _source.front; } auto opSlice(size_t m, size_t n) { assert(m <= n && n < length); return n > m ? this : Result(_source, false); } // Non-standard property @property R source() { return _source; } } return Result(source, source.empty); } } /// @safe unittest { auto s = takeOne([42, 43, 44]); static assert(isRandomAccessRange!(typeof(s))); assert(s.length == 1); assert(!s.empty); assert(s.front == 42); s.front = 43; assert(s.front == 43); assert(s.back == 43); assert(s[0] == 43); s.popFront(); assert(s.length == 0); assert(s.empty); } unittest { struct NonForwardRange { enum empty = false; int front() { return 42; } void popFront() {} } static assert(!isForwardRange!NonForwardRange); auto s = takeOne(NonForwardRange()); assert(s.front == 42); } /++ Returns an empty range which is statically known to be empty and is guaranteed to have $(D length) and be random access regardless of $(D R)'s capabilities. +/ auto takeNone(R)() if(isInputRange!R) { return typeof(takeOne(R.init)).init; } /// @safe unittest { auto range = takeNone!(int[])(); assert(range.length == 0); assert(range.empty); } @safe unittest { enum ctfe = takeNone!(int[])(); static assert(ctfe.length == 0); static assert(ctfe.empty); } /++ Creates an empty range from the given range in $(BIGOH 1). If it can, it will return the same range type. If not, it will return $(D takeExactly(range, 0)). +/ auto takeNone(R)(R range) if(isInputRange!R) { //Makes it so that calls to takeNone which don't use UFCS still work with a //member version if it's defined. static if(is(typeof(R.takeNone))) auto retval = range.takeNone(); //@@@BUG@@@ 8339 else static if(isDynamicArray!R)/+ || (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/ { auto retval = R.init; } //An infinite range sliced at [0 .. 0] would likely still not be empty... else static if(hasSlicing!R && !isInfinite!R) auto retval = range[0 .. 0]; else auto retval = takeExactly(range, 0); //@@@BUG@@@ 7892 prevents this from being done in an out block. assert(retval.empty); return retval; } /// @safe unittest { import std.algorithm : filter; assert(takeNone([42, 27, 19]).empty); assert(takeNone("dlang.org").empty); assert(takeNone(filter!"true"([42, 27, 19])).empty); } @safe unittest { import std.algorithm : filter; struct Dummy { mixin template genInput() { @property bool empty() { return _arr.empty; } @property auto front() { return _arr.front; } void popFront() { _arr.popFront(); } static assert(isInputRange!(typeof(this))); } } alias genInput = Dummy.genInput; static struct NormalStruct { //Disabled to make sure that the takeExactly version is used. @disable this(); this(int[] arr) { _arr = arr; } mixin genInput; int[] _arr; } static struct SliceStruct { @disable this(); this(int[] arr) { _arr = arr; } mixin genInput; @property auto save() { return this; } auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); } @property size_t length() { return _arr.length; } int[] _arr; } static struct InitStruct { mixin genInput; int[] _arr; } static struct TakeNoneStruct { this(int[] arr) { _arr = arr; } @disable this(); mixin genInput; auto takeNone() { return typeof(this)(null); } int[] _arr; } static class NormalClass { this(int[] arr) {_arr = arr;} mixin genInput; int[] _arr; } static class SliceClass { this(int[] arr) { _arr = arr; } mixin genInput; @property auto save() { return new typeof(this)(_arr); } auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); } @property size_t length() { return _arr.length; } int[] _arr; } static class TakeNoneClass { this(int[] arr) { _arr = arr; } mixin genInput; auto takeNone() { return new typeof(this)(null); } int[] _arr; } import std.format : format; foreach(range; AliasSeq!([1, 2, 3, 4, 5], "hello world", "hello world"w, "hello world"d, SliceStruct([1, 2, 3]), //@@@BUG@@@ 8339 forces this to be takeExactly //`InitStruct([1, 2, 3]), TakeNoneStruct([1, 2, 3]))) { static assert(takeNone(range).empty, typeof(range).stringof); assert(takeNone(range).empty); static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof); } foreach(range; AliasSeq!(NormalStruct([1, 2, 3]), InitStruct([1, 2, 3]))) { static assert(takeNone(range).empty, typeof(range).stringof); assert(takeNone(range).empty); static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof); } //Don't work in CTFE. auto normal = new NormalClass([1, 2, 3]); assert(takeNone(normal).empty); static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof); auto slice = new SliceClass([1, 2, 3]); assert(takeNone(slice).empty); static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof); auto taken = new TakeNoneClass([1, 2, 3]); assert(takeNone(taken).empty); static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof); auto filtered = filter!"true"([1, 2, 3, 4, 5]); assert(takeNone(filtered).empty); //@@@BUG@@@ 8339 and 5941 force this to be takeExactly //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof); } /++ + Return a _range advanced to within $(D _n) elements of the end of + $(D _range). + + Intended as the _range equivalent of the Unix + $(WEB en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length + of $(D _range) is less than or equal to $(D _n), $(D _range) is returned + as-is. + + Completes in $(BIGOH 1) steps for ranges that support slicing and have + length. Completes in $(BIGOH _range.length) time for all other ranges. + + Params: + range = _range to get _tail of + n = maximum number of elements to include in _tail + + Returns: + Returns the _tail of $(D _range) augmented with length information +/ auto tail(Range)(Range range, size_t n) if (isInputRange!Range && !isInfinite!Range && (hasLength!Range || isForwardRange!Range)) { static if (hasLength!Range) { immutable length = range.length; if (n >= length) return range.takeExactly(length); else return range.drop(length - n).takeExactly(n); } else { Range scout = range.save; foreach (immutable i; 0 .. n) { if (scout.empty) return range.takeExactly(i); scout.popFront(); } auto tail = range.save; while (!scout.empty) { assert(!tail.empty); scout.popFront(); tail.popFront(); } return tail.takeExactly(n); } } /// pure @safe unittest { // tail -c n assert([1, 2, 3].tail(1) == [3]); assert([1, 2, 3].tail(2) == [2, 3]); assert([1, 2, 3].tail(3) == [1, 2, 3]); assert([1, 2, 3].tail(4) == [1, 2, 3]); assert([1, 2, 3].tail(0).length == 0); // tail --lines=n import std.algorithm.comparison : equal; import std.algorithm.iteration : joiner; import std.string : lineSplitter; assert("one\ntwo\nthree" .lineSplitter .tail(2) .joiner("\n") .equal("two\nthree")); } // @nogc prevented by @@@BUG@@@ 15408 pure nothrow @safe /+@nogc+/ unittest { import std.algorithm.comparison : equal; import std.internal.test.dummyrange; static immutable cheatsheet = [6, 7, 8, 9, 10]; foreach (R; AllDummyRanges) { static if (isInputRange!R && !isInfinite!R && (hasLength!R || isForwardRange!R)) { assert(R.init.tail(5).equal(cheatsheet)); static assert(R.init.tail(5).equal(cheatsheet)); assert(R.init.tail(0).length == 0); assert(R.init.tail(10).equal(R.init)); assert(R.init.tail(11).equal(R.init)); } } // Infinite ranges are not supported static assert(!__traits(compiles, repeat(0).tail(0))); // Neither are non-forward ranges without length static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No, RangeType.Input).init.tail(5))); } @nogc unittest { static immutable input = [1, 2, 3]; static immutable expectedOutput = [2, 3]; assert(input.tail(2) == expectedOutput); } /++ Convenience function which calls $(D range.$(LREF popFrontN)(n)) and returns $(D range). $(D drop) makes it easier to pop elements from a range and then pass it to another function within a single expression, whereas $(D popFrontN) would require multiple statements. $(D dropBack) provides the same functionality but instead calls $(D range.popBackN(n)). Note: $(D drop) and $(D dropBack) will only pop $(I up to) $(D n) elements but will stop if the range is empty first. +/ R drop(R)(R range, size_t n) if(isInputRange!R) { range.popFrontN(n); return range; } /// ditto R dropBack(R)(R range, size_t n) if(isBidirectionalRange!R) { range.popBackN(n); return range; } /// @safe unittest { import std.algorithm : equal; assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]); assert("hello world".drop(6) == "world"); assert("hello world".drop(50).empty); assert("hello world".take(6).drop(3).equal("lo ")); } @safe unittest { import std.algorithm : equal; assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]); assert("hello world".dropBack(6) == "hello"); assert("hello world".dropBack(50).empty); assert("hello world".drop(4).dropBack(4).equal("o w")); } @safe unittest { import std.algorithm : equal; import std.container.dlist; //Remove all but the first two elements auto a = DList!int(0, 1, 9, 9, 9, 9); a.remove(a[].drop(2)); assert(a[].equal(a[].take(2))); } @safe unittest { import std.algorithm : equal, filter; assert(drop("", 5).empty); assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3])); } @safe unittest { import std.algorithm : equal; import std.container.dlist; //insert before the last two elements auto a = DList!int(0, 1, 2, 5, 6); a.insertAfter(a[].dropBack(2), [3, 4]); assert(a[].equal(iota(0, 7))); } /++ Similar to $(LREF drop) and $(D dropBack) but they call $(D range.$(LREF popFrontExactly)(n)) and $(D range.popBackExactly(n)) instead. Note: Unlike $(D drop), $(D dropExactly) will assume that the range holds at least $(D n) elements. This makes $(D dropExactly) faster than $(D drop), but it also means that if $(D range) does not contain at least $(D n) elements, it will attempt to call $(D popFront) on an empty range, which is undefined behavior. So, only use $(D popFrontExactly) when it is guaranteed that $(D range) holds at least $(D n) elements. +/ R dropExactly(R)(R range, size_t n) if(isInputRange!R) { popFrontExactly(range, n); return range; } /// ditto R dropBackExactly(R)(R range, size_t n) if(isBidirectionalRange!R) { popBackExactly(range, n); return range; } /// @safe unittest { import std.algorithm : equal, filterBidirectional; auto a = [1, 2, 3]; assert(a.dropExactly(2) == [3]); assert(a.dropBackExactly(2) == [1]); string s = "日本語"; assert(s.dropExactly(2) == "語"); assert(s.dropBackExactly(2) == "日"); auto bd = filterBidirectional!"true"([1, 2, 3]); assert(bd.dropExactly(2).equal([3])); assert(bd.dropBackExactly(2).equal([1])); } /++ Convenience function which calls $(D range.popFront()) and returns $(D range). $(D dropOne) makes it easier to pop an element from a range and then pass it to another function within a single expression, whereas $(D popFront) would require multiple statements. $(D dropBackOne) provides the same functionality but instead calls $(D range.popBack()). +/ R dropOne(R)(R range) if (isInputRange!R) { range.popFront(); return range; } /// ditto R dropBackOne(R)(R range) if (isBidirectionalRange!R) { range.popBack(); return range; } /// @safe unittest { import std.algorithm : equal, filterBidirectional; import std.container.dlist; auto dl = DList!int(9, 1, 2, 3, 9); assert(dl[].dropOne().dropBackOne().equal([1, 2, 3])); auto a = [1, 2, 3]; assert(a.dropOne() == [2, 3]); assert(a.dropBackOne() == [1, 2]); string s = "日本語"; assert(s.dropOne() == "本語"); assert(s.dropBackOne() == "日本"); auto bd = filterBidirectional!"true"([1, 2, 3]); assert(bd.dropOne().equal([2, 3])); assert(bd.dropBackOne().equal([1, 2])); } /** Repeats one value forever. Models an infinite bidirectional and random access range, with slicing. */ struct Repeat(T) { private: //Store a non-qualified T when possible: This is to make Repeat assignable static if ((is(T == class) || is(T == interface)) && (is(T == const) || is(T == immutable))) { import std.typecons; alias UT = Rebindable!T; } else static if (is(T : Unqual!T) && is(Unqual!T : T)) alias UT = Unqual!T; else alias UT = T; UT _value; public: @property inout(T) front() inout { return _value; } @property inout(T) back() inout { return _value; } enum bool empty = false; void popFront() {} void popBack() {} @property auto save() inout { return this; } inout(T) opIndex(size_t) inout { return _value; } auto opSlice(size_t i, size_t j) in { assert(i <= j); } body { return this.takeExactly(j - i); } private static struct DollarToken {} enum opDollar = DollarToken.init; auto opSlice(size_t, DollarToken) inout { return this; } } /// Ditto Repeat!T repeat(T)(T value) { return Repeat!T(value); } /// @safe unittest { import std.algorithm : equal; assert(equal(5.repeat().take(4), [ 5, 5, 5, 5 ])); } @safe unittest { import std.algorithm : equal; auto r = repeat(5); alias R = typeof(r); static assert(isBidirectionalRange!R); static assert(isForwardRange!R); static assert(isInfinite!R); static assert(hasSlicing!R); assert(r.back == 5); assert(r.front == 5); assert(r.take(4).equal([ 5, 5, 5, 5 ])); assert(r[0 .. 4].equal([ 5, 5, 5, 5 ])); R r2 = r[5 .. $]; } /** Repeats $(D value) exactly $(D n) times. Equivalent to $(D take(repeat(value), n)). */ Take!(Repeat!T) repeat(T)(T value, size_t n) { return take(repeat(value), n); } /// @safe unittest { import std.algorithm : equal; assert(equal(5.repeat(4), 5.repeat().take(4))); } @safe unittest //12007 { static class C{} Repeat!(immutable int) ri; ri = ri.save; Repeat!(immutable C) rc; rc = rc.save; import std.algorithm; immutable int[] A = [1,2,3]; immutable int[] B = [4,5,6]; auto AB = cartesianProduct(A,B); } /** Given callable ($(XREF traits, isCallable)) $(D fun), create as a range whose front is defined by successive calls to $(D fun()). This is especially useful to call function with global side effects (random functions), or to create ranges expressed as a single delegate, rather than an entire $(D front)/$(D popFront)/$(D empty) structure. $(D fun) maybe be passed either a template alias parameter (existing function, delegate, struct type defining static $(D opCall)... ) or a run-time value argument (delegate, function object... ). The result range models an InputRange ($(XREF_PACK range,primitives,isInputRange)). The resulting range will call $(D fun()) on every call to $(D front), and only when $(D front) is called, regardless of how the range is iterated. It is advised to compose generate with either $(XREF_PACK algorithm,iteration,cache) or $(XREF array,array), or to use it in a foreach loop. A by-value foreach loop means that the loop value is not $(D ref). Params: fun = is the $(D isCallable) that gets called on every call to front. Returns: an $(D inputRange) that returns a new value generated by $(D Fun) on any call to $(D front). */ auto generate(Fun)(Fun fun) if (isCallable!fun) { return Generator!(Fun)(fun); } /// ditto auto generate(alias fun)() if (isCallable!fun) { return Generator!(fun)(); } /// @safe pure unittest { import std.algorithm : equal, map; int i = 1; auto powersOfTwo = generate!(() => i *= 2)().take(10); assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"())); } /// @safe pure unittest { import std.algorithm : equal; //Returns a run-time delegate auto infiniteIota(T)(T low, T high) { T i = high; return (){if (i == high) i = low; return i++;}; } //adapted as a range. assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1])); } /// unittest { import std.format, std.random; auto r = generate!(() => uniform(0, 6)).take(10); format("%(%s %)", r); } //private struct Generator(bool onPopFront, bool runtime, Fun...) private struct Generator(Fun...) { static assert(Fun.length == 1); static assert(isInputRange!Generator); private: static if (is(Fun[0])) Fun[0] fun; else alias fun = Fun[0]; public: enum empty = false; auto ref front() @property { return fun(); } void popFront() { } } @safe unittest { import std.algorithm : equal; struct StaticOpCall { static ubyte opCall() { return 5 ; } } assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10))); } @safe pure unittest { import std.algorithm : equal; struct OpCall { ubyte opCall() @safe pure { return 5 ; } } OpCall op; assert(equal(generate(op).take(10), repeat(5).take(10))); } /** Repeats the given forward range ad infinitum. If the original range is infinite (fact that would make $(D Cycle) the identity application), $(D Cycle) detects that and aliases itself to the range type itself. If the original range has random access, $(D Cycle) offers random access and also offers a constructor taking an initial position $(D index). $(D Cycle) works with static arrays in addition to ranges, mostly for performance reasons. Note: The input range must not be empty. Tip: This is a great way to implement simple circular buffers. */ struct Cycle(R) if (isForwardRange!R && !isInfinite!R) { static if (isRandomAccessRange!R && hasLength!R) { private R _original; private size_t _index; this(R input, size_t index = 0) { _original = input; _index = index % _original.length; } @property auto ref front() { return _original[_index]; } static if (is(typeof((cast(const R)_original)[_index]))) { @property auto ref front() const { return _original[_index]; } } static if (hasAssignableElements!R) { @property auto front(ElementType!R val) { _original[_index] = val; } } enum bool empty = false; void popFront() { ++_index; if (_index >= _original.length) _index = 0; } auto ref opIndex(size_t n) { return _original[(n + _index) % _original.length]; } static if (is(typeof((cast(const R)_original)[_index])) && is(typeof((cast(const R)_original).length))) { auto ref opIndex(size_t n) const { return _original[(n + _index) % _original.length]; } } static if (hasAssignableElements!R) { auto opIndexAssign(ElementType!R val, size_t n) { _original[(n + _index) % _original.length] = val; } } @property Cycle save() { //No need to call _original.save, because Cycle never actually modifies _original return Cycle(_original, _index); } private static struct DollarToken {} enum opDollar = DollarToken.init; auto opSlice(size_t i, size_t j) in { assert(i <= j); } body { return this[i .. $].takeExactly(j - i); } auto opSlice(size_t i, DollarToken) { return typeof(this)(_original, _index + i); } } else { private R _original; private R _current; this(R input) { _original = input; _current = input.save; } @property auto ref front() { return _current.front; } static if (is(typeof((cast(const R)_current).front))) { @property auto ref front() const { return _current.front; } } static if (hasAssignableElements!R) { @property auto front(ElementType!R val) { return _current.front = val; } } enum bool empty = false; void popFront() { _current.popFront(); if (_current.empty) _current = _original.save; } @property Cycle save() { //No need to call _original.save, because Cycle never actually modifies _original Cycle ret = this; ret._original = _original; ret._current = _current.save; return ret; } } } template Cycle(R) if (isInfinite!R) { alias Cycle = R; } struct Cycle(R) if (isStaticArray!R) { private alias ElementType = typeof(R.init[0]); private ElementType* _ptr; private size_t _index; nothrow: this(ref R input, size_t index = 0) @system { _ptr = input.ptr; _index = index % R.length; } @property ref inout(ElementType) front() inout @safe { static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted { return p[idx]; } return trustedPtrIdx(_ptr, _index); } enum bool empty = false; void popFront() @safe { ++_index; if (_index >= R.length) _index = 0; } ref inout(ElementType) opIndex(size_t n) inout @safe { static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted { return p[idx % R.length]; } return trustedPtrIdx(_ptr, n + _index); } @property inout(Cycle) save() inout @safe { return this; } private static struct DollarToken {} enum opDollar = DollarToken.init; auto opSlice(size_t i, size_t j) @safe in { assert(i <= j); } body { return this[i .. $].takeExactly(j - i); } inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe { static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted { return cast(inout)Cycle(*cast(R*)(p), idx); } return trustedCtor(_ptr, _index + i); } } /// Ditto Cycle!R cycle(R)(R input) if (isForwardRange!R && !isInfinite!R) { assert(!input.empty); return Cycle!R(input); } /// @safe unittest { import std.algorithm : equal; import std.range : cycle, take; // Here we create an infinitive cyclic sequence from [1, 2] // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1]) // and compare them with the expected values for equality. assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ])); } /// Ditto Cycle!R cycle(R)(R input, size_t index = 0) if (isRandomAccessRange!R && !isInfinite!R) { assert(!input.empty); return Cycle!R(input, index); } Cycle!R cycle(R)(R input) if (isInfinite!R) { return input; } Cycle!R cycle(R)(ref R input, size_t index = 0) @system if (isStaticArray!R) { return Cycle!R(input, index); } @safe unittest { import std.internal.test.dummyrange; import std.algorithm : equal; static assert(isForwardRange!(Cycle!(uint[]))); // Make sure ref is getting propagated properly. int[] nums = [1,2,3]; auto c2 = cycle(nums); c2[3]++; assert(nums[0] == 2); immutable int[] immarr = [1, 2, 3]; auto cycleimm = cycle(immarr); foreach(DummyType; AllDummyRanges) { static if (isForwardRange!DummyType) { DummyType dummy; auto cy = cycle(dummy); static assert(isForwardRange!(typeof(cy))); auto t = take(cy, 20); assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10])); const cRange = cy; assert(cRange.front == 1); static if (hasAssignableElements!DummyType) { { cy.front = 66; scope(exit) cy.front = 1; assert(dummy.front == 66); } static if (isRandomAccessRange!DummyType) { { cy[10] = 66; scope(exit) cy[10] = 1; assert(dummy.front == 66); } assert(cRange[10] == 1); } } static if(hasSlicing!DummyType) { auto slice = cy[5 .. 15]; assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5])); static assert(is(typeof(slice) == typeof(takeExactly(cy, 5)))); auto infSlice = cy[7 .. $]; assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2])); static assert(isInfinite!(typeof(infSlice))); } } } } @system unittest // For static arrays. { import std.algorithm : equal; int[3] a = [ 1, 2, 3 ]; static assert(isStaticArray!(typeof(a))); auto c = cycle(a); assert(a.ptr == c._ptr); assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][])); static assert(isForwardRange!(typeof(c))); // Test qualifiers on slicing. alias C = typeof(c); static assert(is(typeof(c[1 .. $]) == C)); const cConst = c; static assert(is(typeof(cConst[1 .. $]) == const(C))); } @safe unittest // For infinite ranges { struct InfRange { void popFront() { } @property int front() { return 0; } enum empty = false; } InfRange i; auto c = cycle(i); assert (c == i); } @safe unittest { import std.algorithm : equal; int[5] arr = [0, 1, 2, 3, 4]; auto cleD = cycle(arr[]); //Dynamic assert(equal(cleD[5 .. 10], arr[])); //n is a multiple of 5 worth about 3/4 of size_t.max auto n = size_t.max/4 + size_t.max/2; n -= n % 5; //Test index overflow foreach (_ ; 0 .. 10) { cleD = cleD[n .. $]; assert(equal(cleD[5 .. 10], arr[])); } } @system unittest { import std.algorithm : equal; int[5] arr = [0, 1, 2, 3, 4]; auto cleS = cycle(arr); //Static assert(equal(cleS[5 .. 10], arr[])); //n is a multiple of 5 worth about 3/4 of size_t.max auto n = size_t.max/4 + size_t.max/2; n -= n % 5; //Test index overflow foreach (_ ; 0 .. 10) { cleS = cleS[n .. $]; assert(equal(cleS[5 .. 10], arr[])); } } @system unittest { import std.algorithm : equal; int[1] arr = [0]; auto cleS = cycle(arr); cleS = cleS[10 .. $]; assert(equal(cleS[5 .. 10], 0.repeat(5))); assert(cleS.front == 0); } unittest //10845 { import std.algorithm : equal, filter; auto a = inputRangeObject(iota(3).filter!"true"); assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0])); } @safe unittest // 12177 { auto a = recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0"); } // Issue 13390 unittest { import std.exception; import core.exception : AssertError; assertThrown!AssertError(cycle([0, 1, 2][0..0])); } private alias lengthType(R) = typeof(R.init.length.init); /** Iterate several ranges in lockstep. The element type is a proxy tuple that allows accessing the current element in the $(D n)th range by using $(D e[n]). `zip` is similar to $(LREF lockstep), but `lockstep` doesn't bundle its elements and uses the `opApply` protocol. `lockstep` allows reference access to the elements in `foreach` iterations. $(D Zip) offers the lowest range facilities of all components, e.g. it offers random access iff all ranges offer random access, and also offers mutation and swapping if all ranges offer it. Due to this, $(D Zip) is extremely powerful because it allows manipulating several ranges in lockstep. */ struct Zip(Ranges...) if (Ranges.length && allSatisfy!(isInputRange, Ranges)) { import std.format : format; //for generic mixins import std.typecons : Tuple; alias R = Ranges; R ranges; alias ElementType = Tuple!(staticMap!(.ElementType, R)); StoppingPolicy stoppingPolicy = StoppingPolicy.shortest; /** Builds an object. Usually this is invoked indirectly by using the $(LREF zip) function. */ this(R rs, StoppingPolicy s = StoppingPolicy.shortest) { ranges[] = rs[]; stoppingPolicy = s; } /** Returns $(D true) if the range is at end. The test depends on the stopping policy. */ static if (allSatisfy!(isInfinite, R)) { // BUG: Doesn't propagate infiniteness if only some ranges are infinite // and s == StoppingPolicy.longest. This isn't fixable in the // current design since StoppingPolicy is known only at runtime. enum bool empty = false; } else { @property bool empty() { import std.exception : enforce; final switch (stoppingPolicy) { case StoppingPolicy.shortest: foreach (i, Unused; R) { if (ranges[i].empty) return true; } return false; case StoppingPolicy.longest: static if (anySatisfy!(isInfinite, R)) { return false; } else { foreach (i, Unused; R) { if (!ranges[i].empty) return false; } return true; } case StoppingPolicy.requireSameLength: foreach (i, Unused; R[1 .. $]) { enforce(ranges[0].empty == ranges[i + 1].empty, "Inequal-length ranges passed to Zip"); } return ranges[0].empty; } assert(false); } } static if (allSatisfy!(isForwardRange, R)) { @property Zip save() { //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy) return mixin (q{Zip(%(ranges[%s]%|, %), stoppingPolicy)}.format(iota(0, R.length))); } } private .ElementType!(R[i]) tryGetInit(size_t i)() { alias E = .ElementType!(R[i]); static if (!is(typeof({static E i;}))) throw new Exception("Range with non-default constructable elements exhausted."); else return E.init; } /** Returns the current iterated element. */ @property ElementType front() { @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;} //ElementType(tryGetFront!0, tryGetFront!1, ...) return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length))); } /** Sets the front of all iterated ranges. */ static if (allSatisfy!(hasAssignableElements, R)) { @property void front(ElementType v) { foreach (i, Unused; R) { if (!ranges[i].empty) { ranges[i].front = v[i]; } } } } /** Moves out the front. */ static if (allSatisfy!(hasMobileElements, R)) { ElementType moveFront() { @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : .moveFront(ranges[i]);} //ElementType(tryMoveFront!0, tryMoveFront!1, ...) return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length))); } } /** Returns the rightmost element. */ static if (allSatisfy!(isBidirectionalRange, R)) { @property ElementType back() { //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;} //ElementType(tryGetBack!0, tryGetBack!1, ...) return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length))); } /** Moves out the back. */ static if (allSatisfy!(hasMobileElements, R)) { ElementType moveBack() { //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : .moveFront(ranges[i]);} //ElementType(tryMoveBack!0, tryMoveBack!1, ...) return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length))); } } /** Returns the current iterated element. */ static if (allSatisfy!(hasAssignableElements, R)) { @property void back(ElementType v) { //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness. //Not sure the call is even legal for StoppingPolicy.longest foreach (i, Unused; R) { if (!ranges[i].empty) { ranges[i].back = v[i]; } } } } } /** Advances to the next element in all controlled ranges. */ void popFront() { import std.exception : enforce; final switch (stoppingPolicy) { case StoppingPolicy.shortest: foreach (i, Unused; R) { assert(!ranges[i].empty); ranges[i].popFront(); } break; case StoppingPolicy.longest: foreach (i, Unused; R) { if (!ranges[i].empty) ranges[i].popFront(); } break; case StoppingPolicy.requireSameLength: foreach (i, Unused; R) { enforce(!ranges[i].empty, "Invalid Zip object"); ranges[i].popFront(); } break; } } /** Calls $(D popBack) for all controlled ranges. */ static if (allSatisfy!(isBidirectionalRange, R)) { void popBack() { //TODO: Fixme! In case of jaggedness, this is wrong. import std.exception : enforce; final switch (stoppingPolicy) { case StoppingPolicy.shortest: foreach (i, Unused; R) { assert(!ranges[i].empty); ranges[i].popBack(); } break; case StoppingPolicy.longest: foreach (i, Unused; R) { if (!ranges[i].empty) ranges[i].popBack(); } break; case StoppingPolicy.requireSameLength: foreach (i, Unused; R) { enforce(!ranges[i].empty, "Invalid Zip object"); ranges[i].popBack(); } break; } } } /** Returns the length of this range. Defined only if all ranges define $(D length). */ static if (allSatisfy!(hasLength, R)) { @property auto length() { static if (Ranges.length == 1) return ranges[0].length; else { if (stoppingPolicy == StoppingPolicy.requireSameLength) return ranges[0].length; //[min|max](ranges[0].length, ranges[1].length, ...) import std.algorithm : min, max; if (stoppingPolicy == StoppingPolicy.shortest) return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); else return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); } } alias opDollar = length; } /** Returns a slice of the range. Defined only if all range define slicing. */ static if (allSatisfy!(hasSlicing, R)) { auto opSlice(size_t from, size_t to) { //Slicing an infinite range yields the type Take!R //For finite ranges, the type Take!R aliases to R alias ZipResult = Zip!(staticMap!(Take, R)); //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy) return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length))); } } /** Returns the $(D n)th element in the composite range. Defined if all ranges offer random access. */ static if (allSatisfy!(isRandomAccessRange, R)) { ElementType opIndex(size_t n) { //TODO: Fixme! This may create an out of bounds access //for StoppingPolicy.longest //ElementType(ranges[0][n], ranges[1][n], ...) return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length))); } /** Assigns to the $(D n)th element in the composite range. Defined if all ranges offer random access. */ static if (allSatisfy!(hasAssignableElements, R)) { void opIndexAssign(ElementType v, size_t n) { //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest foreach (i, Range; R) { ranges[i][n] = v[i]; } } } /** Destructively reads the $(D n)th element in the composite range. Defined if all ranges offer random access. */ static if (allSatisfy!(hasMobileElements, R)) { ElementType moveAt(size_t n) { //TODO: Fixme! This may create an out of bounds access //for StoppingPolicy.longest //ElementType(.moveAt(ranges[0], n), .moveAt(ranges[1], n), ..., ) return mixin (q{ElementType(%(.moveAt(ranges[%s], n)%|, %))}.format(iota(0, R.length))); } } } } /// Ditto auto zip(Ranges...)(Ranges ranges) if (Ranges.length && allSatisfy!(isInputRange, Ranges)) { return Zip!Ranges(ranges); } /// pure unittest { import std.algorithm : equal, map; // pairwise sum auto arr = [0, 1, 2]; assert(zip(arr, arr.dropOne).map!"a[0] + a[1]".equal([1, 3])); } /// pure unittest { import std.conv: to; int[] a = [ 1, 2, 3 ]; string[] b = [ "a", "b", "c" ]; string[] result; foreach (tup; zip(a, b)) { result ~= tup[0].to!string ~ tup[1]; } assert(result == [ "1a", "2b", "3c" ]); size_t idx = 0; // unpacking tuple elements with foreach foreach (e1, e2; zip(a, b)) { assert(e1 == a[idx]); assert(e2 == b[idx]); ++idx; } } /// $(D zip) is powerful - the following code sorts two arrays in parallel: pure unittest { import std.algorithm : sort; int[] a = [ 1, 2, 3 ]; string[] b = [ "a", "c", "b" ]; zip(a, b).sort!((t1, t2) => t1[0] > t2[0]); assert(a == [ 3, 2, 1 ]); // b is sorted according to a's sorting assert(b == [ "b", "c", "a" ]); } /// Ditto auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges) if (Ranges.length && allSatisfy!(isInputRange, Ranges)) { return Zip!Ranges(ranges, sp); } /** Dictates how iteration in a $(D Zip) should stop. By default stop at the end of the shortest of all ranges. */ enum StoppingPolicy { /// Stop when the shortest range is exhausted shortest, /// Stop when the longest range is exhausted longest, /// Require that all ranges are equal requireSameLength, } unittest { import std.internal.test.dummyrange; import std.algorithm : swap, sort, filter, equal, map; import std.exception : assertThrown, assertNotThrown; import std.typecons : tuple; int[] a = [ 1, 2, 3 ]; float[] b = [ 1.0, 2.0, 3.0 ]; foreach (e; zip(a, b)) { assert(e[0] == e[1]); } swap(a[0], a[1]); auto z = zip(a, b); //swap(z.front(), z.back()); sort!("a[0] < b[0]")(zip(a, b)); assert(a == [1, 2, 3]); assert(b == [2.0, 1.0, 3.0]); z = zip(StoppingPolicy.requireSameLength, a, b); assertNotThrown(z.popBack()); assertNotThrown(z.popBack()); assertNotThrown(z.popBack()); assert(z.empty); assertThrown(z.popBack()); a = [ 1, 2, 3 ]; b = [ 1.0, 2.0, 3.0 ]; sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b)); assert(a == [3, 2, 1]); assert(b == [3.0, 2.0, 1.0]); a = []; b = []; assert(zip(StoppingPolicy.requireSameLength, a, b).empty); // Test infiniteness propagation. static assert(isInfinite!(typeof(zip(repeat(1), repeat(1))))); // Test stopping policies with both value and reference. auto a1 = [1, 2]; auto a2 = [1, 2, 3]; auto stuff = tuple(tuple(a1, a2), tuple(filter!"a"(a1), filter!"a"(a2))); alias FOO = Zip!(immutable(int)[], immutable(float)[]); foreach(t; stuff.expand) { auto arr1 = t[0]; auto arr2 = t[1]; auto zShortest = zip(arr1, arr2); assert(equal(map!"a[0]"(zShortest), [1, 2])); assert(equal(map!"a[1]"(zShortest), [1, 2])); try { auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2); foreach(elem; zSame) {} assert(0); } catch (Throwable) { /* It's supposed to throw.*/ } auto zLongest = zip(StoppingPolicy.longest, arr1, arr2); assert(!zLongest.ranges[0].empty); assert(!zLongest.ranges[1].empty); zLongest.popFront(); zLongest.popFront(); assert(!zLongest.empty); assert(zLongest.ranges[0].empty); assert(!zLongest.ranges[1].empty); zLongest.popFront(); assert(zLongest.empty); } // BUG 8900 assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]); assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]); // Doesn't work yet. Issues w/ emplace. // static assert(is(Zip!(immutable int[], immutable float[]))); // These unittests pass, but make the compiler consume an absurd amount // of RAM and time. Therefore, they should only be run if explicitly // uncommented when making changes to Zip. Also, running them using // make -fwin32.mak unittest makes the compiler completely run out of RAM. // You need to test just this module. /+ foreach(DummyType1; AllDummyRanges) { DummyType1 d1; foreach(DummyType2; AllDummyRanges) { DummyType2 d2; auto r = zip(d1, d2); assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10])); assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10])); static if (isForwardRange!DummyType1 && isForwardRange!DummyType2) { static assert(isForwardRange!(typeof(r))); } static if (isBidirectionalRange!DummyType1 && isBidirectionalRange!DummyType2) { static assert(isBidirectionalRange!(typeof(r))); } static if (isRandomAccessRange!DummyType1 && isRandomAccessRange!DummyType2) { static assert(isRandomAccessRange!(typeof(r))); } } } +/ } pure unittest { import std.algorithm : sort; auto a = [5,4,3,2,1]; auto b = [3,1,2,5,6]; auto z = zip(a, b); sort!"a[0] < b[0]"(z); assert(a == [1, 2, 3, 4, 5]); assert(b == [6, 5, 2, 1, 3]); } @safe pure unittest { import std.typecons : tuple; import std.algorithm : equal; auto LL = iota(1L, 1000L); auto z = zip(LL, [4]); assert(equal(z, [tuple(1L,4)])); auto LL2 = iota(0L, 500L); auto z2 = zip([7], LL2); assert(equal(z2, [tuple(7, 0L)])); } // Text for Issue 11196 @safe pure unittest { import std.exception : assertThrown; static struct S { @disable this(); } assert(zip((S[5]).init[]).length == 5); assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1); assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front); } @safe pure unittest //12007 { static struct R { enum empty = false; void popFront(){} int front(){return 1;} @property R save(){return this;} @property void opAssign(R) @disable; } R r; auto z = zip(r, r); auto zz = z.save; } /* Generate lockstep's opApply function as a mixin string. If withIndex is true prepend a size_t index to the delegate. */ private string lockstepMixin(Ranges...)(bool withIndex) { import std.format : format; string[] params; string[] emptyChecks; string[] dgArgs; string[] popFronts; if (withIndex) { params ~= "size_t"; dgArgs ~= "index"; } foreach (idx, Range; Ranges) { params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); emptyChecks ~= format("!ranges[%s].empty", idx); dgArgs ~= format("ranges[%s].front", idx); popFronts ~= format("ranges[%s].popFront();", idx); } return format( q{ int opApply(scope int delegate(%s) dg) { import std.exception : enforce; auto ranges = _ranges; int res; %s while (%s) { res = dg(%s); if (res) break; %s %s } if (_stoppingPolicy == StoppingPolicy.requireSameLength) { foreach(range; ranges) enforce(range.empty); } return res; } }, params.join(", "), withIndex ? "size_t index = 0;" : "", emptyChecks.join(" && "), dgArgs.join(", "), popFronts.join("\n "), withIndex ? "index++;" : ""); } /** Iterate multiple ranges in lockstep using a $(D foreach) loop. In contrast to $(LREF zip) it allows reference access to its elements. If only a single range is passed in, the $(D Lockstep) aliases itself away. If the ranges are of different lengths and $(D s) == $(D StoppingPolicy.shortest) stop after the shortest range is empty. If the ranges are of different lengths and $(D s) == $(D StoppingPolicy.requireSameLength), throw an exception. $(D s) may not be $(D StoppingPolicy.longest), and passing this will throw an exception. By default $(D StoppingPolicy) is set to $(D StoppingPolicy.shortest). See_Also: $(LREF zip) `lockstep` is similar to $(LREF zip), but `zip` bundles its elements and returns a range. `lockstep` also supports reference access. Use `zip` if you want to pass the result to a range function. */ struct Lockstep(Ranges...) if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges)) { this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest) { import std.exception : enforce; _ranges = ranges; enforce(sp != StoppingPolicy.longest, "Can't use StoppingPolicy.Longest on Lockstep."); _stoppingPolicy = sp; } mixin(lockstepMixin!Ranges(false)); mixin(lockstepMixin!Ranges(true)); private: alias R = Ranges; R _ranges; StoppingPolicy _stoppingPolicy; } // For generic programming, make sure Lockstep!(Range) is well defined for a // single range. template Lockstep(Range) { alias Lockstep = Range; } /// Ditto Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges) if (allSatisfy!(isInputRange, Ranges)) { return Lockstep!(Ranges)(ranges); } /// Ditto Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s) if (allSatisfy!(isInputRange, Ranges)) { static if (Ranges.length > 1) return Lockstep!Ranges(ranges, s); else return ranges[0]; } /// unittest { auto arr1 = [1,2,3,4,5,100]; auto arr2 = [6,7,8,9,10]; foreach (ref a, b; lockstep(arr1, arr2)) { a += b; } assert(arr1 == [7,9,11,13,15,100]); /// Lockstep also supports iterating with an index variable: foreach (index, a, b; lockstep(arr1, arr2)) { assert(arr1[index] == a); assert(arr2[index] == b); } } unittest { import std.conv : to; import std.algorithm : filter; // The filters are to make these the lowest common forward denominator ranges, // i.e. w/o ref return, random access, length, etc. auto foo = filter!"a"([1,2,3,4,5]); immutable bar = [6f,7f,8f,9f,10f].idup; auto l = lockstep(foo, bar); // Should work twice. These are forward ranges with implicit save. foreach(i; 0..2) { uint[] res1; float[] res2; foreach(a, ref b; l) { res1 ~= a; res2 ~= b; } assert(res1 == [1,2,3,4,5]); assert(res2 == [6,7,8,9,10]); assert(bar == [6f,7f,8f,9f,10f]); } // Doc example. auto arr1 = [1,2,3,4,5]; auto arr2 = [6,7,8,9,10]; foreach(ref a, ref b; lockstep(arr1, arr2)) { a += b; } assert(arr1 == [7,9,11,13,15]); // Make sure StoppingPolicy.requireSameLength doesn't throw. auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); foreach(a, b; ls) {} // Make sure StoppingPolicy.requireSameLength throws. arr2.popBack(); ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); try { foreach(a, b; ls) {} assert(0); } catch (Exception) {} // Just make sure 1-range case instantiates. This hangs the compiler // when no explicit stopping policy is specified due to Bug 4652. auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest); // Test with indexing. uint[] res1; float[] res2; size_t[] indices; foreach(i, a, b; lockstep(foo, bar)) { indices ~= i; res1 ~= a; res2 ~= b; } assert(indices == to!(size_t[])([0, 1, 2, 3, 4])); assert(res1 == [1,2,3,4,5]); assert(res2 == [6f,7f,8f,9f,10f]); // Make sure we've worked around the relevant compiler bugs and this at least // compiles w/ >2 ranges. lockstep(foo, foo, foo); // Make sure it works with const. const(int[])[] foo2 = [[1, 2, 3]]; const(int[])[] bar2 = [[4, 5, 6]]; auto c = chain(foo2, bar2); foreach(f, b; lockstep(c, c)) {} // Regression 10468 foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { } } unittest { struct RvalueRange { int[] impl; @property bool empty() { return impl.empty; } @property int front() { return impl[0]; } // N.B. non-ref void popFront() { impl.popFront(); } } auto data1 = [ 1, 2, 3, 4 ]; auto data2 = [ 5, 6, 7, 8 ]; auto r1 = RvalueRange(data1); auto r2 = data2; foreach (a, ref b; lockstep(r1, r2)) { a++; b++; } assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do. // Since r1 is by-value only, the compiler should reject attempts to // foreach over it with ref. static assert(!__traits(compiles, { foreach (ref a, ref b; lockstep(r1, r2)) { a++; } })); } /** Creates a mathematical sequence given the initial values and a recurrence function that computes the next value from the existing values. The sequence comes in the form of an infinite forward range. The type $(D Recurrence) itself is seldom used directly; most often, recurrences are obtained by calling the function $(D recurrence). When calling $(D recurrence), the function that computes the next value is specified as a template argument, and the initial values in the recurrence are passed as regular arguments. For example, in a Fibonacci sequence, there are two initial values (and therefore a state size of 2) because computing the next Fibonacci value needs the past two values. The signature of this function should be: ---- auto fun(R)(R state, size_t n) ---- where $(D n) will be the index of the current value, and $(D state) will be an opaque state vector that can be indexed with array-indexing notation $(D state[i]), where valid values of $(D i) range from $(D (n - 1)) to $(D (n - State.length)). If the function is passed in string form, the state has name $(D "a") and the zero-based index in the recurrence has name $(D "n"). The given string must return the desired value for $(D a[n]) given $(D a[n - 1]), $(D a[n - 2]), $(D a[n - 3]),..., $(D a[n - stateSize]). The state size is dictated by the number of arguments passed to the call to $(D recurrence). The $(D Recurrence) struct itself takes care of managing the recurrence's state and shifting it appropriately. */ struct Recurrence(alias fun, StateType, size_t stateSize) { private import std.functional : binaryFun; StateType[stateSize] _state; size_t _n; this(StateType[stateSize] initial) { _state = initial; } void popFront() { static auto trustedCycle(ref typeof(_state) s) @trusted { return cycle(s); } // The cast here is reasonable because fun may cause integer // promotion, but needs to return a StateType to make its operation // closed. Therefore, we have no other choice. _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")( trustedCycle(_state), _n + stateSize); ++_n; } @property StateType front() { return _state[_n % stateSize]; } @property typeof(this) save() { return this; } enum bool empty = false; } /// @safe unittest { import std.algorithm : equal; // The Fibonacci numbers, using function in string form: // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n] auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])); // The factorials, using function in lambda form: auto fac = recurrence!((a,n) => a[n-1] * n)(1); assert(take(fac, 10).equal([ 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 ])); // The triangular numbers, using function in explicit form: static size_t genTriangular(R)(R state, size_t n) { return state[n-1] + n; } auto tri = recurrence!genTriangular(0); assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45])); } /// Ditto Recurrence!(fun, CommonType!(State), State.length) recurrence(alias fun, State...)(State initial) { CommonType!(State)[State.length] state; foreach (i, Unused; State) { state[i] = initial[i]; } return typeof(return)(state); } @safe unittest { import std.algorithm : equal; auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); static assert(isForwardRange!(typeof(fib))); int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]; assert(equal(take(fib, 10), witness)); foreach (e; take(fib, 10)) {} auto fact = recurrence!("n * a[n-1]")(1); assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6, 2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) ); auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0); foreach (e; take(piapprox, 20)) {} // Thanks to yebblies for this test and the associated fix auto r = recurrence!"a[n-2]"(1, 2); witness = [1, 2, 1, 2, 1]; assert(equal(take(r, 5), witness)); } /** $(D Sequence) is similar to $(D Recurrence) except that iteration is presented in the so-called $(WEB en.wikipedia.org/wiki/Closed_form, closed form). This means that the $(D n)th element in the series is computable directly from the initial values and $(D n) itself. This implies that the interface offered by $(D Sequence) is a random-access range, as opposed to the regular $(D Recurrence), which only offers forward iteration. The state of the sequence is stored as a $(D Tuple) so it can be heterogeneous. */ struct Sequence(alias fun, State) { private: import std.functional : binaryFun; alias compute = binaryFun!(fun, "a", "n"); alias ElementType = typeof(compute(State.init, cast(size_t) 1)); State _state; size_t _n; static struct DollarToken{} public: this(State initial, size_t n = 0) { _state = initial; _n = n; } @property ElementType front() { return compute(_state, _n); } void popFront() { ++_n; } enum opDollar = DollarToken(); auto opSlice(size_t lower, size_t upper) in { assert(upper >= lower); } body { return typeof(this)(_state, _n + lower).take(upper - lower); } auto opSlice(size_t lower, DollarToken) { return typeof(this)(_state, _n + lower); } ElementType opIndex(size_t n) { return compute(_state, n + _n); } enum bool empty = false; @property Sequence save() { return this; } } /// Ditto auto sequence(alias fun, State...)(State args) { import std.typecons : Tuple, tuple; alias Return = Sequence!(fun, Tuple!State); return Return(tuple(args)); } /// Odd numbers, using function in string form: @safe unittest { auto odds = sequence!("a[0] + n * a[1]")(1, 2); assert(odds.front == 1); odds.popFront(); assert(odds.front == 3); odds.popFront(); assert(odds.front == 5); } /// Triangular numbers, using function in lambda form: @safe unittest { auto tri = sequence!((a,n) => n*(n+1)/2)(); // Note random access assert(tri[0] == 0); assert(tri[3] == 6); assert(tri[1] == 1); assert(tri[4] == 10); assert(tri[2] == 3); } /// Fibonacci numbers, using function in explicit form: @safe unittest { import std.math : pow, round, sqrt; static ulong computeFib(S)(S state, size_t n) { // Binet's formula return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) / state[2])); } auto fib = sequence!computeFib( (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio sqrt(5.0)); // Note random access with [] operator assert(fib[1] == 1); assert(fib[4] == 5); assert(fib[3] == 3); assert(fib[2] == 2); assert(fib[9] == 55); } @safe unittest { import std.typecons : Tuple, tuple; auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4)); static assert(isForwardRange!(typeof(y))); //@@BUG //auto y = sequence!("a[0] + n * a[1]")(0, 4); //foreach (e; take(y, 15)) {} //writeln(e); auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))( tuple(1, 2)); for(int currentOdd = 1; currentOdd <= 21; currentOdd += 2) { assert(odds.front == odds[0]); assert(odds[0] == currentOdd); odds.popFront(); } } @safe unittest { import std.algorithm : equal; auto odds = sequence!("a[0] + n * a[1]")(1, 2); static assert(hasSlicing!(typeof(odds))); //Note: don't use drop or take as the target of an equal, //since they'll both just forward to opSlice, making the tests irrelevant // static slicing tests assert(equal(odds[0 .. 5], [1, 3, 5, 7, 9])); assert(equal(odds[3 .. 7], [7, 9, 11, 13])); // relative slicing test, testing slicing is NOT agnostic of state auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $] assert(equal(odds_less5[0 .. 3], [11, 13, 15])); assert(equal(odds_less5[0 .. 10], odds[5 .. 15])); //Infinite slicing tests odds = odds[10 .. $]; assert(equal(odds.take(3), [21, 23, 25])); } // Issue 5036 unittest { auto s = sequence!((a, n) => new int)(0); assert(s.front != s.front); // no caching } /** Construct a range of values that span the given starting and stopping values. Params: begin = The starting value. end = The value that serves as the stopping criterion. This value is not included in the range. step = The value to add to the current value at each iteration. Returns: A range that goes through the numbers $(D begin), $(D begin + step), $(D begin + 2 * step), $(D ...), up to and excluding $(D end). The two-argument overloads have $(D step = 1). If $(D begin < end && step < 0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range is returned. If $(D step == 0) then $(D begin == end) is an error. For built-in types, the range returned is a random access range. For user-defined types that support $(D ++), the range is an input range. Example: --- void main() { import std.stdio; // The following groups all produce the same output of: // 0 1 2 3 4 foreach (i; 0..5) writef("%s ", i); writeln(); import std.range : iota; foreach (i; iota(0, 5)) writef("%s ", i); writeln(); writefln("%(%s %|%)", iota(0, 5)); import std.algorithm : map, copy; import std.format; iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter()); writeln(); } --- */ auto iota(B, E, S)(B begin, E end, S step) if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) && isIntegral!S) in { assert(!(step == 0 && begin != end)); } body { import std.conv : unsigned; alias Value = CommonType!(Unqual!B, Unqual!E); alias StepType = Unqual!S; alias IndexType = typeof(unsigned((end - begin) / step)); static struct Result { private Value current, pastLast; private StepType step; this(Value current, Value pastLast, StepType step) { if ((current < pastLast && step >= 0) || (current > pastLast && step <= 0)) { this.step = step; this.current = current; if (step > 0) { this.pastLast = pastLast - 1; this.pastLast -= (this.pastLast - current) % step; } else { this.pastLast = pastLast + 1; this.pastLast += (current - this.pastLast) % -step; } this.pastLast += step; } else { // Initialize an empty range this.current = this.pastLast = current; this.step = 1; } } @property bool empty() const { return current == pastLast; } @property inout(Value) front() inout { assert(!empty); return current; } void popFront() { assert(!empty); current += step; } @property inout(Value) back() inout { assert(!empty); return pastLast - step; } void popBack() { assert(!empty); pastLast -= step; } @property auto save() { return this; } inout(Value) opIndex(ulong n) inout { assert(n < this.length); // Just cast to Value here because doing so gives overflow behavior // consistent with calling popFront() n times. return cast(inout Value) (current + step * n); } inout(Result) opSlice() inout { return this; } inout(Result) opSlice(ulong lower, ulong upper) inout { assert(upper >= lower && upper <= this.length); return cast(inout Result)Result(cast(Value)(current + lower * step), cast(Value)(pastLast - (length - upper) * step), step); } @property IndexType length() const { if (step > 0) { return unsigned((pastLast - current) / step); } else { return unsigned((current - pastLast) / -step); } } alias opDollar = length; } return Result(begin, end, step); } /// Ditto auto iota(B, E)(B begin, E end) if (isFloatingPoint!(CommonType!(B, E))) { return iota(begin, end, CommonType!(B, E)(1)); } /// Ditto auto iota(B, E)(B begin, E end) if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) { import std.conv : unsigned; alias Value = CommonType!(Unqual!B, Unqual!E); alias IndexType = typeof(unsigned(end - begin)); static struct Result { private Value current, pastLast; this(Value current, Value pastLast) { if (current < pastLast) { this.current = current; this.pastLast = pastLast; } else { // Initialize an empty range this.current = this.pastLast = current; } } @property bool empty() const { return current == pastLast; } @property inout(Value) front() inout { assert(!empty); return current; } void popFront() { assert(!empty); ++current; } @property inout(Value) back() inout { assert(!empty); return cast(inout(Value))(pastLast - 1); } void popBack() { assert(!empty); --pastLast; } @property auto save() { return this; } inout(Value) opIndex(ulong n) inout { assert(n < this.length); // Just cast to Value here because doing so gives overflow behavior // consistent with calling popFront() n times. return cast(inout Value) (current + n); } inout(Result) opSlice() inout { return this; } inout(Result) opSlice(ulong lower, ulong upper) inout { assert(upper >= lower && upper <= this.length); return cast(inout Result)Result(cast(Value)(current + lower), cast(Value)(pastLast - (length - upper))); } @property IndexType length() const { return unsigned(pastLast - current); } alias opDollar = length; } return Result(begin, end); } /// Ditto auto iota(E)(E end) { E begin = 0; return iota(begin, end); } /// Ditto // Specialization for floating-point types auto iota(B, E, S)(B begin, E end, S step) if (isFloatingPoint!(CommonType!(B, E, S))) in { assert(step != 0, "iota: step must not be 0"); assert((end - begin) / step >= 0, "iota: incorrect startup parameters"); } body { alias Value = Unqual!(CommonType!(B, E, S)); static struct Result { private Value start, step; private size_t index, count; this(Value start, Value end, Value step) { import std.conv : to; this.start = start; this.step = step; immutable fcount = (end - start) / step; count = to!size_t(fcount); auto pastEnd = start + count * step; if (step > 0) { if (pastEnd < end) ++count; assert(start + count * step >= end); } else { if (pastEnd > end) ++count; assert(start + count * step <= end); } } @property bool empty() const { return index == count; } @property Value front() const { assert(!empty); return start + step * index; } void popFront() { assert(!empty); ++index; } @property Value back() const { assert(!empty); return start + step * (count - 1); } void popBack() { assert(!empty); --count; } @property auto save() { return this; } Value opIndex(size_t n) const { assert(n < count); return start + step * (n + index); } inout(Result) opSlice() inout { return this; } inout(Result) opSlice(size_t lower, size_t upper) inout { assert(upper >= lower && upper <= count); Result ret = this; ret.index += lower; ret.count = upper - lower + ret.index; return cast(inout Result)ret; } @property size_t length() const { return count - index; } alias opDollar = length; } return Result(begin, end, step); } /// @safe unittest { import std.algorithm : equal; import std.math : approxEqual; auto r = iota(0, 10, 1); assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); r = iota(0, 11, 3); assert(equal(r, [0, 3, 6, 9][])); assert(r[2] == 6); auto rf = iota(0.0, 0.5, 0.1); assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4])); } nothrow @nogc unittest { auto t0 = iota(0, 10); auto t1 = iota(0, 10, 2); auto t2 = iota(1, 1, 0); //float overloads use std.conv.to so can't be @nogc or nothrow } debug unittest {//check the contracts import std.exception : assertThrown; import core.exception : AssertError; assertThrown!AssertError(iota(1,2,0)); assertThrown!AssertError(iota(0f,1f,0f)); assertThrown!AssertError(iota(1f,0f,0.1f)); assertThrown!AssertError(iota(0f,1f,-0.1f)); } unittest { int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; auto r1 = iota(a.ptr, a.ptr + a.length, 1); assert(r1.front == a.ptr); assert(r1.back == a.ptr + a.length - 1); } @safe unittest { import std.math : approxEqual, nextUp, nextDown; import std.algorithm : count, equal; static assert(is(ElementType!(typeof(iota(0f))) == float)); static assert(hasLength!(typeof(iota(0, 2)))); auto r = iota(0, 10, 1); assert(r[$ - 1] == 9); assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); auto rSlice = r[2..8]; assert(equal(rSlice, [2, 3, 4, 5, 6, 7])); rSlice.popFront(); assert(rSlice[0] == rSlice.front); assert(rSlice.front == 3); rSlice.popBack(); assert(rSlice[rSlice.length - 1] == rSlice.back); assert(rSlice.back == 6); rSlice = r[0..4]; assert(equal(rSlice, [0, 1, 2, 3])); auto rr = iota(10); assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); r = iota(0, -10, -1); assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][])); rSlice = r[3..9]; assert(equal(rSlice, [-3, -4, -5, -6, -7, -8])); r = iota(0, -6, -3); assert(equal(r, [0, -3][])); rSlice = r[1..2]; assert(equal(rSlice, [-3])); r = iota(0, -7, -3); assert(equal(r, [0, -3, -6][])); rSlice = r[1..3]; assert(equal(rSlice, [-3, -6])); r = iota(0, 11, 3); assert(equal(r, [0, 3, 6, 9][])); assert(r[2] == 6); rSlice = r[1..3]; assert(equal(rSlice, [3, 6])); auto rf = iota(0.0, 0.5, 0.1); assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4][])); assert(rf.length == 5); rf.popFront(); assert(rf.length == 4); auto rfSlice = rf[1..4]; assert(rfSlice.length == 3); assert(approxEqual(rfSlice, [0.2, 0.3, 0.4])); rfSlice.popFront(); assert(approxEqual(rfSlice[0], 0.3)); rf.popFront(); assert(rf.length == 3); rfSlice = rf[1..3]; assert(rfSlice.length == 2); assert(approxEqual(rfSlice, [0.3, 0.4])); assert(approxEqual(rfSlice[0], 0.3)); // With something just above 0.5 rf = iota(0.0, nextUp(0.5), 0.1); assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][])); rf.popBack(); assert(rf[rf.length - 1] == rf.back); assert(approxEqual(rf.back, 0.4)); assert(rf.length == 5); // going down rf = iota(0.0, -0.5, -0.1); assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4][])); rfSlice = rf[2..5]; assert(approxEqual(rfSlice, [-0.2, -0.3, -0.4])); rf = iota(0.0, nextDown(-0.5), -0.1); assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][])); // iota of longs auto rl = iota(5_000_000L); assert(rl.length == 5_000_000L); // iota of longs with steps auto iota_of_longs_with_steps = iota(50L, 101L, 10); assert(iota_of_longs_with_steps.length == 6); assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L])); // iota of unsigned zero length (issue 6222, actually trying to consume it // is the only way to find something is wrong because the public // properties are all correct) auto iota_zero_unsigned = iota(0, 0u, 3); assert(count(iota_zero_unsigned) == 0); // unsigned reverse iota can be buggy if .length doesn't take them into // account (issue 7982). assert(iota(10u, 0u, -1).length == 10); assert(iota(10u, 0u, -2).length == 5); assert(iota(uint.max, uint.max-10, -1).length == 10); assert(iota(uint.max, uint.max-10, -2).length == 5); assert(iota(uint.max, 0u, -1).length == uint.max); // Issue 8920 foreach (Type; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) { Type val; foreach (i; iota(cast(Type)0, cast(Type)10)) { val++; } assert(val == 10); } } @safe unittest { import std.algorithm : copy; auto idx = new size_t[100]; copy(iota(0, idx.length), idx); } @safe unittest { foreach(range; AliasSeq!(iota(2, 27, 4), iota(3, 9), iota(2.7, 12.3, .1), iota(3.2, 9.7))) { const cRange = range; const e = cRange.empty; const f = cRange.front; const b = cRange.back; const i = cRange[2]; const s1 = cRange[]; const s2 = cRange[0 .. 3]; const l = cRange.length; } } unittest { //The ptr stuff can't be done at compile time, so we unfortunately end //up with some code duplication here. auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6]; { const cRange = iota(arr.ptr, arr.ptr + arr.length, 3); const e = cRange.empty; const f = cRange.front; const b = cRange.back; const i = cRange[2]; const s1 = cRange[]; const s2 = cRange[0 .. 3]; const l = cRange.length; } { const cRange = iota(arr.ptr, arr.ptr + arr.length); const e = cRange.empty; const f = cRange.front; const b = cRange.back; const i = cRange[2]; const s1 = cRange[]; const s2 = cRange[0 .. 3]; const l = cRange.length; } } /* Generic overload that handles arbitrary types that support arithmetic * operations. */ /// ditto auto iota(B, E)(B begin, E end) if (!isIntegral!(CommonType!(B, E)) && !isFloatingPoint!(CommonType!(B, E)) && !isPointer!(CommonType!(B, E)) && is(typeof((ref B b) { ++b; })) && (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) ) { static struct Result { B current; E end; @property bool empty() { static if (is(typeof(B.init < E.init))) return !(current < end); else static if (is(typeof(B.init != E.init))) return current == end; else static assert(0); } @property auto front() { return current; } void popFront() { assert(!empty); ++current; } } return Result(begin, end); } /** User-defined types such as $(XREF bigint, BigInt) are also supported, as long as they can be incremented with $(D ++) and compared with $(D <) or $(D ==). */ // Issue 6447 unittest { import std.algorithm.comparison : equal; import std.bigint; auto s = BigInt(1_000_000_000_000); auto e = BigInt(1_000_000_000_003); auto r = iota(s, e); assert(r.equal([ BigInt(1_000_000_000_000), BigInt(1_000_000_000_001), BigInt(1_000_000_000_002) ])); } unittest { import std.algorithm.comparison : equal; // Test iota() for a type that only supports ++ and != but does not have // '<'-ordering. struct Cyclic(int wrapAround) { int current; this(int start) { current = start % wrapAround; } bool opEquals(Cyclic c) { return current == c.current; } bool opEquals(int i) { return current == i; } void opUnary(string op)() if (op == "++") { current = (current + 1) % wrapAround; } } alias Cycle5 = Cyclic!5; // Easy case auto i1 = iota(Cycle5(1), Cycle5(4)); assert(i1.equal([1, 2, 3])); // Wraparound case auto i2 = iota(Cycle5(3), Cycle5(2)); assert(i2.equal([3, 4, 0, 1 ])); } /** Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges (below). */ enum TransverseOptions { /** When transversed, the elements of a range of ranges are assumed to have different lengths (e.g. a jagged array). */ assumeJagged, //default /** The transversal enforces that the elements of a range of ranges have all the same length (e.g. an array of arrays, all having the same length). Checking is done once upon construction of the transversal range. */ enforceNotJagged, /** The transversal assumes, without verifying, that the elements of a range of ranges have all the same length. This option is useful if checking was already done from the outside of the range. */ assumeNotJagged, } /** Given a range of ranges, iterate transversally through the first elements of each of the enclosed ranges. */ struct FrontTransversal(Ror, TransverseOptions opt = TransverseOptions.assumeJagged) { alias RangeOfRanges = Unqual!(Ror); alias RangeType = .ElementType!RangeOfRanges; alias ElementType = .ElementType!RangeType; private void prime() { static if (opt == TransverseOptions.assumeJagged) { while (!_input.empty && _input.front.empty) { _input.popFront(); } static if (isBidirectionalRange!RangeOfRanges) { while (!_input.empty && _input.back.empty) { _input.popBack(); } } } } /** Construction from an input. */ this(RangeOfRanges input) { _input = input; prime(); static if (opt == TransverseOptions.enforceNotJagged) // (isRandomAccessRange!RangeOfRanges // && hasLength!RangeType) { import std.exception : enforce; if (empty) return; immutable commonLength = _input.front.length; foreach (e; _input) { enforce(e.length == commonLength); } } } /** Forward range primitives. */ static if (isInfinite!RangeOfRanges) { enum bool empty = false; } else { @property bool empty() { return _input.empty; } } /// Ditto @property auto ref front() { assert(!empty); return _input.front.front; } /// Ditto static if (hasMobileElements!RangeType) { ElementType moveFront() { return .moveFront(_input.front); } } static if (hasAssignableElements!RangeType) { @property auto front(ElementType val) { _input.front.front = val; } } /// Ditto void popFront() { assert(!empty); _input.popFront(); prime(); } /** Duplicates this $(D frontTransversal). Note that only the encapsulating range of range will be duplicated. Underlying ranges will not be duplicated. */ static if (isForwardRange!RangeOfRanges) { @property FrontTransversal save() { return FrontTransversal(_input.save); } } static if (isBidirectionalRange!RangeOfRanges) { /** Bidirectional primitives. They are offered if $(D isBidirectionalRange!RangeOfRanges). */ @property auto ref back() { assert(!empty); return _input.back.front; } /// Ditto void popBack() { assert(!empty); _input.popBack(); prime(); } /// Ditto static if (hasMobileElements!RangeType) { ElementType moveBack() { return .moveFront(_input.back); } } static if (hasAssignableElements!RangeType) { @property auto back(ElementType val) { _input.back.front = val; } } } static if (isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged)) { /** Random-access primitive. It is offered if $(D isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged)). */ auto ref opIndex(size_t n) { return _input[n].front; } /// Ditto static if (hasMobileElements!RangeType) { ElementType moveAt(size_t n) { return .moveFront(_input[n]); } } /// Ditto static if (hasAssignableElements!RangeType) { void opIndexAssign(ElementType val, size_t n) { _input[n].front = val; } } /** Slicing if offered if $(D RangeOfRanges) supports slicing and all the conditions for supporting indexing are met. */ static if (hasSlicing!RangeOfRanges) { typeof(this) opSlice(size_t lower, size_t upper) { return typeof(this)(_input[lower..upper]); } } } auto opSlice() { return this; } private: RangeOfRanges _input; } /// Ditto FrontTransversal!(RangeOfRanges, opt) frontTransversal( TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) (RangeOfRanges rr) { return typeof(return)(rr); } /// @safe unittest { import std.algorithm : equal; int[][] x = new int[][2]; x[0] = [1, 2]; x[1] = [3, 4]; auto ror = frontTransversal(x); assert(equal(ror, [ 1, 3 ][])); } @safe unittest { import std.internal.test.dummyrange; import std.algorithm : equal; static assert(is(FrontTransversal!(immutable int[][]))); foreach(DummyType; AllDummyRanges) { auto dummies = [DummyType.init, DummyType.init, DummyType.init, DummyType.init]; foreach(i, ref elem; dummies) { // Just violate the DummyRange abstraction to get what I want. elem.arr = elem.arr[i..$ - (3 - i)]; } auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies); static if (isForwardRange!DummyType) { static assert(isForwardRange!(typeof(ft))); } assert(equal(ft, [1, 2, 3, 4])); // Test slicing. assert(equal(ft[0..2], [1, 2])); assert(equal(ft[1..3], [2, 3])); assert(ft.front == ft.moveFront()); assert(ft.back == ft.moveBack()); assert(ft.moveAt(1) == ft[1]); // Test infiniteness propagation. static assert(isInfinite!(typeof(frontTransversal(repeat("foo"))))); static if (DummyType.r == ReturnBy.Reference) { { ft.front++; scope(exit) ft.front--; assert(dummies.front.front == 2); } { ft.front = 5; scope(exit) ft.front = 1; assert(dummies[0].front == 5); } { ft.back = 88; scope(exit) ft.back = 4; assert(dummies.back.front == 88); } { ft[1] = 99; scope(exit) ft[1] = 2; assert(dummies[1].front == 99); } } } } /** Given a range of ranges, iterate transversally through the the $(D n)th element of each of the enclosed ranges. All elements of the enclosing range must offer random access. */ struct Transversal(Ror, TransverseOptions opt = TransverseOptions.assumeJagged) { private alias RangeOfRanges = Unqual!Ror; private alias InnerRange = ElementType!RangeOfRanges; private alias E = ElementType!InnerRange; private void prime() { static if (opt == TransverseOptions.assumeJagged) { while (!_input.empty && _input.front.length <= _n) { _input.popFront(); } static if (isBidirectionalRange!RangeOfRanges) { while (!_input.empty && _input.back.length <= _n) { _input.popBack(); } } } } /** Construction from an input and an index. */ this(RangeOfRanges input, size_t n) { _input = input; _n = n; prime(); static if (opt == TransverseOptions.enforceNotJagged) { import std.exception : enforce; if (empty) return; immutable commonLength = _input.front.length; foreach (e; _input) { enforce(e.length == commonLength); } } } /** Forward range primitives. */ static if (isInfinite!(RangeOfRanges)) { enum bool empty = false; } else { @property bool empty() { return _input.empty; } } /// Ditto @property auto ref front() { assert(!empty); return _input.front[_n]; } /// Ditto static if (hasMobileElements!InnerRange) { E moveFront() { return .moveAt(_input.front, _n); } } /// Ditto static if (hasAssignableElements!InnerRange) { @property auto front(E val) { _input.front[_n] = val; } } /// Ditto void popFront() { assert(!empty); _input.popFront(); prime(); } /// Ditto static if (isForwardRange!RangeOfRanges) { @property typeof(this) save() { auto ret = this; ret._input = _input.save; return ret; } } static if (isBidirectionalRange!RangeOfRanges) { /** Bidirectional primitives. They are offered if $(D isBidirectionalRange!RangeOfRanges). */ @property auto ref back() { return _input.back[_n]; } /// Ditto void popBack() { assert(!empty); _input.popBack(); prime(); } /// Ditto static if (hasMobileElements!InnerRange) { E moveBack() { return .moveAt(_input.back, _n); } } /// Ditto static if (hasAssignableElements!InnerRange) { @property auto back(E val) { _input.back[_n] = val; } } } static if (isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged)) { /** Random-access primitive. It is offered if $(D isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged)). */ auto ref opIndex(size_t n) { return _input[n][_n]; } /// Ditto static if (hasMobileElements!InnerRange) { E moveAt(size_t n) { return .moveAt(_input[n], _n); } } /// Ditto static if (hasAssignableElements!InnerRange) { void opIndexAssign(E val, size_t n) { _input[n][_n] = val; } } /// Ditto static if(hasLength!RangeOfRanges) { @property size_t length() { return _input.length; } alias opDollar = length; } /** Slicing if offered if $(D RangeOfRanges) supports slicing and all the conditions for supporting indexing are met. */ static if (hasSlicing!RangeOfRanges) { typeof(this) opSlice(size_t lower, size_t upper) { return typeof(this)(_input[lower..upper], _n); } } } auto opSlice() { return this; } private: RangeOfRanges _input; size_t _n; } /// Ditto Transversal!(RangeOfRanges, opt) transversal (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) (RangeOfRanges rr, size_t n) { return typeof(return)(rr, n); } /// @safe unittest { import std.algorithm : equal; int[][] x = new int[][2]; x[0] = [1, 2]; x[1] = [3, 4]; auto ror = transversal(x, 1); assert(equal(ror, [ 2, 4 ][])); } @safe unittest { import std.internal.test.dummyrange; int[][] x = new int[][2]; x[0] = [ 1, 2 ]; x[1] = [3, 4]; auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1); auto witness = [ 2, 4 ]; uint i; foreach (e; ror) assert(e == witness[i++]); assert(i == 2); assert(ror.length == 2); static assert(is(Transversal!(immutable int[][]))); // Make sure ref, assign is being propagated. { ror.front++; scope(exit) ror.front--; assert(x[0][1] == 3); } { ror.front = 5; scope(exit) ror.front = 2; assert(x[0][1] == 5); assert(ror.moveFront() == 5); } { ror.back = 999; scope(exit) ror.back = 4; assert(x[1][1] == 999); assert(ror.moveBack() == 999); } { ror[0] = 999; scope(exit) ror[0] = 2; assert(x[0][1] == 999); assert(ror.moveAt(0) == 999); } // Test w/o ref return. alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random); auto drs = [D.init, D.init]; foreach(num; 0..10) { auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num); assert(t[0] == t[1]); assert(t[1] == num + 1); } static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1)))); // Test slicing. auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]; auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1..3]; assert(mat1[0] == 6); assert(mat1[1] == 10); } struct Transposed(RangeOfRanges) if (isForwardRange!RangeOfRanges && isInputRange!(ElementType!RangeOfRanges) && hasAssignableElements!RangeOfRanges) { //alias ElementType = typeof(map!"a.front"(RangeOfRanges.init)); this(RangeOfRanges input) { this._input = input; } @property auto front() { import std.algorithm : filter, map; return _input.save .filter!(a => !a.empty) .map!(a => a.front); } void popFront() { // Advance the position of each subrange. auto r = _input.save; while (!r.empty) { auto e = r.front; if (!e.empty) { e.popFront(); r.front = e; } r.popFront(); } } // ElementType opIndex(size_t n) // { // return _input[n].front; // } @property bool empty() { if (_input.empty) return true; foreach (e; _input.save) { if (!e.empty) return false; } return true; } @property Transposed save() { return Transposed(_input.save); } auto opSlice() { return this; } private: RangeOfRanges _input; } @safe unittest { // Boundary case: transpose of empty range should be empty int[][] ror = []; assert(transposed(ror).empty); } // Issue 9507 unittest { import std.algorithm : equal; auto r = [[1,2], [3], [4,5], [], [6]]; assert(r.transposed.equal!equal([ [1, 3, 4, 6], [2, 5] ])); } /** Given a range of ranges, returns a range of ranges where the $(I i)'th subrange contains the $(I i)'th elements of the original subranges. */ Transposed!RangeOfRanges transposed(RangeOfRanges)(RangeOfRanges rr) if (isForwardRange!RangeOfRanges && isInputRange!(ElementType!RangeOfRanges) && hasAssignableElements!RangeOfRanges) { return Transposed!RangeOfRanges(rr); } /// @safe unittest { import std.algorithm : equal; int[][] ror = [ [1, 2, 3], [4, 5, 6] ]; auto xp = transposed(ror); assert(equal!"a.equal(b)"(xp, [ [1, 4], [2, 5], [3, 6] ])); } /// @safe unittest { int[][] x = new int[][2]; x[0] = [1, 2]; x[1] = [3, 4]; auto tr = transposed(x); int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ]; uint i; foreach (e; tr) { assert(array(e) == witness[i++]); } } // Issue 8764 @safe unittest { import std.algorithm : equal; ulong[1] t0 = [ 123 ]; assert(!hasAssignableElements!(typeof(t0[].chunks(1)))); assert(!is(typeof(transposed(t0[].chunks(1))))); assert(is(typeof(transposed(t0[].chunks(1).array())))); auto t1 = transposed(t0[].chunks(1).array()); assert(equal!"a.equal(b)"(t1, [[123]])); } /** This struct takes two ranges, $(D source) and $(D indices), and creates a view of $(D source) as if its elements were reordered according to $(D indices). $(D indices) may include only a subset of the elements of $(D source) and may also repeat elements. $(D Source) must be a random access range. The returned range will be bidirectional or random-access if $(D Indices) is bidirectional or random-access, respectively. */ struct Indexed(Source, Indices) if(isRandomAccessRange!Source && isInputRange!Indices && is(typeof(Source.init[ElementType!(Indices).init]))) { this(Source source, Indices indices) { this._source = source; this._indices = indices; } /// Range primitives @property auto ref front() { assert(!empty); return _source[_indices.front]; } /// Ditto void popFront() { assert(!empty); _indices.popFront(); } static if(isInfinite!Indices) { enum bool empty = false; } else { /// Ditto @property bool empty() { return _indices.empty; } } static if(isForwardRange!Indices) { /// Ditto @property typeof(this) save() { // Don't need to save _source because it's never consumed. return typeof(this)(_source, _indices.save); } } /// Ditto static if(hasAssignableElements!Source) { @property auto ref front(ElementType!Source newVal) { assert(!empty); return _source[_indices.front] = newVal; } } static if(hasMobileElements!Source) { /// Ditto auto moveFront() { assert(!empty); return .moveAt(_source, _indices.front); } } static if(isBidirectionalRange!Indices) { /// Ditto @property auto ref back() { assert(!empty); return _source[_indices.back]; } /// Ditto void popBack() { assert(!empty); _indices.popBack(); } /// Ditto static if(hasAssignableElements!Source) { @property auto ref back(ElementType!Source newVal) { assert(!empty); return _source[_indices.back] = newVal; } } static if(hasMobileElements!Source) { /// Ditto auto moveBack() { assert(!empty); return .moveAt(_source, _indices.back); } } } static if(hasLength!Indices) { /// Ditto @property size_t length() { return _indices.length; } alias opDollar = length; } static if(isRandomAccessRange!Indices) { /// Ditto auto ref opIndex(size_t index) { return _source[_indices[index]]; } /// Ditto typeof(this) opSlice(size_t a, size_t b) { return typeof(this)(_source, _indices[a..b]); } static if(hasAssignableElements!Source) { /// Ditto auto opIndexAssign(ElementType!Source newVal, size_t index) { return _source[_indices[index]] = newVal; } } static if(hasMobileElements!Source) { /// Ditto auto moveAt(size_t index) { return .moveAt(_source, _indices[index]); } } } // All this stuff is useful if someone wants to index an Indexed // without adding a layer of indirection. /** Returns the source range. */ @property Source source() { return _source; } /** Returns the indices range. */ @property Indices indices() { return _indices; } static if(isRandomAccessRange!Indices) { /** Returns the physical index into the source range corresponding to a given logical index. This is useful, for example, when indexing an $(D Indexed) without adding another layer of indirection. */ size_t physicalIndex(size_t logicalIndex) { return _indices[logicalIndex]; } /// unittest { auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); assert(ind.physicalIndex(0) == 1); } } private: Source _source; Indices _indices; } /// Ditto Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices) { return typeof(return)(source, indices); } /// @safe unittest { import std.algorithm : equal; auto source = [1, 2, 3, 4, 5]; auto indices = [4, 3, 1, 2, 0, 4]; auto ind = indexed(source, indices); assert(equal(ind, [5, 4, 2, 3, 1, 5])); assert(equal(retro(ind), [5, 1, 3, 2, 4, 5])); } @safe unittest { { auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); assert(ind.physicalIndex(0) == 1); } auto source = [1, 2, 3, 4, 5]; auto indices = [4, 3, 1, 2, 0, 4]; auto ind = indexed(source, indices); // When elements of indices are duplicated and Source has lvalue elements, // these are aliased in ind. ind[0]++; assert(ind[0] == 6); assert(ind[5] == 6); } @safe unittest { import std.internal.test.dummyrange; foreach(DummyType; AllDummyRanges) { auto d = DummyType.init; auto r = indexed([1, 2, 3, 4, 5], d); static assert(propagatesRangeType!(DummyType, typeof(r))); static assert(propagatesLength!(DummyType, typeof(r))); } } /** This range iterates over fixed-sized chunks of size $(D chunkSize) of a $(D source) range. $(D Source) must be a forward range. $(D chunkSize) must be greater than zero. If $(D !isInfinite!Source) and $(D source.walkLength) is not evenly divisible by $(D chunkSize), the back element of this range will contain fewer than $(D chunkSize) elements. */ struct Chunks(Source) if (isForwardRange!Source) { /// Standard constructor this(Source source, size_t chunkSize) { assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize"); _source = source; _chunkSize = chunkSize; } /// Forward range primitives. Always present. @property auto front() { assert(!empty); return _source.save.take(_chunkSize); } /// Ditto void popFront() { assert(!empty); _source.popFrontN(_chunkSize); } static if (!isInfinite!Source) /// Ditto @property bool empty() { return _source.empty; } else // undocumented enum empty = false; /// Ditto @property typeof(this) save() { return typeof(this)(_source.save, _chunkSize); } static if (hasLength!Source) { /// Length. Only if $(D hasLength!Source) is $(D true) @property size_t length() { // Note: _source.length + _chunkSize may actually overflow. // We cast to ulong to mitigate the problem on x86 machines. // For x64 machines, we just suppose we'll never overflow. // The "safe" code would require either an extra branch, or a // modulo operation, which is too expensive for such a rare case return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize); } //Note: No point in defining opDollar here without slicing. //opDollar is defined below in the hasSlicing!Source section } static if (hasSlicing!Source) { //Used for various purposes private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source); /** Indexing and slicing operations. Provided only if $(D hasSlicing!Source) is $(D true). */ auto opIndex(size_t index) { immutable start = index * _chunkSize; immutable end = start + _chunkSize; static if (isInfinite!Source) return _source[start .. end]; else { import std.algorithm : min; immutable len = _source.length; assert(start < len, "chunks index out of bounds"); return _source[start .. min(end, len)]; } } /// Ditto static if (hasLength!Source) typeof(this) opSlice(size_t lower, size_t upper) { import std.algorithm : min; assert(lower <= upper && upper <= length, "chunks slicing index out of bounds"); immutable len = _source.length; return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize); } else static if (hasSliceToEnd) //For slicing an infinite chunk, we need to slice the source to the end. typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper) { assert(lower <= upper, "chunks slicing index out of bounds"); return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower); } static if (isInfinite!Source) { static if (hasSliceToEnd) { private static struct DollarToken{} DollarToken opDollar() { return DollarToken(); } //Slice to dollar typeof(this) opSlice(size_t lower, DollarToken) { return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize); } } } else { //Dollar token carries a static type, with no extra information. //It can lazily transform into _source.length on algorithmic //operations such as : chunks[$/2, $-1]; private static struct DollarToken { Chunks!Source* mom; @property size_t momLength() { return mom.length; } alias momLength this; } DollarToken opDollar() { return DollarToken(&this); } //Slice overloads optimized for using dollar. Without this, to slice to end, we would... //1. Evaluate chunks.length //2. Multiply by _chunksSize //3. To finally just compare it (with min) to the original length of source (!) //These overloads avoid that. typeof(this) opSlice(DollarToken, DollarToken) { static if (hasSliceToEnd) return chunks(_source[$ .. $], _chunkSize); else { immutable len = _source.length; return chunks(_source[len .. len], _chunkSize); } } typeof(this) opSlice(size_t lower, DollarToken) { import std.algorithm : min; assert(lower <= length, "chunks slicing index out of bounds"); static if (hasSliceToEnd) return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize); else { immutable len = _source.length; return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize); } } typeof(this) opSlice(DollarToken, size_t upper) { assert(upper == length, "chunks slicing index out of bounds"); return this[$ .. $]; } } } //Bidirectional range primitives static if (hasSlicing!Source && hasLength!Source) { /** Bidirectional range primitives. Provided only if both $(D hasSlicing!Source) and $(D hasLength!Source) are $(D true). */ @property auto back() { assert(!empty, "back called on empty chunks"); immutable len = _source.length; immutable start = (len - 1) / _chunkSize * _chunkSize; return _source[start .. len]; } /// Ditto void popBack() { assert(!empty, "popBack() called on empty chunks"); immutable end = (_source.length - 1) / _chunkSize * _chunkSize; _source = _source[0 .. end]; } } private: Source _source; size_t _chunkSize; } /// Ditto Chunks!Source chunks(Source)(Source source, size_t chunkSize) if (isForwardRange!Source) { return typeof(return)(source, chunkSize); } /// @safe unittest { import std.algorithm : equal; auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto chunks = chunks(source, 4); assert(chunks[0] == [1, 2, 3, 4]); assert(chunks[1] == [5, 6, 7, 8]); assert(chunks[2] == [9, 10]); assert(chunks.back == chunks[2]); assert(chunks.front == chunks[0]); assert(chunks.length == 3); assert(equal(retro(array(chunks)), array(retro(chunks)))); } @safe unittest { auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto chunks = chunks(source, 4); auto chunks2 = chunks.save; chunks.popFront(); assert(chunks[0] == [5, 6, 7, 8]); assert(chunks[1] == [9, 10]); chunks2.popBack(); assert(chunks2[1] == [5, 6, 7, 8]); assert(chunks2.length == 2); static assert(isRandomAccessRange!(typeof(chunks))); } @safe unittest { import std.algorithm : equal; //Extra toying with slicing and indexing. auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2); auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2); assert (chunks1.length == 5); assert (chunks2.length == 5); assert (chunks1[4] == [4]); assert (chunks2[4] == [4, 4]); assert (chunks1.back == [4]); assert (chunks2.back == [4, 4]); assert (chunks1[0 .. 1].equal([[0, 0]])); assert (chunks1[0 .. 2].equal([[0, 0], [1, 1]])); assert (chunks1[4 .. 5].equal([[4]])); assert (chunks2[4 .. 5].equal([[4, 4]])); assert (chunks1[0 .. 0].equal((int[][]).init)); assert (chunks1[5 .. 5].equal((int[][]).init)); assert (chunks2[5 .. 5].equal((int[][]).init)); //Fun with opDollar assert (chunks1[$ .. $].equal((int[][]).init)); //Quick assert (chunks2[$ .. $].equal((int[][]).init)); //Quick assert (chunks1[$ - 1 .. $].equal([[4]])); //Semiquick assert (chunks2[$ - 1 .. $].equal([[4, 4]])); //Semiquick assert (chunks1[$ .. 5].equal((int[][]).init)); //Semiquick assert (chunks2[$ .. 5].equal((int[][]).init)); //Semiquick assert (chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow } unittest { import std.algorithm : equal, filter; //ForwardRange auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2); assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]])); //InfiniteRange w/o RA auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2); assert(equal!`equal(a, b)`(fibsByPairs.take(2), [[ 1, 1], [ 2, 3]])); //InfiniteRange w/ RA and slicing auto odds = sequence!("a[0] + n * a[1]")(1, 2); auto oddsByPairs = odds.chunks(2); assert(equal!`equal(a, b)`(oddsByPairs.take(2), [[ 1, 3], [ 5, 7]])); //Requires phobos#991 for Sequence to have slice to end static assert(hasSlicing!(typeof(odds))); assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5], [[13, 15], [17, 19]])); assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]])); } /** This range splits a $(D source) range into $(D chunkCount) chunks of approximately equal length. $(D Source) must be a forward range with known length. Unlike $(LREF chunks), $(D evenChunks) takes a chunk count (not size). The returned range will contain zero or more $(D source.length / chunkCount + 1) elements followed by $(D source.length / chunkCount) elements. If $(D source.length < chunkCount), some chunks will be empty. $(D chunkCount) must not be zero, unless $(D source) is also empty. */ struct EvenChunks(Source) if (isForwardRange!Source && hasLength!Source) { /// Standard constructor this(Source source, size_t chunkCount) { assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount"); _source = source; _chunkCount = chunkCount; } /// Forward range primitives. Always present. @property auto front() { assert(!empty); return _source.save.take(_chunkPos(1)); } /// Ditto void popFront() { assert(!empty); _source.popFrontN(_chunkPos(1)); _chunkCount--; } /// Ditto @property bool empty() { return _source.empty; } /// Ditto @property typeof(this) save() { return typeof(this)(_source.save, _chunkCount); } /// Length @property size_t length() { return _chunkCount; } //Note: No point in defining opDollar here without slicing. //opDollar is defined below in the hasSlicing!Source section static if (hasSlicing!Source) { /** Indexing, slicing and bidirectional operations and range primitives. Provided only if $(D hasSlicing!Source) is $(D true). */ auto opIndex(size_t index) { assert(index < _chunkCount, "evenChunks index out of bounds"); return _source[_chunkPos(index) .. _chunkPos(index+1)]; } /// Ditto typeof(this) opSlice(size_t lower, size_t upper) { assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds"); return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower); } /// Ditto @property auto back() { assert(!empty, "back called on empty evenChunks"); return _source[_chunkPos(_chunkCount - 1) .. $]; } /// Ditto void popBack() { assert(!empty, "popBack() called on empty evenChunks"); _source = _source[0 .. _chunkPos(_chunkCount - 1)]; _chunkCount--; } } private: Source _source; size_t _chunkCount; size_t _chunkPos(size_t i) { /* _chunkCount = 5, _source.length = 13: chunk0 | chunk3 | | v v +-+-+-+-+-+ ^ |0|3|.| | | | +-+-+-+-+-+ | div |1|4|.| | | | +-+-+-+-+-+ v |2|5|.| +-+-+-+ <-----> mod <---------> _chunkCount One column is one chunk. popFront and popBack pop the left-most and right-most column, respectively. */ auto div = _source.length / _chunkCount; auto mod = _source.length % _chunkCount; auto pos = i <= mod ? i * (div+1) : mod * (div+1) + (i-mod) * div ; //auto len = i < mod // ? div+1 // : div //; return pos; } } /// Ditto EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount) if (isForwardRange!Source && hasLength!Source) { return typeof(return)(source, chunkCount); } /// @safe unittest { import std.algorithm : equal; auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto chunks = evenChunks(source, 3); assert(chunks[0] == [1, 2, 3, 4]); assert(chunks[1] == [5, 6, 7]); assert(chunks[2] == [8, 9, 10]); } @safe unittest { import std.algorithm : equal; auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto chunks = evenChunks(source, 3); assert(chunks.back == chunks[2]); assert(chunks.front == chunks[0]); assert(chunks.length == 3); assert(equal(retro(array(chunks)), array(retro(chunks)))); auto chunks2 = chunks.save; chunks.popFront(); assert(chunks[0] == [5, 6, 7]); assert(chunks[1] == [8, 9, 10]); chunks2.popBack(); assert(chunks2[1] == [5, 6, 7]); assert(chunks2.length == 2); static assert(isRandomAccessRange!(typeof(chunks))); } @safe unittest { import std.algorithm : equal; int[] source = []; auto chunks = source.evenChunks(0); assert(chunks.length == 0); chunks = source.evenChunks(3); assert(equal(chunks, [[], [], []])); chunks = [1, 2, 3].evenChunks(5); assert(equal(chunks, [[1], [2], [3], [], []])); } private struct OnlyResult(T, size_t arity) { private this(Values...)(auto ref Values values) { this.data = [values]; this.backIndex = arity; } bool empty() @property { return frontIndex >= backIndex; } T front() @property { assert(!empty); return data[frontIndex]; } void popFront() { assert(!empty); ++frontIndex; } T back() @property { assert(!empty); return data[backIndex - 1]; } void popBack() { assert(!empty); --backIndex; } OnlyResult save() @property { return this; } size_t length() @property { return backIndex - frontIndex; } alias opDollar = length; T opIndex(size_t idx) { // when i + idx points to elements popped // with popBack assert(idx < length); return data[frontIndex + idx]; } OnlyResult opSlice() { return this; } OnlyResult opSlice(size_t from, size_t to) { OnlyResult result = this; result.frontIndex += from; result.backIndex = this.frontIndex + to; assert(from <= to && to <= length); return result; } private size_t frontIndex = 0; private size_t backIndex = 0; // @@@BUG@@@ 10643 version(none) { static if(hasElaborateAssign!T) private T[arity] data; else private T[arity] data = void; } else private T[arity] data; } // Specialize for single-element results private struct OnlyResult(T, size_t arity : 1) { @property T front() { assert(!_empty); return _value; } @property T back() { assert(!_empty); return _value; } @property bool empty() const { return _empty; } @property size_t length() const { return !_empty; } @property auto save() { return this; } void popFront() { assert(!_empty); _empty = true; } void popBack() { assert(!_empty); _empty = true; } alias opDollar = length; private this()(auto ref T value) { this._value = value; this._empty = false; } T opIndex(size_t i) { assert(!_empty && i == 0); return _value; } OnlyResult opSlice() { return this; } OnlyResult opSlice(size_t from, size_t to) { assert(from <= to && to <= length); OnlyResult copy = this; copy._empty = _empty || from == to; return copy; } private Unqual!T _value; private bool _empty = true; } // Specialize for the empty range private struct OnlyResult(T, size_t arity : 0) { private static struct EmptyElementType {} bool empty() @property { return true; } size_t length() @property { return 0; } alias opDollar = length; EmptyElementType front() @property { assert(false); } void popFront() { assert(false); } EmptyElementType back() @property { assert(false); } void popBack() { assert(false); } OnlyResult save() @property { return this; } EmptyElementType opIndex(size_t i) { assert(false); } OnlyResult opSlice() { return this; } OnlyResult opSlice(size_t from, size_t to) { assert(from == 0 && to == 0); return this; } } /** Assemble $(D values) into a range that carries all its elements in-situ. Useful when a single value or multiple disconnected values must be passed to an algorithm expecting a range, without having to perform dynamic memory allocation. As copying the range means copying all elements, it can be safely returned from functions. For the same reason, copying the returned range may be expensive for a large number of arguments. */ auto only(Values...)(auto ref Values values) if(!is(CommonType!Values == void) || Values.length == 0) { return OnlyResult!(CommonType!Values, Values.length)(values); } /// @safe unittest { import std.algorithm; import std.uni; assert(equal(only('♡'), "♡")); assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); assert(only("one", "two", "three").joiner(" ").equal("one two three")); string title = "The D Programming Language"; assert(filter!isUpper(title).map!only().join(".") == "T.D.P.L"); } unittest { // Verify that the same common type and same arity // results in the same template instantiation static assert(is(typeof(only(byte.init, int.init)) == typeof(only(int.init, byte.init)))); static assert(is(typeof(only((const(char)[]).init, string.init)) == typeof(only((const(char)[]).init, (const(char)[]).init)))); } // Tests the zero-element result @safe unittest { import std.algorithm : equal; auto emptyRange = only(); alias EmptyRange = typeof(emptyRange); static assert(isInputRange!EmptyRange); static assert(isForwardRange!EmptyRange); static assert(isBidirectionalRange!EmptyRange); static assert(isRandomAccessRange!EmptyRange); static assert(hasLength!EmptyRange); static assert(hasSlicing!EmptyRange); assert(emptyRange.empty); assert(emptyRange.length == 0); assert(emptyRange.equal(emptyRange[])); assert(emptyRange.equal(emptyRange.save)); assert(emptyRange[0 .. 0].equal(emptyRange)); } // Tests the single-element result @safe unittest { import std.algorithm : equal; import std.typecons : tuple; foreach (x; tuple(1, '1', 1.0, "1", [1])) { auto a = only(x); typeof(x)[] e = []; assert(a.front == x); assert(a.back == x); assert(!a.empty); assert(a.length == 1); assert(equal(a, a[])); assert(equal(a, a[0..1])); assert(equal(a[0..0], e)); assert(equal(a[1..1], e)); assert(a[0] == x); auto b = a.save; assert(equal(a, b)); a.popFront(); assert(a.empty && a.length == 0 && a[].empty); b.popBack(); assert(b.empty && b.length == 0 && b[].empty); alias A = typeof(a); static assert(isInputRange!A); static assert(isForwardRange!A); static assert(isBidirectionalRange!A); static assert(isRandomAccessRange!A); static assert(hasLength!A); static assert(hasSlicing!A); } auto imm = only!(immutable int)(1); immutable int[] imme = []; assert(imm.front == 1); assert(imm.back == 1); assert(!imm.empty); assert(imm.init.empty); // Issue 13441 assert(imm.length == 1); assert(equal(imm, imm[])); assert(equal(imm, imm[0..1])); assert(equal(imm[0..0], imme)); assert(equal(imm[1..1], imme)); assert(imm[0] == 1); } // Tests multiple-element results @safe unittest { import std.algorithm : equal, joiner; static assert(!__traits(compiles, only(1, "1"))); auto nums = only!(byte, uint, long)(1, 2, 3); static assert(is(ElementType!(typeof(nums)) == long)); assert(nums.length == 3); foreach(i; 0 .. 3) assert(nums[i] == i + 1); auto saved = nums.save; foreach(i; 1 .. 4) { assert(nums.front == nums[0]); assert(nums.front == i); nums.popFront(); assert(nums.length == 3 - i); } assert(nums.empty); assert(saved.equal(only(1, 2, 3))); assert(saved.equal(saved[])); assert(saved[0 .. 1].equal(only(1))); assert(saved[0 .. 2].equal(only(1, 2))); assert(saved[0 .. 3].equal(saved)); assert(saved[1 .. 3].equal(only(2, 3))); assert(saved[2 .. 3].equal(only(3))); assert(saved[0 .. 0].empty); assert(saved[3 .. 3].empty); alias data = AliasSeq!("one", "two", "three", "four"); static joined = ["one two", "one two three", "one two three four"]; string[] joinedRange = joined; foreach(argCount; AliasSeq!(2, 3, 4)) { auto values = only(data[0 .. argCount]); alias Values = typeof(values); static assert(is(ElementType!Values == string)); static assert(isInputRange!Values); static assert(isForwardRange!Values); static assert(isBidirectionalRange!Values); static assert(isRandomAccessRange!Values); static assert(hasSlicing!Values); static assert(hasLength!Values); assert(values.length == argCount); assert(values[0 .. $].equal(values[0 .. values.length])); assert(values.joiner(" ").equal(joinedRange.front)); joinedRange.popFront(); } assert(saved.retro.equal(only(3, 2, 1))); assert(saved.length == 3); assert(saved.back == 3); saved.popBack(); assert(saved.length == 2); assert(saved.back == 2); assert(saved.front == 1); saved.popFront(); assert(saved.length == 1); assert(saved.front == 2); saved.popBack(); assert(saved.empty); auto imm = only!(immutable int, immutable int)(42, 24); alias Imm = typeof(imm); static assert(is(ElementType!Imm == immutable(int))); assert(!imm.empty); assert(imm.init.empty); // Issue 13441 assert(imm.front == 42); imm.popFront(); assert(imm.front == 24); imm.popFront(); assert(imm.empty); static struct Test { int* a; } immutable(Test) test; cast(void)only(test, test); // Works with mutable indirection } /** Iterate over $(D range) with an attached index variable. Each element is a $(XREF typecons, Tuple) containing the index and the element, in that order, where the index member is named $(D index) and the element member is named $(D value). The index starts at $(D start) and is incremented by one on every iteration. Bidirectionality is propagated only if $(D range) has length. Overflow: If $(D range) has length, then it is an error to pass a value for $(D start) so that $(D start + range.length) is bigger than $(D Enumerator.max), thus it is ensured that overflow cannot happen. If $(D range) does not have length, and $(D popFront) is called when $(D front.index == Enumerator.max), the index will overflow and continue from $(D Enumerator.min). Example: Useful for using $(D foreach) with an index loop variable: ---- import std.stdio : stdin, stdout; import std.range : enumerate; foreach (lineNum, line; stdin.byLine().enumerate(1)) stdout.writefln("line #%s: %s", lineNum, line); ---- */ auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0) if (isIntegral!Enumerator && isInputRange!Range) in { static if (hasLength!Range) { // TODO: core.checkedint supports mixed signedness yet? import core.checkedint : adds, addu; import std.conv : ConvException, to; alias LengthType = typeof(range.length); bool overflow; static if(isSigned!Enumerator && isSigned!LengthType) auto result = adds(start, range.length, overflow); else static if(isSigned!Enumerator) { Largest!(Enumerator, Signed!LengthType) signedLength; try signedLength = to!(typeof(signedLength))(range.length); catch(ConvException) overflow = true; catch(Exception) assert(false); auto result = adds(start, signedLength, overflow); } else { static if(isSigned!LengthType) assert(range.length >= 0); auto result = addu(start, range.length, overflow); } assert(!overflow && result <= Enumerator.max); } } body { // TODO: Relax isIntegral!Enumerator to allow user-defined integral types static struct Result { import std.typecons : Tuple; private: alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value"); Range range; Enumerator index; public: ElemType front() @property { assert(!range.empty); return typeof(return)(index, range.front); } static if (isInfinite!Range) enum bool empty = false; else { bool empty() @property { return range.empty; } } void popFront() { assert(!range.empty); range.popFront(); ++index; // When !hasLength!Range, overflow is expected } static if (isForwardRange!Range) { Result save() @property { return typeof(return)(range.save, index); } } static if (hasLength!Range) { size_t length() @property { return range.length; } alias opDollar = length; static if (isBidirectionalRange!Range) { ElemType back() @property { assert(!range.empty); return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back); } void popBack() { assert(!range.empty); range.popBack(); } } } static if (isRandomAccessRange!Range) { ElemType opIndex(size_t i) { return typeof(return)(cast(Enumerator)(index + i), range[i]); } } static if (hasSlicing!Range) { static if (hasLength!Range) { Result opSlice(size_t i, size_t j) { return typeof(return)(range[i .. j], cast(Enumerator)(index + i)); } } else { static struct DollarToken {} enum opDollar = DollarToken.init; Result opSlice(size_t i, DollarToken) { return typeof(return)(range[i .. $], cast(Enumerator)(index + i)); } auto opSlice(size_t i, size_t j) { return this[i .. $].takeExactly(j - 1); } } } } return Result(range, start); } /// Can start enumeration from a negative position: pure @safe nothrow unittest { import std.array : assocArray; import std.range : enumerate; bool[int] aa = true.repeat(3).enumerate(-1).assocArray(); assert(aa[-1]); assert(aa[0]); assert(aa[1]); } pure @safe nothrow unittest { import std.internal.test.dummyrange; import std.typecons : tuple; static struct HasSlicing { typeof(this) front() @property { return typeof(this).init; } bool empty() @property { return true; } void popFront() {} typeof(this) opSlice(size_t, size_t) { return typeof(this)(); } } foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing)) { alias R = typeof(enumerate(DummyType.init)); static assert(isInputRange!R); static assert(isForwardRange!R == isForwardRange!DummyType); static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType); static assert(!hasAssignableElements!R); static if (hasLength!DummyType) { static assert(hasLength!R); static assert(isBidirectionalRange!R == isBidirectionalRange!DummyType); } static assert(hasSlicing!R == hasSlicing!DummyType); } static immutable values = ["zero", "one", "two", "three"]; auto enumerated = values[].enumerate(); assert(!enumerated.empty); assert(enumerated.front == tuple(0, "zero")); assert(enumerated.back == tuple(3, "three")); typeof(enumerated) saved = enumerated.save; saved.popFront(); assert(enumerated.front == tuple(0, "zero")); assert(saved.front == tuple(1, "one")); assert(saved.length == enumerated.length - 1); saved.popBack(); assert(enumerated.back == tuple(3, "three")); assert(saved.back == tuple(2, "two")); saved.popFront(); assert(saved.front == tuple(2, "two")); assert(saved.back == tuple(2, "two")); saved.popFront(); assert(saved.empty); size_t control = 0; foreach (i, v; enumerated) { static assert(is(typeof(i) == size_t)); static assert(is(typeof(v) == typeof(values[0]))); assert(i == control); assert(v == values[i]); assert(tuple(i, v) == enumerated[i]); ++control; } assert(enumerated[0 .. $].front == tuple(0, "zero")); assert(enumerated[$ - 1 .. $].front == tuple(3, "three")); foreach(i; 0 .. 10) { auto shifted = values[0 .. 2].enumerate(i); assert(shifted.front == tuple(i, "zero")); assert(shifted[0] == shifted.front); auto next = tuple(i + 1, "one"); assert(shifted[1] == next); shifted.popFront(); assert(shifted.front == next); shifted.popFront(); assert(shifted.empty); } foreach(T; AliasSeq!(ubyte, byte, uint, int)) { auto inf = 42.repeat().enumerate(T.max); alias Inf = typeof(inf); static assert(isInfinite!Inf); static assert(hasSlicing!Inf); // test overflow assert(inf.front == tuple(T.max, 42)); inf.popFront(); assert(inf.front == tuple(T.min, 42)); // test slicing inf = inf[42 .. $]; assert(inf.front == tuple(T.min + 42, 42)); auto window = inf[0 .. 2]; assert(window.length == 1); assert(window.front == inf.front); window.popFront(); assert(window.empty); } } pure @safe unittest { import std.algorithm : equal; static immutable int[] values = [0, 1, 2, 3, 4]; foreach(T; AliasSeq!(ubyte, ushort, uint, ulong)) { auto enumerated = values.enumerate!T(); static assert(is(typeof(enumerated.front.index) == T)); assert(enumerated.equal(values[].zip(values))); foreach(T i; 0 .. 5) { auto subset = values[cast(size_t)i .. $]; auto offsetEnumerated = subset.enumerate(i); static assert(is(typeof(enumerated.front.index) == T)); assert(offsetEnumerated.equal(subset.zip(subset))); } } } version(none) // @@@BUG@@@ 10939 { // Re-enable (or remove) if 10939 is resolved. /+pure+/ unittest // Impure because of std.conv.to { import std.exception : assertNotThrown, assertThrown; import core.exception : RangeError; static immutable values = [42]; static struct SignedLengthRange { immutable(int)[] _values = values; int front() @property { assert(false); } bool empty() @property { assert(false); } void popFront() { assert(false); } int length() @property { return cast(int)_values.length; } } SignedLengthRange svalues; foreach(Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long)) { assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max)); assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length)); assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1)); assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max)); assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length)); assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1)); } foreach(Enumerator; AliasSeq!(byte, short, int)) { assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator()); } assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long()); } } /** Returns true if $(D fn) accepts variables of type T1 and T2 in any order. The following code should compile: --- T1 foo(); T2 bar(); fn(foo(), bar()); fn(bar(), foo()); --- */ template isTwoWayCompatible(alias fn, T1, T2) { enum isTwoWayCompatible = is(typeof( (){ T1 foo(); T2 bar(); fn(foo(), bar()); fn(bar(), foo()); } )); } /** Policy used with the searching primitives $(D lowerBound), $(D upperBound), and $(D equalRange) of $(LREF SortedRange) below. */ enum SearchPolicy { /** Searches in a linear fashion. */ linear, /** Searches with a step that is grows linearly (1, 2, 3,...) leading to a quadratic search schedule (indexes tried are 0, 1, 3, 6, 10, 15, 21, 28,...) Once the search overshoots its target, the remaining interval is searched using binary search. The search is completed in $(BIGOH sqrt(n)) time. Use it when you are reasonably confident that the value is around the beginning of the range. */ trot, /** Performs a $(LUCKY galloping search algorithm), i.e. searches with a step that doubles every time, (1, 2, 4, 8, ...) leading to an exponential search schedule (indexes tried are 0, 1, 3, 7, 15, 31, 63,...) Once the search overshoots its target, the remaining interval is searched using binary search. A value is found in $(BIGOH log(n)) time. */ gallop, /** Searches using a classic interval halving policy. The search starts in the middle of the range, and each search step cuts the range in half. This policy finds a value in $(BIGOH log(n)) time but is less cache friendly than $(D gallop) for large ranges. The $(D binarySearch) policy is used as the last step of $(D trot), $(D gallop), $(D trotBackwards), and $(D gallopBackwards) strategies. */ binarySearch, /** Similar to $(D trot) but starts backwards. Use it when confident that the value is around the end of the range. */ trotBackwards, /** Similar to $(D gallop) but starts backwards. Use it when confident that the value is around the end of the range. */ gallopBackwards } /** Represents a sorted range. In addition to the regular range primitives, supports additional operations that take advantage of the ordering, such as merge and binary search. To obtain a $(D SortedRange) from an unsorted range $(D r), use $(XREF_PACK algorithm,sorting,sort) which sorts $(D r) in place and returns the corresponding $(D SortedRange). To construct a $(D SortedRange) from a range $(D r) that is known to be already sorted, use $(LREF assumeSorted) described below. */ struct SortedRange(Range, alias pred = "a < b") if (isInputRange!Range) { private import std.functional : binaryFun; private alias predFun = binaryFun!pred; private bool geq(L, R)(L lhs, R rhs) { return !predFun(lhs, rhs); } private bool gt(L, R)(L lhs, R rhs) { return predFun(rhs, lhs); } private Range _input; // Undocummented because a clearer way to invoke is by calling // assumeSorted. this(Range input) out { // moved out of the body as a workaround for Issue 12661 dbgVerifySorted(); } body { this._input = input; } // Assertion only. private void dbgVerifySorted() { if(!__ctfe) debug { static if (isRandomAccessRange!Range) { import core.bitop : bsr; import std.algorithm : isSorted; // Check the sortedness of the input if (this._input.length < 2) return; immutable size_t msb = bsr(this._input.length) + 1; assert(msb > 0 && msb <= this._input.length); immutable step = this._input.length / msb; auto st = stride(this._input, step); assert(isSorted!pred(st), "Range is not sorted"); } } } /// Range primitives. @property bool empty() //const { return this._input.empty; } /// Ditto static if (isForwardRange!Range) @property auto save() { // Avoid the constructor typeof(this) result = this; result._input = _input.save; return result; } /// Ditto @property auto ref front() { return _input.front; } /// Ditto void popFront() { _input.popFront(); } /// Ditto static if (isBidirectionalRange!Range) { @property auto ref back() { return _input.back; } /// Ditto void popBack() { _input.popBack(); } } /// Ditto static if (isRandomAccessRange!Range) auto ref opIndex(size_t i) { return _input[i]; } /// Ditto static if (hasSlicing!Range) auto opSlice(size_t a, size_t b) { assert(a <= b); typeof(this) result = this; result._input = _input[a .. b];// skip checking return result; } /// Ditto static if (hasLength!Range) { @property size_t length() //const { return _input.length; } alias opDollar = length; } /** Releases the controlled range and returns it. */ auto release() { import std.algorithm : move; return move(_input); } // Assuming a predicate "test" that returns 0 for a left portion // of the range and then 1 for the rest, returns the index at // which the first 1 appears. Used internally by the search routines. private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range) { size_t first = 0, count = _input.length; while (count > 0) { immutable step = count / 2, it = first + step; if (!test(_input[it], v)) { first = it + 1; count -= step + 1; } else { count = step; } } return first; } // Specialization for trot and gallop private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop) && isRandomAccessRange!Range) { if (empty || test(front, v)) return 0; immutable count = length; if (count == 1) return 1; size_t below = 0, above = 1, step = 2; while (!test(_input[above], v)) { // Still too small, update below and increase gait below = above; immutable next = above + step; if (next >= count) { // Overshot - the next step took us beyond the end. So // now adjust next and simply exit the loop to do the // binary search thingie. above = count; break; } // Still in business, increase step and continue above = next; static if (sp == SearchPolicy.trot) ++step; else step <<= 1; } return below + this[below .. above].getTransitionIndex!( SearchPolicy.binarySearch, test, V)(v); } // Specialization for trotBackwards and gallopBackwards private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards) && isRandomAccessRange!Range) { immutable count = length; if (empty || !test(back, v)) return count; if (count == 1) return 0; size_t below = count - 2, above = count - 1, step = 2; while (test(_input[below], v)) { // Still too large, update above and increase gait above = below; if (below < step) { // Overshot - the next step took us beyond the end. So // now adjust next and simply fall through to do the // binary search thingie. below = 0; break; } // Still in business, increase step and continue below -= step; static if (sp == SearchPolicy.trot) ++step; else step <<= 1; } return below + this[below .. above].getTransitionIndex!( SearchPolicy.binarySearch, test, V)(v); } // lowerBound /** This function uses a search with policy $(D sp) to find the largest left subrange on which $(D pred(x, value)) is $(D true) for all $(D x) (e.g., if $(D pred) is "less than", returns the portion of the range with elements strictly smaller than $(D value)). The search schedule and its complexity are documented in $(LREF SearchPolicy). See also STL's $(WEB sgi.com/tech/stl/lower_bound.html, lower_bound). */ auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) if (isTwoWayCompatible!(predFun, ElementType!Range, V) && hasSlicing!Range) { return this[0 .. getTransitionIndex!(sp, geq)(value)]; } /// unittest { import std.algorithm: equal; auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]); auto p = a.lowerBound(4); assert(equal(p, [ 0, 1, 2, 3 ])); } // upperBound /** This function searches with policy $(D sp) to find the largest right subrange on which $(D pred(value, x)) is $(D true) for all $(D x) (e.g., if $(D pred) is "less than", returns the portion of the range with elements strictly greater than $(D value)). The search schedule and its complexity are documented in $(LREF SearchPolicy). For ranges that do not offer random access, $(D SearchPolicy.linear) is the only policy allowed (and it must be specified explicitly lest it exposes user code to unexpected inefficiencies). For random-access searches, all policies are allowed, and $(D SearchPolicy.binarySearch) is the default. See_Also: STL's $(WEB sgi.com/tech/stl/lower_bound.html,upper_bound). */ auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) if (isTwoWayCompatible!(predFun, ElementType!Range, V)) { static assert(hasSlicing!Range || sp == SearchPolicy.linear, "Specify SearchPolicy.linear explicitly for " ~ typeof(this).stringof); static if (sp == SearchPolicy.linear) { for (; !_input.empty && !predFun(value, _input.front); _input.popFront()) { } return this; } else { return this[getTransitionIndex!(sp, gt)(value) .. length]; } } /// unittest { import std.algorithm: equal; auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]); auto p = a.upperBound(3); assert(equal(p, [4, 4, 5, 6])); } // equalRange /** Returns the subrange containing all elements $(D e) for which both $(D pred(e, value)) and $(D pred(value, e)) evaluate to $(D false) (e.g., if $(D pred) is "less than", returns the portion of the range with elements equal to $(D value)). Uses a classic binary search with interval halving until it finds a value that satisfies the condition, then uses $(D SearchPolicy.gallopBackwards) to find the left boundary and $(D SearchPolicy.gallop) to find the right boundary. These policies are justified by the fact that the two boundaries are likely to be near the first found value (i.e., equal ranges are relatively small). Completes the entire search in $(BIGOH log(n)) time. See also STL's $(WEB sgi.com/tech/stl/equal_range.html, equal_range). */ auto equalRange(V)(V value) if (isTwoWayCompatible!(predFun, ElementType!Range, V) && isRandomAccessRange!Range) { size_t first = 0, count = _input.length; while (count > 0) { immutable step = count / 2; auto it = first + step; if (predFun(_input[it], value)) { // Less than value, bump left bound up first = it + 1; count -= step + 1; } else if (predFun(value, _input[it])) { // Greater than value, chop count count = step; } else { // Equal to value, do binary searches in the // leftover portions // Gallop towards the left end as it's likely nearby immutable left = first + this[first .. it] .lowerBound!(SearchPolicy.gallopBackwards)(value).length; first += count; // Gallop towards the right end as it's likely nearby immutable right = first - this[it + 1 .. first] .upperBound!(SearchPolicy.gallop)(value).length; return this[left .. right]; } } return this.init; } /// unittest { import std.algorithm: equal; auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; auto r = a.assumeSorted.equalRange(3); assert(equal(r, [ 3, 3, 3 ])); } // trisect /** Returns a tuple $(D r) such that $(D r[0]) is the same as the result of $(D lowerBound(value)), $(D r[1]) is the same as the result of $(D equalRange(value)), and $(D r[2]) is the same as the result of $(D upperBound(value)). The call is faster than computing all three separately. Uses a search schedule similar to $(D equalRange). Completes the entire search in $(BIGOH log(n)) time. */ auto trisect(V)(V value) if (isTwoWayCompatible!(predFun, ElementType!Range, V) && isRandomAccessRange!Range) { import std.typecons : tuple; size_t first = 0, count = _input.length; while (count > 0) { immutable step = count / 2; auto it = first + step; if (predFun(_input[it], value)) { // Less than value, bump left bound up first = it + 1; count -= step + 1; } else if (predFun(value, _input[it])) { // Greater than value, chop count count = step; } else { // Equal to value, do binary searches in the // leftover portions // Gallop towards the left end as it's likely nearby immutable left = first + this[first .. it] .lowerBound!(SearchPolicy.gallopBackwards)(value).length; first += count; // Gallop towards the right end as it's likely nearby immutable right = first - this[it + 1 .. first] .upperBound!(SearchPolicy.gallop)(value).length; return tuple(this[0 .. left], this[left .. right], this[right .. length]); } } // No equal element was found return tuple(this[0 .. first], this.init, this[first .. length]); } /// unittest { import std.algorithm: equal; auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; auto r = assumeSorted(a).trisect(3); assert(equal(r[0], [ 1, 2 ])); assert(equal(r[1], [ 3, 3, 3 ])); assert(equal(r[2], [ 4, 4, 5, 6 ])); } // contains /** Returns $(D true) if and only if $(D value) can be found in $(D range), which is assumed to be sorted. Performs $(BIGOH log(r.length)) evaluations of $(D pred). See also STL's $(WEB sgi.com/tech/stl/binary_search.html, binary_search). */ bool contains(V)(V value) if (isRandomAccessRange!Range) { if(empty) return false; immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value); if(i >= length) return false; return !predFun(value, _input[i]); } // groupBy /** Returns a range of subranges of elements that are equivalent according to the sorting relation. */ auto groupBy()() { import std.algorithm.iteration : chunkBy; return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a)); } } /// unittest { import std.algorithm : sort; auto a = [ 1, 2, 3, 42, 52, 64 ]; auto r = assumeSorted(a); assert(r.contains(3)); assert(!r.contains(32)); auto r1 = sort!"a > b"(a); assert(r1.contains(3)); assert(!r1.contains(32)); assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]); } /** $(D SortedRange) could accept ranges weaker than random-access, but it is unable to provide interesting functionality for them. Therefore, $(D SortedRange) is currently restricted to random-access ranges. No copy of the original range is ever made. If the underlying range is changed concurrently with its corresponding $(D SortedRange) in ways that break its sortedness, $(D SortedRange) will work erratically. */ @safe unittest { import std.algorithm : swap; auto a = [ 1, 2, 3, 42, 52, 64 ]; auto r = assumeSorted(a); assert(r.contains(42)); swap(a[3], a[5]); // illegal to break sortedness of original range assert(!r.contains(42)); // passes although it shouldn't } @safe unittest { import std.algorithm : equal; auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ]; auto r = assumeSorted(a).trisect(30); assert(equal(r[0], [ 10, 20 ])); assert(equal(r[1], [ 30, 30, 30 ])); assert(equal(r[2], [ 40, 40, 50, 60 ])); r = assumeSorted(a).trisect(35); assert(equal(r[0], [ 10, 20, 30, 30, 30 ])); assert(r[1].empty); assert(equal(r[2], [ 40, 40, 50, 60 ])); } @safe unittest { import std.algorithm : equal; auto a = [ "A", "AG", "B", "E", "F" ]; auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w); assert(equal(r[0], [ "A", "AG" ])); assert(equal(r[1], [ "B" ])); assert(equal(r[2], [ "E", "F" ])); r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d); assert(r[0].empty); assert(equal(r[1], [ "A" ])); assert(equal(r[2], [ "AG", "B", "E", "F" ])); } @safe unittest { import std.algorithm : equal; static void test(SearchPolicy pol)() { auto a = [ 1, 2, 3, 42, 52, 64 ]; auto r = assumeSorted(a); assert(equal(r.lowerBound(42), [1, 2, 3])); assert(equal(r.lowerBound!(pol)(42), [1, 2, 3])); assert(equal(r.lowerBound!(pol)(41), [1, 2, 3])); assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42])); assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42])); assert(equal(r.lowerBound!(pol)(3), [1, 2])); assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52])); assert(equal(r.lowerBound!(pol)(420), a)); assert(equal(r.lowerBound!(pol)(0), a[0 .. 0])); assert(equal(r.upperBound!(pol)(42), [52, 64])); assert(equal(r.upperBound!(pol)(41), [42, 52, 64])); assert(equal(r.upperBound!(pol)(43), [52, 64])); assert(equal(r.upperBound!(pol)(51), [52, 64])); assert(equal(r.upperBound!(pol)(53), [64])); assert(equal(r.upperBound!(pol)(55), [64])); assert(equal(r.upperBound!(pol)(420), a[0 .. 0])); assert(equal(r.upperBound!(pol)(0), a)); } test!(SearchPolicy.trot)(); test!(SearchPolicy.gallop)(); test!(SearchPolicy.trotBackwards)(); test!(SearchPolicy.gallopBackwards)(); test!(SearchPolicy.binarySearch)(); } @safe unittest { // Check for small arrays int[] a; auto r = assumeSorted(a); a = [ 1 ]; r = assumeSorted(a); a = [ 1, 2 ]; r = assumeSorted(a); a = [ 1, 2, 3 ]; r = assumeSorted(a); } @safe unittest { import std.algorithm : swap; auto a = [ 1, 2, 3, 42, 52, 64 ]; auto r = assumeSorted(a); assert(r.contains(42)); swap(a[3], a[5]); // illegal to break sortedness of original range assert(!r.contains(42)); // passes although it shouldn't } @safe unittest { immutable(int)[] arr = [ 1, 2, 3 ]; auto s = assumeSorted(arr); } unittest { import std.algorithm.comparison : equal; int[] arr = [100, 101, 102, 200, 201, 300]; auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr); assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]])); } // Test on an input range unittest { import std.stdio, std.file, std.path, std.conv, std.uuid; auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~ "." ~ randomUUID().toString()); auto f = File(name, "w"); scope(exit) if (exists(name)) remove(name); // write a sorted range of lines to the file f.write("abc\ndef\nghi\njkl"); f.close(); f.open(name, "r"); auto r = assumeSorted(f.byLine()); auto r1 = r.upperBound!(SearchPolicy.linear)("def"); assert(r1.front == "ghi", r1.front); f.close(); } /** Assumes $(D r) is sorted by predicate $(D pred) and returns the corresponding $(D SortedRange!(pred, R)) having $(D r) as support. To keep the checking costs low, the cost is $(BIGOH 1) in release mode (no checks for sortedness are performed). In debug mode, a few random elements of $(D r) are checked for sortedness. The size of the sample is proportional $(BIGOH log(r.length)). That way, checking has no effect on the complexity of subsequent operations specific to sorted ranges (such as binary search). The probability of an arbitrary unsorted range failing the test is very high (however, an almost-sorted range is likely to pass it). To check for sortedness at cost $(BIGOH n), use $(XREF_PACK algorithm,sorting,isSorted). */ auto assumeSorted(alias pred = "a < b", R)(R r) if (isInputRange!(Unqual!R)) { return SortedRange!(Unqual!R, pred)(r); } @safe unittest { import std.algorithm : equal; static assert(isRandomAccessRange!(SortedRange!(int[]))); int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; auto p = assumeSorted(a).lowerBound(4); assert(equal(p, [0, 1, 2, 3])); p = assumeSorted(a).lowerBound(5); assert(equal(p, [0, 1, 2, 3, 4])); p = assumeSorted(a).lowerBound(6); assert(equal(p, [ 0, 1, 2, 3, 4, 5])); p = assumeSorted(a).lowerBound(6.9); assert(equal(p, [ 0, 1, 2, 3, 4, 5, 6])); } @safe unittest { import std.algorithm : equal; int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; auto p = assumeSorted(a).upperBound(3); assert(equal(p, [4, 4, 5, 6 ])); p = assumeSorted(a).upperBound(4.2); assert(equal(p, [ 5, 6 ])); } @safe unittest { import std.conv : text; import std.algorithm : equal; int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; auto p = assumeSorted(a).equalRange(3); assert(equal(p, [ 3, 3, 3 ]), text(p)); p = assumeSorted(a).equalRange(4); assert(equal(p, [ 4, 4 ]), text(p)); p = assumeSorted(a).equalRange(2); assert(equal(p, [ 2 ])); p = assumeSorted(a).equalRange(0); assert(p.empty); p = assumeSorted(a).equalRange(7); assert(p.empty); p = assumeSorted(a).equalRange(3.0); assert(equal(p, [ 3, 3, 3])); } @safe unittest { int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; if (a.length) { auto b = a[a.length / 2]; //auto r = sort(a); //assert(r.contains(b)); } } @safe unittest { auto a = [ 5, 7, 34, 345, 677 ]; auto r = assumeSorted(a); a = null; r = assumeSorted(a); a = [ 1 ]; r = assumeSorted(a); } unittest { bool ok = true; try { auto r2 = assumeSorted([ 677, 345, 34, 7, 5 ]); debug ok = false; } catch (Throwable) { } assert(ok); } // issue 15003 @nogc unittest { static immutable a = [1, 2, 3, 4]; auto r = a.assumeSorted; } /++ Wrapper which effectively makes it possible to pass a range by reference. Both the original range and the RefRange will always have the exact same elements. Any operation done on one will affect the other. So, for instance, if it's passed to a function which would implicitly copy the original range if it were passed to it, the original range is $(I not) copied but is consumed as if it were a reference type. Note that $(D save) works as normal and operates on a new range, so if $(D save) is ever called on the RefRange, then no operations on the saved range will affect the original. +/ struct RefRange(R) if(isInputRange!R) { public: /++ +/ this(R* range) @safe pure nothrow { _range = range; } /++ This does not assign the pointer of $(D rhs) to this $(D RefRange). Rather it assigns the range pointed to by $(D rhs) to the range pointed to by this $(D RefRange). This is because $(I any) operation on a $(D RefRange) is the same is if it occurred to the original range. The one exception is when a $(D RefRange) is assigned $(D null) either directly or because $(D rhs) is $(D null). In that case, $(D RefRange) no longer refers to the original range but is $(D null). +/ auto opAssign(RefRange rhs) { if(_range && rhs._range) *_range = *rhs._range; else _range = rhs._range; return this; } /++ +/ auto opAssign(typeof(null) rhs) { _range = null; } /++ A pointer to the wrapped range. +/ @property inout(R*) ptr() @safe inout pure nothrow { return _range; } version(StdDdoc) { /++ +/ @property auto front() {assert(0);} /++ Ditto +/ @property auto front() const {assert(0);} /++ Ditto +/ @property auto front(ElementType!R value) {assert(0);} } else { @property auto front() { return (*_range).front; } static if(is(typeof((*(cast(const R*)_range)).front))) @property auto front() const { return (*_range).front; } static if(is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value) { return (*_range).front = value; } } version(StdDdoc) { @property bool empty(); /// @property bool empty() const; ///Ditto } else static if(isInfinite!R) enum empty = false; else { @property bool empty() { return (*_range).empty; } static if(is(typeof((*cast(const R*)_range).empty))) @property bool empty() const { return (*_range).empty; } } /++ +/ void popFront() { return (*_range).popFront(); } version(StdDdoc) { /++ Only defined if $(D isForwardRange!R) is $(D true). +/ @property auto save() {assert(0);} /++ Ditto +/ @property auto save() const {assert(0);} /++ Ditto +/ auto opSlice() {assert(0);} /++ Ditto +/ auto opSlice() const {assert(0);} } else static if(isForwardRange!R) { static if(isSafe!((R* r) => (*r).save)) { @property auto save() @trusted { mixin(_genSave()); } static if(is(typeof((*cast(const R*)_range).save))) @property auto save() @trusted const { mixin(_genSave()); } } else { @property auto save() { mixin(_genSave()); } static if(is(typeof((*cast(const R*)_range).save))) @property auto save() const { mixin(_genSave()); } } auto opSlice()() { return save; } auto opSlice()() const { return save; } private static string _genSave() @safe pure nothrow { return `import std.conv;` ~ `alias S = typeof((*_range).save);` ~ `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~ `auto mem = new void[S.sizeof];` ~ `emplace!S(mem, cast(S)(*_range).save);` ~ `return RefRange!S(cast(S*)mem.ptr);`; } static assert(isForwardRange!RefRange); } version(StdDdoc) { /++ Only defined if $(D isBidirectionalRange!R) is $(D true). +/ @property auto back() {assert(0);} /++ Ditto +/ @property auto back() const {assert(0);} /++ Ditto +/ @property auto back(ElementType!R value) {assert(0);} } else static if(isBidirectionalRange!R) { @property auto back() { return (*_range).back; } static if(is(typeof((*(cast(const R*)_range)).back))) @property auto back() const { return (*_range).back; } static if(is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value) { return (*_range).back = value; } } /++ Ditto +/ static if(isBidirectionalRange!R) void popBack() { return (*_range).popBack(); } version(StdDdoc) { /++ Only defined if $(D isRandomAccesRange!R) is $(D true). +/ auto ref opIndex(IndexType)(IndexType index) {assert(0);} /++ Ditto +/ auto ref opIndex(IndexType)(IndexType index) const {assert(0);} } else static if(isRandomAccessRange!R) { auto ref opIndex(IndexType)(IndexType index) if(is(typeof((*_range)[index]))) { return (*_range)[index]; } auto ref opIndex(IndexType)(IndexType index) const if(is(typeof((*cast(const R*)_range)[index]))) { return (*_range)[index]; } } /++ Only defined if $(D hasMobileElements!R) and $(D isForwardRange!R) are $(D true). +/ static if(hasMobileElements!R && isForwardRange!R) auto moveFront() { return (*_range).moveFront(); } /++ Only defined if $(D hasMobileElements!R) and $(D isBidirectionalRange!R) are $(D true). +/ static if(hasMobileElements!R && isBidirectionalRange!R) auto moveBack() { return (*_range).moveBack(); } /++ Only defined if $(D hasMobileElements!R) and $(D isRandomAccessRange!R) are $(D true). +/ static if(hasMobileElements!R && isRandomAccessRange!R) auto moveAt(IndexType)(IndexType index) if(is(typeof((*_range).moveAt(index)))) { return (*_range).moveAt(index); } version(StdDdoc) { /++ Only defined if $(D hasLength!R) is $(D true). +/ @property auto length() {assert(0);} /++ Ditto +/ @property auto length() const {assert(0);} } else static if(hasLength!R) { @property auto length() { return (*_range).length; } static if(is(typeof((*cast(const R*)_range).length))) @property auto length() const { return (*_range).length; } } version(StdDdoc) { /++ Only defined if $(D hasSlicing!R) is $(D true). +/ auto opSlice(IndexType1, IndexType2) (IndexType1 begin, IndexType2 end) {assert(0);} /++ Ditto +/ auto opSlice(IndexType1, IndexType2) (IndexType1 begin, IndexType2 end) const {assert(0);} } else static if(hasSlicing!R) { auto opSlice(IndexType1, IndexType2) (IndexType1 begin, IndexType2 end) if(is(typeof((*_range)[begin .. end]))) { mixin(_genOpSlice()); } auto opSlice(IndexType1, IndexType2) (IndexType1 begin, IndexType2 end) const if(is(typeof((*cast(const R*)_range)[begin .. end]))) { mixin(_genOpSlice()); } private static string _genOpSlice() @safe pure nothrow { return `import std.conv;` ~ `alias S = typeof((*_range)[begin .. end]);` ~ `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~ `auto mem = new void[S.sizeof];` ~ `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~ `return RefRange!S(cast(S*)mem.ptr);`; } } private: R* _range; } /// Basic Example unittest { import std.algorithm; ubyte[] buffer = [1, 9, 45, 12, 22]; auto found1 = find(buffer, 45); assert(found1 == [45, 12, 22]); assert(buffer == [1, 9, 45, 12, 22]); auto wrapped1 = refRange(&buffer); auto found2 = find(wrapped1, 45); assert(*found2.ptr == [45, 12, 22]); assert(buffer == [45, 12, 22]); auto found3 = find(wrapped1.save, 22); assert(*found3.ptr == [22]); assert(buffer == [45, 12, 22]); string str = "hello world"; auto wrappedStr = refRange(&str); assert(str.front == 'h'); str.popFrontN(5); assert(str == " world"); assert(wrappedStr.front == ' '); assert(*wrappedStr.ptr == " world"); } /// opAssign Example. unittest { ubyte[] buffer1 = [1, 2, 3, 4, 5]; ubyte[] buffer2 = [6, 7, 8, 9, 10]; auto wrapped1 = refRange(&buffer1); auto wrapped2 = refRange(&buffer2); assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is &buffer2); assert(wrapped1.ptr !is wrapped2.ptr); assert(buffer1 != buffer2); wrapped1 = wrapped2; //Everything points to the same stuff as before. assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is &buffer2); assert(wrapped1.ptr !is wrapped2.ptr); //But buffer1 has changed due to the assignment. assert(buffer1 == [6, 7, 8, 9, 10]); assert(buffer2 == [6, 7, 8, 9, 10]); buffer2 = [11, 12, 13, 14, 15]; //Everything points to the same stuff as before. assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is &buffer2); assert(wrapped1.ptr !is wrapped2.ptr); //But buffer2 has changed due to the assignment. assert(buffer1 == [6, 7, 8, 9, 10]); assert(buffer2 == [11, 12, 13, 14, 15]); wrapped2 = null; //The pointer changed for wrapped2 but not wrapped1. assert(wrapped1.ptr is &buffer1); assert(wrapped2.ptr is null); assert(wrapped1.ptr !is wrapped2.ptr); //buffer2 is not affected by the assignment. assert(buffer1 == [6, 7, 8, 9, 10]); assert(buffer2 == [11, 12, 13, 14, 15]); } unittest { import std.algorithm; { ubyte[] buffer = [1, 2, 3, 4, 5]; auto wrapper = refRange(&buffer); auto p = wrapper.ptr; auto f = wrapper.front; wrapper.front = f; auto e = wrapper.empty; wrapper.popFront(); auto s = wrapper.save; auto b = wrapper.back; wrapper.back = b; wrapper.popBack(); auto i = wrapper[0]; wrapper.moveFront(); wrapper.moveBack(); wrapper.moveAt(0); auto l = wrapper.length; auto sl = wrapper[0 .. 1]; } { ubyte[] buffer = [1, 2, 3, 4, 5]; const wrapper = refRange(&buffer); const p = wrapper.ptr; const f = wrapper.front; const e = wrapper.empty; const s = wrapper.save; const b = wrapper.back; const i = wrapper[0]; const l = wrapper.length; const sl = wrapper[0 .. 1]; } { ubyte[] buffer = [1, 2, 3, 4, 5]; auto filtered = filter!"true"(buffer); auto wrapper = refRange(&filtered); auto p = wrapper.ptr; auto f = wrapper.front; wrapper.front = f; auto e = wrapper.empty; wrapper.popFront(); auto s = wrapper.save; wrapper.moveFront(); } { ubyte[] buffer = [1, 2, 3, 4, 5]; auto filtered = filter!"true"(buffer); const wrapper = refRange(&filtered); const p = wrapper.ptr; //Cannot currently be const. filter needs to be updated to handle const. /+ const f = wrapper.front; const e = wrapper.empty; const s = wrapper.save; +/ } { string str = "hello world"; auto wrapper = refRange(&str); auto p = wrapper.ptr; auto f = wrapper.front; auto e = wrapper.empty; wrapper.popFront(); auto s = wrapper.save; auto b = wrapper.back; wrapper.popBack(); } } //Test assignment. unittest { ubyte[] buffer1 = [1, 2, 3, 4, 5]; ubyte[] buffer2 = [6, 7, 8, 9, 10]; RefRange!(ubyte[]) wrapper1; RefRange!(ubyte[]) wrapper2 = refRange(&buffer2); assert(wrapper1.ptr is null); assert(wrapper2.ptr is &buffer2); wrapper1 = refRange(&buffer1); assert(wrapper1.ptr is &buffer1); wrapper1 = wrapper2; assert(wrapper1.ptr is &buffer1); assert(buffer1 == buffer2); wrapper1 = RefRange!(ubyte[]).init; assert(wrapper1.ptr is null); assert(wrapper2.ptr is &buffer2); assert(buffer1 == buffer2); assert(buffer1 == [6, 7, 8, 9, 10]); wrapper2 = null; assert(wrapper2.ptr is null); assert(buffer2 == [6, 7, 8, 9, 10]); } unittest { import std.algorithm; //Test that ranges are properly consumed. { int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; auto wrapper = refRange(&arr); assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]); assert(arr == [41, 3, 40, 4, 42, 9]); assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]); assert(arr == [40, 4, 42, 9]); assert(equal(until(wrapper, 42), [40, 4])); assert(arr == [42, 9]); assert(find(wrapper, 12).empty); assert(arr.empty); } { string str = "Hello, world-like object."; auto wrapper = refRange(&str); assert(*find(wrapper, "l").ptr == "llo, world-like object."); assert(str == "llo, world-like object."); assert(equal(take(wrapper, 5), "llo, ")); assert(str == "world-like object."); } //Test that operating on saved ranges does not consume the original. { int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; auto wrapper = refRange(&arr); auto saved = wrapper.save; saved.popFrontN(3); assert(*saved.ptr == [41, 3, 40, 4, 42, 9]); assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); } { string str = "Hello, world-like object."; auto wrapper = refRange(&str); auto saved = wrapper.save; saved.popFrontN(13); assert(*saved.ptr == "like object."); assert(str == "Hello, world-like object."); } //Test that functions which use save work properly. { int[] arr = [1, 42]; auto wrapper = refRange(&arr); assert(equal(commonPrefix(wrapper, [1, 27]), [1])); } { int[] arr = [4, 5, 6, 7, 1, 2, 3]; auto wrapper = refRange(&arr); assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3); assert(arr == [1, 2, 3, 4, 5, 6, 7]); } //Test bidirectional functions. { int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; auto wrapper = refRange(&arr); assert(wrapper.back == 9); assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); wrapper.popBack(); assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]); } { string str = "Hello, world-like object."; auto wrapper = refRange(&str); assert(wrapper.back == '.'); assert(str == "Hello, world-like object."); wrapper.popBack(); assert(str == "Hello, world-like object"); } //Test random access functions. { int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; auto wrapper = refRange(&arr); assert(wrapper[2] == 2); assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]); assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); } //Test move functions. { int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; auto wrapper = refRange(&arr); auto t1 = wrapper.moveFront(); auto t2 = wrapper.moveBack(); wrapper.front = t2; wrapper.back = t1; assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]); sort(wrapper.save); assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]); } } unittest { struct S { @property int front() @safe const pure nothrow { return 0; } enum bool empty = false; void popFront() @safe pure nothrow { } @property auto save() @safe pure nothrow { return this; } } S s; auto wrapper = refRange(&s); static assert(isInfinite!(typeof(wrapper))); } unittest { class C { @property int front() @safe const pure nothrow { return 0; } @property bool empty() @safe const pure nothrow { return false; } void popFront() @safe pure nothrow { } @property auto save() @safe pure nothrow { return this; } } static assert(isForwardRange!C); auto c = new C; auto cWrapper = refRange(&c); static assert(is(typeof(cWrapper) == C)); assert(cWrapper is c); } unittest // issue 14373 { static struct R { @property int front() {return 0;} void popFront() {empty = true;} bool empty = false; } R r; refRange(&r).popFront(); assert(r.empty); } unittest // issue 14575 { struct R { Object front; alias back = front; bool empty = false; void popFront() {empty = true;} alias popBack = popFront; @property R save() {return this;} } static assert(isBidirectionalRange!R); R r; auto rr = refRange(&r); struct R2 { @property Object front() {return null;} @property const(Object) front() const {return null;} alias back = front; bool empty = false; void popFront() {empty = true;} alias popBack = popFront; @property R2 save() {return this;} } static assert(isBidirectionalRange!R2); R2 r2; auto rr2 = refRange(&r2); } /++ Helper function for constructing a $(LREF RefRange). If the given range is a class type (and thus is already a reference type), then the original range is returned rather than a $(LREF RefRange). +/ auto refRange(R)(R* range) if(isInputRange!R && !is(R == class)) { return RefRange!R(range); } /// ditto auto refRange(R)(R* range) if(isInputRange!R && is(R == class)) { return *range; } /*****************************************************************************/ @safe unittest // bug 9060 { import std.algorithm : map, joiner, group, until; // fix for std.algorithm auto r = map!(x => 0)([1]); chain(r, r); zip(r, r); roundRobin(r, r); struct NRAR { typeof(r) input; @property empty() { return input.empty; } @property front() { return input.front; } void popFront() { input.popFront(); } @property save() { return NRAR(input.save); } } auto n1 = NRAR(r); cycle(n1); // non random access range version assumeSorted(r); // fix for std.range joiner([r], [9]); struct NRAR2 { NRAR input; @property empty() { return true; } @property front() { return input; } void popFront() { } @property save() { return NRAR2(input.save); } } auto n2 = NRAR2(n1); joiner(n2); group(r); until(r, 7); static void foo(R)(R r) { until!(x => x > 7)(r); } foo(r); } /********************************* * An OutputRange that discards the data it receives. */ struct NullSink { void put(E)(E){} } /// @safe unittest { import std.algorithm : map, copy; [4, 5, 6].map!(x => x * 2).copy(NullSink()); // data is discarded } /++ Implements a "tee" style pipe, wrapping an input range so that elements of the range can be passed to a provided function or $(LREF OutputRange) as they are iterated over. This is useful for printing out intermediate values in a long chain of range code, performing some operation with side-effects on each call to $(D front) or $(D popFront), or diverting the elements of a range into an auxiliary $(LREF OutputRange). It is important to note that as the resultant range is evaluated lazily, in the case of the version of $(D tee) that takes a function, the function will not actually be executed until the range is "walked" using functions that evaluate ranges, such as $(XREF array,array) or $(XREF_PACK algorithm,iteration,fold). Params: pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever calling `front` is enough to have `tee` mirror elements to `outputRange` (or, respectively, `fun`). If `No.pipeOnPop`, only elements for which `front` does get called will be also sent to `outputRange`/`fun`. inputRange = The input range beeing passed through. outputRange = This range will receive elements of `inputRange` progressively as iteration proceeds. fun = This function will be called with elements of `inputRange` progressively as iteration proceeds. Returns: An input range that offers the elements of `inputRange`. Regardless of whether `inputRange` is a more powerful range (forward, bidirectional etc), the result is always an input range. Reading this causes `inputRange` to be iterated and returns its elements in turn. In addition, the same elements will be passed to `outputRange` or `fun` as well. See_Also: $(XREF_PACK algorithm,iteration,each) +/ auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange) if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1)) { static struct Result { private R1 _input; private R2 _output; static if (!pipeOnPop) { private bool _frontAccessed; } static if (hasLength!R1) { @property length() { return _input.length; } } static if (isInfinite!R1) { enum bool empty = false; } else { @property bool empty() { return _input.empty; } } void popFront() { assert(!_input.empty); static if (pipeOnPop) { put(_output, _input.front); } else { _frontAccessed = false; } _input.popFront(); } @property auto ref front() { static if (!pipeOnPop) { if (!_frontAccessed) { _frontAccessed = true; put(_output, _input.front); } } return _input.front; } } return Result(inputRange, outputRange); } /// Ditto auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange) if (is(typeof(fun) == void) || isSomeFunction!fun) { /* Distinguish between function literals and template lambdas when using either as an $(LREF OutputRange). Since a template has no type, typeof(template) will always return void. If it's a template lambda, it's first necessary to instantiate it with $(D ElementType!R1). */ static if (is(typeof(fun) == void)) alias _fun = fun!(ElementType!R1); else alias _fun = fun; static if (isFunctionPointer!_fun || isDelegate!_fun) { return tee!pipeOnPop(inputRange, _fun); } else { return tee!pipeOnPop(inputRange, &_fun); } } /// @safe unittest { import std.algorithm : equal, filter, map; // Sum values while copying int[] values = [1, 4, 9, 16, 25]; int sum = 0; auto newValues = values.tee!(a => sum += a).array; assert(equal(newValues, values)); assert(sum == 1 + 4 + 9 + 16 + 25); // Count values that pass the first filter int count = 0; auto newValues4 = values.filter!(a => a < 10) .tee!(a => count++) .map!(a => a + 1) .filter!(a => a < 10); //Fine, equal also evaluates any lazy ranges passed to it. //count is not 3 until equal evaluates newValues4 assert(equal(newValues4, [2, 5])); assert(count == 3); } // @safe unittest { import std.algorithm : equal, filter, map; int[] values = [1, 4, 9, 16, 25]; int count = 0; auto newValues = values.filter!(a => a < 10) .tee!(a => count++, No.pipeOnPop) .map!(a => a + 1) .filter!(a => a < 10); auto val = newValues.front; assert(count == 1); //front is only evaluated once per element val = newValues.front; assert(count == 1); //popFront() called, fun will be called //again on the next access to front newValues.popFront(); newValues.front; assert(count == 2); int[] preMap = new int[](3), postMap = []; auto mappedValues = values.filter!(a => a < 10) //Note the two different ways of using tee .tee(preMap) .map!(a => a + 1) .tee!(a => postMap ~= a) .filter!(a => a < 10); assert(equal(mappedValues, [2, 5])); assert(equal(preMap, [1, 4, 9])); assert(equal(postMap, [2, 5, 10])); } // @safe unittest { import std.algorithm : filter, equal, map; char[] txt = "Line one, Line 2".dup; bool isVowel(dchar c) { import std.string : indexOf; return "AaEeIiOoUu".indexOf(c) != -1; } int vowelCount = 0; int shiftedCount = 0; auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0) .filter!(c => !isVowel(c)) .map!(c => (c == ' ') ? c : c + 1) .tee!(c => isVowel(c) ? shiftedCount++ : 0); assert(equal(removeVowels, "Mo o- Mo 3")); assert(vowelCount == 6); assert(shiftedCount == 3); } @safe unittest { // Manually stride to test different pipe behavior. void testRange(Range)(Range r) { const int strideLen = 3; int i = 0; ElementType!Range elem1; ElementType!Range elem2; while (!r.empty) { if (i % strideLen == 0) { //Make sure front is only //evaluated once per item elem1 = r.front; elem2 = r.front; assert(elem1 == elem2); } r.popFront(); i++; } } string txt = "abcdefghijklmnopqrstuvwxyz"; int popCount = 0; auto pipeOnPop = txt.tee!(a => popCount++); testRange(pipeOnPop); assert(popCount == 26); int frontCount = 0; auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop); testRange(pipeOnFront); assert(frontCount == 9); } @safe unittest { import std.algorithm : equal; //Test diverting elements to an OutputRange string txt = "abcdefghijklmnopqrstuvwxyz"; dchar[] asink1 = []; auto fsink = (dchar c) { asink1 ~= c; }; auto result1 = txt.tee(fsink).array; assert(equal(txt, result1) && (equal(result1, asink1))); dchar[] _asink1 = []; auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array; assert(equal(txt, _result1) && (equal(_result1, _asink1))); dchar[] asink2 = new dchar[](txt.length); void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; } auto result2 = txt.tee(&fsink2).array; assert(equal(txt, result2) && equal(result2, asink2)); dchar[] asink3 = new dchar[](txt.length); auto result3 = txt.tee(asink3).array; assert(equal(txt, result3) && equal(result3, asink3)); foreach (CharType; AliasSeq!(char, wchar, dchar)) { auto appSink = appender!(CharType[])(); auto appResult = txt.tee(appSink).array; assert(equal(txt, appResult) && equal(appResult, appSink.data)); } foreach (StringType; AliasSeq!(string, wstring, dstring)) { auto appSink = appender!StringType(); auto appResult = txt.tee(appSink).array; assert(equal(txt, appResult) && equal(appResult, appSink.data)); } } @safe unittest { // Issue 13483 static void func1(T)(T x) {} void func2(int x) {} auto r = [1, 2, 3, 4].tee!func1.tee!func2; } ldc-1.1.0-beta3-src/runtime/phobos/std/range/primitives.d0000664000175000017500000017615412776215007021360 0ustar kaikai/** This module is a submodule of $(LINK2 std_range.html, std.range). It provides basic range functionality by defining several templates for testing whether a given object is a _range, and what kind of _range it is: $(BOOKTABLE , $(TR $(TD $(D $(LREF isInputRange))) $(TD Tests if something is an $(I input _range), defined to be something from which one can sequentially read data using the primitives $(D front), $(D popFront), and $(D empty). )) $(TR $(TD $(D $(LREF isOutputRange))) $(TD Tests if something is an $(I output _range), defined to be something to which one can sequentially write data using the $(D $(LREF put)) primitive. )) $(TR $(TD $(D $(LREF isForwardRange))) $(TD Tests if something is a $(I forward _range), defined to be an input _range with the additional capability that one can save one's current position with the $(D save) primitive, thus allowing one to iterate over the same _range multiple times. )) $(TR $(TD $(D $(LREF isBidirectionalRange))) $(TD Tests if something is a $(I bidirectional _range), that is, a forward _range that allows reverse traversal using the primitives $(D back) and $(D popBack). )) $(TR $(TD $(D $(LREF isRandomAccessRange))) $(TD Tests if something is a $(I random access _range), which is a bidirectional _range that also supports the array subscripting operation via the primitive $(D opIndex). )) ) It also provides number of templates that test for various _range capabilities: $(BOOKTABLE , $(TR $(TD $(D $(LREF hasMobileElements))) $(TD Tests if a given _range's elements can be moved around using the primitives $(D moveFront), $(D moveBack), or $(D moveAt). )) $(TR $(TD $(D $(LREF ElementType))) $(TD Returns the element type of a given _range. )) $(TR $(TD $(D $(LREF ElementEncodingType))) $(TD Returns the encoding element type of a given _range. )) $(TR $(TD $(D $(LREF hasSwappableElements))) $(TD Tests if a _range is a forward _range with swappable elements. )) $(TR $(TD $(D $(LREF hasAssignableElements))) $(TD Tests if a _range is a forward _range with mutable elements. )) $(TR $(TD $(D $(LREF hasLvalueElements))) $(TD Tests if a _range is a forward _range with elements that can be passed by reference and have their address taken. )) $(TR $(TD $(D $(LREF hasLength))) $(TD Tests if a given _range has the $(D length) attribute. )) $(TR $(TD $(D $(LREF isInfinite))) $(TD Tests if a given _range is an $(I infinite _range). )) $(TR $(TD $(D $(LREF hasSlicing))) $(TD Tests if a given _range supports the array slicing operation $(D R[x..y]). )) ) Finally, it includes some convenience functions for manipulating ranges: $(BOOKTABLE , $(TR $(TD $(D $(LREF popFrontN))) $(TD Advances a given _range by up to $(I n) elements. )) $(TR $(TD $(D $(LREF popBackN))) $(TD Advances a given bidirectional _range from the right by up to $(I n) elements. )) $(TR $(TD $(D $(LREF popFrontExactly))) $(TD Advances a given _range by up exactly $(I n) elements. )) $(TR $(TD $(D $(LREF popBackExactly))) $(TD Advances a given bidirectional _range from the right by exactly $(I n) elements. )) $(TR $(TD $(D $(LREF moveFront))) $(TD Removes the front element of a _range. )) $(TR $(TD $(D $(LREF moveBack))) $(TD Removes the back element of a bidirectional _range. )) $(TR $(TD $(D $(LREF moveAt))) $(TD Removes the $(I i)'th element of a random-access _range. )) $(TR $(TD $(D $(LREF walkLength))) $(TD Computes the length of any _range in O(n) time. )) ) Source: $(PHOBOSSRC std/range/_primitives.d) Macros: WIKI = Phobos/StdRange Copyright: Copyright by authors 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu), David Simcha, and Jonathan M Davis. Credit for some of the ideas in building this module goes to $(WEB fantascienza.net/leonardo/so/, Leonardo Maffi). */ module std.range.primitives; import std.traits; /** Returns $(D true) if $(D R) is an input range. An input range must define the primitives $(D empty), $(D popFront), and $(D front). The following code should compile for any input range. ---- R r; // can define a range object if (r.empty) {} // can test for empty r.popFront(); // can invoke popFront() auto h = r.front; // can get the front of the range of non-void type ---- The semantics of an input range (not checkable during compilation) are assumed to be the following ($(D r) is an object of type $(D R)): $(UL $(LI $(D r.empty) returns $(D false) iff there is more data available in the range.) $(LI $(D r.front) returns the current element in the range. It may return by value or by reference. Calling $(D r.front) is allowed only if calling $(D r.empty) has, or would have, returned $(D false).) $(LI $(D r.popFront) advances to the next element in the range. Calling $(D r.popFront) is allowed only if calling $(D r.empty) has, or would have, returned $(D false).)) Params: R = type to be tested Returns: true if R is an InputRange, false if not */ template isInputRange(R) { enum bool isInputRange = is(typeof( (inout int = 0) { R r = R.init; // can define a range object if (r.empty) {} // can test for empty r.popFront(); // can invoke popFront() auto h = r.front; // can get the front of the range })); } /// @safe unittest { struct A {} struct B { void popFront(); @property bool empty(); @property int front(); } static assert(!isInputRange!A); static assert( isInputRange!B); static assert( isInputRange!(int[])); static assert( isInputRange!(char[])); static assert(!isInputRange!(char[4])); static assert( isInputRange!(inout(int)[])); } /+ puts the whole raw element $(D e) into $(D r). doPut will not attempt to iterate, slice or transcode $(D e) in any way shape or form. It will $(B only) call the correct primitive ($(D r.put(e)), $(D r.front = e) or $(D r(0)) once. This can be important when $(D e) needs to be placed in $(D r) unchanged. Furthermore, it can be useful when working with $(D InputRange)s, as doPut guarantees that no more than a single element will be placed. +/ private void doPut(R, E)(ref R r, auto ref E e) { static if(is(PointerTarget!R == struct)) enum usingPut = hasMember!(PointerTarget!R, "put"); else enum usingPut = hasMember!(R, "put"); static if (usingPut) { static assert(is(typeof(r.put(e))), "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); r.put(e); } else static if (isInputRange!R) { static assert(is(typeof(r.front = e)), "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); r.front = e; r.popFront(); } else static if (is(typeof(r(e)))) { r(e); } else { static assert (false, "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); } } @safe unittest { static assert (!isNativeOutputRange!(int, int)); static assert ( isNativeOutputRange!(int[], int)); static assert (!isNativeOutputRange!(int[][], int)); static assert (!isNativeOutputRange!(int, int[])); static assert (!isNativeOutputRange!(int[], int[])); static assert ( isNativeOutputRange!(int[][], int[])); static assert (!isNativeOutputRange!(int, int[][])); static assert (!isNativeOutputRange!(int[], int[][])); static assert (!isNativeOutputRange!(int[][], int[][])); static assert (!isNativeOutputRange!(int[4], int)); static assert ( isNativeOutputRange!(int[4][], int)); //Scary! static assert ( isNativeOutputRange!(int[4][], int[4])); static assert (!isNativeOutputRange!( char[], char)); static assert (!isNativeOutputRange!( char[], dchar)); static assert ( isNativeOutputRange!(dchar[], char)); static assert ( isNativeOutputRange!(dchar[], dchar)); } /++ Outputs $(D e) to $(D r). The exact effect is dependent upon the two types. Several cases are accepted, as described below. The code snippets are attempted in order, and the first to compile "wins" and gets evaluated. In this table "doPut" is a method that places $(D e) into $(D r), using the correct primitive: $(D r.put(e)) if $(D R) defines $(D put), $(D r.front = e) if $(D r) is an input range (followed by $(D r.popFront())), or $(D r(e)) otherwise. $(BOOKTABLE , $(TR $(TH Code Snippet) $(TH Scenario) ) $(TR $(TD $(D r.doPut(e);)) $(TD $(D R) specifically accepts an $(D E).) ) $(TR $(TD $(D r.doPut([ e ]);)) $(TD $(D R) specifically accepts an $(D E[]).) ) $(TR $(TD $(D r.putChar(e);)) $(TD $(D R) accepts some form of string or character. put will transcode the character $(D e) accordingly.) ) $(TR $(TD $(D for (; !e.empty; e.popFront()) put(r, e.front);)) $(TD Copying range $(D E) into $(D R).) ) ) Tip: $(D put) should $(I not) be used "UFCS-style", e.g. $(D r.put(e)). Doing this may call $(D R.put) directly, by-passing any transformation feature provided by $(D Range.put). $(D put(r, e)) is prefered. +/ void put(R, E)(ref R r, E e) { //First level: simply straight up put. static if (is(typeof(doPut(r, e)))) { doPut(r, e); } //Optional optimization block for straight up array to array copy. else static if (isDynamicArray!R && !isNarrowString!R && isDynamicArray!E && is(typeof(r[] = e[]))) { immutable len = e.length; r[0 .. len] = e[]; r = r[len .. $]; } //Accepts E[] ? else static if (is(typeof(doPut(r, [e]))) && !isDynamicArray!R) { if (__ctfe) { E[1] arr = [e]; doPut(r, arr[]); } else doPut(r, (ref e) @trusted { return (&e)[0..1]; }(e)); } //special case for char to string. else static if (isSomeChar!E && is(typeof(putChar(r, e)))) { putChar(r, e); } //Extract each element from the range //We can use "put" here, so we can recursively test a RoR of E. else static if (isInputRange!E && is(typeof(put(r, e.front)))) { //Special optimization: If E is a narrow string, and r accepts characters no-wider than the string's //Then simply feed the characters 1 by 1. static if (isNarrowString!E && ( (is(E : const char[]) && is(typeof(doPut(r, char.max))) && !is(typeof(doPut(r, dchar.max))) && !is(typeof(doPut(r, wchar.max)))) || (is(E : const wchar[]) && is(typeof(doPut(r, wchar.max))) && !is(typeof(doPut(r, dchar.max)))) ) ) { foreach(c; e) doPut(r, c); } else { for (; !e.empty; e.popFront()) put(r, e.front); } } else { static assert (false, "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); } } @safe pure nothrow @nogc unittest { static struct R() { void put(in char[]) {} } R!() r; put(r, 'a'); } //Helper function to handle chars as quickly and as elegantly as possible //Assumes r.put(e)/r(e) has already been tested private void putChar(R, E)(ref R r, E e) if (isSomeChar!E) { ////@@@9186@@@: Can't use (E[]).init ref const( char)[] cstringInit(); ref const(wchar)[] wstringInit(); ref const(dchar)[] dstringInit(); enum csCond = !isDynamicArray!R && is(typeof(doPut(r, cstringInit()))); enum wsCond = !isDynamicArray!R && is(typeof(doPut(r, wstringInit()))); enum dsCond = !isDynamicArray!R && is(typeof(doPut(r, dstringInit()))); //Use "max" to avoid static type demotion enum ccCond = is(typeof(doPut(r, char.max))); enum wcCond = is(typeof(doPut(r, wchar.max))); //enum dcCond = is(typeof(doPut(r, dchar.max))); //Fast transform a narrow char into a wider string static if ((wsCond && E.sizeof < wchar.sizeof) || (dsCond && E.sizeof < dchar.sizeof)) { enum w = wsCond && E.sizeof < wchar.sizeof; Select!(w, wchar, dchar) c = e; typeof(c)[1] arr = [c]; doPut(r, arr[]); } //Encode a wide char into a narrower string else static if (wsCond || csCond) { import std.utf : encode; /+static+/ Select!(wsCond, wchar[2], char[4]) buf; //static prevents purity. doPut(r, buf[0 .. encode(buf, e)]); } //Slowly encode a wide char into a series of narrower chars else static if (wcCond || ccCond) { import std.encoding : encode; alias C = Select!(wcCond, wchar, char); encode!(C, R)(e, r); } else { static assert (false, "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); } } pure unittest { auto f = delegate (const(char)[]) {}; putChar(f, cast(dchar)'a'); } @safe pure unittest { static struct R() { void put(in char[]) {} } R!() r; putChar(r, 'a'); } unittest { struct A {} static assert(!isInputRange!(A)); struct B { void put(int) {} } B b; put(b, 5); } unittest { int[] a = [1, 2, 3], b = [10, 20]; auto c = a; put(a, b); assert(c == [10, 20, 3]); assert(a == [3]); } unittest { int[] a = new int[10]; int b; static assert(isInputRange!(typeof(a))); put(a, b); } unittest { void myprint(in char[] s) { } auto r = &myprint; put(r, 'a'); } unittest { int[] a = new int[10]; static assert(!__traits(compiles, put(a, 1.0L))); put(a, 1); assert(a.length == 9); /* * a[0] = 65; // OK * a[0] = 'A'; // OK * a[0] = "ABC"[0]; // OK * put(a, "ABC"); // OK */ put(a, "ABC"); assert(a.length == 6); } unittest { char[] a = new char[10]; static assert(!__traits(compiles, put(a, 1.0L))); static assert(!__traits(compiles, put(a, 1))); // char[] is NOT output range. static assert(!__traits(compiles, put(a, 'a'))); static assert(!__traits(compiles, put(a, "ABC"))); } unittest { int[][] a = new int[][10]; int[] b = new int[10]; int c; put(b, c); assert(b.length == 9); put(a, b); assert(a.length == 9); static assert(!__traits(compiles, put(a, c))); } unittest { int[][] a = new int[][](3); int[] b = [1]; auto aa = a; put(aa, b); assert(aa == [[], []]); assert(a == [[1], [], []]); int[][3] c = [2]; aa = a; put(aa, c[]); assert(aa.empty); assert(a == [[2], [2], [2]]); } unittest { // Test fix for bug 7476. struct LockingTextWriter { void put(dchar c){} } struct RetroResult { bool end = false; @property bool empty() const { return end; } @property dchar front(){ return 'a'; } void popFront(){ end = true; } } LockingTextWriter w; RetroResult r; put(w, r); } unittest { import std.conv : to; import std.meta : AliasSeq; import std.typecons : tuple; static struct PutC(C) { string result; void put(const(C) c) { result ~= to!string((&c)[0..1]); } } static struct PutS(C) { string result; void put(const(C)[] s) { result ~= to!string(s); } } static struct PutSS(C) { string result; void put(const(C)[][] ss) { foreach(s; ss) result ~= to!string(s); } } PutS!char p; putChar(p, cast(dchar)'a'); //Source Char foreach (SC; AliasSeq!(char, wchar, dchar)) { SC ch = 'I'; dchar dh = '♥'; immutable(SC)[] s = "日本語!"; immutable(SC)[][] ss = ["日本語", "が", "好き", "ですか", "?"]; //Target Char foreach (TC; AliasSeq!(char, wchar, dchar)) { //Testing PutC and PutS foreach (Type; AliasSeq!(PutC!TC, PutS!TC)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 Type type; auto sink = new Type(); //Testing put and sink foreach (value ; tuple(type, sink)) { put(value, ch); assert(value.result == "I"); put(value, dh); assert(value.result == "I♥"); put(value, s); assert(value.result == "I♥日本語!"); put(value, ss); assert(value.result == "I♥日本語!日本語が好きですか?"); } }(); } } } unittest { static struct CharRange { char c; enum empty = false; void popFront(){}; ref char front() return @property { return c; } } CharRange c; put(c, cast(dchar)'H'); put(c, "hello"d); } unittest { // issue 9823 const(char)[] r; void delegate(const(char)[]) dg = (s) { r = s; }; put(dg, ["ABC"]); assert(r == "ABC"); } unittest { // issue 10571 import std.format; string buf; formattedWrite((in char[] s) { buf ~= s; }, "%s", "hello"); assert(buf == "hello"); } unittest { import std.format; import std.meta : AliasSeq; struct PutC(C) { void put(C){} } struct PutS(C) { void put(const(C)[]){} } struct CallC(C) { void opCall(C){} } struct CallS(C) { void opCall(const(C)[]){} } struct FrontC(C) { enum empty = false; auto front()@property{return C.init;} void front(C)@property{} void popFront(){} } struct FrontS(C) { enum empty = false; auto front()@property{return C[].init;} void front(const(C)[])@property{} void popFront(){} } void foo() { foreach(C; AliasSeq!(char, wchar, dchar)) { formattedWrite((C c){}, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); formattedWrite((const(C)[]){}, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); formattedWrite(PutC!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); formattedWrite(PutS!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); CallC!C callC; CallS!C callS; formattedWrite(callC, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); formattedWrite(callS, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); formattedWrite(FrontC!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); formattedWrite(FrontS!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); } formattedWrite((dchar[]).init, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); } } /+ Returns $(D true) if $(D R) is a native output range for elements of type $(D E). An output range is defined functionally as a range that supports the operation $(D doPut(r, e)) as defined above. if $(D doPut(r, e)) is valid, then $(D put(r,e)) will have the same behavior. The two guarantees isNativeOutputRange gives over the larger $(D isOutputRange) are: 1: $(D e) is $(B exactly) what will be placed (not $(D [e]), for example). 2: if $(D E) is a non $(empty) $(D InputRange), then placing $(D e) is guaranteed to not overflow the range. +/ package template isNativeOutputRange(R, E) { enum bool isNativeOutputRange = is(typeof( (inout int = 0) { R r = void; E e; doPut(r, e); })); } /// @safe unittest { int[] r = new int[](4); static assert(isInputRange!(int[])); static assert( isNativeOutputRange!(int[], int)); static assert(!isNativeOutputRange!(int[], int[])); static assert( isOutputRange!(int[], int[])); if (!r.empty) put(r, 1); //guaranteed to succeed if (!r.empty) put(r, [1, 2]); //May actually error out. } /++ Returns $(D true) if $(D R) is an output range for elements of type $(D E). An output range is defined functionally as a range that supports the operation $(D put(r, e)) as defined above. +/ template isOutputRange(R, E) { enum bool isOutputRange = is(typeof( (inout int = 0) { R r = R.init; E e = E.init; put(r, e); })); } /// @safe unittest { void myprint(in char[] s) { } static assert(isOutputRange!(typeof(&myprint), char)); static assert(!isOutputRange!(char[], char)); static assert( isOutputRange!(dchar[], wchar)); static assert( isOutputRange!(dchar[], dchar)); } @safe unittest { import std.array; import std.stdio : writeln; auto app = appender!string(); string s; static assert( isOutputRange!(Appender!string, string)); static assert( isOutputRange!(Appender!string*, string)); static assert(!isOutputRange!(Appender!string, int)); static assert(!isOutputRange!(wchar[], wchar)); static assert( isOutputRange!(dchar[], char)); static assert( isOutputRange!(dchar[], string)); static assert( isOutputRange!(dchar[], wstring)); static assert( isOutputRange!(dchar[], dstring)); static assert(!isOutputRange!(const(int)[], int)); static assert(!isOutputRange!(inout(int)[], int)); } /** Returns $(D true) if $(D R) is a forward range. A forward range is an input range $(D r) that can save "checkpoints" by saving $(D r.save) to another value of type $(D R). Notable examples of input ranges that are $(I not) forward ranges are file/socket ranges; copying such a range will not save the position in the stream, and they most likely reuse an internal buffer as the entire stream does not sit in memory. Subsequently, advancing either the original or the copy will advance the stream, so the copies are not independent. The following code should compile for any forward range. ---- static assert(isInputRange!R); R r1; auto s1 = r1.save; static assert (is(typeof(s1) == R)); ---- Saving a range is not duplicating it; in the example above, $(D r1) and $(D r2) still refer to the same underlying data. They just navigate that data independently. The semantics of a forward range (not checkable during compilation) are the same as for an input range, with the additional requirement that backtracking must be possible by saving a copy of the range object with $(D save) and using it later. */ template isForwardRange(R) { enum bool isForwardRange = isInputRange!R && is(typeof( (inout int = 0) { R r1 = R.init; // NOTE: we cannot check typeof(r1.save) directly // because typeof may not check the right type there, and // because we want to ensure the range can be copied. auto s1 = r1.save; static assert (is(typeof(s1) == R)); })); } /// @safe unittest { static assert(!isForwardRange!(int)); static assert( isForwardRange!(int[])); static assert( isForwardRange!(inout(int)[])); } @safe unittest { // BUG 14544 struct R14544 { int front() { return 0;} void popFront() {} bool empty() { return false; } R14544 save() {return this;} } static assert( isForwardRange!R14544 ); } /** Returns $(D true) if $(D R) is a bidirectional range. A bidirectional range is a forward range that also offers the primitives $(D back) and $(D popBack). The following code should compile for any bidirectional range. The semantics of a bidirectional range (not checkable during compilation) are assumed to be the following ($(D r) is an object of type $(D R)): $(UL $(LI $(D r.back) returns (possibly a reference to) the last element in the range. Calling $(D r.back) is allowed only if calling $(D r.empty) has, or would have, returned $(D false).)) */ template isBidirectionalRange(R) { enum bool isBidirectionalRange = isForwardRange!R && is(typeof( (inout int = 0) { R r = R.init; r.popBack(); auto t = r.back; auto w = r.front; static assert(is(typeof(t) == typeof(w))); })); } /// unittest { alias R = int[]; R r = [0,1]; static assert(isForwardRange!R); // is forward range r.popBack(); // can invoke popBack auto t = r.back; // can get the back of the range auto w = r.front; static assert(is(typeof(t) == typeof(w))); // same type for front and back } @safe unittest { struct A {} struct B { void popFront(); @property bool empty(); @property int front(); } struct C { @property bool empty(); @property C save(); void popFront(); @property int front(); void popBack(); @property int back(); } static assert(!isBidirectionalRange!(A)); static assert(!isBidirectionalRange!(B)); static assert( isBidirectionalRange!(C)); static assert( isBidirectionalRange!(int[])); static assert( isBidirectionalRange!(char[])); static assert( isBidirectionalRange!(inout(int)[])); } /** Returns $(D true) if $(D R) is a random-access range. A random-access range is a bidirectional range that also offers the primitive $(D opIndex), OR an infinite forward range that offers $(D opIndex). In either case, the range must either offer $(D length) or be infinite. The following code should compile for any random-access range. The semantics of a random-access range (not checkable during compilation) are assumed to be the following ($(D r) is an object of type $(D R)): $(UL $(LI $(D r.opIndex(n)) returns a reference to the $(D n)th element in the range.)) Although $(D char[]) and $(D wchar[]) (as well as their qualified versions including $(D string) and $(D wstring)) are arrays, $(D isRandomAccessRange) yields $(D false) for them because they use variable-length encodings (UTF-8 and UTF-16 respectively). These types are bidirectional ranges only. */ template isRandomAccessRange(R) { enum bool isRandomAccessRange = is(typeof( (inout int = 0) { static assert(isBidirectionalRange!R || isForwardRange!R && isInfinite!R); R r = R.init; auto e = r[1]; auto f = r.front; static assert(is(typeof(e) == typeof(f))); static assert(!isNarrowString!R); static assert(hasLength!R || isInfinite!R); static if(is(typeof(r[$]))) { static assert(is(typeof(f) == typeof(r[$]))); static if(!isInfinite!R) static assert(is(typeof(f) == typeof(r[$ - 1]))); } })); } /// unittest { alias R = int[]; // range is finite and bidirectional or infinite and forward. static assert(isBidirectionalRange!R || isForwardRange!R && isInfinite!R); R r = [0,1]; auto e = r[1]; // can index auto f = r.front; static assert(is(typeof(e) == typeof(f))); // same type for indexed and front static assert(!isNarrowString!R); // narrow strings cannot be indexed as ranges static assert(hasLength!R || isInfinite!R); // must have length or be infinite // $ must work as it does with arrays if opIndex works with $ static if(is(typeof(r[$]))) { static assert(is(typeof(f) == typeof(r[$]))); // $ - 1 doesn't make sense with infinite ranges but needs to work // with finite ones. static if(!isInfinite!R) static assert(is(typeof(f) == typeof(r[$ - 1]))); } } @safe unittest { struct A {} struct B { void popFront(); @property bool empty(); @property int front(); } struct C { void popFront(); @property bool empty(); @property int front(); void popBack(); @property int back(); } struct D { @property bool empty(); @property D save(); @property int front(); void popFront(); @property int back(); void popBack(); ref int opIndex(uint); @property size_t length(); alias opDollar = length; //int opSlice(uint, uint); } struct E { bool empty(); E save(); int front(); void popFront(); int back(); void popBack(); ref int opIndex(uint); size_t length(); alias opDollar = length; //int opSlice(uint, uint); } static assert(!isRandomAccessRange!(A)); static assert(!isRandomAccessRange!(B)); static assert(!isRandomAccessRange!(C)); static assert( isRandomAccessRange!(D)); static assert( isRandomAccessRange!(E)); static assert( isRandomAccessRange!(int[])); static assert( isRandomAccessRange!(inout(int)[])); } @safe unittest { // Test fix for bug 6935. struct R { @disable this(); @property bool empty() const { return false; } @property int front() const { return 0; } void popFront() {} @property R save() { return this; } @property int back() const { return 0; } void popBack(){} int opIndex(size_t n) const { return 0; } @property size_t length() const { return 0; } alias opDollar = length; void put(int e){ } } static assert(isInputRange!R); static assert(isForwardRange!R); static assert(isBidirectionalRange!R); static assert(isRandomAccessRange!R); static assert(isOutputRange!(R, int)); } /** Returns $(D true) iff $(D R) is an input range that supports the $(D moveFront) primitive, as well as $(D moveBack) and $(D moveAt) if it's a bidirectional or random access range. These may be explicitly implemented, or may work via the default behavior of the module level functions $(D moveFront) and friends. The following code should compile for any range with mobile elements. ---- alias E = ElementType!R; R r; static assert(isInputRange!R); static assert(is(typeof(moveFront(r)) == E)); static if (isBidirectionalRange!R) static assert(is(typeof(moveBack(r)) == E)); static if (isRandomAccessRange!R) static assert(is(typeof(moveAt(r, 0)) == E)); ---- */ template hasMobileElements(R) { enum bool hasMobileElements = isInputRange!R && is(typeof( (inout int = 0) { alias E = ElementType!R; R r = R.init; static assert(is(typeof(moveFront(r)) == E)); static if (isBidirectionalRange!R) static assert(is(typeof(moveBack(r)) == E)); static if (isRandomAccessRange!R) static assert(is(typeof(moveAt(r, 0)) == E)); })); } /// @safe unittest { import std.algorithm : map; import std.range : iota, repeat; static struct HasPostblit { this(this) {} } auto nonMobile = map!"a"(repeat(HasPostblit.init)); static assert(!hasMobileElements!(typeof(nonMobile))); static assert( hasMobileElements!(int[])); static assert( hasMobileElements!(inout(int)[])); static assert( hasMobileElements!(typeof(iota(1000)))); static assert( hasMobileElements!( string)); static assert( hasMobileElements!(dstring)); static assert( hasMobileElements!( char[])); static assert( hasMobileElements!(dchar[])); } /** The element type of $(D R). $(D R) does not have to be a range. The element type is determined as the type yielded by $(D r.front) for an object $(D r) of type $(D R). For example, $(D ElementType!(T[])) is $(D T) if $(D T[]) isn't a narrow string; if it is, the element type is $(D dchar). If $(D R) doesn't have $(D front), $(D ElementType!R) is $(D void). */ template ElementType(R) { static if (is(typeof(R.init.front.init) T)) alias ElementType = T; else alias ElementType = void; } /// @safe unittest { import std.range : iota; // Standard arrays: returns the type of the elements of the array static assert(is(ElementType!(int[]) == int)); // Accessing .front retrieves the decoded dchar static assert(is(ElementType!(char[]) == dchar)); // rvalue static assert(is(ElementType!(dchar[]) == dchar)); // lvalue // Ditto static assert(is(ElementType!(string) == dchar)); static assert(is(ElementType!(dstring) == immutable(dchar))); // For ranges it gets the type of .front. auto range = iota(0, 10); static assert(is(ElementType!(typeof(range)) == int)); } @safe unittest { static assert(is(ElementType!(byte[]) == byte)); static assert(is(ElementType!(wchar[]) == dchar)); // rvalue static assert(is(ElementType!(wstring) == dchar)); } @safe unittest { enum XYZ : string { a = "foo" } auto x = XYZ.a.front; immutable char[3] a = "abc"; int[] i; void[] buf; static assert(is(ElementType!(XYZ) == dchar)); static assert(is(ElementType!(typeof(a)) == dchar)); static assert(is(ElementType!(typeof(i)) == int)); static assert(is(ElementType!(typeof(buf)) == void)); static assert(is(ElementType!(inout(int)[]) == inout(int))); static assert(is(ElementType!(inout(int[])) == inout(int))); } @safe unittest { static assert(is(ElementType!(int[5]) == int)); static assert(is(ElementType!(int[0]) == int)); static assert(is(ElementType!(char[5]) == dchar)); static assert(is(ElementType!(char[0]) == dchar)); } @safe unittest //11336 { static struct S { this(this) @disable; } static assert(is(ElementType!(S[]) == S)); } @safe unittest // 11401 { // ElementType should also work for non-@propety 'front' struct E { ushort id; } struct R { E front() { return E.init; } } static assert(is(ElementType!R == E)); } /** The encoding element type of $(D R). For narrow strings ($(D char[]), $(D wchar[]) and their qualified variants including $(D string) and $(D wstring)), $(D ElementEncodingType) is the character type of the string. For all other types, $(D ElementEncodingType) is the same as $(D ElementType). */ template ElementEncodingType(R) { static if (is(StringTypeOf!R) && is(R : E[], E)) alias ElementEncodingType = E; else alias ElementEncodingType = ElementType!R; } /// @safe unittest { import std.range : iota; // internally the range stores the encoded type static assert(is(ElementEncodingType!(char[]) == char)); static assert(is(ElementEncodingType!(wstring) == immutable(wchar))); static assert(is(ElementEncodingType!(byte[]) == byte)); auto range = iota(0, 10); static assert(is(ElementEncodingType!(typeof(range)) == int)); } @safe unittest { static assert(is(ElementEncodingType!(wchar[]) == wchar)); static assert(is(ElementEncodingType!(dchar[]) == dchar)); static assert(is(ElementEncodingType!(string) == immutable(char))); static assert(is(ElementEncodingType!(dstring) == immutable(dchar))); static assert(is(ElementEncodingType!(int[]) == int)); } @safe unittest { enum XYZ : string { a = "foo" } auto x = XYZ.a.front; immutable char[3] a = "abc"; int[] i; void[] buf; static assert(is(ElementType!(XYZ) : dchar)); static assert(is(ElementEncodingType!(char[]) == char)); static assert(is(ElementEncodingType!(string) == immutable char)); static assert(is(ElementType!(typeof(a)) : dchar)); static assert(is(ElementType!(typeof(i)) == int)); static assert(is(ElementEncodingType!(typeof(i)) == int)); static assert(is(ElementType!(typeof(buf)) : void)); static assert(is(ElementEncodingType!(inout char[]) : inout(char))); } @safe unittest { static assert(is(ElementEncodingType!(int[5]) == int)); static assert(is(ElementEncodingType!(int[0]) == int)); static assert(is(ElementEncodingType!(char[5]) == char)); static assert(is(ElementEncodingType!(char[0]) == char)); } /** Returns $(D true) if $(D R) is an input range and has swappable elements. The following code should compile for any range with swappable elements. ---- R r; static assert(isInputRange!R); swap(r.front, r.front); static if (isBidirectionalRange!R) swap(r.back, r.front); static if (isRandomAccessRange!R) swap(r[], r.front); ---- */ template hasSwappableElements(R) { import std.algorithm : swap; enum bool hasSwappableElements = isInputRange!R && is(typeof( (inout int = 0) { R r = R.init; swap(r.front, r.front); static if (isBidirectionalRange!R) swap(r.back, r.front); static if (isRandomAccessRange!R) swap(r[0], r.front); })); } /// @safe unittest { static assert(!hasSwappableElements!(const int[])); static assert(!hasSwappableElements!(const(int)[])); static assert(!hasSwappableElements!(inout(int)[])); static assert( hasSwappableElements!(int[])); static assert(!hasSwappableElements!( string)); static assert(!hasSwappableElements!(dstring)); static assert(!hasSwappableElements!( char[])); static assert( hasSwappableElements!(dchar[])); } /** Returns $(D true) if $(D R) is an input range and has mutable elements. The following code should compile for any range with assignable elements. ---- R r; static assert(isInputRange!R); r.front = r.front; static if (isBidirectionalRange!R) r.back = r.front; static if (isRandomAccessRange!R) r[0] = r.front; ---- */ template hasAssignableElements(R) { enum bool hasAssignableElements = isInputRange!R && is(typeof( (inout int = 0) { R r = R.init; r.front = r.front; static if (isBidirectionalRange!R) r.back = r.front; static if (isRandomAccessRange!R) r[0] = r.front; })); } /// @safe unittest { static assert(!hasAssignableElements!(const int[])); static assert(!hasAssignableElements!(const(int)[])); static assert( hasAssignableElements!(int[])); static assert(!hasAssignableElements!(inout(int)[])); static assert(!hasAssignableElements!( string)); static assert(!hasAssignableElements!(dstring)); static assert(!hasAssignableElements!( char[])); static assert( hasAssignableElements!(dchar[])); } /** Tests whether the range $(D R) has lvalue elements. These are defined as elements that can be passed by reference and have their address taken. The following code should compile for any range with lvalue elements. ---- void passByRef(ref ElementType!R stuff); ... static assert(isInputRange!R); passByRef(r.front); static if (isBidirectionalRange!R) passByRef(r.back); static if (isRandomAccessRange!R) passByRef(r[0]); ---- */ template hasLvalueElements(R) { enum bool hasLvalueElements = isInputRange!R && is(typeof( (inout int = 0) { void checkRef(ref ElementType!R stuff); R r = R.init; checkRef(r.front); static if (isBidirectionalRange!R) checkRef(r.back); static if (isRandomAccessRange!R) checkRef(r[0]); })); } /// @safe unittest { import std.range : iota, chain; static assert( hasLvalueElements!(int[])); static assert( hasLvalueElements!(const(int)[])); static assert( hasLvalueElements!(inout(int)[])); static assert( hasLvalueElements!(immutable(int)[])); static assert(!hasLvalueElements!(typeof(iota(3)))); static assert(!hasLvalueElements!( string)); static assert( hasLvalueElements!(dstring)); static assert(!hasLvalueElements!( char[])); static assert( hasLvalueElements!(dchar[])); auto c = chain([1, 2, 3], [4, 5, 6]); static assert( hasLvalueElements!(typeof(c))); } @safe unittest { // bugfix 6336 struct S { immutable int value; } static assert( isInputRange!(S[])); static assert( hasLvalueElements!(S[])); } /** Returns $(D true) if $(D R) has a $(D length) member that returns an integral type. $(D R) does not have to be a range. Note that $(D length) is an optional primitive as no range must implement it. Some ranges do not store their length explicitly, some cannot compute it without actually exhausting the range (e.g. socket streams), and some other ranges may be infinite. Although narrow string types ($(D char[]), $(D wchar[]), and their qualified derivatives) do define a $(D length) property, $(D hasLength) yields $(D false) for them. This is because a narrow string's length does not reflect the number of characters, but instead the number of encoding units, and as such is not useful with range-oriented algorithms. */ template hasLength(R) { enum bool hasLength = !isNarrowString!R && is(typeof( (inout int = 0) { R r = R.init; ulong l = r.length; })); } /// @safe unittest { static assert(!hasLength!(char[])); static assert( hasLength!(int[])); static assert( hasLength!(inout(int)[])); struct A { ulong length; } struct B { size_t length() { return 0; } } struct C { @property size_t length() { return 0; } } static assert( hasLength!(A)); static assert( hasLength!(B)); static assert( hasLength!(C)); } /** Returns $(D true) if $(D R) is an infinite input range. An infinite input range is an input range that has a statically-defined enumerated member called $(D empty) that is always $(D false), for example: ---- struct MyInfiniteRange { enum bool empty = false; ... } ---- */ template isInfinite(R) { static if (isInputRange!R && __traits(compiles, { enum e = R.empty; })) enum bool isInfinite = !R.empty; else enum bool isInfinite = false; } /// @safe unittest { import std.range : Repeat; static assert(!isInfinite!(int[])); static assert( isInfinite!(Repeat!(int))); } /** Returns $(D true) if $(D R) offers a slicing operator with integral boundaries that returns a forward range type. For finite ranges, the result of $(D opSlice) must be of the same type as the original range type. If the range defines $(D opDollar), then it must support subtraction. For infinite ranges, when $(I not) using $(D opDollar), the result of $(D opSlice) must be the result of $(LREF take) or $(LREF takeExactly) on the original range (they both return the same type for infinite ranges). However, when using $(D opDollar), the result of $(D opSlice) must be that of the original range type. The following code must compile for $(D hasSlicing) to be $(D true): ---- R r = void; static if(isInfinite!R) typeof(take(r, 1)) s = r[1 .. 2]; else { static assert(is(typeof(r[1 .. 2]) == R)); R s = r[1 .. 2]; } s = r[1 .. 2]; static if(is(typeof(r[0 .. $]))) { static assert(is(typeof(r[0 .. $]) == R)); R t = r[0 .. $]; t = r[0 .. $]; static if(!isInfinite!R) { static assert(is(typeof(r[0 .. $ - 1]) == R)); R u = r[0 .. $ - 1]; u = r[0 .. $ - 1]; } } static assert(isForwardRange!(typeof(r[1 .. 2]))); static assert(hasLength!(typeof(r[1 .. 2]))); ---- */ template hasSlicing(R) { enum bool hasSlicing = isForwardRange!R && !isNarrowString!R && is(typeof( (inout int = 0) { R r = R.init; static if(isInfinite!R) { typeof(r[1 .. 1]) s = r[1 .. 2]; } else { static assert(is(typeof(r[1 .. 2]) == R)); R s = r[1 .. 2]; } s = r[1 .. 2]; static if(is(typeof(r[0 .. $]))) { static assert(is(typeof(r[0 .. $]) == R)); R t = r[0 .. $]; t = r[0 .. $]; static if(!isInfinite!R) { static assert(is(typeof(r[0 .. $ - 1]) == R)); R u = r[0 .. $ - 1]; u = r[0 .. $ - 1]; } } static assert(isForwardRange!(typeof(r[1 .. 2]))); static assert(hasLength!(typeof(r[1 .. 2]))); })); } /// @safe unittest { import std.range : takeExactly; static assert( hasSlicing!(int[])); static assert( hasSlicing!(const(int)[])); static assert(!hasSlicing!(const int[])); static assert( hasSlicing!(inout(int)[])); static assert(!hasSlicing!(inout int [])); static assert( hasSlicing!(immutable(int)[])); static assert(!hasSlicing!(immutable int[])); static assert(!hasSlicing!string); static assert( hasSlicing!dstring); enum rangeFuncs = "@property int front();" ~ "void popFront();" ~ "@property bool empty();" ~ "@property auto save() { return this; }" ~ "@property size_t length();"; struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); } struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); } struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); } struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); } static assert(!hasSlicing!(A)); static assert( hasSlicing!(B)); static assert( hasSlicing!(C)); static assert(!hasSlicing!(D)); struct InfOnes { enum empty = false; void popFront() {} @property int front() { return 1; } @property InfOnes save() { return this; } auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); } auto opSlice(size_t i, Dollar d) { return this; } struct Dollar {} Dollar opDollar() const { return Dollar.init; } } static assert(hasSlicing!InfOnes); } /** This is a best-effort implementation of $(D length) for any kind of range. If $(D hasLength!Range), simply returns $(D range.length) without checking $(D upTo) (when specified). Otherwise, walks the range through its length and returns the number of elements seen. Performes $(BIGOH n) evaluations of $(D range.empty) and $(D range.popFront()), where $(D n) is the effective length of $(D range). The $(D upTo) parameter is useful to "cut the losses" in case the interest is in seeing whether the range has at least some number of elements. If the parameter $(D upTo) is specified, stops if $(D upTo) steps have been taken and returns $(D upTo). Infinite ranges are compatible, provided the parameter $(D upTo) is specified, in which case the implementation simply returns upTo. */ auto walkLength(Range)(Range range) if (isInputRange!Range && !isInfinite!Range) { static if (hasLength!Range) return range.length; else { size_t result; for ( ; !range.empty ; range.popFront() ) ++result; return result; } } /// ditto auto walkLength(Range)(Range range, const size_t upTo) if (isInputRange!Range) { static if (hasLength!Range) return range.length; else static if (isInfinite!Range) return upTo; else { size_t result; for ( ; result < upTo && !range.empty ; range.popFront() ) ++result; return result; } } @safe unittest { import std.algorithm : filter; import std.range : recurrence, take; //hasLength Range int[] a = [ 1, 2, 3 ]; assert(walkLength(a) == 3); assert(walkLength(a, 0) == 3); assert(walkLength(a, 2) == 3); assert(walkLength(a, 4) == 3); //Forward Range auto b = filter!"true"([1, 2, 3, 4]); assert(b.walkLength() == 4); assert(b.walkLength(0) == 0); assert(b.walkLength(2) == 2); assert(b.walkLength(4) == 4); assert(b.walkLength(6) == 4); //Infinite Range auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1); assert(!__traits(compiles, fibs.walkLength())); assert(fibs.take(10).walkLength() == 10); assert(fibs.walkLength(55) == 55); } /** Eagerly advances $(D r) itself (not a copy) up to $(D n) times (by calling $(D r.popFront)). $(D popFrontN) takes $(D r) by $(D ref), so it mutates the original range. Completes in $(BIGOH 1) steps for ranges that support slicing and have length. Completes in $(BIGOH n) time for all other ranges. Returns: How much $(D r) was actually advanced, which may be less than $(D n) if $(D r) did not have at least $(D n) elements. $(D popBackN) will behave the same but instead removes elements from the back of the (bidirectional) range instead of the front. */ size_t popFrontN(Range)(ref Range r, size_t n) if (isInputRange!Range) { static if (hasLength!Range) { n = cast(size_t) (n < r.length ? n : r.length); } static if (hasSlicing!Range && is(typeof(r = r[n .. $]))) { r = r[n .. $]; } else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. { r = r[n .. r.length]; } else { static if (hasLength!Range) { foreach (i; 0 .. n) r.popFront(); } else { foreach (i; 0 .. n) { if (r.empty) return i; r.popFront(); } } } return n; } /// ditto size_t popBackN(Range)(ref Range r, size_t n) if (isBidirectionalRange!Range) { static if (hasLength!Range) { n = cast(size_t) (n < r.length ? n : r.length); } static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n]))) { r = r[0 .. $ - n]; } else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. { r = r[0 .. r.length - n]; } else { static if (hasLength!Range) { foreach (i; 0 .. n) r.popBack(); } else { foreach (i; 0 .. n) { if (r.empty) return i; r.popBack(); } } } return n; } /// @safe unittest { int[] a = [ 1, 2, 3, 4, 5 ]; a.popFrontN(2); assert(a == [ 3, 4, 5 ]); a.popFrontN(7); assert(a == [ ]); } /// @safe unittest { import std.algorithm : equal; import std.range : iota; auto LL = iota(1L, 7L); auto r = popFrontN(LL, 2); assert(equal(LL, [3L, 4L, 5L, 6L])); assert(r == 2); } /// @safe unittest { int[] a = [ 1, 2, 3, 4, 5 ]; a.popBackN(2); assert(a == [ 1, 2, 3 ]); a.popBackN(7); assert(a == [ ]); } /// @safe unittest { import std.algorithm : equal; import std.range : iota; auto LL = iota(1L, 7L); auto r = popBackN(LL, 2); assert(equal(LL, [1L, 2L, 3L, 4L])); assert(r == 2); } /** Eagerly advances $(D r) itself (not a copy) exactly $(D n) times (by calling $(D r.popFront)). $(D popFrontExactly) takes $(D r) by $(D ref), so it mutates the original range. Completes in $(BIGOH 1) steps for ranges that support slicing, and have either length or are infinite. Completes in $(BIGOH n) time for all other ranges. Note: Unlike $(LREF popFrontN), $(D popFrontExactly) will assume that the range holds at least $(D n) elements. This makes $(D popFrontExactly) faster than $(D popFrontN), but it also means that if $(D range) does not contain at least $(D n) elements, it will attempt to call $(D popFront) on an empty range, which is undefined behavior. So, only use $(D popFrontExactly) when it is guaranteed that $(D range) holds at least $(D n) elements. $(D popBackExactly) will behave the same but instead removes elements from the back of the (bidirectional) range instead of the front. */ void popFrontExactly(Range)(ref Range r, size_t n) if (isInputRange!Range) { static if (hasLength!Range) assert(n <= r.length, "range is smaller than amount of items to pop"); static if (hasSlicing!Range && is(typeof(r = r[n .. $]))) r = r[n .. $]; else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. r = r[n .. r.length]; else foreach (i; 0 .. n) r.popFront(); } /// ditto void popBackExactly(Range)(ref Range r, size_t n) if (isBidirectionalRange!Range) { static if (hasLength!Range) assert(n <= r.length, "range is smaller than amount of items to pop"); static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n]))) r = r[0 .. $ - n]; else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. r = r[0 .. r.length - n]; else foreach (i; 0 .. n) r.popBack(); } /// @safe unittest { import std.algorithm : filterBidirectional, equal; auto a = [1, 2, 3]; a.popFrontExactly(1); assert(a == [2, 3]); a.popBackExactly(1); assert(a == [2]); string s = "日本語"; s.popFrontExactly(1); assert(s == "本語"); s.popBackExactly(1); assert(s == "本"); auto bd = filterBidirectional!"true"([1, 2, 3]); bd.popFrontExactly(1); assert(bd.equal([2, 3])); bd.popBackExactly(1); assert(bd.equal([2])); } /** Moves the front of $(D r) out and returns it. Leaves $(D r.front) in a destroyable state that does not allocate any resources (usually equal to its $(D .init) value). */ ElementType!R moveFront(R)(R r) { static if (is(typeof(&r.moveFront))) { return r.moveFront(); } else static if (!hasElaborateCopyConstructor!(ElementType!R)) { return r.front; } else static if (is(typeof(&(r.front())) == ElementType!R*)) { import std.algorithm : move; return move(r.front); } else { static assert(0, "Cannot move front of a range with a postblit and an rvalue front."); } } /// @safe unittest { auto a = [ 1, 2, 3 ]; assert(moveFront(a) == 1); // define a perfunctory input range struct InputRange { @property bool empty() { return false; } @property int front() { return 42; } void popFront() {} int moveFront() { return 43; } } InputRange r; assert(moveFront(r) == 43); } @safe unittest { struct R { @property ref int front() { static int x = 42; return x; } this(this){} } R r; assert(moveFront(r) == 42); } /** Moves the back of $(D r) out and returns it. Leaves $(D r.back) in a destroyable state that does not allocate any resources (usually equal to its $(D .init) value). */ ElementType!R moveBack(R)(R r) { static if (is(typeof(&r.moveBack))) { return r.moveBack(); } else static if (!hasElaborateCopyConstructor!(ElementType!R)) { return r.back; } else static if (is(typeof(&(r.back())) == ElementType!R*)) { import std.algorithm : move; return move(r.back); } else { static assert(0, "Cannot move back of a range with a postblit and an rvalue back."); } } /// @safe unittest { struct TestRange { int payload = 5; @property bool empty() { return false; } @property TestRange save() { return this; } @property ref int front() return { return payload; } @property ref int back() return { return payload; } void popFront() { } void popBack() { } } static assert(isBidirectionalRange!TestRange); TestRange r; auto x = moveBack(r); assert(x == 5); } /** Moves element at index $(D i) of $(D r) out and returns it. Leaves $(D r.front) in a destroyable state that does not allocate any resources (usually equal to its $(D .init) value). */ ElementType!R moveAt(R, I)(R r, I i) if (isIntegral!I) { static if (is(typeof(&r.moveAt))) { return r.moveAt(i); } else static if (!hasElaborateCopyConstructor!(ElementType!(R))) { return r[i]; } else static if (is(typeof(&r[i]) == ElementType!R*)) { import std.algorithm : move; return move(r[i]); } else { static assert(0, "Cannot move element of a range with a postblit and rvalue elements."); } } /// @safe unittest { auto a = [1,2,3,4]; foreach(idx, it; a) { assert(it == moveAt(a, idx)); } } @safe unittest { import std.internal.test.dummyrange; foreach(DummyType; AllDummyRanges) { auto d = DummyType.init; assert(moveFront(d) == 1); static if (isBidirectionalRange!DummyType) { assert(moveBack(d) == 10); } static if (isRandomAccessRange!DummyType) { assert(moveAt(d, 2) == 3); } } } /** Implements the range interface primitive $(D empty) for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, $(D array.empty) is equivalent to $(D empty(array)). */ @property bool empty(T)(in T[] a) @safe pure nothrow @nogc { return !a.length; } /// @safe pure nothrow unittest { auto a = [ 1, 2, 3 ]; assert(!a.empty); assert(a[3 .. $].empty); } /** Implements the range interface primitive $(D save) for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, $(D array.save) is equivalent to $(D save(array)). The function does not duplicate the content of the array, it simply returns its argument. */ @property T[] save(T)(T[] a) @safe pure nothrow @nogc { return a; } /// @safe pure nothrow unittest { auto a = [ 1, 2, 3 ]; auto b = a.save; assert(b is a); } /** Implements the range interface primitive $(D popFront) for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, $(D array.popFront) is equivalent to $(D popFront(array)). For $(GLOSSARY narrow strings), $(D popFront) automatically advances to the next $(GLOSSARY code point). */ void popFront(T)(ref T[] a) @safe pure nothrow @nogc if (!isNarrowString!(T[]) && !is(T[] == void[])) { assert(a.length, "Attempting to popFront() past the end of an array of " ~ T.stringof); a = a[1 .. $]; } /// @safe pure nothrow unittest { auto a = [ 1, 2, 3 ]; a.popFront(); assert(a == [ 2, 3 ]); } version(unittest) { static assert(!is(typeof({ int[4] a; popFront(a); }))); static assert(!is(typeof({ immutable int[] a; popFront(a); }))); static assert(!is(typeof({ void[] a; popFront(a); }))); } // Specialization for narrow strings. The necessity of void popFront(C)(ref C[] str) @trusted pure nothrow if (isNarrowString!(C[])) { assert(str.length, "Attempting to popFront() past the end of an array of " ~ C.stringof); static if(is(Unqual!C == char)) { immutable c = str[0]; if(c < 0x80) { //ptr is used to avoid unnnecessary bounds checking. str = str.ptr[1 .. str.length]; } else { import core.bitop : bsr; auto msbs = 7 - bsr(~c); if((msbs < 2) | (msbs > 6)) { //Invalid UTF-8 msbs = 1; } str = str[msbs .. $]; } } else static if(is(Unqual!C == wchar)) { immutable u = str[0]; str = str[1 + (u >= 0xD800 && u <= 0xDBFF) .. $]; } else static assert(0, "Bad template constraint."); } @safe pure unittest { import std.meta : AliasSeq; foreach(S; AliasSeq!(string, wstring, dstring)) { S s = "\xC2\xA9hello"; s.popFront(); assert(s == "hello"); S str = "hello\U00010143\u0100\U00010143"; foreach(dchar c; ['h', 'e', 'l', 'l', 'o', '\U00010143', '\u0100', '\U00010143']) { assert(str.front == c); str.popFront(); } assert(str.empty); static assert(!is(typeof({ immutable S a; popFront(a); }))); static assert(!is(typeof({ typeof(S.init[0])[4] a; popFront(a); }))); } C[] _eatString(C)(C[] str) { while(!str.empty) str.popFront(); return str; } enum checkCTFE = _eatString("ウェブサイト@La_Verité.com"); static assert(checkCTFE.empty); enum checkCTFEW = _eatString("ウェブサイト@La_Verité.com"w); static assert(checkCTFEW.empty); } /** Implements the range interface primitive $(D popBack) for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, $(D array.popBack) is equivalent to $(D popBack(array)). For $(GLOSSARY narrow strings), $(D popFront) automatically eliminates the last $(GLOSSARY code point). */ void popBack(T)(ref T[] a) @safe pure nothrow @nogc if (!isNarrowString!(T[]) && !is(T[] == void[])) { assert(a.length); a = a[0 .. $ - 1]; } /// @safe pure nothrow unittest { auto a = [ 1, 2, 3 ]; a.popBack(); assert(a == [ 1, 2 ]); } version(unittest) { static assert(!is(typeof({ immutable int[] a; popBack(a); }))); static assert(!is(typeof({ int[4] a; popBack(a); }))); static assert(!is(typeof({ void[] a; popBack(a); }))); } // Specialization for arrays of char void popBack(T)(ref T[] a) @safe pure if (isNarrowString!(T[])) { import std.utf: strideBack; assert(a.length, "Attempting to popBack() past the front of an array of " ~ T.stringof); a = a[0 .. $ - strideBack(a, $)]; } @safe pure unittest { import std.meta : AliasSeq; foreach(S; AliasSeq!(string, wstring, dstring)) { S s = "hello\xE2\x89\xA0"; s.popBack(); assert(s == "hello"); S s3 = "\xE2\x89\xA0"; auto c = s3.back; assert(c == cast(dchar)'\u2260'); s3.popBack(); assert(s3 == ""); S str = "\U00010143\u0100\U00010143hello"; foreach(dchar ch; ['o', 'l', 'l', 'e', 'h', '\U00010143', '\u0100', '\U00010143']) { assert(str.back == ch); str.popBack(); } assert(str.empty); static assert(!is(typeof({ immutable S a; popBack(a); }))); static assert(!is(typeof({ typeof(S.init[0])[4] a; popBack(a); }))); } } /** Implements the range interface primitive $(D front) for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, $(D array.front) is equivalent to $(D front(array)). For $(GLOSSARY narrow strings), $(D front) automatically returns the first $(GLOSSARY code point) as a $(D dchar). */ @property ref T front(T)(T[] a) @safe pure nothrow @nogc if (!isNarrowString!(T[]) && !is(T[] == void[])) { assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof); return a[0]; } /// @safe pure nothrow unittest { int[] a = [ 1, 2, 3 ]; assert(a.front == 1); } @safe pure nothrow unittest { auto a = [ 1, 2 ]; a.front = 4; assert(a.front == 4); assert(a == [ 4, 2 ]); immutable b = [ 1, 2 ]; assert(b.front == 1); int[2] c = [ 1, 2 ]; assert(c.front == 1); } @property dchar front(T)(T[] a) @safe pure if (isNarrowString!(T[])) { import std.utf : decode; assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof); size_t i = 0; return decode(a, i); } /** Implements the range interface primitive $(D back) for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, $(D array.back) is equivalent to $(D back(array)). For $(GLOSSARY narrow strings), $(D back) automatically returns the last $(GLOSSARY code point) as a $(D dchar). */ @property ref T back(T)(T[] a) @safe pure nothrow @nogc if (!isNarrowString!(T[])) { assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof); return a[$ - 1]; } /// @safe pure nothrow unittest { int[] a = [ 1, 2, 3 ]; assert(a.back == 3); a.back += 4; assert(a.back == 7); } @safe pure nothrow unittest { immutable b = [ 1, 2, 3 ]; assert(b.back == 3); int[3] c = [ 1, 2, 3 ]; assert(c.back == 3); } // Specialization for strings @property dchar back(T)(T[] a) @safe pure if (isNarrowString!(T[])) { import std.utf : decode, strideBack; assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof); size_t i = a.length - strideBack(a, a.length); return decode(a, i); } ldc-1.1.0-beta3-src/runtime/phobos/std/range/interfaces.d0000664000175000017500000003473012776215007021301 0ustar kaikai/** This module is a submodule of $(LINK2 std_range.html, std.range). The main $(D std.range) module provides template-based tools for working with ranges, but sometimes an object-based interface for ranges is needed, such as when runtime polymorphism is required. For this purpose, this submodule provides a number of object and $(D interface) definitions that can be used to wrap around _range objects created by the $(D std.range) templates. $(BOOKTABLE , $(TR $(TD $(D $(LREF InputRange))) $(TD Wrapper for input ranges. )) $(TR $(TD $(D $(LREF InputAssignable))) $(TD Wrapper for input ranges with assignable elements. )) $(TR $(TD $(D $(LREF ForwardRange))) $(TD Wrapper for forward ranges. )) $(TR $(TD $(D $(LREF ForwardAssignable))) $(TD Wrapper for forward ranges with assignable elements. )) $(TR $(TD $(D $(LREF BidirectionalRange))) $(TD Wrapper for bidirectional ranges. )) $(TR $(TD $(D $(LREF BidirectionalAssignable))) $(TD Wrapper for bidirectional ranges with assignable elements. )) $(TR $(TD $(D $(LREF RandomAccessFinite))) $(TD Wrapper for finite random-access ranges. )) $(TR $(TD $(D $(LREF RandomAccessAssignable))) $(TD Wrapper for finite random-access ranges with assignable elements. )) $(TR $(TD $(D $(LREF RandomAccessInfinite))) $(TD Wrapper for infinite random-access ranges. )) $(TR $(TD $(D $(LREF OutputRange))) $(TD Wrapper for output ranges. )) $(TR $(TD $(D $(LREF OutputRangeObject))) $(TD Class that implements the $(D OutputRange) interface and wraps the $(D put) methods in virtual functions. )) $(TR $(TD $(D $(LREF InputRangeObject))) $(TD Class that implements the $(D InputRange) interface and wraps the input _range methods in virtual functions. )) $(TR $(TD $(D $(LREF RefRange))) $(TD Wrapper around a forward _range that gives it reference semantics. )) ) Source: $(PHOBOSSRC std/range/_interfaces.d) Macros: WIKI = Phobos/StdRange Copyright: Copyright by authors 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu), David Simcha, and Jonathan M Davis. Credit for some of the ideas in building this module goes to $(WEB fantascienza.net/leonardo/so/, Leonardo Maffi). */ module std.range.interfaces; import std.meta; import std.range.primitives; import std.traits; /**These interfaces are intended to provide virtual function-based wrappers * around input ranges with element type E. This is useful where a well-defined * binary interface is required, such as when a DLL function or virtual function * needs to accept a generic range as a parameter. Note that * $(LINK2 std_range_primitives.html#isInputRange, isInputRange) and friends check for conformance to structural * interfaces, not for implementation of these $(D interface) types. * * Limitations: * * These interfaces are not capable of forwarding $(D ref) access to elements. * * Infiniteness of the wrapped range is not propagated. * * Length is not propagated in the case of non-random access ranges. * * See_Also: * $(LREF inputRangeObject) */ interface InputRange(E) { /// @property E front(); /// E moveFront(); /// void popFront(); /// @property bool empty(); /* Measurements of the benefits of using opApply instead of range primitives * for foreach, using timings for iterating over an iota(100_000_000) range * with an empty loop body, using the same hardware in each case: * * Bare Iota struct, range primitives: 278 milliseconds * InputRangeObject, opApply: 436 milliseconds (1.57x penalty) * InputRangeObject, range primitives: 877 milliseconds (3.15x penalty) */ /**$(D foreach) iteration uses opApply, since one delegate call per loop * iteration is faster than three virtual function calls. */ int opApply(int delegate(E)); /// Ditto int opApply(int delegate(size_t, E)); } /// unittest { import std.algorithm : map; import std.range : iota; void useRange(InputRange!int range) { // Function body. } // Create a range type. auto squares = map!"a * a"(iota(10)); // Wrap it in an interface. auto squaresWrapped = inputRangeObject(squares); // Use it. useRange(squaresWrapped); } /**Interface for a forward range of type $(D E).*/ interface ForwardRange(E) : InputRange!E { /// @property ForwardRange!E save(); } /**Interface for a bidirectional range of type $(D E).*/ interface BidirectionalRange(E) : ForwardRange!(E) { /// @property BidirectionalRange!E save(); /// @property E back(); /// E moveBack(); /// void popBack(); } /**Interface for a finite random access range of type $(D E).*/ interface RandomAccessFinite(E) : BidirectionalRange!(E) { /// @property RandomAccessFinite!E save(); /// E opIndex(size_t); /// E moveAt(size_t); /// @property size_t length(); /// alias opDollar = length; // Can't support slicing until issues with requiring slicing for all // finite random access ranges are fully resolved. version(none) { /// RandomAccessFinite!E opSlice(size_t, size_t); } } /**Interface for an infinite random access range of type $(D E).*/ interface RandomAccessInfinite(E) : ForwardRange!E { /// E moveAt(size_t); /// @property RandomAccessInfinite!E save(); /// E opIndex(size_t); } /**Adds assignable elements to InputRange.*/ interface InputAssignable(E) : InputRange!E { /// @property void front(E newVal); } /**Adds assignable elements to ForwardRange.*/ interface ForwardAssignable(E) : InputAssignable!E, ForwardRange!E { /// @property ForwardAssignable!E save(); } /**Adds assignable elements to BidirectionalRange.*/ interface BidirectionalAssignable(E) : ForwardAssignable!E, BidirectionalRange!E { /// @property BidirectionalAssignable!E save(); /// @property void back(E newVal); } /**Adds assignable elements to RandomAccessFinite.*/ interface RandomFiniteAssignable(E) : RandomAccessFinite!E, BidirectionalAssignable!E { /// @property RandomFiniteAssignable!E save(); /// void opIndexAssign(E val, size_t index); } /**Interface for an output range of type $(D E). Usage is similar to the * $(D InputRange) interface and descendants.*/ interface OutputRange(E) { /// void put(E); } @safe unittest { // 6973 static assert(isOutputRange!(OutputRange!int, int)); } // CTFE function that generates mixin code for one put() method for each // type E. private string putMethods(E...)() { import std.conv : to; string ret; foreach (ti, Unused; E) { ret ~= "void put(E[" ~ to!string(ti) ~ "] e) { .put(_range, e); }"; } return ret; } /**Implements the $(D OutputRange) interface for all types E and wraps the * $(D put) method for each type $(D E) in a virtual function. */ class OutputRangeObject(R, E...) : staticMap!(OutputRange, E) { // @BUG 4689: There should be constraints on this template class, but // DMD won't let me put them in. private R _range; this(R range) { this._range = range; } mixin(putMethods!E()); } /**Returns the interface type that best matches $(D R).*/ template MostDerivedInputRange(R) if (isInputRange!(Unqual!R)) { private alias E = ElementType!R; static if (isRandomAccessRange!R) { static if (isInfinite!R) { alias MostDerivedInputRange = RandomAccessInfinite!E; } else static if (hasAssignableElements!R) { alias MostDerivedInputRange = RandomFiniteAssignable!E; } else { alias MostDerivedInputRange = RandomAccessFinite!E; } } else static if (isBidirectionalRange!R) { static if (hasAssignableElements!R) { alias MostDerivedInputRange = BidirectionalAssignable!E; } else { alias MostDerivedInputRange = BidirectionalRange!E; } } else static if (isForwardRange!R) { static if (hasAssignableElements!R) { alias MostDerivedInputRange = ForwardAssignable!E; } else { alias MostDerivedInputRange = ForwardRange!E; } } else { static if (hasAssignableElements!R) { alias MostDerivedInputRange = InputAssignable!E; } else { alias MostDerivedInputRange = InputRange!E; } } } /**Implements the most derived interface that $(D R) works with and wraps * all relevant range primitives in virtual functions. If $(D R) is already * derived from the $(D InputRange) interface, aliases itself away. */ template InputRangeObject(R) if (isInputRange!(Unqual!R)) { static if (is(R : InputRange!(ElementType!R))) { alias InputRangeObject = R; } else static if (!is(Unqual!R == R)) { alias InputRangeObject = InputRangeObject!(Unqual!R); } else { /// class InputRangeObject : MostDerivedInputRange!(R) { private R _range; private alias E = ElementType!R; this(R range) { this._range = range; } @property E front() { return _range.front; } E moveFront() { return .moveFront(_range); } void popFront() { _range.popFront(); } @property bool empty() { return _range.empty; } static if (isForwardRange!R) { @property typeof(this) save() { return new typeof(this)(_range.save); } } static if (hasAssignableElements!R) { @property void front(E newVal) { _range.front = newVal; } } static if (isBidirectionalRange!R) { @property E back() { return _range.back; } E moveBack() { return .moveBack(_range); } void popBack() { return _range.popBack(); } static if (hasAssignableElements!R) { @property void back(E newVal) { _range.back = newVal; } } } static if (isRandomAccessRange!R) { E opIndex(size_t index) { return _range[index]; } E moveAt(size_t index) { return .moveAt(_range, index); } static if (hasAssignableElements!R) { void opIndexAssign(E val, size_t index) { _range[index] = val; } } static if (!isInfinite!R) { @property size_t length() { return _range.length; } alias opDollar = length; // Can't support slicing until all the issues with // requiring slicing support for finite random access // ranges are resolved. version(none) { typeof(this) opSlice(size_t lower, size_t upper) { return new typeof(this)(_range[lower..upper]); } } } } // Optimization: One delegate call is faster than three virtual // function calls. Use opApply for foreach syntax. int opApply(int delegate(E) dg) { int res; for(auto r = _range; !r.empty; r.popFront()) { res = dg(r.front); if (res) break; } return res; } int opApply(int delegate(size_t, E) dg) { int res; size_t i = 0; for(auto r = _range; !r.empty; r.popFront()) { res = dg(i, r.front); if (res) break; i++; } return res; } } } } /**Convenience function for creating an $(D InputRangeObject) of the proper type. * See $(LREF InputRange) for an example. */ InputRangeObject!R inputRangeObject(R)(R range) if (isInputRange!R) { static if (is(R : InputRange!(ElementType!R))) { return range; } else { return new InputRangeObject!R(range); } } /**Convenience function for creating an $(D OutputRangeObject) with a base range * of type $(D R) that accepts types $(D E). */ template outputRangeObject(E...) { /// OutputRangeObject!(R, E) outputRangeObject(R)(R range) { return new OutputRangeObject!(R, E)(range); } } /// unittest { import std.array; auto app = appender!(uint[])(); auto appWrapped = outputRangeObject!(uint, uint[])(app); static assert(is(typeof(appWrapped) : OutputRange!(uint[]))); static assert(is(typeof(appWrapped) : OutputRange!(uint))); } unittest { import std.internal.test.dummyrange; import std.algorithm : equal; import std.array; static void testEquality(R)(iInputRange r1, R r2) { assert(equal(r1, r2)); } auto arr = [1,2,3,4]; RandomFiniteAssignable!int arrWrapped = inputRangeObject(arr); static assert(isRandomAccessRange!(typeof(arrWrapped))); // static assert(hasSlicing!(typeof(arrWrapped))); static assert(hasLength!(typeof(arrWrapped))); arrWrapped[0] = 0; assert(arr[0] == 0); assert(arr.moveFront() == 0); assert(arr.moveBack() == 4); assert(arr.moveAt(1) == 2); foreach(elem; arrWrapped) {} foreach(i, elem; arrWrapped) {} assert(inputRangeObject(arrWrapped) is arrWrapped); foreach(DummyType; AllDummyRanges) { auto d = DummyType.init; static assert(propagatesRangeType!(DummyType, typeof(inputRangeObject(d)))); static assert(propagatesRangeType!(DummyType, MostDerivedInputRange!DummyType)); InputRange!uint wrapped = inputRangeObject(d); assert(equal(wrapped, d)); } // Test output range stuff. auto app = appender!(uint[])(); auto appWrapped = outputRangeObject!(uint, uint[])(app); static assert(is(typeof(appWrapped) : OutputRange!(uint[]))); static assert(is(typeof(appWrapped) : OutputRange!(uint))); appWrapped.put(1); appWrapped.put([2, 3]); assert(app.data.length == 3); assert(equal(app.data, [1,2,3])); } ldc-1.1.0-beta3-src/runtime/phobos/std/math.d0000664000175000017500000073063212776215007017017 0ustar kaikai// Written in the D programming language. /** * Contains the elementary mathematical functions (powers, roots, * and trigonometric functions), and low-level floating-point operations. * Mathematical special functions are available in $(D std.mathspecial). * $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Members) ) $(TR $(TDNW Constants) $(TD $(MYREF E) $(MYREF PI) $(MYREF PI_2) $(MYREF PI_4) $(MYREF M_1_PI) $(MYREF M_2_PI) $(MYREF M_2_SQRTPI) $(MYREF LN10) $(MYREF LN2) $(MYREF LOG2) $(MYREF LOG2E) $(MYREF LOG2T) $(MYREF LOG10E) $(MYREF SQRT2) $(MYREF SQRT1_2) )) $(TR $(TDNW Classics) $(TD $(MYREF abs) $(MYREF fabs) $(MYREF sqrt) $(MYREF cbrt) $(MYREF hypot) $(MYREF poly) $(MYREF nextPow2) $(MYREF truncPow2) )) $(TR $(TDNW Trigonometry) $(TD $(MYREF sin) $(MYREF cos) $(MYREF tan) $(MYREF asin) $(MYREF acos) $(MYREF atan) $(MYREF atan2) $(MYREF sinh) $(MYREF cosh) $(MYREF tanh) $(MYREF asinh) $(MYREF acosh) $(MYREF atanh) $(MYREF expi) )) $(TR $(TDNW Rounding) $(TD $(MYREF ceil) $(MYREF floor) $(MYREF round) $(MYREF lround) $(MYREF trunc) $(MYREF rint) $(MYREF lrint) $(MYREF nearbyint) $(MYREF rndtol) )) $(TR $(TDNW Exponentiation & Logarithms) $(TD $(MYREF pow) $(MYREF exp) $(MYREF exp2) $(MYREF expm1) $(MYREF ldexp) $(MYREF frexp) $(MYREF log) $(MYREF log2) $(MYREF log10) $(MYREF logb) $(MYREF ilogb) $(MYREF log1p) $(MYREF scalbn) )) $(TR $(TDNW Modulus) $(TD $(MYREF fmod) $(MYREF modf) $(MYREF remainder) )) $(TR $(TDNW Floating-point operations) $(TD $(MYREF approxEqual) $(MYREF feqrel) $(MYREF fdim) $(MYREF fmax) $(MYREF fmin) $(MYREF fma) $(MYREF nextDown) $(MYREF nextUp) $(MYREF nextafter) $(MYREF NaN) $(MYREF getNaNPayload) $(MYREF cmp) )) $(TR $(TDNW Introspection) $(TD $(MYREF isFinite) $(MYREF isIdentical) $(MYREF isInfinity) $(MYREF isNaN) $(MYREF isNormal) $(MYREF isSubnormal) $(MYREF signbit) $(MYREF sgn) $(MYREF copysign) )) $(TR $(TDNW Complex Numbers) $(TD $(MYREF abs) $(MYREF conj) $(MYREF sin) $(MYREF cos) $(MYREF expi) )) $(TR $(TDNW Hardware Control) $(TD $(MYREF IeeeFlags) $(MYREF FloatingPointControl) )) ) ) * The functionality closely follows the IEEE754-2008 standard for * floating-point arithmetic, including the use of camelCase names rather * than C99-style lower case names. All of these functions behave correctly * when presented with an infinity or NaN. * * The following IEEE 'real' formats are currently supported: * $(UL * $(LI 64 bit Big-endian 'double' (eg PowerPC)) * $(LI 128 bit Big-endian 'quadruple' (eg SPARC)) * $(LI 64 bit Little-endian 'double' (eg x86-SSE2)) * $(LI 80 bit Little-endian, with implied bit 'real80' (eg x87, Itanium)) * $(LI 128 bit Little-endian 'quadruple' (not implemented on any known processor!)) * $(LI Non-IEEE 128 bit Big-endian 'doubledouble' (eg PowerPC) has partial support) * ) * Unlike C, there is no global 'errno' variable. Consequently, almost all of * these functions are pure nothrow. * * Status: * The semantics and names of feqrel and approxEqual will be revised. * * Macros: * WIKI = Phobos/StdMath * * TABLE_SV = * * $0
Special Values
* SVH = $(TR $(TH $1) $(TH $2)) * SV = $(TR $(TD $1) $(TD $2)) * TH3 = $(TR $(TH $1) $(TH $2) $(TH $3)) * TD3 = $(TR $(TD $1) $(TD $2) $(TD $3)) * * NAN = $(RED NAN) * SUP = $0 * GAMMA = Γ * THETA = θ * INTEGRAL = ∫ * INTEGRATE = $(BIG ∫$(SMALL $1)$2) * POWER = $1$2 * SUB = $1$2 * BIGSUM = $(BIG Σ $2$(SMALL $1)) * CHOOSE = $(BIG () $(SMALL $1)$(SMALL $2) $(BIG )) * PLUSMN = ± * INFIN = ∞ * PLUSMNINF = ±∞ * PI = π * LT = < * GT = > * SQRT = √ * HALF = ½ * * Copyright: Copyright Digital Mars 2000 - 2011. * D implementations of tan, atan, atan2, exp, expm1, exp2, log, log10, log1p, * log2, floor, ceil and lrint functions are based on the CEPHES math library, * which is Copyright (C) 2001 Stephen L. Moshier $(LT)steve@moshier.net$(GT) * and are incorporated herein by permission of the author. The author * reserves the right to distribute this material elsewhere under different * copying permissions. These modifications are distributed here under * the following terms: * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright), Don Clugston, * Conversion of CEPHES math library to D by Iain Buclaw * Source: $(PHOBOSSRC std/_math.d) */ module std.math; version (Win64) { version (D_InlineAsm_X86_64) version = Win64_DMD_InlineAsm; } import core.bitop; import core.math; import core.stdc.math; import std.traits; version(LDC) { import ldc.intrinsics; import ldc.llvmasm; version(CRuntime_Microsoft) version = LDC_MSVCRT; version(LDC_MSVCRT) {} else { version(X86) version = INLINE_YL2X; version(X86_64) version = INLINE_YL2X; } } version(DigitalMars) { version = INLINE_YL2X; // x87 has opcodes for these version = INLINE_POLY; } version (X86) version = X86_Any; version (X86_64) version = X86_Any; version (PPC) version = PPC_Any; version (PPC64) version = PPC_Any; version (MIPS) version = MIPS_Any; version (MIPS64) version = MIPS_Any; version(D_InlineAsm_X86) { version = InlineAsm_X86_Any; } else version(D_InlineAsm_X86_64) { version = InlineAsm_X86_Any; } // define InlineAsm*_X87 versions if real is defined as 80-bit x87 version(LDC_MSVCRT) {} else { version (D_InlineAsm_X86) version = InlineAsm_X86_X87; version (D_InlineAsm_X86_64) version = InlineAsm_X86_64_X87; version (InlineAsm_X86_Any) version = InlineAsm_X86_Any_X87; version (Win64_DMD_InlineAsm) version = Win64_DMD_InlineAsm_X87; } version(unittest) { import core.stdc.stdio; static if(real.sizeof > double.sizeof) enum uint useDigits = 16; else enum uint useDigits = 15; /****************************************** * Compare floating point numbers to n decimal digits of precision. * Returns: * 1 match * 0 nomatch */ private bool equalsDigit(real x, real y, uint ndigits) { if (signbit(x) != signbit(y)) return 0; if (isInfinity(x) && isInfinity(y)) return 1; if (isInfinity(x) || isInfinity(y)) return 0; if (isNaN(x) && isNaN(y)) return 1; if (isNaN(x) || isNaN(y)) return 0; char[30] bufx; char[30] bufy; assert(ndigits < bufx.length); int ix; int iy; version(CRuntime_Microsoft) alias real_t = double; else alias real_t = real; ix = sprintf(bufx.ptr, "%.*Lg", ndigits, cast(real_t) x); iy = sprintf(bufy.ptr, "%.*Lg", ndigits, cast(real_t) y); assert(ix < bufx.length && ix > 0); assert(ix < bufy.length && ix > 0); return bufx[0 .. ix] == bufy[0 .. iy]; } } package: // The following IEEE 'real' formats are currently supported. version(LittleEndian) { static assert(real.mant_dig == 53 || real.mant_dig == 64 || real.mant_dig == 113, "Only 64-bit, 80-bit, and 128-bit reals"~ " are supported for LittleEndian CPUs"); } else { static assert(real.mant_dig == 53 || real.mant_dig == 106 || real.mant_dig == 113, "Only 64-bit and 128-bit reals are supported for BigEndian CPUs."~ " double-double reals have partial support"); } // Underlying format exposed through floatTraits enum RealFormat { ieeeHalf, ieeeSingle, ieeeDouble, ieeeExtended, // x87 80-bit real ieeeExtended53, // x87 real rounded to precision of double. ibmExtended, // IBM 128-bit extended ieeeQuadruple, } // Constants used for extracting the components of the representation. // They supplement the built-in floating point properties. template floatTraits(T) { // EXPMASK is a ushort mask to select the exponent portion (without sign) // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort // EXPPOS_SHORT is the index of the exponent when represented as a ushort array. // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array. // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal enum T RECIP_EPSILON = (1/T.epsilon); static if (T.mant_dig == 24) { // Single precision float enum ushort EXPMASK = 0x7F80; enum ushort EXPSHIFT = 7; enum ushort EXPBIAS = 0x3F00; enum uint EXPMASK_INT = 0x7F80_0000; enum uint MANTISSAMASK_INT = 0x007F_FFFF; enum realFormat = RealFormat.ieeeSingle; version(LittleEndian) { enum EXPPOS_SHORT = 1; enum SIGNPOS_BYTE = 3; } else { enum EXPPOS_SHORT = 0; enum SIGNPOS_BYTE = 0; } } else static if (T.mant_dig == 53) { static if (T.sizeof == 8) { // Double precision float, or real == double enum ushort EXPMASK = 0x7FF0; enum ushort EXPSHIFT = 4; enum ushort EXPBIAS = 0x3FE0; enum uint EXPMASK_INT = 0x7FF0_0000; enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only enum realFormat = RealFormat.ieeeDouble; version(LittleEndian) { enum EXPPOS_SHORT = 3; enum SIGNPOS_BYTE = 7; } else { enum EXPPOS_SHORT = 0; enum SIGNPOS_BYTE = 0; } } else static if (T.sizeof == 12) { // Intel extended real80 rounded to double enum ushort EXPMASK = 0x7FFF; enum ushort EXPSHIFT = 0; enum ushort EXPBIAS = 0x3FFE; enum realFormat = RealFormat.ieeeExtended53; version(LittleEndian) { enum EXPPOS_SHORT = 4; enum SIGNPOS_BYTE = 9; } else { enum EXPPOS_SHORT = 0; enum SIGNPOS_BYTE = 0; } } else static assert(false, "No traits support for " ~ T.stringof); } else static if (T.mant_dig == 64) { // Intel extended real80 enum ushort EXPMASK = 0x7FFF; enum ushort EXPSHIFT = 0; enum ushort EXPBIAS = 0x3FFE; enum realFormat = RealFormat.ieeeExtended; version(LittleEndian) { enum EXPPOS_SHORT = 4; enum SIGNPOS_BYTE = 9; } else { enum EXPPOS_SHORT = 0; enum SIGNPOS_BYTE = 0; } } else static if (T.mant_dig == 113) { // Quadruple precision float enum ushort EXPMASK = 0x7FFF; enum ushort EXPSHIFT = 0; enum ushort EXPBIAS = 0x3FFF; enum realFormat = RealFormat.ieeeQuadruple; version(LittleEndian) { enum EXPPOS_SHORT = 7; enum SIGNPOS_BYTE = 15; } else { enum EXPPOS_SHORT = 0; enum SIGNPOS_BYTE = 0; } } else static if (T.mant_dig == 106) { // IBM Extended doubledouble enum ushort EXPMASK = 0x7FF0; enum ushort EXPSHIFT = 4; enum realFormat = RealFormat.ibmExtended; // the exponent byte is not unique version(LittleEndian) { enum EXPPOS_SHORT = 7; // [3] is also an exp short enum SIGNPOS_BYTE = 15; } else { enum EXPPOS_SHORT = 0; // [4] is also an exp short enum SIGNPOS_BYTE = 0; } } else static assert(false, "No traits support for " ~ T.stringof); } // These apply to all floating-point types version(LittleEndian) { enum MANTISSA_LSB = 0; enum MANTISSA_MSB = 1; } else { enum MANTISSA_LSB = 1; enum MANTISSA_MSB = 0; } // Common code for math implementations. // Helper for floor/ceil T floorImpl(T)(const T x) @trusted pure nothrow @nogc { alias F = floatTraits!(T); // Take care not to trigger library calls from the compiler, // while ensuring that we don't get defeated by some optimizers. union floatBits { T rv; ushort[T.sizeof/2] vu; } floatBits y = void; y.rv = x; // Find the exponent (power of 2) static if (F.realFormat == RealFormat.ieeeSingle) { int exp = ((y.vu[F.EXPPOS_SHORT] >> 7) & 0xff) - 0x7f; version (LittleEndian) int pos = 0; else int pos = 3; } else static if (F.realFormat == RealFormat.ieeeDouble) { int exp = ((y.vu[F.EXPPOS_SHORT] >> 4) & 0x7ff) - 0x3ff; version (LittleEndian) int pos = 0; else int pos = 3; } else static if (F.realFormat == RealFormat.ieeeExtended) { int exp = (y.vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff; version (LittleEndian) int pos = 0; else int pos = 4; } else static if (F.realFormat == RealFormat.ieeeQuadruple) { int exp = (y.vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff; version (LittleEndian) int pos = 0; else int pos = 7; } else static assert(false, "Not implemented for this architecture"); if (exp < 0) { if (x < 0.0) return -1.0; else return 0.0; } exp = (T.mant_dig - 1) - exp; // Zero 16 bits at a time. while (exp >= 16) { version (LittleEndian) y.vu[pos++] = 0; else y.vu[pos--] = 0; exp -= 16; } // Clear the remaining bits. if (exp > 0) y.vu[pos] &= 0xffff ^ ((1 << exp) - 1); if ((x < 0.0) && (x != y.rv)) y.rv -= 1.0; return y.rv; } public: // Values obtained from Wolfram Alpha. 116 bits ought to be enough for anybody. // Wolfram Alpha LLC. 2011. Wolfram|Alpha. http://www.wolframalpha.com/input/?i=e+in+base+16 (access July 6, 2011). enum real E = 0x1.5bf0a8b1457695355fb8ac404e7a8p+1L; /** e = 2.718281... */ enum real LOG2T = 0x1.a934f0979a3715fc9257edfe9b5fbp+1L; /** $(SUB log, 2)10 = 3.321928... */ enum real LOG2E = 0x1.71547652b82fe1777d0ffda0d23a8p+0L; /** $(SUB log, 2)e = 1.442695... */ enum real LOG2 = 0x1.34413509f79fef311f12b35816f92p-2L; /** $(SUB log, 10)2 = 0.301029... */ enum real LOG10E = 0x1.bcb7b1526e50e32a6ab7555f5a67cp-2L; /** $(SUB log, 10)e = 0.434294... */ enum real LN2 = 0x1.62e42fefa39ef35793c7673007e5fp-1L; /** ln 2 = 0.693147... */ enum real LN10 = 0x1.26bb1bbb5551582dd4adac5705a61p+1L; /** ln 10 = 2.302585... */ enum real PI = 0x1.921fb54442d18469898cc51701b84p+1L; /** $(_PI) = 3.141592... */ enum real PI_2 = PI/2; /** $(PI) / 2 = 1.570796... */ enum real PI_4 = PI/4; /** $(PI) / 4 = 0.785398... */ enum real M_1_PI = 0x1.45f306dc9c882a53f84eafa3ea69cp-2L; /** 1 / $(PI) = 0.318309... */ enum real M_2_PI = 2*M_1_PI; /** 2 / $(PI) = 0.636619... */ enum real M_2_SQRTPI = 0x1.20dd750429b6d11ae3a914fed7fd8p+0L; /** 2 / $(SQRT)$(PI) = 1.128379... */ enum real SQRT2 = 0x1.6a09e667f3bcc908b2fb1366ea958p+0L; /** $(SQRT)2 = 1.414213... */ enum real SQRT1_2 = SQRT2/2; /** $(SQRT)$(HALF) = 0.707106... */ // Note: Make sure the magic numbers in compiler backend for x87 match these. /*********************************** * Calculates the absolute value of a number * * Params: * Num = (template parameter) type of number * x = real number value * z = complex number value * y = imaginary number value * * Returns: * The absolute value of the number. If floating-point or integral, * the return type will be the same as the input; if complex or * imaginary, the returned value will be the corresponding floating * point type. * * For complex numbers, abs(z) = sqrt( $(POWER z.re, 2) + $(POWER z.im, 2) ) * = hypot(z.re, z.im). */ Num abs(Num)(Num x) @safe pure nothrow if (is(typeof(Num.init >= 0)) && is(typeof(-Num.init)) && !(is(Num* : const(ifloat*)) || is(Num* : const(idouble*)) || is(Num* : const(ireal*)))) { static if (isFloatingPoint!(Num)) return fabs(x); else return x>=0 ? x : -x; } /// ditto auto abs(Num)(Num z) @safe pure nothrow @nogc if (is(Num* : const(cfloat*)) || is(Num* : const(cdouble*)) || is(Num* : const(creal*))) { return hypot(z.re, z.im); } /// ditto auto abs(Num)(Num y) @safe pure nothrow @nogc if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*)) || is(Num* : const(ireal*))) { return fabs(y.im); } /// ditto @safe pure nothrow @nogc unittest { assert(isIdentical(abs(-0.0L), 0.0L)); assert(isNaN(abs(real.nan))); assert(abs(-real.infinity) == real.infinity); assert(abs(-3.2Li) == 3.2L); assert(abs(71.6Li) == 71.6L); assert(abs(-56) == 56); assert(abs(2321312L) == 2321312L); assert(abs(-1L+1i) == sqrt(2.0L)); } @safe pure nothrow @nogc unittest { import std.meta : AliasSeq; foreach (T; AliasSeq!(float, double, real)) { T f = 3; assert(abs(f) == f); assert(abs(-f) == f); } foreach (T; AliasSeq!(cfloat, cdouble, creal)) { T f = -12+3i; assert(abs(f) == hypot(f.re, f.im)); assert(abs(-f) == hypot(f.re, f.im)); } } /*********************************** * Complex conjugate * * conj(x + iy) = x - iy * * Note that z * conj(z) = $(POWER z.re, 2) - $(POWER z.im, 2) * is always a real number */ auto conj(Num)(Num z) @safe pure nothrow @nogc if (is(Num* : const(cfloat*)) || is(Num* : const(cdouble*)) || is(Num* : const(creal*))) { //FIXME //Issue 14206 static if(is(Num* : const(cdouble*))) return cast(cdouble) conj(cast(creal)z); else return z.re - z.im*1fi; } /** ditto */ auto conj(Num)(Num y) @safe pure nothrow @nogc if (is(Num* : const(ifloat*)) || is(Num* : const(idouble*)) || is(Num* : const(ireal*))) { return -y; } /// @safe pure nothrow @nogc unittest { creal c = 7 + 3Li; assert(conj(c) == 7-3Li); ireal z = -3.2Li; assert(conj(z) == -z); } //Issue 14206 @safe pure nothrow @nogc unittest { cdouble c = 7 + 3i; assert(conj(c) == 7-3i); idouble z = -3.2i; assert(conj(z) == -z); } //Issue 14206 @safe pure nothrow @nogc unittest { cfloat c = 7f + 3fi; assert(conj(c) == 7f-3fi); ifloat z = -3.2fi; assert(conj(z) == -z); } /*********************************** * Returns cosine of x. x is in radians. * * $(TABLE_SV * $(TR $(TH x) $(TH cos(x)) $(TH invalid?)) * $(TR $(TD $(NAN)) $(TD $(NAN)) $(TD yes) ) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(NAN)) $(TD yes) ) * ) * Bugs: * Results are undefined if |x| >= $(POWER 2,64). */ version(LDC) { real cos(real x) @safe pure nothrow @nogc { return llvm_cos(x); } ///ditto double cos(double x) @safe pure nothrow @nogc { return llvm_cos(x); } ///ditto float cos(float x) @safe pure nothrow @nogc { return llvm_cos(x); } } else { real cos(real x) @safe pure nothrow @nogc { pragma(inline, true); return core.math.cos(x); } //FIXME ///ditto double cos(double x) @safe pure nothrow @nogc { return cos(cast(real)x); } //FIXME ///ditto float cos(float x) @safe pure nothrow @nogc { return cos(cast(real)x); } } unittest { real function(real) pcos = &cos; assert(pcos != null); } /*********************************** * Returns $(WEB en.wikipedia.org/wiki/Sine, sine) of x. x is in $(WEB en.wikipedia.org/wiki/Radian, radians). * * $(TABLE_SV * $(TH3 x , sin(x) , invalid?) * $(TD3 $(NAN) , $(NAN) , yes ) * $(TD3 $(PLUSMN)0.0, $(PLUSMN)0.0, no ) * $(TD3 $(PLUSMNINF), $(NAN) , yes ) * ) * * Params: * x = angle in radians (not degrees) * Returns: * sine of x * See_Also: * $(MYREF cos), $(MYREF tan), $(MYREF asin) * Bugs: * Results are undefined if |x| >= $(POWER 2,64). */ version(LDC) { real sin(real x) @safe pure nothrow @nogc { return llvm_sin(x); } ///ditto double sin(double x) @safe pure nothrow @nogc { return llvm_sin(x); } ///ditto float sin(float x) @safe pure nothrow @nogc { return llvm_sin(x); } } else { real sin(real x) @safe pure nothrow @nogc { pragma(inline, true); return core.math.sin(x); } //FIXME ///ditto double sin(double x) @safe pure nothrow @nogc { return sin(cast(real)x); } //FIXME ///ditto float sin(float x) @safe pure nothrow @nogc { return sin(cast(real)x); } } /// unittest { import std.math : sin, PI; import std.stdio : writefln; void someFunc() { real x = 30.0; auto result = sin(x * (PI / 180)); // convert degrees to radians writefln("The sine of %s degrees is %s", x, result); } } unittest { real function(real) psin = &sin; assert(psin != null); } /*********************************** * Returns sine for complex and imaginary arguments. * * sin(z) = sin(z.re)*cosh(z.im) + cos(z.re)*sinh(z.im)i * * If both sin($(THETA)) and cos($(THETA)) are required, * it is most efficient to use expi($(THETA)). */ creal sin(creal z) @safe pure nothrow @nogc { creal cs = expi(z.re); creal csh = coshisinh(z.im); return cs.im * csh.re + cs.re * csh.im * 1i; } /** ditto */ ireal sin(ireal y) @safe pure nothrow @nogc { return cosh(y.im)*1i; } /// @safe pure nothrow @nogc unittest { assert(sin(0.0+0.0i) == 0.0); assert(sin(2.0+0.0i) == sin(2.0L) ); } /*********************************** * cosine, complex and imaginary * * cos(z) = cos(z.re)*cosh(z.im) - sin(z.re)*sinh(z.im)i */ creal cos(creal z) @safe pure nothrow @nogc { creal cs = expi(z.re); creal csh = coshisinh(z.im); return cs.re * csh.re - cs.im * csh.im * 1i; } /** ditto */ real cos(ireal y) @safe pure nothrow @nogc { return cosh(y.im); } /// @safe pure nothrow @nogc unittest { assert(cos(0.0+0.0i)==1.0); assert(cos(1.3L+0.0i)==cos(1.3L)); assert(cos(5.2Li)== cosh(5.2L)); } /**************************************************************************** * Returns tangent of x. x is in radians. * * $(TABLE_SV * $(TR $(TH x) $(TH tan(x)) $(TH invalid?)) * $(TR $(TD $(NAN)) $(TD $(NAN)) $(TD yes)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no)) * $(TR $(TD $(PLUSMNINF)) $(TD $(NAN)) $(TD yes)) * ) */ real tan(real x) @trusted pure nothrow @nogc { version (LDC) { return core.stdc.math.tanl(x); } else version(InlineAsm_X86_X87) { asm pure nothrow @nogc { fld x[EBP] ; // load theta fxam ; // test for oddball values fstsw AX ; sahf ; jc trigerr ; // x is NAN, infinity, or empty // 387's can handle subnormals SC18: fptan ; fstp ST(0) ; // dump X, which is always 1 fstsw AX ; sahf ; jnp Lret ; // C2 = 1 (x is out of range) // Do argument reduction to bring x into range fldpi ; fxch ; SC17: fprem1 ; fstsw AX ; sahf ; jp SC17 ; fstp ST(1) ; // remove pi from stack jmp SC18 ; trigerr: jnp Lret ; // if theta is NAN, return theta fstp ST(0) ; // dump theta } return real.nan; Lret: {} } else version(InlineAsm_X86_64_X87) { version (Win64) { asm pure nothrow @nogc { fld real ptr [RCX] ; // load theta } } else { asm pure nothrow @nogc { fld x[RBP] ; // load theta } } asm pure nothrow @nogc { fxam ; // test for oddball values fstsw AX ; test AH,1 ; jnz trigerr ; // x is NAN, infinity, or empty // 387's can handle subnormals SC18: fptan ; fstp ST(0) ; // dump X, which is always 1 fstsw AX ; test AH,4 ; jz Lret ; // C2 = 1 (x is out of range) // Do argument reduction to bring x into range fldpi ; fxch ; SC17: fprem1 ; fstsw AX ; test AH,4 ; jnz SC17 ; fstp ST(1) ; // remove pi from stack jmp SC18 ; trigerr: test AH,4 ; jz Lret ; // if theta is NAN, return theta fstp ST(0) ; // dump theta } return real.nan; Lret: {} } else { // Coefficients for tan(x) static immutable real[3] P = [ -1.7956525197648487798769E7L, 1.1535166483858741613983E6L, -1.3093693918138377764608E4L, ]; static immutable real[5] Q = [ -5.3869575592945462988123E7L, 2.5008380182335791583922E7L, -1.3208923444021096744731E6L, 1.3681296347069295467845E4L, 1.0000000000000000000000E0L, ]; // PI/4 split into three parts. enum real P1 = 7.853981554508209228515625E-1L; enum real P2 = 7.946627356147928367136046290398E-9L; enum real P3 = 3.061616997868382943065164830688E-17L; // Special cases. if (x == 0.0 || isNaN(x)) return x; if (isInfinity(x)) return real.nan; // Make argument positive but save the sign. bool sign = false; if (signbit(x)) { sign = true; x = -x; } // Compute x mod PI/4. real y = floor(x / PI_4); // Strip high bits of integer part. real z = ldexp(y, -4); // Compute y - 16 * (y / 16). z = y - ldexp(floor(z), 4); // Integer and fraction part modulo one octant. int j = cast(int)(z); // Map zeros and singularities to origin. if (j & 1) { j += 1; y += 1.0; } z = ((x - y * P1) - y * P2) - y * P3; real zz = z * z; if (zz > 1.0e-20L) y = z + z * (zz * poly(zz, P) / poly(zz, Q)); else y = z; if (j & 2) y = -1.0 / y; return (sign) ? -y : y; } } @safe nothrow @nogc unittest { static real[2][] vals = // angle,tan [ [ 0, 0], [ .5, .5463024898], [ 1, 1.557407725], [ 1.5, 14.10141995], [ 2, -2.185039863], [ 2.5,-.7470222972], [ 3, -.1425465431], [ 3.5, .3745856402], [ 4, 1.157821282], [ 4.5, 4.637332055], [ 5, -3.380515006], [ 5.5,-.9955840522], [ 6, -.2910061914], [ 6.5, .2202772003], [ 10, .6483608275], // special angles [ PI_4, 1], //[ PI_2, real.infinity], // PI_2 is not _exactly_ pi/2. [ 3*PI_4, -1], [ PI, 0], [ 5*PI_4, 1], //[ 3*PI_2, -real.infinity], [ 7*PI_4, -1], [ 2*PI, 0], ]; int i; for (i = 0; i < vals.length; i++) { real x = vals[i][0]; real r = vals[i][1]; real t = tan(x); //printf("tan(%Lg) = %Lg, should be %Lg\n", x, t, r); if (!isIdentical(r, t)) assert(fabs(r-t) <= .0000001); x = -x; r = -r; t = tan(x); //printf("tan(%Lg) = %Lg, should be %Lg\n", x, t, r); if (!isIdentical(r, t) && !(r!=r && t!=t)) assert(fabs(r-t) <= .0000001); } // overflow assert(isNaN(tan(real.infinity))); assert(isNaN(tan(-real.infinity))); // NaN propagation assert(isIdentical( tan(NaN(0x0123L)), NaN(0x0123L) )); } unittest { assert(equalsDigit(tan(PI / 3), std.math.sqrt(3.0), useDigits)); } /*************** * Calculates the arc cosine of x, * returning a value ranging from 0 to $(PI). * * $(TABLE_SV * $(TR $(TH x) $(TH acos(x)) $(TH invalid?)) * $(TR $(TD $(GT)1.0) $(TD $(NAN)) $(TD yes)) * $(TR $(TD $(LT)-1.0) $(TD $(NAN)) $(TD yes)) * $(TR $(TD $(NAN)) $(TD $(NAN)) $(TD yes)) * ) */ real acos(real x) @safe pure nothrow @nogc { return atan2(sqrt(1-x*x), x); } /// ditto double acos(double x) @safe pure nothrow @nogc { return acos(cast(real)x); } /// ditto float acos(float x) @safe pure nothrow @nogc { return acos(cast(real)x); } unittest { assert(equalsDigit(acos(0.5), std.math.PI / 3, useDigits)); } /*************** * Calculates the arc sine of x, * returning a value ranging from -$(PI)/2 to $(PI)/2. * * $(TABLE_SV * $(TR $(TH x) $(TH asin(x)) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no)) * $(TR $(TD $(GT)1.0) $(TD $(NAN)) $(TD yes)) * $(TR $(TD $(LT)-1.0) $(TD $(NAN)) $(TD yes)) * ) */ real asin(real x) @safe pure nothrow @nogc { return atan2(x, sqrt(1-x*x)); } /// ditto double asin(double x) @safe pure nothrow @nogc { return asin(cast(real)x); } /// ditto float asin(float x) @safe pure nothrow @nogc { return asin(cast(real)x); } unittest { assert(equalsDigit(asin(0.5), PI / 6, useDigits)); } /*************** * Calculates the arc tangent of x, * returning a value ranging from -$(PI)/2 to $(PI)/2. * * $(TABLE_SV * $(TR $(TH x) $(TH atan(x)) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no)) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(NAN)) $(TD yes)) * ) */ real atan(real x) @safe pure nothrow @nogc { version(InlineAsm_X86_Any_X87) { return atan2(x, 1.0L); } else { // Coefficients for atan(x) static immutable real[5] P = [ -5.0894116899623603312185E1L, -9.9988763777265819915721E1L, -6.3976888655834347413154E1L, -1.4683508633175792446076E1L, -8.6863818178092187535440E-1L, ]; static immutable real[6] Q = [ 1.5268235069887081006606E2L, 3.9157570175111990631099E2L, 3.6144079386152023162701E2L, 1.4399096122250781605352E2L, 2.2981886733594175366172E1L, 1.0000000000000000000000E0L, ]; // tan(PI/8) enum real TAN_PI_8 = 4.1421356237309504880169e-1L; // tan(3 * PI/8) enum real TAN3_PI_8 = 2.41421356237309504880169L; // Special cases. if (x == 0.0) return x; if (isInfinity(x)) return copysign(PI_2, x); // Make argument positive but save the sign. bool sign = false; if (signbit(x)) { sign = true; x = -x; } // Range reduction. real y; if (x > TAN3_PI_8) { y = PI_2; x = -(1.0 / x); } else if (x > TAN_PI_8) { y = PI_4; x = (x - 1.0)/(x + 1.0); } else y = 0.0; // Rational form in x^^2. real z = x * x; y = y + (poly(z, P) / poly(z, Q)) * z * x + x; return (sign) ? -y : y; } } /// ditto double atan(double x) @safe pure nothrow @nogc { return atan(cast(real)x); } /// ditto float atan(float x) @safe pure nothrow @nogc { return atan(cast(real)x); } unittest { assert(equalsDigit(atan(std.math.sqrt(3.0)), PI / 3, useDigits)); } /*************** * Calculates the arc tangent of y / x, * returning a value ranging from -$(PI) to $(PI). * * $(TABLE_SV * $(TR $(TH y) $(TH x) $(TH atan(y, x))) * $(TR $(TD $(NAN)) $(TD anything) $(TD $(NAN)) ) * $(TR $(TD anything) $(TD $(NAN)) $(TD $(NAN)) ) * $(TR $(TD $(PLUSMN)0.0) $(TD $(GT)0.0) $(TD $(PLUSMN)0.0) ) * $(TR $(TD $(PLUSMN)0.0) $(TD +0.0) $(TD $(PLUSMN)0.0) ) * $(TR $(TD $(PLUSMN)0.0) $(TD $(LT)0.0) $(TD $(PLUSMN)$(PI))) * $(TR $(TD $(PLUSMN)0.0) $(TD -0.0) $(TD $(PLUSMN)$(PI))) * $(TR $(TD $(GT)0.0) $(TD $(PLUSMN)0.0) $(TD $(PI)/2) ) * $(TR $(TD $(LT)0.0) $(TD $(PLUSMN)0.0) $(TD -$(PI)/2) ) * $(TR $(TD $(GT)0.0) $(TD $(INFIN)) $(TD $(PLUSMN)0.0) ) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD anything) $(TD $(PLUSMN)$(PI)/2)) * $(TR $(TD $(GT)0.0) $(TD -$(INFIN)) $(TD $(PLUSMN)$(PI)) ) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(INFIN)) $(TD $(PLUSMN)$(PI)/4)) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD -$(INFIN)) $(TD $(PLUSMN)3$(PI)/4)) * ) */ real atan2(real y, real x) @trusted pure nothrow @nogc { version(InlineAsm_X86_Any_X87) { version (Win64) { asm pure nothrow @nogc { naked; fld real ptr [RDX]; // y fld real ptr [RCX]; // x fpatan; ret; } } else { asm pure nothrow @nogc { fld y; fld x; fpatan; } } } else { // Special cases. if (isNaN(x) || isNaN(y)) return real.nan; if (y == 0.0) { if (x >= 0 && !signbit(x)) return copysign(0, y); else return copysign(PI, y); } if (x == 0.0) return copysign(PI_2, y); if (isInfinity(x)) { if (signbit(x)) { if (isInfinity(y)) return copysign(3*PI_4, y); else return copysign(PI, y); } else { if (isInfinity(y)) return copysign(PI_4, y); else return copysign(0.0, y); } } if (isInfinity(y)) return copysign(PI_2, y); // Call atan and determine the quadrant. real z = atan(y / x); if (signbit(x)) { if (signbit(y)) z = z - PI; else z = z + PI; } if (z == 0.0) return copysign(z, y); return z; } } /// ditto double atan2(double y, double x) @safe pure nothrow @nogc { return atan2(cast(real)y, cast(real)x); } /// ditto float atan2(float y, float x) @safe pure nothrow @nogc { return atan2(cast(real)y, cast(real)x); } unittest { assert(equalsDigit(atan2(1.0L, std.math.sqrt(3.0L)), PI / 6, useDigits)); } /*********************************** * Calculates the hyperbolic cosine of x. * * $(TABLE_SV * $(TR $(TH x) $(TH cosh(x)) $(TH invalid?)) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(PLUSMN)0.0) $(TD no) ) * ) */ real cosh(real x) @safe pure nothrow @nogc { // cosh = (exp(x)+exp(-x))/2. // The naive implementation works correctly. real y = exp(x); return (y + 1.0/y) * 0.5; } /// ditto double cosh(double x) @safe pure nothrow @nogc { return cosh(cast(real)x); } /// ditto float cosh(float x) @safe pure nothrow @nogc { return cosh(cast(real)x); } unittest { assert(equalsDigit(cosh(1.0), (E + 1.0 / E) / 2, useDigits)); } /*********************************** * Calculates the hyperbolic sine of x. * * $(TABLE_SV * $(TR $(TH x) $(TH sinh(x)) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no)) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(PLUSMN)$(INFIN)) $(TD no)) * ) */ real sinh(real x) @safe pure nothrow @nogc { // sinh(x) = (exp(x)-exp(-x))/2; // Very large arguments could cause an overflow, but // the maximum value of x for which exp(x) + exp(-x)) != exp(x) // is x = 0.5 * (real.mant_dig) * LN2. // = 22.1807 for real80. if (fabs(x) > real.mant_dig * LN2) { return copysign(0.5 * exp(fabs(x)), x); } real y = expm1(x); return 0.5 * y / (y+1) * (y+2); } /// ditto double sinh(double x) @safe pure nothrow @nogc { return sinh(cast(real)x); } /// ditto float sinh(float x) @safe pure nothrow @nogc { return sinh(cast(real)x); } unittest { assert(equalsDigit(sinh(1.0), (E - 1.0 / E) / 2, useDigits)); } /*********************************** * Calculates the hyperbolic tangent of x. * * $(TABLE_SV * $(TR $(TH x) $(TH tanh(x)) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no) ) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(PLUSMN)1.0) $(TD no)) * ) */ real tanh(real x) @safe pure nothrow @nogc { // tanh(x) = (exp(x) - exp(-x))/(exp(x)+exp(-x)) if (fabs(x) > real.mant_dig * LN2) { return copysign(1, x); } real y = expm1(2*x); return y / (y + 2); } /// ditto double tanh(double x) @safe pure nothrow @nogc { return tanh(cast(real)x); } /// ditto float tanh(float x) @safe pure nothrow @nogc { return tanh(cast(real)x); } unittest { assert(equalsDigit(tanh(1.0), sinh(1.0) / cosh(1.0), 15)); } package: /* Returns cosh(x) + I * sinh(x) * Only one call to exp() is performed. */ creal coshisinh(real x) @safe pure nothrow @nogc { // See comments for cosh, sinh. if (fabs(x) > real.mant_dig * LN2) { real y = exp(fabs(x)); return y * 0.5 + 0.5i * copysign(y, x); } else { real y = expm1(x); return (y + 1.0 + 1.0/(y + 1.0)) * 0.5 + 0.5i * y / (y+1) * (y+2); } } @safe pure nothrow @nogc unittest { creal c = coshisinh(3.0L); assert(c.re == cosh(3.0L)); assert(c.im == sinh(3.0L)); } public: /*********************************** * Calculates the inverse hyperbolic cosine of x. * * Mathematically, acosh(x) = log(x + sqrt( x*x - 1)) * * $(TABLE_DOMRG * $(DOMAIN 1..$(INFIN)) * $(RANGE 1..log(real.max), $(INFIN)) ) * $(TABLE_SV * $(SVH x, acosh(x) ) * $(SV $(NAN), $(NAN) ) * $(SV $(LT)1, $(NAN) ) * $(SV 1, 0 ) * $(SV +$(INFIN),+$(INFIN)) * ) */ real acosh(real x) @safe pure nothrow @nogc { if (x > 1/real.epsilon) return LN2 + log(x); else return log(x + sqrt(x*x - 1)); } /// ditto double acosh(double x) @safe pure nothrow @nogc { return acosh(cast(real)x); } /// ditto float acosh(float x) @safe pure nothrow @nogc { return acosh(cast(real)x); } unittest { assert(isNaN(acosh(0.9))); assert(isNaN(acosh(real.nan))); assert(acosh(1.0)==0.0); assert(acosh(real.infinity) == real.infinity); assert(isNaN(acosh(0.5))); assert(equalsDigit(acosh(cosh(3.0)), 3, useDigits)); } /*********************************** * Calculates the inverse hyperbolic sine of x. * * Mathematically, * --------------- * asinh(x) = log( x + sqrt( x*x + 1 )) // if x >= +0 * asinh(x) = -log(-x + sqrt( x*x + 1 )) // if x <= -0 * ------------- * * $(TABLE_SV * $(SVH x, asinh(x) ) * $(SV $(NAN), $(NAN) ) * $(SV $(PLUSMN)0, $(PLUSMN)0 ) * $(SV $(PLUSMN)$(INFIN),$(PLUSMN)$(INFIN)) * ) */ real asinh(real x) @safe pure nothrow @nogc { return (fabs(x) > 1 / real.epsilon) // beyond this point, x*x + 1 == x*x ? copysign(LN2 + log(fabs(x)), x) // sqrt(x*x + 1) == 1 + x * x / ( 1 + sqrt(x*x + 1) ) : copysign(log1p(fabs(x) + x*x / (1 + sqrt(x*x + 1)) ), x); } /// ditto double asinh(double x) @safe pure nothrow @nogc { return asinh(cast(real)x); } /// ditto float asinh(float x) @safe pure nothrow @nogc { return asinh(cast(real)x); } unittest { assert(isIdentical(asinh(0.0), 0.0)); assert(isIdentical(asinh(-0.0), -0.0)); assert(asinh(real.infinity) == real.infinity); assert(asinh(-real.infinity) == -real.infinity); assert(isNaN(asinh(real.nan))); assert(equalsDigit(asinh(sinh(3.0)), 3, useDigits)); } /*********************************** * Calculates the inverse hyperbolic tangent of x, * returning a value from ranging from -1 to 1. * * Mathematically, atanh(x) = log( (1+x)/(1-x) ) / 2 * * * $(TABLE_DOMRG * $(DOMAIN -$(INFIN)..$(INFIN)) * $(RANGE -1..1) ) * $(TABLE_SV * $(SVH x, acosh(x) ) * $(SV $(NAN), $(NAN) ) * $(SV $(PLUSMN)0, $(PLUSMN)0) * $(SV -$(INFIN), -0) * ) */ real atanh(real x) @safe pure nothrow @nogc { // log( (1+x)/(1-x) ) == log ( 1 + (2*x)/(1-x) ) return 0.5 * log1p( 2 * x / (1 - x) ); } /// ditto double atanh(double x) @safe pure nothrow @nogc { return atanh(cast(real)x); } /// ditto float atanh(float x) @safe pure nothrow @nogc { return atanh(cast(real)x); } unittest { assert(isIdentical(atanh(0.0), 0.0)); assert(isIdentical(atanh(-0.0),-0.0)); assert(isNaN(atanh(real.nan))); assert(isNaN(atanh(-real.infinity))); assert(atanh(0.0) == 0); assert(equalsDigit(atanh(tanh(0.5L)), 0.5, useDigits)); } /***************************************** * Returns x rounded to a long value using the current rounding mode. * If the integer value of x is * greater than long.max, the result is * indeterminate. */ version(LDC) long rndtol(real x) @nogc @trusted pure nothrow { return core.stdc.math.llroundl(x); } else long rndtol(real x) @nogc @safe pure nothrow { pragma(inline, true); return core.math.rndtol(x); } //FIXME ///ditto long rndtol(double x) @safe pure nothrow @nogc { return rndtol(cast(real)x); } //FIXME ///ditto long rndtol(float x) @safe pure nothrow @nogc { return rndtol(cast(real)x); } unittest { long function(real) prndtol = &rndtol; assert(prndtol != null); } /***************************************** * Returns x rounded to a long value using the FE_TONEAREST rounding mode. * If the integer value of x is * greater than long.max, the result is * indeterminate. */ extern (C) real rndtonl(real x); /*************************************** * Compute square root of x. * * $(TABLE_SV * $(TR $(TH x) $(TH sqrt(x)) $(TH invalid?)) * $(TR $(TD -0.0) $(TD -0.0) $(TD no)) * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD yes)) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no)) * ) */ version(LDC) { // http://llvm.org/docs/LangRef.html#llvm-sqrt-intrinsic // sqrt(x) when x is less than zero is undefined real sqrt(real x) @safe pure nothrow @nogc { return x < 0 ? NAN : llvm_sqrt(x); } ///ditto double sqrt(double x) @safe pure nothrow @nogc { return x < 0 ? NAN : llvm_sqrt(x); } ///ditto float sqrt(float x) @safe pure nothrow @nogc { return x < 0 ? NAN : llvm_sqrt(x); } } else { float sqrt(float x) @nogc @safe pure nothrow { pragma(inline, true); return core.math.sqrt(x); } /// ditto double sqrt(double x) @nogc @safe pure nothrow { pragma(inline, true); return core.math.sqrt(x); } /// ditto real sqrt(real x) @nogc @safe pure nothrow { pragma(inline, true); return core.math.sqrt(x); } } @safe pure nothrow @nogc unittest { //ctfe enum ZX80 = sqrt(7.0f); enum ZX81 = sqrt(7.0); enum ZX82 = sqrt(7.0L); assert(isNaN(sqrt(-1.0f))); assert(isNaN(sqrt(-1.0))); assert(isNaN(sqrt(-1.0L))); } unittest { float function(float) psqrtf = &sqrt; assert(psqrtf != null); double function(double) psqrtd = &sqrt; assert(psqrtd != null); real function(real) psqrtr = &sqrt; assert(psqrtr != null); } creal sqrt(creal z) @nogc @safe pure nothrow { creal c; real x,y,w,r; if (z == 0) { c = 0 + 0i; } else { real z_re = z.re; real z_im = z.im; x = fabs(z_re); y = fabs(z_im); if (x >= y) { r = y / x; w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r))); } else { r = x / y; w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r))); } if (z_re >= 0) { c = w + (z_im / (w + w)) * 1.0i; } else { if (z_im < 0) w = -w; c = z_im / (w + w) + w * 1.0i; } } return c; } /** * Calculates e$(SUPERSCRIPT x). * * $(TABLE_SV * $(TR $(TH x) $(TH e$(SUPERSCRIPT x)) ) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) ) * $(TR $(TD -$(INFIN)) $(TD +0.0) ) * $(TR $(TD $(NAN)) $(TD $(NAN)) ) * ) */ version(none) { // FIXME: Use of this LLVM intrinsic causes a unit test failure real exp(real x) @safe pure nothrow @nogc { return llvm_exp(x); } ///ditto double exp(double x) @safe pure nothrow @nogc { return llvm_exp(x); } ///ditto float exp(float x) @safe pure nothrow @nogc { return llvm_exp(x); } } else { real exp(real x) @trusted pure nothrow @nogc { version(InlineAsm_X86_X87) { // e^^x = 2^^(LOG2E*x) // (This is valid because the overflow & underflow limits for exp // and exp2 are so similar). return exp2(LOG2E*x); } else version(InlineAsm_X86_64_X87) { // e^^x = 2^^(LOG2E*x) // (This is valid because the overflow & underflow limits for exp // and exp2 are so similar). return exp2(LOG2E*x); } else { alias F = floatTraits!real; static if (F.realFormat == RealFormat.ieeeDouble) { // Coefficients for exp(x) static immutable real[3] P = [ 9.99999999999999999910E-1L, 3.02994407707441961300E-2L, 1.26177193074810590878E-4L, ]; static immutable real[4] Q = [ 2.00000000000000000009E0L, 2.27265548208155028766E-1L, 2.52448340349684104192E-3L, 3.00198505138664455042E-6L, ]; // C1 + C2 = LN2. enum real C1 = 6.93145751953125E-1; enum real C2 = 1.42860682030941723212E-6; // Overflow and Underflow limits. enum real OF = 7.09782712893383996732E2; // ln((1-2^-53) * 2^1024) enum real UF = -7.451332191019412076235E2; // ln(2^-1075) } else static if (F.realFormat == RealFormat.ieeeExtended) { // Coefficients for exp(x) static immutable real[3] P = [ 9.9999999999999999991025E-1L, 3.0299440770744196129956E-2L, 1.2617719307481059087798E-4L, ]; static immutable real[4] Q = [ 2.0000000000000000000897E0L, 2.2726554820815502876593E-1L, 2.5244834034968410419224E-3L, 3.0019850513866445504159E-6L, ]; // C1 + C2 = LN2. enum real C1 = 6.9314575195312500000000E-1L; enum real C2 = 1.4286068203094172321215E-6L; // Overflow and Underflow limits. enum real OF = 1.1356523406294143949492E4L; // ln((1-2^-64) * 2^16384) enum real UF = -1.13994985314888605586758E4L; // ln(2^-16446) } else static assert(0, "Not implemented for this architecture"); // Special cases. // FIXME: set IEEE flags accordingly if (isNaN(x)) return x; if (x > OF) return real.infinity; if (x < UF) return 0.0; // Express: e^^x = e^^g * 2^^n // = e^^g * e^^(n * LOG2E) // = e^^(g + n * LOG2E) int n = cast(int)floor(LOG2E * x + 0.5); x -= n * C1; x -= n * C2; // Rational approximation for exponential of the fractional part: // e^^x = 1 + 2x P(x^^2) / (Q(x^^2) - P(x^^2)) real xx = x * x; real px = x * poly(xx, P); x = px / (poly(xx, Q) - px); x = 1.0 + ldexp(x, 1); // Scale by power of 2. x = ldexp(x, n); return x; } } /// ditto double exp(double x) @safe pure nothrow @nogc { return exp(cast(real)x); } /// ditto float exp(float x) @safe pure nothrow @nogc { return exp(cast(real)x); } } unittest { assert(equalsDigit(exp(3.0L), E * E * E, useDigits)); } /** * Calculates the value of the natural logarithm base (e) * raised to the power of x, minus 1. * * For very small x, expm1(x) is more accurate * than exp(x)-1. * * $(TABLE_SV * $(TR $(TH x) $(TH e$(SUPERSCRIPT x)-1) ) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) ) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) ) * $(TR $(TD -$(INFIN)) $(TD -1.0) ) * $(TR $(TD $(NAN)) $(TD $(NAN)) ) * ) */ real expm1(real x) @trusted pure nothrow @nogc { version(InlineAsm_X86_X87) { enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4 asm pure nothrow @nogc { /* expm1() for x87 80-bit reals, IEEE754-2008 conformant. * Author: Don Clugston. * * expm1(x) = 2^^(rndint(y))* 2^^(y-rndint(y)) - 1 where y = LN2*x. * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^^(rndint(y)) * and 2ym1 = (2^^(y-rndint(y))-1). * If 2rndy < 0.5*real.epsilon, result is -1. * Implementation is otherwise the same as for exp2() */ naked; fld real ptr [ESP+4] ; // x mov AX, [ESP+4+8]; // AX = exponent and sign sub ESP, 12+8; // Create scratch space on the stack // [ESP,ESP+2] = scratchint // [ESP+4..+6, +8..+10, +10] = scratchreal // set scratchreal mantissa = 1.0 mov dword ptr [ESP+8], 0; mov dword ptr [ESP+8+4], 0x80000000; and AX, 0x7FFF; // drop sign bit cmp AX, 0x401D; // avoid InvalidException in fist jae L_extreme; fldl2e; fmulp ST(1), ST; // y = x*log2(e) fist dword ptr [ESP]; // scratchint = rndint(y) fisub dword ptr [ESP]; // y - rndint(y) // and now set scratchreal exponent mov EAX, [ESP]; add EAX, 0x3fff; jle short L_largenegative; cmp EAX,0x8000; jge short L_largepositive; mov [ESP+8+8],AX; f2xm1; // 2ym1 = 2^^(y-rndint(y)) -1 fld real ptr [ESP+8] ; // 2rndy = 2^^rndint(y) fmul ST(1), ST; // ST=2rndy, ST(1)=2rndy*2ym1 fld1; fsubp ST(1), ST; // ST = 2rndy-1, ST(1) = 2rndy * 2ym1 - 1 faddp ST(1), ST; // ST = 2rndy * 2ym1 + 2rndy - 1 add ESP,12+8; ret PARAMSIZE; L_extreme: // Extreme exponent. X is very large positive, very // large negative, infinity, or NaN. fxam; fstsw AX; test AX, 0x0400; // NaN_or_zero, but we already know x!=0 jz L_was_nan; // if x is NaN, returns x test AX, 0x0200; jnz L_largenegative; L_largepositive: // Set scratchreal = real.max. // squaring it will create infinity, and set overflow flag. mov word ptr [ESP+8+8], 0x7FFE; fstp ST(0); fld real ptr [ESP+8]; // load scratchreal fmul ST(0), ST; // square it, to create havoc! L_was_nan: add ESP,12+8; ret PARAMSIZE; L_largenegative: fstp ST(0); fld1; fchs; // return -1. Underflow flag is not set. add ESP,12+8; ret PARAMSIZE; } } else version(InlineAsm_X86_64_X87) { asm pure nothrow @nogc { naked; } version (Win64) { asm pure nothrow @nogc { fld real ptr [RCX]; // x mov AX,[RCX+8]; // AX = exponent and sign } } else { asm pure nothrow @nogc { fld real ptr [RSP+8]; // x mov AX,[RSP+8+8]; // AX = exponent and sign } } asm pure nothrow @nogc { /* expm1() for x87 80-bit reals, IEEE754-2008 conformant. * Author: Don Clugston. * * expm1(x) = 2^(rndint(y))* 2^(y-rndint(y)) - 1 where y = LN2*x. * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^(rndint(y)) * and 2ym1 = (2^(y-rndint(y))-1). * If 2rndy < 0.5*real.epsilon, result is -1. * Implementation is otherwise the same as for exp2() */ sub RSP, 24; // Create scratch space on the stack // [RSP,RSP+2] = scratchint // [RSP+4..+6, +8..+10, +10] = scratchreal // set scratchreal mantissa = 1.0 mov dword ptr [RSP+8], 0; mov dword ptr [RSP+8+4], 0x80000000; and AX, 0x7FFF; // drop sign bit cmp AX, 0x401D; // avoid InvalidException in fist jae L_extreme; fldl2e; fmul ; // y = x*log2(e) fist dword ptr [RSP]; // scratchint = rndint(y) fisub dword ptr [RSP]; // y - rndint(y) // and now set scratchreal exponent mov EAX, [RSP]; add EAX, 0x3fff; jle short L_largenegative; cmp EAX,0x8000; jge short L_largepositive; mov [RSP+8+8],AX; f2xm1; // 2^(y-rndint(y)) -1 fld real ptr [RSP+8] ; // 2^rndint(y) fmul ST(1), ST; fld1; fsubp ST(1), ST; fadd; add RSP,24; ret; L_extreme: // Extreme exponent. X is very large positive, very // large negative, infinity, or NaN. fxam; fstsw AX; test AX, 0x0400; // NaN_or_zero, but we already know x!=0 jz L_was_nan; // if x is NaN, returns x test AX, 0x0200; jnz L_largenegative; L_largepositive: // Set scratchreal = real.max. // squaring it will create infinity, and set overflow flag. mov word ptr [RSP+8+8], 0x7FFE; fstp ST(0); fld real ptr [RSP+8]; // load scratchreal fmul ST(0), ST; // square it, to create havoc! L_was_nan: add RSP,24; ret; L_largenegative: fstp ST(0); fld1; fchs; // return -1. Underflow flag is not set. add RSP,24; ret; } } else { // Coefficients for exp(x) - 1 static immutable real[5] P = [ -1.586135578666346600772998894928250240826E4L, 2.642771505685952966904660652518429479531E3L, -3.423199068835684263987132888286791620673E2L, 1.800826371455042224581246202420972737840E1L, -5.238523121205561042771939008061958820811E-1L, ]; static immutable real[6] Q = [ -9.516813471998079611319047060563358064497E4L, 3.964866271411091674556850458227710004570E4L, -7.207678383830091850230366618190187434796E3L, 7.206038318724600171970199625081491823079E2L, -4.002027679107076077238836622982900945173E1L, 1.000000000000000000000000000000000000000E0L, ]; // C1 + C2 = LN2. enum real C1 = 6.9314575195312500000000E-1L; enum real C2 = 1.4286068203094172321215E-6L; // Overflow and Underflow limits. enum real OF = 1.1356523406294143949492E4L; enum real UF = -4.5054566736396445112120088E1L; // Special cases. if (x > OF) return real.infinity; if (x == 0.0) return x; if (x < UF) return -1.0; // Express x = LN2 (n + remainder), remainder not exceeding 1/2. int n = cast(int)floor(0.5 + x / LN2); x -= n * C1; x -= n * C2; // Rational approximation: // exp(x) - 1 = x + 0.5 x^^2 + x^^3 P(x) / Q(x) real px = x * poly(x, P); real qx = poly(x, Q); real xx = x * x; qx = x + (0.5 * xx + xx * px / qx); // We have qx = exp(remainder LN2) - 1, so: // exp(x) - 1 = 2^^n (qx + 1) - 1 = 2^^n qx + 2^^n - 1. px = ldexp(1.0, n); x = px * qx + (px - 1.0); return x; } } /** * Calculates 2$(SUPERSCRIPT x). * * $(TABLE_SV * $(TR $(TH x) $(TH exp2(x)) ) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) ) * $(TR $(TD -$(INFIN)) $(TD +0.0) ) * $(TR $(TD $(NAN)) $(TD $(NAN)) ) * ) */ version(none) { // FIXME: Use of this LLVM intrinsic causes a unit test failure real exp2(real x) @safe pure nothrow @nogc { return llvm_exp2(x); } ///ditto double exp2(double x) @safe pure nothrow @nogc { return llvm_exp2(x); } ///ditto float exp2(float x) @safe pure nothrow @nogc { return llvm_exp2(x); } } else { real exp2(real x) @nogc @trusted pure nothrow { version(InlineAsm_X86_X87) { enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4 asm pure nothrow @nogc { /* exp2() for x87 80-bit reals, IEEE754-2008 conformant. * Author: Don Clugston. * * exp2(x) = 2^^(rndint(x))* 2^^(y-rndint(x)) * The trick for high performance is to avoid the fscale(28cycles on core2), * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction. * * We can do frndint by using fist. BUT we can't use it for huge numbers, * because it will set the Invalid Operation flag if overflow or NaN occurs. * Fortunately, whenever this happens the result would be zero or infinity. * * We can perform fscale by directly poking into the exponent. BUT this doesn't * work for the (very rare) cases where the result is subnormal. So we fall back * to the slow method in that case. */ naked; fld real ptr [ESP+4] ; // x mov AX, [ESP+4+8]; // AX = exponent and sign sub ESP, 12+8; // Create scratch space on the stack // [ESP,ESP+2] = scratchint // [ESP+4..+6, +8..+10, +10] = scratchreal // set scratchreal mantissa = 1.0 mov dword ptr [ESP+8], 0; mov dword ptr [ESP+8+4], 0x80000000; and AX, 0x7FFF; // drop sign bit cmp AX, 0x401D; // avoid InvalidException in fist jae L_extreme; fist dword ptr [ESP]; // scratchint = rndint(x) fisub dword ptr [ESP]; // x - rndint(x) // and now set scratchreal exponent mov EAX, [ESP]; add EAX, 0x3fff; jle short L_subnormal; cmp EAX,0x8000; jge short L_overflow; mov [ESP+8+8],AX; L_normal: f2xm1; fld1; faddp ST(1), ST; // 2^^(x-rndint(x)) fld real ptr [ESP+8] ; // 2^^rndint(x) add ESP,12+8; fmulp ST(1), ST; ret PARAMSIZE; L_subnormal: // Result will be subnormal. // In this rare case, the simple poking method doesn't work. // The speed doesn't matter, so use the slow fscale method. fild dword ptr [ESP]; // scratchint fld1; fscale; fstp real ptr [ESP+8]; // scratchreal = 2^^scratchint fstp ST(0); // drop scratchint jmp L_normal; L_extreme: // Extreme exponent. X is very large positive, very // large negative, infinity, or NaN. fxam; fstsw AX; test AX, 0x0400; // NaN_or_zero, but we already know x!=0 jz L_was_nan; // if x is NaN, returns x // set scratchreal = real.min_normal // squaring it will return 0, setting underflow flag mov word ptr [ESP+8+8], 1; test AX, 0x0200; jnz L_waslargenegative; L_overflow: // Set scratchreal = real.max. // squaring it will create infinity, and set overflow flag. mov word ptr [ESP+8+8], 0x7FFE; L_waslargenegative: fstp ST(0); fld real ptr [ESP+8]; // load scratchreal fmul ST(0), ST; // square it, to create havoc! L_was_nan: add ESP,12+8; ret PARAMSIZE; } } else version(InlineAsm_X86_64_X87) { asm pure nothrow @nogc { naked; } version (Win64) { asm pure nothrow @nogc { fld real ptr [RCX]; // x mov AX,[RCX+8]; // AX = exponent and sign } } else { asm pure nothrow @nogc { fld real ptr [RSP+8]; // x mov AX,[RSP+8+8]; // AX = exponent and sign } } asm pure nothrow @nogc { /* exp2() for x87 80-bit reals, IEEE754-2008 conformant. * Author: Don Clugston. * * exp2(x) = 2^(rndint(x))* 2^(y-rndint(x)) * The trick for high performance is to avoid the fscale(28cycles on core2), * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction. * * We can do frndint by using fist. BUT we can't use it for huge numbers, * because it will set the Invalid Operation flag is overflow or NaN occurs. * Fortunately, whenever this happens the result would be zero or infinity. * * We can perform fscale by directly poking into the exponent. BUT this doesn't * work for the (very rare) cases where the result is subnormal. So we fall back * to the slow method in that case. */ sub RSP, 24; // Create scratch space on the stack // [RSP,RSP+2] = scratchint // [RSP+4..+6, +8..+10, +10] = scratchreal // set scratchreal mantissa = 1.0 mov dword ptr [RSP+8], 0; mov dword ptr [RSP+8+4], 0x80000000; and AX, 0x7FFF; // drop sign bit cmp AX, 0x401D; // avoid InvalidException in fist jae L_extreme; fist dword ptr [RSP]; // scratchint = rndint(x) fisub dword ptr [RSP]; // x - rndint(x) // and now set scratchreal exponent mov EAX, [RSP]; add EAX, 0x3fff; jle short L_subnormal; cmp EAX,0x8000; jge short L_overflow; mov [RSP+8+8],AX; L_normal: f2xm1; fld1; fadd; // 2^(x-rndint(x)) fld real ptr [RSP+8] ; // 2^rndint(x) add RSP,24; fmulp ST(1), ST; ret; L_subnormal: // Result will be subnormal. // In this rare case, the simple poking method doesn't work. // The speed doesn't matter, so use the slow fscale method. fild dword ptr [RSP]; // scratchint fld1; fscale; fstp real ptr [RSP+8]; // scratchreal = 2^scratchint fstp ST(0); // drop scratchint jmp L_normal; L_extreme: // Extreme exponent. X is very large positive, very // large negative, infinity, or NaN. fxam; fstsw AX; test AX, 0x0400; // NaN_or_zero, but we already know x!=0 jz L_was_nan; // if x is NaN, returns x // set scratchreal = real.min // squaring it will return 0, setting underflow flag mov word ptr [RSP+8+8], 1; test AX, 0x0200; jnz L_waslargenegative; L_overflow: // Set scratchreal = real.max. // squaring it will create infinity, and set overflow flag. mov word ptr [RSP+8+8], 0x7FFE; L_waslargenegative: fstp ST(0); fld real ptr [RSP+8]; // load scratchreal fmul ST(0), ST; // square it, to create havoc! L_was_nan: add RSP,24; ret; } } else { // Coefficients for exp2(x) static immutable real[3] P = [ 2.0803843631901852422887E6L, 3.0286971917562792508623E4L, 6.0614853552242266094567E1L, ]; static immutable real[4] Q = [ 6.0027204078348487957118E6L, 3.2772515434906797273099E5L, 1.7492876999891839021063E3L, 1.0000000000000000000000E0L, ]; // Overflow and Underflow limits. enum real OF = 16384.0L; enum real UF = -16382.0L; // Special cases. if (isNaN(x)) return x; if (x > OF) return real.infinity; if (x < UF) return 0.0; // Separate into integer and fractional parts. int n = cast(int)floor(x + 0.5); x -= n; // Rational approximation: // exp2(x) = 1.0 + 2x P(x^^2) / (Q(x^^2) - P(x^^2)) real xx = x * x; real px = x * poly(xx, P); x = px / (poly(xx, Q) - px); x = 1.0 + ldexp(x, 1); // Scale by power of 2. x = ldexp(x, n); return x; } } } /// unittest { assert(feqrel(exp2(0.5L), SQRT2) >= real.mant_dig -1); assert(exp2(8.0L) == 256.0); assert(exp2(-9.0L)== 1.0L/512.0); } unittest { version(CRuntime_Microsoft) {} else // aexp2/exp2f/exp2l not implemented { assert( core.stdc.math.exp2f(0.0f) == 1 ); assert( core.stdc.math.exp2 (0.0) == 1 ); assert( core.stdc.math.exp2l(0.0L) == 1 ); } } unittest { FloatingPointControl ctrl; if(FloatingPointControl.hasExceptionTraps) ctrl.disableExceptions(FloatingPointControl.allExceptions); ctrl.rounding = FloatingPointControl.roundToNearest; static if (real.mant_dig == 64) // 80-bit reals { static immutable real[2][] exptestpoints = [ // x exp(x) [ 1.0L, E ], [ 0.5L, 0x1.a61298e1e069bc97p+0L ], [ 3.0L, E*E*E ], [ 0x1.1p+13L, 0x1.29aeffefc8ec645p+12557L ], // near overflow [ 0x1.7p+13L, real.infinity ], // close overflow [ 0x1p+80L, real.infinity ], // far overflow [ real.infinity, real.infinity ], [-0x1.18p+13L, 0x1.5e4bf54b4806db9p-12927L ], // near underflow [-0x1.625p+13L, 0x1.a6bd68a39d11f35cp-16358L ], // ditto [-0x1.62dafp+13L, 0x1.96c53d30277021dp-16383L ], // near underflow - subnormal [-0x1.643p+13L, 0x1p-16444L ], // ditto [-0x1.645p+13L, 0 ], // close underflow [-0x1p+30L, 0 ], // far underflow ]; } else static if (real.mant_dig == 53) // 64-bit reals { static immutable real[2][] exptestpoints = [ // x, exp(x) [ 1.0L, E ], [ 0.5L, 0x1.a61298e1e069cp+0L ], [ 3.0L, E*E*E ], [ 0x1.6p+9L, 0x1.93bf4ec282efbp+1015L ], // near overflow [ 0x1.7p+9L, real.infinity ], // close overflow [ 0x1p+80L, real.infinity ], // far overflow [ real.infinity, real.infinity ], [-0x1.6p+9L, 0x1.44a3824e5285fp-1016L ], // near underflow [-0x1.64p+9L, 0x0.06f84920bb2d4p-1022L ], // near underflow - subnormal [-0x1.743p+9L, 0x0.0000000000001p-1022L ], // ditto [-0x1.8p+9L, 0 ], // close underflow [-0x1p30L, 0 ], // far underflow ]; } else static assert(0, "No exp() tests for real type!"); const minEqualMantissaBits = real.mant_dig - 2; real x; IeeeFlags f; foreach (ref pair; exptestpoints) { resetIeeeFlags(); x = exp(pair[0]); f = ieeeFlags; assert(feqrel(x, pair[1]) >= minEqualMantissaBits); version (IeeeFlagsSupport) { // LDC specific: only test over-/underflow bits if real is 80 bits; // neither the official non-asm D implementation nor the llvm.exp.f64 // intrinsic on Win64 (and probably other targets) set these bits version (LDC) static if (real.mant_dig == 64) { // Check the overflow bit if (x == real.infinity) { // don't care about the overflow bit if input was inf // (e.g., the LLVM intrinsic doesn't set it on Linux x86_64) assert(pair[0] == real.infinity || f.overflow); } else assert(!f.overflow); // Check the underflow bit assert(f.underflow == (fabs(x) < real.min_normal)); } // Invalid and div by zero shouldn't be affected. assert(!f.invalid); assert(!f.divByZero); } } // Ideally, exp(0) would not set the inexact flag. // Unfortunately, fldl2e sets it! // So it's not realistic to avoid setting it. assert(exp(0.0L) == 1.0); // NaN propagation. Doesn't set flags, bcos was already NaN. resetIeeeFlags(); x = exp(real.nan); f = ieeeFlags; assert(isIdentical(abs(x), real.nan)); assert(f.flags == 0); resetIeeeFlags(); x = exp(-real.nan); f = ieeeFlags; assert(isIdentical(abs(x), real.nan)); assert(f.flags == 0); x = exp(NaN(0x123)); assert(isIdentical(x, NaN(0x123))); // High resolution test assert(exp(0.5L) == 0x1.A612_98E1_E069_BC97_2DFE_FAB6D_33Fp+0L); } /** * Calculate cos(y) + i sin(y). * * On many CPUs (such as x86), this is a very efficient operation; * almost twice as fast as calculating sin(y) and cos(y) separately, * and is the preferred method when both are required. */ creal expi(real y) @trusted pure nothrow @nogc { version(LDC) { // LDC-specific: don't swap x87 registers for result version(none) // Was InlineAsm_X86_Any_X87 but this causes assertion failures { return __asm!creal("fsincos", "={st},={st(1)},{st}", y); } else { return cos(y) + sin(y)*1i; } } else { version(InlineAsm_X86_Any_X87) { version (Win64) { asm pure nothrow @nogc { naked; fld real ptr [ECX]; fsincos; fxch ST(1), ST(0); ret; } } else { asm pure nothrow @nogc { fld y; fsincos; fxch ST(1), ST(0); } } } else { return cos(y) + sin(y)*1i; } } } /// @safe pure nothrow @nogc unittest { assert(expi(1.3e5L) == cos(1.3e5L) + sin(1.3e5L) * 1i); assert(expi(0.0L) == 1L + 0.0Li); } /********************************************************************* * Separate floating point value into significand and exponent. * * Returns: * Calculate and return $(I x) and $(I exp) such that * value =$(I x)*2$(SUPERSCRIPT exp) and * .5 $(LT)= |$(I x)| $(LT) 1.0 * * $(I x) has same sign as value. * * $(TABLE_SV * $(TR $(TH value) $(TH returns) $(TH exp)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD 0)) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD int.max)) * $(TR $(TD -$(INFIN)) $(TD -$(INFIN)) $(TD int.min)) * $(TR $(TD $(PLUSMN)$(NAN)) $(TD $(PLUSMN)$(NAN)) $(TD int.min)) * ) */ T frexp(T)(const T value, out int exp) @trusted pure nothrow @nogc if(isFloatingPoint!T) { Unqual!T vf = value; ushort* vu = cast(ushort*)&vf; static if(is(Unqual!T == float)) int* vi = cast(int*)&vf; else long* vl = cast(long*)&vf; int ex; alias F = floatTraits!T; ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; static if (F.realFormat == RealFormat.ieeeExtended) { if (ex) { // If exponent is non-zero if (ex == F.EXPMASK) // infinity or NaN { if (*vl & 0x7FFF_FFFF_FFFF_FFFF) // NaN { *vl |= 0xC000_0000_0000_0000; // convert NaNS to NaNQ exp = int.min; } else if (vu[F.EXPPOS_SHORT] & 0x8000) // negative infinity exp = int.min; else // positive infinity exp = int.max; } else { exp = ex - F.EXPBIAS; vu[F.EXPPOS_SHORT] = (0x8000 & vu[F.EXPPOS_SHORT]) | 0x3FFE; } } else if (!*vl) { // vf is +-0.0 exp = 0; } else { // subnormal vf *= F.RECIP_EPSILON; ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; exp = ex - F.EXPBIAS - T.mant_dig + 1; vu[F.EXPPOS_SHORT] = (0x8000 & vu[F.EXPPOS_SHORT]) | 0x3FFE; } return vf; } else static if (F.realFormat == RealFormat.ieeeQuadruple) { if (ex) // If exponent is non-zero { if (ex == F.EXPMASK) { // infinity or NaN if (vl[MANTISSA_LSB] | ( vl[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) // NaN { // convert NaNS to NaNQ vl[MANTISSA_MSB] |= 0x0000_8000_0000_0000; exp = int.min; } else if (vu[F.EXPPOS_SHORT] & 0x8000) // negative infinity exp = int.min; else // positive infinity exp = int.max; } else { exp = ex - F.EXPBIAS; vu[F.EXPPOS_SHORT] = cast(ushort)((0x8000 & vu[F.EXPPOS_SHORT]) | 0x3FFE); } } else if ((vl[MANTISSA_LSB] |(vl[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) == 0) { // vf is +-0.0 exp = 0; } else { // subnormal vf *= F.RECIP_EPSILON; ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; exp = ex - F.EXPBIAS - T.mant_dig + 1; vu[F.EXPPOS_SHORT] = cast(ushort)((0x8000 & vu[F.EXPPOS_SHORT]) | 0x3FFE); } return vf; } else static if (F.realFormat == RealFormat.ieeeDouble) { if (ex) // If exponent is non-zero { if (ex == F.EXPMASK) // infinity or NaN { if (*vl == 0x7FF0_0000_0000_0000) // positive infinity { exp = int.max; } else if (*vl == 0xFFF0_0000_0000_0000) // negative infinity exp = int.min; else { // NaN *vl |= 0x0008_0000_0000_0000; // convert NaNS to NaNQ exp = int.min; } } else { exp = (ex - F.EXPBIAS) >> 4; vu[F.EXPPOS_SHORT] = cast(ushort)((0x800F & vu[F.EXPPOS_SHORT]) | 0x3FE0); } } else if (!(*vl & 0x7FFF_FFFF_FFFF_FFFF)) { // vf is +-0.0 exp = 0; } else { // subnormal vf *= F.RECIP_EPSILON; ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; exp = ((ex - F.EXPBIAS) >> 4) - T.mant_dig + 1; vu[F.EXPPOS_SHORT] = cast(ushort)((0x8000 & vu[F.EXPPOS_SHORT]) | 0x3FE0); } return vf; } else static if (F.realFormat == RealFormat.ieeeSingle) { if (ex) // If exponent is non-zero { if (ex == F.EXPMASK) // infinity or NaN { if (*vi == 0x7F80_0000) // positive infinity { exp = int.max; } else if (*vi == 0xFF80_0000) // negative infinity exp = int.min; else { // NaN *vi |= 0x0040_0000; // convert NaNS to NaNQ exp = int.min; } } else { exp = (ex - F.EXPBIAS) >> 7; vu[F.EXPPOS_SHORT] = cast(ushort)((0x807F & vu[F.EXPPOS_SHORT]) | 0x3F00); } } else if (!(*vi & 0x7FFF_FFFF)) { // vf is +-0.0 exp = 0; } else { // subnormal vf *= F.RECIP_EPSILON; ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; exp = ((ex - F.EXPBIAS) >> 7) - T.mant_dig + 1; vu[F.EXPPOS_SHORT] = cast(ushort)((0x8000 & vu[F.EXPPOS_SHORT]) | 0x3F00); } return vf; } else // static if (F.realFormat == RealFormat.ibmExtended) { assert (0, "frexp not implemented"); } } /// unittest { int exp; real mantissa = frexp(123.456L, exp); // check if values are equal to 19 decimal digits of precision assert(equalsDigit(mantissa * pow(2.0L, cast(real)exp), 123.456L, 19)); assert(frexp(-real.nan, exp) && exp == int.min); assert(frexp(real.nan, exp) && exp == int.min); assert(frexp(-real.infinity, exp) == -real.infinity && exp == int.min); assert(frexp(real.infinity, exp) == real.infinity && exp == int.max); assert(frexp(-0.0, exp) == -0.0 && exp == 0); assert(frexp(0.0, exp) == 0.0 && exp == 0); } unittest { import std.meta, std.typecons; foreach (T; AliasSeq!(real, double, float)) { Tuple!(T, T, int)[] vals = // x,frexp,exp [ tuple(T(0.0), T( 0.0 ), 0), tuple(T(-0.0), T( -0.0), 0), tuple(T(1.0), T( .5 ), 1), tuple(T(-1.0), T( -.5 ), 1), tuple(T(2.0), T( .5 ), 2), tuple(T(float.min_normal/2.0f), T(.5), -126), tuple(T.infinity, T.infinity, int.max), tuple(-T.infinity, -T.infinity, int.min), tuple(T.nan, T.nan, int.min), tuple(-T.nan, -T.nan, int.min), ]; foreach(elem; vals) { T x = elem[0]; T e = elem[1]; int exp = elem[2]; int eptr; T v = frexp(x, eptr); assert(isIdentical(e, v)); assert(exp == eptr); } static if (floatTraits!(T).realFormat == RealFormat.ieeeExtended) { static T[3][] extendedvals = [ // x,frexp,exp [0x1.a5f1c2eb3fe4efp+73L, 0x1.A5F1C2EB3FE4EFp-1L, 74], // normal [0x1.fa01712e8f0471ap-1064L, 0x1.fa01712e8f0471ap-1L, -1063], [T.min_normal, .5, -16381], [T.min_normal/2.0L, .5, -16382] // subnormal ]; foreach(elem; extendedvals) { T x = elem[0]; T e = elem[1]; int exp = cast(int)elem[2]; int eptr; T v = frexp(x, eptr); assert(isIdentical(e, v)); assert(exp == eptr); } } } } unittest { import std.meta: AliasSeq; void foo() { foreach (T; AliasSeq!(real, double, float)) { int exp; const T a = 1; immutable T b = 2; auto c = frexp(a, exp); auto d = frexp(b, exp); } } } /****************************************** * Extracts the exponent of x as a signed integral value. * * If x is not a special value, the result is the same as * $(D cast(int)logb(x)). * * $(TABLE_SV * $(TR $(TH x) $(TH ilogb(x)) $(TH Range error?)) * $(TR $(TD 0) $(TD FP_ILOGB0) $(TD yes)) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD int.max) $(TD no)) * $(TR $(TD $(NAN)) $(TD FP_ILOGBNAN) $(TD no)) * ) */ int ilogb(T)(const T x) @trusted pure nothrow @nogc if(isFloatingPoint!T) { alias F = floatTraits!T; union floatBits { T rv; ushort[T.sizeof/2] vu; uint[T.sizeof/4] vui; static if(T.sizeof >= 8) ulong[T.sizeof/8] vul; } floatBits y = void; y.rv = x; int ex = y.vu[F.EXPPOS_SHORT] & F.EXPMASK; static if (F.realFormat == RealFormat.ieeeExtended) { if (ex) { // If exponent is non-zero if (ex == F.EXPMASK) // infinity or NaN { if (y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF) // NaN return FP_ILOGBNAN; else // +-infinity return int.max; } else { return ex - F.EXPBIAS - 1; } } else if (!y.vul[0]) { // vf is +-0.0 return FP_ILOGB0; } else { // subnormal return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(y.vul[0]); } } else static if (F.realFormat == RealFormat.ieeeQuadruple) { if (ex) // If exponent is non-zero { if (ex == F.EXPMASK) { // infinity or NaN if (y.vul[MANTISSA_LSB] | ( y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) // NaN return FP_ILOGBNAN; else // +- infinity return int.max; } else { return ex - F.EXPBIAS - 1; } } else if ((y.vul[MANTISSA_LSB] | (y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) == 0) { // vf is +-0.0 return FP_ILOGB0; } else { // subnormal ulong msb = y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF; ulong lsb = y.vul[MANTISSA_LSB]; if (msb) return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(msb) + 64; else return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(lsb); } } else static if (F.realFormat == RealFormat.ieeeDouble) { if (ex) // If exponent is non-zero { if (ex == F.EXPMASK) // infinity or NaN { if ((y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FF0_0000_0000_0000) // +- infinity return int.max; else // NaN return FP_ILOGBNAN; } else { return ((ex - F.EXPBIAS) >> 4) - 1; } } else if (!(y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF)) { // vf is +-0.0 return FP_ILOGB0; } else { // subnormal enum MANTISSAMASK_64 = ((cast(ulong)F.MANTISSAMASK_INT) << 32) | 0xFFFF_FFFF; return ((ex - F.EXPBIAS) >> 4) - T.mant_dig + 1 + bsr(y.vul[0] & MANTISSAMASK_64); } } else static if (F.realFormat == RealFormat.ieeeSingle) { if (ex) // If exponent is non-zero { if (ex == F.EXPMASK) // infinity or NaN { if ((y.vui[0] & 0x7FFF_FFFF) == 0x7F80_0000) // +- infinity return int.max; else // NaN return FP_ILOGBNAN; } else { return ((ex - F.EXPBIAS) >> 7) - 1; } } else if (!(y.vui[0] & 0x7FFF_FFFF)) { // vf is +-0.0 return FP_ILOGB0; } else { // subnormal uint mantissa = y.vui[0] & F.MANTISSAMASK_INT; return ((ex - F.EXPBIAS) >> 7) - T.mant_dig + 1 + bsr(mantissa); } } else // static if (F.realFormat == RealFormat.ibmExtended) { core.stdc.math.ilogbl(x); } } /// ditto int ilogb(T)(const T x) @safe pure nothrow @nogc if(isIntegral!T && isUnsigned!T) { if (x == 0) return FP_ILOGB0; else { static assert (T.sizeof <= ulong.sizeof, "integer size too large for the current ilogb implementation"); return bsr(x); } } /// ditto int ilogb(T)(const T x) @safe pure nothrow @nogc if(isIntegral!T && isSigned!T) { // Note: abs(x) can not be used because the return type is not Unsigned and // the return value would be wrong for x == int.min Unsigned!T absx = x>=0 ? x : -x; return ilogb(absx); } alias FP_ILOGB0 = core.stdc.math.FP_ILOGB0; alias FP_ILOGBNAN = core.stdc.math.FP_ILOGBNAN; @trusted nothrow @nogc unittest { import std.meta, std.typecons; foreach (F; AliasSeq!(float, double, real)) { alias T = Tuple!(F, int); T[13] vals = // x, ilogb(x) [ T( F.nan , FP_ILOGBNAN ), T( -F.nan , FP_ILOGBNAN ), T( F.infinity, int.max ), T( -F.infinity, int.max ), T( 0.0 , FP_ILOGB0 ), T( -0.0 , FP_ILOGB0 ), T( 2.0 , 1 ), T( 2.0001 , 1 ), T( 1.9999 , 0 ), T( 0.5 , -1 ), T( 123.123 , 6 ), T( -123.123 , 6 ), T( 0.123 , -4 ), ]; foreach(elem; vals) { assert(ilogb(elem[0]) == elem[1]); } } // min_normal and subnormals assert(ilogb(-float.min_normal) == -126); assert(ilogb(nextUp(-float.min_normal)) == -127); assert(ilogb(nextUp(-float(0.0))) == -149); assert(ilogb(-double.min_normal) == -1022); assert(ilogb(nextUp(-double.min_normal)) == -1023); assert(ilogb(nextUp(-double(0.0))) == -1074); static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) { assert(ilogb(-real.min_normal) == -16382); assert(ilogb(nextUp(-real.min_normal)) == -16383); assert(ilogb(nextUp(-real(0.0))) == -16445); } else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) { assert(ilogb(-real.min_normal) == -1022); assert(ilogb(nextUp(-real.min_normal)) == -1023); assert(ilogb(nextUp(-real(0.0))) == -1074); } // test integer types assert(ilogb(0) == FP_ILOGB0); assert(ilogb(int.max) == 30); assert(ilogb(int.min) == 31); assert(ilogb(uint.max) == 31); assert(ilogb(long.max) == 62); assert(ilogb(long.min) == 63); assert(ilogb(ulong.max) == 63); } /******************************************* * Compute n * 2$(SUPERSCRIPT exp) * References: frexp */ version(LDC) real ldexp(real n, int exp) @nogc @trusted pure nothrow { return core.stdc.math.ldexpl(n, exp); } else real ldexp(real n, int exp) @nogc @safe pure nothrow { pragma(inline, true); return core.math.ldexp(n, exp); } //FIXME ///ditto double ldexp(double n, int exp) @safe pure nothrow @nogc { return ldexp(cast(real)n, exp); } //FIXME ///ditto float ldexp(float n, int exp) @safe pure nothrow @nogc { return ldexp(cast(real)n, exp); } /// @nogc @safe pure nothrow unittest { import std.meta; foreach(T; AliasSeq!(float, double, real)) { T r; r = ldexp(3.0L, 3); assert(r == 24); r = ldexp(cast(T)3.0, cast(int) 3); assert(r == 24); T n = 3.0; int exp = 3; r = ldexp(n, exp); assert(r == 24); } } @safe pure nothrow @nogc unittest { static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) { assert(ldexp(1.0L, -16384) == 0x1p-16384L); assert(ldexp(1.0L, -16382) == 0x1p-16382L); int x; real n = frexp(0x1p-16384L, x); assert(n==0.5L); assert(x==-16383); assert(ldexp(n, x)==0x1p-16384L); } else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) { assert(ldexp(1.0L, -1024) == 0x1p-1024L); assert(ldexp(1.0L, -1022) == 0x1p-1022L); int x; real n = frexp(0x1p-1024L, x); assert(n==0.5L); assert(x==-1023); assert(ldexp(n, x)==0x1p-1024L); } else static assert(false, "Floating point type real not supported"); } /* workaround Issue 14718, float parsing depends on platform strtold typed_allocator.d @safe pure nothrow @nogc unittest { assert(ldexp(1.0, -1024) == 0x1p-1024); assert(ldexp(1.0, -1022) == 0x1p-1022); int x; double n = frexp(0x1p-1024, x); assert(n==0.5); assert(x==-1023); assert(ldexp(n, x)==0x1p-1024); } @safe pure nothrow @nogc unittest { assert(ldexp(1.0f, -128) == 0x1p-128f); assert(ldexp(1.0f, -126) == 0x1p-126f); int x; float n = frexp(0x1p-128f, x); assert(n==0.5f); assert(x==-127); assert(ldexp(n, x)==0x1p-128f); } */ unittest { static real[3][] vals = // value,exp,ldexp [ [ 0, 0, 0], [ 1, 0, 1], [ -1, 0, -1], [ 1, 1, 2], [ 123, 10, 125952], [ real.max, int.max, real.infinity], [ real.max, -int.max, 0], [ real.min_normal, -int.max, 0], ]; int i; for (i = 0; i < vals.length; i++) { real x = vals[i][0]; int exp = cast(int)vals[i][1]; real z = vals[i][2]; real l = ldexp(x, exp); assert(equalsDigit(z, l, 7)); } real function(real, int) pldexp = &ldexp; assert(pldexp != null); } /************************************** * Calculate the natural logarithm of x. * * $(TABLE_SV * $(TR $(TH x) $(TH log(x)) $(TH divide by 0?) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no)) * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes)) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) * ) */ version(LDC) { real log(real x) @safe pure nothrow @nogc { return llvm_log(x); } //double log(double x) @safe pure nothrow @nogc { return llvm_log(x); } //float log(float x) @safe pure nothrow @nogc { return llvm_log(x); } } else { real log(real x) @safe pure nothrow @nogc { version (INLINE_YL2X) return yl2x(x, LN2); else { // Coefficients for log(1 + x) static immutable real[7] P = [ 2.0039553499201281259648E1L, 5.7112963590585538103336E1L, 6.0949667980987787057556E1L, 2.9911919328553073277375E1L, 6.5787325942061044846969E0L, 4.9854102823193375972212E-1L, 4.5270000862445199635215E-5L, ]; static immutable real[7] Q = [ 6.0118660497603843919306E1L, 2.1642788614495947685003E2L, 3.0909872225312059774938E2L, 2.2176239823732856465394E2L, 8.3047565967967209469434E1L, 1.5062909083469192043167E1L, 1.0000000000000000000000E0L, ]; // Coefficients for log(x) static immutable real[4] R = [ -3.5717684488096787370998E1L, 1.0777257190312272158094E1L, -7.1990767473014147232598E-1L, 1.9757429581415468984296E-3L, ]; static immutable real[4] S = [ -4.2861221385716144629696E2L, 1.9361891836232102174846E2L, -2.6201045551331104417768E1L, 1.0000000000000000000000E0L, ]; // C1 + C2 = LN2. enum real C1 = 6.9314575195312500000000E-1L; enum real C2 = 1.4286068203094172321215E-6L; // Special cases. if (isNaN(x)) return x; if (isInfinity(x) && !signbit(x)) return x; if (x == 0.0) return -real.infinity; if (x < 0.0) return real.nan; // Separate mantissa from exponent. // Note, frexp is used so that denormal numbers will be handled properly. real y, z; int exp; x = frexp(x, exp); // Logarithm using log(x) = z + z^^3 P(z) / Q(z), // where z = 2(x - 1)/(x + 1) if((exp > 2) || (exp < -2)) { if(x < SQRT1_2) { // 2(2x - 1)/(2x + 1) exp -= 1; z = x - 0.5; y = 0.5 * z + 0.5; } else { // 2(x - 1)/(x + 1) z = x - 0.5; z -= 0.5; y = 0.5 * x + 0.5; } x = z / y; z = x * x; z = x * (z * poly(z, R) / poly(z, S)); z += exp * C2; z += x; z += exp * C1; return z; } // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) if (x < SQRT1_2) { // 2x - 1 exp -= 1; x = ldexp(x, 1) - 1.0; } else { x = x - 1.0; } z = x * x; y = x * (z * poly(x, P) / poly(x, Q)); y += exp * C2; z = y - ldexp(z, -1); // Note, the sum of above terms does not exceed x/4, // so it contributes at most about 1/4 lsb to the error. z += x; z += exp * C1; return z; } } } /// @safe pure nothrow @nogc unittest { assert(log(E) == 1); } /************************************** * Calculate the base-10 logarithm of x. * * $(TABLE_SV * $(TR $(TH x) $(TH log10(x)) $(TH divide by 0?) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no)) * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes)) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) * ) */ version(LDC) { real log10(real x) @safe pure nothrow @nogc { return llvm_log10(x); } //double log10(double x) @safe pure nothrow @nogc { return llvm_log10(x); } //float log10(float x) @safe pure nothrow @nogc { return llvm_log10(x); } } else { real log10(real x) @safe pure nothrow @nogc { version (INLINE_YL2X) return yl2x(x, LOG2); else { // Coefficients for log(1 + x) static immutable real[7] P = [ 2.0039553499201281259648E1L, 5.7112963590585538103336E1L, 6.0949667980987787057556E1L, 2.9911919328553073277375E1L, 6.5787325942061044846969E0L, 4.9854102823193375972212E-1L, 4.5270000862445199635215E-5L, ]; static immutable real[7] Q = [ 6.0118660497603843919306E1L, 2.1642788614495947685003E2L, 3.0909872225312059774938E2L, 2.2176239823732856465394E2L, 8.3047565967967209469434E1L, 1.5062909083469192043167E1L, 1.0000000000000000000000E0L, ]; // Coefficients for log(x) static immutable real[4] R = [ -3.5717684488096787370998E1L, 1.0777257190312272158094E1L, -7.1990767473014147232598E-1L, 1.9757429581415468984296E-3L, ]; static immutable real[4] S = [ -4.2861221385716144629696E2L, 1.9361891836232102174846E2L, -2.6201045551331104417768E1L, 1.0000000000000000000000E0L, ]; // log10(2) split into two parts. enum real L102A = 0.3125L; enum real L102B = -1.14700043360188047862611052755069732318101185E-2L; // log10(e) split into two parts. enum real L10EA = 0.5L; enum real L10EB = -6.570551809674817234887108108339491770560299E-2L; // Special cases are the same as for log. if (isNaN(x)) return x; if (isInfinity(x) && !signbit(x)) return x; if (x == 0.0) return -real.infinity; if (x < 0.0) return real.nan; // Separate mantissa from exponent. // Note, frexp is used so that denormal numbers will be handled properly. real y, z; int exp; x = frexp(x, exp); // Logarithm using log(x) = z + z^^3 P(z) / Q(z), // where z = 2(x - 1)/(x + 1) if((exp > 2) || (exp < -2)) { if(x < SQRT1_2) { // 2(2x - 1)/(2x + 1) exp -= 1; z = x - 0.5; y = 0.5 * z + 0.5; } else { // 2(x - 1)/(x + 1) z = x - 0.5; z -= 0.5; y = 0.5 * x + 0.5; } x = z / y; z = x * x; y = x * (z * poly(z, R) / poly(z, S)); goto Ldone; } // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) if (x < SQRT1_2) { // 2x - 1 exp -= 1; x = ldexp(x, 1) - 1.0; } else x = x - 1.0; z = x * x; y = x * (z * poly(x, P) / poly(x, Q)); y = y - ldexp(z, -1); // Multiply log of fraction by log10(e) and base 2 exponent by log10(2). // This sequence of operations is critical and it may be horribly // defeated by some compiler optimizers. Ldone: z = y * L10EB; z += x * L10EB; z += exp * L102B; z += y * L10EA; z += x * L10EA; z += exp * L102A; return z; } } } /// @safe pure nothrow @nogc unittest { assert(fabs(log10(1000) - 3) < .000001); } /****************************************** * Calculates the natural logarithm of 1 + x. * * For very small x, log1p(x) will be more accurate than * log(1 + x). * * $(TABLE_SV * $(TR $(TH x) $(TH log1p(x)) $(TH divide by 0?) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no) $(TD no)) * $(TR $(TD -1.0) $(TD -$(INFIN)) $(TD yes) $(TD no)) * $(TR $(TD $(LT)-1.0) $(TD $(NAN)) $(TD no) $(TD yes)) * $(TR $(TD +$(INFIN)) $(TD -$(INFIN)) $(TD no) $(TD no)) * ) */ real log1p(real x) @safe pure nothrow @nogc { version(INLINE_YL2X) { // On x87, yl2xp1 is valid if and only if -0.5 <= lg(x) <= 0.5, // ie if -0.29<=x<=0.414 return (fabs(x) <= 0.25) ? yl2xp1(x, LN2) : yl2x(x+1, LN2); } else { // Special cases. if (isNaN(x) || x == 0.0) return x; if (isInfinity(x) && !signbit(x)) return x; if (x == -1.0) return -real.infinity; if (x < -1.0) return real.nan; return log(x + 1.0); } } /*************************************** * Calculates the base-2 logarithm of x: * $(SUB log, 2)x * * $(TABLE_SV * $(TR $(TH x) $(TH log2(x)) $(TH divide by 0?) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no) ) * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes) ) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no) ) * ) */ version(LDC) { real log2(real x) @safe pure nothrow @nogc { return llvm_log2(x); } //double log2(double x) @safe pure nothrow @nogc { return llvm_log2(x); } //float log2(float x) @safe pure nothrow @nogc { return llvm_log2(x); } } else { real log2(real x) @safe pure nothrow @nogc { version (INLINE_YL2X) return yl2x(x, 1); else { // Coefficients for log(1 + x) static immutable real[7] P = [ 2.0039553499201281259648E1L, 5.7112963590585538103336E1L, 6.0949667980987787057556E1L, 2.9911919328553073277375E1L, 6.5787325942061044846969E0L, 4.9854102823193375972212E-1L, 4.5270000862445199635215E-5L, ]; static immutable real[7] Q = [ 6.0118660497603843919306E1L, 2.1642788614495947685003E2L, 3.0909872225312059774938E2L, 2.2176239823732856465394E2L, 8.3047565967967209469434E1L, 1.5062909083469192043167E1L, 1.0000000000000000000000E0L, ]; // Coefficients for log(x) static immutable real[4] R = [ -3.5717684488096787370998E1L, 1.0777257190312272158094E1L, -7.1990767473014147232598E-1L, 1.9757429581415468984296E-3L, ]; static immutable real[4] S = [ -4.2861221385716144629696E2L, 1.9361891836232102174846E2L, -2.6201045551331104417768E1L, 1.0000000000000000000000E0L, ]; // Special cases are the same as for log. if (isNaN(x)) return x; if (isInfinity(x) && !signbit(x)) return x; if (x == 0.0) return -real.infinity; if (x < 0.0) return real.nan; // Separate mantissa from exponent. // Note, frexp is used so that denormal numbers will be handled properly. real y, z; int exp; x = frexp(x, exp); // Logarithm using log(x) = z + z^^3 P(z) / Q(z), // where z = 2(x - 1)/(x + 1) if((exp > 2) || (exp < -2)) { if(x < SQRT1_2) { // 2(2x - 1)/(2x + 1) exp -= 1; z = x - 0.5; y = 0.5 * z + 0.5; } else { // 2(x - 1)/(x + 1) z = x - 0.5; z -= 0.5; y = 0.5 * x + 0.5; } x = z / y; z = x * x; y = x * (z * poly(z, R) / poly(z, S)); goto Ldone; } // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) if (x < SQRT1_2) { // 2x - 1 exp -= 1; x = ldexp(x, 1) - 1.0; } else x = x - 1.0; z = x * x; y = x * (z * poly(x, P) / poly(x, Q)); y = y - ldexp(z, -1); // Multiply log of fraction by log10(e) and base 2 exponent by log10(2). // This sequence of operations is critical and it may be horribly // defeated by some compiler optimizers. Ldone: z = y * (LOG2E - 1.0); z += x * (LOG2E - 1.0); z += y; z += x; z += exp; return z; } } } /// unittest { // check if values are equal to 19 decimal digits of precision assert(equalsDigit(log2(1024.0L), 10, 19)); } /***************************************** * Extracts the exponent of x as a signed integral value. * * If x is subnormal, it is treated as if it were normalized. * For a positive, finite x: * * 1 $(LT)= $(I x) * FLT_RADIX$(SUPERSCRIPT -logb(x)) $(LT) FLT_RADIX * * $(TABLE_SV * $(TR $(TH x) $(TH logb(x)) $(TH divide by 0?) ) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) $(TD no)) * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) ) * ) */ real logb(real x) @trusted nothrow @nogc { version (Win64_DMD_InlineAsm_X87) { asm pure nothrow @nogc { naked ; fld real ptr [RCX] ; fxtract ; fstp ST(0) ; ret ; } } else version (CRuntime_Microsoft) { asm pure nothrow @nogc { fld x ; fxtract ; fstp ST(0) ; } } else return core.stdc.math.logbl(x); } /************************************ * Calculates the remainder from the calculation x/y. * Returns: * The value of x - i * y, where i is the number of times that y can * be completely subtracted from x. The result has the same sign as x. * * $(TABLE_SV * $(TR $(TH x) $(TH y) $(TH fmod(x, y)) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD not 0.0) $(TD $(PLUSMN)0.0) $(TD no)) * $(TR $(TD $(PLUSMNINF)) $(TD anything) $(TD $(NAN)) $(TD yes)) * $(TR $(TD anything) $(TD $(PLUSMN)0.0) $(TD $(NAN)) $(TD yes)) * $(TR $(TD !=$(PLUSMNINF)) $(TD $(PLUSMNINF)) $(TD x) $(TD no)) * ) */ real fmod(real x, real y) @trusted nothrow @nogc { version (CRuntime_Microsoft) { return x % y; } else return core.stdc.math.fmodl(x, y); } /************************************ * Breaks x into an integral part and a fractional part, each of which has * the same sign as x. The integral part is stored in i. * Returns: * The fractional part of x. * * $(TABLE_SV * $(TR $(TH x) $(TH i (on input)) $(TH modf(x, i)) $(TH i (on return))) * $(TR $(TD $(PLUSMNINF)) $(TD anything) $(TD $(PLUSMN)0.0) $(TD $(PLUSMNINF))) * ) */ real modf(real x, ref real i) @trusted nothrow @nogc { version (CRuntime_Microsoft) { i = trunc(x); return copysign(isInfinity(x) ? 0.0 : x - i, x); } else return core.stdc.math.modfl(x,&i); } /************************************* * Efficiently calculates x * 2$(SUPERSCRIPT n). * * scalbn handles underflow and overflow in * the same fashion as the basic arithmetic operators. * * $(TABLE_SV * $(TR $(TH x) $(TH scalb(x))) * $(TR $(TD $(PLUSMNINF)) $(TD $(PLUSMNINF)) ) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) ) * ) */ real scalbn(real x, int n) @trusted nothrow @nogc { version(InlineAsm_X86_Any_X87) { // scalbnl is not supported on DMD-Windows, so use asm. version (Win64) { asm pure nothrow @nogc { naked ; mov 16[RSP],RCX ; fild word ptr 16[RSP] ; fld real ptr [RDX] ; fscale ; fstp ST(1) ; ret ; } } else { asm pure nothrow @nogc { fild n; fld x; fscale; fstp ST(1); } } } else { return core.stdc.math.scalbnl(x, n); } } /// @safe nothrow @nogc unittest { assert(scalbn(-real.infinity, 5) == -real.infinity); } /*************** * Calculates the cube root of x. * * $(TABLE_SV * $(TR $(TH $(I x)) $(TH cbrt(x)) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no) ) * $(TR $(TD $(NAN)) $(TD $(NAN)) $(TD yes) ) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(PLUSMN)$(INFIN)) $(TD no) ) * ) */ real cbrt(real x) @trusted nothrow @nogc { version (CRuntime_Microsoft) { version (INLINE_YL2X) return copysign(exp2(yl2x(fabs(x), 1.0L/3.0L)), x); else return core.stdc.math.cbrtl(x); } else return core.stdc.math.cbrtl(x); } /******************************* * Returns |x| * * $(TABLE_SV * $(TR $(TH x) $(TH fabs(x))) * $(TR $(TD $(PLUSMN)0.0) $(TD +0.0) ) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) ) * ) */ version(LDC) { real fabs(real x) @safe pure nothrow @nogc { return llvm_fabs(x); } ///ditto double fabs(double x) @safe pure nothrow @nogc { return llvm_fabs(x); } ///ditto float fabs(float x) @safe pure nothrow @nogc { return llvm_fabs(x); } } else { real fabs(real x) @safe pure nothrow @nogc { pragma(inline, true); return core.math.fabs(x); } //FIXME ///ditto double fabs(double x) @safe pure nothrow @nogc { return fabs(cast(real)x); } //FIXME ///ditto float fabs(float x) @safe pure nothrow @nogc { return fabs(cast(real)x); } } unittest { real function(real) pfabs = &fabs; assert(pfabs != null); } /*********************************************************************** * Calculates the length of the * hypotenuse of a right-angled triangle with sides of length x and y. * The hypotenuse is the value of the square root of * the sums of the squares of x and y: * * sqrt($(POWER x, 2) + $(POWER y, 2)) * * Note that hypot(x, y), hypot(y, x) and * hypot(x, -y) are equivalent. * * $(TABLE_SV * $(TR $(TH x) $(TH y) $(TH hypot(x, y)) $(TH invalid?)) * $(TR $(TD x) $(TD $(PLUSMN)0.0) $(TD |x|) $(TD no)) * $(TR $(TD $(PLUSMNINF)) $(TD y) $(TD +$(INFIN)) $(TD no)) * $(TR $(TD $(PLUSMNINF)) $(TD $(NAN)) $(TD +$(INFIN)) $(TD no)) * ) */ real hypot(real x, real y) @safe pure nothrow @nogc { // Scale x and y to avoid underflow and overflow. // If one is huge and the other tiny, return the larger. // If both are huge, avoid overflow by scaling by 1/sqrt(real.max/2). // If both are tiny, avoid underflow by scaling by sqrt(real.min_normal*real.epsilon). enum real SQRTMIN = 0.5 * sqrt(real.min_normal); // This is a power of 2. enum real SQRTMAX = 1.0L / SQRTMIN; // 2^^((max_exp)/2) = nextUp(sqrt(real.max)) static assert(2*(SQRTMAX/2)*(SQRTMAX/2) <= real.max); // Proves that sqrt(real.max) ~~ 0.5/sqrt(real.min_normal) static assert(real.min_normal*real.max > 2 && real.min_normal*real.max <= 4); real u = fabs(x); real v = fabs(y); if (!(u >= v)) // check for NaN as well. { v = u; u = fabs(y); if (u == real.infinity) return u; // hypot(inf, nan) == inf if (v == real.infinity) return v; // hypot(nan, inf) == inf } // Now u >= v, or else one is NaN. if (v >= SQRTMAX*0.5) { // hypot(huge, huge) -- avoid overflow u *= SQRTMIN*0.5; v *= SQRTMIN*0.5; return sqrt(u*u + v*v) * SQRTMAX * 2.0; } if (u <= SQRTMIN) { // hypot (tiny, tiny) -- avoid underflow // This is only necessary to avoid setting the underflow // flag. u *= SQRTMAX / real.epsilon; v *= SQRTMAX / real.epsilon; return sqrt(u*u + v*v) * SQRTMIN * real.epsilon; } if (u * real.epsilon > v) { // hypot (huge, tiny) = huge return u; } // both are in the normal range return sqrt(u*u + v*v); } unittest { static real[3][] vals = // x,y,hypot [ [ 0.0, 0.0, 0.0], [ 0.0, -0.0, 0.0], [ -0.0, -0.0, 0.0], [ 3.0, 4.0, 5.0], [ -300, -400, 500], [0.0, 7.0, 7.0], [9.0, 9*real.epsilon, 9.0], [88/(64*sqrt(real.min_normal)), 105/(64*sqrt(real.min_normal)), 137/(64*sqrt(real.min_normal))], [88/(128*sqrt(real.min_normal)), 105/(128*sqrt(real.min_normal)), 137/(128*sqrt(real.min_normal))], [3*real.min_normal*real.epsilon, 4*real.min_normal*real.epsilon, 5*real.min_normal*real.epsilon], [ real.min_normal, real.min_normal, sqrt(2.0L)*real.min_normal], [ real.max/sqrt(2.0L), real.max/sqrt(2.0L), real.max], [ real.infinity, real.nan, real.infinity], [ real.nan, real.infinity, real.infinity], [ real.nan, real.nan, real.nan], [ real.nan, real.max, real.nan], [ real.max, real.nan, real.nan], ]; for (int i = 0; i < vals.length; i++) { real x = vals[i][0]; real y = vals[i][1]; real z = vals[i][2]; real h = hypot(x, y); assert(isIdentical(z,h) || feqrel(z, h) >= real.mant_dig - 1); } } /************************************** * Returns the value of x rounded upward to the next integer * (toward positive infinity). */ version(LDC) { real ceil(real x) @safe pure nothrow @nogc { return llvm_ceil(x); } ///ditto double ceil(double x) @safe pure nothrow @nogc { return llvm_ceil(x); } ///ditto float ceil(float x) @safe pure nothrow @nogc { return llvm_ceil(x); } } else { real ceil(real x) @trusted pure nothrow @nogc { version (Win64_DMD_InlineAsm_X87) { asm pure nothrow @nogc { naked ; fld real ptr [RCX] ; fstcw 8[RSP] ; mov AL,9[RSP] ; mov DL,AL ; and AL,0xC3 ; or AL,0x08 ; // round to +infinity mov 9[RSP],AL ; fldcw 8[RSP] ; frndint ; mov 9[RSP],DL ; fldcw 8[RSP] ; ret ; } } else version(CRuntime_Microsoft) { short cw; asm pure nothrow @nogc { fld x ; fstcw cw ; mov AL,byte ptr cw+1 ; mov DL,AL ; and AL,0xC3 ; or AL,0x08 ; // round to +infinity mov byte ptr cw+1,AL ; fldcw cw ; frndint ; mov byte ptr cw+1,DL ; fldcw cw ; } } else { // Special cases. if (isNaN(x) || isInfinity(x)) return x; real y = floorImpl(x); if (y < x) y += 1.0; return y; } } /// @safe pure nothrow @nogc unittest { assert(ceil(+123.456L) == +124); assert(ceil(-123.456L) == -123); assert(ceil(-1.234L) == -1); assert(ceil(-0.123L) == 0); assert(ceil(0.0L) == 0); assert(ceil(+0.123L) == 1); assert(ceil(+1.234L) == 2); assert(ceil(real.infinity) == real.infinity); assert(isNaN(ceil(real.nan))); assert(isNaN(ceil(real.init))); } // ditto double ceil(double x) @trusted pure nothrow @nogc { // Special cases. if (isNaN(x) || isInfinity(x)) return x; double y = floorImpl(x); if (y < x) y += 1.0; return y; } @safe pure nothrow @nogc unittest { assert(ceil(+123.456) == +124); assert(ceil(-123.456) == -123); assert(ceil(-1.234) == -1); assert(ceil(-0.123) == 0); assert(ceil(0.0) == 0); assert(ceil(+0.123) == 1); assert(ceil(+1.234) == 2); assert(ceil(double.infinity) == double.infinity); assert(isNaN(ceil(double.nan))); assert(isNaN(ceil(double.init))); } // ditto float ceil(float x) @trusted pure nothrow @nogc { // Special cases. if (isNaN(x) || isInfinity(x)) return x; float y = floorImpl(x); if (y < x) y += 1.0; return y; } @safe pure nothrow @nogc unittest { assert(ceil(+123.456f) == +124); assert(ceil(-123.456f) == -123); assert(ceil(-1.234f) == -1); assert(ceil(-0.123f) == 0); assert(ceil(0.0f) == 0); assert(ceil(+0.123f) == 1); assert(ceil(+1.234f) == 2); assert(ceil(float.infinity) == float.infinity); assert(isNaN(ceil(float.nan))); assert(isNaN(ceil(float.init))); } } /************************************** * Returns the value of x rounded downward to the next integer * (toward negative infinity). */ version(LDC) { real floor(real x) @safe pure nothrow @nogc { return llvm_floor(x); } ///ditto double floor(double x) @safe pure nothrow @nogc { return llvm_floor(x); } ///ditto float floor(float x) @safe pure nothrow @nogc { return llvm_floor(x); } } else { real floor(real x) @trusted pure nothrow @nogc { version (Win64_DMD_InlineAsm_X87) { asm pure nothrow @nogc { naked ; fld real ptr [RCX] ; fstcw 8[RSP] ; mov AL,9[RSP] ; mov DL,AL ; and AL,0xC3 ; or AL,0x04 ; // round to -infinity mov 9[RSP],AL ; fldcw 8[RSP] ; frndint ; mov 9[RSP],DL ; fldcw 8[RSP] ; ret ; } } else version(CRuntime_Microsoft) { short cw; asm pure nothrow @nogc { fld x ; fstcw cw ; mov AL,byte ptr cw+1 ; mov DL,AL ; and AL,0xC3 ; or AL,0x04 ; // round to -infinity mov byte ptr cw+1,AL ; fldcw cw ; frndint ; mov byte ptr cw+1,DL ; fldcw cw ; } } else { // Special cases. if (isNaN(x) || isInfinity(x) || x == 0.0) return x; return floorImpl(x); } } /// @safe pure nothrow @nogc unittest { assert(floor(+123.456L) == +123); assert(floor(-123.456L) == -124); assert(floor(-1.234L) == -2); assert(floor(-0.123L) == -1); assert(floor(0.0L) == 0); assert(floor(+0.123L) == 0); assert(floor(+1.234L) == 1); assert(floor(real.infinity) == real.infinity); assert(isNaN(floor(real.nan))); assert(isNaN(floor(real.init))); } // ditto double floor(double x) @trusted pure nothrow @nogc { // Special cases. if (isNaN(x) || isInfinity(x) || x == 0.0) return x; return floorImpl(x); } @safe pure nothrow @nogc unittest { assert(floor(+123.456) == +123); assert(floor(-123.456) == -124); assert(floor(-1.234) == -2); assert(floor(-0.123) == -1); assert(floor(0.0) == 0); assert(floor(+0.123) == 0); assert(floor(+1.234) == 1); assert(floor(double.infinity) == double.infinity); assert(isNaN(floor(double.nan))); assert(isNaN(floor(double.init))); } // ditto float floor(float x) @trusted pure nothrow @nogc { // Special cases. if (isNaN(x) || isInfinity(x) || x == 0.0) return x; return floorImpl(x); } @safe pure nothrow @nogc unittest { assert(floor(+123.456f) == +123); assert(floor(-123.456f) == -124); assert(floor(-1.234f) == -2); assert(floor(-0.123f) == -1); assert(floor(0.0f) == 0); assert(floor(+0.123f) == 0); assert(floor(+1.234f) == 1); assert(floor(float.infinity) == float.infinity); assert(isNaN(floor(float.nan))); assert(isNaN(floor(float.init))); } } /****************************************** * Rounds x to the nearest integer value, using the current rounding * mode. * * Unlike the rint functions, nearbyint does not raise the * FE_INEXACT exception. */ version(LDC) { real nearbyint(real x) @safe nothrow @nogc { return llvm_nearbyint(x); } //double nearbyint(double x) @safe nothrow @nogc { return llvm_nearbyint(x); } //float nearbyint(float x) @safe nothrow @nogc { return llvm_nearbyint(x); } } else { real nearbyint(real x) @trusted nothrow @nogc { version (CRuntime_Microsoft) { assert(0); // not implemented in C library } else return core.stdc.math.nearbyintl(x); } } /********************************** * Rounds x to the nearest integer value, using the current rounding * mode. * If the return value is not equal to x, the FE_INEXACT * exception is raised. * $(B nearbyint) performs * the same operation, but does not set the FE_INEXACT exception. */ version(LDC) { real rint(real x) @safe pure nothrow @nogc { return llvm_rint(x); } ///ditto double rint(double x) @safe pure nothrow @nogc { return llvm_rint(x); } ///ditto float rint(float x) @safe pure nothrow @nogc { return llvm_rint(x); } } else { real rint(real x) @safe pure nothrow @nogc { pragma(inline, true); return core.math.rint(x); } //FIXME ///ditto double rint(double x) @safe pure nothrow @nogc { return rint(cast(real)x); } //FIXME ///ditto float rint(float x) @safe pure nothrow @nogc { return rint(cast(real)x); } } unittest { real function(real) print = &rint; assert(print != null); } /*************************************** * Rounds x to the nearest integer value, using the current rounding * mode. * * This is generally the fastest method to convert a floating-point number * to an integer. Note that the results from this function * depend on the rounding mode, if the fractional part of x is exactly 0.5. * If using the default rounding mode (ties round to even integers) * lrint(4.5) == 4, lrint(5.5)==6. */ long lrint(real x) @trusted pure nothrow @nogc { version(InlineAsm_X86_Any_X87) { version (Win64) { asm pure nothrow @nogc { naked; fld real ptr [RCX]; fistp qword ptr 8[RSP]; mov RAX,8[RSP]; ret; } } else { long n; asm pure nothrow @nogc { fld x; fistp n; } return n; } } else { alias F = floatTraits!(real); static if (F.realFormat == RealFormat.ieeeDouble) { long result; // Rounding limit when casting from real(double) to ulong. enum real OF = 4.50359962737049600000E15L; uint* vi = cast(uint*)(&x); // Find the exponent and sign uint msb = vi[MANTISSA_MSB]; uint lsb = vi[MANTISSA_LSB]; int exp = ((msb >> 20) & 0x7ff) - 0x3ff; int sign = msb >> 31; msb &= 0xfffff; msb |= 0x100000; if (exp < 63) { if (exp >= 52) result = (cast(long) msb << (exp - 20)) | (lsb << (exp - 52)); else { // Adjust x and check result. real j = sign ? -OF : OF; x = (j + x) - j; msb = vi[MANTISSA_MSB]; lsb = vi[MANTISSA_LSB]; exp = ((msb >> 20) & 0x7ff) - 0x3ff; msb &= 0xfffff; msb |= 0x100000; if (exp < 0) result = 0; else if (exp < 20) result = cast(long) msb >> (20 - exp); else if (exp == 20) result = cast(long) msb; else result = (cast(long) msb << (exp - 20)) | (lsb >> (52 - exp)); } } else { // It is left implementation defined when the number is too large. return cast(long) x; } return sign ? -result : result; } else static if (F.realFormat == RealFormat.ieeeExtended) { long result; // Rounding limit when casting from real(80-bit) to ulong. enum real OF = 9.22337203685477580800E18L; ushort* vu = cast(ushort*)(&x); uint* vi = cast(uint*)(&x); // Find the exponent and sign int exp = (vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff; int sign = (vu[F.EXPPOS_SHORT] >> 15) & 1; if (exp < 63) { // Adjust x and check result. real j = sign ? -OF : OF; x = (j + x) - j; exp = (vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff; version (LittleEndian) { if (exp < 0) result = 0; else if (exp <= 31) result = vi[1] >> (31 - exp); else result = (cast(long) vi[1] << (exp - 31)) | (vi[0] >> (63 - exp)); } else { if (exp < 0) result = 0; else if (exp <= 31) result = vi[1] >> (31 - exp); else result = (cast(long) vi[1] << (exp - 31)) | (vi[2] >> (63 - exp)); } } else { // It is left implementation defined when the number is too large // to fit in a 64bit long. return cast(long) x; } return sign ? -result : result; } else { static assert(false, "Only 64-bit and 80-bit reals are supported by lrint()"); } } } /// @safe pure nothrow @nogc unittest { assert(lrint(4.5) == 4); assert(lrint(5.5) == 6); assert(lrint(-4.5) == -4); assert(lrint(-5.5) == -6); assert(lrint(int.max - 0.5) == 2147483646L); assert(lrint(int.max + 0.5) == 2147483648L); assert(lrint(int.min - 0.5) == -2147483648L); assert(lrint(int.min + 0.5) == -2147483648L); } /******************************************* * Return the value of x rounded to the nearest integer. * If the fractional part of x is exactly 0.5, the return value is * rounded away from zero. */ version(LDC) { real round(real x) @safe nothrow @nogc { return llvm_round(x); } //double round(double x) @safe nothrow @nogc { return llvm_round(x); } //float round(float x) @safe nothrow @nogc { return llvm_round(x); } } else { real round(real x) @trusted nothrow @nogc { version (CRuntime_Microsoft) { auto old = FloatingPointControl.getControlState(); FloatingPointControl.setControlState((old & ~FloatingPointControl.ROUNDING_MASK) | FloatingPointControl.roundToZero); x = rint((x >= 0) ? x + 0.5 : x - 0.5); FloatingPointControl.setControlState(old); return x; } else return core.stdc.math.roundl(x); } } /********************************************** * Return the value of x rounded to the nearest integer. * * If the fractional part of x is exactly 0.5, the return value is rounded * away from zero. */ long lround(real x) @trusted nothrow @nogc { version (Posix) return core.stdc.math.llroundl(x); else assert (0, "lround not implemented"); } version(Posix) { @safe nothrow @nogc unittest { assert(lround(0.49) == 0); assert(lround(0.5) == 1); assert(lround(1.5) == 2); } } /**************************************************** * Returns the integer portion of x, dropping the fractional portion. * * This is also known as "chop" rounding. */ version(LDC) { real trunc(real x) @safe pure nothrow @nogc { return llvm_trunc(x); } //double trunc(double x) @safe pure nothrow @nogc { return llvm_trunc(x); } //float trunc(float x) @safe pure nothrow @nogc { return llvm_trunc(x); } } else { real trunc(real x) @trusted nothrow @nogc { version (Win64_DMD_InlineAsm_X87) { asm pure nothrow @nogc { naked ; fld real ptr [RCX] ; fstcw 8[RSP] ; mov AL,9[RSP] ; mov DL,AL ; and AL,0xC3 ; or AL,0x0C ; // round to 0 mov 9[RSP],AL ; fldcw 8[RSP] ; frndint ; mov 9[RSP],DL ; fldcw 8[RSP] ; ret ; } } else version(CRuntime_Microsoft) { short cw; asm pure nothrow @nogc { fld x ; fstcw cw ; mov AL,byte ptr cw+1 ; mov DL,AL ; and AL,0xC3 ; or AL,0x0C ; // round to 0 mov byte ptr cw+1,AL ; fldcw cw ; frndint ; mov byte ptr cw+1,DL ; fldcw cw ; } } else return core.stdc.math.truncl(x); } } /**************************************************** * Calculate the remainder x REM y, following IEC 60559. * * REM is the value of x - y * n, where n is the integer nearest the exact * value of x / y. * If |n - x / y| == 0.5, n is even. * If the result is zero, it has the same sign as x. * Otherwise, the sign of the result is the sign of x / y. * Precision mode has no effect on the remainder functions. * * remquo returns n in the parameter n. * * $(TABLE_SV * $(TR $(TH x) $(TH y) $(TH remainder(x, y)) $(TH n) $(TH invalid?)) * $(TR $(TD $(PLUSMN)0.0) $(TD not 0.0) $(TD $(PLUSMN)0.0) $(TD 0.0) $(TD no)) * $(TR $(TD $(PLUSMNINF)) $(TD anything) $(TD $(NAN)) $(TD ?) $(TD yes)) * $(TR $(TD anything) $(TD $(PLUSMN)0.0) $(TD $(NAN)) $(TD ?) $(TD yes)) * $(TR $(TD != $(PLUSMNINF)) $(TD $(PLUSMNINF)) $(TD x) $(TD ?) $(TD no)) * ) * * Note: remquo not supported on windows */ real remainder(real x, real y) @trusted nothrow @nogc { version (CRuntime_Microsoft) { int n; return remquo(x, y, n); } else return core.stdc.math.remainderl(x, y); } real remquo(real x, real y, out int n) @trusted nothrow @nogc /// ditto { version (Posix) return core.stdc.math.remquol(x, y, &n); else assert (0, "remquo not implemented"); } /** IEEE exception status flags ('sticky bits') These flags indicate that an exceptional floating-point condition has occurred. They indicate that a NaN or an infinity has been generated, that a result is inexact, or that a signalling NaN has been encountered. If floating-point exceptions are enabled (unmasked), a hardware exception will be generated instead of setting these flags. */ struct IeeeFlags { private: // The x87 FPU status register is 16 bits. // The Pentium SSE2 status register is 32 bits. uint flags; version (X86_Any) { // Applies to both x87 status word (16 bits) and SSE2 status word(32 bits). enum : int { INEXACT_MASK = 0x20, UNDERFLOW_MASK = 0x10, OVERFLOW_MASK = 0x08, DIVBYZERO_MASK = 0x04, INVALID_MASK = 0x01 } // Don't bother about subnormals, they are not supported on most CPUs. // SUBNORMAL_MASK = 0x02; } else version (PPC_Any) { // PowerPC FPSCR is a 32-bit register. enum : int { INEXACT_MASK = 0x02000000, DIVBYZERO_MASK = 0x04000000, UNDERFLOW_MASK = 0x08000000, OVERFLOW_MASK = 0x10000000, INVALID_MASK = 0x20000000 // Summary as PowerPC has five types of invalid exceptions. } } else version (MIPS_Any) { // MIPS 32/64 FCSR is a 32-bit register. enum : int { INEXACT_MASK = 0x40, DIVBYZERO_MASK = 0x20, OVERFLOW_MASK = 0x10, UNDERFLOW_MASK = 0x08, INVALID_MASK = 0x04 } } else version (AArch64) { // AArch64 FPSR is a 32bit register enum : int { INEXACT_MASK = 0x0010, UNDERFLOW_MASK = 0x0008, OVERFLOW_MASK = 0x0004, DIVBYZERO_MASK = 0x0002, INVALID_MASK = 0x0001 } } else version (ARM) { // ARM FPSCR is a 32bit register enum : int { INEXACT_MASK = 0x10, UNDERFLOW_MASK = 0x08, OVERFLOW_MASK = 0x04, DIVBYZERO_MASK = 0x02, INVALID_MASK = 0x01 } } else version(SPARC) { // SPARC FSR is a 32bit register //(64 bits for Sparc 7 & 8, but high 32 bits are uninteresting). enum : int { INEXACT_MASK = 0x020, UNDERFLOW_MASK = 0x080, OVERFLOW_MASK = 0x100, DIVBYZERO_MASK = 0x040, INVALID_MASK = 0x200 } } else static assert(0, "Not implemented"); private: static uint getIeeeFlags() { version (LDC) { version (X86_Any) { return __asm!ushort("fstsw %ax", "={ax}") & 0x3d; } else version (PPC_Any) { double fspr = __asm!double("mffs $0", "=f"); return cast(uint) *cast(ulong*) &fspr; } else version (MIPS_Any) { return __asm!uint("cfc1 $0, $$31", "=r"); } else version (ARM_SoftFloat) { return 0; } else version (AArch64) { return __asm!uint("mrs $0, FPSR\n and $0, $0, #0x1F", "=r"); } else version (ARM) { return __asm!uint("vmrs $0, FPSCR\n and $0, $0, #0x1F", "=r"); } else assert(0, "Not yet supported"); } else version(D_InlineAsm_X86) { asm pure nothrow @nogc { fstsw AX; // NOTE: If compiler supports SSE2, need to OR the result with // the SSE2 status register. // Clear all irrelevant bits and EAX, 0x03D; } } else version(D_InlineAsm_X86_64) { asm pure nothrow @nogc { fstsw AX; // NOTE: If compiler supports SSE2, need to OR the result with // the SSE2 status register. // Clear all irrelevant bits and RAX, 0x03D; } } else version (SPARC) { /* int retval; asm pure nothrow @nogc { st %fsr, retval; } return retval; */ assert(0, "Not yet supported"); } else version (ARM) { assert(false, "Not yet supported."); } else assert(0, "Not yet supported"); } static void resetIeeeFlags() { version (LDC) { version (X86_Any) { __asm("fnclex", "~{fpsw}"); } else version (PPC_Any) { __asm("mtfsb0 3\n mtfsb0 4\n mtfsb0 5\n mtfsb0 6\n mtfsb0 7\n mtfsb0 8\n mtfsb0 9\n mtfsb0 10\n mtfsb0 11\n mtfsb0 12", ""); } else version (MIPS_Any) { cast(void) __asm!uint("cfc1 $0, $$31\n andi $0, $0, 0xFFFFFF80\n ctc1 $0, $$31", "=r"); } else version (AArch64) { // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0502f/CIHHDCHB.html cast(void)__asm!uint ("mrs $0, fpsr\n" // use '\n' as ';' is a comment "and $0, $0, #~0x1f\n" "msr fpsr, $0", "=r"); } else version (ARM_SoftFloat) { } else version (ARM) { // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0408i/Chdfifdc.html cast(void) __asm!uint ("vmrs $0, fpscr\n" "bic $0, #0x1f\n" "vmsr fpscr, $0", "=r"); } else assert(0, "Not yet supported"); } else version(InlineAsm_X86_Any) { asm pure nothrow @nogc { fnclex; } } else { /* SPARC: int tmpval; asm pure nothrow @nogc { st %fsr, tmpval; } tmpval &=0xFFFF_FC00; asm pure nothrow @nogc { ld tmpval, %fsr; } */ assert(0, "Not yet supported"); } } public: version (IeeeFlagsSupport) { /// The result cannot be represented exactly, so rounding occurred. /// (example: x = sin(0.1); ) @property bool inexact() { return (flags & INEXACT_MASK) != 0; } /// A zero was generated by underflow (example: x = real.min*real.epsilon/2;) @property bool underflow() { return (flags & UNDERFLOW_MASK) != 0; } /// An infinity was generated by overflow (example: x = real.max*2;) @property bool overflow() { return (flags & OVERFLOW_MASK) != 0; } /// An infinity was generated by division by zero (example: x = 3/0.0; ) @property bool divByZero() { return (flags & DIVBYZERO_MASK) != 0; } /// A machine NaN was generated. (example: x = real.infinity * 0.0; ) @property bool invalid() { return (flags & INVALID_MASK) != 0; } } } /// version (LDC) { unittest { pragma(msg, "ieeeFlags test disabled, see LDC Issue #888"); } } else unittest { static void func() { int a = 10 * 10; } real a=3.5; // Set all the flags to zero resetIeeeFlags(); assert(!ieeeFlags.divByZero); // Perform a division by zero. a/=0.0L; assert(a==real.infinity); assert(ieeeFlags.divByZero); // Create a NaN a*=0.0L; assert(ieeeFlags.invalid); assert(isNaN(a)); // Check that calling func() has no effect on the // status flags. IeeeFlags f = ieeeFlags; func(); assert(ieeeFlags == f); } version(X86_Any) { version = IeeeFlagsSupport; } else version(PPC_Any) { version = IeeeFlagsSupport; } else version(MIPS_Any) { version = IeeeFlagsSupport; } else version (AArch64) { version = IeeeFlagsSupport; } else version (ARM) { version = IeeeFlagsSupport; } /// Set all of the floating-point status flags to false. void resetIeeeFlags() { IeeeFlags.resetIeeeFlags(); } /// Return a snapshot of the current state of the floating-point status flags. @property IeeeFlags ieeeFlags() { return IeeeFlags(IeeeFlags.getIeeeFlags()); } /** Control the Floating point hardware Change the IEEE754 floating-point rounding mode and the floating-point hardware exceptions. By default, the rounding mode is roundToNearest and all hardware exceptions are disabled. For most applications, debugging is easier if the $(I division by zero), $(I overflow), and $(I invalid operation) exceptions are enabled. These three are combined into a $(I severeExceptions) value for convenience. Note in particular that if $(I invalidException) is enabled, a hardware trap will be generated whenever an uninitialized floating-point variable is used. All changes are temporary. The previous state is restored at the end of the scope. Example: ---- { FloatingPointControl fpctrl; // Enable hardware exceptions for division by zero, overflow to infinity, // invalid operations, and uninitialized floating-point variables. fpctrl.enableExceptions(FloatingPointControl.severeExceptions); // This will generate a hardware exception, if x is a // default-initialized floating point variable: real x; // Add `= 0` or even `= real.nan` to not throw the exception. real y = x * 3.0; // The exception is only thrown for default-uninitialized NaN-s. // NaN-s with other payload are valid: real z = y * real.nan; // ok // Changing the rounding mode: fpctrl.rounding = FloatingPointControl.roundUp; assert(rint(1.1) == 2); // The set hardware exceptions will be disabled when leaving this scope. // The original rounding mode will also be restored. } // Ensure previous values are returned: assert(!FloatingPointControl.enabledExceptions); assert(FloatingPointControl.rounding == FloatingPointControl.roundToNearest); assert(rint(1.1) == 1); ---- */ struct FloatingPointControl { alias RoundingMode = uint; /** IEEE rounding modes. * The default mode is roundToNearest. */ version(AArch64) { enum : RoundingMode { roundToNearest = 0x000000, roundDown = 0x800000, roundUp = 0x400000, roundToZero = 0xC00000 } } else version(ARM) { enum : RoundingMode { roundToNearest = 0x000000, roundDown = 0x800000, roundUp = 0x400000, roundToZero = 0xC00000 } } else version(PPC_Any) { enum : RoundingMode { roundToNearest = 0x00000000, roundDown = 0x00000003, roundUp = 0x00000002, roundToZero = 0x00000001 } } else version(MIPS_Any) { enum : RoundingMode { roundToNearest = 0x00000000, roundDown = 0x00000003, roundUp = 0x00000002, roundToZero = 0x00000001 } } else { enum : RoundingMode { roundToNearest = 0x0000, roundDown = 0x0400, roundUp = 0x0800, roundToZero = 0x0C00 } } /** IEEE hardware exceptions. * By default, all exceptions are masked (disabled). */ version(AArch64) { enum : uint { inexactException = 0x1000, underflowException = 0x0800, overflowException = 0x0400, divByZeroException = 0x0200, invalidException = 0x0100, /// Severe = The overflow, division by zero, and invalid exceptions. severeExceptions = overflowException | divByZeroException | invalidException, allExceptions = severeExceptions | underflowException | inexactException, } } else version(ARM) { enum : uint { subnormalException = 0x8000, inexactException = 0x1000, underflowException = 0x0800, overflowException = 0x0400, divByZeroException = 0x0200, invalidException = 0x0100, /// Severe = The overflow, division by zero, and invalid exceptions. severeExceptions = overflowException | divByZeroException | invalidException, allExceptions = severeExceptions | underflowException | inexactException | subnormalException, } } else version(PPC_Any) { enum : uint { inexactException = 0x0008, divByZeroException = 0x0010, underflowException = 0x0020, overflowException = 0x0040, invalidException = 0x0080, /// Severe = The overflow, division by zero, and invalid exceptions. severeExceptions = overflowException | divByZeroException | invalidException, allExceptions = severeExceptions | underflowException | inexactException, } } else version(MIPS_Any) { enum : uint { inexactException = 0x0800, divByZeroException = 0x0400, overflowException = 0x0200, underflowException = 0x0100, invalidException = 0x0080, /// Severe = The overflow, division by zero, and invalid exceptions. severeExceptions = overflowException | divByZeroException | invalidException, allExceptions = severeExceptions | underflowException | inexactException, } } else { enum : uint { inexactException = 0x20, underflowException = 0x10, overflowException = 0x08, divByZeroException = 0x04, subnormalException = 0x02, invalidException = 0x01, /// Severe = The overflow, division by zero, and invalid exceptions. severeExceptions = overflowException | divByZeroException | invalidException, allExceptions = severeExceptions | underflowException | inexactException | subnormalException, } } private: version(AArch64) { enum uint EXCEPTION_MASK = 0x1F00; enum uint ROUNDING_MASK = 0xC00000; } else version(ARM) { enum uint EXCEPTION_MASK = 0x9F00; enum uint ROUNDING_MASK = 0xC00000; } else version(PPC_Any) { enum uint EXCEPTION_MASK = 0x00F8; enum uint ROUNDING_MASK = 0x0003; } else version(MIPS_Any) { enum uint EXCEPTION_MASK = 0x0F80; enum uint ROUNDING_MASK = 0x0003; } else version(X86) { enum ushort EXCEPTION_MASK = 0x3F; enum ushort ROUNDING_MASK = 0xC00; } else version(X86_64) { enum ushort EXCEPTION_MASK = 0x3F; enum ushort ROUNDING_MASK = 0xC00; } else static assert(false, "Architecture not supported"); public: /// Returns true if the current FPU supports exception trapping @property static bool hasExceptionTraps() @safe nothrow @nogc { version(X86_Any) return true; else version(PPC_Any) return true; else version(MIPS_Any) return true; else version(AArch64) { auto oldState = getControlState(); // If exceptions are not supported, we set the bit but read it back as zero // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/aarch64/fpu/feenablxcpth.c setControlState(oldState | (divByZeroException & EXCEPTION_MASK)); bool result = (getControlState() & EXCEPTION_MASK) != 0; setControlState(oldState); return result; } else version(ARM) { auto oldState = getControlState(); // If exceptions are not supported, we set the bit but read it back as zero // https://sourceware.org/ml/libc-ports/2012-06/msg00091.html setControlState(oldState | (divByZeroException & EXCEPTION_MASK)); bool result = (getControlState() & EXCEPTION_MASK) != 0; setControlState(oldState); return result; } else static assert(false, "Not implemented for this architecture"); } /// Enable (unmask) specific hardware exceptions. Multiple exceptions may be ORed together. void enableExceptions(uint exceptions) @nogc { assert(hasExceptionTraps); initialize(); version(X86_Any) setControlState(getControlState() & ~(exceptions & EXCEPTION_MASK)); else setControlState(getControlState() | (exceptions & EXCEPTION_MASK)); } /// Disable (mask) specific hardware exceptions. Multiple exceptions may be ORed together. void disableExceptions(uint exceptions) @nogc { assert(hasExceptionTraps); initialize(); version(X86_Any) setControlState(getControlState() | (exceptions & EXCEPTION_MASK)); else setControlState(getControlState() & ~(exceptions & EXCEPTION_MASK)); } //// Change the floating-point hardware rounding mode @property void rounding(RoundingMode newMode) @nogc { initialize(); setControlState((getControlState() & ~ROUNDING_MASK) | (newMode & ROUNDING_MASK)); } /// Return the exceptions which are currently enabled (unmasked) @property static uint enabledExceptions() @nogc { assert(hasExceptionTraps); version(X86_Any) return (getControlState() & EXCEPTION_MASK) ^ EXCEPTION_MASK; else return (getControlState() & EXCEPTION_MASK); } /// Return the currently active rounding mode @property static RoundingMode rounding() @nogc { return cast(RoundingMode)(getControlState() & ROUNDING_MASK); } /// Clear all pending exceptions, then restore the original exception state and rounding mode. ~this() @nogc { clearExceptions(); if (initialized) setControlState(savedState); } private: ControlState savedState; bool initialized = false; version(AArch64) { alias ControlState = uint; } else version(ARM) { alias ControlState = uint; } else version(PPC_Any) { alias ControlState = uint; } else version(MIPS_Any) { alias ControlState = uint; } else { alias ControlState = ushort; } void initialize() @nogc { // BUG: This works around the absence of this() constructors. if (initialized) return; clearExceptions(); savedState = getControlState(); initialized = true; } // Clear all pending exceptions static void clearExceptions() @nogc { version (LDC) { version (X86_Any) { __asm("fclex", "~{fpsw}"); } else version (PPC_Any) { __asm("mtfsb0 24\n mtfsb0 25\n mtfsb0 26\n mtfsb0 27\n mtfsb0 28", ""); } else version (MIPS_Any) { cast(void) __asm!uint("cfc1 $0, $$31\n andi $0, $0, 0xFFFFF07F\n ctc1 $0, $$31", "=r"); } else version (AArch64) { // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0502f/CIHHDCHB.html cast(void)__asm!uint ("mrs $0, fpsr\n" // use '\n' as ';' is a comment "and $0, $0, #~0x1f\n" "msr fpsr, $0", "=r"); } else version (ARM_SoftFloat) { } else version (ARM) { ControlState old = getControlState(); old &= ~0b11111; // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0408i/Chdfifdc.html __asm("vmsr FPSCR, $0", "r", old); } else assert(0, "Not yet supported"); } else version (InlineAsm_X86_Any) { asm nothrow @nogc { fclex; } } else assert(0, "Not yet supported"); } // Read from the control register static ControlState getControlState() @trusted nothrow @nogc { version (LDC) { ControlState cont; version (X86) { __asm("xor %eax, %eax\n fstcw $0", "=*m,~{eax},~{flags}", &cont); } else version (X86_64) { __asm("xor %rax, %rax\n fstcw $0", "=*m,~{rax},~{flags}", &cont); } else version (PPC_Any) { double fspr = __asm!double("mffs $0", "={f0}"); cont = cast(ControlState) *cast(ulong*) &fspr; } else version (MIPS_Any) { cont = __asm!uint("cfc1 $0, $$31", "=r"); } else version (AArch64) { cont = __asm!ControlState("mrs $0, FPCR", "=r"); } else version (ARM_SoftFloat) { cont = 0; } else version (ARM) { cont = __asm!ControlState("vmrs $0, FPSCR", "=r"); } else assert(0, "Not yet supported"); return cont; } else version (D_InlineAsm_X86) { short cont; asm nothrow @nogc { xor EAX, EAX; fstcw cont; } return cont; } else version (D_InlineAsm_X86_64) { short cont; asm nothrow @nogc { xor RAX, RAX; fstcw cont; } return cont; } else assert(0, "Not yet supported"); } // Set the control register static void setControlState(ControlState newState) @trusted nothrow @nogc { version (LDC) { version (X86) { __asm("fclex\n fldcw $0", "=*m,~{fpsw}", &newState); } else version (X86_64) { __asm("fclex\n fldcw $0", "=*m,~{fpsw}", &newState); } else version (PPC_Any) { ulong tmpState = newState; double fspr = *cast(double*) &tmpState; __asm("mtfsf 0x0f, $0", "f", fspr); } else version (MIPS_Any) { __asm("ctc1 $0, $$31", "r", newState); } else version (AArch64) { __asm("msr FPCR, $0", "r", newState); } else version (ARM_SoftFloat) { } else version (ARM) { __asm("vmsr FPSCR, $0", "r", newState); } else assert(0, "Not yet supported"); } else version (InlineAsm_X86_Any) { version (Win64) { asm nothrow @nogc { naked; mov 8[RSP],RCX; fclex; fldcw 8[RSP]; ret; } } else { asm nothrow @nogc { fclex; fldcw newState; } } } else assert(0, "Not yet supported"); } } unittest { void ensureDefaults() { assert(FloatingPointControl.rounding == FloatingPointControl.roundToNearest); if(FloatingPointControl.hasExceptionTraps) assert(FloatingPointControl.enabledExceptions == 0); } { FloatingPointControl ctrl; } ensureDefaults(); version(D_HardFloat) { { FloatingPointControl ctrl; ctrl.rounding = FloatingPointControl.roundDown; assert(FloatingPointControl.rounding == FloatingPointControl.roundDown); } ensureDefaults(); } if(FloatingPointControl.hasExceptionTraps) { FloatingPointControl ctrl; ctrl.enableExceptions(FloatingPointControl.divByZeroException | FloatingPointControl.overflowException); assert(ctrl.enabledExceptions == (FloatingPointControl.divByZeroException | FloatingPointControl.overflowException)); ctrl.rounding = FloatingPointControl.roundUp; assert(FloatingPointControl.rounding == FloatingPointControl.roundUp); } ensureDefaults(); } /********************************* * Determines if $(D_PARAM x) is NaN. * params: * x = a floating point number. * returns: * $(D true) if $(D_PARAM x) is Nan. */ bool isNaN(X)(X x) @nogc @trusted pure nothrow if (isFloatingPoint!(X)) { alias F = floatTraits!(X); static if (F.realFormat == RealFormat.ieeeSingle) { const uint p = *cast(uint *)&x; return ((p & 0x7F80_0000) == 0x7F80_0000) && p & 0x007F_FFFF; // not infinity } else static if (F.realFormat == RealFormat.ieeeDouble) { const ulong p = *cast(ulong *)&x; return ((p & 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000) && p & 0x000F_FFFF_FFFF_FFFF; // not infinity } else static if (F.realFormat == RealFormat.ieeeExtended) { const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]; const ulong ps = *cast(ulong *)&x; return e == F.EXPMASK && ps & 0x7FFF_FFFF_FFFF_FFFF; // not infinity } else static if (F.realFormat == RealFormat.ieeeQuadruple) { const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]; const ulong psLsb = (cast(ulong *)&x)[MANTISSA_LSB]; const ulong psMsb = (cast(ulong *)&x)[MANTISSA_MSB]; return e == F.EXPMASK && (psLsb | (psMsb& 0x0000_FFFF_FFFF_FFFF)) != 0; } else { return x != x; } } /// @safe pure nothrow @nogc unittest { assert( isNaN(float.init)); assert( isNaN(-double.init)); assert( isNaN(real.nan)); assert( isNaN(-real.nan)); assert(!isNaN(cast(float)53.6)); assert(!isNaN(cast(real)-53.6)); } // Explicitly undocumented. It will be removed in July 2016. @@@DEPRECATED_2016-07@@@ deprecated("isNaN is not defined for integer types") bool isNaN(X)(X x) @nogc @trusted pure nothrow if (isIntegral!(X)) { return isNaN(cast(float)x); } @safe pure nothrow @nogc unittest { import std.meta; foreach(T; AliasSeq!(float, double, real)) { // CTFE-able tests assert(isNaN(T.init)); assert(isNaN(-T.init)); assert(isNaN(T.nan)); assert(isNaN(-T.nan)); assert(!isNaN(T.infinity)); assert(!isNaN(-T.infinity)); assert(!isNaN(cast(T)53.6)); assert(!isNaN(cast(T)-53.6)); // Runtime tests shared T f; f = T.init; assert(isNaN(f)); assert(isNaN(-f)); f = T.nan; assert(isNaN(f)); assert(isNaN(-f)); f = T.infinity; assert(!isNaN(f)); assert(!isNaN(-f)); f = cast(T)53.6; assert(!isNaN(f)); assert(!isNaN(-f)); } } /********************************* * Determines if $(D_PARAM x) is finite. * params: * x = a floating point number. * returns: * $(D true) if $(D_PARAM x) is finite. */ bool isFinite(X)(X x) @trusted pure nothrow @nogc { alias F = floatTraits!(X); ushort* pe = cast(ushort *)&x; return (pe[F.EXPPOS_SHORT] & F.EXPMASK) != F.EXPMASK; } /// @safe pure nothrow @nogc unittest { assert( isFinite(1.23f)); assert( isFinite(float.max)); assert( isFinite(float.min_normal)); assert(!isFinite(float.nan)); assert(!isFinite(float.infinity)); } @safe pure nothrow @nogc unittest { assert(isFinite(1.23)); assert(isFinite(double.max)); assert(isFinite(double.min_normal)); assert(!isFinite(double.nan)); assert(!isFinite(double.infinity)); assert(isFinite(1.23L)); assert(isFinite(real.max)); assert(isFinite(real.min_normal)); assert(!isFinite(real.nan)); assert(!isFinite(real.infinity)); } // Explicitly undocumented. It will be removed in July 2016. @@@DEPRECATED_2016-07@@@ deprecated("isFinite is not defined for integer types") int isFinite(X)(X x) @trusted pure nothrow @nogc if (isIntegral!(X)) { return isFinite(cast(float)x); } /********************************* * Determines if $(D_PARAM x) is normalized. * * A normalized number must not be zero, subnormal, infinite nor $(NAN). * * params: * x = a floating point number. * returns: * $(D true) if $(D_PARAM x) is normalized. */ /* Need one for each format because subnormal floats might * be converted to normal reals. */ bool isNormal(X)(X x) @trusted pure nothrow @nogc { alias F = floatTraits!(X); static if (F.realFormat == RealFormat.ibmExtended) { // doubledouble is normal if the least significant part is normal. return isNormal((cast(double*)&x)[MANTISSA_LSB]); } else { ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]; return (e != F.EXPMASK && e != 0); } } /// @safe pure nothrow @nogc unittest { float f = 3; double d = 500; real e = 10e+48; assert(isNormal(f)); assert(isNormal(d)); assert(isNormal(e)); f = d = e = 0; assert(!isNormal(f)); assert(!isNormal(d)); assert(!isNormal(e)); assert(!isNormal(real.infinity)); assert(isNormal(-real.max)); assert(!isNormal(real.min_normal/4)); } /********************************* * Determines if $(D_PARAM x) is subnormal. * * Subnormals (also known as "denormal number"), have a 0 exponent * and a 0 most significant mantissa bit. * * params: * x = a floating point number. * returns: * $(D true) if $(D_PARAM x) is a denormal number. */ bool isSubnormal(X)(X x) @trusted pure nothrow @nogc { /* Need one for each format because subnormal floats might be converted to normal reals. */ alias F = floatTraits!(X); static if (F.realFormat == RealFormat.ieeeSingle) { uint *p = cast(uint *)&x; return (*p & F.EXPMASK_INT) == 0 && *p & F.MANTISSAMASK_INT; } else static if (F.realFormat == RealFormat.ieeeDouble) { uint *p = cast(uint *)&x; return (p[MANTISSA_MSB] & F.EXPMASK_INT) == 0 && (p[MANTISSA_LSB] || p[MANTISSA_MSB] & F.MANTISSAMASK_INT); } else static if (F.realFormat == RealFormat.ieeeQuadruple) { ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]; long* ps = cast(long *)&x; return (e == 0 && (((ps[MANTISSA_LSB]|(ps[MANTISSA_MSB]& 0x0000_FFFF_FFFF_FFFF))) != 0)); } else static if (F.realFormat == RealFormat.ieeeExtended) { ushort* pe = cast(ushort *)&x; long* ps = cast(long *)&x; return (pe[F.EXPPOS_SHORT] & F.EXPMASK) == 0 && *ps > 0; } else static if (F.realFormat == RealFormat.ibmExtended) { return isSubnormal((cast(double*)&x)[MANTISSA_MSB]); } else { static assert(false, "Not implemented for this architecture"); } } /// @safe pure nothrow @nogc unittest { import std.meta; foreach (T; AliasSeq!(float, double, real)) { T f; for (f = 1.0; !isSubnormal(f); f /= 2) assert(f != 0); } } // Explicitly undocumented. It will be removed in July 2016. @@@DEPRECATED_2016-07@@@ deprecated("isSubnormal is not defined for integer types") int isSubnormal(X)(X x) @trusted pure nothrow @nogc if (isIntegral!X) { return isSubnormal(cast(double)x); } /********************************* * Determines if $(D_PARAM x) is $(PLUSMN)$(INFIN). * params: * x = a floating point number. * returns: * $(D true) if $(D_PARAM x) is $(PLUSMN)$(INFIN). */ bool isInfinity(X)(X x) @nogc @trusted pure nothrow if (isFloatingPoint!(X)) { alias F = floatTraits!(X); static if (F.realFormat == RealFormat.ieeeSingle) { return ((*cast(uint *)&x) & 0x7FFF_FFFF) == 0x7F80_0000; } else static if (F.realFormat == RealFormat.ieeeDouble) { return ((*cast(ulong *)&x) & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FF0_0000_0000_0000; } else static if (F.realFormat == RealFormat.ieeeExtended) { const ushort e = cast(ushort)(F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]); const ulong ps = *cast(ulong *)&x; // On Motorola 68K, infinity can have hidden bit = 1 or 0. On x86, it is always 1. return e == F.EXPMASK && (ps & 0x7FFF_FFFF_FFFF_FFFF) == 0; } else static if (F.realFormat == RealFormat.ibmExtended) { return (((cast(ulong *)&x)[MANTISSA_MSB]) & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FF8_0000_0000_0000; } else static if (F.realFormat == RealFormat.ieeeQuadruple) { const long psLsb = (cast(long *)&x)[MANTISSA_LSB]; const long psMsb = (cast(long *)&x)[MANTISSA_MSB]; return (psLsb == 0) && (psMsb & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_0000_0000_0000; } else { return (x - 1) == x; } } /// @nogc @safe pure nothrow unittest { assert(!isInfinity(float.init)); assert(!isInfinity(-float.init)); assert(!isInfinity(float.nan)); assert(!isInfinity(-float.nan)); assert(isInfinity(float.infinity)); assert(isInfinity(-float.infinity)); assert(isInfinity(-1.0f / 0.0f)); } @safe pure nothrow @nogc unittest { // CTFE-able tests assert(!isInfinity(double.init)); assert(!isInfinity(-double.init)); assert(!isInfinity(double.nan)); assert(!isInfinity(-double.nan)); assert(isInfinity(double.infinity)); assert(isInfinity(-double.infinity)); assert(isInfinity(-1.0 / 0.0)); assert(!isInfinity(real.init)); assert(!isInfinity(-real.init)); assert(!isInfinity(real.nan)); assert(!isInfinity(-real.nan)); assert(isInfinity(real.infinity)); assert(isInfinity(-real.infinity)); assert(isInfinity(-1.0L / 0.0L)); // Runtime tests shared float f; f = float.init; assert(!isInfinity(f)); assert(!isInfinity(-f)); f = float.nan; assert(!isInfinity(f)); assert(!isInfinity(-f)); f = float.infinity; assert(isInfinity(f)); assert(isInfinity(-f)); f = (-1.0f / 0.0f); assert(isInfinity(f)); shared double d; d = double.init; assert(!isInfinity(d)); assert(!isInfinity(-d)); d = double.nan; assert(!isInfinity(d)); assert(!isInfinity(-d)); d = double.infinity; assert(isInfinity(d)); assert(isInfinity(-d)); d = (-1.0 / 0.0); assert(isInfinity(d)); shared real e; e = real.init; assert(!isInfinity(e)); assert(!isInfinity(-e)); e = real.nan; assert(!isInfinity(e)); assert(!isInfinity(-e)); e = real.infinity; assert(isInfinity(e)); assert(isInfinity(-e)); e = (-1.0L / 0.0L); assert(isInfinity(e)); } /********************************* * Is the binary representation of x identical to y? * * Same as ==, except that positive and negative zero are not identical, * and two $(NAN)s are identical if they have the same 'payload'. */ bool isIdentical(real x, real y) @trusted pure nothrow @nogc { // We're doing a bitwise comparison so the endianness is irrelevant. long* pxs = cast(long *)&x; long* pys = cast(long *)&y; alias F = floatTraits!(real); static if (F.realFormat == RealFormat.ieeeDouble) { return pxs[0] == pys[0]; } else static if (F.realFormat == RealFormat.ieeeQuadruple || F.realFormat == RealFormat.ibmExtended) { return pxs[0] == pys[0] && pxs[1] == pys[1]; } else { ushort* pxe = cast(ushort *)&x; ushort* pye = cast(ushort *)&y; return pxe[4] == pye[4] && pxs[0] == pys[0]; } } /********************************* * Return 1 if sign bit of e is set, 0 if not. */ int signbit(X)(X x) @nogc @trusted pure nothrow { alias F = floatTraits!(X); return ((cast(ubyte *)&x)[F.SIGNPOS_BYTE] & 0x80) != 0; } /// @nogc @safe pure nothrow unittest { debug (math) printf("math.signbit.unittest\n"); assert(!signbit(float.nan)); assert(signbit(-float.nan)); assert(!signbit(168.1234f)); assert(signbit(-168.1234f)); assert(!signbit(0.0f)); assert(signbit(-0.0f)); assert(signbit(-float.max)); assert(!signbit(float.max)); assert(!signbit(double.nan)); assert(signbit(-double.nan)); assert(!signbit(168.1234)); assert(signbit(-168.1234)); assert(!signbit(0.0)); assert(signbit(-0.0)); assert(signbit(-double.max)); assert(!signbit(double.max)); assert(!signbit(real.nan)); assert(signbit(-real.nan)); assert(!signbit(168.1234L)); assert(signbit(-168.1234L)); assert(!signbit(0.0L)); assert(signbit(-0.0L)); assert(signbit(-real.max)); assert(!signbit(real.max)); } // Explicitly undocumented. It will be removed in July 2016. @@@DEPRECATED_2016-07@@@ deprecated("signbit is not defined for integer types") int signbit(X)(X x) @nogc @trusted pure nothrow if (isIntegral!X) { return signbit(cast(float)x); } /********************************* * Return a value composed of to with from's sign bit. */ version(LDC) { R copysign(R, X)(R to, X from) @safe pure nothrow @nogc if (isFloatingPoint!(R) && isFloatingPoint!(X)) { return llvm_copysign(to, cast(R) from); } } else { R copysign(R, X)(R to, X from) @trusted pure nothrow @nogc if (isFloatingPoint!(R) && isFloatingPoint!(X)) { ubyte* pto = cast(ubyte *)&to; const ubyte* pfrom = cast(ubyte *)&from; alias T = floatTraits!(R); alias F = floatTraits!(X); pto[T.SIGNPOS_BYTE] &= 0x7F; pto[T.SIGNPOS_BYTE] |= pfrom[F.SIGNPOS_BYTE] & 0x80; return to; } } // ditto R copysign(R, X)(X to, R from) @trusted pure nothrow @nogc if (isIntegral!(X) && isFloatingPoint!(R)) { return copysign(cast(R)to, from); } @safe pure nothrow @nogc unittest { import std.meta; foreach (X; AliasSeq!(float, double, real, int, long)) { foreach (Y; AliasSeq!(float, double, real)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 X x = 21; Y y = 23.8; Y e = void; e = copysign(x, y); assert(e == 21.0); e = copysign(-x, y); assert(e == 21.0); e = copysign(x, -y); assert(e == -21.0); e = copysign(-x, -y); assert(e == -21.0); static if (isFloatingPoint!X) { e = copysign(X.nan, y); assert(isNaN(e) && !signbit(e)); e = copysign(X.nan, -y); assert(isNaN(e) && signbit(e)); } }(); } } // Explicitly undocumented. It will be removed in July 2016. @@@DEPRECATED_2016-07@@@ deprecated("copysign : from can't be of integer type") R copysign(R, X)(X to, R from) @trusted pure nothrow @nogc if (isIntegral!R) { return copysign(to, cast(float)from); } /********************************* Returns $(D -1) if $(D x < 0), $(D x) if $(D x == 0), $(D 1) if $(D x > 0), and $(NAN) if x==$(NAN). */ F sgn(F)(F x) @safe pure nothrow @nogc { // @@@TODO@@@: make this faster return x > 0 ? 1 : x < 0 ? -1 : x; } /// @safe pure nothrow @nogc unittest { assert(sgn(168.1234) == 1); assert(sgn(-168.1234) == -1); assert(sgn(0.0) == 0); assert(sgn(-0.0) == 0); } // Functions for NaN payloads /* * A 'payload' can be stored in the significand of a $(NAN). One bit is required * to distinguish between a quiet and a signalling $(NAN). This leaves 22 bits * of payload for a float; 51 bits for a double; 62 bits for an 80-bit real; * and 111 bits for a 128-bit quad. */ /** * Create a quiet $(NAN), storing an integer inside the payload. * * For floats, the largest possible payload is 0x3F_FFFF. * For doubles, it is 0x3_FFFF_FFFF_FFFF. * For 80-bit or 128-bit reals, it is 0x3FFF_FFFF_FFFF_FFFF. */ real NaN(ulong payload) @trusted pure nothrow @nogc { alias F = floatTraits!(real); static if (F.realFormat == RealFormat.ieeeExtended) { // real80 (in x86 real format, the implied bit is actually // not implied but a real bit which is stored in the real) ulong v = 3; // implied bit = 1, quiet bit = 1 } else { ulong v = 1; // no implied bit. quiet bit = 1 } ulong a = payload; // 22 Float bits ulong w = a & 0x3F_FFFF; a -= w; v <<=22; v |= w; a >>=22; // 29 Double bits v <<=29; w = a & 0xFFF_FFFF; v |= w; a -= w; a >>=29; static if (F.realFormat == RealFormat.ieeeDouble) { v |= 0x7FF0_0000_0000_0000; real x; * cast(ulong *)(&x) = v; return x; } else { v <<=11; a &= 0x7FF; v |= a; real x = real.nan; // Extended real bits static if (F.realFormat == RealFormat.ieeeQuadruple) { v <<= 1; // there's no implicit bit version(LittleEndian) { *cast(ulong*)(6+cast(ubyte*)(&x)) = v; } else { *cast(ulong*)(2+cast(ubyte*)(&x)) = v; } } else { *cast(ulong *)(&x) = v; } return x; } } pure nothrow @nogc unittest { static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) { auto x = NaN(1); auto xl = *cast(ulong*)&x; assert(xl & 0x8_0000_0000_0000UL); //non-signaling bit, bit 52 assert((xl & 0x7FF0_0000_0000_0000UL) == 0x7FF0_0000_0000_0000UL); //all exp bits set } } /** * Extract an integral payload from a $(NAN). * * Returns: * the integer payload as a ulong. * * For floats, the largest possible payload is 0x3F_FFFF. * For doubles, it is 0x3_FFFF_FFFF_FFFF. * For 80-bit or 128-bit reals, it is 0x3FFF_FFFF_FFFF_FFFF. */ ulong getNaNPayload(real x) @trusted pure nothrow @nogc { // assert(isNaN(x)); alias F = floatTraits!(real); static if (F.realFormat == RealFormat.ieeeDouble) { ulong m = *cast(ulong *)(&x); // Make it look like an 80-bit significand. // Skip exponent, and quiet bit m &= 0x0007_FFFF_FFFF_FFFF; m <<= 11; } else static if (F.realFormat == RealFormat.ieeeQuadruple) { version(LittleEndian) { ulong m = *cast(ulong*)(6+cast(ubyte*)(&x)); } else { ulong m = *cast(ulong*)(2+cast(ubyte*)(&x)); } m >>= 1; // there's no implicit bit } else { ulong m = *cast(ulong *)(&x); } // ignore implicit bit and quiet bit ulong f = m & 0x3FFF_FF00_0000_0000L; ulong w = f >>> 40; w |= (m & 0x00FF_FFFF_F800L) << (22 - 11); w |= (m & 0x7FF) << 51; return w; } debug(UnitTest) { @safe pure nothrow @nogc unittest { real nan4 = NaN(0x789_ABCD_EF12_3456); static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended || floatTraits!(real).realFormat == RealFormat.ieeeQuadruple) { assert (getNaNPayload(nan4) == 0x789_ABCD_EF12_3456); } else { assert (getNaNPayload(nan4) == 0x1_ABCD_EF12_3456); } double nan5 = nan4; assert (getNaNPayload(nan5) == 0x1_ABCD_EF12_3456); float nan6 = nan4; assert (getNaNPayload(nan6) == 0x12_3456); nan4 = NaN(0xFABCD); assert (getNaNPayload(nan4) == 0xFABCD); nan6 = nan4; assert (getNaNPayload(nan6) == 0xFABCD); nan5 = NaN(0x100_0000_0000_3456); assert(getNaNPayload(nan5) == 0x0000_0000_3456); } } /** * Calculate the next largest floating point value after x. * * Return the least number greater than x that is representable as a real; * thus, it gives the next point on the IEEE number line. * * $(TABLE_SV * $(SVH x, nextUp(x) ) * $(SV -$(INFIN), -real.max ) * $(SV $(PLUSMN)0.0, real.min_normal*real.epsilon ) * $(SV real.max, $(INFIN) ) * $(SV $(INFIN), $(INFIN) ) * $(SV $(NAN), $(NAN) ) * ) */ real nextUp(real x) @trusted pure nothrow @nogc { alias F = floatTraits!(real); static if (F.realFormat == RealFormat.ieeeDouble) { return nextUp(cast(double)x); } else static if (F.realFormat == RealFormat.ieeeQuadruple) { ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]; if (e == F.EXPMASK) { // NaN or Infinity if (x == -real.infinity) return -real.max; return x; // +Inf and NaN are unchanged. } ulong* ps = cast(ulong *)&e; if (ps[MANTISSA_LSB] & 0x8000_0000_0000_0000) { // Negative number if (ps[MANTISSA_LSB] == 0 && ps[MANTISSA_MSB] == 0x8000_0000_0000_0000) { // it was negative zero, change to smallest subnormal ps[MANTISSA_LSB] = 0x0000_0000_0000_0001; ps[MANTISSA_MSB] = 0; return x; } --*ps; if (ps[MANTISSA_LSB] == 0) --ps[MANTISSA_MSB]; } else { // Positive number ++ps[MANTISSA_LSB]; if (ps[MANTISSA_LSB] == 0) ++ps[MANTISSA_MSB]; } return x; } else static if (F.realFormat == RealFormat.ieeeExtended) { // For 80-bit reals, the "implied bit" is a nuisance... ushort *pe = cast(ushort *)&x; ulong *ps = cast(ulong *)&x; if ((pe[F.EXPPOS_SHORT] & F.EXPMASK) == F.EXPMASK) { // First, deal with NANs and infinity if (x == -real.infinity) return -real.max; return x; // +Inf and NaN are unchanged. } if (pe[F.EXPPOS_SHORT] & 0x8000) { // Negative number -- need to decrease the significand --*ps; // Need to mask with 0x7FFF... so subnormals are treated correctly. if ((*ps & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_FFFF_FFFF_FFFF) { if (pe[F.EXPPOS_SHORT] == 0x8000) // it was negative zero { *ps = 1; pe[F.EXPPOS_SHORT] = 0; // smallest subnormal. return x; } --pe[F.EXPPOS_SHORT]; if (pe[F.EXPPOS_SHORT] == 0x8000) return x; // it's become a subnormal, implied bit stays low. *ps = 0xFFFF_FFFF_FFFF_FFFF; // set the implied bit return x; } return x; } else { // Positive number -- need to increase the significand. // Works automatically for positive zero. ++*ps; if ((*ps & 0x7FFF_FFFF_FFFF_FFFF) == 0) { // change in exponent ++pe[F.EXPPOS_SHORT]; *ps = 0x8000_0000_0000_0000; // set the high bit } } return x; } else // static if (F.realFormat == RealFormat.ibmExtended) { assert (0, "nextUp not implemented"); } } /** ditto */ double nextUp(double x) @trusted pure nothrow @nogc { ulong *ps = cast(ulong *)&x; if ((*ps & 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000) { // First, deal with NANs and infinity if (x == -x.infinity) return -x.max; return x; // +INF and NAN are unchanged. } if (*ps & 0x8000_0000_0000_0000) // Negative number { if (*ps == 0x8000_0000_0000_0000) // it was negative zero { *ps = 0x0000_0000_0000_0001; // change to smallest subnormal return x; } --*ps; } else { // Positive number ++*ps; } return x; } /** ditto */ float nextUp(float x) @trusted pure nothrow @nogc { uint *ps = cast(uint *)&x; if ((*ps & 0x7F80_0000) == 0x7F80_0000) { // First, deal with NANs and infinity if (x == -x.infinity) return -x.max; return x; // +INF and NAN are unchanged. } if (*ps & 0x8000_0000) // Negative number { if (*ps == 0x8000_0000) // it was negative zero { *ps = 0x0000_0001; // change to smallest subnormal return x; } --*ps; } else { // Positive number ++*ps; } return x; } /** * Calculate the next smallest floating point value before x. * * Return the greatest number less than x that is representable as a real; * thus, it gives the previous point on the IEEE number line. * * $(TABLE_SV * $(SVH x, nextDown(x) ) * $(SV $(INFIN), real.max ) * $(SV $(PLUSMN)0.0, -real.min_normal*real.epsilon ) * $(SV -real.max, -$(INFIN) ) * $(SV -$(INFIN), -$(INFIN) ) * $(SV $(NAN), $(NAN) ) * ) */ real nextDown(real x) @safe pure nothrow @nogc { return -nextUp(-x); } /** ditto */ double nextDown(double x) @safe pure nothrow @nogc { return -nextUp(-x); } /** ditto */ float nextDown(float x) @safe pure nothrow @nogc { return -nextUp(-x); } /// @safe pure nothrow @nogc unittest { assert( nextDown(1.0 + real.epsilon) == 1.0); } @safe pure nothrow @nogc unittest { static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) { // Tests for 80-bit reals assert(isIdentical(nextUp(NaN(0xABC)), NaN(0xABC))); // negative numbers assert( nextUp(-real.infinity) == -real.max ); assert( nextUp(-1.0L-real.epsilon) == -1.0 ); assert( nextUp(-2.0L) == -2.0 + real.epsilon); // subnormals and zero assert( nextUp(-real.min_normal) == -real.min_normal*(1-real.epsilon) ); assert( nextUp(-real.min_normal*(1-real.epsilon)) == -real.min_normal*(1-2*real.epsilon) ); assert( isIdentical(-0.0L, nextUp(-real.min_normal*real.epsilon)) ); assert( nextUp(-0.0L) == real.min_normal*real.epsilon ); assert( nextUp(0.0L) == real.min_normal*real.epsilon ); assert( nextUp(real.min_normal*(1-real.epsilon)) == real.min_normal ); assert( nextUp(real.min_normal) == real.min_normal*(1+real.epsilon) ); // positive numbers assert( nextUp(1.0L) == 1.0 + real.epsilon ); assert( nextUp(2.0L-real.epsilon) == 2.0 ); assert( nextUp(real.max) == real.infinity ); assert( nextUp(real.infinity)==real.infinity ); } double n = NaN(0xABC); assert(isIdentical(nextUp(n), n)); // negative numbers assert( nextUp(-double.infinity) == -double.max ); assert( nextUp(-1-double.epsilon) == -1.0 ); assert( nextUp(-2.0) == -2.0 + double.epsilon); // subnormals and zero assert( nextUp(-double.min_normal) == -double.min_normal*(1-double.epsilon) ); assert( nextUp(-double.min_normal*(1-double.epsilon)) == -double.min_normal*(1-2*double.epsilon) ); assert( isIdentical(-0.0, nextUp(-double.min_normal*double.epsilon)) ); assert( nextUp(0.0) == double.min_normal*double.epsilon ); assert( nextUp(-0.0) == double.min_normal*double.epsilon ); assert( nextUp(double.min_normal*(1-double.epsilon)) == double.min_normal ); assert( nextUp(double.min_normal) == double.min_normal*(1+double.epsilon) ); // positive numbers assert( nextUp(1.0) == 1.0 + double.epsilon ); assert( nextUp(2.0-double.epsilon) == 2.0 ); assert( nextUp(double.max) == double.infinity ); float fn = NaN(0xABC); assert(isIdentical(nextUp(fn), fn)); float f = -float.min_normal*(1-float.epsilon); float f1 = -float.min_normal; assert( nextUp(f1) == f); f = 1.0f+float.epsilon; f1 = 1.0f; assert( nextUp(f1) == f ); f1 = -0.0f; assert( nextUp(f1) == float.min_normal*float.epsilon); assert( nextUp(float.infinity)==float.infinity ); assert(nextDown(1.0L+real.epsilon)==1.0); assert(nextDown(1.0+double.epsilon)==1.0); f = 1.0f+float.epsilon; assert(nextDown(f)==1.0); assert(nextafter(1.0+real.epsilon, -real.infinity)==1.0); } /****************************************** * Calculates the next representable value after x in the direction of y. * * If y > x, the result will be the next largest floating-point value; * if y < x, the result will be the next smallest value. * If x == y, the result is y. * * Remarks: * This function is not generally very useful; it's almost always better to use * the faster functions nextUp() or nextDown() instead. * * The FE_INEXACT and FE_OVERFLOW exceptions will be raised if x is finite and * the function result is infinite. The FE_INEXACT and FE_UNDERFLOW * exceptions will be raised if the function value is subnormal, and x is * not equal to y. */ T nextafter(T)(const T x, const T y) @safe pure nothrow @nogc { if (x == y) return y; return ((y>x) ? nextUp(x) : nextDown(x)); } /// @safe pure nothrow @nogc unittest { float a = 1; assert(is(typeof(nextafter(a, a)) == float)); assert(nextafter(a, a.infinity) > a); double b = 2; assert(is(typeof(nextafter(b, b)) == double)); assert(nextafter(b, b.infinity) > b); real c = 3; assert(is(typeof(nextafter(c, c)) == real)); assert(nextafter(c, c.infinity) > c); } //real nexttoward(real x, real y) { return core.stdc.math.nexttowardl(x, y); } /******************************************* * Returns the positive difference between x and y. * Returns: * $(TABLE_SV * $(TR $(TH x, y) $(TH fdim(x, y))) * $(TR $(TD x $(GT) y) $(TD x - y)) * $(TR $(TD x $(LT)= y) $(TD +0.0)) * ) */ real fdim(real x, real y) @safe pure nothrow @nogc { return (x > y) ? x - y : +0.0; } /**************************************** * Returns the larger of x and y. */ static if (__traits(compiles, llvm_maxnum(1.0, 2.0))) // LDC-specific { real fmax(real x, real y) @safe pure nothrow @nogc { return llvm_maxnum(x, y); } //double fmax(double x, double y) @safe pure nothrow @nogc { return llvm_maxnum(x, y); } //float fmax(float x, float y) @safe pure nothrow @nogc { return llvm_maxnum(x, y); } } else real fmax(real x, real y) @safe pure nothrow @nogc { return x > y ? x : y; } /**************************************** * Returns the smaller of x and y. */ static if (__traits(compiles, llvm_minnum(1.0, 2.0))) // LDC-specific { real fmin(real x, real y) @safe pure nothrow @nogc { return llvm_minnum(x, y); } //double fmin(double x, double y) @safe pure nothrow @nogc { return llvm_minnum(x, y); } //float fmin(float x, float y) @safe pure nothrow @nogc { return llvm_minnum(x, y); } } else real fmin(real x, real y) @safe pure nothrow @nogc { return x < y ? x : y; } /************************************** * Returns (x * y) + z, rounding only once according to the * current rounding mode. * * BUGS: Not currently implemented - rounds twice. */ version(LDC) { real fma(real x, real y, real z) @safe pure nothrow @nogc { return llvm_fma(x, y, z); } //double fma(double x, double y, double z) @safe pure nothrow @nogc { return llvm_fma(x, y, z); } //float fma(float x, float y, float z) @safe pure nothrow @nogc { return llvm_fma(x, y, z); } } else { real fma(real x, real y, real z) @safe pure nothrow @nogc { return (x * y) + z; } } /******************************************************************* * Compute the value of x $(SUPERSCRIPT n), where n is an integer */ Unqual!F pow(F, G)(F x, G n) @nogc @trusted pure nothrow if (isFloatingPoint!(F) && isIntegral!(G)) { version(none) { // Leads to linking error on MSVC x64 as the intrinsic maps to // MSVC++ function `pow(double/float, int)` (a C++ template for // Visual Studio 2015). // Most likely not worth the effort anyway (and hindering CTFE). return llvm_powi!(Unqual!F)(x, cast(int) n); } else { real p = 1.0, v = void; Unsigned!(Unqual!G) m = n; if (n < 0) { switch (n) { case -1: return 1 / x; case -2: return 1 / (x * x); default: } m = -n; v = p / x; } else { switch (n) { case 0: return 1.0; case 1: return x; case 2: return x * x; default: } v = x; } while (1) { if (m & 1) p *= v; m >>= 1; if (!m) break; v *= v; } return p; } } @safe pure nothrow @nogc unittest { // Make sure it instantiates and works properly on immutable values and // with various integer and float types. immutable real x = 46; immutable float xf = x; immutable double xd = x; immutable uint one = 1; immutable ushort two = 2; immutable ubyte three = 3; immutable ulong eight = 8; immutable int neg1 = -1; immutable short neg2 = -2; immutable byte neg3 = -3; immutable long neg8 = -8; assert(pow(x,0) == 1.0); assert(pow(xd,one) == x); assert(pow(xf,two) == x * x); assert(pow(x,three) == x * x * x); assert(pow(x,eight) == (x * x) * (x * x) * (x * x) * (x * x)); assert(pow(x, neg1) == 1 / x); version(X86_64) { pragma(msg, "test disabled on x86_64, see bug 5628"); } else version(LDC) { pragma(msg, "test disabled on LDC, see bug 5628"); } else version(ARM) { pragma(msg, "test disabled on ARM, see bug 5628"); } else { assert(pow(xd, neg2) == 1 / (x * x)); assert(pow(xf, neg8) == 1 / ((x * x) * (x * x) * (x * x) * (x * x))); } assert(feqrel(pow(x, neg3), 1 / (x * x * x)) >= real.mant_dig - 1); } unittest { assert(equalsDigit(pow(2.0L, 10.0L), 1024, 19)); } /** Compute the value of an integer x, raised to the power of a positive * integer n. * * If both x and n are 0, the result is 1. * If n is negative, an integer divide error will occur at runtime, * regardless of the value of x. */ typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @trusted pure nothrow if (isIntegral!(F) && isIntegral!(G)) { if (n<0) return x/0; // Only support positive powers typeof(return) p, v = void; Unqual!G m = n; switch (m) { case 0: p = 1; break; case 1: p = x; break; case 2: p = x * x; break; default: v = x; p = 1; while (1){ if (m & 1) p *= v; m >>= 1; if (!m) break; v *= v; } break; } return p; } /// @safe pure nothrow @nogc unittest { immutable int one = 1; immutable byte two = 2; immutable ubyte three = 3; immutable short four = 4; immutable long ten = 10; assert(pow(two, three) == 8); assert(pow(two, ten) == 1024); assert(pow(one, ten) == 1); assert(pow(ten, four) == 10_000); assert(pow(four, 10) == 1_048_576); assert(pow(three, four) == 81); } /**Computes integer to floating point powers.*/ real pow(I, F)(I x, F y) @nogc @trusted pure nothrow if(isIntegral!I && isFloatingPoint!F) { return pow(cast(real) x, cast(Unqual!F) y); } /********************************************* * Calculates x$(SUPERSCRIPT y). * * $(TABLE_SV * $(TR $(TH x) $(TH y) $(TH pow(x, y)) * $(TH div 0) $(TH invalid?)) * $(TR $(TD anything) $(TD $(PLUSMN)0.0) $(TD 1.0) * $(TD no) $(TD no) ) * $(TR $(TD |x| $(GT) 1) $(TD +$(INFIN)) $(TD +$(INFIN)) * $(TD no) $(TD no) ) * $(TR $(TD |x| $(LT) 1) $(TD +$(INFIN)) $(TD +0.0) * $(TD no) $(TD no) ) * $(TR $(TD |x| $(GT) 1) $(TD -$(INFIN)) $(TD +0.0) * $(TD no) $(TD no) ) * $(TR $(TD |x| $(LT) 1) $(TD -$(INFIN)) $(TD +$(INFIN)) * $(TD no) $(TD no) ) * $(TR $(TD +$(INFIN)) $(TD $(GT) 0.0) $(TD +$(INFIN)) * $(TD no) $(TD no) ) * $(TR $(TD +$(INFIN)) $(TD $(LT) 0.0) $(TD +0.0) * $(TD no) $(TD no) ) * $(TR $(TD -$(INFIN)) $(TD odd integer $(GT) 0.0) $(TD -$(INFIN)) * $(TD no) $(TD no) ) * $(TR $(TD -$(INFIN)) $(TD $(GT) 0.0, not odd integer) $(TD +$(INFIN)) * $(TD no) $(TD no)) * $(TR $(TD -$(INFIN)) $(TD odd integer $(LT) 0.0) $(TD -0.0) * $(TD no) $(TD no) ) * $(TR $(TD -$(INFIN)) $(TD $(LT) 0.0, not odd integer) $(TD +0.0) * $(TD no) $(TD no) ) * $(TR $(TD $(PLUSMN)1.0) $(TD $(PLUSMN)$(INFIN)) $(TD $(NAN)) * $(TD no) $(TD yes) ) * $(TR $(TD $(LT) 0.0) $(TD finite, nonintegral) $(TD $(NAN)) * $(TD no) $(TD yes)) * $(TR $(TD $(PLUSMN)0.0) $(TD odd integer $(LT) 0.0) $(TD $(PLUSMNINF)) * $(TD yes) $(TD no) ) * $(TR $(TD $(PLUSMN)0.0) $(TD $(LT) 0.0, not odd integer) $(TD +$(INFIN)) * $(TD yes) $(TD no)) * $(TR $(TD $(PLUSMN)0.0) $(TD odd integer $(GT) 0.0) $(TD $(PLUSMN)0.0) * $(TD no) $(TD no) ) * $(TR $(TD $(PLUSMN)0.0) $(TD $(GT) 0.0, not odd integer) $(TD +0.0) * $(TD no) $(TD no) ) * ) */ version(none) { // FIXME: Use of this LLVM intrinsic causes a unit test failure Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @safe pure nothrow @nogc if (isFloatingPoint!(F) && isFloatingPoint!(G)) { alias Float = typeof(return); return llvm_pow!(Float)(x, y); } } else { Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @nogc @trusted pure nothrow if (isFloatingPoint!(F) && isFloatingPoint!(G)) { alias Float = typeof(return); static real impl(real x, real y) @nogc pure nothrow { // Special cases. if (isNaN(y)) return y; if (isNaN(x) && y != 0.0) return x; // Even if x is NaN. if (y == 0.0) return 1.0; if (y == 1.0) return x; if (isInfinity(y)) { if (fabs(x) > 1) { if (signbit(y)) return +0.0; else return F.infinity; } else if (fabs(x) == 1) { return y * 0; // generate NaN. } else // < 1 { if (signbit(y)) return F.infinity; else return +0.0; } } if (isInfinity(x)) { if (signbit(x)) { long i = cast(long)y; if (y > 0.0) { if (i == y && i & 1) return -F.infinity; else return F.infinity; } else if (y < 0.0) { if (i == y && i & 1) return -0.0; else return +0.0; } } else { if (y > 0.0) return F.infinity; else if (y < 0.0) return +0.0; } } if (x == 0.0) { if (signbit(x)) { long i = cast(long)y; if (y > 0.0) { if (i == y && i & 1) return -0.0; else return +0.0; } else if (y < 0.0) { if (i == y && i & 1) return -F.infinity; else return F.infinity; } } else { if (y > 0.0) return +0.0; else if (y < 0.0) return F.infinity; } } if (x == 1.0) return 1.0; if (y >= F.max) { if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) return 0.0; if (x > 1.0 || x < -1.0) return F.infinity; } if (y <= -F.max) { if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) return F.infinity; if (x > 1.0 || x < -1.0) return 0.0; } if (x >= F.max) { if (y > 0.0) return F.infinity; else return 0.0; } if (x <= -F.max) { long i = cast(long)y; if (y > 0.0) { if (i == y && i & 1) return -F.infinity; else return F.infinity; } else if (y < 0.0) { if (i == y && i & 1) return -0.0; else return +0.0; } } // Integer power of x. long iy = cast(long)y; if (iy == y && fabs(y) < 32768.0) return pow(x, iy); real sign = 1.0; if (x < 0) { // Result is real only if y is an integer // Check for a non-zero fractional part enum maxOdd = pow(2.0L, real.mant_dig) - 1.0L; static if(maxOdd > ulong.max) { // Generic method, for any FP type if(floor(y) != y) return sqrt(x); // Complex result -- create a NaN const hy = ldexp(y, -1); if(floor(hy) != hy) sign = -1.0; } else { // Much faster, if ulong has enough precision const absY = fabs(y); if(absY <= maxOdd) { const uy = cast(ulong)absY; if(uy != absY) return sqrt(x); // Complex result -- create a NaN if(uy & 1) sign = -1.0; } } x = -x; } version(INLINE_YL2X) { // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) // TODO: This is not accurate in practice. A fast and accurate // (though complicated) method is described in: // "An efficient rounding boundary test for pow(x, y) // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). return sign * exp2( yl2x(x, y) ); } else { // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) // TODO: This is not accurate in practice. A fast and accurate // (though complicated) method is described in: // "An efficient rounding boundary test for pow(x, y) // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). Float w = exp2(y * log2(x)); return sign * w; } } return impl(x, y); } } @safe pure nothrow @nogc unittest { // Test all the special values. These unittests can be run on Windows // by temporarily changing the version(linux) to version(all). immutable float zero = 0; immutable real one = 1; immutable double two = 2; immutable float three = 3; immutable float fnan = float.nan; immutable double dnan = double.nan; immutable real rnan = real.nan; immutable dinf = double.infinity; immutable rninf = -real.infinity; assert(pow(fnan, zero) == 1); assert(pow(dnan, zero) == 1); assert(pow(rnan, zero) == 1); assert(pow(two, dinf) == double.infinity); assert(isIdentical(pow(0.2f, dinf), +0.0)); assert(pow(0.99999999L, rninf) == real.infinity); assert(isIdentical(pow(1.000000001, rninf), +0.0)); assert(pow(dinf, 0.001) == dinf); assert(isIdentical(pow(dinf, -0.001), +0.0)); assert(pow(rninf, 3.0L) == rninf); assert(pow(rninf, 2.0L) == real.infinity); assert(isIdentical(pow(rninf, -3.0), -0.0)); assert(isIdentical(pow(rninf, -2.0), +0.0)); // @@@BUG@@@ somewhere version(OSX) {} else assert(isNaN(pow(one, dinf))); version(OSX) {} else assert(isNaN(pow(-one, dinf))); assert(isNaN(pow(-0.2, PI))); // boundary cases. Note that epsilon == 2^^-n for some n, // so 1/epsilon == 2^^n is always even. assert(pow(-1.0L, 1/real.epsilon - 1.0L) == -1.0L); assert(pow(-1.0L, 1/real.epsilon) == 1.0L); assert(isNaN(pow(-1.0L, 1/real.epsilon-0.5L))); assert(isNaN(pow(-1.0L, -1/real.epsilon+0.5L))); assert(pow(0.0, -3.0) == double.infinity); assert(pow(-0.0, -3.0) == -double.infinity); assert(pow(0.0, -PI) == double.infinity); assert(pow(-0.0, -PI) == double.infinity); assert(isIdentical(pow(0.0, 5.0), 0.0)); assert(isIdentical(pow(-0.0, 5.0), -0.0)); assert(isIdentical(pow(0.0, 6.0), 0.0)); assert(isIdentical(pow(-0.0, 6.0), 0.0)); // Issue #14786 fixed immutable real maxOdd = pow(2.0L, real.mant_dig) - 1.0L; assert(pow(-1.0L, maxOdd) == -1.0L); assert(pow(-1.0L, -maxOdd) == -1.0L); assert(pow(-1.0L, maxOdd + 1.0L) == 1.0L); assert(pow(-1.0L, -maxOdd + 1.0L) == 1.0L); assert(pow(-1.0L, maxOdd - 1.0L) == 1.0L); assert(pow(-1.0L, -maxOdd - 1.0L) == 1.0L); // Now, actual numbers. assert(approxEqual(pow(two, three), 8.0)); assert(approxEqual(pow(two, -2.5), 0.1767767)); // Test integer to float power. immutable uint twoI = 2; assert(approxEqual(pow(twoI, three), 8.0)); } /************************************** * To what precision is x equal to y? * * Returns: the number of mantissa bits which are equal in x and y. * eg, 0x1.F8p+60 and 0x1.F1p+60 are equal to 5 bits of precision. * * $(TABLE_SV * $(TR $(TH x) $(TH y) $(TH feqrel(x, y))) * $(TR $(TD x) $(TD x) $(TD real.mant_dig)) * $(TR $(TD x) $(TD $(GT)= 2*x) $(TD 0)) * $(TR $(TD x) $(TD $(LT)= x/2) $(TD 0)) * $(TR $(TD $(NAN)) $(TD any) $(TD 0)) * $(TR $(TD any) $(TD $(NAN)) $(TD 0)) * ) */ int feqrel(X)(const X x, const X y) @trusted pure nothrow @nogc if (isFloatingPoint!(X)) { /* Public Domain. Author: Don Clugston, 18 Aug 2005. */ alias F = floatTraits!(X); static if (F.realFormat == RealFormat.ibmExtended) { if (cast(double*)(&x)[MANTISSA_MSB] == cast(double*)(&y)[MANTISSA_MSB]) { return double.mant_dig + feqrel(cast(double*)(&x)[MANTISSA_LSB], cast(double*)(&y)[MANTISSA_LSB]); } else { return feqrel(cast(double*)(&x)[MANTISSA_MSB], cast(double*)(&y)[MANTISSA_MSB]); } } else { static assert (F.realFormat == RealFormat.ieeeSingle || F.realFormat == RealFormat.ieeeDouble || F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple); if (x == y) return X.mant_dig; // ensure diff!=0, cope with INF. Unqual!X diff = fabs(x - y); ushort *pa = cast(ushort *)(&x); ushort *pb = cast(ushort *)(&y); ushort *pd = cast(ushort *)(&diff); // The difference in abs(exponent) between x or y and abs(x-y) // is equal to the number of significand bits of x which are // equal to y. If negative, x and y have different exponents. // If positive, x and y are equal to 'bitsdiff' bits. // AND with 0x7FFF to form the absolute value. // To avoid out-by-1 errors, we subtract 1 so it rounds down // if the exponents were different. This means 'bitsdiff' is // always 1 lower than we want, except that if bitsdiff==0, // they could have 0 or 1 bits in common. int bitsdiff = ((( (pa[F.EXPPOS_SHORT] & F.EXPMASK) + (pb[F.EXPPOS_SHORT] & F.EXPMASK) - (1 << F.EXPSHIFT)) >> 1) - (pd[F.EXPPOS_SHORT] & F.EXPMASK)) >> F.EXPSHIFT; if ( (pd[F.EXPPOS_SHORT] & F.EXPMASK) == 0) { // Difference is subnormal // For subnormals, we need to add the number of zeros that // lie at the start of diff's significand. // We do this by multiplying by 2^^real.mant_dig diff *= F.RECIP_EPSILON; return bitsdiff + X.mant_dig - ((pd[F.EXPPOS_SHORT] & F.EXPMASK) >> F.EXPSHIFT); } if (bitsdiff > 0) return bitsdiff + 1; // add the 1 we subtracted before // Avoid out-by-1 errors when factor is almost 2. if (bitsdiff == 0 && ((pa[F.EXPPOS_SHORT] ^ pb[F.EXPPOS_SHORT]) & F.EXPMASK) == 0) { return 1; } else return 0; } } @safe pure nothrow @nogc unittest { void testFeqrel(F)() { // Exact equality assert(feqrel(F.max, F.max) == F.mant_dig); assert(feqrel!(F)(0.0, 0.0) == F.mant_dig); assert(feqrel(F.infinity, F.infinity) == F.mant_dig); // a few bits away from exact equality F w=1; for (int i = 1; i < F.mant_dig - 1; ++i) { assert(feqrel!(F)(1.0 + w * F.epsilon, 1.0) == F.mant_dig-i); assert(feqrel!(F)(1.0 - w * F.epsilon, 1.0) == F.mant_dig-i); assert(feqrel!(F)(1.0, 1 + (w-1) * F.epsilon) == F.mant_dig - i + 1); w*=2; } assert(feqrel!(F)(1.5+F.epsilon, 1.5) == F.mant_dig-1); assert(feqrel!(F)(1.5-F.epsilon, 1.5) == F.mant_dig-1); assert(feqrel!(F)(1.5-F.epsilon, 1.5+F.epsilon) == F.mant_dig-2); // Numbers that are close assert(feqrel!(F)(0x1.Bp+84, 0x1.B8p+84) == 5); assert(feqrel!(F)(0x1.8p+10, 0x1.Cp+10) == 2); assert(feqrel!(F)(1.5 * (1 - F.epsilon), 1.0L) == 2); assert(feqrel!(F)(1.5, 1.0) == 1); assert(feqrel!(F)(2 * (1 - F.epsilon), 1.0L) == 1); // Factors of 2 assert(feqrel(F.max, F.infinity) == 0); assert(feqrel!(F)(2 * (1 - F.epsilon), 1.0L) == 1); assert(feqrel!(F)(1.0, 2.0) == 0); assert(feqrel!(F)(4.0, 1.0) == 0); // Extreme inequality assert(feqrel(F.nan, F.nan) == 0); assert(feqrel!(F)(0.0L, -F.nan) == 0); assert(feqrel(F.nan, F.infinity) == 0); assert(feqrel(F.infinity, -F.infinity) == 0); assert(feqrel(F.max, -F.max) == 0); assert(feqrel(F.min_normal / 8, F.min_normal / 17) == 3); const F Const = 2; immutable F Immutable = 2; auto Compiles = feqrel(Const, Immutable); } assert(feqrel(7.1824L, 7.1824L) == real.mant_dig); testFeqrel!(real)(); testFeqrel!(double)(); testFeqrel!(float)(); } package: // Not public yet /* Return the value that lies halfway between x and y on the IEEE number line. * * Formally, the result is the arithmetic mean of the binary significands of x * and y, multiplied by the geometric mean of the binary exponents of x and y. * x and y must have the same sign, and must not be NaN. * Note: this function is useful for ensuring O(log n) behaviour in algorithms * involving a 'binary chop'. * * Special cases: * If x and y are within a factor of 2, (ie, feqrel(x, y) > 0), the return value * is the arithmetic mean (x + y) / 2. * If x and y are even powers of 2, the return value is the geometric mean, * ieeeMean(x, y) = sqrt(x * y). * */ T ieeeMean(T)(const T x, const T y) @trusted pure nothrow @nogc in { // both x and y must have the same sign, and must not be NaN. assert(signbit(x) == signbit(y)); assert(x == x && y == y); } body { // Runtime behaviour for contract violation: // If signs are opposite, or one is a NaN, return 0. if (!((x>=0 && y>=0) || (x<=0 && y<=0))) return 0.0; // The implementation is simple: cast x and y to integers, // average them (avoiding overflow), and cast the result back to a floating-point number. alias F = floatTraits!(T); T u; static if (F.realFormat == RealFormat.ieeeExtended) { // There's slight additional complexity because they are actually // 79-bit reals... ushort *ue = cast(ushort *)&u; ulong *ul = cast(ulong *)&u; ushort *xe = cast(ushort *)&x; ulong *xl = cast(ulong *)&x; ushort *ye = cast(ushort *)&y; ulong *yl = cast(ulong *)&y; // Ignore the useless implicit bit. (Bonus: this prevents overflows) ulong m = ((*xl) & 0x7FFF_FFFF_FFFF_FFFFL) + ((*yl) & 0x7FFF_FFFF_FFFF_FFFFL); // @@@ BUG? @@@ // Cast shouldn't be here ushort e = cast(ushort) ((xe[F.EXPPOS_SHORT] & F.EXPMASK) + (ye[F.EXPPOS_SHORT] & F.EXPMASK)); if (m & 0x8000_0000_0000_0000L) { ++e; m &= 0x7FFF_FFFF_FFFF_FFFFL; } // Now do a multi-byte right shift uint c = e & 1; // carry e >>= 1; m >>>= 1; if (c) m |= 0x4000_0000_0000_0000L; // shift carry into significand if (e) *ul = m | 0x8000_0000_0000_0000L; // set implicit bit... else *ul = m; // ... unless exponent is 0 (subnormal or zero). ue[4]= e | (xe[F.EXPPOS_SHORT]& 0x8000); // restore sign bit } else static if (F.realFormat == RealFormat.ieeeQuadruple) { // This would be trivial if 'ucent' were implemented... ulong *ul = cast(ulong *)&u; ulong *xl = cast(ulong *)&x; ulong *yl = cast(ulong *)&y; // Multi-byte add, then multi-byte right shift. ulong mh = ((xl[MANTISSA_MSB] & 0x7FFF_FFFF_FFFF_FFFFL) + (yl[MANTISSA_MSB] & 0x7FFF_FFFF_FFFF_FFFFL)); // Discard the lowest bit (to avoid overflow) ulong ml = (xl[MANTISSA_LSB]>>>1) + (yl[MANTISSA_LSB]>>>1); // add the lowest bit back in, if necessary. if (xl[MANTISSA_LSB] & yl[MANTISSA_LSB] & 1) { ++ml; if (ml == 0) ++mh; } mh >>>=1; ul[MANTISSA_MSB] = mh | (xl[MANTISSA_MSB] & 0x8000_0000_0000_0000); ul[MANTISSA_LSB] = ml; } else static if (F.realFormat == RealFormat.ieeeDouble) { ulong *ul = cast(ulong *)&u; ulong *xl = cast(ulong *)&x; ulong *yl = cast(ulong *)&y; ulong m = (((*xl) & 0x7FFF_FFFF_FFFF_FFFFL) + ((*yl) & 0x7FFF_FFFF_FFFF_FFFFL)) >>> 1; m |= ((*xl) & 0x8000_0000_0000_0000L); *ul = m; } else static if (F.realFormat == RealFormat.ieeeSingle) { uint *ul = cast(uint *)&u; uint *xl = cast(uint *)&x; uint *yl = cast(uint *)&y; uint m = (((*xl) & 0x7FFF_FFFF) + ((*yl) & 0x7FFF_FFFF)) >>> 1; m |= ((*xl) & 0x8000_0000); *ul = m; } else { assert(0, "Not implemented"); } return u; } @safe pure nothrow @nogc unittest { assert(ieeeMean(-0.0,-1e-20)<0); assert(ieeeMean(0.0,1e-20)>0); assert(ieeeMean(1.0L,4.0L)==2L); assert(ieeeMean(2.0*1.013,8.0*1.013)==4*1.013); assert(ieeeMean(-1.0L,-4.0L)==-2L); assert(ieeeMean(-1.0,-4.0)==-2); assert(ieeeMean(-1.0f,-4.0f)==-2f); assert(ieeeMean(-1.0,-2.0)==-1.5); assert(ieeeMean(-1*(1+8*real.epsilon),-2*(1+8*real.epsilon)) ==-1.5*(1+5*real.epsilon)); assert(ieeeMean(0x1p60,0x1p-10)==0x1p25); static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) { assert(ieeeMean(1.0L,real.infinity)==0x1p8192L); assert(ieeeMean(0.0L,real.infinity)==1.5); } assert(ieeeMean(0.5*real.min_normal*(1-4*real.epsilon),0.5*real.min_normal) == 0.5*real.min_normal*(1-2*real.epsilon)); } public: version (DigitalMars) { version (Windows) version = RealPacked; else version (linux) version = Real4ByteAligned; } else version (LDC) { version (Windows) version = Real4ByteAligned; else version (linux) version = Real4ByteAligned; } /*********************************** * Evaluate polynomial A(x) = $(SUB a, 0) + $(SUB a, 1)x + $(SUB a, 2)$(POWER x,2) * + $(SUB a,3)$(POWER x,3); ... * * Uses Horner's rule A(x) = $(SUB a, 0) + x($(SUB a, 1) + x($(SUB a, 2) * + x($(SUB a, 3) + ...))) * Params: * x = the value to evaluate. * A = array of coefficients $(SUB a, 0), $(SUB a, 1), etc. */ Unqual!(CommonType!(T1, T2)) poly(T1, T2)(T1 x, in T2[] A) @trusted pure nothrow @nogc if (isFloatingPoint!T1 && isFloatingPoint!T2) in { assert(A.length > 0); } body { static if(is(Unqual!T2 == real)) { return polyImpl(x, A); } else { return polyImplBase(x, A); } } /// @safe nothrow @nogc unittest { real x = 3.1; static real[] pp = [56.1, 32.7, 6]; assert(poly(x, pp) == (56.1L + (32.7L + 6.0L * x) * x)); } @safe nothrow @nogc unittest { double x = 3.1; static double[] pp = [56.1, 32.7, 6]; double y = x; y *= 6.0; y += 32.7; y *= x; y += 56.1; assert(poly(x, pp) == y); } unittest { static assert(poly(3.0, [1.0, 2.0, 3.0]) == 34); } private Unqual!(CommonType!(T1, T2)) polyImplBase(T1, T2)(T1 x, in T2[] A) @trusted pure nothrow @nogc if (isFloatingPoint!T1 && isFloatingPoint!T2) { ptrdiff_t i = A.length - 1; typeof(return) r = A[i]; while (--i >= 0) { r *= x; r += A[i]; } return r; } private real polyImpl(real x, in real[] A) @trusted pure nothrow @nogc { version (INLINE_POLY) { if(__ctfe) { return polyImplBase(x, A); } version (RealPacked) { // BUG: This code assumes a frame pointer in EBP. asm pure nothrow @nogc // assembler by W. Bright { // EDX = (A.length - 1) * real.sizeof mov ECX,A[EBP] ; // ECX = A.length dec ECX ; lea EDX,[ECX][ECX*8] ; add EDX,ECX ; add EDX,A+4[EBP] ; fld real ptr [EDX] ; // ST0 = coeff[ECX] jecxz return_ST ; fld x[EBP] ; // ST0 = x fxch ST(1) ; // ST1 = x, ST0 = r align 4 ; L2: fmul ST,ST(1) ; // r *= x fld real ptr -10[EDX] ; sub EDX,10 ; // deg-- faddp ST(1),ST ; dec ECX ; jne L2 ; fxch ST(1) ; // ST1 = r, ST0 = x fstp ST(0) ; // dump x align 4 ; return_ST: ; ; } } else version (Real4ByteAligned) { asm pure nothrow @nogc // assembler by W. Bright { // EDX = (A.length - 1) * real.sizeof mov ECX,A[EBP] ; // ECX = A.length dec ECX ; lea EDX,[ECX*8] ; lea EDX,[EDX][ECX*4] ; add EDX,A+4[EBP] ; fld real ptr [EDX] ; // ST0 = coeff[ECX] jecxz return_ST ; fld x[EBP] ; // ST0 = x fxch ST(1) ; // ST1 = x, ST0 = r align 4 ; L2: fmul ST,ST(1) ; // r *= x fld real ptr -12[EDX] ; sub EDX,12 ; // deg-- faddp ST(1),ST ; dec ECX ; jne L2 ; fxch ST(1) ; // ST1 = r, ST0 = x fstp ST(0) ; // dump x align 4 ; return_ST: ; ; } } else version (OSX) { asm pure nothrow @nogc // assembler by W. Bright { // EDX = (A.length - 1) * real.sizeof mov ECX,A[EBP] ; // ECX = A.length dec ECX ; lea EDX,[ECX*8] ; add EDX,EDX ; add EDX,A+4[EBP] ; fld real ptr [EDX] ; // ST0 = coeff[ECX] jecxz return_ST ; fld x[EBP] ; // ST0 = x fxch ST(1) ; // ST1 = x, ST0 = r align 4 ; L2: fmul ST,ST(1) ; // r *= x fld real ptr -16[EDX] ; sub EDX,16 ; // deg-- faddp ST(1),ST ; dec ECX ; jne L2 ; fxch ST(1) ; // ST1 = r, ST0 = x fstp ST(0) ; // dump x align 4 ; return_ST: ; ; } } else version (FreeBSD) { asm pure nothrow @nogc // assembler by W. Bright { // EDX = (A.length - 1) * real.sizeof mov ECX,A[EBP] ; // ECX = A.length dec ECX ; lea EDX,[ECX*8] ; lea EDX,[EDX][ECX*4] ; add EDX,A+4[EBP] ; fld real ptr [EDX] ; // ST0 = coeff[ECX] jecxz return_ST ; fld x[EBP] ; // ST0 = x fxch ST(1) ; // ST1 = x, ST0 = r align 4 ; L2: fmul ST,ST(1) ; // r *= x fld real ptr -12[EDX] ; sub EDX,12 ; // deg-- faddp ST(1),ST ; dec ECX ; jne L2 ; fxch ST(1) ; // ST1 = r, ST0 = x fstp ST(0) ; // dump x align 4 ; return_ST: ; ; } } else { static assert(0); } } else { return polyImplBase(x, A); } } /** Computes whether $(D lhs) is approximately equal to $(D rhs) admitting a maximum relative difference $(D maxRelDiff) and a maximum absolute difference $(D maxAbsDiff). If the two inputs are ranges, $(D approxEqual) returns true if and only if the ranges have the same number of elements and if $(D approxEqual) evaluates to $(D true) for each pair of elements. */ bool approxEqual(T, U, V)(T lhs, U rhs, V maxRelDiff, V maxAbsDiff = 1e-5) { import std.range; static if (isInputRange!T) { static if (isInputRange!U) { // Two ranges for (;; lhs.popFront(), rhs.popFront()) { if (lhs.empty) return rhs.empty; if (rhs.empty) return lhs.empty; if (!approxEqual(lhs.front, rhs.front, maxRelDiff, maxAbsDiff)) return false; } } else static if (isIntegral!U) { // convert rhs to real return approxEqual(lhs, real(rhs), maxRelDiff, maxAbsDiff); } else { // lhs is range, rhs is number for (; !lhs.empty; lhs.popFront()) { if (!approxEqual(lhs.front, rhs, maxRelDiff, maxAbsDiff)) return false; } return true; } } else { static if (isInputRange!U) { // lhs is number, rhs is array return approxEqual(rhs, lhs, maxRelDiff, maxAbsDiff); } else static if (isIntegral!T || isIntegral!U) { // convert both lhs and rhs to real return approxEqual(real(lhs), real(rhs), maxRelDiff, maxAbsDiff); } else { // two numbers //static assert(is(T : real) && is(U : real)); if (rhs == 0) { return fabs(lhs) <= maxAbsDiff; } static if (is(typeof(lhs.infinity)) && is(typeof(rhs.infinity))) { if (lhs == lhs.infinity && rhs == rhs.infinity || lhs == -lhs.infinity && rhs == -rhs.infinity) return true; } return fabs((lhs - rhs) / rhs) <= maxRelDiff || maxAbsDiff != 0 && fabs(lhs - rhs) <= maxAbsDiff; } } } /** Returns $(D approxEqual(lhs, rhs, 1e-2, 1e-5)). */ bool approxEqual(T, U)(T lhs, U rhs) { return approxEqual(lhs, rhs, 1e-2, 1e-5); } /// @safe pure nothrow unittest { assert(approxEqual(1.0, 1.0099)); assert(!approxEqual(1.0, 1.011)); float[] arr1 = [ 1.0, 2.0, 3.0 ]; double[] arr2 = [ 1.001, 1.999, 3 ]; assert(approxEqual(arr1, arr2)); real num = real.infinity; assert(num == real.infinity); // Passes. assert(approxEqual(num, real.infinity)); // Fails. num = -real.infinity; assert(num == -real.infinity); // Passes. assert(approxEqual(num, -real.infinity)); // Fails. assert(!approxEqual(3, 0)); assert(approxEqual(3, 3)); assert(approxEqual(3.0, 3)); assert(approxEqual([3, 3, 3], 3.0)); assert(approxEqual([3.0, 3.0, 3.0], 3)); int a = 10; assert(approxEqual(10, a)); } // Explicitly undocumented. They will be removed in March 2017. @@@DEPRECATED_2017-03@@@ // Included for backwards compatibility with Phobos1 deprecated("Phobos1 math functions are deprecated, use isNaN") alias isnan = isNaN; deprecated("Phobos1 math functions are deprecated, use isFinite ") alias isfinite = isFinite; deprecated("Phobos1 math functions are deprecated, use isNormal ") alias isnormal = isNormal; deprecated("Phobos1 math functions are deprecated, use isSubnormal ") alias issubnormal = isSubnormal; deprecated("Phobos1 math functions are deprecated, use isInfinity ") alias isinf = isInfinity; /* ********************************** * Building block functions, they * translate to a single x87 instruction. */ version(LDC) { // If INLINE_YL2X is not defined then there is be no reference // to these functions. version(INLINE_YL2X) { real yl2x(real x, real y) @nogc @trusted pure nothrow // y * log2(x) { return __asm!(real)("fyl2x", "={st},{st(1)},{st},~{st(1)}", y, x); } real yl2xp1(real x, real y) @nogc @trusted pure nothrow // y * log2(x + 1) { return __asm!(real)("fyl2xp1", "={st},{st(1)},{st},~{st(1)}", y, x); } } } else { real yl2x(real x, real y) @nogc @safe pure nothrow; // y * log2(x) real yl2xp1(real x, real y) @nogc @safe pure nothrow; // y * log2(x + 1) } @safe pure nothrow @nogc unittest { version (INLINE_YL2X) { assert(yl2x(1024, 1) == 10); assert(yl2xp1(1023, 1) == 10); } } @safe pure nothrow @nogc unittest { real num = real.infinity; assert(num == real.infinity); // Passes. assert(approxEqual(num, real.infinity)); // Fails. } @safe pure nothrow @nogc unittest { float f = sqrt(2.0f); assert(fabs(f * f - 2.0f) < .00001); double d = sqrt(2.0); assert(fabs(d * d - 2.0) < .00001); real r = sqrt(2.0L); assert(fabs(r * r - 2.0) < .00001); } @safe pure nothrow @nogc unittest { float f = fabs(-2.0f); assert(f == 2); double d = fabs(-2.0); assert(d == 2); real r = fabs(-2.0L); assert(r == 2); } @safe pure nothrow @nogc unittest { float f = sin(-2.0f); assert(fabs(f - -0.909297f) < .00001); double d = sin(-2.0); assert(fabs(d - -0.909297f) < .00001); real r = sin(-2.0L); assert(fabs(r - -0.909297f) < .00001); } @safe pure nothrow @nogc unittest { float f = cos(-2.0f); assert(fabs(f - -0.416147f) < .00001); double d = cos(-2.0); assert(fabs(d - -0.416147f) < .00001); real r = cos(-2.0L); assert(fabs(r - -0.416147f) < .00001); } @safe pure nothrow @nogc unittest { float f = tan(-2.0f); assert(fabs(f - 2.18504f) < .00001); double d = tan(-2.0); assert(fabs(d - 2.18504f) < .00001); real r = tan(-2.0L); assert(fabs(r - 2.18504f) < .00001); } @safe pure nothrow unittest { // issue 6381: floor/ceil should be usable in pure function. auto x = floor(1.2); auto y = ceil(1.2); } /*********************************** * Defines a total order on all floating-point numbers. * * The order is defined as follows: * $(UL * $(LI All numbers in [-$(INFIN), +$(INFIN)] are ordered * the same way as by built-in comparison, with the exception of * -0.0, which is less than +0.0;) * $(LI If the sign bit is set (that is, it's 'negative'), $(NAN) is less * than any number; if the sign bit is not set (it is 'positive'), * $(NAN) is greater than any number;) * $(LI $(NAN)s of the same sign are ordered by the payload ('negative' * ones - in reverse order).) * ) * * Returns: * negative value if $(D x) precedes $(D y) in the order specified above; * 0 if $(D x) and $(D y) are identical, and positive value otherwise. * * See_Also: * $(MYREF isIdentical) * Standards: Conforms to IEEE 754-2008 */ int cmp(T)(const(T) x, const(T) y) @nogc @trusted pure nothrow if (isFloatingPoint!T) { alias F = floatTraits!T; static if (F.realFormat == RealFormat.ieeeSingle || F.realFormat == RealFormat.ieeeDouble) { static if (T.sizeof == 4) alias UInt = uint; else alias UInt = ulong; union Repainter { T number; UInt bits; } enum msb = ~(UInt.max >>> 1); import std.typecons : Tuple; Tuple!(Repainter, Repainter) vars = void; vars[0].number = x; vars[1].number = y; foreach (ref var; vars) if (var.bits & msb) var.bits = ~var.bits; else var.bits |= msb; if (vars[0].bits < vars[1].bits) return -1; else if (vars[0].bits > vars[1].bits) return 1; else return 0; } else static if (F.realFormat == RealFormat.ieeeExtended53 || F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple) { static if (F.realFormat == RealFormat.ieeeQuadruple) alias RemT = ulong; else alias RemT = ushort; struct Bits { ulong bulk; RemT rem; } union Repainter { T number; Bits bits; ubyte[T.sizeof] bytes; } import std.typecons : Tuple; Tuple!(Repainter, Repainter) vars = void; vars[0].number = x; vars[1].number = y; foreach (ref var; vars) if (var.bytes[F.SIGNPOS_BYTE] & 0x80) { var.bits.bulk = ~var.bits.bulk; var.bits.rem = ~var.bits.rem; } else { var.bytes[F.SIGNPOS_BYTE] |= 0x80; } version(LittleEndian) { if (vars[0].bits.rem < vars[1].bits.rem) return -1; else if (vars[0].bits.rem > vars[1].bits.rem) return 1; else if (vars[0].bits.bulk < vars[1].bits.bulk) return -1; else if (vars[0].bits.bulk > vars[1].bits.bulk) return 1; else return 0; } else { if (vars[0].bits.bulk < vars[1].bits.bulk) return -1; else if (vars[0].bits.bulk > vars[1].bits.bulk) return 1; else if (vars[0].bits.rem < vars[1].bits.rem) return -1; else if (vars[0].bits.rem > vars[1].bits.rem) return 1; else return 0; } } else { // IBM Extended doubledouble does not follow the general // sign-exponent-significand layout, so has to be handled generically int xSign = signbit(x), ySign = signbit(y); if (xSign == 1 && ySign == 1) return cmp(-y, -x); else if (xSign == 1) return -1; else if (ySign == 1) return 1; else if (x < y) return -1; else if (x == y) return 0; else if (x > y) return 1; else if (isNaN(x) && !isNaN(y)) return 1; else if (isNaN(y) && !isNaN(x)) return -1; else if (getNaNPayload(x) < getNaNPayload(y)) return -1; else if (getNaNPayload(x) > getNaNPayload(y)) return 1; else return 0; } } /// Most numbers are ordered naturally. unittest { assert(cmp(-double.infinity, -double.max) < 0); assert(cmp(-double.max, -100.0) < 0); assert(cmp(-100.0, -0.5) < 0); assert(cmp(-0.5, 0.0) < 0); assert(cmp(0.0, 0.5) < 0); assert(cmp(0.5, 100.0) < 0); assert(cmp(100.0, double.max) < 0); assert(cmp(double.max, double.infinity) < 0); assert(cmp(1.0, 1.0) == 0); } /// Positive and negative zeroes are distinct. unittest { assert(cmp(-0.0, +0.0) < 0); assert(cmp(+0.0, -0.0) > 0); } /// Depending on the sign, $(NAN)s go to either end of the spectrum. unittest { assert(cmp(-double.nan, -double.infinity) < 0); assert(cmp(double.infinity, double.nan) < 0); assert(cmp(-double.nan, double.nan) < 0); } /// $(NAN)s of the same sign are ordered by the payload. unittest { assert(cmp(NaN(10), NaN(20)) < 0); assert(cmp(-NaN(20), -NaN(10)) < 0); } unittest { import std.meta; foreach (T; AliasSeq!(float, double, real)) { T[] values = [-cast(T)NaN(20), -cast(T)NaN(10), -T.nan, -T.infinity, -T.max, -T.max / 2, T(-16.0), T(-1.0).nextDown, T(-1.0), T(-1.0).nextUp, T(-0.5), -T.min_normal, (-T.min_normal).nextUp, -2 * T.min_normal * T.epsilon, -T.min_normal * T.epsilon, T(-0.0), T(0.0), T.min_normal * T.epsilon, 2 * T.min_normal * T.epsilon, T.min_normal.nextDown, T.min_normal, T(0.5), T(1.0).nextDown, T(1.0), T(1.0).nextUp, T(16.0), T.max / 2, T.max, T.infinity, T.nan, cast(T)NaN(10), cast(T)NaN(20)]; foreach (i, x; values) { foreach (y; values[i + 1 .. $]) { assert(cmp(x, y) < 0); assert(cmp(y, x) > 0); } assert(cmp(x, x) == 0); } } } private enum PowType { floor, ceil } pragma(inline, true) private T powIntegralImpl(PowType type, T)(T val) { import core.bitop : bsr; Unqual!T x = val; static if (isSigned!T) if (x < 0) x = abs(x); if (x == 0) return x; static if (type == PowType.ceil) x = cast(Unqual!T) (Unqual!T(1) << bsr(x) + 1); else x = cast(Unqual!T) (Unqual!T(1) << bsr(x)); static if (isSigned!T) if (val < 0) return -x; return x; } pragma(inline, true) private T powFloatingPointImpl(PowType type, T)(T x) { if (!x.isFinite) return x; if (!x) return x; int exp; auto y = frexp(x, exp); static if (type == PowType.ceil) y = ldexp(cast(T) 0.5, exp + 1); else y = ldexp(cast(T) 0.5, exp); if (!y.isFinite) return cast(T) 0.0; y = copysign(y, x); return y; } /** * Gives the next power of two after $(D val). $(T) can be any built-in * numerical type. * * Params: * val = any number * * Returns: * the next power of two after $(D val) */ T nextPow2(T)(const T val) if (isIntegral!T) { return powIntegralImpl!(PowType.ceil)(val); } /// ditto T nextPow2(T)(const T val) if (isFloatingPoint!T) { return powFloatingPointImpl!(PowType.ceil)(val); } /// @safe @nogc pure nothrow unittest { assert(nextPow2(2) == 4); assert(nextPow2(10) == 16); assert(nextPow2(4000) == 4096); assert(nextPow2(-2) == -4); assert(nextPow2(-10) == -16); version(LDC) {} else { // these tests rely on undefined behaviour, i.e. (1 << 33) == 1 // that fails for LDC with optimizations enabled assert(nextPow2(uint.max) == 1); assert(nextPow2(uint.min) == 0); assert(nextPow2(size_t.max) == 1); assert(nextPow2(size_t.min) == 0); assert(nextPow2(int.max) == int.min); assert(nextPow2(int.min) == -1); assert(nextPow2(long.max) == long.min); assert(nextPow2(long.min) == -1); } } /// @safe @nogc pure nothrow unittest { assert(nextPow2(2.1) == 4.0); assert(nextPow2(-2.0) == -4.0); assert(nextPow2(0.25) == 0.5); assert(nextPow2(-4.0) == -8.0); assert(nextPow2(double.max) == 0.0); assert(nextPow2(double.infinity) == double.infinity); } @safe @nogc pure nothrow unittest { assert(nextPow2(ubyte(2)) == 4); assert(nextPow2(ubyte(10)) == 16); assert(nextPow2(byte(2)) == 4); assert(nextPow2(byte(10)) == 16); assert(nextPow2(short(2)) == 4); assert(nextPow2(short(10)) == 16); assert(nextPow2(short(4000)) == 4096); assert(nextPow2(ushort(2)) == 4); assert(nextPow2(ushort(10)) == 16); assert(nextPow2(ushort(4000)) == 4096); } @safe @nogc pure nothrow unittest { foreach (ulong i; 1 .. 62) { assert(nextPow2(1UL<> 32)); else immutable ulong res = val; return *cast(ubyte[8]*) &res; } private ubyte[4] nativeToBigEndian(uint val) @trusted pure nothrow @nogc { version(LittleEndian) immutable uint res = bswap(val); else immutable uint res = val; return *cast(ubyte[4]*) &res; } private ulong bigEndianToNative(ubyte[8] val) @trusted pure nothrow @nogc { version(LittleEndian) { import std.bitmanip : bigEndianToNative; return bigEndianToNative!ulong(val); } else return *cast(ulong*) &val; } private uint bigEndianToNative(ubyte[4] val) @trusted pure nothrow @nogc { version(LittleEndian) return bswap(*cast(uint*) &val); else return *cast(uint*) &val; } //rotateLeft rotates x left n bits private uint rotateLeft(uint x, uint n) @safe pure nothrow @nogc { // With recently added optimization to DMD (commit 32ea0206 at 07/28/11), this is translated to rol. // No assembler required. return (x << n) | (x >> (32-n)); } //rotateRight rotates x right n bits private uint rotateRight(uint x, uint n) @safe pure nothrow @nogc { return (x >> n) | (x << (32-n)); } private ulong rotateRight(ulong x, uint n) @safe pure nothrow @nogc { return (x >> n) | (x << (64-n)); } /** * Template API SHA1/SHA2 implementation. Supports: SHA-1, SHA-224, SHA-256, * SHA-384, SHA-512, SHA-512/224 and SHA-512/256. * * The hashBlockSize and digestSize are in bits. However, it's likely easier to * simply use the convenience aliases: SHA1, SHA224, SHA256, SHA384, SHA512, * SHA512_224 and SHA512_256. * * See $(D std.digest.digest) for differences between template and OOP API. */ struct SHA(uint hashBlockSize, uint digestSize) { enum blockSize = hashBlockSize; static assert(blockSize == 512 || blockSize == 1024, "Invalid SHA blockSize, must be 512 or 1024"); static assert(digestSize == 160 || digestSize == 224 || digestSize == 256 || digestSize == 384 || digestSize == 512, "Invalid SHA digestSize, must be 224, 256, 384 or 512"); static assert(!(blockSize == 512 && digestSize > 256), "Invalid SHA digestSize for a blockSize of 512. The digestSize must be 160, 224 or 256."); static assert(!(blockSize == 1024 && digestSize < 224), "Invalid SHA digestSize for a blockSize of 1024. The digestSize must be 224, 256, 384 or 512."); static if(digestSize==160) /* SHA-1 */ { version(USE_SSSE3) { import core.cpuid : ssse3; import std.internal.digest.sha_SSSE3 : transformSSSE3; static void transform(uint[5]* state, const(ubyte[64])* block) pure nothrow @nogc { return ssse3 ? transformSSSE3(state, block) : transformX86(state, block); } } else { alias transform = transformX86; } } else static if(blockSize == 512) /* SHA-224, SHA-256 */ alias transform = transformSHA2!uint; else static if(blockSize == 1024) /* SHA-384, SHA-512, SHA-512/224, SHA-512/256 */ alias transform = transformSHA2!ulong; else static assert(0); private: /* magic initialization constants - state (ABCDEFGH) */ static if(blockSize == 512 && digestSize == 160) /* SHA-1 */ { uint[5] state = [0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0]; } else static if(blockSize == 512 && digestSize == 224) /* SHA-224 */ { uint[8] state = [ 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4, ]; } else static if(blockSize == 512 && digestSize == 256) /* SHA-256 */ { uint[8] state = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, ]; } else static if(blockSize == 1024 && digestSize == 224) /* SHA-512/224 */ { ulong[8] state = [ 0x8C3D37C8_19544DA2, 0x73E19966_89DCD4D6, 0x1DFAB7AE_32FF9C82, 0x679DD514_582F9FCF, 0x0F6D2B69_7BD44DA8, 0x77E36F73_04C48942, 0x3F9D85A8_6A1D36C8, 0x1112E6AD_91D692A1, ]; } else static if(blockSize == 1024 && digestSize == 256) /* SHA-512/256 */ { ulong[8] state = [ 0x22312194_FC2BF72C, 0x9F555FA3_C84C64C2, 0x2393B86B_6F53B151, 0x96387719_5940EABD, 0x96283EE2_A88EFFE3, 0xBE5E1E25_53863992, 0x2B0199FC_2C85B8AA, 0x0EB72DDC_81C52CA2, ]; } else static if(blockSize == 1024 && digestSize == 384) /* SHA-384 */ { ulong[8] state = [ 0xcbbb9d5d_c1059ed8, 0x629a292a_367cd507, 0x9159015a_3070dd17, 0x152fecd8_f70e5939, 0x67332667_ffc00b31, 0x8eb44a87_68581511, 0xdb0c2e0d_64f98fa7, 0x47b5481d_befa4fa4, ]; } else static if(blockSize == 1024 && digestSize == 512) /* SHA-512 */ { ulong[8] state = [ 0x6a09e667_f3bcc908, 0xbb67ae85_84caa73b, 0x3c6ef372_fe94f82b, 0xa54ff53a_5f1d36f1, 0x510e527f_ade682d1, 0x9b05688c_2b3e6c1f, 0x1f83d9ab_fb41bd6b, 0x5be0cd19_137e2179, ]; } else static assert(0); /* constants */ static if(blockSize == 512) { static immutable uint[64] constants = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ]; } else static if(blockSize == 1024) { static immutable ulong[80] constants = [ 0x428a2f98_d728ae22, 0x71374491_23ef65cd, 0xb5c0fbcf_ec4d3b2f, 0xe9b5dba5_8189dbbc, 0x3956c25b_f348b538, 0x59f111f1_b605d019, 0x923f82a4_af194f9b, 0xab1c5ed5_da6d8118, 0xd807aa98_a3030242, 0x12835b01_45706fbe, 0x243185be_4ee4b28c, 0x550c7dc3_d5ffb4e2, 0x72be5d74_f27b896f, 0x80deb1fe_3b1696b1, 0x9bdc06a7_25c71235, 0xc19bf174_cf692694, 0xe49b69c1_9ef14ad2, 0xefbe4786_384f25e3, 0x0fc19dc6_8b8cd5b5, 0x240ca1cc_77ac9c65, 0x2de92c6f_592b0275, 0x4a7484aa_6ea6e483, 0x5cb0a9dc_bd41fbd4, 0x76f988da_831153b5, 0x983e5152_ee66dfab, 0xa831c66d_2db43210, 0xb00327c8_98fb213f, 0xbf597fc7_beef0ee4, 0xc6e00bf3_3da88fc2, 0xd5a79147_930aa725, 0x06ca6351_e003826f, 0x14292967_0a0e6e70, 0x27b70a85_46d22ffc, 0x2e1b2138_5c26c926, 0x4d2c6dfc_5ac42aed, 0x53380d13_9d95b3df, 0x650a7354_8baf63de, 0x766a0abb_3c77b2a8, 0x81c2c92e_47edaee6, 0x92722c85_1482353b, 0xa2bfe8a1_4cf10364, 0xa81a664b_bc423001, 0xc24b8b70_d0f89791, 0xc76c51a3_0654be30, 0xd192e819_d6ef5218, 0xd6990624_5565a910, 0xf40e3585_5771202a, 0x106aa070_32bbd1b8, 0x19a4c116_b8d2d0c8, 0x1e376c08_5141ab53, 0x2748774c_df8eeb99, 0x34b0bcb5_e19b48a8, 0x391c0cb3_c5c95a63, 0x4ed8aa4a_e3418acb, 0x5b9cca4f_7763e373, 0x682e6ff3_d6b2b8a3, 0x748f82ee_5defb2fc, 0x78a5636f_43172f60, 0x84c87814_a1f0ab72, 0x8cc70208_1a6439ec, 0x90befffa_23631e28, 0xa4506ceb_de82bde9, 0xbef9a3f7_b2c67915, 0xc67178f2_e372532b, 0xca273ece_ea26619c, 0xd186b8c7_21c0c207, 0xeada7dd6_cde0eb1e, 0xf57d4f7f_ee6ed178, 0x06f067aa_72176fba, 0x0a637dc5_a2c898a6, 0x113f9804_bef90dae, 0x1b710b35_131c471b, 0x28db77f5_23047d84, 0x32caab7b_40c72493, 0x3c9ebe0a_15c9bebc, 0x431d67c4_9c100d4c, 0x4cc5d4be_cb3e42b6, 0x597f299c_fc657e2a, 0x5fcb6fab_3ad6faec, 0x6c44198c_4a475817, ]; } else static assert(0); /* * number of bits, modulo 2^64 (ulong[1]) or 2^128 (ulong[2]), * should just use ucent instead of ulong[2] once it's available */ ulong[blockSize/512] count; ubyte[blockSize/8] buffer; /* input buffer */ static immutable ubyte[128] padding = [ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; /* * Basic SHA1/SHA2 functions. */ static @safe pure nothrow @nogc { /* All SHA1/SHA2 */ T Ch(T)(T x, T y, T z) { return z ^ (x & (y ^ z)); } T Maj(T)(T x, T y, T z) { return (x & y) | (z & (x ^ y)); } /* SHA-1 */ uint Parity(uint x, uint y, uint z) { return x ^ y ^ z; } /* SHA-224, SHA-256 */ uint BigSigma0(uint x) { return rotateRight(x, 2) ^ rotateRight(x, 13) ^ rotateRight(x, 22); } uint BigSigma1(uint x) { return rotateRight(x, 6) ^ rotateRight(x, 11) ^ rotateRight(x, 25); } uint SmSigma0(uint x) { return rotateRight(x, 7) ^ rotateRight(x, 18) ^ x >> 3; } uint SmSigma1(uint x) { return rotateRight(x, 17) ^ rotateRight(x, 19) ^ x >> 10; } /* SHA-384, SHA-512, SHA-512/224, SHA-512/256 */ ulong BigSigma0(ulong x) { return rotateRight(x, 28) ^ rotateRight(x, 34) ^ rotateRight(x, 39); } ulong BigSigma1(ulong x) { return rotateRight(x, 14) ^ rotateRight(x, 18) ^ rotateRight(x, 41); } ulong SmSigma0(ulong x) { return rotateRight(x, 1) ^ rotateRight(x, 8) ^ x >> 7; } ulong SmSigma1(ulong x) { return rotateRight(x, 19) ^ rotateRight(x, 61) ^ x >> 6; } } /* * SHA1 basic transformation. Transforms state based on block. */ static void T_0_15(int i, const(ubyte[64])* input, ref uint[16] W, uint A, ref uint B, uint C, uint D, uint E, ref uint T) pure nothrow @nogc { uint Wi = W[i] = bigEndianToNative(*cast(ubyte[4]*)&((*input)[i*4])); T = Ch(B, C, D) + E + rotateLeft(A, 5) + Wi + 0x5a827999; B = rotateLeft(B, 30); } static void T_16_19(int i, ref uint[16] W, uint A, ref uint B, uint C, uint D, uint E, ref uint T) pure nothrow @nogc { W[i&15] = rotateLeft(W[(i-3)&15] ^ W[(i-8)&15] ^ W[(i-14)&15] ^ W[(i-16)&15], 1); T = Ch(B, C, D) + E + rotateLeft(A, 5) + W[i&15] + 0x5a827999; B = rotateLeft(B, 30); } static void T_20_39(int i, ref uint[16] W, uint A, ref uint B, uint C, uint D, uint E, ref uint T) pure nothrow @nogc { W[i&15] = rotateLeft(W[(i-3)&15] ^ W[(i-8)&15] ^ W[(i-14)&15] ^ W[(i-16)&15], 1); T = Parity(B, C, D) + E + rotateLeft(A, 5) + W[i&15] + 0x6ed9eba1; B = rotateLeft(B, 30); } static void T_40_59(int i, ref uint[16] W, uint A, ref uint B, uint C, uint D, uint E, ref uint T) pure nothrow @nogc { W[i&15] = rotateLeft(W[(i-3)&15] ^ W[(i-8)&15] ^ W[(i-14)&15] ^ W[(i-16)&15], 1); T = Maj(B, C, D) + E + rotateLeft(A, 5) + W[i&15] + 0x8f1bbcdc; B = rotateLeft(B, 30); } static void T_60_79(int i, ref uint[16] W, uint A, ref uint B, uint C, uint D, uint E, ref uint T) pure nothrow @nogc { W[i&15] = rotateLeft(W[(i-3)&15] ^ W[(i-8)&15] ^ W[(i-14)&15] ^ W[(i-16)&15], 1); T = Parity(B, C, D) + E + rotateLeft(A, 5) + W[i&15] + 0xca62c1d6; B = rotateLeft(B, 30); } private static void transformX86(uint[5]* state, const(ubyte[64])* block) pure nothrow @nogc { uint A, B, C, D, E, T; uint[16] W = void; A = (*state)[0]; B = (*state)[1]; C = (*state)[2]; D = (*state)[3]; E = (*state)[4]; T_0_15 ( 0, block, W, A, B, C, D, E, T); T_0_15 ( 1, block, W, T, A, B, C, D, E); T_0_15 ( 2, block, W, E, T, A, B, C, D); T_0_15 ( 3, block, W, D, E, T, A, B, C); T_0_15 ( 4, block, W, C, D, E, T, A, B); T_0_15 ( 5, block, W, B, C, D, E, T, A); T_0_15 ( 6, block, W, A, B, C, D, E, T); T_0_15 ( 7, block, W, T, A, B, C, D, E); T_0_15 ( 8, block, W, E, T, A, B, C, D); T_0_15 ( 9, block, W, D, E, T, A, B, C); T_0_15 (10, block, W, C, D, E, T, A, B); T_0_15 (11, block, W, B, C, D, E, T, A); T_0_15 (12, block, W, A, B, C, D, E, T); T_0_15 (13, block, W, T, A, B, C, D, E); T_0_15 (14, block, W, E, T, A, B, C, D); T_0_15 (15, block, W, D, E, T, A, B, C); T_16_19(16, W, C, D, E, T, A, B); T_16_19(17, W, B, C, D, E, T, A); T_16_19(18, W, A, B, C, D, E, T); T_16_19(19, W, T, A, B, C, D, E); T_20_39(20, W, E, T, A, B, C, D); T_20_39(21, W, D, E, T, A, B, C); T_20_39(22, W, C, D, E, T, A, B); T_20_39(23, W, B, C, D, E, T, A); T_20_39(24, W, A, B, C, D, E, T); T_20_39(25, W, T, A, B, C, D, E); T_20_39(26, W, E, T, A, B, C, D); T_20_39(27, W, D, E, T, A, B, C); T_20_39(28, W, C, D, E, T, A, B); T_20_39(29, W, B, C, D, E, T, A); T_20_39(30, W, A, B, C, D, E, T); T_20_39(31, W, T, A, B, C, D, E); T_20_39(32, W, E, T, A, B, C, D); T_20_39(33, W, D, E, T, A, B, C); T_20_39(34, W, C, D, E, T, A, B); T_20_39(35, W, B, C, D, E, T, A); T_20_39(36, W, A, B, C, D, E, T); T_20_39(37, W, T, A, B, C, D, E); T_20_39(38, W, E, T, A, B, C, D); T_20_39(39, W, D, E, T, A, B, C); T_40_59(40, W, C, D, E, T, A, B); T_40_59(41, W, B, C, D, E, T, A); T_40_59(42, W, A, B, C, D, E, T); T_40_59(43, W, T, A, B, C, D, E); T_40_59(44, W, E, T, A, B, C, D); T_40_59(45, W, D, E, T, A, B, C); T_40_59(46, W, C, D, E, T, A, B); T_40_59(47, W, B, C, D, E, T, A); T_40_59(48, W, A, B, C, D, E, T); T_40_59(49, W, T, A, B, C, D, E); T_40_59(50, W, E, T, A, B, C, D); T_40_59(51, W, D, E, T, A, B, C); T_40_59(52, W, C, D, E, T, A, B); T_40_59(53, W, B, C, D, E, T, A); T_40_59(54, W, A, B, C, D, E, T); T_40_59(55, W, T, A, B, C, D, E); T_40_59(56, W, E, T, A, B, C, D); T_40_59(57, W, D, E, T, A, B, C); T_40_59(58, W, C, D, E, T, A, B); T_40_59(59, W, B, C, D, E, T, A); T_60_79(60, W, A, B, C, D, E, T); T_60_79(61, W, T, A, B, C, D, E); T_60_79(62, W, E, T, A, B, C, D); T_60_79(63, W, D, E, T, A, B, C); T_60_79(64, W, C, D, E, T, A, B); T_60_79(65, W, B, C, D, E, T, A); T_60_79(66, W, A, B, C, D, E, T); T_60_79(67, W, T, A, B, C, D, E); T_60_79(68, W, E, T, A, B, C, D); T_60_79(69, W, D, E, T, A, B, C); T_60_79(70, W, C, D, E, T, A, B); T_60_79(71, W, B, C, D, E, T, A); T_60_79(72, W, A, B, C, D, E, T); T_60_79(73, W, T, A, B, C, D, E); T_60_79(74, W, E, T, A, B, C, D); T_60_79(75, W, D, E, T, A, B, C); T_60_79(76, W, C, D, E, T, A, B); T_60_79(77, W, B, C, D, E, T, A); T_60_79(78, W, A, B, C, D, E, T); T_60_79(79, W, T, A, B, C, D, E); (*state)[0] += E; (*state)[1] += T; (*state)[2] += A; (*state)[3] += B; (*state)[4] += C; /* Zeroize sensitive information. */ W[] = 0; } /* * SHA2 basic transformation. Transforms state based on block. */ static void T_SHA2_0_15(Word)(int i, const(ubyte[blockSize/8])* input, ref Word[16] W, Word A, Word B, Word C, ref Word D, Word E, Word F, Word G, ref Word H, Word K) pure nothrow @nogc { Word Wi = W[i] = bigEndianToNative(*cast(ubyte[Word.sizeof]*)&((*input)[i*Word.sizeof])); Word T1 = H + BigSigma1(E) + Ch(E, F, G) + K + Wi; Word T2 = BigSigma0(A) + Maj(A, B, C); D += T1; H = T1 + T2; } static void T_SHA2_16_79(Word)(int i, ref Word[16] W, Word A, Word B, Word C, ref Word D, Word E, Word F, Word G, ref Word H, Word K) pure nothrow @nogc { W[i&15] = SmSigma1(W[(i-2)&15]) + W[(i-7)&15] + SmSigma0(W[(i-15)&15]) + W[i&15]; Word T1 = H + BigSigma1(E) + Ch(E, F, G) + K + W[i&15]; Word T2 = BigSigma0(A) + Maj(A, B, C); D += T1; H = T1 + T2; } private static void transformSHA2(Word)(Word[8]* state, const(ubyte[blockSize/8])* block) pure nothrow @nogc { Word A, B, C, D, E, F, G, H; Word[16] W = void; A = (*state)[0]; B = (*state)[1]; C = (*state)[2]; D = (*state)[3]; E = (*state)[4]; F = (*state)[5]; G = (*state)[6]; H = (*state)[7]; T_SHA2_0_15!Word ( 0, block, W, A, B, C, D, E, F, G, H, constants[ 0]); T_SHA2_0_15!Word ( 1, block, W, H, A, B, C, D, E, F, G, constants[ 1]); T_SHA2_0_15!Word ( 2, block, W, G, H, A, B, C, D, E, F, constants[ 2]); T_SHA2_0_15!Word ( 3, block, W, F, G, H, A, B, C, D, E, constants[ 3]); T_SHA2_0_15!Word ( 4, block, W, E, F, G, H, A, B, C, D, constants[ 4]); T_SHA2_0_15!Word ( 5, block, W, D, E, F, G, H, A, B, C, constants[ 5]); T_SHA2_0_15!Word ( 6, block, W, C, D, E, F, G, H, A, B, constants[ 6]); T_SHA2_0_15!Word ( 7, block, W, B, C, D, E, F, G, H, A, constants[ 7]); T_SHA2_0_15!Word ( 8, block, W, A, B, C, D, E, F, G, H, constants[ 8]); T_SHA2_0_15!Word ( 9, block, W, H, A, B, C, D, E, F, G, constants[ 9]); T_SHA2_0_15!Word (10, block, W, G, H, A, B, C, D, E, F, constants[10]); T_SHA2_0_15!Word (11, block, W, F, G, H, A, B, C, D, E, constants[11]); T_SHA2_0_15!Word (12, block, W, E, F, G, H, A, B, C, D, constants[12]); T_SHA2_0_15!Word (13, block, W, D, E, F, G, H, A, B, C, constants[13]); T_SHA2_0_15!Word (14, block, W, C, D, E, F, G, H, A, B, constants[14]); T_SHA2_0_15!Word (15, block, W, B, C, D, E, F, G, H, A, constants[15]); T_SHA2_16_79!Word(16, W, A, B, C, D, E, F, G, H, constants[16]); T_SHA2_16_79!Word(17, W, H, A, B, C, D, E, F, G, constants[17]); T_SHA2_16_79!Word(18, W, G, H, A, B, C, D, E, F, constants[18]); T_SHA2_16_79!Word(19, W, F, G, H, A, B, C, D, E, constants[19]); T_SHA2_16_79!Word(20, W, E, F, G, H, A, B, C, D, constants[20]); T_SHA2_16_79!Word(21, W, D, E, F, G, H, A, B, C, constants[21]); T_SHA2_16_79!Word(22, W, C, D, E, F, G, H, A, B, constants[22]); T_SHA2_16_79!Word(23, W, B, C, D, E, F, G, H, A, constants[23]); T_SHA2_16_79!Word(24, W, A, B, C, D, E, F, G, H, constants[24]); T_SHA2_16_79!Word(25, W, H, A, B, C, D, E, F, G, constants[25]); T_SHA2_16_79!Word(26, W, G, H, A, B, C, D, E, F, constants[26]); T_SHA2_16_79!Word(27, W, F, G, H, A, B, C, D, E, constants[27]); T_SHA2_16_79!Word(28, W, E, F, G, H, A, B, C, D, constants[28]); T_SHA2_16_79!Word(29, W, D, E, F, G, H, A, B, C, constants[29]); T_SHA2_16_79!Word(30, W, C, D, E, F, G, H, A, B, constants[30]); T_SHA2_16_79!Word(31, W, B, C, D, E, F, G, H, A, constants[31]); T_SHA2_16_79!Word(32, W, A, B, C, D, E, F, G, H, constants[32]); T_SHA2_16_79!Word(33, W, H, A, B, C, D, E, F, G, constants[33]); T_SHA2_16_79!Word(34, W, G, H, A, B, C, D, E, F, constants[34]); T_SHA2_16_79!Word(35, W, F, G, H, A, B, C, D, E, constants[35]); T_SHA2_16_79!Word(36, W, E, F, G, H, A, B, C, D, constants[36]); T_SHA2_16_79!Word(37, W, D, E, F, G, H, A, B, C, constants[37]); T_SHA2_16_79!Word(38, W, C, D, E, F, G, H, A, B, constants[38]); T_SHA2_16_79!Word(39, W, B, C, D, E, F, G, H, A, constants[39]); T_SHA2_16_79!Word(40, W, A, B, C, D, E, F, G, H, constants[40]); T_SHA2_16_79!Word(41, W, H, A, B, C, D, E, F, G, constants[41]); T_SHA2_16_79!Word(42, W, G, H, A, B, C, D, E, F, constants[42]); T_SHA2_16_79!Word(43, W, F, G, H, A, B, C, D, E, constants[43]); T_SHA2_16_79!Word(44, W, E, F, G, H, A, B, C, D, constants[44]); T_SHA2_16_79!Word(45, W, D, E, F, G, H, A, B, C, constants[45]); T_SHA2_16_79!Word(46, W, C, D, E, F, G, H, A, B, constants[46]); T_SHA2_16_79!Word(47, W, B, C, D, E, F, G, H, A, constants[47]); T_SHA2_16_79!Word(48, W, A, B, C, D, E, F, G, H, constants[48]); T_SHA2_16_79!Word(49, W, H, A, B, C, D, E, F, G, constants[49]); T_SHA2_16_79!Word(50, W, G, H, A, B, C, D, E, F, constants[50]); T_SHA2_16_79!Word(51, W, F, G, H, A, B, C, D, E, constants[51]); T_SHA2_16_79!Word(52, W, E, F, G, H, A, B, C, D, constants[52]); T_SHA2_16_79!Word(53, W, D, E, F, G, H, A, B, C, constants[53]); T_SHA2_16_79!Word(54, W, C, D, E, F, G, H, A, B, constants[54]); T_SHA2_16_79!Word(55, W, B, C, D, E, F, G, H, A, constants[55]); T_SHA2_16_79!Word(56, W, A, B, C, D, E, F, G, H, constants[56]); T_SHA2_16_79!Word(57, W, H, A, B, C, D, E, F, G, constants[57]); T_SHA2_16_79!Word(58, W, G, H, A, B, C, D, E, F, constants[58]); T_SHA2_16_79!Word(59, W, F, G, H, A, B, C, D, E, constants[59]); T_SHA2_16_79!Word(60, W, E, F, G, H, A, B, C, D, constants[60]); T_SHA2_16_79!Word(61, W, D, E, F, G, H, A, B, C, constants[61]); T_SHA2_16_79!Word(62, W, C, D, E, F, G, H, A, B, constants[62]); T_SHA2_16_79!Word(63, W, B, C, D, E, F, G, H, A, constants[63]); static if(is(Word==ulong)) { T_SHA2_16_79!Word(64, W, A, B, C, D, E, F, G, H, constants[64]); T_SHA2_16_79!Word(65, W, H, A, B, C, D, E, F, G, constants[65]); T_SHA2_16_79!Word(66, W, G, H, A, B, C, D, E, F, constants[66]); T_SHA2_16_79!Word(67, W, F, G, H, A, B, C, D, E, constants[67]); T_SHA2_16_79!Word(68, W, E, F, G, H, A, B, C, D, constants[68]); T_SHA2_16_79!Word(69, W, D, E, F, G, H, A, B, C, constants[69]); T_SHA2_16_79!Word(70, W, C, D, E, F, G, H, A, B, constants[70]); T_SHA2_16_79!Word(71, W, B, C, D, E, F, G, H, A, constants[71]); T_SHA2_16_79!Word(72, W, A, B, C, D, E, F, G, H, constants[72]); T_SHA2_16_79!Word(73, W, H, A, B, C, D, E, F, G, constants[73]); T_SHA2_16_79!Word(74, W, G, H, A, B, C, D, E, F, constants[74]); T_SHA2_16_79!Word(75, W, F, G, H, A, B, C, D, E, constants[75]); T_SHA2_16_79!Word(76, W, E, F, G, H, A, B, C, D, constants[76]); T_SHA2_16_79!Word(77, W, D, E, F, G, H, A, B, C, constants[77]); T_SHA2_16_79!Word(78, W, C, D, E, F, G, H, A, B, constants[78]); T_SHA2_16_79!Word(79, W, B, C, D, E, F, G, H, A, constants[79]); } (*state)[0] += A; (*state)[1] += B; (*state)[2] += C; (*state)[3] += D; (*state)[4] += E; (*state)[5] += F; (*state)[6] += G; (*state)[7] += H; /* Zeroize sensitive information. */ W[] = 0; } public: /** * SHA initialization. Begins an SHA1/SHA2 operation. * * Note: * For this SHA Digest implementation calling start after default construction * is not necessary. Calling start is only necessary to reset the Digest. * * Generic code which deals with different Digest types should always call start though. * * Example: * -------- * SHA1 digest; * //digest.start(); //Not necessary * digest.put(0); * -------- */ void start() @safe pure nothrow @nogc { this = typeof(this).init; } /** * Use this to feed the digest with data. * Also implements the $(XREF_PACK range,primitives,isOutputRange) * interface for $(D ubyte) and $(D const(ubyte)[]). */ void put(scope const(ubyte)[] input...) @trusted pure nothrow @nogc { enum blockSizeInBytes = blockSize/8; uint i, index, partLen; auto inputLen = input.length; /* Compute number of bytes mod block size (64 or 128 bytes) */ index = (cast(uint)count[0] >> 3) & (blockSizeInBytes - 1); /* Update number of bits */ static if(blockSize==512) count[0] += inputLen * 8; else static if(blockSize==1024) { /* ugly hack to work around lack of ucent */ auto oldCount0 = count[0]; count[0] += inputLen * 8; if(count[0] < oldCount0) count[1]++; } else static assert(0); partLen = blockSizeInBytes - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { (&buffer[index])[0 .. partLen] = input.ptr[0 .. partLen]; transform (&state, &buffer); for (i = partLen; i + blockSizeInBytes-1 < inputLen; i += blockSizeInBytes) transform(&state, cast(ubyte[blockSizeInBytes]*)(input.ptr + i)); index = 0; } else i = 0; /* Buffer remaining input */ if (inputLen - i) (&buffer[index])[0 .. inputLen-i] = (&input[i])[0 .. inputLen-i]; } /// unittest { typeof(this) dig; dig.put(cast(ubyte)0); //single ubyte dig.put(cast(ubyte)0, cast(ubyte)0); //variadic ubyte[10] buf; dig.put(buf); //buffer } /** * Returns the finished SHA hash. This also calls $(LREF start) to * reset the internal state. */ ubyte[digestSize/8] finish() @trusted pure nothrow @nogc { static if(blockSize==512) { ubyte[32] data = void; uint index, padLen; /* Save number of bits */ ubyte[8] bits = nativeToBigEndian(count[0]); /* Pad out to 56 mod 64. */ index = (cast(uint)count[0] >> 3) & (64 - 1); padLen = (index < 56) ? (56 - index) : (120 - index); put(padding[0 .. padLen]); /* Append length (before padding) */ put(bits); /* Store state in digest */ for (auto i = 0; i < ((digestSize == 160)? 5 : 8); i++) data[i*4..(i+1)*4] = nativeToBigEndian(state[i])[]; /* Zeroize sensitive information. */ start(); return data[0..digestSize/8]; } else static if(blockSize==1024) { ubyte[64] data = void; uint index, padLen; /* Save number of bits */ ubyte[16] bits; bits[ 0..8] = nativeToBigEndian(count[1]); bits[8..16] = nativeToBigEndian(count[0]); /* Pad out to 112 mod 128. */ index = (cast(uint)count[0] >> 3) & (128 - 1); padLen = (index < 112) ? (112 - index) : (240 - index); put(padding[0 .. padLen]); /* Append length (before padding) */ put(bits); /* Store state in digest */ for (auto i = 0; i < 8; i++) data[i*8..(i+1)*8] = nativeToBigEndian(state[i])[]; /* Zeroize sensitive information. */ start(); return data[0..digestSize/8]; } else static assert(0); } /// unittest { //Simple example SHA1 hash; hash.start(); hash.put(cast(ubyte)0); ubyte[20] result = hash.finish(); } } alias SHA1 = SHA!(512, 160); /// SHA alias for SHA-1, hash is ubyte[20] alias SHA224 = SHA!(512, 224); /// SHA alias for SHA-224, hash is ubyte[28] alias SHA256 = SHA!(512, 256); /// SHA alias for SHA-256, hash is ubyte[32] alias SHA384 = SHA!(1024, 384); /// SHA alias for SHA-384, hash is ubyte[48] alias SHA512 = SHA!(1024, 512); /// SHA alias for SHA-512, hash is ubyte[64] alias SHA512_224 = SHA!(1024, 224); /// SHA alias for SHA-512/224, hash is ubyte[28] alias SHA512_256 = SHA!(1024, 256); /// SHA alias for SHA-512/256, hash is ubyte[32] /// unittest { //Simple example, hashing a string using sha1Of helper function ubyte[20] hash = sha1Of("abc"); //Let's get a hash string assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); //The same, but using SHA-224 ubyte[28] hash224 = sha224Of("abc"); assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); } /// unittest { //Using the basic API SHA1 hash; hash.start(); ubyte[1024] data; //Initialize data here... hash.put(data); ubyte[20] result = hash.finish(); } /// unittest { //Let's use the template features: //Note: When passing a SHA1 to a function, it must be passed by reference! void doSomething(T)(ref T hash) if(isDigest!T) { hash.put(cast(ubyte)0); } SHA1 sha; sha.start(); doSomething(sha); assert(toHexString(sha.finish()) == "5BA93C9DB0CFF93F52B521D7420E43F6EDA2784F"); } unittest { assert(isDigest!SHA1); assert(isDigest!SHA224); assert(isDigest!SHA256); assert(isDigest!SHA384); assert(isDigest!SHA512); assert(isDigest!SHA512_224); assert(isDigest!SHA512_256); } unittest { import std.range; ubyte[20] digest; ubyte[28] digest224; ubyte[32] digest256; ubyte[48] digest384; ubyte[64] digest512; ubyte[28] digest512_224; ubyte[32] digest512_256; SHA1 sha; sha.put(cast(ubyte[])"abcdef"); sha.start(); sha.put(cast(ubyte[])""); assert(sha.finish() == cast(ubyte[])x"da39a3ee5e6b4b0d3255bfef95601890afd80709"); SHA224 sha224; sha224.put(cast(ubyte[])"abcdef"); sha224.start(); sha224.put(cast(ubyte[])""); assert(sha224.finish() == cast(ubyte[])x"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"); SHA256 sha256; sha256.put(cast(ubyte[])"abcdef"); sha256.start(); sha256.put(cast(ubyte[])""); assert(sha256.finish() == cast(ubyte[])x"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); SHA384 sha384; sha384.put(cast(ubyte[])"abcdef"); sha384.start(); sha384.put(cast(ubyte[])""); assert(sha384.finish() == cast(ubyte[])x"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"); SHA512 sha512; sha512.put(cast(ubyte[])"abcdef"); sha512.start(); sha512.put(cast(ubyte[])""); assert(sha512.finish() == cast(ubyte[])x"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"); SHA512_224 sha512_224; sha512_224.put(cast(ubyte[])"abcdef"); sha512_224.start(); sha512_224.put(cast(ubyte[])""); assert(sha512_224.finish() == cast(ubyte[])x"6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"); SHA512_256 sha512_256; sha512_256.put(cast(ubyte[])"abcdef"); sha512_256.start(); sha512_256.put(cast(ubyte[])""); assert(sha512_256.finish() == cast(ubyte[])x"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"); digest = sha1Of (""); digest224 = sha224Of (""); digest256 = sha256Of (""); digest384 = sha384Of (""); digest512 = sha512Of (""); digest512_224 = sha512_224Of(""); digest512_256 = sha512_256Of(""); assert(digest == cast(ubyte[])x"da39a3ee5e6b4b0d3255bfef95601890afd80709"); assert(digest224 == cast(ubyte[])x"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"); assert(digest256 == cast(ubyte[])x"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); assert(digest384 == cast(ubyte[])x"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"); assert(digest512 == cast(ubyte[])x"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"); assert(digest512_224 == cast(ubyte[])x"6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"); assert(digest512_256 == cast(ubyte[])x"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"); digest = sha1Of ("a"); digest224 = sha224Of ("a"); digest256 = sha256Of ("a"); digest384 = sha384Of ("a"); digest512 = sha512Of ("a"); digest512_224 = sha512_224Of("a"); digest512_256 = sha512_256Of("a"); assert(digest == cast(ubyte[])x"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"); assert(digest224 == cast(ubyte[])x"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5"); assert(digest256 == cast(ubyte[])x"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"); assert(digest384 == cast(ubyte[])x"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31"); assert(digest512 == cast(ubyte[])x"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75"); assert(digest512_224 == cast(ubyte[])x"d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327"); assert(digest512_256 == cast(ubyte[])x"455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8"); digest = sha1Of ("abc"); digest224 = sha224Of ("abc"); digest256 = sha256Of ("abc"); digest384 = sha384Of ("abc"); digest512 = sha512Of ("abc"); digest512_224 = sha512_224Of("abc"); digest512_256 = sha512_256Of("abc"); assert(digest == cast(ubyte[])x"a9993e364706816aba3e25717850c26c9cd0d89d"); assert(digest224 == cast(ubyte[])x"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"); assert(digest256 == cast(ubyte[])x"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); assert(digest384 == cast(ubyte[])x"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"); assert(digest512 == cast(ubyte[])x"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"); assert(digest512_224 == cast(ubyte[])x"4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"); assert(digest512_256 == cast(ubyte[])x"53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"); digest = sha1Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); digest224 = sha224Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); digest256 = sha256Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); digest384 = sha384Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); digest512 = sha512Of ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); digest512_224 = sha512_224Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); digest512_256 = sha512_256Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); assert(digest == cast(ubyte[])x"84983e441c3bd26ebaae4aa1f95129e5e54670f1"); assert(digest224 == cast(ubyte[])x"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525"); assert(digest256 == cast(ubyte[])x"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); assert(digest384 == cast(ubyte[])x"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b"); assert(digest512 == cast(ubyte[])x"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445"); assert(digest512_224 == cast(ubyte[])x"e5302d6d54bb242275d1e7622d68df6eb02dedd13f564c13dbda2174"); assert(digest512_256 == cast(ubyte[])x"bde8e1f9f19bb9fd3406c90ec6bc47bd36d8ada9f11880dbc8a22a7078b6a461"); digest = sha1Of ("message digest"); digest224 = sha224Of ("message digest"); digest256 = sha256Of ("message digest"); digest384 = sha384Of ("message digest"); digest512 = sha512Of ("message digest"); digest512_224 = sha512_224Of("message digest"); digest512_256 = sha512_256Of("message digest"); assert(digest == cast(ubyte[])x"c12252ceda8be8994d5fa0290a47231c1d16aae3"); assert(digest224 == cast(ubyte[])x"2cb21c83ae2f004de7e81c3c7019cbcb65b71ab656b22d6d0c39b8eb"); assert(digest256 == cast(ubyte[])x"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"); assert(digest384 == cast(ubyte[])x"473ed35167ec1f5d8e550368a3db39be54639f828868e9454c239fc8b52e3c61dbd0d8b4de1390c256dcbb5d5fd99cd5"); assert(digest512 == cast(ubyte[])x"107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c"); assert(digest512_224 == cast(ubyte[])x"ad1a4db188fe57064f4f24609d2a83cd0afb9b398eb2fcaeaae2c564"); assert(digest512_256 == cast(ubyte[])x"0cf471fd17ed69d990daf3433c89b16d63dec1bb9cb42a6094604ee5d7b4e9fb"); digest = sha1Of ("abcdefghijklmnopqrstuvwxyz"); digest224 = sha224Of ("abcdefghijklmnopqrstuvwxyz"); digest256 = sha256Of ("abcdefghijklmnopqrstuvwxyz"); digest384 = sha384Of ("abcdefghijklmnopqrstuvwxyz"); digest512 = sha512Of ("abcdefghijklmnopqrstuvwxyz"); digest512_224 = sha512_224Of("abcdefghijklmnopqrstuvwxyz"); digest512_256 = sha512_256Of("abcdefghijklmnopqrstuvwxyz"); assert(digest == cast(ubyte[])x"32d10c7b8cf96570ca04ce37f2a19d84240d3a89"); assert(digest224 == cast(ubyte[])x"45a5f72c39c5cff2522eb3429799e49e5f44b356ef926bcf390dccc2"); assert(digest256 == cast(ubyte[])x"71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73"); assert(digest384 == cast(ubyte[])x"feb67349df3db6f5924815d6c3dc133f091809213731fe5c7b5f4999e463479ff2877f5f2936fa63bb43784b12f3ebb4"); assert(digest512 == cast(ubyte[])x"4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1"); assert(digest512_224 == cast(ubyte[])x"ff83148aa07ec30655c1b40aff86141c0215fe2a54f767d3f38743d8"); assert(digest512_256 == cast(ubyte[])x"fc3189443f9c268f626aea08a756abe7b726b05f701cb08222312ccfd6710a26"); digest = sha1Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); digest224 = sha224Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); digest256 = sha256Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); digest384 = sha384Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); digest512 = sha512Of ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); digest512_224 = sha512_224Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); digest512_256 = sha512_256Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); assert(digest == cast(ubyte[])x"761c457bf73b14d27e9e9265c46f4b4dda11f940"); assert(digest224 == cast(ubyte[])x"bff72b4fcb7d75e5632900ac5f90d219e05e97a7bde72e740db393d9"); assert(digest256 == cast(ubyte[])x"db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0"); assert(digest384 == cast(ubyte[])x"1761336e3f7cbfe51deb137f026f89e01a448e3b1fafa64039c1464ee8732f11a5341a6f41e0c202294736ed64db1a84"); assert(digest512 == cast(ubyte[])x"1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894"); assert(digest512_224 == cast(ubyte[])x"a8b4b9174b99ffc67d6f49be9981587b96441051e16e6dd036b140d3"); assert(digest512_256 == cast(ubyte[])x"cdf1cc0effe26ecc0c13758f7b4a48e000615df241284185c39eb05d355bb9c8"); digest = sha1Of ("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); digest224 = sha224Of ("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); digest256 = sha256Of ("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); digest384 = sha384Of ("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); digest512 = sha512Of ("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); digest512_224 = sha512_224Of("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); digest512_256 = sha512_256Of("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); assert(digest == cast(ubyte[])x"50abf5706a150990a08b2c5ea40fa0e585554732"); assert(digest224 == cast(ubyte[])x"b50aecbe4e9bb0b57bc5f3ae760a8e01db24f203fb3cdcd13148046e"); assert(digest256 == cast(ubyte[])x"f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e"); assert(digest384 == cast(ubyte[])x"b12932b0627d1c060942f5447764155655bd4da0c9afa6dd9b9ef53129af1b8fb0195996d2de9ca0df9d821ffee67026"); assert(digest512 == cast(ubyte[])x"72ec1ef1124a45b047e8b7c75a932195135bb61de24ec0d1914042246e0aec3a2354e093d76f3048b456764346900cb130d2a4fd5dd16abb5e30bcb850dee843"); assert(digest512_224 == cast(ubyte[])x"ae988faaa47e401a45f704d1272d99702458fea2ddc6582827556dd2"); assert(digest512_256 == cast(ubyte[])x"2c9fdbc0c90bdd87612ee8455474f9044850241dc105b1e8b94b8ddf5fac9148"); ubyte[] onemilliona = new ubyte[1000000]; onemilliona[] = 'a'; digest = sha1Of(onemilliona); digest224 = sha224Of(onemilliona); digest256 = sha256Of(onemilliona); digest384 = sha384Of(onemilliona); digest512 = sha512Of(onemilliona); digest512_224 = sha512_224Of(onemilliona); digest512_256 = sha512_256Of(onemilliona); assert(digest == cast(ubyte[])x"34aa973cd4c4daa4f61eeb2bdbad27316534016f"); assert(digest224 == cast(ubyte[])x"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67"); assert(digest256 == cast(ubyte[])x"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); assert(digest384 == cast(ubyte[])x"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985"); assert(digest512 == cast(ubyte[])x"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"); assert(digest512_224 == cast(ubyte[])x"37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287"); assert(digest512_256 == cast(ubyte[])x"9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21"); auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); digest = sha1Of(oneMillionRange); digest224 = sha224Of(oneMillionRange); digest256 = sha256Of(oneMillionRange); digest384 = sha384Of(oneMillionRange); digest512 = sha512Of(oneMillionRange); digest512_224 = sha512_224Of(oneMillionRange); digest512_256 = sha512_256Of(oneMillionRange); assert(digest == cast(ubyte[])x"34aa973cd4c4daa4f61eeb2bdbad27316534016f"); assert(digest224 == cast(ubyte[])x"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67"); assert(digest256 == cast(ubyte[])x"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); assert(digest384 == cast(ubyte[])x"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985"); assert(digest512 == cast(ubyte[])x"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"); assert(digest512_224 == cast(ubyte[])x"37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287"); assert(digest512_256 == cast(ubyte[])x"9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21"); assert(toHexString(cast(ubyte[20])x"a9993e364706816aba3e25717850c26c9cd0d89d") == "A9993E364706816ABA3E25717850C26C9CD0D89D"); } /** * These are convenience aliases for $(XREF_PACK digest,digest,digest) using the * SHA implementation. */ //simple alias doesn't work here, hope this gets inlined... auto sha1Of(T...)(T data) { return digest!(SHA1, T)(data); } ///ditto auto sha224Of(T...)(T data) { return digest!(SHA224, T)(data); } ///ditto auto sha256Of(T...)(T data) { return digest!(SHA256, T)(data); } ///ditto auto sha384Of(T...)(T data) { return digest!(SHA384, T)(data); } ///ditto auto sha512Of(T...)(T data) { return digest!(SHA512, T)(data); } ///ditto auto sha512_224Of(T...)(T data) { return digest!(SHA512_224, T)(data); } ///ditto auto sha512_256Of(T...)(T data) { return digest!(SHA512_256, T)(data); } /// unittest { ubyte[20] hash = sha1Of("abc"); assert(hash == digest!SHA1("abc")); ubyte[28] hash224 = sha224Of("abc"); assert(hash224 == digest!SHA224("abc")); ubyte[32] hash256 = sha256Of("abc"); assert(hash256 == digest!SHA256("abc")); ubyte[48] hash384 = sha384Of("abc"); assert(hash384 == digest!SHA384("abc")); ubyte[64] hash512 = sha512Of("abc"); assert(hash512 == digest!SHA512("abc")); ubyte[28] hash512_224 = sha512_224Of("abc"); assert(hash512_224 == digest!SHA512_224("abc")); ubyte[32] hash512_256 = sha512_256Of("abc"); assert(hash512_256 == digest!SHA512_256("abc")); } unittest { string a = "Mary has ", b = "a little lamb"; int[] c = [ 1, 2, 3, 4, 5 ]; string d = toHexString(sha1Of(a, b, c)); version(LittleEndian) assert(d == "CDBB611D00AC2387B642D3D7BDF4C3B342237110", d); else assert(d == "A0F1196C7A379C09390476D9CA4AA11B71FD11C8", d); } /** * OOP API SHA1 and SHA2 implementations. * See $(D std.digest.digest) for differences between template and OOP API. * * This is an alias for $(D $(XREF_PACK digest,digest,WrapperDigest)!SHA1), see * there for more information. */ alias SHA1Digest = WrapperDigest!SHA1; alias SHA224Digest = WrapperDigest!SHA224; ///ditto alias SHA256Digest = WrapperDigest!SHA256; ///ditto alias SHA384Digest = WrapperDigest!SHA384; ///ditto alias SHA512Digest = WrapperDigest!SHA512; ///ditto alias SHA512_224Digest = WrapperDigest!SHA512_224; ///ditto alias SHA512_256Digest = WrapperDigest!SHA512_256; ///ditto /// unittest { //Simple example, hashing a string using Digest.digest helper function auto sha = new SHA1Digest(); ubyte[] hash = sha.digest("abc"); //Let's get a hash string assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); //The same, but using SHA-224 auto sha224 = new SHA224Digest(); ubyte[] hash224 = sha224.digest("abc"); //Let's get a hash string assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); } /// unittest { //Let's use the OOP features: void test(Digest dig) { dig.put(cast(ubyte)0); } auto sha = new SHA1Digest(); test(sha); //Let's use a custom buffer: ubyte[20] buf; ubyte[] result = sha.finish(buf[]); assert(toHexString(result) == "5BA93C9DB0CFF93F52B521D7420E43F6EDA2784F"); } unittest { auto sha = new SHA1Digest(); sha.put(cast(ubyte[])"abcdef"); sha.reset(); sha.put(cast(ubyte[])""); assert(sha.finish() == cast(ubyte[])x"da39a3ee5e6b4b0d3255bfef95601890afd80709"); sha.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz"); ubyte[22] result; auto result2 = sha.finish(result[]); assert(result[0 .. 20] == result2 && result2 == cast(ubyte[])x"32d10c7b8cf96570ca04ce37f2a19d84240d3a89"); debug assertThrown!Error(sha.finish(result[0 .. 15])); assert(sha.length == 20); assert(sha.digest("") == cast(ubyte[])x"da39a3ee5e6b4b0d3255bfef95601890afd80709"); assert(sha.digest("a") == cast(ubyte[])x"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"); assert(sha.digest("abc") == cast(ubyte[])x"a9993e364706816aba3e25717850c26c9cd0d89d"); assert(sha.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") == cast(ubyte[])x"84983e441c3bd26ebaae4aa1f95129e5e54670f1"); assert(sha.digest("message digest") == cast(ubyte[])x"c12252ceda8be8994d5fa0290a47231c1d16aae3"); assert(sha.digest("abcdefghijklmnopqrstuvwxyz") == cast(ubyte[])x"32d10c7b8cf96570ca04ce37f2a19d84240d3a89"); assert(sha.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") == cast(ubyte[])x"761c457bf73b14d27e9e9265c46f4b4dda11f940"); assert(sha.digest("1234567890123456789012345678901234567890", "1234567890123456789012345678901234567890") == cast(ubyte[])x"50abf5706a150990a08b2c5ea40fa0e585554732"); ubyte[] onemilliona = new ubyte[1000000]; onemilliona[] = 'a'; assert(sha.digest(onemilliona) == cast(ubyte[])x"34aa973cd4c4daa4f61eeb2bdbad27316534016f"); } ldc-1.1.0-beta3-src/runtime/phobos/std/digest/md.d0000664000175000017500000004406512776215007017743 0ustar kaikai/** * Computes MD5 hashes of arbitrary data. MD5 hashes are 16 byte quantities that are like a * checksum or CRC, but are more robust. * $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Functions) ) $(TR $(TDNW Template API) $(TD $(MYREF MD5) ) ) $(TR $(TDNW OOP API) $(TD $(MYREF MD5Digest)) ) $(TR $(TDNW Helpers) $(TD $(MYREF md5Of)) ) ) ) * This module conforms to the APIs defined in $(D std.digest.digest). To understand the * differences between the template and the OOP API, see $(D std.digest.digest). * * This module publicly imports $(D std.digest.digest) and can be used as a stand-alone * module. * * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * * CTFE: * Digests do not work in CTFE * * Authors: * Piotr Szturmaj, Kai Nacke, Johannes Pfau $(BR) * The routines and algorithms are derived from the $(I RSA Data Security, Inc. MD5 Message-Digest Algorithm). * * References: * $(LINK2 http://en.wikipedia.org/wiki/Md5, Wikipedia on MD5) * * Source: $(PHOBOSSRC std/digest/_md.d) * * Macros: * WIKI = Phobos/StdMd5 */ /* md5.d - RSA Data Security, Inc., MD5 message-digest algorithm * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. */ module std.digest.md; public import std.digest.digest; /// unittest { //Template API import std.digest.md; //Feeding data ubyte[1024] data; MD5 md5; md5.start(); md5.put(data[]); md5.start(); //Start again md5.put(data[]); auto hash = md5.finish(); } /// unittest { //OOP API import std.digest.md; auto md5 = new MD5Digest(); ubyte[] hash = md5.digest("abc"); assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); //Feeding data ubyte[1024] data; md5.put(data[]); md5.reset(); //Start again md5.put(data[]); hash = md5.finish(); } //rotateLeft rotates x left n bits private uint rotateLeft(uint x, uint n) @safe pure nothrow @nogc { // With recently added optimization to DMD (commit 32ea0206 at 07/28/11), this is translated to rol. // No assembler required. return (x << n) | (x >> (32-n)); } /** * Template API MD5 implementation. * See $(D std.digest.digest) for differences between template and OOP API. */ struct MD5 { private: // magic initialization constants uint[4] _state = [0x67452301,0xefcdab89,0x98badcfe,0x10325476]; // state (ABCD) ulong _count; //number of bits, modulo 2^64 ubyte[64] _buffer; // input buffer static immutable ubyte[64] _padding = [ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; // F, G, H and I are basic MD5 functions static @safe pure nothrow @nogc { uint F(uint x, uint y, uint z) { return (x & y) | (~x & z); } uint G(uint x, uint y, uint z) { return (x & z) | (y & ~z); } uint H(uint x, uint y, uint z) { return x ^ y ^ z; } uint I(uint x, uint y, uint z) { return y ^ (x | ~z); } } /* * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. * Rotation is separate from addition to prevent recomputation. */ static void FF(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) @safe pure nothrow @nogc { a += F (b, c, d) + x + ac; a = rotateLeft(a, s); a += b; } static void GG(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) @safe pure nothrow @nogc { a += G (b, c, d) + x + ac; a = rotateLeft(a, s); a += b; } static void HH(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) @safe pure nothrow @nogc { a += H (b, c, d) + x + ac; a = rotateLeft(a, s); a += b; } static void II(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) @safe pure nothrow @nogc { a += I (b, c, d) + x + ac; a = rotateLeft(a, s); a += b; } /* * MD5 basic transformation. Transforms state based on block. */ //Constants for MD5Transform routine. enum { S11 = 7, S12 = 12, S13 = 17, S14 = 22, S21 = 5, S22 = 9, S23 = 14, S24 = 20, S31 = 4, S32 = 11, S33 = 16, S34 = 23, S41 = 6, S42 = 10, S43 = 15, S44 = 21, } private void transform(const(ubyte[64])* block) pure nothrow @nogc { uint a = _state[0], b = _state[1], c = _state[2], d = _state[3]; uint[16] x = void; version(BigEndian) { import std.bitmanip : littleEndianToNative; for(size_t i = 0; i < 16; i++) { x[i] = littleEndianToNative!uint(*cast(ubyte[4]*)&(*block)[i*4]); } } else { (cast(ubyte*)x.ptr)[0 .. 64] = (cast(ubyte*)block)[0 .. 64]; } //Round 1 FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ //Round 2 GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ //Round 3 HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ //Round 4 II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ _state[0] += a; _state[1] += b; _state[2] += c; _state[3] += d; //Zeroize sensitive information. x[] = 0; } public: enum blockSize = 512; /** * Use this to feed the digest with data. * Also implements the $(XREF_PACK range,primitives,isOutputRange) * interface for $(D ubyte) and $(D const(ubyte)[]). * * Example: * ---- * MD5 dig; * dig.put(cast(ubyte)0); //single ubyte * dig.put(cast(ubyte)0, cast(ubyte)0); //variadic * ubyte[10] buf; * dig.put(buf); //buffer * ---- */ void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc { uint i, index, partLen; auto inputLen = data.length; //Compute number of bytes mod 64 index = (cast(uint)_count >> 3) & (64 - 1); //Update number of bits _count += inputLen * 8; partLen = 64 - index; //Transform as many times as possible if (inputLen >= partLen) { (&_buffer[index])[0 .. partLen] = data.ptr[0 .. partLen]; transform(&_buffer); for(i = partLen; i + 63 < inputLen; i += 64) { transform(cast(const(ubyte[64])*)(data[i .. i + 64].ptr)); } index = 0; } else { i = 0; } /* Buffer remaining input */ if (inputLen - i) (&_buffer[index])[0 .. inputLen-i] = (&data[i])[0 .. inputLen-i]; } /** * Used to (re)initialize the MD5 digest. * * Note: * For this MD5 Digest implementation calling start after default construction * is not necessary. Calling start is only necessary to reset the Digest. * * Generic code which deals with different Digest types should always call start though. * * Example: * -------- * MD5 digest; * //digest.start(); //Not necessary * digest.put(0); * -------- */ void start() @safe pure nothrow @nogc { this = MD5.init; } /** * Returns the finished MD5 hash. This also calls $(LREF start) to * reset the internal state. */ ubyte[16] finish() @trusted pure nothrow @nogc { import std.bitmanip : nativeToLittleEndian; ubyte[16] data = void; ubyte[8] bits = void; uint index, padLen; //Save number of bits bits[0 .. 8] = nativeToLittleEndian(_count)[]; //Pad out to 56 mod 64 index = (cast(uint)_count >> 3) & (64 - 1); padLen = (index < 56) ? (56 - index) : (120 - index); put(_padding[0 .. padLen]); //Append length (before padding) put(bits); //Store state in digest data[0 .. 4] = nativeToLittleEndian(_state[0])[]; data[4 .. 8] = nativeToLittleEndian(_state[1])[]; data[8 .. 12] = nativeToLittleEndian(_state[2])[]; data[12 .. 16] = nativeToLittleEndian(_state[3])[]; /* Zeroize sensitive information. */ start(); return data; } /// unittest { //Simple example MD5 hash; hash.start(); hash.put(cast(ubyte)0); ubyte[16] result = hash.finish(); } } /// unittest { //Simple example, hashing a string using md5Of helper function ubyte[16] hash = md5Of("abc"); //Let's get a hash string assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); } /// unittest { //Using the basic API MD5 hash; hash.start(); ubyte[1024] data; //Initialize data here... hash.put(data); ubyte[16] result = hash.finish(); } /// unittest { //Let's use the template features: void doSomething(T)(ref T hash) if(isDigest!T) { hash.put(cast(ubyte)0); } MD5 md5; md5.start(); doSomething(md5); assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); } unittest { assert(isDigest!MD5); } unittest { import std.range; ubyte[16] digest; MD5 md5; md5.put(cast(ubyte[])"abcdef"); md5.start(); md5.put(cast(ubyte[])""); assert(md5.finish() == cast(ubyte[])x"d41d8cd98f00b204e9800998ecf8427e"); digest = md5Of(""); assert(digest == cast(ubyte[])x"d41d8cd98f00b204e9800998ecf8427e"); digest = md5Of("a"); assert(digest == cast(ubyte[])x"0cc175b9c0f1b6a831c399e269772661"); digest = md5Of("abc"); assert(digest == cast(ubyte[])x"900150983cd24fb0d6963f7d28e17f72"); digest = md5Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); assert(digest == cast(ubyte[])x"8215ef0796a20bcaaae116d3876c664a"); digest = md5Of("message digest"); assert(digest == cast(ubyte[])x"f96b697d7cb7938d525a2f31aaf161d0"); digest = md5Of("abcdefghijklmnopqrstuvwxyz"); assert(digest == cast(ubyte[])x"c3fcd3d76192e4007dfb496cca67e13b"); digest = md5Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); assert(digest == cast(ubyte[])x"d174ab98d277d9f5a5611c2c9f419d9f"); digest = md5Of("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); assert(digest == cast(ubyte[])x"57edf4a22be3c955ac49da2e2107b67a"); assert(toHexString(cast(ubyte[16])x"c3fcd3d76192e4007dfb496cca67e13b") == "C3FCD3D76192E4007DFB496CCA67E13B"); ubyte[] onemilliona = new ubyte[1000000]; onemilliona[] = 'a'; digest = md5Of(onemilliona); assert(digest == cast(ubyte[])x"7707D6AE4E027C70EEA2A935C2296F21"); auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); digest = md5Of(oneMillionRange); assert(digest == cast(ubyte[])x"7707D6AE4E027C70EEA2A935C2296F21"); } /** * This is a convenience alias for $(XREF_PACK digest,digest,digest) using the * MD5 implementation. */ //simple alias doesn't work here, hope this gets inlined... auto md5Of(T...)(T data) { return digest!(MD5, T)(data); } /// unittest { ubyte[16] hash = md5Of("abc"); assert(hash == digest!MD5("abc")); } /** * OOP API MD5 implementation. * See $(D std.digest.digest) for differences between template and OOP API. * * This is an alias for $(D $(XREF_PACK digest,digest,WrapperDigest)!MD5), see * there for more information. */ alias MD5Digest = WrapperDigest!MD5; /// unittest { //Simple example, hashing a string using Digest.digest helper function auto md5 = new MD5Digest(); ubyte[] hash = md5.digest("abc"); //Let's get a hash string assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); } /// unittest { //Let's use the OOP features: void test(Digest dig) { dig.put(cast(ubyte)0); } auto md5 = new MD5Digest(); test(md5); //Let's use a custom buffer: ubyte[16] buf; ubyte[] result = md5.finish(buf[]); assert(toHexString(result) == "93B885ADFE0DA089CDF634904FD59F71"); } unittest { auto md5 = new MD5Digest(); md5.put(cast(ubyte[])"abcdef"); md5.reset(); md5.put(cast(ubyte[])""); assert(md5.finish() == cast(ubyte[])x"d41d8cd98f00b204e9800998ecf8427e"); md5.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz"); ubyte[20] result; auto result2 = md5.finish(result[]); assert(result[0 .. 16] == result2 && result2 == cast(ubyte[])x"c3fcd3d76192e4007dfb496cca67e13b"); debug { import std.exception; assertThrown!Error(md5.finish(result[0 .. 15])); } assert(md5.length == 16); assert(md5.digest("") == cast(ubyte[])x"d41d8cd98f00b204e9800998ecf8427e"); assert(md5.digest("a") == cast(ubyte[])x"0cc175b9c0f1b6a831c399e269772661"); assert(md5.digest("abc") == cast(ubyte[])x"900150983cd24fb0d6963f7d28e17f72"); assert(md5.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") == cast(ubyte[])x"8215ef0796a20bcaaae116d3876c664a"); assert(md5.digest("message digest") == cast(ubyte[])x"f96b697d7cb7938d525a2f31aaf161d0"); assert(md5.digest("abcdefghijklmnopqrstuvwxyz") == cast(ubyte[])x"c3fcd3d76192e4007dfb496cca67e13b"); assert(md5.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") == cast(ubyte[])x"d174ab98d277d9f5a5611c2c9f419d9f"); assert(md5.digest("1234567890123456789012345678901234567890", "1234567890123456789012345678901234567890") == cast(ubyte[])x"57edf4a22be3c955ac49da2e2107b67a"); } ldc-1.1.0-beta3-src/runtime/phobos/std/digest/crc.d0000664000175000017500000003357412776215007020115 0ustar kaikai/** Cyclic Redundancy Check (32-bit) implementation. $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Functions) ) $(TR $(TDNW Template API) $(TD $(MYREF CRC32) ) ) $(TR $(TDNW OOP API) $(TD $(MYREF CRC32Digest)) ) $(TR $(TDNW Helpers) $(TD $(MYREF crcHexString) $(MYREF crc32Of)) ) ) ) * * This module conforms to the APIs defined in $(D std.digest.digest). To understand the * differences between the template and the OOP API, see $(D std.digest.digest). * * This module publicly imports $(D std.digest.digest) and can be used as a stand-alone * module. * * Note: * CRCs are usually printed with the MSB first. When using * $(XREF_PACK digest,digest,toHexString) the result will be in an unexpected * order. Use $(XREF_PACK digest,digest,toHexString)'s optional order parameter * to specify decreasing order for the correct result. The $(LREF crcHexString) * alias can also be used for this purpose. * * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * * Authors: Pavel "EvilOne" Minayev, Alex Rønne Petersen, Johannes Pfau * * References: * $(LINK2 http://en.wikipedia.org/wiki/Cyclic_redundancy_check, Wikipedia on CRC) * * Source: $(PHOBOSSRC std/digest/_crc.d) * * Macros: * WIKI = Phobos/StdUtilDigestCRC32 * * Standards: * Implements the 'common' IEEE CRC32 variant * (LSB-first order, Initial value uint.max, complement result) * * CTFE: * Digests do not work in CTFE */ /* * Copyright (c) 2001 - 2002 * Pavel "EvilOne" Minayev * Copyright (c) 2012 * Alex Rønne Petersen * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.digest.crc; public import std.digest.digest; version(unittest) import std.exception; /// unittest { //Template API import std.digest.crc; ubyte[4] hash = crc32Of("The quick brown fox jumps over the lazy dog"); assert(crcHexString(hash) == "414FA339"); //Feeding data ubyte[1024] data; CRC32 crc; crc.put(data[]); crc.start(); //Start again crc.put(data[]); hash = crc.finish(); } /// unittest { //OOP API import std.digest.crc; auto crc = new CRC32Digest(); ubyte[] hash = crc.digest("The quick brown fox jumps over the lazy dog"); assert(crcHexString(hash) == "414FA339"); //352441c2 //Feeding data ubyte[1024] data; crc.put(data[]); crc.reset(); //Start again crc.put(data[]); hash = crc.finish(); } private immutable uint[256] crc32_table = [ 0x00000000,0x77073096,0xee0e612c,0x990951ba,0x076dc419,0x706af48f,0xe963a535, 0x9e6495a3,0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,0x09b64c2b,0x7eb17cbd, 0xe7b82d07,0x90bf1d91,0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de,0x1adad47d, 0x6ddde4eb,0xf4d4b551,0x83d385c7,0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec, 0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,0x3b6e20c8,0x4c69105e,0xd56041e4, 0xa2677172,0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,0x35b5a8fa,0x42b2986c, 0xdbbbc9d6,0xacbcf940,0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,0x26d930ac, 0x51de003a,0xc8d75180,0xbfd06116,0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f, 0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,0x2f6f7c87,0x58684c11,0xc1611dab, 0xb6662d3d,0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,0x71b18589,0x06b6b51f, 0x9fbfe4a5,0xe8b8d433,0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,0x7f6a0dbb, 0x086d3d2d,0x91646c97,0xe6635c01,0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e, 0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,0x65b0d9c6,0x12b7e950,0x8bbeb8ea, 0xfcb9887c,0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,0x4db26158,0x3ab551ce, 0xa3bc0074,0xd4bb30e2,0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,0x4369e96a, 0x346ed9fc,0xad678846,0xda60b8d0,0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9, 0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,0x5768b525,0x206f85b3,0xb966d409, 0xce61e49f,0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,0x59b33d17,0x2eb40d81, 0xb7bd5c3b,0xc0ba6cad,0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,0xead54739, 0x9dd277af,0x04db2615,0x73dc1683,0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8, 0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,0xf00f9344,0x8708a3d2,0x1e01f268, 0x6906c2fe,0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,0xfed41b76,0x89d32be0, 0x10da7a5a,0x67dd4acc,0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,0xd6d6a3e8, 0xa1d1937e,0x38d8c2c4,0x4fdff252,0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b, 0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,0xdf60efc3,0xa867df55,0x316e8eef, 0x4669be79,0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,0xcc0c7795,0xbb0b4703, 0x220216b9,0x5505262f,0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,0xc2d7ffa7, 0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a, 0x9c0906a9,0xeb0e363f,0x72076785,0x05005713,0x95bf4a82,0xe2b87a14,0x7bb12bae, 0x0cb61b38,0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,0x86d3d2d4,0xf1d4e242, 0x68ddb3f8,0x1fda836e,0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,0x88085ae6, 0xff0f6a70,0x66063bca,0x11010b5c,0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45, 0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,0xa7672661,0xd06016f7,0x4969474d, 0x3e6e77db,0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0,0xa9bcae53,0xdebb9ec5, 0x47b2cf7f,0x30b5ffe9,0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,0xbad03605, 0xcdd70693,0x54de5729,0x23d967bf,0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94, 0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d ]; /** * Template API CRC32 implementation. * See $(D std.digest.digest) for differences between template and OOP API. */ struct CRC32 { private: // magic initialization constants uint _state = uint.max; public: /** * Use this to feed the digest with data. * Also implements the $(XREF_PACK range,primitives,isOutputRange) * interface for $(D ubyte) and $(D const(ubyte)[]). */ void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc { foreach (val; data) _state = (_state >> 8) ^ crc32_table[cast(ubyte)_state ^ val]; } /// unittest { CRC32 dig; dig.put(cast(ubyte)0); //single ubyte dig.put(cast(ubyte)0, cast(ubyte)0); //variadic ubyte[10] buf; dig.put(buf); //buffer } /** * Used to initialize the CRC32 digest. * * Note: * For this CRC32 Digest implementation calling start after default construction * is not necessary. Calling start is only necessary to reset the Digest. * * Generic code which deals with different Digest types should always call start though. */ void start() @safe pure nothrow @nogc { this = CRC32.init; } /// unittest { CRC32 digest; //digest.start(); //Not necessary digest.put(0); } /** * Returns the finished CRC32 hash. This also calls $(LREF start) to * reset the internal state. */ ubyte[4] finish() @safe pure nothrow @nogc { auto tmp = peek(); start(); return tmp; } /// unittest { //Simple example CRC32 hash; hash.put(cast(ubyte)0); ubyte[4] result = hash.finish(); } /** * Works like $(D finish) but does not reset the internal state, so it's possible * to continue putting data into this CRC32 after a call to peek. */ ubyte[4] peek() const @safe pure nothrow @nogc { import std.bitmanip : nativeToLittleEndian; //Complement, LSB first / Little Endian, see http://rosettacode.org/wiki/CRC-32 return nativeToLittleEndian(~_state); } } /// unittest { //Simple example, hashing a string using crc32Of helper function ubyte[4] hash = crc32Of("abc"); //Let's get a hash string assert(crcHexString(hash) == "352441C2"); } /// unittest { //Using the basic API CRC32 hash; ubyte[1024] data; //Initialize data here... hash.put(data); ubyte[4] result = hash.finish(); } /// unittest { //Let's use the template features: //Note: When passing a CRC32 to a function, it must be passed by reference! void doSomething(T)(ref T hash) if(isDigest!T) { hash.put(cast(ubyte)0); } CRC32 crc; crc.start(); doSomething(crc); assert(crcHexString(crc.finish()) == "D202EF8D"); } unittest { assert(isDigest!CRC32); } unittest { ubyte[4] digest; CRC32 crc; crc.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz"); assert(crc.peek() == cast(ubyte[])x"bd50274c"); crc.start(); crc.put(cast(ubyte[])""); assert(crc.finish() == cast(ubyte[])x"00000000"); digest = crc32Of(""); assert(digest == cast(ubyte[])x"00000000"); //Test vector from http://rosettacode.org/wiki/CRC-32 assert(crcHexString(crc32Of("The quick brown fox jumps over the lazy dog")) == "414FA339"); digest = crc32Of("a"); assert(digest == cast(ubyte[])x"43beb7e8"); digest = crc32Of("abc"); assert(digest == cast(ubyte[])x"c2412435"); digest = crc32Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); assert(digest == cast(ubyte[])x"5f3f1a17"); digest = crc32Of("message digest"); assert(digest == cast(ubyte[])x"7f9d1520"); digest = crc32Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); assert(digest == cast(ubyte[])x"d2e6c21f"); digest = crc32Of("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); assert(digest == cast(ubyte[])x"724aa97c"); assert(crcHexString(cast(ubyte[4])x"c3fcd3d7") == "D7D3FCC3"); } /** * This is a convenience alias for $(XREF_PACK digest,digest,digest) using the * CRC32 implementation. * * Params: * data = $(D InputRange) of $(D ElementType) implicitly convertible to * $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) or one or more arrays * of any type. * * Returns: * CRC32 of data */ //simple alias doesn't work here, hope this gets inlined... ubyte[4] crc32Of(T...)(T data) { return digest!(CRC32, T)(data); } /// unittest { ubyte[] data = [4,5,7,25]; assert(data.crc32Of == [167, 180, 199, 131]); import std.utf : byChar; assert("hello"d.byChar.crc32Of == [134, 166, 16, 54]); ubyte[4] hash = "abc".crc32Of(); assert(hash == digest!CRC32("ab", "c")); import std.range : iota; enum ubyte S = 5, F = 66; assert(iota(S, F).crc32Of == [59, 140, 234, 154]); } /** * This is a convenience alias for $(XREF_PACK digest,digest,toHexString) * producing the usual CRC32 string output. */ public alias crcHexString = toHexString!(Order.decreasing); ///ditto public alias crcHexString = toHexString!(Order.decreasing, 16); /** * OOP API CRC32 implementation. * See $(D std.digest.digest) for differences between template and OOP API. * * This is an alias for $(D $(XREF_PACK digest,digest,WrapperDigest)!CRC32), see * there for more information. */ alias CRC32Digest = WrapperDigest!CRC32; /// unittest { //Simple example, hashing a string using Digest.digest helper function auto crc = new CRC32Digest(); ubyte[] hash = crc.digest("abc"); //Let's get a hash string assert(crcHexString(hash) == "352441C2"); } /// unittest { //Let's use the OOP features: void test(Digest dig) { dig.put(cast(ubyte)0); } auto crc = new CRC32Digest(); test(crc); //Let's use a custom buffer: ubyte[4] buf; ubyte[] result = crc.finish(buf[]); assert(crcHexString(result) == "D202EF8D"); } /// unittest { //Simple example auto hash = new CRC32Digest(); hash.put(cast(ubyte)0); ubyte[] result = hash.finish(); } /// unittest { //using a supplied buffer ubyte[4] buf; auto hash = new CRC32Digest(); hash.put(cast(ubyte)0); ubyte[] result = hash.finish(buf[]); //The result is now in result (and in buf. If you pass a buffer which is bigger than //necessary, result will have the correct length, but buf will still have it's original //length) } unittest { import std.range; auto crc = new CRC32Digest(); crc.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz"); assert(crc.peek() == cast(ubyte[])x"bd50274c"); crc.reset(); crc.put(cast(ubyte[])""); assert(crc.finish() == cast(ubyte[])x"00000000"); crc.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz"); ubyte[20] result; auto result2 = crc.finish(result[]); assert(result[0 .. 4] == result2 && result2 == cast(ubyte[])x"bd50274c"); debug assertThrown!Error(crc.finish(result[0 .. 3])); assert(crc.length == 4); assert(crc.digest("") == cast(ubyte[])x"00000000"); assert(crc.digest("a") == cast(ubyte[])x"43beb7e8"); assert(crc.digest("abc") == cast(ubyte[])x"c2412435"); assert(crc.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") == cast(ubyte[])x"5f3f1a17"); assert(crc.digest("message digest") == cast(ubyte[])x"7f9d1520"); assert(crc.digest("abcdefghijklmnopqrstuvwxyz") == cast(ubyte[])x"bd50274c"); assert(crc.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") == cast(ubyte[])x"d2e6c21f"); assert(crc.digest("1234567890123456789012345678901234567890", "1234567890123456789012345678901234567890") == cast(ubyte[])x"724aa97c"); ubyte[] onemilliona = new ubyte[1000000]; onemilliona[] = 'a'; auto digest = crc32Of(onemilliona); assert(digest == cast(ubyte[])x"BCBF25DC"); auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); digest = crc32Of(oneMillionRange); assert(digest == cast(ubyte[])x"BCBF25DC"); } ldc-1.1.0-beta3-src/runtime/phobos/std/digest/hmac.d0000664000175000017500000002346312776215007020252 0ustar kaikai// Written in the D programming language. /** This package implements the hash-based message authentication code (_HMAC) algorithm as defined in $(WEB tools.ietf.org/html/rfc2104, RFC2104). See also the corresponding $(WEB en.wikipedia.org/wiki/Hash-based_message_authentication_code, Wikipedia article). $(SCRIPT inhibitQuickIndex = 1;) Macros: WIKI = Phobos/StdDigestHMAC SUBMODULE = $(LINK2 std_digest_$1.html, std.digest.$1) SUBREF = $(LINK2 std_digest_$1.html#.$2, $(TT $2))$(NBSP) License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Source: $(PHOBOSSRC std/digest/_hmac.d) */ module std.digest.hmac; import std.digest.digest : isDigest, hasBlockSize, isDigestibleRange, DigestType; import std.meta : allSatisfy; /** * Template API HMAC implementation. * * This implements an _HMAC over the digest H. If H doesn't provide * information about the block size, it can be supplied explicitly using * the second overload. * * This type conforms to $(XREF digest.digest, isDigest). */ version(StdDdoc) /// Computes an HMAC over data read from stdin. unittest { import std.stdio, std.digest.hmac, std.digest.sha; import std.string : representation; auto secret = "secret".representation; stdin.byChunk(4096) .hmac!SHA1(secret) .toHexString!(LetterCase.lower) .writeln; } template HMAC(H) if (isDigest!H && hasBlockSize!H) { alias HMAC = HMAC!(H, H.blockSize); } /** * Overload of HMAC to be used if H doesn't provide information about its * block size. */ struct HMAC(H, size_t hashBlockSize) if (hashBlockSize % 8 == 0) { enum blockSize = hashBlockSize; private H digest; private ubyte[blockSize / 8] key; /** * Constructs the HMAC digest using the specified secret. */ this(scope const(ubyte)[] secret) { // if secret is too long, shorten it by computing its hash typeof(digest.finish()) buffer = void; if (secret.length > blockSize / 8) { digest.start(); digest.put(secret); buffer = digest.finish(); secret = buffer[]; } // if secret is too short, it will be padded with zeroes // (the key buffer is already zero-initialized) import std.algorithm.mutation : copy; secret.copy(key[]); start(); } /// @safe pure nothrow @nogc unittest { import std.digest.sha, std.digest.hmac; import std.string : representation; auto hmac = HMAC!SHA1("My s3cR3T keY".representation); hmac.put("Hello, world".representation); static immutable expected = [130, 32, 235, 44, 208, 141, 150, 232, 211, 214, 162, 195, 188, 127, 52, 89, 100, 68, 90, 216]; assert(hmac.finish() == expected); } /** * Reinitializes the digest, making it ready for reuse. * * Note: * The constructor leaves the digest in an initialized state, so that this * method only needs to be called if an unfinished digest is to be reused. * * Returns: * A reference to the digest for convenient chaining. */ ref HMAC!(H, blockSize) start() return { ubyte[blockSize / 8] ipad = void; foreach (immutable i; 0 .. blockSize / 8) ipad[i] = key[i] ^ 0x36; digest.start(); digest.put(ipad[]); return this; } /// @safe pure nothrow @nogc unittest { import std.digest.sha, std.digest.hmac; import std.string : representation; string data1 = "Hello, world", data2 = "Hola mundo"; auto hmac = HMAC!SHA1("My s3cR3T keY".representation); hmac.put(data1.representation); hmac.start(); // reset digest hmac.put(data2.representation); // start over static immutable expected = [122, 151, 232, 240, 249, 80, 19, 178, 186, 77, 110, 23, 208, 52, 11, 88, 34, 151, 192, 255]; assert(hmac.finish() == expected); } /** * Feeds a piece of data into the hash computation. This method allows the * type to be used as an $(XREF range, OutputRange). * * Returns: * A reference to the digest for convenient chaining. */ ref HMAC!(H, blockSize) put(in ubyte[] data...) return { digest.put(data); return this; } /// @safe pure nothrow @nogc unittest { import std.digest.sha, std.digest.hmac; import std.string : representation; string data1 = "Hello, world", data2 = "Hola mundo"; auto hmac = HMAC!SHA1("My s3cR3T keY".representation); hmac.put(data1.representation) .put(data2.representation); static immutable expected = [197, 57, 52, 3, 13, 194, 13, 36, 117, 228, 8, 11, 111, 51, 165, 3, 123, 31, 251, 113]; assert(hmac.finish() == expected); } /** * Resets the digest and returns the finished hash. */ DigestType!H finish() { ubyte[blockSize / 8] opad = void; foreach (immutable i; 0 .. blockSize / 8) opad[i] = key[i] ^ 0x5c; auto tmp = digest.finish(); digest.start(); digest.put(opad[]); digest.put(tmp); auto result = digest.finish(); start(); // reset the digest return result; } /// @safe pure nothrow @nogc unittest { import std.digest.sha, std.digest.hmac; import std.string : representation; string data1 = "Hello, world", data2 = "Hola mundo"; auto hmac = HMAC!SHA1("My s3cR3T keY".representation); auto digest = hmac.put(data1.representation) .put(data2.representation) .finish(); static immutable expected = [197, 57, 52, 3, 13, 194, 13, 36, 117, 228, 8, 11, 111, 51, 165, 3, 123, 31, 251, 113]; assert(digest == expected); } } template hmac(H) if (isDigest!H && hasBlockSize!H) { alias hmac = hmac!(H, H.blockSize); } template hmac(H, size_t blockSize) if (isDigest!H) { /** * Constructs an HMAC digest with the specified secret. * * Returns: * An instance of HMAC that can be fed data as desired, and finished * to compute the final hash when done. */ auto hmac(scope const(ubyte)[] secret) { return HMAC!(H, blockSize)(secret); } /// @safe pure nothrow @nogc unittest { import std.digest.sha, std.digest.hmac; import std.string : representation; string data1 = "Hello, world", data2 = "Hola mundo"; auto digest = hmac!SHA1("My s3cR3T keY".representation) .put(data1.representation) .put(data2.representation) .finish(); static immutable expected = [197, 57, 52, 3, 13, 194, 13, 36, 117, 228, 8, 11, 111, 51, 165, 3, 123, 31, 251, 113]; assert(digest == expected); } /** * Computes an _HMAC digest over the given range of data with the * specified secret. * * Returns: * The final _HMAC hash. */ DigestType!H hmac(T...)(scope T data, scope const(ubyte)[] secret) if (allSatisfy!(isDigestibleRange, typeof(data))) { import std.algorithm.mutation : copy; auto hash = HMAC!(H, blockSize)(secret); foreach (datum; data) copy(datum, &hash); return hash.finish(); } /// @system pure nothrow @nogc unittest { import std.digest.sha, std.digest.hmac; import std.string : representation; import std.algorithm : map; string data = "Hello, world"; auto digest = data.representation .map!(a => cast(ubyte)(a+1)) .hmac!SHA1("My s3cR3T keY".representation); static assert(is(typeof(digest) == ubyte[20])); static immutable expected = [163, 208, 118, 179, 216, 93, 17, 10, 84, 200, 87, 104, 244, 111, 136, 214, 167, 210, 58, 10]; assert(digest == expected); } } version(unittest) { import std.digest.digest : toHexString, LetterCase; alias hex = toHexString!(LetterCase.lower); } @safe pure nothrow @nogc unittest { import std.digest.md : MD5; import std.range : isOutputRange; static assert(isOutputRange!(HMAC!MD5, ubyte)); static assert(isDigest!(HMAC!MD5)); static assert(hasBlockSize!(HMAC!MD5) && HMAC!MD5.blockSize == MD5.blockSize); } @system pure nothrow unittest { import std.digest.md : MD5; import std.digest.sha : SHA1, SHA256; ubyte[] nada; assert(hmac!MD5 (nada, nada).hex == "74e6f7298a9c2d168935f58c001bad88"); assert(hmac!SHA1 (nada, nada).hex == "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d"); assert(hmac!SHA256(nada, nada).hex == "b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad"); import std.string : representation; auto key = "key".representation, long_key = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789".representation, data1 = "The quick brown fox ".representation, data2 = "jumps over the lazy dog".representation, data = data1 ~ data2; assert(data.hmac!MD5 (key).hex == "80070713463e7749b90c2dc24911e275"); assert(data.hmac!SHA1 (key).hex == "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"); assert(data.hmac!SHA256(key).hex == "f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8"); assert(data.hmac!MD5 (long_key).hex == "e1728d68e05beae186ea768561963778"); assert(data.hmac!SHA1 (long_key).hex == "560d3cd77316e57ab4bba0c186966200d2b37ba3"); assert(data.hmac!SHA256(long_key).hex == "a1b0065a5d1edd93152c677e1bc1b1e3bc70d3a76619842e7f733f02b8135c04"); assert(hmac!MD5 (key).put(data1).put(data2).finish == data.hmac!MD5 (key)); assert(hmac!SHA1 (key).put(data1).put(data2).finish == data.hmac!SHA1 (key)); assert(hmac!SHA256(key).put(data1).put(data2).finish == data.hmac!SHA256(key)); } ldc-1.1.0-beta3-src/runtime/phobos/std/digest/ripemd.d0000664000175000017500000006251212776215007020620 0ustar kaikai/** * Computes RIPEMD-160 hashes of arbitrary data. RIPEMD-160 hashes are 20 byte quantities * that are like a checksum or CRC, but are more robust. * $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Functions) ) $(TR $(TDNW Template API) $(TD $(MYREF RIPEMD160) ) ) $(TR $(TDNW OOP API) $(TD $(MYREF RIPEMD160Digest)) ) $(TR $(TDNW Helpers) $(TD $(MYREF ripemd160Of)) ) ) ) * This module conforms to the APIs defined in $(D std.digest.digest). To understand the * differences between the template and the OOP API, see $(D std.digest.digest). * * This module publicly imports $(D std.digest.digest) and can be used as a stand-alone * module. * * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * * CTFE: * Digests do not work in CTFE * * Authors: * Kai Nacke $(BR) * The algorithm was designed by Hans Dobbertin, Antoon Bosselaers, and Bart Preneel. $(BR) * The D implementation is a direct translation of the ANSI C implementation by Antoon Bosselaers. * * References: * $(UL * $(LI $(LINK2 http://homes.esat.kuleuven.be/~bosselae/ripemd160.html, The hash function RIPEMD-160)) * $(LI $(LINK2 http://en.wikipedia.org/wiki/RIPEMD-160, Wikipedia on RIPEMD-160)) * ) * * Source: $(PHOBOSSRC std/digest/_ripemd.d) * * Macros: * WIKI = Phobos/StdRipemd */ module std.digest.ripemd; public import std.digest.digest; /// unittest { //Template API import std.digest.md; ubyte[20] hash = ripemd160Of("abc"); assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); //Feeding data ubyte[1024] data; RIPEMD160 md; md.start(); md.put(data[]); md.start(); //Start again md.put(data[]); hash = md.finish(); } /// unittest { //OOP API import std.digest.md; auto md = new RIPEMD160Digest(); ubyte[] hash = md.digest("abc"); assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); //Feeding data ubyte[1024] data; md.put(data[]); md.reset(); //Start again md.put(data[]); hash = md.finish(); } //rotateLeft rotates x left n bits private uint rotateLeft(uint x, uint n) @safe pure nothrow @nogc { // With recently added optimization to DMD (commit 32ea0206 at 07/28/11), this is translated to rol. // No assembler required. return (x << n) | (x >> (32-n)); } /** * Template API RIPEMD160 implementation. * See $(D std.digest.digest) for differences between template and OOP API. */ struct RIPEMD160 { private: // magic initialization constants uint[5] _state = [0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0]; // state (ABCDE) ulong _count; //number of bits, modulo 2^64 ubyte[64] _buffer; // input buffer static immutable ubyte[64] _padding = [ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; // F, G, H, I and J are basic RIPEMD160 functions static @safe pure nothrow @nogc { uint F(uint x, uint y, uint z) { return x ^ y ^ z; } uint G(uint x, uint y, uint z) { return (x & y) | (~x & z); } uint H(uint x, uint y, uint z) { return (x | ~y) ^ z; } uint I(uint x, uint y, uint z) { return (x & z) | (y & ~z); } uint J(uint x, uint y, uint z) { return x ^ (y | ~z); } } /* * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. * Rotation is separate from addition to prevent recomputation. */ /* the ten basic operations FF() through III() */ static void FF(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += F(b, c, d) + x; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } static void GG(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += G(b, c, d) + x + 0x5a827999UL; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } static void HH(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += H(b, c, d) + x + 0x6ed9eba1UL; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } static void II(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += I(b, c, d) + x + 0x8f1bbcdcUL; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } static void JJ(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += J(b, c, d) + x + 0xa953fd4eUL; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } /* * FFF, GGG, HHH, and III transformations for parallel rounds 1, 2, 3, and 4. * Rotation is separate from addition to prevent recomputation. */ static void FFF(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += F(b, c, d) + x; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } static void GGG(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += G(b, c, d) + x + 0x7a6d76e9UL; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } static void HHH(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += H(b, c, d) + x + 0x6d703ef3UL; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } static void III(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += I(b, c, d) + x + 0x5c4dd124UL; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } static void JJJ(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) @safe pure nothrow @nogc { a += J(b, c, d) + x + 0x50a28be6UL; a = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } /* * RIPEMD160 basic transformation. Transforms state based on block. */ private void transform(const(ubyte[64])* block) pure nothrow @nogc { uint aa = _state[0], bb = _state[1], cc = _state[2], dd = _state[3], ee = _state[4]; uint aaa = _state[0], bbb = _state[1], ccc = _state[2], ddd = _state[3], eee = _state[4]; uint[16] x = void; version(BigEndian) { import std.bitmanip : littleEndianToNative; for(size_t i = 0; i < 16; i++) { x[i] = littleEndianToNative!uint(*cast(ubyte[4]*)&(*block)[i*4]); } } else { (cast(ubyte*)x.ptr)[0 .. 64] = (cast(ubyte*)block)[0 .. 64]; } /* round 1 */ FF(aa, bb, cc, dd, ee, x[ 0], 11); FF(ee, aa, bb, cc, dd, x[ 1], 14); FF(dd, ee, aa, bb, cc, x[ 2], 15); FF(cc, dd, ee, aa, bb, x[ 3], 12); FF(bb, cc, dd, ee, aa, x[ 4], 5); FF(aa, bb, cc, dd, ee, x[ 5], 8); FF(ee, aa, bb, cc, dd, x[ 6], 7); FF(dd, ee, aa, bb, cc, x[ 7], 9); FF(cc, dd, ee, aa, bb, x[ 8], 11); FF(bb, cc, dd, ee, aa, x[ 9], 13); FF(aa, bb, cc, dd, ee, x[10], 14); FF(ee, aa, bb, cc, dd, x[11], 15); FF(dd, ee, aa, bb, cc, x[12], 6); FF(cc, dd, ee, aa, bb, x[13], 7); FF(bb, cc, dd, ee, aa, x[14], 9); FF(aa, bb, cc, dd, ee, x[15], 8); /* round 2 */ GG(ee, aa, bb, cc, dd, x[ 7], 7); GG(dd, ee, aa, bb, cc, x[ 4], 6); GG(cc, dd, ee, aa, bb, x[13], 8); GG(bb, cc, dd, ee, aa, x[ 1], 13); GG(aa, bb, cc, dd, ee, x[10], 11); GG(ee, aa, bb, cc, dd, x[ 6], 9); GG(dd, ee, aa, bb, cc, x[15], 7); GG(cc, dd, ee, aa, bb, x[ 3], 15); GG(bb, cc, dd, ee, aa, x[12], 7); GG(aa, bb, cc, dd, ee, x[ 0], 12); GG(ee, aa, bb, cc, dd, x[ 9], 15); GG(dd, ee, aa, bb, cc, x[ 5], 9); GG(cc, dd, ee, aa, bb, x[ 2], 11); GG(bb, cc, dd, ee, aa, x[14], 7); GG(aa, bb, cc, dd, ee, x[11], 13); GG(ee, aa, bb, cc, dd, x[ 8], 12); /* round 3 */ HH(dd, ee, aa, bb, cc, x[ 3], 11); HH(cc, dd, ee, aa, bb, x[10], 13); HH(bb, cc, dd, ee, aa, x[14], 6); HH(aa, bb, cc, dd, ee, x[ 4], 7); HH(ee, aa, bb, cc, dd, x[ 9], 14); HH(dd, ee, aa, bb, cc, x[15], 9); HH(cc, dd, ee, aa, bb, x[ 8], 13); HH(bb, cc, dd, ee, aa, x[ 1], 15); HH(aa, bb, cc, dd, ee, x[ 2], 14); HH(ee, aa, bb, cc, dd, x[ 7], 8); HH(dd, ee, aa, bb, cc, x[ 0], 13); HH(cc, dd, ee, aa, bb, x[ 6], 6); HH(bb, cc, dd, ee, aa, x[13], 5); HH(aa, bb, cc, dd, ee, x[11], 12); HH(ee, aa, bb, cc, dd, x[ 5], 7); HH(dd, ee, aa, bb, cc, x[12], 5); /* round 4 */ II(cc, dd, ee, aa, bb, x[ 1], 11); II(bb, cc, dd, ee, aa, x[ 9], 12); II(aa, bb, cc, dd, ee, x[11], 14); II(ee, aa, bb, cc, dd, x[10], 15); II(dd, ee, aa, bb, cc, x[ 0], 14); II(cc, dd, ee, aa, bb, x[ 8], 15); II(bb, cc, dd, ee, aa, x[12], 9); II(aa, bb, cc, dd, ee, x[ 4], 8); II(ee, aa, bb, cc, dd, x[13], 9); II(dd, ee, aa, bb, cc, x[ 3], 14); II(cc, dd, ee, aa, bb, x[ 7], 5); II(bb, cc, dd, ee, aa, x[15], 6); II(aa, bb, cc, dd, ee, x[14], 8); II(ee, aa, bb, cc, dd, x[ 5], 6); II(dd, ee, aa, bb, cc, x[ 6], 5); II(cc, dd, ee, aa, bb, x[ 2], 12); /* round 5 */ JJ(bb, cc, dd, ee, aa, x[ 4], 9); JJ(aa, bb, cc, dd, ee, x[ 0], 15); JJ(ee, aa, bb, cc, dd, x[ 5], 5); JJ(dd, ee, aa, bb, cc, x[ 9], 11); JJ(cc, dd, ee, aa, bb, x[ 7], 6); JJ(bb, cc, dd, ee, aa, x[12], 8); JJ(aa, bb, cc, dd, ee, x[ 2], 13); JJ(ee, aa, bb, cc, dd, x[10], 12); JJ(dd, ee, aa, bb, cc, x[14], 5); JJ(cc, dd, ee, aa, bb, x[ 1], 12); JJ(bb, cc, dd, ee, aa, x[ 3], 13); JJ(aa, bb, cc, dd, ee, x[ 8], 14); JJ(ee, aa, bb, cc, dd, x[11], 11); JJ(dd, ee, aa, bb, cc, x[ 6], 8); JJ(cc, dd, ee, aa, bb, x[15], 5); JJ(bb, cc, dd, ee, aa, x[13], 6); /* parallel round 1 */ JJJ(aaa, bbb, ccc, ddd, eee, x[ 5], 8); JJJ(eee, aaa, bbb, ccc, ddd, x[14], 9); JJJ(ddd, eee, aaa, bbb, ccc, x[ 7], 9); JJJ(ccc, ddd, eee, aaa, bbb, x[ 0], 11); JJJ(bbb, ccc, ddd, eee, aaa, x[ 9], 13); JJJ(aaa, bbb, ccc, ddd, eee, x[ 2], 15); JJJ(eee, aaa, bbb, ccc, ddd, x[11], 15); JJJ(ddd, eee, aaa, bbb, ccc, x[ 4], 5); JJJ(ccc, ddd, eee, aaa, bbb, x[13], 7); JJJ(bbb, ccc, ddd, eee, aaa, x[ 6], 7); JJJ(aaa, bbb, ccc, ddd, eee, x[15], 8); JJJ(eee, aaa, bbb, ccc, ddd, x[ 8], 11); JJJ(ddd, eee, aaa, bbb, ccc, x[ 1], 14); JJJ(ccc, ddd, eee, aaa, bbb, x[10], 14); JJJ(bbb, ccc, ddd, eee, aaa, x[ 3], 12); JJJ(aaa, bbb, ccc, ddd, eee, x[12], 6); /* parallel round 2 */ III(eee, aaa, bbb, ccc, ddd, x[ 6], 9); III(ddd, eee, aaa, bbb, ccc, x[11], 13); III(ccc, ddd, eee, aaa, bbb, x[ 3], 15); III(bbb, ccc, ddd, eee, aaa, x[ 7], 7); III(aaa, bbb, ccc, ddd, eee, x[ 0], 12); III(eee, aaa, bbb, ccc, ddd, x[13], 8); III(ddd, eee, aaa, bbb, ccc, x[ 5], 9); III(ccc, ddd, eee, aaa, bbb, x[10], 11); III(bbb, ccc, ddd, eee, aaa, x[14], 7); III(aaa, bbb, ccc, ddd, eee, x[15], 7); III(eee, aaa, bbb, ccc, ddd, x[ 8], 12); III(ddd, eee, aaa, bbb, ccc, x[12], 7); III(ccc, ddd, eee, aaa, bbb, x[ 4], 6); III(bbb, ccc, ddd, eee, aaa, x[ 9], 15); III(aaa, bbb, ccc, ddd, eee, x[ 1], 13); III(eee, aaa, bbb, ccc, ddd, x[ 2], 11); /* parallel round 3 */ HHH(ddd, eee, aaa, bbb, ccc, x[15], 9); HHH(ccc, ddd, eee, aaa, bbb, x[ 5], 7); HHH(bbb, ccc, ddd, eee, aaa, x[ 1], 15); HHH(aaa, bbb, ccc, ddd, eee, x[ 3], 11); HHH(eee, aaa, bbb, ccc, ddd, x[ 7], 8); HHH(ddd, eee, aaa, bbb, ccc, x[14], 6); HHH(ccc, ddd, eee, aaa, bbb, x[ 6], 6); HHH(bbb, ccc, ddd, eee, aaa, x[ 9], 14); HHH(aaa, bbb, ccc, ddd, eee, x[11], 12); HHH(eee, aaa, bbb, ccc, ddd, x[ 8], 13); HHH(ddd, eee, aaa, bbb, ccc, x[12], 5); HHH(ccc, ddd, eee, aaa, bbb, x[ 2], 14); HHH(bbb, ccc, ddd, eee, aaa, x[10], 13); HHH(aaa, bbb, ccc, ddd, eee, x[ 0], 13); HHH(eee, aaa, bbb, ccc, ddd, x[ 4], 7); HHH(ddd, eee, aaa, bbb, ccc, x[13], 5); /* parallel round 4 */ GGG(ccc, ddd, eee, aaa, bbb, x[ 8], 15); GGG(bbb, ccc, ddd, eee, aaa, x[ 6], 5); GGG(aaa, bbb, ccc, ddd, eee, x[ 4], 8); GGG(eee, aaa, bbb, ccc, ddd, x[ 1], 11); GGG(ddd, eee, aaa, bbb, ccc, x[ 3], 14); GGG(ccc, ddd, eee, aaa, bbb, x[11], 14); GGG(bbb, ccc, ddd, eee, aaa, x[15], 6); GGG(aaa, bbb, ccc, ddd, eee, x[ 0], 14); GGG(eee, aaa, bbb, ccc, ddd, x[ 5], 6); GGG(ddd, eee, aaa, bbb, ccc, x[12], 9); GGG(ccc, ddd, eee, aaa, bbb, x[ 2], 12); GGG(bbb, ccc, ddd, eee, aaa, x[13], 9); GGG(aaa, bbb, ccc, ddd, eee, x[ 9], 12); GGG(eee, aaa, bbb, ccc, ddd, x[ 7], 5); GGG(ddd, eee, aaa, bbb, ccc, x[10], 15); GGG(ccc, ddd, eee, aaa, bbb, x[14], 8); /* parallel round 5 */ FFF(bbb, ccc, ddd, eee, aaa, x[12] , 8); FFF(aaa, bbb, ccc, ddd, eee, x[15] , 5); FFF(eee, aaa, bbb, ccc, ddd, x[10] , 12); FFF(ddd, eee, aaa, bbb, ccc, x[ 4] , 9); FFF(ccc, ddd, eee, aaa, bbb, x[ 1] , 12); FFF(bbb, ccc, ddd, eee, aaa, x[ 5] , 5); FFF(aaa, bbb, ccc, ddd, eee, x[ 8] , 14); FFF(eee, aaa, bbb, ccc, ddd, x[ 7] , 6); FFF(ddd, eee, aaa, bbb, ccc, x[ 6] , 8); FFF(ccc, ddd, eee, aaa, bbb, x[ 2] , 13); FFF(bbb, ccc, ddd, eee, aaa, x[13] , 6); FFF(aaa, bbb, ccc, ddd, eee, x[14] , 5); FFF(eee, aaa, bbb, ccc, ddd, x[ 0] , 15); FFF(ddd, eee, aaa, bbb, ccc, x[ 3] , 13); FFF(ccc, ddd, eee, aaa, bbb, x[ 9] , 11); FFF(bbb, ccc, ddd, eee, aaa, x[11] , 11); /* combine results */ ddd += cc + _state[1]; /* final result for _state[0] */ _state[1] = _state[2] + dd + eee; _state[2] = _state[3] + ee + aaa; _state[3] = _state[4] + aa + bbb; _state[4] = _state[0] + bb + ccc; _state[0] = ddd; //Zeroize sensitive information. x[] = 0; } public: enum blockSize = 512; /** * Use this to feed the digest with data. * Also implements the $(XREF_PACK range,primitives,isOutputRange) * interface for $(D ubyte) and $(D const(ubyte)[]). * * Example: * ---- * RIPEMD160 dig; * dig.put(cast(ubyte)0); //single ubyte * dig.put(cast(ubyte)0, cast(ubyte)0); //variadic * ubyte[10] buf; * dig.put(buf); //buffer * ---- */ void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc { uint i, index, partLen; auto inputLen = data.length; //Compute number of bytes mod 64 index = (cast(uint)_count >> 3) & (64 - 1); //Update number of bits _count += inputLen * 8; partLen = 64 - index; //Transform as many times as possible if (inputLen >= partLen) { (&_buffer[index])[0 .. partLen] = data.ptr[0 .. partLen]; transform(&_buffer); for(i = partLen; i + 63 < inputLen; i += 64) { transform(cast(const(ubyte[64])*)(data[i .. i + 64].ptr)); } index = 0; } else { i = 0; } /* Buffer remaining input */ if (inputLen - i) (&_buffer[index])[0 .. inputLen-i] = (&data[i])[0 .. inputLen-i]; } /** * Used to (re)initialize the RIPEMD160 digest. * * Note: * For this RIPEMD160 Digest implementation calling start after default construction * is not necessary. Calling start is only necessary to reset the Digest. * * Generic code which deals with different Digest types should always call start though. * * Example: * -------- * RIPEMD160 digest; * //digest.start(); //Not necessary * digest.put(0); * -------- */ void start() @safe pure nothrow @nogc { this = RIPEMD160.init; } /** * Returns the finished RIPEMD160 hash. This also calls $(LREF start) to * reset the internal state. * * Example: * -------- * //Simple example * RIPEMD160 hash; * hash.start(); * hash.put(cast(ubyte)0); * ubyte[20] result = hash.finish(); * assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); * -------- */ ubyte[20] finish() @trusted pure nothrow @nogc { import std.bitmanip : nativeToLittleEndian; ubyte[20] data = void; ubyte[8] bits = void; uint index, padLen; //Save number of bits bits[0 .. 8] = nativeToLittleEndian(_count)[]; //Pad out to 56 mod 64 index = (cast(uint)_count >> 3) & (64 - 1); padLen = (index < 56) ? (56 - index) : (120 - index); put(_padding[0 .. padLen]); //Append length (before padding) put(bits); //Store state in digest data[0 .. 4] = nativeToLittleEndian(_state[0])[]; data[4 .. 8] = nativeToLittleEndian(_state[1])[]; data[8 .. 12] = nativeToLittleEndian(_state[2])[]; data[12 .. 16] = nativeToLittleEndian(_state[3])[]; data[16 .. 20] = nativeToLittleEndian(_state[4])[]; /* Zeroize sensitive information. */ start(); return data; } } /// unittest { //Simple example, hashing a string using ripemd160Of helper function ubyte[20] hash = ripemd160Of("abc"); //Let's get a hash string assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); } /// unittest { //Using the basic API RIPEMD160 hash; hash.start(); ubyte[1024] data; //Initialize data here... hash.put(data); ubyte[20] result = hash.finish(); } /// unittest { //Let's use the template features: void doSomething(T)(ref T hash) if(isDigest!T) { hash.put(cast(ubyte)0); } RIPEMD160 md; md.start(); doSomething(md); assert(toHexString(md.finish()) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); } /// unittest { //Simple example RIPEMD160 hash; hash.start(); hash.put(cast(ubyte)0); ubyte[20] result = hash.finish(); assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); } unittest { assert(isDigest!RIPEMD160); } unittest { import std.range; ubyte[20] digest; RIPEMD160 md; md.put(cast(ubyte[])"abcdef"); md.start(); md.put(cast(ubyte[])""); assert(md.finish() == cast(ubyte[])x"9c1185a5c5e9fc54612808977ee8f548b2258d31"); digest = ripemd160Of(""); assert(digest == cast(ubyte[])x"9c1185a5c5e9fc54612808977ee8f548b2258d31"); digest = ripemd160Of("a"); assert(digest == cast(ubyte[])x"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"); digest = ripemd160Of("abc"); assert(digest == cast(ubyte[])x"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); digest = ripemd160Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); assert(digest == cast(ubyte[])x"12a053384a9c0c88e405a06c27dcf49ada62eb2b"); digest = ripemd160Of("message digest"); assert(digest == cast(ubyte[])x"5d0689ef49d2fae572b881b123a85ffa21595f36"); digest = ripemd160Of("abcdefghijklmnopqrstuvwxyz"); assert(digest == cast(ubyte[])x"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); digest = ripemd160Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); assert(digest == cast(ubyte[])x"b0e20b6e3116640286ed3a87a5713079b21f5189"); digest = ripemd160Of("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); assert(digest == cast(ubyte[])x"9b752e45573d4b39f4dbd3323cab82bf63326bfb"); assert(toHexString(cast(ubyte[20])x"f71c27109c692c1b56bbdceb5b9d2865b3708dbc") == "F71C27109C692C1B56BBDCEB5B9D2865B3708DBC"); ubyte[] onemilliona = new ubyte[1000000]; onemilliona[] = 'a'; digest = ripemd160Of(onemilliona); assert(digest == cast(ubyte[])x"52783243c1697bdbe16d37f97f68f08325dc1528"); auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); digest = ripemd160Of(oneMillionRange); assert(digest == cast(ubyte[])x"52783243c1697bdbe16d37f97f68f08325dc1528"); } /** * This is a convenience alias for $(XREF_PACK digest,digest,digest) using the * RIPEMD160 implementation. */ //simple alias doesn't work here, hope this gets inlined... auto ripemd160Of(T...)(T data) { return digest!(RIPEMD160, T)(data); } /// unittest { ubyte[20] hash = ripemd160Of("abc"); assert(hash == digest!RIPEMD160("abc")); } /** * OOP API RIPEMD160 implementation. * See $(D std.digest.digest) for differences between template and OOP API. * * This is an alias for $(D $(XREF_PACK digest,digest,WrapperDigest)!RIPEMD160), * see there for more information. */ alias RIPEMD160Digest = WrapperDigest!RIPEMD160; /// unittest { //Simple example, hashing a string using Digest.digest helper function auto md = new RIPEMD160Digest(); ubyte[] hash = md.digest("abc"); //Let's get a hash string assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); } /// unittest { //Let's use the OOP features: void test(Digest dig) { dig.put(cast(ubyte)0); } auto md = new RIPEMD160Digest(); test(md); //Let's use a custom buffer: ubyte[20] buf; ubyte[] result = md.finish(buf[]); assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); } unittest { auto md = new RIPEMD160Digest(); md.put(cast(ubyte[])"abcdef"); md.reset(); md.put(cast(ubyte[])""); assert(md.finish() == cast(ubyte[])x"9c1185a5c5e9fc54612808977ee8f548b2258d31"); md.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz"); ubyte[20] result; auto result2 = md.finish(result[]); assert(result[0 .. 20] == result2 && result2 == cast(ubyte[])x"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); debug { import std.exception; assertThrown!Error(md.finish(result[0 .. 19])); } assert(md.length == 20); assert(md.digest("") == cast(ubyte[])x"9c1185a5c5e9fc54612808977ee8f548b2258d31"); assert(md.digest("a") == cast(ubyte[])x"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"); assert(md.digest("abc") == cast(ubyte[])x"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); assert(md.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") == cast(ubyte[])x"12a053384a9c0c88e405a06c27dcf49ada62eb2b"); assert(md.digest("message digest") == cast(ubyte[])x"5d0689ef49d2fae572b881b123a85ffa21595f36"); assert(md.digest("abcdefghijklmnopqrstuvwxyz") == cast(ubyte[])x"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); assert(md.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") == cast(ubyte[])x"b0e20b6e3116640286ed3a87a5713079b21f5189"); assert(md.digest("1234567890123456789012345678901234567890", "1234567890123456789012345678901234567890") == cast(ubyte[])x"9b752e45573d4b39f4dbd3323cab82bf63326bfb"); assert(md.digest(new ubyte[160/8]) // 160 zero bits == cast(ubyte[])x"5c00bd4aca04a9057c09b20b05f723f2e23deb65"); } ldc-1.1.0-beta3-src/runtime/phobos/std/digest/digest.d0000664000175000017500000006754512776215007020632 0ustar kaikai/** * This module describes the _digest APIs used in Phobos. All digests follow * these APIs. Additionally, this module contains useful helper methods which * can be used with every _digest type. * $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Functions) ) $(TR $(TDNW Template API) $(TD $(MYREF isDigest) $(MYREF DigestType) $(MYREF hasPeek) $(MYREF hasBlockSize) $(MYREF ExampleDigest) $(MYREF _digest) $(MYREF hexDigest) $(MYREF makeDigest) ) ) $(TR $(TDNW OOP API) $(TD $(MYREF Digest) ) ) $(TR $(TDNW Helper functions) $(TD $(MYREF toHexString)) ) $(TR $(TDNW Implementation helpers) $(TD $(MYREF digestLength) $(MYREF WrapperDigest)) ) ) ) * APIs: * There are two APIs for digests: The template API and the OOP API. The template API uses structs * and template helpers like $(LREF isDigest). The OOP API implements digests as classes inheriting * the $(LREF Digest) interface. All digests are named so that the template API struct is called "$(B x)" * and the OOP API class is called "$(B x)Digest". For example we have $(D MD5) <--> $(D MD5Digest), * $(D CRC32) <--> $(D CRC32Digest), etc. * * The template API is slightly more efficient. It does not have to allocate memory dynamically, * all memory is allocated on the stack. The OOP API has to allocate in the finish method if no * buffer was provided. If you provide a buffer to the OOP APIs finish function, it doesn't allocate, * but the $(LREF Digest) classes still have to be created using $(D new) which allocates them using the GC. * * The OOP API is useful to change the _digest function and/or _digest backend at 'runtime'. The benefit here * is that switching e.g. Phobos MD5Digest and an OpenSSLMD5Digest implementation is ABI compatible. * * If just one specific _digest type and backend is needed, the template API is usually a good fit. * In this simplest case, the template API can even be used without templates: Just use the "$(B x)" structs * directly. * * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: * Johannes Pfau * * Source: $(PHOBOSSRC std/_digest/_digest.d) * * CTFE: * Digests do not work in CTFE * * TODO: * Digesting single bits (as opposed to bytes) is not implemented. This will be done as another * template constraint helper (hasBitDigesting!T) and an additional interface (BitDigest) */ /* Copyright Johannes Pfau 2012. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.digest.digest; import std.meta : allSatisfy; import std.traits; public import std.ascii : LetterCase; /// unittest { import std.digest.crc; //Simple example char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog"); assert(hexHash == "39A34F41"); //Simple example, using the API manually CRC32 context = makeDigest!CRC32(); context.put(cast(ubyte[])"The quick brown fox jumps over the lazy dog"); ubyte[4] hash = context.finish(); assert(toHexString(hash) == "39A34F41"); } /// unittest { //Generating the hashes of a file, idiomatic D way import std.digest.crc, std.digest.sha, std.digest.md; import std.stdio; // Digests a file and prints the result. void digestFile(Hash)(string filename) if(isDigest!Hash) { auto file = File(filename); auto result = digest!Hash(file.byChunk(4096 * 1024)); writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); } void main(string[] args) { foreach (name; args[1 .. $]) { digestFile!MD5(name); digestFile!SHA1(name); digestFile!CRC32(name); } } } /// unittest { //Generating the hashes of a file using the template API import std.digest.crc, std.digest.sha, std.digest.md; import std.stdio; // Digests a file and prints the result. void digestFile(Hash)(ref Hash hash, string filename) if(isDigest!Hash) { File file = File(filename); //As digests imlement OutputRange, we could use std.algorithm.copy //Let's do it manually for now foreach (buffer; file.byChunk(4096 * 1024)) hash.put(buffer); auto result = hash.finish(); writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); } void uMain(string[] args) { MD5 md5; SHA1 sha1; CRC32 crc32; md5.start(); sha1.start(); crc32.start(); foreach (arg; args[1 .. $]) { digestFile(md5, arg); digestFile(sha1, arg); digestFile(crc32, arg); } } } /// unittest { import std.digest.crc, std.digest.sha, std.digest.md; import std.stdio; // Digests a file and prints the result. void digestFile(Digest hash, string filename) { File file = File(filename); //As digests implement OutputRange, we could use std.algorithm.copy //Let's do it manually for now foreach (buffer; file.byChunk(4096 * 1024)) hash.put(buffer); ubyte[] result = hash.finish(); writefln("%s (%s) = %s", typeid(hash).toString(), filename, toHexString(result)); } void umain(string[] args) { auto md5 = new MD5Digest(); auto sha1 = new SHA1Digest(); auto crc32 = new CRC32Digest(); foreach (arg; args[1 .. $]) { digestFile(md5, arg); digestFile(sha1, arg); digestFile(crc32, arg); } } } version(StdDdoc) version = ExampleDigest; version(ExampleDigest) { /** * This documents the general structure of a Digest in the template API. * All digest implementations should implement the following members and therefore pass * the $(LREF isDigest) test. * * Note: * $(UL * $(LI A digest must be a struct (value type) to pass the $(LREF isDigest) test.) * $(LI A digest passing the $(LREF isDigest) test is always an $(D OutputRange)) * ) */ struct ExampleDigest { public: /** * Use this to feed the digest with data. * Also implements the $(XREF_PACK range,primitives,isOutputRange) * interface for $(D ubyte) and $(D const(ubyte)[]). * The following usages of $(D put) must work for any type which * passes $(LREF isDigest): * Example: * ---- * ExampleDigest dig; * dig.put(cast(ubyte)0); //single ubyte * dig.put(cast(ubyte)0, cast(ubyte)0); //variadic * ubyte[10] buf; * dig.put(buf); //buffer * ---- */ @trusted void put(scope const(ubyte)[] data...) { } /** * This function is used to (re)initialize the digest. * It must be called before using the digest and it also works as a 'reset' function * if the digest has already processed data. */ @trusted void start() { } /** * The finish function returns the final hash sum and resets the Digest. * * Note: * The actual type returned by finish depends on the digest implementation. * $(D ubyte[16]) is just used as an example. It is guaranteed that the type is a * static array of ubytes. * * $(UL * $(LI Use $(LREF DigestType) to obtain the actual return type.) * $(LI Use $(LREF digestLength) to obtain the length of the ubyte array.) * ) */ @trusted ubyte[16] finish() { return (ubyte[16]).init; } } } /// unittest { //Using the OutputRange feature import std.algorithm : copy; import std.range : repeat; import std.digest.md; auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); auto ctx = makeDigest!MD5(); copy(oneMillionRange, &ctx); //Note: You must pass a pointer to copy! assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); } /** * Use this to check if a type is a digest. See $(LREF ExampleDigest) to see what * a type must provide to pass this check. * * Note: * This is very useful as a template constraint (see examples) * * BUGS: * $(UL * $(LI Does not yet verify that put takes scope parameters.) * $(LI Should check that finish() returns a ubyte[num] array) * ) */ template isDigest(T) { import std.range : isOutputRange; enum bool isDigest = isOutputRange!(T, const(ubyte)[]) && isOutputRange!(T, ubyte) && is(T == struct) && is(typeof( { T dig = void; //Can define dig.put(cast(ubyte)0, cast(ubyte)0); //varags dig.start(); //has start auto value = dig.finish(); //has finish })); } /// unittest { import std.digest.crc; static assert(isDigest!CRC32); } /// unittest { import std.digest.crc; void myFunction(T)() if(isDigest!T) { T dig; dig.start(); auto result = dig.finish(); } myFunction!CRC32(); } /** * Use this template to get the type which is returned by a digest's $(LREF finish) method. */ template DigestType(T) { static if(isDigest!T) { alias DigestType = ReturnType!(typeof( { T dig = void; return dig.finish(); })); } else static assert(false, T.stringof ~ " is not a digest! (fails isDigest!T)"); } /// unittest { import std.digest.crc; assert(is(DigestType!(CRC32) == ubyte[4])); } /// unittest { import std.digest.crc; CRC32 dig; dig.start(); DigestType!CRC32 result = dig.finish(); } /** * Used to check if a digest supports the $(D peek) method. * Peek has exactly the same function signatures as finish, but it doesn't reset * the digest's internal state. * * Note: * $(UL * $(LI This is very useful as a template constraint (see examples)) * $(LI This also checks if T passes $(LREF isDigest)) * ) */ template hasPeek(T) { enum bool hasPeek = isDigest!T && is(typeof( { T dig = void; //Can define DigestType!T val = dig.peek(); })); } /// unittest { import std.digest.crc, std.digest.md; assert(!hasPeek!(MD5)); assert(hasPeek!CRC32); } /// unittest { import std.digest.crc; void myFunction(T)() if(hasPeek!T) { T dig; dig.start(); auto result = dig.peek(); } myFunction!CRC32(); } /** * Checks whether the digest has a $(D blockSize) member, which contains the * digest's internal block size in bits. It is primarily used by $(XREF digest.hmac, HMAC). */ template hasBlockSize(T) if (isDigest!T) { enum bool hasBlockSize = __traits(compiles, { size_t blockSize = T.blockSize; }); } /// unittest { import std.digest.md, std.digest.hmac; static assert(hasBlockSize!MD5 && MD5.blockSize == 512); static assert(hasBlockSize!(HMAC!MD5) && HMAC!MD5.blockSize == 512); } package template isDigestibleRange(Range) { import std.digest.md; import std.range : isInputRange, ElementType; enum bool isDigestibleRange = isInputRange!Range && is(typeof( { MD5 ha; //Could use any conformant hash ElementType!Range val; ha.put(val); })); } /** * This is a convenience function to calculate a hash using the template API. * Every digest passing the $(LREF isDigest) test can be used with this function. * * Params: * range= an $(D InputRange) with $(D ElementType) $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) */ DigestType!Hash digest(Hash, Range)(auto ref Range range) if(!isArray!Range && isDigestibleRange!Range) { import std.algorithm : copy; Hash hash; hash.start(); copy(range, &hash); return hash.finish(); } /// unittest { import std.digest.md; import std.range : repeat; auto testRange = repeat!ubyte(cast(ubyte)'a', 100); auto md5 = digest!MD5(testRange); } /** * This overload of the digest function handles arrays. * * Params: * data= one or more arrays of any type */ DigestType!Hash digest(Hash, T...)(scope const T data) if(allSatisfy!(isArray, typeof(data))) { Hash hash; hash.start(); foreach(datum; data) hash.put(cast(const(ubyte[]))datum); return hash.finish(); } /// unittest { import std.digest.md, std.digest.sha, std.digest.crc; auto md5 = digest!MD5( "The quick brown fox jumps over the lazy dog"); auto sha1 = digest!SHA1( "The quick brown fox jumps over the lazy dog"); auto crc32 = digest!CRC32("The quick brown fox jumps over the lazy dog"); assert(toHexString(crc32) == "39A34F41"); } /// unittest { import std.digest.crc; auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); assert(toHexString(crc32) == "39A34F41"); } /** * This is a convenience function similar to $(LREF digest), but it returns the string * representation of the hash. Every digest passing the $(LREF isDigest) test can be used with this * function. * * Params: * order= the order in which the bytes are processed (see $(LREF toHexString)) * range= an $(D InputRange) with $(D ElementType) $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) */ char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, Range)(ref Range range) if(!isArray!Range && isDigestibleRange!Range) { return toHexString!order(digest!Hash(range)); } /// unittest { import std.digest.md; import std.range : repeat; auto testRange = repeat!ubyte(cast(ubyte)'a', 100); assert(hexDigest!MD5(testRange) == "36A92CC94A9E0FA21F625F8BFB007ADF"); } /** * This overload of the hexDigest function handles arrays. * * Params: * order= the order in which the bytes are processed (see $(LREF toHexString)) * data= one or more arrays of any type */ char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, T...)(scope const T data) if(allSatisfy!(isArray, typeof(data))) { return toHexString!order(digest!Hash(data)); } /// unittest { import std.digest.crc; assert(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog") == "414FA339"); } /// unittest { import std.digest.crc; assert(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog") == "414FA339"); } /** * This is a convenience function which returns an initialized digest, so it's not necessary to call * start manually. */ Hash makeDigest(Hash)() { Hash hash; hash.start(); return hash; } /// unittest { import std.digest.md; auto md5 = makeDigest!MD5(); md5.put(0); assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); } /*+*************************** End of template part, welcome to OOP land **************************/ /** * This describes the OOP API. To understand when to use the template API and when to use the OOP API, * see the module documentation at the top of this page. * * The Digest interface is the base interface which is implemented by all digests. * * Note: * A Digest implementation is always an $(D OutputRange) */ interface Digest { public: /** * Use this to feed the digest with data. * Also implements the $(XREF_PACK range,primitives,isOutputRange) * interface for $(D ubyte) and $(D const(ubyte)[]). * * Example: * ---- * void test(Digest dig) * { * dig.put(cast(ubyte)0); //single ubyte * dig.put(cast(ubyte)0, cast(ubyte)0); //variadic * ubyte[10] buf; * dig.put(buf); //buffer * } * ---- */ @trusted nothrow void put(scope const(ubyte)[] data...); /** * Resets the internal state of the digest. * Note: * $(LREF finish) calls this internally, so it's not necessary to call * $(D reset) manually after a call to $(LREF finish). */ @trusted nothrow void reset(); /** * This is the length in bytes of the hash value which is returned by $(LREF finish). * It's also the required size of a buffer passed to $(LREF finish). */ @trusted nothrow @property size_t length() const; /** * The finish function returns the hash value. It takes an optional buffer to copy the data * into. If a buffer is passed, it must be at least $(LREF length) bytes big. */ @trusted nothrow ubyte[] finish(); ///ditto nothrow ubyte[] finish(scope ubyte[] buf); //@@@BUG@@@ http://d.puremagic.com/issues/show_bug.cgi?id=6549 /*in { assert(buf.length >= this.length); }*/ /** * This is a convenience function to calculate the hash of a value using the OOP API. */ final @trusted nothrow ubyte[] digest(scope const(void[])[] data...) { this.reset(); foreach(datum; data) this.put(cast(ubyte[])datum); return this.finish(); } } /// unittest { //Using the OutputRange feature import std.algorithm : copy; import std.range : repeat; import std.digest.md; auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); auto ctx = new MD5Digest(); copy(oneMillionRange, ctx); assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); } /// unittest { import std.digest.md, std.digest.sha, std.digest.crc; ubyte[] md5 = (new MD5Digest()).digest("The quick brown fox jumps over the lazy dog"); ubyte[] sha1 = (new SHA1Digest()).digest("The quick brown fox jumps over the lazy dog"); ubyte[] crc32 = (new CRC32Digest()).digest("The quick brown fox jumps over the lazy dog"); assert(crcHexString(crc32) == "414FA339"); } /// unittest { import std.digest.crc; ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); assert(crcHexString(crc32) == "414FA339"); } unittest { import std.range : isOutputRange; assert(!isDigest!(Digest)); assert(isOutputRange!(Digest, ubyte)); } /// unittest { void test(Digest dig) { dig.put(cast(ubyte)0); //single ubyte dig.put(cast(ubyte)0, cast(ubyte)0); //variadic ubyte[10] buf; dig.put(buf); //buffer } } /*+*************************** End of OOP part, helper functions follow ***************************/ /** * See $(LREF toHexString) */ enum Order : bool { increasing, /// decreasing /// } /** * Used to convert a hash value (a static or dynamic array of ubytes) to a string. * Can be used with the OOP and with the template API. * * The additional order parameter can be used to specify the order of the input data. * By default the data is processed in increasing order, starting at index 0. To process it in the * opposite order, pass Order.decreasing as a parameter. * * The additional letterCase parameter can be used to specify the case of the output data. * By default the output is in upper case. To change it to the lower case * pass LetterCase.lower as a parameter. * * Note: * The function overloads returning a string allocate their return values * using the GC. The versions returning static arrays use pass-by-value for * the return value, effectively avoiding dynamic allocation. */ char[num*2] toHexString(Order order = Order.increasing, size_t num, LetterCase letterCase = LetterCase.upper) (in ubyte[num] digest) { static if (letterCase == LetterCase.upper) { import std.ascii : hexDigits = hexDigits; } else { import std.ascii : hexDigits = lowerHexDigits; } char[num*2] result; size_t i; static if(order == Order.increasing) { foreach(u; digest) { result[i++] = hexDigits[u >> 4]; result[i++] = hexDigits[u & 15]; } } else { size_t j = num - 1; while(i < num*2) { result[i++] = hexDigits[digest[j] >> 4]; result[i++] = hexDigits[digest[j] & 15]; j--; } } return result; } ///ditto char[num*2] toHexString(LetterCase letterCase, Order order = Order.increasing, size_t num)(in ubyte[num] digest) { return toHexString!(order, num, letterCase)(digest); } ///ditto string toHexString(Order order = Order.increasing, LetterCase letterCase = LetterCase.upper) (in ubyte[] digest) { static if (letterCase == LetterCase.upper) { import std.ascii : hexDigits = hexDigits; } else { import std.ascii : hexDigits = lowerHexDigits; } auto result = new char[digest.length*2]; size_t i; static if(order == Order.increasing) { foreach(u; digest) { result[i++] = hexDigits[u >> 4]; result[i++] = hexDigits[u & 15]; } } else { import std.range : retro; foreach(u; retro(digest)) { result[i++] = hexDigits[u >> 4]; result[i++] = hexDigits[u & 15]; } } import std.exception : assumeUnique; return assumeUnique(result); } ///ditto string toHexString(LetterCase letterCase, Order order = Order.increasing)(in ubyte[] digest) { return toHexString!(order, letterCase)(digest); } //For more example unittests, see Digest.digest, digest /// unittest { import std.digest.crc; //Test with template API: auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); //Lower case variant: assert(toHexString!(LetterCase.lower)(crc32) == "39a34f41"); //Usually CRCs are printed in this order, though: assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); assert(toHexString!(LetterCase.lower, Order.decreasing)(crc32) == "414fa339"); } /// unittest { import std.digest.crc; // With OOP API auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); //Usually CRCs are printed in this order, though: assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); } unittest { ubyte[16] data; assert(toHexString(data) == "00000000000000000000000000000000"); assert(toHexString(cast(ubyte[4])[42, 43, 44, 45]) == "2A2B2C2D"); assert(toHexString(cast(ubyte[])[42, 43, 44, 45]) == "2A2B2C2D"); assert(toHexString!(Order.decreasing)(cast(ubyte[4])[42, 43, 44, 45]) == "2D2C2B2A"); assert(toHexString!(Order.decreasing, LetterCase.lower)(cast(ubyte[4])[42, 43, 44, 45]) == "2d2c2b2a"); assert(toHexString!(Order.decreasing)(cast(ubyte[])[42, 43, 44, 45]) == "2D2C2B2A"); } /*+*********************** End of public helper part, private helpers follow ***********************/ /* * Used to convert from a ubyte[] slice to a ref ubyte[N]. * This helper is used internally in the WrapperDigest template to wrap the template API's * finish function. */ ref T[N] asArray(size_t N, T)(ref T[] source, string errorMsg = "") { assert(source.length >= N, errorMsg); return *cast(T[N]*)source.ptr; } /** * This helper is used internally in the WrapperDigest template, but it might be * useful for other purposes as well. It returns the length (in bytes) of the hash value * produced by T. */ template digestLength(T) if(isDigest!T) { enum size_t digestLength = (ReturnType!(T.finish)).length; } /** * Wraps a template API hash struct into a Digest interface. * Modules providing digest implementations will usually provide * an alias for this template (e.g. MD5Digest, SHA1Digest, ...). */ class WrapperDigest(T) if(isDigest!T) : Digest { protected: T _digest; public final: /** * Initializes the digest. */ this() { _digest.start(); } /** * Use this to feed the digest with data. * Also implements the $(XREF_PACK range,primitives,isOutputRange) * interface for $(D ubyte) and $(D const(ubyte)[]). */ @trusted nothrow void put(scope const(ubyte)[] data...) { _digest.put(data); } /** * Resets the internal state of the digest. * Note: * $(LREF finish) calls this internally, so it's not necessary to call * $(D reset) manually after a call to $(LREF finish). */ @trusted nothrow void reset() { _digest.start(); } /** * This is the length in bytes of the hash value which is returned by $(LREF finish). * It's also the required size of a buffer passed to $(LREF finish). */ @trusted nothrow @property size_t length() const pure { return digestLength!T; } /** * The finish function returns the hash value. It takes an optional buffer to copy the data * into. If a buffer is passed, it must have a length at least $(LREF length) bytes. * * Example: * -------- * * import std.digest.md; * ubyte[16] buf; * auto hash = new WrapperDigest!MD5(); * hash.put(cast(ubyte)0); * auto result = hash.finish(buf[]); * //The result is now in result (and in buf). If you pass a buffer which is bigger than * //necessary, result will have the correct length, but buf will still have it's original * //length * -------- */ nothrow ubyte[] finish(scope ubyte[] buf) in { assert(buf.length >= this.length); } body { enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~ "big, check " ~ typeof(this).stringof ~ ".length!"; asArray!(digestLength!T)(buf, msg) = _digest.finish(); return buf[0 .. digestLength!T]; } ///ditto @trusted nothrow ubyte[] finish() { enum len = digestLength!T; auto buf = new ubyte[len]; asArray!(digestLength!T)(buf) = _digest.finish(); return buf; } version(StdDdoc) { /** * Works like $(D finish) but does not reset the internal state, so it's possible * to continue putting data into this WrapperDigest after a call to peek. * * These functions are only available if $(D hasPeek!T) is true. */ @trusted ubyte[] peek(scope ubyte[] buf) const; ///ditto @trusted ubyte[] peek() const; } else static if(hasPeek!T) { @trusted ubyte[] peek(scope ubyte[] buf) const in { assert(buf.length >= this.length); } body { enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~ "big, check " ~ typeof(this).stringof ~ ".length!"; asArray!(digestLength!T)(buf, msg) = _digest.peek(); return buf[0 .. digestLength!T]; } @trusted ubyte[] peek() const { enum len = digestLength!T; auto buf = new ubyte[len]; asArray!(digestLength!T)(buf) = _digest.peek(); return buf; } } } /// unittest { import std.digest.md; //Simple example auto hash = new WrapperDigest!MD5(); hash.put(cast(ubyte)0); auto result = hash.finish(); } /// unittest { //using a supplied buffer import std.digest.md; ubyte[16] buf; auto hash = new WrapperDigest!MD5(); hash.put(cast(ubyte)0); auto result = hash.finish(buf[]); //The result is now in result (and in buf). If you pass a buffer which is bigger than //necessary, result will have the correct length, but buf will still have it's original //length } ldc-1.1.0-beta3-src/runtime/phobos/std/encoding.d0000664000175000017500000026166212776215007017656 0ustar kaikai// Written in the D programming language. /** Classes and functions for handling and transcoding between various encodings. For cases where the _encoding is known at compile-time, functions are provided for arbitrary _encoding and decoding of characters, arbitrary transcoding between strings of different type, as well as validation and sanitization. Encodings currently supported are UTF-8, UTF-16, UTF-32, ASCII, ISO-8859-1 (also known as LATIN-1), ISO-8859-2 (LATIN-2), WINDOWS-1250 and WINDOWS-1252. $(UL $(LI The type $(D AsciiChar) represents an ASCII character.) $(LI The type $(D AsciiString) represents an ASCII string.) $(LI The type $(D Latin1Char) represents an ISO-8859-1 character.) $(LI The type $(D Latin1String) represents an ISO-8859-1 string.) $(LI The type $(D Latin2Char) represents an ISO-8859-2 character.) $(LI The type $(D Latin2String) represents an ISO-8859-2 string.) $(LI The type $(D Windows1250Char) represents a Windows-1250 character.) $(LI The type $(D Windows1250String) represents a Windows-1250 string.) $(LI The type $(D Windows1252Char) represents a Windows-1252 character.) $(LI The type $(D Windows1252String) represents a Windows-1252 string.)) For cases where the _encoding is not known at compile-time, but is known at run-time, we provide the abstract class $(D EncodingScheme) and its subclasses. To construct a run-time encoder/decoder, one does e.g. ---------------------------------------------------- auto e = EncodingScheme.create("utf-8"); ---------------------------------------------------- This library supplies $(D EncodingScheme) subclasses for ASCII, ISO-8859-1 (also known as LATIN-1), ISO-8859-2 (LATIN-2), WINDOWS-1250, WINDOWS-1252, UTF-8, and (on little-endian architectures) UTF-16LE and UTF-32LE; or (on big-endian architectures) UTF-16BE and UTF-32BE. This library provides a mechanism whereby other modules may add $(D EncodingScheme) subclasses for any other _encoding. Macros: WIKI=Phobos/StdEncoding Copyright: Copyright Janice Caron 2008 - 2009. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Janice Caron Source: $(PHOBOSSRC std/_encoding.d) */ /* Copyright Janice Caron 2008 - 2009. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.encoding; import std.traits; import std.range.primitives; unittest { static ubyte[][] validStrings = [ // Plain ASCII cast(ubyte[])"hello", // First possible sequence of a certain length [ 0x00 ], // U+00000000 one byte [ 0xC2, 0x80 ], // U+00000080 two bytes [ 0xE0, 0xA0, 0x80 ], // U+00000800 three bytes [ 0xF0, 0x90, 0x80, 0x80 ], // U+00010000 three bytes // Last possible sequence of a certain length [ 0x7F ], // U+0000007F one byte [ 0xDF, 0xBF ], // U+000007FF two bytes [ 0xEF, 0xBF, 0xBF ], // U+0000FFFF three bytes // Other boundary conditions [ 0xED, 0x9F, 0xBF ], // U+0000D7FF Last character before surrogates [ 0xEE, 0x80, 0x80 ], // U+0000E000 First character after surrogates [ 0xEF, 0xBF, 0xBD ], // U+0000FFFD Unicode replacement character [ 0xF4, 0x8F, 0xBF, 0xBF ], // U+0010FFFF Very last character // Non-character code points /* NOTE: These are legal in UTF, and may be converted from one UTF to another, however they do not represent Unicode characters. These code points have been reserved by Unicode as non-character code points. They are permissible for data exchange within an application, but they are are not permitted to be used as characters. Since this module deals with UTF, and not with Unicode per se, we choose to accept them here. */ [ 0xDF, 0xBE ], // U+0000FFFE [ 0xDF, 0xBF ], // U+0000FFFF ]; static ubyte[][] invalidStrings = [ // First possible sequence of a certain length, but greater // than U+10FFFF [ 0xF8, 0x88, 0x80, 0x80, 0x80 ], // U+00200000 five bytes [ 0xFC, 0x84, 0x80, 0x80, 0x80, 0x80 ], // U+04000000 six bytes // Last possible sequence of a certain length, but greater than U+10FFFF [ 0xF7, 0xBF, 0xBF, 0xBF ], // U+001FFFFF four bytes [ 0xFB, 0xBF, 0xBF, 0xBF, 0xBF ], // U+03FFFFFF five bytes [ 0xFD, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF ], // U+7FFFFFFF six bytes // Other boundary conditions [ 0xF4, 0x90, 0x80, 0x80 ], // U+00110000 // First code // point after // last character // Unexpected continuation bytes [ 0x80 ], [ 0xBF ], [ 0x20, 0x80, 0x20 ], [ 0x20, 0xBF, 0x20 ], [ 0x80, 0x9F, 0xA0 ], // Lonely start bytes [ 0xC0 ], [ 0xCF ], [ 0x20, 0xC0, 0x20 ], [ 0x20, 0xCF, 0x20 ], [ 0xD0 ], [ 0xDF ], [ 0x20, 0xD0, 0x20 ], [ 0x20, 0xDF, 0x20 ], [ 0xE0 ], [ 0xEF ], [ 0x20, 0xE0, 0x20 ], [ 0x20, 0xEF, 0x20 ], [ 0xF0 ], [ 0xF1 ], [ 0xF2 ], [ 0xF3 ], [ 0xF4 ], [ 0xF5 ], // If this were legal it would start a character > U+10FFFF [ 0xF6 ], // If this were legal it would start a character > U+10FFFF [ 0xF7 ], // If this were legal it would start a character > U+10FFFF [ 0xEF, 0xBF ], // Three byte sequence with third byte missing [ 0xF7, 0xBF, 0xBF ], // Four byte sequence with fourth byte missing [ 0xEF, 0xBF, 0xF7, 0xBF, 0xBF ], // Concatenation of the above // Impossible bytes [ 0xF8 ], [ 0xF9 ], [ 0xFA ], [ 0xFB ], [ 0xFC ], [ 0xFD ], [ 0xFE ], [ 0xFF ], [ 0x20, 0xF8, 0x20 ], [ 0x20, 0xF9, 0x20 ], [ 0x20, 0xFA, 0x20 ], [ 0x20, 0xFB, 0x20 ], [ 0x20, 0xFC, 0x20 ], [ 0x20, 0xFD, 0x20 ], [ 0x20, 0xFE, 0x20 ], [ 0x20, 0xFF, 0x20 ], // Overlong sequences, all representing U+002F /* With a safe UTF-8 decoder, all of the following five overlong representations of the ASCII character slash ("/") should be rejected like a malformed UTF-8 sequence */ [ 0xC0, 0xAF ], [ 0xE0, 0x80, 0xAF ], [ 0xF0, 0x80, 0x80, 0xAF ], [ 0xF8, 0x80, 0x80, 0x80, 0xAF ], [ 0xFC, 0x80, 0x80, 0x80, 0x80, 0xAF ], // Maximum overlong sequences /* Below you see the highest Unicode value that is still resulting in an overlong sequence if represented with the given number of bytes. This is a boundary test for safe UTF-8 decoders. All five characters should be rejected like malformed UTF-8 sequences. */ [ 0xC1, 0xBF ], // U+0000007F [ 0xE0, 0x9F, 0xBF ], // U+000007FF [ 0xF0, 0x8F, 0xBF, 0xBF ], // U+0000FFFF [ 0xF8, 0x87, 0xBF, 0xBF, 0xBF ], // U+001FFFFF [ 0xFC, 0x83, 0xBF, 0xBF, 0xBF, 0xBF ], // U+03FFFFFF // Overlong representation of the NUL character /* The following five sequences should also be rejected like malformed UTF-8 sequences and should not be treated like the ASCII NUL character. */ [ 0xC0, 0x80 ], [ 0xE0, 0x80, 0x80 ], [ 0xF0, 0x80, 0x80, 0x80 ], [ 0xF8, 0x80, 0x80, 0x80, 0x80 ], [ 0xFC, 0x80, 0x80, 0x80, 0x80, 0x80 ], // Illegal code positions /* The following UTF-8 sequences should be rejected like malformed sequences, because they never represent valid ISO 10646 characters and a UTF-8 decoder that accepts them might introduce security problems comparable to overlong UTF-8 sequences. */ [ 0xED, 0xA0, 0x80 ], // U+D800 [ 0xED, 0xAD, 0xBF ], // U+DB7F [ 0xED, 0xAE, 0x80 ], // U+DB80 [ 0xED, 0xAF, 0xBF ], // U+DBFF [ 0xED, 0xB0, 0x80 ], // U+DC00 [ 0xED, 0xBE, 0x80 ], // U+DF80 [ 0xED, 0xBF, 0xBF ], // U+DFFF ]; static string[] sanitizedStrings = [ "\uFFFD","\uFFFD", "\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD"," \uFFFD ", " \uFFFD ","\uFFFD\uFFFD\uFFFD","\uFFFD","\uFFFD"," \uFFFD "," \uFFFD ", "\uFFFD","\uFFFD"," \uFFFD "," \uFFFD ","\uFFFD","\uFFFD"," \uFFFD ", " \uFFFD ","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD", "\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD\uFFFD","\uFFFD","\uFFFD", "\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD"," \uFFFD ", " \uFFFD "," \uFFFD "," \uFFFD "," \uFFFD "," \uFFFD "," \uFFFD ", " \uFFFD ","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD", "\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD", "\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD","\uFFFD", ]; // Make sure everything that should be valid, is foreach(a;validStrings) { string s = cast(string)a; assert(isValid(s),"Failed to validate: "~makeReadable(s)); } // Make sure everything that shouldn't be valid, isn't foreach(a;invalidStrings) { string s = cast(string)a; assert(!isValid(s),"Incorrectly validated: "~makeReadable(s)); } // Make sure we can sanitize everything bad assert(invalidStrings.length == sanitizedStrings.length); for(int i=0; i m_charMapEnd && c < 0x100)) return true; if (c >= 0xFFFD) return false; auto idx = 0; while (idx < bstMap.length) { if (bstMap[idx][0] == c) return true; idx = bstMap[idx][0] > c ? 2 * idx + 1 : 2 * idx + 2; // next BST index } return false; } bool isValidCodeUnit(E c) { if (c < m_charMapStart || c > m_charMapEnd) return true; return charMap[c-m_charMapStart] != 0xFFFD; } size_t encodedLength(dchar c) in { assert(canEncode(c)); } body { return 1; } void encodeViaWrite()(dchar c) { if (c < m_charMapStart || (c > m_charMapEnd && c < 0x100)) {} else if (c >= 0xFFFD) { c = '?'; } else { auto idx = 0; while (idx < bstMap.length) { if (bstMap[idx][0] == c) { write(cast(E)bstMap[idx][1]); return; } idx = bstMap[idx][0] > c ? 2 * idx + 1 : 2 * idx + 2; // next BST index } c = '?'; } write(cast(E)c); } void skipViaRead()() { read(); } dchar decodeViaRead()() { E c = read(); return (c >= m_charMapStart && c <= m_charMapEnd) ? charMap[c-m_charMapStart] : c; } dchar safeDecodeViaRead()() { E c = read(); dchar d = (c >= m_charMapStart && c <= m_charMapEnd) ? charMap[c-m_charMapStart] : c; return d == 0xFFFD ? INVALID_SEQUENCE : d; } dchar decodeReverseViaRead()() { E c = read(); return (c >= m_charMapStart && c <= m_charMapEnd) ? charMap[c-m_charMapStart] : c; } @property EString replacementSequence() { return cast(EString)("?"); } mixin EncoderFunctions; } //============================================================================= // ASCII //============================================================================= /** Defines various character sets. */ enum AsciiChar : ubyte { init } /// Ditto alias AsciiString = immutable(AsciiChar)[]; template EncoderInstance(CharType : AsciiChar) { alias E = AsciiChar; alias EString = AsciiString; @property string encodingName() { return "ASCII"; } bool canEncode(dchar c) { return c < 0x80; } bool isValidCodeUnit(AsciiChar c) { return c < 0x80; } size_t encodedLength(dchar c) in { assert(canEncode(c)); } body { return 1; } void encodeX(Range)(dchar c, Range r) { if (!canEncode(c)) c = '?'; r.write(cast(AsciiChar) c); } void encodeViaWrite()(dchar c) { if (!canEncode(c)) c = '?'; write(cast(AsciiChar)c); } void skipViaRead()() { read(); } dchar decodeViaRead()() { return read(); } dchar safeDecodeViaRead()() { dchar c = read(); return canEncode(c) ? c : INVALID_SEQUENCE; } dchar decodeReverseViaRead()() { return read(); } @property EString replacementSequence() { return cast(EString)("?"); } mixin EncoderFunctions; } //============================================================================= // ISO-8859-1 //============================================================================= /** Defines an Latin1-encoded character. */ enum Latin1Char : ubyte { init } /** Defines an Latin1-encoded string (as an array of $(D immutable(Latin1Char))). */ alias Latin1String = immutable(Latin1Char)[]; template EncoderInstance(CharType : Latin1Char) { alias E = Latin1Char; alias EString = Latin1String; @property string encodingName() { return "ISO-8859-1"; } bool canEncode(dchar c) { return c < 0x100; } bool isValidCodeUnit(Latin1Char c) { return true; } size_t encodedLength(dchar c) in { assert(canEncode(c)); } body { return 1; } void encodeViaWrite()(dchar c) { if (!canEncode(c)) c = '?'; write(cast(Latin1Char)c); } void skipViaRead()() { read(); } dchar decodeViaRead()() { return read(); } dchar safeDecodeViaRead()() { return read(); } dchar decodeReverseViaRead()() { return read(); } @property EString replacementSequence() { return cast(EString)("?"); } mixin EncoderFunctions; } //============================================================================= // ISO-8859-2 //============================================================================= /// Defines a Latin2-encoded character. enum Latin2Char : ubyte { init } /** * Defines an Latin2-encoded string (as an array of $(D * immutable(Latin2Char))). */ alias Latin2String = immutable(Latin2Char)[]; private template EncoderInstance(CharType : Latin2Char) { import std.typecons : Tuple, tuple; alias E = Latin2Char; alias EString = Latin2String; @property string encodingName() { return "ISO-8859-2"; } private dchar m_charMapStart = 0xa1; private dchar m_charMapEnd = 0xff; private immutable wstring charMap = "\u0104\u02D8\u0141\u00A4\u013D\u015A\u00A7\u00A8"~ "\u0160\u015E\u0164\u0179\u00AD\u017D\u017B\u00B0"~ "\u0105\u02DB\u0142\u00B4\u013E\u015B\u02C7\u00B8"~ "\u0161\u015F\u0165\u017A\u02DD\u017E\u017C\u0154"~ "\u00C1\u00C2\u0102\u00C4\u0139\u0106\u00C7\u010C"~ "\u00C9\u0118\u00CB\u011A\u00CD\u00CE\u010E\u0110"~ "\u0143\u0147\u00D3\u00D4\u0150\u00D6\u00D7\u0158"~ "\u016E\u00DA\u0170\u00DC\u00DD\u0162\u00DF\u0155"~ "\u00E1\u00E2\u0103\u00E4\u013A\u0107\u00E7\u010D"~ "\u00E9\u0119\u00EB\u011B\u00ED\u00EE\u010F\u0111"~ "\u0144\u0148\u00F3\u00F4\u0151\u00F6\u00F7\u0159"~ "\u016F\u00FA\u0171\u00FC\u00FD\u0163\u02D9"; private immutable Tuple!(wchar, char)[] bstMap = [ tuple('\u0148','\xF2'), tuple('\u00F3','\xF3'), tuple('\u0165','\xBB'), tuple('\u00D3','\xD3'), tuple('\u010F','\xEF'), tuple('\u015B','\xB6'), tuple('\u017C','\xBF'), tuple('\u00C1','\xC1'), tuple('\u00E1','\xE1'), tuple('\u0103','\xE3'), tuple('\u013A','\xE5'), tuple('\u0155','\xE0'), tuple('\u0161','\xB9'), tuple('\u0171','\xFB'), tuple('\u02D8','\xA2'), tuple('\u00AD','\xAD'), tuple('\u00C9','\xC9'), tuple('\u00DA','\xDA'), tuple('\u00E9','\xE9'), tuple('\u00FA','\xFA'), tuple('\u0107','\xE6'), tuple('\u0119','\xEA'), tuple('\u0142','\xB3'), tuple('\u0151','\xF5'), tuple('\u0159','\xF8'), tuple('\u015F','\xBA'), tuple('\u0163','\xFE'), tuple('\u016F','\xF9'), tuple('\u017A','\xBC'), tuple('\u017E','\xBE'), tuple('\u02DB','\xB2'), tuple('\u00A7','\xA7'), tuple('\u00B4','\xB4'), tuple('\u00C4','\xC4'), tuple('\u00CD','\xCD'), tuple('\u00D6','\xD6'), tuple('\u00DD','\xDD'), tuple('\u00E4','\xE4'), tuple('\u00ED','\xED'), tuple('\u00F6','\xF6'), tuple('\u00FD','\xFD'), tuple('\u0105','\xB1'), tuple('\u010D','\xE8'), tuple('\u0111','\xF0'), tuple('\u011B','\xEC'), tuple('\u013E','\xB5'), tuple('\u0144','\xF1'), tuple('\u0150','\xD5'), tuple('\u0154','\xC0'), tuple('\u0158','\xD8'), tuple('\u015A','\xA6'), tuple('\u015E','\xAA'), tuple('\u0160','\xA9'), tuple('\u0162','\xDE'), tuple('\u0164','\xAB'), tuple('\u016E','\xD9'), tuple('\u0170','\xDB'), tuple('\u0179','\xAC'), tuple('\u017B','\xAF'), tuple('\u017D','\xAE'), tuple('\u02C7','\xB7'), tuple('\u02D9','\xFF'), tuple('\u02DD','\xBD'), tuple('\u00A4','\xA4'), tuple('\u00A8','\xA8'), tuple('\u00B0','\xB0'), tuple('\u00B8','\xB8'), tuple('\u00C2','\xC2'), tuple('\u00C7','\xC7'), tuple('\u00CB','\xCB'), tuple('\u00CE','\xCE'), tuple('\u00D4','\xD4'), tuple('\u00D7','\xD7'), tuple('\u00DC','\xDC'), tuple('\u00DF','\xDF'), tuple('\u00E2','\xE2'), tuple('\u00E7','\xE7'), tuple('\u00EB','\xEB'), tuple('\u00EE','\xEE'), tuple('\u00F4','\xF4'), tuple('\u00F7','\xF7'), tuple('\u00FC','\xFC'), tuple('\u0102','\xC3'), tuple('\u0104','\xA1'), tuple('\u0106','\xC6'), tuple('\u010C','\xC8'), tuple('\u010E','\xCF'), tuple('\u0110','\xD0'), tuple('\u0118','\xCA'), tuple('\u011A','\xCC'), tuple('\u0139','\xC5'), tuple('\u013D','\xA5'), tuple('\u0141','\xA3'), tuple('\u0143','\xD1'), tuple('\u0147','\xD2') ]; mixin GenericEncoder!(); } //============================================================================= // WINDOWS-1250 //============================================================================= /// Defines a Windows1250-encoded character. enum Windows1250Char : ubyte { init } /** * Defines an Windows1250-encoded string (as an array of $(D * immutable(Windows1250Char))). */ alias Windows1250String = immutable(Windows1250Char)[]; private template EncoderInstance(CharType : Windows1250Char) { import std.typecons : Tuple, tuple; alias E = Windows1250Char; alias EString = Windows1250String; @property string encodingName() { return "windows-1250"; } private dchar m_charMapStart = 0x80; private dchar m_charMapEnd = 0xff; private immutable wstring charMap = "\u20AC\uFFFD\u201A\uFFFD\u201E\u2026\u2020\u2021"~ "\uFFFD\u2030\u0160\u2039\u015A\u0164\u017D\u0179"~ "\uFFFD\u2018\u2019\u201C\u201D\u2022\u2013\u2014"~ "\uFFFD\u2122\u0161\u203A\u015B\u0165\u017E\u017A"~ "\u00A0\u02C7\u02D8\u0141\u00A4\u0104\u00A6\u00A7"~ "\u00A8\u00A9\u015E\u00AB\u00AC\u00AD\u00AE\u017B"~ "\u00B0\u00B1\u02DB\u0142\u00B4\u00B5\u00B6\u00B7"~ "\u00B8\u0105\u015F\u00BB\u013D\u02DD\u013E\u017C"~ "\u0154\u00C1\u00C2\u0102\u00C4\u0139\u0106\u00C7"~ "\u010C\u00C9\u0118\u00CB\u011A\u00CD\u00CE\u010E"~ "\u0110\u0143\u0147\u00D3\u00D4\u0150\u00D6\u00D7"~ "\u0158\u016E\u00DA\u0170\u00DC\u00DD\u0162\u00DF"~ "\u0155\u00E1\u00E2\u0103\u00E4\u013A\u0107\u00E7"~ "\u010D\u00E9\u0119\u00EB\u011B\u00ED\u00EE\u010F"~ "\u0111\u0144\u0148\u00F3\u00F4\u0151\u00F6\u00F7"~ "\u0159\u016F\u00FA\u0171\u00FC\u00FD\u0163\u02D9"; private immutable Tuple!(wchar, char)[] bstMap = [ tuple('\u011A','\xCC'), tuple('\u00DC','\xDC'), tuple('\u0179','\x8F'), tuple('\u00B7','\xB7'), tuple('\u00FC','\xFC'), tuple('\u0158','\xD8'), tuple('\u201C','\x93'), tuple('\u00AC','\xAC'), tuple('\u00CB','\xCB'), tuple('\u00EB','\xEB'), tuple('\u010C','\xC8'), tuple('\u0143','\xD1'), tuple('\u0162','\xDE'), tuple('\u02D9','\xFF'), tuple('\u2039','\x8B'), tuple('\u00A7','\xA7'), tuple('\u00B1','\xB1'), tuple('\u00C2','\xC2'), tuple('\u00D4','\xD4'), tuple('\u00E2','\xE2'), tuple('\u00F4','\xF4'), tuple('\u0104','\xA5'), tuple('\u0110','\xD0'), tuple('\u013D','\xBC'), tuple('\u0150','\xD5'), tuple('\u015E','\xAA'), tuple('\u016E','\xD9'), tuple('\u017D','\x8E'), tuple('\u2014','\x97'), tuple('\u2021','\x87'), tuple('\u20AC','\x80'), tuple('\u00A4','\xA4'), tuple('\u00A9','\xA9'), tuple('\u00AE','\xAE'), tuple('\u00B5','\xB5'), tuple('\u00BB','\xBB'), tuple('\u00C7','\xC7'), tuple('\u00CE','\xCE'), tuple('\u00D7','\xD7'), tuple('\u00DF','\xDF'), tuple('\u00E7','\xE7'), tuple('\u00EE','\xEE'), tuple('\u00F7','\xF7'), tuple('\u0102','\xC3'), tuple('\u0106','\xC6'), tuple('\u010E','\xCF'), tuple('\u0118','\xCA'), tuple('\u0139','\xC5'), tuple('\u0141','\xA3'), tuple('\u0147','\xD2'), tuple('\u0154','\xC0'), tuple('\u015A','\x8C'), tuple('\u0160','\x8A'), tuple('\u0164','\x8D'), tuple('\u0170','\xDB'), tuple('\u017B','\xAF'), tuple('\u02C7','\xA1'), tuple('\u02DD','\xBD'), tuple('\u2019','\x92'), tuple('\u201E','\x84'), tuple('\u2026','\x85'), tuple('\u203A','\x9B'), tuple('\u2122','\x99'), tuple('\u00A0','\xA0'), tuple('\u00A6','\xA6'), tuple('\u00A8','\xA8'), tuple('\u00AB','\xAB'), tuple('\u00AD','\xAD'), tuple('\u00B0','\xB0'), tuple('\u00B4','\xB4'), tuple('\u00B6','\xB6'), tuple('\u00B8','\xB8'), tuple('\u00C1','\xC1'), tuple('\u00C4','\xC4'), tuple('\u00C9','\xC9'), tuple('\u00CD','\xCD'), tuple('\u00D3','\xD3'), tuple('\u00D6','\xD6'), tuple('\u00DA','\xDA'), tuple('\u00DD','\xDD'), tuple('\u00E1','\xE1'), tuple('\u00E4','\xE4'), tuple('\u00E9','\xE9'), tuple('\u00ED','\xED'), tuple('\u00F3','\xF3'), tuple('\u00F6','\xF6'), tuple('\u00FA','\xFA'), tuple('\u00FD','\xFD'), tuple('\u0103','\xE3'), tuple('\u0105','\xB9'), tuple('\u0107','\xE6'), tuple('\u010D','\xE8'), tuple('\u010F','\xEF'), tuple('\u0111','\xF0'), tuple('\u0119','\xEA'), tuple('\u011B','\xEC'), tuple('\u013A','\xE5'), tuple('\u013E','\xBE'), tuple('\u0142','\xB3'), tuple('\u0144','\xF1'), tuple('\u0148','\xF2'), tuple('\u0151','\xF5'), tuple('\u0155','\xE0'), tuple('\u0159','\xF8'), tuple('\u015B','\x9C'), tuple('\u015F','\xBA'), tuple('\u0161','\x9A'), tuple('\u0163','\xFE'), tuple('\u0165','\x9D'), tuple('\u016F','\xF9'), tuple('\u0171','\xFB'), tuple('\u017A','\x9F'), tuple('\u017C','\xBF'), tuple('\u017E','\x9E'), tuple('\u02D8','\xA2'), tuple('\u02DB','\xB2'), tuple('\u2013','\x96'), tuple('\u2018','\x91'), tuple('\u201A','\x82'), tuple('\u201D','\x94'), tuple('\u2020','\x86'), tuple('\u2022','\x95'), tuple('\u2030','\x89') ]; mixin GenericEncoder!(); } //============================================================================= // WINDOWS-1252 //============================================================================= /// Defines a Windows1252-encoded character. enum Windows1252Char : ubyte { init } /** * Defines an Windows1252-encoded string (as an array of $(D * immutable(Windows1252Char))). */ alias Windows1252String = immutable(Windows1252Char)[]; template EncoderInstance(CharType : Windows1252Char) { import std.typecons : Tuple, tuple; alias E = Windows1252Char; alias EString = Windows1252String; @property string encodingName() { return "windows-1252"; } private dchar m_charMapStart = 0x80; private dchar m_charMapEnd = 0x9f; private immutable wstring charMap = "\u20AC\uFFFD\u201A\u0192\u201E\u2026\u2020\u2021"~ "\u02C6\u2030\u0160\u2039\u0152\uFFFD\u017D\uFFFD"~ "\uFFFD\u2018\u2019\u201C\u201D\u2022\u2013\u2014"~ "\u02DC\u2122\u0161\u203A\u0153\uFFFD\u017E\u0178"; private immutable Tuple!(wchar, char)[] bstMap = [ tuple('\u201C','\x93'), tuple('\u0192','\x83'), tuple('\u2039','\x8B'), tuple('\u0161','\x9A'), tuple('\u2014','\x97'), tuple('\u2021','\x87'), tuple('\u20AC','\x80'), tuple('\u0153','\x9C'), tuple('\u017D','\x8E'), tuple('\u02DC','\x98'), tuple('\u2019','\x92'), tuple('\u201E','\x84'), tuple('\u2026','\x85'), tuple('\u203A','\x9B'), tuple('\u2122','\x99'), tuple('\u0152','\x8C'), tuple('\u0160','\x8A'), tuple('\u0178','\x9F'), tuple('\u017E','\x9E'), tuple('\u02C6','\x88'), tuple('\u2013','\x96'), tuple('\u2018','\x91'), tuple('\u201A','\x82'), tuple('\u201D','\x94'), tuple('\u2020','\x86'), tuple('\u2022','\x95'), tuple('\u2030','\x89') ]; mixin GenericEncoder!(); } //============================================================================= // UTF-8 //============================================================================= template EncoderInstance(CharType : char) { alias E = char; alias EString = immutable(char)[]; @property string encodingName() { return "UTF-8"; } bool canEncode(dchar c) { return isValidCodePoint(c); } bool isValidCodeUnit(char c) { return (c < 0xC0 || (c >= 0xC2 && c < 0xF5)); } immutable ubyte[128] tailTable = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,6,0, ]; private int tails(char c) in { assert(c >= 0x80); } body { return tailTable[c-0x80]; } size_t encodedLength(dchar c) in { assert(canEncode(c)); } body { if (c < 0x80) return 1; if (c < 0x800) return 2; if (c < 0x10000) return 3; return 4; } void encodeViaWrite()(dchar c) { if (c < 0x80) { write(cast(char)c); } else if (c < 0x800) { write(cast(char)((c >> 6) + 0xC0)); write(cast(char)((c & 0x3F) + 0x80)); } else if (c < 0x10000) { write(cast(char)((c >> 12) + 0xE0)); write(cast(char)(((c >> 6) & 0x3F) + 0x80)); write(cast(char)((c & 0x3F) + 0x80)); } else { write(cast(char)((c >> 18) + 0xF0)); write(cast(char)(((c >> 12) & 0x3F) + 0x80)); write(cast(char)(((c >> 6) & 0x3F) + 0x80)); write(cast(char)((c & 0x3F) + 0x80)); } } void skipViaRead()() { auto c = read(); if (c < 0xC0) return; int n = tails(cast(char) c); for (size_t i=0; i 0xF4) // fail overlong 4-6-byte sequences || (c == 0xE0 && ((d & 0xE0) == 0x80)) // fail overlong 3-byte sequences || (c == 0xED && ((d & 0xE0) == 0xA0)) // fail surrogates || (c == 0xF0 && ((d & 0xF0) == 0x80)) // fail overlong 4-byte sequences || (c == 0xF4 && ((d & 0xF0) >= 0x90)) // fail code points > 0x10FFFF ); c &= (1 << (6 - n)) - 1; for (size_t i=0; i> 10))); write(cast(wchar)(0xDC00 + (n & 0x3FF))); } } void skipViaRead()() { wchar c = read(); if (c < 0xD800 || c >= 0xE000) return; read(); } dchar decodeViaRead()() { wchar c = read(); if (c < 0xD800 || c >= 0xE000) return cast(dchar)c; wchar d = read(); c &= 0x3FF; d &= 0x3FF; return 0x10000 + (c << 10) + d; } dchar safeDecodeViaRead()() { wchar c = read(); if (c < 0xD800 || c >= 0xE000) return cast(dchar)c; if (c >= 0xDC00) return INVALID_SEQUENCE; if (!canRead) return INVALID_SEQUENCE; wchar d = peek(); if (d < 0xDC00 || d >= 0xE000) return INVALID_SEQUENCE; d = read(); c &= 0x3FF; d &= 0x3FF; return 0x10000 + (c << 10) + d; } dchar decodeReverseViaRead()() { wchar c = read(); if (c < 0xD800 || c >= 0xE000) return cast(dchar)c; wchar d = read(); c &= 0x3FF; d &= 0x3FF; return 0x10000 + (d << 10) + c; } @property EString replacementSequence() { return "\uFFFD"w; } mixin EncoderFunctions; } //============================================================================= // UTF-32 //============================================================================= template EncoderInstance(CharType : dchar) { alias E = dchar; alias EString = immutable(dchar)[]; @property string encodingName() { return "UTF-32"; } bool canEncode(dchar c) { return isValidCodePoint(c); } bool isValidCodeUnit(dchar c) { return isValidCodePoint(c); } size_t encodedLength(dchar c) in { assert(canEncode(c)); } body { return 1; } void encodeViaWrite()(dchar c) { write(c); } void skipViaRead()() { read(); } dchar decodeViaRead()() { return cast(dchar)read(); } dchar safeDecodeViaRead()() { dchar c = read(); return isValidCodePoint(c) ? c : INVALID_SEQUENCE; } dchar decodeReverseViaRead()() { return cast(dchar)read(); } @property EString replacementSequence() { return "\uFFFD"d; } mixin EncoderFunctions; } //============================================================================= // Below are forwarding functions which expose the function to the user /** Returns true if c is a valid code point Note that this includes the non-character code points U+FFFE and U+FFFF, since these are valid code points (even though they are not valid characters). Supersedes: This function supersedes $(D std.utf.startsValidDchar()). Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: c = the code point to be tested */ bool isValidCodePoint(dchar c) { return c < 0xD800 || (c >= 0xE000 && c < 0x110000); } /** Returns the name of an encoding. The type of encoding cannot be deduced. Therefore, it is necessary to explicitly specify the encoding type. Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 */ @property string encodingName(T)() { return EncoderInstance!(T).encodingName; } /// unittest { assert(encodingName!(char) == "UTF-8"); assert(encodingName!(wchar) == "UTF-16"); assert(encodingName!(dchar) == "UTF-32"); assert(encodingName!(AsciiChar) == "ASCII"); assert(encodingName!(Latin1Char) == "ISO-8859-1"); assert(encodingName!(Latin2Char) == "ISO-8859-2"); assert(encodingName!(Windows1250Char) == "windows-1250"); assert(encodingName!(Windows1252Char) == "windows-1252"); } /** Returns true iff it is possible to represent the specified codepoint in the encoding. The type of encoding cannot be deduced. Therefore, it is necessary to explicitly specify the encoding type. Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 */ bool canEncode(E)(dchar c) { return EncoderInstance!(E).canEncode(c); } /// unittest { assert( canEncode!(Latin1Char)('A')); assert( canEncode!(Latin2Char)('A')); assert(!canEncode!(AsciiChar)('\u00A0')); assert( canEncode!(Latin1Char)('\u00A0')); assert( canEncode!(Latin2Char)('\u00A0')); assert( canEncode!(Windows1250Char)('\u20AC')); assert(!canEncode!(Windows1250Char)('\u20AD')); assert(!canEncode!(Windows1250Char)('\uFFFD')); assert( canEncode!(Windows1252Char)('\u20AC')); assert(!canEncode!(Windows1252Char)('\u20AD')); assert(!canEncode!(Windows1252Char)('\uFFFD')); assert(!canEncode!(char)(cast(dchar)0x110000)); } /** Returns true if the code unit is legal. For example, the byte 0x80 would not be legal in ASCII, because ASCII code units must always be in the range 0x00 to 0x7F. Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: c = the code unit to be tested */ bool isValidCodeUnit(E)(E c) { return EncoderInstance!(E).isValidCodeUnit(c); } /// unittest { assert(!isValidCodeUnit(cast(char)0xC0)); assert(!isValidCodeUnit(cast(char)0xFF)); assert( isValidCodeUnit(cast(wchar)0xD800)); assert(!isValidCodeUnit(cast(dchar)0xD800)); assert(!isValidCodeUnit(cast(AsciiChar)0xA0)); assert( isValidCodeUnit(cast(Windows1250Char)0x80)); assert(!isValidCodeUnit(cast(Windows1250Char)0x81)); assert( isValidCodeUnit(cast(Windows1252Char)0x80)); assert(!isValidCodeUnit(cast(Windows1252Char)0x81)); } /** Returns true if the string is encoded correctly Supersedes: This function supersedes std.utf.validate(), however note that this function returns a bool indicating whether the input was valid or not, whereas the older function would throw an exception. Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: s = the string to be tested */ bool isValid(E)(const(E)[] s) { return s.length == validLength(s); } /// unittest { assert( isValid("\u20AC100")); assert(!isValid(cast(char[3])[167, 133, 175])); } /** Returns the length of the longest possible substring, starting from the first code unit, which is validly encoded. Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: s = the string to be tested */ size_t validLength(E)(const(E)[] s) { size_t result, before = void; while ((before = s.length) > 0) { if (EncoderInstance!(E).safeDecode(s) == INVALID_SEQUENCE) break; result += before - s.length; } return result; } /** Sanitizes a string by replacing malformed code unit sequences with valid code unit sequences. The result is guaranteed to be valid for this encoding. If the input string is already valid, this function returns the original, otherwise it constructs a new string by replacing all illegal code unit sequences with the encoding's replacement character, Invalid sequences will be replaced with the Unicode replacement character (U+FFFD) if the character repertoire contains it, otherwise invalid sequences will be replaced with '?'. Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: s = the string to be sanitized */ immutable(E)[] sanitize(E)(immutable(E)[] s) { size_t n = validLength(s); if (n == s.length) return s; auto repSeq = EncoderInstance!(E).replacementSequence; // Count how long the string needs to be. // Overestimating is not a problem size_t len = s.length; const(E)[] t = s[n..$]; while (t.length != 0) { dchar c = EncoderInstance!(E).safeDecode(t); assert(c == INVALID_SEQUENCE); len += repSeq.length; t = t[validLength(t)..$]; } // Now do the write E[] array = new E[len]; array[0..n] = s[0..n]; size_t offset = n; t = s[n..$]; while (t.length != 0) { dchar c = EncoderInstance!(E).safeDecode(t); assert(c == INVALID_SEQUENCE); array[offset..offset+repSeq.length] = repSeq[]; offset += repSeq.length; n = validLength(t); array[offset..offset+n] = t[0..n]; offset += n; t = t[n..$]; } return cast(immutable(E)[])array[0..offset]; } /// unittest { assert(sanitize("hello \xF0\x80world") == "hello \xEF\xBF\xBDworld"); } /** Returns the length of the first encoded sequence. The input to this function MUST be validly encoded. This is enforced by the function's in-contract. Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: s = the string to be sliced */ size_t firstSequence(E)(const(E)[] s) in { assert(s.length != 0); const(E)[] u = s; assert(safeDecode(u) != INVALID_SEQUENCE); } body { auto before = s.length; EncoderInstance!(E).skip(s); return before - s.length; } /// unittest { assert(firstSequence("\u20AC1000") == "\u20AC".length); assert(firstSequence("hel") == "h".length); } /** Returns the length of the last encoded sequence. The input to this function MUST be validly encoded. This is enforced by the function's in-contract. Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: s = the string to be sliced */ size_t lastSequence(E)(const(E)[] s) in { assert(s.length != 0); assert(isValid(s)); } body { const(E)[] t = s; EncoderInstance!(E).decodeReverse(s); return t.length - s.length; } /// unittest { assert(lastSequence("1000\u20AC") == "\u20AC".length); assert(lastSequence("hellö") == "ö".length); } /** Returns the array index at which the (n+1)th code point begins. The input to this function MUST be validly encoded. This is enforced by the function's in-contract. Supersedes: This function supersedes std.utf.toUTFindex(). Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: s = the string to be counted n = the current code point index */ ptrdiff_t index(E)(const(E)[] s,int n) in { assert(isValid(s)); assert(n >= 0); } body { const(E)[] t = s; for (size_t i=0; i> 6))); put(range, cast(char)(0x80 | (c & 0x3F))); return 2; } if (c <= 0xFFFF) { put(range, cast(char)(0xE0 | (c >> 12))); put(range, cast(char)(0x80 | ((c >> 6) & 0x3F))); put(range, cast(char)(0x80 | (c & 0x3F))); return 3; } if (c <= 0x10FFFF) { put(range, cast(char)(0xF0 | (c >> 18))); put(range, cast(char)(0x80 | ((c >> 12) & 0x3F))); put(range, cast(char)(0x80 | ((c >> 6) & 0x3F))); put(range, cast(char)(0x80 | (c & 0x3F))); return 4; } else { assert(0); } } else static if (is(Unqual!E == wchar)) { if (c <= 0xFFFF) { range.put(cast(wchar) c); return 1; } range.put(cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800)); range.put(cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00)); return 2; } else static if (is(Unqual!E == dchar)) { range.put(c); return 1; } else { static assert(0); } } unittest { import std.array; Appender!(char[]) r; assert(encode!(char)('T', r) == 1); assert(encode!(wchar)('T', r) == 1); assert(encode!(dchar)('T', r) == 1); } /** Encodes a single code point to a delegate. This function encodes a single code point into one or more code units. The code units are passed one at a time to the supplied delegate. The input to this function MUST be a valid code point. This is enforced by the function's in-contract. The type of the output cannot be deduced. Therefore, it is necessary to explicitly specify the encoding as a template parameter. Supersedes: This function supersedes std.utf.encode(), however, note that the function codeUnits() supersedes it more conveniently. Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: c = the code point to be encoded dg = the delegate to invoke for each code unit */ void encode(E)(dchar c, void delegate(E) dg) in { assert(isValidCodePoint(c)); } body { EncoderInstance!(E).encode(c,dg); } /** Encodes the contents of $(D s) in units of type $(D Tgt), writing the result to an output range. Returns: The number of $(D Tgt) elements written. Params: Tgt = Element type of $(D range). s = Input array. range = Output range. */ size_t encode(Tgt, Src, R)(in Src[] s, R range) { size_t result; foreach (c; s) { result += encode!(Tgt)(c, range); } return result; } /** Returns a foreachable struct which can bidirectionally iterate over all code points in a string. The input to this function MUST be validly encoded. This is enforced by the function's in-contract. You can foreach either with or without an index. If an index is specified, it will be initialized at each iteration with the offset into the string at which the code point begins. Supersedes: This function supersedes std.utf.decode(). Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: s = the string to be decoded Example: -------------------------------------------------------- string s = "hello world"; foreach(c;codePoints(s)) { // do something with c (which will always be a dchar) } -------------------------------------------------------- Note that, currently, foreach(c:codePoints(s)) is superior to foreach(c;s) in that the latter will fall over on encountering U+FFFF. */ CodePoints!(E) codePoints(E)(immutable(E)[] s) in { assert(isValid(s)); } body { return CodePoints!(E)(s); } /// unittest { string s = "hello"; string t; foreach(c;codePoints(s)) { t ~= cast(char)c; } assert(s == t); } /** Returns a foreachable struct which can bidirectionally iterate over all code units in a code point. The input to this function MUST be a valid code point. This is enforced by the function's in-contract. The type of the output cannot be deduced. Therefore, it is necessary to explicitly specify the encoding type in the template parameter. Supersedes: This function supersedes std.utf.encode(). Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: c = the code point to be encoded */ CodeUnits!(E) codeUnits(E)(dchar c) in { assert(isValidCodePoint(c)); } body { return CodeUnits!(E)(c); } /// unittest { char[] a; foreach(c;codeUnits!(char)(cast(dchar)'\u20AC')) { a ~= c; } assert(a.length == 3); assert(a[0] == 0xE2); assert(a[1] == 0x82); assert(a[2] == 0xAC); } /** Convert a string from one encoding to another. Supersedes: This function supersedes std.utf.toUTF8(), std.utf.toUTF16() and std.utf.toUTF32() (but note that to!() supersedes it more conveniently). Standards: Unicode 5.0, ASCII, ISO-8859-1, ISO-8859-2, WINDOWS-1250, WINDOWS-1252 Params: s = Source string. $(B Must) be validly encoded. This is enforced by the function's in-contract. r = Destination string See_Also: $(XREF conv, to) */ void transcode(Src,Dst)(immutable(Src)[] s,out immutable(Dst)[] r) in { assert(isValid(s)); } body { static if(is(Src==Dst)) { r = s; } else static if(is(Src==AsciiChar)) { transcode!(char,Dst)(cast(string)s,r); } else { static if(is(Dst == wchar)) { immutable minReservePlace = 2; } else static if(is(Dst == dchar)) { immutable minReservePlace = 1; } else { immutable minReservePlace = 6; } Dst[] buffer = new Dst[s.length]; Dst[] tmpBuffer = buffer; const(Src)[] t = s; while (t.length != 0) { if(tmpBuffer.length < minReservePlace) { size_t prevLength = buffer.length; buffer.length += t.length + minReservePlace; tmpBuffer = buffer[prevLength - tmpBuffer.length .. $]; } EncoderInstance!(Dst).encode(decode(t), tmpBuffer); } r = cast(immutable)buffer[0 .. buffer.length - tmpBuffer.length]; } } /// unittest { wstring ws; // transcode from UTF-8 to UTF-16 transcode("hello world",ws); assert(ws == "hello world"w); Latin1String ls; // transcode from UTF-16 to ISO-8859-1 transcode(ws, ls); assert(ws == "hello world"); } unittest { import std.meta; import std.range; { import std.conv : to; string asciiCharString = to!string(iota(0, 128, 1)); alias Types = AliasSeq!(string, Latin1String, Latin2String, AsciiString, Windows1250String, Windows1252String, dstring, wstring); foreach(S; Types) foreach(D; Types) { string str; S sStr; D dStr; transcode(asciiCharString, sStr); transcode(sStr, dStr); transcode(dStr, str); assert(asciiCharString == str); } } { string czechChars = "Příliš žluťoučký kůň úpěl ďábelské ódy."; alias Types = AliasSeq!(string, dstring, wstring); foreach(S; Types) foreach(D; Types) { string str; S sStr; D dStr; transcode(czechChars, sStr); transcode(sStr, dStr); transcode(dStr, str); assert(czechChars == str); } } } //============================================================================= /** The base class for exceptions thrown by this module */ class EncodingException : Exception { this(string msg) { super(msg); } } class UnrecognizedEncodingException : EncodingException { private this(string msg) { super(msg); } } /** Abstract base class of all encoding schemes */ abstract class EncodingScheme { import std.uni : toLower; /** * Registers a subclass of EncodingScheme. * * This function allows user-defined subclasses of EncodingScheme to * be declared in other modules. * * Example: * ---------------------------------------------- * class Amiga1251 : EncodingScheme * { * shared static this() * { * EncodingScheme.register("path.to.Amiga1251"); * } * } * ---------------------------------------------- */ static void register(string className) { auto scheme = cast(EncodingScheme)ClassInfo.find(className).create(); if (scheme is null) throw new EncodingException("Unable to create class "~className); foreach(encodingName;scheme.names()) { supported[toLower(encodingName)] = className; } } /** * Obtains a subclass of EncodingScheme which is capable of encoding * and decoding the named encoding scheme. * * This function is only aware of EncodingSchemes which have been * registered with the register() function. * * Example: * --------------------------------------------------- * auto scheme = EncodingScheme.create("Amiga-1251"); * --------------------------------------------------- */ static EncodingScheme create(string encodingName) { auto p = toLower(encodingName) in supported; if (p is null) throw new EncodingException("Unrecognized Encoding: "~encodingName); string className = *p; auto scheme = cast(EncodingScheme)ClassInfo.find(className).create(); if (scheme is null) throw new EncodingException("Unable to create class "~className); return scheme; } const { /** * Returns the standard name of the encoding scheme */ abstract override string toString(); /** * Returns an array of all known names for this encoding scheme */ abstract string[] names(); /** * Returns true if the character c can be represented * in this encoding scheme. */ abstract bool canEncode(dchar c); /** * Returns the number of ubytes required to encode this code point. * * The input to this function MUST be a valid code point. * * Params: * c = the code point to be encoded * * Returns: * the number of ubytes required. */ abstract size_t encodedLength(dchar c); /** * Encodes a single code point into a user-supplied, fixed-size buffer. * * This function encodes a single code point into one or more ubytes. * The supplied buffer must be code unit aligned. * (For example, UTF-16LE or UTF-16BE must be wchar-aligned, * UTF-32LE or UTF-32BE must be dchar-aligned, etc.) * * The input to this function MUST be a valid code point. * * Params: * c = the code point to be encoded * buffer = the destination array * * Returns: * the number of ubytes written. */ abstract size_t encode(dchar c, ubyte[] buffer); /** * Decodes a single code point. * * This function removes one or more ubytes from the start of an array, * and returns the decoded code point which those ubytes represent. * * The input to this function MUST be validly encoded. * * Params: * s = the array whose first code point is to be decoded */ abstract dchar decode(ref const(ubyte)[] s); /** * Decodes a single code point. The input does not have to be valid. * * This function removes one or more ubytes from the start of an array, * and returns the decoded code point which those ubytes represent. * * This function will accept an invalidly encoded array as input. * If an invalid sequence is found at the start of the string, this * function will remove it, and return the value INVALID_SEQUENCE. * * Params: * s = the array whose first code point is to be decoded */ abstract dchar safeDecode(ref const(ubyte)[] s); /** * Returns the sequence of ubytes to be used to represent * any character which cannot be represented in the encoding scheme. * * Normally this will be a representation of some substitution * character, such as U+FFFD or '?'. */ abstract @property immutable(ubyte)[] replacementSequence(); } /** * Returns true if the array is encoded correctly * * Params: * s = the array to be tested */ bool isValid(const(ubyte)[] s) { while (s.length != 0) { dchar d = safeDecode(s); if (d == INVALID_SEQUENCE) return false; } return true; } /** * Returns the length of the longest possible substring, starting from * the first element, which is validly encoded. * * Params: * s = the array to be tested */ size_t validLength(const(ubyte)[] s) { const(ubyte)[] r = s; const(ubyte)[] t = s; while (s.length != 0) { if (safeDecode(s) == INVALID_SEQUENCE) break; t = s; } return r.length - t.length; } /** * Sanitizes an array by replacing malformed ubyte sequences with valid * ubyte sequences. The result is guaranteed to be valid for this * encoding scheme. * * If the input array is already valid, this function returns the * original, otherwise it constructs a new array by replacing all illegal * sequences with the encoding scheme's replacement sequence. * * Params: * s = the string to be sanitized */ immutable(ubyte)[] sanitize(immutable(ubyte)[] s) { auto n = validLength(s); if (n == s.length) return s; auto repSeq = replacementSequence; // Count how long the string needs to be. // Overestimating is not a problem auto len = s.length; const(ubyte)[] t = s[n..$]; while (t.length != 0) { dchar c = safeDecode(t); assert(c == INVALID_SEQUENCE); len += repSeq.length; t = t[validLength(t)..$]; } // Now do the write ubyte[] array = new ubyte[len]; array[0..n] = s[0..n]; auto offset = n; t = s[n..$]; while (t.length != 0) { dchar c = safeDecode(t); assert(c == INVALID_SEQUENCE); array[offset..offset+repSeq.length] = repSeq[]; offset += repSeq.length; n = validLength(t); array[offset..offset+n] = t[0..n]; offset += n; t = t[n..$]; } return cast(immutable(ubyte)[])array[0..offset]; } /** * Returns the length of the first encoded sequence. * * The input to this function MUST be validly encoded. * This is enforced by the function's in-contract. * * Params: * s = the array to be sliced */ size_t firstSequence(const(ubyte)[] s) in { assert(s.length != 0); const(ubyte)[] u = s; assert(safeDecode(u) != INVALID_SEQUENCE); } body { const(ubyte)[] t = s; decode(s); return t.length - s.length; } /** * Returns the total number of code points encoded in a ubyte array. * * The input to this function MUST be validly encoded. * This is enforced by the function's in-contract. * * Params: * s = the string to be counted */ size_t count(const(ubyte)[] s) in { assert(isValid(s)); } body { size_t n = 0; while (s.length != 0) { decode(s); ++n; } return n; } /** * Returns the array index at which the (n+1)th code point begins. * * The input to this function MUST be validly encoded. * This is enforced by the function's in-contract. * * Params: * s = the string to be counted * n = the current code point index */ ptrdiff_t index(const(ubyte)[] s, size_t n) in { assert(isValid(s)); assert(n >= 0); } body { const(ubyte)[] t = s; for (size_t i=0; i= 0x20 && c < 0x80) { r ~= c; } else { r ~= "\\x"; r ~= toHexDigit(c >> 4); r ~= toHexDigit(c); } } r ~= "\""; return r; } string makeReadable(wstring s) { string r = "\""; foreach(wchar c;s) { if (c >= 0x20 && c < 0x80) { r ~= cast(char) c; } else { r ~= "\\u"; r ~= toHexDigit(c >> 12); r ~= toHexDigit(c >> 8); r ~= toHexDigit(c >> 4); r ~= toHexDigit(c); } } r ~= "\"w"; return r; } string makeReadable(dstring s) { string r = "\""; foreach(dchar c; s) { if (c >= 0x20 && c < 0x80) { r ~= cast(char) c; } else if (c < 0x10000) { r ~= "\\u"; r ~= toHexDigit(c >> 12); r ~= toHexDigit(c >> 8); r ~= toHexDigit(c >> 4); r ~= toHexDigit(c); } else { r ~= "\\U00"; r ~= toHexDigit(c >> 20); r ~= toHexDigit(c >> 16); r ~= toHexDigit(c >> 12); r ~= toHexDigit(c >> 8); r ~= toHexDigit(c >> 4); r ~= toHexDigit(c); } } r ~= "\"d"; return r; } char toHexDigit(int n) { return "0123456789ABCDEF"[n & 0xF]; } } ldc-1.1.0-beta3-src/runtime/phobos/std/random.d0000664000175000017500000026704012776215007017344 0ustar kaikai// Written in the D programming language. /** Facilities for random number generation. The new-style generator objects hold their own state so they are immune of threading issues. The generators feature a number of well-known and well-documented methods of generating random numbers. An overall fast and reliable means to generate random numbers is the $(D_PARAM Mt19937) generator, which derives its name from "$(LUCKY Mersenne Twister) with a period of 2 to the power of 19937". In memory-constrained situations, $(LUCKY linear congruential) generators such as $(D MinstdRand0) and $(D MinstdRand) might be useful. The standard library provides an alias $(D_PARAM Random) for whichever generator it considers the most fit for the target environment. Example: ---- // Generate a uniformly-distributed integer in the range [0, 14] auto i = uniform(0, 15); // Generate a uniformly-distributed real in the range [0, 100) // using a specific random generator Random gen; auto r = uniform(0.0L, 100.0L, gen); ---- In addition to random number generators, this module features distributions, which skew a generator's output statistical distribution in various ways. So far the uniform distribution for integers and real numbers have been implemented. Upgrading: $(WEB digitalmars.com/d/1.0/phobos/std_random.html#rand, Phobos D1 $(D rand())) can be replaced with $(D uniform!uint()). Source: $(PHOBOSSRC std/_random.d) Macros: WIKI = Phobos/StdRandom Copyright: Copyright Andrei Alexandrescu 2008 - 2009, Joseph Rushton Wakeling 2012. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.org, Andrei Alexandrescu) Masahiro Nakagawa (Xorshift random generator) $(WEB braingam.es, Joseph Rushton Wakeling) (Algorithm D for random sampling) Credits: The entire random number library architecture is derived from the excellent $(WEB open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf, C++0X) random number facility proposed by Jens Maurer and contributed to by researchers at the Fermi laboratory (excluding Xorshift). */ /* Copyright Andrei Alexandrescu 2008 - 2009. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.random; import std.range.primitives; import std.traits; version(unittest) { static import std.meta; package alias PseudoRngTypes = std.meta.AliasSeq!(MinstdRand0, MinstdRand, Mt19937, Xorshift32, Xorshift64, Xorshift96, Xorshift128, Xorshift160, Xorshift192); } // Segments of the code in this file Copyright (c) 1997 by Rick Booth // From "Inner Loops" by Rick Booth, Addison-Wesley // Work derived from: /* A C-program for MT19937, with initialization improved 2002/1/26. Coded by Takuji Nishimura and Makoto Matsumoto. Before using, initialize the state by using init_genrand(seed) or init_by_array(init_key, key_length). Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Any feedback is very welcome. http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) */ /** * Test if Rng is a random-number generator. The overload * taking a ElementType also makes sure that the Rng generates * values of that type. * * A random-number generator has at least the following features: * $(UL * $(LI it's an InputRange) * $(LI it has a 'bool isUniformRandom' field readable in CTFE) * ) */ template isUniformRNG(Rng, ElementType) { enum bool isUniformRNG = isInputRange!Rng && is(typeof(Rng.front) == ElementType) && is(typeof( { static assert(Rng.isUniformRandom); //tag })); } /** * ditto */ template isUniformRNG(Rng) { enum bool isUniformRNG = isInputRange!Rng && is(typeof( { static assert(Rng.isUniformRandom); //tag })); } /** * Test if Rng is seedable. The overload * taking a SeedType also makes sure that the Rng can be seeded with SeedType. * * A seedable random-number generator has the following additional features: * $(UL * $(LI it has a 'seed(ElementType)' function) * ) */ template isSeedable(Rng, SeedType) { enum bool isSeedable = isUniformRNG!(Rng) && is(typeof( { Rng r = void; // can define a Rng object r.seed(SeedType.init); // can seed a Rng })); } ///ditto template isSeedable(Rng) { enum bool isSeedable = isUniformRNG!Rng && is(typeof( { Rng r = void; // can define a Rng object r.seed(typeof(r.front).init); // can seed a Rng })); } @safe pure nothrow unittest { struct NoRng { @property uint front() {return 0;} @property bool empty() {return false;} void popFront() {} } static assert(!isUniformRNG!(NoRng, uint)); static assert(!isUniformRNG!(NoRng)); static assert(!isSeedable!(NoRng, uint)); static assert(!isSeedable!(NoRng)); struct NoRng2 { @property uint front() {return 0;} @property bool empty() {return false;} void popFront() {} enum isUniformRandom = false; } static assert(!isUniformRNG!(NoRng2, uint)); static assert(!isUniformRNG!(NoRng2)); static assert(!isSeedable!(NoRng2, uint)); static assert(!isSeedable!(NoRng2)); struct NoRng3 { @property bool empty() {return false;} void popFront() {} enum isUniformRandom = true; } static assert(!isUniformRNG!(NoRng3, uint)); static assert(!isUniformRNG!(NoRng3)); static assert(!isSeedable!(NoRng3, uint)); static assert(!isSeedable!(NoRng3)); struct validRng { @property uint front() {return 0;} @property bool empty() {return false;} void popFront() {} enum isUniformRandom = true; } static assert(isUniformRNG!(validRng, uint)); static assert(isUniformRNG!(validRng)); static assert(!isSeedable!(validRng, uint)); static assert(!isSeedable!(validRng)); struct seedRng { @property uint front() {return 0;} @property bool empty() {return false;} void popFront() {} void seed(uint val){} enum isUniformRandom = true; } static assert(isUniformRNG!(seedRng, uint)); static assert(isUniformRNG!(seedRng)); static assert(isSeedable!(seedRng, uint)); static assert(isSeedable!(seedRng)); } /** Linear Congruential generator. */ struct LinearCongruentialEngine(UIntType, UIntType a, UIntType c, UIntType m) if(isUnsigned!UIntType) { ///Mark this as a Rng enum bool isUniformRandom = true; /// Does this generator have a fixed range? ($(D_PARAM true)). enum bool hasFixedRange = true; /// Lowest generated value ($(D 1) if $(D c == 0), $(D 0) otherwise). enum UIntType min = ( c == 0 ? 1 : 0 ); /// Highest generated value ($(D modulus - 1)). enum UIntType max = m - 1; /** The parameters of this distribution. The random number is $(D_PARAM x = (x * multipler + increment) % modulus). */ enum UIntType multiplier = a; ///ditto enum UIntType increment = c; ///ditto enum UIntType modulus = m; static assert(isIntegral!(UIntType)); static assert(m == 0 || a < m); static assert(m == 0 || c < m); static assert(m == 0 || (cast(ulong)a * (m-1) + c) % m == (c < a ? c - a + m : c - a)); // Check for maximum range private static ulong gcd(ulong a, ulong b) @safe pure nothrow { while (b) { auto t = b; b = a % b; a = t; } return a; } private static ulong primeFactorsOnly(ulong n) @safe pure nothrow { ulong result = 1; ulong iter = 2; for (; n >= iter * iter; iter += 2 - (iter == 2)) { if (n % iter) continue; result *= iter; do { n /= iter; } while (n % iter == 0); } return result * n; } @safe pure nothrow unittest { static assert(primeFactorsOnly(100) == 10); //writeln(primeFactorsOnly(11)); static assert(primeFactorsOnly(11) == 11); static assert(primeFactorsOnly(7 * 7 * 7 * 11 * 15 * 11) == 7 * 11 * 15); static assert(primeFactorsOnly(129 * 2) == 129 * 2); // enum x = primeFactorsOnly(7 * 7 * 7 * 11 * 15); // static assert(x == 7 * 11 * 15); } private static bool properLinearCongruentialParameters(ulong m, ulong a, ulong c) @safe pure nothrow { if (m == 0) { static if (is(UIntType == uint)) { // Assume m is uint.max + 1 m = (1uL << 32); } else { return false; } } // Bounds checking if (a == 0 || a >= m || c >= m) return false; // c and m are relatively prime if (c > 0 && gcd(c, m) != 1) return false; // a - 1 is divisible by all prime factors of m if ((a - 1) % primeFactorsOnly(m)) return false; // if a - 1 is multiple of 4, then m is a multiple of 4 too. if ((a - 1) % 4 == 0 && m % 4) return false; // Passed all tests return true; } // check here static assert(c == 0 || properLinearCongruentialParameters(m, a, c), "Incorrect instantiation of LinearCongruentialEngine"); /** Constructs a $(D_PARAM LinearCongruentialEngine) generator seeded with $(D x0). */ this(UIntType x0) @safe pure { seed(x0); } /** (Re)seeds the generator. */ void seed(UIntType x0 = 1) @safe pure { static if (c == 0) { import std.exception : enforce; enforce(x0, "Invalid (zero) seed for " ~ LinearCongruentialEngine.stringof); } _x = modulus ? (x0 % modulus) : x0; popFront(); } /** Advances the random sequence. */ void popFront() @safe pure nothrow { static if (m) { static if (is(UIntType == uint) && m == uint.max) { immutable ulong x = (cast(ulong) a * _x + c), v = x >> 32, w = x & uint.max; immutable y = cast(uint)(v + w); _x = (y < v || y == uint.max) ? (y + 1) : y; } else static if (is(UIntType == uint) && m == int.max) { immutable ulong x = (cast(ulong) a * _x + c), v = x >> 31, w = x & int.max; immutable uint y = cast(uint)(v + w); _x = (y >= int.max) ? (y - int.max) : y; } else { _x = cast(UIntType) ((cast(ulong) a * _x + c) % m); } } else { _x = a * _x + c; } } /** Returns the current number in the random sequence. */ @property UIntType front() const @safe pure nothrow { return _x; } /// @property typeof(this) save() @safe pure nothrow { return this; } /** Always $(D false) (random generators are infinite ranges). */ enum bool empty = false; /** Compares against $(D_PARAM rhs) for equality. */ bool opEquals(ref const LinearCongruentialEngine rhs) const @safe pure nothrow { return _x == rhs._x; } private UIntType _x = m ? (a + c) % m : (a + c); } /** Define $(D_PARAM LinearCongruentialEngine) generators with well-chosen parameters. $(D MinstdRand0) implements Park and Miller's "minimal standard" $(WEB wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator, generator) that uses 16807 for the multiplier. $(D MinstdRand) implements a variant that has slightly better spectral behavior by using the multiplier 48271. Both generators are rather simplistic. */ alias MinstdRand0 = LinearCongruentialEngine!(uint, 16807, 0, 2147483647); /// ditto alias MinstdRand = LinearCongruentialEngine!(uint, 48271, 0, 2147483647); /// unittest { // seed with a constant auto rnd0 = MinstdRand0(1); auto n = rnd0.front; // same for each run // Seed with an unpredictable value rnd0.seed(unpredictableSeed); n = rnd0.front; // different across runs } unittest { import std.range; static assert(isForwardRange!MinstdRand); static assert(isUniformRNG!MinstdRand); static assert(isUniformRNG!MinstdRand0); static assert(isUniformRNG!(MinstdRand, uint)); static assert(isUniformRNG!(MinstdRand0, uint)); static assert(isSeedable!MinstdRand); static assert(isSeedable!MinstdRand0); static assert(isSeedable!(MinstdRand, uint)); static assert(isSeedable!(MinstdRand0, uint)); // The correct numbers are taken from The Database of Integer Sequences // http://www.research.att.com/~njas/sequences/eisBTfry00128.txt auto checking0 = [ 16807UL,282475249,1622650073,984943658,1144108930,470211272, 101027544,1457850878,1458777923,2007237709,823564440,1115438165, 1784484492,74243042,114807987,1137522503,1441282327,16531729, 823378840,143542612 ]; //auto rnd0 = MinstdRand0(1); MinstdRand0 rnd0; foreach (e; checking0) { assert(rnd0.front == e); rnd0.popFront(); } // Test the 10000th invocation // Correct value taken from: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf rnd0.seed(); popFrontN(rnd0, 9999); assert(rnd0.front == 1043618065); // Test MinstdRand auto checking = [48271UL,182605794,1291394886,1914720637,2078669041, 407355683]; //auto rnd = MinstdRand(1); MinstdRand rnd; foreach (e; checking) { assert(rnd.front == e); rnd.popFront(); } // Test the 10000th invocation // Correct value taken from: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf rnd.seed(); popFrontN(rnd, 9999); assert(rnd.front == 399268537); // Check .save works foreach (Type; std.meta.AliasSeq!(MinstdRand0, MinstdRand)) { auto rnd1 = Type(unpredictableSeed); auto rnd2 = rnd1.save; assert(rnd1 == rnd2); // Enable next test when RNGs are reference types version(none) { assert(rnd1 !is rnd2); } assert(rnd1.take(100).array() == rnd2.take(100).array()); } } /** The $(LUCKY Mersenne Twister) generator. */ struct MersenneTwisterEngine(UIntType, size_t w, size_t n, size_t m, size_t r, UIntType a, size_t u, size_t s, UIntType b, size_t t, UIntType c, size_t l) if(isUnsigned!UIntType) { static assert(0 < w && w <= UIntType.sizeof * 8); static assert(1 <= m && m <= n); static assert(0 <= r && 0 <= u && 0 <= s && 0 <= t && 0 <= l); static assert(r <= w && u <= w && s <= w && t <= w && l <= w); static assert(0 <= a && 0 <= b && 0 <= c); ///Mark this as a Rng enum bool isUniformRandom = true; /** Parameters for the generator. */ enum size_t wordSize = w; enum size_t stateSize = n; /// ditto enum size_t shiftSize = m; /// ditto enum size_t maskBits = r; /// ditto enum UIntType xorMask = a; /// ditto enum UIntType temperingU = u; /// ditto enum size_t temperingS = s; /// ditto enum UIntType temperingB = b; /// ditto enum size_t temperingT = t; /// ditto enum UIntType temperingC = c; /// ditto enum size_t temperingL = l; /// ditto /// Smallest generated value (0). enum UIntType min = 0; /// Largest generated value. enum UIntType max = UIntType.max >> (UIntType.sizeof * 8u - w); static assert(a <= max && b <= max && c <= max); /// The default seed value. enum UIntType defaultSeed = 5489u; /** Constructs a MersenneTwisterEngine object. */ this(UIntType value) @safe pure nothrow { seed(value); } /** Seeds a MersenneTwisterEngine object. Note: This seed function gives 2^32 starting points. To allow the RNG to be started in any one of its internal states use the seed overload taking an InputRange. */ void seed()(UIntType value = defaultSeed) @safe pure nothrow { static if (w == UIntType.sizeof * 8) { mt[0] = value; } else { static assert(max + 1 > 0); mt[0] = value % (max + 1); } for (mti = 1; mti < n; ++mti) { mt[mti] = cast(UIntType) (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> (w - 2))) + mti); /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mt[]. */ /* 2002/01/09 modified by Makoto Matsumoto */ //mt[mti] &= ResultType.max; /* for >32 bit machines */ } popFront(); } /** Seeds a MersenneTwisterEngine object using an InputRange. Throws: $(D Exception) if the InputRange didn't provide enough elements to seed the generator. The number of elements required is the 'n' template parameter of the MersenneTwisterEngine struct. */ void seed(T)(T range) if(isInputRange!T && is(Unqual!(ElementType!T) == UIntType)) { size_t j; for (j = 0; j < n && !range.empty; ++j, range.popFront()) { mt[j] = range.front; } mti = n; if (range.empty && j < n) { import core.internal.string; UnsignedStringBuf buf = void; string s = "MersenneTwisterEngine.seed: Input range didn't provide enough elements: Need "; s ~= unsignedToTempString(n, buf, 10) ~ " elements."; throw new Exception(s); } popFront(); } /// unittest { import std.algorithm.iteration : map; import std.range : repeat; Mt19937 gen; gen.seed(map!((a) => unpredictableSeed)(repeat(0))); } /** Advances the generator. */ void popFront() @safe pure nothrow { if (mti == size_t.max) seed(); enum UIntType upperMask = ~((cast(UIntType) 1u << (UIntType.sizeof * 8 - (w - r))) - 1), lowerMask = (cast(UIntType) 1u << r) - 1; static immutable UIntType[2] mag01 = [0x0UL, a]; ulong y = void; if (mti >= n) { /* generate N words at one time */ int kk = 0; const limit1 = n - m; for (; kk < limit1; ++kk) { y = (mt[kk] & upperMask)|(mt[kk + 1] & lowerMask); mt[kk] = cast(UIntType) (mt[kk + m] ^ (y >> 1) ^ mag01[cast(UIntType) y & 0x1U]); } const limit2 = n - 1; for (; kk < limit2; ++kk) { y = (mt[kk] & upperMask)|(mt[kk + 1] & lowerMask); mt[kk] = cast(UIntType) (mt[kk + (m -n)] ^ (y >> 1) ^ mag01[cast(UIntType) y & 0x1U]); } y = (mt[n -1] & upperMask)|(mt[0] & lowerMask); mt[n - 1] = cast(UIntType) (mt[m - 1] ^ (y >> 1) ^ mag01[cast(UIntType) y & 0x1U]); mti = 0; } y = mt[mti++]; /* Tempering */ y ^= (y >> temperingU); y ^= (y << temperingS) & temperingB; y ^= (y << temperingT) & temperingC; y ^= (y >> temperingL); _y = cast(UIntType) y; } /** Returns the current random value. */ @property UIntType front() @safe pure nothrow { if (mti == size_t.max) seed(); return _y; } /// @property typeof(this) save() @safe pure nothrow { return this; } /** Always $(D false). */ enum bool empty = false; private UIntType[n] mt; private size_t mti = size_t.max; /* means mt is not initialized */ UIntType _y = UIntType.max; } /** A $(D MersenneTwisterEngine) instantiated with the parameters of the original engine $(WEB math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html, MT19937), generating uniformly-distributed 32-bit numbers with a period of 2 to the power of 19937. Recommended for random number generation unless memory is severely restricted, in which case a $(D LinearCongruentialEngine) would be the generator of choice. */ alias Mt19937 = MersenneTwisterEngine!(uint, 32, 624, 397, 31, 0x9908b0df, 11, 7, 0x9d2c5680, 15, 0xefc60000, 18); /// unittest { // seed with a constant Mt19937 gen; auto n = gen.front; // same for each run // Seed with an unpredictable value gen.seed(unpredictableSeed); n = gen.front; // different across runs } nothrow unittest { import std.algorithm; import std.range; static assert(isUniformRNG!Mt19937); static assert(isUniformRNG!(Mt19937, uint)); static assert(isSeedable!Mt19937); static assert(isSeedable!(Mt19937, uint)); static assert(isSeedable!(Mt19937, typeof(map!((a) => unpredictableSeed)(repeat(0))))); Mt19937 gen; popFrontN(gen, 9999); assert(gen.front == 4123659995); } unittest { import std.exception; import std.range; import std.algorithm; Mt19937 gen; assertThrown(gen.seed(map!((a) => unpredictableSeed)(repeat(0, 623)))); gen.seed(map!((a) => unpredictableSeed)(repeat(0, 624))); //infinite Range gen.seed(map!((a) => unpredictableSeed)(repeat(0))); } @safe pure nothrow unittest { uint a, b; { Mt19937 gen; a = gen.front; } { Mt19937 gen; gen.popFront(); //popFrontN(gen, 1); // skip 1 element b = gen.front; } assert(a != b); } unittest { import std.range; // Check .save works foreach(Type; std.meta.AliasSeq!(Mt19937)) { auto gen1 = Type(unpredictableSeed); auto gen2 = gen1.save; assert(gen1 == gen2); // Danger, Will Robinson -- no opEquals for MT // Enable next test when RNGs are reference types version(none) { assert(gen1 !is gen2); } assert(gen1.take(100).array() == gen2.take(100).array()); } } @safe pure nothrow unittest //11690 { alias MT(UIntType, uint w) = MersenneTwisterEngine!(UIntType, w, 624, 397, 31, 0x9908b0df, 11, 7, 0x9d2c5680, 15, 0xefc60000, 18); foreach (R; std.meta.AliasSeq!(MT!(uint, 32), MT!(ulong, 32), MT!(ulong, 48), MT!(ulong, 64))) auto a = R(); } /** * Xorshift generator using 32bit algorithm. * * Implemented according to $(WEB www.jstatsoft.org/v08/i14/paper, Xorshift RNGs). * * $(BOOKTABLE $(TEXTWITHCOMMAS Supporting bits are below, $(D bits) means second parameter of XorshiftEngine.), * $(TR $(TH bits) $(TH period)) * $(TR $(TD 32) $(TD 2^32 - 1)) * $(TR $(TD 64) $(TD 2^64 - 1)) * $(TR $(TD 96) $(TD 2^96 - 1)) * $(TR $(TD 128) $(TD 2^128 - 1)) * $(TR $(TD 160) $(TD 2^160 - 1)) * $(TR $(TD 192) $(TD 2^192 - 2^32)) * ) */ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType c) if(isUnsigned!UIntType) { static assert(bits == 32 || bits == 64 || bits == 96 || bits == 128 || bits == 160 || bits == 192, "Xorshift supports only 32, 64, 96, 128, 160 and 192 bit versions. " ~ to!string(bits) ~ " is not supported."); public: ///Mark this as a Rng enum bool isUniformRandom = true; /// Always $(D false) (random generators are infinite ranges). enum empty = false; /// Smallest generated value. enum UIntType min = 0; /// Largest generated value. enum UIntType max = UIntType.max; private: enum size = bits / 32; static if (bits == 32) UIntType[size] seeds_ = [2463534242]; else static if (bits == 64) UIntType[size] seeds_ = [123456789, 362436069]; else static if (bits == 96) UIntType[size] seeds_ = [123456789, 362436069, 521288629]; else static if (bits == 128) UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123]; else static if (bits == 160) UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123, 5783321]; else static if (bits == 192) { UIntType[size] seeds_ = [123456789, 362436069, 521288629, 88675123, 5783321, 6615241]; UIntType value_; } else { static assert(false, "Phobos Error: Xorshift has no instantiation rule for " ~ to!string(bits) ~ " bits."); } public: /** * Constructs a $(D XorshiftEngine) generator seeded with $(D_PARAM x0). */ @safe nothrow this(UIntType x0) pure { seed(x0); } /** * (Re)seeds the generator. */ @safe nothrow void seed(UIntType x0) pure { // Initialization routine from MersenneTwisterEngine. foreach (i, e; seeds_) seeds_[i] = x0 = cast(UIntType)(1812433253U * (x0 ^ (x0 >> 30)) + i + 1); // All seeds must not be 0. sanitizeSeeds(seeds_); popFront(); } /** * Returns the current number in the random sequence. */ @property @safe nothrow UIntType front() const pure { static if (bits == 192) return value_; else return seeds_[size - 1]; } /** * Advances the random sequence. */ @safe nothrow void popFront() pure { UIntType temp; static if (bits == 32) { temp = seeds_[0] ^ (seeds_[0] << a); temp = temp ^ (temp >> b); seeds_[0] = temp ^ (temp << c); } else static if (bits == 64) { temp = seeds_[0] ^ (seeds_[0] << a); seeds_[0] = seeds_[1]; seeds_[1] = seeds_[1] ^ (seeds_[1] >> c) ^ temp ^ (temp >> b); } else static if (bits == 96) { temp = seeds_[0] ^ (seeds_[0] << a); seeds_[0] = seeds_[1]; seeds_[1] = seeds_[2]; seeds_[2] = seeds_[2] ^ (seeds_[2] >> c) ^ temp ^ (temp >> b); } else static if (bits == 128) { temp = seeds_[0] ^ (seeds_[0] << a); seeds_[0] = seeds_[1]; seeds_[1] = seeds_[2]; seeds_[2] = seeds_[3]; seeds_[3] = seeds_[3] ^ (seeds_[3] >> c) ^ temp ^ (temp >> b); } else static if (bits == 160) { temp = seeds_[0] ^ (seeds_[0] << a); seeds_[0] = seeds_[1]; seeds_[1] = seeds_[2]; seeds_[2] = seeds_[3]; seeds_[3] = seeds_[4]; seeds_[4] = seeds_[4] ^ (seeds_[4] >> c) ^ temp ^ (temp >> b); } else static if (bits == 192) { temp = seeds_[0] ^ (seeds_[0] >> a); seeds_[0] = seeds_[1]; seeds_[1] = seeds_[2]; seeds_[2] = seeds_[3]; seeds_[3] = seeds_[4]; seeds_[4] = seeds_[4] ^ (seeds_[4] << c) ^ temp ^ (temp << b); value_ = seeds_[4] + (seeds_[5] += 362437); } else { static assert(false, "Phobos Error: Xorshift has no popFront() update for " ~ to!string(bits) ~ " bits."); } } /** * Captures a range state. */ @property @safe nothrow typeof(this) save() pure { return this; } /** * Compares against $(D_PARAM rhs) for equality. */ @safe nothrow bool opEquals(ref const XorshiftEngine rhs) const pure { return seeds_ == rhs.seeds_; } private: @safe static nothrow void sanitizeSeeds(ref UIntType[size] seeds) pure { for (uint i; i < seeds.length; i++) { if (seeds[i] == 0) seeds[i] = i + 1; } } @safe pure nothrow unittest { static if (size == 4) // Other bits too { UIntType[size] seeds = [1, 0, 0, 4]; sanitizeSeeds(seeds); assert(seeds == [1, 2, 3, 4]); } } } /** * Define $(D XorshiftEngine) generators with well-chosen parameters. See each bits examples of "Xorshift RNGs". * $(D Xorshift) is a Xorshift128's alias because 128bits implementation is mostly used. */ alias Xorshift32 = XorshiftEngine!(uint, 32, 13, 17, 15) ; alias Xorshift64 = XorshiftEngine!(uint, 64, 10, 13, 10); /// ditto alias Xorshift96 = XorshiftEngine!(uint, 96, 10, 5, 26); /// ditto alias Xorshift128 = XorshiftEngine!(uint, 128, 11, 8, 19); /// ditto alias Xorshift160 = XorshiftEngine!(uint, 160, 2, 1, 4); /// ditto alias Xorshift192 = XorshiftEngine!(uint, 192, 2, 1, 4); /// ditto alias Xorshift = Xorshift128; /// ditto /// unittest { // Seed with a constant auto rnd = Xorshift(1); auto num = rnd.front; // same for each run // Seed with an unpredictable value rnd.seed(unpredictableSeed); num = rnd.front; // different across rnd } unittest { import std.range; static assert(isForwardRange!Xorshift); static assert(isUniformRNG!Xorshift); static assert(isUniformRNG!(Xorshift, uint)); static assert(isSeedable!Xorshift); static assert(isSeedable!(Xorshift, uint)); // Result from reference implementation. auto checking = [ [2463534242UL, 901999875, 3371835698, 2675058524, 1053936272, 3811264849, 472493137, 3856898176, 2131710969, 2312157505], [362436069UL, 2113136921, 19051112, 3010520417, 951284840, 1213972223, 3173832558, 2611145638, 2515869689, 2245824891], [521288629UL, 1950277231, 185954712, 1582725458, 3580567609, 2303633688, 2394948066, 4108622809, 1116800180, 3357585673], [88675123UL, 3701687786, 458299110, 2500872618, 3633119408, 516391518, 2377269574, 2599949379, 717229868, 137866584], [5783321UL, 393427209, 1947109840, 565829276, 1006220149, 971147905, 1436324242, 2800460115, 1484058076, 3823330032], [0UL, 246875399, 3690007200, 1264581005, 3906711041, 1866187943, 2481925219, 2464530826, 1604040631, 3653403911] ]; alias XorshiftTypes = std.meta.AliasSeq!(Xorshift32, Xorshift64, Xorshift96, Xorshift128, Xorshift160, Xorshift192); foreach (I, Type; XorshiftTypes) { Type rnd; foreach (e; checking[I]) { assert(rnd.front == e); rnd.popFront(); } } // Check .save works foreach (Type; XorshiftTypes) { auto rnd1 = Type(unpredictableSeed); auto rnd2 = rnd1.save; assert(rnd1 == rnd2); // Enable next test when RNGs are reference types version(none) { assert(rnd1 !is rnd2); } assert(rnd1.take(100).array() == rnd2.take(100).array()); } } /* A complete list of all pseudo-random number generators implemented in * std.random. This can be used to confirm that a given function or * object is compatible with all the pseudo-random number generators * available. It is enabled only in unittest mode. */ unittest { foreach(Rng; PseudoRngTypes) { static assert(isUniformRNG!Rng); auto rng = Rng(unpredictableSeed); } } /** A "good" seed for initializing random number engines. Initializing with $(D_PARAM unpredictableSeed) makes engines generate different random number sequences every run. Returns: A single unsigned integer seed value, different on each successive call */ @property uint unpredictableSeed() @trusted { import core.thread : Thread, getpid, MonoTime; static bool seeded; static MinstdRand0 rand; if (!seeded) { uint threadID = cast(uint) cast(void*) Thread.getThis(); rand.seed((getpid() + threadID) ^ cast(uint) MonoTime.currTime.ticks); seeded = true; } rand.popFront(); return cast(uint) (MonoTime.currTime.ticks ^ rand.front); } /// @safe unittest { auto rnd = Random(unpredictableSeed); auto n = rnd.front; static assert(is(typeof(n) == uint)); } /** The "default", "favorite", "suggested" random number generator type on the current platform. It is an alias for one of the previously-defined generators. You may want to use it if (1) you need to generate some nice random numbers, and (2) you don't care for the minutiae of the method being used. */ alias Random = Mt19937; unittest { static assert(isUniformRNG!Random); static assert(isUniformRNG!(Random, uint)); static assert(isSeedable!Random); static assert(isSeedable!(Random, uint)); } /** Global random number generator used by various functions in this module whenever no generator is specified. It is allocated per-thread and initialized to an unpredictable value for each thread. Returns: A singleton instance of the default random number generator */ @property ref Random rndGen() @safe { import std.algorithm : map; import std.range : repeat; static Random result; static bool initialized; if (!initialized) { static if(isSeedable!(Random, typeof(map!((a) => unpredictableSeed)(repeat(0))))) result.seed(map!((a) => unpredictableSeed)(repeat(0))); else result = Random(unpredictableSeed); initialized = true; } return result; } /** Generates a number between $(D a) and $(D b). The $(D boundaries) parameter controls the shape of the interval (open vs. closed on either side). Valid values for $(D boundaries) are $(D "[]"), $(D "$(LPAREN)]"), $(D "[$(RPAREN)"), and $(D "()"). The default interval is closed to the left and open to the right. The version that does not take $(D urng) uses the default generator $(D rndGen). Params: a = lower bound of the _uniform distribution b = upper bound of the _uniform distribution urng = (optional) random number generator to use; if not specified, defaults to $(D rndGen) Returns: A single random variate drawn from the _uniform distribution between $(D a) and $(D b), whose type is the common type of these parameters */ auto uniform(string boundaries = "[)", T1, T2) (T1 a, T2 b) if (!is(CommonType!(T1, T2) == void)) { return uniform!(boundaries, T1, T2, Random)(a, b, rndGen); } /// unittest { auto gen = Random(unpredictableSeed); // Generate an integer in [0, 1023] auto a = uniform(0, 1024, gen); // Generate a float in [0, 1) auto b = uniform(0.0f, 1.0f, gen); } @safe unittest { MinstdRand0 gen; foreach (i; 0 .. 20) { auto x = uniform(0.0, 15.0, gen); assert(0 <= x && x < 15); } foreach (i; 0 .. 20) { auto x = uniform!"[]"('a', 'z', gen); assert('a' <= x && x <= 'z'); } foreach (i; 0 .. 20) { auto x = uniform('a', 'z', gen); assert('a' <= x && x < 'z'); } foreach(i; 0 .. 20) { immutable ubyte a = 0; immutable ubyte b = 15; auto x = uniform(a, b, gen); assert(a <= x && x < b); } } // Implementation of uniform for floating-point types /// ditto auto uniform(string boundaries = "[)", T1, T2, UniformRandomNumberGenerator) (T1 a, T2 b, ref UniformRandomNumberGenerator urng) if (isFloatingPoint!(CommonType!(T1, T2)) && isUniformRNG!UniformRandomNumberGenerator) { import std.exception : enforce; import std.conv : text; alias NumberType = Unqual!(CommonType!(T1, T2)); static if (boundaries[0] == '(') { import std.math : nextafter; NumberType _a = nextafter(cast(NumberType) a, NumberType.infinity); } else { NumberType _a = a; } static if (boundaries[1] == ')') { import std.math : nextafter; NumberType _b = nextafter(cast(NumberType) b, -NumberType.infinity); } else { NumberType _b = b; } enforce(_a <= _b, text("std.random.uniform(): invalid bounding interval ", boundaries[0], a, ", ", b, boundaries[1])); NumberType result = _a + (_b - _a) * cast(NumberType) (urng.front - urng.min) / (urng.max - urng.min); urng.popFront(); return result; } // Implementation of uniform for integral types /+ Description of algorithm and suggestion of correctness: The modulus operator maps an integer to a small, finite space. For instance, `x % 3` will map whatever x is into the range [0 .. 3). 0 maps to 0, 1 maps to 1, 2 maps to 2, 3 maps to 0, and so on infinitely. As long as the integer is uniformly chosen from the infinite space of all non-negative integers then `x % 3` will uniformly fall into that range. (Non-negative is important in this case because some definitions of modulus, namely the one used in computers generally, map negative numbers differently to (-3 .. 0]. `uniform` does not use negative number modulus, thus we can safely ignore that fact.) The issue with computers is that integers have a finite space they must fit in, and our uniformly chosen random number is picked in that finite space. So, that method is not sufficient. You can look at it as the integer space being divided into "buckets" and every bucket after the first bucket maps directly into that first bucket. `[0, 1, 2]`, `[3, 4, 5]`, ... When integers are finite, then the last bucket has the chance to be "incomplete": `[uint.max - 3, uint.max - 2, uint.max - 1]`, `[uint.max]` ... (the last bucket only has 1!). The issue here is that _every_ bucket maps _completely_ to the first bucket except for that last one. The last one doesn't have corresponding mappings to 1 or 2, in this case, which makes it unfair. So, the answer is to simply "reroll" if you're in that last bucket, since it's the only unfair one. Eventually you'll roll into a fair bucket. Simply, instead of the meaning of the last bucket being "maps to `[0]`", it changes to "maps to `[0, 1, 2]`", which is precisely what we want. To generalize, `upperDist` represents the size of our buckets (and, thus, the exclusive upper bound for our desired uniform number). `rnum` is a uniformly random number picked from the space of integers that a computer can hold (we'll say `UpperType` represents that type). We'll first try to do the mapping into the first bucket by doing `offset = rnum % upperDist`. We can figure out the position of the front of the bucket we're in by `bucketFront = rnum - offset`. If we start at `UpperType.max` and walk backwards `upperDist - 1` spaces, then the space we land on is the last acceptable position where a full bucket can fit: ``` bucketFront UpperType.max v v [..., 0, 1, 2, ..., upperDist - 1] ^~~ upperDist - 1 ~~^ ``` If the bucket starts any later, then it must have lost at least one number and at least that number won't be represented fairly. ``` bucketFront UpperType.max v v [..., upperDist - 1, 0, 1, 2, ..., upperDist - 2] ^~~~~~~~ upperDist - 1 ~~~~~~~^ ``` Hence, our condition to reroll is `bucketFront > (UpperType.max - (upperDist - 1))` +/ auto uniform(string boundaries = "[)", T1, T2, RandomGen) (T1 a, T2 b, ref RandomGen rng) if ((isIntegral!(CommonType!(T1, T2)) || isSomeChar!(CommonType!(T1, T2))) && isUniformRNG!RandomGen) { import std.exception : enforce; import std.conv : text, unsigned; alias ResultType = Unqual!(CommonType!(T1, T2)); static if (boundaries[0] == '(') { enforce(a < ResultType.max, text("std.random.uniform(): invalid left bound ", a)); ResultType lower = cast(ResultType) (a + 1); } else { ResultType lower = a; } static if (boundaries[1] == ']') { enforce(lower <= b, text("std.random.uniform(): invalid bounding interval ", boundaries[0], a, ", ", b, boundaries[1])); /* Cannot use this next optimization with dchar, as dchar * only partially uses its full bit range */ static if (!is(ResultType == dchar)) { if (b == ResultType.max && lower == ResultType.min) { // Special case - all bits are occupied return std.random.uniform!ResultType(rng); } } auto upperDist = unsigned(b - lower) + 1u; } else { enforce(lower < b, text("std.random.uniform(): invalid bounding interval ", boundaries[0], a, ", ", b, boundaries[1])); auto upperDist = unsigned(b - lower); } assert(upperDist != 0); alias UpperType = typeof(upperDist); static assert(UpperType.min == 0); UpperType offset, rnum, bucketFront; do { rnum = uniform!UpperType(rng); offset = rnum % upperDist; bucketFront = rnum - offset; } // while we're in an unfair bucket... while (bucketFront > (UpperType.max - (upperDist - 1))); return cast(ResultType)(lower + offset); } @safe unittest { import std.conv : to; auto gen = Mt19937(unpredictableSeed); static assert(isForwardRange!(typeof(gen))); auto a = uniform(0, 1024, gen); assert(0 <= a && a <= 1024); auto b = uniform(0.0f, 1.0f, gen); assert(0 <= b && b < 1, to!string(b)); auto c = uniform(0.0, 1.0); assert(0 <= c && c < 1); foreach (T; std.meta.AliasSeq!(char, wchar, dchar, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real)) { T lo = 0, hi = 100; // Try tests with each of the possible bounds { T init = uniform(lo, hi); size_t i = 50; while (--i && uniform(lo, hi) == init) {} assert(i > 0); } { T init = uniform!"[)"(lo, hi); size_t i = 50; while (--i && uniform(lo, hi) == init) {} assert(i > 0); } { T init = uniform!"(]"(lo, hi); size_t i = 50; while (--i && uniform(lo, hi) == init) {} assert(i > 0); } { T init = uniform!"()"(lo, hi); size_t i = 50; while (--i && uniform(lo, hi) == init) {} assert(i > 0); } { T init = uniform!"[]"(lo, hi); size_t i = 50; while (--i && uniform(lo, hi) == init) {} assert(i > 0); } /* Test case with closed boundaries covering whole range * of integral type */ static if (isIntegral!T || isSomeChar!T) { foreach (immutable _; 0 .. 100) { auto u = uniform!"[]"(T.min, T.max); static assert(is(typeof(u) == T)); assert(T.min <= u, "Lower bound violation for uniform!\"[]\" with " ~ T.stringof); assert(u <= T.max, "Upper bound violation for uniform!\"[]\" with " ~ T.stringof); } } } auto reproRng = Xorshift(239842); foreach (T; std.meta.AliasSeq!(char, wchar, dchar, byte, ubyte, short, ushort, int, uint, long, ulong)) { T lo = T.min + 10, hi = T.max - 10; T init = uniform(lo, hi, reproRng); size_t i = 50; while (--i && uniform(lo, hi, reproRng) == init) {} assert(i > 0); } { bool sawLB = false, sawUB = false; foreach (i; 0 .. 50) { auto x = uniform!"[]"('a', 'd', reproRng); if (x == 'a') sawLB = true; if (x == 'd') sawUB = true; assert('a' <= x && x <= 'd'); } assert(sawLB && sawUB); } { bool sawLB = false, sawUB = false; foreach (i; 0 .. 50) { auto x = uniform('a', 'd', reproRng); if (x == 'a') sawLB = true; if (x == 'c') sawUB = true; assert('a' <= x && x < 'd'); } assert(sawLB && sawUB); } { bool sawLB = false, sawUB = false; foreach (i; 0 .. 50) { immutable int lo = -2, hi = 2; auto x = uniform!"()"(lo, hi, reproRng); if (x == (lo+1)) sawLB = true; if (x == (hi-1)) sawUB = true; assert(lo < x && x < hi); } assert(sawLB && sawUB); } { bool sawLB = false, sawUB = false; foreach (i; 0 .. 50) { immutable ubyte lo = 0, hi = 5; auto x = uniform(lo, hi, reproRng); if (x == lo) sawLB = true; if (x == (hi-1)) sawUB = true; assert(lo <= x && x < hi); } assert(sawLB && sawUB); } { foreach (i; 0 .. 30) { assert(i == uniform(i, i+1, reproRng)); } } } /** Generates a uniformly-distributed number in the range $(D [T.min, T.max]) for any integral or character type $(D T). If no random number generator is passed, uses the default $(D rndGen). Params: urng = (optional) random number generator to use; if not specified, defaults to $(D rndGen) Returns: Random variate drawn from the _uniform distribution across all possible values of the integral or character type $(D T). */ auto uniform(T, UniformRandomNumberGenerator) (ref UniformRandomNumberGenerator urng) if (!is(T == enum) && (isIntegral!T || isSomeChar!T) && isUniformRNG!UniformRandomNumberGenerator) { /* dchar does not use its full bit range, so we must * revert to the uniform with specified bounds */ static if (is(T == dchar)) { return uniform!"[]"(T.min, T.max); } else { auto r = urng.front; urng.popFront(); static if (T.sizeof <= r.sizeof) { return cast(T) r; } else { static assert(T.sizeof == 8 && r.sizeof == 4); T r1 = urng.front | (cast(T)r << 32); urng.popFront(); return r1; } } } /// Ditto auto uniform(T)() if (!is(T == enum) && (isIntegral!T || isSomeChar!T)) { return uniform!T(rndGen); } @safe unittest { foreach(T; std.meta.AliasSeq!(char, wchar, dchar, byte, ubyte, short, ushort, int, uint, long, ulong)) { T init = uniform!T(); size_t i = 50; while (--i && uniform!T() == init) {} assert(i > 0); foreach (immutable _; 0 .. 100) { auto u = uniform!T(); static assert(is(typeof(u) == T)); assert(T.min <= u, "Lower bound violation for uniform!" ~ T.stringof); assert(u <= T.max, "Upper bound violation for uniform!" ~ T.stringof); } } } /** Returns a uniformly selected member of enum $(D E). If no random number generator is passed, uses the default $(D rndGen). Params: urng = (optional) random number generator to use; if not specified, defaults to $(D rndGen) Returns: Random variate drawn with equal probability from any of the possible values of the enum $(D E). */ auto uniform(E, UniformRandomNumberGenerator) (ref UniformRandomNumberGenerator urng) if (is(E == enum) && isUniformRNG!UniformRandomNumberGenerator) { static immutable E[EnumMembers!E.length] members = [EnumMembers!E]; return members[std.random.uniform(0, members.length, urng)]; } /// Ditto auto uniform(E)() if (is(E == enum)) { return uniform!E(rndGen); } /// @safe unittest { enum Fruit { apple, mango, pear } auto randFruit = uniform!Fruit(); } @safe unittest { enum Fruit { Apple = 12, Mango = 29, Pear = 72 } foreach (_; 0 .. 100) { foreach(f; [uniform!Fruit(), rndGen.uniform!Fruit()]) { assert(f == Fruit.Apple || f == Fruit.Mango || f == Fruit.Pear); } } } /** * Generates a uniformly-distributed floating point number of type * $(D T) in the range [0, 1$(RPAREN). If no random number generator is * specified, the default RNG $(D rndGen) will be used as the source * of randomness. * * $(D uniform01) offers a faster generation of random variates than * the equivalent $(D uniform!"[$(RPAREN)"(0.0, 1.0)) and so may be preferred * for some applications. * * Params: * rng = (optional) random number generator to use; * if not specified, defaults to $(D rndGen) * * Returns: * Floating-point random variate of type $(D T) drawn from the _uniform * distribution across the half-open interval [0, 1$(RPAREN). * */ T uniform01(T = double)() if (isFloatingPoint!T) { return uniform01!T(rndGen); } /// ditto T uniform01(T = double, UniformRNG)(ref UniformRNG rng) if (isFloatingPoint!T && isUniformRNG!UniformRNG) out (result) { assert(0 <= result); assert(result < 1); } body { alias R = typeof(rng.front); static if (isIntegral!R) { enum T factor = 1 / (T(1) + rng.max - rng.min); } else static if (isFloatingPoint!R) { enum T factor = 1 / (rng.max - rng.min); } else { static assert(false); } while (true) { immutable T u = (rng.front - rng.min) * factor; rng.popFront(); import core.stdc.limits : CHAR_BIT; // CHAR_BIT is always 8 static if (isIntegral!R && T.mant_dig >= (CHAR_BIT * R.sizeof)) { /* If RNG variates are integral and T has enough precision to hold * R without loss, we're guaranteed by the definition of factor * that precisely u < 1. */ return u; } else { /* Otherwise we have to check whether u is beyond the assumed range * because of the loss of precision, or for another reason, a * floating-point RNG can return a variate that is exactly equal to * its maximum. */ if (u < 1) { return u; } } } // Shouldn't ever get here. assert(false); } @safe unittest { import std.meta; foreach (UniformRNG; PseudoRngTypes) { foreach (T; std.meta.AliasSeq!(float, double, real)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 UniformRNG rng = UniformRNG(unpredictableSeed); auto a = uniform01(); assert(is(typeof(a) == double)); assert(0 <= a && a < 1); auto b = uniform01(rng); assert(is(typeof(a) == double)); assert(0 <= b && b < 1); auto c = uniform01!T(); assert(is(typeof(c) == T)); assert(0 <= c && c < 1); auto d = uniform01!T(rng); assert(is(typeof(d) == T)); assert(0 <= d && d < 1); T init = uniform01!T(rng); size_t i = 50; while (--i && uniform01!T(rng) == init) {} assert(i > 0); assert(i < 50); }(); } } /** Generates a uniform probability distribution of size $(D n), i.e., an array of size $(D n) of positive numbers of type $(D F) that sum to $(D 1). If $(D useThis) is provided, it is used as storage. */ F[] uniformDistribution(F = double)(size_t n, F[] useThis = null) if(isFloatingPoint!F) { import std.numeric : normalize; useThis.length = n; foreach (ref e; useThis) { e = uniform(0.0, 1); } normalize(useThis); return useThis; } @safe unittest { import std.math; import std.algorithm; static assert(is(CommonType!(double, int) == double)); auto a = uniformDistribution(5); assert(a.length == 5); assert(approxEqual(reduce!"a + b"(a), 1)); a = uniformDistribution(10, a); assert(a.length == 10); assert(approxEqual(reduce!"a + b"(a), 1)); } /** Shuffles elements of $(D r) using $(D gen) as a shuffler. $(D r) must be a random-access range with length. If no RNG is specified, $(D rndGen) will be used. Params: r = random-access range whose elements are to be shuffled gen = (optional) random number generator to use; if not specified, defaults to $(D rndGen) */ void randomShuffle(Range, RandomGen)(Range r, ref RandomGen gen) if(isRandomAccessRange!Range && isUniformRNG!RandomGen) { return partialShuffle!(Range, RandomGen)(r, r.length, gen); } /// ditto void randomShuffle(Range)(Range r) if(isRandomAccessRange!Range) { return randomShuffle(r, rndGen); } unittest { import std.algorithm; foreach(RandomGen; PseudoRngTypes) { // Also tests partialShuffle indirectly. auto a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; auto b = a.dup; auto gen = RandomGen(unpredictableSeed); randomShuffle(a, gen); sort(a); assert(a == b); randomShuffle(a); sort(a); assert(a == b); } } /** Partially shuffles the elements of $(D r) such that upon returning $(D r[0..n]) is a random subset of $(D r) and is randomly ordered. $(D r[n..r.length]) will contain the elements not in $(D r[0..n]). These will be in an undefined order, but will not be random in the sense that their order after $(D partialShuffle) returns will not be independent of their order before $(D partialShuffle) was called. $(D r) must be a random-access range with length. $(D n) must be less than or equal to $(D r.length). If no RNG is specified, $(D rndGen) will be used. Params: r = random-access range whose elements are to be shuffled n = number of elements of $(D r) to shuffle (counting from the beginning); must be less than $(D r.length) gen = (optional) random number generator to use; if not specified, defaults to $(D rndGen) */ void partialShuffle(Range, RandomGen)(Range r, in size_t n, ref RandomGen gen) if(isRandomAccessRange!Range && isUniformRNG!RandomGen) { import std.exception : enforce; import std.algorithm : swapAt; enforce(n <= r.length, "n must be <= r.length for partialShuffle."); foreach (i; 0 .. n) { swapAt(r, i, uniform(i, r.length, gen)); } } /// ditto void partialShuffle(Range)(Range r, in size_t n) if(isRandomAccessRange!Range) { return partialShuffle(r, n, rndGen); } unittest { import std.algorithm; foreach(RandomGen; PseudoRngTypes) { auto a = [0, 1, 1, 2, 3]; auto b = a.dup; // Pick a fixed seed so that the outcome of the statistical // test below is deterministic. auto gen = RandomGen(12345); // NUM times, pick LEN elements from the array at random. immutable int LEN = 2; immutable int NUM = 750; int[][] chk; foreach(step; 0..NUM) { partialShuffle(a, LEN, gen); chk ~= a[0..LEN].dup; } // Check that each possible a[0..LEN] was produced at least once. // For a perfectly random RandomGen, the probability that each // particular combination failed to appear would be at most // 0.95 ^^ NUM which is approximately 1,962e-17. // As long as hardware failure (e.g. bit flip) probability // is higher, we are fine with this unittest. sort(chk); assert(equal(uniq(chk), [ [0,1], [0,2], [0,3], [1,0], [1,1], [1,2], [1,3], [2,0], [2,1], [2,3], [3,0], [3,1], [3,2], ])); // Check that all the elements are still there. sort(a); assert(equal(a, b)); } } /** Rolls a dice with relative probabilities stored in $(D proportions). Returns the index in $(D proportions) that was chosen. Params: rnd = (optional) random number generator to use; if not specified, defaults to $(D rndGen) proportions = forward range or list of individual values whose elements correspond to the probabilities with which to choose the corresponding index value Returns: Random variate drawn from the index values [0, ... $(D proportions.length) - 1], with the probability of getting an individual index value $(D i) being proportional to $(D proportions[i]). */ size_t dice(Rng, Num)(ref Rng rnd, Num[] proportions...) if (isNumeric!Num && isForwardRange!Rng) { return diceImpl(rnd, proportions); } /// Ditto size_t dice(R, Range)(ref R rnd, Range proportions) if (isForwardRange!Range && isNumeric!(ElementType!Range) && !isArray!Range) { return diceImpl(rnd, proportions); } /// Ditto size_t dice(Range)(Range proportions) if (isForwardRange!Range && isNumeric!(ElementType!Range) && !isArray!Range) { return diceImpl(rndGen, proportions); } /// Ditto size_t dice(Num)(Num[] proportions...) if (isNumeric!Num) { return diceImpl(rndGen, proportions); } /// unittest { auto x = dice(0.5, 0.5); // x is 0 or 1 in equal proportions auto y = dice(50, 50); // y is 0 or 1 in equal proportions auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 20% of the time, // and 2 10% of the time } private size_t diceImpl(Rng, Range)(ref Rng rng, Range proportions) if (isForwardRange!Range && isNumeric!(ElementType!Range) && isForwardRange!Rng) in { import std.algorithm : all; assert(proportions.save.all!"a >= 0"); } body { import std.exception : enforce; import std.algorithm : reduce; double sum = reduce!"a + b"(0.0, proportions.save); enforce(sum > 0, "Proportions in a dice cannot sum to zero"); immutable point = uniform(0.0, sum, rng); assert(point < sum); auto mass = 0.0; size_t i = 0; foreach (e; proportions) { mass += e; if (point < mass) return i; i++; } // this point should not be reached assert(false); } unittest { auto rnd = Random(unpredictableSeed); auto i = dice(rnd, 0.0, 100.0); assert(i == 1); i = dice(rnd, 100.0, 0.0); assert(i == 0); i = dice(100U, 0U); assert(i == 0); } /** Covers a given range $(D r) in a random manner, i.e. goes through each element of $(D r) once and only once, just in a random order. $(D r) must be a random-access range with length. If no random number generator is passed to $(D randomCover), the thread-global RNG rndGen will be used internally. Params: r = random-access range to cover rng = (optional) random number generator to use; if not specified, defaults to $(D rndGen) Returns: Range whose elements consist of the elements of $(D r), in random order. Will be a forward range if both $(D r) and $(D rng) are forward ranges, an input range otherwise. Example: ---- int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]; foreach (e; randomCover(a)) { writeln(e); } ---- $(B WARNING:) If an alternative RNG is desired, it is essential for this to be a $(I new) RNG seeded in an unpredictable manner. Passing it a RNG used elsewhere in the program will result in unintended correlations, due to the current implementation of RNGs as value types. Example: ---- int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]; foreach (e; randomCover(a, Random(unpredictableSeed))) // correct! { writeln(e); } foreach (e; randomCover(a, rndGen)) // DANGEROUS!! rndGen gets copied by value { writeln(e); } foreach (e; randomCover(a, rndGen)) // ... so this second random cover { // will output the same sequence as writeln(e); // the previous one. } ---- */ struct RandomCover(Range, UniformRNG = void) if (isRandomAccessRange!Range && (isUniformRNG!UniformRNG || is(UniformRNG == void))) { private Range _input; private bool[] _chosen; private size_t _current; private size_t _alreadyChosen = 0; static if (is(UniformRNG == void)) { this(Range input) { _input = input; _chosen.length = _input.length; if (_chosen.length == 0) { _alreadyChosen = 1; } } } else { private UniformRNG _rng; this(Range input, ref UniformRNG rng) { _input = input; _rng = rng; _chosen.length = _input.length; if (_chosen.length == 0) { _alreadyChosen = 1; } } this(Range input, UniformRNG rng) { this(input, rng); } } static if (hasLength!Range) { @property size_t length() { if (_alreadyChosen == 0) { return _input.length; } else { return (1 + _input.length) - _alreadyChosen; } } } @property auto ref front() { if (_alreadyChosen == 0) { popFront(); } return _input[_current]; } void popFront() { if (_alreadyChosen >= _input.length) { // No more elements ++_alreadyChosen; // means we're done return; } size_t k = _input.length - _alreadyChosen; size_t i; foreach (e; _input) { if (_chosen[i]) { ++i; continue; } // Roll a dice with k faces static if (is(UniformRNG == void)) { auto chooseMe = uniform(0, k) == 0; } else { auto chooseMe = uniform(0, k, _rng) == 0; } assert(k > 1 || chooseMe); if (chooseMe) { _chosen[i] = true; _current = i; ++_alreadyChosen; return; } --k; ++i; } } static if (isForwardRange!UniformRNG) { @property typeof(this) save() { auto ret = this; ret._input = _input.save; ret._rng = _rng.save; return ret; } } @property bool empty() { return _alreadyChosen > _input.length; } } /// Ditto auto randomCover(Range, UniformRNG)(Range r, auto ref UniformRNG rng) if (isRandomAccessRange!Range && isUniformRNG!UniformRNG) { return RandomCover!(Range, UniformRNG)(r, rng); } /// Ditto auto randomCover(Range)(Range r) if (isRandomAccessRange!Range) { return RandomCover!(Range, void)(r); } unittest { import std.algorithm; import std.conv; int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]; foreach (UniformRNG; std.meta.AliasSeq!(void, PseudoRngTypes)) { static if (is(UniformRNG == void)) { auto rc = randomCover(a); static assert(isInputRange!(typeof(rc))); static assert(!isForwardRange!(typeof(rc))); } else { auto rng = UniformRNG(unpredictableSeed); auto rc = randomCover(a, rng); static assert(isForwardRange!(typeof(rc))); // check for constructor passed a value-type RNG auto rc2 = RandomCover!(int[], UniformRNG)(a, UniformRNG(unpredictableSeed)); static assert(isForwardRange!(typeof(rc2))); } int[] b = new int[9]; uint i; foreach (e; rc) { //writeln(e); b[i++] = e; } sort(b); assert(a == b, text(b)); } } unittest { // Bugzilla 12589 int[] r = []; auto rc = randomCover(r); assert(rc.length == 0); assert(rc.empty); } // RandomSample /** Selects a random subsample out of $(D r), containing exactly $(D n) elements. The order of elements is the same as in the original range. The total length of $(D r) must be known. If $(D total) is passed in, the total number of sample is considered to be $(D total). Otherwise, $(D RandomSample) uses $(D r.length). Params: r = range to sample from n = number of elements to include in the sample; must be less than or equal to the total number of elements in $(D r) and/or the parameter $(D total) (if provided) total = (semi-optional) number of elements of $(D r) from which to select the sample (counting from the beginning); must be less than or equal to the total number of elements in $(D r) itself. May be omitted if $(D r) has the $(D .length) property and the sample is to be drawn from all elements of $(D r). rng = (optional) random number generator to use; if not specified, defaults to $(D rndGen) Returns: Range whose elements consist of a randomly selected subset of the elements of $(D r), in the same order as these elements appear in $(D r) itself. Will be a forward range if both $(D r) and $(D rng) are forward ranges, an input range otherwise. $(D RandomSample) implements Jeffrey Scott Vitter's Algorithm D (see Vitter $(WEB dx.doi.org/10.1145/358105.893, 1984), $(WEB dx.doi.org/10.1145/23002.23003, 1987)), which selects a sample of size $(D n) in O(n) steps and requiring O(n) random variates, regardless of the size of the data being sampled. The exception to this is if traversing k elements on the input range is itself an O(k) operation (e.g. when sampling lines from an input file), in which case the sampling calculation will inevitably be of O(total). RandomSample will throw an exception if $(D total) is verifiably less than the total number of elements available in the input, or if $(D n > total). If no random number generator is passed to $(D randomSample), the thread-global RNG rndGen will be used internally. Example: ---- int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; // Print 5 random elements picked off from a foreach (e; randomSample(a, 5)) { writeln(e); } ---- $(B WARNING:) If an alternative RNG is desired, it is essential for this to be a $(I new) RNG seeded in an unpredictable manner. Passing it a RNG used elsewhere in the program will result in unintended correlations, due to the current implementation of RNGs as value types. Example: ---- int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; foreach (e; randomSample(a, 5, Random(unpredictableSeed))) // correct! { writeln(e); } foreach (e; randomSample(a, 5, rndGen)) // DANGEROUS!! rndGen gets { // copied by value writeln(e); } foreach (e; randomSample(a, 5, rndGen)) // ... so this second random { // sample will select the same writeln(e); // values as the previous one. } ---- */ struct RandomSample(Range, UniformRNG = void) if (isInputRange!Range && (isUniformRNG!UniformRNG || is(UniformRNG == void))) { private size_t _available, _toSelect; private enum ushort _alphaInverse = 13; // Vitter's recommended value. private double _Vprime; private Range _input; private size_t _index; private enum Skip { None, A, D } private Skip _skip = Skip.None; // If we're using the default thread-local random number generator then // we shouldn't store a copy of it here. UniformRNG == void is a sentinel // for this. If we're using a user-specified generator then we have no // choice but to store a copy. static if (is(UniformRNG == void)) { static if (hasLength!Range) { this(Range input, size_t howMany) { _input = input; initialize(howMany, input.length); } } this(Range input, size_t howMany, size_t total) { _input = input; initialize(howMany, total); } } else { UniformRNG _rng; static if (hasLength!Range) { this(Range input, size_t howMany, ref UniformRNG rng) { _rng = rng; _input = input; initialize(howMany, input.length); } this(Range input, size_t howMany, UniformRNG rng) { this(input, howMany, rng); } } this(Range input, size_t howMany, size_t total, ref UniformRNG rng) { _rng = rng; _input = input; initialize(howMany, total); } this(Range input, size_t howMany, size_t total, UniformRNG rng) { this(input, howMany, total, rng); } } private void initialize(size_t howMany, size_t total) { import std.exception : enforce; import std.conv : text; _available = total; _toSelect = howMany; enforce(_toSelect <= _available, text("RandomSample: cannot sample ", _toSelect, " items when only ", _available, " are available")); static if (hasLength!Range) { enforce(_available <= _input.length, text("RandomSample: specified ", _available, " items as available when input contains only ", _input.length)); } } private void initializeFront() { assert(_skip == Skip.None); // We can save ourselves a random variate by checking right // at the beginning if we should use Algorithm A. if ((_alphaInverse * _toSelect) > _available) { _skip = Skip.A; } else { _skip = Skip.D; _Vprime = newVprime(_toSelect); } prime(); } /** Range primitives. */ @property bool empty() const { return _toSelect == 0; } /// Ditto @property auto ref front() { assert(!empty); // The first sample point must be determined here to avoid // having it always correspond to the first element of the // input. The rest of the sample points are determined each // time we call popFront(). if (_skip == Skip.None) { initializeFront(); } return _input.front; } /// Ditto void popFront() { // First we need to check if the sample has // been initialized in the first place. if (_skip == Skip.None) { initializeFront(); } _input.popFront(); --_available; --_toSelect; ++_index; prime(); } /// Ditto static if (isForwardRange!Range && isForwardRange!UniformRNG) { @property typeof(this) save() { auto ret = this; ret._input = _input.save; ret._rng = _rng.save; return ret; } } /// Ditto @property size_t length() { return _toSelect; } /** Returns the index of the visited record. */ @property size_t index() { if (_skip == Skip.None) { initializeFront(); } return _index; } private size_t skip() { assert(_skip != Skip.None); // Step D1: if the number of points still to select is greater // than a certain proportion of the remaining data points, i.e. // if n >= alpha * N where alpha = 1/13, we carry out the // sampling with Algorithm A. if (_skip == Skip.A) { return skipA(); } else if ((_alphaInverse * _toSelect) > _available) { // We shouldn't get here unless the current selected // algorithm is D. assert(_skip == Skip.D); _skip = Skip.A; return skipA(); } else { assert(_skip == Skip.D); return skipD(); } } /* Vitter's Algorithm A, used when the ratio of needed sample values to remaining data values is sufficiently large. */ private size_t skipA() { size_t s; double v, quot, top; if (_toSelect==1) { static if (is(UniformRNG == void)) { s = uniform(0, _available); } else { s = uniform(0, _available, _rng); } } else { v = 0; top = _available - _toSelect; quot = top / _available; static if (is(UniformRNG == void)) { v = uniform!"()"(0.0, 1.0); } else { v = uniform!"()"(0.0, 1.0, _rng); } while (quot > v) { ++s; quot *= (top - s) / (_available - s); } } return s; } /* Randomly reset the value of _Vprime. */ private double newVprime(size_t remaining) { static if (is(UniformRNG == void)) { double r = uniform!"()"(0.0, 1.0); } else { double r = uniform!"()"(0.0, 1.0, _rng); } return r ^^ (1.0 / remaining); } /* Vitter's Algorithm D. For an extensive description of the algorithm and its rationale, see: * Vitter, J.S. (1984), "Faster methods for random sampling", Commun. ACM 27(7): 703--718 * Vitter, J.S. (1987) "An efficient algorithm for sequential random sampling", ACM Trans. Math. Softw. 13(1): 58-67. Variable names are chosen to match those in Vitter's paper. */ private size_t skipD() { import std.math : isNaN, trunc; // Confirm that the check in Step D1 is valid and we // haven't been sent here by mistake assert((_alphaInverse * _toSelect) <= _available); // Now it's safe to use the standard Algorithm D mechanism. if (_toSelect > 1) { size_t s; size_t qu1 = 1 + _available - _toSelect; double x, y1; assert(!_Vprime.isNaN()); while (true) { // Step D2: set values of x and u. while(1) { x = _available * (1-_Vprime); s = cast(size_t) trunc(x); if (s < qu1) break; _Vprime = newVprime(_toSelect); } static if (is(UniformRNG == void)) { double u = uniform!"()"(0.0, 1.0); } else { double u = uniform!"()"(0.0, 1.0, _rng); } y1 = (u * (cast(double) _available) / qu1) ^^ (1.0/(_toSelect - 1)); _Vprime = y1 * ((-x/_available)+1.0) * ( qu1/( (cast(double) qu1) - s ) ); // Step D3: if _Vprime <= 1.0 our work is done and we return S. // Otherwise ... if (_Vprime > 1.0) { size_t top = _available - 1, limit; double y2 = 1.0, bottom; if (_toSelect > (s+1)) { bottom = _available - _toSelect; limit = _available - s; } else { bottom = _available - (s+1); limit = qu1; } foreach (size_t t; limit .. _available) { y2 *= top/bottom; top--; bottom--; } // Step D4: decide whether or not to accept the current value of S. if (_available/(_available-x) < y1 * (y2 ^^ (1.0/(_toSelect-1)))) { // If it's not acceptable, we generate a new value of _Vprime // and go back to the start of the for (;;) loop. _Vprime = newVprime(_toSelect); } else { // If it's acceptable we generate a new value of _Vprime // based on the remaining number of sample points needed, // and return S. _Vprime = newVprime(_toSelect-1); return s; } } else { // Return if condition D3 satisfied. return s; } } } else { // If only one sample point remains to be taken ... return cast(size_t) trunc(_available * _Vprime); } } private void prime() { if (empty) { return; } assert(_available && _available >= _toSelect); immutable size_t s = skip(); assert(s + _toSelect <= _available); static if (hasLength!Range) { assert(s + _toSelect <= _input.length); } assert(!_input.empty); _input.popFrontExactly(s); _index += s; _available -= s; assert(_available > 0); } } /// Ditto auto randomSample(Range)(Range r, size_t n, size_t total) if (isInputRange!Range) { return RandomSample!(Range, void)(r, n, total); } /// Ditto auto randomSample(Range)(Range r, size_t n) if (isInputRange!Range && hasLength!Range) { return RandomSample!(Range, void)(r, n, r.length); } /// Ditto auto randomSample(Range, UniformRNG)(Range r, size_t n, size_t total, auto ref UniformRNG rng) if (isInputRange!Range && isUniformRNG!UniformRNG) { return RandomSample!(Range, UniformRNG)(r, n, total, rng); } /// Ditto auto randomSample(Range, UniformRNG)(Range r, size_t n, auto ref UniformRNG rng) if (isInputRange!Range && hasLength!Range && isUniformRNG!UniformRNG) { return RandomSample!(Range, UniformRNG)(r, n, r.length, rng); } unittest { import std.exception; import std.range; import std.conv : text; // For test purposes, an infinite input range struct TestInputRange { private auto r = recurrence!"a[n-1] + 1"(0); bool empty() @property const pure nothrow { return r.empty; } auto front() @property pure nothrow { return r.front; } void popFront() pure nothrow { r.popFront(); } } static assert(isInputRange!TestInputRange); static assert(!isForwardRange!TestInputRange); int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; foreach (UniformRNG; PseudoRngTypes) { auto rng = UniformRNG(1234); /* First test the most general case: randomSample of input range, with and * without a specified random number generator. */ static assert(isInputRange!(typeof(randomSample(TestInputRange(), 5, 10)))); static assert(isInputRange!(typeof(randomSample(TestInputRange(), 5, 10, rng)))); static assert(!isForwardRange!(typeof(randomSample(TestInputRange(), 5, 10)))); static assert(!isForwardRange!(typeof(randomSample(TestInputRange(), 5, 10, rng)))); // test case with range initialized by direct call to struct { auto sample = RandomSample!(TestInputRange, UniformRNG) (TestInputRange(), 5, 10, UniformRNG(unpredictableSeed)); static assert(isInputRange!(typeof(sample))); static assert(!isForwardRange!(typeof(sample))); } /* Now test the case of an input range with length. We ignore the cases * already covered by the previous tests. */ static assert(isInputRange!(typeof(randomSample(TestInputRange().takeExactly(10), 5)))); static assert(isInputRange!(typeof(randomSample(TestInputRange().takeExactly(10), 5, rng)))); static assert(!isForwardRange!(typeof(randomSample(TestInputRange().takeExactly(10), 5)))); static assert(!isForwardRange!(typeof(randomSample(TestInputRange().takeExactly(10), 5, rng)))); // test case with range initialized by direct call to struct { auto sample = RandomSample!(typeof(TestInputRange().takeExactly(10)), UniformRNG) (TestInputRange().takeExactly(10), 5, 10, UniformRNG(unpredictableSeed)); static assert(isInputRange!(typeof(sample))); static assert(!isForwardRange!(typeof(sample))); } // Now test the case of providing a forward range as input. static assert(!isForwardRange!(typeof(randomSample(a, 5)))); static if (isForwardRange!UniformRNG) { static assert(isForwardRange!(typeof(randomSample(a, 5, rng)))); // ... and test with range initialized directly { auto sample = RandomSample!(int[], UniformRNG) (a, 5, UniformRNG(unpredictableSeed)); static assert(isForwardRange!(typeof(sample))); } } else { static assert(isInputRange!(typeof(randomSample(a, 5, rng)))); static assert(!isForwardRange!(typeof(randomSample(a, 5, rng)))); // ... and test with range initialized directly { auto sample = RandomSample!(int[], UniformRNG) (a, 5, UniformRNG(unpredictableSeed)); static assert(isInputRange!(typeof(sample))); static assert(!isForwardRange!(typeof(sample))); } } /* Check that randomSample will throw an error if we claim more * items are available than there actually are, or if we try to * sample more items than are available. */ assert(collectExceptionMsg(randomSample(a, 5, 15)) == "RandomSample: specified 15 items as available when input contains only 10"); assert(collectExceptionMsg(randomSample(a, 15)) == "RandomSample: cannot sample 15 items when only 10 are available"); assert(collectExceptionMsg(randomSample(a, 9, 8)) == "RandomSample: cannot sample 9 items when only 8 are available"); assert(collectExceptionMsg(randomSample(TestInputRange(), 12, 11)) == "RandomSample: cannot sample 12 items when only 11 are available"); /* Check that sampling algorithm never accidentally overruns the end of * the input range. If input is an InputRange without .length, this * relies on the user specifying the total number of available items * correctly. */ { uint i = 0; foreach (e; randomSample(a, a.length)) { assert(e == i); ++i; } assert(i == a.length); i = 0; foreach (e; randomSample(TestInputRange(), 17, 17)) { assert(e == i); ++i; } assert(i == 17); } // Check length properties of random samples. assert(randomSample(a, 5).length == 5); assert(randomSample(a, 5, 10).length == 5); assert(randomSample(a, 5, rng).length == 5); assert(randomSample(a, 5, 10, rng).length == 5); assert(randomSample(TestInputRange(), 5, 10).length == 5); assert(randomSample(TestInputRange(), 5, 10, rng).length == 5); // ... and emptiness! assert(randomSample(a, 0).empty); assert(randomSample(a, 0, 5).empty); assert(randomSample(a, 0, rng).empty); assert(randomSample(a, 0, 5, rng).empty); assert(randomSample(TestInputRange(), 0, 10).empty); assert(randomSample(TestInputRange(), 0, 10, rng).empty); /* Test that the (lazy) evaluation of random samples works correctly. * * We cover 2 different cases: a sample where the ratio of sample points * to total points is greater than the threshold for using Algorithm, and * one where the ratio is small enough (< 1/13) for Algorithm D to be used. * * For each, we also cover the case with and without a specified RNG. */ { // Small sample/source ratio, no specified RNG. uint i = 0; foreach (e; randomSample(randomCover(a), 5)) { ++i; } assert(i == 5); // Small sample/source ratio, specified RNG. i = 0; foreach (e; randomSample(randomCover(a), 5, rng)) { ++i; } assert(i == 5); // Large sample/source ratio, no specified RNG. i = 0; foreach (e; randomSample(TestInputRange(), 123, 123_456)) { ++i; } assert(i == 123); // Large sample/source ratio, specified RNG. i = 0; foreach (e; randomSample(TestInputRange(), 123, 123_456, rng)) { ++i; } assert(i == 123); /* Sample/source ratio large enough to start with Algorithm D, * small enough to switch to Algorithm A. */ i = 0; foreach (e; randomSample(TestInputRange(), 10, 131)) { ++i; } assert(i == 10); } // Test that the .index property works correctly { auto sample1 = randomSample(TestInputRange(), 654, 654_321); for (; !sample1.empty; sample1.popFront()) { assert(sample1.front == sample1.index); } auto sample2 = randomSample(TestInputRange(), 654, 654_321, rng); for (; !sample2.empty; sample2.popFront()) { assert(sample2.front == sample2.index); } /* Check that it also works if .index is called before .front. * See: http://d.puremagic.com/issues/show_bug.cgi?id=10322 */ auto sample3 = randomSample(TestInputRange(), 654, 654_321); for (; !sample3.empty; sample3.popFront()) { assert(sample3.index == sample3.front); } auto sample4 = randomSample(TestInputRange(), 654, 654_321, rng); for (; !sample4.empty; sample4.popFront()) { assert(sample4.index == sample4.front); } } /* Test behaviour if .popFront() is called before sample is read. * This is a rough-and-ready check that the statistical properties * are in the ballpark -- not a proper validation of statistical * quality! This incidentally also checks for reference-type * initialization bugs, as the foreach() loop will operate on a * copy of the popFronted (and hence initialized) sample. */ { size_t count0, count1, count99; foreach(_; 0 .. 100_000) { auto sample = randomSample(iota(100), 5, &rng); sample.popFront(); foreach(s; sample) { if (s == 0) { ++count0; } else if (s == 1) { ++count1; } else if (s == 99) { ++count99; } } } /* Statistical assumptions here: this is a sequential sampling process * so (i) 0 can only be the first sample point, so _can't_ be in the * remainder of the sample after .popFront() is called. (ii) By similar * token, 1 can only be in the remainder if it's the 2nd point of the * whole sample, and hence if 0 was the first; probability of 0 being * first and 1 second is 5/100 * 4/99 (thank you, Algorithm S:-) and * so the mean count of 1 should be about 202. Finally, 99 can only * be the _last_ sample point to be picked, so its probability of * inclusion should be independent of the .popFront() and it should * occur with frequency 5/100, hence its count should be about 5000. * Unfortunately we have to set quite a high tolerance because with * sample size small enough for unittests to run in reasonable time, * the variance can be quite high. */ assert(count0 == 0); assert(count1 < 300, text("1: ", count1, " > 300.")); assert(4_700 < count99, text("99: ", count99, " < 4700.")); assert(count99 < 5_300, text("99: ", count99, " > 5300.")); } /* Odd corner-cases: RandomSample has 2 constructors that are not called * by the randomSample() helper functions, but that can be used if the * constructor is called directly. These cover the case of the user * specifying input but not input length. */ { auto input1 = TestInputRange().takeExactly(456_789); static assert(hasLength!(typeof(input1))); auto sample1 = RandomSample!(typeof(input1), void)(input1, 789); static assert(isInputRange!(typeof(sample1))); static assert(!isForwardRange!(typeof(sample1))); assert(sample1.length == 789); assert(sample1._available == 456_789); uint i = 0; for (; !sample1.empty; sample1.popFront()) { assert(sample1.front == sample1.index); ++i; } assert(i == 789); auto input2 = TestInputRange().takeExactly(456_789); static assert(hasLength!(typeof(input2))); auto sample2 = RandomSample!(typeof(input2), typeof(rng))(input2, 789, rng); static assert(isInputRange!(typeof(sample2))); static assert(!isForwardRange!(typeof(sample2))); assert(sample2.length == 789); assert(sample2._available == 456_789); i = 0; for (; !sample2.empty; sample2.popFront()) { assert(sample2.front == sample2.index); ++i; } assert(i == 789); } /* Test that the save property works where input is a forward range, * and RandomSample is using a (forward range) random number generator * that is not rndGen. */ static if (isForwardRange!UniformRNG) { auto sample1 = randomSample(a, 5, rng); auto sample2 = sample1.save; assert(sample1.array() == sample2.array()); } // Bugzilla 8314 { auto sample(RandomGen)(uint seed) { return randomSample(a, 1, RandomGen(seed)).front; } // Start from 1 because not all RNGs accept 0 as seed. immutable fst = sample!UniformRNG(1); uint n = 1; while (sample!UniformRNG(++n) == fst && n < n.max) {} assert(n < n.max); } } } ldc-1.1.0-beta3-src/runtime/phobos/std/zlib.d0000664000175000017500000004361112776215007017020 0ustar kaikai// Written in the D programming language. /** * Compress/decompress data using the $(WEB www._zlib.net, _zlib library). * * Examples: * * If you have a small buffer you can use $(LREF compress) and * $(LREF uncompress) directly. * * ------- * import std.zlib; * * auto src = * "the quick brown fox jumps over the lazy dog\r * the quick brown fox jumps over the lazy dog\r"; * * ubyte[] dst; * ubyte[] result; * * dst = compress(src); * result = cast(ubyte[])uncompress(dst); * assert(result == src); * ------- * * When the data to be compressed doesn't fit in one buffer, use * $(LREF Compress) and $(LREF UnCompress). * * ------- * import std.zlib; * import std.stdio; * import std.conv: to; * import std.algorithm: map; * * UnCompress decmp = new UnCompress; * foreach (chunk; stdin.byChunk(4096).map!(x => decmp.uncompress(x))) * { * chunk.to!string.write; * } * ------- * * References: * $(WEB en.wikipedia.org/wiki/Zlib, Wikipedia) * * Macros: * WIKI = Phobos/StdZlib * * Copyright: Copyright Digital Mars 2000 - 2011. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * Source: $(PHOBOSSRC std/_zlib.d) */ /* Copyright Digital Mars 2000 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.zlib; //debug=zlib; // uncomment to turn on debugging printf's import etc.c.zlib; // Values for 'mode' enum { Z_NO_FLUSH = 0, Z_SYNC_FLUSH = 2, Z_FULL_FLUSH = 3, Z_FINISH = 4, } /************************************* * Errors throw a ZlibException. */ class ZlibException : Exception { this(int errnum) { string msg; switch (errnum) { case Z_STREAM_END: msg = "stream end"; break; case Z_NEED_DICT: msg = "need dict"; break; case Z_ERRNO: msg = "errno"; break; case Z_STREAM_ERROR: msg = "stream error"; break; case Z_DATA_ERROR: msg = "data error"; break; case Z_MEM_ERROR: msg = "mem error"; break; case Z_BUF_ERROR: msg = "buf error"; break; case Z_VERSION_ERROR: msg = "version error"; break; default: msg = "unknown error"; break; } super(msg); } } /** * $(P Compute the Adler-32 checksum of a buffer's worth of data.) * * Params: * adler = the starting checksum for the computation. Use 1 * for a new checksum. Use the output of this function * for a cumulative checksum. * buf = buffer containing input data * * Returns: * A $(D uint) checksum for the provided input data and starting checksum * * See_Also: * $(LINK http://en.wikipedia.org/wiki/Adler-32) */ uint adler32(uint adler, const(void)[] buf) { import std.range : chunks; foreach(chunk; (cast(ubyte[])buf).chunks(0xFFFF0000)) { adler = etc.c.zlib.adler32(adler, chunk.ptr, cast(uint)chunk.length); } return adler; } /// unittest { static ubyte[] data = [1,2,3,4,5,6,7,8,9,10]; uint adler = adler32(0u, data); assert(adler == 0xdc0037); } unittest { static string data = "test"; uint adler = adler32(1, data); assert(adler == 0x045d01c1); } /** * $(P Compute the CRC32 checksum of a buffer's worth of data.) * * Params: * crc = the starting checksum for the computation. Use 0 * for a new checksum. Use the output of this function * for a cumulative checksum. * buf = buffer containing input data * * Returns: * A $(D uint) checksum for the provided input data and starting checksum * * See_Also: * $(LINK http://en.wikipedia.org/wiki/Cyclic_redundancy_check) */ uint crc32(uint crc, const(void)[] buf) { import std.range : chunks; foreach(chunk; (cast(ubyte[])buf).chunks(0xFFFF0000)) { crc = etc.c.zlib.crc32(crc, chunk.ptr, cast(uint)chunk.length); } return crc; } unittest { static ubyte[] data = [1,2,3,4,5,6,7,8,9,10]; uint crc; debug(zlib) printf("D.zlib.crc32.unittest\n"); crc = crc32(0u, cast(void[])data); debug(zlib) printf("crc = %x\n", crc); assert(crc == 0x2520577b); } /** * $(P Compress data) * * Params: * srcbuf = buffer containing the data to compress * level = compression level. Legal values are -1..9, with -1 indicating * the default level (6), 0 indicating no compression, 1 being the * least compression and 9 being the most. * * Returns: * the compressed data */ ubyte[] compress(const(void)[] srcbuf, int level) in { assert(-1 <= level && level <= 9); } body { auto destlen = srcbuf.length + ((srcbuf.length + 1023) / 1024) + 12; auto destbuf = new ubyte[destlen]; auto err = etc.c.zlib.compress2(destbuf.ptr, &destlen, cast(ubyte *)srcbuf.ptr, srcbuf.length, level); if (err) { delete destbuf; throw new ZlibException(err); } destbuf.length = destlen; return destbuf; } /********************************************* * ditto */ ubyte[] compress(const(void)[] srcbuf) { return compress(srcbuf, Z_DEFAULT_COMPRESSION); } /********************************************* * Decompresses the data in srcbuf[]. * Params: * srcbuf = buffer containing the compressed data. * destlen = size of the uncompressed data. * It need not be accurate, but the decompression will be faster * if the exact size is supplied. * winbits = the base two logarithm of the maximum window size. * Returns: the decompressed data. */ void[] uncompress(const(void)[] srcbuf, size_t destlen = 0u, int winbits = 15) { import std.conv : to; int err; ubyte[] destbuf; if (!destlen) destlen = srcbuf.length * 2 + 1; etc.c.zlib.z_stream zs; zs.next_in = cast(typeof(zs.next_in)) srcbuf.ptr; zs.avail_in = to!uint(srcbuf.length); err = etc.c.zlib.inflateInit2(&zs, winbits); if (err) { throw new ZlibException(err); } size_t olddestlen = 0u; loop: while (true) { destbuf.length = destlen; zs.next_out = cast(typeof(zs.next_out)) &destbuf[olddestlen]; zs.avail_out = to!uint(destlen - olddestlen); olddestlen = destlen; err = etc.c.zlib.inflate(&zs, Z_NO_FLUSH); switch (err) { case Z_OK: destlen = destbuf.length * 2; continue loop; case Z_STREAM_END: destbuf.length = zs.total_out; err = etc.c.zlib.inflateEnd(&zs); if (err != Z_OK) throw new ZlibException(err); return destbuf; default: etc.c.zlib.inflateEnd(&zs); throw new ZlibException(err); } } assert(0); } unittest { auto src = "the quick brown fox jumps over the lazy dog\r the quick brown fox jumps over the lazy dog\r "; ubyte[] dst; ubyte[] result; //arrayPrint(src); dst = compress(src); //arrayPrint(dst); result = cast(ubyte[])uncompress(dst); //arrayPrint(result); assert(result == src); } unittest { ubyte[] src = new ubyte[1000000]; ubyte[] dst; ubyte[] result; src[] = 0x80; dst = compress(src); assert(dst.length*2 + 1 < src.length); result = cast(ubyte[]) uncompress(dst); assert(result == src); } /+ void arrayPrint(ubyte[] array) { //printf("array %p,%d\n", cast(void*)array, array.length); for (size_t i = 0; i < array.length; i++) { printf("%02x ", array[i]); if (((i + 1) & 15) == 0) printf("\n"); } printf("\n\n"); } +/ /// the header format the compressed stream is wrapped in enum HeaderFormat { deflate, /// a standard zlib header gzip, /// a gzip file format header determineFromData /// used when decompressing. Try to automatically detect the stream format by looking at the data } /********************************************* * Used when the data to be compressed is not all in one buffer. */ class Compress { import std.conv: to; private: z_stream zs; int level = Z_DEFAULT_COMPRESSION; int inited; immutable bool gzip; void error(int err) { if (inited) { deflateEnd(&zs); inited = 0; } throw new ZlibException(err); } public: /** * Constructor. * * Params: * level = compression level. Legal values are 1..9, with 1 being the least * compression and 9 being the most. The default value is 6. * header = sets the compression type to one of the options available * in $(LREF HeaderFormat). Defaults to HeaderFormat.deflate. * * See_Also: * $(LREF compress), $(LREF HeaderFormat) */ this(int level, HeaderFormat header = HeaderFormat.deflate) in { assert(1 <= level && level <= 9); } body { this.level = level; this.gzip = header == HeaderFormat.gzip; } /// ditto this(HeaderFormat header = HeaderFormat.deflate) { this.gzip = header == HeaderFormat.gzip; } ~this() { int err; if (inited) { inited = 0; deflateEnd(&zs); } } /** * Compress the data in buf and return the compressed data. * Params: * buf = data to compress * * Returns: * the compressed data. The buffers returned from successive calls to this should be concatenated together. * */ const(void)[] compress(const(void)[] buf) { int err; ubyte[] destbuf; if (buf.length == 0) return null; if (!inited) { err = deflateInit2(&zs, level, Z_DEFLATED, 15 + (gzip ? 16 : 0), 8, Z_DEFAULT_STRATEGY); if (err) error(err); inited = 1; } destbuf = new ubyte[zs.avail_in + buf.length]; zs.next_out = destbuf.ptr; zs.avail_out = to!uint(destbuf.length); if (zs.avail_in) buf = zs.next_in[0 .. zs.avail_in] ~ cast(ubyte[]) buf; zs.next_in = cast(typeof(zs.next_in)) buf.ptr; zs.avail_in = to!uint(buf.length); err = deflate(&zs, Z_NO_FLUSH); if (err != Z_STREAM_END && err != Z_OK) { delete destbuf; error(err); } destbuf.length = destbuf.length - zs.avail_out; return destbuf; } /*** * Compress and return any remaining data. * The returned data should be appended to that returned by compress(). * Params: * mode = one of the following: * $(DL $(DT Z_SYNC_FLUSH ) $(DD Syncs up flushing to the next byte boundary. Used when more data is to be compressed later on.) $(DT Z_FULL_FLUSH ) $(DD Syncs up flushing to the next byte boundary. Used when more data is to be compressed later on, and the decompressor needs to be restartable at this point.) $(DT Z_FINISH) $(DD (default) Used when finished compressing the data. ) ) */ void[] flush(int mode = Z_FINISH) in { assert(mode == Z_FINISH || mode == Z_SYNC_FLUSH || mode == Z_FULL_FLUSH); } body { ubyte[] destbuf; ubyte[512] tmpbuf = void; int err; if (!inited) return null; /* may be zs.avail_out+ * zs.avail_out is set nonzero by deflate in previous compress() */ //tmpbuf = new void[zs.avail_out]; zs.next_out = tmpbuf.ptr; zs.avail_out = tmpbuf.length; while( (err = deflate(&zs, mode)) != Z_STREAM_END) { if (err == Z_OK) { if (zs.avail_out != 0 && mode != Z_FINISH) break; else if(zs.avail_out == 0) { destbuf ~= tmpbuf; zs.next_out = tmpbuf.ptr; zs.avail_out = tmpbuf.length; continue; } err = Z_BUF_ERROR; } delete destbuf; error(err); } destbuf ~= tmpbuf[0 .. (tmpbuf.length - zs.avail_out)]; if (mode == Z_FINISH) { err = deflateEnd(&zs); inited = 0; if (err) error(err); } return destbuf; } } /****** * Used when the data to be decompressed is not all in one buffer. */ class UnCompress { import std.conv: to; private: z_stream zs; int inited; int done; size_t destbufsize; HeaderFormat format; void error(int err) { if (inited) { inflateEnd(&zs); inited = 0; } throw new ZlibException(err); } public: /** * Construct. destbufsize is the same as for D.zlib.uncompress(). */ this(uint destbufsize) { this.destbufsize = destbufsize; } /** ditto */ this(HeaderFormat format = HeaderFormat.determineFromData) { this.format = format; } ~this() { int err; if (inited) { inited = 0; inflateEnd(&zs); } done = 1; } /** * Decompress the data in buf and return the decompressed data. * The buffers returned from successive calls to this should be concatenated * together. */ const(void)[] uncompress(const(void)[] buf) in { assert(!done); } body { int err; ubyte[] destbuf; if (buf.length == 0) return null; if (!inited) { int windowBits = 15; if(format == HeaderFormat.gzip) windowBits += 16; else if(format == HeaderFormat.determineFromData) windowBits += 32; err = inflateInit2(&zs, windowBits); if (err) error(err); inited = 1; } if (!destbufsize) destbufsize = to!uint(buf.length) * 2; destbuf = new ubyte[zs.avail_in * 2 + destbufsize]; zs.next_out = destbuf.ptr; zs.avail_out = to!uint(destbuf.length); if (zs.avail_in) buf = zs.next_in[0 .. zs.avail_in] ~ cast(ubyte[]) buf; zs.next_in = cast(ubyte*) buf.ptr; zs.avail_in = to!uint(buf.length); err = inflate(&zs, Z_NO_FLUSH); if (err != Z_STREAM_END && err != Z_OK) { delete destbuf; error(err); } destbuf.length = destbuf.length - zs.avail_out; return destbuf; } /** * Decompress and return any remaining data. * The returned data should be appended to that returned by uncompress(). * The UnCompress object cannot be used further. */ void[] flush() in { assert(!done); } out { assert(done); } body { ubyte[] extra; ubyte[] destbuf; int err; done = 1; if (!inited) return null; L1: destbuf = new ubyte[zs.avail_in * 2 + 100]; zs.next_out = destbuf.ptr; zs.avail_out = to!uint(destbuf.length); err = etc.c.zlib.inflate(&zs, Z_NO_FLUSH); if (err == Z_OK && zs.avail_out == 0) { extra ~= destbuf; goto L1; } if (err != Z_STREAM_END) { delete destbuf; if (err == Z_OK) err = Z_BUF_ERROR; error(err); } destbuf = destbuf.ptr[0 .. zs.next_out - destbuf.ptr]; err = etc.c.zlib.inflateEnd(&zs); inited = 0; if (err) error(err); if (extra.length) destbuf = extra ~ destbuf; return destbuf; } } /* ========================== unittest ========================= */ private import std.stdio; private import std.random; unittest // by Dave { debug(zlib) writeln("std.zlib.unittest"); bool CompressThenUncompress (void[] src) { ubyte[] dst = std.zlib.compress(src); double ratio = (dst.length / cast(double)src.length); debug(zlib) writef("src.length: %1$d, dst: %2$d, Ratio = %3$f", src.length, dst.length, ratio); ubyte[] uncompressedBuf; uncompressedBuf = cast(ubyte[]) std.zlib.uncompress(dst); assert(src.length == uncompressedBuf.length); assert(src == uncompressedBuf); return true; } // smallish buffers for(int idx = 0; idx < 25; idx++) { char[] buf = new char[uniform(0, 100)]; // Alternate between more & less compressible foreach(ref char c; buf) c = cast(char) (' ' + (uniform(0, idx % 2 ? 91 : 2))); if(CompressThenUncompress(buf)) { debug(zlib) writeln("; Success."); } else { return; } } // larger buffers for(int idx = 0; idx < 25; idx++) { char[] buf = new char[uniform(0, 1000/*0000*/)]; // Alternate between more & less compressible foreach(ref char c; buf) c = cast(char) (' ' + (uniform(0, idx % 2 ? 91 : 10))); if(CompressThenUncompress(buf)) { debug(zlib) writefln("; Success."); } else { return; } } debug(zlib) writefln("PASSED std.zlib.unittest"); } unittest // by Artem Rebrov { Compress cmp = new Compress; UnCompress decmp = new UnCompress; const(void)[] input; input = "tesatdffadf"; const(void)[] buf = cmp.compress(input); buf ~= cmp.flush(); const(void)[] output = decmp.uncompress(buf); //writefln("input = '%s'", cast(char[])input); //writefln("output = '%s'", cast(char[])output); assert( output[] == input[] ); } ldc-1.1.0-beta3-src/runtime/phobos/std/signals.d0000664000175000017500000004113012776215007017512 0ustar kaikai// Written in the D programming language. /** * Signals and Slots are an implementation of the Observer Pattern. * Essentially, when a Signal is emitted, a list of connected Observers * (called slots) are called. * * There have been several D implementations of Signals and Slots. * This version makes use of several new features in D, which make * using it simpler and less error prone. In particular, it is no * longer necessary to instrument the slots. * * References: * $(LUCKY A Deeper Look at Signals and Slots)$(BR) * $(LINK2 http://en.wikipedia.org/wiki/Observer_pattern, Observer pattern)$(BR) * $(LINK2 http://en.wikipedia.org/wiki/Signals_and_slots, Wikipedia)$(BR) * $(LINK2 http://boost.org/doc/html/$(SIGNALS).html, Boost Signals)$(BR) * $(LINK2 http://qt-project.org/doc/qt-5/signalsandslots.html, Qt)$(BR) * * There has been a great deal of discussion in the D newsgroups * over this, and several implementations: * * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/signal_slots_library_4825.html, signal slots library)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Signals_and_Slots_in_D_42387.html, Signals and Slots in D)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dynamic_binding_--_Qt_s_Signals_and_Slots_vs_Objective-C_42260.html, Dynamic binding -- Qt's Signals and Slots vs Objective-C)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dissecting_the_SS_42377.html, Dissecting the SS)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/dwt/about_harmonia_454.html, about harmonia)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/1502.html, Another event handling module)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/41825.html, Suggestion: signal/slot mechanism)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/13251.html, Signals and slots?)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/10714.html, Signals and slots ready for evaluation)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/1393.html, Signals & Slots for Walter)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/28456.html, Signal/Slot mechanism?)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/19470.html, Modern Features?)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/16592.html, Delegates vs interfaces)$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/16583.html, The importance of component programming (properties$(COMMA) signals and slots$(COMMA) etc))$(BR) * $(LINK2 http://www.digitalmars.com/d/archives/16368.html, signals and slots)$(BR) * * Bugs: * Slots can only be delegates formed from class objects or * interfaces to class objects. If a delegate to something else * is passed to connect(), such as a struct member function, * a nested function or a COM interface, undefined behavior * will result. * * Not safe for multiple threads operating on the same signals * or slots. * Macros: * WIKI = Phobos/StdSignals * SIGNALS=signals * * Copyright: Copyright Digital Mars 2000 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * Source: $(PHOBOSSRC std/_signals.d) */ /* Copyright Digital Mars 2000 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.signals; import std.stdio; import core.stdc.stdlib : calloc, realloc, free; import core.exception : onOutOfMemoryError; // Special function for internal use only. // Use of this is where the slot had better be a delegate // to an object or an interface that is part of an object. extern (C) Object _d_toObject(void* p); // Used in place of Object.notifyRegister and Object.notifyUnRegister. alias DisposeEvt = void delegate(Object); extern (C) void rt_attachDisposeEvent( Object obj, DisposeEvt evt ); extern (C) void rt_detachDisposeEvent( Object obj, DisposeEvt evt ); //debug=signal; /************************ * Mixin to create a signal within a class object. * * Different signals can be added to a class by naming the mixins. */ mixin template Signal(T1...) { static import core.stdc.stdlib; static import core.exception; /*** * A slot is implemented as a delegate. * The slot_t is the type of the delegate. * The delegate must be to an instance of a class or an interface * to a class instance. * Delegates to struct instances or nested functions must not be * used as slots. */ alias slot_t = void delegate(T1); /*** * Call each of the connected slots, passing the argument(s) i to them. */ final void emit( T1 i ) { foreach (slot; slots[0 .. slots_idx]) { if (slot) slot(i); } } /*** * Add a slot to the list of slots to be called when emit() is called. */ final void connect(slot_t slot) { /* Do this: * slots ~= slot; * but use malloc() and friends instead */ auto len = slots.length; if (slots_idx == len) { if (slots.length == 0) { len = 4; auto p = core.stdc.stdlib.calloc(slot_t.sizeof, len); if (!p) core.exception.onOutOfMemoryError(); slots = (cast(slot_t*)p)[0 .. len]; } else { len = len * 2 + 4; auto p = core.stdc.stdlib.realloc(slots.ptr, slot_t.sizeof * len); if (!p) core.exception.onOutOfMemoryError(); slots = (cast(slot_t*)p)[0 .. len]; slots[slots_idx + 1 .. $] = null; } } slots[slots_idx++] = slot; L1: Object o = _d_toObject(slot.ptr); rt_attachDisposeEvent(o, &unhook); } /*** * Remove a slot from the list of slots to be called when emit() is called. */ final void disconnect(slot_t slot) { debug (signal) writefln("Signal.disconnect(slot)"); for (size_t i = 0; i < slots_idx; ) { if (slots[i] == slot) { slots_idx--; slots[i] = slots[slots_idx]; slots[slots_idx] = null; // not strictly necessary Object o = _d_toObject(slot.ptr); rt_detachDisposeEvent(o, &unhook); } else i++; } } /* ** * Special function called when o is destroyed. * It causes any slots dependent on o to be removed from the list * of slots to be called by emit(). */ final void unhook(Object o) { debug (signal) writefln("Signal.unhook(o = %s)", cast(void*)o); for (size_t i = 0; i < slots_idx; ) { if (_d_toObject(slots[i].ptr) is o) { slots_idx--; slots[i] = slots[slots_idx]; slots[slots_idx] = null; // not strictly necessary } else i++; } } /* ** * There can be multiple destructors inserted by mixins. */ ~this() { /* ** * When this object is destroyed, need to let every slot * know that this object is destroyed so they are not left * with dangling references to it. */ if (slots.length) { foreach (slot; slots[0 .. slots_idx]) { if (slot) { Object o = _d_toObject(slot.ptr); rt_detachDisposeEvent(o, &unhook); } } core.stdc.stdlib.free(slots.ptr); slots = null; } } private: slot_t[] slots; // the slots to call from emit() size_t slots_idx; // used length of slots[] } /// unittest { import std.signals; int observedMessageCounter = 0; class Observer { // our slot void watch(string msg, int value) { switch(observedMessageCounter++) { case 0: assert(msg == "setting new value"); assert(value == 4); break; case 1: assert(msg == "setting new value"); assert(value == 6); break; default: assert(0, "Unknown observation"); } } } class Foo { int value() { return _value; } int value(int v) { if (v != _value) { _value = v; // call all the connected slots with the two parameters emit("setting new value", v); } return v; } // Mix in all the code we need to make Foo into a signal mixin Signal!(string, int); private : int _value; } Foo a = new Foo; Observer o = new Observer; a.value = 3; // should not call o.watch() a.connect(&o.watch); // o.watch is the slot a.value = 4; // should call o.watch() a.disconnect(&o.watch); // o.watch is no longer a slot a.value = 5; // so should not call o.watch() a.connect(&o.watch); // connect again a.value = 6; // should call o.watch() destroy(o); // destroying o should automatically disconnect it a.value = 7; // should not call o.watch() assert(observedMessageCounter == 2); } // A function whose sole purpose is to get this module linked in // so the unittest will run. void linkin() { } unittest { class Observer { void watch(string msg, int i) { //writefln("Observed msg '%s' and value %s", msg, i); captured_value = i; captured_msg = msg; } int captured_value; string captured_msg; } class Foo { @property int value() { return _value; } @property int value(int v) { if (v != _value) { _value = v; emit("setting new value", v); } return v; } mixin Signal!(string, int); private: int _value; } Foo a = new Foo; Observer o = new Observer; // check initial condition assert(o.captured_value == 0); assert(o.captured_msg == ""); // set a value while no observation is in place a.value = 3; assert(o.captured_value == 0); assert(o.captured_msg == ""); // connect the watcher and trigger it a.connect(&o.watch); a.value = 4; assert(o.captured_value == 4); assert(o.captured_msg == "setting new value"); // disconnect the watcher and make sure it doesn't trigger a.disconnect(&o.watch); a.value = 5; assert(o.captured_value == 4); assert(o.captured_msg == "setting new value"); // reconnect the watcher and make sure it triggers a.connect(&o.watch); a.value = 6; assert(o.captured_value == 6); assert(o.captured_msg == "setting new value"); // destroy the underlying object and make sure it doesn't cause // a crash or other problems destroy(o); a.value = 7; } unittest { class Observer { int i; long l; string str; void watchInt(string str, int i) { this.str = str; this.i = i; } void watchLong(string str, long l) { this.str = str; this.l = l; } } class Bar { @property void value1(int v) { s1.emit("str1", v); } @property void value2(int v) { s2.emit("str2", v); } @property void value3(long v) { s3.emit("str3", v); } mixin Signal!(string, int) s1; mixin Signal!(string, int) s2; mixin Signal!(string, long) s3; } void test(T)(T a) { auto o1 = new Observer; auto o2 = new Observer; auto o3 = new Observer; // connect the watcher and trigger it a.s1.connect(&o1.watchInt); a.s2.connect(&o2.watchInt); a.s3.connect(&o3.watchLong); assert(!o1.i && !o1.l && o1.str == null); assert(!o2.i && !o2.l && o2.str == null); assert(!o3.i && !o3.l && o3.str == null); a.value1 = 11; assert(o1.i == 11 && !o1.l && o1.str == "str1"); assert(!o2.i && !o2.l && o2.str == null); assert(!o3.i && !o3.l && o3.str == null); o1.i = -11; o1.str = "x1"; a.value2 = 12; assert(o1.i == -11 && !o1.l && o1.str == "x1"); assert(o2.i == 12 && !o2.l && o2.str == "str2"); assert(!o3.i && !o3.l && o3.str == null); o2.i = -12; o2.str = "x2"; a.value3 = 13; assert(o1.i == -11 && !o1.l && o1.str == "x1"); assert(o2.i == -12 && !o1.l && o2.str == "x2"); assert(!o3.i && o3.l == 13 && o3.str == "str3"); o3.l = -13; o3.str = "x3"; // disconnect the watchers and make sure it doesn't trigger a.s1.disconnect(&o1.watchInt); a.s2.disconnect(&o2.watchInt); a.s3.disconnect(&o3.watchLong); a.value1 = 21; a.value2 = 22; a.value3 = 23; assert(o1.i == -11 && !o1.l && o1.str == "x1"); assert(o2.i == -12 && !o1.l && o2.str == "x2"); assert(!o3.i && o3.l == -13 && o3.str == "x3"); // reconnect the watcher and make sure it triggers a.s1.connect(&o1.watchInt); a.s2.connect(&o2.watchInt); a.s3.connect(&o3.watchLong); a.value1 = 31; a.value2 = 32; a.value3 = 33; assert(o1.i == 31 && !o1.l && o1.str == "str1"); assert(o2.i == 32 && !o1.l && o2.str == "str2"); assert(!o3.i && o3.l == 33 && o3.str == "str3"); // destroy observers destroy(o1); destroy(o2); destroy(o3); a.value1 = 41; a.value2 = 42; a.value3 = 43; } test(new Bar); class BarDerived: Bar { @property void value4(int v) { s4.emit("str4", v); } @property void value5(int v) { s5.emit("str5", v); } @property void value6(long v) { s6.emit("str6", v); } mixin Signal!(string, int) s4; mixin Signal!(string, int) s5; mixin Signal!(string, long) s6; } auto a = new BarDerived; test!Bar(a); test!BarDerived(a); auto o4 = new Observer; auto o5 = new Observer; auto o6 = new Observer; // connect the watcher and trigger it a.s4.connect(&o4.watchInt); a.s5.connect(&o5.watchInt); a.s6.connect(&o6.watchLong); assert(!o4.i && !o4.l && o4.str == null); assert(!o5.i && !o5.l && o5.str == null); assert(!o6.i && !o6.l && o6.str == null); a.value4 = 44; assert(o4.i == 44 && !o4.l && o4.str == "str4"); assert(!o5.i && !o5.l && o5.str == null); assert(!o6.i && !o6.l && o6.str == null); o4.i = -44; o4.str = "x4"; a.value5 = 45; assert(o4.i == -44 && !o4.l && o4.str == "x4"); assert(o5.i == 45 && !o5.l && o5.str == "str5"); assert(!o6.i && !o6.l && o6.str == null); o5.i = -45; o5.str = "x5"; a.value6 = 46; assert(o4.i == -44 && !o4.l && o4.str == "x4"); assert(o5.i == -45 && !o4.l && o5.str == "x5"); assert(!o6.i && o6.l == 46 && o6.str == "str6"); o6.l = -46; o6.str = "x6"; // disconnect the watchers and make sure it doesn't trigger a.s4.disconnect(&o4.watchInt); a.s5.disconnect(&o5.watchInt); a.s6.disconnect(&o6.watchLong); a.value4 = 54; a.value5 = 55; a.value6 = 56; assert(o4.i == -44 && !o4.l && o4.str == "x4"); assert(o5.i == -45 && !o4.l && o5.str == "x5"); assert(!o6.i && o6.l == -46 && o6.str == "x6"); // reconnect the watcher and make sure it triggers a.s4.connect(&o4.watchInt); a.s5.connect(&o5.watchInt); a.s6.connect(&o6.watchLong); a.value4 = 64; a.value5 = 65; a.value6 = 66; assert(o4.i == 64 && !o4.l && o4.str == "str4"); assert(o5.i == 65 && !o4.l && o5.str == "str5"); assert(!o6.i && o6.l == 66 && o6.str == "str6"); // destroy observers destroy(o4); destroy(o5); destroy(o6); a.value4 = 44; a.value5 = 45; a.value6 = 46; } version(none) // Disabled because of dmd @@@BUG5028@@@ unittest { class A { mixin Signal!(string, int) s1; } class B : A { mixin Signal!(string, int) s2; } } ldc-1.1.0-beta3-src/runtime/phobos/std/conv.d0000664000175000017500000046034012776215007017027 0ustar kaikai// Written in the D programming language. /** A one-stop shop for converting values from one type to another. Copyright: Copyright Digital Mars 2007-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei Alexandrescu), Shin Fujishiro, Adam D. Ruppe, Kenji Hara Source: $(PHOBOSSRC std/_conv.d) Macros: WIKI = Phobos/StdConv */ module std.conv; public import std.ascii : LetterCase; import std.meta; import std.range.primitives; import std.traits; // Same as std.string.format, but "self-importing". // Helps reduce code and imports, particularly in static asserts. // Also helps with missing imports errors. package template convFormat() { import std.format : format; alias convFormat = format; } /* ************* Exceptions *************** */ /** * Thrown on conversion errors. */ class ConvException : Exception { @safe pure nothrow this(string s, string fn = __FILE__, size_t ln = __LINE__) { super(s, fn, ln); } } private string convError_unexpected(S)(S source) { return source.empty ? "end of input" : text("'", source.front, "'"); } private auto convError(S, T)(S source, string fn = __FILE__, size_t ln = __LINE__) { return new ConvException( text("Unexpected ", convError_unexpected(source), " when converting from type "~S.stringof~" to type "~T.stringof), fn, ln); } private auto convError(S, T)(S source, int radix, string fn = __FILE__, size_t ln = __LINE__) { return new ConvException( text("Unexpected ", convError_unexpected(source), " when converting from type "~S.stringof~" base ", radix, " to type "~T.stringof), fn, ln); } @safe pure/* nothrow*/ // lazy parameter bug private auto parseError(lazy string msg, string fn = __FILE__, size_t ln = __LINE__) { return new ConvException(text("Can't parse string: ", msg), fn, ln); } private void parseCheck(alias source)(dchar c, string fn = __FILE__, size_t ln = __LINE__) { if (source.empty) throw parseError(text("unexpected end of input when expecting", "\"", c, "\"")); if (source.front != c) throw parseError(text("\"", c, "\" is missing"), fn, ln); source.popFront(); } private { template isImaginary(T) { enum bool isImaginary = staticIndexOf!(Unqual!T, ifloat, idouble, ireal) >= 0; } template isComplex(T) { enum bool isComplex = staticIndexOf!(Unqual!T, cfloat, cdouble, creal) >= 0; } template isNarrowInteger(T) { enum bool isNarrowInteger = staticIndexOf!(Unqual!T, byte, ubyte, short, ushort) >= 0; } T toStr(T, S)(S src) if (isSomeString!T) { // workaround for Bugzilla 14198 static if (is(S == bool) && is(typeof({ T s = "string"; }))) { return src ? "true" : "false"; } else { import std.format : FormatSpec, formatValue; import std.array : appender; auto w = appender!T(); FormatSpec!(ElementEncodingType!T) f; formatValue(w, src, f); return w.data; } } template isExactSomeString(T) { enum isExactSomeString = isSomeString!T && !is(T == enum); } template isEnumStrToStr(S, T) { enum isEnumStrToStr = isImplicitlyConvertible!(S, T) && is(S == enum) && isExactSomeString!T; } template isNullToStr(S, T) { enum isNullToStr = isImplicitlyConvertible!(S, T) && (is(Unqual!S == typeof(null))) && isExactSomeString!T; } template isRawStaticArray(T, A...) { enum isRawStaticArray = A.length == 0 && isStaticArray!T && !is(T == class) && !is(T == interface) && !is(T == struct) && !is(T == union); } } /** * Thrown on conversion overflow errors. */ class ConvOverflowException : ConvException { @safe pure nothrow this(string s, string fn = __FILE__, size_t ln = __LINE__) { super(s, fn, ln); } } /** The $(D_PARAM to) family of functions converts a value from type $(D_PARAM Source) to type $(D_PARAM Target). The source type is deduced and the target type must be specified, for example the expression $(D_PARAM to!int(42.0)) converts the number 42 from $(D_PARAM double) to $(D_PARAM int). The conversion is "safe", i.e., it checks for overflow; $(D_PARAM to!int(4.2e10)) would throw the $(D_PARAM ConvOverflowException) exception. Overflow checks are only inserted when necessary, e.g., $(D_PARAM to!double(42)) does not do any checking because any int fits in a double. Converting a value to its own type (useful mostly for generic code) simply returns its argument. Example: ------------------------- int a = 42; auto b = to!int(a); // b is int with value 42 auto c = to!double(3.14); // c is double with value 3.14 ------------------------- Converting among numeric types is a safe way to cast them around. Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use $(D_PARAM roundTo).) Example: ------------------------- int a = 420; auto b = to!long(a); // same as long b = a; auto c = to!byte(a / 10); // fine, c = 42 auto d = to!byte(a); // throw ConvOverflowException double e = 4.2e6; auto f = to!int(e); // f == 4200000 e = -3.14; auto g = to!uint(e); // fails: floating-to-integral negative overflow e = 3.14; auto h = to!uint(e); // h = 3 e = 3.99; h = to!uint(a); // h = 3 e = -3.99; f = to!int(a); // f = -3 ------------------------- Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for $(D_PARAM real) (when $(D_PARAM real) is 80-bit, e.g. on Intel machines). Example: ------------------------- int a = 16_777_215; // 2^24 - 1, largest proper integer representable as float assert(to!int(to!float(a)) == a); assert(to!int(to!float(-a)) == -a); a += 2; assert(to!int(to!float(a)) == a); // fails! ------------------------- Conversions from string to numeric types differ from the C equivalents $(D_PARAM atoi()) and $(D_PARAM atol()) by checking for overflow and not allowing whitespace. For conversion of strings to signed types, the grammar recognized is:
$(I Integer): $(I Sign UnsignedInteger)
$(I UnsignedInteger)
$(I Sign):
    $(B +)
    $(B -)
For conversion to unsigned types, the grammar recognized is:
$(I UnsignedInteger):
    $(I DecimalDigit)
    $(I DecimalDigit) $(I UnsignedInteger)
Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted. Example: ------------------------- int[] a = [1, 2, 3]; auto b = to!(float[])(a); assert(b == [1.0f, 2, 3]); string str = "1 2 3 4 5 6"; auto numbers = to!(double[])(split(str)); assert(numbers == [1.0, 2, 3, 4, 5, 6]); int[string] c; c["a"] = 1; c["b"] = 2; auto d = to!(double[wstring])(c); assert(d["a"w] == 1 && d["b"w] == 2); ------------------------- Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity: ------------------------- int[string][double[int[]]] a; ... auto b = to!(short[wstring][string[double[]]])(a); ------------------------- This conversion works because $(D_PARAM to!short) applies to an $(D_PARAM int), $(D_PARAM to!wstring) applies to a $(D_PARAM string), $(D_PARAM to!string) applies to a $(D_PARAM double), and $(D_PARAM to!(double[])) applies to an $(D_PARAM int[]). The conversion might throw an exception because $(D_PARAM to!short) might fail the range check. */ /** Entry point that dispatches to the appropriate conversion primitive. Client code normally calls $(D _to!TargetType(value)) (and not some variant of $(D toImpl)). */ template to(T) { T to(A...)(A args) if (!isRawStaticArray!A) { return toImpl!T(args); } // Fix issue 6175 T to(S)(ref S arg) if (isRawStaticArray!S) { return toImpl!T(arg); } } // Tests for issue 6175 @safe pure nothrow unittest { char[9] sarr = "blablabla"; auto darr = to!(char[])(sarr); assert(sarr.ptr == darr.ptr); assert(sarr.length == darr.length); } // Tests for issue 7348 @safe pure /+nothrow+/ unittest { assert(to!string(null) == "null"); assert(text(null) == "null"); } // Tests for issue 11390 @safe pure /+nothrow+/ unittest { const(typeof(null)) ctn; immutable(typeof(null)) itn; assert(to!string(ctn) == "null"); assert(to!string(itn) == "null"); } // Tests for issue 8729: do NOT skip leading WS @safe pure unittest { import std.exception; foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) { assertThrown!ConvException(to!T(" 0")); assertThrown!ConvException(to!T(" 0", 8)); } foreach (T; AliasSeq!(float, double, real)) { assertThrown!ConvException(to!T(" 0")); } assertThrown!ConvException(to!bool(" true")); alias NullType = typeof(null); assertThrown!ConvException(to!NullType(" null")); alias ARR = int[]; assertThrown!ConvException(to!ARR(" [1]")); alias AA = int[int]; assertThrown!ConvException(to!AA(" [1:1]")); } /** If the source type is implicitly convertible to the target type, $(D to) simply performs the implicit conversion. */ T toImpl(T, S)(S value) if (isImplicitlyConvertible!(S, T) && !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) { template isSignedInt(T) { enum isSignedInt = isIntegral!T && isSigned!T; } alias isUnsignedInt = isUnsigned; // Conversion from integer to integer, and changing its sign static if (isUnsignedInt!S && isSignedInt!T && S.sizeof == T.sizeof) { // unsigned to signed & same size import std.exception : enforce; enforce(value <= cast(S)T.max, new ConvOverflowException("Conversion positive overflow")); } else static if (isSignedInt!S && isUnsignedInt!T) { // signed to unsigned import std.exception : enforce; enforce(0 <= value, new ConvOverflowException("Conversion negative overflow")); } return value; } @safe pure nothrow unittest { enum E { a } // Issue 9523 - Allow identity enum conversion auto e = to!E(E.a); assert(e == E.a); } @safe pure nothrow unittest { int a = 42; auto b = to!long(a); assert(a == b); } // Tests for issue 6377 @safe pure unittest { import std.exception; // Conversion between same size foreach (S; AliasSeq!(byte, short, int, long)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 alias U = Unsigned!S; foreach (Sint; AliasSeq!(S, const S, immutable S)) foreach (Uint; AliasSeq!(U, const U, immutable U)) { // positive overflow Uint un = Uint.max; assertThrown!ConvOverflowException(to!Sint(un), text(Sint.stringof, ' ', Uint.stringof, ' ', un)); // negative overflow Sint sn = -1; assertThrown!ConvOverflowException(to!Uint(sn), text(Sint.stringof, ' ', Uint.stringof, ' ', un)); } }(); // Conversion between different size foreach (i, S1; AliasSeq!(byte, short, int, long)) foreach ( S2; AliasSeq!(byte, short, int, long)[i+1..$]) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 alias U1 = Unsigned!S1; alias U2 = Unsigned!S2; static assert(U1.sizeof < S2.sizeof); // small unsigned to big signed foreach (Uint; AliasSeq!(U1, const U1, immutable U1)) foreach (Sint; AliasSeq!(S2, const S2, immutable S2)) { Uint un = Uint.max; assertNotThrown(to!Sint(un)); assert(to!Sint(un) == un); } // big unsigned to small signed foreach (Uint; AliasSeq!(U2, const U2, immutable U2)) foreach (Sint; AliasSeq!(S1, const S1, immutable S1)) { Uint un = Uint.max; assertThrown(to!Sint(un)); } static assert(S1.sizeof < U2.sizeof); // small signed to big unsigned foreach (Sint; AliasSeq!(S1, const S1, immutable S1)) foreach (Uint; AliasSeq!(U2, const U2, immutable U2)) { Sint sn = -1; assertThrown!ConvOverflowException(to!Uint(sn)); } // big signed to small unsigned foreach (Sint; AliasSeq!(S2, const S2, immutable S2)) foreach (Uint; AliasSeq!(U1, const U1, immutable U1)) { Sint sn = -1; assertThrown!ConvOverflowException(to!Uint(sn)); } }(); } /* Converting static arrays forwards to their dynamic counterparts. */ T toImpl(T, S)(ref S s) if (isRawStaticArray!S) { return toImpl!(T, typeof(s[0])[])(s); } @safe pure nothrow unittest { char[4] test = ['a', 'b', 'c', 'd']; static assert(!isInputRange!(Unqual!(char[4]))); assert(to!string(test) == test); } /** When source type supports member template function opCast, it is used. */ T toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) && is(typeof(S.init.opCast!T()) : T) && !isExactSomeString!T && !is(typeof(T(value)))) { return value.opCast!T(); } @safe pure unittest { static struct Test { struct T { this(S s) @safe pure { } } struct S { T opCast(U)() @safe pure { assert(false); } } } to!(Test.T)(Test.S()); // make sure std.conv.to is doing the same thing as initialization Test.S s; Test.T t = s; } @safe pure unittest { class B { T opCast(T)() { return 43; } } auto b = new B; assert(to!int(b) == 43); struct S { T opCast(T)() { return 43; } } auto s = S(); assert(to!int(s) == 43); } /** When target type supports 'converting construction', it is used. $(UL $(LI If target type is struct, $(D T(value)) is used.) $(LI If target type is class, $(D new T(value)) is used.)) */ T toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) && is(T == struct) && is(typeof(T(value)))) { return T(value); } // Bugzilla 3961 @safe pure unittest { struct Int { int x; } Int i = to!Int(1); static struct Int2 { int x; this(int x) @safe pure { this.x = x; } } Int2 i2 = to!Int2(1); static struct Int3 { int x; static Int3 opCall(int x) @safe pure { Int3 i; i.x = x; return i; } } Int3 i3 = to!Int3(1); } // Bugzilla 6808 @safe pure unittest { static struct FakeBigInt { this(string s) @safe pure {} } string s = "101"; auto i3 = to!FakeBigInt(s); } /// ditto T toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) && is(T == class) && is(typeof(new T(value)))) { return new T(value); } @safe pure unittest { static struct S { int x; } static class C { int x; this(int x) @safe pure { this.x = x; } } static class B { int value; this(S src) @safe pure { value = src.x; } this(C src) @safe pure { value = src.x; } } S s = S(1); auto b1 = to!B(s); // == new B(s) assert(b1.value == 1); C c = new C(2); auto b2 = to!B(c); // == new B(c) assert(b2.value == 2); auto c2 = to!C(3); // == new C(3) assert(c2.x == 3); } @safe pure unittest { struct S { class A { this(B b) @safe pure {} } class B : A { this() @safe pure { super(this); } } } S.B b = new S.B(); S.A a = to!(S.A)(b); // == cast(S.A)b // (do not run construction conversion like new S.A(b)) assert(b is a); static class C : Object { this() @safe pure {} this(Object o) @safe pure {} } Object oc = new C(); C a2 = to!C(oc); // == new C(a) // Construction conversion overrides down-casting conversion assert(a2 !is a); // } /** Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null. */ T toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) && (is(S == class) || is(S == interface)) && !is(typeof(value.opCast!T()) : T) && (is(T == class) || is(T == interface)) && !is(typeof(new T(value)))) { static if (is(T == immutable)) { // immutable <- immutable enum isModConvertible = is(S == immutable); } else static if (is(T == const)) { static if (is(T == shared)) { // shared const <- shared // shared const <- shared const // shared const <- immutable enum isModConvertible = is(S == shared) || is(S == immutable); } else { // const <- mutable // const <- immutable enum isModConvertible = !is(S == shared); } } else { static if (is(T == shared)) { // shared <- shared mutable enum isModConvertible = is(S == shared) && !is(S == const); } else { // (mutable) <- (mutable) enum isModConvertible = is(Unqual!S == S); } } static assert(isModConvertible, "Bad modifier conversion: "~S.stringof~" to "~T.stringof); auto result = ()@trusted{ return cast(T) value; }(); if (!result && value) { throw new ConvException("Cannot convert object of static type " ~S.classinfo.name~" and dynamic type "~value.classinfo.name ~" to type "~T.classinfo.name); } return result; } @safe pure unittest { import std.exception; // Testing object conversions class A {} class B : A {} class C : A {} A a1 = new A, a2 = new B, a3 = new C; assert(to!B(a2) is a2); assert(to!C(a3) is a3); assertThrown!ConvException(to!B(a3)); } // Unittest for 6288 @safe pure unittest { import std.exception; alias Identity(T) = T; alias toConst(T) = const T; alias toShared(T) = shared T; alias toSharedConst(T) = shared const T; alias toImmutable(T) = immutable T; template AddModifier(int n) if (0 <= n && n < 5) { static if (n == 0) alias AddModifier = Identity; else static if (n == 1) alias AddModifier = toConst; else static if (n == 2) alias AddModifier = toShared; else static if (n == 3) alias AddModifier = toSharedConst; else static if (n == 4) alias AddModifier = toImmutable; } interface I {} interface J {} class A {} class B : A {} class C : B, I, J {} class D : I {} foreach (m1; AliasSeq!(0,1,2,3,4)) // enumerate modifiers foreach (m2; AliasSeq!(0,1,2,3,4)) // ditto (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 alias srcmod = AddModifier!m1; alias tgtmod = AddModifier!m2; //pragma(msg, srcmod!Object, " -> ", tgtmod!Object, ", convertible = ", // isImplicitlyConvertible!(srcmod!Object, tgtmod!Object)); // Compile time convertible equals to modifier convertible. static if (isImplicitlyConvertible!(srcmod!Object, tgtmod!Object)) { // Test runtime conversions: class to class, class to interface, // interface to class, and interface to interface // Check that the runtime conversion to succeed srcmod!A ac = new srcmod!C(); srcmod!I ic = new srcmod!C(); assert(to!(tgtmod!C)(ac) !is null); // A(c) to C assert(to!(tgtmod!I)(ac) !is null); // A(c) to I assert(to!(tgtmod!C)(ic) !is null); // I(c) to C assert(to!(tgtmod!J)(ic) !is null); // I(c) to J // Check that the runtime conversion fails srcmod!A ab = new srcmod!B(); srcmod!I id = new srcmod!D(); assertThrown(to!(tgtmod!C)(ab)); // A(b) to C assertThrown(to!(tgtmod!I)(ab)); // A(b) to I assertThrown(to!(tgtmod!C)(id)); // I(d) to C assertThrown(to!(tgtmod!J)(id)); // I(d) to J } else { // Check that the conversion is rejected statically static assert(!is(typeof(to!(tgtmod!C)(srcmod!A.init)))); // A to C static assert(!is(typeof(to!(tgtmod!I)(srcmod!A.init)))); // A to I static assert(!is(typeof(to!(tgtmod!C)(srcmod!I.init)))); // I to C static assert(!is(typeof(to!(tgtmod!J)(srcmod!I.init)))); // I to J } }(); } /** Stringize conversion from all types is supported. $(UL $(LI String _to string conversion works for any two string types having ($(D char), $(D wchar), $(D dchar)) character widths and any combination of qualifiers (mutable, $(D const), or $(D immutable)).) $(LI Converts array (other than strings) to string. Each element is converted by calling $(D to!T).) $(LI Associative array to string conversion. Each element is printed by calling $(D to!T).) $(LI Object to string conversion calls $(D toString) against the object or returns $(D "null") if the object is null.) $(LI Struct to string conversion calls $(D toString) against the struct if it is defined.) $(LI For structs that do not define $(D toString), the conversion to string produces the list of fields.) $(LI Enumerated types are converted to strings as their symbolic names.) $(LI Boolean values are printed as $(D "true") or $(D "false").) $(LI $(D char), $(D wchar), $(D dchar) to a string type.) $(LI Unsigned or signed integers to strings. $(DL $(DT [special case]) $(DD Convert integral value to string in $(D_PARAM radix) radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the $(D_PARAM letterCase) parameter.))) $(LI All floating point types to all string types.) $(LI Pointer to string conversions prints the pointer as a $(D size_t) value. If pointer is $(D char*), treat it as C-style strings. In that case, this function is $(D @system).)) */ T toImpl(T, S)(S value) if (!(isImplicitlyConvertible!(S, T) && !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) && !isInfinite!S && isExactSomeString!T) { static if (isExactSomeString!S && value[0].sizeof == ElementEncodingType!T.sizeof) { // string-to-string with incompatible qualifier conversion static if (is(ElementEncodingType!T == immutable)) { // conversion (mutable|const) -> immutable return value.idup; } else { // conversion (immutable|const) -> mutable return value.dup; } } else static if (isExactSomeString!S) { import std.array : appender; // other string-to-string //Use Appender directly instead of toStr, which also uses a formatedWrite auto w = appender!T(); w.put(value); return w.data; } else static if (isIntegral!S && !is(S == enum)) { // other integral-to-string conversions with default radix return toImpl!(T, S)(value, 10); } else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[])) { import core.stdc.string : memcpy; import std.exception : enforce; // Converting void array to string alias Char = Unqual!(ElementEncodingType!T); auto raw = cast(const(ubyte)[]) value; enforce(raw.length % Char.sizeof == 0, new ConvException("Alignment mismatch in converting a " ~ S.stringof ~ " to a " ~ T.stringof)); auto result = new Char[raw.length / Char.sizeof]; ()@trusted{ memcpy(result.ptr, value.ptr, value.length); }(); return cast(T) result; } else static if (isPointer!S && is(S : const(char)*)) { import core.stdc.string : strlen; // It is unsafe because we cannot guarantee that the pointer is null terminated. return value ? cast(T) value[0 .. strlen(value)].dup : null; } else static if (isSomeString!T && is(S == enum)) { static if (isSwitchable!(OriginalType!S) && EnumMembers!S.length <= 50) { switch(value) { foreach (member; NoDuplicates!(EnumMembers!S)) { case member: return to!T(enumRep!(immutable(T), S, member)); } default: } } else { foreach (member; EnumMembers!S) { if (value == member) return to!T(enumRep!(immutable(T), S, member)); } } import std.format : FormatSpec, formatValue; import std.array : appender; //Default case, delegate to format //Note: we don't call toStr directly, to avoid duplicate work. auto app = appender!T(); app.put("cast("); app.put(S.stringof); app.put(')'); FormatSpec!char f; formatValue(app, cast(OriginalType!S)value, f); return app.data; } else { // other non-string values runs formatting return toStr!T(value); } } // Bugzilla 14042 unittest { immutable(char)* ptr = "hello".ptr; auto result = ptr.to!(char[]); } /* Check whether type $(D T) can be used in a switch statement. This is useful for compile-time generation of switch case statements. */ private template isSwitchable(E) { enum bool isSwitchable = is(typeof({ switch (E.init) { default: } })); } // unittest { static assert(isSwitchable!int); static assert(!isSwitchable!double); static assert(!isSwitchable!real); } //Static representation of the index I of the enum S, //In representation T. //T must be an immutable string (avoids un-necessary initializations). private template enumRep(T, S, S value) if (is (T == immutable) && isExactSomeString!T && is(S == enum)) { static T enumRep = toStr!T(value); } @safe pure unittest { import std.exception; void dg() { // string to string conversion alias Chars = AliasSeq!(char, wchar, dchar); foreach (LhsC; Chars) { alias LhStrings = AliasSeq!(LhsC[], const(LhsC)[], immutable(LhsC)[]); foreach (Lhs; LhStrings) { foreach (RhsC; Chars) { alias RhStrings = AliasSeq!(RhsC[], const(RhsC)[], immutable(RhsC)[]); foreach (Rhs; RhStrings) { Lhs s1 = to!Lhs("wyda"); Rhs s2 = to!Rhs(s1); //writeln(Lhs.stringof, " -> ", Rhs.stringof); assert(s1 == to!Lhs(s2)); } } } } foreach (T; Chars) { foreach (U; Chars) { T[] s1 = to!(T[])("Hello, world!"); auto s2 = to!(U[])(s1); assert(s1 == to!(T[])(s2)); auto s3 = to!(const(U)[])(s1); assert(s1 == to!(T[])(s3)); auto s4 = to!(immutable(U)[])(s1); assert(s1 == to!(T[])(s4)); } } } dg(); assertCTFEable!dg; } @safe pure unittest { // Conversion reinterpreting void array to string auto a = "abcx"w; const(void)[] b = a; assert(b.length == 8); auto c = to!(wchar[])(b); assert(c == "abcx"); } @system pure nothrow unittest { // char* to string conversion assert(to!string(cast(char*) null) == ""); assert(to!string("foo\0".ptr) == "foo"); } @safe pure /+nothrow+/ unittest { // Conversion representing bool value with string bool b; assert(to!string(b) == "false"); b = true; assert(to!string(b) == "true"); } @safe pure unittest { // Conversion representing character value with string alias AllChars = AliasSeq!( char, const( char), immutable( char), wchar, const(wchar), immutable(wchar), dchar, const(dchar), immutable(dchar)); foreach (Char1; AllChars) { foreach (Char2; AllChars) { Char1 c = 'a'; assert(to!(Char2[])(c)[0] == c); } uint x = 4; assert(to!(Char1[])(x) == "4"); } string s = "foo"; string s2; foreach (char c; s) { s2 ~= to!string(c); } //printf("%.*s", s2); assert(s2 == "foo"); } @safe pure nothrow unittest { import std.exception; // Conversion representing integer values with string foreach (Int; AliasSeq!(ubyte, ushort, uint, ulong)) { assert(to!string(Int(0)) == "0"); assert(to!string(Int(9)) == "9"); assert(to!string(Int(123)) == "123"); } foreach (Int; AliasSeq!(byte, short, int, long)) { assert(to!string(Int(0)) == "0"); assert(to!string(Int(9)) == "9"); assert(to!string(Int(123)) == "123"); assert(to!string(Int(-0)) == "0"); assert(to!string(Int(-9)) == "-9"); assert(to!string(Int(-123)) == "-123"); assert(to!string(const(Int)(6)) == "6"); } assert(wtext(int.max) == "2147483647"w); assert(wtext(int.min) == "-2147483648"w); assert(to!string(0L) == "0"); assertCTFEable!( { assert(to!string(1uL << 62) == "4611686018427387904"); assert(to!string(0x100000000) == "4294967296"); assert(to!string(-138L) == "-138"); }); } @safe pure /+nothrow+/ unittest { // Conversion representing dynamic/static array with string long[] b = [ 1, 3, 5 ]; auto s = to!string(b); assert(to!string(b) == "[1, 3, 5]", s); } /*@safe pure */unittest // sprintf issue { double[2] a = [ 1.5, 2.5 ]; assert(to!string(a) == "[1.5, 2.5]"); } /*@safe pure */unittest { // Conversion representing associative array with string int[string] a = ["0":1, "1":2]; assert(to!string(a) == `["0":1, "1":2]` || to!string(a) == `["1":2, "0":1]`); } unittest { // Conversion representing class object with string class A { override string toString() const { return "an A"; } } A a; assert(to!string(a) == "null"); a = new A; assert(to!string(a) == "an A"); // Bug 7660 class C { override string toString() const { return "C"; } } struct S { C c; alias c this; } S s; s.c = new C(); assert(to!string(s) == "C"); } unittest { // Conversion representing struct object with string struct S1 { string toString() { return "wyda"; } } assert(to!string(S1()) == "wyda"); struct S2 { int a = 42; float b = 43.5; } S2 s2; assert(to!string(s2) == "S2(42, 43.5)"); // Test for issue 8080 struct S8080 { short[4] data; alias data this; string toString() { return ""; } } S8080 s8080; assert(to!string(s8080) == ""); } /+nothrow+/ unittest { // Conversion representing enum value with string enum EB : bool { a = true } enum EU : uint { a = 0, b = 1, c = 2 } // base type is unsigned enum EI : int { a = -1, b = 0, c = 1 } // base type is signed (bug 7909) enum EF : real { a = 1.414, b = 1.732, c = 2.236 } enum EC : char { a = 'x', b = 'y' } enum ES : string { a = "aaa", b = "bbb" } foreach (E; AliasSeq!(EB, EU, EI, EF, EC, ES)) { assert(to! string(E.a) == "a"c); assert(to!wstring(E.a) == "a"w); assert(to!dstring(E.a) == "a"d); } // Test an value not corresponding to an enum member. auto o = cast(EU)5; assert(to! string(o) == "cast(EU)5"c); assert(to!wstring(o) == "cast(EU)5"w); assert(to!dstring(o) == "cast(EU)5"d); } unittest { enum E { foo, doo = foo, // check duplicate switch statements bar, } //Test regression 12494 assert(to!string(E.foo) == "foo"); assert(to!string(E.doo) == "foo"); assert(to!string(E.bar) == "bar"); foreach (S; AliasSeq!(string, wstring, dstring, const(char[]), const(wchar[]), const(dchar[]))) { auto s1 = to!S(E.foo); auto s2 = to!S(E.foo); assert(s1 == s2); // ensure we don't allocate when it's unnecessary assert(s1 is s2); } foreach (S; AliasSeq!(char[], wchar[], dchar[])) { auto s1 = to!S(E.foo); auto s2 = to!S(E.foo); assert(s1 == s2); // ensure each mutable array is unique assert(s1 !is s2); } } /// ditto @trusted pure T toImpl(T, S)(S value, uint radix, LetterCase letterCase = LetterCase.upper) if (isIntegral!S && isExactSomeString!T) in { assert(radix >= 2 && radix <= 36); } body { alias EEType = Unqual!(ElementEncodingType!T); T toStringRadixConvert(size_t bufLen)(uint runtimeRadix = 0) { Unsigned!(Unqual!S) div = void, mValue = unsigned(value); size_t index = bufLen; EEType[bufLen] buffer = void; char baseChar = letterCase == LetterCase.lower ? 'a' : 'A'; char mod = void; do { div = cast(S)(mValue / runtimeRadix ); mod = cast(ubyte)(mValue % runtimeRadix); mod += mod < 10 ? '0' : baseChar - 10; buffer[--index] = cast(char)mod; mValue = div; } while (mValue); return cast(T)buffer[index .. $].dup; } import std.array; switch(radix) { case 10: // The (value+0) is so integral promotions happen to the type return toChars!(10, EEType)(value + 0).array; case 16: // The unsigned(unsigned(value)+0) is so unsigned integral promotions happen to the type if (letterCase == letterCase.upper) return toChars!(16, EEType, LetterCase.upper)(unsigned(unsigned(value) + 0)).array; else return toChars!(16, EEType, LetterCase.lower)(unsigned(unsigned(value) + 0)).array; case 2: return toChars!(2, EEType)(unsigned(unsigned(value) + 0)).array; case 8: return toChars!(8, EEType)(unsigned(unsigned(value) + 0)).array; default: return toStringRadixConvert!(S.sizeof * 6)(radix); } } @safe pure nothrow unittest { foreach (Int; AliasSeq!(uint, ulong)) { assert(to!string(Int(16), 16) == "10"); assert(to!string(Int(15), 2u) == "1111"); assert(to!string(Int(1), 2u) == "1"); assert(to!string(Int(0x1234AF), 16u) == "1234AF"); assert(to!string(Int(0x1234BCD), 16u, LetterCase.upper) == "1234BCD"); assert(to!string(Int(0x1234AF), 16u, LetterCase.lower) == "1234af"); } foreach (Int; AliasSeq!(int, long)) { assert(to!string(Int(-10), 10u) == "-10"); } assert(to!string(byte(-10), 16) == "F6"); assert(to!string(long.min) == "-9223372036854775808"); assert(to!string(long.max) == "9223372036854775807"); } /** Narrowing numeric-numeric conversions throw when the value does not fit in the narrower type. */ T toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) && (isNumeric!S || isSomeChar!S || isBoolean!S) && (isNumeric!T || isSomeChar!T || isBoolean!T) && !is(T == enum)) { enum sSmallest = mostNegative!S; enum tSmallest = mostNegative!T; static if (sSmallest < 0) { // possible underflow converting from a signed static if (tSmallest == 0) { immutable good = value >= 0; } else { static assert(tSmallest < 0); immutable good = value >= tSmallest; } if (!good) throw new ConvOverflowException("Conversion negative overflow"); } static if (S.max > T.max) { // possible overflow if (value > T.max) throw new ConvOverflowException("Conversion positive overflow"); } return (ref value)@trusted{ return cast(T) value; }(value); } @safe pure unittest { import std.exception; dchar a = ' '; assert(to!char(a) == ' '); a = 300; assert(collectException(to!char(a))); dchar from0 = 'A'; char to0 = to!char(from0); wchar from1 = 'A'; char to1 = to!char(from1); char from2 = 'A'; char to2 = to!char(from2); char from3 = 'A'; wchar to3 = to!wchar(from3); char from4 = 'A'; dchar to4 = to!dchar(from4); } unittest { import std.exception; // Narrowing conversions from enum -> integral should be allowed, but they // should throw at runtime if the enum value doesn't fit in the target // type. enum E1 : ulong { A = 1, B = 1UL<<48, C = 0 } assert(to!int(E1.A) == 1); assert(to!bool(E1.A) == true); assertThrown!ConvOverflowException(to!int(E1.B)); // E1.B overflows int assertThrown!ConvOverflowException(to!bool(E1.B)); // E1.B overflows bool assert(to!bool(E1.C) == false); enum E2 : long { A = -1L<<48, B = -1<<31, C = 1<<31 } assertThrown!ConvOverflowException(to!int(E2.A)); // E2.A overflows int assertThrown!ConvOverflowException(to!uint(E2.B)); // E2.B overflows uint assert(to!int(E2.B) == -1<<31); // but does not overflow int assert(to!int(E2.C) == 1<<31); // E2.C does not overflow int enum E3 : int { A = -1, B = 1, C = 255, D = 0 } assertThrown!ConvOverflowException(to!ubyte(E3.A)); assertThrown!ConvOverflowException(to!bool(E3.A)); assert(to!byte(E3.A) == -1); assert(to!byte(E3.B) == 1); assert(to!ubyte(E3.C) == 255); assert(to!bool(E3.B) == true); assertThrown!ConvOverflowException(to!byte(E3.C)); assertThrown!ConvOverflowException(to!bool(E3.C)); assert(to!bool(E3.D) == false); } /** Array-to-array conversion (except when target is a string type) converts each element in turn by using $(D to). */ T toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) && !isSomeString!S && isDynamicArray!S && !isExactSomeString!T && isArray!T) { alias E = typeof(T.init[0]); static if (isStaticArray!T) { import std.exception : enforce; auto res = to!(E[])(value); enforce!ConvException(T.length == res.length, convFormat("Length mismatch when converting to static array: %s vs %s", T.length, res.length)); return res[0 .. T.length]; } else { import std.array : appender; auto w = appender!(E[])(); w.reserve(value.length); foreach (i, ref e; value) { w.put(to!E(e)); } return w.data; } } @safe pure unittest { import std.exception; // array to array conversions uint[] a = [ 1u, 2, 3 ]; auto b = to!(float[])(a); assert(b == [ 1.0f, 2, 3 ]); //auto c = to!(string[])(b); //assert(c[0] == "1" && c[1] == "2" && c[2] == "3"); immutable(int)[3] d = [ 1, 2, 3 ]; b = to!(float[])(d); assert(b == [ 1.0f, 2, 3 ]); uint[][] e = [ a, a ]; auto f = to!(float[][])(e); assert(f[0] == b && f[1] == b); // Test for bug 8264 struct Wrap { string wrap; alias wrap this; } Wrap[] warr = to!(Wrap[])(["foo", "bar"]); // should work // Issue 12633 import std.conv : to; const s2 = ["10", "20"]; immutable int[2] a3 = s2.to!(int[2]); assert(a3 == [10, 20]); // verify length mismatches are caught immutable s4 = [1, 2, 3, 4]; foreach (i; [1, 4]) { auto ex = collectException(s4[0 .. i].to!(int[2])); assert(ex && ex.msg == "Length mismatch when converting to static array: 2 vs " ~ [cast(char)(i + '0')], ex ? ex.msg : "Exception was not thrown!"); } } /*@safe pure */unittest { auto b = [ 1.0f, 2, 3 ]; auto c = to!(string[])(b); assert(c[0] == "1" && c[1] == "2" && c[2] == "3"); } /** Associative array to associative array conversion converts each key and each value in turn. */ T toImpl(T, S)(S value) if (isAssociativeArray!S && isAssociativeArray!T && !is(T == enum)) { /* This code is potentially unsafe. */ alias K2 = KeyType!T; alias V2 = ValueType!T; // While we are "building" the AA, we need to unqualify its values, and only re-qualify at the end Unqual!V2[K2] result; foreach (k1, v1; value) { // Cast values temporarily to Unqual!V2 to store them to result variable result[to!K2(k1)] = cast(Unqual!V2) to!V2(v1); } // Cast back to original type return cast(T)result; } @safe /*pure */unittest { // hash to hash conversions int[string] a; a["0"] = 1; a["1"] = 2; auto b = to!(double[dstring])(a); assert(b["0"d] == 1 && b["1"d] == 2); } @safe /*pure */unittest // Bugzilla 8705, from doc { import std.exception; int[string][double[int[]]] a; auto b = to!(short[wstring][string[double[]]])(a); a = [null:["hello":int.max]]; assertThrown!ConvOverflowException(to!(short[wstring][string[double[]]])(a)); } unittest // Extra cases for AA with qualifiers conversion { int[][int[]] a;// = [[], []]; auto b = to!(immutable(short[])[immutable short[]])(a); double[dstring][int[long[]]] c; auto d = to!(immutable(short[immutable wstring])[immutable string[double[]]])(c); } private void testIntegralToFloating(Integral, Floating)() { Integral a = 42; auto b = to!Floating(a); assert(a == b); assert(a == to!Integral(b)); } private void testFloatingToIntegral(Floating, Integral)() { bool convFails(Source, Target, E)(Source src) { try auto t = to!Target(src); catch (E) return true; return false; } // convert some value Floating a = 4.2e1; auto b = to!Integral(a); assert(is(typeof(b) == Integral) && b == 42); // convert some negative value (if applicable) a = -4.2e1; static if (Integral.min < 0) { b = to!Integral(a); assert(is(typeof(b) == Integral) && b == -42); } else { // no go for unsigned types assert(convFails!(Floating, Integral, ConvOverflowException)(a)); } // convert to the smallest integral value a = 0.0 + Integral.min; static if (Integral.min < 0) { a = -a; // -Integral.min not representable as an Integral assert(convFails!(Floating, Integral, ConvOverflowException)(a) || Floating.sizeof <= Integral.sizeof); } a = 0.0 + Integral.min; assert(to!Integral(a) == Integral.min); --a; // no more representable as an Integral assert(convFails!(Floating, Integral, ConvOverflowException)(a) || Floating.sizeof <= Integral.sizeof); a = 0.0 + Integral.max; // fwritefln(stderr, "%s a=%g, %s conv=%s", Floating.stringof, a, // Integral.stringof, to!Integral(a)); assert(to!Integral(a) == Integral.max || Floating.sizeof <= Integral.sizeof); ++a; // no more representable as an Integral assert(convFails!(Floating, Integral, ConvOverflowException)(a) || Floating.sizeof <= Integral.sizeof); // convert a value with a fractional part a = 3.14; assert(to!Integral(a) == 3); a = 3.99; assert(to!Integral(a) == 3); static if (Integral.min < 0) { a = -3.14; assert(to!Integral(a) == -3); a = -3.99; assert(to!Integral(a) == -3); } } @safe pure unittest { alias AllInts = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong); alias AllFloats = AliasSeq!(float, double, real); alias AllNumerics = AliasSeq!(AllInts, AllFloats); // test with same type { foreach (T; AllNumerics) { T a = 42; auto b = to!T(a); assert(is(typeof(a) == typeof(b)) && a == b); } } // test that floating-point numbers convert properly to largest ints // see http://oregonstate.edu/~peterseb/mth351/docs/351s2001_fp80x87.html // look for "largest fp integer with a predecessor" { // float int a = 16_777_215; // 2^24 - 1 assert(to!int(to!float(a)) == a); assert(to!int(to!float(-a)) == -a); // double long b = 9_007_199_254_740_991; // 2^53 - 1 assert(to!long(to!double(b)) == b); assert(to!long(to!double(-b)) == -b); // real // @@@ BUG IN COMPILER @@@ // ulong c = 18_446_744_073_709_551_615UL; // 2^64 - 1 // assert(to!ulong(to!real(c)) == c); // assert(to!ulong(-to!real(c)) == c); } // test conversions floating => integral { // AllInts[0 .. $ - 1] should be AllInts // @@@ BUG IN COMPILER @@@ foreach (Integral; AllInts[0 .. $ - 1]) { foreach (Floating; AllFloats) { testFloatingToIntegral!(Floating, Integral)(); } } } // test conversion integral => floating { foreach (Integral; AllInts[0 .. $ - 1]) { foreach (Floating; AllFloats) { testIntegralToFloating!(Integral, Floating)(); } } } // test parsing { foreach (T; AllNumerics) { // from type immutable(char)[2] auto a = to!T("42"); assert(a == 42); // from type char[] char[] s1 = "42".dup; a = to!T(s1); assert(a == 42); // from type char[2] char[2] s2; s2[] = "42"; a = to!T(s2); assert(a == 42); // from type immutable(wchar)[2] a = to!T("42"w); assert(a == 42); } } } /*@safe pure */unittest { alias AllInts = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong); alias AllFloats = AliasSeq!(float, double, real); alias AllNumerics = AliasSeq!(AllInts, AllFloats); // test conversions to string { foreach (T; AllNumerics) { T a = 42; assert(to!string(a) == "42"); //assert(to!wstring(a) == "42"w); //assert(to!dstring(a) == "42"d); // array test // T[] b = new T[2]; // b[0] = 42; // b[1] = 33; // assert(to!string(b) == "[42,33]"); } } // test array to string conversion foreach (T ; AllNumerics) { auto a = [to!T(1), 2, 3]; assert(to!string(a) == "[1, 2, 3]"); } // test enum to int conversion // enum Testing { Test1, Test2 }; // Testing t; // auto a = to!string(t); // assert(a == "0"); } /** String to non-string conversion runs parsing. $(UL $(LI When the source is a wide string, it is first converted to a narrow string and then parsed.) $(LI When the source is a narrow string, normal text parsing occurs.)) */ T toImpl(T, S)(S value) if ( isExactSomeString!S && isDynamicArray!S && !isExactSomeString!T && is(typeof(parse!T(value)))) { scope(success) { if (value.length) { throw convError!(S, T)(value); } } return parse!T(value); } /// ditto T toImpl(T, S)(S value, uint radix) if ( isExactSomeString!S && isDynamicArray!S && !isExactSomeString!T && is(typeof(parse!T(value, radix)))) { scope(success) { if (value.length) { throw convError!(S, T)(value); } } return parse!T(value, radix); } @safe pure unittest { // Issue 6668 - ensure no collaterals thrown try { to!uint("-1"); } catch (ConvException e) { assert(e.next is null); } } @safe pure unittest { foreach (Str; AliasSeq!(string, wstring, dstring)) { Str a = "123"; assert(to!int(a) == 123); assert(to!double(a) == 123); } // 6255 auto n = to!int("FF", 16); assert(n == 255); } /** Convert a value that is implicitly convertible to the enum base type into an Enum value. If the value does not match any enum member values a ConvException is thrown. Enums with floating-point or string base types are not supported. */ T toImpl(T, S)(S value) if (is(T == enum) && !is(S == enum) && is(typeof(value == OriginalType!T.init)) && !isFloatingPoint!(OriginalType!T) && !isSomeString!(OriginalType!T)) { foreach (Member; EnumMembers!T) { if (Member == value) return Member; } throw new ConvException(convFormat("Value (%s) does not match any member value of enum '%s'", value, T.stringof)); } @safe pure unittest { import std.exception; enum En8143 : int { A = 10, B = 20, C = 30, D = 20 } enum En8143[][] m3 = to!(En8143[][])([[10, 30], [30, 10]]); static assert(m3 == [[En8143.A, En8143.C], [En8143.C, En8143.A]]); En8143 en1 = to!En8143(10); assert(en1 == En8143.A); assertThrown!ConvException(to!En8143(5)); // matches none En8143[][] m1 = to!(En8143[][])([[10, 30], [30, 10]]); assert(m1 == [[En8143.A, En8143.C], [En8143.C, En8143.A]]); } /*************************************************************** Rounded conversion from floating point to integral. Rounded conversions do not work with non-integral target types. */ template roundTo(Target) { Target roundTo(Source)(Source value) { import std.math : trunc; static assert(isFloatingPoint!Source); static assert(isIntegral!Target); return to!Target(trunc(value + (value < 0 ? -0.5L : 0.5L))); } } /// unittest { assert(roundTo!int(3.14) == 3); assert(roundTo!int(3.49) == 3); assert(roundTo!int(3.5) == 4); assert(roundTo!int(3.999) == 4); assert(roundTo!int(-3.14) == -3); assert(roundTo!int(-3.49) == -3); assert(roundTo!int(-3.5) == -4); assert(roundTo!int(-3.999) == -4); assert(roundTo!(const int)(to!(const double)(-3.999)) == -4); } unittest { import std.exception; // boundary values foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint)) { assert(roundTo!Int(Int.min - 0.4L) == Int.min); assert(roundTo!Int(Int.max + 0.4L) == Int.max); assertThrown!ConvOverflowException(roundTo!Int(Int.min - 0.5L)); assertThrown!ConvOverflowException(roundTo!Int(Int.max + 0.5L)); } } /** The $(D parse) family of functions works quite like the $(D to) family, except that: $(OL $(LI It only works with character ranges as input.) $(LI It takes the input by reference. (This means that rvalues - such as string literals - are not accepted: use $(D to) instead.)) $(LI It advances the input to the position following the conversion.) $(LI It does not throw if it could not convert the entire input.)) It still throws if an overflow occurred during conversion or if no character of the input was meaningfully converted. */ Target parse(Target, Source)(ref Source s) if (isInputRange!Source && isSomeChar!(ElementType!Source) && is(Unqual!Target == bool)) { import std.ascii : toLower; if (!s.empty) { auto c1 = toLower(s.front); bool result = (c1 == 't'); if (result || c1 == 'f') { s.popFront(); foreach (c; result ? "rue" : "alse") { if (s.empty || toLower(s.front) != c) goto Lerr; s.popFront(); } return result; } } Lerr: throw parseError("bool should be case-insensitive 'true' or 'false'"); } /// unittest { import std.string : munch; string test = "123 \t 76.14"; auto a = parse!uint(test); assert(a == 123); assert(test == " \t 76.14"); // parse bumps string munch(test, " \t\n\r"); // skip ws assert(test == "76.14"); auto b = parse!double(test); assert(b == 76.14); assert(test == ""); } unittest { import std.exception; import std.algorithm : equal; struct InputString { string _s; @property auto front() { return _s.front; } @property bool empty() { return _s.empty; } void popFront() { _s.popFront(); } } auto s = InputString("trueFALSETrueFalsetRUEfALSE"); assert(parse!bool(s) == true); assert(s.equal("FALSETrueFalsetRUEfALSE")); assert(parse!bool(s) == false); assert(s.equal("TrueFalsetRUEfALSE")); assert(parse!bool(s) == true); assert(s.equal("FalsetRUEfALSE")); assert(parse!bool(s) == false); assert(s.equal("tRUEfALSE")); assert(parse!bool(s) == true); assert(s.equal("fALSE")); assert(parse!bool(s) == false); assert(s.empty); foreach (ss; ["tfalse", "ftrue", "t", "f", "tru", "fals", ""]) { s = InputString(ss); assertThrown!ConvException(parse!bool(s)); } } Target parse(Target, Source)(ref Source s) if (isSomeChar!(ElementType!Source) && isIntegral!Target && !is(Target == enum)) { static if (Target.sizeof < int.sizeof) { // smaller types are handled like integers auto v = .parse!(Select!(Target.min < 0, int, uint))(s); auto result = ()@trusted{ return cast(Target) v; }(); if (result == v) return result; throw new ConvOverflowException("Overflow in integral conversion"); } else { // int or larger types static if (Target.min < 0) bool sign = 0; else enum bool sign = 0; enum char maxLastDigit = Target.min < 0 ? 7 : 5; Unqual!(typeof(s.front)) c; if (s.empty) goto Lerr; c = s.front; static if (Target.min < 0) { switch (c) { case '-': sign = true; goto case '+'; case '+': s.popFront(); if (s.empty) goto Lerr; c = s.front; break; default: break; } } c -= '0'; if (c <= 9) { Target v = cast(Target)c; s.popFront(); while (!s.empty) { c = cast(typeof(c)) (s.front - '0'); if (c > 9) break; if (v >= 0 && (v < Target.max/10 || (v == Target.max/10 && c <= maxLastDigit + sign))) { // Note: `v` can become negative here in case of parsing // the most negative value: v = cast(Target) (v * 10 + c); s.popFront(); } else throw new ConvOverflowException("Overflow in integral conversion"); } if (sign) v = -v; return v; } Lerr: throw convError!(Source, Target)(s); } } @safe pure unittest { string s = "123"; auto a = parse!int(s); } @safe pure unittest { foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) { { assert(to!Int("0") == 0); static if (isSigned!Int) { assert(to!Int("+0") == 0); assert(to!Int("-0") == 0); } } static if (Int.sizeof >= byte.sizeof) { assert(to!Int("6") == 6); assert(to!Int("23") == 23); assert(to!Int("68") == 68); assert(to!Int("127") == 0x7F); static if (isUnsigned!Int) { assert(to!Int("255") == 0xFF); } static if (isSigned!Int) { assert(to!Int("+6") == 6); assert(to!Int("+23") == 23); assert(to!Int("+68") == 68); assert(to!Int("+127") == 0x7F); assert(to!Int("-6") == -6); assert(to!Int("-23") == -23); assert(to!Int("-68") == -68); assert(to!Int("-128") == -128); } } static if (Int.sizeof >= short.sizeof) { assert(to!Int("468") == 468); assert(to!Int("32767") == 0x7FFF); static if (isUnsigned!Int) { assert(to!Int("65535") == 0xFFFF); } static if (isSigned!Int) { assert(to!Int("+468") == 468); assert(to!Int("+32767") == 0x7FFF); assert(to!Int("-468") == -468); assert(to!Int("-32768") == -32768); } } static if (Int.sizeof >= int.sizeof) { assert(to!Int("2147483647") == 0x7FFFFFFF); static if (isUnsigned!Int) { assert(to!Int("4294967295") == 0xFFFFFFFF); } static if (isSigned!Int) { assert(to!Int("+2147483647") == 0x7FFFFFFF); assert(to!Int("-2147483648") == -2147483648); } } static if (Int.sizeof >= long.sizeof) { assert(to!Int("9223372036854775807") == 0x7FFFFFFFFFFFFFFF); static if (isUnsigned!Int) { assert(to!Int("18446744073709551615") == 0xFFFFFFFFFFFFFFFF); } static if (isSigned!Int) { assert(to!Int("+9223372036854775807") == 0x7FFFFFFFFFFFFFFF); assert(to!Int("-9223372036854775808") == 0x8000000000000000); } } } } @safe pure unittest { import std.exception; // parsing error check foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) { { immutable string[] errors1 = [ "", "-", "+", "-+", " ", " 0", "0 ", "- 0", "1-", "xx", "123h", "-+1", "--1", "+-1", "++1", ]; foreach (j, s; errors1) assertThrown!ConvException(to!Int(s)); } // parse!SomeUnsigned cannot parse head sign. static if (isUnsigned!Int) { immutable string[] errors2 = [ "+5", "-78", ]; foreach (j, s; errors2) assertThrown!ConvException(to!Int(s)); } } // positive overflow check foreach (i, Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) { immutable string[] errors = [ "128", // > byte.max "256", // > ubyte.max "32768", // > short.max "65536", // > ushort.max "2147483648", // > int.max "4294967296", // > uint.max "9223372036854775808", // > long.max "18446744073709551616", // > ulong.max ]; foreach (j, s; errors[i..$]) assertThrown!ConvOverflowException(to!Int(s)); } // negative overflow check foreach (i, Int; AliasSeq!(byte, short, int, long)) { immutable string[] errors = [ "-129", // < byte.min "-32769", // < short.min "-2147483649", // < int.min "-9223372036854775809", // < long.min ]; foreach (j, s; errors[i..$]) assertThrown!ConvOverflowException(to!Int(s)); } } @safe pure unittest { void checkErrMsg(string input, dchar charInMsg, dchar charNotInMsg) { try { int x = input.to!int(); assert(false, "Invalid conversion did not throw"); } catch(ConvException e) { // Ensure error message contains failing character, not the character // beyond. import std.algorithm.searching : canFind; assert( e.msg.canFind(charInMsg) && !e.msg.canFind(charNotInMsg)); } catch(Exception e) { assert(false, "Did not throw ConvException"); } } checkErrMsg("@$", '@', '$'); checkErrMsg("@$123", '@', '$'); checkErrMsg("1@$23", '@', '$'); checkErrMsg("1@$", '@', '$'); checkErrMsg("1@$2", '@', '$'); checkErrMsg("12@$", '@', '$'); } @safe pure unittest { import std.exception; assertCTFEable!({ string s = "1234abc"; assert(parse! int(s) == 1234 && s == "abc"); }); assertCTFEable!({ string s = "-1234abc"; assert(parse! int(s) == -1234 && s == "abc"); }); assertCTFEable!({ string s = "1234abc"; assert(parse!uint(s) == 1234 && s == "abc"); }); } // Issue 13931 @safe pure unittest { import std.exception; assertThrown!ConvOverflowException("-21474836480".to!int()); assertThrown!ConvOverflowException("-92233720368547758080".to!long()); } // Issue 14396 @safe pure unittest { struct StrInputRange { this (string s) { str = s; } char front() const @property { return str[front_index]; } char popFront() { return str[front_index++]; } bool empty() const @property { return str.length <= front_index; } string str; size_t front_index = 0; } auto input = StrInputRange("777"); assert(parse!int(input) == 777); } /// ditto Target parse(Target, Source)(ref Source s, uint radix) if (isSomeChar!(ElementType!Source) && isIntegral!Target && !is(Target == enum)) in { assert(radix >= 2 && radix <= 36); } body { import core.checkedint : mulu, addu; if (radix == 10) return parse!Target(s); immutable uint beyond = (radix < 10 ? '0' : 'a'-10) + radix; Target v = 0; bool atStart = true; for (; !s.empty; s.popFront()) { uint c = s.front; if (c < '0') break; if (radix < 10) { if (c >= beyond) break; } else { if (c > '9') { c |= 0x20;//poorman's tolower if (c < 'a' || c >= beyond) break; c -= 'a'-10-'0'; } } bool overflow = false; auto nextv = v.mulu(radix, overflow).addu(c - '0', overflow); if (overflow || nextv > Target.max) goto Loverflow; v = cast(Target) nextv; atStart = false; } if (atStart) goto Lerr; return v; Loverflow: throw new ConvOverflowException("Overflow in integral conversion"); Lerr: throw convError!(Source, Target)(s, radix); } @safe pure unittest { string s; // parse doesn't accept rvalues foreach (i; 2..37) { assert(parse!int(s = "0", i) == 0); assert(parse!int(s = "1", i) == 1); assert(parse!byte(s = "10", i) == i); } assert(parse!int(s = "0011001101101", 2) == 0b0011001101101); assert(parse!int(s = "765", 8) == octal!765); assert(parse!int(s = "fCDe", 16) == 0xfcde); // 6609 assert(parse!int(s = "-42", 10) == -42); } @safe pure unittest // bugzilla 7302 { import std.range : cycle; auto r = cycle("2A!"); auto u = parse!uint(r, 16); assert(u == 42); assert(r.front == '!'); } @safe pure unittest // bugzilla 13163 { import std.exception; foreach (s; ["fff", "123"]) assertThrown!ConvOverflowException(s.parse!ubyte(16)); } Target parse(Target, Source)(ref Source s) if (isExactSomeString!Source && is(Target == enum)) { import std.algorithm : startsWith; Target result; size_t longest_match = 0; foreach (i, e; EnumMembers!Target) { auto ident = __traits(allMembers, Target)[i]; if (longest_match < ident.length && s.startsWith(ident)) { result = e; longest_match = ident.length ; } } if (longest_match > 0) { s = s[longest_match .. $]; return result ; } throw new ConvException( Target.stringof ~ " does not have a member named '" ~ to!string(s) ~ "'"); } unittest { import std.exception; enum EB : bool { a = true, b = false, c = a } enum EU { a, b, c } enum EI { a = -1, b = 0, c = 1 } enum EF : real { a = 1.414, b = 1.732, c = 2.236 } enum EC : char { a = 'a', b = 'b', c = 'c' } enum ES : string { a = "aaa", b = "bbb", c = "ccc" } foreach (E; AliasSeq!(EB, EU, EI, EF, EC, ES)) { assert(to!E("a"c) == E.a); assert(to!E("b"w) == E.b); assert(to!E("c"d) == E.c); assertThrown!ConvException(to!E("d")); } } @safe pure unittest // bugzilla 4744 { enum A { member1, member11, member111 } assert(to!A("member1" ) == A.member1 ); assert(to!A("member11" ) == A.member11 ); assert(to!A("member111") == A.member111); auto s = "member1111"; assert(parse!A(s) == A.member111 && s == "1"); } Target parse(Target, Source)(ref Source p) if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) && isFloatingPoint!Target && !is(Target == enum)) { import std.ascii : isDigit, isAlpha, toLower, toUpper, isHexDigit; import std.exception : enforce; import core.stdc.math : HUGE_VAL; static immutable real[14] negtab = [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L, 1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ]; static immutable real[13] postab = [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L, 1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ]; // static immutable string infinity = "infinity"; // static immutable string nans = "nans"; ConvException bailOut()(string msg = null, string fn = __FILE__, size_t ln = __LINE__) { if (msg == null) msg = "Floating point conversion error"; return new ConvException(text(msg, " for input \"", p, "\"."), fn, ln); } enforce(!p.empty, bailOut()); char sign = 0; /* indicating + */ switch (p.front) { case '-': sign++; p.popFront(); enforce(!p.empty, bailOut()); if (toLower(p.front) == 'i') goto case 'i'; enforce(!p.empty, bailOut()); break; case '+': p.popFront(); enforce(!p.empty, bailOut()); break; case 'i': case 'I': p.popFront(); enforce(!p.empty, bailOut()); if (toLower(p.front) == 'n') { p.popFront(); enforce(!p.empty, bailOut()); if (toLower(p.front) == 'f') { // 'inf' p.popFront(); return sign ? -Target.infinity : Target.infinity; } } goto default; default: {} } bool isHex = false; bool startsWithZero = p.front == '0'; if(startsWithZero) { p.popFront(); if(p.empty) { return (sign) ? -0.0 : 0.0; } isHex = p.front == 'x' || p.front == 'X'; } real ldval = 0.0; char dot = 0; /* if decimal point has been seen */ int exp = 0; long msdec = 0, lsdec = 0; ulong msscale = 1; if (isHex) { int guard = 0; int anydigits = 0; uint ndigits = 0; p.popFront(); while (!p.empty) { int i = p.front; while (isHexDigit(i)) { anydigits = 1; i = isAlpha(i) ? ((i & ~0x20) - ('A' - 10)) : i - '0'; if (ndigits < 16) { msdec = msdec * 16 + i; if (msdec) ndigits++; } else if (ndigits == 16) { while (msdec >= 0) { exp--; msdec <<= 1; i <<= 1; if (i & 0x10) msdec |= 1; } guard = i << 4; ndigits++; exp += 4; } else { guard |= i; exp += 4; } exp -= dot; p.popFront(); if (p.empty) break; i = p.front; if (i == '_') { p.popFront(); if (p.empty) break; i = p.front; } } if (i == '.' && !dot) { p.popFront(); dot = 4; } else break; } // Round up if (guard && (sticky || odd)) if (guard & 0x80 && (guard & 0x7F || msdec & 1)) { msdec++; if (msdec == 0) // overflow { msdec = 0x8000000000000000L; exp++; } } enforce(anydigits, bailOut()); enforce(!p.empty && (p.front == 'p' || p.front == 'P'), bailOut("Floating point parsing: exponent is required")); char sexp; int e; sexp = 0; p.popFront(); if (!p.empty) { switch (p.front) { case '-': sexp++; goto case; case '+': p.popFront(); enforce(!p.empty, new ConvException("Error converting input"~ " to floating point")); break; default: {} } } ndigits = 0; e = 0; while (!p.empty && isDigit(p.front)) { if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow { e = e * 10 + p.front - '0'; } p.popFront(); ndigits = 1; } exp += (sexp) ? -e : e; enforce(ndigits, new ConvException("Error converting input"~ " to floating point")); static if (real.mant_dig == 64) { if (msdec) { int e2 = 0x3FFF + 63; // left justify mantissa while (msdec >= 0) { msdec <<= 1; e2--; } // Stuff mantissa directly into real ()@trusted{ *cast(long*)&ldval = msdec; }(); ()@trusted{ (cast(ushort*)&ldval)[4] = cast(ushort) e2; }(); import std.math : ldexp; // Exponent is power of 2, not power of 10 ldval = ldexp(ldval,exp); } } else static if (real.mant_dig == 53) { if (msdec) { //Exponent bias + 52: //After shifting 52 times left, exp must be 1 int e2 = 0x3FF + 52; // right justify mantissa // first 11 bits must be zero, rest is implied bit + mantissa // shift one time less, do rounding, shift again while ((msdec & 0xFFC0_0000_0000_0000) != 0) { msdec = ((cast(ulong)msdec) >> 1); e2++; } //Have to shift one more time //and do rounding if((msdec & 0xFFE0_0000_0000_0000) != 0) { auto roundUp = (msdec & 0x1); msdec = ((cast(ulong)msdec) >> 1); e2++; if(roundUp) { msdec += 1; //If mantissa was 0b1111... and we added +1 //the mantissa should be 0b10000 (think of implicit bit) //and the exponent increased if((msdec & 0x0020_0000_0000_0000) != 0) { msdec = 0x0010_0000_0000_0000; e2++; } } } // left justify mantissa // bit 11 must be 1 while ((msdec & 0x0010_0000_0000_0000) == 0) { msdec <<= 1; e2--; } // Stuff mantissa directly into double // (first including implicit bit) ()@trusted{ *cast(long *)&ldval = msdec; }(); //Store exponent, now overwriting implicit bit ()@trusted{ *cast(long *)&ldval &= 0x000F_FFFF_FFFF_FFFF; }(); ()@trusted{ *cast(long *)&ldval |= ((e2 & 0xFFFUL) << 52); }(); import std.math : ldexp; // Exponent is power of 2, not power of 10 ldval = ldexp(ldval,exp); } } else static assert(false, "Floating point format of real type not supported"); goto L6; } else // not hex { if (toUpper(p.front) == 'N' && !startsWithZero) { // nan p.popFront(); enforce(!p.empty && toUpper(p.front) == 'A', new ConvException("error converting input to floating point")); p.popFront(); enforce(!p.empty && toUpper(p.front) == 'N', new ConvException("error converting input to floating point")); // skip past the last 'n' p.popFront(); return typeof(return).nan; } bool sawDigits = startsWithZero; while (!p.empty) { int i = p.front; while (isDigit(i)) { sawDigits = true; /* must have at least 1 digit */ if (msdec < (0x7FFFFFFFFFFFL-10)/10) msdec = msdec * 10 + (i - '0'); else if (msscale < (0xFFFFFFFF-10)/10) { lsdec = lsdec * 10 + (i - '0'); msscale *= 10; } else { exp++; } exp -= dot; p.popFront(); if (p.empty) break; i = p.front; if (i == '_') { p.popFront(); if (p.empty) break; i = p.front; } } if (i == '.' && !dot) { p.popFront(); dot++; } else { break; } } enforce(sawDigits, new ConvException("no digits seen")); } if (!p.empty && (p.front == 'e' || p.front == 'E')) { char sexp; int e; sexp = 0; p.popFront(); enforce(!p.empty, new ConvException("Unexpected end of input")); switch (p.front) { case '-': sexp++; goto case; case '+': p.popFront(); break; default: {} } bool sawDigits = 0; e = 0; while (!p.empty && isDigit(p.front)) { if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow { e = e * 10 + p.front - '0'; } p.popFront(); sawDigits = 1; } exp += (sexp) ? -e : e; enforce(sawDigits, new ConvException("No digits seen.")); } ldval = msdec; if (msscale != 1) /* if stuff was accumulated in lsdec */ ldval = ldval * msscale + lsdec; if (ldval) { uint u = 0; int pow = 4096; while (exp > 0) { while (exp >= pow) { ldval *= postab[u]; exp -= pow; } pow >>= 1; u++; } while (exp < 0) { while (exp <= -pow) { ldval *= negtab[u]; enforce(ldval != 0, new ConvException("Range error")); exp += pow; } pow >>= 1; u++; } } L6: // if overflow occurred enforce(ldval != HUGE_VAL, new ConvException("Range error")); L1: return (sign) ? -ldval : ldval; } unittest { import std.exception; import std.math : isNaN, fabs; // Compare reals with given precision bool feq(in real rx, in real ry, in real precision = 0.000001L) { if (rx == ry) return 1; if (isNaN(rx)) return cast(bool)isNaN(ry); if (isNaN(ry)) return 0; return cast(bool)(fabs(rx - ry) <= precision); } // Make given typed literal F Literal(F)(F f) { return f; } foreach (Float; AliasSeq!(float, double, real)) { assert(to!Float("123") == Literal!Float(123)); assert(to!Float("+123") == Literal!Float(+123)); assert(to!Float("-123") == Literal!Float(-123)); assert(to!Float("123e2") == Literal!Float(123e2)); assert(to!Float("123e+2") == Literal!Float(123e+2)); assert(to!Float("123e-2") == Literal!Float(123e-2)); assert(to!Float("123.") == Literal!Float(123.0)); assert(to!Float(".375") == Literal!Float(.375)); assert(to!Float("1.23375E+2") == Literal!Float(1.23375E+2)); assert(to!Float("0") is 0.0); assert(to!Float("-0") is -0.0); assert(isNaN(to!Float("nan"))); assertThrown!ConvException(to!Float("\x00")); } // min and max float f = to!float("1.17549e-38"); assert(feq(cast(real)f, cast(real)1.17549e-38)); assert(feq(cast(real)f, cast(real)float.min_normal)); f = to!float("3.40282e+38"); assert(to!string(f) == to!string(3.40282e+38)); // min and max double d = to!double("2.22508e-308"); assert(feq(cast(real)d, cast(real)2.22508e-308)); assert(feq(cast(real)d, cast(real)double.min_normal)); d = to!double("1.79769e+308"); assert(to!string(d) == to!string(1.79769e+308)); assert(to!string(d) == to!string(double.max)); assert(to!string(to!real(to!string(real.max / 2L))) == to!string(real.max / 2L)); // min and max real r = to!real(to!string(real.min_normal)); version(NetBSD) { // NetBSD notice // to!string returns 3.3621e-4932L. It is less than real.min_normal and it is subnormal value // Simple C code // long double rd = 3.3621e-4932L; // printf("%Le\n", rd); // has unexpected result: 1.681050e-4932 // // Bug report: http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50937 } else { assert(to!string(r) == to!string(real.min_normal)); } r = to!real(to!string(real.max)); assert(to!string(r) == to!string(real.max)); } //Tests for the double implementation unittest { static if(real.mant_dig == 53) { import core.stdc.stdlib, std.exception, std.math; //Should be parsed exactly: 53 bit mantissa string s = "0x1A_BCDE_F012_3456p10"; auto x = parse!real(s); assert(x == 0x1A_BCDE_F012_3456p10L); //1 bit is implicit assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0xA_BCDE_F012_3456); assert(strtod("0x1ABCDEF0123456p10", null) == x); //Should be parsed exactly: 10 bit mantissa s = "0x3FFp10"; x = parse!real(s); assert(x == 0x03FFp10); //1 bit is implicit assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_F800_0000_0000); assert(strtod("0x3FFp10", null) == x); //60 bit mantissa, round up s = "0xFFF_FFFF_FFFF_FFFFp10"; x = parse!real(s); assert(approxEqual(x, 0xFFF_FFFF_FFFF_FFFFp10)); //1 bit is implicit assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x0000_0000_0000_0000); assert(strtod("0xFFFFFFFFFFFFFFFp10", null) == x); //60 bit mantissa, round down s = "0xFFF_FFFF_FFFF_FF90p10"; x = parse!real(s); assert(approxEqual(x, 0xFFF_FFFF_FFFF_FF90p10)); //1 bit is implicit assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_FFFF_FFFF_FFFF); assert(strtod("0xFFFFFFFFFFFFF90p10", null) == x); //61 bit mantissa, round up 2 s = "0x1F0F_FFFF_FFFF_FFFFp10"; x = parse!real(s); assert(approxEqual(x, 0x1F0F_FFFF_FFFF_FFFFp10)); //1 bit is implicit assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_1000_0000_0000); assert(strtod("0x1F0FFFFFFFFFFFFFp10", null) == x); //61 bit mantissa, round down 2 s = "0x1F0F_FFFF_FFFF_FF10p10"; x = parse!real(s); assert(approxEqual(x, 0x1F0F_FFFF_FFFF_FF10p10)); //1 bit is implicit assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_0FFF_FFFF_FFFF); assert(strtod("0x1F0FFFFFFFFFFF10p10", null) == x); //Huge exponent s = "0x1F_FFFF_FFFF_FFFFp900"; x = parse!real(s); assert(strtod("0x1FFFFFFFFFFFFFp900", null) == x); //exponent too big -> converror s = ""; assertThrown!ConvException(x = parse!real(s)); assert(strtod("0x1FFFFFFFFFFFFFp1024", null) == real.infinity); //-exponent too big -> 0 s = "0x1FFFFFFFFFFFFFp-2000"; x = parse!real(s); assert(x == 0); assert(strtod("0x1FFFFFFFFFFFFFp-2000", null) == x); } } unittest { import core.stdc.errno; import core.stdc.stdlib; errno = 0; // In case it was set by another unittest in a different module. struct longdouble { static if(real.mant_dig == 64) { ushort[5] value; } else static if(real.mant_dig == 53) { ushort[4] value; } else static assert(false, "Not implemented"); } real ld; longdouble x; real ld1; longdouble x1; int i; static if(real.mant_dig == 64) enum s = "0x1.FFFFFFFFFFFFFFFEp-16382"; else static if(real.mant_dig == 53) enum s = "0x1.FFFFFFFFFFFFFFFEp-1000"; else static assert(false, "Floating point format for real not supported"); auto s2 = s.idup; ld = parse!real(s2); assert(s2.empty); x = *cast(longdouble *)&ld; static if(real.mant_dig == 64) { version (CRuntime_Microsoft) ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod else version (CRuntime_Bionic) ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod else ld1 = strtold(s.ptr, null); } else ld1 = strtold(s.ptr, null); x1 = *cast(longdouble *)&ld1; assert(x1 == x && ld1 == ld); // for (i = 4; i >= 0; i--) // { // printf("%04x ", x.value[i]); // } // printf("\n"); assert(!errno); s2 = "1.0e5"; ld = parse!real(s2); assert(s2.empty); x = *cast(longdouble *)&ld; ld1 = strtold("1.0e5", null); x1 = *cast(longdouble *)&ld1; // for (i = 4; i >= 0; i--) // { // printf("%04x ", x.value[i]); // } // printf("\n"); } @safe pure unittest { import std.exception; // Bugzilla 4959 { auto s = "0 "; auto x = parse!double(s); assert(s == " "); assert(x == 0.0); } // Bugzilla 3369 assert(to!float("inf") == float.infinity); assert(to!float("-inf") == -float.infinity); // Bugzilla 6160 assert(6_5.536e3L == to!real("6_5.536e3")); // 2^16 assert(0x1000_000_000_p10 == to!real("0x1000_000_000_p10")); // 7.03687e+13 // Bugzilla 6258 assertThrown!ConvException(to!real("-")); assertThrown!ConvException(to!real("in")); // Bugzilla 7055 assertThrown!ConvException(to!float("INF2")); //extra stress testing auto ssOK = ["1.", "1.1.1", "1.e5", "2e1e", "2a", "2e1_1", "inf", "-inf", "infa", "-infa", "inf2e2", "-inf2e2"]; auto ssKO = ["", " ", "2e", "2e+", "2e-", "2ee", "2e++1", "2e--1", "2e_1", "+inf"]; foreach (s; ssOK) parse!double(s); foreach (s; ssKO) assertThrown!ConvException(parse!double(s)); } /** Parsing one character off a string returns the character and bumps the string up one position. */ Target parse(Target, Source)(ref Source s) if (isExactSomeString!Source && staticIndexOf!(Unqual!Target, dchar, Unqual!(ElementEncodingType!Source)) >= 0) { if (s.empty) throw convError!(Source, Target)(s); static if (is(Unqual!Target == dchar)) { Target result = s.front; s.popFront(); return result; } else { // Special case: okay so parse a Char off a Char[] Target result = s[0]; s = s[1 .. $]; return result; } } @safe pure unittest { foreach (Str; AliasSeq!(string, wstring, dstring)) { foreach (Char; AliasSeq!(char, wchar, dchar)) { static if (is(Unqual!Char == dchar) || Char.sizeof == ElementEncodingType!Str.sizeof) { Str s = "aaa"; assert(parse!Char(s) == 'a'); assert(s == "aa"); } } } } Target parse(Target, Source)(ref Source s) if (!isSomeString!Source && isInputRange!Source && isSomeChar!(ElementType!Source) && isSomeChar!Target && Target.sizeof >= ElementType!Source.sizeof && !is(Target == enum)) { if (s.empty) throw convError!(Source, Target)(s); Target result = s.front; s.popFront(); return result; } /* Tests for to!bool and parse!bool */ @safe pure unittest { import std.exception; assert (to!bool("TruE") == true); assert (to!bool("faLse"d) == false); assertThrown!ConvException(to!bool("maybe")); auto t = "TrueType"; assert (parse!bool(t) == true); assert (t == "Type"); auto f = "False killer whale"d; assert (parse!bool(f) == false); assert (f == " killer whale"d); auto m = "maybe"; assertThrown!ConvException(parse!bool(m)); assert (m == "maybe"); // m shouldn't change on failure auto s = "true"; auto b = parse!(const(bool))(s); assert(b == true); } // input range to null literal conversions Target parse(Target, Source)(ref Source s) if (isInputRange!Source && isSomeChar!(ElementType!Source) && is(Unqual!Target == typeof(null))) { import std.ascii : toLower; foreach (c; "null") { if (s.empty || toLower(s.front) != c) throw parseError("null should be case-insensitive 'null'"); s.popFront(); } return null; } @safe pure unittest { import std.exception; alias NullType = typeof(null); auto s1 = "null"; assert(parse!NullType(s1) is null); assert(s1 == ""); auto s2 = "NUll"d; assert(parse!NullType(s2) is null); assert(s2 == ""); auto m = "maybe"; assertThrown!ConvException(parse!NullType(m)); assert(m == "maybe"); // m shouldn't change on failure auto s = "NULL"; assert(parse!(const NullType)(s) is null); } //Used internally by parse Array/AA, to remove ascii whites package void skipWS(R)(ref R r) { import std.ascii : isWhite; static if (isSomeString!R) { //Implementation inspired from stripLeft. foreach (i, dchar c; r) { if (!isWhite(c)) { r = r[i .. $]; return; } } r = r[0 .. 0]; //Empty string with correct type. return; } else { for (; !r.empty && isWhite(r.front); r.popFront()) {} } } /** * Parses an array from a string given the left bracket (default $(D * '[')), right bracket (default $(D ']')), and element separator (by * default $(D ',')). */ Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar comma = ',') if (isExactSomeString!Source && isDynamicArray!Target && !is(Target == enum)) { Target result; parseCheck!s(lbracket); skipWS(s); if (s.empty) throw convError!(Source, Target)(s); if (s.front == rbracket) { s.popFront(); return result; } for (;; s.popFront(), skipWS(s)) { result ~= parseElement!(ElementType!Target)(s); skipWS(s); if (s.empty) throw convError!(Source, Target)(s); if (s.front != comma) break; } parseCheck!s(rbracket); return result; } unittest { int[] a = [1, 2, 3, 4, 5]; auto s = to!string(a); assert(to!(int[])(s) == a); } unittest { int[][] a = [ [1, 2] , [3], [4, 5] ]; auto s = to!string(a); assert(to!(int[][])(s) == a); } unittest { int[][][] ia = [ [[1,2],[3,4],[5]] , [[6],[],[7,8,9]] , [[]] ]; char[] s = to!(char[])(ia); int[][][] ia2; ia2 = to!(typeof(ia2))(s); assert( ia == ia2); } @safe pure unittest { auto s1 = `[['h', 'e', 'l', 'l', 'o'], "world"]`; auto a1 = parse!(string[])(s1); assert(a1 == ["hello", "world"]); auto s2 = `["aaa", "bbb", "ccc"]`; auto a2 = parse!(string[])(s2); assert(a2 == ["aaa", "bbb", "ccc"]); } @safe pure unittest { import std.exception; //Check proper failure auto s = "[ 1 , 2 , 3 ]"; foreach (i ; 0..s.length-1) { auto ss = s[0 .. i]; assertThrown!ConvException(parse!(int[])(ss)); } int[] arr = parse!(int[])(s); } @safe pure unittest { //Checks parsing of strings with escaped characters string s1 = `[ "Contains a\0null!", "tab\there", "line\nbreak", "backslash \\ slash / question \?", "number \x35 five", "unicode \u65E5 sun", "very long \U000065E5 sun" ]`; //Note: escaped characters purposefully replaced and isolated to guarantee //there are no typos in the escape syntax string[] s2 = [ "Contains a" ~ '\0' ~ "null!", "tab" ~ '\t' ~ "here", "line" ~ '\n' ~ "break", "backslash " ~ '\\' ~ " slash / question ?", "number 5 five", "unicode 日 sun", "very long 日 sun" ]; assert(s2 == parse!(string[])(s1)); assert(s1.empty); } /// ditto Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar comma = ',') if (isExactSomeString!Source && isStaticArray!Target && !is(Target == enum)) { static if (hasIndirections!Target) Target result = Target.init[0].init; else Target result = void; parseCheck!s(lbracket); skipWS(s); if (s.empty) throw convError!(Source, Target)(s); if (s.front == rbracket) { static if (result.length != 0) goto Lmanyerr; else { s.popFront(); return result; } } for (size_t i = 0; ; s.popFront(), skipWS(s)) { if (i == result.length) goto Lmanyerr; result[i++] = parseElement!(ElementType!Target)(s); skipWS(s); if (s.empty) throw convError!(Source, Target)(s); if (s.front != comma) { if (i != result.length) goto Lfewerr; break; } } parseCheck!s(rbracket); return result; Lmanyerr: throw parseError(text("Too many elements in input, ", result.length, " elements expected.")); Lfewerr: throw parseError(text("Too few elements in input, ", result.length, " elements expected.")); } @safe pure unittest { import std.exception; auto s1 = "[1,2,3,4]"; auto sa1 = parse!(int[4])(s1); assert(sa1 == [1,2,3,4]); auto s2 = "[[1],[2,3],[4]]"; auto sa2 = parse!(int[][3])(s2); assert(sa2 == [[1],[2,3],[4]]); auto s3 = "[1,2,3]"; assertThrown!ConvException(parse!(int[4])(s3)); auto s4 = "[1,2,3,4,5]"; assertThrown!ConvException(parse!(int[4])(s4)); } /** * Parses an associative array from a string given the left bracket (default $(D * '[')), right bracket (default $(D ']')), key-value separator (default $(D * ':')), and element seprator (by default $(D ',')). */ Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar keyval = ':', dchar comma = ',') if (isExactSomeString!Source && isAssociativeArray!Target && !is(Target == enum)) { alias KeyType = typeof(Target.init.keys[0]); alias ValType = typeof(Target.init.values[0]); Target result; parseCheck!s(lbracket); skipWS(s); if (s.empty) throw convError!(Source, Target)(s); if (s.front == rbracket) { s.popFront(); return result; } for (;; s.popFront(), skipWS(s)) { auto key = parseElement!KeyType(s); skipWS(s); parseCheck!s(keyval); skipWS(s); auto val = parseElement!ValType(s); skipWS(s); result[key] = val; if (s.empty) throw convError!(Source, Target)(s); if (s.front != comma) break; } parseCheck!s(rbracket); return result; } @safe pure unittest { auto s1 = "[1:10, 2:20, 3:30]"; auto aa1 = parse!(int[int])(s1); assert(aa1 == [1:10, 2:20, 3:30]); auto s2 = `["aaa":10, "bbb":20, "ccc":30]`; auto aa2 = parse!(int[string])(s2); assert(aa2 == ["aaa":10, "bbb":20, "ccc":30]); auto s3 = `["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]`; auto aa3 = parse!(int[][string])(s3); assert(aa3 == ["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]); } @safe pure unittest { import std.exception; //Check proper failure auto s = "[1:10, 2:20, 3:30]"; foreach (i ; 0 .. s.length-1) { auto ss = s[0 .. i]; assertThrown!ConvException(parse!(int[int])(ss)); } int[int] aa = parse!(int[int])(s); } private dchar parseEscape(Source)(ref Source s) if (isInputRange!Source && isSomeChar!(ElementType!Source)) { parseCheck!s('\\'); if (s.empty) throw parseError("Unterminated escape sequence"); dchar getHexDigit()(ref Source s_ = s) // workaround { import std.ascii : isAlpha, isHexDigit; if (s_.empty) throw parseError("Unterminated escape sequence"); s_.popFront(); if (s_.empty) throw parseError("Unterminated escape sequence"); dchar c = s_.front; if (!isHexDigit(c)) throw parseError("Hex digit is missing"); return isAlpha(c) ? ((c & ~0x20) - ('A' - 10)) : c - '0'; } dchar result; switch (s.front) { case '"': result = '\"'; break; case '\'': result = '\''; break; case '0': result = '\0'; break; case '?': result = '\?'; break; case '\\': result = '\\'; break; case 'a': result = '\a'; break; case 'b': result = '\b'; break; case 'f': result = '\f'; break; case 'n': result = '\n'; break; case 'r': result = '\r'; break; case 't': result = '\t'; break; case 'v': result = '\v'; break; case 'x': result = getHexDigit() << 4; result |= getHexDigit(); break; case 'u': result = getHexDigit() << 12; result |= getHexDigit() << 8; result |= getHexDigit() << 4; result |= getHexDigit(); break; case 'U': result = getHexDigit() << 28; result |= getHexDigit() << 24; result |= getHexDigit() << 20; result |= getHexDigit() << 16; result |= getHexDigit() << 12; result |= getHexDigit() << 8; result |= getHexDigit() << 4; result |= getHexDigit(); break; default: throw parseError("Unknown escape character " ~ to!string(s.front)); } if (s.empty) throw parseError("Unterminated escape sequence"); s.popFront(); return result; } @safe pure unittest { string[] s1 = [ `\"`, `\'`, `\?`, `\\`, `\a`, `\b`, `\f`, `\n`, `\r`, `\t`, `\v`, //Normal escapes //`\141`, //@@@9621@@@ Octal escapes. `\x61`, `\u65E5`, `\U00012456` //`\&`, `\"`, //@@@9621@@@ Named Character Entities. ]; const(dchar)[] s2 = [ '\"', '\'', '\?', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v', //Normal escapes //'\141', //@@@9621@@@ Octal escapes. '\x61', '\u65E5', '\U00012456' //'\&', '\"', //@@@9621@@@ Named Character Entities. ]; foreach (i ; 0 .. s1.length) { assert(s2[i] == parseEscape(s1[i])); assert(s1[i].empty); } } @safe pure unittest { import std.exception; string[] ss = [ `hello!`, //Not an escape `\`, //Premature termination `\/`, //Not an escape `\gggg`, //Not an escape `\xzz`, //Not an hex `\x0`, //Premature hex end `\XB9`, //Not legal hex syntax `\u!!`, //Not a unicode hex `\777`, //Octal is larger than a byte //Note: Throws, but simply because octals are unsupported `\u123`, //Premature hex end `\U123123` //Premature hex end ]; foreach (s ; ss) assertThrown!ConvException(parseEscape(s)); } // Undocumented Target parseElement(Target, Source)(ref Source s) if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) && isExactSomeString!Target) { import std.array : appender; auto result = appender!Target(); // parse array of chars if (s.empty) throw convError!(Source, Target)(s); if (s.front == '[') return parse!Target(s); parseCheck!s('\"'); if (s.empty) throw convError!(Source, Target)(s); if (s.front == '\"') { s.popFront(); return result.data; } while (true) { if (s.empty) throw parseError("Unterminated quoted string"); switch (s.front) { case '\"': s.popFront(); return result.data; case '\\': result.put(parseEscape(s)); break; default: result.put(s.front); s.popFront(); break; } } assert(0); } // ditto Target parseElement(Target, Source)(ref Source s) if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) && isSomeChar!Target && !is(Target == enum)) { Target c; parseCheck!s('\''); if (s.empty) throw convError!(Source, Target)(s); if (s.front != '\\') { c = s.front; s.popFront(); } else c = parseEscape(s); parseCheck!s('\''); return c; } // ditto Target parseElement(Target, Source)(ref Source s) if (isInputRange!Source && isSomeChar!(ElementType!Source) && !isSomeString!Target && !isSomeChar!Target) { return parse!Target(s); } /*************************************************************** * Convenience functions for converting any number and types of * arguments into _text (the three character widths). */ string text(T...)(T args) { return textImpl!string(args); } ///ditto wstring wtext(T...)(T args) { return textImpl!wstring(args); } ///ditto dstring dtext(T...)(T args) { return textImpl!dstring(args); } private S textImpl(S, U...)(U args) { static if (U.length == 0) { return null; } else { auto result = to!S(args[0]); foreach (arg; args[1 .. $]) result ~= to!S(arg); return result; } } /// unittest { assert( text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"c); assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w); assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d); } unittest { assert(text() is null); assert(wtext() is null); assert(dtext() is null); } /*************************************************************** The $(D octal) facility provides a means to declare a number in base 8. Using $(D octal!177) or $(D octal!"177") for 127 represented in octal (same as 0177 in C). The rules for strings are the usual for literals: If it can fit in an $(D int), it is an $(D int). Otherwise, it is a $(D long). But, if the user specifically asks for a $(D long) with the $(D L) suffix, always give the $(D long). Give an unsigned iff it is asked for with the $(D U) or $(D u) suffix. _Octals created from integers preserve the type of the passed-in integral. See_Also: $(LREF parse) for parsing octal strings at runtime. */ template octal(string num) if(isOctalLiteral(num)) { static if((octalFitsInInt!num && !literalIsLong!num) && !literalIsUnsigned!num) enum octal = octal!int(num); else static if((!octalFitsInInt!num || literalIsLong!num) && !literalIsUnsigned!num) enum octal = octal!long(num); else static if((octalFitsInInt!num && !literalIsLong!num) && literalIsUnsigned!num) enum octal = octal!uint(num); else static if((!octalFitsInInt!(num) || literalIsLong!(num)) && literalIsUnsigned!(num)) enum octal = octal!ulong(num); else static assert(false); } /// Ditto template octal(alias decimalInteger) if (isIntegral!(typeof(decimalInteger))) { enum octal = octal!(typeof(decimalInteger))(to!string(decimalInteger)); } /// unittest { // same as 0177 auto x = octal!177; // octal is a compile-time device enum y = octal!160; // Create an unsigned octal auto z = octal!"1_000_000u"; } /* Takes a string, num, which is an octal literal, and returns its value, in the type T specified. */ private T octal(T)(string num) { assert(isOctalLiteral(num)); ulong pow = 1; T value = 0; foreach_reverse (immutable pos; 0 .. num.length) { char s = num[pos]; if (s < '0' || s > '7') // we only care about digits; skip the rest // safe to skip - this is checked out in the assert so these // are just suffixes continue; value += pow * (s - '0'); pow *= 8; } return value; } /// unittest { int a = octal!int("10"); assert(a == 8); } /* Take a look at int.max and int.max+1 in octal and the logic for this function follows directly. */ private template octalFitsInInt(string octalNum) { // note it is important to strip the literal of all // non-numbers. kill the suffix and underscores lest they mess up // the number of digits here that we depend on. enum bool octalFitsInInt = strippedOctalLiteral(octalNum).length < 11 || strippedOctalLiteral(octalNum).length == 11 && strippedOctalLiteral(octalNum)[0] == '1'; } private string strippedOctalLiteral(string original) { string stripped = ""; foreach (c; original) if (c >= '0' && c <= '7') stripped ~= c; return stripped; } private template literalIsLong(string num) { static if (num.length > 1) // can be xxL or xxLu according to spec enum literalIsLong = (num[$-1] == 'L' || num[$-2] == 'L'); else enum literalIsLong = false; } private template literalIsUnsigned(string num) { static if (num.length > 1) // can be xxU or xxUL according to spec enum literalIsUnsigned = (num[$-1] == 'u' || num[$-2] == 'u') // both cases are allowed too || (num[$-1] == 'U' || num[$-2] == 'U'); else enum literalIsUnsigned = false; } /* Returns if the given string is a correctly formatted octal literal. The format is specified in spec/lex.html. The leading zero is allowed, but not required. */ private bool isOctalLiteral(string num) { if (num.length == 0) return false; // Must start with a number. To avoid confusion, literals that // start with a '0' are not allowed if (num[0] == '0' && num.length > 1) return false; if (num[0] < '0' || num[0] > '7') return false; foreach (i, c; num) { if ((c < '0' || c > '7') && c != '_') // not a legal character { if (i < num.length - 2) return false; else // gotta check for those suffixes { if (c != 'U' && c != 'u' && c != 'L') return false; if (i != num.length - 1) { // if we're not the last one, the next one must // also be a suffix to be valid char c2 = num[$-1]; if (c2 != 'U' && c2 != 'u' && c2 != 'L') return false; // spam at the end of the string if (c2 == c) return false; // repeats are disallowed } } } } return true; } unittest { // ensure that you get the right types, even with embedded underscores auto w = octal!"100_000_000_000"; static assert(!is(typeof(w) == int)); auto w2 = octal!"1_000_000_000"; static assert(is(typeof(w2) == int)); static assert(octal!"45" == 37); static assert(octal!"0" == 0); static assert(octal!"7" == 7); static assert(octal!"10" == 8); static assert(octal!"666" == 438); static assert(octal!45 == 37); static assert(octal!0 == 0); static assert(octal!7 == 7); static assert(octal!10 == 8); static assert(octal!666 == 438); static assert(octal!"66_6" == 438); static assert(octal!2520046213 == 356535435); static assert(octal!"2520046213" == 356535435); static assert(octal!17777777777 == int.max); static assert(!__traits(compiles, octal!823)); static assert(!__traits(compiles, octal!"823")); static assert(!__traits(compiles, octal!"_823")); static assert(!__traits(compiles, octal!"spam")); static assert(!__traits(compiles, octal!"77%")); static assert(is(typeof(octal!"17777777777") == int)); static assert(octal!"17777777777" == int.max); static assert(is(typeof(octal!"20000000000U") == ulong)); // Shouldn't this be uint? static assert(octal!"20000000000" == uint(int.max) + 1); static assert(is(typeof(octal!"777777777777777777777") == long)); static assert(octal!"777777777777777777777" == long.max); static assert(is(typeof(octal!"1000000000000000000000U") == ulong)); static assert(octal!"1000000000000000000000" == ulong(long.max) + 1); int a; long b; // biggest value that should fit in an it a = octal!"17777777777"; assert(a == int.max); // should not fit in the int static assert(!__traits(compiles, a = octal!"20000000000")); // ... but should fit in a long b = octal!"20000000000"; assert(b == 1L + int.max); b = octal!"1L"; assert(b == 1); b = octal!1L; assert(b == 1); } /+ emplaceRef is a package function for phobos internal use. It works like emplace, but takes its argument by ref (as opposed to "by pointer"). This makes it easier to use, easier to be safe, and faster in a non-inline build. Furthermore, emplaceRef optionally takes a type paremeter, which specifies the type we want to build. This helps to build qualified objects on mutable buffer, without breaking the type system with unsafe casts. +/ package void emplaceRef(T, UT, Args...)(ref UT chunk, auto ref Args args) if (is(UT == Unqual!T)) { static if (args.length == 0) { static assert (is(typeof({static T i;})), convFormat("Cannot emplace a %1$s because %1$s.this() is annotated with @disable.", T.stringof)); static if (is(T == class)) static assert (!isAbstractClass!T, T.stringof ~ " is abstract and it can't be emplaced"); emplaceInitializer(chunk); } else static if ( !is(T == struct) && Args.length == 1 /* primitives, enums, arrays */ || Args.length == 1 && is(typeof({T t = args[0];})) /* conversions */ || is(typeof(T(args))) /* general constructors */) { static struct S { T payload; this(ref Args x) { static if (Args.length == 1) static if (is(typeof(payload = x[0]))) payload = x[0]; else payload = T(x[0]); else payload = T(x); } } if (__ctfe) { static if (is(typeof(chunk = T(args)))) chunk = T(args); else static if (args.length == 1 && is(typeof(chunk = args[0]))) chunk = args[0]; else assert(0, "CTFE emplace doesn't support " ~ T.stringof ~ " from " ~ Args.stringof); } else { S* p = () @trusted { return cast(S*) &chunk; }(); emplaceInitializer(*p); p.__ctor(args); } } else static if (is(typeof(chunk.__ctor(args)))) { // This catches the rare case of local types that keep a frame pointer emplaceInitializer(chunk); chunk.__ctor(args); } else { //We can't emplace. Try to diagnose a disabled postblit. static assert(!(Args.length == 1 && is(Args[0] : T)), convFormat("Cannot emplace a %1$s because %1$s.this(this) is annotated with @disable.", T.stringof)); //We can't emplace. static assert(false, convFormat("%s cannot be emplaced from %s.", T.stringof, Args[].stringof)); } } // ditto package void emplaceRef(UT, Args...)(ref UT chunk, auto ref Args args) if (is(UT == Unqual!UT)) { emplaceRef!(UT, UT)(chunk, args); } //emplace helper functions private void emplaceInitializer(T)(ref T chunk) @trusted pure nothrow { static if (!hasElaborateAssign!T && isAssignable!T) chunk = T.init; else { import core.stdc.string : memcpy; static immutable T init = T.init; memcpy(&chunk, &init, T.sizeof); } } // emplace /** Given a pointer $(D chunk) to uninitialized memory (but already typed as $(D T)), constructs an object of non-$(D class) type $(D T) at that address. Returns: A pointer to the newly constructed object (which is the same as $(D chunk)). */ T* emplace(T)(T* chunk) @safe pure nothrow { emplaceRef!T(*chunk); return chunk; } /// unittest { static struct S { int i = 42; } S[2] s2 = void; emplace(&s2); assert(s2[0].i == 42 && s2[1].i == 42); } /** Given a pointer $(D chunk) to uninitialized memory (but already typed as a non-class type $(D T)), constructs an object of type $(D T) at that address from arguments $(D args). This function can be $(D @trusted) if the corresponding constructor of $(D T) is $(D @safe). Returns: A pointer to the newly constructed object (which is the same as $(D chunk)). */ T* emplace(T, Args...)(T* chunk, auto ref Args args) if (is(T == struct) || Args.length == 1) { emplaceRef!T(*chunk, args); return chunk; } /// unittest { int a; int b = 42; assert(*emplace!int(&a, b) == 42); } private void testEmplaceChunk(void[] chunk, size_t typeSize, size_t typeAlignment, string typeName) @nogc pure nothrow { assert(chunk.length >= typeSize, "emplace: Chunk size too small."); assert((cast(size_t)chunk.ptr) % typeAlignment == 0, "emplace: Chunk is not aligned."); } /** Given a raw memory area $(D chunk), constructs an object of $(D class) type $(D T) at that address. The constructor is passed the arguments $(D Args). The $(D chunk) must be as least as large as $(D T) needs and should have an alignment multiple of $(D T)'s alignment. (The size of a $(D class) instance is obtained by using $(D __traits(classInstanceSize, T))). This function can be $(D @trusted) if the corresponding constructor of $(D T) is $(D @safe). Returns: A pointer to the newly constructed object. */ T emplace(T, Args...)(void[] chunk, auto ref Args args) if (is(T == class)) { static assert (!isAbstractClass!T, T.stringof ~ " is abstract and it can't be emplaced"); enum classSize = __traits(classInstanceSize, T); testEmplaceChunk(chunk, classSize, classInstanceAlignment!T, T.stringof); auto result = cast(T) chunk.ptr; // Initialize the object in its pre-ctor state chunk[0 .. classSize] = typeid(T).initializer[]; // Call the ctor if any static if (is(typeof(result.__ctor(args)))) { // T defines a genuine constructor accepting args // Go the classic route: write .init first, then call ctor result.__ctor(args); } else { static assert(args.length == 0 && !is(typeof(&T.__ctor)), "Don't know how to initialize an object of type " ~ T.stringof ~ " with arguments " ~ Args.stringof); } return result; } /// unittest { interface I {} class K : I {} K k = void; emplace(&k); assert(k is null); I i = void; emplace(&i); assert(i is null); } @nogc pure nothrow unittest { int var = 6; ubyte[__traits(classInstanceSize, __conv_EmplaceTestClass)] buf; auto k = emplace!__conv_EmplaceTestClass(buf, 5, var); assert(k.i == 5); assert(var == 7); } /** Given a raw memory area $(D chunk), constructs an object of non-$(D class) type $(D T) at that address. The constructor is passed the arguments $(D args), if any. The $(D chunk) must be as least as large as $(D T) needs and should have an alignment multiple of $(D T)'s alignment. This function can be $(D @trusted) if the corresponding constructor of $(D T) is $(D @safe). Returns: A pointer to the newly constructed object. */ T* emplace(T, Args...)(void[] chunk, auto ref Args args) if (!is(T == class)) { testEmplaceChunk(chunk, T.sizeof, T.alignof, T.stringof); emplaceRef!(T, Unqual!T)(*cast(Unqual!T*) chunk.ptr, args); return cast(T*) chunk.ptr; } /// unittest { struct S { int a, b; } auto p = new void[S.sizeof]; S s; s.a = 42; s.b = 43; auto s1 = emplace!S(p, s); assert(s1.a == 42 && s1.b == 43); } // Bulk of emplace unittests starts here unittest /* unions */ { static union U { string a; int b; struct { long c; int[] d; } } U u1 = void; U u2 = { "hello" }; emplace(&u1, u2); assert(u1.a == "hello"); } version(unittest) private struct __conv_EmplaceTest { int i = 3; this(int i) { assert(this.i == 3 && i == 5); this.i = i; } this(int i, ref int j) { assert(i == 5 && j == 6); this.i = i; ++j; } @disable: this(); this(this); void opAssign(); } version(unittest) private class __conv_EmplaceTestClass { int i = 3; this(int i) @nogc @safe pure nothrow { assert(this.i == 3 && i == 5); this.i = i; } this(int i, ref int j) @nogc @safe pure nothrow { assert(i == 5 && j == 6); this.i = i; ++j; } } unittest // bugzilla 15772 { abstract class Foo {} class Bar: Foo {} void[] memory; // test in emplaceInitializer static assert(!is(typeof(emplace!Foo(cast(Foo*) memory.ptr)))); static assert( is(typeof(emplace!Bar(cast(Bar*) memory.ptr)))); // test in the emplace overload that takes void[] static assert(!is(typeof(emplace!Foo(memory)))); static assert( is(typeof(emplace!Bar(memory)))); } unittest { struct S { @disable this(); } S s = void; static assert(!__traits(compiles, emplace(&s))); emplace(&s, S.init); } unittest { struct S1 {} struct S2 { void opAssign(S2); } S1 s1 = void; S2 s2 = void; S1[2] as1 = void; S2[2] as2 = void; emplace(&s1); emplace(&s2); emplace(&as1); emplace(&as2); } unittest { static struct S1 { this(this) @disable; } static struct S2 { this() @disable; } S1[2] ss1 = void; S2[2] ss2 = void; emplace(&ss1); static assert(!__traits(compiles, emplace(&ss2))); S1 s1 = S1.init; S2 s2 = S2.init; static assert(!__traits(compiles, emplace(&ss1, s1))); emplace(&ss2, s2); } unittest { struct S { immutable int i; } S s = void; S[2] ss1 = void; S[2] ss2 = void; emplace(&s, 5); assert(s.i == 5); emplace(&ss1, s); assert(ss1[0].i == 5 && ss1[1].i == 5); emplace(&ss2, ss1); assert(ss2 == ss1); } //Start testing emplace-args here unittest { interface I {} class K : I {} K k = null, k2 = new K; assert(k !is k2); emplace!K(&k, k2); assert(k is k2); I i = null; assert(i !is k); emplace!I(&i, k); assert(i is k); } unittest { static struct S { int i = 5; void opAssign(S){assert(0);} } S[2] sa = void; S[2] sb; emplace(&sa, sb); assert(sa[0].i == 5 && sa[1].i == 5); } //Start testing emplace-struct here // Test constructor branch unittest { struct S { double x = 5, y = 6; this(int a, int b) { assert(x == 5 && y == 6); x = a; y = b; } } auto s1 = new void[S.sizeof]; auto s2 = S(42, 43); assert(*emplace!S(cast(S*) s1.ptr, s2) == s2); assert(*emplace!S(cast(S*) s1, 44, 45) == S(44, 45)); } unittest { __conv_EmplaceTest k = void; emplace(&k, 5); assert(k.i == 5); } unittest { int var = 6; __conv_EmplaceTest k = void; emplace(&k, 5, var); assert(k.i == 5); assert(var == 7); } // Test matching fields branch unittest { struct S { uint n; } S s; emplace!S(&s, 2U); assert(s.n == 2); } unittest { struct S { int a, b; this(int){} } S s; static assert(!__traits(compiles, emplace!S(&s, 2, 3))); } unittest { struct S { int a, b = 7; } S s1 = void, s2 = void; emplace!S(&s1, 2); assert(s1.a == 2 && s1.b == 7); emplace!S(&s2, 2, 3); assert(s2.a == 2 && s2.b == 3); } //opAssign unittest { static struct S { int i = 5; void opAssign(int){assert(0);} void opAssign(S){assert(0);} } S sa1 = void; S sa2 = void; S sb1 = S(1); emplace(&sa1, sb1); emplace(&sa2, 2); assert(sa1.i == 1); assert(sa2.i == 2); } //postblit precedence unittest { //Works, but breaks in "-w -O" because of @@@9332@@@. //Uncomment test when 9332 is fixed. static struct S { int i; this(S other){assert(false);} this(int i){this.i = i;} this(this){} } S a = void; assert(is(typeof({S b = a;}))); //Postblit assert(is(typeof({S b = S(a);}))); //Constructor auto b = S(5); emplace(&a, b); assert(a.i == 5); static struct S2 { int* p; this(const S2){} } static assert(!is(immutable S2 : S2)); S2 s2 = void; immutable is2 = (immutable S2).init; emplace(&s2, is2); } //nested structs and postblit unittest { static struct S { int* p; this(int i){p = [i].ptr;} this(this) { if (p) p = [*p].ptr; } } static struct SS { S s; void opAssign(const SS) { assert(0); } } SS ssa = void; SS ssb = SS(S(5)); emplace(&ssa, ssb); assert(*ssa.s.p == 5); assert(ssa.s.p != ssb.s.p); } //disabled postblit unittest { static struct S1 { int i; @disable this(this); } S1 s1 = void; emplace(&s1, 1); assert(s1.i == 1); static assert(!__traits(compiles, emplace(&s1, S1.init))); static struct S2 { int i; @disable this(this); this(ref S2){} } S2 s2 = void; static assert(!__traits(compiles, emplace(&s2, 1))); emplace(&s2, S2.init); static struct SS1 { S1 s; } SS1 ss1 = void; emplace(&ss1); static assert(!__traits(compiles, emplace(&ss1, SS1.init))); static struct SS2 { S2 s; } SS2 ss2 = void; emplace(&ss2); static assert(!__traits(compiles, emplace(&ss2, SS2.init))); // SS1 sss1 = s1; //This doesn't compile // SS1 sss1 = SS1(s1); //This doesn't compile // So emplace shouldn't compile either static assert(!__traits(compiles, emplace(&sss1, s1))); static assert(!__traits(compiles, emplace(&sss2, s2))); } //Imutability unittest { //Castable immutability { static struct S1 { int i; } static assert(is( immutable(S1) : S1)); S1 sa = void; auto sb = immutable(S1)(5); emplace(&sa, sb); assert(sa.i == 5); } //Un-castable immutability { static struct S2 { int* p; } static assert(!is(immutable(S2) : S2)); S2 sa = void; auto sb = immutable(S2)(null); assert(!__traits(compiles, emplace(&sa, sb))); } } unittest { static struct S { immutable int i; immutable(int)* j; } S s = void; emplace(&s, 1, null); emplace(&s, 2, &s.i); assert(s is S(2, &s.i)); } //Context pointer unittest { int i = 0; { struct S1 { void foo(){++i;} } S1 sa = void; S1 sb; emplace(&sa, sb); sa.foo(); assert(i == 1); } { struct S2 { void foo(){++i;} this(this){} } S2 sa = void; S2 sb; emplace(&sa, sb); sa.foo(); assert(i == 2); } ////NOTE: THESE WILL COMPILE ////But will not correctly emplace the context pointer ////The problem lies with voldemort, and not emplace. //{ // struct S3 // { // int k; // void foo(){++i;} // } //} //S3 s3 = void; //emplace(&s3); //S3.init has no context pointer information //emplace(&s3, 1); //No way to obtain context pointer once inside emplace } //Alias this unittest { static struct S { int i; } //By Ref { static struct SS1 { int j; S s; alias s this; } S s = void; SS1 ss = SS1(1, S(2)); emplace(&s, ss); assert(s.i == 2); } //By Value { static struct SS2 { int j; S s; S foo() @property{return s;} alias foo this; } S s = void; SS2 ss = SS2(1, S(2)); emplace(&s, ss); assert(s.i == 2); } } version(unittest) { //Ambiguity struct __std_conv_S { int i; this(__std_conv_SS ss) {assert(0);} static opCall(__std_conv_SS ss) { __std_conv_S s; s.i = ss.j; return s; } } struct __std_conv_SS { int j; __std_conv_S s; ref __std_conv_S foo() return @property {s.i = j; return s;} alias foo this; } static assert(is(__std_conv_SS : __std_conv_S)); unittest { __std_conv_S s = void; __std_conv_SS ss = __std_conv_SS(1); __std_conv_S sTest1 = ss; //this calls "SS alias this" (and not "S.this(SS)") emplace(&s, ss); //"alias this" should take precedence in emplace over "opCall" assert(s.i == 1); } } //Nested classes unittest { class A{} static struct S { A a; } S s1 = void; S s2 = S(new A); emplace(&s1, s2); assert(s1.a is s2.a); } //safety & nothrow & CTFE unittest { //emplace should be safe for anything with no elaborate opassign static struct S1 { int i; } static struct S2 { int i; this(int j)@safe nothrow{i = j;} } int i; S1 s1 = void; S2 s2 = void; auto pi = &i; auto ps1 = &s1; auto ps2 = &s2; void foo() @safe nothrow { emplace(pi); emplace(pi, 5); emplace(ps1); emplace(ps1, 5); emplace(ps1, S1.init); emplace(ps2); emplace(ps2, 5); emplace(ps2, S2.init); } foo(); T bar(T)() @property { T t/+ = void+/; //CTFE void illegal emplace(&t, 5); return t; } // CTFE enum a = bar!int; static assert(a == 5); enum b = bar!S1; static assert(b.i == 5); enum c = bar!S2; static assert(c.i == 5); // runtime auto aa = bar!int; assert(aa == 5); auto bb = bar!S1; assert(bb.i == 5); auto cc = bar!S2; assert(cc.i == 5); } unittest { struct S { int[2] get(){return [1, 2];} alias get this; } struct SS { int[2] ii; } struct ISS { int[2] ii; } S s; SS ss = void; ISS iss = void; emplace(&ss, s); emplace(&iss, s); assert(ss.ii == [1, 2]); assert(iss.ii == [1, 2]); } //disable opAssign unittest { static struct S { @disable void opAssign(S); } S s; emplace(&s, S.init); } //opCall unittest { int i; //Without constructor { static struct S1 { int i; static S1 opCall(int*){assert(0);} } S1 s = void; static assert(!__traits(compiles, emplace(&s, 1))); } //With constructor { static struct S2 { int i = 0; static S2 opCall(int*){assert(0);} static S2 opCall(int){assert(0);} this(int i){this.i = i;} } S2 s = void; emplace(&s, 1); assert(s.i == 1); } //With postblit ambiguity { static struct S3 { int i = 0; static S3 opCall(ref S3){assert(0);} } S3 s = void; emplace(&s, S3.init); } } unittest //@@@9559@@@ { import std.algorithm : map; import std.typecons : Nullable; import std.array: array; alias I = Nullable!int; auto ints = [0, 1, 2].map!(i => i & 1 ? I.init : I(i))(); auto asArray = array(ints); } unittest //http://forum.dlang.org/post/nxbdgtdlmwscocbiypjs@forum.dlang.org { import std.array : array; import std.datetime : SysTime, UTC; import std.math : isNaN; static struct A { double i; } static struct B { invariant() { if(j == 0) assert(a.i.isNaN(), "why is 'j' zero?? and i is not NaN?"); else assert(!a.i.isNaN()); } SysTime when; // comment this line avoid the breakage int j; A a; } B b1 = B.init; assert(&b1); // verify that default eyes invariants are ok; auto b2 = B(SysTime(0, UTC()), 1, A(1)); assert(&b2); auto b3 = B(SysTime(0, UTC()), 1, A(1)); assert(&b3); auto arr = [b2, b3]; assert(arr[0].j == 1); assert(arr[1].j == 1); auto a2 = arr.array(); // << bang, invariant is raised, also if b2 and b3 are good } //static arrays unittest { static struct S { int[2] ii; } static struct IS { immutable int[2] ii; } int[2] ii; S s = void; IS ims = void; ubyte ub = 2; emplace(&s, ub); emplace(&s, ii); emplace(&ims, ub); emplace(&ims, ii); uint[2] uu; static assert(!__traits(compiles, {S ss = S(uu);})); static assert(!__traits(compiles, emplace(&s, uu))); } unittest { int[2] sii; int[2] sii2; uint[2] uii; uint[2] uii2; emplace(&sii, 1); emplace(&sii, 1U); emplace(&uii, 1); emplace(&uii, 1U); emplace(&sii, sii2); //emplace(&sii, uii2); //Sorry, this implementation doesn't know how to... //emplace(&uii, sii2); //Sorry, this implementation doesn't know how to... emplace(&uii, uii2); emplace(&sii, sii2[]); //emplace(&sii, uii2[]); //Sorry, this implementation doesn't know how to... //emplace(&uii, sii2[]); //Sorry, this implementation doesn't know how to... emplace(&uii, uii2[]); } unittest { bool allowDestruction = false; struct S { int i; this(this){} ~this(){assert(allowDestruction);} } S s = S(1); S[2] ss1 = void; S[2] ss2 = void; S[2] ss3 = void; emplace(&ss1, s); emplace(&ss2, ss1); emplace(&ss3, ss2[]); assert(ss1[1] == s); assert(ss2[1] == s); assert(ss3[1] == s); allowDestruction = true; } unittest { //Checks postblit, construction, and context pointer int count = 0; struct S { this(this) { ++count; } ~this() { --count; } } S s; { S[4] ss = void; emplace(&ss, s); assert(count == 4); } assert(count == 0); } unittest { struct S { int i; } S s; S[2][2][2] sss = void; emplace(&sss, s); } unittest //Constness { import std.stdio; int a = void; emplaceRef!(const int)(a, 5); immutable i = 5; const(int)* p = void; emplaceRef!(const int*)(p, &i); struct S { int* p; } alias IS = immutable(S); S s = void; emplaceRef!IS(s, IS()); S[2] ss = void; emplaceRef!(IS[2])(ss, IS()); IS[2] iss = IS.init; emplaceRef!(IS[2])(ss, iss); emplaceRef!(IS[2])(ss, iss[]); } pure nothrow @safe @nogc unittest { int i; emplaceRef(i); emplaceRef!int(i); emplaceRef(i, 5); emplaceRef!int(i, 5); } // Test attribute propagation for UDTs pure nothrow @safe /* @nogc */ unittest { static struct Safe { this(this) pure nothrow @safe @nogc {} } Safe safe = void; emplaceRef(safe, Safe()); Safe[1] safeArr = [Safe()]; Safe[1] uninitializedSafeArr = void; emplaceRef(uninitializedSafeArr, safe); emplaceRef(uninitializedSafeArr, safeArr); static struct Unsafe { this(this) @system {} } Unsafe unsafe = void; static assert(!__traits(compiles, emplaceRef(unsafe, Unsafe()))); Unsafe[1] unsafeArr = [Unsafe()]; Unsafe[1] uninitializedUnsafeArr = void; static assert(!__traits(compiles, emplaceRef(uninitializedUnsafeArr, unsafe))); static assert(!__traits(compiles, emplaceRef(uninitializedUnsafeArr, unsafeArr))); } unittest { // Issue 15313 static struct Node { int payload; Node* next; uint refs; } import core.stdc.stdlib : malloc; void[] buf = malloc(Node.sizeof)[0 .. Node.sizeof]; import std.conv : emplace; const Node* n = emplace!(const Node)(buf, 42, null, 10); assert(n.payload == 42); assert(n.next == null); assert(n.refs == 10); } unittest { int var = 6; auto k = emplace!__conv_EmplaceTest(new void[__conv_EmplaceTest.sizeof], 5, var); assert(k.i == 5); assert(var == 7); } unittest { class A { int x = 5; int y = 42; this(int z) { assert(x == 5 && y == 42); x = y = z; } } void[] buf; static byte[__traits(classInstanceSize, A)] sbuf; buf = sbuf[]; auto a = emplace!A(buf, 55); assert(a.x == 55 && a.y == 55); // emplace in bigger buffer buf = new byte[](__traits(classInstanceSize, A) + 10); a = emplace!A(buf, 55); assert(a.x == 55 && a.y == 55); // need ctor args static assert(!is(typeof(emplace!A(buf)))); } // Bulk of emplace unittests ends here unittest { import std.algorithm : equal, map; // Check fix for http://d.puremagic.com/issues/show_bug.cgi?id=2971 assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345])); } // Undocumented for the time being void toTextRange(T, W)(T value, W writer) if (isIntegral!T && isOutputRange!(W, char)) { char[value.sizeof * 4] buffer = void; uint i = cast(uint) (buffer.length - 1); bool negative = value < 0; Unqual!(Unsigned!T) v = negative ? -value : value; while (v >= 10) { auto c = cast(uint) (v % 10); v /= 10; buffer[i--] = cast(char) (c + '0'); } buffer[i] = cast(char) (v + '0'); //hexDigits[cast(uint) v]; if (negative) buffer[--i] = '-'; put(writer, buffer[i .. $]); } unittest { import std.array : appender; auto result = appender!(char[])(); toTextRange(-1, result); assert(result.data == "-1"); } /** Returns the corresponding _unsigned value for $(D x) (e.g. if $(D x) has type $(D int), it returns $(D cast(uint) x)). The advantage compared to the cast is that you do not need to rewrite the cast if $(D x) later changes type (e.g from $(D int) to $(D long)). Note that the result is always mutable even if the original type was const or immutable. In order to retain the constness, use $(XREF traits, Unsigned). */ auto unsigned(T)(T x) if (isIntegral!T) { return cast(Unqual!(Unsigned!T))x; } /// unittest { immutable int s = 42; auto u1 = unsigned(s); //not qualified static assert(is(typeof(u1) == uint)); Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification static assert(is(typeof(u2) == immutable uint)); immutable u3 = unsigned(s); //explicitly qualified } unittest { foreach(T; AliasSeq!(byte, ubyte)) { static assert(is(typeof(unsigned(cast(T)1)) == ubyte)); static assert(is(typeof(unsigned(cast(const T)1)) == ubyte)); static assert(is(typeof(unsigned(cast(immutable T)1)) == ubyte)); } foreach(T; AliasSeq!(short, ushort)) { static assert(is(typeof(unsigned(cast(T)1)) == ushort)); static assert(is(typeof(unsigned(cast(const T)1)) == ushort)); static assert(is(typeof(unsigned(cast(immutable T)1)) == ushort)); } foreach(T; AliasSeq!(int, uint)) { static assert(is(typeof(unsigned(cast(T)1)) == uint)); static assert(is(typeof(unsigned(cast(const T)1)) == uint)); static assert(is(typeof(unsigned(cast(immutable T)1)) == uint)); } foreach(T; AliasSeq!(long, ulong)) { static assert(is(typeof(unsigned(cast(T)1)) == ulong)); static assert(is(typeof(unsigned(cast(const T)1)) == ulong)); static assert(is(typeof(unsigned(cast(immutable T)1)) == ulong)); } } auto unsigned(T)(T x) if (isSomeChar!T) { // All characters are unsigned static assert(T.min == 0); return cast(Unqual!T) x; } unittest { foreach(T; AliasSeq!(char, wchar, dchar)) { static assert(is(typeof(unsigned(cast(T)'A')) == T)); static assert(is(typeof(unsigned(cast(const T)'A')) == T)); static assert(is(typeof(unsigned(cast(immutable T)'A')) == T)); } } /** Returns the corresponding _signed value for $(D x) (e.g. if $(D x) has type $(D uint), it returns $(D cast(int) x)). The advantage compared to the cast is that you do not need to rewrite the cast if $(D x) later changes type (e.g from $(D uint) to $(D ulong)). Note that the result is always mutable even if the original type was const or immutable. In order to retain the constness, use $(XREF traits, Signed). */ auto signed(T)(T x) if (isIntegral!T) { return cast(Unqual!(Signed!T))x; } /// unittest { immutable uint u = 42; auto s1 = signed(u); //not qualified static assert(is(typeof(s1) == int)); Signed!(typeof(u)) s2 = signed(u); //same qualification static assert(is(typeof(s2) == immutable int)); immutable s3 = signed(u); //explicitly qualified } unittest { foreach(T; AliasSeq!(byte, ubyte)) { static assert(is(typeof(signed(cast(T)1)) == byte)); static assert(is(typeof(signed(cast(const T)1)) == byte)); static assert(is(typeof(signed(cast(immutable T)1)) == byte)); } foreach(T; AliasSeq!(short, ushort)) { static assert(is(typeof(signed(cast(T)1)) == short)); static assert(is(typeof(signed(cast(const T)1)) == short)); static assert(is(typeof(signed(cast(immutable T)1)) == short)); } foreach(T; AliasSeq!(int, uint)) { static assert(is(typeof(signed(cast(T)1)) == int)); static assert(is(typeof(signed(cast(const T)1)) == int)); static assert(is(typeof(signed(cast(immutable T)1)) == int)); } foreach(T; AliasSeq!(long, ulong)) { static assert(is(typeof(signed(cast(T)1)) == long)); static assert(is(typeof(signed(cast(const T)1)) == long)); static assert(is(typeof(signed(cast(immutable T)1)) == long)); } } unittest { // issue 10874 enum Test { a = 0 } ulong l = 0; auto t = l.to!Test; } /** A wrapper on top of the built-in cast operator that allows one to restrict casting of the original type of the value. A common issue with using a raw cast is that it may silently continue to compile even if the value's type has changed during refactoring, which breaks the initial assumption about the cast. Params: From = The type to cast from. The programmer must ensure it is legal to make this cast. */ template castFrom(From) { /** Params: To = The type _to cast _to. value = The value _to cast. It must be of type $(D From), otherwise a compile-time error is emitted. Returns: the value after the cast, returned by reference if possible. */ auto ref to(To, T)(auto ref T value) @system { static assert ( is(From == T), "the value to cast is not of specified type '" ~ From.stringof ~ "', it is of type '" ~ T.stringof ~ "'" ); static assert ( is(typeof(cast(To)value)), "can't cast from '" ~ From.stringof ~ "' to '" ~ To.stringof ~ "'" ); return cast(To) value; } /// unittest { // Regular cast, which has been verified to be legal by the programmer: { long x; auto y = cast(int) x; } // However this will still compile if 'x' is changed to be a pointer: { long* x; auto y = cast(int) x; } // castFrom provides a more reliable alternative to casting: { long x; auto y = castFrom!long.to!int(x); } // Changing the type of 'x' will now issue a compiler error, // allowing bad casts to be caught before it's too late: { long* x; static assert ( !__traits(compiles, castFrom!long.to!int(x)) ); // if cast is still needed, must be changed to: auto y = castFrom!(long*).to!int(x); } } } /** Check the correctness of a string for $(D hexString). The result is true if and only if the input string is composed of whitespace characters (\f\n\r\t\v lineSep paraSep nelSep) and an even number of hexadecimal digits (regardless of the case). */ private bool isHexLiteral(String)(in String hexData) { import std.ascii : isHexDigit; import std.uni : lineSep, paraSep, nelSep; size_t i; foreach(const dchar c; hexData) { switch (c) { case ' ': case '\t': case '\v': case '\f': case '\r': case '\n': case lineSep: case paraSep: case nelSep: continue; default: break; } if (c.isHexDigit) ++i; else return false; } return !(i & 1); } /// unittest { // test all the hex digits static assert( ("0123456789abcdefABCDEF").isHexLiteral); // empty or white strings are not valid static assert( "\r\n\t".isHexLiteral); // but are accepted if the count of hex digits is even static assert( "A\r\n\tB".isHexLiteral); } unittest { import std.ascii; // empty/whites static assert( "".isHexLiteral); static assert( " \r".isHexLiteral); static assert( whitespace.isHexLiteral); static assert( ""w.isHexLiteral); static assert( " \r"w.isHexLiteral); static assert( ""d.isHexLiteral); static assert( " \r"d.isHexLiteral); static assert( "\u2028\u2029\u0085"d.isHexLiteral); // odd x strings static assert( !("5" ~ whitespace).isHexLiteral); static assert( !"123".isHexLiteral); static assert( !"1A3".isHexLiteral); static assert( !"1 23".isHexLiteral); static assert( !"\r\n\tC".isHexLiteral); static assert( !"123"w.isHexLiteral); static assert( !"1A3"w.isHexLiteral); static assert( !"1 23"w.isHexLiteral); static assert( !"\r\n\tC"w.isHexLiteral); static assert( !"123"d.isHexLiteral); static assert( !"1A3"d.isHexLiteral); static assert( !"1 23"d.isHexLiteral); static assert( !"\r\n\tC"d.isHexLiteral); // even x strings with invalid charset static assert( !"12gG".isHexLiteral); static assert( !"2A 3q".isHexLiteral); static assert( !"12gG"w.isHexLiteral); static assert( !"2A 3q"w.isHexLiteral); static assert( !"12gG"d.isHexLiteral); static assert( !"2A 3q"d.isHexLiteral); // valid x strings static assert( ("5A" ~ whitespace).isHexLiteral); static assert( ("5A 01A C FF de 1b").isHexLiteral); static assert( ("0123456789abcdefABCDEF").isHexLiteral); static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF").isHexLiteral); static assert( ("5A 01A C FF de 1b"w).isHexLiteral); static assert( ("0123456789abcdefABCDEF"w).isHexLiteral); static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"w).isHexLiteral); static assert( ("5A 01A C FF de 1b"d).isHexLiteral); static assert( ("0123456789abcdefABCDEF"d).isHexLiteral); static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"d).isHexLiteral); // library version allows what's pointed by issue 10454 static assert( ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").isHexLiteral); } /** Converts a hex literal to a string at compile time. Takes a string made of hexadecimal digits and returns the matching string by converting each pair of digits to a character. The input string can also include white characters, which can be used to keep the literal string readable in the source code. The function is intended to replace the hexadecimal literal strings starting with $(D 'x'), which could be removed to simplify the core language. Params: hexData = string to be converted. Returns: a $(D string), a $(D wstring) or a $(D dstring), according to the type of hexData. */ template hexString(string hexData) if (hexData.isHexLiteral) { immutable hexString = hexStrImpl(hexData); } /// ditto template hexString(wstring hexData) if (hexData.isHexLiteral) { immutable hexString = hexStrImpl(hexData); } /// ditto template hexString(dstring hexData) if (hexData.isHexLiteral) { immutable hexString = hexStrImpl(hexData); } /// unittest { // conversion at compile time auto string1 = hexString!"304A314B"; assert(string1 == "0J1K"); auto string2 = hexString!"304A314B"w; assert(string2 == "0J1K"w); auto string3 = hexString!"304A314B"d; assert(string3 == "0J1K"d); } /* Takes a hexadecimal string literal and returns its representation. hexData is granted to be a valid string by the caller. C is granted to be a valid char type by the caller. */ @safe nothrow pure private auto hexStrImpl(String)(String hexData) { import std.ascii; alias C = Unqual!(ElementEncodingType!String); C[] result; result.length = hexData.length / 2; size_t cnt; ubyte v; foreach(c; hexData) { if (c.isHexDigit) { ubyte x; if (c >= '0' && c <= '9') x = cast(ubyte)(c - '0'); else if (c >= 'a' && c <= 'f') x = cast(ubyte)(c - ('a' - 10)); else if (c >= 'A' && c <= 'F') x = cast(ubyte)(c - ('A' - 10)); if (cnt & 1) { v = cast(ubyte)((v << 4) | x); result[cnt / 2] = v; } else v = x; ++cnt; } } result.length = cnt / 2; return result; } unittest { // compile time assert(hexString!"46 47 48 49 4A 4B" == "FGHIJK"); assert(hexString!"30\r\n\t\f\v31 32 33 32 31 30" == "0123210"); assert(hexString!"ab cd" == hexString!"ABCD"); } /** * Convert integer to a range of characters. * Intended to be lightweight and fast. * * Params: * radix = 2, 8, 10, 16 * Char = character type for output * letterCase = lower for deadbeef, upper for DEADBEEF * value = integer to convert. Can be uint or ulong. If radix is 10, can also be * int or long. * Returns: * Random access range with slicing and everything */ auto toChars(ubyte radix = 10, Char = char, LetterCase letterCase = LetterCase.lower, T)(T value) pure nothrow @nogc @safe if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) && (is(Unqual!T == uint) || is(Unqual!T == ulong) || radix == 10 && (is(Unqual!T == int) || is(Unqual!T == long)))) { alias UT = Unqual!T; static if (radix == 10) { /* uint.max is 42_9496_7295 * int.max is 21_4748_3647 * ulong.max is 1844_6744_0737_0955_1615 * long.max is 922_3372_0368_5477_5807 */ static struct Result { void initialize(UT value) { bool neg = false; if (value < 10) { if (value >= 0) { lwr = 0; upr = 1; buf[0] = cast(char)(cast(uint)value + '0'); return; } value = -value; neg = true; } auto i = cast(uint)buf.length - 1; while (cast(Unsigned!UT)value >= 10) { buf[i] = cast(ubyte)('0' + cast(Unsigned!UT)value % 10); value = unsigned(value) / 10; --i; } buf[i] = cast(char)(cast(uint)value + '0'); if (neg) { buf[i - 1] = '-'; --i; } lwr = i; upr = cast(uint)buf.length; } @property size_t length() { return upr - lwr; } @property bool empty() { return upr == lwr; } @property Char front() { return buf[lwr]; } void popFront() { ++lwr; } @property Char back() { return buf[upr - 1]; } void popBack() { --upr; } @property Result save() { return this; } Char opIndex(size_t i) { return buf[lwr + i]; } Result opSlice(size_t lwr, size_t upr) { Result result = void; result.buf = buf; result.lwr = cast(uint)(this.lwr + lwr); result.upr = cast(uint)(this.lwr + upr); return result; } private: uint lwr = void, upr = void; char[(UT.sizeof == 4) ? 10 + isSigned!T : 20] buf = void; } Result result = void; result.initialize(value); return result; } else { static if (radix == 2) enum SHIFT = 1; else static if (radix == 8) enum SHIFT = 3; else static if (radix == 16) enum SHIFT = 4; else static assert(0); static struct Result { this(UT value) { this.value = value; ubyte len = 1; while (value >>>= SHIFT) ++len; this.len = len; } @property size_t length() { return len; } @property bool empty() { return len == 0; } @property Char front() { return opIndex(0); } void popFront() { --len; } @property Char back() { return opIndex(len - 1); } void popBack() { value >>>= SHIFT; --len; } @property Result save() { return this; } Char opIndex(size_t i) { Char c = (value >>> ((len - i - 1) * SHIFT)) & ((1 << SHIFT) - 1); return cast(Char)((radix < 10 || c < 10) ? c + '0' : (letterCase == LetterCase.upper ? c + 'A' - 10 : c + 'a' - 10)); } Result opSlice(size_t lwr, size_t upr) { Result result = void; result.value = value >>> ((len - upr) * SHIFT); result.len = cast(ubyte)(upr - lwr); return result; } private: UT value; ubyte len; } return Result(value); } } unittest { import std.array; import std.range; { assert(toChars!2(0u).array == "0"); assert(toChars!2(0Lu).array == "0"); assert(toChars!2(1u).array == "1"); assert(toChars!2(1Lu).array == "1"); auto r = toChars!2(2u); assert(r.length == 2); assert(r[0] == '1'); assert(r[1..2].array == "0"); auto s = r.save; assert(r.array == "10"); assert(s.retro.array == "01"); } { assert(toChars!8(0u).array == "0"); assert(toChars!8(0Lu).array == "0"); assert(toChars!8(1u).array == "1"); assert(toChars!8(1234567Lu).array == "4553207"); auto r = toChars!8(8u); assert(r.length == 2); assert(r[0] == '1'); assert(r[1..2].array == "0"); auto s = r.save; assert(r.array == "10"); assert(s.retro.array == "01"); } { assert(toChars!10(0u).array == "0"); assert(toChars!10(0Lu).array == "0"); assert(toChars!10(1u).array == "1"); assert(toChars!10(1234567Lu).array == "1234567"); assert(toChars!10(uint.max).array == "4294967295"); assert(toChars!10(ulong.max).array == "18446744073709551615"); auto r = toChars(10u); assert(r.length == 2); assert(r[0] == '1'); assert(r[1..2].array == "0"); auto s = r.save; assert(r.array == "10"); assert(s.retro.array == "01"); } { assert(toChars!10(0).array == "0"); assert(toChars!10(0L).array == "0"); assert(toChars!10(1).array == "1"); assert(toChars!10(1234567L).array == "1234567"); assert(toChars!10(int.max).array == "2147483647"); assert(toChars!10(long.max).array == "9223372036854775807"); assert(toChars!10(-int.max).array == "-2147483647"); assert(toChars!10(-long.max).array == "-9223372036854775807"); assert(toChars!10(int.min).array == "-2147483648"); assert(toChars!10(long.min).array == "-9223372036854775808"); auto r = toChars!10(10); assert(r.length == 2); assert(r[0] == '1'); assert(r[1..2].array == "0"); auto s = r.save; assert(r.array == "10"); assert(s.retro.array == "01"); } { assert(toChars!(16)(0u).array == "0"); assert(toChars!(16)(0Lu).array == "0"); assert(toChars!(16)(10u).array == "a"); assert(toChars!(16, char, LetterCase.upper)(0x12AF34567Lu).array == "12AF34567"); auto r = toChars!(16)(16u); assert(r.length == 2); assert(r[0] == '1'); assert(r[1..2].array == "0"); auto s = r.save; assert(r.array == "10"); assert(s.retro.array == "01"); } } unittest // opSlice (issue 16192) { import std.meta: AliasSeq; static struct Test { ubyte radix; uint number; } alias tests = AliasSeq!( Test(2, 0b1_0110_0111u), Test(2, 0b10_1100_1110u), Test(8, octal!123456701u), Test(8, octal!1234567012u), Test(10, 123456789u), Test(10, 1234567890u), Test(16, 0x789ABCDu), Test(16, 0x789ABCDEu), ); foreach (test; tests) { enum ubyte radix = test.radix; auto original = toChars!radix(test.number); // opSlice vs popFront auto r = original.save; size_t i = 0; for (; !r.empty; r.popFront(), ++i) { assert(original[i .. original.length].tupleof == r.tupleof); // tupleof is used to work around issue 16216. } // opSlice vs popBack r = original.save; i = 0; for (; !r.empty; r.popBack(), ++i) { assert(original[0 .. original.length - i].tupleof == r.tupleof); } // opSlice vs both popFront and popBack r = original.save; i = 0; for (; r.length >= 2; r.popFront(), r.popBack(), ++i) { assert(original[i .. original.length - i].tupleof == r.tupleof); } } } ldc-1.1.0-beta3-src/runtime/phobos/std/c/0000775000175000017500000000000012776215007016130 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/c/stdio.d0000664000175000017500000000066112776215007017422 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.stdio) instead. This module will be * removed in June 2017.) * * C's <stdio.h> for the D programming language * Authors: Walter Bright, Digital Mars, http://www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCStdio */ deprecated("Import core.stdc.stdio instead") module std.c.stdio; public import core.stdc.stdio; ldc-1.1.0-beta3-src/runtime/phobos/std/c/math.d0000664000175000017500000000060512776215007017227 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.math) instead. This module will be * removed in June 2017.) * * C's <math.h> * Authors: Walter Bright, Digital Mars, www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCMath */ deprecated("Import core.stdc.math instead") module std.c.math; public import core.stdc.math; ldc-1.1.0-beta3-src/runtime/phobos/std/c/stddef.d0000664000175000017500000000063012776215007017545 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.stddef) instead. This module will be * removed in June 2017.) * * C's <stddef.h> * Authors: Walter Bright, Digital Mars, http://www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCStddef */ deprecated("Import core.stdc.stddef instead") module std.c.stddef; public import core.stdc.stddef; ldc-1.1.0-beta3-src/runtime/phobos/std/c/windows/0000775000175000017500000000000012776215007017622 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/c/windows/stat.d0000664000175000017500000000053212776215007020742 0ustar kaikai /// Placed into public domain /// Author: Walter Bright // @@@DEPRECATED_2017-06@@@ /++ $(RED Deprecated. Use $(D core.sys.windows.stat) instead. This module will be removed in June 2017.) +/ deprecated("Import core.sys.windows.stat instead") module std.c.windows.stat; version (Windows): public import core.sys.windows.stat; ldc-1.1.0-beta3-src/runtime/phobos/std/c/windows/windows.d0000664000175000017500000000063112776215007021461 0ustar kaikai /* Windows is a registered trademark of Microsoft Corporation in the United States and other countries. */ // @@@DEPRECATED_2017-06@@@ /++ $(RED Deprecated. Use $(D core.sys.windows.windows) instead. This module will be removed in June 2017.) +/ deprecated("Import core.sys.windows.windows instead") module std.c.windows.windows; version (Windows): public import core.sys.windows.windows; ldc-1.1.0-beta3-src/runtime/phobos/std/c/windows/winsock.d0000664000175000017500000000057212776215007021450 0ustar kaikai/* Written by Christopher E. Miller Placed into public domain. */ // @@@DEPRECATED_2017-06@@@ /++ $(RED Deprecated. Use $(D core.sys.windows.winsock2) instead. This module will be removed in June 2017.) +/ deprecated("Import core.sys.windows.winsock2 instead") module std.c.windows.winsock; version (Windows): public import core.sys.windows.winsock2; ldc-1.1.0-beta3-src/runtime/phobos/std/c/windows/com.d0000664000175000017500000000043412776215007020546 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /++ $(RED Deprecated. Use $(D core.sys.windows.com) instead. This module will be removed in June 2017.) +/ deprecated("Import core.sys.windows.com instead") module std.c.windows.com; version (Windows): public import core.sys.windows.com; ldc-1.1.0-beta3-src/runtime/phobos/std/c/stdlib.d0000664000175000017500000000107712776215007017563 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.stdlib) or $(D core.sys.posix.stdlib) * instead. This module will be removed in June 2017.) * * C's <stdlib.h> * D Programming Language runtime library * Authors: Walter Bright, Digital Mars, http://www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCStdlib */ deprecated("Import core.stdc.stdlib or core.sys.posix.stdlib instead") module std.c.stdlib; public import core.stdc.stdlib; version(Posix) public import core.sys.posix.stdlib: setenv, unsetenv; ldc-1.1.0-beta3-src/runtime/phobos/std/c/wcharh.d0000664000175000017500000000061712776215007017555 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.wchar_) instead. This module will be * removed in June 2017.) * * C's <wchar.h> * Authors: Walter Bright, Digital Mars, www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCWchar */ deprecated("Import core.stdc.wchar_ instead") module std.c.wcharh; public import core.stdc.wchar_; ldc-1.1.0-beta3-src/runtime/phobos/std/c/freebsd/0000775000175000017500000000000012776215007017542 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/c/freebsd/socket.d0000664000175000017500000000126512776215007021203 0ustar kaikai// Written in the D programming language. // @@@DEPRECATED_2017-06@@@ /++ $(RED Deprecated. Use the appropriate $(D core.sys.posix.*) modules instead. This module will be removed in June 2017.) +/ deprecated("Import the appropriate core.sys.posix.* modules instead") module std.c.freebsd.socket; version (FreeBSD): public import core.sys.posix.netdb; public import core.sys.posix.sys.socket : AF_APPLETALK, AF_IPX, SOCK_RDM, MSG_NOSIGNAL; public import core.sys.posix.netinet.in_ : IPPROTO_IGMP, IPPROTO_GGP, IPPROTO_PUP, IPPROTO_IDP, IPPROTO_ND, IPPROTO_MAX, INADDR_LOOPBACK, INADDR_NONE; ldc-1.1.0-beta3-src/runtime/phobos/std/c/time.d0000664000175000017500000000060512776215007017234 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.time) instead. This module will be * removed in June 2017.) * * C's <time.h> * Authors: Walter Bright, Digital Mars, www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCTime */ deprecated("Import core.stdc.time instead") module std.c.time; public import core.stdc.time; ldc-1.1.0-beta3-src/runtime/phobos/std/c/linux/0000775000175000017500000000000012776215007017267 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/c/linux/linux.d0000664000175000017500000000365412776215007020603 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /* Written by Walter Bright, Christopher E. Miller, and many others. * http://www.digitalmars.com/d/ * Placed into public domain. * Linux(R) is the registered trademark of Linus Torvalds in the U.S. and other * countries. */ /++ $(RED Deprecated. Use the appropriate $(D core.sys.posix.*) modules instead. This module will be removed in June 2017.) +/ deprecated("Import the appropriate core.sys.posix.* modules instead") module std.c.linux.linux; version (linux): public import core.sys.posix.pthread; extern (C) { extern __gshared { void* __libc_stack_end; int __data_start; int _end; void *_deh_beg; void *_deh_end; } } struct struct_stat64 // distinguish it from the stat() function { ulong st_dev; /// device uint __pad1; uint st_ino; /// file serial number uint st_mode; /// file mode uint st_nlink; /// link count uint st_uid; /// user ID of file's owner uint st_gid; /// user ID of group's owner ulong st_rdev; /// if device then device number uint __pad2; align(4) ulong st_size; int st_blksize; /// optimal I/O block size ulong st_blocks; /// number of allocated 512 byte blocks int st_atime; uint st_atimensec; int st_mtime; uint st_mtimensec; int st_ctime; uint st_ctimensec; ulong st_ino64; } int fstat64(int, struct_stat64*); int fstat64(in char*, struct_stat64*); public import core.sys.posix.dirent; public import core.sys.posix.dlfcn; public import core.sys.posix.fcntl; public import core.sys.posix.pwd; public import core.sys.posix.time; public import core.sys.posix.unistd; public import core.sys.posix.utime; public import core.sys.posix.sys.mman; public import core.sys.posix.sys.stat; public import core.sys.posix.sys.time; public import core.sys.posix.sys.types; public import core.sys.posix.sys.wait; ldc-1.1.0-beta3-src/runtime/phobos/std/c/linux/linuxextern.d0000664000175000017500000000073212776215007022023 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /* Written by Walter Bright. * www.digitalmars.com * Placed into public domain. * Linux(R) is the registered trademark of Linus Torvalds in the U.S. and other * countries. */ /++ $(RED Deprecated. Remove this import. This module no longer contains anything.) +/ deprecated("This module no longer contains anything. Just remove the import.") module std.c.linux.linuxextern; // No longer needed since "extern" storage class ldc-1.1.0-beta3-src/runtime/phobos/std/c/linux/tipc.d0000664000175000017500000000064112776215007020374 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.sys.linux.tipc) instead. This module will be * removed in June 2017.) * * Interface for Linux TIPC sockets, /usr/include/linux/tipc.h * * Copyright: Public Domain * License: Public Domain * Authors: Leandro Lucarella */ deprecated("Import core.sys.linux.tipc instead") module std.c.linux.tipc; public import core.sys.linux.tipc; ldc-1.1.0-beta3-src/runtime/phobos/std/c/linux/socket.d0000664000175000017500000000510112776215007020721 0ustar kaikai/* Written by Christopher E. Miller Placed into public domain. */ // @@@DEPRECATED_2017-06@@@ /++ $(RED Deprecated. Use the appropriate $(D core.sys.posix.*) modules instead. This module will be removed in June 2017.) +/ deprecated("Import the appropriate core.sys.posix.* modules instead") module std.c.linux.socket; version (linux): private import core.stdc.stdint; public import core.sys.posix.arpa.inet; public import core.sys.posix.netdb; public import core.sys.posix.netinet.tcp; public import core.sys.posix.netinet.in_; public import core.sys.posix.sys.select; public import core.sys.posix.sys.socket; extern(C): int gethostbyname_r(in char* name, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop); int gethostbyname2_r(in char* name, int af, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop); enum: int { SD_RECEIVE = 0, SD_SEND = 1, SD_BOTH = 2, } enum: int { IP_MULTICAST_LOOP = 34, IP_ADD_MEMBERSHIP = 35, IP_DROP_MEMBERSHIP = 36, // ... IPV6_ADDRFORM = 1, IPV6_PKTINFO = 2, IPV6_HOPOPTS = 3, IPV6_DSTOPTS = 4, IPV6_RTHDR = 5, IPV6_PKTOPTIONS = 6, IPV6_CHECKSUM = 7, IPV6_HOPLIMIT = 8, IPV6_NEXTHOP = 9, IPV6_AUTHHDR = 10, IPV6_MULTICAST_HOPS = 18, IPV6_ROUTER_ALERT = 22, IPV6_MTU_DISCOVER = 23, IPV6_MTU = 24, IPV6_RECVERR = 25, IPV6_V6ONLY = 26, IPV6_JOIN_ANYCAST = 27, IPV6_LEAVE_ANYCAST = 28, IPV6_IPSEC_POLICY = 34, IPV6_XFRM_POLICY = 35, } enum: int { TCP_NODELAY = 1, // Don't delay send to coalesce packets TCP_MAXSEG = 2, // Set maximum segment size TCP_CORK = 3, // Control sending of partial frames TCP_KEEPIDLE = 4, // Start keeplives after this period TCP_KEEPINTVL = 5, // Interval between keepalives TCP_KEEPCNT = 6, // Number of keepalives before death TCP_SYNCNT = 7, // Number of SYN retransmits TCP_LINGER2 = 8, // Life time of orphaned FIN-WAIT-2 state TCP_DEFER_ACCEPT = 9, // Wake up listener only when data arrive TCP_WINDOW_CLAMP = 10, // Bound advertised window TCP_INFO = 11, // Information about this connection. TCP_QUICKACK = 12, // Bock/reenable quick ACKs. TCP_CONGESTION = 13, // Congestion control algorithm. TCP_MD5SIG = 14, // TCP MD5 Signature (RFC2385) } ldc-1.1.0-beta3-src/runtime/phobos/std/c/linux/pthread.d0000664000175000017500000000104112776215007021057 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /* Written by Walter Bright, Christopher E. Miller, and many others. * www.digitalmars.com * Placed into public domain. */ /++ $(RED Deprecated. Use $(core.sys.posix.pthread) or the appropriate $(D core.sys.posix.*) modules instead. This module will be removed in June 2017.) +/ deprecated("Import core.sys.posix.pthread or the appropriate core.sys.posix.* modules instead") module std.c.linux.pthread; version (linux): import std.c.linux.linux; public import core.sys.posix.pthread; ldc-1.1.0-beta3-src/runtime/phobos/std/c/linux/termios.d0000664000175000017500000000044312776215007021117 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /++ $(RED Deprecated. Use $(D core.sys.posix.termios) instead. This module will be removed in June 2017.) +/ deprecated("Import core.sys.posix.termios instead") module std.c.linux.termios; version (linux): public import core.sys.posix.termios; ldc-1.1.0-beta3-src/runtime/phobos/std/c/locale.d0000664000175000017500000000060112776215007017531 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.locale) instead. This module will be * removed in June 2017.) * * C's <locale.h> * License: Public Domain * Standards: * ISO/IEC 9899:1999 7.11 * Macros: * WIKI=Phobos/StdCLocale */ deprecated("Import core.stdc.locale instead") module std.c.locale; public import core.stdc.locale; ldc-1.1.0-beta3-src/runtime/phobos/std/c/stdarg.d0000664000175000017500000000064112776215007017562 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.stdarg) instead. This module will be * removed in June 2017.) * * C's <stdarg.h> * Authors: Hauke Duden and Walter Bright, Digital Mars, www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCStdarg */ deprecated("Import core.stdc.stdarg instead") module std.c.stdarg; public import core.stdc.stdarg; ldc-1.1.0-beta3-src/runtime/phobos/std/c/fenv.d0000664000175000017500000000061412776215007017234 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.fenv) instead. This module will be * removed in June 2017.) * * C's <fenv.h> * Authors: Walter Bright, Digital Mars, http://www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCFenv */ deprecated("Import core.stdc.fenv instead") module std.c.fenv; public import core.stdc.fenv; ldc-1.1.0-beta3-src/runtime/phobos/std/c/osx/0000775000175000017500000000000012776215007016741 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/c/osx/socket.d0000664000175000017500000000300512776215007020374 0ustar kaikai/* Written by Christopher E. Miller Placed into public domain. */ // @@@DEPRECATED_2017-06@@@ /++ $(RED Deprecated. Use the appropriate $(D core.sys.posix.*) modules instead. This module will be removed in June 2017.) +/ deprecated("Import the appropriate core.sys.posix.* instead") module std.c.osx.socket; version (OSX): private import core.stdc.stdint; public import core.sys.posix.arpa.inet; public import core.sys.posix.netdb; public import core.sys.posix.netinet.tcp; public import core.sys.posix.netinet.in_; public import core.sys.posix.sys.select; public import core.sys.posix.sys.socket; extern(C): // Not defined in OSX, so these will be removed at the end of deprecation enum: int { SD_RECEIVE = 0, SD_SEND = 1, SD_BOTH = 2, } enum: int { IP_MULTICAST_LOOP = 11, IP_ADD_MEMBERSHIP = 12, IP_DROP_MEMBERSHIP = 13, // ... //IPV6_ADDRFORM = 1, IPV6_PKTINFO = 19, IPV6_HOPOPTS = 22, IPV6_DSTOPTS = 23, IPV6_RTHDR = 24, IPV6_PKTOPTIONS = 25, IPV6_CHECKSUM = 26, IPV6_HOPLIMIT = 20, IPV6_NEXTHOP = 21, //IPV6_AUTHHDR = 10, IPV6_MULTICAST_HOPS = 10, //IPV6_ROUTER_ALERT = 22, //IPV6_MTU_DISCOVER = 23, //IPV6_MTU = 24, //IPV6_RECVERR = 25, IPV6_V6ONLY = 27, //IPV6_JOIN_ANYCAST = 27, //IPV6_LEAVE_ANYCAST = 28, IPV6_IPSEC_POLICY = 28, //IPV6_XFRM_POLICY = 35, } ldc-1.1.0-beta3-src/runtime/phobos/std/c/string.d0000664000175000017500000000063012776215007017602 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.string) instead. This module will be * removed in June 2017.) * * C's <string.h> * Authors: Walter Bright, Digital Mars, http://www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCString */ deprecated("Import core.stdc.string instead") module std.c.string; public import core.stdc.string; ldc-1.1.0-beta3-src/runtime/phobos/std/c/process.d0000664000175000017500000000630712776215007017761 0ustar kaikai// @@@DEPRECATED_2017-06@@@ /** * $(RED Deprecated. Use $(D core.stdc.stdlib) or the appropriate * core.sys.posix.* modules instead. This module will be removed in June * 2017.) * * C's <process.h> * Authors: Walter Bright, Digital Mars, www.digitalmars.com * License: Public Domain * Macros: * WIKI=Phobos/StdCProcess */ deprecated("Import core.stdc.stdlib or the appropriate core.sys.posix.* modules instead") module std.c.process; private import core.stdc.stddef; public import core.stdc.stdlib : exit, abort, system; extern (C): //These declarations are not defined or used elsewhere. void _c_exit(); void _cexit(); void _dodtors(); int getpid(); enum { WAIT_CHILD, WAIT_GRANDCHILD } int cwait(int *,int,int); int wait(int *); int execlpe(in char *, in char *,...); //These constants are undefined elsewhere and only used in the deprecated part //of std.process. enum { _P_WAIT, _P_NOWAIT, _P_OVERLAY }; //These declarations are defined for Posix in core.sys.posix.unistd but unused //from here. void _exit(int); int execl(in char *, in char *,...); int execle(in char *, in char *,...); int execlp(in char *, in char *,...); //All of these except for execvpe are defined for Posix in core.sys.posix.unistd //and only used in the old part of std.process. int execv(in char *, in char **); int execve(in char *, in char **, in char **); int execvp(in char *, in char **); int execvpe(in char *, in char **, in char **); //All these Windows declarations are not publicly defined elsewhere and only //spawnvp is used once in a deprecated function in std.process. version (Windows) { uint _beginthread(void function(void *),uint,void *); extern (Windows) alias stdfp = uint function (void *); uint _beginthreadex(void* security, uint stack_size, stdfp start_addr, void* arglist, uint initflag, uint* thrdaddr); void _endthread(); void _endthreadex(uint); int spawnl(int, in char *, in char *,...); int spawnle(int, in char *, in char *,...); int spawnlp(int, in char *, in char *,...); int spawnlpe(int, in char *, in char *,...); int spawnv(int, in char *, in char **); int spawnve(int, in char *, in char **, in char **); int spawnvp(int, in char *, in char **); int spawnvpe(int, in char *, in char **, in char **); int _wsystem(in wchar_t *); int _wspawnl(int, in wchar_t *, in wchar_t *, ...); int _wspawnle(int, in wchar_t *, in wchar_t *, ...); int _wspawnlp(int, in wchar_t *, in wchar_t *, ...); int _wspawnlpe(int, in wchar_t *, in wchar_t *, ...); int _wspawnv(int, in wchar_t *, in wchar_t **); int _wspawnve(int, in wchar_t *, in wchar_t **, in wchar_t **); int _wspawnvp(int, in wchar_t *, in wchar_t **); int _wspawnvpe(int, in wchar_t *, in wchar_t **, in wchar_t **); int _wexecl(in wchar_t *, in wchar_t *, ...); int _wexecle(in wchar_t *, in wchar_t *, ...); int _wexeclp(in wchar_t *, in wchar_t *, ...); int _wexeclpe(in wchar_t *, in wchar_t *, ...); int _wexecv(in wchar_t *, in wchar_t **); int _wexecve(in wchar_t *, in wchar_t **, in wchar_t **); int _wexecvp(in wchar_t *, in wchar_t **); int _wexecvpe(in wchar_t *, in wchar_t **, in wchar_t **); } ldc-1.1.0-beta3-src/runtime/phobos/std/base64.d0000664000175000017500000017517612776215007017160 0ustar kaikai// Written in the D programming language. /** * Support for Base64 encoding and decoding. * * This module provides two default implementations of Base64 encoding, * $(D $(LREF Base64)) with a standard encoding alphabet, and a variant * $(D $(LREF Base64URL)) that has a modified encoding alphabet designed to be * safe for embedding in URLs and filenames. * * Both variants are implemented as instantiations of the template * $(D $(LREF Base64Impl)). Most users will not need to use this template * directly; however, it can be used to create customized Base64 encodings, * such as one that omits padding characters, or one that is safe to embed * inside a regular expression. * * Example: * ----- * ubyte[] data = [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]; * * const(char)[] encoded = Base64.encode(data); * assert(encoded == "FPucA9l+"); * * ubyte[] decoded = Base64.decode("FPucA9l+"); * assert(decoded == [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]); * ----- * * The range API is supported for both encoding and decoding: * * Example: * ----- * // Create MIME Base64 with CRLF, per line 76. * File f = File("./text.txt", "r"); * scope(exit) f.close(); * * Appender!string mime64 = appender!string; * * foreach (encoded; Base64.encoder(f.byChunk(57))) * { * mime64.put(encoded); * mime64.put("\r\n"); * } * * writeln(mime64.data); * ----- * * References: * $(WEB tools.ietf.org/html/rfc4648, RFC 4648 - The Base16, Base32, and Base64 * Data Encodings) * * Copyright: Masahiro Nakagawa 2010-. * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Masahiro Nakagawa, Daniel Murphy (Single value Encoder and Decoder) * Source: $(PHOBOSSRC std/_base64.d) * Macros: * LREF2=$(D $2) */ module std.base64; import std.exception; // enforce import std.range.primitives; // isInputRange, isOutputRange, isForwardRange, ElementType, hasLength import std.traits; // isArray // Make sure module header code examples work correctly. unittest { ubyte[] data = [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]; const(char)[] encoded = Base64.encode(data); assert(encoded == "FPucA9l+"); ubyte[] decoded = Base64.decode("FPucA9l+"); assert(decoded == [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]); } /** * Implementation of standard _Base64 encoding. * * See $(D $(LREF Base64Impl)) for a description of available methods. */ alias Base64 = Base64Impl!('+', '/'); /// unittest { ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; assert(Base64.encode(data) == "g9cwegE/"); assert(Base64.decode("g9cwegE/") == data); } /** * Variation of Base64 encoding that is safe for use in URLs and filenames. * * See $(D $(LREF Base64Impl)) for a description of available methods. */ alias Base64URL = Base64Impl!('-', '_'); /// unittest { ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; assert(Base64URL.encode(data) == "g9cwegE_"); assert(Base64URL.decode("g9cwegE_") == data); } /** * Template for implementing Base64 encoding and decoding. * * For most purposes, direct usage of this template is not necessary; instead, * this module provides two default implementations: $(D $(LREF Base64)) and * $(D $(LREF Base64URL)), that implement basic Base64 encoding and a variant * intended for use in URLs and filenames, respectively. * * Customized Base64 encoding schemes can be implemented by instantiating this * template with the appropriate arguments. For example: * * ----- * // Non-standard Base64 format for embedding in regular expressions. * alias Base64Re = Base64Impl!('!', '=', Base64.NoPadding); * ----- * * NOTE: * Encoded strings will not have any padding if the $(D Padding) parameter is * set to $(D NoPadding). */ template Base64Impl(char Map62th, char Map63th, char Padding = '=') { enum NoPadding = '\0'; /// represents no-padding encoding // Verify Base64 characters static assert(Map62th < 'A' || Map62th > 'Z', "Character '" ~ Map62th ~ "' cannot be used twice"); static assert(Map63th < 'A' || Map63th > 'Z', "Character '" ~ Map63th ~ "' cannot be used twice"); static assert(Padding < 'A' || Padding > 'Z', "Character '" ~ Padding ~ "' cannot be used twice"); static assert(Map62th < 'a' || Map62th > 'z', "Character '" ~ Map62th ~ "' cannot be used twice"); static assert(Map63th < 'a' || Map63th > 'z', "Character '" ~ Map63th ~ "' cannot be used twice"); static assert(Padding < 'a' || Padding > 'z', "Character '" ~ Padding ~ "' cannot be used twice"); static assert(Map62th < '0' || Map62th > '9', "Character '" ~ Map62th ~ "' cannot be used twice"); static assert(Map63th < '0' || Map63th > '9', "Character '" ~ Map63th ~ "' cannot be used twice"); static assert(Padding < '0' || Padding > '9', "Character '" ~ Padding ~ "' cannot be used twice"); static assert(Map62th != Map63th, "Character '" ~ Map63th ~ "' cannot be used twice"); static assert(Map62th != Padding, "Character '" ~ Padding ~ "' cannot be used twice"); static assert(Map63th != Padding, "Character '" ~ Padding ~ "' cannot be used twice"); static assert(Map62th != NoPadding, "'\\0' is not a valid Base64character"); static assert(Map63th != NoPadding, "'\\0' is not a valid Base64character"); /* Encode functions */ private immutable EncodeMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ~ Map62th ~ Map63th; /** * Calculates the length needed to store the encoded string corresponding * to an input of the given length. * * Params: * sourceLength = Length of the source array. * * Returns: * The length of a Base64 encoding of an array of the given length. */ @safe pure nothrow size_t encodeLength(in size_t sourceLength) { static if (Padding == NoPadding) return (sourceLength / 3) * 4 + (sourceLength % 3 == 0 ? 0 : sourceLength % 3 == 1 ? 2 : 3); else return (sourceLength / 3 + (sourceLength % 3 ? 1 : 0)) * 4; } /// unittest { ubyte[] data = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; // Allocate a buffer large enough to hold the encoded string. auto buf = new char[encodeLength(data.length)]; Base64.encode(data, buf); assert(buf == "Gis8TV1u"); } // ubyte[] to char[] /** * Encode $(D_PARAM source) into a $(D char[]) buffer using Base64 * encoding. * * Params: * source = The $(LINK2 std_range_primitives.html#isInputRange, input * range) to _encode. * buffer = The $(D char[]) buffer to store the encoded result. * * Returns: * The slice of $(D_PARAM buffer) that contains the encoded string. */ @trusted pure char[] encode(R1, R2)(in R1 source, R2 buffer) if (isArray!R1 && is(ElementType!R1 : ubyte) && is(R2 == char[])) in { assert(buffer.length >= encodeLength(source.length), "Insufficient buffer for encoding"); } out(result) { assert(result.length == encodeLength(source.length), "The length of result is different from Base64"); } body { immutable srcLen = source.length; if (srcLen == 0) return []; immutable blocks = srcLen / 3; immutable remain = srcLen % 3; auto bufptr = buffer.ptr; auto srcptr = source.ptr; foreach (Unused; 0..blocks) { immutable val = srcptr[0] << 16 | srcptr[1] << 8 | srcptr[2]; *bufptr++ = EncodeMap[val >> 18 ]; *bufptr++ = EncodeMap[val >> 12 & 0x3f]; *bufptr++ = EncodeMap[val >> 6 & 0x3f]; *bufptr++ = EncodeMap[val & 0x3f]; srcptr += 3; } if (remain) { immutable val = srcptr[0] << 16 | (remain == 2 ? srcptr[1] << 8 : 0); *bufptr++ = EncodeMap[val >> 18 ]; *bufptr++ = EncodeMap[val >> 12 & 0x3f]; final switch (remain) { case 2: *bufptr++ = EncodeMap[val >> 6 & 0x3f]; static if (Padding != NoPadding) *bufptr++ = Padding; break; case 1: static if (Padding != NoPadding) { *bufptr++ = Padding; *bufptr++ = Padding; } break; } } // encode method can't assume buffer length. So, slice needed. return buffer[0..bufptr - buffer.ptr]; } /// unittest { ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; char[32] buffer; // much bigger than necessary // Just to be sure... auto encodedLength = Base64.encodeLength(data.length); assert(buffer.length >= encodedLength); // encode() returns a slice to the provided buffer. auto encoded = Base64.encode(data, buffer[]); assert(encoded is buffer[0 .. encodedLength]); assert(encoded == "g9cwegE/"); } // InputRange to char[] /** * ditto */ char[] encode(R1, R2)(R1 source, R2 buffer) if (!isArray!R1 && isInputRange!R1 && is(ElementType!R1 : ubyte) && hasLength!R1 && is(R2 == char[])) in { assert(buffer.length >= encodeLength(source.length), "Insufficient buffer for encoding"); } out(result) { // @@@BUG@@@ D's DbC can't caputre an argument of function and store the result of precondition. //assert(result.length == encodeLength(source.length), "The length of result is different from Base64"); } body { immutable srcLen = source.length; if (srcLen == 0) return []; immutable blocks = srcLen / 3; immutable remain = srcLen % 3; auto bufptr = buffer.ptr; foreach (Unused; 0..blocks) { immutable v1 = source.front; source.popFront(); immutable v2 = source.front; source.popFront(); immutable v3 = source.front; source.popFront(); immutable val = v1 << 16 | v2 << 8 | v3; *bufptr++ = EncodeMap[val >> 18 ]; *bufptr++ = EncodeMap[val >> 12 & 0x3f]; *bufptr++ = EncodeMap[val >> 6 & 0x3f]; *bufptr++ = EncodeMap[val & 0x3f]; } if (remain) { size_t val = source.front << 16; if (remain == 2) { source.popFront(); val |= source.front << 8; } *bufptr++ = EncodeMap[val >> 18 ]; *bufptr++ = EncodeMap[val >> 12 & 0x3f]; final switch (remain) { case 2: *bufptr++ = EncodeMap[val >> 6 & 0x3f]; static if (Padding != NoPadding) *bufptr++ = Padding; break; case 1: static if (Padding != NoPadding) { *bufptr++ = Padding; *bufptr++ = Padding; } break; } } // @@@BUG@@@ Workaround for DbC problem. See comment on 'out'. version (unittest) assert(bufptr - buffer.ptr == encodeLength(srcLen), "The length of result is different from Base64"); // encode method can't assume buffer length. So, slice needed. return buffer[0..bufptr - buffer.ptr]; } // ubyte[] to OutputRange /** * Encodes $(D_PARAM source) into an * $(LINK2 std_range_primitives.html#isOutputRange, output range) using * Base64 encoding. * * Params: * source = The $(LINK2 std_range_primitives.html#isInputRange, input * range) to _encode. * range = The $(LINK2 std_range_primitives.html#isOutputRange, output * range) to store the encoded result. * * Returns: * The number of times the output range's $(D put) method was invoked. */ size_t encode(R1, R2)(in R1 source, auto ref R2 range) if (isArray!R1 && is(ElementType!R1 : ubyte) && !is(R2 == char[]) && isOutputRange!(R2, char)) out(result) { assert(result == encodeLength(source.length), "The number of put is different from the length of Base64"); } body { immutable srcLen = source.length; if (srcLen == 0) return 0; immutable blocks = srcLen / 3; immutable remain = srcLen % 3; auto srcptr = source.ptr; size_t pcount; foreach (Unused; 0..blocks) { immutable val = srcptr[0] << 16 | srcptr[1] << 8 | srcptr[2]; put(range, EncodeMap[val >> 18 ]); put(range, EncodeMap[val >> 12 & 0x3f]); put(range, EncodeMap[val >> 6 & 0x3f]); put(range, EncodeMap[val & 0x3f]); srcptr += 3; pcount += 4; } if (remain) { immutable val = srcptr[0] << 16 | (remain == 2 ? srcptr[1] << 8 : 0); put(range, EncodeMap[val >> 18 ]); put(range, EncodeMap[val >> 12 & 0x3f]); pcount += 2; final switch (remain) { case 2: put(range, EncodeMap[val >> 6 & 0x3f]); pcount++; static if (Padding != NoPadding) { put(range, Padding); pcount++; } break; case 1: static if (Padding != NoPadding) { put(range, Padding); put(range, Padding); pcount += 2; } break; } } return pcount; } /// unittest { struct OutputRange { char[] result; void put(const(char) ch) { result ~= ch; } } ubyte[] data = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; // This overload of encode() returns the number of calls to the output // range's put method. OutputRange output; assert(Base64.encode(data, output) == 8); assert(output.result == "Gis8TV1u"); } // InputRange to OutputRange /** * ditto */ size_t encode(R1, R2)(R1 source, auto ref R2 range) if (!isArray!R1 && isInputRange!R1 && is(ElementType!R1 : ubyte) && hasLength!R1 && !is(R2 == char[]) && isOutputRange!(R2, char)) out(result) { // @@@BUG@@@ Workaround for DbC problem. //assert(result == encodeLength(source.length), "The number of put is different from the length of Base64"); } body { immutable srcLen = source.length; if (srcLen == 0) return 0; immutable blocks = srcLen / 3; immutable remain = srcLen % 3; size_t pcount; foreach (Unused; 0..blocks) { immutable v1 = source.front; source.popFront(); immutable v2 = source.front; source.popFront(); immutable v3 = source.front; source.popFront(); immutable val = v1 << 16 | v2 << 8 | v3; put(range, EncodeMap[val >> 18 ]); put(range, EncodeMap[val >> 12 & 0x3f]); put(range, EncodeMap[val >> 6 & 0x3f]); put(range, EncodeMap[val & 0x3f]); pcount += 4; } if (remain) { size_t val = source.front << 16; if (remain == 2) { source.popFront(); val |= source.front << 8; } put(range, EncodeMap[val >> 18 ]); put(range, EncodeMap[val >> 12 & 0x3f]); pcount += 2; final switch (remain) { case 2: put(range, EncodeMap[val >> 6 & 0x3f]); pcount++; static if (Padding != NoPadding) { put(range, Padding); pcount++; } break; case 1: static if (Padding != NoPadding) { put(range, Padding); put(range, Padding); pcount += 2; } break; } } // @@@BUG@@@ Workaround for DbC problem. version (unittest) assert(pcount == encodeLength(srcLen), "The number of put is different from the length of Base64"); return pcount; } /** * Encodes $(D_PARAM source) to newly-allocated buffer. * * This convenience method alleviates the need to manually manage output * buffers. * * Params: * source = The $(LINK2 std_range_primitives.html#isInputRange, input * range) to _encode. * * Returns: * A newly-allocated $(D char[]) buffer containing the encoded string. */ @safe pure char[] encode(Range)(Range source) if (isArray!Range && is(ElementType!Range : ubyte)) { return encode(source, new char[encodeLength(source.length)]); } /// unittest { ubyte[] data = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; assert(Base64.encode(data) == "Gis8TV1u"); } /** * ditto */ char[] encode(Range)(Range source) if (!isArray!Range && isInputRange!Range && is(ElementType!Range : ubyte) && hasLength!Range) { return encode(source, new char[encodeLength(source.length)]); } /** * An $(LINK2 std_range_primitives.html#isInputRange, input range) that * iterates over the respective Base64 encodings of a range of data items. * * This range will be a $(LINK2 std_range_primitives.html#isForwardRange, * forward range) if the underlying data source is at least a forward * range. * * Note: This struct is not intended to be created in user code directly; * use the $(LREF encoder) function instead. */ struct Encoder(Range) if (isInputRange!Range && (is(ElementType!Range : const(ubyte)[]) || is(ElementType!Range : const(char)[]))) { private: Range range_; char[] buffer_, encoded_; public: this(Range range) { range_ = range; doEncoding(); } /** * Returns: * true if there is no more encoded data left. */ @property @trusted bool empty() { return range_.empty; } /** * Returns: The current chunk of encoded data. */ @property @safe nothrow char[] front() { return encoded_; } /** * Advance the range to the next chunk of encoded data. * * Throws: * $(D Base64Exception) If invoked when * $(LREF2 .Base64Impl.Encoder.empty, empty) returns $(D true). */ void popFront() { enforce(!empty, new Base64Exception("Cannot call popFront on Encoder with no data remaining")); range_.popFront(); /* * This check is very ugly. I think this is a Range's flaw. * I very strongly want the Range guideline for unified implementation. * * In this case, Encoder becomes a beautiful implementation if 'front' performs Base64 encoding. */ if (!empty) doEncoding(); } static if (isForwardRange!Range) { /** * Save the current iteration state of the range. * * This method is only available if the underlying range is a * $(LINK2 std_range_primitives.html#isForwardRange, forward * range). * * Returns: * A copy of $(D this). */ @property typeof(this) save() { typeof(return) encoder; encoder.range_ = range_.save; encoder.buffer_ = buffer_.dup; encoder.encoded_ = encoder.buffer_[0..encoded_.length]; return encoder; } } private: void doEncoding() { auto data = cast(const(ubyte)[])range_.front; auto size = encodeLength(data.length); if (size > buffer_.length) buffer_.length = size; encoded_ = encode(data, buffer_); } } /** * An $(LINK2 std_range_primitives.html#isInputRange, input range) that * iterates over the encoded bytes of the given source data. * * It will be a $(LINK2 std_range_primitives.html#isForwardRange, forward * range) if the underlying data source is at least a forward range. * * Note: This struct is not intended to be created in user code directly; * use the $(LREF encoder) function instead. */ struct Encoder(Range) if (isInputRange!Range && is(ElementType!Range : ubyte)) { private: Range range_; ubyte first; int pos, padding; public: this(Range range) { range_ = range; static if (isForwardRange!Range) range_ = range_.save; if (range_.empty) pos = -1; else popFront(); } /** * Returns: * true if there are no more encoded characters to be iterated. */ @property @safe nothrow bool empty() const { static if (Padding == NoPadding) return pos < 0; else return pos < 0 && !padding; } /** * Returns: The current encoded character. */ @property @safe nothrow ubyte front() { return first; } /** * Advance to the next encoded character. * * Throws: * $(D Base64Exception) If invoked when $(LREF2 .Base64Impl.Encoder.empty.2, * empty) returns $(D true). */ void popFront() { enforce(!empty, new Base64Exception("Cannot call popFront on Encoder with no data remaining")); static if (Padding != NoPadding) if (padding) { first = Padding; pos = -1; padding--; return; } if (range_.empty) { pos = -1; return; } final switch (pos) { case 0: first = EncodeMap[range_.front >> 2]; break; case 1: immutable t = (range_.front & 0b11) << 4; range_.popFront(); if (range_.empty) { first = EncodeMap[t]; padding = 3; } else { first = EncodeMap[t | (range_.front >> 4)]; } break; case 2: immutable t = (range_.front & 0b1111) << 2; range_.popFront(); if (range_.empty) { first = EncodeMap[t]; padding = 2; } else { first = EncodeMap[t | (range_.front >> 6)]; } break; case 3: first = EncodeMap[range_.front & 0b111111]; range_.popFront(); break; } ++pos %= 4; } static if (isForwardRange!Range) { /** * Save the current iteration state of the range. * * This method is only available if the underlying range is a * $(LINK2 std_range_primitives.html#isForwardRange, forward * range). * * Returns: * A copy of $(D this). */ @property typeof(this) save() { auto encoder = this; encoder.range_ = encoder.range_.save; return encoder; } } } /** * Construct an $(D Encoder) that iterates over the Base64 encoding of the * given $(LINK2 std_range_primitives.html#isInputRange, input range). * * Params: * range = An $(LINK2 std_range_primitives.html#isInputRange, input * range) over the data to be encoded. * * Returns: * If $(D_PARAM range) is a range of bytes, an $(D Encoder) that iterates * over the bytes of the corresponding Base64 encoding. * * If $(D_PARAM range) is a range of ranges of bytes, an $(D Encoder) that * iterates over the Base64 encoded strings of each element of the range. * * In both cases, the returned $(D Encoder) will be a * $(LINK2 std_range_primitives.html#isForwardRange, forward range) if the * given $(D range) is at least a forward range, otherwise it will be only * an input range. * * Example: * This example encodes the input one line at a time. * ----- * File f = File("text.txt", "r"); * scope(exit) f.close(); * * uint line = 0; * foreach (encoded; Base64.encoder(f.byLine())) * { * writeln(++line, ". ", encoded); * } * ----- * * Example: * This example encodes the input data one byte at a time. * ----- * ubyte[] data = cast(ubyte[]) "0123456789"; * * // The ElementType of data is not aggregation type * foreach (encoded; Base64.encoder(data)) * { * writeln(encoded); * } * ----- */ Encoder!(Range) encoder(Range)(Range range) if (isInputRange!Range) { return typeof(return)(range); } /* Decode functions */ private immutable int[char.max + 1] DecodeMap = [ 'A':0b000000, 'B':0b000001, 'C':0b000010, 'D':0b000011, 'E':0b000100, 'F':0b000101, 'G':0b000110, 'H':0b000111, 'I':0b001000, 'J':0b001001, 'K':0b001010, 'L':0b001011, 'M':0b001100, 'N':0b001101, 'O':0b001110, 'P':0b001111, 'Q':0b010000, 'R':0b010001, 'S':0b010010, 'T':0b010011, 'U':0b010100, 'V':0b010101, 'W':0b010110, 'X':0b010111, 'Y':0b011000, 'Z':0b011001, 'a':0b011010, 'b':0b011011, 'c':0b011100, 'd':0b011101, 'e':0b011110, 'f':0b011111, 'g':0b100000, 'h':0b100001, 'i':0b100010, 'j':0b100011, 'k':0b100100, 'l':0b100101, 'm':0b100110, 'n':0b100111, 'o':0b101000, 'p':0b101001, 'q':0b101010, 'r':0b101011, 's':0b101100, 't':0b101101, 'u':0b101110, 'v':0b101111, 'w':0b110000, 'x':0b110001, 'y':0b110010, 'z':0b110011, '0':0b110100, '1':0b110101, '2':0b110110, '3':0b110111, '4':0b111000, '5':0b111001, '6':0b111010, '7':0b111011, '8':0b111100, '9':0b111101, Map62th:0b111110, Map63th:0b111111, Padding:-1 ]; /** * Given a Base64 encoded string, calculates the length of the decoded * string. * * Params: * sourceLength = The length of the Base64 encoding. * * Returns: * The length of the decoded string corresponding to a Base64 encoding of * length $(D_PARAM sourceLength). */ @safe pure nothrow size_t decodeLength(in size_t sourceLength) { static if (Padding == NoPadding) return (sourceLength / 4) * 3 + (sourceLength % 4 < 2 ? 0 : sourceLength % 4 == 2 ? 1 : 2); else return (sourceLength / 4) * 3; } /// unittest { auto encoded = "Gis8TV1u"; // Allocate a sufficiently large buffer to hold to decoded result. auto buffer = new ubyte[Base64.decodeLength(encoded.length)]; Base64.decode(encoded, buffer); assert(buffer == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); } // Used in decode contracts. Calculates the actual size the decoded // result should have, taking into account trailing padding. @safe pure nothrow private size_t realDecodeLength(R)(R source) { auto expect = decodeLength(source.length); static if (Padding != NoPadding) { if (source.length % 4 == 0) { expect -= source.length == 0 ? 0 : source[$ - 2] == Padding ? 2 : source[$ - 1] == Padding ? 1 : 0; } } return expect; } // char[] to ubyte[] /** * Decodes $(D_PARAM source) into the given buffer. * * Params: * source = The $(LINK2 std_range_primitives.html#isInputRange, input * range) to _decode. * buffer = The buffer to store decoded result. * * Returns: * The slice of $(D_PARAM buffer) containing the decoded result. * * Throws: * $(D Base64Exception) if $(D_PARAM source) contains characters outside the * base alphabet of the current Base64 encoding scheme. */ @trusted pure ubyte[] decode(R1, R2)(in R1 source, R2 buffer) if (isArray!R1 && is(ElementType!R1 : dchar) && is(R2 == ubyte[]) && isOutputRange!(R2, ubyte)) in { assert(buffer.length >= decodeLength(source.length), "Insufficient buffer for decoding"); } out(result) { immutable expect = realDecodeLength(source); assert(result.length == expect, "The length of result is different from the expected length"); } body { immutable srcLen = source.length; if (srcLen == 0) return []; static if (Padding != NoPadding) enforce(srcLen % 4 == 0, new Base64Exception("Invalid length of encoded data")); immutable blocks = srcLen / 4; auto srcptr = source.ptr; auto bufptr = buffer.ptr; foreach (Unused; 0..blocks) { immutable v1 = decodeChar(*srcptr++); immutable v2 = decodeChar(*srcptr++); *bufptr++ = cast(ubyte)(v1 << 2 | v2 >> 4); immutable v3 = decodeChar(*srcptr++); if (v3 == -1) break; *bufptr++ = cast(ubyte)((v2 << 4 | v3 >> 2) & 0xff); immutable v4 = decodeChar(*srcptr++); if (v4 == -1) break; *bufptr++ = cast(ubyte)((v3 << 6 | v4) & 0xff); } static if (Padding == NoPadding) { immutable remain = srcLen % 4; if (remain) { immutable v1 = decodeChar(*srcptr++); immutable v2 = decodeChar(*srcptr++); *bufptr++ = cast(ubyte)(v1 << 2 | v2 >> 4); if (remain == 3) *bufptr++ = cast(ubyte)((v2 << 4 | decodeChar(*srcptr++) >> 2) & 0xff); } } return buffer[0..bufptr - buffer.ptr]; } /// unittest { auto encoded = "Gis8TV1u"; ubyte[32] buffer; // much bigger than necessary // Just to be sure... auto decodedLength = Base64.decodeLength(encoded.length); assert(buffer.length >= decodedLength); // decode() returns a slice of the given buffer. auto decoded = Base64.decode(encoded, buffer[]); assert(decoded is buffer[0 .. decodedLength]); assert(decoded == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); } // InputRange to ubyte[] /** * ditto */ ubyte[] decode(R1, R2)(R1 source, R2 buffer) if (!isArray!R1 && isInputRange!R1 && is(ElementType!R1 : dchar) && hasLength!R1 && is(R2 == ubyte[]) && isOutputRange!(R2, ubyte)) in { assert(buffer.length >= decodeLength(source.length), "Insufficient buffer for decoding"); } out(result) { // @@@BUG@@@ Workaround for DbC problem. //immutable expect = decodeLength(source.length) - 2; //assert(result.length >= expect, "The length of result is smaller than expected length"); } body { immutable srcLen = source.length; if (srcLen == 0) return []; static if (Padding != NoPadding) enforce(srcLen % 4 == 0, new Base64Exception("Invalid length of encoded data")); immutable blocks = srcLen / 4; auto bufptr = buffer.ptr; foreach (Unused; 0..blocks) { immutable v1 = decodeChar(source.front); source.popFront(); immutable v2 = decodeChar(source.front); source.popFront(); *bufptr++ = cast(ubyte)(v1 << 2 | v2 >> 4); immutable v3 = decodeChar(source.front); if (v3 == -1) break; *bufptr++ = cast(ubyte)((v2 << 4 | v3 >> 2) & 0xff); source.popFront(); immutable v4 = decodeChar(source.front); if (v4 == -1) break; *bufptr++ = cast(ubyte)((v3 << 6 | v4) & 0xff); source.popFront(); } static if (Padding == NoPadding) { immutable remain = srcLen % 4; if (remain) { immutable v1 = decodeChar(source.front); source.popFront(); immutable v2 = decodeChar(source.front); *bufptr++ = cast(ubyte)(v1 << 2 | v2 >> 4); if (remain == 3) { source.popFront(); *bufptr++ = cast(ubyte)((v2 << 4 | decodeChar(source.front) >> 2) & 0xff); } } } // @@@BUG@@@ Workaround for DbC problem. version (unittest) assert((bufptr - buffer.ptr) >= (decodeLength(srcLen) - 2), "The length of result is smaller than expected length"); return buffer[0..bufptr - buffer.ptr]; } // char[] to OutputRange /** * Decodes $(D_PARAM source) into a given * $(LINK2 std_range_primitives.html#isOutputRange, output range). * * Params: * source = The $(LINK2 std_range_primitives.html#isInputRange, input * range) to _decode. * range = The $(LINK2 std_range_primitives.html#isOutputRange, output * range) to store the decoded result. * * Returns: * The number of times the output range's $(D put) method was invoked. * * Throws: * $(D Base64Exception) if $(D_PARAM source) contains characters outside the * base alphabet of the current Base64 encoding scheme. */ size_t decode(R1, R2)(in R1 source, auto ref R2 range) if (isArray!R1 && is(ElementType!R1 : dchar) && !is(R2 == ubyte[]) && isOutputRange!(R2, ubyte)) out(result) { immutable expect = realDecodeLength(source); assert(result == expect, "The result of decode is different from the expected"); } body { immutable srcLen = source.length; if (srcLen == 0) return 0; static if (Padding != NoPadding) enforce(srcLen % 4 == 0, new Base64Exception("Invalid length of encoded data")); immutable blocks = srcLen / 4; auto srcptr = source.ptr; size_t pcount; foreach (Unused; 0..blocks) { immutable v1 = decodeChar(*srcptr++); immutable v2 = decodeChar(*srcptr++); put(range, cast(ubyte)(v1 << 2 | v2 >> 4)); pcount++; immutable v3 = decodeChar(*srcptr++); if (v3 == -1) break; put(range, cast(ubyte)((v2 << 4 | v3 >> 2) & 0xff)); pcount++; immutable v4 = decodeChar(*srcptr++); if (v4 == -1) break; put(range, cast(ubyte)((v3 << 6 | v4) & 0xff)); pcount++; } static if (Padding == NoPadding) { immutable remain = srcLen % 4; if (remain) { immutable v1 = decodeChar(*srcptr++); immutable v2 = decodeChar(*srcptr++); put(range, cast(ubyte)(v1 << 2 | v2 >> 4)); pcount++; if (remain == 3) { put(range, cast(ubyte)((v2 << 4 | decodeChar(*srcptr++) >> 2) & 0xff)); pcount++; } } } return pcount; } /// unittest { struct OutputRange { ubyte[] result; void put(ubyte b) { result ~= b; } } OutputRange output; // This overload of decode() returns the number of calls to put(). assert(Base64.decode("Gis8TV1u", output) == 6); assert(output.result == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); } // InputRange to OutputRange /** * ditto */ size_t decode(R1, R2)(R1 source, auto ref R2 range) if (!isArray!R1 && isInputRange!R1 && is(ElementType!R1 : dchar) && hasLength!R1 && !is(R2 == ubyte[]) && isOutputRange!(R2, ubyte)) out(result) { // @@@BUG@@@ Workaround for DbC problem. //immutable expect = decodeLength(source.length) - 2; //assert(result >= expect, "The length of result is smaller than expected length"); } body { immutable srcLen = source.length; if (srcLen == 0) return 0; static if (Padding != NoPadding) enforce(srcLen % 4 == 0, new Base64Exception("Invalid length of encoded data")); immutable blocks = srcLen / 4; size_t pcount; foreach (Unused; 0..blocks) { immutable v1 = decodeChar(source.front); source.popFront(); immutable v2 = decodeChar(source.front); source.popFront(); put(range, cast(ubyte)(v1 << 2 | v2 >> 4)); pcount++; immutable v3 = decodeChar(source.front); if (v3 == -1) break; put(range, cast(ubyte)((v2 << 4 | v3 >> 2) & 0xff)); source.popFront(); pcount++; immutable v4 = decodeChar(source.front); if (v4 == -1) break; put(range, cast(ubyte)((v3 << 6 | v4) & 0xff)); source.popFront(); pcount++; } static if (Padding == NoPadding) { immutable remain = srcLen % 4; if (remain) { immutable v1 = decodeChar(source.front); source.popFront(); immutable v2 = decodeChar(source.front); put(range, cast(ubyte)(v1 << 2 | v2 >> 4)); pcount++; if (remain == 3) { source.popFront(); put(range, cast(ubyte)((v2 << 4 | decodeChar(source.front) >> 2) & 0xff)); pcount++; } } } // @@@BUG@@@ Workaround for DbC problem. version (unittest) assert(pcount >= (decodeLength(srcLen) - 2), "The length of result is smaller than expected length"); return pcount; } /** * Decodes $(D_PARAM source) into newly-allocated buffer. * * This convenience method alleviates the need to manually manage decoding * buffers. * * Params: * source = The $(LINK2 std_range_primitives.html#isInputRange, input * range) to _decode. * * Returns: * A newly-allocated $(D ubyte[]) buffer containing the decoded string. */ @safe pure ubyte[] decode(Range)(Range source) if (isArray!Range && is(ElementType!Range : dchar)) { return decode(source, new ubyte[decodeLength(source.length)]); } /// unittest { auto data = "Gis8TV1u"; assert(Base64.decode(data) == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); } /** * ditto */ ubyte[] decode(Range)(Range source) if (!isArray!Range && isInputRange!Range && is(ElementType!Range : dchar) && hasLength!Range) { return decode(source, new ubyte[decodeLength(source.length)]); } /** * An $(LINK2 std_range_primitives.html#isInputRange, input range) that * iterates over the decoded data of a range of Base64 encodings. * * This range will be a $(LINK2 std_range_primitives.html#isForwardRange, * forward range) if the underlying data source is at least a forward * range. * * Note: This struct is not intended to be created in user code directly; * use the $(LREF decoder) function instead. */ struct Decoder(Range) if (isInputRange!Range && (is(ElementType!Range : const(char)[]) || is(ElementType!Range : const(ubyte)[]))) { private: Range range_; ubyte[] buffer_, decoded_; public: this(Range range) { range_ = range; doDecoding(); } /** * Returns: * true if there are no more elements to be iterated. */ @property @trusted bool empty() { return range_.empty; } /** * Returns: The decoding of the current element in the input. */ @property @safe nothrow ubyte[] front() { return decoded_; } /** * Advance to the next element in the input to be decoded. * * Throws: * $(D Base64Exception) if invoked when $(LREF2 .Base64Impl.Decoder.empty, * empty) returns $(D true). */ void popFront() { enforce(!empty, new Base64Exception("Cannot call popFront on Decoder with no data remaining.")); range_.popFront(); /* * I mentioned Encoder's popFront. */ if (!empty) doDecoding(); } static if (isForwardRange!Range) { /** * Saves the current iteration state. * * This method is only available if the underlying range is a * $(LINK2 std_range_primitives.html#isForwardRange, forward * range). * * Returns: A copy of $(D this). */ @property typeof(this) save() { typeof(return) decoder; decoder.range_ = range_.save; decoder.buffer_ = buffer_.dup; decoder.decoded_ = decoder.buffer_[0..decoded_.length]; return decoder; } } private: void doDecoding() { auto data = cast(const(char)[])range_.front; static if (Padding == NoPadding) { while (data.length % 4 == 1) { range_.popFront(); data ~= cast(const(char)[])range_.front; } } else { while (data.length % 4 != 0) { range_.popFront(); data ~= cast(const(char)[])range_.front; } } auto size = decodeLength(data.length); if (size > buffer_.length) buffer_.length = size; decoded_ = decode(data, buffer_); } } /** * An $(LINK2 std_range_primitives.html#isInputRange, input range) that * iterates over the bytes of data decoded from a Base64 encoded string. * * This range will be a $(LINK2 std_range_primitives.html#isForwardRange, * forward range) if the underlying data source is at least a forward * range. * * Note: This struct is not intended to be created in user code directly; * use the $(LREF decoder) function instead. */ struct Decoder(Range) if (isInputRange!Range && is(ElementType!Range : char)) { private: Range range_; ubyte first; int pos; public: this(Range range) { range_ = range; static if (isForwardRange!Range) range_ = range_.save; static if (Padding != NoPadding && hasLength!Range) enforce(range_.length % 4 == 0, new Base64Exception("Invalid length of encoded data")); if (range_.empty) pos = -1; else popFront(); } /** * Returns: * true if there are no more elements to be iterated. */ @property @safe nothrow bool empty() const { return pos < 0; } /** * Returns: The current decoded byte. */ @property @safe nothrow ubyte front() { return first; } /** * Advance to the next decoded byte. * * Throws: * $(D Base64Exception) if invoked when $(LREF2 .Base64Impl.Decoder.empty, * empty) returns $(D true). */ void popFront() { enforce(!empty, new Base64Exception("Cannot call popFront on Decoder with no data remaining")); static if (Padding == NoPadding) { bool endCondition() { return range_.empty; } } else { bool endCondition() { enforce(!range_.empty, new Base64Exception("Missing padding")); return range_.front == Padding; } } if (range_.empty || range_.front == Padding) { pos = -1; return; } final switch (pos) { case 0: enforce(!endCondition(), new Base64Exception("Premature end of data found")); immutable t = DecodeMap[range_.front] << 2; range_.popFront(); enforce(!endCondition(), new Base64Exception("Premature end of data found")); first = cast(ubyte)(t | (DecodeMap[range_.front] >> 4)); break; case 1: immutable t = (DecodeMap[range_.front] & 0b1111) << 4; range_.popFront(); if (endCondition()) { pos = -1; return; } else { first = cast(ubyte)(t | (DecodeMap[range_.front] >> 2)); } break; case 2: immutable t = (DecodeMap[range_.front] & 0b11) << 6; range_.popFront(); if (endCondition()) { pos = -1; return; } else { first = cast(ubyte)(t | DecodeMap[range_.front]); } range_.popFront(); break; } ++pos %= 3; } static if (isForwardRange!Range) { /** * Saves the current iteration state. * * This method is only available if the underlying range is a * $(LINK2 std_range_primitives.html#isForwardRange, forward * range). * * Returns: A copy of $(D this). */ @property typeof(this) save() { auto decoder = this; decoder.range_ = decoder.range_.save; return decoder; } } } /** * Construct a $(D Decoder) that iterates over the decoding of the given * Base64 encoded data. * * Params: * range = An $(LINK2 std_range_primitives.html#isInputRange, input * range) over the data to be decoded. * * Returns: * If $(D_PARAM range) is a range of characters, a $(D Decoder) that * iterates over the bytes of the corresponding Base64 decoding. * * If $(D_PARAM range) is a range of ranges of characters, a $(D Decoder) * that iterates over the decoded strings corresponding to each element of * the range. In this case, the length of each subrange must be a multiple * of 4; the returned _decoder does not keep track of Base64 decoding * state across subrange boundaries. * * In both cases, the returned $(D Decoder) will be a * $(LINK2 std_range_primitives.html#isForwardRange, forward range) if the * given $(D range) is at least a forward range, otherwise it will be only * an input range. * * If the input data contains characters not found in the base alphabet of * the current Base64 encoding scheme, the returned range may throw a * $(D Base64Exception). * * Example: * This example shows decoding over a range of input data lines. * ----- * foreach (decoded; Base64.decoder(stdin.byLine())) * { * writeln(decoded); * } * ----- * * Example: * This example shows decoding one byte at a time. * ----- * auto encoded = Base64.encoder(cast(ubyte[])"0123456789"); * foreach (n; map!q{a - '0'}(Base64.decoder(encoded))) * { * writeln(n); * } * ----- */ Decoder!(Range) decoder(Range)(Range range) if (isInputRange!Range) { return typeof(return)(range); } private: @safe pure int decodeChar()(char chr) { immutable val = DecodeMap[chr]; // enforce can't be a pure function, so I use trivial check. if (val == 0 && chr != 'A') throw new Base64Exception("Invalid character: " ~ chr); return val; } @safe pure int decodeChar()(dchar chr) { // See above comment. if (chr > 0x7f) throw new Base64Exception("Base64-encoded character must be a single byte"); return decodeChar(cast(char)chr); } } /** * Exception thrown upon encountering Base64 encoding or decoding errors. */ class Base64Exception : Exception { @safe pure nothrow this(string s, string fn = __FILE__, size_t ln = __LINE__) { super(s, fn, ln); } } unittest { import std.algorithm : sort, equal; import std.conv; import std.file; import std.stdio; alias Base64Re = Base64Impl!('!', '=', Base64.NoPadding); // Test vectors from RFC 4648 ubyte[][string] tv = [ "" :cast(ubyte[])"", "f" :cast(ubyte[])"f", "fo" :cast(ubyte[])"fo", "foo" :cast(ubyte[])"foo", "foob" :cast(ubyte[])"foob", "fooba" :cast(ubyte[])"fooba", "foobar":cast(ubyte[])"foobar" ]; { // Base64 // encode assert(Base64.encodeLength(tv[""].length) == 0); assert(Base64.encodeLength(tv["f"].length) == 4); assert(Base64.encodeLength(tv["fo"].length) == 4); assert(Base64.encodeLength(tv["foo"].length) == 4); assert(Base64.encodeLength(tv["foob"].length) == 8); assert(Base64.encodeLength(tv["fooba"].length) == 8); assert(Base64.encodeLength(tv["foobar"].length) == 8); assert(Base64.encode(tv[""]) == ""); assert(Base64.encode(tv["f"]) == "Zg=="); assert(Base64.encode(tv["fo"]) == "Zm8="); assert(Base64.encode(tv["foo"]) == "Zm9v"); assert(Base64.encode(tv["foob"]) == "Zm9vYg=="); assert(Base64.encode(tv["fooba"]) == "Zm9vYmE="); assert(Base64.encode(tv["foobar"]) == "Zm9vYmFy"); // decode assert(Base64.decodeLength(Base64.encode(tv[""]).length) == 0); assert(Base64.decodeLength(Base64.encode(tv["f"]).length) == 3); assert(Base64.decodeLength(Base64.encode(tv["fo"]).length) == 3); assert(Base64.decodeLength(Base64.encode(tv["foo"]).length) == 3); assert(Base64.decodeLength(Base64.encode(tv["foob"]).length) == 6); assert(Base64.decodeLength(Base64.encode(tv["fooba"]).length) == 6); assert(Base64.decodeLength(Base64.encode(tv["foobar"]).length) == 6); assert(Base64.decode(Base64.encode(tv[""])) == tv[""]); assert(Base64.decode(Base64.encode(tv["f"])) == tv["f"]); assert(Base64.decode(Base64.encode(tv["fo"])) == tv["fo"]); assert(Base64.decode(Base64.encode(tv["foo"])) == tv["foo"]); assert(Base64.decode(Base64.encode(tv["foob"])) == tv["foob"]); assert(Base64.decode(Base64.encode(tv["fooba"])) == tv["fooba"]); assert(Base64.decode(Base64.encode(tv["foobar"])) == tv["foobar"]); assertThrown!Base64Exception(Base64.decode("ab|c")); // Test decoding incomplete strings. RFC does not specify the correct // behavior, but the code should never throw Errors on invalid input. // decodeLength is nothrow assert(Base64.decodeLength(1) == 0); assert(Base64.decodeLength(2) <= 1); assert(Base64.decodeLength(3) <= 2); // may throw Exceptions, may not throw Errors assertThrown!Base64Exception(Base64.decode("Zg")); assertThrown!Base64Exception(Base64.decode("Zg=")); assertThrown!Base64Exception(Base64.decode("Zm8")); assertThrown!Base64Exception(Base64.decode("Zg==;")); } { // No padding // encode assert(Base64Re.encodeLength(tv[""].length) == 0); assert(Base64Re.encodeLength(tv["f"].length) == 2); assert(Base64Re.encodeLength(tv["fo"].length) == 3); assert(Base64Re.encodeLength(tv["foo"].length) == 4); assert(Base64Re.encodeLength(tv["foob"].length) == 6); assert(Base64Re.encodeLength(tv["fooba"].length) == 7); assert(Base64Re.encodeLength(tv["foobar"].length) == 8); assert(Base64Re.encode(tv[""]) == ""); assert(Base64Re.encode(tv["f"]) == "Zg"); assert(Base64Re.encode(tv["fo"]) == "Zm8"); assert(Base64Re.encode(tv["foo"]) == "Zm9v"); assert(Base64Re.encode(tv["foob"]) == "Zm9vYg"); assert(Base64Re.encode(tv["fooba"]) == "Zm9vYmE"); assert(Base64Re.encode(tv["foobar"]) == "Zm9vYmFy"); // decode assert(Base64Re.decodeLength(Base64Re.encode(tv[""]).length) == 0); assert(Base64Re.decodeLength(Base64Re.encode(tv["f"]).length) == 1); assert(Base64Re.decodeLength(Base64Re.encode(tv["fo"]).length) == 2); assert(Base64Re.decodeLength(Base64Re.encode(tv["foo"]).length) == 3); assert(Base64Re.decodeLength(Base64Re.encode(tv["foob"]).length) == 4); assert(Base64Re.decodeLength(Base64Re.encode(tv["fooba"]).length) == 5); assert(Base64Re.decodeLength(Base64Re.encode(tv["foobar"]).length) == 6); assert(Base64Re.decode(Base64Re.encode(tv[""])) == tv[""]); assert(Base64Re.decode(Base64Re.encode(tv["f"])) == tv["f"]); assert(Base64Re.decode(Base64Re.encode(tv["fo"])) == tv["fo"]); assert(Base64Re.decode(Base64Re.encode(tv["foo"])) == tv["foo"]); assert(Base64Re.decode(Base64Re.encode(tv["foob"])) == tv["foob"]); assert(Base64Re.decode(Base64Re.encode(tv["fooba"])) == tv["fooba"]); assert(Base64Re.decode(Base64Re.encode(tv["foobar"])) == tv["foobar"]); // decodeLength is nothrow assert(Base64.decodeLength(1) == 0); } { // with OutputRange import std.array; auto a = Appender!(char[])([]); auto b = Appender!(ubyte[])([]); assert(Base64.encode(tv[""], a) == 0); assert(Base64.decode(a.data, b) == 0); assert(tv[""] == b.data); a.clear(); b.clear(); assert(Base64.encode(tv["f"], a) == 4); assert(Base64.decode(a.data, b) == 1); assert(tv["f"] == b.data); a.clear(); b.clear(); assert(Base64.encode(tv["fo"], a) == 4); assert(Base64.decode(a.data, b) == 2); assert(tv["fo"] == b.data); a.clear(); b.clear(); assert(Base64.encode(tv["foo"], a) == 4); assert(Base64.decode(a.data, b) == 3); assert(tv["foo"] == b.data); a.clear(); b.clear(); assert(Base64.encode(tv["foob"], a) == 8); assert(Base64.decode(a.data, b) == 4); assert(tv["foob"] == b.data); a.clear(); b.clear(); assert(Base64.encode(tv["fooba"], a) == 8); assert(Base64.decode(a.data, b) == 5); assert(tv["fooba"] == b.data); a.clear(); b.clear(); assert(Base64.encode(tv["foobar"], a) == 8); assert(Base64.decode(a.data, b) == 6); assert(tv["foobar"] == b.data); a.clear(); b.clear(); } // @@@9543@@@ These tests were disabled because they actually relied on the input range having length. // The implementation (currently) doesn't support encoding/decoding from a length-less source. version(none) { // with InputRange // InputRange to ubyte[] or char[] auto encoded = Base64.encode(map!(to!(ubyte))(["20", "251", "156", "3", "217", "126"])); assert(encoded == "FPucA9l+"); assert(Base64.decode(map!q{a}(encoded)) == [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]); // InputRange to OutputRange auto a = Appender!(char[])([]); auto b = Appender!(ubyte[])([]); assert(Base64.encode(map!(to!(ubyte))(["20", "251", "156", "3", "217", "126"]), a) == 8); assert(a.data == "FPucA9l+"); assert(Base64.decode(map!q{a}(a.data), b) == 6); assert(b.data == [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]); } { // Encoder and Decoder { string encode_file = std.file.deleteme ~ "-testingEncoder"; std.file.write(encode_file, "\nf\nfo\nfoo\nfoob\nfooba\nfoobar"); auto witness = ["", "Zg==", "Zm8=", "Zm9v", "Zm9vYg==", "Zm9vYmE=", "Zm9vYmFy"]; auto f = File(encode_file); scope(exit) { f.close(); assert(!f.isOpen); std.file.remove(encode_file); } size_t i; foreach (encoded; Base64.encoder(f.byLine())) assert(encoded == witness[i++]); assert(i == witness.length); } { string decode_file = std.file.deleteme ~ "-testingDecoder"; std.file.write(decode_file, "\nZg==\nZm8=\nZm9v\nZm9vYg==\nZm9vYmE=\nZm9vYmFy"); auto witness = sort(tv.keys); auto f = File(decode_file); scope(exit) { f.close(); assert(!f.isOpen); std.file.remove(decode_file); } size_t i; foreach (decoded; Base64.decoder(f.byLine())) assert(decoded == witness[i++]); assert(i == witness.length); } { // ForwardRange { auto encoder = Base64.encoder(sort(tv.values)); auto witness = ["", "Zg==", "Zm8=", "Zm9v", "Zm9vYg==", "Zm9vYmE=", "Zm9vYmFy"]; size_t i; assert(encoder.front == witness[i++]); encoder.popFront(); assert(encoder.front == witness[i++]); encoder.popFront(); assert(encoder.front == witness[i++]); encoder.popFront(); foreach (encoded; encoder.save) assert(encoded == witness[i++]); } { auto decoder = Base64.decoder(["", "Zg==", "Zm8=", "Zm9v", "Zm9vYg==", "Zm9vYmE=", "Zm9vYmFy"]); auto witness = sort(tv.values); size_t i; assert(decoder.front == witness[i++]); decoder.popFront(); assert(decoder.front == witness[i++]); decoder.popFront(); assert(decoder.front == witness[i++]); decoder.popFront(); foreach (decoded; decoder.save) assert(decoded == witness[i++]); } } } { // Encoder and Decoder for single character encoding and decoding alias Base64NoPadding = Base64Impl!('+', '/', Base64.NoPadding); auto tests = [ "" : ["", "", "", ""], "f" : ["Zg==", "Zg==", "Zg", "Zg"], "fo" : ["Zm8=", "Zm8=", "Zm8", "Zm8"], "foo" : ["Zm9v", "Zm9v", "Zm9v", "Zm9v"], "foob" : ["Zm9vYg==", "Zm9vYg==", "Zm9vYg", "Zm9vYg"], "fooba" : ["Zm9vYmE=", "Zm9vYmE=", "Zm9vYmE", "Zm9vYmE"], "foobar" : ["Zm9vYmFy", "Zm9vYmFy", "Zm9vYmFy", "Zm9vYmFy"], ]; foreach (u, e; tests) { assert(equal(Base64.encoder(cast(ubyte[])u), e[0])); assert(equal(Base64.decoder(Base64.encoder(cast(ubyte[])u)), u)); assert(equal(Base64URL.encoder(cast(ubyte[])u), e[1])); assert(equal(Base64URL.decoder(Base64URL.encoder(cast(ubyte[])u)), u)); assert(equal(Base64NoPadding.encoder(cast(ubyte[])u), e[2])); assert(equal(Base64NoPadding.decoder(Base64NoPadding.encoder(cast(ubyte[])u)), u)); assert(equal(Base64Re.encoder(cast(ubyte[])u), e[3])); assert(equal(Base64Re.decoder(Base64Re.encoder(cast(ubyte[])u)), u)); } } } // Regression control for the output range ref bug in encode. unittest { struct InputRange { ubyte[] impl = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; @property bool empty() { return impl.length == 0; } @property ubyte front() { return impl[0]; } void popFront() { impl = impl[1 .. $]; } @property size_t length() { return impl.length; } } struct OutputRange { char[] result; void put(char b) { result ~= b; } } InputRange ir; OutputRange or; assert(Base64.encode(ir, or) == 8); assert(or.result == "Gis8TV1u"); // Verify that any existing workaround that uses & still works. InputRange ir2; OutputRange or2; assert(Base64.encode(ir2, &or2) == 8); assert(or2.result == "Gis8TV1u"); } // Regression control for the output range ref bug in decode. unittest { struct InputRange { const(char)[] impl = "Gis8TV1u"; @property bool empty() { return impl.length == 0; } @property dchar front() { return impl[0]; } void popFront() { impl = impl[1 .. $]; } @property size_t length() { return impl.length; } } struct OutputRange { ubyte[] result; void put(ubyte b) { result ~= b; } } InputRange ir; OutputRange or; assert(Base64.decode(ir, or) == 6); assert(or.result == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); // Verify that any existing workaround that uses & still works. InputRange ir2; OutputRange or2; assert(Base64.decode(ir2, &or2) == 6); assert(or2.result == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); } ldc-1.1.0-beta3-src/runtime/phobos/std/format.d0000664000175000017500000056230012776215007017351 0ustar kaikai// Written in the D programming language. /** This module implements the formatting functionality for strings and I/O. It's comparable to C99's $(D vsprintf()) and uses a similar _format encoding scheme. For an introductory look at $(B std._format)'s capabilities and how to use this module see the dedicated $(LINK2 http://wiki.dlang.org/Defining_custom_print_format_specifiers, DWiki article). This module centers around two functions: $(BOOKTABLE , $(TR $(TH Function Name) $(TH Description) ) $(TR $(TD $(D $(LREF formattedRead))) $(TD Reads values according to the _format string from an InputRange. )) $(TR $(TD $(D $(LREF formattedWrite))) $(TD Formats its arguments according to the _format string and puts them to an OutputRange. )) ) Please see the documentation of function $(D $(LREF formattedWrite)) for a description of the _format string. Two functions have been added for convenience: $(BOOKTABLE , $(TR $(TH Function Name) $(TH Description) ) $(TR $(TD $(D $(LREF _format))) $(TD Returns a GC-allocated string with the formatting result. )) $(TR $(TD $(D $(LREF sformat))) $(TD Puts the formatting result into a preallocated array. )) ) These two functions are publicly imported by $(LINK2 std_string.html, std.string) to be easily available. The functions $(D $(LREF formatValue)) and $(D $(LREF unformatValue)) are used for the plumbing. Macros: WIKI = Phobos/StdFormat Copyright: Copyright Digital Mars 2000-2013. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB walterbright.com, Walter Bright), $(WEB erdani.com, Andrei Alexandrescu), and Kenji Hara Source: $(PHOBOSSRC std/_format.d) */ module std.format; //debug=format; // uncomment to turn on debugging printf's import core.vararg; import std.exception; import std.meta; import std.range.primitives; import std.traits; version(CRuntime_DigitalMars) { version = DigitalMarsC; } version (DigitalMarsC) { // This is DMC's internal floating point formatting function extern (C) { extern shared char* function(int c, int flags, int precision, in real* pdval, char* buf, size_t* psl, int width) __pfloatfmt; } } /********************************************************************** * Signals a mismatch between a format and its corresponding argument. */ class FormatException : Exception { @safe pure nothrow this() { super("format error"); } @safe pure nothrow this(string msg, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null) { super(msg, fn, ln, next); } } private alias enforceFmt = enforceEx!FormatException; /********************************************************************** Interprets variadic argument list $(D args), formats them according to $(D fmt), and sends the resulting characters to $(D w). The encoding of the output is the same as $(D Char). The type $(D Writer) must satisfy $(D $(XREF_PACK range,primitives,isOutputRange)!(Writer, Char)). The variadic arguments are normally consumed in order. POSIX-style $(WEB opengroup.org/onlinepubs/009695399/functions/printf.html, positional parameter syntax) is also supported. Each argument is formatted into a sequence of chars according to the format specification, and the characters are passed to $(D w). As many arguments as specified in the format string are consumed and formatted. If there are fewer arguments than format specifiers, a $(D FormatException) is thrown. If there are more remaining arguments than needed by the format specification, they are ignored but only if at least one argument was formatted. The format string supports the formatting of array and nested array elements via the grouping format specifiers $(B %() and $(B %)). Each matching pair of $(B %() and $(B %)) corresponds with a single array argument. The enclosed sub-format string is applied to individual array elements. The trailing portion of the sub-format string following the conversion specifier for the array element is interpreted as the array delimiter, and is therefore omitted following the last array element. The $(B %|) specifier may be used to explicitly indicate the start of the delimiter, so that the preceding portion of the string will be included following the last array element. (See below for explicit examples.) Params: w = Output is sent to this writer. Typical output writers include $(XREF array,Appender!string) and $(XREF stdio,LockingTextWriter). fmt = Format string. args = Variadic argument list. Returns: Formatted number of arguments. Throws: Mismatched arguments and formats result in a $(D FormatException) being thrown. Format_String: $(I Format strings) consist of characters interspersed with $(I format specifications). Characters are simply copied to the output (such as putc) after any necessary conversion to the corresponding UTF-8 sequence. The format string has the following grammar: $(PRE $(I FormatString): $(I FormatStringItem)* $(I FormatStringItem): $(B '%%') $(B '%') $(I Position) $(I Flags) $(I Width) $(I Precision) $(I FormatChar) $(B '%$(LPAREN)') $(I FormatString) $(B '%$(RPAREN)') $(I OtherCharacterExceptPercent) $(I Position): $(I empty) $(I Integer) $(B '$') $(I Flags): $(I empty) $(B '-') $(I Flags) $(B '+') $(I Flags) $(B '#') $(I Flags) $(B '0') $(I Flags) $(B ' ') $(I Flags) $(I Width): $(I empty) $(I Integer) $(B '*') $(I Precision): $(I empty) $(B '.') $(B '.') $(I Integer) $(B '.*') $(I Integer): $(I Digit) $(I Digit) $(I Integer) $(I Digit): $(B '0')|$(B '1')|$(B '2')|$(B '3')|$(B '4')|$(B '5')|$(B '6')|$(B '7')|$(B '8')|$(B '9') $(I FormatChar): $(B 's')|$(B 'c')|$(B 'b')|$(B 'd')|$(B 'o')|$(B 'x')|$(B 'X')|$(B 'e')|$(B 'E')|$(B 'f')|$(B 'F')|$(B 'g')|$(B 'G')|$(B 'a')|$(B 'A') ) $(BOOKTABLE Flags affect formatting depending on the specifier as follows., $(TR $(TH Flag) $(TH Types affected) $(TH Semantics)) $(TR $(TD $(B '-')) $(TD numeric) $(TD Left justify the result in the field. It overrides any $(B 0) flag.)) $(TR $(TD $(B '+')) $(TD numeric) $(TD Prefix positive numbers in a signed conversion with a $(B +). It overrides any $(I space) flag.)) $(TR $(TD $(B '#')) $(TD integral ($(B 'o'))) $(TD Add to precision as necessary so that the first digit of the octal formatting is a '0', even if both the argument and the $(I Precision) are zero.)) $(TR $(TD $(B '#')) $(TD integral ($(B 'x'), $(B 'X'))) $(TD If non-zero, prefix result with $(B 0x) ($(B 0X)).)) $(TR $(TD $(B '#')) $(TD floating) $(TD Always insert the decimal point and print trailing zeros.)) $(TR $(TD $(B '0')) $(TD numeric) $(TD Use leading zeros to pad rather than spaces (except for the floating point values $(D nan) and $(D infinity)). Ignore if there's a $(I Precision).)) $(TR $(TD $(B ' ')) $(TD numeric) $(TD Prefix positive numbers in a signed conversion with a space.))) $(DL $(DT $(I Width)) $(DD Specifies the minimum field width. If the width is a $(B *), an additional argument of type $(B int), preceding the actual argument, is taken as the width. If the width is negative, it is as if the $(B -) was given as a $(I Flags) character.) $(DT $(I Precision)) $(DD Gives the precision for numeric conversions. If the precision is a $(B *), an additional argument of type $(B int), preceding the actual argument, is taken as the precision. If it is negative, it is as if there was no $(I Precision) specifier.) $(DT $(I FormatChar)) $(DD $(DL $(DT $(B 's')) $(DD The corresponding argument is formatted in a manner consistent with its type: $(DL $(DT $(B bool)) $(DD The result is $(D "true") or $(D "false").) $(DT integral types) $(DD The $(B %d) format is used.) $(DT floating point types) $(DD The $(B %g) format is used.) $(DT string types) $(DD The result is the string converted to UTF-8. A $(I Precision) specifies the maximum number of characters to use in the result.) $(DT structs) $(DD If the struct defines a $(B toString()) method the result is the string returned from this function. Otherwise the result is StructName(field0, field1, ...) where fieldn is the nth element formatted with the default format.) $(DT classes derived from $(B Object)) $(DD The result is the string returned from the class instance's $(B .toString()) method. A $(I Precision) specifies the maximum number of characters to use in the result.) $(DT unions) $(DD If the union defines a $(B toString()) method the result is the string returned from this function. Otherwise the result is the name of the union, without its contents.) $(DT non-string static and dynamic arrays) $(DD The result is [s0, s1, ...] where sn is the nth element formatted with the default format.) $(DT associative arrays) $(DD The result is the equivalent of what the initializer would look like for the contents of the associative array, e.g.: ["red" : 10, "blue" : 20].) )) $(DT $(B 'c')) $(DD The corresponding argument must be a character type.) $(DT $(B 'b','d','o','x','X')) $(DD The corresponding argument must be an integral type and is formatted as an integer. If the argument is a signed type and the $(I FormatChar) is $(B d) it is converted to a signed string of characters, otherwise it is treated as unsigned. An argument of type $(B bool) is formatted as '1' or '0'. The base used is binary for $(B b), octal for $(B o), decimal for $(B d), and hexadecimal for $(B x) or $(B X). $(B x) formats using lower case letters, $(B X) uppercase. If there are fewer resulting digits than the $(I Precision), leading zeros are used as necessary. If the $(I Precision) is 0 and the number is 0, no digits result.) $(DT $(B 'e','E')) $(DD A floating point number is formatted as one digit before the decimal point, $(I Precision) digits after, the $(I FormatChar), ±, followed by at least a two digit exponent: $(I d.dddddd)e$(I ±dd). If there is no $(I Precision), six digits are generated after the decimal point. If the $(I Precision) is 0, no decimal point is generated.) $(DT $(B 'f','F')) $(DD A floating point number is formatted in decimal notation. The $(I Precision) specifies the number of digits generated after the decimal point. It defaults to six. At least one digit is generated before the decimal point. If the $(I Precision) is zero, no decimal point is generated.) $(DT $(B 'g','G')) $(DD A floating point number is formatted in either $(B e) or $(B f) format for $(B g); $(B E) or $(B F) format for $(B G). The $(B f) format is used if the exponent for an $(B e) format is greater than -5 and less than the $(I Precision). The $(I Precision) specifies the number of significant digits, and defaults to six. Trailing zeros are elided after the decimal point, if the fractional part is zero then no decimal point is generated.) $(DT $(B 'a','A')) $(DD A floating point number is formatted in hexadecimal exponential notation 0x$(I h.hhhhhh)p$(I ±d). There is one hexadecimal digit before the decimal point, and as many after as specified by the $(I Precision). If the $(I Precision) is zero, no decimal point is generated. If there is no $(I Precision), as many hexadecimal digits as necessary to exactly represent the mantissa are generated. The exponent is written in as few digits as possible, but at least one, is in decimal, and represents a power of 2 as in $(I h.hhhhhh)*2$(I ±d). The exponent for zero is zero. The hexadecimal digits, x and p are in upper case if the $(I FormatChar) is upper case.) )) ) Floating point NaN's are formatted as $(B nan) if the $(I FormatChar) is lower case, or $(B NAN) if upper. Floating point infinities are formatted as $(B inf) or $(B infinity) if the $(I FormatChar) is lower case, or $(B INF) or $(B INFINITY) if upper. Example: ----------------- import std.array : appender; import std.format : formattedWrite; auto writer = appender!string(); formattedWrite(writer, "%s is the ultimate %s.", 42, "answer"); assert(writer.data == "42 is the ultimate answer."); // Clear the writer writer = appender!string(); formattedWrite(writer, "Date: %2$s %1$s", "October", 5); assert(writer.data == "Date: 5 October"); ----------------- The positional and non-positional styles can be mixed in the same format string. (POSIX leaves this behavior undefined.) The internal counter for non-positional parameters tracks the next parameter after the largest positional parameter already used. Example using array and nested array formatting: ------------------------- import std.stdio; void main() { writefln("My items are %(%s %).", [1,2,3]); writefln("My items are %(%s, %).", [1,2,3]); } ------------------------- The output is: $(CONSOLE My items are 1 2 3. My items are 1, 2, 3. ) The trailing end of the sub-format string following the specifier for each item is interpreted as the array delimiter, and is therefore omitted following the last array item. The $(B %|) delimiter specifier may be used to indicate where the delimiter begins, so that the portion of the format string prior to it will be retained in the last array element: ------------------------- import std.stdio; void main() { writefln("My items are %(-%s-%|, %).", [1,2,3]); } ------------------------- which gives the output: $(CONSOLE My items are -1-, -2-, -3-. ) These compound format specifiers may be nested in the case of a nested array argument: ------------------------- import std.stdio; void main() { auto mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; writefln("%(%(%d %)\n%)", mat); writeln(); writefln("[%(%(%d %)\n %)]", mat); writeln(); writefln("[%([%(%d %)]%|\n %)]", mat); writeln(); } ------------------------- The output is: $(CONSOLE 1 2 3 4 5 6 7 8 9 [1 2 3 4 5 6 7 8 9] [[1 2 3] [4 5 6] [7 8 9]] ) Inside a compound format specifier, strings and characters are escaped automatically. To avoid this behavior, add $(B '-') flag to $(D "%$(LPAREN)"). ------------------------- import std.stdio; void main() { writefln("My friends are %s.", ["John", "Nancy"]); writefln("My friends are %(%s, %).", ["John", "Nancy"]); writefln("My friends are %-(%s, %).", ["John", "Nancy"]); } ------------------------- which gives the output: $(CONSOLE My friends are ["John", "Nancy"]. My friends are "John", "Nancy". My friends are John, Nancy. ) */ uint formattedWrite(Writer, Char, A...)(Writer w, in Char[] fmt, A args) { import std.conv : text, to; alias FPfmt = void function(Writer, const(void)*, ref FormatSpec!Char) @safe pure nothrow; auto spec = FormatSpec!Char(fmt); FPfmt[A.length] funs; const(void)*[A.length] argsAddresses; if (!__ctfe) { foreach (i, Arg; A) { funs[i] = ()@trusted{ return cast(FPfmt)&formatGeneric!(Writer, Arg, Char); }(); // We can safely cast away shared because all data is either // immutable or completely owned by this function. argsAddresses[i] = (ref arg)@trusted{ return cast(const void*) &arg; }(args[i]); // Reflect formatting @safe/pure ability of each arguments to this function if (0) formatValue(w, args[i], spec); } } // Are we already done with formats? Then just dump each parameter in turn uint currentArg = 0; while (spec.writeUpToNextSpec(w)) { if (currentArg == funs.length && !spec.indexStart) { // leftover spec? enforceFmt(fmt.length == 0, text("Orphan format specifier: %", spec.spec)); break; } if (spec.width == spec.DYNAMIC) { auto width = to!(typeof(spec.width))(getNthInt(currentArg, args)); if (width < 0) { spec.flDash = true; width = -width; } spec.width = width; ++currentArg; } else if (spec.width < 0) { // means: get width as a positional parameter auto index = cast(uint) -spec.width; assert(index > 0); auto width = to!(typeof(spec.width))(getNthInt(index - 1, args)); if (currentArg < index) currentArg = index; if (width < 0) { spec.flDash = true; width = -width; } spec.width = width; } if (spec.precision == spec.DYNAMIC) { auto precision = to!(typeof(spec.precision))( getNthInt(currentArg, args)); if (precision >= 0) spec.precision = precision; // else negative precision is same as no precision else spec.precision = spec.UNSPECIFIED; ++currentArg; } else if (spec.precision < 0) { // means: get precision as a positional parameter auto index = cast(uint) -spec.precision; assert(index > 0); auto precision = to!(typeof(spec.precision))( getNthInt(index- 1, args)); if (currentArg < index) currentArg = index; if (precision >= 0) spec.precision = precision; // else negative precision is same as no precision else spec.precision = spec.UNSPECIFIED; } // Format! if (spec.indexStart > 0) { // using positional parameters! // Make the conditional compilation of this loop explicit, to avoid "statement not reachable" warnings. static if(A.length > 0) { foreach (i; spec.indexStart - 1 .. spec.indexEnd) { if (funs.length <= i) break; if (__ctfe) formatNth(w, spec, i, args); else funs[i](w, argsAddresses[i], spec); } } if (currentArg < spec.indexEnd) currentArg = spec.indexEnd; } else { if (__ctfe) formatNth(w, spec, currentArg, args); else funs[currentArg](w, argsAddresses[currentArg], spec); ++currentArg; } } return currentArg; } @safe pure unittest { import std.array; auto w = appender!string(); formattedWrite(w, "%s %d", "@safe/pure", 42); assert(w.data == "@safe/pure 42"); } /** Reads characters from input range $(D r), converts them according to $(D fmt), and writes them to $(D args). Params: r = The range to read from. fmt = The format of the data to read. args = The drain of the data read. Returns: On success, the function returns the number of variables filled. This count can match the expected number of readings or fewer, even zero, if a matching failure happens. */ uint formattedRead(R, Char, S...)(ref R r, const(Char)[] fmt, S args) { import std.typecons : isTuple; auto spec = FormatSpec!Char(fmt); static if (!S.length) { spec.readUpToNextSpec(r); enforce(spec.trailing.empty, "Trailing characters in formattedRead format string"); return 0; } else { // The function below accounts for '*' == fields meant to be // read and skipped void skipUnstoredFields() { for (;;) { spec.readUpToNextSpec(r); if (spec.width != spec.DYNAMIC) break; // must skip this field skipData(r, spec); } } skipUnstoredFields(); if (r.empty) { // Input is empty, nothing to read return 0; } alias A = typeof(*args[0]); static if (isTuple!A) { foreach (i, T; A.Types) { (*args[0])[i] = unformatValue!(T)(r, spec); skipUnstoredFields(); } } else { *args[0] = unformatValue!(A)(r, spec); } return 1 + formattedRead(r, spec.trailing, args[1 .. $]); } } /// unittest { string s = "hello!124:34.5"; string a; int b; double c; formattedRead(s, "%s!%s:%s", &a, &b, &c); assert(a == "hello" && b == 124 && c == 34.5); } unittest { import std.math; string s = " 1.2 3.4 "; double x, y, z; assert(formattedRead(s, " %s %s %s ", &x, &y, &z) == 2); assert(s.empty); assert(approxEqual(x, 1.2)); assert(approxEqual(y, 3.4)); assert(isNaN(z)); } template FormatSpec(Char) if (!is(Unqual!Char == Char)) { alias FormatSpec = FormatSpec!(Unqual!Char); } /** * A General handler for $(D printf) style format specifiers. Used for building more * specific formatting functions. */ struct FormatSpec(Char) if (is(Unqual!Char == Char)) { import std.ascii : isDigit; import std.algorithm : startsWith; import std.conv : parse, text, to; /** Minimum _width, default $(D 0). */ int width = 0; /** Precision. Its semantics depends on the argument type. For floating point numbers, _precision dictates the number of decimals printed. */ int precision = UNSPECIFIED; /** Special value for width and precision. $(D DYNAMIC) width or precision means that they were specified with $(D '*') in the format string and are passed at runtime through the varargs. */ enum int DYNAMIC = int.max; /** Special value for precision, meaning the format specifier contained no explicit precision. */ enum int UNSPECIFIED = DYNAMIC - 1; /** The actual format specifier, $(D 's') by default. */ char spec = 's'; /** Index of the argument for positional parameters, from $(D 1) to $(D ubyte.max). ($(D 0) means not used). */ ubyte indexStart; /** Index of the last argument for positional parameter range, from $(D 1) to $(D ubyte.max). ($(D 0) means not used). */ ubyte indexEnd; version(StdDdoc) { /** The format specifier contained a $(D '-') ($(D printf) compatibility). */ bool flDash; /** The format specifier contained a $(D '0') ($(D printf) compatibility). */ bool flZero; /** The format specifier contained a $(D ' ') ($(D printf) compatibility). */ bool flSpace; /** The format specifier contained a $(D '+') ($(D printf) compatibility). */ bool flPlus; /** The format specifier contained a $(D '#') ($(D printf) compatibility). */ bool flHash; // Fake field to allow compilation ubyte allFlags; } else { union { import std.bitmanip : bitfields; mixin(bitfields!( bool, "flDash", 1, bool, "flZero", 1, bool, "flSpace", 1, bool, "flPlus", 1, bool, "flHash", 1, ubyte, "", 3)); ubyte allFlags; } } /** In case of a compound format specifier starting with $(D "%$(LPAREN)") and ending with $(D "%$(RPAREN)"), $(D _nested) contains the string contained within the two separators. */ const(Char)[] nested; /** In case of a compound format specifier, $(D _sep) contains the string positioning after $(D "%|"). */ const(Char)[] sep; /** $(D _trailing) contains the rest of the format string. */ const(Char)[] trailing; /* This string is inserted before each sequence (e.g. array) formatted (by default $(D "[")). */ enum immutable(Char)[] seqBefore = "["; /* This string is inserted after each sequence formatted (by default $(D "]")). */ enum immutable(Char)[] seqAfter = "]"; /* This string is inserted after each element keys of a sequence (by default $(D ":")). */ enum immutable(Char)[] keySeparator = ":"; /* This string is inserted in between elements of a sequence (by default $(D ", ")). */ enum immutable(Char)[] seqSeparator = ", "; /** Construct a new $(D FormatSpec) using the format string $(D fmt), no processing is done until needed. */ this(in Char[] fmt) @safe pure { trailing = fmt; } bool writeUpToNextSpec(OutputRange)(OutputRange writer) { if (trailing.empty) return false; for (size_t i = 0; i < trailing.length; ++i) { if (trailing[i] != '%') continue; put(writer, trailing[0 .. i]); trailing = trailing[i .. $]; enforceFmt(trailing.length >= 2, `Unterminated format specifier: "%"`); trailing = trailing[1 .. $]; if (trailing[0] != '%') { // Spec found. Fill up the spec, and bailout fillUp(); return true; } // Doubled! Reset and Keep going i = 0; } // no format spec found put(writer, trailing); trailing = null; return false; } unittest { import std.array; auto w = appender!(char[])(); auto f = FormatSpec("abc%sdef%sghi"); f.writeUpToNextSpec(w); assert(w.data == "abc", w.data); assert(f.trailing == "def%sghi", text(f.trailing)); f.writeUpToNextSpec(w); assert(w.data == "abcdef", w.data); assert(f.trailing == "ghi"); // test with embedded %%s f = FormatSpec("ab%%cd%%ef%sg%%h%sij"); w.clear(); f.writeUpToNextSpec(w); assert(w.data == "ab%cd%ef" && f.trailing == "g%%h%sij", w.data); f.writeUpToNextSpec(w); assert(w.data == "ab%cd%efg%h" && f.trailing == "ij"); // bug4775 f = FormatSpec("%%%s"); w.clear(); f.writeUpToNextSpec(w); assert(w.data == "%" && f.trailing == ""); f = FormatSpec("%%%%%s%%"); w.clear(); while (f.writeUpToNextSpec(w)) continue; assert(w.data == "%%%"); f = FormatSpec("a%%b%%c%"); w.clear(); assertThrown!FormatException(f.writeUpToNextSpec(w)); assert(w.data == "a%b%c" && f.trailing == "%"); } private void fillUp() { // Reset content if (__ctfe) { flDash = false; flZero = false; flSpace = false; flPlus = false; flHash = false; } else { allFlags = 0; } width = 0; precision = UNSPECIFIED; nested = null; // Parse the spec (we assume we're past '%' already) for (size_t i = 0; i < trailing.length; ) { switch (trailing[i]) { case '(': // Embedded format specifier. auto j = i + 1; // Get the matching balanced paren for (uint innerParens;;) { enforceFmt(j + 1 < trailing.length, text("Incorrect format specifier: %", trailing[i .. $])); if (trailing[j++] != '%') { // skip, we're waiting for %( and %) continue; } if (trailing[j] == '-') // for %-( { ++j; // skip enforceFmt(j < trailing.length, text("Incorrect format specifier: %", trailing[i .. $])); } if (trailing[j] == ')') { if (innerParens-- == 0) break; } else if (trailing[j] == '|') { if (innerParens == 0) break; } else if (trailing[j] == '(') { ++innerParens; } } if (trailing[j] == '|') { auto k = j; for (++j;;) { if (trailing[j++] != '%') continue; if (trailing[j] == '%') ++j; else if (trailing[j] == ')') break; else throw new Exception( text("Incorrect format specifier: %", trailing[j .. $])); } nested = trailing[i + 1 .. k - 1]; sep = trailing[k + 1 .. j - 1]; } else { nested = trailing[i + 1 .. j - 1]; sep = null; // use null (issue 12135) } //this = FormatSpec(innerTrailingSpec); spec = '('; // We practically found the format specifier trailing = trailing[j + 1 .. $]; return; case '-': flDash = true; ++i; break; case '+': flPlus = true; ++i; break; case '#': flHash = true; ++i; break; case '0': flZero = true; ++i; break; case ' ': flSpace = true; ++i; break; case '*': if (isDigit(trailing[++i])) { // a '*' followed by digits and '$' is a // positional format trailing = trailing[1 .. $]; width = -parse!(typeof(width))(trailing); i = 0; enforceFmt(trailing[i++] == '$', "$ expected"); } else { // read result width = DYNAMIC; } break; case '1': .. case '9': auto tmp = trailing[i .. $]; const widthOrArgIndex = parse!uint(tmp); enforceFmt(tmp.length, text("Incorrect format specifier %", trailing[i .. $])); i = tmp.ptr - trailing.ptr; if (tmp.startsWith('$')) { // index of the form %n$ indexEnd = indexStart = to!ubyte(widthOrArgIndex); ++i; } else if (tmp.startsWith(':')) { // two indexes of the form %m:n$, or one index of the form %m:$ indexStart = to!ubyte(widthOrArgIndex); tmp = tmp[1 .. $]; if (tmp.startsWith('$')) { indexEnd = indexEnd.max; } else { indexEnd = parse!(typeof(indexEnd))(tmp); } i = tmp.ptr - trailing.ptr; enforceFmt(trailing[i++] == '$', "$ expected"); } else { // width width = to!int(widthOrArgIndex); } break; case '.': // Precision if (trailing[++i] == '*') { if (isDigit(trailing[++i])) { // a '.*' followed by digits and '$' is a // positional precision trailing = trailing[i .. $]; i = 0; precision = -parse!int(trailing); enforceFmt(trailing[i++] == '$', "$ expected"); } else { // read result precision = DYNAMIC; } } else if (trailing[i] == '-') { // negative precision, as good as 0 precision = 0; auto tmp = trailing[i .. $]; parse!int(tmp); // skip digits i = tmp.ptr - trailing.ptr; } else if (isDigit(trailing[i])) { auto tmp = trailing[i .. $]; precision = parse!int(tmp); i = tmp.ptr - trailing.ptr; } else { // "." was specified, but nothing after it precision = 0; } break; default: // this is the format char spec = cast(char) trailing[i++]; trailing = trailing[i .. $]; return; } // end switch } // end for throw new Exception(text("Incorrect format specifier: ", trailing)); } //-------------------------------------------------------------------------- private bool readUpToNextSpec(R)(ref R r) { import std.ascii : isLower, isWhite; import std.utf : stride; // Reset content if (__ctfe) { flDash = false; flZero = false; flSpace = false; flPlus = false; flHash = false; } else { allFlags = 0; } width = 0; precision = UNSPECIFIED; nested = null; // Parse the spec while (trailing.length) { if (*trailing.ptr == '%') { if (trailing.length > 1 && trailing.ptr[1] == '%') { assert(!r.empty); // Require a '%' if (r.front != '%') break; trailing = trailing[2 .. $]; r.popFront(); } else { enforce(isLower(trailing[1]) || trailing[1] == '*' || trailing[1] == '(', text("'%", trailing[1], "' not supported with formatted read")); trailing = trailing[1 .. $]; fillUp(); return true; } } else { if (trailing.ptr[0] == ' ') { while (!r.empty && isWhite(r.front)) r.popFront(); //r = std.algorithm.find!(not!(isWhite))(r); } else { enforce(!r.empty, text("parseToFormatSpec: Cannot find character `", trailing.ptr[0], "' in the input string.")); if (r.front != trailing.front) break; r.popFront(); } trailing = trailing[stride(trailing, 0) .. $]; } } return false; } private string getCurFmtStr() const { import std.array : appender; auto w = appender!string(); auto f = FormatSpec!Char("%s"); // for stringnize put(w, '%'); if (indexStart != 0) { formatValue(w, indexStart, f); put(w, '$'); } if (flDash) put(w, '-'); if (flZero) put(w, '0'); if (flSpace) put(w, ' '); if (flPlus) put(w, '+'); if (flHash) put(w, '#'); if (width != 0) formatValue(w, width, f); if (precision != FormatSpec!Char.UNSPECIFIED) { put(w, '.'); formatValue(w, precision, f); } put(w, spec); return w.data; } unittest { // issue 5237 import std.array; auto w = appender!string(); auto f = FormatSpec!char("%.16f"); f.writeUpToNextSpec(w); // dummy eating assert(f.spec == 'f'); auto fmt = f.getCurFmtStr(); assert(fmt == "%.16f"); } private const(Char)[] headUpToNextSpec() { import std.array : appender; auto w = appender!(typeof(return))(); auto tr = trailing; while (tr.length) { if (*tr.ptr == '%') { if (tr.length > 1 && tr.ptr[1] == '%') { tr = tr[2 .. $]; w.put('%'); } else break; } else { w.put(tr.front); tr.popFront(); } } return w.data; } string toString() { return text("address = ", cast(void*) &this, "\nwidth = ", width, "\nprecision = ", precision, "\nspec = ", spec, "\nindexStart = ", indexStart, "\nindexEnd = ", indexEnd, "\nflDash = ", flDash, "\nflZero = ", flZero, "\nflSpace = ", flSpace, "\nflPlus = ", flPlus, "\nflHash = ", flHash, "\nnested = ", nested, "\ntrailing = ", trailing, "\n"); } } /// @safe pure unittest { import std.array; auto a = appender!(string)(); auto fmt = "Number: %2.4e\nString: %s"; auto f = FormatSpec!char(fmt); f.writeUpToNextSpec(a); assert(a.data == "Number: "); assert(f.trailing == "\nString: %s"); assert(f.spec == 'e'); assert(f.width == 2); assert(f.precision == 4); f.writeUpToNextSpec(a); assert(a.data == "Number: \nString: "); assert(f.trailing == ""); assert(f.spec == 's'); } // Issue 14059 unittest { import std.array : appender; auto a = appender!(string)(); auto f = FormatSpec!char("%-(%s%"); // %)") assertThrown(f.writeUpToNextSpec(a)); f = FormatSpec!char("%(%-"); // %)") assertThrown(f.writeUpToNextSpec(a)); } /** Helper function that returns a $(D FormatSpec) for a single specifier given in $(D fmt) Params: fmt = A format specifier Returns: A $(D FormatSpec) with the specifier parsed. Enforces giving only one specifier to the function. */ FormatSpec!Char singleSpec(Char)(Char[] fmt) { import std.conv : text; enforce(fmt.length >= 2, new Exception("fmt must be at least 2 characters long")); enforce(fmt.front == '%', new Exception("fmt must start with a '%' character")); static struct DummyOutputRange { void put(C)(C[] buf) {} // eat elements } auto a = DummyOutputRange(); auto spec = FormatSpec!Char(fmt); //dummy write spec.writeUpToNextSpec(a); enforce(spec.trailing.empty, new Exception(text("Trailing characters in fmt string: '", spec.trailing))); return spec; } /// unittest { auto spec = singleSpec("%2.3e"); assert(spec.trailing == ""); assert(spec.spec == 'e'); assert(spec.width == 2); assert(spec.precision == 3); assertThrown(singleSpec("")); assertThrown(singleSpec("2.3e")); assertThrown(singleSpec("%2.3eTest")); } /** $(D bool)s are formatted as "true" or "false" with %s and as "1" or "0" with integral-specific format specs. Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(BooleanTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { BooleanTypeOf!T val = obj; if (f.spec == 's') { string s = val ? "true" : "false"; if (!f.flDash) { // right align if (f.width > s.length) foreach (i ; 0 .. f.width - s.length) put(w, ' '); put(w, s); } else { // left align put(w, s); if (f.width > s.length) foreach (i ; 0 .. f.width - s.length) put(w, ' '); } } else formatValue(w, cast(int) val, f); } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%s"); formatValue(w, true, spec); assert(w.data == "true"); } @safe pure unittest { assertCTFEable!( { formatTest( false, "false" ); formatTest( true, "true" ); }); } unittest { class C1 { bool val; alias val this; this(bool v){ val = v; } } class C2 { bool val; alias val this; this(bool v){ val = v; } override string toString() const { return "C"; } } formatTest( new C1(false), "false" ); formatTest( new C1(true), "true" ); formatTest( new C2(false), "C" ); formatTest( new C2(true), "C" ); struct S1 { bool val; alias val this; } struct S2 { bool val; alias val this; string toString() const { return "S"; } } formatTest( S1(false), "false" ); formatTest( S1(true), "true" ); formatTest( S2(false), "S" ); formatTest( S2(true), "S" ); } unittest { string t1 = format("[%6s] [%6s] [%-6s]", true, false, true); assert(t1 == "[ true] [ false] [true ]"); string t2 = format("[%3s] [%-2s]", true, false); assert(t2 == "[true] [false]"); } /** $(D null) literal is formatted as $(D "null"). Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(Unqual!T == typeof(null)) && !is(T == enum) && !hasToString!(T, Char)) { enforceFmt(f.spec == 's', "null"); put(w, "null"); } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%s"); formatValue(w, null, spec); assert(w.data == "null"); } @safe pure unittest { assertCTFEable!( { formatTest( null, "null" ); }); } /** Integrals are formatted like $(D printf) does. Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { alias U = IntegralTypeOf!T; U val = obj; // Extracting alias this may be impure/system/may-throw if (f.spec == 'r') { // raw write, skip all else and write the thing auto raw = (ref val)@trusted{ return (cast(const char*) &val)[0 .. val.sizeof]; }(val); if (needToSwapEndianess(f)) { foreach_reverse (c; raw) put(w, c); } else { foreach (c; raw) put(w, c); } return; } uint base = f.spec == 'x' || f.spec == 'X' ? 16 : f.spec == 'o' ? 8 : f.spec == 'b' ? 2 : f.spec == 's' || f.spec == 'd' || f.spec == 'u' ? 10 : 0; enforceFmt(base > 0, "integral"); // Forward on to formatIntegral to handle both U and const(U) // Saves duplication of code for both versions. static if (is(ucent) && (is(U == cent) || is(U == ucent))) alias C = U; else static if (isSigned!U) alias C = long; else alias C = ulong; formatIntegral(w, cast(C) val, f, base, Unsigned!U.max); } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%d"); formatValue(w, 1337, spec); assert(w.data == "1337"); } private void formatIntegral(Writer, T, Char)(Writer w, const(T) val, const ref FormatSpec!Char fs, uint base, ulong mask) { T arg = val; bool negative = (base == 10 && arg < 0); if (negative) { arg = -arg; } // All unsigned integral types should fit in ulong. static if (is(ucent) && is(typeof(arg) == ucent)) formatUnsigned(w, (cast(ucent) arg) & mask, fs, base, negative); else formatUnsigned(w, (cast(ulong) arg) & mask, fs, base, negative); } private void formatUnsigned(Writer, T, Char)(Writer w, T arg, const ref FormatSpec!Char fs, uint base, bool negative) { /* Write string: * leftpad prefix1 prefix2 zerofill digits rightpad */ /* Convert arg to digits[]. * Note that 0 becomes an empty digits[] */ char[64] buffer = void; // 64 bits in base 2 at most char[] digits; { size_t i = buffer.length; while (arg) { --i; char c = cast(char) (arg % base); arg /= base; if (c < 10) buffer[i] = cast(char)(c + '0'); else buffer[i] = cast(char)(c + (fs.spec == 'x' ? 'a' - 10 : 'A' - 10)); } digits = buffer[i .. $]; // got the digits without the sign } int precision = (fs.precision == fs.UNSPECIFIED) ? 1 : fs.precision; char padChar = 0; if (!fs.flDash) { padChar = (fs.flZero && fs.precision == fs.UNSPECIFIED) ? '0' : ' '; } // Compute prefix1 and prefix2 char prefix1 = 0; char prefix2 = 0; if (base == 10) { if (negative) prefix1 = '-'; else if (fs.flPlus) prefix1 = '+'; else if (fs.flSpace) prefix1 = ' '; } else if (base == 16 && fs.flHash && digits.length) { prefix1 = '0'; prefix2 = fs.spec == 'x' ? 'x' : 'X'; } // adjust precision to print a '0' for octal if alternate format is on else if (base == 8 && fs.flHash && (precision <= 1 || precision <= digits.length) && // too low precision digits.length > 0) prefix1 = '0'; size_t zerofill = precision > digits.length ? precision - digits.length : 0; size_t leftpad = 0; size_t rightpad = 0; ptrdiff_t spacesToPrint = fs.width - ((prefix1 != 0) + (prefix2 != 0) + zerofill + digits.length); if (spacesToPrint > 0) // need to do some padding { if (padChar == '0') zerofill += spacesToPrint; else if (padChar) leftpad = spacesToPrint; else rightpad = spacesToPrint; } /**** Print ****/ foreach (i ; 0 .. leftpad) put(w, ' '); if (prefix1) put(w, prefix1); if (prefix2) put(w, prefix2); foreach (i ; 0 .. zerofill) put(w, '0'); put(w, digits); foreach (i ; 0 .. rightpad) put(w, ' '); } @safe pure unittest { assertCTFEable!( { formatTest( 10, "10" ); }); } unittest { class C1 { long val; alias val this; this(long v){ val = v; } } class C2 { long val; alias val this; this(long v){ val = v; } override string toString() const { return "C"; } } formatTest( new C1(10), "10" ); formatTest( new C2(10), "C" ); struct S1 { long val; alias val this; } struct S2 { long val; alias val this; string toString() const { return "S"; } } formatTest( S1(10), "10" ); formatTest( S2(10), "S" ); } // bugzilla 9117 unittest { static struct Frop {} static struct Foo { int n = 0; alias n this; T opCast(T) () if (is(T == Frop)) { return Frop(); } string toString() { return "Foo"; } } static struct Bar { Foo foo; alias foo this; string toString() { return "Bar"; } } const(char)[] result; void put(const char[] s){ result ~= s; } Foo foo; formattedWrite(&put, "%s", foo); // OK assert(result == "Foo"); result = null; Bar bar; formattedWrite(&put, "%s", bar); // NG assert(result == "Bar"); } /** Floating-point values are formatted like $(D printf) does. Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { import core.stdc.stdio : snprintf; import std.algorithm : find, min; FormatSpec!Char fs = f; // fs is copy for change its values. FloatingPointTypeOf!T val = obj; if (fs.spec == 'r') { // raw write, skip all else and write the thing auto raw = (ref val)@trusted{ return (cast(const char*) &val)[0 .. val.sizeof]; }(val); if (needToSwapEndianess(f)) { foreach_reverse (c; raw) put(w, c); } else { foreach (c; raw) put(w, c); } return; } enforceFmt(find("fgFGaAeEs", fs.spec).length, "incompatible format character for floating point type"); version (CRuntime_Microsoft) { import std.math : isNaN, isInfinity; double tval = val; // convert early to get "inf" in case of overflow string s; if (isNaN(tval)) s = "nan"; // snprintf writes 1.#QNAN else if (isInfinity(tval)) s = val >= 0 ? "inf" : "-inf"; // snprintf writes 1.#INF if (s.length > 0) { version(none) { return formatValue(w, s, f); } else // FIXME:workaroun { s = s[0 .. f.precision < $ ? f.precision : $]; if (!f.flDash) { // right align if (f.width > s.length) foreach (j ; 0 .. f.width - s.length) put(w, ' '); put(w, s); } else { // left align put(w, s); if (f.width > s.length) foreach (j ; 0 .. f.width - s.length) put(w, ' '); } return; } } } else alias tval = val; if (fs.spec == 's') fs.spec = 'g'; char[1 /*%*/ + 5 /*flags*/ + 3 /*width.prec*/ + 2 /*format*/ + 1 /*\0*/] sprintfSpec = void; sprintfSpec[0] = '%'; uint i = 1; if (fs.flDash) sprintfSpec[i++] = '-'; if (fs.flPlus) sprintfSpec[i++] = '+'; if (fs.flZero) sprintfSpec[i++] = '0'; if (fs.flSpace) sprintfSpec[i++] = ' '; if (fs.flHash) sprintfSpec[i++] = '#'; sprintfSpec[i .. i + 3] = "*.*"; i += 3; if (is(Unqual!(typeof(val)) == real)) sprintfSpec[i++] = 'L'; sprintfSpec[i++] = fs.spec; sprintfSpec[i] = 0; //printf("format: '%s'; geeba: %g\n", sprintfSpec.ptr, val); char[512] buf = void; immutable n = ()@trusted{ return snprintf(buf.ptr, buf.length, sprintfSpec.ptr, fs.width, // negative precision is same as no precision specified fs.precision == fs.UNSPECIFIED ? -1 : fs.precision, tval); }(); enforceFmt(n >= 0, "floating point formatting failure"); put(w, buf[0 .. min(n, buf.length-1)]); } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%.1f"); formatValue(w, 1337.7, spec); assert(w.data == "1337.7"); } @safe /*pure*/ unittest // formatting floating point values is now impure { import std.conv : to; foreach (T; AliasSeq!(float, double, real)) { formatTest( to!( T)(5.5), "5.5" ); formatTest( to!( const T)(5.5), "5.5" ); formatTest( to!(immutable T)(5.5), "5.5" ); formatTest( T.nan, "nan" ); } } unittest { formatTest( 2.25, "2.25" ); class C1 { double val; alias val this; this(double v){ val = v; } } class C2 { double val; alias val this; this(double v){ val = v; } override string toString() const { return "C"; } } formatTest( new C1(2.25), "2.25" ); formatTest( new C2(2.25), "C" ); struct S1 { double val; alias val this; } struct S2 { double val; alias val this; string toString() const { return "S"; } } formatTest( S1(2.25), "2.25" ); formatTest( S2(2.25), "S" ); } /* Formatting a $(D creal) is deprecated but still kept around for a while. Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(Unqual!T : creal) && !is(T == enum) && !hasToString!(T, Char)) { creal val = obj; formatValue(w, val.re, f); if (val.im >= 0) { put(w, '+'); } formatValue(w, val.im, f); put(w, 'i'); } @safe /*pure*/ unittest // formatting floating point values is now impure { import std.conv : to; foreach (T; AliasSeq!(cfloat, cdouble, creal)) { formatTest( to!( T)(1 + 1i), "1+1i" ); formatTest( to!( const T)(1 + 1i), "1+1i" ); formatTest( to!(immutable T)(1 + 1i), "1+1i" ); } foreach (T; AliasSeq!(cfloat, cdouble, creal)) { formatTest( to!( T)(0 - 3i), "0-3i" ); formatTest( to!( const T)(0 - 3i), "0-3i" ); formatTest( to!(immutable T)(0 - 3i), "0-3i" ); } } unittest { formatTest( 3+2.25i, "3+2.25i" ); class C1 { cdouble val; alias val this; this(cdouble v){ val = v; } } class C2 { cdouble val; alias val this; this(cdouble v){ val = v; } override string toString() const { return "C"; } } formatTest( new C1(3+2.25i), "3+2.25i" ); formatTest( new C2(3+2.25i), "C" ); struct S1 { cdouble val; alias val this; } struct S2 { cdouble val; alias val this; string toString() const { return "S"; } } formatTest( S1(3+2.25i), "3+2.25i" ); formatTest( S2(3+2.25i), "S" ); } /* Formatting an $(D ireal) is deprecated but still kept around for a while. Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(Unqual!T : ireal) && !is(T == enum) && !hasToString!(T, Char)) { ireal val = obj; formatValue(w, val.im, f); put(w, 'i'); } @safe /*pure*/ unittest // formatting floating point values is now impure { import std.conv : to; foreach (T; AliasSeq!(ifloat, idouble, ireal)) { formatTest( to!( T)(1i), "1i" ); formatTest( to!( const T)(1i), "1i" ); formatTest( to!(immutable T)(1i), "1i" ); } } unittest { formatTest( 2.25i, "2.25i" ); class C1 { idouble val; alias val this; this(idouble v){ val = v; } } class C2 { idouble val; alias val this; this(idouble v){ val = v; } override string toString() const { return "C"; } } formatTest( new C1(2.25i), "2.25i" ); formatTest( new C2(2.25i), "C" ); struct S1 { idouble val; alias val this; } struct S2 { idouble val; alias val this; string toString() const { return "S"; } } formatTest( S1(2.25i), "2.25i" ); formatTest( S2(2.25i), "S" ); } /** Individual characters ($(D char), $(D wchar), or $(D dchar)) are formatted as Unicode characters with %s and as integers with integral-specific format specs. Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(CharTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { CharTypeOf!T val = obj; if (f.spec == 's' || f.spec == 'c') { put(w, val); } else { alias U = AliasSeq!(ubyte, ushort, uint)[CharTypeOf!T.sizeof/2]; formatValue(w, cast(U) val, f); } } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%c"); formatValue(w, 'a', spec); assert(w.data == "a"); } @safe pure unittest { assertCTFEable!( { formatTest( 'c', "c" ); }); } unittest { class C1 { char val; alias val this; this(char v){ val = v; } } class C2 { char val; alias val this; this(char v){ val = v; } override string toString() const { return "C"; } } formatTest( new C1('c'), "c" ); formatTest( new C2('c'), "C" ); struct S1 { char val; alias val this; } struct S2 { char val; alias val this; string toString() const { return "S"; } } formatTest( S1('c'), "c" ); formatTest( S2('c'), "S" ); } @safe pure unittest { //Little Endian formatTest( "%-r", cast( char)'c', ['c' ] ); formatTest( "%-r", cast(wchar)'c', ['c', 0 ] ); formatTest( "%-r", cast(dchar)'c', ['c', 0, 0, 0] ); formatTest( "%-r", '本', ['\x2c', '\x67'] ); //Big Endian formatTest( "%+r", cast( char)'c', [ 'c'] ); formatTest( "%+r", cast(wchar)'c', [0, 'c'] ); formatTest( "%+r", cast(dchar)'c', [0, 0, 0, 'c'] ); formatTest( "%+r", '本', ['\x67', '\x2c'] ); } /** Strings are formatted like $(D printf) does. Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(StringTypeOf!T) && !is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { Unqual!(StringTypeOf!T) val = obj; // for `alias this`, see bug5371 formatRange(w, val, f); } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%s"); formatValue(w, "hello", spec); assert(w.data == "hello"); } unittest { formatTest( "abc", "abc" ); } unittest { // Test for bug 5371 for classes class C1 { const string var; alias var this; this(string s){ var = s; } } class C2 { string var; alias var this; this(string s){ var = s; } } formatTest( new C1("c1"), "c1" ); formatTest( new C2("c2"), "c2" ); // Test for bug 5371 for structs struct S1 { const string var; alias var this; } struct S2 { string var; alias var this; } formatTest( S1("s1"), "s1" ); formatTest( S2("s2"), "s2" ); } unittest { class C3 { string val; alias val this; this(string s){ val = s; } override string toString() const { return "C"; } } formatTest( new C3("c3"), "C" ); struct S3 { string val; alias val this; string toString() const { return "S"; } } formatTest( S3("s3"), "S" ); } @safe pure unittest { //Little Endian formatTest( "%-r", "ab"c, ['a' , 'b' ] ); formatTest( "%-r", "ab"w, ['a', 0 , 'b', 0 ] ); formatTest( "%-r", "ab"d, ['a', 0, 0, 0, 'b', 0, 0, 0] ); formatTest( "%-r", "日本語"c, ['\xe6', '\x97', '\xa5', '\xe6', '\x9c', '\xac', '\xe8', '\xaa', '\x9e'] ); formatTest( "%-r", "日本語"w, ['\xe5', '\x65', '\x2c', '\x67', '\x9e', '\x8a' ] ); formatTest( "%-r", "日本語"d, ['\xe5', '\x65', '\x00', '\x00', '\x2c', '\x67', '\x00', '\x00', '\x9e', '\x8a', '\x00', '\x00'] ); //Big Endian formatTest( "%+r", "ab"c, [ 'a', 'b'] ); formatTest( "%+r", "ab"w, [ 0, 'a', 0, 'b'] ); formatTest( "%+r", "ab"d, [0, 0, 0, 'a', 0, 0, 0, 'b'] ); formatTest( "%+r", "日本語"c, ['\xe6', '\x97', '\xa5', '\xe6', '\x9c', '\xac', '\xe8', '\xaa', '\x9e'] ); formatTest( "%+r", "日本語"w, [ '\x65', '\xe5', '\x67', '\x2c', '\x8a', '\x9e'] ); formatTest( "%+r", "日本語"d, ['\x00', '\x00', '\x65', '\xe5', '\x00', '\x00', '\x67', '\x2c', '\x00', '\x00', '\x8a', '\x9e'] ); } /** Static-size arrays are formatted as dynamic arrays. Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, auto ref T obj, ref FormatSpec!Char f) if (is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { formatValue(w, obj[], f); } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%s"); char[2] two = ['a', 'b']; formatValue(w, two, spec); assert(w.data == "ab"); } unittest // Test for issue 8310 { import std.array : appender; FormatSpec!char f; auto w = appender!string(); char[2] two = ['a', 'b']; formatValue(w, two, f); char[2] getTwo(){ return two; } formatValue(w, getTwo(), f); } /** Dynamic arrays are formatted as input ranges. Specializations: $(UL $(LI $(D void[]) is formatted like $(D ubyte[]).) $(LI Const array is converted to input range by removing its qualifier.)) Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(DynamicArrayTypeOf!T) && !is(StringTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { static if (is(const(ArrayTypeOf!T) == const(void[]))) { formatValue(w, cast(const ubyte[])obj, f); } else static if (!isInputRange!T) { alias U = Unqual!(ArrayTypeOf!T); static assert(isInputRange!U); U val = obj; formatValue(w, val, f); } else { formatRange(w, obj, f); } } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%s"); auto two = [1, 2]; formatValue(w, two, spec); assert(w.data == "[1, 2]"); } // alias this, input range I/F, and toString() unittest { struct S(int flags) { int[] arr; static if (flags & 1) alias arr this; static if (flags & 2) { @property bool empty() const { return arr.length == 0; } @property int front() const { return arr[0] * 2; } void popFront() { arr = arr[1..$]; } } static if (flags & 4) string toString() const { return "S"; } } formatTest(S!0b000([0, 1, 2]), "S!0([0, 1, 2])"); formatTest(S!0b001([0, 1, 2]), "[0, 1, 2]"); // Test for bug 7628 formatTest(S!0b010([0, 1, 2]), "[0, 2, 4]"); formatTest(S!0b011([0, 1, 2]), "[0, 2, 4]"); formatTest(S!0b100([0, 1, 2]), "S"); formatTest(S!0b101([0, 1, 2]), "S"); // Test for bug 7628 formatTest(S!0b110([0, 1, 2]), "S"); formatTest(S!0b111([0, 1, 2]), "S"); class C(uint flags) { int[] arr; static if (flags & 1) alias arr this; this(int[] a) { arr = a; } static if (flags & 2) { @property bool empty() const { return arr.length == 0; } @property int front() const { return arr[0] * 2; } void popFront() { arr = arr[1..$]; } } static if (flags & 4) override string toString() const { return "C"; } } formatTest(new C!0b000([0, 1, 2]), (new C!0b000([])).toString()); formatTest(new C!0b001([0, 1, 2]), "[0, 1, 2]"); // Test for bug 7628 formatTest(new C!0b010([0, 1, 2]), "[0, 2, 4]"); formatTest(new C!0b011([0, 1, 2]), "[0, 2, 4]"); formatTest(new C!0b100([0, 1, 2]), "C"); formatTest(new C!0b101([0, 1, 2]), "C"); // Test for bug 7628 formatTest(new C!0b110([0, 1, 2]), "C"); formatTest(new C!0b111([0, 1, 2]), "C"); } unittest { // void[] void[] val0; formatTest( val0, "[]" ); void[] val = cast(void[])cast(ubyte[])[1, 2, 3]; formatTest( val, "[1, 2, 3]" ); void[0] sval0 = []; formatTest( sval0, "[]"); void[3] sval = cast(void[3])cast(ubyte[3])[1, 2, 3]; formatTest( sval, "[1, 2, 3]" ); } unittest { // const(T[]) -> const(T)[] const short[] a = [1, 2, 3]; formatTest( a, "[1, 2, 3]" ); struct S { const(int[]) arr; alias arr this; } auto s = S([1,2,3]); formatTest( s, "[1, 2, 3]" ); } unittest { // 6640 struct Range { string value; @property bool empty() const { return !value.length; } @property dchar front() const { return value.front; } void popFront() { value.popFront(); } @property size_t length() const { return value.length; } } immutable table = [ ["[%s]", "[string]"], ["[%10s]", "[ string]"], ["[%-10s]", "[string ]"], ["[%(%02x %)]", "[73 74 72 69 6e 67]"], ["[%(%c %)]", "[s t r i n g]"], ]; foreach (e; table) { formatTest(e[0], "string", e[1]); formatTest(e[0], Range("string"), e[1]); } } unittest { // string literal from valid UTF sequence is encoding free. foreach (StrType; AliasSeq!(string, wstring, dstring)) { // Valid and printable (ASCII) formatTest( [cast(StrType)"hello"], `["hello"]` ); // 1 character escape sequences (' is not escaped in strings) formatTest( [cast(StrType)"\"'\0\\\a\b\f\n\r\t\v"], `["\"'\0\\\a\b\f\n\r\t\v"]` ); // 1 character optional escape sequences formatTest( [cast(StrType)"\'\?"], `["'?"]` ); // Valid and non-printable code point (<= U+FF) formatTest( [cast(StrType)"\x10\x1F\x20test"], `["\x10\x1F test"]` ); // Valid and non-printable code point (<= U+FFFF) formatTest( [cast(StrType)"\u200B..\u200F"], `["\u200B..\u200F"]` ); // Valid and non-printable code point (<= U+10FFFF) formatTest( [cast(StrType)"\U000E0020..\U000E007F"], `["\U000E0020..\U000E007F"]` ); } // invalid UTF sequence needs hex-string literal postfix (c/w/d) { // U+FFFF with UTF-8 (Invalid code point for interchange) formatTest( [cast(string)[0xEF, 0xBF, 0xBF]], `[x"EF BF BF"c]` ); // U+FFFF with UTF-16 (Invalid code point for interchange) formatTest( [cast(wstring)[0xFFFF]], `[x"FFFF"w]` ); // U+FFFF with UTF-32 (Invalid code point for interchange) formatTest( [cast(dstring)[0xFFFF]], `[x"FFFF"d]` ); } } unittest { // nested range formatting with array of string formatTest( "%({%(%02x %)}%| %)", ["test", "msg"], `{74 65 73 74} {6d 73 67}` ); } unittest { // stop auto escaping inside range formatting auto arr = ["hello", "world"]; formatTest( "%(%s, %)", arr, `"hello", "world"` ); formatTest( "%-(%s, %)", arr, `hello, world` ); auto aa1 = [1:"hello", 2:"world"]; formatTest( "%(%s:%s, %)", aa1, [`1:"hello", 2:"world"`, `2:"world", 1:"hello"`] ); formatTest( "%-(%s:%s, %)", aa1, [`1:hello, 2:world`, `2:world, 1:hello`] ); auto aa2 = [1:["ab", "cd"], 2:["ef", "gh"]]; formatTest( "%-(%s:%s, %)", aa2, [`1:["ab", "cd"], 2:["ef", "gh"]`, `2:["ef", "gh"], 1:["ab", "cd"]`] ); formatTest( "%-(%s:%(%s%), %)", aa2, [`1:"ab""cd", 2:"ef""gh"`, `2:"ef""gh", 1:"ab""cd"`] ); formatTest( "%-(%s:%-(%s%)%|, %)", aa2, [`1:abcd, 2:efgh`, `2:efgh, 1:abcd`] ); } // input range formatting private void formatRange(Writer, T, Char)(ref Writer w, ref T val, ref FormatSpec!Char f) if (isInputRange!T) { import std.conv : text; // Formatting character ranges like string if (f.spec == 's') { alias E = ElementType!T; static if (!is(E == enum) && is(CharTypeOf!E)) { static if (is(StringTypeOf!T)) { auto s = val[0 .. f.precision < $ ? f.precision : $]; if (!f.flDash) { // right align if (f.width > s.length) foreach (i ; 0 .. f.width - s.length) put(w, ' '); put(w, s); } else { // left align put(w, s); if (f.width > s.length) foreach (i ; 0 .. f.width - s.length) put(w, ' '); } } else { if (!f.flDash) { static if (hasLength!T) { // right align auto len = val.length; } else static if (isForwardRange!T && !isInfinite!T) { auto len = walkLength(val.save); } else { enforce(f.width == 0, "Cannot right-align a range without length"); size_t len = 0; } if (f.precision != f.UNSPECIFIED && len > f.precision) len = f.precision; if (f.width > len) foreach (i ; 0 .. f.width - len) put(w, ' '); if (f.precision == f.UNSPECIFIED) put(w, val); else { size_t printed = 0; for (; !val.empty && printed < f.precision; val.popFront(), ++printed) put(w, val.front); } } else { size_t printed = void; // left align if (f.precision == f.UNSPECIFIED) { static if (hasLength!T) { printed = val.length; put(w, val); } else { printed = 0; for (; !val.empty; val.popFront(), ++printed) put(w, val.front); } } else { printed = 0; for (; !val.empty && printed < f.precision; val.popFront(), ++printed) put(w, val.front); } if (f.width > printed) foreach (i ; 0 .. f.width - printed) put(w, ' '); } } } else { put(w, f.seqBefore); if (!val.empty) { formatElement(w, val.front, f); val.popFront(); for (size_t i; !val.empty; val.popFront(), ++i) { put(w, f.seqSeparator); formatElement(w, val.front, f); } } static if (!isInfinite!T) put(w, f.seqAfter); } } else if (f.spec == 'r') { static if (is(DynamicArrayTypeOf!T)) { alias ARR = DynamicArrayTypeOf!T; foreach (e ; cast(ARR)val) { formatValue(w, e, f); } } else { for (size_t i; !val.empty; val.popFront(), ++i) { formatValue(w, val.front, f); } } } else if (f.spec == '(') { if (val.empty) return; // Nested specifier is to be used for (;;) { auto fmt = FormatSpec!Char(f.nested); fmt.writeUpToNextSpec(w); if (f.flDash) formatValue(w, val.front, fmt); else formatElement(w, val.front, fmt); if (f.sep.ptr) { put(w, fmt.trailing); val.popFront(); if (val.empty) break; put(w, f.sep); } else { val.popFront(); if (val.empty) break; put(w, fmt.trailing); } } } else throw new Exception(text("Incorrect format specifier for range: %", f.spec)); } // character formatting with ecaping private void formatChar(Writer)(Writer w, in dchar c, in char quote) { import std.uni : isGraphical; string fmt; if (isGraphical(c)) { if (c == quote || c == '\\') put(w, '\\'); put(w, c); return; } else if (c <= 0xFF) { if (c < 0x20) { foreach (i, k; "\n\r\t\a\b\f\v\0") { if (c == k) { put(w, '\\'); put(w, "nrtabfv0"[i]); return; } } } fmt = "\\x%02X"; } else if (c <= 0xFFFF) fmt = "\\u%04X"; else fmt = "\\U%08X"; formattedWrite(w, fmt, cast(uint)c); } // undocumented because of deprecation // string elements are formatted like UTF-8 string literals. void formatElement(Writer, T, Char)(Writer w, T val, ref FormatSpec!Char f) if (is(StringTypeOf!T) && !is(T == enum)) { import std.utf : UTFException; import std.array : appender; StringTypeOf!T str = val; // bug 8015 if (f.spec == 's') { try { // ignore other specifications and quote auto app = appender!(typeof(val[0])[])(); put(app, '\"'); for (size_t i = 0; i < str.length; ) { import std.utf : decode; auto c = decode(str, i); // \uFFFE and \uFFFF are considered valid by isValidDchar, // so need checking for interchange. if (c == 0xFFFE || c == 0xFFFF) goto LinvalidSeq; formatChar(app, c, '"'); } put(app, '\"'); put(w, app.data); return; } catch (UTFException) { } // If val contains invalid UTF sequence, formatted like HexString literal LinvalidSeq: static if (is(typeof(str[0]) : const(char))) { enum postfix = 'c'; alias IntArr = const(ubyte)[]; } else static if (is(typeof(str[0]) : const(wchar))) { enum postfix = 'w'; alias IntArr = const(ushort)[]; } else static if (is(typeof(str[0]) : const(dchar))) { enum postfix = 'd'; alias IntArr = const(uint)[]; } formattedWrite(w, "x\"%(%02X %)\"%s", cast(IntArr)str, postfix); } else formatValue(w, str, f); } unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%s"); formatElement(w, "Hello World", spec); assert(w.data == "\"Hello World\""); } unittest { // Test for bug 8015 import std.typecons; struct MyStruct { string str; @property string toStr() { return str; } alias toStr this; } Tuple!(MyStruct) t; } // undocumented because of deprecation // Character elements are formatted like UTF-8 character literals. void formatElement(Writer, T, Char)(Writer w, T val, ref FormatSpec!Char f) if (is(CharTypeOf!T) && !is(T == enum)) { if (f.spec == 's') { put(w, '\''); formatChar(w, val, '\''); put(w, '\''); } else formatValue(w, val, f); } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%s"); formatElement(w, "H", spec); assert(w.data == "\"H\"", w.data); } // undocumented // Maybe T is noncopyable struct, so receive it by 'auto ref'. void formatElement(Writer, T, Char)(Writer w, auto ref T val, ref FormatSpec!Char f) if (!is(StringTypeOf!T) && !is(CharTypeOf!T) || is(T == enum)) { formatValue(w, val, f); } /** Associative arrays are formatted by using $(D ':') and $(D ", ") as separators, and enclosed by $(D '[') and $(D ']'). Params: w = The $(D OutputRange) to write to. obj = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!Char f) if (is(AssocArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { AssocArrayTypeOf!T val = obj; enforceFmt(f.spec == 's' || f.spec == '(', "associative"); enum const(Char)[] defSpec = "%s" ~ f.keySeparator ~ "%s" ~ f.seqSeparator; auto fmtSpec = f.spec == '(' ? f.nested : defSpec; size_t i = 0, end = val.length; if (f.spec == 's') put(w, f.seqBefore); foreach (k, ref v; val) { auto fmt = FormatSpec!Char(fmtSpec); fmt.writeUpToNextSpec(w); if (f.flDash) { formatValue(w, k, fmt); fmt.writeUpToNextSpec(w); formatValue(w, v, fmt); } else { formatElement(w, k, fmt); fmt.writeUpToNextSpec(w); formatElement(w, v, fmt); } if (f.sep !is null) { fmt.writeUpToNextSpec(w); if (++i != end) put(w, f.sep); } else { if (++i != end) fmt.writeUpToNextSpec(w); } } if (f.spec == 's') put(w, f.seqAfter); } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%s"); auto aa = ["H":"W"]; formatElement(w, aa, spec); assert(w.data == "[\"H\":\"W\"]", w.data); } unittest { int[string] aa0; formatTest( aa0, `[]` ); // elements escaping formatTest( ["aaa":1, "bbb":2], [`["aaa":1, "bbb":2]`, `["bbb":2, "aaa":1]`] ); formatTest( ['c':"str"], `['c':"str"]` ); formatTest( ['"':"\"", '\'':"'"], [`['"':"\"", '\'':"'"]`, `['\'':"'", '"':"\""]`] ); // range formatting for AA auto aa3 = [1:"hello", 2:"world"]; // escape formatTest( "{%(%s:%s $ %)}", aa3, [`{1:"hello" $ 2:"world"}`, `{2:"world" $ 1:"hello"}`]); // use range formatting for key and value, and use %| formatTest( "{%([%04d->%(%c.%)]%| $ %)}", aa3, [`{[0001->h.e.l.l.o] $ [0002->w.o.r.l.d]}`, `{[0002->w.o.r.l.d] $ [0001->h.e.l.l.o]}`] ); // issue 12135 formatTest("%(%s:<%s>%|,%)", [1:2], "1:<2>"); formatTest("%(%s:<%s>%|%)" , [1:2], "1:<2>"); } unittest { class C1 { int[char] val; alias val this; this(int[char] v){ val = v; } } class C2 { int[char] val; alias val this; this(int[char] v){ val = v; } override string toString() const { return "C"; } } formatTest( new C1(['c':1, 'd':2]), [`['c':1, 'd':2]`, `['d':2, 'c':1]`] ); formatTest( new C2(['c':1, 'd':2]), "C" ); struct S1 { int[char] val; alias val this; } struct S2 { int[char] val; alias val this; string toString() const { return "S"; } } formatTest( S1(['c':1, 'd':2]), [`['c':1, 'd':2]`, `['d':2, 'c':1]`] ); formatTest( S2(['c':1, 'd':2]), "S" ); } unittest // Issue 8921 { enum E : char { A = 'a', B = 'b', C = 'c' } E[3] e = [E.A, E.B, E.C]; formatTest(e, "[A, B, C]"); E[] e2 = [E.A, E.B, E.C]; formatTest(e2, "[A, B, C]"); } template hasToString(T, Char) { static if(isPointer!T && !isAggregateType!T) { // X* does not have toString, even if X is aggregate type has toString. enum hasToString = 0; } else static if (is(typeof({ T val = void; FormatSpec!Char f; val.toString((const(char)[] s){}, f); }))) { enum hasToString = 4; } else static if (is(typeof({ T val = void; val.toString((const(char)[] s){}, "%s"); }))) { enum hasToString = 3; } else static if (is(typeof({ T val = void; val.toString((const(char)[] s){}); }))) { enum hasToString = 2; } else static if (is(typeof({ T val = void; return val.toString(); }()) S) && isSomeString!S) { enum hasToString = 1; } else { enum hasToString = 0; } } // object formatting with toString private void formatObject(Writer, T, Char)(ref Writer w, ref T val, ref FormatSpec!Char f) if (hasToString!(T, Char)) { static if (is(typeof(val.toString((const(char)[] s){}, f)))) { val.toString((const(char)[] s) { put(w, s); }, f); } else static if (is(typeof(val.toString((const(char)[] s){}, "%s")))) { val.toString((const(char)[] s) { put(w, s); }, f.getCurFmtStr()); } else static if (is(typeof(val.toString((const(char)[] s){})))) { val.toString((const(char)[] s) { put(w, s); }); } else static if (is(typeof(val.toString()) S) && isSomeString!S) { put(w, val.toString()); } else static assert(0); } void enforceValidFormatSpec(T, Char)(ref FormatSpec!Char f) { static if (!isInputRange!T && hasToString!(T, Char) != 4) { enforceFmt(f.spec == 's', "Expected '%s' format specifier for type '" ~ T.stringof ~ "'"); } } unittest { static interface IF1 { } class CIF1 : IF1 { } static struct SF1 { } static union UF1 { } static class CF1 { } static interface IF2 { string toString(); } static class CIF2 : IF2 { override string toString() { return ""; } } static struct SF2 { string toString() { return ""; } } static union UF2 { string toString() { return ""; } } static class CF2 { override string toString() { return ""; } } static interface IK1 { void toString(scope void delegate(const(char)[]) sink, FormatSpec!char) const; } static class CIK1 : IK1 { override void toString(scope void delegate(const(char)[]) sink, FormatSpec!char) const { sink("CIK1"); } } static struct KS1 { void toString(scope void delegate(const(char)[]) sink, FormatSpec!char) const { sink("KS1"); } } static union KU1 { void toString(scope void delegate(const(char)[]) sink, FormatSpec!char) const { sink("KU1"); } } static class KC1 { void toString(scope void delegate(const(char)[]) sink, FormatSpec!char) const { sink("KC1"); } } IF1 cif1 = new CIF1; assertThrown!FormatException(format("%f", cif1)); assertThrown!FormatException(format("%f", SF1())); assertThrown!FormatException(format("%f", UF1())); assertThrown!FormatException(format("%f", new CF1())); IF2 cif2 = new CIF2; assertThrown!FormatException(format("%f", cif2)); assertThrown!FormatException(format("%f", SF2())); assertThrown!FormatException(format("%f", UF2())); assertThrown!FormatException(format("%f", new CF2())); IK1 cik1 = new CIK1; assert(format("%f", cik1) == "CIK1"); assert(format("%f", KS1()) == "KS1"); assert(format("%f", KU1()) == "KU1"); assert(format("%f", new KC1()) == "KC1"); } /** Aggregates ($(D struct), $(D union), $(D class), and $(D interface)) are basically formatted by calling $(D toString). $(D toString) should have one of the following signatures: --- const void toString(scope void delegate(const(char)[]) sink, FormatSpec fmt); const void toString(scope void delegate(const(char)[]) sink, string fmt); const void toString(scope void delegate(const(char)[]) sink); const string toString(); --- For the class objects which have input range interface, $(UL $(LI If the instance $(D toString) has overridden $(D Object.toString), it is used.) $(LI Otherwise, the objects are formatted as input range.)) For the struct and union objects which does not have $(D toString), $(UL $(LI If they have range interface, formatted as input range.) $(LI Otherwise, they are formatted like $(D Type(field1, filed2, ...)).)) Otherwise, are formatted just as their type name. */ void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!Char f) if (is(T == class) && !is(T == enum)) { enforceValidFormatSpec!(T, Char)(f); // TODO: Change this once toString() works for shared objects. static assert(!is(T == shared), "unable to format shared objects"); if (val is null) put(w, "null"); else { static if (hasToString!(T, Char) > 1 || (!isInputRange!T && !is(BuiltinTypeOf!T))) { formatObject!(Writer, T, Char)(w, val, f); } else { //string delegate() dg = &val.toString; Object o = val; // workaround string delegate() dg = &o.toString; if (dg.funcptr != &Object.toString) // toString is overridden { formatObject(w, val, f); } else static if (isInputRange!T) { formatRange(w, val, f); } else static if (is(BuiltinTypeOf!T X)) { X x = val; formatValue(w, x, f); } else { formatObject(w, val, f); } } } } /++ $(D formatValue) allows to reuse existing format specifiers: +/ unittest { import std.format; struct Point { int x, y; void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) const { sink("("); sink.formatValue(x, fmt); sink(","); sink.formatValue(y, fmt); sink(")"); } } auto p = Point(16,11); assert(format("%03d", p) == "(016,011)"); assert(format("%02x", p) == "(10,0b)"); } /++ The following code compares the use of $(D formatValue) and $(D formattedWrite). +/ unittest { import std.format; import std.array : appender; auto writer1 = appender!string(); writer1.formattedWrite("%08b", 42); auto writer2 = appender!string(); auto f = singleSpec("%08b"); writer2.formatValue(42, f); assert(writer1.data == writer2.data && writer1.data == "00101010"); } unittest { import std.array : appender; import std.range.interfaces; // class range (issue 5154) auto c = inputRangeObject([1,2,3,4]); formatTest( c, "[1, 2, 3, 4]" ); assert(c.empty); c = null; formatTest( c, "null" ); } unittest { // 5354 // If the class has both range I/F and custom toString, the use of custom // toString routine is prioritized. // Enable the use of custom toString that gets a sink delegate // for class formatting. enum inputRangeCode = q{ int[] arr; this(int[] a){ arr = a; } @property int front() const { return arr[0]; } @property bool empty() const { return arr.length == 0; } void popFront(){ arr = arr[1..$]; } }; class C1 { mixin(inputRangeCode); void toString(scope void delegate(const(char)[]) dg, ref FormatSpec!char f) const { dg("[012]"); } } class C2 { mixin(inputRangeCode); void toString(scope void delegate(const(char)[]) dg, string f) const { dg("[012]"); } } class C3 { mixin(inputRangeCode); void toString(scope void delegate(const(char)[]) dg) const { dg("[012]"); } } class C4 { mixin(inputRangeCode); override string toString() const { return "[012]"; } } class C5 { mixin(inputRangeCode); } formatTest( new C1([0, 1, 2]), "[012]" ); formatTest( new C2([0, 1, 2]), "[012]" ); formatTest( new C3([0, 1, 2]), "[012]" ); formatTest( new C4([0, 1, 2]), "[012]" ); formatTest( new C5([0, 1, 2]), "[0, 1, 2]" ); } /// ditto void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!Char f) if (is(T == interface) && (hasToString!(T, Char) || !is(BuiltinTypeOf!T)) && !is(T == enum)) { enforceValidFormatSpec!(T, Char)(f); if (val is null) put(w, "null"); else { static if (hasToString!(T, Char)) { formatObject(w, val, f); } else static if (isInputRange!T) { formatRange(w, val, f); } else { version (Windows) { import core.sys.windows.com : IUnknown; static if (is(T : IUnknown)) { formatValue(w, *cast(void**)&val, f); } else { formatValue(w, cast(Object)val, f); } } else { formatValue(w, cast(Object)val, f); } } } } unittest { // interface import std.range.interfaces; InputRange!int i = inputRangeObject([1,2,3,4]); formatTest( i, "[1, 2, 3, 4]" ); assert(i.empty); i = null; formatTest( i, "null" ); // interface (downcast to Object) interface Whatever {} class C : Whatever { override @property string toString() const { return "ab"; } } Whatever val = new C; formatTest( val, "ab" ); // Issue 11175 version (Windows) { import core.sys.windows.windows : HRESULT; import core.sys.windows.com : IUnknown, IID; interface IUnknown2 : IUnknown { } class D : IUnknown2 { extern(Windows) HRESULT QueryInterface(const(IID)* riid, void** pvObject) { return typeof(return).init; } extern(Windows) uint AddRef() { return 0; } extern(Windows) uint Release() { return 0; } } IUnknown2 d = new D; string expected = format("%X", cast(void*)d); formatTest(d, expected); } } /// ditto // Maybe T is noncopyable struct, so receive it by 'auto ref'. void formatValue(Writer, T, Char)(Writer w, auto ref T val, ref FormatSpec!Char f) if ((is(T == struct) || is(T == union)) && (hasToString!(T, Char) || !is(BuiltinTypeOf!T)) && !is(T == enum)) { enforceValidFormatSpec!(T, Char)(f); static if (hasToString!(T, Char)) { formatObject(w, val, f); } else static if (isInputRange!T) { formatRange(w, val, f); } else static if (is(T == struct)) { enum left = T.stringof~"("; enum separator = ", "; enum right = ")"; put(w, left); foreach (i, e; val.tupleof) { static if (0 < i && val.tupleof[i-1].offsetof == val.tupleof[i].offsetof) { static if (i == val.tupleof.length - 1 || val.tupleof[i].offsetof != val.tupleof[i+1].offsetof) put(w, separator~val.tupleof[i].stringof[4..$]~"}"); else put(w, separator~val.tupleof[i].stringof[4..$]); } else { static if (i+1 < val.tupleof.length && val.tupleof[i].offsetof == val.tupleof[i+1].offsetof) put(w, (i > 0 ? separator : "")~"#{overlap "~val.tupleof[i].stringof[4..$]); else { static if (i > 0) put(w, separator); formatElement(w, e, f); } } } put(w, right); } else { put(w, T.stringof); } } unittest { // bug 4638 struct U8 { string toString() const { return "blah"; } } struct U16 { wstring toString() const { return "blah"; } } struct U32 { dstring toString() const { return "blah"; } } formatTest( U8(), "blah" ); formatTest( U16(), "blah" ); formatTest( U32(), "blah" ); } unittest { // 3890 struct Int{ int n; } struct Pair{ string s; Int i; } formatTest( Pair("hello", Int(5)), `Pair("hello", Int(5))` ); } unittest { // union formatting without toString union U1 { int n; string s; } U1 u1; formatTest( u1, "U1" ); // union formatting with toString union U2 { int n; string s; string toString() const { return s; } } U2 u2; u2.s = "hello"; formatTest( u2, "hello" ); } unittest { import std.array; // 7230 static struct Bug7230 { string s = "hello"; union { string a; int b; double c; } long x = 10; } Bug7230 bug; bug.b = 123; FormatSpec!char f; auto w = appender!(char[])(); formatValue(w, bug, f); assert(w.data == `Bug7230("hello", #{overlap a, b, c}, 10)`); } unittest { import std.array; static struct S{ @disable this(this); } S s; FormatSpec!char f; auto w = appender!string(); formatValue(w, s, f); assert(w.data == "S()"); } /** $(D enum) is formatted like its base value. Params: w = The $(D OutputRange) to write to. val = The value to write. f = The $(D FormatSpec) defining how to write the value. */ void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!Char f) if (is(T == enum)) { if (f.spec == 's') { foreach (i, e; EnumMembers!T) { if (val == e) { formatValue(w, __traits(allMembers, T)[i], f); return; } } // val is not a member of T, output cast(T)rawValue instead. put(w, "cast(" ~ T.stringof ~ ")"); static assert(!is(OriginalType!T == T)); } formatValue(w, cast(OriginalType!T)val, f); } /// unittest { import std.array : appender; auto w = appender!string(); auto spec = singleSpec("%s"); enum A { first, second, third } formatElement(w, A.second, spec); assert(w.data == "second"); } unittest { enum A { first, second, third } formatTest( A.second, "second" ); formatTest( cast(A)72, "cast(A)72" ); } unittest { enum A : string { one = "uno", two = "dos", three = "tres" } formatTest( A.three, "three" ); formatTest( cast(A)"mill\ón", "cast(A)mill\ón" ); } unittest { enum A : bool { no, yes } formatTest( A.yes, "yes" ); formatTest( A.no, "no" ); } unittest { // Test for bug 6892 enum Foo { A = 10 } formatTest("%s", Foo.A, "A"); formatTest(">%4s<", Foo.A, "> A<"); formatTest("%04d", Foo.A, "0010"); formatTest("%+2u", Foo.A, "+10"); formatTest("%02x", Foo.A, "0a"); formatTest("%3o", Foo.A, " 12"); formatTest("%b", Foo.A, "1010"); } /** Pointers are formatted as hex integers. */ void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!Char f) if (isPointer!T && !is(T == enum) && !hasToString!(T, Char)) { static if (isInputRange!T) { if (val !is null) { formatRange(w, *val, f); return; } } static if (is(typeof({ shared const void* p = val; }))) alias SharedOf(T) = shared(T); else alias SharedOf(T) = T; const SharedOf!(void*) p = val; const pnum = ()@trusted{ return cast(ulong) p; }(); if (f.spec == 's') { if (p is null) { put(w, "null"); return; } FormatSpec!Char fs = f; // fs is copy for change its values. fs.spec = 'X'; formatValue(w, pnum, fs); } else { enforceFmt(f.spec == 'X' || f.spec == 'x', "Expected one of %s, %x or %X for pointer type."); formatValue(w, pnum, f); } } @safe pure unittest { // pointer import std.range; auto r = retro([1,2,3,4]); auto p = ()@trusted{ auto p = &r; return p; }(); formatTest( p, "[4, 3, 2, 1]" ); assert(p.empty); p = null; formatTest( p, "null" ); auto q = ()@trusted{ return cast(void*)0xFFEECCAA; }(); formatTest( q, "FFEECCAA" ); } pure unittest { // Test for issue 7869 struct S { string toString() const { return ""; } } S* p = null; formatTest( p, "null" ); S* q = cast(S*)0xFFEECCAA; formatTest( q, "FFEECCAA" ); } unittest { // Test for issue 8186 class B { int*a; this(){ a = new int; } alias a this; } formatTest( B.init, "null" ); } pure unittest { // Test for issue 9336 shared int i; format("%s", &i); } pure unittest { // Test for issue 11778 int* p = null; assertThrown(format("%d", p)); assertThrown(format("%04d", p + 2)); } pure unittest { // Test for issue 12505 void* p = null; formatTest( "%08X", p, "00000000" ); } /** Delegates are formatted by 'ReturnType delegate(Parameters) FunctionAttributes' */ void formatValue(Writer, T, Char)(Writer w, scope T, ref FormatSpec!Char f) if (isDelegate!T) { formatValue(w, T.stringof, f); } /// unittest { import std.conv : to; int i; int foo(short k) @nogc { return i + k; } int delegate(short) @nogc bar() nothrow { return &foo; } assert(to!string(&bar) == "int delegate(short) @nogc delegate() nothrow"); } unittest { void func() {} formatTest( &func, "void delegate()" ); } /* Formats an object of type 'D' according to 'f' and writes it to 'w'. The pointer 'arg' is assumed to point to an object of type 'D'. The untyped signature is for the sake of taking this function's address. */ private void formatGeneric(Writer, D, Char)(Writer w, const(void)* arg, ref FormatSpec!Char f) { formatValue(w, *cast(D*) arg, f); } private void formatNth(Writer, Char, A...)(Writer w, ref FormatSpec!Char f, size_t index, A args) { import std.conv : to; static string gencode(size_t count)() { string result; foreach (n; 0 .. count) { auto num = to!string(n); result ~= "case "~num~":"~ " formatValue(w, args["~num~"], f);"~ " break;"; } return result; } switch (index) { mixin(gencode!(A.length)()); default: assert(0, "n = "~cast(char)(index + '0')); } } pure unittest { int[] a = [ 1, 3, 2 ]; formatTest( "testing %(%s & %) embedded", a, "testing 1 & 3 & 2 embedded"); formatTest( "testing %((%s) %)) wyda3", a, "testing (1) (3) (2) wyda3" ); int[0] empt = []; formatTest( "(%s)", empt, "([])" ); } //------------------------------------------------------------------------------ // Fix for issue 1591 private int getNthInt(A...)(uint index, A args) { import std.conv : to; static if (A.length) { if (index) { return getNthInt(index - 1, args[1 .. $]); } static if (isIntegral!(typeof(args[0]))) { return to!int(args[0]); } else { throw new FormatException("int expected"); } } else { throw new FormatException("int expected"); } } /* ======================== Unit Tests ====================================== */ version(unittest) void formatTest(T)(T val, string expected, size_t ln = __LINE__, string fn = __FILE__) { import core.exception; import std.array : appender; import std.conv : text; FormatSpec!char f; auto w = appender!string(); formatValue(w, val, f); enforce!AssertError( w.data == expected, text("expected = `", expected, "`, result = `", w.data, "`"), fn, ln); } version(unittest) void formatTest(T)(string fmt, T val, string expected, size_t ln = __LINE__, string fn = __FILE__) { import core.exception; import std.array : appender; import std.conv : text; auto w = appender!string(); formattedWrite(w, fmt, val); enforce!AssertError( w.data == expected, text("expected = `", expected, "`, result = `", w.data, "`"), fn, ln); } version(unittest) void formatTest(T)(T val, string[] expected, size_t ln = __LINE__, string fn = __FILE__) { import core.exception; import std.conv : text; import std.array : appender; FormatSpec!char f; auto w = appender!string(); formatValue(w, val, f); foreach(cur; expected) { if(w.data == cur) return; } enforce!AssertError( false, text("expected one of `", expected, "`, result = `", w.data, "`"), fn, ln); } version(unittest) void formatTest(T)(string fmt, T val, string[] expected, size_t ln = __LINE__, string fn = __FILE__) { import core.exception; import std.conv : text; import std.array : appender; auto w = appender!string(); formattedWrite(w, fmt, val); foreach(cur; expected) { if(w.data == cur) return; } enforce!AssertError( false, text("expected one of `", expected, "`, result = `", w.data, "`"), fn, ln); } @safe /*pure*/ unittest // formatting floating point values is now impure { import std.array; auto stream = appender!string(); formattedWrite(stream, "%s", 1.1); assert(stream.data == "1.1", stream.data); } pure unittest { import std.algorithm; import std.array; auto stream = appender!string(); formattedWrite(stream, "%s", map!"a*a"([2, 3, 5])); assert(stream.data == "[4, 9, 25]", stream.data); // Test shared data. stream = appender!string(); shared int s = 6; formattedWrite(stream, "%s", s); assert(stream.data == "6"); } pure unittest { import std.array; auto stream = appender!string(); formattedWrite(stream, "%u", 42); assert(stream.data == "42", stream.data); } pure unittest { // testing raw writes import std.array; auto w = appender!(char[])(); uint a = 0x02030405; formattedWrite(w, "%+r", a); assert(w.data.length == 4 && w.data[0] == 2 && w.data[1] == 3 && w.data[2] == 4 && w.data[3] == 5); w.clear(); formattedWrite(w, "%-r", a); assert(w.data.length == 4 && w.data[0] == 5 && w.data[1] == 4 && w.data[2] == 3 && w.data[3] == 2); } pure unittest { // testing positional parameters import std.array; auto w = appender!(char[])(); formattedWrite(w, "Numbers %2$s and %1$s are reversed and %1$s%2$s repeated", 42, 0); assert(w.data == "Numbers 0 and 42 are reversed and 420 repeated", w.data); w.clear(); formattedWrite(w, "asd%s", 23); assert(w.data == "asd23", w.data); w.clear(); formattedWrite(w, "%s%s", 23, 45); assert(w.data == "2345", w.data); } unittest { import std.conv : text, octal; import std.array : appender; import std.c.stdio : snprintf; import core.stdc.string : strlen; debug(format) printf("std.format.format.unittest\n"); auto stream = appender!(char[])(); //goto here; formattedWrite(stream, "hello world! %s %s ", true, 57, 1_000_000_000, 'x', " foo"); assert(stream.data == "hello world! true 57 ", stream.data); stream.clear(); formattedWrite(stream, "%g %A %s", 1.67, -1.28, float.nan); // core.stdc.stdio.fwrite(stream.data.ptr, stream.data.length, 1, stderr); /* The host C library is used to format floats. C99 doesn't * specify what the hex digit before the decimal point is for * %A. */ version (CRuntime_Glibc) { assert(stream.data == "1.67 -0X1.47AE147AE147BP+0 nan", stream.data); } else version (OSX) { assert(stream.data == "1.67 -0X1.47AE147AE147BP+0 nan", stream.data); } else version (MinGW) { assert(stream.data == "1.67 -0XA.3D70A3D70A3D8P-3 nan", stream.data); } else version (CRuntime_Microsoft) { assert(stream.data == "1.67 -0X1.47AE14P+0 nan" || stream.data == "1.67 -0X1.47AE147AE147BP+0 nan", // MSVCRT 14+ (VS 2015) stream.data); } else { assert(stream.data == "1.67 -0X1.47AE147AE147BP+0 nan", stream.data); } stream.clear(); formattedWrite(stream, "%x %X", 0x1234AF, 0xAFAFAFAF); assert(stream.data == "1234af AFAFAFAF"); stream.clear(); formattedWrite(stream, "%b %o", 0x1234AF, 0xAFAFAFAF); assert(stream.data == "100100011010010101111 25753727657"); stream.clear(); formattedWrite(stream, "%d %s", 0x1234AF, 0xAFAFAFAF); assert(stream.data == "1193135 2947526575"); stream.clear(); // formattedWrite(stream, "%s", 1.2 + 3.4i); // assert(stream.data == "1.2+3.4i"); // stream.clear(); formattedWrite(stream, "%a %A", 1.32, 6.78f); //formattedWrite(stream, "%x %X", 1.32); version (CRuntime_Microsoft) assert(stream.data == "0x1.51eb85p+0 0X1.B1EB86P+2" || stream.data == "0x1.51eb851eb851fp+0 0X1.B1EB860000000P+2"); // MSVCRT 14+ (VS 2015) else assert(stream.data == "0x1.51eb851eb851fp+0 0X1.B1EB86P+2"); stream.clear(); formattedWrite(stream, "%#06.*f",2,12.345); assert(stream.data == "012.35"); stream.clear(); formattedWrite(stream, "%#0*.*f",6,2,12.345); assert(stream.data == "012.35"); stream.clear(); const real constreal = 1; formattedWrite(stream, "%g",constreal); assert(stream.data == "1"); stream.clear(); formattedWrite(stream, "%7.4g:", 12.678); assert(stream.data == " 12.68:"); stream.clear(); formattedWrite(stream, "%7.4g:", 12.678L); assert(stream.data == " 12.68:"); stream.clear(); formattedWrite(stream, "%04f|%05d|%#05x|%#5x",-4.0,-10,1,1); assert(stream.data == "-4.000000|-0010|0x001| 0x1", stream.data); stream.clear(); int i; string s; i = -10; formattedWrite(stream, "%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(stream.data == "-10|-10|-10|-10|-10.0000"); stream.clear(); i = -5; formattedWrite(stream, "%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(stream.data == "-5| -5|-05|-5|-5.0000"); stream.clear(); i = 0; formattedWrite(stream, "%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(stream.data == "0| 0|000|0|0.0000"); stream.clear(); i = 5; formattedWrite(stream, "%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(stream.data == "5| 5|005|5|5.0000"); stream.clear(); i = 10; formattedWrite(stream, "%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(stream.data == "10| 10|010|10|10.0000"); stream.clear(); formattedWrite(stream, "%.0d", 0); assert(stream.data == ""); stream.clear(); formattedWrite(stream, "%.g", .34); assert(stream.data == "0.3"); stream.clear(); stream.clear(); formattedWrite(stream, "%.0g", .34); assert(stream.data == "0.3"); stream.clear(); formattedWrite(stream, "%.2g", .34); assert(stream.data == "0.34"); stream.clear(); formattedWrite(stream, "%0.0008f", 1e-08); assert(stream.data == "0.00000001"); stream.clear(); formattedWrite(stream, "%0.0008f", 1e-05); assert(stream.data == "0.00001000"); //return; //core.stdc.stdio.fwrite(stream.data.ptr, stream.data.length, 1, stderr); s = "helloworld"; string r; stream.clear(); formattedWrite(stream, "%.2s", s[0..5]); assert(stream.data == "he"); stream.clear(); formattedWrite(stream, "%.20s", s[0..5]); assert(stream.data == "hello"); stream.clear(); formattedWrite(stream, "%8s", s[0..5]); assert(stream.data == " hello"); byte[] arrbyte = new byte[4]; arrbyte[0] = 100; arrbyte[1] = -99; arrbyte[3] = 0; stream.clear(); formattedWrite(stream, "%s", arrbyte); assert(stream.data == "[100, -99, 0, 0]", stream.data); ubyte[] arrubyte = new ubyte[4]; arrubyte[0] = 100; arrubyte[1] = 200; arrubyte[3] = 0; stream.clear(); formattedWrite(stream, "%s", arrubyte); assert(stream.data == "[100, 200, 0, 0]", stream.data); short[] arrshort = new short[4]; arrshort[0] = 100; arrshort[1] = -999; arrshort[3] = 0; stream.clear(); formattedWrite(stream, "%s", arrshort); assert(stream.data == "[100, -999, 0, 0]"); stream.clear(); formattedWrite(stream, "%s",arrshort); assert(stream.data == "[100, -999, 0, 0]"); ushort[] arrushort = new ushort[4]; arrushort[0] = 100; arrushort[1] = 20_000; arrushort[3] = 0; stream.clear(); formattedWrite(stream, "%s", arrushort); assert(stream.data == "[100, 20000, 0, 0]"); int[] arrint = new int[4]; arrint[0] = 100; arrint[1] = -999; arrint[3] = 0; stream.clear(); formattedWrite(stream, "%s", arrint); assert(stream.data == "[100, -999, 0, 0]"); stream.clear(); formattedWrite(stream, "%s",arrint); assert(stream.data == "[100, -999, 0, 0]"); long[] arrlong = new long[4]; arrlong[0] = 100; arrlong[1] = -999; arrlong[3] = 0; stream.clear(); formattedWrite(stream, "%s", arrlong); assert(stream.data == "[100, -999, 0, 0]"); stream.clear(); formattedWrite(stream, "%s",arrlong); assert(stream.data == "[100, -999, 0, 0]"); ulong[] arrulong = new ulong[4]; arrulong[0] = 100; arrulong[1] = 999; arrulong[3] = 0; stream.clear(); formattedWrite(stream, "%s", arrulong); assert(stream.data == "[100, 999, 0, 0]"); string[] arr2 = new string[4]; arr2[0] = "hello"; arr2[1] = "world"; arr2[3] = "foo"; stream.clear(); formattedWrite(stream, "%s", arr2); assert(stream.data == `["hello", "world", "", "foo"]`, stream.data); stream.clear(); formattedWrite(stream, "%.8d", 7); assert(stream.data == "00000007"); stream.clear(); formattedWrite(stream, "%.8x", 10); assert(stream.data == "0000000a"); stream.clear(); formattedWrite(stream, "%-3d", 7); assert(stream.data == "7 "); stream.clear(); formattedWrite(stream, "%*d", -3, 7); assert(stream.data == "7 "); stream.clear(); formattedWrite(stream, "%.*d", -3, 7); //writeln(stream.data); assert(stream.data == "7"); stream.clear(); formattedWrite(stream, "%s", "abc"c); assert(stream.data == "abc"); stream.clear(); formattedWrite(stream, "%s", "def"w); assert(stream.data == "def", text(stream.data.length)); stream.clear(); formattedWrite(stream, "%s", "ghi"d); assert(stream.data == "ghi"); here: void* p = cast(void*)0xDEADBEEF; stream.clear(); formattedWrite(stream, "%s", p); assert(stream.data == "DEADBEEF", stream.data); stream.clear(); formattedWrite(stream, "%#x", 0xabcd); assert(stream.data == "0xabcd"); stream.clear(); formattedWrite(stream, "%#X", 0xABCD); assert(stream.data == "0XABCD"); stream.clear(); formattedWrite(stream, "%#o", octal!12345); assert(stream.data == "012345"); stream.clear(); formattedWrite(stream, "%o", 9); assert(stream.data == "11"); stream.clear(); formattedWrite(stream, "%+d", 123); assert(stream.data == "+123"); stream.clear(); formattedWrite(stream, "%+d", -123); assert(stream.data == "-123"); stream.clear(); formattedWrite(stream, "% d", 123); assert(stream.data == " 123"); stream.clear(); formattedWrite(stream, "% d", -123); assert(stream.data == "-123"); stream.clear(); formattedWrite(stream, "%%"); assert(stream.data == "%"); stream.clear(); formattedWrite(stream, "%d", true); assert(stream.data == "1"); stream.clear(); formattedWrite(stream, "%d", false); assert(stream.data == "0"); stream.clear(); formattedWrite(stream, "%d", 'a'); assert(stream.data == "97", stream.data); wchar wc = 'a'; stream.clear(); formattedWrite(stream, "%d", wc); assert(stream.data == "97"); dchar dc = 'a'; stream.clear(); formattedWrite(stream, "%d", dc); assert(stream.data == "97"); byte b = byte.max; stream.clear(); formattedWrite(stream, "%x", b); assert(stream.data == "7f"); stream.clear(); formattedWrite(stream, "%x", ++b); assert(stream.data == "80"); stream.clear(); formattedWrite(stream, "%x", ++b); assert(stream.data == "81"); short sh = short.max; stream.clear(); formattedWrite(stream, "%x", sh); assert(stream.data == "7fff"); stream.clear(); formattedWrite(stream, "%x", ++sh); assert(stream.data == "8000"); stream.clear(); formattedWrite(stream, "%x", ++sh); assert(stream.data == "8001"); i = int.max; stream.clear(); formattedWrite(stream, "%x", i); assert(stream.data == "7fffffff"); stream.clear(); formattedWrite(stream, "%x", ++i); assert(stream.data == "80000000"); stream.clear(); formattedWrite(stream, "%x", ++i); assert(stream.data == "80000001"); stream.clear(); formattedWrite(stream, "%x", 10); assert(stream.data == "a"); stream.clear(); formattedWrite(stream, "%X", 10); assert(stream.data == "A"); stream.clear(); formattedWrite(stream, "%x", 15); assert(stream.data == "f"); stream.clear(); formattedWrite(stream, "%X", 15); assert(stream.data == "F"); Object c = null; stream.clear(); formattedWrite(stream, "%s", c); assert(stream.data == "null"); enum TestEnum { Value1, Value2 } stream.clear(); formattedWrite(stream, "%s", TestEnum.Value2); assert(stream.data == "Value2", stream.data); stream.clear(); formattedWrite(stream, "%s", cast(TestEnum)5); assert(stream.data == "cast(TestEnum)5", stream.data); //immutable(char[5])[int] aa = ([3:"hello", 4:"betty"]); //stream.clear(); formattedWrite(stream, "%s", aa.values); //core.stdc.stdio.fwrite(stream.data.ptr, stream.data.length, 1, stderr); //assert(stream.data == "[[h,e,l,l,o],[b,e,t,t,y]]"); //stream.clear(); formattedWrite(stream, "%s", aa); //assert(stream.data == "[3:[h,e,l,l,o],4:[b,e,t,t,y]]"); static const dchar[] ds = ['a','b']; for (int j = 0; j < ds.length; ++j) { stream.clear(); formattedWrite(stream, " %d", ds[j]); if (j == 0) assert(stream.data == " 97"); else assert(stream.data == " 98"); } stream.clear(); formattedWrite(stream, "%.-3d", 7); assert(stream.data == "7", ">" ~ stream.data ~ "<"); } unittest { import std.array; import std.stdio; immutable(char[5])[int] aa = ([3:"hello", 4:"betty"]); assert(aa[3] == "hello"); assert(aa[4] == "betty"); auto stream = appender!(char[])(); alias AllNumerics = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real); foreach (T; AllNumerics) { T value = 1; stream.clear(); formattedWrite(stream, "%s", value); assert(stream.data == "1"); } stream.clear(); formattedWrite(stream, "%s", aa); } unittest { string s = "hello!124:34.5"; string a; int b; double c; formattedRead(s, "%s!%s:%s", &a, &b, &c); assert(a == "hello" && b == 124 && c == 34.5); } version(unittest) void formatReflectTest(T)(ref T val, string fmt, string formatted, string fn = __FILE__, size_t ln = __LINE__) { import core.exception; import std.array : appender; auto w = appender!string(); formattedWrite(w, fmt, val); auto input = w.data; enforce!AssertError( input == formatted, input, fn, ln); T val2; formattedRead(input, fmt, &val2); static if (isAssociativeArray!T) if (__ctfe) { alias aa1 = val; alias aa2 = val2; assert(aa1 == aa2); assert(aa1.length == aa2.length); assert(aa1.keys == aa2.keys); assert(aa1.values == aa2.values); assert(aa1.values.length == aa2.values.length); foreach (i; 0 .. aa1.values.length) assert(aa1.values[i] == aa2.values[i]); foreach (i, key; aa1.keys) assert(aa1.values[i] == aa1[key]); foreach (i, key; aa2.keys) assert(aa2.values[i] == aa2[key]); return; } enforce!AssertError( val == val2, input, fn, ln); } version(unittest) void formatReflectTest(T)(ref T val, string fmt, string[] formatted, string fn = __FILE__, size_t ln = __LINE__) { import core.exception; import std.array : appender; auto w = appender!string(); formattedWrite(w, fmt, val); auto input = w.data; foreach(cur; formatted) { if(input == cur) return; } enforce!AssertError( false, input, fn, ln); T val2; formattedRead(input, fmt, &val2); static if (isAssociativeArray!T) if (__ctfe) { alias aa1 = val; alias aa2 = val2; assert(aa1 == aa2); assert(aa1.length == aa2.length); assert(aa1.keys == aa2.keys); assert(aa1.values == aa2.values); assert(aa1.values.length == aa2.values.length); foreach (i; 0 .. aa1.values.length) assert(aa1.values[i] == aa2.values[i]); foreach (i, key; aa1.keys) assert(aa1.values[i] == aa1[key]); foreach (i, key; aa2.keys) assert(aa2.values[i] == aa2[key]); return; } enforce!AssertError( val == val2, input, fn, ln); } unittest { void booleanTest() { auto b = true; formatReflectTest(b, "%s", `true`); formatReflectTest(b, "%b", `1`); formatReflectTest(b, "%o", `1`); formatReflectTest(b, "%d", `1`); formatReflectTest(b, "%u", `1`); formatReflectTest(b, "%x", `1`); } void integerTest() { auto n = 127; formatReflectTest(n, "%s", `127`); formatReflectTest(n, "%b", `1111111`); formatReflectTest(n, "%o", `177`); formatReflectTest(n, "%d", `127`); formatReflectTest(n, "%u", `127`); formatReflectTest(n, "%x", `7f`); } void floatingTest() { auto f = 3.14; formatReflectTest(f, "%s", `3.14`); version (MinGW) formatReflectTest(f, "%e", `3.140000e+000`); else formatReflectTest(f, "%e", `3.140000e+00`); formatReflectTest(f, "%f", `3.140000`); formatReflectTest(f, "%g", `3.14`); } void charTest() { auto c = 'a'; formatReflectTest(c, "%s", `a`); formatReflectTest(c, "%c", `a`); formatReflectTest(c, "%b", `1100001`); formatReflectTest(c, "%o", `141`); formatReflectTest(c, "%d", `97`); formatReflectTest(c, "%u", `97`); formatReflectTest(c, "%x", `61`); } void strTest() { auto s = "hello"; formatReflectTest(s, "%s", `hello`); formatReflectTest(s, "%(%c,%)", `h,e,l,l,o`); formatReflectTest(s, "%(%s,%)", `'h','e','l','l','o'`); formatReflectTest(s, "[%(<%c>%| $ %)]", `[ $ $ $ $ ]`); } void daTest() { auto a = [1,2,3,4]; formatReflectTest(a, "%s", `[1, 2, 3, 4]`); formatReflectTest(a, "[%(%s; %)]", `[1; 2; 3; 4]`); formatReflectTest(a, "[%(<%s>%| $ %)]", `[<1> $ <2> $ <3> $ <4>]`); } void saTest() { int[4] sa = [1,2,3,4]; formatReflectTest(sa, "%s", `[1, 2, 3, 4]`); formatReflectTest(sa, "[%(%s; %)]", `[1; 2; 3; 4]`); formatReflectTest(sa, "[%(<%s>%| $ %)]", `[<1> $ <2> $ <3> $ <4>]`); } void aaTest() { auto aa = [1:"hello", 2:"world"]; formatReflectTest(aa, "%s", [`[1:"hello", 2:"world"]`, `[2:"world", 1:"hello"]`]); formatReflectTest(aa, "[%(%s->%s, %)]", [`[1->"hello", 2->"world"]`, `[2->"world", 1->"hello"]`]); formatReflectTest(aa, "{%([%s=%(%c%)]%|; %)}", [`{[1=hello]; [2=world]}`, `{[2=world]; [1=hello]}`]); } import std.exception; assertCTFEable!( { booleanTest(); integerTest(); if (!__ctfe) floatingTest(); // snprintf charTest(); strTest(); daTest(); saTest(); aaTest(); return true; }); } //------------------------------------------------------------------------------ private void skipData(Range, Char)(ref Range input, ref FormatSpec!Char spec) { import std.ascii : isDigit; import std.conv : text; switch (spec.spec) { case 'c': input.popFront(); break; case 'd': if (input.front == '+' || input.front == '-') input.popFront(); goto case 'u'; case 'u': while (!input.empty && isDigit(input.front)) input.popFront(); break; default: assert(false, text("Format specifier not understood: %", spec.spec)); } } private template acceptedSpecs(T) { static if (isIntegral!T) enum acceptedSpecs = "bdosuxX"; else static if (isFloatingPoint!T) enum acceptedSpecs = "seEfgG"; else static if (isSomeChar!T) enum acceptedSpecs = "bcdosuxX"; // integral + 'c' else enum acceptedSpecs = ""; } /** * Reads a boolean value and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range && is(Unqual!T == bool)) { import std.algorithm : find; import std.conv : parse, text; if (spec.spec == 's') { return parse!T(input); } enforce(find(acceptedSpecs!long, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); return unformatValue!long(input, spec) != 0; } pure unittest { string line; bool f1; line = "true"; formattedRead(line, "%s", &f1); assert(f1); line = "TrUE"; formattedRead(line, "%s", &f1); assert(f1); line = "false"; formattedRead(line, "%s", &f1); assert(!f1); line = "fALsE"; formattedRead(line, "%s", &f1); assert(!f1); line = "1"; formattedRead(line, "%d", &f1); assert(f1); line = "-1"; formattedRead(line, "%d", &f1); assert(f1); line = "0"; formattedRead(line, "%d", &f1); assert(!f1); line = "-0"; formattedRead(line, "%d", &f1); assert(!f1); } /** * Reads null literal and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range && is(T == typeof(null))) { import std.conv : parse, text; enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); return parse!T(input); } /** Reads an integral value and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range && isIntegral!T && !is(T == enum)) { import std.algorithm : find; import std.conv : parse, text; enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); enforce(spec.width == 0, "Parsing integers with a width specification is not implemented"); // TODO uint base = spec.spec == 'x' || spec.spec == 'X' ? 16 : spec.spec == 'o' ? 8 : spec.spec == 'b' ? 2 : spec.spec == 's' || spec.spec == 'd' || spec.spec == 'u' ? 10 : 0; assert(base != 0); return parse!T(input, base); } /** Reads a floating-point value and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isFloatingPoint!T && !is(T == enum)) { import std.algorithm : find; import std.conv : parse, text; if (spec.spec == 'r') { // raw read //enforce(input.length >= T.sizeof); enforce(isSomeString!Range || ElementType!(Range).sizeof == 1, "Cannot parse input of type %s".format(Range.stringof)); union X { ubyte[T.sizeof] raw; T typed; } X x; foreach (i; 0 .. T.sizeof) { static if (isSomeString!Range) { x.raw[i] = input[0]; input = input[1 .. $]; } else { // TODO: recheck this x.raw[i] = cast(ubyte) input.front; input.popFront(); } } return x.typed; } enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); return parse!T(input); } version(none)unittest { union A { char[float.sizeof] untyped; float typed; } A a; a.typed = 5.5; char[] input = a.untyped[]; float witness; formattedRead(input, "%r", &witness); assert(witness == a.typed); } pure unittest { import std.typecons; char[] line = "1 2".dup; int a, b; formattedRead(line, "%s %s", &a, &b); assert(a == 1 && b == 2); line = "10 2 3".dup; formattedRead(line, "%d ", &a); assert(a == 10); assert(line == "2 3"); Tuple!(int, float) t; line = "1 2.125".dup; formattedRead(line, "%d %g", &t); assert(t[0] == 1 && t[1] == 2.125); line = "1 7643 2.125".dup; formattedRead(line, "%s %*u %s", &t); assert(t[0] == 1 && t[1] == 2.125); } /** * Reads one character and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range && isSomeChar!T && !is(T == enum)) { import std.algorithm : find; import std.conv : to, text; if (spec.spec == 's' || spec.spec == 'c') { auto result = to!T(input.front); input.popFront(); return result; } enforce(find(acceptedSpecs!T, spec.spec).length, text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); static if (T.sizeof == 1) return unformatValue!ubyte(input, spec); else static if (T.sizeof == 2) return unformatValue!ushort(input, spec); else static if (T.sizeof == 4) return unformatValue!uint(input, spec); else static assert(0); } pure unittest { string line; char c1, c2; line = "abc"; formattedRead(line, "%s%c", &c1, &c2); assert(c1 == 'a' && c2 == 'b'); assert(line == "c"); } /** Reads a string and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range && is(StringTypeOf!T) && !isAggregateType!T && !is(T == enum)) { import std.conv : text; if (spec.spec == '(') { return unformatRange!T(input, spec); } enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); static if (isStaticArray!T) { T result; auto app = result[]; } else { import std.array : appender; auto app = appender!T(); } if (spec.trailing.empty) { for (; !input.empty; input.popFront()) { static if (isStaticArray!T) if (app.empty) break; app.put(input.front); } } else { auto end = spec.trailing.front; for (; !input.empty && input.front != end; input.popFront()) { static if (isStaticArray!T) if (app.empty) break; app.put(input.front); } } static if (isStaticArray!T) { enforce(app.empty, "need more input"); return result; } else return app.data; } pure unittest { string line; string s1, s2; line = "hello, world"; formattedRead(line, "%s", &s1); assert(s1 == "hello, world", s1); line = "hello, world;yah"; formattedRead(line, "%s;%s", &s1, &s2); assert(s1 == "hello, world", s1); assert(s2 == "yah", s2); line = `['h','e','l','l','o']`; string s3; formattedRead(line, "[%(%s,%)]", &s3); assert(s3 == "hello"); line = `"hello"`; string s4; formattedRead(line, "\"%(%c%)\"", &s4); assert(s4 == "hello"); } /** Reads an array (except for string types) and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range && isArray!T && !is(StringTypeOf!T) && !isAggregateType!T && !is(T == enum)) { import std.conv : parse, text; if (spec.spec == '(') { return unformatRange!T(input, spec); } enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); return parse!T(input); } pure unittest { string line; line = "[1,2,3]"; int[] s1; formattedRead(line, "%s", &s1); assert(s1 == [1,2,3]); } pure unittest { string line; line = "[1,2,3]"; int[] s1; formattedRead(line, "[%(%s,%)]", &s1); assert(s1 == [1,2,3]); line = `["hello", "world"]`; string[] s2; formattedRead(line, "[%(%s, %)]", &s2); assert(s2 == ["hello", "world"]); line = "123 456"; int[] s3; formattedRead(line, "%(%s %)", &s3); assert(s3 == [123, 456]); line = "h,e,l,l,o; w,o,r,l,d"; string[] s4; formattedRead(line, "%(%(%c,%); %)", &s4); assert(s4 == ["hello", "world"]); } pure unittest { string line; int[4] sa1; line = `[1,2,3,4]`; formattedRead(line, "%s", &sa1); assert(sa1 == [1,2,3,4]); int[4] sa2; line = `[1,2,3]`; assertThrown(formattedRead(line, "%s", &sa2)); int[4] sa3; line = `[1,2,3,4,5]`; assertThrown(formattedRead(line, "%s", &sa3)); } pure unittest { string input; int[4] sa1; input = `[1,2,3,4]`; formattedRead(input, "[%(%s,%)]", &sa1); assert(sa1 == [1,2,3,4]); int[4] sa2; input = `[1,2,3]`; assertThrown(formattedRead(input, "[%(%s,%)]", &sa2)); } pure unittest { // 7241 string input = "a"; auto spec = FormatSpec!char("%s"); spec.readUpToNextSpec(input); auto result = unformatValue!(dchar[1])(input, spec); assert(result[0] == 'a'); } /** * Reads an associative array and returns it. */ T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range && isAssociativeArray!T && !is(T == enum)) { import std.conv : parse, text; if (spec.spec == '(') { return unformatRange!T(input, spec); } enforce(spec.spec == 's', text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof)); return parse!T(input); } pure unittest { string line; string[int] aa1; line = `[1:"hello", 2:"world"]`; formattedRead(line, "%s", &aa1); assert(aa1 == [1:"hello", 2:"world"]); int[string] aa2; line = `{"hello"=1; "world"=2}`; formattedRead(line, "{%(%s=%s; %)}", &aa2); assert(aa2 == ["hello":1, "world":2]); int[string] aa3; line = `{[hello=1]; [world=2]}`; formattedRead(line, "{%([%(%c%)=%s]%|; %)}", &aa3); assert(aa3 == ["hello":1, "world":2]); } //debug = unformatRange; private T unformatRange(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) in { assert(spec.spec == '('); } body { debug (unformatRange) printf("unformatRange:\n"); T result; static if (isStaticArray!T) { size_t i; } const(Char)[] cont = spec.trailing; for (size_t j = 0; j < spec.trailing.length; ++j) { if (spec.trailing[j] == '%') { cont = spec.trailing[0 .. j]; break; } } debug (unformatRange) printf("\t"); debug (unformatRange) if (!input.empty) printf("input.front = %c, ", input.front); debug (unformatRange) printf("cont = %.*s\n", cont); bool checkEnd() { return input.empty || !cont.empty && input.front == cont.front; } if (!checkEnd()) { for (;;) { auto fmt = FormatSpec!Char(spec.nested); fmt.readUpToNextSpec(input); enforce(!input.empty, "Unexpected end of input when parsing range"); debug (unformatRange) printf("\t) spec = %c, front = %c ", fmt.spec, input.front); static if (isStaticArray!T) { result[i++] = unformatElement!(typeof(T.init[0]))(input, fmt); } else static if (isDynamicArray!T) { result ~= unformatElement!(ElementType!T)(input, fmt); } else static if (isAssociativeArray!T) { auto key = unformatElement!(typeof(T.init.keys[0]))(input, fmt); fmt.readUpToNextSpec(input); // eat key separator result[key] = unformatElement!(typeof(T.init.values[0]))(input, fmt); } debug (unformatRange) { if (input.empty) printf("-> front = [empty] "); else printf("-> front = %c ", input.front); } static if (isStaticArray!T) { debug (unformatRange) printf("i = %u < %u\n", i, T.length); enforce(i <= T.length, "Too many format specifiers for static array of length %d".format(T.length)); } if (spec.sep != null) fmt.readUpToNextSpec(input); auto sep = spec.sep != null ? spec.sep : fmt.trailing; debug (unformatRange) { if (!sep.empty && !input.empty) printf("-> %c, sep = %.*s\n", input.front, sep); else printf("\n"); } if (checkEnd()) break; if (!sep.empty && input.front == sep.front) { while (!sep.empty) { enforce(!input.empty, "Unexpected end of input when parsing range separator"); enforce(input.front == sep.front, "Unexpected character when parsing range separator"); input.popFront(); sep.popFront(); } debug (unformatRange) printf("input.front = %c\n", input.front); } } } static if (isStaticArray!T) { enforce(i == T.length, "Too few (%d) format specifiers for static array of length %d".format(i, T.length)); } return result; } // Undocumented T unformatElement(T, Range, Char)(ref Range input, ref FormatSpec!Char spec) if (isInputRange!Range) { import std.conv : parseElement; static if (isSomeString!T) { if (spec.spec == 's') { return parseElement!T(input); } } else static if (isSomeChar!T) { if (spec.spec == 's') { return parseElement!T(input); } } return unformatValue!T(input, spec); } // Legacy implementation enum Mangle : char { Tvoid = 'v', Tbool = 'b', Tbyte = 'g', Tubyte = 'h', Tshort = 's', Tushort = 't', Tint = 'i', Tuint = 'k', Tlong = 'l', Tulong = 'm', Tfloat = 'f', Tdouble = 'd', Treal = 'e', Tifloat = 'o', Tidouble = 'p', Tireal = 'j', Tcfloat = 'q', Tcdouble = 'r', Tcreal = 'c', Tchar = 'a', Twchar = 'u', Tdchar = 'w', Tarray = 'A', Tsarray = 'G', Taarray = 'H', Tpointer = 'P', Tfunction = 'F', Tident = 'I', Tclass = 'C', Tstruct = 'S', Tenum = 'E', Ttypedef = 'T', Tdelegate = 'D', Tconst = 'x', Timmutable = 'y', } // return the TypeInfo for a primitive type and null otherwise. This // is required since for arrays of ints we only have the mangled char // to work from. If arrays always subclassed TypeInfo_Array this // routine could go away. private TypeInfo primitiveTypeInfo(Mangle m) { // BUG: should fix this in static this() to avoid double checked locking bug __gshared TypeInfo[Mangle] dic; if (!dic.length) { dic = [ Mangle.Tvoid : typeid(void), Mangle.Tbool : typeid(bool), Mangle.Tbyte : typeid(byte), Mangle.Tubyte : typeid(ubyte), Mangle.Tshort : typeid(short), Mangle.Tushort : typeid(ushort), Mangle.Tint : typeid(int), Mangle.Tuint : typeid(uint), Mangle.Tlong : typeid(long), Mangle.Tulong : typeid(ulong), Mangle.Tfloat : typeid(float), Mangle.Tdouble : typeid(double), Mangle.Treal : typeid(real), Mangle.Tifloat : typeid(ifloat), Mangle.Tidouble : typeid(idouble), Mangle.Tireal : typeid(ireal), Mangle.Tcfloat : typeid(cfloat), Mangle.Tcdouble : typeid(cdouble), Mangle.Tcreal : typeid(creal), Mangle.Tchar : typeid(char), Mangle.Twchar : typeid(wchar), Mangle.Tdchar : typeid(dchar) ]; } auto p = m in dic; return p ? *p : null; } // This stuff has been removed from the docs and is planned for deprecation. /* * Interprets variadic argument list pointed to by argptr whose types * are given by arguments[], formats them according to embedded format * strings in the variadic argument list, and sends the resulting * characters to putc. * * The variadic arguments are consumed in order. Each is formatted * into a sequence of chars, using the default format specification * for its type, and the characters are sequentially passed to putc. * If a $(D char[]), $(D wchar[]), or $(D dchar[]) argument is * encountered, it is interpreted as a format string. As many * arguments as specified in the format string are consumed and * formatted according to the format specifications in that string and * passed to putc. If there are too few remaining arguments, a * $(D FormatException) is thrown. If there are more remaining arguments than * needed by the format specification, the default processing of * arguments resumes until they are all consumed. * * Params: * putc = Output is sent do this delegate, character by character. * arguments = Array of $(D TypeInfo)s, one for each argument to be formatted. * argptr = Points to variadic argument list. * * Throws: * Mismatched arguments and formats result in a $(D FormatException) being thrown. * * Format_String: * $(I Format strings) * consist of characters interspersed with * $(I format specifications). Characters are simply copied * to the output (such as putc) after any necessary conversion * to the corresponding UTF-8 sequence. * * A $(I format specification) starts with a '%' character, * and has the following grammar: $(CONSOLE $(I FormatSpecification): $(B '%%') $(B '%') $(I Flags) $(I Width) $(I Precision) $(I FormatChar) $(I Flags): $(I empty) $(B '-') $(I Flags) $(B '+') $(I Flags) $(B '#') $(I Flags) $(B '0') $(I Flags) $(B ' ') $(I Flags) $(I Width): $(I empty) $(I Integer) $(B '*') $(I Precision): $(I empty) $(B '.') $(B '.') $(I Integer) $(B '.*') $(I Integer): $(I Digit) $(I Digit) $(I Integer) $(I Digit): $(B '0') $(B '1') $(B '2') $(B '3') $(B '4') $(B '5') $(B '6') $(B '7') $(B '8') $(B '9') $(I FormatChar): $(B 's') $(B 'b') $(B 'd') $(B 'o') $(B 'x') $(B 'X') $(B 'e') $(B 'E') $(B 'f') $(B 'F') $(B 'g') $(B 'G') $(B 'a') $(B 'A') ) $(DL $(DT $(I Flags)) $(DL $(DT $(B '-')) $(DD Left justify the result in the field. It overrides any $(B 0) flag.) $(DT $(B '+')) $(DD Prefix positive numbers in a signed conversion with a $(B +). It overrides any $(I space) flag.) $(DT $(B '#')) $(DD Use alternative formatting: $(DL $(DT For $(B 'o'):) $(DD Add to precision as necessary so that the first digit of the octal formatting is a '0', even if both the argument and the $(I Precision) are zero.) $(DT For $(B 'x') ($(B 'X')):) $(DD If non-zero, prefix result with $(B 0x) ($(B 0X)).) $(DT For floating point formatting:) $(DD Always insert the decimal point.) $(DT For $(B 'g') ($(B 'G')):) $(DD Do not elide trailing zeros.) )) $(DT $(B '0')) $(DD For integer and floating point formatting when not nan or infinity, use leading zeros to pad rather than spaces. Ignore if there's a $(I Precision).) $(DT $(B ' ')) $(DD Prefix positive numbers in a signed conversion with a space.) ) $(DT $(I Width)) $(DD Specifies the minimum field width. If the width is a $(B *), the next argument, which must be of type $(B int), is taken as the width. If the width is negative, it is as if the $(B -) was given as a $(I Flags) character.) $(DT $(I Precision)) $(DD Gives the precision for numeric conversions. If the precision is a $(B *), the next argument, which must be of type $(B int), is taken as the precision. If it is negative, it is as if there was no $(I Precision).) $(DT $(I FormatChar)) $(DD $(DL $(DT $(B 's')) $(DD The corresponding argument is formatted in a manner consistent with its type: $(DL $(DT $(B bool)) $(DD The result is 'true' or 'false'.) $(DT integral types) $(DD The $(B %d) format is used.) $(DT floating point types) $(DD The $(B %g) format is used.) $(DT string types) $(DD The result is the string converted to UTF-8.) A $(I Precision) specifies the maximum number of characters to use in the result. $(DT classes derived from $(B Object)) $(DD The result is the string returned from the class instance's $(B .toString()) method. A $(I Precision) specifies the maximum number of characters to use in the result.) $(DT non-string static and dynamic arrays) $(DD The result is [s0, s1, ...] where sk is the kth element formatted with the default format.) )) $(DT $(B 'b','d','o','x','X')) $(DD The corresponding argument must be an integral type and is formatted as an integer. If the argument is a signed type and the $(I FormatChar) is $(B d) it is converted to a signed string of characters, otherwise it is treated as unsigned. An argument of type $(B bool) is formatted as '1' or '0'. The base used is binary for $(B b), octal for $(B o), decimal for $(B d), and hexadecimal for $(B x) or $(B X). $(B x) formats using lower case letters, $(B X) uppercase. If there are fewer resulting digits than the $(I Precision), leading zeros are used as necessary. If the $(I Precision) is 0 and the number is 0, no digits result.) $(DT $(B 'e','E')) $(DD A floating point number is formatted as one digit before the decimal point, $(I Precision) digits after, the $(I FormatChar), ±, followed by at least a two digit exponent: $(I d.dddddd)e$(I ±dd). If there is no $(I Precision), six digits are generated after the decimal point. If the $(I Precision) is 0, no decimal point is generated.) $(DT $(B 'f','F')) $(DD A floating point number is formatted in decimal notation. The $(I Precision) specifies the number of digits generated after the decimal point. It defaults to six. At least one digit is generated before the decimal point. If the $(I Precision) is zero, no decimal point is generated.) $(DT $(B 'g','G')) $(DD A floating point number is formatted in either $(B e) or $(B f) format for $(B g); $(B E) or $(B F) format for $(B G). The $(B f) format is used if the exponent for an $(B e) format is greater than -5 and less than the $(I Precision). The $(I Precision) specifies the number of significant digits, and defaults to six. Trailing zeros are elided after the decimal point, if the fractional part is zero then no decimal point is generated.) $(DT $(B 'a','A')) $(DD A floating point number is formatted in hexadecimal exponential notation 0x$(I h.hhhhhh)p$(I ±d). There is one hexadecimal digit before the decimal point, and as many after as specified by the $(I Precision). If the $(I Precision) is zero, no decimal point is generated. If there is no $(I Precision), as many hexadecimal digits as necessary to exactly represent the mantissa are generated. The exponent is written in as few digits as possible, but at least one, is in decimal, and represents a power of 2 as in $(I h.hhhhhh)*2$(I ±d). The exponent for zero is zero. The hexadecimal digits, x and p are in upper case if the $(I FormatChar) is upper case.) ) Floating point NaN's are formatted as $(B nan) if the $(I FormatChar) is lower case, or $(B NAN) if upper. Floating point infinities are formatted as $(B inf) or $(B infinity) if the $(I FormatChar) is lower case, or $(B INF) or $(B INFINITY) if upper. )) Example: ------------------------- import core.stdc.stdio; import std.format; void myPrint(...) { void putc(dchar c) { fputc(c, stdout); } std.format.doFormat(&putc, _arguments, _argptr); } void main() { int x = 27; // prints 'The answer is 27:6' myPrint("The answer is %s:", x, 6); } ------------------------ */ void doFormat()(scope void delegate(dchar) putc, TypeInfo[] arguments, va_list ap) { import std.utf : toUCSindex, isValidDchar, UTFException, toUTF8; import core.stdc.string : strlen; import core.stdc.stdlib : alloca, malloc, realloc, free; import core.stdc.stdio : snprintf; size_t bufLength = 1024; void* argBuffer = malloc(bufLength); scope(exit) free(argBuffer); size_t bufUsed = 0; foreach(ti; arguments) { // Ensure the required alignment bufUsed += ti.talign - 1; bufUsed -= (cast(size_t)argBuffer + bufUsed) & (ti.talign - 1); auto pos = bufUsed; // Align to next word boundary bufUsed += ti.tsize + size_t.sizeof - 1; bufUsed -= (cast(size_t)argBuffer + bufUsed) & (size_t.sizeof - 1); // Resize buffer if necessary while (bufUsed > bufLength) { bufLength *= 2; argBuffer = realloc(argBuffer, bufLength); } // Copy argument into buffer va_arg(ap, ti, argBuffer + pos); } auto argptr = argBuffer; void* skipArg(TypeInfo ti) { // Ensure the required alignment argptr += ti.talign - 1; argptr -= cast(size_t)argptr & (ti.talign - 1); auto p = argptr; // Align to next word boundary argptr += ti.tsize + size_t.sizeof - 1; argptr -= cast(size_t)argptr & (size_t.sizeof - 1); return p; } auto getArg(T)() { return *cast(T*)skipArg(typeid(T)); } TypeInfo ti; Mangle m; uint flags; int field_width; int precision; enum : uint { FLdash = 1, FLplus = 2, FLspace = 4, FLhash = 8, FLlngdbl = 0x20, FL0pad = 0x40, FLprecision = 0x80, } static TypeInfo skipCI(TypeInfo valti) { for (;;) { if (typeid(valti).name.length == 18 && typeid(valti).name[9..18] == "Invariant") valti = (cast(TypeInfo_Invariant)valti).base; else if (typeid(valti).name.length == 14 && typeid(valti).name[9..14] == "Const") valti = (cast(TypeInfo_Const)valti).base; else break; } return valti; } void formatArg(char fc) { bool vbit; ulong vnumber; char vchar; dchar vdchar; Object vobject; real vreal; creal vcreal; Mangle m2; int signed = 0; uint base = 10; int uc; char[ulong.sizeof * 8] tmpbuf; // long enough to print long in binary const(char)* prefix = ""; string s; void putstr(const char[] s) { //printf("putstr: s = %.*s, flags = x%x\n", s.length, s.ptr, flags); ptrdiff_t padding = field_width - (strlen(prefix) + toUCSindex(s, s.length)); ptrdiff_t prepad = 0; ptrdiff_t postpad = 0; if (padding > 0) { if (flags & FLdash) postpad = padding; else prepad = padding; } if (flags & FL0pad) { while (*prefix) putc(*prefix++); while (prepad--) putc('0'); } else { while (prepad--) putc(' '); while (*prefix) putc(*prefix++); } foreach (dchar c; s) putc(c); while (postpad--) putc(' '); } void putreal(real v) { //printf("putreal %Lg\n", vreal); switch (fc) { case 's': fc = 'g'; break; case 'f', 'F', 'e', 'E', 'g', 'G', 'a', 'A': break; default: //printf("fc = '%c'\n", fc); Lerror: throw new FormatException("incompatible format character for floating point type"); } version (DigitalMarsC) { uint sl; char[] fbuf = tmpbuf; if (!(flags & FLprecision)) precision = 6; while (1) { sl = fbuf.length; prefix = (*__pfloatfmt)(fc, flags | FLlngdbl, precision, &v, cast(char*)fbuf, &sl, field_width); if (sl != -1) break; sl = fbuf.length * 2; fbuf = (cast(char*)alloca(sl * char.sizeof))[0 .. sl]; } putstr(fbuf[0 .. sl]); } else { ptrdiff_t sl; char[] fbuf = tmpbuf; char[12] format; format[0] = '%'; int i = 1; if (flags & FLdash) format[i++] = '-'; if (flags & FLplus) format[i++] = '+'; if (flags & FLspace) format[i++] = ' '; if (flags & FLhash) format[i++] = '#'; if (flags & FL0pad) format[i++] = '0'; format[i + 0] = '*'; format[i + 1] = '.'; format[i + 2] = '*'; format[i + 3] = 'L'; format[i + 4] = fc; format[i + 5] = 0; if (!(flags & FLprecision)) precision = -1; while (1) { sl = fbuf.length; int n; version (CRuntime_Microsoft) { import std.math : isNaN, isInfinity; if (isNaN(v)) // snprintf writes 1.#QNAN n = snprintf(fbuf.ptr, sl, "nan"); else if(isInfinity(v)) // snprintf writes 1.#INF n = snprintf(fbuf.ptr, sl, v < 0 ? "-inf" : "inf"); else n = snprintf(fbuf.ptr, sl, format.ptr, field_width, precision, cast(double)v); } else n = snprintf(fbuf.ptr, sl, format.ptr, field_width, precision, v); //printf("format = '%s', n = %d\n", cast(char*)format, n); if (n >= 0 && n < sl) { sl = n; break; } if (n < 0) sl = sl * 2; else sl = n + 1; fbuf = (cast(char*)alloca(sl * char.sizeof))[0 .. sl]; } putstr(fbuf[0 .. sl]); } return; } static Mangle getMan(TypeInfo ti) { auto m = cast(Mangle)typeid(ti).name[9]; if (typeid(ti).name.length == 20 && typeid(ti).name[9..20] == "StaticArray") m = cast(Mangle)'G'; return m; } /* p = pointer to the first element in the array * len = number of elements in the array * valti = type of the elements */ void putArray(void* p, size_t len, TypeInfo valti) { //printf("\nputArray(len = %u), tsize = %u\n", len, valti.tsize); putc('['); valti = skipCI(valti); size_t tsize = valti.tsize; auto argptrSave = argptr; auto tiSave = ti; auto mSave = m; ti = valti; //printf("\n%.*s\n", typeid(valti).name.length, typeid(valti).name.ptr); m = getMan(valti); while (len--) { //doFormat(putc, (&valti)[0 .. 1], p); argptr = p; formatArg('s'); p += tsize; if (len > 0) putc(','); } m = mSave; ti = tiSave; argptr = argptrSave; putc(']'); } void putAArray(ubyte[long] vaa, TypeInfo valti, TypeInfo keyti) { putc('['); bool comma=false; auto argptrSave = argptr; auto tiSave = ti; auto mSave = m; valti = skipCI(valti); keyti = skipCI(keyti); foreach(ref fakevalue; vaa) { if (comma) putc(','); comma = true; void *pkey = &fakevalue; version (D_LP64) pkey -= (long.sizeof + 15) & ~(15); else pkey -= (long.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); // the key comes before the value auto keysize = keyti.tsize; version (D_LP64) auto keysizet = (keysize + 15) & ~(15); else auto keysizet = (keysize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); void* pvalue = pkey + keysizet; //doFormat(putc, (&keyti)[0..1], pkey); m = getMan(keyti); argptr = pkey; ti = keyti; formatArg('s'); putc(':'); //doFormat(putc, (&valti)[0..1], pvalue); m = getMan(valti); argptr = pvalue; ti = valti; formatArg('s'); } m = mSave; ti = tiSave; argptr = argptrSave; putc(']'); } //printf("formatArg(fc = '%c', m = '%c')\n", fc, m); int mi; switch (m) { case Mangle.Tbool: vbit = getArg!(bool)(); if (fc != 's') { vnumber = vbit; goto Lnumber; } putstr(vbit ? "true" : "false"); return; case Mangle.Tchar: vchar = getArg!(char)(); if (fc != 's') { vnumber = vchar; goto Lnumber; } L2: putstr((&vchar)[0 .. 1]); return; case Mangle.Twchar: vdchar = getArg!(wchar)(); goto L1; case Mangle.Tdchar: vdchar = getArg!(dchar)(); L1: if (fc != 's') { vnumber = vdchar; goto Lnumber; } if (vdchar <= 0x7F) { vchar = cast(char)vdchar; goto L2; } else { if (!isValidDchar(vdchar)) throw new UTFException("invalid dchar in format"); char[4] vbuf; putstr(toUTF8(vbuf, vdchar)); } return; case Mangle.Tbyte: signed = 1; vnumber = getArg!(byte)(); goto Lnumber; case Mangle.Tubyte: vnumber = getArg!(ubyte)(); goto Lnumber; case Mangle.Tshort: signed = 1; vnumber = getArg!(short)(); goto Lnumber; case Mangle.Tushort: vnumber = getArg!(ushort)(); goto Lnumber; case Mangle.Tint: signed = 1; vnumber = getArg!(int)(); goto Lnumber; case Mangle.Tuint: Luint: vnumber = getArg!(uint)(); goto Lnumber; case Mangle.Tlong: signed = 1; vnumber = cast(ulong)getArg!(long)(); goto Lnumber; case Mangle.Tulong: Lulong: vnumber = getArg!(ulong)(); goto Lnumber; case Mangle.Tclass: vobject = getArg!(Object)(); if (vobject is null) s = "null"; else s = vobject.toString(); goto Lputstr; case Mangle.Tpointer: vnumber = cast(ulong)getArg!(void*)(); if (fc != 'x') uc = 1; flags |= FL0pad; if (!(flags & FLprecision)) { flags |= FLprecision; precision = (void*).sizeof; } base = 16; goto Lnumber; case Mangle.Tfloat: case Mangle.Tifloat: if (fc == 'x' || fc == 'X') goto Luint; vreal = getArg!(float)(); goto Lreal; case Mangle.Tdouble: case Mangle.Tidouble: if (fc == 'x' || fc == 'X') goto Lulong; vreal = getArg!(double)(); goto Lreal; case Mangle.Treal: case Mangle.Tireal: vreal = getArg!(real)(); goto Lreal; case Mangle.Tcfloat: vcreal = getArg!(cfloat)(); goto Lcomplex; case Mangle.Tcdouble: vcreal = getArg!(cdouble)(); goto Lcomplex; case Mangle.Tcreal: vcreal = getArg!(creal)(); goto Lcomplex; case Mangle.Tsarray: putArray(argptr, (cast(TypeInfo_StaticArray)ti).len, (cast(TypeInfo_StaticArray)ti).next); return; case Mangle.Tarray: mi = 10; if (typeid(ti).name.length == 14 && typeid(ti).name[9..14] == "Array") { // array of non-primitive types TypeInfo tn = (cast(TypeInfo_Array)ti).next; tn = skipCI(tn); switch (cast(Mangle)typeid(tn).name[9]) { case Mangle.Tchar: goto LarrayChar; case Mangle.Twchar: goto LarrayWchar; case Mangle.Tdchar: goto LarrayDchar; default: break; } void[] va = getArg!(void[])(); putArray(va.ptr, va.length, tn); return; } if (typeid(ti).name.length == 25 && typeid(ti).name[9..25] == "AssociativeArray") { // associative array ubyte[long] vaa = getArg!(ubyte[long])(); putAArray(vaa, (cast(TypeInfo_AssociativeArray)ti).next, (cast(TypeInfo_AssociativeArray)ti).key); return; } while (1) { m2 = cast(Mangle)typeid(ti).name[mi]; switch (m2) { case Mangle.Tchar: LarrayChar: s = getArg!(string)(); goto Lputstr; case Mangle.Twchar: LarrayWchar: wchar[] sw = getArg!(wchar[])(); s = toUTF8(sw); goto Lputstr; case Mangle.Tdchar: LarrayDchar: s = toUTF8(getArg!(dstring)()); Lputstr: if (fc != 's') throw new FormatException("string"); if (flags & FLprecision && precision < s.length) s = s[0 .. precision]; putstr(s); break; case Mangle.Tconst: case Mangle.Timmutable: mi++; continue; default: TypeInfo ti2 = primitiveTypeInfo(m2); if (!ti2) goto Lerror; void[] va = getArg!(void[])(); putArray(va.ptr, va.length, ti2); } return; } assert(0); case Mangle.Ttypedef: ti = (cast(TypeInfo_Typedef)ti).base; m = cast(Mangle)typeid(ti).name[9]; formatArg(fc); return; case Mangle.Tenum: ti = (cast(TypeInfo_Enum)ti).base; m = cast(Mangle)typeid(ti).name[9]; formatArg(fc); return; case Mangle.Tstruct: { TypeInfo_Struct tis = cast(TypeInfo_Struct)ti; if (tis.xtoString is null) throw new FormatException("Can't convert " ~ tis.toString() ~ " to string: \"string toString()\" not defined"); s = tis.xtoString(skipArg(tis)); goto Lputstr; } default: goto Lerror; } Lnumber: switch (fc) { case 's': case 'd': if (signed) { if (cast(long)vnumber < 0) { prefix = "-"; vnumber = -vnumber; } else if (flags & FLplus) prefix = "+"; else if (flags & FLspace) prefix = " "; } break; case 'b': signed = 0; base = 2; break; case 'o': signed = 0; base = 8; break; case 'X': uc = 1; if (flags & FLhash && vnumber) prefix = "0X"; signed = 0; base = 16; break; case 'x': if (flags & FLhash && vnumber) prefix = "0x"; signed = 0; base = 16; break; default: goto Lerror; } if (!signed) { switch (m) { case Mangle.Tbyte: vnumber &= 0xFF; break; case Mangle.Tshort: vnumber &= 0xFFFF; break; case Mangle.Tint: vnumber &= 0xFFFFFFFF; break; default: break; } } if (flags & FLprecision && fc != 'p') flags &= ~FL0pad; if (vnumber < base) { if (vnumber == 0 && precision == 0 && flags & FLprecision && !(fc == 'o' && flags & FLhash)) { putstr(null); return; } if (precision == 0 || !(flags & FLprecision)) { vchar = cast(char)('0' + vnumber); if (vnumber < 10) vchar = cast(char)('0' + vnumber); else vchar = cast(char)((uc ? 'A' - 10 : 'a' - 10) + vnumber); goto L2; } } { ptrdiff_t n = tmpbuf.length; char c; int hexoffset = uc ? ('A' - ('9' + 1)) : ('a' - ('9' + 1)); while (vnumber) { c = cast(char)((vnumber % base) + '0'); if (c > '9') c += hexoffset; vnumber /= base; tmpbuf[--n] = c; } if (tmpbuf.length - n < precision && precision < tmpbuf.length) { ptrdiff_t m = tmpbuf.length - precision; tmpbuf[m .. n] = '0'; n = m; } else if (flags & FLhash && fc == 'o') prefix = "0"; putstr(tmpbuf[n .. tmpbuf.length]); return; } Lreal: putreal(vreal); return; Lcomplex: putreal(vcreal.re); if (vcreal.im >= 0) { putc('+'); } putreal(vcreal.im); putc('i'); return; Lerror: throw new FormatException("formatArg"); } for (int j = 0; j < arguments.length; ) { ti = arguments[j++]; //printf("arg[%d]: '%.*s' %d\n", j, typeid(ti).name.length, typeid(ti).name.ptr, typeid(ti).name.length); //ti.print(); flags = 0; precision = 0; field_width = 0; ti = skipCI(ti); int mi = 9; do { if (typeid(ti).name.length <= mi) goto Lerror; m = cast(Mangle)typeid(ti).name[mi++]; } while (m == Mangle.Tconst || m == Mangle.Timmutable); if (m == Mangle.Tarray) { if (typeid(ti).name.length == 14 && typeid(ti).name[9..14] == "Array") { TypeInfo tn = (cast(TypeInfo_Array)ti).next; tn = skipCI(tn); switch (cast(Mangle)typeid(tn).name[9]) { case Mangle.Tchar: case Mangle.Twchar: case Mangle.Tdchar: ti = tn; mi = 9; break; default: break; } } L1: Mangle m2 = cast(Mangle)typeid(ti).name[mi]; string fmt; // format string wstring wfmt; dstring dfmt; /* For performance reasons, this code takes advantage of the * fact that most format strings will be ASCII, and that the * format specifiers are always ASCII. This means we only need * to deal with UTF in a couple of isolated spots. */ switch (m2) { case Mangle.Tchar: fmt = getArg!(string)(); break; case Mangle.Twchar: wfmt = getArg!(wstring)(); fmt = toUTF8(wfmt); break; case Mangle.Tdchar: dfmt = getArg!(dstring)(); fmt = toUTF8(dfmt); break; case Mangle.Tconst: case Mangle.Timmutable: mi++; goto L1; default: formatArg('s'); continue; } for (size_t i = 0; i < fmt.length; ) { dchar c = fmt[i++]; dchar getFmtChar() { // Valid format specifier characters will never be UTF if (i == fmt.length) throw new FormatException("invalid specifier"); return fmt[i++]; } int getFmtInt() { int n; while (1) { n = n * 10 + (c - '0'); if (n < 0) // overflow throw new FormatException("int overflow"); c = getFmtChar(); if (c < '0' || c > '9') break; } return n; } int getFmtStar() { Mangle m; TypeInfo ti; if (j == arguments.length) throw new FormatException("too few arguments"); ti = arguments[j++]; m = cast(Mangle)typeid(ti).name[9]; if (m != Mangle.Tint) throw new FormatException("int argument expected"); return getArg!(int)(); } if (c != '%') { if (c > 0x7F) // if UTF sequence { i--; // back up and decode UTF sequence import std.utf : decode; c = decode(fmt, i); } Lputc: putc(c); continue; } // Get flags {-+ #} flags = 0; while (1) { c = getFmtChar(); switch (c) { case '-': flags |= FLdash; continue; case '+': flags |= FLplus; continue; case ' ': flags |= FLspace; continue; case '#': flags |= FLhash; continue; case '0': flags |= FL0pad; continue; case '%': if (flags == 0) goto Lputc; break; default: break; } break; } // Get field width field_width = 0; if (c == '*') { field_width = getFmtStar(); if (field_width < 0) { flags |= FLdash; field_width = -field_width; } c = getFmtChar(); } else if (c >= '0' && c <= '9') field_width = getFmtInt(); if (flags & FLplus) flags &= ~FLspace; if (flags & FLdash) flags &= ~FL0pad; // Get precision precision = 0; if (c == '.') { flags |= FLprecision; //flags &= ~FL0pad; c = getFmtChar(); if (c == '*') { precision = getFmtStar(); if (precision < 0) { precision = 0; flags &= ~FLprecision; } c = getFmtChar(); } else if (c >= '0' && c <= '9') precision = getFmtInt(); } if (j == arguments.length) goto Lerror; ti = arguments[j++]; ti = skipCI(ti); mi = 9; do { m = cast(Mangle)typeid(ti).name[mi++]; } while (m == Mangle.Tconst || m == Mangle.Timmutable); if (c > 0x7F) // if UTF sequence goto Lerror; // format specifiers can't be UTF formatArg(cast(char)c); } } else { formatArg('s'); } } return; Lerror: throw new FormatException(); } private bool needToSwapEndianess(Char)(ref FormatSpec!Char f) { import std.system : endian, Endian; return endian == Endian.littleEndian && f.flPlus || endian == Endian.bigEndian && f.flDash; } /* ======================== Unit Tests ====================================== */ unittest { import std.conv : octal; int i; string s; debug(format) printf("std.format.format.unittest\n"); s = format("hello world! %s %s %s%s%s", true, 57, 1_000_000_000, 'x', " foo"); assert(s == "hello world! true 57 1000000000x foo"); s = format("%s %A %s", 1.67, -1.28, float.nan); /* The host C library is used to format floats. * C99 doesn't specify what the hex digit before the decimal point * is for %A. */ //version (linux) // assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan"); //else version (OSX) // assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan", s); //else version (MinGW) assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan", s); else version (CRuntime_Microsoft) assert(s == "1.67 -0X1.47AE14P+0 nan" || s == "1.67 -0X1.47AE147AE147BP+0 nan", s); // MSVCRT 14+ (VS 2015) else assert(s == "1.67 -0X1.47AE147AE147BP+0 nan", s); s = format("%x %X", 0x1234AF, 0xAFAFAFAF); assert(s == "1234af AFAFAFAF"); s = format("%b %o", 0x1234AF, 0xAFAFAFAF); assert(s == "100100011010010101111 25753727657"); s = format("%d %s", 0x1234AF, 0xAFAFAFAF); assert(s == "1193135 2947526575"); //version(X86_64) //{ // pragma(msg, "several format tests disabled on x86_64 due to bug 5625"); //} //else //{ s = format("%s", 1.2 + 3.4i); assert(s == "1.2+3.4i", s); //s = format("%x %X", 1.32, 6.78f); //assert(s == "3ff51eb851eb851f 40D8F5C3"); //} s = format("%#06.*f",2,12.345); assert(s == "012.35"); s = format("%#0*.*f",6,2,12.345); assert(s == "012.35"); s = format("%7.4g:", 12.678); assert(s == " 12.68:"); s = format("%7.4g:", 12.678L); assert(s == " 12.68:"); s = format("%04f|%05d|%#05x|%#5x",-4.0,-10,1,1); assert(s == "-4.000000|-0010|0x001| 0x1"); i = -10; s = format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(s == "-10|-10|-10|-10|-10.0000"); i = -5; s = format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(s == "-5| -5|-05|-5|-5.0000"); i = 0; s = format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(s == "0| 0|000|0|0.0000"); i = 5; s = format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(s == "5| 5|005|5|5.0000"); i = 10; s = format("%d|%3d|%03d|%1d|%01.4f",i,i,i,i,cast(double) i); assert(s == "10| 10|010|10|10.0000"); s = format("%.0d", 0); assert(s == ""); s = format("%.g", .34); assert(s == "0.3"); s = format("%.0g", .34); assert(s == "0.3"); s = format("%.2g", .34); assert(s == "0.34"); s = format("%0.0008f", 1e-08); assert(s == "0.00000001"); s = format("%0.0008f", 1e-05); assert(s == "0.00001000"); s = "helloworld"; string r; r = format("%.2s", s[0..5]); assert(r == "he"); r = format("%.20s", s[0..5]); assert(r == "hello"); r = format("%8s", s[0..5]); assert(r == " hello"); byte[] arrbyte = new byte[4]; arrbyte[0] = 100; arrbyte[1] = -99; arrbyte[3] = 0; r = format("%s", arrbyte); assert(r == "[100, -99, 0, 0]"); ubyte[] arrubyte = new ubyte[4]; arrubyte[0] = 100; arrubyte[1] = 200; arrubyte[3] = 0; r = format("%s", arrubyte); assert(r == "[100, 200, 0, 0]"); short[] arrshort = new short[4]; arrshort[0] = 100; arrshort[1] = -999; arrshort[3] = 0; r = format("%s", arrshort); assert(r == "[100, -999, 0, 0]"); ushort[] arrushort = new ushort[4]; arrushort[0] = 100; arrushort[1] = 20_000; arrushort[3] = 0; r = format("%s", arrushort); assert(r == "[100, 20000, 0, 0]"); int[] arrint = new int[4]; arrint[0] = 100; arrint[1] = -999; arrint[3] = 0; r = format("%s", arrint); assert(r == "[100, -999, 0, 0]"); long[] arrlong = new long[4]; arrlong[0] = 100; arrlong[1] = -999; arrlong[3] = 0; r = format("%s", arrlong); assert(r == "[100, -999, 0, 0]"); ulong[] arrulong = new ulong[4]; arrulong[0] = 100; arrulong[1] = 999; arrulong[3] = 0; r = format("%s", arrulong); assert(r == "[100, 999, 0, 0]"); string[] arr2 = new string[4]; arr2[0] = "hello"; arr2[1] = "world"; arr2[3] = "foo"; r = format("%s", arr2); assert(r == `["hello", "world", "", "foo"]`); r = format("%.8d", 7); assert(r == "00000007"); r = format("%.8x", 10); assert(r == "0000000a"); r = format("%-3d", 7); assert(r == "7 "); r = format("%*d", -3, 7); assert(r == "7 "); r = format("%.*d", -3, 7); assert(r == "7"); r = format("abc"c); assert(r == "abc"); //format() returns the same type as inputted. wstring wr; wr = format("def"w); assert(wr == "def"w); dstring dr; dr = format("ghi"d); assert(dr == "ghi"d); void* p = cast(void*)0xDEADBEEF; r = format("%s", p); assert(r == "DEADBEEF"); r = format("%#x", 0xabcd); assert(r == "0xabcd"); r = format("%#X", 0xABCD); assert(r == "0XABCD"); r = format("%#o", octal!12345); assert(r == "012345"); r = format("%o", 9); assert(r == "11"); r = format("%#o", 0); // issue 15663 assert(r == "0"); r = format("%+d", 123); assert(r == "+123"); r = format("%+d", -123); assert(r == "-123"); r = format("% d", 123); assert(r == " 123"); r = format("% d", -123); assert(r == "-123"); r = format("%%"); assert(r == "%"); r = format("%d", true); assert(r == "1"); r = format("%d", false); assert(r == "0"); r = format("%d", 'a'); assert(r == "97"); wchar wc = 'a'; r = format("%d", wc); assert(r == "97"); dchar dc = 'a'; r = format("%d", dc); assert(r == "97"); byte b = byte.max; r = format("%x", b); assert(r == "7f"); r = format("%x", ++b); assert(r == "80"); r = format("%x", ++b); assert(r == "81"); short sh = short.max; r = format("%x", sh); assert(r == "7fff"); r = format("%x", ++sh); assert(r == "8000"); r = format("%x", ++sh); assert(r == "8001"); i = int.max; r = format("%x", i); assert(r == "7fffffff"); r = format("%x", ++i); assert(r == "80000000"); r = format("%x", ++i); assert(r == "80000001"); r = format("%x", 10); assert(r == "a"); r = format("%X", 10); assert(r == "A"); r = format("%x", 15); assert(r == "f"); r = format("%X", 15); assert(r == "F"); Object c = null; r = format("%s", c); assert(r == "null"); enum TestEnum { Value1, Value2 } r = format("%s", TestEnum.Value2); assert(r == "Value2"); immutable(char[5])[int] aa = ([3:"hello", 4:"betty"]); r = format("%s", aa.values); assert(r == `["hello", "betty"]` || r == `["betty", "hello"]`); r = format("%s", aa); assert(r == `[3:"hello", 4:"betty"]` || r == `[4:"betty", 3:"hello"]`); static const dchar[] ds = ['a','b']; for (int j = 0; j < ds.length; ++j) { r = format(" %d", ds[j]); if (j == 0) assert(r == " 97"); else assert(r == " 98"); } r = format(">%14d<, %s", 15, [1,2,3]); assert(r == "> 15<, [1, 2, 3]"); assert(format("%8s", "bar") == " bar"); assert(format("%8s", "b\u00e9ll\u00f4") == " b\u00e9ll\u00f4"); } unittest { // bugzilla 3479 import std.array; auto stream = appender!(char[])(); formattedWrite(stream, "%2$.*1$d", 12, 10); assert(stream.data == "000000000010", stream.data); } unittest { // bug 6893 import std.array; enum E : ulong { A, B, C } auto stream = appender!(char[])(); formattedWrite(stream, "%s", E.C); assert(stream.data == "C"); } /***************************************************** * Format arguments into a string. * * Params: fmt = Format string. For detailed specification, see $(XREF _format,formattedWrite). * args = Variadic list of arguments to format into returned string. */ immutable(Char)[] format(Char, Args...)(in Char[] fmt, Args args) if (isSomeChar!Char) { import std.format : formattedWrite, FormatException; import std.array : appender; auto w = appender!(immutable(Char)[]); auto n = formattedWrite(w, fmt, args); version (all) { // In the future, this check will be removed to increase consistency // with formattedWrite import std.conv : text; import std.exception : enforce; enforce(n == args.length, new FormatException( text("Orphan format arguments: args[", n, "..", args.length, "]"))); } return w.data; } unittest { import std.format; import core.exception; import std.exception; assertCTFEable!( { // assert(format(null) == ""); assert(format("foo") == "foo"); assert(format("foo%%") == "foo%"); assert(format("foo%s", 'C') == "fooC"); assert(format("%s foo", "bar") == "bar foo"); assert(format("%s foo %s", "bar", "abc") == "bar foo abc"); assert(format("foo %d", -123) == "foo -123"); assert(format("foo %d", 123) == "foo 123"); assertThrown!FormatException(format("foo %s")); assertThrown!FormatException(format("foo %s", 123, 456)); assert(format("hel%slo%s%s%s", "world", -138, 'c', true) == "helworldlo-138ctrue"); }); assert(is(typeof(format("happy")) == string)); assert(is(typeof(format("happy"w)) == wstring)); assert(is(typeof(format("happy"d)) == dstring)); } /***************************************************** * Format arguments into buffer $(I buf) which must be large * enough to hold the result. Throws RangeError if it is not. * Returns: The slice of $(D buf) containing the formatted string. */ char[] sformat(Char, Args...)(char[] buf, in Char[] fmt, Args args) { import core.exception : onRangeError; import std.utf : encode; import std.format : formattedWrite, FormatException; size_t i; struct Sink { void put(dchar c) { char[4] enc; auto n = encode(enc, c); if (buf.length < i + n) onRangeError("std.string.sformat", 0); buf[i .. i + n] = enc[0 .. n]; i += n; } void put(const(char)[] s) { if (buf.length < i + s.length) onRangeError("std.string.sformat", 0); buf[i .. i + s.length] = s[]; i += s.length; } void put(const(wchar)[] s) { for (; !s.empty; s.popFront()) put(s.front); } void put(const(dchar)[] s) { for (; !s.empty; s.popFront()) put(s.front); } } auto n = formattedWrite(Sink(), fmt, args); version (all) { // In the future, this check will be removed to increase consistency // with formattedWrite import std.conv : text; import std.exception : enforce; enforce(n == args.length, new FormatException( text("Orphan format arguments: args[", n, "..", args.length, "]"))); } return buf[0 .. i]; } unittest { import core.exception; import std.format; debug(string) trustedPrintf("std.string.sformat.unittest\n"); import std.exception; assertCTFEable!( { char[10] buf; assert(sformat(buf[], "foo") == "foo"); assert(sformat(buf[], "foo%%") == "foo%"); assert(sformat(buf[], "foo%s", 'C') == "fooC"); assert(sformat(buf[], "%s foo", "bar") == "bar foo"); assertThrown!RangeError(sformat(buf[], "%s foo %s", "bar", "abc")); assert(sformat(buf[], "foo %d", -123) == "foo -123"); assert(sformat(buf[], "foo %d", 123) == "foo 123"); assertThrown!FormatException(sformat(buf[], "foo %s")); assertThrown!FormatException(sformat(buf[], "foo %s", 123, 456)); assert(sformat(buf[], "%s %s %s", "c"c, "w"w, "d"d) == "c w d"); }); } ldc-1.1.0-beta3-src/runtime/phobos/std/ascii.d0000664000175000017500000004025512776215007017151 0ustar kaikai// Written in the D programming language. /++ Functions which operate on ASCII characters. All of the functions in std._ascii accept Unicode characters but effectively ignore them if they're not ASCII. All $(D isX) functions return $(D false) for non-ASCII characters, and all $(D toX) functions do nothing to non-ASCII characters. For functions which operate on Unicode characters, see $(LINK2 std_uni.html, std.uni). References: $(LINK2 http://www.digitalmars.com/d/ascii-table.html, ASCII Table), $(WEB en.wikipedia.org/wiki/Ascii, Wikipedia) Macros: WIKI=Phobos/StdASCII Copyright: Copyright 2000 - 2013 License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB digitalmars.com, Walter Bright) and Jonathan M Davis Source: $(PHOBOSSRC std/_ascii.d) +/ module std.ascii; version (unittest) { // FIXME: When dmd bug #314 is fixed, make these selective. import std.meta; // : AliasSeq; import std.range; // : chain; import std.traits; // : functionAttributes, FunctionAttribute, isSafe; } immutable fullHexDigits = "0123456789ABCDEFabcdef"; /// 0..9A..Fa..f immutable hexDigits = fullHexDigits[0..16]; /// 0..9A..F immutable lowerHexDigits = "0123456789abcdef"; /// 0..9a..f immutable digits = hexDigits[0..10]; /// 0..9 immutable octalDigits = digits[0..8]; /// 0..7 immutable letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; /// A..Za..z immutable uppercase = letters[0..26]; /// A..Z immutable lowercase = letters[26..52]; /// a..z immutable whitespace = " \t\v\r\n\f"; /// ASCII _whitespace /++ Letter case specifier. +/ enum LetterCase : bool { upper, /// Upper case letters lower /// Lower case letters } /// Newline sequence for this system. version(Windows) immutable newline = "\r\n"; else version(Posix) immutable newline = "\n"; else static assert(0, "Unsupported OS"); /++ Params: c = The character to test. Returns: Whether $(D c) is a letter or a number (0..9, a..z, A..Z). +/ bool isAlphaNum(dchar c) @safe pure nothrow @nogc { return c <= 'z' && c >= '0' && (c <= '9' || c >= 'a' || (c >= 'A' && c <= 'Z')); } /// @safe pure nothrow @nogc unittest { assert( isAlphaNum('A')); assert( isAlphaNum('1')); assert(!isAlphaNum('#')); // N.B.: does not return true for non-ASCII Unicode alphanumerics: assert(!isAlphaNum('á')); } unittest { foreach(c; chain(digits, octalDigits, fullHexDigits, letters, lowercase, uppercase)) assert(isAlphaNum(c)); foreach(c; whitespace) assert(!isAlphaNum(c)); } /++ Params: c = The character to test. Returns: Whether $(D c) is an ASCII letter (A..Z, a..z). +/ bool isAlpha(dchar c) @safe pure nothrow @nogc { // Optimizer can turn this into a bitmask operation on 64 bit code return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } /// @safe pure nothrow @nogc unittest { assert( isAlpha('A')); assert(!isAlpha('1')); assert(!isAlpha('#')); // N.B.: does not return true for non-ASCII Unicode alphabetic characters: assert(!isAlpha('á')); } unittest { foreach(c; chain(letters, lowercase, uppercase)) assert(isAlpha(c)); foreach(c; chain(digits, octalDigits, whitespace)) assert(!isAlpha(c)); } /++ Params: c = The character to test. Returns: Whether $(D c) is a lowercase ASCII letter (a..z). +/ bool isLower(dchar c) @safe pure nothrow @nogc { return c >= 'a' && c <= 'z'; } /// @safe pure nothrow @nogc unittest { assert( isLower('a')); assert(!isLower('A')); assert(!isLower('#')); // N.B.: does not return true for non-ASCII Unicode lowercase letters assert(!isLower('á')); assert(!isLower('Á')); } unittest { foreach(c; lowercase) assert(isLower(c)); foreach(c; chain(digits, uppercase, whitespace)) assert(!isLower(c)); } /++ Params: c = The character to test. Returns: Whether $(D c) is an uppercase ASCII letter (A..Z). +/ bool isUpper(dchar c) @safe pure nothrow @nogc { return c <= 'Z' && 'A' <= c; } /// @safe pure nothrow @nogc unittest { assert( isUpper('A')); assert(!isUpper('a')); assert(!isUpper('#')); // N.B.: does not return true for non-ASCII Unicode uppercase letters assert(!isUpper('á')); assert(!isUpper('Á')); } unittest { foreach(c; uppercase) assert(isUpper(c)); foreach(c; chain(digits, lowercase, whitespace)) assert(!isUpper(c)); } /++ Params: c = The character to test. Returns: Whether $(D c) is a digit (0..9). +/ bool isDigit(dchar c) @safe pure nothrow @nogc { return '0' <= c && c <= '9'; } /// @safe pure nothrow @nogc unittest { assert( isDigit('3')); assert( isDigit('8')); assert(!isDigit('B')); assert(!isDigit('#')); // N.B.: does not return true for non-ASCII Unicode numbers assert(!isDigit('0')); // full-width digit zero (U+FF10) assert(!isDigit('4')); // full-width digit four (U+FF14) } unittest { foreach(c; digits) assert(isDigit(c)); foreach(c; chain(letters, whitespace)) assert(!isDigit(c)); } /++ Params: c = The character to test. Returns: Whether $(D c) is a digit in base 8 (0..7). +/ bool isOctalDigit(dchar c) @safe pure nothrow @nogc { return c >= '0' && c <= '7'; } /// @safe pure nothrow @nogc unittest { assert( isOctalDigit('0')); assert( isOctalDigit('7')); assert(!isOctalDigit('8')); assert(!isOctalDigit('A')); assert(!isOctalDigit('#')); } unittest { foreach(c; octalDigits) assert(isOctalDigit(c)); foreach(c; chain(letters, ['8', '9'], whitespace)) assert(!isOctalDigit(c)); } /++ Params: c = The character to test. Returns: Whether $(D c) is a digit in base 16 (0..9, A..F, a..f). +/ bool isHexDigit(dchar c) @safe pure nothrow @nogc { return c <= 'f' && c >= '0' && (c <= '9' || c >= 'a' || (c >= 'A' && c <= 'F')); } /// @safe pure nothrow @nogc unittest { assert( isHexDigit('0')); assert( isHexDigit('A')); assert( isHexDigit('f')); // lowercase hex digits are accepted assert(!isHexDigit('g')); assert(!isHexDigit('G')); assert(!isHexDigit('#')); } unittest { foreach(c; fullHexDigits) assert(isHexDigit(c)); foreach(c; chain(lowercase[6 .. $], uppercase[6 .. $], whitespace)) assert(!isHexDigit(c)); } /++ Params: c = The character to test. Returns: Whether or not $(D c) is a whitespace character. That includes the space, tab, vertical tab, form feed, carriage return, and linefeed characters. +/ bool isWhite(dchar c) @safe pure nothrow @nogc { return c == ' ' || (c >= 0x09 && c <= 0x0D); } /// @safe pure nothrow @nogc unittest { assert( isWhite(' ')); assert( isWhite('\t')); assert( isWhite('\n')); assert(!isWhite('1')); assert(!isWhite('a')); assert(!isWhite('#')); // N.B.: Does not return true for non-ASCII Unicode whitespace characters. static import std.uni; assert(std.uni.isWhite('\u00A0')); assert(!isWhite('\u00A0')); // std.ascii.isWhite } unittest { foreach(c; whitespace) assert(isWhite(c)); foreach(c; chain(digits, letters)) assert(!isWhite(c)); } /++ Params: c = The character to test. Returns: Whether $(D c) is a control character. +/ bool isControl(dchar c) @safe pure nothrow @nogc { return c < 0x20 || c == 0x7F; } /// @safe pure nothrow @nogc unittest { assert( isControl('\0')); assert( isControl('\022')); assert( isControl('\n')); // newline is both whitespace and control assert(!isControl(' ')); assert(!isControl('1')); assert(!isControl('a')); assert(!isControl('#')); // N.B.: non-ASCII Unicode control characters are not recognized: assert(!isControl('\u0080')); assert(!isControl('\u2028')); assert(!isControl('\u2029')); } unittest { foreach(dchar c; 0 .. 32) assert(isControl(c)); assert(isControl(127)); foreach(c; chain(digits, letters, [' '])) assert(!isControl(c)); } /++ Params: c = The character to test. Returns: Whether or not $(D c) is a punctuation character. That includes all ASCII characters which are not control characters, letters, digits, or whitespace. +/ bool isPunctuation(dchar c) @safe pure nothrow @nogc { return c <= '~' && c >= '!' && !isAlphaNum(c); } /// @safe pure nothrow @nogc unittest { assert( isPunctuation('.')); assert( isPunctuation(',')); assert( isPunctuation(':')); assert( isPunctuation('!')); assert( isPunctuation('#')); assert( isPunctuation('~')); assert( isPunctuation('+')); assert( isPunctuation('_')); assert(!isPunctuation('1')); assert(!isPunctuation('a')); assert(!isPunctuation(' ')); assert(!isPunctuation('\n')); assert(!isPunctuation('\0')); // N.B.: Non-ASCII Unicode punctuation characters are not recognized. assert(!isPunctuation('\u2012')); // (U+2012 = en-dash) } unittest { foreach(dchar c; 0 .. 128) { if(isControl(c) || isAlphaNum(c) || c == ' ') assert(!isPunctuation(c)); else assert(isPunctuation(c)); } } /++ Params: c = The character to test. Returns: Whether or not $(D c) is a printable character other than the space character. +/ bool isGraphical(dchar c) @safe pure nothrow @nogc { return '!' <= c && c <= '~'; } /// @safe pure nothrow @nogc unittest { assert( isGraphical('1')); assert( isGraphical('a')); assert( isGraphical('#')); assert(!isGraphical(' ')); // whitespace is not graphical assert(!isGraphical('\n')); assert(!isGraphical('\0')); // N.B.: Unicode graphical characters are not regarded as such. assert(!isGraphical('á')); } unittest { foreach(dchar c; 0 .. 128) { if(isControl(c) || c == ' ') assert(!isGraphical(c)); else assert(isGraphical(c)); } } /++ Params: c = The character to test. Returns: Whether or not $(D c) is a printable character - including the space character. +/ bool isPrintable(dchar c) @safe pure nothrow @nogc { return c >= ' ' && c <= '~'; } /// @safe pure nothrow @nogc unittest { assert( isPrintable(' ')); // whitespace is printable assert( isPrintable('1')); assert( isPrintable('a')); assert( isPrintable('#')); assert(!isPrintable('\0')); // control characters are not printable // N.B.: Printable non-ASCII Unicode characters are not recognized. assert(!isPrintable('á')); } unittest { foreach(dchar c; 0 .. 128) { if(isControl(c)) assert(!isPrintable(c)); else assert(isPrintable(c)); } } /++ Params: c = The character to test. Returns: Whether or not $(D c) is in the ASCII character set - i.e. in the range 0..0x7F. +/ bool isASCII(dchar c) @safe pure nothrow @nogc { return c <= 0x7F; } /// @safe pure nothrow @nogc unittest { assert( isASCII('a')); assert(!isASCII('á')); } unittest { foreach(dchar c; 0 .. 128) assert(isASCII(c)); assert(!isASCII(128)); } /++ Converts an ASCII letter to lowercase. Params: c = A character of any type that implicitly converts to $(D dchar). In the case where it's a built-in type, or an enum of a built-in type, $(D Unqual!(OriginalType!C)) is returned, whereas if it's a user-defined type, $(D dchar) is returned. Returns: The corresponding lowercase letter, if $(D c) is an uppercase ASCII character, otherwise $(D c) itself. +/ auto toLower(C)(C c) if(is(C : dchar)) { import std.traits : isAggregateType, OriginalType, Unqual; alias OC = OriginalType!C; static if (isAggregateType!OC) alias R = dchar; else alias R = Unqual!OC; return isUpper(c) ? cast(R)(cast(R)c + 'a' - 'A') : cast(R)c; } /// @safe pure nothrow @nogc unittest { assert(toLower('a') == 'a'); assert(toLower('A') == 'a'); assert(toLower('#') == '#'); // N.B.: Non-ASCII Unicode uppercase letters are not converted. assert(toLower('Á') == 'Á'); } @safe pure nothrow unittest { foreach(C; AliasSeq!(char, wchar, dchar, immutable char, ubyte)) { foreach(i, c; uppercase) assert(toLower(cast(C)c) == lowercase[i]); foreach(C c; 0 .. 128) { if(c < 'A' || c > 'Z') assert(toLower(c) == c); else assert(toLower(c) != c); } foreach(C c; 128 .. C.max) assert(toLower(c) == c); //CTFE static assert(toLower(cast(C)'a') == 'a'); static assert(toLower(cast(C)'A') == 'a'); } } /++ Converts an ASCII letter to uppercase. Params: c = Any type which implicitly converts to $(D dchar). In the case where it's a built-in type, or an enum of a built-in type, $(D Unqual!(OriginalType!C)) is returned, whereas if it's a user-defined type, $(D dchar) is returned. Returns: The corresponding uppercase letter, if $(D c) is a lowercase ASCII character, otherwise $(D c) itself. +/ auto toUpper(C)(C c) if(is(C : dchar)) { import std.traits : isAggregateType, OriginalType, Unqual; alias OC = OriginalType!C; static if (isAggregateType!OC) alias R = dchar; else alias R = Unqual!OC; return isLower(c) ? cast(R)(cast(R)c - ('a' - 'A')) : cast(R)c; } /// @safe pure nothrow @nogc unittest { assert(toUpper('a') == 'A'); assert(toUpper('A') == 'A'); assert(toUpper('#') == '#'); // N.B.: Non-ASCII Unicode lowercase letters are not converted. assert(toUpper('á') == 'á'); } @safe pure nothrow unittest { foreach(C; AliasSeq!(char, wchar, dchar, immutable char, ubyte)) { foreach(i, c; lowercase) assert(toUpper(cast(C)c) == uppercase[i]); foreach(C c; 0 .. 128) { if(c < 'a' || c > 'z') assert(toUpper(c) == c); else assert(toUpper(c) != c); } foreach(C c; 128 .. C.max) assert(toUpper(c) == c); //CTFE static assert(toUpper(cast(C)'a') == 'A'); static assert(toUpper(cast(C)'A') == 'A'); } } unittest //Test both toUpper and toLower with non-builtin { //User Defined [Char|Wchar|Dchar] static struct UDC { char c; alias c this; } static struct UDW { wchar c; alias c this; } static struct UDD { dchar c; alias c this; } //[Char|Wchar|Dchar] Enum enum CE : char {a = 'a', A = 'A'} enum WE : wchar {a = 'a', A = 'A'} enum DE : dchar {a = 'a', A = 'A'} //User Defined [Char|Wchar|Dchar] Enum enum UDCE : UDC {a = UDC('a'), A = UDC('A')} enum UDWE : UDW {a = UDW('a'), A = UDW('A')} enum UDDE : UDD {a = UDD('a'), A = UDD('A')} //User defined types with implicit cast to dchar test. foreach (Char; AliasSeq!(UDC, UDW, UDD)) { assert(toLower(Char('a')) == 'a'); assert(toLower(Char('A')) == 'a'); static assert(toLower(Char('a')) == 'a'); static assert(toLower(Char('A')) == 'a'); static assert(toUpper(Char('a')) == 'A'); static assert(toUpper(Char('A')) == 'A'); } //Various enum tests. foreach (Enum; AliasSeq!(CE, WE, DE, UDCE, UDWE, UDDE)) { assert(toLower(Enum.a) == 'a'); assert(toLower(Enum.A) == 'a'); assert(toUpper(Enum.a) == 'A'); assert(toUpper(Enum.A) == 'A'); static assert(toLower(Enum.a) == 'a'); static assert(toLower(Enum.A) == 'a'); static assert(toUpper(Enum.a) == 'A'); static assert(toUpper(Enum.A) == 'A'); } //Return value type tests for enum of non-UDT. These should be the original type. foreach (T; AliasSeq!(CE, WE, DE)) { alias C = OriginalType!T; static assert(is(typeof(toLower(T.init)) == C)); static assert(is(typeof(toUpper(T.init)) == C)); } //Return value tests for UDT and enum of UDT. These should be dchar foreach (T; AliasSeq!(UDC, UDW, UDD, UDCE, UDWE, UDDE)) { static assert(is(typeof(toLower(T.init)) == dchar)); static assert(is(typeof(toUpper(T.init)) == dchar)); } } ldc-1.1.0-beta3-src/runtime/phobos/std/stdint.d0000664000175000017500000000666412776215007017374 0ustar kaikai// Written in the D programming language. /** * D constrains integral types to specific sizes. But efficiency of different sizes varies from machine to machine, pointer sizes vary, and the maximum integer size varies. stdint offers a portable way of trading off size vs efficiency, in a manner compatible with the stdint.h definitions in C. The exact aliases are types of exactly the specified number of bits. The at least aliases are at least the specified number of bits large, and can be larger. The fast aliases are the fastest integral type supported by the processor that is at least as wide as the specified number of bits. The aliases are: $(ATABLE $(TR $(TH Exact Alias) $(TH Description) $(TH At Least Alias) $(TH Description) $(TH Fast Alias) $(TH Description) )$(TR $(TD int8_t) $(TD exactly 8 bits signed) $(TD int_least8_t) $(TD at least 8 bits signed) $(TD int_fast8_t) $(TD fast 8 bits signed) )$(TR $(TD uint8_t) $(TD exactly 8 bits unsigned) $(TD uint_least8_t) $(TD at least 8 bits unsigned) $(TD uint_fast8_t) $(TD fast 8 bits unsigned) )$(TR $(TD int16_t) $(TD exactly 16 bits signed) $(TD int_least16_t) $(TD at least 16 bits signed) $(TD int_fast16_t) $(TD fast 16 bits signed) )$(TR $(TD uint16_t) $(TD exactly 16 bits unsigned) $(TD uint_least16_t) $(TD at least 16 bits unsigned) $(TD uint_fast16_t) $(TD fast 16 bits unsigned) )$(TR $(TD int32_t) $(TD exactly 32 bits signed) $(TD int_least32_t) $(TD at least 32 bits signed) $(TD int_fast32_t) $(TD fast 32 bits signed) )$(TR $(TD uint32_t) $(TD exactly 32 bits unsigned) $(TD uint_least32_t) $(TD at least 32 bits unsigned) $(TD uint_fast32_t) $(TD fast 32 bits unsigned) )$(TR $(TD int64_t) $(TD exactly 64 bits signed) $(TD int_least64_t) $(TD at least 64 bits signed) $(TD int_fast64_t) $(TD fast 64 bits signed) )$(TR $(TD uint64_t) $(TD exactly 64 bits unsigned) $(TD uint_least64_t) $(TD at least 64 bits unsigned) $(TD uint_fast64_t) $(TD fast 64 bits unsigned) )) The ptr aliases are integral types guaranteed to be large enough to hold a pointer without losing bits: $(ATABLE $(TR $(TH Alias) $(TH Description) )$(TR $(TD intptr_t) $(TD signed integral type large enough to hold a pointer) )$(TR $(TD uintptr_t) $(TD unsigned integral type large enough to hold a pointer) )) The max aliases are the largest integral types: $(ATABLE $(TR $(TH Alias) $(TH Description) )$(TR $(TD intmax_t) $(TD the largest signed integral type) )$(TR $(TD uintmax_t) $(TD the largest unsigned integral type) )) * Macros: * WIKI=Phobos/StdStdint * ATABLE=$0
* * Copyright: Copyright Digital Mars 2000 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * Source: $(PHOBOSSRC std/_stdint.d) */ /* Copyright Digital Mars 2000 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.stdint; public import core.stdc.stdint; ldc-1.1.0-beta3-src/runtime/phobos/std/demangle.d0000664000175000017500000000406012776215007017627 0ustar kaikai// Written in the D programming language. /** * Demangle D mangled names. * * Macros: * WIKI = Phobos/StdDemangle * * Copyright: Copyright Digital Mars 2000 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright), * Thomas K$(UUML)hne, Frits van Bommel * Source: $(PHOBOSSRC std/_demangle.d) */ /* * Copyright Digital Mars 2000 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.demangle; /+ private class MangleException : Exception { this() { super("MangleException"); } } +/ /***************************** * Demangle D mangled names. * * If it is not a D mangled name, it returns its argument name. * Example: * This program reads standard in and writes it to standard out, * pretty-printing any found D mangled names. ------------------- import core.stdc.stdio : stdin; import std.stdio; import std.ascii; import std.demangle; void test(int x, float y) { } int main() { string buffer; bool inword; int c; writefln("Try typing in: %s", test.mangleof); while ((c = fgetc(stdin)) != EOF) { if (inword) { if (c == '_' || isAlphaNum(c)) buffer ~= cast(char) c; else { inword = false; write(demangle(buffer), cast(char) c); } } else { if (c == '_' || isAlpha(c)) { inword = true; buffer.length = 0; buffer ~= cast(char) c; } else write(cast(char) c); } } if (inword) write(demangle(buffer)); return 0; } ------------------- */ string demangle(string name) { import core.demangle : demangle; import std.exception : assumeUnique; auto ret = demangle(name); return assumeUnique(ret); } ldc-1.1.0-beta3-src/runtime/phobos/std/uuid.d0000664000175000017500000015667412776215007017044 0ustar kaikai/** * A $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, UUID), or * $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, Universally unique identifier), * is intended to uniquely identify information in a distributed environment * without significant central coordination. It can be * used to tag objects with very short lifetimes, or to reliably identify very * persistent objects across a network. * $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Functions) ) $(TR $(TDNW Parsing UUIDs) $(TD $(MYREF parseUUID) $(MYREF UUID) $(MYREF UUIDParsingException) $(MYREF uuidRegex) ) ) $(TR $(TDNW Generating UUIDs) $(TD $(MYREF sha1UUID) $(MYREF randomUUID) $(MYREF md5UUID) ) ) $(TR $(TDNW Using UUIDs) $(TD $(MYREF2 UUID.uuidVersion, uuidVersion) $(MYREF2 UUID.variant, variant) $(MYREF2 UUID.toString, toString) $(MYREF2 UUID.data, data) $(MYREF2 UUID.swap, swap) $(MYREF2 UUID.opEquals, opEquals) $(MYREF2 UUID.opCmp, opCmp) $(MYREF2 UUID.toHash, toHash) ) ) $(TR $(TDNW UUID namespaces) $(TD $(MYREF dnsNamespace) $(MYREF urlNamespace) $(MYREF oidNamespace) $(MYREF x500Namespace) ) ) ) ) * UUIDs have many applications. Some examples follow: Databases may use UUIDs to identify * rows or records in order to ensure that they are unique across different * databases, or for publication/subscription services. Network messages may be * identified with a UUID to ensure that different parts of a message are put back together * again. Distributed computing may use UUIDs to identify a remote procedure call. * Transactions and classes involved in serialization may be identified by UUIDs. * Microsoft's component object model (COM) uses UUIDs to distinguish different software * component interfaces. UUIDs are inserted into documents from Microsoft Office programs. * UUIDs identify audio or video streams in the Advanced Systems Format (ASF). UUIDs are * also a basis for OIDs (object identifiers), and URNs (uniform resource name). * * An attractive feature of UUIDs when compared to alternatives is their relative small size, * of 128 bits, or 16 bytes. Another is that the creation of UUIDs does not require * a centralized authority. * * When UUIDs are generated by one of the defined mechanisms, they are either guaranteed * to be unique, different from all other generated UUIDs (that is, it has never been * generated before and it will never be generated again), or it is extremely likely * to be unique (depending on the mechanism). * * For efficiency, UUID is implemented as a struct. UUIDs are therefore empty if not explicitly * initialized. An UUID is empty if $(MYREF3 UUID.empty, empty) is true. Empty UUIDs are equal to * $(D UUID.init), which is a UUID with all 16 bytes set to 0. * Use UUID's constructors or the UUID generator functions to get an initialized UUID. * * This is a port of $(LINK2 http://www.boost.org/doc/libs/1_42_0/libs/uuid/uuid.html, * boost._uuid) from the Boost project with some minor additions and API * changes for a more D-like API. * * Standards: * $(LINK2 http://www.ietf.org/rfc/rfc4122.txt, RFC 4122) * * See_Also: * $(LINK http://en.wikipedia.org/wiki/Universally_unique_identifier) * * Copyright: Copyright Johannes Pfau 2011 - . * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Johannes Pfau * Source: $(PHOBOSSRC std/_uuid.d) * * Macros: * MYREF2 = $(TT $1)  * MYREF3 = $(D $1) */ /* Copyright Johannes Pfau 2011 - 2012. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.uuid; /// unittest { import std.uuid; UUID[] ids; ids ~= randomUUID(); ids ~= md5UUID("test.name.123"); ids ~= sha1UUID("test.name.123"); foreach(entry; ids) { assert(entry.variant == UUID.Variant.rfc4122); } assert(ids[0].uuidVersion == UUID.Version.randomNumberBased); assert(ids[1].toString() == "22390768-cced-325f-8f0f-cfeaa19d0ccd"); assert(ids[1].data == [34, 57, 7, 104, 204, 237, 50, 95, 143, 15, 207, 234, 161, 157, 12, 205]); UUID id; assert(id.empty); } import std.range.primitives; import std.traits; /** * */ public struct UUID { import std.meta : AliasSeq, allSatisfy; private: alias skipSeq = AliasSeq!(8, 13, 18, 23); alias byteSeq = AliasSeq!(0,2,4,6,/++/9,11,/++/14,16,/++/19,21,/++/24,26,28,30,32,34); @safe pure nothrow @nogc Char toChar(Char)(size_t i) const { if(i <= 9) return cast(Char)('0' + i); else return cast(Char)('a' + (i-10)); } @safe pure nothrow unittest { assert(UUID(cast(ubyte[16])[138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]).toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); } // Reinterpret the UUID as an array of some other primitive. @trusted ref T[16 / T.sizeof] asArrayOf(T)() return if (isIntegral!T) { return *cast(typeof(return)*)&data; } public: /** * RFC 4122 defines different internal data layouts for UUIDs. These are * the UUID formats supported by this module. It's * possible to read, compare and use all these Variants, but * UUIDs generated by this module will always be in rfc4122 format. * * Note: Do not confuse this with $(XREF _variant, _Variant). */ enum Variant { ncs, /// NCS backward compatibility rfc4122, /// Defined in RFC 4122 document microsoft, /// Microsoft Corporation backward compatibility future ///Reserved for future use } /** * RFC 4122 defines different UUID versions. The version shows * how a UUID was generated, e.g. a version 4 UUID was generated * from a random number, a version 3 UUID from an MD5 hash of a name. * * Note: * All of these UUID versions can be read and processed by * $(D std.uuid), but only version 3, 4 and 5 UUIDs can be generated. */ enum Version { ///Unknown version unknown = -1, ///Version 1 timeBased = 1, ///Version 2 dceSecurity = 2, ///Version 3 (Name based + MD5) nameBasedMD5 = 3, ///Version 4 (Random) randomNumberBased = 4, ///Version 5 (Name based + SHA-1) nameBasedSHA1 = 5 } union { /** * It is sometimes useful to get or set the 16 bytes of a UUID * directly. * * Note: * UUID uses a 16-ubyte representation for the UUID data. * RFC 4122 defines a UUID as a special structure in big-endian * format. These 16-ubytes always equal the big-endian structure * defined in RFC 4122. * * Example: * ----------------------------------------------- * auto rawData = uuid.data; //get data * rawData[0] = 1; //modify * uuid.data = rawData; //set data * uuid.data[1] = 2; //modify directly * ----------------------------------------------- */ ubyte[16] data; private ulong[2] ulongs; static if(size_t.sizeof == 4) private uint[4] uints; } /* * We could use a union here to also provide access to the * fields specified in RFC 4122, but as we never have to access * those (only necessary for version 1 (and maybe 2) UUIDs), * that is not needed right now. */ @safe pure unittest { UUID tmp; tmp.data = cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,12, 13,14,15]; assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11, 12,13,14,15]); tmp.data[2] = 3; assert(tmp.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11, 12,13,14,15]); auto tmp2 = cast(immutable UUID)tmp; assert(tmp2.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11, 12,13,14,15]); } /** * Construct a UUID struct from the 16 byte representation * of a UUID. */ @safe pure nothrow @nogc this(ref in ubyte[16] uuidData) { data = uuidData; } /// ditto @safe pure nothrow @nogc this(in ubyte[16] uuidData) { data = uuidData; } /// @safe pure unittest { enum ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; auto uuid = UUID(data); enum ctfe = UUID(data); assert(uuid.data == data); assert(ctfe.data == data); } /** * Construct a UUID struct from the 16 byte representation * of a UUID. Variadic constructor to allow a simpler syntax, see examples. * You need to pass exactly 16 ubytes. */ @safe pure this(T...)(T uuidData) if(uuidData.length == 16 && allSatisfy!(isIntegral, T)) { import std.conv : to; foreach(idx, it; uuidData) { this.data[idx] = to!ubyte(it); } } /// unittest { auto tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11, 12,13,14,15]); } unittest { UUID tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11, 12,13,14,15]); enum UUID ctfeID = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); assert(ctfeID == tmp); //Too few arguments assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14)))); //Too many arguments assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1)))); } /** * * Parse a UUID from its canonical string form. An UUID in its * canonical form looks like this: 8ab3060e-2cba-4f23-b74c-b52db3bdfb46 * * Throws: * $(LREF UUIDParsingException) if the input is invalid * * CTFE: * This function is supported in CTFE code. Note that error messages * caused by a malformed UUID parsed at compile time can be cryptic, * but errors are detected and reported at * compile time. * * Note: * This is a strict parser. It only accepts the pattern above. * It doesn't support any leading or trailing characters. It only * accepts characters used for hex numbers and the string must have * hyphens exactly like above. * * For a less strict parser, see $(LREF parseUUID) */ this(T)(in T[] uuid) if(isSomeChar!(Unqual!T)) { import std.conv : to, parse; if(uuid.length < 36) { throw new UUIDParsingException(to!string(uuid), 0, UUIDParsingException.Reason.tooLittle, "Insufficient Input"); } if(uuid.length > 36) { throw new UUIDParsingException(to!string(uuid), 35, UUIDParsingException.Reason.tooMuch, "Input is too long, need exactly 36 characters"); } enum skipInd = [skipSeq]; foreach(pos; skipInd) if(uuid[pos] != '-') throw new UUIDParsingException(to!string(uuid), pos, UUIDParsingException.Reason.invalidChar, "Expected '-'"); ubyte[16] data2; //ctfe bug uint pos = void; foreach(i, p; byteSeq) { enum uint s = 'a'-10-'0'; uint h = uuid[p]; uint l = uuid[p+1]; pos = p; if(h < '0') goto Lerr; if(l < '0') goto Lerr; if (h > '9') { h |= 0x20; //poorman's tolower if (h < 'a') goto Lerr; if (h > 'f') goto Lerr; h -= s; } if (l > '9') { l |= 0x20; //poorman's tolower if (l < 'a') goto Lerr; if (l > 'f') goto Lerr; l -= s; } h -= '0'; l -= '0'; data2[i] = cast(ubyte)((h << 4) ^ l); } this.data = data2; return; Lerr: throw new UUIDParsingException(to!string(uuid), pos, UUIDParsingException.Reason.invalidChar, "Couldn't parse ubyte"); } /// @safe pure unittest { auto id = UUID("8AB3060E-2cba-4f23-b74c-b52db3bdfb46"); assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]); assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); //Can also be used in CTFE, for example as UUID literals: enum ctfeID = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); //here parsing is done at compile time, no runtime overhead! } @safe pure unittest { import std.exception; import std.meta; import std.conv : to; foreach(S; AliasSeq!(char[], const(char)[], immutable(char)[], wchar[], const(wchar)[], immutable(wchar)[], dchar[], const(dchar)[], immutable(dchar)[], immutable(char[]), immutable(wchar[]), immutable(dchar[]))) { //Test valid, working cases assert(UUID(to!S("00000000-0000-0000-0000-000000000000")).empty); auto id = UUID(to!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46")); assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]); assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); enum UUID ctfe = UUID(to!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46")); assert(ctfe == id); assert(UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a")).data == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]); //Test too short UUIDS auto except = collectException!UUIDParsingException( UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886"))); assert(except && except.reason == UUIDParsingException.Reason.tooLittle); //Test too long UUIDS except = collectException!UUIDParsingException( UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa"))); assert(except && except.reason == UUIDParsingException.Reason.tooMuch); //Test dashes except = collectException!UUIDParsingException( UUID(to!S("8ab3060e2cba-4f23-b74c-b52db3bdfb-46"))); assert(except && except.reason == UUIDParsingException.Reason.invalidChar); //Test dashes 2 except = collectException!UUIDParsingException( UUID(to!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46"))); assert(except && except.reason == UUIDParsingException.Reason.invalidChar); //Test invalid characters //make sure 36 characters in total or we'll get a 'tooMuch' reason except = collectException!UUIDParsingException( UUID(to!S("{8ab3060e-2cba-4f23-b74c-b52db3bdf6}"))); assert(except && except.reason == UUIDParsingException.Reason.invalidChar); //Boost test assert(UUID(to!S("01234567-89ab-cdef-0123-456789ABCDEF")) == UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef])); } } /** * Returns true if and only if the UUID is equal * to {00000000-0000-0000-0000-000000000000} */ @trusted pure nothrow @nogc @property bool empty() const { if(__ctfe) return data == (ubyte[16]).init; auto p = cast(const(size_t*))data.ptr; static if(size_t.sizeof == 4) return p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0; else static if(size_t.sizeof == 8) return p[0] == 0 && p[1] == 0; else static assert(false, "nonsense, it's not 32 or 64 bit"); } /// @safe pure unittest { UUID id; assert(id.empty); id = UUID("00000000-0000-0000-0000-000000000001"); assert(!id.empty); } @safe pure unittest { ubyte[16] getData(size_t i) { ubyte[16] data; data[i] = 1; return data; } for(size_t i = 0; i < 16; i++) { assert(!UUID(getData(i)).empty); } enum ctfeEmpty = UUID.init.empty; assert(ctfeEmpty); bool ctfeTest() { for(size_t i = 0; i < 16; i++) { auto ctfeEmpty2 = UUID(getData(i)).empty; assert(!ctfeEmpty2); } return true; } enum res = ctfeTest(); } /** * RFC 4122 defines different internal data layouts for UUIDs. * Returns the format used by this UUID. * * Note: Do not confuse this with $(XREF _variant, _Variant). * The type of this property is $(MYREF3 std.uuid.UUID.Variant, _Variant). * * See_Also: * $(MYREF3 UUID.Variant, Variant) */ @safe pure nothrow @nogc @property Variant variant() const { //variant is stored in octet 7 //which is index 8, since indexes count backwards auto octet7 = data[8]; //octet 7 is array index 8 if((octet7 & 0x80) == 0x00) //0b0xxxxxxx return Variant.ncs; else if((octet7 & 0xC0) == 0x80) //0b10xxxxxx return Variant.rfc4122; else if((octet7 & 0xE0) == 0xC0) //0b110xxxxx return Variant.microsoft; else { //assert((octet7 & 0xE0) == 0xE0, "Unknown UUID variant!") //0b111xxxx return Variant.future; } } /// @safe pure unittest { assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").variant == UUID.Variant.rfc4122); } pure unittest { Variant[ubyte] tests = cast(Variant[ubyte])[0x00 : Variant.ncs, 0x10 : Variant.ncs, 0x20 : Variant.ncs, 0x30 : Variant.ncs, 0x40 : Variant.ncs, 0x50 : Variant.ncs, 0x60 : Variant.ncs, 0x70 : Variant.ncs, 0x80 : Variant.rfc4122, 0x90 : Variant.rfc4122, 0xa0 : Variant.rfc4122, 0xb0 : Variant.rfc4122, 0xc0 : Variant.microsoft, 0xd0 : Variant.microsoft, 0xe0 : Variant.future, 0xf0 : Variant.future]; foreach(key, value; tests) { UUID u; u.data[8] = key; assert(u.variant == value); } } /** * RFC 4122 defines different UUID versions. The version shows * how a UUID was generated, e.g. a version 4 UUID was generated * from a random number, a version 3 UUID from an MD5 hash of a name. * Returns the version used by this UUID. * * See_Also: * $(MYREF3 UUID.Version, Version) */ @safe pure nothrow @nogc @property Version uuidVersion() const { //version is stored in octet 9 //which is index 6, since indexes count backwards auto octet9 = data[6]; if ((octet9 & 0xF0) == 0x10) return Version.timeBased; else if ((octet9 & 0xF0) == 0x20) return Version.dceSecurity; else if ((octet9 & 0xF0) == 0x30) return Version.nameBasedMD5; else if ((octet9 & 0xF0) == 0x40) return Version.randomNumberBased; else if ((octet9 & 0xF0) == 0x50) return Version.nameBasedSHA1; else return Version.unknown; } /// unittest { assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").uuidVersion == UUID.Version.randomNumberBased); } unittest { Version[ubyte] tests = cast(Version[ubyte]) [ 0x00 : UUID.Version.unknown, 0x10 : UUID.Version.timeBased, 0x20 : UUID.Version.dceSecurity, 0x30 : UUID.Version.nameBasedMD5, 0x40 : UUID.Version.randomNumberBased, 0x50 : UUID.Version.nameBasedSHA1, 0x60 : UUID.Version.unknown, 0x70 : UUID.Version.unknown, 0x80 : UUID.Version.unknown, 0x90 : UUID.Version.unknown, 0xa0 : UUID.Version.unknown, 0xb0 : UUID.Version.unknown, 0xc0 : UUID.Version.unknown, 0xd0 : UUID.Version.unknown, 0xe0 : UUID.Version.unknown, 0xf0 : UUID.Version.unknown]; foreach(key, value; tests) { UUID u; u.data[6] = key; assert(u.uuidVersion == value); } } /** * Swap the data of this UUID with the data of rhs. */ @safe pure nothrow @nogc void swap(ref UUID rhs) { auto bck = data; data = rhs.data; rhs.data = bck; } /// unittest { immutable ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; UUID u1; UUID u2 = UUID(data); u1.swap(u2); assert(u1 == UUID(data)); assert(u2 == UUID.init); } /** * All of the standard numeric operators are defined for * the UUID struct. */ @safe pure nothrow @nogc bool opEquals(in UUID s) const { return ulongs[0] == s.ulongs[0] && ulongs[1] == s.ulongs[1]; } /// pure unittest { //compare UUIDs assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init); //UUIDs in associative arrays: int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1, UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2, UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3]; assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3); //UUIDS can be sorted: import std.algorithm; UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"), UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"), UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")]; sort(ids); } /** * ditto */ @safe pure nothrow @nogc bool opEquals(ref in UUID s) const { return ulongs[0] == s.ulongs[0] && ulongs[1] == s.ulongs[1]; } /** * ditto */ @safe pure nothrow @nogc int opCmp(in UUID s) const { import std.algorithm : cmp; return cmp(this.data[], s.data[]); } /** * ditto */ @safe pure nothrow @nogc int opCmp(ref in UUID s) const { import std.algorithm : cmp; return cmp(this.data[], s.data[]); } /** * ditto */ @safe pure nothrow @nogc UUID opAssign(in UUID s) { ulongs[0] = s.ulongs[0]; ulongs[1] = s.ulongs[1]; return this; } /** * ditto */ @safe pure nothrow @nogc UUID opAssign(ref in UUID s) { ulongs[0] = s.ulongs[0]; ulongs[1] = s.ulongs[1]; return this; } /** * ditto */ //MurmurHash2 @safe pure nothrow @nogc size_t toHash() const { static if(size_t.sizeof == 4) { enum uint m = 0x5bd1e995; enum uint n = 16; enum uint r = 24; uint h = n; uint k = uints[0]; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; k = uints[1]; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; k = uints[2]; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; k = uints[3]; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; } else { enum ulong m = 0xc6a4a7935bd1e995UL; enum ulong n = m * 16; enum uint r = 47; ulong h = n; ulong k = ulongs[0]; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; k = ulongs[1]; k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; } return h; } unittest { assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init); int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1, UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2, UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3]; assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3); import std.algorithm; UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"), UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"), UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")]; sort(ids); auto id2 = ids.dup; ids = [UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"), UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"), UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")]; sort(ids); assert(ids == id2); //test comparsion UUID u1; UUID u2 = UUID(cast(ubyte[16])[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]); UUID u3 = UUID(cast(ubyte[16])[255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255]); assert(u1 == u1); assert(u1 != u2); assert(u1 < u2); assert(u2 < u3); assert(u1 <= u1); assert(u1 <= u2); assert(u2 <= u3); assert(u2 >= u2); assert(u3 >= u2); assert(u3 >= u3); assert(u2 >= u1); assert(u3 >= u1); // test hash assert(u1.toHash() != u2.toHash()); assert(u2.toHash() != u3.toHash()); assert(u3.toHash() != u1.toHash()); } /** * Write the UUID into `result` as an ASCII string in the canonical form. */ @safe pure nothrow @nogc void toString(Range)(Range result) const if (isRandomAccessRange!Range && hasAssignableElements!Range && hasLength!Range && (isSomeChar!(typeof(Range.init[0])) || isUnsigned!(typeof(Range.init[0]))) || isSomeString!Range && isMutable!(typeof(Range.init[0]))) in { assert(result.length >= 36, "Result's length for UUID.toString must be greater or equal 36."); } body { alias Char = typeof(Range.init[0]); foreach(pos; skipSeq) result[pos] = cast(Char)('-'); foreach(i, pos; byteSeq) { const uint entry = this.data[i]; const uint hi = entry >> 4; result[pos ] = toChar!Char(hi); const uint lo = (entry) & 0x0F; result[pos+1] = toChar!Char(lo); } } /** * Call a delegate with a string in the canonical form. */ void toString(scope void delegate(const(char)[]) sink) const { char[36] result = void; toString(result[]); sink(result[]); } /** * Return the UUID as a string in the canonical form. */ @trusted pure nothrow string toString() const { import std.exception: assumeUnique; auto result = new char[36]; toString(result); return result.assumeUnique; } /// @safe pure unittest { immutable str = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"; auto id = UUID(str); assert(id.toString() == str); } @safe pure nothrow @nogc unittest { import std.meta: AliasSeq; foreach(Char; AliasSeq!(char, wchar, dchar)) { alias String = immutable(Char)[]; //CTFE enum String s = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"; enum id = UUID(s); static if(is(Char == char)) { enum p = id.toString(); static assert(s == p); } //nogc Char[36] str; id.toString(str[]); assert(str == s); } } pure nothrow @nogc unittest { import std.encoding: Char = AsciiChar; enum utfstr = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"; alias String = immutable(Char)[]; enum String s = cast(String)utfstr; enum id = UUID(utfstr); //nogc Char[36] str; id.toString(str[]); assert(str == s); } unittest { auto u1 = UUID(cast(ubyte[16])[138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]); assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); u1 = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); char[] buf; void sink(const(char)[] data) { buf ~= data; } u1.toString(&sink); assert(buf == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); } } /** * This function generates a name based (Version 3) UUID from a namespace UUID and a name. * If no namespace UUID was passed, the empty UUID $(D UUID.init) is used. * * Note: * The default namespaces ($(LREF dnsNamespace), ...) defined by * this module should be used when appropriate. * * RFC 4122 recommends to use Version 5 UUIDs (SHA-1) instead of Version 3 * UUIDs (MD5) for new applications. * * CTFE: * CTFE is not supported. * * Note: * RFC 4122 isn't very clear on how UUIDs should be generated from names. * It is possible that different implementations return different UUIDs * for the same input, so be warned. The implementation for UTF-8 strings * and byte arrays used by $(D std.uuid) is compatible with Boost's implementation. * $(D std.uuid) guarantees that the same input to this function will generate * the same output at any time, on any system (this especially means endianness * doesn't matter). * * Note: * This function does not provide overloads for wstring and dstring, as * there's no clear answer on how that should be implemented. It could be * argued, that string, wstring and dstring input should have the same output, * but that wouldn't be compatible with Boost, which generates different output * for strings and wstrings. It's always possible to pass wstrings and dstrings * by using the ubyte[] function overload (but be aware of endianness issues!). */ @safe pure nothrow @nogc UUID md5UUID(const(char[]) name, const UUID namespace = UUID.init) { return md5UUID(cast(const(ubyte[]))name, namespace); } /** * ditto */ @safe pure nothrow @nogc UUID md5UUID(const(ubyte[]) data, const UUID namespace = UUID.init) { import std.digest.md : MD5; MD5 hash; hash.start(); /* * NOTE: RFC 4122 says namespace should be converted to big-endian. * We always keep the UUID data in big-endian representation, so * that's fine */ hash.put(namespace.data[]); hash.put(data[]); UUID u; u.data = hash.finish(); //set variant //must be 0b10xxxxxx u.data[8] &= 0b10111111; u.data[8] |= 0b10000000; //set version //must be 0b0011xxxx u.data[6] &= 0b00111111; u.data[6] |= 0b00110000; return u; } /// unittest { //Use default UUID.init namespace auto simpleID = md5UUID("test.uuid.any.string"); //use a name-based id as namespace auto namespace = md5UUID("my.app"); auto id = md5UUID("some-description", namespace); } @safe pure unittest { auto simpleID = md5UUID("test.uuid.any.string"); assert(simpleID.data == cast(ubyte[16])[126, 206, 86, 72, 29, 233, 62, 213, 178, 139, 198, 136, 188, 135, 153, 123]); auto namespace = md5UUID("my.app"); auto id = md5UUID("some-description", namespace); assert(id.data == cast(ubyte[16])[166, 138, 167, 79, 48, 219, 55, 166, 170, 103, 39, 73, 216, 150, 144, 164]); auto constTest = md5UUID(cast(const(char)[])"test"); constTest = md5UUID(cast(const(char[]))"test"); char[] mutable = "test".dup; id = md5UUID(mutable, namespace); const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222]; id = md5UUID(data); assert(id.data == cast(ubyte[16])[16, 50, 29, 247, 243, 185, 61, 178, 157, 100, 253, 236, 73, 76, 51, 47]); assert(id.variant == UUID.Variant.rfc4122); assert(id.uuidVersion == UUID.Version.nameBasedMD5); auto correct = UUID("3d813cbb-47fb-32ba-91df-831e1593ac29"); auto u = md5UUID("www.widgets.com", dnsNamespace); //enum ctfeId = md5UUID("www.widgets.com", dnsNamespace); //assert(ctfeId == u); assert(u == correct); assert(u.variant == UUID.Variant.rfc4122); assert(u.uuidVersion == UUID.Version.nameBasedMD5); } /** * This function generates a name based (Version 5) UUID from a namespace * UUID and a name. * If no namespace UUID was passed, the empty UUID $(D UUID.init) is used. * * Note: * The default namespaces ($(LREF dnsNamespace), ...) defined by * this module should be used when appropriate. * * CTFE: * CTFE is not supported. * * Note: * RFC 4122 isn't very clear on how UUIDs should be generated from names. * It is possible that different implementations return different UUIDs * for the same input, so be warned. The implementation for UTF-8 strings * and byte arrays used by $(D std.uuid) is compatible with Boost's implementation. * $(D std.uuid) guarantees that the same input to this function will generate * the same output at any time, on any system (this especially means endianness * doesn't matter). * * Note: * This function does not provide overloads for wstring and dstring, as * there's no clear answer on how that should be implemented. It could be * argued, that string, wstring and dstring input should have the same output, * but that wouldn't be compatible with Boost, which generates different output * for strings and wstrings. It's always possible to pass wstrings and dstrings * by using the ubyte[] function overload (but be aware of endianness issues!). */ @safe pure nothrow @nogc UUID sha1UUID(in char[] name, const UUID namespace = UUID.init) { return sha1UUID(cast(const(ubyte[]))name, namespace); } /** * ditto */ @safe pure nothrow @nogc UUID sha1UUID(in ubyte[] data, const UUID namespace = UUID.init) { import std.digest.sha : SHA1; SHA1 sha; sha.start(); /* * NOTE: RFC 4122 says namespace should be converted to big-endian. * We always keep the UUID data in big-endian representation, so * that's fine */ sha.put(namespace.data[]); sha.put(data[]); auto hash = sha.finish(); auto u = UUID(); u.data[] = hash[0 .. 16]; //set variant //must be 0b10xxxxxx u.data[8] &= 0b10111111; u.data[8] |= 0b10000000; //set version //must be 0b0101xxxx u.data[6] &= 0b01011111; u.data[6] |= 0b01010000; return u; } /// unittest { //Use default UUID.init namespace auto simpleID = sha1UUID("test.uuid.any.string"); //use a name-based id as namespace auto namespace = sha1UUID("my.app"); auto id = sha1UUID("some-description", namespace); } @safe pure unittest { auto simpleID = sha1UUID("test.uuid.any.string"); assert(simpleID.data == cast(ubyte[16])[16, 209, 239, 61, 99, 12, 94, 70, 159, 79, 255, 250, 131, 79, 14, 147]); auto namespace = sha1UUID("my.app"); auto id = sha1UUID("some-description", namespace); assert(id.data == cast(ubyte[16])[225, 94, 195, 219, 126, 75, 83, 71, 157, 52, 247, 43, 238, 248, 148, 46]); auto constTest = sha1UUID(cast(const(char)[])"test"); constTest = sha1UUID(cast(const(char[]))"test"); char[] mutable = "test".dup; id = sha1UUID(mutable, namespace); const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222]; id = sha1UUID(data); assert(id.data == cast(ubyte[16])[60, 65, 92, 240, 96, 46, 95, 238, 149, 100, 12, 64, 199, 194, 243, 12]); auto correct = UUID("21f7f8de-8051-5b89-8680-0195ef798b6a"); auto u = sha1UUID("www.widgets.com", dnsNamespace); assert(u == correct); assert(u.variant == UUID.Variant.rfc4122); assert(u.uuidVersion == UUID.Version.nameBasedSHA1); } /** * This function generates a random number based UUID from a random * number generator. * * CTFE: * This function is not supported at compile time. * */ @safe UUID randomUUID() { import std.random : rndGen; return randomUUID(rndGen); } /** * ditto */ /** * Params: * randomGen = uniform RNG * See_Also: $(XREF random, isUniformRNG) */ UUID randomUUID(RNG)(ref RNG randomGen) if (isInputRange!RNG && isIntegral!(ElementType!RNG)) { import std.random : isUniformRNG; static assert (isUniformRNG!RNG, "randomGen must be a uniform RNG"); alias E = ElementEncodingType!RNG; enum size_t elemSize = E.sizeof; static assert (elemSize <= 16); static assert (16 % elemSize == 0); UUID u; foreach (ref E e ; u.asArrayOf!E()) { e = randomGen.front; randomGen.popFront(); } //set variant //must be 0b10xxxxxx u.data[8] &= 0b10111111; u.data[8] |= 0b10000000; //set version //must be 0b0100xxxx u.data[6] &= 0b01001111; u.data[6] |= 0b01000000; return u; } /// @safe unittest { import std.random : Xorshift192, unpredictableSeed; //simple call auto uuid = randomUUID(); //provide a custom RNG. Must be seeded manually. Xorshift192 gen; gen.seed(unpredictableSeed); auto uuid3 = randomUUID(gen); } /* * Original boost.uuid used Mt19937, we don't want * to use anything worse than that. If Random is changed * to something else, this assert and the randomUUID function * have to be updated. */ @safe unittest { import std.random : rndGen, Mt19937; static assert(is(typeof(rndGen) == Mt19937)); } @safe unittest { import std.random : Xorshift192, unpredictableSeed; //simple call auto uuid = randomUUID(); //provide a custom RNG. Must be seeded manually. Xorshift192 gen; gen.seed(unpredictableSeed); auto uuid3 = randomUUID(gen); auto u1 = randomUUID(); auto u2 = randomUUID(); assert(u1 != u2); assert(u1.variant == UUID.Variant.rfc4122); assert(u1.uuidVersion == UUID.Version.randomNumberBased); } /** * This is a less strict parser compared to the parser used in the * UUID constructor. It enforces the following rules: * * $(UL * $(LI hex numbers are always two hexdigits([0-9a-fA-F])) * $(LI there must be exactly 16 such pairs in the input, not less, not more) * $(LI there can be exactly one dash between two hex-pairs, but not more) * $(LI there can be multiple characters enclosing the 16 hex pairs, * as long as these characters do not contain [0-9a-fA-F]) * ) * * Note: * Like most parsers, it consumes its argument. This means: * ------------------------- * string s = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46"; * parseUUID(s); * assert(s == ""); * ------------------------- * * Throws: * $(LREF UUIDParsingException) if the input is invalid * * CTFE: * This function is supported in CTFE code. Note that error messages * caused by a malformed UUID parsed at compile time can be cryptic, * but errors are detected and reported at compile time. */ UUID parseUUID(T)(T uuidString) if(isSomeString!T) { return parseUUID(uuidString); } ///ditto UUID parseUUID(Range)(ref Range uuidRange) if(isInputRange!Range && is(Unqual!(ElementType!Range) == dchar)) { import std.conv : ConvException, parse; import std.ascii : isHexDigit; static if(isForwardRange!Range) auto errorCopy = uuidRange.save; void parserError()(size_t pos, UUIDParsingException.Reason reason, string message, Throwable next = null, string file = __FILE__, size_t line = __LINE__) { static if(isForwardRange!Range) { import std.conv : to; static if(isInfinite!Range) { throw new UUIDParsingException(to!string(take(errorCopy, pos)), pos, reason, message, next, file, line); } else { throw new UUIDParsingException(to!string(errorCopy), pos, reason, message, next, file, line); } } else { throw new UUIDParsingException("", pos, reason, message, next, file, line); } } static if(hasLength!Range) { import std.conv : to; if(uuidRange.length < 32) { throw new UUIDParsingException(to!string(uuidRange), 0, UUIDParsingException.Reason.tooLittle, "Insufficient Input"); } } UUID result; size_t consumed; size_t element = 0; //skip garbage size_t skip()() { size_t skipped; while(!uuidRange.empty && !isHexDigit(uuidRange.front)) { skipped++; uuidRange.popFront(); } return skipped; } consumed += skip(); if(uuidRange.empty) parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input"); bool dashAllowed = false; parseLoop: while(!uuidRange.empty) { dchar character = uuidRange.front; if(character == '-') { if(!dashAllowed) parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected '-'"); else dashAllowed = false; consumed++; } else if(!isHexDigit(character)) { parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected character (wanted a hexDigit)"); } else { try { consumed += 2; static if(isSomeString!Range) { if(uuidRange.length < 2) { parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input"); } auto part = uuidRange[0 .. 2]; result.data[element++] = parse!ubyte(part, 16); uuidRange.popFront(); } else { dchar[2] copyBuf; copyBuf[0] = character; uuidRange.popFront(); if(uuidRange.empty) { parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input"); } copyBuf[1] = uuidRange.front; auto part = copyBuf[]; result.data[element++] = parse!ubyte(part, 16); } if(element == 16) { uuidRange.popFront(); break parseLoop; } dashAllowed = true; } catch(ConvException e) { parserError(consumed, UUIDParsingException.Reason.invalidChar, "Couldn't parse ubyte", e); } } uuidRange.popFront(); } assert(element <= 16); if(element < 16) parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input"); consumed += skip(); if(!uuidRange.empty) parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected character"); return result; } /// unittest { auto id = parseUUID("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46"); //no dashes id = parseUUID("8ab3060e2cba4f23b74cb52db3bdfb46"); //dashes at different positions id = parseUUID("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46"); //leading / trailing characters id = parseUUID("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}"); //unicode id = parseUUID("ü8ab3060e2cba4f23b74cb52db3bdfb46ü"); //multiple trailing/leading characters id = parseUUID("///8ab3060e2cba4f23b74cb52db3bdfb46||"); //Can also be used in CTFE, for example as UUID literals: enum ctfeID = parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); //here parsing is done at compile time, no runtime overhead! } @safe pure unittest { import std.exception; import std.meta; import std.conv : to; struct TestRange(bool forward) { dstring input; @property dchar front() { return input.front; } void popFront() { input.popFront(); } @property bool empty() { return input.empty; } static if(forward) { @property TestRange!true save() { return this; } } } alias TestInputRange = TestRange!false; alias TestForwardRange = TestRange!true; assert(isInputRange!TestInputRange); assert(is(ElementType!TestInputRange == dchar)); assert(isInputRange!TestForwardRange); assert(isForwardRange!TestForwardRange); assert(is(ElementType!TestForwardRange == dchar)); //Helper function for unittests - Need to pass ranges by ref UUID parseHelper(T)(string input) { static if(is(T == TestInputRange) || is(T == TestForwardRange)) { T range = T(to!dstring(input)); return parseUUID(range); } else return parseUUID(to!T(input)); } foreach(S; AliasSeq!(char[], const(char)[], immutable(char)[], wchar[], const(wchar)[], immutable(wchar)[], dchar[], const(dchar)[], immutable(dchar)[], immutable(char[]), immutable(wchar[]), immutable(dchar[]), TestForwardRange, TestInputRange)) { //Verify examples. auto id = parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46"); //no dashes id = parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46"); //dashes at different positions id = parseHelper!S("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46"); //leading / trailing characters id = parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}"); //unicode id = parseHelper!S("ü8ab3060e2cba4f23b74cb52db3bdfb46ü"); //multiple trailing/leading characters id = parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||"); enum ctfeId = parseHelper!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); assert(parseHelper!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46") == ctfeId); //Test valid, working cases assert(parseHelper!S("00000000-0000-0000-0000-000000000000").empty); assert(parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46").data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]); assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]); //wstring / dstring assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]); assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]); //Test too short UUIDS auto except = collectException!UUIDParsingException( parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886")); assert(except && except.reason == UUIDParsingException.Reason.tooLittle); //Test too long UUIDS except = collectException!UUIDParsingException( parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa")); assert(except && except.reason == UUIDParsingException.Reason.invalidChar); //Test too long UUIDS 2 except = collectException!UUIDParsingException( parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a-aa")); assert(except && except.reason == UUIDParsingException.Reason.invalidChar); //Test dashes assert(parseHelper!S("8ab3060e2cba-4f23-b74c-b52db3bdfb46") == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46")); assert(parseHelper!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46") == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46")); assert(parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46") == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46")); except = collectException!UUIDParsingException( parseHelper!S("8-ab3060e2cba-4f23-b74c-b52db3bdfb46")); assert(except && except.reason == UUIDParsingException.Reason.invalidChar); //Test leading/trailing characters assert(parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}") == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46")); assert(parseHelper!S("{8ab3060e2cba4f23b74cb52db3bdfb46}") == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46")); //Boost test auto u_increasing = UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); assert(parseHelper!S("0123456789abcdef0123456789ABCDEF") == UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef])); //unicode assert(parseHelper!S("ü8ab3060e2cba4f23b74cb52db3bdfb46ü") == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46")); //multiple trailing/leading characters assert(parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||") == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46")); } } /** * Default namespace from RFC 4122 * * Name string is a fully-qualified domain name */ enum dnsNamespace = UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8"); /** * Default namespace from RFC 4122 * * Name string is a URL */ enum urlNamespace = UUID("6ba7b811-9dad-11d1-80b4-00c04fd430c8"); /** * Default namespace from RFC 4122 * * Name string is an ISO OID */ enum oidNamespace = UUID("6ba7b812-9dad-11d1-80b4-00c04fd430c8"); /** * Default namespace from RFC 4122 * * Name string is an X.500 DN (in DER or a text output format) */ enum x500Namespace = UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8"); /** * Regex string to extract UUIDs from text. */ enum uuidRegex = "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}"~ "-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"; /// unittest { import std.algorithm; import std.regex; string test = "Lorem ipsum dolor sit amet, consetetur "~ "6ba7b814-9dad-11d1-80b4-00c04fd430c8 sadipscing \n"~ "elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore \r\n"~ "magna aliquyam erat, sed diam voluptua. "~ "8ab3060e-2cba-4f23-b74c-b52db3bdfb46 At vero eos et accusam et "~ "justo duo dolores et ea rebum."; auto r = regex(uuidRegex, "g"); UUID[] found; foreach(c; match(test, r)) { found ~= UUID(c.hit); } assert(found == [ UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8"), UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"), ]); } /** * This exception is thrown if an error occurs when parsing a UUID * from a string. */ public class UUIDParsingException : Exception { /** * The reason why parsing the UUID string failed (if known) */ enum Reason { unknown, /// tooLittle, ///The passed in input was correct, but more input was expected. tooMuch, ///The input data is too long (There's no guarantee the first part of the data is valid) invalidChar, ///Encountered an invalid character } ///ditto Reason reason; ///The original input string which should have been parsed. string input; ///The position in the input string where the error occurred. size_t position; private this(string input, size_t pos, Reason why = Reason.unknown, string msg = "", Throwable next = null, string file = __FILE__, size_t line = __LINE__) pure @trusted { import std.array : replace; import std.format : format; this.input = input; this.position = pos; this.reason = why; string message = format("An error occured in the UUID parser: %s\n" ~ " * Input:\t'%s'\n * Position:\t%s", msg, replace(replace(input, "\r", "\\r"), "\n", "\\n"), pos); super(message, file, line, next); } } /// unittest { auto ex = new UUIDParsingException("foo", 10, UUIDParsingException.Reason.tooMuch); assert(ex.input == "foo"); assert(ex.position == 10); assert(ex.reason == UUIDParsingException.Reason.tooMuch); } ldc-1.1.0-beta3-src/runtime/phobos/std/traits.d0000664000175000017500000064215612776215007017377 0ustar kaikai// Written in the D programming language. /** * Templates which extract information about types and symbols at compile time. * * $(SCRIPT inhibitQuickIndex = 1;) * * $(DIVC quickindex, * $(BOOKTABLE , * $(TR $(TH Category) $(TH Templates)) * $(TR $(TD Symbol Name _traits) $(TD * $(LREF fullyQualifiedName) * $(LREF moduleName) * $(LREF packageName) * )) * $(TR $(TD Function _traits) $(TD * $(LREF arity) * $(LREF functionAttributes) * $(LREF functionLinkage) * $(LREF FunctionTypeOf) * $(LREF isSafe) * $(LREF isUnsafe) * $(LREF ParameterDefaults) * $(LREF ParameterIdentifierTuple) * $(LREF ParameterStorageClassTuple) * $(LREF Parameters) * $(LREF ReturnType) * $(LREF SetFunctionAttributes) * $(LREF variadicFunctionStyle) * )) * $(TR $(TD Aggregate Type _traits) $(TD * $(LREF BaseClassesTuple) * $(LREF BaseTypeTuple) * $(LREF classInstanceAlignment) * $(LREF EnumMembers) * $(LREF FieldNameTuple) * $(LREF Fields) * $(LREF hasAliasing) * $(LREF hasElaborateAssign) * $(LREF hasElaborateCopyConstructor) * $(LREF hasElaborateDestructor) * $(LREF hasIndirections) * $(LREF hasMember) * $(LREF hasNested) * $(LREF hasUnsharedAliasing) * $(LREF InterfacesTuple) * $(LREF isNested) * $(LREF MemberFunctionsTuple) * $(LREF RepresentationTypeTuple) * $(LREF TemplateArgsOf) * $(LREF TemplateOf) * $(LREF TransitiveBaseTypeTuple) * )) * $(TR $(TD Type Conversion) $(TD * $(LREF CommonType) * $(LREF ImplicitConversionTargets) * $(LREF CopyTypeQualifiers) * $(LREF CopyConstness) * $(LREF isAssignable) * $(LREF isCovariantWith) * $(LREF isImplicitlyConvertible) * )) * * $(TR $(TD Categories of types) $(TD * $(LREF isAggregateType) * $(LREF isArray) * $(LREF isAssociativeArray) * $(LREF isAutodecodableString) * $(LREF isBasicType) * $(LREF isBoolean) * $(LREF isBuiltinType) * $(LREF isDynamicArray) * $(LREF isFloatingPoint) * $(LREF isIntegral) * $(LREF isNarrowString) * $(LREF isNumeric) * $(LREF isPointer) * $(LREF isScalarType) * $(LREF isSigned) * $(LREF isSomeChar) * $(LREF isSomeString) * $(LREF isStaticArray) * $(LREF isUnsigned) * )) * $(TR $(TD Type behaviours) $(TD * $(LREF isAbstractClass) * $(LREF isAbstractFunction) * $(LREF isCallable) * $(LREF isDelegate) * $(LREF isExpressions) * $(LREF isFinalClass) * $(LREF isFinalFunction) * $(LREF isFunctionPointer) * $(LREF isInstanceOf) * $(LREF isIterable) * $(LREF isMutable) * $(LREF isSomeFunction) * $(LREF isTypeTuple) * )) * $(TR $(TD General Types) $(TD * $(LREF ForeachType) * $(LREF KeyType) * $(LREF Largest) * $(LREF mostNegative) * $(LREF OriginalType) * $(LREF PointerTarget) * $(LREF Signed) * $(LREF Unqual) * $(LREF Unsigned) * $(LREF ValueType) * )) * $(TR $(TD Misc) $(TD * $(LREF mangledName) * $(LREF Select) * $(LREF select) * )) * $(TR $(TD User-Defined Attributes) $(TD * $(LREF hasUDA) * $(LREF getUDAs) * $(LREF getSymbolsByUDA) * )) * ) * ) * * Macros: * WIKI = Phobos/StdTraits * * Copyright: Copyright Digital Mars 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright), * Tomasz Stachowiak ($(D isExpressions)), * $(WEB erdani.org, Andrei Alexandrescu), * Shin Fujishiro, * $(WEB octarineparrot.com, Robert Clipsham), * $(WEB klickverbot.at, David Nadlinger), * Kenji Hara, * Shoichi Kato * Source: $(PHOBOSSRC std/_traits.d) */ /* Copyright Digital Mars 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.traits; import std.typetuple; /////////////////////////////////////////////////////////////////////////////// // Functions /////////////////////////////////////////////////////////////////////////////// // Petit demangler // (this or similar thing will eventually go to std.demangle if necessary // ctfe stuffs are available) private { struct Demangle(T) { T value; // extracted information string rest; } /* Demangles mstr as the storage class part of Argument. */ Demangle!uint demangleParameterStorageClass(string mstr) { uint pstc = 0; // parameter storage class // Argument --> Argument2 | M Argument2 if (mstr.length > 0 && mstr[0] == 'M') { pstc |= ParameterStorageClass.scope_; mstr = mstr[1 .. $]; } // Argument2 --> Type | J Type | K Type | L Type ParameterStorageClass stc2; switch (mstr.length ? mstr[0] : char.init) { case 'J': stc2 = ParameterStorageClass.out_; break; case 'K': stc2 = ParameterStorageClass.ref_; break; case 'L': stc2 = ParameterStorageClass.lazy_; break; case 'N': if (mstr.length >= 2 && mstr[1] == 'k') stc2 = ParameterStorageClass.return_; break; default : break; } if (stc2 != ParameterStorageClass.init) { pstc |= stc2; mstr = mstr[1 .. $]; if (stc2 & ParameterStorageClass.return_) mstr = mstr[1 .. $]; } return Demangle!uint(pstc, mstr); } /* Demangles mstr as FuncAttrs. */ Demangle!uint demangleFunctionAttributes(string mstr) { enum LOOKUP_ATTRIBUTE = [ 'a': FunctionAttribute.pure_, 'b': FunctionAttribute.nothrow_, 'c': FunctionAttribute.ref_, 'd': FunctionAttribute.property, 'e': FunctionAttribute.trusted, 'f': FunctionAttribute.safe, 'i': FunctionAttribute.nogc, 'j': FunctionAttribute.return_ ]; uint atts = 0; // FuncAttrs --> FuncAttr | FuncAttr FuncAttrs // FuncAttr --> empty | Na | Nb | Nc | Nd | Ne | Nf | Ni | Nj // except 'Ng' == inout, because it is a qualifier of function type while (mstr.length >= 2 && mstr[0] == 'N' && mstr[1] != 'g' && mstr[1] != 'k') { if (FunctionAttribute att = LOOKUP_ATTRIBUTE[ mstr[1] ]) { atts |= att; mstr = mstr[2 .. $]; } else assert(0); } return Demangle!uint(atts, mstr); } static if (is(ucent)) { alias CentTypeList = TypeTuple!(cent, ucent); alias SignedCentTypeList = TypeTuple!(cent); alias UnsignedCentTypeList = TypeTuple!(ucent); } else { alias CentTypeList = TypeTuple!(); alias SignedCentTypeList = TypeTuple!(); alias UnsignedCentTypeList = TypeTuple!(); } alias IntegralTypeList = TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, CentTypeList); alias SignedIntTypeList = TypeTuple!(byte, short, int, long, SignedCentTypeList); alias UnsignedIntTypeList = TypeTuple!(ubyte, ushort, uint, ulong, UnsignedCentTypeList); alias FloatingPointTypeList = TypeTuple!(float, double, real); alias ImaginaryTypeList = TypeTuple!(ifloat, idouble, ireal); alias ComplexTypeList = TypeTuple!(cfloat, cdouble, creal); alias NumericTypeList = TypeTuple!(IntegralTypeList, FloatingPointTypeList); alias CharTypeList = TypeTuple!(char, wchar, dchar); } package { /// Add specific qualifier to the given type T. template MutableOf(T) { alias MutableOf = T ; } } /// Add specific qualifier to the given type T. template InoutOf(T) { alias InoutOf = inout(T) ; } /// ditto. template ConstOf(T) { alias ConstOf = const(T) ; } /// ditto. template SharedOf(T) { alias SharedOf = shared(T) ; } /// ditto. template SharedInoutOf(T) { alias SharedInoutOf = shared(inout(T)); } /// ditto. template SharedConstOf(T) { alias SharedConstOf = shared(const(T)); } /// ditto. template ImmutableOf(T) { alias ImmutableOf = immutable(T) ; } unittest { static assert(is( MutableOf!int == int)); static assert(is( InoutOf!int == inout int)); static assert(is( ConstOf!int == const int)); static assert(is( SharedOf!int == shared int)); static assert(is(SharedInoutOf!int == shared inout int)); static assert(is(SharedConstOf!int == shared const int)); static assert(is( ImmutableOf!int == immutable int)); } // Get qualifier template from the given type T template QualifierOf(T) { static if (is(T == shared(const U), U)) alias QualifierOf = SharedConstOf; else static if (is(T == const U , U)) alias QualifierOf = ConstOf; else static if (is(T == shared(inout U), U)) alias QualifierOf = SharedInoutOf; else static if (is(T == inout U , U)) alias QualifierOf = InoutOf; else static if (is(T == immutable U , U)) alias QualifierOf = ImmutableOf; else static if (is(T == shared U , U)) alias QualifierOf = SharedOf; else alias QualifierOf = MutableOf; } unittest { alias Qual1 = QualifierOf!( int); static assert(is(Qual1!long == long)); alias Qual2 = QualifierOf!( inout int); static assert(is(Qual2!long == inout long)); alias Qual3 = QualifierOf!( const int); static assert(is(Qual3!long == const long)); alias Qual4 = QualifierOf!(shared int); static assert(is(Qual4!long == shared long)); alias Qual5 = QualifierOf!(shared inout int); static assert(is(Qual5!long == shared inout long)); alias Qual6 = QualifierOf!(shared const int); static assert(is(Qual6!long == shared const long)); alias Qual7 = QualifierOf!( immutable int); static assert(is(Qual7!long == immutable long)); } version(unittest) { alias TypeQualifierList = TypeTuple!(MutableOf, ConstOf, SharedOf, SharedConstOf, ImmutableOf); struct SubTypeOf(T) { T val; alias val this; } } private alias parentOf(alias sym) = Identity!(__traits(parent, sym)); private alias parentOf(alias sym : T!Args, alias T, Args...) = Identity!(__traits(parent, T)); /** * Get the full package name for the given symbol. */ template packageName(alias T) { import std.algorithm : startsWith; static if (__traits(compiles, parentOf!T)) enum parent = packageName!(parentOf!T); else enum string parent = null; static if (T.stringof.startsWith("package ")) enum packageName = (parent.length ? parent ~ '.' : "") ~ T.stringof[8 .. $]; else static if (parent) enum packageName = parent; else static assert(false, T.stringof ~ " has no parent"); } /// unittest { import std.traits; static assert(packageName!packageName == "std"); } unittest { import std.array; // Commented out because of dmd @@@BUG8922@@@ // static assert(packageName!std == "std"); // this package (currently: "std.std") static assert(packageName!(std.traits) == "std"); // this module static assert(packageName!packageName == "std"); // symbol in this module static assert(packageName!(std.array) == "std"); // other module from same package import core.sync.barrier; // local import static assert(packageName!core == "core"); static assert(packageName!(core.sync) == "core.sync"); static assert(packageName!Barrier == "core.sync"); struct X12287(T) { T i; } static assert(packageName!(X12287!int.i) == "std"); } version (none) version(unittest) //Please uncomment me when changing packageName to test global imports { import core.sync.barrier; // global import static assert(packageName!core == "core"); static assert(packageName!(core.sync) == "core.sync"); static assert(packageName!Barrier == "core.sync"); } /** * Get the module name (including package) for the given symbol. */ template moduleName(alias T) { import std.algorithm : startsWith; static assert(!T.stringof.startsWith("package "), "cannot get the module name for a package"); static if (T.stringof.startsWith("module ")) { static if (__traits(compiles, packageName!T)) enum packagePrefix = packageName!T ~ '.'; else enum packagePrefix = ""; enum moduleName = packagePrefix ~ T.stringof[7..$]; } else alias moduleName = moduleName!(parentOf!T); // If you use enum, it will cause compiler ICE } /// unittest { import std.traits; static assert(moduleName!moduleName == "std.traits"); } unittest { import std.array; static assert(!__traits(compiles, moduleName!std)); static assert(moduleName!(std.traits) == "std.traits"); // this module static assert(moduleName!moduleName == "std.traits"); // symbol in this module static assert(moduleName!(std.array) == "std.array"); // other module static assert(moduleName!(std.array.array) == "std.array"); // symbol in other module import core.sync.barrier; // local import static assert(!__traits(compiles, moduleName!(core.sync))); static assert(moduleName!(core.sync.barrier) == "core.sync.barrier"); static assert(moduleName!Barrier == "core.sync.barrier"); struct X12287(T) { T i; } static assert(moduleName!(X12287!int.i) == "std.traits"); } version (none) version(unittest) //Please uncomment me when changing moduleName to test global imports { import core.sync.barrier; // global import static assert(!__traits(compiles, moduleName!(core.sync))); static assert(moduleName!(core.sync.barrier) == "core.sync.barrier"); static assert(moduleName!Barrier == "core.sync.barrier"); } /*** * Get the fully qualified name of a type or a symbol. Can act as an intelligent type/symbol to string converter. Example: ----------------- module myModule; struct MyStruct {} static assert(fullyQualifiedName!(const MyStruct[]) == "const(myModule.MyStruct[])"); ----------------- */ template fullyQualifiedName(T...) if (T.length == 1) { static if (is(T)) enum fullyQualifiedName = fqnType!(T[0], false, false, false, false); else enum fullyQualifiedName = fqnSym!(T[0]); } /// unittest { static assert(fullyQualifiedName!fullyQualifiedName == "std.traits.fullyQualifiedName"); } version(unittest) { // Used for both fqnType and fqnSym unittests private struct QualifiedNameTests { struct Inner { } ref const(Inner[string]) func( ref Inner var1, lazy scope string var2 ); ref const(Inner[string]) retfunc( return ref Inner var1 ); Inner inoutFunc(inout Inner) inout; shared(const(Inner[string])[]) data; const Inner delegate(double, string) @safe nothrow deleg; inout(int) delegate(inout int) inout inoutDeleg; Inner function(out double, string) funcPtr; extern(C) Inner function(double, string) cFuncPtr; extern(C) void cVarArg(int, ...); void dVarArg(...); void dVarArg2(int, ...); void typesafeVarArg(int[] ...); Inner[] array; Inner[16] sarray; Inner[Inner] aarray; const(Inner[const(Inner)]) qualAarray; shared(immutable(Inner) delegate(ref double, scope string) const shared @trusted nothrow) attrDeleg; struct Data(T) { int x; } void tfunc(T...)(T args) {} template Inst(alias A) { int x; } class Test12309(T, int x, string s) {} } private enum QualifiedEnum { a = 42 } } private template fqnSym(alias T : X!A, alias X, A...) { template fqnTuple(T...) { static if (T.length == 0) enum fqnTuple = ""; else static if (T.length == 1) { static if (isExpressionTuple!T) enum fqnTuple = T[0].stringof; else enum fqnTuple = fullyQualifiedName!(T[0]); } else enum fqnTuple = fqnTuple!(T[0]) ~ ", " ~ fqnTuple!(T[1 .. $]); } enum fqnSym = fqnSym!(__traits(parent, X)) ~ '.' ~ __traits(identifier, X) ~ "!(" ~ fqnTuple!A ~ ")"; } private template fqnSym(alias T) { static if (__traits(compiles, __traits(parent, T))) enum parentPrefix = fqnSym!(__traits(parent, T)) ~ '.'; else enum parentPrefix = null; static string adjustIdent(string s) { import std.algorithm : skipOver, findSplit; if (s.skipOver("package ") || s.skipOver("module ")) return s; return s.findSplit("(")[0]; } enum fqnSym = parentPrefix ~ adjustIdent(__traits(identifier, T)); } unittest { alias fqn = fullyQualifiedName; // Make sure those 2 are the same static assert(fqnSym!fqn == fqn!fqn); static assert(fqn!fqn == "std.traits.fullyQualifiedName"); alias qnTests = QualifiedNameTests; enum prefix = "std.traits.QualifiedNameTests."; static assert(fqn!(qnTests.Inner) == prefix ~ "Inner"); static assert(fqn!(qnTests.func) == prefix ~ "func"); static assert(fqn!(qnTests.Data!int) == prefix ~ "Data!(int)"); static assert(fqn!(qnTests.Data!int.x) == prefix ~ "Data!(int).x"); static assert(fqn!(qnTests.tfunc!(int[])) == prefix ~ "tfunc!(int[])"); static assert(fqn!(qnTests.Inst!(Object)) == prefix ~ "Inst!(object.Object)"); static assert(fqn!(qnTests.Inst!(Object).x) == prefix ~ "Inst!(object.Object).x"); static assert(fqn!(qnTests.Test12309!(int, 10, "str")) == prefix ~ "Test12309!(int, 10, \"str\")"); import core.sync.barrier; static assert(fqn!Barrier == "core.sync.barrier.Barrier"); } private template fqnType(T, bool alreadyConst, bool alreadyImmutable, bool alreadyShared, bool alreadyInout) { import std.format : format; // Convenience tags enum { _const = 0, _immutable = 1, _shared = 2, _inout = 3 } alias qualifiers = TypeTuple!(is(T == const), is(T == immutable), is(T == shared), is(T == inout)); alias noQualifiers = TypeTuple!(false, false, false, false); string storageClassesString(uint psc)() @property { alias PSC = ParameterStorageClass; return format("%s%s%s%s%s", psc & PSC.scope_ ? "scope " : "", psc & PSC.return_ ? "return " : "", psc & PSC.out_ ? "out " : "", psc & PSC.ref_ ? "ref " : "", psc & PSC.lazy_ ? "lazy " : "" ); } string parametersTypeString(T)() @property { alias parameters = Parameters!(T); alias parameterStC = ParameterStorageClassTuple!(T); enum variadic = variadicFunctionStyle!T; static if (variadic == Variadic.no) enum variadicStr = ""; else static if (variadic == Variadic.c) enum variadicStr = ", ..."; else static if (variadic == Variadic.d) enum variadicStr = parameters.length ? ", ..." : "..."; else static if (variadic == Variadic.typesafe) enum variadicStr = " ..."; else static assert(0, "New variadic style has been added, please update fullyQualifiedName implementation"); static if (parameters.length) { import std.algorithm : map; import std.range : join, zip; string result = join( map!(a => format("%s%s", a[0], a[1]))( zip([staticMap!(storageClassesString, parameterStC)], [staticMap!(fullyQualifiedName, parameters)]) ), ", " ); return result ~= variadicStr; } else return variadicStr; } string linkageString(T)() @property { enum linkage = functionLinkage!T; if (linkage != "D") return format("extern(%s) ", linkage); else return ""; } string functionAttributeString(T)() @property { alias FA = FunctionAttribute; enum attrs = functionAttributes!T; static if (attrs == FA.none) return ""; else return format("%s%s%s%s%s%s%s%s", attrs & FA.pure_ ? " pure" : "", attrs & FA.nothrow_ ? " nothrow" : "", attrs & FA.ref_ ? " ref" : "", attrs & FA.property ? " @property" : "", attrs & FA.trusted ? " @trusted" : "", attrs & FA.safe ? " @safe" : "", attrs & FA.nogc ? " @nogc" : "", attrs & FA.return_ ? " return" : "" ); } string addQualifiers(string typeString, bool addConst, bool addImmutable, bool addShared, bool addInout) { auto result = typeString; if (addShared) { result = format("shared(%s)", result); } if (addConst || addImmutable || addInout) { result = format("%s(%s)", addConst ? "const" : addImmutable ? "immutable" : "inout", result ); } return result; } // Convenience template to avoid copy-paste template chain(string current) { enum chain = addQualifiers(current, qualifiers[_const] && !alreadyConst, qualifiers[_immutable] && !alreadyImmutable, qualifiers[_shared] && !alreadyShared, qualifiers[_inout] && !alreadyInout); } static if (is(T == string)) { enum fqnType = "string"; } else static if (is(T == wstring)) { enum fqnType = "wstring"; } else static if (is(T == dstring)) { enum fqnType = "dstring"; } else static if (isBasicType!T && !is(T == enum)) { enum fqnType = chain!((Unqual!T).stringof); } else static if (isAggregateType!T || is(T == enum)) { enum fqnType = chain!(fqnSym!T); } else static if (isStaticArray!T) { import std.conv; enum fqnType = chain!( format("%s[%s]", fqnType!(typeof(T.init[0]), qualifiers), T.length) ); } else static if (isArray!T) { enum fqnType = chain!( format("%s[]", fqnType!(typeof(T.init[0]), qualifiers)) ); } else static if (isAssociativeArray!T) { enum fqnType = chain!( format("%s[%s]", fqnType!(ValueType!T, qualifiers), fqnType!(KeyType!T, noQualifiers)) ); } else static if (isSomeFunction!T) { static if (is(T F == delegate)) { enum qualifierString = format("%s%s", is(F == shared) ? " shared" : "", is(F == inout) ? " inout" : is(F == immutable) ? " immutable" : is(F == const) ? " const" : "" ); enum formatStr = "%s%s delegate(%s)%s%s"; enum fqnType = chain!( format(formatStr, linkageString!T, fqnType!(ReturnType!T, noQualifiers), parametersTypeString!(T), functionAttributeString!T, qualifierString) ); } else { static if (isFunctionPointer!T) enum formatStr = "%s%s function(%s)%s"; else enum formatStr = "%s%s(%s)%s"; enum fqnType = chain!( format(formatStr, linkageString!T, fqnType!(ReturnType!T, noQualifiers), parametersTypeString!(T), functionAttributeString!T) ); } } else static if (isPointer!T) { enum fqnType = chain!( format("%s*", fqnType!(PointerTarget!T, qualifiers)) ); } else static if (is(T : __vector(V[N]), V, size_t N)) { enum fqnType = chain!( format("__vector(%s[%s])", fqnType!(V, qualifiers), N) ); } else // In case something is forgotten static assert(0, "Unrecognized type " ~ T.stringof ~ ", can't convert to fully qualified string"); } unittest { import std.format : format; alias fqn = fullyQualifiedName; // Verify those 2 are the same for simple case alias Ambiguous = const(QualifiedNameTests.Inner); static assert(fqn!Ambiguous == fqnType!(Ambiguous, false, false, false, false)); // Main tests enum inner_name = "std.traits.QualifiedNameTests.Inner"; with (QualifiedNameTests) { // Special cases static assert(fqn!(string) == "string"); static assert(fqn!(wstring) == "wstring"); static assert(fqn!(dstring) == "dstring"); // Basic qualified name static assert(fqn!(Inner) == inner_name); static assert(fqn!(QualifiedEnum) == "std.traits.QualifiedEnum"); // type static assert(fqn!(QualifiedEnum.a) == "std.traits.QualifiedEnum.a"); // symbol // Array types static assert(fqn!(typeof(array)) == format("%s[]", inner_name)); static assert(fqn!(typeof(sarray)) == format("%s[16]", inner_name)); static assert(fqn!(typeof(aarray)) == format("%s[%s]", inner_name, inner_name)); // qualified key for AA static assert(fqn!(typeof(qualAarray)) == format("const(%s[const(%s)])", inner_name, inner_name)); // Qualified composed data types static assert(fqn!(typeof(data)) == format("shared(const(%s[string])[])", inner_name)); // Function types + function attributes static assert(fqn!(typeof(func)) == format("const(%s[string])(ref %s, scope lazy string) ref", inner_name, inner_name)); static assert(fqn!(typeof(retfunc)) == format("const(%s[string])(return %s) ref", inner_name, inner_name)); static assert(fqn!(typeof(inoutFunc)) == format("inout(%s(inout(%s)))", inner_name, inner_name)); static assert(fqn!(typeof(deleg)) == format("const(%s delegate(double, string) nothrow @safe)", inner_name)); static assert(fqn!(typeof(inoutDeleg)) == "inout(int) delegate(inout(int)) inout"); static assert(fqn!(typeof(funcPtr)) == format("%s function(out double, string)", inner_name)); static assert(fqn!(typeof(cFuncPtr)) == format("extern(C) %s function(double, string)", inner_name)); // Delegate type with qualified function type static assert(fqn!(typeof(attrDeleg)) == format("shared(immutable(%s) "~ "delegate(ref double, scope string) nothrow @trusted shared const)", inner_name)); // Variable argument function types static assert(fqn!(typeof(cVarArg)) == "extern(C) void(int, ...)"); static assert(fqn!(typeof(dVarArg)) == "void(...)"); static assert(fqn!(typeof(dVarArg2)) == "void(int, ...)"); static assert(fqn!(typeof(typesafeVarArg)) == "void(int[] ...)"); // SIMD vector static if (is(__vector(float[4]))) { static assert(fqn!(__vector(float[4])) == "__vector(float[4])"); } } } /*** * Get the type of the return value from a function, * a pointer to function, a delegate, a struct * with an opCall, a pointer to a struct with an opCall, * or a class with an $(D opCall). Please note that $(D_KEYWORD ref) * is not part of a type, but the attribute of the function * (see template $(LREF functionAttributes)). */ template ReturnType(func...) if (func.length == 1 && isCallable!func) { static if (is(FunctionTypeOf!func R == return)) alias ReturnType = R; else static assert(0, "argument has no return type"); } /// unittest { int foo(); ReturnType!foo x; // x is declared as int } unittest { struct G { int opCall (int i) { return 1;} } alias ShouldBeInt = ReturnType!G; static assert(is(ShouldBeInt == int)); G g; static assert(is(ReturnType!g == int)); G* p; alias pg = ReturnType!p; static assert(is(pg == int)); class C { int opCall (int i) { return 1;} } static assert(is(ReturnType!C == int)); C c; static assert(is(ReturnType!c == int)); class Test { int prop() @property { return 0; } } alias R_Test_prop = ReturnType!(Test.prop); static assert(is(R_Test_prop == int)); alias R_dglit = ReturnType!((int a) { return a; }); static assert(is(R_dglit == int)); } /*** Get, as a tuple, the types of the parameters to a function, a pointer to function, a delegate, a struct with an $(D opCall), a pointer to a struct with an $(D opCall), or a class with an $(D opCall). */ template Parameters(func...) if (func.length == 1 && isCallable!func) { static if (is(FunctionTypeOf!func P == function)) alias Parameters = P; else static assert(0, "argument has no parameters"); } /// unittest { int foo(int, long); void bar(Parameters!foo); // declares void bar(int, long); void abc(Parameters!foo[1]); // declares void abc(long); } /** * Alternate name for $(LREF Parameters), kept for legacy compatibility. */ alias ParameterTypeTuple = Parameters; unittest { int foo(int i, bool b) { return 0; } static assert(is(ParameterTypeTuple!foo == TypeTuple!(int, bool))); static assert(is(ParameterTypeTuple!(typeof(&foo)) == TypeTuple!(int, bool))); struct S { real opCall(real r, int i) { return 0.0; } } S s; static assert(is(ParameterTypeTuple!S == TypeTuple!(real, int))); static assert(is(ParameterTypeTuple!(S*) == TypeTuple!(real, int))); static assert(is(ParameterTypeTuple!s == TypeTuple!(real, int))); class Test { int prop() @property { return 0; } } alias P_Test_prop = ParameterTypeTuple!(Test.prop); static assert(P_Test_prop.length == 0); alias P_dglit = ParameterTypeTuple!((int a){}); static assert(P_dglit.length == 1); static assert(is(P_dglit[0] == int)); } /** Returns the number of arguments of function $(D func). arity is undefined for variadic functions. */ template arity(alias func) if ( isCallable!func && variadicFunctionStyle!func == Variadic.no ) { enum size_t arity = Parameters!func.length; } /// unittest { void foo(){} static assert(arity!foo==0); void bar(uint){} static assert(arity!bar==1); void variadicFoo(uint...){} static assert(!__traits(compiles, arity!variadicFoo)); } /** Returns a tuple consisting of the storage classes of the parameters of a function $(D func). */ enum ParameterStorageClass : uint { /** * These flags can be bitwise OR-ed together to represent complex storage * class. */ none = 0, scope_ = 0b000_1, /// ditto out_ = 0b001_0, /// ditto ref_ = 0b010_0, /// ditto lazy_ = 0b100_0, /// ditto return_ = 0b1000_0, /// ditto } /// ditto template ParameterStorageClassTuple(func...) if (func.length == 1 && isCallable!func) { alias Func = Unqual!(FunctionTypeOf!func); /* * TypeFuncion: * CallConvention FuncAttrs Arguments ArgClose Type */ alias Params = Parameters!Func; // chop off CallConvention and FuncAttrs enum margs = demangleFunctionAttributes(mangledName!Func[1 .. $]).rest; // demangle Arguments and store parameter storage classes in a tuple template demangleNextParameter(string margs, size_t i = 0) { static if (i < Params.length) { enum demang = demangleParameterStorageClass(margs); enum skip = mangledName!(Params[i]).length; // for bypassing Type enum rest = demang.rest; alias demangleNextParameter = TypeTuple!( demang.value + 0, // workaround: "not evaluatable at ..." demangleNextParameter!(rest[skip .. $], i + 1) ); } else // went thru all the parameters { alias demangleNextParameter = TypeTuple!(); } } alias ParameterStorageClassTuple = demangleNextParameter!margs; } /// unittest { alias STC = ParameterStorageClass; // shorten the enum name void func(ref int ctx, out real result, real param) { } alias pstc = ParameterStorageClassTuple!func; static assert(pstc.length == 3); // three parameters static assert(pstc[0] == STC.ref_); static assert(pstc[1] == STC.out_); static assert(pstc[2] == STC.none); } unittest { alias STC = ParameterStorageClass; void noparam() {} static assert(ParameterStorageClassTuple!noparam.length == 0); void test(scope int, ref int, out int, lazy int, int, return ref int) { } alias test_pstc = ParameterStorageClassTuple!test; static assert(test_pstc.length == 6); static assert(test_pstc[0] == STC.scope_); static assert(test_pstc[1] == STC.ref_); static assert(test_pstc[2] == STC.out_); static assert(test_pstc[3] == STC.lazy_); static assert(test_pstc[4] == STC.none); static assert(test_pstc[5] == STC.return_); interface Test { void test_const(int) const; void test_sharedconst(int) shared const; } Test testi; alias test_const_pstc = ParameterStorageClassTuple!(Test.test_const); static assert(test_const_pstc.length == 1); static assert(test_const_pstc[0] == STC.none); alias test_sharedconst_pstc = ParameterStorageClassTuple!(testi.test_sharedconst); static assert(test_sharedconst_pstc.length == 1); static assert(test_sharedconst_pstc[0] == STC.none); alias dglit_pstc = ParameterStorageClassTuple!((ref int a) {}); static assert(dglit_pstc.length == 1); static assert(dglit_pstc[0] == STC.ref_); // Bugzilla 9317 static inout(int) func(inout int param) { return param; } static assert(ParameterStorageClassTuple!(typeof(func))[0] == STC.none); } unittest { // Bugzilla 14253 static struct Foo { ref Foo opAssign(ref Foo rhs) return { return this; } } alias tup = ParameterStorageClassTuple!(__traits(getOverloads, Foo, "opAssign")[0]); } /** Get, as a tuple, the identifiers of the parameters to a function symbol. */ template ParameterIdentifierTuple(func...) if (func.length == 1 && isCallable!func) { static if (is(FunctionTypeOf!func PT == __parameters)) { template Get(size_t i) { static if (!isFunctionPointer!func && !isDelegate!func // Unnamed parameters yield CT error. && is(typeof(__traits(identifier, PT[i..i+1]))x)) { enum Get = __traits(identifier, PT[i..i+1]); } else { enum Get = ""; } } } else { static assert(0, func[0].stringof ~ "is not a function"); // Define dummy entities to avoid pointless errors template Get(size_t i) { enum Get = ""; } alias PT = TypeTuple!(); } template Impl(size_t i = 0) { static if (i == PT.length) alias Impl = TypeTuple!(); else alias Impl = TypeTuple!(Get!i, Impl!(i+1)); } alias ParameterIdentifierTuple = Impl!(); } /// unittest { int foo(int num, string name, int); static assert([ParameterIdentifierTuple!foo] == ["num", "name", ""]); } unittest { alias PIT = ParameterIdentifierTuple; void bar(int num, string name, int[] array){} static assert([PIT!bar] == ["num", "name", "array"]); // might be changed in the future? void function(int num, string name) fp; static assert([PIT!fp] == ["", ""]); // might be changed in the future? void delegate(int num, string name, int[long] aa) dg; static assert([PIT!dg] == ["", "", ""]); interface Test { @property string getter(); @property void setter(int a); Test method(int a, long b, string c); } static assert([PIT!(Test.getter)] == []); static assert([PIT!(Test.setter)] == ["a"]); static assert([PIT!(Test.method)] == ["a", "b", "c"]); /+ // depends on internal void baw(int, string, int[]){} static assert([PIT!baw] == ["_param_0", "_param_1", "_param_2"]); // depends on internal void baz(TypeTuple!(int, string, int[]) args){} static assert([PIT!baz] == ["_param_0", "_param_1", "_param_2"]); +/ } /** Get, as a tuple, the default value of the parameters to a function symbol. If a parameter doesn't have the default value, $(D void) is returned instead. */ template ParameterDefaults(func...) if (func.length == 1 && isCallable!func) { static if (is(FunctionTypeOf!(func[0]) PT == __parameters)) { template Get(size_t i) { enum ParamName = ParameterIdentifierTuple!(func[0])[i]; static if (ParamName.length) enum get = (PT[i..i+1]) => mixin(ParamName); else // Unnamed parameter enum get = (PT[i..i+1] __args) => __args[0]; static if (is(typeof(get()))) enum Get = get(); else alias Get = void; // If default arg doesn't exist, returns void instead. } } else static if (is(FunctionTypeOf!func PT == __parameters)) { template Get(size_t i) { enum Get = ""; } } else { static assert(0, func[0].stringof ~ "is not a function"); // Define dummy entities to avoid pointless errors template Get(size_t i) { enum Get = ""; } alias PT = TypeTuple!(); } template Impl(size_t i = 0) { static if (i == PT.length) alias Impl = TypeTuple!(); else alias Impl = TypeTuple!(Get!i, Impl!(i+1)); } alias ParameterDefaults = Impl!(); } /// unittest { int foo(int num, string name = "hello", int[] = [1,2,3]); static assert(is(ParameterDefaults!foo[0] == void)); static assert( ParameterDefaults!foo[1] == "hello"); static assert( ParameterDefaults!foo[2] == [1,2,3]); } /** * Alternate name for $(LREF ParameterDefaults), kept for legacy compatibility. */ alias ParameterDefaultValueTuple = ParameterDefaults; unittest { alias PDVT = ParameterDefaultValueTuple; void bar(int n = 1, string s = "hello"){} static assert(PDVT!bar.length == 2); static assert(PDVT!bar[0] == 1); static assert(PDVT!bar[1] == "hello"); static assert(is(typeof(PDVT!bar) == typeof(TypeTuple!(1, "hello")))); void baz(int x, int n = 1, string s = "hello"){} static assert(PDVT!baz.length == 3); static assert(is(PDVT!baz[0] == void)); static assert( PDVT!baz[1] == 1); static assert( PDVT!baz[2] == "hello"); static assert(is(typeof(PDVT!baz) == typeof(TypeTuple!(void, 1, "hello")))); // bug 10800 - property functions return empty string @property void foo(int x = 3) { } static assert(PDVT!foo.length == 1); static assert(PDVT!foo[0] == 3); static assert(is(typeof(PDVT!foo) == typeof(TypeTuple!(3)))); struct Colour { ubyte a,r,g,b; static immutable Colour white = Colour(255,255,255,255); } void bug8106(Colour c = Colour.white){} //pragma(msg, PDVT!bug8106); static assert(PDVT!bug8106[0] == Colour.white); } /** Returns the attributes attached to a function $(D func). */ enum FunctionAttribute : uint { /** * These flags can be bitwise OR-ed together to represent a complex attribute. */ none = 0, pure_ = 1 << 0, /// ditto nothrow_ = 1 << 1, /// ditto ref_ = 1 << 2, /// ditto property = 1 << 3, /// ditto trusted = 1 << 4, /// ditto safe = 1 << 5, /// ditto nogc = 1 << 6, /// ditto system = 1 << 7, /// ditto const_ = 1 << 8, /// ditto immutable_ = 1 << 9, /// ditto inout_ = 1 << 10, /// ditto shared_ = 1 << 11, /// ditto return_ = 1 << 12, /// ditto } /// ditto template functionAttributes(func...) if (func.length == 1 && isCallable!func) { // @bug: workaround for opCall alias FuncSym = Select!(is(typeof(__traits(getFunctionAttributes, func))), func, Unqual!(FunctionTypeOf!func)); enum FunctionAttribute functionAttributes = extractAttribFlags!(__traits(getFunctionAttributes, FuncSym))(); } /// unittest { import std.traits : functionAttributes, FunctionAttribute; alias FA = FunctionAttribute; // shorten the enum name real func(real x) pure nothrow @safe { return x; } static assert(functionAttributes!func & FA.pure_); static assert(functionAttributes!func & FA.safe); static assert(!(functionAttributes!func & FA.trusted)); // not @trusted } unittest { alias FA = FunctionAttribute; struct S { int noF() { return 0; } int constF() const { return 0; } int immutableF() immutable { return 0; } int inoutF() inout { return 0; } int sharedF() shared { return 0; } int x; ref int refF() return { return x; } int propertyF() @property { return 0; } int nothrowF() nothrow { return 0; } int nogcF() @nogc { return 0; } int systemF() @system { return 0; } int trustedF() @trusted { return 0; } int safeF() @safe { return 0; } int pureF() pure { return 0; } } static assert(functionAttributes!(S.noF) == FA.system); static assert(functionAttributes!(typeof(S.noF)) == FA.system); static assert(functionAttributes!(S.constF) == (FA.const_ | FA.system)); static assert(functionAttributes!(typeof(S.constF)) == (FA.const_ | FA.system)); static assert(functionAttributes!(S.immutableF) == (FA.immutable_ | FA.system)); static assert(functionAttributes!(typeof(S.immutableF)) == (FA.immutable_ | FA.system)); static assert(functionAttributes!(S.inoutF) == (FA.inout_ | FA.system)); static assert(functionAttributes!(typeof(S.inoutF)) == (FA.inout_ | FA.system)); static assert(functionAttributes!(S.sharedF) == (FA.shared_ | FA.system)); static assert(functionAttributes!(typeof(S.sharedF)) == (FA.shared_ | FA.system)); static assert(functionAttributes!(S.refF) == (FA.ref_ | FA.system | FA.return_)); static assert(functionAttributes!(typeof(S.refF)) == (FA.ref_ | FA.system | FA.return_)); static assert(functionAttributes!(S.propertyF) == (FA.property | FA.system)); static assert(functionAttributes!(typeof(&S.propertyF)) == (FA.property | FA.system)); static assert(functionAttributes!(S.nothrowF) == (FA.nothrow_ | FA.system)); static assert(functionAttributes!(typeof(S.nothrowF)) == (FA.nothrow_ | FA.system)); static assert(functionAttributes!(S.nogcF) == (FA.nogc | FA.system)); static assert(functionAttributes!(typeof(S.nogcF)) == (FA.nogc | FA.system)); static assert(functionAttributes!(S.systemF) == FA.system); static assert(functionAttributes!(typeof(S.systemF)) == FA.system); static assert(functionAttributes!(S.trustedF) == FA.trusted); static assert(functionAttributes!(typeof(S.trustedF)) == FA.trusted); static assert(functionAttributes!(S.safeF) == FA.safe); static assert(functionAttributes!(typeof(S.safeF)) == FA.safe); static assert(functionAttributes!(S.pureF) == (FA.pure_ | FA.system)); static assert(functionAttributes!(typeof(S.pureF)) == (FA.pure_ | FA.system)); int pure_nothrow() nothrow pure { return 0; } void safe_nothrow() @safe nothrow { } static ref int static_ref_property() @property { return *(new int); } ref int ref_property() @property { return *(new int); } static assert(functionAttributes!(pure_nothrow) == (FA.pure_ | FA.nothrow_ | FA.system)); static assert(functionAttributes!(typeof(pure_nothrow)) == (FA.pure_ | FA.nothrow_ | FA.system)); static assert(functionAttributes!(safe_nothrow) == (FA.safe | FA.nothrow_)); static assert(functionAttributes!(typeof(safe_nothrow)) == (FA.safe | FA.nothrow_)); static assert(functionAttributes!(static_ref_property) == (FA.property | FA.ref_ | FA.system)); static assert(functionAttributes!(typeof(&static_ref_property)) == (FA.property | FA.ref_ | FA.system)); static assert(functionAttributes!(ref_property) == (FA.property | FA.ref_ | FA.system)); static assert(functionAttributes!(typeof(&ref_property)) == (FA.property | FA.ref_ | FA.system)); struct S2 { int pure_const() const pure { return 0; } int pure_sharedconst() const shared pure { return 0; } } static assert(functionAttributes!(S2.pure_const) == (FA.const_ | FA.pure_ | FA.system)); static assert(functionAttributes!(typeof(S2.pure_const)) == (FA.const_ | FA.pure_ | FA.system)); static assert(functionAttributes!(S2.pure_sharedconst) == (FA.const_ | FA.shared_ | FA.pure_ | FA.system)); static assert(functionAttributes!(typeof(S2.pure_sharedconst)) == (FA.const_ | FA.shared_ | FA.pure_ | FA.system)); static assert(functionAttributes!((int a) { }) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.safe)); static assert(functionAttributes!(typeof((int a) { })) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.safe)); auto safeDel = delegate() @safe { }; static assert(functionAttributes!(safeDel) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.safe)); static assert(functionAttributes!(typeof(safeDel)) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.safe)); auto trustedDel = delegate() @trusted { }; static assert(functionAttributes!(trustedDel) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.trusted)); static assert(functionAttributes!(typeof(trustedDel)) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.trusted)); auto systemDel = delegate() @system { }; static assert(functionAttributes!(systemDel) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.system)); static assert(functionAttributes!(typeof(systemDel)) == (FA.pure_ | FA.nothrow_ | FA.nogc | FA.system)); } private FunctionAttribute extractAttribFlags(Attribs...)() { auto res = FunctionAttribute.none; foreach (attrib; Attribs) { switch (attrib) with (FunctionAttribute) { case "pure": res |= pure_; break; case "nothrow": res |= nothrow_; break; case "ref": res |= ref_; break; case "@property": res |= property; break; case "@trusted": res |= trusted; break; case "@safe": res |= safe; break; case "@nogc": res |= nogc; break; case "@system": res |= system; break; case "const": res |= const_; break; case "immutable": res |= immutable_; break; case "inout": res |= inout_; break; case "shared": res |= shared_; break; case "return": res |= return_; break; default: assert(0, attrib); } } return res; } /** $(D true) if $(D func) is $(D @safe) or $(D @trusted). */ template isSafe(alias func) if(isCallable!func) { enum isSafe = (functionAttributes!func & FunctionAttribute.safe) != 0 || (functionAttributes!func & FunctionAttribute.trusted) != 0; } /// unittest { @safe int add(int a, int b) {return a+b;} @trusted int sub(int a, int b) {return a-b;} @system int mul(int a, int b) {return a*b;} static assert( isSafe!add); static assert( isSafe!sub); static assert(!isSafe!mul); } unittest { //Member functions interface Set { int systemF() @system; int trustedF() @trusted; int safeF() @safe; } static assert( isSafe!(Set.safeF)); static assert( isSafe!(Set.trustedF)); static assert(!isSafe!(Set.systemF)); //Functions @safe static safeFunc() {} @trusted static trustedFunc() {} @system static systemFunc() {} static assert( isSafe!safeFunc); static assert( isSafe!trustedFunc); static assert(!isSafe!systemFunc); //Delegates auto safeDel = delegate() @safe {}; auto trustedDel = delegate() @trusted {}; auto systemDel = delegate() @system {}; static assert( isSafe!safeDel); static assert( isSafe!trustedDel); static assert(!isSafe!systemDel); //Lambdas static assert( isSafe!({safeDel();})); static assert( isSafe!({trustedDel();})); static assert(!isSafe!({systemDel();})); //Static opCall struct SafeStatic { @safe static SafeStatic opCall() { return SafeStatic.init; } } struct TrustedStatic { @trusted static TrustedStatic opCall() { return TrustedStatic.init; } } struct SystemStatic { @system static SystemStatic opCall() { return SystemStatic.init; } } static assert( isSafe!(SafeStatic())); static assert( isSafe!(TrustedStatic())); static assert(!isSafe!(SystemStatic())); //Non-static opCall struct Safe { @safe Safe opCall() { return Safe.init; } } struct Trusted { @trusted Trusted opCall() { return Trusted.init; } } struct System { @system System opCall() { return System.init; } } static assert( isSafe!(Safe.init())); static assert( isSafe!(Trusted.init())); static assert(!isSafe!(System.init())); } /** $(D true) if $(D func) is $(D @system). */ template isUnsafe(alias func) { enum isUnsafe = !isSafe!func; } /// unittest { @safe int add(int a, int b) {return a+b;} @trusted int sub(int a, int b) {return a-b;} @system int mul(int a, int b) {return a*b;} static assert(!isUnsafe!add); static assert(!isUnsafe!sub); static assert( isUnsafe!mul); } unittest { //Member functions interface Set { int systemF() @system; int trustedF() @trusted; int safeF() @safe; } static assert(!isUnsafe!(Set.safeF)); static assert(!isUnsafe!(Set.trustedF)); static assert( isUnsafe!(Set.systemF)); //Functions @safe static safeFunc() {} @trusted static trustedFunc() {} @system static systemFunc() {} static assert(!isUnsafe!safeFunc); static assert(!isUnsafe!trustedFunc); static assert( isUnsafe!systemFunc); //Delegates auto safeDel = delegate() @safe {}; auto trustedDel = delegate() @trusted {}; auto systemDel = delegate() @system {}; static assert(!isUnsafe!safeDel); static assert(!isUnsafe!trustedDel); static assert( isUnsafe!systemDel); //Lambdas static assert(!isUnsafe!({safeDel();})); static assert(!isUnsafe!({trustedDel();})); static assert( isUnsafe!({systemDel();})); //Static opCall struct SafeStatic { @safe static SafeStatic opCall() { return SafeStatic.init; } } struct TrustedStatic { @trusted static TrustedStatic opCall() { return TrustedStatic.init; } } struct SystemStatic { @system static SystemStatic opCall() { return SystemStatic.init; } } static assert(!isUnsafe!(SafeStatic())); static assert(!isUnsafe!(TrustedStatic())); static assert( isUnsafe!(SystemStatic())); //Non-static opCall struct Safe { @safe Safe opCall() { return Safe.init; } } struct Trusted { @trusted Trusted opCall() { return Trusted.init; } } struct System { @system System opCall() { return System.init; } } static assert(!isUnsafe!(Safe.init())); static assert(!isUnsafe!(Trusted.init())); static assert( isUnsafe!(System.init())); } // Explicitly undocumented. It will be removed in June 2016. @@@DEPRECATED_2016-06@@@ deprecated("Please use allSatisfy(isSafe, ...) instead.") template areAllSafe(funcs...) if (funcs.length > 0) { static if (funcs.length == 1) { enum areAllSafe = isSafe!(funcs[0]); } else static if (isSafe!(funcs[0])) { enum areAllSafe = areAllSafe!(funcs[1..$]); } else { enum areAllSafe = false; } } // Verify Example deprecated unittest { @safe int add(int a, int b) {return a+b;} @trusted int sub(int a, int b) {return a-b;} @system int mul(int a, int b) {return a*b;} static assert( areAllSafe!(add, add)); static assert( areAllSafe!(add, sub)); static assert(!areAllSafe!(sub, mul)); } deprecated unittest { interface Set { int systemF() @system; int trustedF() @trusted; int safeF() @safe; } static assert( areAllSafe!((int a){}, Set.safeF)); static assert( areAllSafe!((int a){}, Set.safeF, Set.trustedF)); static assert(!areAllSafe!(Set.trustedF, Set.systemF)); } /** Returns the calling convention of function as a string. */ template functionLinkage(func...) if (func.length == 1 && isCallable!func) { alias Func = Unqual!(FunctionTypeOf!func); enum string functionLinkage = [ 'F': "D", 'U': "C", 'W': "Windows", 'V': "Pascal", 'R': "C++" ][ mangledName!Func[0] ]; } /// unittest { extern(D) void Dfunc() {} extern(C) void Cfunc() {} static assert(functionLinkage!Dfunc == "D"); static assert(functionLinkage!Cfunc == "C"); string a = functionLinkage!Dfunc; assert(a == "D"); auto fp = &Cfunc; string b = functionLinkage!fp; assert(b == "C"); } unittest { interface Test { void const_func() const; void sharedconst_func() shared const; } static assert(functionLinkage!(Test.const_func) == "D"); static assert(functionLinkage!(Test.sharedconst_func) == "D"); static assert(functionLinkage!((int a){}) == "D"); } /** Determines what kind of variadic parameters function has. */ enum Variadic { no, /// Function is not variadic. c, /// Function is a _C-style variadic function. /// Function is a _D-style variadic function, which uses d, /// __argptr and __arguments. typesafe, /// Function is a typesafe variadic function. } /// ditto template variadicFunctionStyle(func...) if (func.length == 1 && isCallable!func) { alias Func = Unqual!(FunctionTypeOf!func); // TypeFuncion --> CallConvention FuncAttrs Arguments ArgClose Type enum callconv = functionLinkage!Func; enum mfunc = mangledName!Func; enum mtype = mangledName!(ReturnType!Func); static assert(mfunc[$ - mtype.length .. $] == mtype, mfunc ~ "|" ~ mtype); enum argclose = mfunc[$ - mtype.length - 1]; static assert(argclose >= 'X' && argclose <= 'Z'); enum Variadic variadicFunctionStyle = argclose == 'X' ? Variadic.typesafe : argclose == 'Y' ? (callconv == "C") ? Variadic.c : Variadic.d : Variadic.no; // 'Z' } /// unittest { void func() {} static assert(variadicFunctionStyle!func == Variadic.no); extern(C) int printf(in char*, ...); static assert(variadicFunctionStyle!printf == Variadic.c); } unittest { import core.vararg; extern(D) void novar() {} extern(C) void cstyle(int, ...) {} extern(D) void dstyle(...) {} extern(D) void typesafe(int[]...) {} static assert(variadicFunctionStyle!novar == Variadic.no); static assert(variadicFunctionStyle!cstyle == Variadic.c); static assert(variadicFunctionStyle!dstyle == Variadic.d); static assert(variadicFunctionStyle!typesafe == Variadic.typesafe); static assert(variadicFunctionStyle!((int[] a...) {}) == Variadic.typesafe); } /** Get the function type from a callable object $(D func). Using builtin $(D typeof) on a property function yields the types of the property value, not of the property function itself. Still, $(D FunctionTypeOf) is able to obtain function types of properties. Note: Do not confuse function types with function pointer types; function types are usually used for compile-time reflection purposes. */ template FunctionTypeOf(func...) if (func.length == 1 && isCallable!func) { static if (is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function) || is(typeof(& func[0]) Fsym == delegate)) { alias FunctionTypeOf = Fsym; // HIT: (nested) function symbol } else static if (is(typeof(& func[0].opCall) Fobj == delegate)) { alias FunctionTypeOf = Fobj; // HIT: callable object } else static if (is(typeof(& func[0].opCall) Ftyp : Ftyp*) && is(Ftyp == function)) { alias FunctionTypeOf = Ftyp; // HIT: callable type } else static if (is(func[0] T) || is(typeof(func[0]) T)) { static if (is(T == function)) alias FunctionTypeOf = T; // HIT: function else static if (is(T Fptr : Fptr*) && is(Fptr == function)) alias FunctionTypeOf = Fptr; // HIT: function pointer else static if (is(T Fdlg == delegate)) alias FunctionTypeOf = Fdlg; // HIT: delegate else static assert(0); } else static assert(0); } /// unittest { class C { int value() @property { return 0; } } static assert(is( typeof(C.value) == int )); static assert(is( FunctionTypeOf!(C.value) == function )); } unittest { int test(int a) { return 0; } int propGet() @property { return 0; } int propSet(int a) @property { return 0; } int function(int) test_fp; int delegate(int) test_dg; static assert(is( typeof(test) == FunctionTypeOf!(typeof(test)) )); static assert(is( typeof(test) == FunctionTypeOf!test )); static assert(is( typeof(test) == FunctionTypeOf!test_fp )); static assert(is( typeof(test) == FunctionTypeOf!test_dg )); alias int GetterType() @property; alias int SetterType(int) @property; static assert(is( FunctionTypeOf!propGet == GetterType )); static assert(is( FunctionTypeOf!propSet == SetterType )); interface Prop { int prop() @property; } Prop prop; static assert(is( FunctionTypeOf!(Prop.prop) == GetterType )); static assert(is( FunctionTypeOf!(prop.prop) == GetterType )); class Callable { int opCall(int) { return 0; } } auto call = new Callable; static assert(is( FunctionTypeOf!call == typeof(test) )); struct StaticCallable { static int opCall(int) { return 0; } } StaticCallable stcall_val; StaticCallable* stcall_ptr; static assert(is( FunctionTypeOf!stcall_val == typeof(test) )); static assert(is( FunctionTypeOf!stcall_ptr == typeof(test) )); interface Overloads { void test(string); real test(real); int test(int); int test() @property; } alias ov = TypeTuple!(__traits(getVirtualFunctions, Overloads, "test")); alias F_ov0 = FunctionTypeOf!(ov[0]); alias F_ov1 = FunctionTypeOf!(ov[1]); alias F_ov2 = FunctionTypeOf!(ov[2]); alias F_ov3 = FunctionTypeOf!(ov[3]); static assert(is(F_ov0* == void function(string))); static assert(is(F_ov1* == real function(real))); static assert(is(F_ov2* == int function(int))); static assert(is(F_ov3* == int function() @property)); alias F_dglit = FunctionTypeOf!((int a){ return a; }); static assert(is(F_dglit* : int function(int))); } /** * Constructs a new function or delegate type with the same basic signature * as the given one, but different attributes (including linkage). * * This is especially useful for adding/removing attributes to/from types in * generic code, where the actual type name cannot be spelt out. * * Params: * T = The base type. * linkage = The desired linkage of the result type. * attrs = The desired $(LREF FunctionAttribute)s of the result type. */ template SetFunctionAttributes(T, string linkage, uint attrs) if (isFunctionPointer!T || isDelegate!T) { mixin({ import std.algorithm : canFind; static assert(!(attrs & FunctionAttribute.trusted) || !(attrs & FunctionAttribute.safe), "Cannot have a function/delegate that is both trusted and safe."); enum linkages = ["D", "C", "Windows", "Pascal", "C++", "System"]; static assert(canFind(linkages, linkage), "Invalid linkage '" ~ linkage ~ "', must be one of " ~ linkages.stringof ~ "."); string result = "alias "; static if (linkage != "D") result ~= "extern(" ~ linkage ~ ") "; static if (attrs & FunctionAttribute.ref_) result ~= "ref "; result ~= "ReturnType!T"; static if (isDelegate!T) result ~= " delegate"; else result ~= " function"; result ~= "("; static if (Parameters!T.length > 0) result ~= "Parameters!T"; enum varStyle = variadicFunctionStyle!T; static if (varStyle == Variadic.c) result ~= ", ..."; else static if (varStyle == Variadic.d) result ~= "..."; else static if (varStyle == Variadic.typesafe) result ~= "..."; result ~= ")"; static if (attrs & FunctionAttribute.pure_) result ~= " pure"; static if (attrs & FunctionAttribute.nothrow_) result ~= " nothrow"; static if (attrs & FunctionAttribute.property) result ~= " @property"; static if (attrs & FunctionAttribute.trusted) result ~= " @trusted"; static if (attrs & FunctionAttribute.safe) result ~= " @safe"; static if (attrs & FunctionAttribute.nogc) result ~= " @nogc"; static if (attrs & FunctionAttribute.system) result ~= " @system"; static if (attrs & FunctionAttribute.const_) result ~= " const"; static if (attrs & FunctionAttribute.immutable_) result ~= " immutable"; static if (attrs & FunctionAttribute.inout_) result ~= " inout"; static if (attrs & FunctionAttribute.shared_) result ~= " shared"; static if (attrs & FunctionAttribute.return_) result ~= " return"; result ~= " SetFunctionAttributes;"; return result; }()); } /// Ditto template SetFunctionAttributes(T, string linkage, uint attrs) if (is(T == function)) { // To avoid a lot of syntactic headaches, we just use the above version to // operate on the corresponding function pointer type and then remove the // indirection again. alias SetFunctionAttributes = FunctionTypeOf!(SetFunctionAttributes!(T*, linkage, attrs)); } /// unittest { alias ExternC(T) = SetFunctionAttributes!(T, "C", functionAttributes!T); auto assumePure(T)(T t) if (isFunctionPointer!T || isDelegate!T) { enum attrs = functionAttributes!T | FunctionAttribute.pure_; return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; } } version (unittest) { // Some function types to test. int sc(scope int, ref int, out int, lazy int, int); extern(System) int novar(); extern(C) int cstyle(int, ...); extern(D) int dstyle(...); extern(D) int typesafe(int[]...); } unittest { import std.algorithm : reduce; alias FA = FunctionAttribute; foreach (BaseT; TypeTuple!(typeof(&sc), typeof(&novar), typeof(&cstyle), typeof(&dstyle), typeof(&typesafe))) { foreach (T; TypeTuple!(BaseT, FunctionTypeOf!BaseT)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 enum linkage = functionLinkage!T; enum attrs = functionAttributes!T; static assert(is(SetFunctionAttributes!(T, linkage, attrs) == T), "Identity check failed for: " ~ T.stringof); // Check that all linkage types work (D-style variadics require D linkage). static if (variadicFunctionStyle!T != Variadic.d) { foreach (newLinkage; TypeTuple!("D", "C", "Windows", "Pascal", "C++")) { alias New = SetFunctionAttributes!(T, newLinkage, attrs); static assert(functionLinkage!New == newLinkage, "Linkage test failed for: " ~ T.stringof ~ ", " ~ newLinkage ~ " (got " ~ New.stringof ~ ")"); } } // Add @safe. alias T1 = SetFunctionAttributes!(T, functionLinkage!T, FA.safe); static assert(functionAttributes!T1 == FA.safe); // Add all known attributes, excluding conflicting ones. enum allAttrs = reduce!"a | b"([EnumMembers!FA]) & ~FA.safe & ~FA.property & ~FA.const_ & ~FA.immutable_ & ~FA.inout_ & ~FA.shared_ & ~FA.system & ~FA.return_; alias T2 = SetFunctionAttributes!(T1, functionLinkage!T, allAttrs); static assert(functionAttributes!T2 == allAttrs); // Strip all attributes again. alias T3 = SetFunctionAttributes!(T2, functionLinkage!T, FA.none); static assert(is(T3 == T)); }(); } } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Aggregate Types //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// /** Determines whether $(D T) has its own context pointer. $(D T) must be either $(D class), $(D struct), or $(D union). */ template isNested(T) if(is(T == class) || is(T == struct) || is(T == union)) { enum isNested = __traits(isNested, T); } /// unittest { static struct S { } static assert(!isNested!S); int i; struct NestedStruct { void f() { ++i; } } static assert(isNested!NestedStruct); } /** Determines whether $(D T) or any of its representation types have a context pointer. */ template hasNested(T) { static if(isStaticArray!T && T.length) enum hasNested = hasNested!(typeof(T.init[0])); else static if(is(T == class) || is(T == struct) || is(T == union)) enum hasNested = isNested!T || anySatisfy!(.hasNested, Fields!T); else enum hasNested = false; } /// unittest { static struct S { } int i; struct NS { void f() { ++i; } } static assert(!hasNested!(S[2])); static assert(hasNested!(NS[2])); } unittest { static assert(!__traits(compiles, isNested!int)); static assert(!hasNested!int); static struct StaticStruct { } static assert(!isNested!StaticStruct); static assert(!hasNested!StaticStruct); int i; struct NestedStruct { void f() { ++i; } } static assert( isNested!NestedStruct); static assert( hasNested!NestedStruct); static assert( isNested!(immutable NestedStruct)); static assert( hasNested!(immutable NestedStruct)); static assert(!__traits(compiles, isNested!(NestedStruct[1]))); static assert( hasNested!(NestedStruct[1])); static assert(!hasNested!(NestedStruct[0])); struct S1 { NestedStruct nested; } static assert(!isNested!S1); static assert( hasNested!S1); static struct S2 { NestedStruct nested; } static assert(!isNested!S2); static assert( hasNested!S2); static struct S3 { NestedStruct[0] nested; } static assert(!isNested!S3); static assert(!hasNested!S3); static union U { NestedStruct nested; } static assert(!isNested!U); static assert( hasNested!U); static class StaticClass { } static assert(!isNested!StaticClass); static assert(!hasNested!StaticClass); class NestedClass { void f() { ++i; } } static assert( isNested!NestedClass); static assert( hasNested!NestedClass); static assert( isNested!(immutable NestedClass)); static assert( hasNested!(immutable NestedClass)); static assert(!__traits(compiles, isNested!(NestedClass[1]))); static assert( hasNested!(NestedClass[1])); static assert(!hasNested!(NestedClass[0])); } /*** * Get as a tuple the types of the fields of a struct, class, or union. * This consists of the fields that take up memory space, * excluding the hidden fields like the virtual function * table pointer or a context pointer for nested types. * If $(D T) isn't a struct, class, or union returns a tuple * with one element $(D T). */ template Fields(T) { static if (is(T == struct) || is(T == union)) alias Fields = typeof(T.tupleof[0 .. $ - isNested!T]); else static if (is(T == class)) alias Fields = typeof(T.tupleof); else alias Fields = TypeTuple!T; } /// unittest { struct S { int x; float y; } static assert(is(Fields!S == TypeTuple!(int, float))); } /** * Alternate name for $(LREF Fields), kept for legacy compatibility. */ alias FieldTypeTuple = Fields; unittest { static assert(is(FieldTypeTuple!int == TypeTuple!int)); static struct StaticStruct1 { } static assert(is(FieldTypeTuple!StaticStruct1 == TypeTuple!())); static struct StaticStruct2 { int a, b; } static assert(is(FieldTypeTuple!StaticStruct2 == TypeTuple!(int, int))); int i; struct NestedStruct1 { void f() { ++i; } } static assert(is(FieldTypeTuple!NestedStruct1 == TypeTuple!())); struct NestedStruct2 { int a; void f() { ++i; } } static assert(is(FieldTypeTuple!NestedStruct2 == TypeTuple!int)); class NestedClass { int a; void f() { ++i; } } static assert(is(FieldTypeTuple!NestedClass == TypeTuple!int)); } //Required for FieldNameTuple private enum NameOf(alias T) = T.stringof; /** * Get as an expression tuple the names of the fields of a struct, class, or * union. This consists of the fields that take up memory space, excluding the * hidden fields like the virtual function table pointer or a context pointer * for nested types. If $(D T) isn't a struct, class, or union returns an * expression tuple with an empty string. */ template FieldNameTuple(T) { static if (is(T == struct) || is(T == union)) alias FieldNameTuple = staticMap!(NameOf, T.tupleof[0 .. $ - isNested!T]); else static if (is(T == class)) alias FieldNameTuple = staticMap!(NameOf, T.tupleof); else alias FieldNameTuple = TypeTuple!""; } /// unittest { struct S { int x; float y; } static assert(FieldNameTuple!S == TypeTuple!("x", "y")); static assert(FieldNameTuple!int == TypeTuple!""); } unittest { static assert(FieldNameTuple!int == TypeTuple!""); static struct StaticStruct1 { } static assert(is(FieldNameTuple!StaticStruct1 == TypeTuple!())); static struct StaticStruct2 { int a, b; } static assert(FieldNameTuple!StaticStruct2 == TypeTuple!("a", "b")); int i; struct NestedStruct1 { void f() { ++i; } } static assert(is(FieldNameTuple!NestedStruct1 == TypeTuple!())); struct NestedStruct2 { int a; void f() { ++i; } } static assert(FieldNameTuple!NestedStruct2 == TypeTuple!"a"); class NestedClass { int a; void f() { ++i; } } static assert(FieldNameTuple!NestedClass == TypeTuple!"a"); } /*** Get the primitive types of the fields of a struct or class, in topological order. */ template RepresentationTypeTuple(T) { template Impl(T...) { static if (T.length == 0) { alias Impl = TypeTuple!(); } else { import std.typecons : Rebindable; static if (is(T[0] R: Rebindable!R)) { alias Impl = Impl!(Impl!R, T[1 .. $]); } else static if (is(T[0] == struct) || is(T[0] == union)) { // @@@BUG@@@ this should work //alias .RepresentationTypes!(T[0].tupleof) // RepresentationTypes; alias Impl = Impl!(FieldTypeTuple!(T[0]), T[1 .. $]); } else { alias Impl = TypeTuple!(T[0], Impl!(T[1 .. $])); } } } static if (is(T == struct) || is(T == union) || is(T == class)) { alias RepresentationTypeTuple = Impl!(FieldTypeTuple!T); } else { alias RepresentationTypeTuple = Impl!T; } } /// unittest { struct S1 { int a; float b; } struct S2 { char[] a; union { S1 b; S1 * c; } } alias R = RepresentationTypeTuple!S2; assert(R.length == 4 && is(R[0] == char[]) && is(R[1] == int) && is(R[2] == float) && is(R[3] == S1*)); } unittest { alias S1 = RepresentationTypeTuple!int; static assert(is(S1 == TypeTuple!int)); struct S2 { int a; } struct S3 { int a; char b; } struct S4 { S1 a; int b; S3 c; } static assert(is(RepresentationTypeTuple!S2 == TypeTuple!int)); static assert(is(RepresentationTypeTuple!S3 == TypeTuple!(int, char))); static assert(is(RepresentationTypeTuple!S4 == TypeTuple!(int, int, int, char))); struct S11 { int a; float b; } struct S21 { char[] a; union { S11 b; S11 * c; } } alias R = RepresentationTypeTuple!S21; assert(R.length == 4 && is(R[0] == char[]) && is(R[1] == int) && is(R[2] == float) && is(R[3] == S11*)); class C { int a; float b; } alias R1 = RepresentationTypeTuple!C; static assert(R1.length == 2 && is(R1[0] == int) && is(R1[1] == float)); /* Issue 6642 */ import std.typecons : Rebindable; struct S5 { int a; Rebindable!(immutable Object) b; } alias R2 = RepresentationTypeTuple!S5; static assert(R2.length == 2 && is(R2[0] == int) && is(R2[1] == immutable(Object))); } /* Statically evaluates to $(D true) if and only if $(D T)'s representation contains at least one field of pointer or array type. Members of class types are not considered raw pointers. Pointers to immutable objects are not considered raw aliasing. */ private template hasRawAliasing(T...) { template Impl(T...) { static if (T.length == 0) { enum Impl = false; } else { static if (is(T[0] foo : U*, U) && !isFunctionPointer!(T[0])) enum has = !is(U == immutable); else static if (is(T[0] foo : U[], U) && !isStaticArray!(T[0])) enum has = !is(U == immutable); else static if (isAssociativeArray!(T[0])) enum has = !is(T[0] == immutable); else enum has = false; enum Impl = has || Impl!(T[1 .. $]); } } enum hasRawAliasing = Impl!(RepresentationTypeTuple!T); } /// unittest { // simple types static assert(!hasRawAliasing!int); static assert( hasRawAliasing!(char*)); // references aren't raw pointers static assert(!hasRawAliasing!Object); // built-in arrays do contain raw pointers static assert( hasRawAliasing!(int[])); // aggregate of simple types struct S1 { int a; double b; } static assert(!hasRawAliasing!S1); // indirect aggregation struct S2 { S1 a; double b; } static assert(!hasRawAliasing!S2); } unittest { // struct with a pointer member struct S3 { int a; double * b; } static assert( hasRawAliasing!S3); // struct with an indirect pointer member struct S4 { S3 a; double b; } static assert( hasRawAliasing!S4); struct S5 { int a; Object z; int c; } static assert( hasRawAliasing!S3); static assert( hasRawAliasing!S4); static assert(!hasRawAliasing!S5); union S6 { int a; int b; } union S7 { int a; int * b; } static assert(!hasRawAliasing!S6); static assert( hasRawAliasing!S7); static assert(!hasRawAliasing!(void delegate())); static assert(!hasRawAliasing!(void delegate() const)); static assert(!hasRawAliasing!(void delegate() immutable)); static assert(!hasRawAliasing!(void delegate() shared)); static assert(!hasRawAliasing!(void delegate() shared const)); static assert(!hasRawAliasing!(const(void delegate()))); static assert(!hasRawAliasing!(immutable(void delegate()))); struct S8 { void delegate() a; int b; Object c; } class S12 { typeof(S8.tupleof) a; } class S13 { typeof(S8.tupleof) a; int* b; } static assert(!hasRawAliasing!S8); static assert(!hasRawAliasing!S12); static assert( hasRawAliasing!S13); enum S9 { a } static assert(!hasRawAliasing!S9); // indirect members struct S10 { S7 a; int b; } struct S11 { S6 a; int b; } static assert( hasRawAliasing!S10); static assert(!hasRawAliasing!S11); static assert( hasRawAliasing!(int[string])); static assert(!hasRawAliasing!(immutable(int[string]))); } /* Statically evaluates to $(D true) if and only if $(D T)'s representation contains at least one non-shared field of pointer or array type. Members of class types are not considered raw pointers. Pointers to immutable objects are not considered raw aliasing. */ private template hasRawUnsharedAliasing(T...) { template Impl(T...) { static if (T.length == 0) { enum Impl = false; } else { static if (is(T[0] foo : U*, U) && !isFunctionPointer!(T[0])) enum has = !is(U == immutable) && !is(U == shared); else static if (is(T[0] foo : U[], U) && !isStaticArray!(T[0])) enum has = !is(U == immutable) && !is(U == shared); else static if (isAssociativeArray!(T[0])) enum has = !is(T[0] == immutable) && !is(T[0] == shared); else enum has = false; enum Impl = has || Impl!(T[1 .. $]); } } enum hasRawUnsharedAliasing = Impl!(RepresentationTypeTuple!T); } /// unittest { // simple types static assert(!hasRawUnsharedAliasing!int); static assert( hasRawUnsharedAliasing!(char*)); static assert(!hasRawUnsharedAliasing!(shared char*)); // references aren't raw pointers static assert(!hasRawUnsharedAliasing!Object); // built-in arrays do contain raw pointers static assert( hasRawUnsharedAliasing!(int[])); static assert(!hasRawUnsharedAliasing!(shared int[])); // aggregate of simple types struct S1 { int a; double b; } static assert(!hasRawUnsharedAliasing!S1); // indirect aggregation struct S2 { S1 a; double b; } static assert(!hasRawUnsharedAliasing!S2); // struct with a pointer member struct S3 { int a; double * b; } static assert( hasRawUnsharedAliasing!S3); struct S4 { int a; shared double * b; } static assert(!hasRawUnsharedAliasing!S4); } unittest { // struct with a pointer member struct S3 { int a; double * b; } static assert( hasRawUnsharedAliasing!S3); struct S4 { int a; shared double * b; } static assert(!hasRawUnsharedAliasing!S4); // struct with an indirect pointer member struct S5 { S3 a; double b; } static assert( hasRawUnsharedAliasing!S5); struct S6 { S4 a; double b; } static assert(!hasRawUnsharedAliasing!S6); struct S7 { int a; Object z; int c; } static assert( hasRawUnsharedAliasing!S5); static assert(!hasRawUnsharedAliasing!S6); static assert(!hasRawUnsharedAliasing!S7); union S8 { int a; int b; } union S9 { int a; int* b; } union S10 { int a; shared int* b; } static assert(!hasRawUnsharedAliasing!S8); static assert( hasRawUnsharedAliasing!S9); static assert(!hasRawUnsharedAliasing!S10); static assert(!hasRawUnsharedAliasing!(void delegate())); static assert(!hasRawUnsharedAliasing!(void delegate() const)); static assert(!hasRawUnsharedAliasing!(void delegate() immutable)); static assert(!hasRawUnsharedAliasing!(void delegate() shared)); static assert(!hasRawUnsharedAliasing!(void delegate() shared const)); static assert(!hasRawUnsharedAliasing!(const(void delegate()))); static assert(!hasRawUnsharedAliasing!(const(void delegate() const))); static assert(!hasRawUnsharedAliasing!(const(void delegate() immutable))); static assert(!hasRawUnsharedAliasing!(const(void delegate() shared))); static assert(!hasRawUnsharedAliasing!(const(void delegate() shared const))); static assert(!hasRawUnsharedAliasing!(immutable(void delegate()))); static assert(!hasRawUnsharedAliasing!(immutable(void delegate() const))); static assert(!hasRawUnsharedAliasing!(immutable(void delegate() immutable))); static assert(!hasRawUnsharedAliasing!(immutable(void delegate() shared))); static assert(!hasRawUnsharedAliasing!(immutable(void delegate() shared const))); static assert(!hasRawUnsharedAliasing!(shared(void delegate()))); static assert(!hasRawUnsharedAliasing!(shared(void delegate() const))); static assert(!hasRawUnsharedAliasing!(shared(void delegate() immutable))); static assert(!hasRawUnsharedAliasing!(shared(void delegate() shared))); static assert(!hasRawUnsharedAliasing!(shared(void delegate() shared const))); static assert(!hasRawUnsharedAliasing!(shared(const(void delegate())))); static assert(!hasRawUnsharedAliasing!(shared(const(void delegate() const)))); static assert(!hasRawUnsharedAliasing!(shared(const(void delegate() immutable)))); static assert(!hasRawUnsharedAliasing!(shared(const(void delegate() shared)))); static assert(!hasRawUnsharedAliasing!(shared(const(void delegate() shared const)))); static assert(!hasRawUnsharedAliasing!(void function())); enum S13 { a } static assert(!hasRawUnsharedAliasing!S13); // indirect members struct S14 { S9 a; int b; } struct S15 { S10 a; int b; } struct S16 { S6 a; int b; } static assert( hasRawUnsharedAliasing!S14); static assert(!hasRawUnsharedAliasing!S15); static assert(!hasRawUnsharedAliasing!S16); static assert( hasRawUnsharedAliasing!(int[string])); static assert(!hasRawUnsharedAliasing!(shared(int[string]))); static assert(!hasRawUnsharedAliasing!(immutable(int[string]))); struct S17 { void delegate() shared a; void delegate() immutable b; void delegate() shared const c; shared(void delegate()) d; shared(void delegate() shared) e; shared(void delegate() immutable) f; shared(void delegate() shared const) g; immutable(void delegate()) h; immutable(void delegate() shared) i; immutable(void delegate() immutable) j; immutable(void delegate() shared const) k; shared(const(void delegate())) l; shared(const(void delegate() shared)) m; shared(const(void delegate() immutable)) n; shared(const(void delegate() shared const)) o; } struct S18 { typeof(S17.tupleof) a; void delegate() p; } struct S19 { typeof(S17.tupleof) a; Object p; } struct S20 { typeof(S17.tupleof) a; int* p; } class S21 { typeof(S17.tupleof) a; } class S22 { typeof(S17.tupleof) a; void delegate() p; } class S23 { typeof(S17.tupleof) a; Object p; } class S24 { typeof(S17.tupleof) a; int* p; } static assert(!hasRawUnsharedAliasing!S17); static assert(!hasRawUnsharedAliasing!(immutable(S17))); static assert(!hasRawUnsharedAliasing!(shared(S17))); static assert(!hasRawUnsharedAliasing!S18); static assert(!hasRawUnsharedAliasing!(immutable(S18))); static assert(!hasRawUnsharedAliasing!(shared(S18))); static assert(!hasRawUnsharedAliasing!S19); static assert(!hasRawUnsharedAliasing!(immutable(S19))); static assert(!hasRawUnsharedAliasing!(shared(S19))); static assert( hasRawUnsharedAliasing!S20); static assert(!hasRawUnsharedAliasing!(immutable(S20))); static assert(!hasRawUnsharedAliasing!(shared(S20))); static assert(!hasRawUnsharedAliasing!S21); static assert(!hasRawUnsharedAliasing!(immutable(S21))); static assert(!hasRawUnsharedAliasing!(shared(S21))); static assert(!hasRawUnsharedAliasing!S22); static assert(!hasRawUnsharedAliasing!(immutable(S22))); static assert(!hasRawUnsharedAliasing!(shared(S22))); static assert(!hasRawUnsharedAliasing!S23); static assert(!hasRawUnsharedAliasing!(immutable(S23))); static assert(!hasRawUnsharedAliasing!(shared(S23))); static assert( hasRawUnsharedAliasing!S24); static assert(!hasRawUnsharedAliasing!(immutable(S24))); static assert(!hasRawUnsharedAliasing!(shared(S24))); struct S25 {} class S26 {} interface S27 {} union S28 {} static assert(!hasRawUnsharedAliasing!S25); static assert(!hasRawUnsharedAliasing!S26); static assert(!hasRawUnsharedAliasing!S27); static assert(!hasRawUnsharedAliasing!S28); } /* Statically evaluates to $(D true) if and only if $(D T)'s representation includes at least one non-immutable object reference. */ private template hasObjects(T...) { static if (T.length == 0) { enum hasObjects = false; } else static if (is(T[0] == struct)) { enum hasObjects = hasObjects!( RepresentationTypeTuple!(T[0]), T[1 .. $]); } else { enum hasObjects = ((is(T[0] == class) || is(T[0] == interface)) && !is(T[0] == immutable)) || hasObjects!(T[1 .. $]); } } /* Statically evaluates to $(D true) if and only if $(D T)'s representation includes at least one non-immutable non-shared object reference. */ private template hasUnsharedObjects(T...) { static if (T.length == 0) { enum hasUnsharedObjects = false; } else static if (is(T[0] == struct)) { enum hasUnsharedObjects = hasUnsharedObjects!( RepresentationTypeTuple!(T[0]), T[1 .. $]); } else { enum hasUnsharedObjects = ((is(T[0] == class) || is(T[0] == interface)) && !is(T[0] == immutable) && !is(T[0] == shared)) || hasUnsharedObjects!(T[1 .. $]); } } /** Returns $(D true) if and only if $(D T)'s representation includes at least one of the following: $(OL $(LI a raw pointer $(D U*) and $(D U) is not immutable;) $(LI an array $(D U[]) and $(D U) is not immutable;) $(LI a reference to a class or interface type $(D C) and $(D C) is not immutable.) $(LI an associative array that is not immutable.) $(LI a delegate.)) */ template hasAliasing(T...) { import std.typecons : Rebindable; static if (T.length && is(T[0] : Rebindable!R, R)) { enum hasAliasing = hasAliasing!(R, T[1 .. $]); } else { template isAliasingDelegate(T) { enum isAliasingDelegate = isDelegate!T && !is(T == immutable) && !is(FunctionTypeOf!T == immutable); } enum hasAliasing = hasRawAliasing!T || hasObjects!T || anySatisfy!(isAliasingDelegate, T, RepresentationTypeTuple!T); } } /// unittest { struct S1 { int a; Object b; } struct S2 { string a; } struct S3 { int a; immutable Object b; } struct S4 { float[3] vals; } static assert( hasAliasing!S1); static assert(!hasAliasing!S2); static assert(!hasAliasing!S3); static assert(!hasAliasing!S4); } unittest { static assert( hasAliasing!(uint[uint])); static assert(!hasAliasing!(immutable(uint[uint]))); static assert( hasAliasing!(void delegate())); static assert( hasAliasing!(void delegate() const)); static assert(!hasAliasing!(void delegate() immutable)); static assert( hasAliasing!(void delegate() shared)); static assert( hasAliasing!(void delegate() shared const)); static assert( hasAliasing!(const(void delegate()))); static assert( hasAliasing!(const(void delegate() const))); static assert(!hasAliasing!(const(void delegate() immutable))); static assert( hasAliasing!(const(void delegate() shared))); static assert( hasAliasing!(const(void delegate() shared const))); static assert(!hasAliasing!(immutable(void delegate()))); static assert(!hasAliasing!(immutable(void delegate() const))); static assert(!hasAliasing!(immutable(void delegate() immutable))); static assert(!hasAliasing!(immutable(void delegate() shared))); static assert(!hasAliasing!(immutable(void delegate() shared const))); static assert( hasAliasing!(shared(const(void delegate())))); static assert( hasAliasing!(shared(const(void delegate() const)))); static assert(!hasAliasing!(shared(const(void delegate() immutable)))); static assert( hasAliasing!(shared(const(void delegate() shared)))); static assert( hasAliasing!(shared(const(void delegate() shared const)))); static assert(!hasAliasing!(void function())); interface I; static assert( hasAliasing!I); import std.typecons : Rebindable; static assert( hasAliasing!(Rebindable!(const Object))); static assert(!hasAliasing!(Rebindable!(immutable Object))); static assert( hasAliasing!(Rebindable!(shared Object))); static assert( hasAliasing!(Rebindable!Object)); struct S5 { void delegate() immutable b; shared(void delegate() immutable) f; immutable(void delegate() immutable) j; shared(const(void delegate() immutable)) n; } struct S6 { typeof(S5.tupleof) a; void delegate() p; } static assert(!hasAliasing!S5); static assert( hasAliasing!S6); struct S7 { void delegate() a; int b; Object c; } class S8 { int a; int b; } class S9 { typeof(S8.tupleof) a; } class S10 { typeof(S8.tupleof) a; int* b; } static assert( hasAliasing!S7); static assert( hasAliasing!S8); static assert( hasAliasing!S9); static assert( hasAliasing!S10); struct S11 {} class S12 {} interface S13 {} union S14 {} static assert(!hasAliasing!S11); static assert( hasAliasing!S12); static assert( hasAliasing!S13); static assert(!hasAliasing!S14); } /** Returns $(D true) if and only if $(D T)'s representation includes at least one of the following: $(OL $(LI a raw pointer $(D U*);) $(LI an array $(D U[]);) $(LI a reference to a class type $(D C).) $(LI an associative array.) $(LI a delegate.)) */ template hasIndirections(T) { static if (is(T == struct) || is(T == union)) enum hasIndirections = anySatisfy!(.hasIndirections, FieldTypeTuple!T); else static if (isStaticArray!T && is(T : E[N], E, size_t N)) enum hasIndirections = is(E == void) ? true : hasIndirections!E; else static if (isFunctionPointer!T) enum hasIndirections = false; else enum hasIndirections = isPointer!T || isDelegate!T || isDynamicArray!T || isAssociativeArray!T || is (T == class) || is(T == interface); } /// unittest { static assert( hasIndirections!(int[string])); static assert( hasIndirections!(void delegate())); static assert( hasIndirections!(void delegate() immutable)); static assert( hasIndirections!(immutable(void delegate()))); static assert( hasIndirections!(immutable(void delegate() immutable))); static assert(!hasIndirections!(void function())); static assert( hasIndirections!(void*[1])); static assert(!hasIndirections!(byte[1])); } unittest { // void static array hides actual type of bits, so "may have indirections". static assert( hasIndirections!(void[1])); interface I {} struct S1 {} struct S2 { int a; } struct S3 { int a; int b; } struct S4 { int a; int* b; } struct S5 { int a; Object b; } struct S6 { int a; string b; } struct S7 { int a; immutable Object b; } struct S8 { int a; immutable I b; } struct S9 { int a; void delegate() b; } struct S10 { int a; immutable(void delegate()) b; } struct S11 { int a; void delegate() immutable b; } struct S12 { int a; immutable(void delegate() immutable) b; } class S13 {} class S14 { int a; } class S15 { int a; int b; } class S16 { int a; Object b; } class S17 { string a; } class S18 { int a; immutable Object b; } class S19 { int a; immutable(void delegate() immutable) b; } union S20 {} union S21 { int a; } union S22 { int a; int b; } union S23 { int a; Object b; } union S24 { string a; } union S25 { int a; immutable Object b; } union S26 { int a; immutable(void delegate() immutable) b; } static assert( hasIndirections!I); static assert(!hasIndirections!S1); static assert(!hasIndirections!S2); static assert(!hasIndirections!S3); static assert( hasIndirections!S4); static assert( hasIndirections!S5); static assert( hasIndirections!S6); static assert( hasIndirections!S7); static assert( hasIndirections!S8); static assert( hasIndirections!S9); static assert( hasIndirections!S10); static assert( hasIndirections!S12); static assert( hasIndirections!S13); static assert( hasIndirections!S14); static assert( hasIndirections!S15); static assert( hasIndirections!S16); static assert( hasIndirections!S17); static assert( hasIndirections!S18); static assert( hasIndirections!S19); static assert(!hasIndirections!S20); static assert(!hasIndirections!S21); static assert(!hasIndirections!S22); static assert( hasIndirections!S23); static assert( hasIndirections!S24); static assert( hasIndirections!S25); static assert( hasIndirections!S26); } unittest //12000 { static struct S(T) { static assert(hasIndirections!T); } static class A(T) { S!A a; } A!int dummy; } /** Returns $(D true) if and only if $(D T)'s representation includes at least one of the following: $(OL $(LI a raw pointer $(D U*) and $(D U) is not immutable or shared;) $(LI an array $(D U[]) and $(D U) is not immutable or shared;) $(LI a reference to a class type $(D C) and $(D C) is not immutable or shared.) $(LI an associative array that is not immutable or shared.) $(LI a delegate that is not shared.)) */ template hasUnsharedAliasing(T...) { import std.typecons : Rebindable; static if (!T.length) { enum hasUnsharedAliasing = false; } else static if (is(T[0] R: Rebindable!R)) { enum hasUnsharedAliasing = hasUnsharedAliasing!R; } else { template unsharedDelegate(T) { enum bool unsharedDelegate = isDelegate!T && !is(T == shared) && !is(T == shared) && !is(T == immutable) && !is(FunctionTypeOf!T == shared) && !is(FunctionTypeOf!T == immutable); } enum hasUnsharedAliasing = hasRawUnsharedAliasing!(T[0]) || anySatisfy!(unsharedDelegate, RepresentationTypeTuple!(T[0])) || hasUnsharedObjects!(T[0]) || hasUnsharedAliasing!(T[1..$]); } } /// unittest { struct S1 { int a; Object b; } struct S2 { string a; } struct S3 { int a; immutable Object b; } static assert( hasUnsharedAliasing!S1); static assert(!hasUnsharedAliasing!S2); static assert(!hasUnsharedAliasing!S3); struct S4 { int a; shared Object b; } struct S5 { char[] a; } struct S6 { shared char[] b; } struct S7 { float[3] vals; } static assert(!hasUnsharedAliasing!S4); static assert( hasUnsharedAliasing!S5); static assert(!hasUnsharedAliasing!S6); static assert(!hasUnsharedAliasing!S7); } unittest { /* Issue 6642 */ import std.typecons : Rebindable; struct S8 { int a; Rebindable!(immutable Object) b; } static assert(!hasUnsharedAliasing!S8); static assert( hasUnsharedAliasing!(uint[uint])); static assert( hasUnsharedAliasing!(void delegate())); static assert( hasUnsharedAliasing!(void delegate() const)); static assert(!hasUnsharedAliasing!(void delegate() immutable)); static assert(!hasUnsharedAliasing!(void delegate() shared)); static assert(!hasUnsharedAliasing!(void delegate() shared const)); } unittest { import std.typecons : Rebindable; static assert( hasUnsharedAliasing!(const(void delegate()))); static assert( hasUnsharedAliasing!(const(void delegate() const))); static assert(!hasUnsharedAliasing!(const(void delegate() immutable))); static assert(!hasUnsharedAliasing!(const(void delegate() shared))); static assert(!hasUnsharedAliasing!(const(void delegate() shared const))); static assert(!hasUnsharedAliasing!(immutable(void delegate()))); static assert(!hasUnsharedAliasing!(immutable(void delegate() const))); static assert(!hasUnsharedAliasing!(immutable(void delegate() immutable))); static assert(!hasUnsharedAliasing!(immutable(void delegate() shared))); static assert(!hasUnsharedAliasing!(immutable(void delegate() shared const))); static assert(!hasUnsharedAliasing!(shared(void delegate()))); static assert(!hasUnsharedAliasing!(shared(void delegate() const))); static assert(!hasUnsharedAliasing!(shared(void delegate() immutable))); static assert(!hasUnsharedAliasing!(shared(void delegate() shared))); static assert(!hasUnsharedAliasing!(shared(void delegate() shared const))); static assert(!hasUnsharedAliasing!(shared(const(void delegate())))); static assert(!hasUnsharedAliasing!(shared(const(void delegate() const)))); static assert(!hasUnsharedAliasing!(shared(const(void delegate() immutable)))); static assert(!hasUnsharedAliasing!(shared(const(void delegate() shared)))); static assert(!hasUnsharedAliasing!(shared(const(void delegate() shared const)))); static assert(!hasUnsharedAliasing!(void function())); interface I {} static assert(hasUnsharedAliasing!I); static assert( hasUnsharedAliasing!(Rebindable!(const Object))); static assert(!hasUnsharedAliasing!(Rebindable!(immutable Object))); static assert(!hasUnsharedAliasing!(Rebindable!(shared Object))); static assert( hasUnsharedAliasing!(Rebindable!Object)); /* Issue 6979 */ static assert(!hasUnsharedAliasing!(int, shared(int)*)); static assert( hasUnsharedAliasing!(int, int*)); static assert( hasUnsharedAliasing!(int, const(int)[])); static assert( hasUnsharedAliasing!(int, shared(int)*, Rebindable!Object)); static assert(!hasUnsharedAliasing!(shared(int)*, Rebindable!(shared Object))); static assert(!hasUnsharedAliasing!()); struct S9 { void delegate() shared a; void delegate() immutable b; void delegate() shared const c; shared(void delegate()) d; shared(void delegate() shared) e; shared(void delegate() immutable) f; shared(void delegate() shared const) g; immutable(void delegate()) h; immutable(void delegate() shared) i; immutable(void delegate() immutable) j; immutable(void delegate() shared const) k; shared(const(void delegate())) l; shared(const(void delegate() shared)) m; shared(const(void delegate() immutable)) n; shared(const(void delegate() shared const)) o; } struct S10 { typeof(S9.tupleof) a; void delegate() p; } struct S11 { typeof(S9.tupleof) a; Object p; } struct S12 { typeof(S9.tupleof) a; int* p; } class S13 { typeof(S9.tupleof) a; } class S14 { typeof(S9.tupleof) a; void delegate() p; } class S15 { typeof(S9.tupleof) a; Object p; } class S16 { typeof(S9.tupleof) a; int* p; } static assert(!hasUnsharedAliasing!S9); static assert(!hasUnsharedAliasing!(immutable(S9))); static assert(!hasUnsharedAliasing!(shared(S9))); static assert( hasUnsharedAliasing!S10); static assert(!hasUnsharedAliasing!(immutable(S10))); static assert(!hasUnsharedAliasing!(shared(S10))); static assert( hasUnsharedAliasing!S11); static assert(!hasUnsharedAliasing!(immutable(S11))); static assert(!hasUnsharedAliasing!(shared(S11))); static assert( hasUnsharedAliasing!S12); static assert(!hasUnsharedAliasing!(immutable(S12))); static assert(!hasUnsharedAliasing!(shared(S12))); static assert( hasUnsharedAliasing!S13); static assert(!hasUnsharedAliasing!(immutable(S13))); static assert(!hasUnsharedAliasing!(shared(S13))); static assert( hasUnsharedAliasing!S14); static assert(!hasUnsharedAliasing!(immutable(S14))); static assert(!hasUnsharedAliasing!(shared(S14))); static assert( hasUnsharedAliasing!S15); static assert(!hasUnsharedAliasing!(immutable(S15))); static assert(!hasUnsharedAliasing!(shared(S15))); static assert( hasUnsharedAliasing!S16); static assert(!hasUnsharedAliasing!(immutable(S16))); static assert(!hasUnsharedAliasing!(shared(S16))); struct S17 {} class S18 {} interface S19 {} union S20 {} static assert(!hasUnsharedAliasing!S17); static assert( hasUnsharedAliasing!S18); static assert( hasUnsharedAliasing!S19); static assert(!hasUnsharedAliasing!S20); } /** True if $(D S) or any type embedded directly in the representation of $(D S) defines an elaborate copy constructor. Elaborate copy constructors are introduced by defining $(D this(this)) for a $(D struct). Classes and unions never have elaborate copy constructors. */ template hasElaborateCopyConstructor(S) { static if(isStaticArray!S && S.length) { enum bool hasElaborateCopyConstructor = hasElaborateCopyConstructor!(typeof(S.init[0])); } else static if(is(S == struct)) { enum hasElaborateCopyConstructor = hasMember!(S, "__postblit") || anySatisfy!(.hasElaborateCopyConstructor, FieldTypeTuple!S); } else { enum bool hasElaborateCopyConstructor = false; } } /// unittest { static assert(!hasElaborateCopyConstructor!int); static struct S1 { } static struct S2 { this(this) {} } static struct S3 { S2 field; } static struct S4 { S3[1] field; } static struct S5 { S3[] field; } static struct S6 { S3[0] field; } static struct S7 { @disable this(); S3 field; } static assert(!hasElaborateCopyConstructor!S1); static assert( hasElaborateCopyConstructor!S2); static assert( hasElaborateCopyConstructor!(immutable S2)); static assert( hasElaborateCopyConstructor!S3); static assert( hasElaborateCopyConstructor!(S3[1])); static assert(!hasElaborateCopyConstructor!(S3[0])); static assert( hasElaborateCopyConstructor!S4); static assert(!hasElaborateCopyConstructor!S5); static assert(!hasElaborateCopyConstructor!S6); static assert( hasElaborateCopyConstructor!S7); } /** True if $(D S) or any type directly embedded in the representation of $(D S) defines an elaborate assignment. Elaborate assignments are introduced by defining $(D opAssign(typeof(this))) or $(D opAssign(ref typeof(this))) for a $(D struct) or when there is a compiler-generated $(D opAssign). A type $(D S) gets compiler-generated $(D opAssign) in case it has an elaborate copy constructor or elaborate destructor. Classes and unions never have elaborate assignments. Note: Structs with (possibly nested) postblit operator(s) will have a hidden yet elaborate compiler generated assignment operator (unless explicitly disabled). */ template hasElaborateAssign(S) { static if(isStaticArray!S && S.length) { enum bool hasElaborateAssign = hasElaborateAssign!(typeof(S.init[0])); } else static if(is(S == struct)) { enum hasElaborateAssign = is(typeof(S.init.opAssign(rvalueOf!S))) || is(typeof(S.init.opAssign(lvalueOf!S))) || anySatisfy!(.hasElaborateAssign, FieldTypeTuple!S); } else { enum bool hasElaborateAssign = false; } } /// unittest { static assert(!hasElaborateAssign!int); static struct S { void opAssign(S) {} } static assert( hasElaborateAssign!S); static assert(!hasElaborateAssign!(const(S))); static struct S1 { void opAssign(ref S1) {} } static struct S2 { void opAssign(int) {} } static struct S3 { S s; } static assert( hasElaborateAssign!S1); static assert(!hasElaborateAssign!S2); static assert( hasElaborateAssign!S3); static assert( hasElaborateAssign!(S3[1])); static assert(!hasElaborateAssign!(S3[0])); } unittest { static struct S { void opAssign(S) {} } static struct S4 { void opAssign(U)(U u) {} @disable void opAssign(U)(ref U u); } static assert( hasElaborateAssign!S4); static struct S41 { void opAssign(U)(ref U u) {} @disable void opAssign(U)(U u); } static assert( hasElaborateAssign!S41); static struct S5 { @disable this(); this(int n){ s = S(); } S s; } static assert( hasElaborateAssign!S5); static struct S6 { this(this) {} } static struct S7 { this(this) {} @disable void opAssign(S7); } static struct S8 { this(this) {} @disable void opAssign(S8); void opAssign(int) {} } static struct S9 { this(this) {} void opAssign(int) {} } static struct S10 { ~this() { } } static assert( hasElaborateAssign!S6); static assert(!hasElaborateAssign!S7); static assert(!hasElaborateAssign!S8); static assert( hasElaborateAssign!S9); static assert( hasElaborateAssign!S10); static struct SS6 { S6 s; } static struct SS7 { S7 s; } static struct SS8 { S8 s; } static struct SS9 { S9 s; } static assert( hasElaborateAssign!SS6); static assert( hasElaborateAssign!SS7); static assert( hasElaborateAssign!SS8); static assert( hasElaborateAssign!SS9); } /** True if $(D S) or any type directly embedded in the representation of $(D S) defines an elaborate destructor. Elaborate destructors are introduced by defining $(D ~this()) for a $(D struct). Classes and unions never have elaborate destructors, even though classes may define $(D ~this()). */ template hasElaborateDestructor(S) { static if(isStaticArray!S && S.length) { enum bool hasElaborateDestructor = hasElaborateDestructor!(typeof(S.init[0])); } else static if(is(S == struct)) { enum hasElaborateDestructor = hasMember!(S, "__dtor") || anySatisfy!(.hasElaborateDestructor, FieldTypeTuple!S); } else { enum bool hasElaborateDestructor = false; } } /// unittest { static assert(!hasElaborateDestructor!int); static struct S1 { } static struct S2 { ~this() {} } static struct S3 { S2 field; } static struct S4 { S3[1] field; } static struct S5 { S3[] field; } static struct S6 { S3[0] field; } static struct S7 { @disable this(); S3 field; } static assert(!hasElaborateDestructor!S1); static assert( hasElaborateDestructor!S2); static assert( hasElaborateDestructor!(immutable S2)); static assert( hasElaborateDestructor!S3); static assert( hasElaborateDestructor!(S3[1])); static assert(!hasElaborateDestructor!(S3[0])); static assert( hasElaborateDestructor!S4); static assert(!hasElaborateDestructor!S5); static assert(!hasElaborateDestructor!S6); static assert( hasElaborateDestructor!S7); } alias Identity(alias A) = A; /** Yields $(D true) if and only if $(D T) is an aggregate that defines a symbol called $(D name). */ enum hasMember(T, string name) = __traits(hasMember, T, name); /// unittest { static assert(!hasMember!(int, "blah")); struct S1 { int blah; } struct S2 { int blah(){ return 0; } } class C1 { int blah; } class C2 { int blah(){ return 0; } } static assert(hasMember!(S1, "blah")); static assert(hasMember!(S2, "blah")); static assert(hasMember!(C1, "blah")); static assert(hasMember!(C2, "blah")); } unittest { // 8321 struct S { int x; void f(){} void t()(){} template T(){} } struct R1(T) { T t; alias t this; } struct R2(T) { T t; @property ref inout(T) payload() inout { return t; } alias t this; } static assert(hasMember!(S, "x")); static assert(hasMember!(S, "f")); static assert(hasMember!(S, "t")); static assert(hasMember!(S, "T")); static assert(hasMember!(R1!S, "x")); static assert(hasMember!(R1!S, "f")); static assert(hasMember!(R1!S, "t")); static assert(hasMember!(R1!S, "T")); static assert(hasMember!(R2!S, "x")); static assert(hasMember!(R2!S, "f")); static assert(hasMember!(R2!S, "t")); static assert(hasMember!(R2!S, "T")); } unittest { static struct S { void opDispatch(string n, A)(A dummy) {} } static assert(hasMember!(S, "foo")); } /** Retrieves the members of an enumerated type $(D enum E). Params: E = An enumerated type. $(D E) may have duplicated values. Returns: Static tuple composed of the members of the enumerated type $(D E). The members are arranged in the same order as declared in $(D E). Note: An enum can have multiple members which have the same value. If you want to use EnumMembers to e.g. generate switch cases at compile-time, you should use the $(XREF typetuple, NoDuplicates) template to avoid generating duplicate switch cases. Note: Returned values are strictly typed with $(D E). Thus, the following code does not work without the explicit cast: -------------------- enum E : int { a, b, c } int[] abc = cast(int[]) [ EnumMembers!E ]; -------------------- Cast is not necessary if the type of the variable is inferred. See the example below. Example: Creating an array of enumerated values: -------------------- enum Sqrts : real { one = 1, two = 1.41421, three = 1.73205, } auto sqrts = [ EnumMembers!Sqrts ]; assert(sqrts == [ Sqrts.one, Sqrts.two, Sqrts.three ]); -------------------- A generic function $(D rank(v)) in the following example uses this template for finding a member $(D e) in an enumerated type $(D E). -------------------- // Returns i if e is the i-th enumerator of E. size_t rank(E)(E e) if (is(E == enum)) { foreach (i, member; EnumMembers!E) { if (e == member) return i; } assert(0, "Not an enum member"); } enum Mode { read = 1, write = 2, map = 4, } assert(rank(Mode.read ) == 0); assert(rank(Mode.write) == 1); assert(rank(Mode.map ) == 2); -------------------- */ template EnumMembers(E) if (is(E == enum)) { // Supply the specified identifier to an constant value. template WithIdentifier(string ident) { static if (ident == "Symbolize") { template Symbolize(alias value) { enum Symbolize = value; } } else { mixin("template Symbolize(alias "~ ident ~")" ~"{" ~"alias Symbolize = "~ ident ~";" ~"}"); } } template EnumSpecificMembers(names...) { static if (names.length > 0) { alias EnumSpecificMembers = TypeTuple!( WithIdentifier!(names[0]) .Symbolize!(__traits(getMember, E, names[0])), EnumSpecificMembers!(names[1 .. $]) ); } else { alias EnumSpecificMembers = TypeTuple!(); } } alias EnumMembers = EnumSpecificMembers!(__traits(allMembers, E)); } unittest { enum A { a } static assert([ EnumMembers!A ] == [ A.a ]); enum B { a, b, c, d, e } static assert([ EnumMembers!B ] == [ B.a, B.b, B.c, B.d, B.e ]); } unittest // typed enums { enum A : string { a = "alpha", b = "beta" } static assert([ EnumMembers!A ] == [ A.a, A.b ]); static struct S { int value; int opCmp(S rhs) const nothrow { return value - rhs.value; } } enum B : S { a = S(1), b = S(2), c = S(3) } static assert([ EnumMembers!B ] == [ B.a, B.b, B.c ]); } unittest // duplicated values { enum A { a = 0, b = 0, c = 1, d = 1, e } static assert([ EnumMembers!A ] == [ A.a, A.b, A.c, A.d, A.e ]); } unittest { enum E { member, a = 0, b = 0 } static assert(__traits(identifier, EnumMembers!E[0]) == "member"); static assert(__traits(identifier, EnumMembers!E[1]) == "a"); static assert(__traits(identifier, EnumMembers!E[2]) == "b"); } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Classes and Interfaces //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// /*** * Get a $(D_PARAM TypeTuple) of the base class and base interfaces of * this class or interface. $(D_PARAM BaseTypeTuple!Object) returns * the empty type tuple. */ template BaseTypeTuple(A) { static if (is(A P == super)) alias BaseTypeTuple = P; else static assert(0, "argument is not a class or interface"); } /// unittest { interface I1 { } interface I2 { } interface I12 : I1, I2 { } static assert(is(BaseTypeTuple!I12 == TypeTuple!(I1, I2))); interface I3 : I1 { } interface I123 : I1, I2, I3 { } static assert(is(BaseTypeTuple!I123 == TypeTuple!(I1, I2, I3))); } unittest { interface I1 { } interface I2 { } class A { } class C : A, I1, I2 { } alias TL = BaseTypeTuple!C; assert(TL.length == 3); assert(is (TL[0] == A)); assert(is (TL[1] == I1)); assert(is (TL[2] == I2)); assert(BaseTypeTuple!Object.length == 0); } /** * Get a $(D_PARAM TypeTuple) of $(I all) base classes of this class, * in decreasing order. Interfaces are not included. $(D_PARAM * BaseClassesTuple!Object) yields the empty type tuple. */ template BaseClassesTuple(T) if (is(T == class)) { static if (is(T == Object)) { alias BaseClassesTuple = TypeTuple!(); } else static if (is(BaseTypeTuple!T[0] == Object)) { alias BaseClassesTuple = TypeTuple!Object; } else { alias BaseClassesTuple = TypeTuple!(BaseTypeTuple!T[0], BaseClassesTuple!(BaseTypeTuple!T[0])); } } /// unittest { class C1 { } class C2 : C1 { } class C3 : C2 { } static assert(!BaseClassesTuple!Object.length); static assert(is(BaseClassesTuple!C1 == TypeTuple!(Object))); static assert(is(BaseClassesTuple!C2 == TypeTuple!(C1, Object))); static assert(is(BaseClassesTuple!C3 == TypeTuple!(C2, C1, Object))); } unittest { struct S { } static assert(!__traits(compiles, BaseClassesTuple!S)); interface I { } static assert(!__traits(compiles, BaseClassesTuple!I)); class C4 : I { } class C5 : C4, I { } static assert(is(BaseClassesTuple!C5 == TypeTuple!(C4, Object))); } /** * Get a $(D_PARAM TypeTuple) of $(I all) interfaces directly or * indirectly inherited by this class or interface. Interfaces do not * repeat if multiply implemented. $(D_PARAM InterfacesTuple!Object) * yields the empty type tuple. */ template InterfacesTuple(T) { template Flatten(H, T...) { static if (T.length) { alias Flatten = TypeTuple!(Flatten!H, Flatten!T); } else { static if (is(H == interface)) alias Flatten = TypeTuple!(H, InterfacesTuple!H); else alias Flatten = InterfacesTuple!H; } } static if (is(T S == super) && S.length) alias InterfacesTuple = NoDuplicates!(Flatten!S); else alias InterfacesTuple = TypeTuple!(); } unittest { // doc example interface I1 {} interface I2 {} class A : I1, I2 { } class B : A, I1 { } class C : B { } alias TL = InterfacesTuple!C; static assert(is(TL[0] == I1) && is(TL[1] == I2)); } unittest { interface Iaa {} interface Iab {} interface Iba {} interface Ibb {} interface Ia : Iaa, Iab {} interface Ib : Iba, Ibb {} interface I : Ia, Ib {} interface J {} class B2 : J {} class C2 : B2, Ia, Ib {} static assert(is(InterfacesTuple!I == TypeTuple!(Ia, Iaa, Iab, Ib, Iba, Ibb))); static assert(is(InterfacesTuple!C2 == TypeTuple!(J, Ia, Iaa, Iab, Ib, Iba, Ibb))); } /** * Get a $(D_PARAM TypeTuple) of $(I all) base classes of $(D_PARAM * T), in decreasing order, followed by $(D_PARAM T)'s * interfaces. $(D_PARAM TransitiveBaseTypeTuple!Object) yields the * empty type tuple. */ template TransitiveBaseTypeTuple(T) { static if (is(T == Object)) alias TransitiveBaseTypeTuple = TypeTuple!(); else alias TransitiveBaseTypeTuple = TypeTuple!(BaseClassesTuple!T, InterfacesTuple!T); } /// unittest { interface J1 {} interface J2 {} class B1 {} class B2 : B1, J1, J2 {} class B3 : B2, J1 {} alias TL = TransitiveBaseTypeTuple!B3; assert(TL.length == 5); assert(is (TL[0] == B2)); assert(is (TL[1] == B1)); assert(is (TL[2] == Object)); assert(is (TL[3] == J1)); assert(is (TL[4] == J2)); assert(TransitiveBaseTypeTuple!Object.length == 0); } /** Returns a tuple of non-static functions with the name $(D name) declared in the class or interface $(D C). Covariant duplicates are shrunk into the most derived one. */ template MemberFunctionsTuple(C, string name) if (is(C == class) || is(C == interface)) { static if (__traits(hasMember, C, name)) { /* * First, collect all overloads in the class hierarchy. */ template CollectOverloads(Node) { static if (__traits(hasMember, Node, name) && __traits(compiles, __traits(getMember, Node, name))) { // Get all overloads in sight (not hidden). alias inSight = TypeTuple!(__traits(getVirtualFunctions, Node, name)); // And collect all overloads in ancestor classes to reveal hidden // methods. The result may contain duplicates. template walkThru(Parents...) { static if (Parents.length > 0) alias walkThru = TypeTuple!( CollectOverloads!(Parents[0]), walkThru!(Parents[1 .. $]) ); else alias walkThru = TypeTuple!(); } static if (is(Node Parents == super)) alias CollectOverloads = TypeTuple!(inSight, walkThru!Parents); else alias CollectOverloads = TypeTuple!inSight; } else alias CollectOverloads = TypeTuple!(); // no overloads in this hierarchy } // duplicates in this tuple will be removed by shrink() alias overloads = CollectOverloads!C; // shrinkOne!args[0] = the most derived one in the covariant siblings of target // shrinkOne!args[1..$] = non-covariant others template shrinkOne(/+ alias target, rest... +/ args...) { alias target = args[0 .. 1]; // prevent property functions from being evaluated alias rest = args[1 .. $]; static if (rest.length > 0) { alias Target = FunctionTypeOf!target; alias Rest0 = FunctionTypeOf!(rest[0]); static if (isCovariantWith!(Target, Rest0)) // target overrides rest[0] -- erase rest[0]. alias shrinkOne = shrinkOne!(target, rest[1 .. $]); else static if (isCovariantWith!(Rest0, Target)) // rest[0] overrides target -- erase target. alias shrinkOne = shrinkOne!(rest[0], rest[1 .. $]); else // target and rest[0] are distinct. alias shrinkOne = TypeTuple!( shrinkOne!(target, rest[1 .. $]), rest[0] // keep ); } else alias shrinkOne = TypeTuple!target; // done } /* * Now shrink covariant overloads into one. */ template shrink(overloads...) { static if (overloads.length > 0) { alias temp = shrinkOne!overloads; alias shrink = TypeTuple!(temp[0], shrink!(temp[1 .. $])); } else alias shrink = TypeTuple!(); // done } // done. alias MemberFunctionsTuple = shrink!overloads; } else alias MemberFunctionsTuple = TypeTuple!(); } /// unittest { interface I { I foo(); } class B { real foo(real v) { return v; } } class C : B, I { override C foo() { return this; } // covariant overriding of I.foo() } alias foos = MemberFunctionsTuple!(C, "foo"); static assert(foos.length == 2); static assert(__traits(isSame, foos[0], C.foo)); static assert(__traits(isSame, foos[1], B.foo)); } unittest { interface I { I test(); } interface J : I { J test(); } interface K { K test(int); } class B : I, K { K test(int) { return this; } B test() { return this; } static void test(string) { } } class C : B, J { override C test() { return this; } } alias test =MemberFunctionsTuple!(C, "test"); static assert(test.length == 2); static assert(is(FunctionTypeOf!(test[0]) == FunctionTypeOf!(C.test))); static assert(is(FunctionTypeOf!(test[1]) == FunctionTypeOf!(K.test))); alias noexist = MemberFunctionsTuple!(C, "noexist"); static assert(noexist.length == 0); interface L { int prop() @property; } alias prop = MemberFunctionsTuple!(L, "prop"); static assert(prop.length == 1); interface Test_I { void foo(); void foo(int); void foo(int, int); } interface Test : Test_I {} alias Test_foo = MemberFunctionsTuple!(Test, "foo"); static assert(Test_foo.length == 3); static assert(is(typeof(&Test_foo[0]) == void function())); static assert(is(typeof(&Test_foo[2]) == void function(int))); static assert(is(typeof(&Test_foo[1]) == void function(int, int))); } /** Returns an alias to the template that $(D T) is an instance of. */ template TemplateOf(alias T : Base!Args, alias Base, Args...) { alias TemplateOf = Base; } /// ditto template TemplateOf(T : Base!Args, alias Base, Args...) { alias TemplateOf = Base; } /// unittest { struct Foo(T, U) {} static assert(__traits(isSame, TemplateOf!(Foo!(int, real)), Foo)); } unittest { template Foo1(A) {} template Foo2(A, B) {} template Foo3(alias A) {} template Foo4(string A) {} struct Foo5(A) {} struct Foo6(A, B) {} struct Foo7(alias A) {} template Foo8(A) { template Foo9(B) {} } template Foo10() {} static assert(__traits(isSame, TemplateOf!(Foo1!(int)), Foo1)); static assert(__traits(isSame, TemplateOf!(Foo2!(int, int)), Foo2)); static assert(__traits(isSame, TemplateOf!(Foo3!(123)), Foo3)); static assert(__traits(isSame, TemplateOf!(Foo4!("123")), Foo4)); static assert(__traits(isSame, TemplateOf!(Foo5!(int)), Foo5)); static assert(__traits(isSame, TemplateOf!(Foo6!(int, int)), Foo6)); static assert(__traits(isSame, TemplateOf!(Foo7!(123)), Foo7)); static assert(__traits(isSame, TemplateOf!(Foo8!(int).Foo9!(real)), Foo8!(int).Foo9)); static assert(__traits(isSame, TemplateOf!(Foo10!()), Foo10)); } /** Returns a $(D TypeTuple) of the template arguments used to instantiate $(D T). */ template TemplateArgsOf(alias T : Base!Args, alias Base, Args...) { alias TemplateArgsOf = Args; } /// ditto template TemplateArgsOf(T : Base!Args, alias Base, Args...) { alias TemplateArgsOf = Args; } /// unittest { struct Foo(T, U) {} static assert(is(TemplateArgsOf!(Foo!(int, real)) == TypeTuple!(int, real))); } unittest { template Foo1(A) {} template Foo2(A, B) {} template Foo3(alias A) {} template Foo4(string A) {} struct Foo5(A) {} struct Foo6(A, B) {} struct Foo7(alias A) {} template Foo8(A) { template Foo9(B) {} } template Foo10() {} enum x = 123; enum y = "123"; static assert(is(TemplateArgsOf!(Foo1!(int)) == TypeTuple!(int))); static assert(is(TemplateArgsOf!(Foo2!(int, int)) == TypeTuple!(int, int))); static assert(__traits(isSame, TemplateArgsOf!(Foo3!(x)), TypeTuple!(x))); static assert(TemplateArgsOf!(Foo4!(y)) == TypeTuple!(y)); static assert(is(TemplateArgsOf!(Foo5!(int)) == TypeTuple!(int))); static assert(is(TemplateArgsOf!(Foo6!(int, int)) == TypeTuple!(int, int))); static assert(__traits(isSame, TemplateArgsOf!(Foo7!(x)), TypeTuple!(x))); static assert(is(TemplateArgsOf!(Foo8!(int).Foo9!(real)) == TypeTuple!(real))); static assert(is(TemplateArgsOf!(Foo10!()) == TypeTuple!())); } private template maxAlignment(U...) if (isTypeTuple!U) { static if (U.length == 0) static assert(0); else static if (U.length == 1) enum maxAlignment = U[0].alignof; else { import std.algorithm : max; enum maxAlignment = max(staticMap!(.maxAlignment, U)); } } /** Returns class instance alignment. */ template classInstanceAlignment(T) if(is(T == class)) { alias classInstanceAlignment = maxAlignment!(void*, typeof(T.tupleof)); } /// unittest { class A { byte b; } class B { long l; } // As class instance always has a hidden pointer static assert(classInstanceAlignment!A == (void*).alignof); static assert(classInstanceAlignment!B == long.alignof); } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Type Conversion //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// /** Get the type that all types can be implicitly converted to. Useful e.g. in figuring out an array type from a bunch of initializing values. Returns $(D_PARAM void) if passed an empty list, or if the types have no common type. */ template CommonType(T...) { static if (!T.length) { alias CommonType = void; } else static if (T.length == 1) { static if(is(typeof(T[0]))) { alias CommonType = typeof(T[0]); } else { alias CommonType = T[0]; } } else static if (is(typeof(true ? T[0].init : T[1].init) U)) { alias CommonType = CommonType!(U, T[2 .. $]); } else alias CommonType = void; } /// unittest { alias X = CommonType!(int, long, short); assert(is(X == long)); alias Y = CommonType!(int, char[], short); assert(is(Y == void)); } unittest { static assert(is(CommonType!(3) == int)); static assert(is(CommonType!(double, 4, float) == double)); static assert(is(CommonType!(string, char[]) == const(char)[])); static assert(is(CommonType!(3, 3U) == uint)); } /** * Returns a tuple with all possible target types of an implicit * conversion of a value of type $(D_PARAM T). * * Important note: * * The possible targets are computed more conservatively than the D * 2.005 compiler does, eliminating all dangerous conversions. For * example, $(D_PARAM ImplicitConversionTargets!double) does not * include $(D_PARAM float). */ template ImplicitConversionTargets(T) { static if (is(T == bool)) alias ImplicitConversionTargets = TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, CentTypeList, float, double, real, char, wchar, dchar); else static if (is(T == byte)) alias ImplicitConversionTargets = TypeTuple!(short, ushort, int, uint, long, ulong, CentTypeList, float, double, real, char, wchar, dchar); else static if (is(T == ubyte)) alias ImplicitConversionTargets = TypeTuple!(short, ushort, int, uint, long, ulong, CentTypeList, float, double, real, char, wchar, dchar); else static if (is(T == short)) alias ImplicitConversionTargets = TypeTuple!(int, uint, long, ulong, CentTypeList, float, double, real); else static if (is(T == ushort)) alias ImplicitConversionTargets = TypeTuple!(int, uint, long, ulong, CentTypeList, float, double, real); else static if (is(T == int)) alias ImplicitConversionTargets = TypeTuple!(long, ulong, CentTypeList, float, double, real); else static if (is(T == uint)) alias ImplicitConversionTargets = TypeTuple!(long, ulong, CentTypeList, float, double, real); else static if (is(T == long)) alias ImplicitConversionTargets = TypeTuple!(float, double, real); else static if (is(T == ulong)) alias ImplicitConversionTargets = TypeTuple!(float, double, real); else static if (is(cent) && is(T == cent)) alias ImplicitConversionTargets = TypeTuple!(float, double, real); else static if (is(ucent) && is(T == ucent)) alias ImplicitConversionTargets = TypeTuple!(float, double, real); else static if (is(T == float)) alias ImplicitConversionTargets = TypeTuple!(double, real); else static if (is(T == double)) alias ImplicitConversionTargets = TypeTuple!real; else static if (is(T == char)) alias ImplicitConversionTargets = TypeTuple!(wchar, dchar, byte, ubyte, short, ushort, int, uint, long, ulong, CentTypeList, float, double, real); else static if (is(T == wchar)) alias ImplicitConversionTargets = TypeTuple!(dchar, short, ushort, int, uint, long, ulong, CentTypeList, float, double, real); else static if (is(T == dchar)) alias ImplicitConversionTargets = TypeTuple!(int, uint, long, ulong, CentTypeList, float, double, real); else static if (is(T : typeof(null))) alias ImplicitConversionTargets = TypeTuple!(typeof(null)); else static if(is(T : Object)) alias ImplicitConversionTargets = TransitiveBaseTypeTuple!(T); else static if (isDynamicArray!T && !is(typeof(T.init[0]) == const)) alias ImplicitConversionTargets = TypeTuple!(const(Unqual!(typeof(T.init[0])))[]); else static if (is(T : void*)) alias ImplicitConversionTargets = TypeTuple!(void*); else alias ImplicitConversionTargets = TypeTuple!(); } unittest { static assert(is(ImplicitConversionTargets!(double)[0] == real)); static assert(is(ImplicitConversionTargets!(string)[0] == const(char)[])); } /** Is $(D From) implicitly convertible to $(D To)? */ template isImplicitlyConvertible(From, To) { enum bool isImplicitlyConvertible = is(typeof({ void fun(ref From v) { void gun(To) {} gun(v); } })); } unittest { static assert( isImplicitlyConvertible!(immutable(char), char)); static assert( isImplicitlyConvertible!(const(char), char)); static assert( isImplicitlyConvertible!(char, wchar)); static assert(!isImplicitlyConvertible!(wchar, char)); // bug6197 static assert(!isImplicitlyConvertible!(const(ushort), ubyte)); static assert(!isImplicitlyConvertible!(const(uint), ubyte)); static assert(!isImplicitlyConvertible!(const(ulong), ubyte)); // from std.conv.implicitlyConverts assert(!isImplicitlyConvertible!(const(char)[], string)); assert( isImplicitlyConvertible!(string, const(char)[])); } /** Returns $(D true) iff a value of type $(D Rhs) can be assigned to a variable of type $(D Lhs). $(D isAssignable) returns whether both an lvalue and rvalue can be assigned. If you omit $(D Rhs), $(D isAssignable) will check identity assignable of $(D Lhs). */ enum isAssignable(Lhs, Rhs = Lhs) = isRvalueAssignable!(Lhs, Rhs) && isLvalueAssignable!(Lhs, Rhs); /// unittest { static assert( isAssignable!(long, int)); static assert(!isAssignable!(int, long)); static assert( isAssignable!(const(char)[], string)); static assert(!isAssignable!(string, char[])); // int is assignable to int static assert( isAssignable!int); // immutable int is not assignable to immutable int static assert(!isAssignable!(immutable int)); } // ditto private enum isRvalueAssignable(Lhs, Rhs = Lhs) = __traits(compiles, lvalueOf!Lhs = rvalueOf!Rhs); // ditto private enum isLvalueAssignable(Lhs, Rhs = Lhs) = __traits(compiles, lvalueOf!Lhs = lvalueOf!Rhs); unittest { static assert(!isAssignable!(immutable int, int)); static assert( isAssignable!(int, immutable int)); static assert(!isAssignable!(inout int, int)); static assert( isAssignable!(int, inout int)); static assert(!isAssignable!(inout int)); static assert( isAssignable!(shared int, int)); static assert( isAssignable!(int, shared int)); static assert( isAssignable!(shared int)); static assert( isAssignable!(void[1], void[1])); struct S { @disable this(); this(int n){} } static assert( isAssignable!(S, S)); struct S2 { this(int n){} } static assert( isAssignable!(S2, S2)); static assert(!isAssignable!(S2, int)); struct S3 { @disable void opAssign(); } static assert( isAssignable!(S3, S3)); struct S3X { @disable void opAssign(S3X); } static assert(!isAssignable!(S3X, S3X)); struct S4 { void opAssign(int); } static assert( isAssignable!(S4, S4)); static assert( isAssignable!(S4, int)); static assert( isAssignable!(S4, immutable int)); struct S5 { @disable this(); @disable this(this); } struct S6 { void opAssign(in ref S5); } static assert(!isAssignable!(S6, S5)); static assert(!isRvalueAssignable!(S6, S5)); static assert( isLvalueAssignable!(S6, S5)); static assert( isLvalueAssignable!(S6, immutable S5)); } // Equivalent with TypeStruct::isAssignable in compiler code. package template isBlitAssignable(T) { static if (is(OriginalType!T U) && !is(T == U)) { enum isBlitAssignable = isBlitAssignable!U; } else static if (isStaticArray!T && is(T == E[n], E, size_t n)) // Workaround for issue 11499 : isStaticArray!T should not be necessary. { enum isBlitAssignable = isBlitAssignable!E; } else static if (is(T == struct) || is(T == union)) { enum isBlitAssignable = isMutable!T && { size_t offset = 0; bool assignable = true; foreach (i, F; FieldTypeTuple!T) { static if (i == 0) { } else if (T.tupleof[i].offsetof == offset) { if (assignable) continue; } else { if (!assignable) return false; } assignable = isBlitAssignable!(typeof(T.tupleof[i])); offset = T.tupleof[i].offsetof; } return assignable; }(); } else enum isBlitAssignable = isMutable!T; } unittest { static assert( isBlitAssignable!int); static assert(!isBlitAssignable!(const int)); class C{ const int i; } static assert( isBlitAssignable!C); struct S1{ int i; } struct S2{ const int i; } static assert( isBlitAssignable!S1); static assert(!isBlitAssignable!S2); struct S3X { union { int x; int y; } } struct S3Y { union { int x; const int y; } } struct S3Z { union { const int x; const int y; } } static assert( isBlitAssignable!(S3X)); static assert( isBlitAssignable!(S3Y)); static assert(!isBlitAssignable!(S3Z)); static assert(!isBlitAssignable!(const S3X)); static assert(!isBlitAssignable!(inout S3Y)); static assert(!isBlitAssignable!(immutable S3Z)); static assert( isBlitAssignable!(S3X[3])); static assert( isBlitAssignable!(S3Y[3])); static assert(!isBlitAssignable!(S3Z[3])); enum ES3X : S3X { a = S3X() } enum ES3Y : S3Y { a = S3Y() } enum ES3Z : S3Z { a = S3Z() } static assert( isBlitAssignable!(ES3X)); static assert( isBlitAssignable!(ES3Y)); static assert(!isBlitAssignable!(ES3Z)); static assert(!isBlitAssignable!(const ES3X)); static assert(!isBlitAssignable!(inout ES3Y)); static assert(!isBlitAssignable!(immutable ES3Z)); static assert( isBlitAssignable!(ES3X[3])); static assert( isBlitAssignable!(ES3Y[3])); static assert(!isBlitAssignable!(ES3Z[3])); union U1X { int x; int y; } union U1Y { int x; const int y; } union U1Z { const int x; const int y; } static assert( isBlitAssignable!(U1X)); static assert( isBlitAssignable!(U1Y)); static assert(!isBlitAssignable!(U1Z)); static assert(!isBlitAssignable!(const U1X)); static assert(!isBlitAssignable!(inout U1Y)); static assert(!isBlitAssignable!(immutable U1Z)); static assert( isBlitAssignable!(U1X[3])); static assert( isBlitAssignable!(U1Y[3])); static assert(!isBlitAssignable!(U1Z[3])); enum EU1X : U1X { a = U1X() } enum EU1Y : U1Y { a = U1Y() } enum EU1Z : U1Z { a = U1Z() } static assert( isBlitAssignable!(EU1X)); static assert( isBlitAssignable!(EU1Y)); static assert(!isBlitAssignable!(EU1Z)); static assert(!isBlitAssignable!(const EU1X)); static assert(!isBlitAssignable!(inout EU1Y)); static assert(!isBlitAssignable!(immutable EU1Z)); static assert( isBlitAssignable!(EU1X[3])); static assert( isBlitAssignable!(EU1Y[3])); static assert(!isBlitAssignable!(EU1Z[3])); struct SA { @property int[3] foo() { return [1,2,3]; } alias foo this; const int x; // SA is not blit assignable } static assert(!isStaticArray!SA); static assert(!isBlitAssignable!(SA[3])); } /* Works like $(D isImplicitlyConvertible), except this cares only about storage classes of the arguments. */ private template isStorageClassImplicitlyConvertible(From, To) { alias Pointify(T) = void*; enum isStorageClassImplicitlyConvertible = isImplicitlyConvertible!( ModifyTypePreservingTQ!(Pointify, From), ModifyTypePreservingTQ!(Pointify, To) ); } unittest { static assert( isStorageClassImplicitlyConvertible!( int, const int)); static assert( isStorageClassImplicitlyConvertible!(immutable int, const int)); static assert(!isStorageClassImplicitlyConvertible!(const int, int)); static assert(!isStorageClassImplicitlyConvertible!(const int, immutable int)); static assert(!isStorageClassImplicitlyConvertible!(int, shared int)); static assert(!isStorageClassImplicitlyConvertible!(shared int, int)); } /** Determines whether the function type $(D F) is covariant with $(D G), i.e., functions of the type $(D F) can override ones of the type $(D G). */ template isCovariantWith(F, G) if (is(F == function) && is(G == function)) { static if (is(F : G)) enum isCovariantWith = true; else { alias Upr = F; alias Lwr = G; /* * Check for calling convention: require exact match. */ template checkLinkage() { enum ok = functionLinkage!Upr == functionLinkage!Lwr; } /* * Check for variadic parameter: require exact match. */ template checkVariadicity() { enum ok = variadicFunctionStyle!Upr == variadicFunctionStyle!Lwr; } /* * Check for function storage class: * - overrider can have narrower storage class than base */ template checkSTC() { // Note the order of arguments. The convertion order Lwr -> Upr is // correct since Upr should be semantically 'narrower' than Lwr. enum ok = isStorageClassImplicitlyConvertible!(Lwr, Upr); } /* * Check for function attributes: * - require exact match for ref and @property * - overrider can add pure and nothrow, but can't remove them * - @safe and @trusted are covariant with each other, unremovable */ template checkAttributes() { alias FA = FunctionAttribute; enum uprAtts = functionAttributes!Upr; enum lwrAtts = functionAttributes!Lwr; // enum wantExact = FA.ref_ | FA.property; enum safety = FA.safe | FA.trusted; enum ok = ( (uprAtts & wantExact) == (lwrAtts & wantExact)) && ( (uprAtts & FA.pure_ ) >= (lwrAtts & FA.pure_ )) && ( (uprAtts & FA.nothrow_) >= (lwrAtts & FA.nothrow_)) && (!!(uprAtts & safety ) >= !!(lwrAtts & safety )) ; } /* * Check for return type: usual implicit convertion. */ template checkReturnType() { enum ok = is(ReturnType!Upr : ReturnType!Lwr); } /* * Check for parameters: * - require exact match for types (cf. bugzilla 3075) * - require exact match for in, out, ref and lazy * - overrider can add scope, but can't remove */ template checkParameters() { alias STC = ParameterStorageClass; alias UprParams = Parameters!Upr; alias LwrParams = Parameters!Lwr; alias UprPSTCs = ParameterStorageClassTuple!Upr; alias LwrPSTCs = ParameterStorageClassTuple!Lwr; // template checkNext(size_t i) { static if (i < UprParams.length) { enum uprStc = UprPSTCs[i]; enum lwrStc = LwrPSTCs[i]; // enum wantExact = STC.out_ | STC.ref_ | STC.lazy_ | STC.return_; enum ok = ((uprStc & wantExact ) == (lwrStc & wantExact )) && ((uprStc & STC.scope_) >= (lwrStc & STC.scope_)) && checkNext!(i + 1).ok; } else enum ok = true; // done } static if (UprParams.length == LwrParams.length) enum ok = is(UprParams == LwrParams) && checkNext!(0).ok; else enum ok = false; } /* run all the checks */ enum isCovariantWith = checkLinkage !().ok && checkVariadicity!().ok && checkSTC !().ok && checkAttributes !().ok && checkReturnType !().ok && checkParameters !().ok ; } } /// unittest { interface I { I clone(); } interface J { J clone(); } class C : I { override C clone() // covariant overriding of I.clone() { return new C; } } // C.clone() can override I.clone(), indeed. static assert(isCovariantWith!(typeof(C.clone), typeof(I.clone))); // C.clone() can't override J.clone(); the return type C is not implicitly // convertible to J. static assert(!isCovariantWith!(typeof(C.clone), typeof(J.clone))); } unittest { enum bool isCovariantWith(alias f, alias g) = .isCovariantWith!(typeof(f), typeof(g)); // covariant return type interface I {} interface J : I {} interface BaseA { const(I) test(int); } interface DerivA_1 : BaseA { override const(J) test(int); } interface DerivA_2 : BaseA { override J test(int); } static assert( isCovariantWith!(DerivA_1.test, BaseA.test)); static assert( isCovariantWith!(DerivA_2.test, BaseA.test)); static assert(!isCovariantWith!(BaseA.test, DerivA_1.test)); static assert(!isCovariantWith!(BaseA.test, DerivA_2.test)); static assert( isCovariantWith!(BaseA.test, BaseA.test)); static assert( isCovariantWith!(DerivA_1.test, DerivA_1.test)); static assert( isCovariantWith!(DerivA_2.test, DerivA_2.test)); // scope parameter interface BaseB { void test( int, int); } interface DerivB_1 : BaseB { override void test(scope int, int); } interface DerivB_2 : BaseB { override void test( int, scope int); } interface DerivB_3 : BaseB { override void test(scope int, scope int); } static assert( isCovariantWith!(DerivB_1.test, BaseB.test)); static assert( isCovariantWith!(DerivB_2.test, BaseB.test)); static assert( isCovariantWith!(DerivB_3.test, BaseB.test)); static assert(!isCovariantWith!(BaseB.test, DerivB_1.test)); static assert(!isCovariantWith!(BaseB.test, DerivB_2.test)); static assert(!isCovariantWith!(BaseB.test, DerivB_3.test)); // function storage class interface BaseC { void test() ; } interface DerivC_1 : BaseC { override void test() const; } static assert( isCovariantWith!(DerivC_1.test, BaseC.test)); static assert(!isCovariantWith!(BaseC.test, DerivC_1.test)); // increasing safety interface BaseE { void test() ; } interface DerivE_1 : BaseE { override void test() @safe ; } interface DerivE_2 : BaseE { override void test() @trusted; } static assert( isCovariantWith!(DerivE_1.test, BaseE.test)); static assert( isCovariantWith!(DerivE_2.test, BaseE.test)); static assert(!isCovariantWith!(BaseE.test, DerivE_1.test)); static assert(!isCovariantWith!(BaseE.test, DerivE_2.test)); // @safe and @trusted interface BaseF { void test1() @safe; void test2() @trusted; } interface DerivF : BaseF { override void test1() @trusted; override void test2() @safe; } static assert( isCovariantWith!(DerivF.test1, BaseF.test1)); static assert( isCovariantWith!(DerivF.test2, BaseF.test2)); } // Needed for rvalueOf/lvalueOf because "inout on return means // inout must be on a parameter as well" private struct __InoutWorkaroundStruct{} /** Creates an lvalue or rvalue of type $(D T) for $(D typeof(...)) and $(D __traits(compiles, ...)) purposes. No actual value is returned. Note: Trying to use returned value will result in a "Symbol Undefined" error at link time. Example: --- // Note that `f` doesn't have to be implemented // as is isn't called. int f(int); bool f(ref int); static assert(is(typeof(f(rvalueOf!int)) == int)); static assert(is(typeof(f(lvalueOf!int)) == bool)); int i = rvalueOf!int; // error, no actual value is returned --- */ @property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init); /// ditto @property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init); // Note: unittest can't be used as an example here as function overloads // aren't allowed inside functions. unittest { void needLvalue(T)(ref T); static struct S { } int i; struct Nested { void f() { ++i; } } foreach(T; TypeTuple!(int, immutable int, inout int, string, S, Nested, Object)) { static assert(!__traits(compiles, needLvalue(rvalueOf!T))); static assert( __traits(compiles, needLvalue(lvalueOf!T))); static assert(is(typeof(rvalueOf!T) == T)); static assert(is(typeof(lvalueOf!T) == T)); } static assert(!__traits(compiles, rvalueOf!int = 1)); static assert( __traits(compiles, lvalueOf!byte = 127)); static assert(!__traits(compiles, lvalueOf!byte = 128)); } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // SomethingTypeOf //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// private template AliasThisTypeOf(T) if (isAggregateType!T) { alias members = TypeTuple!(__traits(getAliasThis, T)); static if (members.length == 1) { alias AliasThisTypeOf = typeof(__traits(getMember, T.init, members[0])); } else static assert(0, T.stringof~" does not have alias this type"); } /* */ template BooleanTypeOf(T) { static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT)) alias X = BooleanTypeOf!AT; else alias X = OriginalType!T; static if (is(Unqual!X == bool)) { alias BooleanTypeOf = X; } else static assert(0, T.stringof~" is not boolean type"); } unittest { // unexpected failure, maybe dmd type-merging bug foreach (T; TypeTuple!bool) foreach (Q; TypeQualifierList) { static assert( is(Q!T == BooleanTypeOf!( Q!T ))); static assert( is(Q!T == BooleanTypeOf!( SubTypeOf!(Q!T) ))); } foreach (T; TypeTuple!(void, NumericTypeList, ImaginaryTypeList, ComplexTypeList, CharTypeList)) foreach (Q; TypeQualifierList) { static assert(!is(BooleanTypeOf!( Q!T )), Q!T.stringof); static assert(!is(BooleanTypeOf!( SubTypeOf!(Q!T) ))); } } unittest { struct B { bool val; alias val this; } struct S { B b; alias b this; } static assert(is(BooleanTypeOf!B == bool)); static assert(is(BooleanTypeOf!S == bool)); } /* */ template IntegralTypeOf(T) { static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT)) alias X = IntegralTypeOf!AT; else alias X = OriginalType!T; static if (staticIndexOf!(Unqual!X, IntegralTypeList) >= 0) { alias IntegralTypeOf = X; } else static assert(0, T.stringof~" is not an integral type"); } unittest { foreach (T; IntegralTypeList) foreach (Q; TypeQualifierList) { static assert( is(Q!T == IntegralTypeOf!( Q!T ))); static assert( is(Q!T == IntegralTypeOf!( SubTypeOf!(Q!T) ))); } foreach (T; TypeTuple!(void, bool, FloatingPointTypeList, ImaginaryTypeList, ComplexTypeList, CharTypeList)) foreach (Q; TypeQualifierList) { static assert(!is(IntegralTypeOf!( Q!T ))); static assert(!is(IntegralTypeOf!( SubTypeOf!(Q!T) ))); } } /* */ template FloatingPointTypeOf(T) { static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT)) alias X = FloatingPointTypeOf!AT; else alias X = OriginalType!T; static if (staticIndexOf!(Unqual!X, FloatingPointTypeList) >= 0) { alias FloatingPointTypeOf = X; } else static assert(0, T.stringof~" is not a floating point type"); } unittest { foreach (T; FloatingPointTypeList) foreach (Q; TypeQualifierList) { static assert( is(Q!T == FloatingPointTypeOf!( Q!T ))); static assert( is(Q!T == FloatingPointTypeOf!( SubTypeOf!(Q!T) ))); } foreach (T; TypeTuple!(void, bool, IntegralTypeList, ImaginaryTypeList, ComplexTypeList, CharTypeList)) foreach (Q; TypeQualifierList) { static assert(!is(FloatingPointTypeOf!( Q!T ))); static assert(!is(FloatingPointTypeOf!( SubTypeOf!(Q!T) ))); } } /* */ template NumericTypeOf(T) { static if (is(IntegralTypeOf!T X) || is(FloatingPointTypeOf!T X)) { alias NumericTypeOf = X; } else static assert(0, T.stringof~" is not a numeric type"); } unittest { foreach (T; NumericTypeList) foreach (Q; TypeQualifierList) { static assert( is(Q!T == NumericTypeOf!( Q!T ))); static assert( is(Q!T == NumericTypeOf!( SubTypeOf!(Q!T) ))); } foreach (T; TypeTuple!(void, bool, CharTypeList, ImaginaryTypeList, ComplexTypeList)) foreach (Q; TypeQualifierList) { static assert(!is(NumericTypeOf!( Q!T ))); static assert(!is(NumericTypeOf!( SubTypeOf!(Q!T) ))); } } /* */ template UnsignedTypeOf(T) { static if (is(IntegralTypeOf!T X) && staticIndexOf!(Unqual!X, UnsignedIntTypeList) >= 0) alias UnsignedTypeOf = X; else static assert(0, T.stringof~" is not an unsigned type."); } /* */ template SignedTypeOf(T) { static if (is(IntegralTypeOf!T X) && staticIndexOf!(Unqual!X, SignedIntTypeList) >= 0) alias SignedTypeOf = X; else static if (is(FloatingPointTypeOf!T X)) alias SignedTypeOf = X; else static assert(0, T.stringof~" is not an signed type."); } /* */ template CharTypeOf(T) { static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT)) alias X = CharTypeOf!AT; else alias X = OriginalType!T; static if (staticIndexOf!(Unqual!X, CharTypeList) >= 0) { alias CharTypeOf = X; } else static assert(0, T.stringof~" is not a character type"); } unittest { foreach (T; CharTypeList) foreach (Q; TypeQualifierList) { static assert( is(CharTypeOf!( Q!T ))); static assert( is(CharTypeOf!( SubTypeOf!(Q!T) ))); } foreach (T; TypeTuple!(void, bool, NumericTypeList, ImaginaryTypeList, ComplexTypeList)) foreach (Q; TypeQualifierList) { static assert(!is(CharTypeOf!( Q!T ))); static assert(!is(CharTypeOf!( SubTypeOf!(Q!T) ))); } foreach (T; TypeTuple!(string, wstring, dstring, char[4])) foreach (Q; TypeQualifierList) { static assert(!is(CharTypeOf!( Q!T ))); static assert(!is(CharTypeOf!( SubTypeOf!(Q!T) ))); } } /* */ template StaticArrayTypeOf(T) { static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT)) alias X = StaticArrayTypeOf!AT; else alias X = OriginalType!T; static if (is(X : E[n], E, size_t n)) alias StaticArrayTypeOf = X; else static assert(0, T.stringof~" is not a static array type"); } unittest { foreach (T; TypeTuple!(bool, NumericTypeList, ImaginaryTypeList, ComplexTypeList)) foreach (Q; TypeTuple!(TypeQualifierList, InoutOf, SharedInoutOf)) { static assert(is( Q!( T[1] ) == StaticArrayTypeOf!( Q!( T[1] ) ) )); foreach (P; TypeQualifierList) { // SubTypeOf cannot have inout type static assert(is( Q!(P!(T[1])) == StaticArrayTypeOf!( Q!(SubTypeOf!(P!(T[1]))) ) )); } } foreach (T; TypeTuple!void) foreach (Q; TypeTuple!TypeQualifierList) { static assert(is( StaticArrayTypeOf!( Q!(void[1]) ) == Q!(void[1]) )); } } /* */ template DynamicArrayTypeOf(T) { static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT)) alias X = DynamicArrayTypeOf!AT; else alias X = OriginalType!T; static if (is(Unqual!X : E[], E) && !is(typeof({ enum n = X.length; }))) { alias DynamicArrayTypeOf = X; } else static assert(0, T.stringof~" is not a dynamic array"); } unittest { foreach (T; TypeTuple!(/*void, */bool, NumericTypeList, ImaginaryTypeList, ComplexTypeList)) foreach (Q; TypeTuple!(TypeQualifierList, InoutOf, SharedInoutOf)) { static assert(is( Q!T[] == DynamicArrayTypeOf!( Q!T[] ) )); static assert(is( Q!(T[]) == DynamicArrayTypeOf!( Q!(T[]) ) )); foreach (P; TypeTuple!(MutableOf, ConstOf, ImmutableOf)) { static assert(is( Q!(P!T[]) == DynamicArrayTypeOf!( Q!(SubTypeOf!(P!T[])) ) )); static assert(is( Q!(P!(T[])) == DynamicArrayTypeOf!( Q!(SubTypeOf!(P!(T[]))) ) )); } } static assert(!is(DynamicArrayTypeOf!(int[3]))); static assert(!is(DynamicArrayTypeOf!(void[3]))); static assert(!is(DynamicArrayTypeOf!(typeof(null)))); } /* */ template ArrayTypeOf(T) { static if (is(StaticArrayTypeOf!T X) || is(DynamicArrayTypeOf!T X)) { alias ArrayTypeOf = X; } else static assert(0, T.stringof~" is not an array type"); } /* Always returns the Dynamic Array version. */ template StringTypeOf(T) { static if (is(T == typeof(null))) { // It is impossible to determine exact string type from typeof(null) - // it means that StringTypeOf!(typeof(null)) is undefined. // Then this behavior is convenient for template constraint. static assert(0, T.stringof~" is not a string type"); } else static if (is(T : const char[]) || is(T : const wchar[]) || is(T : const dchar[])) { static if (is(T : U[], U)) alias StringTypeOf = U[]; else static assert(0); } else static assert(0, T.stringof~" is not a string type"); } unittest { foreach (T; CharTypeList) foreach (Q; TypeTuple!(MutableOf, ConstOf, ImmutableOf, InoutOf)) { static assert(is(Q!T[] == StringTypeOf!( Q!T[] ))); static if (!__traits(isSame, Q, InoutOf)) { static assert(is(Q!T[] == StringTypeOf!( SubTypeOf!(Q!T[]) ))); alias Str = Q!T[]; class C(S) { S val; alias val this; } static assert(is(StringTypeOf!(C!Str) == Str)); } } foreach (T; CharTypeList) foreach (Q; TypeTuple!(SharedOf, SharedConstOf, SharedInoutOf)) { static assert(!is(StringTypeOf!( Q!T[] ))); } } unittest { static assert(is(StringTypeOf!(char[4]) == char[])); } /* */ template AssocArrayTypeOf(T) { static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT)) alias X = AssocArrayTypeOf!AT; else alias X = OriginalType!T; static if (is(Unqual!X : V[K], K, V)) { alias AssocArrayTypeOf = X; } else static assert(0, T.stringof~" is not an associative array type"); } unittest { foreach (T; TypeTuple!(int/*bool, CharTypeList, NumericTypeList, ImaginaryTypeList, ComplexTypeList*/)) foreach (P; TypeTuple!(TypeQualifierList, InoutOf, SharedInoutOf)) foreach (Q; TypeTuple!(TypeQualifierList, InoutOf, SharedInoutOf)) foreach (R; TypeTuple!(TypeQualifierList, InoutOf, SharedInoutOf)) { static assert(is( P!(Q!T[R!T]) == AssocArrayTypeOf!( P!(Q!T[R!T]) ) )); } foreach (T; TypeTuple!(int/*bool, CharTypeList, NumericTypeList, ImaginaryTypeList, ComplexTypeList*/)) foreach (O; TypeTuple!(TypeQualifierList, InoutOf, SharedInoutOf)) foreach (P; TypeTuple!TypeQualifierList) foreach (Q; TypeTuple!TypeQualifierList) foreach (R; TypeTuple!TypeQualifierList) { static assert(is( O!(P!(Q!T[R!T])) == AssocArrayTypeOf!( O!(SubTypeOf!(P!(Q!T[R!T]))) ) )); } } /* */ template BuiltinTypeOf(T) { static if (is(T : void)) alias BuiltinTypeOf = void; else static if (is(BooleanTypeOf!T X)) alias BuiltinTypeOf = X; else static if (is(IntegralTypeOf!T X)) alias BuiltinTypeOf = X; else static if (is(FloatingPointTypeOf!T X))alias BuiltinTypeOf = X; else static if (is(T : const(ireal))) alias BuiltinTypeOf = ireal; //TODO else static if (is(T : const(creal))) alias BuiltinTypeOf = creal; //TODO else static if (is(CharTypeOf!T X)) alias BuiltinTypeOf = X; else static if (is(ArrayTypeOf!T X)) alias BuiltinTypeOf = X; else static if (is(AssocArrayTypeOf!T X)) alias BuiltinTypeOf = X; else static assert(0); } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // isSomething //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// /** * Detect whether $(D T) is a built-in boolean type. */ enum bool isBoolean(T) = is(BooleanTypeOf!T) && !isAggregateType!T; /// unittest { static assert( isBoolean!bool); enum EB : bool { a = true } static assert( isBoolean!EB); static assert(!isBoolean!(SubTypeOf!bool)); } /** * Detect whether $(D T) is a built-in integral type. Types $(D bool), * $(D char), $(D wchar), and $(D dchar) are not considered integral. */ enum bool isIntegral(T) = is(IntegralTypeOf!T) && !isAggregateType!T; unittest { foreach (T; IntegralTypeList) { foreach (Q; TypeQualifierList) { static assert( isIntegral!(Q!T)); static assert(!isIntegral!(SubTypeOf!(Q!T))); } } static assert(!isIntegral!float); enum EU : uint { a = 0, b = 1, c = 2 } // base type is unsigned enum EI : int { a = -1, b = 0, c = 1 } // base type is signed (bug 7909) static assert(isIntegral!EU && isUnsigned!EU && !isSigned!EU); static assert(isIntegral!EI && !isUnsigned!EI && isSigned!EI); } /** * Detect whether $(D T) is a built-in floating point type. */ enum bool isFloatingPoint(T) = is(FloatingPointTypeOf!T) && !isAggregateType!T; unittest { enum EF : real { a = 1.414, b = 1.732, c = 2.236 } foreach (T; TypeTuple!(FloatingPointTypeList, EF)) { foreach (Q; TypeQualifierList) { static assert( isFloatingPoint!(Q!T)); static assert(!isFloatingPoint!(SubTypeOf!(Q!T))); } } foreach (T; IntegralTypeList) { foreach (Q; TypeQualifierList) { static assert(!isFloatingPoint!(Q!T)); } } } /** Detect whether $(D T) is a built-in numeric type (integral or floating point). */ enum bool isNumeric(T) = is(NumericTypeOf!T) && !isAggregateType!T; unittest { foreach (T; TypeTuple!(NumericTypeList)) { foreach (Q; TypeQualifierList) { static assert( isNumeric!(Q!T)); static assert(!isNumeric!(SubTypeOf!(Q!T))); } } } /** Detect whether $(D T) is a scalar type (a built-in numeric, character or boolean type). */ enum bool isScalarType(T) = isNumeric!T || isSomeChar!T || isBoolean!T; /// unittest { static assert(!isScalarType!void); static assert( isScalarType!(immutable(int))); static assert( isScalarType!(shared(float))); static assert( isScalarType!(shared(const bool))); static assert( isScalarType!(const(dchar))); } /** Detect whether $(D T) is a basic type (scalar type or void). */ enum bool isBasicType(T) = isScalarType!T || is(T == void); /// unittest { static assert(isBasicType!void); static assert(isBasicType!(immutable(int))); static assert(isBasicType!(shared(float))); static assert(isBasicType!(shared(const bool))); static assert(isBasicType!(const(dchar))); } /** Detect whether $(D T) is a built-in unsigned numeric type. */ enum bool isUnsigned(T) = is(UnsignedTypeOf!T) && !isAggregateType!T; unittest { foreach (T; TypeTuple!(UnsignedIntTypeList)) { foreach (Q; TypeQualifierList) { static assert( isUnsigned!(Q!T)); static assert(!isUnsigned!(SubTypeOf!(Q!T))); } } } /** Detect whether $(D T) is a built-in signed numeric type. */ enum bool isSigned(T) = is(SignedTypeOf!T) && !isAggregateType!T; unittest { foreach (T; TypeTuple!(SignedIntTypeList)) { foreach (Q; TypeQualifierList) { static assert( isSigned!(Q!T)); static assert(!isSigned!(SubTypeOf!(Q!T))); } } } /** Detect whether $(D T) is one of the built-in character types. */ enum bool isSomeChar(T) = is(CharTypeOf!T) && !isAggregateType!T; /// unittest { static assert(!isSomeChar!int); static assert(!isSomeChar!byte); static assert(!isSomeChar!string); static assert(!isSomeChar!wstring); static assert(!isSomeChar!dstring); static assert(!isSomeChar!(char[4])); } unittest { enum EC : char { a = 'x', b = 'y' } foreach (T; TypeTuple!(CharTypeList, EC)) { foreach (Q; TypeQualifierList) { static assert( isSomeChar!( Q!T )); static assert(!isSomeChar!( SubTypeOf!(Q!T) )); } } } /** Detect whether $(D T) is one of the built-in string types. The built-in string types are $(D Char[]), where $(D Char) is any of $(D char), $(D wchar) or $(D dchar), with or without qualifiers. Static arrays of characters (like $(D char[80])) are not considered built-in string types. */ enum bool isSomeString(T) = is(StringTypeOf!T) && !isAggregateType!T && !isStaticArray!T; /// unittest { static assert(!isSomeString!int); static assert(!isSomeString!(int[])); static assert(!isSomeString!(byte[])); static assert(!isSomeString!(typeof(null))); static assert(!isSomeString!(char[4])); enum ES : string { a = "aaa", b = "bbb" } static assert( isSomeString!ES); } unittest { foreach (T; TypeTuple!(char[], dchar[], string, wstring, dstring)) { static assert( isSomeString!( T )); static assert(!isSomeString!(SubTypeOf!(T))); } } /** * Detect whether type $(D T) is a narrow string. * * All arrays that use char, wchar, and their qualified versions are narrow * strings. (Those include string and wstring). */ enum bool isNarrowString(T) = (is(T : const char[]) || is(T : const wchar[])) && !isAggregateType!T && !isStaticArray!T; /// unittest { static assert(isNarrowString!string); static assert(isNarrowString!wstring); static assert(isNarrowString!(char[])); static assert(isNarrowString!(wchar[])); static assert(!isNarrowString!dstring); static assert(!isNarrowString!(dchar[])); } unittest { foreach (T; TypeTuple!(char[], string, wstring)) { foreach (Q; TypeTuple!(MutableOf, ConstOf, ImmutableOf)/*TypeQualifierList*/) { static assert( isNarrowString!( Q!T )); static assert(!isNarrowString!( SubTypeOf!(Q!T) )); } } foreach (T; TypeTuple!(int, int[], byte[], dchar[], dstring, char[4])) { foreach (Q; TypeQualifierList) { static assert(!isNarrowString!( Q!T )); static assert(!isNarrowString!( SubTypeOf!(Q!T) )); } } } /* Detect whether $(D T) is a struct or static array that is implicitly convertible to a string. */ template isConvertibleToString(T) { enum isConvertibleToString = (isAggregateType!T || isStaticArray!T) && is(StringTypeOf!T); } unittest { static struct AliasedString { string s; alias s this; } assert(!isConvertibleToString!string); assert(isConvertibleToString!AliasedString); assert(isConvertibleToString!(char[25])); } package template convertToString(T) { static if (isConvertibleToString!T) alias convertToString = StringTypeOf!T; else alias convertToString = T; } /** * Detect whether type $(D T) is a string that will be autodecoded. * * All arrays that use char, wchar, and their qualified versions are narrow * strings. (Those include string and wstring). * Aggregates that implicitly cast to narrow strings are included. * * Params: * T = type to be tested * * Returns: * true if T represents a string that is subject to autodecoding * * See Also: * $(LREF isNarrowString) */ enum bool isAutodecodableString(T) = (is(T : const char[]) || is(T : const wchar[])) && !isStaticArray!T; /// unittest { static struct Stringish { string s; alias s this; } assert(isAutodecodableString!wstring); assert(isAutodecodableString!Stringish); assert(!isAutodecodableString!dstring); } /** * Detect whether type $(D T) is a static array. */ enum bool isStaticArray(T) = is(StaticArrayTypeOf!T) && !isAggregateType!T; /// unittest { static assert(!isStaticArray!(const(int)[])); static assert(!isStaticArray!(immutable(int)[])); static assert(!isStaticArray!(const(int)[4][])); static assert(!isStaticArray!(int[])); static assert(!isStaticArray!(int[char])); static assert(!isStaticArray!(int[1][])); static assert(!isStaticArray!(int[int])); static assert(!isStaticArray!int); } unittest { foreach (T; TypeTuple!(int[51], int[][2], char[][int][11], immutable char[13u], const(real)[1], const(real)[1][1], void[0])) { foreach (Q; TypeQualifierList) { static assert( isStaticArray!( Q!T )); static assert(!isStaticArray!( SubTypeOf!(Q!T) )); } } //enum ESA : int[1] { a = [1], b = [2] } //static assert( isStaticArray!ESA); } /** * Detect whether type $(D T) is a dynamic array. */ enum bool isDynamicArray(T) = is(DynamicArrayTypeOf!T) && !isAggregateType!T; unittest { foreach (T; TypeTuple!(int[], char[], string, long[3][], double[string][])) { foreach (Q; TypeQualifierList) { static assert( isDynamicArray!( Q!T )); static assert(!isDynamicArray!( SubTypeOf!(Q!T) )); } } static assert(!isDynamicArray!(int[5])); static assert(!isDynamicArray!(typeof(null))); //enum EDA : int[] { a = [1], b = [2] } //static assert( isDynamicArray!EDA); } /** * Detect whether type $(D T) is an array (static or dynamic; for associative * arrays see $(LREF isAssociativeArray)). */ enum bool isArray(T) = isStaticArray!T || isDynamicArray!T; unittest { foreach (T; TypeTuple!(int[], int[5], void[])) { foreach (Q; TypeQualifierList) { static assert( isArray!(Q!T)); static assert(!isArray!(SubTypeOf!(Q!T))); } } static assert(!isArray!uint); static assert(!isArray!(uint[uint])); static assert(!isArray!(typeof(null))); } /** * Detect whether $(D T) is an associative array type */ enum bool isAssociativeArray(T) = is(AssocArrayTypeOf!T) && !isAggregateType!T; unittest { struct Foo { @property uint[] keys() { return null; } @property uint[] values() { return null; } } foreach (T; TypeTuple!(int[int], int[string], immutable(char[5])[int])) { foreach (Q; TypeQualifierList) { static assert( isAssociativeArray!(Q!T)); static assert(!isAssociativeArray!(SubTypeOf!(Q!T))); } } static assert(!isAssociativeArray!Foo); static assert(!isAssociativeArray!int); static assert(!isAssociativeArray!(int[])); static assert(!isAssociativeArray!(typeof(null))); //enum EAA : int[int] { a = [1:1], b = [2:2] } //static assert( isAssociativeArray!EAA); } /** * Detect whether type $(D T) is a builtin type. */ enum bool isBuiltinType(T) = is(BuiltinTypeOf!T) && !isAggregateType!T; /// unittest { class C; union U; struct S; interface I; static assert( isBuiltinType!void); static assert( isBuiltinType!string); static assert( isBuiltinType!(int[])); static assert( isBuiltinType!(C[string])); static assert(!isBuiltinType!C); static assert(!isBuiltinType!U); static assert(!isBuiltinType!S); static assert(!isBuiltinType!I); static assert(!isBuiltinType!(void delegate(int))); } /** * Detect whether type $(D T) is a SIMD vector type. */ enum bool isSIMDVector(T) = is(T : __vector(V[N]), V, size_t N); unittest { static if (is(__vector(float[4]))) { alias SimdVec = __vector(float[4]); static assert(isSIMDVector!(__vector(float[4]))); static assert(isSIMDVector!SimdVec); } static assert(!isSIMDVector!uint); static assert(!isSIMDVector!(float[4])); } /** * Detect whether type $(D T) is a pointer. */ enum bool isPointer(T) = is(T == U*, U) && !isAggregateType!T; unittest { foreach (T; TypeTuple!(int*, void*, char[]*)) { foreach (Q; TypeQualifierList) { static assert( isPointer!(Q!T)); static assert(!isPointer!(SubTypeOf!(Q!T))); } } static assert(!isPointer!uint); static assert(!isPointer!(uint[uint])); static assert(!isPointer!(char[])); static assert(!isPointer!(typeof(null))); } /** Returns the target type of a pointer. */ alias PointerTarget(T : T*) = T; // Explicitly undocumented. It will be removed in June 2016. @@@DEPRECATED_2016-06@@@ deprecated("Please use PointerTarget instead.") alias pointerTarget = PointerTarget; unittest { static assert( is(PointerTarget!(int*) == int)); static assert( is(PointerTarget!(long*) == long)); static assert(!is(PointerTarget!int)); } /** * Detect whether type $(D T) is an aggregate type. */ enum bool isAggregateType(T) = is(T == struct) || is(T == union) || is(T == class) || is(T == interface); /// unittest { class C; union U; struct S; interface I; static assert( isAggregateType!C); static assert( isAggregateType!U); static assert( isAggregateType!S); static assert( isAggregateType!I); static assert(!isAggregateType!void); static assert(!isAggregateType!string); static assert(!isAggregateType!(int[])); static assert(!isAggregateType!(C[string])); static assert(!isAggregateType!(void delegate(int))); } /** * Returns $(D true) if T can be iterated over using a $(D foreach) loop with * a single loop variable of automatically inferred type, regardless of how * the $(D foreach) loop is implemented. This includes ranges, structs/classes * that define $(D opApply) with a single loop variable, and builtin dynamic, * static and associative arrays. */ enum bool isIterable(T) = is(typeof({ foreach(elem; T.init) {} })); /// unittest { struct OpApply { int opApply(int delegate(ref uint) dg) { assert(0); } } struct Range { @property uint front() { assert(0); } void popFront() { assert(0); } enum bool empty = false; } static assert( isIterable!(uint[])); static assert( isIterable!OpApply); static assert( isIterable!(uint[string])); static assert( isIterable!Range); static assert(!isIterable!uint); } /** * Returns true if T is not const or immutable. Note that isMutable is true for * string, or immutable(char)[], because the 'head' is mutable. */ enum bool isMutable(T) = !is(T == const) && !is(T == immutable) && !is(T == inout); /// unittest { static assert( isMutable!int); static assert( isMutable!string); static assert( isMutable!(shared int)); static assert( isMutable!(shared const(int)[])); static assert(!isMutable!(const int)); static assert(!isMutable!(inout int)); static assert(!isMutable!(shared(const int))); static assert(!isMutable!(shared(inout int))); static assert(!isMutable!(immutable string)); } /** * Returns true if T is an instance of the template S. */ enum bool isInstanceOf(alias S, T) = is(T == S!Args, Args...); /// unittest { static struct Foo(T...) { } static struct Bar(T...) { } static struct Doo(T) { } static struct ABC(int x) { } static assert(isInstanceOf!(Foo, Foo!int)); static assert(!isInstanceOf!(Foo, Bar!int)); static assert(!isInstanceOf!(Foo, int)); static assert(isInstanceOf!(Doo, Doo!int)); static assert(isInstanceOf!(ABC, ABC!1)); static assert(!__traits(compiles, isInstanceOf!(Foo, Foo))); } /** * Check whether the tuple T is an expression tuple. * An expression tuple only contains expressions. * * See_Also: $(LREF isTypeTuple). */ template isExpressions(T ...) { static if (T.length >= 2) enum bool isExpressions = isExpressions!(T[0 .. $/2]) && isExpressions!(T[$/2 .. $]); else static if (T.length == 1) enum bool isExpressions = !is(T[0]) && __traits(compiles, { auto ex = T[0]; }); else enum bool isExpressions = true; // default } /// unittest { static assert(isExpressions!(1, 2.0, "a")); static assert(!isExpressions!(int, double, string)); static assert(!isExpressions!(int, 2.0, "a")); } /** * Alternate name for $(LREF isExpressions), kept for legacy compatibility. */ alias isExpressionTuple = isExpressions; unittest { void foo(); static int bar() { return 42; } enum aa = [ 1: -1 ]; alias myint = int; static assert( isExpressionTuple!(42)); static assert( isExpressionTuple!aa); static assert( isExpressionTuple!("cattywampus", 2.7, aa)); static assert( isExpressionTuple!(bar())); static assert(!isExpressionTuple!isExpressionTuple); static assert(!isExpressionTuple!foo); static assert(!isExpressionTuple!( (a) { } )); static assert(!isExpressionTuple!int); static assert(!isExpressionTuple!myint); } /** * Check whether the tuple $(D T) is a type tuple. * A type tuple only contains types. * * See_Also: $(LREF isExpressions). */ template isTypeTuple(T...) { static if (T.length >= 2) enum bool isTypeTuple = isTypeTuple!(T[0 .. $/2]) && isTypeTuple!(T[$/2 .. $]); else static if (T.length == 1) enum bool isTypeTuple = is(T[0]); else enum bool isTypeTuple = true; // default } /// unittest { static assert(isTypeTuple!(int, float, string)); static assert(!isTypeTuple!(1, 2.0, "a")); static assert(!isTypeTuple!(1, double, string)); } unittest { class C {} void func(int) {} auto c = new C; enum CONST = 42; static assert( isTypeTuple!int); static assert( isTypeTuple!string); static assert( isTypeTuple!C); static assert( isTypeTuple!(typeof(func))); static assert( isTypeTuple!(int, char, double)); static assert(!isTypeTuple!c); static assert(!isTypeTuple!isTypeTuple); static assert(!isTypeTuple!CONST); } /** Detect whether symbol or type $(D T) is a function pointer. */ template isFunctionPointer(T...) if (T.length == 1) { static if (is(T[0] U) || is(typeof(T[0]) U)) { static if (is(U F : F*) && is(F == function)) enum bool isFunctionPointer = true; else enum bool isFunctionPointer = false; } else enum bool isFunctionPointer = false; } /// unittest { static void foo() {} void bar() {} auto fpfoo = &foo; static assert( isFunctionPointer!fpfoo); static assert( isFunctionPointer!(void function())); auto dgbar = &bar; static assert(!isFunctionPointer!dgbar); static assert(!isFunctionPointer!(void delegate())); static assert(!isFunctionPointer!foo); static assert(!isFunctionPointer!bar); static assert( isFunctionPointer!((int a) {})); } /** Detect whether symbol or type $(D T) is a delegate. */ template isDelegate(T...) if (T.length == 1) { static if (is(typeof(& T[0]) U : U*) && is(typeof(& T[0]) U == delegate)) { // T is a (nested) function symbol. enum bool isDelegate = true; } else static if (is(T[0] W) || is(typeof(T[0]) W)) { // T is an expression or a type. Take the type of it and examine. enum bool isDelegate = is(W == delegate); } else enum bool isDelegate = false; } /// unittest { static void sfunc() { } int x; void func() { x++; } int delegate() dg; assert(isDelegate!dg); assert(isDelegate!(int delegate())); assert(isDelegate!(typeof(&func))); int function() fp; assert(!isDelegate!fp); assert(!isDelegate!(int function())); assert(!isDelegate!(typeof(&sfunc))); } /** Detect whether symbol or type $(D T) is a function, a function pointer or a delegate. */ template isSomeFunction(T...) if (T.length == 1) { static if (is(typeof(& T[0]) U : U*) && is(U == function) || is(typeof(& T[0]) U == delegate)) { // T is a (nested) function symbol. enum bool isSomeFunction = true; } else static if (is(T[0] W) || is(typeof(T[0]) W)) { // T is an expression or a type. Take the type of it and examine. static if (is(W F : F*) && is(F == function)) enum bool isSomeFunction = true; // function pointer else enum bool isSomeFunction = is(W == function) || is(W == delegate); } else enum bool isSomeFunction = false; } unittest { static real func(ref int) { return 0; } static void prop() @property { } void nestedFunc() { } void nestedProp() @property { } class C { real method(ref int) { return 0; } real prop() @property { return 0; } } auto c = new C; auto fp = &func; auto dg = &c.method; real val; static assert( isSomeFunction!func); static assert( isSomeFunction!prop); static assert( isSomeFunction!nestedFunc); static assert( isSomeFunction!nestedProp); static assert( isSomeFunction!(C.method)); static assert( isSomeFunction!(C.prop)); static assert( isSomeFunction!(c.prop)); static assert( isSomeFunction!(c.prop)); static assert( isSomeFunction!fp); static assert( isSomeFunction!dg); static assert( isSomeFunction!(typeof(func))); static assert( isSomeFunction!(real function(ref int))); static assert( isSomeFunction!(real delegate(ref int))); static assert( isSomeFunction!((int a) { return a; })); static assert(!isSomeFunction!int); static assert(!isSomeFunction!val); static assert(!isSomeFunction!isSomeFunction); } /** Detect whether $(D T) is a callable object, which can be called with the function call operator $(D $(LPAREN)...$(RPAREN)). */ template isCallable(T...) if (T.length == 1) { static if (is(typeof(& T[0].opCall) == delegate)) // T is a object which has a member function opCall(). enum bool isCallable = true; else static if (is(typeof(& T[0].opCall) V : V*) && is(V == function)) // T is a type which has a static member function opCall(). enum bool isCallable = true; else enum bool isCallable = isSomeFunction!T; } /// unittest { interface I { real value() @property; } struct S { static int opCall(int) { return 0; } } class C { int opCall(int) { return 0; } } auto c = new C; static assert( isCallable!c); static assert( isCallable!S); static assert( isCallable!(c.opCall)); static assert( isCallable!(I.value)); static assert( isCallable!((int a) { return a; })); static assert(!isCallable!I); } /** * Detect whether $(D T) is a an abstract function. */ template isAbstractFunction(T...) if (T.length == 1) { enum bool isAbstractFunction = __traits(isAbstractFunction, T[0]); } unittest { struct S { void foo() { } } class C { void foo() { } } class AC { abstract void foo(); } static assert(!isAbstractFunction!(S.foo)); static assert(!isAbstractFunction!(C.foo)); static assert( isAbstractFunction!(AC.foo)); } /** * Detect whether $(D T) is a a final function. */ template isFinalFunction(T...) if (T.length == 1) { enum bool isFinalFunction = __traits(isFinalFunction, T[0]); } /// unittest { struct S { void bar() { } } final class FC { void foo(); } class C { void bar() { } final void foo(); } static assert(!isFinalFunction!(S.bar)); static assert( isFinalFunction!(FC.foo)); static assert(!isFinalFunction!(C.bar)); static assert( isFinalFunction!(C.foo)); } /** Determines whether function $(D f) requires a context pointer. */ template isNestedFunction(alias f) { enum isNestedFunction = __traits(isNested, f); } unittest { static void f() { } void g() { } static assert(!isNestedFunction!f); static assert( isNestedFunction!g); } /** * Detect whether $(D T) is a an abstract class. */ template isAbstractClass(T...) if (T.length == 1) { enum bool isAbstractClass = __traits(isAbstractClass, T[0]); } /// unittest { struct S { } class C { } abstract class AC { } static assert(!isAbstractClass!S); static assert(!isAbstractClass!C); static assert( isAbstractClass!AC); } /** * Detect whether $(D T) is a a final class. */ template isFinalClass(T...) if (T.length == 1) { enum bool isFinalClass = __traits(isFinalClass, T[0]); } /// unittest { class C { } abstract class AC { } final class FC1 : C { } final class FC2 { } static assert(!isFinalClass!C); static assert(!isFinalClass!AC); static assert( isFinalClass!FC1); static assert( isFinalClass!FC2); } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // General Types //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// /** Removes all qualifiers, if any, from type $(D T). */ template Unqual(T) { version (none) // Error: recursive alias declaration @@@BUG1308@@@ { static if (is(T U == const U)) alias Unqual = Unqual!U; else static if (is(T U == immutable U)) alias Unqual = Unqual!U; else static if (is(T U == inout U)) alias Unqual = Unqual!U; else static if (is(T U == shared U)) alias Unqual = Unqual!U; else alias Unqual = T; } else // workaround { static if (is(T U == immutable U)) alias Unqual = U; else static if (is(T U == shared inout const U)) alias Unqual = U; else static if (is(T U == shared inout U)) alias Unqual = U; else static if (is(T U == shared const U)) alias Unqual = U; else static if (is(T U == shared U)) alias Unqual = U; else static if (is(T U == inout const U)) alias Unqual = U; else static if (is(T U == inout U)) alias Unqual = U; else static if (is(T U == const U)) alias Unqual = U; else alias Unqual = T; } } /// unittest { static assert(is(Unqual!int == int)); static assert(is(Unqual!(const int) == int)); static assert(is(Unqual!(immutable int) == int)); static assert(is(Unqual!(shared int) == int)); static assert(is(Unqual!(shared(const int)) == int)); } unittest { static assert(is(Unqual!( int) == int)); static assert(is(Unqual!( const int) == int)); static assert(is(Unqual!( inout int) == int)); static assert(is(Unqual!( inout const int) == int)); static assert(is(Unqual!(shared int) == int)); static assert(is(Unqual!(shared const int) == int)); static assert(is(Unqual!(shared inout int) == int)); static assert(is(Unqual!(shared inout const int) == int)); static assert(is(Unqual!( immutable int) == int)); alias ImmIntArr = immutable(int[]); static assert(is(Unqual!ImmIntArr == immutable(int)[])); } // [For internal use] package template ModifyTypePreservingTQ(alias Modifier, T) { static if (is(T U == immutable U)) alias ModifyTypePreservingTQ = immutable Modifier!U; else static if (is(T U == shared inout const U)) alias ModifyTypePreservingTQ = shared inout const Modifier!U; else static if (is(T U == shared inout U)) alias ModifyTypePreservingTQ = shared inout Modifier!U; else static if (is(T U == shared const U)) alias ModifyTypePreservingTQ = shared const Modifier!U; else static if (is(T U == shared U)) alias ModifyTypePreservingTQ = shared Modifier!U; else static if (is(T U == inout const U)) alias ModifyTypePreservingTQ = inout const Modifier!U; else static if (is(T U == inout U)) alias ModifyTypePreservingTQ = inout Modifier!U; else static if (is(T U == const U)) alias ModifyTypePreservingTQ = const Modifier!U; else alias ModifyTypePreservingTQ = Modifier!T; } unittest { alias Intify(T) = int; static assert(is(ModifyTypePreservingTQ!(Intify, real) == int)); static assert(is(ModifyTypePreservingTQ!(Intify, const real) == const int)); static assert(is(ModifyTypePreservingTQ!(Intify, inout real) == inout int)); static assert(is(ModifyTypePreservingTQ!(Intify, inout const real) == inout const int)); static assert(is(ModifyTypePreservingTQ!(Intify, shared real) == shared int)); static assert(is(ModifyTypePreservingTQ!(Intify, shared const real) == shared const int)); static assert(is(ModifyTypePreservingTQ!(Intify, shared inout real) == shared inout int)); static assert(is(ModifyTypePreservingTQ!(Intify, shared inout const real) == shared inout const int)); static assert(is(ModifyTypePreservingTQ!(Intify, immutable real) == immutable int)); } /** * Copies type qualifiers from $(D FromType) to $(D ToType). * * Supported type qualifiers: * $(UL * $(LI $(D const)) * $(LI $(D inout)) * $(LI $(D immutable)) * $(LI $(D shared)) * ) */ template CopyTypeQualifiers(FromType, ToType) { alias T(U) = ToType; alias CopyTypeQualifiers = ModifyTypePreservingTQ!(T, FromType); } /// unittest { static assert(is(CopyTypeQualifiers!(inout const real, int) == inout const int)); } unittest { static assert(is(CopyTypeQualifiers!( real, int) == int)); static assert(is(CopyTypeQualifiers!( const real, int) == const int)); static assert(is(CopyTypeQualifiers!( inout real, int) == inout int)); static assert(is(CopyTypeQualifiers!( inout const real, int) == inout const int)); static assert(is(CopyTypeQualifiers!(shared real, int) == shared int)); static assert(is(CopyTypeQualifiers!(shared const real, int) == shared const int)); static assert(is(CopyTypeQualifiers!(shared inout real, int) == shared inout int)); static assert(is(CopyTypeQualifiers!(shared inout const real, int) == shared inout const int)); static assert(is(CopyTypeQualifiers!( immutable real, int) == immutable int)); } /** Returns the type of `Target` with the "constness" of `Source`. A type's $(BOLD constness) refers to whether it is `const`, `immutable`, or `inout`. If `source` has no constness, the returned type will be the same as `Target`. */ template CopyConstness(FromType, ToType) { alias Unshared(T) = T; alias Unshared(T: shared U, U) = U; alias CopyConstness = Unshared!(CopyTypeQualifiers!(FromType, ToType)); } /// unittest { const(int) i; CopyConstness!(typeof(i), float) f; assert( is(typeof(f) == const float)); CopyConstness!(char, uint) u; assert( is(typeof(u) == uint)); //The 'shared' qualifier will not be copied assert(!is(CopyConstness!(shared bool, int) == shared int)); //But the constness will be assert( is(CopyConstness!(shared const real, double) == const double)); //Careful, const(int)[] is a mutable array of const(int) alias MutT = CopyConstness!(const(int)[], int); assert(!is(MutT == const(int))); //Okay, const(int[]) applies to array and contained ints alias CstT = CopyConstness!(const(int[]), int); assert( is(CstT == const(int))); } unittest { struct Test { void method1() {} void method2() const {} void method3() immutable {} } assert(is(CopyConstness!(typeof(Test.method1), real) == real)); assert(is(CopyConstness!(typeof(Test.method2), byte) == const(byte))); assert(is(CopyConstness!(typeof(Test.method3), string) == immutable(string))); } unittest { assert(is(CopyConstness!(inout(int)[], int[]) == int[])); assert(is(CopyConstness!(inout(int[]), int[]) == inout(int[]))); } unittest { static assert(is(CopyConstness!( int, real) == real)); static assert(is(CopyConstness!(const int, real) == const real)); static assert(is(CopyConstness!(inout int, real) == inout real)); static assert(is(CopyConstness!(inout const int, real) == inout const real)); static assert(is(CopyConstness!(shared int, real) == real)); static assert(is(CopyConstness!(shared const int, real) == const real)); static assert(is(CopyConstness!(shared inout int, real) == inout real)); static assert(is(CopyConstness!(shared inout const int, real) == inout const real)); static assert(is(CopyConstness!(immutable int, real) == immutable real)); } /** Returns the inferred type of the loop variable when a variable of type T is iterated over using a $(D foreach) loop with a single loop variable and automatically inferred return type. Note that this may not be the same as $(D std.range.ElementType!Range) in the case of narrow strings, or if T has both opApply and a range interface. */ template ForeachType(T) { alias ForeachType = ReturnType!(typeof( (inout int x = 0) { foreach(elem; T.init) { return elem; } assert(0); })); } /// unittest { static assert(is(ForeachType!(uint[]) == uint)); static assert(is(ForeachType!string == immutable(char))); static assert(is(ForeachType!(string[string]) == string)); static assert(is(ForeachType!(inout(int)[]) == inout(int))); } /** * Strips off all $(D enum)s from type $(D T). */ template OriginalType(T) { template Impl(T) { static if (is(T U == enum)) alias Impl = OriginalType!U; else alias Impl = T; } alias OriginalType = ModifyTypePreservingTQ!(Impl, T); } /// unittest { enum E : real { a } enum F : E { a = E.a } alias G = const(F); static assert(is(OriginalType!E == real)); static assert(is(OriginalType!F == real)); static assert(is(OriginalType!G == const real)); } /** * Get the Key type of an Associative Array. */ alias KeyType(V : V[K], K) = K; /// unittest { import std.traits; alias Hash = int[string]; static assert(is(KeyType!Hash == string)); static assert(is(ValueType!Hash == int)); KeyType!Hash str = "a"; // str is declared as string ValueType!Hash num = 1; // num is declared as int } /** * Get the Value type of an Associative Array. */ alias ValueType(V : V[K], K) = V; /// unittest { import std.traits; alias Hash = int[string]; static assert(is(KeyType!Hash == string)); static assert(is(ValueType!Hash == int)); KeyType!Hash str = "a"; // str is declared as string ValueType!Hash num = 1; // num is declared as int } /** * Returns the corresponding unsigned type for T. T must be a numeric * integral type, otherwise a compile-time error occurs. */ template Unsigned(T) { template Impl(T) { static if (is(T : __vector(V[N]), V, size_t N)) alias Impl = __vector(Impl!V[N]); else static if (isUnsigned!T) alias Impl = T; else static if (isSigned!T && !isFloatingPoint!T) { static if (is(T == byte )) alias Impl = ubyte; static if (is(T == short)) alias Impl = ushort; static if (is(T == int )) alias Impl = uint; static if (is(T == long )) alias Impl = ulong; static if (is(ucent) && is(T == cent )) alias Impl = ucent; } else static assert(false, "Type " ~ T.stringof ~ " does not have an Unsigned counterpart"); } alias Unsigned = ModifyTypePreservingTQ!(Impl, OriginalType!T); } unittest { alias U1 = Unsigned!int; alias U2 = Unsigned!(const(int)); alias U3 = Unsigned!(immutable(int)); static assert(is(U1 == uint)); static assert(is(U2 == const(uint))); static assert(is(U3 == immutable(uint))); static if (is(__vector(int[4])) && is(__vector(uint[4]))) { alias UV1 = Unsigned!(__vector(int[4])); alias UV2 = Unsigned!(const(__vector(int[4]))); static assert(is(UV1 == __vector(uint[4]))); static assert(is(UV2 == const(__vector(uint[4])))); } //struct S {} //alias U2 = Unsigned!S; //alias U3 = Unsigned!double; static if (is(ucent)) { alias U4 = Unsigned!cent; alias U5 = Unsigned!(const(cent)); alias U6 = Unsigned!(immutable(cent)); static assert(is(U4 == ucent)); static assert(is(U5 == const(ucent))); static assert(is(U6 == immutable(ucent))); } } /** Returns the largest type, i.e. T such that T.sizeof is the largest. If more than one type is of the same size, the leftmost argument of these in will be returned. */ template Largest(T...) if(T.length >= 1) { static if (T.length == 1) { alias Largest = T[0]; } else static if (T.length == 2) { static if(T[0].sizeof >= T[1].sizeof) { alias Largest = T[0]; } else { alias Largest = T[1]; } } else { alias Largest = Largest!(Largest!(T[0 .. $/2]), Largest!(T[$/2 .. $])); } } /// unittest { static assert(is(Largest!(uint, ubyte, ushort, real) == real)); static assert(is(Largest!(ulong, double) == ulong)); static assert(is(Largest!(double, ulong) == double)); static assert(is(Largest!(uint, byte, double, short) == double)); static if (is(ucent)) static assert(is(Largest!(uint, ubyte, ucent, ushort) == ucent)); } /** Returns the corresponding signed type for T. T must be a numeric integral type, otherwise a compile-time error occurs. */ template Signed(T) { template Impl(T) { static if (is(T : __vector(V[N]), V, size_t N)) alias Impl = __vector(Impl!V[N]); else static if (isSigned!T) alias Impl = T; else static if (isUnsigned!T) { static if (is(T == ubyte )) alias Impl = byte; static if (is(T == ushort)) alias Impl = short; static if (is(T == uint )) alias Impl = int; static if (is(T == ulong )) alias Impl = long; static if (is(ucent) && is(T == ucent )) alias Impl = cent; } else static assert(false, "Type " ~ T.stringof ~ " does not have an Signed counterpart"); } alias Signed = ModifyTypePreservingTQ!(Impl, OriginalType!T); } /// unittest { alias S1 = Signed!uint; static assert(is(S1 == int)); alias S2 = Signed!(const(uint)); static assert(is(S2 == const(int))); alias S3 = Signed!(immutable(uint)); static assert(is(S3 == immutable(int))); static if (is(ucent)) { alias S4 = Signed!ucent; static assert(is(S4 == cent)); } } unittest { static assert(is(Signed!float == float)); static if (is(__vector(int[4])) && is(__vector(uint[4]))) { alias SV1 = Signed!(__vector(uint[4])); alias SV2 = Signed!(const(__vector(uint[4]))); static assert(is(SV1 == __vector(int[4]))); static assert(is(SV2 == const(__vector(int[4])))); } } /** Returns the most negative value of the numeric type T. */ template mostNegative(T) if(isNumeric!T || isSomeChar!T || isBoolean!T) { static if (is(typeof(T.min_normal))) enum mostNegative = -T.max; else static if (T.min == 0) enum byte mostNegative = 0; else enum mostNegative = T.min; } /// unittest { static assert(mostNegative!float == -float.max); static assert(mostNegative!double == -double.max); static assert(mostNegative!real == -real.max); static assert(mostNegative!bool == false); } /// unittest { foreach(T; TypeTuple!(bool, byte, short, int, long)) static assert(mostNegative!T == T.min); foreach(T; TypeTuple!(ubyte, ushort, uint, ulong, char, wchar, dchar)) static assert(mostNegative!T == 0); } //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Misc. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// /** Returns the mangled name of symbol or type $(D sth). $(D mangledName) is the same as builtin $(D .mangleof) property, except that the correct names of property functions are obtained. -------------------- module test; import std.traits : mangledName; class C { int value() @property; } pragma(msg, C.value.mangleof); // prints "i" pragma(msg, mangledName!(C.value)); // prints "_D4test1C5valueMFNdZi" -------------------- */ template mangledName(sth...) if (sth.length == 1) { static if (is(typeof(sth[0]) X) && is(X == void)) { // sth[0] is a template symbol enum string mangledName = removeDummyEnvelope(Dummy!sth.Hook.mangleof); } else { enum string mangledName = sth[0].mangleof; } } private template Dummy(T...) { struct Hook {} } private string removeDummyEnvelope(string s) { // remove --> S3std6traits ... Z4Hook s = s[12 .. $ - 6]; // remove --> DIGIT+ __T5Dummy foreach (i, c; s) { if (c < '0' || '9' < c) { s = s[i .. $]; break; } } s = s[9 .. $]; // __T5Dummy // remove --> T | V | S immutable kind = s[0]; s = s[1 .. $]; if (kind == 'S') // it's a symbol { /* * The mangled symbol name is packed in LName --> Number Name. Here * we are chopping off the useless preceding Number, which is the * length of Name in decimal notation. * * NOTE: n = m + Log(m) + 1; n = LName.length, m = Name.length. */ immutable n = s.length; size_t m_upb = 10; foreach (k; 1 .. 5) // k = Log(m_upb) { if (n < m_upb + k + 1) { // Now m_upb/10 <= m < m_upb; hence k = Log(m) + 1. s = s[k .. $]; break; } m_upb *= 10; } } return s; } unittest { class C { int value() @property { return 0; } } static assert(mangledName!int == int.mangleof); static assert(mangledName!C == C.mangleof); static assert(mangledName!(C.value)[$ - 12 .. $] == "5valueMFNdZi"); static assert(mangledName!mangledName == "3std6traits11mangledName"); static assert(mangledName!removeDummyEnvelope == "_D3std6traits19removeDummyEnvelopeFAyaZAya"); int x; static if (is(typeof({ return x; }) : int delegate() pure)) // issue 9148 static assert(mangledName!((int a) { return a+x; }) == "DFNaNbNiNfiZi"); // pure nothrow @safe @nogc else static assert(mangledName!((int a) { return a+x; }) == "DFNbNiNfiZi"); // nothrow @safe @nnogc } unittest { // Test for bug 5718 import std.demangle; int foo; auto foo_demangled = demangle(mangledName!foo); assert(foo_demangled[0 .. 4] == "int " && foo_demangled[$-3 .. $] == "foo", foo_demangled); void bar(){} auto bar_demangled = demangle(mangledName!bar); assert(bar_demangled[0 .. 5] == "void " && bar_demangled[$-5 .. $] == "bar()"); } // XXX Select & select should go to another module. (functional or algorithm?) /** Aliases itself to $(D T[0]) if the boolean $(D condition) is $(D true) and to $(D T[1]) otherwise. */ template Select(bool condition, T...) if (T.length == 2) { import std.meta : Alias; alias Select = Alias!(T[!condition]); } /// unittest { // can select types static assert(is(Select!(true, int, long) == int)); static assert(is(Select!(false, int, long) == long)); static struct Foo {} static assert(is(Select!(false, const(int), const(Foo)) == const(Foo))); // can select symbols int a = 1; int b = 2; alias selA = Select!(true, a, b); alias selB = Select!(false, a, b); assert(selA == 1); assert(selB == 2); // can select (compile-time) expressions enum val = Select!(false, -4, 9 - 6); static assert(val == 3); } /** If $(D cond) is $(D true), returns $(D a) without evaluating $(D b). Otherwise, returns $(D b) without evaluating $(D a). */ A select(bool cond : true, A, B)(A a, lazy B b) { return a; } /// Ditto B select(bool cond : false, A, B)(lazy A a, B b) { return b; } unittest { real pleasecallme() { return 0; } int dontcallme() { assert(0); } auto a = select!true(pleasecallme(), dontcallme()); auto b = select!false(dontcallme(), pleasecallme()); static assert(is(typeof(a) == real)); static assert(is(typeof(b) == real)); } /** * Determine if a symbol has a given * $(DDSUBLINK spec/attribute,uda, user-defined attribute). */ template hasUDA(alias symbol, alias attribute) { import std.typetuple : staticIndexOf; static if (is(attribute == struct) || is(attribute == class)) { template GetTypeOrExp(alias S) { static if (is(typeof(S))) alias GetTypeOrExp = typeof(S); else alias GetTypeOrExp = S; } enum bool hasUDA = staticIndexOf!(attribute, staticMap!(GetTypeOrExp, __traits(getAttributes, symbol))) != -1; } else enum bool hasUDA = staticIndexOf!(attribute, __traits(getAttributes, symbol)) != -1; } /// unittest { enum E; struct S; struct Named { string name; } @("alpha") int a; static assert(hasUDA!(a, "alpha")); static assert(!hasUDA!(a, S)); static assert(!hasUDA!(a, E)); @(E) int b; static assert(!hasUDA!(b, "alpha")); static assert(!hasUDA!(b, S)); static assert(hasUDA!(b, E)); @E int c; static assert(!hasUDA!(c, "alpha")); static assert(!hasUDA!(c, S)); static assert(hasUDA!(c, E)); @(S, E) int d; static assert(!hasUDA!(d, "alpha")); static assert(hasUDA!(d, S)); static assert(hasUDA!(d, E)); @S int e; static assert(!hasUDA!(e, "alpha")); static assert(hasUDA!(e, S)); static assert(!hasUDA!(e, E)); @(S, E, "alpha") int f; static assert(hasUDA!(f, "alpha")); static assert(hasUDA!(f, S)); static assert(hasUDA!(f, E)); @(100) int g; static assert(hasUDA!(g, 100)); @Named("abc") int h; static assert(hasUDA!(h, Named)); } /** * Gets the $(DDSUBLINK spec/attribute,uda, user-defined attributes) of the * given type from the given symbol. */ template getUDAs(alias symbol, alias attribute) { import std.typetuple : Filter; template isDesiredUDA(alias S) { static if(__traits(compiles, is(typeof(S) == attribute))) { enum isDesiredUDA = is(typeof(S) == attribute); } else { enum isDesiredUDA = isInstanceOf!(attribute, typeof(S)); } } alias getUDAs = Filter!(isDesiredUDA, __traits(getAttributes, symbol)); } /// unittest { struct Attr { string name; int value; } @Attr("Answer", 42) int a; static assert(getUDAs!(a, Attr)[0].name == "Answer"); static assert(getUDAs!(a, Attr)[0].value == 42); @(Attr("Answer", 42), "string", 9999) int b; static assert(getUDAs!(b, Attr)[0].name == "Answer"); static assert(getUDAs!(b, Attr)[0].value == 42); @Attr("Answer", 42) @Attr("Pi", 3) int c; static assert(getUDAs!(c, Attr)[0].name == "Answer"); static assert(getUDAs!(c, Attr)[0].value == 42); static assert(getUDAs!(c, Attr)[1].name == "Pi"); static assert(getUDAs!(c, Attr)[1].value == 3); struct AttrT(T) { string name; T value; } @AttrT!uint("Answer", 42) @AttrT!int("Pi", 3) @AttrT int d; static assert(getUDAs!(d, AttrT)[0].name == "Answer"); static assert(getUDAs!(d, AttrT)[0].value == 42); static assert(getUDAs!(d, AttrT)[1].name == "Pi"); static assert(getUDAs!(d, AttrT)[1].value == 3); static assert(getUDAs!(d, AttrT!uint)[0].name == "Answer"); static assert(getUDAs!(d, AttrT!uint)[0].value == 42); static assert(getUDAs!(d, AttrT!int)[0].name == "Pi"); static assert(getUDAs!(d, AttrT!int)[0].value == 3); } /** * Gets all symbols within `symbol` that have the given user-defined attribute. * This is not recursive; it will not search for symbols within symbols such as * nested structs or unions. */ template getSymbolsByUDA(alias symbol, alias attribute) { import std.string : format; import std.meta : AliasSeq, Filter; // translate a list of strings into symbols. mixing in the entire alias // avoids trying to access the symbol, which could cause a privacy violation template toSymbols(names...) { static if (names.length == 1) mixin("alias toSymbols = AliasSeq!(symbol.%s);".format(names[0])); else mixin("alias toSymbols = AliasSeq!(symbol.%s, toSymbols!(names[1..$]));" .format(names[0])); } enum hasSpecificUDA(string name) = mixin("hasUDA!(symbol.%s, attribute)".format(name)); alias membersWithUDA = toSymbols!(Filter!(hasSpecificUDA, __traits(allMembers, symbol))); // if the symbol itself has the UDA, tack it on to the front of the list static if (hasUDA!(symbol, attribute)) alias getSymbolsByUDA = AliasSeq!(symbol, membersWithUDA); else alias getSymbolsByUDA = membersWithUDA; } /// unittest { enum Attr; static struct A { @Attr int a; int b; @Attr void doStuff() {} void doOtherStuff() {} static struct Inner { // Not found by getSymbolsByUDA @Attr int c; } } // Finds both variables and functions with the attribute, but // doesn't include the variables and functions without it. static assert(getSymbolsByUDA!(A, Attr).length == 2); // Can access attributes on the symbols returned by getSymbolsByUDA. static assert(hasUDA!(getSymbolsByUDA!(A, Attr)[0], Attr)); static assert(hasUDA!(getSymbolsByUDA!(A, Attr)[1], Attr)); static struct UDA { string name; } static struct B { @UDA("X") int x; @UDA("Y") int y; @(100) int z; } // Finds both UDA attributes. static assert(getSymbolsByUDA!(B, UDA).length == 2); // Finds one `100` attribute. static assert(getSymbolsByUDA!(B, 100).length == 1); // Can get the value of the UDA from the return value static assert(getUDAs!(getSymbolsByUDA!(B, UDA)[0], UDA)[0].name == "X"); @UDA("A") static struct C { @UDA("B") int d; } // Also checks the symbol itself static assert(getSymbolsByUDA!(C, UDA).length == 2); static assert(getSymbolsByUDA!(C, UDA)[0].stringof == "C"); static assert(getSymbolsByUDA!(C, UDA)[1].stringof == "d"); } // #15335: getSymbolsByUDA fails if type has private members unittest { // HasPrivateMembers has, well, private members, one of which has a UDA. import std.internal.test.uda; static assert(getSymbolsByUDA!(HasPrivateMembers, Attr).length == 2); static assert(hasUDA!(getSymbolsByUDA!(HasPrivateMembers, Attr)[0], Attr)); static assert(hasUDA!(getSymbolsByUDA!(HasPrivateMembers, Attr)[1], Attr)); } /** Returns: $(D true) iff all types $(D T) are the same. */ template allSameType(T...) { static if (T.length <= 1) { enum bool allSameType = true; } else { enum bool allSameType = is(T[0] == T[1]) && allSameType!(T[1..$]); } } /// unittest { static assert(allSameType!(int, int)); static assert(allSameType!(int, int, int)); static assert(allSameType!(float, float, float)); static assert(!allSameType!(int, double)); static assert(!allSameType!(int, float, double)); static assert(!allSameType!(int, float, double, real)); static assert(!allSameType!(short, int, float, double, real)); } /** Returns: $(D true) iff the type $(D T) can be tested in an $(D if)-expression, that is if $(D if (pred(T.init)) {}) is compilable. */ enum ifTestable(T, alias pred = a => a) = __traits(compiles, { if (pred(T.init)) {} }); unittest { import std.meta : AliasSeq; static assert(allSatisfy!(ifTestable, AliasSeq!(bool, int, float, double, string))); struct BoolWrapper { bool value; } static assert(!ifTestable!(bool, a => BoolWrapper(a))); } ldc-1.1.0-beta3-src/runtime/phobos/std/parallelism.d0000664000175000017500000041076612776215007020376 0ustar kaikai/** $(D std._parallelism) implements high-level primitives for SMP _parallelism. These include parallel foreach, parallel reduce, parallel eager map, pipelining and future/promise _parallelism. $(D std._parallelism) is recommended when the same operation is to be executed in parallel on different data, or when a function is to be executed in a background thread and its result returned to a well-defined main thread. For communication between arbitrary threads, see $(D std.concurrency). $(D std._parallelism) is based on the concept of a $(D Task). A $(D Task) is an object that represents the fundamental unit of work in this library and may be executed in parallel with any other $(D Task). Using $(D Task) directly allows programming with a future/promise paradigm. All other supported _parallelism paradigms (parallel foreach, map, reduce, pipelining) represent an additional level of abstraction over $(D Task). They automatically create one or more $(D Task) objects, or closely related types that are conceptually identical but not part of the public API. After creation, a $(D Task) may be executed in a new thread, or submitted to a $(D TaskPool) for execution. A $(D TaskPool) encapsulates a task queue and its worker threads. Its purpose is to efficiently map a large number of $(D Task)s onto a smaller number of threads. A task queue is a FIFO queue of $(D Task) objects that have been submitted to the $(D TaskPool) and are awaiting execution. A worker thread is a thread that is associated with exactly one task queue. It executes the $(D Task) at the front of its queue when the queue has work available, or sleeps when no work is available. Each task queue is associated with zero or more worker threads. If the result of a $(D Task) is needed before execution by a worker thread has begun, the $(D Task) can be removed from the task queue and executed immediately in the thread where the result is needed. Warning: Unless marked as $(D @trusted) or $(D @safe), artifacts in this module allow implicit data sharing between threads and cannot guarantee that client code is free from low level data races. Synopsis: --- import std.algorithm, std.parallelism, std.range; void main() { // Parallel reduce can be combined with // std.algorithm.map to interesting effect. // The following example (thanks to Russel Winder) // calculates pi by quadrature using // std.algorithm.map and TaskPool.reduce. // getTerm is evaluated in parallel as needed by // TaskPool.reduce. // // Timings on an Athlon 64 X2 dual core machine: // // TaskPool.reduce: 12.170 s // std.algorithm.reduce: 24.065 s immutable n = 1_000_000_000; immutable delta = 1.0 / n; real getTerm(int i) { immutable x = ( i - 0.5 ) * delta; return delta / ( 1.0 + x * x ) ; } immutable pi = 4.0 * taskPool.reduce!"a + b"( std.algorithm.map!getTerm(iota(n)) ); } --- Source: $(PHOBOSSRC std/_parallelism.d) Author: David Simcha Copyright: Copyright (c) 2009-2011, David Simcha. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0) */ module std.parallelism; import core.atomic; import core.exception; import core.memory; import core.sync.condition; import core.thread; import std.algorithm; import std.conv; import std.exception; import std.functional; import std.math; import std.meta; import std.range; import std.traits; import std.typecons; version(OSX) { version = useSysctlbyname; } else version(FreeBSD) { version = useSysctlbyname; } else version(NetBSD) { version = useSysctlbyname; } version(Windows) { // BUGS: Only works on Windows 2000 and above. shared static this() { import core.sys.windows.windows; SYSTEM_INFO si; GetSystemInfo(&si); totalCPUs = max(1, cast(uint) si.dwNumberOfProcessors); } } else version(linux) { import core.sys.posix.unistd; shared static this() { totalCPUs = cast(uint) sysconf(_SC_NPROCESSORS_ONLN); } } else version(Solaris) { import core.sys.posix.unistd; shared static this() { totalCPUs = cast(uint) sysconf(_SC_NPROCESSORS_ONLN); } } else version(useSysctlbyname) { extern(C) int sysctlbyname( const char *, void *, size_t *, void *, size_t ); shared static this() { version(OSX) { auto nameStr = "machdep.cpu.core_count\0".ptr; } else version(FreeBSD) { auto nameStr = "hw.ncpu\0".ptr; } else version(NetBSD) { auto nameStr = "hw.ncpu\0".ptr; } uint ans; size_t len = uint.sizeof; sysctlbyname(nameStr, &ans, &len, null, 0); totalCPUs = ans; } } else { static assert(0, "Don't know how to get N CPUs on this OS."); } immutable size_t cacheLineSize; shared static this() { import core.cpuid : datacache; size_t lineSize = 0; foreach (cachelevel; datacache) { if (cachelevel.lineSize > lineSize && cachelevel.lineSize < uint.max) { lineSize = cachelevel.lineSize; } } cacheLineSize = lineSize; } /* Atomics code. These forward to core.atomic, but are written like this for two reasons: 1. They used to actually contain ASM code and I don' want to have to change to directly calling core.atomic in a zillion different places. 2. core.atomic has some misc. issues that make my use cases difficult without wrapping it. If I didn't wrap it, casts would be required basically everywhere. */ private void atomicSetUbyte(T)(ref T stuff, T newVal) if (__traits(isIntegral, T) && is(T : ubyte)) { //core.atomic.cas(cast(shared) &stuff, stuff, newVal); atomicStore(*(cast(shared) &stuff), newVal); } private ubyte atomicReadUbyte(T)(ref T val) if (__traits(isIntegral, T) && is(T : ubyte)) { return atomicLoad(*(cast(shared) &val)); } // This gets rid of the need for a lot of annoying casts in other parts of the // code, when enums are involved. private bool atomicCasUbyte(T)(ref T stuff, T testVal, T newVal) if (__traits(isIntegral, T) && is(T : ubyte)) { return core.atomic.cas(cast(shared) &stuff, testVal, newVal); } /*--------------------- Generic helper functions, etc.------------------------*/ private template MapType(R, functions...) { static assert(functions.length); ElementType!R e = void; alias MapType = typeof(adjoin!(staticMap!(unaryFun, functions))(e)); } private template ReduceType(alias fun, R, E) { alias ReduceType = typeof(binaryFun!fun(E.init, ElementType!R.init)); } private template noUnsharedAliasing(T) { enum bool noUnsharedAliasing = !hasUnsharedAliasing!T; } // This template tests whether a function may be executed in parallel from // @safe code via Task.executeInNewThread(). There is an additional // requirement for executing it via a TaskPool. (See isSafeReturn). private template isSafeTask(F) { enum bool isSafeTask = (functionAttributes!F & (FunctionAttribute.safe | FunctionAttribute.trusted)) != 0 && (functionAttributes!F & FunctionAttribute.ref_) == 0 && (isFunctionPointer!F || !hasUnsharedAliasing!F) && allSatisfy!(noUnsharedAliasing, Parameters!F); } unittest { alias F1 = void function() @safe; alias F2 = void function(); alias F3 = void function(uint, string) @trusted; alias F4 = void function(uint, char[]); static assert( isSafeTask!F1); static assert(!isSafeTask!F2); static assert( isSafeTask!F3); static assert(!isSafeTask!F4); alias F5 = uint[] function(uint, string) pure @trusted; static assert( isSafeTask!F5); } // This function decides whether Tasks that meet all of the other requirements // for being executed from @safe code can be executed on a TaskPool. // When executing via TaskPool, it's theoretically possible // to return a value that is also pointed to by a worker thread's thread local // storage. When executing from executeInNewThread(), the thread that executed // the Task is terminated by the time the return value is visible in the calling // thread, so this is a non-issue. It's also a non-issue for pure functions // since they can't read global state. private template isSafeReturn(T) { static if(!hasUnsharedAliasing!(T.ReturnType)) { enum isSafeReturn = true; } else static if(T.isPure) { enum isSafeReturn = true; } else { enum isSafeReturn = false; } } private template randAssignable(R) { enum randAssignable = isRandomAccessRange!R && hasAssignableElements!R; } private enum TaskStatus : ubyte { notStarted, inProgress, done } private template AliasReturn(alias fun, T...) { alias AliasReturn = typeof({ T args; return fun(args); }); } // Should be private, but std.algorithm.reduce is used in the zero-thread case // and won't work w/ private. template reduceAdjoin(functions...) { static if(functions.length == 1) { alias reduceAdjoin = binaryFun!(functions[0]); } else { T reduceAdjoin(T, U)(T lhs, U rhs) { alias funs = staticMap!(binaryFun, functions); foreach(i, Unused; typeof(lhs.expand)) { lhs.expand[i] = funs[i](lhs.expand[i], rhs); } return lhs; } } } private template reduceFinish(functions...) { static if(functions.length == 1) { alias reduceFinish = binaryFun!(functions[0]); } else { T reduceFinish(T)(T lhs, T rhs) { alias funs = staticMap!(binaryFun, functions); foreach(i, Unused; typeof(lhs.expand)) { lhs.expand[i] = funs[i](lhs.expand[i], rhs.expand[i]); } return lhs; } } } private template isRoundRobin(R : RoundRobinBuffer!(C1, C2), C1, C2) { enum isRoundRobin = true; } private template isRoundRobin(T) { enum isRoundRobin = false; } unittest { static assert( isRoundRobin!(RoundRobinBuffer!(void delegate(char[]), bool delegate()))); static assert(!isRoundRobin!(uint)); } // This is the base "class" for all of the other tasks. Using C-style // polymorphism to allow more direct control over memory allocation, etc. private struct AbstractTask { AbstractTask* prev; AbstractTask* next; // Pointer to a function that executes this task. void function(void*) runTask; Throwable exception; ubyte taskStatus = TaskStatus.notStarted; bool done() @property { if(atomicReadUbyte(taskStatus) == TaskStatus.done) { if(exception) { throw exception; } return true; } return false; } void job() { runTask(&this); } } /** $(D Task) represents the fundamental unit of work. A $(D Task) may be executed in parallel with any other $(D Task). Using this struct directly allows future/promise _parallelism. In this paradigm, a function (or delegate or other callable) is executed in a thread other than the one it was called from. The calling thread does not block while the function is being executed. A call to $(D workForce), $(D yieldForce), or $(D spinForce) is used to ensure that the $(D Task) has finished executing and to obtain the return value, if any. These functions and $(D done) also act as full memory barriers, meaning that any memory writes made in the thread that executed the $(D Task) are guaranteed to be visible in the calling thread after one of these functions returns. The $(XREF parallelism, task) and $(XREF parallelism, scopedTask) functions can be used to create an instance of this struct. See $(D task) for usage examples. Function results are returned from $(D yieldForce), $(D spinForce) and $(D workForce) by ref. If $(D fun) returns by ref, the reference will point to the returned reference of $(D fun). Otherwise it will point to a field in this struct. Copying of this struct is disabled, since it would provide no useful semantics. If you want to pass this struct around, you should do so by reference or pointer. Bugs: Changes to $(D ref) and $(D out) arguments are not propagated to the call site, only to $(D args) in this struct. */ struct Task(alias fun, Args...) { AbstractTask base = {runTask : &impl}; alias base this; private @property AbstractTask* basePtr() { return &base; } private static void impl(void* myTask) { import std.algorithm.internal : addressOf; Task* myCastedTask = cast(typeof(this)*) myTask; static if(is(ReturnType == void)) { fun(myCastedTask._args); } else static if(is(typeof(addressOf(fun(myCastedTask._args))))) { myCastedTask.returnVal = addressOf(fun(myCastedTask._args)); } else { myCastedTask.returnVal = fun(myCastedTask._args); } } private TaskPool pool; private bool isScoped; // True if created with scopedTask. Args _args; /** The arguments the function was called with. Changes to $(D out) and $(D ref) arguments will be visible here. */ static if(__traits(isSame, fun, run)) { alias args = _args[1..$]; } else { alias args = _args; } // The purpose of this code is to decide whether functions whose // return values have unshared aliasing can be executed via // TaskPool from @safe code. See isSafeReturn. static if(__traits(isSame, fun, run)) { static if(isFunctionPointer!(_args[0])) { private enum bool isPure = functionAttributes!(Args[0]) & FunctionAttribute.pure_; } else { // BUG: Should check this for delegates too, but std.traits // apparently doesn't allow this. isPure is irrelevant // for delegates, at least for now since shared delegates // don't work. private enum bool isPure = false; } } else { // We already know that we can't execute aliases in @safe code, so // just put a dummy value here. private enum bool isPure = false; } /** The return type of the function called by this $(D Task). This can be $(D void). */ alias ReturnType = typeof(fun(_args)); static if(!is(ReturnType == void)) { static if(is(typeof(&fun(_args)))) { // Ref return. ReturnType* returnVal; ref ReturnType fixRef(ReturnType* val) { return *val; } } else { ReturnType returnVal; ref ReturnType fixRef(ref ReturnType val) { return val; } } } private void enforcePool() { enforce(this.pool !is null, "Job not submitted yet."); } static if(Args.length > 0) { private this(Args args) { _args = args; } } // Work around DMD bug 6588, allow immutable elements. static if(allSatisfy!(isAssignable, Args)) { typeof(this) opAssign(typeof(this) rhs) { foreach(i, Type; typeof(this.tupleof)) { this.tupleof[i] = rhs.tupleof[i]; } return this; } } else { @disable typeof(this) opAssign(typeof(this) rhs) { assert(0); } } /** If the $(D Task) isn't started yet, execute it in the current thread. If it's done, return its return value, if any. If it's in progress, busy spin until it's done, then return the return value. If it threw an exception, rethrow that exception. This function should be used when you expect the result of the $(D Task) to be available on a timescale shorter than that of an OS context switch. */ @property ref ReturnType spinForce() @trusted { enforcePool(); this.pool.tryDeleteExecute(basePtr); while(atomicReadUbyte(this.taskStatus) != TaskStatus.done) {} if(exception) { throw exception; } static if(!is(ReturnType == void)) { return fixRef(this.returnVal); } } /** If the $(D Task) isn't started yet, execute it in the current thread. If it's done, return its return value, if any. If it's in progress, wait on a condition variable. If it threw an exception, rethrow that exception. This function should be used for expensive functions, as waiting on a condition variable introduces latency, but avoids wasted CPU cycles. */ @property ref ReturnType yieldForce() @trusted { enforcePool(); this.pool.tryDeleteExecute(basePtr); if(done) { static if(is(ReturnType == void)) { return; } else { return fixRef(this.returnVal); } } pool.waiterLock(); scope(exit) pool.waiterUnlock(); while(atomicReadUbyte(this.taskStatus) != TaskStatus.done) { pool.waitUntilCompletion(); } if(exception) { throw exception; } static if(!is(ReturnType == void)) { return fixRef(this.returnVal); } } /** If this $(D Task) was not started yet, execute it in the current thread. If it is finished, return its result. If it is in progress, execute any other $(D Task) from the $(D TaskPool) instance that this $(D Task) was submitted to until this one is finished. If it threw an exception, rethrow that exception. If no other tasks are available or this $(D Task) was executed using $(D executeInNewThread), wait on a condition variable. */ @property ref ReturnType workForce() @trusted { enforcePool(); this.pool.tryDeleteExecute(basePtr); while(true) { if(done) // done() implicitly checks for exceptions. { static if(is(ReturnType == void)) { return; } else { return fixRef(this.returnVal); } } AbstractTask* job; { // Locking explicitly and calling popNoSync() because // pop() waits on a condition variable if there are no Tasks // in the queue. pool.queueLock(); scope(exit) pool.queueUnlock(); job = pool.popNoSync(); } if(job !is null) { version(verboseUnittest) { stderr.writeln("Doing workForce work."); } pool.doJob(job); if(done) { static if(is(ReturnType == void)) { return; } else { return fixRef(this.returnVal); } } } else { version(verboseUnittest) { stderr.writeln("Yield from workForce."); } return yieldForce; } } } /** Returns $(D true) if the $(D Task) is finished executing. Throws: Rethrows any exception thrown during the execution of the $(D Task). */ @property bool done() @trusted { // Explicitly forwarded for documentation purposes. return base.done; } /** Create a new thread for executing this $(D Task), execute it in the newly created thread, then terminate the thread. This can be used for future/promise parallelism. An explicit priority may be given to the $(D Task). If one is provided, its value is forwarded to $(D core.thread.Thread.priority). See $(XREF parallelism, task) for usage example. */ void executeInNewThread() @trusted { pool = new TaskPool(basePtr); } /// Ditto void executeInNewThread(int priority) @trusted { pool = new TaskPool(basePtr, priority); } @safe ~this() { if(isScoped && pool !is null && taskStatus != TaskStatus.done) { yieldForce; } } // When this is uncommented, it somehow gets called on returning from // scopedTask even though the struct shouldn't be getting copied. //@disable this(this) {} } // Calls $(D fpOrDelegate) with $(D args). This is an // adapter that makes $(D Task) work with delegates, function pointers and // functors instead of just aliases. ReturnType!F run(F, Args...)(F fpOrDelegate, ref Args args) { return fpOrDelegate(args); } /** Creates a $(D Task) on the GC heap that calls an alias. This may be executed via $(D Task.executeInNewThread) or by submitting to a $(XREF parallelism, TaskPool). A globally accessible instance of $(D TaskPool) is provided by $(XREF parallelism, taskPool). Returns: A pointer to the $(D Task). Example: --- // Read two files into memory at the same time. import std.file; void main() { // Create and execute a Task for reading // foo.txt. auto file1Task = task!read("foo.txt"); file1Task.executeInNewThread(); // Read bar.txt in parallel. auto file2Data = read("bar.txt"); // Get the results of reading foo.txt. auto file1Data = file1Task.yieldForce; } --- --- // Sorts an array using a parallel quick sort algorithm. // The first partition is done serially. Both recursion // branches are then executed in parallel. // // Timings for sorting an array of 1,000,000 doubles on // an Athlon 64 X2 dual core machine: // // This implementation: 176 milliseconds. // Equivalent serial implementation: 280 milliseconds void parallelSort(T)(T[] data) { // Sort small subarrays serially. if(data.length < 100) { std.algorithm.sort(data); return; } // Partition the array. swap(data[$ / 2], data[$ - 1]); auto pivot = data[$ - 1]; bool lessThanPivot(T elem) { return elem < pivot; } auto greaterEqual = partition!lessThanPivot(data[0..$ - 1]); swap(data[$ - greaterEqual.length - 1], data[$ - 1]); auto less = data[0..$ - greaterEqual.length - 1]; greaterEqual = data[$ - greaterEqual.length..$]; // Execute both recursion branches in parallel. auto recurseTask = task!parallelSort(greaterEqual); taskPool.put(recurseTask); parallelSort(less); recurseTask.yieldForce; } --- */ auto task(alias fun, Args...)(Args args) { return new Task!(fun, Args)(args); } /** Creates a $(D Task) on the GC heap that calls a function pointer, delegate, or class/struct with overloaded opCall. Example: --- // Read two files in at the same time again, // but this time use a function pointer instead // of an alias to represent std.file.read. import std.file; void main() { // Create and execute a Task for reading // foo.txt. auto file1Task = task(&read, "foo.txt"); file1Task.executeInNewThread(); // Read bar.txt in parallel. auto file2Data = read("bar.txt"); // Get the results of reading foo.txt. auto file1Data = file1Task.yieldForce; } --- Notes: This function takes a non-scope delegate, meaning it can be used with closures. If you can't allocate a closure due to objects on the stack that have scoped destruction, see $(D scopedTask), which takes a scope delegate. */ auto task(F, Args...)(F delegateOrFp, Args args) if(is(typeof(delegateOrFp(args))) && !isSafeTask!F) { return new Task!(run, F, Args)(delegateOrFp, args); } /** Version of $(D task) usable from $(D @safe) code. Usage mechanics are identical to the non-@safe case, but safety introduces some restrictions: 1. $(D fun) must be @safe or @trusted. 2. $(D F) must not have any unshared aliasing as defined by $(XREF traits, hasUnsharedAliasing). This means it may not be an unshared delegate or a non-shared class or struct with overloaded $(D opCall). This also precludes accepting template alias parameters. 3. $(D Args) must not have unshared aliasing. 4. $(D fun) must not return by reference. 5. The return type must not have unshared aliasing unless $(D fun) is $(D pure) or the $(D Task) is executed via $(D executeInNewThread) instead of using a $(D TaskPool). */ @trusted auto task(F, Args...)(F fun, Args args) if(is(typeof(fun(args))) && isSafeTask!F) { return new Task!(run, F, Args)(fun, args); } /** These functions allow the creation of $(D Task) objects on the stack rather than the GC heap. The lifetime of a $(D Task) created by $(D scopedTask) cannot exceed the lifetime of the scope it was created in. $(D scopedTask) might be preferred over $(D task): 1. When a $(D Task) that calls a delegate is being created and a closure cannot be allocated due to objects on the stack that have scoped destruction. The delegate overload of $(D scopedTask) takes a $(D scope) delegate. 2. As a micro-optimization, to avoid the heap allocation associated with $(D task) or with the creation of a closure. Usage is otherwise identical to $(D task). Notes: $(D Task) objects created using $(D scopedTask) will automatically call $(D Task.yieldForce) in their destructor if necessary to ensure the $(D Task) is complete before the stack frame they reside on is destroyed. */ auto scopedTask(alias fun, Args...)(Args args) { auto ret = Task!(fun, Args)(args); ret.isScoped = true; return ret; } /// Ditto auto scopedTask(F, Args...)(scope F delegateOrFp, Args args) if(is(typeof(delegateOrFp(args))) && !isSafeTask!F) { auto ret = Task!(run, F, Args)(delegateOrFp, args); ret.isScoped = true; return ret; } /// Ditto @trusted auto scopedTask(F, Args...)(F fun, Args args) if(is(typeof(fun(args))) && isSafeTask!F) { auto ret = Task!(run, F, Args)(fun, args); ret.isScoped = true; return ret; } /** The total number of CPU cores available on the current machine, as reported by the operating system. */ immutable uint totalCPUs; /* This class serves two purposes: 1. It distinguishes std.parallelism threads from other threads so that the std.parallelism daemon threads can be terminated. 2. It adds a reference to the pool that the thread is a member of, which is also necessary to allow the daemon threads to be properly terminated. */ private final class ParallelismThread : Thread { this(void delegate() dg) { super(dg); } TaskPool pool; } // Kill daemon threads. shared static ~this() { auto allThreads = Thread.getAll(); foreach(thread; allThreads) { auto pthread = cast(ParallelismThread) thread; if(pthread is null) continue; auto pool = pthread.pool; if(!pool.isDaemon) continue; pool.stop(); pthread.join(); } } /** This class encapsulates a task queue and a set of worker threads. Its purpose is to efficiently map a large number of $(D Task)s onto a smaller number of threads. A task queue is a FIFO queue of $(D Task) objects that have been submitted to the $(D TaskPool) and are awaiting execution. A worker thread is a thread that executes the $(D Task) at the front of the queue when one is available and sleeps when the queue is empty. This class should usually be used via the global instantiation available via the $(XREF parallelism, taskPool) property. Occasionally it is useful to explicitly instantiate a $(D TaskPool): 1. When you want $(D TaskPool) instances with multiple priorities, for example a low priority pool and a high priority pool. 2. When the threads in the global task pool are waiting on a synchronization primitive (for example a mutex), and you want to parallelize the code that needs to run before these threads can be resumed. */ final class TaskPool { private: // A pool can either be a regular pool or a single-task pool. A // single-task pool is a dummy pool that's fired up for // Task.executeInNewThread(). bool isSingleTask; ParallelismThread[] pool; Thread singleTaskThread; AbstractTask* head; AbstractTask* tail; PoolState status = PoolState.running; Condition workerCondition; Condition waiterCondition; Mutex queueMutex; Mutex waiterMutex; // For waiterCondition // The instanceStartIndex of the next instance that will be created. __gshared static size_t nextInstanceIndex = 1; // The index of the current thread. static size_t threadIndex; // The index of the first thread in this instance. immutable size_t instanceStartIndex; // The index that the next thread to be initialized in this pool will have. size_t nextThreadIndex; enum PoolState : ubyte { running, finishing, stopNow } void doJob(AbstractTask* job) { assert(job.taskStatus == TaskStatus.inProgress); assert(job.next is null); assert(job.prev is null); scope(exit) { if(!isSingleTask) { waiterLock(); scope(exit) waiterUnlock(); notifyWaiters(); } } try { job.job(); } catch(Throwable e) { job.exception = e; } atomicSetUbyte(job.taskStatus, TaskStatus.done); } // This function is used for dummy pools created by Task.executeInNewThread(). void doSingleTask() { // No synchronization. Pool is guaranteed to only have one thread, // and the queue is submitted to before this thread is created. assert(head); auto t = head; t.next = t.prev = head = null; doJob(t); } // This function performs initialization for each thread that affects // thread local storage and therefore must be done from within the // worker thread. It then calls executeWorkLoop(). void startWorkLoop() { // Initialize thread index. { queueLock(); scope(exit) queueUnlock(); threadIndex = nextThreadIndex; nextThreadIndex++; } executeWorkLoop(); } // This is the main work loop that worker threads spend their time in // until they terminate. It's also entered by non-worker threads when // finish() is called with the blocking variable set to true. void executeWorkLoop() { while(atomicReadUbyte(status) != PoolState.stopNow) { AbstractTask* task = pop(); if (task is null) { if(atomicReadUbyte(status) == PoolState.finishing) { atomicSetUbyte(status, PoolState.stopNow); return; } } else { doJob(task); } } } // Pop a task off the queue. AbstractTask* pop() { queueLock(); scope(exit) queueUnlock(); auto ret = popNoSync(); while(ret is null && status == PoolState.running) { wait(); ret = popNoSync(); } return ret; } AbstractTask* popNoSync() out(returned) { /* If task.prev and task.next aren't null, then another thread * can try to delete this task from the pool after it's * alreadly been deleted/popped. */ if(returned !is null) { assert(returned.next is null); assert(returned.prev is null); } } body { if(isSingleTask) return null; AbstractTask* returned = head; if (head !is null) { head = head.next; returned.prev = null; returned.next = null; returned.taskStatus = TaskStatus.inProgress; } if(head !is null) { head.prev = null; } return returned; } // Push a task onto the queue. void abstractPut(AbstractTask* task) { queueLock(); scope(exit) queueUnlock(); abstractPutNoSync(task); } void abstractPutNoSync(AbstractTask* task) in { assert(task); } out { assert(tail.prev !is tail); assert(tail.next is null, text(tail.prev, '\t', tail.next)); if(tail.prev !is null) { assert(tail.prev.next is tail, text(tail.prev, '\t', tail.next)); } } body { // Not using enforce() to save on function call overhead since this // is a performance critical function. if(status != PoolState.running) { throw new Error( "Cannot submit a new task to a pool after calling " ~ "finish() or stop()." ); } task.next = null; if (head is null) //Queue is empty. { head = task; tail = task; tail.prev = null; } else { assert(tail); task.prev = tail; tail.next = task; tail = task; } notify(); } void abstractPutGroupNoSync(AbstractTask* h, AbstractTask* t) { if(status != PoolState.running) { throw new Error( "Cannot submit a new task to a pool after calling " ~ "finish() or stop()." ); } if(head is null) { head = h; tail = t; } else { h.prev = tail; tail.next = h; tail = t; } notifyAll(); } void tryDeleteExecute(AbstractTask* toExecute) { if(isSingleTask) return; if( !deleteItem(toExecute) ) { return; } try { toExecute.job(); } catch(Exception e) { toExecute.exception = e; } atomicSetUbyte(toExecute.taskStatus, TaskStatus.done); } bool deleteItem(AbstractTask* item) { queueLock(); scope(exit) queueUnlock(); return deleteItemNoSync(item); } bool deleteItemNoSync(AbstractTask* item) { if(item.taskStatus != TaskStatus.notStarted) { return false; } item.taskStatus = TaskStatus.inProgress; if(item is head) { // Make sure head gets set properly. popNoSync(); return true; } if(item is tail) { tail = tail.prev; if(tail !is null) { tail.next = null; } item.next = null; item.prev = null; return true; } if(item.next !is null) { assert(item.next.prev is item); // Check queue consistency. item.next.prev = item.prev; } if(item.prev !is null) { assert(item.prev.next is item); // Check queue consistency. item.prev.next = item.next; } item.next = null; item.prev = null; return true; } void queueLock() { assert(queueMutex); if(!isSingleTask) queueMutex.lock(); } void queueUnlock() { assert(queueMutex); if(!isSingleTask) queueMutex.unlock(); } void waiterLock() { if(!isSingleTask) waiterMutex.lock(); } void waiterUnlock() { if(!isSingleTask) waiterMutex.unlock(); } void wait() { if(!isSingleTask) workerCondition.wait(); } void notify() { if(!isSingleTask) workerCondition.notify(); } void notifyAll() { if(!isSingleTask) workerCondition.notifyAll(); } void waitUntilCompletion() { if(isSingleTask) { singleTaskThread.join(); } else { waiterCondition.wait(); } } void notifyWaiters() { if(!isSingleTask) waiterCondition.notifyAll(); } // Private constructor for creating dummy pools that only have one thread, // only execute one Task, and then terminate. This is used for // Task.executeInNewThread(). this(AbstractTask* task, int priority = int.max) { assert(task); // Dummy value, not used. instanceStartIndex = 0; this.isSingleTask = true; task.taskStatus = TaskStatus.inProgress; this.head = task; singleTaskThread = new Thread(&doSingleTask); singleTaskThread.start(); // Disabled until writing code to support // running thread with specified priority // See https://d.puremagic.com/issues/show_bug.cgi?id=8960 /*if(priority != int.max) { singleTaskThread.priority = priority; }*/ } public: // This is used in parallel_algorithm but is too unstable to document // as public API. size_t defaultWorkUnitSize(size_t rangeLen) const @safe pure nothrow { if(this.size == 0) { return rangeLen; } immutable size_t eightSize = 4 * (this.size + 1); auto ret = (rangeLen / eightSize) + ((rangeLen % eightSize == 0) ? 0 : 1); return max(ret, 1); } /** Default constructor that initializes a $(D TaskPool) with $(D totalCPUs) - 1 worker threads. The minus 1 is included because the main thread will also be available to do work. Note: On single-core machines, the primitives provided by $(D TaskPool) operate transparently in single-threaded mode. */ this() @trusted { this(totalCPUs - 1); } /** Allows for custom number of worker threads. */ this(size_t nWorkers) @trusted { synchronized(typeid(TaskPool)) { instanceStartIndex = nextInstanceIndex; // The first worker thread to be initialized will have this index, // and will increment it. The second worker to be initialized will // have this index plus 1. nextThreadIndex = instanceStartIndex; nextInstanceIndex += nWorkers; } queueMutex = new Mutex(this); waiterMutex = new Mutex(); workerCondition = new Condition(queueMutex); waiterCondition = new Condition(waiterMutex); pool = new ParallelismThread[nWorkers]; foreach(ref poolThread; pool) { poolThread = new ParallelismThread(&startWorkLoop); poolThread.pool = this; poolThread.start(); } } /** Implements a parallel foreach loop over a range. This works by implicitly creating and submitting one $(D Task) to the $(D TaskPool) for each worker thread. A work unit is a set of consecutive elements of $(D range) to be processed by a worker thread between communication with any other thread. The number of elements processed per work unit is controlled by the $(D workUnitSize) parameter. Smaller work units provide better load balancing, but larger work units avoid the overhead of communicating with other threads frequently to fetch the next work unit. Large work units also avoid false sharing in cases where the range is being modified. The less time a single iteration of the loop takes, the larger $(D workUnitSize) should be. For very expensive loop bodies, $(D workUnitSize) should be 1. An overload that chooses a default work unit size is also available. Example: --- // Find the logarithm of every number from 1 to // 10_000_000 in parallel. auto logs = new double[10_000_000]; // Parallel foreach works with or without an index // variable. It can be iterate by ref if range.front // returns by ref. // Iterate over logs using work units of size 100. foreach(i, ref elem; taskPool.parallel(logs, 100)) { elem = log(i + 1.0); } // Same thing, but use the default work unit size. // // Timings on an Athlon 64 X2 dual core machine: // // Parallel foreach: 388 milliseconds // Regular foreach: 619 milliseconds foreach(i, ref elem; taskPool.parallel(logs)) { elem = log(i + 1.0); } --- Notes: The memory usage of this implementation is guaranteed to be constant in $(D range.length). Breaking from a parallel foreach loop via a break, labeled break, labeled continue, return or goto statement throws a $(D ParallelForeachError). In the case of non-random access ranges, parallel foreach buffers lazily to an array of size $(D workUnitSize) before executing the parallel portion of the loop. The exception is that, if a parallel foreach is executed over a range returned by $(D asyncBuf) or $(D map), the copying is elided and the buffers are simply swapped. In this case $(D workUnitSize) is ignored and the work unit size is set to the buffer size of $(D range). A memory barrier is guaranteed to be executed on exit from the loop, so that results produced by all threads are visible in the calling thread. $(B Exception Handling): When at least one exception is thrown from inside a parallel foreach loop, the submission of additional $(D Task) objects is terminated as soon as possible, in a non-deterministic manner. All executing or enqueued work units are allowed to complete. Then, all exceptions that were thrown by any work unit are chained using $(D Throwable.next) and rethrown. The order of the exception chaining is non-deterministic. */ ParallelForeach!R parallel(R)(R range, size_t workUnitSize) { enforce(workUnitSize > 0, "workUnitSize must be > 0."); alias RetType = ParallelForeach!R; return RetType(this, range, workUnitSize); } /// Ditto ParallelForeach!R parallel(R)(R range) { static if(hasLength!R) { // Default work unit size is such that we would use 4x as many // slots as are in this thread pool. size_t workUnitSize = defaultWorkUnitSize(range.length); return parallel(range, workUnitSize); } else { // Just use a really, really dumb guess if the user is too lazy to // specify. return parallel(range, 512); } } /// template amap(functions...) { /** Eager parallel map. The eagerness of this function means it has less overhead than the lazily evaluated $(D TaskPool.map) and should be preferred where the memory requirements of eagerness are acceptable. $(D functions) are the functions to be evaluated, passed as template alias parameters in a style similar to $(XREF_PACK algorithm,iteration,map). The first argument must be a random access range. For performance reasons, amap will assume the range elements have not yet been initialized. Elements will be overwritten without calling a destructor nor doing an assignment. As such, the range must not contain meaningful data: either un-initialized objects, or objects in their $(D .init) state. --- auto numbers = iota(100_000_000.0); // Find the square roots of numbers. // // Timings on an Athlon 64 X2 dual core machine: // // Parallel eager map: 0.802 s // Equivalent serial implementation: 1.768 s auto squareRoots = taskPool.amap!sqrt(numbers); --- Immediately after the range argument, an optional work unit size argument may be provided. Work units as used by $(D amap) are identical to those defined for parallel foreach. If no work unit size is provided, the default work unit size is used. --- // Same thing, but make work unit size 100. auto squareRoots = taskPool.amap!sqrt(numbers, 100); --- An output range for returning the results may be provided as the last argument. If one is not provided, an array of the proper type will be allocated on the garbage collected heap. If one is provided, it must be a random access range with assignable elements, must have reference semantics with respect to assignment to its elements, and must have the same length as the input range. Writing to adjacent elements from different threads must be safe. --- // Same thing, but explicitly allocate an array // to return the results in. The element type // of the array may be either the exact type // returned by functions or an implicit conversion // target. auto squareRoots = new float[numbers.length]; taskPool.amap!sqrt(numbers, squareRoots); // Multiple functions, explicit output range, and // explicit work unit size. auto results = new Tuple!(float, real)[numbers.length]; taskPool.amap!(sqrt, log)(numbers, 100, results); --- Note: A memory barrier is guaranteed to be executed after all results are written but before returning so that results produced by all threads are visible in the calling thread. Tips: To perform the mapping operation in place, provide the same range for the input and output range. To parallelize the copying of a range with expensive to evaluate elements to an array, pass an identity function (a function that just returns whatever argument is provided to it) to $(D amap). $(B Exception Handling): When at least one exception is thrown from inside the map functions, the submission of additional $(D Task) objects is terminated as soon as possible, in a non-deterministic manner. All currently executing or enqueued work units are allowed to complete. Then, all exceptions that were thrown from any work unit are chained using $(D Throwable.next) and rethrown. The order of the exception chaining is non-deterministic. */ auto amap(Args...)(Args args) if(isRandomAccessRange!(Args[0])) { alias fun = adjoin!(staticMap!(unaryFun, functions)); alias range = args[0]; immutable len = range.length; static if( Args.length > 1 && randAssignable!(Args[$ - 1]) && is(MapType!(Args[0], functions) : ElementType!(Args[$ - 1])) ) { alias buf = args[$ - 1]; alias args2 = args[0..$ - 1]; alias Args2 = Args[0..$ - 1]; enforce(buf.length == len, text("Can't use a user supplied buffer that's the wrong ", "size. (Expected :", len, " Got: ", buf.length)); } else static if(randAssignable!(Args[$ - 1]) && Args.length > 1) { static assert(0, "Wrong buffer type."); } else { auto buf = uninitializedArray!(MapType!(Args[0], functions)[])(len); alias args2 = args; alias Args2 = Args; } if(!len) return buf; static if(isIntegral!(Args2[$ - 1])) { static assert(args2.length == 2); auto workUnitSize = cast(size_t) args2[1]; } else { static assert(args2.length == 1, Args); auto workUnitSize = defaultWorkUnitSize(range.length); } alias R = typeof(range); if(workUnitSize > len) { workUnitSize = len; } // Handle as a special case: if(size == 0) { size_t index = 0; foreach(elem; range) { emplaceRef(buf[index++], fun(elem)); } return buf; } // Effectively -1: chunkIndex + 1 == 0: shared size_t workUnitIndex = size_t.max; shared bool shouldContinue = true; void doIt() { scope(failure) { // If an exception is thrown, all threads should bail. atomicStore(shouldContinue, false); } while(atomicLoad(shouldContinue)) { immutable myUnitIndex = atomicOp!"+="(workUnitIndex, 1); immutable start = workUnitSize * myUnitIndex; if(start >= len) { atomicStore(shouldContinue, false); break; } immutable end = min(len, start + workUnitSize); static if (hasSlicing!R) { auto subrange = range[start..end]; foreach(i; start..end) { emplaceRef(buf[i], fun(subrange.front)); subrange.popFront(); } } else { foreach(i; start..end) { emplaceRef(buf[i], fun(range[i])); } } } } submitAndExecute(this, &doIt); return buf; } } /// template map(functions...) { /** A semi-lazy parallel map that can be used for pipelining. The map functions are evaluated for the first $(D bufSize) elements and stored in a buffer and made available to $(D popFront). Meanwhile, in the background a second buffer of the same size is filled. When the first buffer is exhausted, it is swapped with the second buffer and filled while the values from what was originally the second buffer are read. This implementation allows for elements to be written to the buffer without the need for atomic operations or synchronization for each write, and enables the mapping function to be evaluated efficiently in parallel. $(D map) has more overhead than the simpler procedure used by $(D amap) but avoids the need to keep all results in memory simultaneously and works with non-random access ranges. Params: source = The input range to be mapped. If $(D source) is not random access it will be lazily buffered to an array of size $(D bufSize) before the map function is evaluated. (For an exception to this rule, see Notes.) bufSize = The size of the buffer to store the evaluated elements. workUnitSize = The number of elements to evaluate in a single $(D Task). Must be less than or equal to $(D bufSize), and should be a fraction of $(D bufSize) such that all worker threads can be used. If the default of size_t.max is used, workUnitSize will be set to the pool-wide default. Returns: An input range representing the results of the map. This range has a length iff $(D source) has a length. Notes: If a range returned by $(D map) or $(D asyncBuf) is used as an input to $(D map), then as an optimization the copying from the output buffer of the first range to the input buffer of the second range is elided, even though the ranges returned by $(D map) and $(D asyncBuf) are non-random access ranges. This means that the $(D bufSize) parameter passed to the current call to $(D map) will be ignored and the size of the buffer will be the buffer size of $(D source). Example: --- // Pipeline reading a file, converting each line // to a number, taking the logarithms of the numbers, // and performing the additions necessary to find // the sum of the logarithms. auto lineRange = File("numberList.txt").byLine(); auto dupedLines = std.algorithm.map!"a.idup"(lineRange); auto nums = taskPool.map!(to!double)(dupedLines); auto logs = taskPool.map!log10(nums); double sum = 0; foreach(elem; logs) { sum += elem; } --- $(B Exception Handling): Any exceptions thrown while iterating over $(D source) or computing the map function are re-thrown on a call to $(D popFront) or, if thrown during construction, are simply allowed to propagate to the caller. In the case of exceptions thrown while computing the map function, the exceptions are chained as in $(D TaskPool.amap). */ auto map(S)(S source, size_t bufSize = 100, size_t workUnitSize = size_t.max) if(isInputRange!S) { enforce(workUnitSize == size_t.max || workUnitSize <= bufSize, "Work unit size must be smaller than buffer size."); alias fun = adjoin!(staticMap!(unaryFun, functions)); static final class Map { // This is a class because the task needs to be located on the // heap and in the non-random access case source needs to be on // the heap, too. private: enum bufferTrick = is(typeof(source.buf1)) && is(typeof(source.bufPos)) && is(typeof(source.doBufSwap())); alias E = MapType!(S, functions); E[] buf1, buf2; S source; TaskPool pool; Task!(run, E[] delegate(E[]), E[]) nextBufTask; size_t workUnitSize; size_t bufPos; bool lastTaskWaited; static if(isRandomAccessRange!S) { alias FromType = S; void popSource() { static if(__traits(compiles, source[0..source.length])) { source = source[min(buf1.length, source.length)..source.length]; } else static if(__traits(compiles, source[0..$])) { source = source[min(buf1.length, source.length)..$]; } else { static assert(0, "S must have slicing for Map." ~ " " ~ S.stringof ~ " doesn't."); } } } else static if(bufferTrick) { // Make sure we don't have the buffer recycling overload of // asyncBuf. static if( is(typeof(source.source)) && isRoundRobin!(typeof(source.source)) ) { static assert(0, "Cannot execute a parallel map on " ~ "the buffer recycling overload of asyncBuf." ); } alias FromType = typeof(source.buf1); FromType from; // Just swap our input buffer with source's output buffer. // No need to copy element by element. FromType dumpToFrom() { assert(source.buf1.length <= from.length); from.length = source.buf1.length; swap(source.buf1, from); // Just in case this source has been popped before // being sent to map: from = from[source.bufPos..$]; static if(is(typeof(source._length))) { source._length -= (from.length - source.bufPos); } source.doBufSwap(); return from; } } else { alias FromType = ElementType!S[]; // The temporary array that data is copied to before being // mapped. FromType from; FromType dumpToFrom() { assert(from !is null); size_t i; for(; !source.empty && i < from.length; source.popFront()) { from[i++] = source.front; } from = from[0..i]; return from; } } static if(hasLength!S) { size_t _length; public @property size_t length() const @safe pure nothrow { return _length; } } this(S source, size_t bufSize, size_t workUnitSize, TaskPool pool) { static if(bufferTrick) { bufSize = source.buf1.length; } buf1.length = bufSize; buf2.length = bufSize; static if(!isRandomAccessRange!S) { from.length = bufSize; } this.workUnitSize = (workUnitSize == size_t.max) ? pool.defaultWorkUnitSize(bufSize) : workUnitSize; this.source = source; this.pool = pool; static if(hasLength!S) { _length = source.length; } buf1 = fillBuf(buf1); submitBuf2(); } // The from parameter is a dummy and ignored in the random access // case. E[] fillBuf(E[] buf) { static if(isRandomAccessRange!S) { auto toMap = take(source, buf.length); scope(success) popSource(); } else { auto toMap = dumpToFrom(); } buf = buf[0..min(buf.length, toMap.length)]; // Handle as a special case: if(pool.size == 0) { size_t index = 0; foreach(elem; toMap) { buf[index++] = fun(elem); } return buf; } pool.amap!functions(toMap, workUnitSize, buf); return buf; } void submitBuf2() in { assert(nextBufTask.prev is null); assert(nextBufTask.next is null); } body { // Hack to reuse the task object. nextBufTask = typeof(nextBufTask).init; nextBufTask._args[0] = &fillBuf; nextBufTask._args[1] = buf2; pool.put(nextBufTask); } void doBufSwap() { if(lastTaskWaited) { // Then the source is empty. Signal it here. buf1 = null; buf2 = null; static if(!isRandomAccessRange!S) { from = null; } return; } buf2 = buf1; buf1 = nextBufTask.yieldForce; bufPos = 0; if(source.empty) { lastTaskWaited = true; } else { submitBuf2(); } } public: @property auto front() { return buf1[bufPos]; } void popFront() { static if(hasLength!S) { _length--; } bufPos++; if(bufPos >= buf1.length) { doBufSwap(); } } static if(std.range.isInfinite!S) { enum bool empty = false; } else { bool empty() @property { // popFront() sets this when source is empty return buf1.length == 0; } } } return new Map(source, bufSize, workUnitSize, this); } } /** Given a $(D source) range that is expensive to iterate over, returns an input range that asynchronously buffers the contents of $(D source) into a buffer of $(D bufSize) elements in a worker thread, while making previously buffered elements from a second buffer, also of size $(D bufSize), available via the range interface of the returned object. The returned range has a length iff $(D hasLength!S). $(D asyncBuf) is useful, for example, when performing expensive operations on the elements of ranges that represent data on a disk or network. Example: --- import std.conv, std.stdio; void main() { // Fetch lines of a file in a background thread // while processing previously fetched lines, // dealing with byLine's buffer recycling by // eagerly duplicating every line. auto lines = File("foo.txt").byLine(); auto duped = std.algorithm.map!"a.idup"(lines); // Fetch more lines in the background while we // process the lines already read into memory // into a matrix of doubles. double[][] matrix; auto asyncReader = taskPool.asyncBuf(duped); foreach(line; asyncReader) { auto ls = line.split("\t"); matrix ~= to!(double[])(ls); } } --- $(B Exception Handling): Any exceptions thrown while iterating over $(D source) are re-thrown on a call to $(D popFront) or, if thrown during construction, simply allowed to propagate to the caller. */ auto asyncBuf(S)(S source, size_t bufSize = 100) if(isInputRange!S) { static final class AsyncBuf { // This is a class because the task and source both need to be on // the heap. // The element type of S. alias E = ElementType!S; // Needs to be here b/c of forward ref bugs. private: E[] buf1, buf2; S source; TaskPool pool; Task!(run, E[] delegate(E[]), E[]) nextBufTask; size_t bufPos; bool lastTaskWaited; static if(hasLength!S) { size_t _length; // Available if hasLength!S. public @property size_t length() const @safe pure nothrow { return _length; } } this(S source, size_t bufSize, TaskPool pool) { buf1.length = bufSize; buf2.length = bufSize; this.source = source; this.pool = pool; static if(hasLength!S) { _length = source.length; } buf1 = fillBuf(buf1); submitBuf2(); } E[] fillBuf(E[] buf) { assert(buf !is null); size_t i; for(; !source.empty && i < buf.length; source.popFront()) { buf[i++] = source.front; } buf = buf[0..i]; return buf; } void submitBuf2() in { assert(nextBufTask.prev is null); assert(nextBufTask.next is null); } body { // Hack to reuse the task object. nextBufTask = typeof(nextBufTask).init; nextBufTask._args[0] = &fillBuf; nextBufTask._args[1] = buf2; pool.put(nextBufTask); } void doBufSwap() { if(lastTaskWaited) { // Then source is empty. Signal it here. buf1 = null; buf2 = null; return; } buf2 = buf1; buf1 = nextBufTask.yieldForce; bufPos = 0; if(source.empty) { lastTaskWaited = true; } else { submitBuf2(); } } public: E front() @property { return buf1[bufPos]; } void popFront() { static if(hasLength!S) { _length--; } bufPos++; if(bufPos >= buf1.length) { doBufSwap(); } } static if(std.range.isInfinite!S) { enum bool empty = false; } else { /// bool empty() @property { // popFront() sets this when source is empty: return buf1.length == 0; } } } return new AsyncBuf(source, bufSize, this); } /** Given a callable object $(D next) that writes to a user-provided buffer and a second callable object $(D empty) that determines whether more data is available to write via $(D next), returns an input range that asynchronously calls $(D next) with a set of size $(D nBuffers) of buffers and makes the results available in the order they were obtained via the input range interface of the returned object. Similarly to the input range overload of $(D asyncBuf), the first half of the buffers are made available via the range interface while the second half are filled and vice-versa. Params: next = A callable object that takes a single argument that must be an array with mutable elements. When called, $(D next) writes data to the array provided by the caller. empty = A callable object that takes no arguments and returns a type implicitly convertible to $(D bool). This is used to signify that no more data is available to be obtained by calling $(D next). initialBufSize = The initial size of each buffer. If $(D next) takes its array by reference, it may resize the buffers. nBuffers = The number of buffers to cycle through when calling $(D next). Example: --- // Fetch lines of a file in a background // thread while processing previously fetched // lines, without duplicating any lines. auto file = File("foo.txt"); void next(ref char[] buf) { file.readln(buf); } // Fetch more lines in the background while we // process the lines already read into memory // into a matrix of doubles. double[][] matrix; auto asyncReader = taskPool.asyncBuf(&next, &file.eof); foreach(line; asyncReader) { auto ls = line.split("\t"); matrix ~= to!(double[])(ls); } --- $(B Exception Handling): Any exceptions thrown while iterating over $(D range) are re-thrown on a call to $(D popFront). Warning: Using the range returned by this function in a parallel foreach loop will not work because buffers may be overwritten while the task that processes them is in queue. This is checked for at compile time and will result in a static assertion failure. */ auto asyncBuf(C1, C2)(C1 next, C2 empty, size_t initialBufSize = 0, size_t nBuffers = 100) if(is(typeof(C2.init()) : bool) && Parameters!C1.length == 1 && Parameters!C2.length == 0 && isArray!(Parameters!C1[0]) ) { auto roundRobin = RoundRobinBuffer!(C1, C2)(next, empty, initialBufSize, nBuffers); return asyncBuf(roundRobin, nBuffers / 2); } /// template reduce(functions...) { /** Parallel reduce on a random access range. Except as otherwise noted, usage is similar to $(XREF_PACK algorithm,iteration,_reduce). This function works by splitting the range to be reduced into work units, which are slices to be reduced in parallel. Once the results from all work units are computed, a final serial reduction is performed on these results to compute the final answer. Therefore, care must be taken to choose the seed value appropriately. Because the reduction is being performed in parallel, $(D functions) must be associative. For notational simplicity, let # be an infix operator representing $(D functions). Then, (a # b) # c must equal a # (b # c). Floating point addition is not associative even though addition in exact arithmetic is. Summing floating point numbers using this function may give different results than summing serially. However, for many practical purposes floating point addition can be treated as associative. Note that, since $(D functions) are assumed to be associative, additional optimizations are made to the serial portion of the reduction algorithm. These take advantage of the instruction level parallelism of modern CPUs, in addition to the thread-level parallelism that the rest of this module exploits. This can lead to better than linear speedups relative to $(XREF_PACK algorithm,iteration,_reduce), especially for fine-grained benchmarks like dot products. An explicit seed may be provided as the first argument. If provided, it is used as the seed for all work units and for the final reduction of results from all work units. Therefore, if it is not the identity value for the operation being performed, results may differ from those generated by $(XREF_PACK algorithm,iteration,_reduce) or depending on how many work units are used. The next argument must be the range to be reduced. --- // Find the sum of squares of a range in parallel, using // an explicit seed. // // Timings on an Athlon 64 X2 dual core machine: // // Parallel reduce: 72 milliseconds // Using std.algorithm.reduce instead: 181 milliseconds auto nums = iota(10_000_000.0f); auto sumSquares = taskPool.reduce!"a + b"( 0.0, std.algorithm.map!"a * a"(nums) ); --- If no explicit seed is provided, the first element of each work unit is used as a seed. For the final reduction, the result from the first work unit is used as the seed. --- // Find the sum of a range in parallel, using the first // element of each work unit as the seed. auto sum = taskPool.reduce!"a + b"(nums); --- An explicit work unit size may be specified as the last argument. Specifying too small a work unit size will effectively serialize the reduction, as the final reduction of the result of each work unit will dominate computation time. If $(D TaskPool.size) for this instance is zero, this parameter is ignored and one work unit is used. --- // Use a work unit size of 100. auto sum2 = taskPool.reduce!"a + b"(nums, 100); // Work unit size of 100 and explicit seed. auto sum3 = taskPool.reduce!"a + b"(0.0, nums, 100); --- Parallel reduce supports multiple functions, like $(D std.algorithm.reduce). --- // Find both the min and max of nums. auto minMax = taskPool.reduce!(min, max)(nums); assert(minMax[0] == reduce!min(nums)); assert(minMax[1] == reduce!max(nums)); --- $(B Exception Handling): After this function is finished executing, any exceptions thrown are chained together via $(D Throwable.next) and rethrown. The chaining order is non-deterministic. */ auto reduce(Args...)(Args args) { alias fun = reduceAdjoin!functions; alias finishFun = reduceFinish!functions; static if(isIntegral!(Args[$ - 1])) { size_t workUnitSize = cast(size_t) args[$ - 1]; alias args2 = args[0..$ - 1]; alias Args2 = Args[0..$ - 1]; } else { alias args2 = args; alias Args2 = Args; } auto makeStartValue(Type)(Type e) { static if(functions.length == 1) { return e; } else { typeof(adjoin!(staticMap!(binaryFun, functions))(e, e)) seed = void; foreach (i, T; seed.Types) { emplaceRef(seed.expand[i], e); } return seed; } } static if(args2.length == 2) { static assert(isInputRange!(Args2[1])); alias range = args2[1]; alias seed = args2[0]; enum explicitSeed = true; static if(!is(typeof(workUnitSize))) { size_t workUnitSize = defaultWorkUnitSize(range.length); } } else { static assert(args2.length == 1); alias range = args2[0]; static if(!is(typeof(workUnitSize))) { size_t workUnitSize = defaultWorkUnitSize(range.length); } enforce(!range.empty, "Cannot reduce an empty range with first element as start value."); auto seed = makeStartValue(range.front); enum explicitSeed = false; range.popFront(); } alias E = typeof(seed); alias R = typeof(range); E reduceOnRange(R range, size_t lowerBound, size_t upperBound) { // This is for exploiting instruction level parallelism by // using multiple accumulator variables within each thread, // since we're assuming functions are associative anyhow. // This is so that loops can be unrolled automatically. enum ilpTuple = AliasSeq!(0, 1, 2, 3, 4, 5); enum nILP = ilpTuple.length; immutable subSize = (upperBound - lowerBound) / nILP; if(subSize <= 1) { // Handle as a special case. static if(explicitSeed) { E result = seed; } else { E result = makeStartValue(range[lowerBound]); lowerBound++; } foreach(i; lowerBound..upperBound) { result = fun(result, range[i]); } return result; } assert(subSize > 1); E[nILP] results; size_t[nILP] offsets; foreach(i; ilpTuple) { offsets[i] = lowerBound + subSize * i; static if(explicitSeed) { results[i] = seed; } else { results[i] = makeStartValue(range[offsets[i]]); offsets[i]++; } } immutable nLoop = subSize - (!explicitSeed); foreach(i; 0..nLoop) { foreach(j; ilpTuple) { results[j] = fun(results[j], range[offsets[j]]); offsets[j]++; } } // Finish the remainder. foreach(i; nILP * subSize + lowerBound..upperBound) { results[$ - 1] = fun(results[$ - 1], range[i]); } foreach(i; ilpTuple[1..$]) { results[0] = finishFun(results[0], results[i]); } return results[0]; } immutable len = range.length; if(len == 0) { return seed; } if(this.size == 0) { return finishFun(seed, reduceOnRange(range, 0, len)); } // Unlike the rest of the functions here, I can't use the Task object // recycling trick here because this has to work on non-commutative // operations. After all the tasks are done executing, fun() has to // be applied on the results of these to get a final result, but // it can't be evaluated out of order. if(workUnitSize > len) { workUnitSize = len; } immutable size_t nWorkUnits = (len / workUnitSize) + ((len % workUnitSize == 0) ? 0 : 1); assert(nWorkUnits * workUnitSize >= len); alias RTask = Task!(run, typeof(&reduceOnRange), R, size_t, size_t); RTask[] tasks; // Can't use alloca() due to Bug 3753. Use a fixed buffer // backed by malloc(). enum maxStack = 2_048; byte[maxStack] buf = void; immutable size_t nBytesNeeded = nWorkUnits * RTask.sizeof; import core.stdc.stdlib; if(nBytesNeeded < maxStack) { tasks = (cast(RTask*) buf.ptr)[0..nWorkUnits]; } else { auto ptr = cast(RTask*) malloc(nBytesNeeded); if(!ptr) { throw new OutOfMemoryError( "Out of memory in std.parallelism." ); } tasks = ptr[0..nWorkUnits]; } scope(exit) { if(nBytesNeeded > maxStack) { free(tasks.ptr); } } foreach (ref t; tasks[]) emplaceRef(t, RTask()); // Hack to take the address of a nested function w/o // making a closure. static auto scopedAddress(D)(scope D del) { return del; } size_t curPos = 0; void useTask(ref RTask task) { task.pool = this; task._args[0] = scopedAddress(&reduceOnRange); task._args[3] = min(len, curPos + workUnitSize); // upper bound. task._args[1] = range; // range task._args[2] = curPos; // lower bound. curPos += workUnitSize; } foreach(ref task; tasks) { useTask(task); } foreach(i; 1..tasks.length - 1) { tasks[i].next = tasks[i + 1].basePtr; tasks[i + 1].prev = tasks[i].basePtr; } if(tasks.length > 1) { queueLock(); scope(exit) queueUnlock(); abstractPutGroupNoSync( tasks[1].basePtr, tasks[$ - 1].basePtr ); } if(tasks.length > 0) { try { tasks[0].job(); } catch(Throwable e) { tasks[0].exception = e; } tasks[0].taskStatus = TaskStatus.done; // Try to execute each of these in the current thread foreach(ref task; tasks[1..$]) { tryDeleteExecute(task.basePtr); } } // Now that we've tried to execute every task, they're all either // done or in progress. Force all of them. E result = seed; Throwable firstException, lastException; foreach(ref task; tasks) { try { task.yieldForce; } catch(Throwable e) { addToChain(e, firstException, lastException); continue; } if(!firstException) result = finishFun(result, task.returnVal); } if(firstException) throw firstException; return result; } } /** Gets the index of the current thread relative to this $(D TaskPool). Any thread not in this pool will receive an index of 0. The worker threads in this pool receive unique indices of 1 through $(D this.size). This function is useful for maintaining worker-local resources. Example: --- // Execute a loop that computes the greatest common // divisor of every number from 0 through 999 with // 42 in parallel. Write the results out to // a set of files, one for each thread. This allows // results to be written out without any synchronization. import std.conv, std.range, std.numeric, std.stdio; void main() { auto filesHandles = new File[taskPool.size + 1]; scope(exit) { foreach(ref handle; fileHandles) { handle.close(); } } foreach(i, ref handle; fileHandles) { handle = File("workerResults" ~ to!string(i) ~ ".txt"); } foreach(num; parallel(iota(1_000))) { auto outHandle = fileHandles[taskPool.workerIndex]; outHandle.writeln(num, '\t', gcd(num, 42)); } } --- */ size_t workerIndex() @property @safe const nothrow { immutable rawInd = threadIndex; return (rawInd >= instanceStartIndex && rawInd < instanceStartIndex + size) ? (rawInd - instanceStartIndex + 1) : 0; } /** Struct for creating worker-local storage. Worker-local storage is thread-local storage that exists only for worker threads in a given $(D TaskPool) plus a single thread outside the pool. It is allocated on the garbage collected heap in a way that avoids _false sharing, and doesn't necessarily have global scope within any thread. It can be accessed from any worker thread in the $(D TaskPool) that created it, and one thread outside this $(D TaskPool). All threads outside the pool that created a given instance of worker-local storage share a single slot. Since the underlying data for this struct is heap-allocated, this struct has reference semantics when passed between functions. The main uses cases for $(D WorkerLocalStorageStorage) are: 1. Performing parallel reductions with an imperative, as opposed to functional, programming style. In this case, it's useful to treat $(D WorkerLocalStorageStorage) as local to each thread for only the parallel portion of an algorithm. 2. Recycling temporary buffers across iterations of a parallel foreach loop. Example: --- // Calculate pi as in our synopsis example, but // use an imperative instead of a functional style. immutable n = 1_000_000_000; immutable delta = 1.0L / n; auto sums = taskPool.workerLocalStorage(0.0L); foreach(i; parallel(iota(n))) { immutable x = ( i - 0.5L ) * delta; immutable toAdd = delta / ( 1.0 + x * x ); sums.get += toAdd; } // Add up the results from each worker thread. real pi = 0; foreach(threadResult; sums.toRange) { pi += 4.0L * threadResult; } --- */ static struct WorkerLocalStorage(T) { private: TaskPool pool; size_t size; size_t elemSize; bool* stillThreadLocal; static size_t roundToLine(size_t num) pure nothrow { if(num % cacheLineSize == 0) { return num; } else { return ((num / cacheLineSize) + 1) * cacheLineSize; } } void* data; void initialize(TaskPool pool) { this.pool = pool; size = pool.size + 1; stillThreadLocal = new bool; *stillThreadLocal = true; // Determines whether the GC should scan the array. auto blkInfo = (typeid(T).flags & 1) ? cast(GC.BlkAttr) 0 : GC.BlkAttr.NO_SCAN; immutable nElem = pool.size + 1; elemSize = roundToLine(T.sizeof); // The + 3 is to pad one full cache line worth of space on either side // of the data structure to make sure false sharing with completely // unrelated heap data is prevented, and to provide enough padding to // make sure that data is cache line-aligned. data = GC.malloc(elemSize * (nElem + 3), blkInfo) + elemSize; // Cache line align data ptr. data = cast(void*) roundToLine(cast(size_t) data); foreach(i; 0..nElem) { this.opIndex(i) = T.init; } } ref T opIndex(size_t index) { assert(index < size, text(index, '\t', uint.max)); return *(cast(T*) (data + elemSize * index)); } void opIndexAssign(T val, size_t index) { assert(index < size); *(cast(T*) (data + elemSize * index)) = val; } public: /** Get the current thread's instance. Returns by ref. Note that calling $(D get) from any thread outside the $(D TaskPool) that created this instance will return the same reference, so an instance of worker-local storage should only be accessed from one thread outside the pool that created it. If this rule is violated, undefined behavior will result. If assertions are enabled and $(D toRange) has been called, then this WorkerLocalStorage instance is no longer worker-local and an assertion failure will result when calling this method. This is not checked when assertions are disabled for performance reasons. */ ref T get() @property { assert(*stillThreadLocal, "Cannot call get() on this instance of WorkerLocalStorage " ~ "because it is no longer worker-local." ); return opIndex(pool.workerIndex); } /** Assign a value to the current thread's instance. This function has the same caveats as its overload. */ void get(T val) @property { assert(*stillThreadLocal, "Cannot call get() on this instance of WorkerLocalStorage " ~ "because it is no longer worker-local." ); opIndexAssign(val, pool.workerIndex); } /** Returns a range view of the values for all threads, which can be used to further process the results of each thread after running the parallel part of your algorithm. Do not use this method in the parallel portion of your algorithm. Calling this function sets a flag indicating that this struct is no longer worker-local, and attempting to use the $(D get) method again will result in an assertion failure if assertions are enabled. */ WorkerLocalStorageRange!T toRange() @property { if(*stillThreadLocal) { *stillThreadLocal = false; // Make absolutely sure results are visible to all threads. // This is probably not necessary since some other // synchronization primitive will be used to signal that the // parallel part of the algorithm is done, but the // performance impact should be negligible, so it's better // to be safe. ubyte barrierDummy; atomicSetUbyte(barrierDummy, 1); } return WorkerLocalStorageRange!T(this); } } /** Range primitives for worker-local storage. The purpose of this is to access results produced by each worker thread from a single thread once you are no longer using the worker-local storage from multiple threads. Do not use this struct in the parallel portion of your algorithm. The proper way to instantiate this object is to call $(D WorkerLocalStorage.toRange). Once instantiated, this object behaves as a finite random-access range with assignable, lvalue elements and a length equal to the number of worker threads in the $(D TaskPool) that created it plus 1. */ static struct WorkerLocalStorageRange(T) { private: WorkerLocalStorage!T workerLocalStorage; size_t _length; size_t beginOffset; this(WorkerLocalStorage!T wl) { this.workerLocalStorage = wl; _length = wl.size; } public: ref T front() @property { return this[0]; } ref T back() @property { return this[_length - 1]; } void popFront() { if(_length > 0) { beginOffset++; _length--; } } void popBack() { if(_length > 0) { _length--; } } typeof(this) save() @property { return this; } ref T opIndex(size_t index) { assert(index < _length); return workerLocalStorage[index + beginOffset]; } void opIndexAssign(T val, size_t index) { assert(index < _length); workerLocalStorage[index] = val; } typeof(this) opSlice(size_t lower, size_t upper) { assert(upper <= _length); auto newWl = this.workerLocalStorage; newWl.data += lower * newWl.elemSize; newWl.size = upper - lower; return typeof(this)(newWl); } bool empty() @property { return length == 0; } size_t length() @property { return _length; } } /** Creates an instance of worker-local storage, initialized with a given value. The value is $(D lazy) so that you can, for example, easily create one instance of a class for each worker. For usage example, see the $(D WorkerLocalStorage) struct. */ WorkerLocalStorage!T workerLocalStorage(T)(lazy T initialVal = T.init) { WorkerLocalStorage!T ret; ret.initialize(this); foreach(i; 0..size + 1) { ret[i] = initialVal; } // Memory barrier to make absolutely sure that what we wrote is // visible to worker threads. ubyte barrierDummy; atomicSetUbyte(barrierDummy, 0); return ret; } /** Signals to all worker threads to terminate as soon as they are finished with their current $(D Task), or immediately if they are not executing a $(D Task). $(D Task)s that were in queue will not be executed unless a call to $(D Task.workForce), $(D Task.yieldForce) or $(D Task.spinForce) causes them to be executed. Use only if you have waited on every $(D Task) and therefore know the queue is empty, or if you speculatively executed some tasks and no longer need the results. */ void stop() @trusted { queueLock(); scope(exit) queueUnlock(); atomicSetUbyte(status, PoolState.stopNow); notifyAll(); } /** Signals worker threads to terminate when the queue becomes empty. If blocking argument is true, wait for all worker threads to terminate before returning. This option might be used in applications where task results are never consumed-- e.g. when $(D TaskPool) is employed as a rudimentary scheduler for tasks which communicate by means other than return values. Warning: Calling this function with $(D blocking = true) from a worker thread that is a member of the same $(D TaskPool) that $(D finish) is being called on will result in a deadlock. */ void finish(bool blocking = false) @trusted { { queueLock(); scope(exit) queueUnlock(); atomicCasUbyte(status, PoolState.running, PoolState.finishing); notifyAll(); } if (blocking) { // Use this thread as a worker until everything is finished. executeWorkLoop(); foreach(t; pool) { // Maybe there should be something here to prevent a thread // from calling join() on itself if this function is called // from a worker thread in the same pool, but: // // 1. Using an if statement to skip join() would result in // finish() returning without all tasks being finished. // // 2. If an exception were thrown, it would bubble up to the // Task from which finish() was called and likely be // swallowed. t.join(); } } } /// Returns the number of worker threads in the pool. @property size_t size() @safe const pure nothrow { return pool.length; } /** Put a $(D Task) object on the back of the task queue. The $(D Task) object may be passed by pointer or reference. Example: --- import std.file; // Create a task. auto t = task!read("foo.txt"); // Add it to the queue to be executed. taskPool.put(t); --- Notes: @trusted overloads of this function are called for $(D Task)s if $(XREF traits, hasUnsharedAliasing) is false for the $(D Task)'s return type or the function the $(D Task) executes is $(D pure). $(D Task) objects that meet all other requirements specified in the $(D @trusted) overloads of $(D task) and $(D scopedTask) may be created and executed from $(D @safe) code via $(D Task.executeInNewThread) but not via $(D TaskPool). While this function takes the address of variables that may be on the stack, some overloads are marked as @trusted. $(D Task) includes a destructor that waits for the task to complete before destroying the stack frame it is allocated on. Therefore, it is impossible for the stack frame to be destroyed before the task is complete and no longer referenced by a $(D TaskPool). */ void put(alias fun, Args...)(ref Task!(fun, Args) task) if(!isSafeReturn!(typeof(task))) { task.pool = this; abstractPut(task.basePtr); } /// Ditto void put(alias fun, Args...)(Task!(fun, Args)* task) if(!isSafeReturn!(typeof(*task))) { enforce(task !is null, "Cannot put a null Task on a TaskPool queue."); put(*task); } @trusted void put(alias fun, Args...)(ref Task!(fun, Args) task) if(isSafeReturn!(typeof(task))) { task.pool = this; abstractPut(task.basePtr); } @trusted void put(alias fun, Args...)(Task!(fun, Args)* task) if(isSafeReturn!(typeof(*task))) { enforce(task !is null, "Cannot put a null Task on a TaskPool queue."); put(*task); } /** These properties control whether the worker threads are daemon threads. A daemon thread is automatically terminated when all non-daemon threads have terminated. A non-daemon thread will prevent a program from terminating as long as it has not terminated. If any $(D TaskPool) with non-daemon threads is active, either $(D stop) or $(D finish) must be called on it before the program can terminate. The worker treads in the $(D TaskPool) instance returned by the $(D taskPool) property are daemon by default. The worker threads of manually instantiated task pools are non-daemon by default. Note: For a size zero pool, the getter arbitrarily returns true and the setter has no effect. */ bool isDaemon() @property @trusted { queueLock(); scope(exit) queueUnlock(); return (size == 0) ? true : pool[0].isDaemon; } /// Ditto void isDaemon(bool newVal) @property @trusted { queueLock(); scope(exit) queueUnlock(); foreach(thread; pool) { thread.isDaemon = newVal; } } /** These functions allow getting and setting the OS scheduling priority of the worker threads in this $(D TaskPool). They forward to $(D core.thread.Thread.priority), so a given priority value here means the same thing as an identical priority value in $(D core.thread). Note: For a size zero pool, the getter arbitrarily returns $(D core.thread.Thread.PRIORITY_MIN) and the setter has no effect. */ int priority() @property @trusted { return (size == 0) ? core.thread.Thread.PRIORITY_MIN : pool[0].priority; } /// Ditto void priority(int newPriority) @property @trusted { if(size > 0) { foreach(t; pool) { t.priority = newPriority; } } } } /** Returns a lazily initialized global instantiation of $(D TaskPool). This function can safely be called concurrently from multiple non-worker threads. The worker threads in this pool are daemon threads, meaning that it is not necessary to call $(D TaskPool.stop) or $(D TaskPool.finish) before terminating the main thread. */ @property TaskPool taskPool() @trusted { import std.concurrency : initOnce; __gshared TaskPool pool; return initOnce!pool({ auto p = new TaskPool(defaultPoolThreads); p.isDaemon = true; return p; }()); } private shared uint _defaultPoolThreads; shared static this() { atomicStore(_defaultPoolThreads, totalCPUs - 1); } /** These properties get and set the number of worker threads in the $(D TaskPool) instance returned by $(D taskPool). The default value is $(D totalCPUs) - 1. Calling the setter after the first call to $(D taskPool) does not changes number of worker threads in the instance returned by $(D taskPool). */ @property uint defaultPoolThreads() @trusted { return atomicLoad(_defaultPoolThreads); } /// Ditto @property void defaultPoolThreads(uint newVal) @trusted { atomicStore(_defaultPoolThreads, newVal); } /** Convenience functions that forwards to $(D taskPool.parallel). The purpose of these is to make parallel foreach less verbose and more readable. Example: --- // Find the logarithm of every number from // 1 to 1_000_000 in parallel, using the // default TaskPool instance. auto logs = new double[1_000_000]; foreach(i, ref elem; parallel(logs)) { elem = log(i + 1.0); } --- */ ParallelForeach!R parallel(R)(R range) { return taskPool.parallel(range); } /// Ditto ParallelForeach!R parallel(R)(R range, size_t workUnitSize) { return taskPool.parallel(range, workUnitSize); } // Thrown when a parallel foreach loop is broken from. class ParallelForeachError : Error { this() { super("Cannot break from a parallel foreach loop using break, return, " ~ "labeled break/continue or goto statements."); } } /*------Structs that implement opApply for parallel foreach.------------------*/ private template randLen(R) { enum randLen = isRandomAccessRange!R && hasLength!R; } private void submitAndExecute( TaskPool pool, scope void delegate() doIt ) { immutable nThreads = pool.size + 1; alias PTask = typeof(scopedTask(doIt)); import core.stdc.stdlib; import core.stdc.string : memcpy; // The logical thing to do would be to just use alloca() here, but that // causes problems on Windows for reasons that I don't understand // (tentatively a compiler bug) and definitely doesn't work on Posix due // to Bug 3753. Therefore, allocate a fixed buffer and fall back to // malloc() if someone's using a ridiculous amount of threads. Also, // the using a byte array instead of a PTask array as the fixed buffer // is to prevent d'tors from being called on uninitialized excess PTask // instances. enum nBuf = 64; byte[nBuf * PTask.sizeof] buf = void; PTask[] tasks; if(nThreads <= nBuf) { tasks = (cast(PTask*) buf.ptr)[0..nThreads]; } else { auto ptr = cast(PTask*) malloc(nThreads * PTask.sizeof); if(!ptr) throw new OutOfMemoryError("Out of memory in std.parallelism."); tasks = ptr[0..nThreads]; } scope(exit) { if(nThreads > nBuf) { free(tasks.ptr); } } foreach(ref t; tasks) { import core.stdc.string : memcpy; // This silly looking code is necessary to prevent d'tors from being // called on uninitialized objects. auto temp = scopedTask(doIt); memcpy(&t, &temp, PTask.sizeof); // This has to be done to t after copying, not temp before copying. // Otherwise, temp's destructor will sit here and wait for the // task to finish. t.pool = pool; } foreach(i; 1..tasks.length - 1) { tasks[i].next = tasks[i + 1].basePtr; tasks[i + 1].prev = tasks[i].basePtr; } if(tasks.length > 1) { pool.queueLock(); scope(exit) pool.queueUnlock(); pool.abstractPutGroupNoSync( tasks[1].basePtr, tasks[$ - 1].basePtr ); } if(tasks.length > 0) { try { tasks[0].job(); } catch(Throwable e) { tasks[0].exception = e; } tasks[0].taskStatus = TaskStatus.done; // Try to execute each of these in the current thread foreach(ref task; tasks[1..$]) { pool.tryDeleteExecute(task.basePtr); } } Throwable firstException, lastException; foreach(i, ref task; tasks) { try { task.yieldForce; } catch(Throwable e) { addToChain(e, firstException, lastException); continue; } } if(firstException) throw firstException; } void foreachErr() { throw new ParallelForeachError(); } int doSizeZeroCase(R, Delegate)(ref ParallelForeach!R p, Delegate dg) { with(p) { int res = 0; size_t index = 0; // The explicit ElementType!R in the foreach loops is necessary for // correct behavior when iterating over strings. static if(hasLvalueElements!R) { foreach(ref ElementType!R elem; range) { static if(Parameters!dg.length == 2) { res = dg(index, elem); } else { res = dg(elem); } if(res) foreachErr(); index++; } } else { foreach(ElementType!R elem; range) { static if(Parameters!dg.length == 2) { res = dg(index, elem); } else { res = dg(elem); } if(res) foreachErr(); index++; } } return res; } } private enum string parallelApplyMixinRandomAccess = q{ // Handle empty thread pool as special case. if(pool.size == 0) { return doSizeZeroCase(this, dg); } // Whether iteration is with or without an index variable. enum withIndex = Parameters!(typeof(dg)).length == 2; shared size_t workUnitIndex = size_t.max; // Effectively -1: chunkIndex + 1 == 0 immutable len = range.length; if(!len) return 0; shared bool shouldContinue = true; void doIt() { scope(failure) { // If an exception is thrown, all threads should bail. atomicStore(shouldContinue, false); } while(atomicLoad(shouldContinue)) { immutable myUnitIndex = atomicOp!"+="(workUnitIndex, 1); immutable start = workUnitSize * myUnitIndex; if(start >= len) { atomicStore(shouldContinue, false); break; } immutable end = min(len, start + workUnitSize); foreach(i; start..end) { static if(withIndex) { if(dg(i, range[i])) foreachErr(); } else { if(dg(range[i])) foreachErr(); } } } } submitAndExecute(pool, &doIt); return 0; }; enum string parallelApplyMixinInputRange = q{ // Handle empty thread pool as special case. if(pool.size == 0) { return doSizeZeroCase(this, dg); } // Whether iteration is with or without an index variable. enum withIndex = Parameters!(typeof(dg)).length == 2; // This protects the range while copying it. auto rangeMutex = new Mutex(); shared bool shouldContinue = true; // The total number of elements that have been popped off range. // This is updated only while protected by rangeMutex; size_t nPopped = 0; static if( is(typeof(range.buf1)) && is(typeof(range.bufPos)) && is(typeof(range.doBufSwap())) ) { // Make sure we don't have the buffer recycling overload of // asyncBuf. static if( is(typeof(range.source)) && isRoundRobin!(typeof(range.source)) ) { static assert(0, "Cannot execute a parallel foreach loop on " ~ "the buffer recycling overload of asyncBuf."); } enum bool bufferTrick = true; } else { enum bool bufferTrick = false; } void doIt() { scope(failure) { // If an exception is thrown, all threads should bail. atomicStore(shouldContinue, false); } static if(hasLvalueElements!R) { alias Temp = ElementType!R*[]; Temp temp; // Returns: The previous value of nPopped. size_t makeTemp() { import std.algorithm.internal : addressOf; if(temp is null) { temp = uninitializedArray!Temp(workUnitSize); } rangeMutex.lock(); scope(exit) rangeMutex.unlock(); size_t i = 0; for(; i < workUnitSize && !range.empty; range.popFront(), i++) { temp[i] = addressOf(range.front); } temp = temp[0..i]; auto ret = nPopped; nPopped += temp.length; return ret; } } else { alias Temp = ElementType!R[]; Temp temp; // Returns: The previous value of nPopped. static if(!bufferTrick) size_t makeTemp() { if(temp is null) { temp = uninitializedArray!Temp(workUnitSize); } rangeMutex.lock(); scope(exit) rangeMutex.unlock(); size_t i = 0; for(; i < workUnitSize && !range.empty; range.popFront(), i++) { temp[i] = range.front; } temp = temp[0..i]; auto ret = nPopped; nPopped += temp.length; return ret; } static if(bufferTrick) size_t makeTemp() { rangeMutex.lock(); scope(exit) rangeMutex.unlock(); // Elide copying by just swapping buffers. temp.length = range.buf1.length; swap(range.buf1, temp); // This is necessary in case popFront() has been called on // range before entering the parallel foreach loop. temp = temp[range.bufPos..$]; static if(is(typeof(range._length))) { range._length -= (temp.length - range.bufPos); } range.doBufSwap(); auto ret = nPopped; nPopped += temp.length; return ret; } } while(atomicLoad(shouldContinue)) { auto overallIndex = makeTemp(); if(temp.empty) { atomicStore(shouldContinue, false); break; } foreach(i; 0..temp.length) { scope(success) overallIndex++; static if(hasLvalueElements!R) { static if(withIndex) { if(dg(overallIndex, *temp[i])) foreachErr(); } else { if(dg(*temp[i])) foreachErr(); } } else { static if(withIndex) { if(dg(overallIndex, temp[i])) foreachErr(); } else { if(dg(temp[i])) foreachErr(); } } } } } submitAndExecute(pool, &doIt); return 0; }; // Calls e.next until the end of the chain is found. private Throwable findLastException(Throwable e) pure nothrow { if(e is null) return null; while(e.next) { e = e.next; } return e; } // Adds e to the exception chain. private void addToChain( Throwable e, ref Throwable firstException, ref Throwable lastException ) pure nothrow { if(firstException) { assert(lastException); lastException.next = e; lastException = findLastException(e); } else { firstException = e; lastException = findLastException(e); } } private struct ParallelForeach(R) { TaskPool pool; R range; size_t workUnitSize; alias E = ElementType!R; static if(hasLvalueElements!R) { alias NoIndexDg = int delegate(ref E); alias IndexDg = int delegate(size_t, ref E); } else { alias NoIndexDg = int delegate(E); alias IndexDg = int delegate(size_t, E); } int opApply(scope NoIndexDg dg) { static if(randLen!R) { mixin(parallelApplyMixinRandomAccess); } else { mixin(parallelApplyMixinInputRange); } } int opApply(scope IndexDg dg) { static if(randLen!R) { mixin(parallelApplyMixinRandomAccess); } else { mixin(parallelApplyMixinInputRange); } } } /* This struct buffers the output of a callable that outputs data into a user-supplied buffer into a set of buffers of some fixed size. It allows these buffers to be accessed with an input range interface. This is used internally in the buffer-recycling overload of TaskPool.asyncBuf, which creates an instance and forwards it to the input range overload of asyncBuf. */ private struct RoundRobinBuffer(C1, C2) { // No need for constraints because they're already checked for in asyncBuf. alias Array = Parameters!(C1.init)[0]; alias T = typeof(Array.init[0]); T[][] bufs; size_t index; C1 nextDel; C2 emptyDel; bool _empty; bool primed; this( C1 nextDel, C2 emptyDel, size_t initialBufSize, size_t nBuffers ) { this.nextDel = nextDel; this.emptyDel = emptyDel; bufs.length = nBuffers; foreach(ref buf; bufs) { buf.length = initialBufSize; } } void prime() in { assert(!empty); } body { scope(success) primed = true; nextDel(bufs[index]); } T[] front() @property in { assert(!empty); } body { if(!primed) prime(); return bufs[index]; } void popFront() { if(empty || emptyDel()) { _empty = true; return; } index = (index + 1) % bufs.length; primed = false; } bool empty() @property const @safe pure nothrow { return _empty; } } version(unittest) { // This was the only way I could get nested maps to work. __gshared TaskPool poolInstance; import std.stdio; } // These test basic functionality but don't stress test for threading bugs. // These are the tests that should be run every time Phobos is compiled. unittest { poolInstance = new TaskPool(2); scope(exit) poolInstance.stop(); // The only way this can be verified is manually. debug(std_parallelism) stderr.writeln("totalCPUs = ", totalCPUs); auto oldPriority = poolInstance.priority; poolInstance.priority = Thread.PRIORITY_MAX; assert(poolInstance.priority == Thread.PRIORITY_MAX); poolInstance.priority = Thread.PRIORITY_MIN; assert(poolInstance.priority == Thread.PRIORITY_MIN); poolInstance.priority = oldPriority; assert(poolInstance.priority == oldPriority); static void refFun(ref uint num) { num++; } uint x; // Test task(). auto t = task!refFun(x); poolInstance.put(t); t.yieldForce; assert(t.args[0] == 1); auto t2 = task(&refFun, x); poolInstance.put(t2); t2.yieldForce; assert(t2.args[0] == 1); // Test scopedTask(). auto st = scopedTask!refFun(x); poolInstance.put(st); st.yieldForce; assert(st.args[0] == 1); auto st2 = scopedTask(&refFun, x); poolInstance.put(st2); st2.yieldForce; assert(st2.args[0] == 1); // Test executeInNewThread(). auto ct = scopedTask!refFun(x); ct.executeInNewThread(Thread.PRIORITY_MAX); ct.yieldForce; assert(ct.args[0] == 1); // Test ref return. uint toInc = 0; static ref T makeRef(T)(ref T num) { return num; } auto t3 = task!makeRef(toInc); taskPool.put(t3); assert(t3.args[0] == 0); t3.spinForce++; assert(t3.args[0] == 1); static void testSafe() @safe { static int bump(int num) { return num + 1; } auto safePool = new TaskPool(0); auto t = task(&bump, 1); taskPool.put(t); assert(t.yieldForce == 2); auto st = scopedTask(&bump, 1); taskPool.put(st); assert(st.yieldForce == 2); safePool.stop(); } auto arr = [1,2,3,4,5]; auto nums = new uint[5]; auto nums2 = new uint[5]; foreach(i, ref elem; poolInstance.parallel(arr)) { elem++; nums[i] = cast(uint) i + 2; nums2[i] = elem; } assert(nums == [2,3,4,5,6], text(nums)); assert(nums2 == nums, text(nums2)); assert(arr == nums, text(arr)); // Test const/immutable arguments. static int add(int lhs, int rhs) { return lhs + rhs; } immutable addLhs = 1; immutable addRhs = 2; auto addTask = task(&add, addLhs, addRhs); auto addScopedTask = scopedTask(&add, addLhs, addRhs); poolInstance.put(addTask); poolInstance.put(addScopedTask); assert(addTask.yieldForce == 3); assert(addScopedTask.yieldForce == 3); // Test parallel foreach with non-random access range. auto range = filter!"a != 666"([0, 1, 2, 3, 4]); foreach(i, elem; poolInstance.parallel(range)) { nums[i] = cast(uint) i; } assert(nums == [0,1,2,3,4]); auto logs = new double[1_000_000]; foreach(i, ref elem; poolInstance.parallel(logs)) { elem = log(i + 1.0); } foreach(i, elem; logs) { assert(approxEqual(elem, cast(double) log(i + 1))); } assert(poolInstance.amap!"a * a"([1,2,3,4,5]) == [1,4,9,16,25]); assert(poolInstance.amap!"a * a"([1,2,3,4,5], new long[5]) == [1,4,9,16,25]); assert(poolInstance.amap!("a * a", "-a")([1,2,3]) == [tuple(1, -1), tuple(4, -2), tuple(9, -3)]); auto tupleBuf = new Tuple!(int, int)[3]; poolInstance.amap!("a * a", "-a")([1,2,3], tupleBuf); assert(tupleBuf == [tuple(1, -1), tuple(4, -2), tuple(9, -3)]); poolInstance.amap!("a * a", "-a")([1,2,3], 5, tupleBuf); assert(tupleBuf == [tuple(1, -1), tuple(4, -2), tuple(9, -3)]); // Test amap with a non-array buffer. auto toIndex = new int[5]; auto indexed = std.range.indexed(toIndex, [3, 1, 4, 0, 2]); poolInstance.amap!"a * 2"([1, 2, 3, 4, 5], indexed); assert(equal(indexed, [2, 4, 6, 8, 10])); assert(equal(toIndex, [8, 4, 10, 2, 6])); poolInstance.amap!"a / 2"(indexed, indexed); assert(equal(indexed, [1, 2, 3, 4, 5])); assert(equal(toIndex, [4, 2, 5, 1, 3])); auto buf = new int[5]; poolInstance.amap!"a * a"([1,2,3,4,5], buf); assert(buf == [1,4,9,16,25]); poolInstance.amap!"a * a"([1,2,3,4,5], 4, buf); assert(buf == [1,4,9,16,25]); assert(poolInstance.reduce!"a + b"([1]) == 1); assert(poolInstance.reduce!"a + b"([1,2,3,4]) == 10); assert(poolInstance.reduce!"a + b"(0.0, [1,2,3,4]) == 10); assert(poolInstance.reduce!"a + b"(0.0, [1,2,3,4], 1) == 10); assert(poolInstance.reduce!(min, max)([1,2,3,4]) == tuple(1, 4)); assert(poolInstance.reduce!("a + b", "a * b")(tuple(0, 1), [1,2,3,4]) == tuple(10, 24)); immutable serialAns = std.algorithm.reduce!"a + b"(iota(1000)); assert(poolInstance.reduce!"a + b"(0, iota(1000)) == serialAns); assert(poolInstance.reduce!"a + b"(iota(1000)) == serialAns); // Test worker-local storage. auto wl = poolInstance.workerLocalStorage(0); foreach(i; poolInstance.parallel(iota(1000), 1)) { wl.get = wl.get + i; } auto wlRange = wl.toRange; auto parallelSum = poolInstance.reduce!"a + b"(wlRange); assert(parallelSum == 499500); assert(wlRange[0..1][0] == wlRange[0]); assert(wlRange[1..2][0] == wlRange[1]); // Test finish() { static void slowFun() { Thread.sleep(dur!"msecs"(1)); } auto pool1 = new TaskPool(); auto tSlow = task!slowFun(); pool1.put(tSlow); pool1.finish(); tSlow.yieldForce; // Can't assert that pool1.status == PoolState.stopNow because status // doesn't change until after the "done" flag is set and the waiting // thread is woken up. auto pool2 = new TaskPool(); auto tSlow2 = task!slowFun(); pool2.put(tSlow2); pool2.finish(true); // blocking assert(tSlow2.done); // Test fix for Bug 8582 by making pool size zero. auto pool3 = new TaskPool(0); auto tSlow3 = task!slowFun(); pool3.put(tSlow3); pool3.finish(true); // blocking assert(tSlow3.done); // This is correct because no thread will terminate unless pool2.status // and pool3.status have already been set to stopNow. assert(pool2.status == TaskPool.PoolState.stopNow); assert(pool3.status == TaskPool.PoolState.stopNow); } // Test default pool stuff. assert(taskPool.size == totalCPUs - 1); nums = new uint[1000]; foreach(i; parallel(iota(1000))) { nums[i] = cast(uint) i; } assert(equal(nums, iota(1000))); assert(equal( poolInstance.map!"a * a"(iota(30_000_001), 10_000), std.algorithm.map!"a * a"(iota(30_000_001)) )); // The filter is to kill random access and test the non-random access // branch. assert(equal( poolInstance.map!"a * a"( filter!"a == a"(iota(30_000_001) ), 10_000, 1000), std.algorithm.map!"a * a"(iota(30_000_001)) )); assert( reduce!"a + b"(0UL, poolInstance.map!"a * a"(iota(3_000_001), 10_000) ) == reduce!"a + b"(0UL, std.algorithm.map!"a * a"(iota(3_000_001)) ) ); assert(equal( iota(1_000_002), poolInstance.asyncBuf(filter!"a == a"(iota(1_000_002))) )); { import std.file : deleteme; string temp_file = deleteme ~ "-tempDelMe.txt"; auto file = File(temp_file, "wb"); scope(exit) { file.close(); import std.file; remove(temp_file); } auto written = [[1.0, 2, 3], [4.0, 5, 6], [7.0, 8, 9]]; foreach(row; written) { file.writeln(join(to!(string[])(row), "\t")); } file = File(temp_file); void next(ref char[] buf) { file.readln(buf); import std.string : chomp; buf = chomp(buf); } double[][] read; auto asyncReader = taskPool.asyncBuf(&next, &file.eof); foreach(line; asyncReader) { if(line.length == 0) continue; auto ls = line.split("\t"); read ~= to!(double[])(ls); } assert(read == written); file.close(); } // Test Map/AsyncBuf chaining. auto abuf = poolInstance.asyncBuf(iota(-1.0, 3_000_000), 100); auto temp = poolInstance.map!sqrt( abuf, 100, 5 ); auto lmchain = poolInstance.map!"a * a"(temp, 100, 5); lmchain.popFront(); int ii; foreach( elem; (lmchain)) { if(!approxEqual(elem, ii)) { stderr.writeln(ii, '\t', elem); } ii++; } // Test buffer trick in parallel foreach. abuf = poolInstance.asyncBuf(iota(-1.0, 1_000_000), 100); abuf.popFront(); auto bufTrickTest = new size_t[abuf.length]; foreach(i, elem; parallel(abuf)) { bufTrickTest[i] = i; } assert(equal(iota(1_000_000), bufTrickTest)); auto myTask = task!(std.math.abs)(-1); taskPool.put(myTask); assert(myTask.spinForce == 1); // Test that worker local storage from one pool receives an index of 0 // when the index is queried w.r.t. another pool. The only way to do this // is non-deterministically. foreach(i; parallel(iota(1000), 1)) { assert(poolInstance.workerIndex == 0); } foreach(i; poolInstance.parallel(iota(1000), 1)) { assert(taskPool.workerIndex == 0); } // Test exception handling. static void parallelForeachThrow() { foreach(elem; parallel(iota(10))) { throw new Exception(""); } } assertThrown!Exception(parallelForeachThrow()); static int reduceException(int a, int b) { throw new Exception(""); } assertThrown!Exception( poolInstance.reduce!reduceException(iota(3)) ); static int mapException(int a) { throw new Exception(""); } assertThrown!Exception( poolInstance.amap!mapException(iota(3)) ); static void mapThrow() { auto m = poolInstance.map!mapException(iota(3)); m.popFront(); } assertThrown!Exception(mapThrow()); struct ThrowingRange { @property int front() { return 1; } void popFront() { throw new Exception(""); } enum bool empty = false; } assertThrown!Exception(poolInstance.asyncBuf(ThrowingRange.init)); } //version = parallelismStressTest; // These are more like stress tests than real unit tests. They print out // tons of stuff and should not be run every time make unittest is run. version(parallelismStressTest) { unittest { size_t attempt; for(; attempt < 10; attempt++) foreach(poolSize; [0, 4]) { poolInstance = new TaskPool(poolSize); uint[] numbers = new uint[1_000]; foreach(i; poolInstance.parallel( iota(0, numbers.length)) ) { numbers[i] = cast(uint) i; } // Make sure it works. foreach(i; 0..numbers.length) { assert(numbers[i] == i); } stderr.writeln("Done creating nums."); auto myNumbers = filter!"a % 7 > 0"( iota(0, 1000)); foreach(num; poolInstance.parallel(myNumbers)) { assert(num % 7 > 0 && num < 1000); } stderr.writeln("Done modulus test."); uint[] squares = poolInstance.amap!"a * a"(numbers, 100); assert(squares.length == numbers.length); foreach(i, number; numbers) { assert(squares[i] == number * number); } stderr.writeln("Done squares."); auto sumFuture = task!( reduce!"a + b" )(numbers); poolInstance.put(sumFuture); ulong sumSquares = 0; foreach(elem; numbers) { sumSquares += elem * elem; } uint mySum = sumFuture.spinForce(); assert(mySum == 999 * 1000 / 2); auto mySumParallel = poolInstance.reduce!"a + b"(numbers); assert(mySum == mySumParallel); stderr.writeln("Done sums."); auto myTask = task( { synchronized writeln("Our lives are parallel...Our lives are parallel."); }); poolInstance.put(myTask); auto nestedOuter = "abcd"; auto nestedInner = iota(0, 10, 2); foreach(i, letter; poolInstance.parallel(nestedOuter, 1)) { foreach(j, number; poolInstance.parallel(nestedInner, 1)) { synchronized writeln(i, ": ", letter, " ", j, ": ", number); } } poolInstance.stop(); } assert(attempt == 10); writeln("Press enter to go to next round of unittests."); readln(); } // These unittests are intended more for actual testing and not so much // as examples. unittest { foreach(attempt; 0..10) foreach(poolSize; [0, 4]) { poolInstance = new TaskPool(poolSize); // Test indexing. stderr.writeln("Creator Raw Index: ", poolInstance.threadIndex); assert(poolInstance.workerIndex() == 0); // Test worker-local storage. auto workerLocalStorage = poolInstance.workerLocalStorage!uint(1); foreach(i; poolInstance.parallel(iota(0U, 1_000_000))) { workerLocalStorage.get++; } assert(reduce!"a + b"(workerLocalStorage.toRange) == 1_000_000 + poolInstance.size + 1); // Make sure work is reasonably balanced among threads. This test is // non-deterministic and is more of a sanity check than something that // has an absolute pass/fail. shared(uint)[void*] nJobsByThread; foreach(thread; poolInstance.pool) { nJobsByThread[cast(void*) thread] = 0; } nJobsByThread[ cast(void*) Thread.getThis()] = 0; foreach(i; poolInstance.parallel( iota(0, 1_000_000), 100 )) { atomicOp!"+="( nJobsByThread[ cast(void*) Thread.getThis() ], 1); } stderr.writeln("\nCurrent thread is: ", cast(void*) Thread.getThis()); stderr.writeln("Workload distribution: "); foreach(k, v; nJobsByThread) { stderr.writeln(k, '\t', v); } // Test whether amap can be nested. real[][] matrix = new real[][](1000, 1000); foreach(i; poolInstance.parallel( iota(0, matrix.length) )) { foreach(j; poolInstance.parallel( iota(0, matrix[0].length) )) { matrix[i][j] = i * j; } } // Get around weird bugs having to do w/ sqrt being an intrinsic: static real mySqrt(real num) { return sqrt(num); } static real[] parallelSqrt(real[] nums) { return poolInstance.amap!mySqrt(nums); } real[][] sqrtMatrix = poolInstance.amap!parallelSqrt(matrix); foreach(i, row; sqrtMatrix) { foreach(j, elem; row) { real shouldBe = sqrt( cast(real) i * j); assert(approxEqual(shouldBe, elem)); sqrtMatrix[i][j] = shouldBe; } } auto saySuccess = task( { stderr.writeln( "Success doing matrix stuff that involves nested pool use."); }); poolInstance.put(saySuccess); saySuccess.workForce(); // A more thorough test of amap, reduce: Find the sum of the square roots of // matrix. static real parallelSum(real[] input) { return poolInstance.reduce!"a + b"(input); } auto sumSqrt = poolInstance.reduce!"a + b"( poolInstance.amap!parallelSum( sqrtMatrix ) ); assert(approxEqual(sumSqrt, 4.437e8)); stderr.writeln("Done sum of square roots."); // Test whether tasks work with function pointers. auto nanTask = task(&isNaN, 1.0L); poolInstance.put(nanTask); assert(nanTask.spinForce == false); if(poolInstance.size > 0) { // Test work waiting. static void uselessFun() { foreach(i; 0..1_000_000) {} } auto uselessTasks = new typeof(task(&uselessFun))[1000]; foreach(ref uselessTask; uselessTasks) { uselessTask = task(&uselessFun); } foreach(ref uselessTask; uselessTasks) { poolInstance.put(uselessTask); } foreach(ref uselessTask; uselessTasks) { uselessTask.workForce(); } } // Test the case of non-random access + ref returns. int[] nums = [1,2,3,4,5]; static struct RemoveRandom { int[] arr; ref int front() { return arr.front; } void popFront() { arr.popFront(); } bool empty() { return arr.empty; } } auto refRange = RemoveRandom(nums); foreach(ref elem; poolInstance.parallel(refRange)) { elem++; } assert(nums == [2,3,4,5,6], text(nums)); stderr.writeln("Nums: ", nums); poolInstance.stop(); } } } version(unittest) { struct __S_12733 { invariant() { assert(checksum == 1234567890); } this(ulong u){n = u;} void opAssign(__S_12733 s){this.n = s.n;} ulong n; ulong checksum = 1234567890; } static auto __genPair_12733(ulong n) { return __S_12733(n); } } unittest { immutable ulong[] data = [ 2UL^^59-1, 2UL^^59-1, 2UL^^59-1, 112_272_537_195_293UL ]; auto result = taskPool.amap!__genPair_12733(data); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/0000775000175000017500000000000012776215007020403 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/experimental/note.md0000664000175000017500000000005312776215007021670 0ustar kaikaiThis is intended for experimental modules. ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/logger/0000775000175000017500000000000012776215007021662 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/experimental/logger/multilogger.d0000664000175000017500000001276312776215007024372 0ustar kaikaimodule std.experimental.logger.multilogger; import std.experimental.logger.core; import std.experimental.logger.filelogger; /** This Element is stored inside the $(D MultiLogger) and associates a $(D Logger) to a $(D string). */ struct MultiLoggerEntry { string name; /// The name if the $(D Logger) Logger logger; /// The stored $(D Logger) } /** MultiLogger logs to multiple $(D Logger). The $(D Logger)s are stored in an $(D Logger[]) in their order of insertion. Every data logged to this $(D MultiLogger) will be distributed to all the $(D Logger)s inserted into it. This $(D MultiLogger) implementation can hold multiple $(D Logger)s with the same name. If the method $(D removeLogger) is used to remove a $(D Logger) only the first occurrence with that name will be removed. */ class MultiLogger : Logger { /** A constructor for the $(D MultiLogger) Logger. Params: lv = The $(D LogLevel) for the $(D MultiLogger). By default the $(D LogLevel) for $(D MultiLogger) is $(D LogLevel.all). Example: ------------- auto l1 = new MultiLogger(LogLevel.trace); ------------- */ this(const LogLevel lv = LogLevel.all) @safe { super(lv); } /** This member holds all $(D Logger)s stored in the $(D MultiLogger). When inheriting from $(D MultiLogger) this member can be used to gain access to the stored $(D Logger). */ protected MultiLoggerEntry[] logger; /** This method inserts a new Logger into the $(D MultiLogger). Params: name = The name of the $(D Logger) to insert. newLogger = The $(D Logger) to insert. */ void insertLogger(string name, Logger newLogger) @safe { this.logger ~= MultiLoggerEntry(name, newLogger); } /** This method removes a Logger from the $(D MultiLogger). Params: toRemove = The name of the $(D Logger) to remove. If the $(D Logger) is not found $(D null) will be returned. Only the first occurrence of a $(D Logger) with the given name will be removed. Returns: The removed $(D Logger). */ Logger removeLogger(in char[] toRemove) @safe { import std.algorithm : copy; import std.range.primitives : back, popBack; for (size_t i = 0; i < this.logger.length; ++i) { if (this.logger[i].name == toRemove) { Logger ret = this.logger[i].logger; this.logger[i] = this.logger.back; this.logger.popBack(); return ret; } } return null; } /* The override to pass the payload to all children of the $(D MultiLoggerBase). */ override protected void writeLogMsg(ref LogEntry payload) @safe { foreach (it; this.logger) { /* We don't perform any checks here to avoid race conditions. Instead the child will check on its own if its log level matches and assume LogLevel.all for the globalLogLevel (since we already know the message passes this test). */ it.logger.forwardMsg(payload); } } } @safe unittest { import std.experimental.logger.nulllogger; import std.exception : assertThrown; auto a = new MultiLogger; auto n0 = new NullLogger(); auto n1 = new NullLogger(); a.insertLogger("zero", n0); a.insertLogger("one", n1); auto n0_1 = a.removeLogger("zero"); assert(n0_1 is n0); auto n = a.removeLogger("zero"); assert(n is null); auto n1_1 = a.removeLogger("one"); assert(n1_1 is n1); n = a.removeLogger("one"); assert(n is null); } @safe unittest { auto a = new MultiLogger; auto n0 = new TestLogger; auto n1 = new TestLogger; a.insertLogger("zero", n0); a.insertLogger("one", n1); a.log("Hello TestLogger"); int line = __LINE__; assert(n0.msg == "Hello TestLogger"); assert(n0.line == line); assert(n1.msg == "Hello TestLogger"); assert(n0.line == line); } // Issue #16 unittest { import std.file : deleteme; import std.stdio : File; import std.string : indexOf; string logName = deleteme ~ __FUNCTION__ ~ ".log"; auto logFileOutput = File(logName, "w"); scope(exit) { import std.file : remove; logFileOutput.close(); remove(logName); } auto traceLog = new FileLogger(logFileOutput, LogLevel.all); auto infoLog = new TestLogger(LogLevel.info); auto root = new MultiLogger(LogLevel.all); root.insertLogger("fileLogger", traceLog); root.insertLogger("stdoutLogger", infoLog); string tMsg = "A trace message"; root.trace(tMsg); int line1 = __LINE__; assert(infoLog.line != line1); assert(infoLog.msg != tMsg); string iMsg = "A info message"; root.info(iMsg); int line2 = __LINE__; assert(infoLog.line == line2); assert(infoLog.msg == iMsg, infoLog.msg ~ ":" ~ iMsg); logFileOutput.close(); logFileOutput = File(logName, "r"); assert(logFileOutput.isOpen); assert(!logFileOutput.eof); auto line = logFileOutput.readln(); assert(line.indexOf(tMsg) != -1, line ~ ":" ~ tMsg); assert(!logFileOutput.eof); line = logFileOutput.readln(); assert(line.indexOf(iMsg) != -1, line ~ ":" ~ tMsg); } @safe unittest { auto dl = cast(FileLogger)sharedLog; assert(dl !is null); assert(dl.logLevel == LogLevel.all); assert(globalLogLevel == LogLevel.all); auto tl = cast(StdForwardLogger)stdThreadLocalLog; assert(tl !is null); stdThreadLocalLog.logLevel = LogLevel.all; } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/logger/nulllogger.d0000664000175000017500000000163112776215007024202 0ustar kaikaimodule std.experimental.logger.nulllogger; import std.experimental.logger.core; /** The $(D NullLogger) will not process any log messages. In case of a log message with $(D LogLevel.fatal) nothing will happen. */ class NullLogger : Logger { /** The default constructor for the $(D NullLogger). Independent of the parameter this Logger will never log a message. Params: lv = The $(D LogLevel) for the $(D NullLogger). By default the $(D LogLevel) for $(D NullLogger) is $(D LogLevel.all). */ this(const LogLevel lv = LogLevel.all) @safe { super(lv); this.fatalHandler = delegate() {}; } override protected void writeLogMsg(ref LogEntry payload) @safe @nogc { } } /// @safe unittest { auto nl1 = new NullLogger(LogLevel.all); nl1.info("You will never read this."); nl1.fatal("You will never read this, either and it will not throw"); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/logger/package.d0000664000175000017500000002015012776215007023420 0ustar kaikai/** Implements logging facilities. Copyright: Copyright Robert "burner" Schadek 2013 -- License: Boost License 1.0. Authors: $(WEB http://www.svs.informatik.uni-oldenburg.de/60865.html, Robert burner Schadek) $(H3 Basic Logging) Message logging is a common approach to expose runtime information of a program. Logging should be easy, but also flexible and powerful, therefore $(D D) provides a standard interface for logging. The easiest way to create a log message is to write: ------------- import std.experimental.logger; void main() { log("Hello World"); } ------------- This will print a message to the $(D stderr) device. The message will contain the filename, the linenumber, the name of the surrounding function, the time and the message. More complex log call can go along the lines like: ------------- log("Logging to the sharedLog with its default LogLevel"); logf(LogLevel.info, 5 < 6, "%s to the sharedLog with its LogLevel.info", "Logging"); info("Logging to the sharedLog with its info LogLevel"); warning(5 < 6, "Logging to the sharedLog with its LogLevel.warning if 5 is less than 6"); error("Logging to the sharedLog with its error LogLevel"); errorf("Logging %s the sharedLog %s its error LogLevel", "to", "with"); critical("Logging to the"," sharedLog with its error LogLevel"); fatal("Logging to the sharedLog with its fatal LogLevel"); auto fLogger = new FileLogger("NameOfTheLogFile"); fLogger.log("Logging to the fileLogger with its default LogLevel"); fLogger.info("Logging to the fileLogger with its default LogLevel"); fLogger.warning(5 < 6, "Logging to the fileLogger with its LogLevel.warning if 5 is less than 6"); fLogger.warningf(5 < 6, "Logging to the fileLogger with its LogLevel.warning if %s is %s than 6", 5, "less"); fLogger.critical("Logging to the fileLogger with its info LogLevel"); fLogger.log(LogLevel.trace, 5 < 6, "Logging to the fileLogger"," with its default LogLevel if 5 is less than 6"); fLogger.fatal("Logging to the fileLogger with its warning LogLevel"); ------------- Additionally, this example shows how a new $(D FileLogger) is created. Individual $(D Logger) and the global log functions share commonly named functions to log data. The names of the functions are as follows: $(LI $(D log)) $(LI $(D trace)) $(LI $(D info)) $(LI $(D warning)) $(LI $(D critical)) $(LI $(D fatal)) The default $(D Logger) will by default log to $(D stderr) and has a default $(D LogLevel) of $(D LogLevel.all). The default Logger can be accessed by using the property called $(D sharedLog). This property a reference to the current default $(D Logger). This reference can be used to assign a new default $(D Logger). ------------- sharedLog = new FileLogger("New_Default_Log_File.log"); ------------- Additional $(D Logger) can be created by creating a new instance of the required $(D Logger). $(H3 Logging Fundamentals) $(H4 LogLevel) The $(D LogLevel) of a log call can be defined in two ways. The first is by calling $(D log) and passing the $(D LogLevel) explicit as the first argument. The second way of setting the $(D LogLevel) of a log call, is by calling either $(D trace), $(D info), $(D warning), $(D critical), or $(D fatal). The log call will than have the respective $(D LogLevel). If no $(D LogLevel) is defined the log call will use the current $(D LogLevel) of the used $(D Logger). If data is logged with $(D LogLevel) $(D fatal) by default an $(D Error) will be thrown. This behaviour can be modified by using the member $(D fatalHandler) to assign a custom delegate to handle log call with $(D LogLevel) $(D fatal). $(H4 Conditional Logging) Conditional logging can be achieved be passing a $(D bool) as first argument to a log function. If conditional logging is used the condition must be $(D true) in order to have the log message logged. In order to combine an explicit $(D LogLevel) passing with conditional logging, the $(D LogLevel) has to be passed as first argument followed by the $(D bool). $(H4 Filtering Log Messages) Messages are logged if the $(D LogLevel) of the log message is greater than or equal to than the $(D LogLevel) of the used $(D Logger) and additionally if the $(D LogLevel) of the log message is greater equal to the global $(D LogLevel). If a condition is passed into the log call, this condition must be true. The global $(D LogLevel) is accessible by using $(D globalLogLevel). To assign the $(D LogLevel) of a $(D Logger) use the $(D logLevel) property of the logger. $(H4 Printf Style Logging) If $(D printf)-style logging is needed add a $(B f) to the logging call, such as $(D myLogger.infof("Hello %s", "world");) or $(D fatalf("errno %d", 1337)). The additional $(B f) appended to the function name enables $(D printf)-style logging for all combinations of explicit $(D LogLevel) and conditional logging functions and methods. $(H4 Thread Local Redirection) Calls to the free standing log functions are not directly forwarded to the global $(D Logger) $(D sharedLog). Actually, a thread local $(D Logger) of type $(D StdForwardLogger) process the log call and then, by default, forward the created $(D Logger.LogEntry) to the $(D sharedLog) $(D Logger). The thread local $(D Logger) is accessable by the $(D stdThreadLocalLog) property. This property allows to assign user defined $(D Logger). The default $(D LogLevel) of the $(D stdThreadLocalLog) $(D Logger) is $(D LogLevel.all) and it will therefore forward all messaged to the $(D sharedLog) $(D Logger). The $(D LogLevel) of the $(D stdThreadLocalLog) can be used to filter log calls before they reach the $(D sharedLog) $(D Logger). $(H3 User Defined Logger) To customize the $(D Logger) behavior, create a new $(D class) that inherits from the abstract $(D Logger) $(D class), and implements the $(D writeLogMsg) method. ------------- class MyCustomLogger : Logger { this(LogLevel lv) @safe { super(lv); } override void writeLogMsg(ref LogEntry payload) { // log message in my custom way } } auto logger = new MyCustomLogger(LogLevel.info); logger.log("Awesome log message with LogLevel.info"); ------------- To gain more precise control over the logging process, additionally to overwriting the $(D writeLogMsg) method the methods $(D beginLogMsg), $(D logMsgPart) and $(D finishLogMsg) can be overwritten. $(H3 Compile Time Disabling of $(D Logger)) In order to disable logging at compile time, pass $(D StdLoggerDisableLogging) as a version argument to the $(D D) compiler when compiling your program code. This will disable all logging functionality. Specific $(D LogLevel) can be disabled at compile time as well. In order to disable logging with the $(D trace) $(D LogLevel) pass $(D StdLoggerDisableTrace) as a version. The following table shows which version statement disables which $(D LogLevel). $(TABLE $(TR $(TD $(D LogLevel.trace) ) $(TD StdLoggerDisableTrace)) $(TR $(TD $(D LogLevel.info) ) $(TD StdLoggerDisableInfo)) $(TR $(TD $(D LogLevel.warning) ) $(TD StdLoggerDisableWarning)) $(TR $(TD $(D LogLevel.error) ) $(TD StdLoggerDisableError)) $(TR $(TD $(D LogLevel.critical) ) $(TD StdLoggerDisableCritical)) $(TR $(TD $(D LogLevel.fatal) ) $(TD StdLoggerDisableFatal)) ) Such a version statement will only disable logging in the associated compile unit. $(H3 Provided Logger) By default four $(D Logger) implementations are given. The $(D FileLogger) logs data to files. It can also be used to log to $(D stdout) and $(D stderr) as these devices are files as well. A $(D Logger) that logs to $(D stdout) can therefore be created by $(D new FileLogger(stdout)). The $(D MultiLogger) is basically an associative array of $(D string)s to $(D Logger). It propagates log calls to its stored $(D Logger). The $(D ArrayLogger) contains an array of $(D Logger) and also propagates log calls to its stored $(D Logger). The $(D NullLogger) does not do anything. It will never log a message and will never throw on a log call with $(D LogLevel) $(D error). */ module std.experimental.logger; public import std.experimental.logger.core; public import std.experimental.logger.filelogger; public import std.experimental.logger.nulllogger; public import std.experimental.logger.multilogger; ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/logger/core.d0000664000175000017500000032377712776215007023002 0ustar kaikaimodule std.experimental.logger.core; import std.array; import std.stdio; import std.conv; import std.datetime; import std.string; import std.range; import std.traits; import std.exception; import std.concurrency; import std.format; import core.atomic; import core.sync.mutex : Mutex; import std.experimental.logger.filelogger; shared static this() { stdSharedLoggerMutex = new Mutex; } /** This template evaluates if the passed $(D LogLevel) is active. The previously described version statements are used to decide if the $(D LogLevel) is active. The version statements only influence the compile unit they are used with, therefore this function can only disable logging this specific compile unit. */ template isLoggingActiveAt(LogLevel ll) { version (StdLoggerDisableLogging) { enum isLoggingActiveAt = false; } else { static if (ll == LogLevel.trace) { version (StdLoggerDisableTrace) enum isLoggingActiveAt = false; } else static if (ll == LogLevel.info) { version (StdLoggerDisableInfo) enum isLoggingActiveAt = false; } else static if (ll == LogLevel.warning) { version (StdLoggerDisableWarning) enum isLoggingActiveAt = false; } else static if (ll == LogLevel.error) { version (StdLoggerDisableError) enum isLoggingActiveAt = false; } else static if (ll == LogLevel.critical) { version (StdLoggerDisableCritical) enum isLoggingActiveAt = false; } else static if (ll == LogLevel.fatal) { version (StdLoggerDisableFatal) enum isLoggingActiveAt = false; } // If `isLoggingActiveAt` didn't get defined above to false, // we default it to true. static if (!is(typeof(isLoggingActiveAt) == bool)) { enum isLoggingActiveAt = true; } } } /// This compile-time flag is $(D true) if logging is not statically disabled. enum isLoggingActive = isLoggingActiveAt!(LogLevel.all); /** This functions is used at runtime to determine if a $(D LogLevel) is active. The same previously defined version statements are used to disable certain levels. Again the version statements are associated with a compile unit and can therefore not disable logging in other compile units. pure bool isLoggingEnabled()(LogLevel ll) @safe nothrow @nogc */ bool isLoggingEnabled()(LogLevel ll, LogLevel loggerLL, LogLevel globalLL, lazy bool condition = true) @safe { switch (ll) { case LogLevel.trace: version (StdLoggerDisableTrace) return false; else break; case LogLevel.info: version (StdLoggerDisableInfo) return false; else break; case LogLevel.warning: version (StdLoggerDisableWarning) return false; else break; case LogLevel.critical: version (StdLoggerDisableCritical) return false; else break; case LogLevel.fatal: version (StdLoggerDisableFatal) return false; else break; default: break; } return ll >= globalLL && ll >= loggerLL && ll != LogLevel.off && globalLL != LogLevel.off && loggerLL != LogLevel.off && condition; } /** This template returns the $(D LogLevel) named "logLevel" of type $(D LogLevel) defined in a user defined module where the filename has the suffix "_loggerconfig.d". This $(D LogLevel) sets the minimal $(D LogLevel) of the module. A minimal $(D LogLevel) can be defined on a per module basis. In order to define a module $(D LogLevel) a file with a modulename "MODULENAME_loggerconfig" must be found. If no such module exists and the module is a nested module, it is checked if there exists a "PARENT_MODULE_loggerconfig" module with such a symbol. If this module exists and it contains a $(D LogLevel) called logLevel this $(D LogLevel) will be used. This parent lookup is continued until there is no parent module. Then the moduleLogLevel is $(D LogLevel.all). */ template moduleLogLevel(string moduleName) if (!moduleName.length) { // default enum moduleLogLevel = LogLevel.all; } /// unittest { static assert(moduleLogLevel!"" == LogLevel.all); } /// ditto template moduleLogLevel(string moduleName) if (moduleName.length) { import std.string : format; mixin(q{ static if (__traits(compiles, {import %1$s : logLevel;})) { import %1$s : logLevel; static assert(is(typeof(logLevel) : LogLevel), "Expect 'logLevel' to be of Type 'LogLevel'."); // don't enforce enum here alias moduleLogLevel = logLevel; } else // use logLevel of package or default alias moduleLogLevel = moduleLogLevel!(parentOf(moduleName)); }.format(moduleName ~ "_loggerconfig")); } /// unittest { static assert(moduleLogLevel!"not.amodule.path" == LogLevel.all); } private string parentOf(string mod) { foreach_reverse (i, c; mod) if (c == '.') return mod[0 .. i]; return null; } /* This function formates a $(D SysTime) into an $(D OutputRange). The $(D SysTime) is formatted similar to $(LREF std.datatime.DateTime.toISOExtString) except the fractional second part. The fractional second part is in milliseconds and is always 3 digits. */ void systimeToISOString(OutputRange)(OutputRange o, const ref SysTime time) if (isOutputRange!(OutputRange,string)) { const auto dt = cast(DateTime)time; const auto fsec = time.fracSecs.total!"msecs"; formattedWrite(o, "%04d-%02d-%02dT%02d:%02d:%02d.%03d", dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, fsec); } /** This function logs data. In order for the data to be processed, the $(D LogLevel) of the log call must be greater or equal to the $(D LogLevel) of the $(D sharedLog) and the $(D defaultLogLevel); additionally the condition passed must be $(D true). Params: ll = The $(D LogLevel) used by this log call. condition = The condition must be $(D true) for the data to be logged. args = The data that should be logged. Example: -------------------- log(LogLevel.warning, true, "Hello World", 3.1415); -------------------- */ void log(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(const LogLevel ll, lazy bool condition, lazy A args) if (args.length != 1) { version(LDC) pragma(inline, true); // Must inline because of __FILE__ as template parameter static if (isLoggingActive) { if (ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.log!(line, file, funcName, prettyFuncName, moduleName) (ll, condition, args); } } } /// Ditto void log(T, string moduleName = __MODULE__)(const LogLevel ll, lazy bool condition, lazy T arg, int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__) { static if (isLoggingActive) { if (ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.log!(T,moduleName)(ll, condition, arg, line, file, funcName, prettyFuncName); } } } /** This function logs data. In order for the data to be processed the $(D LogLevel) of the log call must be greater or equal to the $(D LogLevel) of the $(D sharedLog). Params: ll = The $(D LogLevel) used by this log call. args = The data that should be logged. Example: -------------------- log(LogLevel.warning, "Hello World", 3.1415); -------------------- */ void log(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(const LogLevel ll, lazy A args) if (args.length > 1 && !is(Unqual!(A[0]) : bool)) { version(LDC) pragma(inline, true); // Must inline because of __FILE__ as template parameter static if (isLoggingActive) { if (ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.log!(line, file, funcName, prettyFuncName, moduleName) (ll, args); } } } /// Ditto void log(T, string moduleName = __MODULE__)(const LogLevel ll, lazy T arg, int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__) { static if (isLoggingActive) { if (ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.log!T(ll, arg, line, file, funcName, prettyFuncName, moduleName); } } } /** This function logs data. In order for the data to be processed the $(D LogLevel) of the $(D sharedLog) must be greater or equal to the $(D defaultLogLevel) add the condition passed must be $(D true). Params: condition = The condition must be $(D true) for the data to be logged. args = The data that should be logged. Example: -------------------- log(true, "Hello World", 3.1415); -------------------- */ void log(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy bool condition, lazy A args) if (args.length != 1) { version(LDC) pragma(inline, true); // Must inline because of __FILE__ as template parameter static if (isLoggingActive) { stdThreadLocalLog.log!(line, file, funcName, prettyFuncName, moduleName) (stdThreadLocalLog.logLevel, condition, args); } } /// Ditto void log(T, string moduleName = __MODULE__)(lazy bool condition, lazy T arg, int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__) { static if (isLoggingActive) { stdThreadLocalLog.log!(T,moduleName)(stdThreadLocalLog.logLevel, condition, arg, line, file, funcName, prettyFuncName); } } /** This function logs data. In order for the data to be processed the $(D LogLevel) of the $(D sharedLog) must be greater or equal to the $(D defaultLogLevel). Params: args = The data that should be logged. Example: -------------------- log("Hello World", 3.1415); -------------------- */ void log(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy A args) if ((args.length > 1 && !is(Unqual!(A[0]) : bool) && !is(Unqual!(A[0]) == LogLevel)) || args.length == 0) { version(LDC) pragma(inline, true); // Must inline because of __FILE__ as template parameter static if (isLoggingActive) { stdThreadLocalLog.log!(line, file, funcName, prettyFuncName, moduleName)(stdThreadLocalLog.logLevel, args); } } void log(T)(lazy T arg, int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__) { static if (isLoggingActive) { stdThreadLocalLog.log!T(stdThreadLocalLog.logLevel, arg, line, file, funcName, prettyFuncName, moduleName); } } /** This function logs data in a $(D printf)-style manner. In order for the data to be processed the $(D LogLevel) of the log call must be greater or equal to the $(D LogLevel) of the $(D sharedLog) and the $(D defaultLogLevel) additionally the condition passed must be $(D true). Params: ll = The $(D LogLevel) used by this log call. condition = The condition must be $(D true) for the data to be logged. msg = The $(D printf)-style string. args = The data that should be logged. Example: -------------------- logf(LogLevel.warning, true, "Hello World %f", 3.1415); -------------------- */ void logf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(const LogLevel ll, lazy bool condition, lazy string msg, lazy A args) { version(LDC) pragma(inline, true); // Must inline because of __FILE__ as template parameter static if (isLoggingActive) { if (ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.logf!(line, file, funcName, prettyFuncName, moduleName) (ll, condition, msg, args); } } } /** This function logs data in a $(D printf)-style manner. In order for the data to be processed the $(D LogLevel) of the log call must be greater or equal to the $(D LogLevel) of the $(D sharedLog) and the $(D defaultLogLevel). Params: ll = The $(D LogLevel) used by this log call. msg = The $(D printf)-style string. args = The data that should be logged. Example: -------------------- logf(LogLevel.warning, "Hello World %f", 3.1415); -------------------- */ void logf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(const LogLevel ll, lazy string msg, lazy A args) { static if (isLoggingActive) { if (ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.logf!(line, file, funcName, prettyFuncName, moduleName) (ll, msg, args); } } } /** This function logs data in a $(D printf)-style manner. In order for the data to be processed the $(D LogLevel) of the log call must be greater or equal to the $(D defaultLogLevel) additionally the condition passed must be $(D true). Params: condition = The condition must be $(D true) for the data to be logged. msg = The $(D printf)-style string. args = The data that should be logged. Example: -------------------- logf(true, "Hello World %f", 3.1415); -------------------- */ void logf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy bool condition, lazy string msg, lazy A args) { static if (isLoggingActive) { stdThreadLocalLog.logf!(line, file, funcName, prettyFuncName, moduleName) (stdThreadLocalLog.logLevel, condition, msg, args); } } /** This function logs data in a $(D printf)-style manner. In order for the data to be processed the $(D LogLevel) of the log call must be greater or equal to the $(D defaultLogLevel). Params: msg = The $(D printf)-style string. args = The data that should be logged. Example: -------------------- logf("Hello World %f", 3.1415); -------------------- */ void logf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy string msg, lazy A args) { static if (isLoggingActive) { stdThreadLocalLog.logf!(line, file, funcName,prettyFuncName, moduleName) (stdThreadLocalLog.logLevel, msg, args); } } /** This template provides the global log functions with the $(D LogLevel) is encoded in the function name. The aliases following this template create the public names of these log functions. */ template defaultLogFunction(LogLevel ll) { void defaultLogFunction(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy A args) if ((args.length > 0 && !is(Unqual!(A[0]) : bool)) || args.length == 0) { static if (isLoggingActiveAt!ll && ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.memLogFunctions!(ll).logImpl!(line, file, funcName, prettyFuncName, moduleName)(args); } } void defaultLogFunction(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy bool condition, lazy A args) { static if (isLoggingActiveAt!ll && ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.memLogFunctions!(ll).logImpl!(line, file, funcName, prettyFuncName, moduleName)(condition, args); } } } /** This function logs data to the $(D stdThreadLocalLog), optionally depending on a condition. In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the $(D stdThreadLocalLog) and must be greater or equal than the global $(D LogLevel). Additionally the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the $(D stdSharedLogger). If a condition is given, it must evaluate to $(D true). Params: condition = The condition must be $(D true) for the data to be logged. args = The data that should be logged. Example: -------------------- trace(1337, "is number"); info(1337, "is number"); error(1337, "is number"); critical(1337, "is number"); fatal(1337, "is number"); trace(true, 1337, "is number"); info(false, 1337, "is number"); error(true, 1337, "is number"); critical(false, 1337, "is number"); fatal(true, 1337, "is number"); -------------------- */ alias trace = defaultLogFunction!(LogLevel.trace); /// Ditto alias info = defaultLogFunction!(LogLevel.info); /// Ditto alias warning = defaultLogFunction!(LogLevel.warning); /// Ditto alias error = defaultLogFunction!(LogLevel.error); /// Ditto alias critical = defaultLogFunction!(LogLevel.critical); /// Ditto alias fatal = defaultLogFunction!(LogLevel.fatal); /** This template provides the global $(D printf)-style log functions with the $(D LogLevel) is encoded in the function name. The aliases following this template create the public names of the log functions. */ template defaultLogFunctionf(LogLevel ll) { void defaultLogFunctionf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy string msg, lazy A args) { static if (isLoggingActiveAt!ll && ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.memLogFunctions!(ll).logImplf!(line, file, funcName, prettyFuncName, moduleName)(msg, args); } } void defaultLogFunctionf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy bool condition, lazy string msg, lazy A args) { static if (isLoggingActiveAt!ll && ll >= moduleLogLevel!moduleName) { stdThreadLocalLog.memLogFunctions!(ll).logImplf!(line, file, funcName, prettyFuncName, moduleName)(condition, msg, args); } } } /** This function logs data to the $(D sharedLog) in a $(D printf)-style manner. In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the $(D sharedLog) and must be greater or equal than the global $(D LogLevel). Additionally the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the $(D stdSharedLogger). Params: msg = The $(D printf)-style string. args = The data that should be logged. Example: -------------------- tracef("is number %d", 1); infof("is number %d", 2); errorf("is number %d", 3); criticalf("is number %d", 4); fatalf("is number %d", 5); -------------------- The second version of the function logs data to the $(D sharedLog) in a $(D printf)-style manner. In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the $(D sharedLog) and must be greater or equal than the global $(D LogLevel). Additionally the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the $(D stdSharedLogger). Params: condition = The condition must be $(D true) for the data to be logged. msg = The $(D printf)-style string. args = The data that should be logged. Example: -------------------- tracef(false, "is number %d", 1); infof(false, "is number %d", 2); errorf(true, "is number %d", 3); criticalf(true, "is number %d", 4); fatalf(someFunct(), "is number %d", 5); -------------------- */ alias tracef = defaultLogFunctionf!(LogLevel.trace); /// Ditto alias infof = defaultLogFunctionf!(LogLevel.info); /// Ditto alias warningf = defaultLogFunctionf!(LogLevel.warning); /// Ditto alias errorf = defaultLogFunctionf!(LogLevel.error); /// Ditto alias criticalf = defaultLogFunctionf!(LogLevel.critical); /// Ditto alias fatalf = defaultLogFunctionf!(LogLevel.fatal); private struct MsgRange { import std.traits : isSomeString, isSomeChar; private Logger log; private char[] buffer; this(Logger log) @safe { this.log = log; } void put(T)(T msg) @safe if (isSomeString!T) { log.logMsgPart(msg); } void put(dchar elem) @safe { import std.utf : encode; encode(this.buffer, elem); log.logMsgPart(this.buffer); } } private void formatString(A...)(MsgRange oRange, A args) { import std.format : formattedWrite; foreach (arg; args) { std.format.formattedWrite(oRange, "%s", arg); } } unittest { void dummy() @safe { auto tl = new TestLogger(); auto dst = MsgRange(tl); formatString(dst, "aaa", "bbb"); } dummy(); } /** There are eight usable logging level. These level are $(I all), $(I trace), $(I info), $(I warning), $(I error), $(I critical), $(I fatal), and $(I off). If a log function with $(D LogLevel.fatal) is called the shutdown handler of that logger is called. */ enum LogLevel : ubyte { all = 1, /** Lowest possible assignable $(D LogLevel). */ trace = 32, /** $(D LogLevel) for tracing the execution of the program. */ info = 64, /** This level is used to display information about the program. */ warning = 96, /** warnings about the program should be displayed with this level. */ error = 128, /** Information about errors should be logged with this level.*/ critical = 160, /** Messages that inform about critical errors should be logged with this level. */ fatal = 192, /** Log messages that describe fatal errors should use this level. */ off = ubyte.max /** Highest possible $(D LogLevel). */ } /** This class is the base of every logger. In order to create a new kind of logger a deriving class needs to implement the $(D writeLogMsg) method. By default this is not thread-safe. It is also possible to $(D override) the three methods $(D beginLogMsg), $(D logMsgPart) and $(D finishLogMsg) together, this option gives more flexibility. */ abstract class Logger { /** LogEntry is a aggregation combining all information associated with a log message. This aggregation will be passed to the method writeLogMsg. */ protected struct LogEntry { /// the filename the log function was called from string file; /// the line number the log function was called from int line; /// the name of the function the log function was called from string funcName; /// the pretty formatted name of the function the log function was /// called from string prettyFuncName; /// the name of the module the log message is coming from string moduleName; /// the $(D LogLevel) associated with the log message LogLevel logLevel; /// thread id of the log message Tid threadId; /// the time the message was logged SysTime timestamp; /// the message of the log message string msg; /// A refernce to the $(D Logger) used to create this $(D LogEntry) Logger logger; } /** This constructor takes a name of type $(D string), and a $(D LogLevel). Every subclass of $(D Logger) has to call this constructor from their constructor. It sets the $(D LogLevel), the name of the $(D Logger), and creates a fatal handler. The fatal handler will throw an $(D Error) if a log call is made with a $(D LogLevel) $(D LogLevel.fatal). */ this(LogLevel lv) @safe { this.logLevel_ = lv; this.fatalHandler_ = delegate() { throw new Error("A fatal log message was logged"); }; this.mutex = new Mutex(); } /** A custom logger must implement this method in order to work in a $(D MultiLogger) and $(D ArrayLogger). Params: payload = All information associated with call to log function. See_Also: beginLogMsg, logMsgPart, finishLogMsg */ abstract protected void writeLogMsg(ref LogEntry payload) @safe; /* The default implementation will use an $(D std.array.appender) internally to construct the message string. This means dynamic, GC memory allocation. A logger can avoid this allocation by reimplementing $(D beginLogMsg), $(D logMsgPart) and $(D finishLogMsg). $(D beginLogMsg) is always called first, followed by any number of calls to $(D logMsgPart) and one call to $(D finishLogMsg). As an example for such a custom $(D Logger) compare this: ---------------- class CLogger : Logger { override void beginLogMsg(string file, int line, string funcName, string prettyFuncName, string moduleName, LogLevel logLevel, Tid threadId, SysTime timestamp) { ... logic here } override void logMsgPart(const(char)[] msg) { ... logic here } override void finishLogMsg() { ... logic here } void writeLogMsg(ref LogEntry payload) { this.beginLogMsg(payload.file, payload.line, payload.funcName, payload.prettyFuncName, payload.moduleName, payload.logLevel, payload.threadId, payload.timestamp, payload.logger); this.logMsgPart(payload.msg); this.finishLogMsg(); } } ---------------- */ protected void beginLogMsg(string file, int line, string funcName, string prettyFuncName, string moduleName, LogLevel logLevel, Tid threadId, SysTime timestamp, Logger logger) @safe { static if (isLoggingActive) { msgAppender = appender!string(); header = LogEntry(file, line, funcName, prettyFuncName, moduleName, logLevel, threadId, timestamp, null, logger); } } /** Logs a part of the log message. */ protected void logMsgPart(const(char)[] msg) @safe { static if (isLoggingActive) { msgAppender.put(msg); } } /** Signals that the message has been written and no more calls to $(D logMsgPart) follow. */ protected void finishLogMsg() @safe { static if (isLoggingActive) { header.msg = msgAppender.data; this.writeLogMsg(header); } } /** The $(D LogLevel) determines if the log call are processed or dropped by the $(D Logger). In order for the log call to be processed the $(D LogLevel) of the log call must be greater or equal to the $(D LogLevel) of the $(D logger). These two methods set and get the $(D LogLevel) of the used $(D Logger). Example: ----------- auto f = new FileLogger(stdout); f.logLevel = LogLevel.info; assert(f.logLevel == LogLevel.info); ----------- */ @property final LogLevel logLevel() const pure @safe @nogc { return trustedLoad(this.logLevel_); } /// Ditto @property final void logLevel(const LogLevel lv) @safe @nogc { synchronized (mutex) this.logLevel_ = lv; } /** This $(D delegate) is called in case a log message with $(D LogLevel.fatal) gets logged. By default an $(D Error) will be thrown. */ @property final void delegate() fatalHandler() @safe @nogc { synchronized (mutex) return this.fatalHandler_; } /// Ditto @property final void fatalHandler(void delegate() @safe fh) @safe @nogc { synchronized (mutex) this.fatalHandler_ = fh; } /** This method allows forwarding log entries from one logger to another. $(D forwardMsg) will ensure proper synchronization and then call $(D writeLogMsg). This is an API for implementing your own loggers and should not be called by normal user code. A notable difference from other logging functions is that the $(D globalLogLevel) wont be evaluated again since it is assumed that the caller already checked that. */ void forwardMsg(ref LogEntry payload) @trusted { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(payload.logLevel, this.logLevel_, globalLogLevel)) { this.writeLogMsg(payload); if (payload.logLevel == LogLevel.fatal) this.fatalHandler_(); } } } /** This template provides the log functions for the $(D Logger) $(D class) with the $(D LogLevel) encoded in the function name. For further information see the the two functions defined inside of this template. The aliases following this template create the public names of these log functions. */ template memLogFunctions(LogLevel ll) { /** This function logs data to the used $(D Logger). In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the used $(D Logger) and must be greater or equal than the global $(D LogLevel). Params: args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stdout); s.trace(1337, "is number"); s.info(1337, "is number"); s.error(1337, "is number"); s.critical(1337, "is number"); s.fatal(1337, "is number"); -------------------- */ void logImpl(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy A args) if (args.length == 0 || (args.length > 0 && !is(A[0] : bool))) { static if (isLoggingActiveAt!ll && ll >= moduleLogLevel!moduleName) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, args); this.finishLogMsg(); static if (ll == LogLevel.fatal) this.fatalHandler_(); } } } /** This function logs data to the used $(D Logger) depending on a condition. In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the used $(D Logger) and must be greater or equal than the global $(D LogLevel) additionally the condition passed must be $(D true). Params: condition = The condition must be $(D true) for the data to be logged. args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stdout); s.trace(true, 1337, "is number"); s.info(false, 1337, "is number"); s.error(true, 1337, "is number"); s.critical(false, 1337, "is number"); s.fatal(true, 1337, "is number"); -------------------- */ void logImpl(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy bool condition, lazy A args) { static if (isLoggingActiveAt!ll && ll >= moduleLogLevel!moduleName) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel, condition)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, args); this.finishLogMsg(); static if (ll == LogLevel.fatal) this.fatalHandler_(); } } } /** This function logs data to the used $(D Logger) in a $(D printf)-style manner. In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the used $(D Logger) and must be greater or equal than the global $(D LogLevel) additionally the passed condition must be $(D true). Params: condition = The condition must be $(D true) for the data to be logged. msg = The $(D printf)-style string. args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stderr); s.tracef(true, "is number %d", 1); s.infof(true, "is number %d", 2); s.errorf(false, "is number %d", 3); s.criticalf(someFunc(), "is number %d", 4); s.fatalf(true, "is number %d", 5); -------------------- */ void logImplf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy bool condition, lazy string msg, lazy A args) { static if (isLoggingActiveAt!ll && ll >= moduleLogLevel!moduleName) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel, condition)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formattedWrite(writer, msg, args); this.finishLogMsg(); static if (ll == LogLevel.fatal) this.fatalHandler_(); } } } /** This function logs data to the used $(D Logger) in a $(D printf)-style manner. In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the used $(D Logger) and must be greater or equal than the global $(D LogLevel). Params: msg = The $(D printf)-style string. args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stderr); s.tracef("is number %d", 1); s.infof("is number %d", 2); s.errorf("is number %d", 3); s.criticalf("is number %d", 4); s.fatalf("is number %d", 5); -------------------- */ void logImplf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy string msg, lazy A args) { static if (isLoggingActiveAt!ll && ll >= moduleLogLevel!moduleName) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formattedWrite(writer, msg, args); this.finishLogMsg(); static if (ll == LogLevel.fatal) this.fatalHandler_(); } } } } /// Ditto alias trace = memLogFunctions!(LogLevel.trace).logImpl; /// Ditto alias tracef = memLogFunctions!(LogLevel.trace).logImplf; /// Ditto alias info = memLogFunctions!(LogLevel.info).logImpl; /// Ditto alias infof = memLogFunctions!(LogLevel.info).logImplf; /// Ditto alias warning = memLogFunctions!(LogLevel.warning).logImpl; /// Ditto alias warningf = memLogFunctions!(LogLevel.warning).logImplf; /// Ditto alias error = memLogFunctions!(LogLevel.error).logImpl; /// Ditto alias errorf = memLogFunctions!(LogLevel.error).logImplf; /// Ditto alias critical = memLogFunctions!(LogLevel.critical).logImpl; /// Ditto alias criticalf = memLogFunctions!(LogLevel.critical).logImplf; /// Ditto alias fatal = memLogFunctions!(LogLevel.fatal).logImpl; /// Ditto alias fatalf = memLogFunctions!(LogLevel.fatal).logImplf; /** This method logs data with the $(D LogLevel) of the used $(D Logger). This method takes a $(D bool) as first argument. In order for the data to be processed the $(D bool) must be $(D true) and the $(D LogLevel) of the Logger must be greater or equal to the global $(D LogLevel). Params: args = The data that should be logged. condition = The condition must be $(D true) for the data to be logged. args = The data that is to be logged. Returns: The logger used by the logging function as reference. Example: -------------------- auto l = new StdioLogger(); l.log(1337); -------------------- */ final void log(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(const LogLevel ll, lazy bool condition, lazy A args) if (args.length != 1) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel, condition)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, args); this.finishLogMsg(); if (ll == LogLevel.fatal) this.fatalHandler_(); } } } /// Ditto final void log(T, string moduleName = __MODULE__)(const LogLevel ll, lazy bool condition, lazy T args, int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel, condition) && ll >= moduleLogLevel!moduleName) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, args); this.finishLogMsg(); if (ll == LogLevel.fatal) this.fatalHandler_(); } } } /** This function logs data to the used $(D Logger) with a specific $(D LogLevel). In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the used $(D Logger) and must be greater or equal than the global $(D LogLevel). Params: ll = The specific $(D LogLevel) used for logging the log message. args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stdout); s.log(LogLevel.trace, 1337, "is number"); s.log(LogLevel.info, 1337, "is number"); s.log(LogLevel.warning, 1337, "is number"); s.log(LogLevel.error, 1337, "is number"); s.log(LogLevel.fatal, 1337, "is number"); -------------------- */ final void log(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(const LogLevel ll, lazy A args) if ((args.length > 1 && !is(Unqual!(A[0]) : bool)) || args.length == 0) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, args); this.finishLogMsg(); if (ll == LogLevel.fatal) this.fatalHandler_(); } } } /// Ditto final void log(T)(const LogLevel ll, lazy T args, int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, args); this.finishLogMsg(); if (ll == LogLevel.fatal) this.fatalHandler_(); } } } /** This function logs data to the used $(D Logger) depending on a explicitly passed condition with the $(D LogLevel) of the used $(D Logger). In order for the resulting log message to be logged the $(D LogLevel) of the used $(D Logger) must be greater or equal than the global $(D LogLevel) and the condition must be $(D true). Params: condition = The condition must be $(D true) for the data to be logged. args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stdout); s.log(true, 1337, "is number"); s.log(true, 1337, "is number"); s.log(true, 1337, "is number"); s.log(false, 1337, "is number"); s.log(false, 1337, "is number"); -------------------- */ final void log(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy bool condition, lazy A args) if (args.length != 1) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(this.logLevel_, this.logLevel_, globalLogLevel, condition)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, this.logLevel_, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, args); this.finishLogMsg(); if (this.logLevel_ == LogLevel.fatal) this.fatalHandler_(); } } } /// Ditto final void log(T)(lazy bool condition, lazy T args, int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(this.logLevel_, this.logLevel_, globalLogLevel, condition)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, this.logLevel_, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, args); this.finishLogMsg(); if (this.logLevel_ == LogLevel.fatal) this.fatalHandler_(); } } } /** This function logs data to the used $(D Logger) with the $(D LogLevel) of the used $(D Logger). In order for the resulting log message to be logged the $(D LogLevel) of the used $(D Logger) must be greater or equal than the global $(D LogLevel). Params: args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stdout); s.log(1337, "is number"); s.log(info, 1337, "is number"); s.log(1337, "is number"); s.log(1337, "is number"); s.log(1337, "is number"); -------------------- */ final void log(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy A args) if ((args.length > 1 && !is(Unqual!(A[0]) : bool) && !is(Unqual!(A[0]) == LogLevel)) || args.length == 0) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(this.logLevel_, this.logLevel_, globalLogLevel)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, this.logLevel_, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, args); this.finishLogMsg(); if (this.logLevel_ == LogLevel.fatal) this.fatalHandler_(); } } } /// Ditto final void log(T)(lazy T arg, int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(this.logLevel_, this.logLevel_, globalLogLevel)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, this.logLevel_, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formatString(writer, arg); this.finishLogMsg(); if (this.logLevel_ == LogLevel.fatal) this.fatalHandler_(); } } } /** This function logs data to the used $(D Logger) with a specific $(D LogLevel) and depending on a condition in a $(D printf)-style manner. In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the used $(D Logger) and must be greater or equal than the global $(D LogLevel) and the condition must be $(D true). Params: ll = The specific $(D LogLevel) used for logging the log message. condition = The condition must be $(D true) for the data to be logged. msg = The format string used for this log call. args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stdout); s.logf(LogLevel.trace, true ,"%d %s", 1337, "is number"); s.logf(LogLevel.info, true ,"%d %s", 1337, "is number"); s.logf(LogLevel.warning, true ,"%d %s", 1337, "is number"); s.logf(LogLevel.error, false ,"%d %s", 1337, "is number"); s.logf(LogLevel.fatal, true ,"%d %s", 1337, "is number"); -------------------- */ final void logf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(const LogLevel ll, lazy bool condition, lazy string msg, lazy A args) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel, condition)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formattedWrite(writer, msg, args); this.finishLogMsg(); if (ll == LogLevel.fatal) this.fatalHandler_(); } } } /** This function logs data to the used $(D Logger) with a specific $(D LogLevel) in a $(D printf)-style manner. In order for the resulting log message to be logged the $(D LogLevel) must be greater or equal than the $(D LogLevel) of the used $(D Logger) and must be greater or equal than the global $(D LogLevel). Params: ll = The specific $(D LogLevel) used for logging the log message. msg = The format string used for this log call. args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stdout); s.logf(LogLevel.trace, "%d %s", 1337, "is number"); s.logf(LogLevel.info, "%d %s", 1337, "is number"); s.logf(LogLevel.warning, "%d %s", 1337, "is number"); s.logf(LogLevel.error, "%d %s", 1337, "is number"); s.logf(LogLevel.fatal, "%d %s", 1337, "is number"); -------------------- */ final void logf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(const LogLevel ll, lazy string msg, lazy A args) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(ll, this.logLevel_, globalLogLevel)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, ll, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formattedWrite(writer, msg, args); this.finishLogMsg(); if (ll == LogLevel.fatal) this.fatalHandler_(); } } } /** This function logs data to the used $(D Logger) depending on a condition with the $(D LogLevel) of the used $(D Logger) in a $(D printf)-style manner. In order for the resulting log message to be logged the $(D LogLevel) of the used $(D Logger) must be greater or equal than the global $(D LogLevel) and the condition must be $(D true). Params: condition = The condition must be $(D true) for the data to be logged. msg = The format string used for this log call. args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stdout); s.logf(true ,"%d %s", 1337, "is number"); s.logf(true ,"%d %s", 1337, "is number"); s.logf(true ,"%d %s", 1337, "is number"); s.logf(false ,"%d %s", 1337, "is number"); s.logf(true ,"%d %s", 1337, "is number"); -------------------- */ final void logf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy bool condition, lazy string msg, lazy A args) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(this.logLevel_, this.logLevel_, globalLogLevel, condition)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, this.logLevel_, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formattedWrite(writer, msg, args); this.finishLogMsg(); if (this.logLevel_ == LogLevel.fatal) this.fatalHandler_(); } } } /** This method logs data to the used $(D Logger) with the $(D LogLevel) of the this $(D Logger) in a $(D printf)-style manner. In order for the data to be processed the $(D LogLevel) of the $(D Logger) must be greater or equal to the global $(D LogLevel). Params: msg = The format string used for this log call. args = The data that should be logged. Example: -------------------- auto s = new FileLogger(stdout); s.logf("%d %s", 1337, "is number"); s.logf("%d %s", 1337, "is number"); s.logf("%d %s", 1337, "is number"); s.logf("%d %s", 1337, "is number"); s.logf("%d %s", 1337, "is number"); -------------------- */ final void logf(int line = __LINE__, string file = __FILE__, string funcName = __FUNCTION__, string prettyFuncName = __PRETTY_FUNCTION__, string moduleName = __MODULE__, A...)(lazy string msg, lazy A args) { static if (isLoggingActive) synchronized (mutex) { if (isLoggingEnabled(this.logLevel_, this.logLevel_, globalLogLevel)) { this.beginLogMsg(file, line, funcName, prettyFuncName, moduleName, this.logLevel_, thisTid, Clock.currTime, this); auto writer = MsgRange(this); formattedWrite(writer, msg, args); this.finishLogMsg(); if (this.logLevel_ == LogLevel.fatal) this.fatalHandler_(); } } } private void delegate() @safe fatalHandler_; private shared LogLevel logLevel_ = LogLevel.info; private Mutex mutex; protected Appender!string msgAppender; protected LogEntry header; } // Thread Global private __gshared Mutex stdSharedLoggerMutex; private __gshared Logger stdSharedDefaultLogger; private shared Logger stdSharedLogger; private shared LogLevel stdLoggerGlobalLogLevel = LogLevel.all; /* This method returns the global default Logger. * Marked @trusted because of excessive reliance on __gshared data */ private @property Logger defaultSharedLoggerImpl() @trusted { static __gshared ubyte[__traits(classInstanceSize, FileLogger)] _buffer; synchronized (stdSharedLoggerMutex) { auto buffer = cast(ubyte[]) _buffer; if (stdSharedDefaultLogger is null) { stdSharedDefaultLogger = emplace!FileLogger(buffer, stderr, LogLevel.all); } } return stdSharedDefaultLogger; } /** This property sets and gets the default $(D Logger). Example: ------------- sharedLog = new FileLogger(yourFile); ------------- The example sets a new $(D FileLogger) as new $(D sharedLog). If at some point you want to use the original default logger again, you can use $(D sharedLog = null;). This will put back the original. Note: While getting and setting $(D sharedLog) is thread-safe, it has to be considered that the returned reference is only a current snapshot and in the following code, you must make sure no other thread reassigns to it between reading and writing $(D sharedLog). ------------- if (sharedLog !is myLogger) sharedLog = new myLogger; ------------- */ @property Logger sharedLog() @safe { static auto trustedLoad(ref shared Logger logger) @trusted { return atomicLoad!(MemoryOrder.acq)(logger); } // If we have set up our own logger use that if (auto logger = trustedLoad(stdSharedLogger)) { return logger; } else { // Otherwise resort to the default logger return defaultSharedLoggerImpl; } } /// Ditto @property void sharedLog(Logger logger) @trusted { atomicStore!(MemoryOrder.rel)(stdSharedLogger, cast(shared) logger); } /** This methods get and set the global $(D LogLevel). Every log message with a $(D LogLevel) lower as the global $(D LogLevel) will be discarded before it reaches $(D writeLogMessage) method of any $(D Logger). */ /* Implementation note: For any public logging call, the global log level shall only be queried once on entry. Otherwise when another threads changes the level, we would work with different levels at different spots in the code. */ @property LogLevel globalLogLevel() @safe @nogc { return trustedLoad(stdLoggerGlobalLogLevel); } /// Ditto @property void globalLogLevel(LogLevel ll) @safe { trustedStore(stdLoggerGlobalLogLevel, ll); } // Thread Local /** The $(D StdForwardLogger) will always forward anything to the sharedLog. The $(D StdForwardLogger) will not throw if data is logged with $(D LogLevel.fatal). */ class StdForwardLogger : Logger { /** The default constructor for the $(D StdForwardLogger). Params: lv = The $(D LogLevel) for the $(D MultiLogger). By default the $(D LogLevel) is $(D all). */ this(const LogLevel lv = LogLevel.all) @safe { super(lv); this.fatalHandler = delegate() {}; } override protected void writeLogMsg(ref LogEntry payload) { sharedLog.forwardMsg(payload); } } /// @safe unittest { auto nl1 = new StdForwardLogger(LogLevel.all); } /** This $(D LogLevel) is unqiue to every thread. The thread local $(D Logger) will use this $(D LogLevel) to filter log calls every same way as presented earlier. */ //public LogLevel threadLogLevel = LogLevel.all; private Logger stdLoggerThreadLogger; private Logger stdLoggerDefaultThreadLogger; /* This method returns the thread local default Logger. */ private @property Logger stdThreadLocalLogImpl() @trusted { static ubyte[__traits(classInstanceSize, StdForwardLogger)] _buffer; auto buffer = cast(ubyte[]) _buffer; if (stdLoggerDefaultThreadLogger is null) { stdLoggerDefaultThreadLogger = emplace!StdForwardLogger(buffer, LogLevel.all); } return stdLoggerDefaultThreadLogger; } /** This function returns a thread unique $(D Logger), that by default propergates all data logged to it to the $(D sharedLog). These properties can be used to set and get this $(D Logger). Every modification to this $(D Logger) will only be visible in the thread the modification has been done from. This $(D Logger) is called by the free standing log functions. This allows to create thread local redirections and still use the free standing log functions. */ @property Logger stdThreadLocalLog() @safe { // If we have set up our own logger use that if (auto logger = stdLoggerThreadLogger) return logger; else // Otherwise resort to the default logger return stdThreadLocalLogImpl; } /// Ditto @property void stdThreadLocalLog(Logger logger) @safe { stdLoggerThreadLogger = logger; } /// Ditto unittest { import std.file : deleteme, remove; Logger l = stdThreadLocalLog; stdThreadLocalLog = new FileLogger(deleteme ~ "-someFile.log"); scope(exit) remove(deleteme ~ "-someFile.log"); auto tempLog = stdThreadLocalLog; stdThreadLocalLog = l; destroy(tempLog); } @safe unittest { LogLevel ll = globalLogLevel; globalLogLevel = LogLevel.fatal; assert(globalLogLevel == LogLevel.fatal); globalLogLevel = ll; } package class TestLogger : Logger { int line = -1; string file = null; string func = null; string prettyFunc = null; string msg = null; LogLevel lvl; this(const LogLevel lv = LogLevel.all) @safe { super(lv); } override protected void writeLogMsg(ref LogEntry payload) @safe { this.line = payload.line; this.file = payload.file; this.func = payload.funcName; this.prettyFunc = payload.prettyFuncName; this.lvl = payload.logLevel; this.msg = payload.msg; } } version(unittest) private void testFuncNames(Logger logger) @safe { string s = "I'm here"; logger.log(s); } @safe unittest { auto tl1 = new TestLogger(); testFuncNames(tl1); assert(tl1.func == "std.experimental.logger.core.testFuncNames", tl1.func); assert(tl1.prettyFunc == "void std.experimental.logger.core.testFuncNames(Logger logger) @safe", tl1.prettyFunc); assert(tl1.msg == "I'm here", tl1.msg); } @safe unittest { auto tl1 = new TestLogger(LogLevel.all); tl1.log(); assert(tl1.line == __LINE__ - 1); tl1.log(true); assert(tl1.line == __LINE__ - 1); tl1.log(false); assert(tl1.line == __LINE__ - 3); tl1.log(LogLevel.info); assert(tl1.line == __LINE__ - 1); tl1.log(LogLevel.off); assert(tl1.line == __LINE__ - 3); tl1.log(LogLevel.info, true); assert(tl1.line == __LINE__ - 1); tl1.log(LogLevel.info, false); assert(tl1.line == __LINE__ - 3); auto oldunspecificLogger = sharedLog; scope(exit) { sharedLog = oldunspecificLogger; } sharedLog = tl1; log(); assert(tl1.line == __LINE__ - 1); log(LogLevel.info); assert(tl1.line == __LINE__ - 1); log(true); assert(tl1.line == __LINE__ - 1); log(LogLevel.warning, true); assert(tl1.line == __LINE__ - 1); trace(); assert(tl1.line == __LINE__ - 1); } @safe unittest { import std.experimental.logger.multilogger : MultiLogger; auto tl1 = new TestLogger; auto tl2 = new TestLogger; auto ml = new MultiLogger(); ml.insertLogger("one", tl1); ml.insertLogger("two", tl2); string msg = "Hello Logger World"; ml.log(msg); int lineNumber = __LINE__ - 1; assert(tl1.msg == msg); assert(tl1.line == lineNumber); assert(tl2.msg == msg); assert(tl2.line == lineNumber); ml.removeLogger("one"); ml.removeLogger("two"); auto n = ml.removeLogger("one"); assert(n is null); } @safe unittest { bool errorThrown = false; auto tl = new TestLogger; auto dele = delegate() { errorThrown = true; }; tl.fatalHandler = dele; tl.fatal(); assert(errorThrown); } @safe unittest { auto l = new TestLogger(LogLevel.all); string msg = "Hello Logger World"; l.log(msg); int lineNumber = __LINE__ - 1; assert(l.msg == msg); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); l.log(true, msg); lineNumber = __LINE__ - 1; assert(l.msg == msg, l.msg); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); l.log(false, msg); assert(l.msg == msg); assert(l.line == lineNumber, to!string(l.line)); assert(l.logLevel == LogLevel.all); msg = "%s Another message"; l.logf(msg, "Yet"); lineNumber = __LINE__ - 1; assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); l.logf(true, msg, "Yet"); lineNumber = __LINE__ - 1; assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); l.logf(false, msg, "Yet"); assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); () @trusted { assertThrown!Throwable(l.logf(LogLevel.fatal, msg, "Yet")); } (); lineNumber = __LINE__ - 2; assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); () @trusted { assertThrown!Throwable(l.logf(LogLevel.fatal, true, msg, "Yet")); } (); lineNumber = __LINE__ - 2; assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); assertNotThrown(l.logf(LogLevel.fatal, false, msg, "Yet")); assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); auto oldunspecificLogger = sharedLog; assert(oldunspecificLogger.logLevel == LogLevel.all, to!string(oldunspecificLogger.logLevel)); assert(l.logLevel == LogLevel.all); sharedLog = l; assert(globalLogLevel == LogLevel.all, to!string(globalLogLevel)); scope(exit) { sharedLog = oldunspecificLogger; } assert(sharedLog.logLevel == LogLevel.all); assert(stdThreadLocalLog.logLevel == LogLevel.all); assert(globalLogLevel == LogLevel.all); msg = "Another message"; log(msg); lineNumber = __LINE__ - 1; assert(l.logLevel == LogLevel.all); assert(l.line == lineNumber, to!string(l.line)); assert(l.msg == msg, l.msg); log(true, msg); lineNumber = __LINE__ - 1; assert(l.msg == msg); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); log(false, msg); assert(l.msg == msg); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); msg = "%s Another message"; logf(msg, "Yet"); lineNumber = __LINE__ - 1; assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); logf(true, msg, "Yet"); lineNumber = __LINE__ - 1; assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); logf(false, msg, "Yet"); assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); msg = "%s Another message"; () @trusted { assertThrown!Throwable(logf(LogLevel.fatal, msg, "Yet")); } (); lineNumber = __LINE__ - 2; assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); () @trusted { assertThrown!Throwable(logf(LogLevel.fatal, true, msg, "Yet")); } (); lineNumber = __LINE__ - 2; assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); assertNotThrown(logf(LogLevel.fatal, false, msg, "Yet")); assert(l.msg == msg.format("Yet")); assert(l.line == lineNumber); assert(l.logLevel == LogLevel.all); } unittest // default logger { import std.file : deleteme, exists, remove; string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile"; FileLogger l = new FileLogger(filename); auto oldunspecificLogger = sharedLog; sharedLog = l; scope(exit) { remove(filename); assert(!exists(filename)); sharedLog = oldunspecificLogger; globalLogLevel = LogLevel.all; } string notWritten = "this should not be written to file"; string written = "this should be written to file"; globalLogLevel = LogLevel.critical; assert(globalLogLevel == LogLevel.critical); log(LogLevel.warning, notWritten); log(LogLevel.critical, written); l.file.flush(); l.file.close(); auto file = File(filename, "r"); assert(!file.eof); string readLine = file.readln(); assert(readLine.indexOf(written) != -1, readLine); assert(readLine.indexOf(notWritten) == -1, readLine); file.close(); } unittest { import std.file : deleteme, remove; string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile"; auto oldunspecificLogger = sharedLog; scope(exit) { remove(filename); sharedLog = oldunspecificLogger; globalLogLevel = LogLevel.all; } string notWritten = "this should not be written to file"; string written = "this should be written to file"; auto l = new FileLogger(filename); sharedLog = l; sharedLog.logLevel = LogLevel.critical; log(LogLevel.error, false, notWritten); log(LogLevel.critical, true, written); destroy(l); auto file = File(filename, "r"); auto readLine = file.readln(); assert(!readLine.empty, readLine); assert(readLine.indexOf(written) != -1); assert(readLine.indexOf(notWritten) == -1); file.close(); } @safe unittest { auto tl = new TestLogger(LogLevel.all); int l = __LINE__; tl.info("a"); assert(tl.line == l+1); assert(tl.msg == "a"); assert(tl.logLevel == LogLevel.all); assert(globalLogLevel == LogLevel.all); l = __LINE__; tl.trace("b"); assert(tl.msg == "b", tl.msg); assert(tl.line == l+1, to!string(tl.line)); } // testing possible log conditions @safe unittest { auto oldunspecificLogger = sharedLog; auto mem = new TestLogger; mem.fatalHandler = delegate() {}; sharedLog = mem; scope(exit) { sharedLog = oldunspecificLogger; globalLogLevel = LogLevel.all; } int value = 0; foreach (gll; [cast(LogLevel) LogLevel.all, LogLevel.trace, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical, LogLevel.fatal, LogLevel.off]) { globalLogLevel = gll; foreach (ll; [cast(LogLevel) LogLevel.all, LogLevel.trace, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical, LogLevel.fatal, LogLevel.off]) { mem.logLevel = ll; foreach (cond; [true, false]) { foreach (condValue; [true, false]) { foreach (memOrG; [true, false]) { foreach (prntf; [true, false]) { foreach (ll2; [cast(LogLevel) LogLevel.all, LogLevel.trace, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical, LogLevel.fatal, LogLevel.off]) { foreach (singleMulti; 0 .. 2) { int lineCall; mem.msg = "-1"; if (memOrG) { if (prntf) { if (cond) { if (singleMulti == 0) { mem.logf(ll2, condValue, "%s", value); lineCall = __LINE__; } else { mem.logf(ll2, condValue, "%d %d", value, value); lineCall = __LINE__; } } else { if (singleMulti == 0) { mem.logf(ll2, "%s", value); lineCall = __LINE__; } else { mem.logf(ll2, "%d %d", value, value); lineCall = __LINE__; } } } else { if (cond) { if (singleMulti == 0) { mem.log(ll2, condValue, to!string(value)); lineCall = __LINE__; } else { mem.log(ll2, condValue, to!string(value), value); lineCall = __LINE__; } } else { if (singleMulti == 0) { mem.log(ll2, to!string(value)); lineCall = __LINE__; } else { mem.log(ll2, to!string(value), value); lineCall = __LINE__; } } } } else { if (prntf) { if (cond) { if (singleMulti == 0) { logf(ll2, condValue, "%s", value); lineCall = __LINE__; } else { logf(ll2, condValue, "%s %d", value, value); lineCall = __LINE__; } } else { if (singleMulti == 0) { logf(ll2, "%s", value); lineCall = __LINE__; } else { logf(ll2, "%s %s", value, value); lineCall = __LINE__; } } } else { if (cond) { if (singleMulti == 0) { log(ll2, condValue, to!string(value)); lineCall = __LINE__; } else { log(ll2, condValue, value, to!string(value)); lineCall = __LINE__; } } else { if (singleMulti == 0) { log(ll2, to!string(value)); lineCall = __LINE__; } else { log(ll2, value, to!string(value)); lineCall = __LINE__; } } } } string valueStr = to!string(value); ++value; bool ll2Off = (ll2 != LogLevel.off); bool gllOff = (gll != LogLevel.off); bool llOff = (ll != LogLevel.off); bool condFalse = (cond ? condValue : true); bool ll2VSgll = (ll2 >= gll); bool ll2VSll = (ll2 >= ll); bool shouldLog = ll2Off && gllOff && llOff && condFalse && ll2VSgll && ll2VSll; /* writefln( "go(%b) ll2o(%b) c(%b) lg(%b) ll(%b) s(%b)" , gll != LogLevel.off, ll2 != LogLevel.off, cond ? condValue : true, ll2 >= gll, ll2 >= ll, shouldLog); */ if (shouldLog) { assert(mem.msg.indexOf(valueStr) != -1, format( "lineCall(%d) ll2Off(%u) gll(%u) ll(%u) ll2(%u) " ~ "cond(%b) condValue(%b)" ~ " memOrG(%b) shouldLog(%b) %s == %s" ~ " %b %b %b %b %b", lineCall, ll2Off, gll, ll, ll2, cond, condValue, memOrG, shouldLog, mem.msg, valueStr, gllOff, llOff, condFalse, ll2VSgll, ll2VSll )); } else { assert(mem.msg.indexOf(valueStr), format( "lineCall(%d) ll2Off(%u) gll(%u) ll(%u) ll2(%u) " ~ "cond(%b) condValue(%b)" ~ " memOrG(%b) shouldLog(%b) %s == %s" ~ " %b %b %b %b %b", lineCall, ll2Off, gll, ll, ll2, cond, condValue, memOrG, shouldLog, mem.msg, valueStr, gllOff, llOff, condFalse, ll2VSgll, ll2VSll )); } } } } } } } } } } // more testing @safe unittest { auto oldunspecificLogger = sharedLog; auto mem = new TestLogger; mem.fatalHandler = delegate() {}; sharedLog = mem; scope(exit) { sharedLog = oldunspecificLogger; globalLogLevel = LogLevel.all; } int value = 0; foreach (gll; [cast(LogLevel) LogLevel.all, LogLevel.trace, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical, LogLevel.fatal, LogLevel.off]) { globalLogLevel = gll; foreach (ll; [cast(LogLevel) LogLevel.all, LogLevel.trace, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical, LogLevel.fatal, LogLevel.off]) { mem.logLevel = ll; foreach (tll; [cast(LogLevel) LogLevel.all, LogLevel.trace, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical, LogLevel.fatal, LogLevel.off]) { stdThreadLocalLog.logLevel = tll; foreach (cond; [true, false]) { foreach (condValue; [true, false]) { foreach (memOrG; [true, false]) { foreach (prntf; [true, false]) { foreach (singleMulti; 0 .. 2) { int lineCall; mem.msg = "-1"; if (memOrG) { if (prntf) { if (cond) { if (singleMulti == 0) { mem.logf(condValue, "%s", value); lineCall = __LINE__; } else { mem.logf(condValue, "%d %d", value, value); lineCall = __LINE__; } } else { if (singleMulti == 0) { mem.logf("%s", value); lineCall = __LINE__; } else { mem.logf("%d %d", value, value); lineCall = __LINE__; } } } else { if (cond) { if (singleMulti == 0) { mem.log(condValue, to!string(value)); lineCall = __LINE__; } else { mem.log(condValue, to!string(value), value); lineCall = __LINE__; } } else { if (singleMulti == 0) { mem.log(to!string(value)); lineCall = __LINE__; } else { mem.log(to!string(value), value); lineCall = __LINE__; } } } } else { if (prntf) { if (cond) { if (singleMulti == 0) { logf(condValue, "%s", value); lineCall = __LINE__; } else { logf(condValue, "%s %d", value, value); lineCall = __LINE__; } } else { if (singleMulti == 0) { logf("%s", value); lineCall = __LINE__; } else { logf("%s %s", value, value); lineCall = __LINE__; } } } else { if (cond) { if (singleMulti == 0) { log(condValue, to!string(value)); lineCall = __LINE__; } else { log(condValue, value, to!string(value)); lineCall = __LINE__; } } else { if (singleMulti == 0) { log(to!string(value)); lineCall = __LINE__; } else { log(value, to!string(value)); lineCall = __LINE__; } } } } string valueStr = to!string(value); ++value; bool gllOff = (gll != LogLevel.off); bool llOff = (ll != LogLevel.off); bool tllOff = (tll != LogLevel.off); bool llVSgll = (ll >= gll); bool tllVSll = (stdThreadLocalLog.logLevel >= ll); bool condFalse = (cond ? condValue : true); bool shouldLog = gllOff && llOff && (memOrG ? true : tllOff) && (memOrG ? (ll >= gll) : (tll >= gll && tll >= ll)) && condFalse; if (shouldLog) { assert(mem.msg.indexOf(valueStr) != -1, format("\ngll(%s) ll(%s) tll(%s) " ~ "cond(%s) condValue(%s) " ~ "memOrG(%s) prntf(%s) " ~ "singleMulti(%s)", gll, ll, tll, cond, condValue, memOrG, prntf, singleMulti) ~ format(" gllOff(%s) llOff(%s) " ~ "llVSgll(%s) tllVSll(%s) " ~ "tllOff(%s) condFalse(%s) " ~ "shoudlLog(%s)", gll != LogLevel.off, ll != LogLevel.off, llVSgll, tllVSll, tllOff, condFalse, shouldLog) ~ format("msg(%s) line(%s) " ~ "lineCall(%s) valueStr(%s)", mem.msg, mem.line, lineCall, valueStr) ); } else { assert(mem.msg.indexOf(valueStr) == -1, format("\ngll(%s) ll(%s) tll(%s) " ~ "cond(%s) condValue(%s) " ~ "memOrG(%s) prntf(%s) " ~ "singleMulti(%s)", gll, ll, tll, cond, condValue, memOrG, prntf, singleMulti) ~ format(" gllOff(%s) llOff(%s) " ~ "llVSgll(%s) tllVSll(%s) " ~ "tllOff(%s) condFalse(%s) " ~ "shoudlLog(%s)", gll != LogLevel.off, ll != LogLevel.off, llVSgll, tllVSll, tllOff, condFalse, shouldLog) ~ format("msg(%s) line(%s) " ~ "lineCall(%s) valueStr(%s)", mem.msg, mem.line, lineCall, valueStr) ); } } } } } } } } } } // testing more possible log conditions @safe unittest { bool fatalLog; auto mem = new TestLogger; mem.fatalHandler = delegate() { fatalLog = true; }; auto oldunspecificLogger = sharedLog; stdThreadLocalLog.logLevel = LogLevel.all; sharedLog = mem; scope(exit) { sharedLog = oldunspecificLogger; globalLogLevel = LogLevel.all; } foreach (gll; [cast(LogLevel) LogLevel.all, LogLevel.trace, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical, LogLevel.fatal, LogLevel.off]) { globalLogLevel = gll; foreach (ll; [cast(LogLevel) LogLevel.all, LogLevel.trace, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical, LogLevel.fatal, LogLevel.off]) { mem.logLevel = ll; foreach (tll; [cast(LogLevel) LogLevel.all, LogLevel.trace, LogLevel.info, LogLevel.warning, LogLevel.error, LogLevel.critical, LogLevel.fatal, LogLevel.off]) { stdThreadLocalLog.logLevel = tll; foreach (cond; [true, false]) { assert(globalLogLevel == gll); assert(mem.logLevel == ll); bool gllVSll = LogLevel.trace >= globalLogLevel; bool llVSgll = ll >= globalLogLevel; bool lVSll = LogLevel.trace >= ll; bool gllOff = globalLogLevel != LogLevel.off; bool llOff = mem.logLevel != LogLevel.off; bool tllOff = stdThreadLocalLog.logLevel != LogLevel.off; bool tllVSll = tll >= ll; bool tllVSgll = tll >= gll; bool lVSgll = LogLevel.trace >= tll; bool test = llVSgll && gllVSll && lVSll && gllOff && llOff && cond; bool testG = gllOff && llOff && tllOff && lVSgll && tllVSll && tllVSgll && cond; mem.line = -1; /* writefln("gll(%3u) ll(%3u) cond(%b) test(%b)", gll, ll, cond, test); writefln("%b %b %b %b %b %b test2(%b)", llVSgll, gllVSll, lVSll, gllOff, llOff, cond, test2); */ mem.trace(__LINE__); int line = __LINE__; assert(test ? mem.line == line : true); line = -1; trace(__LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.trace(cond, __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; trace(cond, __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.tracef("%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; tracef("%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.tracef(cond, "%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; tracef(cond, "%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; llVSgll = ll >= globalLogLevel; lVSll = LogLevel.info >= ll; lVSgll = LogLevel.info >= tll; test = llVSgll && gllVSll && lVSll && gllOff && llOff && cond; testG = gllOff && llOff && tllOff && tllVSll && tllVSgll && lVSgll && cond; mem.info(__LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; info(__LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.info(cond, __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; info(cond, __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.infof("%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; infof("%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.infof(cond, "%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; infof(cond, "%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; llVSgll = ll >= globalLogLevel; lVSll = LogLevel.warning >= ll; lVSgll = LogLevel.warning >= tll; test = llVSgll && gllVSll && lVSll && gllOff && llOff && cond; testG = gllOff && llOff && tllOff && tllVSll && tllVSgll && lVSgll && cond; mem.warning(__LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; warning(__LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.warning(cond, __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; warning(cond, __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.warningf("%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; warningf("%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.warningf(cond, "%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; warningf(cond, "%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; llVSgll = ll >= globalLogLevel; lVSll = LogLevel.critical >= ll; lVSgll = LogLevel.critical >= tll; test = llVSgll && gllVSll && lVSll && gllOff && llOff && cond; testG = gllOff && llOff && tllOff && tllVSll && tllVSgll && lVSgll && cond; mem.critical(__LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; critical(__LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.critical(cond, __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; critical(cond, __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.criticalf("%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; criticalf("%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; mem.criticalf(cond, "%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; criticalf(cond, "%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; llVSgll = ll >= globalLogLevel; lVSll = LogLevel.fatal >= ll; lVSgll = LogLevel.fatal >= tll; test = llVSgll && gllVSll && lVSll && gllOff && llOff && cond; testG = gllOff && llOff && tllOff && tllVSll && tllVSgll && lVSgll && cond; mem.fatal(__LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; assert(test ? fatalLog : true); fatalLog = false; fatal(__LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; assert(testG ? fatalLog : true); fatalLog = false; mem.fatal(cond, __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; assert(test ? fatalLog : true); fatalLog = false; fatal(cond, __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; assert(testG ? fatalLog : true); fatalLog = false; mem.fatalf("%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; assert(test ? fatalLog : true); fatalLog = false; fatalf("%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; assert(testG ? fatalLog : true); fatalLog = false; mem.fatalf(cond, "%d", __LINE__); line = __LINE__; assert(test ? mem.line == line : true); line = -1; assert(test ? fatalLog : true); fatalLog = false; fatalf(cond, "%d", __LINE__); line = __LINE__; assert(testG ? mem.line == line : true); line = -1; assert(testG ? fatalLog : true); fatalLog = false; } } } } } // Issue #5 @safe unittest { auto oldunspecificLogger = sharedLog; scope(exit) { sharedLog = oldunspecificLogger; globalLogLevel = LogLevel.all; } auto tl = new TestLogger(LogLevel.info); sharedLog = tl; trace("trace"); assert(tl.msg.indexOf("trace") == -1); } // Issue #5 @safe unittest { import std.experimental.logger.multilogger : MultiLogger; stdThreadLocalLog.logLevel = LogLevel.all; auto oldunspecificLogger = sharedLog; scope(exit) { sharedLog = oldunspecificLogger; globalLogLevel = LogLevel.all; } auto logger = new MultiLogger(LogLevel.error); auto tl = new TestLogger(LogLevel.info); logger.insertLogger("required", tl); sharedLog = logger; trace("trace"); assert(tl.msg.indexOf("trace") == -1); info("info"); assert(tl.msg.indexOf("info") == -1); error("error"); assert(tl.msg.indexOf("error") == 0); } unittest { import std.exception : assertThrown; auto tl = new TestLogger(); assertThrown!Throwable(tl.fatal("fatal")); } // log objects with non-safe toString unittest { struct Test { string toString() const @system { return "test"; } } auto tl = new TestLogger(); tl.info(Test.init); assert(tl.msg == "test"); } // Workaround for atomics not allowed in @safe code private auto trustedLoad(T)(ref shared T value) @trusted { return atomicLoad!(MemoryOrder.acq)(value); } // ditto private void trustedStore(T)(ref shared T dst, ref T src) @trusted { atomicStore!(MemoryOrder.rel)(dst, src); } // check that thread-local logging does not propagate // to shared logger unittest { import std.concurrency, core.atomic, core.thread; static shared logged_count = 0; class TestLog : Logger { Tid tid; this() { super (LogLevel.trace); this.tid = thisTid; } override void writeLogMsg(ref LogEntry payload) @trusted { assert(thisTid == this.tid); atomicOp!"+="(logged_count, 1); } } class IgnoredLog : Logger { this() { super (LogLevel.trace); } override void writeLogMsg(ref LogEntry payload) @trusted { assert(false); } } auto oldSharedLog = sharedLog; scope(exit) { sharedLog = oldSharedLog; } sharedLog = new IgnoredLog; Thread[] spawned; foreach (i; 0..4) { spawned ~= new Thread({ stdThreadLocalLog = new TestLog; trace("zzzzzzzzzz"); }); spawned[$-1].start(); } foreach (t; spawned) t.join(); assert (atomicOp!"=="(logged_count, 4)); } @safe unittest { auto dl = cast(FileLogger)sharedLog; assert(dl !is null); assert(dl.logLevel == LogLevel.all); assert(globalLogLevel == LogLevel.all); auto tl = cast(StdForwardLogger)stdThreadLocalLog; assert(tl !is null); stdThreadLocalLog.logLevel = LogLevel.all; } // Issue 14940 @safe unittest { import std.typecons : Nullable; Nullable!int a = 1; auto l = new TestLogger(); l.infof("log: %s", a); assert(l.msg == "log: 1"); } // Ensure @system toString methods work unittest { enum SystemToStringMsg = "SystemToString"; static struct SystemToString { string toString() @system { return SystemToStringMsg; } } auto tl = new TestLogger(); SystemToString sts; tl.logf("%s", sts); assert(tl.msg == SystemToStringMsg); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/logger/filelogger.d0000664000175000017500000001404012776215007024145 0ustar kaikaimodule std.experimental.logger.filelogger; import std.stdio; import std.experimental.logger.core; /** This $(D Logger) implementation writes log messages to the associated file. The name of the file has to be passed on construction time. If the file is already present new log messages will be append at its end. */ class FileLogger : Logger { import std.format : formattedWrite; import std.datetime : SysTime; import std.concurrency : Tid; /** A constructor for the $(D FileLogger) Logger. Params: fn = The filename of the output file of the $(D FileLogger). If that file can not be opened for writting an exception will be thrown. lv = The $(D LogLevel) for the $(D FileLogger). By default the $(D LogLevel) for $(D FileLogger) is $(D LogLevel.all). Example: ------------- auto l1 = new FileLogger("logFile", "loggerName"); auto l2 = new FileLogger("logFile", "loggerName", LogLevel.fatal); ------------- */ this(in string fn, const LogLevel lv = LogLevel.all) @safe { import std.exception : enforce; super(lv); this.filename = fn; this.file_.open(this.filename, "a"); } /** A constructor for the $(D FileLogger) Logger that takes a reference to a $(D File). The $(D File) passed must be open for all the log call to the $(D FileLogger). If the $(D File) gets closed, using the $(D FileLogger) for logging will result in undefined behaviour. Params: file = The file used for logging. lv = The $(D LogLevel) for the $(D FileLogger). By default the $(D LogLevel) for $(D FileLogger) is $(D LogLevel.all). Example: ------------- auto file = File("logFile.log", "w"); auto l1 = new FileLogger(file, "LoggerName"); auto l2 = new FileLogger(file, "LoggerName", LogLevel.fatal); ------------- */ this(File file, const LogLevel lv = LogLevel.all) @safe { super(lv); this.file_ = file; } /** If the $(D FileLogger) is managing the $(D File) it logs to, this method will return a reference to this File. */ @property File file() @safe { return this.file_; } /* This method overrides the base class method in order to log to a file without requiring heap allocated memory. Additionally, the $(D FileLogger) local mutex is logged to serialize the log calls. */ override protected void beginLogMsg(string file, int line, string funcName, string prettyFuncName, string moduleName, LogLevel logLevel, Tid threadId, SysTime timestamp, Logger logger) @safe { import std.string : lastIndexOf; ptrdiff_t fnIdx = file.lastIndexOf('/') + 1; ptrdiff_t funIdx = funcName.lastIndexOf('.') + 1; auto lt = this.file_.lockingTextWriter(); systimeToISOString(lt, timestamp); formattedWrite(lt, ":%s:%s:%u ", file[fnIdx .. $], funcName[funIdx .. $], line); } /* This methods overrides the base class method and writes the parts of the log call directly to the file. */ override protected void logMsgPart(const(char)[] msg) { formattedWrite(this.file_.lockingTextWriter(), "%s", msg); } /* This methods overrides the base class method and finalizes the active log call. This requires flushing the $(D File) and releasing the $(D FileLogger) local mutex. */ override protected void finishLogMsg() { this.file_.lockingTextWriter().put("\n"); this.file_.flush(); } /* This methods overrides the base class method and delegates the $(D LogEntry) data to the actual implementation. */ override protected void writeLogMsg(ref LogEntry payload) { this.beginLogMsg(payload.file, payload.line, payload.funcName, payload.prettyFuncName, payload.moduleName, payload.logLevel, payload.threadId, payload.timestamp, payload.logger); this.logMsgPart(payload.msg); this.finishLogMsg(); } /** If the $(D FileLogger) was constructed with a filename, this method returns this filename. Otherwise an empty $(D string) is returned. */ string getFilename() { return this.filename; } private File file_; private string filename; } unittest { import std.file : deleteme, remove; import std.array : empty; import std.string : indexOf; string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile"; auto l = new FileLogger(filename); scope(exit) { remove(filename); } string notWritten = "this should not be written to file"; string written = "this should be written to file"; l.logLevel = LogLevel.critical; l.log(LogLevel.warning, notWritten); l.log(LogLevel.critical, written); destroy(l); auto file = File(filename, "r"); string readLine = file.readln(); assert(readLine.indexOf(written) != -1, readLine); readLine = file.readln(); assert(readLine.indexOf(notWritten) == -1, readLine); } unittest { import std.file : deleteme, remove; import std.array : empty; import std.string : indexOf; string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile"; auto file = File(filename, "w"); auto l = new FileLogger(file); scope(exit) { remove(filename); } string notWritten = "this should not be written to file"; string written = "this should be written to file"; l.logLevel = LogLevel.critical; l.log(LogLevel.warning, notWritten); l.log(LogLevel.critical, written); file.close(); file = File(filename, "r"); string readLine = file.readln(); assert(readLine.indexOf(written) != -1, readLine); readLine = file.readln(); assert(readLine.indexOf(notWritten) == -1, readLine); file.close(); } @safe unittest { auto dl = cast(FileLogger)sharedLog; assert(dl !is null); assert(dl.logLevel == LogLevel.all); assert(globalLogLevel == LogLevel.all); auto tl = cast(StdForwardLogger)stdThreadLocalLog; assert(tl !is null); stdThreadLocalLog.logLevel = LogLevel.all; } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/0000775000175000017500000000000012776215007022363 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/showcase.d0000664000175000017500000000540212776215007024345 0ustar kaikai/** Collection of typical and useful prebuilt allocators using the given components. User code would typically import this module and use its facilities, or import individual heap building blocks and assemble them. */ module std.experimental.allocator.showcase; import std.experimental.allocator.building_blocks.fallback_allocator, std.experimental.allocator.gc_allocator, std.experimental.allocator.building_blocks.region; import std.traits : hasMember; /** Allocator that uses stack allocation for up to $(D stackSize) bytes and then falls back to $(D Allocator). Defined as: ---- alias StackFront(size_t stackSize, Allocator) = FallbackAllocator!( InSituRegion!(stackSize, Allocator.alignment, hasMember!(Allocator, "deallocate") ? Yes.defineDeallocate : No.defineDeallocate), Allocator); ---- Choosing `stackSize` is as always a compromise. Too small a size exhausts the stack storage after a few allocations, after which there are no gains over the backup allocator. Too large a size increases the stack consumed by the thread and may end up worse off because it explores cold portions of the stack. */ alias StackFront(size_t stackSize, Allocator = GCAllocator) = FallbackAllocator!( InSituRegion!(stackSize, Allocator.alignment), Allocator); /// unittest { StackFront!4096 a; auto b = a.allocate(4000); assert(b.length == 4000); auto c = a.allocate(4000); assert(c.length == 4000); a.deallocate(b); a.deallocate(c); } /** Creates a scalable `AllocatorList` of `Regions`, each having at least `bytesPerRegion` bytes. Allocation is very fast. This allocator does not offer `deallocate` but does free all regions in its destructor. It is recommended for short-lived batch applications that count on never running out of memory. */ auto mmapRegionList(size_t bytesPerRegion) { static struct Factory { size_t bytesPerRegion; private import std.algorithm : max; private import std.experimental.allocator.building_blocks.region : Region; private import std.experimental.allocator.mmap_allocator : MmapAllocator; this(size_t n) { bytesPerRegion = n; } auto opCall(size_t n) { return Region!MmapAllocator(max(n, bytesPerRegion)); } } import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; auto shop = Factory(bytesPerRegion); return AllocatorList!(Factory, NullAllocator)(shop); } /// unittest { auto alloc = mmapRegionList(1024 * 1024); const b = alloc.allocate(100); assert(b.length == 100); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/common.d0000664000175000017500000004721612776215007024032 0ustar kaikai/** Utility and ancillary artifacts of `std.experimental.allocator`. This module shouldn't be used directly; its functionality will be migrated into more appropriate parts of `std`. Authors: $(WEB erdani.com, Andrei Alexandrescu), Timon Gehr (`Ternary`) */ module std.experimental.allocator.common; import std.algorithm, std.traits; /** Ternary type with three thruth values. */ struct Ternary { @safe @nogc nothrow pure: package ubyte value = 6; package static Ternary make(ubyte b) { Ternary r = void; r.value = b; return r; } /** In addition to `false` and `true`, `Ternary` offers `unknown`. */ enum no = make(0); /// ditto enum yes = make(2); /// ditto enum unknown = make(6); /** Construct and assign from a `bool`, receiving `no` for `false` and `yes` for `true`. */ this(bool b) { value = b << 1; } /// ditto void opAssign(bool b) { value = b << 1; } /** Construct a ternary value from another ternary value */ this(const Ternary b) { value = b.value; } /** $(TABLE Truth table for logical operations, $(TR $(TH `a`) $(TH `b`) $(TH `$(TILDE)a`) $(TH `a | b`) $(TH `a & b`) $(TH `a ^ b`)) $(TR $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `no`)) $(TR $(TD `no`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `no`) $(TD `yes`)) $(TR $(TD `no`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `no`) $(TD `unknown`)) $(TR $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `yes`)) $(TR $(TD `yes`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `yes`) $(TD `no`)) $(TR $(TD `yes`) $(TD `unknown`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`)) $(TR $(TD `unknown`) $(TD `no`) $(TD `unknown`) $(TD `unknown`) $(TD `no`) $(TD `unknown`)) $(TR $(TD `unknown`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`)) $(TR $(TD `unknown`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `unknown`) $(TD `unknown`)) ) */ Ternary opUnary(string s)() if (s == "~") { return make(386 >> value & 6); } /// ditto Ternary opBinary(string s)(Ternary rhs) if (s == "|") { return make(25_512 >> value + rhs.value & 6); } /// ditto Ternary opBinary(string s)(Ternary rhs) if (s == "&") { return make(26_144 >> value + rhs.value & 6); } /// ditto Ternary opBinary(string s)(Ternary rhs) if (s == "^") { return make(26_504 >> value + rhs.value & 6); } } @safe @nogc nothrow pure unittest { alias f = Ternary.no, t = Ternary.yes, u = Ternary.unknown; Ternary[27] truthTableAnd = [ t, t, t, t, u, u, t, f, f, u, t, u, u, u, u, u, f, f, f, t, f, f, u, f, f, f, f, ]; Ternary[27] truthTableOr = [ t, t, t, t, u, t, t, f, t, u, t, t, u, u, u, u, f, u, f, t, t, f, u, u, f, f, f, ]; Ternary[27] truthTableXor = [ t, t, f, t, u, u, t, f, t, u, t, u, u, u, u, u, f, u, f, t, t, f, u, u, f, f, f, ]; for (auto i = 0; i != truthTableAnd.length; i += 3) { assert((truthTableAnd[i] & truthTableAnd[i + 1]) == truthTableAnd[i + 2]); assert((truthTableOr[i] | truthTableOr[i + 1]) == truthTableOr[i + 2]); assert((truthTableXor[i] ^ truthTableXor[i + 1]) == truthTableXor[i + 2]); } Ternary a; assert(a == Ternary.unknown); static assert(!is(typeof({ if (a) {} }))); assert(!is(typeof({ auto b = Ternary(3); }))); a = true; assert(a == Ternary.yes); a = false; assert(a == Ternary.no); a = Ternary.unknown; assert(a == Ternary.unknown); Ternary b; b = a; assert(b == a); assert(~Ternary.yes == Ternary.no); assert(~Ternary.no == Ternary.yes); assert(~Ternary.unknown == Ternary.unknown); } /** Returns the size in bytes of the state that needs to be allocated to hold an object of type $(D T). $(D stateSize!T) is zero for $(D struct)s that are not nested and have no nonstatic member variables. */ template stateSize(T) { static if (is(T == class) || is(T == interface)) enum stateSize = __traits(classInstanceSize, T); else static if (is(T == struct) || is(T == union)) enum stateSize = Fields!T.length || isNested!T ? T.sizeof : 0; else static if (is(T == void)) enum size_t stateSize = 0; else enum stateSize = T.sizeof; } @safe @nogc nothrow pure unittest { static assert(stateSize!void == 0); struct A {} static assert(stateSize!A == 0); struct B { int x; } static assert(stateSize!B == 4); interface I1 {} //static assert(stateSize!I1 == 2 * size_t.sizeof); class C1 {} static assert(stateSize!C1 == 3 * size_t.sizeof); class C2 { char c; } static assert(stateSize!C2 == 4 * size_t.sizeof); static class C3 { char c; } static assert(stateSize!C3 == 2 * size_t.sizeof + char.sizeof); } /** $(D chooseAtRuntime) is a compile-time constant of type $(D size_t) that several parameterized structures in this module recognize to mean deferral to runtime of the exact value. For example, $(D BitmappedBlock!(Allocator, 4096)) (described in detail below) defines a block allocator with block size of 4096 bytes, whereas $(D BitmappedBlock!(Allocator, chooseAtRuntime)) defines a block allocator that has a field storing the block size, initialized by the user. */ enum chooseAtRuntime = size_t.max - 1; /** $(D unbounded) is a compile-time constant of type $(D size_t) that several parameterized structures in this module recognize to mean "infinite" bounds for the parameter. For example, $(D Freelist) (described in detail below) accepts a $(D maxNodes) parameter limiting the number of freelist items. If $(D unbounded) is passed for $(D maxNodes), then there is no limit and no checking for the number of nodes. */ enum unbounded = size_t.max; /** The alignment that is guaranteed to accommodate any D object allocation on the current platform. */ enum uint platformAlignment = std.algorithm.max(double.alignof, real.alignof); /** The default good size allocation is deduced as $(D n) rounded up to the allocator's alignment. */ size_t goodAllocSize(A)(auto ref A a, size_t n) { return n.roundUpToMultipleOf(a.alignment); } /** Returns s rounded up to a multiple of base. */ @safe @nogc nothrow pure package size_t roundUpToMultipleOf(size_t s, uint base) { assert(base); auto rem = s % base; return rem ? s + base - rem : s; } @safe @nogc nothrow pure unittest { assert(10.roundUpToMultipleOf(11) == 11); assert(11.roundUpToMultipleOf(11) == 11); assert(12.roundUpToMultipleOf(11) == 22); assert(118.roundUpToMultipleOf(11) == 121); } /** Returns `n` rounded up to a multiple of alignment, which must be a power of 2. */ @safe @nogc nothrow pure package size_t roundUpToAlignment(size_t n, uint alignment) { assert(alignment.isPowerOf2); immutable uint slack = cast(uint) n & (alignment - 1); const result = slack ? n + alignment - slack : n; assert(result >= n); return result; } @safe @nogc nothrow pure unittest { assert(10.roundUpToAlignment(4) == 12); assert(11.roundUpToAlignment(2) == 12); assert(12.roundUpToAlignment(8) == 16); assert(118.roundUpToAlignment(64) == 128); } /** Returns `n` rounded down to a multiple of alignment, which must be a power of 2. */ @safe @nogc nothrow pure package size_t roundDownToAlignment(size_t n, uint alignment) { assert(alignment.isPowerOf2); return n & ~size_t(alignment - 1); } @safe @nogc nothrow pure unittest { assert(10.roundDownToAlignment(4) == 8); assert(11.roundDownToAlignment(2) == 10); assert(12.roundDownToAlignment(8) == 8); assert(63.roundDownToAlignment(64) == 0); } /** Advances the beginning of `b` to start at alignment `a`. The resulting buffer may therefore be shorter. Returns the adjusted buffer, or null if obtaining a non-empty buffer is impossible. */ @nogc nothrow pure package void[] roundUpToAlignment(void[] b, uint a) { auto e = b.ptr + b.length; auto p = cast(void*) roundUpToAlignment(cast(size_t) b.ptr, a); if (e <= p) return null; return p[0 .. e - p]; } @nogc nothrow pure unittest { void[] empty; assert(roundUpToAlignment(empty, 4) == null); char[128] buf; // At least one pointer inside buf is 128-aligned assert(roundUpToAlignment(buf, 128) !is null); } /** Like `a / b` but rounds the result up, not down. */ @safe @nogc nothrow pure package size_t divideRoundUp(size_t a, size_t b) { assert(b); return (a + b - 1) / b; } /** Returns `s` rounded up to a multiple of `base`. */ @nogc nothrow pure package void[] roundStartToMultipleOf(void[] s, uint base) { assert(base); auto p = cast(void*) roundUpToMultipleOf( cast(size_t) s.ptr, base); auto end = s.ptr + s.length; return p[0 .. end - p]; } nothrow pure unittest { void[] p; assert(roundStartToMultipleOf(p, 16) is null); p = new ulong[10]; assert(roundStartToMultipleOf(p, 16) is p); } /** Returns $(D s) rounded up to the nearest power of 2. */ @safe @nogc nothrow pure package size_t roundUpToPowerOf2(size_t s) { import std.meta : AliasSeq; assert(s <= (size_t.max >> 1) + 1); --s; static if (size_t.sizeof == 4) alias Shifts = AliasSeq!(1, 2, 4, 8, 16); else alias Shifts = AliasSeq!(1, 2, 4, 8, 16, 32); foreach (i; Shifts) { s |= s >> i; } return s + 1; } @safe @nogc nothrow pure unittest { assert(0.roundUpToPowerOf2 == 0); assert(1.roundUpToPowerOf2 == 1); assert(2.roundUpToPowerOf2 == 2); assert(3.roundUpToPowerOf2 == 4); assert(7.roundUpToPowerOf2 == 8); assert(8.roundUpToPowerOf2 == 8); assert(10.roundUpToPowerOf2 == 16); assert(11.roundUpToPowerOf2 == 16); assert(12.roundUpToPowerOf2 == 16); assert(118.roundUpToPowerOf2 == 128); assert((size_t.max >> 1).roundUpToPowerOf2 == (size_t.max >> 1) + 1); assert(((size_t.max >> 1) + 1).roundUpToPowerOf2 == (size_t.max >> 1) + 1); } /** Returns the number of trailing zeros of $(D x). */ @safe @nogc nothrow pure package uint trailingZeros(ulong x) { uint result; while (result < 64 && !(x & (1UL << result))) { ++result; } return result; } @safe @nogc nothrow pure unittest { assert(trailingZeros(0) == 64); assert(trailingZeros(1) == 0); assert(trailingZeros(2) == 1); assert(trailingZeros(3) == 0); assert(trailingZeros(4) == 2); } /** Returns `true` if `ptr` is aligned at `alignment`. */ @nogc nothrow pure package bool alignedAt(void* ptr, uint alignment) { return cast(size_t) ptr % alignment == 0; } /** Returns the effective alignment of `ptr`, i.e. the largest power of two that is a divisor of `ptr`. */ @nogc nothrow pure package uint effectiveAlignment(void* ptr) { return 1U << trailingZeros(cast(size_t) ptr); } @nogc nothrow pure unittest { int x; assert(effectiveAlignment(&x) >= int.alignof); } /** Aligns a pointer down to a specified alignment. The resulting pointer is less than or equal to the given pointer. */ @nogc nothrow pure package void* alignDownTo(void* ptr, uint alignment) { assert(alignment.isPowerOf2); return cast(void*) (cast(size_t) ptr & ~(alignment - 1UL)); } /** Aligns a pointer up to a specified alignment. The resulting pointer is greater than or equal to the given pointer. */ @nogc nothrow pure package void* alignUpTo(void* ptr, uint alignment) { assert(alignment.isPowerOf2); immutable uint slack = cast(size_t) ptr & (alignment - 1U); return slack ? ptr + alignment - slack : ptr; } // Credit: Matthias Bentrup /** Returns `true` if `x` is a nonzero power of two. */ @safe @nogc nothrow pure package bool isPowerOf2(uint x) { return (x & -x) > (x - 1); } @safe @nogc nothrow pure unittest { assert(!isPowerOf2(0)); assert(isPowerOf2(1)); assert(isPowerOf2(2)); assert(!isPowerOf2(3)); assert(isPowerOf2(4)); assert(!isPowerOf2(5)); assert(!isPowerOf2(6)); assert(!isPowerOf2(7)); assert(isPowerOf2(8)); assert(!isPowerOf2(9)); assert(!isPowerOf2(10)); assert(isPowerOf2(1UL << 31)); } @safe @nogc nothrow pure package bool isGoodStaticAlignment(uint x) { return x.isPowerOf2; } @safe @nogc nothrow pure package bool isGoodDynamicAlignment(uint x) { return x.isPowerOf2 && x >= (void*).sizeof; } /* If $(D b.length + delta <= a.goodAllocSize(b.length)), $(D expand) just adjusts $(D b) and returns $(D true). Otherwise, returns $(D false). $(D expand) does not attempt to use $(D Allocator.reallocate) even if defined. This is deliberate so allocators may use it internally within their own implementation of $(D expand). */ //bool expand(Allocator)(ref Allocator a, ref void[] b, size_t delta) //{ // if (!b.ptr) // { // b = a.allocate(delta); // return b.length == delta; // } // if (delta == 0) return true; // immutable length = b.length + delta; // if (length <= a.goodAllocSize(b.length)) // { // b = b.ptr[0 .. length]; // return true; // } // return false; //} /** The default $(D reallocate) function first attempts to use $(D expand). If $(D Allocator.expand) is not defined or returns $(D false), $(D reallocate) allocates a new block of memory of appropriate size and copies data from the old block to the new block. Finally, if $(D Allocator) defines $(D deallocate), $(D reallocate) uses it to free the old memory block. $(D reallocate) does not attempt to use $(D Allocator.reallocate) even if defined. This is deliberate so allocators may use it internally within their own implementation of $(D reallocate). */ bool reallocate(Allocator)(ref Allocator a, ref void[] b, size_t s) { if (b.length == s) return true; static if (hasMember!(Allocator, "expand")) { if (b.length <= s && a.expand(b, s - b.length)) return true; } auto newB = a.allocate(s); if (newB.length != s) return false; if (newB.length <= b.length) newB[] = b[0 .. newB.length]; else newB[0 .. b.length] = b[]; static if (hasMember!(Allocator, "deallocate")) a.deallocate(b); b = newB; return true; } /** The default $(D alignedReallocate) function first attempts to use $(D expand). If $(D Allocator.expand) is not defined or returns $(D false), $(D alignedReallocate) allocates a new block of memory of appropriate size and copies data from the old block to the new block. Finally, if $(D Allocator) defines $(D deallocate), $(D alignedReallocate) uses it to free the old memory block. $(D alignedReallocate) does not attempt to use $(D Allocator.reallocate) even if defined. This is deliberate so allocators may use it internally within their own implementation of $(D reallocate). */ bool alignedReallocate(Allocator)(ref Allocator alloc, ref void[] b, size_t s, uint a) { static if (hasMember!(Allocator, "expand")) { if (b.length <= s && b.ptr.alignedAt(a) && alloc.expand(b, s - b.length)) return true; } else { if (b.length == s) return true; } auto newB = alloc.alignedAllocate(s, a); if (newB.length <= b.length) newB[] = b[0 .. newB.length]; else newB[0 .. b.length] = b[]; static if (hasMember!(Allocator, "deallocate")) alloc.deallocate(b); b = newB; return true; } /** Forwards each of the methods in `funs` (if defined) to `member`. */ /*package*/ string forwardToMember(string member, string[] funs...) { string result = " import std.traits : hasMember, Parameters;\n"; foreach (fun; funs) { result ~= " static if (hasMember!(typeof("~member~"), `"~fun~"`)) auto ref "~fun~"(Parameters!(typeof("~member~"."~fun~")) args) { return "~member~"."~fun~"(args); }\n"; } return result; } package void testAllocator(alias make)() { import std.conv : text; import std.stdio : writeln, stderr; alias A = typeof(make()); scope(failure) stderr.writeln("testAllocator failed for ", A.stringof); auto a = make(); // Test alignment static assert(A.alignment.isPowerOf2); // Test goodAllocSize assert(a.goodAllocSize(1) >= A.alignment, text(a.goodAllocSize(1), " < ", A.alignment)); assert(a.goodAllocSize(11) >= 11.roundUpToMultipleOf(A.alignment)); assert(a.goodAllocSize(111) >= 111.roundUpToMultipleOf(A.alignment)); // Test allocate assert(a.allocate(0) is null); auto b1 = a.allocate(1); assert(b1.length == 1); auto b2 = a.allocate(2); assert(b2.length == 2); assert(b2.ptr + b2.length <= b1.ptr || b1.ptr + b1.length <= b2.ptr); // Test alignedAllocate static if (hasMember!(A, "alignedAllocate")) {{ auto b3 = a.alignedAllocate(1, 256); assert(b3.length <= 1); assert(b3.ptr.alignedAt(256)); assert(a.alignedReallocate(b3, 2, 512)); assert(b3.ptr.alignedAt(512)); static if (hasMember!(A, "alignedDeallocate")) { a.alignedDeallocate(b3); } }} else { static assert(!hasMember!(A, "alignedDeallocate")); // This seems to be a bug in the compiler: //static assert(!hasMember!(A, "alignedReallocate"), A.stringof); } static if (hasMember!(A, "allocateAll")) {{ auto aa = make(); if (aa.allocateAll().ptr) { // Can't get any more memory assert(!aa.allocate(1).ptr); } auto ab = make(); const b4 = ab.allocateAll(); assert(b4.length); // Can't get any more memory assert(!ab.allocate(1).ptr); }} static if (hasMember!(A, "expand")) {{ assert(a.expand(b1, 0)); auto len = b1.length; if (a.expand(b1, 102)) { assert(b1.length == len + 102, text(b1.length, " != ", len + 102)); } auto aa = make(); void[] b5 = null; assert(aa.expand(b5, 0)); assert(b5 is null); assert(aa.expand(b5, 1)); assert(b5.length == 1); }} void[] b6 = null; assert(a.reallocate(b6, 0)); assert(b6.length == 0); assert(a.reallocate(b6, 1)); assert(b6.length == 1, text(b6.length)); // Test owns static if (hasMember!(A, "owns")) {{ assert(a.owns(null) == Ternary.no); assert(a.owns(b1) == Ternary.yes); assert(a.owns(b2) == Ternary.yes); assert(a.owns(b6) == Ternary.yes); }} static if (hasMember!(A, "resolveInternalPointer")) {{ assert(a.resolveInternalPointer(null) is null); auto p = a.resolveInternalPointer(b1.ptr); assert(p.ptr is b1.ptr && p.length >= b1.length); p = a.resolveInternalPointer(b1.ptr + b1.length / 2); assert(p.ptr is b1.ptr && p.length >= b1.length); p = a.resolveInternalPointer(b2.ptr); assert(p.ptr is b2.ptr && p.length >= b2.length); p = a.resolveInternalPointer(b2.ptr + b2.length / 2); assert(p.ptr is b2.ptr && p.length >= b2.length); p = a.resolveInternalPointer(b6.ptr); assert(p.ptr is b6.ptr && p.length >= b6.length); p = a.resolveInternalPointer(b6.ptr + b6.length / 2); assert(p.ptr is b6.ptr && p.length >= b6.length); static int[10] b7 = [ 1, 2, 3 ]; assert(a.resolveInternalPointer(b7.ptr) is null); assert(a.resolveInternalPointer(b7.ptr + b7.length / 2) is null); assert(a.resolveInternalPointer(b7.ptr + b7.length) is null); int[3] b8 = [ 1, 2, 3 ]; assert(a.resolveInternalPointer(b8.ptr).ptr is null); assert(a.resolveInternalPointer(b8.ptr + b8.length / 2) is null); assert(a.resolveInternalPointer(b8.ptr + b8.length) is null); }} } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/package.d0000664000175000017500000016001112776215007024122 0ustar kaikai// Written in the D programming language. /** High-level interface for allocators. Implements bundled allocation/creation and destruction/deallocation of data including `struct`s and `class`es, and also array primitives related to allocation. This module is the entry point for both making use of allocators and for their documentation. Synopsis: --- // Allocate an int, initialize it with 42 int* p = theAllocator.make!int(42); assert(*p == 42); // Destroy and deallocate it theAllocator.dispose(p); // Allocate using the global process allocator p = processAllocator.make!int(100); assert(*p == 100); // Destroy and deallocate processAllocator.dispose(p); // Create an array of 50 doubles initialized to -1.0 double[] arr = theAllocator.makeArray!double(50, -1.0); // Append two zeros to it theAllocator.expandArray(arr, 2, 0.0); // On second thought, take that back theAllocator.shrinkArray(arr, 2); // Destroy and deallocate theAllocator.dispose(arr); --- $(H2 Layered Structure) D's allocators have a layered structure in both implementation and documentation: $(OL $(LI A high-level, dynamically-typed layer (described further down in this module). It consists of an interface called $(LREF IAllocator), which concrete allocators need to implement. The interface primitives themselves are oblivious to the type of the objects being allocated; they only deal in `void[]`, by necessity of the interface being dynamic (as opposed to type-parameterized). Each thread has a current allocator it uses by default, which is a thread-local variable $(LREF theAllocator) of type $(LREF IAllocator). The process has a global _allocator called $(LREF processAllocator), also of type $(LREF IAllocator). When a new thread is created, $(LREF processAllocator) is copied into $(LREF theAllocator). An application can change the objects to which these references point. By default, at application startup, $(LREF processAllocator) refers to an object that uses D's garbage collected heap. This layer also include high-level functions such as $(LREF make) and $(LREF dispose) that comfortably allocate/create and respectively destroy/deallocate objects. This layer is all needed for most casual uses of allocation primitives.) $(LI A mid-level, statically-typed layer for assembling several allocators into one. It uses properties of the type of the objects being created to route allocation requests to possibly specialized allocators. This layer is relatively thin and implemented and documented in the $(XREF2 std,experimental,_allocator,typed) module. It allows an interested user to e.g. use different allocators for arrays versus fixed-sized objects, to the end of better overall performance.) $(LI A low-level collection of highly generic $(I heap building blocks)$(MDASH) Lego-like pieces that can be used to assemble application-specific allocators. The real allocation smarts are occurring at this level. This layer is of interest to advanced applications that want to configure their own allocators. A good illustration of typical uses of these building blocks is module $(XREF2 std,experimental,_allocator,showcase) which defines a collection of frequently- used preassembled allocator objects. The implementation and documentation entry point is $(XREF2 std,experimental,_allocator,building_blocks). By design, the primitives of the static interface have the same signatures as the $(LREF IAllocator) primitives but are for the most part optional and driven by static introspection. The parameterized class $(LREF CAllocatorImpl) offers an immediate and useful means to package a static low-level _allocator into an implementation of $(LREF IAllocator).) $(LI Core _allocator objects that interface with D's garbage collected heap ($(XREF2 std,experimental,_allocator,gc_allocator)), the C `malloc` family ($(XREF2 std,experimental,_allocator,mallocator)), and the OS ($(XREF2 std,experimental,_allocator,mmap_allocator)). Most custom allocators would ultimately obtain memory from one of these core allocators.) ) $(H2 Idiomatic Use of $(D std.experimental._allocator)) As of this time, $(D std.experimental._allocator) is not integrated with D's built-in operators that allocate memory, such as `new`, array literals, or array concatenation operators. That means $(D std.experimental._allocator) is opt-in$(MDASH)applications need to make explicit use of it. For casual creation and disposal of dynamically-allocated objects, use $(LREF make), $(LREF dispose), and the array-specific functions $(LREF makeArray), $(LREF expandArray), and $(LREF shrinkArray). These use by default D's garbage collected heap, but open the application to better configuration options. These primitives work either with `theAllocator` but also with any allocator obtained by combining heap building blocks. For example: ---- void fun(size_t n) { // Use the current allocator int[] a1 = theAllocator.makeArray!int(n); scope(exit) theAllocator.dispose(a1); ... } ---- To experiment with alternative allocators, set $(LREF theAllocator) for the current thread. For example, consider an application that allocates many 8-byte objects. These are not well supported by the default _allocator, so a $(A $(MY_JOIN_LINE std,experimental,_allocator,building_blocks,free_list).html, free list _allocator) would be recommended. To install one in `main`, the application would use: ---- void main() { import std.experimental.allocator.building_blocks.free_list : FreeList; theAllocator = allocatorObject(FreeList!8()); ... } ---- $(H3 Saving the `IAllocator` Reference For Later Use) As with any global resource, setting `theAllocator` and `processAllocator` should not be done often and casually. In particular, allocating memory with one allocator and deallocating with another causes undefined behavior. Typically, these variables are set during application initialization phase and last through the application. To avoid this, long-lived objects that need to perform allocations, reallocations, and deallocations relatively often may want to store a reference to the _allocator object they use throughout their lifetime. Then, instead of using `theAllocator` for internal allocation-related tasks, they'd use the internally held reference. For example, consider a user-defined hash table: ---- struct HashTable { private IAllocator _allocator; this(size_t buckets, IAllocator allocator = theAllocator) { this._allocator = allocator; ... } // Getter and setter IAllocator allocator() { return _allocator; } void allocator(IAllocator a) { assert(empty); _allocator = a; } } ---- Following initialization, the `HashTable` object would consistently use its $(D _allocator) object for acquiring memory. Furthermore, setting $(D HashTable._allocator) to point to a different _allocator should be legal but only if the object is empty; otherwise, the object wouldn't be able to deallocate its existing state. $(H3 Using Allocators without `IAllocator`) Allocators assembled from the heap building blocks don't need to go through `IAllocator` to be usable. They have the same primitives as `IAllocator` and they work with $(LREF make), $(LREF makeArray), $(LREF dispose) etc. So it suffice to create allocator objects wherever fit and use them appropriately: ---- void fun(size_t n) { // Use a stack-installed allocator for up to 64KB StackFront!65536 myAllocator; int[] a2 = myAllocator.makeArray!int(n); scope(exit) myAllocator.dispose(a2); ... } ---- In this case, `myAllocator` does not obey the `IAllocator` interface, but implements its primitives so it can work with `makeArray` by means of duck typing. One important thing to note about this setup is that statically-typed assembled allocators are almost always faster than allocators that go through `IAllocator`. An important rule of thumb is: "assemble allocator first, adapt to `IAllocator` after". A good allocator implements intricate logic by means of template assembly, and gets wrapped with `IAllocator` (usually by means of $(LREF allocatorObject)) only once, at client level. Macros: MYREF = $(LINK2 std_experimental_allocator_$2.html, $1)  MYREF2 = $(LINK2 std_experimental_allocator_$2.html#$1, $1)  TDC = $(D $1)$+ TDC2 = $(D $(MYREF $1,$+)) TDC3 = $(D $(MYREF2 $1,$+)) RES = $(I result) POST = $(BR)$(SMALL $(I Post:) $(BLUE $(D $0))) MY_JOIN_LINE = $1$(MY_JOIN_LINE_TAIL $+) MY_JOIN_LINE_TAIL = _$1$(MY_JOIN_LINE_TAIL $+) JOIN_DOT = $1$(JOIN_DOT_TAIL $+) JOIN_DOT_TAIL = .$1$(JOIN_DOT_TAIL $+) XREF2 = $(A $(MY_JOIN_LINE $1,$+).html,$(D $(JOIN_DOT $1,$+))) Copyright: Andrei Alexandrescu 2013-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/experimental/_allocator) */ module std.experimental.allocator; public import std.experimental.allocator.common, std.experimental.allocator.typed; // Example in the synopsis above unittest { import std.experimental.allocator.building_blocks.free_list : FreeList; import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.building_blocks.segregator : Segregator; import std.experimental.allocator.building_blocks.bucketizer : Bucketizer; import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock; alias FList = FreeList!(GCAllocator, 0, unbounded); alias A = Segregator!( 8, FreeList!(GCAllocator, 0, 8), 128, Bucketizer!(FList, 1, 128, 16), 256, Bucketizer!(FList, 129, 256, 32), 512, Bucketizer!(FList, 257, 512, 64), 1024, Bucketizer!(FList, 513, 1024, 128), 2048, Bucketizer!(FList, 1025, 2048, 256), 3584, Bucketizer!(FList, 2049, 3584, 512), 4072 * 1024, AllocatorList!( (n) => BitmappedBlock!(4096)(GCAllocator.instance.allocate( max(n, 4072 * 1024)))), GCAllocator ); A tuMalloc; auto b = tuMalloc.allocate(500); assert(b.length == 500); auto c = tuMalloc.allocate(113); assert(c.length == 113); assert(tuMalloc.expand(c, 14)); tuMalloc.deallocate(b); tuMalloc.deallocate(c); } import std.algorithm, std.conv, std.exception, std.range, std.traits, std.typecons; version(unittest) import std.random, std.stdio; /** Dynamic allocator interface. Code that defines allocators ultimately implements this interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations. Composition of allocators is not recommended at this level due to inflexibility of dynamic interfaces and inefficiencies caused by cascaded multiple calls. Instead, compose allocators using the static interface defined in $(A std_experimental_allocator_building_blocks.html, `std.experimental.allocator.building_blocks`), then adapt the composed allocator to `IAllocator` (possibly by using $(LREF CAllocatorImpl) below). Methods returning $(D Ternary) return $(D Ternary.yes) upon success, $(D Ternary.no) upon failure, and $(D Ternary.unknown) if the primitive is not implemented by the allocator instance. */ interface IAllocator { /** Returns the alignment offered. */ @property uint alignment(); /** Returns the good allocation size that guarantees zero internal fragmentation. */ size_t goodAllocSize(size_t s); /** Allocates `n` bytes of memory. */ void[] allocate(size_t, TypeInfo ti = null); /** Allocates `n` bytes of memory with specified alignment `a`. Implementations that do not support this primitive should always return `null`. */ void[] alignedAllocate(size_t n, uint a); /** Allocates and returns all memory available to this allocator. Implementations that do not support this primitive should always return `null`. */ void[] allocateAll(); /** Expands a memory block in place and returns `true` if successful. Implementations that don't support this primitive should always return `false`. */ bool expand(ref void[], size_t); /// Reallocates a memory block. bool reallocate(ref void[], size_t); /// Reallocates a memory block with specified alignment. bool alignedReallocate(ref void[] b, size_t size, uint alignment); /** Returns $(D Ternary.yes) if the allocator owns $(D b), $(D Ternary.no) if the allocator doesn't own $(D b), and $(D Ternary.unknown) if ownership cannot be determined. Implementations that don't support this primitive should always return `Ternary.unknown`. */ Ternary owns(void[] b); /** Resolves an internal pointer to the full block allocated. Implementations that don't support this primitive should always return `Ternary.unknown`. */ Ternary resolveInternalPointer(void* p, ref void[] result); /** Deallocates a memory block. Implementations that don't support this primitive should always return `false`. A simple way to check that an allocator supports deallocation is to call $(D deallocate(null)). */ bool deallocate(void[] b); /** Deallocates all memory. Implementations that don't support this primitive should always return `false`. */ bool deallocateAll(); /** Returns $(D Ternary.yes) if no memory is currently allocated from this allocator, $(D Ternary.no) if some allocations are currently active, or $(D Ternary.unknown) if not supported. */ Ternary empty(); } __gshared IAllocator _processAllocator; IAllocator _threadAllocator; shared static this() { assert(!_processAllocator); import std.experimental.allocator.gc_allocator : GCAllocator; _processAllocator = allocatorObject(GCAllocator.instance); } static this() { assert(!_threadAllocator); _threadAllocator = _processAllocator; } /** Gets/sets the allocator for the current thread. This is the default allocator that should be used for allocating thread-local memory. For allocating memory to be shared across threads, use $(D processAllocator) (below). By default, $(D theAllocator) ultimately fetches memory from $(D processAllocator), which in turn uses the garbage collected heap. */ @property IAllocator theAllocator() { return _threadAllocator; } /// Ditto @property void theAllocator(IAllocator a) { assert(a); _threadAllocator = a; } /// unittest { // Install a new allocator that is faster for 128-byte allocations. import std.experimental.allocator.building_blocks.free_list : FreeList; import std.experimental.allocator.gc_allocator : GCAllocator; auto oldAllocator = theAllocator; scope(exit) theAllocator = oldAllocator; theAllocator = allocatorObject(FreeList!(GCAllocator, 128)()); // Use the now changed allocator to allocate an array const ubyte[] arr = theAllocator.makeArray!ubyte(128); assert(arr.ptr); //... } /** Gets/sets the allocator for the current process. This allocator must be used for allocating memory shared across threads. Objects created using this allocator can be cast to $(D shared). */ @property IAllocator processAllocator() { return _processAllocator; } /// Ditto @property void processAllocator(IAllocator a) { assert(a); _processAllocator = a; } unittest { assert(processAllocator); assert(processAllocator is theAllocator); } /** Dynamically allocates (using $(D alloc)) and then creates in the memory allocated an object of type $(D T), using $(D args) (if any) for its initialization. Initialization occurs in the memory allocated and is otherwise semantically the same as $(D T(args)). (Note that using $(D alloc.make!(T[])) creates a pointer to an (empty) array of $(D T)s, not an array. To use an allocator to allocate and initialize an array, use $(D alloc.makeArray!T) described below.) Params: T = Type of the object being created. alloc = The allocator used for getting the needed memory. It may be an object implementing the static interface for allocators, or an $(D IAllocator) reference. args = Optional arguments used for initializing the created object. If not present, the object is default constructed. Returns: If $(D T) is a class type, returns a reference to the created $(D T) object. Otherwise, returns a $(D T*) pointing to the created object. In all cases, returns $(D null) if allocation failed. Throws: If $(D T)'s constructor throws, deallocates the allocated memory and propagates the exception. */ auto make(T, Allocator, A...)(auto ref Allocator alloc, auto ref A args) { import std.algorithm : max; import std.conv : emplace; auto m = alloc.allocate(max(stateSize!T, 1)); if (!m.ptr) return null; scope(failure) alloc.deallocate(m); static if (is(T == class)) return emplace!T(m, args); else return emplace(cast(T*) m.ptr, args); } /// unittest { // Dynamically allocate one integer const int* p1 = theAllocator.make!int; // It's implicitly initialized with its .init value assert(*p1 == 0); // Dynamically allocate one double, initialize to 42.5 const double* p2 = theAllocator.make!double(42.5); assert(*p2 == 42.5); // Dynamically allocate a struct static struct Point { int x, y, z; } // Use the generated constructor taking field values in order const Point* p = theAllocator.make!Point(1, 2); assert(p.x == 1 && p.y == 2 && p.z == 0); // Dynamically allocate a class object static class Customer { uint id = uint.max; this() {} this(uint id) { this.id = id; } // ... } Customer cust = theAllocator.make!Customer; assert(cust.id == uint.max); // default initialized cust = theAllocator.make!Customer(42); assert(cust.id == 42); } unittest // bugzilla 15639 & 15772 { abstract class Foo {} class Bar: Foo {} static assert(!is(typeof(theAllocator.make!Foo))); static assert( is(typeof(theAllocator.make!Bar))); } unittest { void test(Allocator)(auto ref Allocator alloc) { const int* a = alloc.make!int(10); assert(*a == 10); struct A { int x; string y; double z; } A* b = alloc.make!A(42); assert(b.x == 42); assert(b.y is null); import std.math : isNaN; assert(b.z.isNaN); b = alloc.make!A(43, "44", 45); assert(b.x == 43); assert(b.y == "44"); assert(b.z == 45); static class B { int x; string y; double z; this(int _x, string _y = null, double _z = double.init) { x = _x; y = _y; z = _z; } } B c = alloc.make!B(42); assert(c.x == 42); assert(c.y is null); assert(c.z.isNaN); c = alloc.make!B(43, "44", 45); assert(c.x == 43); assert(c.y == "44"); assert(c.z == 45); const parray = alloc.make!(int[]); assert((*parray).empty); } import std.experimental.allocator.gc_allocator : GCAllocator; test(GCAllocator.instance); test(theAllocator); } private void fillWithMemcpy(T)(void[] array, auto ref T filler) nothrow { import core.stdc.string : memcpy; if (!array.length) return; memcpy(array.ptr, &filler, T.sizeof); // Fill the array from the initialized portion of itself exponentially. for (size_t offset = T.sizeof; offset < array.length; ) { size_t extent = min(offset, array.length - offset); memcpy(array.ptr + offset, array.ptr, extent); offset += extent; } } unittest { int[] a; fillWithMemcpy(a, 42); assert(a.length == 0); a = [ 1, 2, 3, 4, 5 ]; fillWithMemcpy(a, 42); assert(a == [ 42, 42, 42, 42, 42]); } private T[] uninitializedFillDefault(T)(T[] array) nothrow { T t = T.init; fillWithMemcpy(array, t); return array; } pure nothrow @nogc unittest { static struct S { int x = 42; @disable this(this); } int[5] expected = [42, 42, 42, 42, 42]; S[5] arr = void; uninitializedFillDefault(arr); assert ((cast(int*)arr.ptr)[0 .. arr.length] == expected); } unittest { int[] a = [1, 2, 4]; uninitializedFillDefault(a); assert(a == [0, 0, 0]); } /** Create an array of $(D T) with $(D length) elements using $(D alloc). The array is either default-initialized, filled with copies of $(D init), or initialized with values fetched from `range`. Params: T = element type of the array being created alloc = the allocator used for getting memory length = length of the newly created array init = element used for filling the array range = range used for initializing the array elements Returns: The newly-created array, or $(D null) if either $(D length) was $(D 0) or allocation failed. Throws: The first two overloads throw only if `alloc`'s primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws. */ T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length) { if (!length) return null; auto m = alloc.allocate(T.sizeof * length); if (!m.ptr) return null; return uninitializedFillDefault(cast(T[]) m); } unittest { void test1(A)(auto ref A alloc) { int[] a = alloc.makeArray!int(0); assert(a.length == 0 && a.ptr is null); a = alloc.makeArray!int(5); assert(a.length == 5); assert(a == [ 0, 0, 0, 0, 0]); } void test2(A)(auto ref A alloc) { static struct S { int x = 42; @disable this(this); } S[] arr = alloc.makeArray!S(5); assert(arr.length == 5); assert((cast(int*)arr.ptr)[0 .. 5] == [ 42, 42, 42, 42, 42]); } import std.experimental.allocator.gc_allocator : GCAllocator; test1(GCAllocator.instance); test1(theAllocator); test2(GCAllocator.instance); test2(theAllocator); } /// Ditto T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length, auto ref T init) { if (!length) return null; auto m = alloc.allocate(T.sizeof * length); if (!m.ptr) return null; auto result = cast(T[]) m; import std.traits : hasElaborateCopyConstructor; static if (hasElaborateCopyConstructor!T) { scope(failure) alloc.deallocate(m); size_t i = 0; static if (hasElaborateDestructor!T) { scope (failure) { foreach (j; 0 .. i) { destroy(result[j]); } } } for (; i < length; ++i) { emplace!T(result.ptr + i, init); } } else { fillWithMemcpy(result, init); } return result; } /// unittest { int[] a = theAllocator.makeArray!int(2); assert(a == [0, 0]); a = theAllocator.makeArray!int(3, 42); assert(a == [42, 42, 42]); import std.range : only; a = theAllocator.makeArray!int(only(42, 43, 44)); assert(a == [42, 43, 44]); } unittest { void test(A)(auto ref A alloc) { long[] a = alloc.makeArray!long(0, 42); assert(a.length == 0 && a.ptr is null); a = alloc.makeArray!long(5, 42); assert(a.length == 5); assert(a == [ 42, 42, 42, 42, 42 ]); } import std.experimental.allocator.gc_allocator : GCAllocator; test(GCAllocator.instance); test(theAllocator); } /// Ditto T[] makeArray(T, Allocator, R)(auto ref Allocator alloc, R range) if (isInputRange!R) { static if (isForwardRange!R) { size_t length = walkLength(range.save); if (!length) return null; auto m = alloc.allocate(T.sizeof * length); if (!m.ptr) return null; auto result = cast(T[]) m; size_t i = 0; scope (failure) { foreach (j; 0 .. i) { destroy(result[j]); } alloc.deallocate(m); } for (; !range.empty; range.popFront, ++i) { import std.conv : emplace; emplace!T(result.ptr + i, range.front); } return result; } else { // Estimated size size_t estimated = 8; auto m = alloc.allocate(T.sizeof * estimated); if (!m.ptr) return null; auto result = cast(T[]) m; size_t initialized = 0; void bailout() { foreach (i; 0 .. initialized) { destroy(result[i]); } alloc.deallocate(m); } scope (failure) bailout; for (; !range.empty; range.popFront, ++initialized) { if (initialized == estimated) { // Need to reallocate if (!alloc.reallocate(m, T.sizeof * (estimated *= 2))) { bailout; return null; } result = cast(T[]) m; } import std.conv : emplace; emplace!T(result.ptr + initialized, range.front); } // Try to shrink memory, no harm if not possible if (initialized < estimated && alloc.reallocate(m, T.sizeof * initialized)) { result = cast(T[]) m; } return result[0 .. initialized]; } } unittest { void test(A)(auto ref A alloc) { long[] a = alloc.makeArray!long((int[]).init); assert(a.length == 0 && a.ptr is null); a = alloc.makeArray!long([5, 42]); assert(a.length == 2); assert(a == [ 5, 42]); } import std.experimental.allocator.gc_allocator : GCAllocator; test(GCAllocator.instance); test(theAllocator); } version(unittest) { private struct ForcedInputRange { int[]* array; bool empty() { return !array || (*array).empty; } ref int front() { return (*array)[0]; } void popFront() { *array = (*array)[1 .. $]; } } } unittest { import std.array : array; import std.range : iota; int[] arr = iota(10).array; void test(A)(auto ref A alloc) { ForcedInputRange r; long[] a = alloc.makeArray!long(r); assert(a.length == 0 && a.ptr is null); auto arr2 = arr; r.array = &arr2; a = alloc.makeArray!long(r); assert(a.length == 10); assert(a == iota(10).array); } import std.experimental.allocator.gc_allocator : GCAllocator; test(GCAllocator.instance); test(theAllocator); } /** Grows $(D array) by appending $(D delta) more elements. The needed memory is allocated using $(D alloc). The extra elements added are either default- initialized, filled with copies of $(D init), or initialized with values fetched from `range`. Params: T = element type of the array being created alloc = the allocator used for getting memory array = a reference to the array being grown delta = number of elements to add (upon success the new length of $(D array) is $(D array.length + delta)) init = element used for filling the array range = range used for initializing the array elements Returns: $(D true) upon success, $(D false) if memory could not be allocated. In the latter case $(D array) is left unaffected. Throws: The first two overloads throw only if `alloc`'s primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws. */ bool expandArray(T, Allocator)(auto ref Allocator alloc, ref T[] array, size_t delta) { if (!delta) return true; immutable oldLength = array.length; void[] buf = array; if (!alloc.reallocate(buf, buf.length + T.sizeof * delta)) return false; array = cast(T[]) buf; array[oldLength .. $].uninitializedFillDefault; return true; } unittest { void test(A)(auto ref A alloc) { auto arr = alloc.makeArray!int([1, 2, 3]); assert(alloc.expandArray(arr, 3)); assert(arr == [1, 2, 3, 0, 0, 0]); } import std.experimental.allocator.gc_allocator : GCAllocator; test(GCAllocator.instance); test(theAllocator); } /// Ditto bool expandArray(T, Allocator)(auto ref Allocator alloc, ref T[] array, size_t delta, auto ref T init) { if (!delta) return true; void[] buf = array; if (!alloc.reallocate(buf, buf.length + T.sizeof * delta)) return false; immutable oldLength = array.length; array = cast(T[]) buf; scope(failure) array[oldLength .. $].uninitializedFillDefault; import std.algorithm : uninitializedFill; array[oldLength .. $].uninitializedFill(init); return true; } unittest { void test(A)(auto ref A alloc) { auto arr = alloc.makeArray!int([1, 2, 3]); assert(alloc.expandArray(arr, 3, 1)); assert(arr == [1, 2, 3, 1, 1, 1]); } import std.experimental.allocator.gc_allocator : GCAllocator; test(GCAllocator.instance); test(theAllocator); } /// Ditto bool expandArray(T, Allocator, R)(auto ref Allocator alloc, ref T[] array, R range) if (isInputRange!R) { static if (isForwardRange!R) { immutable delta = walkLength(range.save); if (!delta) return true; immutable oldLength = array.length; // Reallocate support memory void[] buf = array; if (!alloc.reallocate(buf, buf.length + T.sizeof * delta)) { return false; } array = cast(T[]) buf; // At this point we're committed to the new length. auto toFill = array[oldLength .. $]; scope (failure) { // Fill the remainder with default-constructed data toFill.uninitializedFillDefault; } for (; !range.empty; range.popFront, toFill.popFront) { assert(!toFill.empty); import std.conv : emplace; emplace!T(&toFill.front, range.front); } assert(toFill.empty); } else { scope(failure) { // The last element didn't make it, fill with default array[$ - 1 .. $].uninitializedFillDefault; } void[] buf = array; for (; !range.empty; range.popFront) { if (!alloc.reallocate(buf, buf.length + T.sizeof)) { array = cast(T[]) buf; return false; } import std.conv : emplace; emplace!T(buf[$ - T.sizeof .. $], range.front); } array = cast(T[]) buf; } return true; } /// unittest { auto arr = theAllocator.makeArray!int([1, 2, 3]); assert(theAllocator.expandArray(arr, 2)); assert(arr == [1, 2, 3, 0, 0]); import std.range : only; assert(theAllocator.expandArray(arr, only(4, 5))); assert(arr == [1, 2, 3, 0, 0, 4, 5]); ForcedInputRange r; int[] b = [ 1, 2, 3, 4 ]; auto temp = b; r.array = &temp; assert(theAllocator.expandArray(arr, r)); assert(arr == [1, 2, 3, 0, 0, 4, 5, 1, 2, 3, 4]); } /** Shrinks an array by $(D delta) elements. If $(D array.length < delta), does nothing and returns `false`. Otherwise, destroys the last $(D array.length - delta) elements in the array and then reallocates the array's buffer. If reallocation fails, fills the array with default-initialized data. Params: T = element type of the array being created alloc = the allocator used for getting memory array = a reference to the array being shrunk delta = number of elements to remove (upon success the new length of $(D array) is $(D array.length - delta)) Returns: `true` upon success, `false` if memory could not be reallocated. In the latter case, the slice $(D array[$ - delta .. $]) is left with default-initialized elements. Throws: The first two overloads throw only if `alloc`'s primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws. */ bool shrinkArray(T, Allocator)(auto ref Allocator alloc, ref T[] array, size_t delta) { if (delta > array.length) return false; // Destroy elements. If a destructor throws, fill the already destroyed // stuff with the default initializer. { size_t destroyed; scope(failure) { array[$ - delta .. $][0 .. destroyed].uninitializedFillDefault; } foreach (ref e; array[$ - delta .. $]) { e.destroy; ++destroyed; } } if (delta == array.length) { alloc.deallocate(array); array = null; return true; } void[] buf = array; if (!alloc.reallocate(buf, buf.length - T.sizeof * delta)) { // urgh, at least fill back with default array[$ - delta .. $].uninitializedFillDefault; return false; } array = cast(T[]) buf; return true; } /// unittest { int[] a = theAllocator.makeArray!int(100, 42); assert(a.length == 100); assert(theAllocator.shrinkArray(a, 98)); assert(a.length == 2); assert(a == [42, 42]); } unittest { void test(A)(auto ref A alloc) { long[] a = alloc.makeArray!long((int[]).init); assert(a.length == 0 && a.ptr is null); a = alloc.makeArray!long(100, 42); assert(alloc.shrinkArray(a, 98)); assert(a.length == 2); assert(a == [ 42, 42]); } import std.experimental.allocator.gc_allocator : GCAllocator; test(GCAllocator.instance); test(theAllocator); } /** Destroys and then deallocates (using $(D alloc)) the object pointed to by a pointer, the class object referred to by a $(D class) or $(D interface) reference, or an entire array. It is assumed the respective entities had been allocated with the same allocator. */ void dispose(A, T)(auto ref A alloc, T* p) { static if (hasElaborateDestructor!T) { destroy(*p); } alloc.deallocate((cast(void*)p)[0 .. T.sizeof]); } /// Ditto void dispose(A, T)(auto ref A alloc, T p) if (is(T == class) || is(T == interface)) { if (!p) return; static if (is(T == interface)) { version(Windows) { import core.sys.windows.unknwn; static assert(!is(T: IUnknown), "COM interfaces can't be destroyed in " ~ __PRETTY_FUNCTION__); } auto ob = cast(Object) p; } else alias ob = p; auto support = (cast(void*) ob)[0 .. typeid(ob).initializer.length]; destroy(p); alloc.deallocate(support); } /// Ditto void dispose(A, T)(auto ref A alloc, T[] array) { static if (hasElaborateDestructor!(typeof(array[0]))) { foreach (ref e; array) { destroy(e); } } alloc.deallocate(array); } unittest { static int x; static interface I { void method(); } static class A : I { int y; override void method() { x = 21; } ~this() { x = 42; } } static class B : A { } auto a = theAllocator.make!A; a.method(); assert(x == 21); theAllocator.dispose(a); assert(x == 42); B b = theAllocator.make!B; b.method(); assert(x == 21); theAllocator.dispose(b); assert(x == 42); I i = theAllocator.make!B; i.method(); assert(x == 21); theAllocator.dispose(i); assert(x == 42); int[] arr = theAllocator.makeArray!int(43); theAllocator.dispose(arr); } unittest //bugzilla 15721 { import std.experimental.allocator.mallocator: Mallocator; interface Foo {} class Bar: Foo {} Bar bar; Foo foo; bar = Mallocator.instance.make!Bar; foo = cast(Foo) bar; Mallocator.instance.dispose(foo); } /** Returns a dynamically-typed $(D CAllocator) built around a given statically- typed allocator $(D a) of type $(D A). Passing a pointer to the allocator creates a dynamic allocator around the allocator pointed to by the pointer, without attempting to copy or move it. Passing the allocator by value or reference behaves as follows. $(UL $(LI If $(D A) has no state, the resulting object is allocated in static shared storage.) $(LI If $(D A) has state and is copyable, the result will store a copy of it within. The result itself is allocated in its own statically-typed allocator.) $(LI If $(D A) has state and is not copyable, the result will move the passed-in argument into the result. The result itself is allocated in its own statically-typed allocator.) ) */ CAllocatorImpl!A allocatorObject(A)(auto ref A a) if (!isPointer!A) { import std.conv : emplace; static if (stateSize!A == 0) { enum s = stateSize!(CAllocatorImpl!A).divideRoundUp(ulong.sizeof); static __gshared ulong[s] state; static __gshared CAllocatorImpl!A result; if (!result) { // Don't care about a few races result = emplace!(CAllocatorImpl!A)(state[]); } assert(result); return result; } else static if (is(typeof({ A b = a; A c = b; }))) // copyable { auto state = a.allocate(stateSize!(CAllocatorImpl!A)); import std.traits : hasMember; static if (hasMember!(A, "deallocate")) { scope(failure) a.deallocate(state); } return cast(CAllocatorImpl!A) emplace!(CAllocatorImpl!A)(state); } else // the allocator object is not copyable { // This is sensitive... create on the stack and then move enum s = stateSize!(CAllocatorImpl!A).divideRoundUp(ulong.sizeof); ulong[s] state; import std.algorithm : move; emplace!(CAllocatorImpl!A)(state[], move(a)); auto dynState = a.allocate(stateSize!(CAllocatorImpl!A)); // Bitblast the object in its final destination dynState[] = state[]; return cast(CAllocatorImpl!A) dynState.ptr; } } /// Ditto CAllocatorImpl!(A, Yes.indirect) allocatorObject(A)(A* pa) { assert(pa); import std.conv : emplace; auto state = pa.allocate(stateSize!(CAllocatorImpl!(A, Yes.indirect))); import std.traits : hasMember; static if (hasMember!(A, "deallocate")) { scope(failure) pa.deallocate(state); } return emplace!(CAllocatorImpl!(A, Yes.indirect)) (state, pa); } /// unittest { import std.experimental.allocator.mallocator : Mallocator; IAllocator a = allocatorObject(Mallocator.instance); auto b = a.allocate(100); assert(b.length == 100); assert(a.deallocate(b)); // The in-situ region must be used by pointer import std.experimental.allocator.building_blocks.region : InSituRegion; auto r = InSituRegion!1024(); a = allocatorObject(&r); b = a.allocate(200); assert(b.length == 200); // In-situ regions can deallocate the last allocation assert(a.deallocate(b)); } /** Implementation of $(D IAllocator) using $(D Allocator). This adapts a statically-built allocator type to $(D IAllocator) that is directly usable by non-templated code. Usually $(D CAllocatorImpl) is used indirectly by calling $(LREF theAllocator). */ class CAllocatorImpl(Allocator, Flag!"indirect" indirect = No.indirect) : IAllocator { import std.traits : hasMember; /** The implementation is available as a public member. */ static if (indirect) { private Allocator* pimpl; ref Allocator impl() { return *pimpl; } this(Allocator* pa) { pimpl = pa; } } else { static if (stateSize!Allocator) Allocator impl; else alias impl = Allocator.instance; } /// Returns $(D impl.alignment). override @property uint alignment() { return impl.alignment; } /** Returns $(D impl.goodAllocSize(s)). */ override size_t goodAllocSize(size_t s) { return impl.goodAllocSize(s); } /** Returns $(D impl.allocate(s)). */ override void[] allocate(size_t s, TypeInfo ti = null) { return impl.allocate(s); } /** If $(D impl.alignedAllocate) exists, calls it and returns the result. Otherwise, always returns `null`. */ override void[] alignedAllocate(size_t s, uint a) { static if (hasMember!(Allocator, "alignedAllocate")) return impl.alignedAllocate(s, a); else return null; } /** If `Allocator` implements `owns`, forwards to it. Otherwise, returns `Ternary.unknown`. */ override Ternary owns(void[] b) { static if (hasMember!(Allocator, "owns")) return impl.owns(b); else return Ternary.unknown; } /// Returns $(D impl.expand(b, s)) if defined, $(D false) otherwise. override bool expand(ref void[] b, size_t s) { static if (hasMember!(Allocator, "expand")) return impl.expand(b, s); else return false; } /// Returns $(D impl.reallocate(b, s)). override bool reallocate(ref void[] b, size_t s) { return impl.reallocate(b, s); } /// Forwards to $(D impl.alignedReallocate). bool alignedReallocate(ref void[] b, size_t s, uint a) { static if (!hasMember!(Allocator, "alignedAllocate")) { return false; } else { return impl.alignedReallocate(b, s, a); } } // Undocumented for now Ternary resolveInternalPointer(void* p, ref void[] result) { static if (hasMember!(Allocator, "resolveInternalPointer")) { result = impl.resolveInternalPointer(p); return Ternary(result.ptr !is null); } else { return Ternary.unknown; } } /** If $(D impl.deallocate) is not defined, returns $(D Ternary.unknown). If $(D impl.deallocate) returns $(D void) (the common case), calls it and returns $(D Ternary.yes). If $(D impl.deallocate) returns $(D bool), calls it and returns $(D Ternary.yes) for $(D true), $(D Ternary.no) for $(D false). */ override bool deallocate(void[] b) { static if (hasMember!(Allocator, "deallocate")) { return impl.deallocate(b); } else { return false; } } /** Calls $(D impl.deallocateAll()) and returns $(D Ternary.yes) if defined, otherwise returns $(D Ternary.unknown). */ override bool deallocateAll() { static if (hasMember!(Allocator, "deallocateAll")) { return impl.deallocateAll(); } else { return false; } } /** Forwards to $(D impl.empty()) if defined, otherwise returns $(D Ternary.unknown). */ override Ternary empty() { static if (hasMember!(Allocator, "empty")) { return Ternary(impl.empty); } else { return Ternary.unknown; } } /** Returns $(D impl.allocateAll()) if present, $(D null) otherwise. */ override void[] allocateAll() { static if (hasMember!(Allocator, "allocateAll")) { return impl.allocateAll(); } else { return null; } } } // Example in intro above unittest { // Allocate an int, initialize it with 42 int* p = theAllocator.make!int(42); assert(*p == 42); // Destroy and deallocate it theAllocator.dispose(p); // Allocate using the global process allocator p = processAllocator.make!int(100); assert(*p == 100); // Destroy and deallocate processAllocator.dispose(p); // Create an array of 50 doubles initialized to -1.0 double[] arr = theAllocator.makeArray!double(50, -1.0); // Append two zeros to it theAllocator.expandArray(arr, 2, 0.0); // On second thought, take that back theAllocator.shrinkArray(arr, 2); // Destroy and deallocate theAllocator.dispose(arr); } __EOF__ /** Stores an allocator object in thread-local storage (i.e. non-$(D shared) D global). $(D ThreadLocal!A) is a subtype of $(D A) so it appears to implement $(D A)'s allocator primitives. $(D A) must hold state, otherwise $(D ThreadLocal!A) refuses instantiation. This means e.g. $(D ThreadLocal!Mallocator) does not work because $(D Mallocator)'s state is not stored as members of $(D Mallocator), but instead is hidden in the C library implementation. */ struct ThreadLocal(A) { static assert(stateSize!A, typeof(A).stringof ~ " does not have state so it cannot be used with ThreadLocal"); /** The allocator instance. */ static A instance; /** `ThreadLocal!A` is a subtype of `A` so it appears to implement `A`'s allocator primitives. */ alias instance this; /** `ThreadLocal` disables all constructors. The intended usage is `ThreadLocal!A.instance`. */ @disable this(); /// Ditto @disable this(this); } /// unittest { static assert(!is(ThreadLocal!Mallocator)); static assert(!is(ThreadLocal!GCAllocator)); alias ThreadLocal!(FreeList!(GCAllocator, 0, 8)) Allocator; auto b = Allocator.instance.allocate(5); static assert(hasMember!(Allocator, "allocate")); } /* (Not public.) A binary search tree that uses no allocation of its own. Instead, it relies on user code to allocate nodes externally. Then $(D EmbeddedTree)'s primitives wire the nodes appropriately. Warning: currently $(D EmbeddedTree) is not using rebalancing, so it may degenerate. A red-black tree implementation storing the color with one of the pointers is planned for the future. */ private struct EmbeddedTree(T, alias less) { static struct Node { T payload; Node* left, right; } private Node* root; private Node* insert(Node* n, ref Node* backref) { backref = n; n.left = n.right = null; return n; } Node* find(Node* data) { for (auto n = root; n; ) { if (less(data, n)) { n = n.left; } else if (less(n, data)) { n = n.right; } else { return n; } } return null; } Node* insert(Node* data) { if (!root) { root = data; data.left = data.right = null; return root; } auto n = root; for (;;) { if (less(data, n)) { if (!n.left) { // Found insertion point return insert(data, n.left); } n = n.left; } else if (less(n, data)) { if (!n.right) { // Found insertion point return insert(data, n.right); } n = n.right; } else { // Found return n; } if (!n) return null; } } Node* remove(Node* data) { auto n = root; Node* parent = null; for (;;) { if (!n) return null; if (less(data, n)) { parent = n; n = n.left; } else if (less(n, data)) { parent = n; n = n.right; } else { // Found remove(n, parent); return n; } } } private void remove(Node* n, Node* parent) { assert(n); assert(!parent || parent.left == n || parent.right == n); Node** referrer = parent ? (parent.left == n ? &parent.left : &parent.right) : &root; if (!n.left) { *referrer = n.right; } else if (!n.right) { *referrer = n.left; } else { // Find the leftmost child in the right subtree auto leftmost = n.right; Node** leftmostReferrer = &n.right; while (leftmost.left) { leftmostReferrer = &leftmost.left; leftmost = leftmost.left; } // Unlink leftmost from there *leftmostReferrer = leftmost.right; // Link leftmost in lieu of n leftmost.left = n.left; leftmost.right = n.right; *referrer = leftmost; } } Ternary empty() const { return Ternary(!root); } void dump() { writeln(typeid(this), " @ ", cast(void*) &this); dump(root, 3); } void dump(Node* r, uint indent) { write(repeat(' ', indent).array); if (!r) { writeln("(null)"); return; } writeln(r.payload, " @ ", cast(void*) r); dump(r.left, indent + 3); dump(r.right, indent + 3); } void assertSane() { static bool isBST(Node* r, Node* lb, Node* ub) { if (!r) return true; if (lb && !less(lb, r)) return false; if (ub && !less(r, ub)) return false; return isBST(r.left, lb, r) && isBST(r.right, r, ub); } if (isBST(root, null, null)) return; dump; assert(0); } } unittest { alias a = GCAllocator.instance; alias Tree = EmbeddedTree!(int, (a, b) => a.payload < b.payload); Tree t; assert(t.empty); int[] vals = [ 6, 3, 9, 1, 0, 2, 8, 11 ]; foreach (v; vals) { auto n = new Tree.Node(v, null, null); assert(t.insert(n)); assert(n); t.assertSane; } assert(!t.empty); foreach (v; vals) { Tree.Node n = { v }; assert(t.remove(&n)); t.assertSane; } assert(t.empty); } /* $(D InternalPointersTree) adds a primitive on top of another allocator: calling $(D resolveInternalPointer(p)) returns the block within which the internal pointer $(D p) lies. Pointers right after the end of allocated blocks are also considered internal. The implementation stores three additional words with each allocation (one for the block size and two for search management). */ private struct InternalPointersTree(Allocator) { alias Tree = EmbeddedTree!(size_t, (a, b) => cast(void*) a + a.payload < cast(void*) b); alias Parent = AffixAllocator!(Allocator, Tree.Node); // Own state private Tree blockMap; alias alignment = Parent.alignment; /** The implementation is available as a public member. */ static if (stateSize!Parent) Parent parent; else alias parent = Parent.instance; /// Allocator API. void[] allocate(size_t bytes) { auto r = parent.allocate(bytes); if (!r.ptr) return r; Tree.Node* n = &parent.prefix(r); n.payload = bytes; blockMap.insert(n) || assert(0); return r; } /// Ditto bool deallocate(void[] b) { if (!b.ptr) return; Tree.Node* n = &parent.prefix(b); blockMap.remove(n) || assert(false); parent.deallocate(b); return true; } /// Ditto static if (hasMember!(Allocator, "reallocate")) bool reallocate(ref void[] b, size_t s) { auto n = &parent.prefix(b); assert(n.payload == b.length); blockMap.remove(n) || assert(0); if (!parent.reallocate(b, s)) { // Failed, must reinsert the same node in the tree assert(n.payload == b.length); blockMap.insert(n) || assert(0); return false; } // Insert the new node n = &parent.prefix(b); n.payload = s; blockMap.insert(n) || assert(0); return true; } /// Ditto Ternary owns(void[] b) { return Ternary(resolveInternalPointer(b.ptr) !is null); } /// Ditto Ternary empty() { return Ternary(blockMap.empty); } /** Returns the block inside which $(D p) resides, or $(D null) if the pointer does not belong. */ void[] resolveInternalPointer(void* p) { // Must define a custom find Tree.Node* find() { for (auto n = blockMap.root; n; ) { if (p < n) { n = n.left; } else if (p > (cast(void*) (n + 1)) + n.payload) { n = n.right; } else { return n; } } return null; } auto n = find(); if (!n) return null; return (cast(void*) (n + 1))[0 .. n.payload]; } } unittest { InternalPointersTree!(Mallocator) a; int[] vals = [ 6, 3, 9, 1, 2, 8, 11 ]; void[][] allox; foreach (v; vals) { allox ~= a.allocate(v); } a.blockMap.assertSane; foreach (b; allox) { auto p = a.resolveInternalPointer(b.ptr); assert(p.ptr is b.ptr && p.length >= b.length); p = a.resolveInternalPointer(b.ptr + b.length); assert(p.ptr is b.ptr && p.length >= b.length); p = a.resolveInternalPointer(b.ptr + b.length / 2); assert(p.ptr is b.ptr && p.length >= b.length); auto bogus = new void[b.length]; assert(a.resolveInternalPointer(bogus.ptr) is null); } foreach (b; allox.randomCover) { a.deallocate(b); } assert(a.empty); } //version (std_allocator_benchmark) unittest { static void testSpeed(A)() { static if (stateSize!A) A a; else alias a = A.instance; void[][128] bufs; import std.random; foreach (i; 0 .. 100_000) { auto j = uniform(0, bufs.length); switch (uniform(0, 2)) { case 0: a.deallocate(bufs[j]); bufs[j] = a.allocate(uniform(0, 4096)); break; case 1: a.deallocate(bufs[j]); bufs[j] = null; break; default: assert(0); } } } alias FList = FreeList!(GCAllocator, 0, unbounded); alias A = Segregator!( 8, FreeList!(GCAllocator, 0, 8), 128, Bucketizer!(FList, 1, 128, 16), 256, Bucketizer!(FList, 129, 256, 32), 512, Bucketizer!(FList, 257, 512, 64), 1024, Bucketizer!(FList, 513, 1024, 128), 2048, Bucketizer!(FList, 1025, 2048, 256), 3584, Bucketizer!(FList, 2049, 3584, 512), 4072 * 1024, AllocatorList!( (size_t n) => BitmappedBlock!(4096)(GCAllocator.instance.allocate( max(n, 4072 * 1024)))), GCAllocator ); import std.datetime, std.experimental.allocator.null_allocator; if (false) writeln(benchmark!( testSpeed!NullAllocator, testSpeed!Mallocator, testSpeed!GCAllocator, testSpeed!(ThreadLocal!A), testSpeed!(A), )(20)[].map!(t => t.to!("seconds", double))); } unittest { auto a = allocatorObject(Mallocator.instance); auto b = a.allocate(100); assert(b.length == 100); FreeList!(GCAllocator, 0, 8) fl; auto sa = allocatorObject(fl); b = a.allocate(101); assert(b.length == 101); FallbackAllocator!(InSituRegion!(10240, 64), GCAllocator) fb; // Doesn't work yet... //a = allocatorObject(fb); //b = a.allocate(102); //assert(b.length == 102); } /// unittest { /// Define an allocator bound to the built-in GC. IAllocator alloc = allocatorObject(GCAllocator.instance); auto b = alloc.allocate(42); assert(b.length == 42); assert(alloc.deallocate(b) == Ternary.yes); // Define an elaborate allocator and bind it to the class API. // Note that the same variable "alloc" is used. alias FList = FreeList!(GCAllocator, 0, unbounded); alias A = ThreadLocal!( Segregator!( 8, FreeList!(GCAllocator, 0, 8), 128, Bucketizer!(FList, 1, 128, 16), 256, Bucketizer!(FList, 129, 256, 32), 512, Bucketizer!(FList, 257, 512, 64), 1024, Bucketizer!(FList, 513, 1024, 128), 2048, Bucketizer!(FList, 1025, 2048, 256), 3584, Bucketizer!(FList, 2049, 3584, 512), 4072 * 1024, AllocatorList!( (n) => BitmappedBlock!(4096)(GCAllocator.instance.allocate( max(n, 4072 * 1024)))), GCAllocator ) ); auto alloc2 = allocatorObject(A.instance); b = alloc.allocate(101); assert(alloc.deallocate(b) == Ternary.yes); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/gc_allocator.d0000664000175000017500000001041012776215007025155 0ustar kaikaimodule std.experimental.allocator.gc_allocator; import std.experimental.allocator.common; /** D's built-in garbage-collected allocator. */ struct GCAllocator { import core.memory : GC; unittest { testAllocator!(() => GCAllocator.instance); } /** The alignment is a static constant equal to $(D platformAlignment), which ensures proper alignment for any D data type. */ enum uint alignment = platformAlignment; /** Standard allocator methods per the semantics defined above. The $(D deallocate) and $(D reallocate) methods are $(D @system) because they may move memory around, leaving dangling pointers in user code. */ @trusted void[] allocate(size_t bytes) shared { if (!bytes) return null; auto p = GC.malloc(bytes); return p ? p[0 .. bytes] : null; } /// Ditto @system bool expand(ref void[] b, size_t delta) shared { if (delta == 0) return true; if (b is null) { b = allocate(delta); return b.ptr != null; // we assume allocate will achieve the correct size. } immutable curLength = GC.sizeOf(b.ptr); assert(curLength != 0); // we have a valid GC pointer here immutable desired = b.length + delta; if(desired > curLength) // check to see if the current block can't hold the data { immutable sizeRequest = desired - curLength; immutable newSize = GC.extend(b.ptr, sizeRequest, sizeRequest); if (newSize == 0) { // expansion unsuccessful return false; } assert(newSize >= desired); } b = b.ptr[0 .. desired]; return true; } /// Ditto @system bool reallocate(ref void[] b, size_t newSize) shared { import core.exception : OutOfMemoryError; try { auto p = cast(ubyte*) GC.realloc(b.ptr, newSize); b = p[0 .. newSize]; } catch (OutOfMemoryError) { // leave the block in place, tell caller return false; } return true; } /// Ditto void[] resolveInternalPointer(void* p) shared { auto r = GC.addrOf(p); if (!r) return null; return r[0 .. GC.sizeOf(r)]; } /// Ditto @system bool deallocate(void[] b) shared { GC.free(b.ptr); return true; } /// Ditto size_t goodAllocSize(size_t n) shared { if(n == 0) return 0; if(n <= 16) return 16; import core.bitop: bsr; auto largestBit = bsr(n-1) + 1; if (largestBit <= 12) // 4096 or less return size_t(1) << largestBit; // larger, we use a multiple of 4096. return ((n + 4095) / 4096) * 4096; } /** Returns the global instance of this allocator type. The garbage collected allocator is thread-safe, therefore all of its methods and `instance` itself are $(D shared). */ static shared GCAllocator instance; // Leave it undocummented for now. @trusted void collect() shared { GC.collect(); } } /// unittest { auto buffer = GCAllocator.instance.allocate(1024 * 1024 * 4); // deallocate upon scope's end (alternatively: leave it to collection) scope(exit) GCAllocator.instance.deallocate(buffer); //... } unittest { auto b = GCAllocator.instance.allocate(10_000); assert(GCAllocator.instance.expand(b, 1)); } unittest { import core.memory: GC; // test allocation sizes assert(GCAllocator.instance.goodAllocSize(1) == 16); for(size_t s = 16; s <= 8192; s *= 2) { assert(GCAllocator.instance.goodAllocSize(s) == s); assert(GCAllocator.instance.goodAllocSize(s - (s / 2) + 1) == s); auto buffer = GCAllocator.instance.allocate(s); scope(exit) GCAllocator.instance.deallocate(buffer); assert(GC.sizeOf(buffer.ptr) == s); auto buffer2 = GCAllocator.instance.allocate(s - (s / 2) + 1); scope(exit) GCAllocator.instance.deallocate(buffer2); assert(GC.sizeOf(buffer2.ptr) == s); } // anything above a page is simply rounded up to next page assert(GCAllocator.instance.goodAllocSize(4096 * 4 + 1) == 4096 * 5); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/0000775000175000017500000000000012776215007025515 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/free_list.d0000664000175000017500000010061212776215007027636 0ustar kaikaimodule std.experimental.allocator.building_blocks.free_list; import std.experimental.allocator.common; import std.typecons : Flag, Yes, No; /** $(WEB en.wikipedia.org/wiki/Free_list, Free list allocator), stackable on top of another allocator. Allocation requests between $(D min) and $(D max) bytes are rounded up to $(D max) and served from a singly-linked list of buffers deallocated in the past. All other allocations are directed to $(D ParentAllocator). Due to the simplicity of free list management, allocations from the free list are fast. One instantiation is of particular interest: $(D FreeList!(0, unbounded)) puts every deallocation in the freelist, and subsequently serves any allocation from the freelist (if not empty). There is no checking of size matching, which would be incorrect for a freestanding allocator but is both correct and fast when an owning allocator on top of the free list allocator (such as $(D Segregator)) is already in charge of handling size checking. The following methods are defined if $(D ParentAllocator) defines them, and forward to it: $(D expand), $(D owns), $(D reallocate). */ struct FreeList(ParentAllocator, size_t minSize, size_t maxSize = minSize, Flag!"adaptive" adaptive = No.adaptive) { import std.conv : text; import std.exception : enforce; import std.traits : hasMember; static assert(minSize != unbounded, "Use minSize = 0 for no low bound."); static assert(maxSize >= (void*).sizeof, "Maximum size must accommodate a pointer."); private enum unchecked = minSize == 0 && maxSize == unbounded; private enum hasTolerance = !unchecked && (minSize != maxSize || maxSize == chooseAtRuntime); static if (minSize == chooseAtRuntime) { /** Returns the smallest allocation size eligible for allocation from the freelist. (If $(D minSize != chooseAtRuntime), this is simply an alias for $(D minSize).) */ @property size_t min() const { assert(_min != chooseAtRuntime); return _min; } /** If $(D FreeList) has been instantiated with $(D minSize == chooseAtRuntime), then the $(D min) property is writable. Setting it must precede any allocation. Params: low = new value for $(D min) Precondition: $(D low <= max), or $(D maxSize == chooseAtRuntime) and $(D max) has not yet been initialized. Also, no allocation has been yet done with this allocator. Postcondition: $(D min == low) */ @property void min(size_t low) { assert(low <= max || max == chooseAtRuntime); minimize; _min = low; } } else { alias min = minSize; } static if (maxSize == chooseAtRuntime) { /** Returns the largest allocation size eligible for allocation from the freelist. (If $(D maxSize != chooseAtRuntime), this is simply an alias for $(D maxSize).) All allocation requests for sizes greater than or equal to $(D min) and less than or equal to $(D max) are rounded to $(D max) and forwarded to the parent allocator. When the block fitting the same constraint gets deallocated, it is put in the freelist with the allocated size assumed to be $(D max). */ @property size_t max() const { return _max; } /** If $(D FreeList) has been instantiated with $(D maxSize == chooseAtRuntime), then the $(D max) property is writable. Setting it must precede any allocation. Params: high = new value for $(D max) Precondition: $(D high >= min), or $(D minSize == chooseAtRuntime) and $(D min) has not yet been initialized. Also $(D high >= (void*).sizeof). Also, no allocation has been yet done with this allocator. Postcondition: $(D max == high) */ @property void max(size_t high) { assert((high >= min || min == chooseAtRuntime) && high >= (void*).sizeof); minimize; _max = high; } /// unittest { FreeList!(Mallocator, chooseAtRuntime, chooseAtRuntime) a; a.min = 64; a.max = 128; assert(a.min == 64); assert(a.max == 128); } } else { alias max = maxSize; } private bool tooSmall(size_t n) const { static if (minSize == 0) return false; else return n < min; } private bool tooLarge(size_t n) const { static if (maxSize == unbounded) return false; else return n > max; } private bool freeListEligible(size_t n) const { static if (unchecked) { return true; } else { static if (minSize == 0) { if (!n) return false; } static if (minSize == maxSize && minSize != chooseAtRuntime) return n == maxSize; else return !tooSmall(n) && !tooLarge(n); } } static if (!unchecked) private void[] blockFor(Node* p) { assert(p); return (cast(void*) p)[0 .. max]; } // statistics { static if (adaptive == Yes.adaptive) { private enum double windowLength = 1000.0; private enum double tooFewMisses = 0.01; private double probMiss = 1.0; // start with a high miss probability private uint accumSamples, accumMisses; void updateStats() { assert(accumSamples >= accumMisses); /* Given that for the past windowLength samples we saw misses with estimated probability probMiss, and assuming the new sample wasMiss or not, what's the new estimated probMiss? */ probMiss = (probMiss * windowLength + accumMisses) / (windowLength + accumSamples); assert(probMiss <= 1.0); accumSamples = 0; accumMisses = 0; // If probability to miss is under x%, yank one off the freelist static if (!unchecked) { if (probMiss < tooFewMisses && _root) { auto b = blockFor(_root); _root = _root.next; parent.deallocate(b); } } } } // } statistics private struct Node { Node* next; } static assert(ParentAllocator.alignment >= Node.alignof); // state { /** The parent allocator. Depending on whether $(D ParentAllocator) holds state or not, this is a member variable or an alias for `ParentAllocator.instance`. */ static if (stateSize!ParentAllocator) ParentAllocator parent; else alias parent = ParentAllocator.instance; private Node* root; static if (minSize == chooseAtRuntime) private size_t _min = chooseAtRuntime; static if (maxSize == chooseAtRuntime) private size_t _max = chooseAtRuntime; // } /** Alignment offered. */ alias alignment = ParentAllocator.alignment; /** If $(D maxSize == unbounded), returns $(D parent.goodAllocSize(bytes)). Otherwise, returns $(D max) for sizes in the interval $(D [min, max]), and $(D parent.goodAllocSize(bytes)) otherwise. Precondition: If set at runtime, $(D min) and/or $(D max) must be initialized appropriately. Postcondition: $(D result >= bytes) */ size_t goodAllocSize(size_t bytes) { assert(minSize != chooseAtRuntime && maxSize != chooseAtRuntime); static if (maxSize != unbounded) { if (freeListEligible(bytes)) { assert(parent.goodAllocSize(max) == max, text("Wrongly configured freelist: maximum should be ", parent.goodAllocSize(max), " instead of ", max)); return max; } } return parent.goodAllocSize(bytes); } private void[] allocateEligible(size_t bytes) { assert(bytes); if (root) { // faster auto result = (cast(ubyte*) root)[0 .. bytes]; root = root.next; return result; } // slower static if (hasTolerance) { immutable toAllocate = max; } else { alias toAllocate = bytes; } assert(toAllocate == max || max == unbounded); auto result = parent.allocate(toAllocate); static if (hasTolerance) { if (result) result = result.ptr[0 .. bytes]; } static if (adaptive == Yes.adaptive) { ++accumMisses; updateStats; } return result; } /** Allocates memory either off of the free list or from the parent allocator. If $(D n) is within $(D [min, max]) or if the free list is unchecked ($(D minSize == 0 && maxSize == size_t.max)), then the free list is consulted first. If not empty (hit), the block at the front of the free list is removed from the list and returned. Otherwise (miss), a new block of $(D max) bytes is allocated, truncated to $(D n) bytes, and returned. Params: n = number of bytes to allocate Returns: The allocated block, or $(D null). Precondition: If set at runtime, $(D min) and/or $(D max) must be initialized appropriately. Postcondition: $(D result.length == bytes || result is null) */ void[] allocate(size_t n) { static if (adaptive == Yes.adaptive) ++accumSamples; assert(n < size_t.max / 2); // fast path if (freeListEligible(n)) { return allocateEligible(n); } // slower static if (adaptive == Yes.adaptive) { updateStats; } return parent.allocate(n); } // Forwarding methods mixin(forwardToMember("parent", "expand", "owns", "reallocate")); /** If $(D block.length) is within $(D [min, max]) or if the free list is unchecked ($(D minSize == 0 && maxSize == size_t.max)), then inserts the block at the front of the free list. For all others, forwards to $(D parent.deallocate) if $(D Parent.deallocate) is defined. Params: block = Block to deallocate. Precondition: If set at runtime, $(D min) and/or $(D max) must be initialized appropriately. The block must have been allocated with this freelist, and no dynamic changing of $(D min) or $(D max) is allowed to occur between allocation and deallocation. */ bool deallocate(void[] block) { if (freeListEligible(block.length)) { if (min == 0) { // In this case a null pointer might have made it this far. if (block is null) return true; } auto t = root; root = cast(Node*) block.ptr; root.next = t; return true; } static if (hasMember!(ParentAllocator, "deallocate")) return parent.deallocate(block); else return false; } /** Defined only if $(D ParentAllocator) defines $(D deallocateAll). If so, forwards to it and resets the freelist. */ static if (hasMember!(ParentAllocator, "deallocateAll")) bool deallocateAll() { root = null; return parent.deallocateAll(); } /** Nonstandard function that minimizes the memory usage of the freelist by freeing each element in turn. Defined only if $(D ParentAllocator) defines $(D deallocate). */ static if (hasMember!(ParentAllocator, "deallocate") && !unchecked) void minimize() { while (root) { auto nuke = blockFor(root); root = root.next; parent.deallocate(nuke); } } } unittest { import std.experimental.allocator.gc_allocator : GCAllocator; FreeList!(GCAllocator, 0, 8) fl; assert(fl.root is null); auto b1 = fl.allocate(7); //assert(fl._root !is null); fl.allocate(8); assert(fl.root is null); fl.deallocate(b1); assert(fl.root !is null); fl.allocate(8); assert(fl.root is null); } /** Free list built on top of exactly one contiguous block of memory. The block is assumed to have been allocated with $(D ParentAllocator), and is released in $(D ContiguousFreeList)'s destructor (unless $(D ParentAllocator) is $(D NullAllocator)). $(D ContiguousFreeList) has most advantages of $(D FreeList) but fewer disadvantages. It has better cache locality because items are closer to one another. It imposes less fragmentation on its parent allocator. The disadvantages of $(D ContiguousFreeList) over $(D FreeList) are its pay upfront model (as opposed to $(D FreeList)'s pay-as-you-go approach), and a hard limit on the number of nodes in the list. Thus, a large number of long- lived objects may occupy the entire block, making it unavailable for serving allocations from the free list. However, an absolute cap on the free list size may be beneficial. The options $(D minSize == unbounded) and $(D maxSize == unbounded) are not available for $(D ContiguousFreeList). */ struct ContiguousFreeList(ParentAllocator, size_t minSize, size_t maxSize = minSize) { import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; import std.experimental.allocator.building_blocks.stats_collector : StatsCollector, Options; import std.traits : hasMember; alias Impl = FreeList!(NullAllocator, minSize, maxSize); enum unchecked = minSize == 0 && maxSize == unbounded; alias Node = Impl.Node; alias SParent = StatsCollector!(ParentAllocator, Options.bytesUsed); // state { /** The parent allocator. Depending on whether $(D ParentAllocator) holds state or not, this is a member variable or an alias for `ParentAllocator.instance`. */ SParent parent; FreeList!(NullAllocator, minSize, maxSize) fl; void[] support; size_t allocated; // } /// Alignment offered. enum uint alignment = (void*).alignof; private void initialize(void[] buffer, size_t itemSize = fl.max) { assert(itemSize != unbounded && itemSize != chooseAtRuntime); assert(buffer.ptr.alignedAt(alignment)); immutable available = buffer.length / itemSize; if (available == 0) return; support = buffer; fl.root = cast(Node*) buffer.ptr; auto past = cast(Node*) (buffer.ptr + available * itemSize); for (auto n = fl.root; ; ) { auto next = cast(Node*) (cast(ubyte*) n + itemSize); if (next == past) { n.next = null; break; } assert(next < past); assert(n < next); n.next = next; n = next; } } /** Constructors setting up the memory structured as a free list. Params: buffer = Buffer to structure as a free list. If $(D ParentAllocator) is not $(D NullAllocator), the buffer is assumed to be allocated by $(D parent) and will be freed in the destructor. parent = Parent allocator. For construction from stateless allocators, use their `instance` static member. bytes = Bytes (not items) to be allocated for the free list. Memory will be allocated during construction and deallocated in the destructor. max = Maximum size eligible for freelisting. Construction with this parameter is defined only if $(D maxSize == chooseAtRuntime) or $(D maxSize == unbounded). min = Minimum size eligible for freelisting. Construction with this parameter is defined only if $(D minSize == chooseAtRuntime). If this condition is met and no $(D min) parameter is present, $(D min) is initialized with $(D max). */ static if (!stateSize!ParentAllocator) this(void[] buffer) { initialize(buffer); } /// ditto static if (stateSize!ParentAllocator) this(ParentAllocator parent, void[] buffer) { initialize(buffer); this.parent = SParent(parent); } /// ditto static if (!stateSize!ParentAllocator) this(size_t bytes) { initialize(ParentAllocator.instance.allocate(bytes)); } /// ditto static if (stateSize!ParentAllocator) this(ParentAllocator parent, size_t bytes) { initialize(parent.allocate(bytes)); this.parent = SParent(parent); } /// ditto static if (!stateSize!ParentAllocator && (maxSize == chooseAtRuntime || maxSize == unbounded)) this(size_t bytes, size_t max) { static if (maxSize == chooseAtRuntime) fl.max = max; static if (minSize == chooseAtRuntime) fl.min = max; initialize(parent.allocate(bytes), max); } /// ditto static if (stateSize!ParentAllocator && (maxSize == chooseAtRuntime || maxSize == unbounded)) this(ParentAllocator parent, size_t bytes, size_t max) { static if (maxSize == chooseAtRuntime) fl.max = max; static if (minSize == chooseAtRuntime) fl.min = max; initialize(parent.allocate(bytes), max); this.parent = SParent(parent); } /// ditto static if (!stateSize!ParentAllocator && (maxSize == chooseAtRuntime || maxSize == unbounded) && minSize == chooseAtRuntime) this(size_t bytes, size_t min, size_t max) { static if (maxSize == chooseAtRuntime) fl.max = max; fl.min = min; initialize(parent.allocate(bytes), max); static if (stateSize!ParentAllocator) this.parent = SParent(parent); } /// ditto static if (stateSize!ParentAllocator && (maxSize == chooseAtRuntime || maxSize == unbounded) && minSize == chooseAtRuntime) this(ParentAllocator parent, size_t bytes, size_t min, size_t max) { static if (maxSize == chooseAtRuntime) fl.max = max; fl.min = min; initialize(parent.allocate(bytes), max); static if (stateSize!ParentAllocator) this.parent = SParent(parent); } /** If $(D n) is eligible for freelisting, returns $(D max). Otherwise, returns $(D parent.goodAllocSize(n)). Precondition: If set at runtime, $(D min) and/or $(D max) must be initialized appropriately. Postcondition: $(D result >= bytes) */ size_t goodAllocSize(size_t n) { if (fl.freeListEligible(n)) return fl.max; return parent.goodAllocSize(n); } /** Allocate $(D n) bytes of memory. If $(D n) is eligible for freelist and the freelist is not empty, pops the memory off the free list. In all other cases, uses the parent allocator. */ void[] allocate(size_t n) { auto result = fl.allocate(n); if (result) { // Only case we care about: eligible sizes allocated from us ++allocated; return result; } // All others, allocate from parent return parent.allocate(n); } /** Defined if `ParentAllocator` defines it. Checks whether the block belongs to this allocator. */ static if (hasMember!(SParent, "owns") || unchecked) Ternary owns(void[] b) { if (support.ptr <= b.ptr && b.ptr < support.ptr + support.length) return Ternary.yes; static if (unchecked) return Ternary.no; else return parent.owns(b); } /** Deallocates $(D b). If it's of eligible size, it's put on the free list. Otherwise, it's returned to $(D parent). Precondition: $(D b) has been allocated with this allocator, or is $(D null). */ bool deallocate(void[] b) { if (support.ptr <= b.ptr && b.ptr < support.ptr + support.length) { // we own this guy import std.conv : text; assert(fl.freeListEligible(b.length), text(b.length)); assert(allocated); --allocated; // Put manually in the freelist auto t = fl.root; fl.root = cast(Node*) b.ptr; fl.root.next = t; return true; } return parent.deallocate(b); } /** Deallocates everything from the parent. */ static if (hasMember!(ParentAllocator, "deallocateAll") && stateSize!ParentAllocator) bool deallocateAll() { bool result = fl.deallocateAll && parent.deallocateAll; allocated = 0; return result; } /** Returns `Ternary.yes` if no memory is currently allocated with this allocator, `Ternary.no` otherwise. This method never returns `Ternary.unknown`. */ Ternary empty() { return Ternary(allocated == 0 && parent.bytesUsed == 0); } } /// unittest { import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; alias ScalableFreeList = AllocatorList!((n) => ContiguousFreeList!(GCAllocator, 0, unbounded)(4096) ); } unittest { import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; alias A = ContiguousFreeList!(NullAllocator, 0, 64); auto a = A(new void[1024]); assert(a.empty == Ternary.yes); assert(a.goodAllocSize(15) == 64); assert(a.goodAllocSize(65) == NullAllocator.instance.goodAllocSize(65)); auto b = a.allocate(100); assert(a.empty == Ternary.yes); assert(b.length == 0); a.deallocate(b); b = a.allocate(64); assert(a.empty == Ternary.no); assert(b.length == 64); assert(a.owns(b) == Ternary.yes); assert(a.owns(null) == Ternary.no); a.deallocate(b); } unittest { import std.experimental.allocator.building_blocks.region : Region; import std.experimental.allocator.gc_allocator : GCAllocator; alias A = ContiguousFreeList!(Region!GCAllocator, 0, 64); auto a = A(Region!GCAllocator(1024 * 4), 1024); assert(a.empty == Ternary.yes); assert(a.goodAllocSize(15) == 64); assert(a.goodAllocSize(65) == a.parent.goodAllocSize(65)); auto b = a.allocate(100); assert(a.empty == Ternary.no); assert(a.allocated == 0); assert(b.length == 100); a.deallocate(b); assert(a.empty == Ternary.yes); b = a.allocate(64); assert(a.empty == Ternary.no); assert(b.length == 64); assert(a.owns(b) == Ternary.yes); assert(a.owns(null) == Ternary.no); a.deallocate(b); } unittest { import std.experimental.allocator.gc_allocator : GCAllocator; alias A = ContiguousFreeList!(GCAllocator, 64, 64); auto a = A(1024); const b = a.allocate(100); assert(b.length == 100); } /** FreeList shared across threads. Allocation and deallocation are lock-free. The parameters have the same semantics as for $(D FreeList). $(D expand) is defined to forward to $(ParentAllocator.expand) (it must be also $(D shared)). */ struct SharedFreeList(ParentAllocator, size_t minSize, size_t maxSize = minSize, size_t approxMaxNodes = unbounded) { import std.conv : text; import std.exception : enforce; import std.traits : hasMember; static assert(approxMaxNodes, "approxMaxNodes must not be null."); static assert(minSize != unbounded, "Use minSize = 0 for no low bound."); static assert(maxSize >= (void*).sizeof, "Maximum size must accommodate a pointer."); private import core.atomic; static if (minSize != chooseAtRuntime) { alias min = minSize; } else { private shared size_t _min = chooseAtRuntime; @property size_t min() const shared { assert(_min != chooseAtRuntime); return _min; } @property void min(size_t x) shared { enforce(x <= max); enforce(cas(&_min, chooseAtRuntime, x), "SharedFreeList.min must be initialized exactly once."); } static if (maxSize == chooseAtRuntime) { // Both bounds can be set, provide one function for setting both in // one shot. void setBounds(size_t low, size_t high) shared { enforce(low <= high && high >= (void*).sizeof); enforce(cas(&_min, chooseAtRuntime, low), "SharedFreeList.min must be initialized exactly once."); enforce(cas(&_max, chooseAtRuntime, high), "SharedFreeList.max must be initialized exactly once."); } } } private bool tooSmall(size_t n) const shared { static if (minSize == 0) return false; else static if (minSize == chooseAtRuntime) return n < _min; else return n < minSize; } static if (maxSize != chooseAtRuntime) { alias max = maxSize; } else { private shared size_t _max = chooseAtRuntime; @property size_t max() const shared { return _max; } @property void max(size_t x) shared { enforce(x >= _min && x >= (void*).sizeof); enforce(cas(&_max, chooseAtRuntime, x), "SharedFreeList.max must be initialized exactly once."); } } private bool tooLarge(size_t n) const shared { static if (maxSize == unbounded) return false; else static if (maxSize == chooseAtRuntime) return n > _max; else return n > maxSize; } private bool freeListEligible(size_t n) const shared { static if (minSize == maxSize && minSize != chooseAtRuntime) return n == maxSize; else return !tooSmall(n) && !tooLarge(n); } static if (approxMaxNodes != chooseAtRuntime) { alias approxMaxLength = approxMaxNodes; } else { private shared size_t _approxMaxLength = chooseAtRuntime; @property size_t approxMaxLength() const shared { return _approxMaxLength; } @property void approxMaxLength(size_t x) shared { _approxMaxLength = enforce(x); } } static if (approxMaxNodes != unbounded) { private shared size_t nodes; private void incNodes() shared { atomicOp!("+=")(nodes, 1); } private void decNodes() shared { assert(nodes); atomicOp!("-=")(nodes, 1); } private bool nodesFull() shared { return nodes >= approxMaxLength; } } else { private static void incNodes() { } private static void decNodes() { } private enum bool nodesFull = false; } version (StdDdoc) { /** Properties for getting (and possibly setting) the bounds. Setting bounds is allowed only once , and before any allocation takes place. Otherwise, the primitives have the same semantics as those of $(D FreeList). */ @property size_t min(); /// Ditto @property void min(size_t newMinSize); /// Ditto @property size_t max(); /// Ditto @property void max(size_t newMaxSize); /// Ditto void setBounds(size_t newMin, size_t newMax); /// unittest { SharedFreeList!(Mallocator, chooseAtRuntime, chooseAtRuntime) a; // Set the maxSize first so setting the minSize doesn't throw a.max = 128; a.min = 64; a.setBounds(64, 128); // equivalent assert(a.max == 128); assert(a.min == 64); } /** Properties for getting (and possibly setting) the approximate maximum length of a shared freelist. */ @property size_t approxMaxLength() const shared; /// ditto @property void approxMaxLength(size_t x) shared; /// unittest { SharedFreeList!(Mallocator, 50, 50, chooseAtRuntime) a; // Set the maxSize first so setting the minSize doesn't throw a.approxMaxLength = 128; assert(a.approxMaxLength == 128); a.approxMaxLength = 1024; assert(a.approxMaxLength == 1024); a.approxMaxLength = 1; assert(a.approxMaxLength == 1); } } /** The parent allocator. Depending on whether $(D ParentAllocator) holds state or not, this is a member variable or an alias for `ParentAllocator.instance`. */ static if (stateSize!ParentAllocator) shared ParentAllocator parent; else alias parent = ParentAllocator.instance; mixin(forwardToMember("parent", "expand")); private struct Node { Node* next; } static assert(ParentAllocator.alignment >= Node.alignof); private Node* _root; /// Standard primitives. enum uint alignment = ParentAllocator.alignment; /// Ditto size_t goodAllocSize(size_t bytes) shared { if (freeListEligible(bytes)) return maxSize == unbounded ? bytes : max; return parent.goodAllocSize(bytes); } /// Ditto static if (hasMember!(ParentAllocator, "owns")) Ternary owns(void[] b) shared const { return parent.owns(b); } /// Ditto static if (hasMember!(ParentAllocator, "reallocate")) bool reallocate(void[] b, size_t s) { return parent.reallocate(b, s); } /// Ditto void[] allocate(size_t bytes) shared { assert(bytes < size_t.max / 2); if (!freeListEligible(bytes)) return parent.allocate(bytes); if (maxSize != unbounded) bytes = max; // Pop off the freelist shared Node* oldRoot = void, next = void; do { oldRoot = _root; // atomic load if (!oldRoot) return allocateFresh(bytes); next = oldRoot.next; // atomic load } while (!cas(&_root, oldRoot, next)); // great, snatched the root decNodes(); return (cast(ubyte*) oldRoot)[0 .. bytes]; } private void[] allocateFresh(const size_t bytes) shared { assert(bytes == max || max == unbounded); return parent.allocate(bytes); } /// Ditto bool deallocate(void[] b) shared { if (!nodesFull && freeListEligible(b.length)) { auto newRoot = cast(shared Node*) b.ptr; shared Node* oldRoot; do { oldRoot = _root; newRoot.next = oldRoot; } while (!cas(&_root, oldRoot, newRoot)); incNodes(); return true; } static if (hasMember!(ParentAllocator, "deallocate")) return parent.deallocate(b); else return false; } /// Ditto bool deallocateAll() shared { bool result = false; static if (hasMember!(ParentAllocator, "deallocateAll")) { result = parent.deallocateAll(); } else static if (hasMember!(ParentAllocator, "deallocate")) { result = true; for (auto n = _root; n; n = n.next) { if (!parent.deallocate((cast(ubyte*)n)[0 .. max])) result = false; } } _root = null; return result; } } unittest { import std.algorithm.comparison : equal; import std.concurrency : receiveOnly, send, spawn, thisTid, Tid; import std.range : repeat; import std.experimental.allocator.mallocator : Mallocator; static shared SharedFreeList!(Mallocator, 64, 128, 10) a; assert(a.goodAllocSize(1) == platformAlignment); auto b = a.allocate(100); a.deallocate(b); static void fun(Tid tid, int i) { scope(exit) tid.send(true); auto b = cast(ubyte[]) a.allocate(100); b[] = cast(ubyte) i; assert(b.equal(repeat(cast(ubyte) i, b.length))); a.deallocate(b); } Tid[] tids; foreach (i; 0 .. 20) { tids ~= spawn(&fun, thisTid, i); } foreach (i; 0 .. 20) { assert(receiveOnly!bool); } } unittest { import std.experimental.allocator.mallocator : Mallocator; shared SharedFreeList!(Mallocator, chooseAtRuntime, chooseAtRuntime) a; a.allocate(64); } unittest { import std.experimental.allocator.mallocator : Mallocator; shared SharedFreeList!(Mallocator, chooseAtRuntime, chooseAtRuntime, chooseAtRuntime) a; a.allocate(64); } unittest { import std.experimental.allocator.mallocator : Mallocator; shared SharedFreeList!(Mallocator, 30, 40) a; a.allocate(64); } unittest { import std.experimental.allocator.mallocator : Mallocator; shared SharedFreeList!(Mallocator, 30, 40, chooseAtRuntime) a; a.allocate(64); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/stats_collector.d0000664000175000017500000005733712776215007031105 0ustar kaikai// Written in the D programming language. /** Allocator that collects useful statistics about allocations, both global and per calling point. The statistics collected can be configured statically by choosing combinations of `Options` appropriately. Example: ---- import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.building_blocks.free_list : FreeList; alias Allocator = StatsCollector!(GCAllocator, Options.bytesUsed); ---- */ module std.experimental.allocator.building_blocks.stats_collector; import std.experimental.allocator.common; /** _Options for $(D StatsCollector) defined below. Each enables during compilation one specific counter, statistic, or other piece of information. */ enum Options : ulong { /** Counts the number of calls to $(D owns). */ numOwns = 1u << 0, /** Counts the number of calls to $(D allocate). All calls are counted, including requests for zero bytes or failed requests. */ numAllocate = 1u << 1, /** Counts the number of calls to $(D allocate) that succeeded, i.e. they returned a block as large as requested. (N.B. requests for zero bytes count as successful.) */ numAllocateOK = 1u << 2, /** Counts the number of calls to $(D expand), regardless of arguments or result. */ numExpand = 1u << 3, /** Counts the number of calls to $(D expand) that resulted in a successful expansion. */ numExpandOK = 1u << 4, /** Counts the number of calls to $(D reallocate), regardless of arguments or result. */ numReallocate = 1u << 5, /** Counts the number of calls to $(D reallocate) that succeeded. (Reallocations to zero bytes count as successful.) */ numReallocateOK = 1u << 6, /** Counts the number of calls to $(D reallocate) that resulted in an in-place reallocation (no memory moved). If this number is close to the total number of reallocations, that indicates the allocator finds room at the current block's end in a large fraction of the cases, but also that internal fragmentation may be high (the size of the unit of allocation is large compared to the typical allocation size of the application). */ numReallocateInPlace = 1u << 7, /** Counts the number of calls to $(D deallocate). */ numDeallocate = 1u << 8, /** Counts the number of calls to $(D deallocateAll). */ numDeallocateAll = 1u << 9, /** Chooses all $(D numXxx) flags. */ numAll = (1u << 10) - 1, /** Tracks bytes currently allocated by this allocator. This number goes up and down as memory is allocated and deallocated, and is zero if the allocator currently has no active allocation. */ bytesUsed = 1u << 10, /** Tracks total cumulative bytes allocated by means of $(D allocate), $(D expand), and $(D reallocate) (when resulting in an expansion). This number always grows and indicates allocation traffic. To compute bytes deallocated cumulatively, subtract $(D bytesUsed) from $(D bytesAllocated). */ bytesAllocated = 1u << 11, /** Tracks the sum of all $(D delta) values in calls of the form $(D expand(b, delta)) that succeed (return $(D true)). */ bytesExpanded = 1u << 12, /** Tracks the sum of all $(D b.length - s) with $(D b.length > s) in calls of the form $(D realloc(b, s)) that succeed (return $(D true)). In per-call statistics, also unambiguously counts the bytes deallocated with $(D deallocate). */ bytesContracted = 1u << 13, /** Tracks the sum of all bytes moved as a result of calls to $(D realloc) that were unable to reallocate in place. A large number (relative to $(D bytesAllocated)) indicates that the application should use larger preallocations. */ bytesMoved = 1u << 14, /** Tracks the sum of all bytes NOT moved as result of calls to $(D realloc) that managed to reallocate in place. A large number (relative to $(D bytesAllocated)) indicates that the application is expansion-intensive and is saving a good amount of moves. However, if this number is relatively small and $(D bytesSlack) is high, it means the application is overallocating for little benefit. */ bytesNotMoved = 1u << 15, /** Measures the sum of extra bytes allocated beyond the bytes requested, i.e. the $(WEB goo.gl/YoKffF, internal fragmentation). This is the current effective number of slack bytes, and it goes up and down with time. */ bytesSlack = 1u << 16, /** Measures the maximum bytes allocated over the time. This is useful for dimensioning allocators. */ bytesHighTide = 1u << 17, /** Chooses all $(D byteXxx) flags. */ bytesAll = ((1u << 18) - 1) & ~numAll, /** Combines all flags above. */ all = (1u << 18) - 1 } /** Allocator that collects extra data about allocations. Since each piece of information adds size and time overhead, statistics can be individually enabled or disabled through compile-time $(D flags). All stats of the form $(D numXxx) record counts of events occurring, such as calls to functions and specific results. The stats of the form $(D bytesXxx) collect cumulative sizes. In addition, the data $(D callerSize), $(D callerModule), $(D callerFile), $(D callerLine), and $(D callerTime) is associated with each specific allocation. This data prefixes each allocation. */ struct StatsCollector(Allocator, ulong flags = Options.all, ulong perCallFlags = 0) { private: import std.traits : hasMember, Signed; static string define(string type, string[] names...) { string result; foreach (v; names) result ~= "static if (flags & Options."~v~") {" ~ "private "~type~" _"~v~";" ~ "public const("~type~") "~v~"() const { return _"~v~"; }" ~ "}"; return result; } void add(string counter)(Signed!size_t n) { mixin("static if (flags & Options." ~ counter ~ ") _" ~ counter ~ " += n;"); static if (counter == "bytesUsed" && (flags & Options.bytesHighTide)) { if (bytesHighTide < bytesUsed ) _bytesHighTide = bytesUsed; } } void up(string counter)() { add!counter(1); } void down(string counter)() { add!counter(-1); } version (StdDdoc) { /** Read-only properties enabled by the homonym $(D flags) chosen by the user. Example: ---- StatsCollector!(Mallocator, Options.bytesUsed | Options.bytesAllocated) a; auto d1 = a.allocate(10); auto d2 = a.allocate(11); a.deallocate(d1); assert(a.bytesAllocated == 21); assert(a.bytesUsed == 11); a.deallocate(d2); assert(a.bytesAllocated == 21); assert(a.bytesUsed == 0); ---- */ @property ulong numOwns() const; /// Ditto @property ulong numAllocate() const; /// Ditto @property ulong numAllocateOK() const; /// Ditto @property ulong numExpand() const; /// Ditto @property ulong numExpandOK() const; /// Ditto @property ulong numReallocate() const; /// Ditto @property ulong numReallocateOK() const; /// Ditto @property ulong numReallocateInPlace() const; /// Ditto @property ulong numDeallocate() const; /// Ditto @property ulong numDeallocateAll() const; /// Ditto @property ulong bytesUsed() const; /// Ditto @property ulong bytesAllocated() const; /// Ditto @property ulong bytesExpanded() const; /// Ditto @property ulong bytesContracted() const; /// Ditto @property ulong bytesMoved() const; /// Ditto @property ulong bytesNotMoved() const; /// Ditto @property ulong bytesSlack() const; /// Ditto @property ulong bytesHighTide() const; } public: /** The parent allocator is publicly accessible either as a direct member if it holds state, or as an alias to `Allocator.instance` otherwise. One may use it for making calls that won't count toward statistics collection. */ static if (stateSize!Allocator) Allocator parent; else alias parent = Allocator.instance; private: // Per-allocator state mixin(define("ulong", "numOwns", "numAllocate", "numAllocateOK", "numExpand", "numExpandOK", "numReallocate", "numReallocateOK", "numReallocateInPlace", "numDeallocate", "numDeallocateAll", "bytesUsed", "bytesAllocated", "bytesExpanded", "bytesContracted", "bytesMoved", "bytesNotMoved", "bytesSlack", "bytesHighTide", )); public: /// Alignment offered is equal to $(D Allocator.alignment). alias alignment = Allocator.alignment; /** Increments $(D numOwns) (per instance and and per call) and forwards to $(D parent.owns(b)). */ static if (hasMember!(Allocator, "owns")) { static if ((perCallFlags & Options.numOwns) == 0) Ternary owns(void[] b) { return ownsImpl(b); } else Ternary owns(string f = __FILE, uint n = line)(void[] b) { return ownsImpl!(f, n)(b); } } private Ternary ownsImpl(string f = null, uint n = 0)(void[] b) { up!"numOwns"; addPerCall!(f, n, "numOwns")(1); return parent.owns(b); } /** Forwards to $(D parent.allocate). Affects per instance: $(D numAllocate), $(D bytesUsed), $(D bytesAllocated), $(D bytesSlack), $(D numAllocateOK), and $(D bytesHighTide). Affects per call: $(D numAllocate), $(D numAllocateOK), and $(D bytesAllocated). */ static if (!(perCallFlags & (Options.numAllocate | Options.numAllocateOK | Options.bytesAllocated))) { void[] allocate(size_t n) { return allocateImpl(n); } } else { void[] allocate(string f = __FILE__, ulong n = __LINE__) (size_t bytes) { return allocateImpl!(f, n)(bytes); } } private void[] allocateImpl(string f = null, ulong n = 0)(size_t bytes) { auto result = parent.allocate(bytes); add!"bytesUsed"(result.length); add!"bytesAllocated"(result.length); immutable slack = this.goodAllocSize(result.length) - result.length; add!"bytesSlack"(slack); up!"numAllocate"; add!"numAllocateOK"(result.length == bytes); // allocating 0 bytes is OK addPerCall!(f, n, "numAllocate", "numAllocateOK", "bytesAllocated") (1, result.length == bytes, result.length); return result; } /** Defined whether or not $(D Allocator.expand) is defined. Affects per instance: $(D numExpand), $(D numExpandOK), $(D bytesExpanded), $(D bytesSlack), $(D bytesAllocated), and $(D bytesUsed). Affects per call: $(D numExpand), $(D numExpandOK), $(D bytesExpanded), and $(D bytesAllocated). */ static if (!(perCallFlags & (Options.numExpand | Options.numExpandOK | Options.bytesExpanded))) { bool expand(ref void[] b, size_t delta) { return expandImpl(b, delta); } } else { bool expand(string f = __FILE__, uint n = __LINE__) (ref void[] b, size_t delta) { return expandImpl!(f, n)(b, delta); } } private bool expandImpl(string f = null, uint n = 0)(ref void[] b, size_t s) { up!"numExpand"; Signed!size_t slack = 0; static if (!hasMember!(Allocator, "expand")) { auto result = s == 0; } else { immutable bytesSlackB4 = this.goodAllocSize(b.length) - b.length; auto result = parent.expand(b, s); if (result) { up!"numExpandOK"; add!"bytesUsed"(s); add!"bytesAllocated"(s); add!"bytesExpanded"(s); slack = Signed!size_t(this.goodAllocSize(b.length) - b.length - bytesSlackB4); add!"bytesSlack"(slack); } } immutable xtra = result ? s : 0; addPerCall!(f, n, "numExpand", "numExpandOK", "bytesExpanded", "bytesAllocated") (1, result, xtra, xtra); return result; } /** Defined whether or not $(D Allocator.reallocate) is defined. Affects per instance: $(D numReallocate), $(D numReallocateOK), $(D numReallocateInPlace), $(D bytesNotMoved), $(D bytesAllocated), $(D bytesSlack), $(D bytesExpanded), and $(D bytesContracted). Affects per call: $(D numReallocate), $(D numReallocateOK), $(D numReallocateInPlace), $(D bytesNotMoved), $(D bytesExpanded), $(D bytesContracted), and $(D bytesMoved). */ static if (!(perCallFlags & (Options.numReallocate | Options.numReallocateOK | Options.numReallocateInPlace | Options.bytesNotMoved | Options.bytesExpanded | Options.bytesContracted | Options.bytesMoved))) { bool reallocate(ref void[] b, size_t s) { return reallocateImpl(b, s); } } else { bool reallocate(string f = __FILE__, ulong n = __LINE__) (ref void[] b, size_t s) { return reallocateImpl!(f, n)(b, s); } } private bool reallocateImpl(string f = null, uint n = 0) (ref void[] b, size_t s) { up!"numReallocate"; const bytesSlackB4 = this.goodAllocSize(b.length) - b.length; const oldB = b.ptr; const oldLength = b.length; const result = parent.reallocate(b, s); Signed!size_t slack = 0; bool wasInPlace = false; Signed!size_t delta = 0; if (result) { up!"numReallocateOK"; slack = (this.goodAllocSize(b.length) - b.length) - bytesSlackB4; add!"bytesSlack"(slack); add!"bytesUsed"(Signed!size_t(b.length - oldLength)); if (oldB == b.ptr) { // This was an in-place reallocation, yay wasInPlace = true; up!"numReallocateInPlace"; add!"bytesNotMoved"(oldLength); delta = b.length - oldLength; if (delta >= 0) { // Expansion add!"bytesAllocated"(delta); add!"bytesExpanded"(delta); } else { // Contraction add!"bytesContracted"(-delta); } } else { // This was a allocate-move-deallocate cycle add!"bytesAllocated"(b.length); add!"bytesMoved"(oldLength); } } addPerCall!(f, n, "numReallocate", "numReallocateOK", "numReallocateInPlace", "bytesNotMoved", "bytesExpanded", "bytesContracted", "bytesMoved") (1, result, wasInPlace, wasInPlace ? oldLength : 0, delta >= 0 ? delta : 0, delta < 0 ? -delta : 0, wasInPlace ? 0 : oldLength); return result; } /** Defined whether or not $(D Allocator.deallocate) is defined. Affects per instance: $(D numDeallocate), $(D bytesUsed), and $(D bytesSlack). Affects per call: $(D numDeallocate) and $(D bytesContracted). */ static if (!(perCallFlags & (Options.numDeallocate | Options.bytesContracted))) bool deallocate(void[] b) { return deallocateImpl(b); } else bool deallocate(string f = __FILE__, uint n = __LINE__)(void[] b) { return deallocateImpl!(f, n)(b); } private bool deallocateImpl(string f = null, uint n = 0)(void[] b) { up!"numDeallocate"; add!"bytesUsed"(-Signed!size_t(b.length)); add!"bytesSlack"(-(this.goodAllocSize(b.length) - b.length)); addPerCall!(f, n, "numDeallocate", "bytesContracted")(1, b.length); static if (hasMember!(Allocator, "deallocate")) return parent.deallocate(b); else return false; } static if (hasMember!(Allocator, "deallocateAll")) { /** Defined only if $(D Allocator.deallocateAll) is defined. Affects per instance and per call $(D numDeallocateAll). */ static if (!(perCallFlags & Options.numDeallocateAll)) bool deallocateAll() { return deallocateAllImpl(); } else bool deallocateAll(string f = __FILE__, uint n = __LINE__)() { return deallocateAllImpl!(f, n)(); } private bool deallocateAllImpl(string f = null, uint n = 0)() { up!"numDeallocateAll"; addPerCall!(f, n, "numDeallocateAll")(1); static if ((flags & Options.bytesUsed)) _bytesUsed = 0; return parent.deallocateAll(); } } /** Defined only if $(D Options.bytesUsed) is defined. Returns $(D bytesUsed == 0). */ static if (flags & Options.bytesUsed) Ternary empty() { return Ternary(_bytesUsed == 0); } /** Reports per instance statistics to $(D output) (e.g. $(D stdout)). The format is simple: one kind and value per line, separated by a colon, e.g. $(D bytesAllocated:7395404) */ void reportStatistics(R)(auto ref R output) { import std.traits : EnumMembers; import std.conv : to; foreach (e; EnumMembers!Options) { static if ((flags & e) && e != Options.numAll && e != Options.bytesAll && e != Options.all) output.write(e.to!string, ":", mixin(e.to!string), '\n'); } } static if (perCallFlags) { /** Defined if $(D perCallFlags) is nonzero. */ struct PerCallStatistics { /// The file and line of the call. string file; /// Ditto uint line; /// The options corresponding to the statistics collected. Options[] opts; /// The values of the statistics. Has the same length as $(D opts). ulong[] values; // Next in the chain. private PerCallStatistics* next; /** Format to a string such as: $(D mymodule.d(655): [numAllocate:21, numAllocateOK:21, bytesAllocated:324202]). */ string toString() const { import std.conv : text, to; auto result = text(file, "(", line, "): ["); foreach (i, opt; opts) { if (i) result ~= ", "; result ~= opt.to!string; result ~= ':'; result ~= values[i].to!string; } return result ~= "]"; } } private static PerCallStatistics* root; /** Defined if $(D perCallFlags) is nonzero. Iterates all monitored file/line instances. The order of iteration is not meaningful (items are inserted at the front of a list upon the first call), so preprocessing the statistics after collection might be appropriate. */ static auto byFileLine() { static struct Voldemort { PerCallStatistics* current; bool empty() { return !current; } ref PerCallStatistics front() { return *current; } void popFront() { current = current.next; } auto save() { return this; } } return Voldemort(root); } /** Defined if $(D perCallFlags) is nonzero. Outputs (e.g. to a $(D File)) a simple report of the collected per-call statistics. */ static void reportPerCallStatistics(R)(auto ref R output) { output.write("Stats for: ", StatsCollector.stringof, '\n'); foreach (ref stat; byFileLine) { output.write(stat, '\n'); } } private PerCallStatistics* statsAt(string f, uint n, opts...)() { import std.range : repeat; import std.array : array; static PerCallStatistics s = { f, n, [ opts ], repeat(0UL, opts.length).array }; static bool inserted; if (!inserted) { // Insert as root s.next = root; root = &s; inserted = true; } return &s; } private void addPerCall(string f, uint n, names...)(ulong[] values...) { import std.array : join; enum uint mask = mixin("Options."~[names].join("|Options.")); static if (perCallFlags & mask) { // Per allocation info auto ps = mixin("statsAt!(f, n," ~ "Options."~[names].join(", Options.") ~")"); foreach (i; 0 .. names.length) { ps.values[i] += values[i]; } } } } else { private void addPerCall(string f, uint n, names...)(ulong[]...) { } } } /// unittest { import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.building_blocks.free_list : FreeList; alias Allocator = StatsCollector!(GCAllocator, Options.all, Options.all); Allocator alloc; auto b = alloc.allocate(10); alloc.reallocate(b, 20); alloc.deallocate(b); import std.file : deleteme, remove; import std.stdio : File; import std.range : walkLength; auto f = deleteme ~ "-dlang.std.experimental.allocator.stats_collector.txt"; scope(exit) remove(f); Allocator.reportPerCallStatistics(File(f, "w")); alloc.reportStatistics(File(f, "a")); assert(File(f).byLine.walkLength == 22); } unittest { void test(Allocator)() { import std.range : walkLength; import std.stdio : writeln; Allocator a; auto b1 = a.allocate(100); assert(a.numAllocate == 1); assert(a.expand(b1, 0)); assert(a.reallocate(b1, b1.length + 1)); auto b2 = a.allocate(101); assert(a.numAllocate == 2); assert(a.bytesAllocated == 202); assert(a.bytesUsed == 202); auto b3 = a.allocate(202); assert(a.numAllocate == 3); assert(a.bytesAllocated == 404); a.deallocate(b2); assert(a.numDeallocate == 1); a.deallocate(b1); assert(a.numDeallocate == 2); a.deallocate(b3); assert(a.numDeallocate == 3); assert(a.numAllocate == a.numDeallocate); assert(a.bytesUsed == 0); //import std.stdio; //Allocator.reportPerCallStatistics(stdout); //a.reportStatistics(stdout); } import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.building_blocks.free_list : FreeList; test!(StatsCollector!(GCAllocator, Options.all, Options.all)); test!(StatsCollector!(FreeList!(GCAllocator, 128), Options.all, Options.all)); } unittest { void test(Allocator)() { import std.range : walkLength; import std.stdio : writeln; Allocator a; auto b1 = a.allocate(100); assert(a.expand(b1, 0)); assert(a.reallocate(b1, b1.length + 1)); auto b2 = a.allocate(101); auto b3 = a.allocate(202); a.deallocate(b2); a.deallocate(b1); a.deallocate(b3); } import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.building_blocks.free_list : FreeList; test!(StatsCollector!(GCAllocator, 0, 0)); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/affix_allocator.d0000664000175000017500000002403112776215007031017 0ustar kaikaimodule std.experimental.allocator.building_blocks.affix_allocator; /** Allocator that adds some extra data before (of type $(D Prefix)) and/or after (of type $(D Suffix)) any allocation made with its parent allocator. This is useful for uses where additional allocation-related information is needed, such as mutexes, reference counts, or walls for debugging memory corruption errors. If $(D Prefix) is not $(D void), $(D Allocator) must guarantee an alignment at least as large as $(D Prefix.alignof). Suffixes are slower to get at because of alignment rounding, so prefixes should be preferred. However, small prefixes blunt the alignment so if a large alignment with a small affix is needed, suffixes should be chosen. The following methods are defined if $(D Allocator) defines them, and forward to it: $(D deallocateAll), $(D empty), $(D owns). */ struct AffixAllocator(Allocator, Prefix, Suffix = void) { import std.conv, std.experimental.allocator.common, std.traits; import std.algorithm : min; static assert( !stateSize!Prefix || Allocator.alignment >= Prefix.alignof, "AffixAllocator does not work with allocators offering a smaller" ~ " alignment than the prefix alignment."); static assert(alignment % Suffix.alignof == 0, "This restriction could be relaxed in the future."); /** If $(D Prefix) is $(D void), the alignment is that of the parent. Otherwise, the alignment is the same as the $(D Prefix)'s alignment. */ enum uint alignment = isPowerOf2(stateSize!Prefix) ? min(stateSize!Prefix, Allocator.alignment) : (stateSize!Prefix ? Prefix.alignof : Allocator.alignment); /** If the parent allocator $(D Allocator) is stateful, an instance of it is stored as a member. Otherwise, $(D AffixAllocator) uses `Allocator.instance`. In either case, the name $(D _parent) is uniformly used for accessing the parent allocator. */ static if (stateSize!Allocator) Allocator parent; else alias parent = Allocator.instance; private template Impl() { size_t goodAllocSize(size_t s) { auto a = actualAllocationSize(s); return roundUpToMultipleOf(parent.goodAllocSize(a) - stateSize!Prefix - stateSize!Suffix, this.alignment); } private size_t actualAllocationSize(size_t s) const { assert(s > 0); static if (!stateSize!Suffix) { return s + stateSize!Prefix; } else { return roundUpToMultipleOf(s + stateSize!Prefix, Suffix.alignof) + stateSize!Suffix; } } private void[] actualAllocation(void[] b) const { assert(b !is null); return (b.ptr - stateSize!Prefix) [0 .. actualAllocationSize(b.length)]; } void[] allocate(size_t bytes) { if (!bytes) return null; auto result = parent.allocate(actualAllocationSize(bytes)); if (result is null) return null; static if (stateSize!Prefix) { assert(result.ptr.alignedAt(Prefix.alignof)); emplace!Prefix(cast(Prefix*)result.ptr); } static if (stateSize!Suffix) { auto suffixP = result.ptr + result.length - Suffix.sizeof; assert(suffixP.alignedAt(Suffix.alignof)); emplace!Suffix(cast(Suffix*)(suffixP)); } return result[stateSize!Prefix .. stateSize!Prefix + bytes]; } static if (hasMember!(Allocator, "allocateAll")) void[] allocateAll() { auto result = parent.allocateAll(); if (result is null) return null; if (result.length < actualAllocationSize(1)) { deallocate(result); return null; } static if (stateSize!Prefix) { assert(result.length > stateSize!Prefix); emplace!Prefix(cast(Prefix*)result.ptr); result = result[stateSize!Prefix .. $]; } static if (stateSize!Suffix) { assert(result.length > stateSize!Suffix); // Ehm, find a properly aligned place for the suffix auto p = (result.ptr + result.length - stateSize!Suffix) .alignDownTo(Suffix.alignof); assert(p > result.ptr); emplace!Suffix(cast(Suffix*) p); result = result[0 .. p - result.ptr]; } return result; } static if (hasMember!(Allocator, "owns")) Ternary owns(void[] b) { if (b is null) return Ternary.no; return parent.owns(actualAllocation(b)); } static if (hasMember!(Allocator, "resolveInternalPointer")) void[] resolveInternalPointer(void* p) { auto p1 = parent.resolveInternalPointer(p); if (p1 is null) return p1; p1 = p1[stateSize!Prefix .. $]; auto p2 = (p1.ptr + p1.length - stateSize!Suffix) .alignDownTo(Suffix.alignof); return p1[0 .. p2 - p1.ptr]; } static if (!stateSize!Suffix && hasMember!(Allocator, "expand")) bool expand(ref void[] b, size_t delta) { if (!b.ptr) { b = allocate(delta); return b.length == delta; } auto t = actualAllocation(b); const result = parent.expand(t, delta); if (!result) return false; b = b.ptr[0 .. b.length + delta]; return true; } static if (hasMember!(Allocator, "reallocate")) bool reallocate(ref void[] b, size_t s) { if (b is null) { b = allocate(s); return b.length == s; } auto t = actualAllocation(b); const result = parent.reallocate(t, actualAllocationSize(s)); if (!result) return false; // no harm done b = t.ptr[stateSize!Prefix .. stateSize!Prefix + s]; return true; } static if (hasMember!(Allocator, "deallocate")) bool deallocate(void[] b) { if (!b.ptr) return true; return parent.deallocate(actualAllocation(b)); } /* The following methods are defined if $(D ParentAllocator) defines them, and forward to it: $(D deallocateAll), $(D empty).*/ mixin(forwardToMember("parent", "deallocateAll", "empty")); // Extra functions static if (stateSize!Prefix) static ref Prefix prefix(void[] b) { assert(b.ptr && b.ptr.alignedAt(Prefix.alignof)); return (cast(Prefix*)b.ptr)[-1]; } static if (stateSize!Suffix) ref Suffix suffix(void[] b) { assert(b.ptr); auto p = b.ptr - stateSize!Prefix + actualAllocationSize(b.length); assert(p && p.alignedAt(Suffix.alignof)); return (cast(Suffix*) p)[-1]; } } version (StdDdoc) { /** Standard allocator methods. Each is defined if and only if the parent allocator defines the homonym method (except for $(D goodAllocSize), which may use the global default). Also, the methods will be $(D shared) if the parent allocator defines them as such. */ size_t goodAllocSize(size_t); /// Ditto void[] allocate(size_t); /// Ditto Ternary owns(void[]); /// Ditto bool expand(ref void[] b, size_t delta); /// Ditto bool reallocate(ref void[] b, size_t s); /// Ditto bool deallocate(void[] b); /// Ditto bool deallocateAll(); /// Ditto Ternary empty(); /** The `instance` singleton is defined if and only if the parent allocator has no state and defines its own `it` object. */ static AffixAllocator instance; /** Affix access functions offering mutable references to the affixes of a block previously allocated with this allocator. $(D b) may not be null. They are defined if and only if the corresponding affix is not $(D void). Precondition: $(D b !is null) */ static ref Prefix prefix(void[] b); /// Ditto static ref Suffix suffix(void[] b); } else static if (is(typeof(Allocator.instance) == shared)) { static shared AffixAllocator instance; shared { mixin Impl!(); } } else { mixin Impl!(); static if (stateSize!Allocator == 0) static __gshared AffixAllocator instance; } } /// unittest { import std.experimental.allocator.mallocator : Mallocator; // One word before and after each allocation. alias A = AffixAllocator!(Mallocator, size_t, size_t); auto b = A.instance.allocate(11); A.instance.prefix(b) = 0xCAFE_BABE; A.instance.suffix(b) = 0xDEAD_BEEF; assert(A.instance.prefix(b) == 0xCAFE_BABE && A.instance.suffix(b) == 0xDEAD_BEEF); } unittest { import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock; import std.experimental.allocator.common : testAllocator; testAllocator!({ auto a = AffixAllocator!(BitmappedBlock!128, ulong, ulong) (BitmappedBlock!128(new void[128 * 4096])); return a; }); } unittest { import std.experimental.allocator.mallocator : Mallocator; alias A = AffixAllocator!(Mallocator, size_t); auto b = A.instance.allocate(10); A.instance.prefix(b) = 10; assert(A.instance.prefix(b) == 10); import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; alias B = AffixAllocator!(NullAllocator, size_t); b = B.instance.allocate(100); assert(b is null); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/allocator_list.d0000664000175000017500000005006012776215007030676 0ustar kaikaimodule std.experimental.allocator.building_blocks.allocator_list; import std.experimental.allocator.common; import std.experimental.allocator.building_blocks.null_allocator; import std.experimental.allocator.gc_allocator; version(unittest) import std.stdio; // Turn this on for debugging // debug = allocator_list; /** Given an $(LUCKY object factory) of type `Factory` or a factory function `factoryFunction`, and optionally also `BookkeepingAllocator` as a supplemental allocator for bookkeeping, `AllocatorList` creates an allocator that lazily creates as many allocators are needed for satisfying client allocation requests. An embedded list builds a most-recently-used strategy: the most recent allocators used in calls to either `allocate`, `owns` (successful calls only), or `deallocate` are tried for new allocations in order of their most recent use. Thus, although core operations take in theory $(BIGOH k) time for $(D k) allocators in current use, in many workloads the factor is sublinear. Details of the actual strategy may change in future releases. `AllocatorList` is primarily intended for coarse-grained handling of allocators, i.e. the number of allocators in the list is expected to be relatively small compared to the number of allocations handled by each allocator. However, the per-allocator overhead is small so using `AllocatorList` with a large number of allocators should be satisfactory as long as the most-recently-used strategy is fast enough for the application. `AllocatorList` makes an effort to return allocated memory back when no longer used. It does so by destroying empty allocators. However, in order to avoid thrashing (excessive creation/destruction of allocators under certain use patterns), it keeps unused allocators for a while. Params: factoryFunction = A function or template function (including function literals). New allocators are created by calling `factoryFunction(n)` with strictly positive numbers `n`. Delegates that capture their enviroment are not created amid concerns regarding garbage creation for the environment. When the factory needs state, a `Factory` object should be used. BookkeepingAllocator = Allocator used for storing bookkeeping data. The size of bookkeeping data is proportional to the number of allocators. If $(D BookkeepingAllocator) is $(D NullAllocator), then $(D AllocatorList) is "ouroboros-style", i.e. it keeps the bookkeeping data in memory obtained from the allocators themselves. Note that for ouroboros-style management, the size $(D n) passed to $(D make) will be occasionally different from the size requested by client code. Factory = Type of a factory object that returns new allocators on a need basis. For an object $(D sweatshop) of type $(D Factory), `sweatshop(n)` should return an allocator able to allocate at least `n` bytes (i.e. `Factory` must define `opCall(size_t)` to return an allocator object). Usually the capacity of allocators created should be much larger than $(D n) such that an allocator can be used for many subsequent allocations. $(D n) is passed only to ensure the minimum necessary for the next allocation. The factory object is allowed to hold state, which will be stored inside `AllocatorList` as a direct `public` member called `factory`. */ struct AllocatorList(Factory, BookkeepingAllocator = GCAllocator) { import std.traits : hasMember; import std.conv : emplace; import std.algorithm : min, move; import std.experimental.allocator.building_blocks.stats_collector : StatsCollector, Options; private enum ouroboros = is(BookkeepingAllocator == NullAllocator); /** Alias for `typeof(Factory()(1))`, i.e. the type of the individual allocators. */ alias Allocator = typeof(Factory.init(1)); // Allocator used internally private alias SAllocator = StatsCollector!(Allocator, Options.bytesUsed); private static struct Node { // Allocator in this node SAllocator a; Node* next; @disable this(this); // Is this node unused? void setUnused() { next = &this; } bool unused() const { return next is &this; } // Just forward everything to the allocator alias a this; } /** If $(D BookkeepingAllocator) is not $(D NullAllocator), $(D bkalloc) is defined and accessible. */ // State is stored in an array, but it has a list threaded through it by // means of "nextIdx". // state { static if (!ouroboros) { static if (stateSize!BookkeepingAllocator) BookkeepingAllocator bkalloc; else alias bkalloc = BookkeepingAllocator.instance; } static if (stateSize!Factory) { Factory factory; } private Node[] allocators; private Node* root; // } static if (stateSize!Factory) { private auto make(size_t n) { return factory(n); } } else { private auto make(size_t n) { Factory f; return f(n); } } /** Constructs an `AllocatorList` given a factory object. This constructor is defined only if `Factory` has state. */ static if (stateSize!Factory) this(ref Factory plant) { factory = plant; } /// Ditto static if (stateSize!Factory) this(Factory plant) { factory = plant; } static if (hasMember!(Allocator, "deallocateAll") && hasMember!(Allocator, "owns")) ~this() { deallocateAll; } /** The alignment offered. */ enum uint alignment = Allocator.alignment; /** Allocate a block of size $(D s). First tries to allocate from the existing list of already-created allocators. If neither can satisfy the request, creates a new allocator by calling $(D make(s)) and delegates the request to it. However, if the allocation fresh off a newly created allocator fails, subsequent calls to $(D allocate) will not cause more calls to $(D make). */ void[] allocate(size_t s) { for (auto p = &root, n = *p; n; p = &n.next, n = *p) { auto result = n.allocate(s); if (result.length != s) continue; // Bring to front if not already if (root != n) { *p = n.next; n.next = root; root = n; return result; } } // Can't allocate from the current pool. Check if we just added a new // allocator, in that case it won't do any good to add yet another. if (root && root.empty == Ternary.yes) { // no can do return null; } // Add a new allocator if (auto a = addAllocator(s)) { auto result = a.allocate(s); assert(owns(result) == Ternary.yes || !result.ptr); return result; } return null; } private void moveAllocators(void[] newPlace) { assert(newPlace.ptr.alignedAt(Node.alignof)); assert(newPlace.length % Node.sizeof == 0); auto newAllocators = cast(Node[]) newPlace; assert(allocators.length <= newAllocators.length); // Move allocators foreach (i, ref e; allocators) { if (e.unused) { newAllocators[i].setUnused; continue; } import core.stdc.string : memcpy; memcpy(&newAllocators[i].a, &e.a, e.a.sizeof); if (e.next) { newAllocators[i].next = newAllocators.ptr + (e.next - allocators.ptr); } else { newAllocators[i].next = null; } } // Mark the unused portion as unused foreach (i; allocators.length .. newAllocators.length) { newAllocators[i].setUnused; } auto toFree = allocators; // Change state { root = newAllocators.ptr + (root - allocators.ptr); allocators = newAllocators; // } // Free the olden buffer static if (ouroboros) { static if (hasMember!(Allocator, "deallocate") && hasMember!(Allocator, "owns")) deallocate(toFree); } else { bkalloc.deallocate(toFree); } } static if (ouroboros) private Node* addAllocator(size_t atLeastBytes) { void[] t = allocators; static if (hasMember!(Allocator, "expand") && hasMember!(Allocator, "owns")) { immutable bool expanded = t && this.expand(t, Node.sizeof); } else { enum expanded = false; } if (expanded) { import std.c.string : memcpy; assert(t.length % Node.sizeof == 0); assert(t.ptr.alignedAt(Node.alignof)); allocators = cast(Node[]) t; allocators[$ - 1].setUnused; auto newAlloc = SAllocator(make(atLeastBytes)); memcpy(&allocators[$ - 1].a, &newAlloc, newAlloc.sizeof); emplace(&newAlloc); } else { immutable toAlloc = (allocators.length + 1) * Node.sizeof + atLeastBytes + 128; auto newAlloc = SAllocator(make(toAlloc)); auto newPlace = newAlloc.allocate( (allocators.length + 1) * Node.sizeof); if (!newPlace) return null; moveAllocators(newPlace); import core.stdc.string : memcpy; memcpy(&allocators[$ - 1].a, &newAlloc, newAlloc.sizeof); emplace(&newAlloc); assert(allocators[$ - 1].owns(allocators) == Ternary.yes); } // Insert as new root if (root != &allocators[$ - 1]) { allocators[$ - 1].next = root; root = &allocators[$ - 1]; } else { // This is the first one root.next = null; } assert(!root.unused); return root; } static if (!ouroboros) private Node* addAllocator(size_t atLeastBytes) { void[] t = allocators; static if (hasMember!(BookkeepingAllocator, "expand")) immutable bool expanded = bkalloc.expand(t, Node.sizeof); else immutable bool expanded = false; if (expanded) { assert(t.length % Node.sizeof == 0); assert(t.ptr.alignedAt(Node.alignof)); allocators = cast(Node[]) t; allocators[$ - 1].setUnused; } else { // Could not expand, create a new block t = bkalloc.allocate((allocators.length + 1) * Node.sizeof); assert(t.length % Node.sizeof == 0); if (!t.ptr) return null; moveAllocators(t); } assert(allocators[$ - 1].unused); auto newAlloc = SAllocator(make(atLeastBytes)); import core.stdc.string : memcpy; memcpy(&allocators[$ - 1].a, &newAlloc, newAlloc.sizeof); emplace(&newAlloc); // Creation succeeded, insert as root if (allocators.length == 1) allocators[$ - 1].next = null; else allocators[$ - 1].next = root; assert(allocators[$ - 1].a.bytesUsed == 0); root = &allocators[$ - 1]; return root; } /** Defined only if `Allocator` defines `owns`. Tries each allocator in turn, in most-recently-used order. If the owner is found, it is moved to the front of the list as a side effect under the assumption it will be used soon. Returns: `Ternary.yes` if one allocator was found to return `Ternary.yes`, `Ternary.no` if all component allocators returned `Ternary.no`, and `Ternary.unknown` if no allocator returned `Ternary.yes` and at least one returned `Ternary.unknown`. */ static if (hasMember!(Allocator, "owns")) Ternary owns(void[] b) { auto result = Ternary.no; for (auto p = &root, n = *p; n; p = &n.next, n = *p) { immutable t = n.owns(b); if (t != Ternary.yes) { if (t == Ternary.unknown) result = t; continue; } // Move the owner to front, speculating it'll be used if (n != root) { *p = n.next; n.next = root; root = n; } return Ternary.yes; } return result; } /** Defined only if $(D Allocator.expand) is defined. Finds the owner of $(D b) and calls $(D expand) for it. The owner is not brought to the head of the list. */ static if (hasMember!(Allocator, "expand") && hasMember!(Allocator, "owns")) bool expand(ref void[] b, size_t delta) { if (!b.ptr) { b = allocate(delta); return b.length == delta; } for (auto p = &root, n = *p; n; p = &n.next, n = *p) { if (n.owns(b) == Ternary.yes) return n.expand(b, delta); } return false; } /** Defined only if $(D Allocator.reallocate) is defined. Finds the owner of $(D b) and calls $(D reallocate) for it. If that fails, calls the global $(D reallocate), which allocates a new block and moves memory. */ static if (hasMember!(Allocator, "reallocate")) bool reallocate(ref void[] b, size_t s) { // First attempt to reallocate within the existing node if (!b.ptr) { b = allocate(s); return b.length == s; } for (auto p = &root, n = *p; n; p = &n.next, n = *p) { if (n.owns(b) == Ternary.yes) return n.reallocate(b, s); } // Failed, but we may find new memory in a new node. return .reallocate(this, b, s); } /** Defined if $(D Allocator.deallocate) and $(D Allocator.owns) are defined. */ static if (hasMember!(Allocator, "deallocate") && hasMember!(Allocator, "owns")) bool deallocate(void[] b) { if (!b.ptr) return true; assert(allocators.length); assert(owns(b) == Ternary.yes); bool result; for (auto p = &root, n = *p; ; p = &n.next, n = *p) { assert(n); if (n.owns(b) != Ternary.yes) continue; result = n.deallocate(b); // Bring to front if (n != root) { *p = n.next; n.next = root; root = n; } if (n.empty != Ternary.yes) return result; break; } // Hmmm... should we return this allocator back to the wild? Let's // decide if there are TWO empty allocators we can release ONE. This // is to avoid thrashing. // Note that loop starts from the second element. for (auto p = &root.next, n = *p; n; p = &n.next, n = *p) { if (n.unused || n.empty != Ternary.yes) continue; // Used and empty baby, nuke it! n.a.destroy; *p = n.next; n.setUnused; break; } return result; } /** Defined only if $(D Allocator.owns) and $(D Allocator.deallocateAll) are defined. */ static if (ouroboros && hasMember!(Allocator, "deallocateAll") && hasMember!(Allocator, "owns")) bool deallocateAll() { Node* special; foreach (ref n; allocators) { if (n.unused) continue; if (n.owns(allocators) == Ternary.yes) { special = &n; continue; } n.a.deallocateAll; n.a.destroy; } assert(special || !allocators.ptr); if (special) { special.deallocate(allocators); } allocators = null; root = null; return true; } static if (!ouroboros && hasMember!(Allocator, "deallocateAll") && hasMember!(Allocator, "owns")) bool deallocateAll() { foreach (ref n; allocators) { if (n.unused) continue; n.a.deallocateAll; n.a.destroy; } bkalloc.deallocate(allocators); allocators = null; root = null; return true; } /** Returns `Ternary.yes` if no allocators are currently active, `Ternary.no` otherwise. This methods never returns `Ternary.unknown`. */ Ternary empty() const { return Ternary(!allocators.length); } } /// Ditto template AllocatorList(alias factoryFunction, BookkeepingAllocator = GCAllocator) { alias A = typeof(factoryFunction(1)); static assert( // is a template function (including literals) is(typeof({A function(size_t) @system x = factoryFunction!size_t;})) || // or a function (including literals) is(typeof({A function(size_t) @system x = factoryFunction;})) , "Only function names and function literals that take size_t" ~ " and return an allocator are accepted, not " ~ typeof(factoryFunction).stringof ); static struct Factory { A opCall(size_t n) { return factoryFunction(n); } } alias AllocatorList = .AllocatorList!(Factory, BookkeepingAllocator); } /// version(Posix) unittest { import std.algorithm : max; import std.experimental.allocator.building_blocks.region : Region; import std.experimental.allocator.mmap_allocator : MmapAllocator; import std.experimental.allocator.building_blocks.segregator : Segregator; import std.experimental.allocator.building_blocks.free_list : ContiguousFreeList; // Ouroboros allocator list based upon 4MB regions, fetched directly from // mmap. All memory is released upon destruction. alias A1 = AllocatorList!((n) => Region!MmapAllocator(max(n, 1024 * 4096)), NullAllocator); // Allocator list based upon 4MB regions, fetched from the garbage // collector. All memory is released upon destruction. alias A2 = AllocatorList!((n) => Region!GCAllocator(max(n, 1024 * 4096))); // Ouroboros allocator list based upon 4MB regions, fetched from the garbage // collector. Memory is left to the collector. alias A3 = AllocatorList!( (n) => Region!NullAllocator(new void[max(n, 1024 * 4096)]), NullAllocator); // Allocator list that creates one freelist for all objects alias A4 = Segregator!( 64, AllocatorList!( (n) => ContiguousFreeList!(NullAllocator, 0, 64)( GCAllocator.instance.allocate(4096))), GCAllocator); A4 a; auto small = a.allocate(64); assert(small); a.deallocate(small); auto b1 = a.allocate(1024 * 8192); assert(b1 !is null); // still works due to overdimensioning b1 = a.allocate(1024 * 10); assert(b1.length == 1024 * 10); } unittest { // Create an allocator based upon 4MB regions, fetched from the GC heap. import std.algorithm : max; import std.experimental.allocator.building_blocks.region : Region; AllocatorList!((n) => Region!GCAllocator(new void[max(n, 1024 * 4096)]), NullAllocator) a; const b1 = a.allocate(1024 * 8192); assert(b1 !is null); // still works due to overdimensioning const b2 = a.allocate(1024 * 10); assert(b2.length == 1024 * 10); a.deallocateAll(); } unittest { // Create an allocator based upon 4MB regions, fetched from the GC heap. import std.algorithm : max; import std.experimental.allocator.building_blocks.region : Region; AllocatorList!((n) => Region!()(new void[max(n, 1024 * 4096)])) a; auto b1 = a.allocate(1024 * 8192); assert(b1 !is null); // still works due to overdimensioning b1 = a.allocate(1024 * 10); assert(b1.length == 1024 * 10); a.deallocateAll(); } unittest { import std.algorithm : max; import std.experimental.allocator.building_blocks.region : Region; AllocatorList!((n) => Region!()(new void[max(n, 1024 * 4096)])) a; auto b1 = a.allocate(1024 * 8192); assert(b1 !is null); b1 = a.allocate(1024 * 10); assert(b1.length == 1024 * 10); a.allocate(1024 * 4095); a.deallocateAll(); assert(a.empty == Ternary.yes); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/region.d0000664000175000017500000006130112776215007027146 0ustar kaikaimodule std.experimental.allocator.building_blocks.region; import std.experimental.allocator.common; import std.experimental.allocator.building_blocks.null_allocator; import std.typecons : Flag, Yes, No; /** A $(D Region) allocator allocates memory straight from one contiguous chunk. There is no deallocation, and once the region is full, allocation requests return $(D null). Therefore, $(D Region)s are often used (a) in conjunction with more sophisticated allocators; or (b) for batch-style very fast allocations that deallocate everything at once. The region only stores three pointers, corresponding to the current position in the store and the limits. One allocation entails rounding up the allocation size for alignment purposes, bumping the current pointer, and comparing it against the limit. If $(D ParentAllocator) is different from $(D NullAllocator), $(D Region) deallocates the chunk of memory during destruction. The $(D minAlign) parameter establishes alignment. If $(D minAlign > 1), the sizes of all allocation requests are rounded up to a multiple of $(D minAlign). Applications aiming at maximum speed may want to choose $(D minAlign = 1) and control alignment externally. */ struct Region(ParentAllocator = NullAllocator, uint minAlign = platformAlignment, Flag!"growDownwards" growDownwards = No.growDownwards) { static assert(minAlign.isGoodStaticAlignment); static assert(ParentAllocator.alignment >= minAlign); import std.traits : hasMember; // state { /** The _parent allocator. Depending on whether $(D ParentAllocator) holds state or not, this is a member variable or an alias for `ParentAllocator.instance`. */ static if (stateSize!ParentAllocator) { ParentAllocator parent; } else { alias parent = ParentAllocator.instance; } private void* _current, _begin, _end; // } /** Constructs a region backed by a user-provided store. Assumes $(D store) is aligned at $(D minAlign). Also assumes the memory was allocated with $(D ParentAllocator) (if different from $(D NullAllocator)). Params: store = User-provided store backing up the region. $(D store) must be aligned at $(D minAlign) (enforced with $(D assert)). If $(D ParentAllocator) is different from $(D NullAllocator), memory is assumed to have been allocated with $(D ParentAllocator). n = Bytes to allocate using $(D ParentAllocator). This constructor is only defined If $(D ParentAllocator) is different from $(D NullAllocator). If $(D parent.allocate(n)) returns $(D null), the region will be initialized as empty (correctly initialized but unable to allocate). */ this(void[] store) { store = store.roundUpToAlignment(alignment); store = store[0 .. $.roundDownToAlignment(alignment)]; assert(store.ptr.alignedAt(minAlign)); assert(store.length % minAlign == 0); _begin = store.ptr; _end = store.ptr + store.length; static if (growDownwards) _current = _end; else _current = store.ptr; } /// Ditto static if (!is(ParentAllocator == NullAllocator)) this(size_t n) { this(parent.allocate(n.roundUpToAlignment(alignment))); } /* TODO: The postblit of $(D BasicRegion) is disabled because such objects should not be copied around naively. */ //@disable this(this); /** If `ParentAllocator` is not `NullAllocator` and defines `deallocate`, the region defines a destructor that uses `ParentAllocator.delete` to free the memory chunk. */ static if (!is(ParentAllocator == NullAllocator) && hasMember!(ParentAllocator, "deallocate")) ~this() { parent.deallocate(_begin[0 .. _end - _begin]); } /** Alignment offered. */ alias alignment = minAlign; /** Allocates $(D n) bytes of memory. The shortest path involves an alignment adjustment (if $(D alignment > 1)), an increment, and a comparison. Params: n = number of bytes to allocate Returns: A properly-aligned buffer of size $(D n) or $(D null) if request could not be satisfied. */ void[] allocate(size_t n) { static if (growDownwards) { if (available < n) return null; static if (minAlign > 1) const rounded = n.roundUpToAlignment(alignment); else alias rounded = n; assert(available >= rounded); auto result = (_current - rounded)[0 .. n]; assert(result.ptr >= _begin); _current = result.ptr; assert(owns(result) == Ternary.yes); return result; } else { auto result = _current[0 .. n]; static if (minAlign > 1) const rounded = n.roundUpToAlignment(alignment); else alias rounded = n; _current += rounded; if (_current <= _end) return result; // Slow path, backtrack _current -= rounded; return null; } } /** Allocates $(D n) bytes of memory aligned at alignment $(D a). Params: n = number of bytes to allocate a = alignment for the allocated block Returns: Either a suitable block of $(D n) bytes aligned at $(D a), or $(D null). */ void[] alignedAllocate(size_t n, uint a) { assert(a.isPowerOf2); static if (growDownwards) { const available = _current - _begin; if (available < n) return null; auto result = (_current - n).alignDownTo(a)[0 .. n]; if (result.ptr >= _begin) { _current = result.ptr; return result; } } else { // Just bump the pointer to the next good allocation auto save = _current; _current = _current.alignUpTo(a); auto result = allocate(n); if (result.ptr) { assert(result.length == n); return result; } // Failed, rollback _current = save; } return null; } /// Allocates and returns all memory available to this region. void[] allocateAll() { static if (growDownwards) { auto result = _begin[0 .. available]; _current = _begin; } else { auto result = _current[0 .. available]; _current = _end; } return result; } /** Expands an allocated block in place. Expansion will succeed only if the block is the last allocated. Defined only if `growDownwards` is `No.growDownwards`. */ static if (growDownwards == No.growDownwards) bool expand(ref void[] b, size_t delta) { assert(owns(b) == Ternary.yes || b.ptr is null); assert(b.ptr + b.length <= _current || b.ptr is null); if (!b.ptr) { b = allocate(delta); return b.length == delta; } auto newLength = b.length + delta; if (_current < b.ptr + b.length + alignment) { // This was the last allocation! Allocate some more and we're done. if (this.goodAllocSize(b.length) == this.goodAllocSize(newLength) || allocate(delta).length == delta) { b = b.ptr[0 .. newLength]; assert(_current < b.ptr + b.length + alignment); return true; } } return false; } /** Deallocates $(D b). This works only if $(D b) was obtained as the last call to $(D allocate); otherwise (i.e. another allocation has occurred since) it does nothing. This semantics is tricky and therefore $(D deallocate) is defined only if $(D Region) is instantiated with $(D Yes.defineDeallocate) as the third template argument. Params: b = Block previously obtained by a call to $(D allocate) against this allocator ($(D null) is allowed). */ bool deallocate(void[] b) { assert(owns(b) == Ternary.yes || b.ptr is null); static if (growDownwards) { if (b.ptr == _current) { _current += this.goodAllocSize(b.length); return true; } } else { if (b.ptr + this.goodAllocSize(b.length) == _current) { assert(b.ptr !is null || _current is null); _current = b.ptr; return true; } } return false; } /** Deallocates all memory allocated by this region, which can be subsequently reused for new allocations. */ bool deallocateAll() { static if (growDownwards) { _current = _end; } else { _current = _begin; } return true; } /** Queries whether $(D b) has been allocated with this region. Params: b = Arbitrary block of memory ($(D null) is allowed; $(D owns(null)) returns $(D false)). Returns: $(D true) if $(D b) has been allocated with this region, $(D false) otherwise. */ Ternary owns(void[] b) const { return Ternary(b.ptr >= _begin && b.ptr + b.length <= _end); } /** Returns `Ternary.yes` if no memory has been allocated in this region, `Ternary.no` otherwise. (Never returns `Ternary.unknown`.) */ Ternary empty() const { return Ternary(_current == _begin); } /// Nonstandard property that returns bytes available for allocation. size_t available() const { static if (growDownwards) { return _current - _begin; } else { return _end - _current; } } } /// unittest { import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; import std.algorithm : max; // Create a scalable list of regions. Each gets at least 1MB at a time by // using malloc. auto batchAllocator = AllocatorList!( (size_t n) => Region!Mallocator(max(n, 1024 * 1024)) )(); auto b = batchAllocator.allocate(101); assert(b.length == 101); // This will cause a second allocation b = batchAllocator.allocate(2 * 1024 * 1024); assert(b.length == 2 * 1024 * 1024); // Destructor will free the memory } unittest { import std.experimental.allocator.mallocator : Mallocator; // Create a 64 KB region allocated with malloc auto reg = Region!(Mallocator, Mallocator.alignment, Yes.growDownwards)(1024 * 64); const b = reg.allocate(101); assert(b.length == 101); // Destructor will free the memory } /** $(D InSituRegion) is a convenient region that carries its storage within itself (in the form of a statically-sized array). The first template argument is the size of the region and the second is the needed alignment. Depending on the alignment requested and platform details, the actual available storage may be smaller than the compile-time parameter. To make sure that at least $(D n) bytes are available in the region, use $(D InSituRegion!(n + a - 1, a)). Given that the most frequent use of `InSituRegion` is as a stack allocator, it allocates starting at the end on systems where stack grows downwards, such that hot memory is used first. */ struct InSituRegion(size_t size, size_t minAlign = platformAlignment) { import std.algorithm : max; import std.conv : to; import std.traits : hasMember; static assert(minAlign.isGoodStaticAlignment); static assert(size >= minAlign); version (X86) enum growDownwards = Yes.growDownwards; else version (X86_64) enum growDownwards = Yes.growDownwards; else version (ARM) enum growDownwards = Yes.growDownwards; else version (AArch64) enum growDownwards = Yes.growDownwards; else version (PPC) enum growDownwards = Yes.growDownwards; else version (PPC64) enum growDownwards = Yes.growDownwards; else version (MIPS) enum growDownwards = Yes.growDownwards; else version (MIPS64) enum growDownwards = Yes.growDownwards; else version (SPARC) enum growDownwards = Yes.growDownwards; else version (SystemZ) enum growDownwards = Yes.growDownwards; else static assert(0, "Dunno how the stack grows on this architecture."); @disable this(this); // state { private Region!(NullAllocator, minAlign, growDownwards) _impl; union { private ubyte[size] _store = void; private double _forAlignmentOnly1 = void; } // } /** An alias for $(D minAlign), which must be a valid alignment (nonzero power of 2). The start of the region and all allocation requests will be rounded up to a multiple of the alignment. ---- InSituRegion!(4096) a1; assert(a1.alignment == platformAlignment); InSituRegion!(4096, 64) a2; assert(a2.alignment == 64); ---- */ alias alignment = minAlign; private void lazyInit() { assert(!_impl._current); //static if (alignment > double.alignof) //{ // auto p = _store.ptr.alignUpTo(alignment); //} //else // auto p = _store.ptr; _impl = typeof(_impl)(_store); assert(_impl._current.alignedAt(alignment)); } /** Allocates $(D bytes) and returns them, or $(D null) if the region cannot accommodate the request. For efficiency reasons, if $(D bytes == 0) the function returns an empty non-null slice. */ void[] allocate(size_t n) { // Fast path entry: auto result = _impl.allocate(n); if (result.length == n) return result; // Slow path if (_impl._current) return null; // no more room lazyInit; assert(_impl._current); goto entry; } /** As above, but the memory allocated is aligned at $(D a) bytes. */ void[] alignedAllocate(size_t n, uint a) { // Fast path entry: auto result = _impl.alignedAllocate(n, a); if (result.length == n) return result; // Slow path if (_impl._current) return null; // no more room lazyInit; assert(_impl._current); goto entry; } /** Deallocates $(D b). This works only if $(D b) was obtained as the last call to $(D allocate); otherwise (i.e. another allocation has occurred since) it does nothing. This semantics is tricky and therefore $(D deallocate) is defined only if $(D Region) is instantiated with $(D Yes.defineDeallocate) as the third template argument. Params: b = Block previously obtained by a call to $(D allocate) against this allocator ($(D null) is allowed). */ bool deallocate(void[] b) { if (!_impl._current) return b is null; return _impl.deallocate(b); } /** Returns `Ternary.yes` if `b` is the result of a previous allocation, `Ternary.no` otherwise. */ Ternary owns(void[] b) { if (!_impl._current) return Ternary.no; return _impl.owns(b); } /** Expands an allocated block in place. Expansion will succeed only if the block is the last allocated. */ static if (hasMember!(typeof(_impl), "expand")) bool expand(ref void[] b, size_t delta) { if (!_impl._current) lazyInit; return _impl.expand(b, delta); } /** Deallocates all memory allocated with this allocator. */ bool deallocateAll() { // We don't care to lazily init the region return _impl.deallocateAll; } /** Allocates all memory available with this allocator. */ void[] allocateAll() { if (!_impl._current) lazyInit; return _impl.allocateAll; } /** Nonstandard function that returns the bytes available for allocation. */ size_t available() { if (!_impl._current) lazyInit; return _impl.available; } } /// unittest { // 128KB region, allocated to x86's cache line InSituRegion!(128 * 1024, 16) r1; auto a1 = r1.allocate(101); assert(a1.length == 101); // 128KB region, with fallback to the garbage collector. import std.experimental.allocator.building_blocks.fallback_allocator : FallbackAllocator; import std.experimental.allocator.building_blocks.free_list : FreeList; import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock; FallbackAllocator!(InSituRegion!(128 * 1024), GCAllocator) r2; const a2 = r2.allocate(102); assert(a2.length == 102); // Reap with GC fallback. InSituRegion!(128 * 1024, 8) tmp3; FallbackAllocator!(BitmappedBlock!(64, 8), GCAllocator) r3; r3.primary = BitmappedBlock!(64, 8)(tmp3.allocateAll()); const a3 = r3.allocate(103); assert(a3.length == 103); // Reap/GC with a freelist for small objects up to 16 bytes. InSituRegion!(128 * 1024, 64) tmp4; FreeList!(FallbackAllocator!(BitmappedBlock!(64, 64), GCAllocator), 0, 16) r4; r4.parent.primary = BitmappedBlock!(64, 64)(tmp4.allocateAll()); const a4 = r4.allocate(104); assert(a4.length == 104); } unittest { InSituRegion!(4096, 1) r1; auto a = r1.allocate(2001); assert(a.length == 2001); import std.conv : text; assert(r1.available == 2095, text(r1.available)); InSituRegion!(65_536, 1024*4) r2; assert(r2.available <= 65_536); a = r2.allocate(2001); assert(a.length == 2001); } private extern(C) void* sbrk(long); private extern(C) int brk(shared void*); /** Allocator backed by $(D $(LUCKY sbrk)) for Posix systems. Due to the fact that $(D sbrk) is not thread-safe $(WEB lifecs.likai.org/2010/02/sbrk-is-not-thread- safe.html, by design), $(D SbrkRegion) uses a mutex internally. This implies that uncontrolled calls to $(D brk) and $(D sbrk) may affect the workings of $(D SbrkRegion) adversely. */ version(Posix) struct SbrkRegion(uint minAlign = platformAlignment) { private import core.sys.posix.pthread : pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_t, pthread_mutex_lock, pthread_mutex_unlock, PTHREAD_MUTEX_INITIALIZER; private static shared pthread_mutex_t sbrkMutex = PTHREAD_MUTEX_INITIALIZER; // workaround for https://issues.dlang.org/show_bug.cgi?id=14617 version(OSX) { shared static this() { pthread_mutex_init(cast(pthread_mutex_t*) &sbrkMutex, null) == 0 || assert(0); } shared static ~this() { pthread_mutex_destroy(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); } } static assert(minAlign.isGoodStaticAlignment); static assert(size_t.sizeof == (void*).sizeof); private shared void* _brkInitial, _brkCurrent; /** Instance shared by all callers. */ static shared SbrkRegion instance; /** Standard allocator primitives. */ enum uint alignment = minAlign; /// Ditto void[] allocate(size_t bytes) shared { static if (minAlign > 1) const rounded = bytes.roundUpToMultipleOf(alignment); else alias rounded = bytes; pthread_mutex_lock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); scope(exit) pthread_mutex_unlock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); // Assume sbrk returns the old break. Most online documentation confirms // that, except for http://www.inf.udec.cl/~leo/Malloc_tutorial.pdf, // which claims the returned value is not portable. auto p = sbrk(rounded); if (p == cast(void*) -1) { return null; } if (!_brkInitial) { _brkInitial = cast(shared) p; assert(cast(size_t) _brkInitial % minAlign == 0, "Too large alignment chosen for " ~ typeof(this).stringof); } _brkCurrent = cast(shared) (p + rounded); return p[0 .. bytes]; } /// Ditto void[] alignedAllocate(size_t bytes, uint a) shared { pthread_mutex_lock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); scope(exit) pthread_mutex_unlock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); if (!_brkInitial) { // This is one extra call, but it'll happen only once. _brkInitial = cast(shared) sbrk(0); assert(cast(size_t) _brkInitial % minAlign == 0, "Too large alignment chosen for " ~ typeof(this).stringof); (_brkInitial != cast(void*) -1) || assert(0); _brkCurrent = _brkInitial; } immutable size_t delta = cast(shared void*) roundUpToMultipleOf( cast(size_t) _brkCurrent, a) - _brkCurrent; // Still must make sure the total size is aligned to the allocator's // alignment. immutable rounded = (bytes + delta).roundUpToMultipleOf(alignment); auto p = sbrk(rounded); if (p == cast(void*) -1) { return null; } _brkCurrent = cast(shared) (p + rounded); return p[delta .. delta + bytes]; } /** The $(D expand) method may only succeed if the argument is the last block allocated. In that case, $(D expand) attempts to push the break pointer to the right. */ bool expand(ref void[] b, size_t delta) shared { if (b is null) return (b = allocate(delta)) !is null; assert(_brkInitial && _brkCurrent); // otherwise where did b come from? pthread_mutex_lock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); scope(exit) pthread_mutex_unlock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); if (_brkCurrent != b.ptr + b.length) return false; // Great, can expand the last block static if (minAlign > 1) const rounded = delta.roundUpToMultipleOf(alignment); else alias rounded = bytes; auto p = sbrk(rounded); if (p == cast(void*) -1) { return false; } _brkCurrent = cast(shared) (p + rounded); b = b.ptr[0 .. b.length + delta]; return true; } /// Ditto Ternary owns(void[] b) shared { // No need to lock here. assert(!_brkCurrent || b.ptr + b.length <= _brkCurrent); return Ternary(_brkInitial && b.ptr >= _brkInitial); } /** The $(D deallocate) method only works (and returns $(D true)) on systems that support reducing the break address (i.e. accept calls to $(D sbrk) with negative offsets). OSX does not accept such. In addition the argument must be the last block allocated. */ bool deallocate(void[] b) shared { static if (minAlign > 1) const rounded = b.length.roundUpToMultipleOf(alignment); else const rounded = b.length; pthread_mutex_lock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); scope(exit) pthread_mutex_unlock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); if (_brkCurrent != b.ptr + rounded) return false; assert(b.ptr >= _brkInitial); if (sbrk(-rounded) == cast(void*) -1) return false; _brkCurrent = cast(shared) b.ptr; return true; } /** The $(D deallocateAll) method only works (and returns $(D true)) on systems that support reducing the break address (i.e. accept calls to $(D sbrk) with negative offsets). OSX does not accept such. */ bool deallocateAll() shared { pthread_mutex_lock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); scope(exit) pthread_mutex_unlock(cast(pthread_mutex_t*) &sbrkMutex) == 0 || assert(0); return !_brkInitial || brk(_brkInitial) == 0; } /// Standard allocator API. Ternary empty() { // Also works when they're both null. return Ternary(_brkCurrent == _brkInitial); } } version(Posix) unittest { // Let's test the assumption that sbrk(n) returns the old address const p1 = sbrk(0); const p2 = sbrk(4096); assert(p1 == p2); const p3 = sbrk(0); assert(p3 == p2 + 4096); // Try to reset brk, but don't make a fuss if it doesn't work sbrk(-4096); } version(Posix) unittest { alias alloc = SbrkRegion!(8).instance; auto a = alloc.alignedAllocate(2001, 4096); assert(a.length == 2001); auto b = alloc.allocate(2001); assert(b.length == 2001); assert(alloc.owns(a) == Ternary.yes); assert(alloc.owns(b) == Ternary.yes); // reducing the brk does not work on OSX version(OSX) {} else { assert(alloc.deallocate(b)); assert(alloc.deallocateAll); } } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/package.d0000664000175000017500000004017712776215007027266 0ustar kaikai/** $(H2 Assembling Your Own Allocator) In addition to defining the interfaces above, this package also implements untyped composable memory allocators. They are $(I untyped) because they deal exclusively in $(D void[]) and have no notion of what type the memory allocated would be destined for. They are $(I composable) because the included allocators are building blocks that can be assembled in complex nontrivial allocators. $(P Unlike the allocators for the C and C++ programming languages, which manage the allocated size internally, these allocators require that the client maintains (or knows $(I a priori)) the allocation size for each piece of memory allocated. Put simply, the client must pass the allocated size upon deallocation. Storing the size in the _allocator has significant negative performance implications, and is virtually always redundant because client code needs knowledge of the allocated size in order to avoid buffer overruns. (See more discussion in a $(WEB open- std.org/JTC1/SC22/WG21/docs/papers/2013/n3536.html, proposal) for sized deallocation in C++.) For this reason, allocators herein traffic in $(D void[]) as opposed to $(D void*).) $(P In order to be usable as an _allocator, a type should implement the following methods with their respective semantics. Only $(D alignment) and $(D allocate) are required. If any of the other methods is missing, the _allocator is assumed to not have that capability (for example some allocators do not offer manual deallocation of memory). Allocators should NOT implement unsupported methods to always fail. For example, an allocator that lacks the capability to implement `alignedAllocate` should not define it at all (as opposed to defining it to always return `null` or throw an exception). The missing implementation statically informs other components about the allocator's capabilities and allows them to make design decisions accordingly.) $(BOOKTABLE , $(TR $(TH Method name) $(TH Semantics)) $(TR $(TDC uint alignment;, $(POST $(RES) > 0)) $(TD Returns the minimum alignment of all data returned by the allocator. An allocator may implement $(D alignment) as a statically-known $(D enum) value only. Applications that need dynamically-chosen alignment values should use the $(D alignedAllocate) and $(D alignedReallocate) APIs.)) $(TR $(TDC size_t goodAllocSize(size_t n);, $(POST $(RES) >= n)) $(TD Allocators customarily allocate memory in discretely-sized chunks. Therefore, a request for $(D n) bytes may result in a larger allocation. The extra memory allocated goes unused and adds to the so-called $(WEB goo.gl/YoKffF,internal fragmentation). The function $(D goodAllocSize(n)) returns the actual number of bytes that would be allocated upon a request for $(D n) bytes. This module defines a default implementation that returns $(D n) rounded up to a multiple of the allocator's alignment.)) $(TR $(TDC void[] allocate(size_t s);, $(POST $(RES) is null || $(RES).length == s)) $(TD If $(D s == 0), the call may return any empty slice (including $(D null)). Otherwise, the call allocates $(D s) bytes of memory and returns the allocated block, or $(D null) if the request could not be satisfied.)) $(TR $(TDC void[] alignedAllocate(size_t s, uint a);, $(POST $(RES) is null || $(RES).length == s)) $(TD Similar to `allocate`, with the additional guarantee that the memory returned is aligned to at least `a` bytes. `a` must be a power of 2.)) $(TR $(TDC void[] allocateAll();) $(TD Offers all of allocator's memory to the caller, so it's usually defined by fixed-size allocators. If the allocator is currently NOT managing any memory, then $(D allocateAll()) shall allocate and return all memory available to the allocator, and subsequent calls to all allocation primitives should not succeed (e..g $(D allocate) shall return $(D null) etc). Otherwise, $(D allocateAll) only works on a best-effort basis, and the allocator is allowed to return $(D null) even if does have available memory. Memory allocated with $(D allocateAll) is not otherwise special (e.g. can be reallocated or deallocated with the usual primitives, if defined).)) $(TR $(TDC bool expand(ref void[] b, size_t delta);, $(POST !$(RES) || b.length == $(I old)(b).length + delta)) $(TD Expands $(D b) by $(D delta) bytes. If $(D delta == 0), succeeds without changing $(D b). If $(D b is null), the call evaluates $(D b = allocate(delta)) and returns $(D b !is null). Otherwise, $(D b) must be a buffer previously allocated with the same allocator. If expansion was successful, $(D expand) changes $(D b)'s length to $(D b.length + delta) and returns $(D true). Upon failure, the call effects no change upon the allocator object, leaves $(D b) unchanged, and returns $(D false).)) $(TR $(TDC bool reallocate(ref void[] b, size_t s);, $(POST !$(RES) || b.length == s)) $(TD Reallocates $(D b) to size $(D s), possibly moving memory around. $(D b) must be $(D null) or a buffer allocated with the same allocator. If reallocation was successful, $(D reallocate) changes $(D b) appropriately and returns $(D true). Upon failure, the call effects no change upon the allocator object, leaves $(D b) unchanged, and returns $(D false). An allocator should implement $(D reallocate) if it can derive some advantage from doing so; otherwise, this module defines a $(D reallocate) free function implemented in terms of $(D expand), $(D allocate), and $(D deallocate).)) $(TR $(TDC bool alignedReallocate(ref void[] b,$(BR) size_t s, uint a);, $(POST !$(RES) || b.length == s)) $(TD Similar to $(D reallocate), but guarantees the reallocated memory is aligned at $(D a) bytes. The buffer must have been originated with a call to $(D alignedAllocate). $(D a) must be a power of 2 greater than $(D (void*).sizeof). An allocator should implement $(D alignedReallocate) if it can derive some advantage from doing so; otherwise, this module defines a $(D alignedReallocate) free function implemented in terms of $(D expand), $(D alignedAllocate), and $(D deallocate).)) $(TR $(TDC Ternary owns(void[] b);) $(TD Returns `Ternary.yes` if `b` has been allocated with this allocator. An allocator should define this method only if it can decide on ownership precisely and fast (in constant time, logarithmic time, or linear time with a low multiplication factor). Traditional allocators such as the C heap do not define such functionality. If $(D b is null), the allocator shall return `Ternary.no`, i.e. no allocator owns the `null` slice.)) $(TR $(TDC void[] resolveInternalPointer(void* p);) $(TD If $(D p) is a pointer somewhere inside a block allocated with this allocator, returns a pointer to the beginning of the allocated block. Otherwise, returns $(D null). If the pointer points immediately after an allocated block, the result is implementation defined.)) $(TR $(TDC bool deallocate(void[] b);) $(TD If $(D b is null), does nothing and returns `true`. Otherwise, deallocates memory previously allocated with this allocator and returns `true` if successful, `false` otherwise. An implementation that would not support deallocation (i.e. would always return `false` should not define this primitive at all.))) $(TR $(TDC bool deallocateAll();, $(POST empty)) $(TD Deallocates all memory allocated with this allocator. If an allocator implements this method, it must specify whether its destructor calls it, too.)) $(TR $(TDC Ternary empty();) $(TD Returns `Ternary.yes` if and only if the allocator holds no memory (i.e. no allocation has occurred, or all allocations have been deallocated).)) $(TR $(TDC static Allocator instance;, $(POST instance $(I is a valid) Allocator $(I object))) $(TD Some allocators are $(I monostate), i.e. have only an instance and hold only global state. (Notable examples are C's own `malloc`-based allocator and D's garbage-collected heap.) Such allocators must define a static $(D instance) instance that serves as the symbolic placeholder for the global instance of the allocator. An allocator should not hold state and define `instance` simultaneously. Depending on whether the allocator is thread-safe or not, this instance may be $(D shared).)) ) $(H2 Sample Assembly) The example below features an _allocator modeled after $(WEB goo.gl/m7329l, jemalloc), which uses a battery of free-list allocators spaced so as to keep internal fragmentation to a minimum. The $(D FList) definitions specify no bounds for the freelist because the $(D Segregator) does all size selection in advance. Sizes through 3584 bytes are handled via freelists of staggered sizes. Sizes from 3585 bytes through 4072 KB are handled by a $(D BitmappedBlock) with a block size of 4 KB. Sizes above that are passed direct to the $(D Mallocator). ---- alias FList = FreeList!(GCAllocator, 0, unbounded); alias A = Segregator!( 8, FreeList!(GCAllocator, 0, 8), 128, Bucketizer!(FList, 1, 128, 16), 256, Bucketizer!(FList, 129, 256, 32), 512, Bucketizer!(FList, 257, 512, 64), 1024, Bucketizer!(FList, 513, 1024, 128), 2048, Bucketizer!(FList, 1025, 2048, 256), 3584, Bucketizer!(FList, 2049, 3584, 512), 4072 * 1024, AllocatorList!( () => BitmappedBlock!(GCAllocator, 4096)(4072 * 1024)), GCAllocator ); A tuMalloc; auto b = tuMalloc.allocate(500); assert(b.length == 500); auto c = tuMalloc.allocate(113); assert(c.length == 113); assert(tuMalloc.expand(c, 14)); tuMalloc.deallocate(b); tuMalloc.deallocate(c); ---- $(H2 Allocating memory for sharing across threads) One allocation pattern used in multithreaded applications is to share memory across threads, and to deallocate blocks in a different thread than the one that allocated it. All allocators in this module accept and return $(D void[]) (as opposed to $(D shared void[])). This is because at the time of allocation, deallocation, or reallocation, the memory is effectively not $(D shared) (if it were, it would reveal a bug at the application level). The issue remains of calling $(D a.deallocate(b)) from a different thread than the one that allocated $(D b). It follows that both threads must have access to the same instance $(D a) of the respective allocator type. By definition of D, this is possible only if $(D a) has the $(D shared) qualifier. It follows that the allocator type must implement $(D allocate) and $(D deallocate) as $(D shared) methods. That way, the allocator commits to allowing usable $(D shared) instances. Conversely, allocating memory with one non-$(D shared) allocator, passing it across threads (by casting the obtained buffer to $(D shared)), and later deallocating it in a different thread (either with a different allocator object or with the same allocator object after casting it to $(D shared)) is illegal. $(H2 Building Blocks) $(P The table below gives a synopsis of predefined allocator building blocks, with their respective modules. Either `import` the needed modules individually, or `import` `std.experimental.building_blocks`, which imports them all `public`ly. The building blocks can be assembled in unbounded ways and also combined with your own. For a collection of typical and useful preassembled allocators and for inspiration in defining more such assemblies, refer to $(LINK2 std_experimental_allocator_showcase.html, `std.experimental.allocator.building_blocks.showcase`).) $(BOOKTABLE, $(TR $(TH Allocator$(BR)) $(TH Description)) $(TR $(TDC2 NullAllocator, null_allocator) $(TD Very good at doing absolutely nothing. A good starting point for defining other allocators or for studying the API.)) $(TR $(TDC3 GCAllocator, gc_allocator) $(TD The system-provided garbage-collector allocator. This should be the default fallback allocator tapping into system memory. It offers manual $(D free) and dutifully collects litter.)) $(TR $(TDC3 Mallocator, mallocator) $(TD The C heap _allocator, a.k.a. $(D malloc)/$(D realloc)/$(D free). Use sparingly and only for code that is unlikely to leak.)) $(TR $(TDC3 AlignedMallocator, mallocator) $(TD Interface to OS-specific _allocators that support specifying alignment: $(WEB man7.org/linux/man-pages/man3/posix_memalign.3.html, $(D posix_memalign)) on Posix and $(WEB msdn.microsoft.com/en-us/library/fs9stz4e(v=vs.80).aspx, $(D __aligned_xxx)) on Windows.)) $(TR $(TDC2 AffixAllocator, affix_allocator) $(TD Allocator that allows and manages allocating extra prefix and/or a suffix bytes for each block allocated.)) $(TR $(TDC2 BitmappedBlock, bitmapped_block) $(TD Organizes one contiguous chunk of memory in equal-size blocks and tracks allocation status at the cost of one bit per block.)) $(TR $(TDC2 FallbackAllocator, fallback_allocator) $(TD Allocator that combines two other allocators - primary and fallback. Allocation requests are first tried with primary, and upon failure are passed to the fallback. Useful for small and fast allocators fronting general-purpose ones.)) $(TR $(TDC2 FreeList, free_list) $(TD Allocator that implements a $(WEB wikipedia.org/wiki/Free_list, free list) on top of any other allocator. The preferred size, tolerance, and maximum elements are configurable at compile- and run time.)) $(TR $(TDC2 SharedFreeList, free_list) $(TD Same features as $(D FreeList), but packaged as a $(D shared) structure that is accessible to several threads.)) $(TR $(TDC2 FreeTree, free_tree) $(TD Allocator similar to $(D FreeList) that uses a binary search tree to adaptively store not one, but many free lists.)) $(TR $(TDC2 Region, region) $(TD Region allocator organizes a chunk of memory as a simple bump-the-pointer allocator.)) $(TR $(TDC2 InSituRegion, region) $(TD Region holding its own allocation, most often on the stack. Has statically-determined size.)) $(TR $(TDC2 SbrkRegion, region) $(TD Region using $(D $(LUCKY sbrk)) for allocating memory.)) $(TR $(TDC3 MmapAllocator, mmap_allocator) $(TD Allocator using $(D $(LUCKY mmap)) directly.)) $(TR $(TDC2 StatsCollector, stats_collector) $(TD Collect statistics about any other allocator.)) $(TR $(TDC2 Quantizer, quantizer) $(TD Allocates in coarse-grained quantas, thus improving performance of reallocations by often reallocating in place. The drawback is higher memory consumption because of allocated and unused memory.)) $(TR $(TDC2 AllocatorList, allocator_list) $(TD Given an allocator factory, lazily creates as many allocators as needed to satisfy allocation requests. The allocators are stored in a linked list. Requests for allocation are satisfied by searching the list in a linear manner.)) $(TR $(TDC2 Segregator, segregator) $(TD Segregates allocation requests by size and dispatches them to distinct allocators.)) $(TR $(TDC2 Bucketizer, bucketizer) $(TD Divides allocation sizes in discrete buckets and uses an array of allocators, one per bucket, to satisfy requests.)) $(COMMENT $(TR $(TDC2 InternalPointersTree) $(TD Adds support for resolving internal pointers on top of another allocator.))) ) Macros: MYREF = $(LINK2 std_experimental_allocator_building_blocks_$2.html, $1)  MYREF2 = $(LINK2 std_experimental_allocator_building_blocks_$2.html#$1, $1)  MYREF3 = $(LINK2 std_experimental_allocator_$2.html#$1, $1)  TDC = $(TDNW $(D $1)$+) TDC2 = $(TDNW $(D $(MYREF2 $1,$+))$(BR)$(SMALL $(D std.experimental.allocator.building_blocks.$2))) TDC3 = $(TDNW $(D $(MYREF3 $1,$+))$(BR)$(SMALL $(D std.experimental.allocator.$2))) RES = $(I result) POST = $(BR)$(SMALL $(I Post:) $(BLUE $(D $0))) */ module std.experimental.allocator.building_blocks; public import std.experimental.allocator.building_blocks.affix_allocator, std.experimental.allocator.building_blocks.allocator_list, std.experimental.allocator.building_blocks.bucketizer, std.experimental.allocator.building_blocks.fallback_allocator, std.experimental.allocator.building_blocks.free_list, std.experimental.allocator.building_blocks.free_tree, std.experimental.allocator.gc_allocator, std.experimental.allocator.building_blocks.bitmapped_block, std.experimental.allocator.building_blocks.kernighan_ritchie, std.experimental.allocator.mallocator, std.experimental.allocator.mmap_allocator, std.experimental.allocator.building_blocks.null_allocator, std.experimental.allocator.building_blocks.quantizer, std.experimental.allocator.building_blocks.region, std.experimental.allocator.building_blocks.segregator, std.experimental.allocator.building_blocks.stats_collector; ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/segregator.d0000664000175000017500000003057312776215007030034 0ustar kaikaimodule std.experimental.allocator.building_blocks.segregator; import std.experimental.allocator.common; /** Dispatches allocations (and deallocations) between two allocators ($(D SmallAllocator) and $(D LargeAllocator)) depending on the size allocated, as follows. All allocations smaller than or equal to $(D threshold) will be dispatched to $(D SmallAllocator). The others will go to $(D LargeAllocator). If both allocators are $(D shared), the $(D Segregator) will also offer $(D shared) methods. */ struct Segregator(size_t threshold, SmallAllocator, LargeAllocator) { import std.algorithm : min; import std.traits : hasMember; static if (stateSize!SmallAllocator) private SmallAllocator _small; else private alias _small = SmallAllocator.instance; static if (stateSize!LargeAllocator) private LargeAllocator _large; else private alias _large = LargeAllocator.instance; version (StdDdoc) { /** The alignment offered is the minimum of the two allocators' alignment. */ enum uint alignment; /** This method is defined only if at least one of the allocators defines it. The good allocation size is obtained from $(D SmallAllocator) if $(D s <= threshold), or $(D LargeAllocator) otherwise. (If one of the allocators does not define $(D goodAllocSize), the default implementation in this module applies.) */ static size_t goodAllocSize(size_t s); /** The memory is obtained from $(D SmallAllocator) if $(D s <= threshold), or $(D LargeAllocator) otherwise. */ void[] allocate(size_t); /** This method is defined if both allocators define it, and forwards to $(D SmallAllocator) or $(D LargeAllocator) appropriately. */ void[] alignedAllocate(size_t, uint); /** This method is defined only if at least one of the allocators defines it. If $(D SmallAllocator) defines $(D expand) and $(D b.length + delta <= threshold), the call is forwarded to $(D SmallAllocator). If $( LargeAllocator) defines $(D expand) and $(D b.length > threshold), the call is forwarded to $(D LargeAllocator). Otherwise, the call returns $(D false). */ bool expand(ref void[] b, size_t delta); /** This method is defined only if at least one of the allocators defines it. If $(D SmallAllocator) defines $(D reallocate) and $(D b.length <= threshold && s <= threshold), the call is forwarded to $(D SmallAllocator). If $(D LargeAllocator) defines $(D expand) and $(D b.length > threshold && s > threshold), the call is forwarded to $(D LargeAllocator). Otherwise, the call returns $(D false). */ bool reallocate(ref void[] b, size_t s); /** This method is defined only if at least one of the allocators defines it, and work similarly to $(D reallocate). */ bool alignedReallocate(ref void[] b, size_t s); /** This method is defined only if both allocators define it. The call is forwarded to $(D SmallAllocator) if $(D b.length <= threshold), or $(D LargeAllocator) otherwise. */ Ternary owns(void[] b); /** This function is defined only if both allocators define it, and forwards appropriately depending on $(D b.length). */ bool deallocate(void[] b); /** This function is defined only if both allocators define it, and calls $(D deallocateAll) for them in turn. */ bool deallocateAll(); /** This function is defined only if both allocators define it, and returns the conjunction of $(D empty) calls for the two. */ Ternary empty(); } /** Composite allocators involving nested instantiations of $(D Segregator) make it difficult to access individual sub-allocators stored within. $(D allocatorForSize) simplifies the task by supplying the allocator nested inside a $(D Segregator) that is responsible for a specific size $(D s). Example: ---- alias A = Segregator!(300, Segregator!(200, A1, A2), A3); A a; static assert(typeof(a.allocatorForSize!10) == A1); static assert(typeof(a.allocatorForSize!250) == A2); static assert(typeof(a.allocatorForSize!301) == A3); ---- */ ref auto allocatorForSize(size_t s)() { static if (s <= threshold) static if (is(SmallAllocator == Segregator!(Args), Args...)) return _small.allocatorForSize!s; else return _small; else static if (is(LargeAllocator == Segregator!(Args), Args...)) return _large.allocatorForSize!s; else return _large; } enum uint alignment = min(SmallAllocator.alignment, LargeAllocator.alignment); private template Impl() { size_t goodAllocSize(size_t s) { return s <= threshold ? _small.goodAllocSize(s) : _large.goodAllocSize(s); } void[] allocate(size_t s) { return s <= threshold ? _small.allocate(s) : _large.allocate(s); } static if (hasMember!(SmallAllocator, "alignedAllocate") && hasMember!(LargeAllocator, "alignedAllocate")) void[] alignedAllocate(size_t s, uint a) { return s <= threshold ? _small.alignedAllocate(s, a) : _large.alignedAllocate(s, a); } static if (hasMember!(SmallAllocator, "expand") || hasMember!(LargeAllocator, "expand")) bool expand(ref void[] b, size_t delta) { if (b.length + delta <= threshold) { // Old and new allocations handled by _small static if (hasMember!(SmallAllocator, "expand")) return _small.expand(b, delta); else return false; } if (b.length > threshold) { // Old and new allocations handled by _large static if (hasMember!(LargeAllocator, "expand")) return _large.expand(b, delta); else return false; } // Oops, cross-allocator transgression return false; } static if (hasMember!(SmallAllocator, "reallocate") || hasMember!(LargeAllocator, "reallocate")) bool reallocate(ref void[] b, size_t s) { static if (hasMember!(SmallAllocator, "reallocate")) if (b.length <= threshold && s <= threshold) { // Old and new allocations handled by _small return _small.reallocate(b, s); } static if (hasMember!(LargeAllocator, "reallocate")) if (b.length > threshold && s > threshold) { // Old and new allocations handled by _large return _large.reallocate(b, s); } // Cross-allocator transgression return .reallocate(this, b, s); } static if (hasMember!(SmallAllocator, "alignedReallocate") || hasMember!(LargeAllocator, "alignedReallocate")) bool reallocate(ref void[] b, size_t s) { static if (hasMember!(SmallAllocator, "alignedReallocate")) if (b.length <= threshold && s <= threshold) { // Old and new allocations handled by _small return _small.alignedReallocate(b, s); } static if (hasMember!(LargeAllocator, "alignedReallocate")) if (b.length > threshold && s > threshold) { // Old and new allocations handled by _large return _large.alignedReallocate(b, s); } // Cross-allocator transgression return .alignedReallocate(this, b, s); } static if (hasMember!(SmallAllocator, "owns") && hasMember!(LargeAllocator, "owns")) Ternary owns(void[] b) { return Ternary(b.length <= threshold ? _small.owns(b) : _large.owns(b)); } static if (hasMember!(SmallAllocator, "deallocate") && hasMember!(LargeAllocator, "deallocate")) bool deallocate(void[] data) { return data.length <= threshold ? _small.deallocate(data) : _large.deallocate(data); } static if (hasMember!(SmallAllocator, "deallocateAll") && hasMember!(LargeAllocator, "deallocateAll")) bool deallocateAll() { // Use & insted of && to evaluate both return _small.deallocateAll() & _large.deallocateAll(); } static if (hasMember!(SmallAllocator, "empty") && hasMember!(LargeAllocator, "empty")) Ternary empty() { return _small.empty && _large.empty; } static if (hasMember!(SmallAllocator, "resolveInternalPointer") && hasMember!(LargeAllocator, "resolveInternalPointer")) void[] resolveInternalPointer(void* p) { if (auto r = _small.resolveInternalPointer(p)) return r; return _large.resolveInternalPointer(p); } } private enum sharedMethods = !stateSize!SmallAllocator && !stateSize!LargeAllocator && is(typeof(SmallAllocator.instance) == shared) && is(typeof(LargeAllocator.instance) == shared); //pragma(msg, sharedMethods); static if (sharedMethods) { static shared Segregator instance; shared { mixin Impl!(); } } else { static if (!stateSize!SmallAllocator && !stateSize!LargeAllocator) static __gshared Segregator instance; mixin Impl!(); } } /// unittest { import std.experimental.allocator.building_blocks.free_list : FreeList; import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.gc_allocator : GCAllocator; alias A = Segregator!( 1024 * 4, Segregator!( 128, FreeList!(Mallocator, 0, 128), GCAllocator), Segregator!( 1024 * 1024, Mallocator, GCAllocator) ); A a; auto b = a.allocate(200); assert(b.length == 200); a.deallocate(b); } /** A $(D Segregator) with more than three arguments expands to a composition of elemental $(D Segregator)s, as illustrated by the following example: ---- alias A = Segregator!( n1, A1, n2, A2, n3, A3, A4 ); ---- With this definition, allocation requests for $(D n1) bytes or less are directed to $(D A1); requests between $(D n1 + 1) and $(D n2) bytes (inclusive) are directed to $(D A2); requests between $(D n2 + 1) and $(D n3) bytes (inclusive) are directed to $(D A3); and requests for more than $(D n3) bytes are directed to $(D A4). If some particular range should not be handled, $(D NullAllocator) may be used appropriately. */ template Segregator(Args...) if (Args.length > 3) { // Binary search private enum cutPoint = ((Args.length - 2) / 4) * 2; static if (cutPoint >= 2) { alias Segregator = .Segregator!( Args[cutPoint], .Segregator!(Args[0 .. cutPoint], Args[cutPoint + 1]), .Segregator!(Args[cutPoint + 2 .. $]) ); } else { // Favor small sizes alias Segregator = .Segregator!( Args[0], Args[1], .Segregator!(Args[2 .. $]) ); } // Linear search //alias Segregator = .Segregator!( // Args[0], Args[1], // .Segregator!(Args[2 .. $]) //); } /// unittest { import std.experimental.allocator.building_blocks.free_list : FreeList; import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.gc_allocator : GCAllocator; alias A = Segregator!( 128, FreeList!(Mallocator, 0, 128), 1024 * 4, GCAllocator, 1024 * 1024, Mallocator, GCAllocator ); A a; auto b = a.allocate(201); assert(b.length == 201); a.deallocate(b); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/null_allocator.d0000664000175000017500000000532312776215007030677 0ustar kaikaimodule std.experimental.allocator.building_blocks.null_allocator; /* _ _ _ _ _ _ _ | \ | | | | | /\ | | | | | | \| |_ _| | | / \ | | | ___ ___ __ _| |_ ___ _ __ | . ` | | | | | | / /\ \ | | |/ _ \ / __/ _` | __/ _ \| '__| | |\ | |_| | | |/ ____ \| | | (_) | (_| (_| | || (_) | | |_| \_|\__,_|_|_/_/ \_\_|_|\___/ \___\__,_|\__\___/|_| */ /** $(D NullAllocator) is an emphatically empty implementation of the allocator interface. Although it has no direct use, it is useful as a "terminator" in composite allocators. */ struct NullAllocator { import std.experimental.allocator.common : Ternary; /** $(D NullAllocator) advertises a relatively large _alignment equal to 64 KB. This is because $(D NullAllocator) never actually needs to honor this alignment and because composite allocators using $(D NullAllocator) shouldn't be unnecessarily constrained. */ enum uint alignment = 64 * 1024; /// Returns $(D n). //size_t goodAllocSize(size_t n) shared const //{ return .goodAllocSize(this, n); } /// Always returns $(D null). void[] allocate(size_t) shared { return null; } /// Always returns $(D null). void[] alignedAllocate(size_t, uint) shared { return null; } /// Always returns $(D null). void[] allocateAll() shared { return null; } /** These methods return $(D false). Precondition: $(D b is null). This is because there is no other possible legitimate input. */ bool expand(ref void[] b, size_t) shared { assert(b is null); return false; } /// Ditto bool reallocate(ref void[] b, size_t) shared { assert(b is null); return false; } /// Ditto bool alignedReallocate(ref void[] b, size_t, uint) shared { assert(b is null); return false; } /// Returns $(D Ternary.no). Ternary owns(void[]) shared const { return Ternary.no; } /** Returns $(D null). */ void[] resolveInternalPointer(void*) shared const { return null; } /** No-op. Precondition: $(D b is null) */ bool deallocate(void[] b) shared { assert(b is null); return true; } /** No-op. */ bool deallocateAll() shared { return true; } /** Returns $(D Ternary.yes). */ Ternary empty() shared const { return Ternary.yes; } /** Returns the $(D shared) global instance of the $(D NullAllocator). */ static shared NullAllocator instance; } unittest { auto b = NullAllocator.instance.allocate(100); assert(b is null); NullAllocator.instance.deallocate(b); NullAllocator.instance.deallocateAll(); import std.experimental.allocator.common : Ternary; assert(NullAllocator.instance.owns(null) == Ternary.no); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/scoped_allocator.d0000664000175000017500000001151712776215007031204 0ustar kaikaimodule std.experimental.allocator.building_blocks.scoped_allocator; import std.experimental.allocator.common; /** $(D ScopedAllocator) delegates all allocation requests to $(D ParentAllocator). When destroyed, the $(D ScopedAllocator) object automatically calls $(D deallocate) for all memory allocated through its lifetime. (The $(D deallocateAll) function is also implemented with the same semantics.) $(D deallocate) is also supported, which is where most implementation effort and overhead of $(D ScopedAllocator) go. If $(D deallocate) is not needed, a simpler design combining $(D AllocatorList) with $(D Region) is recommended. */ struct ScopedAllocator(ParentAllocator) { unittest { testAllocator!(() => ScopedAllocator()); } private import std.experimental.allocator.building_blocks.affix_allocator : AffixAllocator; private import std.traits : hasMember; private struct Node { Node* prev; Node* next; size_t length; } alias Allocator = AffixAllocator!(ParentAllocator, Node); // state { /** If $(D ParentAllocator) is stateful, $(D parent) is a property giving access to an $(D AffixAllocator!ParentAllocator). Otherwise, $(D parent) is an alias for `AffixAllocator!ParentAllocator.instance`. */ static if (stateSize!ParentAllocator) { Allocator parent; } else { alias parent = Allocator.instance; } private Node* root; // } /** $(D ScopedAllocator) is not copyable. */ @disable this(this); /** $(D ScopedAllocator)'s destructor releases all memory allocated during its lifetime. */ ~this() { deallocateAll; } /// Alignment offered enum alignment = Allocator.alignment; /** Forwards to $(D parent.goodAllocSize) (which accounts for the management overhead). */ size_t goodAllocSize(size_t n) { return parent.goodAllocSize(n); } /** Allocates memory. For management it actually allocates extra memory from the parent. */ void[] allocate(size_t n) { auto b = parent.allocate(n); if (!b.ptr) return b; Node* toInsert = & parent.prefix(b); toInsert.prev = null; toInsert.next = root; toInsert.length = n; root = toInsert; return b; } /** Forwards to $(D parent.expand(b, delta)). */ static if (hasMember!(Allocator, "expand")) bool expand(ref void[] b, size_t delta) { auto result = parent.expand(b, delta); if (result && b.ptr) { parent.prefix(b).length = b.length; } return result; } /** Reallocates $(D b) to new size $(D s). */ bool reallocate(ref void[] b, size_t s) { // Remove from list if (b.ptr) { Node* n = & parent.prefix(b); if (n.prev) n.prev.next = n.next; else root = n.next; if (n.next) n.next.prev = n.prev; } auto result = parent.reallocate(b, s); // Add back to list if (b.ptr) { Node* n = & parent.prefix(b); n.prev = null; n.next = root; n.length = s; root = n; } return result; } /** Forwards to $(D parent.owns(b)). */ static if (hasMember!(Allocator, "owns")) Ternary owns(void[] b) { return parent.owns(b); } /** Deallocates $(D b). */ static if (hasMember!(Allocator, "deallocate")) bool deallocate(void[] b) { // Remove from list if (b.ptr) { Node* n = & parent.prefix(b); if (n.prev) n.prev.next = n.next; else root = n.next; if (n.next) n.next.prev = n.prev; } return parent.deallocate(b); } /** Deallocates all memory allocated. */ bool deallocateAll() { bool result = true; for (auto n = root; n; ) { void* p = n + 1; auto length = n.length; n = n.next; if (!parent.deallocate(p[0 .. length])) result = false; } root = null; return result; } /** Returns `Ternary.yes` if this allocator is not responsible for any memory, `Ternary.no` otherwise. (Never returns `Ternary.unknown`.) */ Ternary empty() const { return Ternary(root is null); } } /// unittest { import std.experimental.allocator.mallocator : Mallocator; ScopedAllocator!Mallocator alloc; assert(alloc.empty == Ternary.yes); const b = alloc.allocate(10); assert(b.length == 10); assert(alloc.empty == Ternary.no); } unittest { import std.experimental.allocator.gc_allocator : GCAllocator; testAllocator!(() => ScopedAllocator!GCAllocator()); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/kernighan_ritchie.d0000664000175000017500000006144412776215007031350 0ustar kaikaimodule std.experimental.allocator.building_blocks.kernighan_ritchie; import std.experimental.allocator.building_blocks.null_allocator; //debug = KRRegion; debug(KRRegion) import std.stdio; version(unittest) import std.conv : text; // KRRegion /** $(D KRRegion) draws inspiration from the $(LINK2 std_experimental_allocator_region.html, region allocation strategy) and also the $(WEB stackoverflow.com/questions/13159564/explain-this-implementation-of-malloc-from-the-kr-book, famed allocator) described by Brian Kernighan and Dennis Ritchie in section 8.7 of the book $(WEB amazon.com/exec/obidos/ASIN/0131103628/classicempire, "The C Programming Language"), Second Edition, Prentice Hall, 1988. $(H4 `KRRegion` = `Region` + Kernighan-Ritchie Allocator) Initially, `KRRegion` starts in "region" mode: allocations are served from the memory chunk in a region fashion. Thus, as long as there is enough memory left, $(D KRRegion.allocate) has the performance profile of a region allocator. Deallocation inserts (in $(BIGOH 1) time) the deallocated blocks in an unstructured freelist, which is not read in region mode. Once the region cannot serve an $(D allocate) request, $(D KRRegion) switches to "free list" mode. It sorts the list of previously deallocated blocks by address and serves allocation requests off that free list. The allocation and deallocation follow the pattern described by Kernighan and Ritchie. The recommended use of `KRRegion` is as a $(I region with deallocation). If the `KRRegion` is dimensioned appropriately, it could often not enter free list mode during its lifetime. Thus it is as fast as a simple region, whilst offering deallocation at a small cost. When the region memory is exhausted, the previously deallocated memory is still usable, at a performance cost. If the region is not excessively large and fragmented, the linear allocation and deallocation cost may still be compensated for by the good locality characteristics. If the chunk of memory managed is large, it may be desirable to switch management to free list from the beginning. That way, memory may be used in a more compact manner than region mode. To force free list mode, call $(D switchToFreeList) shortly after construction or when deemed appropriate. The smallest size that can be allocated is two words (16 bytes on 64-bit systems, 8 bytes on 32-bit systems). This is because the free list management needs two words (one for the length, the other for the next pointer in the singly-linked list). The $(D ParentAllocator) type parameter is the type of the allocator used to allocate the memory chunk underlying the $(D KRRegion) object. Choosing the default ($(D NullAllocator)) means the user is responsible for passing a buffer at construction (and for deallocating it if necessary). Otherwise, $(D KRRegion) automatically deallocates the buffer during destruction. For that reason, if $(D ParentAllocator) is not $(D NullAllocator), then $(D KRRegion) is not copyable. $(H4 Implementation Details) In free list mode, $(D KRRegion) embeds a free blocks list onto the chunk of memory. The free list is circular, coalesced, and sorted by address at all times. Allocations and deallocations take time proportional to the number of previously deallocated blocks. (In practice the cost may be lower, e.g. if memory is deallocated in reverse order of allocation, all operations take constant time.) Memory utilization is good (small control structure and no per-allocation overhead). The disadvantages of freelist mode include proneness to fragmentation, a minimum allocation size of two words, and linear worst-case allocation and deallocation times. Similarities of `KRRegion` (in free list mode) with the Kernighan-Ritchie allocator: $(UL $(LI Free blocks have variable size and are linked in a singly-linked list.) $(LI The freelist is maintained in increasing address order, which makes coalescing easy.) $(LI The strategy for finding the next available block is first fit.) $(LI The free list is circular, with the last node pointing back to the first.) $(LI Coalescing is carried during deallocation.) ) Differences from the Kernighan-Ritchie allocator: $(UL $(LI Once the chunk is exhausted, the Kernighan-Ritchie allocator allocates another chunk using operating system primitives. For better composability, $(D KRRegion) just gets full (returns $(D null) on new allocation requests). The decision to allocate more blocks is deferred to a higher-level entity. For an example, see the example below using $(D AllocatorList) in conjunction with $(D KRRegion).) $(LI Allocated blocks do not hold a size prefix. This is because in D the size information is available in client code at deallocation time.) ) */ struct KRRegion(ParentAllocator = NullAllocator) { import std.experimental.allocator.common : stateSize, alignedAt, Ternary; import std.traits : hasMember; private static struct Node { import std.typecons : tuple, Tuple; Node* next; size_t size; this(this) @disable; void[] payload() inout { return (cast(ubyte*) &this)[0 .. size]; } bool adjacent(in Node* right) const { assert(right); auto p = payload; return p.ptr + p.length == right; } bool coalesce() { if (!adjacent(next)) return false; size += next.size; next = next.next; return true; } Tuple!(void[], Node*) allocateHere(size_t bytes) { assert(bytes >= Node.sizeof); assert(bytes % Node.alignof == 0); assert(next); assert(!adjacent(next)); if (size < bytes) return typeof(return)(); assert(size >= bytes); immutable leftover = size - bytes; if (leftover >= Node.sizeof) { // There's room for another node auto newNode = cast(Node*) ((cast(ubyte*) &this) + bytes); newNode.size = leftover; newNode.next = next == &this ? newNode : next; assert(next); return tuple(payload, newNode); } // No slack space, just return next node return tuple(payload, next == &this ? null : next); } } // state { /** If $(D ParentAllocator) holds state, $(D parent) is a public member of type $(D KRRegion). Otherwise, $(D parent) is an $(D alias) for `ParentAllocator.instance`. */ static if (stateSize!ParentAllocator) ParentAllocator parent; else alias parent = ParentAllocator.instance; private void[] payload; private Node* root; private bool regionMode = true; // } auto byNodePtr() { static struct Range { Node* start, current; @property bool empty() { return !current; } @property Node* front() { return current; } void popFront() { assert(current && current.next); current = current.next; if (current == start) current = null; } @property Range save() { return this; } } import std.range : isForwardRange; static assert(isForwardRange!Range); return Range(root, root); } string toString() { import std.format : format; string s = "KRRegion@"; s ~= format("%s-%s(0x%s[%s] %s", &this, &this + 1, payload.ptr, payload.length, regionMode ? "(region)" : "(freelist)"); Node* lastNode = null; if (!regionMode) { foreach (node; byNodePtr) { s ~= format(", %sfree(0x%s[%s])", lastNode && lastNode.adjacent(node) ? "+" : "", cast(void*) node, node.size); lastNode = node; } } else { for (auto node = root; node; node = node.next) { s ~= format(", %sfree(0x%s[%s])", lastNode && lastNode.adjacent(node) ? "+" : "", cast(void*) node, node.size); lastNode = node; } } s ~= ')'; return s; } private void assertValid(string s) { assert(!regionMode); if (!payload.ptr) { assert(!root, s); return; } if (!root) { return; } assert(root >= payload.ptr, s); assert(root < payload.ptr + payload.length, s); // Check that the list terminates size_t n; foreach (node; byNodePtr) { assert(node.next); assert(!node.adjacent(node.next)); assert(n++ < payload.length / Node.sizeof, s); } } private Node* sortFreelist(Node* root) { // Find a monotonic run auto last = root; for (;;) { if (!last.next) return root; if (last > last.next) break; assert(last < last.next); last = last.next; } auto tail = last.next; last.next = null; tail = sortFreelist(tail); return merge(root, tail); } private Node* merge(Node* left, Node* right) { assert(left != right); if (!left) return right; if (!right) return left; if (left < right) { auto result = left; result.next = merge(left.next, right); return result; } auto result = right; result.next = merge(left, right.next); return result; } private void coalesceAndMakeCircular() { for (auto n = root;;) { assert(!n.next || n < n.next); if (!n.next) { // Convert to circular n.next = root; break; } if (n.coalesce) continue; // possibly another coalesce n = n.next; } } /** Create a $(D KRRegion). If $(D ParentAllocator) is not $(D NullAllocator), $(D KRRegion)'s destructor will call $(D parent.deallocate). Params: b = Block of memory to serve as support for the allocator. Memory must be larger than two words and word-aligned. n = Capacity desired. This constructor is defined only if $(D ParentAllocator) is not $(D NullAllocator). */ this(void[] b) { if (b.length < Node.sizeof) { // Init as empty assert(root is null); assert(payload is null); return; } assert(b.length >= Node.sizeof); assert(b.ptr.alignedAt(Node.alignof)); assert(b.length >= 2 * Node.sizeof); payload = b; root = cast(Node*) b.ptr; // Initialize the free list with all list assert(regionMode); root.next = null; root.size = b.length; debug(KRRegion) writefln("KRRegion@%s: init with %s[%s]", &this, b.ptr, b.length); } /// Ditto static if (!is(ParentAllocator == NullAllocator)) this(size_t n) { assert(n > Node.sizeof); this(parent.allocate(n)); } /// Ditto static if (!is(ParentAllocator == NullAllocator) && hasMember!(ParentAllocator, "deallocate")) ~this() { parent.deallocate(payload); } /** Forces free list mode. If already in free list mode, does nothing. Otherwise, sorts the free list accumulated so far and switches strategy for future allocations to KR style. */ void switchToFreeList() { if (!regionMode) return; regionMode = false; if (!root) return; root = sortFreelist(root); coalesceAndMakeCircular; } /* Noncopyable */ @disable this(this); /** Word-level alignment. */ enum alignment = Node.alignof; /** Allocates $(D n) bytes. Allocation searches the list of available blocks until a free block with $(D n) or more bytes is found (first fit strategy). The block is split (if larger) and returned. Params: n = number of bytes to _allocate Returns: A word-aligned buffer of $(D n) bytes, or $(D null). */ void[] allocate(size_t n) { if (!n || !root) return null; const actualBytes = goodAllocSize(n); // Try the region first if (regionMode) { // Only look at the head of the freelist if (root.size >= actualBytes) { // Enough room for allocation void* result = root; immutable balance = root.size - actualBytes; if (balance >= Node.sizeof) { auto newRoot = cast(Node*) (result + actualBytes); newRoot.next = root.next; newRoot.size = balance; root = newRoot; } else { root = null; switchToFreeList; } return result[0 .. n]; } // Not enough memory, switch to freelist mode and fall through switchToFreeList; } // Try to allocate from next after the iterating node for (auto pnode = root;;) { assert(!pnode.adjacent(pnode.next)); auto k = pnode.next.allocateHere(actualBytes); if (k[0] !is null) { // awes assert(k[0].length >= n); if (root == pnode.next) root = k[1]; pnode.next = k[1]; return k[0][0 .. n]; } pnode = pnode.next; if (pnode == root) break; } return null; } /** Deallocates $(D b), which is assumed to have been previously allocated with this allocator. Deallocation performs a linear search in the free list to preserve its sorting order. It follows that blocks with higher addresses in allocators with many free blocks are slower to deallocate. Params: b = block to be deallocated */ bool deallocate(void[] b) { debug(KRRegion) writefln("KRRegion@%s: deallocate(%s[%s])", &this, b.ptr, b.length); if (!b.ptr) return true; assert(owns(b) == Ternary.yes); assert(b.ptr.alignedAt(Node.alignof)); // Insert back in the freelist, keeping it sorted by address. Do not // coalesce at this time. Instead, do it lazily during allocation. auto n = cast(Node*) b.ptr; n.size = goodAllocSize(b.length); if (regionMode) { assert(root); // Insert right after root n.next = root.next; root.next = n; return true; } if (!root) { // What a sight for sore eyes root = n; root.next = root; return true; } version(assert) foreach (test; byNodePtr) { assert(test != n); } // Linear search auto pnode = root; do { assert(pnode && pnode.next); assert(pnode != n); assert(pnode.next != n); if (pnode < pnode.next) { if (pnode >= n || n >= pnode.next) continue; // Insert in between pnode and pnode.next n.next = pnode.next; pnode.next = n; n.coalesce; pnode.coalesce; root = pnode; return true; } else if (pnode < n) { // Insert at the end of the list n.next = pnode.next; pnode.next = n; pnode.coalesce; root = pnode; return true; } else if (n < pnode.next) { // Insert at the front of the list n.next = pnode.next; pnode.next = n; n.coalesce; root = n; return true; } } while ((pnode = pnode.next) != root); assert(0, "Wrong parameter passed to deallocate"); } /** Allocates all memory available to this allocator. If the allocator is empty, returns the entire available block of memory. Otherwise, it still performs a best-effort allocation: if there is no fragmentation (e.g. $(D allocate) has been used but not $(D deallocate)), allocates and returns the only available block of memory. The operation takes time proportional to the number of adjacent free blocks at the front of the free list. These blocks get coalesced, whether $(D allocateAll) succeeds or fails due to fragmentation. */ void[] allocateAll() { //debug(KRRegion) assertValid("allocateAll"); //debug(KRRegion) scope(exit) assertValid("allocateAll"); if (regionMode) switchToFreeList; if (root && root.next == root) return allocate(root.size); return null; } /// unittest { import std.experimental.allocator.gc_allocator : GCAllocator; auto alloc = KRRegion!GCAllocator(1024 * 64); const b1 = alloc.allocate(2048); assert(b1.length == 2048); const b2 = alloc.allocateAll; assert(b2.length == 1024 * 62); } /** Deallocates all memory currently allocated, making the allocator ready for other allocations. This is a $(BIGOH 1) operation. */ bool deallocateAll() { debug(KRRegion) assertValid("deallocateAll"); debug(KRRegion) scope(exit) assertValid("deallocateAll"); root = cast(Node*) payload.ptr; // Initialize the free list with all list if (root) { root.next = root; root.size = payload.length; } return true; } /** Checks whether the allocator is responsible for the allocation of $(D b). It does a simple $(BIGOH 1) range check. $(D b) should be a buffer either allocated with $(D this) or obtained through other means. */ Ternary owns(void[] b) { debug(KRRegion) assertValid("owns"); debug(KRRegion) scope(exit) assertValid("owns"); return Ternary(b.ptr >= payload.ptr && b.ptr < payload.ptr + payload.length); } /** Adjusts $(D n) to a size suitable for allocation (two words or larger, word-aligned). */ static size_t goodAllocSize(size_t n) { import std.experimental.allocator.common : roundUpToMultipleOf; return n <= Node.sizeof ? Node.sizeof : n.roundUpToMultipleOf(alignment); } /** Returns: `Ternary.yes` if the allocator is empty, `Ternary.no` otherwise. Never returns `Ternary.unknown`. */ Ternary empty() { return Ternary(root && root.size == payload.length); } } /** $(D KRRegion) is preferable to $(D Region) as a front for a general-purpose allocator if $(D deallocate) is needed, yet the actual deallocation traffic is relatively low. The example below shows a $(D KRRegion) using stack storage fronting the GC allocator. */ unittest { import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.building_blocks.fallback_allocator : fallbackAllocator; import std.experimental.allocator.common : Ternary; // KRRegion fronting a general-purpose allocator ubyte[1024 * 128] buf; auto alloc = fallbackAllocator(KRRegion!()(buf), GCAllocator.instance); auto b = alloc.allocate(100); assert(b.length == 100); assert(alloc.primary.owns(b) == Ternary.yes); } /** The code below defines a scalable allocator consisting of 1 MB (or larger) blocks fetched from the garbage-collected heap. Each block is organized as a KR-style heap. More blocks are allocated and freed on a need basis. This is the closest example to the allocator introduced in the K$(AMP)R book. It should perform slightly better because instead of searching through one large free list, it searches through several shorter lists in LRU order. Also, it actually returns memory to the operating system when possible. */ unittest { import std.algorithm : max; import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.mmap_allocator : MmapAllocator; import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; AllocatorList!(n => KRRegion!MmapAllocator(max(n * 16, 1024 * 1024))) alloc; } unittest { import std.algorithm : max; import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.common : Ternary; import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; /* Create a scalable allocator consisting of 1 MB (or larger) blocks fetched from the garbage-collected heap. Each block is organized as a KR-style heap. More blocks are allocated and freed on a need basis. */ AllocatorList!(n => KRRegion!Mallocator(max(n * 16, 1024 * 1024)), NullAllocator) alloc; void[][50] array; foreach (i; 0 .. array.length) { auto length = i * 10_000 + 1; array[i] = alloc.allocate(length); assert(array[i].ptr); assert(array[i].length == length); } import std.random : randomShuffle; randomShuffle(array[]); foreach (i; 0 .. array.length) { assert(array[i].ptr); assert(alloc.owns(array[i]) == Ternary.yes); alloc.deallocate(array[i]); } } unittest { import std.algorithm : max; import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.common : Ternary; import std.experimental.allocator.mmap_allocator : MmapAllocator; import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; /* Create a scalable allocator consisting of 1 MB (or larger) blocks fetched from the garbage-collected heap. Each block is organized as a KR-style heap. More blocks are allocated and freed on a need basis. */ AllocatorList!((n) { auto result = KRRegion!MmapAllocator(max(n * 2, 1024 * 1024)); return result; }) alloc; void[][99] array; foreach (i; 0 .. array.length) { auto length = i * 10_000 + 1; array[i] = alloc.allocate(length); assert(array[i].ptr); foreach (j; 0 .. i) { assert(array[i].ptr != array[j].ptr); } assert(array[i].length == length); } import std.random : randomShuffle; randomShuffle(array[]); foreach (i; 0 .. array.length) { assert(alloc.owns(array[i]) == Ternary.yes); alloc.deallocate(array[i]); } } unittest { import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; import std.algorithm : max; import std.experimental.allocator.common : testAllocator; testAllocator!(() => AllocatorList!( n => KRRegion!GCAllocator(max(n * 16, 1024 * 1024)))()); } unittest { import std.experimental.allocator.gc_allocator : GCAllocator; auto alloc = KRRegion!GCAllocator(1024 * 1024); void[][] array; foreach (i; 1 .. 4) { array ~= alloc.allocate(i); assert(array[$ - 1].length == i); } alloc.deallocate(array[1]); alloc.deallocate(array[0]); alloc.deallocate(array[2]); assert(alloc.allocateAll().length == 1024 * 1024); } unittest { import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.common : Ternary; auto alloc = KRRegion!()(GCAllocator.instance.allocate(1024 * 1024)); const store = alloc.allocate(KRRegion!().sizeof); auto p = cast(KRRegion!()* ) store.ptr; import std.conv : emplace; import std.algorithm : move; import core.stdc.string : memcpy; memcpy(p, &alloc, alloc.sizeof); emplace(&alloc); void[][100] array; foreach (i; 0 .. array.length) { auto length = 100 * i + 1; array[i] = p.allocate(length); assert(array[i].length == length, text(array[i].length)); assert(p.owns(array[i]) == Ternary.yes); } import std.random : randomShuffle; randomShuffle(array[]); foreach (i; 0 .. array.length) { assert(p.owns(array[i]) == Ternary.yes); p.deallocate(array[i]); } auto b = p.allocateAll(); assert(b.length == 1024 * 1024 - KRRegion!().sizeof, text(b.length)); } unittest { import std.experimental.allocator.gc_allocator : GCAllocator; auto alloc = KRRegion!()(GCAllocator.instance.allocate(1024 * 1024)); auto p = alloc.allocateAll(); assert(p.length == 1024 * 1024); alloc.deallocateAll(); p = alloc.allocateAll(); assert(p.length == 1024 * 1024); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/bitmapped_block.d0000664000175000017500000013355212776215007031012 0ustar kaikaimodule std.experimental.allocator.building_blocks.bitmapped_block; import std.experimental.allocator.common; import std.experimental.allocator.building_blocks.null_allocator; /** $(D BitmappedBlock) implements a simple heap consisting of one contiguous area of memory organized in blocks, each of size $(D theBlockSize). A block is a unit of allocation. A bitmap serves as bookkeeping data, more precisely one bit per block indicating whether that block is currently allocated or not. Passing $(D NullAllocator) as $(D ParentAllocator) (the default) means user code manages allocation of the memory block from the outside; in that case $(D BitmappedBlock) must be constructed with a $(D void[]) preallocated block and has no responsibility regarding the lifetime of its support underlying storage. If another allocator type is passed, $(D BitmappedBlock) defines a destructor that uses the parent allocator to release the memory block. That makes the combination of $(D AllocatorList), $(D BitmappedBlock), and a back-end allocator such as $(D MmapAllocator) a simple and scalable solution for memory allocation. There are advantages to storing bookkeeping data separated from the payload (as opposed to e.g. using $(D AffixAllocator) to store metadata together with each allocation). The layout is more compact (overhead is one bit per block), searching for a free block during allocation enjoys better cache locality, and deallocation does not touch memory around the payload being deallocated (which is often cold). Allocation requests are handled on a first-fit basis. Although linear in complexity, allocation is in practice fast because of the compact bookkeeping representation, use of simple and fast bitwise routines, and caching of the first available block position. A known issue with this general approach is fragmentation, partially mitigated by coalescing. Since $(D BitmappedBlock) does not need to maintain the allocated size, freeing memory implicitly coalesces free blocks together. Also, tuning $(D blockSize) has a considerable impact on both internal and external fragmentation. The size of each block can be selected either during compilation or at run time. Statically-known block sizes are frequent in practice and yield slightly better performance. To choose a block size statically, pass it as the $(D blockSize) parameter as in $(D BitmappedBlock!(Allocator, 4096)). To choose a block size parameter, use $(D BitmappedBlock!(Allocator, chooseAtRuntime)) and pass the block size to the constructor. */ struct BitmappedBlock(size_t theBlockSize, uint theAlignment = platformAlignment, ParentAllocator = NullAllocator) { import std.typecons; import std.traits : hasMember; version(unittest) import std.stdio; import std.conv : text; unittest { import std.experimental.allocator.mallocator : AlignedMallocator; import std.algorithm : max; auto m = AlignedMallocator.instance.alignedAllocate(1024 * 64, max(theAlignment, cast(uint) size_t.sizeof)); scope(exit) AlignedMallocator.instance.deallocate(m); testAllocator!(() => BitmappedBlock(m)); } static assert(theBlockSize > 0 && theAlignment.isGoodStaticAlignment); static assert(theBlockSize == chooseAtRuntime || theBlockSize % theAlignment == 0, "Block size must be a multiple of the alignment"); /** If $(D blockSize == chooseAtRuntime), $(D BitmappedBlock) offers a read/write property $(D blockSize). It must be set before any use of the allocator. Otherwise (i.e. $(D theBlockSize) is a legit constant), $(D blockSize) is an alias for $(D theBlockSize). Whether constant or variable, must also be a multiple of $(D alignment). This constraint is $(D assert)ed statically and dynamically. */ static if (theBlockSize != chooseAtRuntime) { alias blockSize = theBlockSize; } else { @property uint blockSize() { return _blockSize; } @property void blockSize(uint s) { assert(!_control && s % alignment == 0); _blockSize = s; } private uint _blockSize; } static if (is(ParentAllocator == NullAllocator)) { private enum parentAlignment = platformAlignment; } else { private alias parentAlignment = ParentAllocator.alignment; static assert(parentAlignment >= ulong.alignof); } /** The _alignment offered is user-configurable statically through parameter $(D theAlignment), defaulted to $(D platformAlignment). */ alias alignment = theAlignment; // state { /** The _parent allocator. Depending on whether $(D ParentAllocator) holds state or not, this is a member variable or an alias for `ParentAllocator.instance`. */ static if (stateSize!ParentAllocator) { ParentAllocator parent; } else { alias parent = ParentAllocator.instance; } private uint _blocks; private BitVector _control; private void[] _payload; private size_t _startIdx; // } private size_t totalAllocation(size_t capacity) { auto blocks = capacity.divideRoundUp(blockSize); auto leadingUlongs = blocks.divideRoundUp(64); import std.algorithm : min; immutable initialAlignment = min(parentAlignment, 1U << trailingZeros(leadingUlongs * 8)); auto maxSlack = alignment <= initialAlignment ? 0 : alignment - initialAlignment; //writeln(maxSlack); return leadingUlongs * 8 + maxSlack + blockSize * blocks; } /** Constructs a block allocator given a hunk of memory, or a desired capacity in bytes. $(UL $(LI If $(D ParentAllocator) is $(D NullAllocator), only the constructor taking $(D data) is defined and the user is responsible for freeing $(D data) if desired.) $(LI Otherwise, both constructors are defined. The $(D data)-based constructor assumes memory has been allocated with the parent allocator. The $(D capacity)-based constructor uses $(D ParentAllocator) to allocate an appropriate contiguous hunk of memory. Regardless of the constructor used, the destructor releases the memory by using $(D ParentAllocator.deallocate).) ) */ this(void[] data) { immutable a = data.ptr.effectiveAlignment; assert(a >= size_t.alignof || !data.ptr, "Data must be aligned properly"); immutable ulong totalBits = data.length * 8; immutable ulong bitsPerBlock = blockSize * 8 + 1; // Get a first estimate import std.conv : to; _blocks = to!uint(totalBits / bitsPerBlock); // Reality is a bit more complicated, iterate until a good number of // blocks found. for (; _blocks; --_blocks) { immutable controlWords = _blocks.divideRoundUp(64); auto payload = data[controlWords * 8 .. $].roundStartToMultipleOf( alignment); if (payload.length < _blocks * blockSize) { // Overestimated continue; } _control = BitVector((cast(ulong*)data.ptr)[0 .. controlWords]); _control[] = 0; _payload = payload; break; } } /// Ditto static if (!is(ParentAllocator == NullAllocator)) this(size_t capacity) { size_t toAllocate = totalAllocation(capacity); auto data = parent.allocate(toAllocate); this(data); assert(_blocks * blockSize >= capacity); } /** If $(D ParentAllocator) is not $(D NullAllocator) and defines $(D deallocate), the destructor is defined to deallocate the block held. */ static if (!is(ParentAllocator == NullAllocator) && hasMember!(ParentAllocator, "deallocate")) ~this() { auto start = _control.rep.ptr, end = _payload.ptr + _payload.length; parent.deallocate(start[0 .. end - start]); } /* Adjusts the memoized _startIdx to the leftmost control word that has at least one zero bit. Assumes all control words to the left of $(D _control[_startIdx]) are already occupied. */ private void adjustStartIdx() { while (_startIdx < _control.rep.length && _control.rep[_startIdx] == ulong.max) { ++_startIdx; } } /* Returns the blocks corresponding to the control bits starting at word index wordIdx and bit index msbIdx (MSB=0) for a total of howManyBlocks. */ private void[] blocksFor(size_t wordIdx, uint msbIdx, size_t howManyBlocks) { assert(msbIdx <= 63); const start = (wordIdx * 64 + msbIdx) * blockSize; const end = start + blockSize * howManyBlocks; if (end <= _payload.length) return _payload[start .. end]; // This could happen if we have more control bits than available memory. // That's possible because the control bits are rounded up to fit in // 64-bit words. return null; } /** Returns the actual bytes allocated when $(D n) bytes are requested, i.e. $(D n.roundUpToMultipleOf(blockSize)). */ size_t goodAllocSize(size_t n) { return n.roundUpToMultipleOf(blockSize); } /** Allocates $(D s) bytes of memory and returns it, or $(D null) if memory could not be allocated. The following information might be of help with choosing the appropriate block size. Actual allocation occurs in sizes multiple of the block size. Allocating one block is the fastest because only one 0 bit needs to be found in the metadata. Allocating 2 through 64 blocks is the next cheapest because it affects a maximum of two $(D ulong)s in the metadata. Allocations greater than 64 blocks require a multiword search through the metadata. */ @trusted void[] allocate(const size_t s) { const blocks = s.divideRoundUp(blockSize); //writefln("Allocating %s blocks each of size %s", blocks, blockSize); void[] result = void; switcharoo: switch (blocks) { case 1: // inline code here for speed // find the next available block foreach (i; _startIdx .. _control.rep.length) { const w = _control.rep[i]; if (w == ulong.max) continue; uint j = leadingOnes(w); assert(j < 64); assert((_control.rep[i] & ((1UL << 63) >> j)) == 0); _control.rep[i] |= (1UL << 63) >> j; if (i == _startIdx) { adjustStartIdx(); } result = blocksFor(i, j, 1); break switcharoo; } goto case 0; // fall through case 0: return null; case 2: .. case 64: result = smallAlloc(cast(uint) blocks); break; default: result = hugeAlloc(blocks); break; } return result.ptr ? result.ptr[0 .. s] : null; } /** Allocates a block with specified alignment $(D a). The alignment must be a power of 2. If $(D a <= alignment), function forwards to $(D allocate). Otherwise, it attempts to overallocate and then adjust the result for proper alignment. In the worst case the slack memory is around two blocks. */ void[] alignedAllocate(size_t n, uint a) { assert(a.isPowerOf2); if (a <= alignment) return allocate(n); // Overallocate to make sure we can get an aligned block auto b = allocate((n + a - alignment).roundUpToMultipleOf(blockSize)); if (!b.ptr) return null; auto result = b.roundStartToMultipleOf(a); assert(result.length >= n); result = result.ptr[0 .. n]; // final result // Free any blocks that might be slack at the beginning auto slackHeadingBlocks = (result.ptr - b.ptr) / blockSize; if (slackHeadingBlocks) { deallocate(b[0 .. slackHeadingBlocks * blockSize]); } // Free any blocks that might be slack at the end auto slackTrailingBlocks = ((b.ptr + b.length) - (result.ptr + result.length)) / blockSize; if (slackTrailingBlocks) { deallocate(b[$ - slackTrailingBlocks * blockSize .. $]); } return result; } /** If the $(D BitmappedBlock) object is empty (has no active allocation), allocates all memory within and returns a slice to it. Otherwise, returns $(D null) (i.e. no attempt is made to allocate the largest available block). */ void[] allocateAll() { if (empty != Ternary.yes) return null; _control[] = 1; return _payload; } /** Returns `Ternary.yes` if `b` belongs to the `BitmappedBlock` object, `Ternary.no` otherwise. Never returns `Ternary.unkown`. (This method is somewhat tolerant in that accepts an interior slice.) */ Ternary owns(void[] b) const { //if (!b.ptr) return Ternary.no; assert(b.ptr !is null || b.length == 0, "Corrupt block."); return Ternary(b.ptr >= _payload.ptr && b.ptr + b.length <= _payload.ptr + _payload.length); } /* Tries to allocate "blocks" blocks at the exact position indicated by the position wordIdx/msbIdx (msbIdx counts from MSB, i.e. MSB has index 0). If it succeeds, fills "result" with the result and returns tuple(size_t.max, 0). Otherwise, returns a tuple with the next position to search. */ private Tuple!(size_t, uint) allocateAt(size_t wordIdx, uint msbIdx, size_t blocks, ref void[] result) { assert(blocks > 0); assert(wordIdx < _control.rep.length); assert(msbIdx <= 63); if (msbIdx + blocks <= 64) { // Allocation should fit this control word if (setBitsIfZero(_control.rep[wordIdx], cast(uint) (64 - msbIdx - blocks), 63 - msbIdx)) { // Success result = blocksFor(wordIdx, msbIdx, blocks); return tuple(size_t.max, 0u); } // Can't allocate, make a suggestion return msbIdx + blocks == 64 ? tuple(wordIdx + 1, 0u) : tuple(wordIdx, cast(uint) (msbIdx + blocks)); } // Allocation spans two control words or more immutable mask = ulong.max >> msbIdx; if (_control.rep[wordIdx] & mask) { // We can't allocate the rest of this control word, // return a suggestion. return tuple(wordIdx + 1, 0u); } // We can allocate the rest of this control word, but we first need to // make sure we can allocate the tail. if (wordIdx + 1 == _control.rep.length) { // No more memory return tuple(_control.rep.length, 0u); } auto hint = allocateAt(wordIdx + 1, 0, blocks - 64 + msbIdx, result); if (hint[0] == size_t.max) { // We did it! _control.rep[wordIdx] |= mask; result = blocksFor(wordIdx, msbIdx, blocks); return tuple(size_t.max, 0u); } // Failed, return a suggestion that skips this whole run. return hint; } /* Allocates as many blocks as possible at the end of the blocks indicated by wordIdx. Returns the number of blocks allocated. */ private uint allocateAtTail(size_t wordIdx) { assert(wordIdx < _control.rep.length); const available = trailingZeros(_control.rep[wordIdx]); _control.rep[wordIdx] |= ulong.max >> available; return available; } private void[] smallAlloc(uint blocks) { assert(blocks >= 2 && blocks <= 64, text(blocks)); foreach (i; _startIdx .. _control.rep.length) { // Test within the current 64-bit word const v = _control.rep[i]; if (v == ulong.max) continue; auto j = findContigOnes(~v, blocks); if (j < 64) { // yay, found stuff setBits(_control.rep[i], 64 - j - blocks, 63 - j); return blocksFor(i, j, blocks); } // Next, try allocations that cross a word auto available = trailingZeros(v); if (available == 0) continue; if (i + 1 >= _control.rep.length) break; assert(available < blocks); // otherwise we should have found it auto needed = blocks - available; assert(needed > 0 && needed < 64); if (allocateAtFront(i + 1, needed)) { // yay, found a block crossing two words _control.rep[i] |= (1UL << available) - 1; return blocksFor(i, 64 - available, blocks); } } return null; } private void[] hugeAlloc(size_t blocks) { assert(blocks > 64); if (_startIdx == _control._rep.length) { assert(_control.allAre1); return null; } auto i = _control.findZeros(blocks, _startIdx * 64); if (i == i.max) return null; // Allocate those bits _control[i .. i + blocks] = 1; return _payload[cast(size_t) (i * blockSize) .. cast(size_t) ((i + blocks) * blockSize)]; //void[] result; //auto pos = tuple(_startIdx, 0); //for (;;) //{ // if (pos[0] >= _control.rep.length) // { // // No more memory // return null; // } // pos = allocateAt(pos[0], pos[1], blocks, result); // if (pos[0] == size_t.max) // { // // Found and allocated // return result; // } //} } // Rounds sizeInBytes to a multiple of blockSize. private size_t bytes2blocks(size_t sizeInBytes) { return (sizeInBytes + blockSize - 1) / blockSize; } /* Allocates given blocks at the beginning blocks indicated by wordIdx. Returns true if allocation was possible, false otherwise. */ private bool allocateAtFront(size_t wordIdx, uint blocks) { assert(wordIdx < _control.rep.length && blocks >= 1 && blocks <= 64); const mask = (1UL << (64 - blocks)) - 1; if (_control.rep[wordIdx] > mask) return false; // yay, works _control.rep[wordIdx] |= ~mask; return true; } /** Expands an allocated block in place. */ @trusted bool expand(ref void[] b, immutable size_t delta) { // Dispose with trivial corner cases if (delta == 0) return true; if (b is null) { b = allocate(delta); return b !is null; } /* To simplify matters, refuse to expand buffers that don't start at a block start (this may be the case for blocks allocated with alignedAllocate). */ if ((b.ptr - _payload.ptr) % blockSize) return false; const blocksOld = bytes2blocks(b.length); const blocksNew = bytes2blocks(b.length + delta); assert(blocksOld <= blocksNew); // Possibly we have enough slack at the end of the block! if (blocksOld == blocksNew) { b = b.ptr[0 .. b.length + delta]; return true; } assert((b.ptr - _payload.ptr) % blockSize == 0); const blockIdx = (b.ptr - _payload.ptr) / blockSize; const blockIdxAfter = blockIdx + blocksOld; //writefln("blockIdx: %s, blockIdxAfter: %s", blockIdx, blockIdxAfter); // Try the maximum const wordIdx = blockIdxAfter / 64, msbIdx = cast(uint) (blockIdxAfter % 64); void[] p; auto hint = allocateAt(wordIdx, msbIdx, blocksNew - blocksOld, p); if (hint[0] != size_t.max) { return false; } // Expansion successful assert(p.ptr == b.ptr + blocksOld * blockSize, text(p.ptr, " != ", b.ptr + blocksOld * blockSize)); b = b.ptr[0 .. b.length + delta]; return true; } /** Reallocates a previously-allocated block. Contractions occur in place. */ @system bool reallocate(ref void[] b, size_t newSize) { if (!b.ptr) { b = allocate(newSize); return b.length == newSize; } if (newSize == 0) { deallocate(b); b = null; return true; } if (newSize < b.length) { // Shrink. Will shrink in place by deallocating the trailing part. auto newCapacity = bytes2blocks(newSize) * blockSize; deallocate(b[newCapacity .. $]); b = b[0 .. newSize]; return true; } // Go the slow route return .reallocate(this, b, newSize); } /** Reallocates a block previously allocated with $(D alignedAllocate). Contractions do not occur in place. */ @system bool alignedReallocate(ref void[] b, size_t newSize, uint a) { if (newSize == 0) { deallocate(b); b = null; return true; } // Go the slow route return .alignedReallocate(this, b, newSize, a); } /** Deallocates a block previously allocated with this allocator. */ bool deallocate(void[] b) { if (b is null) return true; // Adjust pointer, might be inside a block after alignedAllocate //auto p = (b.ptr - _payload.ptr) / blockSize // Locate position immutable pos = b.ptr - _payload.ptr; immutable blockIdx = pos / blockSize; // Adjust pointer, might be inside a block due to alignedAllocate auto begin = _payload.ptr + blockIdx * blockSize, end = b.ptr + b.length; b = begin[0 .. end - begin]; // Round up size to multiple of block size auto blocks = b.length.divideRoundUp(blockSize); // Get into details auto wordIdx = blockIdx / 64, msbIdx = cast(uint) (blockIdx % 64); if (_startIdx > wordIdx) _startIdx = wordIdx; // Three stages: heading bits, full words, leftover bits if (msbIdx) { if (blocks + msbIdx <= 64) { resetBits(_control.rep[wordIdx], cast(uint) (64 - msbIdx - blocks), 63 - msbIdx); return true; } else { _control.rep[wordIdx] &= ulong.max << 64 - msbIdx; blocks -= 64 - msbIdx; ++wordIdx; msbIdx = 0; } } // Stage 2: reset one word at a time for (; blocks >= 64; blocks -= 64) { _control.rep[wordIdx++] = 0; } // Stage 3: deal with leftover bits, if any assert(wordIdx <= _control.rep.length); if (blocks) { _control.rep[wordIdx] &= ulong.max >> blocks; } return true; } /** Forcibly deallocates all memory allocated by this allocator, making it available for further allocations. Does not return memory to $(D ParentAllocator). */ bool deallocateAll() { _control[] = 0; _startIdx = 0; return true; } /** Returns `Ternary.yes` if no memory is currently allocated with this allocator, otherwise `Ternary.no`. This method never returns `Ternary.unknown`. */ Ternary empty() { return Ternary(_control.allAre0()); } void dump() { import std.stdio; writefln("%s @ %s {", typeid(this), cast(void*) _control._rep.ptr); scope(exit) writeln("}"); assert(_payload.length == blockSize * _blocks); assert(_control.length >= _blocks); writefln(" _startIdx=%s; blockSize=%s; blocks=%s", _startIdx, blockSize, _blocks); if (!_control.length) return; uint blockCount = 1; bool inAllocatedStore = _control[0]; void* start = _payload.ptr; for (size_t i = 1;; ++i) { if (i >= _blocks || _control[i] != inAllocatedStore) { writefln(" %s block at 0x%s, length: %s (%s*%s)", inAllocatedStore ? "Busy" : "Free", cast(void*) start, blockCount * blockSize, blockCount, blockSize); if (i >= _blocks) break; assert(i < _control.length); inAllocatedStore = _control[i]; start = _payload.ptr + blockCount * blockSize; blockCount = 1; } else { ++blockCount; } } } } /// unittest { // Create a block allocator on top of a 10KB stack region. import std.experimental.allocator.building_blocks.region : InSituRegion; import std.traits : hasMember; InSituRegion!(10_240, 64) r; auto a = BitmappedBlock!(64, 64)(r.allocateAll()); static assert(hasMember!(InSituRegion!(10_240, 64), "allocateAll")); const b = a.allocate(100); assert(b.length == 100); } unittest { import std.experimental.allocator.gc_allocator : GCAllocator; testAllocator!(() => BitmappedBlock!(64, 8, GCAllocator)(1024 * 64)); } unittest { static void testAllocateAll(size_t bs)(uint blocks, uint blocksAtATime) { import std.algorithm : min; assert(bs); import std.experimental.allocator.gc_allocator : GCAllocator; auto a = BitmappedBlock!(bs, min(bs, platformAlignment))( GCAllocator.instance.allocate((blocks * bs * 8 + blocks) / 8) ); import std.conv : text; assert(blocks >= a._blocks, text(blocks, " < ", a._blocks)); blocks = a._blocks; // test allocation of 0 bytes auto x = a.allocate(0); assert(x is null); // test allocation of 1 byte x = a.allocate(1); assert(x.length == 1 || blocks == 0, text(x.ptr, " ", x.length, " ", a)); a.deallocateAll(); //writeln("Control words: ", a._control.length); //writeln("Payload bytes: ", a._payload.length); bool twice = true; begin: foreach (i; 0 .. blocks / blocksAtATime) { auto b = a.allocate(bs * blocksAtATime); assert(b.length == bs * blocksAtATime, text(i, ": ", b.length)); } assert(a.allocate(bs * blocksAtATime) is null); assert(a.allocate(1) is null); // Now deallocate all and do it again! a.deallocateAll(); // Test deallocation auto v = new void[][blocks / blocksAtATime]; foreach (i; 0 .. blocks / blocksAtATime) { auto b = a.allocate(bs * blocksAtATime); assert(b.length == bs * blocksAtATime, text(i, ": ", b.length)); v[i] = b; } assert(a.allocate(bs * blocksAtATime) is null); assert(a.allocate(1) is null); foreach (i; 0 .. blocks / blocksAtATime) { a.deallocate(v[i]); } foreach (i; 0 .. blocks / blocksAtATime) { auto b = a.allocate(bs * blocksAtATime); assert(b.length == bs * blocksAtATime, text(i, ": ", b.length)); v[i] = b; } foreach (i; 0 .. v.length) { a.deallocate(v[i]); } if (twice) { twice = false; goto begin; } a.deallocateAll; // test expansion if (blocks >= blocksAtATime) { foreach (i; 0 .. blocks / blocksAtATime - 1) { auto b = a.allocate(bs * blocksAtATime); assert(b.length == bs * blocksAtATime, text(i, ": ", b.length)); (cast(ubyte[]) b)[] = 0xff; a.expand(b, blocksAtATime * bs) || assert(0, text(i)); (cast(ubyte[]) b)[] = 0xfe; assert(b.length == bs * blocksAtATime * 2, text(i, ": ", b.length)); a.reallocate(b, blocksAtATime * bs) || assert(0); assert(b.length == bs * blocksAtATime, text(i, ": ", b.length)); } } } testAllocateAll!(1)(0, 1); testAllocateAll!(1)(8, 1); testAllocateAll!(4096)(128, 1); testAllocateAll!(1)(0, 2); testAllocateAll!(1)(128, 2); testAllocateAll!(4096)(128, 2); testAllocateAll!(1)(0, 4); testAllocateAll!(1)(128, 4); testAllocateAll!(4096)(128, 4); testAllocateAll!(1)(0, 3); testAllocateAll!(1)(24, 3); testAllocateAll!(3008)(100, 1); testAllocateAll!(3008)(100, 3); testAllocateAll!(1)(0, 128); testAllocateAll!(1)(128 * 1, 128); testAllocateAll!(128 * 20)(13 * 128, 128); } // Test totalAllocation unittest { BitmappedBlock!(8, 8, NullAllocator) h1; assert(h1.totalAllocation(1) >= 8); assert(h1.totalAllocation(64) >= 64); //writeln(h1.totalAllocation(8 * 64)); assert(h1.totalAllocation(8 * 64) >= 8 * 64); assert(h1.totalAllocation(8 * 63) >= 8 * 63); assert(h1.totalAllocation(8 * 64 + 1) >= 8 * 65); BitmappedBlock!(64, 8, NullAllocator) h2; assert(h2.totalAllocation(1) >= 64); assert(h2.totalAllocation(64 * 64) >= 64 * 64); BitmappedBlock!(4096, 4096, NullAllocator) h3; assert(h3.totalAllocation(1) >= 4096); assert(h3.totalAllocation(64 * 4096) >= 64 * 4096); assert(h3.totalAllocation(64 * 4096 + 1) >= 65 * 4096); } // BitmappedBlockWithInternalPointers /** A $(D BitmappedBlock) with additional structure for supporting $(D resolveInternalPointer). To that end, $(D BitmappedBlockWithInternalPointers) adds a bitmap (one bit per block) that marks object starts. The bitmap itself has variable size and is allocated together with regular allocations. The time complexity of $(D resolveInternalPointer) is $(BIGOH k), where $(D k) is the size of the object within which the internal pointer is looked up. */ struct BitmappedBlockWithInternalPointers( size_t theBlockSize, uint theAlignment = platformAlignment, ParentAllocator = NullAllocator) { import std.conv : text; unittest { import std.experimental.allocator.mallocator : AlignedMallocator; auto m = AlignedMallocator.instance.alignedAllocate(1024 * 64, theAlignment); scope(exit) AlignedMallocator.instance.deallocate(m); testAllocator!(() => BitmappedBlockWithInternalPointers(m)); } // state { private BitmappedBlock!(theBlockSize, theAlignment, NullAllocator) _heap; private BitVector _allocStart; // } /** Constructors accepting desired capacity or a preallocated buffer, similar in semantics to those of $(D BitmappedBlock). */ this(void[] data) { _heap = BitmappedBlock!(theBlockSize, theAlignment, ParentAllocator)(data); } /// Ditto static if (!is(ParentAllocator == NullAllocator)) this(size_t capacity) { // Add room for the _allocStart vector _heap = BitmappedBlock!(theBlockSize, theAlignment, ParentAllocator) (capacity + capacity.divideRoundUp(64)); } // Makes sure there's enough room for _allocStart private bool ensureRoomForAllocStart(size_t len) { if (_allocStart.length >= len) return true; // Must ensure there's room immutable oldLength = _allocStart.rep.length; immutable bits = len.roundUpToMultipleOf(64); void[] b = _allocStart.rep; if (!_heap.reallocate(b, bits / 8)) return false; assert(b.length * 8 == bits, text(b.length * 8, " != ", bits)); _allocStart = BitVector(cast(ulong[]) b); assert(_allocStart.rep.length * 64 == bits); _allocStart.rep[oldLength .. $] = ulong.max; return true; } /** Allocator primitives. */ alias alignment = theAlignment; /// Ditto size_t goodAllocSize(size_t n) { return n.roundUpToMultipleOf(_heap.blockSize); } /// Ditto void[] allocate(size_t bytes) { auto r = _heap.allocate(bytes); if (!r.ptr) return r; immutable block = (r.ptr - _heap._payload.ptr) / _heap.blockSize; immutable blocks = (r.length + _heap.blockSize - 1) / _heap.blockSize; if (!ensureRoomForAllocStart(block + blocks)) { // Failed, free r and bailout _heap.deallocate(r); return null; } assert(block < _allocStart.length); assert(block + blocks <= _allocStart.length); // Mark the _allocStart bits assert(blocks > 0); _allocStart[block] = 1; _allocStart[block + 1 .. block + blocks] = 0; assert(block + blocks == _allocStart.length || _allocStart[block + blocks] == 1); return r; } /// Ditto void[] allocateAll() { auto r = _heap.allocateAll(); if (!r.ptr) return r; // Carve space at the end for _allocStart auto p = alignDownTo(r.ptr + r.length - 8, ulong.alignof); r = r[0 .. p - r.ptr]; // Initialize _allocStart _allocStart = BitVector(cast(ulong[]) p[0 .. 8]); _allocStart[] = 0; immutable block = (r.ptr - _heap._payload.ptr) / _heap.blockSize; assert(block < _allocStart.length); _allocStart[block] = 1; return r; } /// Ditto bool expand(ref void[] b, size_t bytes) { if (!bytes) return true; if (b is null) { b = allocate(bytes); return b !is null; } immutable oldBlocks = (b.length + _heap.blockSize - 1) / _heap.blockSize; assert(oldBlocks); immutable newBlocks = (b.length + bytes + _heap.blockSize - 1) / _heap.blockSize; assert(newBlocks >= oldBlocks); immutable block = (b.ptr - _heap._payload.ptr) / _heap.blockSize; assert(_allocStart[block]); if (!ensureRoomForAllocStart(block + newBlocks) || !_heap.expand(b, bytes)) { return false; } // Zero only the expanded bits _allocStart[block + oldBlocks .. block + newBlocks] = 0; assert(_allocStart[block]); return true; } /// Ditto bool deallocate(void[] b) { // No need to touch _allocStart here - except for the first bit, it's // meaningless in freed memory. The first bit is already 1. return _heap.deallocate(b); // TODO: one smart thing to do is reduce memory occupied by // _allocStart if we're freeing the rightmost block. } /// Ditto void[] resolveInternalPointer(void* p) { if (p < _heap._payload.ptr || p >= _heap._payload.ptr + _heap._payload.length) { return null; } // Find block start auto block = (p - _heap._payload.ptr) / _heap.blockSize; if (block >= _allocStart.length) return null; // This may happen during marking, so comment it out. // if (!_heap._control[block]) return null; // Within an allocation, must find the 1 just to the left of it auto i = _allocStart.find1Backward(block); if (i == i.max) return null; auto j = _allocStart.find1(i + 1); return _heap._payload.ptr[cast(size_t) (_heap.blockSize * i) .. cast(size_t) (_heap.blockSize * j)]; } /// Ditto Ternary empty() { return _heap.empty; } // Currently unused private void markAllAsUnused() { // Mark all deallocated memory with 1 so we minimize damage created by // false pointers. TODO: improve speed. foreach (i, ref e; _allocStart.rep) { // Set to 1 all bits in _allocStart[i] that were 0 in control, and // leave the others unchanged. // (0, 0) => 1; (0, 1) => 0; (1, 0) => 1; (1, 1) => 1 e |= ~_heap._control.rep[i]; } // Now zero all control bits _heap._control[] = 0; // EXCEPT for the _allocStart block itself markAsUsed(_allocStart.rep); } // Currently unused private bool markAsUsed(void[] b) { // Locate position immutable pos = b.ptr - _heap._payload.ptr; assert(pos % _heap.blockSize == 0); auto blockIdx = pos / _heap.blockSize; if (_heap._control[blockIdx]) return false; // Round up size to multiple of block size auto blocks = b.length.divideRoundUp(_heap.blockSize); _heap._control[blockIdx .. blockIdx + blocks] = 1; return true; } // Currently unused private void doneMarking() { // Nothing to do, what's free stays free. } } unittest { auto h = BitmappedBlockWithInternalPointers!(4096)(new void[4096 * 1024]); auto b = h.allocate(123); assert(b.length == 123); const p = h.resolveInternalPointer(b.ptr + 17); assert(p.ptr is b.ptr); assert(p.length >= b.length); b = h.allocate(4096); assert(h.resolveInternalPointer(b.ptr) is b); assert(h.resolveInternalPointer(b.ptr + 11) is b); assert(h.resolveInternalPointer(b.ptr - 40_970) is null); assert(h.expand(b, 1)); assert(b.length == 4097); assert(h.resolveInternalPointer(b.ptr + 4096).ptr is b.ptr); } /** Returns the number of most significant ones before a zero can be found in $(D x). If $(D x) contains no zeros (i.e. is equal to $(D ulong.max)), returns 64. */ private uint leadingOnes(ulong x) { uint result = 0; while (cast(long) x < 0) { ++result; x <<= 1; } return result; } unittest { assert(leadingOnes(0) == 0); assert(leadingOnes(~0UL) == 64); assert(leadingOnes(0xF000_0000_0000_0000) == 4); assert(leadingOnes(0xE400_0000_0000_0000) == 3); assert(leadingOnes(0xC700_0200_0000_0000) == 2); assert(leadingOnes(0x8000_0030_0000_0000) == 1); assert(leadingOnes(0x2000_0000_0000_0000) == 0); } /** Finds a run of contiguous ones in $(D x) of length at least $(D n). */ private uint findContigOnes(ulong x, uint n) { while (n > 1) { immutable s = n >> 1; x &= x << s; n -= s; } return leadingOnes(~x); } unittest { assert(findContigOnes(0x0000_0000_0000_0300, 2) == 54); assert(findContigOnes(~0UL, 1) == 0); assert(findContigOnes(~0UL, 2) == 0); assert(findContigOnes(~0UL, 32) == 0); assert(findContigOnes(~0UL, 64) == 0); assert(findContigOnes(0UL, 1) == 64); assert(findContigOnes(0x4000_0000_0000_0000, 1) == 1); assert(findContigOnes(0x0000_0F00_0000_0000, 4) == 20); } /* Unconditionally sets the bits from lsb through msb in w to zero. */ private void setBits(ref ulong w, uint lsb, uint msb) { assert(lsb <= msb && msb < 64); const mask = (ulong.max << lsb) & (ulong.max >> (63 - msb)); w |= mask; } unittest { ulong w; w = 0; setBits(w, 0, 63); assert(w == ulong.max); w = 0; setBits(w, 1, 63); assert(w == ulong.max - 1); w = 6; setBits(w, 0, 1); assert(w == 7); w = 6; setBits(w, 3, 3); assert(w == 14); } /* Are bits from lsb through msb in w zero? If so, make then 1 and return the resulting w. Otherwise, just return 0. */ private bool setBitsIfZero(ref ulong w, uint lsb, uint msb) { assert(lsb <= msb && msb < 64); const mask = (ulong.max << lsb) & (ulong.max >> (63 - msb)); if (w & mask) return false; w |= mask; return true; } // Assigns bits in w from lsb through msb to zero. private void resetBits(ref ulong w, uint lsb, uint msb) { assert(lsb <= msb && msb < 64); const mask = (ulong.max << lsb) & (ulong.max >> (63 - msb)); w &= ~mask; } /* Bit disposition is MSB=0 (leftmost, big endian). */ private struct BitVector { ulong[] _rep; auto rep() { return _rep; } this(ulong[] data) { _rep = data; } void opSliceAssign(bool b) { _rep[] = b ? ulong.max : 0; } void opSliceAssign(bool b, ulong x, ulong y) { assert(x <= y && y <= _rep.length * 64); if (x == y) return; --y; assert(x / 64 <= size_t.max); immutable i1 = cast(size_t) (x / 64); immutable uint b1 = 63 - x % 64; assert(y / 64 <= size_t.max); immutable i2 = cast(size_t) (y / 64); immutable uint b2 = 63 - y % 64; assert(i1 <= i2 && i2 < _rep.length); if (i1 == i2) { // Inside the same word assert(b1 >= b2); if (b) setBits(_rep[i1], b2, b1); else resetBits(_rep[i1], b2, b1); } else { // Spans multiple words assert(i1 < i2); if (b) setBits(_rep[i1], 0, b1); else resetBits(_rep[i1], 0, b1); _rep[i1 + 1 .. i2] = b; if (b) setBits(_rep[i2], b2, 63); else resetBits(_rep[i2], b2, 63); } } bool opIndex(ulong x) { assert(x < length); return (_rep[cast(size_t) (x / 64)] & (0x8000_0000_0000_0000UL >> (x % 64))) != 0; } void opIndexAssign(bool b, ulong x) { assert(x / 64 <= size_t.max); immutable i = cast(size_t) (x / 64); immutable j = 0x8000_0000_0000_0000UL >> (x % 64); if (b) _rep[i] |= j; else _rep[i] &= ~j; } ulong length() const { return _rep.length * 64; } /* Returns the index of the first 1 to the right of i (including i itself), or length if not found. */ ulong find1(ulong i) { assert(i < length); assert(i / 64 <= size_t.max); auto w = cast(size_t) (i / 64); immutable b = i % 64; // 0 through 63, 0 when i == 0 immutable mask = ulong.max >> b; if (auto current = _rep[w] & mask) { // Great, found return w * 64 + leadingOnes(~current); } // The current word doesn't have the solution, find the leftmost 1 // going to the right. for (++w; w < _rep.length; ++w) { if (auto current = _rep[w]) { return w * 64 + leadingOnes(~current); } } return length; } /* Returns the index of the first 1 to the left of i (including i itself), or ulong.max if not found. */ ulong find1Backward(ulong i) { assert(i < length); auto w = cast(size_t) (i / 64); immutable b = 63 - (i % 64); // 0 through 63, 63 when i == 0 immutable mask = ~((1UL << b) - 1); assert(mask != 0); // First, let's see if the current word has a bit larger than ours. if (auto currentWord = _rep[w] & mask) { // Great, this word contains the result. return w * 64 + 63 - currentWord.trailingZeros; } // The current word doesn't have the solution, find the rightmost 1 // going to the left. while (w >= 1) { --w; if (auto currentWord = _rep[w]) return w * 64 + (63 - currentWord.trailingZeros); } return ulong.max; } /// Are all bits zero? bool allAre0() const { foreach (w; _rep) if (w) return false; return true; } /// Are all bits one? bool allAre1() const { foreach (w; _rep) if (w != ulong.max) return false; return true; } ulong findZeros(immutable size_t howMany, ulong start) { assert(start < length); assert(howMany > 64); auto i = cast(size_t) (start / 64); while (_rep[i] & 1) { // No trailing zeros in this word, try the next one if (++i == _rep.length) return ulong.max; start = i * 64; } // Adjust start to have only trailing zeros after it auto prefixLength = 64; while (_rep[i] & (ulong.max >> (64 - prefixLength))) { assert(prefixLength > 0); --prefixLength; ++start; } assert(howMany > prefixLength); auto needed = howMany - prefixLength; for (++i; needed >= 64; needed -= 64, ++i) { if (i >= _rep.length) return ulong.max; if (_rep[i] != 0) return findZeros(howMany, i * 64); } // Leftover < 64 bits assert(needed < 64); if (!needed) return start; if (i >= _rep.length) return ulong.max; if (leadingOnes(~_rep[i]) >= needed) return start; return findZeros(howMany, i * 64); } } unittest { auto v = BitVector(new ulong[10]); assert(v.length == 640); v[] = 0; v[53] = 1; assert(v[52] == 0); assert(v[53] == 1); assert(v[54] == 0); v[] = 0; v[53 .. 55] = 1; assert(v[52] == 0); assert(v[53] == 1); assert(v[54] == 1); assert(v[55] == 0); v[] = 0; v[2 .. 65] = 1; assert(v.rep[0] == 0x3FFF_FFFF_FFFF_FFFF); assert(v.rep[1] == 0x8000_0000_0000_0000); assert(v.rep[2] == 0); v[] = 0; assert(v.find1Backward(0) == ulong.max); assert(v.find1Backward(43) == ulong.max); assert(v.find1Backward(83) == ulong.max); v[0] = 1; assert(v.find1Backward(0) == 0); assert(v.find1Backward(43) == 0); import std.conv : text; assert(v.find1Backward(83) == 0, text(v.find1Backward(83))); v[0] = 0; v[101] = 1; assert(v.find1Backward(0) == ulong.max); assert(v.find1Backward(43) == ulong.max); assert(v.find1Backward(83) == ulong.max); assert(v.find1Backward(100) == ulong.max); assert(v.find1Backward(101) == 101); assert(v.find1Backward(553) == 101); v[0 .. v.length] = 0; v[v.length .. v.length] = 0; v[0 .. 0] = 0; v[] = 0; assert(v.find1(0) == v.length); v[139] = 1; assert(v.find1(0) == 139); assert(v.find1(100) == 139); assert(v.find1(138) == 139); assert(v.find1(139) == 139); assert(v.find1(140) == v.length); v[] = 0; assert(v.findZeros(100, 0) == 0); foreach (i; 0 .. 500) assert(v.findZeros(100, i) == i, text(v.findZeros(100, i), " != ", i)); assert(v.findZeros(540, 99) == 99); assert(v.findZeros(99, 540) == 540); assert(v.findZeros(540, 100) == 100); assert(v.findZeros(640, 0) == 0); assert(v.findZeros(641, 1) == ulong.max); assert(v.findZeros(641, 100) == ulong.max); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/bucketizer.d0000664000175000017500000001667512776215007030050 0ustar kaikaimodule std.experimental.allocator.building_blocks.bucketizer; /** A $(D Bucketizer) uses distinct allocators for handling allocations of sizes in the intervals $(D [min, min + step - 1]), $(D [min + step, min + 2 * step - 1]), $(D [min + 2 * step, min + 3 * step - 1]), $(D ...), $(D [max - step + 1, max]). $(D Bucketizer) holds a fixed-size array of allocators and dispatches calls to them appropriately. The size of the array is $(D (max + 1 - min) / step), which must be an exact division. Allocations for sizes smaller than $(D min) or larger than $(D max) are illegal for $(D Bucketizer). To handle them separately, $(D Segregator) may be of use. */ struct Bucketizer(Allocator, size_t min, size_t max, size_t step) { import std.traits : hasMember; import common = std.experimental.allocator.common : roundUpToMultipleOf, reallocate, Ternary; static assert((max - (min - 1)) % step == 0, "Invalid limits when instantiating " ~ Bucketizer.stringof); //static if (min == chooseAtRuntime) size_t _min; //else alias _min = min; //static if (max == chooseAtRuntime) size_t _max; //else alias _max = max; //static if (step == chooseAtRuntime) size_t _step; //else alias _step = step; // state { /** The array of allocators is publicly available for e.g. initialization and inspection. */ Allocator[(max + 1 - min) / step] buckets; // } private Allocator* allocatorFor(size_t n) { const i = (n - min) / step; return i < buckets.length ? buckets.ptr + i : null; } /** The alignment offered is the same as $(D Allocator.alignment). */ enum uint alignment = Allocator.alignment; /** Rounds up to the maximum size of the bucket in which $(D bytes) falls. */ size_t goodAllocSize(size_t bytes) const { // round up bytes such that bytes - min + 1 is a multiple of step assert(bytes >= min); const min_1 = min - 1; return min_1 + roundUpToMultipleOf(bytes - min_1, step); } /** Directs the call to either one of the $(D buckets) allocators. */ void[] allocate(size_t bytes) { if (!bytes) return null; if (auto a = allocatorFor(bytes)) { const actual = goodAllocSize(bytes); auto result = a.allocate(actual); return result.ptr ? result.ptr[0 .. bytes] : null; } return null; } /** Directs the call to either one of the $(D buckets) allocators. Defined only if `Allocator` defines `alignedAllocate`. */ static if (hasMember!(Allocator, "alignedAllocate")) void[] alignedAllocate(size_t bytes, uint a) { if (!bytes) return null; if (auto a = allocatorFor(b.length)) { const actual = goodAllocSize(bytes); auto result = a.alignedAllocate(actual); return result.ptr ? result.ptr[0 .. bytes] : null; } return null; } /** This method allows expansion within the respective bucket range. It succeeds if both $(D b.length) and $(D b.length + delta) fall in a range of the form $(D [min + k * step, min + (k + 1) * step - 1]). */ bool expand(ref void[] b, size_t delta) { if (!b.ptr) { b = allocate(delta); return b.length == delta; } assert(b.length >= min && b.length <= max); const available = goodAllocSize(b.length); const desired = b.length + delta; if (available < desired) return false; b = b.ptr[0 .. desired]; return true; } /** This method allows reallocation within the respective bucket range. If both $(D b.length) and $(D size) fall in a range of the form $(D [min + k * step, min + (k + 1) * step - 1]), then reallocation is in place. Otherwise, reallocation with moving is attempted. */ bool reallocate(ref void[] b, size_t size) { if (size == 0) { deallocate(b); b = null; return true; } if (size >= b.length) { return expand(b, size - b.length); } assert(b.length >= min && b.length <= max); if (goodAllocSize(size) == goodAllocSize(b.length)) { b = b.ptr[0 .. size]; return true; } // Move cross buckets return common.reallocate(this, b, size); } /** Similar to `reallocate`, with alignment. Defined only if `Allocator` defines `alignedReallocate`. */ static if (hasMember!(Allocator, "alignedReallocate")) bool alignedReallocate(ref void[] b, size_t size, uint a) { if (size == 0) { deallocate(b); b = null; return true; } if (size >= b.length) { return expand(b, size - b.length); } assert(b.length >= min && b.length <= max); if (goodAllocSize(size) == goodAllocSize(b.length)) { b = b.ptr[0 .. size]; return true; } // Move cross buckets return .alignedReallocate(this, b, size, a); } /** Defined only if `Allocator` defines `owns`. Finds the owner of `b` and forwards the call to it. */ static if (hasMember!(Allocator, "owns")) Ternary owns(void[] b) { if (!b.ptr) return Ternary.no; if (auto a = allocatorFor(b.length)) { const actual = goodAllocSize(b.length); return a.owns(b.ptr[0 .. actual]); } return Ternary.no; } /** This method is only defined if $(D Allocator) defines $(D deallocate). */ static if (hasMember!(Allocator, "deallocate")) bool deallocate(void[] b) { if (!b.ptr) return true; if (auto a = allocatorFor(b.length)) { a.deallocate(b.ptr[0 .. goodAllocSize(b.length)]); } return true; } /** This method is only defined if all allocators involved define $(D deallocateAll), and calls it for each bucket in turn. Returns `true` if all allocators could deallocate all. */ static if (hasMember!(Allocator, "deallocateAll")) bool deallocateAll() { bool result = true; foreach (ref a; buckets) { if (!a.deallocateAll()) result = false; } return result; } /** This method is only defined if all allocators involved define $(D resolveInternalPointer), and tries it for each bucket in turn. */ static if (hasMember!(Allocator, "resolveInternalPointer")) void[] resolveInternalPointer(void* p) { foreach (ref a; buckets) { if (auto r = a.resolveInternalPointer(p)) return r; } return null; } } /// unittest { import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; import std.experimental.allocator.building_blocks.free_list : FreeList; import std.experimental.allocator.building_blocks.region : Region; import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.common : unbounded, Ternary; import std.algorithm : max; Bucketizer!( FreeList!( AllocatorList!( (size_t n) => Region!Mallocator(max(n, 1024 * 1024))), 0, unbounded), 65, 512, 64) a; auto b = a.allocate(400); assert(b.length == 400); assert(a.owns(b) == Ternary.yes); a.deallocate(b); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/free_tree.d0000664000175000017500000003042312776215007027624 0ustar kaikaimodule std.experimental.allocator.building_blocks.free_tree; import std.experimental.allocator.common; //debug = std_experimental_allocator_free_tree; /** The Free Tree allocator, stackable on top of any other allocator, bears similarity with the free list allocator. Instead of a singly-linked list of previously freed blocks, it maintains a binary search tree. This allows the Free Tree allocator to manage blocks of arbitrary lengths and search them efficiently. Common uses of $(D FreeTree) include: $(UL $(LI Adding $(D deallocate) capability to an allocator that lacks it (such as simple regions).) $(LI Getting the benefits of multiple adaptable freelists that do not need to be tuned for one specific size but insted automatically adapts itself to frequently used sizes.) ) The free tree has special handling of duplicates (a singly-linked list per node) in anticipation of large number of duplicates. Allocation time from the free tree is expected to be $(BIGOH log n) where $(D n) is the number of distinct sizes (not total nodes) kept in the free tree. Allocation requests first search the tree for a buffer of suitable size deallocated in the past. If a match is found, the node is removed from the tree and the memory is returned. Otherwise, the allocation is directed to $(D ParentAllocator). If at this point $(D ParentAllocator) also fails to allocate, $(D FreeTree) frees everything and then tries the parent allocator again. Upon deallocation, the deallocated block is inserted in the internally maintained free tree (not returned to the parent). The free tree is not kept balanced. Instead, it has a last-in-first-out flavor because newly inserted blocks are rotated to the root of the tree. That way allocations are cache friendly and also frequently used sizes are more likely to be found quickly, whereas seldom used sizes migrate to the leaves of the tree. $(D FreeTree) rounds up small allocations to at least $(D 4 * size_t.sizeof), which on 64-bit system is one cache line size. If very small objects need to be efficiently allocated, the $(D FreeTree) should be fronted with an appropriate small object allocator. The following methods are defined if $(D ParentAllocator) defines them, and forward to it: $(D allocateAll), $(D expand), $(D owns), $(D reallocate). */ struct FreeTree(ParentAllocator) { static assert(ParentAllocator.alignment % size_t.alignof == 0, "FreeTree must be on top of a word-aligned allocator"); import std.algorithm : min, max, swap; import std.traits : hasMember; // State { static if (stateSize!ParentAllocator) private ParentAllocator parent; else private alias parent = ParentAllocator.instance; private Node* root; // that's the entire added state // } private struct Node { Node*[2] kid; Node* sibling; size_t size; ref Node* left() { return kid[0]; } ref Node* right() { return kid[1]; } } // Removes "which" from the tree, returns the memory it occupied private void[] remove(ref Node* which) { assert(which); assert(!which.sibling); auto result = (cast(ubyte*) which)[0 .. which.size]; if (!which.right) which = which.left; else if (!which.left) which = which.right; else { // result has two kids static bool toggler; // Crude randomization: alternate left/right choices toggler = !toggler; auto newRoot = which.kid[toggler], orphan = which.kid[!toggler]; which = newRoot; for (Node* n = void; (n = newRoot.kid[!toggler]) !is null; ) { newRoot = n; } newRoot.kid[!toggler] = orphan; } return result; } private void[] findAndRemove(ref Node* n, size_t s) { if (!n) return null; if (s == n.size) { if (auto sis = n.sibling) { // Nice, give away one from the freelist auto result = (cast(ubyte*) sis)[0 .. sis.size]; n.sibling = sis.sibling; return result; } return remove(n); } return findAndRemove(n.kid[s > n.size], s); } debug(std_experimental_allocator_free_tree) private void dump() { import std.stdio : writef, writefln, writeln; writeln(typeof(this).stringof, "@", &this, " {"); scope(exit) writeln("}"); if (!root) return; static void recurse(Node* n, uint indent = 4) { if (!n) { writefln("%*s(null)", indent, ""); return; } for (auto sis = n; sis; sis = sis.sibling) { writef("%*s%x (%s bytes) ", indent, "", cast(void*) n, n.size); } writeln; if (!n.left && !n.right) return; recurse(n.left, indent + 4); recurse(n.right, indent + 4); } recurse(root); } private string formatSizes() { string result = "("; void recurse(Node* n) { if (!n) { result ~= "_"; return; } import std.conv : to; result ~= to!string(n.size); for (auto sis = n.sibling; sis; sis = sis.sibling) { result ~= "+moar"; } if (n.left || n.right) { result ~= " ("; recurse(n.left); result ~= ' '; recurse(n.right); result ~= ")"; } } recurse(root); return result ~= ")"; } private static void rotate(ref Node* parent, bool toRight) { assert(parent); auto opposing = parent.kid[!toRight]; if (!opposing) return; parent.kid[!toRight] = opposing.kid[toRight]; opposing.kid[toRight] = parent; parent = opposing; } // Inserts which into the tree, making it the new root private void insertAsRoot(Node* which) { assert(which); debug(std_experimental_allocator_free_tree) { assertValid; scope(exit) assertValid; } static void recurse(ref Node* where, Node* which) { if (!where) { where = which; which.left = null; which.right = null; which.sibling = null; return; } if (which.size == where.size) { // Special handling of duplicates which.sibling = where.sibling; where.sibling = which; which.left = null; which.right = null; return; } bool goRight = which.size > where.size; recurse(where.kid[goRight], which); rotate(where, !goRight); } recurse(root, which); } private void assertValid() { debug(std_experimental_allocator_free_tree) { static bool isBST(Node* n, size_t lb = 0, size_t ub = size_t.max) { if (!n) return true; for (auto sis = n.sibling; sis; sis = sis.sibling) { assert(n.size == sis.size); assert(sis.left is null); assert(sis.right is null); } return lb < n.size && n.size <= ub && isBST(n.left, lb, min(ub, n.size)) && isBST(n.right, max(lb, n.size), ub); } if (isBST(root)) return; dump; assert(0); } } /** The $(D FreeTree) is word aligned. */ enum uint alignment = size_t.alignof; /** The $(D FreeTree) allocator is noncopyable. */ this(this) @disable; /** The destructor of $(D FreeTree) releases all memory back to the parent allocator. */ static if (hasMember!(ParentAllocator, "deallocate")) ~this() { clear; } /** Returns $(D parent.goodAllocSize(max(Node.sizeof, s))). */ static if (stateSize!ParentAllocator) size_t goodAllocSize(size_t s) { return parent.goodAllocSize(max(Node.sizeof, s)); } else static size_t goodAllocSize(size_t s) { return parent.goodAllocSize(max(Node.sizeof, s)); } /** Allocates $(D n) bytes of memory. First consults the free tree, and returns from it if a suitably sized block is found. Otherwise, the parent allocator is tried. If allocation from the parent succeeds, the allocated block is returned. Otherwise, the free tree tries an alternate strategy: If $(D ParentAllocator) defines $(D deallocate), $(D FreeTree) releases all of its contents and tries again. TODO: Splitting and coalescing should be implemented if $(D ParentAllocator) does not defined $(D deallocate). */ void[] allocate(size_t n) { assertValid; auto result = findAndRemove(root, goodAllocSize(n)); if (result.ptr) return result.ptr[0 .. n]; // Parent ran out of juice, desperation mode on static if (hasMember!(ParentAllocator, "deallocate")) { clear; return parent.allocate(n); } else { // TODO: get smart here return null; } } // Forwarding methods mixin(forwardToMember("parent", "allocateAll", "expand", "owns", "reallocate")); /** Places $(D b) into the free tree. */ bool deallocate(void[] b) { if (!b.ptr) return true; auto which = cast(Node*) b.ptr; which.size = goodAllocSize(b.length); // deliberately don't initialize which.left and which.right assert(which.size >= Node.sizeof); insertAsRoot(which); return true; } unittest // test a few simple configurations { import std.experimental.allocator.gc_allocator; FreeTree!GCAllocator a; auto b1 = a.allocate(10000); auto b2 = a.allocate(20000); auto b3 = a.allocate(30000); assert(b1.ptr && b2.ptr && b3.ptr); a.deallocate(b1); a.deallocate(b3); a.deallocate(b2); assert(a.formatSizes == "(20480 (12288 32768))", a.formatSizes); b1 = a.allocate(10000); assert(a.formatSizes == "(20480 (_ 32768))", a.formatSizes); b1 = a.allocate(30000); assert(a.formatSizes == "(20480)", a.formatSizes); b1 = a.allocate(20000); assert(a.formatSizes == "(_)", a.formatSizes); } unittest // build a complex free tree { import std.experimental.allocator.gc_allocator, std.range; FreeTree!GCAllocator a; uint[] sizes = [3008,704,1856,576,1632,672,832,1856,1120,2656,1216,672, 448,992,2400,1376,2688,2656,736,1440]; void[][] allocs; foreach (s; sizes) allocs ~= a.allocate(s); foreach_reverse (b; allocs) { assert(b.ptr); a.deallocate(b); } a.assertValid; allocs = null; foreach (s; sizes) allocs ~= a.allocate(s); assert(a.root is null); a.assertValid; } /** Defined if $(D ParentAllocator.deallocate) exists, and returns to it all memory held in the free tree. */ static if (hasMember!(ParentAllocator, "deallocate")) void clear() { void recurse(Node* n) { if (!n) return; recurse(n.left); recurse(n.right); parent.deallocate((cast(ubyte*) n)[0 .. n.size]); } recurse(root); root = null; } /** Defined if $(D ParentAllocator.deallocateAll) exists, and forwards to it. Also nullifies the free tree (it's assumed the parent frees all memory stil managed by the free tree). */ static if (hasMember!(ParentAllocator, "deallocateAll")) bool deallocateAll() { // This is easy, just nuke the root and deallocate all from the // parent root = null; return parent.deallocateAll; } } unittest { import std.experimental.allocator.gc_allocator; testAllocator!(() => FreeTree!GCAllocator()); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/fallback_allocator.d0000664000175000017500000002575212776215007031474 0ustar kaikaimodule std.experimental.allocator.building_blocks.fallback_allocator; import std.experimental.allocator.common; /** $(D FallbackAllocator) is the allocator equivalent of an "or" operator in algebra. An allocation request is first attempted with the $(D Primary) allocator. If that returns $(D null), the request is forwarded to the $(D Fallback) allocator. All other requests are dispatched appropriately to one of the two allocators. In order to work, $(D FallbackAllocator) requires that $(D Primary) defines the $(D owns) method. This is needed in order to decide which allocator was responsible for a given allocation. $(D FallbackAllocator) is useful for fast, special-purpose allocators backed up by general-purpose allocators. The example below features a stack region backed up by the $(D GCAllocator). */ struct FallbackAllocator(Primary, Fallback) { import std.algorithm.comparison : min; import std.traits : hasMember; unittest { testAllocator!(() => FallbackAllocator()); } /// The primary allocator. static if (stateSize!Primary) Primary primary; else alias primary = Primary.instance; /// The fallback allocator. static if (stateSize!Fallback) Fallback fallback; else alias fallback = Fallback.instance; /** If both $(D Primary) and $(D Fallback) are stateless, $(D FallbackAllocator) defines a static instance called `instance`. */ static if (!stateSize!Primary && !stateSize!Fallback) { static FallbackAllocator instance; } /** The alignment offered is the minimum of the two allocators' alignment. */ enum uint alignment = min(Primary.alignment, Fallback.alignment); /** Allocates memory trying the primary allocator first. If it returns $(D null), the fallback allocator is tried. */ void[] allocate(size_t s) { auto result = primary.allocate(s); return result.length == s ? result : fallback.allocate(s); } /** $(D FallbackAllocator) offers $(D alignedAllocate) iff at least one of the allocators also offers it. It attempts to allocate using either or both. */ static if (hasMember!(Primary, "alignedAllocate") || hasMember!(Fallback, "alignedAllocate")) void[] alignedAllocate(size_t s, uint a) { static if (hasMember!(Primary, "alignedAllocate")) {{ auto result = primary.alignedAllocate(s, a); if (result.length == s) return result; }} static if (hasMember!(Fallback, "alignedAllocate")) {{ auto result = fallback.alignedAllocate(s, a); if (result.length == s) return result; }} return null; } /** $(D expand) is defined if and only if at least one of the allocators defines $(D expand). It works as follows. If $(D primary.owns(b)), then the request is forwarded to $(D primary.expand) if it is defined, or fails (returning $(D false)) otherwise. If $(D primary) does not own $(D b), then the request is forwarded to $(D fallback.expand) if it is defined, or fails (returning $(D false)) otherwise. */ static if (hasMember!(Primary, "owns") && (hasMember!(Primary, "expand") || hasMember!(Fallback, "expand"))) bool expand(ref void[] b, size_t delta) { if (!delta) return true; if (!b.ptr) { b = allocate(delta); return b.length == delta; } if (primary.owns(b) == Ternary.yes) { static if (hasMember!(Primary, "expand")) return primary.expand(b, delta); else return false; } static if (hasMember!(Fallback, "expand")) return fallback.expand(b, delta); else return false; } /** $(D reallocate) works as follows. If $(D primary.owns(b)), then $(D primary.reallocate(b, newSize)) is attempted. If it fails, an attempt is made to move the allocation from $(D primary) to $(D fallback). If $(D primary) does not own $(D b), then $(D fallback.reallocate(b, newSize)) is attempted. If that fails, an attempt is made to move the allocation from $(D fallback) to $(D primary). */ static if (hasMember!(Primary, "owns")) bool reallocate(ref void[] b, size_t newSize) { bool crossAllocatorMove(From, To)(ref From from, ref To to) { auto b1 = to.allocate(newSize); if (b1.length != newSize) return false; if (b.length < newSize) b1[0 .. b.length] = b[]; else b1[] = b[0 .. newSize]; static if (hasMember!(From, "deallocate")) from.deallocate(b); b = b1; return true; } if (b is null || primary.owns(b) == Ternary.yes) { return primary.reallocate(b, newSize) // Move from primary to fallback || crossAllocatorMove(primary, fallback); } return fallback.reallocate(b, newSize) // Interesting. Move from fallback to primary. || crossAllocatorMove(fallback, primary); } static if (hasMember!(Primary, "owns") && (hasMember!(Primary, "alignedAllocate") || hasMember!(Fallback, "alignedAllocate"))) bool alignedReallocate(ref void[] b, size_t newSize, uint a) { bool crossAllocatorMove(From, To)(ref From from, ref To to) { static if (!hasMember!(To, "alignedAllocate")) { return false; } else { auto b1 = to.alignedAllocate(newSize, a); if (b1.length != newSize) return false; if (b.length < newSize) b1[0 .. b.length] = b[]; else b1[] = b[0 .. newSize]; static if (hasMember!(From, "deallocate")) from.deallocate(b); b = b1; return true; } } static if (hasMember!(Primary, "alignedAllocate")) { if (b is null || primary.owns(b) == Ternary.yes) { return primary.alignedReallocate(b, newSize, a) || crossAllocatorMove(primary, fallback); } } static if (hasMember!(Fallback, "alignedAllocate")) { return fallback.alignedReallocate(b, newSize, a) || crossAllocatorMove(fallback, primary); } else { return false; } } /** $(D owns) is defined if and only if both allocators define $(D owns). Returns $(D primary.owns(b) | fallback.owns(b)). */ static if (hasMember!(Primary, "owns") && hasMember!(Fallback, "owns")) Ternary owns(void[] b) { return primary.owns(b) | fallback.owns(b); } /** $(D resolveInternalPointer) is defined if and only if both allocators define it. */ static if (hasMember!(Primary, "resolveInternalPointer") && hasMember!(Fallback, "resolveInternalPointer")) void[] resolveInternalPointer(void* p) { if (auto r = primary.resolveInternalPointer(p)) return r; if (auto r = fallback.resolveInternalPointer(p)) return r; return null; } /** $(D deallocate) is defined if and only if at least one of the allocators define $(D deallocate). It works as follows. If $(D primary.owns(b)), then the request is forwarded to $(D primary.deallocate) if it is defined, or is a no-op otherwise. If $(D primary) does not own $(D b), then the request is forwarded to $(D fallback.deallocate) if it is defined, or is a no-op otherwise. */ static if (hasMember!(Primary, "owns") && (hasMember!(Primary, "deallocate") || hasMember!(Fallback, "deallocate"))) bool deallocate(void[] b) { if (primary.owns(b) == Ternary.yes) { static if (hasMember!(Primary, "deallocate")) return primary.deallocate(b); else return false; } else { static if (hasMember!(Fallback, "deallocate")) return fallback.deallocate(b); else return false; } } /** $(D empty) is defined if both allocators also define it. Returns: $(D primary.empty & fallback.empty) */ static if (hasMember!(Primary, "empty") && hasMember!(Fallback, "empty")) Ternary empty() { return primary.empty & fallback.empty; } } unittest { import std.experimental.allocator.building_blocks.region : InSituRegion; import std.experimental.allocator.gc_allocator : GCAllocator; import std.conv : text; FallbackAllocator!(InSituRegion!16_384, GCAllocator) a; // This allocation uses the stack auto b1 = a.allocate(1024); assert(b1.length == 1024, text(b1.length)); assert(a.primary.owns(b1) == Ternary.yes); // This large allocation will go to the Mallocator auto b2 = a.allocate(1024 * 1024); assert(a.primary.owns(b2) == Ternary.no); a.deallocate(b1); a.deallocate(b2); } /* Forwards an argument from one function to another */ private auto ref forward(alias arg)() { static if (__traits(isRef, arg)) { return arg; } else { import std.algorithm : move; return move(arg); } } unittest { void fun(T)(auto ref T, string) { /* ... */ } void gun(T...)(auto ref T args) { fun(forward!(args[0]), forward!(args[1])); } gun(42, "hello"); int x; gun(x, "hello"); } unittest { static void checkByRef(T)(auto ref T value) { static assert(__traits(isRef, value)); } static void checkByVal(T)(auto ref T value) { static assert(!__traits(isRef, value)); } static void test1(ref int a) { checkByRef(forward!a); } static void test2(int a) { checkByVal(forward!a); } static void test3() { int a; checkByVal(forward!a); } } /** Convenience function that uses type deduction to return the appropriate $(D FallbackAllocator) instance. To initialize with allocators that don't have state, use their $(D it) static member. */ FallbackAllocator!(Primary, Fallback) fallbackAllocator(Primary, Fallback)(auto ref Primary p, auto ref Fallback f) { alias R = FallbackAllocator!(Primary, Fallback); import std.algorithm : move; static if (stateSize!Primary) static if (stateSize!Fallback) return R(forward!p, forward!f); else return R(forward!p); else static if (stateSize!Fallback) return R(forward!f); else return R(); } /// unittest { import std.experimental.allocator.building_blocks.region : Region; import std.experimental.allocator.gc_allocator : GCAllocator; auto a = fallbackAllocator(Region!GCAllocator(1024), GCAllocator.instance); auto b1 = a.allocate(1020); assert(b1.length == 1020); assert(a.primary.owns(b1) == Ternary.yes); auto b2 = a.allocate(10); assert(b2.length == 10); assert(a.primary.owns(b2) == Ternary.no); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/building_blocks/quantizer.d0000664000175000017500000001765412776215007027721 0ustar kaikaimodule std.experimental.allocator.building_blocks.quantizer; import std.experimental.allocator.common; /** This allocator sits on top of $(D ParentAllocator) and quantizes allocation sizes, usually from arbitrary positive numbers to a small set of round numbers (e.g. powers of two, page sizes etc). This technique is commonly used to: $(UL $(LI Preallocate more memory than requested such that later on, when reallocation is needed (e.g. to grow an array), expansion can be done quickly in place. Reallocation to smaller sizes is also fast (in-place) when the new size requested is within the same quantum as the existing size. Code that's reallocation-heavy can therefore benefit from fronting a generic allocator with a $(D Quantizer). These advantages are present even if $(D ParentAllocator) does not support reallocation at all.) $(LI Improve behavior of allocators sensitive to allocation sizes, such as $(D FreeList) and $(D FreeTree). Rounding allocation requests up makes for smaller free lists/trees at the cost of slack memory (internal fragmentation).) ) The following methods are forwarded to the parent allocator if present: $(D allocateAll), $(D owns), $(D deallocateAll), $(D empty). Preconditions: $(D roundingFunction) must satisfy three constraints. These are not enforced (save for the use of $(D assert)) for the sake of efficiency. $(OL $(LI $(D roundingFunction(n) >= n) for all $(D n) of type $(D size_t);) $(LI $(D roundingFunction) must be monotonically increasing, i.e. $(D roundingFunction(n1) <= roundingFunction(n2)) for all $(D n1 < n2);) $(LI $(D roundingFunction) must be $(D pure), i.e. always return the same value for a given $(D n).) ) */ struct Quantizer(ParentAllocator, alias roundingFunction) { import std.traits : hasMember; /** The parent allocator. Depending on whether $(D ParentAllocator) holds state or not, this is a member variable or an alias for `ParentAllocator.instance`. */ static if (stateSize!ParentAllocator) { ParentAllocator parent; } else { alias parent = ParentAllocator.instance; static __gshared Quantizer instance; } /** Returns $(D roundingFunction(n)). */ size_t goodAllocSize(size_t n) { auto result = roundingFunction(n); assert(result >= n); return result; } /** Alignment is identical to that of the parent. */ enum alignment = ParentAllocator.alignment; /** Gets a larger buffer $(D buf) by calling $(D parent.allocate(goodAllocSize(n))). If $(D buf) is $(D null), returns $(D null). Otherwise, returns $(D buf[0 .. n]). */ void[] allocate(size_t n) { auto result = parent.allocate(goodAllocSize(n)); return result.ptr ? result.ptr[0 .. n] : null; } /** Defined only if $(D parent.alignedAllocate) exists and works similarly to $(D allocate) by forwarding to $(D parent.alignedAllocate(goodAllocSize(n), a)). */ static if (hasMember!(ParentAllocator, "alignedAllocate")) void[] alignedAllocate(size_t n, uint) { auto result = parent.alignedAllocate(goodAllocSize(n)); return result.ptr ? result.ptr[0 .. n] : null; } /** First checks whether there's enough slack memory preallocated for $(D b) by evaluating $(D b.length + delta <= goodAllocSize(b.length)). If that's the case, expands $(D b) in place. Otherwise, attempts to use $(D parent.expand) appropriately if present. */ bool expand(ref void[] b, size_t delta) { if (!b.ptr) { b = allocate(delta); return b.length == delta; } immutable allocated = goodAllocSize(b.length), needed = b.length + delta, neededAllocation = goodAllocSize(needed); assert(b.length <= allocated); assert(needed <= neededAllocation); assert(allocated <= neededAllocation); // Second test needed because expand must work for null pointers, too. if (allocated == neededAllocation) { // Nice! b = b.ptr[0 .. needed]; return true; } // Hail Mary static if (hasMember!(ParentAllocator, "expand")) { // Expand to the appropriate quantum auto original = b.ptr[0 .. allocated]; assert(goodAllocSize(needed) >= allocated); if (!parent.expand(original, neededAllocation - allocated)) return false; // Dial back the size b = original.ptr[0 .. needed]; return true; } else { return false; } } /** Expands or shrinks allocated block to an allocated size of $(D goodAllocSize(s)). Expansion occurs in place under the conditions required by $(D expand). Shrinking occurs in place if $(D goodAllocSize(b.length) == goodAllocSize(s)). */ bool reallocate(ref void[] b, size_t s) { if (!b.ptr) { b = allocate(s); return b.length == s; } if (s >= b.length && expand(b, s - b.length)) return true; immutable toAllocate = goodAllocSize(s), allocated = goodAllocSize(b.length); // Are the lengths within the same quantum? if (allocated == toAllocate) { // Reallocation (whether up or down) will be done in place b = b.ptr[0 .. s]; return true; } // Defer to parent (or global) with quantized size auto original = b.ptr[0 .. allocated]; if (!parent.reallocate(original, toAllocate)) return false; b = original.ptr[0 .. s]; return true; } /** Defined only if $(D ParentAllocator.alignedAllocate) exists. Expansion occurs in place under the conditions required by $(D expand). Shrinking occurs in place if $(D goodAllocSize(b.length) == goodAllocSize(s)). */ static if (hasMember!(ParentAllocator, "alignedAllocate")) bool alignedReallocate(ref void[] b, size_t s, uint a) { if (!b.ptr) { b = alignedAllocate(s); return b.length == s; } if (s >= b.length && expand(b, s - b.length)) return true; immutable toAllocate = goodAllocSize(s), allocated = goodAllocSize(b.length); // Are the lengths within the same quantum? if (allocated == toAllocate) { assert(b.ptr); // code above must have caught this // Reallocation (whether up or down) will be done in place b = b.ptr[0 .. s]; return true; } // Defer to parent (or global) with quantized size auto original = b.ptr[0 .. allocated]; if (!parent.alignedReallocate(original, toAllocate, a)) return false; b = original.ptr[0 .. s]; return true; } /** Defined if $(D ParentAllocator.deallocate) exists and forwards to $(D parent.deallocate(b.ptr[0 .. goodAllocSize(b.length)])). */ static if (hasMember!(ParentAllocator, "deallocate")) bool deallocate(void[] b) { if (!b.ptr) return true; return parent.deallocate(b.ptr[0 .. goodAllocSize(b.length)]); } // Forwarding methods mixin(forwardToMember("parent", "allocateAll", "owns", "deallocateAll", "empty")); } /// unittest { import std.experimental.allocator.building_blocks.free_tree : FreeTree; import std.experimental.allocator.gc_allocator : GCAllocator; // Quantize small allocations to a multiple of cache line, large ones to a // multiple of page size alias MyAlloc = Quantizer!( FreeTree!GCAllocator, n => n.roundUpToMultipleOf(n <= 16_384 ? 64 : 4096)); MyAlloc alloc; const buf = alloc.allocate(256); assert(buf.ptr); } unittest { import std.experimental.allocator.gc_allocator : GCAllocator; alias MyAlloc = Quantizer!(GCAllocator, (size_t n) => n.roundUpToMultipleOf(64)); testAllocator!(() => MyAlloc()); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/mmap_allocator.d0000664000175000017500000000404112776215007025521 0ustar kaikaimodule std.experimental.allocator.mmap_allocator; // MmapAllocator /** Allocator (currently defined only for Posix) using $(D $(LUCKY mmap)) and $(D $(LUCKY munmap)) directly. There is no additional structure: each call to $(D allocate(s)) issues a call to $(D mmap(null, s, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)), and each call to $(D deallocate(b)) issues $(D munmap(b.ptr, b.length)). So $(D MmapAllocator) is usually intended for allocating large chunks to be managed by fine-granular allocators. */ struct MmapAllocator { /// The one shared instance. static shared MmapAllocator instance; /** Alignment is page-size and hardcoded to 4096 (even though on certain systems it could be larger). */ enum size_t alignment = 4096; version(Posix) { /// Allocator API. void[] allocate(size_t bytes) shared { import core.sys.posix.sys.mman; if (!bytes) return null; auto p = mmap(null, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (p is MAP_FAILED) return null; return p[0 .. bytes]; } /// Ditto bool deallocate(void[] b) shared { import core.sys.posix.sys.mman : munmap; if (b.ptr) munmap(b.ptr, b.length) == 0 || assert(0); return true; } } else version(Windows) { import core.sys.windows.windows; /// Allocator API. void[] allocate(size_t bytes) shared { if (!bytes) return null; auto p = VirtualAlloc(null, bytes, MEM_COMMIT, PAGE_READWRITE); if (p == null) return null; return p[0 .. bytes]; } /// Ditto bool deallocate(void[] b) shared { return b.ptr is null || VirtualFree(b.ptr, 0, MEM_RELEASE) != 0; } } } unittest { alias alloc = MmapAllocator.instance; auto p = alloc.allocate(100); assert(p.length == 100); alloc.deallocate(p); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/mallocator.d0000664000175000017500000002377412776215007024702 0ustar kaikaimodule std.experimental.allocator.mallocator; import std.experimental.allocator.common; /** The C heap allocator. */ struct Mallocator { unittest { testAllocator!(() => Mallocator.instance); } /** The alignment is a static constant equal to $(D platformAlignment), which ensures proper alignment for any D data type. */ enum uint alignment = platformAlignment; /** Standard allocator methods per the semantics defined above. The $(D deallocate) and $(D reallocate) methods are $(D @system) because they may move memory around, leaving dangling pointers in user code. Somewhat paradoxically, $(D malloc) is $(D @safe) but that's only useful to safe programs that can afford to leak memory allocated. */ @trusted @nogc nothrow void[] allocate(size_t bytes) shared { import core.stdc.stdlib : malloc; if (!bytes) return null; auto p = malloc(bytes); return p ? p[0 .. bytes] : null; } /// Ditto @system @nogc nothrow bool deallocate(void[] b) shared { import core.stdc.stdlib : free; free(b.ptr); return true; } /// Ditto @system @nogc nothrow bool reallocate(ref void[] b, size_t s) shared { import core.stdc.stdlib : realloc; if (!s) { // fuzzy area in the C standard, see http://goo.gl/ZpWeSE // so just deallocate and nullify the pointer deallocate(b); b = null; return true; } auto p = cast(ubyte*) realloc(b.ptr, s); if (!p) return false; b = p[0 .. s]; return true; } /** Returns the global instance of this allocator type. The C heap allocator is thread-safe, therefore all of its methods and `it` itself are $(D shared). */ static shared Mallocator instance; } /// @nogc nothrow unittest { auto buffer = Mallocator.instance.allocate(1024 * 1024 * 4); scope(exit) Mallocator.instance.deallocate(buffer); //... } @nogc nothrow unittest { @nogc nothrow static void test(A)() { int* p = null; p = cast(int*) A.instance.allocate(int.sizeof); scope(exit) A.instance.deallocate(p[0 .. int.sizeof]); *p = 42; assert(*p == 42); } test!Mallocator(); } @nogc nothrow unittest { static void test(A)() { import std.experimental.allocator : make; Object p = null; p = A.instance.make!Object(); assert(p !is null); } test!Mallocator(); } version (Posix) @nogc nothrow private extern(C) int posix_memalign(void**, size_t, size_t); version (Windows) { // DMD Win 32 bit, DigitalMars C standard library misses the _aligned_xxx // functions family (snn.lib) version(CRuntime_DigitalMars) { // Helper to cast the infos written before the aligned pointer // this header keeps track of the size (required to realloc) and of // the base ptr (required to free). private struct AlignInfo { void* basePtr; size_t size; @nogc nothrow static AlignInfo* opCall(void* ptr) { return cast(AlignInfo*) (ptr - AlignInfo.sizeof); } } @nogc nothrow private void* _aligned_malloc(size_t size, size_t alignment) { import std.c.stdlib: malloc; size_t offset = alignment + size_t.sizeof * 2 - 1; // unaligned chunk void* basePtr = malloc(size + offset); if (!basePtr) return null; // get aligned location within the chunk void* alignedPtr = cast(void**)((cast(size_t)(basePtr) + offset) & ~(alignment - 1)); // write the header before the aligned pointer AlignInfo* head = AlignInfo(alignedPtr); head.basePtr = basePtr; head.size = size; return alignedPtr; } @nogc nothrow private void* _aligned_realloc(void* ptr, size_t size, size_t alignment) { import std.c.stdlib: free; import std.c.string: memcpy; if(!ptr) return _aligned_malloc(size, alignment); // gets the header from the exising pointer AlignInfo* head = AlignInfo(ptr); // gets a new aligned pointer void* alignedPtr = _aligned_malloc(size, alignment); if (!alignedPtr) { //to https://msdn.microsoft.com/en-us/library/ms235462.aspx //see Return value: in this case the original block is unchanged return null; } // copy exising data memcpy(alignedPtr, ptr, head.size); free(head.basePtr); return alignedPtr; } @nogc nothrow private void _aligned_free(void *ptr) { import std.c.stdlib: free; if (!ptr) return; AlignInfo* head = AlignInfo(ptr); free(head.basePtr); } } // DMD Win 64 bit, uses microsoft standard C library which implements them else { @nogc nothrow private extern(C) void* _aligned_malloc(size_t, size_t); @nogc nothrow private extern(C) void _aligned_free(void *memblock); @nogc nothrow private extern(C) void* _aligned_realloc(void *, size_t, size_t); } } /** Aligned allocator using OS-specific primitives, under a uniform API. */ struct AlignedMallocator { unittest { testAllocator!(() => typeof(this).instance); } /** The default alignment is $(D platformAlignment). */ enum uint alignment = platformAlignment; /** Forwards to $(D alignedAllocate(bytes, platformAlignment)). */ @trusted @nogc nothrow void[] allocate(size_t bytes) shared { if (!bytes) return null; return alignedAllocate(bytes, alignment); } /** Uses $(WEB man7.org/linux/man-pages/man3/posix_memalign.3.html, $(D posix_memalign)) on Posix and $(WEB msdn.microsoft.com/en-us/library/8z34s9c6(v=vs.80).aspx, $(D __aligned_malloc)) on Windows. */ version(Posix) @trusted @nogc nothrow void[] alignedAllocate(size_t bytes, uint a) shared { import core.stdc.errno : ENOMEM, EINVAL; assert(a.isGoodDynamicAlignment); void* result; auto code = posix_memalign(&result, a, bytes); if (code == ENOMEM) return null; else if (code == EINVAL) assert (0, "AlignedMallocator.alignment is not a power of two multiple of (void*).sizeof, according to posix_memalign!"); else if (code != 0) assert (0, "posix_memalign returned an unknown code!"); else return result[0 .. bytes]; } else version(Windows) @trusted @nogc nothrow void[] alignedAllocate(size_t bytes, uint a) shared { auto result = _aligned_malloc(bytes, a); return result ? result[0 .. bytes] : null; } else static assert(0); /** Calls $(D free(b.ptr)) on Posix and $(WEB msdn.microsoft.com/en-US/library/17b5h8td(v=vs.80).aspx, $(D __aligned_free(b.ptr))) on Windows. */ version (Posix) @system @nogc nothrow bool deallocate(void[] b) shared { import core.stdc.stdlib : free; free(b.ptr); return true; } else version (Windows) @system @nogc nothrow bool deallocate(void[] b) shared { _aligned_free(b.ptr); return true; } else static assert(0); /** On Posix, forwards to $(D realloc). On Windows, forwards to $(D alignedReallocate(b, newSize, platformAlignment)). */ version (Posix) @system @nogc nothrow bool reallocate(ref void[] b, size_t newSize) shared { return Mallocator.instance.reallocate(b, newSize); } version (Windows) @system @nogc nothrow bool reallocate(ref void[] b, size_t newSize) shared { return alignedReallocate(b, newSize, alignment); } /** On Posix, uses $(D alignedAllocate) and copies data around because there is no realloc for aligned memory. On Windows, calls $(WEB msdn.microsoft.com/en-US/library/y69db7sx(v=vs.80).aspx, $(D __aligned_realloc(b.ptr, newSize, a))). */ version (Windows) @system @nogc nothrow bool alignedReallocate(ref void[] b, size_t s, uint a) shared { if (!s) { deallocate(b); b = null; return true; } auto p = cast(ubyte*) _aligned_realloc(b.ptr, s, a); if (!p) return false; b = p[0 .. s]; return true; } /** Returns the global instance of this allocator type. The C heap allocator is thread-safe, therefore all of its methods and `instance` itself are $(D shared). */ static shared AlignedMallocator instance; } /// @nogc nothrow unittest { auto buffer = AlignedMallocator.instance.alignedAllocate(1024 * 1024 * 4, 128); scope(exit) AlignedMallocator.instance.deallocate(buffer); //... } version(unittest) version(CRuntime_DigitalMars) @nogc nothrow size_t addr(ref void* ptr) { return cast(size_t) ptr; } version(CRuntime_DigitalMars) @nogc nothrow unittest { void* m; m = _aligned_malloc(16, 0x10); if (m) { assert((m.addr & 0xF) == 0); _aligned_free(m); } m = _aligned_malloc(16, 0x100); if (m) { assert((m.addr & 0xFF) == 0); _aligned_free(m); } m = _aligned_malloc(16, 0x1000); if (m) { assert((m.addr & 0xFFF) == 0); _aligned_free(m); } m = _aligned_malloc(16, 0x10); if (m) { assert((cast(size_t)m & 0xF) == 0); m = _aligned_realloc(m, 32, 0x10000); if (m) assert((m.addr & 0xFFFF) == 0); _aligned_free(m); } m = _aligned_malloc(8, 0x10); if (m) { *cast(ulong*) m = 0X01234567_89ABCDEF; m = _aligned_realloc(m, 0x800, 0x1000); if (m) assert(*cast(ulong*) m == 0X01234567_89ABCDEF); _aligned_free(m); } } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/allocator/typed.d0000664000175000017500000003522112776215007023660 0ustar kaikai/** This module defines `TypedAllocator`, a statically-typed allocator that aggregates multiple untyped allocators and uses them depending on the static properties of the types allocated. For example, distinct allocators may be used for thread-local vs. thread-shared data, or for fixed-size data (`struct`, `class` objects) vs. resizable data (arrays). Macros: T2=$(TR $(D $1) $(TD $(ARGS $+))) */ module std.experimental.allocator.typed; import std.experimental.allocator; import std.experimental.allocator.common; import std.traits : isPointer, hasElaborateDestructor; import std.typecons : Flag, Yes, No; import std.algorithm : min; import std.range : isInputRange, isForwardRange, walkLength, save, empty, front, popFront; /** Allocation-related flags dictated by type characteristics. `TypedAllocator` deduces these flags from the type being allocated and uses the appropriate allocator accordingly. */ enum AllocFlag : uint { init = 0, /** Fixed-size allocation (unlikely to get reallocated later). Examples: `int`, `double`, any `struct` or `class` type. By default it is assumed that the allocation is variable-size, i.e. susceptible to later reallocation (for example all array types). This flag is advisory, i.e. in-place resizing may be attempted for `fixedSize` allocations and may succeed. The flag is just a hint to the compiler it may use allocation strategies that work well with objects of fixed size. */ fixedSize = 1, /** The type being allocated embeds no pointers. Examples: `int`, `int[]`, $(D Tuple!(int, float)). The implicit conservative assumption is that the type has members with indirections so it needs to be scanned if garbage collected. Example of types with pointers: `int*[]`, $(D Tuple!(int, string)). */ hasNoIndirections = 4, /** By default it is conservatively assumed that allocated memory may be `cast` to `shared`, passed across threads, and deallocated in a different thread than the one that allocated it. If that's not the case, there are two options. First, `immutableShared` means the memory is allocated for `immutable` data and will be deallocated in the same thread it was allocated in. Second, `threadLocal` means the memory is not to be shared across threads at all. The two flags cannot be simultaneously present. */ immutableShared = 8, /// ditto threadLocal = 16, } /** `TypedAllocator` acts like a chassis on which several specialized allocators can be assembled. To let the system make a choice about a particular kind of allocation, use `Default` for the respective parameters. There is a hierarchy of allocation kinds. When an allocator is implemented for a given combination of flags, it is used. Otherwise, the next down the list is chosen. $(BOOKTABLE , $(TR $(TH `AllocFlag` combination) $(TH Description)) $(T2 AllocFlag.threadLocal |$(NBSP)AllocFlag.hasNoIndirections |$(NBSP)AllocFlag.fixedSize, This is the most specific allocation policy: the memory being allocated is thread local, has no indirections at all, and will not be reallocated. Examples of types fitting this description: `int`, `double`, $(D Tuple!(int, long)), but not $(D Tuple!(int, string)), which contains an indirection.) $(T2 AllocFlag.threadLocal |$(NBSP)AllocFlag.hasNoIndirections, As above, but may be reallocated later. Examples of types fitting this description are $(D int[]), $(D double[]), $(D Tuple!(int, long)[]), but not $(D Tuple!(int, string)[]), which contains an indirection.) $(T2 AllocFlag.threadLocal, As above, but may embed indirections. Examples of types fitting this description are $(D int*[]), $(D Object[]), $(D Tuple!(int, string)[]).) $(T2 AllocFlag.immutableShared |$(NBSP)AllocFlag.hasNoIndirections |$(NBSP)AllocFlag.fixedSize, The type being allocated is `immutable` and has no pointers. The thread that allocated it must also deallocate it. Example: `immutable(int)`.) $(T2 AllocFlag.immutableShared |$(NBSP)AllocFlag.hasNoIndirections, As above, but the type may be appended to in the future. Example: `string`.) $(T2 AllocFlag.immutableShared, As above, but the type may embed references. Example: `immutable(Object)[]`.) $(T2 AllocFlag.hasNoIndirections |$(NBSP)AllocFlag.fixedSize, The type being allocated may be shared across threads, embeds no indirections, and has fixed size.) $(T2 AllocFlag.hasNoIndirections, The type being allocated may be shared across threads, may embed indirections, and has variable size.) $(T2 AllocFlag.fixedSize, The type being allocated may be shared across threads, may embed indirections, and has fixed size.) $(T2 0, The most conservative/general allocation: memory may be shared, deallocated in a different thread, may or may not be resized, and may embed references.) ) Params: PrimaryAllocator = The default allocator. Policies = Zero or more pairs consisting of an `AllocFlag` and an allocator type. */ struct TypedAllocator(PrimaryAllocator, Policies...) { import std.typecons : Tuple; import std.meta : AliasSeq; import std.algorithm.sorting : isSorted; static assert(Policies.length == 0 || isSorted([Stride2!Policies])); private template Stride2(T...) { static if (T.length >= 2) { alias Stride2 = AliasSeq!(T[0], Stride2!(T[2 .. $])); } else { alias Stride2 = AliasSeq!(T[0 .. $]); } } // state { static if (stateSize!PrimaryAllocator) private PrimaryAllocator primary; else alias primary = PrimaryAllocator.instance; static if (Policies.length > 0) private Tuple!(Stride2!(Policies[1 .. $])) extras; // } //pragma(msg, "Allocators available: ", typeof(extras)); private static bool match(uint have, uint want) { enum uint maskAway = ~(AllocFlag.immutableShared | AllocFlag.threadLocal); // Do we offer thread local? if (have & AllocFlag.threadLocal) { if (want & AllocFlag.threadLocal) return match(have & maskAway, want & maskAway); return false; } if (have & AllocFlag.immutableShared) { // Okay to ask for either thread local or immutable shared if (want & (AllocFlag.threadLocal | AllocFlag.immutableShared)) return match(have & maskAway, want & maskAway); return false; } // From here on we have full-blown thread sharing. if (have & AllocFlag.hasNoIndirections) { if (want & AllocFlag.hasNoIndirections) return match(have & ~AllocFlag.hasNoIndirections, want & ~AllocFlag.hasNoIndirections); return false; } // Fixed size or variable size both match. return true; } /** Given `flags` as a combination of `AllocFlag` values, or a type `T`, returns the allocator that's a closest fit in capabilities. */ auto ref allocatorFor(uint flags)() { static if (Policies.length == 0 || !match(Policies[0], flags)) { return primary; } else static if (Policies.length && match(Policies[$ - 2], flags)) { return extras[$ - 1]; } else { foreach (i, choice; Stride2!Policies) { static if (!match(choice, flags)) { return extras[i - 1]; } } assert(0); } } /// ditto auto ref allocatorFor(T)() { static if (is(T == void[])) { return primary; } else { return allocatorFor!(type2flags!T)(); } } /** Given a type `T`, returns its allocation-related flags as a combination of `AllocFlag` values. */ static uint type2flags(T)() { uint result; static if (is(T == immutable)) result |= AllocFlag.immutableShared; else static if (is(T == shared)) result |= AllocFlag.forSharing; static if (!is(T == U[], U)) result |= AllocFlag.fixedSize; import std.traits : hasIndirections; static if (!hasIndirections!T) result |= AllocFlag.hasNoIndirections; return result; } /** Dynamically allocates (using the appropriate allocator chosen with `allocatorFor!T`) and then creates in the memory allocated an object of type `T`, using `args` (if any) for its initialization. Initialization occurs in the memory allocated and is otherwise semantically the same as `T(args)`. (Note that using `make!(T[])` creates a pointer to an (empty) array of `T`s, not an array. To allocate and initialize an array, use `makeArray!T` described below.) Params: T = Type of the object being created. args = Optional arguments used for initializing the created object. If not present, the object is default constructed. Returns: If `T` is a class type, returns a reference to the created `T` object. Otherwise, returns a `T*` pointing to the created object. In all cases, returns `null` if allocation failed. Throws: If `T`'s constructor throws, deallocates the allocated memory and propagates the exception. */ auto make(T, A...)(auto ref A args) { return .make!T(allocatorFor!T, args); } /** Create an array of `T` with `length` elements. The array is either default-initialized, filled with copies of `init`, or initialized with values fetched from `range`. Params: T = element type of the array being created length = length of the newly created array init = element used for filling the array range = range used for initializing the array elements Returns: The newly-created array, or `null` if either `length` was `0` or allocation failed. Throws: The first two overloads throw only if the used allocator's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws. */ T[] makeArray(T)(size_t length) { return .makeArray!T(allocatorFor!(T[]), length); } /// Ditto T[] makeArray(T)(size_t length, auto ref T init) { return .makeArray!T(allocatorFor!(T[]), init, length); } /// Ditto T[] makeArray(T, R)(R range) if (isInputRange!R) { return .makeArray!T(allocatorFor!(T[]), range); } /** Grows `array` by appending `delta` more elements. The needed memory is allocated using the same allocator that was used for the array type. The extra elements added are either default-initialized, filled with copies of `init`, or initialized with values fetched from `range`. Params: T = element type of the array being created array = a reference to the array being grown delta = number of elements to add (upon success the new length of `array` is $(D array.length + delta)) init = element used for filling the array range = range used for initializing the array elements Returns: `true` upon success, `false` if memory could not be allocated. In the latter case `array` is left unaffected. Throws: The first two overloads throw only if the used allocator's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws. */ bool expandArray(T)(ref T[] array, size_t delta) { return .expandArray(allocatorFor!(T[]), array, delta); } /// Ditto bool expandArray(T)(T[] array, size_t delta, auto ref T init) { return .expandArray(allocatorFor!(T[]), array, delta, init); } /// Ditto bool expandArray(T, R)(ref T[] array, R range) if (isInputRange!R) { return .expandArray(allocatorFor!(T[]), array, range); } /** Shrinks an array by `delta` elements using `allocatorFor!(T[])`. If $(D arr.length < delta), does nothing and returns `false`. Otherwise, destroys the last $(D arr.length - delta) elements in the array and then reallocates the array's buffer. If reallocation fails, fills the array with default-initialized data. Params: T = element type of the array being created arr = a reference to the array being shrunk delta = number of elements to remove (upon success the new length of `arr` is $(D arr.length - delta)) Returns: `true` upon success, `false` if memory could not be reallocated. In the latter case $(D arr[$ - delta .. $]) is left with default-initialized elements. Throws: The first two overloads throw only if the used allocator's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws. */ bool shrinkArray(T)(ref T[] arr, size_t delta) { return .shrinkArray(allocatorFor!(T[]), arr, delta); } /** Destroys and then deallocates (using `allocatorFor!T`) the object pointed to by a pointer, the class object referred to by a `class` or `interface` reference, or an entire array. It is assumed the respective entities had been allocated with the same allocator. */ void dispose(T)(T* p) { return .dispose(allocatorFor!T, p); } /// Ditto void dispose(T)(T p) if (is(T == class) || is(T == interface)) { return .dispose(allocatorFor!T, p); } /// Ditto void dispose(T)(T[] array) { return .dispose(allocatorFor!(T[]), array); } } /// unittest { import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.mmap_allocator : MmapAllocator; alias MyAllocator = TypedAllocator!(GCAllocator, AllocFlag.fixedSize | AllocFlag.threadLocal, Mallocator, AllocFlag.fixedSize | AllocFlag.threadLocal | AllocFlag.hasNoIndirections, MmapAllocator, ); MyAllocator a; auto b = &a.allocatorFor!0(); static assert(is(typeof(*b) == shared GCAllocator)); enum f1 = AllocFlag.fixedSize | AllocFlag.threadLocal; auto c = &a.allocatorFor!f1(); static assert(is(typeof(*c) == Mallocator)); enum f2 = AllocFlag.fixedSize | AllocFlag.threadLocal; static assert(is(typeof(a.allocatorFor!f2()) == Mallocator)); // Partial match enum f3 = AllocFlag.threadLocal; static assert(is(typeof(a.allocatorFor!f3()) == Mallocator)); int* p = a.make!int; scope(exit) a.dispose(p); int[] arr = a.makeArray!int(42); scope(exit) a.dispose(arr); assert(a.expandArray(arr, 3)); assert(a.shrinkArray(arr, 4)); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/ndslice/0000775000175000017500000000000012776215007022024 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/experimental/ndslice/slice.d0000664000175000017500000023077312776215007023304 0ustar kaikai/** This is a submodule of $(LINK2 std_experimental_ndslice.html, std.experimental.ndslice). License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Ilya Yaroshenko Source: $(PHOBOSSRC std/_experimental/_ndslice/_slice.d) Macros: SUBMODULE = $(LINK2 std_experimental_ndslice_$1.html, std.experimental.ndslice.$1) SUBREF = $(LINK2 std_experimental_ndslice_$1.html#.$2, $(TT $2))$(NBSP) T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) T4=$(TR $(TDNW $(LREF $1)) $(TD $2) $(TD $3) $(TD $4)) STD = $(TD $(SMALL $0)) */ module std.experimental.ndslice.slice; import std.traits; import std.meta; import std.typecons; //: Flag, Yes, No; import std.experimental.ndslice.internal; /++ Creates an n-dimensional slice-shell over a `range`. Params: range = a random access range or an array; only index operator `auto opIndex(size_t index)` is required for ranges. The length of the range should be equal to the sum of shift and the product of lengths. If `allowDownsize`, the length of the range should be greater than or equal to the sum of shift and the product of lengths. lengths = list of lengths for each dimension shift = index of the first element of a `range`. The first `shift` elements of range are ignored. Names = names of elements in a slice tuple. Slice tuple is a slice, which holds single set of lengths and strides for a number of ranges. mod = If `yes`, the array will be replaced with its pointer to improve performance. Use `no` for compile time function evaluation. Returns: n-dimensional slice +/ auto sliced( Flag!"replaceArrayWithPointer" replaceArrayWithPointer = Yes.replaceArrayWithPointer, Flag!"allowDownsize" allowDownsize = No.allowDownsize, Range, Lengths...)(Range range, Lengths lengths) if (!isStaticArray!Range && !isNarrowString!Range && allSatisfy!(isIndex, Lengths) && Lengths.length) { return .sliced!(replaceArrayWithPointer, allowDownsize, Lengths.length, Range)(range, [lengths]); } ///ditto auto sliced( Flag!"replaceArrayWithPointer" replaceArrayWithPointer = Yes.replaceArrayWithPointer, Flag!"allowDownsize" allowDownsize = No.allowDownsize, size_t N, Range)(Range range, auto ref in size_t[N] lengths, size_t shift = 0) if (!isStaticArray!Range && !isNarrowString!Range && N) in { import std.range.primitives: hasLength; foreach (len; lengths) assert(len > 0, "All lengths must be positive." ~ tailErrorMessage!()); static if (hasLength!Range) { static if (allowDownsize) { assert(lengthsProduct!N(lengths) + shift <= range.length, "Range length must be greater than or equal to the sum of shift and the product of lengths." ~ tailErrorMessage!()); } else { assert(lengthsProduct!N(lengths) + shift == range.length, "Range length must be equal to the sum of shift and the product of lengths." ~ tailErrorMessage!()); } } } body { static if (isDynamicArray!Range && replaceArrayWithPointer) { Slice!(N, typeof(range.ptr)) ret = void; ret._ptr = range.ptr + shift; } else { alias S = Slice!(N, ImplicitlyUnqual!(typeof(range))); static if (hasElaborateAssign!(S.PureRange)) S ret; else S ret = void; static if (hasPtrBehavior!(S.PureRange)) { static if (S.NSeq.length == 1) ret._ptr = range; else ret._ptr = range._ptr; ret._ptr += shift; } else { static if (S.NSeq.length == 1) { ret._ptr._range = range; ret._ptr._shift = shift; } else { ret._ptr = range._ptr; ret._ptr._shift += range._strides[0] * shift; } } } ret._lengths[N - 1] = lengths[N - 1]; static if (ret.NSeq.length == 1) ret._strides[N - 1] = 1; else ret._strides[N - 1] = range._strides[0]; foreach_reverse(i; Iota!(0, N - 1)) { ret._lengths[i] = lengths[i]; ret._strides[i] = ret._strides[i + 1] * ret._lengths[i + 1]; } foreach (i; Iota!(N, ret.PureN)) { ret._lengths[i] = range._lengths[i - N + 1]; ret._strides[i] = range._strides[i - N + 1]; } return ret; } private enum bool _isSlice(T) = is(T : Slice!(N, Range), size_t N, Range); ///ditto template sliced(Names...) if (Names.length && !anySatisfy!(isType, Names) && allSatisfy!(isStringValue, Names)) { mixin ( " auto sliced( Flag!`replaceArrayWithPointer` replaceArrayWithPointer = Yes.replaceArrayWithPointer, Flag!`allowDownsize` allowDownsize = No.allowDownsize, " ~ _Range_Types!Names ~ " Lengths...) (" ~ _Range_DeclarationList!Names ~ "Lengths lengths) if (allSatisfy!(isIndex, Lengths)) { alias sliced = .sliced!Names; return sliced!(replaceArrayWithPointer, allowDownsize)(" ~ _Range_Values!Names ~ "[lengths]); } auto sliced( Flag!`replaceArrayWithPointer` replaceArrayWithPointer = Yes.replaceArrayWithPointer, Flag!`allowDownsize` allowDownsize = No.allowDownsize, size_t N, " ~ _Range_Types!Names ~ ") (" ~ _Range_DeclarationList!Names ~" auto ref in size_t[N] lengths, size_t shift = 0) { alias RS = AliasSeq!(" ~ _Range_Types!Names ~ ");" ~ q{ import std.range.primitives: hasLength; import std.meta: staticMap; static assert(!anySatisfy!(_isSlice, RS), `Packed slices are not allowed in slice tuples` ~ tailErrorMessage!()); alias PT = PtrTuple!Names; alias SPT = PT!(staticMap!(PrepareRangeType, RS)); static if (hasElaborateAssign!SPT) SPT range; else SPT range = void; version(assert) immutable minLength = lengthsProduct!N(lengths) + shift; foreach (i, name; Names) { alias T = typeof(range.ptrs[i]); alias R = RS[i]; static assert(!isStaticArray!R); static assert(!isNarrowString!R); mixin (`alias r = range_` ~ name ~`;`); static if (hasLength!R) { static if (allowDownsize) { assert(minLength <= r.length, `length of range '` ~ name ~`' must be greater than or equal ` ~ `to the sum of shift and the product of lengths.` ~ tailErrorMessage!()); } else { assert(minLength == r.length, `length of range '` ~ name ~`' must be equal ` ~ `to the sum of shift and the product of lengths.` ~ tailErrorMessage!()); } } static if (isDynamicArray!T && replaceArrayWithPointer) range.ptrs[i] = r.ptr; else range.ptrs[i] = T(0, r); } return .sliced!(replaceArrayWithPointer, allowDownsize, N, SPT)(range, lengths, shift); } ~ "}"); } /// Creates a slice from an array. pure nothrow unittest { auto slice = new int [5 * 6 * 7].sliced(5, 6, 7); assert(slice.length == 5); assert(slice.elementsCount == 5 * 6 * 7); static assert(is(typeof(slice) == Slice!(3, int*))); } /// Creates a slice using shift parameter. @safe @nogc pure nothrow unittest { import std.range: iota; auto slice = (5 * 6 * 7 + 9).iota.sliced([5, 6, 7], 9); assert(slice.length == 5); assert(slice.elementsCount == 5 * 6 * 7); assert(slice[0, 0, 0] == 9); } /// $(LINK2 https://en.wikipedia.org/wiki/Vandermonde_matrix, Vandermonde matrix) pure nothrow unittest { auto vandermondeMatrix(Slice!(1, double*) x) { auto ret = new double[x.length ^^ 2] .sliced(x.length, x.length); foreach (i; 0 .. x.length) foreach (j; 0 .. x.length) ret[i, j] = x[i] ^^ j; return ret; } auto x = [1.0, 2, 3, 4, 5].sliced(5); auto v = vandermondeMatrix(x); assert(v == [[ 1.0, 1, 1, 1, 1], [ 1.0, 2, 4, 8, 16], [ 1.0, 3, 9, 27, 81], [ 1.0, 4, 16, 64, 256], [ 1.0, 5, 25, 125, 625]]); } /++ Creates a slice composed of named elements, each one of which corresponds to a given argument. See also $(LREF assumeSameStructure). +/ pure nothrow unittest { import std.algorithm.comparison: equal; import std.experimental.ndslice.selection: byElement; import std.range: iota; auto alpha = 12.iota; auto beta = new int[12]; auto m = sliced!("a", "b")(alpha, beta, 4, 3); foreach (r; m) foreach (e; r) e.b = e.a; assert(equal(alpha, beta)); beta[] = 0; foreach (e; m.byElement) e.b = e.a; assert(equal(alpha, beta)); } /++ Creates an array and an n-dimensional slice over it. +/ pure nothrow unittest { auto createSlice(T, Lengths...)(Lengths lengths) { return createSlice2!(T, Lengths.length)(cast(size_t[Lengths.length])[lengths]); } ///ditto auto createSlice2(T, size_t N)(auto ref size_t[N] lengths) { size_t length = lengths[0]; foreach (len; lengths[1 .. N]) length *= len; return new T[length].sliced(lengths); } auto slice = createSlice!int(5, 6, 7); assert(slice.length == 5); assert(slice.elementsCount == 5 * 6 * 7); static assert(is(typeof(slice) == Slice!(3, int*))); auto duplicate = createSlice2!int(slice.shape); duplicate[] = slice; } /++ Creates a common n-dimensional array. +/ pure nothrow unittest { auto ndarray(size_t N, Range)(auto ref Slice!(N, Range) slice) { import std.array: array; static if (N == 1) { return slice.array; } else { import std.algorithm.iteration: map; return slice.map!(a => ndarray(a)).array; } } import std.range: iota; auto ar = ndarray(12.iota.sliced(3, 4)); static assert(is(typeof(ar) == int[][])); assert(ar == [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]); } /++ Allocates an array through a specified allocator and creates an n-dimensional slice over it. See also $(LINK2 std_experimental_allocator.html, std.experimental.allocator). +/ unittest { import std.experimental.allocator; // `theAllocator.makeSlice(3, 4)` allocates an array with length equal to `12` // and returns this array and a `2`-dimensional slice-shell over it. auto makeSlice(T, Allocator, Lengths...)(auto ref Allocator alloc, Lengths lengths) { enum N = Lengths.length; struct Result { T[] array; Slice!(N, T*) slice; } size_t length = lengths[0]; foreach (len; lengths[1 .. N]) length *= len; T[] a = alloc.makeArray!T(length); return Result(a, a.sliced(lengths)); } auto tup = makeSlice!int(theAllocator, 2, 3, 4); static assert(is(typeof(tup.array) == int[])); static assert(is(typeof(tup.slice) == Slice!(3, int*))); assert(tup.array.length == 24); assert(tup.slice.elementsCount == 24); assert(tup.array.ptr == &tup.slice[0, 0, 0]); theAllocator.dispose(tup.array); } /// Input range primitives for slices over user defined types pure nothrow @nogc unittest { struct MyIota { //`[index]` operator overloading auto opIndex(size_t index) { return index; } } alias S = Slice!(3, MyIota); auto slice = MyIota().sliced(20, 10); import std.range.primitives; static assert(hasLength!S); static assert(isInputRange!S); static assert(isForwardRange!S == false); } /// Random access range primitives for slices over user defined types pure nothrow @nogc unittest { struct MyIota { //`[index]` operator overloading auto opIndex(size_t index) { return index; } // `save` property to allow a slice to be a forward range auto save() @property { return this; } } alias S = Slice!(3, MyIota); auto slice = MyIota().sliced(20, 10); import std.range.primitives; static assert(hasLength!S); static assert(hasSlicing!S); static assert(isForwardRange!S); static assert(isBidirectionalRange!S); static assert(isRandomAccessRange!S); } /// Slice tuple and flags pure nothrow @nogc unittest { import std.typecons: Yes, No; static immutable a = [1, 2, 3, 4, 5, 6]; static immutable b = [1.0, 2, 3, 4, 5, 6]; alias namedSliced = sliced!("a", "b"); auto slice = namedSliced!(No.replaceArrayWithPointer, Yes.allowDownsize) (a, b, 2, 3); assert(slice[1, 2].a == slice[1, 2].b); } // sliced slice pure nothrow unittest { import std.range: iota; auto data = new int[24]; foreach (int i,ref e; data) e = i; auto a = data[0..10].sliced(10)[0..6].sliced(2, 3); auto b = 10.iota.sliced(10)[0..6].sliced(2, 3); assert(a == b); a[] += b; foreach (int i, e; data[0..6]) assert(e == 2*i); foreach (int i, e; data[6..$]) assert(e == i+6); auto c = data.sliced(12, 2)[0..6].sliced(2, 3); auto d = 24.iota.sliced(12, 2)[0..6].sliced(2, 3); auto cc = data[0..12].sliced(2, 3, 2); auto dc = 12.iota.sliced(2, 3, 2); assert(c._lengths == cc._lengths); assert(c._strides == cc._strides); assert(d._lengths == dc._lengths); assert(d._strides == dc._strides); assert(cc == c); assert(dc == d); auto e = data.sliced(8, 3)[0..5].sliced(5); auto f = 24.iota.sliced(8, 3)[0..5].sliced(5); assert(e == data[0..15].sliced(5, 3)); assert(f == 15.iota.sliced(5, 3)); } private template _Range_Types(Names...) { static if (Names.length) enum string _Range_Types = "Range_" ~ Names[0] ~ ", " ~ _Range_Types!(Names[1..$]); else enum string _Range_Types = ""; } private template _Range_Values(Names...) { static if (Names.length) enum string _Range_Values = "range_" ~ Names[0] ~ ", " ~ _Range_Values!(Names[1..$]); else enum string _Range_Values = ""; } private template _Range_DeclarationList(Names...) { static if (Names.length) enum string _Range_DeclarationList = "Range_" ~ Names[0] ~ " range_" ~ Names[0] ~ ", " ~ _Range_DeclarationList!(Names[1..$]); else enum string _Range_DeclarationList = ""; } private template _Slice_DeclarationList(Names...) { static if (Names.length) enum string _Slice_DeclarationList = "Slice!(N, Range_" ~ Names[0] ~ ") slice_" ~ Names[0] ~ ", " ~ _Slice_DeclarationList!(Names[1..$]); else enum string _Slice_DeclarationList = ""; } /++ Groups slices into a slice tuple. The slices must have identical structure. Slice tuple is a slice, which holds single set of lengths and strides for a number of ranges. Params: Names = names of elements in a slice tuple Returns: n-dimensional slice See_also: $(LREF .Slice.structure). +/ template assumeSameStructure(Names...) if (Names.length && !anySatisfy!(isType, Names) && allSatisfy!(isStringValue, Names)) { mixin ( " auto assumeSameStructure( size_t N, " ~ _Range_Types!Names ~ ") (" ~ _Slice_DeclarationList!Names ~ ") { alias RS = AliasSeq!(" ~_Range_Types!Names ~ ");" ~ q{ import std.meta: staticMap; static assert(!anySatisfy!(_isSlice, RS), `Packed slices not allowed in slice tuples` ~ tailErrorMessage!()); alias PT = PtrTuple!Names; alias SPT = PT!(staticMap!(PrepareRangeType, RS)); static if (hasElaborateAssign!SPT) Slice!(N, SPT) ret; else Slice!(N, SPT) ret = void; mixin (`alias slice0 = slice_` ~ Names[0] ~`;`); ret._lengths = slice0._lengths; ret._strides = slice0._strides; ret._ptr.ptrs[0] = slice0._ptr; foreach (i, name; Names[1..$]) { mixin (`alias slice = slice_` ~ name ~`;`); assert(ret._lengths == slice._lengths, `Shapes must be identical` ~ tailErrorMessage!()); assert(ret._strides == slice._strides, `Strides must be identical` ~ tailErrorMessage!()); ret._ptr.ptrs[i+1] = slice._ptr; } return ret; } ~ "}"); } /// pure nothrow unittest { import std.algorithm.comparison: equal; import std.experimental.ndslice.selection: byElement; import std.range: iota; auto alpha = 12.iota .sliced(4, 3); auto beta = new int[12].sliced(4, 3); auto m = assumeSameStructure!("a", "b")(alpha, beta); foreach (r; m) foreach (e; r) e.b = e.a; assert(alpha == beta); beta[] = 0; foreach (e; m.byElement) e.b = e.a; assert(alpha == beta); } /// @safe @nogc pure nothrow unittest { import std.algorithm.iteration: map, sum, reduce; import std.algorithm.comparison: max; import std.experimental.ndslice.iteration: transposed; /// Returns maximal column average. auto maxAvg(S)(S matrix) { return matrix.transposed.map!sum.reduce!max / matrix.length; } enum matrix = [1, 2, 3, 4].sliced!(No.replaceArrayWithPointer)(2, 2); ///Сompile time function evaluation static assert(maxAvg(matrix) == 3); } /++ Returns the element type of the `Slice` type. +/ alias DeepElementType(S : Slice!(N, Range), size_t N, Range) = S.DeepElemType; /// unittest { import std.range: iota; static assert(is(DeepElementType!(Slice!(4, const(int)[])) == const(int))); static assert(is(DeepElementType!(Slice!(4, immutable(int)*)) == immutable(int))); static assert(is(DeepElementType!(Slice!(4, typeof(100.iota))) == int)); //packed slice static assert(is(DeepElementType!(Slice!(2, Slice!(5, int*))) == Slice!(4, int*))); } /++ Presents $(LREF .Slice.structure). +/ struct Structure(size_t N) { /// size_t[N] lengths; /// sizediff_t[N] strides; } /++ Presents an n-dimensional view over a range. $(H3 Definitions) In order to change data in a slice using overloaded operators such as `=`, `+=`, `++`, a syntactic structure of type `[]` must be used. It is worth noting that just like for regular arrays, operations `a = b` and `a[] = b` have different meanings. In the first case, after the operation is carried out, `a` simply points at the same data as `b` does, and the data which `a` previously pointed at remains unmodified. Here, `а` and `b` must be of the same type. In the second case, `a` points at the same data as before, but the data itself will be changed. In this instance, the number of dimensions of `b` may be less than the number of dimensions of `а`; and `b` can be a Slice, a regular multidimensional array, or simply a value (e.g. a number). In the following table you will find the definitions you might come across in comments on operator overloading. $(BOOKTABLE $(TR $(TH Definition) $(TH Examples at `N == 3`)) $(TR $(TD An $(BLUE interval) is a part of a sequence of type `i .. j`.) $(STD `2..$-3`, `0..4`)) $(TR $(TD An $(BLUE index) is a part of a sequence of type `i`.) $(STD `3`, `$-1`)) $(TR $(TD A $(BLUE partially defined slice) is a sequence composed of $(BLUE intervals) and $(BLUE indexes) with an overall length strictly less than `N`.) $(STD `[3]`, `[0..$]`, `[3, 3]`, `[0..$,0..3]`, `[0..$,2]`)) $(TR $(TD A $(BLUE fully defined index) is a sequence composed only of $(BLUE indexes) with an overall length equal to `N`.) $(STD `[2,3,1]`)) $(TR $(TD A $(BLUE fully defined slice) is an empty sequence or a sequence composed of $(BLUE indexes) and at least one $(BLUE interval) with an overall length equal to `N`.) $(STD `[]`, `[3..$,0..3,0..$-1]`, `[2,0..$,1]`)) ) $(H3 Internal Binary Representation) Multidimensional Slice is a structure that consists of lengths, strides, and a pointer. For ranges, a shell is used instead of a pointer. This shell contains a shift of the current initial element of a multidimensional slice and the range itself. With the exception of overloaded operators, no functions in this package change or copy data. The operations are only carried out on lengths, strides, and pointers. If a slice is defined over a range, only the shift of the initial element changes instead of the pointer. $(H4 Internal Representation for Pointers) Type definition ------- Slice!(N, T*) ------- Schema ------- Slice!(N, T*) size_t[N] lengths sizediff_t[N] strides T* ptr ------- Example: Definitions ------- import std.experimental.ndslice; auto a = new double[24]; Slice!(3, double*) s = a.sliced(2, 3, 4); Slice!(3, double*) t = s.transposed!(1, 2, 0); Slice!(3, double*) r = r.reversed!1; ------- Representation ------- s________________________ lengths[0] ::= 2 lengths[1] ::= 3 lengths[2] ::= 4 strides[0] ::= 12 strides[1] ::= 4 strides[2] ::= 1 ptr ::= &a[0] t____transposed!(1, 2, 0) lengths[0] ::= 3 lengths[1] ::= 4 lengths[2] ::= 2 strides[0] ::= 4 strides[1] ::= 1 strides[2] ::= 12 ptr ::= &a[0] r______________reversed!1 lengths[0] ::= 2 lengths[1] ::= 3 lengths[2] ::= 4 strides[0] ::= 12 strides[1] ::= -4 strides[2] ::= 1 ptr ::= &a[8] // (old_strides[1] * (lengths[1] - 1)) = 8 ------- $(H4 Internal Representation for Ranges) Type definition ------- Slice!(N, Range) ------- Representation ------- Slice!(N, Range) size_t[N] lengths sizediff_t[N] strides PtrShell!T ptr sizediff_t shift Range range ------- Example: Definitions ------- import std.experimental.ndslice; import std.range: iota; auto a = iota(24); alias A = typeof(a); Slice!(3, A) s = a.sliced(2, 3, 4); Slice!(3, A) t = s.transposed!(1, 2, 0); Slice!(3, A) r = r.reversed!1; ------- Representation ------- s________________________ lengths[0] ::= 2 lengths[1] ::= 3 lengths[2] ::= 4 strides[0] ::= 12 strides[1] ::= 4 strides[2] ::= 1 shift ::= 0 range ::= a t____transposed!(1, 2, 0) lengths[0] ::= 3 lengths[1] ::= 4 lengths[2] ::= 2 strides[0] ::= 4 strides[1] ::= 1 strides[2] ::= 12 shift ::= 0 range ::= a r______________reversed!1 lengths[0] ::= 2 lengths[1] ::= 3 lengths[2] ::= 4 strides[0] ::= 12 strides[1] ::= -4 strides[2] ::= 1 shift ::= 8 // (old_strides[1] * (lengths[1] - 1)) = 8 range ::= a ------- +/ struct Slice(size_t _N, _Range) if (_N && _N < 256LU && ((!is(Unqual!_Range : Slice!(N0, Range0), size_t N0, Range0) && (isPointer!_Range || is(typeof(_Range.init[size_t.init])))) || is(_Range == Slice!(N1, Range1), size_t N1, Range1))) { package: enum doUnittest = is(_Range == int*) && _N == 1; alias N = _N; alias Range = _Range; alias This = Slice!(N, Range); static if (is(Range == Slice!(N_, Range_), size_t N_, Range_)) { enum size_t PureN = N + Range.PureN - 1; alias PureRange = Range.PureRange; alias NSeq = AliasSeq!(N, Range.NSeq); } else { alias PureN = N; alias PureRange = Range; alias NSeq = AliasSeq!(N); } alias PureThis = Slice!(PureN, PureRange); static assert(PureN < 256, "Slice: Pure N should be less than 256"); static if (N == 1) alias ElemType = typeof(Range.init[size_t.init]); else alias ElemType = Slice!(N-1, Range); static if (NSeq.length == 1) alias DeepElemType = typeof(Range.init[size_t.init]); else static if (Range.N == 1) alias DeepElemType = Range.ElemType; else alias DeepElemType = Slice!(Range.N - 1, Range.Range); enum hasAccessByRef = isPointer!PureRange || __traits(compiles, { auto a = &(_ptr[0]); } ); enum PureIndexLength(Slices...) = Filter!(isIndex, Slices).length; template isFullPureIndex(Indexes...) { static if (allSatisfy!(isIndex, Indexes)) enum isFullPureIndex = Indexes.length == N; else static if (Indexes.length == 1 && isStaticArray!(Indexes[0])) enum isFullPureIndex = Indexes[0].length == N && isIndex!(ForeachType!(Indexes[0])); else enum isFullPureIndex = false; } enum isPureSlice(Slices...) = Slices.length <= N && PureIndexLength!Slices < N && Filter!(isStaticArray, Slices).length == 0; enum isFullPureSlice(Slices...) = Slices.length == 0 || Slices.length == N && PureIndexLength!Slices < N && Filter!(isStaticArray, Slices).length == 0; size_t[PureN] _lengths; sizediff_t[PureN] _strides; static if (hasPtrBehavior!PureRange) PureRange _ptr; else PtrShell!PureRange _ptr; sizediff_t backIndex(size_t dimension = 0)() @property const if (dimension < N) { return _strides[dimension] * (_lengths[dimension] - 1); } size_t indexStride(Indexes...)(Indexes _indexes) if (isFullPureIndex!Indexes) { static if (isStaticArray!(Indexes[0])) { size_t stride; foreach (i; Iota!(0, N)) //static { assert(_indexes[0][i] < _lengths[i], "indexStride: index at position " ~ i.stringof ~ " (from range [0 .." ~ N.stringof ~ ")) " ~ " must be less than corresponding length"); stride += _strides[i] * _indexes[0][i]; } return stride; } else { size_t stride; foreach (i, index; _indexes) //static { assert(index < _lengths[i], "indexStride: index at position " ~ i.stringof ~ " (from range [0 .." ~ N.stringof ~ ")) " ~ " must be less than corresponding length"); stride += _strides[i] * index; } return stride; } } this(ref in size_t[PureN] lengths, ref in sizediff_t[PureN] strides, PureRange range) { foreach (i; Iota!(0, PureN)) _lengths[i] = lengths[i]; foreach (i; Iota!(0, PureN)) _strides[i] = strides[i]; static if (hasPtrBehavior!PureRange) _ptr = range; else _ptr._range = range; } static if (!hasPtrBehavior!PureRange) this(ref in size_t[PureN] lengths, ref in sizediff_t[PureN] strides, PtrShell!PureRange shell) { foreach (i; Iota!(0, PureN)) _lengths[i] = lengths[i]; foreach (i; Iota!(0, PureN)) _strides[i] = strides[i]; _ptr = shell; } public: /++ Returns: static array of lengths See_also: $(LREF .Slice.structure) +/ size_t[N] shape() @property const { pragma(inline, true); return _lengths[0 .. N]; } static if (doUnittest) /// Regular slice @safe @nogc pure nothrow unittest { import std.range: iota; assert(60.iota .sliced(3, 4, 5) .shape == cast(size_t[3])[3, 4, 5]); } static if (doUnittest) /// Packed slice @safe @nogc pure nothrow unittest { import std.experimental.ndslice.selection: pack; import std.range: iota; assert((3 * 4 * 5 * 6 * 7).iota .sliced(3, 4, 5, 6, 7) .pack!2 .shape == cast(size_t[3])[3, 4, 5]); } /++ Returns: static array of lengths and static array of strides See_also: $(LREF .Slice.shape) +/ Structure!N structure() @property const { pragma(inline, true); return typeof(return)(_lengths[0 .. N], _strides[0 .. N]); } static if (doUnittest) /// Regular slice @safe @nogc pure nothrow unittest { import std.range: iota; assert(60.iota .sliced(3, 4, 5) .structure == Structure!3([3, 4, 5], [20, 5, 1])); } static if (doUnittest) /// Modified regular slice @safe @nogc pure nothrow unittest { import std.experimental.ndslice.selection: pack; import std.experimental.ndslice.iteration: reversed, strided, transposed; import std.range: iota; assert(600.iota .sliced(3, 4, 50) .reversed!2 //makes stride negative .strided!2(6) //multiplies stride by 6 and changes corresponding length .transposed!2 //brings dimension `2` to the first position .structure == Structure!3([9, 3, 4], [-6, 200, 50])); } static if (doUnittest) /// Packed slice @safe @nogc pure nothrow unittest { import std.experimental.ndslice.selection: pack; import std.range: iota; assert((3 * 4 * 5 * 6 * 7).iota .sliced(3, 4, 5, 6, 7) .pack!2 .structure == Structure!3([3, 4, 5], [20 * 42, 5 * 42, 1 * 42])); } /++ Range primitive. Defined only if `Range` is a forward range or a pointer type. +/ static if (canSave!PureRange) auto save() @property { static if (isPointer!PureRange) return typeof(this)(_lengths, _strides, _ptr); else return typeof(this)(_lengths, _strides, _ptr.save); } static if (doUnittest) /// Forward range @safe @nogc pure nothrow unittest { import std.range: iota; auto slice = 6.iota.sliced(2, 3).save; } static if (doUnittest) /// Pointer type. pure nothrow unittest { //slice type is `Slice!(2, int*)` auto slice = new int[6].sliced(2, 3).save; } /++ Multidimensional `length` property. Returns: length of the corresponding dimension See_also: $(LREF .Slice.shape), $(LREF .Slice.structure) +/ size_t length(size_t dimension = 0)() @property const if (dimension < N) { pragma(inline, true); return _lengths[dimension]; } static if (doUnittest) /// @safe @nogc pure nothrow unittest { import std.range: iota; auto slice = 60.iota.sliced(3, 4, 5); assert(slice.length == 3); assert(slice.length!0 == 3); assert(slice.length!1 == 4); assert(slice.length!2 == 5); } alias opDollar = length; /++ Multidimensional `stride` property. Returns: stride of the corresponding dimension See_also: $(LREF .Slice.structure) +/ size_t stride(size_t dimension = 0)() @property const if (dimension < N) { return _strides[dimension]; } static if (doUnittest) /// Regular slice @safe @nogc pure nothrow unittest { import std.range: iota; auto slice = 60.iota.sliced(3, 4, 5); assert(slice.stride == 20); assert(slice.stride!0 == 20); assert(slice.stride!1 == 5); assert(slice.stride!2 == 1); } static if (doUnittest) /// Modified regular slice @safe @nogc pure nothrow unittest { import std.experimental.ndslice.iteration: reversed, strided, swapped; import std.range: iota; assert(600.iota .sliced(3, 4, 50) .reversed!2 //makes stride negative .strided!2(6) //multiplies stride by 6 and changes the corresponding length .swapped!(1, 2) //swaps dimensions `1` and `2` .stride!1 == -6); } /++ Multidimensional input range primitive. +/ bool empty(size_t dimension = 0)() @property const if (dimension < N) { pragma(inline, true); return _lengths[dimension] == 0; } ///ditto auto ref front(size_t dimension = 0)() @property if (dimension < N) { assert(!empty!dimension); static if (PureN == 1) { static if (__traits(compiles,{ auto _f = _ptr.front; })) return _ptr.front; else return _ptr[0]; } else { static if (hasElaborateAssign!PureRange) ElemType ret; else ElemType ret = void; foreach (i; Iota!(0, dimension)) { ret._lengths[i] = _lengths[i]; ret._strides[i] = _strides[i]; } foreach (i; Iota!(dimension, PureN-1)) { ret._lengths[i] = _lengths[i + 1]; ret._strides[i] = _strides[i + 1]; } ret._ptr = _ptr; return ret; } } static if (PureN == 1 && isMutable!DeepElemType && !hasAccessByRef) { ///ditto auto front(size_t dimension = 0, T)(T value) @property if (dimension == 0) { assert(!empty!dimension); static if (__traits(compiles, { _ptr.front = value; })) return _ptr.front = value; else return _ptr[0] = value; } } ///ditto auto ref back(size_t dimension = 0)() @property if (dimension < N) { assert(!empty!dimension); static if (PureN == 1) { return _ptr[backIndex]; } else { static if (hasElaborateAssign!PureRange) ElemType ret; else ElemType ret = void; foreach (i; Iota!(0, dimension)) { ret._lengths[i] = _lengths[i]; ret._strides[i] = _strides[i]; } foreach (i; Iota!(dimension, PureN-1)) { ret._lengths[i] = _lengths[i + 1]; ret._strides[i] = _strides[i + 1]; } ret._ptr = _ptr + backIndex!dimension; return ret; } } static if (PureN == 1 && isMutable!DeepElemType && !hasAccessByRef) { ///ditto auto back(size_t dimension = 0, T)(T value) @property if (dimension == 0) { assert(!empty!dimension); return _ptr[backIndex] = value; } } ///ditto void popFront(size_t dimension = 0)() if (dimension < N) { pragma(inline, true); assert(_lengths[dimension], __FUNCTION__ ~ ": length!" ~ dimension.stringof ~ " should be greater than 0."); _lengths[dimension]--; _ptr += _strides[dimension]; } ///ditto void popBack(size_t dimension = 0)() if (dimension < N) { pragma(inline, true); assert(_lengths[dimension], __FUNCTION__ ~ ": length!" ~ dimension.stringof ~ " should be greater than 0."); _lengths[dimension]--; } ///ditto void popFrontExactly(size_t dimension = 0)(size_t n) if (dimension < N) { pragma(inline, true); assert(n <= _lengths[dimension], __FUNCTION__ ~ ": n should be less than or equal to length!" ~ dimension.stringof); _lengths[dimension] -= n; _ptr += _strides[dimension] * n; } ///ditto void popBackExactly(size_t dimension = 0)(size_t n) if (dimension < N) { pragma(inline, true); assert(n <= _lengths[dimension], __FUNCTION__ ~ ": n should be less than or equal to length!" ~ dimension.stringof); _lengths[dimension] -= n; } ///ditto void popFrontN(size_t dimension = 0)(size_t n) if (dimension < N) { pragma(inline, true); import std.algorithm.comparison: min; popFrontExactly!dimension(min(n, _lengths[dimension])); } ///ditto void popBackN(size_t dimension = 0)(size_t n) if (dimension < N) { pragma(inline, true); import std.algorithm.comparison: min; popBackExactly!dimension(min(n, _lengths[dimension])); } static if (doUnittest) /// @safe @nogc pure nothrow unittest { import std.range: iota; import std.range.primitives; auto slice = 6000.iota.sliced(10, 20, 30); static assert(isRandomAccessRange!(typeof(slice))); static assert(hasSlicing!(typeof(slice))); static assert(hasLength!(typeof(slice))); assert(slice.shape == cast(size_t[3])[10, 20, 30]); slice.popFront; slice.popFront!1; slice.popBackExactly!2(4); assert(slice.shape == cast(size_t[3])[9, 19, 26]); auto matrix = slice.front!1; assert(matrix.shape == cast(size_t[2])[9, 26]); auto column = matrix.back!1; assert(column.shape == cast(size_t[1])[9]); slice.popFrontExactly!1(slice.length!1); assert(slice.empty == false); assert(slice.empty!1 == true); assert(slice.empty!2 == false); assert(slice.shape == cast(size_t[3])[9, 0, 26]); assert(slice.back.front!1.empty); slice.popFrontN!0(40); slice.popFrontN!2(40); assert(slice.shape == cast(size_t[3])[0, 0, 0]); } package void popFront(size_t dimension) { assert(dimension < N, __FUNCTION__ ~ ": dimension should be less than N = " ~ N.stringof); assert(_lengths[dimension], ": length!dim should be greater than 0."); _lengths[dimension]--; _ptr += _strides[dimension]; } package void popBack(size_t dimension) { assert(dimension < N, __FUNCTION__ ~ ": dimension should be less than N = " ~ N.stringof); assert(_lengths[dimension], ": length!dim should be greater than 0."); _lengths[dimension]--; } package void popFrontExactly(size_t dimension, size_t n) { assert(dimension < N, __FUNCTION__ ~ ": dimension should be less than N = " ~ N.stringof); assert(n <= _lengths[dimension], __FUNCTION__ ~ ": n should be less than or equal to length!dim"); _lengths[dimension] -= n; _ptr += _strides[dimension] * n; } package void popBackExactly(size_t dimension, size_t n) { assert(dimension < N, __FUNCTION__ ~ ": dimension should be less than N = " ~ N.stringof); assert(n <= _lengths[dimension], __FUNCTION__ ~ ": n should be less than or equal to length!dim"); _lengths[dimension] -= n; } package void popFrontN(size_t dimension, size_t n) { assert(dimension < N, __FUNCTION__ ~ ": dimension should be less than N = " ~ N.stringof); import std.algorithm.comparison: min; popFrontExactly(dimension, min(n, _lengths[dimension])); } package void popBackN(size_t dimension, size_t n) { assert(dimension < N, __FUNCTION__ ~ ": dimension should be less than N = " ~ N.stringof); import std.algorithm.comparison: min; popBackExactly(dimension, min(n, _lengths[dimension])); } /++ Returns: total number of elements in a slice +/ size_t elementsCount() const { size_t len = 1; foreach (i; Iota!(0, N)) len *= _lengths[i]; return len; } static if (doUnittest) /// Regular slice @safe @nogc pure nothrow unittest { import std.range: iota; assert(60.iota.sliced(3, 4, 5).elementsCount == 60); } static if (doUnittest) /// Packed slice @safe @nogc pure nothrow unittest { import std.experimental.ndslice.selection: pack, evertPack; import std.range: iota; auto slice = (3 * 4 * 5 * 6 * 7 * 8).iota .sliced(3, 4, 5, 6, 7, 8); auto p = slice.pack!2; assert(p.elementsCount == 360); assert(p[0, 0, 0, 0].elementsCount == 56); assert(p.evertPack.elementsCount == 56); } /++ Overloading `==` and `!=` +/ bool opEquals(size_t NR, RangeR)(auto ref Slice!(NR, RangeR) rslice) if (Slice!(NR, RangeR).PureN == PureN) { if (this._lengths != rslice._lengths) return false; static if ( !hasReference!(typeof(this)) && !hasReference!(typeof(rslice)) && __traits(compiles, this._ptr == rslice._ptr) ) { if (this._strides == rslice._strides && this._ptr == rslice._ptr) return true; } return opEqualsImpl(this, rslice); } ///ditto bool opEquals(T)(T[] rarrary) { if (this.length != rarrary.length) return false; foreach(i, ref e; rarrary) if (e != this[i]) return false; return true; } static if (doUnittest) /// pure nothrow unittest { auto a = [1, 2, 3, 4].sliced(2, 2); assert(a != [1, 2, 3, 4, 5, 6].sliced(2, 3)); assert(a != [[1, 2, 3], [4, 5, 6]]); assert(a == [1, 2, 3, 4].sliced(2, 2)); assert(a == [[1, 2], [3, 4]]); assert(a != [9, 2, 3, 4].sliced(2, 2)); assert(a != [[9, 2], [3, 4]]); } _Slice opSlice(size_t dimension)(size_t i, size_t j) if (dimension < N) in { assert(i <= j, "Slice.opSlice!" ~ dimension.stringof ~ ": the left bound must be less than or equal to the right bound."); assert(j - i <= _lengths[dimension], "Slice.opSlice!" ~ dimension.stringof ~ ": difference between the right and the left bounds must be less than or equal to the length of the given dimension."); } body { pragma(inline, true); return typeof(return)(i, j); } /++ $(BLUE Fully defined index). +/ auto ref opIndex(Indexes...)(Indexes _indexes) if (isFullPureIndex!Indexes) { static if (PureN == N) return _ptr[indexStride(_indexes)]; else return DeepElemType(_lengths[N .. $], _strides[N .. $], _ptr + indexStride(_indexes)); } static if (doUnittest) /// pure nothrow unittest { auto slice = new int[10].sliced(5, 2); auto p = &slice[1, 1]; *p = 3; assert(slice[1, 1] == 3); size_t[2] index = [1, 1]; assert(slice[index] == 3); } /++ $(BLUE Partially or fully defined slice). +/ auto opIndex(Slices...)(Slices slices) if (isPureSlice!Slices) { static if (Slices.length) { enum size_t j(size_t n) = n - Filter!(isIndex, Slices[0 .. n+1]).length; enum size_t F = PureIndexLength!Slices; enum size_t S = Slices.length; static assert(N-F > 0); size_t stride; static if (hasElaborateAssign!PureRange) Slice!(N-F, Range) ret; else Slice!(N-F, Range) ret = void; foreach (i, slice; slices) //static { static if (isIndex!(Slices[i])) { assert(slice < _lengths[i], "Slice.opIndex: index must be less than length"); stride += _strides[i] * slice; } else { stride += _strides[i] * slice.i; ret._lengths[j!i] = slice.j - slice.i; ret._strides[j!i] = _strides[i]; } } foreach (i; Iota!(S, PureN)) { ret._lengths[i - F] = _lengths[i]; ret._strides[i - F] = _strides[i]; } ret._ptr = _ptr + stride; return ret; } else { return this; } } static if (doUnittest) /// pure nothrow unittest { auto slice = new int[15].sliced(5, 3); /// Fully defined slice assert(slice[] == slice); auto sublice = slice[0..$-2, 1..$]; /// Partially defined slice auto row = slice[3]; auto col = slice[0..$, 1]; } static if (doUnittest) pure nothrow unittest { auto slice = new int[15].sliced!(No.replaceArrayWithPointer)(5, 3); /// Fully defined slice assert(slice[] == slice); auto sublice = slice[0..$-2, 1..$]; /// Partially defined slice auto row = slice[3]; auto col = slice[0..$, 1]; } static if (isMutable!DeepElemType && PureN == N) { private void opIndexAssignImpl(string op, size_t RN, RRange, Slices...)(Slice!(RN, RRange) value, Slices slices) if (isFullPureSlice!Slices && RN <= ReturnType!(opIndex!Slices).N) { auto slice = this[slices]; assert(slice._lengths[$ - RN .. $] == value._lengths, __FUNCTION__ ~ ": argument must have the corresponding shape."); version(none) //future optimization static if ((isPointer!Range || isDynamicArray!Range) && (isPointer!RRange || isDynamicArray!RRange)) { enum d = slice.N - value.N; foreach_reverse (i; Iota!(0, value.N)) if (slice._lengths[i + d] == 1) { if (value._lengths[i] == 1) { static if (i != value.N - 1) { import std.experimental.ndslice.iteration: swapped; slice = slice.swapped(i + d, slice.N - 1); value = value.swapped(i , value.N - 1); } goto L1; } else { goto L2; } } L1: _indexAssign!(true, op)(slice, value); return; } L2: _indexAssign!(false, op)(slice, value); } private void opIndexAssignImpl(string op, T, Slices...)(T[] value, Slices slices) if (isFullPureSlice!Slices && !isDynamicArray!DeepElemType && DynamicArrayDimensionsCount!(T[]) <= ReturnType!(opIndex!Slices).N) { auto slice = this[slices]; version(none) //future optimization static if (isPointer!Range || isDynamicArray!Range) { if (slice._lengths[$-1] == 1) { _indexAssign!(true, op)(slice, value); return; } } _indexAssign!(false, op)(slice, value); } private void opIndexAssignImpl(string op, T, Slices...)(T value, Slices slices) if (isFullPureSlice!Slices && (!isDynamicArray!T || isDynamicArray!DeepElemType) && !is(T : Slice!(RN, RRange), size_t RN, RRange)) { auto slice = this[slices]; version(none) //future optimization static if (isPointer!Range || isDynamicArray!Range) { if (slice._lengths[$-1] == 1) { _indexAssign!(true, op)(slice, value); return; } } _indexAssign!(false, op)(slice, value); } /++ Assignment of a value of `Slice` type to a $(BLUE fully defined slice). +/ void opIndexAssign(size_t RN, RRange, Slices...)(Slice!(RN, RRange) value, Slices slices) if (isFullPureSlice!Slices && RN <= ReturnType!(opIndex!Slices).N) { opIndexAssignImpl!""(value, slices); } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); auto b = [1, 2, 3, 4].sliced(2, 2); a[0..$, 0..$-1] = b; assert(a == [[1, 2, 0], [3, 4, 0]]); a[0..$, 0..$-1] = b[0]; assert(a == [[1, 2, 0], [1, 2, 0]]); a[1, 0..$-1] = b[1]; assert(a[1] == [3, 4, 0]); a[1, 0..$-1][] = b[0]; assert(a[1] == [1, 2, 0]); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); auto b = [1, 2, 3, 4].sliced(2, 2); a[0..$, 0..$-1] = b; assert(a == [[1, 2, 0], [3, 4, 0]]); a[0..$, 0..$-1] = b[0]; assert(a == [[1, 2, 0], [1, 2, 0]]); a[1, 0..$-1] = b[1]; assert(a[1] == [3, 4, 0]); a[1, 0..$-1][] = b[0]; assert(a[1] == [1, 2, 0]); } /++ Assignment of a regular multidimensional array to a $(BLUE fully defined slice). +/ void opIndexAssign(T, Slices...)(T[] value, Slices slices) if (isFullPureSlice!Slices && !isDynamicArray!DeepElemType && DynamicArrayDimensionsCount!(T[]) <= ReturnType!(opIndex!Slices).N) { opIndexAssignImpl!""(value, slices); } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); auto b = [[1, 2], [3, 4]]; a[] = [[1, 2, 3], [4, 5, 6]]; assert(a == [[1, 2, 3], [4, 5, 6]]); a[0..$, 0..$-1] = [[1, 2], [3, 4]]; assert(a == [[1, 2, 3], [3, 4, 6]]); a[0..$, 0..$-1] = [1, 2]; assert(a == [[1, 2, 3], [1, 2, 6]]); a[1, 0..$-1] = [3, 4]; assert(a[1] == [3, 4, 6]); a[1, 0..$-1][] = [3, 4]; assert(a[1] == [3, 4, 6]); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); auto b = [[1, 2], [3, 4]]; a[] = [[1, 2, 3], [4, 5, 6]]; assert(a == [[1, 2, 3], [4, 5, 6]]); a[0..$, 0..$-1] = [[1, 2], [3, 4]]; assert(a == [[1, 2, 3], [3, 4, 6]]); a[0..$, 0..$-1] = [1, 2]; assert(a == [[1, 2, 3], [1, 2, 6]]); a[1, 0..$-1] = [3, 4]; assert(a[1] == [3, 4, 6]); a[1, 0..$-1][] = [3, 4]; assert(a[1] == [3, 4, 6]); } /++ Assignment of a value (e.g. a number) to a $(BLUE fully defined slice). +/ void opIndexAssign(T, Slices...)(T value, Slices slices) if (isFullPureSlice!Slices && (!isDynamicArray!T || isDynamicArray!DeepElemType) && !is(T : Slice!(RN, RRange), size_t RN, RRange)) { opIndexAssignImpl!""(value, slices); } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); a[] = 9; assert(a == [[9, 9, 9], [9, 9, 9]]); a[0..$, 0..$-1] = 1; assert(a == [[1, 1, 9], [1, 1, 9]]); a[0..$, 0..$-1] = 2; assert(a == [[2, 2, 9], [2, 2, 9]]); a[1, 0..$-1] = 3; assert(a[1] == [3, 3, 9]); a[1, 0..$-1] = 4; assert(a[1] == [4, 4, 9]); a[1, 0..$-1][] = 5; assert(a[1] == [5, 5, 9]); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); a[] = 9; assert(a == [[9, 9, 9], [9, 9, 9]]); a[0..$, 0..$-1] = 1; assert(a == [[1, 1, 9], [1, 1, 9]]); a[0..$, 0..$-1] = 2; assert(a == [[2, 2, 9], [2, 2, 9]]); a[1, 0..$-1] = 3; assert(a[1] == [3, 3, 9]); a[1, 0..$-1] = 4; assert(a[1] == [4, 4, 9]); a[1, 0..$-1][] = 5; assert(a[1] == [5, 5, 9]); } /++ Assignment of a value (e.g. a number) to a $(BLUE fully defined index). +/ auto ref opIndexAssign(T, Indexes...)(T value, Indexes _indexes) if (isFullPureIndex!Indexes) { return _ptr[indexStride(_indexes)] = value; } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); a[1, 2] = 3; assert(a[1, 2] == 3); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); a[1, 2] = 3; assert(a[1, 2] == 3); } /++ Op Assignment `op=` of a value (e.g. a number) to a $(BLUE fully defined index). +/ auto ref opIndexOpAssign(string op, T, Indexes...)(T value, Indexes _indexes) if (isFullPureIndex!Indexes) { mixin (`return _ptr[indexStride(_indexes)] ` ~ op ~ `= value;`); } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); a[1, 2] += 3; assert(a[1, 2] == 3); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); a[1, 2] += 3; assert(a[1, 2] == 3); } /++ Op Assignment `op=` of a value of `Slice` type to a $(BLUE fully defined slice). +/ void opIndexOpAssign(string op, size_t RN, RRange, Slices...)(Slice!(RN, RRange) value, Slices slices) if (isFullPureSlice!Slices && RN <= ReturnType!(opIndex!Slices).N) { opIndexAssignImpl!op(value, slices); } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); auto b = [1, 2, 3, 4].sliced(2, 2); a[0..$, 0..$-1] += b; assert(a == [[1, 2, 0], [3, 4, 0]]); a[0..$, 0..$-1] += b[0]; assert(a == [[2, 4, 0], [4, 6, 0]]); a[1, 0..$-1] += b[1]; assert(a[1] == [7, 10, 0]); a[1, 0..$-1][] += b[0]; assert(a[1] == [8, 12, 0]); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); auto b = [1, 2, 3, 4].sliced(2, 2); a[0..$, 0..$-1] += b; assert(a == [[1, 2, 0], [3, 4, 0]]); a[0..$, 0..$-1] += b[0]; assert(a == [[2, 4, 0], [4, 6, 0]]); a[1, 0..$-1] += b[1]; assert(a[1] == [7, 10, 0]); a[1, 0..$-1][] += b[0]; assert(a[1] == [8, 12, 0]); } /++ Op Assignment `op=` of a regular multidimensional array to a $(BLUE fully defined slice). +/ void opIndexOpAssign(string op, T, Slices...)(T[] value, Slices slices) if (isFullPureSlice!Slices && !isDynamicArray!DeepElemType && DynamicArrayDimensionsCount!(T[]) <= ReturnType!(opIndex!Slices).N) { opIndexAssignImpl!op(value, slices); } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); a[0..$, 0..$-1] += [[1, 2], [3, 4]]; assert(a == [[1, 2, 0], [3, 4, 0]]); a[0..$, 0..$-1] += [1, 2]; assert(a == [[2, 4, 0], [4, 6, 0]]); a[1, 0..$-1] += [3, 4]; assert(a[1] == [7, 10, 0]); a[1, 0..$-1][] += [1, 2]; assert(a[1] == [8, 12, 0]); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); a[0..$, 0..$-1] += [[1, 2], [3, 4]]; assert(a == [[1, 2, 0], [3, 4, 0]]); a[0..$, 0..$-1] += [1, 2]; assert(a == [[2, 4, 0], [4, 6, 0]]); a[1, 0..$-1] += [3, 4]; assert(a[1] == [7, 10, 0]); a[1, 0..$-1][] += [1, 2]; assert(a[1] == [8, 12, 0]); } /++ Op Assignment `op=` of a value (e.g. a number) to a $(BLUE fully defined slice). +/ void opIndexOpAssign(string op, T, Slices...)(T value, Slices slices) if (isFullPureSlice!Slices && (!isDynamicArray!T || isDynamicArray!DeepElemType) && !is(T : Slice!(RN, RRange), size_t RN, RRange)) { opIndexAssignImpl!op(value, slices); } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); a[] += 1; assert(a == [[1, 1, 1], [1, 1, 1]]); a[0..$, 0..$-1] += 2; assert(a == [[3, 3, 1], [3, 3, 1]]); a[1, 0..$-1] += 3; assert(a[1] == [6, 6, 1]); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); a[] += 1; assert(a == [[1, 1, 1], [1, 1, 1]]); a[0..$, 0..$-1] += 2; assert(a == [[3, 3, 1], [3, 3, 1]]); a[1, 0..$-1] += 3; assert(a[1] == [6, 6, 1]); } /++ Increment `++` and Decrement `--` operators for a $(BLUE fully defined index). +/ auto ref opIndexUnary(string op, Indexes...)(Indexes _indexes) if (isFullPureIndex!Indexes && (op == `++` || op == `--`)) { mixin (`return ` ~ op ~ `_ptr[indexStride(_indexes)];`); } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); ++a[1, 2]; assert(a[1, 2] == 1); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); ++a[1, 2]; assert(a[1, 2] == 1); } /++ Increment `++` and Decrement `--` operators for a $(BLUE fully defined slice). +/ void opIndexUnary(string op, Slices...)(Slices slices) if (isFullPureSlice!Slices && (op == `++` || op == `--`)) { auto sl = this[slices]; static if (sl.N == 1) { for (; sl.length; sl.popFront) { mixin (op ~ `sl.front;`); } } else { foreach (v; sl) { mixin (op ~ `v[];`); } } } static if (doUnittest) /// pure nothrow unittest { auto a = new int[6].sliced(2, 3); ++a[]; assert(a == [[1, 1, 1], [1, 1, 1]]); --a[1, 0..$-1]; assert(a[1] == [0, 0, 1]); } static if (doUnittest) pure nothrow unittest { auto a = new int[6].sliced!(No.replaceArrayWithPointer)(2, 3); ++a[]; assert(a == [[1, 1, 1], [1, 1, 1]]); --a[1, 0..$-1]; assert(a[1] == [0, 0, 1]); } } } /++ Slicing, indexing, and arithmetic operations. +/ pure nothrow unittest { import std.array: array; import std.range: iota; import std.experimental.ndslice.iteration: transposed; auto tensor = 60.iota.array.sliced(3, 4, 5); assert(tensor[1, 2] == tensor[1][2]); assert(tensor[1, 2, 3] == tensor[1][2][3]); assert( tensor[0..$, 0..$, 4] == tensor.transposed!2[4]); assert(&tensor[0..$, 0..$, 4][1, 2] is &tensor[1, 2, 4]); tensor[1, 2, 3]++; //`opIndex` returns value by reference. --tensor[1, 2, 3]; //`opUnary` ++tensor[]; tensor[] -= 1; // `opIndexAssing` accepts only fully defined indexes and slices. // Use an additional empty slice `[]`. static assert(!__traits(compiles), tensor[0 .. 2] *= 2); tensor[0 .. 2][] *= 2; //OK, empty slice tensor[0 .. 2, 3, 0..$] /= 2; //OK, 3 index or slice positions are defined. //fully defined index may be replaced by a static array size_t[3] index = [1, 2, 3]; assert(tensor[index] == tensor[1, 2, 3]); } /++ Operations with rvalue slices. +/ pure nothrow unittest { import std.experimental.ndslice.iteration: transposed, everted; auto tensor = new int[60].sliced(3, 4, 5); auto matrix = new int[12].sliced(3, 4); auto vector = new int[ 3].sliced(3); foreach (i; 0..3) vector[i] = i; // fills matrix columns matrix.transposed[] = vector; // fills tensor with vector // transposed tensor shape is (4, 5, 3) // vector shape is ( 3) tensor.transposed!(1, 2)[] = vector; // transposed tensor shape is (5, 3, 4) // matrix shape is ( 3, 4) tensor.transposed!2[] += matrix; // transposed tensor shape is (5, 4, 3) // transposed matrix shape is ( 4, 3) tensor.everted[] ^= matrix.transposed; // XOR } /++ Creating a slice from text. See also $(LINK2 std_format.html, std.format). +/ unittest { import std.algorithm, std.conv, std.exception, std.format, std.functional, std.string, std.range; Slice!(2, int*) toMatrix(string str) { string[][] data = str.lineSplitter.filter!(not!empty).map!split.array; size_t rows = data .length.enforce("empty input"); size_t columns = data[0].length.enforce("empty first row"); data.each!(a => enforce(a.length == columns, "rows have different lengths")); auto slice = new int[rows * columns].sliced(rows, columns); foreach (i, line; data) foreach (j, num; line) slice[i, j] = num.to!int; return slice; } auto input = "\r1 2 3\r\n 4 5 6\n"; auto matrix = toMatrix(input); assert(matrix == [[1, 2, 3], [4, 5, 6]]); // back to text auto text2 = format("%(%(%s %)\n%)\n", matrix); assert(text2 == "1 2 3\n4 5 6\n"); } // Slicing @safe @nogc pure nothrow unittest { import std.range: iota; auto a = 240000.iota.sliced(10, 20, 30, 40); auto b = a[0..$, 10, 4 .. 27, 4]; auto c = b[2 .. 9, 5 .. 10]; auto d = b[3..$, $-2]; assert(b[4, 17] == a[4, 10, 21, 4]); assert(c[1, 2] == a[3, 10, 11, 4]); assert(d[3] == a[6, 10, 25, 4]); } // Operator overloading. # 1 pure nothrow unittest { import std.range: iota; import std.array: array; auto fun(ref int x) { x *= 3; } auto tensor = 720 .iota .array .sliced(8, 9, 10); ++tensor[]; fun(tensor[0, 0, 0]); assert(tensor[0, 0, 0] == 3); tensor[0, 0, 0] *= 4; tensor[0, 0, 0]--; assert(tensor[0, 0, 0] == 11); } // Operator overloading. # 2 pure nothrow unittest { import std.algorithm.iteration: map; import std.array: array; import std.bigint; import std.range: iota; auto matrix = 72 .iota .map!(i => BigInt(i)) .array .sliced(8, 9); matrix[3 .. 6, 2] += 100; foreach (i; 0 .. 8) foreach (j; 0 .. 9) if (i >= 3 && i < 6 && j == 2) assert(matrix[i, j] >= 100); else assert(matrix[i, j] < 100); } // Operator overloading. # 3 pure nothrow unittest { import std.algorithm.iteration: map; import std.array: array; import std.range: iota; auto matrix = 72 .iota .array .sliced(8, 9); matrix[] = matrix; matrix[] += matrix; assert(matrix[2, 3] == (2 * 9 + 3) * 2); auto vec = iota(100, 109).sliced(9); matrix[] = vec; foreach (v; matrix) assert(v == vec); matrix[] += vec; foreach (vector; matrix) foreach (elem; vector) assert(elem >= 200); } // Type deduction unittest { // Arrays foreach (T; AliasSeq!(int, const int, immutable int)) static assert(is(typeof((T[]).init.sliced(3, 4)) == Slice!(2, T*))); // Container Array import std.container.array; Array!int ar; static assert(is(typeof(ar[].sliced(3, 4)) == Slice!(2, typeof(ar[])))); // Implicit conversion of a range to its unqualified type. import std.range: iota; auto i0 = 60.iota; const i1 = 60.iota; immutable i2 = 60.iota; alias S = Slice!(3, typeof(iota(0))); foreach (i; AliasSeq!(i0, i1, i2)) static assert(is(typeof(i.sliced(3, 4, 5)) == S)); } // Test for map #1 unittest { import std.algorithm.iteration: map; import std.range.primitives; auto slice = [1, 2, 3, 4].sliced(2, 2); auto r = slice.map!(a => a.map!(a => a * 6)); assert(r.front.front == 6); assert(r.front.back == 12); assert(r.back.front == 18); assert(r.back.back == 24); assert(r[0][0] == 6); assert(r[0][1] == 12); assert(r[1][0] == 18); assert(r[1][1] == 24); static assert(hasSlicing!(typeof(r))); static assert(isForwardRange!(typeof(r))); static assert(isRandomAccessRange!(typeof(r))); } // Test for map #2 unittest { import std.algorithm.iteration: map; import std.range.primitives; auto data = [1, 2, 3, 4].map!(a => a * 2); static assert(hasSlicing!(typeof(data))); static assert(isForwardRange!(typeof(data))); static assert(isRandomAccessRange!(typeof(data))); auto slice = data.sliced(2, 2); static assert(hasSlicing!(typeof(slice))); static assert(isForwardRange!(typeof(slice))); static assert(isRandomAccessRange!(typeof(slice))); auto r = slice.map!(a => a.map!(a => a * 3)); static assert(hasSlicing!(typeof(r))); static assert(isForwardRange!(typeof(r))); static assert(isRandomAccessRange!(typeof(r))); assert(r.front.front == 6); assert(r.front.back == 12); assert(r.back.front == 18); assert(r.back.back == 24); assert(r[0][0] == 6); assert(r[0][1] == 12); assert(r[1][0] == 18); assert(r[1][1] == 24); } private bool opEqualsImpl (size_t NL, RangeL, size_t NR, RangeR)( auto ref Slice!(NL, RangeL) ls, auto ref Slice!(NR, RangeR) rs) in { assert(ls._lengths == rs._lengths); } body { foreach (i; 0 .. ls.length) { static if (Slice!(NL, RangeL).PureN == 1) { if (ls[i] != rs[i]) return false; } else { if (!opEqualsImpl(ls[i], rs[i])) return false; } } return true; } private struct PtrShell(Range) { sizediff_t _shift; Range _range; enum hasAccessByRef = isPointer!Range || __traits(compiles, { auto a = &(_range[0]); } ); void opOpAssign(string op)(sizediff_t shift) if (op == `+` || op == `-`) { pragma(inline, true); mixin (`_shift ` ~ op ~ `= shift;`); } auto opBinary(string op)(sizediff_t shift) if (op == `+` || op == `-`) { mixin (`return typeof(this)(_shift ` ~ op ~ ` shift, _range);`); } auto ref opIndex(sizediff_t index) in { import std.range.primitives: hasLength; assert(_shift + index >= 0); static if (hasLength!Range) assert(_shift + index <= _range.length); } body { return _range[_shift + index]; } static if (!hasAccessByRef) { auto ref opIndexAssign(T)(T value, sizediff_t index) in { import std.range.primitives: hasLength; assert(_shift + index >= 0); static if (hasLength!Range) assert(_shift + index <= _range.length); } body { return _range[_shift + index] = value; } auto ref opIndexOpAssign(string op, T)(T value, sizediff_t index) in { import std.range.primitives: hasLength; assert(_shift + index >= 0); static if (hasLength!Range) assert(_shift + index <= _range.length); } body { mixin (`return _range[_shift + index] ` ~ op ~ `= value;`); } auto ref opIndexUnary(string op)(sizediff_t index) in { import std.range.primitives: hasLength; assert(_shift + index >= 0); static if (hasLength!Range) assert(_shift + index <= _range.length); } body { mixin (`return ` ~ op ~ `_range[_shift + index];`); } } static if (canSave!Range) auto save() @property { static if (isDynamicArray!Range) return typeof(this)(_shift, _range); else return typeof(this)(_shift, _range.save); } } private auto ptrShell(Range)(Range range, sizediff_t shift = 0) { return PtrShell!Range(shift, range); } @safe pure nothrow unittest { import std.internal.test.dummyrange; foreach (RB; AliasSeq!(ReturnBy.Reference, ReturnBy.Value)) { DummyRange!(RB, Length.Yes, RangeType.Random) range; range.reinit; assert(range.length >= 10); auto ptr = range.ptrShell; assert(ptr[0] == range[0]); auto save0 = range[0]; ptr[0] += 10; ++ptr[0]; assert(ptr[0] == save0 + 11); (ptr + 5)[2] = 333; assert(range[7] == 333); } } pure nothrow unittest { import std.internal.test.dummyrange; foreach (RB; AliasSeq!(ReturnBy.Reference, ReturnBy.Value)) { DummyRange!(RB, Length.Yes, RangeType.Random) range; range.reinit; assert(range.length >= 10); auto slice = range.sliced(10); assert(slice[0] == range[0]); auto save0 = range[0]; slice[0] += 10; ++slice[0]; assert(slice[0] == save0 + 11); slice[5 .. $][2] = 333; assert(range[7] == 333); } } private enum isSlicePointer(T) = isPointer!T || is(T : PtrShell!R, R); private struct LikePtr {} package template hasPtrBehavior(T) { static if (isPointer!T) enum hasPtrBehavior = true; else static if (!isAggregateType!T) enum hasPtrBehavior = false; else enum hasPtrBehavior = hasUDA!(T, LikePtr); } private template PtrTuple(Names...) { @LikePtr struct PtrTuple(Ptrs...) if (allSatisfy!(isSlicePointer, Ptrs) && Ptrs.length == Names.length) { Ptrs ptrs; static if (allSatisfy!(canSave, Ptrs)) auto save() @property { static if (anySatisfy!(hasElaborateAssign, Ptrs)) PtrTuple p; else PtrTuple p = void; foreach (i, ref ptr; ptrs) static if (isPointer!(Ptrs[i])) p.ptrs[i] = ptr; else p.ptrs[i] = ptr.save; return p; } void opOpAssign(string op)(sizediff_t shift) if (op == `+` || op == `-`) { foreach (ref ptr; ptrs) mixin (`ptr ` ~ op ~ `= shift;`); } auto opBinary(string op)(sizediff_t shift) if (op == `+` || op == `-`) { auto ret = this.ptrs; ret.opOpAssign!op(shift); return ret; } public struct Index { Ptrs _ptrs__; mixin (PtrTupleFrontMembers!Names); } auto opIndex(sizediff_t index) { auto p = ptrs; foreach (ref ptr; p) ptr += index; return Index(p); } auto front() @property { return Index(ptrs); } } } pure nothrow unittest { auto a = new int[20], b = new int[20]; import std.stdio; alias T = PtrTuple!("a", "b"); alias S = T!(int*, int*); auto t = S(a.ptr, b.ptr); t[4].a++; auto r = t[4]; r.b = r.a * 2; assert(b[4] == 2); t.front.a++; r = t.front; r.b = r.a * 2; assert(b[0] == 2); } private template PtrTupleFrontMembers(Names...) if (Names.length <= 32) { static if (Names.length) { alias Top = Names[0..$-1]; enum int m = Top.length; enum PtrTupleFrontMembers = PtrTupleFrontMembers!Top ~ " @property auto ref " ~ Names[$-1] ~ "() { static if (__traits(compiles,{ auto _f = _ptrs__[" ~ m.stringof ~ "].front; })) return _ptrs__[" ~ m.stringof ~ "].front; else return _ptrs__[" ~ m.stringof ~ "][0]; } "; } else { enum PtrTupleFrontMembers = ""; } } private template PrepareRangeType(Range) { static if (isPointer!Range) alias PrepareRangeType = Range; else alias PrepareRangeType = PtrShell!Range; } private enum bool isType(alias T) = false; private enum bool isType(T) = true; private enum isStringValue(alias T) = is(typeof(T) : string); private void _indexAssign(bool lastStrideEquals1, string op, size_t N, size_t RN, Range, RRange)(Slice!(N, Range) slice, Slice!(RN, RRange) value) if (N >= RN) { static if (N == 1) { static if (lastStrideEquals1 && (isPointer!Range || isDynamicArray!Range) && (isPointer!RRange || isDynamicArray!RRange)) { static if (isPointer!Range) auto l = slice._ptr; else auto l = slice._ptr._range[slice._ptr._shift .. slice._ptr._shift + slice._lengths[0]]; static if (isPointer!RRange) auto r = value._ptr; else auto r = value._ptr._range[value._ptr._shift .. value._ptr._shift + value._lengths[0]]; auto len = slice._lengths[0]; for (size_t i; i < len; i++) { mixin("l[i]" ~ op ~ "= r[i];"); } } else { while (slice._lengths[0]) { mixin("slice.front " ~ op ~ "= value.front;"); slice.popFront; value.popFront; } } } else static if (N == RN) { while (slice._lengths[0]) { _indexAssign!(lastStrideEquals1, op)(slice.front, value.front); slice.popFront; value.popFront; } } else { while (slice._lengths[0]) { _indexAssign!(lastStrideEquals1, op)(slice.front, value); slice.popFront; } } } private void _indexAssign(bool lastStrideEquals1, string op, size_t N, Range, T)(Slice!(N, Range) slice, T[] value) if (DynamicArrayDimensionsCount!(T[]) <= N) { assert(slice.length == value.length, __FUNCTION__ ~ ": argument must have the same length."); static if (N == 1) { static if (lastStrideEquals1 && (isPointer!Range || isDynamicArray!Range)) { static if (isPointer!Range) auto l = slice._ptr; else auto l = slice._ptr._range[slice._ptr._shift .. slice._ptr._shift + slice._lengths[0]]; auto r = value; auto len = slice._lengths[0]; for (size_t i; i < len; i++) { mixin("l[i]" ~ op ~ "= r[i];"); } } else { while (slice._lengths[0]) { mixin("slice.front " ~ op ~ "= value[0];"); slice.popFront; value = value[1..$]; } } } else static if (N == DynamicArrayDimensionsCount!(T[])) { while (slice._lengths[0]) { _indexAssign!(lastStrideEquals1, op)(slice.front, value[0]); slice.popFront; value = value[1 .. $]; } } else { while (slice._lengths[0]) { _indexAssign!(lastStrideEquals1, op)(slice.front, value); slice.popFront; } } } private void _indexAssign(bool lastStrideEquals1, string op, size_t N, Range, T)(Slice!(N, Range) slice, T value) if ((!isDynamicArray!T || isDynamicArray!(Slice!(N, Range).DeepElemType)) && !is(T : Slice!(RN, RRange), size_t RN, RRange)) { static if (N == 1) { static if (lastStrideEquals1 && (isPointer!Range || isDynamicArray!Range)) { static if (isPointer!Range) auto l = slice._ptr; else auto l = slice._ptr._range[slice._ptr._shift .. $]; auto len = slice._lengths[0]; for (size_t i; i < len; i++) { mixin("l[i]" ~ op ~ "= value;"); } } else { while (slice._lengths[0]) { mixin("slice.front " ~ op ~ "= value;"); slice.popFront; } } } else { while (slice._lengths[0]) { _indexAssign!(lastStrideEquals1, op)(slice.front, value); slice.popFront; } } } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/ndslice/package.d0000664000175000017500000003754212776215007023577 0ustar kaikai/+ ## Guide for Slice/BLAS contributors 1. Make sure functions are a. inlined(!), b. `@nogc`, c. `nothrow`, d. `pure`. For this reason, it is preferable to use _simple_ `assert`s with messages that can be computed at compile time. The goals are: 1. to reduce executable size for _any_ compilation mode 2. to reduce template bloat in object files 3. to reduce compilation time 4. to allow users to write extern C bindings for code libraries on `Slice` type. 2. `std.format`, `std.string`, and `std.conv` should not be used in error message formatting.`"Use" ~ Concatenation.stringof`. 3. `mixin template`s may be used for pretty error message formatting. 4. `Exception`s/`enforce`s should no be used to check indexes and lengths. Exceptions are only allowed for algorithms where validation of input data is too complicated for the user. `reshape` function is a good example of a case where Exceptions are required. If a function might throw an exception, an example with exception handing should be added. 5. For simple checks like matrix transposition, compile time flags should not be used. It is much better to opt for runtime matrix transposition. Furthermore, Slice type provides runtime matrix transposition out of the box. 6. _Fortran_VS_C_ flags should not be used. They are about notation, but not about the algorithm itself. For math world users, a corresponding code example might be included in the documentation. `transposed` / `everted` can be used in cache-friendly codes. 7. Compile time evaluation should not be used to produce dummy types like `IdentityMatrix`. 8. Memory allocation and algorithm logic should be separated whenever possible. 9. CTFE unittests should be added to new functions. +/ /** $(H1 Multidimensional Random Access Ranges) The package provides a multidimensional array implementation. It would be well suited to creating machine learning and image processing algorithms, but should also be general enough for use anywhere with homogeneously-typed multidimensional data. In addition, it includes various functions for iteration, accessing, and manipulation. Quick_Start: $(SUBREF slice, sliced) is a function designed to create a multidimensional view over a range. Multidimensional view is presented by $(SUBREF slice, Slice) type. ------ auto matrix = new double[12].sliced(3, 4); matrix[] = 0; ------ Note: In many examples $(LINK2 std_range.html#iota, std.range.iota) is used instead of a regular array, which makes it possible to carry out tests without memory allocation. $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Submodule) $(TH Declarations) ) $(TR $(TDNW Basic Level $(BR) $(SMALL $(SUBREF slice, Slice), its properties, operator overloading)) $(TDNW $(SUBMODULE slice)) $(TD $(SUBREF slice, sliced) $(SUBREF slice, Slice) $(SUBREF slice, assumeSameStructure) $(SUBREF slice, ReplaceArrayWithPointer) $(SUBREF slice, DeepElementType) ) ) $(TR $(TDNW Middle Level $(BR) $(SMALL Various iteration operators)) $(TDNW $(SUBMODULE iteration)) $(TD $(SUBREF iteration, transposed) $(SUBREF iteration, strided) $(SUBREF iteration, reversed) $(SUBREF iteration, rotated) $(SUBREF iteration, everted) $(SUBREF iteration, swapped) $(SUBREF iteration, allReversed) $(SUBREF iteration, dropToHypercube) and other `drop` primitives ) ) $(TR $(TDNW Advanced Level $(BR) $(SMALL Abstract operators for loop free programming $(BR) Take `movingWindowByChannel` as an example)) $(TDNW $(SUBMODULE selection)) $(TD $(SUBREF selection, blocks) $(SUBREF selection, windows) $(SUBREF selection, diagonal) $(SUBREF selection, reshape) $(SUBREF selection, byElement) $(SUBREF selection, byElementInStandardSimplex) $(SUBREF selection, indexSlice) $(SUBREF selection, pack) $(SUBREF selection, evertPack) $(SUBREF selection, unpack) ) ) )) $(H2 Example: Image Processing) A median filter is implemented as an example. The function `movingWindowByChannel` can also be used with other filters that use a sliding window as the argument, in particular with convolution matrices such as the $(LINK2 https://en.wikipedia.org/wiki/Sobel_operator, Sobel operator). `movingWindowByChannel` iterates over an image in sliding window mode. Each window is transferred to a `filter`, which calculates the value of the pixel that corresponds to the given window. This function does not calculate border cases in which a window overlaps the image partially. However, the function can still be used to carry out such calculations. That can be done by creating an amplified image, with the edges reflected from the original image, and then applying the given function to the new file. Note: You can find the example at $(LINK2 https://github.com/DlangScience/examples/tree/master/image_processing/median-filter, GitHub). ------- /++ Params: filter = unary function. Dimension window 2D is the argument. image = image dimensions `(h, w, c)`, where с is the number of channels in the image nr = number of rows in the window nс = number of columns in the window Returns: image dimensions `(h - nr + 1, w - nc + 1, c)`, where с is the number of channels in the image. Dense data layout is guaranteed. +/ Slice!(3, C*) movingWindowByChannel(alias filter, C) (Slice!(3, C*) image, size_t nr, size_t nc) { import std.algorithm.iteration: map; import std.array: array; // 0. 3D // The last dimension represents the color channel. auto wnds = image // 1. 2D composed of 1D // Packs the last dimension. .pack!1 // 2. 2D composed of 2D composed of 1D // Splits image into overlapping windows. .windows(nr, nc) // 3. 5D // Unpacks the windows. .unpack // 4. 5D // Brings the color channel dimension to the third position. .transposed!(0, 1, 4) // 5. 3D Composed of 2D // Packs the last two dimensions. .pack!2; return wnds // 6. Range composed of 2D // Gathers all windows in the range. .byElement // 7. Range composed of pixels // 2D to pixel lazy conversion. .map!filter // 8. `C[]` // The only memory allocation in this function. .array // 9. 3D // Returns slice with corresponding shape. .sliced(wnds.shape); } ------- A function that calculates the value of iterator median is also necessary. ------- /++ Params: r = input range buf = buffer with length no less than the number of elements in `r` Returns: median value over the range `r` +/ T median(Range, T)(Range r, T[] buf) { import std.algorithm.sorting: topN; size_t n; foreach (e; r) buf[n++] = e; auto m = n >> 1; buf[0 .. n].topN(m); return buf[m]; } ------- The `main` function: ------- void main(string[] args) { import std.conv: to; import std.getopt: getopt, defaultGetoptPrinter; import std.path: stripExtension; uint nr, nc, def = 3; auto helpInformation = args.getopt( "nr", "number of rows in window, default value is " ~ def.to!string, &nr, "nc", "number of columns in window, default value is equal to nr", &nc); if (helpInformation.helpWanted) { defaultGetoptPrinter( "Usage: median-filter [] []\noptions:", helpInformation.options); return; } if (!nr) nr = def; if (!nc) nc = nr; auto buf = new ubyte[nr * nc]; foreach (name; args[1 .. $]) { import imageformats; // can be found at code.dlang.org IFImage image = read_image(name); auto ret = image.pixels .sliced(cast(size_t)image.h, cast(size_t)image.w, cast(size_t)image.c) .movingWindowByChannel !(window => median(window.byElement, buf)) (nr, nc); write_image( name.stripExtension ~ "_filtered.png", ret.length!1, ret.length!0, (&ret[0, 0, 0])[0 .. ret.elementsCount]); } } ------- This program works both with color and grayscale images. ------- $ median-filter --help Usage: median-filter [] [] options: --nr number of rows in window, default value is 3 --nc number of columns in window default value equals to nr -h --help This help information. ------- $(H2 Compared with `numpy.ndarray`) numpy is undoubtedly one of the most effective software packages that has facilitated the work of many engineers and scientists. However, due to the specifics of implementation of Python, a programmer who wishes to use the functions not represented in numpy may find that the built-in functions implemented specifically for numpy are not enough, and their Python implementations work at a very low speed. Extending numpy can be done, but is somewhat laborious as even the most basic numpy functions that refer directly to `ndarray` data must be implemented in C for reasonable performance. At the same time, while working with `ndslice`, an engineer has access to the whole set of standard D library, so the functions he creates will be as efficient as if they were written in C. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Ilya Yaroshenko Acknowledgements: John Loughran Colvin Source: $(PHOBOSSRC std/_experimental/_ndslice/_package.d) Macros: SUBMODULE = $(LINK2 std_experimental_ndslice_$1.html, std.experimental.ndslice.$1) SUBREF = $(LINK2 std_experimental_ndslice_$1.html#.$2, $(TT $2))$(NBSP) T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) T4=$(TR $(TDNW $(LREF $1)) $(TD $2) $(TD $3) $(TD $4)) */ module std.experimental.ndslice; public import std.experimental.ndslice.slice; public import std.experimental.ndslice.iteration; public import std.experimental.ndslice.selection; // relaxed example unittest { static Slice!(3, ubyte*) movingWindowByChannel (Slice!(3, ubyte*) image, size_t nr, size_t nc, ubyte delegate(Slice!(2, ubyte*)) filter) { import std.algorithm.iteration: map; import std.array: array; auto wnds = image .pack!1 .windows(nr, nc) .unpack .transposed!(0, 1, 4) .pack!2; return wnds .byElement .map!filter .array .sliced(wnds.shape); } static T median(Range, T)(Range r, T[] buf) { import std.algorithm.sorting: topN; size_t n; foreach (e; r) buf[n++] = e; auto m = n >> 1; buf[0 .. n].topN(m); return buf[m]; } import std.conv: to; import std.getopt: getopt, defaultGetoptPrinter; import std.path: stripExtension; auto args = ["std"]; uint nr, nc, def = 3; auto helpInformation = args.getopt( "nr", "number of rows in window, default value is " ~ def.to!string, &nr, "nc", "number of columns in window default value equals to nr", &nc); if (helpInformation.helpWanted) { defaultGetoptPrinter( "Usage: median-filter [] []\noptions:", helpInformation.options); return; } if (!nr) nr = def; if (!nc) nc = nr; auto buf = new ubyte[nr * nc]; foreach (name; args[1 .. $]) { auto ret = movingWindowByChannel (new ubyte[300].sliced(10, 10, 3), nr, nc, window => median(window.byElement, buf)); } } @safe @nogc pure nothrow unittest { import std.algorithm.comparison: equal; import std.range: iota; immutable r = 1000.iota; auto t0 = r.sliced(1000); assert(t0.front == 0); assert(t0.back == 999); assert(t0[9] == 9); auto t1 = t0[10 .. 20]; assert(t1.front == 10); assert(t1.back == 19); assert(t1[9] == 19); t1.popFront(); assert(t1.front == 11); t1.popFront(); assert(t1.front == 12); t1.popBack(); assert(t1.back == 18); t1.popBack(); assert(t1.back == 17); assert(t1.equal(iota(12, 18))); } pure nothrow unittest { import std.algorithm.comparison: equal; import std.array: array; import std.range: iota; auto r = 1000.iota.array; auto t0 = r.sliced(1000); assert(t0.length == 1000); assert(t0.front == 0); assert(t0.back == 999); assert(t0[9] == 9); auto t1 = t0[10 .. 20]; assert(t1.front == 10); assert(t1.back == 19); assert(t1[9] == 19); t1.popFront(); assert(t1.front == 11); t1.popFront(); assert(t1.front == 12); t1.popBack(); assert(t1.back == 18); t1.popBack(); assert(t1.back == 17); assert(t1.equal(iota(12, 18))); t1.front = 13; assert(t1.front == 13); t1.front++; assert(t1.front == 14); t1.front += 2; assert(t1.front == 16); t1.front = 12; assert((t1.front = 12) == 12); t1.back = 13; assert(t1.back == 13); t1.back++; assert(t1.back == 14); t1.back += 2; assert(t1.back == 16); t1.back = 12; assert((t1.back = 12) == 12); t1[3] = 13; assert(t1[3] == 13); t1[3]++; assert(t1[3] == 14); t1[3] += 2; assert(t1[3] == 16); t1[3] = 12; assert((t1[3] = 12) == 12); t1[3 .. 5] = 100; assert(t1[2] != 100); assert(t1[3] == 100); assert(t1[4] == 100); assert(t1[5] != 100); t1[3 .. 5] += 100; assert(t1[2] < 100); assert(t1[3] == 200); assert(t1[4] == 200); assert(t1[5] < 100); --t1[3 .. 5]; assert(t1[2] < 100); assert(t1[3] == 199); assert(t1[4] == 199); assert(t1[5] < 100); --t1[]; assert(t1[3] == 198); assert(t1[4] == 198); t1[] += 2; assert(t1[3] == 200); assert(t1[4] == 200); t1[] *= t1[]; assert(t1[3] == 40000); assert(t1[4] == 40000); assert(&t1[$ - 1] is &(t1.back())); } @safe @nogc pure nothrow unittest { import std.range: iota; auto r = (10_000L * 2 * 3 * 4).iota; auto t0 = r.sliced(10, 20, 30, 40); assert(t0.length == 10); assert(t0.length!0 == 10); assert(t0.length!1 == 20); assert(t0.length!2 == 30); assert(t0.length!3 == 40); } pure nothrow unittest { import std.experimental.ndslice.internal: Iota; import std.meta: AliasSeq; import std.range; import std.typecons: Tuple; foreach (R; AliasSeq!( int*, int[], typeof(1.iota), const(int)*, const(int)[], immutable(int)*, immutable(int)[], double*, double[], typeof(10.0.iota), Tuple!(double, int[string])*, Tuple!(double, int[string])[])) foreach (n; Iota!(1, 4)) { alias S = Slice!(n, R); static assert(isRandomAccessRange!S); static assert(hasSlicing!S); static assert(hasLength!S); } immutable int[] im = [1,2,3,4,5,6]; auto slice = im.sliced(2, 3); } pure nothrow unittest { auto tensor = new int[3 * 4 * 8].sliced(3, 4, 8); assert(&(tensor.back.back.back()) is &tensor[2, 3, 7]); assert(&(tensor.front.front.front()) is &tensor[0, 0, 0]); } pure nothrow unittest { import std.experimental.ndslice.selection: pack; auto slice = new int[24].sliced(2, 3, 4); auto r0 = slice.pack!1[1, 2]; slice.pack!1[1, 2][] = 4; auto r1 = slice[1, 2]; assert(slice[1, 2, 3] == 4); } pure nothrow unittest { auto ar = new int[3 * 8 * 9]; auto tensor = ar.sliced(3, 8, 9); tensor[0, 1, 2] = 4; tensor[0, 1, 2]++; assert(tensor[0, 1, 2] == 5); tensor[0, 1, 2]--; assert(tensor[0, 1, 2] == 4); tensor[0, 1, 2] += 2; assert(tensor[0, 1, 2] == 6); auto matrix = tensor[0 .. $, 1, 0 .. $]; matrix[] = 10; assert(tensor[0, 1, 2] == 10); assert(matrix[0, 2] == tensor[0, 1, 2]); assert(&matrix[0, 2] is &tensor[0, 1, 2]); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/ndslice/internal.d0000664000175000017500000001153212776215007024007 0ustar kaikaimodule std.experimental.ndslice.internal; import std.traits; import std.meta; //: AliasSeq, anySatisfy, Filter, Reverse; package: enum string tailErrorMessage( string fun = __FUNCTION__, string pfun = __PRETTY_FUNCTION__) = " - - - Error in function " ~ fun ~ " - - - Function prototype " ~ pfun ~ " _____"; mixin template _DefineRet() { alias Ret = typeof(return); static if (hasElaborateAssign!(Ret.PureRange)) Ret ret; else Ret ret = void; } mixin template DimensionsCountCTError() { static assert(Dimensions.length <= N, "Dimensions list length = " ~ Dimensions.length.stringof ~ " should be less than or equal to N = " ~ N.stringof ~ tailErrorMessage!()); } enum DimensionsCountRTError = q{ assert(dimensions.length <= N, "Dimensions list length should be less than or equal to N = " ~ N.stringof ~ tailErrorMessage!()); }; mixin template DimensionCTError() { static assert(dimension >= 0, "dimension = " ~ dimension.stringof ~ " at position " ~ i.stringof ~ " should be greater than or equal to 0" ~ tailErrorMessage!()); static assert(dimension < N, "dimension = " ~ dimension.stringof ~ " at position " ~ i.stringof ~ " should be less than N = " ~ N.stringof ~ tailErrorMessage!()); } enum DimensionRTError = q{ static if (isSigned!(typeof(dimension))) assert(dimension >= 0, "dimension should be greater than or equal to 0" ~ tailErrorMessage!()); assert(dimension < N, "dimension should be less than N = " ~ N.stringof ~ tailErrorMessage!()); }; private alias IncFront(Seq...) = AliasSeq!(Seq[0] + 1, Seq[1 .. $]); private alias DecFront(Seq...) = AliasSeq!(Seq[0] - 1, Seq[1 .. $]); private enum bool isNotZero(alias t) = t != 0; alias NSeqEvert(Seq...) = Filter!(isNotZero, DecFront!(Reverse!(IncFront!Seq))); alias Parts(Seq...) = DecAll!(IncFront!Seq); alias Snowball(Seq...) = AliasSeq!(size_t.init, SnowballImpl!(size_t.init, Seq)); private template SnowballImpl(size_t val, Seq...) { static if (Seq.length == 0) alias SnowballImpl = AliasSeq!(); else alias SnowballImpl = AliasSeq!(Seq[0] + val, SnowballImpl!(Seq[0] + val, Seq[1 .. $])); } private template DecAll(Seq...) { static if (Seq.length == 0) alias DecAll = AliasSeq!(); else alias DecAll = AliasSeq!(Seq[0] - 1, DecAll!(Seq[1 .. $])); } template SliceFromSeq(Range, Seq...) { static if (Seq.length == 0) alias SliceFromSeq = Range; else { import std.experimental.ndslice.slice: Slice; alias SliceFromSeq = SliceFromSeq!(Slice!(Seq[$ - 1], Range), Seq[0 .. $ - 1]); } } template DynamicArrayDimensionsCount(T) { static if(isDynamicArray!T) enum size_t DynamicArrayDimensionsCount = 1 + DynamicArrayDimensionsCount!(typeof(T.init[0])); else enum size_t DynamicArrayDimensionsCount = 0; } bool isPermutation(size_t N)(auto ref in size_t[N] perm) { int[N] mask; if (isValidPartialPermutationImpl(perm, mask) == false) return false; foreach (e; mask) if (e == false) return false; return true; } bool isValidPartialPermutation(size_t N)(in size_t[] perm) { int[N] mask; return isValidPartialPermutationImpl(perm, mask); } private bool isValidPartialPermutationImpl(size_t N)(in size_t[] perm, ref int[N] mask) { if (perm.length == 0) return false; foreach (j; perm) { if (j >= N) return false; if (mask[j]) //duplicate return false; mask[j] = true; } return true; } enum isIndex(I) = is(I : size_t); private enum isReference(P) = hasIndirections!P || isFunctionPointer!P || is(P == interface); enum hasReference(T) = anySatisfy!(isReference, RepresentationTypeTuple!T); alias ImplicitlyUnqual(T) = Select!(isImplicitlyConvertible!(T, Unqual!T), Unqual!T, T); //TODO: replace with `static foreach` template Iota(size_t i, size_t j) { static assert(i <= j, "Iota: i should be less than or equal to j"); static if (i == j) alias Iota = AliasSeq!(); else alias Iota = AliasSeq!(i, Iota!(i + 1, j)); } template Repeat(T, size_t N) { static if (N) alias Repeat = AliasSeq!(Repeat!(T, N - 1), T); else alias Repeat = AliasSeq!(); } size_t lengthsProduct(size_t N)(auto ref in size_t[N] lengths) { size_t length = lengths[0]; foreach (i; Iota!(1, N)) length *= lengths[i]; return length; } pure nothrow unittest { const size_t[3] lengths = [3, 4, 5]; assert(lengthsProduct(lengths) == 60); assert(lengthsProduct([3, 4, 5]) == 60); } enum canSave(T) = isPointer!T || isDynamicArray!T || __traits(compiles, { T r1 = T.init; auto s1 = r1.save; static assert (is(typeof(s1) == T)); }); struct _Slice { size_t i, j; } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/ndslice/selection.d0000664000175000017500000013004412776215007024160 0ustar kaikai/** $(SCRIPT inhibitQuickIndex = 1;) This is a submodule of $(LINK2 std_experimental_ndslice.html, std.experimental.ndslice). Selectors create new views and iteration patterns over the same data, without copying. $(H2 Subspace selectors) Subspace selectors serve to generalize and combine other selectors easily. For a slice of `Slice!(N, Range)` type `slice.pack!K` creates a slice of slices of `Slice!(N-K, Slice!(K+1, Range))` type by packing the last `K` dimensions of the top dimension pack, and the type of element of `slice.byElement` is `Slice!(K, Range)`. Another way to use $(LREF pack) is transposition of dimension packs using $(LREF evertPack). Examples of use of subspace selectors are available for selectors, $(SUBREF slice, Slice.shape), and $(SUBREF slice, Slice.elementsCount). $(BOOKTABLE , $(TR $(TH Function Name) $(TH Description)) $(T2 pack , returns slice of slices) $(T2 unpack , merges all dimension packs) $(T2 evertPack, reverses dimension packs) ) $(BOOKTABLE $(H2 Selectors), $(TR $(TH Function Name) $(TH Description)) $(T2 byElement, a random access range of all elements with `index` property) $(T2 byElementInStandardSimplex, an input range of all elements in standard simplex of hypercube with `index` property. If the slice has two dimensions, it is a range of all elements of upper left triangular matrix.) $(T2 indexSlice, returns a slice with elements equal to the initial index) $(T2 reshape, returns a new slice for the same data) $(T2 diagonal, 1-dimensional slice composed of diagonal elements) $(T2 blocks, n-dimensional slice composed of n-dimensional non-overlapping blocks. If the slice has two dimensions, it is a block matrix.) $(T2 windows, n-dimensional slice of n-dimensional overlapping windows. If the slice has two dimensions, it is a sliding window.) ) License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Ilya Yaroshenko Source: $(PHOBOSSRC std/_experimental/_ndslice/_selection.d) Macros: SUBMODULE = $(LINK2 std_experimental_ndslice_$1.html, std.experimental.ndslice.$1) SUBREF = $(LINK2 std_experimental_ndslice_$1.html#.$2, $(TT $2))$(NBSP) T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) T4=$(TR $(TDNW $(LREF $1)) $(TD $2) $(TD $3) $(TD $4)) */ module std.experimental.ndslice.selection; import std.traits; import std.meta; //: allSatisfy; import std.experimental.ndslice.internal; import std.experimental.ndslice.slice; //: Slice; /++ Creates a packed slice, i.e. slice of slices. The function does not carry out any calculations, it simply returns the same binary data presented differently. Params: K = sizes of dimension packs Returns: `pack!K` returns `Slice!(N-K, Slice!(K+1, Range))`; `slice.pack!(K1, K2, ..., Kn)` is the same as `slice.pacKed!K1.pacKed!K2. ... pacKed!Kn`. +/ template pack(K...) { auto pack(size_t N, Range)(auto ref Slice!(N, Range) slice) { template Template(size_t NInner, Range, R...) { static if (R.length > 0) { static if (NInner > R[0]) alias Template = Template!(NInner - R[0], Slice!(R[0] + 1, Range), R[1 .. $]); else static assert(0, "Sum of all lengths of packs " ~ K.stringof ~ " should be less than N = "~ N.stringof ~ tailErrorMessage!()); } else { alias Template = Slice!(NInner, Range); } } with (slice) return Template!(N, Range, K)(_lengths, _strides, _ptr); } } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range.primitives: ElementType; import std.range: iota; import std.algorithm.comparison: equal; auto r = (3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11).iota; auto a = r.sliced(3, 4, 5, 6, 7, 8, 9, 10, 11); auto b = a.pack!(2, 3); // same as `a.pack!2.pack!3` auto c = b[1, 2, 3, 4]; auto d = c[5, 6, 7]; auto e = d[8, 9]; auto g = a[1, 2, 3, 4, 5, 6, 7, 8, 9]; assert(e == g); assert(a == b); assert(c == a[1, 2, 3, 4]); alias R = typeof(r); static assert(is(typeof(b) == typeof(a.pack!2.pack!3))); static assert(is(typeof(b) == Slice!(4, Slice!(4, Slice!(3, R))))); static assert(is(typeof(c) == Slice!(3, Slice!(3, R)))); static assert(is(typeof(d) == Slice!(2, R))); static assert(is(typeof(e) == ElementType!R)); } @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.selection; import std.range: iota; auto r = (3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11).iota; auto a = r.sliced(3, 4, 5, 6, 7, 8, 9, 10, 11); auto b = a.pack!(2, 3); static assert(b.shape.length == 4); static assert(b.structure.lengths.length == 4); static assert(b.structure.strides.length == 4); static assert(b .byElement.front .shape.length == 3); static assert(b .byElement.front .byElement.front .shape.length == 2); } /++ Unpacks a packed slice. The function does not carry out any calculations, it simply returns the same binary data presented differently. Params: slice = packed slice Returns: unpacked slice See_also: $(LREF pack), $(LREF evertPack) +/ Slice!(N, Range).PureThis unpack(size_t N, Range)(auto ref Slice!(N, Range) slice) { with (slice) return PureThis(_lengths, _strides, _ptr); } /// pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; import std.algorithm.comparison: equal; auto r = (3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11).iota; auto a = r.sliced(3, 4, 5, 6, 7, 8, 9, 10, 11); auto b = a.pack!(2, 3).unpack(); static assert(is(typeof(a) == typeof(b))); assert(a == b); } /++ Reverses the order of dimension packs. This function is used in a functional pipeline with other selectors. Params: slice = packed slice Returns: packed slice See_also: $(LREF pack), $(LREF unpack) +/ SliceFromSeq!(Slice!(N, Range).PureRange, NSeqEvert!(Slice!(N, Range).NSeq)) evertPack(size_t N, Range)(auto ref Slice!(N, Range) slice) { mixin _DefineRet; static assert(Ret.NSeq.length > 0); with (slice) { alias C = Snowball!(Parts!NSeq); alias D = Reverse!(Snowball!(Reverse!(Parts!NSeq))); foreach (i, _; NSeq) { foreach (j; Iota!(0, C[i + 1] - C[i])) { ret._lengths[j + D[i + 1]] = _lengths[j + C[i]]; ret._strides[j + D[i + 1]] = _strides[j + C[i]]; } } ret._ptr = _ptr; return ret; } } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration: transposed; import std.range: iota; auto slice = (3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11).iota .sliced(3, 4, 5, 6, 7, 8, 9, 10, 11); assert(slice .pack!2 .evertPack .unpack == slice.transposed!( slice.shape.length-2, slice.shape.length-1)); } /// pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration: transposed; import std.range.primitives: ElementType; import std.range: iota; import std.algorithm.comparison: equal; auto r = (3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11).iota; auto a = r.sliced(3, 4, 5, 6, 7, 8, 9, 10, 11); auto b = a .pack!(2, 3) .evertPack; auto c = b[8, 9]; auto d = c[5, 6, 7]; auto e = d[1, 2, 3, 4]; auto g = a[1, 2, 3, 4, 5, 6, 7, 8, 9]; assert(e == g); assert(a == b.evertPack); assert(c == a.transposed!(7, 8, 4, 5, 6)[8, 9]); alias R = typeof(r); static assert(is(typeof(b) == Slice!(2, Slice!(4, Slice!(5, R))))); static assert(is(typeof(c) == Slice!(3, Slice!(5, R)))); static assert(is(typeof(d) == Slice!(4, R))); static assert(is(typeof(e) == ElementType!R)); } @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; static assert(is(typeof(new int[20] .sliced(20) .evertPack) == Slice!(1LU, int*))); static assert(is(typeof(new int[20] .sliced(20) .sliced(3) .evertPack) == Slice!(2LU, int*))); static assert(is(typeof(new int[20] .sliced(20) .sliced(1,2,3) .sliced(3) .evertPack) == Slice!(3LU, Slice!(2LU, int*)))); static assert(is(typeof(new int[20] .sliced(20) .sliced(1,2,3) .evertPack) == Slice!(4LU, int*))); } /++ Returns a 1-dimensional slice over the main diagonal of an n-dimensional slice. `diagonal` can be generalized with other selectors such as $(LREF blocks) (diagonal blocks) and $(LREF windows) (multi-diagonal slice). Params: N = dimension count slice = input slice Returns: packed `1`-dimensional composed of `N`-dimensional slices +/ Slice!(1, Range) diagonal(size_t N, Range)(auto ref Slice!(N, Range) slice) { auto NewN = slice.PureN - N + 1; mixin _DefineRet; ret._lengths[0] = slice._lengths[0]; ret._strides[0] = slice._strides[0]; foreach (i; Iota!(1, N)) { if (ret._lengths[0] > slice._lengths[i]) ret._lengths[0] = slice._lengths[i]; ret._strides[0] += slice._strides[i]; } foreach (i; Iota!(1, ret.PureN)) { ret._lengths[i] = slice._lengths[i + N - 1]; ret._strides[i] = slice._strides[i + N - 1]; } ret._ptr = slice._ptr; return ret; } /// Matrix, main diagonal @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.algorithm.comparison: equal; import std.range: iota, only; // ------- // | 0 1 2 | // | 3 4 5 | // ------- //-> // | 0 4 | assert(6.iota .sliced(2, 3) .diagonal .equal(only(0, 4))); } /// ditto pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new int[9].sliced(3, 3); int i; foreach (ref e; slice.diagonal) e = ++i; assert(slice == [ [1, 0, 0], [0, 2, 0], [0, 0, 3]]); } /// Matrix, subdiagonal @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration: dropOne; import std.algorithm.comparison: equal; import std.range: iota, only; // ------- // | 0 1 2 | // | 3 4 5 | // ------- //-> // | 1 5 | assert(6.iota .sliced(2, 3) .dropOne!1 .diagonal .equal(only(1, 5))); } /// Matrix, antidiagonal @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration: dropToHypercube, reversed; import std.algorithm.comparison: equal; import std.range: iota, only; // ------- // | 0 1 2 | // | 3 4 5 | // ------- //-> // | 1 3 | assert(6.iota .sliced(2, 3) .dropToHypercube .reversed!1 .diagonal .equal(only(1, 3))); } /// 3D, main diagonal @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.algorithm.comparison: equal; import std.range: iota, only; // ----------- // | 0 1 2 | // | 3 4 5 | // - - - - - - // | 6 7 8 | // | 9 10 11 | // ----------- //-> // | 0 10 | assert(12.iota .sliced(2, 2, 3) .diagonal .equal(only(0, 10))); } /// 3D, subdiagonal @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration: dropOne; import std.algorithm.comparison: equal; import std.range: iota, only; // ----------- // | 0 1 2 | // | 3 4 5 | // - - - - - - // | 6 7 8 | // | 9 10 11 | // ----------- //-> // | 1 11 | assert(12.iota .sliced(2, 2, 3) .dropOne!2 .diagonal .equal(only(1, 11))); } /// 3D, diagonal plain @safe pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration: dropOne; import std.algorithm.comparison: equal; import std.range: iota; // ----------- // | 0 1 2 | // | 3 4 5 | // | 6 7 8 | // - - - - - - // | 9 10 11 | // | 12 13 14 | // | 15 16 17 | // - - - - - - // | 18 20 21 | // | 22 23 24 | // | 24 25 26 | // ----------- //-> // ----------- // | 0 4 8 | // | 9 13 17 | // | 18 23 26 | // ----------- auto slice = 27.iota .sliced(3, 3, 3) .pack!2 .evertPack .diagonal .evertPack; assert(slice == [[ 0, 4, 8], [ 9, 13, 17], [18, 22, 26]]); } /++ Returns an n-dimensional slice of n-dimensional non-overlapping blocks. `blocks` can be generalized with other selectors. For example, `blocks` in combination with $(LREF diagonal) can be used to get a slice of diagonal blocks. Params: N = dimension count slice = slice to be split into blocks lengths = dimensions of block, residual blocks are ignored Returns: packed `N`-dimensional slice composed of `N`-dimensional slices +/ Slice!(N, Slice!(N+1, Range)) blocks(size_t N, Range, Lengths...)(auto ref Slice!(N, Range) slice, Lengths lengths) if (allSatisfy!(isIndex, Lengths) && Lengths.length == N) in { foreach (i, length; lengths) assert(length > 0, "length of dimension = " ~ i.stringof ~ " must be positive" ~ tailErrorMessage!()); } body { mixin _DefineRet; foreach (dimension; Iota!(0, N)) { ret._lengths[dimension] = slice._lengths[dimension] / lengths[dimension]; ret._strides[dimension] = slice._strides[dimension]; if (ret._lengths[dimension]) //do not remove `if (...)` ret._strides[dimension] *= lengths[dimension]; ret._lengths[dimension + N] = lengths[dimension]; ret._strides[dimension + N] = slice._strides[dimension]; } foreach (dimension; Iota!(N, slice.PureN)) { ret._lengths[dimension + N] = slice._lengths[dimension]; ret._strides[dimension + N] = slice._strides[dimension]; } ret._ptr = slice._ptr; return ret; } /// pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new int[40].sliced(5, 8); auto blocks = slice.blocks(2, 3); int i; foreach (block; blocks.byElement) block[] = ++i; assert(blocks == [[[[1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2]]], [[[3, 3, 3], [3, 3, 3]], [[4, 4, 4], [4, 4, 4]]]]); assert( slice == [[1, 1, 1, 2, 2, 2, 0, 0], [1, 1, 1, 2, 2, 2, 0, 0], [3, 3, 3, 4, 4, 4, 0, 0], [3, 3, 3, 4, 4, 4, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]); } /// Diagonal blocks pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new int[40].sliced(5, 8); auto blocks = slice.blocks(2, 3); auto diagonalBlocks = blocks.diagonal.unpack; diagonalBlocks[0][] = 1; diagonalBlocks[1][] = 2; assert(diagonalBlocks == [[[1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2]]]); assert(blocks == [[[[1, 1, 1], [1, 1, 1]], [[0, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [0, 0, 0]], [[2, 2, 2], [2, 2, 2]]]]); assert(slice == [[1, 1, 1, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 2, 2, 2, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]); } /// Matrix divided into vertical blocks pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new int[65].sliced(5, 13); auto blocks = slice .pack!1 .evertPack .blocks(3) .unpack .pack!2; int i; foreach (block; blocks.byElement) block[] = ++i; assert(slice == [[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0], [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0], [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0], [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0], [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0]]); } /++ Returns an n-dimensional slice of n-dimensional overlapping windows. `windows` can be generalized with other selectors. For example, `windows` in combination with $(LREF diagonal) can be used to get a multi-diagonal slice. Params: N = dimension count slice = slice to be iterated lengths = dimensions of windows Returns: packed `N`-dimensional slice composed of `N`-dimensional slices +/ Slice!(N, Slice!(N+1, Range)) windows(size_t N, Range, Lengths...)(auto ref Slice!(N, Range) slice, Lengths lengths) if (allSatisfy!(isIndex, Lengths) && Lengths.length == N) in { foreach (i, length; lengths) assert(length > 0, "length of dimension = " ~ i.stringof ~ " must be positive" ~ tailErrorMessage!()); } body { mixin _DefineRet; foreach (dimension; Iota!(0, N)) { ret._lengths[dimension] = slice._lengths[dimension] >= lengths[dimension] ? slice._lengths[dimension] - lengths[dimension] + 1: 0; ret._strides[dimension] = slice._strides[dimension]; ret._lengths[dimension + N] = lengths[dimension]; ret._strides[dimension + N] = slice._strides[dimension]; } foreach (dimension; Iota!(N, slice.PureN)) { ret._lengths[dimension + N] = slice._lengths[dimension]; ret._strides[dimension + N] = slice._strides[dimension]; } ret._ptr = slice._ptr; return ret; } /// pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new int[40].sliced(5, 8); auto windows = slice.windows(2, 3); foreach (window; windows.byElement) window[] += 1; assert(slice == [[1, 2, 3, 3, 3, 3, 2, 1], [2, 4, 6, 6, 6, 6, 4, 2], [2, 4, 6, 6, 6, 6, 4, 2], [2, 4, 6, 6, 6, 6, 4, 2], [1, 2, 3, 3, 3, 3, 2, 1]]); } /// pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new int[40].sliced(5, 8); auto windows = slice.windows(2, 3); windows[1, 2][] = 1; windows[1, 2][0, 1] += 1; windows.unpack[1, 2, 0, 1] += 1; assert(slice == [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 3, 1, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]); } /// Multi-diagonal matrix pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new int[64].sliced(8, 8); auto windows = slice.windows(3, 3); auto multidiagonal = windows .diagonal .unpack; foreach (window; multidiagonal) window[] += 1; assert(slice == [[ 1, 1, 1, 0, 0, 0, 0, 0], [ 1, 2, 2, 1, 0, 0, 0, 0], [ 1, 2, 3, 2, 1, 0, 0, 0], [0, 1, 2, 3, 2, 1, 0, 0], [0, 0, 1, 2, 3, 2, 1, 0], [0, 0, 0, 1, 2, 3, 2, 1], [0, 0, 0, 0, 1, 2, 2, 1], [0, 0, 0, 0, 0, 1, 1, 1]]); } /// Sliding window over matrix columns pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new int[40].sliced(5, 8); auto windows = slice .pack!1 .evertPack .windows(3) .unpack .pack!2; foreach (window; windows.byElement) window[] += 1; assert(slice == [[1, 2, 3, 3, 3, 3, 2, 1], [1, 2, 3, 3, 3, 3, 2, 1], [1, 2, 3, 3, 3, 3, 2, 1], [1, 2, 3, 3, 3, 3, 2, 1], [1, 2, 3, 3, 3, 3, 2, 1]]); } /++ Returns a new slice for the same data. Params: slice = slice to be reshaped lengths = list of new dimensions. One of the lengths can be set to `-1`. In this case, the corresponding dimension is inferable. Returns: reshaped slice Throws: $(LREF ReshapeException) if the slice cannot be reshaped with the input lengths. +/ Slice!(Lengths.length, Range) reshape ( size_t N, Range , Lengths... ) (auto ref Slice!(N, Range) slice, Lengths lengths) if ( allSatisfy!(isIndex, Lengths) && Lengths.length) { mixin _DefineRet; foreach (i; Iota!(0, ret.N)) ret._lengths[i] = lengths[i]; immutable size_t eco = slice.elementsCount; size_t ecn = ret .elementsCount; if (eco == 0) throw new ReshapeException( slice._lengths.dup, slice._strides.dup, ret. _lengths.dup, "slice should be not empty"); foreach (i; Iota!(0, ret.N)) if (ret._lengths[i] == -1) { ecn = -ecn; ret._lengths[i] = eco / ecn; ecn *= ret._lengths[i]; break; } if (eco != ecn) throw new ReshapeException( slice._lengths.dup, slice._strides.dup, ret. _lengths.dup, "total element count should be the same"); for (size_t oi, ni, oj, nj; oi < slice.N && ni < ret.N; oi = oj, ni = nj) { size_t op = slice._lengths[oj++]; size_t np = ret ._lengths[nj++]; for (;;) { if (op < np) op *= slice._lengths[oj++]; if (op > np) np *= ret ._lengths[nj++]; if (op == np) break; } while (oj < slice.N && slice._lengths[oj] == 1) oj++; while (nj < ret .N && ret ._lengths[nj] == 1) nj++; for (size_t l = oi, r = oi + 1; r < oj; r++) if (slice._lengths[r] != 1) { if (slice._strides[l] != slice._lengths[r] * slice._strides[r]) throw new ReshapeException( slice._lengths.dup, slice._strides.dup, ret. _lengths.dup, "structure is incompatible with new shape"); l = r; } ret._strides[nj - 1] = slice._strides[oj - 1]; foreach_reverse(i; ni .. nj - 1) ret._strides[i] = ret._lengths[i + 1] * ret._strides[i + 1]; assert((oi == slice.N) == (ni == ret.N)); } foreach (i; Iota!(ret.N, ret.PureN)) { ret._lengths[i] = slice._lengths[i + slcie.N - ret.N]; ret._strides[i] = slice._strides[i + slcie.N - ret.N]; } ret._ptr = slice._ptr; return ret; } /// @safe pure unittest { import std.experimental.ndslice.slice; import std.range: iota; import std.experimental.ndslice.iteration: allReversed; auto slice = 12.iota .sliced(3, 4) .allReversed .reshape(-1, 3); assert(slice == [[11, 10, 9], [ 8, 7, 6], [ 5, 4, 3], [ 2, 1, 0]]); } /// Reshaping with memory allocation pure unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration: reversed; import std.array: array; auto reshape2(S, L...)(S slice, L lengths) { // Tries to reshape without allocation try return slice.reshape(lengths); catch(ReshapeException e) //allocates the elements and creates a slice //Note: -1 length is not supported by reshape2 return slice.byElement.array.sliced(lengths); } auto slice = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] .sliced(3, 4) .reversed!0; assert(reshape2(slice, 4, 3) == [[ 8, 9, 10], [11, 4, 5], [ 6, 7, 0], [ 1, 2, 3]]); } @safe pure unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration: allReversed; import std.stdio; import std.range: iota; auto slice = 12.iota.sliced(1, 1, 3, 2, 1, 2, 1).allReversed; assert(slice.reshape(1, -1, 1, 1, 3, 1) == [[[[[[11], [10], [9]]]], [[[[ 8], [ 7], [6]]]], [[[[ 5], [ 4], [3]]]], [[[[ 2], [ 1], [0]]]]]]); } /// See_also: $(LREF reshape) class ReshapeException: Exception { /// Old lengths size_t[] lengths; /// Old strides sizediff_t[] strides; /// New lengths size_t[] newLengths; /// this( size_t[] lengths, sizediff_t[] strides, size_t[] newLengths, string msg, string file = __FILE__, uint line = cast(uint)__LINE__, Throwable next = null ) pure nothrow @nogc @safe { super(msg, file, line, next); this.lengths = lengths; this.strides = strides; this.newLengths = newLengths; } } /++ Returns a random access range of all elements of a slice. The order of elements is preserved. `byElement` can be generalized with other selectors. Params: N = dimension count slice = slice to be iterated Returns: random access range composed of elements of the `slice` +/ auto byElement(size_t N, Range)(auto ref Slice!(N, Range) slice) { with (Slice!(N, Range)) { /++ ByElement shifts the range's `_ptr` without modifying its strides and lengths. +/ static struct ByElement { This _slice; size_t _length; size_t[N] _indexes; static if (canSave!PureRange) auto save() @property { return typeof(this)(_slice.save, _length, _indexes); } bool empty() const @property { pragma(inline, true); return _length == 0; } size_t length() const @property { pragma(inline, true); return _length; } auto ref front() @property { assert(!this.empty); static if (N == PureN) { return _slice._ptr[0]; } else with (_slice) { alias M = DeepElemType.PureN; return DeepElemType(_lengths[$ - M .. $], _strides[$ - M .. $], _ptr); } } static if (PureN == 1 && isMutable!DeepElemType && !hasAccessByRef) auto front(E)(E elem) @property { assert(!this.empty); return _slice._ptr[0] = elem; } void popFront() { assert(_length != 0); _length--; popFrontImpl; } private void popFrontImpl() { foreach_reverse(i; Iota!(0, N)) with (_slice) { _ptr += _strides[i]; _indexes[i]++; if (_indexes[i] < _lengths[i]) return; debug (ndslice) assert(_indexes[i] == _lengths[i]); _ptr -= _lengths[i] * _strides[i]; _indexes[i] = 0; } } auto ref back() @property { assert(!this.empty); return opIndex(_length - 1); } static if (PureN == 1 && isMutable!DeepElemType && !hasAccessByRef) auto back(E)(E elem) @property { assert(!this.empty); return opIndexAssign(_length - 1, elem); } void popBack() { pragma(inline, true); assert(_length != 0); _length--; } void popFrontExactly(size_t n) in { assert(n <= _length); } body { _length -= n; //calculates shift and new indexes sizediff_t _shift; n += _indexes[N-1]; foreach_reverse(i; Iota!(1, N)) with (_slice) { immutable v = n / _lengths[i]; n %= _lengths[i]; _shift += (n - _indexes[i]) * _strides[i]; _indexes[i] = n; n = _indexes[i - 1] + v; } assert(n < _slice._lengths[0]); with (_slice) { _shift += (n - _indexes[0]) * _strides[0]; _indexes[0] = n; } _slice._ptr += _shift; } void popBackExactly(size_t n) in { assert(n <= _length); } body { pragma(inline, true); _length -= n; } //calculates shift for index n private sizediff_t getShift(size_t n) in { assert(n < _length); } body { sizediff_t _shift; n += _indexes[N-1]; foreach_reverse(i; Iota!(1, N)) with (_slice) { immutable v = n / _lengths[i]; n %= _lengths[i]; _shift += (n - _indexes[i]) * _strides[i]; n = _indexes[i - 1] + v; } debug (ndslice) assert(n < _slice._lengths[0]); with (_slice) _shift += (n - _indexes[0]) * _strides[0]; return _shift; } auto ref opIndex(size_t index) { static if (N == PureN) { return _slice._ptr[getShift(index)]; } else with (_slice) { alias M = DeepElemType.PureN; return DeepElemType(_lengths[$ - M .. $], _strides[$ - M .. $], _ptr); } } static if (PureN == 1 && isMutable!DeepElemType && !hasAccessByRef) auto opIndexAssign(E)(E elem, size_t index) { static if (N == PureN) { return _slice._ptr[getShift(index)] = elem; } else { static assert(0, "ByElement.opIndexAssign is not implemented for packed slices." ~ "Use additional empty slicing `elemsOfSlice[index][] = value`" ~ tailErrorMessage()); } } static if (isMutable!DeepElemType && N == PureN) { auto opIndexAssign(V)(V val, _Slice slice) { return this[slice][] = val; } auto opIndexAssign(V)(V val) { foreach (ref e; this) e = val; return this; } auto opIndexAssign(V : T[], T)(V val) if (__traits(compiles, front = val[0])) { assert(_length == val.length, "lengths should be equal" ~ tailErrorMessage!()); foreach (ref e; this) { e = val[0]; val = val[1 .. $]; } return this; } auto opIndexAssign(V : Slice!(1, _Range), _Range)(V val) if (__traits(compiles, front = val.front)) { assert(_length == val.length, "lengths should be equal" ~ tailErrorMessage!()); foreach (ref e; this) { e = val.front; val.popFront; } return this; } } auto opIndex(_Slice sl) { auto ret = this; ret.popFrontExactly(sl.i); ret.popBackExactly(_length - sl.j); return ret; } alias opDollar = length; _Slice opSlice(size_t pos : 0)(size_t i, size_t j) in { assert(i <= j, "the left bound must be less than or equal to the right bound" ~ tailErrorMessage!()); assert(j - i <= _length, "the difference between the right and the left bound must be less than or equal to range length" ~ tailErrorMessage!()); } body { pragma(inline, true); return typeof(return)(i, j); } size_t[N] index() @property { pragma(inline, true); return _indexes; } } return ByElement(slice, slice.elementsCount); } } /// Regular slice @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.algorithm.comparison: equal; import std.range: iota; assert(20.iota .sliced(4, 5) .byElement .equal(20.iota)); } /// Packed slice @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration; import std.range: iota, drop; import std.algorithm.comparison: equal; assert((3 * 4 * 5 * 6 * 7).iota .sliced(3, 4, 5, 6, 7) .pack!2 .byElement() .drop(1) .front .byElement .equal(iota(6 * 7, 6 * 7 * 2))); } /// Properties pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; auto elems = 12.iota.sliced(3, 4).byElement; elems.popFrontExactly(2); assert(elems.front == 2); assert(elems.index == [0, 2]); elems.popBackExactly(2); assert(elems.back == 9); assert(elems.length == 8); } /// Index property pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new long[20].sliced(5, 4); for(auto elems = slice.byElement; !elems.empty; elems.popFront) { size_t[2] index = elems.index; elems.front = index[0] * 10 + index[1] * 3; } assert(slice == [[ 0, 3, 6, 9], [10, 13, 16, 19], [20, 23, 26, 29], [30, 33, 36, 39], [40, 43, 46, 49]]); } /++ Random access and slicing +/ @nogc nothrow unittest { import std.experimental.ndslice.slice; import std.algorithm.comparison: equal; import std.array: array; import std.range: iota, repeat; static data = 20.iota.array; auto elems = data.sliced(4, 5).byElement; elems = elems[11 .. $ - 2]; assert(elems.length == 7); assert(elems.front == 11); assert(elems.back == 17); foreach (i; 0 .. 7) assert(elems[i] == i + 11); // assign an element elems[2 .. 6] = -1; assert(elems[2 .. 6].equal(repeat(-1, 4))); // assign an array static ar = [-1, -2, -3, -4]; elems[2 .. 6] = ar; assert(elems[2 .. 6].equal(ar)); // assign a slice ar[] *= 2; auto sl = ar.sliced(ar.length); elems[2 .. 6] = sl; assert(elems[2 .. 6].equal(sl)); } /++ Forward access works faster than random access or backward access. Use $(SUBREF iteration, allReversed) in pipeline before `byElement` to achieve fast backward access. +/ @safe @nogc pure nothrow unittest { import std.range: retro, iota; import std.experimental.ndslice.iteration: allReversed; auto slice = 60.iota.sliced(3, 4, 5); /// Slow backward iteration #1 foreach (ref e; slice.byElement.retro) { //... } /// Slow backward iteration #2 foreach_reverse (ref e; slice.byElement) { //... } /// Fast backward iteration foreach (ref e; slice.allReversed.byElement) { //... } } @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, isRandomAccessRange, hasSlicing; auto elems = 20.iota.sliced(4, 5).byElement; static assert(isRandomAccessRange!(typeof(elems))); static assert(hasSlicing!(typeof(elems))); } // Checks strides @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration; import std.range: iota, isRandomAccessRange; auto elems = 20.iota.sliced(4, 5).everted.byElement; static assert(isRandomAccessRange!(typeof(elems))); elems = elems[11 .. $ - 2]; auto elems2 = elems; foreach (i; 0 .. 7) { assert(elems[i] == elems2.front); elems2.popFront; } } @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration; import std.range: iota, isForwardRange, hasLength; import std.algorithm.comparison: equal; auto range = (3 * 4 * 5 * 6 * 7).iota; auto slice0 = range.sliced(3, 4, 5, 6, 7); auto slice1 = slice0.transposed!(2, 1).pack!2; auto elems0 = slice0.byElement; auto elems1 = slice1.byElement; import std.meta; foreach (S; AliasSeq!(typeof(elems0), typeof(elems1))) { static assert(isForwardRange!S); static assert(hasLength!S); } assert(elems0.length == slice0.elementsCount); assert(elems1.length == 5 * 4 * 3); auto elems2 = elems1; foreach (q; slice1) foreach (w; q) foreach (e; w) { assert(!elems2.empty); assert(e == elems2.front); elems2.popFront; } assert(elems2.empty); elems0.popFront(); elems0.popFrontExactly(slice0.elementsCount - 14); assert(elems0.length == 13); assert(elems0.equal(range[slice0.elementsCount - 13 .. slice0.elementsCount])); foreach (elem; elems0) {} } // Issue 15549 unittest { import std.range: iota; import std.range.primitives; alias A = typeof(10.iota.sliced(2, 5).sliced(1, 1, 1, 1)); static assert(isRandomAccessRange!A); static assert(hasLength!A); static assert(hasSlicing!A); alias B = typeof(new double[10].sliced(2, 5).sliced(1, 1, 1, 1)); static assert(isRandomAccessRange!B); static assert(hasLength!B); static assert(hasSlicing!B); } /++ Returns an forward range of all elements of standard simplex of a slice. In case the slice has two dimensions, it is composed of elements of upper left triangular matrix. The order of elements is preserved. `byElementInStandardSimplex` can be generalized with other selectors. Params: N = dimension count slice = slice to be iterated Returns: forward range composed of all elements of standard simplex of the `slice` +/ auto byElementInStandardSimplex(size_t N, Range)(auto ref Slice!(N, Range) slice, size_t maxCobeLength = size_t.max) { with (Slice!(N, Range)) { /++ ByElementInTopSimplex shifts the range's `_ptr` without modifying its strides and lengths. +/ static struct ByElementInTopSimplex { This _slice; size_t _length; size_t maxCobeLength; size_t sum; size_t[N] _indexes; static if (canSave!PureRange) auto save() @property { return typeof(this)(_slice.save, _length, maxCobeLength, sum, _indexes); } bool empty() const @property { pragma(inline, true); return _length == 0; } size_t length() const @property { pragma(inline, true); return _length; } auto ref front() @property { assert(!this.empty); static if (N == PureN) return _slice._ptr[0]; else with (_slice) { alias M = DeepElemType.PureN; return DeepElemType(_lengths[$ - M .. $], _strides[$ - M .. $], _ptr); } } static if (PureN == 1 && isMutable!DeepElemType && !hasAccessByRef) auto front(E)(E elem) @property { pragma(inline, true); assert(!this.empty); return _slice._ptr[0] = elem; } void popFront() { pragma(inline, true); assert(_length != 0); _length--; popFrontImpl; } private void popFrontImpl() { foreach_reverse(i; Iota!(0, N)) with (_slice) { _ptr += _strides[i]; _indexes[i]++; debug (ndslice) assert(_indexes[i] <= _lengths[i]); sum++; if (sum < maxCobeLength) return; debug (ndslice) assert(sum == maxCobeLength); _ptr -= _indexes[i] * _strides[i]; sum -= _indexes[i]; _indexes[i] = 0; } } size_t[N] index() @property { pragma(inline, true); return _indexes; } } foreach (i; Iota!(0, N)) if (maxCobeLength > slice._lengths[i]) maxCobeLength = slice._lengths[i]; immutable size_t elementsCount = ((maxCobeLength + 1) * maxCobeLength ^^ (N - 1)) / 2; return ByElementInTopSimplex(slice, elementsCount, maxCobeLength); } } /// pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = new int[20].sliced(4, 5); auto elems = slice .byElementInStandardSimplex; int i; foreach (ref e; elems) e = ++i; assert(slice == [[ 1, 2, 3, 4, 0], [ 5, 6, 7, 0, 0], [ 8, 9, 0, 0, 0], [10, 0, 0, 0, 0]]); } /// pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.iteration; auto slice = new int[20].sliced(4, 5); auto elems = slice .transposed .allReversed .byElementInStandardSimplex; int i; foreach (ref e; elems) e = ++i; assert(slice == [[0, 0, 0, 0, 4], [0, 0, 0, 7, 3], [0, 0, 9, 6, 2], [0, 10, 8, 5, 1]]); } /// Properties @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; auto elems = 12.iota.sliced(3, 4).byElementInStandardSimplex; elems.popFront; assert(elems.front == 1); assert(elems.index == cast(size_t[2])[0, 1]); import std.range: popFrontN; elems.popFrontN(3); assert(elems.front == 5); assert(elems.index == cast(size_t[2])[1, 1]); assert(elems.length == 2); } /++ Returns a slice, the elements of which are equal to the initial index value. Params: N = dimension count lengths = list of dimension lengths Returns: `N`-dimensional slice composed of indexes See_also: $(LREF IndexSlice) +/ IndexSlice!(Lengths.length) indexSlice(Lengths...)(Lengths lengths) if (allSatisfy!(isIndex, Lengths)) { return .indexSlice!(Lengths.length)([lengths]); } ///ditto IndexSlice!N indexSlice(size_t N)(auto ref size_t[N] lengths) { import std.experimental.ndslice.slice: sliced; with (typeof(return)) return Range(lengths[1 .. $]).sliced(lengths); } /// @safe @nogc pure nothrow unittest { auto im = indexSlice(7, 9); assert(im[2, 1] == cast(size_t[2])[2, 1]); for (auto elems = im.byElement; !elems.empty; elems.popFront) assert(elems.front == elems.index); //slicing works correctly auto cm = im[1 .. $ - 3, 4 .. $ - 1]; assert(cm[2, 1] == cast(size_t[2])[3, 5]); } /++ Slice composed of indexes. See_also: $(LREF indexSlice) +/ template IndexSlice(size_t N) if (N) { struct IndexMap { private size_t[N-1] _lengths; auto save() @property const { pragma(inline, true); return this; } size_t[N] opIndex(size_t index) const { pragma(inline, true); size_t[N] indexes = void; foreach_reverse(i; Iota!(0, N - 1)) { indexes[i + 1] = index % _lengths[i]; index /= _lengths[i]; } indexes[0] = index; return indexes; } } alias IndexSlice = Slice!(N, IndexMap); } /// @safe @nogc pure nothrow unittest { alias IS4 = IndexSlice!4; static assert(is(IS4 == Slice!(4, Range), Range)); } unittest { auto r = indexSlice(1); } ldc-1.1.0-beta3-src/runtime/phobos/std/experimental/ndslice/iteration.d0000664000175000017500000010030512776215007024166 0ustar kaikai/** $(SCRIPT inhibitQuickIndex = 1;) This is a submodule of $(LINK2 std_experimental_ndslice.html, std.experimental.ndslice). Operators only change strides and lengths of a slice. The range of a slice remains unmodified. All operators return slice of the same type as the type of the argument. $(BOOKTABLE $(H2 Transpose operators), $(TR $(TH Function Name) $(TH Descriprottion)) $(T2 transposed, `100000.iota.sliced(3, 4, 5, 6, 7).transposed!(4, 0, 1).shape` returns `[7, 3, 4, 5, 6]`.) $(T2 swapped, `1000.iota.sliced(3, 4, 5).swapped!(1, 2).shape` returns `[3, 5, 4]`.) $(T2 everted, `1000.iota.sliced(3, 4, 5).everted.shape` returns `[5, 4, 3]`.) ) See also $(SUBREF selection, evertPack). $(BOOKTABLE $(H2 Iteration operators), $(TR $(TH Function Name) $(TH Description)) $(T2 strided, `1000.iota.sliced(13, 40).strided!(0, 1)(2, 5).shape` equals to `[7, 8]`.) $(T2 reversed, `slice.reversed!0` returns the slice with reversed direction of iteration for top level dimension.) $(T2 allReversed, `20.iota.sliced(4, 5).allReversed` equals to `20.iota.retro.sliced(4, 5)`.) ) $(BOOKTABLE $(H2 Other operators), $(TR $(TH Function Name) $(TH Description)) $(T2 rotated, `10.iota.sliced(2, 3).rotated` equals to `[[2, 5], [1, 4], [0, 3]]`.) ) $(H4 Drop operators) $(LREF dropToHypercube) $(LREF drop) $(LREF dropBack) $(LREF dropOne) $(LREF dropBackOne) $(LREF dropExactly) $(LREF dropBackExactly) $(LREF allDrop) $(LREF allDropBack) $(LREF allDropOne) $(LREF allDropBackOne) $(LREF allDropExactly) $(LREF allDropBackExactly) $(GRAMMAR $(GNAME DropOperatorName): $(D dropToHypercube) $(GLINK DropRoot) $(GLINK DropRoot) $(GLINK DropSuffix) $(GLINK DropRoot) $(D Back) $(GLINK DropRoot) $(D Back) $(GLINK DropSuffix) $(GNAME DropRoot): $(D drop) $(D allDrop) $(GNAME DropSuffix): $(D One) $(D Exactly) ) $(H2 Bifacial operators) Some operators are bifacial, i.e. they have two versions: one with template parameters, and another one with function parameters. Versions with template parameters are preferable because they allow compile time checks and can be optimized better. $(BOOKTABLE , $(TR $(TH Function Name) $(TH Variadic) $(TH Template) $(TH Function)) $(T4 swapped, No, `slice.swapped!(2, 3)`, `slice.swapped(2, 3)`) $(T4 rotated, No, `slice.rotated!(2, 3)(-1)`, `slice.rotated(2, 3, -1)`) $(T4 strided, Yes/No, `slice.strided!(1, 2)(20, 40)`, `slice.strided(1, 20).strided(2, 40)`) $(T4 transposed, Yes, `slice.transposed!(1, 4, 3)`, `slice.transposed(1, 4, 3)`) $(T4 reversed, Yes, `slice.reversed!(0, 2)`, `slice.reversed(0, 2)`) ) Bifacial interface of $(LREF drop), $(LREF dropBack) $(LREF dropExactly), and $(LREF dropBackExactly) is identical to that of $(LREF strided). Bifacial interface of $(LREF dropOne) and $(LREF dropBackOne) is identical to that of $(LREF reversed). License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Ilya Yaroshenko Source: $(PHOBOSSRC std/_experimental/_ndslice/_iteration.d) Macros: SUBMODULE = $(LINK2 std_experimental_ndslice_$1.html, std.experimental.ndslice.$1) SUBREF = $(LINK2 std_experimental_ndslice_$1.html#.$2, $(TT $2))$(NBSP) T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) T4=$(TR $(TDNW $(LREF $1)) $(TD $2) $(TD $3) $(TD $4)) */ module std.experimental.ndslice.iteration; import std.traits; import std.experimental.ndslice.internal; import std.experimental.ndslice.slice; //: Slice; private enum _swappedCode = q{ with (slice) { auto tl = _lengths[dimensionA]; auto ts = _strides[dimensionA]; _lengths[dimensionA] = _lengths[dimensionB]; _strides[dimensionA] = _strides[dimensionB]; _lengths[dimensionB] = tl; _strides[dimensionB] = ts; } return slice; }; /++ Swaps two dimensions. Params: slice = input slice dimensionA = first dimension dimensionB = second dimension Returns: n-dimensional slice of the same type See_also: $(LREF everted), $(LREF transposed) +/ template swapped(size_t dimensionA, size_t dimensionB) { auto swapped(size_t N, Range)(Slice!(N, Range) slice) { { enum i = 0; alias dimension = dimensionA; mixin DimensionCTError; } { enum i = 1; alias dimension = dimensionB; mixin DimensionCTError; } mixin (_swappedCode); } } /// ditto Slice!(N, Range) swapped(size_t N, Range)(Slice!(N, Range) slice, size_t dimensionA, size_t dimensionB) in{ { alias dimension = dimensionA; mixin (DimensionRTError); } { alias dimension = dimensionB; mixin (DimensionRTError); } } body { mixin (_swappedCode); } /// ditto Slice!(2, Range) swapped(Range)(Slice!(2, Range) slice) body { return slice.swapped!(0, 1); } /// Template @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; assert((3 * 4 * 5 * 6).iota .sliced(3, 4, 5, 6) .swapped!(3, 1) .shape == cast(size_t[4])[3, 6, 5, 4]); } /// Function @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; assert((3 * 4 * 5 * 6).iota .sliced(3, 4, 5, 6) .swapped(1, 3) .shape == cast(size_t[4])[3, 6, 5, 4]); } /// 2D @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; assert(12.iota .sliced(3, 4) .swapped .shape == cast(size_t[2])[4, 3]); } private enum _rotatedCode = q{ k &= 0b11; if (k == 0) return slice; if (k == 2) return slice.allReversed; static if (__traits(compiles, { enum _enum = dimensionA + dimensionB; })) { slice = slice.swapped!(dimensionA, dimensionB); if (k == 1) return slice.reversed!dimensionA; else return slice.reversed!dimensionB; } else { slice = slice.swapped (dimensionA, dimensionB); if (k == 1) return slice.reversed(dimensionA); else return slice.reversed(dimensionB); } }; /++ Rotates two selected dimensions by `k*90` degrees. The order of dimensions is important. If the slice has two dimensions, the default direction is counterclockwise. Params: slice = input slice dimensionA = first dimension dimensionB = second dimension k = rotation counter, can be negative Returns: n-dimensional slice of the same type +/ template rotated(size_t dimensionA, size_t dimensionB) { auto rotated(size_t N, Range)(Slice!(N, Range) slice, sizediff_t k = 1) { { enum i = 0; alias dimension = dimensionA; mixin DimensionCTError; } { enum i = 1; alias dimension = dimensionB; mixin DimensionCTError; } mixin (_rotatedCode); } } /// ditto Slice!(N, Range) rotated(size_t N, Range)(Slice!(N, Range) slice, size_t dimensionA, size_t dimensionB, sizediff_t k = 1) in{ { alias dimension = dimensionA; mixin (DimensionRTError); } { alias dimension = dimensionB; mixin (DimensionRTError); } } body { mixin (_rotatedCode); } /// ditto Slice!(2, Range) rotated(Range)(Slice!(2, Range) slice, sizediff_t k = 1) body { return slice.rotated!(0, 1)(k); } /// Template @safe pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; auto slice = 6.iota.sliced(2, 3); auto a = [[0, 1, 2], [3, 4, 5]]; auto b = [[2, 5], [1, 4], [0, 3]]; auto c = [[5, 4, 3], [2, 1, 0]]; auto d = [[3, 0], [4, 1], [5, 2]]; assert(slice.rotated ( 4) == a); assert(slice.rotated!(0, 1)(-4) == a); assert(slice.rotated (1, 0, 8) == a); assert(slice.rotated == b); assert(slice.rotated!(0, 1)(-3) == b); assert(slice.rotated (1, 0, 3) == b); assert(slice.rotated ( 6) == c); assert(slice.rotated!(0, 1)( 2) == c); assert(slice.rotated (0, 1, -2) == c); assert(slice.rotated ( 7) == d); assert(slice.rotated!(0, 1)( 3) == d); assert(slice.rotated (1, 0, ) == d); } /++ Reverses the order of dimensions. Params: slice = input slice Returns: n-dimensional slice of the same type See_also: $(LREF swapped), $(LREF transposed) +/ Slice!(N, Range) everted(size_t N, Range)(auto ref Slice!(N, Range) slice) { mixin _DefineRet; with (slice) { foreach (i; Iota!(0, N)) { ret._lengths[N - 1 - i] = _lengths[i]; ret._strides[N - 1 - i] = _strides[i]; } foreach (i; Iota!(N, PureN)) { ret._lengths[i] = _lengths[i]; ret._strides[i] = _strides[i]; } ret._ptr = _ptr; return ret; } } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; assert(60.iota .sliced(3, 4, 5) .everted .shape == cast(size_t[3])[5, 4, 3]); } private enum _transposedCode = q{ mixin _DefineRet; with (slice) { foreach (i; Iota!(0, N)) { ret._lengths[i] = _lengths[perm[i]]; ret._strides[i] = _strides[perm[i]]; } foreach (i; Iota!(N, PureN)) { ret._lengths[i] = _lengths[i]; ret._strides[i] = _strides[i]; } ret._ptr = _ptr; return ret; } }; private size_t[N] completeTranspose(size_t N)(in size_t[] dimensions) { assert(dimensions.length <= N); size_t[N] ctr; uint[N] mask; foreach (i, ref dimension; dimensions) { mask[dimension] = true; ctr[i] = dimension; } size_t j = dimensions.length; foreach (i, e; mask) if (e == false) ctr[j++] = i; return ctr; } /++ N-dimensional transpose operator. Brings selected dimensions to the first position. Params: slice = input slice Dimensions = indexes of dimensions to be brought to the first position dimensions = indexes of dimensions to be brought to the first position dimension = index of dimension to be brought to the first position Returns: n-dimensional slice of the same type See_also: $(LREF swapped), $(LREF everted) +/ template transposed(Dimensions...) if (Dimensions.length) { Slice!(N, Range) transposed(size_t N, Range)(auto ref Slice!(N, Range) slice) { mixin DimensionsCountCTError; foreach (i, dimension; Dimensions) mixin DimensionCTError; static assert(isValidPartialPermutation!N([Dimensions]), "Failed to complete permutation of dimensions " ~ Dimensions.stringof ~ tailErrorMessage!()); enum perm = completeTranspose!N([Dimensions]); static assert(perm.isPermutation, __PRETTY_FUNCTION__ ~ ": internal error."); mixin (_transposedCode); } } ///ditto Slice!(N, Range) transposed(size_t N, Range)(auto ref Slice!(N, Range) slice, size_t dimension) in { mixin (DimensionRTError); } body { size_t[1] permutation = void; permutation[0] = dimension; immutable perm = completeTranspose!N(permutation); assert(perm.isPermutation, __PRETTY_FUNCTION__ ~ ": internal error."); mixin (_transposedCode); } ///ditto Slice!(N, Range) transposed(size_t N, Range)(auto ref Slice!(N, Range) slice, in size_t[] dimensions...) in { mixin (DimensionsCountRTError); foreach (dimension; dimensions) mixin (DimensionRTError); } body { assert(dimensions.isValidPartialPermutation!N, "Failed to complete permutation of dimensions." ~ tailErrorMessage!()); immutable perm = completeTranspose!N(dimensions); assert(perm.isPermutation, __PRETTY_FUNCTION__ ~ ": internal error."); mixin (_transposedCode); } ///ditto Slice!(2, Range) transposed(Range)(auto ref Slice!(2, Range) slice) { return .transposed!(1, 0)(slice); } /// Template @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; assert((3 * 4 * 5 * 6 * 7).iota .sliced(3, 4, 5, 6, 7) .transposed!(4, 1, 0) .shape == cast(size_t[5])[7, 4, 3, 5, 6]); } /// Function @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; assert((3 * 4 * 5 * 6 * 7).iota .sliced(3, 4, 5, 6, 7) .transposed(4, 1, 0) .shape == cast(size_t[5])[7, 4, 3, 5, 6]); } /// Single-argument function @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; assert((3 * 4 * 5 * 6 * 7).iota .sliced(3, 4, 5, 6, 7) .transposed(4) .shape == cast(size_t[5])[7, 3, 4, 5, 6]); } /// `2`-dimensional transpose @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota; assert(12.iota .sliced(3, 4) .transposed .shape == cast(size_t[2])[4, 3]); } private enum _reversedCode = q{ with (slice) { if (_lengths[dimension]) _ptr += _strides[dimension] * (_lengths[dimension] - 1); _strides[dimension] = -_strides[dimension]; } }; /++ Reverses the direction of iteration for all dimensions. Params: slice = input slice Returns: n-dimensional slice of the same type +/ Slice!(N, Range) allReversed(size_t N, Range)(Slice!(N, Range) slice) { foreach (dimension; Iota!(0, N)) { mixin (_reversedCode); } return slice; } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, retro; auto a = 20.iota.sliced(4, 5).allReversed; auto b = 20.iota.retro.sliced(4, 5); assert(a == b); } /++ Reverses the direction of iteration for selected dimensions. Params: slice = input slice Dimensions = indexes of dimensions to reverse order of iteration dimensions = indexes of dimensions to reverse order of iteration dimension = index of dimension to reverse order of iteration Returns: n-dimensional slice of the same type +/ template reversed(Dimensions...) if (Dimensions.length) { auto reversed(size_t N, Range)(Slice!(N, Range) slice) { foreach (i, dimension; Dimensions) { mixin DimensionCTError; mixin (_reversedCode); } return slice; } } ///ditto Slice!(N, Range) reversed(size_t N, Range)(Slice!(N, Range) slice, size_t dimension) in { mixin (DimensionRTError); } body { mixin (_reversedCode); return slice; } ///ditto Slice!(N, Range) reversed(size_t N, Range)(Slice!(N, Range) slice, in size_t[] dimensions...) in { foreach (dimension; dimensions) mixin (DimensionRTError); } body { foreach (dimension; dimensions) mixin (_reversedCode); return slice; } /// pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = [1, 2, 3, 4].sliced(2, 2); assert(slice == [[1, 2], [3, 4]]); // Template assert(slice.reversed! 0 == [[3, 4], [1, 2]]); assert(slice.reversed! 1 == [[2, 1], [4, 3]]); assert(slice.reversed!(0, 1) == [[4, 3], [2, 1]]); assert(slice.reversed!(1, 0) == [[4, 3], [2, 1]]); assert(slice.reversed!(1, 1) == [[1, 2], [3, 4]]); assert(slice.reversed!(0, 0, 0) == [[3, 4], [1, 2]]); // Function assert(slice.reversed (0) == [[3, 4], [1, 2]]); assert(slice.reversed (1) == [[2, 1], [4, 3]]); assert(slice.reversed (0, 1) == [[4, 3], [2, 1]]); assert(slice.reversed (1, 0) == [[4, 3], [2, 1]]); assert(slice.reversed (1, 1) == [[1, 2], [3, 4]]); assert(slice.reversed (0, 0, 0) == [[3, 4], [1, 2]]); } @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.selection; import std.algorithm.comparison: equal; import std.range: iota, retro, chain; auto i0 = iota(0, 4); auto r0 = i0.retro; auto i1 = iota(4, 8); auto r1 = i1.retro; auto i2 = iota(8, 12); auto r2 = i2.retro; auto slice = 12.iota.sliced(3, 4); assert(slice .byElement.equal(chain(i0, i1, i2))); // Template assert(slice.reversed!(0) .byElement.equal(chain(i2, i1, i0))); assert(slice.reversed!(1) .byElement.equal(chain(r0, r1, r2))); assert(slice.reversed!(0, 1) .byElement.equal(chain(r2, r1, r0))); assert(slice.reversed!(1, 0) .byElement.equal(chain(r2, r1, r0))); assert(slice.reversed!(1, 1) .byElement.equal(chain(i0, i1, i2))); assert(slice.reversed!(0, 0, 0).byElement.equal(chain(i2, i1, i0))); // Function assert(slice.reversed (0) .byElement.equal(chain(i2, i1, i0))); assert(slice.reversed (1) .byElement.equal(chain(r0, r1, r2))); assert(slice.reversed (0, 1) .byElement.equal(chain(r2, r1, r0))); assert(slice.reversed (1, 0) .byElement.equal(chain(r2, r1, r0))); assert(slice.reversed (1, 1) .byElement.equal(chain(i0, i1, i2))); assert(slice.reversed (0, 0, 0).byElement.equal(chain(i2, i1, i0))); } private enum _stridedCode = q{ assert(factor > 0, "factor must be positive" ~ tailErrorMessage!()); immutable rem = slice._lengths[dimension] % factor; slice._lengths[dimension] /= factor; if (slice._lengths[dimension]) //do not remove `if (...)` slice._strides[dimension] *= factor; if (rem) slice._lengths[dimension]++; }; /++ Multiplies the stride of the selected dimension by the factor. Params: slice = input slice Dimensions = indexes of dimensions to be strided dimensions = indexes of dimensions to be strided factors = list of step extension factors factor = step extension factors Returns: n-dimensional slice of the same type +/ template strided(Dimensions...) if (Dimensions.length) { auto strided(size_t N, Range)(Slice!(N, Range) slice, Repeat!(size_t, Dimensions.length) factors) body { foreach (i, dimension; Dimensions) { mixin DimensionCTError; immutable factor = factors[i]; mixin (_stridedCode); } return slice; } } ///ditto Slice!(N, Range) strided(size_t N, Range)(Slice!(N, Range) slice, size_t dimension, size_t factor) in { mixin (DimensionRTError); } body { mixin (_stridedCode); return slice; } /// pure nothrow unittest { import std.experimental.ndslice.slice; auto slice = [0,1,2,3, 4,5,6,7, 8,9,10,11].sliced(3, 4); assert(slice == [[0,1,2,3], [4,5,6,7], [8,9,10,11]]); // Template assert(slice.strided!0(2) == [[0,1,2,3], [8,9,10,11]]); assert(slice.strided!1(3) == [[0, 3], [4, 7], [8, 11]]); assert(slice.strided!(0, 1)(2, 3) == [[0, 3], [8, 11]]); // Function assert(slice.strided(0, 2) == [[0,1,2,3], [8,9,10,11]]); assert(slice.strided(1, 3) == [[0, 3], [4, 7], [8, 11]]); assert(slice.strided(0, 2).strided(1, 3) == [[0, 3], [8, 11]]); } /// @safe @nogc pure nothrow unittest { import std.range: iota; static assert(iota(13 * 40).sliced(13, 40).strided!(0, 1)(2, 5).shape == [7, 8]); static assert(93.iota.sliced(93).strided!(0, 0)(7, 3).shape == [5]); } @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.experimental.ndslice.selection; import std.algorithm.comparison: equal; import std.range: iota, stride, chain; auto i0 = iota(0, 4); auto s0 = i0.stride(3); auto i1 = iota(4, 8); auto s1 = i1.stride(3); auto i2 = iota(8, 12); auto s2 = i2.stride(3); auto slice = 12.iota.sliced(3, 4); assert(slice .byElement.equal(chain(i0, i1, i2))); // Template assert(slice.strided!0(2) .byElement.equal(chain(i0, i2))); assert(slice.strided!1(3) .byElement.equal(chain(s0, s1, s2))); assert(slice.strided!(0, 1)(2, 3).byElement.equal(chain(s0, s2))); // Function assert(slice.strided(0, 2).byElement.equal(chain(i0, i2))); assert(slice.strided(1, 3).byElement.equal(chain(s0, s1, s2))); assert(slice.strided(0, 2).strided(1, 3).byElement.equal(chain(s0, s2))); } /++ Convenience function which calls `slice.popFront!dimension()` for each dimension and returns the slice. `allDropBackOne` provides the same functionality but calls `slice.popBack!dimension()` instead. Params: slice = input slice Returns: n-dimensional slice of the same type +/ Slice!(N, Range) allDropOne(size_t N, Range)(Slice!(N, Range) slice) { foreach (dimension; Iota!(0, N)) slice.popFront!dimension; return slice; } ///ditto Slice!(N, Range) allDropBackOne(size_t N, Range)(Slice!(N, Range) slice) { foreach (dimension; Iota!(0, N)) slice.popBack!dimension; return slice; } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, retro; auto a = 20.iota.sliced(4, 5); assert(a.allDropOne[0, 0] == 6); assert(a.allDropOne.shape == cast(size_t[2])[3, 4]); assert(a.allDropBackOne[$ - 1, $ - 1] == 13); assert(a.allDropBackOne.shape == cast(size_t[2])[3, 4]); } /++ These functions are similar to `allDrop` and `allDropBack` but they call `slice.popFrontExactly!dimension(n)` and `slice.popBackExactly!dimension(n)` instead. Note: Unlike `allDrop`, `allDropExactly(n)` assume that the slice holds a multi-dimensional cube with a size of at least n. This makes `allDropExactly` faster than `allDrop`. Only use `allDropExactly` when it is guaranteed that the slice holds a multi-dimensional cube with a size of at least n. Params: slice = input slice n = number of elements to drop Returns: n-dimensional slice of the same type +/ Slice!(N, Range) allDropExactly(size_t N, Range)(Slice!(N, Range) slice, size_t n) { foreach (dimension; Iota!(0, N)) slice.popFrontExactly!dimension(n); return slice; } ///ditto Slice!(N, Range) allDropBackExactly(size_t N, Range)(Slice!(N, Range) slice, size_t n) { foreach (dimension; Iota!(0, N)) slice.popBackExactly!dimension(n); return slice; } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, retro; auto a = 20.iota.sliced(4, 5); assert(a.allDropExactly(2)[0, 0] == 12); assert(a.allDropExactly(2).shape == cast(size_t[2])[2, 3]); assert(a.allDropBackExactly(2)[$ - 1, $ - 1] == 7); assert(a.allDropBackExactly(2).shape == cast(size_t[2])[2, 3]); } /++ Convenience function which calls `slice.popFrontN!dimension(n)` for each dimension and returns the slice. `allDropBack` provides the same functionality but calls `slice.popBackN!dimension(n)` instead. Note: `allDrop` and `allDropBack` remove up to n elements and stop when the slice is empty. Params: slice = input slice n = number of elements to drop Returns: n-dimensional slice of the same type +/ Slice!(N, Range) allDrop(size_t N, Range)(Slice!(N, Range) slice, size_t n) { foreach (dimension; Iota!(0, N)) slice.popFrontN!dimension(n); return slice; } ///ditto Slice!(N, Range) allDropBack(size_t N, Range)(Slice!(N, Range) slice, size_t n) { foreach (dimension; Iota!(0, N)) slice.popBackN!dimension(n); return slice; } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, retro; auto a = 20.iota.sliced(4, 5); assert(a.allDrop(2)[0, 0] == 12); assert(a.allDrop(2).shape == cast(size_t[2])[2, 3]); assert(a.allDropBack(2)[$ - 1, $ - 1] == 7); assert(a.allDropBack(2).shape == cast(size_t[2])[2, 3]); assert(a.allDrop (5).shape == cast(size_t[2])[0, 0]); assert(a.allDropBack(5).shape == cast(size_t[2])[0, 0]); } /++ Convenience function which calls `slice.popFront!dimension()` for selected dimensions and returns the slice. `dropBackOne` provides the same functionality but calls `slice.popBack!dimension()` instead. Params: slice = input slice Returns: n-dimensional slice of the same type +/ template dropOne(Dimensions...) if (Dimensions.length) { Slice!(N, Range) dropOne(size_t N, Range)(Slice!(N, Range) slice) { foreach (i, dimension; Dimensions) { mixin DimensionCTError; slice.popFront!dimension; } return slice; } } ///ditto Slice!(N, Range) dropOne(size_t N, Range)(Slice!(N, Range) slice, size_t dimension) in { mixin (DimensionRTError); } body { slice.popFront(dimension); return slice; } ///ditto Slice!(N, Range) dropOne(size_t N, Range)(Slice!(N, Range) slice, in size_t[] dimensions...) in { foreach (dimension; dimensions) mixin (DimensionRTError); } body { foreach (dimension; dimensions) slice.popFront(dimension); return slice; } ///ditto template dropBackOne(Dimensions...) if (Dimensions.length) { Slice!(N, Range) dropBackOne(size_t N, Range)(Slice!(N, Range) slice) { foreach (i, dimension; Dimensions) { mixin DimensionCTError; slice.popBack!dimension; } return slice; } } ///ditto Slice!(N, Range) dropBackOne(size_t N, Range)(Slice!(N, Range) slice, size_t dimension) in { mixin (DimensionRTError); } body { slice.popBack(dimension); return slice; } ///ditto Slice!(N, Range) dropBackOne(size_t N, Range)(Slice!(N, Range) slice, in size_t[] dimensions...) in { foreach (dimension; dimensions) mixin (DimensionRTError); } body { foreach (dimension; dimensions) slice.popBack(dimension); return slice; } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, retro; auto a = 20.iota.sliced(4, 5); assert(a.dropOne!(1, 0)[0, 0] == 6); assert(a.dropOne (1, 0)[0, 0] == 6); assert(a.dropOne!(1, 0).shape == cast(size_t[2])[3, 4]); assert(a.dropOne (1, 0).shape == cast(size_t[2])[3, 4]); assert(a.dropBackOne!(1, 0)[$ - 1, $ - 1] == 13); assert(a.dropBackOne (1, 0)[$ - 1, $ - 1] == 13); assert(a.dropBackOne!(1, 0).shape == cast(size_t[2])[3, 4]); assert(a.dropBackOne (1, 0).shape == cast(size_t[2])[3, 4]); assert(a.dropOne!(0, 0)[0, 0] == 10); assert(a.dropOne (0, 0)[0, 0] == 10); assert(a.dropOne!(0, 0).shape == cast(size_t[2])[2, 5]); assert(a.dropOne (0, 0).shape == cast(size_t[2])[2, 5]); assert(a.dropBackOne!(1, 1)[$ - 1, $ - 1] == 17); assert(a.dropBackOne (1, 1)[$ - 1, $ - 1] == 17); assert(a.dropBackOne!(1, 1).shape == cast(size_t[2])[4, 3]); assert(a.dropBackOne (1, 1).shape == cast(size_t[2])[4, 3]); } @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, retro; auto a = 20.iota.sliced(4, 5); assert(a.dropOne(0).dropOne(0)[0, 0] == 10); assert(a.dropOne(0).dropOne(0).shape == cast(size_t[2])[2, 5]); assert(a.dropBackOne(1).dropBackOne(1)[$ - 1, $ - 1] == 17); assert(a.dropBackOne(1).dropBackOne(1).shape == cast(size_t[2])[4, 3]); } /++ These functions are similar to `drop` and `dropBack` but they call `slice.popFrontExactly!dimension(n)` and `slice.popBackExactly!dimension(n)` instead. Note: Unlike `drop`, `dropExactly` assumes that the slice holds enough elements in the selected dimension. This makes `dropExactly` faster than `drop`. Params: slice = input slice ns = list of numbers of elements to drop n = number of elements to drop Returns: n-dimensional slice of the same type +/ template dropExactly(Dimensions...) if (Dimensions.length) { Slice!(N, Range) dropExactly(size_t N, Range)(Slice!(N, Range) slice, Repeat!(size_t, Dimensions.length) ns) body { foreach (i, dimension; Dimensions) { mixin DimensionCTError; slice.popFrontExactly!dimension(ns[i]); } return slice; } } ///ditto Slice!(N, Range) dropExactly(size_t N, Range)(Slice!(N, Range) slice, size_t dimension, size_t n) in { mixin (DimensionRTError); } body { slice.popFrontExactly(dimension, n); return slice; } ///ditto template dropBackExactly(Dimensions...) if (Dimensions.length) { Slice!(N, Range) dropBackExactly(size_t N, Range)(Slice!(N, Range) slice, Repeat!(size_t, Dimensions.length) ns) body { foreach (i, dimension; Dimensions) { mixin DimensionCTError; slice.popBackExactly!dimension(ns[i]); } return slice; } } ///ditto Slice!(N, Range) dropBackExactly(size_t N, Range)(Slice!(N, Range) slice, size_t dimension, size_t n) in { mixin (DimensionRTError); } body { slice.popBackExactly(dimension, n); return slice; } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, retro; auto a = 20.iota.sliced(4, 5); assert(a.dropExactly !(1, 0)(2, 3)[0, 0] == 17); assert(a.dropExactly !(1, 0)(2, 3).shape == cast(size_t[2])[1, 3]); assert(a.dropBackExactly!(0, 1)(2, 3)[$ - 1, $ - 1] == 6); assert(a.dropBackExactly!(0, 1)(2, 3).shape == cast(size_t[2])[2, 2]); assert(a.dropExactly(1, 2).dropExactly(0, 3)[0, 0] == 17); assert(a.dropExactly(1, 2).dropExactly(0, 3).shape == cast(size_t[2])[1, 3]); assert(a.dropBackExactly(0, 2).dropBackExactly(1, 3)[$ - 1, $ - 1] == 6); assert(a.dropBackExactly(0, 2).dropBackExactly(1, 3).shape == cast(size_t[2])[2, 2]); } /++ Convenience function which calls `slice.popFrontN!dimension(n)` for the selected dimension and returns the slice. `dropBack` provides the same functionality but calls `slice.popBackN!dimension(n)` instead. Note: `drop` and `dropBack` remove up to n elements and stop when the slice is empty. Params: slice = input slice ns = list of numbers of elements to drop n = number of elements to drop Returns: n-dimensional slice of the same type +/ template drop(Dimensions...) if (Dimensions.length) { Slice!(N, Range) drop(size_t N, Range)(Slice!(N, Range) slice, Repeat!(size_t, Dimensions.length) ns) body { foreach (i, dimension; Dimensions) { mixin DimensionCTError; slice.popFrontN!dimension(ns[i]); } return slice; } } ///ditto Slice!(N, Range) drop(size_t N, Range)(Slice!(N, Range) slice, size_t dimension, size_t n) in { mixin (DimensionRTError); } body { slice.popFrontN(dimension, n); return slice; } ///ditto template dropBack(Dimensions...) if (Dimensions.length) { Slice!(N, Range) dropBack(size_t N, Range)(Slice!(N, Range) slice, Repeat!(size_t, Dimensions.length) ns) body { foreach (i, dimension; Dimensions) { mixin DimensionCTError; slice.popBackN!dimension(ns[i]); } return slice; } } ///ditto Slice!(N, Range) dropBack(size_t N, Range)(Slice!(N, Range) slice, size_t dimension, size_t n) in { mixin (DimensionRTError); } body { slice.popBackN(dimension, n); return slice; } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, retro; auto a = 20.iota.sliced(4, 5); assert(a.drop !(1, 0)(2, 3)[0, 0] == 17); assert(a.drop !(1, 0)(2, 3).shape == cast(size_t[2])[1, 3]); assert(a.dropBack!(0, 1)(2, 3)[$ - 1, $ - 1] == 6); assert(a.dropBack!(0, 1)(2, 3).shape == cast(size_t[2])[2, 2]); assert(a.dropBack!(0, 1)(5, 5).shape == cast(size_t[2])[0, 0]); assert(a.drop(1, 2).drop(0, 3)[0, 0] == 17); assert(a.drop(1, 2).drop(0, 3).shape == cast(size_t[2])[1, 3]); assert(a.dropBack(0, 2).dropBack(1, 3)[$ - 1, $ - 1] == 6); assert(a.dropBack(0, 2).dropBack(1, 3).shape == cast(size_t[2])[2, 2]); assert(a.dropBack(0, 5).dropBack(1, 5).shape == cast(size_t[2])[0, 0]); } /++ Returns maximal multidimensional cube. Params: slice = input slice Returns: n-dimensional slice of the same type +/ Slice!(N, Range) dropToHypercube(size_t N, Range)(Slice!(N, Range) slice) body { size_t length = slice._lengths[0]; foreach (i; Iota!(1, N)) if (length > slice._lengths[i]) length = slice._lengths[i]; foreach (i; Iota!(0, N)) slice._lengths[i] = length; return slice; } /// @safe @nogc pure nothrow unittest { import std.experimental.ndslice.slice; import std.range: iota, retro; assert((5 * 3 * 6 * 7).iota .sliced(5, 3, 6, 7) .dropToHypercube .shape == cast(size_t[4])[3, 3, 3, 3]); } ldc-1.1.0-beta3-src/runtime/phobos/std/windows/0000775000175000017500000000000012776215007017400 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/windows/iunknown.d0000664000175000017500000000050712776215007021417 0ustar kaikai// Written in the D programming language. // @@@DEPRECATED_2017-06@@@ /++ $(RED Deprecated. Use $(D core.sys.windows.com) instead. This module will be removed in June 2017.) +/ deprecated("Import core.sys.windows.com instead") module std.windows.iunknown; // Replaced by: public import core.sys.windows.com; ldc-1.1.0-beta3-src/runtime/phobos/std/windows/syserror.d0000664000175000017500000001255712776215007021447 0ustar kaikai// Written in the D programming language. /** * Convert Win32 error code to string. * * Copyright: Copyright Digital Mars 2006 - 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * Credits: Based on code written by Regan Heath */ /* Copyright Digital Mars 2006 - 2013. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.windows.syserror; import std.traits : isSomeString; version (StdDdoc) { private { alias DWORD = uint; enum LANG_NEUTRAL = 0, SUBLANG_DEFAULT = 1; } /** Query the text for a Windows error code, as returned by $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360.aspx, $(D GetLastError)), as a D string. */ string sysErrorString( DWORD errCode, // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) is the user's default language int langId = LANG_NEUTRAL, int subLangId = SUBLANG_DEFAULT) @trusted; /********************* Thrown if errors that set $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360.aspx, $(D GetLastError)) occur. */ class WindowsException : Exception { private alias DWORD = int; final @property DWORD code(); /// $(D GetLastError)'s return value. this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted; } /++ If $(D !!value) is true, $(D value) is returned. Otherwise, $(D new WindowsException(GetLastError(), msg)) is thrown. $(D WindowsException) assumes that the last operation set $(D GetLastError()) appropriately. Example: -------------------- wenforce(DeleteFileA("junk.tmp"), "DeleteFile failed"); -------------------- +/ T wenforce(T, S)(T value, lazy S msg = null, string file = __FILE__, size_t line = __LINE__) @safe if (isSomeString!S); } else: version (Windows): import std.windows.charset; import std.array : appender; import std.conv : to; import std.format : formattedWrite; import core.sys.windows.windows; string sysErrorString( DWORD errCode, // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) is the user's default language int langId = LANG_NEUTRAL, int subLangId = SUBLANG_DEFAULT) @trusted { auto buf = appender!string(); if (!putSysError(errCode, buf, MAKELANGID(langId, subLangId))) { throw new Exception( "failed getting error string for WinAPI error code: " ~ sysErrorString(GetLastError())); } return buf.data; } bool putSysError(Writer)(DWORD code, Writer w, /*WORD*/int langId = 0) { wchar *lpMsgBuf = null; auto res = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, null, code, langId, cast(LPWSTR)&lpMsgBuf, 0, null); scope(exit) if (lpMsgBuf) LocalFree(lpMsgBuf); if (lpMsgBuf) { import std.string : strip; w.put(lpMsgBuf[0..res].strip()); return true; } else return false; } class WindowsException : Exception { import core.sys.windows.windows; final @property DWORD code() { return _code; } /// $(D GetLastError)'s return value. private DWORD _code; this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted { _code = code; auto buf = appender!string(); if (str != null) { buf.put(str); if (code) buf.put(": "); } if (code) { auto success = putSysError(code, buf); formattedWrite(buf, success ? " (error %d)" : "Error %d", code); } super(buf.data, file, line); } } T wenforce(T, S)(T value, lazy S msg = null, string file = __FILE__, size_t line = __LINE__) if (isSomeString!S) { if (!value) throw new WindowsException(GetLastError(), to!string(msg), file, line); return value; } T wenforce(T)(T condition, const(char)[] name, const(wchar)* namez, string file = __FILE__, size_t line = __LINE__) { if (condition) return condition; string names; if (!name) { static string trustedToString(const(wchar)* stringz) @trusted { import std.conv : to; import core.stdc.wchar_ : wcslen; auto len = wcslen(stringz); return to!string(stringz[0 .. len]); } names = trustedToString(namez); } else names = to!string(name); throw new WindowsException(GetLastError(), names, file, line); } version(Windows) unittest { import std.exception; import std.string; import std.algorithm : startsWith, endsWith; auto e = collectException!WindowsException( DeleteFileA("unexisting.txt").wenforce("DeleteFile") ); assert(e.code == ERROR_FILE_NOT_FOUND); assert(e.msg.startsWith("DeleteFile: ")); // can't test the entire message, as it depends on Windows locale assert(e.msg.endsWith(" (error 2)")); // Test code zero e = new WindowsException(0); assert(e.msg == ""); e = new WindowsException(0, "Test"); assert(e.msg == "Test"); } ldc-1.1.0-beta3-src/runtime/phobos/std/windows/charset.d0000664000175000017500000000661012776215007021201 0ustar kaikai// Written in the D programming language. /** * Support UTF-8 on Windows 95, 98 and ME systems. * * Macros: * WIKI = Phobos/StdWindowsCharset * * Copyright: Copyright Digital Mars 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) */ /* Copyright Digital Mars 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.windows.charset; version (StdDdoc) { /****************************************** * Converts the UTF-8 string s into a null-terminated string in a Windows * 8-bit character set. * * Params: * s = UTF-8 string to convert. * codePage = is the number of the target codepage, or * 0 - ANSI, * 1 - OEM, * 2 - Mac * * Authors: * yaneurao, Walter Bright, Stewart Gordon */ const(char)* toMBSz(in char[] s, uint codePage = 0); /********************************************** * Converts the null-terminated string s from a Windows 8-bit character set * into a UTF-8 char array. * * Params: * s = UTF-8 string to convert. * codePage = is the number of the source codepage, or * 0 - ANSI, * 1 - OEM, * 2 - Mac * Authors: Stewart Gordon, Walter Bright */ string fromMBSz(immutable(char)* s, int codePage = 0); } else: version (Windows): private import std.conv; private import core.sys.windows.windows; private import std.windows.syserror; private import std.utf; private import std.string; import std.internal.cstring; const(char)* toMBSz(in char[] s, uint codePage = 0) { // Only need to do this if any chars have the high bit set foreach (char c; s) { if (c >= 0x80) { char[] result; int readLen; auto wsTmp = s.tempCStringW(); result.length = WideCharToMultiByte(codePage, 0, wsTmp, -1, null, 0, null, null); if (result.length) { readLen = WideCharToMultiByte(codePage, 0, wsTmp, -1, result.ptr, to!int(result.length), null, null); } if (!readLen || readLen != result.length) { throw new Exception("Couldn't convert string: " ~ sysErrorString(GetLastError())); } return result.ptr; } } return std.string.toStringz(s); } string fromMBSz(immutable(char)* s, int codePage = 0) { const(char)* c; for (c = s; *c != 0; c++) { if (*c >= 0x80) { wchar[] result; int readLen; result.length = MultiByteToWideChar(codePage, 0, s, -1, null, 0); if (result.length) { readLen = MultiByteToWideChar(codePage, 0, s, -1, result.ptr, to!int(result.length)); } if (!readLen || readLen != result.length) { throw new Exception("Couldn't convert string: " ~ sysErrorString(GetLastError())); } return std.utf.toUTF8(result[0 .. result.length-1]); // omit trailing null } } return s[0 .. c-s]; // string is ASCII, no conversion necessary } ldc-1.1.0-beta3-src/runtime/phobos/std/windows/registry.d0000664000175000017500000014362712776215007021432 0ustar kaikai/** This library provides Win32 Registry facilities. Copyright: Copyright 2003-2004 by Matthew Wilson and Synesis Software Written by Matthew Wilson License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Author: Matthew Wilson, Kenji Hara History: Created 15th March 2003, Updated 25th April 2004, Source: $(PHOBOSSRC std/windows/_registry.d) */ /* ///////////////////////////////////////////////////////////////////////////// * * 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: * * - 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. * - Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * - This notice may not be removed or altered from any source * distribution. * * ////////////////////////////////////////////////////////////////////////// */ module std.windows.registry; version (Windows): import std.array; import std.system : Endian, endian; import std.exception; import core.sys.windows.windows; import std.windows.syserror; import std.conv; import std.utf : toUTF8, toUTF16; private import std.internal.windows.advapi32; import std.internal.cstring; //debug = winreg; debug(winreg) import std.stdio; private { import core.sys.windows.winbase : lstrlenW; void enforceSucc(LONG res, lazy string message, string fn = __FILE__, size_t ln = __LINE__) { if (res != ERROR_SUCCESS) throw new RegistryException(message, res, fn, ln); } } /* ************* Exceptions *************** */ // Do not use. Left for compatibility. class Win32Exception : WindowsException { @safe this(string message, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null) { super(0, message, fn, ln); } @safe this(string message, int errnum, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null) { super(errnum, message, fn, ln); } @property int error() { return super.code; } } version(unittest) import std.string : startsWith, endsWith; unittest { // Test that we can throw and catch one by its own type string message = "Test W1"; auto e = collectException!Win32Exception( enforce(false, new Win32Exception(message))); assert(e.msg.startsWith(message)); } unittest { // ditto string message = "Test W2"; int code = 5; auto e = collectException!Win32Exception( enforce(false, new Win32Exception(message, code))); assert(e.error == code); assert(e.msg.startsWith(message)); } /** Exception class thrown by the std.windows.registry classes. */ class RegistryException : Win32Exception { public: /** Creates an instance of the exception. Params: message = The message associated with the exception. */ @safe this(string message, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null) { super(message, fn, ln, next); } /** Creates an instance of the exception, with the given. Params: message = The message associated with the exception. error = The Win32 error number associated with the exception. */ @safe this(string message, int error, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null) { super(message, error, fn, ln, next); } } unittest { // (i) Test that we can throw and catch one by its own type string message = "Test 1"; int code = 3; auto e = collectException!RegistryException( enforce(false, new RegistryException(message, code))); assert(e.error == code); assert(e.msg.startsWith(message)); } unittest { // ditto string message = "Test 2"; auto e = collectException!RegistryException( enforce(false, new RegistryException(message))); assert(e.msg.startsWith(message)); } /* ************* public enumerations *************** */ /** Enumeration of the recognised registry access modes. */ enum REGSAM { KEY_QUERY_VALUE = 0x0001, /// Permission to query subkey data KEY_SET_VALUE = 0x0002, /// Permission to set subkey data KEY_CREATE_SUB_KEY = 0x0004, /// Permission to create subkeys KEY_ENUMERATE_SUB_KEYS = 0x0008, /// Permission to enumerate subkeys KEY_NOTIFY = 0x0010, /// Permission for change notification KEY_CREATE_LINK = 0x0020, /// Permission to create a symbolic link KEY_WOW64_32KEY = 0x0200, /// Enables a 64- or 32-bit application to open a 32-bit key KEY_WOW64_64KEY = 0x0100, /// Enables a 64- or 32-bit application to open a 64-bit key KEY_WOW64_RES = 0x0300, /// KEY_READ = (STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & ~(SYNCHRONIZE), /// Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, /// KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY access rights KEY_WRITE = (STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & ~(SYNCHRONIZE), /// Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, /// and KEY_CREATE_SUB_KEY access rights KEY_EXECUTE = KEY_READ & ~(SYNCHRONIZE), /// Permission for read access KEY_ALL_ACCESS = (STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & ~(SYNCHRONIZE), /// Combines the KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, /// KEY_NOTIFY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, and /// KEY_SET_VALUE access rights, plus all the standard /// access rights except SYNCHRONIZE } /** Enumeration of the recognised registry value types. */ enum REG_VALUE_TYPE : DWORD { REG_UNKNOWN = -1, /// REG_NONE = 0, /// The null value type. (In practise this is treated as a zero-length binary array by the Win32 registry) REG_SZ = 1, /// A zero-terminated string REG_EXPAND_SZ = 2, /// A zero-terminated string containing expandable environment variable references REG_BINARY = 3, /// A binary blob REG_DWORD = 4, /// A 32-bit unsigned integer REG_DWORD_LITTLE_ENDIAN = 4, /// A 32-bit unsigned integer, stored in little-endian byte order REG_DWORD_BIG_ENDIAN = 5, /// A 32-bit unsigned integer, stored in big-endian byte order REG_LINK = 6, /// A registry link REG_MULTI_SZ = 7, /// A set of zero-terminated strings REG_RESOURCE_LIST = 8, /// A hardware resource list REG_FULL_RESOURCE_DESCRIPTOR = 9, /// A hardware resource descriptor REG_RESOURCE_REQUIREMENTS_LIST = 10, /// A hardware resource requirements list REG_QWORD = 11, /// A 64-bit unsigned integer REG_QWORD_LITTLE_ENDIAN = 11, /// A 64-bit unsigned integer, stored in little-endian byte order } /* ************* private *************** */ private import core.sys.windows.winnt : DELETE , READ_CONTROL , WRITE_DAC , WRITE_OWNER , SYNCHRONIZE , STANDARD_RIGHTS_REQUIRED, STANDARD_RIGHTS_READ , STANDARD_RIGHTS_WRITE , STANDARD_RIGHTS_EXECUTE , STANDARD_RIGHTS_ALL , SPECIFIC_RIGHTS_ALL ; private import core.sys.windows.winreg : REG_CREATED_NEW_KEY , REG_OPENED_EXISTING_KEY ; // Returns samDesired but without WoW64 flags if not in WoW64 mode // for compatibility with Windows 2000 private REGSAM compatibleRegsam(in REGSAM samDesired) { return isWow64 ? samDesired : cast(REGSAM)(samDesired & ~REGSAM.KEY_WOW64_RES); } ///Returns true, if we are in WoW64 mode and have WoW64 flags private bool haveWoW64Job(in REGSAM samDesired) { return isWow64 && (samDesired & REGSAM.KEY_WOW64_RES); } private REG_VALUE_TYPE _RVT_from_Endian(Endian endian) { final switch (endian) { case Endian.bigEndian: return REG_VALUE_TYPE.REG_DWORD_BIG_ENDIAN; case Endian.littleEndian: return REG_VALUE_TYPE.REG_DWORD_LITTLE_ENDIAN; } } private LONG regCloseKey(in HKEY hkey) in { assert(hkey !is null); } body { /* No need to attempt to close any of the standard hive keys. * Although it's documented that calling RegCloseKey() on any of * these hive keys is ignored, we'd rather not trust the Win32 * API. */ if (cast(uint)hkey & 0x80000000) { switch (cast(uint)hkey) { case HKEY_CLASSES_ROOT: case HKEY_CURRENT_USER: case HKEY_LOCAL_MACHINE: case HKEY_USERS: case HKEY_PERFORMANCE_DATA: case HKEY_PERFORMANCE_TEXT: case HKEY_PERFORMANCE_NLSTEXT: case HKEY_CURRENT_CONFIG: case HKEY_DYN_DATA: return ERROR_SUCCESS; default: /* Do nothing */ break; } } return RegCloseKey(hkey); } private void regFlushKey(in HKEY hkey) in { assert(hkey !is null); } body { immutable res = RegFlushKey(hkey); enforceSucc(res, "Key cannot be flushed"); } private HKEY regCreateKey(in HKEY hkey, in string subKey, in DWORD dwOptions, in REGSAM samDesired, in LPSECURITY_ATTRIBUTES lpsa, out DWORD disposition) in { assert(hkey !is null); assert(subKey !is null); } body { HKEY hkeyResult; enforceSucc(RegCreateKeyExW( hkey, subKey.tempCStringW(), 0, null, dwOptions, compatibleRegsam(samDesired), cast(LPSECURITY_ATTRIBUTES) lpsa, &hkeyResult, &disposition), "Failed to create requested key: \"" ~ subKey ~ "\""); return hkeyResult; } private void regDeleteKey(in HKEY hkey, in string subKey, in REGSAM samDesired) in { assert(hkey !is null); assert(subKey !is null); } body { LONG res; if (haveWoW64Job(samDesired)) { loadAdvapi32(); res = pRegDeleteKeyExW(hkey, subKey.tempCStringW(), samDesired, 0); } else { res = RegDeleteKeyW(hkey, subKey.tempCStringW()); } enforceSucc(res, "Key cannot be deleted: \"" ~ subKey ~ "\""); } private void regDeleteValue(in HKEY hkey, in string valueName) in { assert(hkey !is null); assert(valueName !is null); } body { enforceSucc(RegDeleteValueW(hkey, valueName.tempCStringW()), "Value cannot be deleted: \"" ~ valueName ~ "\""); } private HKEY regDup(HKEY hkey) in { assert(hkey !is null); } body { /* Can't duplicate standard keys, but don't need to, so can just return */ if (cast(uint)hkey & 0x80000000) { switch (cast(uint)hkey) { case HKEY_CLASSES_ROOT: case HKEY_CURRENT_USER: case HKEY_LOCAL_MACHINE: case HKEY_USERS: case HKEY_PERFORMANCE_DATA: case HKEY_PERFORMANCE_TEXT: case HKEY_PERFORMANCE_NLSTEXT: case HKEY_CURRENT_CONFIG: case HKEY_DYN_DATA: return hkey; default: /* Do nothing */ break; } } HKEY hkeyDup; immutable res = RegOpenKeyW(hkey, null, &hkeyDup); debug(winreg) { if (res != ERROR_SUCCESS) { writefln("regDup() failed: 0x%08x 0x%08x %d", hkey, hkeyDup, res); } assert(res == ERROR_SUCCESS); } return (res == ERROR_SUCCESS) ? hkeyDup : null; } private LONG regEnumKeyName(in HKEY hkey, in DWORD index, ref wchar[] name, out DWORD cchName) in { assert(hkey !is null); assert(name !is null); assert(name.length > 0); } out(res) { assert(res != ERROR_MORE_DATA); } body { // The Registry API lies about the lengths of a very few sub-key lengths // so we have to test to see if it whinges about more data, and provide // more if it does. for (;;) { cchName = to!DWORD(name.length); immutable res = RegEnumKeyExW(hkey, index, name.ptr, &cchName, null, null, null, null); if (res != ERROR_MORE_DATA) return res; // Now need to increase the size of the buffer and try again name.length *= 2; } assert(0); } private LONG regEnumValueName(in HKEY hkey, in DWORD dwIndex, ref wchar[] name, out DWORD cchName) in { assert(hkey !is null); } body { for (;;) { cchName = to!DWORD(name.length); immutable res = RegEnumValueW(hkey, dwIndex, name.ptr, &cchName, null, null, null, null); if (res != ERROR_MORE_DATA) return res; name.length *= 2; } assert(0); } private LONG regGetNumSubKeys(in HKEY hkey, out DWORD cSubKeys, out DWORD cchSubKeyMaxLen) in { assert(hkey !is null); } body { return RegQueryInfoKeyW(hkey, null, null, null, &cSubKeys, &cchSubKeyMaxLen, null, null, null, null, null, null); } private LONG regGetNumValues(in HKEY hkey, out DWORD cValues, out DWORD cchValueMaxLen) in { assert(hkey !is null); } body { return RegQueryInfoKeyW(hkey, null, null, null, null, null, null, &cValues, &cchValueMaxLen, null, null, null); } private REG_VALUE_TYPE regGetValueType(in HKEY hkey, in string name) in { assert(hkey !is null); } body { REG_VALUE_TYPE type; enforceSucc(RegQueryValueExW(hkey, name.tempCStringW(), null, cast(LPDWORD) &type, null, null), "Value cannot be opened: \"" ~ name ~ "\""); return type; } private HKEY regOpenKey(in HKEY hkey, in string subKey, in REGSAM samDesired) in { assert(hkey !is null); assert(subKey !is null); } body { HKEY hkeyResult; enforceSucc(RegOpenKeyExW(hkey, subKey.tempCStringW(), 0, compatibleRegsam(samDesired), &hkeyResult), "Failed to open requested key: \"" ~ subKey ~ "\""); return hkeyResult; } private void regQueryValue(in HKEY hkey, string name, out string value, REG_VALUE_TYPE reqType) in { assert(hkey !is null); } body { import core.bitop : bswap; REG_VALUE_TYPE type; // See bugzilla 961 on this union U { uint dw; ulong qw; } U u; void* data = &u.qw; DWORD cbData = u.qw.sizeof; auto keynameTmp = name.tempCStringW(); LONG res = RegQueryValueExW(hkey, keynameTmp, null, cast(LPDWORD) &type, data, &cbData); if (res == ERROR_MORE_DATA) { data = (new ubyte[cbData]).ptr; res = RegQueryValueExW(hkey, keynameTmp, null, cast(LPDWORD) &type, data, &cbData); } enforceSucc(res, "Cannot read the requested value"); enforce(type == reqType, new RegistryException("Value type has been changed since the value was acquired")); switch (type) { case REG_VALUE_TYPE.REG_SZ: case REG_VALUE_TYPE.REG_EXPAND_SZ: auto wstr = (cast(immutable(wchar)*)data)[0 .. cbData / wchar.sizeof]; assert(wstr.length > 0 && wstr[$-1] == '\0'); if (wstr.length && wstr[$-1] == '\0') wstr.length = wstr.length - 1; assert(wstr.length == 0 || wstr[$-1] != '\0'); value = toUTF8(wstr); break; case REG_VALUE_TYPE.REG_DWORD_LITTLE_ENDIAN: version(LittleEndian) value = to!string(u.dw); else value = to!string(core.bitop.bswap(u.dw)); break; case REG_VALUE_TYPE.REG_DWORD_BIG_ENDIAN: version(LittleEndian) value = to!string(core.bitop.bswap(u.dw)); else value = to!string(u.dw); break; case REG_VALUE_TYPE.REG_QWORD_LITTLE_ENDIAN: value = to!string(u.qw); break; case REG_VALUE_TYPE.REG_BINARY: case REG_VALUE_TYPE.REG_MULTI_SZ: default: throw new RegistryException("Cannot read the given value as a string"); } } private void regQueryValue(in HKEY hkey, in string name, out string[] value, REG_VALUE_TYPE reqType) in { assert(hkey !is null); } body { REG_VALUE_TYPE type; auto keynameTmp = name.tempCStringW(); wchar[] data = new wchar[256]; DWORD cbData = to!DWORD(data.length * wchar.sizeof); LONG res = RegQueryValueExW(hkey, keynameTmp, null, cast(LPDWORD) &type, data.ptr, &cbData); if (res == ERROR_MORE_DATA) { data.length = cbData / wchar.sizeof; res = RegQueryValueExW(hkey, keynameTmp, null, cast(LPDWORD) &type, data.ptr, &cbData); } else if (res == ERROR_SUCCESS) { data.length = cbData / wchar.sizeof; } enforceSucc(res, "Cannot read the requested value"); enforce(type == REG_VALUE_TYPE.REG_MULTI_SZ, new RegistryException("Cannot read the given value as a string")); enforce(type == reqType, new RegistryException("Value type has been changed since the value was acquired")); // Remove last two (or one) null terminator assert(data.length > 0 && data[$-1] == '\0'); data.length = data.length - 1; if (data.length > 0 && data[$-1] == '\0') data.length = data.length - 1; auto list = std.array.split(data[], "\0"); value.length = list.length; foreach (i, ref v; value) { v = toUTF8(list[i]); } } private void regQueryValue(in HKEY hkey, in string name, out uint value, REG_VALUE_TYPE reqType) in { assert(hkey !is null); } body { import core.bitop : bswap; REG_VALUE_TYPE type; DWORD cbData = value.sizeof; enforceSucc(RegQueryValueExW(hkey, name.tempCStringW(), null, cast(LPDWORD) &type, &value, &cbData), "Cannot read the requested value"); enforce(type == reqType, new RegistryException("Value type has been changed since the value was acquired")); switch (type) { case REG_VALUE_TYPE.REG_DWORD_LITTLE_ENDIAN: version(LittleEndian) static assert(REG_VALUE_TYPE.REG_DWORD == REG_VALUE_TYPE.REG_DWORD_LITTLE_ENDIAN); else value = core.bitop.bswap(value); break; case REG_VALUE_TYPE.REG_DWORD_BIG_ENDIAN: version(LittleEndian) value = core.bitop.bswap(value); else static assert(REG_VALUE_TYPE.REG_DWORD == REG_VALUE_TYPE.REG_DWORD_BIG_ENDIAN); break; default: throw new RegistryException("Cannot read the given value as a 32-bit integer"); } } private void regQueryValue(in HKEY hkey, in string name, out ulong value, REG_VALUE_TYPE reqType) in { assert(hkey !is null); } body { REG_VALUE_TYPE type; DWORD cbData = value.sizeof; enforceSucc(RegQueryValueExW(hkey, name.tempCStringW(), null, cast(LPDWORD) &type, &value, &cbData), "Cannot read the requested value"); enforce(type == reqType, new RegistryException("Value type has been changed since the value was acquired")); switch (type) { case REG_VALUE_TYPE.REG_QWORD_LITTLE_ENDIAN: break; default: throw new RegistryException("Cannot read the given value as a 64-bit integer"); } } private void regQueryValue(in HKEY hkey, in string name, out byte[] value, REG_VALUE_TYPE reqType) in { assert(hkey !is null); } body { REG_VALUE_TYPE type; byte[] data = new byte[100]; DWORD cbData = to!DWORD(data.length); LONG res; auto keynameTmp = name.tempCStringW(); res = RegQueryValueExW(hkey, keynameTmp, null, cast(LPDWORD) &type, data.ptr, &cbData); if (res == ERROR_MORE_DATA) { data.length = cbData; res = RegQueryValueExW(hkey, keynameTmp, null, cast(LPDWORD) &type, data.ptr, &cbData); } enforceSucc(res, "Cannot read the requested value"); enforce(type == reqType, new RegistryException("Value type has been changed since the value was acquired")); switch (type) { case REG_VALUE_TYPE.REG_BINARY: data.length = cbData; value = data; break; default: throw new RegistryException("Cannot read the given value as a string"); } } private void regSetValue(in HKEY hkey, in string subKey, in REG_VALUE_TYPE type, in LPCVOID lpData, in DWORD cbData) in { assert(hkey !is null); } body { enforceSucc(RegSetValueExW(hkey, subKey.tempCStringW(), 0, type, cast(BYTE*) lpData, cbData), "Value cannot be set: \"" ~ subKey ~ "\""); } private void regProcessNthKey(HKEY hkey, scope void delegate(scope LONG delegate(DWORD, out string)) dg) { DWORD cSubKeys; DWORD cchSubKeyMaxLen; immutable res = regGetNumSubKeys(hkey, cSubKeys, cchSubKeyMaxLen); assert(res == ERROR_SUCCESS); wchar[] sName = new wchar[cchSubKeyMaxLen + 1]; dg((DWORD index, out string name) { DWORD cchName; immutable res = regEnumKeyName(hkey, index, sName, cchName); if (res == ERROR_SUCCESS) { name = toUTF8(sName[0 .. cchName]); } return res; }); } private void regProcessNthValue(HKEY hkey, scope void delegate(scope LONG delegate(DWORD, out string)) dg) { DWORD cValues; DWORD cchValueMaxLen; immutable res = regGetNumValues(hkey, cValues, cchValueMaxLen); assert(res == ERROR_SUCCESS); wchar[] sName = new wchar[cchValueMaxLen + 1]; dg((DWORD index, out string name) { DWORD cchName; immutable res = regEnumValueName(hkey, index, sName, cchName); if (res == ERROR_SUCCESS) { name = toUTF8(sName[0 .. cchName]); } return res; }); } /* ************* public classes *************** */ /** This class represents a registry key. */ class Key { @safe pure nothrow invariant() { assert(m_hkey !is null); } private: @safe pure nothrow this(HKEY hkey, string name, bool created) in { assert(hkey !is null); } body { m_hkey = hkey; m_name = name; } ~this() { regCloseKey(m_hkey); // Even though this is horried waste-of-cycles programming // we're doing it here so that the m_hkey = null; } public: /// The name of the key @property string name() @safe pure nothrow const { return m_name; } /** The number of sub keys. */ @property size_t keyCount() const { uint cSubKeys; uint cchSubKeyMaxLen; enforceSucc(regGetNumSubKeys(m_hkey, cSubKeys, cchSubKeyMaxLen), "Number of sub-keys cannot be determined"); return cSubKeys; } /** An enumerable sequence of all the sub-keys of this key. */ @property KeySequence keys() @safe pure { return new KeySequence(this); } /** An enumerable sequence of the names of all the sub-keys of this key. */ @property KeyNameSequence keyNames() @safe pure { return new KeyNameSequence(this); } /** The number of values. */ @property size_t valueCount() const { uint cValues; uint cchValueMaxLen; enforceSucc(regGetNumValues(m_hkey, cValues, cchValueMaxLen), "Number of values cannot be determined"); return cValues; } /** An enumerable sequence of all the values of this key. */ @property ValueSequence values() @safe pure { return new ValueSequence(this); } /** An enumerable sequence of the names of all the values of this key. */ @property ValueNameSequence valueNames() @safe pure { return new ValueNameSequence(this); } public: /** Returns the named sub-key of this key. Params: name = The name of the subkey to create. May not be $(D null). Returns: The created key. Throws: $(D RegistryException) is thrown if the key cannot be created. */ Key createKey(string name, REGSAM access = REGSAM.KEY_ALL_ACCESS) { enforce(!name.empty, new RegistryException("Key name is invalid")); DWORD disposition; HKEY hkey = regCreateKey(m_hkey, name, 0, access, null, disposition); assert(hkey !is null); // Potential resource leak here!! // // If the allocation of the memory for Key fails, the HKEY could be // lost. Hence, we catch such a failure by the finally, and release // the HKEY there. If the creation of try { Key key = new Key(hkey, name, disposition == REG_CREATED_NEW_KEY); hkey = null; return key; } finally { if (hkey !is null) { regCloseKey(hkey); } } } /** Returns the named sub-key of this key. Params: name = The name of the subkey to aquire. If name is the empty string, then the called key is duplicated. access = The desired access; one of the $(D REGSAM) enumeration. Returns: The aquired key. Throws: This function never returns $(D null). If a key corresponding to the requested name is not found, $(D RegistryException) is thrown. */ Key getKey(string name, REGSAM access = REGSAM.KEY_READ) { if (name.empty) return new Key(regDup(m_hkey), m_name, false); HKEY hkey = regOpenKey(m_hkey, name, access); assert(hkey !is null); // Potential resource leak here!! // // If the allocation of the memory for Key fails, the HKEY could be // lost. Hence, we catch such a failure by the finally, and release // the HKEY there. If the creation of try { Key key = new Key(hkey, name, false); hkey = null; return key; } finally { if (hkey != null) { regCloseKey(hkey); } } } /** Deletes the named key. Params: name = The name of the key to delete. May not be $(D null). */ void deleteKey(string name, REGSAM access = cast(REGSAM)0) { enforce(!name.empty, new RegistryException("Key name is invalid")); regDeleteKey(m_hkey, name, access); } /** Returns the named value. If $(D name) is the empty string, then the default value is returned. Returns: This function never returns $(D null). If a value corresponding to the requested name is not found, $(D RegistryException) is thrown. */ Value getValue(string name) { return new Value(this, name, regGetValueType(m_hkey, name)); } /** Sets the named value with the given 32-bit unsigned integer value. Params: name = The name of the value to set. If it is the empty string, sets the default value. value = The 32-bit unsigned value to set. Throws: If a value corresponding to the requested name is not found, $(D RegistryException) is thrown. */ void setValue(string name, uint value) { setValue(name, value, endian); } /** Sets the named value with the given 32-bit unsigned integer value, according to the desired byte-ordering. Params: name = The name of the value to set. If it is the empty string, sets the default value. value = The 32-bit unsigned value to set. endian = Can be $(D Endian.BigEndian) or $(D Endian.LittleEndian). Throws: If a value corresponding to the requested name is not found, $(D RegistryException) is thrown. */ void setValue(string name, uint value, Endian endian) { REG_VALUE_TYPE type = _RVT_from_Endian(endian); assert(type == REG_VALUE_TYPE.REG_DWORD_BIG_ENDIAN || type == REG_VALUE_TYPE.REG_DWORD_LITTLE_ENDIAN); regSetValue(m_hkey, name, type, &value, value.sizeof); } /** Sets the named value with the given 64-bit unsigned integer value. Params: name = The name of the value to set. If it is the empty string, sets the default value. value = The 64-bit unsigned value to set. Throws: If a value corresponding to the requested name is not found, $(D RegistryException) is thrown. */ void setValue(string name, ulong value) { regSetValue(m_hkey, name, REG_VALUE_TYPE.REG_QWORD, &value, value.sizeof); } /** Sets the named value with the given string value. Params: name = The name of the value to set. If it is the empty string, sets the default value. value = The string value to set. Throws: If a value corresponding to the requested name is not found, $(D RegistryException) is thrown. */ void setValue(string name, string value) { setValue(name, value, false); } /** Sets the named value with the given string value. Params: name = The name of the value to set. If it is the empty string, sets the default value. value = The string value to set. asEXPAND_SZ = If $(D true), the value will be stored as an expandable environment string, otherwise as a normal string. Throws: If a value corresponding to the requested name is not found, $(D RegistryException) is thrown. */ void setValue(string name, string value, bool asEXPAND_SZ) { auto pszTmp = value.tempCStringW(); const(void)* data = pszTmp; DWORD len = to!DWORD(lstrlenW(pszTmp) * wchar.sizeof); regSetValue(m_hkey, name, asEXPAND_SZ ? REG_VALUE_TYPE.REG_EXPAND_SZ : REG_VALUE_TYPE.REG_SZ, data, len); } /** Sets the named value with the given multiple-strings value. Params: name = The name of the value to set. If it is the empty string, sets the default value. value = The multiple-strings value to set. Throws: If a value corresponding to the requested name is not found, $(D RegistryException) is thrown. */ void setValue(string name, string[] value) { wstring[] data = new wstring[value.length+1]; foreach (i, ref s; data[0..$-1]) { s = toUTF16(value[i]); } data[$-1] = "\0"; auto ws = std.array.join(data, "\0"w); regSetValue(m_hkey, name, REG_VALUE_TYPE.REG_MULTI_SZ, ws.ptr, to!uint(ws.length * wchar.sizeof)); } /** Sets the named value with the given binary value. Params: name = The name of the value to set. If it is the empty string, sets the default value. value = The binary value to set. Throws: If a value corresponding to the requested name is not found, $(D RegistryException) is thrown. */ void setValue(string name, byte[] value) { regSetValue(m_hkey, name, REG_VALUE_TYPE.REG_BINARY, value.ptr, to!DWORD(value.length)); } /** Deletes the named value. Params: name = The name of the value to delete. May not be $(D null). Throws: If a value of the requested name is not found, $(D RegistryException) is thrown. */ void deleteValue(string name) { regDeleteValue(m_hkey, name); } /** Flushes any changes to the key to disk. */ void flush() { regFlushKey(m_hkey); } private: HKEY m_hkey; string m_name; } /** This class represents a value of a registry key. */ class Value { @safe pure nothrow invariant() { assert(m_key !is null); } private: @safe pure nothrow this(Key key, string name, REG_VALUE_TYPE type) in { assert(null !is key); } body { m_key = key; m_type = type; m_name = name; } public: /** The name of the value. If the value represents a default value of a key, which has no name, the returned string will be of zero length. */ @property string name() @safe pure nothrow const { return m_name; } /** The type of value. */ @property REG_VALUE_TYPE type() @safe pure nothrow const { return m_type; } /** Obtains the current value of the value as a string. If the value's type is REG_EXPAND_SZ the returned value is not expanded; $(D value_EXPAND_SZ) should be called Returns: The contents of the value. Throws: $(D RegistryException) if the type of the value is not REG_SZ, REG_EXPAND_SZ, REG_DWORD, or REG_QWORD. */ @property string value_SZ() const { string value; regQueryValue(m_key.m_hkey, m_name, value, m_type); return value; } /** Obtains the current value as a string, within which any environment variables have undergone expansion. This function works with the same value-types as $(D value_SZ). Returns: The contents of the value. */ @property string value_EXPAND_SZ() const { string value = value_SZ; // ExpandEnvironemntStrings(): // http://msdn2.microsoft.com/en-us/library/ms724265.aspx const srcTmp = value.tempCStringW(); DWORD cchRequired = ExpandEnvironmentStringsW(srcTmp, null, 0); wchar[] newValue = new wchar[cchRequired]; immutable DWORD count = enforce!Win32Exception( ExpandEnvironmentStringsW(srcTmp, newValue.ptr, to!DWORD(newValue.length)), "Failed to expand environment variables"); return toUTF8(newValue[0 .. count-1]); // remove trailing 0 } /** Obtains the current value as an array of strings. Returns: The contents of the value. Throws: $(D RegistryException) if the type of the value is not REG_MULTI_SZ. */ @property string[] value_MULTI_SZ() const { string[] value; regQueryValue(m_key.m_hkey, m_name, value, m_type); return value; } /** Obtains the current value as a 32-bit unsigned integer, ordered correctly according to the current architecture. Returns: The contents of the value. Throws: $(D RegistryException) is thrown for all types other than REG_DWORD, REG_DWORD_LITTLE_ENDIAN and REG_DWORD_BIG_ENDIAN. */ @property uint value_DWORD() const { uint value; regQueryValue(m_key.m_hkey, m_name, value, m_type); return value; } /** Obtains the value as a 64-bit unsigned integer, ordered correctly according to the current architecture. Returns: The contents of the value. Throws: $(D RegistryException) if the type of the value is not REG_QWORD. */ @property ulong value_QWORD() const { ulong value; regQueryValue(m_key.m_hkey, m_name, value, m_type); return value; } /** Obtains the value as a binary blob. Returns: The contents of the value. Throws: $(D RegistryException) if the type of the value is not REG_BINARY. */ @property byte[] value_BINARY() const { byte[] value; regQueryValue(m_key.m_hkey, m_name, value, m_type); return value; } private: Key m_key; REG_VALUE_TYPE m_type; string m_name; } /** Represents the local system registry. */ final class Registry { private: @disable this() { } public: /// Returns the root key for the HKEY_CLASSES_ROOT hive static @property Key classesRoot() { return new Key(HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT", false); } /// Returns the root key for the HKEY_CURRENT_USER hive static @property Key currentUser() { return new Key(HKEY_CURRENT_USER, "HKEY_CURRENT_USER", false); } /// Returns the root key for the HKEY_LOCAL_MACHINE hive static @property Key localMachine() { return new Key(HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE", false); } /// Returns the root key for the HKEY_USERS hive static @property Key users() { return new Key(HKEY_USERS, "HKEY_USERS", false); } /// Returns the root key for the HKEY_PERFORMANCE_DATA hive static @property Key performanceData() { return new Key(HKEY_PERFORMANCE_DATA, "HKEY_PERFORMANCE_DATA", false); } /// Returns the root key for the HKEY_CURRENT_CONFIG hive static @property Key currentConfig() { return new Key(HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG", false); } /// Returns the root key for the HKEY_DYN_DATA hive static @property Key dynData() { return new Key(HKEY_DYN_DATA, "HKEY_DYN_DATA", false); } } /** An enumerable sequence representing the names of the sub-keys of a registry Key. Example: ---- Key key = ... foreach (string subkeyName; key.keyNames) { // using subkeyName } ---- */ class KeyNameSequence { @safe pure nothrow invariant() { assert(m_key !is null); } private: @safe pure nothrow this(Key key) { m_key = key; } public: /** The number of keys. */ @property size_t count() const { return m_key.keyCount; } /** The name of the key at the given index. Params: index = The 0-based index of the key to retrieve. Returns: The name of the key corresponding to the given index. Throws: RegistryException if no corresponding key is retrieved. */ string getKeyName(size_t index) { string name; regProcessNthKey(m_key.m_hkey, (scope LONG delegate(DWORD, out string) getName) { enforceSucc(getName(to!DWORD(index), name), "Invalid key"); }); return name; } /** The name of the key at the given index. Params: index = The 0-based index of the key to retrieve. Returns: The name of the key corresponding to the given index. Throws: $(D RegistryException) if no corresponding key is retrieved. */ string opIndex(size_t index) { return getKeyName(index); } public: /// int opApply(scope int delegate(ref string name) dg) { int result; regProcessNthKey(m_key.m_hkey, (scope LONG delegate(DWORD, out string) getName) { for (DWORD index = 0; !result; ++index) { string name; immutable res = getName(index, name); if (res == ERROR_NO_MORE_ITEMS) // Enumeration complete break; enforceSucc(res, "Key name enumeration incomplete"); result = dg(name); } }); return result; } private: Key m_key; } /** An enumerable sequence representing the sub-keys of a registry Key. Example: ---- Key key = ... foreach (Key subkey; key.keys) { // using subkey } ---- */ class KeySequence { @safe pure nothrow invariant() { assert(m_key !is null); } private: @safe pure nothrow this(Key key) { m_key = key; } public: /** The number of keys. */ @property size_t count() const { return m_key.keyCount; } /** The key at the given index. Params: index = The 0-based index of the key to retrieve. Returns: The key corresponding to the given index. Throws: $(D RegistryException) if no corresponding key is retrieved. */ Key getKey(size_t index) { string name; regProcessNthKey(m_key.m_hkey, (scope LONG delegate(DWORD, out string) getName) { enforceSucc(getName(to!DWORD(index), name), "Invalid key"); }); return m_key.getKey(name); } /** The key at the given index. Params: index = The 0-based index of the key to retrieve. Returns: The key corresponding to the given index. Throws: $(D RegistryException) if no corresponding key is retrieved. */ Key opIndex(size_t index) { return getKey(index); } public: /// int opApply(scope int delegate(ref Key key) dg) { int result = 0; regProcessNthKey(m_key.m_hkey, (scope LONG delegate(DWORD, out string) getName) { for (DWORD index = 0; !result; ++index) { string name; immutable res = getName(index, name); if (res == ERROR_NO_MORE_ITEMS) // Enumeration complete break; enforceSucc(res, "Key enumeration incomplete"); try { Key key = m_key.getKey(name); result = dg(key); } catch (RegistryException e) { // Skip inaccessible keys; they are // accessible via the KeyNameSequence if (e.error == ERROR_ACCESS_DENIED) continue; throw e; } } }); return result; } private: Key m_key; } /** An enumerable sequence representing the names of the values of a registry Key. Example: ---- Key key = ... foreach (string valueName; key.valueNames) { // using valueName } ---- */ class ValueNameSequence { @safe pure nothrow invariant() { assert(m_key !is null); } private: @safe pure nothrow this(Key key) { m_key = key; } public: /** The number of values. */ @property size_t count() const { return m_key.valueCount; } /** The name of the value at the given index. Params: index = The 0-based index of the value to retrieve. Returns: The name of the value corresponding to the given index. Throws: $(D RegistryException) if no corresponding value is retrieved. */ string getValueName(size_t index) { string name; regProcessNthValue(m_key.m_hkey, (scope LONG delegate(DWORD, out string) getName) { enforceSucc(getName(to!DWORD(index), name), "Invalid value"); }); return name; } /** The name of the value at the given index. Params: index = The 0-based index of the value to retrieve. Returns: The name of the value corresponding to the given index. Throws: $(D RegistryException) if no corresponding value is retrieved. */ string opIndex(size_t index) { return getValueName(index); } public: /// int opApply(scope int delegate(ref string name) dg) { int result = 0; regProcessNthValue(m_key.m_hkey, (scope LONG delegate(DWORD, out string) getName) { for (DWORD index = 0; !result; ++index) { string name; immutable res = getName(index, name); if (res == ERROR_NO_MORE_ITEMS) // Enumeration complete break; enforceSucc(res, "Value name enumeration incomplete"); result = dg(name); } }); return result; } private: Key m_key; } /** An enumerable sequence representing the values of a registry Key. Example: ---- Key key = ... foreach (Value value; key.values) { // using value } ---- */ class ValueSequence { @safe pure nothrow invariant() { assert(m_key !is null); } private: @safe pure nothrow this(Key key) { m_key = key; } public: /// The number of values @property size_t count() const { return m_key.valueCount; } /** The value at the given $(D index). Params: index = The 0-based index of the value to retrieve Returns: The value corresponding to the given index. Throws: $(D RegistryException) if no corresponding value is retrieved */ Value getValue(size_t index) { string name; regProcessNthValue(m_key.m_hkey, (scope LONG delegate(DWORD, out string) getName) { enforceSucc(getName(to!DWORD(index), name), "Invalid value"); }); return m_key.getValue(name); } /** The value at the given $(D index). Params: index = The 0-based index of the value to retrieve. Returns: The value corresponding to the given index. Throws: $(D RegistryException) if no corresponding value is retrieved. */ Value opIndex(size_t index) { return getValue(index); } public: /// int opApply(scope int delegate(ref Value value) dg) { int result = 0; regProcessNthValue(m_key.m_hkey, (scope LONG delegate(DWORD, out string) getName) { for (DWORD index = 0; !result; ++index) { string name; immutable res = getName(index, name); if (res == ERROR_NO_MORE_ITEMS) // Enumeration complete break; enforceSucc(res, "Value enumeration incomplete"); Value value = m_key.getValue(name); result = dg(value); } }); return result; } private: Key m_key; } unittest { debug(winreg) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); debug(winreg) writefln("std.windows.registry.unittest read"); /+ // Mask for test speed up Key HKCR = Registry.classesRoot; Key CLSID = HKCR.getKey("CLSID"); foreach (Key key; CLSID.keys) { foreach (Value val; key.values) { } } +/ Key HKCU = Registry.currentUser; assert(HKCU); // Enumerate all subkeys of key Software Key softwareKey = HKCU.getKey("Software"); assert(softwareKey); foreach (Key key; softwareKey.keys) { //writefln("Key %s", key.name); foreach (Value val; key.values) { } } } unittest { debug(winreg) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); debug(winreg) writefln("std.windows.registry.unittest write"); // Warning: This unit test writes to the registry. // The test can fail if you don't have sufficient rights Key HKCU = Registry.currentUser; assert(HKCU); // Create a new key string unittestKeyName = "Temporary key for a D UnitTest which can be deleted afterwards"; Key unittestKey = HKCU.createKey(unittestKeyName); assert(unittestKey); Key cityKey = unittestKey.createKey("CityCollection using foreign names with umlauts and accents: \u00f6\u00e4\u00fc\u00d6\u00c4\u00dc\u00e0\u00e1\u00e2\u00df"); cityKey.setValue("K\u00f6ln", "Germany"); // Cologne cityKey.setValue("\u041c\u0438\u043d\u0441\u043a", "Belarus"); // Minsk cityKey.setValue("\u5317\u4eac", "China"); // Bejing bool foundCologne, foundMinsk, foundBeijing; foreach (Value v; cityKey.values) { auto vname = v.name; auto vvalue_SZ = v.value_SZ; if (v.name == "K\u00f6ln") { foundCologne = true; assert(v.value_SZ == "Germany"); } if (v.name == "\u041c\u0438\u043d\u0441\u043a") { foundMinsk = true; assert(v.value_SZ == "Belarus"); } if (v.name == "\u5317\u4eac") { foundBeijing = true; assert(v.value_SZ == "China"); } } assert(foundCologne); assert(foundMinsk); assert(foundBeijing); Key stateKey = unittestKey.createKey("StateCollection"); stateKey.setValue("Germany", ["D\u00fcsseldorf", "K\u00f6ln", "Hamburg"]); Value v = stateKey.getValue("Germany"); string[] actual = v.value_MULTI_SZ; assert(actual.length == 3); assert(actual[0] == "D\u00fcsseldorf"); assert(actual[1] == "K\u00f6ln"); assert(actual[2] == "Hamburg"); Key numberKey = unittestKey.createKey("Number"); numberKey.setValue("One", 1); Value one = numberKey.getValue("One"); assert(one.value_SZ == "1"); assert(one.value_DWORD == 1); unittestKey.deleteKey(numberKey.name); unittestKey.deleteKey(stateKey.name); unittestKey.deleteKey(cityKey.name); HKCU.deleteKey(unittestKeyName); auto e = collectException!RegistryException(HKCU.getKey("cDhmxsX9K23a8Uf869uB")); assert(e.msg.endsWith(" (error 2)")); } ldc-1.1.0-beta3-src/runtime/phobos/std/stream.d0000664000175000017500000026201012776215007017347 0ustar kaikai// Written in the D programming language /** * $(RED Deprecated: This module is considered out-dated and not up to Phobos' * current standards. It will be remove in October 2016.) * * Source: $(PHOBOSSRC std/_stream.d) * Macros: * WIKI = Phobos/StdStream */ /* * Copyright (c) 2001-2005 * Pavel "EvilOne" Minayev * with buffering and endian support added by Ben Hinkle * with buffered readLine performance improvements by Dave Fladebo * with opApply inspired by (and mostly copied from) Regan Heath * with bug fixes and MemoryStream/SliceStream enhancements by Derick Eddington * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Author makes no representations about * the suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. */ deprecated("It will be removed from Phobos in October 2016. If you still need it, go to https://github.com/DigitalMars/undeaD") module std.stream; // @@@DEPRECATED_2016-10@@@ import std.internal.cstring; /* Class structure: * InputStream interface for reading * OutputStream interface for writing * Stream abstract base of stream implementations * File an OS file stream * FilterStream a base-class for wrappers around another stream * BufferedStream a buffered stream wrapping another stream * BufferedFile a buffered File * EndianStream a wrapper stream for swapping byte order and BOMs * SliceStream a portion of another stream * MemoryStream a stream entirely stored in main memory * TArrayStream a stream wrapping an array-like buffer */ /// A base class for stream exceptions. class StreamException: Exception { /// Construct a StreamException with given error message. this(string msg) { super(msg); } } /// Thrown when unable to read data from Stream. class ReadException: StreamException { /// Construct a ReadException with given error message. this(string msg) { super(msg); } } /// Thrown when unable to write data to Stream. class WriteException: StreamException { /// Construct a WriteException with given error message. this(string msg) { super(msg); } } /// Thrown when unable to move Stream pointer. class SeekException: StreamException { /// Construct a SeekException with given error message. this(string msg) { super(msg); } } // seek whence... enum SeekPos { Set, Current, End } private { import std.conv; import std.algorithm; import std.ascii; import std.format; import std.system; // for Endian enumeration import std.utf; import core.bitop; // for bswap import core.vararg; import std.file; } /// InputStream is the interface for readable streams. interface InputStream { /*** * Read exactly size bytes into the buffer. * * Throws a ReadException if it is not correct. */ void readExact(void* buffer, size_t size); /*** * Read a block of data big enough to fill the given array buffer. * * Returns: the actual number of bytes read. Unfilled bytes are not modified. */ size_t read(ubyte[] buffer); /*** * Read a basic type or counted string. * * Throw a ReadException if it could not be read. * Outside of byte, ubyte, and char, the format is * implementation-specific and should not be used except as opposite actions * to write. */ void read(out byte x); void read(out ubyte x); /// ditto void read(out short x); /// ditto void read(out ushort x); /// ditto void read(out int x); /// ditto void read(out uint x); /// ditto void read(out long x); /// ditto void read(out ulong x); /// ditto void read(out float x); /// ditto void read(out double x); /// ditto void read(out real x); /// ditto void read(out ifloat x); /// ditto void read(out idouble x); /// ditto void read(out ireal x); /// ditto void read(out cfloat x); /// ditto void read(out cdouble x); /// ditto void read(out creal x); /// ditto void read(out char x); /// ditto void read(out wchar x); /// ditto void read(out dchar x); /// ditto // reads a string, written earlier by write() void read(out char[] s); /// ditto // reads a Unicode string, written earlier by write() void read(out wchar[] s); /// ditto /*** * Read a line that is terminated with some combination of carriage return and * line feed or end-of-file. * * The terminators are not included. The wchar version * is identical. The optional buffer parameter is filled (reallocating * it if necessary) and a slice of the result is returned. */ char[] readLine(); char[] readLine(char[] result); /// ditto wchar[] readLineW(); /// ditto wchar[] readLineW(wchar[] result); /// ditto /*** * Overload foreach statements to read the stream line by line and call the * supplied delegate with each line or with each line with line number. * * The string passed in line may be reused between calls to the delegate. * Line numbering starts at 1. * Breaking out of the foreach will leave the stream * position at the beginning of the next line to be read. * For example, to echo a file line-by-line with line numbers run: * ------------------------------------ * Stream file = new BufferedFile("sample.txt"); * foreach(ulong n, char[] line; file) * { * writefln("line %d: %s", n, line); * } * file.close(); * ------------------------------------ */ // iterate through the stream line-by-line int opApply(scope int delegate(ref char[] line) dg); int opApply(scope int delegate(ref ulong n, ref char[] line) dg); /// ditto int opApply(scope int delegate(ref wchar[] line) dg); /// ditto int opApply(scope int delegate(ref ulong n, ref wchar[] line) dg); /// ditto /// Read a string of the given length, /// throwing ReadException if there was a problem. char[] readString(size_t length); /*** * Read a string of the given length, throwing ReadException if there was a * problem. * * The file format is implementation-specific and should not be used * except as opposite actions to write. */ wchar[] readStringW(size_t length); /*** * Read and return the next character in the stream. * * This is the only method that will handle ungetc properly. * getcw's format is implementation-specific. * If EOF is reached then getc returns char.init and getcw returns wchar.init. */ char getc(); wchar getcw(); /// ditto /*** * Push a character back onto the stream. * * They will be returned in first-in last-out order from getc/getcw. * Only has effect on further calls to getc() and getcw(). */ char ungetc(char c); wchar ungetcw(wchar c); /// ditto /*** * Scan a string from the input using a similar form to C's scanf * and std.format. * * An argument of type string is interpreted as a format string. * All other arguments must be pointer types. * If a format string is not present a default will be supplied computed from * the base type of the pointer type. An argument of type string* is filled * (possibly with appending characters) and a slice of the result is assigned * back into the argument. For example the following readf statements * are equivalent: * -------------------------- * int x; * double y; * string s; * file.readf(&x, " hello ", &y, &s); * file.readf("%d hello %f %s", &x, &y, &s); * file.readf("%d hello %f", &x, &y, "%s", &s); * -------------------------- */ int vreadf(TypeInfo[] arguments, va_list args); int readf(...); /// ditto /// Retrieve the number of bytes available for immediate reading. @property size_t available(); /*** * Return whether the current file position is the same as the end of the * file. * * This does not require actually reading past the end, as with stdio. For * non-seekable streams this might only return true after attempting to read * past the end. */ @property bool eof(); @property bool isOpen(); /// Return true if the stream is currently open. } /// Interface for writable streams. interface OutputStream { /*** * Write exactly size bytes from buffer, or throw a WriteException if that * could not be done. */ void writeExact(const void* buffer, size_t size); /*** * Write as much of the buffer as possible, * returning the number of bytes written. */ size_t write(const(ubyte)[] buffer); /*** * Write a basic type. * * Outside of byte, ubyte, and char, the format is implementation-specific * and should only be used in conjunction with read. * Throw WriteException on error. */ void write(byte x); void write(ubyte x); /// ditto void write(short x); /// ditto void write(ushort x); /// ditto void write(int x); /// ditto void write(uint x); /// ditto void write(long x); /// ditto void write(ulong x); /// ditto void write(float x); /// ditto void write(double x); /// ditto void write(real x); /// ditto void write(ifloat x); /// ditto void write(idouble x); /// ditto void write(ireal x); /// ditto void write(cfloat x); /// ditto void write(cdouble x); /// ditto void write(creal x); /// ditto void write(char x); /// ditto void write(wchar x); /// ditto void write(dchar x); /// ditto /*** * Writes a string, together with its length. * * The format is implementation-specific * and should only be used in conjunction with read. * Throw WriteException on error. */ void write(const(char)[] s); void write(const(wchar)[] s); /// ditto /*** * Write a line of text, * appending the line with an operating-system-specific line ending. * * Throws WriteException on error. */ void writeLine(const(char)[] s); /*** * Write a line of text, * appending the line with an operating-system-specific line ending. * * The format is implementation-specific. * Throws WriteException on error. */ void writeLineW(const(wchar)[] s); /*** * Write a string of text. * * Throws WriteException if it could not be fully written. */ void writeString(const(char)[] s); /*** * Write a string of text. * * The format is implementation-specific. * Throws WriteException if it could not be fully written. */ void writeStringW(const(wchar)[] s); /*** * Print a formatted string into the stream using printf-style syntax, * returning the number of bytes written. */ size_t vprintf(const(char)[] format, va_list args); size_t printf(const(char)[] format, ...); /// ditto /*** * Print a formatted string into the stream using writef-style syntax. * References: std.format. * Returns: self to chain with other stream commands like flush. */ OutputStream writef(...); OutputStream writefln(...); /// ditto OutputStream writefx(TypeInfo[] arguments, va_list argptr, int newline = false); /// ditto void flush(); /// Flush pending output if appropriate. void close(); /// Close the stream, flushing output if appropriate. @property bool isOpen(); /// Return true if the stream is currently open. } /*** * Stream is the base abstract class from which the other stream classes derive. * * Stream's byte order is the format native to the computer. * * Reading: * These methods require that the readable flag be set. * Problems with reading result in a ReadException being thrown. * Stream implements the InputStream interface in addition to the * readBlock method. * * Writing: * These methods require that the writeable flag be set. Problems with writing * result in a WriteException being thrown. Stream implements the OutputStream * interface in addition to the following methods: * writeBlock * copyFrom * copyFrom * * Seeking: * These methods require that the seekable flag be set. * Problems with seeking result in a SeekException being thrown. * seek, seekSet, seekCur, seekEnd, position, size, toString, toHash */ // not really abstract, but its instances will do nothing useful class Stream : InputStream, OutputStream { private import std.string, std.digest.crc, core.stdc.stdlib, core.stdc.stdio; // stream abilities bool readable = false; /// Indicates whether this stream can be read from. bool writeable = false; /// Indicates whether this stream can be written to. bool seekable = false; /// Indicates whether this stream can be seeked within. protected bool isopen = true; /// Indicates whether this stream is open. protected bool readEOF = false; /** Indicates whether this stream is at eof * after the last read attempt. */ protected bool prevCr = false; /** For a non-seekable stream indicates that * the last readLine or readLineW ended on a * '\r' character. */ this() {} /*** * Read up to size bytes into the buffer and return the number of bytes * actually read. A return value of 0 indicates end-of-file. */ abstract size_t readBlock(void* buffer, size_t size); // reads block of data of specified size, // throws ReadException on error void readExact(void* buffer, size_t size) { for(;;) { if (!size) return; size_t readsize = readBlock(buffer, size); // return 0 on eof if (readsize == 0) break; buffer += readsize; size -= readsize; } if (size != 0) throw new ReadException("not enough data in stream"); } // reads block of data big enough to fill the given // array, returns actual number of bytes read size_t read(ubyte[] buffer) { return readBlock(buffer.ptr, buffer.length); } // read a single value of desired type, // throw ReadException on error void read(out byte x) { readExact(&x, x.sizeof); } void read(out ubyte x) { readExact(&x, x.sizeof); } void read(out short x) { readExact(&x, x.sizeof); } void read(out ushort x) { readExact(&x, x.sizeof); } void read(out int x) { readExact(&x, x.sizeof); } void read(out uint x) { readExact(&x, x.sizeof); } void read(out long x) { readExact(&x, x.sizeof); } void read(out ulong x) { readExact(&x, x.sizeof); } void read(out float x) { readExact(&x, x.sizeof); } void read(out double x) { readExact(&x, x.sizeof); } void read(out real x) { readExact(&x, x.sizeof); } void read(out ifloat x) { readExact(&x, x.sizeof); } void read(out idouble x) { readExact(&x, x.sizeof); } void read(out ireal x) { readExact(&x, x.sizeof); } void read(out cfloat x) { readExact(&x, x.sizeof); } void read(out cdouble x) { readExact(&x, x.sizeof); } void read(out creal x) { readExact(&x, x.sizeof); } void read(out char x) { readExact(&x, x.sizeof); } void read(out wchar x) { readExact(&x, x.sizeof); } void read(out dchar x) { readExact(&x, x.sizeof); } // reads a string, written earlier by write() void read(out char[] s) { size_t len; read(len); s = readString(len); } // reads a Unicode string, written earlier by write() void read(out wchar[] s) { size_t len; read(len); s = readStringW(len); } // reads a line, terminated by either CR, LF, CR/LF, or EOF char[] readLine() { return readLine(null); } // reads a line, terminated by either CR, LF, CR/LF, or EOF // reusing the memory in buffer if result will fit and otherwise // allocates a new string char[] readLine(char[] result) { size_t strlen = 0; char ch = getc(); while (readable) { switch (ch) { case '\r': if (seekable) { ch = getc(); if (ch != '\n') ungetc(ch); } else { prevCr = true; } goto case; case '\n': case char.init: result.length = strlen; return result; default: if (strlen < result.length) { result[strlen] = ch; } else { result ~= ch; } strlen++; } ch = getc(); } result.length = strlen; return result; } // reads a Unicode line, terminated by either CR, LF, CR/LF, // or EOF; pretty much the same as the above, working with // wchars rather than chars wchar[] readLineW() { return readLineW(null); } // reads a Unicode line, terminated by either CR, LF, CR/LF, // or EOF; // fills supplied buffer if line fits and otherwise allocates a new string. wchar[] readLineW(wchar[] result) { size_t strlen = 0; wchar c = getcw(); while (readable) { switch (c) { case '\r': if (seekable) { c = getcw(); if (c != '\n') ungetcw(c); } else { prevCr = true; } goto case; case '\n': case wchar.init: result.length = strlen; return result; default: if (strlen < result.length) { result[strlen] = c; } else { result ~= c; } strlen++; } c = getcw(); } result.length = strlen; return result; } // iterate through the stream line-by-line - due to Regan Heath int opApply(scope int delegate(ref char[] line) dg) { int res = 0; char[128] buf; while (!eof) { char[] line = readLine(buf); res = dg(line); if (res) break; } return res; } // iterate through the stream line-by-line with line count and string int opApply(scope int delegate(ref ulong n, ref char[] line) dg) { int res = 0; ulong n = 1; char[128] buf; while (!eof) { auto line = readLine(buf); res = dg(n,line); if (res) break; n++; } return res; } // iterate through the stream line-by-line with wchar[] int opApply(scope int delegate(ref wchar[] line) dg) { int res = 0; wchar[128] buf; while (!eof) { auto line = readLineW(buf); res = dg(line); if (res) break; } return res; } // iterate through the stream line-by-line with line count and wchar[] int opApply(scope int delegate(ref ulong n, ref wchar[] line) dg) { int res = 0; ulong n = 1; wchar[128] buf; while (!eof) { auto line = readLineW(buf); res = dg(n,line); if (res) break; n++; } return res; } // reads a string of given length, throws // ReadException on error char[] readString(size_t length) { char[] result = new char[length]; readExact(result.ptr, length); return result; } // reads a Unicode string of given length, throws // ReadException on error wchar[] readStringW(size_t length) { auto result = new wchar[length]; readExact(result.ptr, result.length * wchar.sizeof); return result; } // unget buffer private wchar[] unget; final bool ungetAvailable() { return unget.length > 1; } // reads and returns next character from the stream, // handles characters pushed back by ungetc() // returns char.init on eof. char getc() { char c; if (prevCr) { prevCr = false; c = getc(); if (c != '\n') return c; } if (unget.length > 1) { c = cast(char)unget[unget.length - 1]; unget.length = unget.length - 1; } else { readBlock(&c,1); } return c; } // reads and returns next Unicode character from the // stream, handles characters pushed back by ungetc() // returns wchar.init on eof. wchar getcw() { wchar c; if (prevCr) { prevCr = false; c = getcw(); if (c != '\n') return c; } if (unget.length > 1) { c = unget[unget.length - 1]; unget.length = unget.length - 1; } else { void* buf = &c; size_t n = readBlock(buf,2); if (n == 1 && readBlock(buf+1,1) == 0) throw new ReadException("not enough data in stream"); } return c; } // pushes back character c into the stream; only has // effect on further calls to getc() and getcw() char ungetc(char c) { if (c == c.init) return c; // first byte is a dummy so that we never set length to 0 if (unget.length == 0) unget.length = 1; unget ~= c; return c; } // pushes back Unicode character c into the stream; only // has effect on further calls to getc() and getcw() wchar ungetcw(wchar c) { if (c == c.init) return c; // first byte is a dummy so that we never set length to 0 if (unget.length == 0) unget.length = 1; unget ~= c; return c; } int vreadf(TypeInfo[] arguments, va_list args) { string fmt; int j = 0; int count = 0, i = 0; char c; bool firstCharacter = true; while ((j < arguments.length || i < fmt.length) && !eof) { if(firstCharacter) { c = getc(); firstCharacter = false; } if (fmt.length == 0 || i == fmt.length) { i = 0; if (arguments[j] is typeid(string) || arguments[j] is typeid(char[]) || arguments[j] is typeid(const(char)[])) { fmt = va_arg!(string)(args); j++; continue; } else if (arguments[j] is typeid(int*) || arguments[j] is typeid(byte*) || arguments[j] is typeid(short*) || arguments[j] is typeid(long*)) { fmt = "%d"; } else if (arguments[j] is typeid(uint*) || arguments[j] is typeid(ubyte*) || arguments[j] is typeid(ushort*) || arguments[j] is typeid(ulong*)) { fmt = "%d"; } else if (arguments[j] is typeid(float*) || arguments[j] is typeid(double*) || arguments[j] is typeid(real*)) { fmt = "%f"; } else if (arguments[j] is typeid(char[]*) || arguments[j] is typeid(wchar[]*) || arguments[j] is typeid(dchar[]*)) { fmt = "%s"; } else if (arguments[j] is typeid(char*)) { fmt = "%c"; } } if (fmt[i] == '%') { // a field i++; bool suppress = false; if (fmt[i] == '*') { // suppress assignment suppress = true; i++; } // read field width int width = 0; while (isDigit(fmt[i])) { width = width * 10 + (fmt[i] - '0'); i++; } if (width == 0) width = -1; // skip any modifier if present if (fmt[i] == 'h' || fmt[i] == 'l' || fmt[i] == 'L') i++; // check the typechar and act accordingly switch (fmt[i]) { case 'd': // decimal/hexadecimal/octal integer case 'D': case 'u': case 'U': case 'o': case 'O': case 'x': case 'X': case 'i': case 'I': { while (isWhite(c)) { c = getc(); count++; } bool neg = false; if (c == '-') { neg = true; c = getc(); count++; } else if (c == '+') { c = getc(); count++; } char ifmt = cast(char)(fmt[i] | 0x20); if (ifmt == 'i') { // undetermined base if (c == '0') { // octal or hex c = getc(); count++; if (c == 'x' || c == 'X') { // hex ifmt = 'x'; c = getc(); count++; } else { // octal ifmt = 'o'; } } else // decimal ifmt = 'd'; } long n = 0; switch (ifmt) { case 'd': // decimal case 'u': { while (isDigit(c) && width) { n = n * 10 + (c - '0'); width--; c = getc(); count++; } } break; case 'o': { // octal while (isOctalDigit(c) && width) { n = n * 8 + (c - '0'); width--; c = getc(); count++; } } break; case 'x': { // hexadecimal while (isHexDigit(c) && width) { n *= 0x10; if (isDigit(c)) n += c - '0'; else n += 0xA + (c | 0x20) - 'a'; width--; c = getc(); count++; } } break; default: assert(0); } if (neg) n = -n; if (arguments[j] is typeid(int*)) { int* p = va_arg!(int*)(args); *p = cast(int)n; } else if (arguments[j] is typeid(short*)) { short* p = va_arg!(short*)(args); *p = cast(short)n; } else if (arguments[j] is typeid(byte*)) { byte* p = va_arg!(byte*)(args); *p = cast(byte)n; } else if (arguments[j] is typeid(long*)) { long* p = va_arg!(long*)(args); *p = n; } else if (arguments[j] is typeid(uint*)) { uint* p = va_arg!(uint*)(args); *p = cast(uint)n; } else if (arguments[j] is typeid(ushort*)) { ushort* p = va_arg!(ushort*)(args); *p = cast(ushort)n; } else if (arguments[j] is typeid(ubyte*)) { ubyte* p = va_arg!(ubyte*)(args); *p = cast(ubyte)n; } else if (arguments[j] is typeid(ulong*)) { ulong* p = va_arg!(ulong*)(args); *p = cast(ulong)n; } j++; i++; } break; case 'f': // float case 'F': case 'e': case 'E': case 'g': case 'G': { while (isWhite(c)) { c = getc(); count++; } bool neg = false; if (c == '-') { neg = true; c = getc(); count++; } else if (c == '+') { c = getc(); count++; } real r = 0; while (isDigit(c) && width) { r = r * 10 + (c - '0'); width--; c = getc(); count++; } if (width && c == '.') { width--; c = getc(); count++; double frac = 1; while (isDigit(c) && width) { r = r * 10 + (c - '0'); frac *= 10; width--; c = getc(); count++; } r /= frac; } if (width && (c == 'e' || c == 'E')) { width--; c = getc(); count++; if (width) { bool expneg = false; if (c == '-') { expneg = true; width--; c = getc(); count++; } else if (c == '+') { width--; c = getc(); count++; } real exp = 0; while (isDigit(c) && width) { exp = exp * 10 + (c - '0'); width--; c = getc(); count++; } if (expneg) { while (exp--) r /= 10; } else { while (exp--) r *= 10; } } } if(width && (c == 'n' || c == 'N')) { width--; c = getc(); count++; if(width && (c == 'a' || c == 'A')) { width--; c = getc(); count++; if(width && (c == 'n' || c == 'N')) { width--; c = getc(); count++; r = real.nan; } } } if(width && (c == 'i' || c == 'I')) { width--; c = getc(); count++; if(width && (c == 'n' || c == 'N')) { width--; c = getc(); count++; if(width && (c == 'f' || c == 'F')) { width--; c = getc(); count++; r = real.infinity; } } } if (neg) r = -r; if (arguments[j] is typeid(float*)) { float* p = va_arg!(float*)(args); *p = r; } else if (arguments[j] is typeid(double*)) { double* p = va_arg!(double*)(args); *p = r; } else if (arguments[j] is typeid(real*)) { real* p = va_arg!(real*)(args); *p = r; } j++; i++; } break; case 's': { // string while (isWhite(c)) { c = getc(); count++; } char[] s; char[]* p; size_t strlen; if (arguments[j] is typeid(char[]*)) { p = va_arg!(char[]*)(args); s = *p; } while (!isWhite(c) && c != char.init) { if (strlen < s.length) { s[strlen] = c; } else { s ~= c; } strlen++; c = getc(); count++; } s = s[0 .. strlen]; if (arguments[j] is typeid(char[]*)) { *p = s; } else if (arguments[j] is typeid(char*)) { s ~= 0; auto q = va_arg!(char*)(args); q[0 .. s.length] = s[]; } else if (arguments[j] is typeid(wchar[]*)) { auto q = va_arg!(const(wchar)[]*)(args); *q = toUTF16(s); } else if (arguments[j] is typeid(dchar[]*)) { auto q = va_arg!(const(dchar)[]*)(args); *q = toUTF32(s); } j++; i++; } break; case 'c': { // character(s) char* s = va_arg!(char*)(args); if (width < 0) width = 1; else while (isWhite(c)) { c = getc(); count++; } while (width-- && !eof) { *(s++) = c; c = getc(); count++; } j++; i++; } break; case 'n': { // number of chars read so far int* p = va_arg!(int*)(args); *p = count; j++; i++; } break; default: // read character as is goto nws; } } else if (isWhite(fmt[i])) { // skip whitespace while (isWhite(c)) c = getc(); i++; } else { // read character as is nws: if (fmt[i] != c) break; c = getc(); i++; } } ungetc(c); return count; } int readf(...) { return vreadf(_arguments, _argptr); } // returns estimated number of bytes available for immediate reading @property size_t available() { return 0; } /*** * Write up to size bytes from buffer in the stream, returning the actual * number of bytes that were written. */ abstract size_t writeBlock(const void* buffer, size_t size); // writes block of data of specified size, // throws WriteException on error void writeExact(const void* buffer, size_t size) { const(void)* p = buffer; for(;;) { if (!size) return; size_t writesize = writeBlock(p, size); if (writesize == 0) break; p += writesize; size -= writesize; } if (size != 0) throw new WriteException("unable to write to stream"); } // writes the given array of bytes, returns // actual number of bytes written size_t write(const(ubyte)[] buffer) { return writeBlock(buffer.ptr, buffer.length); } // write a single value of desired type, // throw WriteException on error void write(byte x) { writeExact(&x, x.sizeof); } void write(ubyte x) { writeExact(&x, x.sizeof); } void write(short x) { writeExact(&x, x.sizeof); } void write(ushort x) { writeExact(&x, x.sizeof); } void write(int x) { writeExact(&x, x.sizeof); } void write(uint x) { writeExact(&x, x.sizeof); } void write(long x) { writeExact(&x, x.sizeof); } void write(ulong x) { writeExact(&x, x.sizeof); } void write(float x) { writeExact(&x, x.sizeof); } void write(double x) { writeExact(&x, x.sizeof); } void write(real x) { writeExact(&x, x.sizeof); } void write(ifloat x) { writeExact(&x, x.sizeof); } void write(idouble x) { writeExact(&x, x.sizeof); } void write(ireal x) { writeExact(&x, x.sizeof); } void write(cfloat x) { writeExact(&x, x.sizeof); } void write(cdouble x) { writeExact(&x, x.sizeof); } void write(creal x) { writeExact(&x, x.sizeof); } void write(char x) { writeExact(&x, x.sizeof); } void write(wchar x) { writeExact(&x, x.sizeof); } void write(dchar x) { writeExact(&x, x.sizeof); } // writes a string, together with its length void write(const(char)[] s) { write(s.length); writeString(s); } // writes a Unicode string, together with its length void write(const(wchar)[] s) { write(s.length); writeStringW(s); } // writes a line, throws WriteException on error void writeLine(const(char)[] s) { writeString(s); version (Windows) writeString("\r\n"); else version (Mac) writeString("\r"); else writeString("\n"); } // writes a Unicode line, throws WriteException on error void writeLineW(const(wchar)[] s) { writeStringW(s); version (Windows) writeStringW("\r\n"); else version (Mac) writeStringW("\r"); else writeStringW("\n"); } // writes a string, throws WriteException on error void writeString(const(char)[] s) { writeExact(s.ptr, s.length); } // writes a Unicode string, throws WriteException on error void writeStringW(const(wchar)[] s) { writeExact(s.ptr, s.length * wchar.sizeof); } // writes data to stream using vprintf() syntax, // returns number of bytes written size_t vprintf(const(char)[] format, va_list args) { // shamelessly stolen from OutBuffer, // by Walter's permission char[1024] buffer; char* p = buffer.ptr; // Can't use `tempCString()` here as it will result in compilation error: // "cannot mix core.std.stdlib.alloca() and exception handling". auto f = toStringz(format); size_t psize = buffer.length; size_t count; while (true) { version (Windows) { count = vsnprintf(p, psize, f, args); if (count != -1) break; psize *= 2; p = cast(char*) alloca(psize); } else version (Posix) { count = vsnprintf(p, psize, f, args); if (count == -1) psize *= 2; else if (count >= psize) psize = count + 1; else break; p = cast(char*) alloca(psize); } else throw new Exception("unsupported platform"); } writeString(p[0 .. count]); return count; } // writes data to stream using printf() syntax, // returns number of bytes written size_t printf(const(char)[] format, ...) { va_list ap; va_start(ap, format); auto result = vprintf(format, ap); va_end(ap); return result; } private void doFormatCallback(dchar c) { char[4] buf; auto b = std.utf.toUTF8(buf, c); writeString(b); } // writes data to stream using writef() syntax, OutputStream writef(...) { return writefx(_arguments,_argptr,0); } // writes data with trailing newline OutputStream writefln(...) { return writefx(_arguments,_argptr,1); } // writes data with optional trailing newline OutputStream writefx(TypeInfo[] arguments, va_list argptr, int newline=false) { doFormat(&doFormatCallback,arguments,argptr); if (newline) writeLine(""); return this; } /*** * Copies all data from s into this stream. * This may throw ReadException or WriteException on failure. * This restores the file position of s so that it is unchanged. */ void copyFrom(Stream s) { if (seekable) { ulong pos = s.position; s.position = 0; copyFrom(s, s.size); s.position = pos; } else { ubyte[128] buf; while (!s.eof) { size_t m = s.readBlock(buf.ptr, buf.length); writeExact(buf.ptr, m); } } } /*** * Copy a specified number of bytes from the given stream into this one. * This may throw ReadException or WriteException on failure. * Unlike the previous form, this doesn't restore the file position of s. */ void copyFrom(Stream s, ulong count) { ubyte[128] buf; while (count > 0) { size_t n = cast(size_t)(count 1) unget.length = 1; // keep at least 1 so that data ptr stays } // close the stream somehow; the default just flushes the buffer void close() { if (isopen) flush(); readEOF = prevCr = isopen = readable = writeable = seekable = false; } /*** * Read the entire stream and return it as a string. * If the stream is not seekable the contents from the current position to eof * is read and returned. */ override string toString() { if (!readable) return super.toString(); try { size_t pos; size_t rdlen; size_t blockSize; char[] result; if (seekable) { ulong orig_pos = position; scope(exit) position = orig_pos; position = 0; blockSize = cast(size_t)size; result = new char[blockSize]; while (blockSize > 0) { rdlen = readBlock(&result[pos], blockSize); pos += rdlen; blockSize -= rdlen; } } else { blockSize = 4096; result = new char[blockSize]; while ((rdlen = readBlock(&result[pos], blockSize)) > 0) { pos += rdlen; blockSize += rdlen; result.length = result.length + blockSize; } } return cast(string) result[0 .. pos]; } catch (Throwable) { return super.toString(); } } /*** * Get a hash of the stream by reading each byte and using it in a CRC-32 * checksum. */ override size_t toHash() @trusted { if (!readable || !seekable) return super.toHash(); try { ulong pos = position; scope(exit) position = pos; CRC32 crc; crc.start(); position = 0; ulong len = size; for (ulong i = 0; i < len; i++) { ubyte c; read(c); crc.put(c); } union resUnion { size_t hash; ubyte[4] crcVal; } resUnion res; res.crcVal = crc.finish(); return res.hash; } catch (Throwable) { return super.toHash(); } } // helper for checking that the stream is readable final protected void assertReadable() { if (!readable) throw new ReadException("Stream is not readable"); } // helper for checking that the stream is writeable final protected void assertWriteable() { if (!writeable) throw new WriteException("Stream is not writeable"); } // helper for checking that the stream is seekable final protected void assertSeekable() { if (!seekable) throw new SeekException("Stream is not seekable"); } unittest { // unit test for Issue 3363 import std.stdio; immutable fileName = std.file.deleteme ~ "-issue3363.txt"; auto w = std.stdio.File(fileName, "w"); scope (exit) remove(fileName.ptr); w.write("one two three"); w.close(); auto r = std.stdio.File(fileName, "r"); const(char)[] constChar; string str; char[] chars; r.readf("%s %s %s", &constChar, &str, &chars); assert (constChar == "one", constChar); assert (str == "two", str); assert (chars == "three", chars); } unittest { //unit tests for Issue 1668 void tryFloatRoundtrip(float x, string fmt = "", string pad = "") { auto s = new MemoryStream(); s.writef(fmt, x, pad); s.position = 0; float f; assert(s.readf(&f)); assert(x == f || (x != x && f != f)); //either equal or both NaN } tryFloatRoundtrip(1.0); tryFloatRoundtrip(1.0, "%f"); tryFloatRoundtrip(1.0, "", " "); tryFloatRoundtrip(1.0, "%f", " "); tryFloatRoundtrip(3.14); tryFloatRoundtrip(3.14, "%f"); tryFloatRoundtrip(3.14, "", " "); tryFloatRoundtrip(3.14, "%f", " "); float nan = float.nan; tryFloatRoundtrip(nan); tryFloatRoundtrip(nan, "%f"); tryFloatRoundtrip(nan, "", " "); tryFloatRoundtrip(nan, "%f", " "); float inf = 1.0/0.0; tryFloatRoundtrip(inf); tryFloatRoundtrip(inf, "%f"); tryFloatRoundtrip(inf, "", " "); tryFloatRoundtrip(inf, "%f", " "); tryFloatRoundtrip(-inf); tryFloatRoundtrip(-inf,"%f"); tryFloatRoundtrip(-inf, "", " "); tryFloatRoundtrip(-inf, "%f", " "); } } /*** * A base class for streams that wrap a source stream with additional * functionality. * * The method implementations forward read/write/seek calls to the * source stream. A FilterStream can change the position of the source stream * arbitrarily and may not keep the source stream state in sync with the * FilterStream, even upon flushing and closing the FilterStream. It is * recommended to not make any assumptions about the state of the source position * and read/write state after a FilterStream has acted upon it. Specifc subclasses * of FilterStream should document how they modify the source stream and if any * invariants hold true between the source and filter. */ class FilterStream : Stream { private Stream s; // source stream /// Property indicating when this stream closes to close the source stream as /// well. /// Defaults to true. bool nestClose = true; /// Construct a FilterStream for the given source. this(Stream source) { s = source; resetSource(); } // source getter/setter /*** * Get the current source stream. */ final Stream source(){return s;} /*** * Set the current source stream. * * Setting the source stream closes this stream before attaching the new * source. Attaching an open stream reopens this stream and resets the stream * state. */ void source(Stream s) { close(); this.s = s; resetSource(); } /*** * Indicates the source stream changed state and that this stream should reset * any readable, writeable, seekable, isopen and buffering flags. */ void resetSource() { if (s !is null) { readable = s.readable; writeable = s.writeable; seekable = s.seekable; isopen = s.isOpen; } else { readable = writeable = seekable = false; isopen = false; } readEOF = prevCr = false; } // read from source override size_t readBlock(void* buffer, size_t size) { size_t res = s.readBlock(buffer,size); readEOF = res == 0; return res; } // write to source override size_t writeBlock(const void* buffer, size_t size) { return s.writeBlock(buffer,size); } // close stream override void close() { if (isopen) { super.close(); if (nestClose) s.close(); } } // seek on source override ulong seek(long offset, SeekPos whence) { readEOF = false; return s.seek(offset,whence); } override @property size_t available() { return s.available; } override void flush() { super.flush(); s.flush(); } } /*** * This subclass is for buffering a source stream. * * A buffered stream must be * closed explicitly to ensure the final buffer content is written to the source * stream. The source stream position is changed according to the block size so * reading or writing to the BufferedStream may not change the source stream * position by the same amount. */ class BufferedStream : FilterStream { ubyte[] buffer; // buffer, if any size_t bufferCurPos; // current position in buffer size_t bufferLen; // amount of data in buffer bool bufferDirty = false; size_t bufferSourcePos; // position in buffer of source stream position ulong streamPos; // absolute position in source stream /* Example of relationship between fields: * * s ...01234567890123456789012EOF * buffer |-- --| * bufferCurPos | * bufferLen |-- --| * bufferSourcePos | * */ invariant() { assert(bufferSourcePos <= bufferLen); assert(bufferCurPos <= bufferLen); assert(bufferLen <= buffer.length); } enum size_t DefaultBufferSize = 8192; /*** * Create a buffered stream for the stream source with the buffer size * bufferSize. */ this(Stream source, size_t bufferSize = DefaultBufferSize) { super(source); if (bufferSize) buffer = new ubyte[bufferSize]; } override protected void resetSource() { super.resetSource(); streamPos = 0; bufferLen = bufferSourcePos = bufferCurPos = 0; bufferDirty = false; } // reads block of data of specified size using any buffered data // returns actual number of bytes read override size_t readBlock(void* result, size_t len) { if (len == 0) return 0; assertReadable(); ubyte* outbuf = cast(ubyte*)result; size_t readsize = 0; if (bufferCurPos + len < bufferLen) { // buffer has all the data so copy it outbuf[0 .. len] = buffer[bufferCurPos .. bufferCurPos+len]; bufferCurPos += len; readsize = len; goto ExitRead; } readsize = bufferLen - bufferCurPos; if (readsize > 0) { // buffer has some data so copy what is left outbuf[0 .. readsize] = buffer[bufferCurPos .. bufferLen]; outbuf += readsize; bufferCurPos += readsize; len -= readsize; } flush(); if (len >= buffer.length) { // buffer can't hold the data so fill output buffer directly size_t siz = super.readBlock(outbuf, len); readsize += siz; streamPos += siz; } else { // read a new block into buffer bufferLen = super.readBlock(buffer.ptr, buffer.length); if (bufferLen < len) len = bufferLen; outbuf[0 .. len] = buffer[0 .. len]; bufferSourcePos = bufferLen; streamPos += bufferLen; bufferCurPos = len; readsize += len; } ExitRead: return readsize; } // write block of data of specified size // returns actual number of bytes written override size_t writeBlock(const void* result, size_t len) { assertWriteable(); ubyte* buf = cast(ubyte*)result; size_t writesize = 0; if (bufferLen == 0) { // buffer is empty so fill it if possible if ((len < buffer.length) && (readable)) { // read in data if the buffer is currently empty bufferLen = s.readBlock(buffer.ptr, buffer.length); bufferSourcePos = bufferLen; streamPos += bufferLen; } else if (len >= buffer.length) { // buffer can't hold the data so write it directly and exit writesize = s.writeBlock(buf,len); streamPos += writesize; goto ExitWrite; } } if (bufferCurPos + len <= buffer.length) { // buffer has space for all the data so copy it and exit buffer[bufferCurPos .. bufferCurPos+len] = buf[0 .. len]; bufferCurPos += len; bufferLen = bufferCurPos > bufferLen ? bufferCurPos : bufferLen; writesize = len; bufferDirty = true; goto ExitWrite; } writesize = buffer.length - bufferCurPos; if (writesize > 0) { // buffer can take some data buffer[bufferCurPos .. buffer.length] = buf[0 .. writesize]; bufferCurPos = bufferLen = buffer.length; buf += writesize; len -= writesize; bufferDirty = true; } assert(bufferCurPos == buffer.length); assert(bufferLen == buffer.length); flush(); writesize += writeBlock(buf,len); ExitWrite: return writesize; } override ulong seek(long offset, SeekPos whence) { assertSeekable(); if ((whence != SeekPos.Current) || (offset + bufferCurPos < 0) || (offset + bufferCurPos >= bufferLen)) { flush(); streamPos = s.seek(offset,whence); } else { bufferCurPos += offset; } readEOF = false; return streamPos-bufferSourcePos+bufferCurPos; } // Buffered readLine - Dave Fladebo // reads a line, terminated by either CR, LF, CR/LF, or EOF // reusing the memory in buffer if result will fit, otherwise // will reallocate (using concatenation) template TreadLine(T) { T[] readLine(T[] inBuffer) { size_t lineSize = 0; bool haveCR = false; T c = '\0'; size_t idx = 0; ubyte* pc = cast(ubyte*)&c; L0: for(;;) { size_t start = bufferCurPos; L1: foreach(ubyte b; buffer[start .. bufferLen]) { bufferCurPos++; pc[idx] = b; if(idx < T.sizeof - 1) { idx++; continue L1; } else { idx = 0; } if(c == '\n' || haveCR) { if(haveCR && c != '\n') bufferCurPos--; break L0; } else { if(c == '\r') { haveCR = true; } else { if(lineSize < inBuffer.length) { inBuffer[lineSize] = c; } else { inBuffer ~= c; } lineSize++; } } } flush(); size_t res = super.readBlock(buffer.ptr, buffer.length); if(!res) break L0; // EOF bufferSourcePos = bufferLen = res; streamPos += res; } return inBuffer[0 .. lineSize]; } } // template TreadLine(T) override char[] readLine(char[] inBuffer) { if (ungetAvailable()) return super.readLine(inBuffer); else return TreadLine!(char).readLine(inBuffer); } alias readLine = Stream.readLine; override wchar[] readLineW(wchar[] inBuffer) { if (ungetAvailable()) return super.readLineW(inBuffer); else return TreadLine!(wchar).readLine(inBuffer); } alias readLineW = Stream.readLineW; override void flush() out { assert(bufferCurPos == 0); assert(bufferSourcePos == 0); assert(bufferLen == 0); } body { if (writeable && bufferDirty) { if (bufferSourcePos != 0 && seekable) { // move actual file pointer to front of buffer streamPos = s.seek(-bufferSourcePos, SeekPos.Current); } // write buffer out bufferSourcePos = s.writeBlock(buffer.ptr, bufferLen); if (bufferSourcePos != bufferLen) { throw new WriteException("Unable to write to stream"); } } super.flush(); long diff = cast(long)bufferCurPos-bufferSourcePos; if (diff != 0 && seekable) { // move actual file pointer to current position streamPos = s.seek(diff, SeekPos.Current); } // reset buffer data to be empty bufferSourcePos = bufferCurPos = bufferLen = 0; bufferDirty = false; } // returns true if end of stream is reached, false otherwise override @property bool eof() { if ((buffer.length == 0) || !readable) { return super.eof; } // some simple tests to avoid flushing if (ungetAvailable() || bufferCurPos != bufferLen) return false; if (bufferLen == buffer.length) flush(); size_t res = super.readBlock(&buffer[bufferLen],buffer.length-bufferLen); bufferSourcePos += res; bufferLen += res; streamPos += res; return readEOF; } // returns size of stream override @property ulong size() { if (bufferDirty) flush(); return s.size; } // returns estimated number of bytes available for immediate reading override @property size_t available() { return bufferLen - bufferCurPos; } } /// An exception for File errors. class StreamFileException: StreamException { /// Construct a StreamFileException with given error message. this(string msg) { super(msg); } } /// An exception for errors during File.open. class OpenException: StreamFileException { /// Construct an OpenFileException with given error message. this(string msg) { super(msg); } } /// Specifies the $(LREF File) access mode used when opening the file. enum FileMode { In = 1, /// Opens the file for reading. Out = 2, /// Opens the file for writing. OutNew = 6, /// Opens the file for writing, creates a new file if it doesn't exist. Append = 10 /// Opens the file for writing, appending new data to the end of the file. } version (Windows) { private import core.sys.windows.windows; extern (Windows) { void FlushFileBuffers(HANDLE hFile); DWORD GetFileType(HANDLE hFile); } } version (Posix) { private import core.sys.posix.fcntl; private import core.sys.posix.unistd; alias HANDLE = int; } /// This subclass is for unbuffered file system streams. class File: Stream { version (Windows) { private HANDLE hFile; } version (Posix) { private HANDLE hFile = -1; } this() { super(); version (Windows) { hFile = null; } version (Posix) { hFile = -1; } isopen = false; } // opens existing handle; use with care! this(HANDLE hFile, FileMode mode) { super(); this.hFile = hFile; readable = cast(bool)(mode & FileMode.In); writeable = cast(bool)(mode & FileMode.Out); version(Windows) { seekable = GetFileType(hFile) == 1; // FILE_TYPE_DISK } else { auto result = lseek(hFile, 0, 0); seekable = (result != ~0); } } /*** * Create the stream with no open file, an open file in read mode, or an open * file with explicit file mode. * mode, if given, is a combination of FileMode.In * (indicating a file that can be read) and FileMode.Out (indicating a file * that can be written). * Opening a file for reading that doesn't exist will error. * Opening a file for writing that doesn't exist will create the file. * The FileMode.OutNew mode will open the file for writing and reset the * length to zero. * The FileMode.Append mode will open the file for writing and move the * file position to the end of the file. */ this(string filename, FileMode mode = FileMode.In) { this(); open(filename, mode); } /*** * Open a file for the stream, in an identical manner to the constructors. * If an error occurs an OpenException is thrown. */ void open(string filename, FileMode mode = FileMode.In) { close(); int access, share, createMode; parseMode(mode, access, share, createMode); seekable = true; readable = cast(bool)(mode & FileMode.In); writeable = cast(bool)(mode & FileMode.Out); version (Windows) { hFile = CreateFileW(filename.tempCStringW(), access, share, null, createMode, 0, null); isopen = hFile != INVALID_HANDLE_VALUE; } version (Posix) { hFile = core.sys.posix.fcntl.open(filename.tempCString(), access | createMode, share); isopen = hFile != -1; } if (!isopen) throw new OpenException(cast(string) ("Cannot open or create file '" ~ filename ~ "'")); else if ((mode & FileMode.Append) == FileMode.Append) seekEnd(0); } private void parseMode(int mode, out int access, out int share, out int createMode) { version (Windows) { share |= FILE_SHARE_READ | FILE_SHARE_WRITE; if (mode & FileMode.In) { access |= GENERIC_READ; createMode = OPEN_EXISTING; } if (mode & FileMode.Out) { access |= GENERIC_WRITE; createMode = OPEN_ALWAYS; // will create if not present } if ((mode & FileMode.OutNew) == FileMode.OutNew) { createMode = CREATE_ALWAYS; // resets file } } version (Posix) { share = octal!666; if (mode & FileMode.In) { access = O_RDONLY; } if (mode & FileMode.Out) { createMode = O_CREAT; // will create if not present access = O_WRONLY; } if (access == (O_WRONLY | O_RDONLY)) { access = O_RDWR; } if ((mode & FileMode.OutNew) == FileMode.OutNew) { access |= O_TRUNC; // resets file } } } /// Create a file for writing. void create(string filename) { create(filename, FileMode.OutNew); } /// ditto void create(string filename, FileMode mode) { close(); open(filename, mode | FileMode.OutNew); } /// Close the current file if it is open; otherwise it does nothing. override void close() { if (isopen) { super.close(); if (hFile) { version (Windows) { CloseHandle(hFile); hFile = null; } else version (Posix) { core.sys.posix.unistd.close(hFile); hFile = -1; } } } } // destructor, closes file if still opened ~this() { close(); } version (Windows) { // returns size of stream override @property ulong size() { assertSeekable(); uint sizehi; uint sizelow = GetFileSize(hFile,&sizehi); return (cast(ulong)sizehi << 32) + sizelow; } } override size_t readBlock(void* buffer, size_t size) { assertReadable(); version (Windows) { auto dwSize = to!DWORD(size); ReadFile(hFile, buffer, dwSize, &dwSize, null); size = dwSize; } else version (Posix) { size = core.sys.posix.unistd.read(hFile, buffer, size); if (size == -1) size = 0; } readEOF = (size == 0); return size; } override size_t writeBlock(const void* buffer, size_t size) { assertWriteable(); version (Windows) { auto dwSize = to!DWORD(size); WriteFile(hFile, buffer, dwSize, &dwSize, null); size = dwSize; } else version (Posix) { size = core.sys.posix.unistd.write(hFile, buffer, size); if (size == -1) size = 0; } return size; } override ulong seek(long offset, SeekPos rel) { assertSeekable(); version (Windows) { int hi = cast(int)(offset>>32); uint low = SetFilePointer(hFile, cast(int)offset, &hi, rel); if ((low == INVALID_SET_FILE_POINTER) && (GetLastError() != 0)) throw new SeekException("unable to move file pointer"); ulong result = (cast(ulong)hi << 32) + low; } else version (Posix) { auto result = lseek(hFile, cast(off_t)offset, rel); if (result == cast(typeof(result))-1) throw new SeekException("unable to move file pointer"); } readEOF = false; return cast(ulong)result; } /*** * For a seekable file returns the difference of the size and position and * otherwise returns 0. */ override @property size_t available() { if (seekable) { ulong lavail = size - position; if (lavail > size_t.max) lavail = size_t.max; return cast(size_t)lavail; } return 0; } // OS-specific property, just in case somebody wants // to mess with underlying API HANDLE handle() { return hFile; } // run a few tests unittest { import std.internal.cstring : tempCString; import core.stdc.stdio : remove; File file = new File; int i = 666; auto stream_file = std.file.deleteme ~ "-stream.$$$"; file.create(stream_file); // should be ok to write assert(file.writeable); file.writeLine("Testing stream.d:"); file.writeString("Hello, world!"); file.write(i); // string#1 + string#2 + int should give exacly that version (Windows) assert(file.position == 19 + 13 + 4); version (Posix) assert(file.position == 18 + 13 + 4); // we must be at the end of file assert(file.eof); file.close(); // no operations are allowed when file is closed assert(!file.readable && !file.writeable && !file.seekable); file.open(stream_file); // should be ok to read assert(file.readable); assert(file.available == file.size); char[] line = file.readLine(); char[] exp = "Testing stream.d:".dup; assert(line[0] == 'T'); assert(line.length == exp.length); assert(!std.algorithm.cmp(line, "Testing stream.d:")); // jump over "Hello, " file.seek(7, SeekPos.Current); version (Windows) assert(file.position == 19 + 7); version (Posix) assert(file.position == 18 + 7); assert(!std.algorithm.cmp(file.readString(6), "world!")); i = 0; file.read(i); assert(i == 666); // string#1 + string#2 + int should give exacly that version (Windows) assert(file.position == 19 + 13 + 4); version (Posix) assert(file.position == 18 + 13 + 4); // we must be at the end of file assert(file.eof); file.close(); file.open(stream_file,FileMode.OutNew | FileMode.In); file.writeLine("Testing stream.d:"); file.writeLine("Another line"); file.writeLine(""); file.writeLine("That was blank"); file.position = 0; char[][] lines; foreach(char[] line; file) { lines ~= line.dup; } assert( lines.length == 4 ); assert( lines[0] == "Testing stream.d:"); assert( lines[1] == "Another line"); assert( lines[2] == ""); assert( lines[3] == "That was blank"); file.position = 0; lines = new char[][4]; foreach(ulong n, char[] line; file) { lines[cast(size_t)(n-1)] = line.dup; } assert( lines[0] == "Testing stream.d:"); assert( lines[1] == "Another line"); assert( lines[2] == ""); assert( lines[3] == "That was blank"); file.close(); remove(stream_file.tempCString()); } } /*** * This subclass is for buffered file system streams. * * It is a convenience class for wrapping a File in a BufferedStream. * A buffered stream must be closed explicitly to ensure the final buffer * content is written to the file. */ class BufferedFile: BufferedStream { /// opens file for reading this() { super(new File()); } /// opens file in requested mode and buffer size this(string filename, FileMode mode = FileMode.In, size_t bufferSize = DefaultBufferSize) { super(new File(filename,mode),bufferSize); } /// opens file for reading with requested buffer size this(File file, size_t bufferSize = DefaultBufferSize) { super(file,bufferSize); } /// opens existing handle; use with care! this(HANDLE hFile, FileMode mode, size_t buffersize = DefaultBufferSize) { super(new File(hFile,mode),buffersize); } /// opens file in requested mode void open(string filename, FileMode mode = FileMode.In) { File sf = cast(File)s; sf.open(filename,mode); resetSource(); } /// creates file in requested mode void create(string filename, FileMode mode = FileMode.OutNew) { File sf = cast(File)s; sf.create(filename,mode); resetSource(); } // run a few tests same as File unittest { import std.internal.cstring : tempCString; import core.stdc.stdio : remove; BufferedFile file = new BufferedFile; int i = 666; auto stream_file = std.file.deleteme ~ "-stream.$$$"; file.create(stream_file); // should be ok to write assert(file.writeable); file.writeLine("Testing stream.d:"); file.writeString("Hello, world!"); file.write(i); // string#1 + string#2 + int should give exacly that version (Windows) assert(file.position == 19 + 13 + 4); version (Posix) assert(file.position == 18 + 13 + 4); // we must be at the end of file assert(file.eof); long oldsize = cast(long)file.size; file.close(); // no operations are allowed when file is closed assert(!file.readable && !file.writeable && !file.seekable); file.open(stream_file); // should be ok to read assert(file.readable); // test getc/ungetc and size char c1 = file.getc(); file.ungetc(c1); assert( file.size == oldsize ); assert(!std.algorithm.cmp(file.readLine(), "Testing stream.d:")); // jump over "Hello, " file.seek(7, SeekPos.Current); version (Windows) assert(file.position == 19 + 7); version (Posix) assert(file.position == 18 + 7); assert(!std.algorithm.cmp(file.readString(6), "world!")); i = 0; file.read(i); assert(i == 666); // string#1 + string#2 + int should give exacly that version (Windows) assert(file.position == 19 + 13 + 4); version (Posix) assert(file.position == 18 + 13 + 4); // we must be at the end of file assert(file.eof); file.close(); remove(stream_file.tempCString()); } } /// UTF byte-order-mark signatures enum BOM { UTF8, /// UTF-8 UTF16LE, /// UTF-16 Little Endian UTF16BE, /// UTF-16 Big Endian UTF32LE, /// UTF-32 Little Endian UTF32BE, /// UTF-32 Big Endian } private enum int NBOMS = 5; immutable Endian[NBOMS] BOMEndian = [ std.system.endian, Endian.littleEndian, Endian.bigEndian, Endian.littleEndian, Endian.bigEndian ]; immutable ubyte[][NBOMS] ByteOrderMarks = [ [0xEF, 0xBB, 0xBF], [0xFF, 0xFE], [0xFE, 0xFF], [0xFF, 0xFE, 0x00, 0x00], [0x00, 0x00, 0xFE, 0xFF] ]; /*** * This subclass wraps a stream with big-endian or little-endian byte order * swapping. * * UTF Byte-Order-Mark (BOM) signatures can be read and deduced or * written. * Note that an EndianStream should not be used as the source of another * FilterStream since a FilterStream call the source with byte-oriented * read/write requests and the EndianStream will not perform any byte swapping. * The EndianStream reads and writes binary data (non-getc functions) in a * one-to-one * manner with the source stream so the source stream's position and state will be * kept in sync with the EndianStream if only non-getc functions are called. */ class EndianStream : FilterStream { Endian endian; /// Endianness property of the source stream. /*** * Create the endian stream for the source stream source with endianness end. * The default endianness is the native byte order. * The Endian type is defined * in the std.system module. */ this(Stream source, Endian end = std.system.endian) { super(source); endian = end; } /*** * Return -1 if no BOM and otherwise read the BOM and return it. * * If there is no BOM or if bytes beyond the BOM are read then the bytes read * are pushed back onto the ungetc buffer or ungetcw buffer. * Pass ungetCharSize == 2 to use * ungetcw instead of ungetc when no BOM is present. */ int readBOM(int ungetCharSize = 1) { ubyte[4] BOM_buffer; int n = 0; // the number of read bytes int result = -1; // the last match or -1 for (int i=0; i < NBOMS; ++i) { int j; immutable ubyte[] bom = ByteOrderMarks[i]; for (j=0; j < bom.length; ++j) { if (n <= j) { // have to read more if (eof) break; readExact(&BOM_buffer[n++],1); } if (BOM_buffer[j] != bom[j]) break; } if (j == bom.length) // found a match result = i; } ptrdiff_t m = 0; if (result != -1) { endian = BOMEndian[result]; // set stream endianness m = ByteOrderMarks[result].length; } if ((ungetCharSize == 1 && result == -1) || (result == BOM.UTF8)) { while (n-- > m) ungetc(BOM_buffer[n]); } else { // should eventually support unget for dchar as well if (n & 1) // make sure we have an even number of bytes readExact(&BOM_buffer[n++],1); while (n > m) { n -= 2; wchar cw = *(cast(wchar*)&BOM_buffer[n]); fixBO(&cw,2); ungetcw(cw); } } return result; } /*** * Correct the byte order of buffer to match native endianness. * size must be even. */ final void fixBO(const(void)* buffer, size_t size) { if (endian != std.system.endian) { ubyte* startb = cast(ubyte*)buffer; uint* start = cast(uint*)buffer; switch (size) { case 0: break; case 2: { ubyte x = *startb; *startb = *(startb+1); *(startb+1) = x; break; } case 4: { *start = bswap(*start); break; } default: { uint* end = cast(uint*)(buffer + size - uint.sizeof); while (start < end) { uint x = bswap(*start); *start = bswap(*end); *end = x; ++start; --end; } startb = cast(ubyte*)start; ubyte* endb = cast(ubyte*)end; auto len = uint.sizeof - (startb - endb); if (len > 0) fixBO(startb,len); } } } } /*** * Correct the byte order of the given buffer in blocks of the given size and * repeated the given number of times. * size must be even. */ final void fixBlockBO(void* buffer, uint size, size_t repeat) { while (repeat--) { fixBO(buffer,size); buffer += size; } } override void read(out byte x) { readExact(&x, x.sizeof); } override void read(out ubyte x) { readExact(&x, x.sizeof); } override void read(out short x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out ushort x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out int x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out uint x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out long x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out ulong x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out float x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out double x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out real x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out ifloat x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out idouble x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out ireal x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out cfloat x) { readExact(&x, x.sizeof); fixBlockBO(&x,float.sizeof,2); } override void read(out cdouble x) { readExact(&x, x.sizeof); fixBlockBO(&x,double.sizeof,2); } override void read(out creal x) { readExact(&x, x.sizeof); fixBlockBO(&x,real.sizeof,2); } override void read(out char x) { readExact(&x, x.sizeof); } override void read(out wchar x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override void read(out dchar x) { readExact(&x, x.sizeof); fixBO(&x,x.sizeof); } override wchar getcw() { wchar c; if (prevCr) { prevCr = false; c = getcw(); if (c != '\n') return c; } if (unget.length > 1) { c = unget[unget.length - 1]; unget.length = unget.length - 1; } else { void* buf = &c; size_t n = readBlock(buf,2); if (n == 1 && readBlock(buf+1,1) == 0) throw new ReadException("not enough data in stream"); fixBO(&c,c.sizeof); } return c; } override wchar[] readStringW(size_t length) { wchar[] result = new wchar[length]; readExact(result.ptr, length * wchar.sizeof); fixBlockBO(result.ptr, wchar.sizeof, length); return result; } /// Write the specified BOM b to the source stream. void writeBOM(BOM b) { immutable ubyte[] bom = ByteOrderMarks[b]; writeBlock(bom.ptr, bom.length); } override void write(byte x) { writeExact(&x, x.sizeof); } override void write(ubyte x) { writeExact(&x, x.sizeof); } override void write(short x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(ushort x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(int x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(uint x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(long x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(ulong x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(float x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(double x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(real x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(ifloat x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(idouble x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(ireal x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(cfloat x) { fixBlockBO(&x,float.sizeof,2); writeExact(&x, x.sizeof); } override void write(cdouble x) { fixBlockBO(&x,double.sizeof,2); writeExact(&x, x.sizeof); } override void write(creal x) { fixBlockBO(&x,real.sizeof,2); writeExact(&x, x.sizeof); } override void write(char x) { writeExact(&x, x.sizeof); } override void write(wchar x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void write(dchar x) { fixBO(&x,x.sizeof); writeExact(&x, x.sizeof); } override void writeStringW(const(wchar)[] str) { foreach(wchar cw;str) { fixBO(&cw,2); s.writeExact(&cw, 2); } } override @property bool eof() { return s.eof && !ungetAvailable(); } override @property ulong size() { return s.size; } unittest { MemoryStream m; m = new MemoryStream (); EndianStream em = new EndianStream(m,Endian.bigEndian); uint x = 0x11223344; em.write(x); assert( m.data[0] == 0x11 ); assert( m.data[1] == 0x22 ); assert( m.data[2] == 0x33 ); assert( m.data[3] == 0x44 ); em.position = 0; ushort x2 = 0x5566; em.write(x2); assert( m.data[0] == 0x55 ); assert( m.data[1] == 0x66 ); em.position = 0; static ubyte[12] x3 = [1,2,3,4,5,6,7,8,9,10,11,12]; em.fixBO(x3.ptr,12); if (std.system.endian == Endian.littleEndian) { assert( x3[0] == 12 ); assert( x3[1] == 11 ); assert( x3[2] == 10 ); assert( x3[4] == 8 ); assert( x3[5] == 7 ); assert( x3[6] == 6 ); assert( x3[8] == 4 ); assert( x3[9] == 3 ); assert( x3[10] == 2 ); assert( x3[11] == 1 ); } em.endian = Endian.littleEndian; em.write(x); assert( m.data[0] == 0x44 ); assert( m.data[1] == 0x33 ); assert( m.data[2] == 0x22 ); assert( m.data[3] == 0x11 ); em.position = 0; em.write(x2); assert( m.data[0] == 0x66 ); assert( m.data[1] == 0x55 ); em.position = 0; em.fixBO(x3.ptr,12); if (std.system.endian == Endian.bigEndian) { assert( x3[0] == 12 ); assert( x3[1] == 11 ); assert( x3[2] == 10 ); assert( x3[4] == 8 ); assert( x3[5] == 7 ); assert( x3[6] == 6 ); assert( x3[8] == 4 ); assert( x3[9] == 3 ); assert( x3[10] == 2 ); assert( x3[11] == 1 ); } em.writeBOM(BOM.UTF8); assert( m.position == 3 ); assert( m.data[0] == 0xEF ); assert( m.data[1] == 0xBB ); assert( m.data[2] == 0xBF ); em.writeString ("Hello, world"); em.position = 0; assert( m.position == 0 ); assert( em.readBOM() == BOM.UTF8 ); assert( m.position == 3 ); assert( em.getc() == 'H' ); em.position = 0; em.writeBOM(BOM.UTF16BE); assert( m.data[0] == 0xFE ); assert( m.data[1] == 0xFF ); em.position = 0; em.writeBOM(BOM.UTF16LE); assert( m.data[0] == 0xFF ); assert( m.data[1] == 0xFE ); em.position = 0; em.writeString ("Hello, world"); em.position = 0; assert( em.readBOM() == -1 ); assert( em.getc() == 'H' ); assert( em.getc() == 'e' ); assert( em.getc() == 'l' ); assert( em.getc() == 'l' ); em.position = 0; } } /*** * Parameterized subclass that wraps an array-like buffer with a stream * interface. * * The type Buffer must support the length property, opIndex and opSlice. * Compile in release mode when directly instantiating a TArrayStream to avoid * link errors. */ class TArrayStream(Buffer): Stream { Buffer buf; // current data ulong len; // current data length ulong cur; // current file position /// Create the stream for the the buffer buf. Non-copying. this(Buffer buf) { super (); this.buf = buf; this.len = buf.length; readable = writeable = seekable = true; } // ensure subclasses don't violate this invariant() { assert(len <= buf.length); assert(cur <= len); } override size_t readBlock(void* buffer, size_t size) { assertReadable(); ubyte* cbuf = cast(ubyte*) buffer; if (len - cur < size) size = cast(size_t)(len - cur); ubyte[] ubuf = cast(ubyte[])buf[cast(size_t)cur .. cast(size_t)(cur + size)]; cbuf[0 .. size] = ubuf[]; cur += size; return size; } override size_t writeBlock(const void* buffer, size_t size) { assertWriteable(); ubyte* cbuf = cast(ubyte*) buffer; ulong blen = buf.length; if (cur + size > blen) size = cast(size_t)(blen - cur); ubyte[] ubuf = cast(ubyte[])buf[cast(size_t)cur .. cast(size_t)(cur + size)]; ubuf[] = cbuf[0 .. size]; cur += size; if (cur > len) len = cur; return size; } override ulong seek(long offset, SeekPos rel) { assertSeekable(); long scur; // signed to saturate to 0 properly switch (rel) { case SeekPos.Set: scur = offset; break; case SeekPos.Current: scur = cast(long)(cur + offset); break; case SeekPos.End: scur = cast(long)(len + offset); break; default: assert(0); } if (scur < 0) cur = 0; else if (scur > len) cur = len; else cur = cast(ulong)scur; return cur; } override @property size_t available () { return cast(size_t)(len - cur); } /// Get the current memory data in total. @property ubyte[] data() { if (len > size_t.max) throw new StreamException("Stream too big"); const(void)[] res = buf[0 .. cast(size_t)len]; return cast(ubyte[])res; } override string toString() { // assume data is UTF8 return to!(string)(cast(char[])data); } } /* Test the TArrayStream */ unittest { char[100] buf; TArrayStream!(char[]) m; m = new TArrayStream!(char[]) (buf); assert (m.isOpen); m.writeString ("Hello, world"); assert (m.position == 12); assert (m.available == 88); assert (m.seekSet (0) == 0); assert (m.available == 100); assert (m.seekCur (4) == 4); assert (m.available == 96); assert (m.seekEnd (-8) == 92); assert (m.available == 8); assert (m.size == 100); assert (m.seekSet (4) == 4); assert (m.readString (4) == "o, w"); m.writeString ("ie"); assert (buf[0..12] == "Hello, wield"); assert (m.position == 10); assert (m.available == 90); assert (m.size == 100); m.seekSet (0); assert (m.printf ("Answer is %d", 42) == 12); assert (buf[0..12] == "Answer is 42"); } /// This subclass reads and constructs an array of bytes in memory. class MemoryStream: TArrayStream!(ubyte[]) { /// Create the output buffer and setup for reading, writing, and seeking. // clear to an empty buffer. this() { this(cast(ubyte[]) null); } /*** * Create the output buffer and setup for reading, writing, and seeking. * Load it with specific input data. */ this(ubyte[] buf) { super (buf); } this(byte[] buf) { this(cast(ubyte[]) buf); } /// ditto this(char[] buf) { this(cast(ubyte[]) buf); } /// ditto /// Ensure the stream can write count extra bytes from cursor position without an allocation. void reserve(size_t count) { if (cur + count > buf.length) buf.length = cast(uint)((cur + count) * 2); } override size_t writeBlock(const void* buffer, size_t size) { reserve(size); return super.writeBlock(buffer,size); } unittest { MemoryStream m; m = new MemoryStream (); assert (m.isOpen); m.writeString ("Hello, world"); assert (m.position == 12); assert (m.seekSet (0) == 0); assert (m.available == 12); assert (m.seekCur (4) == 4); assert (m.available == 8); assert (m.seekEnd (-8) == 4); assert (m.available == 8); assert (m.size == 12); assert (m.readString (4) == "o, w"); m.writeString ("ie"); assert (cast(char[]) m.data == "Hello, wield"); m.seekEnd (0); m.writeString ("Foo"); assert (m.position == 15); assert (m.available == 0); m.writeString ("Foo foo foo foo foo foo foo"); assert (m.position == 42); m.position = 0; assert (m.available == 42); m.writef("%d %d %s",100,345,"hello"); auto str = m.toString(); assert (str[0..13] == "100 345 hello", str[0 .. 13]); assert (m.available == 29); assert (m.position == 13); MemoryStream m2; m.position = 3; m2 = new MemoryStream (); m2.writeString("before"); m2.copyFrom(m,10); str = m2.toString(); assert (str[0..16] == "before 345 hello"); m2.position = 3; m2.copyFrom(m); auto str2 = m.toString(); str = m2.toString(); assert (str == ("bef" ~ str2)); } } import std.mmfile; /*** * This subclass wraps a memory-mapped file with the stream API. * See std.mmfile module. */ class MmFileStream : TArrayStream!(MmFile) { /// Create stream wrapper for file. this(MmFile file) { super (file); MmFile.Mode mode = file.mode(); writeable = mode > MmFile.Mode.read; } override void flush() { if (isopen) { super.flush(); buf.flush(); } } override void close() { if (isopen) { super.close(); delete buf; buf = null; } } } unittest { auto test_file = std.file.deleteme ~ "-testing.txt"; MmFile mf = new MmFile(test_file,MmFile.Mode.readWriteNew,100,null); MmFileStream m; m = new MmFileStream (mf); m.writeString ("Hello, world"); assert (m.position == 12); assert (m.seekSet (0) == 0); assert (m.seekCur (4) == 4); assert (m.seekEnd (-8) == 92); assert (m.size == 100); assert (m.seekSet (4)); assert (m.readString (4) == "o, w"); m.writeString ("ie"); ubyte[] dd = m.data; assert ((cast(char[]) dd)[0 .. 12] == "Hello, wield"); m.position = 12; m.writeString ("Foo"); assert (m.position == 15); m.writeString ("Foo foo foo foo foo foo foo"); assert (m.position == 42); m.close(); mf = new MmFile(test_file); m = new MmFileStream (mf); assert (!m.writeable); char[] str = m.readString(12); assert (str == "Hello, wield"); m.close(); std.file.remove(test_file); } /*** * This subclass slices off a portion of another stream, making seeking relative * to the boundaries of the slice. * * It could be used to section a large file into a * set of smaller files, such as with tar archives. Reading and writing a * SliceStream does not modify the position of the source stream if it is * seekable. */ class SliceStream : FilterStream { private { ulong pos; // our position relative to low ulong low; // low stream offset. ulong high; // high stream offset. bool bounded; // upper-bounded by high. } /*** * Indicate both the source stream to use for reading from and the low part of * the slice. * * The high part of the slice is dependent upon the end of the source * stream, so that if you write beyond the end it resizes the stream normally. */ this (Stream s, ulong low) in { assert (low <= s.size); } body { super(s); this.low = low; this.high = 0; this.bounded = false; } /*** * Indicate the high index as well. * * Attempting to read or write past the high * index results in the end being clipped off. */ this (Stream s, ulong low, ulong high) in { assert (low <= high); assert (high <= s.size); } body { super(s); this.low = low; this.high = high; this.bounded = true; } invariant() { if (bounded) assert (pos <= high - low); else // size() does not appear to be const, though it should be assert (pos <= (cast()s).size - low); } override size_t readBlock (void *buffer, size_t size) { assertReadable(); if (bounded && size > high - low - pos) size = cast(size_t)(high - low - pos); ulong bp = s.position; if (seekable) s.position = low + pos; size_t ret = super.readBlock(buffer, size); if (seekable) { pos = s.position - low; s.position = bp; } return ret; } override size_t writeBlock (const void *buffer, size_t size) { assertWriteable(); if (bounded && size > high - low - pos) size = cast(size_t)(high - low - pos); ulong bp = s.position; if (seekable) s.position = low + pos; size_t ret = s.writeBlock(buffer, size); if (seekable) { pos = s.position - low; s.position = bp; } return ret; } override ulong seek(long offset, SeekPos rel) { assertSeekable(); long spos; switch (rel) { case SeekPos.Set: spos = offset; break; case SeekPos.Current: spos = cast(long)(pos + offset); break; case SeekPos.End: if (bounded) spos = cast(long)(high - low + offset); else spos = cast(long)(s.size - low + offset); break; default: assert(0); } if (spos < 0) pos = 0; else if (bounded && spos > high - low) pos = high - low; else if (!bounded && spos > s.size - low) pos = s.size - low; else pos = cast(ulong)spos; readEOF = false; return pos; } override @property size_t available() { size_t res = s.available; ulong bp = s.position; if (bp <= pos+low && pos+low <= bp+res) { if (!bounded || bp+res <= high) return cast(size_t)(bp + res - pos - low); else if (high <= bp+res) return cast(size_t)(high - pos - low); } return 0; } unittest { MemoryStream m; SliceStream s; m = new MemoryStream ((cast(char[])"Hello, world").dup); s = new SliceStream (m, 4, 8); assert (s.size == 4); assert (m.position == 0); assert (s.position == 0); assert (m.available == 12); assert (s.available == 4); assert (s.writeBlock (cast(char *) "Vroom", 5) == 4); assert (m.position == 0); assert (s.position == 4); assert (m.available == 12); assert (s.available == 0); assert (s.seekEnd (-2) == 2); assert (s.available == 2); assert (s.seekEnd (2) == 4); assert (s.available == 0); assert (m.position == 0); assert (m.available == 12); m.seekEnd(0); m.writeString("\nBlaho"); assert (m.position == 18); assert (m.available == 0); assert (s.position == 4); assert (s.available == 0); s = new SliceStream (m, 4); assert (s.size == 14); assert (s.toString () == "Vrooorld\nBlaho"); s.seekEnd (0); assert (s.available == 0); s.writeString (", etcetera."); assert (s.position == 25); assert (s.seekSet (0) == 0); assert (s.size == 25); assert (m.position == 18); assert (m.size == 29); assert (m.toString() == "HellVrooorld\nBlaho, etcetera."); } } ldc-1.1.0-beta3-src/runtime/phobos/std/concurrencybase.d0000664000175000017500000000072612776215007021245 0ustar kaikai// Written in the D programming language. /** * The only purpose of this module is to do the static construction for * std.concurrency, to eliminate cyclic construction errors. * * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Source: $(PHOBOSSRC std/_concurrencybase.d) */ module std.concurrencybase; import core.sync.mutex; extern(C) void std_concurrency_static_this(); shared static this() { std_concurrency_static_this(); } ldc-1.1.0-beta3-src/runtime/phobos/std/stdiobase.d0000664000175000017500000000135712776215007020036 0ustar kaikai// Written in the D programming language. /** * The only purpose of this module is to do the static construction for * std.stdio, to eliminate cyclic construction errors. * * Copyright: Copyright Andrei Alexandrescu 2008 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB erdani.org, Andrei Alexandrescu) * Source: $(PHOBOSSRC std/_stdiobase.d) */ /* Copyright Andrei Alexandrescu 2008 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.stdiobase; extern(C) void std_stdio_static_this(); shared static this() { std_stdio_static_this(); } ldc-1.1.0-beta3-src/runtime/phobos/std/compiler.d0000664000175000017500000000365212776215007017673 0ustar kaikai// Written in the D programming language. /** * Identify the compiler used and its various features. * * Macros: * WIKI = Phobos/StdCompiler * * Copyright: Copyright Digital Mars 2000 - 2011. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright), Alex Rønne Petersen * Source: $(PHOBOSSRC std/_compiler.d) */ /* Copyright Digital Mars 2000 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.compiler; immutable { /// Vendor specific string naming the compiler, for example: "Digital Mars D". string name = __VENDOR__; /// Master list of D compiler vendors. enum Vendor { unknown = 0, /// Compiler vendor could not be detected digitalMars = 1, /// Digital Mars D (DMD) gnu = 2, /// GNU D Compiler (GDC) llvm = 3, /// LLVM D Compiler (LDC) dotNET = 4, /// D.NET sdc = 5, /// Stupid D Compiler (SDC) } /// Which vendor produced this compiler. version(StdDdoc) Vendor vendor; else version(DigitalMars) Vendor vendor = Vendor.digitalMars; else version(GNU) Vendor vendor = Vendor.gnu; else version(LDC) Vendor vendor = Vendor.llvm; else version(D_NET) Vendor vendor = Vendor.dotNET; else version(SDC) Vendor vendor = Vendor.sdc; else Vendor vendor = Vendor.unknown; /** * The vendor specific version number, as in * version_major.version_minor */ uint version_major = __VERSION__ / 1000; uint version_minor = __VERSION__ % 1000; /// ditto /** * The version of the D Programming Language Specification * supported by the compiler. */ uint D_major = 2; uint D_minor = 0; } ldc-1.1.0-beta3-src/runtime/phobos/std/functional.d0000664000175000017500000012156612776215007020230 0ustar kaikai// Written in the D programming language. /** Functions that manipulate other functions. This module provides functions for compile time function composition. These functions are helpful when constructing predicates for the algorithms in $(LINK2 std_algorithm.html, std.algorithm) or $(LINK2 std_range.html, std.range). $(BOOKTABLE , $(TR $(TH Function Name) $(TH Description) ) $(TR $(TD $(D $(LREF adjoin))) $(TD Joins a couple of functions into one that executes the original functions independently and returns a tuple with all the results. )) $(TR $(TD $(D $(LREF compose)), $(D $(LREF pipe))) $(TD Join a couple of functions into one that executes the original functions one after the other, using one function's result for the next function's argument. )) $(TR $(TD $(D $(LREF forward))) $(TD Forwards function arguments while saving ref-ness. )) $(TR $(TD $(D $(LREF lessThan)), $(D $(LREF greaterThan)), $(D $(LREF equalTo))) $(TD Ready-made predicate functions to compare two values. )) $(TR $(TD $(D $(LREF memoize))) $(TD Creates a function that caches its result for fast re-evalation. )) $(TR $(TD $(D $(LREF not))) $(TD Creates a function that negates another. )) $(TR $(TD $(D $(LREF partial))) $(TD Creates a function that binds the first argument of a given function to a given value. )) $(TR $(TD $(D $(LREF reverseArgs)), $(D $(LREF binaryReverseArgs))) $(TD Predicate that reverses the order of its arguments. )) $(TR $(TD $(D $(LREF toDelegate))) $(TD Converts a callable to a delegate. )) $(TR $(TD $(D $(LREF unaryFun)), $(D $(LREF binaryFun))) $(TD Create a unary or binary function from a string. Most often used when defining algorithms on ranges. )) ) Macros: WIKI = Phobos/StdFunctional Copyright: Copyright Andrei Alexandrescu 2008 - 2009. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.org, Andrei Alexandrescu) Source: $(PHOBOSSRC std/_functional.d) */ /* Copyright Andrei Alexandrescu 2008 - 2009. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.functional; import std.meta, std.traits; private template needOpCallAlias(alias fun) { /* Determine whether or not unaryFun and binaryFun need to alias to fun or * fun.opCall. Basically, fun is a function object if fun(...) compiles. We * want is(unaryFun!fun) (resp., is(binaryFun!fun)) to be true if fun is * any function object. There are 4 possible cases: * * 1) fun is the type of a function object with static opCall; * 2) fun is an instance of a function object with static opCall; * 3) fun is the type of a function object with non-static opCall; * 4) fun is an instance of a function object with non-static opCall. * * In case (1), is(unaryFun!fun) should compile, but does not if unaryFun * aliases itself to fun, because typeof(fun) is an error when fun itself * is a type. So it must be aliased to fun.opCall instead. All other cases * should be aliased to fun directly. */ static if (is(typeof(fun.opCall) == function)) { import std.traits : Parameters; enum needOpCallAlias = !is(typeof(fun)) && __traits(compiles, () { return fun(Parameters!fun.init); }); } else enum needOpCallAlias = false; } /** Transforms a string representing an expression into a unary function. The string must either use symbol name $(D a) as the parameter or provide the symbol via the $(D parmName) argument. If $(D fun) is not a string, $(D unaryFun) aliases itself away to $(D fun). */ template unaryFun(alias fun, string parmName = "a") { static if (is(typeof(fun) : string)) { static if (!fun._ctfeMatchUnary(parmName)) { import std.traits, std.typecons, std.meta; import std.algorithm, std.conv, std.exception, std.math, std.range, std.string; } auto unaryFun(ElementType)(auto ref ElementType __a) { mixin("alias " ~ parmName ~ " = __a ;"); return mixin(fun); } } else static if (needOpCallAlias!fun) { // Issue 9906 alias unaryFun = fun.opCall; } else { alias unaryFun = fun; } } /// unittest { // Strings are compiled into functions: alias isEven = unaryFun!("(a & 1) == 0"); assert(isEven(2) && !isEven(1)); } unittest { static int f1(int a) { return a + 1; } static assert(is(typeof(unaryFun!(f1)(1)) == int)); assert(unaryFun!(f1)(41) == 42); int f2(int a) { return a + 1; } static assert(is(typeof(unaryFun!(f2)(1)) == int)); assert(unaryFun!(f2)(41) == 42); assert(unaryFun!("a + 1")(41) == 42); //assert(unaryFun!("return a + 1;")(41) == 42); int num = 41; assert(unaryFun!"a + 1"(num) == 42); // Issue 9906 struct Seen { static bool opCall(int n) { return true; } } static assert(needOpCallAlias!Seen); static assert(is(typeof(unaryFun!Seen(1)))); assert(unaryFun!Seen(1)); Seen s; static assert(!needOpCallAlias!s); static assert(is(typeof(unaryFun!s(1)))); assert(unaryFun!s(1)); struct FuncObj { bool opCall(int n) { return true; } } FuncObj fo; static assert(!needOpCallAlias!fo); static assert(is(typeof(unaryFun!fo))); assert(unaryFun!fo(1)); // Function object with non-static opCall can only be called with an // instance, not with merely the type. static assert(!is(typeof(unaryFun!FuncObj))); } /** Transforms a string representing an expression into a binary function. The string must either use symbol names $(D a) and $(D b) as the parameters or provide the symbols via the $(D parm1Name) and $(D parm2Name) arguments. If $(D fun) is not a string, $(D binaryFun) aliases itself away to $(D fun). */ template binaryFun(alias fun, string parm1Name = "a", string parm2Name = "b") { static if (is(typeof(fun) : string)) { static if (!fun._ctfeMatchBinary(parm1Name, parm2Name)) { import std.traits, std.typecons, std.meta; import std.algorithm, std.conv, std.exception, std.math, std.range, std.string; } auto binaryFun(ElementType1, ElementType2) (auto ref ElementType1 __a, auto ref ElementType2 __b) { mixin("alias "~parm1Name~" = __a ;"); mixin("alias "~parm2Name~" = __b ;"); return mixin(fun); } } else static if (needOpCallAlias!fun) { // Issue 9906 alias binaryFun = fun.opCall; } else { alias binaryFun = fun; } } /// unittest { alias less = binaryFun!("a < b"); assert(less(1, 2) && !less(2, 1)); alias greater = binaryFun!("a > b"); assert(!greater("1", "2") && greater("2", "1")); } unittest { static int f1(int a, string b) { return a + 1; } static assert(is(typeof(binaryFun!(f1)(1, "2")) == int)); assert(binaryFun!(f1)(41, "a") == 42); string f2(int a, string b) { return b ~ "2"; } static assert(is(typeof(binaryFun!(f2)(1, "1")) == string)); assert(binaryFun!(f2)(1, "4") == "42"); assert(binaryFun!("a + b")(41, 1) == 42); //@@BUG //assert(binaryFun!("return a + b;")(41, 1) == 42); // Issue 9906 struct Seen { static bool opCall(int x, int y) { return true; } } static assert(is(typeof(binaryFun!Seen))); assert(binaryFun!Seen(1,1)); struct FuncObj { bool opCall(int x, int y) { return true; } } FuncObj fo; static assert(!needOpCallAlias!fo); static assert(is(typeof(binaryFun!fo))); assert(unaryFun!fo(1,1)); // Function object with non-static opCall can only be called with an // instance, not with merely the type. static assert(!is(typeof(binaryFun!FuncObj))); } // skip all ASCII chars except a..z, A..Z, 0..9, '_' and '.'. private uint _ctfeSkipOp(ref string op) { if (!__ctfe) assert(false); import std.ascii : isASCII, isAlphaNum; immutable oldLength = op.length; while (op.length) { immutable front = op[0]; if(front.isASCII() && !(front.isAlphaNum() || front == '_' || front == '.')) op = op[1..$]; else break; } return oldLength != op.length; } // skip all digits private uint _ctfeSkipInteger(ref string op) { if (!__ctfe) assert(false); import std.ascii : isDigit; immutable oldLength = op.length; while (op.length) { immutable front = op[0]; if(front.isDigit()) op = op[1..$]; else break; } return oldLength != op.length; } // skip name private uint _ctfeSkipName(ref string op, string name) { if (!__ctfe) assert(false); if (op.length >= name.length && op[0..name.length] == name) { op = op[name.length..$]; return 1; } return 0; } // returns 1 if $(D fun) is trivial unary function private uint _ctfeMatchUnary(string fun, string name) { if (!__ctfe) assert(false); import std.stdio; fun._ctfeSkipOp(); for (;;) { immutable h = fun._ctfeSkipName(name) + fun._ctfeSkipInteger(); if (h == 0) { fun._ctfeSkipOp(); break; } else if (h == 1) { if(!fun._ctfeSkipOp()) break; } else return 0; } return fun.length == 0; } unittest { static assert(!_ctfeMatchUnary("sqrt(ё)", "ё")); static assert(!_ctfeMatchUnary("ё.sqrt", "ё")); static assert(!_ctfeMatchUnary(".ё+ё", "ё")); static assert(!_ctfeMatchUnary("_ё+ё", "ё")); static assert(!_ctfeMatchUnary("ёё", "ё")); static assert(_ctfeMatchUnary("a+a", "a")); static assert(_ctfeMatchUnary("a + 10", "a")); static assert(_ctfeMatchUnary("4 == a", "a")); static assert(_ctfeMatchUnary("2==a", "a")); static assert(_ctfeMatchUnary("1 != a", "a")); static assert(_ctfeMatchUnary("a!=4", "a")); static assert(_ctfeMatchUnary("a< 1", "a")); static assert(_ctfeMatchUnary("434 < a", "a")); static assert(_ctfeMatchUnary("132 > a", "a")); static assert(_ctfeMatchUnary("123 >a", "a")); static assert(_ctfeMatchUnary("a>82", "a")); static assert(_ctfeMatchUnary("ё>82", "ё")); static assert(_ctfeMatchUnary("ё[ё(ё)]", "ё")); static assert(_ctfeMatchUnary("ё[21]", "ё")); } // returns 1 if $(D fun) is trivial binary function private uint _ctfeMatchBinary(string fun, string name1, string name2) { if (!__ctfe) assert(false); fun._ctfeSkipOp(); for (;;) { immutable h = fun._ctfeSkipName(name1) + fun._ctfeSkipName(name2) + fun._ctfeSkipInteger(); if (h == 0) { fun._ctfeSkipOp(); break; } else if (h == 1) { if(!fun._ctfeSkipOp()) break; } else return 0; } return fun.length == 0; } unittest { static assert(!_ctfeMatchBinary("sqrt(ё)", "ё", "b")); static assert(!_ctfeMatchBinary("ё.sqrt", "ё", "b")); static assert(!_ctfeMatchBinary(".ё+ё", "ё", "b")); static assert(!_ctfeMatchBinary("_ё+ё", "ё", "b")); static assert(!_ctfeMatchBinary("ёё", "ё", "b")); static assert(_ctfeMatchBinary("a+a", "a", "b")); static assert(_ctfeMatchBinary("a + 10", "a", "b")); static assert(_ctfeMatchBinary("4 == a", "a", "b")); static assert(_ctfeMatchBinary("2==a", "a", "b")); static assert(_ctfeMatchBinary("1 != a", "a", "b")); static assert(_ctfeMatchBinary("a!=4", "a", "b")); static assert(_ctfeMatchBinary("a< 1", "a", "b")); static assert(_ctfeMatchBinary("434 < a", "a", "b")); static assert(_ctfeMatchBinary("132 > a", "a", "b")); static assert(_ctfeMatchBinary("123 >a", "a", "b")); static assert(_ctfeMatchBinary("a>82", "a", "b")); static assert(_ctfeMatchBinary("ё>82", "ё", "q")); static assert(_ctfeMatchBinary("ё[ё(10)]", "ё", "q")); static assert(_ctfeMatchBinary("ё[21]", "ё", "q")); static assert(!_ctfeMatchBinary("sqrt(ё)+b", "b", "ё")); static assert(!_ctfeMatchBinary("ё.sqrt-b", "b", "ё")); static assert(!_ctfeMatchBinary(".ё+b", "b", "ё")); static assert(!_ctfeMatchBinary("_b+ё", "b", "ё")); static assert(!_ctfeMatchBinary("ba", "b", "a")); static assert(_ctfeMatchBinary("a+b", "b", "a")); static assert(_ctfeMatchBinary("a + b", "b", "a")); static assert(_ctfeMatchBinary("b == a", "b", "a")); static assert(_ctfeMatchBinary("b==a", "b", "a")); static assert(_ctfeMatchBinary("b != a", "b", "a")); static assert(_ctfeMatchBinary("a!=b", "b", "a")); static assert(_ctfeMatchBinary("a< b", "b", "a")); static assert(_ctfeMatchBinary("b < a", "b", "a")); static assert(_ctfeMatchBinary("b > a", "b", "a")); static assert(_ctfeMatchBinary("b >a", "b", "a")); static assert(_ctfeMatchBinary("a>b", "b", "a")); static assert(_ctfeMatchBinary("ё>b", "b", "ё")); static assert(_ctfeMatchBinary("b[ё(-1)]", "b", "ё")); static assert(_ctfeMatchBinary("ё[-21]", "b", "ё")); } //undocumented template safeOp(string S) if (S=="<"||S==">"||S=="<="||S==">="||S=="=="||S=="!=") { private bool unsafeOp(ElementType1, ElementType2)(ElementType1 a, ElementType2 b) pure if (isIntegral!ElementType1 && isIntegral!ElementType2) { alias T = CommonType!(ElementType1, ElementType2); return mixin("cast(T)a "~S~" cast(T)b"); } bool safeOp(T0, T1)(auto ref T0 a, auto ref T1 b) { static if (isIntegral!T0 && isIntegral!T1 && (mostNegative!T0 < 0) != (mostNegative!T1 < 0)) { static if (S == "<=" || S == "<") { static if (mostNegative!T0 < 0) immutable result = a < 0 || unsafeOp(a, b); else immutable result = b >= 0 && unsafeOp(a, b); } else { static if (mostNegative!T0 < 0) immutable result = a >= 0 && unsafeOp(a, b); else immutable result = b < 0 || unsafeOp(a, b); } } else { static assert (is(typeof(mixin("a "~S~" b"))), "Invalid arguments: Cannot compare types " ~ T0.stringof ~ " and " ~ T1.stringof ~ "."); immutable result = mixin("a "~S~" b"); } return result; } } unittest //check user defined types { import std.algorithm : equal; struct Foo { int a; auto opEquals(Foo foo) { return a == foo.a; } } assert(safeOp!"!="(Foo(1), Foo(2))); } /** Predicate that returns $(D_PARAM a < b). Correctly compares signed and unsigned integers, ie. -1 < 2U. */ alias lessThan = safeOp!"<"; /// pure @safe @nogc nothrow unittest { assert(lessThan(2, 3)); assert(lessThan(2U, 3U)); assert(lessThan(2, 3.0)); assert(lessThan(-2, 3U)); assert(lessThan(2, 3U)); assert(!lessThan(3U, -2)); assert(!lessThan(3U, 2)); assert(!lessThan(0, 0)); assert(!lessThan(0U, 0)); assert(!lessThan(0, 0U)); } /** Predicate that returns $(D_PARAM a > b). Correctly compares signed and unsigned integers, ie. 2U > -1. */ alias greaterThan = safeOp!">"; /// unittest { assert(!greaterThan(2, 3)); assert(!greaterThan(2U, 3U)); assert(!greaterThan(2, 3.0)); assert(!greaterThan(-2, 3U)); assert(!greaterThan(2, 3U)); assert(greaterThan(3U, -2)); assert(greaterThan(3U, 2)); assert(!greaterThan(0, 0)); assert(!greaterThan(0U, 0)); assert(!greaterThan(0, 0U)); } /** Predicate that returns $(D_PARAM a == b). Correctly compares signed and unsigned integers, ie. !(-1 == ~0U). */ alias equalTo = safeOp!"=="; /// unittest { assert(equalTo(0U, 0)); assert(equalTo(0, 0U)); assert(!equalTo(-1, ~0U)); } /** N-ary predicate that reverses the order of arguments, e.g., given $(D pred(a, b, c)), returns $(D pred(c, b, a)). */ template reverseArgs(alias pred) { auto reverseArgs(Args...)(auto ref Args args) if (is(typeof(pred(Reverse!args)))) { return pred(Reverse!args); } } /// unittest { alias gt = reverseArgs!(binaryFun!("a < b")); assert(gt(2, 1) && !gt(1, 1)); int x = 42; bool xyz(int a, int b) { return a * x < b / x; } auto foo = &xyz; foo(4, 5); alias zyx = reverseArgs!(foo); assert(zyx(5, 4) == foo(4, 5)); } /// unittest { int abc(int a, int b, int c) { return a * b + c; } alias cba = reverseArgs!abc; assert(abc(91, 17, 32) == cba(32, 17, 91)); } /// unittest { int a(int a) { return a * 2; } alias _a = reverseArgs!a; assert(a(2) == _a(2)); } /// unittest { int b() { return 4; } alias _b = reverseArgs!b; assert(b() == _b()); } /** Binary predicate that reverses the order of arguments, e.g., given $(D pred(a, b)), returns $(D pred(b, a)). */ template binaryReverseArgs(alias pred) { auto binaryReverseArgs(ElementType1, ElementType2) (auto ref ElementType1 a, auto ref ElementType2 b) { return pred(b, a); } } /// unittest { alias gt = binaryReverseArgs!(binaryFun!("a < b")); assert(gt(2, 1) && !gt(1, 1)); } /// unittest { int x = 42; bool xyz(int a, int b) { return a * x < b / x; } auto foo = &xyz; foo(4, 5); alias zyx = binaryReverseArgs!(foo); assert(zyx(5, 4) == foo(4, 5)); } /** Negates predicate $(D pred). */ template not(alias pred) { auto not(T...)(auto ref T args) { static if (is(typeof(!pred(args)))) return !pred(args); else static if (T.length == 1) return !unaryFun!pred(args); else static if (T.length == 2) return !binaryFun!pred(args); else static assert(0); } } /// unittest { import std.functional; import std.algorithm : find; import std.uni : isWhite; string a = " Hello, world!"; assert(find!(not!isWhite)(a) == "Hello, world!"); } unittest { assert(not!"a != 5"(5)); assert(not!"a != b"(5, 5)); assert(not!(() => false)()); assert(not!(a => a != 5)(5)); assert(not!((a, b) => a != b)(5, 5)); assert(not!((a, b, c) => a * b * c != 125 )(5, 5, 5)); } /** $(LINK2 http://en.wikipedia.org/wiki/Partial_application, Partially applies) $(D_PARAM fun) by tying its first argument to $(D_PARAM arg). */ template partial(alias fun, alias arg) { static if (is(typeof(fun) == delegate) || is(typeof(fun) == function)) { ReturnType!fun partial(Parameters!fun[1..$] args2) { return fun(arg, args2); } } else { auto partial(Ts...)(Ts args2) { static if (is(typeof(fun(arg, args2)))) { return fun(arg, args2); } else { static string errormsg() { string msg = "Cannot call '" ~ fun.stringof ~ "' with arguments " ~ "(" ~ arg.stringof; foreach(T; Ts) msg ~= ", " ~ T.stringof; msg ~= ")."; return msg; } static assert(0, errormsg()); } } } } /// unittest { int fun(int a, int b) { return a + b; } alias fun5 = partial!(fun, 5); assert(fun5(6) == 11); // Note that in most cases you'd use an alias instead of a value // assignment. Using an alias allows you to partially evaluate template // functions without committing to a particular type of the function. } // Explicitly undocumented. It will be removed in March 2016. @@@DEPRECATED_2016-03@@@ deprecated("Please use std.functional.partial instead") alias curry = partial; // tests for partially evaluating callables unittest { static int f1(int a, int b) { return a + b; } assert(partial!(f1, 5)(6) == 11); int f2(int a, int b) { return a + b; } int x = 5; assert(partial!(f2, x)(6) == 11); x = 7; assert(partial!(f2, x)(6) == 13); static assert(partial!(f2, 5)(6) == 11); auto dg = &f2; auto f3 = &partial!(dg, x); assert(f3(6) == 13); static int funOneArg(int a) { return a; } assert(partial!(funOneArg, 1)() == 1); static int funThreeArgs(int a, int b, int c) { return a + b + c; } alias funThreeArgs1 = partial!(funThreeArgs, 1); assert(funThreeArgs1(2, 3) == 6); static assert(!is(typeof(funThreeArgs1(2)))); enum xe = 5; alias fe = partial!(f2, xe); static assert(fe(6) == 11); } // tests for partially evaluating templated/overloaded callables unittest { static auto add(A, B)(A x, B y) { return x + y; } alias add5 = partial!(add, 5); assert(add5(6) == 11); static assert(!is(typeof(add5()))); static assert(!is(typeof(add5(6, 7)))); // taking address of templated partial evaluation needs explicit type auto dg = &add5!(int); assert(dg(6) == 11); int x = 5; alias addX = partial!(add, x); assert(addX(6) == 11); static struct Callable { static string opCall(string a, string b) { return a ~ b; } int opCall(int a, int b) { return a * b; } double opCall(double a, double b) { return a + b; } } Callable callable; assert(partial!(Callable, "5")("6") == "56"); assert(partial!(callable, 5)(6) == 30); assert(partial!(callable, 7.0)(3.0) == 7.0 + 3.0); static struct TCallable { auto opCall(A, B)(A a, B b) { return a + b; } } TCallable tcallable; assert(partial!(tcallable, 5)(6) == 11); static assert(!is(typeof(partial!(tcallable, "5")(6)))); static A funOneArg(A)(A a) { return a; } alias funOneArg1 = partial!(funOneArg, 1); assert(funOneArg1() == 1); static auto funThreeArgs(A, B, C)(A a, B b, C c) { return a + b + c; } alias funThreeArgs1 = partial!(funThreeArgs, 1); assert(funThreeArgs1(2, 3) == 6); static assert(!is(typeof(funThreeArgs1(1)))); auto dg2 = &funOneArg1!(); assert(dg2() == 1); } /** Takes multiple functions and adjoins them together. The result is a $(XREF typecons, Tuple) with one element per passed-in function. Upon invocation, the returned tuple is the adjoined results of all functions. Note: In the special case where only a single function is provided ($(D F.length == 1)), adjoin simply aliases to the single passed function ($(D F[0])). */ template adjoin(F...) if (F.length == 1) { alias adjoin = F[0]; } /// ditto template adjoin(F...) if (F.length > 1) { auto adjoin(V...)(auto ref V a) { import std.typecons : tuple; static if (F.length == 2) { return tuple(F[0](a), F[1](a)); } else static if (F.length == 3) { return tuple(F[0](a), F[1](a), F[2](a)); } else { import std.format : format; import std.range : iota; return mixin (q{tuple(%(F[%s](a)%|, %))}.format(iota(0, F.length))); } } } /// unittest { import std.functional, std.typecons; static bool f1(int a) { return a != 0; } static int f2(int a) { return a / 2; } auto x = adjoin!(f1, f2)(5); assert(is(typeof(x) == Tuple!(bool, int))); assert(x[0] == true && x[1] == 2); } unittest { import std.typecons; static bool F1(int a) { return a != 0; } auto x1 = adjoin!(F1)(5); static int F2(int a) { return a / 2; } auto x2 = adjoin!(F1, F2)(5); assert(is(typeof(x2) == Tuple!(bool, int))); assert(x2[0] && x2[1] == 2); auto x3 = adjoin!(F1, F2, F2)(5); assert(is(typeof(x3) == Tuple!(bool, int, int))); assert(x3[0] && x3[1] == 2 && x3[2] == 2); bool F4(int a) { return a != x1; } alias eff4 = adjoin!(F4); static struct S { bool delegate(int) store; int fun() { return 42 + store(5); } } S s; s.store = (int a) { return eff4(a); }; auto x4 = s.fun(); assert(x4 == 43); } unittest { import std.meta : staticMap; import std.typecons : Tuple, tuple; alias funs = staticMap!(unaryFun, "a", "a * 2", "a * 3", "a * a", "-a"); alias afun = adjoin!funs; assert(afun(5) == tuple(5, 10, 15, 25, -5)); static class C{} alias IC = immutable(C); IC foo(){return typeof(return).init;} Tuple!(IC, IC, IC, IC) ret1 = adjoin!(foo, foo, foo, foo)(); static struct S{int* p;} alias IS = immutable(S); IS bar(){return typeof(return).init;} enum Tuple!(IS, IS, IS, IS) ret2 = adjoin!(bar, bar, bar, bar)(); } /** Composes passed-in functions $(D fun[0], fun[1], ...) returning a function $(D f(x)) that in turn returns $(D fun[0](fun[1](...(x)))...). Each function can be a regular functions, a delegate, or a string. */ template compose(fun...) { static if (fun.length == 1) { alias compose = unaryFun!(fun[0]); } else static if (fun.length == 2) { // starch alias fun0 = unaryFun!(fun[0]); alias fun1 = unaryFun!(fun[1]); // protein: the core composition operation typeof({ E a; return fun0(fun1(a)); }()) compose(E)(E a) { return fun0(fun1(a)); } } else { // protein: assembling operations alias compose = compose!(fun[0], compose!(fun[1 .. $])); } } /// unittest { import std.algorithm: equal, map; import std.array: split; import std.conv: to; // First split a string in whitespace-separated tokens and then // convert each token into an integer assert(compose!(map!(to!(int)), split)("1 2 3").equal([1, 2, 3])); } /** Pipes functions in sequence. Offers the same functionality as $(D compose), but with functions specified in reverse order. This may lead to more readable code in some situation because the order of execution is the same as lexical order. Example: ---- // Read an entire text file, split the resulting string in // whitespace-separated tokens, and then convert each token into an // integer int[] a = pipe!(readText, split, map!(to!(int)))("file.txt"); ---- */ alias pipe(fun...) = compose!(Reverse!(fun)); unittest { import std.conv : to; string foo(int a) { return to!(string)(a); } int bar(string a) { return to!(int)(a) + 1; } double baz(int a) { return a + 0.5; } assert(compose!(baz, bar, foo)(1) == 2.5); assert(pipe!(foo, bar, baz)(1) == 2.5); assert(compose!(baz, `to!(int)(a) + 1`, foo)(1) == 2.5); assert(compose!(baz, bar)("1"[]) == 2.5); assert(compose!(baz, bar)("1") == 2.5); assert(compose!(`a + 0.5`, `to!(int)(a) + 1`, foo)(1) == 2.5); } /** * $(LUCKY Memoizes) a function so as to avoid repeated * computation. The memoization structure is a hash table keyed by a * tuple of the function's arguments. There is a speed gain if the * function is repeatedly called with the same arguments and is more * expensive than a hash table lookup. For more information on memoization, refer to $(WEB docs.google.com/viewer?url=http%3A%2F%2Fhop.perl.plover.com%2Fbook%2Fpdf%2F03CachingAndMemoization.pdf, this book chapter). Example: ---- double transmogrify(int a, string b) { ... expensive computation ... } alias fastTransmogrify = memoize!transmogrify; unittest { auto slow = transmogrify(2, "hello"); auto fast = fastTransmogrify(2, "hello"); assert(slow == fast); } ---- Technically the memoized function should be pure because $(D memoize) assumes it will always return the same result for a given tuple of arguments. However, $(D memoize) does not enforce that because sometimes it is useful to memoize an impure function, too. */ template memoize(alias fun) { // alias Args = Parameters!fun; // Bugzilla 13580 ReturnType!fun memoize(Parameters!fun args) { alias Args = Parameters!fun; import std.typecons : Tuple; static ReturnType!fun[Tuple!Args] memo; auto t = Tuple!Args(args); if (auto p = t in memo) return *p; return memo[t] = fun(args); } } /// ditto template memoize(alias fun, uint maxSize) { // alias Args = Parameters!fun; // Bugzilla 13580 ReturnType!fun memoize(Parameters!fun args) { import std.typecons : tuple; static struct Value { Parameters!fun args; ReturnType!fun res; } static Value[] memo; static size_t[] initialized; if (!memo.length) { import core.memory; enum attr = GC.BlkAttr.NO_INTERIOR | (hasIndirections!Value ? 0 : GC.BlkAttr.NO_SCAN); memo = (cast(Value*)GC.malloc(Value.sizeof * maxSize, attr))[0 .. maxSize]; enum nwords = (maxSize + 8 * size_t.sizeof - 1) / (8 * size_t.sizeof); initialized = (cast(size_t*)GC.calloc(nwords * size_t.sizeof, attr | GC.BlkAttr.NO_SCAN))[0 .. nwords]; } import core.bitop : bt, bts; import std.conv : emplace; size_t hash; foreach (ref arg; args) hash = hashOf(arg, hash); // cuckoo hashing immutable idx1 = hash % maxSize; if (!bt(initialized.ptr, idx1)) { emplace(&memo[idx1], args, fun(args)); bts(initialized.ptr, idx1); // only set to initialized after setting args and value (bugzilla 14025) return memo[idx1].res; } else if (memo[idx1].args == args) return memo[idx1].res; // FNV prime immutable idx2 = (hash * 16777619) % maxSize; if (!bt(initialized.ptr, idx2)) { emplace(&memo[idx2], memo[idx1]); bts(initialized.ptr, idx2); // only set to initialized after setting args and value (bugzilla 14025) } else if (memo[idx2].args == args) return memo[idx2].res; else if (idx1 != idx2) memo[idx2] = memo[idx1]; memo[idx1] = Value(args, fun(args)); return memo[idx1].res; } } /** * To _memoize a recursive function, simply insert the memoized call in lieu of the plain recursive call. * For example, to transform the exponential-time Fibonacci implementation into a linear-time computation: */ unittest { ulong fib(ulong n) { return n < 2 ? 1 : memoize!fib(n - 2) + memoize!fib(n - 1); } assert(fib(10) == 89); } /** * To improve the speed of the factorial function, */ unittest { ulong fact(ulong n) { return n < 2 ? 1 : n * memoize!fact(n - 1); } assert(fact(10) == 3628800); } /** * This memoizes all values of $(D fact) up to the largest argument. To only cache the final * result, move $(D memoize) outside the function as shown below. */ unittest { ulong factImpl(ulong n) { return n < 2 ? 1 : n * factImpl(n - 1); } alias fact = memoize!factImpl; assert(fact(10) == 3628800); } /** * When the $(D maxSize) parameter is specified, memoize will used * a fixed size hash table to limit the number of cached entries. */ unittest { ulong fact(ulong n) { // Memoize no more than 8 values return n < 2 ? 1 : n * memoize!(fact, 8)(n - 1); } assert(fact(8) == 40320); // using more entries than maxSize will overwrite existing entries assert(fact(10) == 3628800); } unittest { import core.math; alias msqrt = memoize!(function double(double x) { return sqrt(x); }); auto y = msqrt(2.0); assert(y == msqrt(2.0)); y = msqrt(4.0); assert(y == sqrt(4.0)); // alias mrgb2cmyk = memoize!rgb2cmyk; // auto z = mrgb2cmyk([43, 56, 76]); // assert(z == mrgb2cmyk([43, 56, 76])); //alias mfib = memoize!fib; static ulong fib(ulong n) { alias mfib = memoize!fib; return n < 2 ? 1 : mfib(n - 2) + mfib(n - 1); } auto z = fib(10); assert(z == 89); static ulong fact(ulong n) { alias mfact = memoize!fact; return n < 2 ? 1 : n * mfact(n - 1); } assert(fact(10) == 3628800); // Issue 12568 static uint len2(const string s) { // Error alias mLen2 = memoize!len2; if (s.length == 0) return 0; else return 1 + mLen2(s[1 .. $]); } int _func(int x) { return 1; } alias func = memoize!(_func, 10); assert(func(int.init) == 1); assert(func(int.init) == 1); } private struct DelegateFaker(F) { import std.typecons; // for @safe static F castToF(THIS)(THIS x) @trusted { return cast(F) x; } /* * What all the stuff below does is this: *-------------------- * struct DelegateFaker(F) { * extern(linkage) * [ref] ReturnType!F doIt(Parameters!F args) [@attributes] * { * auto fp = cast(F) &this; * return fp(args); * } * } *-------------------- */ // We will use MemberFunctionGenerator in std.typecons. This is a policy // configuration for generating the doIt(). template GeneratingPolicy() { // Inform the genereator that we only have type information. enum WITHOUT_SYMBOL = true; // Generate the function body of doIt(). template generateFunctionBody(unused...) { enum generateFunctionBody = // [ref] ReturnType doIt(Parameters args) @attributes q{ // When this function gets called, the this pointer isn't // really a this pointer (no instance even really exists), but // a function pointer that points to the function to be called. // Cast it to the correct type and call it. auto fp = castToF(&this); return fp(args); }; } } // Type information used by the generated code. alias FuncInfo_doIt = FuncInfo!(F); // Generate the member function doIt(). mixin( std.typecons.MemberFunctionGenerator!(GeneratingPolicy!()) .generateFunction!("FuncInfo_doIt", "doIt", F) ); } /** * Convert a callable to a delegate with the same parameter list and * return type, avoiding heap allocations and use of auxiliary storage. * * Example: * ---- * void doStuff() { * writeln("Hello, world."); * } * * void runDelegate(void delegate() myDelegate) { * myDelegate(); * } * * auto delegateToPass = toDelegate(&doStuff); * runDelegate(delegateToPass); // Calls doStuff, prints "Hello, world." * ---- * * BUGS: * $(UL * $(LI Does not work with $(D @safe) functions.) * $(LI Ignores C-style / D-style variadic arguments.) * ) */ auto toDelegate(F)(auto ref F fp) if (isCallable!(F)) { static if (is(F == delegate)) { return fp; } else static if (is(typeof(&F.opCall) == delegate) || (is(typeof(&F.opCall) V : V*) && is(V == function))) { return toDelegate(&fp.opCall); } else { alias DelType = typeof(&(new DelegateFaker!(F)).doIt); static struct DelegateFields { union { DelType del; //pragma(msg, typeof(del)); struct { void* contextPtr; void* funcPtr; } } } // fp is stored in the returned delegate's context pointer. // The returned delegate's function pointer points to // DelegateFaker.doIt. DelegateFields df; df.contextPtr = cast(void*) fp; DelegateFaker!(F) dummy; auto dummyDel = &dummy.doIt; df.funcPtr = dummyDel.funcptr; return df.del; } } unittest { static int inc(ref uint num) { num++; return 8675309; } uint myNum = 0; auto incMyNumDel = toDelegate(&inc); static assert(is(typeof(incMyNumDel) == int delegate(ref uint))); auto returnVal = incMyNumDel(myNum); assert(myNum == 1); interface I { int opCall(); } class C: I { int opCall() { inc(myNum); return myNum;} } auto c = new C; auto i = cast(I) c; auto getvalc = toDelegate(c); assert(getvalc() == 2); auto getvali = toDelegate(i); assert(getvali() == 3); struct S1 { int opCall() { inc(myNum); return myNum; } } static assert(!is(typeof(&s1.opCall) == delegate)); S1 s1; auto getvals1 = toDelegate(s1); assert(getvals1() == 4); struct S2 { static int opCall() { return 123456; } } static assert(!is(typeof(&S2.opCall) == delegate)); S2 s2; auto getvals2 =&S2.opCall; assert(getvals2() == 123456); /* test for attributes */ { static int refvar = 0xDeadFace; static ref int func_ref() { return refvar; } static int func_pure() pure { return 1; } static int func_nothrow() nothrow { return 2; } static int func_property() @property { return 3; } static int func_safe() @safe { return 4; } static int func_trusted() @trusted { return 5; } static int func_system() @system { return 6; } static int func_pure_nothrow() pure nothrow { return 7; } static int func_pure_nothrow_safe() pure @safe { return 8; } auto dg_ref = toDelegate(&func_ref); auto dg_pure = toDelegate(&func_pure); auto dg_nothrow = toDelegate(&func_nothrow); auto dg_property = toDelegate(&func_property); auto dg_safe = toDelegate(&func_safe); auto dg_trusted = toDelegate(&func_trusted); auto dg_system = toDelegate(&func_system); auto dg_pure_nothrow = toDelegate(&func_pure_nothrow); auto dg_pure_nothrow_safe = toDelegate(&func_pure_nothrow_safe); //static assert(is(typeof(dg_ref) == ref int delegate())); // [BUG@DMD] static assert(is(typeof(dg_pure) == int delegate() pure)); static assert(is(typeof(dg_nothrow) == int delegate() nothrow)); static assert(is(typeof(dg_property) == int delegate() @property)); //static assert(is(typeof(dg_safe) == int delegate() @safe)); static assert(is(typeof(dg_trusted) == int delegate() @trusted)); static assert(is(typeof(dg_system) == int delegate() @system)); static assert(is(typeof(dg_pure_nothrow) == int delegate() pure nothrow)); //static assert(is(typeof(dg_pure_nothrow_safe) == int delegate() @safe pure nothrow)); assert(dg_ref() == refvar); assert(dg_pure() == 1); assert(dg_nothrow() == 2); assert(dg_property() == 3); //assert(dg_safe() == 4); assert(dg_trusted() == 5); assert(dg_system() == 6); assert(dg_pure_nothrow() == 7); //assert(dg_pure_nothrow_safe() == 8); } /* test for linkage */ { struct S { extern(C) static void xtrnC() {} extern(D) static void xtrnD() {} } auto dg_xtrnC = toDelegate(&S.xtrnC); auto dg_xtrnD = toDelegate(&S.xtrnD); static assert(! is(typeof(dg_xtrnC) == typeof(dg_xtrnD))); } } /** Forwards function arguments with saving ref-ness. */ template forward(args...) { import std.meta; static if (args.length) { import std.algorithm.mutation : move; alias arg = args[0]; static if (__traits(isRef, arg)) alias fwd = arg; else @property fwd()(){ return move(arg); } alias forward = AliasSeq!(fwd, forward!(args[1..$])); } else alias forward = AliasSeq!(); } /// @safe unittest { class C { static int foo(int n) { return 1; } static int foo(ref int n) { return 2; } } int bar()(auto ref int x) { return C.foo(forward!x); } assert(bar(1) == 1); int i; assert(bar(i) == 2); } /// @safe unittest { void foo(int n, ref string s) { s = null; foreach (i; 0..n) s ~= "Hello"; } // forwards all arguments which are bound to parameter tuple void bar(Args...)(auto ref Args args) { return foo(forward!args); } // forwards all arguments with swapping order void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); } string s; bar(1, s); assert(s == "Hello"); baz(s, 2); assert(s == "HelloHello"); } @safe unittest { auto foo(TL...)(auto ref TL args) { string result = ""; foreach (i, _; args) { //pragma(msg, "[",i,"] ", __traits(isRef, args[i]) ? "L" : "R"); result ~= __traits(isRef, args[i]) ? "L" : "R"; } return result; } string bar(TL...)(auto ref TL args) { return foo(forward!args); } string baz(TL...)(auto ref TL args) { int x; return foo(forward!args[3], forward!args[2], 1, forward!args[1], forward!args[0], x); } struct S {} S makeS(){ return S(); } int n; string s; assert(bar(S(), makeS(), n, s) == "RRLL"); assert(baz(S(), makeS(), n, s) == "LLRRRL"); } @safe unittest { ref int foo(return ref int a) { return a; } ref int bar(Args)(auto ref Args args) { return foo(forward!args); } static assert(!__traits(compiles, { auto x1 = bar(3); })); // case of NG int value = 3; auto x2 = bar(value); // case of OK } ldc-1.1.0-beta3-src/runtime/phobos/std/socket.d0000664000175000017500000031552112776215007017352 0ustar kaikai// Written in the D programming language /* Copyright (C) 2004-2011 Christopher E. Miller Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. socket.d 1.4 Jan 2011 Thanks to Benjamin Herr for his assistance. */ /** * Socket primitives. * Example: See $(SAMPLESRC listener.d) and $(SAMPLESRC htmlget.d) * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Christopher E. Miller, $(WEB klickverbot.at, David Nadlinger), * $(WEB thecybershadow.net, Vladimir Panteleev) * Source: $(PHOBOSSRC std/_socket.d) * Macros: * WIKI=Phobos/StdSocket */ module std.socket; import core.stdc.stdint, core.stdc.string, std.string, core.stdc.stdlib, std.conv; import core.stdc.config; import core.time : dur, Duration; import std.exception; import std.internal.cstring; @safe: version(Windows) { pragma (lib, "ws2_32.lib"); pragma (lib, "wsock32.lib"); public import core.sys.windows.winsock2; private import core.sys.windows.windows, std.windows.syserror; private alias _ctimeval = core.sys.windows.winsock2.timeval; private alias _clinger = core.sys.windows.winsock2.linger; enum socket_t : SOCKET { INVALID_SOCKET } private const int _SOCKET_ERROR = SOCKET_ERROR; private int _lasterr() nothrow @nogc { return WSAGetLastError(); } } else version(Posix) { version(linux) { enum : int { TCP_KEEPIDLE = 4, TCP_KEEPINTVL = 5 } } import core.sys.posix.netdb; import core.sys.posix.sys.un : sockaddr_un; private import core.sys.posix.fcntl; private import core.sys.posix.unistd; private import core.sys.posix.arpa.inet; private import core.sys.posix.netinet.tcp; private import core.sys.posix.netinet.in_; private import core.sys.posix.sys.time; private import core.sys.posix.sys.select; private import core.sys.posix.sys.socket; private alias _ctimeval = core.sys.posix.sys.time.timeval; private alias _clinger = core.sys.posix.sys.socket.linger; private import core.stdc.errno; enum socket_t : int32_t { init = -1 } private const int _SOCKET_ERROR = -1; private enum : int { SD_RECEIVE = SHUT_RD, SD_SEND = SHUT_WR, SD_BOTH = SHUT_RDWR } private int _lasterr() nothrow @nogc { return errno; } } else { static assert(0); // No socket support yet. } version(unittest) { static assert(is(uint32_t == uint)); static assert(is(uint16_t == ushort)); private import std.stdio : writefln; // Print a message on exception instead of failing the unittest. private void softUnittest(void delegate() @safe test, int line = __LINE__) @trusted { try test(); catch (Throwable e) { writefln(" --- std.socket(%d) test fails depending on environment ---", line); writefln(" (%s)", e); } } } /// Base exception thrown by $(D std.socket). class SocketException: Exception { mixin basicExceptionCtors; } // Needs to be public so that SocketOSException can be thrown outside of // std.socket (since it uses it as a default argument), but it probably doesn't // need to actually show up in the docs, since there's not really any public // need for it outside of being a default argument. string formatSocketError(int err) @trusted { version(Posix) { char[80] buf; const(char)* cs; version (CRuntime_Glibc) { cs = strerror_r(err, buf.ptr, buf.length); } else version (OSX) { auto errs = strerror_r(err, buf.ptr, buf.length); if (errs == 0) cs = buf.ptr; else return "Socket error " ~ to!string(err); } else version (FreeBSD) { auto errs = strerror_r(err, buf.ptr, buf.length); if (errs == 0) cs = buf.ptr; else return "Socket error " ~ to!string(err); } else version (NetBSD) { auto errs = strerror_r(err, buf.ptr, buf.length); if (errs == 0) cs = buf.ptr; else return "Socket error " ~ to!string(err); } else version (Solaris) { auto errs = strerror_r(err, buf.ptr, buf.length); if (errs == 0) cs = buf.ptr; else return "Socket error " ~ to!string(err); } else version (CRuntime_Bionic) { auto errs = strerror_r(err, buf.ptr, buf.length); if (errs == 0) cs = buf.ptr; else return "Socket error " ~ to!string(err); } else static assert(0); auto len = strlen(cs); if(cs[len - 1] == '\n') len--; if(cs[len - 1] == '\r') len--; return cs[0 .. len].idup; } else version(Windows) { return sysErrorString(err); } else return "Socket error " ~ to!string(err); } /// Retrieve the error message for the most recently encountered network error. @property string lastSocketError() { return formatSocketError(_lasterr()); } /// Socket exceptions representing network errors reported by the operating /// system. class SocketOSException: SocketException { int errorCode; /// Platform-specific error code. /// this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null, int err = _lasterr(), string function(int) @trusted errorFormatter = &formatSocketError) { errorCode = err; if (msg.length) super(msg ~ ": " ~ errorFormatter(err), file, line, next); else super(errorFormatter(err), file, line, next); } /// this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__, int err = _lasterr(), string function(int) @trusted errorFormatter = &formatSocketError) { this(msg, file, line, next, err, errorFormatter); } /// this(string msg, int err, string function(int) @trusted errorFormatter = &formatSocketError, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { this(msg, file, line, next, err, errorFormatter); } } /// Socket exceptions representing invalid parameters specified by user code. class SocketParameterException: SocketException { mixin basicExceptionCtors; } /// Socket exceptions representing attempts to use network capabilities not /// available on the current system. class SocketFeatureException: SocketException { mixin basicExceptionCtors; } /// Return $(D true) if the last socket operation failed because the socket /// was in non-blocking mode and the operation would have blocked. bool wouldHaveBlocked() nothrow @nogc { version(Windows) return _lasterr() == WSAEWOULDBLOCK; else version(Posix) return _lasterr() == EAGAIN; else static assert(0); } private immutable { typeof(&getnameinfo) getnameinfoPointer; typeof(&getaddrinfo) getaddrinfoPointer; typeof(&freeaddrinfo) freeaddrinfoPointer; } shared static this() @system { version(Windows) { WSADATA wd; // Winsock will still load if an older version is present. // The version is just a request. int val; val = WSAStartup(0x2020, &wd); if(val) // Request Winsock 2.2 for IPv6. throw new SocketOSException("Unable to initialize socket library", val); // These functions may not be present on older Windows versions. // See the comment in InternetAddress.toHostNameString() for details. auto ws2Lib = GetModuleHandleA("ws2_32.dll"); if (ws2Lib) { getnameinfoPointer = cast(typeof(getnameinfoPointer)) GetProcAddress(ws2Lib, "getnameinfo"); getaddrinfoPointer = cast(typeof(getaddrinfoPointer)) GetProcAddress(ws2Lib, "getaddrinfo"); freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer)) GetProcAddress(ws2Lib, "freeaddrinfo"); } } else version(Posix) { getnameinfoPointer = &getnameinfo; getaddrinfoPointer = &getaddrinfo; freeaddrinfoPointer = &freeaddrinfo; } } shared static ~this() @system nothrow @nogc { version(Windows) { WSACleanup(); } } /** * The communication domain used to resolve an address. */ enum AddressFamily: int { UNSPEC = AF_UNSPEC, /// Unspecified address family UNIX = AF_UNIX, /// Local communication INET = AF_INET, /// Internet Protocol version 4 IPX = AF_IPX, /// Novell IPX APPLETALK = AF_APPLETALK, /// AppleTalk INET6 = AF_INET6, /// Internet Protocol version 6 } /** * Communication semantics */ enum SocketType: int { STREAM = SOCK_STREAM, /// Sequenced, reliable, two-way communication-based byte streams DGRAM = SOCK_DGRAM, /// Connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order RAW = SOCK_RAW, /// Raw protocol access RDM = SOCK_RDM, /// Reliably-delivered message datagrams SEQPACKET = SOCK_SEQPACKET, /// Sequenced, reliable, two-way connection-based datagrams with a fixed maximum length } /** * Protocol */ enum ProtocolType: int { IP = IPPROTO_IP, /// Internet Protocol version 4 ICMP = IPPROTO_ICMP, /// Internet Control Message Protocol IGMP = IPPROTO_IGMP, /// Internet Group Management Protocol GGP = IPPROTO_GGP, /// Gateway to Gateway Protocol TCP = IPPROTO_TCP, /// Transmission Control Protocol PUP = IPPROTO_PUP, /// PARC Universal Packet Protocol UDP = IPPROTO_UDP, /// User Datagram Protocol IDP = IPPROTO_IDP, /// Xerox NS protocol RAW = IPPROTO_RAW, /// Raw IP packets IPV6 = IPPROTO_IPV6, /// Internet Protocol version 6 } /** * $(D Protocol) is a class for retrieving protocol information. * * Example: * --- * auto proto = new Protocol; * writeln("About protocol TCP:"); * if (proto.getProtocolByType(ProtocolType.TCP)) * { * writefln(" Name: %s", proto.name); * foreach(string s; proto.aliases) * writefln(" Alias: %s", s); * } * else * writeln(" No information found"); * --- */ class Protocol { /// These members are populated when one of the following functions are called successfully: ProtocolType type; string name; /// ditto string[] aliases; /// ditto void populate(protoent* proto) @system pure nothrow { type = cast(ProtocolType)proto.p_proto; name = to!string(proto.p_name); int i; for(i = 0;; i++) { if(!proto.p_aliases[i]) break; } if(i) { aliases = new string[i]; for(i = 0; i != aliases.length; i++) { aliases[i] = to!string(proto.p_aliases[i]); } } else { aliases = null; } } /** Returns: false on failure */ bool getProtocolByName(in char[] name) @trusted nothrow { protoent* proto; proto = getprotobyname(name.tempCString()); if(!proto) return false; populate(proto); return true; } /** Returns: false on failure */ // Same as getprotobynumber(). bool getProtocolByType(ProtocolType type) @trusted nothrow { protoent* proto; proto = getprotobynumber(type); if(!proto) return false; populate(proto); return true; } } // Skip this test on Android because getprotobyname/number are // unimplemented in bionic. version(CRuntime_Bionic) {} else unittest { softUnittest({ Protocol proto = new Protocol; assert(proto.getProtocolByType(ProtocolType.TCP)); //writeln("About protocol TCP:"); //writefln("\tName: %s", proto.name); // foreach(string s; proto.aliases) // { // writefln("\tAlias: %s", s); // } assert(proto.name == "tcp"); assert(proto.aliases.length == 1 && proto.aliases[0] == "TCP"); }); } /** * $(D Service) is a class for retrieving service information. * * Example: * --- * auto serv = new Service; * writeln("About service epmap:"); * if (serv.getServiceByName("epmap", "tcp")) * { * writefln(" Service: %s", serv.name); * writefln(" Port: %d", serv.port); * writefln(" Protocol: %s", serv.protocolName); * foreach (string s; serv.aliases) * writefln(" Alias: %s", s); * } * else * writefln(" No service for epmap."); * --- */ class Service { /// These members are populated when one of the following functions are called successfully: string name; string[] aliases; /// ditto ushort port; /// ditto string protocolName; /// ditto void populate(servent* serv) @system pure nothrow { name = to!string(serv.s_name); port = ntohs(cast(ushort)serv.s_port); protocolName = to!string(serv.s_proto); int i; for(i = 0;; i++) { if(!serv.s_aliases[i]) break; } if(i) { aliases = new string[i]; for(i = 0; i != aliases.length; i++) { aliases[i] = to!string(serv.s_aliases[i]); } } else { aliases = null; } } /** * If a protocol name is omitted, any protocol will be matched. * Returns: false on failure. */ bool getServiceByName(in char[] name, in char[] protocolName = null) @trusted nothrow { servent* serv; serv = getservbyname(name.tempCString(), protocolName.tempCString()); if(!serv) return false; populate(serv); return true; } /// ditto bool getServiceByPort(ushort port, in char[] protocolName = null) @trusted nothrow { servent* serv; serv = getservbyport(port, protocolName.tempCString()); if(!serv) return false; populate(serv); return true; } } unittest { softUnittest({ Service serv = new Service; if(serv.getServiceByName("epmap", "tcp")) { // writefln("About service epmap:"); // writefln("\tService: %s", serv.name); // writefln("\tPort: %d", serv.port); // writefln("\tProtocol: %s", serv.protocolName); // foreach(string s; serv.aliases) // { // writefln("\tAlias: %s", s); // } // For reasons unknown this is loc-srv on Wine and epmap on Windows assert(serv.name == "loc-srv" || serv.name == "epmap", serv.name); assert(serv.port == 135); assert(serv.protocolName == "tcp"); } else { writefln("No service for epmap."); } }); } private mixin template socketOSExceptionCtors() { /// this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null, int err = _lasterr()) { super(msg, file, line, next, err); } /// this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__, int err = _lasterr()) { super(msg, next, file, line, err); } /// this(string msg, int err, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(msg, next, file, line, err); } } /** * Class for exceptions thrown from an $(D InternetHost). */ class HostException: SocketOSException { mixin socketOSExceptionCtors; } /** * $(D InternetHost) is a class for resolving IPv4 addresses. * * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods * instead of using this class directly. * * Example: * --- * auto ih = new InternetHost; * * // Forward lookup * writeln("About www.digitalmars.com:"); * if (ih.getHostByName("www.digitalmars.com")) * { * writefln(" Name: %s", ih.name); * auto ip = InternetAddress.addrToString(ih.addrList[0]); * writefln(" IP address: %s", ip); * foreach (string s; ih.aliases) * writefln(" Alias: %s", s); * writeln("---"); * * // Reverse lookup * writefln("About IP %s:", ip); * if (ih.getHostByAddr(ih.addrList[0])) * { * writefln(" Name: %s", ih.name); * foreach (string s; ih.aliases) * writefln(" Alias: %s", s); * } * else * writeln(" Reverse lookup failed"); * } * else * writeln(" Can't resolve www.digitalmars.com"); * --- */ class InternetHost { /// These members are populated when one of the following functions are called successfully: string name; string[] aliases; /// ditto uint[] addrList; /// ditto void validHostent(in hostent* he) { if(he.h_addrtype != cast(int)AddressFamily.INET || he.h_length != 4) throw new HostException("Address family mismatch"); } void populate(hostent* he) @system pure nothrow { int i; char* p; name = to!string(he.h_name); for(i = 0;; i++) { p = he.h_aliases[i]; if(!p) break; } if(i) { aliases = new string[i]; for(i = 0; i != aliases.length; i++) { aliases[i] = to!string(he.h_aliases[i]); } } else { aliases = null; } for(i = 0;; i++) { p = he.h_addr_list[i]; if(!p) break; } if(i) { addrList = new uint[i]; for(i = 0; i != addrList.length; i++) { addrList[i] = ntohl(*(cast(uint*)he.h_addr_list[i])); } } else { addrList = null; } } private bool getHostNoSync(string opMixin, T)(T param) @system { mixin(opMixin); if (!he) return false; validHostent(he); populate(he); return true; } version(Windows) alias getHost = getHostNoSync; else { // posix systems use global state for return value, so we // must synchronize across all threads private bool getHost(string opMixin, T)(T param) @system { synchronized(this.classinfo) return getHostNoSync!(opMixin, T)(param); } } /** * Resolve host name. * Returns: false if unable to resolve. */ bool getHostByName(in char[] name) @trusted { static if (is(typeof(gethostbyname_r))) { return getHostNoSync!q{ hostent he_v; hostent* he; ubyte[256] buffer_v = void; auto buffer = buffer_v[]; auto param_zTmp = param.tempCString(); while (true) { he = &he_v; int errno; if (gethostbyname_r(param_zTmp, he, buffer.ptr, buffer.length, &he, &errno) == ERANGE) buffer.length = buffer.length * 2; else break; } }(name); } else { return getHost!q{ auto he = gethostbyname(param.tempCString()); }(name); } } /** * Resolve IPv4 address number. * * Params: * addr = The IPv4 address to resolve, in host byte order. * Returns: * false if unable to resolve. */ bool getHostByAddr(uint addr) @trusted { return getHost!q{ auto x = htonl(param); auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET); }(addr); } /** * Same as previous, but addr is an IPv4 address string in the * dotted-decimal form $(I a.b.c.d). * Returns: false if unable to resolve. */ bool getHostByAddr(in char[] addr) @trusted { return getHost!q{ auto x = inet_addr(param.tempCString()); enforce(x != INADDR_NONE, new SocketParameterException("Invalid IPv4 address")); auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET); }(addr); } } unittest { InternetHost ih = new InternetHost; ih.getHostByAddr(0x7F_00_00_01); assert(ih.addrList[0] == 0x7F_00_00_01); ih.getHostByAddr("127.0.0.1"); assert(ih.addrList[0] == 0x7F_00_00_01); softUnittest({ if (!ih.getHostByName("www.digitalmars.com")) return; // don't fail if not connected to internet //writefln("addrList.length = %d", ih.addrList.length); assert(ih.addrList.length); InternetAddress ia = new InternetAddress(ih.addrList[0], InternetAddress.PORT_ANY); assert(ih.name == "www.digitalmars.com" || ih.name == "digitalmars.com", ih.name); // writefln("IP address = %s", ia.toAddrString()); // writefln("name = %s", ih.name); // foreach(int i, string s; ih.aliases) // { // writefln("aliases[%d] = %s", i, s); // } // writefln("---"); //assert(ih.getHostByAddr(ih.addrList[0])); // writefln("name = %s", ih.name); // foreach(int i, string s; ih.aliases) // { // writefln("aliases[%d] = %s", i, s); // } }); } /// Holds information about a socket _address retrieved by $(D getAddressInfo). struct AddressInfo { AddressFamily family; /// Address _family SocketType type; /// Socket _type ProtocolType protocol; /// Protocol Address address; /// Socket _address string canonicalName; /// Canonical name, when $(D AddressInfoFlags.CANONNAME) is used. } // A subset of flags supported on all platforms with getaddrinfo. /// Specifies option flags for $(D getAddressInfo). enum AddressInfoFlags: int { /// The resulting addresses will be used in a call to $(D Socket.bind). PASSIVE = AI_PASSIVE, /// The canonical name is returned in $(D canonicalName) member in the first $(D AddressInfo). CANONNAME = AI_CANONNAME, /// The $(D node) parameter passed to $(D getAddressInfo) must be a numeric string. /// This will suppress any potentially lengthy network host address lookups. NUMERICHOST = AI_NUMERICHOST, } /// On POSIX, getaddrinfo uses its own error codes, and thus has its own /// formatting function. private string formatGaiError(int err) @trusted { version(Windows) { return sysErrorString(err); } else { synchronized return to!string(gai_strerror(err)); } } /** * Provides _protocol-independent translation from host names to socket * addresses. If advanced functionality is not required, consider using * $(D getAddress) for compatibility with older systems. * * Returns: Array with one $(D AddressInfo) per socket address. * * Throws: $(D SocketOSException) on failure, or $(D SocketFeatureException) * if this functionality is not available on the current system. * * Params: * node = string containing host name or numeric address * options = optional additional parameters, identified by type: * $(UL $(LI $(D string) - service name or port number) * $(LI $(D AddressInfoFlags) - option flags) * $(LI $(D AddressFamily) - address family to filter by) * $(LI $(D SocketType) - socket type to filter by) * $(LI $(D ProtocolType) - protocol to filter by)) * * Example: * --- * // Roundtrip DNS resolution * auto results = getAddressInfo("www.digitalmars.com"); * assert(results[0].address.toHostNameString() == * "digitalmars.com"); * * // Canonical name * results = getAddressInfo("www.digitalmars.com", * AddressInfoFlags.CANONNAME); * assert(results[0].canonicalName == "digitalmars.com"); * * // IPv6 resolution * results = getAddressInfo("ipv6.google.com"); * assert(results[0].family == AddressFamily.INET6); * * // Multihomed resolution * results = getAddressInfo("google.com"); * assert(results.length > 1); * * // Parsing IPv4 * results = getAddressInfo("127.0.0.1", * AddressInfoFlags.NUMERICHOST); * assert(results.length && results[0].family == * AddressFamily.INET); * * // Parsing IPv6 * results = getAddressInfo("::1", * AddressInfoFlags.NUMERICHOST); * assert(results.length && results[0].family == * AddressFamily.INET6); * --- */ AddressInfo[] getAddressInfo(T...)(in char[] node, T options) @trusted { const(char)[] service = null; addrinfo hints; hints.ai_family = AF_UNSPEC; foreach (option; options) { static if (is(typeof(option) : const(char)[])) service = option; else static if (is(typeof(option) == AddressInfoFlags)) hints.ai_flags |= option; else static if (is(typeof(option) == AddressFamily)) hints.ai_family = option; else static if (is(typeof(option) == SocketType)) hints.ai_socktype = option; else static if (is(typeof(option) == ProtocolType)) hints.ai_protocol = option; else static assert(0, "Unknown getAddressInfo option type: " ~ typeof(option).stringof); } return getAddressInfoImpl(node, service, &hints); } private AddressInfo[] getAddressInfoImpl(in char[] node, in char[] service, addrinfo* hints) @system { import std.array : appender; if (getaddrinfoPointer && freeaddrinfoPointer) { addrinfo* ai_res; int ret = getaddrinfoPointer( node.tempCString(), service.tempCString(), hints, &ai_res); enforce(ret == 0, new SocketOSException("getaddrinfo error", ret, &formatGaiError)); scope(exit) freeaddrinfoPointer(ai_res); auto result = appender!(AddressInfo[])(); // Use const to force UnknownAddressReference to copy the sockaddr. for (const(addrinfo)* ai = ai_res; ai; ai = ai.ai_next) result ~= AddressInfo( cast(AddressFamily) ai.ai_family, cast(SocketType ) ai.ai_socktype, cast(ProtocolType ) ai.ai_protocol, new UnknownAddressReference(ai.ai_addr, cast(socklen_t) ai.ai_addrlen), ai.ai_canonname ? to!string(ai.ai_canonname) : null); assert(result.data.length > 0); return result.data; } throw new SocketFeatureException("Address info lookup is not available " ~ "on this system."); } unittest { softUnittest({ if (getaddrinfoPointer) { // Roundtrip DNS resolution auto results = getAddressInfo("www.digitalmars.com"); assert(results[0].address.toHostNameString() == "digitalmars.com"); // Canonical name results = getAddressInfo("www.digitalmars.com", AddressInfoFlags.CANONNAME); assert(results[0].canonicalName == "digitalmars.com"); // IPv6 resolution //results = getAddressInfo("ipv6.google.com"); //assert(results[0].family == AddressFamily.INET6); // Multihomed resolution //results = getAddressInfo("google.com"); //assert(results.length > 1); // Parsing IPv4 results = getAddressInfo("127.0.0.1", AddressInfoFlags.NUMERICHOST); assert(results.length && results[0].family == AddressFamily.INET); // Parsing IPv6 results = getAddressInfo("::1", AddressInfoFlags.NUMERICHOST); assert(results.length && results[0].family == AddressFamily.INET6); } }); if (getaddrinfoPointer) { auto results = getAddressInfo(null, "1234", AddressInfoFlags.PASSIVE, SocketType.STREAM, ProtocolType.TCP, AddressFamily.INET); assert(results.length == 1 && results[0].address.toString() == "0.0.0.0:1234"); } } private ushort serviceToPort(in char[] service) { if (service == "") return InternetAddress.PORT_ANY; else if (isNumeric(service)) return to!ushort(service); else { auto s = new Service(); s.getServiceByName(service); return s.port; } } /** * Provides _protocol-independent translation from host names to socket * addresses. Uses $(D getAddressInfo) if the current system supports it, * and $(D InternetHost) otherwise. * * Returns: Array with one $(D Address) instance per socket address. * * Throws: $(D SocketOSException) on failure. * * Example: * --- * writeln("Resolving www.digitalmars.com:"); * try * { * auto addresses = getAddress("www.digitalmars.com"); * foreach (address; addresses) * writefln(" IP: %s", address.toAddrString()); * } * catch (SocketException e) * writefln(" Lookup failed: %s", e.msg); * --- */ Address[] getAddress(in char[] hostname, in char[] service = null) { if (getaddrinfoPointer && freeaddrinfoPointer) { // use getAddressInfo auto infos = getAddressInfo(hostname, service); Address[] results; results.length = infos.length; foreach (i, ref result; results) result = infos[i].address; return results; } else return getAddress(hostname, serviceToPort(service)); } /// ditto Address[] getAddress(in char[] hostname, ushort port) { if (getaddrinfoPointer && freeaddrinfoPointer) return getAddress(hostname, to!string(port)); else { // use getHostByName auto ih = new InternetHost; if (!ih.getHostByName(hostname)) throw new AddressException( text("Unable to resolve host '", hostname, "'")); Address[] results; foreach (uint addr; ih.addrList) results ~= new InternetAddress(addr, port); return results; } } unittest { softUnittest({ auto addresses = getAddress("63.105.9.61"); assert(addresses.length && addresses[0].toAddrString() == "63.105.9.61"); if (getaddrinfoPointer) { // test via gethostbyname auto getaddrinfoPointerBackup = getaddrinfoPointer; cast() getaddrinfoPointer = null; scope(exit) cast() getaddrinfoPointer = getaddrinfoPointerBackup; addresses = getAddress("63.105.9.61"); assert(addresses.length && addresses[0].toAddrString() == "63.105.9.61"); } }); } /** * Provides _protocol-independent parsing of network addresses. Does not * attempt name resolution. Uses $(D getAddressInfo) with * $(D AddressInfoFlags.NUMERICHOST) if the current system supports it, and * $(D InternetAddress) otherwise. * * Returns: An $(D Address) instance representing specified address. * * Throws: $(D SocketException) on failure. * * Example: * --- * writeln("Enter IP address:"); * string ip = readln().chomp(); * try * { * Address address = parseAddress(ip); * writefln("Looking up reverse of %s:", * address.toAddrString()); * try * { * string reverse = address.toHostNameString(); * if (reverse) * writefln(" Reverse name: %s", reverse); * else * writeln(" Reverse hostname not found."); * } * catch (SocketException e) * writefln(" Lookup error: %s", e.msg); * } * catch (SocketException e) * { * writefln(" %s is not a valid IP address: %s", * ip, e.msg); * } * --- */ Address parseAddress(in char[] hostaddr, in char[] service = null) { if (getaddrinfoPointer && freeaddrinfoPointer) return getAddressInfo(hostaddr, service, AddressInfoFlags.NUMERICHOST)[0].address; else return parseAddress(hostaddr, serviceToPort(service)); } /// ditto Address parseAddress(in char[] hostaddr, ushort port) { if (getaddrinfoPointer && freeaddrinfoPointer) return parseAddress(hostaddr, to!string(port)); else { auto in4_addr = InternetAddress.parse(hostaddr); enforce(in4_addr != InternetAddress.ADDR_NONE, new SocketParameterException("Invalid IP address")); return new InternetAddress(in4_addr, port); } } unittest { softUnittest({ auto address = parseAddress("63.105.9.61"); assert(address.toAddrString() == "63.105.9.61"); if (getaddrinfoPointer) { // test via inet_addr auto getaddrinfoPointerBackup = getaddrinfoPointer; cast() getaddrinfoPointer = null; scope(exit) cast() getaddrinfoPointer = getaddrinfoPointerBackup; address = parseAddress("63.105.9.61"); assert(address.toAddrString() == "63.105.9.61"); } assert(collectException!SocketException(parseAddress("Invalid IP address"))); }); } /** * Class for exceptions thrown from an $(D Address). */ class AddressException: SocketOSException { mixin socketOSExceptionCtors; } /** * $(D Address) is an abstract class for representing a socket addresses. * * Example: * --- * writeln("About www.google.com port 80:"); * try * { * Address[] addresses = getAddress("www.google.com", 80); * writefln(" %d addresses found.", addresses.length); * foreach (int i, Address a; addresses) * { * writefln(" Address %d:", i+1); * writefln(" IP address: %s", a.toAddrString()); * writefln(" Hostname: %s", a.toHostNameString()); * writefln(" Port: %s", a.toPortString()); * writefln(" Service name: %s", * a.toServiceNameString()); * } * } * catch (SocketException e) * writefln(" Lookup error: %s", e.msg); * --- */ abstract class Address { /// Returns pointer to underlying $(D sockaddr) structure. abstract @property sockaddr* name() pure nothrow @nogc; abstract @property const(sockaddr)* name() const pure nothrow @nogc; /// ditto /// Returns actual size of underlying $(D sockaddr) structure. abstract @property socklen_t nameLen() const pure nothrow @nogc; /// Family of this address. @property AddressFamily addressFamily() const pure nothrow @nogc { return cast(AddressFamily) name.sa_family; } // Common code for toAddrString and toHostNameString private final string toHostString(bool numeric) @trusted const { // getnameinfo() is the recommended way to perform a reverse (name) // lookup on both Posix and Windows. However, it is only available // on Windows XP and above, and not included with the WinSock import // libraries shipped with DMD. Thus, we check for getnameinfo at // runtime in the shared module constructor, and use it if it's // available in the base class method. Classes for specific network // families (e.g. InternetHost) override this method and use a // deprecated, albeit commonly-available method when getnameinfo() // is not available. // http://technet.microsoft.com/en-us/library/aa450403.aspx if (getnameinfoPointer) { auto buf = new char[NI_MAXHOST]; auto ret = getnameinfoPointer( name, nameLen, buf.ptr, cast(uint)buf.length, null, 0, numeric ? NI_NUMERICHOST : NI_NAMEREQD); if (!numeric) { if (ret==EAI_NONAME) return null; version(Windows) if (ret==WSANO_DATA) return null; } enforce(ret == 0, new AddressException("Could not get " ~ (numeric ? "host address" : "host name"))); return assumeUnique(buf[0 .. strlen(buf.ptr)]); } throw new SocketFeatureException((numeric ? "Host address" : "Host name") ~ " lookup for this address family is not available on this system."); } // Common code for toPortString and toServiceNameString private final string toServiceString(bool numeric) @trusted const { // See toHostNameString() for details about getnameinfo(). if (getnameinfoPointer) { auto buf = new char[NI_MAXSERV]; enforce(getnameinfoPointer( name, nameLen, null, 0, buf.ptr, cast(uint)buf.length, numeric ? NI_NUMERICSERV : NI_NAMEREQD ) == 0, new AddressException("Could not get " ~ (numeric ? "port number" : "service name"))); return assumeUnique(buf[0 .. strlen(buf.ptr)]); } throw new SocketFeatureException((numeric ? "Port number" : "Service name") ~ " lookup for this address family is not available on this system."); } /** * Attempts to retrieve the host address as a human-readable string. * * Throws: $(D AddressException) on failure, or $(D SocketFeatureException) * if address retrieval for this address family is not available on the * current system. */ string toAddrString() const { return toHostString(true); } /** * Attempts to retrieve the host name as a fully qualified domain name. * * Returns: The FQDN corresponding to this $(D Address), or $(D null) if * the host name did not resolve. * * Throws: $(D AddressException) on error, or $(D SocketFeatureException) * if host name lookup for this address family is not available on the * current system. */ string toHostNameString() const { return toHostString(false); } /** * Attempts to retrieve the numeric port number as a string. * * Throws: $(D AddressException) on failure, or $(D SocketFeatureException) * if port number retrieval for this address family is not available on the * current system. */ string toPortString() const { return toServiceString(true); } /** * Attempts to retrieve the service name as a string. * * Throws: $(D AddressException) on failure, or $(D SocketFeatureException) * if service name lookup for this address family is not available on the * current system. */ string toServiceNameString() const { return toServiceString(false); } /// Human readable string representing this address. override string toString() const { try { string host = toAddrString(); string port = toPortString(); if (host.indexOf(':') >= 0) return "[" ~ host ~ "]:" ~ port; else return host ~ ":" ~ port; } catch (SocketException) return "Unknown"; } } /** * $(D UnknownAddress) encapsulates an unknown socket address. */ class UnknownAddress: Address { protected: sockaddr sa; public: override @property sockaddr* name() { return &sa; } override @property const(sockaddr)* name() const { return &sa; } override @property socklen_t nameLen() const { return cast(socklen_t) sa.sizeof; } } /** * $(D UnknownAddressReference) encapsulates a reference to an arbitrary * socket address. */ class UnknownAddressReference: Address { protected: sockaddr* sa; socklen_t len; public: /// Constructs an $(D Address) with a reference to the specified $(D sockaddr). this(sockaddr* sa, socklen_t len) pure nothrow @nogc { this.sa = sa; this.len = len; } /// Constructs an $(D Address) with a copy of the specified $(D sockaddr). this(const(sockaddr)* sa, socklen_t len) @system pure nothrow { this.sa = cast(sockaddr*) (cast(ubyte*)sa)[0..len].dup.ptr; this.len = len; } override @property sockaddr* name() { return sa; } override @property const(sockaddr)* name() const { return sa; } override @property socklen_t nameLen() const { return cast(socklen_t) len; } } /** * $(D InternetAddress) encapsulates an IPv4 (Internet Protocol version 4) * socket address. * * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods * instead of using this class directly. */ class InternetAddress: Address { protected: sockaddr_in sin; this() pure nothrow @nogc { } public: override @property sockaddr* name() { return cast(sockaddr*)&sin; } override @property const(sockaddr)* name() const { return cast(const(sockaddr)*)&sin; } override @property socklen_t nameLen() const { return cast(socklen_t) sin.sizeof; } enum uint ADDR_ANY = INADDR_ANY; /// Any IPv4 host address. enum uint ADDR_NONE = INADDR_NONE; /// An invalid IPv4 host address. enum ushort PORT_ANY = 0; /// Any IPv4 port number. /// Returns the IPv4 _port number (in host byte order). @property ushort port() const pure nothrow @nogc { return ntohs(sin.sin_port); } /// Returns the IPv4 address number (in host byte order). @property uint addr() const pure nothrow @nogc { return ntohl(sin.sin_addr.s_addr); } /** * Construct a new $(D InternetAddress). * Params: * addr = an IPv4 address string in the dotted-decimal form a.b.c.d, * or a host name which will be resolved using an $(D InternetHost) * object. * port = port number, may be $(D PORT_ANY). */ this(in char[] addr, ushort port) { uint uiaddr = parse(addr); if(ADDR_NONE == uiaddr) { InternetHost ih = new InternetHost; if(!ih.getHostByName(addr)) //throw new AddressException("Invalid internet address"); throw new AddressException( text("Unable to resolve host '", addr, "'")); uiaddr = ih.addrList[0]; } sin.sin_family = AddressFamily.INET; sin.sin_addr.s_addr = htonl(uiaddr); sin.sin_port = htons(port); } /** * Construct a new $(D InternetAddress). * Params: * addr = (optional) an IPv4 address in host byte order, may be $(D ADDR_ANY). * port = port number, may be $(D PORT_ANY). */ this(uint addr, ushort port) pure nothrow @nogc { sin.sin_family = AddressFamily.INET; sin.sin_addr.s_addr = htonl(addr); sin.sin_port = htons(port); } /// ditto this(ushort port) pure nothrow @nogc { sin.sin_family = AddressFamily.INET; sin.sin_addr.s_addr = ADDR_ANY; sin.sin_port = htons(port); } /** * Construct a new $(D InternetAddress). * Params: * addr = A sockaddr_in as obtained from lower-level API calls such as getifaddrs. */ this(sockaddr_in addr) pure nothrow @nogc { assert(addr.sin_family == AddressFamily.INET); sin = addr; } /// Human readable string representing the IPv4 address in dotted-decimal form. override string toAddrString() @trusted const { return to!string(inet_ntoa(sin.sin_addr)); } /// Human readable string representing the IPv4 port. override string toPortString() const { return std.conv.to!string(port); } /** * Attempts to retrieve the host name as a fully qualified domain name. * * Returns: The FQDN corresponding to this $(D InternetAddress), or * $(D null) if the host name did not resolve. * * Throws: $(D AddressException) on error. */ override string toHostNameString() const { // getnameinfo() is the recommended way to perform a reverse (name) // lookup on both Posix and Windows. However, it is only available // on Windows XP and above, and not included with the WinSock import // libraries shipped with DMD. Thus, we check for getnameinfo at // runtime in the shared module constructor, and fall back to the // deprecated getHostByAddr() if it could not be found. See also: // http://technet.microsoft.com/en-us/library/aa450403.aspx if (getnameinfoPointer) return super.toHostNameString(); else { auto host = new InternetHost(); if (!host.getHostByAddr(ntohl(sin.sin_addr.s_addr))) return null; return host.name; } } /** * Compares with another InternetAddress of same type for equality * Returns: true if the InternetAddresses share the same address and * port number. */ override bool opEquals(Object o) const { auto other = cast(InternetAddress)o; return other && this.sin.sin_addr.s_addr == other.sin.sin_addr.s_addr && this.sin.sin_port == other.sin.sin_port; } /// @system unittest { auto addr1 = new InternetAddress("127.0.0.1", 80); auto addr2 = new InternetAddress("127.0.0.2", 80); assert(addr1 == addr1); assert(addr1 != addr2); } /** * Parse an IPv4 address string in the dotted-decimal form $(I a.b.c.d) * and return the number. * Returns: If the string is not a legitimate IPv4 address, * $(D ADDR_NONE) is returned. */ static uint parse(in char[] addr) @trusted nothrow { return ntohl(inet_addr(addr.tempCString())); } /** * Convert an IPv4 address number in host byte order to a human readable * string representing the IPv4 address in dotted-decimal form. */ static string addrToString(uint addr) @trusted nothrow { in_addr sin_addr; sin_addr.s_addr = htonl(addr); return to!string(inet_ntoa(sin_addr)); } } unittest { softUnittest({ const InternetAddress ia = new InternetAddress("63.105.9.61", 80); assert(ia.toString() == "63.105.9.61:80"); }); softUnittest({ // test construction from a sockaddr_in sockaddr_in sin; sin.sin_addr.s_addr = htonl(0x7F_00_00_01); // 127.0.0.1 sin.sin_family = AddressFamily.INET; sin.sin_port = htons(80); const InternetAddress ia = new InternetAddress(sin); assert(ia.toString() == "127.0.0.1:80"); }); softUnittest({ // test reverse lookup auto ih = new InternetHost; if (ih.getHostByName("digitalmars.com")) { const ia = new InternetAddress(ih.addrList[0], 80); assert(ia.toHostNameString() == "digitalmars.com"); if (getnameinfoPointer) { // test reverse lookup, via gethostbyaddr auto getnameinfoPointerBackup = getnameinfoPointer; cast() getnameinfoPointer = null; scope(exit) cast() getnameinfoPointer = getnameinfoPointerBackup; assert(ia.toHostNameString() == "digitalmars.com"); } } }); version (SlowTests) softUnittest({ // test failing reverse lookup const InternetAddress ia = new InternetAddress("127.114.111.120", 80); assert(ia.toHostNameString() is null); if (getnameinfoPointer) { // test failing reverse lookup, via gethostbyaddr auto getnameinfoPointerBackup = getnameinfoPointer; getnameinfoPointer = null; scope(exit) getnameinfoPointer = getnameinfoPointerBackup; assert(ia.toHostNameString() is null); } }); } /** * $(D Internet6Address) encapsulates an IPv6 (Internet Protocol version 6) * socket address. * * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods * instead of using this class directly. */ class Internet6Address: Address { protected: sockaddr_in6 sin6; this() pure nothrow @nogc { } public: override @property sockaddr* name() { return cast(sockaddr*)&sin6; } override @property const(sockaddr)* name() const { return cast(const(sockaddr)*)&sin6; } override @property socklen_t nameLen() const { return cast(socklen_t) sin6.sizeof; } /// Any IPv6 host address. static @property ref const(ubyte)[16] ADDR_ANY() pure nothrow @nogc { const(ubyte)[16]* addr; static if (is(typeof(IN6ADDR_ANY))) { addr = &IN6ADDR_ANY.s6_addr; return *addr; } else static if (is(typeof(in6addr_any))) { addr = &in6addr_any.s6_addr; return *addr; } else static assert(0); } /// Any IPv6 port number. enum ushort PORT_ANY = 0; /// Returns the IPv6 port number. @property ushort port() const pure nothrow @nogc { return ntohs(sin6.sin6_port); } /// Returns the IPv6 address. @property ubyte[16] addr() const pure nothrow @nogc { return sin6.sin6_addr.s6_addr; } /** * Construct a new $(D Internet6Address). * Params: * addr = an IPv6 host address string in the form described in RFC 2373, * or a host name which will be resolved using $(D getAddressInfo). * service = (optional) service name. */ this(in char[] addr, in char[] service = null) @trusted { auto results = getAddressInfo(addr, service, AddressFamily.INET6); assert(results.length && results[0].family == AddressFamily.INET6); sin6 = *cast(sockaddr_in6*)results[0].address.name; } /** * Construct a new $(D Internet6Address). * Params: * addr = an IPv6 host address string in the form described in RFC 2373, * or a host name which will be resolved using $(D getAddressInfo). * port = port number, may be $(D PORT_ANY). */ this(in char[] addr, ushort port) { if (port == PORT_ANY) this(addr); else this(addr, to!string(port)); } /** * Construct a new $(D Internet6Address). * Params: * addr = (optional) an IPv6 host address in host byte order, or * $(D ADDR_ANY). * port = port number, may be $(D PORT_ANY). */ this(ubyte[16] addr, ushort port) pure nothrow @nogc { sin6.sin6_family = AddressFamily.INET6; sin6.sin6_addr.s6_addr = addr; sin6.sin6_port = htons(port); } /// ditto this(ushort port) pure nothrow @nogc { sin6.sin6_family = AddressFamily.INET6; sin6.sin6_addr.s6_addr = ADDR_ANY; sin6.sin6_port = htons(port); } /** * Construct a new $(D Internet6Address). * Params: * addr = A sockaddr_in6 as obtained from lower-level API calls such as getifaddrs. */ this(sockaddr_in6 addr) pure nothrow @nogc { assert(addr.sin6_family == AddressFamily.INET6); sin6 = addr; } /** * Parse an IPv6 host address string as described in RFC 2373, and return the * address. * Throws: $(D SocketException) on error. */ static ubyte[16] parse(in char[] addr) @trusted { // Although we could use inet_pton here, it's only available on Windows // versions starting with Vista, so use getAddressInfo with NUMERICHOST // instead. auto results = getAddressInfo(addr, AddressInfoFlags.NUMERICHOST); if (results.length && results[0].family == AddressFamily.INET6) return (cast(sockaddr_in6*)results[0].address.name).sin6_addr.s6_addr; throw new AddressException("Not an IPv6 address", 0); } } unittest { softUnittest({ const Internet6Address ia = new Internet6Address("::1", 80); assert(ia.toString() == "[::1]:80"); }); softUnittest({ // test construction from a sockaddr_in6 sockaddr_in6 sin; sin.sin6_addr.s6_addr = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; // [::1] sin.sin6_family = AddressFamily.INET6; sin.sin6_port = htons(80); const Internet6Address ia = new Internet6Address(sin); assert(ia.toString() == "[::1]:80"); }); } version(StdDdoc) { static if (!is(sockaddr_un)) { // This exists only to allow the constructor taking // a sockaddr_un to be compilable for documentation // on platforms that don't supply a sockaddr_un. struct sockaddr_un { } } /** * $(D UnixAddress) encapsulates an address for a Unix domain socket * ($(D AF_UNIX)). Available only on supported systems. */ class UnixAddress: Address { private this() pure nothrow @nogc {} /// Construct a new $(D UnixAddress) from the specified path. this(in char[] path) { } /** * Construct a new $(D UnixAddress). * Params: * addr = A sockaddr_un as obtained from lower-level API calls. */ this(sockaddr_un addr) pure nothrow @nogc { } /// Get the underlying _path. @property string path() const { return null; } /// ditto override string toString() const { return null; } override @property sockaddr* name() { return null; } override @property const(sockaddr)* name() const { return null; } override @property socklen_t nameLen() const { return 0; } } } else static if (is(sockaddr_un)) { class UnixAddress: Address { protected: struct { align (1): sockaddr_un sun; char unused = '\0'; // placeholder for a terminating '\0' } this() pure nothrow @nogc { sun.sun_family = AddressFamily.UNIX; sun.sun_path = '?'; } public: override @property sockaddr* name() { return cast(sockaddr*)&sun; } override @property const(sockaddr)* name() const { return cast(const(sockaddr)*)&sun; } override @property socklen_t nameLen() @trusted const { return cast(socklen_t) (sockaddr_un.init.sun_path.offsetof + strlen(cast(const(char*)) sun.sun_path.ptr) + 1); } this(in char[] path) @trusted pure { enforce(path.length <= sun.sun_path.sizeof, new SocketParameterException("Path too long")); sun.sun_family = AddressFamily.UNIX; sun.sun_path.ptr[0..path.length] = (cast(byte[]) path)[]; sun.sun_path.ptr[path.length] = 0; } this(sockaddr_un addr) pure nothrow @nogc { assert(addr.sun_family == AddressFamily.UNIX); sun = addr; } @property string path() @trusted const pure { return to!string(cast(const(char)*)sun.sun_path.ptr); } override string toString() const pure { return path; } } unittest { import core.stdc.stdio : remove; import std.file: deleteme; immutable ubyte[] data = [1, 2, 3, 4]; Socket[2] pair; auto name = deleteme ~ "-unix-socket"; auto address = new UnixAddress(name); auto listener = new Socket(AddressFamily.UNIX, SocketType.STREAM); scope(exit) listener.close(); listener.bind(address); scope(exit) () @trusted { remove(name.tempCString()); } (); assert(listener.localAddress.toString == name); listener.listen(1); pair[0] = new Socket(AddressFamily.UNIX, SocketType.STREAM); scope(exit) listener.close(); pair[0].connect(address); scope(exit) pair[0].close(); pair[1] = listener.accept(); scope(exit) pair[1].close(); pair[0].send(data); auto buf = new ubyte[data.length]; pair[1].receive(buf); assert(buf == data); } } /** * Class for exceptions thrown by $(D Socket.accept). */ class SocketAcceptException: SocketOSException { mixin socketOSExceptionCtors; } /// How a socket is shutdown: enum SocketShutdown: int { RECEIVE = SD_RECEIVE, /// socket receives are disallowed SEND = SD_SEND, /// socket sends are disallowed BOTH = SD_BOTH, /// both RECEIVE and SEND } /// Flags may be OR'ed together: enum SocketFlags: int { NONE = 0, /// no flags specified OOB = MSG_OOB, /// out-of-band stream data PEEK = MSG_PEEK, /// peek at incoming data without removing it from the queue, only for receiving DONTROUTE = MSG_DONTROUTE, /// data should not be subject to routing; this flag may be ignored. Only for sending } private mixin template FieldProxy(string target, string field) { mixin(` @property typeof(`~target~`) `~field~`() const pure nothrow @nogc { return `~target~`; } /// ditto @property typeof(`~target~`) `~field~`(typeof(`~target~`) value) pure nothrow @nogc { return `~target~` = value; } `); } /// Duration timeout value. struct TimeVal { _ctimeval ctimeval; alias tv_sec_t = typeof(ctimeval.tv_sec); alias tv_usec_t = typeof(ctimeval.tv_usec); version (StdDdoc) // no DDoc for string mixins, can't forward individual fields { tv_sec_t seconds; /// Number of _seconds. tv_usec_t microseconds; /// Number of additional _microseconds. } else { // D interface mixin FieldProxy!(`ctimeval.tv_sec`, `seconds`); mixin FieldProxy!(`ctimeval.tv_usec`, `microseconds`); } } /** * A collection of sockets for use with $(D Socket.select). * * $(D SocketSet) wraps the platform $(D fd_set) type. However, unlike * $(D fd_set), $(D SocketSet) is not statically limited to $(D FD_SETSIZE) * or any other limit, and grows as needed. */ class SocketSet { private: version (Windows) { // On Windows, fd_set is an array of socket handles, // following a word containing the fd_set instance size. // We use one dynamic array for everything, and use its first // element(s) for the count. alias fd_set_count_type = typeof(fd_set.init.fd_count); alias fd_set_type = typeof(fd_set.init.fd_array[0]); static assert(fd_set_type.sizeof == socket_t.sizeof); // Number of fd_set_type elements at the start of our array that are // used for the socket count and alignment enum FD_SET_OFFSET = fd_set.fd_array.offsetof / fd_set_type.sizeof; static assert(FD_SET_OFFSET); static assert(fd_set.fd_count.offsetof % fd_set_type.sizeof == 0); fd_set_type[] set; final void resize(size_t size) pure nothrow { set.length = FD_SET_OFFSET + size; } final ref inout(fd_set_count_type) count() @trusted @property inout pure nothrow @nogc { assert(set.length); return *cast(inout(fd_set_count_type)*)set.ptr; } final size_t capacity() @property const pure nothrow @nogc { return set.length - FD_SET_OFFSET; } final inout(socket_t)[] fds() @trusted inout @property pure nothrow @nogc { return cast(inout(socket_t)[])set[FD_SET_OFFSET..FD_SET_OFFSET+count]; } } else version (Posix) { // On Posix, fd_set is a bit array. We assume that the fd_set // type (declared in core.sys.posix.sys.select) is a structure // containing a single field, a static array. static assert(fd_set.tupleof.length==1); // This is the type used in the fd_set array. // Using the type of the correct size is important for big-endian // architectures. alias fd_set_type = typeof(fd_set.init.tupleof[0][0]); // Number of file descriptors represented by one fd_set_type enum FD_NFDBITS = 8 * fd_set_type.sizeof; static fd_set_type mask(uint n) pure nothrow @nogc { return (cast(fd_set_type)1) << (n % FD_NFDBITS); } // Array size to fit that many sockets static size_t lengthFor(size_t size) pure nothrow @nogc { return (size + (FD_NFDBITS-1)) / FD_NFDBITS; } fd_set_type[] set; final void resize(size_t size) pure nothrow { set.length = lengthFor(size); } // Make sure we can fit that many sockets final void setMinCapacity(size_t size) pure nothrow { auto length = lengthFor(size); if (set.length < length) set.length = length; } final size_t capacity() @property const pure nothrow @nogc { return set.length * FD_NFDBITS; } int maxfd; } else static assert(false, "Unknown platform"); public: /** * Create a SocketSet with a specific initial capacity (defaults to * $(D FD_SETSIZE), the system's default capacity). */ this(size_t size = FD_SETSIZE) pure nothrow { resize(size); reset(); } /// Reset the $(D SocketSet) so that there are 0 $(D Socket)s in the collection. void reset() pure nothrow @nogc { version (Windows) count = 0; else { set[] = 0; maxfd = -1; } } void add(socket_t s) @trusted pure nothrow { version (Windows) { if (count == capacity) { set.length *= 2; set.length = set.capacity; } ++count; fds[$-1] = s; } else { auto index = s / FD_NFDBITS; auto length = set.length; if (index >= length) { while (index >= length) length *= 2; set.length = length; set.length = set.capacity; } set[index] |= mask(s); if (maxfd < s) maxfd = s; } } /// Add a $(D Socket) to the collection. /// The socket must not already be in the collection. void add(Socket s) pure nothrow { add(s.sock); } void remove(socket_t s) pure nothrow { version (Windows) { import std.algorithm : countUntil; auto fds = fds; auto p = fds.countUntil(s); if (p >= 0) fds[p] = fds[--count]; } else { auto index = s / FD_NFDBITS; if (index >= set.length) return; set[index] &= ~mask(s); // note: adjusting maxfd would require scanning the set, not worth it } } /// Remove this $(D Socket) from the collection. /// Does nothing if the socket is not in the collection already. void remove(Socket s) pure nothrow { remove(s.sock); } int isSet(socket_t s) const pure nothrow @nogc { version (Windows) { import std.algorithm; return fds.canFind(s) ? 1 : 0; } else { if (s > maxfd) return 0; auto index = s / FD_NFDBITS; return (set[index] & mask(s)) ? 1 : 0; } } /// Return nonzero if this $(D Socket) is in the collection. int isSet(Socket s) const pure nothrow @nogc { return isSet(s.sock); } /// Return the current capacity of this $(D SocketSet). The exact /// meaning of the return value varies from platform to platform. /// /// Note that since D 2.065, this value does not indicate a /// restriction, and $(D SocketSet) will grow its capacity as /// needed automatically. @property uint max() const pure nothrow @nogc { return cast(uint)capacity; } fd_set* toFd_set() @trusted pure nothrow @nogc { return cast(fd_set*)set.ptr; } int selectn() const pure nothrow @nogc { version (Windows) { return count; } else version (Posix) { return maxfd + 1; } } } unittest { auto fds = cast(socket_t[]) [cast(socket_t)1, 2, 0, 1024, 17, 42, 1234, 77, 77+32, 77+64]; auto set = new SocketSet(); foreach (fd; fds) assert(!set.isSet(fd)); foreach (fd; fds) set.add(fd); foreach (fd; fds) assert(set.isSet(fd)); // Make sure SocketSet reimplements fd_set correctly auto fdset = set.toFd_set(); foreach (fd; fds[0]..cast(socket_t)(fds[$-1]+1)) assert(cast(bool)set.isSet(fd) == cast(bool)(() @trusted => FD_ISSET(fd, fdset))()); foreach (fd; fds) { assert(set.isSet(fd)); set.remove(fd); assert(!set.isSet(fd)); } } unittest { softUnittest({ enum PAIRS = 768; version(Posix) () @trusted { enum LIMIT = 2048; static assert(LIMIT > PAIRS*2); import core.sys.posix.sys.resource; rlimit fileLimit; getrlimit(RLIMIT_NOFILE, &fileLimit); assert(fileLimit.rlim_max > LIMIT, "Open file hard limit too low"); fileLimit.rlim_cur = LIMIT; setrlimit(RLIMIT_NOFILE, &fileLimit); } (); Socket[2][PAIRS] pairs; foreach (ref pair; pairs) pair = socketPair(); scope(exit) { foreach (pair; pairs) { pair[0].close(); pair[1].close(); } } import std.random; auto rng = Xorshift(42); pairs[].randomShuffle(rng); auto readSet = new SocketSet(); auto writeSet = new SocketSet(); auto errorSet = new SocketSet(); foreach (testPair; pairs) { void fillSets() { readSet.reset(); writeSet.reset(); errorSet.reset(); foreach (ref pair; pairs) foreach (s; pair[]) { readSet.add(s); writeSet.add(s); errorSet.add(s); } } fillSets(); auto n = Socket.select(readSet, writeSet, errorSet); assert(n == PAIRS*2); // All in writeSet assert(writeSet.isSet(testPair[0])); assert(writeSet.isSet(testPair[1])); assert(!readSet.isSet(testPair[0])); assert(!readSet.isSet(testPair[1])); assert(!errorSet.isSet(testPair[0])); assert(!errorSet.isSet(testPair[1])); ubyte[1] b; testPair[0].send(b[]); fillSets(); n = Socket.select(readSet, null, null); assert(n == 1); // testPair[1] assert(readSet.isSet(testPair[1])); assert(!readSet.isSet(testPair[0])); testPair[1].receive(b[]); } }); } unittest // Issue 14012, 14013 { auto set = new SocketSet(1); assert(set.max >= 0); enum LIMIT = 4096; foreach (n; 0..LIMIT) set.add(cast(socket_t)n); assert(set.max >= LIMIT); } /// The level at which a socket option is defined: enum SocketOptionLevel: int { SOCKET = SOL_SOCKET, /// Socket level IP = ProtocolType.IP, /// Internet Protocol version 4 level ICMP = ProtocolType.ICMP, /// Internet Control Message Protocol level IGMP = ProtocolType.IGMP, /// Internet Group Management Protocol level GGP = ProtocolType.GGP, /// Gateway to Gateway Protocol level TCP = ProtocolType.TCP, /// Transmission Control Protocol level PUP = ProtocolType.PUP, /// PARC Universal Packet Protocol level UDP = ProtocolType.UDP, /// User Datagram Protocol level IDP = ProtocolType.IDP, /// Xerox NS protocol level RAW = ProtocolType.RAW, /// Raw IP packet level IPV6 = ProtocolType.IPV6, /// Internet Protocol version 6 level } /// _Linger information for use with SocketOption.LINGER. struct Linger { _clinger clinger; version (StdDdoc) // no DDoc for string mixins, can't forward individual fields { private alias l_onoff_t = typeof(_clinger.init.l_onoff ); private alias l_linger_t = typeof(_clinger.init.l_linger); l_onoff_t on; /// Nonzero for _on. l_linger_t time; /// Linger _time. } else { // D interface mixin FieldProxy!(`clinger.l_onoff`, `on`); mixin FieldProxy!(`clinger.l_linger`, `time`); } } /// Specifies a socket option: enum SocketOption: int { DEBUG = SO_DEBUG, /// Record debugging information BROADCAST = SO_BROADCAST, /// Allow transmission of broadcast messages REUSEADDR = SO_REUSEADDR, /// Allow local reuse of address LINGER = SO_LINGER, /// Linger on close if unsent data is present OOBINLINE = SO_OOBINLINE, /// Receive out-of-band data in band SNDBUF = SO_SNDBUF, /// Send buffer size RCVBUF = SO_RCVBUF, /// Receive buffer size DONTROUTE = SO_DONTROUTE, /// Do not route SNDTIMEO = SO_SNDTIMEO, /// Send timeout RCVTIMEO = SO_RCVTIMEO, /// Receive timeout ERROR = SO_ERROR, /// Retrieve and clear error status KEEPALIVE = SO_KEEPALIVE, /// Enable keep-alive packets ACCEPTCONN = SO_ACCEPTCONN, /// Listen RCVLOWAT = SO_RCVLOWAT, /// Minimum number of input bytes to process SNDLOWAT = SO_SNDLOWAT, /// Minimum number of output bytes to process TYPE = SO_TYPE, /// Socket type // SocketOptionLevel.TCP: TCP_NODELAY = .TCP_NODELAY, /// Disable the Nagle algorithm for send coalescing // SocketOptionLevel.IPV6: IPV6_UNICAST_HOPS = .IPV6_UNICAST_HOPS, /// IP unicast hop limit IPV6_MULTICAST_IF = .IPV6_MULTICAST_IF, /// IP multicast interface IPV6_MULTICAST_LOOP = .IPV6_MULTICAST_LOOP, /// IP multicast loopback IPV6_MULTICAST_HOPS = .IPV6_MULTICAST_HOPS, /// IP multicast hops IPV6_JOIN_GROUP = .IPV6_JOIN_GROUP, /// Add an IP group membership IPV6_LEAVE_GROUP = .IPV6_LEAVE_GROUP, /// Drop an IP group membership IPV6_V6ONLY = .IPV6_V6ONLY, /// Treat wildcard bind as AF_INET6-only } /** * $(D Socket) is a class that creates a network communication endpoint using * the Berkeley sockets interface. */ class Socket { private: socket_t sock; AddressFamily _family; version(Windows) bool _blocking = false; /// Property to get or set whether the socket is blocking or nonblocking. // The WinSock timeouts seem to be effectively skewed by a constant // offset of about half a second (value in milliseconds). This has // been confirmed on updated (as of Jun 2011) Windows XP, Windows 7 // and Windows Server 2008 R2 boxes. The unittest below tests this // behavior. enum WINSOCK_TIMEOUT_SKEW = 500; unittest { version(SlowTests) softUnittest({ import std.datetime; enum msecs = 1000; auto pair = socketPair(); auto sock = pair[0]; sock.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"msecs"(msecs)); auto sw = StopWatch(AutoStart.yes); ubyte[1] buf; sock.receive(buf); sw.stop(); Duration readBack = void; sock.getOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, readBack); assert(readBack.total!"msecs" == msecs); assert(sw.peek().msecs > msecs-100 && sw.peek().msecs < msecs+100); }); } void setSock(socket_t handle) { assert(handle != socket_t.init); sock = handle; // Set the option to disable SIGPIPE on send() if the platform // has it (e.g. on OS X). static if (is(typeof(SO_NOSIGPIPE))) { setOption(SocketOptionLevel.SOCKET, cast(SocketOption)SO_NOSIGPIPE, true); } } // For use with accepting(). protected this() pure nothrow @nogc { } public: /** * Create a blocking socket. If a single protocol type exists to support * this socket type within the address family, the $(D ProtocolType) may be * omitted. */ this(AddressFamily af, SocketType type, ProtocolType protocol) @trusted { _family = af; auto handle = cast(socket_t) socket(af, type, protocol); if(handle == socket_t.init) throw new SocketOSException("Unable to create socket"); setSock(handle); } // A single protocol exists to support this socket type within the // protocol family, so the ProtocolType is assumed. /// ditto this(AddressFamily af, SocketType type) { this(af, type, cast(ProtocolType)0); // Pseudo protocol number. } /// ditto this(AddressFamily af, SocketType type, in char[] protocolName) @trusted { protoent* proto; proto = getprotobyname(protocolName.tempCString()); if(!proto) throw new SocketOSException("Unable to find the protocol"); this(af, type, cast(ProtocolType)proto.p_proto); } /** * Create a blocking socket using the parameters from the specified * $(D AddressInfo) structure. */ this(in AddressInfo info) { this(info.family, info.type, info.protocol); } /// Use an existing socket handle. this(socket_t sock, AddressFamily af) pure nothrow @nogc { assert(sock != socket_t.init); this.sock = sock; this._family = af; } ~this() nothrow @nogc { close(); } /// Get underlying socket handle. @property socket_t handle() const pure nothrow @nogc { return sock; } /** * Get/set socket's blocking flag. * * When a socket is blocking, calls to receive(), accept(), and send() * will block and wait for data/action. * A non-blocking socket will immediately return instead of blocking. */ @property bool blocking() @trusted const nothrow @nogc { version(Windows) { return _blocking; } else version(Posix) { return !(fcntl(handle, F_GETFL, 0) & O_NONBLOCK); } } /// ditto @property void blocking(bool byes) @trusted { version(Windows) { uint num = !byes; if(_SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num)) goto err; _blocking = byes; } else version(Posix) { int x = fcntl(sock, F_GETFL, 0); if(-1 == x) goto err; if(byes) x &= ~O_NONBLOCK; else x |= O_NONBLOCK; if(-1 == fcntl(sock, F_SETFL, x)) goto err; } return; // Success. err: throw new SocketOSException("Unable to set socket blocking"); } /// Get the socket's address family. @property AddressFamily addressFamily() { return _family; } /// Property that indicates if this is a valid, alive socket. @property bool isAlive() @trusted const { int type; socklen_t typesize = cast(socklen_t) type.sizeof; return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize); } /// Associate a local address with this socket. void bind(Address addr) @trusted { if(_SOCKET_ERROR == .bind(sock, addr.name, addr.nameLen)) throw new SocketOSException("Unable to bind socket"); } /** * Establish a connection. If the socket is blocking, connect waits for * the connection to be made. If the socket is nonblocking, connect * returns immediately and the connection attempt is still in progress. */ void connect(Address to) @trusted { if(_SOCKET_ERROR == .connect(sock, to.name, to.nameLen)) { int err; err = _lasterr(); if(!blocking) { version(Windows) { if(WSAEWOULDBLOCK == err) return; } else version(Posix) { if(EINPROGRESS == err) return; } else { static assert(0); } } throw new SocketOSException("Unable to connect socket", err); } } /** * Listen for an incoming connection. $(D bind) must be called before you * can $(D listen). The $(D backlog) is a request of how many pending * incoming connections are queued until $(D accept)ed. */ void listen(int backlog) @trusted { if(_SOCKET_ERROR == .listen(sock, backlog)) throw new SocketOSException("Unable to listen on socket"); } /** * Called by $(D accept) when a new $(D Socket) must be created for a new * connection. To use a derived class, override this method and return an * instance of your class. The returned $(D Socket)'s handle must not be * set; $(D Socket) has a protected constructor $(D this()) to use in this * situation. */ // Override to use a derived class. // The returned socket's handle must not be set. protected Socket accepting() pure nothrow { return new Socket; } /** * Accept an incoming connection. If the socket is blocking, $(D accept) * waits for a connection request. Throws $(D SocketAcceptException) if * unable to _accept. See $(D accepting) for use with derived classes. */ Socket accept() @trusted { auto newsock = cast(socket_t).accept(sock, null, null); if(socket_t.init == newsock) throw new SocketAcceptException("Unable to accept socket connection"); Socket newSocket; try { newSocket = accepting(); assert(newSocket.sock == socket_t.init); newSocket.setSock(newsock); version(Windows) newSocket._blocking = _blocking; //inherits blocking mode newSocket._family = _family; //same family } catch(Throwable o) { _close(newsock); throw o; } return newSocket; } /// Disables sends and/or receives. void shutdown(SocketShutdown how) @trusted nothrow @nogc { .shutdown(sock, cast(int)how); } private static void _close(socket_t sock) @system nothrow @nogc { version(Windows) { .closesocket(sock); } else version(Posix) { .close(sock); } } /** * Immediately drop any connections and release socket resources. * Calling $(D shutdown) before $(D close) is recommended for * connection-oriented sockets. The $(D Socket) object is no longer * usable after $(D close). */ //calling shutdown() before this is recommended //for connection-oriented sockets void close() @trusted nothrow @nogc { _close(sock); sock = socket_t.init; } /// Returns the local machine's host name. // Idea from mango. static @property string hostName() @trusted // getter { char[256] result; // Host names are limited to 255 chars. if(_SOCKET_ERROR == .gethostname(result.ptr, result.length)) throw new SocketOSException("Unable to obtain host name"); return to!string(result.ptr); } /// Remote endpoint $(D Address). @property Address remoteAddress() @trusted { Address addr = createAddress(); socklen_t nameLen = addr.nameLen; if(_SOCKET_ERROR == .getpeername(sock, addr.name, &nameLen)) throw new SocketOSException("Unable to obtain remote socket address"); if(nameLen > addr.nameLen) throw new SocketParameterException("Not enough socket address storage"); assert(addr.addressFamily == _family); return addr; } /// Local endpoint $(D Address). @property Address localAddress() @trusted { Address addr = createAddress(); socklen_t nameLen = addr.nameLen; if(_SOCKET_ERROR == .getsockname(sock, addr.name, &nameLen)) throw new SocketOSException("Unable to obtain local socket address"); if(nameLen > addr.nameLen) throw new SocketParameterException("Not enough socket address storage"); assert(addr.addressFamily == _family); return addr; } /** * Send or receive error code. See $(D wouldHaveBlocked), * $(D lastSocketError) and $(D Socket.getErrorText) for obtaining more * information about the error. */ enum int ERROR = _SOCKET_ERROR; /** * Send data on the connection. If the socket is blocking and there is no * buffer space left, $(D send) waits. * Returns: The number of bytes actually sent, or $(D Socket.ERROR) on * failure. */ //returns number of bytes actually sent, or -1 on error ptrdiff_t send(const(void)[] buf, SocketFlags flags) @trusted { static if (is(typeof(MSG_NOSIGNAL))) { flags = cast(SocketFlags)(flags | MSG_NOSIGNAL); } version( Windows ) auto sent = .send(sock, buf.ptr, to!int(buf.length), cast(int)flags); else auto sent = .send(sock, buf.ptr, buf.length, cast(int)flags); return sent; } /// ditto ptrdiff_t send(const(void)[] buf) { return send(buf, SocketFlags.NONE); } /** * Send data to a specific destination Address. If the destination address is * not specified, a connection must have been made and that address is used. * If the socket is blocking and there is no buffer space left, $(D sendTo) waits. * Returns: The number of bytes actually sent, or $(D Socket.ERROR) on * failure. */ ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags, Address to) @trusted { static if (is(typeof(MSG_NOSIGNAL))) { flags = cast(SocketFlags)(flags | MSG_NOSIGNAL); } version( Windows ) return .sendto( sock, buf.ptr, std.conv.to!int(buf.length), cast(int)flags, to.name, to.nameLen ); else return .sendto(sock, buf.ptr, buf.length, cast(int)flags, to.name, to.nameLen); } /// ditto ptrdiff_t sendTo(const(void)[] buf, Address to) { return sendTo(buf, SocketFlags.NONE, to); } //assumes you connect()ed /// ditto ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags) @trusted { static if (is(typeof(MSG_NOSIGNAL))) { flags = cast(SocketFlags)(flags | MSG_NOSIGNAL); } version(Windows) return .sendto(sock, buf.ptr, to!int(buf.length), cast(int)flags, null, 0); else return .sendto(sock, buf.ptr, buf.length, cast(int)flags, null, 0); } //assumes you connect()ed /// ditto ptrdiff_t sendTo(const(void)[] buf) { return sendTo(buf, SocketFlags.NONE); } /** * Receive data on the connection. If the socket is blocking, $(D receive) * waits until there is data to be received. * Returns: The number of bytes actually received, $(D 0) if the remote side * has closed the connection, or $(D Socket.ERROR) on failure. */ //returns number of bytes actually received, 0 on connection closure, or -1 on error ptrdiff_t receive(void[] buf, SocketFlags flags) @trusted { version(Windows) // Does not use size_t { return buf.length ? .recv(sock, buf.ptr, to!int(buf.length), cast(int)flags) : 0; } else { return buf.length ? .recv(sock, buf.ptr, buf.length, cast(int)flags) : 0; } } /// ditto ptrdiff_t receive(void[] buf) { return receive(buf, SocketFlags.NONE); } /** * Receive data and get the remote endpoint $(D Address). * If the socket is blocking, $(D receiveFrom) waits until there is data to * be received. * Returns: The number of bytes actually received, $(D 0) if the remote side * has closed the connection, or $(D Socket.ERROR) on failure. */ ptrdiff_t receiveFrom(void[] buf, SocketFlags flags, ref Address from) @trusted { if(!buf.length) //return 0 and don't think the connection closed return 0; if (from is null || from.addressFamily != _family) from = createAddress(); socklen_t nameLen = from.nameLen; version(Windows) { auto read = .recvfrom(sock, buf.ptr, to!int(buf.length), cast(int)flags, from.name, &nameLen); assert(from.addressFamily == _family); // if(!read) //connection closed return read; } else { auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, from.name, &nameLen); assert(from.addressFamily == _family); // if(!read) //connection closed return read; } } /// ditto ptrdiff_t receiveFrom(void[] buf, ref Address from) { return receiveFrom(buf, SocketFlags.NONE, from); } //assumes you connect()ed /// ditto ptrdiff_t receiveFrom(void[] buf, SocketFlags flags) @trusted { if(!buf.length) //return 0 and don't think the connection closed return 0; version(Windows) { auto read = .recvfrom(sock, buf.ptr, to!int(buf.length), cast(int)flags, null, null); // if(!read) //connection closed return read; } else { auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null); // if(!read) //connection closed return read; } } //assumes you connect()ed /// ditto ptrdiff_t receiveFrom(void[] buf) { return receiveFrom(buf, SocketFlags.NONE); } /// Get a socket option. /// Returns: The number of bytes written to $(D result). //returns the length, in bytes, of the actual result - very different from getsockopt() int getOption(SocketOptionLevel level, SocketOption option, void[] result) @trusted { socklen_t len = cast(socklen_t) result.length; if(_SOCKET_ERROR == .getsockopt(sock, cast(int)level, cast(int)option, result.ptr, &len)) throw new SocketOSException("Unable to get socket option"); return len; } /// Common case of getting integer and boolean options. int getOption(SocketOptionLevel level, SocketOption option, out int32_t result) @trusted { return getOption(level, option, (&result)[0 .. 1]); } /// Get the linger option. int getOption(SocketOptionLevel level, SocketOption option, out Linger result) @trusted { //return getOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]); return getOption(level, option, (&result.clinger)[0 .. 1]); } /// Get a timeout (duration) option. void getOption(SocketOptionLevel level, SocketOption option, out Duration result) @trusted { enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO, new SocketParameterException("Not a valid timeout option: " ~ to!string(option))); // WinSock returns the timeout values as a milliseconds DWORD, // while Linux and BSD return a timeval struct. version (Windows) { int msecs; getOption(level, option, (&msecs)[0 .. 1]); if (option == SocketOption.RCVTIMEO) msecs += WINSOCK_TIMEOUT_SKEW; result = dur!"msecs"(msecs); } else version (Posix) { TimeVal tv; getOption(level, option, (&tv.ctimeval)[0..1]); result = dur!"seconds"(tv.seconds) + dur!"usecs"(tv.microseconds); } else static assert(false); } /// Set a socket option. void setOption(SocketOptionLevel level, SocketOption option, void[] value) @trusted { if(_SOCKET_ERROR == .setsockopt(sock, cast(int)level, cast(int)option, value.ptr, cast(uint) value.length)) throw new SocketOSException("Unable to set socket option"); } /// Common case for setting integer and boolean options. void setOption(SocketOptionLevel level, SocketOption option, int32_t value) @trusted { setOption(level, option, (&value)[0 .. 1]); } /// Set the linger option. void setOption(SocketOptionLevel level, SocketOption option, Linger value) @trusted { //setOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]); setOption(level, option, (&value.clinger)[0 .. 1]); } /** * Sets a timeout (duration) option, i.e. $(D SocketOption.SNDTIMEO) or * $(D RCVTIMEO). Zero indicates no timeout. * * In a typical application, you might also want to consider using * a non-blocking socket instead of setting a timeout on a blocking one. * * Note: While the receive timeout setting is generally quite accurate * on *nix systems even for smaller durations, there are two issues to * be aware of on Windows: First, although undocumented, the effective * timeout duration seems to be the one set on the socket plus half * a second. $(D setOption()) tries to compensate for that, but still, * timeouts under 500ms are not possible on Windows. Second, be aware * that the actual amount of time spent until a blocking call returns * randomly varies on the order of 10ms. * * Params: * level = The level at which a socket option is defined. * option = Either $(D SocketOption.SNDTIMEO) or $(D SocketOption.RCVTIMEO). * value = The timeout duration to set. Must not be negative. * * Throws: $(D SocketException) if setting the options fails. * * Example: * --- * import std.datetime; * auto pair = socketPair(); * scope(exit) foreach (s; pair) s.close(); * * // Set a receive timeout, and then wait at one end of * // the socket pair, knowing that no data will arrive. * pair[0].setOption(SocketOptionLevel.SOCKET, * SocketOption.RCVTIMEO, dur!"seconds"(1)); * * auto sw = StopWatch(AutoStart.yes); * ubyte[1] buffer; * pair[0].receive(buffer); * writefln("Waited %s ms until the socket timed out.", * sw.peek.msecs); * --- */ void setOption(SocketOptionLevel level, SocketOption option, Duration value) @trusted { enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO, new SocketParameterException("Not a valid timeout option: " ~ to!string(option))); enforce(value >= dur!"hnsecs"(0), new SocketParameterException( "Timeout duration must not be negative.")); version (Windows) { import std.algorithm.comparison : max; auto msecs = to!int(value.total!"msecs"); if (msecs != 0 && option == SocketOption.RCVTIMEO) msecs = max(1, msecs - WINSOCK_TIMEOUT_SKEW); setOption(level, option, msecs); } else version (Posix) { _ctimeval tv; value.split!("seconds", "usecs")(tv.tv_sec, tv.tv_usec); setOption(level, option, (&tv)[0 .. 1]); } else static assert(false); } /// Get a text description of this socket's error status, and clear the /// socket's error status. string getErrorText() { int32_t error; getOption(SocketOptionLevel.SOCKET, SocketOption.ERROR, error); return formatSocketError(error); } /** * Enables TCP keep-alive with the specified parameters. * * Params: * time = Number of seconds with no activity until the first * keep-alive packet is sent. * interval = Number of seconds between when successive keep-alive * packets are sent if no acknowledgement is received. * * Throws: $(D SocketOSException) if setting the options fails, or * $(D SocketFeatureException) if setting keep-alive parameters is * unsupported on the current platform. */ void setKeepAlive(int time, int interval) @trusted { version(Windows) { tcp_keepalive options; options.onoff = 1; options.keepalivetime = time * 1000; options.keepaliveinterval = interval * 1000; uint cbBytesReturned; enforce(WSAIoctl(sock, SIO_KEEPALIVE_VALS, &options, options.sizeof, null, 0, &cbBytesReturned, null, null) == 0, new SocketOSException("Error setting keep-alive")); } else static if (is(typeof(TCP_KEEPIDLE)) && is(typeof(TCP_KEEPINTVL))) { setOption(SocketOptionLevel.TCP, cast(SocketOption)TCP_KEEPIDLE, time); setOption(SocketOptionLevel.TCP, cast(SocketOption)TCP_KEEPINTVL, interval); setOption(SocketOptionLevel.SOCKET, SocketOption.KEEPALIVE, true); } else throw new SocketFeatureException("Setting keep-alive options " ~ "is not supported on this platform"); } /** * Wait for a socket to change status. A wait timeout of $(Duration) or * $(D TimeVal), may be specified; if a timeout is not specified or the * $(D TimeVal) is $(D null), the maximum timeout is used. The $(D TimeVal) * timeout has an unspecified value when $(D select) returns. * Returns: The number of sockets with status changes, $(D 0) on timeout, * or $(D -1) on interruption. If the return value is greater than $(D 0), * the $(D SocketSets) are updated to only contain the sockets having status * changes. For a connecting socket, a write status change means the * connection is established and it's able to send. For a listening socket, * a read status change means there is an incoming connection request and * it's able to accept. */ //SocketSet's updated to include only those sockets which an event occured //returns the number of events, 0 on timeout, or -1 on interruption //for a connect()ing socket, writeability means connected //for a listen()ing socket, readability means listening //Winsock: possibly internally limited to 64 sockets per set static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, Duration timeout) @trusted { auto vals = timeout.split!("seconds", "usecs")(); TimeVal tv; tv.seconds = cast(tv.tv_sec_t )vals.seconds; tv.microseconds = cast(tv.tv_usec_t)vals.usecs; return select(checkRead, checkWrite, checkError, &tv); } /// ditto //maximum timeout static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError) { return select(checkRead, checkWrite, checkError, null); } /// Ditto static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, TimeVal* timeout) @trusted in { //make sure none of the SocketSet's are the same object if(checkRead) { assert(checkRead !is checkWrite); assert(checkRead !is checkError); } if(checkWrite) { assert(checkWrite !is checkError); } } body { fd_set* fr, fw, fe; int n = 0; version(Windows) { // Windows has a problem with empty fd_set`s that aren't null. fr = checkRead && checkRead.count ? checkRead.toFd_set() : null; fw = checkWrite && checkWrite.count ? checkWrite.toFd_set() : null; fe = checkError && checkError.count ? checkError.toFd_set() : null; } else { if(checkRead) { fr = checkRead.toFd_set(); n = checkRead.selectn(); } else { fr = null; } if(checkWrite) { fw = checkWrite.toFd_set(); int _n; _n = checkWrite.selectn(); if(_n > n) n = _n; } else { fw = null; } if(checkError) { fe = checkError.toFd_set(); int _n; _n = checkError.selectn(); if(_n > n) n = _n; } else { fe = null; } // Make sure the sets' capacity matches, to avoid select reading // out of bounds just because one set was bigger than another if (checkRead ) checkRead .setMinCapacity(n); if (checkWrite) checkWrite.setMinCapacity(n); if (checkError) checkError.setMinCapacity(n); } int result = .select(n, fr, fw, fe, &timeout.ctimeval); version(Windows) { if(_SOCKET_ERROR == result && WSAGetLastError() == WSAEINTR) return -1; } else version(Posix) { if(_SOCKET_ERROR == result && errno == EINTR) return -1; } else { static assert(0); } if(_SOCKET_ERROR == result) throw new SocketOSException("Socket select error"); return result; } /// Returns a new Address object for the current address family. /// Can be overridden to support other addresses. protected Address createAddress() pure nothrow { Address result; switch(_family) { static if (is(sockaddr_un)) { case AddressFamily.UNIX: result = new UnixAddress; break; } case AddressFamily.INET: result = new InternetAddress; break; case AddressFamily.INET6: result = new Internet6Address; break; default: result = new UnknownAddress; } return result; } } /// $(D TcpSocket) is a shortcut class for a TCP Socket. class TcpSocket: Socket { /// Constructs a blocking TCP Socket. this(AddressFamily family) { super(family, SocketType.STREAM, ProtocolType.TCP); } /// Constructs a blocking IPv4 TCP Socket. this() { this(AddressFamily.INET); } //shortcut /// Constructs a blocking TCP Socket and connects to an $(D Address). this(Address connectTo) { this(connectTo.addressFamily); connect(connectTo); } } /// $(D UdpSocket) is a shortcut class for a UDP Socket. class UdpSocket: Socket { /// Constructs a blocking UDP Socket. this(AddressFamily family) { super(family, SocketType.DGRAM, ProtocolType.UDP); } /// Constructs a blocking IPv4 UDP Socket. this() { this(AddressFamily.INET); } } /** * Creates a pair of connected sockets. * * The two sockets are indistinguishable. * * Throws: $(D SocketException) if creation of the sockets fails. * * Example: * --- * immutable ubyte[] data = [1, 2, 3, 4]; * auto pair = socketPair(); * scope(exit) foreach (s; pair) s.close(); * * pair[0].send(data); * * auto buf = new ubyte[data.length]; * pair[1].receive(buf); * assert(buf == data); * --- */ Socket[2] socketPair() @trusted { version(Posix) { int[2] socks; if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1) throw new SocketOSException("Unable to create socket pair"); Socket toSocket(size_t id) { auto s = new Socket; s.setSock(cast(socket_t)socks[id]); s._family = AddressFamily.UNIX; return s; } return [toSocket(0), toSocket(1)]; } else version(Windows) { // We do not have socketpair() on Windows, just manually create a // pair of sockets connected over some localhost port. Socket[2] result; auto listener = new TcpSocket(); listener.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true); listener.bind(new InternetAddress(INADDR_LOOPBACK, InternetAddress.PORT_ANY)); auto addr = listener.localAddress; listener.listen(1); result[0] = new TcpSocket(addr); result[1] = listener.accept(); listener.close(); return result; } else static assert(false); } unittest { immutable ubyte[] data = [1, 2, 3, 4]; auto pair = socketPair(); scope(exit) foreach (s; pair) s.close(); pair[0].send(data); auto buf = new ubyte[data.length]; pair[1].receive(buf); assert(buf == data); } ldc-1.1.0-beta3-src/runtime/phobos/std/typecons.d0000664000175000017500000057741412776215007017741 0ustar kaikai// Written in the D programming language. /** This module implements a variety of type constructors, i.e., templates that allow construction of new, useful general-purpose types. Source: $(PHOBOSSRC std/_typecons.d) Macros: WIKI = Phobos/StdVariant Synopsis: ---- // value tuples alias Coord = Tuple!(float, "x", float, "y", float, "z"); Coord c; c[1] = 1; // access by index c.z = 1; // access by given name alias DicEntry = Tuple!(string, string); // names can be omitted // Rebindable references to const and immutable objects void bar() { const w1 = new Widget, w2 = new Widget; w1.foo(); // w1 = w2 would not work; can't rebind const object auto r = Rebindable!(const Widget)(w1); // invoke method as if r were a Widget object r.foo(); // rebind r to refer to another object r = w2; } ---- Copyright: Copyright the respective authors, 2008- License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.org, Andrei Alexandrescu), $(WEB bartoszmilewski.wordpress.com, Bartosz Milewski), Don Clugston, Shin Fujishiro, Kenji Hara */ module std.typecons; import std.meta; // : AliasSeq, allSatisfy; import std.traits; debug(Unique) import std.stdio; /** Encapsulates unique ownership of a resource. Resource of type $(D T) is deleted at the end of the scope, unless it is transferred. The transfer can be explicit, by calling $(D release), or implicit, when returning Unique from a function. The resource can be a polymorphic class object, in which case Unique behaves polymorphically too. */ struct Unique(T) { /** Represents a reference to $(D T). Resolves to $(D T*) if $(D T) is a value type. */ static if (is(T:Object)) alias RefT = T; else alias RefT = T*; public: // Deferred in case we get some language support for checking uniqueness. version(None) /** Allows safe construction of $(D Unique). It creates the resource and guarantees unique ownership of it (unless $(D T) publishes aliases of $(D this)). Note: Nested structs/classes cannot be created. Params: args = Arguments to pass to $(D T)'s constructor. --- static class C {} auto u = Unique!(C).create(); --- */ static Unique!T create(A...)(auto ref A args) if (__traits(compiles, new T(args))) { debug(Unique) writeln("Unique.create for ", T.stringof); Unique!T u; u._p = new T(args); return u; } /** Constructor that takes an rvalue. It will ensure uniqueness, as long as the rvalue isn't just a view on an lvalue (e.g., a cast). Typical usage: ---- Unique!Foo f = new Foo; ---- */ this(RefT p) { debug(Unique) writeln("Unique constructor with rvalue"); _p = p; } /** Constructor that takes an lvalue. It nulls its source. The nulling will ensure uniqueness as long as there are no previous aliases to the source. */ this(ref RefT p) { _p = p; debug(Unique) writeln("Unique constructor nulling source"); p = null; assert(p is null); } /** Constructor that takes a $(D Unique) of a type that is convertible to our type. Typically used to transfer a $(D Unique) rvalue of derived type to a $(D Unique) of base type. Example: --- class C : Object {} Unique!C uc = new C; Unique!Object uo = uc.release; --- */ this(U)(Unique!U u) if (is(u.RefT:RefT)) { debug(Unique) writeln("Unique constructor converting from ", U.stringof); _p = u._p; u._p = null; } /// Transfer ownership from a $(D Unique) of a type that is convertible to our type. void opAssign(U)(Unique!U u) if (is(u.RefT:RefT)) { debug(Unique) writeln("Unique opAssign converting from ", U.stringof); // first delete any resource we own destroy(this); _p = u._p; u._p = null; } ~this() { debug(Unique) writeln("Unique destructor of ", (_p is null)? null: _p); if (_p !is null) delete _p; _p = null; } /** Returns whether the resource exists. */ @property bool isEmpty() const { return _p is null; } /** Transfer ownership to a $(D Unique) rvalue. Nullifies the current contents. */ Unique release() { debug(Unique) writeln("Release"); auto u = Unique(_p); assert(_p is null); debug(Unique) writeln("return from Release"); return u; } /** Forwards member access to contents. */ RefT opDot() { return _p; } /** Postblit operator is undefined to prevent the cloning of $(D Unique) objects. */ @disable this(this); private: RefT _p; } /// unittest { static struct S { int i; this(int i){this.i = i;} } Unique!S produce() { // Construct a unique instance of S on the heap Unique!S ut = new S(5); // Implicit transfer of ownership return ut; } // Borrow a unique resource by ref void increment(ref Unique!S ur) { ur.i++; } void consume(Unique!S u2) { assert(u2.i == 6); // Resource automatically deleted here } Unique!S u1; assert(u1.isEmpty); u1 = produce(); increment(u1); assert(u1.i == 6); //consume(u1); // Error: u1 is not copyable // Transfer ownership of the resource consume(u1.release); assert(u1.isEmpty); } unittest { // test conversion to base ref int deleted = 0; class C { ~this(){deleted++;} } // constructor conversion Unique!Object u = Unique!C(new C); static assert(!__traits(compiles, {u = new C;})); assert(!u.isEmpty); destroy(u); assert(deleted == 1); Unique!C uc = new C; static assert(!__traits(compiles, {Unique!Object uo = uc;})); Unique!Object uo = new C; // opAssign conversion, deleting uo resource first uo = uc.release; assert(uc.isEmpty); assert(!uo.isEmpty); assert(deleted == 2); } unittest { debug(Unique) writeln("Unique class"); class Bar { ~this() { debug(Unique) writeln(" Bar destructor"); } int val() const { return 4; } } alias UBar = Unique!(Bar); UBar g(UBar u) { debug(Unique) writeln("inside g"); return u.release; } auto ub = UBar(new Bar); assert(!ub.isEmpty); assert(ub.val == 4); static assert(!__traits(compiles, {auto ub3 = g(ub);})); debug(Unique) writeln("Calling g"); auto ub2 = g(ub.release); debug(Unique) writeln("Returned from g"); assert(ub.isEmpty); assert(!ub2.isEmpty); } unittest { debug(Unique) writeln("Unique struct"); struct Foo { ~this() { debug(Unique) writeln(" Foo destructor"); } int val() const { return 3; } } alias UFoo = Unique!(Foo); UFoo f(UFoo u) { debug(Unique) writeln("inside f"); return u.release; } auto uf = UFoo(new Foo); assert(!uf.isEmpty); assert(uf.val == 3); static assert(!__traits(compiles, {auto uf3 = f(uf);})); debug(Unique) writeln("Unique struct: calling f"); auto uf2 = f(uf.release); debug(Unique) writeln("Unique struct: returned from f"); assert(uf.isEmpty); assert(!uf2.isEmpty); } // Used in Tuple.toString private template sharedToString(alias field) if(is(typeof(field) == shared)) { static immutable sharedToString = typeof(field).stringof; } private template sharedToString(alias field) if(!is(typeof(field) == shared)) { alias sharedToString = field; } /** Tuple of values, for example $(D Tuple!(int, string)) is a record that stores an $(D int) and a $(D string). $(D Tuple) can be used to bundle values together, notably when returning multiple values from a function. If $(D obj) is a `Tuple`, the individual members are accessible with the syntax $(D obj[0]) for the first field, $(D obj[1]) for the second, and so on. The choice of zero-based indexing instead of one-base indexing was motivated by the ability to use value `Tuple`s with various compile-time loop constructs (e.g. $(XREF meta, AliasSeq) iteration), all of which use zero-based indexing. Params: Specs = A list of types (and optionally, member names) that the `Tuple` contains. */ template Tuple(Specs...) { import std.meta : staticMap; // Parse (type,name) pairs (FieldSpecs) out of the specified // arguments. Some fields would have name, others not. template parseSpecs(Specs...) { static if (Specs.length == 0) { alias parseSpecs = AliasSeq!(); } else static if (is(Specs[0])) { static if (is(typeof(Specs[1]) : string)) { alias parseSpecs = AliasSeq!(FieldSpec!(Specs[0 .. 2]), parseSpecs!(Specs[2 .. $])); } else { alias parseSpecs = AliasSeq!(FieldSpec!(Specs[0]), parseSpecs!(Specs[1 .. $])); } } else { static assert(0, "Attempted to instantiate Tuple with an " ~"invalid argument: "~ Specs[0].stringof); } } template FieldSpec(T, string s = "") { alias Type = T; alias name = s; } alias fieldSpecs = parseSpecs!Specs; // Used with staticMap. alias extractType(alias spec) = spec.Type; alias extractName(alias spec) = spec.name; // Generates named fields as follows: // alias name_0 = Identity!(field[0]); // alias name_1 = Identity!(field[1]); // : // NOTE: field[k] is an expression (which yields a symbol of a // variable) and can't be aliased directly. string injectNamedFields() { string decl = ""; foreach (i, name; staticMap!(extractName, fieldSpecs)) { import std.format : format; decl ~= format("alias _%s = Identity!(field[%s]);", i, i); if (name.length != 0) { decl ~= format("alias %s = _%s;", name, i); } } return decl; } // Returns Specs for a subtuple this[from .. to] preserving field // names if any. alias sliceSpecs(size_t from, size_t to) = staticMap!(expandSpec, fieldSpecs[from .. to]); template expandSpec(alias spec) { static if (spec.name.length == 0) { alias expandSpec = AliasSeq!(spec.Type); } else { alias expandSpec = AliasSeq!(spec.Type, spec.name); } } enum areCompatibleTuples(Tup1, Tup2, string op) = isTuple!Tup2 && is(typeof( (ref Tup1 tup1, ref Tup2 tup2) { static assert(tup1.field.length == tup2.field.length); foreach (i, _; Tup1.Types) { auto lhs = typeof(tup1.field[i]).init; auto rhs = typeof(tup2.field[i]).init; static if (op == "=") lhs = rhs; else auto result = mixin("lhs "~op~" rhs"); } })); enum areBuildCompatibleTuples(Tup1, Tup2) = isTuple!Tup2 && is(typeof( { static assert(Tup1.Types.length == Tup2.Types.length); foreach (i, _; Tup1.Types) static assert(isBuildable!(Tup1.Types[i], Tup2.Types[i])); })); /+ Returns $(D true) iff a $(D T) can be initialized from a $(D U). +/ enum isBuildable(T, U) = is(typeof( { U u = U.init; T t = u; })); /+ Helper for partial instanciation +/ template isBuildableFrom(U) { enum isBuildableFrom(T) = isBuildable!(T, U); } struct Tuple { /** * The types of the `Tuple`'s components. */ alias Types = staticMap!(extractType, fieldSpecs); /// unittest { alias Fields = Tuple!(int, "id", string, float); static assert(is(Fields.Types == AliasSeq!(int, string, float))); } /** * The names of the `Tuple`'s components. Unnamed fields have empty names. */ alias fieldNames = staticMap!(extractName, fieldSpecs); /// unittest { alias Fields = Tuple!(int, "id", string, float); static assert(Fields.fieldNames == AliasSeq!("id", "", "")); } /** * Use $(D t.expand) for a `Tuple` $(D t) to expand it into its * components. The result of $(D expand) acts as if the `Tuple`'s components * were listed as a list of values. (Ordinarily, a $(D Tuple) acts as a * single value.) */ Types expand; mixin(injectNamedFields()); /// unittest { auto t1 = tuple(1, " hello ", 2.3); assert(t1.toString() == `Tuple!(int, string, double)(1, " hello ", 2.3)`); void takeSeveralTypes(int n, string s, bool b) { assert(n == 4 && s == "test" && b == false); } auto t2 = tuple(4, "test", false); //t.expand acting as a list of values takeSeveralTypes(t2.expand); } static if (is(Specs)) { // This is mostly to make t[n] work. alias expand this; } else { @property ref inout(Tuple!Types) _Tuple_super() inout @trusted { foreach (i, _; Types) // Rely on the field layout { static assert(typeof(return).init.tupleof[i].offsetof == expand[i].offsetof); } return *cast(typeof(return)*) &(field[0]); } // This is mostly to make t[n] work. alias _Tuple_super this; } // backwards compatibility alias field = expand; /** * Constructor taking one value for each field. * * Params: * values = A list of values that are either the same * types as those given by the `Types` field * of this `Tuple`, or can implicitly convert * to those types. They must be in the same * order as they appear in `Types`. */ static if (Types.length > 0) { this(Types values) { field[] = values[]; } } /// unittest { alias ISD = Tuple!(int, string, double); auto tup = ISD(1, "test", 3.2); assert(tup.toString() == `Tuple!(int, string, double)(1, "test", 3.2)`); } /** * Constructor taking a compatible array. * * Params: * values = A compatible static array to build the `Tuple` from. * Array slices are not supported. */ this(U, size_t n)(U[n] values) if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types)) { foreach (i, _; Types) { field[i] = values[i]; } } /// unittest { int[2] ints; Tuple!(int, int) t = ints; } /** * Constructor taking a compatible `Tuple`. Two `Tuple`s are compatible * $(B iff) they are both of the same length, and, for each type `T` on the * left-hand side, the corresponding type `U` on the right-hand side can * implicitly convert to `T`. * * Params: * another = A compatible `Tuple` to build from. Its type must be * compatible with the target `Tuple`'s type. */ this(U)(U another) if (areBuildCompatibleTuples!(typeof(this), U)) { field[] = another.field[]; } /// unittest { alias IntVec = Tuple!(int, int, int); alias DubVec = Tuple!(double, double, double); IntVec iv = tuple(1, 1, 1); //Ok, int can implicitly convert to double DubVec dv = iv; //Error: double cannot implicitly convert to int //IntVec iv2 = dv; } /** * Comparison for equality. Two `Tuple`s are considered equal * $(B iff) they fulfill the following criteria: * * $(UL * $(LI Each `Tuple` is the same length.) * $(LI For each type `T` on the left-hand side and each type * `U` on the right-hand side, values of type `T` can be * compared with values of type `U`.) * $(LI For each value `v1` on the left-hand side and each value * `v2` on the right-hand side, the expression `v1 == v2` is * true.)) * * Params: * rhs = The `Tuple` to compare against. It must meeting the criteria * for comparison between `Tuple`s. * * Returns: * true if both `Tuple`s are equal, otherwise false. */ bool opEquals(R)(R rhs) if (areCompatibleTuples!(typeof(this), R, "==")) { return field[] == rhs.field[]; } /// ditto bool opEquals(R)(R rhs) const if (areCompatibleTuples!(typeof(this), R, "==")) { return field[] == rhs.field[]; } /// unittest { Tuple!(int, string) t1 = tuple(1, "test"); Tuple!(double, string) t2 = tuple(1.0, "test"); //Ok, int can be compared with double and //both have a value of 1 assert(t1 == t2); } /** * Comparison for ordering. * * Params: * rhs = The `Tuple` to compare against. It must meet the criteria * for comparison between `Tuple`s. * * Returns: * For any values `v1` on the right-hand side and `v2` on the * left-hand side: * * $(UL * $(LI A negative integer if the expression `v1 < v2` is true.) * $(LI A positive integer if the expression `v1 > v2` is true.) * $(LI 0 if the expression `v1 == v2` is true.)) */ int opCmp(R)(R rhs) if (areCompatibleTuples!(typeof(this), R, "<")) { foreach (i, Unused; Types) { if (field[i] != rhs.field[i]) { return field[i] < rhs.field[i] ? -1 : 1; } } return 0; } /// ditto int opCmp(R)(R rhs) const if (areCompatibleTuples!(typeof(this), R, "<")) { foreach (i, Unused; Types) { if (field[i] != rhs.field[i]) { return field[i] < rhs.field[i] ? -1 : 1; } } return 0; } /** The first `v1` for which `v1 > v2` is true determines the result. This could lead to unexpected behaviour. */ unittest { auto tup1 = tuple(1, 1, 1); auto tup2 = tuple(1, 100, 100); assert(tup1 < tup2); //Only the first result matters for comparison tup1[0] = 2; assert(tup1 > tup2); } /** * Assignment from another `Tuple`. * * Params: * rhs = The source `Tuple` to assign from. Each element of the * source `Tuple` must be implicitly assignable to each * respective element of the target `Tuple`. */ void opAssign(R)(auto ref R rhs) if (areCompatibleTuples!(typeof(this), R, "=")) { import std.algorithm : swap; static if (is(R : Tuple!Types) && !__traits(isRef, rhs)) { if (__ctfe) { // Cannot use swap at compile time field[] = rhs.field[]; } else { // Use swap-and-destroy to optimize rvalue assignment swap!(Tuple!Types)(this, rhs); } } else { // Do not swap; opAssign should be called on the fields. field[] = rhs.field[]; } } /** * Takes a slice of this `Tuple`. * * Params: * from = A `size_t` designating the starting position of the slice. * to = A `size_t` designating the ending position (exclusive) of the slice. * * Returns: * A new `Tuple` that is a slice from `[from, to$(RPAREN)` of the original. * It has the same types and values as the range `[from, to$(RPAREN)` in * the original. */ @property ref Tuple!(sliceSpecs!(from, to)) slice(size_t from, size_t to)() @trusted if (from <= to && to <= Types.length) { return *cast(typeof(return)*) &(field[from]); } /// unittest { Tuple!(int, string, float, double) a; a[1] = "abc"; a[2] = 4.5; auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); assert(s[0] == "abc" && s[1] == 4.5); } /** Creates a hash of this `Tuple`. Returns: A `size_t` representing the hash of this `Tuple`. */ size_t toHash() const nothrow @trusted { size_t h = 0; foreach (i, T; Types) h += typeid(T).getHash(cast(const void*)&field[i]); return h; } /// template toString() { /** * Converts to string. * * Returns: * The string representation of this `Tuple`. */ string toString()() const { import std.array : appender; auto app = appender!string(); this.toString((const(char)[] chunk) => app ~= chunk); return app.data; } import std.format : FormatSpec; /** * Formats `Tuple` with either `%s`, `%(inner%)` or `%(inner%|sep%)`. * * $(TABLE2 Formats supported by Tuple, * $(THEAD Format, Description) * $(TROW $(P `%s`), $(P Format like `Tuple!(types)(elements formatted with %s each)`.)) * $(TROW $(P `%(inner%)`), $(P The format `inner` is applied the expanded `Tuple`, so * it may contain as many formats as the `Tuple` has fields.)) * $(TROW $(P `%(inner%|sep%)`), $(P The format `inner` is one format, that is applied * on all fields of the `Tuple`. The inner format must be compatible to all * of them.))) * --- * Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ]; * * // Default format * assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`); * * // One Format for each individual component * assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10)) == `0x1 v 1.0000 w 0xa`); * assert(format( "%#x v %.4f w %#x" , tuple(1, 1.0, 10).expand) == `0x1 v 1.0000 w 0xa`); * * // One Format for all components * assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`); * * // Array of Tuples * assert(format("%(%(f(%d) = %.1f%); %)", tupList) == `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`); * * * // Error: %( %) missing. * assertThrown!FormatException( * format("%d, %f", tuple(1, 2.0)) == `1, 2.0` * ); * * // Error: %( %| %) missing. * assertThrown!FormatException( * format("%d", tuple(1, 2)) == `1, 2` * ); * * // Error: %d inadequate for double. * assertThrown!FormatException( * format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0` * ); * --- */ void toString(DG)(scope DG sink) const { toString(sink, FormatSpec!char()); } /// ditto void toString(DG, Char)(scope DG sink, FormatSpec!Char fmt) const { import std.format : formatElement, formattedWrite, FormatException; if (fmt.nested) { if (fmt.sep) { foreach (i, Type; Types) { static if (i > 0) { sink(fmt.sep); } // TODO: Change this once formattedWrite() works for shared objects. static if (is(Type == class) && is(Type == shared)) { sink(Type.stringof); } else { formattedWrite(sink, fmt.nested, this.field[i]); } } } else { formattedWrite(sink, fmt.nested, staticMap!(sharedToString, this.expand)); } } else if (fmt.spec == 's') { enum header = Unqual!(typeof(this)).stringof ~ "(", footer = ")", separator = ", "; sink(header); foreach (i, Type; Types) { static if (i > 0) { sink(separator); } // TODO: Change this once formatElement() works for shared objects. static if (is(Type == class) && is(Type == shared)) { sink(Type.stringof); } else { FormatSpec!Char f; formatElement(sink, field[i], f); } } sink(footer); } else { throw new FormatException( "Expected '%s' or '%(...%)' or '%(...%|...%)' format specifier for type '" ~ Unqual!(typeof(this)).stringof ~ "', not '%" ~ fmt.spec ~ "'."); } } } } } /// unittest { Tuple!(int, int) point; // assign coordinates point[0] = 5; point[1] = 6; // read coordinates auto x = point[0]; auto y = point[1]; } /** `Tuple` members can be named. It is legal to mix named and unnamed members. The method above is still applicable to all fields. */ unittest { alias Entry = Tuple!(int, "index", string, "value"); Entry e; e.index = 4; e.value = "Hello"; assert(e[1] == "Hello"); assert(e[0] == 4); } /** A `Tuple` with named fields is a distinct type from a `Tuple` with unnamed fields, i.e. each naming imparts a separate type for the `Tuple`. Two `Tuple`s differing in naming only are still distinct, even though they might have the same structure. */ unittest { Tuple!(int, "x", int, "y") point1; Tuple!(int, int) point2; assert(!is(typeof(point1) == typeof(point2))); } /** Create a copy of a `Tuple` with its fields in reverse order. Params: t = The `Tuple` to copy. Returns: A copy of `t` with its fields in reverse order. */ ReverseTupleType!T reverse(T)(T t) if (isTuple!T) { import std.meta : Reverse; // @@@BUG@@@ Cannot be an internal function due to forward reference issues. // @@@BUG@@@ 9929 Need 'this' when calling template with expanded tuple // return tuple(Reverse!(t.expand)); typeof(return) result; auto tup = t.expand; result.expand = Reverse!tup; return result; } /// unittest { auto tup = tuple(1, "2"); assert(tup.reverse == tuple("2", 1)); } /* Get a Tuple type with the reverse specification of Tuple T. */ private template ReverseTupleType(T) if (isTuple!T) { static if (is(T : Tuple!A, A...)) alias ReverseTupleType = Tuple!(ReverseTupleSpecs!A); } /* Reverse the Specs of a Tuple. */ private template ReverseTupleSpecs(T...) { static if (T.length > 1) { static if (is(typeof(T[$-1]) : string)) { alias ReverseTupleSpecs = AliasSeq!(T[$-2], T[$-1], ReverseTupleSpecs!(T[0 .. $-2])); } else { alias ReverseTupleSpecs = AliasSeq!(T[$-1], ReverseTupleSpecs!(T[0 .. $-1])); } } else { alias ReverseTupleSpecs = T; } } unittest { import std.conv; { Tuple!(int, "a", int, "b") nosh; static assert(nosh.length == 2); nosh.a = 5; nosh.b = 6; assert(nosh.a == 5); assert(nosh.b == 6); } { Tuple!(short, double) b; static assert(b.length == 2); b[1] = 5; auto a = Tuple!(int, real)(b); assert(a[0] == 0 && a[1] == 5); a = Tuple!(int, real)(1, 2); assert(a[0] == 1 && a[1] == 2); auto c = Tuple!(int, "a", double, "b")(a); assert(c[0] == 1 && c[1] == 2); } { Tuple!(int, real) nosh; nosh[0] = 5; nosh[1] = 0; assert(nosh[0] == 5 && nosh[1] == 0); assert(nosh.to!string == "Tuple!(int, real)(5, 0)", nosh.to!string); Tuple!(int, int) yessh; nosh = yessh; } { class A {} Tuple!(int, shared A) nosh; nosh[0] = 5; assert(nosh[0] == 5 && nosh[1] is null); assert(nosh.to!string == "Tuple!(int, shared(A))(5, shared(A))"); } { Tuple!(int, string) t; t[0] = 10; t[1] = "str"; assert(t[0] == 10 && t[1] == "str"); assert(t.to!string == `Tuple!(int, string)(10, "str")`, t.to!string); } { Tuple!(int, "a", double, "b") x; static assert(x.a.offsetof == x[0].offsetof); static assert(x.b.offsetof == x[1].offsetof); x.b = 4.5; x.a = 5; assert(x[0] == 5 && x[1] == 4.5); assert(x.a == 5 && x.b == 4.5); } // indexing { Tuple!(int, real) t; static assert(is(typeof(t[0]) == int)); static assert(is(typeof(t[1]) == real)); int* p0 = &t[0]; real* p1 = &t[1]; t[0] = 10; t[1] = -200.0L; assert(*p0 == t[0]); assert(*p1 == t[1]); } // slicing { Tuple!(int, "x", real, "y", double, "z", string) t; t[0] = 10; t[1] = 11; t[2] = 12; t[3] = "abc"; auto a = t.slice!(0, 3); assert(a.length == 3); assert(a.x == t.x); assert(a.y == t.y); assert(a.z == t.z); auto b = t.slice!(2, 4); assert(b.length == 2); assert(b.z == t.z); assert(b[1] == t[3]); } // nesting { Tuple!(Tuple!(int, real), Tuple!(string, "s")) t; static assert(is(typeof(t[0]) == Tuple!(int, real))); static assert(is(typeof(t[1]) == Tuple!(string, "s"))); static assert(is(typeof(t[0][0]) == int)); static assert(is(typeof(t[0][1]) == real)); static assert(is(typeof(t[1].s) == string)); t[0] = tuple(10, 20.0L); t[1].s = "abc"; assert(t[0][0] == 10); assert(t[0][1] == 20.0L); assert(t[1].s == "abc"); } // non-POD { static struct S { int count; this(this) { ++count; } ~this() { --count; } void opAssign(S rhs) { count = rhs.count; } } Tuple!(S, S) ss; Tuple!(S, S) ssCopy = ss; assert(ssCopy[0].count == 1); assert(ssCopy[1].count == 1); ssCopy[1] = ssCopy[0]; assert(ssCopy[1].count == 2); } // bug 2800 { static struct R { Tuple!(int, int) _front; @property ref Tuple!(int, int) front() return { return _front; } @property bool empty() { return _front[0] >= 10; } void popFront() { ++_front[0]; } } foreach (a; R()) { static assert(is(typeof(a) == Tuple!(int, int))); assert(0 <= a[0] && a[0] < 10); assert(a[1] == 0); } } // Construction with compatible elements { auto t1 = Tuple!(int, double)(1, 1); // 8702 auto t8702a = tuple(tuple(1)); auto t8702b = Tuple!(Tuple!(int))(Tuple!(int)(1)); } // Construction with compatible tuple { Tuple!(int, int) x; x[0] = 10; x[1] = 20; Tuple!(int, "a", double, "b") y = x; assert(y.a == 10); assert(y.b == 20); // incompatible static assert(!__traits(compiles, Tuple!(int, int)(y))); } // 6275 { const int x = 1; auto t1 = tuple(x); alias T = Tuple!(const(int)); auto t2 = T(1); } // 9431 { alias T = Tuple!(int[1][]); auto t = T([[10]]); } // 7666 { auto tup = tuple(1, "2"); assert(tup.reverse == tuple("2", 1)); } { Tuple!(int, "x", string, "y") tup = tuple(1, "2"); auto rev = tup.reverse; assert(rev == tuple("2", 1)); assert(rev.x == 1 && rev.y == "2"); } { Tuple!(wchar, dchar, int, "x", string, "y", char, byte, float) tup; tup = tuple('a', 'b', 3, "4", 'c', cast(byte)0x0D, 0.00); auto rev = tup.reverse; assert(rev == tuple(0.00, cast(byte)0x0D, 'c', "4", 3, 'b', 'a')); assert(rev.x == 3 && rev.y == "4"); } } unittest { // opEquals { struct Equ1 { bool opEquals(Equ1) { return true; } } auto tm1 = tuple(Equ1.init); const tc1 = tuple(Equ1.init); static assert( is(typeof(tm1 == tm1))); static assert(!is(typeof(tm1 == tc1))); static assert(!is(typeof(tc1 == tm1))); static assert(!is(typeof(tc1 == tc1))); struct Equ2 { bool opEquals(const Equ2) const { return true; } } auto tm2 = tuple(Equ2.init); const tc2 = tuple(Equ2.init); static assert( is(typeof(tm2 == tm2))); static assert( is(typeof(tm2 == tc2))); static assert( is(typeof(tc2 == tm2))); static assert( is(typeof(tc2 == tc2))); struct Equ3 { bool opEquals(T)(T) { return true; } } auto tm3 = tuple(Equ3.init); // bugzilla 8686 const tc3 = tuple(Equ3.init); static assert( is(typeof(tm3 == tm3))); static assert( is(typeof(tm3 == tc3))); static assert(!is(typeof(tc3 == tm3))); static assert(!is(typeof(tc3 == tc3))); struct Equ4 { bool opEquals(T)(T) const { return true; } } auto tm4 = tuple(Equ4.init); const tc4 = tuple(Equ4.init); static assert( is(typeof(tm4 == tm4))); static assert( is(typeof(tm4 == tc4))); static assert( is(typeof(tc4 == tm4))); static assert( is(typeof(tc4 == tc4))); } // opCmp { struct Cmp1 { int opCmp(Cmp1) { return 0; } } auto tm1 = tuple(Cmp1.init); const tc1 = tuple(Cmp1.init); static assert( is(typeof(tm1 < tm1))); static assert(!is(typeof(tm1 < tc1))); static assert(!is(typeof(tc1 < tm1))); static assert(!is(typeof(tc1 < tc1))); struct Cmp2 { int opCmp(const Cmp2) const { return 0; } } auto tm2 = tuple(Cmp2.init); const tc2 = tuple(Cmp2.init); static assert( is(typeof(tm2 < tm2))); static assert( is(typeof(tm2 < tc2))); static assert( is(typeof(tc2 < tm2))); static assert( is(typeof(tc2 < tc2))); struct Cmp3 { int opCmp(T)(T) { return 0; } } auto tm3 = tuple(Cmp3.init); const tc3 = tuple(Cmp3.init); static assert( is(typeof(tm3 < tm3))); static assert( is(typeof(tm3 < tc3))); static assert(!is(typeof(tc3 < tm3))); static assert(!is(typeof(tc3 < tc3))); struct Cmp4 { int opCmp(T)(T) const { return 0; } } auto tm4 = tuple(Cmp4.init); const tc4 = tuple(Cmp4.init); static assert( is(typeof(tm4 < tm4))); static assert( is(typeof(tm4 < tc4))); static assert( is(typeof(tc4 < tm4))); static assert( is(typeof(tc4 < tc4))); } // Bugzilla 14890 static void test14890(inout int[] dummy) { alias V = Tuple!(int, int); V mv; const V cv; immutable V iv; inout V wv; // OK <- NG inout const V wcv; // OK <- NG foreach (v1; AliasSeq!(mv, cv, iv, wv, wcv)) foreach (v2; AliasSeq!(mv, cv, iv, wv, wcv)) { assert(!(v1 < v2)); } } { int[2] ints = [ 1, 2 ]; Tuple!(int, int) t = ints; assert(t[0] == 1 && t[1] == 2); Tuple!(long, uint) t2 = ints; assert(t2[0] == 1 && t2[1] == 2); } } @safe unittest { auto t1 = Tuple!(int, "x", string, "y")(1, "a"); assert(t1.x == 1); assert(t1.y == "a"); void foo(Tuple!(int, string) t2) {} foo(t1); Tuple!(int, int)[] arr; arr ~= tuple(10, 20); // OK arr ~= Tuple!(int, "x", int, "y")(10, 20); // NG -> OK static assert(is(typeof(Tuple!(int, "x", string, "y").tupleof) == typeof(Tuple!(int, string ).tupleof))); } unittest { // Bugzilla 10686 immutable Tuple!(int) t1; auto r1 = t1[0]; // OK immutable Tuple!(int, "x") t2; auto r2 = t2[0]; // error } unittest { import std.exception : assertCTFEable; // Bugzilla 10218 assertCTFEable!( { auto t = tuple(1); t = tuple(2); // assignment }); } unittest { class Foo{} Tuple!(immutable(Foo)[]) a; } unittest { //Test non-assignable static struct S { int* p; } alias IS = immutable S; static assert(!isAssignable!IS); auto s = IS.init; alias TIS = Tuple!IS; TIS a = tuple(s); TIS b = a; alias TISIS = Tuple!(IS, IS); TISIS d = tuple(s, s); IS[2] ss; TISIS e = TISIS(ss); } // Bugzilla #9819 unittest { alias T = Tuple!(int, "x", double, "foo"); static assert(T.fieldNames[0] == "x"); static assert(T.fieldNames[1] == "foo"); alias Fields = Tuple!(int, "id", string, float); static assert(Fields.fieldNames == AliasSeq!("id", "", "")); } // Bugzilla 13837 unittest { // New behaviour, named arguments. static assert(is( typeof(tuple!("x")(1)) == Tuple!(int, "x"))); static assert(is( typeof(tuple!("x")(1.0)) == Tuple!(double, "x"))); static assert(is( typeof(tuple!("x")("foo")) == Tuple!(string, "x"))); static assert(is( typeof(tuple!("x", "y")(1, 2.0)) == Tuple!(int, "x", double, "y"))); auto a = tuple!("a", "b", "c")("1", 2, 3.0f); static assert(is(typeof(a.a) == string)); static assert(is(typeof(a.b) == int)); static assert(is(typeof(a.c) == float)); // Old behaviour, but with explicit type parameters. static assert(is( typeof(tuple!(int, double)(1, 2.0)) == Tuple!(int, double))); static assert(is( typeof(tuple!(const int)(1)) == Tuple!(const int))); static assert(is( typeof(tuple()) == Tuple!())); // Nonsensical behaviour static assert(!__traits(compiles, tuple!(1)(2))); static assert(!__traits(compiles, tuple!("x")(1, 2))); static assert(!__traits(compiles, tuple!("x", "y")(1))); static assert(!__traits(compiles, tuple!("x")())); static assert(!__traits(compiles, tuple!("x", int)(2))); } unittest { class C {} Tuple!(Rebindable!(const C)) a; Tuple!(const C) b; a = b; } @nogc unittest { alias T = Tuple!(string, "s"); T x; x = T.init; } @safe unittest { import std.format : format, FormatException; import std.exception : assertThrown; // enum tupStr = tuple(1, 1.0).toString; // toString is *impure*. //static assert (tupStr == `Tuple!(int, double)(1, 1)`); Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ]; // Default format assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`); // One Format for each individual component assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10)) == `0x1 v 1.0000 w 0xa`); assert(format( "%#x v %.4f w %#x" , tuple(1, 1.0, 10).expand) == `0x1 v 1.0000 w 0xa`); // One Format for all components assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`); // Array of Tuples assert(format("%(%(f(%d) = %.1f%); %)", tupList) == `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`); // Error: %( %) missing. assertThrown!FormatException( format("%d, %f", tuple(1, 2.0)) == `1, 2.0` ); // Error: %( %| %) missing. assertThrown!FormatException( format("%d", tuple(1, 2)) == `1, 2` ); // Error: %d inadequate for double assertThrown!FormatException( format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0` ); } /** Constructs a $(D Tuple) object instantiated and initialized according to the given arguments. Params: Names = A list of strings naming each successive field of the `Tuple`. Each name matches up with the corresponding field given by `Args`. A name does not have to be provided for every field, but as the names must proceed in order, it is not possible to skip one field and name the next after it. args = Values to initialize the `Tuple` with. The `Tuple`'s type will be inferred from the types of the values given. Returns: A new `Tuple` with its type inferred from the arguments given. */ template tuple(Names...) { auto tuple(Args...)(Args args) { static if (Names.length == 0) { // No specified names, just infer types from Args... return Tuple!Args(args); } else static if (!is(typeof(Names[0]) : string)) { // Names[0] isn't a string, must be explicit types. return Tuple!Names(args); } else { // Names[0] is a string, so must be specifying names. static assert(Names.length == Args.length, "Insufficient number of names given."); // Interleave(a, b).and(c, d) == (a, c, b, d) // This is to get the interleaving of types and names for Tuple // e.g. Tuple!(int, "x", string, "y") template Interleave(A...) { template and(B...) if (B.length == 1) { alias AliasSeq!(A[0], B[0]) and; } template and(B...) if (B.length != 1) { alias AliasSeq!(A[0], B[0], Interleave!(A[1..$]).and!(B[1..$])) and; } } return Tuple!(Interleave!(Args).and!(Names))(args); } } } /// unittest { auto value = tuple(5, 6.7, "hello"); assert(value[0] == 5); assert(value[1] == 6.7); assert(value[2] == "hello"); // Field names can be provided. auto entry = tuple!("index", "value")(4, "Hello"); assert(entry.index == 4); assert(entry.value == "Hello"); } /** Returns $(D true) if and only if $(D T) is an instance of $(D std.typecons.Tuple). Params: T = The type to check. Returns: true if `T` is a `Tuple` type, false otherwise. */ enum isTuple(T) = __traits(compiles, { void f(Specs...)(Tuple!Specs tup) {} f(T.init); } ); /// unittest { static assert(isTuple!(Tuple!())); static assert(isTuple!(Tuple!(int))); static assert(isTuple!(Tuple!(int, real, string))); static assert(isTuple!(Tuple!(int, "x", real, "y"))); static assert(isTuple!(Tuple!(int, Tuple!(real), string))); } unittest { static assert(isTuple!(const Tuple!(int))); static assert(isTuple!(immutable Tuple!(int))); static assert(!isTuple!(int)); static assert(!isTuple!(const int)); struct S {} static assert(!isTuple!(S)); } // used by both Rebindable and UnqualRef private mixin template RebindableCommon(T, U, alias This) if (is(T == class) || is(T == interface) || isAssociativeArray!T) { private union { T original; U stripped; } @trusted pure nothrow @nogc { void opAssign(T another) { stripped = cast(U) another; } void opAssign(typeof(this) another) { stripped = another.stripped; } static if (is(T == const U) && is(T == const shared U)) { // safely assign immutable to const / const shared void opAssign(This!(immutable U) another) { stripped = another.stripped; } } this(T initializer) { opAssign(initializer); } @property ref inout(T) get() inout { return original; } } alias get this; } /** $(D Rebindable!(T)) is a simple, efficient wrapper that behaves just like an object of type $(D T), except that you can reassign it to refer to another object. For completeness, $(D Rebindable!(T)) aliases itself away to $(D T) if $(D T) is a non-const object type. You may want to use $(D Rebindable) when you want to have mutable storage referring to $(D const) objects, for example an array of references that must be sorted in place. $(D Rebindable) does not break the soundness of D's type system and does not incur any of the risks usually associated with $(D cast). Params: T = An object, interface, array slice type, or associative array type. */ template Rebindable(T) if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T) { static if (is(T == const U, U) || is(T == immutable U, U)) { static if (isDynamicArray!T) { import std.range.primitives : ElementEncodingType; alias Rebindable = const(ElementEncodingType!T)[]; } else { struct Rebindable { mixin RebindableCommon!(T, U, Rebindable); } } } else { alias Rebindable = T; } } ///Regular $(D const) object references cannot be reassigned. unittest { class Widget { int x; int y() const { return x; } } const a = new Widget; // Fine a.y(); // error! can't modify const a // a.x = 5; // error! can't modify const a // a = new Widget; } /** However, $(D Rebindable!(Widget)) does allow reassignment, while otherwise behaving exactly like a $(D const Widget). */ unittest { class Widget { int x; int y() const { return x; } } auto a = Rebindable!(const Widget)(new Widget); // Fine a.y(); // error! can't modify const a // a.x = 5; // Fine a = new Widget; } /** Convenience function for creating a $(D Rebindable) using automatic type inference. Params: obj = A reference to an object, interface, associative array, or an array slice to initialize the `Rebindable` with. Returns: A newly constructed `Rebindable` initialized with the given reference. */ Rebindable!T rebindable(T)(T obj) if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T) { typeof(return) ret; ret = obj; return ret; } /** This function simply returns the $(D Rebindable) object passed in. It's useful in generic programming cases when a given object may be either a regular $(D class) or a $(D Rebindable). Params: obj = An instance of Rebindable!T. Returns: `obj` without any modification. */ Rebindable!T rebindable(T)(Rebindable!T obj) { return obj; } unittest { interface CI { int foo() const; } class C : CI { int foo() const { return 42; } @property int bar() const { return 23; } } Rebindable!(C) obj0; static assert(is(typeof(obj0) == C)); Rebindable!(const(C)) obj1; static assert(is(typeof(obj1.get) == const(C)), typeof(obj1.get).stringof); static assert(is(typeof(obj1.stripped) == C)); obj1 = new C; assert(obj1.get !is null); obj1 = new const(C); assert(obj1.get !is null); Rebindable!(immutable(C)) obj2; static assert(is(typeof(obj2.get) == immutable(C))); static assert(is(typeof(obj2.stripped) == C)); obj2 = new immutable(C); assert(obj1.get !is null); // test opDot assert(obj2.foo() == 42); assert(obj2.bar == 23); interface I { final int foo() const { return 42; } } Rebindable!(I) obj3; static assert(is(typeof(obj3) == I)); Rebindable!(const I) obj4; static assert(is(typeof(obj4.get) == const I)); static assert(is(typeof(obj4.stripped) == I)); static assert(is(typeof(obj4.foo()) == int)); obj4 = new class I {}; Rebindable!(immutable C) obj5i; Rebindable!(const C) obj5c; obj5c = obj5c; obj5c = obj5i; obj5i = obj5i; static assert(!__traits(compiles, obj5i = obj5c)); // Test the convenience functions. auto obj5convenience = rebindable(obj5i); assert(obj5convenience is obj5i); auto obj6 = rebindable(new immutable(C)); static assert(is(typeof(obj6) == Rebindable!(immutable C))); assert(obj6.foo() == 42); auto obj7 = rebindable(new C); CI interface1 = obj7; auto interfaceRebind1 = rebindable(interface1); assert(interfaceRebind1.foo() == 42); const interface2 = interface1; auto interfaceRebind2 = rebindable(interface2); assert(interfaceRebind2.foo() == 42); auto arr = [1,2,3,4,5]; const arrConst = arr; assert(rebindable(arr) == arr); assert(rebindable(arrConst) == arr); // Issue 7654 immutable(char[]) s7654; Rebindable!(typeof(s7654)) r7654 = s7654; foreach (T; AliasSeq!(char, wchar, char, int)) { static assert(is(Rebindable!(immutable(T[])) == immutable(T)[])); static assert(is(Rebindable!(const(T[])) == const(T)[])); static assert(is(Rebindable!(T[]) == T[])); } // Issue 12046 static assert(!__traits(compiles, Rebindable!(int[1]))); static assert(!__traits(compiles, Rebindable!(const int[1]))); // Pull request 3341 Rebindable!(immutable int[int]) pr3341 = [123:345]; assert(pr3341[123] == 345); immutable int[int] pr3341_aa = [321:543]; pr3341 = pr3341_aa; assert(pr3341[321] == 543); assert(rebindable(pr3341_aa)[321] == 543); } /** Similar to $(D Rebindable!(T)) but strips all qualifiers from the reference as opposed to just constness / immutability. Primary intended use case is with shared (having thread-local reference to shared class data) Params: T = A class or interface type. */ template UnqualRef(T) if (is(T == class) || is(T == interface)) { static if (is(T == const U, U) || is(T == immutable U, U) || is(T == shared U, U) || is(T == const shared U, U)) { struct UnqualRef { mixin RebindableCommon!(T, U, UnqualRef); } } else { alias UnqualRef = T; } } /// unittest { class Data {} static shared(Data) a; static UnqualRef!(shared Data) b; import core.thread; auto thread = new core.thread.Thread({ a = new shared Data(); b = new shared Data(); }); thread.start(); thread.join(); assert(a !is null); assert(b is null); } unittest { class C { } alias T = UnqualRef!(const shared C); static assert (is(typeof(T.stripped) == C)); } /** Order the provided members to minimize size while preserving alignment. Alignment is not always optimal for 80-bit reals, nor for structs declared as align(1). Params: E = A list of the types to be aligned, representing fields of an aggregate such as a `struct` or `class`. names = The names of the fields that are to be aligned. Returns: A string to be mixed in to an aggregate, such as a `struct` or `class`. */ string alignForSize(E...)(const char[][] names...) { // Sort all of the members by .alignof. // BUG: Alignment is not always optimal for align(1) structs // or 80-bit reals or 64-bit primitives on x86. // TRICK: Use the fact that .alignof is always a power of 2, // and maximum 16 on extant systems. Thus, we can perform // a very limited radix sort. // Contains the members with .alignof = 64,32,16,8,4,2,1 assert(E.length == names.length, "alignForSize: There should be as many member names as the types"); string[7] declaration = ["", "", "", "", "", "", ""]; foreach (i, T; E) { auto a = T.alignof; auto k = a>=64? 0 : a>=32? 1 : a>=16? 2 : a>=8? 3 : a>=4? 4 : a>=2? 5 : 6; declaration[k] ~= T.stringof ~ " " ~ names[i] ~ ";\n"; } auto s = ""; foreach (decl; declaration) s ~= decl; return s; } /// unittest { struct Banner { mixin(alignForSize!(byte[6], double)(["name", "height"])); } } unittest { enum x = alignForSize!(int[], char[3], short, double[5])("x", "y","z", "w"); struct Foo { int x; } enum y = alignForSize!(ubyte, Foo, cdouble)("x", "y", "z"); enum passNormalX = x == "double[5] w;\nint[] x;\nshort z;\nchar[3] y;\n"; enum passNormalY = y == "cdouble z;\nFoo y;\nubyte x;\n"; enum passAbnormalX = x == "int[] x;\ndouble[5] w;\nshort z;\nchar[3] y;\n"; enum passAbnormalY = y == "Foo y;\ncdouble z;\nubyte x;\n"; // ^ blame http://d.puremagic.com/issues/show_bug.cgi?id=231 static assert(passNormalX || passAbnormalX && double.alignof <= (int[]).alignof); static assert(passNormalY || passAbnormalY && double.alignof <= int.alignof); } // Issue 12914 unittest { immutable string[] fieldNames = ["x", "y"]; struct S { mixin(alignForSize!(byte, int)(fieldNames)); } } /** Defines a value paired with a distinctive "null" state that denotes the absence of a value. If default constructed, a $(D Nullable!T) object starts in the null state. Assigning it renders it non-null. Calling $(D nullify) can nullify it again. Practically $(D Nullable!T) stores a $(D T) and a $(D bool). */ struct Nullable(T) { private T _value; private bool _isNull = true; /** Constructor initializing $(D this) with $(D value). Params: value = The value to initialize this `Nullable` with. */ this(inout T value) inout { _value = value; _isNull = false; } template toString() { import std.format : FormatSpec, formatValue; // Needs to be a template because of DMD @@BUG@@ 13737. void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) { if (isNull) { sink.formatValue("Nullable.null", fmt); } else { sink.formatValue(_value, fmt); } } // Issue 14940 void toString()(scope void delegate(const(char)[]) @safe sink, FormatSpec!char fmt) { if (isNull) { sink.formatValue("Nullable.null", fmt); } else { sink.formatValue(_value, fmt); } } } /** Check if `this` is in the null state. Returns: true $(B iff) `this` is in the null state, otherwise false. */ @property bool isNull() const @safe pure nothrow { return _isNull; } /// unittest { Nullable!int ni; assert(ni.isNull); ni = 0; assert(!ni.isNull); } // Issue 14940 @safe unittest { import std.array : appender; import std.format : formattedWrite; auto app = appender!string(); Nullable!int a = 1; formattedWrite(app, "%s", a); assert(app.data == "1"); } /** Forces $(D this) to the null state. */ void nullify()() { .destroy(_value); _isNull = true; } /// unittest { Nullable!int ni = 0; assert(!ni.isNull); ni.nullify(); assert(ni.isNull); } /** Assigns $(D value) to the internally-held state. If the assignment succeeds, $(D this) becomes non-null. Params: value = A value of type `T` to assign to this `Nullable`. */ void opAssign()(T value) { _value = value; _isNull = false; } /** If this `Nullable` wraps a type that already has a null value (such as a pointer), then assigning the null value to this `Nullable` is no different than assigning any other value of type `T`, and the resulting code will look very strange. It is strongly recommended that this be avoided by instead using the version of `Nullable` that takes an additional `nullValue` template argument. */ unittest { //Passes Nullable!(int*) npi; assert(npi.isNull); //Passes?! npi = null; assert(!npi.isNull); } /** Gets the value. $(D this) must not be in the null state. This function is also called for the implicit conversion to $(D T). Returns: The value held internally by this `Nullable`. */ @property ref inout(T) get() inout @safe pure nothrow { enum message = "Called `get' on null Nullable!" ~ T.stringof ~ "."; assert(!isNull, message); return _value; } /// unittest { import std.exception: assertThrown, assertNotThrown; Nullable!int ni; //`get` is implicitly called. Will throw //an AssertError in non-release mode assertThrown!Throwable(ni == 0); ni = 0; assertNotThrown!Throwable(ni == 0); } /** Implicitly converts to $(D T). $(D this) must not be in the null state. */ alias get this; } /// unittest { struct CustomerRecord { string name; string address; int customerNum; } Nullable!CustomerRecord getByName(string name) { //A bunch of hairy stuff return Nullable!CustomerRecord.init; } auto queryResult = getByName("Doe, John"); if (!queryResult.isNull) { //Process Mr. Doe's customer record auto address = queryResult.address; auto customerNum = queryResult.customerNum; //Do some things with this customer's info } else { //Add the customer to the database } } unittest { import std.exception : assertThrown; Nullable!int a; assert(a.isNull); assertThrown!Throwable(a.get); a = 5; assert(!a.isNull); assert(a == 5); assert(a != 3); assert(a.get != 3); a.nullify(); assert(a.isNull); a = 3; assert(a == 3); a *= 6; assert(a == 18); a = a; assert(a == 18); a.nullify(); assertThrown!Throwable(a += 2); } unittest { auto k = Nullable!int(74); assert(k == 74); k.nullify(); assert(k.isNull); } unittest { static int f(in Nullable!int x) { return x.isNull ? 42 : x.get; } Nullable!int a; assert(f(a) == 42); a = 8; assert(f(a) == 8); a.nullify(); assert(f(a) == 42); } unittest { import std.exception : assertThrown; static struct S { int x; } Nullable!S s; assert(s.isNull); s = S(6); assert(s == S(6)); assert(s != S(0)); assert(s.get != S(0)); s.x = 9190; assert(s.x == 9190); s.nullify(); assertThrown!Throwable(s.x = 9441); } unittest { // Ensure Nullable can be used in pure/nothrow/@safe environment. function() @safe pure nothrow { Nullable!int n; assert(n.isNull); n = 4; assert(!n.isNull); assert(n == 4); n.nullify(); assert(n.isNull); }(); } unittest { // Ensure Nullable can be used when the value is not pure/nothrow/@safe static struct S { int x; this(this) @system {} } Nullable!S s; assert(s.isNull); s = S(5); assert(!s.isNull); assert(s.x == 5); s.nullify(); assert(s.isNull); } unittest { // Bugzilla 9404 alias N = Nullable!int; void foo(N a) { N b; b = a; // `N b = a;` works fine } N n; foo(n); } unittest { //Check nullable immutable is constructable { auto a1 = Nullable!(immutable int)(); auto a2 = Nullable!(immutable int)(1); auto i = a2.get; } //Check immutable nullable is constructable { auto a1 = immutable (Nullable!int)(); auto a2 = immutable (Nullable!int)(1); auto i = a2.get; } } unittest { alias NInt = Nullable!int; //Construct tests { //from other Nullable null NInt a1; NInt b1 = a1; assert(b1.isNull); //from other Nullable non-null NInt a2 = NInt(1); NInt b2 = a2; assert(b2 == 1); //Construct from similar nullable auto a3 = immutable(NInt)(); NInt b3 = a3; assert(b3.isNull); } //Assign tests { //from other Nullable null NInt a1; NInt b1; b1 = a1; assert(b1.isNull); //from other Nullable non-null NInt a2 = NInt(1); NInt b2; b2 = a2; assert(b2 == 1); //Construct from similar nullable auto a3 = immutable(NInt)(); NInt b3 = a3; b3 = a3; assert(b3.isNull); } } unittest { //Check nullable is nicelly embedable in a struct static struct S1 { Nullable!int ni; } static struct S2 //inspired from 9404 { Nullable!int ni; this(S2 other) { ni = other.ni; } void opAssign(S2 other) { ni = other.ni; } } foreach (S; AliasSeq!(S1, S2)) { S a; S b = a; S c; c = a; } } unittest { // Bugzilla 10268 import std.json; JSONValue value = null; auto na = Nullable!JSONValue(value); struct S1 { int val; } struct S2 { int* val; } struct S3 { immutable int* val; } { auto sm = S1(1); immutable si = immutable S1(1); auto x1 = Nullable!S1(sm); auto x2 = immutable Nullable!S1(sm); auto x3 = Nullable!S1(si); auto x4 = immutable Nullable!S1(si); assert(x1.val == 1); assert(x2.val == 1); assert(x3.val == 1); assert(x4.val == 1); } auto nm = 10; immutable ni = 10; { auto sm = S2(&nm); immutable si = immutable S2(&ni); auto x1 = Nullable!S2(sm); static assert(!__traits(compiles, { auto x2 = immutable Nullable!S2(sm); })); static assert(!__traits(compiles, { auto x3 = Nullable!S2(si); })); auto x4 = immutable Nullable!S2(si); assert(*x1.val == 10); assert(*x4.val == 10); } { auto sm = S3(&ni); immutable si = immutable S3(&ni); auto x1 = Nullable!S3(sm); auto x2 = immutable Nullable!S3(sm); auto x3 = Nullable!S3(si); auto x4 = immutable Nullable!S3(si); assert(*x1.val == 10); assert(*x2.val == 10); assert(*x3.val == 10); assert(*x4.val == 10); } } unittest { // Bugzila 10357 import std.datetime; Nullable!SysTime time = SysTime(0); } unittest { import std.conv: to; import std.array; // Bugzilla 10915 Appender!string buffer; Nullable!int ni; assert(ni.to!string() == "Nullable.null"); struct Test { string s; } alias NullableTest = Nullable!Test; NullableTest nt = Test("test"); assert(nt.to!string() == `Test("test")`); NullableTest ntn = Test("null"); assert(ntn.to!string() == `Test("null")`); class TestToString { double d; this (double d) { this.d = d; } override string toString() { return d.to!string(); } } Nullable!TestToString ntts = new TestToString(2.5); assert(ntts.to!string() == "2.5"); } /** Just like $(D Nullable!T), except that the null state is defined as a particular value. For example, $(D Nullable!(uint, uint.max)) is an $(D uint) that sets aside the value $(D uint.max) to denote a null state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D Nullable!T) because it does not need to store an extra $(D bool). Params: T = The wrapped type for which Nullable provides a null value. nullValue = The null value which denotes the null state of this `Nullable`. Must be of type `T`. */ struct Nullable(T, T nullValue) { private T _value = nullValue; /** Constructor initializing $(D this) with $(D value). Params: value = The value to initialize this `Nullable` with. */ this(T value) { _value = value; } template toString() { import std.format : FormatSpec, formatValue; // Needs to be a template because of DMD @@BUG@@ 13737. void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) { if (isNull) { sink.formatValue("Nullable.null", fmt); } else { sink.formatValue(_value, fmt); } } } /** Check if `this` is in the null state. Returns: true $(B iff) `this` is in the null state, otherwise false. */ @property bool isNull() const { //Need to use 'is' if T is a nullable type and //nullValue is null, or it's a compiler error static if (is(CommonType!(T, typeof(null)) == T) && nullValue is null) { return _value is nullValue; } else { return _value == nullValue; } } /// unittest { Nullable!(int, -1) ni; //Initialized to "null" state assert(ni.isNull); ni = 0; assert(!ni.isNull); } /** Forces $(D this) to the null state. */ void nullify()() { _value = nullValue; } /// unittest { Nullable!(int, -1) ni = 0; assert(!ni.isNull); ni = -1; assert(ni.isNull); } /** Assigns $(D value) to the internally-held state. If the assignment succeeds, $(D this) becomes non-null. No null checks are made. Note that the assignment may leave $(D this) in the null state. Params: value = A value of type `T` to assign to this `Nullable`. If it is `nullvalue`, then the internal state of this `Nullable` will be set to null. */ void opAssign()(T value) { _value = value; } /** If this `Nullable` wraps a type that already has a null value (such as a pointer), and that null value is not given for `nullValue`, then assigning the null value to this `Nullable` is no different than assigning any other value of type `T`, and the resulting code will look very strange. It is strongly recommended that this be avoided by using `T`'s "built in" null value for `nullValue`. */ unittest { //Passes enum nullVal = cast(int*)0xCAFEBABE; Nullable!(int*, nullVal) npi; assert(npi.isNull); //Passes?! npi = null; assert(!npi.isNull); } /** Gets the value. $(D this) must not be in the null state. This function is also called for the implicit conversion to $(D T). Returns: The value held internally by this `Nullable`. */ @property ref inout(T) get() inout { //@@@6169@@@: We avoid any call that might evaluate nullValue's %s, //Because it might messup get's purity and safety inference. enum message = "Called `get' on null Nullable!(" ~ T.stringof ~ ",nullValue)."; assert(!isNull, message); return _value; } /// unittest { import std.exception: assertThrown, assertNotThrown; Nullable!(int, -1) ni; //`get` is implicitly called. Will throw //an error in non-release mode assertThrown!Throwable(ni == 0); ni = 0; assertNotThrown!Throwable(ni == 0); } /** Implicitly converts to $(D T). $(D this) must not be in the null state. */ alias get this; } /// unittest { Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle) { //Find the needle, returning -1 if not found return Nullable!(size_t, size_t.max).init; } void sendLunchInvite(string name) { } //It's safer than C... auto coworkers = ["Jane", "Jim", "Marry", "Fred"]; auto pos = indexOf(coworkers, "Bob"); if (!pos.isNull) { //Send Bob an invitation to lunch sendLunchInvite(coworkers[pos]); } else { //Bob not found; report the error } //And there's no overhead static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof); } unittest { import std.exception : assertThrown; Nullable!(int, int.min) a; assert(a.isNull); assertThrown!Throwable(a.get); a = 5; assert(!a.isNull); assert(a == 5); static assert(a.sizeof == int.sizeof); } unittest { auto a = Nullable!(int, int.min)(8); assert(a == 8); a.nullify(); assert(a.isNull); } unittest { static int f(in Nullable!(int, int.min) x) { return x.isNull ? 42 : x.get; } Nullable!(int, int.min) a; assert(f(a) == 42); a = 8; assert(f(a) == 8); a.nullify(); assert(f(a) == 42); } unittest { // Ensure Nullable can be used in pure/nothrow/@safe environment. function() @safe pure nothrow { Nullable!(int, int.min) n; assert(n.isNull); n = 4; assert(!n.isNull); assert(n == 4); n.nullify(); assert(n.isNull); }(); } unittest { // Ensure Nullable can be used when the value is not pure/nothrow/@safe static struct S { int x; bool opEquals(const S s) const @system { return s.x == x; } } Nullable!(S, S(711)) s; assert(s.isNull); s = S(5); assert(!s.isNull); assert(s.x == 5); s.nullify(); assert(s.isNull); } unittest { //Check nullable is nicelly embedable in a struct static struct S1 { Nullable!(int, 0) ni; } static struct S2 //inspired from 9404 { Nullable!(int, 0) ni; this(S2 other) { ni = other.ni; } void opAssign(S2 other) { ni = other.ni; } } foreach (S; AliasSeq!(S1, S2)) { S a; S b = a; S c; c = a; } } unittest { import std.conv: to; // Bugzilla 10915 Nullable!(int, 1) ni = 1; assert(ni.to!string() == "Nullable.null"); struct Test { string s; } alias NullableTest = Nullable!(Test, Test("null")); NullableTest nt = Test("test"); assert(nt.to!string() == `Test("test")`); NullableTest ntn = Test("null"); assert(ntn.to!string() == "Nullable.null"); class TestToString { double d; this(double d) { this.d = d; } override string toString() { return d.to!string(); } } alias NullableTestToString = Nullable!(TestToString, null); NullableTestToString ntts = new TestToString(2.5); assert(ntts.to!string() == "2.5"); } /** Just like $(D Nullable!T), except that the object refers to a value sitting elsewhere in memory. This makes assignments overwrite the initially assigned value. Internally $(D NullableRef!T) only stores a pointer to $(D T) (i.e., $(D Nullable!T.sizeof == (T*).sizeof)). */ struct NullableRef(T) { private T* _value; /** Constructor binding $(D this) to $(D value). Params: value = The value to bind to. */ this(T* value) @safe pure nothrow { _value = value; } template toString() { import std.format : FormatSpec, formatValue; // Needs to be a template because of DMD @@BUG@@ 13737. void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) { if (isNull) { sink.formatValue("Nullable.null", fmt); } else { sink.formatValue(*_value, fmt); } } } /** Binds the internal state to $(D value). Params: value = A pointer to a value of type `T` to bind this `NullableRef` to. */ void bind(T* value) @safe pure nothrow { _value = value; } /// unittest { NullableRef!int nr = new int(42); assert(nr == 42); int* n = new int(1); nr.bind(n); assert(nr == 1); } /** Returns $(D true) if and only if $(D this) is in the null state. Returns: true if `this` is in the null state, otherwise false. */ @property bool isNull() const @safe pure nothrow { return _value is null; } /// unittest { NullableRef!int nr; assert(nr.isNull); int* n = new int(42); nr.bind(n); assert(!nr.isNull && nr == 42); } /** Forces $(D this) to the null state. */ void nullify() @safe pure nothrow { _value = null; } /// unittest { NullableRef!int nr = new int(42); assert(!nr.isNull); nr.nullify(); assert(nr.isNull); } /** Assigns $(D value) to the internally-held state. Params: value = A value of type `T` to assign to this `NullableRef`. If the internal state of this `NullableRef` has not been initialized, an error will be thrown in non-release mode. */ void opAssign()(T value) if (isAssignable!T) //@@@9416@@@ { enum message = "Called `opAssign' on null NullableRef!" ~ T.stringof ~ "."; assert(!isNull, message); *_value = value; } /// unittest { import std.exception: assertThrown, assertNotThrown; NullableRef!int nr; assert(nr.isNull); assertThrown!Throwable(nr = 42); nr.bind(new int(0)); assert(!nr.isNull); assertNotThrown!Throwable(nr = 42); assert(nr == 42); } /** Gets the value. $(D this) must not be in the null state. This function is also called for the implicit conversion to $(D T). */ @property ref inout(T) get() inout @safe pure nothrow { enum message = "Called `get' on null NullableRef!" ~ T.stringof ~ "."; assert(!isNull, message); return *_value; } /// unittest { import std.exception: assertThrown, assertNotThrown; NullableRef!int nr; //`get` is implicitly called. Will throw //an error in non-release mode assertThrown!Throwable(nr == 0); nr.bind(new int(0)); assertNotThrown!Throwable(nr == 0); } /** Implicitly converts to $(D T). $(D this) must not be in the null state. */ alias get this; } unittest { import std.exception : assertThrown; int x = 5, y = 7; auto a = NullableRef!(int)(&x); assert(!a.isNull); assert(a == 5); assert(x == 5); a = 42; assert(x == 42); assert(!a.isNull); assert(a == 42); a.nullify(); assert(x == 42); assert(a.isNull); assertThrown!Throwable(a.get); assertThrown!Throwable(a = 71); a.bind(&y); assert(a == 7); y = 135; assert(a == 135); } unittest { static int f(in NullableRef!int x) { return x.isNull ? 42 : x.get; } int x = 5; auto a = NullableRef!int(&x); assert(f(a) == 5); a.nullify(); assert(f(a) == 42); } unittest { // Ensure NullableRef can be used in pure/nothrow/@safe environment. function() @safe pure nothrow { auto storage = new int; *storage = 19902; NullableRef!int n; assert(n.isNull); n.bind(storage); assert(!n.isNull); assert(n == 19902); n = 2294; assert(n == 2294); assert(*storage == 2294); n.nullify(); assert(n.isNull); }(); } unittest { // Ensure NullableRef can be used when the value is not pure/nothrow/@safe static struct S { int x; this(this) @system {} bool opEquals(const S s) const @system { return s.x == x; } } auto storage = S(5); NullableRef!S s; assert(s.isNull); s.bind(&storage); assert(!s.isNull); assert(s.x == 5); s.nullify(); assert(s.isNull); } unittest { //Check nullable is nicelly embedable in a struct static struct S1 { NullableRef!int ni; } static struct S2 //inspired from 9404 { NullableRef!int ni; this(S2 other) { ni = other.ni; } void opAssign(S2 other) { ni = other.ni; } } foreach (S; AliasSeq!(S1, S2)) { S a; S b = a; S c; c = a; } } unittest { import std.conv: to; // Bugzilla 10915 NullableRef!int nri; assert(nri.to!string() == "Nullable.null"); struct Test { string s; } NullableRef!Test nt = new Test("test"); assert(nt.to!string() == `Test("test")`); class TestToString { double d; this(double d) { this.d = d; } override string toString() { return d.to!string(); } } TestToString tts = new TestToString(2.5); NullableRef!TestToString ntts = &tts; assert(ntts.to!string() == "2.5"); } /** $(D BlackHole!Base) is a subclass of $(D Base) which automatically implements all abstract member functions in $(D Base) as do-nothing functions. Each auto-implemented function just returns the default value of the return type without doing anything. The name came from $(WEB search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole) Perl module by Sean M. Burke. Params: Base = A non-final class for `BlackHole` to inherit from. See_Also: $(LREF AutoImplement), $(LREF generateEmptyFunction) */ alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction, isAbstractFunction); /// unittest { import std.math: isNaN; static abstract class C { int m_value; this(int v) { m_value = v; } int value() @property { return m_value; } abstract real realValue() @property; abstract void doSomething(); } auto c = new BlackHole!C(42); assert(c.value == 42); // Returns real.init which is NaN assert(c.realValue.isNaN); // Abstract functions are implemented as do-nothing c.doSomething(); } unittest { import std.math : isNaN; // return default { interface I_1 { real test(); } auto o = new BlackHole!I_1; assert(o.test().isNaN()); // NaN } // doc example { static class C { int m_value; this(int v) { m_value = v; } int value() @property { return m_value; } abstract real realValue() @property; abstract void doSomething(); } auto c = new BlackHole!C(42); assert(c.value == 42); assert(c.realValue.isNaN); // NaN c.doSomething(); } // Bugzilla 12058 interface Foo { inout(Object) foo() inout; } BlackHole!Foo o; } /** $(D WhiteHole!Base) is a subclass of $(D Base) which automatically implements all abstract member functions as functions that always fail. These functions simply throw an $(D Error) and never return. `Whitehole` is useful for trapping the use of class member functions that haven't been implemented. The name came from $(WEB search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole) Perl module by Michael G Schwern. Params: Base = A non-final class for `WhiteHole` to inherit from. See_Also: $(LREF AutoImplement), $(LREF generateAssertTrap) */ alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap, isAbstractFunction); /// unittest { import std.exception: assertThrown; static class C { abstract void notYetImplemented(); } auto c = new WhiteHole!C; assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error } // / ditto class NotImplementedError : Error { this(string method) { super(method ~ " is not implemented"); } } unittest { import std.exception : assertThrown; // nothrow { interface I_1 { void foo(); void bar() nothrow; } auto o = new WhiteHole!I_1; assertThrown!NotImplementedError(o.foo()); assertThrown!NotImplementedError(o.bar()); } // doc example { static class C { abstract void notYetImplemented(); } auto c = new WhiteHole!C; try { c.notYetImplemented(); assert(0); } catch (Error e) {} } } /** $(D AutoImplement) automatically implements (by default) all abstract member functions in the class or interface $(D Base) in specified way. Params: how = template which specifies _how functions will be implemented/overridden. Two arguments are passed to $(D how): the type $(D Base) and an alias to an implemented function. Then $(D how) must return an implemented function body as a string. The generated function body can use these keywords: $(UL $(LI $(D a0), $(D a1), …: arguments passed to the function;) $(LI $(D args): a tuple of the arguments;) $(LI $(D self): an alias to the function itself;) $(LI $(D parent): an alias to the overridden function (if any).) ) You may want to use templated property functions (instead of Implicit Template Properties) to generate complex functions: -------------------- // Prints log messages for each call to overridden functions. string generateLogger(C, alias fun)() @property { import std.traits; enum qname = C.stringof ~ "." ~ __traits(identifier, fun); string stmt; stmt ~= q{ struct Importer { import std.stdio; } }; stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`; static if (!__traits(isAbstractFunction, fun)) { static if (is(ReturnType!fun == void)) stmt ~= q{ parent(args); }; else stmt ~= q{ auto r = parent(args); Importer.writeln("--> ", r); return r; }; } return stmt; } -------------------- what = template which determines _what functions should be implemented/overridden. An argument is passed to $(D what): an alias to a non-final member function in $(D Base). Then $(D what) must return a boolean value. Return $(D true) to indicate that the passed function should be implemented/overridden. -------------------- // Sees if fun returns something. enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void); -------------------- Note: Generated code is inserted in the scope of $(D std.typecons) module. Thus, any useful functions outside $(D std.typecons) cannot be used in the generated code. To workaround this problem, you may $(D import) necessary things in a local struct, as done in the $(D generateLogger()) template in the above example. BUGS: $(UL $(LI Variadic arguments to constructors are not forwarded to super.) $(LI Deep interface inheritance causes compile error with messages like "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar does not override any function". [$(BUGZILLA 2525), $(BUGZILLA 3525)] ) $(LI The $(D parent) keyword is actually a delegate to the super class' corresponding member function. [$(BUGZILLA 2540)] ) $(LI Using alias template parameter in $(D how) and/or $(D what) may cause strange compile error. Use template tuple parameter instead to workaround this problem. [$(BUGZILLA 4217)] ) ) */ class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base { private alias autoImplement_helper_ = AutoImplement_Helper!("autoImplement_helper_", "Base", Base, how, what); mixin(autoImplement_helper_.code); } /* * Code-generating stuffs are encupsulated in this helper template so that * namespace pollution, which can cause name confliction with Base's public * members, should be minimized. */ private template AutoImplement_Helper(string myName, string baseName, Base, alias generateMethodBody, alias cherrypickMethod) { private static: //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Internal stuffs //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Returns function overload sets in the class C, filtered with pred. template enumerateOverloads(C, alias pred) { template Impl(names...) { import std.meta : Filter; static if (names.length > 0) { alias methods = Filter!(pred, MemberFunctionsTuple!(C, names[0])); alias next = Impl!(names[1 .. $]); static if (methods.length > 0) alias Impl = AliasSeq!(OverloadSet!(names[0], methods), next); else alias Impl = next; } else alias Impl = AliasSeq!(); } alias enumerateOverloads = Impl!(__traits(allMembers, C)); } //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Target functions //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Add a non-final check to the cherrypickMethod. enum bool canonicalPicker(fun.../+[BUG 4217]+/) = !__traits(isFinalFunction, fun[0]) && cherrypickMethod!(fun); /* * A tuple of overload sets, each item of which consists of functions to be * implemented by the generated code. */ alias targetOverloadSets = enumerateOverloads!(Base, canonicalPicker); /* * A tuple of the super class' constructors. Used for forwarding * constructor calls. */ static if (__traits(hasMember, Base, "__ctor")) alias ctorOverloadSet = OverloadSet!("__ctor", __traits(getOverloads, Base, "__ctor")); else alias ctorOverloadSet = OverloadSet!("__ctor"); // empty //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Type information //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// /* * The generated code will be mixed into AutoImplement, which will be * instantiated in this module's scope. Thus, any user-defined types are * out of scope and cannot be used directly (i.e. by their names). * * We will use FuncInfo instances for accessing return types and parameter * types of the implemented functions. The instances will be populated to * the AutoImplement's scope in a certain way; see the populate() below. */ // Returns the preferred identifier for the FuncInfo instance for the i-th // overloaded function with the name. template INTERNAL_FUNCINFO_ID(string name, size_t i) { import std.format : format; enum string INTERNAL_FUNCINFO_ID = format("F_%s_%s", name, i); } /* * Insert FuncInfo instances about all the target functions here. This * enables the generated code to access type information via, for example, * "autoImplement_helper_.F_foo_1". */ template populate(overloads...) { static if (overloads.length > 0) { mixin populate!(overloads[0].name, overloads[0].contents); mixin populate!(overloads[1 .. $]); } } template populate(string name, methods...) { static if (methods.length > 0) { mixin populate!(name, methods[0 .. $ - 1]); // alias target = methods[$ - 1]; enum ith = methods.length - 1; mixin("alias " ~ INTERNAL_FUNCINFO_ID!(name, ith) ~ " = FuncInfo!target;"); } } public mixin populate!(targetOverloadSets); public mixin populate!( ctorOverloadSet ); //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Code-generating policies //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// /* Common policy configurations for generating constructors and methods. */ template CommonGeneratingPolicy() { // base class identifier which generated code should use enum string BASE_CLASS_ID = baseName; // FuncInfo instance identifier which generated code should use template FUNCINFO_ID(string name, size_t i) { enum string FUNCINFO_ID = myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i); } } /* Policy configurations for generating constructors. */ template ConstructorGeneratingPolicy() { mixin CommonGeneratingPolicy; /* Generates constructor body. Just forward to the base class' one. */ string generateFunctionBody(ctor.../+[BUG 4217]+/)() @property { enum varstyle = variadicFunctionStyle!(typeof(&ctor[0])); static if (varstyle & (Variadic.c | Variadic.d)) { // the argptr-forwarding problem //pragma(msg, "Warning: AutoImplement!(", Base, ") ", // "ignored variadic arguments to the constructor ", // FunctionTypeOf!(typeof(&ctor[0])) ); } return "super(args);"; } } /* Policy configurations for genearting target methods. */ template MethodGeneratingPolicy() { mixin CommonGeneratingPolicy; /* Geneartes method body. */ string generateFunctionBody(func.../+[BUG 4217]+/)() @property { return generateMethodBody!(Base, func); // given } } //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Generated code //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// alias ConstructorGenerator = MemberFunctionGenerator!(ConstructorGeneratingPolicy!()); alias MethodGenerator = MemberFunctionGenerator!(MethodGeneratingPolicy!()); public enum string code = ConstructorGenerator.generateCode!( ctorOverloadSet ) ~ "\n" ~ MethodGenerator.generateCode!(targetOverloadSets); debug (SHOW_GENERATED_CODE) { pragma(msg, "-------------------- < ", Base, " >"); pragma(msg, code); pragma(msg, "--------------------"); } } //debug = SHOW_GENERATED_CODE; unittest { import core.vararg; // no function to implement { interface I_1 {} auto o = new BlackHole!I_1; } // parameters { interface I_3 { void test(int, in int, out int, ref int, lazy int); } auto o = new BlackHole!I_3; } // use of user-defined type { struct S {} interface I_4 { S test(); } auto o = new BlackHole!I_4; } // overloads { interface I_5 { void test(string); real test(real); int test(); } auto o = new BlackHole!I_5; } // constructor forwarding { static class C_6 { this(int n) { assert(n == 42); } this(string s) { assert(s == "Deeee"); } this(...) {} } auto o1 = new BlackHole!C_6(42); auto o2 = new BlackHole!C_6("Deeee"); auto o3 = new BlackHole!C_6(1, 2, 3, 4); } // attributes { interface I_7 { ref int test_ref(); int test_pure() pure; int test_nothrow() nothrow; int test_property() @property; int test_safe() @safe; int test_trusted() @trusted; int test_system() @system; int test_pure_nothrow() pure nothrow; } auto o = new BlackHole!I_7; } // storage classes { interface I_8 { void test_const() const; void test_immutable() immutable; void test_shared() shared; void test_shared_const() shared const; } auto o = new BlackHole!I_8; } /+ // deep inheritance { // XXX [BUG 2525,3525] // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic() interface I { void foo(); } interface J : I {} interface K : J {} static abstract class C_9 : K {} auto o = new BlackHole!C_9; }+/ } version(unittest) { // Issue 10647 // Add prefix "issue10647_" as a workaround for issue 1238 private string issue10647_generateDoNothing(C, alias fun)() @property { string stmt; static if (is(ReturnType!fun == void)) stmt ~= ""; else { string returnType = ReturnType!fun.stringof; stmt ~= "return "~returnType~".init;"; } return stmt; } private template issue10647_isAlwaysTrue(alias fun) { enum issue10647_isAlwaysTrue = true; } // Do nothing template private template issue10647_DoNothing(Base) { alias issue10647_DoNothing = AutoImplement!(Base, issue10647_generateDoNothing, issue10647_isAlwaysTrue); } // A class to be overridden private class issue10647_Foo{ void bar(int a) { } } } unittest { auto foo = new issue10647_DoNothing!issue10647_Foo(); foo.bar(13); } /* Used by MemberFunctionGenerator. */ package template OverloadSet(string nam, T...) { enum string name = nam; alias contents = T; } /* Used by MemberFunctionGenerator. */ package template FuncInfo(alias func, /+[BUG 4217 ?]+/ T = typeof(&func)) { alias RT = ReturnType!T; alias PT = Parameters!T; } package template FuncInfo(Func) { alias RT = ReturnType!Func; alias PT = Parameters!Func; } /* General-purpose member function generator. -------------------- template GeneratingPolicy() { // [optional] the name of the class where functions are derived enum string BASE_CLASS_ID; // [optional] define this if you have only function types enum bool WITHOUT_SYMBOL; // [optional] Returns preferred identifier for i-th parameter. template PARAMETER_VARIABLE_ID(size_t i); // Returns the identifier of the FuncInfo instance for the i-th overload // of the specified name. The identifier must be accessible in the scope // where generated code is mixed. template FUNCINFO_ID(string name, size_t i); // Returns implemented function body as a string. When WITHOUT_SYMBOL is // defined, the latter is used. template generateFunctionBody(alias func); template generateFunctionBody(string name, FuncType); } -------------------- */ package template MemberFunctionGenerator(alias Policy) { private static: //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Internal stuffs //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// import std.format; enum CONSTRUCTOR_NAME = "__ctor"; // true if functions are derived from a base class enum WITH_BASE_CLASS = __traits(hasMember, Policy, "BASE_CLASS_ID"); // true if functions are specified as types, not symbols enum WITHOUT_SYMBOL = __traits(hasMember, Policy, "WITHOUT_SYMBOL"); // preferred identifier for i-th parameter variable static if (__traits(hasMember, Policy, "PARAMETER_VARIABLE_ID")) { alias PARAMETER_VARIABLE_ID = Policy.PARAMETER_VARIABLE_ID; } else { enum string PARAMETER_VARIABLE_ID(size_t i) = format("a%s", i); // default: a0, a1, ... } // Returns a tuple consisting of 0,1,2,...,n-1. For static foreach. template CountUp(size_t n) { static if (n > 0) alias CountUp = AliasSeq!(CountUp!(n - 1), n - 1); else alias CountUp = AliasSeq!(); } //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Code generator //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// /* * Runs through all the target overload sets and generates D code which * implements all the functions in the overload sets. */ public string generateCode(overloads...)() @property { string code = ""; // run through all the overload sets foreach (i_; CountUp!(0 + overloads.length)) // workaround { enum i = 0 + i_; // workaround alias oset = overloads[i]; code ~= generateCodeForOverloadSet!(oset); static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME) { // The generated function declarations may hide existing ones // in the base class (cf. HiddenFuncError), so we put an alias // declaration here to reveal possible hidden functions. code ~= format("alias %s = %s.%s;\n", oset.name, Policy.BASE_CLASS_ID, // [BUG 2540] super. oset.name); } } return code; } // handle each overload set private string generateCodeForOverloadSet(alias oset)() @property { string code = ""; foreach (i_; CountUp!(0 + oset.contents.length)) // workaround { enum i = 0 + i_; // workaround code ~= generateFunction!( Policy.FUNCINFO_ID!(oset.name, i), oset.name, oset.contents[i]) ~ "\n"; } return code; } /* * Returns D code which implements the function func. This function * actually generates only the declarator part; the function body part is * generated by the functionGenerator() policy. */ public string generateFunction( string myFuncInfo, string name, func... )() @property { import std.format : format; enum isCtor = (name == CONSTRUCTOR_NAME); string code; // the result auto paramsRes = generateParameters!(myFuncInfo, func)(); code ~= paramsRes.imports; /*** Function Declarator ***/ { alias Func = FunctionTypeOf!(func); alias FA = FunctionAttribute; enum atts = functionAttributes!(func); enum realName = isCtor ? "this" : name; // FIXME?? Make it so that these aren't CTFE funcs any more, since // Format is deprecated, and format works at compile time? /* Made them CTFE funcs just for the sake of Format!(...) */ // return type with optional "ref" static string make_returnType() { string rtype = ""; if (!isCtor) { if (atts & FA.ref_) rtype ~= "ref "; rtype ~= myFuncInfo ~ ".RT"; } return rtype; } enum returnType = make_returnType(); // function attributes attached after declaration static string make_postAtts() { string poatts = ""; if (atts & FA.pure_ ) poatts ~= " pure"; if (atts & FA.nothrow_) poatts ~= " nothrow"; if (atts & FA.property) poatts ~= " @property"; if (atts & FA.safe ) poatts ~= " @safe"; if (atts & FA.trusted ) poatts ~= " @trusted"; return poatts; } enum postAtts = make_postAtts(); // function storage class static string make_storageClass() { string postc = ""; if (is(Func == shared)) postc ~= " shared"; if (is(Func == const)) postc ~= " const"; if (is(Func == inout)) postc ~= " inout"; if (is(Func == immutable)) postc ~= " immutable"; return postc; } enum storageClass = make_storageClass(); // if (__traits(isVirtualMethod, func)) code ~= "override "; code ~= format("extern(%s) %s %s(%s) %s %s\n", functionLinkage!(func), returnType, realName, paramsRes.params, postAtts, storageClass ); } /*** Function Body ***/ code ~= "{\n"; { enum nparams = Parameters!(func).length; /* Declare keywords: args, self and parent. */ string preamble; preamble ~= "alias args = AliasSeq!(" ~ enumerateParameters!(nparams) ~ ");\n"; if (!isCtor) { preamble ~= "alias self = " ~ name ~ ";\n"; if (WITH_BASE_CLASS && !__traits(isAbstractFunction, func)) //preamble ~= "alias super." ~ name ~ " parent;\n"; // [BUG 2540] preamble ~= "auto parent = &super." ~ name ~ ";\n"; } // Function body static if (WITHOUT_SYMBOL) enum fbody = Policy.generateFunctionBody!(name, func); else enum fbody = Policy.generateFunctionBody!(func); code ~= preamble; code ~= fbody; } code ~= "}"; return code; } /* * Returns D code which declares function parameters, * and optionally any imports (e.g. core.vararg) * "ref int a0, real a1, ..." */ static struct GenParams { string imports, params; } private GenParams generateParameters(string myFuncInfo, func...)() { alias STC = ParameterStorageClass; alias stcs = ParameterStorageClassTuple!(func); enum nparams = stcs.length; string imports = ""; // any imports required string params = ""; // parameters foreach (i, stc; stcs) { if (i > 0) params ~= ", "; // Parameter storage classes. if (stc & STC.scope_) params ~= "scope "; if (stc & STC.out_ ) params ~= "out "; if (stc & STC.ref_ ) params ~= "ref "; if (stc & STC.lazy_ ) params ~= "lazy "; // Take parameter type from the FuncInfo. params ~= format("%s.PT[%s]", myFuncInfo, i); // Declare a parameter variable. params ~= " " ~ PARAMETER_VARIABLE_ID!(i); } // Add some ellipsis part if needed. auto style = variadicFunctionStyle!(func); final switch (style) { case Variadic.no: break; case Variadic.c, Variadic.d: imports ~= "import core.vararg;\n"; // (...) or (a, b, ...) params ~= (nparams == 0) ? "..." : ", ..."; break; case Variadic.typesafe: params ~= " ..."; break; } return typeof(return)(imports, params); } // Returns D code which enumerates n parameter variables using comma as the // separator. "a0, a1, a2, a3" private string enumerateParameters(size_t n)() @property { string params = ""; foreach (i_; CountUp!(n)) { enum i = 0 + i_; // workaround if (i > 0) params ~= ", "; params ~= PARAMETER_VARIABLE_ID!(i); } return params; } } /** Predefined how-policies for $(D AutoImplement). These templates are also used by $(D BlackHole) and $(D WhiteHole), respectively. */ template generateEmptyFunction(C, func.../+[BUG 4217]+/) { static if (is(ReturnType!(func) == void)) enum string generateEmptyFunction = q{ }; else static if (functionAttributes!(func) & FunctionAttribute.ref_) enum string generateEmptyFunction = q{ static typeof(return) dummy; return dummy; }; else enum string generateEmptyFunction = q{ return typeof(return).init; }; } /// ditto template generateAssertTrap(C, func...) { enum string generateAssertTrap = `throw new NotImplementedError("` ~ C.stringof ~ "." ~ __traits(identifier, func) ~ `");`; } private { pragma(mangle, "_d_toObject") extern(C) pure nothrow Object typecons_d_toObject(void* p); } /* * Avoids opCast operator overloading. */ private template dynamicCast(T) if (is(T == class) || is(T == interface)) { @trusted T dynamicCast(S)(inout S source) if (is(S == class) || is(S == interface)) { static if (is(Unqual!S : Unqual!T)) { import std.traits : QualifierOf; alias Qual = QualifierOf!S; // SharedOf or MutableOf alias TmpT = Qual!(Unqual!T); inout(TmpT) tmp = source; // bypass opCast by implicit conversion return *cast(T*)(&tmp); // + variable pointer cast + dereference } else { return cast(T)typecons_d_toObject(*cast(void**)(&source)); } } } unittest { class C { @disable opCast(T)() {} } auto c = new C; static assert(!__traits(compiles, cast(Object)c)); auto o = dynamicCast!Object(c); assert(c is o); interface I { @disable opCast(T)() {} Object instance(); } interface J { @disable opCast(T)() {} Object instance(); } class D : I, J { Object instance() { return this; } } I i = new D(); static assert(!__traits(compiles, cast(J)i)); J j = dynamicCast!J(i); assert(i.instance() is j.instance()); } /** * Supports structural based typesafe conversion. * * If $(D Source) has structural conformance with the $(D interface) $(D Targets), * wrap creates internal wrapper class which inherits $(D Targets) and * wrap $(D src) object, then return it. */ template wrap(Targets...) if (Targets.length >= 1 && allSatisfy!(isMutable, Targets)) { import std.meta : staticMap; // strict upcast auto wrap(Source)(inout Source src) @trusted pure nothrow if (Targets.length == 1 && is(Source : Targets[0])) { alias T = Select!(is(Source == shared), shared Targets[0], Targets[0]); return dynamicCast!(inout T)(src); } // structural upcast template wrap(Source) if (!allSatisfy!(Bind!(isImplicitlyConvertible, Source), Targets)) { auto wrap(inout Source src) { static assert(hasRequireMethods!(), "Source "~Source.stringof~ " does not have structural conformance to "~ Targets.stringof); alias T = Select!(is(Source == shared), shared Impl, Impl); return new inout T(src); } template FuncInfo(string s, F) { enum name = s; alias type = F; } // Concat all Targets function members into one tuple template Concat(size_t i = 0) { static if (i >= Targets.length) alias Concat = AliasSeq!(); else { alias Concat = AliasSeq!(GetOverloadedMethods!(Targets[i]), Concat!(i + 1)); } } // Remove duplicated functions based on the identifier name and function type covariance template Uniq(members...) { static if (members.length == 0) alias Uniq = AliasSeq!(); else { alias func = members[0]; enum name = __traits(identifier, func); alias type = FunctionTypeOf!func; template check(size_t i, mem...) { static if (i >= mem.length) enum ptrdiff_t check = -1; else { enum ptrdiff_t check = __traits(identifier, func) == __traits(identifier, mem[i]) && !is(DerivedFunctionType!(type, FunctionTypeOf!(mem[i])) == void) ? i : check!(i + 1, mem); } } enum ptrdiff_t x = 1 + check!(0, members[1 .. $]); static if (x >= 1) { alias typex = DerivedFunctionType!(type, FunctionTypeOf!(members[x])); alias remain = Uniq!(members[1 .. x], members[x + 1 .. $]); static if (remain.length >= 1 && remain[0].name == name && !is(DerivedFunctionType!(typex, remain[0].type) == void)) { alias F = DerivedFunctionType!(typex, remain[0].type); alias Uniq = AliasSeq!(FuncInfo!(name, F), remain[1 .. $]); } else alias Uniq = AliasSeq!(FuncInfo!(name, typex), remain); } else { alias Uniq = AliasSeq!(FuncInfo!(name, type), Uniq!(members[1 .. $])); } } } alias TargetMembers = Uniq!(Concat!()); // list of FuncInfo alias SourceMembers = GetOverloadedMethods!Source; // list of function symbols // Check whether all of SourceMembers satisfy covariance target in TargetMembers template hasRequireMethods(size_t i = 0) { static if (i >= TargetMembers.length) enum hasRequireMethods = true; else { enum hasRequireMethods = findCovariantFunction!(TargetMembers[i], Source, SourceMembers) != -1 && hasRequireMethods!(i + 1); } } // Internal wrapper class final class Impl : Structural, Targets { private: Source _wrap_source; this( inout Source s) inout @safe pure nothrow { _wrap_source = s; } this(shared inout Source s) shared inout @safe pure nothrow { _wrap_source = s; } // BUG: making private should work with NVI. protected final inout(Object) _wrap_getSource() inout @trusted { return dynamicCast!(inout Object)(_wrap_source); } import std.conv : to; import std.functional : forward; template generateFun(size_t i) { enum name = TargetMembers[i].name; enum fa = functionAttributes!(TargetMembers[i].type); static @property stc() { string r; if (fa & FunctionAttribute.property) r ~= "@property "; if (fa & FunctionAttribute.ref_) r ~= "ref "; if (fa & FunctionAttribute.pure_) r ~= "pure "; if (fa & FunctionAttribute.nothrow_) r ~= "nothrow "; if (fa & FunctionAttribute.trusted) r ~= "@trusted "; if (fa & FunctionAttribute.safe) r ~= "@safe "; return r; } static @property mod() { alias type = AliasSeq!(TargetMembers[i].type)[0]; string r; static if (is(type == immutable)) r ~= " immutable"; else { static if (is(type == shared)) r ~= " shared"; static if (is(type == const)) r ~= " const"; else static if (is(type == inout)) r ~= " inout"; //else --> mutable } return r; } enum n = to!string(i); static if (fa & FunctionAttribute.property) { static if (Parameters!(TargetMembers[i].type).length == 0) enum fbody = "_wrap_source."~name; else enum fbody = "_wrap_source."~name~" = forward!args"; } else { enum fbody = "_wrap_source."~name~"(forward!args)"; } enum generateFun = "override "~stc~"ReturnType!(TargetMembers["~n~"].type) " ~ name~"(Parameters!(TargetMembers["~n~"].type) args) "~mod~ "{ return "~fbody~"; }"; } public: mixin mixinAll!( staticMap!(generateFun, staticIota!(0, TargetMembers.length))); } } } /// ditto template wrap(Targets...) if (Targets.length >= 1 && !allSatisfy!(isMutable, Targets)) { import std.meta : staticMap; alias wrap = .wrap!(staticMap!(Unqual, Targets)); } // Internal class to support dynamic cross-casting private interface Structural { inout(Object) _wrap_getSource() inout @safe pure nothrow; } /** * Extract object which wrapped by $(D wrap). */ template unwrap(Target) if (isMutable!Target) { // strict downcast auto unwrap(Source)(inout Source src) @trusted pure nothrow if (is(Target : Source)) { alias T = Select!(is(Source == shared), shared Target, Target); return dynamicCast!(inout T)(src); } // structural downcast auto unwrap(Source)(inout Source src) @trusted pure nothrow if (!is(Target : Source)) { alias T = Select!(is(Source == shared), shared Target, Target); Object o = dynamicCast!(Object)(src); // remove qualifier do { if (auto a = dynamicCast!(Structural)(o)) { if (auto d = dynamicCast!(inout T)(o = a._wrap_getSource())) return d; } else if (auto d = dynamicCast!(inout T)(o)) return d; else break; } while (o); return null; } } /// ditto template unwrap(Target) if (!isMutable!Target) { alias unwrap = .unwrap!(Unqual!Target); } /// unittest { interface Quack { int quack(); @property int height(); } interface Flyer { @property int height(); } class Duck : Quack { int quack() { return 1; } @property int height() { return 10; } } class Human { int quack() { return 2; } @property int height() { return 20; } } Duck d1 = new Duck(); Human h1 = new Human(); interface Refleshable { int reflesh(); } // does not have structural conformance static assert(!__traits(compiles, d1.wrap!Refleshable)); static assert(!__traits(compiles, h1.wrap!Refleshable)); // strict upcast Quack qd = d1.wrap!Quack; assert(qd is d1); assert(qd.quack() == 1); // calls Duck.quack // strict downcast Duck d2 = qd.unwrap!Duck; assert(d2 is d1); // structural upcast Quack qh = h1.wrap!Quack; assert(qh.quack() == 2); // calls Human.quack // structural downcast Human h2 = qh.unwrap!Human; assert(h2 is h1); // structural upcast (two steps) Quack qx = h1.wrap!Quack; // Human -> Quack Flyer fx = qx.wrap!Flyer; // Quack -> Flyer assert(fx.height == 20); // calls Human.height // strucural downcast (two steps) Quack qy = fx.unwrap!Quack; // Flyer -> Quack Human hy = qy.unwrap!Human; // Quack -> Human assert(hy is h1); // strucural downcast (one step) Human hz = fx.unwrap!Human; // Flyer -> Human assert(hz is h1); } /// unittest { interface A { int run(); } interface B { int stop(); @property int status(); } class X { int run() { return 1; } int stop() { return 2; } @property int status() { return 3; } } auto x = new X(); auto ab = x.wrap!(A, B); A a = ab; B b = ab; assert(a.run() == 1); assert(b.stop() == 2); assert(b.status == 3); static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property); } unittest { class A { int draw() { return 1; } int draw(int v) { return v; } int draw() const { return 2; } int draw() shared { return 3; } int draw() shared const { return 4; } int draw() immutable { return 5; } } interface Drawable { int draw(); int draw() const; int draw() shared; int draw() shared const; int draw() immutable; } interface Drawable2 { int draw(int v); } auto ma = new A(); auto sa = new shared A(); auto ia = new immutable A(); { Drawable md = ma.wrap!Drawable; const Drawable cd = ma.wrap!Drawable; shared Drawable sd = sa.wrap!Drawable; shared const Drawable scd = sa.wrap!Drawable; immutable Drawable id = ia.wrap!Drawable; assert( md.draw() == 1); assert( cd.draw() == 2); assert( sd.draw() == 3); assert(scd.draw() == 4); assert( id.draw() == 5); } { Drawable2 d = ma.wrap!Drawable2; static assert(!__traits(compiles, d.draw())); assert(d.draw(10) == 10); } } unittest { // Bugzilla 10377 import std.range, std.algorithm; interface MyInputRange(T) { @property T front(); void popFront(); @property bool empty(); } //auto o = iota(0,10,1).inputRangeObject(); //pragma(msg, __traits(allMembers, typeof(o))); auto r = iota(0,10,1).inputRangeObject().wrap!(MyInputRange!int)(); assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); } unittest { // Bugzilla 10536 interface Interface { int foo(); } class Pluggable { int foo() { return 1; } @disable void opCast(T, this X)(); // ! } Interface i = new Pluggable().wrap!Interface; assert(i.foo() == 1); } unittest { // Enhancement 10538 interface Interface { int foo(); int bar(int); } class Pluggable { int opDispatch(string name, A...)(A args) { return 100; } } Interface i = wrap!Interface(new Pluggable()); assert(i.foo() == 100); assert(i.bar(10) == 100); } // Make a tuple of non-static function symbols private template GetOverloadedMethods(T) { import std.meta : Filter; alias allMembers = AliasSeq!(__traits(allMembers, T)); template follows(size_t i = 0) { static if (i >= allMembers.length) { alias follows = AliasSeq!(); } else static if (!__traits(compiles, mixin("T."~allMembers[i]))) { alias follows = follows!(i + 1); } else { enum name = allMembers[i]; template isMethod(alias f) { static if (is(typeof(&f) F == F*) && is(F == function)) enum isMethod = !__traits(isStaticFunction, f); else enum isMethod = false; } alias follows = AliasSeq!( std.meta.Filter!(isMethod, __traits(getOverloads, T, name)), follows!(i + 1)); } } alias GetOverloadedMethods = follows!(); } // find a function from Fs that has same identifier and covariant type with f private template findCovariantFunction(alias finfo, Source, Fs...) { template check(size_t i = 0) { static if (i >= Fs.length) enum ptrdiff_t check = -1; else { enum ptrdiff_t check = (finfo.name == __traits(identifier, Fs[i])) && isCovariantWith!(FunctionTypeOf!(Fs[i]), finfo.type) ? i : check!(i + 1); } } enum x = check!(); static if (x == -1 && is(typeof(Source.opDispatch))) { alias Params = Parameters!(finfo.type); enum ptrdiff_t findCovariantFunction = is(typeof(( Source).init.opDispatch!(finfo.name)(Params.init))) || is(typeof(( const Source).init.opDispatch!(finfo.name)(Params.init))) || is(typeof(( immutable Source).init.opDispatch!(finfo.name)(Params.init))) || is(typeof(( shared Source).init.opDispatch!(finfo.name)(Params.init))) || is(typeof((shared const Source).init.opDispatch!(finfo.name)(Params.init))) ? ptrdiff_t.max : -1; } else enum ptrdiff_t findCovariantFunction = x; } private enum TypeModifier { mutable = 0, // type is mutable const_ = 1, // type is const immutable_ = 2, // type is immutable shared_ = 4, // type is shared inout_ = 8, // type is wild } private template TypeMod(T) { static if (is(T == immutable)) { enum mod1 = TypeModifier.immutable_; enum mod2 = 0; } else { enum mod1 = is(T == shared) ? TypeModifier.shared_ : 0; static if (is(T == const)) enum mod2 = TypeModifier.const_; else static if (is(T == inout)) enum mod2 = TypeModifier.inout_; else enum mod2 = TypeModifier.mutable; } enum TypeMod = cast(TypeModifier)(mod1 | mod2); } version(unittest) { private template UnittestFuncInfo(alias f) { enum name = __traits(identifier, f); alias type = FunctionTypeOf!f; } } unittest { class A { int draw() { return 1; } @property int value() { return 2; } final int run() { return 3; } } alias methods = GetOverloadedMethods!A; alias int F1(); alias @property int F2(); alias string F3(); alias nothrow @trusted uint F4(); alias int F5(Object); alias bool F6(Object); static assert(methods.length == 3 + 4); static assert(__traits(identifier, methods[0]) == "draw" && is(typeof(&methods[0]) == F1*)); static assert(__traits(identifier, methods[1]) == "value" && is(typeof(&methods[1]) == F2*)); static assert(__traits(identifier, methods[2]) == "run" && is(typeof(&methods[2]) == F1*)); int draw() { return 0; } @property int value() { return 0; } void opEquals() {} int nomatch() { return 0; } static assert(findCovariantFunction!(UnittestFuncInfo!draw, A, methods) == 0); static assert(findCovariantFunction!(UnittestFuncInfo!value, A, methods) == 1); static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, A, methods) == -1); static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, A, methods) == -1); // considering opDispatch class B { void opDispatch(string name, A...)(A) {} } alias methodsB = GetOverloadedMethods!B; static assert(findCovariantFunction!(UnittestFuncInfo!draw, B, methodsB) == ptrdiff_t.max); static assert(findCovariantFunction!(UnittestFuncInfo!value, B, methodsB) == ptrdiff_t.max); static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, B, methodsB) == ptrdiff_t.max); static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, B, methodsB) == ptrdiff_t.max); } private template DerivedFunctionType(T...) { static if (!T.length) { alias DerivedFunctionType = void; } else static if (T.length == 1) { static if (is(T[0] == function)) { alias DerivedFunctionType = T[0]; } else { alias DerivedFunctionType = void; } } else static if (is(T[0] P0 == function) && is(T[1] P1 == function)) { alias FA = FunctionAttribute; alias F0 = T[0], R0 = ReturnType!F0, PSTC0 = ParameterStorageClassTuple!F0; alias F1 = T[1], R1 = ReturnType!F1, PSTC1 = ParameterStorageClassTuple!F1; enum FA0 = functionAttributes!F0; enum FA1 = functionAttributes!F1; template CheckParams(size_t i = 0) { static if (i >= P0.length) enum CheckParams = true; else { enum CheckParams = (is(P0[i] == P1[i]) && PSTC0[i] == PSTC1[i]) && CheckParams!(i + 1); } } static if (R0.sizeof == R1.sizeof && !is(CommonType!(R0, R1) == void) && P0.length == P1.length && CheckParams!() && TypeMod!F0 == TypeMod!F1 && variadicFunctionStyle!F0 == variadicFunctionStyle!F1 && functionLinkage!F0 == functionLinkage!F1 && ((FA0 ^ FA1) & (FA.ref_ | FA.property)) == 0) { alias R = Select!(is(R0 : R1), R0, R1); alias FX = FunctionTypeOf!(R function(P0)); // @system is default alias FY = SetFunctionAttributes!(FX, functionLinkage!F0, (FA0 | FA1) & ~FA.system); alias DerivedFunctionType = DerivedFunctionType!(FY, T[2 .. $]); } else alias DerivedFunctionType = void; } else alias DerivedFunctionType = void; } unittest { // attribute covariance alias int F1(); static assert(is(DerivedFunctionType!(F1, F1) == F1)); alias int F2() pure nothrow; static assert(is(DerivedFunctionType!(F1, F2) == F2)); alias int F3() @safe; alias int F23() @safe pure nothrow; static assert(is(DerivedFunctionType!(F2, F3) == F23)); // return type covariance alias long F4(); static assert(is(DerivedFunctionType!(F1, F4) == void)); class C {} class D : C {} alias C F5(); alias D F6(); static assert(is(DerivedFunctionType!(F5, F6) == F6)); alias typeof(null) F7(); alias int[] F8(); alias int* F9(); static assert(is(DerivedFunctionType!(F5, F7) == F7)); static assert(is(DerivedFunctionType!(F7, F8) == void)); static assert(is(DerivedFunctionType!(F7, F9) == F7)); // variadic type equality alias int F10(int); alias int F11(int...); alias int F12(int, ...); static assert(is(DerivedFunctionType!(F10, F11) == void)); static assert(is(DerivedFunctionType!(F10, F12) == void)); static assert(is(DerivedFunctionType!(F11, F12) == void)); // linkage equality alias extern(C) int F13(int); alias extern(D) int F14(int); alias extern(Windows) int F15(int); static assert(is(DerivedFunctionType!(F13, F14) == void)); static assert(is(DerivedFunctionType!(F13, F15) == void)); static assert(is(DerivedFunctionType!(F14, F15) == void)); // ref & @property equality alias int F16(int); alias ref int F17(int); alias @property int F18(int); static assert(is(DerivedFunctionType!(F16, F17) == void)); static assert(is(DerivedFunctionType!(F16, F18) == void)); static assert(is(DerivedFunctionType!(F17, F18) == void)); } package template staticIota(int beg, int end) { static if (beg + 1 >= end) { static if (beg >= end) { alias staticIota = AliasSeq!(); } else { alias staticIota = AliasSeq!(+beg); } } else { enum mid = beg + (end - beg) / 2; alias staticIota = AliasSeq!(staticIota!(beg, mid), staticIota!(mid, end)); } } private template mixinAll(mixins...) { static if (mixins.length == 1) { static if (is(typeof(mixins[0]) == string)) { mixin(mixins[0]); } else { alias it = mixins[0]; mixin it; } } else static if (mixins.length >= 2) { mixin mixinAll!(mixins[ 0 .. $/2]); mixin mixinAll!(mixins[$/2 .. $ ]); } } private template Bind(alias Template, args1...) { alias Bind(args2...) = Template!(args1, args2); } /** Options regarding auto-initialization of a $(D RefCounted) object (see the definition of $(D RefCounted) below). */ enum RefCountedAutoInitialize { /// Do not auto-initialize the object no, /// Auto-initialize the object yes, } /** Defines a reference-counted object containing a $(D T) value as payload. $(D RefCounted) keeps track of all references of an object, and when the reference count goes down to zero, frees the underlying store. $(D RefCounted) uses $(D malloc) and $(D free) for operation. $(D RefCounted) is unsafe and should be used with care. No references to the payload should be escaped outside the $(D RefCounted) object. The $(D autoInit) option makes the object ensure the store is automatically initialized. Leaving $(D autoInit == RefCountedAutoInitialize.yes) (the default option) is convenient but has the cost of a test whenever the payload is accessed. If $(D autoInit == RefCountedAutoInitialize.no), user code must call either $(D refCountedStore.isInitialized) or $(D refCountedStore.ensureInitialized) before attempting to access the payload. Not doing so results in null pointer dereference. */ struct RefCounted(T, RefCountedAutoInitialize autoInit = RefCountedAutoInitialize.yes) if (!is(T == class) && !(is(T == interface))) { /// $(D RefCounted) storage implementation. struct RefCountedStore { private struct Impl { T _payload; size_t _count; } private Impl* _store; private void initialize(A...)(auto ref A args) { import core.exception : onOutOfMemoryError; import core.memory : GC; import core.stdc.stdlib : malloc; import std.conv : emplace; _store = cast(Impl*)malloc(Impl.sizeof); if (_store is null) onOutOfMemoryError(); static if (hasIndirections!T) GC.addRange(&_store._payload, T.sizeof); emplace(&_store._payload, args); _store._count = 1; } private void move(ref T source) { import core.exception : onOutOfMemoryError; import core.memory : GC; import core.stdc.stdlib : malloc; import core.stdc.string : memcpy, memset; _store = cast(Impl*)malloc(Impl.sizeof); if (_store is null) onOutOfMemoryError(); static if (hasIndirections!T) GC.addRange(&_store._payload, T.sizeof); // Can't use std.algorithm.move(source, _store._payload) // here because it requires the target to be initialized. // Might be worth to add this as `moveEmplace` // Can avoid destructing result. static if (hasElaborateAssign!T || !isAssignable!T) memcpy(&_store._payload, &source, T.sizeof); else _store._payload = source; // If the source defines a destructor or a postblit hook, we must obliterate the // object in order to avoid double freeing and undue aliasing static if (hasElaborateDestructor!T || hasElaborateCopyConstructor!T) { // If T is nested struct, keep original context pointer static if (__traits(isNested, T)) enum sz = T.sizeof - (void*).sizeof; else enum sz = T.sizeof; auto init = typeid(T).initializer(); if (init.ptr is null) // null ptr means initialize to 0s memset(&source, 0, sz); else memcpy(&source, init.ptr, sz); } _store._count = 1; } /** Returns $(D true) if and only if the underlying store has been allocated and initialized. */ @property nothrow @safe pure @nogc bool isInitialized() const { return _store !is null; } /** Returns underlying reference count if it is allocated and initialized (a positive integer), and $(D 0) otherwise. */ @property nothrow @safe pure @nogc size_t refCount() const { return isInitialized ? _store._count : 0; } /** Makes sure the payload was properly initialized. Such a call is typically inserted before using the payload. */ void ensureInitialized() { if (!isInitialized) initialize(); } } RefCountedStore _refCounted; /// Returns storage implementation struct. @property nothrow @safe ref inout(RefCountedStore) refCountedStore() inout { return _refCounted; } /** Constructor that initializes the payload. Postcondition: $(D refCountedStore.isInitialized) */ this(A...)(auto ref A args) if (A.length > 0) { _refCounted.initialize(args); } /// Ditto this(T val) { _refCounted.move(val); } /** Constructor that tracks the reference count appropriately. If $(D !refCountedStore.isInitialized), does nothing. */ this(this) @safe pure nothrow @nogc { if (!_refCounted.isInitialized) return; ++_refCounted._store._count; } /** Destructor that tracks the reference count appropriately. If $(D !refCountedStore.isInitialized), does nothing. When the reference count goes down to zero, calls $(D destroy) agaist the payload and calls $(D free) to deallocate the corresponding resource. */ ~this() { if (!_refCounted.isInitialized) return; assert(_refCounted._store._count > 0); if (--_refCounted._store._count) return; // Done, deallocate .destroy(_refCounted._store._payload); static if (hasIndirections!T) { import core.memory : GC; GC.removeRange(&_refCounted._store._payload); } import core.stdc.stdlib : free; free(_refCounted._store); _refCounted._store = null; } /** Assignment operators */ void opAssign(typeof(this) rhs) { import std.algorithm : swap; swap(_refCounted._store, rhs._refCounted._store); } /// Ditto void opAssign(T rhs) { import std.algorithm : move; static if (autoInit == RefCountedAutoInitialize.yes) { _refCounted.ensureInitialized(); } else { assert(_refCounted.isInitialized); } move(rhs, _refCounted._store._payload); } //version to have a single properly ddoc'ed function (w/ correct sig) version(StdDdoc) { /** Returns a reference to the payload. If (autoInit == RefCountedAutoInitialize.yes), calls $(D refCountedStore.ensureInitialized). Otherwise, just issues $(D assert(refCountedStore.isInitialized)). Used with $(D alias refCountedPayload this;), so callers can just use the $(D RefCounted) object as a $(D T). $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).) So if $(D autoInit == RefCountedAutoInitialize.no) or called for a constant or immutable object, then $(D refCountedPayload) will also be qualified as safe and nothrow (but will still assert if not initialized). */ @property ref T refCountedPayload() return; /// ditto @property nothrow @safe pure @nogc ref inout(T) refCountedPayload() inout return; } else { static if (autoInit == RefCountedAutoInitialize.yes) { //Can't use inout here because of potential mutation @property ref T refCountedPayload() return { _refCounted.ensureInitialized(); return _refCounted._store._payload; } } @property nothrow @safe pure @nogc ref inout(T) refCountedPayload() inout return { assert(_refCounted.isInitialized, "Attempted to access an uninitialized payload."); return _refCounted._store._payload; } } /** Returns a reference to the payload. If (autoInit == RefCountedAutoInitialize.yes), calls $(D refCountedStore.ensureInitialized). Otherwise, just issues $(D assert(refCountedStore.isInitialized)). */ alias refCountedPayload this; } /// unittest { // A pair of an $(D int) and a $(D size_t) - the latter being the // reference count - will be dynamically allocated auto rc1 = RefCounted!int(5); assert(rc1 == 5); // No more allocation, add just one extra reference count auto rc2 = rc1; // Reference semantics rc2 = 42; assert(rc1 == 42); // the pair will be freed when rc1 and rc2 go out of scope } unittest { RefCounted!int* p; { auto rc1 = RefCounted!int(5); p = &rc1; assert(rc1 == 5); assert(rc1._refCounted._store._count == 1); auto rc2 = rc1; assert(rc1._refCounted._store._count == 2); // Reference semantics rc2 = 42; assert(rc1 == 42); rc2 = rc2; assert(rc2._refCounted._store._count == 2); rc1 = rc2; assert(rc1._refCounted._store._count == 2); } assert(p._refCounted._store == null); // RefCounted as a member struct A { RefCounted!int x; this(int y) { x._refCounted.initialize(y); } A copy() { auto another = this; return another; } } auto a = A(4); auto b = a.copy(); assert(a.x._refCounted._store._count == 2, "BUG 4356 still unfixed"); } unittest { import std.algorithm : swap; RefCounted!int p1, p2; swap(p1, p2); } // 6606 unittest { union U { size_t i; void* p; } struct S { U u; } alias SRC = RefCounted!S; } // 6436 unittest { struct S { this(ref int val) { assert(val == 3); ++val; } } int val = 3; auto s = RefCounted!S(val); assert(val == 4); } unittest { RefCounted!int a; a = 5; //This should not assert assert(a == 5); RefCounted!int b; b = a; //This should not assert either assert(b == 5); } /** * Initializes a `RefCounted` with `val`. The template parameter * `T` of `RefCounted` is inferred from `val`. * This function can be used to move non-copyable values to the heap. * It also disables the `autoInit` option of `RefCounted`. * * Params: * val = The value to be reference counted * Returns: * An initialized $(D RefCounted) containing $(D val). * See_Also: * $(WEB http://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared, C++'s make_shared) */ RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val) { typeof(return) res; res._refCounted.move(val); return res; } /// unittest { static struct File { string name; @disable this(this); // not copyable ~this() { name = null; } } auto file = File("name"); assert(file.name == "name"); // file cannot be copied and has unique ownership static assert(!__traits(compiles, {auto file2 = file;})); // make the file refcounted to share ownership import std.algorithm.mutation : move; auto rcFile = refCounted(move(file)); assert(rcFile.name == "name"); assert(file.name == null); auto rcFile2 = rcFile; assert(rcFile.refCountedStore.refCount == 2); // file gets properly closed when last reference is dropped } /** Creates a proxy for the value `a` that will forward all operations while disabling implicit conversions. The aliased item `a` must be an $(B lvalue). This is useful for creating a new type from the "base" type (though this is $(B not) a subtype-supertype relationship; the new type is not related to the old type in any way, by design). The new type supports all operations that the underlying type does, including all operators such as `+`, `--`, `<`, `[]`, etc. Params: a = The value to act as a proxy for all operations. It must be an lvalue. */ mixin template Proxy(alias a) { private alias ValueType = typeof({ return a; }()); private enum bool accessibleFrom(T) = is(typeof((ref T self){ cast(void)mixin("self." ~ a.stringof); })); static if (is(typeof(this) == class)) { override bool opEquals(Object o) { if (auto b = cast(typeof(this))o) { import std.algorithm : startsWith; static assert(startsWith(a.stringof, "this.")); return a == mixin("b."~a.stringof[5..$]); // remove "this." } return false; } bool opEquals(T)(T b) if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a)))) { static if (is(typeof(a.opEquals(b)))) return a.opEquals(b); else static if (is(typeof(b.opEquals(a)))) return b.opEquals(a); else return a == b; } override int opCmp(Object o) { if (auto b = cast(typeof(this))o) { import std.algorithm : startsWith; static assert(startsWith(a.stringof, "this.")); // remove "this." return a < mixin("b."~a.stringof[5..$]) ? -1 : a > mixin("b."~a.stringof[5..$]) ? +1 : 0; } static if (is(ValueType == class)) return a.opCmp(o); else throw new Exception("Attempt to compare a "~typeid(this).toString~" and a "~typeid(o).toString); } int opCmp(T)(auto ref const T b) if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a)))) { static if (is(typeof(a.opCmp(b)))) return a.opCmp(b); else static if (is(typeof(b.opCmp(a)))) return -b.opCmp(b); else return a < b ? -1 : a > b ? +1 : 0; } static if (accessibleFrom!(const typeof(this))) { override hash_t toHash() const nothrow @trusted { static if (is(typeof(&a) == ValueType*)) alias v = a; else auto v = a; // if a is (property) function return typeid(ValueType).getHash(cast(const void*)&v); } } } else { auto ref opEquals(this X, B)(auto ref B b) { static if (is(immutable B == immutable typeof(this))) { import std.algorithm : startsWith; static assert(startsWith(a.stringof, "this.")); return a == mixin("b."~a.stringof[5..$]); // remove "this." } else return a == b; } auto ref opCmp(this X, B)(auto ref B b) if (!is(typeof(a.opCmp(b))) || !is(typeof(b.opCmp(a)))) { static if (is(typeof(a.opCmp(b)))) return a.opCmp(b); else static if (is(typeof(b.opCmp(a)))) return -b.opCmp(a); else static if (isFloatingPoint!ValueType || isFloatingPoint!B) return a < b ? -1 : a > b ? +1 : a == b ? 0 : float.nan; else return a < b ? -1 : (a > b); } static if (accessibleFrom!(const typeof(this))) { hash_t toHash() const nothrow @trusted { static if (is(typeof(&a) == ValueType*)) alias v = a; else auto v = a; // if a is (property) function return typeid(ValueType).getHash(cast(const void*)&v); } } } auto ref opCall(this X, Args...)(auto ref Args args) { return a(args); } auto ref opCast(T, this X)() { return cast(T)a; } auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; } auto ref opSlice(this X )() { return a[]; } auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) { return a[b..e]; } auto ref opUnary (string op, this X )() { return mixin(op~"a"); } auto ref opIndexUnary(string op, this X, D...)(auto ref D i) { return mixin(op~"a[i]"); } auto ref opSliceUnary(string op, this X )() { return mixin(op~"a[]"); } auto ref opSliceUnary(string op, this X, B, E)(auto ref B b, auto ref E e) { return mixin(op~"a[b..e]"); } auto ref opBinary(string op, this X, B)(auto ref B b) if (op == "in" && is(typeof(a in b)) || op != "in") { return mixin("a "~op~" b"); } auto ref opBinaryRight(string op, this X, B)(auto ref B b) { return mixin("b "~op~" a"); } static if (!is(typeof(this) == class)) { private import std.traits; static if (isAssignable!ValueType) { auto ref opAssign(this X)(auto ref typeof(this) v) { a = mixin("v."~a.stringof[5..$]); // remove "this." return this; } } else { @disable void opAssign(this X)(auto ref typeof(this) v); } } auto ref opAssign (this X, V )(auto ref V v) if (!is(V == typeof(this))) { return a = v; } auto ref opIndexAssign(this X, V, D...)(auto ref V v, auto ref D i) { return a[i] = v; } auto ref opSliceAssign(this X, V )(auto ref V v) { return a[] = v; } auto ref opSliceAssign(this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e) { return a[b..e] = v; } auto ref opOpAssign (string op, this X, V )(auto ref V v) { return mixin("a " ~op~"= v"); } auto ref opIndexOpAssign(string op, this X, V, D...)(auto ref V v, auto ref D i) { return mixin("a[i] " ~op~"= v"); } auto ref opSliceOpAssign(string op, this X, V )(auto ref V v) { return mixin("a[] " ~op~"= v"); } auto ref opSliceOpAssign(string op, this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e) { return mixin("a[b..e] "~op~"= v"); } template opDispatch(string name) { static if (is(typeof(__traits(getMember, a, name)) == function)) { // non template function auto ref opDispatch(this X, Args...)(auto ref Args args) { return mixin("a."~name~"(args)"); } } else static if (is(typeof({ enum x = mixin("a."~name); }))) { // built-in type field, manifest constant, and static non-mutable field enum opDispatch = mixin("a."~name); } else static if (is(typeof(mixin("a."~name))) || __traits(getOverloads, a, name).length != 0) { // field or property function @property auto ref opDispatch(this X)() { return mixin("a."~name); } @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); } } else { // member template template opDispatch(T...) { enum targs = T.length ? "!T" : ""; auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); } } } } import std.traits : isArray; static if (isArray!ValueType) { auto opDollar() const { return a.length; } } else static if (is(typeof(a.opDollar!0))) { auto ref opDollar(size_t pos)() { return a.opDollar!pos(); } } else static if (is(typeof(a.opDollar) == function)) { auto ref opDollar() { return a.opDollar(); } } else static if (is(typeof(a.opDollar))) { alias opDollar = a.opDollar; } } /// unittest { struct MyInt { private int value; mixin Proxy!value; this(int n){ value = n; } } MyInt n = 10; // Enable operations that original type has. ++n; assert(n == 11); assert(n * 2 == 22); void func(int n) { } // Disable implicit conversions to original type. //int x = n; //func(n); } ///The proxied value must be an $(B lvalue). unittest { struct NewIntType { //Won't work; the literal '1' is //is an rvalue, not an lvalue //mixin Proxy!1; //Okay, n is an lvalue int n; mixin Proxy!n; this(int n) { this.n = n; } } NewIntType nit = 0; nit++; assert(nit == 1); struct NewObjectType { Object obj; //Ok, obj is an lvalue mixin Proxy!obj; this (Object o) { obj = o; } } NewObjectType not = new Object(); assert(__traits(compiles, not.toHash())); } /** There is one exception to the fact that the new type is not related to the old type. $(DDSUBLINK spec/function,pseudo-member, Pseudo-member) functions are usable with the new type; they will be forwarded on to the proxied value. */ unittest { import std.math; float f = 1.0; assert(!f.isInfinity); struct NewFloat { float _; mixin Proxy!_; this(float f) { _ = f; } } NewFloat nf = 1.0f; assert(!nf.isInfinity); } unittest { static struct MyInt { private int value; mixin Proxy!value; this(int n) inout { value = n; } enum str = "str"; static immutable arr = [1,2,3]; } foreach (T; AliasSeq!(MyInt, const MyInt, immutable MyInt)) { T m = 10; static assert(!__traits(compiles, { int x = m; })); static assert(!__traits(compiles, { void func(int n){} func(m); })); assert(m == 10); assert(m != 20); assert(m < 20); assert(+m == 10); assert(-m == -10); assert(cast(double)m == 10.0); assert(m + 10 == 20); assert(m - 5 == 5); assert(m * 20 == 200); assert(m / 2 == 5); assert(10 + m == 20); assert(15 - m == 5); assert(20 * m == 200); assert(50 / m == 5); static if (is(T == MyInt)) // mutable { assert(++m == 11); assert(m++ == 11); assert(m == 12); assert(--m == 11); assert(m-- == 11); assert(m == 10); m = m; m = 20; assert(m == 20); } static assert(T.max == int.max); static assert(T.min == int.min); static assert(T.init == int.init); static assert(T.str == "str"); static assert(T.arr == [1,2,3]); } } unittest { static struct MyArray { private int[] value; mixin Proxy!value; this(int[] arr) { value = arr; } this(immutable int[] arr) immutable { value = arr; } } foreach (T; AliasSeq!(MyArray, const MyArray, immutable MyArray)) { static if (is(T == immutable) && !is(typeof({ T a = [1,2,3,4]; }))) T a = [1,2,3,4].idup; // workaround until qualified ctor is properly supported else T a = [1,2,3,4]; assert(a == [1,2,3,4]); assert(a != [5,6,7,8]); assert(+a[0] == 1); version (LittleEndian) assert(cast(ulong[])a == [0x0000_0002_0000_0001, 0x0000_0004_0000_0003]); else assert(cast(ulong[])a == [0x0000_0001_0000_0002, 0x0000_0003_0000_0004]); assert(a ~ [10,11] == [1,2,3,4,10,11]); assert(a[0] == 1); assert(a[] == [1,2,3,4]); assert(a[2..4] == [3,4]); static if (is(T == MyArray)) // mutable { a = a; a = [5,6,7,8]; assert(a == [5,6,7,8]); a[0] = 0; assert(a == [0,6,7,8]); a[] = 1; assert(a == [1,1,1,1]); a[0..3] = 2; assert(a == [2,2,2,1]); a[0] += 2; assert(a == [4,2,2,1]); a[] *= 2; assert(a == [8,4,4,2]); a[0..2] /= 2; assert(a == [4,2,4,2]); } } } unittest { class Foo { int field; @property int val1() const { return field; } @property void val1(int n) { field = n; } @property ref int val2() { return field; } int func(int x, int y) const { return x; } void func1(ref int a) { a = 9; } T ifti1(T)(T t) { return t; } void ifti2(Args...)(Args args) { } void ifti3(T, Args...)(Args args) { } T opCast(T)(){ return T.init; } T tempfunc(T)() { return T.init; } } class Hoge { Foo foo; mixin Proxy!foo; this(Foo f) { foo = f; } } auto h = new Hoge(new Foo()); int n; static assert(!__traits(compiles, { Foo f = h; })); // field h.field = 1; // lhs of assign n = h.field; // rhs of assign assert(h.field == 1); // lhs of BinExp assert(1 == h.field); // rhs of BinExp assert(n == 1); // getter/setter property function h.val1 = 4; n = h.val1; assert(h.val1 == 4); assert(4 == h.val1); assert(n == 4); // ref getter property function h.val2 = 8; n = h.val2; assert(h.val2 == 8); assert(8 == h.val2); assert(n == 8); // member function assert(h.func(2,4) == 2); h.func1(n); assert(n == 9); // IFTI assert(h.ifti1(4) == 4); h.ifti2(4); h.ifti3!int(4, 3); // bug5896 test assert(h.opCast!int() == 0); assert(cast(int)h == 0); const ih = new const Hoge(new Foo()); static assert(!__traits(compiles, ih.opCast!int())); static assert(!__traits(compiles, cast(int)ih)); // template member function assert(h.tempfunc!int() == 0); } unittest // about Proxy inside a class { class MyClass { int payload; mixin Proxy!payload; this(int i){ payload = i; } string opCall(string msg){ return msg; } int pow(int i){ return payload ^^ i; } } class MyClass2 { MyClass payload; mixin Proxy!payload; this(int i){ payload = new MyClass(i); } } class MyClass3 { int payload; mixin Proxy!payload; this(int i){ payload = i; } } // opEquals Object a = new MyClass(5); Object b = new MyClass(5); Object c = new MyClass2(5); Object d = new MyClass3(5); assert(a == b); assert((cast(MyClass)a) == 5); assert(5 == (cast(MyClass)b)); assert(5 == cast(MyClass2)c); assert(a != d); assert(c != a); // oops! above line is unexpected, isn't it? // the reason is below. // MyClass2.opEquals knows MyClass but, // MyClass.opEquals doesn't know MyClass2. // so, c.opEquals(a) is true, but a.opEquals(c) is false. // furthermore, opEquals(T) couldn't be invoked. assert((cast(MyClass2)c) != (cast(MyClass)a)); // opCmp Object e = new MyClass2(7); assert(a < cast(MyClass2)e); // OK. and assert(e > a); // OK, but... // assert(a < e); // RUNTIME ERROR! // assert((cast(MyClass)a) < e); // RUNTIME ERROR! assert(3 < cast(MyClass)a); assert((cast(MyClass2)e) < 11); // opCall assert((cast(MyClass2)e)("hello") == "hello"); // opCast assert((cast(MyClass)(cast(MyClass2)c)) == a); assert((cast(int)(cast(MyClass2)c)) == 5); // opIndex class MyClass4 { string payload; mixin Proxy!payload; this(string s){ payload = s; } } class MyClass5 { MyClass4 payload; mixin Proxy!payload; this(string s){ payload = new MyClass4(s); } } auto f = new MyClass4("hello"); assert(f[1] == 'e'); auto g = new MyClass5("hello"); assert(f[1] == 'e'); // opSlice assert(f[2..4] == "ll"); // opUnary assert(-(cast(MyClass2)c) == -5); // opBinary assert((cast(MyClass)a) + (cast(MyClass2)c) == 10); assert(5 + cast(MyClass)a == 10); // opAssign (cast(MyClass2)c) = 11; assert((cast(MyClass2)c) == 11); (cast(MyClass2)c) = new MyClass(13); assert((cast(MyClass2)c) == 13); // opOpAssign assert((cast(MyClass2)c) += 4); assert((cast(MyClass2)c) == 17); // opDispatch assert((cast(MyClass2)c).pow(2) == 289); // opDollar assert(f[2..$-1] == "ll"); // toHash int[Object] hash; hash[a] = 19; hash[c] = 21; assert(hash[b] == 19); assert(hash[c] == 21); } unittest { struct MyInt { int payload; mixin Proxy!payload; } MyInt v; v = v; struct Foo { @disable void opAssign(typeof(this)); } struct MyFoo { Foo payload; mixin Proxy!payload; } MyFoo f; static assert(!__traits(compiles, f = f)); struct MyFoo2 { Foo payload; mixin Proxy!payload; // override default Proxy behavior void opAssign(typeof(this) rhs){} } MyFoo2 f2; f2 = f2; } unittest { // bug8613 static struct Name { mixin Proxy!val; private string val; this(string s) { val = s; } } bool[Name] names; names[Name("a")] = true; bool* b = Name("a") in names; } unittest { // bug14213, using function for the payload static struct S { int foo() { return 12; } mixin Proxy!foo; } static class C { int foo() { return 12; } mixin Proxy!foo; } S s; assert(s + 1 == 13); C c = new C(); assert(s * 2 == 24); } // Check all floating point comparisons for both Proxy and Typedef, // also against int and a Typedef!int, to be as regression-proof // as possible. bug 15561 unittest { static struct MyFloatImpl { float value; mixin Proxy!value; } static void allFail(T0, T1)(T0 a, T1 b) { assert(!(a==b)); assert(!(ab)); assert(!(a>=b)); } foreach (T1; AliasSeq!(MyFloatImpl, Typedef!float, Typedef!double, float, real, Typedef!int, int)) { foreach (T2; AliasSeq!(MyFloatImpl, Typedef!float)) { T1 a; T2 b; static if (isFloatingPoint!T1 || isFloatingPoint!(TypedefType!T1)) allFail(a, b); a = 3; allFail(a, b); b = 4; assert(a!=b); assert(ab)); assert(!(a>=b)); a = 4; assert(a==b); assert(!(ab)); assert(a>=b); } } } /** $(B Typedef) allows the creation of a unique type which is based on an existing type. Unlike the $(D alias) feature, $(B Typedef) ensures the two types are not considered as equals. Example: ---- alias MyInt = Typedef!int; static void takeInt(int) { } static void takeMyInt(MyInt) { } int i; takeInt(i); // ok takeMyInt(i); // fails MyInt myInt; takeInt(myInt); // fails takeMyInt(myInt); // ok ---- Params: init = Optional initial value for the new type. For example: ---- alias MyInt = Typedef!(int, 10); MyInt myInt; assert(myInt == 10); // default-initialized to 10 ---- cookie = Optional, used to create multiple unique types which are based on the same origin type $(D T). For example: ---- alias TypeInt1 = Typedef!int; alias TypeInt2 = Typedef!int; // The two Typedefs are the same type. static assert(is(TypeInt1 == TypeInt2)); alias MoneyEuros = Typedef!(float, float.init, "euros"); alias MoneyDollars = Typedef!(float, float.init, "dollars"); // The two Typedefs are _not_ the same type. static assert(!is(MoneyEuros == MoneyDollars)); ---- Note: If a library routine cannot handle the Typedef type, you can use the $(D TypedefType) template to extract the type which the Typedef wraps. */ struct Typedef(T, T init = T.init, string cookie=null) { private T Typedef_payload = init; this(T init) { Typedef_payload = init; } this(Typedef tdef) { this(tdef.Typedef_payload); } // We need to add special overload for cast(Typedef!X)exp, // thus we can't simply inherit Proxy!Typedef_payload T2 opCast(T2 : Typedef!(T, Unused), this X, T, Unused...)() { return T2(cast(T)Typedef_payload); } auto ref opCast(T2, this X)() { return cast(T2)Typedef_payload; } mixin Proxy!Typedef_payload; } /** Get the underlying type which a $(D Typedef) wraps. If $(D T) is not a $(D Typedef) it will alias itself to $(D T). */ template TypedefType(T) { static if (is(T : Typedef!Arg, Arg)) alias TypedefType = Arg; else alias TypedefType = T; } /// unittest { import std.typecons: Typedef, TypedefType; import std.conv: to; alias MyInt = Typedef!int; static assert(is(TypedefType!MyInt == int)); /// Instantiating with a non-Typedef will return that type static assert(is(TypedefType!int == int)); string num = "5"; // extract the needed type MyInt myInt = MyInt( num.to!(TypedefType!MyInt) ); assert(myInt == 5); // cast to the underlying type to get the value that's being wrapped int x = cast(TypedefType!MyInt)myInt; alias MyIntInit = Typedef!(int, 42); static assert(is(TypedefType!MyIntInit == int)); static assert(MyIntInit() == 42); } unittest { Typedef!int x = 10; static assert(!__traits(compiles, { int y = x; })); static assert(!__traits(compiles, { long z = x; })); Typedef!int y = 10; assert(x == y); static assert(Typedef!int.init == int.init); Typedef!(float, 1.0) z; // specifies the init assert(z == 1.0); static assert(typeof(z).init == 1.0); alias Dollar = Typedef!(int, 0, "dollar"); alias Yen = Typedef!(int, 0, "yen"); static assert(!is(Dollar == Yen)); Typedef!(int[3]) sa; static assert(sa.length == 3); static assert(typeof(sa).length == 3); Typedef!(int[3]) dollar1; assert(dollar1[0..$] is dollar1[0..3]); Typedef!(int[]) dollar2; dollar2.length = 3; assert(dollar2[0..$] is dollar2[0..3]); static struct Dollar1 { static struct DollarToken {} enum opDollar = DollarToken.init; auto opSlice(size_t, DollarToken) { return 1; } auto opSlice(size_t, size_t) { return 2; } } Typedef!Dollar1 drange1; assert(drange1[0..$] == 1); assert(drange1[0..1] == 2); static struct Dollar2 { size_t opDollar(size_t pos)() { return pos == 0 ? 1 : 100; } size_t opIndex(size_t i, size_t j) { return i + j; } } Typedef!Dollar2 drange2; assert(drange2[$, $] == 101); static struct Dollar3 { size_t opDollar() { return 123; } size_t opIndex(size_t i) { return i; } } Typedef!Dollar3 drange3; assert(drange3[$] == 123); } unittest { // bug8655 import std.typecons; import std.bitmanip; static import core.stdc.config; alias c_ulong = Typedef!(core.stdc.config.c_ulong); static struct Foo { mixin(bitfields!( c_ulong, "NameOffset", 31, c_ulong, "NameIsString", 1 )); } } unittest // Issue 12596 { import std.typecons; alias TD = Typedef!int; TD x = TD(1); TD y = TD(x); assert(x == y); } unittest // about toHash { import std.typecons; { alias TD = Typedef!int; int[TD] td; td[TD(1)] = 1; assert(td[TD(1)] == 1); } { alias TD = Typedef!(int[]); int[TD] td; td[TD([1,2,3,4])] = 2; assert(td[TD([1,2,3,4])] == 2); } { alias TD = Typedef!(int[][]); int[TD] td; td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] = 3; assert(td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] == 3); } { struct MyStruct{ int x; } alias TD = Typedef!MyStruct; int[TD] td; td[TD(MyStruct(10))] = 4; assert(TD(MyStruct(20)) !in td); assert(td[TD(MyStruct(10))] == 4); } { static struct MyStruct2 { int x; size_t toHash() const nothrow @safe { return x; } bool opEquals(ref const MyStruct2 r) const { return r.x == x; } } alias TD = Typedef!MyStruct2; int[TD] td; td[TD(MyStruct2(50))] = 5; assert(td[TD(MyStruct2(50))] == 5); } { class MyClass{} alias TD = Typedef!MyClass; int[TD] td; auto c = new MyClass; td[TD(c)] = 6; assert(TD(new MyClass) !in td); assert(td[TD(c)] == 6); } } unittest { alias String = Typedef!(char[]); alias CString = Typedef!(const(char)[]); CString cs = "fubar"; String s = cast(String)cs; assert(cs == s); char[] s2 = cast(char[])cs; const(char)[] cs2 = cast(const(char)[])s; assert(s2 == cs2); } /** Allocates a $(D class) object right inside the current scope, therefore avoiding the overhead of $(D new). This facility is unsafe; it is the responsibility of the user to not escape a reference to the object outside the scope. Note: it's illegal to move a class reference even if you are sure there are no pointers to it. As such, it is illegal to move a scoped object. */ template scoped(T) if (is(T == class)) { // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for // small objects). We will just use the maximum of filed alignments. alias alignment = classInstanceAlignment!T; alias aligned = _alignUp!alignment; static struct Scoped { // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory. private void[aligned(__traits(classInstanceSize, T) + size_t.sizeof) + alignment] Scoped_store = void; @property inout(T) Scoped_payload() inout { void* alignedStore = cast(void*) aligned(cast(size_t) Scoped_store.ptr); // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly. immutable size_t d = alignedStore - Scoped_store.ptr; size_t* currD = cast(size_t*) &Scoped_store[$ - size_t.sizeof]; if(d != *currD) { import core.stdc.string; memmove(alignedStore, Scoped_store.ptr + *currD, __traits(classInstanceSize, T)); *currD = d; } return cast(inout(T)) alignedStore; } alias Scoped_payload this; @disable this(); @disable this(this); ~this() { // `destroy` will also write .init but we have no functions in druntime // for deterministic finalization and memory releasing for now. .destroy(Scoped_payload); } } /// Returns the scoped object @system auto scoped(Args...)(auto ref Args args) { import std.conv : emplace; Scoped result = void; void* alignedStore = cast(void*) aligned(cast(size_t) result.Scoped_store.ptr); immutable size_t d = alignedStore - result.Scoped_store.ptr; *cast(size_t*) &result.Scoped_store[$ - size_t.sizeof] = d; emplace!(Unqual!T)(result.Scoped_store[d .. $ - size_t.sizeof], args); return result; } } /// unittest { class A { int x; this() {x = 0;} this(int i){x = i;} } // Standard usage auto a1 = scoped!A(); auto a2 = scoped!A(1); a1.x = 42; assert(a1.x == 42); assert(a2.x == 1); // Restrictions static assert(!is(typeof({ auto e1 = a1; // illegal, scoped objects can't be copied assert([a2][0].x == 42); // ditto alias ScopedObject = typeof(a1); auto e2 = ScopedObject(); //Illegal, must be built via scoped!A auto e3 = ScopedObject(1); //Illegal, must be built via scoped!A }))); // Use as member variable struct B { typeof(scoped!A()) a; // note the trailing parentheses } // Use with alias alias makeScopedA = scoped!A; auto a6 = makeScopedA(); auto a7 = makeScopedA(); } private size_t _alignUp(size_t alignment)(size_t n) if(alignment > 0 && !((alignment - 1) & alignment)) { enum badEnd = alignment - 1; // 0b11, 0b111, ... return (n + badEnd) & ~badEnd; } unittest // Issue 6580 testcase { enum alignment = (void*).alignof; static class C0 { } static class C1 { byte b; } static class C2 { byte[2] b; } static class C3 { byte[3] b; } static class C7 { byte[7] b; } static assert(scoped!C0().sizeof % alignment == 0); static assert(scoped!C1().sizeof % alignment == 0); static assert(scoped!C2().sizeof % alignment == 0); static assert(scoped!C3().sizeof % alignment == 0); static assert(scoped!C7().sizeof % alignment == 0); enum longAlignment = long.alignof; static class C1long { long long_; byte byte_ = 4; this() { } this(long _long, ref int i) { long_ = _long; ++i; } } static class C2long { byte[2] byte_ = [5, 6]; long long_ = 7; } static assert(scoped!C1long().sizeof % longAlignment == 0); static assert(scoped!C2long().sizeof % longAlignment == 0); void alignmentTest() { int var = 5; auto c1long = scoped!C1long(3, var); assert(var == 6); auto c2long = scoped!C2long(); assert(cast(size_t)&c1long.long_ % longAlignment == 0); assert(cast(size_t)&c2long.long_ % longAlignment == 0); assert(c1long.long_ == 3 && c1long.byte_ == 4); assert(c2long.byte_ == [5, 6] && c2long.long_ == 7); } alignmentTest(); version(DigitalMars) { void test(size_t size) { import core.stdc.stdlib; alloca(size); alignmentTest(); } foreach(i; 0 .. 10) test(i); } else { void test(size_t size)() { byte[size] arr; alignmentTest(); } foreach(i; AliasSeq!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) test!i(); } } unittest // Original Issue 6580 testcase { class C { int i; byte b; } auto sa = [scoped!C(), scoped!C()]; assert(cast(size_t)&sa[0].i % int.alignof == 0); assert(cast(size_t)&sa[1].i % int.alignof == 0); // fails } unittest { class A { int x = 1; } auto a1 = scoped!A(); assert(a1.x == 1); auto a2 = scoped!A(); a1.x = 42; a2.x = 53; assert(a1.x == 42); } unittest { class A { int x = 1; this() { x = 2; } } auto a1 = scoped!A(); assert(a1.x == 2); auto a2 = scoped!A(); a1.x = 42; a2.x = 53; assert(a1.x == 42); } unittest { class A { int x = 1; this(int y) { x = y; } ~this() {} } auto a1 = scoped!A(5); assert(a1.x == 5); auto a2 = scoped!A(42); a1.x = 42; a2.x = 53; assert(a1.x == 42); } unittest { class A { static bool dead; ~this() { dead = true; } } class B : A { static bool dead; ~this() { dead = true; } } { auto b = scoped!B(); } assert(B.dead, "asdasd"); assert(A.dead, "asdasd"); } unittest // Issue 8039 testcase { static int dels; static struct S { ~this(){ ++dels; } } static class A { S s; } dels = 0; { scoped!A(); } assert(dels == 1); static class B { S[2] s; } dels = 0; { scoped!B(); } assert(dels == 2); static struct S2 { S[3] s; } static class C { S2[2] s; } dels = 0; { scoped!C(); } assert(dels == 6); static class D: A { S2[2] s; } dels = 0; { scoped!D(); } assert(dels == 1+6); } unittest { // bug4500 class A { this() { a = this; } this(int i) { a = this; } A a; bool check() { return this is a; } } auto a1 = scoped!A(); assert(a1.check()); auto a2 = scoped!A(1); assert(a2.check()); a1.a = a1; assert(a1.check()); } unittest { static class A { static int sdtor; this() { ++sdtor; assert(sdtor == 1); } ~this() { assert(sdtor == 1); --sdtor; } } interface Bob {} static class ABob : A, Bob { this() { ++sdtor; assert(sdtor == 2); } ~this() { assert(sdtor == 2); --sdtor; } } A.sdtor = 0; scope(exit) assert(A.sdtor == 0); auto abob = scoped!ABob(); } unittest { static class A { this(int) {} } static assert(!__traits(compiles, scoped!A())); } unittest { static class A { @property inout(int) foo() inout { return 1; } } auto a1 = scoped!A(); assert(a1.foo == 1); static assert(is(typeof(a1.foo) == int)); auto a2 = scoped!(const(A))(); assert(a2.foo == 1); static assert(is(typeof(a2.foo) == const(int))); auto a3 = scoped!(immutable(A))(); assert(a3.foo == 1); static assert(is(typeof(a3.foo) == immutable(int))); const c1 = scoped!A(); assert(c1.foo == 1); static assert(is(typeof(c1.foo) == const(int))); const c2 = scoped!(const(A))(); assert(c2.foo == 1); static assert(is(typeof(c2.foo) == const(int))); const c3 = scoped!(immutable(A))(); assert(c3.foo == 1); static assert(is(typeof(c3.foo) == immutable(int))); } unittest { class C { this(ref int val) { assert(val == 3); ++val; } } int val = 3; auto s = scoped!C(val); assert(val == 4); } unittest { class C { this(){} this(int){} this(int, int){} } alias makeScopedC = scoped!C; auto a = makeScopedC(); auto b = makeScopedC(1); auto c = makeScopedC(1, 1); static assert(is(typeof(a) == typeof(b))); static assert(is(typeof(b) == typeof(c))); } /** Defines a simple, self-documenting yes/no flag. This makes it easy for APIs to define functions accepting flags without resorting to $(D bool), which is opaque in calls, and without needing to define an enumerated type separately. Using $(D Flag!"Name") instead of $(D bool) makes the flag's meaning visible in calls. Each yes/no flag has its own type, which makes confusions and mix-ups impossible. Example: Code calling $(D getLine) (usually far away from its definition) can't be understood without looking at the documentation, even by users familiar with the API: ---- string getLine(bool keepTerminator) { ... if (keepTerminator) ... ... } ... auto line = getLine(false); ---- Assuming the reverse meaning (i.e. "ignoreTerminator") and inserting the wrong code compiles and runs with erroneous results. After replacing the boolean parameter with an instantiation of $(D Flag), code calling $(D getLine) can be easily read and understood even by people not fluent with the API: ---- string getLine(Flag!"keepTerminator" keepTerminator) { ... if (keepTerminator) ... ... } ... auto line = getLine(Yes.keepTerminator); ---- The structs $(D Yes) and $(D No) are provided as shorthand for $(D Flag!"Name".yes) and $(D Flag!"Name".no) and are preferred for brevity and readability. These convenience structs mean it is usually unnecessary and counterproductive to create an alias of a $(D Flag) as a way of avoiding typing out the full type while specifying the affirmative or negative options. Passing categorical data by means of unstructured $(D bool) parameters is classified under "simple-data coupling" by Steve McConnell in the $(LUCKY Code Complete) book, along with three other kinds of coupling. The author argues citing several studies that coupling has a negative effect on code quality. $(D Flag) offers a simple structuring method for passing yes/no flags to APIs. */ template Flag(string name) { /// enum Flag : bool { /** When creating a value of type $(D Flag!"Name"), use $(D Flag!"Name".no) for the negative option. When using a value of type $(D Flag!"Name"), compare it against $(D Flag!"Name".no) or just $(D false) or $(D 0). */ no = false, /** When creating a value of type $(D Flag!"Name"), use $(D Flag!"Name".yes) for the affirmative option. When using a value of type $(D Flag!"Name"), compare it against $(D Flag!"Name".yes). */ yes = true } } /** Convenience names that allow using e.g. $(D Yes.encryption) instead of $(D Flag!"encryption".yes) and $(D No.encryption) instead of $(D Flag!"encryption".no). */ struct Yes { template opDispatch(string name) { enum opDispatch = Flag!name.yes; } } //template yes(string name) { enum Flag!name yes = Flag!name.yes; } /// Ditto struct No { template opDispatch(string name) { enum opDispatch = Flag!name.no; } } /// unittest { Flag!"abc" flag1; assert(flag1 == Flag!"abc".no); assert(flag1 == No.abc); assert(!flag1); if (flag1) assert(false); flag1 = Yes.abc; assert(flag1); if (!flag1) assert(false); if (flag1) {} else assert(false); assert(flag1 == Yes.abc); } /** Detect whether an enum is of integral type and has only "flag" values (i.e. values with a bit count of exactly 1). Additionally, a zero value is allowed for compatibility with enums including a "None" value. */ template isBitFlagEnum(E) { static if (is(E Base == enum) && isIntegral!Base) { enum isBitFlagEnum = (E.min >= 0) && { foreach (immutable flag; EnumMembers!E) { Base value = flag; value &= value - 1; if (value != 0) return false; } return true; }(); } else { enum isBitFlagEnum = false; } } /// @safe pure nothrow unittest { enum A { None, A = 1<<0, B = 1<<1, C = 1<<2, D = 1<<3, } static assert(isBitFlagEnum!A); enum B { A, B, C, D // D == 3 } static assert(!isBitFlagEnum!B); enum C: double { A = 1<<0, B = 1<<1 } static assert(!isBitFlagEnum!C); } /** A typesafe structure for storing combinations of enum values. This template defines a simple struct to represent bitwise OR combinations of enum values. It can be used if all the enum values are integral constants with a bit count of at most 1, or if the $(D unsafe) parameter is explicitly set to Yes. This is much safer than using the enum itself to store the OR combination, which can produce surprising effects like this: ---- enum E { A = 1<<0, B = 1<<1 } E e = E.A | E.B; // will throw SwitchError final switch(e) { case E.A: return; case E.B: return; } ---- */ struct BitFlags(E, Flag!"unsafe" unsafe = No.unsafe) if (unsafe || isBitFlagEnum!(E)) { @safe @nogc pure nothrow: private: enum isBaseEnumType(T) = is(E == T); alias Base = OriginalType!E; Base mValue; static struct Negation { @safe @nogc pure nothrow: private: Base mValue; // Prevent non-copy construction outside the module. @disable this(); this(Base value) { mValue = value; } } public: this(E flag) { this = flag; } this(T...)(T flags) if (allSatisfy!(isBaseEnumType, T)) { this = flags; } bool opCast(B: bool)() const { return mValue != 0; } Base opCast(B)() const if (isImplicitlyConvertible!(Base, B)) { return mValue; } Negation opUnary(string op)() const if (op == "~") { return Negation(~mValue); } auto ref opAssign(T...)(T flags) if (allSatisfy!(isBaseEnumType, T)) { mValue = 0; foreach (E flag; flags) { mValue |= flag; } return this; } auto ref opAssign(E flag) { mValue = flag; return this; } auto ref opOpAssign(string op: "|")(BitFlags flags) { mValue |= flags.mValue; return this; } auto ref opOpAssign(string op: "&")(BitFlags flags) { mValue &= flags.mValue; return this; } auto ref opOpAssign(string op: "|")(E flag) { mValue |= flag; return this; } auto ref opOpAssign(string op: "&")(E flag) { mValue &= flag; return this; } auto ref opOpAssign(string op: "&")(Negation negatedFlags) { mValue &= negatedFlags.mValue; return this; } auto opBinary(string op)(BitFlags flags) const if (op == "|" || op == "&") { BitFlags result = this; result.opOpAssign!op(flags); return result; } auto opBinary(string op)(E flag) const if (op == "|" || op == "&") { BitFlags result = this; result.opOpAssign!op(flag); return result; } auto opBinary(string op: "&")(Negation negatedFlags) const { BitFlags result = this; result.opOpAssign!op(negatedFlags); return result; } auto opBinaryRight(string op)(E flag) const if (op == "|" || op == "&") { return opBinary!op(flag); } } /// BitFlags can be manipulated with the usual operators @safe @nogc pure nothrow unittest { // You can use such an enum with BitFlags straight away enum Enum { None, A = 1<<0, B = 1<<1, C = 1<<2 } BitFlags!Enum flags1; assert(!(flags1 & (Enum.A | Enum.B | Enum.C))); // You need to specify the $(D unsafe) parameter for enum with custom values enum UnsafeEnum { A, B, C, D = B|C } static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags2; })); BitFlags!(UnsafeEnum, Yes.unsafe) flags3; immutable BitFlags!Enum flags_empty; // A default constructed BitFlags has no value set assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C)); // Value can be set with the | operator immutable BitFlags!Enum flags_A = flags_empty | Enum.A; // And tested with the & operator assert(flags_A & Enum.A); // Which commutes assert(Enum.A & flags_A); // BitFlags can be variadically initialized immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B); assert((flags_AB & Enum.A) && (flags_AB & Enum.B) && !(flags_AB & Enum.C)); // Use the ~ operator for subtracting flags immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A); assert(!(flags_B & Enum.A) && (flags_B & Enum.B) && !(flags_B & Enum.C)); // You can use the EnumMembers template to set all flags immutable BitFlags!Enum flags_all = EnumMembers!Enum; // use & between BitFlags for intersection immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C); assert (flags_B == (flags_BC & flags_AB)); // All the binary operators work in their assignment version BitFlags!Enum temp = flags_empty; temp |= flags_AB; assert(temp == (flags_empty | flags_AB)); temp = flags_empty; temp |= Enum.B; assert(temp == (flags_empty | Enum.B)); temp = flags_empty; temp &= flags_AB; assert(temp == (flags_empty & flags_AB)); temp = flags_empty; temp &= Enum.A; assert(temp == (flags_empty & Enum.A)); // BitFlags with no value set evaluate to false assert(!flags_empty); // BitFlags with at least one value set evaluate to true assert(flags_A); // This can be useful to check intersection between BitFlags assert(flags_A & flags_AB); assert(flags_AB & Enum.A); // Finally, you can of course get you raw value out of flags auto value = cast(int)flags_A; assert(value == Enum.A); } // ReplaceType /** Replaces all occurrences of `From` into `To`, in one or more types `T`. For example, $(D ReplaceType!(int, uint, Tuple!(int, float)[string])) yields $(D Tuple!(uint, float)[string]). The types in which replacement is performed may be arbitrarily complex, including qualifiers, built-in type constructors (pointers, arrays, associative arrays, functions, and delegates), and template instantiations; replacement proceeds transitively through the type definition. However, member types in `struct`s or `class`es are not replaced because there are no ways to express the types resulting after replacement. This is an advanced type manipulation necessary e.g. for replacing the placeholder type `This` in $(XREF variant, Algebraic). Returns: `ReplaceType` aliases itself to the type(s) that result after replacement. */ template ReplaceType(From, To, T...) { static if (T.length == 1) { static if (is(T[0] == From)) alias ReplaceType = To; else static if (is(T[0] == const(U), U)) alias ReplaceType = const(ReplaceType!(From, To, U)); else static if (is(T[0] == immutable(U), U)) alias ReplaceType = immutable(ReplaceType!(From, To, U)); else static if (is(T[0] == shared(U), U)) alias ReplaceType = shared(ReplaceType!(From, To, U)); else static if (is(T[0] == U*, U)) { static if (is(U == function)) alias ReplaceType = replaceTypeInFunctionType!(From, To, T[0]); else alias ReplaceType = ReplaceType!(From, To, U)*; } else static if (is(T[0] == delegate)) { alias ReplaceType = replaceTypeInFunctionType!(From, To, T[0]); } else static if (is(T[0] == function)) { static assert(0, "Function types not supported," " use a function pointer type instead of "~T[0].stringof); } else static if (is(T[0] : U!V, alias U, V...)) { template replaceTemplateArgs(T...) { static if (is(typeof(T[0]))) // template argument is value or symbol enum replaceTemplateArgs = T[0]; else alias replaceTemplateArgs = ReplaceType!(From, To, T[0]); } alias ReplaceType = U!(staticMap!(replaceTemplateArgs, V)); } else static if (is(T[0] == struct)) // don't match with alias this struct below (Issue 15168) alias ReplaceType = T[0]; else static if (is(T[0] == U[], U)) alias ReplaceType = ReplaceType!(From, To, U)[]; else static if (is(T[0] == U[n], U, size_t n)) alias ReplaceType = ReplaceType!(From, To, U)[n]; else static if (is(T[0] == U[V], U, V)) alias ReplaceType = ReplaceType!(From, To, U)[ReplaceType!(From, To, V)]; else alias ReplaceType = T[0]; } else static if (T.length > 1) { alias ReplaceType = AliasSeq!(ReplaceType!(From, To, T[0]), ReplaceType!(From, To, T[1 .. $])); } else { alias ReplaceType = AliasSeq!(); } } /// unittest { static assert( is(ReplaceType!(int, string, int[]) == string[]) && is(ReplaceType!(int, string, int[int]) == string[string]) && is(ReplaceType!(int, string, const(int)[]) == const(string)[]) && is(ReplaceType!(int, string, Tuple!(int[], float)) == Tuple!(string[], float)) ); } private template replaceTypeInFunctionType(From, To, fun) { alias RX = ReplaceType!(From, To, ReturnType!fun); alias PX = AliasSeq!(ReplaceType!(From, To, Parameters!fun)); // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return // tuple if Parameters!fun.length == 1 string gen() { enum linkage = functionLinkage!fun; alias attributes = functionAttributes!fun; enum variadicStyle = variadicFunctionStyle!fun; alias storageClasses = ParameterStorageClassTuple!fun; string result; result ~= "extern(" ~ linkage ~ ") "; static if (attributes & FunctionAttribute.ref_) { result ~= "ref "; } result ~= "RX"; static if (is(fun == delegate)) result ~= " delegate"; else result ~= " function"; result ~= "("; foreach (i, _; PX) { if (i) result ~= ", "; if (storageClasses[i] & ParameterStorageClass.scope_) result ~= "scope "; if (storageClasses[i] & ParameterStorageClass.out_) result ~= "out "; if (storageClasses[i] & ParameterStorageClass.ref_) result ~= "ref "; if (storageClasses[i] & ParameterStorageClass.lazy_) result ~= "lazy "; if (storageClasses[i] & ParameterStorageClass.return_) result ~= "return "; result ~= "PX[" ~ i.stringof ~ "]"; } static if (variadicStyle == Variadic.typesafe) result ~= " ..."; else static if (variadicStyle != Variadic.no) result ~= ", ..."; result ~= ")"; static if (attributes & FunctionAttribute.pure_) result ~= " pure"; static if (attributes & FunctionAttribute.nothrow_) result ~= " nothrow"; static if (attributes & FunctionAttribute.property) result ~= " @property"; static if (attributes & FunctionAttribute.trusted) result ~= " @trusted"; static if (attributes & FunctionAttribute.safe) result ~= " @safe"; static if (attributes & FunctionAttribute.nogc) result ~= " @nogc"; static if (attributes & FunctionAttribute.system) result ~= " @system"; static if (attributes & FunctionAttribute.const_) result ~= " @const"; static if (attributes & FunctionAttribute.immutable_) result ~= " immutable"; static if (attributes & FunctionAttribute.inout_) result ~= " inout"; static if (attributes & FunctionAttribute.shared_) result ~= " shared"; static if (attributes & FunctionAttribute.return_) result ~= " return"; return result; } //pragma(msg, "gen ==> ", gen()); mixin("alias replaceTypeInFunctionType = " ~ gen() ~ ";"); } unittest { template Test(Ts...) { static if (Ts.length) { //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", " // ~Ts[1].stringof~", "~Ts[2].stringof~")"); static assert(is(ReplaceType!(Ts[0], Ts[1], Ts[2]) == Ts[3]), "ReplaceType!("~Ts[0].stringof~", "~Ts[1].stringof~", " ~Ts[2].stringof~") == " ~ReplaceType!(Ts[0], Ts[1], Ts[2]).stringof); alias Test = Test!(Ts[4 .. $]); } else alias Test = void; } //import core.stdc.stdio; alias RefFun1 = ref int function(float, long); alias RefFun2 = ref float function(float, long); extern(C) int printf(const char*, ...) nothrow @nogc @system; extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system; int func(float); int x; struct S1 { void foo() { x = 1; } } struct S2 { void bar() { x = 2; } } alias Pass = Test!( int, float, typeof(&func), float delegate(float), int, float, typeof(&printf), typeof(&floatPrintf), int, float, int function(out long, ...), float function(out long, ...), int, float, int function(ref float, long), float function(ref float, long), int, float, int function(ref int, long), float function(ref float, long), int, float, int function(out int, long), float function(out float, long), int, float, int function(lazy int, long), float function(lazy float, long), int, float, int function(out long, ref const int), float function(out long, ref const float), int, int, int, int, int, float, int, float, int, float, const int, const float, int, float, immutable int, immutable float, int, float, shared int, shared float, int, float, int*, float*, int, float, const(int)*, const(float)*, int, float, const(int*), const(float*), const(int)*, float, const(int*), const(float), int*, float, const(int)*, const(int)*, int, float, int[], float[], int, float, int[42], float[42], int, float, const(int)[42], const(float)[42], int, float, const(int[42]), const(float[42]), int, float, int[int], float[float], int, float, int[double], float[double], int, float, double[int], double[float], int, float, int function(float, long), float function(float, long), int, float, int function(float), float function(float), int, float, int function(float, int), float function(float, float), int, float, int delegate(float, long), float delegate(float, long), int, float, int delegate(float), float delegate(float), int, float, int delegate(float, int), float delegate(float, float), int, float, Unique!int, Unique!float, int, float, Tuple!(float, int), Tuple!(float, float), int, float, RefFun1, RefFun2, S1, S2, S1[1][][S1]* function(), S2[1][][S2]* function(), int, string, int[3] function( int[] arr, int[2] ...) pure @trusted, string[3] function(string[] arr, string[2] ...) pure @trusted, ); // Bugzilla 15168 static struct T1 { string s; alias s this; } static struct T2 { char[10] s; alias s this; } static struct T3 { string[string] s; alias s this; } alias Pass2 = Test!( ubyte, ubyte, T1, T1, ubyte, ubyte, T2, T2, ubyte, ubyte, T3, T3, ); } ldc-1.1.0-beta3-src/runtime/phobos/std/uni.d0000664000175000017500000106206412776215007016657 0ustar kaikai// Written in the D programming language. /++ $(P The $(D std.uni) module provides an implementation of fundamental Unicode algorithms and data structures. This doesn't include UTF encoding and decoding primitives, see $(XREF _utf, decode) and $(XREF _utf, encode) in std.utf for this functionality. ) $(P All primitives listed operate on Unicode characters and sets of characters. For functions which operate on ASCII characters and ignore Unicode $(CHARACTERS), see $(LINK2 std_ascii.html, std.ascii). For definitions of Unicode $(CHARACTER), $(CODEPOINT) and other terms used throughout this module see the $(S_LINK Terminology, terminology) section below. ) $(P The focus of this module is the core needs of developing Unicode-aware applications. To that effect it provides the following optimized primitives: ) $(UL $(LI Character classification by category and common properties: $(LREF isAlpha), $(LREF isWhite) and others. ) $(LI Case-insensitive string comparison ($(LREF sicmp), $(LREF icmp)). ) $(LI Converting text to any of the four normalization forms via $(LREF normalize). ) $(LI Decoding ($(LREF decodeGrapheme)) and iteration ($(LREF byGrapheme), $(LREF graphemeStride)) by user-perceived characters, that is by $(LREF Grapheme) clusters. ) $(LI Decomposing and composing of individual character(s) according to canonical or compatibility rules, see $(LREF compose) and $(LREF decompose), including the specific version for Hangul syllables $(LREF composeJamo) and $(LREF decomposeHangul). ) ) $(P It's recognized that an application may need further enhancements and extensions, such as less commonly known algorithms, or tailoring existing ones for region specific needs. To help users with building any extra functionality beyond the core primitives, the module provides: ) $(UL $(LI $(LREF CodepointSet), a type for easy manipulation of sets of characters. Besides the typical set algebra it provides an unusual feature: a D source code generator for detection of $(CODEPOINTS) in this set. This is a boon for meta-programming parser frameworks, and is used internally to power classification in small sets like $(LREF isWhite). ) $(LI A way to construct optimal packed multi-stage tables also known as a special case of $(LUCKY Trie). The functions $(LREF codepointTrie), $(LREF codepointSetTrie) construct custom tries that map dchar to value. The end result is a fast and predictable $(BIGOH 1) lookup that powers functions like $(LREF isAlpha) and $(LREF combiningClass), but for user-defined data sets. ) $(LI A useful technique for Unicode-aware parsers that perform character classification of encoded $(CODEPOINTS) is to avoid unnecassary decoding at all costs. $(LREF utfMatcher) provides an improvement over the usual workflow of decode-classify-process, combining the decoding and classification steps. By extracting necessary bits directly from encoded $(S_LINK Code unit, code units) matchers achieve significant performance improvements. See $(LREF MatcherConcept) for the common interface of UTF matchers. ) $(LI Generally useful building blocks for customized normalization: $(LREF combiningClass) for querying combining class and $(LREF allowedIn) for testing the Quick_Check property of a given normalization form. ) $(LI Access to a large selection of commonly used sets of $(CODEPOINTS). $(S_LINK Unicode properties, Supported sets) include Script, Block and General Category. The exact contents of a set can be observed in the CLDR utility, on the $(WEB www.unicode.org/cldr/utility/properties.jsp, property index) page of the Unicode website. See $(LREF unicode) for easy and (optionally) compile-time checked set queries. ) ) $(SECTION Synopsis) --- import std.uni; void main() { // initialize code point sets using script/block or property name // now 'set' contains code points from both scripts. auto set = unicode("Cyrillic") | unicode("Armenian"); // same thing but simpler and checked at compile-time auto ascii = unicode.ASCII; auto currency = unicode.Currency_Symbol; // easy set ops auto a = set & ascii; assert(a.empty); // as it has no intersection with ascii a = set | ascii; auto b = currency - a; // subtract all ASCII, Cyrillic and Armenian // some properties of code point sets assert(b.length > 45); // 46 items in Unicode 6.1, even more in 6.2 // testing presence of a code point in a set // is just fine, it is O(logN) assert(!b['$']); assert(!b['\u058F']); // Armenian dram sign assert(b['¥']); // building fast lookup tables, these guarantee O(1) complexity // 1-level Trie lookup table essentially a huge bit-set ~262Kb auto oneTrie = toTrie!1(b); // 2-level far more compact but typically slightly slower auto twoTrie = toTrie!2(b); // 3-level even smaller, and a bit slower yet auto threeTrie = toTrie!3(b); assert(oneTrie['£']); assert(twoTrie['£']); assert(threeTrie['£']); // build the trie with the most sensible trie level // and bind it as a functor auto cyrillicOrArmenian = toDelegate(set); auto balance = find!(cyrillicOrArmenian)("Hello ընկեր!"); assert(balance == "ընկեր!"); // compatible with bool delegate(dchar) bool delegate(dchar) bindIt = cyrillicOrArmenian; // Normalization string s = "Plain ascii (and not only), is always normalized!"; assert(s is normalize(s));// is the same string string nonS = "A\u0308ffin"; // A ligature auto nS = normalize(nonS); // to NFC, the W3C endorsed standard assert(nS == "Äffin"); assert(nS != nonS); string composed = "Äffin"; assert(normalize!NFD(composed) == "A\u0308ffin"); // to NFKD, compatibility decomposition useful for fuzzy matching/searching assert(normalize!NFKD("2¹⁰") == "210"); } --- $(SECTION Terminology) $(P The following is a list of important Unicode notions and definitions. Any conventions used specifically in this module alone are marked as such. The descriptions are based on the formal definition as found in $(WEB www.unicode.org/versions/Unicode6.2.0/ch03.pdf, chapter three of The Unicode Standard Core Specification.) ) $(P $(DEF Abstract character) A unit of information used for the organization, control, or representation of textual data. Note that: $(UL $(LI When representing data, the nature of that data is generally symbolic as opposed to some other kind of data (for example, visual).) $(LI An abstract character has no concrete form and should not be confused with a $(S_LINK Glyph, glyph).) $(LI An abstract character does not necessarily correspond to what a user thinks of as a “character” and should not be confused with a $(LREF Grapheme).) $(LI The abstract characters encoded (see Encoded character) are known as Unicode abstract characters.) $(LI Abstract characters not directly encoded by the Unicode Standard can often be represented by the use of combining character sequences.) ) ) $(P $(DEF Canonical decomposition) The decomposition of a character or character sequence that results from recursively applying the canonical mappings found in the Unicode Character Database and these described in Conjoining Jamo Behavior (section 12 of $(WEB www.unicode.org/uni2book/ch03.pdf, Unicode Conformance)). ) $(P $(DEF Canonical composition) The precise definition of the Canonical composition is the algorithm as specified in $(WEB www.unicode.org/uni2book/ch03.pdf, Unicode Conformance) section 11. Informally it's the process that does the reverse of the canonical decomposition with the addition of certain rules that e.g. prevent legacy characters from appearing in the composed result. ) $(P $(DEF Canonical equivalent) Two character sequences are said to be canonical equivalents if their full canonical decompositions are identical. ) $(P $(DEF Character) Typically differs by context. For the purpose of this documentation the term $(I character) implies $(I encoded character), that is, a code point having an assigned abstract character (a symbolic meaning). ) $(P $(DEF Code point) Any value in the Unicode codespace; that is, the range of integers from 0 to 10FFFF (hex). Not all code points are assigned to encoded characters. ) $(P $(DEF Code unit) The minimal bit combination that can represent a unit of encoded text for processing or interchange. Depending on the encoding this could be: 8-bit code units in the UTF-8 ($(D char)), 16-bit code units in the UTF-16 ($(D wchar)), and 32-bit code units in the UTF-32 ($(D dchar)). $(I Note that in UTF-32, a code unit is a code point and is represented by the D $(D dchar) type.) ) $(P $(DEF Combining character) A character with the General Category of Combining Mark(M). $(UL $(LI All characters with non-zero canonical combining class are combining characters, but the reverse is not the case: there are combining characters with a zero combining class. ) $(LI These characters are not normally used in isolation unless they are being described. They include such characters as accents, diacritics, Hebrew points, Arabic vowel signs, and Indic matras. ) ) ) $(P $(DEF Combining class) A numerical value used by the Unicode Canonical Ordering Algorithm to determine which sequences of combining marks are to be considered canonically equivalent and which are not. ) $(P $(DEF Compatibility decomposition) The decomposition of a character or character sequence that results from recursively applying both the compatibility mappings and the canonical mappings found in the Unicode Character Database, and those described in Conjoining Jamo Behavior no characters can be further decomposed. ) $(P $(DEF Compatibility equivalent) Two character sequences are said to be compatibility equivalents if their full compatibility decompositions are identical. ) $(P $(DEF Encoded character) An association (or mapping) between an abstract character and a code point. ) $(P $(DEF Glyph) The actual, concrete image of a glyph representation having been rasterized or otherwise imaged onto some display surface. ) $(P $(DEF Grapheme base) A character with the property Grapheme_Base, or any standard Korean syllable block. ) $(P $(DEF Grapheme cluster) Defined as the text between grapheme boundaries as specified by Unicode Standard Annex #29, $(WEB www.unicode.org/reports/tr29/, Unicode text segmentation). Important general properties of a grapheme: $(UL $(LI The grapheme cluster represents a horizontally segmentable unit of text, consisting of some grapheme base (which may consist of a Korean syllable) together with any number of nonspacing marks applied to it. ) $(LI A grapheme cluster typically starts with a grapheme base and then extends across any subsequent sequence of nonspacing marks. A grapheme cluster is most directly relevant to text rendering and processes such as cursor placement and text selection in editing, but may also be relevant to comparison and searching. ) $(LI For many processes, a grapheme cluster behaves as if it was a single character with the same properties as its grapheme base. Effectively, nonspacing marks apply $(I graphically) to the base, but do not change its properties. ) ) $(P This module defines a number of primitives that work with graphemes: $(LREF Grapheme), $(LREF decodeGrapheme) and $(LREF graphemeStride). All of them are using $(I extended grapheme) boundaries as defined in the aforementioned standard annex. ) ) $(P $(DEF Nonspacing mark) A combining character with the General Category of Nonspacing Mark (Mn) or Enclosing Mark (Me). ) $(P $(DEF Spacing mark) A combining character that is not a nonspacing mark.) $(SECTION Normalization) $(P The concepts of $(S_LINK Canonical equivalent, canonical equivalent) or $(S_LINK Compatibility equivalent, compatibility equivalent) characters in the Unicode Standard make it necessary to have a full, formal definition of equivalence for Unicode strings. String equivalence is determined by a process called normalization, whereby strings are converted into forms which are compared directly for identity. This is the primary goal of the normalization process, see the function $(LREF normalize) to convert into any of the four defined forms. ) $(P A very important attribute of the Unicode Normalization Forms is that they must remain stable between versions of the Unicode Standard. A Unicode string normalized to a particular Unicode Normalization Form in one version of the standard is guaranteed to remain in that Normalization Form for implementations of future versions of the standard. ) $(P The Unicode Standard specifies four normalization forms. Informally, two of these forms are defined by maximal decomposition of equivalent sequences, and two of these forms are defined by maximal $(I composition) of equivalent sequences. $(UL $(LI Normalization Form D (NFD): The $(S_LINK Canonical decomposition, canonical decomposition) of a character sequence.) $(LI Normalization Form KD (NFKD): The $(S_LINK Compatibility decomposition, compatibility decomposition) of a character sequence.) $(LI Normalization Form C (NFC): The canonical composition of the $(S_LINK Canonical decomposition, canonical decomposition) of a coded character sequence.) $(LI Normalization Form KC (NFKC): The canonical composition of the $(S_LINK Compatibility decomposition, compatibility decomposition) of a character sequence) ) ) $(P The choice of the normalization form depends on the particular use case. NFC is the best form for general text, since it's more compatible with strings converted from legacy encodings. NFKC is the preferred form for identifiers, especially where there are security concerns. NFD and NFKD are the most useful for internal processing. ) $(SECTION Construction of lookup tables) $(P The Unicode standard describes a set of algorithms that depend on having the ability to quickly look up various properties of a code point. Given the the codespace of about 1 million $(CODEPOINTS), it is not a trivial task to provide a space-efficient solution for the multitude of properties.) $(P Common approaches such as hash-tables or binary search over sorted code point intervals (as in $(LREF InversionList)) are insufficient. Hash-tables have enormous memory footprint and binary search over intervals is not fast enough for some heavy-duty algorithms. ) $(P The recommended solution (see Unicode Implementation Guidelines) is using multi-stage tables that are an implementation of the $(WEB en.wikipedia.org/wiki/Trie, Trie) data structure with integer keys and a fixed number of stages. For the remainder of the section this will be called a fixed trie. The following describes a particular implementation that is aimed for the speed of access at the expense of ideal size savings. ) $(P Taking a 2-level Trie as an example the principle of operation is as follows. Split the number of bits in a key (code point, 21 bits) into 2 components (e.g. 15 and 8). The first is the number of bits in the index of the trie and the other is number of bits in each page of the trie. The layout of the trie is then an array of size 2^^bits-of-index followed an array of memory chunks of size 2^^bits-of-page/bits-per-element. ) $(P The number of pages is variable (but not less then 1) unlike the number of entries in the index. The slots of the index all have to contain a number of a page that is present. The lookup is then just a couple of operations - slice the upper bits, lookup an index for these, take a page at this index and use the lower bits as an offset within this page. Assuming that pages are laid out consequently in one array at $(D pages), the pseudo-code is: ) --- auto elemsPerPage = (2 ^^ bits_per_page) / Value.sizeOfInBits; pages[index[n >> bits_per_page]][n & (elemsPerPage - 1)]; --- $(P Where if $(D elemsPerPage) is a power of 2 the whole process is a handful of simple instructions and 2 array reads. Subsequent levels of the trie are introduced by recursing on this notion - the index array is treated as values. The number of bits in index is then again split into 2 parts, with pages over 'current-index' and the new 'upper-index'. ) $(P For completeness a level 1 trie is simply an array. The current implementation takes advantage of bit-packing values when the range is known to be limited in advance (such as $(D bool)). See also $(LREF BitPacked) for enforcing it manually. The major size advantage however comes from the fact that multiple $(B identical pages on every level are merged) by construction. ) $(P The process of constructing a trie is more involved and is hidden from the user in a form of the convenience functions $(LREF codepointTrie), $(LREF codepointSetTrie) and the even more convenient $(LREF toTrie). In general a set or built-in AA with $(D dchar) type can be turned into a trie. The trie object in this module is read-only (immutable); it's effectively frozen after construction. ) $(SECTION Unicode properties) $(P This is a full list of Unicode properties accessible through $(LREF unicode) with specific helpers per category nested within. Consult the $(WEB www.unicode.org/cldr/utility/properties.jsp, CLDR utility) when in doubt about the contents of a particular set.) $(P General category sets listed below are only accessible with the $(LREF unicode) shorthand accessor.) $(BOOKTABLE $(B General category ), $(TR $(TH Abb.) $(TH Long form) $(TH Abb.) $(TH Long form)$(TH Abb.) $(TH Long form)) $(TR $(TD L) $(TD Letter) $(TD Cn) $(TD Unassigned) $(TD Po) $(TD Other_Punctuation)) $(TR $(TD Ll) $(TD Lowercase_Letter) $(TD Co) $(TD Private_Use) $(TD Ps) $(TD Open_Punctuation)) $(TR $(TD Lm) $(TD Modifier_Letter) $(TD Cs) $(TD Surrogate) $(TD S) $(TD Symbol)) $(TR $(TD Lo) $(TD Other_Letter) $(TD N) $(TD Number) $(TD Sc) $(TD Currency_Symbol)) $(TR $(TD Lt) $(TD Titlecase_Letter) $(TD Nd) $(TD Decimal_Number) $(TD Sk) $(TD Modifier_Symbol)) $(TR $(TD Lu) $(TD Uppercase_Letter) $(TD Nl) $(TD Letter_Number) $(TD Sm) $(TD Math_Symbol)) $(TR $(TD M) $(TD Mark) $(TD No) $(TD Other_Number) $(TD So) $(TD Other_Symbol)) $(TR $(TD Mc) $(TD Spacing_Mark) $(TD P) $(TD Punctuation) $(TD Z) $(TD Separator)) $(TR $(TD Me) $(TD Enclosing_Mark) $(TD Pc) $(TD Connector_Punctuation) $(TD Zl) $(TD Line_Separator)) $(TR $(TD Mn) $(TD Nonspacing_Mark) $(TD Pd) $(TD Dash_Punctuation) $(TD Zp) $(TD Paragraph_Separator)) $(TR $(TD C) $(TD Other) $(TD Pe) $(TD Close_Punctuation) $(TD Zs) $(TD Space_Separator)) $(TR $(TD Cc) $(TD Control) $(TD Pf) $(TD Final_Punctuation) $(TD -) $(TD Any)) $(TR $(TD Cf) $(TD Format) $(TD Pi) $(TD Initial_Punctuation) $(TD -) $(TD ASCII)) ) $(P Sets for other commonly useful properties that are accessible with $(LREF unicode):) $(BOOKTABLE $(B Common binary properties), $(TR $(TH Name) $(TH Name) $(TH Name)) $(TR $(TD Alphabetic) $(TD Ideographic) $(TD Other_Uppercase)) $(TR $(TD ASCII_Hex_Digit) $(TD IDS_Binary_Operator) $(TD Pattern_Syntax)) $(TR $(TD Bidi_Control) $(TD ID_Start) $(TD Pattern_White_Space)) $(TR $(TD Cased) $(TD IDS_Trinary_Operator) $(TD Quotation_Mark)) $(TR $(TD Case_Ignorable) $(TD Join_Control) $(TD Radical)) $(TR $(TD Dash) $(TD Logical_Order_Exception) $(TD Soft_Dotted)) $(TR $(TD Default_Ignorable_Code_Point) $(TD Lowercase) $(TD STerm)) $(TR $(TD Deprecated) $(TD Math) $(TD Terminal_Punctuation)) $(TR $(TD Diacritic) $(TD Noncharacter_Code_Point) $(TD Unified_Ideograph)) $(TR $(TD Extender) $(TD Other_Alphabetic) $(TD Uppercase)) $(TR $(TD Grapheme_Base) $(TD Other_Default_Ignorable_Code_Point) $(TD Variation_Selector)) $(TR $(TD Grapheme_Extend) $(TD Other_Grapheme_Extend) $(TD White_Space)) $(TR $(TD Grapheme_Link) $(TD Other_ID_Continue) $(TD XID_Continue)) $(TR $(TD Hex_Digit) $(TD Other_ID_Start) $(TD XID_Start)) $(TR $(TD Hyphen) $(TD Other_Lowercase) ) $(TR $(TD ID_Continue) $(TD Other_Math) ) ) $(P Bellow is the table with block names accepted by $(LREF unicode.block). Note that the shorthand version $(LREF unicode) requires "In" to be prepended to the names of blocks so as to disambiguate scripts and blocks.) $(BOOKTABLE $(B Blocks), $(TR $(TD Aegean Numbers) $(TD Ethiopic Extended) $(TD Mongolian)) $(TR $(TD Alchemical Symbols) $(TD Ethiopic Extended-A) $(TD Musical Symbols)) $(TR $(TD Alphabetic Presentation Forms) $(TD Ethiopic Supplement) $(TD Myanmar)) $(TR $(TD Ancient Greek Musical Notation) $(TD General Punctuation) $(TD Myanmar Extended-A)) $(TR $(TD Ancient Greek Numbers) $(TD Geometric Shapes) $(TD New Tai Lue)) $(TR $(TD Ancient Symbols) $(TD Georgian) $(TD NKo)) $(TR $(TD Arabic) $(TD Georgian Supplement) $(TD Number Forms)) $(TR $(TD Arabic Extended-A) $(TD Glagolitic) $(TD Ogham)) $(TR $(TD Arabic Mathematical Alphabetic Symbols) $(TD Gothic) $(TD Ol Chiki)) $(TR $(TD Arabic Presentation Forms-A) $(TD Greek and Coptic) $(TD Old Italic)) $(TR $(TD Arabic Presentation Forms-B) $(TD Greek Extended) $(TD Old Persian)) $(TR $(TD Arabic Supplement) $(TD Gujarati) $(TD Old South Arabian)) $(TR $(TD Armenian) $(TD Gurmukhi) $(TD Old Turkic)) $(TR $(TD Arrows) $(TD Halfwidth and Fullwidth Forms) $(TD Optical Character Recognition)) $(TR $(TD Avestan) $(TD Hangul Compatibility Jamo) $(TD Oriya)) $(TR $(TD Balinese) $(TD Hangul Jamo) $(TD Osmanya)) $(TR $(TD Bamum) $(TD Hangul Jamo Extended-A) $(TD Phags-pa)) $(TR $(TD Bamum Supplement) $(TD Hangul Jamo Extended-B) $(TD Phaistos Disc)) $(TR $(TD Basic Latin) $(TD Hangul Syllables) $(TD Phoenician)) $(TR $(TD Batak) $(TD Hanunoo) $(TD Phonetic Extensions)) $(TR $(TD Bengali) $(TD Hebrew) $(TD Phonetic Extensions Supplement)) $(TR $(TD Block Elements) $(TD High Private Use Surrogates) $(TD Playing Cards)) $(TR $(TD Bopomofo) $(TD High Surrogates) $(TD Private Use Area)) $(TR $(TD Bopomofo Extended) $(TD Hiragana) $(TD Rejang)) $(TR $(TD Box Drawing) $(TD Ideographic Description Characters) $(TD Rumi Numeral Symbols)) $(TR $(TD Brahmi) $(TD Imperial Aramaic) $(TD Runic)) $(TR $(TD Braille Patterns) $(TD Inscriptional Pahlavi) $(TD Samaritan)) $(TR $(TD Buginese) $(TD Inscriptional Parthian) $(TD Saurashtra)) $(TR $(TD Buhid) $(TD IPA Extensions) $(TD Sharada)) $(TR $(TD Byzantine Musical Symbols) $(TD Javanese) $(TD Shavian)) $(TR $(TD Carian) $(TD Kaithi) $(TD Sinhala)) $(TR $(TD Chakma) $(TD Kana Supplement) $(TD Small Form Variants)) $(TR $(TD Cham) $(TD Kanbun) $(TD Sora Sompeng)) $(TR $(TD Cherokee) $(TD Kangxi Radicals) $(TD Spacing Modifier Letters)) $(TR $(TD CJK Compatibility) $(TD Kannada) $(TD Specials)) $(TR $(TD CJK Compatibility Forms) $(TD Katakana) $(TD Sundanese)) $(TR $(TD CJK Compatibility Ideographs) $(TD Katakana Phonetic Extensions) $(TD Sundanese Supplement)) $(TR $(TD CJK Compatibility Ideographs Supplement) $(TD Kayah Li) $(TD Superscripts and Subscripts)) $(TR $(TD CJK Radicals Supplement) $(TD Kharoshthi) $(TD Supplemental Arrows-A)) $(TR $(TD CJK Strokes) $(TD Khmer) $(TD Supplemental Arrows-B)) $(TR $(TD CJK Symbols and Punctuation) $(TD Khmer Symbols) $(TD Supplemental Mathematical Operators)) $(TR $(TD CJK Unified Ideographs) $(TD Lao) $(TD Supplemental Punctuation)) $(TR $(TD CJK Unified Ideographs Extension A) $(TD Latin-1 Supplement) $(TD Supplementary Private Use Area-A)) $(TR $(TD CJK Unified Ideographs Extension B) $(TD Latin Extended-A) $(TD Supplementary Private Use Area-B)) $(TR $(TD CJK Unified Ideographs Extension C) $(TD Latin Extended Additional) $(TD Syloti Nagri)) $(TR $(TD CJK Unified Ideographs Extension D) $(TD Latin Extended-B) $(TD Syriac)) $(TR $(TD Combining Diacritical Marks) $(TD Latin Extended-C) $(TD Tagalog)) $(TR $(TD Combining Diacritical Marks for Symbols) $(TD Latin Extended-D) $(TD Tagbanwa)) $(TR $(TD Combining Diacritical Marks Supplement) $(TD Lepcha) $(TD Tags)) $(TR $(TD Combining Half Marks) $(TD Letterlike Symbols) $(TD Tai Le)) $(TR $(TD Common Indic Number Forms) $(TD Limbu) $(TD Tai Tham)) $(TR $(TD Control Pictures) $(TD Linear B Ideograms) $(TD Tai Viet)) $(TR $(TD Coptic) $(TD Linear B Syllabary) $(TD Tai Xuan Jing Symbols)) $(TR $(TD Counting Rod Numerals) $(TD Lisu) $(TD Takri)) $(TR $(TD Cuneiform) $(TD Low Surrogates) $(TD Tamil)) $(TR $(TD Cuneiform Numbers and Punctuation) $(TD Lycian) $(TD Telugu)) $(TR $(TD Currency Symbols) $(TD Lydian) $(TD Thaana)) $(TR $(TD Cypriot Syllabary) $(TD Mahjong Tiles) $(TD Thai)) $(TR $(TD Cyrillic) $(TD Malayalam) $(TD Tibetan)) $(TR $(TD Cyrillic Extended-A) $(TD Mandaic) $(TD Tifinagh)) $(TR $(TD Cyrillic Extended-B) $(TD Mathematical Alphanumeric Symbols) $(TD Transport And Map Symbols)) $(TR $(TD Cyrillic Supplement) $(TD Mathematical Operators) $(TD Ugaritic)) $(TR $(TD Deseret) $(TD Meetei Mayek) $(TD Unified Canadian Aboriginal Syllabics)) $(TR $(TD Devanagari) $(TD Meetei Mayek Extensions) $(TD Unified Canadian Aboriginal Syllabics Extended)) $(TR $(TD Devanagari Extended) $(TD Meroitic Cursive) $(TD Vai)) $(TR $(TD Dingbats) $(TD Meroitic Hieroglyphs) $(TD Variation Selectors)) $(TR $(TD Domino Tiles) $(TD Miao) $(TD Variation Selectors Supplement)) $(TR $(TD Egyptian Hieroglyphs) $(TD Miscellaneous Mathematical Symbols-A) $(TD Vedic Extensions)) $(TR $(TD Emoticons) $(TD Miscellaneous Mathematical Symbols-B) $(TD Vertical Forms)) $(TR $(TD Enclosed Alphanumerics) $(TD Miscellaneous Symbols) $(TD Yijing Hexagram Symbols)) $(TR $(TD Enclosed Alphanumeric Supplement) $(TD Miscellaneous Symbols and Arrows) $(TD Yi Radicals)) $(TR $(TD Enclosed CJK Letters and Months) $(TD Miscellaneous Symbols And Pictographs) $(TD Yi Syllables)) $(TR $(TD Enclosed Ideographic Supplement) $(TD Miscellaneous Technical) ) $(TR $(TD Ethiopic) $(TD Modifier Tone Letters) ) ) $(P Bellow is the table with script names accepted by $(LREF unicode.script) and by the shorthand version $(LREF unicode):) $(BOOKTABLE $(B Scripts), $(TR $(TD Arabic) $(TD Hanunoo) $(TD Old_Italic)) $(TR $(TD Armenian) $(TD Hebrew) $(TD Old_Persian)) $(TR $(TD Avestan) $(TD Hiragana) $(TD Old_South_Arabian)) $(TR $(TD Balinese) $(TD Imperial_Aramaic) $(TD Old_Turkic)) $(TR $(TD Bamum) $(TD Inherited) $(TD Oriya)) $(TR $(TD Batak) $(TD Inscriptional_Pahlavi) $(TD Osmanya)) $(TR $(TD Bengali) $(TD Inscriptional_Parthian) $(TD Phags_Pa)) $(TR $(TD Bopomofo) $(TD Javanese) $(TD Phoenician)) $(TR $(TD Brahmi) $(TD Kaithi) $(TD Rejang)) $(TR $(TD Braille) $(TD Kannada) $(TD Runic)) $(TR $(TD Buginese) $(TD Katakana) $(TD Samaritan)) $(TR $(TD Buhid) $(TD Kayah_Li) $(TD Saurashtra)) $(TR $(TD Canadian_Aboriginal) $(TD Kharoshthi) $(TD Sharada)) $(TR $(TD Carian) $(TD Khmer) $(TD Shavian)) $(TR $(TD Chakma) $(TD Lao) $(TD Sinhala)) $(TR $(TD Cham) $(TD Latin) $(TD Sora_Sompeng)) $(TR $(TD Cherokee) $(TD Lepcha) $(TD Sundanese)) $(TR $(TD Common) $(TD Limbu) $(TD Syloti_Nagri)) $(TR $(TD Coptic) $(TD Linear_B) $(TD Syriac)) $(TR $(TD Cuneiform) $(TD Lisu) $(TD Tagalog)) $(TR $(TD Cypriot) $(TD Lycian) $(TD Tagbanwa)) $(TR $(TD Cyrillic) $(TD Lydian) $(TD Tai_Le)) $(TR $(TD Deseret) $(TD Malayalam) $(TD Tai_Tham)) $(TR $(TD Devanagari) $(TD Mandaic) $(TD Tai_Viet)) $(TR $(TD Egyptian_Hieroglyphs) $(TD Meetei_Mayek) $(TD Takri)) $(TR $(TD Ethiopic) $(TD Meroitic_Cursive) $(TD Tamil)) $(TR $(TD Georgian) $(TD Meroitic_Hieroglyphs) $(TD Telugu)) $(TR $(TD Glagolitic) $(TD Miao) $(TD Thaana)) $(TR $(TD Gothic) $(TD Mongolian) $(TD Thai)) $(TR $(TD Greek) $(TD Myanmar) $(TD Tibetan)) $(TR $(TD Gujarati) $(TD New_Tai_Lue) $(TD Tifinagh)) $(TR $(TD Gurmukhi) $(TD Nko) $(TD Ugaritic)) $(TR $(TD Han) $(TD Ogham) $(TD Vai)) $(TR $(TD Hangul) $(TD Ol_Chiki) $(TD Yi)) ) $(P Bellow is the table of names accepted by $(LREF unicode.hangulSyllableType).) $(BOOKTABLE $(B Hangul syllable type), $(TR $(TH Abb.) $(TH Long form)) $(TR $(TD L) $(TD Leading_Jamo)) $(TR $(TD LV) $(TD LV_Syllable)) $(TR $(TD LVT) $(TD LVT_Syllable) ) $(TR $(TD T) $(TD Trailing_Jamo)) $(TR $(TD V) $(TD Vowel_Jamo)) ) References: $(WEB www.digitalmars.com/d/ascii-table.html, ASCII Table), $(WEB en.wikipedia.org/wiki/Unicode, Wikipedia), $(WEB www.unicode.org, The Unicode Consortium), $(WEB www.unicode.org/reports/tr15/, Unicode normalization forms), $(WEB www.unicode.org/reports/tr29/, Unicode text segmentation) $(WEB www.unicode.org/uni2book/ch05.pdf, Unicode Implementation Guidelines) $(WEB www.unicode.org/uni2book/ch03.pdf, Unicode Conformance) Trademarks: Unicode(tm) is a trademark of Unicode, Inc. Macros: WIKI=Phobos/StdUni Copyright: Copyright 2013 - License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Dmitry Olshansky Source: $(PHOBOSSRC std/_uni.d) Standards: $(WEB www.unicode.org/versions/Unicode6.2.0/, Unicode v6.2) Macros: SECTION =

$0

DEF = S_LINK = $+ CODEPOINT = $(S_LINK Code point, code point) CODEPOINTS = $(S_LINK Code point, code points) CHARACTER = $(S_LINK Character, character) CHARACTERS = $(S_LINK Character, characters) CLUSTER = $(S_LINK Grapheme cluster, grapheme cluster) +/ module std.uni; import core.stdc.stdlib; import std.meta, std.traits; import std.range.primitives; // debug = std_uni; debug(std_uni) import std.stdio; private: version (unittest) { private: struct TestAliasedString { string get() @safe @nogc pure nothrow { return _s; } alias get this; @disable this(this); string _s; } bool testAliasedString(alias func, Args...)(string s, Args args) { import std.algorithm.comparison : equal; auto a = func(TestAliasedString(s), args); auto b = func(s, args); static if (is(typeof(equal(a, b)))) { // For ranges, compare contents instead of object identity. return equal(a, b); } else { return a == b; } } } version(std_uni_bootstrap){} else { import std.internal.unicode_tables; // generated file } void copyBackwards(T,U)(T[] src, U[] dest) { assert(src.length == dest.length); for(size_t i=src.length; i-- > 0; ) dest[i] = src[i]; } void copyForward(T,U)(T[] src, U[] dest) { assert(src.length == dest.length); for(size_t i=0; i 45); // 46 items in Unicode 6.1, even more in 6.2 // testing presence of a code point in a set // is just fine, it is O(logN) assert(!b['$']); assert(!b['\u058F']); // Armenian dram sign assert(b['¥']); // building fast lookup tables, these guarantee O(1) complexity // 1-level Trie lookup table essentially a huge bit-set ~262Kb auto oneTrie = toTrie!1(b); // 2-level far more compact but typically slightly slower auto twoTrie = toTrie!2(b); // 3-level even smaller, and a bit slower yet auto threeTrie = toTrie!3(b); assert(oneTrie['£']); assert(twoTrie['£']); assert(threeTrie['£']); // build the trie with the most sensible trie level // and bind it as a functor auto cyrillicOrArmenian = toDelegate(set); auto balance = find!(cyrillicOrArmenian)("Hello ընկեր!"); assert(balance == "ընկեր!"); // compatible with bool delegate(dchar) bool delegate(dchar) bindIt = cyrillicOrArmenian; // Normalization string s = "Plain ascii (and not only), is always normalized!"; assert(s is normalize(s));// is the same string string nonS = "A\u0308ffin"; // A ligature auto nS = normalize(nonS); // to NFC, the W3C endorsed standard assert(nS == "Äffin"); assert(nS != nonS); string composed = "Äffin"; assert(normalize!NFD(composed) == "A\u0308ffin"); // to NFKD, compatibility decomposition useful for fuzzy matching/searching assert(normalize!NFKD("2¹⁰") == "210"); } enum lastDchar = 0x10FFFF; auto force(T, F)(F from) if(isIntegral!T && !is(T == F)) { assert(from <= T.max && from >= T.min); return cast(T)from; } auto force(T, F)(F from) if(isBitPacked!T && !is(T == F)) { assert(from <= 2^^bitSizeOf!T-1); return T(cast(TypeOfBitPacked!T)from); } auto force(T, F)(F from) if(is(T == F)) { return from; } // repeat X times the bit-pattern in val assuming it's length is 'bits' size_t replicateBits(size_t times, size_t bits)(size_t val) @safe pure nothrow @nogc { static if(times == 1) return val; else static if(bits == 1) { static if(times == size_t.sizeof*8) return val ? size_t.max : 0; else return val ? (1<= 1) offsets[i] = offsets[i-1] + spaceFor!(bitSizeOf!(Types[i-1]))(sizes[i-1]); } storage = new size_t[full_size]; } this(const(size_t)[] raw_offsets, const(size_t)[] raw_sizes, const(size_t)[] data)const @safe pure nothrow @nogc { offsets[] = raw_offsets[]; sz[] = raw_sizes[]; storage = data; } @property auto slice(size_t n)()inout pure nothrow @nogc { auto ptr = raw_ptr!n; return packedArrayView!(Types[n])(ptr, sz[n]); } @property auto ptr(size_t n)()inout pure nothrow @nogc { auto ptr = raw_ptr!n; return inout(PackedPtr!(Types[n]))(ptr); } template length(size_t n) { @property size_t length()const @safe pure nothrow @nogc{ return sz[n]; } @property void length(size_t new_size) { if(new_size > sz[n]) {// extend size_t delta = (new_size - sz[n]); sz[n] += delta; delta = spaceFor!(bitSizeOf!(Types[n]))(delta); storage.length += delta;// extend space at end // raw_slice!x must follow resize as it could be moved! // next stmts move all data past this array, last-one-goes-first static if(n != dim-1) { auto start = raw_ptr!(n+1); // len includes delta size_t len = (storage.ptr+storage.length-start); copyBackwards(start[0..len-delta], start[delta..len]); start[0..delta] = 0; // offsets are used for raw_slice, ptr etc. foreach(i; n+1..dim) offsets[i] += delta; } } else if(new_size < sz[n]) {// shrink size_t delta = (sz[n] - new_size); sz[n] -= delta; delta = spaceFor!(bitSizeOf!(Types[n]))(delta); // move all data past this array, forward direction static if(n != dim-1) { auto start = raw_ptr!(n+1); size_t len = (storage.ptr+storage.length-start); copyForward(start[0..len-delta], start[delta..len]); // adjust offsets last, they affect raw_slice foreach(i; n+1..dim) offsets[i] -= delta; } storage.length -= delta; } // else - NOP } } @property size_t bytes(size_t n=size_t.max)() const { static if(n == size_t.max) return storage.length*size_t.sizeof; else static if(n != Types.length-1) return (raw_ptr!(n+1)-raw_ptr!n)*size_t.sizeof; else return (storage.ptr+storage.length - raw_ptr!n)*size_t.sizeof; } void store(OutRange)(scope OutRange sink) const if(isOutputRange!(OutRange, char)) { import std.format; formattedWrite(sink, "[%( 0x%x, %)]", offsets[]); formattedWrite(sink, ", [%( 0x%x, %)]", sz[]); formattedWrite(sink, ", [%( 0x%x, %)]", storage); } private: @property auto raw_ptr(size_t n)()inout pure nothrow @nogc { static if(n == 0) return storage.ptr; else { return storage.ptr+offsets[n]; } } enum dim = Types.length; size_t[dim] offsets;// offset for level x size_t[dim] sz;// size of level x alias bitWidth = staticMap!(bitSizeOf, Types); size_t[] storage; } unittest { import std.conv; enum dg = (){ // sizes are: // lvl0: 3, lvl1 : 2, lvl2: 1 auto m = MultiArray!(int, ubyte, int)(3,2,1); static void check(size_t k, T)(ref T m, int n) { foreach(i; 0..n) assert(m.slice!(k)[i] == i+1, text("level:",i," : ",m.slice!(k)[0..n])); } static void checkB(size_t k, T)(ref T m, int n) { foreach(i; 0..n) assert(m.slice!(k)[i] == n-i, text("level:",i," : ",m.slice!(k)[0..n])); } static void fill(size_t k, T)(ref T m, int n) { foreach(i; 0..n) m.slice!(k)[i] = force!ubyte(i+1); } static void fillB(size_t k, T)(ref T m, int n) { foreach(i; 0..n) m.slice!(k)[i] = force!ubyte(n-i); } m.length!1 = 100; fill!1(m, 100); check!1(m, 100); m.length!0 = 220; fill!0(m, 220); check!1(m, 100); check!0(m, 220); m.length!2 = 17; fillB!2(m, 17); checkB!2(m, 17); check!0(m, 220); check!1(m, 100); m.length!2 = 33; checkB!2(m, 17); fillB!2(m, 33); checkB!2(m, 33); check!0(m, 220); check!1(m, 100); m.length!1 = 195; fillB!1(m, 195); checkB!1(m, 195); checkB!2(m, 33); check!0(m, 220); auto marr = MultiArray!(BitPacked!(uint, 4), BitPacked!(uint, 6))(20, 10); marr.length!0 = 15; marr.length!1 = 30; fill!1(marr, 30); fill!0(marr, 15); check!1(marr, 30); check!0(marr, 15); return 0; }; enum ct = dg(); auto rt = dg(); } unittest {// more bitpacking tests import std.conv; alias Bitty = MultiArray!(BitPacked!(size_t, 3) , BitPacked!(size_t, 4) , BitPacked!(size_t, 3) , BitPacked!(size_t, 6) , bool); alias fn1 = sliceBits!(13, 16); alias fn2 = sliceBits!( 9, 13); alias fn3 = sliceBits!( 6, 9); alias fn4 = sliceBits!( 0, 6); static void check(size_t lvl, MA)(ref MA arr){ for(size_t i = 0; i< arr.length!lvl; i++) assert(arr.slice!(lvl)[i] == i, text("Mismatch on lvl ", lvl, " idx ", i, " value: ", arr.slice!(lvl)[i])); } static void fillIdx(size_t lvl, MA)(ref MA arr){ for(size_t i = 0; i< arr.length!lvl; i++) arr.slice!(lvl)[i] = i; } Bitty m1; m1.length!4 = 10; m1.length!3 = 2^^6; m1.length!2 = 2^^3; m1.length!1 = 2^^4; m1.length!0 = 2^^3; m1.length!4 = 2^^16; for(size_t i = 0; i< m1.length!4; i++) m1.slice!(4)[i] = i % 2; fillIdx!1(m1); check!1(m1); fillIdx!2(m1); check!2(m1); fillIdx!3(m1); check!3(m1); fillIdx!0(m1); check!0(m1); check!3(m1); check!2(m1); check!1(m1); for(size_t i=0; i < 2^^16; i++) { m1.slice!(4)[i] = i % 2; m1.slice!(0)[fn1(i)] = fn1(i); m1.slice!(1)[fn2(i)] = fn2(i); m1.slice!(2)[fn3(i)] = fn3(i); m1.slice!(3)[fn4(i)] = fn4(i); } for(size_t i=0; i < 2^^16; i++) { assert(m1.slice!(4)[i] == i % 2); assert(m1.slice!(0)[fn1(i)] == fn1(i)); assert(m1.slice!(1)[fn2(i)] == fn2(i)); assert(m1.slice!(2)[fn3(i)] == fn3(i)); assert(m1.slice!(3)[fn4(i)] == fn4(i)); } } size_t spaceFor(size_t _bits)(size_t new_len) @safe pure nothrow @nogc { enum bits = _bits == 1 ? 1 : ceilPowerOf2(_bits);// see PackedArrayView static if(bits > 8*size_t.sizeof) { static assert(bits % (size_t.sizeof*8) == 0); return new_len * bits/(8*size_t.sizeof); } else { enum factor = size_t.sizeof*8/bits; return (new_len+factor-1)/factor; // rounded up } } template isBitPackableType(T) { enum isBitPackableType = isBitPacked!T || isIntegral!T || is(T == bool) || isSomeChar!T; } //============================================================================ template PackedArrayView(T) if((is(T dummy == BitPacked!(U, sz), U, size_t sz) && isBitPackableType!U) || isBitPackableType!T) { private enum bits = bitSizeOf!T; alias PackedArrayView = PackedArrayViewImpl!(T, bits > 1 ? ceilPowerOf2(bits) : 1); } //unsafe and fast access to a chunk of RAM as if it contains packed values template PackedPtr(T) if((is(T dummy == BitPacked!(U, sz), U, size_t sz) && isBitPackableType!U) || isBitPackableType!T) { private enum bits = bitSizeOf!T; alias PackedPtr = PackedPtrImpl!(T, bits > 1 ? ceilPowerOf2(bits) : 1); } @trusted struct PackedPtrImpl(T, size_t bits) { pure nothrow: static assert(isPowerOf2(bits)); this(inout(size_t)* ptr)inout @safe @nogc { origin = ptr; } private T simpleIndex(size_t n) inout { auto q = n / factor; auto r = n % factor; return cast(T)((origin[q] >> bits*r) & mask); } private void simpleWrite(TypeOfBitPacked!T val, size_t n) in { static if(isIntegral!T) assert(val <= mask); } body { auto q = n / factor; auto r = n % factor; size_t tgt_shift = bits*r; size_t word = origin[q]; origin[q] = (word & ~(mask<= e) { foreach (i; s..e) if(ptr[i]) return false; return true; } size_t pad_e = roundDown(e); size_t i; for(i=s; i= end) //rounded up >= then end of slice { //nothing to gain, use per element assignment foreach(i; start..end) ptr[i] = val; return; } size_t pad_end = roundDown(end); // rounded down size_t i; for(i=start; i= max) { if(pred(range[idx+m], needle)) idx += m; m /= 2; } mixin(genUnrolledSwitchSearch(max)); return idx; } // size_t floorPowerOf2(size_t arg) @safe pure nothrow @nogc { import core.bitop : bsr; assert(arg > 1); // else bsr is undefined return 1< 1); // else bsr is undefined return 1< delta) {// replace increases length delta = stuff.length - delta;// now, new is > old by delta static if(is(Policy == void)) dest.length = dest.length+delta;//@@@BUG lame @property else dest = Policy.realloc(dest, dest.length+delta); copyBackwards(dest[to..dest.length-delta], dest[to+delta..dest.length]); copyForward(stuff, dest[from..stuff_end]); } else if(stuff.length == delta) { copy(stuff, dest[from..to]); } else {// replace decreases length by delta delta = delta - stuff.length; copy(stuff, dest[from..stuff_end]); copyForward(dest[to..dest.length], dest[stuff_end..dest.length-delta]); static if(is(Policy == void)) dest.length = dest.length - delta;//@@@BUG lame @property else dest = Policy.realloc(dest, dest.length-delta); } return stuff_end; } // Simple storage manipulation policy @trusted public struct GcPolicy { static T[] dup(T)(const T[] arr) { return arr.dup; } static T[] alloc(T)(size_t size) { return new T[size]; } static T[] realloc(T)(T[] arr, size_t sz) { arr.length = sz; return arr; } static void replaceImpl(T, Range)(ref T[] dest, size_t from, size_t to, Range stuff) { replaceInPlace(dest, from, to, stuff); } static void append(T, V)(ref T[] arr, V value) if(!isInputRange!V) { arr ~= force!T(value); } static void append(T, V)(ref T[] arr, V value) if(isInputRange!V) { insertInPlace(arr, arr.length, value); } static void destroy(T)(ref T arr) if(isDynamicArray!T && is(Unqual!T == T)) { debug { arr[] = cast(typeof(T.init[0]))(0xdead_beef); } arr = null; } static void destroy(T)(ref T arr) if(isDynamicArray!T && !is(Unqual!T == T)) { arr = null; } } // ditto @trusted struct ReallocPolicy { static T[] dup(T)(const T[] arr) { auto result = alloc!T(arr.length); result[] = arr[]; return result; } static T[] alloc(T)(size_t size) { import std.exception : enforce; auto ptr = cast(T*)enforce(malloc(T.sizeof*size), "out of memory on C heap"); return ptr[0..size]; } static T[] realloc(T)(T[] arr, size_t size) { import std.exception : enforce; if(!size) { destroy(arr); return null; } auto ptr = cast(T*)enforce(core.stdc.stdlib.realloc( arr.ptr, T.sizeof*size), "out of memory on C heap"); return ptr[0..size]; } static void replaceImpl(T, Range)(ref T[] dest, size_t from, size_t to, Range stuff) { genericReplace!(ReallocPolicy)(dest, from, to, stuff); } static void append(T, V)(ref T[] arr, V value) if(!isInputRange!V) { arr = realloc(arr, arr.length+1); arr[$-1] = force!T(value); } static void append(T, V)(ref T[] arr, V value) if(isInputRange!V && hasLength!V) { arr = realloc(arr, arr.length+value.length); copy(value, arr[$-value.length..$]); } static void destroy(T)(ref T[] arr) { if(arr.ptr) free(arr.ptr); arr = null; } } //build hack alias _RealArray = CowArray!ReallocPolicy; unittest { with(ReallocPolicy) { bool test(T, U, V)(T orig, size_t from, size_t to, U toReplace, V result, string file = __FILE__, size_t line = __LINE__) { { replaceImpl(orig, from, to, toReplace); scope(exit) destroy(orig); if(!equalS(orig, result)) return false; } return true; } static T[] arr(T)(T[] args... ) { return dup(args); } assert(test(arr([1, 2, 3, 4]), 0, 0, [5, 6, 7], [5, 6, 7, 1, 2, 3, 4])); assert(test(arr([1, 2, 3, 4]), 0, 2, cast(int[])[], [3, 4])); assert(test(arr([1, 2, 3, 4]), 0, 4, [5, 6, 7], [5, 6, 7])); assert(test(arr([1, 2, 3, 4]), 0, 2, [5, 6, 7], [5, 6, 7, 3, 4])); assert(test(arr([1, 2, 3, 4]), 2, 3, [5, 6, 7], [1, 2, 5, 6, 7, 4])); } } /** Tests if T is some kind a set of code points. Intended for template constraints. */ public template isCodepointSet(T) { static if(is(T dummy == InversionList!(Args), Args...)) enum isCodepointSet = true; else enum isCodepointSet = false; } /** Tests if $(D T) is a pair of integers that implicitly convert to $(D V). The following code must compile for any pair $(D T): --- (T x){ V a = x[0]; V b = x[1];} --- The following must not compile: --- (T x){ V c = x[2];} --- */ public template isIntegralPair(T, V=uint) { enum isIntegralPair = is(typeof((T x){ V a = x[0]; V b = x[1];})) && !is(typeof((T x){ V c = x[2]; })); } /** The recommended default type for set of $(CODEPOINTS). For details, see the current implementation: $(LREF InversionList). */ public alias CodepointSet = InversionList!GcPolicy; //@@@BUG: std.typecons tuples depend on std.format to produce fields mixin // which relies on std.uni.isGraphical and this chain blows up with Forward reference error // hence below doesn't seem to work // public alias CodepointInterval = Tuple!(uint, "a", uint, "b"); /** The recommended type of $(XREF _typecons, Tuple) to represent [a, b$(RPAREN) intervals of $(CODEPOINTS). As used in $(LREF InversionList). Any interval type should pass $(LREF isIntegralPair) trait. */ public struct CodepointInterval { pure: uint[2] _tuple; alias _tuple this; @safe pure nothrow @nogc: this(uint low, uint high) { _tuple[0] = low; _tuple[1] = high; } bool opEquals(T)(T val) const { return this[0] == val[0] && this[1] == val[1]; } @property ref inout(uint) a() inout { return _tuple[0]; } @property ref inout(uint) b() inout { return _tuple[1]; } } //@@@BUG another forward reference workaround @trusted bool equalS(R1, R2)(R1 lhs, R2 rhs) { for(;;){ if(lhs.empty) return rhs.empty; if(rhs.empty) return false; if(lhs.front != rhs.front) return false; lhs.popFront(); rhs.popFront(); } } /** $(P $(D InversionList) is a set of $(CODEPOINTS) represented as an array of open-right [a, b$(RPAREN) intervals (see $(LREF CodepointInterval) above). The name comes from the way the representation reads left to right. For instance a set of all values [10, 50$(RPAREN), [80, 90$(RPAREN), plus a singular value 60 looks like this: ) --- 10, 50, 60, 61, 80, 90 --- $(P The way to read this is: start with negative meaning that all numbers smaller then the next one are not present in this set (and positive - the contrary). Then switch positive/negative after each number passed from left to right. ) $(P This way negative spans until 10, then positive until 50, then negative until 60, then positive until 61, and so on. As seen this provides a space-efficient storage of highly redundant data that comes in long runs. A description which Unicode $(CHARACTER) properties fit nicely. The technique itself could be seen as a variation on $(LUCKY RLE encoding). ) $(P Sets are value types (just like $(D int) is) thus they are never aliased. ) Example: --- auto a = CodepointSet('a', 'z'+1); auto b = CodepointSet('A', 'Z'+1); auto c = a; a = a | b; assert(a == CodepointSet('A', 'Z'+1, 'a', 'z'+1)); assert(a != c); --- $(P See also $(LREF unicode) for simpler construction of sets from predefined ones. ) $(P Memory usage is 8 bytes per each contiguous interval in a set. The value semantics are achieved by using the $(WEB en.wikipedia.org/wiki/Copy-on-write, COW) technique and thus it's $(RED not) safe to cast this type to $(D_KEYWORD shared). ) Note: $(P It's not recommended to rely on the template parameters or the exact type of a current $(CODEPOINT) set in $(D std.uni). The type and parameters may change when the standard allocators design is finalized. Use $(LREF isCodepointSet) with templates or just stick with the default alias $(LREF CodepointSet) throughout the whole code base. ) */ @trusted public struct InversionList(SP=GcPolicy) { import std.range : assumeSorted; public: /** Construct from another code point set of any type. */ this(Set)(Set set) pure if(isCodepointSet!Set) { uint[] arr; foreach(v; set.byInterval) { arr ~= v.a; arr ~= v.b; } data = CowArray!(SP).reuse(arr); } /** Construct a set from a forward range of code point intervals. */ this(Range)(Range intervals) pure if(isForwardRange!Range && isIntegralPair!(ElementType!Range)) { uint[] arr; foreach(v; intervals) { SP.append(arr, v.a); SP.append(arr, v.b); } data = CowArray!(SP).reuse(arr); sanitize(); //enforce invariant: sort intervals etc. } //helper function that avoids sanity check to be CTFE-friendly private static fromIntervals(Range)(Range intervals) pure { import std.algorithm : map; import std.range : roundRobin; auto flattened = roundRobin(intervals.save.map!"a[0]"(), intervals.save.map!"a[1]"()); InversionList set; set.data = CowArray!(SP)(flattened); return set; } //ditto untill sort is CTFE-able private static fromIntervals()(uint[] intervals...) pure in { import std.conv : text; assert(intervals.length % 2 == 0, "Odd number of interval bounds [a, b)!"); for (uint i = 0; i < intervals.length; i += 2) { auto a = intervals[i], b = intervals[i+1]; assert(a < b, text("illegal interval [a, b): ", a, " > ", b)); } } body { InversionList set; set.data = CowArray!(SP)(intervals); return set; } /** Construct a set from plain values of code point intervals. */ this()(uint[] intervals...) in { import std.conv : text; assert(intervals.length % 2 == 0, "Odd number of interval bounds [a, b)!"); for (uint i = 0; i < intervals.length; i += 2) { auto a = intervals[i], b = intervals[i+1]; assert(a < b, text("illegal interval [a, b): ", a, " > ", b)); } } body { data = CowArray!(SP)(intervals); sanitize(); //enforce invariant: sort intervals etc. } /// unittest { import std.algorithm.comparison : equal; auto set = CodepointSet('a', 'z'+1, 'а', 'я'+1); foreach(v; 'a'..'z'+1) assert(set[v]); // Cyrillic lowercase interval foreach(v; 'а'..'я'+1) assert(set[v]); //specific order is not required, intervals may interesect auto set2 = CodepointSet('а', 'я'+1, 'a', 'd', 'b', 'z'+1); //the same end result assert(set2.byInterval.equal(set.byInterval)); } /** Get range that spans all of the $(CODEPOINT) intervals in this $(LREF InversionList). Example: ----------- import std.algorithm.comparison : equal; import std.typecons : tuple; auto set = CodepointSet('A', 'D'+1, 'a', 'd'+1); assert(set.byInterval.equal([tuple('A','E'), tuple('a','e')])); ----------- */ @property auto byInterval() { return Intervals!(typeof(data))(data); } /** Tests the presence of code point $(D val) in this set. */ bool opIndex(uint val) const { // the <= ensures that searching in interval of [a, b) for 'a' you get .length == 1 // return assumeSorted!((a,b) => a<=b)(data[]).lowerBound(val).length & 1; return sharSwitchLowerBound!"a<=b"(data[], val) & 1; } /// unittest { auto gothic = unicode.Gothic; // Gothic letter ahsa assert(gothic['\U00010330']); // no ascii in Gothic obviously assert(!gothic['$']); } // Linear scan for $(D ch). Useful only for small sets. // TODO: // used internally in std.regex // should be properly exposed in a public API ? package auto scanFor()(dchar ch) const { immutable len = data.length; for(size_t i = 0; i < len; i++) if(ch < data[i]) return i & 1; return 0; } /// Number of $(CODEPOINTS) in this set @property size_t length() { size_t sum = 0; foreach(iv; byInterval) { sum += iv.b - iv.a; } return sum; } // bootstrap full set operations from 4 primitives (suitable as a template mixin): // addInterval, skipUpTo, dropUpTo & byInterval iteration //============================================================================ public: /** $(P Sets support natural syntax for set algebra, namely: ) $(BOOKTABLE , $(TR $(TH Operator) $(TH Math notation) $(TH Description) ) $(TR $(TD &) $(TD a ∩ b) $(TD intersection) ) $(TR $(TD |) $(TD a ∪ b) $(TD union) ) $(TR $(TD -) $(TD a ∖ b) $(TD subtraction) ) $(TR $(TD ~) $(TD a ~ b) $(TD symmetric set difference i.e. (a ∪ b) \ (a ∩ b)) ) ) */ This opBinary(string op, U)(U rhs) if(isCodepointSet!U || is(U:dchar)) { static if(op == "&" || op == "|" || op == "~") {// symmetric ops thus can swap arguments to reuse r-value static if(is(U:dchar)) { auto tmp = this; mixin("tmp "~op~"= rhs; "); return tmp; } else { static if(is(Unqual!U == U)) { // try hard to reuse r-value mixin("rhs "~op~"= this;"); return rhs; } else { auto tmp = this; mixin("tmp "~op~"= rhs;"); return tmp; } } } else static if(op == "-") // anti-symmetric { auto tmp = this; tmp -= rhs; return tmp; } else static assert(0, "no operator "~op~" defined for Set"); } /// unittest { import std.algorithm.comparison : equal; import std.range : iota; auto lower = unicode.LowerCase; auto upper = unicode.UpperCase; auto ascii = unicode.ASCII; assert((lower & upper).empty); // no intersection auto lowerASCII = lower & ascii; assert(lowerASCII.byCodepoint.equal(iota('a', 'z'+1))); // throw away all of the lowercase ASCII assert((ascii - lower).length == 128 - 26); auto onlyOneOf = lower ~ ascii; assert(!onlyOneOf['Δ']); // not ASCII and not lowercase assert(onlyOneOf['$']); // ASCII and not lowercase assert(!onlyOneOf['a']); // ASCII and lowercase assert(onlyOneOf['я']); // not ASCII but lowercase // throw away all cased letters from ASCII auto noLetters = ascii - (lower | upper); assert(noLetters.length == 128 - 26*2); } /// The 'op=' versions of the above overloaded operators. ref This opOpAssign(string op, U)(U rhs) if(isCodepointSet!U || is(U:dchar)) { static if(op == "|") // union { static if(is(U:dchar)) { this.addInterval(rhs, rhs+1); return this; } else return this.add(rhs); } else static if(op == "&") // intersection return this.intersect(rhs);// overloaded else static if(op == "-") // set difference return this.sub(rhs);// overloaded else static if(op == "~") // symmetric set difference { auto copy = this & rhs; this |= rhs; this -= copy; return this; } else static assert(0, "no operator "~op~" defined for Set"); } /** Tests the presence of codepoint $(D ch) in this set, the same as $(LREF opIndex). */ bool opBinaryRight(string op: "in", U)(U ch) const if(is(U : dchar)) { return this[ch]; } /// unittest { assert('я' in unicode.Cyrillic); assert(!('z' in unicode.Cyrillic)); } /** * Obtains a set that is the inversion of this set. * * See_Also: $(LREF inverted) */ auto opUnary(string op: "!")() { return this.inverted; } /** A range that spans each $(CODEPOINT) in this set. */ @property auto byCodepoint() { @trusted static struct CodepointRange { this(This set) { r = set.byInterval; if(!r.empty) cur = r.front.a; } @property dchar front() const { return cast(dchar)cur; } @property bool empty() const { return r.empty; } void popFront() { cur++; while(cur >= r.front.b) { r.popFront(); if(r.empty) break; cur = r.front.a; } } private: uint cur; typeof(This.init.byInterval) r; } return CodepointRange(this); } /// unittest { import std.algorithm.comparison : equal; import std.range : iota; auto set = unicode.ASCII; set.byCodepoint.equal(iota(0, 0x80)); } /** $(P Obtain textual representation of this set in from of open-right intervals and feed it to $(D sink). ) $(P Used by various standard formatting facilities such as $(XREF _format, formattedWrite), $(XREF _stdio, write), $(XREF _stdio, writef), $(XREF _conv, to) and others. ) Example: --- import std.conv; assert(unicode.ASCII.to!string == "[0..128$(RPAREN)"); --- */ private import std.format : FormatException, FormatSpec; /*************************************** * Obtain a textual representation of this InversionList * in form of open-right intervals. * * The formatting flag is applied individually to each value, for example: * $(LI $(B %s) and $(B %d) format the intervals as a [low..high$(RPAREN) range of integrals) * $(LI $(B %x) formats the intervals as a [low..high$(RPAREN) range of lowercase hex characters) * $(LI $(B %X) formats the intervals as a [low..high$(RPAREN) range of uppercase hex characters) */ void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) /* const */ { import std.format; auto range = byInterval; if(range.empty) return; while (1) { auto i = range.front; range.popFront(); put(sink, "["); formatValue(sink, i.a, fmt); put(sink, ".."); formatValue(sink, i.b, fmt); put(sink, ")"); if (range.empty) return; put(sink, " "); } } /// unittest { import std.conv : to; import std.format : format; import std.uni : unicode; assert(unicode.Cyrillic.to!string == "[1024..1157) [1159..1320) [7467..7468) [7544..7545) [11744..11776) [42560..42648) [42655..42656)"); // The specs '%s' and '%d' are equivalent to the to!string call above. assert(format("%d", unicode.Cyrillic) == unicode.Cyrillic.to!string); assert(format("%#x", unicode.Cyrillic) == "[0x400..0x485) [0x487..0x528) [0x1d2b..0x1d2c) [0x1d78..0x1d79) [0x2de0..0x2e00) [0xa640..0xa698) [0xa69f..0xa6a0)"); assert(format("%#X", unicode.Cyrillic) == "[0X400..0X485) [0X487..0X528) [0X1D2B..0X1D2C) [0X1D78..0X1D79) [0X2DE0..0X2E00) [0XA640..0XA698) [0XA69F..0XA6A0)"); } unittest { import std.exception : assertThrown; import std.format : format; assertThrown!FormatException(format("%a", unicode.ASCII)); } /** Add an interval [a, b$(RPAREN) to this set. */ ref add()(uint a, uint b) { addInterval(a, b); return this; } /// unittest { CodepointSet someSet; someSet.add('0', '5').add('A','Z'+1); someSet.add('5', '9'+1); assert(someSet['0']); assert(someSet['5']); assert(someSet['9']); assert(someSet['Z']); } private: package(std) // used from: std.regex.internal.parser ref intersect(U)(U rhs) if(isCodepointSet!U) { Marker mark; foreach( i; rhs.byInterval) { mark = this.dropUpTo(i.a, mark); mark = this.skipUpTo(i.b, mark); } this.dropUpTo(uint.max, mark); return this; } ref intersect()(dchar ch) { foreach(i; byInterval) if(i.a <= ch && ch < i.b) return this = This.init.add(ch, ch+1); this = This.init; return this; } /// unittest { assert(unicode.Cyrillic.intersect('-').byInterval.empty); } ref sub()(dchar ch) { return subChar(ch); } // same as the above except that skip & drop parts are swapped package(std) // used from: std.regex.internal.parser ref sub(U)(U rhs) if(isCodepointSet!U) { uint top; Marker mark; foreach(i; rhs.byInterval) { mark = this.skipUpTo(i.a, mark); mark = this.dropUpTo(i.b, mark); } return this; } package(std) // used from: std.regex.internal.parse ref add(U)(U rhs) if(isCodepointSet!U) { Marker start; foreach(i; rhs.byInterval) { start = addInterval(i.a, i.b, start); } return this; } // end of mixin-able part //============================================================================ public: /** Obtains a set that is the inversion of this set. See the '!' $(LREF opUnary) for the same but using operators. */ @property auto inverted() { InversionList inversion = this; if(inversion.data.length == 0) { inversion.addInterval(0, lastDchar+1); return inversion; } if(inversion.data[0] != 0) genericReplace(inversion.data, 0, 0, [0]); else genericReplace(inversion.data, 0, 1, cast(uint[])null); if(data[data.length-1] != lastDchar+1) genericReplace(inversion.data, inversion.data.length, inversion.data.length, [lastDchar+1]); else genericReplace(inversion.data, inversion.data.length-1, inversion.data.length, cast(uint[])null); return inversion; } /// unittest { auto set = unicode.ASCII; // union with the inverse gets all of the code points in the Unicode assert((set | set.inverted).length == 0x110000); // no intersection with the inverse assert((set & set.inverted).empty); } /** Generates string with D source code of unary function with name of $(D funcName) taking a single $(D dchar) argument. If $(D funcName) is empty the code is adjusted to be a lambda function. The function generated tests if the $(CODEPOINT) passed belongs to this set or not. The result is to be used with string mixin. The intended usage area is aggressive optimization via meta programming in parser generators and the like. Note: Use with care for relatively small or regular sets. It could end up being slower then just using multi-staged tables. Example: --- import std.stdio; // construct set directly from [a, b$RPAREN intervals auto set = CodepointSet(10, 12, 45, 65, 100, 200); writeln(set); writeln(set.toSourceCode("func")); --- The above outputs something along the lines of: --- bool func(dchar ch) @safe pure nothrow @nogc { if(ch < 45) { if(ch == 10 || ch == 11) return true; return false; } else if (ch < 65) return true; else { if(ch < 100) return false; if(ch < 200) return true; return false; } } --- */ string toSourceCode(string funcName="") { import std.array : array; import std.format : format; import std.algorithm : countUntil; enum maxBinary = 3; static string linearScope(R)(R ivals, string indent) { string result = indent~"{\n"; string deeper = indent~" "; foreach(ival; ivals) { auto span = ival[1] - ival[0]; assert(span != 0); if(span == 1) { result ~= format("%sif(ch == %s) return true;\n", deeper, ival[0]); } else if(span == 2) { result ~= format("%sif(ch == %s || ch == %s) return true;\n", deeper, ival[0], ival[0]+1); } else { if(ival[0] != 0) // dchar is unsigned and < 0 is useless result ~= format("%sif(ch < %s) return false;\n", deeper, ival[0]); result ~= format("%sif(ch < %s) return true;\n", deeper, ival[1]); } } result ~= format("%sreturn false;\n%s}\n", deeper, indent); // including empty range of intervals return result; } static string binaryScope(R)(R ivals, string indent) { // time to do unrolled comparisons? if(ivals.length < maxBinary) return linearScope(ivals, indent); else return bisect(ivals, ivals.length/2, indent); } // not used yet if/elsebinary search is far better with DMD as of 2.061 // and GDC is doing fine job either way static string switchScope(R)(R ivals, string indent) { string result = indent~"switch(ch){\n"; string deeper = indent~" "; foreach(ival; ivals) { if(ival[0]+1 == ival[1]) { result ~= format("%scase %s: return true;\n", deeper, ival[0]); } else { result ~= format("%scase %s: .. case %s: return true;\n", deeper, ival[0], ival[1]-1); } } result ~= deeper~"default: return false;\n"~indent~"}\n"; return result; } static string bisect(R)(R range, size_t idx, string indent) { string deeper = indent ~ " "; // bisect on one [a, b) interval at idx string result = indent~"{\n"; // less branch, < a result ~= format("%sif(ch < %s)\n%s", deeper, range[idx][0], binaryScope(range[0..idx], deeper)); // middle point, >= a && < b result ~= format("%selse if (ch < %s) return true;\n", deeper, range[idx][1]); // greater or equal branch, >= b result ~= format("%selse\n%s", deeper, binaryScope(range[idx+1..$], deeper)); return result~indent~"}\n"; } string code = format("bool %s(dchar ch) @safe pure nothrow @nogc\n", funcName.empty ? "function" : funcName); auto range = byInterval.array(); // special case first bisection to be on ASCII vs beyond auto tillAscii = countUntil!"a[0] > 0x80"(range); if(tillAscii <= 0) // everything is ASCII or nothing is ascii (-1 & 0) code ~= binaryScope(range, ""); else code ~= bisect(range, tillAscii, ""); return code; } /** True if this set doesn't contain any $(CODEPOINTS). */ @property bool empty() const { return data.length == 0; } /// unittest { CodepointSet emptySet; assert(emptySet.length == 0); assert(emptySet.empty); } private: alias This = typeof(this); alias Marker = size_t; // a random-access range of integral pairs static struct Intervals(Range) { this(Range sp) { slice = sp; start = 0; end = sp.length; } this(Range sp, size_t s, size_t e) { slice = sp; start = s; end = e; } @property auto front()const { uint a = slice[start]; uint b = slice[start+1]; return CodepointInterval(a, b); } //may break sorted property - but we need std.sort to access it //hence package protection attribute package @property auto front(CodepointInterval val) { slice[start] = val.a; slice[start+1] = val.b; } @property auto back()const { uint a = slice[end-2]; uint b = slice[end-1]; return CodepointInterval(a, b); } //ditto about package package @property auto back(CodepointInterval val) { slice[end-2] = val.a; slice[end-1] = val.b; } void popFront() { start += 2; } void popBack() { end -= 2; } auto opIndex(size_t idx) const { uint a = slice[start+idx*2]; uint b = slice[start+idx*2+1]; return CodepointInterval(a, b); } //ditto about package package auto opIndexAssign(CodepointInterval val, size_t idx) { slice[start+idx*2] = val.a; slice[start+idx*2+1] = val.b; } auto opSlice(size_t s, size_t e) { return Intervals(slice, s*2+start, e*2+start); } @property size_t length()const { return slice.length/2; } @property bool empty()const { return start == end; } @property auto save(){ return this; } private: size_t start, end; Range slice; } // called after construction from intervals // to make sure invariants hold void sanitize() { import std.algorithm : sort, SwapStrategy, max; if (data.length == 0) return; alias Ival = CodepointInterval; //intervals wrapper for a _range_ over packed array auto ivals = Intervals!(typeof(data[]))(data[]); //@@@BUG@@@ can't use "a.a < b.a" see issue 12265 sort!((a,b) => a.a < b.a, SwapStrategy.stable)(ivals); // what follows is a variation on stable remove // differences: // - predicate is binary, and is tested against // the last kept element (at 'i'). // - predicate mutates lhs (merges rhs into lhs) size_t len = ivals.length; size_t i = 0; size_t j = 1; while (j < len) { if (ivals[i].b >= ivals[j].a) { ivals[i] = Ival(ivals[i].a, max(ivals[i].b, ivals[j].b)); j++; } else //unmergable { // check if there is a hole after merges // (in the best case we do 0 writes to ivals) if (j != i+1) ivals[i+1] = ivals[j]; //copy over i++; j++; } } len = i + 1; for (size_t k=0; k + 1 < len; k++) { assert(ivals[k].a < ivals[k].b); assert(ivals[k].b < ivals[k+1].a); } data.length = len * 2; } // special case for normal InversionList ref subChar(dchar ch) { auto mark = skipUpTo(ch); if(mark != data.length && data[mark] == ch && data[mark-1] == ch) { // it has split, meaning that ch happens to be in one of intervals data[mark] = data[mark]+1; } return this; } // Marker addInterval(int a, int b, Marker hint=Marker.init) in { assert(a <= b); } body { import std.range : assumeSorted, SearchPolicy; auto range = assumeSorted(data[]); size_t pos; size_t a_idx = hint + range[hint..$].lowerBound!(SearchPolicy.gallop)(a).length; if(a_idx == range.length) { // [---+++----++++----++++++] // [ a b] data.append(a, b); return data.length-1; } size_t b_idx = range[a_idx..range.length].lowerBound!(SearchPolicy.gallop)(b).length+a_idx; uint[3] buf = void; uint to_insert; debug(std_uni) { writefln("a_idx=%d; b_idx=%d;", a_idx, b_idx); } if(b_idx == range.length) { // [-------++++++++----++++++-] // [ s a b] if(a_idx & 1)// a in positive { buf[0] = b; to_insert = 1; } else// a in negative { buf[0] = a; buf[1] = b; to_insert = 2; } pos = genericReplace(data, a_idx, b_idx, buf[0..to_insert]); return pos - 1; } uint top = data[b_idx]; debug(std_uni) { writefln("a_idx=%d; b_idx=%d;", a_idx, b_idx); writefln("a=%s; b=%s; top=%s;", a, b, top); } if(a_idx & 1) {// a in positive if(b_idx & 1)// b in positive { // [-------++++++++----++++++-] // [ s a b ] buf[0] = top; to_insert = 1; } else // b in negative { // [-------++++++++----++++++-] // [ s a b ] if(top == b) { assert(b_idx+1 < data.length); buf[0] = data[b_idx+1]; pos = genericReplace(data, a_idx, b_idx+2, buf[0..1]); return pos - 1; } buf[0] = b; buf[1] = top; to_insert = 2; } } else { // a in negative if(b_idx & 1) // b in positive { // [----------+++++----++++++-] // [ a b ] buf[0] = a; buf[1] = top; to_insert = 2; } else// b in negative { // [----------+++++----++++++-] // [ a s b ] if(top == b) { assert(b_idx+1 < data.length); buf[0] = a; buf[1] = data[b_idx+1]; pos = genericReplace(data, a_idx, b_idx+2, buf[0..2]); return pos - 1; } buf[0] = a; buf[1] = b; buf[2] = top; to_insert = 3; } } pos = genericReplace(data, a_idx, b_idx+1, buf[0..to_insert]); debug(std_uni) { writefln("marker idx: %d; length=%d", pos, data[pos], data.length); writeln("inserting ", buf[0..to_insert]); } return pos - 1; } // Marker dropUpTo(uint a, Marker pos=Marker.init) in { assert(pos % 2 == 0); // at start of interval } body { auto range = assumeSorted!"a<=b"(data[pos..data.length]); if(range.empty) return pos; size_t idx = pos; idx += range.lowerBound(a).length; debug(std_uni) { writeln("dropUpTo full length=", data.length); writeln(pos,"~~~", idx); } if(idx == data.length) return genericReplace(data, pos, idx, cast(uint[])[]); if(idx & 1) { // a in positive //[--+++----++++++----+++++++------...] // |<---si s a t genericReplace(data, pos, idx, [a]); } else { // a in negative //[--+++----++++++----+++++++-------+++...] // |<---si s a t genericReplace(data, pos, idx, cast(uint[])[]); } return pos; } // Marker skipUpTo(uint a, Marker pos=Marker.init) out(result) { assert(result % 2 == 0);// always start of interval //(may be 0-width after-split) } body { assert(data.length % 2 == 0); auto range = assumeSorted!"a<=b"(data[pos..data.length]); size_t idx = pos+range.lowerBound(a).length; if(idx >= data.length) // could have Marker point to recently removed stuff return data.length; if(idx & 1)// inside of interval, check for split { uint top = data[idx]; if(top == a)// no need to split, it's end return idx+1; uint start = data[idx-1]; if(a == start) return idx-1; // split it up genericReplace(data, idx, idx+1, [a, a, top]); return idx+1; // avoid odd index } return idx; } CowArray!SP data; } @system unittest { import std.conv; assert(unicode.ASCII.to!string() == "[0..128)"); } // pedantic version for ctfe, and aligned-access only architectures @trusted uint safeRead24(const ubyte* ptr, size_t idx) pure nothrow @nogc { idx *= 3; version(LittleEndian) return ptr[idx] + (cast(uint)ptr[idx+1]<<8) + (cast(uint)ptr[idx+2]<<16); else return (cast(uint)ptr[idx]<<16) + (cast(uint)ptr[idx+1]<<8) + ptr[idx+2]; } // ditto @trusted void safeWrite24(ubyte* ptr, uint val, size_t idx) pure nothrow @nogc { idx *= 3; version(LittleEndian) { ptr[idx] = val & 0xFF; ptr[idx+1] = (val>>8) & 0xFF; ptr[idx+2] = (val>>16) & 0xFF; } else { ptr[idx] = (val>>16) & 0xFF; ptr[idx+1] = (val>>8) & 0xFF; ptr[idx+2] = val & 0xFF; } } // unaligned x86-like read/write functions @trusted uint unalignedRead24(const ubyte* ptr, size_t idx) pure nothrow @nogc { uint* src = cast(uint*)(ptr+3*idx); version(LittleEndian) return *src & 0xFF_FFFF; else return *src >> 8; } // ditto @trusted void unalignedWrite24(ubyte* ptr, uint val, size_t idx) pure nothrow @nogc { uint* dest = cast(uint*)(cast(ubyte*)ptr + 3*idx); version(LittleEndian) *dest = val | (*dest & 0xFF00_0000); else *dest = (val<<8) | (*dest & 0xFF); } uint read24(const ubyte* ptr, size_t idx) @safe pure nothrow @nogc { static if(hasUnalignedReads) return __ctfe ? safeRead24(ptr, idx) : unalignedRead24(ptr, idx); else return safeRead24(ptr, idx); } void write24(ubyte* ptr, uint val, size_t idx) @safe pure nothrow @nogc { static if(hasUnalignedReads) return __ctfe ? safeWrite24(ptr, val, idx) : unalignedWrite24(ptr, val, idx); else return safeWrite24(ptr, val, idx); } @trusted struct CowArray(SP=GcPolicy) { static auto reuse(uint[] arr) { CowArray cow; cow.data = arr; SP.append(cow.data, 1); assert(cow.refCount == 1); assert(cow.length == arr.length); return cow; } this(Range)(Range range) if(isInputRange!Range && hasLength!Range) { import std.algorithm : copy; length = range.length; copy(range, data[0..$-1]); } this(Range)(Range range) if(isForwardRange!Range && !hasLength!Range) { import std.algorithm : copy; auto len = walkLength(range.save); length = len; copy(range, data[0..$-1]); } this(this) { if(!empty) { refCount = refCount + 1; } } ~this() { if(!empty) { auto cnt = refCount; if(cnt == 1) SP.destroy(data); else refCount = cnt - 1; } } // no ref-count for empty U24 array @property bool empty() const { return data.length == 0; } // report one less then actual size @property size_t length() const { return data.length ? data.length - 1 : 0; } //+ an extra slot for ref-count @property void length(size_t len) { import std.algorithm : min, copy; if(len == 0) { if(!empty) freeThisReference(); return; } immutable total = len + 1; // including ref-count if(empty) { data = SP.alloc!uint(total); refCount = 1; return; } auto cur_cnt = refCount; if(cur_cnt != 1) // have more references to this memory { refCount = cur_cnt - 1; auto new_data = SP.alloc!uint(total); // take shrinking into account auto to_copy = min(total, data.length) - 1; copy(data[0..to_copy], new_data[0..to_copy]); data = new_data; // before setting refCount! refCount = 1; } else // 'this' is the only reference { // use the realloc (hopefully in-place operation) data = SP.realloc(data, total); refCount = 1; // setup a ref-count in the new end of the array } } alias opDollar = length; uint opIndex()(size_t idx)const { return data[idx]; } void opIndexAssign(uint val, size_t idx) { auto cnt = refCount; if(cnt != 1) dupThisReference(cnt); data[idx] = val; } // auto opSlice(size_t from, size_t to) { if(!empty) { auto cnt = refCount; if(cnt != 1) dupThisReference(cnt); } return data[from .. to]; } // auto opSlice(size_t from, size_t to) const { return data[from .. to]; } // length slices before the ref count auto opSlice() { return opSlice(0, length); } // ditto auto opSlice() const { return opSlice(0, length); } void append(Range)(Range range) if(isInputRange!Range && hasLength!Range && is(ElementType!Range : uint)) { size_t nl = length + range.length; length = nl; copy(range, this[nl-range.length..nl]); } void append()(uint[] val...) { length = length + val.length; data[$-val.length-1 .. $-1] = val[]; } bool opEquals()(auto const ref CowArray rhs)const { if(empty ^ rhs.empty) return false; // one is empty and the other isn't return empty || data[0..$-1] == rhs.data[0..$-1]; } private: // ref-count is right after the data @property uint refCount() const { return data[$-1]; } @property void refCount(uint cnt) { data[$-1] = cnt; } void freeThisReference() { auto count = refCount; if(count != 1) // have more references to this memory { // dec shared ref-count refCount = count - 1; data = []; } else SP.destroy(data); assert(!data.ptr); } void dupThisReference(uint count) in { assert(!empty && count != 1 && count == refCount); } body { import std.algorithm : copy; // dec shared ref-count refCount = count - 1; // copy to the new chunk of RAM auto new_data = SP.alloc!uint(data.length); // bit-blit old stuff except the counter copy(data[0..$-1], new_data[0..$-1]); data = new_data; // before setting refCount! refCount = 1; // so that this updates the right one } uint[] data; } @safe unittest// Uint24 tests { import std.algorithm; import std.conv; import std.range; void funcRef(T)(ref T u24) { u24.length = 2; u24[1] = 1024; T u24_c = u24; assert(u24[1] == 1024); u24.length = 0; assert(u24.empty); u24.append([1, 2]); assert(equalS(u24[], [1, 2])); u24.append(111); assert(equalS(u24[], [1, 2, 111])); assert(!u24_c.empty && u24_c[1] == 1024); u24.length = 3; copy(iota(0, 3), u24[]); assert(equalS(u24[], iota(0, 3))); assert(u24_c[1] == 1024); } void func2(T)(T u24) { T u24_2 = u24; T u24_3; u24_3 = u24_2; assert(u24_2 == u24_3); assert(equalS(u24[], u24_2[])); assert(equalS(u24_2[], u24_3[])); funcRef(u24_3); assert(equalS(u24_3[], iota(0, 3))); assert(!equalS(u24_2[], u24_3[])); assert(equalS(u24_2[], u24[])); u24_2 = u24_3; assert(equalS(u24_2[], iota(0, 3))); // to test that passed arg is intact outside // plus try out opEquals u24 = u24_3; u24 = T.init; u24_3 = T.init; assert(u24.empty); assert(u24 == u24_3); assert(u24 != u24_2); } foreach(Policy; AliasSeq!(GcPolicy, ReallocPolicy)) { alias Range = typeof(CowArray!Policy.init[]); alias U24A = CowArray!Policy; static assert(isForwardRange!Range); static assert(isBidirectionalRange!Range); static assert(isOutputRange!(Range, uint)); static assert(isRandomAccessRange!(Range)); auto arr = U24A([42u, 36, 100]); assert(arr[0] == 42); assert(arr[1] == 36); arr[0] = 72; arr[1] = 0xFE_FEFE; assert(arr[0] == 72); assert(arr[1] == 0xFE_FEFE); assert(arr[2] == 100); U24A arr2 = arr; assert(arr2[0] == 72); arr2[0] = 11; // test COW-ness assert(arr[0] == 72); assert(arr2[0] == 11); // set this to about 100M to stress-test COW memory management foreach(v; 0..10_000) func2(arr); assert(equalS(arr[], [72, 0xFE_FEFE, 100])); auto r2 = U24A(iota(0, 100)); assert(equalS(r2[], iota(0, 100)), text(r2[])); copy(iota(10, 170, 2), r2[10..90]); assert(equalS(r2[], chain(iota(0, 10), iota(10, 170, 2), iota(90, 100))) , text(r2[])); } } version(unittest) { private alias AllSets = AliasSeq!(InversionList!GcPolicy, InversionList!ReallocPolicy); } @safe unittest// core set primitives test { import std.conv; foreach(CodeList; AllSets) { CodeList a; //"plug a hole" test a.add(10, 20).add(25, 30).add(15, 27); assert(a == CodeList(10, 30), text(a)); auto x = CodeList.init; x.add(10, 20).add(30, 40).add(50, 60); a = x; a.add(20, 49);//[10, 49) [50, 60) assert(a == CodeList(10, 49, 50 ,60)); a = x; a.add(20, 50); assert(a == CodeList(10, 60), text(a)); // simple unions, mostly edge effects x = CodeList.init; x.add(10, 20).add(40, 60); a = x; a.add(10, 25); //[10, 25) [40, 60) assert(a == CodeList(10, 25, 40, 60)); a = x; a.add(5, 15); //[5, 20) [40, 60) assert(a == CodeList(5, 20, 40, 60)); a = x; a.add(0, 10); // [0, 20) [40, 60) assert(a == CodeList(0, 20, 40, 60)); a = x; a.add(0, 5); // prepand assert(a == CodeList(0, 5, 10, 20, 40, 60), text(a)); a = x; a.add(5, 20); assert(a == CodeList(5, 20, 40, 60)); a = x; a.add(3, 37); assert(a == CodeList(3, 37, 40, 60)); a = x; a.add(37, 65); assert(a == CodeList(10, 20, 37, 65)); // some tests on helpers for set intersection x = CodeList.init.add(10, 20).add(40, 60).add(100, 120); a = x; auto m = a.skipUpTo(60); a.dropUpTo(110, m); assert(a == CodeList(10, 20, 40, 60, 110, 120), text(a.data[])); a = x; a.dropUpTo(100); assert(a == CodeList(100, 120), text(a.data[])); a = x; m = a.skipUpTo(50); a.dropUpTo(140, m); assert(a == CodeList(10, 20, 40, 50), text(a.data[])); a = x; a.dropUpTo(60); assert(a == CodeList(100, 120), text(a.data[])); } } //test constructor to work with any order of intervals @safe unittest { import std.conv, std.range, std.algorithm; import std.typecons; //ensure constructor handles bad ordering and overlap auto c1 = CodepointSet('а', 'я'+1, 'А','Я'+1); foreach(ch; chain(iota('а', 'я'+1), iota('А','Я'+1))) assert(ch in c1, to!string(ch)); //contiguos assert(CodepointSet(1000, 1006, 1006, 1009) .byInterval.equal([tuple(1000, 1009)])); //contains assert(CodepointSet(900, 1200, 1000, 1100) .byInterval.equal([tuple(900, 1200)])); //intersect left assert(CodepointSet(900, 1100, 1000, 1200) .byInterval.equal([tuple(900, 1200)])); //intersect right assert(CodepointSet(1000, 1200, 900, 1100) .byInterval.equal([tuple(900, 1200)])); //ditto with extra items at end assert(CodepointSet(1000, 1200, 900, 1100, 800, 850) .byInterval.equal([tuple(800, 850), tuple(900, 1200)])); assert(CodepointSet(900, 1100, 1000, 1200, 800, 850) .byInterval.equal([tuple(800, 850), tuple(900, 1200)])); //"plug a hole" test auto c2 = CodepointSet(20, 40, 60, 80, 100, 140, 150, 200, 40, 60, 80, 100, 140, 150 ); assert(c2.byInterval.equal([tuple(20, 200)])); auto c3 = CodepointSet( 20, 40, 60, 80, 100, 140, 150, 200, 0, 10, 15, 100, 10, 20, 200, 220); assert(c3.byInterval.equal([tuple(0, 140), tuple(150, 220)])); } @safe unittest { // full set operations import std.conv; foreach(CodeList; AllSets) { CodeList a, b, c, d; //"plug a hole" a.add(20, 40).add(60, 80).add(100, 140).add(150, 200); b.add(40, 60).add(80, 100).add(140, 150); c = a | b; d = b | a; assert(c == CodeList(20, 200), text(CodeList.stringof," ", c)); assert(c == d, text(c," vs ", d)); b = CodeList.init.add(25, 45).add(65, 85).add(95,110).add(150, 210); c = a | b; //[20,45) [60, 85) [95, 140) [150, 210) d = b | a; assert(c == CodeList(20, 45, 60, 85, 95, 140, 150, 210), text(c)); assert(c == d, text(c," vs ", d)); b = CodeList.init.add(10, 20).add(30,100).add(145,200); c = a | b;//[10, 140) [145, 200) d = b | a; assert(c == CodeList(10, 140, 145, 200)); assert(c == d, text(c," vs ", d)); b = CodeList.init.add(0, 10).add(15, 100).add(10, 20).add(200, 220); c = a | b;//[0, 140) [150, 220) d = b | a; assert(c == CodeList(0, 140, 150, 220)); assert(c == d, text(c," vs ", d)); a = CodeList.init.add(20, 40).add(60, 80); b = CodeList.init.add(25, 35).add(65, 75); c = a & b; d = b & a; assert(c == CodeList(25, 35, 65, 75), text(c)); assert(c == d, text(c," vs ", d)); a = CodeList.init.add(20, 40).add(60, 80).add(100, 140).add(150, 200); b = CodeList.init.add(25, 35).add(65, 75).add(110, 130).add(160, 180); c = a & b; d = b & a; assert(c == CodeList(25, 35, 65, 75, 110, 130, 160, 180), text(c)); assert(c == d, text(c," vs ", d)); a = CodeList.init.add(20, 40).add(60, 80).add(100, 140).add(150, 200); b = CodeList.init.add(10, 30).add(60, 120).add(135, 160); c = a & b;//[20, 30)[60, 80) [100, 120) [135, 140) [150, 160) d = b & a; assert(c == CodeList(20, 30, 60, 80, 100, 120, 135, 140, 150, 160),text(c)); assert(c == d, text(c, " vs ",d)); assert((c & a) == c); assert((d & b) == d); assert((c & d) == d); b = CodeList.init.add(40, 60).add(80, 100).add(140, 200); c = a & b; d = b & a; assert(c == CodeList(150, 200), text(c)); assert(c == d, text(c, " vs ",d)); assert((c & a) == c); assert((d & b) == d); assert((c & d) == d); assert((a & a) == a); assert((b & b) == b); a = CodeList.init.add(20, 40).add(60, 80).add(100, 140).add(150, 200); b = CodeList.init.add(30, 60).add(75, 120).add(190, 300); c = a - b;// [30, 40) [60, 75) [120, 140) [150, 190) d = b - a;// [40, 60) [80, 100) [200, 300) assert(c == CodeList(20, 30, 60, 75, 120, 140, 150, 190), text(c)); assert(d == CodeList(40, 60, 80, 100, 200, 300), text(d)); assert(c - d == c, text(c-d, " vs ", c)); assert(d - c == d, text(d-c, " vs ", d)); assert(c - c == CodeList.init); assert(d - d == CodeList.init); a = CodeList.init.add(20, 40).add( 60, 80).add(100, 140).add(150, 200); b = CodeList.init.add(10, 50).add(60, 160).add(190, 300); c = a - b;// [160, 190) d = b - a;// [10, 20) [40, 50) [80, 100) [140, 150) [200, 300) assert(c == CodeList(160, 190), text(c)); assert(d == CodeList(10, 20, 40, 50, 80, 100, 140, 150, 200, 300), text(d)); assert(c - d == c, text(c-d, " vs ", c)); assert(d - c == d, text(d-c, " vs ", d)); assert(c - c == CodeList.init); assert(d - d == CodeList.init); a = CodeList.init.add(20, 40).add(60, 80).add(100, 140).add(150, 200); b = CodeList.init.add(10, 30).add(45, 100).add(130, 190); c = a ~ b; // [10, 20) [30, 40) [45, 60) [80, 130) [140, 150) [190, 200) d = b ~ a; assert(c == CodeList(10, 20, 30, 40, 45, 60, 80, 130, 140, 150, 190, 200), text(c)); assert(c == d, text(c, " vs ", d)); } } } @safe unittest// vs single dchar { import std.conv; CodepointSet a = CodepointSet(10, 100, 120, 200); assert(a - 'A' == CodepointSet(10, 65, 66, 100, 120, 200), text(a - 'A')); assert((a & 'B') == CodepointSet(66, 67)); } @safe unittest// iteration & opIndex { import std.conv; import std.typecons; foreach(CodeList; AliasSeq!(InversionList!(ReallocPolicy))) { auto arr = "ABCDEFGHIJKLMabcdefghijklm"d; auto a = CodeList('A','N','a', 'n'); assert(equalS(a.byInterval, [tuple(cast(uint)'A', cast(uint)'N'), tuple(cast(uint)'a', cast(uint)'n')] ), text(a.byInterval)); // same @@@BUG as in issue 8949 ? version(bug8949) { assert(equalS(retro(a.byInterval), [tuple(cast(uint)'a', cast(uint)'n'), tuple(cast(uint)'A', cast(uint)'N')] ), text(retro(a.byInterval))); } auto achr = a.byCodepoint; assert(equalS(achr, arr), text(a.byCodepoint)); foreach(ch; a.byCodepoint) assert(a[ch]); auto x = CodeList(100, 500, 600, 900, 1200, 1500); assert(equalS(x.byInterval, [ tuple(100, 500), tuple(600, 900), tuple(1200, 1500)]), text(x.byInterval)); foreach(ch; x.byCodepoint) assert(x[ch]); static if(is(CodeList == CodepointSet)) { auto y = CodeList(x.byInterval); assert(equalS(x.byInterval, y.byInterval)); } assert(equalS(CodepointSet.init.byInterval, cast(Tuple!(uint, uint)[])[])); assert(equalS(CodepointSet.init.byCodepoint, cast(dchar[])[])); } } //============================================================================ // Generic Trie template and various ways to build it //============================================================================ // debug helper to get a shortened array dump auto arrayRepr(T)(T x) { import std.conv : text; if(x.length > 32) { return text(x[0..16],"~...~", x[x.length-16..x.length]); } else return text(x); } /** Maps $(D Key) to a suitable integer index within the range of $(D size_t). The mapping is constructed by applying predicates from $(D Prefix) left to right and concatenating the resulting bits. The first (leftmost) predicate defines the most significant bits of the resulting index. */ template mapTrieIndex(Prefix...) { size_t mapTrieIndex(Key)(Key key) if(isValidPrefixForTrie!(Key, Prefix)) { alias p = Prefix; size_t idx; foreach(i, v; p[0..$-1]) { idx |= p[i](key); idx <<= p[i+1].bitSize; } idx |= p[$-1](key); return idx; } } /* $(D TrieBuilder) is a type used for incremental construction of $(LREF Trie)s. See $(LREF buildTrie) for generic helpers built on top of it. */ @trusted struct TrieBuilder(Value, Key, Args...) if(isBitPackableType!Value && isValidArgsForTrie!(Key, Args)) { import std.exception : enforce; private: // last index is not stored in table, it is used as an offset to values in a block. static if(is(Value == bool))// always pack bool alias V = BitPacked!(Value, 1); else alias V = Value; static auto deduceMaxIndex(Preds...)() { size_t idx = 1; foreach(v; Preds) idx *= 2^^v.bitSize; return idx; } static if(is(typeof(Args[0]) : Key)) // Args start with upper bound on Key { alias Prefix = Args[1..$]; enum lastPageSize = 2^^Prefix[$-1].bitSize; enum translatedMaxIndex = mapTrieIndex!(Prefix)(Args[0]); enum roughedMaxIndex = (translatedMaxIndex + lastPageSize-1)/lastPageSize*lastPageSize; // check warp around - if wrapped, use the default deduction rule enum maxIndex = roughedMaxIndex < translatedMaxIndex ? deduceMaxIndex!(Prefix)() : roughedMaxIndex; } else { alias Prefix = Args; enum maxIndex = deduceMaxIndex!(Prefix)(); } alias getIndex = mapTrieIndex!(Prefix); enum lastLevel = Prefix.length-1; struct ConstructState { size_t idx_zeros, idx_ones; } // iteration over levels of Trie, each indexes its own level and thus a shortened domain size_t[Prefix.length] indices; // default filler value to use Value defValue; // this is a full-width index of next item size_t curIndex; // all-zeros page index, all-ones page index (+ indicator if there is such a page) ConstructState[Prefix.length] state; // the table being constructed MultiArray!(idxTypes!(Key, fullBitSize!(Prefix), Prefix[0..$]), V) table; @disable this(); //shortcut for index variable at level 'level' @property ref idx(size_t level)(){ return indices[level]; } // this function assumes no holes in the input so // indices are going one by one void addValue(size_t level, T)(T val, size_t numVals) { alias j = idx!level; enum pageSize = 1<= pageSize) { numVals -= pageSize; ptr[j..j+pageSize] = val; j += pageSize; spillToNextPage!level(ptr); } } if(numVals) { // the leftovers, an incomplete page ptr[j..j+numVals] = val; j += numVals; } } } void spillToNextPage(size_t level, Slice)(ref Slice ptr) { // last level (i.e. topmost) has 1 "page" // thus it need not to add a new page on upper level static if(level != 0) spillToNextPageImpl!(level)(ptr); } // this can re-use the current page if duplicate or allocate a new one // it also makes sure that previous levels point to the correct page in this level void spillToNextPageImpl(size_t level, Slice)(ref Slice ptr) { alias NextIdx = typeof(table.slice!(level-1)[0]); NextIdx next_lvl_index; enum pageSize = 1< [%s..%s]" ,level ,indices[level-1], pageSize, j, j+pageSize); writeln("LEVEL(", level , ") mapped page is: ", slice, ": ", arrayRepr(ptr[j..j+pageSize])); writeln("LEVEL(", level , ") src page is :", ptr, ": ", arrayRepr(slice[0..pageSize])); } idx!level -= pageSize; // reuse this page, it is duplicate break; } } if(j == last) { L_allocate_page: next_lvl_index = force!NextIdx(idx!level/pageSize - 1); if(state[level].idx_zeros == size_t.max && ptr.zeros(j, j+pageSize)) { state[level].idx_zeros = next_lvl_index; } // allocate next page version(none) { writefln("LEVEL(%s) page allocated: %s" , level, arrayRepr(slice[0..pageSize])); writefln("LEVEL(%s) index: %s ; page at this index %s" , level , next_lvl_index , arrayRepr( table.slice!(level) [pageSize*next_lvl_index..(next_lvl_index+1)*pageSize] )); } table.length!level = table.length!level + pageSize; } L_know_index: // for the previous level, values are indices to the pages in the current level addValue!(level-1)(next_lvl_index, 1); ptr = table.slice!level; //re-load the slice after moves } // idx - full-width index to fill with v (full-width index != key) // fills everything in the range of [curIndex, idx) with filler void putAt(size_t idx, Value v) { assert(idx >= curIndex); size_t numFillers = idx - curIndex; addValue!lastLevel(defValue, numFillers); addValue!lastLevel(v, 1); curIndex = idx + 1; } // ditto, but sets the range of [idxA, idxB) to v void putRangeAt(size_t idxA, size_t idxB, Value v) { assert(idxA >= curIndex); assert(idxB >= idxA); size_t numFillers = idxA - curIndex; addValue!lastLevel(defValue, numFillers); addValue!lastLevel(v, idxB - idxA); curIndex = idxB; // open-right } enum errMsg = "non-monotonic prefix function(s), an unsorted range or "~ "duplicate key->value mapping"; public: /** Construct a builder, where $(D filler) is a value to indicate empty slots (or "not found" condition). */ this(Value filler) { curIndex = 0; defValue = filler; // zeros-page index, ones-page index foreach(ref v; state) v = ConstructState(size_t.max, size_t.max); table = typeof(table)(indices); // one page per level is a bootstrap minimum foreach(i, Pred; Prefix) table.length!i = (1<= idxA && idxA >= curIndex, errMsg); putRangeAt(idxA, idxB, v); } /** Put a value $(D v) into slot mapped by $(D key). All slots prior to $(D key) are filled with the default filler. */ void putValue(Key key, Value v) { import std.conv : text; auto idx = getIndex(key); enforce(idx >= curIndex, text(errMsg, " ", idx)); putAt(idx, v); } /// Finishes construction of Trie, yielding an immutable Trie instance. auto build() { static if(maxIndex != 0) // doesn't cover full range of size_t { assert(curIndex <= maxIndex); addValue!lastLevel(defValue, maxIndex - curIndex); } else { if(curIndex != 0 // couldn't wrap around || (Prefix.length != 1 && indices[lastLevel] == 0)) // can be just empty { addValue!lastLevel(defValue, size_t.max - curIndex); addValue!lastLevel(defValue, 1); } // else curIndex already completed the full range of size_t by wrapping around } return Trie!(V, Key, maxIndex, Prefix)(table); } } /* $(P A generic Trie data-structure for a fixed number of stages. The design goal is optimal speed with smallest footprint size. ) $(P It's intentionally read-only and doesn't provide constructors. To construct one use a special builder, see $(LREF TrieBuilder) and $(LREF buildTrie). ) */ @trusted public struct Trie(Value, Key, Args...) if(isValidPrefixForTrie!(Key, Args) || (isValidPrefixForTrie!(Key, Args[1..$]) && is(typeof(Args[0]) : size_t))) { static if(is(typeof(Args[0]) : size_t)) { enum maxIndex = Args[0]; enum hasBoundsCheck = true; alias Prefix = Args[1..$]; } else { enum hasBoundsCheck = false; alias Prefix = Args; } private this()(typeof(_table) table) { _table = table; } // only for constant Tries constructed from precompiled tables private this()(const(size_t)[] offsets, const(size_t)[] sizes, const(size_t)[] data) const { _table = typeof(_table)(offsets, sizes, data); } /* $(P Lookup the $(D key) in this $(D Trie). ) $(P The lookup always succeeds if key fits the domain provided during construction. The whole domain defined is covered so instead of not found condition the sentinel (filler) value could be used. ) $(P See $(LREF buildTrie), $(LREF TrieBuilder) for how to define a domain of $(D Trie) keys and the sentinel value. ) Note: Domain range-checking is only enabled in debug builds and results in assertion failure. */ // templated to auto-detect pure, @safe and nothrow TypeOfBitPacked!Value opIndex()(Key key) const { static if(hasBoundsCheck) assert(mapTrieIndex!Prefix(key) < maxIndex); size_t idx; alias p = Prefix; idx = cast(size_t)p[0](key); foreach(i, v; p[0..$-1]) idx = cast(size_t)((_table.ptr!i[idx]< 0) alias GetBitSlicing = AliasSeq!(sliceBits!(top - sizes[0], top), GetBitSlicing!(top - sizes[0], sizes[1..$])); else alias GetBitSlicing = AliasSeq!(); } template callableWith(T) { template callableWith(alias Pred) { static if(!is(typeof(Pred(T.init)))) enum callableWith = false; else { alias Result = typeof(Pred(T.init)); enum callableWith = isBitPackableType!(TypeOfBitPacked!(Result)); } } } /* Check if $(D Prefix) is a valid set of predicates for $(D Trie) template having $(D Key) as the type of keys. This requires all predicates to be callable, take single argument of type $(D Key) and return unsigned value. */ template isValidPrefixForTrie(Key, Prefix...) { enum isValidPrefixForTrie = allSatisfy!(callableWith!Key, Prefix); // TODO: tighten the screws } /* Check if $(D Args) is a set of maximum key value followed by valid predicates for $(D Trie) template having $(D Key) as the type of keys. */ template isValidArgsForTrie(Key, Args...) { static if(Args.length > 1) { enum isValidArgsForTrie = isValidPrefixForTrie!(Key, Args) || (isValidPrefixForTrie!(Key, Args[1..$]) && is(typeof(Args[0]) : Key)); } else enum isValidArgsForTrie = isValidPrefixForTrie!Args; } @property size_t sumOfIntegerTuple(ints...)() { size_t count=0; foreach(v; ints) count += v; return count; } /** A shorthand for creating a custom multi-level fixed Trie from a $(D CodepointSet). $(D sizes) are numbers of bits per level, with the most significant bits used first. Note: The sum of $(D sizes) must be equal 21. See_Also: $(LREF toTrie), which is even simpler. Example: --- { import std.stdio; auto set = unicode("Number"); auto trie = codepointSetTrie!(8, 5, 8)(set); writeln("Input code points to test:"); foreach(line; stdin.byLine) { int count=0; foreach(dchar ch; line) if(trie[ch])// is number count++; writefln("Contains %d number code points.", count); } } --- */ public template codepointSetTrie(sizes...) if(sumOfIntegerTuple!sizes == 21) { auto codepointSetTrie(Set)(Set set) if(isCodepointSet!Set) { auto builder = TrieBuilder!(bool, dchar, lastDchar+1, GetBitSlicing!(21, sizes))(false); foreach(ival; set.byInterval) builder.putRange(ival[0], ival[1], true); return builder.build(); } } /// Type of Trie generated by codepointSetTrie function. public template CodepointSetTrie(sizes...) if(sumOfIntegerTuple!sizes == 21) { alias Prefix = GetBitSlicing!(21, sizes); alias CodepointSetTrie = typeof(TrieBuilder!(bool, dchar, lastDchar+1, Prefix)(false).build()); } /** A slightly more general tool for building fixed $(D Trie) for the Unicode data. Specifically unlike $(D codepointSetTrie) it's allows creating mappings of $(D dchar) to an arbitrary type $(D T). Note: Overload taking $(D CodepointSet)s will naturally convert only to bool mapping $(D Trie)s. */ public template codepointTrie(T, sizes...) if(sumOfIntegerTuple!sizes == 21) { alias Prefix = GetBitSlicing!(21, sizes); static if(is(TypeOfBitPacked!T == bool)) { auto codepointTrie(Set)(in Set set) if(isCodepointSet!Set) { return codepointSetTrie(set); } } auto codepointTrie()(T[dchar] map, T defValue=T.init) { return buildTrie!(T, dchar, Prefix)(map, defValue); } // unsorted range of pairs auto codepointTrie(R)(R range, T defValue=T.init) if(isInputRange!R && is(typeof(ElementType!R.init[0]) : T) && is(typeof(ElementType!R.init[1]) : dchar)) { // build from unsorted array of pairs // TODO: expose index sorting functions for Trie return buildTrie!(T, dchar, Prefix)(range, defValue, true); } } /// pure unittest { import std.algorithm.comparison : max; import std.algorithm.searching : count; // pick characters from the Greek script auto set = unicode.Greek; // a user-defined property (or an expensive function) // that we want to look up static uint luckFactor(dchar ch) { // here we consider a character lucky // if its code point has a lot of identical hex-digits // e.g. arabic letter DDAL (\u0688) has a "luck factor" of 2 ubyte[6] nibbles; // 6 4-bit chunks of code point uint value = ch; foreach(i; 0..6) { nibbles[i] = value & 0xF; value >>= 4; } uint luck; foreach(n; nibbles) luck = cast(uint)max(luck, count(nibbles[], n)); return luck; } // only unsigned built-ins are supported at the moment alias LuckFactor = BitPacked!(uint, 3); // create a temporary associative array (AA) LuckFactor[dchar] map; foreach(ch; set.byCodepoint) map[ch] = LuckFactor(luckFactor(ch)); // bits per stage are chosen randomly, fell free to optimize auto trie = codepointTrie!(LuckFactor, 8, 5, 8)(map); // from now on the AA is not needed foreach(ch; set.byCodepoint) assert(trie[ch] == luckFactor(ch)); // verify // CJK is not Greek, thus it has the default value assert(trie['\u4444'] == 0); // and here is a couple of quite lucky Greek characters: // Greek small letter epsilon with dasia assert(trie['\u1F11'] == 3); // Ancient Greek metretes sign assert(trie['\U00010181'] == 3); } /// Type of Trie as generated by codepointTrie function. public template CodepointTrie(T, sizes...) if(sumOfIntegerTuple!sizes == 21) { alias Prefix = GetBitSlicing!(21, sizes); alias CodepointTrie = typeof(TrieBuilder!(T, dchar, lastDchar+1, Prefix)(T.init).build()); } // @@@BUG multiSort can's access private symbols from uni public template cmpK0(alias Pred) { import std.typecons; static bool cmpK0(Value, Key) (Tuple!(Value, Key) a, Tuple!(Value, Key) b) { return Pred(a[1]) < Pred(b[1]); } } /* The most general utility for construction of $(D Trie)s short of using $(D TrieBuilder) directly. Provides a number of convenience overloads. $(D Args) is tuple of maximum key value followed by predicates to construct index from key. Alternatively if the first argument is not a value convertible to $(D Key) then the whole tuple of $(D Args) is treated as predicates and the maximum Key is deduced from predicates. */ public template buildTrie(Value, Key, Args...) if(isValidArgsForTrie!(Key, Args)) { static if(is(typeof(Args[0]) : Key)) // prefix starts with upper bound on Key { alias Prefix = Args[1..$]; } else alias Prefix = Args; alias getIndex = mapTrieIndex!(Prefix); // for multi-sort template GetComparators(size_t n) { static if(n > 0) alias GetComparators = AliasSeq!(GetComparators!(n-1), cmpK0!(Prefix[n-1])); else alias GetComparators = AliasSeq!(); } /* Build $(D Trie) from a range of a Key-Value pairs, assuming it is sorted by Key as defined by the following lambda: ------ (a, b) => mapTrieIndex!(Prefix)(a) < mapTrieIndex!(Prefix)(b) ------ Exception is thrown if it's detected that the above order doesn't hold. In other words $(LREF mapTrieIndex) should be a monotonically increasing function that maps $(D Key) to an integer. See_Also: $(XREF _algorithm, sort), $(XREF _range, SortedRange), $(XREF _algorithm, setUnion). */ auto buildTrie(Range)(Range range, Value filler=Value.init) if(isInputRange!Range && is(typeof(Range.init.front[0]) : Value) && is(typeof(Range.init.front[1]) : Key)) { auto builder = TrieBuilder!(Value, Key, Prefix)(filler); foreach(v; range) builder.putValue(v[1], v[0]); return builder.build(); } /* If $(D Value) is bool (or BitPacked!(bool, x)) then it's possible to build $(D Trie) from a range of open-right intervals of $(D Key)s. The requirement on the ordering of keys (and the behavior on the violation of it) is the same as for Key-Value range overload. Intervals denote ranges of !$(D filler) i.e. the opposite of filler. If no filler provided keys inside of the intervals map to true, and $(D filler) is false. */ auto buildTrie(Range)(Range range, Value filler=Value.init) if(is(TypeOfBitPacked!Value == bool) && isInputRange!Range && is(typeof(Range.init.front[0]) : Key) && is(typeof(Range.init.front[1]) : Key)) { auto builder = TrieBuilder!(Value, Key, Prefix)(filler); foreach(ival; range) builder.putRange(ival[0], ival[1], !filler); return builder.build(); } auto buildTrie(Range)(Range range, Value filler, bool unsorted) if(isInputRange!Range && is(typeof(Range.init.front[0]) : Value) && is(typeof(Range.init.front[1]) : Key)) { import std.algorithm : multiSort; alias Comps = GetComparators!(Prefix.length); if(unsorted) multiSort!(Comps)(range); return buildTrie(range, filler); } /* If $(D Value) is bool (or BitPacked!(bool, x)) then it's possible to build $(D Trie) simply from an input range of $(D Key)s. The requirement on the ordering of keys (and the behavior on the violation of it) is the same as for Key-Value range overload. Keys found in range denote !$(D filler) i.e. the opposite of filler. If no filler provided keys map to true, and $(D filler) is false. */ auto buildTrie(Range)(Range range, Value filler=Value.init) if(is(TypeOfBitPacked!Value == bool) && isInputRange!Range && is(typeof(Range.init.front) : Key)) { auto builder = TrieBuilder!(Value, Key, Prefix)(filler); foreach(v; range) builder.putValue(v, !filler); return builder.build(); } /* If $(D Key) is unsigned integer $(D Trie) could be constructed from array of values where array index serves as key. */ auto buildTrie()(Value[] array, Value filler=Value.init) if(isUnsigned!Key) { auto builder = TrieBuilder!(Value, Key, Prefix)(filler); foreach(idx, v; array) builder.putValue(idx, v); return builder.build(); } /* Builds $(D Trie) from associative array. */ auto buildTrie(Key, Value)(Value[Key] map, Value filler=Value.init) { import std.range : zip, array; auto range = array(zip(map.values, map.keys)); return buildTrie(range, filler, true); // sort it } } // helper in place of assumeSize to //reduce mangled name & help DMD inline Trie functors struct clamp(size_t bits) { static size_t opCall(T)(T arg){ return arg; } enum bitSize = bits; } struct clampIdx(size_t idx, size_t bits) { static size_t opCall(T)(T arg){ return arg[idx]; } enum bitSize = bits; } /** Conceptual type that outlines the common properties of all UTF Matchers. Note: For illustration purposes only, every method call results in assertion failure. Use $(LREF utfMatcher) to obtain a concrete matcher for UTF-8 or UTF-16 encodings. */ public struct MatcherConcept { /** $(P Perform a semantic equivalent 2 operations: decoding a $(CODEPOINT) at front of $(D inp) and testing if it belongs to the set of $(CODEPOINTS) of this matcher. ) $(P The effect on $(D inp) depends on the kind of function called:) $(P Match. If the codepoint is found in the set then range $(D inp) is advanced by its size in $(S_LINK Code unit, code units), otherwise the range is not modifed.) $(P Skip. The range is always advanced by the size of the tested $(CODEPOINT) regardless of the result of test.) $(P Test. The range is left unaffected regardless of the result of test.) */ public bool match(Range)(ref Range inp) if(isRandomAccessRange!Range && is(ElementType!Range : char)) { assert(false); } ///ditto public bool skip(Range)(ref Range inp) if(isRandomAccessRange!Range && is(ElementType!Range : char)) { assert(false); } ///ditto public bool test(Range)(ref Range inp) if(isRandomAccessRange!Range && is(ElementType!Range : char)) { assert(false); } /// @safe unittest { string truth = "2² = 4"; auto m = utfMatcher!char(unicode.Number); assert(m.match(truth)); // '2' is a number all right assert(truth == "² = 4"); // skips on match assert(m.match(truth)); // so is the superscript '2' assert(!m.match(truth)); // space is not a number assert(truth == " = 4"); // unaffected on no match assert(!m.skip(truth)); // same test ... assert(truth == "= 4"); // but skips a codepoint regardless assert(!m.test(truth)); // '=' is not a number assert(truth == "= 4"); // test never affects argument } /* Advanced feature - provide direct access to a subset of matcher based a set of known encoding lengths. Lengths are provided in $(S_LINK Code unit, code units). The sub-matcher then may do less operations per any $(D test)/$(D match). Use with care as the sub-matcher won't match any $(CODEPOINTS) that have encoded length that doesn't belong to the selected set of lengths. Also the sub-matcher object references the parent matcher and must not be used past the liftetime of the latter. Another caveat of using sub-matcher is that skip is not available preciesly because sub-matcher doesn't detect all lengths. */ @property auto subMatcher(Lengths...)() { assert(0); return this; } /// @safe unittest { auto m = utfMatcher!char(unicode.Number); string square = "2²"; // about sub-matchers assert(!m.subMatcher!(2,3,4).test(square)); // ASCII no covered assert(m.subMatcher!1.match(square)); // ASCII-only, works assert(!m.subMatcher!1.test(square)); // unicode '²' assert(m.subMatcher!(2,3,4).match(square)); // assert(square == ""); wstring wsquare = "2²"; auto m16 = utfMatcher!wchar(unicode.Number); // may keep ref, but the orignal (m16) must be kept alive auto bmp = m16.subMatcher!1; assert(bmp.match(wsquare)); // Okay, in basic multilingual plan assert(bmp.match(wsquare)); // And '²' too } } /** Test if $(D M) is an UTF Matcher for ranges of $(D Char). */ public enum isUtfMatcher(M, C) = __traits(compiles, (){ C[] s; auto d = s.decoder; M m; assert(is(typeof(m.match(d)) == bool)); assert(is(typeof(m.test(d)) == bool)); static if(is(typeof(m.skip(d)))) { assert(is(typeof(m.skip(d)) == bool)); assert(is(typeof(m.skip(s)) == bool)); } assert(is(typeof(m.match(s)) == bool)); assert(is(typeof(m.test(s)) == bool)); }); unittest { alias CharMatcher = typeof(utfMatcher!char(CodepointSet.init)); alias WcharMatcher = typeof(utfMatcher!wchar(CodepointSet.init)); static assert(isUtfMatcher!(CharMatcher, char)); static assert(isUtfMatcher!(CharMatcher, immutable(char))); static assert(isUtfMatcher!(WcharMatcher, wchar)); static assert(isUtfMatcher!(WcharMatcher, immutable(wchar))); } enum Mode { alwaysSkip, neverSkip, skipOnMatch } mixin template ForwardStrings() { private bool fwdStr(string fn, C)(ref C[] str) const pure { alias type = typeof(units(str)); return mixin(fn~"(*cast(type*)&str)"); } } template Utf8Matcher() { enum validSize(int sz) = sz >= 1 && sz <=4; void badEncoding() pure @safe { import std.utf; throw new UTFException("Invalid UTF-8 sequence"); } //for 1-stage ASCII alias AsciiSpec = AliasSeq!(bool, char, clamp!7); //for 2-stage lookup of 2 byte UTF-8 sequences alias Utf8Spec2 = AliasSeq!(bool, char[2], clampIdx!(0, 5), clampIdx!(1, 6)); //ditto for 3 byte alias Utf8Spec3 = AliasSeq!(bool, char[3], clampIdx!(0, 4), clampIdx!(1, 6), clampIdx!(2, 6) ); //ditto for 4 byte alias Utf8Spec4 = AliasSeq!(bool, char[4], clampIdx!(0, 3), clampIdx!(1, 6), clampIdx!(2, 6), clampIdx!(3, 6) ); alias Tables = AliasSeq!( typeof(TrieBuilder!(AsciiSpec)(false).build()), typeof(TrieBuilder!(Utf8Spec2)(false).build()), typeof(TrieBuilder!(Utf8Spec3)(false).build()), typeof(TrieBuilder!(Utf8Spec4)(false).build()) ); alias Table(int size) = Tables[size-1]; enum leadMask(size_t size) = (cast(size_t)1<<(7 - size))-1; enum encMask(size_t size) = ((1< 1) { import std.utf : encode; char[4] buf; std.utf.encode(buf, ch); char[sz] ret; buf[0] &= leadMask!sz; foreach(n; 1..sz) buf[n] = buf[n] & 0x3f; //keep 6 lower bits ret[] = buf[0..sz]; return ret; } auto build(Set)(Set set) { import std.algorithm : map; auto ascii = set & unicode.ASCII; auto utf8_2 = set & CodepointSet(0x80, 0x800); auto utf8_3 = set & CodepointSet(0x800, 0x1_0000); auto utf8_4 = set & CodepointSet(0x1_0000, lastDchar+1); auto asciiT = ascii.byCodepoint.map!(x=>cast(char)x).buildTrie!(AsciiSpec); auto utf8_2T = utf8_2.byCodepoint.map!(x=>encode!2(x)).buildTrie!(Utf8Spec2); auto utf8_3T = utf8_3.byCodepoint.map!(x=>encode!3(x)).buildTrie!(Utf8Spec3); auto utf8_4T = utf8_4.byCodepoint.map!(x=>encode!4(x)).buildTrie!(Utf8Spec4); alias Ret = Impl!(1,2,3,4); return Ret(asciiT, utf8_2T, utf8_3T, utf8_4T); } // Bootstrap UTF-8 static matcher interface // from 3 primitives: tab!(size), lookup and Sizes mixin template DefMatcher() { import std.format : format; enum hasASCII = staticIndexOf!(1, Sizes) >= 0; alias UniSizes = Erase!(1, Sizes); //generate dispatch code sequence for unicode parts static auto genDispatch() { string code; foreach(size; UniSizes) code ~= format(q{ if ((ch & ~leadMask!%d) == encMask!(%d)) return lookup!(%d, mode)(inp); else }, size, size, size); static if (Sizes.length == 4) //covers all code unit cases code ~= "{ badEncoding(); return false; }"; else code ~= "return false;"; //may be just fine but not covered return code; } enum dispatch = genDispatch(); public bool match(Range)(ref Range inp) const pure @trusted if(isRandomAccessRange!Range && is(ElementType!Range : char)) { enum mode = Mode.skipOnMatch; assert(!inp.empty); auto ch = inp[0]; static if(hasASCII) { if (ch < 0x80) { bool r = tab!1[ch]; if(r) inp.popFront(); return r; } else mixin(dispatch); } else mixin(dispatch); } static if(Sizes.length == 4) // can skip iff can detect all encodings { public bool skip(Range)(ref Range inp) const pure @trusted if(isRandomAccessRange!Range && is(ElementType!Range : char)) { enum mode = Mode.alwaysSkip; assert(!inp.empty); auto ch = inp[0]; static if(hasASCII) { if (ch < 0x80) { inp.popFront(); return tab!1[ch]; } else mixin(dispatch); } else mixin(dispatch); } } public bool test(Range)(ref Range inp) const pure @trusted if(isRandomAccessRange!Range && is(ElementType!Range : char)) { enum mode = Mode.neverSkip; assert(!inp.empty); auto ch = inp[0]; static if(hasASCII) { if (ch < 0x80) return tab!1[ch]; else mixin(dispatch); } else mixin(dispatch); } bool match(C)(ref C[] str) const pure @trusted if(isSomeChar!C) { return fwdStr!"match"(str); } bool skip(C)(ref C[] str) const pure @trusted if(isSomeChar!C) { return fwdStr!"skip"(str); } bool test(C)(ref C[] str) const pure @trusted if(isSomeChar!C) { return fwdStr!"test"(str); } mixin ForwardStrings; } struct Impl(Sizes...) { static assert(allSatisfy!(validSize, Sizes), "Only lengths of 1, 2, 3 and 4 code unit are possible for UTF-8"); private: //pick tables for chosen sizes alias OurTabs = staticMap!(Table, Sizes); OurTabs tables; mixin DefMatcher; //static disptach helper UTF size ==> table alias tab(int i) = tables[i - 1]; package @property auto subMatcher(SizesToPick...)() @trusted { return CherryPick!(Impl, SizesToPick)(&this); } bool lookup(int size, Mode mode, Range)(ref Range inp) const pure @trusted { import std.typecons; if(inp.length < size) { badEncoding(); return false; } char[size] needle = void; needle[0] = leadMask!size & inp[0]; foreach(i; staticIota!(1, size)) { needle[i] = truncate(inp[i]); } //overlong encoding checks static if(size == 2) { //0x80-0x7FF //got 6 bits in needle[1], must use at least 8 bits //must use at least 2 bits in needle[1] if(needle[0] < 2) badEncoding(); } else static if(size == 3) { //0x800-0xFFFF //got 6 bits in needle[2], must use at least 12bits //must use 6 bits in needle[1] or anything in needle[0] if(needle[0] == 0 && needle[1] < 0x20) badEncoding(); } else static if(size == 4) { //0x800-0xFFFF //got 2x6=12 bits in needle[2..3] must use at least 17bits //must use 5 bits (or above) in needle[1] or anything in needle[0] if(needle[0] == 0 && needle[1] < 0x10) badEncoding(); } static if(mode == Mode.alwaysSkip) { inp.popFrontN(size); return tab!size[needle]; } else static if(mode == Mode.neverSkip) { return tab!size[needle]; } else { static assert(mode == Mode.skipOnMatch); if (tab!size[needle]) { inp.popFrontN(size); return true; } else return false; } } } struct CherryPick(I, Sizes...) { static assert(allSatisfy!(validSize, Sizes), "Only lengths of 1, 2, 3 and 4 code unit are possible for UTF-8"); private: I* m; @property ref tab(int i)() const pure { return m.tables[i - 1]; } bool lookup(int size, Mode mode, Range)(ref Range inp) const pure { return m.lookup!(size, mode)(inp); } mixin DefMatcher; } } template Utf16Matcher() { enum validSize(int sz) = sz >= 1 && sz <=2; void badEncoding() pure { import std.utf; throw new UTFException("Invalid UTF-16 sequence"); } // 1-stage ASCII alias AsciiSpec = AliasSeq!(bool, wchar, clamp!7); //2-stage BMP alias BmpSpec = AliasSeq!(bool, wchar, sliceBits!(7, 16), sliceBits!(0, 7)); //4-stage - full Unicode //assume that 0xD800 & 0xDC00 bits are cleared //thus leaving 10 bit per wchar to worry about alias UniSpec = AliasSeq!(bool, wchar[2], assumeSize!(x=>x[0]>>4, 6), assumeSize!(x=>x[0]&0xf, 4), assumeSize!(x=>x[1]>>6, 4), assumeSize!(x=>x[1]&0x3f, 6), ); alias Ascii = typeof(TrieBuilder!(AsciiSpec)(false).build()); alias Bmp = typeof(TrieBuilder!(BmpSpec)(false).build()); alias Uni = typeof(TrieBuilder!(UniSpec)(false).build()); auto encode2(dchar ch) { ch -= 0x1_0000; assert(ch <= 0xF_FFFF); wchar[2] ret; //do not put surrogate bits, they are sliced off ret[0] = cast(wchar)(ch>>10); ret[1] = (ch & 0xFFF); return ret; } auto build(Set)(Set set) { import std.algorithm : map; auto ascii = set & unicode.ASCII; auto bmp = (set & CodepointSet.fromIntervals(0x80, 0xFFFF+1)) - CodepointSet.fromIntervals(0xD800, 0xDFFF+1); auto other = set - (bmp | ascii); auto asciiT = ascii.byCodepoint.map!(x=>cast(char)x).buildTrie!(AsciiSpec); auto bmpT = bmp.byCodepoint.map!(x=>cast(wchar)x).buildTrie!(BmpSpec); auto otherT = other.byCodepoint.map!(x=>encode2(x)).buildTrie!(UniSpec); alias Ret = Impl!(1,2); return Ret(asciiT, bmpT, otherT); } //bootstrap full UTF-16 matcher interace from //sizeFlags, lookupUni and ascii mixin template DefMatcher() { public bool match(Range)(ref Range inp) const pure @trusted if(isRandomAccessRange!Range && is(ElementType!Range : wchar)) { enum mode = Mode.skipOnMatch; assert(!inp.empty); auto ch = inp[0]; static if(sizeFlags & 1) { if (ch < 0x80) { if (ascii[ch]) { inp.popFront(); return true; } else return false; } return lookupUni!mode(inp); } else return lookupUni!mode(inp); } static if(Sizes.length == 2) { public bool skip(Range)(ref Range inp) const pure @trusted if(isRandomAccessRange!Range && is(ElementType!Range : wchar)) { enum mode = Mode.alwaysSkip; assert(!inp.empty); auto ch = inp[0]; static if(sizeFlags & 1) { if (ch < 0x80) { inp.popFront(); return ascii[ch]; } else return lookupUni!mode(inp); } else return lookupUni!mode(inp); } } public bool test(Range)(ref Range inp) const pure @trusted if(isRandomAccessRange!Range && is(ElementType!Range : wchar)) { enum mode = Mode.neverSkip; assert(!inp.empty); auto ch = inp[0]; static if(sizeFlags & 1) return ch < 0x80 ? ascii[ch] : lookupUni!mode(inp); else return lookupUni!mode(inp); } bool match(C)(ref C[] str) const pure @trusted if(isSomeChar!C) { return fwdStr!"match"(str); } bool skip(C)(ref C[] str) const pure @trusted if(isSomeChar!C) { return fwdStr!"skip"(str); } bool test(C)(ref C[] str) const pure @trusted if(isSomeChar!C) { return fwdStr!"test"(str); } mixin ForwardStrings; //dispatch strings to range versions } struct Impl(Sizes...) if(Sizes.length >= 1 && Sizes.length <= 2) { private: static assert(allSatisfy!(validSize, Sizes), "Only lengths of 1 and 2 code units are possible in UTF-16"); static if(Sizes.length > 1) enum sizeFlags = Sizes[0] | Sizes[1]; else enum sizeFlags = Sizes[0]; static if(sizeFlags & 1) { Ascii ascii; Bmp bmp; } static if(sizeFlags & 2) { Uni uni; } mixin DefMatcher; package @property auto subMatcher(SizesToPick...)() @trusted { return CherryPick!(Impl, SizesToPick)(&this); } bool lookupUni(Mode mode, Range)(ref Range inp) const pure { wchar x = cast(wchar)(inp[0] - 0xD800); //not a high surrogate if(x > 0x3FF) { //low surrogate if(x <= 0x7FF) badEncoding(); static if(sizeFlags & 1) { auto ch = inp[0]; static if(mode == Mode.alwaysSkip) inp.popFront(); static if(mode == Mode.skipOnMatch) { if (bmp[ch]) { inp.popFront(); return true; } else return false; } else return bmp[ch]; } else //skip is not available for sub-matchers, so just false return false; } else { static if(sizeFlags & 2) { if(inp.length < 2) badEncoding(); wchar y = cast(wchar)(inp[1] - 0xDC00); //not a low surrogate if(y > 0x3FF) badEncoding(); wchar[2] needle = [inp[0] & 0x3ff, inp[1] & 0x3ff]; static if(mode == Mode.alwaysSkip) inp.popFrontN(2); static if(mode == Mode.skipOnMatch) { if (uni[needle]) { inp.popFrontN(2); return true; } else return false; } else return uni[needle]; } else //ditto return false; } } } struct CherryPick(I, Sizes...) if(Sizes.length >= 1 && Sizes.length <= 2) { private: I* m; enum sizeFlags = I.sizeFlags; static if(sizeFlags & 1) { @property ref ascii()() const pure{ return m.ascii; } } bool lookupUni(Mode mode, Range)(ref Range inp) const pure { return m.lookupUni!mode(inp); } mixin DefMatcher; static assert(allSatisfy!(validSize, Sizes), "Only lengths of 1 and 2 code units are possible in UTF-16"); } } private auto utf8Matcher(Set)(Set set) @trusted { return Utf8Matcher!().build(set); } private auto utf16Matcher(Set)(Set set) @trusted { return Utf16Matcher!().build(set); } /** Constructs a matcher object to classify $(CODEPOINTS) from the $(D set) for encoding that has $(D Char) as code unit. See $(LREF MatcherConcept) for API outline. */ public auto utfMatcher(Char, Set)(Set set) @trusted if(isCodepointSet!Set) { static if(is(Char : char)) return utf8Matcher(set); else static if(is(Char : wchar)) return utf16Matcher(set); else static if(is(Char : dchar)) static assert(false, "UTF-32 needs no decoding, and thus not supported by utfMatcher"); else static assert(false, "Only character types 'char' and 'wchar' are allowed"); } //a range of code units, packed with index to speed up forward iteration package auto decoder(C)(C[] s, size_t offset=0) @safe pure nothrow @nogc if(is(C : wchar) || is(C : char)) { static struct Decoder { pure nothrow: C[] str; size_t idx; @property C front(){ return str[idx]; } @property C back(){ return str[$-1]; } void popFront(){ idx++; } void popBack(){ str = str[0..$-1]; } void popFrontN(size_t n){ idx += n; } @property bool empty(){ return idx == str.length; } @property auto save(){ return this; } auto opIndex(size_t i){ return str[idx+i]; } @property size_t length(){ return str.length - idx; } alias opDollar = length; auto opSlice(size_t a, size_t b){ return Decoder(str[0..idx+b], idx+a); } } static assert(isRandomAccessRange!Decoder); static assert(is(ElementType!Decoder : C)); return Decoder(s, offset); } /* Expose UTF string $(D s) as a random-access range of $(S_LINK Code unit, code units). */ package auto units(C)(C[] s) @safe pure nothrow @nogc if(is(C : wchar) || is(C : char)) { static struct Units { pure nothrow: C[] str; @property C front(){ return str[0]; } @property C back(){ return str[$-1]; } void popFront(){ str = str[1..$]; } void popBack(){ str = str[0..$-1]; } void popFrontN(size_t n){ str = str[n..$]; } @property bool empty(){ return 0 == str.length; } @property auto save(){ return this; } auto opIndex(size_t i){ return str[i]; } @property size_t length(){ return str.length; } alias opDollar = length; auto opSlice(size_t a, size_t b){ return Units(str[a..b]); } } static assert(isRandomAccessRange!Units); static assert(is(ElementType!Units : C)); return Units(s); } @safe unittest { import std.range; string rs = "hi! ネемног砀 текста"; auto codec = rs.decoder; auto utf8 = utf8Matcher(unicode.Letter); auto asc = utf8.subMatcher!(1); auto uni = utf8.subMatcher!(2,3,4); assert(asc.test(codec)); assert(!uni.match(codec)); assert(utf8.skip(codec)); assert(codec.idx == 1); assert(!uni.match(codec)); assert(asc.test(codec)); assert(utf8.skip(codec)); assert(codec.idx == 2); assert(!asc.match(codec)); assert(!utf8.test(codec)); assert(!utf8.skip(codec)); assert(!asc.test(codec)); assert(!utf8.test(codec)); assert(!utf8.skip(codec)); assert(utf8.test(codec)); foreach(i; 0..7) { assert(!asc.test(codec)); assert(uni.test(codec)); assert(utf8.skip(codec)); } assert(!utf8.test(codec)); assert(!utf8.skip(codec)); //the same with match where applicable codec = rs.decoder; assert(utf8.match(codec)); assert(codec.idx == 1); assert(utf8.match(codec)); assert(codec.idx == 2); assert(!utf8.match(codec)); assert(codec.idx == 2); assert(!utf8.skip(codec)); assert(!utf8.skip(codec)); foreach(i; 0..7) { assert(!asc.test(codec)); assert(utf8.test(codec)); assert(utf8.match(codec)); } auto i = codec.idx; assert(!utf8.match(codec)); assert(codec.idx == i); } @safe unittest { import std.range; static bool testAll(Matcher, Range)(ref Matcher m, ref Range r) { bool t = m.test(r); auto save = r.idx; assert(t == m.match(r)); assert(r.idx == save || t); //ether no change or was match r.idx = save; static if(is(typeof(m.skip(r)))) { assert(t == m.skip(r)); assert(r.idx != save); //always changed r.idx = save; } return t; } auto utf16 = utfMatcher!wchar(unicode.L); auto bmp = utf16.subMatcher!1; auto nonBmp = utf16.subMatcher!1; auto utf8 = utfMatcher!char(unicode.L); auto ascii = utf8.subMatcher!1; auto uni2 = utf8.subMatcher!2; auto uni3 = utf8.subMatcher!3; auto uni24 = utf8.subMatcher!(2,4); foreach(ch; unicode.L.byCodepoint.stride(3)) { import std.utf : encode; char[4] buf; wchar[2] buf16; auto len = encode(buf, ch); auto len16 = encode(buf16, ch); auto c8 = buf[0..len].decoder; auto c16 = buf16[0..len16].decoder; assert(testAll(utf16, c16)); assert(testAll(bmp, c16) || len16 != 1); assert(testAll(nonBmp, c16) || len16 != 2); assert(testAll(utf8, c8)); //submatchers return false on out of their domain assert(testAll(ascii, c8) || len != 1); assert(testAll(uni2, c8) || len != 2); assert(testAll(uni3, c8) || len != 3); assert(testAll(uni24, c8) || (len != 2 && len !=4)); } } // cover decode fail cases of Matcher unittest { import std.exception : collectException; import std.format : format; import std.algorithm; auto utf16 = utfMatcher!wchar(unicode.L); auto utf8 = utfMatcher!char(unicode.L); //decode failure cases UTF-8 alias fails8 = AliasSeq!("\xC1", "\x80\x00","\xC0\x00", "\xCF\x79", "\xFF\x00\0x00\0x00\x00", "\xC0\0x80\0x80\x80", "\x80\0x00\0x00\x00", "\xCF\x00\0x00\0x00\x00"); foreach(msg; fails8){ assert(collectException((){ auto s = msg; import std.utf; size_t idx = 0; //decode(s, idx); utf8.test(s); }()), format("%( %2x %)", cast(ubyte[])msg)); } //decode failure cases UTF-16 alias fails16 = AliasSeq!([0xD811], [0xDC02]); foreach(msg; fails16){ assert(collectException((){ auto s = msg.map!(x => cast(wchar)x); utf16.test(s); }())); } } /++ Convenience function to construct optimal configurations for packed Trie from any $(D set) of $(CODEPOINTS). The parameter $(D level) indicates the number of trie levels to use, allowed values are: 1, 2, 3 or 4. Levels represent different trade-offs speed-size wise. $(P Level 1 is fastest and the most memory hungry (a bit array). ) $(P Level 4 is the slowest and has the smallest footprint. ) See the $(S_LINK Synopsis, Synopsis) section for example. Note: Level 4 stays very practical (being faster and more predictable) compared to using direct lookup on the $(D set) itself. +/ public auto toTrie(size_t level, Set)(Set set) if(isCodepointSet!Set) { static if(level == 1) return codepointSetTrie!(21)(set); else static if(level == 2) return codepointSetTrie!(10, 11)(set); else static if(level == 3) return codepointSetTrie!(8, 5, 8)(set); else static if(level == 4) return codepointSetTrie!(6, 4, 4, 7)(set); else static assert(false, "Sorry, toTrie doesn't support levels > 4, use codepointSetTrie directly"); } /** $(P Builds a $(D Trie) with typically optimal speed-size trade-off and wraps it into a delegate of the following type: $(D bool delegate(dchar ch)). ) $(P Effectively this creates a 'tester' lambda suitable for algorithms like std.algorithm.find that take unary predicates. ) See the $(S_LINK Synopsis, Synopsis) section for example. */ public auto toDelegate(Set)(Set set) if(isCodepointSet!Set) { // 3 is very small and is almost as fast as 2-level (due to CPU caches?) auto t = toTrie!3(set); return (dchar ch) => t[ch]; } /** $(P Opaque wrapper around unsigned built-in integers and code unit (char/wchar/dchar) types. Parameter $(D sz) indicates that the value is confined to the range of [0, 2^^sz$(RPAREN). With this knowledge it can be packed more tightly when stored in certain data-structures like trie. ) Note: $(P The $(D BitPacked!(T, sz)) is implicitly convertible to $(D T) but not vise-versa. Users have to ensure the value fits in the range required and use the $(D cast) operator to perform the conversion.) */ struct BitPacked(T, size_t sz) if(isIntegral!T || is(T:dchar)) { enum bitSize = sz; T _value; alias _value this; } /* Depending on the form of the passed argument $(D bitSizeOf) returns the amount of bits required to represent a given type or a return type of a given functor. */ template bitSizeOf(Args...) if(Args.length == 1) { alias T = Args[0]; static if(__traits(compiles, { size_t val = T.bitSize; })) //(is(typeof(T.bitSize) : size_t)) { enum bitSizeOf = T.bitSize; } else static if(is(ReturnType!T dummy == BitPacked!(U, bits), U, size_t bits)) { enum bitSizeOf = bitSizeOf!(ReturnType!T); } else { enum bitSizeOf = T.sizeof*8; } } /** Tests if $(D T) is some instantiation of $(LREF BitPacked)!(U, x) and thus suitable for packing. */ template isBitPacked(T) { static if(is(T dummy == BitPacked!(U, bits), U, size_t bits)) enum isBitPacked = true; else enum isBitPacked = false; } /** Gives the type $(D U) from $(LREF BitPacked)!(U, x) or $(D T) itself for every other type. */ template TypeOfBitPacked(T) { static if(is(T dummy == BitPacked!(U, bits), U, size_t bits)) alias TypeOfBitPacked = U; else alias TypeOfBitPacked = T; } /* Wrapper, used in definition of custom data structures from $(D Trie) template. Applying it to a unary lambda function indicates that the returned value always fits within $(D bits) of bits. */ struct assumeSize(alias Fn, size_t bits) { enum bitSize = bits; static auto ref opCall(T)(auto ref T arg) { return Fn(arg); } } /* A helper for defining lambda function that yields a slice of certain bits from an unsigned integral value. The resulting lambda is wrapped in assumeSize and can be used directly with $(D Trie) template. */ struct sliceBits(size_t from, size_t to) { //for now bypass assumeSize, DMD has trouble inlining it enum bitSize = to-from; static auto opCall(T)(T x) out(result) { assert(result < (1<> from) & ((1<<(to-from))-1); } } @safe pure nothrow @nogc uint low_8(uint x) { return x&0xFF; } @safe pure nothrow @nogc uint midlow_8(uint x){ return (x&0xFF00)>>8; } alias lo8 = assumeSize!(low_8, 8); alias mlo8 = assumeSize!(midlow_8, 8); static assert(bitSizeOf!lo8 == 8); static assert(bitSizeOf!(sliceBits!(4, 7)) == 3); static assert(bitSizeOf!(BitPacked!(uint, 2)) == 2); template Sequence(size_t start, size_t end) { static if(start < end) alias Sequence = AliasSeq!(start, Sequence!(start+1, end)); else alias Sequence = AliasSeq!(); } //---- TRIE TESTS ---- unittest { import std.conv; import std.algorithm; import std.range; static trieStats(TRIE)(TRIE t) { version(std_uni_stats) { import std.stdio; writeln("---TRIE FOOTPRINT STATS---"); foreach(i; staticIota!(0, t.table.dim) ) { writefln("lvl%s = %s bytes; %s pages" , i, t.bytes!i, t.pages!i); } writefln("TOTAL: %s bytes", t.bytes); version(none) { writeln("INDEX (excluding value level):"); foreach(i; staticIota!(0, t.table.dim-1) ) writeln(t.table.slice!(i)[0..t.table.length!i]); } writeln("---------------------------"); } } //@@@BUG link failure, lambdas not found by linker somehow (in case of trie2) // alias lo8 = assumeSize!(8, function (uint x) { return x&0xFF; }); // alias next8 = assumeSize!(7, function (uint x) { return (x&0x7F00)>>8; }); alias Set = CodepointSet; auto set = Set('A','Z','a','z'); auto trie = buildTrie!(bool, uint, 256, lo8)(set.byInterval);// simple bool array for(int a='a'; a<'z';a++) assert(trie[a]); for(int a='A'; a<'Z';a++) assert(trie[a]); for(int a=0; a<'A'; a++) assert(!trie[a]); for(int a ='Z'; a<'a'; a++) assert(!trie[a]); trieStats(trie); auto redundant2 = Set( 1, 18, 256+2, 256+111, 512+1, 512+18, 768+2, 768+111); auto trie2 = buildTrie!(bool, uint, 1024, mlo8, lo8)(redundant2.byInterval); trieStats(trie2); foreach(e; redundant2.byCodepoint) assert(trie2[e], text(cast(uint)e, " - ", trie2[e])); foreach(i; 0..1024) { assert(trie2[i] == (i in redundant2)); } auto redundant3 = Set( 2, 4, 6, 8, 16, 2+16, 4+16, 16+6, 16+8, 16+16, 2+32, 4+32, 32+6, 32+8, ); enum max3 = 256; // sliceBits auto trie3 = buildTrie!(bool, uint, max3, sliceBits!(6,8), sliceBits!(4,6), sliceBits!(0,4) )(redundant3.byInterval); trieStats(trie3); foreach(i; 0..max3) assert(trie3[i] == (i in redundant3), text(cast(uint)i)); auto redundant4 = Set( 10, 64, 64+10, 128, 128+10, 256, 256+10, 512, 1000, 2000, 3000, 4000, 5000, 6000 ); enum max4 = 2^^16; auto trie4 = buildTrie!(bool, size_t, max4, sliceBits!(13, 16), sliceBits!(9, 13), sliceBits!(6, 9) , sliceBits!(0, 6) )(redundant4.byInterval); foreach(i; 0..max4){ if(i in redundant4) assert(trie4[i], text(cast(uint)i)); } trieStats(trie4); alias mapToS = mapTrieIndex!(useItemAt!(0, char)); string[] redundantS = ["tea", "start", "orange"]; redundantS.sort!((a,b) => mapToS(a) < mapToS(b))(); auto strie = buildTrie!(bool, string, useItemAt!(0, char))(redundantS); // using first char only assert(redundantS == ["orange", "start", "tea"]); assert(strie["test"], text(strie["test"])); assert(!strie["aea"]); assert(strie["s"]); // a bit size test auto a = array(map!(x => to!ubyte(x))(iota(0, 256))); auto bt = buildTrie!(bool, ubyte, sliceBits!(7, 8), sliceBits!(5, 7), sliceBits!(0, 5))(a); trieStats(bt); foreach(i; 0..256) assert(bt[cast(ubyte)i]); } template useItemAt(size_t idx, T) if(isIntegral!T || is(T: dchar)) { size_t impl(in T[] arr){ return arr[idx]; } alias useItemAt = assumeSize!(impl, 8*T.sizeof); } template useLastItem(T) { size_t impl(in T[] arr){ return arr[$-1]; } alias useLastItem = assumeSize!(impl, 8*T.sizeof); } template fullBitSize(Prefix...) { static if(Prefix.length > 0) enum fullBitSize = bitSizeOf!(Prefix[0])+fullBitSize!(Prefix[1..$]); else enum fullBitSize = 0; } template idxTypes(Key, size_t fullBits, Prefix...) { static if(Prefix.length == 1) {// the last level is value level, so no index once reduced to 1-level alias idxTypes = AliasSeq!(); } else { // Important note on bit packing // Each level has to hold enough of bits to address the next one // The bottom level is known to hold full bit width // thus it's size in pages is full_bit_width - size_of_last_prefix // Recourse on this notion alias idxTypes = AliasSeq!( idxTypes!(Key, fullBits - bitSizeOf!(Prefix[$-1]), Prefix[0..$-1]), BitPacked!(typeof(Prefix[$-2](Key.init)), fullBits - bitSizeOf!(Prefix[$-1])) ); } } //============================================================================ @safe pure int comparePropertyName(Char1, Char2)(const(Char1)[] a, const(Char2)[] b) if (is(Char1 : dchar) && is(Char2 : dchar)) { import std.ascii : toLower; import std.algorithm : cmp, map, filter; static bool pred(dchar c) {return !c.isWhite && c != '-' && c != '_';} return cmp( a.map!toLower.filter!pred, b.map!toLower.filter!pred); } @safe pure unittest { assert(!comparePropertyName("foo-bar", "fooBar")); } bool propertyNameLess(Char1, Char2)(const(Char1)[] a, const(Char2)[] b) @safe pure if (is(Char1 : dchar) && is(Char2 : dchar)) { return comparePropertyName(a, b) < 0; } //============================================================================ // Utilities for compression of Unicode code point sets //============================================================================ @safe void compressTo(uint val, ref ubyte[] arr) pure nothrow { // not optimized as usually done 1 time (and not public interface) if(val < 128) arr ~= cast(ubyte)val; else if(val < (1<<13)) { arr ~= (0b1_00<<5) | cast(ubyte)(val>>8); arr ~= val & 0xFF; } else { assert(val < (1<<21)); arr ~= (0b1_01<<5) | cast(ubyte)(val>>16); arr ~= (val >> 8) & 0xFF; arr ~= val & 0xFF; } } @safe uint decompressFrom(const(ubyte)[] arr, ref size_t idx) pure { import std.exception : enforce; uint first = arr[idx++]; if(!(first & 0x80)) // no top bit -> [0..127] return first; uint extra = ((first>>5) & 1) + 1; // [1, 2] uint val = (first & 0x1F); enforce(idx + extra <= arr.length, "bad code point interval encoding"); foreach(j; 0..extra) val = (val<<8) | arr[idx+j]; idx += extra; return val; } package ubyte[] compressIntervals(Range)(Range intervals) if(isInputRange!Range && isIntegralPair!(ElementType!Range)) { ubyte[] storage; uint base = 0; // RLE encode foreach(val; intervals) { compressTo(val[0]-base, storage); base = val[0]; if(val[1] != lastDchar+1) // till the end of the domain so don't store it { compressTo(val[1]-base, storage); base = val[1]; } } return storage; } @safe pure unittest { import std.typecons; auto run = [tuple(80, 127), tuple(128, (1<<10)+128)]; ubyte[] enc = [cast(ubyte)80, 47, 1, (0b1_00<<5) | (1<<2), 0]; assert(compressIntervals(run) == enc); auto run2 = [tuple(0, (1<<20)+512+1), tuple((1<<20)+512+4, lastDchar+1)]; ubyte[] enc2 = [cast(ubyte)0, (0b1_01<<5) | (1<<4), 2, 1, 3]; // odd length-ed assert(compressIntervals(run2) == enc2); size_t idx = 0; assert(decompressFrom(enc, idx) == 80); assert(decompressFrom(enc, idx) == 47); assert(decompressFrom(enc, idx) == 1); assert(decompressFrom(enc, idx) == (1<<10)); idx = 0; assert(decompressFrom(enc2, idx) == 0); assert(decompressFrom(enc2, idx) == (1<<20)+512+1); assert(equalS(decompressIntervals(compressIntervals(run)), run)); assert(equalS(decompressIntervals(compressIntervals(run2)), run2)); } // Creates a range of $(D CodepointInterval) that lazily decodes compressed data. @safe package auto decompressIntervals(const(ubyte)[] data) pure { return DecompressedIntervals(data); } @safe struct DecompressedIntervals { pure: const(ubyte)[] _stream; size_t _idx; CodepointInterval _front; this(const(ubyte)[] stream) { _stream = stream; popFront(); } @property CodepointInterval front() { assert(!empty); return _front; } void popFront() { if(_idx == _stream.length) { _idx = size_t.max; return; } uint base = _front[1]; _front[0] = base + decompressFrom(_stream, _idx); if(_idx == _stream.length)// odd length ---> till the end _front[1] = lastDchar+1; else { base = _front[0]; _front[1] = base + decompressFrom(_stream, _idx); } } @property bool empty() const { return _idx == size_t.max; } @property DecompressedIntervals save() { return this; } } static assert(isInputRange!DecompressedIntervals); static assert(isForwardRange!DecompressedIntervals); //============================================================================ version(std_uni_bootstrap){} else { // helper for looking up code point sets @trusted ptrdiff_t findUnicodeSet(alias table, C)(in C[] name) pure { import std.range : assumeSorted; import std.algorithm : map; auto range = assumeSorted!((a,b) => propertyNameLess(a,b)) (table.map!"a.name"()); size_t idx = range.lowerBound(name).length; if(idx < range.length && comparePropertyName(range[idx], name) == 0) return idx; return -1; } // another one that loads it @trusted bool loadUnicodeSet(alias table, Set, C)(in C[] name, ref Set dest) pure { auto idx = findUnicodeSet!table(name); if(idx >= 0) { dest = Set(asSet(table[idx].compressed)); return true; } return false; } @trusted bool loadProperty(Set=CodepointSet, C) (in C[] name, ref Set target) pure { alias ucmp = comparePropertyName; // conjure cumulative properties by hand if(ucmp(name, "L") == 0 || ucmp(name, "Letter") == 0) { target = asSet(uniProps.Lu); target |= asSet(uniProps.Ll); target |= asSet(uniProps.Lt); target |= asSet(uniProps.Lo); target |= asSet(uniProps.Lm); } else if(ucmp(name,"LC") == 0 || ucmp(name,"Cased Letter")==0) { target = asSet(uniProps.Ll); target |= asSet(uniProps.Lu); target |= asSet(uniProps.Lt);// Title case } else if(ucmp(name, "M") == 0 || ucmp(name, "Mark") == 0) { target = asSet(uniProps.Mn); target |= asSet(uniProps.Mc); target |= asSet(uniProps.Me); } else if(ucmp(name, "N") == 0 || ucmp(name, "Number") == 0) { target = asSet(uniProps.Nd); target |= asSet(uniProps.Nl); target |= asSet(uniProps.No); } else if(ucmp(name, "P") == 0 || ucmp(name, "Punctuation") == 0) { target = asSet(uniProps.Pc); target |= asSet(uniProps.Pd); target |= asSet(uniProps.Ps); target |= asSet(uniProps.Pe); target |= asSet(uniProps.Pi); target |= asSet(uniProps.Pf); target |= asSet(uniProps.Po); } else if(ucmp(name, "S") == 0 || ucmp(name, "Symbol") == 0) { target = asSet(uniProps.Sm); target |= asSet(uniProps.Sc); target |= asSet(uniProps.Sk); target |= asSet(uniProps.So); } else if(ucmp(name, "Z") == 0 || ucmp(name, "Separator") == 0) { target = asSet(uniProps.Zs); target |= asSet(uniProps.Zl); target |= asSet(uniProps.Zp); } else if(ucmp(name, "C") == 0 || ucmp(name, "Other") == 0) { target = asSet(uniProps.Co); target |= asSet(uniProps.Lo); target |= asSet(uniProps.No); target |= asSet(uniProps.So); target |= asSet(uniProps.Po); } else if(ucmp(name, "graphical") == 0){ target = asSet(uniProps.Alphabetic); target |= asSet(uniProps.Mn); target |= asSet(uniProps.Mc); target |= asSet(uniProps.Me); target |= asSet(uniProps.Nd); target |= asSet(uniProps.Nl); target |= asSet(uniProps.No); target |= asSet(uniProps.Pc); target |= asSet(uniProps.Pd); target |= asSet(uniProps.Ps); target |= asSet(uniProps.Pe); target |= asSet(uniProps.Pi); target |= asSet(uniProps.Pf); target |= asSet(uniProps.Po); target |= asSet(uniProps.Zs); target |= asSet(uniProps.Sm); target |= asSet(uniProps.Sc); target |= asSet(uniProps.Sk); target |= asSet(uniProps.So); } else if(ucmp(name, "any") == 0) target = Set.fromIntervals(0, 0x110000); else if(ucmp(name, "ascii") == 0) target = Set.fromIntervals(0, 0x80); else return loadUnicodeSet!(uniProps.tab)(name, target); return true; } // CTFE-only helper for checking property names at compile-time @safe bool isPrettyPropertyName(C)(in C[] name) { import std.algorithm : find; auto names = [ "L", "Letter", "LC", "Cased Letter", "M", "Mark", "N", "Number", "P", "Punctuation", "S", "Symbol", "Z", "Separator", "Graphical", "any", "ascii" ]; auto x = find!(x => comparePropertyName(x, name) == 0)(names); return !x.empty; } // ditto, CTFE-only, not optimized @safe private static bool findSetName(alias table, C)(in C[] name) { return findUnicodeSet!table(name) >= 0; } template SetSearcher(alias table, string kind) { /// Run-time checked search. static auto opCall(C)(in C[] name) if(is(C : dchar)) { import std.conv : to; CodepointSet set; if(loadUnicodeSet!table(name, set)) return set; throw new Exception("No unicode set for "~kind~" by name " ~name.to!string()~" was found."); } /// Compile-time checked search. static @property auto opDispatch(string name)() { static if(findSetName!table(name)) { CodepointSet set; loadUnicodeSet!table(name, set); return set; } else static assert(false, "No unicode set for "~kind~" by name " ~name~" was found."); } } /** A single entry point to lookup Unicode $(CODEPOINT) sets by name or alias of a block, script or general category. It uses well defined standard rules of property name lookup. This includes fuzzy matching of names, so that 'White_Space', 'white-SpAce' and 'whitespace' are all considered equal and yield the same set of white space $(CHARACTERS). */ @safe public struct unicode { /** Performs the lookup of set of $(CODEPOINTS) with compile-time correctness checking. This short-cut version combines 3 searches: across blocks, scripts, and common binary properties. Note that since scripts and blocks overlap the usual trick to disambiguate is used - to get a block use $(D unicode.InBlockName), to search a script use $(D unicode.ScriptName). See_Also: $(LREF block), $(LREF script) and (not included in this search) $(LREF hangulSyllableType). */ static @property auto opDispatch(string name)() pure { static if(findAny(name)) return loadAny(name); else static assert(false, "No unicode set by name "~name~" was found."); } /// unittest { auto ascii = unicode.ASCII; assert(ascii['A']); assert(ascii['~']); assert(!ascii['\u00e0']); // matching is case-insensitive assert(ascii == unicode.ascII); assert(!ascii['à']); // underscores, '-' and whitespace in names are ignored too auto latin = unicode.in_latin1_Supplement; assert(latin['à']); assert(!latin['$']); // BTW Latin 1 Supplement is a block, hence "In" prefix assert(latin == unicode("In Latin 1 Supplement")); import std.exception; // run-time look up throws if no such set is found assert(collectException(unicode("InCyrilliac"))); } /** The same lookup across blocks, scripts, or binary properties, but performed at run-time. This version is provided for cases where $(D name) is not known beforehand; otherwise compile-time checked $(LREF opDispatch) is typically a better choice. See the $(S_LINK Unicode properties, table of properties) for available sets. */ static auto opCall(C)(in C[] name) if(is(C : dchar)) { return loadAny(name); } /** Narrows down the search for sets of $(CODEPOINTS) to all Unicode blocks. Note: Here block names are unambiguous as no scripts are searched and thus to search use simply $(D unicode.block.BlockName) notation. See $(S_LINK Unicode properties, table of properties) for available sets. See_Also: $(S_LINK Unicode properties, table of properties). */ struct block { mixin SetSearcher!(blocks.tab, "block"); } /// unittest { // use .block for explicitness assert(unicode.block.Greek_and_Coptic == unicode.InGreek_and_Coptic); } /** Narrows down the search for sets of $(CODEPOINTS) to all Unicode scripts. See the $(S_LINK Unicode properties, table of properties) for available sets. */ struct script { mixin SetSearcher!(scripts.tab, "script"); } /// unittest { auto arabicScript = unicode.script.arabic; auto arabicBlock = unicode.block.arabic; // there is an intersection between script and block assert(arabicBlock['؁']); assert(arabicScript['؁']); // but they are different assert(arabicBlock != arabicScript); assert(arabicBlock == unicode.inArabic); assert(arabicScript == unicode.arabic); } /** Fetch a set of $(CODEPOINTS) that have the given hangul syllable type. Other non-binary properties (once supported) follow the same notation - $(D unicode.propertyName.propertyValue) for compile-time checked access and $(D unicode.propertyName(propertyValue)) for run-time checked one. See the $(S_LINK Unicode properties, table of properties) for available sets. */ struct hangulSyllableType { mixin SetSearcher!(hangul.tab, "hangul syllable type"); } /// unittest { // L here is syllable type not Letter as in unicode.L short-cut auto leadingVowel = unicode.hangulSyllableType("L"); // check that some leading vowels are present foreach(vowel; '\u1110'..'\u115F') assert(leadingVowel[vowel]); assert(leadingVowel == unicode.hangulSyllableType.L); } private: alias ucmp = comparePropertyName; static bool findAny(string name) { return isPrettyPropertyName(name) || findSetName!(uniProps.tab)(name) || findSetName!(scripts.tab)(name) || (ucmp(name[0..2],"In") == 0 && findSetName!(blocks.tab)(name[2..$])); } static auto loadAny(Set=CodepointSet, C)(in C[] name) pure { import std.conv : to; Set set; bool loaded = loadProperty(name, set) || loadUnicodeSet!(scripts.tab)(name, set) || (name.length > 2 && ucmp(name[0..2],"In") == 0 && loadUnicodeSet!(blocks.tab)(name[2..$], set)); if(loaded) return set; throw new Exception("No unicode set by name "~name.to!string()~" was found."); } // FIXME: re-disable once the compiler is fixed // Disabled to prevent the mistake of creating instances of this pseudo-struct. //@disable ~this(); } unittest { assert(unicode("InHebrew") == asSet(blocks.Hebrew)); assert(unicode("separator") == (asSet(uniProps.Zs) | asSet(uniProps.Zl) | asSet(uniProps.Zp))); assert(unicode("In-Kharoshthi") == asSet(blocks.Kharoshthi)); } enum EMPTY_CASE_TRIE = ushort.max;// from what gen_uni uses internally // control - '\r' enum controlSwitch = ` case '\u0000':..case '\u0008':case '\u000E':..case '\u001F':case '\u007F':..case '\u0084':case '\u0086':..case '\u009F': case '\u0009':..case '\u000C': case '\u0085': `; // TODO: redo the most of hangul stuff algorithmically in case of Graphemes too // kill unrolled switches private static bool isRegionalIndicator(dchar ch) @safe { return ch >= '\U0001F1E6' && ch <= '\U0001F1FF'; } template genericDecodeGrapheme(bool getValue) { alias graphemeExtend = graphemeExtendTrie; alias spacingMark = mcTrie; static if(getValue) alias Value = Grapheme; else alias Value = void; Value genericDecodeGrapheme(Input)(ref Input range) { enum GraphemeState { Start, CR, RI, L, V, LVT } static if(getValue) Grapheme grapheme; auto state = GraphemeState.Start; enum eat = q{ static if(getValue) grapheme ~= ch; range.popFront(); }; dchar ch; assert(!range.empty, "Attempting to decode grapheme from an empty " ~ Input.stringof); while(!range.empty) { ch = range.front; final switch(state) with(GraphemeState) { case Start: mixin(eat); if(ch == '\r') state = CR; else if(isRegionalIndicator(ch)) state = RI; else if(isHangL(ch)) state = L; else if(hangLV[ch] || isHangV(ch)) state = V; else if(hangLVT[ch]) state = LVT; else if(isHangT(ch)) state = LVT; else { switch(ch) { mixin(controlSwitch); goto L_End; default: goto L_End_Extend; } } break; case CR: if(ch == '\n') mixin(eat); goto L_End_Extend; case RI: if(isRegionalIndicator(ch)) mixin(eat); else goto L_End_Extend; break; case L: if(isHangL(ch)) mixin(eat); else if(isHangV(ch) || hangLV[ch]) { state = V; mixin(eat); } else if(hangLVT[ch]) { state = LVT; mixin(eat); } else goto L_End_Extend; break; case V: if(isHangV(ch)) mixin(eat); else if(isHangT(ch)) { state = LVT; mixin(eat); } else goto L_End_Extend; break; case LVT: if(isHangT(ch)) { mixin(eat); } else goto L_End_Extend; break; } } L_End_Extend: while(!range.empty) { ch = range.front; // extend & spacing marks if(!graphemeExtend[ch] && !spacingMark[ch]) break; mixin(eat); } L_End: static if(getValue) return grapheme; } } public: // Public API continues /++ Computes the length of grapheme cluster starting at $(D index). Both the resulting length and the $(D index) are measured in $(S_LINK Code unit, code units). Params: C = type that is implicitly convertible to $(D dchars) input = array of grapheme clusters index = starting index into $(D input[]) Returns: length of grapheme cluster +/ size_t graphemeStride(C)(in C[] input, size_t index) if(is(C : dchar)) { auto src = input[index..$]; auto n = src.length; genericDecodeGrapheme!(false)(src); return n - src.length; } /// @safe unittest { assert(graphemeStride(" ", 1) == 1); // A + combing ring above string city = "A\u030Arhus"; size_t first = graphemeStride(city, 0); assert(first == 3); //\u030A has 2 UTF-8 code units assert(city[0..first] == "A\u030A"); assert(city[first..$] == "rhus"); } /++ Reads one full grapheme cluster from an input range of dchar $(D inp). For examples see the $(LREF Grapheme) below. Note: This function modifies $(D inp) and thus $(D inp) must be an L-value. +/ Grapheme decodeGrapheme(Input)(ref Input inp) if(isInputRange!Input && is(Unqual!(ElementType!Input) == dchar)) { return genericDecodeGrapheme!true(inp); } unittest { Grapheme gr; string s = " \u0020\u0308 "; gr = decodeGrapheme(s); assert(gr.length == 1 && gr[0] == ' '); gr = decodeGrapheme(s); assert(gr.length == 2 && equalS(gr[0..2], " \u0308")); s = "\u0300\u0308\u1100"; assert(equalS(decodeGrapheme(s)[], "\u0300\u0308")); assert(equalS(decodeGrapheme(s)[], "\u1100")); s = "\u11A8\u0308\uAC01"; assert(equalS(decodeGrapheme(s)[], "\u11A8\u0308")); assert(equalS(decodeGrapheme(s)[], "\uAC01")); } /++ $(P Iterate a string by grapheme.) $(P Useful for doing string manipulation that needs to be aware of graphemes.) See_Also: $(LREF byCodePoint) +/ auto byGrapheme(Range)(Range range) if(isInputRange!Range && is(Unqual!(ElementType!Range) == dchar)) { // TODO: Bidirectional access static struct Result { private Range _range; private Grapheme _front; bool empty() @property { return _front.length == 0; } Grapheme front() @property { return _front; } void popFront() { _front = _range.empty ? Grapheme.init : _range.decodeGrapheme(); } static if(isForwardRange!Range) { Result save() @property { return Result(_range.save, _front); } } } auto result = Result(range); result.popFront(); return result; } /// unittest { import std.conv; import std.range; import std.algorithm; auto text = "noe\u0308l"; // noël using e + combining diaeresis assert(text.walkLength == 5); // 5 code points auto gText = text.byGrapheme; assert(gText.walkLength == 4); // 4 graphemes assert(gText.take(3).equal("noe\u0308".byGrapheme)); assert(gText.drop(3).equal("l".byGrapheme)); } // For testing non-forward-range input ranges version(unittest) private static struct InputRangeString { private string s; bool empty() @property { return s.empty; } dchar front() @property { return s.front; } void popFront() { s.popFront(); } } unittest { import std.conv; import std.range; import std.algorithm; assert("".byGrapheme.walkLength == 0); auto reverse = "le\u0308on"; assert(reverse.walkLength == 5); auto gReverse = reverse.byGrapheme; assert(gReverse.walkLength == 4); foreach(text; AliasSeq!("noe\u0308l"c, "noe\u0308l"w, "noe\u0308l"d)) { assert(text.walkLength == 5); static assert(isForwardRange!(typeof(text))); auto gText = text.byGrapheme; static assert(isForwardRange!(typeof(gText))); assert(gText.walkLength == 4); assert(gText.array.retro.equal(gReverse)); } auto nonForwardRange = InputRangeString("noe\u0308l").byGrapheme; static assert(!isForwardRange!(typeof(nonForwardRange))); assert(nonForwardRange.walkLength == 4); } /++ $(P Lazily transform a range of $(LREF Grapheme)s to a range of code points.) $(P Useful for converting the result to a string after doing operations on graphemes.) $(P Acts as the identity function when given a range of code points.) +/ auto byCodePoint(Range)(Range range) if(isInputRange!Range && is(Unqual!(ElementType!Range) == Grapheme)) { // TODO: Propagate bidirectional access static struct Result { private Range _range; private size_t i = 0; bool empty() @property { return _range.empty; } dchar front() @property { return _range.front[i]; } void popFront() { ++i; if(i >= _range.front.length) { _range.popFront(); i = 0; } } static if(isForwardRange!Range) { Result save() @property { return Result(_range.save, i); } } } return Result(range); } /// Ditto Range byCodePoint(Range)(Range range) if(isInputRange!Range && is(Unqual!(ElementType!Range) == dchar)) { return range; } /// unittest { import std.conv : text; import std.range; string s = "noe\u0308l"; // noël // reverse it and convert the result to a string string reverse = s.byGrapheme .array .retro .byCodePoint .text; assert(reverse == "le\u0308on"); // lëon } unittest { import std.conv; import std.algorithm; assert("".byGrapheme.byCodePoint.equal("")); string text = "noe\u0308l"; static assert(is(typeof(text.byCodePoint) == string)); auto gText = InputRangeString(text).byGrapheme; static assert(!isForwardRange!(typeof(gText))); auto cpText = gText.byCodePoint; static assert(!isForwardRange!(typeof(cpText))); assert(cpText.walkLength == text.walkLength); } @trusted: /++ $(P A structure designed to effectively pack $(CHARACTERS) of a $(CLUSTER). ) $(P $(D Grapheme) has value semantics so 2 copies of a $(D Grapheme) always refer to distinct objects. In most actual scenarios a $(D Grapheme) fits on the stack and avoids memory allocation overhead for all but quite long clusters. ) See_Also: $(LREF decodeGrapheme), $(LREF graphemeStride) +/ @trusted struct Grapheme { import std.exception : enforce; public: this(C)(in C[] chars...) if(is(C : dchar)) { this ~= chars; } this(Input)(Input seq) if(!isDynamicArray!Input && isInputRange!Input && is(ElementType!Input : dchar)) { this ~= seq; } /// Gets a $(CODEPOINT) at the given index in this cluster. dchar opIndex(size_t index) const pure nothrow @nogc { assert(index < length); return read24(isBig ? ptr_ : small_.ptr, index); } /++ Writes a $(CODEPOINT) $(D ch) at given index in this cluster. Warning: Use of this facility may invalidate grapheme cluster, see also $(LREF Grapheme.valid). +/ void opIndexAssign(dchar ch, size_t index) pure nothrow @nogc { assert(index < length); write24(isBig ? ptr_ : small_.ptr, ch, index); } /// unittest { auto g = Grapheme("A\u0302"); assert(g[0] == 'A'); assert(g.valid); g[1] = '~'; // ASCII tilda is not a combining mark assert(g[1] == '~'); assert(!g.valid); } /++ Random-access range over Grapheme's $(CHARACTERS). Warning: Invalidates when this Grapheme leaves the scope, attempts to use it then would lead to memory corruption. +/ @system auto opSlice(size_t a, size_t b) pure nothrow @nogc { return sliceOverIndexed(a, b, &this); } /// ditto @system auto opSlice() pure nothrow @nogc { return sliceOverIndexed(0, length, &this); } /// Grapheme cluster length in $(CODEPOINTS). @property size_t length() const pure nothrow @nogc { return isBig ? len_ : slen_ & 0x7F; } /++ Append $(CHARACTER) $(D ch) to this grapheme. Warning: Use of this facility may invalidate grapheme cluster, see also $(D valid). See_Also: $(LREF Grapheme.valid) +/ ref opOpAssign(string op)(dchar ch) { static if(op == "~") { if(!isBig) { if(slen_ + 1 > small_cap) convertToBig();// & fallthrough to "big" branch else { write24(small_.ptr, ch, smallLength); slen_++; return this; } } assert(isBig); if(len_ + 1 > cap_) { cap_ += grow; ptr_ = cast(ubyte*)enforce(realloc(ptr_, 3*(cap_+1)), "realloc failed"); } write24(ptr_, ch, len_++); return this; } else static assert(false, "No operation "~op~" defined for Grapheme"); } /// unittest { import std.algorithm.comparison : equal; auto g = Grapheme("A"); assert(g.valid); g ~= '\u0301'; assert(g[].equal("A\u0301")); assert(g.valid); g ~= "B"; // not a valid grapheme cluster anymore assert(!g.valid); // still could be useful though assert(g[].equal("A\u0301B")); } /// Append all $(CHARACTERS) from the input range $(D inp) to this Grapheme. ref opOpAssign(string op, Input)(Input inp) if(isInputRange!Input && is(ElementType!Input : dchar)) { static if(op == "~") { foreach(dchar ch; inp) this ~= ch; return this; } else static assert(false, "No operation "~op~" defined for Grapheme"); } /++ True if this object contains valid extended grapheme cluster. Decoding primitives of this module always return a valid $(D Grapheme). Appending to and direct manipulation of grapheme's $(CHARACTERS) may render it no longer valid. Certain applications may chose to use Grapheme as a "small string" of any $(CODEPOINTS) and ignore this property entirely. +/ @property bool valid()() /*const*/ { auto r = this[]; genericDecodeGrapheme!false(r); return r.length == 0; } this(this) { if(isBig) {// dup it auto raw_cap = 3*(cap_+1); auto p = cast(ubyte*)enforce(malloc(raw_cap), "malloc failed"); p[0..raw_cap] = ptr_[0..raw_cap]; ptr_ = p; } } ~this() { if(isBig) { free(ptr_); } } private: enum small_bytes = ((ubyte*).sizeof+3*size_t.sizeof-1); // "out of the blue" grow rate, needs testing // (though graphemes are typically small < 9) enum grow = 20; enum small_cap = small_bytes/3; enum small_flag = 0x80, small_mask = 0x7F; // 16 bytes in 32bits, should be enough for the majority of cases union { struct { ubyte* ptr_; size_t cap_; size_t len_; size_t padding_; } struct { ubyte[small_bytes] small_; ubyte slen_; } } void convertToBig() { size_t k = smallLength; ubyte* p = cast(ubyte*)enforce(malloc(3*(grow+1)), "malloc failed"); for(int i=0; i len_); cap_ = grow; setBig(); } void setBig() pure nothrow @nogc { slen_ |= small_flag; } @property size_t smallLength() const pure nothrow @nogc { return slen_ & small_mask; } @property ubyte isBig() const pure nothrow @nogc { return slen_ & small_flag; } } static assert(Grapheme.sizeof == size_t.sizeof*4); /// unittest { import std.algorithm : filter; string bold = "ku\u0308hn"; // note that decodeGrapheme takes parameter by ref auto first = decodeGrapheme(bold); assert(first.length == 1); assert(first[0] == 'k'); // the next grapheme is 2 characters long auto wideOne = decodeGrapheme(bold); // slicing a grapheme yields a random-access range of dchar assert(wideOne[].equalS("u\u0308")); assert(wideOne.length == 2); static assert(isRandomAccessRange!(typeof(wideOne[]))); // all of the usual range manipulation is possible assert(wideOne[].filter!isMark().equalS("\u0308")); auto g = Grapheme("A"); assert(g.valid); g ~= '\u0301'; assert(g[].equalS("A\u0301")); assert(g.valid); g ~= "B"; // not a valid grapheme cluster anymore assert(!g.valid); // still could be useful though assert(g[].equalS("A\u0301B")); } unittest { auto g = Grapheme("A\u0302"); assert(g[0] == 'A'); assert(g.valid); g[1] = '~'; // ASCII tilda is not a combining mark assert(g[1] == '~'); assert(!g.valid); } unittest { import std.conv; import std.algorithm; import std.range; // not valid clusters (but it just a test) auto g = Grapheme('a', 'b', 'c', 'd', 'e'); assert(g[0] == 'a'); assert(g[1] == 'b'); assert(g[2] == 'c'); assert(g[3] == 'd'); assert(g[4] == 'e'); g[3] = 'Й'; assert(g[2] == 'c'); assert(g[3] == 'Й', text(g[3], " vs ", 'Й')); assert(g[4] == 'e'); assert(!g.valid); g ~= 'ц'; g ~= '~'; assert(g[0] == 'a'); assert(g[1] == 'b'); assert(g[2] == 'c'); assert(g[3] == 'Й'); assert(g[4] == 'e'); assert(g[5] == 'ц'); assert(g[6] == '~'); assert(!g.valid); Grapheme copy = g; copy[0] = 'X'; copy[1] = '-'; assert(g[0] == 'a' && copy[0] == 'X'); assert(g[1] == 'b' && copy[1] == '-'); assert(equalS(g[2..g.length], copy[2..copy.length])); copy = Grapheme("АБВГДЕЁЖЗИКЛМ"); assert(equalS(copy[0..8], "АБВГДЕЁЖ"), text(copy[0..8])); copy ~= "xyz"; assert(equalS(copy[13..15], "xy"), text(copy[13..15])); assert(!copy.valid); Grapheme h; foreach(dchar v; iota(cast(int)'A', cast(int)'Z'+1).map!"cast(dchar)a"()) h ~= v; assert(equalS(h[], iota(cast(int)'A', cast(int)'Z'+1))); } /++ $(P Does basic case-insensitive comparison of strings $(D str1) and $(D str2). This function uses simpler comparison rule thus achieving better performance than $(LREF icmp). However keep in mind the warning below.) Params: str1 = a string or a $(D ForwardRange) of $(D dchar)s str2 = a string or a $(D ForwardRange) of $(D dchar)s Returns: An $(D int) that is 0 if the strings match, <0 if $(D str1) is lexicographically "less" than $(D str2), >0 if $(D str1) is lexicographically "greater" than $(D str2) Warning: This function only handles 1:1 $(CODEPOINT) mapping and thus is not sufficient for certain alphabets like German, Greek and few others. See_Also: $(LREF icmp) $(XREF_PACK algorithm,comparison,cmp) +/ int sicmp(S1, S2)(S1 str1, S2 str2) if(isForwardRange!S1 && is(Unqual!(ElementType!S1) == dchar) && isForwardRange!S2 && is(Unqual!(ElementType!S2) == dchar)) { alias sTable = simpleCaseTable; size_t ridx=0; foreach(dchar lhs; str1) { if(ridx == str2.length) return 1; import std.utf : decode; dchar rhs = decode(str2, ridx); int diff = lhs - rhs; if(!diff) continue; size_t idx = simpleCaseTrie[lhs]; size_t idx2 = simpleCaseTrie[rhs]; // simpleCaseTrie is packed index table if(idx != EMPTY_CASE_TRIE) { if(idx2 != EMPTY_CASE_TRIE) {// both cased chars // adjust idx --> start of bucket idx = idx - sTable[idx].n; idx2 = idx2 - sTable[idx2].n; if(idx == idx2)// one bucket, equivalent chars continue; else// not the same bucket diff = sTable[idx].ch - sTable[idx2].ch; } else diff = sTable[idx - sTable[idx].n].ch - rhs; } else if(idx2 != EMPTY_CASE_TRIE) { diff = lhs - sTable[idx2 - sTable[idx2].n].ch; } // one of chars is not cased at all return diff; } return ridx == str2.length ? 0 : -1; } /// unittest{ assert(sicmp("Август", "авгусТ") == 0); // Greek also works as long as there is no 1:M mapping in sight assert(sicmp("ΌΎ", "όύ") == 0); // things like the following won't get matched as equal // Greek small letter iota with dialytika and tonos assert(sicmp("ΐ", "\u03B9\u0308\u0301") != 0); // while icmp has no problem with that assert(icmp("ΐ", "\u03B9\u0308\u0301") == 0); assert(icmp("ΌΎ", "όύ") == 0); } // overloads for the most common cases to reduce compile time @safe pure /*TODO nothrow*/ { int sicmp(const(char)[] str1, const(char)[] str2) { return sicmp!(const(char)[], const(char)[])(str1, str2); } int sicmp(const(wchar)[] str1, const(wchar)[] str2) { return sicmp!(const(wchar)[], const(wchar)[])(str1, str2); } int sicmp(const(dchar)[] str1, const(dchar)[] str2) { return sicmp!(const(dchar)[], const(dchar)[])(str1, str2); } } private int fullCasedCmp(Range)(dchar lhs, dchar rhs, ref Range rtail) @trusted pure /*TODO nothrow*/ { import std.algorithm : skipOver; alias fTable = fullCaseTable; size_t idx = fullCaseTrie[lhs]; // fullCaseTrie is packed index table if(idx == EMPTY_CASE_TRIE) return lhs; size_t start = idx - fTable[idx].n; size_t end = fTable[idx].size + start; assert(fTable[start].entry_len == 1); for(idx=start; idx sequence int cmpLR = fullCasedCmp(lhs, rhs, str2); if(!cmpLR) continue; // then rhs to sequence int cmpRL = fullCasedCmp(rhs, lhs, str1); if(!cmpRL) continue; // cmpXX contain remapped codepoints // to obtain stable ordering of icmp diff = cmpLR - cmpRL; return diff; } } /// unittest{ assert(icmp("Rußland", "Russland") == 0); assert(icmp("ᾩ -> \u1F70\u03B9", "\u1F61\u03B9 -> ᾲ") == 0); } // overloads for the most common cases to reduce compile time @safe pure /*TODO nothrow*/ { int icmp(const(char)[] str1, const(char)[] str2) { return icmp!(const(char)[], const(char)[])(str1, str2); } int icmp(const(wchar)[] str1, const(wchar)[] str2) { return icmp!(const(wchar)[], const(wchar)[])(str1, str2); } int icmp(const(dchar)[] str1, const(dchar)[] str2) { return icmp!(const(dchar)[], const(dchar)[])(str1, str2); } } unittest { import std.conv; import std.exception : assertCTFEable; import std.algorithm; assertCTFEable!( { foreach(cfunc; AliasSeq!(icmp, sicmp)) { foreach(S1; AliasSeq!(string, wstring, dstring)) foreach(S2; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(cfunc("".to!S1(), "".to!S2()) == 0); assert(cfunc("A".to!S1(), "".to!S2()) > 0); assert(cfunc("".to!S1(), "0".to!S2()) < 0); assert(cfunc("abc".to!S1(), "abc".to!S2()) == 0); assert(cfunc("abcd".to!S1(), "abc".to!S2()) > 0); assert(cfunc("abc".to!S1(), "abcd".to!S2()) < 0); assert(cfunc("Abc".to!S1(), "aBc".to!S2()) == 0); assert(cfunc("авГуст".to!S1(), "АВгУСТ".to!S2()) == 0); // Check example: assert(cfunc("Август".to!S1(), "авгусТ".to!S2()) == 0); assert(cfunc("ΌΎ".to!S1(), "όύ".to!S2()) == 0); }(); // check that the order is properly agnostic to the case auto strs = [ "Apple", "ORANGE", "orAcle", "amp", "banana"]; sort!((a,b) => cfunc(a,b) < 0)(strs); assert(strs == ["amp", "Apple", "banana", "orAcle", "ORANGE"]); } assert(icmp("ßb", "ssa") > 0); // Check example: assert(icmp("Russland", "Rußland") == 0); assert(icmp("ᾩ -> \u1F70\u03B9", "\u1F61\u03B9 -> ᾲ") == 0); assert(icmp("ΐ"w, "\u03B9\u0308\u0301") == 0); assert(sicmp("ΐ", "\u03B9\u0308\u0301") != 0); //bugzilla 11057 assert( icmp("K", "L") < 0 ); }); } // This is package for the moment to be used as a support tool for std.regex // It needs a better API /* Return a range of all $(CODEPOINTS) that casefold to and from this $(D ch). */ package auto simpleCaseFoldings(dchar ch) { alias sTable = simpleCaseTable; static struct Range { pure nothrow: uint idx; //if == uint.max, then read c. union { dchar c; // == 0 - empty range uint len; } @property bool isSmall() const { return idx == uint.max; } this(dchar ch) { idx = uint.max; c = ch; } this(uint start, uint size) { idx = start; len = size; } @property dchar front() const { assert(!empty); if(isSmall) { return c; } auto ch = sTable[idx].ch; return ch; } @property bool empty() const { if(isSmall) { return c == 0; } return len == 0; } @property uint length() const { if(isSmall) { return c == 0 ? 0 : 1; } return len; } void popFront() { if(isSmall) c = 0; else { idx++; len--; } } } immutable idx = simpleCaseTrie[ch]; if (idx == EMPTY_CASE_TRIE) return Range(ch); auto entry = sTable[idx]; immutable start = idx - entry.n; return Range(start, entry.size); } unittest { import std.exception : assertCTFEable; import std.algorithm : canFind; import std.array; assertCTFEable!((){ auto r = simpleCaseFoldings('Э').array; assert(r.length == 2); assert(r.canFind('э') && r.canFind('Э')); auto sr = simpleCaseFoldings('~'); assert(sr.equalS("~")); //A with ring above - casefolds to the same bucket as Angstrom sign sr = simpleCaseFoldings('Å'); assert(sr.length == 3); assert(sr.canFind('å') && sr.canFind('Å') && sr.canFind('\u212B')); }); } /++ $(P Returns the $(S_LINK Combining class, combining class) of $(D ch).) +/ ubyte combiningClass(dchar ch) @safe pure nothrow @nogc { return combiningClassTrie[ch]; } /// unittest{ // shorten the code alias CC = combiningClass; // combining tilda assert(CC('\u0303') == 230); // combining ring below assert(CC('\u0325') == 220); // the simple consequence is that "tilda" should be // placed after a "ring below" in a sequence } @safe pure nothrow @nogc unittest { foreach(ch; 0..0x80) assert(combiningClass(ch) == 0); assert(combiningClass('\u05BD') == 22); assert(combiningClass('\u0300') == 230); assert(combiningClass('\u0317') == 220); assert(combiningClass('\u1939') == 222); } /// Unicode character decomposition type. enum UnicodeDecomposition { /// Canonical decomposition. The result is canonically equivalent sequence. Canonical, /** Compatibility decomposition. The result is compatibility equivalent sequence. Note: Compatibility decomposition is a $(B lossy) conversion, typically suitable only for fuzzy matching and internal processing. */ Compatibility } /** Shorthand aliases for character decomposition type, passed as a template parameter to $(LREF decompose). */ enum { Canonical = UnicodeDecomposition.Canonical, Compatibility = UnicodeDecomposition.Compatibility }; /++ Try to canonically compose 2 $(CHARACTERS). Returns the composed $(CHARACTER) if they do compose and dchar.init otherwise. The assumption is that $(D first) comes before $(D second) in the original text, usually meaning that the first is a starter. Note: Hangul syllables are not covered by this function. See $(D composeJamo) below. +/ public dchar compose(dchar first, dchar second) pure nothrow { import std.internal.unicode_comp; import std.algorithm : map; import std.range : assumeSorted; size_t packed = compositionJumpTrie[first]; if(packed == ushort.max) return dchar.init; // unpack offset and length size_t idx = packed & composeIdxMask, cnt = packed >> composeCntShift; // TODO: optimize this micro binary search (no more then 4-5 steps) auto r = compositionTable[idx..idx+cnt].map!"a.rhs"().assumeSorted(); auto target = r.lowerBound(second).length; if(target == cnt) return dchar.init; auto entry = compositionTable[idx+target]; if(entry.rhs != second) return dchar.init; return entry.composed; } /// unittest{ assert(compose('A','\u0308') == '\u00C4'); assert(compose('A', 'B') == dchar.init); assert(compose('C', '\u0301') == '\u0106'); // note that the starter is the first one // thus the following doesn't compose assert(compose('\u0308', 'A') == dchar.init); } /++ Returns a full $(S_LINK Canonical decomposition, Canonical) (by default) or $(S_LINK Compatibility decomposition, Compatibility) decomposition of $(CHARACTER) $(D ch). If no decomposition is available returns a $(LREF Grapheme) with the $(D ch) itself. Note: This function also decomposes hangul syllables as prescribed by the standard. See_Also: $(LREF decomposeHangul) for a restricted version that takes into account only hangul syllables but no other decompositions. +/ public Grapheme decompose(UnicodeDecomposition decompType=Canonical)(dchar ch) { import std.internal.unicode_decomp; import std.algorithm : until; static if(decompType == Canonical) { alias table = decompCanonTable; alias mapping = canonMappingTrie; } else static if(decompType == Compatibility) { alias table = decompCompatTable; alias mapping = compatMappingTrie; } ushort idx = mapping[ch]; if(!idx) // not found, check hangul arithmetic decomposition return decomposeHangul(ch); auto decomp = table[idx..$].until(0); return Grapheme(decomp); } /// unittest { assert(compose('A','\u0308') == '\u00C4'); assert(compose('A', 'B') == dchar.init); assert(compose('C', '\u0301') == '\u0106'); // note that the starter is the first one // thus the following doesn't compose assert(compose('\u0308', 'A') == dchar.init); assert(decompose('Ĉ')[].equalS("C\u0302")); assert(decompose('D')[].equalS("D")); assert(decompose('\uD4DC')[].equalS("\u1111\u1171\u11B7")); assert(decompose!Compatibility('¹')[].equalS("1")); } //---------------------------------------------------------------------------- // Hangul specific composition/decomposition enum jamoSBase = 0xAC00; enum jamoLBase = 0x1100; enum jamoVBase = 0x1161; enum jamoTBase = 0x11A7; enum jamoLCount = 19, jamoVCount = 21, jamoTCount = 28; enum jamoNCount = jamoVCount * jamoTCount; enum jamoSCount = jamoLCount * jamoNCount; // Tests if $(D ch) is a Hangul leading consonant jamo. bool isJamoL(dchar ch) pure nothrow @nogc { // first cmp rejects ~ 1M code points above leading jamo range return ch < jamoLBase+jamoLCount && ch >= jamoLBase; } // Tests if $(D ch) is a Hangul vowel jamo. bool isJamoT(dchar ch) pure nothrow @nogc { // first cmp rejects ~ 1M code points above trailing jamo range // Note: ch == jamoTBase doesn't indicate trailing jamo (TIndex must be > 0) return ch < jamoTBase+jamoTCount && ch > jamoTBase; } // Tests if $(D ch) is a Hangul trailnig consonant jamo. bool isJamoV(dchar ch) pure nothrow @nogc { // first cmp rejects ~ 1M code points above vowel range return ch < jamoVBase+jamoVCount && ch >= jamoVBase; } int hangulSyllableIndex(dchar ch) pure nothrow @nogc { int idxS = cast(int)ch - jamoSBase; return idxS >= 0 && idxS < jamoSCount ? idxS : -1; } // internal helper: compose hangul syllables leaving dchar.init in holes void hangulRecompose(dchar[] seq) pure nothrow @nogc { for(size_t idx = 0; idx + 1 < seq.length; ) { if(isJamoL(seq[idx]) && isJamoV(seq[idx+1])) { int indexL = seq[idx] - jamoLBase; int indexV = seq[idx+1] - jamoVBase; int indexLV = indexL * jamoNCount + indexV * jamoTCount; if(idx + 2 < seq.length && isJamoT(seq[idx+2])) { seq[idx] = jamoSBase + indexLV + seq[idx+2] - jamoTBase; seq[idx+1] = dchar.init; seq[idx+2] = dchar.init; idx += 3; } else { seq[idx] = jamoSBase + indexLV; seq[idx+1] = dchar.init; idx += 2; } } else idx++; } } //---------------------------------------------------------------------------- public: /** Decomposes a Hangul syllable. If $(D ch) is not a composed syllable then this function returns $(LREF Grapheme) containing only $(D ch) as is. */ Grapheme decomposeHangul(dchar ch) { int idxS = cast(int)ch - jamoSBase; if(idxS < 0 || idxS >= jamoSCount) return Grapheme(ch); int idxL = idxS / jamoNCount; int idxV = (idxS % jamoNCount) / jamoTCount; int idxT = idxS % jamoTCount; int partL = jamoLBase + idxL; int partV = jamoVBase + idxV; if(idxT > 0) // there is a trailling consonant (T); decomposition return Grapheme(partL, partV, jamoTBase + idxT); else // decomposition return Grapheme(partL, partV); } /// unittest { import std.algorithm; assert(decomposeHangul('\uD4DB')[].equal("\u1111\u1171\u11B6")); } /++ Try to compose hangul syllable out of a leading consonant ($(D lead)), a $(D vowel) and optional $(D trailing) consonant jamos. On success returns the composed LV or LVT hangul syllable. If any of $(D lead) and $(D vowel) are not a valid hangul jamo of the respective $(CHARACTER) class returns dchar.init. +/ dchar composeJamo(dchar lead, dchar vowel, dchar trailing=dchar.init) pure nothrow @nogc { if(!isJamoL(lead)) return dchar.init; int indexL = lead - jamoLBase; if(!isJamoV(vowel)) return dchar.init; int indexV = vowel - jamoVBase; int indexLV = indexL * jamoNCount + indexV * jamoTCount; dchar syllable = jamoSBase + indexLV; return isJamoT(trailing) ? syllable + (trailing - jamoTBase) : syllable; } /// unittest { assert(composeJamo('\u1111', '\u1171', '\u11B6') == '\uD4DB'); // leaving out T-vowel, or passing any codepoint // that is not trailing consonant composes an LV-syllable assert(composeJamo('\u1111', '\u1171') == '\uD4CC'); assert(composeJamo('\u1111', '\u1171', ' ') == '\uD4CC'); assert(composeJamo('\u1111', 'A') == dchar.init); assert(composeJamo('A', '\u1171') == dchar.init); } unittest { import std.conv; static void testDecomp(UnicodeDecomposition T)(dchar ch, string r) { Grapheme g = decompose!T(ch); assert(equalS(g[], r), text(g[], " vs ", r)); } testDecomp!Canonical('\u1FF4', "\u03C9\u0301\u0345"); testDecomp!Canonical('\uF907', "\u9F9C"); testDecomp!Compatibility('\u33FF', "\u0067\u0061\u006C"); testDecomp!Compatibility('\uA7F9', "\u0153"); // check examples assert(decomposeHangul('\uD4DB')[].equalS("\u1111\u1171\u11B6")); assert(composeJamo('\u1111', '\u1171', '\u11B6') == '\uD4DB'); assert(composeJamo('\u1111', '\u1171') == '\uD4CC'); // leave out T-vowel assert(composeJamo('\u1111', '\u1171', ' ') == '\uD4CC'); assert(composeJamo('\u1111', 'A') == dchar.init); assert(composeJamo('A', '\u1171') == dchar.init); } /** Enumeration type for normalization forms, passed as template parameter for functions like $(LREF normalize). */ enum NormalizationForm { NFC, NFD, NFKC, NFKD } enum { /** Shorthand aliases from values indicating normalization forms. */ NFC = NormalizationForm.NFC, ///ditto NFD = NormalizationForm.NFD, ///ditto NFKC = NormalizationForm.NFKC, ///ditto NFKD = NormalizationForm.NFKD }; /++ Returns $(D input) string normalized to the chosen form. Form C is used by default. For more information on normalization forms see the $(S_LINK Normalization, normalization section). Note: In cases where the string in question is already normalized, it is returned unmodified and no memory allocation happens. +/ inout(C)[] normalize(NormalizationForm norm=NFC, C)(inout(C)[] input) { import std.algorithm : sort, SwapStrategy; import std.range : zip; import std.array : appender; auto anchors = splitNormalized!norm(input); if(anchors[0] == input.length && anchors[1] == input.length) return input; dchar[] decomposed; decomposed.reserve(31); ubyte[] ccc; ccc.reserve(31); auto app = appender!(C[])(); do { app.put(input[0..anchors[0]]); foreach(dchar ch; input[anchors[0]..anchors[1]]) static if(norm == NFD || norm == NFC) { foreach(dchar c; decompose!Canonical(ch)[]) decomposed ~= c; } else // NFKD & NFKC { foreach(dchar c; decompose!Compatibility(ch)[]) decomposed ~= c; } ccc.length = decomposed.length; size_t firstNonStable = 0; ubyte lastClazz = 0; foreach(idx, dchar ch; decomposed) { auto clazz = combiningClass(ch); ccc[idx] = clazz; if(clazz == 0 && lastClazz != 0) { // found a stable code point after unstable ones sort!("a[0] < b[0]", SwapStrategy.stable) (zip(ccc[firstNonStable..idx], decomposed[firstNonStable..idx])); firstNonStable = decomposed.length; } else if(clazz != 0 && lastClazz == 0) { // found first unstable code point after stable ones firstNonStable = idx; } lastClazz = clazz; } sort!("a[0] < b[0]", SwapStrategy.stable) (zip(ccc[firstNonStable..$], decomposed[firstNonStable..$])); static if(norm == NFC || norm == NFKC) { import std.algorithm : countUntil; size_t idx = 0; auto first = countUntil(ccc, 0); if(first >= 0) // no starters?? no recomposition { for(;;) { auto second = recompose(first, decomposed, ccc); if(second == decomposed.length) break; first = second; } // 2nd pass for hangul syllables hangulRecompose(decomposed); } } static if(norm == NFD || norm == NFKD) app.put(decomposed); else { import std.algorithm : remove; auto clean = remove!("a == dchar.init", SwapStrategy.stable)(decomposed); app.put(decomposed[0 .. clean.length]); } // reset variables decomposed.length = 0; decomposed.assumeSafeAppend(); ccc.length = 0; ccc.assumeSafeAppend(); input = input[anchors[1]..$]; // and move on anchors = splitNormalized!norm(input); }while(anchors[0] != input.length); app.put(input[0..anchors[0]]); return cast(inout(C)[])app.data; } /// unittest { // any encoding works wstring greet = "Hello world"; assert(normalize(greet) is greet); // the same exact slice // An example of a character with all 4 forms being different: // Greek upsilon with acute and hook symbol (code point 0x03D3) assert(normalize!NFC("ϓ") == "\u03D3"); assert(normalize!NFD("ϓ") == "\u03D2\u0301"); assert(normalize!NFKC("ϓ") == "\u038E"); assert(normalize!NFKD("ϓ") == "\u03A5\u0301"); } unittest { import std.conv; assert(normalize!NFD("abc\uF904def") == "abc\u6ED1def", text(normalize!NFD("abc\uF904def"))); assert(normalize!NFKD("2¹⁰") == "210", normalize!NFKD("2¹⁰")); assert(normalize!NFD("Äffin") == "A\u0308ffin"); // check example // any encoding works wstring greet = "Hello world"; assert(normalize(greet) is greet); // the same exact slice // An example of a character with all 4 forms being different: // Greek upsilon with acute and hook symbol (code point 0x03D3) assert(normalize!NFC("ϓ") == "\u03D3"); assert(normalize!NFD("ϓ") == "\u03D2\u0301"); assert(normalize!NFKC("ϓ") == "\u038E"); assert(normalize!NFKD("ϓ") == "\u03A5\u0301"); } // canonically recompose given slice of code points, works in-place and mutates data private size_t recompose(size_t start, dchar[] input, ubyte[] ccc) pure nothrow { assert(input.length == ccc.length); int accumCC = -1;// so that it's out of 0..255 range bool foundSolidStarter = false; // writefln("recomposing %( %04x %)", input); // first one is always a starter thus we start at i == 1 size_t i = start+1; for(; ; ) { if(i == input.length) break; int curCC = ccc[i]; // In any character sequence beginning with a starter S // a character C is blocked from S if and only if there // is some character B between S and C, and either B // is a starter or it has the same or higher combining class as C. //------------------------ // Applying to our case: // S is input[0] // accumCC is the maximum CCC of characters between C and S, // as ccc are sorted // C is input[i] if(curCC > accumCC) { dchar comp = compose(input[start], input[i]); if(comp != dchar.init) { input[start] = comp; input[i] = dchar.init;// put a sentinel // current was merged so its CCC shouldn't affect // composing with the next one } else { // if it was a starter then accumCC is now 0, end of loop accumCC = curCC; if(accumCC == 0) break; } } else{ // ditto here accumCC = curCC; if(accumCC == 0) break; } i++; } return i; } // returns tuple of 2 indexes that delimit: // normalized text, piece that needs normalization and // the rest of input starting with stable code point private auto splitNormalized(NormalizationForm norm, C)(const(C)[] input) { import std.typecons : tuple; auto result = input; ubyte lastCC = 0; foreach(idx, dchar ch; input) { static if(norm == NFC) if(ch < 0x0300) { lastCC = 0; continue; } ubyte CC = combiningClass(ch); if(lastCC > CC && CC != 0) { return seekStable!norm(idx, input); } if(notAllowedIn!norm(ch)) { return seekStable!norm(idx, input); } lastCC = CC; } return tuple(input.length, input.length); } private auto seekStable(NormalizationForm norm, C)(size_t idx, in C[] input) { import std.utf : codeLength; import std.typecons : tuple; auto br = input[0..idx]; size_t region_start = 0;// default for(;;) { if(br.empty)// start is 0 break; dchar ch = br.back; if(combiningClass(ch) == 0 && allowedIn!norm(ch)) { region_start = br.length - codeLength!C(ch); break; } br.popFront(); } ///@@@BUG@@@ can't use find: " find is a nested function and can't be used..." size_t region_end=input.length;// end is $ by default foreach(i, dchar ch; input[idx..$]) { if(combiningClass(ch) == 0 && allowedIn!norm(ch)) { region_end = i+idx; break; } } // writeln("Region to normalize: ", input[region_start..region_end]); return tuple(region_start, region_end); } /** Tests if dchar $(D ch) is always allowed (Quick_Check=YES) in normalization form $(D norm). */ public bool allowedIn(NormalizationForm norm)(dchar ch) { return !notAllowedIn!norm(ch); } /// unittest { // e.g. Cyrillic is always allowed, so is ASCII assert(allowedIn!NFC('я')); assert(allowedIn!NFD('я')); assert(allowedIn!NFKC('я')); assert(allowedIn!NFKD('я')); assert(allowedIn!NFC('Z')); } // not user friendly name but more direct private bool notAllowedIn(NormalizationForm norm)(dchar ch) { static if(norm == NFC) alias qcTrie = nfcQCTrie; else static if(norm == NFD) alias qcTrie = nfdQCTrie; else static if(norm == NFKC) alias qcTrie = nfkcQCTrie; else static if(norm == NFKD) alias qcTrie = nfkdQCTrie; else static assert("Unknown normalization form "~norm); return qcTrie[ch]; } unittest { assert(allowedIn!NFC('я')); assert(allowedIn!NFD('я')); assert(allowedIn!NFKC('я')); assert(allowedIn!NFKD('я')); assert(allowedIn!NFC('Z')); } } version(std_uni_bootstrap) { // old version used for bootstrapping of gen_uni.d that generates // up to date optimal versions of all of isXXX functions @safe pure nothrow @nogc public bool isWhite(dchar c) { import std.ascii : isWhite; return isWhite(c) || c == lineSep || c == paraSep || c == '\u0085' || c == '\u00A0' || c == '\u1680' || c == '\u180E' || (c >= '\u2000' && c <= '\u200A') || c == '\u202F' || c == '\u205F' || c == '\u3000'; } } else { // trusted -> avoid bounds check @trusted pure nothrow @nogc { // hide template instances behind functions (Bugzilla 13232) ushort toLowerIndex(dchar c) { return toLowerIndexTrie[c]; } ushort toLowerSimpleIndex(dchar c) { return toLowerSimpleIndexTrie[c]; } dchar toLowerTab(size_t idx) { return toLowerTable[idx]; } ushort toTitleIndex(dchar c) { return toTitleIndexTrie[c]; } ushort toTitleSimpleIndex(dchar c) { return toTitleSimpleIndexTrie[c]; } dchar toTitleTab(size_t idx) { return toTitleTable[idx]; } ushort toUpperIndex(dchar c) { return toUpperIndexTrie[c]; } ushort toUpperSimpleIndex(dchar c) { return toUpperSimpleIndexTrie[c]; } dchar toUpperTab(size_t idx) { return toUpperTable[idx]; } } public: /++ Whether or not $(D c) is a Unicode whitespace $(CHARACTER). (general Unicode category: Part of C0(tab, vertical tab, form feed, carriage return, and linefeed characters), Zs, Zl, Zp, and NEL(U+0085)) +/ @safe pure nothrow @nogc public bool isWhite(dchar c) { return isWhiteGen(c); // call pregenerated binary search } /++ Return whether $(D c) is a Unicode lowercase $(CHARACTER). +/ @safe pure nothrow @nogc bool isLower(dchar c) { import std.ascii : isLower, isASCII; if(isASCII(c)) return isLower(c); return lowerCaseTrie[c]; } @safe unittest { import std.ascii : isLower; foreach(v; 0..0x80) assert(isLower(v) == .isLower(v)); assert(.isLower('я')); assert(.isLower('й')); assert(!.isLower('Ж')); // Greek HETA assert(!.isLower('\u0370')); assert(.isLower('\u0371')); assert(!.isLower('\u039C')); // capital MU assert(.isLower('\u03B2')); // beta // from extended Greek assert(!.isLower('\u1F18')); assert(.isLower('\u1F00')); foreach(v; unicode.lowerCase.byCodepoint) assert(.isLower(v) && !isUpper(v)); } /++ Return whether $(D c) is a Unicode uppercase $(CHARACTER). +/ @safe pure nothrow @nogc bool isUpper(dchar c) { import std.ascii : isUpper, isASCII; if(isASCII(c)) return isUpper(c); return upperCaseTrie[c]; } @safe unittest { import std.ascii : isLower; foreach(v; 0..0x80) assert(isLower(v) == .isLower(v)); assert(!isUpper('й')); assert(isUpper('Ж')); // Greek HETA assert(isUpper('\u0370')); assert(!isUpper('\u0371')); assert(isUpper('\u039C')); // capital MU assert(!isUpper('\u03B2')); // beta // from extended Greek assert(!isUpper('\u1F00')); assert(isUpper('\u1F18')); foreach(v; unicode.upperCase.byCodepoint) assert(isUpper(v) && !.isLower(v)); } //TODO: Hidden for now, needs better API. //Other transforms could use better API as well, but this one is a new primitive. @safe pure nothrow @nogc private dchar toTitlecase(dchar c) { // optimize ASCII case if(c < 0xAA) { if(c < 'a') return c; if(c <= 'z') return c - 32; return c; } size_t idx = toTitleSimpleIndex(c); if(idx != ushort.max) { return toTitleTab(idx); } return c; } private alias UpperTriple = AliasSeq!(toUpperIndex, MAX_SIMPLE_UPPER, toUpperTab); private alias LowerTriple = AliasSeq!(toLowerIndex, MAX_SIMPLE_LOWER, toLowerTab); // generic toUpper/toLower on whole string, creates new or returns as is private S toCase(alias indexFn, uint maxIdx, alias tableFn, S)(S s) @trusted pure if(isSomeString!S) { import std.array : appender; foreach(i, dchar cOuter; s) { ushort idx = indexFn(cOuter); if(idx == ushort.max) continue; auto result = appender!S(s[0..i]); result.reserve(s.length); foreach(dchar c; s[i .. $]) { idx = indexFn(c); if(idx == ushort.max) result.put(c); else if(idx < maxIdx) { c = tableFn(idx); result.put(c); } else { auto val = tableFn(idx); // unpack length + codepoint uint len = val>>24; result.put(cast(dchar)(val & 0xFF_FFFF)); foreach(j; idx+1..idx+len) result.put(tableFn(j)); } } return result.data; } return s; } unittest //12428 { import std.array; auto s = "abcdefghij".replicate(300); s = s[0..10]; toUpper(s); assert(s == "abcdefghij"); } // generic toUpper/toLower on whole range, returns range private auto toCaser(alias indexFn, uint maxIdx, alias tableFn, Range)(Range str) // Accept range of dchar's if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && ElementEncodingType!Range.sizeof == dchar.sizeof) { static struct ToCaserImpl { @property bool empty() { return !nLeft && r.empty; } @property auto front() { if (!nLeft) { dchar c = r.front; const idx = indexFn(c); if (idx == ushort.max) { buf[0] = c; nLeft = 1; } else if (idx < maxIdx) { buf[0] = tableFn(idx); nLeft = 1; } else { auto val = tableFn(idx); // unpack length + codepoint nLeft = val >> 24; if (nLeft == 0) nLeft = 1; assert(nLeft <= buf.length); buf[nLeft - 1] = cast(dchar)(val & 0xFF_FFFF); foreach (j; 1 .. nLeft) buf[nLeft - j - 1] = tableFn(idx + j); } } return buf[nLeft - 1]; } void popFront() { if (!nLeft) front; assert(nLeft); --nLeft; if (!nLeft) r.popFront(); } static if (isForwardRange!Range) { @property auto save() { auto ret = this; ret.r = r.save; return ret; } } private: Range r; uint nLeft; dchar[3] buf = void; } return ToCaserImpl(str); } /********************* * Convert input range or string to upper or lower case. * * Does not allocate memory. * Characters in UTF-8 or UTF-16 format that cannot be decoded * are treated as $(XREF utf, replacementDchar). * * Params: * str = string or range of characters * * Returns: * an InputRange of dchars * * See_Also: * $(LREF toUpper), $(LREF toLower) */ auto asLowerCase(Range)(Range str) if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { static if (ElementEncodingType!Range.sizeof < dchar.sizeof) { import std.utf : byDchar; // Decode first return toCaser!LowerTriple(str.byDchar); } else { return toCaser!LowerTriple(str); } } /// ditto auto asUpperCase(Range)(Range str) if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { static if (ElementEncodingType!Range.sizeof < dchar.sizeof) { import std.utf : byDchar; // Decode first return toCaser!UpperTriple(str.byDchar); } else { return toCaser!UpperTriple(str); } } /// @safe pure unittest { import std.algorithm.comparison : equal; assert("hEllo".asUpperCase.equal("HELLO")); } auto asLowerCase(Range)(auto ref Range str) if (isConvertibleToString!Range) { return asLowerCase!(StringTypeOf!Range)(str); } auto asUpperCase(Range)(auto ref Range str) if (isConvertibleToString!Range) { return asUpperCase!(StringTypeOf!Range)(str); } unittest { assert(testAliasedString!asLowerCase("hEllo")); assert(testAliasedString!asUpperCase("hEllo")); } unittest { import std.array; auto a = "HELLo".asLowerCase; auto savea = a.save; auto s = a.array; assert(s == "hello"); s = savea.array; assert(s == "hello"); string[] lower = ["123", "abcфеж", "\u0131\u023f\u03c9", "i\u0307\u1Fe2"]; string[] upper = ["123", "ABCФЕЖ", "I\u2c7e\u2126", "\u0130\u03A5\u0308\u0300"]; foreach (i, slwr; lower) { import std.utf : byChar; auto sx = slwr.asUpperCase.byChar.array; assert(sx == toUpper(slwr)); auto sy = upper[i].asLowerCase.byChar.array; assert(sy == toLower(upper[i])); } // Not necessary to call r.front for (auto r = lower[3].asUpperCase; !r.empty; r.popFront()) { } import std.algorithm.comparison : equal; "HELLo"w.asLowerCase.equal("hello"d); "HELLo"w.asUpperCase.equal("HELLO"d); "HELLo"d.asLowerCase.equal("hello"d); "HELLo"d.asUpperCase.equal("HELLO"d); import std.utf : byChar; assert(toLower("\u1Fe2") == asLowerCase("\u1Fe2").byChar.array); } // generic capitalizer on whole range, returns range private auto toCapitalizer(alias indexFnUpper, uint maxIdxUpper, alias tableFnUpper, Range)(Range str) // Accept range of dchar's if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && ElementEncodingType!Range.sizeof == dchar.sizeof) { static struct ToCapitalizerImpl { @property bool empty() { return lower ? lwr.empty : !nLeft && r.empty; } @property auto front() { if (lower) return lwr.front; if (!nLeft) { dchar c = r.front; const idx = indexFnUpper(c); if (idx == ushort.max) { buf[0] = c; nLeft = 1; } else if (idx < maxIdxUpper) { buf[0] = tableFnUpper(idx); nLeft = 1; } else { auto val = tableFnUpper(idx); // unpack length + codepoint nLeft = val >> 24; if (nLeft == 0) nLeft = 1; assert(nLeft <= buf.length); buf[nLeft - 1] = cast(dchar)(val & 0xFF_FFFF); foreach (j; 1 .. nLeft) buf[nLeft - j - 1] = tableFnUpper(idx + j); } } return buf[nLeft - 1]; } void popFront() { if (lower) lwr.popFront(); else { if (!nLeft) front; assert(nLeft); --nLeft; if (!nLeft) { r.popFront(); lwr = r.asLowerCase(); lower = true; } } } static if (isForwardRange!Range) { @property auto save() { auto ret = this; ret.r = r.save; ret.lwr = lwr.save; return ret; } } private: Range r; typeof(r.asLowerCase) lwr; // range representing the lower case rest of string bool lower = false; // false for first character, true for rest of string dchar[3] buf = void; uint nLeft = 0; } return ToCapitalizerImpl(str); } /********************* * Capitalize input range or string, meaning convert the first * character to upper case and subsequent characters to lower case. * * Does not allocate memory. * Characters in UTF-8 or UTF-16 format that cannot be decoded * are treated as $(XREF utf, replacementDchar). * * Params: * str = string or range of characters * * Returns: * an InputRange of dchars * * See_Also: * $(LREF toUpper), $(LREF toLower) * $(LREF asUpperCase), $(LREF asLowerCase) */ auto asCapitalized(Range)(Range str) if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { static if (ElementEncodingType!Range.sizeof < dchar.sizeof) { import std.utf : byDchar; // Decode first return toCapitalizer!UpperTriple(str.byDchar); } else { return toCapitalizer!UpperTriple(str); } } /// @safe pure unittest { import std.algorithm.comparison : equal; assert("hEllo".asCapitalized.equal("Hello")); } auto asCapitalized(Range)(auto ref Range str) if (isConvertibleToString!Range) { return asCapitalized!(StringTypeOf!Range)(str); } unittest { assert(testAliasedString!asCapitalized("hEllo")); } @safe pure nothrow @nogc unittest { auto r = "hEllo".asCapitalized(); assert(r.front == 'H'); } unittest { import std.array; auto a = "hELLo".asCapitalized; auto savea = a.save; auto s = a.array; assert(s == "Hello"); s = savea.array; assert(s == "Hello"); string[2][] cases = [ ["", ""], ["h", "H"], ["H", "H"], ["3", "3"], ["123", "123"], ["h123A", "H123a"], ["феж", "Феж"], ["\u1Fe2", "\u03a5\u0308\u0300"], ]; foreach (i; 0 .. cases.length) { import std.utf : byChar; auto r = cases[i][0].asCapitalized.byChar.array; auto result = cases[i][1]; assert(r == result); } // Don't call r.front for (auto r = "\u1Fe2".asCapitalized; !r.empty; r.popFront()) { } import std.algorithm.comparison : equal; "HELLo"w.asCapitalized.equal("Hello"d); "hElLO"w.asCapitalized.equal("Hello"d); "hello"d.asCapitalized.equal("Hello"d); "HELLO"d.asCapitalized.equal("Hello"d); import std.utf : byChar; assert(asCapitalized("\u0130").byChar.array == asUpperCase("\u0130").byChar.array); } // TODO: helper, I wish std.utf was more flexible (and stright) private size_t encodeTo(char[] buf, size_t idx, dchar c) @trusted pure nothrow @nogc { if (c <= 0x7F) { buf[idx] = cast(char)c; idx++; } else if (c <= 0x7FF) { buf[idx] = cast(char)(0xC0 | (c >> 6)); buf[idx+1] = cast(char)(0x80 | (c & 0x3F)); idx += 2; } else if (c <= 0xFFFF) { buf[idx] = cast(char)(0xE0 | (c >> 12)); buf[idx+1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[idx+2] = cast(char)(0x80 | (c & 0x3F)); idx += 3; } else if (c <= 0x10FFFF) { buf[idx] = cast(char)(0xF0 | (c >> 18)); buf[idx+1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); buf[idx+2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[idx+3] = cast(char)(0x80 | (c & 0x3F)); idx += 4; } else assert(0); return idx; } unittest { char[] s = "abcd".dup; size_t i = 0; i = encodeTo(s, i, 'X'); assert(s == "Xbcd"); i = encodeTo(s, i, cast(dchar)'\u00A9'); assert(s == "X\xC2\xA9d"); } // TODO: helper, I wish std.utf was more flexible (and stright) private size_t encodeTo(wchar[] buf, size_t idx, dchar c) @trusted pure { import std.utf; if (c <= 0xFFFF) { if (0xD800 <= c && c <= 0xDFFF) throw (new UTFException("Encoding an isolated surrogate code point in UTF-16")).setSequence(c); buf[idx] = cast(wchar)c; idx++; } else if (c <= 0x10FFFF) { buf[idx] = cast(wchar)((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); buf[idx+1] = cast(wchar)(((c - 0x10000) & 0x3FF) + 0xDC00); idx += 2; } else assert(0); return idx; } private size_t encodeTo(dchar[] buf, size_t idx, dchar c) @trusted pure nothrow @nogc { buf[idx] = c; idx++; return idx; } private void toCaseInPlace(alias indexFn, uint maxIdx, alias tableFn, C)(ref C[] s) @trusted pure if (is(C == char) || is(C == wchar) || is(C == dchar)) { import std.utf; size_t curIdx = 0; size_t destIdx = 0; alias slowToCase = toCaseInPlaceAlloc!(indexFn, maxIdx, tableFn); size_t lastUnchanged = 0; // in-buffer move of bytes to a new start index // the trick is that it may not need to copy at all static size_t moveTo(C[] str, size_t dest, size_t from, size_t to) { // Interestingly we may just bump pointer for a while // then have to copy if a re-cased char was smaller the original // later we may regain pace with char that got bigger // In the end it sometimes flip-flops between the 2 cases below if(dest == from) return to; // got to copy foreach(C c; str[from..to]) str[dest++] = c; return dest; } while(curIdx != s.length) { size_t startIdx = curIdx; dchar ch = decode(s, curIdx); // TODO: special case for ASCII auto caseIndex = indexFn(ch); if(caseIndex == ushort.max) // unchanged, skip over { continue; } else if(caseIndex < maxIdx) // 1:1 codepoint mapping { // previous cased chars had the same length as uncased ones // thus can just adjust pointer destIdx = moveTo(s, destIdx, lastUnchanged, startIdx); lastUnchanged = curIdx; dchar cased = tableFn(caseIndex); auto casedLen = codeLength!C(cased); if(casedLen + destIdx > curIdx) // no place to fit cased char { // switch to slow codepath, where we allocate return slowToCase(s, startIdx, destIdx); } else { destIdx = encodeTo(s, destIdx, cased); } } else // 1:m codepoint mapping, slow codepath { destIdx = moveTo(s, destIdx, lastUnchanged, startIdx); lastUnchanged = curIdx; return slowToCase(s, startIdx, destIdx); } assert(destIdx <= curIdx); } if(lastUnchanged != s.length) { destIdx = moveTo(s, destIdx, lastUnchanged, s.length); } s = s[0..destIdx]; } // helper to precalculate size of case-converted string private template toCaseLength(alias indexFn, uint maxIdx, alias tableFn) { size_t toCaseLength(C)(in C[] str) { import std.utf; size_t codeLen = 0; size_t lastNonTrivial = 0; size_t curIdx = 0; while(curIdx != str.length) { size_t startIdx = curIdx; dchar ch = decode(str, curIdx); ushort caseIndex = indexFn(ch); if(caseIndex == ushort.max) continue; else if(caseIndex < maxIdx) { codeLen += startIdx - lastNonTrivial; lastNonTrivial = curIdx; dchar cased = tableFn(caseIndex); codeLen += codeLength!C(cased); } else { codeLen += startIdx - lastNonTrivial; lastNonTrivial = curIdx; auto val = tableFn(caseIndex); auto len = val>>24; dchar cased = val & 0xFF_FFFF; codeLen += codeLength!C(cased); foreach(j; caseIndex+1..caseIndex+len) codeLen += codeLength!C(tableFn(j)); } } if(lastNonTrivial != str.length) codeLen += str.length - lastNonTrivial; return codeLen; } } unittest { import std.conv; alias toLowerLength = toCaseLength!(LowerTriple); assert(toLowerLength("abcd") == 4); assert(toLowerLength("аБВгд456") == 10+3); } // slower code path that preallocates and then copies // case-converted stuf to the new string private template toCaseInPlaceAlloc(alias indexFn, uint maxIdx, alias tableFn) { void toCaseInPlaceAlloc(C)(ref C[] s, size_t curIdx, size_t destIdx) @trusted pure if (is(C == char) || is(C == wchar) || is(C == dchar)) { import std.utf : decode; alias caseLength = toCaseLength!(indexFn, maxIdx, tableFn); auto trueLength = destIdx + caseLength(s[curIdx..$]); C[] ns = new C[trueLength]; ns[0..destIdx] = s[0..destIdx]; size_t lastUnchanged = curIdx; while(curIdx != s.length) { size_t startIdx = curIdx; // start of current codepoint dchar ch = decode(s, curIdx); auto caseIndex = indexFn(ch); if(caseIndex == ushort.max) // skip over { continue; } else if(caseIndex < maxIdx) // 1:1 codepoint mapping { dchar cased = tableFn(caseIndex); auto toCopy = startIdx - lastUnchanged; ns[destIdx .. destIdx+toCopy] = s[lastUnchanged .. startIdx]; lastUnchanged = curIdx; destIdx += toCopy; destIdx = encodeTo(ns, destIdx, cased); } else // 1:m codepoint mapping, slow codepath { auto toCopy = startIdx - lastUnchanged; ns[destIdx .. destIdx+toCopy] = s[lastUnchanged .. startIdx]; lastUnchanged = curIdx; destIdx += toCopy; auto val = tableFn(caseIndex); // unpack length + codepoint uint len = val>>24; destIdx = encodeTo(ns, destIdx, cast(dchar)(val & 0xFF_FFFF)); foreach(j; caseIndex+1..caseIndex+len) destIdx = encodeTo(ns, destIdx, tableFn(j)); } } if(lastUnchanged != s.length) { auto toCopy = s.length - lastUnchanged; ns[destIdx..destIdx+toCopy] = s[lastUnchanged..$]; destIdx += toCopy; } assert(ns.length == destIdx); s = ns; } } /++ Converts $(D s) to lowercase (by performing Unicode lowercase mapping) in place. For a few characters string length may increase after the transformation, in such a case the function reallocates exactly once. If $(D s) does not have any uppercase characters, then $(D s) is unaltered. +/ void toLowerInPlace(C)(ref C[] s) @trusted pure if (is(C == char) || is(C == wchar) || is(C == dchar)) { toCaseInPlace!(LowerTriple)(s); } // overloads for the most common cases to reduce compile time @safe pure /*TODO nothrow*/ { void toLowerInPlace(ref char[] s) { toLowerInPlace!char(s); } void toLowerInPlace(ref wchar[] s) { toLowerInPlace!wchar(s); } void toLowerInPlace(ref dchar[] s) { toLowerInPlace!dchar(s); } } /++ Converts $(D s) to uppercase (by performing Unicode uppercase mapping) in place. For a few characters string length may increase after the transformation, in such a case the function reallocates exactly once. If $(D s) does not have any lowercase characters, then $(D s) is unaltered. +/ void toUpperInPlace(C)(ref C[] s) @trusted pure if (is(C == char) || is(C == wchar) || is(C == dchar)) { toCaseInPlace!(UpperTriple)(s); } // overloads for the most common cases to reduce compile time/code size @safe pure /*TODO nothrow*/ { void toUpperInPlace(ref char[] s) { toUpperInPlace!char(s); } void toUpperInPlace(ref wchar[] s) { toUpperInPlace!wchar(s); } void toUpperInPlace(ref dchar[] s) { toUpperInPlace!dchar(s); } } /++ If $(D c) is a Unicode uppercase $(CHARACTER), then its lowercase equivalent is returned. Otherwise $(D c) is returned. Warning: certain alphabets like German and Greek have no 1:1 upper-lower mapping. Use overload of toLower which takes full string instead. +/ @safe pure nothrow @nogc dchar toLower(dchar c) { // optimize ASCII case if(c < 0xAA) { if(c < 'A') return c; if(c <= 'Z') return c + 32; return c; } size_t idx = toLowerSimpleIndex(c); if(idx != ushort.max) { return toLowerTab(idx); } return c; } /++ Returns a string which is identical to $(D s) except that all of its characters are converted to lowercase (by preforming Unicode lowercase mapping). If none of $(D s) characters were affected, then $(D s) itself is returned. +/ S toLower(S)(S s) @trusted pure if(isSomeString!S) { return toCase!(LowerTriple)(s); } // overloads for the most common cases to reduce compile time @safe pure /*TODO nothrow*/ { string toLower(string s) { return toLower!string(s); } wstring toLower(wstring s) { return toLower!wstring(s); } dstring toLower(dstring s) { return toLower!dstring(s); } } @trusted unittest //@@@BUG std.format is not @safe { import std.format : format; static import std.ascii; foreach(ch; 0..0x80) assert(std.ascii.toLower(ch) == toLower(ch)); assert(toLower('Я') == 'я'); assert(toLower('Δ') == 'δ'); foreach(ch; unicode.upperCase.byCodepoint) { dchar low = ch.toLower(); assert(low == ch || isLower(low), format("%s -> %s", ch, low)); } assert(toLower("АЯ") == "ая"); assert("\u1E9E".toLower == "\u00df"); assert("\u00df".toUpper == "SS"); } //bugzilla 9629 unittest { wchar[] test = "hello þ world"w.dup; auto piece = test[6..7]; toUpperInPlace(piece); assert(test == "hello Þ world"); } unittest { import std.algorithm : cmp; string s1 = "FoL"; string s2 = toLower(s1); assert(cmp(s2, "fol") == 0, s2); assert(s2 != s1); char[] s3 = s1.dup; toLowerInPlace(s3); assert(s3 == s2); s1 = "A\u0100B\u0101d"; s2 = toLower(s1); s3 = s1.dup; assert(cmp(s2, "a\u0101b\u0101d") == 0); assert(s2 !is s1); toLowerInPlace(s3); assert(s3 == s2); s1 = "A\u0460B\u0461d"; s2 = toLower(s1); s3 = s1.dup; assert(cmp(s2, "a\u0461b\u0461d") == 0); assert(s2 !is s1); toLowerInPlace(s3); assert(s3 == s2); s1 = "\u0130"; s2 = toLower(s1); s3 = s1.dup; assert(s2 == "i\u0307"); assert(s2 !is s1); toLowerInPlace(s3); assert(s3 == s2); // Test on wchar and dchar strings. assert(toLower("Some String"w) == "some string"w); assert(toLower("Some String"d) == "some string"d); // bugzilla 12455 dchar c = 'İ'; // '\U0130' LATIN CAPITAL LETTER I WITH DOT ABOVE assert(isUpper(c)); assert(toLower(c) == 'i'); // extend on 12455 reprot - check simple-case toUpper too c = '\u1f87'; assert(isLower(c)); assert(toUpper(c) == '\u1F8F'); } /++ If $(D c) is a Unicode lowercase $(CHARACTER), then its uppercase equivalent is returned. Otherwise $(D c) is returned. Warning: Certain alphabets like German and Greek have no 1:1 upper-lower mapping. Use overload of toUpper which takes full string instead. toUpper can be used as an argument to $(XREF_PACK algorithm,iteration,map) to produce an algorithm that can convert a range of characters to upper case without allocating memory. A string can then be produced by using $(XREF_PACK algorithm,mutation,copy) to send it to an $(XREF array, appender). +/ @safe pure nothrow @nogc dchar toUpper(dchar c) { // optimize ASCII case if(c < 0xAA) { if(c < 'a') return c; if(c <= 'z') return c - 32; return c; } size_t idx = toUpperSimpleIndex(c); if(idx != ushort.max) { return toUpperTab(idx); } return c; } /// unittest { import std.algorithm; import std.uni; import std.array; auto abuf = appender!(char[])(); "hello".map!toUpper.copy(&abuf); assert(abuf.data == "HELLO"); } @trusted unittest { import std.format : format; static import std.ascii; foreach(ch; 0..0x80) assert(std.ascii.toUpper(ch) == toUpper(ch)); assert(toUpper('я') == 'Я'); assert(toUpper('δ') == 'Δ'); auto title = unicode.Titlecase_Letter; foreach(ch; unicode.lowerCase.byCodepoint) { dchar up = ch.toUpper(); assert(up == ch || isUpper(up) || title[up], format("%x -> %x", ch, up)); } } /++ Returns a string which is identical to $(D s) except that all of its characters are converted to uppercase (by preforming Unicode uppercase mapping). If none of $(D s) characters were affected, then $(D s) itself is returned. +/ S toUpper(S)(S s) @trusted pure if(isSomeString!S) { return toCase!(UpperTriple)(s); } // overloads for the most common cases to reduce compile time @safe pure /*TODO nothrow*/ { string toUpper(string s) { return toUpper!string(s); } wstring toUpper(wstring s) { return toUpper!wstring(s); } dstring toUpper(dstring s) { return toUpper!dstring(s); } } unittest { import std.algorithm : cmp; string s1 = "FoL"; string s2; char[] s3; s2 = toUpper(s1); s3 = s1.dup; toUpperInPlace(s3); assert(s3 == s2, s3); assert(cmp(s2, "FOL") == 0); assert(s2 !is s1); s1 = "a\u0100B\u0101d"; s2 = toUpper(s1); s3 = s1.dup; toUpperInPlace(s3); assert(s3 == s2); assert(cmp(s2, "A\u0100B\u0100D") == 0); assert(s2 !is s1); s1 = "a\u0460B\u0461d"; s2 = toUpper(s1); s3 = s1.dup; toUpperInPlace(s3); assert(s3 == s2); assert(cmp(s2, "A\u0460B\u0460D") == 0); assert(s2 !is s1); } unittest { static void doTest(C)(const(C)[] s, const(C)[] trueUp, const(C)[] trueLow) { import std.format : format; string diff = "src: %( %x %)\nres: %( %x %)\ntru: %( %x %)"; auto low = s.toLower() , up = s.toUpper(); auto lowInp = s.dup, upInp = s.dup; lowInp.toLowerInPlace(); upInp.toUpperInPlace(); assert(low == trueLow, format(diff, low, trueLow)); assert(up == trueUp, format(diff, up, trueUp)); assert(lowInp == trueLow, format(diff, cast(ubyte[])s, cast(ubyte[])lowInp, cast(ubyte[])trueLow)); assert(upInp == trueUp, format(diff, cast(ubyte[])s, cast(ubyte[])upInp, cast(ubyte[])trueUp)); } foreach(S; AliasSeq!(dstring, wstring, string)) { S easy = "123"; S good = "abCФеж"; S awful = "\u0131\u023f\u2126"; S wicked = "\u0130\u1FE2"; auto options = [easy, good, awful, wicked]; S[] lower = ["123", "abcфеж", "\u0131\u023f\u03c9", "i\u0307\u1Fe2"]; S[] upper = ["123", "ABCФЕЖ", "I\u2c7e\u2126", "\u0130\u03A5\u0308\u0300"]; foreach(val; AliasSeq!(easy, good)) { auto e = val.dup; auto g = e; e.toUpperInPlace(); assert(e is g); e.toLowerInPlace(); assert(e is g); } foreach(i, v; options) { doTest(v, upper[i], lower[i]); } // a few combinatorial runs foreach(i; 0..options.length) foreach(j; i..options.length) foreach(k; j..options.length) { auto sample = options[i] ~ options[j] ~ options[k]; auto sample2 = options[k] ~ options[j] ~ options[i]; doTest(sample, upper[i] ~ upper[j] ~ upper[k], lower[i] ~ lower[j] ~ lower[k]); doTest(sample2, upper[k] ~ upper[j] ~ upper[i], lower[k] ~ lower[j] ~ lower[i]); } } } /++ Returns whether $(D c) is a Unicode alphabetic $(CHARACTER) (general Unicode category: Alphabetic). +/ @safe pure nothrow @nogc bool isAlpha(dchar c) { // optimization if(c < 0xAA) { size_t x = c - 'A'; if(x <= 'Z' - 'A') return true; else { x = c - 'a'; if(x <= 'z'-'a') return true; } return false; } return alphaTrie[c]; } @safe unittest { auto alpha = unicode("Alphabetic"); foreach(ch; alpha.byCodepoint) assert(isAlpha(ch)); foreach(ch; 0..0x4000) assert((ch in alpha) == isAlpha(ch)); } /++ Returns whether $(D c) is a Unicode mark (general Unicode category: Mn, Me, Mc). +/ @safe pure nothrow @nogc bool isMark(dchar c) { return markTrie[c]; } @safe unittest { auto mark = unicode("Mark"); foreach(ch; mark.byCodepoint) assert(isMark(ch)); foreach(ch; 0..0x4000) assert((ch in mark) == isMark(ch)); } /++ Returns whether $(D c) is a Unicode numerical $(CHARACTER) (general Unicode category: Nd, Nl, No). +/ @safe pure nothrow @nogc bool isNumber(dchar c) { return numberTrie[c]; } @safe unittest { auto n = unicode("N"); foreach(ch; n.byCodepoint) assert(isNumber(ch)); foreach(ch; 0..0x4000) assert((ch in n) == isNumber(ch)); } /++ Returns whether $(D c) is a Unicode punctuation $(CHARACTER) (general Unicode category: Pd, Ps, Pe, Pc, Po, Pi, Pf). +/ @safe pure nothrow @nogc bool isPunctuation(dchar c) { return punctuationTrie[c]; } unittest { assert(isPunctuation('\u0021')); assert(isPunctuation('\u0028')); assert(isPunctuation('\u0029')); assert(isPunctuation('\u002D')); assert(isPunctuation('\u005F')); assert(isPunctuation('\u00AB')); assert(isPunctuation('\u00BB')); foreach(ch; unicode("P").byCodepoint) assert(isPunctuation(ch)); } /++ Returns whether $(D c) is a Unicode symbol $(CHARACTER) (general Unicode category: Sm, Sc, Sk, So). +/ @safe pure nothrow @nogc bool isSymbol(dchar c) { return symbolTrie[c]; } unittest { import std.format : format; assert(isSymbol('\u0024')); assert(isSymbol('\u002B')); assert(isSymbol('\u005E')); assert(isSymbol('\u00A6')); foreach(ch; unicode("S").byCodepoint) assert(isSymbol(ch), format("%04x", ch)); } /++ Returns whether $(D c) is a Unicode space $(CHARACTER) (general Unicode category: Zs) Note: This doesn't include '\n', '\r', \t' and other non-space $(CHARACTER). For commonly used less strict semantics see $(LREF isWhite). +/ @safe pure nothrow @nogc bool isSpace(dchar c) { return isSpaceGen(c); } unittest { assert(isSpace('\u0020')); auto space = unicode.Zs; foreach(ch; space.byCodepoint) assert(isSpace(ch)); foreach(ch; 0..0x1000) assert(isSpace(ch) == space[ch]); } /++ Returns whether $(D c) is a Unicode graphical $(CHARACTER) (general Unicode category: L, M, N, P, S, Zs). +/ @safe pure nothrow @nogc bool isGraphical(dchar c) { return graphicalTrie[c]; } unittest { auto set = unicode("Graphical"); import std.format : format; foreach(ch; set.byCodepoint) assert(isGraphical(ch), format("%4x", ch)); foreach(ch; 0..0x4000) assert((ch in set) == isGraphical(ch)); } /++ Returns whether $(D c) is a Unicode control $(CHARACTER) (general Unicode category: Cc). +/ @safe pure nothrow @nogc bool isControl(dchar c) { return isControlGen(c); } unittest { assert(isControl('\u0000')); assert(isControl('\u0081')); assert(!isControl('\u0100')); auto cc = unicode.Cc; foreach(ch; cc.byCodepoint) assert(isControl(ch)); foreach(ch; 0..0x1000) assert(isControl(ch) == cc[ch]); } /++ Returns whether $(D c) is a Unicode formatting $(CHARACTER) (general Unicode category: Cf). +/ @safe pure nothrow @nogc bool isFormat(dchar c) { return isFormatGen(c); } unittest { assert(isFormat('\u00AD')); foreach(ch; unicode("Format").byCodepoint) assert(isFormat(ch)); } // code points for private use, surrogates are not likely to change in near feature // if need be they can be generated from unicode data as well /++ Returns whether $(D c) is a Unicode Private Use $(CODEPOINT) (general Unicode category: Co). +/ @safe pure nothrow @nogc bool isPrivateUse(dchar c) { return (0x00_E000 <= c && c <= 0x00_F8FF) || (0x0F_0000 <= c && c <= 0x0F_FFFD) || (0x10_0000 <= c && c <= 0x10_FFFD); } /++ Returns whether $(D c) is a Unicode surrogate $(CODEPOINT) (general Unicode category: Cs). +/ @safe pure nothrow @nogc bool isSurrogate(dchar c) { return (0xD800 <= c && c <= 0xDFFF); } /++ Returns whether $(D c) is a Unicode high surrogate (lead surrogate). +/ @safe pure nothrow @nogc bool isSurrogateHi(dchar c) { return (0xD800 <= c && c <= 0xDBFF); } /++ Returns whether $(D c) is a Unicode low surrogate (trail surrogate). +/ @safe pure nothrow @nogc bool isSurrogateLo(dchar c) { return (0xDC00 <= c && c <= 0xDFFF); } /++ Returns whether $(D c) is a Unicode non-character i.e. a $(CODEPOINT) with no assigned abstract character. (general Unicode category: Cn) +/ @safe pure nothrow @nogc bool isNonCharacter(dchar c) { return nonCharacterTrie[c]; } unittest { auto set = unicode("Cn"); foreach(ch; set.byCodepoint) assert(isNonCharacter(ch)); } private: // load static data from pre-generated tables into usable datastructures @safe auto asSet(const (ubyte)[] compressed) pure { return CodepointSet.fromIntervals(decompressIntervals(compressed)); } @safe pure nothrow auto asTrie(T...)(in TrieEntry!T e) { return const(CodepointTrie!T)(e.offsets, e.sizes, e.data); } @safe pure nothrow @nogc @property { // It's important to use auto return here, so that the compiler // only runs semantic on the return type if the function gets // used. Also these are functions rather than templates to not // increase the object size of the caller. auto lowerCaseTrie() { static immutable res = asTrie(lowerCaseTrieEntries); return res; } auto upperCaseTrie() { static immutable res = asTrie(upperCaseTrieEntries); return res; } auto simpleCaseTrie() { static immutable res = asTrie(simpleCaseTrieEntries); return res; } auto fullCaseTrie() { static immutable res = asTrie(fullCaseTrieEntries); return res; } auto alphaTrie() { static immutable res = asTrie(alphaTrieEntries); return res; } auto markTrie() { static immutable res = asTrie(markTrieEntries); return res; } auto numberTrie() { static immutable res = asTrie(numberTrieEntries); return res; } auto punctuationTrie() { static immutable res = asTrie(punctuationTrieEntries); return res; } auto symbolTrie() { static immutable res = asTrie(symbolTrieEntries); return res; } auto graphicalTrie() { static immutable res = asTrie(graphicalTrieEntries); return res; } auto nonCharacterTrie() { static immutable res = asTrie(nonCharacterTrieEntries); return res; } //normalization quick-check tables auto nfcQCTrie() { import std.internal.unicode_norm; static immutable res = asTrie(nfcQCTrieEntries); return res; } auto nfdQCTrie() { import std.internal.unicode_norm; static immutable res = asTrie(nfdQCTrieEntries); return res; } auto nfkcQCTrie() { import std.internal.unicode_norm; static immutable res = asTrie(nfkcQCTrieEntries); return res; } auto nfkdQCTrie() { import std.internal.unicode_norm; static immutable res = asTrie(nfkdQCTrieEntries); return res; } //grapheme breaking algorithm tables auto mcTrie() { import std.internal.unicode_grapheme; static immutable res = asTrie(mcTrieEntries); return res; } auto graphemeExtendTrie() { import std.internal.unicode_grapheme; static immutable res = asTrie(graphemeExtendTrieEntries); return res; } auto hangLV() { import std.internal.unicode_grapheme; static immutable res = asTrie(hangulLVTrieEntries); return res; } auto hangLVT() { import std.internal.unicode_grapheme; static immutable res = asTrie(hangulLVTTrieEntries); return res; } // tables below are used for composition/decomposition auto combiningClassTrie() { import std.internal.unicode_comp; static immutable res = asTrie(combiningClassTrieEntries); return res; } auto compatMappingTrie() { import std.internal.unicode_decomp; static immutable res = asTrie(compatMappingTrieEntries); return res; } auto canonMappingTrie() { import std.internal.unicode_decomp; static immutable res = asTrie(canonMappingTrieEntries); return res; } auto compositionJumpTrie() { import std.internal.unicode_comp; static immutable res = asTrie(compositionJumpTrieEntries); return res; } //case conversion tables auto toUpperIndexTrie() { static immutable res = asTrie(toUpperIndexTrieEntries); return res; } auto toLowerIndexTrie() { static immutable res = asTrie(toLowerIndexTrieEntries); return res; } auto toTitleIndexTrie() { static immutable res = asTrie(toTitleIndexTrieEntries); return res; } //simple case conversion tables auto toUpperSimpleIndexTrie() { static immutable res = asTrie(toUpperSimpleIndexTrieEntries); return res; } auto toLowerSimpleIndexTrie() { static immutable res = asTrie(toLowerSimpleIndexTrieEntries); return res; } auto toTitleSimpleIndexTrie() { static immutable res = asTrie(toTitleSimpleIndexTrieEntries); return res; } } }// version(!std_uni_bootstrap) ldc-1.1.0-beta3-src/runtime/phobos/std/mmfile.d0000664000175000017500000004742212776215007017335 0ustar kaikai// Written in the D programming language. /** * Read and write memory mapped files. * Macros: * WIKI=Phobos/StdMmfile * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright), * Matthew Wilson * Source: $(PHOBOSSRC std/_mmfile.d) */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.mmfile; private import std.file; private import core.stdc.stdio; private import core.stdc.stdlib; private import core.stdc.errno; private import std.path; private import std.string; import std.conv, std.exception, std.stdio; import std.internal.cstring; //debug = MMFILE; version (Windows) { private import core.sys.windows.windows; private import std.utf; private import std.windows.syserror; } else version (Posix) { private import core.sys.posix.fcntl; private import core.sys.posix.unistd; private import core.sys.posix.sys.mman; private import core.sys.posix.sys.stat; } else { static assert(0); } /** * MmFile objects control the memory mapped file resource. */ class MmFile { /** * The mode the memory mapped file is opened with. */ enum Mode { read, /// Read existing file readWriteNew, /// Delete existing file, write new file readWrite, /// Read/Write existing file, create if not existing readCopyOnWrite, /// Read/Write existing file, copy on write } /** * Open memory mapped file filename for reading. * File is closed when the object instance is deleted. * Throws: * std.file.FileException */ this(string filename) { this(filename, Mode.read, 0, null); } version(linux) this(File file, Mode mode = Mode.read, ulong size = 0, void* address = null, size_t window = 0) { // Save a copy of the File to make sure the fd stays open. this.file = file; this(file.fileno, mode, size, address, window); } version(linux) private this(int fildes, Mode mode, ulong size, void* address, size_t window) { int oflag; int fmode; switch (mode) { case Mode.read: flags = MAP_SHARED; prot = PROT_READ; oflag = O_RDONLY; fmode = 0; break; case Mode.readWriteNew: assert(size != 0); flags = MAP_SHARED; prot = PROT_READ | PROT_WRITE; oflag = O_CREAT | O_RDWR | O_TRUNC; fmode = octal!660; break; case Mode.readWrite: flags = MAP_SHARED; prot = PROT_READ | PROT_WRITE; oflag = O_CREAT | O_RDWR; fmode = octal!660; break; case Mode.readCopyOnWrite: flags = MAP_PRIVATE; prot = PROT_READ | PROT_WRITE; oflag = O_RDWR; fmode = 0; break; default: assert(0); } fd = fildes; // Adjust size stat_t statbuf = void; errnoEnforce(fstat(fd, &statbuf) == 0); if (prot & PROT_WRITE && size > statbuf.st_size) { // Need to make the file size bytes big lseek(fd, cast(off_t)(size - 1), SEEK_SET); char c = 0; core.sys.posix.unistd.write(fd, &c, 1); } else if (prot & PROT_READ && size == 0) size = statbuf.st_size; this.size = size; // Map the file into memory! size_t initial_map = (window && 2*window>32); hFileMap = CreateFileMappingW(hFile, null, flProtect, hi, cast(uint)size, null); wenforce(hFileMap, "CreateFileMapping"); scope(failure) { CloseHandle(hFileMap); hFileMap = null; } if (size == 0 && filename != null) { uint sizehi; uint sizelow = GetFileSize(hFile, &sizehi); wenforce(sizelow != INVALID_FILE_SIZE || GetLastError() != ERROR_SUCCESS, "GetFileSize"); size = (cast(ulong)sizehi << 32) + sizelow; } this.size = size; size_t initial_map = (window && 2*window statbuf.st_size) { // Need to make the file size bytes big .lseek(fd, cast(off_t)(size - 1), SEEK_SET); char c = 0; core.sys.posix.unistd.write(fd, &c, 1); } else if (prot & PROT_READ && size == 0) size = statbuf.st_size; } else { fd = -1; version(CRuntime_Glibc) import core.sys.linux.sys.mman : MAP_ANON; flags |= MAP_ANON; } this.size = size; size_t initial_map = (window && 2*window= start && i < start+data.length; } // unmap the current range private void unmap() { debug (MMFILE) printf("MmFile.unmap()\n"); version(Windows) { wenforce(!data.ptr || UnmapViewOfFile(data.ptr) != FALSE, "UnmapViewOfFile"); } else { errnoEnforce(!data.ptr || munmap(cast(void*)data, data.length) == 0, "munmap failed"); } data = null; } // map range private void map(ulong start, size_t len) { debug (MMFILE) printf("MmFile.map(%lld, %d)\n", start, len); void* p; if (start+len > size) len = cast(size_t)(size-start); version(Windows) { uint hi = cast(uint)(start>>32); p = MapViewOfFileEx(hFileMap, dwDesiredAccess, hi, cast(uint)start, len, address); wenforce(p, "MapViewOfFileEx"); } else { p = mmap(address, len, prot, flags, fd, cast(off_t)start); errnoEnforce(p != MAP_FAILED); } data = p[0 .. len]; this.start = start; } // ensure a given position is mapped private void ensureMapped(ulong i) { debug (MMFILE) printf("MmFile.ensureMapped(%lld)\n", i); if (!mapped(i)) { unmap(); if (window == 0) { map(0,cast(size_t)size); } else { ulong block = i/window; if (block == 0) map(0,2*window); else map(window*(block-1),3*window); } } } // ensure a given range is mapped private void ensureMapped(ulong i, ulong j) { debug (MMFILE) printf("MmFile.ensureMapped(%lld, %lld)\n", i, j); if (!mapped(i) || !mapped(j-1)) { unmap(); if (window == 0) { map(0,cast(size_t)size); } else { ulong iblock = i/window; ulong jblock = (j-1)/window; if (iblock == 0) { map(0,cast(size_t)(window*(jblock+2))); } else { map(window*(iblock-1),cast(size_t)(window*(jblock-iblock+3))); } } } } private: string filename; void[] data; ulong start; size_t window; ulong size; Mode mMode; void* address; version (linux) File file; version (Windows) { HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hFileMap = null; uint dwDesiredAccess; } else version (Posix) { int fd; int prot; int flags; int fmode; } else { static assert(0); } // Report error, where errno gives the error number // void errNo() // { // version (Windows) // { // throw new FileException(filename, GetLastError()); // } // else version (linux) // { // throw new FileException(filename, errno); // } // else // { // static assert(0); // } // } } unittest { import std.file : deleteme; const size_t K = 1024; size_t win = 64*K; // assume the page size is 64K version(Windows) { /+ these aren't defined in core.sys.windows.windows so let's use default SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); win = sysinfo.dwAllocationGranularity; +/ } else version (linux) { // getpagesize() is not defined in the unix D headers so use the guess } string test_file = std.file.deleteme ~ "-testing.txt"; MmFile mf = new MmFile(test_file,MmFile.Mode.readWriteNew, 100*K,null,win); ubyte[] str = cast(ubyte[])"1234567890"; ubyte[] data = cast(ubyte[])mf[0 .. 10]; data[] = str[]; assert( mf[0 .. 10] == str ); data = cast(ubyte[])mf[50 .. 60]; data[] = str[]; assert( mf[50 .. 60] == str ); ubyte[] data2 = cast(ubyte[])mf[20*K .. 60*K]; assert( data2.length == 40*K ); assert( data2[$-1] == 0 ); mf[100*K-1] = cast(ubyte)'b'; data2 = cast(ubyte[])mf[21*K .. 100*K]; assert( data2.length == 79*K ); assert( data2[$-1] == 'b' ); delete mf; std.file.remove(test_file); // Create anonymous mapping auto test = new MmFile(null, MmFile.Mode.readWriteNew, 1024*1024, null); } version(linux) unittest // Issue 14868 { import std.typecons : scoped; import std.file : deleteme; // Test retaining ownership of File/fd auto fn = std.file.deleteme ~ "-testing.txt"; scope(exit) std.file.remove(fn); File(fn, "wb").writeln("Testing!"); scoped!MmFile(File(fn)); // Test that unique ownership of File actually leads to the fd being closed auto f = File(fn); auto fd = f.fileno; { auto mf = scoped!MmFile(f); f = File.init; } assert(.close(fd) == -1); } unittest // Issue 14994, 14995 { import std.file : deleteme; import std.typecons : scoped; // Zero-length map may or may not be valid on OSX and NetBSD version (OSX) import std.exception : verifyThrown = collectException; version (NetBSD) import std.exception : verifyThrown = collectException; else import std.exception : verifyThrown = assertThrown; auto fn = std.file.deleteme ~ "-testing.txt"; scope(exit) std.file.remove(fn); verifyThrown(scoped!MmFile(fn, MmFile.Mode.readWrite, 0, null)); } ldc-1.1.0-beta3-src/runtime/phobos/std/bigint.d0000664000175000017500000012157412776215007017341 0ustar kaikai/** Arbitrary-precision ('bignum') arithmetic. * * Performance is optimized for numbers below ~1000 decimal digits. * For X86 machines, highly optimised assembly routines are used. * * The following algorithms are currently implemented: * $(UL * $(LI Karatsuba multiplication) * $(LI Squaring is optimized independently of multiplication) * $(LI Divide-and-conquer division) * $(LI Binary exponentiation) * ) * * For very large numbers, consider using the $(WEB gmplib.org, GMP library) instead. * * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Don Clugston * Source: $(PHOBOSSRC std/_bigint.d) */ /* Copyright Don Clugston 2008 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.bigint; import std.conv : ConvException; private import std.internal.math.biguintcore; private import std.format : FormatSpec, FormatException; private import std.traits; /** A struct representing an arbitrary precision integer. * * All arithmetic operations are supported, except unsigned shift right (>>>). * Bitwise operations (|, &, ^, ~) are supported, and behave as if BigInt was * an infinite length 2's complement number. * * BigInt implements value semantics using copy-on-write. This means that * assignment is cheap, but operations such as x++ will cause heap * allocation. (But note that for most bigint operations, heap allocation is * inevitable anyway.) */ struct BigInt { private: BigUint data; // BigInt adds signed arithmetic to BigUint. bool sign = false; public: /** * Construct a BigInt from a decimal or hexadecimal string. * * The number must be in the form of a D decimal or hex literal. It may * have a leading + or - sign; followed by "0x" if hexadecimal. * Underscores are permitted. An empty string is treated as "0". * * Throws: ConvException if invalid character found, or string is empty. */ this(T : const(char)[])(T s, string file = __FILE__, size_t line = __LINE__) pure { if (s.length == 0) throw new ConvException("Can't initialize BigInt with "~ "empty string", file, line); bool neg = false; if (s[0] == '-') { neg = true; s = s[1..$]; } else if (s[0] == '+') { s = s[1..$]; } data = 0UL; bool ok; assert(isZero()); if (s.length > 2 && (s[0..2] == "0x" || s[0..2] == "0X")) { ok = data.fromHexString(s[2..$]); } else { ok = data.fromDecimalString(s); } if (!ok) throw new ConvException("Invalid digit string", file, line); if (isZero()) neg = false; sign = neg; } /// Construct a BigInt from a built-in integral type. this(T)(T x) pure nothrow if (isIntegral!T) { data = data.init; // @@@: Workaround for compiler bug opAssign(x); } /// unittest { ulong data = 1_000_000_000_000; auto bigData = BigInt(data); assert(data == BigInt("1_000_000_000_000")); } /// Construct a BigInt from another BigInt. this(T)(T x) pure nothrow if (is(Unqual!T == BigInt)) { opAssign(x); } /// unittest { const(BigInt) b1 = BigInt("1_234_567_890"); BigInt b2 = BigInt(b1); assert(b2 == BigInt("1_234_567_890")); } /// Assignment from built-in integer types. BigInt opAssign(T)(T x) pure nothrow if (isIntegral!T) { data = cast(ulong)absUnsign(x); sign = (x < 0); return this; } /// unittest { auto b = BigInt("123"); b = 456; assert(b == BigInt("456")); } /// Assignment from another BigInt. BigInt opAssign(T:BigInt)(T x) pure @nogc { data = x.data; sign = x.sign; return this; } /// unittest { auto b1 = BigInt("123"); auto b2 = BigInt("456"); b2 = b1; assert(b2 == BigInt("123")); } /** * Implements assignment operators from built-in integers of the form * $(D BigInt op= integer). */ BigInt opOpAssign(string op, T)(T y) pure nothrow if ((op=="+" || op=="-" || op=="*" || op=="/" || op=="%" || op==">>" || op=="<<" || op=="^^" || op=="|" || op=="&" || op=="^") && isIntegral!T) { ulong u = absUnsign(y); static if (op=="+") { data = BigUint.addOrSubInt(data, u, sign != (y<0), sign); } else static if (op=="-") { data = BigUint.addOrSubInt(data, u, sign == (y<0), sign); } else static if (op=="*") { if (y == 0) { sign = false; data = 0UL; } else { sign = ( sign != (y<0) ); data = BigUint.mulInt(data, u); } } else static if (op=="/") { assert(y!=0, "Division by zero"); static if (T.sizeof <= uint.sizeof) { data = BigUint.divInt(data, cast(uint)u); } else { data = BigUint.divInt(data, u); } sign = data.isZero() ? false : sign ^ (y < 0); } else static if (op=="%") { assert(y!=0, "Division by zero"); static if (is(immutable(T) == immutable(long)) || is( immutable(T) == immutable(ulong) )) { this %= BigInt(y); } else { data = cast(ulong)BigUint.modInt(data, cast(uint)u); if (data.isZero()) sign = false; } // x%y always has the same sign as x. // This is not the same as mathematical mod. } else static if (op==">>" || op=="<<") { // Do a left shift if y>0 and <<, or // if y<0 and >>; else do a right shift. if (y == 0) return this; else if ((y > 0) == (op=="<<")) { // Sign never changes during left shift data = data.opShl(u); } else { data = data.opShr(u); if (data.isZero()) sign = false; } } else static if (op=="^^") { sign = (y & 1) ? sign : false; data = BigUint.pow(data, u); } else static if (op=="|" || op=="&" || op=="^") { BigInt b = y; opOpAssign!op(b); } else static assert(0, "BigInt " ~ op[0..$-1] ~ "= " ~ T.stringof ~ " is not supported"); return this; } /// unittest { auto b = BigInt("1_000_000_000"); b += 12345; assert(b == BigInt("1_000_012_345")); b /= 5; assert(b == BigInt("200_002_469")); } /** * Implements assignment operators of the form $(D BigInt op= BigInt). */ BigInt opOpAssign(string op, T)(T y) pure nothrow if ((op=="+" || op== "-" || op=="*" || op=="|" || op=="&" || op=="^" || op=="/" || op=="%") && is (T: BigInt)) { static if (op == "+") { data = BigUint.addOrSub(data, y.data, sign != y.sign, &sign); } else static if (op == "-") { data = BigUint.addOrSub(data, y.data, sign == y.sign, &sign); } else static if (op == "*") { data = BigUint.mul(data, y.data); sign = isZero() ? false : sign ^ y.sign; } else static if (op == "/") { y.checkDivByZero(); if (!isZero()) { data = BigUint.div(data, y.data); sign = isZero() ? false : sign ^ y.sign; } } else static if (op == "%") { y.checkDivByZero(); if (!isZero()) { data = BigUint.mod(data, y.data); // x%y always has the same sign as x. if (isZero()) sign = false; } } else static if (op == "|" || op == "&" || op == "^") { data = BigUint.bitwiseOp!op(data, y.data, sign, y.sign, sign); } else static assert(0, "BigInt " ~ op[0..$-1] ~ "= " ~ T.stringof ~ " is not supported"); return this; } /// unittest { auto x = BigInt("123"); auto y = BigInt("321"); x += y; assert(x == BigInt("444")); } /** * Implements binary operators between BigInts. */ BigInt opBinary(string op, T)(T y) pure nothrow const if ((op=="+" || op == "*" || op=="-" || op=="|" || op=="&" || op=="^" || op=="/" || op=="%") && is (T: BigInt)) { BigInt r = this; return r.opOpAssign!(op)(y); } /// unittest { auto x = BigInt("123"); auto y = BigInt("456"); BigInt z = x * y; assert(z == BigInt("56088")); } /** * Implements binary operators between BigInt's and built-in integers. */ BigInt opBinary(string op, T)(T y) pure nothrow const if ((op=="+" || op == "*" || op=="-" || op=="/" || op=="|" || op=="&" || op=="^"|| op==">>" || op=="<<" || op=="^^") && isIntegral!T) { BigInt r = this; return r.opOpAssign!(op)(y); } /// unittest { auto x = BigInt("123"); x *= 300; assert(x == BigInt("36900")); } /** Implements a narrowing remainder operation with built-in integer types. This binary operator returns a narrower, built-in integer type where applicable, according to the following table. $(TABLE , $(TR $(TD `BigInt`) $(TD $(CODE_PERCENT)) $(TD `long`) $(TD $(RARR)) $(TD `long`)) $(TR $(TD `BigInt`) $(TD $(CODE_PERCENT)) $(TD `ulong`) $(TD $(RARR)) $(TD `BigInt`)) $(TR $(TD `BigInt`) $(TD $(CODE_PERCENT)) $(TD other type) $(TD $(RARR)) $(TD `int`)) ) */ auto opBinary(string op, T)(T y) pure nothrow const if (op == "%" && isIntegral!T) { assert(y!=0); // BigInt % long => long // BigInt % ulong => BigInt // BigInt % other_type => int static if (is(Unqual!T == long) || is(Unqual!T == ulong)) { auto r = this % BigInt(y); static if (is(Unqual!T == long)) { return r.toLong(); } else { // return as-is to avoid overflow return r; } } else { uint u = absUnsign(y); int rem = BigUint.modInt(data, u); // x%y always has the same sign as x. // This is not the same as mathematical mod. return sign ? -rem : rem; } } /// unittest { auto x = BigInt("1_000_000_500"); long l = 1_000_000L; ulong ul = 2_000_000UL; int i = 500_000; short s = 30_000; assert(is(typeof(x % l) == long) && x % l == 500L); assert(is(typeof(x % ul) == BigInt) && x % ul == BigInt(500)); assert(is(typeof(x % i) == int) && x % i == 500); assert(is(typeof(x % s) == int) && x % s == 10500); } /** Implements operators with built-in integers on the left-hand side and BigInt on the right-hand side. */ BigInt opBinaryRight(string op, T)(T y) pure nothrow const if ((op=="+" || op=="*" || op=="|" || op=="&" || op=="^") && isIntegral!T) { return opBinary!(op)(y); } /// unittest { auto x = BigInt("100"); BigInt y = 123 + x; assert(y == BigInt("223")); BigInt z = 123 - x; assert(z == BigInt("23")); // Dividing a built-in integer type by BigInt always results in // something that fits in a built-in type, so the built-in type is // returned, not BigInt. assert(is(typeof(1000 / x) == int)); assert(1000 / x == 10); } // BigInt = integer op BigInt /// ditto BigInt opBinaryRight(string op, T)(T y) pure nothrow const if (op == "-" && isIntegral!T) { ulong u = absUnsign(y); BigInt r; static if (op == "-") { r.sign = sign; r.data = BigUint.addOrSubInt(data, u, sign == (y<0), r.sign); r.negate(); } return r; } // integer = integer op BigInt /// ditto T opBinaryRight(string op, T)(T x) pure nothrow const if ((op=="%" || op=="/") && isIntegral!T) { checkDivByZero(); static if (op == "%") { // x%y always has the same sign as x. if (data.ulongLength > 1) return x; ulong u = absUnsign(x); ulong rem = u % data.peekUlong(0); // x%y always has the same sign as x. return cast(T)((x<0) ? -rem : rem); } else static if (op == "/") { if (data.ulongLength > 1) return 0; return cast(T)(x / data.peekUlong(0)); } } // const unary operations /** Implements BigInt unary operators. */ BigInt opUnary(string op)() pure nothrow const if (op=="+" || op=="-" || op=="~") { static if (op=="-") { BigInt r = this; r.negate(); return r; } else static if (op=="~") { return -(this+1); } else static if (op=="+") return this; } // non-const unary operations /// ditto BigInt opUnary(string op)() pure nothrow if (op=="++" || op=="--") { static if (op=="++") { data = BigUint.addOrSubInt(data, 1UL, sign, sign); return this; } else static if (op=="--") { data = BigUint.addOrSubInt(data, 1UL, !sign, sign); return this; } } /// unittest { auto x = BigInt("1234"); assert(-x == BigInt("-1234")); ++x; assert(x == BigInt("1235")); } /** Implements BigInt equality test with other BigInt's and built-in integer types. */ bool opEquals()(auto ref const BigInt y) const pure @nogc { return sign == y.sign && y.data == data; } /// ditto bool opEquals(T)(T y) const pure nothrow @nogc if (isIntegral!T) { if (sign != (y<0)) return 0; return data.opEquals(cast(ulong)absUnsign(y)); } /// unittest { auto x = BigInt("12345"); auto y = BigInt("12340"); int z = 12345; int w = 54321; assert(x == x); assert(x != y); assert(x == y + 5); assert(x == z); assert(x != w); } /** Implements casting to bool. */ T opCast(T:bool)() pure nothrow @nogc const { return !isZero(); } /// unittest { // Non-zero values are regarded as true auto x = BigInt("1"); auto y = BigInt("10"); assert(x); assert(y); // Zero value is regarded as false auto z = BigInt("0"); assert(!z); } /** Implements casting to integer types. Throws: $(XREF conv,ConvOverflowException) if the number exceeds the target type's range. */ T opCast(T:ulong)() /*pure*/ const { if (isUnsigned!T && sign) { /* throw */ } else if (data.ulongLength == 1) { ulong l = data.peekUlong(0); if (isUnsigned!T || !sign) { if (l <= T.max) return cast(T)l; } else { if (l <= ulong(T.max)+1) return cast(T)-long(l); // -long.min==long.min } } import std.conv : ConvOverflowException; import std.string : format; throw new ConvOverflowException( "BigInt(%d) cannot be represented as a %s" .format(this, T.stringof)); } /// unittest { import std.conv : to, ConvOverflowException; import std.exception : assertThrown; assert(BigInt("0").to!int == 0); assert(BigInt("0").to!ubyte == 0); assert(BigInt("255").to!ubyte == 255); assertThrown!ConvOverflowException(BigInt("256").to!ubyte); assertThrown!ConvOverflowException(BigInt("-1").to!ubyte); } unittest { import std.conv : to, ConvOverflowException; import std.exception : assertThrown; assert(BigInt("-1").to!byte == -1); assert(BigInt("-128").to!byte == -128); assert(BigInt("127").to!byte == 127); assertThrown!ConvOverflowException(BigInt("-129").to!byte); assertThrown!ConvOverflowException(BigInt("128").to!byte); assert(BigInt("0").to!uint == 0); assert(BigInt("4294967295").to!uint == uint.max); assertThrown!ConvOverflowException(BigInt("4294967296").to!uint); assertThrown!ConvOverflowException(BigInt("-1").to!uint); assert(BigInt("-1").to!int == -1); assert(BigInt("-2147483648").to!int == int.min); assert(BigInt("2147483647").to!int == int.max); assertThrown!ConvOverflowException(BigInt("-2147483649").to!int); assertThrown!ConvOverflowException(BigInt("2147483648").to!int); assert(BigInt("0").to!ulong == 0); assert(BigInt("18446744073709551615").to!ulong == ulong.max); assertThrown!ConvOverflowException(BigInt("18446744073709551616").to!ulong); assertThrown!ConvOverflowException(BigInt("-1").to!ulong); assert(BigInt("-1").to!long == -1); assert(BigInt("-9223372036854775808").to!long == long.min); assert(BigInt("9223372036854775807").to!long == long.max); assertThrown!ConvOverflowException(BigInt("-9223372036854775809").to!long); assertThrown!ConvOverflowException(BigInt("9223372036854775808").to!long); } /** Implements casting to/from qualified BigInt's. Warning: Casting to/from $(D const) or $(D immutable) may break type system guarantees. Use with care. */ T opCast(T)() pure nothrow @nogc const if (is(Unqual!T == BigInt)) { return this; } /// unittest { const(BigInt) x = BigInt("123"); BigInt y = cast() x; // cast away const assert(y == x); } // Hack to make BigInt's typeinfo.compare work properly. // Note that this must appear before the other opCmp overloads, otherwise // DMD won't find it. /** Implements 3-way comparisons of BigInt with BigInt or BigInt with built-in integers. */ int opCmp(ref const BigInt y) pure nothrow @nogc const { // Simply redirect to the "real" opCmp implementation. return this.opCmp!BigInt(y); } /// ditto int opCmp(T)(T y) pure nothrow @nogc const if (isIntegral!T) { if (sign != (y<0) ) return sign ? -1 : 1; int cmp = data.opCmp(cast(ulong)absUnsign(y)); return sign? -cmp: cmp; } /// ditto int opCmp(T:BigInt)(const T y) pure nothrow @nogc const { if (sign!=y.sign) return sign ? -1 : 1; int cmp = data.opCmp(y.data); return sign? -cmp: cmp; } /// unittest { auto x = BigInt("100"); auto y = BigInt("10"); int z = 50; const int w = 200; assert(y < x); assert(x > z); assert(z > y); assert(x < w); } /** Returns: The value of this BigInt as a long, or +/- long.max if outside the representable range. */ long toLong() @safe pure nothrow const @nogc { return (sign ? -1 : 1) * (data.ulongLength == 1 && (data.peekUlong(0) <= sign+cast(ulong)(long.max)) // 1+long.max = |long.min| ? cast(long)(data.peekUlong(0)) : long.max); } /// unittest { auto b = BigInt("12345"); long l = b.toLong(); assert(l == 12345); } /** Returns: The value of this BigInt as an int, or +/- int.max if outside the representable range. */ int toInt() @safe pure nothrow @nogc const { return (sign ? -1 : 1) * (data.uintLength == 1 && (data.peekUint(0) <= sign+cast(uint)(int.max)) // 1+int.max = |int.min| ? cast(int)(data.peekUint(0)) : int.max); } /// unittest { auto big = BigInt("5_000_000"); auto i = big.toInt(); assert(i == 5_000_000); // Numbers that are too big to fit into an int will be clamped to int.max. auto tooBig = BigInt("5_000_000_000"); i = tooBig.toInt(); assert(i == int.max); } /// Number of significant uints which are used in storing this number. /// The absolute value of this BigInt is always < 2$(SUPERSCRIPT 32*uintLength) @property size_t uintLength() @safe pure nothrow @nogc const { return data.uintLength; } /// Number of significant ulongs which are used in storing this number. /// The absolute value of this BigInt is always < 2$(SUPERSCRIPT 64*ulongLength) @property size_t ulongLength() @safe pure nothrow @nogc const { return data.ulongLength; } /** Convert the BigInt to string, passing it to the given sink. * * Params: * sink = A delegate for accepting possibly piecewise segments of the * formatted string. * formatString = A format string specifying the output format. * * $(TABLE Available output formats:, * $(TR $(TD "d") $(TD Decimal)) * $(TR $(TD "x") $(TD Hexadecimal, lower case)) * $(TR $(TD "X") $(TD Hexadecimal, upper case)) * $(TR $(TD "s") $(TD Default formatting (same as "d") )) * $(TR $(TD null) $(TD Default formatting (same as "d") )) * ) */ void toString(scope void delegate(const (char)[]) sink, string formatString) const { auto f = FormatSpec!char(formatString); f.writeUpToNextSpec(sink); toString(sink, f); } /// ditto void toString(scope void delegate(const(char)[]) sink, ref FormatSpec!char f) const { auto hex = (f.spec == 'x' || f.spec == 'X'); if (!(f.spec == 's' || f.spec == 'd' || hex)) throw new FormatException("Format specifier not understood: %" ~ f.spec); char[] buff; if (f.spec == 'X') { buff = data.toHexString(0, '_', 0, f.flZero ? '0' : ' ', LetterCase.upper); } else if (f.spec == 'x') { buff = data.toHexString(0, '_', 0, f.flZero ? '0' : ' ', LetterCase.lower); } else { buff = data.toDecimalString(0); } assert(buff.length > 0); char signChar = isNegative() ? '-' : 0; auto minw = buff.length + (signChar ? 1 : 0); if (!hex && !signChar && (f.width == 0 || minw < f.width)) { if (f.flPlus) { signChar = '+'; ++minw; } else if (f.flSpace) { signChar = ' '; ++minw; } } auto maxw = minw < f.width ? f.width : minw; auto difw = maxw - minw; if (!f.flDash && !f.flZero) foreach (i; 0 .. difw) sink(" "); if (signChar) sink((&signChar)[0..1]); if (!f.flDash && f.flZero) foreach (i; 0 .. difw) sink("0"); sink(buff); if (f.flDash) foreach (i; 0 .. difw) sink(" "); } /** $(D toString) is rarely directly invoked; the usual way of using it is via $(LINK2 std_format.html#format, std.format.format): */ unittest { import std.format : format; auto x = BigInt("1_000_000"); x *= 12345; assert(format("%d", x) == "12345000000"); assert(format("%x", x) == "2_dfd1c040"); assert(format("%X", x) == "2_DFD1C040"); } // Implement toHash so that BigInt works properly as an AA key. /** Returns: A unique hash of the BigInt's value suitable for use in a hash table. */ size_t toHash() const @safe nothrow { return data.toHash() + sign; } /** $(D toHash) is rarely directly invoked; it is implicitly used when BigInt is used as the key of an associative array. */ unittest { string[BigInt] aa; aa[BigInt(123)] = "abc"; aa[BigInt(456)] = "def"; assert(aa[BigInt(123)] == "abc"); assert(aa[BigInt(456)] == "def"); } private: void negate() @safe pure nothrow @nogc { if (!data.isZero()) sign = !sign; } bool isZero() pure const nothrow @nogc @safe { return data.isZero(); } bool isNegative() pure const nothrow @nogc @safe { return sign; } // Generate a runtime error if division by zero occurs void checkDivByZero() pure const nothrow @safe { if (isZero()) throw new Error("BigInt division by zero"); } } /// unittest { BigInt a = "9588669891916142"; BigInt b = "7452469135154800"; auto c = a * b; assert(c == BigInt("71459266416693160362545788781600")); auto d = b * a; assert(d == BigInt("71459266416693160362545788781600")); assert(d == c); d = c * BigInt("794628672112"); assert(d == BigInt("56783581982794522489042432639320434378739200")); auto e = c + d; assert(e == BigInt("56783581982865981755459125799682980167520800")); auto f = d + c; assert(f == e); auto g = f - c; assert(g == d); g = f - d; assert(g == c); e = 12345678; g = c + e; auto h = g / b; auto i = g % b; assert(h == a); assert(i == e); BigInt j = "-0x9A56_57f4_7B83_AB78"; j ^^= 11; } /** Params: x = The $(D BigInt) to convert to a decimal $(D string). Returns: A $(D string) that represents the $(D BigInt) as a decimal number. */ string toDecimalString(const(BigInt) x) { string outbuff=""; void sink(const(char)[] s) { outbuff ~= s; } x.toString(&sink, "%d"); return outbuff; } /// unittest { auto x = BigInt("123"); x *= 1000; x += 456; auto xstr = x.toDecimalString(); assert(xstr == "123456"); } /** Params: x = The $(D BigInt) to convert to a hexadecimal $(D string). Returns: A $(D string) that represents the $(D BigInt) as a hexadecimal (base 16) number in upper case. */ string toHex(const(BigInt) x) { string outbuff=""; void sink(const(char)[] s) { outbuff ~= s; } x.toString(&sink, "%X"); return outbuff; } /// unittest { auto x = BigInt("123"); x *= 1000; x += 456; auto xstr = x.toHex(); assert(xstr == "1E240"); } /** Returns the absolute value of x converted to the corresponding unsigned type. Params: x = The integral value to return the absolute value of. Returns: The absolute value of x. */ Unsigned!T absUnsign(T)(T x) if (isIntegral!T) { static if (isSigned!T) { import std.conv; /* This returns the correct result even when x = T.min * on two's complement machines because unsigned(T.min) = |T.min| * even though -T.min = T.min. */ return unsigned((x < 0) ? -x : x); } else { return x; } } nothrow pure unittest { BigInt a, b; a = 1; b = 2; auto c = a + b; } nothrow pure unittest { long a; BigInt b; auto c = a + b; auto d = b + a; } nothrow pure unittest { BigInt x = 1, y = 2; assert(x < y); assert(x <= y); assert(y >= x); assert(y > x); assert(x != y); long r1 = x.toLong; assert(r1 == 1); BigInt r2 = 10 % x; assert(r2 == 0); BigInt r3 = 10 / y; assert(r3 == 5); BigInt[] arr = [BigInt(1)]; auto incr = arr[0]++; assert(arr == [BigInt(2)]); assert(incr == BigInt(1)); } unittest { // Radix conversion assert( toDecimalString(BigInt("-1_234_567_890_123_456_789")) == "-1234567890123456789"); assert( toHex(BigInt("0x1234567890123456789")) == "123_45678901_23456789"); assert( toHex(BigInt("0x00000000000000000000000000000000000A234567890123456789")) == "A23_45678901_23456789"); assert( toHex(BigInt("0x000_00_000000_000_000_000000000000_000000_")) == "0"); assert(BigInt(-0x12345678).toInt() == -0x12345678); assert(BigInt(-0x12345678).toLong() == -0x12345678); assert(BigInt(0x1234_5678_9ABC_5A5AL).ulongLength == 1); assert(BigInt(0x1234_5678_9ABC_5A5AL).toLong() == 0x1234_5678_9ABC_5A5AL); assert(BigInt(-0x1234_5678_9ABC_5A5AL).toLong() == -0x1234_5678_9ABC_5A5AL); assert(BigInt(0xF234_5678_9ABC_5A5AL).toLong() == long.max); assert(BigInt(-0x123456789ABCL).toInt() == -int.max); char[] s1 = "123".dup; // bug 8164 assert(BigInt(s1) == 123); char[] s2 = "0xABC".dup; assert(BigInt(s2) == 2748); assert((BigInt(-2) + BigInt(1)) == BigInt(-1)); BigInt a = ulong.max - 5; auto b = -long.max % a; assert( b == -long.max % (ulong.max - 5)); b = long.max / a; assert( b == long.max /(ulong.max - 5)); assert(BigInt(1) - 1 == 0); assert((-4) % BigInt(5) == -4); // bug 5928 assert(BigInt(-4) % BigInt(5) == -4); assert(BigInt(2)/BigInt(-3) == BigInt(0)); // bug 8022 assert(BigInt("-1") > long.min); // bug 9548 } unittest // Minimum signed value bug tests. { assert(BigInt("-0x8000000000000000") == BigInt(long.min)); assert(BigInt("-0x8000000000000000")+1 > BigInt(long.min)); assert(BigInt("-0x80000000") == BigInt(int.min)); assert(BigInt("-0x80000000")+1 > BigInt(int.min)); assert(BigInt(long.min).toLong() == long.min); // lossy toLong bug for long.min assert(BigInt(int.min).toInt() == int.min); // lossy toInt bug for int.min assert(BigInt(long.min).ulongLength == 1); assert(BigInt(int.min).uintLength == 1); // cast/sign extend bug in opAssign BigInt a; a += int.min; assert(a == BigInt(int.min)); a = int.min - BigInt(int.min); assert(a == 0); a = int.min; assert(a == BigInt(int.min)); assert(int.min % (BigInt(int.min)-1) == int.min); assert((BigInt(int.min)-1)%int.min == -1); } unittest // Recursive division, bug 5568 { enum Z = 4843; BigInt m = (BigInt(1) << (Z*8) ) - 1; m -= (BigInt(1) << (Z*6)) - 1; BigInt oldm = m; BigInt a = (BigInt(1) << (Z*4) )-1; BigInt b = m % a; m /= a; m *= a; assert( m + b == oldm); m = (BigInt(1) << (4846 + 4843) ) - 1; a = (BigInt(1) << 4846 ) - 1; b = (BigInt(1) << (4846*2 + 4843)) - 1; BigInt c = (BigInt(1) << (4846*2 + 4843*2)) - 1; BigInt w = c - b + a; assert(w % m == 0); // Bug 6819. ^^ BigInt z1 = BigInt(10)^^64; BigInt w1 = BigInt(10)^^128; assert(z1^^2 == w1); BigInt z2 = BigInt(1)<<64; BigInt w2 = BigInt(1)<<128; assert(z2^^2 == w2); // Bug 7993 BigInt n7793 = 10; assert( n7793 / 1 == 10); // Bug 7973 auto a7973 = 10_000_000_000_000_000; const c7973 = 10_000_000_000_000_000; immutable i7973 = 10_000_000_000_000_000; BigInt v7973 = 2551700137; v7973 %= a7973; assert(v7973 == 2551700137); v7973 %= c7973; assert(v7973 == 2551700137); v7973 %= i7973; assert(v7973 == 2551700137); // 8165 BigInt[2] a8165; a8165[0] = a8165[1] = 1; } unittest { import std.array; import std.format; immutable string[][] table = [ /* fmt, +10 -10 */ ["%d", "10", "-10"], ["%+d", "+10", "-10"], ["%-d", "10", "-10"], ["%+-d", "+10", "-10"], ["%4d", " 10", " -10"], ["%+4d", " +10", " -10"], ["%-4d", "10 ", "-10 "], ["%+-4d", "+10 ", "-10 "], ["%04d", "0010", "-010"], ["%+04d", "+010", "-010"], ["%-04d", "10 ", "-10 "], ["%+-04d", "+10 ", "-10 "], ["% 04d", " 010", "-010"], ["%+ 04d", "+010", "-010"], ["%- 04d", " 10 ", "-10 "], ["%+- 04d", "+10 ", "-10 "], ]; auto w1 = appender!(char[])(); auto w2 = appender!(char[])(); foreach (entry; table) { immutable fmt = entry[0]; formattedWrite(w1, fmt, BigInt(10)); formattedWrite(w2, fmt, 10); assert(w1.data == w2.data); assert(w1.data == entry[1]); w1.clear(); w2.clear(); formattedWrite(w1, fmt, BigInt(-10)); formattedWrite(w2, fmt, -10); assert(w1.data == w2.data); assert(w1.data == entry[2]); w1.clear(); w2.clear(); } } unittest { import std.array; import std.format; immutable string[][] table = [ /* fmt, +10 -10 */ ["%x", "a", "-a"], ["%+x", "a", "-a"], ["%-x", "a", "-a"], ["%+-x", "a", "-a"], ["%4x", " a", " -a"], ["%+4x", " a", " -a"], ["%-4x", "a ", "-a "], ["%+-4x", "a ", "-a "], ["%04x", "000a", "-00a"], ["%+04x", "000a", "-00a"], ["%-04x", "a ", "-a "], ["%+-04x", "a ", "-a "], ["% 04x", "000a", "-00a"], ["%+ 04x", "000a", "-00a"], ["%- 04x", "a ", "-a "], ["%+- 04x", "a ", "-a "], ]; auto w1 = appender!(char[])(); auto w2 = appender!(char[])(); foreach (entry; table) { immutable fmt = entry[0]; formattedWrite(w1, fmt, BigInt(10)); formattedWrite(w2, fmt, 10); assert(w1.data == w2.data); // Equal only positive BigInt assert(w1.data == entry[1]); w1.clear(); w2.clear(); formattedWrite(w1, fmt, BigInt(-10)); //formattedWrite(w2, fmt, -10); //assert(w1.data == w2.data); assert(w1.data == entry[2]); w1.clear(); //w2.clear(); } } unittest { import std.array; import std.format; immutable string[][] table = [ /* fmt, +10 -10 */ ["%X", "A", "-A"], ["%+X", "A", "-A"], ["%-X", "A", "-A"], ["%+-X", "A", "-A"], ["%4X", " A", " -A"], ["%+4X", " A", " -A"], ["%-4X", "A ", "-A "], ["%+-4X", "A ", "-A "], ["%04X", "000A", "-00A"], ["%+04X", "000A", "-00A"], ["%-04X", "A ", "-A "], ["%+-04X", "A ", "-A "], ["% 04X", "000A", "-00A"], ["%+ 04X", "000A", "-00A"], ["%- 04X", "A ", "-A "], ["%+- 04X", "A ", "-A "], ]; auto w1 = appender!(char[])(); auto w2 = appender!(char[])(); foreach (entry; table) { immutable fmt = entry[0]; formattedWrite(w1, fmt, BigInt(10)); formattedWrite(w2, fmt, 10); assert(w1.data == w2.data); // Equal only positive BigInt assert(w1.data == entry[1]); w1.clear(); w2.clear(); formattedWrite(w1, fmt, BigInt(-10)); //formattedWrite(w2, fmt, -10); //assert(w1.data == w2.data); assert(w1.data == entry[2]); w1.clear(); //w2.clear(); } } // 6448 unittest { import std.array; import std.format; auto w1 = appender!string(); auto w2 = appender!string(); int x = 100; formattedWrite(w1, "%010d", x); BigInt bx = x; formattedWrite(w2, "%010d", bx); assert(w1.data == w2.data); //8011 BigInt y = -3; ++y; assert(y.toLong() == -2); y = 1; --y; assert(y.toLong() == 0); --y; assert(y.toLong() == -1); --y; assert(y.toLong() == -2); } unittest { import std.math:abs; auto r = abs(BigInt(-1000)); // 6486 assert(r == 1000); auto r2 = abs(const(BigInt)(-500)); // 11188 assert(r2 == 500); auto r3 = abs(immutable(BigInt)(-733)); // 11188 assert(r3 == 733); // opCast!bool BigInt one = 1, zero; assert(one && !zero); } unittest // 6850 { pure long pureTest() { BigInt a = 1; BigInt b = 1336; a += b; return a.toLong(); } assert(pureTest() == 1337); } unittest // 8435 & 10118 { auto i = BigInt(100); auto j = BigInt(100); // Two separate BigInt instances representing same value should have same // hash. assert(typeid(i).getHash(&i) == typeid(j).getHash(&j)); assert(typeid(i).compare(&i, &j) == 0); // BigInt AA keys should behave consistently. int[BigInt] aa; aa[BigInt(123)] = 123; assert(BigInt(123) in aa); aa[BigInt(123)] = 321; assert(aa[BigInt(123)] == 321); auto keys = aa.byKey; assert(keys.front == BigInt(123)); keys.popFront(); assert(keys.empty); } unittest // 11148 { void foo(BigInt) {} const BigInt cbi = 3; immutable BigInt ibi = 3; assert(__traits(compiles, foo(cbi))); assert(__traits(compiles, foo(ibi))); import std.meta : AliasSeq; import std.conv : to; foreach (T1; AliasSeq!(BigInt, const(BigInt), immutable(BigInt))) { foreach (T2; AliasSeq!(BigInt, const(BigInt), immutable(BigInt))) { T1 t1 = 2; T2 t2 = t1; T2 t2_1 = to!T2(t1); T2 t2_2 = cast(T2)t1; assert(t2 == t1); assert(t2 == 2); assert(t2_1 == t1); assert(t2_1 == 2); assert(t2_2 == t1); assert(t2_2 == 2); } } BigInt n = 2; n *= 2; } unittest // 8167 { BigInt a = BigInt(3); BigInt b = BigInt(a); } unittest // 9061 { long l1 = 0x12345678_90ABCDEF; long l2 = 0xFEDCBA09_87654321; long l3 = l1 | l2; long l4 = l1 & l2; long l5 = l1 ^ l2; BigInt b1 = l1; BigInt b2 = l2; BigInt b3 = b1 | b2; BigInt b4 = b1 & b2; BigInt b5 = b1 ^ b2; assert(l3 == b3); assert(l4 == b4); assert(l5 == b5); } unittest // 11600 { import std.conv; import std.exception : assertThrown; // Original bug report assertThrown!ConvException(to!BigInt("avadakedavra")); // Digit string lookalikes that are actually invalid assertThrown!ConvException(to!BigInt("0123hellothere")); assertThrown!ConvException(to!BigInt("-hihomarylowe")); assertThrown!ConvException(to!BigInt("__reallynow__")); assertThrown!ConvException(to!BigInt("-123four")); } unittest // 11583 { BigInt x = 0; assert((x > 0) == false); } unittest // 13391 { BigInt x1 = "123456789"; BigInt x2 = "123456789123456789"; BigInt x3 = "123456789123456789123456789"; import std.meta : AliasSeq; foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) { assert((x1 * T.max) / T.max == x1); assert((x2 * T.max) / T.max == x2); assert((x3 * T.max) / T.max == x3); } assert(x1 / -123456789 == -1); assert(x1 / 123456789U == 1); assert(x1 / -123456789L == -1); assert(x1 / 123456789UL == 1); assert(x2 / -123456789123456789L == -1); assert(x2 / 123456789123456789UL == 1); assert(x1 / uint.max == 0); assert(x1 / ulong.max == 0); assert(x2 / ulong.max == 0); x1 /= 123456789UL; assert(x1 == 1); x2 /= 123456789123456789UL; assert(x2 == 1); } unittest // 13963 { BigInt x = 1; import std.meta : AliasSeq; foreach(Int; AliasSeq!(byte, ubyte, short, ushort, int, uint)) { assert(is(typeof(x % Int(1)) == int)); } assert(is(typeof(x % 1L) == long)); assert(is(typeof(x % 1UL) == BigInt)); auto x1 = BigInt(8); auto x2 = -BigInt(long.min) + 1; // long assert(x1 % 2L == 0L); assert(-x1 % 2L == 0L); assert(x1 % 3L == 2L); assert(x1 % -3L == 2L); assert(-x1 % 3L == -2L); assert(-x1 % -3L == -2L); assert(x1 % 11L == 8L); assert(x1 % -11L == 8L); assert(-x1 % 11L == -8L); assert(-x1 % -11L == -8L); // ulong assert(x1 % 2UL == BigInt(0)); assert(-x1 % 2UL == BigInt(0)); assert(x1 % 3UL == BigInt(2)); assert(-x1 % 3UL == -BigInt(2)); assert(x1 % 11UL == BigInt(8)); assert(-x1 % 11UL == -BigInt(8)); assert(x2 % ulong.max == x2); assert(-x2 % ulong.max == -x2); } unittest // 14124 { auto x = BigInt(-3); x %= 3; assert(!x.isNegative()); assert(x.isZero()); x = BigInt(-3); x %= cast(ushort)3; assert(!x.isNegative()); assert(x.isZero()); x = BigInt(-3); x %= 3L; assert(!x.isNegative()); assert(x.isZero()); x = BigInt(3); x %= -3; assert(!x.isNegative()); assert(x.isZero()); } // issue 15678 unittest { import std.exception : assertThrown; assertThrown!ConvException(BigInt("")); assertThrown!ConvException(BigInt("0x1234BARF")); assertThrown!ConvException(BigInt("1234PUKE")); } ldc-1.1.0-beta3-src/runtime/phobos/std/numeric.d0000664000175000017500000027451412776215007017532 0ustar kaikai// Written in the D programming language. /** This module is a port of a growing fragment of the $(D_PARAM numeric) header in Alexander Stepanov's $(LINK2 http://sgi.com/tech/stl, Standard Template Library), with a few additions. Macros: WIKI = Phobos/StdNumeric Copyright: Copyright Andrei Alexandrescu 2008 - 2009. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.org, Andrei Alexandrescu), Don Clugston, Robert Jacques Source: $(PHOBOSSRC std/_numeric.d) */ /* Copyright Andrei Alexandrescu 2008 - 2009. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.numeric; import std.complex; import std.exception; import std.math; import std.range.primitives; import std.traits; import std.typecons; version(unittest) { import std.stdio; } /// Format flags for CustomFloat. public enum CustomFloatFlags { /// Adds a sign bit to allow for signed numbers. signed = 1, /** * Store values in normalized form by default. The actual precision of the * significand is extended by 1 bit by assuming an implicit leading bit of 1 * instead of 0. i.e. $(D 1.nnnn) instead of $(D 0.nnnn). * True for all $(LUCKY IEE754) types */ storeNormalized = 2, /** * Stores the significand in $(LUCKY IEEE754 denormalized) form when the * exponent is 0. Required to express the value 0. */ allowDenorm = 4, /// Allows the storage of $(LUCKY IEEE754 _infinity) values. infinity = 8, /// Allows the storage of $(LUCKY IEEE754 Not a Number) values. nan = 16, /** * If set, select an exponent bias such that max_exp = 1. * i.e. so that the maximum value is >= 1.0 and < 2.0. * Ignored if the exponent bias is manually specified. */ probability = 32, /// If set, unsigned custom floats are assumed to be negative. negativeUnsigned = 64, /**If set, 0 is the only allowed $(LUCKY IEEE754 denormalized) number. * Requires allowDenorm and storeNormalized. */ allowDenormZeroOnly = 128 | allowDenorm | storeNormalized, /// Include _all of the $(LUCKY IEEE754) options. ieee = signed | storeNormalized | allowDenorm | infinity | nan , /// Include none of the above options. none = 0 } private template CustomFloatParams(uint bits) { enum CustomFloatFlags flags = CustomFloatFlags.ieee ^ ((bits == 80) ? CustomFloatFlags.storeNormalized : CustomFloatFlags.none); static if (bits == 8) alias CustomFloatParams = CustomFloatParams!( 4, 3, flags); static if (bits == 16) alias CustomFloatParams = CustomFloatParams!(10, 5, flags); static if (bits == 32) alias CustomFloatParams = CustomFloatParams!(23, 8, flags); static if (bits == 64) alias CustomFloatParams = CustomFloatParams!(52, 11, flags); static if (bits == 80) alias CustomFloatParams = CustomFloatParams!(64, 15, flags); } private template CustomFloatParams(uint precision, uint exponentWidth, CustomFloatFlags flags) { import std.meta : AliasSeq; alias CustomFloatParams = AliasSeq!( precision, exponentWidth, flags, (1 << (exponentWidth - ((flags & flags.probability) == 0))) - ((flags & (flags.nan | flags.infinity)) != 0) - ((flags & flags.probability) != 0) ); // ((flags & CustomFloatFlags.probability) == 0) } /** * Allows user code to define custom floating-point formats. These formats are * for storage only; all operations on them are performed by first implicitly * extracting them to $(D real) first. After the operation is completed the * result can be stored in a custom floating-point value via assignment. */ template CustomFloat(uint bits) if (bits == 8 || bits == 16 || bits == 32 || bits == 64 || bits == 80) { alias CustomFloat = CustomFloat!(CustomFloatParams!(bits)); } /// ditto template CustomFloat(uint precision, uint exponentWidth, CustomFloatFlags flags = CustomFloatFlags.ieee) if (((flags & flags.signed) + precision + exponentWidth) % 8 == 0 && precision + exponentWidth > 0) { alias CustomFloat = CustomFloat!(CustomFloatParams!(precision, exponentWidth, flags)); } /// unittest { // Define a 16-bit floating point values CustomFloat!16 x; // Using the number of bits CustomFloat!(10, 5) y; // Using the precision and exponent width CustomFloat!(10, 5,CustomFloatFlags.ieee) z; // Using the precision, exponent width and format flags CustomFloat!(10, 5,CustomFloatFlags.ieee, 15) w; // Using the precision, exponent width, format flags and exponent offset bias // Use the 16-bit floats mostly like normal numbers w = x*y - 1; // Functions calls require conversion z = sin(+x) + cos(+y); // Use unary plus to concisely convert to a real z = sin(x.get!float) + cos(y.get!float); // Or use get!T z = sin(cast(float)x) + cos(cast(float)y); // Or use cast(T) to explicitly convert // Define a 8-bit custom float for storing probabilities alias Probability = CustomFloat!(4, 4, CustomFloatFlags.ieee^CustomFloatFlags.probability^CustomFloatFlags.signed ); auto p = Probability(0.5); } /// ditto struct CustomFloat(uint precision, // fraction bits (23 for float) uint exponentWidth, // exponent bits (8 for float) Exponent width CustomFloatFlags flags, uint bias) if (((flags & flags.signed) + precision + exponentWidth) % 8 == 0 && precision + exponentWidth > 0) { import std.bitmanip; import std.meta; private: // get the correct unsigned bitfield type to support > 32 bits template uType(uint bits) { static if(bits <= size_t.sizeof*8) alias uType = size_t; else alias uType = ulong ; } // get the correct signed bitfield type to support > 32 bits template sType(uint bits) { static if(bits <= ptrdiff_t.sizeof*8-1) alias sType = ptrdiff_t; else alias sType = long; } alias T_sig = uType!precision; alias T_exp = uType!exponentWidth; alias T_signed_exp = sType!exponentWidth; alias Flags = CustomFloatFlags; // Facilitate converting numeric types to custom float union ToBinary(F) if (is(typeof(CustomFloatParams!(F.sizeof*8))) || is(F == real)) { F set; // If on Linux or Mac, where 80-bit reals are padded, ignore the // padding. import std.algorithm : min; CustomFloat!(CustomFloatParams!(min(F.sizeof*8, 80))) get; // Convert F to the correct binary type. static typeof(get) opCall(F value) { ToBinary r; r.set = value; return r.get; } alias get this; } // Perform IEEE rounding with round to nearest detection void roundedShift(T,U)(ref T sig, U shift) { if (sig << (T.sizeof*8 - shift) == cast(T) 1uL << (T.sizeof*8 - 1)) { // round to even sig >>= shift; sig += sig & 1; } else { sig >>= shift - 1; sig += sig & 1; // Perform standard rounding sig >>= 1; } } // Convert the current value to signed exponent, normalized form void toNormalized(T,U)(ref T sig, ref U exp) { sig = significand; auto shift = (T.sizeof*8) - precision; exp = exponent; static if (flags&(Flags.infinity|Flags.nan)) { // Handle inf or nan if (exp == exponent_max) { exp = exp.max; sig <<= shift; static if (flags&Flags.storeNormalized) { // Save inf/nan in denormalized format sig >>= 1; sig += cast(T) 1uL << (T.sizeof*8 - 1); } return; } } if ((~flags&Flags.storeNormalized) || // Convert denormalized form to normalized form ((flags&Flags.allowDenorm) && exp==0)) { if(sig > 0) { import core.bitop : bsr; auto shift2 = precision - bsr(sig); exp -= shift2-1; shift += shift2; } else // value = 0.0 { exp = exp.min; return; } } sig <<= shift; exp -= bias; } // Set the current value from signed exponent, normalized form void fromNormalized(T,U)(ref T sig, ref U exp) { auto shift = (T.sizeof*8) - precision; if (exp == exp.max) { // infinity or nan exp = exponent_max; static if (flags & Flags.storeNormalized) sig <<= 1; // convert back to normalized form static if (~flags & Flags.infinity) // No infinity support? enforce(sig != 0, "Infinity floating point value assigned to a " ~ typeof(this).stringof~" (no infinity support)."); static if (~flags & Flags.nan) // No NaN support? enforce(sig == 0,"NaN floating point value assigned to a " ~ typeof(this).stringof~" (no nan support)."); sig >>= shift; return; } if (exp == exp.min) // 0.0 { exp = 0; sig = 0; return; } exp += bias; if (exp <= 0) { static if ((flags&Flags.allowDenorm) || // Convert from normalized form to denormalized (~flags&Flags.storeNormalized)) { shift += -exp; roundedShift(sig,1); sig += cast(T) 1uL << (T.sizeof*8 - 1); // Add the leading 1 exp = 0; } else enforce((flags&Flags.storeNormalized) && exp == 0, "Underflow occured assigning to a " ~ typeof(this).stringof ~ " (no denormal support)."); } else { static if (~flags&Flags.storeNormalized) { // Convert from normalized form to denormalized roundedShift(sig,1); sig += cast(T) 1uL << (T.sizeof*8 - 1); // Add the leading 1 } } if (shift > 0) roundedShift(sig,shift); if (sig > significand_max) { // handle significand overflow (should only be 1 bit) static if (~flags&Flags.storeNormalized) { sig >>= 1; } else sig &= significand_max; exp++; } static if ((flags&Flags.allowDenormZeroOnly)==Flags.allowDenormZeroOnly) { // disallow non-zero denormals if (exp == 0) { sig <<= 1; if (sig > significand_max && (sig&significand_max) > 0) // Check and round to even exp++; sig = 0; } } if (exp >= exponent_max) { static if (flags&(Flags.infinity|Flags.nan)) { sig = 0; exp = exponent_max; static if (~flags&(Flags.infinity)) enforce(false, "Overflow occured assigning to a " ~ typeof(this).stringof~" (no infinity support)."); } else enforce(exp == exponent_max, "Overflow occured assigning to a " ~ typeof(this).stringof~" (no infinity support)."); } } public: static if (precision == 64) // CustomFloat!80 support hack { ulong significand; enum ulong significand_max = ulong.max; mixin(bitfields!( T_exp , "exponent", exponentWidth, bool , "sign" , flags & flags.signed )); } else { mixin(bitfields!( T_sig, "significand", precision, T_exp, "exponent" , exponentWidth, bool , "sign" , flags & flags.signed )); } /// Returns: infinity value static if (flags & Flags.infinity) static @property CustomFloat infinity() { CustomFloat value; static if (flags & Flags.signed) value.sign = 0; value.significand = 0; value.exponent = exponent_max; return value; } /// Returns: NaN value static if (flags & Flags.nan) static @property CustomFloat nan() { CustomFloat value; static if (flags & Flags.signed) value.sign = 0; value.significand = cast(typeof(significand_max)) 1L << (precision-1); value.exponent = exponent_max; return value; } /// Returns: number of decimal digits of precision static @property size_t dig() { auto shiftcnt = precision - ((flags&Flags.storeNormalized) != 0); auto x = (shiftcnt == 64) ? 0 : 1uL << shiftcnt; return cast(size_t) log10(x); } /// Returns: smallest increment to the value 1 static @property CustomFloat epsilon() { CustomFloat value; static if (flags & Flags.signed) value.sign = 0; T_signed_exp exp = -precision; T_sig sig = 0; value.fromNormalized(sig,exp); if (exp == 0 && sig == 0) // underflowed to zero { static if ((flags&Flags.allowDenorm) || (~flags&Flags.storeNormalized)) sig = 1; else sig = cast(T) 1uL << (precision - 1); } value.exponent = cast(value.T_exp) exp; value.significand = cast(value.T_sig) sig; return value; } /// the number of bits in mantissa enum mant_dig = precision + ((flags&Flags.storeNormalized) != 0); /// Returns: maximum int value such that 10max_10_exp is representable static @property int max_10_exp(){ return cast(int) log10( +max ); } /// maximum int value such that 2max_exp-1 is representable enum max_exp = exponent_max-bias+((~flags&(Flags.infinity|flags.nan))!=0); /// Returns: minimum int value such that 10min_10_exp is representable static @property int min_10_exp(){ return cast(int) log10( +min_normal ); } /// minimum int value such that 2min_exp-1 is representable as a normalized value enum min_exp = cast(T_signed_exp)-bias +1+ ((flags&Flags.allowDenorm)!=0); /// Returns: largest representable value that's not infinity static @property CustomFloat max() { CustomFloat value; static if (flags & Flags.signed) value.sign = 0; value.exponent = exponent_max - ((flags&(flags.infinity|flags.nan)) != 0); value.significand = significand_max; return value; } /// Returns: smallest representable normalized value that's not 0 static @property CustomFloat min_normal() { CustomFloat value; static if (flags & Flags.signed) value.sign = 0; value.exponent = 1; static if(flags&Flags.storeNormalized) value.significand = 0; else value.significand = cast(T_sig) 1uL << (precision - 1); return value; } /// Returns: real part @property CustomFloat re() { return this; } /// Returns: imaginary part static @property CustomFloat im() { return CustomFloat(0.0f); } /// Initialize from any $(D real) compatible type. this(F)(F input) if (__traits(compiles, cast(real)input )) { this = input; } /// Self assignment void opAssign(F:CustomFloat)(F input) { static if (flags & Flags.signed) sign = input.sign; exponent = input.exponent; significand = input.significand; } /// Assigns from any $(D real) compatible type. void opAssign(F)(F input) if (__traits(compiles, cast(real)input)) { import std.conv: text; static if (staticIndexOf!(Unqual!F, float, double, real) >= 0) auto value = ToBinary!(Unqual!F)(input); else auto value = ToBinary!(real )(input); // Assign the sign bit static if (~flags & Flags.signed) enforce( (!value.sign)^((flags&flags.negativeUnsigned)>0) , "Incorrectly signed floating point value assigned to a " ~ typeof(this).stringof~" (no sign support)."); else sign = value.sign; CommonType!(T_signed_exp ,value.T_signed_exp) exp = value.exponent; CommonType!(T_sig, value.T_sig ) sig = value.significand; value.toNormalized(sig,exp); fromNormalized(sig,exp); assert(exp <= exponent_max, text(typeof(this).stringof ~ " exponent too large: " ,exp," > ",exponent_max, "\t",input,"\t",sig)); assert(sig <= significand_max, text(typeof(this).stringof ~ " significand too large: ",sig," > ",significand_max, "\t",input,"\t",exp," ",exponent_max)); exponent = cast(T_exp) exp; significand = cast(T_sig) sig; } /// Fetches the stored value either as a $(D float), $(D double) or $(D real). @property F get(F)() if (staticIndexOf!(Unqual!F, float, double, real) >= 0) { import std.conv: text; ToBinary!F result; static if (flags&Flags.signed) result.sign = sign; else result.sign = (flags&flags.negativeUnsigned) > 0; CommonType!(T_signed_exp ,result.get.T_signed_exp ) exp = exponent; // Assign the exponent and fraction CommonType!(T_sig, result.get.T_sig ) sig = significand; toNormalized(sig,exp); result.fromNormalized(sig,exp); assert(exp <= result.exponent_max, text("get exponent too large: " ,exp," > ",result.exponent_max) ); assert(sig <= result.significand_max, text("get significand too large: ",sig," > ",result.significand_max) ); result.exponent = cast(result.get.T_exp) exp; result.significand = cast(result.get.T_sig) sig; return result.set; } ///ditto T opCast(T)() if (__traits(compiles, get!T )) { return get!T; } /// Convert the CustomFloat to a real and perform the relavent operator on the result real opUnary(string op)() if (__traits(compiles, mixin(op~`(get!real)`)) || op=="++" || op=="--") { static if (op=="++" || op=="--") { auto result = get!real; this = mixin(op~`result`); return result; } else return mixin(op~`get!real`); } /// ditto real opBinary(string op,T)(T b) if (__traits(compiles, mixin(`get!real`~op~`b`))) { return mixin(`get!real`~op~`b`); } /// ditto real opBinaryRight(string op,T)(T a) if ( __traits(compiles, mixin(`a`~op~`get!real`)) && !__traits(compiles, mixin(`get!real`~op~`b`))) { return mixin(`a`~op~`get!real`); } /// ditto int opCmp(T)(auto ref T b) if (__traits(compiles, cast(real)b)) { auto x = get!real; auto y = cast(real) b; return (x>=y)-(x<=y); } /// ditto void opOpAssign(string op, T)(auto ref T b) if (__traits(compiles, mixin(`get!real`~op~`cast(real)b`))) { return mixin(`this = this `~op~` cast(real)b`); } /// ditto template toString() { import std.format : FormatSpec, formatValue; // Needs to be a template because of DMD @@BUG@@ 13737. void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) { sink.formatValue(get!real, fmt); } } } unittest { import std.meta; alias FPTypes = AliasSeq!( CustomFloat!(5, 10), CustomFloat!(5, 11, CustomFloatFlags.ieee ^ CustomFloatFlags.signed), CustomFloat!(1, 15, CustomFloatFlags.ieee ^ CustomFloatFlags.signed), CustomFloat!(4, 3, CustomFloatFlags.ieee | CustomFloatFlags.probability ^ CustomFloatFlags.signed) ); foreach (F; FPTypes) { auto x = F(0.125); assert(x.get!float == 0.125F); assert(x.get!double == 0.125); x -= 0.0625; assert(x.get!float == 0.0625F); assert(x.get!double == 0.0625); x *= 2; assert(x.get!float == 0.125F); assert(x.get!double == 0.125); x /= 4; assert(x.get!float == 0.03125); assert(x.get!double == 0.03125); x = 0.5; x ^^= 4; assert(x.get!float == 1 / 16.0F); assert(x.get!double == 1 / 16.0); } } unittest { import std.conv; CustomFloat!(5, 10) y = CustomFloat!(5, 10)(0.125); assert(y.to!string == "0.125"); } /** Defines the fastest type to use when storing temporaries of a calculation intended to ultimately yield a result of type $(D F) (where $(D F) must be one of $(D float), $(D double), or $(D real)). When doing a multi-step computation, you may want to store intermediate results as $(D FPTemporary!F). The necessity of $(D FPTemporary) stems from the optimized floating-point operations and registers present in virtually all processors. When adding numbers in the example above, the addition may in fact be done in $(D real) precision internally. In that case, storing the intermediate $(D result) in $(D double format) is not only less precise, it is also (surprisingly) slower, because a conversion from $(D real) to $(D double) is performed every pass through the loop. This being a lose-lose situation, $(D FPTemporary!F) has been defined as the $(I fastest) type to use for calculations at precision $(D F). There is no need to define a type for the $(I most accurate) calculations, as that is always $(D real). Finally, there is no guarantee that using $(D FPTemporary!F) will always be fastest, as the speed of floating-point calculations depends on very many factors. */ template FPTemporary(F) if (isFloatingPoint!F) { alias FPTemporary = real; } /// unittest { // Average numbers in an array double avg(in double[] a) { if (a.length == 0) return 0; FPTemporary!double result = 0; foreach (e; a) result += e; return result / a.length; } auto a = [1.0, 2.0, 3.0]; assert(approxEqual(avg(a), 2)); } /** Implements the $(WEB tinyurl.com/2zb9yr, secant method) for finding a root of the function $(D fun) starting from points $(D [xn_1, x_n]) (ideally close to the root). $(D Num) may be $(D float), $(D double), or $(D real). */ template secantMethod(alias fun) { import std.functional : unaryFun; Num secantMethod(Num)(Num xn_1, Num xn) { auto fxn = unaryFun!(fun)(xn_1), d = xn_1 - xn; typeof(fxn) fxn_1; xn = xn_1; while (!approxEqual(d, 0) && isFinite(d)) { xn_1 = xn; xn -= d; fxn_1 = fxn; fxn = unaryFun!(fun)(xn); d *= -fxn / (fxn - fxn_1); } return xn; } } /// unittest { float f(float x) { return cos(x) - x*x*x; } auto x = secantMethod!(f)(0f, 1f); assert(approxEqual(x, 0.865474)); } unittest { scope(failure) stderr.writeln("Failure testing secantMethod"); float f(float x) { return cos(x) - x*x*x; } immutable x = secantMethod!(f)(0f, 1f); assert(approxEqual(x, 0.865474)); auto d = &f; immutable y = secantMethod!(d)(0f, 1f); assert(approxEqual(y, 0.865474)); } /** * Return true if a and b have opposite sign. */ private bool oppositeSigns(T1, T2)(T1 a, T2 b) { return signbit(a) != signbit(b); } public: /** Find a real root of a real function f(x) via bracketing. * * Given a function $(D f) and a range $(D [a..b]) such that $(D f(a)) * and $(D f(b)) have opposite signs or at least one of them equals ±0, * returns the value of $(D x) in * the range which is closest to a root of $(D f(x)). If $(D f(x)) * has more than one root in the range, one will be chosen * arbitrarily. If $(D f(x)) returns NaN, NaN will be returned; * otherwise, this algorithm is guaranteed to succeed. * * Uses an algorithm based on TOMS748, which uses inverse cubic * interpolation whenever possible, otherwise reverting to parabolic * or secant interpolation. Compared to TOMS748, this implementation * improves worst-case performance by a factor of more than 100, and * typical performance by a factor of 2. For 80-bit reals, most * problems require 8 to 15 calls to $(D f(x)) to achieve full machine * precision. The worst-case performance (pathological cases) is * approximately twice the number of bits. * * References: "On Enclosing Simple Roots of Nonlinear Equations", * G. Alefeld, F.A. Potra, Yixun Shi, Mathematics of Computation 61, * pp733-744 (1993). Fortran code available from $(WEB * www.netlib.org,www.netlib.org) as algorithm TOMS478. * */ T findRoot(T, DF, DT)(scope DF f, in T a, in T b, scope DT tolerance) //= (T a, T b) => false) if( isFloatingPoint!T && is(typeof(tolerance(T.init, T.init)) : bool) && is(typeof(f(T.init)) == R, R) && isFloatingPoint!R ) { immutable fa = f(a); if(fa == 0) return a; immutable fb = f(b); if(fb == 0) return b; immutable r = findRoot(f, a, b, fa, fb, tolerance); // Return the first value if it is smaller or NaN return !(fabs(r[2]) > fabs(r[3])) ? r[0] : r[1]; } ///ditto T findRoot(T, DF)(scope DF f, in T a, in T b) { return findRoot(f, a, b, (T a, T b) => false); } /** Find root of a real function f(x) by bracketing, allowing the * termination condition to be specified. * * Params: * * f = Function to be analyzed * * ax = Left bound of initial range of $(D f) known to contain the * root. * * bx = Right bound of initial range of $(D f) known to contain the * root. * * fax = Value of $(D f(ax)). * * fbx = Value of $(D f(bx)). $(D fax) and $(D fbx) should have opposite signs. * ($(D f(ax)) and $(D f(bx)) are commonly known in advance.) * * * tolerance = Defines an early termination condition. Receives the * current upper and lower bounds on the root. The * delegate must return $(D true) when these bounds are * acceptable. If this function always returns $(D false), * full machine precision will be achieved. * * Returns: * * A tuple consisting of two ranges. The first two elements are the * range (in $(D x)) of the root, while the second pair of elements * are the corresponding function values at those points. If an exact * root was found, both of the first two elements will contain the * root, and the second pair of elements will be 0. */ Tuple!(T, T, R, R) findRoot(T, R, DF, DT)(scope DF f, in T ax, in T bx, in R fax, in R fbx, scope DT tolerance) // = (T a, T b) => false) if( isFloatingPoint!T && is(typeof(tolerance(T.init, T.init)) : bool) && is(typeof(f(T.init)) == R) && isFloatingPoint!R ) in { assert(!ax.isNaN() && !bx.isNaN(), "Limits must not be NaN"); assert(signbit(fax) != signbit(fbx), "Parameters must bracket the root."); } body { // Author: Don Clugston. This code is (heavily) modified from TOMS748 // (www.netlib.org). The changes to improve the worst-cast performance are // entirely original. T a, b, d; // [a..b] is our current bracket. d is the third best guess. R fa, fb, fd; // Values of f at a, b, d. bool done = false; // Has a root been found? // Allow ax and bx to be provided in reverse order if (ax <= bx) { a = ax; fa = fax; b = bx; fb = fbx; } else { a = bx; fa = fbx; b = ax; fb = fax; } // Test the function at point c; update brackets accordingly void bracket(T c) { R fc = f(c); if (fc == 0 || fc.isNaN()) // Exact solution, or NaN { a = c; fa = fc; d = c; fd = fc; done = true; return; } // Determine new enclosing interval if (signbit(fa) != signbit(fc)) { d = b; fd = fb; b = c; fb = fc; } else { d = a; fd = fa; a = c; fa = fc; } } /* Perform a secant interpolation. If the result would lie on a or b, or if a and b differ so wildly in magnitude that the result would be meaningless, perform a bisection instead. */ static T secant_interpolate(T a, T b, R fa, R fb) { if (( ((a - b) == a) && b!=0) || (a!=0 && ((b - a) == b))) { // Catastrophic cancellation if (a == 0) a = copysign(T(0), b); else if (b == 0) b = copysign(T(0), a); else if (signbit(a) != signbit(b)) return 0; T c = ieeeMean(a, b); return c; } // avoid overflow if (b - a > T.max) return b / 2 + a / 2; if (fb - fa > R.max) return a - (b - a) / 2; T c = a - (fa / (fb - fa)) * (b - a); if (c == a || c == b) return (a + b) / 2; return c; } /* Uses 'numsteps' newton steps to approximate the zero in [a..b] of the quadratic polynomial interpolating f(x) at a, b, and d. Returns: The approximate zero in [a..b] of the quadratic polynomial. */ T newtonQuadratic(int numsteps) { // Find the coefficients of the quadratic polynomial. immutable T a0 = fa; immutable T a1 = (fb - fa)/(b - a); immutable T a2 = ((fd - fb)/(d - b) - a1)/(d - a); // Determine the starting point of newton steps. T c = oppositeSigns(a2, fa) ? a : b; // start the safeguarded newton steps. foreach (int i; 0..numsteps) { immutable T pc = a0 + (a1 + a2 * (c - b))*(c - a); immutable T pdc = a1 + a2*((2 * c) - (a + b)); if (pdc == 0) return a - a0 / a1; else c = c - pc / pdc; } return c; } // On the first iteration we take a secant step: if (fa == 0 || fa.isNaN()) { done = true; b = a; fb = fa; } else if (fb == 0 || fb.isNaN()) { done = true; a = b; fa = fb; } else { bracket(secant_interpolate(a, b, fa, fb)); } // Starting with the second iteration, higher-order interpolation can // be used. int itnum = 1; // Iteration number int baditer = 1; // Num bisections to take if an iteration is bad. T c, e; // e is our fourth best guess R fe; whileloop: while (!done && (b != nextUp(a)) && !tolerance(a, b)) { T a0 = a, b0 = b; // record the brackets // Do two higher-order (cubic or parabolic) interpolation steps. foreach (int QQ; 0..2) { // Cubic inverse interpolation requires that // all four function values fa, fb, fd, and fe are distinct; // otherwise use quadratic interpolation. bool distinct = (fa != fb) && (fa != fd) && (fa != fe) && (fb != fd) && (fb != fe) && (fd != fe); // The first time, cubic interpolation is impossible. if (itnum<2) distinct = false; bool ok = distinct; if (distinct) { // Cubic inverse interpolation of f(x) at a, b, d, and e immutable q11 = (d - e) * fd / (fe - fd); immutable q21 = (b - d) * fb / (fd - fb); immutable q31 = (a - b) * fa / (fb - fa); immutable d21 = (b - d) * fd / (fd - fb); immutable d31 = (a - b) * fb / (fb - fa); immutable q22 = (d21 - q11) * fb / (fe - fb); immutable q32 = (d31 - q21) * fa / (fd - fa); immutable d32 = (d31 - q21) * fd / (fd - fa); immutable q33 = (d32 - q22) * fa / (fe - fa); c = a + (q31 + q32 + q33); if (c.isNaN() || (c <= a) || (c >= b)) { // DAC: If the interpolation predicts a or b, it's // probable that it's the actual root. Only allow this if // we're already close to the root. if (c == a && a - b != a) { c = nextUp(a); } else if (c == b && a - b != -b) { c = nextDown(b); } else { ok = false; } } } if (!ok) { // DAC: Alefeld doesn't explain why the number of newton steps // should vary. c = newtonQuadratic(distinct ? 3 : 2); if (c.isNaN() || (c <= a) || (c >= b)) { // Failure, try a secant step: c = secant_interpolate(a, b, fa, fb); } } ++itnum; e = d; fe = fd; bracket(c); if (done || ( b == nextUp(a)) || tolerance(a, b)) break whileloop; if (itnum == 2) continue whileloop; } // Now we take a double-length secant step: T u; R fu; if (fabs(fa) < fabs(fb)) { u = a; fu = fa; } else { u = b; fu = fb; } c = u - 2 * (fu / (fb - fa)) * (b - a); // DAC: If the secant predicts a value equal to an endpoint, it's // probably false. if (c==a || c==b || c.isNaN() || fabs(c - u) > (b - a) / 2) { if ((a-b) == a || (b-a) == b) { if ((a>0 && b<0) || (a<0 && b>0)) c = 0; else { if (a==0) c = ieeeMean(copysign(T(0), b), b); else if (b==0) c = ieeeMean(copysign(T(0), a), a); else c = ieeeMean(a, b); } } else { c = a + (b - a) / 2; } } e = d; fe = fd; bracket(c); if (done || (b == nextUp(a)) || tolerance(a, b)) break; // IMPROVE THE WORST-CASE PERFORMANCE // We must ensure that the bounds reduce by a factor of 2 // in binary space! every iteration. If we haven't achieved this // yet, or if we don't yet know what the exponent is, // perform a binary chop. if ((a==0 || b==0 || (fabs(a) >= T(0.5) * fabs(b) && fabs(b) >= T(0.5) * fabs(a))) && (b - a) < T(0.25) * (b0 - a0)) { baditer = 1; continue; } // DAC: If this happens on consecutive iterations, we probably have a // pathological function. Perform a number of bisections equal to the // total number of consecutive bad iterations. if ((b - a) < T(0.25) * (b0 - a0)) baditer = 1; foreach (int QQ; 0..baditer) { e = d; fe = fd; T w; if ((a>0 && b<0) || (a<0 && b>0)) w = 0; else { T usea = a; T useb = b; if (a == 0) usea = copysign(T(0), b); else if (b == 0) useb = copysign(T(0), a); w = ieeeMean(usea, useb); } bracket(w); } ++baditer; } return Tuple!(T, T, R, R)(a, b, fa, fb); } ///ditto Tuple!(T, T, R, R) findRoot(T, R, DF)(scope DF f, in T ax, in T bx, in R fax, in R fbx) { return findRoot(f, ax, bx, fax, fbx, (T a, T b) => false); } ///ditto T findRoot(T, R)(scope R delegate(T) f, in T a, in T b, scope bool delegate(T lo, T hi) tolerance = (T a, T b) => false) { return findRoot!(T, R delegate(T), bool delegate(T lo, T hi))(f, a, b, tolerance); } nothrow unittest { int numProblems = 0; int numCalls; void testFindRoot(real delegate(real) @nogc @safe nothrow pure f , real x1, real x2) @nogc @safe nothrow pure { //numCalls=0; //++numProblems; assert(!x1.isNaN() && !x2.isNaN()); assert(signbit(x1) != signbit(x2)); auto result = findRoot(f, x1, x2, f(x1), f(x2), (real lo, real hi) { return false; }); auto flo = f(result[0]); auto fhi = f(result[1]); if (flo!=0) { assert(oppositeSigns(flo, fhi)); } } // Test functions real cubicfn(real x) @nogc @safe nothrow pure { //++numCalls; if (x>float.max) x = float.max; if (x<-double.max) x = -double.max; // This has a single real root at -59.286543284815 return 0.386*x*x*x + 23*x*x + 15.7*x + 525.2; } // Test a function with more than one root. real multisine(real x) { ++numCalls; return sin(x); } //testFindRoot( &multisine, 6, 90); //testFindRoot(&cubicfn, -100, 100); //testFindRoot( &cubicfn, -double.max, real.max); /* Tests from the paper: * "On Enclosing Simple Roots of Nonlinear Equations", G. Alefeld, F.A. Potra, * Yixun Shi, Mathematics of Computation 61, pp733-744 (1993). */ // Parameters common to many alefeld tests. int n; real ale_a, ale_b; int powercalls = 0; real power(real x) { ++powercalls; ++numCalls; return pow(x, n) + double.min_normal; } int [] power_nvals = [3, 5, 7, 9, 19, 25]; // Alefeld paper states that pow(x,n) is a very poor case, where bisection // outperforms his method, and gives total numcalls = // 921 for bisection (2.4 calls per bit), 1830 for Alefeld (4.76/bit), // 2624 for brent (6.8/bit) // ... but that is for double, not real80. // This poor performance seems mainly due to catastrophic cancellation, // which is avoided here by the use of ieeeMean(). // I get: 231 (0.48/bit). // IE this is 10X faster in Alefeld's worst case numProblems=0; foreach (k; power_nvals) { n = k; //testFindRoot(&power, -1, 10); } int powerProblems = numProblems; // Tests from Alefeld paper int [9] alefeldSums; real alefeld0(real x) { ++alefeldSums[0]; ++numCalls; real q = sin(x) - x/2; for (int i=1; i<20; ++i) q+=(2*i-5.0)*(2*i-5.0)/((x-i*i)*(x-i*i)*(x-i*i)); return q; } real alefeld1(real x) { ++numCalls; ++alefeldSums[1]; return ale_a*x + exp(ale_b * x); } real alefeld2(real x) { ++numCalls; ++alefeldSums[2]; return pow(x, n) - ale_a; } real alefeld3(real x) { ++numCalls; ++alefeldSums[3]; return (1.0 +pow(1.0L-n, 2))*x - pow(1.0L-n*x, 2); } real alefeld4(real x) { ++numCalls; ++alefeldSums[4]; return x*x - pow(1-x, n); } real alefeld5(real x) { ++numCalls; ++alefeldSums[5]; return (1+pow(1.0L-n, 4))*x - pow(1.0L-n*x, 4); } real alefeld6(real x) { ++numCalls; ++alefeldSums[6]; return exp(-n*x)*(x-1.01L) + pow(x, n); } real alefeld7(real x) { ++numCalls; ++alefeldSums[7]; return (n*x-1)/((n-1)*x); } numProblems=0; //testFindRoot(&alefeld0, PI_2, PI); for (n=1; n<=10; ++n) { //testFindRoot(&alefeld0, n*n+1e-9L, (n+1)*(n+1)-1e-9L); } ale_a = -40; ale_b = -1; //testFindRoot(&alefeld1, -9, 31); ale_a = -100; ale_b = -2; //testFindRoot(&alefeld1, -9, 31); ale_a = -200; ale_b = -3; //testFindRoot(&alefeld1, -9, 31); int [] nvals_3 = [1, 2, 5, 10, 15, 20]; int [] nvals_5 = [1, 2, 4, 5, 8, 15, 20]; int [] nvals_6 = [1, 5, 10, 15, 20]; int [] nvals_7 = [2, 5, 15, 20]; for (int i=4; i<12; i+=2) { n = i; ale_a = 0.2; //testFindRoot(&alefeld2, 0, 5); ale_a=1; //testFindRoot(&alefeld2, 0.95, 4.05); //testFindRoot(&alefeld2, 0, 1.5); } foreach (i; nvals_3) { n=i; //testFindRoot(&alefeld3, 0, 1); } foreach (i; nvals_3) { n=i; //testFindRoot(&alefeld4, 0, 1); } foreach (i; nvals_5) { n=i; //testFindRoot(&alefeld5, 0, 1); } foreach (i; nvals_6) { n=i; //testFindRoot(&alefeld6, 0, 1); } foreach (i; nvals_7) { n=i; //testFindRoot(&alefeld7, 0.01L, 1); } real worstcase(real x) { ++numCalls; return x<0.3*real.max? -0.999e-3 : 1.0; } //testFindRoot(&worstcase, -real.max, real.max); // just check that the double + float cases compile //findRoot((double x){ return 0.0; }, -double.max, double.max); //findRoot((float x){ return 0.0f; }, -float.max, float.max); /* int grandtotal=0; foreach (calls; alefeldSums) { grandtotal+=calls; } grandtotal-=2*numProblems; printf("\nALEFELD TOTAL = %d avg = %f (alefeld avg=19.3 for double)\n", grandtotal, (1.0*grandtotal)/numProblems); powercalls -= 2*powerProblems; printf("POWER TOTAL = %d avg = %f ", powercalls, (1.0*powercalls)/powerProblems); */ //Issue 14231 auto xp = findRoot((float x) => x, 0f, 1f); auto xn = findRoot((float x) => x, -1f, -0f); } //regression control unittest { static assert(__traits(compiles, findRoot((float x)=>cast(real)x, float.init, float.init))); static assert(__traits(compiles, findRoot!real((x)=>cast(double)x, real.init, real.init))); static assert(__traits(compiles, findRoot((real x)=>cast(double)x, real.init, real.init))); } /** Computes $(LUCKY Euclidean distance) between input ranges $(D a) and $(D b). The two ranges must have the same length. The three-parameter version stops computation as soon as the distance is greater than or equal to $(D limit) (this is useful to save computation if a small distance is sought). */ CommonType!(ElementType!(Range1), ElementType!(Range2)) euclideanDistance(Range1, Range2)(Range1 a, Range2 b) if (isInputRange!(Range1) && isInputRange!(Range2)) { enum bool haveLen = hasLength!(Range1) && hasLength!(Range2); static if (haveLen) enforce(a.length == b.length); Unqual!(typeof(return)) result = 0; for (; !a.empty; a.popFront(), b.popFront()) { auto t = a.front - b.front; result += t * t; } static if (!haveLen) enforce(b.empty); return sqrt(result); } /// Ditto CommonType!(ElementType!(Range1), ElementType!(Range2)) euclideanDistance(Range1, Range2, F)(Range1 a, Range2 b, F limit) if (isInputRange!(Range1) && isInputRange!(Range2)) { limit *= limit; enum bool haveLen = hasLength!(Range1) && hasLength!(Range2); static if (haveLen) enforce(a.length == b.length); Unqual!(typeof(return)) result = 0; for (; ; a.popFront(), b.popFront()) { if (a.empty) { static if (!haveLen) enforce(b.empty); break; } auto t = a.front - b.front; result += t * t; if (result >= limit) break; } return sqrt(result); } unittest { import std.meta : AliasSeq; foreach(T; AliasSeq!(double, const double, immutable double)) { T[] a = [ 1.0, 2.0, ]; T[] b = [ 4.0, 6.0, ]; assert(euclideanDistance(a, b) == 5); assert(euclideanDistance(a, b, 5) == 5); assert(euclideanDistance(a, b, 4) == 5); assert(euclideanDistance(a, b, 2) == 3); } } /** Computes the $(LUCKY dot product) of input ranges $(D a) and $(D b). The two ranges must have the same length. If both ranges define length, the check is done once; otherwise, it is done at each iteration. */ CommonType!(ElementType!(Range1), ElementType!(Range2)) dotProduct(Range1, Range2)(Range1 a, Range2 b) if (isInputRange!(Range1) && isInputRange!(Range2) && !(isArray!(Range1) && isArray!(Range2))) { enum bool haveLen = hasLength!(Range1) && hasLength!(Range2); static if (haveLen) enforce(a.length == b.length); Unqual!(typeof(return)) result = 0; for (; !a.empty; a.popFront(), b.popFront()) { result += a.front * b.front; } static if (!haveLen) enforce(b.empty); return result; } /// Ditto CommonType!(F1, F2) dotProduct(F1, F2)(in F1[] avector, in F2[] bvector) { immutable n = avector.length; assert(n == bvector.length); auto avec = avector.ptr, bvec = bvector.ptr; Unqual!(typeof(return)) sum0 = 0, sum1 = 0; const all_endp = avec + n; const smallblock_endp = avec + (n & ~3); const bigblock_endp = avec + (n & ~15); for (; avec != bigblock_endp; avec += 16, bvec += 16) { sum0 += avec[0] * bvec[0]; sum1 += avec[1] * bvec[1]; sum0 += avec[2] * bvec[2]; sum1 += avec[3] * bvec[3]; sum0 += avec[4] * bvec[4]; sum1 += avec[5] * bvec[5]; sum0 += avec[6] * bvec[6]; sum1 += avec[7] * bvec[7]; sum0 += avec[8] * bvec[8]; sum1 += avec[9] * bvec[9]; sum0 += avec[10] * bvec[10]; sum1 += avec[11] * bvec[11]; sum0 += avec[12] * bvec[12]; sum1 += avec[13] * bvec[13]; sum0 += avec[14] * bvec[14]; sum1 += avec[15] * bvec[15]; } for (; avec != smallblock_endp; avec += 4, bvec += 4) { sum0 += avec[0] * bvec[0]; sum1 += avec[1] * bvec[1]; sum0 += avec[2] * bvec[2]; sum1 += avec[3] * bvec[3]; } sum0 += sum1; /* Do trailing portion in naive loop. */ while (avec != all_endp) { sum0 += *avec * *bvec; ++avec; ++bvec; } return sum0; } unittest { import std.meta : AliasSeq; foreach(T; AliasSeq!(double, const double, immutable double)) { T[] a = [ 1.0, 2.0, ]; T[] b = [ 4.0, 6.0, ]; assert(dotProduct(a, b) == 16); assert(dotProduct([1, 3, -5], [4, -2, -1]) == 3); } // Make sure the unrolled loop codepath gets tested. static const x = [1.0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]; static const y = [2.0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; assertCTFEable!({ assert(dotProduct(x, y) == 2280); }); } /** Computes the $(LUCKY cosine similarity) of input ranges $(D a) and $(D b). The two ranges must have the same length. If both ranges define length, the check is done once; otherwise, it is done at each iteration. If either range has all-zero elements, return 0. */ CommonType!(ElementType!(Range1), ElementType!(Range2)) cosineSimilarity(Range1, Range2)(Range1 a, Range2 b) if (isInputRange!(Range1) && isInputRange!(Range2)) { enum bool haveLen = hasLength!(Range1) && hasLength!(Range2); static if (haveLen) enforce(a.length == b.length); Unqual!(typeof(return)) norma = 0, normb = 0, dotprod = 0; for (; !a.empty; a.popFront(), b.popFront()) { immutable t1 = a.front, t2 = b.front; norma += t1 * t1; normb += t2 * t2; dotprod += t1 * t2; } static if (!haveLen) enforce(b.empty); if (norma == 0 || normb == 0) return 0; return dotprod / sqrt(norma * normb); } unittest { import std.meta : AliasSeq; foreach(T; AliasSeq!(double, const double, immutable double)) { T[] a = [ 1.0, 2.0, ]; T[] b = [ 4.0, 3.0, ]; assert(approxEqual( cosineSimilarity(a, b), 10.0 / sqrt(5.0 * 25), 0.01)); } } /** Normalizes values in $(D range) by multiplying each element with a number chosen such that values sum up to $(D sum). If elements in $(D range) sum to zero, assigns $(D sum / range.length) to all. Normalization makes sense only if all elements in $(D range) are positive. $(D normalize) assumes that is the case without checking it. Returns: $(D true) if normalization completed normally, $(D false) if all elements in $(D range) were zero or if $(D range) is empty. */ bool normalize(R)(R range, ElementType!(R) sum = 1) if (isForwardRange!(R)) { ElementType!(R) s = 0; // Step 1: Compute sum and length of the range static if (hasLength!(R)) { const length = range.length; foreach (e; range) { s += e; } } else { uint length = 0; foreach (e; range) { s += e; ++length; } } // Step 2: perform normalization if (s == 0) { if (length) { auto f = sum / range.length; foreach (ref e; range) e = f; } return false; } // The path most traveled assert(s >= 0); auto f = sum / s; foreach (ref e; range) e *= f; return true; } /// unittest { double[] a = []; assert(!normalize(a)); a = [ 1.0, 3.0 ]; assert(normalize(a)); assert(a == [ 0.25, 0.75 ]); a = [ 0.0, 0.0 ]; assert(!normalize(a)); assert(a == [ 0.5, 0.5 ]); } /** Compute the sum of binary logarithms of the input range $(D r). The error of this method is much smaller than with a naive sum of log2. */ ElementType!Range sumOfLog2s(Range)(Range r) if (isInputRange!Range && isFloatingPoint!(ElementType!Range)) { long exp = 0; Unqual!(typeof(return)) x = 1; foreach (e; r) { if (e < 0) return typeof(return).nan; int lexp = void; x *= frexp(e, lexp); exp += lexp; if (x < 0.5) { x *= 2; exp--; } } return exp + log2(x); } /// unittest { assert(sumOfLog2s(new double[0]) == 0); assert(sumOfLog2s([0.0L]) == -real.infinity); assert(sumOfLog2s([-0.0L]) == -real.infinity); assert(sumOfLog2s([2.0L]) == 1); assert(sumOfLog2s([-2.0L]).isNaN()); assert(sumOfLog2s([real.nan]).isNaN()); assert(sumOfLog2s([-real.nan]).isNaN()); assert(sumOfLog2s([real.infinity]) == real.infinity); assert(sumOfLog2s([-real.infinity]).isNaN()); assert(sumOfLog2s([ 0.25, 0.25, 0.25, 0.125 ]) == -9); } /** Computes $(LUCKY _entropy) of input range $(D r) in bits. This function assumes (without checking) that the values in $(D r) are all in $(D [0, 1]). For the entropy to be meaningful, often $(D r) should be normalized too (i.e., its values should sum to 1). The two-parameter version stops evaluating as soon as the intermediate result is greater than or equal to $(D max). */ ElementType!Range entropy(Range)(Range r) if (isInputRange!Range) { Unqual!(typeof(return)) result = 0.0; foreach (e; r) { if (!e) continue; result -= e * log2(e); } return result; } /// Ditto ElementType!Range entropy(Range, F)(Range r, F max) if (isInputRange!Range && !is(CommonType!(ElementType!Range, F) == void)) { Unqual!(typeof(return)) result = 0.0; foreach (e; r) { if (!e) continue; result -= e * log2(e); if (result >= max) break; } return result; } unittest { import std.meta : AliasSeq; foreach(T; AliasSeq!(double, const double, immutable double)) { T[] p = [ 0.0, 0, 0, 1 ]; assert(entropy(p) == 0); p = [ 0.25, 0.25, 0.25, 0.25 ]; assert(entropy(p) == 2); assert(entropy(p, 1) == 1); } } /** Computes the $(LUCKY Kullback-Leibler divergence) between input ranges $(D a) and $(D b), which is the sum $(D ai * log(ai / bi)). The base of logarithm is 2. The ranges are assumed to contain elements in $(D [0, 1]). Usually the ranges are normalized probability distributions, but this is not required or checked by $(D kullbackLeiblerDivergence). If any element $(D bi) is zero and the corresponding element $(D ai) nonzero, returns infinity. (Otherwise, if $(D ai == 0 && bi == 0), the term $(D ai * log(ai / bi)) is considered zero.) If the inputs are normalized, the result is positive. */ CommonType!(ElementType!Range1, ElementType!Range2) kullbackLeiblerDivergence(Range1, Range2)(Range1 a, Range2 b) if (isInputRange!(Range1) && isInputRange!(Range2)) { enum bool haveLen = hasLength!(Range1) && hasLength!(Range2); static if (haveLen) enforce(a.length == b.length); Unqual!(typeof(return)) result = 0; for (; !a.empty; a.popFront(), b.popFront()) { immutable t1 = a.front; if (t1 == 0) continue; immutable t2 = b.front; if (t2 == 0) return result.infinity; assert(t1 > 0 && t2 > 0); result += t1 * log2(t1 / t2); } static if (!haveLen) enforce(b.empty); return result; } /// unittest { double[] p = [ 0.0, 0, 0, 1 ]; assert(kullbackLeiblerDivergence(p, p) == 0); double[] p1 = [ 0.25, 0.25, 0.25, 0.25 ]; assert(kullbackLeiblerDivergence(p1, p1) == 0); assert(kullbackLeiblerDivergence(p, p1) == 2); assert(kullbackLeiblerDivergence(p1, p) == double.infinity); double[] p2 = [ 0.2, 0.2, 0.2, 0.4 ]; assert(approxEqual(kullbackLeiblerDivergence(p1, p2), 0.0719281)); assert(approxEqual(kullbackLeiblerDivergence(p2, p1), 0.0780719)); } /** Computes the $(LUCKY Jensen-Shannon divergence) between $(D a) and $(D b), which is the sum $(D (ai * log(2 * ai / (ai + bi)) + bi * log(2 * bi / (ai + bi))) / 2). The base of logarithm is 2. The ranges are assumed to contain elements in $(D [0, 1]). Usually the ranges are normalized probability distributions, but this is not required or checked by $(D jensenShannonDivergence). If the inputs are normalized, the result is bounded within $(D [0, 1]). The three-parameter version stops evaluations as soon as the intermediate result is greater than or equal to $(D limit). */ CommonType!(ElementType!Range1, ElementType!Range2) jensenShannonDivergence(Range1, Range2)(Range1 a, Range2 b) if (isInputRange!Range1 && isInputRange!Range2 && is(CommonType!(ElementType!Range1, ElementType!Range2))) { enum bool haveLen = hasLength!(Range1) && hasLength!(Range2); static if (haveLen) enforce(a.length == b.length); Unqual!(typeof(return)) result = 0; for (; !a.empty; a.popFront(), b.popFront()) { immutable t1 = a.front; immutable t2 = b.front; immutable avg = (t1 + t2) / 2; if (t1 != 0) { result += t1 * log2(t1 / avg); } if (t2 != 0) { result += t2 * log2(t2 / avg); } } static if (!haveLen) enforce(b.empty); return result / 2; } /// Ditto CommonType!(ElementType!Range1, ElementType!Range2) jensenShannonDivergence(Range1, Range2, F)(Range1 a, Range2 b, F limit) if (isInputRange!Range1 && isInputRange!Range2 && is(typeof(CommonType!(ElementType!Range1, ElementType!Range2).init >= F.init) : bool)) { enum bool haveLen = hasLength!(Range1) && hasLength!(Range2); static if (haveLen) enforce(a.length == b.length); Unqual!(typeof(return)) result = 0; limit *= 2; for (; !a.empty; a.popFront(), b.popFront()) { immutable t1 = a.front; immutable t2 = b.front; immutable avg = (t1 + t2) / 2; if (t1 != 0) { result += t1 * log2(t1 / avg); } if (t2 != 0) { result += t2 * log2(t2 / avg); } if (result >= limit) break; } static if (!haveLen) enforce(b.empty); return result / 2; } /// unittest { double[] p = [ 0.0, 0, 0, 1 ]; assert(jensenShannonDivergence(p, p) == 0); double[] p1 = [ 0.25, 0.25, 0.25, 0.25 ]; assert(jensenShannonDivergence(p1, p1) == 0); assert(approxEqual(jensenShannonDivergence(p1, p), 0.548795)); double[] p2 = [ 0.2, 0.2, 0.2, 0.4 ]; assert(approxEqual(jensenShannonDivergence(p1, p2), 0.0186218)); assert(approxEqual(jensenShannonDivergence(p2, p1), 0.0186218)); assert(approxEqual(jensenShannonDivergence(p2, p1, 0.005), 0.00602366)); } /** The so-called "all-lengths gap-weighted string kernel" computes a similarity measure between $(D s) and $(D t) based on all of their common subsequences of all lengths. Gapped subsequences are also included. To understand what $(D gapWeightedSimilarity(s, t, lambda)) computes, consider first the case $(D lambda = 1) and the strings $(D s = ["Hello", "brave", "new", "world"]) and $(D t = ["Hello", "new", "world"]). In that case, $(D gapWeightedSimilarity) counts the following matches: $(OL $(LI three matches of length 1, namely $(D "Hello"), $(D "new"), and $(D "world");) $(LI three matches of length 2, namely ($(D "Hello", "new")), ($(D "Hello", "world")), and ($(D "new", "world"));) $(LI one match of length 3, namely ($(D "Hello", "new", "world")).)) The call $(D gapWeightedSimilarity(s, t, 1)) simply counts all of these matches and adds them up, returning 7. ---- string[] s = ["Hello", "brave", "new", "world"]; string[] t = ["Hello", "new", "world"]; assert(gapWeightedSimilarity(s, t, 1) == 7); ---- Note how the gaps in matching are simply ignored, for example ($(D "Hello", "new")) is deemed as good a match as ($(D "new", "world")). This may be too permissive for some applications. To eliminate gapped matches entirely, use $(D lambda = 0): ---- string[] s = ["Hello", "brave", "new", "world"]; string[] t = ["Hello", "new", "world"]; assert(gapWeightedSimilarity(s, t, 0) == 4); ---- The call above eliminated the gapped matches ($(D "Hello", "new")), ($(D "Hello", "world")), and ($(D "Hello", "new", "world")) from the tally. That leaves only 4 matches. The most interesting case is when gapped matches still participate in the result, but not as strongly as ungapped matches. The result will be a smooth, fine-grained similarity measure between the input strings. This is where values of $(D lambda) between 0 and 1 enter into play: gapped matches are $(I exponentially penalized with the number of gaps) with base $(D lambda). This means that an ungapped match adds 1 to the return value; a match with one gap in either string adds $(D lambda) to the return value; ...; a match with a total of $(D n) gaps in both strings adds $(D pow(lambda, n)) to the return value. In the example above, we have 4 matches without gaps, 2 matches with one gap, and 1 match with three gaps. The latter match is ($(D "Hello", "world")), which has two gaps in the first string and one gap in the second string, totaling to three gaps. Summing these up we get $(D 4 + 2 * lambda + pow(lambda, 3)). ---- string[] s = ["Hello", "brave", "new", "world"]; string[] t = ["Hello", "new", "world"]; assert(gapWeightedSimilarity(s, t, 0.5) == 4 + 0.5 * 2 + 0.125); ---- $(D gapWeightedSimilarity) is useful wherever a smooth similarity measure between sequences allowing for approximate matches is needed. The examples above are given with words, but any sequences with elements comparable for equality are allowed, e.g. characters or numbers. $(D gapWeightedSimilarity) uses a highly optimized dynamic programming implementation that needs $(D 16 * min(s.length, t.length)) extra bytes of memory and $(BIGOH s.length * t.length) time to complete. */ F gapWeightedSimilarity(alias comp = "a == b", R1, R2, F)(R1 s, R2 t, F lambda) if (isRandomAccessRange!(R1) && hasLength!(R1) && isRandomAccessRange!(R2) && hasLength!(R2)) { import std.functional : binaryFun; import std.algorithm : swap; import core.stdc.stdlib; if (s.length < t.length) return gapWeightedSimilarity(t, s, lambda); if (!t.length) return 0; immutable tl1 = t.length + 1; auto dpvi = enforce(cast(F*) malloc(F.sizeof * 2 * t.length)); auto dpvi1 = dpvi + t.length; scope(exit) free(dpvi < dpvi1 ? dpvi : dpvi1); dpvi[0 .. t.length] = 0; dpvi1[0] = 0; immutable lambda2 = lambda * lambda; F result = 0; foreach (i; 0 .. s.length) { const si = s[i]; for (size_t j = 0;;) { F dpsij = void; if (binaryFun!(comp)(si, t[j])) { dpsij = 1 + dpvi[j]; result += dpsij; } else { dpsij = 0; } immutable j1 = j + 1; if (j1 == t.length) break; dpvi1[j1] = dpsij + lambda * (dpvi1[j] + dpvi[j1]) - lambda2 * dpvi[j]; j = j1; } swap(dpvi, dpvi1); } return result; } unittest { string[] s = ["Hello", "brave", "new", "world"]; string[] t = ["Hello", "new", "world"]; assert(gapWeightedSimilarity(s, t, 1) == 7); assert(gapWeightedSimilarity(s, t, 0) == 4); assert(gapWeightedSimilarity(s, t, 0.5) == 4 + 2 * 0.5 + 0.125); } /** The similarity per $(D gapWeightedSimilarity) has an issue in that it grows with the lengths of the two strings, even though the strings are not actually very similar. For example, the range $(D ["Hello", "world"]) is increasingly similar with the range $(D ["Hello", "world", "world", "world",...]) as more instances of $(D "world") are appended. To prevent that, $(D gapWeightedSimilarityNormalized) computes a normalized version of the similarity that is computed as $(D gapWeightedSimilarity(s, t, lambda) / sqrt(gapWeightedSimilarity(s, t, lambda) * gapWeightedSimilarity(s, t, lambda))). The function $(D gapWeightedSimilarityNormalized) (a so-called normalized kernel) is bounded in $(D [0, 1]), reaches $(D 0) only for ranges that don't match in any position, and $(D 1) only for identical ranges. The optional parameters $(D sSelfSim) and $(D tSelfSim) are meant for avoiding duplicate computation. Many applications may have already computed $(D gapWeightedSimilarity(s, s, lambda)) and/or $(D gapWeightedSimilarity(t, t, lambda)). In that case, they can be passed as $(D sSelfSim) and $(D tSelfSim), respectively. */ Select!(isFloatingPoint!(F), F, double) gapWeightedSimilarityNormalized(alias comp = "a == b", R1, R2, F) (R1 s, R2 t, F lambda, F sSelfSim = F.init, F tSelfSim = F.init) if (isRandomAccessRange!(R1) && hasLength!(R1) && isRandomAccessRange!(R2) && hasLength!(R2)) { static bool uncomputed(F n) { static if (isFloatingPoint!(F)) return isNaN(n); else return n == n.init; } if (uncomputed(sSelfSim)) sSelfSim = gapWeightedSimilarity!(comp)(s, s, lambda); if (sSelfSim == 0) return 0; if (uncomputed(tSelfSim)) tSelfSim = gapWeightedSimilarity!(comp)(t, t, lambda); if (tSelfSim == 0) return 0; return gapWeightedSimilarity!(comp)(s, t, lambda) / sqrt(cast(typeof(return)) sSelfSim * tSelfSim); } /// unittest { string[] s = ["Hello", "brave", "new", "world"]; string[] t = ["Hello", "new", "world"]; assert(gapWeightedSimilarity(s, s, 1) == 15); assert(gapWeightedSimilarity(t, t, 1) == 7); assert(gapWeightedSimilarity(s, t, 1) == 7); assert(approxEqual(gapWeightedSimilarityNormalized(s, t, 1), 7.0 / sqrt(15.0 * 7), 0.01)); } /** Similar to $(D gapWeightedSimilarity), just works in an incremental manner by first revealing the matches of length 1, then gapped matches of length 2, and so on. The memory requirement is $(BIGOH s.length * t.length). The time complexity is $(BIGOH s.length * t.length) time for computing each step. Continuing on the previous example: The implementation is based on the pseudocode in Fig. 4 of the paper $(WEB jmlr.csail.mit.edu/papers/volume6/rousu05a/rousu05a.pdf, "Efficient Computation of Gapped Substring Kernels on Large Alphabets") by Rousu et al., with additional algorithmic and systems-level optimizations. */ struct GapWeightedSimilarityIncremental(Range, F = double) if (isRandomAccessRange!(Range) && hasLength!(Range)) { import core.stdc.stdlib; private: Range s, t; F currentValue = 0; F* kl; size_t gram = void; F lambda = void, lambda2 = void; public: /** Constructs an object given two ranges $(D s) and $(D t) and a penalty $(D lambda). Constructor completes in $(BIGOH s.length * t.length) time and computes all matches of length 1. */ this(Range s, Range t, F lambda) { enforce(lambda > 0); this.gram = 0; this.lambda = lambda; this.lambda2 = lambda * lambda; // for efficiency only size_t iMin = size_t.max, jMin = size_t.max, iMax = 0, jMax = 0; /* initialize */ Tuple!(size_t, size_t) * k0; size_t k0len; scope(exit) free(k0); currentValue = 0; foreach (i, si; s) { foreach (j; 0 .. t.length) { if (si != t[j]) continue; k0 = cast(typeof(k0)) realloc(k0, ++k0len * (*k0).sizeof); with (k0[k0len - 1]) { field[0] = i; field[1] = j; } // Maintain the minimum and maximum i and j if (iMin > i) iMin = i; if (iMax < i) iMax = i; if (jMin > j) jMin = j; if (jMax < j) jMax = j; } } if (iMin > iMax) return; assert(k0len); currentValue = k0len; // Chop strings down to the useful sizes s = s[iMin .. iMax + 1]; t = t[jMin .. jMax + 1]; this.s = s; this.t = t; // Si = errnoEnforce(cast(F *) malloc(t.length * F.sizeof)); kl = errnoEnforce(cast(F *) malloc(s.length * t.length * F.sizeof)); kl[0 .. s.length * t.length] = 0; foreach (pos; 0 .. k0len) { with (k0[pos]) { kl[(field[0] - iMin) * t.length + field[1] -jMin] = lambda2; } } } /** Returns: $(D this). */ ref GapWeightedSimilarityIncremental opSlice() { return this; } /** Computes the match of the popFront length. Completes in $(BIGOH s.length * t.length) time. */ void popFront() { import std.algorithm : swap; // This is a large source of optimization: if similarity at // the gram-1 level was 0, then we can safely assume // similarity at the gram level is 0 as well. if (empty) return; // Now attempt to match gapped substrings of length `gram' ++gram; currentValue = 0; auto Si = cast(F*) alloca(t.length * F.sizeof); Si[0 .. t.length] = 0; foreach (i; 0 .. s.length) { const si = s[i]; F Sij_1 = 0; F Si_1j_1 = 0; auto kli = kl + i * t.length; for (size_t j = 0;;) { const klij = kli[j]; const Si_1j = Si[j]; const tmp = klij + lambda * (Si_1j + Sij_1) - lambda2 * Si_1j_1; // now update kl and currentValue if (si == t[j]) currentValue += kli[j] = lambda2 * Si_1j_1; else kli[j] = 0; // commit to Si Si[j] = tmp; if (++j == t.length) break; // get ready for the popFront step; virtually increment j, // so essentially stuffj_1 <-- stuffj Si_1j_1 = Si_1j; Sij_1 = tmp; } } currentValue /= pow(lambda, 2 * (gram + 1)); version (none) { Si_1[0 .. t.length] = 0; kl[0 .. min(t.length, maxPerimeter + 1)] = 0; foreach (i; 1 .. min(s.length, maxPerimeter + 1)) { auto kli = kl + i * t.length; assert(s.length > i); const si = s[i]; auto kl_1i_1 = kl_1 + (i - 1) * t.length; kli[0] = 0; F lastS = 0; foreach (j; 1 .. min(maxPerimeter - i + 1, t.length)) { immutable j_1 = j - 1; immutable tmp = kl_1i_1[j_1] + lambda * (Si_1[j] + lastS) - lambda2 * Si_1[j_1]; kl_1i_1[j_1] = float.nan; Si_1[j_1] = lastS; lastS = tmp; if (si == t[j]) { currentValue += kli[j] = lambda2 * lastS; } else { kli[j] = 0; } } Si_1[t.length - 1] = lastS; } currentValue /= pow(lambda, 2 * (gram + 1)); // get ready for the popFront computation swap(kl, kl_1); } } /** Returns: The gapped similarity at the current match length (initially 1, grows with each call to $(D popFront)). */ @property F front() { return currentValue; } /** Returns: Whether there are more matches. */ @property bool empty() { if (currentValue) return false; if (kl) { free(kl); kl = null; } return true; } } /** Ditto */ GapWeightedSimilarityIncremental!(R, F) gapWeightedSimilarityIncremental(R, F) (R r1, R r2, F penalty) { return typeof(return)(r1, r2, penalty); } /// unittest { string[] s = ["Hello", "brave", "new", "world"]; string[] t = ["Hello", "new", "world"]; auto simIter = gapWeightedSimilarityIncremental(s, t, 1.0); assert(simIter.front == 3); // three 1-length matches simIter.popFront(); assert(simIter.front == 3); // three 2-length matches simIter.popFront(); assert(simIter.front == 1); // one 3-length match simIter.popFront(); assert(simIter.empty); // no more match } unittest { import std.conv: text; string[] s = ["Hello", "brave", "new", "world"]; string[] t = ["Hello", "new", "world"]; auto simIter = gapWeightedSimilarityIncremental(s, t, 1.0); //foreach (e; simIter) writeln(e); assert(simIter.front == 3); // three 1-length matches simIter.popFront(); assert(simIter.front == 3, text(simIter.front)); // three 2-length matches simIter.popFront(); assert(simIter.front == 1); // one 3-length matches simIter.popFront(); assert(simIter.empty); // no more match s = ["Hello"]; t = ["bye"]; simIter = gapWeightedSimilarityIncremental(s, t, 0.5); assert(simIter.empty); s = ["Hello"]; t = ["Hello"]; simIter = gapWeightedSimilarityIncremental(s, t, 0.5); assert(simIter.front == 1); // one match simIter.popFront(); assert(simIter.empty); s = ["Hello", "world"]; t = ["Hello"]; simIter = gapWeightedSimilarityIncremental(s, t, 0.5); assert(simIter.front == 1); // one match simIter.popFront(); assert(simIter.empty); s = ["Hello", "world"]; t = ["Hello", "yah", "world"]; simIter = gapWeightedSimilarityIncremental(s, t, 0.5); assert(simIter.front == 2); // two 1-gram matches simIter.popFront(); assert(simIter.front == 0.5, text(simIter.front)); // one 2-gram match, 1 gap } unittest { GapWeightedSimilarityIncremental!(string[]) sim = GapWeightedSimilarityIncremental!(string[])( ["nyuk", "I", "have", "no", "chocolate", "giba"], ["wyda", "I", "have", "I", "have", "have", "I", "have", "hehe"], 0.5); double[] witness = [ 7.0, 4.03125, 0, 0 ]; foreach (e; sim) { //writeln(e); assert(e == witness.front); witness.popFront(); } witness = [ 3.0, 1.3125, 0.25 ]; sim = GapWeightedSimilarityIncremental!(string[])( ["I", "have", "no", "chocolate"], ["I", "have", "some", "chocolate"], 0.5); foreach (e; sim) { //writeln(e); assert(e == witness.front); witness.popFront(); } assert(witness.empty); } /** Computes the greatest common divisor of $(D a) and $(D b) by using Euclid's algorithm. */ T gcd(T)(T a, T b) { static if (is(T == const) || is(T == immutable)) { return gcd!(Unqual!T)(a, b); } else { static if (T.min < 0) { enforce(a >= 0 && b >=0); } while (b) { auto t = b; b = a % b; a = t; } return a; } } /// unittest { assert(gcd(2 * 5 * 7 * 7, 5 * 7 * 11) == 5 * 7); const int a = 5 * 13 * 23 * 23, b = 13 * 59; assert(gcd(a, b) == 13); } // This is to make tweaking the speed/size vs. accuracy tradeoff easy, // though floats seem accurate enough for all practical purposes, since // they pass the "approxEqual(inverseFft(fft(arr)), arr)" test even for // size 2 ^^ 22. private alias lookup_t = float; /**A class for performing fast Fourier transforms of power of two sizes. * This class encapsulates a large amount of state that is reusable when * performing multiple FFTs of sizes smaller than or equal to that specified * in the constructor. This results in substantial speedups when performing * multiple FFTs with a known maximum size. However, * a free function API is provided for convenience if you need to perform a * one-off FFT. * * References: * $(WEB en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm) */ final class Fft { import std.algorithm : map; import core.bitop : bsf; import std.array : uninitializedArray; private: immutable lookup_t[][] negSinLookup; void enforceSize(R)(R range) const { import std.conv: text; enforce(range.length <= size, text( "FFT size mismatch. Expected ", size, ", got ", range.length)); } void fftImpl(Ret, R)(Stride!R range, Ret buf) const in { assert(range.length >= 4); assert(isPowerOfTwo(range.length)); } body { auto recurseRange = range; recurseRange.doubleSteps(); if(buf.length > 4) { fftImpl(recurseRange, buf[0..$ / 2]); recurseRange.popHalf(); fftImpl(recurseRange, buf[$ / 2..$]); } else { // Do this here instead of in another recursion to save on // recursion overhead. slowFourier2(recurseRange, buf[0..$ / 2]); recurseRange.popHalf(); slowFourier2(recurseRange, buf[$ / 2..$]); } butterfly(buf); } // This algorithm works by performing the even and odd parts of our FFT // using the "two for the price of one" method mentioned at // http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM#Head521 // by making the odd terms into the imaginary components of our new FFT, // and then using symmetry to recombine them. void fftImplPureReal(Ret, R)(R range, Ret buf) const in { assert(range.length >= 4); assert(isPowerOfTwo(range.length)); } body { alias E = ElementType!R; // Converts odd indices of range to the imaginary components of // a range half the size. The even indices become the real components. static if(isArray!R && isFloatingPoint!E) { // Then the memory layout of complex numbers provides a dirt // cheap way to convert. This is a common case, so take advantage. auto oddsImag = cast(Complex!E[]) range; } else { // General case: Use a higher order range. We can assume // source.length is even because it has to be a power of 2. static struct OddToImaginary { R source; alias C = Complex!(CommonType!(E, typeof(buf[0].re))); @property { C front() { return C(source[0], source[1]); } C back() { immutable n = source.length; return C(source[n - 2], source[n - 1]); } typeof(this) save() { return typeof(this)(source.save); } bool empty() { return source.empty; } size_t length() { return source.length / 2; } } void popFront() { source.popFront(); source.popFront(); } void popBack() { source.popBack(); source.popBack(); } C opIndex(size_t index) { return C(source[index * 2], source[index * 2 + 1]); } typeof(this) opSlice(size_t lower, size_t upper) { return typeof(this)(source[lower * 2..upper * 2]); } } auto oddsImag = OddToImaginary(range); } fft(oddsImag, buf[0..$ / 2]); auto evenFft = buf[0..$ / 2]; auto oddFft = buf[$ / 2..$]; immutable halfN = evenFft.length; oddFft[0].re = buf[0].im; oddFft[0].im = 0; evenFft[0].im = 0; // evenFft[0].re is already right b/c it's aliased with buf[0].re. foreach (k; 1..halfN / 2 + 1) { immutable bufk = buf[k]; immutable bufnk = buf[buf.length / 2 - k]; evenFft[k].re = 0.5 * (bufk.re + bufnk.re); evenFft[halfN - k].re = evenFft[k].re; evenFft[k].im = 0.5 * (bufk.im - bufnk.im); evenFft[halfN - k].im = -evenFft[k].im; oddFft[k].re = 0.5 * (bufk.im + bufnk.im); oddFft[halfN - k].re = oddFft[k].re; oddFft[k].im = 0.5 * (bufnk.re - bufk.re); oddFft[halfN - k].im = -oddFft[k].im; } butterfly(buf); } void butterfly(R)(R buf) const in { assert(isPowerOfTwo(buf.length)); } body { immutable n = buf.length; immutable localLookup = negSinLookup[bsf(n)]; assert(localLookup.length == n); immutable cosMask = n - 1; immutable cosAdd = n / 4 * 3; lookup_t negSinFromLookup(size_t index) pure nothrow { return localLookup[index]; } lookup_t cosFromLookup(size_t index) pure nothrow { // cos is just -sin shifted by PI * 3 / 2. return localLookup[(index + cosAdd) & cosMask]; } immutable halfLen = n / 2; // This loop is unrolled and the two iterations are interleaved // relative to the textbook FFT to increase ILP. This gives roughly 5% // speedups on DMD. for (size_t k = 0; k < halfLen; k += 2) { immutable cosTwiddle1 = cosFromLookup(k); immutable sinTwiddle1 = negSinFromLookup(k); immutable cosTwiddle2 = cosFromLookup(k + 1); immutable sinTwiddle2 = negSinFromLookup(k + 1); immutable realLower1 = buf[k].re; immutable imagLower1 = buf[k].im; immutable realLower2 = buf[k + 1].re; immutable imagLower2 = buf[k + 1].im; immutable upperIndex1 = k + halfLen; immutable upperIndex2 = upperIndex1 + 1; immutable realUpper1 = buf[upperIndex1].re; immutable imagUpper1 = buf[upperIndex1].im; immutable realUpper2 = buf[upperIndex2].re; immutable imagUpper2 = buf[upperIndex2].im; immutable realAdd1 = cosTwiddle1 * realUpper1 - sinTwiddle1 * imagUpper1; immutable imagAdd1 = sinTwiddle1 * realUpper1 + cosTwiddle1 * imagUpper1; immutable realAdd2 = cosTwiddle2 * realUpper2 - sinTwiddle2 * imagUpper2; immutable imagAdd2 = sinTwiddle2 * realUpper2 + cosTwiddle2 * imagUpper2; buf[k].re += realAdd1; buf[k].im += imagAdd1; buf[k + 1].re += realAdd2; buf[k + 1].im += imagAdd2; buf[upperIndex1].re = realLower1 - realAdd1; buf[upperIndex1].im = imagLower1 - imagAdd1; buf[upperIndex2].re = realLower2 - realAdd2; buf[upperIndex2].im = imagLower2 - imagAdd2; } } // This constructor is used within this module for allocating the // buffer space elsewhere besides the GC heap. It's definitely **NOT** // part of the public API and definitely **IS** subject to change. // // Also, this is unsafe because the memSpace buffer will be cast // to immutable. public this(lookup_t[] memSpace) // Public b/c of bug 4636. { immutable size = memSpace.length / 2; /* Create a lookup table of all negative sine values at a resolution of * size and all smaller power of two resolutions. This may seem * inefficient, but having all the lookups be next to each other in * memory at every level of iteration is a huge win performance-wise. */ if(size == 0) { return; } enforce(isPowerOfTwo(size), "Can only do FFTs on ranges with a size that is a power of two."); auto table = new lookup_t[][bsf(size) + 1]; table[$ - 1] = memSpace[$ - size..$]; memSpace = memSpace[0..size]; auto lastRow = table[$ - 1]; lastRow[0] = 0; // -sin(0) == 0. foreach (ptrdiff_t i; 1..size) { // The hard coded cases are for improved accuracy and to prevent // annoying non-zeroness when stuff should be zero. if (i == size / 4) lastRow[i] = -1; // -sin(pi / 2) == -1. else if (i == size / 2) lastRow[i] = 0; // -sin(pi) == 0. else if (i == size * 3 / 4) lastRow[i] = 1; // -sin(pi * 3 / 2) == 1 else lastRow[i] = -sin(i * 2.0L * PI / size); } // Fill in all the other rows with strided versions. foreach (i; 1..table.length - 1) { immutable strideLength = size / (2 ^^ i); auto strided = Stride!(lookup_t[])(lastRow, strideLength); table[i] = memSpace[$ - strided.length..$]; memSpace = memSpace[0..$ - strided.length]; size_t copyIndex; foreach (elem; strided) { table[i][copyIndex++] = elem; } } negSinLookup = cast(immutable) table; } public: /**Create an $(D Fft) object for computing fast Fourier transforms of * power of two sizes of $(D size) or smaller. $(D size) must be a * power of two. */ this(size_t size) { // Allocate all twiddle factor buffers in one contiguous block so that, // when one is done being used, the next one is next in cache. auto memSpace = uninitializedArray!(lookup_t[])(2 * size); this(memSpace); } @property size_t size() const { return (negSinLookup is null) ? 0 : negSinLookup[$ - 1].length; } /**Compute the Fourier transform of range using the $(BIGOH N log N) * Cooley-Tukey Algorithm. $(D range) must be a random-access range with * slicing and a length equal to $(D size) as provided at the construction of * this object. The contents of range can be either numeric types, * which will be interpreted as pure real values, or complex types with * properties or members $(D .re) and $(D .im) that can be read. * * Note: Pure real FFTs are automatically detected and the relevant * optimizations are performed. * * Returns: An array of complex numbers representing the transformed data in * the frequency domain. * * Conventions: The exponent is negative and the factor is one, * i.e., output[j] := sum[ exp(-2 PI i j k / N) input[k] ]. */ Complex!F[] fft(F = double, R)(R range) const if (isFloatingPoint!F && isRandomAccessRange!R) { enforceSize(range); Complex!F[] ret; if (range.length == 0) { return ret; } // Don't waste time initializing the memory for ret. ret = uninitializedArray!(Complex!F[])(range.length); fft(range, ret); return ret; } /**Same as the overload, but allows for the results to be stored in a user- * provided buffer. The buffer must be of the same length as range, must be * a random-access range, must have slicing, and must contain elements that are * complex-like. This means that they must have a .re and a .im member or * property that can be both read and written and are floating point numbers. */ void fft(Ret, R)(R range, Ret buf) const if(isRandomAccessRange!Ret && isComplexLike!(ElementType!Ret) && hasSlicing!Ret) { enforce(buf.length == range.length); enforceSize(range); if (range.length == 0) { return; } else if (range.length == 1) { buf[0] = range[0]; return; } else if (range.length == 2) { slowFourier2(range, buf); return; } else { alias E = ElementType!R; static if (is(E : real)) { return fftImplPureReal(range, buf); } else { static if (is(R : Stride!R)) return fftImpl(range, buf); else return fftImpl(Stride!R(range, 1), buf); } } } /** * Computes the inverse Fourier transform of a range. The range must be a * random access range with slicing, have a length equal to the size * provided at construction of this object, and contain elements that are * either of type std.complex.Complex or have essentially * the same compile-time interface. * * Returns: The time-domain signal. * * Conventions: The exponent is positive and the factor is 1/N, i.e., * output[j] := (1 / N) sum[ exp(+2 PI i j k / N) input[k] ]. */ Complex!F[] inverseFft(F = double, R)(R range) const if (isRandomAccessRange!R && isComplexLike!(ElementType!R) && isFloatingPoint!F) { enforceSize(range); Complex!F[] ret; if (range.length == 0) { return ret; } // Don't waste time initializing the memory for ret. ret = uninitializedArray!(Complex!F[])(range.length); inverseFft(range, ret); return ret; } /** * Inverse FFT that allows a user-supplied buffer to be provided. The buffer * must be a random access range with slicing, and its elements * must be some complex-like type. */ void inverseFft(Ret, R)(R range, Ret buf) const if (isRandomAccessRange!Ret && isComplexLike!(ElementType!Ret) && hasSlicing!Ret) { enforceSize(range); auto swapped = map!swapRealImag(range); fft(swapped, buf); immutable lenNeg1 = 1.0 / buf.length; foreach (ref elem; buf) { auto temp = elem.re * lenNeg1; elem.re = elem.im * lenNeg1; elem.im = temp; } } } // This mixin creates an Fft object in the scope it's mixed into such that all // memory owned by the object is deterministically destroyed at the end of that // scope. private enum string MakeLocalFft = q{ import core.stdc.stdlib; import core.exception : OutOfMemoryError; auto lookupBuf = (cast(lookup_t*) malloc(range.length * 2 * lookup_t.sizeof)) [0..2 * range.length]; if (!lookupBuf.ptr) { throw new OutOfMemoryError(__FILE__, __LINE__); } scope(exit) free(cast(void*) lookupBuf.ptr); auto fftObj = scoped!Fft(lookupBuf); }; /**Convenience functions that create an $(D Fft) object, run the FFT or inverse * FFT and return the result. Useful for one-off FFTs. * * Note: In addition to convenience, these functions are slightly more * efficient than manually creating an Fft object for a single use, * as the Fft object is deterministically destroyed before these * functions return. */ Complex!F[] fft(F = double, R)(R range) { mixin(MakeLocalFft); return fftObj.fft!(F, R)(range); } /// ditto void fft(Ret, R)(R range, Ret buf) { mixin(MakeLocalFft); return fftObj.fft!(Ret, R)(range, buf); } /// ditto Complex!F[] inverseFft(F = double, R)(R range) { mixin(MakeLocalFft); return fftObj.inverseFft!(F, R)(range); } /// ditto void inverseFft(Ret, R)(R range, Ret buf) { mixin(MakeLocalFft); return fftObj.inverseFft!(Ret, R)(range, buf); } unittest { import std.algorithm; import std.range; import std.conv; // Test values from R and Octave. auto arr = [1,2,3,4,5,6,7,8]; auto fft1 = fft(arr); assert(approxEqual(map!"a.re"(fft1), [36.0, -4, -4, -4, -4, -4, -4, -4])); assert(approxEqual(map!"a.im"(fft1), [0, 9.6568, 4, 1.6568, 0, -1.6568, -4, -9.6568])); auto fft1Retro = fft(retro(arr)); assert(approxEqual(map!"a.re"(fft1Retro), [36.0, 4, 4, 4, 4, 4, 4, 4])); assert(approxEqual(map!"a.im"(fft1Retro), [0, -9.6568, -4, -1.6568, 0, 1.6568, 4, 9.6568])); auto fft1Float = fft(to!(float[])(arr)); assert(approxEqual(map!"a.re"(fft1), map!"a.re"(fft1Float))); assert(approxEqual(map!"a.im"(fft1), map!"a.im"(fft1Float))); alias C = Complex!float; auto arr2 = [C(1,2), C(3,4), C(5,6), C(7,8), C(9,10), C(11,12), C(13,14), C(15,16)]; auto fft2 = fft(arr2); assert(approxEqual(map!"a.re"(fft2), [64.0, -27.3137, -16, -11.3137, -8, -4.6862, 0, 11.3137])); assert(approxEqual(map!"a.im"(fft2), [72, 11.3137, 0, -4.686, -8, -11.3137, -16, -27.3137])); auto inv1 = inverseFft(fft1); assert(approxEqual(map!"a.re"(inv1), arr)); assert(reduce!max(map!"a.im"(inv1)) < 1e-10); auto inv2 = inverseFft(fft2); assert(approxEqual(map!"a.re"(inv2), map!"a.re"(arr2))); assert(approxEqual(map!"a.im"(inv2), map!"a.im"(arr2))); // FFTs of size 0, 1 and 2 are handled as special cases. Test them here. ushort[] empty; assert(fft(empty) == null); assert(inverseFft(fft(empty)) == null); real[] oneElem = [4.5L]; auto oneFft = fft(oneElem); assert(oneFft.length == 1); assert(oneFft[0].re == 4.5L); assert(oneFft[0].im == 0); auto oneInv = inverseFft(oneFft); assert(oneInv.length == 1); assert(approxEqual(oneInv[0].re, 4.5)); assert(approxEqual(oneInv[0].im, 0)); long[2] twoElems = [8, 4]; auto twoFft = fft(twoElems[]); assert(twoFft.length == 2); assert(approxEqual(twoFft[0].re, 12)); assert(approxEqual(twoFft[0].im, 0)); assert(approxEqual(twoFft[1].re, 4)); assert(approxEqual(twoFft[1].im, 0)); auto twoInv = inverseFft(twoFft); assert(approxEqual(twoInv[0].re, 8)); assert(approxEqual(twoInv[0].im, 0)); assert(approxEqual(twoInv[1].re, 4)); assert(approxEqual(twoInv[1].im, 0)); } // Swaps the real and imaginary parts of a complex number. This is useful // for inverse FFTs. C swapRealImag(C)(C input) { return C(input.im, input.re); } private: // The reasons I couldn't use std.algorithm were b/c its stride length isn't // modifiable on the fly and because range has grown some performance hacks // for powers of 2. struct Stride(R) { import core.bitop : bsf; Unqual!R range; size_t _nSteps; size_t _length; alias E = ElementType!(R); this(R range, size_t nStepsIn) { this.range = range; _nSteps = nStepsIn; _length = (range.length + _nSteps - 1) / nSteps; } size_t length() const @property { return _length; } typeof(this) save() @property { auto ret = this; ret.range = ret.range.save; return ret; } E opIndex(size_t index) { return range[index * _nSteps]; } E front() @property { return range[0]; } void popFront() { if (range.length >= _nSteps) { range = range[_nSteps..range.length]; _length--; } else { range = range[0..0]; _length = 0; } } // Pops half the range's stride. void popHalf() { range = range[_nSteps / 2..range.length]; } bool empty() const @property { return length == 0; } size_t nSteps() const @property { return _nSteps; } void doubleSteps() { _nSteps *= 2; _length /= 2; } size_t nSteps(size_t newVal) @property { _nSteps = newVal; // Using >> bsf(nSteps) is a few cycles faster than / nSteps. _length = (range.length + _nSteps - 1) >> bsf(nSteps); return newVal; } } // Hard-coded base case for FFT of size 2. This is actually a TON faster than // using a generic slow DFT. This seems to be the best base case. (Size 1 // can be coded inline as buf[0] = range[0]). void slowFourier2(Ret, R)(R range, Ret buf) { assert(range.length == 2); assert(buf.length == 2); buf[0] = range[0] + range[1]; buf[1] = range[0] - range[1]; } // Hard-coded base case for FFT of size 4. Doesn't work as well as the size // 2 case. void slowFourier4(Ret, R)(R range, Ret buf) { alias C = ElementType!Ret; assert(range.length == 4); assert(buf.length == 4); buf[0] = range[0] + range[1] + range[2] + range[3]; buf[1] = range[0] - range[1] * C(0, 1) - range[2] + range[3] * C(0, 1); buf[2] = range[0] - range[1] + range[2] - range[3]; buf[3] = range[0] + range[1] * C(0, 1) - range[2] - range[3] * C(0, 1); } bool isPowerOfTwo(N)(N num) if (isScalarType!N && !isFloatingPoint!N) { import core.bitop : bsf, bsr; return bsr(num) == bsf(num); } N roundDownToPowerOf2(N)(N num) if (isScalarType!N && !isFloatingPoint!N) { import core.bitop : bsr; return num & (cast(N) 1 << bsr(num)); } unittest { assert(roundDownToPowerOf2(7) == 4); assert(roundDownToPowerOf2(4) == 4); } template isComplexLike(T) { enum bool isComplexLike = is(typeof(T.init.re)) && is(typeof(T.init.im)); } unittest { static assert(isComplexLike!(Complex!double)); static assert(!isComplexLike!(uint)); } ldc-1.1.0-beta3-src/runtime/phobos/std/cstream.d0000664000175000017500000001452212776215007017515 0ustar kaikai// Written in the D programming language. /** * $(RED Deprecated: This module is considered out-dated and not up to Phobos' * current standards. It will be remove in October 2016.) * * The std.cstream module bridges core.stdc.stdio (or std.stdio) and std.stream. * Both core.stdc.stdio and std.stream are publicly imported by std.cstream. * * Macros: * WIKI=Phobos/StdCstream * * Copyright: Copyright Ben Hinkle 2007 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Ben Hinkle * Source: $(PHOBOSSRC std/_cstream.d) */ /* Copyright Ben Hinkle 2007 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ deprecated("It will be removed from Phobos in October 2016. If you still need it, go to https://github.com/DigitalMars/undeaD") module std.cstream; // @@@DEPRECATED_2016-10@@@ public import core.stdc.stdio; public import std.stream; version(unittest) import std.stdio; import std.algorithm; /** * A Stream wrapper for a C file of type FILE*. */ class CFile : Stream { protected FILE* cfile; /** * Create the stream wrapper for the given C file. * Params: * cfile = a valid C $(B FILE) pointer to wrap. * mode = a bitwise combination of $(B FileMode.In) for a readable file * and $(B FileMode.Out) for a writeable file. * seekable = indicates if the stream should be _seekable. */ this(FILE* cfile, FileMode mode, bool seekable = false) { super(); this.file = cfile; readable = cast(bool)(mode & FileMode.In); writeable = cast(bool)(mode & FileMode.Out); this.seekable = seekable; } /** * Closes the stream. */ ~this() { close(); } /** * Property to get or set the underlying file for this stream. * Setting the file marks the stream as open. */ @property FILE* file() { return cfile; } /** * Ditto */ @property void file(FILE* cfile) { this.cfile = cfile; isopen = true; } /** * Overrides of the $(B Stream) methods to call the underlying $(B FILE*) * C functions. */ override void flush() { fflush(cfile); } /** * Ditto */ override void close() { if (isopen) fclose(cfile); isopen = readable = writeable = seekable = false; } /** * Ditto */ override bool eof() { return cast(bool)(readEOF || feof(cfile)); } /** * Ditto */ override char getc() { return cast(char)fgetc(cfile); } /** * Ditto */ override char ungetc(char c) { return cast(char)core.stdc.stdio.ungetc(c,cfile); } /** * Ditto */ override size_t readBlock(void* buffer, size_t size) { size_t n = fread(buffer,1,size,cfile); readEOF = cast(bool)(n == 0); return n; } /** * Ditto */ override size_t writeBlock(const void* buffer, size_t size) { return fwrite(buffer,1,size,cfile); } /** * Ditto */ override ulong seek(long offset, SeekPos rel) { readEOF = false; if (fseek(cfile,cast(int)offset,rel) != 0) throw new SeekException("unable to move file pointer"); return ftell(cfile); } /** * Ditto */ override void writeLine(const(char)[] s) { writeString(s); writeString("\n"); } /** * Ditto */ override void writeLineW(const(wchar)[] s) { writeStringW(s); writeStringW("\n"); } // run a few tests unittest { import std.file : deleteme; import std.internal.cstring : tempCString; auto stream_file = (deleteme ~ "-stream.txt").tempCString(); FILE* f = fopen(stream_file,"w"); assert(f !is null); CFile file = new CFile(f,FileMode.Out); int i = 666; // should be ok to write assert(file.writeable); file.writeLine("Testing stream.d:"); file.writeString("Hello, world!"); file.write(i); // string#1 + string#2 + int should give exacly that version (Windows) assert(file.position == 19 + 13 + 4); version (Posix) assert(file.position == 18 + 13 + 4); file.close(); // no operations are allowed when file is closed assert(!file.readable && !file.writeable && !file.seekable); f = fopen(stream_file,"r"); file = new CFile(f,FileMode.In,true); // should be ok to read assert(file.readable); auto line = file.readLine(); auto exp = "Testing stream.d:"; assert(line[0] == 'T'); assert(line.length == exp.length); assert(!std.algorithm.cmp(line, "Testing stream.d:")); // jump over "Hello, " file.seek(7, SeekPos.Current); version (Windows) assert(file.position == 19 + 7); version (Posix) assert(file.position == 18 + 7); assert(!std.algorithm.cmp(file.readString(6), "world!")); i = 0; file.read(i); assert(i == 666); // string#1 + string#2 + int should give exacly that version (Windows) assert(file.position == 19 + 13 + 4); version (Posix) assert(file.position == 18 + 13 + 4); // we must be at the end of file file.close(); f = fopen(stream_file,"w+"); file = new CFile(f,FileMode.In|FileMode.Out,true); file.writeLine("Testing stream.d:"); file.writeLine("Another line"); file.writeLine(""); file.writeLine("That was blank"); file.position = 0; char[][] lines; foreach(char[] line; file) { lines ~= line.dup; } assert( lines.length == 5 ); assert( lines[0] == "Testing stream.d:"); assert( lines[1] == "Another line"); assert( lines[2] == ""); assert( lines[3] == "That was blank"); file.position = 0; lines = new char[][5]; foreach(ulong n, char[] line; file) { lines[cast(size_t)(n-1)] = line.dup; } assert( lines[0] == "Testing stream.d:"); assert( lines[1] == "Another line"); assert( lines[2] == ""); assert( lines[3] == "That was blank"); file.close(); remove(stream_file); } } /** * CFile wrapper of core.stdc.stdio.stdin (not seekable). */ __gshared CFile din; /** * CFile wrapper of core.stdc.stdio.stdout (not seekable). */ __gshared CFile dout; /** * CFile wrapper of core.stdc.stdio.stderr (not seekable). */ __gshared CFile derr; shared static this() { // open standard I/O devices din = new CFile(core.stdc.stdio.stdin,FileMode.In); dout = new CFile(core.stdc.stdio.stdout,FileMode.Out); derr = new CFile(core.stdc.stdio.stderr,FileMode.Out); } ldc-1.1.0-beta3-src/runtime/phobos/std/regex/0000775000175000017500000000000012776215007017020 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/regex/package.d0000664000175000017500000013667712776215007020604 0ustar kaikai/++ $(LUCKY Regular expressions) are a commonly used method of pattern matching on strings, with $(I regex) being a catchy word for a pattern in this domain specific language. Typical problems usually solved by regular expressions include validation of user input and the ubiquitous find $(AMP) replace in text processing utilities. $(SECTION Synopsis) --- import std.regex; import std.stdio; void main() { // Print out all possible dd/mm/yy(yy) dates found in user input. auto r = regex(r"\b[0-9][0-9]?/[0-9][0-9]?/[0-9][0-9](?:[0-9][0-9])?\b"); foreach(line; stdin.byLine) { // matchAll() returns a range that can be iterated // to get all subsequent matches. foreach(c; matchAll(line, r)) writeln(c.hit); } } ... // Create a static regex at compile-time, which contains fast native code. auto ctr = ctRegex!(`^.*/([^/]+)/?$`); // It works just like a normal regex: auto c2 = matchFirst("foo/bar", ctr); // First match found here, if any assert(!c2.empty); // Be sure to check if there is a match before examining contents! assert(c2[1] == "bar"); // Captures is a range of submatches: 0 = full match. ... // The result of the $(D matchAll) is directly testable with if/assert/while. // e.g. test if a string consists of letters: assert(matchFirst("Letter", `^\p{L}+$`)); --- $(SECTION Syntax and general information) The general usage guideline is to keep regex complexity on the side of simplicity, as its capabilities reside in purely character-level manipulation. As such it's ill-suited for tasks involving higher level invariants like matching an integer number $(U bounded) in an [a,b] interval. Checks of this sort of are better addressed by additional post-processing. The basic syntax shouldn't surprise experienced users of regular expressions. For an introduction to $(D std.regex) see a $(WEB dlang.org/regular-expression.html, short tour) of the module API and its abilities. There are other web resources on regular expressions to help newcomers, and a good $(WEB www.regular-expressions.info, reference with tutorial) can easily be found. This library uses a remarkably common ECMAScript syntax flavor with the following extensions: $(UL $(LI Named subexpressions, with Python syntax. ) $(LI Unicode properties such as Scripts, Blocks and common binary properties e.g Alphabetic, White_Space, Hex_Digit etc.) $(LI Arbitrary length and complexity lookbehind, including lookahead in lookbehind and vise-versa.) ) $(REG_START Pattern syntax ) $(I std.regex operates on codepoint level, 'character' in this table denotes a single Unicode codepoint.) $(REG_TABLE $(REG_TITLE Pattern element, Semantics ) $(REG_TITLE Atoms, Match single characters ) $(REG_ROW any character except [{|*+?()^$, Matches the character itself. ) $(REG_ROW ., In single line mode matches any character. Otherwise it matches any character except '\n' and '\r'. ) $(REG_ROW [class], Matches a single character that belongs to this character class. ) $(REG_ROW [^class], Matches a single character that does $(U not) belong to this character class.) $(REG_ROW \cC, Matches the control character corresponding to letter C) $(REG_ROW \xXX, Matches a character with hexadecimal value of XX. ) $(REG_ROW \uXXXX, Matches a character with hexadecimal value of XXXX. ) $(REG_ROW \U00YYYYYY, Matches a character with hexadecimal value of YYYYYY. ) $(REG_ROW \f, Matches a formfeed character. ) $(REG_ROW \n, Matches a linefeed character. ) $(REG_ROW \r, Matches a carriage return character. ) $(REG_ROW \t, Matches a tab character. ) $(REG_ROW \v, Matches a vertical tab character. ) $(REG_ROW \d, Matches any Unicode digit. ) $(REG_ROW \D, Matches any character except Unicode digits. ) $(REG_ROW \w, Matches any word character (note: this includes numbers).) $(REG_ROW \W, Matches any non-word character.) $(REG_ROW \s, Matches whitespace, same as \p{White_Space}.) $(REG_ROW \S, Matches any character except those recognized as $(I \s ). ) $(REG_ROW \\, Matches \ character. ) $(REG_ROW \c where c is one of [|*+?(), Matches the character c itself. ) $(REG_ROW \p{PropertyName}, Matches a character that belongs to the Unicode PropertyName set. Single letter abbreviations can be used without surrounding {,}. ) $(REG_ROW \P{PropertyName}, Matches a character that does not belong to the Unicode PropertyName set. Single letter abbreviations can be used without surrounding {,}. ) $(REG_ROW \p{InBasicLatin}, Matches any character that is part of the BasicLatin Unicode $(U block).) $(REG_ROW \P{InBasicLatin}, Matches any character except ones in the BasicLatin Unicode $(U block).) $(REG_ROW \p{Cyrillic}, Matches any character that is part of Cyrillic $(U script).) $(REG_ROW \P{Cyrillic}, Matches any character except ones in Cyrillic $(U script).) $(REG_TITLE Quantifiers, Specify repetition of other elements) $(REG_ROW *, Matches previous character/subexpression 0 or more times. Greedy version - tries as many times as possible.) $(REG_ROW *?, Matches previous character/subexpression 0 or more times. Lazy version - stops as early as possible.) $(REG_ROW +, Matches previous character/subexpression 1 or more times. Greedy version - tries as many times as possible.) $(REG_ROW +?, Matches previous character/subexpression 1 or more times. Lazy version - stops as early as possible.) $(REG_ROW {n}, Matches previous character/subexpression exactly n times. ) $(REG_ROW {n$(COMMA)}, Matches previous character/subexpression n times or more. Greedy version - tries as many times as possible. ) $(REG_ROW {n$(COMMA)}?, Matches previous character/subexpression n times or more. Lazy version - stops as early as possible.) $(REG_ROW {n$(COMMA)m}, Matches previous character/subexpression n to m times. Greedy version - tries as many times as possible, but no more than m times. ) $(REG_ROW {n$(COMMA)m}?, Matches previous character/subexpression n to m times. Lazy version - stops as early as possible, but no less then n times.) $(REG_TITLE Other, Subexpressions $(AMP) alternations ) $(REG_ROW (regex), Matches subexpression regex, saving matched portion of text for later retrieval. ) $(REG_ROW (?:regex), Matches subexpression regex, $(U not) saving matched portion of text. Useful to speed up matching. ) $(REG_ROW A|B, Matches subexpression A, or failing that, matches B. ) $(REG_ROW (?P$(LT)name$(GT)regex), Matches named subexpression regex labeling it with name 'name'. When referring to a matched portion of text, names work like aliases in addition to direct numbers. ) $(REG_TITLE Assertions, Match position rather than character ) $(REG_ROW ^, Matches at the begining of input or line (in multiline mode).) $(REG_ROW $, Matches at the end of input or line (in multiline mode). ) $(REG_ROW \b, Matches at word boundary. ) $(REG_ROW \B, Matches when $(U not) at word boundary. ) $(REG_ROW (?=regex), Zero-width lookahead assertion. Matches at a point where the subexpression regex could be matched starting from the current position. ) $(REG_ROW (?!regex), Zero-width negative lookahead assertion. Matches at a point where the subexpression regex could $(U not) be matched starting from the current position. ) $(REG_ROW (?<=regex), Zero-width lookbehind assertion. Matches at a point where the subexpression regex could be matched ending at the current position (matching goes backwards). ) $(REG_ROW (? $0 REG_START =

$0

SECTION =

$0

S_LINK = $+ +/ module std.regex; import std.regex.internal.ir; import std.regex.internal.thompson; //TODO: get rid of this dependency import std.exception, std.traits, std.range; /++ $(D Regex) object holds regular expression pattern in compiled form. Instances of this object are constructed via calls to $(D regex). This is an intended form for caching and storage of frequently used regular expressions. Example: Test if this object doesn't contain any compiled pattern. --- Regex!char r; assert(r.empty); r = regex(""); // Note: "" is a valid regex pattern. assert(!r.empty); --- Getting a range of all the named captures in the regex. ---- import std.range; import std.algorithm; auto re = regex(`(?P\w+) = (?P\d+)`); auto nc = re.namedCaptures; static assert(isRandomAccessRange!(typeof(nc))); assert(!nc.empty); assert(nc.length == 2); assert(nc.equal(["name", "var"])); assert(nc[0] == "name"); assert(nc[1..$].equal(["var"])); ---- +/ public alias Regex(Char) = std.regex.internal.ir.Regex!(Char); /++ A $(D StaticRegex) is $(D Regex) object that contains D code specially generated at compile-time to speed up matching. Implicitly convertible to normal $(D Regex), however doing so will result in losing this additional capability. +/ public alias StaticRegex(Char) = std.regex.internal.ir.StaticRegex!(Char); /++ Compile regular expression pattern for the later execution. Returns: $(D Regex) object that works on inputs having the same character width as $(D pattern). Params: pattern = Regular expression flags = The _attributes (g, i, m and x accepted) Throws: $(D RegexException) if there were any errors during compilation. +/ @trusted public auto regex(S)(S pattern, const(char)[] flags="") if(isSomeString!(S)) { import std.functional; enum cacheSize = 8; //TODO: invent nice interface to control regex caching if(__ctfe) return regexImpl(pattern, flags); return memoize!(regexImpl!S, cacheSize)(pattern, flags); } public auto regexImpl(S)(S pattern, const(char)[] flags="") if(isSomeString!(S)) { import std.regex.internal.parser; auto parser = Parser!(Unqual!(typeof(pattern)))(pattern, flags); auto r = parser.program; return r; } template ctRegexImpl(alias pattern, string flags=[]) { import std.regex.internal.parser, std.regex.internal.backtracking; enum r = regex(pattern, flags); alias Char = BasicElementOf!(typeof(pattern)); enum source = ctGenRegExCode(r); alias Matcher = BacktrackingMatcher!(true); @trusted bool func(ref Matcher!Char matcher) { debug(std_regex_ctr) pragma(msg, source); mixin(source); } enum nr = StaticRegex!Char(r, &func); } /++ Compile regular expression using CTFE and generate optimized native machine code for matching it. Returns: StaticRegex object for faster matching. Params: pattern = Regular expression flags = The _attributes (g, i, m and x accepted) +/ public enum ctRegex(alias pattern, alias flags=[]) = ctRegexImpl!(pattern, flags).nr; enum isRegexFor(RegEx, R) = is(RegEx == Regex!(BasicElementOf!R)) || is(RegEx == StaticRegex!(BasicElementOf!R)); /++ $(D Captures) object contains submatches captured during a call to $(D match) or iteration over $(D RegexMatch) range. First element of range is the whole match. +/ @trusted public struct Captures(R, DIndex = size_t) if(isSomeString!R) {//@trusted because of union inside alias DataIndex = DIndex; alias String = R; private: import std.conv; R _input; bool _empty; enum smallString = 3; union { Group!DataIndex[] big_matches; Group!DataIndex[smallString] small_matches; } uint _f, _b; uint _ngroup; NamedGroup[] _names; this()(R input, uint ngroups, NamedGroup[] named) { _input = input; _ngroup = ngroups; _names = named; newMatches(); _b = _ngroup; _f = 0; } this(alias Engine)(ref RegexMatch!(R,Engine) rmatch) { _input = rmatch._input; _ngroup = rmatch._engine.re.ngroup; _names = rmatch._engine.re.dict; newMatches(); _b = _ngroup; _f = 0; } @property Group!DataIndex[] matches() { return _ngroup > smallString ? big_matches : small_matches[0 .. _ngroup]; } void newMatches() { if(_ngroup > smallString) big_matches = new Group!DataIndex[_ngroup]; } public: ///Slice of input prior to the match. @property R pre() { return _empty ? _input[] : _input[0 .. matches[0].begin]; } ///Slice of input immediately after the match. @property R post() { return _empty ? _input[] : _input[matches[0].end .. $]; } ///Slice of matched portion of input. @property R hit() { assert(!_empty); return _input[matches[0].begin .. matches[0].end]; } ///Range interface. @property R front() { assert(!empty); return _input[matches[_f].begin .. matches[_f].end]; } ///ditto @property R back() { assert(!empty); return _input[matches[_b - 1].begin .. matches[_b - 1].end]; } ///ditto void popFront() { assert(!empty); ++_f; } ///ditto void popBack() { assert(!empty); --_b; } ///ditto @property bool empty() const { return _empty || _f >= _b; } ///ditto R opIndex()(size_t i) /*const*/ //@@@BUG@@@ { assert(_f + i < _b,text("requested submatch number ", i," is out of range")); assert(matches[_f + i].begin <= matches[_f + i].end, text("wrong match: ", matches[_f + i].begin, "..", matches[_f + i].end)); return _input[matches[_f + i].begin .. matches[_f + i].end]; } /++ Explicit cast to bool. Useful as a shorthand for !(x.empty) in if and assert statements. --- import std.regex; assert(!matchFirst("nothing", "something")); --- +/ @safe bool opCast(T:bool)() const nothrow { return !empty; } /++ Lookup named submatch. --- import std.regex; import std.range; auto c = matchFirst("a = 42;", regex(`(?P\w+)\s*=\s*(?P\d+);`)); assert(c["var"] == "a"); assert(c["value"] == "42"); popFrontN(c, 2); //named groups are unaffected by range primitives assert(c["var"] =="a"); assert(c.front == "42"); ---- +/ R opIndex(String)(String i) /*const*/ //@@@BUG@@@ if(isSomeString!String) { size_t index = lookupNamedGroup(_names, i); return _input[matches[index].begin .. matches[index].end]; } ///Number of matches in this object. @property size_t length() const { return _empty ? 0 : _b - _f; } ///A hook for compatibility with original std.regex. @property ref captures(){ return this; } } /// unittest { auto c = matchFirst("@abc#", regex(`(\w)(\w)(\w)`)); assert(c.pre == "@"); // Part of input preceding match assert(c.post == "#"); // Immediately after match assert(c.hit == c[0] && c.hit == "abc"); // The whole match assert(c[2] == "b"); assert(c.front == "abc"); c.popFront(); assert(c.front == "a"); assert(c.back == "c"); c.popBack(); assert(c.back == "b"); popFrontN(c, 2); assert(c.empty); assert(!matchFirst("nothing", "something")); } /++ A regex engine state, as returned by $(D match) family of functions. Effectively it's a forward range of Captures!R, produced by lazily searching for matches in a given input. $(D alias Engine) specifies an engine type to use during matching, and is automatically deduced in a call to $(D match)/$(D bmatch). +/ @trusted public struct RegexMatch(R, alias Engine = ThompsonMatcher) if(isSomeString!R) { private: import core.stdc.stdlib; alias Char = BasicElementOf!R; alias EngineType = Engine!Char; EngineType _engine; R _input; Captures!(R,EngineType.DataIndex) _captures; void[] _memory;//is ref-counted this(RegEx)(R input, RegEx prog) { _input = input; immutable size = EngineType.initialMemory(prog)+size_t.sizeof; _memory = (enforce(malloc(size), "malloc failed")[0..size]); scope(failure) free(_memory.ptr); *cast(size_t*)_memory.ptr = 1; _engine = EngineType(prog, Input!Char(input), _memory[size_t.sizeof..$]); static if(is(RegEx == StaticRegex!(BasicElementOf!R))) _engine.nativeFn = prog.nativeFn; _captures = Captures!(R,EngineType.DataIndex)(this); _captures._empty = !_engine.match(_captures.matches); debug(std_regex_allocation) writefln("RefCount (ctor): %x %d", _memory.ptr, counter); } @property ref size_t counter(){ return *cast(size_t*)_memory.ptr; } public: this(this) { if(_memory.ptr) { ++counter; debug(std_regex_allocation) writefln("RefCount (postblit): %x %d", _memory.ptr, *cast(size_t*)_memory.ptr); } } ~this() { if(_memory.ptr && --*cast(size_t*)_memory.ptr == 0) { debug(std_regex_allocation) writefln("RefCount (dtor): %x %d", _memory.ptr, *cast(size_t*)_memory.ptr); free(cast(void*)_memory.ptr); } } ///Shorthands for front.pre, front.post, front.hit. @property R pre() { return _captures.pre; } ///ditto @property R post() { return _captures.post; } ///ditto @property R hit() { return _captures.hit; } /++ Functionality for processing subsequent matches of global regexes via range interface: --- import std.regex; auto m = matchAll("Hello, world!", regex(`\w+`)); assert(m.front.hit == "Hello"); m.popFront(); assert(m.front.hit == "world"); m.popFront(); assert(m.empty); --- +/ @property auto front() { return _captures; } ///ditto void popFront() { if(counter != 1) {//do cow magic first counter--;//we abandon this reference immutable size = EngineType.initialMemory(_engine.re)+size_t.sizeof; _memory = (enforce(malloc(size), "malloc failed")[0..size]); _engine = _engine.dupTo(_memory[size_t.sizeof..size]); counter = 1;//points to new chunk } //previous _captures can have escaped references from Capture object _captures.newMatches(); _captures._empty = !_engine.match(_captures.matches); } ///ditto auto save(){ return this; } ///Test if this match object is empty. @property bool empty(){ return _captures._empty; } ///Same as !(x.empty), provided for its convenience in conditional statements. T opCast(T:bool)(){ return !empty; } /// Same as .front, provided for compatibility with original std.regex. @property auto captures(){ return _captures; } } private @trusted auto matchOnce(alias Engine, RegEx, R)(R input, RegEx re) { import core.stdc.stdlib; alias Char = BasicElementOf!R; alias EngineType = Engine!Char; size_t size = EngineType.initialMemory(re); void[] memory = enforce(malloc(size), "malloc failed")[0..size]; scope(exit) free(memory.ptr); auto captures = Captures!(R, EngineType.DataIndex)(input, re.ngroup, re.dict); auto engine = EngineType(re, Input!Char(input), memory); static if(is(RegEx == StaticRegex!(BasicElementOf!R))) engine.nativeFn = re.nativeFn; captures._empty = !engine.match(captures.matches); return captures; } private auto matchMany(alias Engine, RegEx, R)(R input, RegEx re) { re.flags |= RegexOption.global; return RegexMatch!(R, Engine)(input, re); } unittest { //sanity checks for new API auto re = regex("abc"); assert(!"abc".matchOnce!(ThompsonMatcher)(re).empty); assert("abc".matchOnce!(ThompsonMatcher)(re)[0] == "abc"); } private enum isReplaceFunctor(alias fun, R) = __traits(compiles, (Captures!R c) { fun(c); }); // the lowest level - just stuff replacements into the sink private @trusted void replaceCapturesInto(alias output, Sink, R, T) (ref Sink sink, R input, T captures) if(isOutputRange!(Sink, dchar) && isSomeString!R) { sink.put(captures.pre); // a hack to get around bogus errors, should be simply output(captures, sink) // "is a nested function and cannot be accessed from" static if(isReplaceFunctor!(output, R)) sink.put(output(captures)); //"mutator" type of function else output(captures, sink); //"output" type of function sink.put(captures.post); } // ditto for a range of captures private void replaceMatchesInto(alias output, Sink, R, T) (ref Sink sink, R input, T matches) if(isOutputRange!(Sink, dchar) && isSomeString!R) { size_t offset = 0; foreach(cap; matches) { sink.put(cap.pre[offset .. $]); // same hack, see replaceCapturesInto static if(isReplaceFunctor!(output, R)) sink.put(output(cap)); //"mutator" type of function else output(cap, sink); //"output" type of function offset = cap.pre.length + cap.hit.length; } sink.put(input[offset .. $]); } // a general skeleton of replaceFirst private R replaceFirstWith(alias output, R, RegEx)(R input, RegEx re) if(isSomeString!R && isRegexFor!(RegEx, R)) { auto data = matchFirst(input, re); if(data.empty) return input; auto app = appender!(R)(); replaceCapturesInto!output(app, input, data); return app.data; } // ditto for replaceAll // the method parameter allows old API to ride on the back of the new one private R replaceAllWith(alias output, alias method=matchAll, R, RegEx)(R input, RegEx re) if(isSomeString!R && isRegexFor!(RegEx, R)) { auto matches = method(input, re); //inout(C)[] fails if(matches.empty) return input; auto app = appender!(R)(); replaceMatchesInto!output(app, input, matches); return app.data; } /++ Start matching $(D input) to regex pattern $(D re), using Thompson NFA matching scheme. The use of this function is $(RED discouraged) - use either of $(LREF matchAll) or $(LREF matchFirst). Delegating the kind of operation to "g" flag is soon to be phased out along with the ability to choose the exact matching scheme. The choice of matching scheme to use depends highly on the pattern kind and can done automatically on case by case basis. Returns: a $(D RegexMatch) object holding engine state after first match. +/ public auto match(R, RegEx)(R input, RegEx re) if(isSomeString!R && is(RegEx == Regex!(BasicElementOf!R))) { import std.regex.internal.thompson; return RegexMatch!(Unqual!(typeof(input)),ThompsonMatcher)(input, re); } ///ditto public auto match(R, String)(R input, String re) if(isSomeString!R && isSomeString!String) { import std.regex.internal.thompson; return RegexMatch!(Unqual!(typeof(input)),ThompsonMatcher)(input, regex(re)); } public auto match(R, RegEx)(R input, RegEx re) if(isSomeString!R && is(RegEx == StaticRegex!(BasicElementOf!R))) { import std.regex.internal.backtracking; return RegexMatch!(Unqual!(typeof(input)),BacktrackingMatcher!true)(input, re); } /++ Find the first (leftmost) slice of the $(D input) that matches the pattern $(D re). This function picks the most suitable regular expression engine depending on the pattern properties. $(D re) parameter can be one of three types: $(UL $(LI Plain string, in which case it's compiled to bytecode before matching. ) $(LI Regex!char (wchar/dchar) that contains a pattern in the form of compiled bytecode. ) $(LI StaticRegex!char (wchar/dchar) that contains a pattern in the form of compiled native machine code. ) ) Returns: $(LREF Captures) containing the extent of a match together with all submatches if there was a match, otherwise an empty $(LREF Captures) object. +/ public auto matchFirst(R, RegEx)(R input, RegEx re) if(isSomeString!R && is(RegEx == Regex!(BasicElementOf!R))) { import std.regex.internal.thompson; return matchOnce!ThompsonMatcher(input, re); } ///ditto public auto matchFirst(R, String)(R input, String re) if(isSomeString!R && isSomeString!String) { import std.regex.internal.thompson; return matchOnce!ThompsonMatcher(input, regex(re)); } public auto matchFirst(R, RegEx)(R input, RegEx re) if(isSomeString!R && is(RegEx == StaticRegex!(BasicElementOf!R))) { import std.regex.internal.backtracking; return matchOnce!(BacktrackingMatcher!true)(input, re); } /++ Initiate a search for all non-overlapping matches to the pattern $(D re) in the given $(D input). The result is a lazy range of matches generated as they are encountered in the input going left to right. This function picks the most suitable regular expression engine depending on the pattern properties. $(D re) parameter can be one of three types: $(UL $(LI Plain string, in which case it's compiled to bytecode before matching. ) $(LI Regex!char (wchar/dchar) that contains a pattern in the form of compiled bytecode. ) $(LI StaticRegex!char (wchar/dchar) that contains a pattern in the form of compiled native machine code. ) ) Returns: $(LREF RegexMatch) object that represents matcher state after the first match was found or an empty one if not present. +/ public auto matchAll(R, RegEx)(R input, RegEx re) if(isSomeString!R && is(RegEx == Regex!(BasicElementOf!R))) { import std.regex.internal.thompson; return matchMany!ThompsonMatcher(input, re); } ///ditto public auto matchAll(R, String)(R input, String re) if(isSomeString!R && isSomeString!String) { import std.regex.internal.thompson; return matchMany!ThompsonMatcher(input, regex(re)); } public auto matchAll(R, RegEx)(R input, RegEx re) if(isSomeString!R && is(RegEx == StaticRegex!(BasicElementOf!R))) { import std.regex.internal.backtracking; return matchMany!(BacktrackingMatcher!true)(input, re); } // another set of tests just to cover the new API @system unittest { import std.conv : to; import std.algorithm : map, equal; foreach(String; AliasSeq!(string, wstring, const(dchar)[])) { auto str1 = "blah-bleh".to!String(); auto pat1 = "bl[ae]h".to!String(); auto mf = matchFirst(str1, pat1); assert(mf.equal(["blah".to!String()])); auto mAll = matchAll(str1, pat1); assert(mAll.equal!((a,b) => a.equal(b)) ([["blah".to!String()], ["bleh".to!String()]])); auto str2 = "1/03/12 - 3/03/12".to!String(); auto pat2 = regex(r"(\d+)/(\d+)/(\d+)".to!String()); auto mf2 = matchFirst(str2, pat2); assert(mf2.equal(["1/03/12", "1", "03", "12"].map!(to!String)())); auto mAll2 = matchAll(str2, pat2); assert(mAll2.front.equal(mf2)); mAll2.popFront(); assert(mAll2.front.equal(["3/03/12", "3", "03", "12"].map!(to!String)())); mf2.popFrontN(3); assert(mf2.equal(["12".to!String()])); auto ctPat = ctRegex!(`(?P\d+)/(?P\d+)`.to!String()); auto str = "2 + 34/56 - 6/1".to!String(); auto cmf = matchFirst(str, ctPat); assert(cmf.equal(["34/56", "34", "56"].map!(to!String)())); assert(cmf["Quot"] == "34".to!String()); assert(cmf["Denom"] == "56".to!String()); auto cmAll = matchAll(str, ctPat); assert(cmAll.front.equal(cmf)); cmAll.popFront(); assert(cmAll.front.equal(["6/1", "6", "1"].map!(to!String)())); } } /++ Start matching of $(D input) to regex pattern $(D re), using traditional $(LUCKY backtracking) matching scheme. The use of this function is $(RED discouraged) - use either of $(LREF matchAll) or $(LREF matchFirst). Delegating the kind of operation to "g" flag is soon to be phased out along with the ability to choose the exact matching scheme. The choice of matching scheme to use depends highly on the pattern kind and can done automatically on case by case basis. Returns: a $(D RegexMatch) object holding engine state after first match. +/ public auto bmatch(R, RegEx)(R input, RegEx re) if(isSomeString!R && is(RegEx == Regex!(BasicElementOf!R))) { import std.regex.internal.backtracking; return RegexMatch!(Unqual!(typeof(input)), BacktrackingMatcher!false)(input, re); } ///ditto public auto bmatch(R, String)(R input, String re) if(isSomeString!R && isSomeString!String) { import std.regex.internal.backtracking; return RegexMatch!(Unqual!(typeof(input)), BacktrackingMatcher!false)(input, regex(re)); } public auto bmatch(R, RegEx)(R input, RegEx re) if(isSomeString!R && is(RegEx == StaticRegex!(BasicElementOf!R))) { import std.regex.internal.backtracking; return RegexMatch!(Unqual!(typeof(input)),BacktrackingMatcher!true)(input, re); } // produces replacement string from format using captures for substitution package void replaceFmt(R, Capt, OutR) (R format, Capt captures, OutR sink, bool ignoreBadSubs = false) if(isOutputRange!(OutR, ElementEncodingType!R[]) && isOutputRange!(OutR, ElementEncodingType!(Capt.String)[])) { import std.algorithm, std.conv; import std.ascii: isDigit, isAlpha; enum State { Normal, Dollar } auto state = State.Normal; size_t offset; L_Replace_Loop: while(!format.empty) final switch(state) { case State.Normal: for(offset = 0; offset < format.length; offset++)//no decoding { if(format[offset] == '$') { state = State.Dollar; sink.put(format[0 .. offset]); format = format[offset+1 .. $];//ditto continue L_Replace_Loop; } } sink.put(format[0 .. offset]); format = format[offset .. $]; break; case State.Dollar: if(isDigit(format[0])) { uint digit = parse!uint(format); enforce(ignoreBadSubs || digit < captures.length, text("invalid submatch number ", digit)); if(digit < captures.length) sink.put(captures[digit]); } else if(format[0] == '{') { auto x = find!(a => !isAlpha(a))(format[1..$]); enforce(!x.empty && x[0] == '}', "no matching '}' in replacement format"); auto name = format[1 .. $ - x.length]; format = x[1..$]; enforce(!name.empty, "invalid name in ${...} replacement format"); sink.put(captures[name]); } else if(format[0] == '&') { sink.put(captures[0]); format = format[1 .. $]; } else if(format[0] == '`') { sink.put(captures.pre); format = format[1 .. $]; } else if(format[0] == '\'') { sink.put(captures.post); format = format[1 .. $]; } else if(format[0] == '$') { sink.put(format[0 .. 1]); format = format[1 .. $]; } state = State.Normal; break; } enforce(state == State.Normal, "invalid format string in regex replace"); } /++ Construct a new string from $(D input) by replacing the first match with a string generated from it according to the $(D format) specifier. To replace all matches use $(LREF replaceAll). Params: input = string to search re = compiled regular expression to use format = format string to generate replacements from, see $(S_LINK Replace format string, the format string). Returns: A string of the same type with the first match (if any) replaced. If no match is found returns the input string itself. +/ public R replaceFirst(R, C, RegEx)(R input, RegEx re, const(C)[] format) if(isSomeString!R && is(C : dchar) && isRegexFor!(RegEx, R)) { return replaceFirstWith!((m, sink) => replaceFmt(format, m, sink))(input, re); } /// unittest { assert(replaceFirst("noon", regex("n"), "[$&]") == "[n]oon"); } /++ This is a general replacement tool that construct a new string by replacing matches of pattern $(D re) in the $(D input). Unlike the other overload there is no format string instead captures are passed to to a user-defined functor $(D fun) that returns a new string to use as replacement. This version replaces the first match in $(D input), see $(LREF replaceAll) to replace the all of the matches. Returns: A new string of the same type as $(D input) with all matches replaced by return values of $(D fun). If no matches found returns the $(D input) itself. +/ public R replaceFirst(alias fun, R, RegEx)(R input, RegEx re) if(isSomeString!R && isRegexFor!(RegEx, R)) { return replaceFirstWith!((m, sink) => sink.put(fun(m)))(input, re); } /// unittest { import std.conv: to; string list = "#21 out of 46"; string newList = replaceFirst!(cap => to!string(to!int(cap.hit)+1)) (list, regex(`[0-9]+`)); assert(newList == "#22 out of 46"); } /++ A variation on $(LREF replaceFirst) that instead of allocating a new string on each call outputs the result piece-wise to the $(D sink). In particular this enables efficient construction of a final output incrementally. Like in $(LREF replaceFirst) family of functions there is an overload for the substitution guided by the $(D format) string and the one with the user defined callback. +/ public @trusted void replaceFirstInto(Sink, R, C, RegEx) (ref Sink sink, R input, RegEx re, const(C)[] format) if(isOutputRange!(Sink, dchar) && isSomeString!R && is(C : dchar) && isRegexFor!(RegEx, R)) { replaceCapturesInto!((m, sink) => replaceFmt(format, m, sink)) (sink, input, matchFirst(input, re)); } ///ditto public @trusted void replaceFirstInto(alias fun, Sink, R, RegEx) (Sink sink, R input, RegEx re) if(isOutputRange!(Sink, dchar) && isSomeString!R && isRegexFor!(RegEx, R)) { replaceCapturesInto!fun(sink, input, matchFirst(input, re)); } /// unittest { import std.array; string m1 = "first message\n"; string m2 = "second message\n"; auto result = appender!string(); replaceFirstInto(result, m1, regex(`([a-z]+) message`), "$1"); //equivalent of the above with user-defined callback replaceFirstInto!(cap=>cap[1])(result, m2, regex(`([a-z]+) message`)); assert(result.data == "first\nsecond\n"); } //examples for replaceFirst @system unittest { import std.conv; string list = "#21 out of 46"; string newList = replaceFirst!(cap => to!string(to!int(cap.hit)+1)) (list, regex(`[0-9]+`)); assert(newList == "#22 out of 46"); import std.array; string m1 = "first message\n"; string m2 = "second message\n"; auto result = appender!string(); replaceFirstInto(result, m1, regex(`([a-z]+) message`), "$1"); //equivalent of the above with user-defined callback replaceFirstInto!(cap=>cap[1])(result, m2, regex(`([a-z]+) message`)); assert(result.data == "first\nsecond\n"); } /++ Construct a new string from $(D input) by replacing all of the fragments that match a pattern $(D re) with a string generated from the match according to the $(D format) specifier. To replace only the first match use $(LREF replaceFirst). Params: input = string to search re = compiled regular expression to use format = format string to generate replacements from, see $(S_LINK Replace format string, the format string). Returns: A string of the same type as $(D input) with the all of the matches (if any) replaced. If no match is found returns the input string itself. +/ public @trusted R replaceAll(R, C, RegEx)(R input, RegEx re, const(C)[] format) if(isSomeString!R && is(C : dchar) && isRegexFor!(RegEx, R)) { return replaceAllWith!((m, sink) => replaceFmt(format, m, sink))(input, re); } /// unittest { // insert comma as thousands delimiter auto re = regex(r"(?<=\d)(?=(\d\d\d)+\b)","g"); assert(replaceAll("12000 + 42100 = 54100", re, ",") == "12,000 + 42,100 = 54,100"); } /++ This is a general replacement tool that construct a new string by replacing matches of pattern $(D re) in the $(D input). Unlike the other overload there is no format string instead captures are passed to to a user-defined functor $(D fun) that returns a new string to use as replacement. This version replaces all of the matches found in $(D input), see $(LREF replaceFirst) to replace the first match only. Returns: A new string of the same type as $(D input) with all matches replaced by return values of $(D fun). If no matches found returns the $(D input) itself. Params: input = string to search re = compiled regular expression fun = delegate to use +/ public @trusted R replaceAll(alias fun, R, RegEx)(R input, RegEx re) if(isSomeString!R && isRegexFor!(RegEx, R)) { return replaceAllWith!((m, sink) => sink.put(fun(m)))(input, re); } /// unittest { string baz(Captures!(string) m) { return std.string.toUpper(m.hit); } // Capitalize the letters 'a' and 'r': auto s = replaceAll!(baz)("Strap a rocket engine on a chicken.", regex("[ar]")); assert(s == "StRAp A Rocket engine on A chicken."); } /++ A variation on $(LREF replaceAll) that instead of allocating a new string on each call outputs the result piece-wise to the $(D sink). In particular this enables efficient construction of a final output incrementally. As with $(LREF replaceAll) there are 2 overloads - one with a format string, the other one with a user defined functor. +/ public @trusted void replaceAllInto(Sink, R, C, RegEx) (Sink sink, R input, RegEx re, const(C)[] format) if(isOutputRange!(Sink, dchar) && isSomeString!R && is(C : dchar) && isRegexFor!(RegEx, R)) { replaceMatchesInto!((m, sink) => replaceFmt(format, m, sink)) (sink, input, matchAll(input, re)); } ///ditto public @trusted void replaceAllInto(alias fun, Sink, R, RegEx) (Sink sink, R input, RegEx re) if(isOutputRange!(Sink, dchar) && isSomeString!R && isRegexFor!(RegEx, R)) { replaceMatchesInto!fun(sink, input, matchAll(input, re)); } /// @system unittest { // insert comma as thousands delimiter in fifty randomly produced big numbers import std.array, std.random, std.conv, std.range; static re = regex(`(?<=\d)(?=(\d\d\d)+\b)`, "g"); auto sink = appender!(char [])(); enum ulong min = 10UL ^^ 10, max = 10UL ^^ 19; foreach (i; 0 .. 50) { sink.clear(); replaceAllInto(sink, text(uniform(min, max)), re, ","); foreach (pos; iota(sink.data.length - 4, 0, -4)) assert(sink.data[pos] == ','); } } // exercise all of the replace APIs @system unittest { import std.conv; // try and check first/all simple substitution foreach(S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[])) { S s1 = "curt trial".to!S(); S s2 = "round dome".to!S(); S t1F = "court trial".to!S(); S t2F = "hound dome".to!S(); S t1A = "court trial".to!S(); S t2A = "hound home".to!S(); auto re1 = regex("curt".to!S()); auto re2 = regex("[dr]o".to!S()); assert(replaceFirst(s1, re1, "court") == t1F); assert(replaceFirst(s2, re2, "ho") == t2F); assert(replaceAll(s1, re1, "court") == t1A); assert(replaceAll(s2, re2, "ho") == t2A); auto rep1 = replaceFirst!(cap => cap[0][0]~"o".to!S()~cap[0][1..$])(s1, re1); assert(rep1 == t1F); assert(replaceFirst!(cap => "ho".to!S())(s2, re2) == t2F); auto rep1A = replaceAll!(cap => cap[0][0]~"o".to!S()~cap[0][1..$])(s1, re1); assert(rep1A == t1A); assert(replaceAll!(cap => "ho".to!S())(s2, re2) == t2A); auto sink = appender!S(); replaceFirstInto(sink, s1, re1, "court"); assert(sink.data == t1F); replaceFirstInto(sink, s2, re2, "ho"); assert(sink.data == t1F~t2F); replaceAllInto(sink, s1, re1, "court"); assert(sink.data == t1F~t2F~t1A); replaceAllInto(sink, s2, re2, "ho"); assert(sink.data == t1F~t2F~t1A~t2A); } } /++ Old API for replacement, operation depends on flags of pattern $(D re). With "g" flag it performs the equivalent of $(LREF replaceAll) otherwise it works the same as $(LREF replaceFirst). The use of this function is $(RED discouraged), please use $(LREF replaceAll) or $(LREF replaceFirst) explicitly. +/ public R replace(alias scheme = match, R, C, RegEx)(R input, RegEx re, const(C)[] format) if(isSomeString!R && isRegexFor!(RegEx, R)) { return replaceAllWith!((m, sink) => replaceFmt(format, m, sink), match)(input, re); } ///ditto public R replace(alias fun, R, RegEx)(R input, RegEx re) if(isSomeString!R && isRegexFor!(RegEx, R)) { return replaceAllWith!(fun, match)(input, re); } /++ Range that splits a string using a regular expression as a separator. +/ public struct Splitter(Range, alias RegEx = Regex) if(isSomeString!Range && isRegexFor!(RegEx, Range)) { private: Range _input; size_t _offset; alias Rx = typeof(match(Range.init,RegEx.init)); Rx _match; @trusted this(Range input, RegEx separator) {//@@@BUG@@@ generated opAssign of RegexMatch is not @trusted _input = input; separator.flags |= RegexOption.global; if (_input.empty) { //there is nothing to match at all, make _offset > 0 _offset = 1; } else { _match = Rx(_input, separator); } } public: auto ref opSlice() { return this.save; } ///Forward range primitives. @property Range front() { import std.algorithm : min; assert(!empty && _offset <= _match.pre.length && _match.pre.length <= _input.length); return _input[_offset .. min($, _match.pre.length)]; } ///ditto @property bool empty() { return _offset > _input.length; } ///ditto void popFront() { assert(!empty); if (_match.empty) { //No more separators, work is done here _offset = _input.length + 1; } else { //skip past the separator _offset = _match.pre.length + _match.hit.length; _match.popFront(); } } ///ditto @property auto save() { return this; } } /** A helper function, creates a $(D Splitter) on range $(D r) separated by regex $(D pat). Captured subexpressions have no effect on the resulting range. */ public Splitter!(Range, RegEx) splitter(Range, RegEx)(Range r, RegEx pat) if(is(BasicElementOf!Range : dchar) && isRegexFor!(RegEx, Range)) { return Splitter!(Range, RegEx)(r, pat); } /// unittest { import std.algorithm: equal; auto s1 = ", abc, de, fg, hi, "; assert(equal(splitter(s1, regex(", *")), ["", "abc", "de", "fg", "hi", ""])); } ///An eager version of $(D splitter) that creates an array with splitted slices of $(D input). public @trusted String[] split(String, RegEx)(String input, RegEx rx) if(isSomeString!String && isRegexFor!(RegEx, String)) { auto a = appender!(String[])(); foreach(e; splitter(input, rx)) a.put(e); return a.data; } ///Exception object thrown in case of errors during regex compilation. public alias RegexException = std.regex.internal.ir.RegexException; ldc-1.1.0-beta3-src/runtime/phobos/std/regex/internal/0000775000175000017500000000000012776215007020634 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/regex/internal/thompson.d0000664000175000017500000007660212776215007022663 0ustar kaikai//Written in the D programming language /* Implementation of Thompson NFA std.regex engine. Key point is evaluation of all possible threads (state) at each step in a breadth-first manner, thereby geting some nice properties: - looking at each character only once - merging of equivalent threads, that gives matching process linear time complexity */ module std.regex.internal.thompson; package(std.regex): import std.regex.internal.ir; import std.range; //State of VM thread struct Thread(DataIndex) { Thread* next; //intrusive linked list uint pc; uint counter; //loop counter uint uopCounter; //counts micro operations inside one macro instruction (e.g. BackRef) Group!DataIndex[1] matches; } //head-tail singly-linked list struct ThreadList(DataIndex) { Thread!DataIndex* tip = null, toe = null; //add new thread to the start of list void insertFront(Thread!DataIndex* t) { if(tip) { t.next = tip; tip = t; } else { t.next = null; tip = toe = t; } } //add new thread to the end of list void insertBack(Thread!DataIndex* t) { if(toe) { toe.next = t; toe = t; } else tip = toe = t; toe.next = null; } //move head element out of list Thread!DataIndex* fetch() { auto t = tip; if(tip == toe) tip = toe = null; else tip = tip.next; return t; } //non-destructive iteration of ThreadList struct ThreadRange { const(Thread!DataIndex)* ct; this(ThreadList tlist){ ct = tlist.tip; } @property bool empty(){ return ct is null; } @property const(Thread!DataIndex)* front(){ return ct; } @property popFront() { assert(ct); ct = ct.next; } } @property bool empty() { return tip == null; } ThreadRange opSlice() { return ThreadRange(this); } } /+ Thomspon matcher does all matching in lockstep, never looking at the same char twice +/ @trusted struct ThompsonMatcher(Char, Stream = Input!Char) if(is(Char : dchar)) { alias DataIndex = Stream.DataIndex; Thread!DataIndex* freelist; ThreadList!DataIndex clist, nlist; DataIndex[] merge; Group!DataIndex[] backrefed; Regex!Char re; //regex program Stream s; dchar front; DataIndex index; DataIndex genCounter; //merge trace counter, goes up on every dchar size_t[size_t] subCounters; //a table of gen counter per sub-engine: PC -> counter size_t threadSize; bool matched; bool exhausted; static if(__traits(hasMember,Stream, "search")) { enum kicked = true; } else enum kicked = false; static size_t getThreadSize(const ref Regex!Char re) { return re.ngroup ? (Thread!DataIndex).sizeof + (re.ngroup-1)*(Group!DataIndex).sizeof : (Thread!DataIndex).sizeof - (Group!DataIndex).sizeof; } static size_t initialMemory(const ref Regex!Char re) { return getThreadSize(re)*re.threadCount + re.hotspotTableSize*size_t.sizeof; } //true if it's start of input @property bool atStart(){ return index == 0; } //true if it's end of input @property bool atEnd(){ return index == s.lastIndex && s.atEnd; } bool next() { if(!s.nextChar(front, index)) { index = s.lastIndex; return false; } return true; } static if(kicked) { bool search() { if(!s.search(re.kickstart, front, index)) { index = s.lastIndex; return false; } return true; } } void initExternalMemory(void[] memory) { threadSize = getThreadSize(re); prepareFreeList(re.threadCount, memory); if(re.hotspotTableSize) { merge = arrayInChunk!(DataIndex)(re.hotspotTableSize, memory); merge[] = 0; } } this()(Regex!Char program, Stream stream, void[] memory) { re = program; s = stream; initExternalMemory(memory); genCounter = 0; } this(S)(ref ThompsonMatcher!(Char,S) matcher, Bytecode[] piece, Stream stream) { s = stream; re = matcher.re; re.ir = piece; threadSize = matcher.threadSize; merge = matcher.merge; freelist = matcher.freelist; front = matcher.front; index = matcher.index; } auto fwdMatcher()(Bytecode[] piece, size_t counter) { auto m = ThompsonMatcher!(Char, Stream)(this, piece, s); m.genCounter = counter; return m; } auto bwdMatcher()(Bytecode[] piece, size_t counter) { alias BackLooper = typeof(s.loopBack(index)); auto m = ThompsonMatcher!(Char, BackLooper)(this, piece, s.loopBack(index)); m.genCounter = counter; m.next(); return m; } auto dupTo(void[] memory) { typeof(this) tmp = this;//bitblit tmp.initExternalMemory(memory); tmp.genCounter = 0; return tmp; } enum MatchResult{ NoMatch, PartialMatch, Match, } bool match(Group!DataIndex[] matches) { debug(std_regex_matcher) writeln("------------------------------------------"); if(exhausted) { return false; } if(re.flags & RegexInfo.oneShot) { next(); exhausted = true; return matchOneShot(matches)==MatchResult.Match; } static if(kicked) if(!re.kickstart.empty) return matchImpl!(true)(matches); return matchImpl!(false)(matches); } //match the input and fill matches bool matchImpl(bool withSearch)(Group!DataIndex[] matches) { if(!matched && clist.empty) { static if(withSearch) search(); else next(); } else//char in question is fetched in prev call to match { matched = false; } if(!atEnd)//if no char for(;;) { genCounter++; debug(std_regex_matcher) { writefln("Threaded matching threads at %s", s[index..s.lastIndex]); foreach(t; clist[]) { assert(t); writef("pc=%s ",t.pc); write(t.matches); writeln(); } } for(Thread!DataIndex* t = clist.fetch(); t; t = clist.fetch()) { eval!true(t, matches); } if(!matched)//if we already have match no need to push the engine eval!true(createStart(index), matches);//new thread staring at this position else if(nlist.empty) { debug(std_regex_matcher) writeln("Stopped matching before consuming full input"); break;//not a partial match for sure } clist = nlist; nlist = (ThreadList!DataIndex).init; if(clist.tip is null) { static if(withSearch) { if(!search()) break; } else { if(!next()) break; } } else if(!next()) { if (!atEnd) return false; exhausted = true; break; } } genCounter++; //increment also on each end debug(std_regex_matcher) writefln("Threaded matching threads at end"); //try out all zero-width posibilities for(Thread!DataIndex* t = clist.fetch(); t; t = clist.fetch()) { eval!false(t, matches); } if(!matched) eval!false(createStart(index), matches);//new thread starting at end of input if(matched) {//in case NFA found match along the way //and last possible longer alternative ultimately failed s.reset(matches[0].end);//reset to last successful match next();//and reload front character //--- here the exact state of stream was restored --- exhausted = atEnd || !(re.flags & RegexOption.global); //+ empty match advances the input if(!exhausted && matches[0].begin == matches[0].end) next(); } return matched; } /+ handle succesful threads +/ void finish(const(Thread!DataIndex)* t, Group!DataIndex[] matches) { matches.ptr[0..re.ngroup] = t.matches.ptr[0..re.ngroup]; debug(std_regex_matcher) { writef("FOUND pc=%s prog_len=%s", t.pc, re.ir.length); if(!matches.empty) writefln(": %s..%s", matches[0].begin, matches[0].end); foreach(v; matches) writefln("%d .. %d", v.begin, v.end); } matched = true; } /+ match thread against codepoint, cutting trough all 0-width instructions and taking care of control flow, then add it to nlist +/ void eval(bool withInput)(Thread!DataIndex* t, Group!DataIndex[] matches) { ThreadList!DataIndex worklist; debug(std_regex_matcher) writeln("---- Evaluating thread"); for(;;) { debug(std_regex_matcher) { writef("\tpc=%s [", t.pc); foreach(x; worklist[]) writef(" %s ", x.pc); writeln("]"); } switch(re.ir[t.pc].code) { case IR.End: finish(t, matches); matches[0].end = index; //fix endpoint of the whole match recycle(t); //cut off low priority threads recycle(clist); recycle(worklist); debug(std_regex_matcher) writeln("Finished thread ", matches); return; case IR.Wordboundary: dchar back; DataIndex bi; //at start & end of input if(atStart && wordTrie[front]) { t.pc += IRL!(IR.Wordboundary); break; } else if(atEnd && s.loopBack(index).nextChar(back, bi) && wordTrie[back]) { t.pc += IRL!(IR.Wordboundary); break; } else if(s.loopBack(index).nextChar(back, bi)) { bool af = wordTrie[front]; bool ab = wordTrie[back]; if(af ^ ab) { t.pc += IRL!(IR.Wordboundary); break; } } recycle(t); t = worklist.fetch(); if(!t) return; break; case IR.Notwordboundary: dchar back; DataIndex bi; //at start & end of input if(atStart && wordTrie[front]) { recycle(t); t = worklist.fetch(); if(!t) return; break; } else if(atEnd && s.loopBack(index).nextChar(back, bi) && wordTrie[back]) { recycle(t); t = worklist.fetch(); if(!t) return; break; } else if(s.loopBack(index).nextChar(back, bi)) { bool af = wordTrie[front]; bool ab = wordTrie[back] != 0; if(af ^ ab) { recycle(t); t = worklist.fetch(); if(!t) return; break; } } t.pc += IRL!(IR.Wordboundary); break; case IR.Bol: dchar back; DataIndex bi; if(atStart ||( (re.flags & RegexOption.multiline) && s.loopBack(index).nextChar(back,bi) && startOfLine(back, front == '\n'))) { t.pc += IRL!(IR.Bol); } else { recycle(t); t = worklist.fetch(); if(!t) return; } break; case IR.Eol: debug(std_regex_matcher) writefln("EOL (front 0x%x) %s", front, s[index..s.lastIndex]); dchar back; DataIndex bi; //no matching inside \r\n if(atEnd || ((re.flags & RegexOption.multiline) && endOfLine(front, s.loopBack(index).nextChar(back, bi) && back == '\r'))) { t.pc += IRL!(IR.Eol); } else { recycle(t); t = worklist.fetch(); if(!t) return; } break; case IR.InfiniteStart, IR.InfiniteQStart: t.pc += re.ir[t.pc].data + IRL!(IR.InfiniteStart); goto case IR.InfiniteEnd; //both Q and non-Q case IR.RepeatStart, IR.RepeatQStart: t.pc += re.ir[t.pc].data + IRL!(IR.RepeatStart); goto case IR.RepeatEnd; //both Q and non-Q case IR.RepeatEnd: case IR.RepeatQEnd: //len, step, min, max uint len = re.ir[t.pc].data; uint step = re.ir[t.pc+2].raw; uint min = re.ir[t.pc+3].raw; if(t.counter < min) { t.counter += step; t.pc -= len; break; } if(merge[re.ir[t.pc + 1].raw+t.counter] < genCounter) { debug(std_regex_matcher) writefln("A thread(pc=%s) passed there : %s ; GenCounter=%s mergetab=%s", t.pc, index, genCounter, merge[re.ir[t.pc + 1].raw+t.counter] ); merge[re.ir[t.pc + 1].raw+t.counter] = genCounter; } else { debug(std_regex_matcher) writefln("A thread(pc=%s) got merged there : %s ; GenCounter=%s mergetab=%s", t.pc, index, genCounter, merge[re.ir[t.pc + 1].raw+t.counter] ); recycle(t); t = worklist.fetch(); if(!t) return; break; } uint max = re.ir[t.pc+4].raw; if(t.counter < max) { if(re.ir[t.pc].code == IR.RepeatEnd) { //queue out-of-loop thread worklist.insertFront(fork(t, t.pc + IRL!(IR.RepeatEnd), t.counter % step)); t.counter += step; t.pc -= len; } else { //queue into-loop thread worklist.insertFront(fork(t, t.pc - len, t.counter + step)); t.counter %= step; t.pc += IRL!(IR.RepeatEnd); } } else { t.counter %= step; t.pc += IRL!(IR.RepeatEnd); } break; case IR.InfiniteEnd: case IR.InfiniteQEnd: if(merge[re.ir[t.pc + 1].raw+t.counter] < genCounter) { debug(std_regex_matcher) writefln("A thread(pc=%s) passed there : %s ; GenCounter=%s mergetab=%s", t.pc, index, genCounter, merge[re.ir[t.pc + 1].raw+t.counter] ); merge[re.ir[t.pc + 1].raw+t.counter] = genCounter; } else { debug(std_regex_matcher) writefln("A thread(pc=%s) got merged there : %s ; GenCounter=%s mergetab=%s", t.pc, index, genCounter, merge[re.ir[t.pc + 1].raw+t.counter] ); recycle(t); t = worklist.fetch(); if(!t) return; break; } uint len = re.ir[t.pc].data; uint pc1, pc2; //branches to take in priority order if(re.ir[t.pc].code == IR.InfiniteEnd) { pc1 = t.pc - len; pc2 = t.pc + IRL!(IR.InfiniteEnd); } else { pc1 = t.pc + IRL!(IR.InfiniteEnd); pc2 = t.pc - len; } static if(withInput) { worklist.insertFront(fork(t, pc2, t.counter)); t.pc = pc1; } else { worklist.insertFront(fork(t, pc2, t.counter)); t.pc = pc1; } break; case IR.OrEnd: if(merge[re.ir[t.pc + 1].raw+t.counter] < genCounter) { debug(std_regex_matcher) writefln("A thread(pc=%s) passed there : %s ; GenCounter=%s mergetab=%s", t.pc, s[index .. s.lastIndex], genCounter, merge[re.ir[t.pc + 1].raw + t.counter] ); merge[re.ir[t.pc + 1].raw+t.counter] = genCounter; t.pc += IRL!(IR.OrEnd); } else { debug(std_regex_matcher) writefln("A thread(pc=%s) got merged there : %s ; GenCounter=%s mergetab=%s", t.pc, s[index .. s.lastIndex], genCounter, merge[re.ir[t.pc + 1].raw + t.counter] ); recycle(t); t = worklist.fetch(); if(!t) return; } break; case IR.OrStart: t.pc += IRL!(IR.OrStart); goto case; case IR.Option: uint next = t.pc + re.ir[t.pc].data + IRL!(IR.Option); //queue next Option if(re.ir[next].code == IR.Option) { worklist.insertFront(fork(t, next, t.counter)); } t.pc += IRL!(IR.Option); break; case IR.GotoEndOr: t.pc = t.pc + re.ir[t.pc].data + IRL!(IR.GotoEndOr); goto case IR.OrEnd; case IR.GroupStart: uint n = re.ir[t.pc].data; t.matches.ptr[n].begin = index; t.pc += IRL!(IR.GroupStart); break; case IR.GroupEnd: uint n = re.ir[t.pc].data; t.matches.ptr[n].end = index; t.pc += IRL!(IR.GroupEnd); break; case IR.Backref: uint n = re.ir[t.pc].data; Group!DataIndex* source = re.ir[t.pc].localRef ? t.matches.ptr : backrefed.ptr; assert(source); if(source[n].begin == source[n].end)//zero-width Backref! { t.pc += IRL!(IR.Backref); } else static if(withInput) { size_t idx = source[n].begin + t.uopCounter; size_t end = source[n].end; if(s[idx..end].front == front) { import std.utf : stride; t.uopCounter += stride(s[idx..end], 0); if(t.uopCounter + source[n].begin == source[n].end) {//last codepoint t.pc += IRL!(IR.Backref); t.uopCounter = 0; } nlist.insertBack(t); } else recycle(t); t = worklist.fetch(); if(!t) return; break; } else { recycle(t); t = worklist.fetch(); if(!t) return; break; } break; case IR.LookbehindStart: case IR.NeglookbehindStart: uint len = re.ir[t.pc].data; uint ms = re.ir[t.pc + 1].raw, me = re.ir[t.pc + 2].raw; uint end = t.pc + len + IRL!(IR.LookbehindEnd) + IRL!(IR.LookbehindStart); bool positive = re.ir[t.pc].code == IR.LookbehindStart; static if(Stream.isLoopback) auto matcher = fwdMatcher(re.ir[t.pc .. end], subCounters.get(t.pc, 0)); else auto matcher = bwdMatcher(re.ir[t.pc .. end], subCounters.get(t.pc, 0)); matcher.re.ngroup = me - ms; matcher.backrefed = backrefed.empty ? t.matches : backrefed; //backMatch auto mRes = matcher.matchOneShot(t.matches.ptr[ms .. me], IRL!(IR.LookbehindStart)); freelist = matcher.freelist; subCounters[t.pc] = matcher.genCounter; if((mRes == MatchResult.Match) ^ positive) { recycle(t); t = worklist.fetch(); if(!t) return; break; } else t.pc = end; break; case IR.LookaheadStart: case IR.NeglookaheadStart: auto save = index; uint len = re.ir[t.pc].data; uint ms = re.ir[t.pc+1].raw, me = re.ir[t.pc+2].raw; uint end = t.pc+len+IRL!(IR.LookaheadEnd)+IRL!(IR.LookaheadStart); bool positive = re.ir[t.pc].code == IR.LookaheadStart; static if(Stream.isLoopback) auto matcher = bwdMatcher(re.ir[t.pc .. end], subCounters.get(t.pc, 0)); else auto matcher = fwdMatcher(re.ir[t.pc .. end], subCounters.get(t.pc, 0)); matcher.re.ngroup = me - ms; matcher.backrefed = backrefed.empty ? t.matches : backrefed; auto mRes = matcher.matchOneShot(t.matches.ptr[ms .. me], IRL!(IR.LookaheadStart)); freelist = matcher.freelist; subCounters[t.pc] = matcher.genCounter; s.reset(index); next(); if((mRes == MatchResult.Match) ^ positive) { recycle(t); t = worklist.fetch(); if(!t) return; break; } else t.pc = end; break; case IR.LookaheadEnd: case IR.NeglookaheadEnd: case IR.LookbehindEnd: case IR.NeglookbehindEnd: finish(t, matches.ptr[0 .. re.ngroup]); recycle(t); //cut off low priority threads recycle(clist); recycle(worklist); return; case IR.Nop: t.pc += IRL!(IR.Nop); break; static if(withInput) { case IR.OrChar: uint len = re.ir[t.pc].sequence; uint end = t.pc + len; static assert(IRL!(IR.OrChar) == 1); for(; t.pc < end; t.pc++) if(re.ir[t.pc].data == front) break; if(t.pc != end) { t.pc = end; nlist.insertBack(t); } else recycle(t); t = worklist.fetch(); if(!t) return; break; case IR.Char: if(front == re.ir[t.pc].data) { t.pc += IRL!(IR.Char); nlist.insertBack(t); } else recycle(t); t = worklist.fetch(); if(!t) return; break; case IR.Any: t.pc += IRL!(IR.Any); if(!(re.flags & RegexOption.singleline) && (front == '\r' || front == '\n')) recycle(t); else nlist.insertBack(t); t = worklist.fetch(); if(!t) return; break; case IR.CodepointSet: if(re.charsets[re.ir[t.pc].data].scanFor(front)) { t.pc += IRL!(IR.CodepointSet); nlist.insertBack(t); } else { recycle(t); } t = worklist.fetch(); if(!t) return; break; case IR.Trie: if(re.tries[re.ir[t.pc].data][front]) { t.pc += IRL!(IR.Trie); nlist.insertBack(t); } else { recycle(t); } t = worklist.fetch(); if(!t) return; break; default: assert(0, "Unrecognized instruction " ~ re.ir[t.pc].mnemonic); } else { default: recycle(t); t = worklist.fetch(); if(!t) return; } } } } enum uint RestartPc = uint.max; //match the input, evaluating IR without searching MatchResult matchOneShot(Group!DataIndex[] matches, uint startPc = 0) { debug(std_regex_matcher) { writefln("---------------single shot match ----------------- "); } alias evalFn = eval; assert(clist == (ThreadList!DataIndex).init || startPc == RestartPc); // incorrect after a partial match assert(nlist == (ThreadList!DataIndex).init || startPc == RestartPc); if(!atEnd)//if no char { debug(std_regex_matcher) { writefln("-- Threaded matching threads at %s", s[index..s.lastIndex]); } if(startPc!=RestartPc) { auto startT = createStart(index, startPc); genCounter++; evalFn!true(startT, matches); } for(;;) { debug(std_regex_matcher) writeln("\n-- Started iteration of main cycle"); genCounter++; debug(std_regex_matcher) { foreach(t; clist[]) { assert(t); } } for(Thread!DataIndex* t = clist.fetch(); t; t = clist.fetch()) { evalFn!true(t, matches); } if(nlist.empty) { debug(std_regex_matcher) writeln("Stopped matching before consuming full input"); break;//not a partial match for sure } clist = nlist; nlist = (ThreadList!DataIndex).init; if(!next()) { if (!atEnd) return MatchResult.PartialMatch; break; } debug(std_regex_matcher) writeln("-- Ended iteration of main cycle\n"); } } genCounter++; //increment also on each end debug(std_regex_matcher) writefln("-- Matching threads at end"); //try out all zero-width posibilities for(Thread!DataIndex* t = clist.fetch(); t; t = clist.fetch()) { evalFn!false(t, matches); } if(!matched) evalFn!false(createStart(index, startPc), matches); return (matched?MatchResult.Match:MatchResult.NoMatch); } //get a dirty recycled Thread Thread!DataIndex* allocate() { assert(freelist, "not enough preallocated memory"); Thread!DataIndex* t = freelist; freelist = freelist.next; return t; } //link memory into a free list of Threads void prepareFreeList(size_t size, ref void[] memory) { void[] mem = memory[0 .. threadSize*size]; memory = memory[threadSize * size .. $]; freelist = cast(Thread!DataIndex*)&mem[0]; size_t i; for(i = threadSize; i < threadSize*size; i += threadSize) (cast(Thread!DataIndex*)&mem[i-threadSize]).next = cast(Thread!DataIndex*)&mem[i]; (cast(Thread!DataIndex*)&mem[i-threadSize]).next = null; } //dispose a thread void recycle(Thread!DataIndex* t) { t.next = freelist; freelist = t; } //dispose list of threads void recycle(ref ThreadList!DataIndex list) { if(list.tip) { // just put this head-tail list in front of freelist list.toe.next = freelist; freelist = list.tip; list = list.init; } } //creates a copy of master thread with given pc Thread!DataIndex* fork(Thread!DataIndex* master, uint pc, uint counter) { auto t = allocate(); t.matches.ptr[0..re.ngroup] = master.matches.ptr[0..re.ngroup]; t.pc = pc; t.counter = counter; t.uopCounter = 0; return t; } //creates a start thread Thread!DataIndex* createStart(DataIndex index, uint pc = 0) { auto t = allocate(); t.matches.ptr[0..re.ngroup] = (Group!DataIndex).init; t.matches[0].begin = index; t.pc = pc; t.counter = 0; t.uopCounter = 0; return t; } } ldc-1.1.0-beta3-src/runtime/phobos/std/regex/internal/generator.d0000664000175000017500000001430712776215007022774 0ustar kaikai/* Generators - components that generate strings for a given regex pattern. For the moment undocumented, and is subject to change. */ module std.regex.internal.generator; /* Useful utility for self-testing, an infinite range of string samples that _have_ to match given compiled regex. Caveats: supports only a simple subset of bytecode. */ @trusted private struct SampleGenerator(Char) { import std.regex.internal.ir; import std.array, std.format, std.utf, std.random; Regex!Char re; Appender!(char[]) app; uint limit, seed; Xorshift gen; //generator for pattern r, with soft maximum of threshold elements //and a given random seed this(ref Regex!Char r, uint threshold, uint randomSeed) { re = r; limit = threshold; seed = randomSeed; app = appender!(Char[])(); compose(); } uint rand(uint x) { uint r = gen.front % x; gen.popFront(); return r; } void compose() { uint pc = 0, counter = 0, dataLenOld = uint.max; for(;;) { switch(re.ir[pc].code) { case IR.Char: formattedWrite(app,"%s", cast(dchar)re.ir[pc].data); pc += IRL!(IR.Char); break; case IR.OrChar: uint len = re.ir[pc].sequence; formattedWrite(app, "%s", cast(dchar)re.ir[pc + rand(len)].data); pc += len; break; case IR.CodepointSet: case IR.Trie: auto set = re.charsets[re.ir[pc].data]; auto x = rand(cast(uint)set.byInterval.length); auto y = rand(set.byInterval[x].b - set.byInterval[x].a); formattedWrite(app, "%s", cast(dchar)(set.byInterval[x].a+y)); pc += IRL!(IR.CodepointSet); break; case IR.Any: uint x; do { x = rand(0x11_000); }while(x == '\r' || x == '\n' || !isValidDchar(x)); formattedWrite(app, "%s", cast(dchar)x); pc += IRL!(IR.Any); break; case IR.GotoEndOr: pc += IRL!(IR.GotoEndOr)+re.ir[pc].data; assert(re.ir[pc].code == IR.OrEnd); goto case; case IR.OrEnd: pc += IRL!(IR.OrEnd); break; case IR.OrStart: pc += IRL!(IR.OrStart); goto case; case IR.Option: uint next = pc + re.ir[pc].data + IRL!(IR.Option); uint nOpt = 0; //queue next Option while(re.ir[next].code == IR.Option) { nOpt++; next += re.ir[next].data + IRL!(IR.Option); } nOpt++; nOpt = rand(nOpt); for(;nOpt; nOpt--) { pc += re.ir[pc].data + IRL!(IR.Option); } assert(re.ir[pc].code == IR.Option); pc += IRL!(IR.Option); break; case IR.RepeatStart:case IR.RepeatQStart: pc += IRL!(IR.RepeatStart)+re.ir[pc].data; goto case IR.RepeatEnd; case IR.RepeatEnd: case IR.RepeatQEnd: uint len = re.ir[pc].data; uint step = re.ir[pc+2].raw; uint min = re.ir[pc+3].raw; if(counter < min) { counter += step; pc -= len; break; } uint max = re.ir[pc+4].raw; if(counter < max) { if(app.data.length < limit && rand(3) > 0) { pc -= len; counter += step; } else { counter = counter%step; pc += IRL!(IR.RepeatEnd); } } else { counter = counter%step; pc += IRL!(IR.RepeatEnd); } break; case IR.InfiniteStart, IR.InfiniteQStart: pc += re.ir[pc].data + IRL!(IR.InfiniteStart); goto case IR.InfiniteEnd; //both Q and non-Q case IR.InfiniteEnd: case IR.InfiniteQEnd: uint len = re.ir[pc].data; if(app.data.length == dataLenOld) { pc += IRL!(IR.InfiniteEnd); break; } dataLenOld = cast(uint)app.data.length; if(app.data.length < limit && rand(3) > 0) pc = pc - len; else pc = pc + IRL!(IR.InfiniteEnd); break; case IR.GroupStart, IR.GroupEnd: pc += IRL!(IR.GroupStart); break; case IR.Bol, IR.Wordboundary, IR.Notwordboundary: case IR.LookaheadStart, IR.NeglookaheadStart, IR.LookbehindStart, IR.NeglookbehindStart: default: return; } } } @property Char[] front() { return app.data; } @property empty(){ return false; } void popFront() { app.shrinkTo(0); compose(); } } unittest { import std.range, std.regex; auto re = regex(`P[a-z]{3,}q`); auto gen = SampleGenerator!char(re, 20, 3141592); static assert(isInputRange!(typeof(gen))); //@@@BUG@@@ somehow gen.take(1_000) doesn't work foreach(v; take(gen, 1_000)) assert(v.match(re)); } ldc-1.1.0-beta3-src/runtime/phobos/std/regex/internal/ir.d0000664000175000017500000005621712776215007021426 0ustar kaikai/* Implementation of std.regex IR, an intermediate representation of a regular expression pattern. This is a common ground between frontend regex component (parser) and backend components - generators, matchers and other "filters". */ module std.regex.internal.ir; package(std.regex): import std.exception, std.uni, std.meta, std.traits, std.range; // just a common trait, may be moved elsewhere alias BasicElementOf(Range) = Unqual!(ElementEncodingType!Range); // heuristic value determines maximum CodepointSet length suitable for linear search enum maxCharsetUsed = 6; // another variable to tweak behavior of caching generated Tries for character classes enum maxCachedTries = 8; alias Trie = CodepointSetTrie!(13, 8); alias makeTrie = codepointSetTrie!(13, 8); Trie[CodepointSet] trieCache; //accessor with caching @trusted Trie getTrie(CodepointSet set) {// @@@BUG@@@ 6357 almost all properties of AA are not @safe if(__ctfe || maxCachedTries == 0) return makeTrie(set); else { auto p = set in trieCache; if(p) return *p; if(trieCache.length == maxCachedTries) { // flush entries in trieCache trieCache = null; } return (trieCache[set] = makeTrie(set)); } } @trusted auto memoizeExpr(string expr)() { if(__ctfe) return mixin(expr); alias T = typeof(mixin(expr)); static T slot; static bool initialized; if(!initialized) { slot = mixin(expr); initialized = true; } return slot; } //property for \w character class @property CodepointSet wordCharacter() { return memoizeExpr!("unicode.Alphabetic | unicode.Mn | unicode.Mc | unicode.Me | unicode.Nd | unicode.Pc")(); } @property Trie wordTrie() { return memoizeExpr!("makeTrie(wordCharacter)")(); } // some special Unicode white space characters private enum NEL = '\u0085', LS = '\u2028', PS = '\u2029'; //Regular expression engine/parser options: // global - search all nonoverlapping matches in input // casefold - case insensitive matching, do casefolding on match in unicode mode // freeform - ignore whitespace in pattern, to match space use [ ] or \s // multiline - switch ^, $ detect start and end of linesinstead of just start and end of input enum RegexOption: uint { global = 0x1, casefold = 0x2, freeform = 0x4, nonunicode = 0x8, multiline = 0x10, singleline = 0x20 } //do not reorder this list alias RegexOptionNames = AliasSeq!('g', 'i', 'x', 'U', 'm', 's'); static assert( RegexOption.max < 0x80); // flags that allow guide execution of engine enum RegexInfo : uint { oneShot = 0x80 } // IR bit pattern: 0b1_xxxxx_yy // where yy indicates class of instruction, xxxxx for actual operation code // 00: atom, a normal instruction // 01: open, opening of a group, has length of contained IR in the low bits // 10: close, closing of a group, has length of contained IR in the low bits // 11 unused // // Loops with Q (non-greedy, with ? mark) must have the same size / other properties as non Q version // Possible changes: //* merge group, option, infinite/repeat start (to never copy during parsing of (a|b){1,2}) //* reorganize groups to make n args easier to find, or simplify the check for groups of similar ops // (like lookaround), or make it easier to identify hotspots. enum IR:uint { Char = 0b1_00000_00, //a character Any = 0b1_00001_00, //any character CodepointSet = 0b1_00010_00, //a most generic CodepointSet [...] Trie = 0b1_00011_00, //CodepointSet implemented as Trie //match with any of a consecutive OrChar's in this sequence //(used for case insensitive match) //OrChar holds in upper two bits of data total number of OrChars in this _sequence_ //the drawback of this representation is that it is difficult // to detect a jump in the middle of it OrChar = 0b1_00100_00, Nop = 0b1_00101_00, //no operation (padding) End = 0b1_00110_00, //end of program Bol = 0b1_00111_00, //beginning of a string ^ Eol = 0b1_01000_00, //end of a string $ Wordboundary = 0b1_01001_00, //boundary of a word Notwordboundary = 0b1_01010_00, //not a word boundary Backref = 0b1_01011_00, //backreference to a group (that has to be pinned, i.e. locally unique) (group index) GroupStart = 0b1_01100_00, //start of a group (x) (groupIndex+groupPinning(1bit)) GroupEnd = 0b1_01101_00, //end of a group (x) (groupIndex+groupPinning(1bit)) Option = 0b1_01110_00, //start of an option within an alternation x | y (length) GotoEndOr = 0b1_01111_00, //end of an option (length of the rest) //... any additional atoms here OrStart = 0b1_00000_01, //start of alternation group (length) OrEnd = 0b1_00000_10, //end of the or group (length,mergeIndex) //with this instruction order //bit mask 0b1_00001_00 could be used to test/set greediness InfiniteStart = 0b1_00001_01, //start of an infinite repetition x* (length) InfiniteEnd = 0b1_00001_10, //end of infinite repetition x* (length,mergeIndex) InfiniteQStart = 0b1_00010_01, //start of a non eager infinite repetition x*? (length) InfiniteQEnd = 0b1_00010_10, //end of non eager infinite repetition x*? (length,mergeIndex) RepeatStart = 0b1_00011_01, //start of a {n,m} repetition (length) RepeatEnd = 0b1_00011_10, //end of x{n,m} repetition (length,step,minRep,maxRep) RepeatQStart = 0b1_00100_01, //start of a non eager x{n,m}? repetition (length) RepeatQEnd = 0b1_00100_10, //end of non eager x{n,m}? repetition (length,step,minRep,maxRep) // LookaheadStart = 0b1_00101_01, //begin of the lookahead group (length) LookaheadEnd = 0b1_00101_10, //end of a lookahead group (length) NeglookaheadStart = 0b1_00110_01, //start of a negative lookahead (length) NeglookaheadEnd = 0b1_00110_10, //end of a negative lookahead (length) LookbehindStart = 0b1_00111_01, //start of a lookbehind (length) LookbehindEnd = 0b1_00111_10, //end of a lookbehind (length) NeglookbehindStart= 0b1_01000_01, //start of a negative lookbehind (length) NeglookbehindEnd = 0b1_01000_10, //end of negative lookbehind (length) } //a shorthand for IR length - full length of specific opcode evaluated at compile time template IRL(IR code) { enum uint IRL = lengthOfIR(code); } static assert (IRL!(IR.LookaheadStart) == 3); //how many parameters follow the IR, should be optimized fixing some IR bits int immediateParamsIR(IR i){ switch (i){ case IR.OrEnd,IR.InfiniteEnd,IR.InfiniteQEnd: return 1; case IR.RepeatEnd, IR.RepeatQEnd: return 4; case IR.LookaheadStart, IR.NeglookaheadStart, IR.LookbehindStart, IR.NeglookbehindStart: return 2; default: return 0; } } //full length of IR instruction inlcuding all parameters that might follow it int lengthOfIR(IR i) { return 1 + immediateParamsIR(i); } //full length of the paired IR instruction inlcuding all parameters that might follow it int lengthOfPairedIR(IR i) { return 1 + immediateParamsIR(pairedIR(i)); } //if the operation has a merge point (this relies on the order of the ops) bool hasMerge(IR i) { return (i&0b11)==0b10 && i <= IR.RepeatQEnd; } //is an IR that opens a "group" bool isStartIR(IR i) { return (i&0b11)==0b01; } //is an IR that ends a "group" bool isEndIR(IR i) { return (i&0b11)==0b10; } //is a standalone IR bool isAtomIR(IR i) { return (i&0b11)==0b00; } //makes respective pair out of IR i, swapping start/end bits of instruction IR pairedIR(IR i) { assert(isStartIR(i) || isEndIR(i)); return cast(IR)(i ^ 0b11); } //encoded IR instruction struct Bytecode { uint raw; //natural constraints enum maxSequence = 2+4; enum maxData = 1<<22; enum maxRaw = 1<<31; this(IR code, uint data) { assert(data < (1<<22) && code < 256); raw = code<<24 | data; } this(IR code, uint data, uint seq) { assert(data < (1<<22) && code < 256 ); assert(seq >= 2 && seq < maxSequence); raw = code << 24 | (seq - 2)<<22 | data; } //store raw data static Bytecode fromRaw(uint data) { Bytecode t; t.raw = data; return t; } //bit twiddling helpers //0-arg template due to @@@BUG@@@ 10985 @property uint data()() const { return raw & 0x003f_ffff; } //ditto //0-arg template due to @@@BUG@@@ 10985 @property uint sequence()() const { return 2 + (raw >> 22 & 0x3); } //ditto //0-arg template due to @@@BUG@@@ 10985 @property IR code()() const { return cast(IR)(raw>>24); } //ditto @property bool hotspot() const { return hasMerge(code); } //test the class of this instruction @property bool isAtom() const { return isAtomIR(code); } //ditto @property bool isStart() const { return isStartIR(code); } //ditto @property bool isEnd() const { return isEndIR(code); } //number of arguments for this instruction @property int args() const { return immediateParamsIR(code); } //mark this GroupStart or GroupEnd as referenced in backreference void setBackrefence() { assert(code == IR.GroupStart || code == IR.GroupEnd); raw = raw | 1 << 23; } //is referenced @property bool backreference() const { assert(code == IR.GroupStart || code == IR.GroupEnd); return cast(bool)(raw & 1 << 23); } //mark as local reference (for backrefs in lookarounds) void setLocalRef() { assert(code == IR.Backref); raw = raw | 1 << 23; } //is a local ref @property bool localRef() const { assert(code == IR.Backref); return cast(bool)(raw & 1 << 23); } //human readable name of instruction @trusted @property string mnemonic()() const {//@@@BUG@@@ to is @system import std.conv; return to!string(code); } //full length of instruction @property uint length() const { return lengthOfIR(code); } //full length of respective start/end of this instruction @property uint pairedLength() const { return lengthOfPairedIR(code); } //returns bytecode of paired instruction (assuming this one is start or end) @property Bytecode paired() const {//depends on bit and struct layout order assert(isStart || isEnd); return Bytecode.fromRaw(raw ^ 0b11 << 24); } //gets an index into IR block of the respective pair uint indexOfPair(uint pc) const { assert(isStart || isEnd); return isStart ? pc + data + length : pc - data - lengthOfPairedIR(code); } } static assert(Bytecode.sizeof == 4); //index entry structure for name --> number of submatch struct NamedGroup { string name; uint group; } //holds pair of start-end markers for a submatch struct Group(DataIndex) { DataIndex begin, end; @trusted string toString()() const { import std.format; auto a = appender!string(); formattedWrite(a, "%s..%s", begin, end); return a.data; } } //debugging tool, prints out instruction along with opcodes @trusted string disassemble(in Bytecode[] irb, uint pc, in NamedGroup[] dict=[]) { import std.array, std.format; auto output = appender!string(); formattedWrite(output,"%s", irb[pc].mnemonic); switch(irb[pc].code) { case IR.Char: formattedWrite(output, " %s (0x%x)",cast(dchar)irb[pc].data, irb[pc].data); break; case IR.OrChar: formattedWrite(output, " %s (0x%x) seq=%d", cast(dchar)irb[pc].data, irb[pc].data, irb[pc].sequence); break; case IR.RepeatStart, IR.InfiniteStart, IR.Option, IR.GotoEndOr, IR.OrStart: //forward-jump instructions uint len = irb[pc].data; formattedWrite(output, " pc=>%u", pc+len+IRL!(IR.RepeatStart)); break; case IR.RepeatEnd, IR.RepeatQEnd: //backward-jump instructions uint len = irb[pc].data; formattedWrite(output, " pc=>%u min=%u max=%u step=%u", pc - len, irb[pc + 3].raw, irb[pc + 4].raw, irb[pc + 2].raw); break; case IR.InfiniteEnd, IR.InfiniteQEnd, IR.OrEnd: //ditto uint len = irb[pc].data; formattedWrite(output, " pc=>%u", pc-len); break; case IR.LookaheadEnd, IR.NeglookaheadEnd: //ditto uint len = irb[pc].data; formattedWrite(output, " pc=>%u", pc-len); break; case IR.GroupStart, IR.GroupEnd: uint n = irb[pc].data; string name; foreach(v;dict) if(v.group == n) { name = "'"~v.name~"'"; break; } formattedWrite(output, " %s #%u " ~ (irb[pc].backreference ? "referenced" : ""), name, n); break; case IR.LookaheadStart, IR.NeglookaheadStart, IR.LookbehindStart, IR.NeglookbehindStart: uint len = irb[pc].data; uint start = irb[pc+1].raw, end = irb[pc+2].raw; formattedWrite(output, " pc=>%u [%u..%u]", pc + len + IRL!(IR.LookaheadStart), start, end); break; case IR.Backref: case IR.CodepointSet: case IR.Trie: uint n = irb[pc].data; formattedWrite(output, " %u", n); if(irb[pc].code == IR.Backref) formattedWrite(output, " %s", irb[pc].localRef ? "local" : "global"); break; default://all data-free instructions } if(irb[pc].hotspot) formattedWrite(output, " Hotspot %u", irb[pc+1].raw); return output.data; } //disassemble the whole chunk @trusted void printBytecode()(in Bytecode[] slice, in NamedGroup[] dict=[]) { import std.stdio; for(uint pc=0; pc= end; } @property size_t length() { return end - start; } alias opDollar = length; @property NamedGroupRange save() { return NamedGroupRange(groups, start, end); } void popFront() { assert(!empty); start++; } void popBack() { assert(!empty); end--; } string opIndex()(size_t i) { assert(start + i < end, "Requested named group is out of range."); return groups[start+i].name; } NamedGroupRange opSlice(size_t low, size_t high) { assert(low <= high); assert(start + high <= end); return NamedGroupRange(groups, start + low, start + high); } NamedGroupRange opSlice() { return this.save; } } return NamedGroupRange(dict, 0, dict.length); } package(std.regex): import std.regex.internal.kickstart : Kickstart; //TODO: get rid of this dependency NamedGroup[] dict; //maps name -> user group number uint ngroup; //number of internal groups uint maxCounterDepth; //max depth of nested {n,m} repetitions uint hotspotTableSize; //number of entries in merge table uint threadCount; uint flags; //global regex flags public const(Trie)[] tries; // uint[] backrefed; //bit array of backreferenced submatches Kickstart!Char kickstart; //bit access helper uint isBackref(uint n) { if(n/32 >= backrefed.length) return 0; return backrefed[n / 32] & (1 << (n & 31)); } //check if searching is not needed void checkIfOneShot() { if(flags & RegexOption.multiline) return; L_CheckLoop: for(uint i = 0; i < ir.length; i += ir[i].length) { switch(ir[i].code) { case IR.Bol: flags |= RegexInfo.oneShot; break L_CheckLoop; case IR.GroupStart, IR.GroupEnd, IR.Eol, IR.Wordboundary, IR.Notwordboundary: break; default: break L_CheckLoop; } } } //print out disassembly a program's IR @trusted debug(std_regex_parser) void print() const {//@@@BUG@@@ write is system for(uint i = 0; i < ir.length; i += ir[i].length) { writefln("%d\t%s ", i, disassemble(ir, i, dict)); } writeln("Total merge table size: ", hotspotTableSize); writeln("Max counter nesting depth: ", maxCounterDepth); } } //@@@BUG@@@ (unreduced) - public makes it inaccessible in std.regex.package (!) /*public*/ struct StaticRegex(Char) { package(std.regex): import std.regex.internal.backtracking; alias Matcher = BacktrackingMatcher!(true); alias MatchFn = bool function(ref Matcher!Char) @trusted; MatchFn nativeFn; public: Regex!Char _regex; alias _regex this; this(Regex!Char re, MatchFn fn) { _regex = re; nativeFn = fn; } } // The stuff below this point is temporarrily part of IR module // but may need better place in the future (all internals) package(std.regex): //Simple UTF-string abstraction compatible with stream interface struct Input(Char) if(is(Char :dchar)) { import std.utf; alias DataIndex = size_t; enum { isLoopback = false }; alias String = const(Char)[]; String _origin; size_t _index; //constructs Input object out of plain string this(String input, size_t idx = 0) { _origin = input; _index = idx; } //codepoint at current stream position bool nextChar(ref dchar res, ref size_t pos) { pos = _index; if(_index == _origin.length) return false; res = std.utf.decode(_origin, _index); return true; } @property bool atEnd(){ return _index == _origin.length; } bool search(Kickstart)(ref Kickstart kick, ref dchar res, ref size_t pos) { size_t idx = kick.search(_origin, _index); _index = idx; return nextChar(res, pos); } //index of at End position @property size_t lastIndex(){ return _origin.length; } //support for backtracker engine, might not be present void reset(size_t index){ _index = index; } String opSlice(size_t start, size_t end){ return _origin[start..end]; } struct BackLooper { alias DataIndex = size_t; enum { isLoopback = true }; String _origin; size_t _index; this(Input input, size_t index) { _origin = input._origin; _index = index; } @trusted bool nextChar(ref dchar res,ref size_t pos) { pos = _index; if(_index == 0) return false; res = _origin[0.._index].back; _index -= std.utf.strideBack(_origin, _index); return true; } @property atEnd(){ return _index == 0 || _index == std.utf.strideBack(_origin, _index); } auto loopBack(size_t index){ return Input(_origin, index); } //support for backtracker engine, might not be present //void reset(size_t index){ _index = index ? index-std.utf.strideBack(_origin, index) : 0; } void reset(size_t index){ _index = index; } String opSlice(size_t start, size_t end){ return _origin[end..start]; } //index of at End position @property size_t lastIndex(){ return 0; } } auto loopBack(size_t index){ return BackLooper(this, index); } } //both helpers below are internal, on its own are quite "explosive" //unsafe, no initialization of elements @system T[] mallocArray(T)(size_t len) { import core.stdc.stdlib; return (cast(T*)malloc(len * T.sizeof))[0 .. len]; } //very unsafe, no initialization @system T[] arrayInChunk(T)(size_t len, ref void[] chunk) { auto ret = (cast(T*)chunk.ptr)[0..len]; chunk = chunk[len * T.sizeof .. $]; return ret; } // @trusted uint lookupNamedGroup(String)(NamedGroup[] dict, String name) {//equal is @system? import std.conv; import std.algorithm : map, equal; auto fnd = assumeSorted!"cmp(a,b) < 0"(map!"a.name"(dict)).lowerBound(name).length; enforce(fnd < dict.length && equal(dict[fnd].name, name), text("no submatch named ", name)); return dict[fnd].group; } //whether ch is one of unicode newline sequences //0-arg template due to @@@BUG@@@ 10985 bool endOfLine()(dchar front, bool seenCr) { return ((front == '\n') ^ seenCr) || front == '\r' || front == NEL || front == LS || front == PS; } // //0-arg template due to @@@BUG@@@ 10985 bool startOfLine()(dchar back, bool seenNl) { return ((back == '\r') ^ seenNl) || back == '\n' || back == NEL || back == LS || back == PS; } //Test if bytecode starting at pc in program 're' can match given codepoint //Returns: 0 - can't tell, -1 if doesn't match int quickTestFwd(RegEx)(uint pc, dchar front, const ref RegEx re) { static assert(IRL!(IR.OrChar) == 1);//used in code processing IR.OrChar for(;;) switch(re.ir[pc].code) { case IR.OrChar: uint len = re.ir[pc].sequence; uint end = pc + len; if(re.ir[pc].data != front && re.ir[pc+1].data != front) { for(pc = pc+2; pc < end; pc++) if(re.ir[pc].data == front) break; if(pc == end) return -1; } return 0; case IR.Char: if(front == re.ir[pc].data) return 0; else return -1; case IR.Any: return 0; case IR.CodepointSet: if(re.charsets[re.ir[pc].data].scanFor(front)) return 0; else return -1; case IR.GroupStart, IR.GroupEnd: pc += IRL!(IR.GroupStart); break; case IR.Trie: if(re.tries[re.ir[pc].data][front]) return 0; else return -1; default: return 0; } } ///Exception object thrown in case of errors during regex compilation. public class RegexException : Exception { mixin basicExceptionCtors; } ldc-1.1.0-beta3-src/runtime/phobos/std/regex/internal/kickstart.d0000664000175000017500000004655612776215007023020 0ustar kaikai/* Kickstart is a coarse-grained "filter" engine that finds likely matches to be verified by full-blown matcher. */ module std.regex.internal.kickstart; package(std.regex): import std.regex.internal.ir; import std.algorithm, std.range, std.utf; //utility for shiftOr, returns a minimum number of bytes to test in a Char uint effectiveSize(Char)() { static if(is(Char == char)) return 1; else static if(is(Char == wchar)) return 2; else static if(is(Char == dchar)) return 3; else static assert(0); } /* Kickstart engine using ShiftOr algorithm, a bit parallel technique for inexact string searching. */ struct ShiftOr(Char) { private: uint[] table; uint fChar; uint n_length; enum charSize = effectiveSize!Char(); //maximum number of chars in CodepointSet to process enum uint charsetThreshold = 32_000; static struct ShiftThread { uint[] tab; uint mask; uint idx; uint pc, counter, hops; this(uint newPc, uint newCounter, uint[] table) { pc = newPc; counter = newCounter; mask = 1; idx = 0; hops = 0; tab = table; } void setMask(uint idx, uint mask) { tab[idx] |= mask; } void setInvMask(uint idx, uint mask) { tab[idx] &= ~mask; } void set(alias setBits = setInvMask)(dchar ch) { static if(charSize == 3) { uint val = ch, tmask = mask; setBits(val&0xFF, tmask); tmask <<= 1; val >>= 8; setBits(val&0xFF, tmask); tmask <<= 1; val >>= 8; assert(val <= 0x10); setBits(val, tmask); tmask <<= 1; } else { Char[dchar.sizeof/Char.sizeof] buf; uint tmask = mask; size_t total = encode(buf, ch); for(size_t i = 0; i < total; i++, tmask<<=1) { static if(charSize == 1) setBits(buf[i], tmask); else static if(charSize == 2) { setBits(buf[i]&0xFF, tmask); tmask <<= 1; setBits(buf[i]>>8, tmask); } } } } void add(dchar ch){ return set!setInvMask(ch); } void advance(uint s) { mask <<= s; idx += s; } @property bool full(){ return !mask; } } static ShiftThread fork(ShiftThread t, uint newPc, uint newCounter) { ShiftThread nt = t; nt.pc = newPc; nt.counter = newCounter; return nt; } @trusted static ShiftThread fetch(ref ShiftThread[] worklist) { auto t = worklist[$-1]; worklist.length -= 1; if(!__ctfe) cast(void)worklist.assumeSafeAppend(); return t; } static uint charLen(uint ch) { assert(ch <= 0x10FFFF); return codeLength!Char(cast(dchar)ch)*charSize; } public: @trusted this(ref Regex!Char re, uint[] memory) { import std.conv; assert(memory.length == 256); fChar = uint.max; L_FindChar: for(size_t i = 0;;) { switch(re.ir[i].code) { case IR.Char: fChar = re.ir[i].data; static if(charSize != 3) { Char[dchar.sizeof/Char.sizeof] buf; encode(buf, fChar); fChar = buf[0]; } fChar = fChar & 0xFF; break L_FindChar; case IR.GroupStart, IR.GroupEnd: i += IRL!(IR.GroupStart); break; case IR.Bol, IR.Wordboundary, IR.Notwordboundary: i += IRL!(IR.Bol); break; default: break L_FindChar; } } table = memory; table[] = uint.max; ShiftThread[] trs; ShiftThread t = ShiftThread(0, 0, table); //locate first fixed char if any n_length = 32; for(;;) { L_Eval_Thread: for(;;) { switch(re.ir[t.pc].code) { case IR.Char: uint s = charLen(re.ir[t.pc].data); if(t.idx+s > n_length) goto L_StopThread; t.add(re.ir[t.pc].data); t.advance(s); t.pc += IRL!(IR.Char); break; case IR.OrChar://assumes IRL!(OrChar) == 1 uint len = re.ir[t.pc].sequence; uint end = t.pc + len; uint[Bytecode.maxSequence] s; uint numS; for(uint i = 0; i < len; i++) { auto x = charLen(re.ir[t.pc+i].data); if(countUntil(s[0..numS], x) < 0) s[numS++] = x; } for(uint i = t.pc; i < end; i++) { t.add(re.ir[i].data); } for(uint i = 0; i < numS; i++) { auto tx = fork(t, t.pc + len, t.counter); if(tx.idx + s[i] <= n_length) { tx.advance(s[i]); trs ~= tx; } } if(!trs.empty) t = fetch(trs); else goto L_StopThread; break; case IR.CodepointSet: case IR.Trie: auto set = re.charsets[re.ir[t.pc].data]; uint[4] s; uint numS; static if(charSize == 3) { s[0] = charSize; numS = 1; } else { static if(charSize == 1) static immutable codeBounds = [0x0, 0x7F, 0x80, 0x7FF, 0x800, 0xFFFF, 0x10000, 0x10FFFF]; else //== 2 static immutable codeBounds = [0x0, 0xFFFF, 0x10000, 0x10FFFF]; uint[] arr = new uint[set.byInterval.length * 2]; size_t ofs = 0; foreach(ival; set.byInterval) { arr[ofs++] = ival.a; arr[ofs++] = ival.b; } auto srange = assumeSorted!"a <= b"(arr); for(uint i = 0; i < codeBounds.length/2; i++) { auto start = srange.lowerBound(codeBounds[2*i]).length; auto end = srange.lowerBound(codeBounds[2*i+1]).length; if(end > start || (end == start && (end & 1))) s[numS++] = (i+1)*charSize; } } if(numS == 0 || t.idx + s[numS-1] > n_length) goto L_StopThread; auto chars = set.length; if(chars > charsetThreshold) goto L_StopThread; foreach(ch; set.byCodepoint) { //avoid surrogate pairs if(0xD800 <= ch && ch <= 0xDFFF) continue; t.add(ch); } for(uint i = 0; i < numS; i++) { auto tx = fork(t, t.pc + IRL!(IR.CodepointSet), t.counter); tx.advance(s[i]); trs ~= tx; } if(!trs.empty) t = fetch(trs); else goto L_StopThread; break; case IR.Any: goto L_StopThread; case IR.GotoEndOr: t.pc += IRL!(IR.GotoEndOr)+re.ir[t.pc].data; assert(re.ir[t.pc].code == IR.OrEnd); goto case; case IR.OrEnd: t.pc += IRL!(IR.OrEnd); break; case IR.OrStart: t.pc += IRL!(IR.OrStart); goto case; case IR.Option: uint next = t.pc + re.ir[t.pc].data + IRL!(IR.Option); //queue next Option if(re.ir[next].code == IR.Option) { trs ~= fork(t, next, t.counter); } t.pc += IRL!(IR.Option); break; case IR.RepeatStart:case IR.RepeatQStart: t.pc += IRL!(IR.RepeatStart)+re.ir[t.pc].data; goto case IR.RepeatEnd; case IR.RepeatEnd: case IR.RepeatQEnd: uint len = re.ir[t.pc].data; uint step = re.ir[t.pc+2].raw; uint min = re.ir[t.pc+3].raw; if(t.counter < min) { t.counter += step; t.pc -= len; break; } uint max = re.ir[t.pc+4].raw; if(t.counter < max) { trs ~= fork(t, t.pc - len, t.counter + step); t.counter = t.counter%step; t.pc += IRL!(IR.RepeatEnd); } else { t.counter = t.counter%step; t.pc += IRL!(IR.RepeatEnd); } break; case IR.InfiniteStart, IR.InfiniteQStart: t.pc += re.ir[t.pc].data + IRL!(IR.InfiniteStart); goto case IR.InfiniteEnd; //both Q and non-Q case IR.InfiniteEnd: case IR.InfiniteQEnd: uint len = re.ir[t.pc].data; uint pc1, pc2; //branches to take in priority order if(++t.hops == 32) goto L_StopThread; pc1 = t.pc + IRL!(IR.InfiniteEnd); pc2 = t.pc - len; trs ~= fork(t, pc2, t.counter); t.pc = pc1; break; case IR.GroupStart, IR.GroupEnd: t.pc += IRL!(IR.GroupStart); break; case IR.Bol, IR.Wordboundary, IR.Notwordboundary: t.pc += IRL!(IR.Bol); break; case IR.LookaheadStart, IR.NeglookaheadStart, IR.LookbehindStart, IR.NeglookbehindStart: t.pc += IRL!(IR.LookaheadStart) + IRL!(IR.LookaheadEnd) + re.ir[t.pc].data; break; default: L_StopThread: assert(re.ir[t.pc].code >= 0x80, text(re.ir[t.pc].code)); debug (fred_search) writeln("ShiftOr stumbled on ",re.ir[t.pc].mnemonic); n_length = min(t.idx, n_length); break L_Eval_Thread; } } if(trs.empty) break; t = fetch(trs); } debug(std_regex_search) { writeln("Min length: ", n_length); } } @property bool empty() const { return n_length == 0; } @property uint length() const{ return n_length/charSize; } // lookup compatible bit pattern in haystack, return starting index // has a useful trait: if supplied with valid UTF indexes, // returns only valid UTF indexes // (that given the haystack in question is valid UTF string) @trusted size_t search(const(Char)[] haystack, size_t idx) {//@BUG: apparently assumes little endian machines import std.conv, core.stdc.string; assert(!empty); auto p = cast(const(ubyte)*)(haystack.ptr+idx); uint state = uint.max; uint limit = 1u<<(n_length - 1u); debug(std_regex_search) writefln("Limit: %32b",limit); if(fChar != uint.max) { const(ubyte)* end = cast(ubyte*)(haystack.ptr + haystack.length); const orginalAlign = cast(size_t)p & (Char.sizeof-1); while(p != end) { if(!~state) {//speed up seeking first matching place for(;;) { assert(p <= end, text(p," vs ", end)); p = cast(ubyte*)memchr(p, fChar, end - p); if(!p) return haystack.length; if((cast(size_t)p & (Char.sizeof-1)) == orginalAlign) break; if(++p == end) return haystack.length; } state = ~1u; assert((cast(size_t)p & (Char.sizeof-1)) == orginalAlign); static if(charSize == 3) { state = (state<<1) | table[p[1]]; state = (state<<1) | table[p[2]]; p += 4; } else p++; //first char is tested, see if that's all if(!(state & limit)) return (p-cast(ubyte*)haystack.ptr)/Char.sizeof -length; } else {//have some bits/states for possible matches, //use the usual shift-or cycle static if(charSize == 3) { state = (state<<1) | table[p[0]]; state = (state<<1) | table[p[1]]; state = (state<<1) | table[p[2]]; p += 4; } else { state = (state<<1) | table[p[0]]; p++; } if(!(state & limit)) return (p-cast(ubyte*)haystack.ptr)/Char.sizeof -length; } debug(std_regex_search) writefln("State: %32b", state); } } else { //normal path, partially unrolled for char/wchar static if(charSize == 3) { const(ubyte)* end = cast(ubyte*)(haystack.ptr + haystack.length); while(p != end) { state = (state<<1) | table[p[0]]; state = (state<<1) | table[p[1]]; state = (state<<1) | table[p[2]]; p += 4; if(!(state & limit))//division rounds down for dchar return (p-cast(ubyte*)haystack.ptr)/Char.sizeof -length; } } else { auto len = cast(ubyte*)(haystack.ptr + haystack.length) - p; size_t i = 0; if(len & 1) { state = (state<<1) | table[p[i++]]; if(!(state & limit)) return idx+i/Char.sizeof-length; } while(i < len) { state = (state<<1) | table[p[i++]]; if(!(state & limit)) return idx+i/Char.sizeof -length; state = (state<<1) | table[p[i++]]; if(!(state & limit)) return idx+i/Char.sizeof -length; debug(std_regex_search) writefln("State: %32b", state); } } } return haystack.length; } @system debug static void dump(uint[] table) {//@@@BUG@@@ writef(ln) is @system import std.stdio; for(size_t i = 0; i < table.length; i += 4) { writefln("%32b %32b %32b %32b",table[i], table[i+1], table[i+2], table[i+3]); } } } unittest { import std.conv, std.regex; @trusted void test_fixed(alias Kick)() { foreach(i, v; AliasSeq!(char, wchar, dchar)) { alias Char = v; alias String = immutable(v)[]; auto r = regex(to!String(`abc$`)); auto kick = Kick!Char(r, new uint[256]); assert(kick.length == 3, text(Kick.stringof," ",v.stringof, " == ", kick.length)); auto r2 = regex(to!String(`(abc){2}a+`)); kick = Kick!Char(r2, new uint[256]); assert(kick.length == 7, text(Kick.stringof,v.stringof," == ", kick.length)); auto r3 = regex(to!String(`\b(a{2}b{3}){2,4}`)); kick = Kick!Char(r3, new uint[256]); assert(kick.length == 10, text(Kick.stringof,v.stringof," == ", kick.length)); auto r4 = regex(to!String(`\ba{2}c\bxyz`)); kick = Kick!Char(r4, new uint[256]); assert(kick.length == 6, text(Kick.stringof,v.stringof, " == ", kick.length)); auto r5 = regex(to!String(`\ba{2}c\b`)); kick = Kick!Char(r5, new uint[256]); size_t x = kick.search("aabaacaa", 0); assert(x == 3, text(Kick.stringof,v.stringof," == ", kick.length)); x = kick.search("aabaacaa", x+1); assert(x == 8, text(Kick.stringof,v.stringof," == ", kick.length)); } } @trusted void test_flex(alias Kick)() { foreach(i, v; AliasSeq!(char, wchar, dchar)) { alias Char = v; alias String = immutable(v)[]; auto r = regex(to!String(`abc[a-z]`)); auto kick = Kick!Char(r, new uint[256]); auto x = kick.search(to!String("abbabca"), 0); assert(x == 3, text("real x is ", x, " ",v.stringof)); auto r2 = regex(to!String(`(ax|bd|cdy)`)); String s2 = to!String("abdcdyabax"); kick = Kick!Char(r2, new uint[256]); x = kick.search(s2, 0); assert(x == 1, text("real x is ", x)); x = kick.search(s2, x+1); assert(x == 3, text("real x is ", x)); x = kick.search(s2, x+1); assert(x == 8, text("real x is ", x)); auto rdot = regex(to!String(`...`)); kick = Kick!Char(rdot, new uint[256]); assert(kick.length == 0); auto rN = regex(to!String(`a(b+|c+)x`)); kick = Kick!Char(rN, new uint[256]); assert(kick.length == 3); assert(kick.search("ababx",0) == 2); assert(kick.search("abaacba",0) == 3);//expected inexact } } test_fixed!(ShiftOr)(); test_flex!(ShiftOr)(); } alias Kickstart = ShiftOr; ldc-1.1.0-beta3-src/runtime/phobos/std/regex/internal/parser.d0000664000175000017500000014221012776215007022275 0ustar kaikai//Written in the D programming language /* Regular expression pattern parser. */ module std.regex.internal.parser; import std.regex.internal.ir; import std.algorithm, std.range, std.uni, std.meta, std.traits, std.typecons, std.exception; static import std.ascii; // package relevant info from parser into a regex object auto makeRegex(S)(Parser!S p) { Regex!(BasicElementOf!S) re; with(re) { ir = p.ir; dict = p.dict; ngroup = p.groupStack.top; maxCounterDepth = p.counterDepth; flags = p.re_flags; charsets = p.charsets; tries = p.tries; backrefed = p.backrefed; re.lightPostprocess(); debug(std_regex_parser) { print(); } //@@@BUG@@@ (not reduced) //somehow just using validate _collides_ with std.utf.validate (!) version(assert) re.validateRe(); } return re; } // helper for unittest auto makeRegex(S)(S arg) if(isSomeString!S) { return makeRegex(Parser!S(arg, "")); } unittest { auto re = makeRegex(`(?P\w+) = (?P\d+)`); auto nc = re.namedCaptures; static assert(isRandomAccessRange!(typeof(nc))); assert(!nc.empty); assert(nc.length == 2); assert(nc.equal(["name", "var"])); assert(nc[0] == "name"); assert(nc[1..$].equal(["var"])); re = makeRegex(`(\w+) (?P\w+) (\w+)`); nc = re.namedCaptures; assert(nc.length == 1); assert(nc[0] == "named"); assert(nc.front == "named"); assert(nc.back == "named"); re = makeRegex(`(\w+) (\w+)`); nc = re.namedCaptures; assert(nc.empty); re = makeRegex(`(?P\d{4})/(?P\d{2})/(?P\d{2})/`); nc = re.namedCaptures; auto cp = nc.save; assert(nc.equal(cp)); nc.popFront(); assert(nc.equal(cp[1..$])); nc.popBack(); assert(nc.equal(cp[1 .. $ - 1])); } @trusted void reverseBytecode()(Bytecode[] code) { Bytecode[] rev = new Bytecode[code.length]; uint revPc = cast(uint)rev.length; Stack!(Tuple!(uint, uint, uint)) stack; uint start = 0; uint end = cast(uint)code.length; for(;;) { for(uint pc = start; pc < end; ) { uint len = code[pc].length; if(code[pc].code == IR.GotoEndOr) break; //pick next alternation branch if(code[pc].isAtom) { rev[revPc - len .. revPc] = code[pc .. pc + len]; revPc -= len; pc += len; } else if(code[pc].isStart || code[pc].isEnd) { //skip over other embedded lookbehinds they are reversed if(code[pc].code == IR.LookbehindStart || code[pc].code == IR.NeglookbehindStart) { uint blockLen = len + code[pc].data + code[pc].pairedLength; rev[revPc - blockLen .. revPc] = code[pc .. pc + blockLen]; pc += blockLen; revPc -= blockLen; continue; } uint second = code[pc].indexOfPair(pc); uint secLen = code[second].length; rev[revPc - secLen .. revPc] = code[second .. second + secLen]; revPc -= secLen; if(code[pc].code == IR.OrStart) { //we pass len bytes forward, but secLen in reverse uint revStart = revPc - (second + len - secLen - pc); uint r = revStart; uint i = pc + IRL!(IR.OrStart); while(code[i].code == IR.Option) { if(code[i - 1].code != IR.OrStart) { assert(code[i - 1].code == IR.GotoEndOr); rev[r - 1] = code[i - 1]; } rev[r] = code[i]; auto newStart = i + IRL!(IR.Option); auto newEnd = newStart + code[i].data; auto newRpc = r + code[i].data + IRL!(IR.Option); if(code[newEnd].code != IR.OrEnd) { newRpc--; } stack.push(tuple(newStart, newEnd, newRpc)); r += code[i].data + IRL!(IR.Option); i += code[i].data + IRL!(IR.Option); } pc = i; revPc = revStart; assert(code[pc].code == IR.OrEnd); } else pc += len; } } if(stack.empty) break; start = stack.top[0]; end = stack.top[1]; revPc = stack.top[2]; stack.pop(); } code[] = rev[]; } alias Escapables = AliasSeq!('[', ']', '\\', '^', '$', '.', '|', '?', ',', '-', ';', ':', '#', '&', '%', '/', '<', '>', '`', '*', '+', '(', ')', '{', '}', '~'); //test if a given string starts with hex number of maxDigit that's a valid codepoint //returns it's value and skips these maxDigit chars on success, throws on failure dchar parseUniHex(Char)(ref Char[] str, size_t maxDigit) { //std.conv.parse is both @system and bogus enforce(str.length >= maxDigit,"incomplete escape sequence"); uint val; for(int k = 0; k < maxDigit; k++) { auto current = str[k];//accepts ascii only, so it's OK to index directly if('0' <= current && current <= '9') val = val * 16 + current - '0'; else if('a' <= current && current <= 'f') val = val * 16 + current -'a' + 10; else if('A' <= current && current <= 'F') val = val * 16 + current - 'A' + 10; else throw new Exception("invalid escape sequence"); } enforce(val <= 0x10FFFF, "invalid codepoint"); str = str[maxDigit..$]; return val; } @system unittest //BUG canFind is system { string[] non_hex = [ "000j", "000z", "FffG", "0Z"]; string[] hex = [ "01", "ff", "00af", "10FFFF" ]; int[] value = [ 1, 0xFF, 0xAF, 0x10FFFF ]; foreach(v; non_hex) assert(collectException(parseUniHex(v, v.length)).msg .canFind("invalid escape sequence")); foreach(i, v; hex) assert(parseUniHex(v, v.length) == value[i]); string over = "0011FFFF"; assert(collectException(parseUniHex(over, over.length)).msg .canFind("invalid codepoint")); } //heuristic value determines maximum CodepointSet length suitable for linear search enum maxCharsetUsed = 6; enum maxCachedTries = 8; alias Trie = CodepointSetTrie!(13, 8); alias makeTrie = codepointSetTrie!(13, 8); Trie[CodepointSet] trieCache; //accessor with caching @trusted Trie getTrie(CodepointSet set) {// @@@BUG@@@ 6357 almost all properties of AA are not @safe if(__ctfe || maxCachedTries == 0) return makeTrie(set); else { auto p = set in trieCache; if(p) return *p; if(trieCache.length == maxCachedTries) { // flush entries in trieCache trieCache = null; } return (trieCache[set] = makeTrie(set)); } } auto caseEnclose(CodepointSet set) { auto cased = set & unicode.LC; foreach (dchar ch; cased.byCodepoint) { foreach(c; simpleCaseFoldings(ch)) set |= c; } return set; } /+ fetch codepoint set corresponding to a name (InBlock or binary property) +/ @trusted CodepointSet getUnicodeSet(in char[] name, bool negated, bool casefold) { CodepointSet s = unicode(name); //FIXME: caseEnclose for new uni as Set | CaseEnclose(SET && LC) if(casefold) s = caseEnclose(s); if(negated) s = s.inverted; return s; } //basic stack, just in case it gets used anywhere else then Parser @trusted struct Stack(T) { T[] data; @property bool empty(){ return data.empty; } @property size_t length(){ return data.length; } void push(T val){ data ~= val; } T pop() { assert(!empty); auto val = data[$ - 1]; data = data[0 .. $ - 1]; if(!__ctfe) cast(void)data.assumeSafeAppend(); return val; } @property ref T top() { assert(!empty); return data[$ - 1]; } } //safety limits enum maxGroupNumber = 2^^19; enum maxLookaroundDepth = 16; // *Bytecode.sizeof, i.e. 1Mb of bytecode alone enum maxCompiledLength = 2^^18; //amounts to up to 4 Mb of auxilary table for matching enum maxCumulativeRepetitionLength = 2^^20; struct Parser(R) if (isForwardRange!R && is(ElementType!R : dchar)) { enum infinite = ~0u; dchar _current; bool empty; R pat, origin; //keep full pattern for pretty printing error messages Bytecode[] ir; //resulting bytecode uint re_flags = 0; //global flags e.g. multiline + internal ones Stack!(uint) fixupStack; //stack of opened start instructions NamedGroup[] dict; //maps name -> user group number //current num of group, group nesting level and repetitions step Stack!(uint) groupStack; uint nesting = 0; uint lookaroundNest = 0; uint counterDepth = 0; //current depth of nested counted repetitions CodepointSet[] charsets; // const(Trie)[] tries; // uint[] backrefed; //bitarray for groups @trusted this(S)(R pattern, S flags) if(isSomeString!S) { pat = origin = pattern; //reserve slightly more then avg as sampled from unittests if(!__ctfe) ir.reserve((pat.length*5+2)/4); parseFlags(flags); _current = ' ';//a safe default for freeform parsing next(); try { parseRegex(); } catch(Exception e) { error(e.msg);//also adds pattern location } put(Bytecode(IR.End, 0)); } //mark referenced groups for latter processing void markBackref(uint n) { if(n/32 >= backrefed.length) backrefed.length = n/32 + 1; backrefed[n / 32] |= 1 << (n & 31); } bool isOpenGroup(uint n) { // walk the fixup stack and see if there are groups labeled 'n' // fixup '0' is reserved for alternations return fixupStack.data[1..$]. canFind!(fix => ir[fix].code == IR.GroupStart && ir[fix].data == n)(); } @property dchar current(){ return _current; } bool _next() { if(pat.empty) { empty = true; return false; } _current = pat.front; pat.popFront(); return true; } void skipSpace() { while(isWhite(current) && _next()){ } } bool next() { if(re_flags & RegexOption.freeform) { bool r = _next(); skipSpace(); return r; } else return _next(); } void put(Bytecode code) { enforce(ir.length < maxCompiledLength, "maximum compiled pattern length is exceeded"); ir ~= code; } void putRaw(uint number) { enforce(ir.length < maxCompiledLength, "maximum compiled pattern length is exceeded"); ir ~= Bytecode.fromRaw(number); } //parsing number with basic overflow check uint parseDecimal() { uint r = 0; while(std.ascii.isDigit(current)) { if(r >= (uint.max/10)) error("Overflow in decimal number"); r = 10*r + cast(uint)(current-'0'); if(!next()) break; } return r; } //parse control code of form \cXXX, c assumed to be the current symbol dchar parseControlCode() { enforce(next(), "Unfinished escape sequence"); enforce(('a' <= current && current <= 'z') || ('A' <= current && current <= 'Z'), "Only letters are allowed after \\c"); return current & 0x1f; } // @trusted void parseFlags(S)(S flags) {//@@@BUG@@@ text is @system import std.conv; foreach(ch; flags)//flags are ASCII anyway { L_FlagSwitch: switch(ch) { foreach(i, op; __traits(allMembers, RegexOption)) { case RegexOptionNames[i]: if(re_flags & mixin("RegexOption."~op)) throw new RegexException(text("redundant flag specified: ",ch)); re_flags |= mixin("RegexOption."~op); break L_FlagSwitch; } default: throw new RegexException(text("unknown regex flag '",ch,"'")); } } } //parse and store IR for regex pattern @trusted void parseRegex() { fixupStack.push(0); groupStack.push(1);//0 - whole match auto maxCounterDepth = counterDepth; uint fix;//fixup pointer while(!empty) { debug(std_regex_parser) writeln("*LR*\nSource: ", pat, "\nStack: ",fixupStack.stack.data); switch(current) { case '(': next(); nesting++; uint nglob; fixupStack.push(cast(uint)ir.length); if(current == '?') { next(); switch(current) { case ':': put(Bytecode(IR.Nop, 0)); next(); break; case '=': genLookaround(IR.LookaheadStart); next(); break; case '!': genLookaround(IR.NeglookaheadStart); next(); break; case 'P': next(); if(current != '<') error("Expected '<' in named group"); string name; if(!next() || !(isAlpha(current) || current == '_')) error("Expected alpha starting a named group"); name ~= current; while(next() && (isAlpha(current) || current == '_' || std.ascii.isDigit(current))) { name ~= current; } if(current != '>') error("Expected '>' closing named group"); next(); nglob = groupStack.top++; enforce(groupStack.top <= maxGroupNumber, "limit on submatches is exceeded"); auto t = NamedGroup(name, nglob); auto d = assumeSorted!"a.name < b.name"(dict); auto ind = d.lowerBound(t).length; insertInPlace(dict, ind, t); put(Bytecode(IR.GroupStart, nglob)); break; case '<': next(); if(current == '=') genLookaround(IR.LookbehindStart); else if(current == '!') genLookaround(IR.NeglookbehindStart); else error("'!' or '=' expected after '<'"); next(); break; default: error(" ':', '=', '<', 'P' or '!' expected after '(?' "); } } else { nglob = groupStack.top++; enforce(groupStack.top <= maxGroupNumber, "limit on number of submatches is exceeded"); put(Bytecode(IR.GroupStart, nglob)); } break; case ')': enforce(nesting, "Unmatched ')'"); nesting--; next(); fix = fixupStack.pop(); switch(ir[fix].code) { case IR.GroupStart: put(Bytecode(IR.GroupEnd,ir[fix].data)); parseQuantifier(fix); break; case IR.LookaheadStart, IR.NeglookaheadStart, IR.LookbehindStart, IR.NeglookbehindStart: assert(lookaroundNest); fixLookaround(fix); lookaroundNest--; break; case IR.Option: //| xxx ) //two fixups: last option + full OR finishAlternation(fix); fix = fixupStack.top; switch(ir[fix].code) { case IR.GroupStart: fixupStack.pop(); put(Bytecode(IR.GroupEnd,ir[fix].data)); parseQuantifier(fix); break; case IR.LookaheadStart, IR.NeglookaheadStart, IR.LookbehindStart, IR.NeglookbehindStart: assert(lookaroundNest); lookaroundNest--; fix = fixupStack.pop(); fixLookaround(fix); break; default://(?:xxx) fixupStack.pop(); parseQuantifier(fix); } break; default://(?:xxx) parseQuantifier(fix); } break; case '|': next(); fix = fixupStack.top; if(ir.length > fix && ir[fix].code == IR.Option) { ir[fix] = Bytecode(ir[fix].code, cast(uint)ir.length - fix); put(Bytecode(IR.GotoEndOr, 0)); fixupStack.top = cast(uint)ir.length; //replace latest fixup for Option put(Bytecode(IR.Option, 0)); break; } uint len, orStart; //start a new option if(fixupStack.length == 1) {//only root entry, effectively no fixup len = cast(uint)ir.length + IRL!(IR.GotoEndOr); orStart = 0; } else {//IR.lookahead, etc. fixups that have length > 1, thus check ir[x].length len = cast(uint)ir.length - fix - (ir[fix].length - 1); orStart = fix + ir[fix].length; } insertInPlace(ir, orStart, Bytecode(IR.OrStart, 0), Bytecode(IR.Option, len)); assert(ir[orStart].code == IR.OrStart); put(Bytecode(IR.GotoEndOr, 0)); fixupStack.push(orStart); //fixup for StartOR fixupStack.push(cast(uint)ir.length); //for second Option put(Bytecode(IR.Option, 0)); break; default://no groups or whatever uint start = cast(uint)ir.length; parseAtom(); parseQuantifier(start); } } if(fixupStack.length != 1) { fix = fixupStack.pop(); enforce(ir[fix].code == IR.Option, "no matching ')'"); finishAlternation(fix); enforce(fixupStack.length == 1, "no matching ')'"); } } //helper function, finalizes IR.Option, fix points to the first option of sequence void finishAlternation(uint fix) { enforce(ir[fix].code == IR.Option, "no matching ')'"); ir[fix] = Bytecode(ir[fix].code, cast(uint)ir.length - fix - IRL!(IR.OrStart)); fix = fixupStack.pop(); enforce(ir[fix].code == IR.OrStart, "no matching ')'"); ir[fix] = Bytecode(IR.OrStart, cast(uint)ir.length - fix - IRL!(IR.OrStart)); put(Bytecode(IR.OrEnd, cast(uint)ir.length - fix - IRL!(IR.OrStart))); uint pc = fix + IRL!(IR.OrStart); while(ir[pc].code == IR.Option) { pc = pc + ir[pc].data; if(ir[pc].code != IR.GotoEndOr) break; ir[pc] = Bytecode(IR.GotoEndOr, cast(uint)(ir.length - pc - IRL!(IR.OrEnd))); pc += IRL!(IR.GotoEndOr); } put(Bytecode.fromRaw(0)); } //parse and store IR for atom-quantifier pair @trusted void parseQuantifier(uint offset) {//copy is @system uint replace = ir[offset].code == IR.Nop; if(empty && !replace) return; uint min, max; switch(current) { case '*': min = 0; max = infinite; break; case '?': min = 0; max = 1; break; case '+': min = 1; max = infinite; break; case '{': enforce(next(), "Unexpected end of regex pattern"); enforce(std.ascii.isDigit(current), "First number required in repetition"); min = parseDecimal(); if(current == '}') max = min; else if(current == ',') { next(); if(std.ascii.isDigit(current)) max = parseDecimal(); else if(current == '}') max = infinite; else error("Unexpected symbol in regex pattern"); skipSpace(); if(current != '}') error("Unmatched '{' in regex pattern"); } else error("Unexpected symbol in regex pattern"); if(min > max) error("Illegal {n,m} quantifier"); break; default: if(replace) { copy(ir[offset + 1 .. $], ir[offset .. $ - 1]); ir.length -= 1; } return; } uint len = cast(uint)ir.length - offset - replace; bool greedy = true; //check only if we managed to get new symbol if(next() && current == '?') { greedy = false; next(); } if(max != infinite) { if(min != 1 || max != 1) { Bytecode op = Bytecode(greedy ? IR.RepeatStart : IR.RepeatQStart, len); if(replace) ir[offset] = op; else insertInPlace(ir, offset, op); put(Bytecode(greedy ? IR.RepeatEnd : IR.RepeatQEnd, len)); put(Bytecode.init); //hotspot putRaw(1); putRaw(min); putRaw(max); counterDepth = std.algorithm.max(counterDepth, nesting+1); } } else if(min) //&& max is infinite { if(min != 1) { Bytecode op = Bytecode(greedy ? IR.RepeatStart : IR.RepeatQStart, len); if(replace) ir[offset] = op; else insertInPlace(ir, offset, op); offset += 1;//so it still points to the repeated block put(Bytecode(greedy ? IR.RepeatEnd : IR.RepeatQEnd, len)); put(Bytecode.init); //hotspot putRaw(1); putRaw(min); putRaw(min); counterDepth = std.algorithm.max(counterDepth, nesting+1); } else if(replace) { copy(ir[offset+1 .. $], ir[offset .. $-1]); ir.length -= 1; } put(Bytecode(greedy ? IR.InfiniteStart : IR.InfiniteQStart, len)); enforce(ir.length + len < maxCompiledLength, "maximum compiled pattern length is exceeded"); ir ~= ir[offset .. offset+len]; //IR.InfinteX is always a hotspot put(Bytecode(greedy ? IR.InfiniteEnd : IR.InfiniteQEnd, len)); put(Bytecode.init); //merge index } else//vanila {0,inf} { Bytecode op = Bytecode(greedy ? IR.InfiniteStart : IR.InfiniteQStart, len); if(replace) ir[offset] = op; else insertInPlace(ir, offset, op); //IR.InfinteX is always a hotspot put(Bytecode(greedy ? IR.InfiniteEnd : IR.InfiniteQEnd, len)); put(Bytecode.init); //merge index } } //parse and store IR for atom void parseAtom() { if(empty) return; switch(current) { case '*', '?', '+', '|', '{', '}': error("'*', '+', '?', '{', '}' not allowed in atom"); break; case '.': put(Bytecode(IR.Any, 0)); next(); break; case '[': parseCharset(); break; case '\\': enforce(_next(), "Unfinished escape sequence"); parseEscape(); break; case '^': put(Bytecode(IR.Bol, 0)); next(); break; case '$': put(Bytecode(IR.Eol, 0)); next(); break; default: //FIXME: getCommonCasing in new std uni if(re_flags & RegexOption.casefold) { auto range = simpleCaseFoldings(current); assert(range.length <= 5); if(range.length == 1) put(Bytecode(IR.Char, range.front)); else foreach(v; range) put(Bytecode(IR.OrChar, v, cast(uint)range.length)); } else put(Bytecode(IR.Char, current)); next(); } } //generate code for start of lookaround: (?= (?! (?<= (?= 0) { if(ivals.length*2 > maxCharsetUsed) put(Bytecode(IR.Trie, cast(uint)n)); else put(Bytecode(IR.CodepointSet, cast(uint)n)); return; } if(ivals.length*2 > maxCharsetUsed) { auto t = getTrie(set); put(Bytecode(IR.Trie, cast(uint)tries.length)); tries ~= t; debug(std_regex_allocation) writeln("Trie generated"); } else { put(Bytecode(IR.CodepointSet, cast(uint)charsets.length)); tries ~= Trie.init; } charsets ~= set; assert(charsets.length == tries.length); } } //parse and generate IR for escape stand alone escape sequence @trusted void parseEscape() {//accesses array of appender switch(current) { case 'f': next(); put(Bytecode(IR.Char, '\f')); break; case 'n': next(); put(Bytecode(IR.Char, '\n')); break; case 'r': next(); put(Bytecode(IR.Char, '\r')); break; case 't': next(); put(Bytecode(IR.Char, '\t')); break; case 'v': next(); put(Bytecode(IR.Char, '\v')); break; case 'd': next(); charsetToIr(unicode.Nd); break; case 'D': next(); charsetToIr(unicode.Nd.inverted); break; case 'b': next(); put(Bytecode(IR.Wordboundary, 0)); break; case 'B': next(); put(Bytecode(IR.Notwordboundary, 0)); break; case 's': next(); charsetToIr(unicode.White_Space); break; case 'S': next(); charsetToIr(unicode.White_Space.inverted); break; case 'w': next(); charsetToIr(wordCharacter); break; case 'W': next(); charsetToIr(wordCharacter.inverted); break; case 'p': case 'P': auto CodepointSet = parseUnicodePropertySpec(current == 'P'); charsetToIr(CodepointSet); break; case 'x': uint code = parseUniHex(pat, 2); next(); put(Bytecode(IR.Char,code)); break; case 'u': case 'U': uint code = parseUniHex(pat, current == 'u' ? 4 : 8); next(); put(Bytecode(IR.Char, code)); break; case 'c': //control codes Bytecode code = Bytecode(IR.Char, parseControlCode()); next(); put(code); break; case '0': next(); put(Bytecode(IR.Char, 0));//NUL character break; case '1': .. case '9': uint nref = cast(uint)current - '0'; uint maxBackref = sum(groupStack.data); enforce(nref < maxBackref, "Backref to unseen group"); //perl's disambiguation rule i.e. //get next digit only if there is such group number while(nref < maxBackref && next() && std.ascii.isDigit(current)) { nref = nref * 10 + current - '0'; } if(nref >= maxBackref) nref /= 10; enforce(!isOpenGroup(nref), "Backref to open group"); uint localLimit = maxBackref - groupStack.top; if(nref >= localLimit) { put(Bytecode(IR.Backref, nref-localLimit)); ir[$-1].setLocalRef(); } else put(Bytecode(IR.Backref, nref)); markBackref(nref); break; default: auto op = Bytecode(IR.Char, current); next(); put(op); } } //parse and return a CodepointSet for \p{...Property...} and \P{...Property..}, //\ - assumed to be processed, p - is current CodepointSet parseUnicodePropertySpec(bool negated) { enum MAX_PROPERTY = 128; char[MAX_PROPERTY] result; uint k = 0; enforce(next(), "eof parsing unicode property spec"); if(current == '{') { while(k < MAX_PROPERTY && next() && current !='}' && current !=':') if(current != '-' && current != ' ' && current != '_') result[k++] = cast(char)std.ascii.toLower(current); enforce(k != MAX_PROPERTY, "invalid property name"); enforce(current == '}', "} expected "); } else {//single char properties e.g.: \pL, \pN ... enforce(current < 0x80, "invalid property name"); result[k++] = cast(char)current; } auto s = getUnicodeSet(result[0..k], negated, cast(bool)(re_flags & RegexOption.casefold)); enforce(!s.empty, "unrecognized unicode property spec"); next(); return s; } // @trusted void error(string msg) { import std.format; auto app = appender!string(); ir = null; formattedWrite(app, "%s\nPattern with error: `%s` <--HERE-- `%s`", msg, origin[0..$-pat.length], pat); throw new RegexException(app.data); } alias Char = BasicElementOf!R; @property program() { return makeRegex(this); } } /+ lightweight post process step, only essentials +/ @trusted void lightPostprocess(Char)(ref Regex!Char zis) {//@@@BUG@@@ write is @system with(zis) { struct FixedStack(T) { T[] arr; uint _top; //this(T[] storage){ arr = storage; _top = -1; } @property ref T top(){ assert(!empty); return arr[_top]; } void push(T x){ arr[++_top] = x; } T pop() { assert(!empty); return arr[_top--]; } @property bool empty(){ return _top == -1; } } auto counterRange = FixedStack!uint(new uint[maxCounterDepth+1], -1); counterRange.push(1); ulong cumRange = 0; for(uint i = 0; i < ir.length; i += ir[i].length) { if(ir[i].hotspot) { assert(i + 1 < ir.length, "unexpected end of IR while looking for hotspot"); ir[i+1] = Bytecode.fromRaw(hotspotTableSize); hotspotTableSize += counterRange.top; } switch(ir[i].code) { case IR.RepeatStart, IR.RepeatQStart: uint repEnd = cast(uint)(i + ir[i].data + IRL!(IR.RepeatStart)); assert(ir[repEnd].code == ir[i].paired.code); uint max = ir[repEnd + 4].raw; ir[repEnd+2].raw = counterRange.top; ir[repEnd+3].raw *= counterRange.top; ir[repEnd+4].raw *= counterRange.top; ulong cntRange = cast(ulong)(max)*counterRange.top; cumRange += cntRange; enforce(cumRange < maxCumulativeRepetitionLength, "repetition length limit is exceeded"); counterRange.push(cast(uint)cntRange + counterRange.top); threadCount += counterRange.top; break; case IR.RepeatEnd, IR.RepeatQEnd: threadCount += counterRange.top; counterRange.pop(); break; case IR.GroupStart: if(isBackref(ir[i].data)) ir[i].setBackrefence(); threadCount += counterRange.top; break; case IR.GroupEnd: if(isBackref(ir[i].data)) ir[i].setBackrefence(); threadCount += counterRange.top; break; default: threadCount += counterRange.top; } } checkIfOneShot(); if(!(flags & RegexInfo.oneShot)) kickstart = Kickstart!Char(zis, new uint[](256)); debug(std_regex_allocation) writefln("IR processed, max threads: %d", threadCount); } } //IR code validator - proper nesting, illegal instructions, etc. @trusted void validateRe(Char)(ref Regex!Char zis) {//@@@BUG@@@ text is @system import std.conv; with(zis) { for(uint pc = 0; pc < ir.length; pc += ir[pc].length) { if(ir[pc].isStart || ir[pc].isEnd) { uint dest = ir[pc].indexOfPair(pc); assert(dest < ir.length, text("Wrong length in opcode at pc=", pc, " ", dest, " vs ", ir.length)); assert(ir[dest].paired == ir[pc], text("Wrong pairing of opcodes at pc=", pc, "and pc=", dest)); } else if(ir[pc].isAtom) { } else assert(0, text("Unknown type of instruction at pc=", pc)); } } } ldc-1.1.0-beta3-src/runtime/phobos/std/regex/internal/tests.d0000664000175000017500000012126312776215007022150 0ustar kaikai/* Regualar expressions package test suite. */ module std.regex.internal.tests; package(std.regex): import std.algorithm, std.conv, std.exception, std.meta, std.range, std.typecons, std.regex; import std.regex.internal.parser : Escapables; // characters that need escaping alias Sequence(int B, int E) = staticIota!(B, E); unittest {//sanity checks regex("(a|b)*"); regex(`(?:([0-9A-F]+)\.\.([0-9A-F]+)|([0-9A-F]+))\s*;\s*(.*)\s*#`); regex("abc|edf|ighrg"); auto r1 = regex("abc"); auto r2 = regex("(gylba)"); assert(match("abcdef", r1).hit == "abc"); assert(!match("wida",r2)); assert(bmatch("abcdef", r1).hit == "abc"); assert(!bmatch("wida", r2)); assert(match("abc", "abc".dup)); assert(bmatch("abc", "abc".dup)); Regex!char rc; assert(rc.empty); rc = regex("test"); assert(!rc.empty); } /* The test vectors in this file are altered from Henry Spencer's regexp test code. His copyright notice is: Copyright (c) 1986 by University of Toronto. Written by Henry Spencer. Not derived from licensed software. Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from defects in it. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. */ unittest { struct TestVectors { string pattern; string input; string result; string format; string replace; string flags; } static immutable TestVectors[] tv = [ TestVectors( "a\\b", "a", "y", "$&", "a" ), TestVectors( "(a)b\\1", "abaab","y", "$&", "aba" ), TestVectors( "()b\\1", "aaab", "y", "$&", "b" ), TestVectors( "abc", "abc", "y", "$&", "abc" ), TestVectors( "abc", "xbc", "n", "-", "-" ), TestVectors( "abc", "axc", "n", "-", "-" ), TestVectors( "abc", "abx", "n", "-", "-" ), TestVectors( "abc", "xabcy","y", "$&", "abc" ), TestVectors( "abc", "ababc","y", "$&", "abc" ), TestVectors( "ab*c", "abc", "y", "$&", "abc" ), TestVectors( "ab*bc", "abc", "y", "$&", "abc" ), TestVectors( "ab*bc", "abbc", "y", "$&", "abbc" ), TestVectors( "ab*bc", "abbbbc","y", "$&", "abbbbc" ), TestVectors( "ab+bc", "abbc", "y", "$&", "abbc" ), TestVectors( "ab+bc", "abc", "n", "-", "-" ), TestVectors( "ab+bc", "abq", "n", "-", "-" ), TestVectors( "ab+bc", "abbbbc","y", "$&", "abbbbc" ), TestVectors( "ab?bc", "abbc", "y", "$&", "abbc" ), TestVectors( "ab?bc", "abc", "y", "$&", "abc" ), TestVectors( "ab?bc", "abbbbc","n", "-", "-" ), TestVectors( "ab?c", "abc", "y", "$&", "abc" ), TestVectors( "^abc$", "abc", "y", "$&", "abc" ), TestVectors( "^abc$", "abcc", "n", "-", "-" ), TestVectors( "^abc", "abcc", "y", "$&", "abc" ), TestVectors( "^abc$", "aabc", "n", "-", "-" ), TestVectors( "abc$", "aabc", "y", "$&", "abc" ), TestVectors( "^", "abc", "y", "$&", "" ), TestVectors( "$", "abc", "y", "$&", "" ), TestVectors( "a.c", "abc", "y", "$&", "abc" ), TestVectors( "a.c", "axc", "y", "$&", "axc" ), TestVectors( "a.*c", "axyzc","y", "$&", "axyzc" ), TestVectors( "a.*c", "axyzd","n", "-", "-" ), TestVectors( "a[bc]d", "abc", "n", "-", "-" ), TestVectors( "a[bc]d", "abd", "y", "$&", "abd" ), TestVectors( "a[b-d]e", "abd", "n", "-", "-" ), TestVectors( "a[b-d]e", "ace", "y", "$&", "ace" ), TestVectors( "a[b-d]", "aac", "y", "$&", "ac" ), TestVectors( "a[-b]", "a-", "y", "$&", "a-" ), TestVectors( "a[b-]", "a-", "y", "$&", "a-" ), TestVectors( "a[b-a]", "-", "c", "-", "-" ), TestVectors( "a[]b", "-", "c", "-", "-" ), TestVectors( "a[", "-", "c", "-", "-" ), TestVectors( "a]", "a]", "y", "$&", "a]" ), TestVectors( "a[\\]]b", "a]b", "y", "$&", "a]b" ), TestVectors( "a[^bc]d", "aed", "y", "$&", "aed" ), TestVectors( "a[^bc]d", "abd", "n", "-", "-" ), TestVectors( "a[^-b]c", "adc", "y", "$&", "adc" ), TestVectors( "a[^-b]c", "a-c", "n", "-", "-" ), TestVectors( "a[^\\]b]c", "adc", "y", "$&", "adc" ), TestVectors( "ab|cd", "abc", "y", "$&", "ab" ), TestVectors( "ab|cd", "abcd", "y", "$&", "ab" ), TestVectors( "()ef", "def", "y", "$&-$1", "ef-" ), TestVectors( "()*", "-", "y", "-", "-" ), TestVectors( "*a", "-", "c", "-", "-" ), TestVectors( "^*", "-", "y", "-", "-" ), TestVectors( "$*", "-", "y", "-", "-" ), TestVectors( "(*)b", "-", "c", "-", "-" ), TestVectors( "$b", "b", "n", "-", "-" ), TestVectors( "a\\", "-", "c", "-", "-" ), TestVectors( "a\\(b", "a(b", "y", "$&-$1", "a(b-" ), TestVectors( "a\\(*b", "ab", "y", "$&", "ab" ), TestVectors( "a\\(*b", "a((b", "y", "$&", "a((b" ), TestVectors( "a\\\\b", "a\\b", "y", "$&", "a\\b" ), TestVectors( "abc)", "-", "c", "-", "-" ), TestVectors( "(abc", "-", "c", "-", "-" ), TestVectors( "((a))", "abc", "y", "$&-$1-$2", "a-a-a" ), TestVectors( "(a)b(c)", "abc", "y", "$&-$1-$2", "abc-a-c" ), TestVectors( "a+b+c", "aabbabc","y", "$&", "abc" ), TestVectors( "a**", "-", "c", "-", "-" ), TestVectors( "a*?a", "aa", "y", "$&", "a" ), TestVectors( "(a*)*", "aaa", "y", "-", "-" ), TestVectors( "(a*)+", "aaa", "y", "-", "-" ), TestVectors( "(a|)*", "-", "y", "-", "-" ), TestVectors( "(a*|b)*", "aabb", "y", "-", "-" ), TestVectors( "(a|b)*", "ab", "y", "$&-$1", "ab-b" ), TestVectors( "(a+|b)*", "ab", "y", "$&-$1", "ab-b" ), TestVectors( "(a+|b)+", "ab", "y", "$&-$1", "ab-b" ), TestVectors( "(a+|b)?", "ab", "y", "$&-$1", "a-a" ), TestVectors( "[^ab]*", "cde", "y", "$&", "cde" ), TestVectors( "(^)*", "-", "y", "-", "-" ), TestVectors( "(ab|)*", "-", "y", "-", "-" ), TestVectors( ")(", "-", "c", "-", "-" ), TestVectors( "", "abc", "y", "$&", "" ), TestVectors( "abc", "", "n", "-", "-" ), TestVectors( "a*", "", "y", "$&", "" ), TestVectors( "([abc])*d", "abbbcd", "y", "$&-$1", "abbbcd-c" ), TestVectors( "([abc])*bcd", "abcd", "y", "$&-$1", "abcd-a" ), TestVectors( "a|b|c|d|e", "e", "y", "$&", "e" ), TestVectors( "(a|b|c|d|e)f", "ef", "y", "$&-$1", "ef-e" ), TestVectors( "((a*|b))*", "aabb", "y", "-", "-" ), TestVectors( "abcd*efg", "abcdefg", "y", "$&", "abcdefg" ), TestVectors( "ab*", "xabyabbbz", "y", "$&", "ab" ), TestVectors( "ab*", "xayabbbz", "y", "$&", "a" ), TestVectors( "(ab|cd)e", "abcde", "y", "$&-$1", "cde-cd" ), TestVectors( "[abhgefdc]ij", "hij", "y", "$&", "hij" ), TestVectors( "^(ab|cd)e", "abcde", "n", "x$1y", "xy" ), TestVectors( "(abc|)ef", "abcdef", "y", "$&-$1", "ef-" ), TestVectors( "(a|b)c*d", "abcd", "y", "$&-$1", "bcd-b" ), TestVectors( "(ab|ab*)bc", "abc", "y", "$&-$1", "abc-a" ), TestVectors( "a([bc]*)c*", "abc", "y", "$&-$1", "abc-bc" ), TestVectors( "a([bc]*)(c*d)", "abcd", "y", "$&-$1-$2", "abcd-bc-d" ), TestVectors( "a([bc]+)(c*d)", "abcd", "y", "$&-$1-$2", "abcd-bc-d" ), TestVectors( "a([bc]*)(c+d)", "abcd", "y", "$&-$1-$2", "abcd-b-cd" ), TestVectors( "a[bcd]*dcdcde", "adcdcde", "y", "$&", "adcdcde" ), TestVectors( "a[bcd]+dcdcde", "adcdcde", "n", "-", "-" ), TestVectors( "(ab|a)b*c", "abc", "y", "$&-$1", "abc-ab" ), TestVectors( "((a)(b)c)(d)", "abcd", "y", "$1-$2-$3-$4", "abc-a-b-d" ), TestVectors( "[a-zA-Z_][a-zA-Z0-9_]*", "alpha", "y", "$&", "alpha" ), TestVectors( "^a(bc+|b[eh])g|.h$", "abh", "y", "$&-$1", "bh-" ), TestVectors( "(bc+d$|ef*g.|h?i(j|k))", "effgz", "y", "$&-$1-$2", "effgz-effgz-" ), TestVectors( "(bc+d$|ef*g.|h?i(j|k))", "ij", "y", "$&-$1-$2", "ij-ij-j" ), TestVectors( "(bc+d$|ef*g.|h?i(j|k))", "effg", "n", "-", "-" ), TestVectors( "(bc+d$|ef*g.|h?i(j|k))", "bcdd", "n", "-", "-" ), TestVectors( "(bc+d$|ef*g.|h?i(j|k))", "reffgz", "y", "$&-$1-$2", "effgz-effgz-" ), TestVectors( "(((((((((a)))))))))", "a", "y", "$&", "a" ), TestVectors( "multiple words of text", "uh-uh", "n", "-", "-" ), TestVectors( "multiple words", "multiple words, yeah", "y", "$&", "multiple words" ), TestVectors( "(.*)c(.*)", "abcde", "y", "$&-$1-$2", "abcde-ab-de" ), TestVectors( "\\((.*), (.*)\\)", "(a, b)", "y", "($2, $1)", "(b, a)" ), TestVectors( "abcd", "abcd", "y", "$&-&-$$$&", "abcd-&-$abcd" ), TestVectors( "a(bc)d", "abcd", "y", "$1-$$1-$$$1", "bc-$1-$bc" ), TestVectors( "[k]", "ab", "n", "-", "-" ), TestVectors( "[ -~]*", "abc", "y", "$&", "abc" ), TestVectors( "[ -~ -~]*", "abc", "y", "$&", "abc" ), TestVectors( "[ -~ -~ -~]*", "abc", "y", "$&", "abc" ), TestVectors( "[ -~ -~ -~ -~]*", "abc", "y", "$&", "abc" ), TestVectors( "[ -~ -~ -~ -~ -~]*", "abc", "y", "$&", "abc" ), TestVectors( "[ -~ -~ -~ -~ -~ -~]*", "abc", "y", "$&", "abc" ), TestVectors( "[ -~ -~ -~ -~ -~ -~ -~]*", "abc", "y", "$&", "abc" ), TestVectors( "a{2}", "candy", "n", "", "" ), TestVectors( "a{2}", "caandy", "y", "$&", "aa" ), TestVectors( "a{2}", "caaandy", "y", "$&", "aa" ), TestVectors( "a{2,}", "candy", "n", "", "" ), TestVectors( "a{2,}", "caandy", "y", "$&", "aa" ), TestVectors( "a{2,}", "caaaaaandy", "y", "$&", "aaaaaa" ), TestVectors( "a{1,3}", "cndy", "n", "", "" ), TestVectors( "a{1,3}", "candy", "y", "$&", "a" ), TestVectors( "a{1,3}", "caandy", "y", "$&", "aa" ), TestVectors( "a{1,3}", "caaaaaandy", "y", "$&", "aaa" ), TestVectors( "e?le?", "angel", "y", "$&", "el" ), TestVectors( "e?le?", "angle", "y", "$&", "le" ), TestVectors( "\\bn\\w", "noonday", "y", "$&", "no" ), TestVectors( "\\wy\\b", "possibly yesterday", "y", "$&", "ly" ), TestVectors( "\\w\\Bn", "noonday", "y", "$&", "on" ), TestVectors( "y\\B\\w", "possibly yesterday", "y", "$&", "ye" ), TestVectors( "\\cJ", "abc\ndef", "y", "$&", "\n" ), TestVectors( "\\d", "B2 is", "y", "$&", "2" ), TestVectors( "\\D", "B2 is", "y", "$&", "B" ), TestVectors( "\\s\\w*", "foo bar", "y", "$&", " bar" ), TestVectors( "\\S\\w*", "foo bar", "y", "$&", "foo" ), TestVectors( "abc", "ababc", "y", "$&", "abc" ), TestVectors( "apple(,)\\sorange\\1", "apple, orange, cherry, peach", "y", "$&", "apple, orange," ), TestVectors( "(\\w+)\\s(\\w+)", "John Smith", "y", "$2, $1", "Smith, John" ), TestVectors( "\\n\\f\\r\\t\\v", "abc\n\f\r\t\vdef", "y", "$&", "\n\f\r\t\v" ), TestVectors( ".*c", "abcde", "y", "$&", "abc" ), TestVectors( "^\\w+((;|=)\\w+)+$", "some=host=tld", "y", "$&-$1-$2", "some=host=tld-=tld-=" ), TestVectors( "^\\w+((\\.|-)\\w+)+$", "some.host.tld", "y", "$&-$1-$2", "some.host.tld-.tld-." ), TestVectors( "q(a|b)*q", "xxqababqyy", "y", "$&-$1", "qababq-b" ), TestVectors( "^(a)(b){0,1}(c*)", "abcc", "y", "$1 $2 $3", "a b cc" ), TestVectors( "^(a)((b){0,1})(c*)", "abcc", "y", "$1 $2 $3", "a b b" ), TestVectors( "^(a)(b)?(c*)", "abcc", "y", "$1 $2 $3", "a b cc" ), TestVectors( "^(a)((b)?)(c*)", "abcc", "y", "$1 $2 $3", "a b b" ), TestVectors( "^(a)(b){0,1}(c*)", "acc", "y", "$1 $2 $3", "a cc" ), TestVectors( "^(a)((b){0,1})(c*)", "acc", "y", "$1 $2 $3", "a " ), TestVectors( "^(a)(b)?(c*)", "acc", "y", "$1 $2 $3", "a cc" ), TestVectors( "^(a)((b)?)(c*)", "acc", "y", "$1 $2 $3", "a " ), TestVectors( "(?:ab){3}", "_abababc","y", "$&-$1", "ababab-" ), TestVectors( "(?:a(?:x)?)+", "aaxaxx", "y", "$&-$1-$2", "aaxax--" ), TestVectors( `\W\w\W`, "aa b!ca", "y", "$&", " b!"), //more repetitions: TestVectors( "(?:a{2,4}b{1,3}){1,2}", "aaabaaaabbb", "y", "$&", "aaabaaaabbb" ), TestVectors( "(?:a{2,4}b{1,3}){1,2}?", "aaabaaaabbb", "y", "$&", "aaab" ), //groups: TestVectors( "(abc)|(edf)|(xyz)", "xyz", "y", "$1-$2-$3","--xyz"), TestVectors( "(?P\\d+)/(?P\\d+)", "2/3", "y", "${d}/${q}", "3/2"), //set operations: TestVectors( "[a-z--d-f]", " dfa", "y", "$&", "a"), TestVectors( "[abc[pq--acq]]{2}", "bqpaca", "y", "$&", "pa"), TestVectors( "[a-z9&&abc0-9]{3}", "z90a0abc", "y", "$&", "abc"), TestVectors( "[0-9a-f~~0-5a-z]{2}", "g0a58x", "y", "$&", "8x"), TestVectors( "[abc[pq]xyz[rs]]{4}", "cqxr", "y", "$&", "cqxr"), TestVectors( "[abcdf--[ab&&[bcd]][acd]]", "abcdefgh", "y", "$&", "f"), TestVectors( "[a-c||d-f]+", "abcdef", "y", "$&", "abcdef"), TestVectors( "[a-f--a-c]+", "abcdef", "y", "$&", "def"), TestVectors( "[a-c&&b-f]+", "abcdef", "y", "$&", "bc"), TestVectors( "[a-c~~b-f]+", "abcdef", "y", "$&", "a"), //unicode blocks & properties: TestVectors( `\P{Inlatin1suppl ement}`, "\u00c2!", "y", "$&", "!"), TestVectors( `\p{InLatin-1 Supplement}\p{in-mathematical-operators}\P{Inlatin1suppl ement}`, "\u00c2\u2200\u00c3\u2203.", "y", "$&", "\u00c3\u2203."), TestVectors( `[-+*/\p{in-mathematical-operators}]{2}`, "a+\u2212", "y", "$&", "+\u2212"), TestVectors( `\p{Ll}+`, "XabcD", "y", "$&", "abc"), TestVectors( `\p{Lu}+`, "абвГДЕ", "y", "$&", "ГДЕ"), TestVectors( `^\p{Currency Symbol}\p{Sc}`, "$₤", "y", "$&", "$₤"), TestVectors( `\p{Common}\p{Thai}`, "!ฆ", "y", "$&", "!ฆ"), TestVectors( `[\d\s]*\D`, "12 \t3\U00001680\u0F20_2", "y", "$&", "12 \t3\U00001680\u0F20_"), TestVectors( `[c-wф]фф`, "ффф", "y", "$&", "ффф"), //case insensitive: TestVectors( `^abcdEf$`, "AbCdEF", "y", "$&", "AbCdEF", "i"), TestVectors( `Русский язык`, "рУсскИй ЯзЫк", "y", "$&", "рУсскИй ЯзЫк", "i"), TestVectors( `ⒶⒷⓒ` , "ⓐⓑⒸ", "y", "$&", "ⓐⓑⒸ", "i"), TestVectors( "\U00010400{2}", "\U00010428\U00010400 ", "y", "$&", "\U00010428\U00010400", "i"), TestVectors( `[adzУ-Я]{4}`, "DzюЯ", "y", "$&", "DzюЯ", "i"), TestVectors( `\p{L}\p{Lu}{10}`, "абвгдеЖЗИКЛ", "y", "$&", "абвгдеЖЗИКЛ", "i"), TestVectors( `(?:Dåb){3}`, "DåbDÅBdÅb", "y", "$&", "DåbDÅBdÅb", "i"), //escapes: TestVectors( `\u0041\u005a\U00000065\u0001`, "AZe\u0001", "y", "$&", "AZe\u0001"), TestVectors( `\u`, "", "c", "-", "-"), TestVectors( `\U`, "", "c", "-", "-"), TestVectors( `\u003`, "", "c", "-", "-"), TestVectors( `[\x00-\x7f]{4}`, "\x00\x09ab", "y", "$&", "\x00\x09ab"), TestVectors( `[\cJ\cK\cA-\cD]{3}\cQ`, "\x01\x0B\x0A\x11", "y", "$&", "\x01\x0B\x0A\x11"), TestVectors( `\r\n\v\t\f\\`, "\r\n\v\t\f\\", "y", "$&", "\r\n\v\t\f\\"), TestVectors( `[\u0003\u0001]{2}`, "\u0001\u0003", "y", "$&", "\u0001\u0003"), TestVectors( `^[\u0020-\u0080\u0001\n-\r]{8}`, "abc\u0001\v\f\r\n", "y", "$&", "abc\u0001\v\f\r\n"), TestVectors( `\w+\S\w+`, "ab7!44c", "y", "$&", "ab7!44c"), TestVectors( `\b\w+\b`, " abde4 ", "y", "$&", "abde4"), TestVectors( `\b\w+\b`, " abde4", "y", "$&", "abde4"), TestVectors( `\b\w+\b`, "abde4 ", "y", "$&", "abde4"), TestVectors( `\pL\pS`, "a\u02DA", "y", "$&", "a\u02DA"), TestVectors( `\pX`, "", "c", "-", "-"), // ^, $, \b, \B, multiline : TestVectors( `\r.*?$`, "abc\r\nxy", "y", "$&", "\r\nxy", "sm"), TestVectors( `^a$^b$`, "a\r\nb\n", "n", "$&", "-", "m"), TestVectors( `^a$\r\n^b$`,"a\r\nb\n", "y", "$&", "a\r\nb", "m"), TestVectors( `^$`, "\r\n", "y", "$&", "", "m"), TestVectors( `^a$\nx$`, "a\nx\u2028","y", "$&", "a\nx", "m"), TestVectors( `^a$\nx$`, "a\nx\u2029","y", "$&", "a\nx", "m"), TestVectors( `^a$\nx$`, "a\nx\u0085","y", "$&", "a\nx","m"), TestVectors( `^x$`, "\u2028x", "y", "$&", "x", "m"), TestVectors( `^x$`, "\u2029x", "y", "$&", "x", "m"), TestVectors( `^x$`, "\u0085x", "y", "$&", "x", "m"), TestVectors( `\b^.`, "ab", "y", "$&", "a"), TestVectors( `\B^.`, "ab", "n", "-", "-"), TestVectors( `^ab\Bc\B`, "\r\nabcd", "y", "$&", "abc", "m"), TestVectors( `^.*$`, "12345678", "y", "$&", "12345678"), // luckily obtained regression on incremental matching in backtracker TestVectors( `^(?:(?:([0-9A-F]+)\.\.([0-9A-F]+)|([0-9A-F]+))\s*;\s*([^ ]*)\s*#|# (?:\w|_)+=((?:\w|_)+))`, "0020 ; White_Space # ", "y", "$1-$2-$3", "--0020"), //lookahead TestVectors( "(foo.)(?=(bar))", "foobar foodbar", "y", "$&-$1-$2", "food-food-bar" ), TestVectors( `\b(\d+)[a-z](?=\1)`, "123a123", "y", "$&-$1", "123a-123" ), TestVectors( `\$(?!\d{3})\w+`, "$123 $abc", "y", "$&", "$abc"), TestVectors( `(abc)(?=(ed(f))\3)`, "abcedff", "y", "-", "-"), TestVectors( `\b[A-Za-z0-9.]+(?=(@(?!gmail)))`, "a@gmail,x@com", "y", "$&-$1", "x-@"), TestVectors( `x()(abc)(?=(d)(e)(f)\2)`, "xabcdefabc", "y", "$&", "xabc"), TestVectors( `x()(abc)(?=(d)(e)(f)()\3\4\5)`, "xabcdefdef", "y", "$&", "xabc"), //lookback TestVectors( `(?<=(ab))\d`, "12ba3ab4", "y", "$&-$1", "4-ab", "i"), TestVectors( `\w(?"); assert(bmatch("texttext", greed).hit == "text"); } unittest { auto cr8 = ctRegex!("^(a)(b)?(c*)"); auto m8 = bmatch("abcc",cr8); assert(m8); assert(m8.captures[1] == "a"); assert(m8.captures[2] == "b"); assert(m8.captures[3] == "cc"); auto cr9 = ctRegex!("q(a|b)*q"); auto m9 = match("xxqababqyy",cr9); assert(m9); assert(equal(bmatch("xxqababqyy",cr9).captures, ["qababq", "b"])); } unittest { auto rtr = regex("a|b|c"); enum ctr = regex("a|b|c"); assert(equal(rtr.ir,ctr.ir)); //CTFE parser BUG is triggered by group //in the middle of alternation (at least not first and not last) enum testCT = regex(`abc|(edf)|xyz`); auto testRT = regex(`abc|(edf)|xyz`); assert(equal(testCT.ir,testRT.ir)); } unittest { enum cx = ctRegex!"(A|B|C)"; auto mx = match("B",cx); assert(mx); assert(equal(mx.captures, [ "B", "B"])); enum cx2 = ctRegex!"(A|B)*"; assert(match("BAAA",cx2)); enum cx3 = ctRegex!("a{3,4}","i"); auto mx3 = match("AaA",cx3); assert(mx3); assert(mx3.captures[0] == "AaA"); enum cx4 = ctRegex!(`^a{3,4}?[a-zA-Z0-9~]{1,2}`,"i"); auto mx4 = match("aaaabc", cx4); assert(mx4); assert(mx4.captures[0] == "aaaab"); auto cr8 = ctRegex!("(a)(b)?(c*)"); auto m8 = bmatch("abcc",cr8); assert(m8); assert(m8.captures[1] == "a"); assert(m8.captures[2] == "b"); assert(m8.captures[3] == "cc"); auto cr9 = ctRegex!(".*$", "gm"); auto m9 = match("First\rSecond", cr9); assert(m9); assert(equal(map!"a.hit"(m9), ["First", "", "Second"])); } unittest { //global matching void test_body(alias matchFn)() { string s = "a quick brown fox jumps over a lazy dog"; auto r1 = regex("\\b[a-z]+\\b","g"); string[] test; foreach(m; matchFn(s, r1)) test ~= m.hit; assert(equal(test, [ "a", "quick", "brown", "fox", "jumps", "over", "a", "lazy", "dog"])); auto free_reg = regex(` abc \s+ " ( [^"]+ | \\ " )+ " z `, "x"); auto m = match(`abc "quoted string with \" inside"z`,free_reg); assert(m); string mails = " hey@you.com no@spam.net "; auto rm = regex(`@(?<=\S+@)\S+`,"g"); assert(equal(map!"a[0]"(matchFn(mails, rm)), ["@you.com", "@spam.net"])); auto m2 = matchFn("First line\nSecond line",regex(".*$","gm")); assert(equal(map!"a[0]"(m2), ["First line", "", "Second line"])); auto m2a = matchFn("First line\nSecond line",regex(".+$","gm")); assert(equal(map!"a[0]"(m2a), ["First line", "Second line"])); auto m2b = matchFn("First line\nSecond line",regex(".+?$","gm")); assert(equal(map!"a[0]"(m2b), ["First line", "Second line"])); debug(std_regex_test) writeln("!!! FReD FLAGS test done "~matchFn.stringof~" !!!"); } test_body!bmatch(); test_body!match(); } //tests for accumulated std.regex issues and other regressions unittest { void test_body(alias matchFn)() { //issue 5857 //matching goes out of control if ... in (...){x} has .*/.+ auto c = matchFn("axxxzayyyyyzd",regex("(a.*z){2}d")).captures; assert(c[0] == "axxxzayyyyyzd"); assert(c[1] == "ayyyyyz"); auto c2 = matchFn("axxxayyyyyd",regex("(a.*){2}d")).captures; assert(c2[0] == "axxxayyyyyd"); assert(c2[1] == "ayyyyy"); //issue 2108 //greedy vs non-greedy auto nogreed = regex(""); assert(matchFn("texttext", nogreed).hit == "text"); auto greed = regex(""); assert(matchFn("texttext", greed).hit == "texttext"); //issue 4574 //empty successful match still advances the input string[] pres, posts, hits; foreach(m; matchFn("abcabc", regex("","g"))) { pres ~= m.pre; posts ~= m.post; assert(m.hit.empty); } auto heads = [ "abcabc", "abcab", "abca", "abc", "ab", "a", "" ]; auto tails = [ "abcabc", "bcabc", "cabc", "abc", "bc", "c", "" ]; assert(pres == array(retro(heads))); assert(posts == tails); //issue 6076 //regression on .* auto re = regex("c.*|d"); auto m = matchFn("mm", re); assert(!m); debug(std_regex_test) writeln("!!! FReD REGRESSION test done "~matchFn.stringof~" !!!"); auto rprealloc = regex(`((.){5}.{1,10}){5}`); auto arr = array(repeat('0',100)); auto m2 = matchFn(arr, rprealloc); assert(m2); assert(collectException( regex(r"^(import|file|binary|config)\s+([^\(]+)\(?([^\)]*)\)?\s*$") ) is null); foreach(ch; [Escapables]) { assert(match(to!string(ch),regex(`[\`~ch~`]`))); assert(!match(to!string(ch),regex(`[^\`~ch~`]`))); assert(match(to!string(ch),regex(`[\`~ch~`-\`~ch~`]`))); } //bugzilla 7718 string strcmd = "./myApp.rb -os OSX -path \"/GIT/Ruby Apps/sec\" -conf 'notimer'"; auto reStrCmd = regex (`(".*")|('.*')`, "g"); assert(equal(map!"a[0]"(matchFn(strcmd, reStrCmd)), [`"/GIT/Ruby Apps/sec"`, `'notimer'`])); } test_body!bmatch(); test_body!match(); } // tests for replace unittest { void test(alias matchFn)() { import std.uni : toUpper; foreach(i, v; AliasSeq!(string, wstring, dstring)) { auto baz(Cap)(Cap m) if (is(Cap == Captures!(Cap.String))) { return toUpper(m.hit); } alias String = v; assert(std.regex.replace!(matchFn)(to!String("ark rapacity"), regex(to!String("r")), to!String("c")) == to!String("ack rapacity")); assert(std.regex.replace!(matchFn)(to!String("ark rapacity"), regex(to!String("r"), "g"), to!String("c")) == to!String("ack capacity")); assert(std.regex.replace!(matchFn)(to!String("noon"), regex(to!String("^n")), to!String("[$&]")) == to!String("[n]oon")); assert(std.regex.replace!(matchFn)(to!String("test1 test2"), regex(to!String(`\w+`),"g"), to!String("$`:$'")) == to!String(": test2 test1 :")); auto s = std.regex.replace!(baz!(Captures!(String)))(to!String("Strap a rocket engine on a chicken."), regex(to!String("[ar]"), "g")); assert(s == "StRAp A Rocket engine on A chicken."); } debug(std_regex_test) writeln("!!! Replace test done "~matchFn.stringof~" !!!"); } test!(bmatch)(); test!(match)(); } // tests for splitter unittest { auto s1 = ", abc, de, fg, hi, "; auto sp1 = splitter(s1, regex(", *")); auto w1 = ["", "abc", "de", "fg", "hi", ""]; assert(equal(sp1, w1)); auto s2 = ", abc, de, fg, hi"; auto sp2 = splitter(s2, regex(", *")); auto w2 = ["", "abc", "de", "fg", "hi"]; uint cnt; foreach(e; sp2) { assert(w2[cnt++] == e); } assert(equal(sp2, w2)); } unittest { char[] s1 = ", abc, de, fg, hi, ".dup; auto sp2 = splitter(s1, regex(", *")); } unittest { auto s1 = ", abc, de, fg, hi, "; auto w1 = ["", "abc", "de", "fg", "hi", ""]; assert(equal(split(s1, regex(", *")), w1[])); } unittest { // bugzilla 7141 string pattern = `[a\--b]`; assert(match("-", pattern)); assert(match("b", pattern)); string pattern2 = `[&-z]`; assert(match("b", pattern2)); } unittest {//bugzilla 7111 assert(match("", regex("^"))); } unittest {//bugzilla 7300 assert(!match("a"d, "aa"d)); } unittest {//bugzilla 7674 assert("1234".replace(regex("^"), "$$") == "$1234"); assert("hello?".replace(regex(r"\?", "g"), r"\?") == r"hello\?"); assert("hello?".replace(regex(r"\?", "g"), r"\\?") != r"hello\?"); } unittest {// bugzilla 7679 foreach(S; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 enum re = ctRegex!(to!S(r"\.")); auto str = to!S("a.b"); assert(equal(std.regex.splitter(str, re), [to!S("a"), to!S("b")])); assert(split(str, re) == [to!S("a"), to!S("b")]); }(); } unittest {//bugzilla 8203 string data = " NAME = XPAW01_STA:STATION NAME = XPAW01_STA "; auto uniFileOld = data; auto r = regex( r"^NAME = (?P[a-zA-Z0-9_]+):*(?P[a-zA-Z0-9_]*)","gm"); auto uniCapturesNew = match(uniFileOld, r); for(int i = 0; i < 20; i++) foreach (matchNew; uniCapturesNew) {} //a second issue with same symptoms auto r2 = regex(`([а-яА-Я\-_]+\s*)+(?<=[\s\.,\^])`); match("аллея Театральная", r2); } unittest {// bugzilla 8637 purity of enforce auto m = match("hello world", regex("world")); enforce(m); } // bugzilla 8725 unittest { static italic = regex( r"\* (?!\s+) (.*?) (?!\s+) \*", "gx" ); string input = "this * is* interesting, *very* interesting"; assert(replace(input, italic, "$1") == "this * is* interesting, very interesting"); } // bugzilla 8349 unittest { enum peakRegexStr = r"\>(wgEncode.*Tfbs.*\.(?:narrow)|(?:broad)Peak.gz)"; enum peakRegex = ctRegex!(peakRegexStr); //note that the regex pattern itself is probably bogus assert(match(r"\>wgEncode-blah-Tfbs.narrow", peakRegex)); } // bugzilla 9211 unittest { auto rx_1 = regex(r"^(\w)*(\d)"); auto m = match("1234", rx_1); assert(equal(m.front, ["1234", "3", "4"])); auto rx_2 = regex(r"^([0-9])*(\d)"); auto m2 = match("1234", rx_2); assert(equal(m2.front, ["1234", "3", "4"])); } // bugzilla 9280 unittest { string tomatch = "a!b@c"; static r = regex(r"^(?P.*?)!(?P.*?)@(?P.*?)$"); auto nm = match(tomatch, r); assert(nm); auto c = nm.captures; assert(c[1] == "a"); assert(c["nick"] == "a"); } // bugzilla 9579 unittest { char[] input = ['a', 'b', 'c']; string format = "($1)"; // used to give a compile error: auto re = regex(`(a)`, "g"); auto r = replace(input, re, format); assert(r == "(a)bc"); } // bugzilla 9634 unittest { auto re = ctRegex!"(?:a+)"; assert(match("aaaa", re).hit == "aaaa"); } //bugzilla 10798 unittest { auto cr = ctRegex!("[abcd--c]*"); auto m = "abc".match(cr); assert(m); assert(m.hit == "ab"); } // bugzilla 10913 unittest { @system static string foo(const(char)[] s) { return s.dup; } @safe static string bar(const(char)[] s) { return s.dup; } () @system { replace!((a) => foo(a.hit))("blah", regex(`a`)); }(); () @safe { replace!((a) => bar(a.hit))("blah", regex(`a`)); }(); } // bugzilla 11262 unittest { enum reg = ctRegex!(r",", "g"); auto str = "This,List"; str = str.replace(reg, "-"); assert(str == "This-List"); } // bugzilla 11775 unittest { assert(collectException(regex("a{1,0}"))); } // bugzilla 11839 unittest { assert(regex(`(?P\w+)`).namedCaptures.equal(["var1"])); assert(collectException(regex(`(?P<1>\w+)`))); assert(regex(`(?P\w+)`).namedCaptures.equal(["v1"])); assert(regex(`(?P<__>\w+)`).namedCaptures.equal(["__"])); assert(regex(`(?P<я>\w+)`).namedCaptures.equal(["я"])); } // bugzilla 12076 unittest { auto RE = ctRegex!(r"(?abc)`); assert(collectException("abc".matchFirst(r)["b"])); } // bugzilla 12691 unittest { assert(bmatch("e@", "^([a-z]|)*$").empty); assert(bmatch("e@", ctRegex!`^([a-z]|)*$`).empty); } //bugzilla 12713 unittest { assertThrown(regex("[[a-z]([a-z]|(([[a-z])))")); } //bugzilla 12747 unittest { assertThrown(regex(`^x(\1)`)); assertThrown(regex(`^(x(\1))`)); assertThrown(regex(`^((x)(?=\1))`)); } // bugzilla 14529 unittest { auto ctPat2 = regex(r"^[CDF]$", "i"); foreach(v; ["C", "c", "D", "d", "F", "f"]) assert(matchAll(v, ctPat2).front.hit == v); } ldc-1.1.0-beta3-src/runtime/phobos/std/regex/internal/backtracking.d0000664000175000017500000014370612776215007023437 0ustar kaikai/* Implementation of backtracking std.regex engine. Contains both compile-time and run-time versions. */ module std.regex.internal.backtracking; package(std.regex): import std.regex.internal.ir; import std.range, std.typecons, std.traits, core.stdc.stdlib; /+ BacktrackingMatcher implements backtracking scheme of matching regular expressions. +/ template BacktrackingMatcher(bool CTregex) { @trusted struct BacktrackingMatcher(Char, Stream = Input!Char) if(is(Char : dchar)) { alias DataIndex = Stream.DataIndex; struct State {//top bit in pc is set if saved along with matches DataIndex index; uint pc, counter, infiniteNesting; } static assert(State.sizeof % size_t.sizeof == 0); enum stateSize = State.sizeof / size_t.sizeof; enum initialStack = 1<<11; // items in a block of segmented stack alias String = const(Char)[]; alias RegEx = Regex!Char; alias MatchFn = bool function (ref BacktrackingMatcher!(Char, Stream)); RegEx re; //regex program static if(CTregex) MatchFn nativeFn; //native code for that program //Stream state Stream s; DataIndex index; dchar front; bool exhausted; //backtracking machine state uint pc, counter; DataIndex lastState = 0; //top of state stack DataIndex[] trackers; static if(!CTregex) uint infiniteNesting; size_t[] memory; //local slice of matches, global for backref Group!DataIndex[] matches, backrefed; static if(__traits(hasMember,Stream, "search")) { enum kicked = true; } else enum kicked = false; static size_t initialMemory(const ref RegEx re) { return (re.ngroup+1)*DataIndex.sizeof //trackers + stackSize(re)*size_t.sizeof; } static size_t stackSize(const ref RegEx re) { return initialStack*(stateSize + re.ngroup*(Group!DataIndex).sizeof/size_t.sizeof)+1; } @property bool atStart(){ return index == 0; } @property bool atEnd(){ return index == s.lastIndex && s.atEnd; } void next() { if(!s.nextChar(front, index)) index = s.lastIndex; } void search() { static if(kicked) { if(!s.search(re.kickstart, front, index)) { index = s.lastIndex; } } else next(); } // void newStack() { auto chunk = mallocArray!(size_t)(stackSize(re)); chunk[0] = cast(size_t)(memory.ptr); memory = chunk[1..$]; } void initExternalMemory(void[] memBlock) { trackers = arrayInChunk!(DataIndex)(re.ngroup+1, memBlock); memory = cast(size_t[])memBlock; memory[0] = 0; //hidden pointer memory = memory[1..$]; } void initialize(ref RegEx program, Stream stream, void[] memBlock) { re = program; s = stream; exhausted = false; initExternalMemory(memBlock); backrefed = null; } auto dupTo(void[] memory) { typeof(this) tmp = this; tmp.initExternalMemory(memory); return tmp; } this(ref RegEx program, Stream stream, void[] memBlock, dchar ch, DataIndex idx) { initialize(program, stream, memBlock); front = ch; index = idx; } this(ref RegEx program, Stream stream, void[] memBlock) { initialize(program, stream, memBlock); next(); } auto fwdMatcher(ref BacktrackingMatcher matcher, void[] memBlock) { alias BackMatcherTempl = .BacktrackingMatcher!(CTregex); alias BackMatcher = BackMatcherTempl!(Char, Stream); auto fwdMatcher = BackMatcher(matcher.re, s, memBlock, front, index); return fwdMatcher; } auto bwdMatcher(ref BacktrackingMatcher matcher, void[] memBlock) { alias BackMatcherTempl = .BacktrackingMatcher!(CTregex); alias BackMatcher = BackMatcherTempl!(Char, typeof(s.loopBack(index))); auto fwdMatcher = BackMatcher(matcher.re, s.loopBack(index), memBlock); return fwdMatcher; } // bool matchFinalize() { size_t start = index; if(matchImpl()) {//stream is updated here matches[0].begin = start; matches[0].end = index; if(!(re.flags & RegexOption.global) || atEnd) exhausted = true; if(start == index)//empty match advances input next(); return true; } else return false; } //lookup next match, fill matches with indices into input bool match(Group!DataIndex[] matches) { debug(std_regex_matcher) { writeln("------------------------------------------"); } if(exhausted) //all matches collected return false; this.matches = matches; if(re.flags & RegexInfo.oneShot) { exhausted = true; DataIndex start = index; auto m = matchImpl(); if(m) { matches[0].begin = start; matches[0].end = index; } return m; } static if(kicked) { if(!re.kickstart.empty) { for(;;) { if(matchFinalize()) return true; else { if(atEnd) break; search(); if(atEnd) { exhausted = true; return matchFinalize(); } } } exhausted = true; return false; //early return } } //no search available - skip a char at a time for(;;) { if(matchFinalize()) return true; else { if(atEnd) break; next(); if(atEnd) { exhausted = true; return matchFinalize(); } } } exhausted = true; return false; } /+ match subexpression against input, results are stored in matches +/ bool matchImpl() { static if(CTregex && is(typeof(nativeFn(this)))) { debug(std_regex_ctr) writeln("using C-T matcher"); return nativeFn(this); } else { pc = 0; counter = 0; lastState = 0; infiniteNesting = -1;//intentional auto start = s._index; debug(std_regex_matcher) writeln("Try match starting at ", s[index..s.lastIndex]); for(;;) { debug(std_regex_matcher) writefln("PC: %s\tCNT: %s\t%s \tfront: %s src: %s", pc, counter, disassemble(re.ir, pc, re.dict), front, s._index); switch(re.ir[pc].code) { case IR.OrChar://assumes IRL!(OrChar) == 1 if(atEnd) goto L_backtrack; uint len = re.ir[pc].sequence; uint end = pc + len; if(re.ir[pc].data != front && re.ir[pc+1].data != front) { for(pc = pc+2; pc < end; pc++) if(re.ir[pc].data == front) break; if(pc == end) goto L_backtrack; } pc = end; next(); break; case IR.Char: if(atEnd || front != re.ir[pc].data) goto L_backtrack; pc += IRL!(IR.Char); next(); break; case IR.Any: if(atEnd || (!(re.flags & RegexOption.singleline) && (front == '\r' || front == '\n'))) goto L_backtrack; pc += IRL!(IR.Any); next(); break; case IR.CodepointSet: if(atEnd || !re.charsets[re.ir[pc].data].scanFor(front)) goto L_backtrack; next(); pc += IRL!(IR.CodepointSet); break; case IR.Trie: if(atEnd || !re.tries[re.ir[pc].data][front]) goto L_backtrack; next(); pc += IRL!(IR.Trie); break; case IR.Wordboundary: dchar back; DataIndex bi; //at start & end of input if(atStart && wordTrie[front]) { pc += IRL!(IR.Wordboundary); break; } else if(atEnd && s.loopBack(index).nextChar(back, bi) && wordTrie[back]) { pc += IRL!(IR.Wordboundary); break; } else if(s.loopBack(index).nextChar(back, bi)) { bool af = wordTrie[front]; bool ab = wordTrie[back]; if(af ^ ab) { pc += IRL!(IR.Wordboundary); break; } } goto L_backtrack; case IR.Notwordboundary: dchar back; DataIndex bi; //at start & end of input if(atStart && wordTrie[front]) goto L_backtrack; else if(atEnd && s.loopBack(index).nextChar(back, bi) && wordTrie[back]) goto L_backtrack; else if(s.loopBack(index).nextChar(back, bi)) { bool af = wordTrie[front]; bool ab = wordTrie[back]; if(af ^ ab) goto L_backtrack; } pc += IRL!(IR.Wordboundary); break; case IR.Bol: dchar back; DataIndex bi; if(atStart) pc += IRL!(IR.Bol); else if((re.flags & RegexOption.multiline) && s.loopBack(index).nextChar(back,bi) && endOfLine(back, front == '\n')) { pc += IRL!(IR.Bol); } else goto L_backtrack; break; case IR.Eol: dchar back; DataIndex bi; debug(std_regex_matcher) writefln("EOL (front 0x%x) %s", front, s[index..s.lastIndex]); //no matching inside \r\n if(atEnd || ((re.flags & RegexOption.multiline) && endOfLine(front, s.loopBack(index).nextChar(back,bi) && back == '\r'))) { pc += IRL!(IR.Eol); } else goto L_backtrack; break; case IR.InfiniteStart, IR.InfiniteQStart: trackers[infiniteNesting+1] = index; pc += re.ir[pc].data + IRL!(IR.InfiniteStart); //now pc is at end IR.Infininite(Q)End uint len = re.ir[pc].data; int test; if(re.ir[pc].code == IR.InfiniteEnd) { test = quickTestFwd(pc+IRL!(IR.InfiniteEnd), front, re); if(test >= 0) pushState(pc+IRL!(IR.InfiniteEnd), counter); infiniteNesting++; pc -= len; } else { test = quickTestFwd(pc - len, front, re); if(test >= 0) { infiniteNesting++; pushState(pc - len, counter); infiniteNesting--; } pc += IRL!(IR.InfiniteEnd); } break; case IR.RepeatStart, IR.RepeatQStart: pc += re.ir[pc].data + IRL!(IR.RepeatStart); break; case IR.RepeatEnd: case IR.RepeatQEnd: //len, step, min, max uint len = re.ir[pc].data; uint step = re.ir[pc+2].raw; uint min = re.ir[pc+3].raw; uint max = re.ir[pc+4].raw; if(counter < min) { counter += step; pc -= len; } else if(counter < max) { if(re.ir[pc].code == IR.RepeatEnd) { pushState(pc + IRL!(IR.RepeatEnd), counter%step); counter += step; pc -= len; } else { pushState(pc - len, counter + step); counter = counter%step; pc += IRL!(IR.RepeatEnd); } } else { counter = counter%step; pc += IRL!(IR.RepeatEnd); } break; case IR.InfiniteEnd: case IR.InfiniteQEnd: uint len = re.ir[pc].data; debug(std_regex_matcher) writeln("Infinited nesting:", infiniteNesting); assert(infiniteNesting < trackers.length); if(trackers[infiniteNesting] == index) {//source not consumed pc += IRL!(IR.InfiniteEnd); infiniteNesting--; break; } else trackers[infiniteNesting] = index; int test; if(re.ir[pc].code == IR.InfiniteEnd) { test = quickTestFwd(pc+IRL!(IR.InfiniteEnd), front, re); if(test >= 0) { infiniteNesting--; pushState(pc + IRL!(IR.InfiniteEnd), counter); infiniteNesting++; } pc -= len; } else { test = quickTestFwd(pc-len, front, re); if(test >= 0) pushState(pc-len, counter); pc += IRL!(IR.InfiniteEnd); infiniteNesting--; } break; case IR.OrEnd: pc += IRL!(IR.OrEnd); break; case IR.OrStart: pc += IRL!(IR.OrStart); goto case; case IR.Option: uint len = re.ir[pc].data; if(re.ir[pc+len].code == IR.GotoEndOr)//not a last one { pushState(pc + len + IRL!(IR.Option), counter); //remember 2nd branch } pc += IRL!(IR.Option); break; case IR.GotoEndOr: pc = pc + re.ir[pc].data + IRL!(IR.GotoEndOr); break; case IR.GroupStart: uint n = re.ir[pc].data; matches[n].begin = index; debug(std_regex_matcher) writefln("IR group #%u starts at %u", n, index); pc += IRL!(IR.GroupStart); break; case IR.GroupEnd: uint n = re.ir[pc].data; matches[n].end = index; debug(std_regex_matcher) writefln("IR group #%u ends at %u", n, index); pc += IRL!(IR.GroupEnd); break; case IR.LookaheadStart: case IR.NeglookaheadStart: uint len = re.ir[pc].data; auto save = index; uint ms = re.ir[pc+1].raw, me = re.ir[pc+2].raw; auto mem = malloc(initialMemory(re))[0..initialMemory(re)]; scope(exit) free(mem.ptr); static if(Stream.isLoopback) { auto matcher = bwdMatcher(this, mem); } else { auto matcher = fwdMatcher(this, mem); } matcher.matches = matches[ms .. me]; matcher.backrefed = backrefed.empty ? matches : backrefed; matcher.re.ir = re.ir[pc+IRL!(IR.LookaheadStart) .. pc+IRL!(IR.LookaheadStart)+len+IRL!(IR.LookaheadEnd)]; bool match = matcher.matchImpl() ^ (re.ir[pc].code == IR.NeglookaheadStart); s.reset(save); next(); if(!match) goto L_backtrack; else { pc += IRL!(IR.LookaheadStart)+len+IRL!(IR.LookaheadEnd); } break; case IR.LookbehindStart: case IR.NeglookbehindStart: uint len = re.ir[pc].data; uint ms = re.ir[pc+1].raw, me = re.ir[pc+2].raw; auto mem = malloc(initialMemory(re))[0..initialMemory(re)]; scope(exit) free(mem.ptr); static if(Stream.isLoopback) { alias Matcher = BacktrackingMatcher!(Char, Stream); auto matcher = Matcher(re, s, mem, front, index); } else { alias Matcher = BacktrackingMatcher!(Char, typeof(s.loopBack(index))); auto matcher = Matcher(re, s.loopBack(index), mem); } matcher.matches = matches[ms .. me]; matcher.re.ir = re.ir[pc + IRL!(IR.LookbehindStart) .. pc + IRL!(IR.LookbehindStart) + len + IRL!(IR.LookbehindEnd)]; matcher.backrefed = backrefed.empty ? matches : backrefed; bool match = matcher.matchImpl() ^ (re.ir[pc].code == IR.NeglookbehindStart); if(!match) goto L_backtrack; else { pc += IRL!(IR.LookbehindStart)+len+IRL!(IR.LookbehindEnd); } break; case IR.Backref: uint n = re.ir[pc].data; auto referenced = re.ir[pc].localRef ? s[matches[n].begin .. matches[n].end] : s[backrefed[n].begin .. backrefed[n].end]; while(!atEnd && !referenced.empty && front == referenced.front) { next(); referenced.popFront(); } if(referenced.empty) pc++; else goto L_backtrack; break; case IR.Nop: pc += IRL!(IR.Nop); break; case IR.LookaheadEnd: case IR.NeglookaheadEnd: case IR.LookbehindEnd: case IR.NeglookbehindEnd: case IR.End: return true; default: debug printBytecode(re.ir[0..$]); assert(0); L_backtrack: if(!popState()) { s.reset(start); return false; } } } } assert(0); } @property size_t stackAvail() { return memory.length - lastState; } bool prevStack() { import core.stdc.stdlib; size_t* prev = memory.ptr-1; prev = cast(size_t*)*prev;//take out hidden pointer if(!prev) return false; free(memory.ptr);//last segment is freed in RegexMatch immutable size = initialStack*(stateSize + 2*re.ngroup); memory = prev[0..size]; lastState = size; return true; } void stackPush(T)(T val) if(!isDynamicArray!T) { *cast(T*)&memory[lastState] = val; enum delta = (T.sizeof+size_t.sizeof/2)/size_t.sizeof; lastState += delta; debug(std_regex_matcher) writeln("push element SP= ", lastState); } void stackPush(T)(T[] val) { static assert(T.sizeof % size_t.sizeof == 0); (cast(T*)&memory[lastState])[0..val.length] = val[0..$]; lastState += val.length*(T.sizeof/size_t.sizeof); debug(std_regex_matcher) writeln("push array SP= ", lastState); } void stackPop(T)(ref T val) if(!isDynamicArray!T) { enum delta = (T.sizeof+size_t.sizeof/2)/size_t.sizeof; lastState -= delta; val = *cast(T*)&memory[lastState]; debug(std_regex_matcher) writeln("pop element SP= ", lastState); } void stackPop(T)(T[] val) { stackPop(val); // call ref version } void stackPop(T)(ref T[] val) { lastState -= val.length*(T.sizeof/size_t.sizeof); val[0..$] = (cast(T*)&memory[lastState])[0..val.length]; debug(std_regex_matcher) writeln("pop array SP= ", lastState); } static if(!CTregex) { //helper function, saves engine state void pushState(uint pc, uint counter) { if(stateSize + trackers.length + matches.length > stackAvail) { newStack(); lastState = 0; } *cast(State*)&memory[lastState] = State(index, pc, counter, infiniteNesting); lastState += stateSize; memory[lastState .. lastState + 2 * matches.length] = (cast(size_t[])matches)[]; lastState += 2*matches.length; if(trackers.length) { memory[lastState .. lastState + trackers.length] = trackers[]; lastState += trackers.length; } debug(std_regex_matcher) writefln("Saved(pc=%s) front: %s src: %s", pc, front, s[index..s.lastIndex]); } //helper function, restores engine state bool popState() { if(!lastState) return prevStack(); if (trackers.length) { lastState -= trackers.length; trackers[] = memory[lastState .. lastState + trackers.length]; } lastState -= 2*matches.length; auto pm = cast(size_t[])matches; pm[] = memory[lastState .. lastState + 2 * matches.length]; lastState -= stateSize; State* state = cast(State*)&memory[lastState]; index = state.index; pc = state.pc; counter = state.counter; infiniteNesting = state.infiniteNesting; debug(std_regex_matcher) { writefln("Restored matches", front, s[index .. s.lastIndex]); foreach(i, m; matches) writefln("Sub(%d) : %s..%s", i, m.begin, m.end); } s.reset(index); next(); debug(std_regex_matcher) writefln("Backtracked (pc=%s) front: %s src: %s", pc, front, s[index..s.lastIndex]); return true; } } } } //very shitty string formatter, $$ replaced with next argument converted to string @trusted string ctSub( U...)(string format, U args) { import std.conv; bool seenDollar; foreach(i, ch; format) { if(ch == '$') { if(seenDollar) { static if(args.length > 0) { return format[0 .. i - 1] ~ to!string(args[0]) ~ ctSub(format[i + 1 .. $], args[1 .. $]); } else assert(0); } else seenDollar = true; } else seenDollar = false; } return format; } alias Sequence(int B, int E) = staticIota!(B, E); struct CtContext { import std.conv; //dirty flags bool counter, infNesting; // to make a unique advancement counter per nesting level of loops int curInfLoop, nInfLoops; //to mark the portion of matches to save int match, total_matches; int reserved; //state of codegenerator struct CtState { string code; int addr; } this(Char)(Regex!Char re) { match = 1; reserved = 1; //first match is skipped total_matches = re.ngroup; } CtContext lookaround(uint s, uint e) { CtContext ct; ct.total_matches = e - s; ct.match = 1; return ct; } //restore state having current context string restoreCode() { string text; //stack is checked in L_backtrack text ~= counter ? " stackPop(counter);" : " counter = 0;"; if(infNesting) { text ~= ctSub(` stackPop(trackers[0..$$]); `, curInfLoop + 1); } if(match < total_matches) { text ~= ctSub(" stackPop(matches[$$..$$]);", reserved, match); text ~= ctSub(" matches[$$..$] = typeof(matches[0]).init;", match); } else text ~= ctSub(" stackPop(matches[$$..$]);", reserved); return text; } //save state having current context string saveCode(uint pc, string count_expr="counter") { string text = ctSub(" if(stackAvail < $$*(Group!(DataIndex)).sizeof/size_t.sizeof + trackers.length + $$) { newStack(); lastState = 0; }", match - reserved, cast(int)counter + 2); if(match < total_matches) text ~= ctSub(" stackPush(matches[$$..$$]);", reserved, match); else text ~= ctSub(" stackPush(matches[$$..$]);", reserved); if(infNesting) { text ~= ctSub(` stackPush(trackers[0..$$]); `, curInfLoop + 1); } text ~= counter ? ctSub(" stackPush($$);", count_expr) : ""; text ~= ctSub(" stackPush(index); stackPush($$); \n", pc); return text; } // CtState ctGenBlock(Bytecode[] ir, int addr) { CtState result; result.addr = addr; while(!ir.empty) { auto n = ctGenGroup(ir, result.addr); result.code ~= n.code; result.addr = n.addr; } return result; } // CtState ctGenGroup(ref Bytecode[] ir, int addr) { import std.algorithm : max; auto bailOut = "goto L_backtrack;"; auto nextInstr = ctSub("goto case $$;", addr+1); CtState r; assert(!ir.empty); switch(ir[0].code) { case IR.InfiniteStart, IR.InfiniteQStart, IR.RepeatStart, IR.RepeatQStart: bool infLoop = ir[0].code == IR.InfiniteStart || ir[0].code == IR.InfiniteQStart; infNesting = infNesting || infLoop; if(infLoop) { curInfLoop++; nInfLoops = max(nInfLoops, curInfLoop+1); } counter = counter || ir[0].code == IR.RepeatStart || ir[0].code == IR.RepeatQStart; uint len = ir[0].data; auto nir = ir[ir[0].length .. ir[0].length+len]; r = ctGenBlock(nir, addr+1); if(infLoop) curInfLoop--; //start/end codegen //r.addr is at last test+ jump of loop, addr+1 is body of loop nir = ir[ir[0].length + len .. $]; r.code = ctGenFixupCode(ir[0..ir[0].length], addr, r.addr) ~ r.code; r.code ~= ctGenFixupCode(nir, r.addr, addr+1); r.addr += 2; //account end instruction + restore state ir = nir; break; case IR.OrStart: uint len = ir[0].data; auto nir = ir[ir[0].length .. ir[0].length+len]; r = ctGenAlternation(nir, addr); ir = ir[ir[0].length + len .. $]; assert(ir[0].code == IR.OrEnd); ir = ir[ir[0].length..$]; break; case IR.LookaheadStart: case IR.NeglookaheadStart: case IR.LookbehindStart: case IR.NeglookbehindStart: uint len = ir[0].data; bool behind = ir[0].code == IR.LookbehindStart || ir[0].code == IR.NeglookbehindStart; bool negative = ir[0].code == IR.NeglookaheadStart || ir[0].code == IR.NeglookbehindStart; string fwdType = "typeof(fwdMatcher(matcher, []))"; string bwdType = "typeof(bwdMatcher(matcher, []))"; string fwdCreate = "fwdMatcher(matcher, mem)"; string bwdCreate = "bwdMatcher(matcher, mem)"; uint start = IRL!(IR.LookbehindStart); uint end = IRL!(IR.LookbehindStart)+len+IRL!(IR.LookaheadEnd); CtContext context = lookaround(ir[1].raw, ir[2].raw); //split off new context auto slice = ir[start .. end]; r.code ~= ctSub(` case $$: //fake lookaround "atom" static if(typeof(matcher.s).isLoopback) alias Lookaround = $$; else alias Lookaround = $$; static bool matcher_$$(ref Lookaround matcher) @trusted { //(neg)lookaround piece start $$ //(neg)lookaround piece ends } auto save = index; auto mem = malloc(initialMemory(re))[0..initialMemory(re)]; scope(exit) free(mem.ptr); static if(typeof(matcher.s).isLoopback) auto lookaround = $$; else auto lookaround = $$; lookaround.matches = matches[$$..$$]; lookaround.backrefed = backrefed.empty ? matches : backrefed; lookaround.nativeFn = &matcher_$$; //hookup closure's binary code bool match = $$; s.reset(save); next(); if(match) $$ else $$`, addr, behind ? fwdType : bwdType, behind ? bwdType : fwdType, addr, context.ctGenRegEx(slice), behind ? fwdCreate : bwdCreate, behind ? bwdCreate : fwdCreate, ir[1].raw, ir[2].raw, //start - end of matches slice addr, negative ? "!lookaround.matchImpl()" : "lookaround.matchImpl()", nextInstr, bailOut); ir = ir[end .. $]; r.addr = addr + 1; break; case IR.LookaheadEnd: case IR.NeglookaheadEnd: case IR.LookbehindEnd: case IR.NeglookbehindEnd: ir = ir[IRL!(IR.LookaheadEnd) .. $]; r.addr = addr; break; default: assert(ir[0].isAtom, text(ir[0].mnemonic)); r = ctGenAtom(ir, addr); } return r; } //generate source for bytecode contained in OrStart ... OrEnd CtState ctGenAlternation(Bytecode[] ir, int addr) { CtState[] pieces; CtState r; enum optL = IRL!(IR.Option); for(;;) { assert(ir[0].code == IR.Option); auto len = ir[0].data; if(optL+len < ir.length && ir[optL+len].code == IR.Option)//not a last option { auto nir = ir[optL .. optL+len-IRL!(IR.GotoEndOr)]; r = ctGenBlock(nir, addr+2);//space for Option + restore state //r.addr+1 to account GotoEndOr at end of branch r.code = ctGenFixupCode(ir[0 .. ir[0].length], addr, r.addr+1) ~ r.code; addr = r.addr+1;//leave space for GotoEndOr pieces ~= r; ir = ir[optL + len .. $]; } else { pieces ~= ctGenBlock(ir[optL..$], addr); addr = pieces[$-1].addr; break; } } r = pieces[0]; for(uint i = 1; i < pieces.length; i++) { r.code ~= ctSub(` case $$: goto case $$; `, pieces[i-1].addr, addr); r.code ~= pieces[i].code; } r.addr = addr; return r; } // generate fixup code for instruction in ir, // fixup means it has an alternative way for control flow string ctGenFixupCode(Bytecode[] ir, int addr, int fixup) { return ctGenFixupCode(ir, addr, fixup); // call ref Bytecode[] version } string ctGenFixupCode(ref Bytecode[] ir, int addr, int fixup) { string r; string testCode; r = ctSub(` case $$: debug(std_regex_matcher) writeln("#$$");`, addr, addr); switch(ir[0].code) { case IR.InfiniteStart, IR.InfiniteQStart: r ~= ctSub( ` trackers[$$] = DataIndex.max; goto case $$;`, curInfLoop, fixup); ir = ir[ir[0].length..$]; break; case IR.InfiniteEnd: testCode = ctQuickTest(ir[IRL!(IR.InfiniteEnd) .. $],addr + 1); r ~= ctSub( ` if(trackers[$$] == index) {//source not consumed goto case $$; } trackers[$$] = index; $$ { $$ } goto case $$; case $$: //restore state and go out of loop $$ goto case;`, curInfLoop, addr+2, curInfLoop, testCode, saveCode(addr+1), fixup, addr+1, restoreCode()); ir = ir[ir[0].length..$]; break; case IR.InfiniteQEnd: testCode = ctQuickTest(ir[IRL!(IR.InfiniteEnd) .. $],addr + 1); auto altCode = testCode.length ? ctSub("else goto case $$;", fixup) : ""; r ~= ctSub( ` if(trackers[$$] == index) {//source not consumed goto case $$; } trackers[$$] = index; $$ { $$ goto case $$; } $$ case $$://restore state and go inside loop $$ goto case $$;`, curInfLoop, addr+2, curInfLoop, testCode, saveCode(addr+1), addr+2, altCode, addr+1, restoreCode(), fixup); ir = ir[ir[0].length..$]; break; case IR.RepeatStart, IR.RepeatQStart: r ~= ctSub( ` goto case $$;`, fixup); ir = ir[ir[0].length..$]; break; case IR.RepeatEnd, IR.RepeatQEnd: //len, step, min, max uint len = ir[0].data; uint step = ir[2].raw; uint min = ir[3].raw; uint max = ir[4].raw; r ~= ctSub(` if(counter < $$) { debug(std_regex_matcher) writeln("RepeatEnd min case pc=", $$); counter += $$; goto case $$; }`, min, addr, step, fixup); if(ir[0].code == IR.RepeatEnd) { string counter_expr = ctSub("counter % $$", step); r ~= ctSub(` else if(counter < $$) { $$ counter += $$; goto case $$; }`, max, saveCode(addr+1, counter_expr), step, fixup); } else { string counter_expr = ctSub("counter % $$", step); r ~= ctSub(` else if(counter < $$) { $$ counter = counter % $$; goto case $$; }`, max, saveCode(addr+1,counter_expr), step, addr+2); } r ~= ctSub(` else { counter = counter % $$; goto case $$; } case $$: //restore state $$ goto case $$;`, step, addr+2, addr+1, restoreCode(), ir[0].code == IR.RepeatEnd ? addr+2 : fixup ); ir = ir[ir[0].length..$]; break; case IR.Option: r ~= ctSub( ` { $$ } goto case $$; case $$://restore thunk to go to the next group $$ goto case $$;`, saveCode(addr+1), addr+2, addr+1, restoreCode(), fixup); ir = ir[ir[0].length..$]; break; default: assert(0, text(ir[0].mnemonic)); } return r; } string ctQuickTest(Bytecode[] ir, int id) { uint pc = 0; while(pc < ir.length && ir[pc].isAtom) { if(ir[pc].code == IR.GroupStart || ir[pc].code == IR.GroupEnd) { pc++; } else if(ir[pc].code == IR.Backref) break; else { auto code = ctAtomCode(ir[pc..$], -1); return ctSub(` int test_$$() { $$ //$$ } if(test_$$() >= 0)`, id, code.ptr ? code : "return 0;", ir[pc].mnemonic, id); } } return ""; } //process & generate source for simple bytecodes at front of ir using address addr CtState ctGenAtom(ref Bytecode[] ir, int addr) { CtState result; result.code = ctAtomCode(ir, addr); ir.popFrontN(ir[0].code == IR.OrChar ? ir[0].sequence : ir[0].length); result.addr = addr + 1; return result; } //D code for atom at ir using address addr, addr < 0 means quickTest string ctAtomCode(Bytecode[] ir, int addr) { string code; string bailOut, nextInstr; if(addr < 0) { bailOut = "return -1;"; nextInstr = "return 0;"; } else { bailOut = "goto L_backtrack;"; nextInstr = ctSub("goto case $$;", addr+1); code ~= ctSub( ` case $$: debug(std_regex_matcher) writeln("#$$"); `, addr, addr); } switch(ir[0].code) { case IR.OrChar://assumes IRL!(OrChar) == 1 code ~= ctSub(` if(atEnd) $$`, bailOut); uint len = ir[0].sequence; for(uint i = 0; i < len; i++) { code ~= ctSub( ` if(front == $$) { $$ $$ }`, ir[i].data, addr >= 0 ? "next();" :"", nextInstr); } code ~= ctSub( ` $$`, bailOut); break; case IR.Char: code ~= ctSub( ` if(atEnd || front != $$) $$ $$ $$`, ir[0].data, bailOut, addr >= 0 ? "next();" :"", nextInstr); break; case IR.Any: code ~= ctSub( ` if(atEnd || (!(re.flags & RegexOption.singleline) && (front == '\r' || front == '\n'))) $$ $$ $$`, bailOut, addr >= 0 ? "next();" :"",nextInstr); break; case IR.CodepointSet: code ~= ctSub( ` if(atEnd || !re.charsets[$$].scanFor(front)) $$ $$ $$`, ir[0].data, bailOut, addr >= 0 ? "next();" :"", nextInstr); break; case IR.Trie: code ~= ctSub( ` if(atEnd || !re.tries[$$][front]) $$ $$ $$`, ir[0].data, bailOut, addr >= 0 ? "next();" :"", nextInstr); break; case IR.Wordboundary: code ~= ctSub( ` dchar back; DataIndex bi; if(atStart && wordTrie[front]) { $$ } else if(atEnd && s.loopBack(index).nextChar(back, bi) && wordTrie[back]) { $$ } else if(s.loopBack(index).nextChar(back, bi)) { bool af = wordTrie[front]; bool ab = wordTrie[back]; if(af ^ ab) { $$ } } $$`, nextInstr, nextInstr, nextInstr, bailOut); break; case IR.Notwordboundary: code ~= ctSub( ` dchar back; DataIndex bi; //at start & end of input if(atStart && wordTrie[front]) $$ else if(atEnd && s.loopBack(index).nextChar(back, bi) && wordTrie[back]) $$ else if(s.loopBack(index).nextChar(back, bi)) { bool af = wordTrie[front]; bool ab = wordTrie[back]; if(af ^ ab) $$ } $$`, bailOut, bailOut, bailOut, nextInstr); break; case IR.Bol: code ~= ctSub(` dchar back; DataIndex bi; if(atStart || ((re.flags & RegexOption.multiline) && s.loopBack(index).nextChar(back,bi) && endOfLine(back, front == '\n'))) { debug(std_regex_matcher) writeln("BOL matched"); $$ } else $$`, nextInstr, bailOut); break; case IR.Eol: code ~= ctSub(` dchar back; DataIndex bi; debug(std_regex_matcher) writefln("EOL (front 0x%x) %s", front, s[index..s.lastIndex]); //no matching inside \r\n if(atEnd || ((re.flags & RegexOption.multiline) && endOfLine(front, s.loopBack(index).nextChar(back,bi) && back == '\r'))) { debug(std_regex_matcher) writeln("EOL matched"); $$ } else $$`, nextInstr, bailOut); break; case IR.GroupStart: code ~= ctSub(` matches[$$].begin = index; $$`, ir[0].data, nextInstr); match = ir[0].data+1; break; case IR.GroupEnd: code ~= ctSub(` matches[$$].end = index; $$`, ir[0].data, nextInstr); break; case IR.Backref: string mStr = "auto referenced = "; mStr ~= ir[0].localRef ? ctSub("s[matches[$$].begin .. matches[$$].end];", ir[0].data, ir[0].data) : ctSub("s[backrefed[$$].begin .. backrefed[$$].end];", ir[0].data, ir[0].data); code ~= ctSub( ` $$ while(!atEnd && !referenced.empty && front == referenced.front) { next(); referenced.popFront(); } if(referenced.empty) $$ else $$`, mStr, nextInstr, bailOut); break; case IR.Nop: case IR.End: break; default: assert(0, text(ir[0].mnemonic, " is not supported yet")); } return code; } //generate D code for the whole regex public string ctGenRegEx(Bytecode[] ir) { auto bdy = ctGenBlock(ir, 0); auto r = ` import core.stdc.stdlib; with(matcher) { pc = 0; counter = 0; lastState = 0; auto start = s._index;`; r ~= ` goto StartLoop; debug(std_regex_matcher) writeln("Try CT matching starting at ",s[index..s.lastIndex]); L_backtrack: if(lastState || prevStack()) { stackPop(pc); stackPop(index); s.reset(index); next(); } else { s.reset(start); return false; } StartLoop: switch(pc) { `; r ~= bdy.code; r ~= ctSub(` case $$: break;`,bdy.addr); r ~= ` default: assert(0); } return true; } `; return r; } } string ctGenRegExCode(Char)(Regex!Char re) { auto context = CtContext(re); return context.ctGenRegEx(re.ir); } ldc-1.1.0-beta3-src/runtime/phobos/std/concurrency.d0000664000175000017500000021201212776215007020403 0ustar kaikai/** * This is a low-level messaging API upon which more structured or restrictive * APIs may be built. The general idea is that every messageable entity is * represented by a common handle type called a Tid, which allows messages to * be sent to logical threads that are executing in both the current process * and in external processes using the same interface. This is an important * aspect of scalability because it allows the components of a program to be * spread across available resources with few to no changes to the actual * implementation. * * A logical thread is an execution context that has its own stack and which * runs asynchronously to other logical threads. These may be preemptively * scheduled kernel threads, fibers (cooperative user-space threads), or some * other concept with similar behavior. * * The type of concurrency used when logical threads are created is determined * by the Scheduler selected at initialization time. The default behavior is * currently to create a new kernel thread per call to spawn, but other * schedulers are available that multiplex fibers across the main thread or * use some combination of the two approaches. * * Synposis: * --- * import std.stdio; * import std.concurrency; * * void spawnedFunc(Tid ownerTid) * { * // Receive a message from the owner thread. * receive( * (int i) { writeln("Received the number ", i);} * ); * * // Send a message back to the owner thread * // indicating success. * send(ownerTid, true); * } * * void main() * { * // Start spawnedFunc in a new thread. * auto childTid = spawn(&spawnedFunc, thisTid); * * // Send the number 42 to this new thread. * send(childTid, 42); * * // Receive the result code. * auto wasSuccessful = receiveOnly!(bool); * assert(wasSuccessful); * writeln("Successfully printed number."); * } * --- * * Copyright: Copyright Sean Kelly 2009 - 2014. * License: Boost License 1.0. * Authors: Sean Kelly, Alex Rønne Petersen, Martin Nowak * Source: $(PHOBOSSRC std/_concurrency.d) */ /* Copyright Sean Kelly 2009 - 2014. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.concurrency; public { import std.variant; } private { import core.atomic; import core.thread; import core.sync.mutex; import core.sync.condition; import std.algorithm; import std.exception; import std.meta; import std.range; import std.string; import std.traits; import std.typecons; import std.concurrencybase; template hasLocalAliasing(T...) { static if( !T.length ) enum hasLocalAliasing = false; else enum hasLocalAliasing = (std.traits.hasUnsharedAliasing!(T[0]) && !is(T[0] == Tid)) || std.concurrency.hasLocalAliasing!(T[1 .. $]); } enum MsgType { standard, priority, linkDead, } struct Message { MsgType type; Variant data; this(T...)( MsgType t, T vals ) if( T.length < 1 ) { static assert( false, "messages must contain at least one item" ); } this(T...)( MsgType t, T vals ) if( T.length == 1 ) { type = t; data = vals[0]; } this(T...)( MsgType t, T vals ) if( T.length > 1 ) { type = t; data = Tuple!(T)( vals ); } @property auto convertsTo(T...)() { static if( T.length == 1 ) return is( T[0] == Variant ) || data.convertsTo!(T); else return data.convertsTo!(Tuple!(T)); } @property auto get(T...)() { static if( T.length == 1 ) { static if( is( T[0] == Variant ) ) return data; else return data.get!(T); } else { return data.get!(Tuple!(T)); } } auto map(Op)( Op op ) { alias Args = Parameters!(Op); static if( Args.length == 1 ) { static if( is( Args[0] == Variant ) ) return op( data ); else return op( data.get!(Args) ); } else { return op( data.get!(Tuple!(Args)).expand ); } } } void checkops(T...)( T ops ) { foreach( i, t1; T ) { static assert( isFunctionPointer!t1 || isDelegate!t1 ); alias a1 = Parameters!(t1); alias r1 = ReturnType!(t1); static if( i < T.length - 1 && is( r1 == void ) ) { static assert( a1.length != 1 || !is( a1[0] == Variant ), "function with arguments " ~ a1.stringof ~ " occludes successive function" ); foreach( t2; T[i+1 .. $] ) { static assert( isFunctionPointer!t2 || isDelegate!t2 ); alias a2 = Parameters!(t2); static assert( !is( a1 == a2 ), "function with arguments " ~ a1.stringof ~ " occludes successive function" ); } } } } @property ref ThreadInfo thisInfo() { if( scheduler is null ) return ThreadInfo.thisInfo; return scheduler.thisInfo; } } static ~this() { thisInfo.cleanup(); } ////////////////////////////////////////////////////////////////////////////// // Exceptions ////////////////////////////////////////////////////////////////////////////// /** * Thrown on calls to $(D receiveOnly) if a message other than the type * the receiving thread expected is sent. */ class MessageMismatch : Exception { this( string msg = "Unexpected message type" ) { super( msg ); } } /** * Thrown on calls to $(D receive) if the thread that spawned the receiving * thread has terminated and no more messages exist. */ class OwnerTerminated : Exception { this( Tid t, string msg = "Owner terminated" ) { super( msg ); tid = t; } Tid tid; } /** * Thrown if a linked thread has terminated. */ class LinkTerminated : Exception { this( Tid t, string msg = "Link terminated" ) { super( msg ); tid = t; } Tid tid; } /** * Thrown if a message was sent to a thread via * $(XREF concurrency, prioritySend) and the receiver does not have a handler * for a message of this type. */ class PriorityMessageException : Exception { this( Variant vals ) { super( "Priority message" ); message = vals; } /** * The message that was sent. */ Variant message; } /** * Thrown on mailbox crowding if the mailbox is configured with * $(D OnCrowding.throwException). */ class MailboxFull : Exception { this( Tid t, string msg = "Mailbox full" ) { super( msg ); tid = t; } Tid tid; } /** * Thrown when a Tid is missing, e.g. when $(D ownerTid) doesn't * find an owner thread. */ class TidMissingException : Exception { mixin basicExceptionCtors; } ////////////////////////////////////////////////////////////////////////////// // Thread ID ////////////////////////////////////////////////////////////////////////////// /** * An opaque type used to represent a logical thread. */ struct Tid { private: this( MessageBox m ) @safe { mbox = m; } MessageBox mbox; public: /** * Generate a convenient string for identifying this Tid. This is only * useful to see if Tid's that are currently executing are the same or * different, e.g. for logging and debugging. It is potentially possible * that a Tid executed in the future will have the same toString() output * as another Tid that has already terminated. */ void toString(scope void delegate(const(char)[]) sink) { import std.format; formattedWrite(sink, "Tid(%x)", cast(void*)mbox); } } unittest { import std.conv : text; Tid tid; assert(text(tid) == "Tid(0)"); auto tid2 = thisTid; assert(text(tid2) != "Tid(0)"); auto tid3 = tid2; assert(text(tid2) == text(tid3)); } /** * Returns the caller's Tid. */ @property Tid thisTid() @safe { // TODO: remove when concurrency is safe auto trus = delegate() @trusted { if( thisInfo.ident != Tid.init ) return thisInfo.ident; thisInfo.ident = Tid( new MessageBox ); return thisInfo.ident; }; return trus(); } /** * Return the Tid of the thread which spawned the caller's thread. * * Throws: A $(D TidMissingException) exception if * there is no owner thread. */ @property Tid ownerTid() { enforce!TidMissingException(thisInfo.owner.mbox !is null, "Error: Thread has no owner thread."); return thisInfo.owner; } unittest { static void fun() { string res = receiveOnly!string(); assert(res == "Main calling"); ownerTid.send("Child responding"); } assertThrown!TidMissingException(ownerTid); auto child = spawn(&fun); child.send("Main calling"); string res = receiveOnly!string(); assert(res == "Child responding"); } ////////////////////////////////////////////////////////////////////////////// // Thread Creation ////////////////////////////////////////////////////////////////////////////// private template isSpawnable(F, T...) { template isParamsImplicitlyConvertible(F1, F2, int i=0) { alias param1 = Parameters!F1; alias param2 = Parameters!F2; static if (param1.length != param2.length) enum isParamsImplicitlyConvertible = false; else static if (param1.length == i) enum isParamsImplicitlyConvertible = true; else static if (isImplicitlyConvertible!(param2[i], param1[i])) enum isParamsImplicitlyConvertible = isParamsImplicitlyConvertible!(F1, F2, i+1); else enum isParamsImplicitlyConvertible = false; } enum isSpawnable = isCallable!F && is(ReturnType!F == void) && isParamsImplicitlyConvertible!(F, void function(T)) && ( isFunctionPointer!F || !hasUnsharedAliasing!F); } /** * Starts fn(args) in a new logical thread. * * Executes the supplied function in a new logical thread represented by * $(D Tid). The calling thread is designated as the owner of the new thread. * When the owner thread terminates an $(D OwnerTerminated) message will be * sent to the new thread, causing an $(D OwnerTerminated) exception to be * thrown on $(D receive()). * * Params: * fn = The function to execute. * args = Arguments to the function. * * Returns: * A Tid representing the new logical thread. * * Notes: * $(D args) must not have unshared aliasing. In other words, all arguments * to $(D fn) must either be $(D shared) or $(D immutable) or have no * pointer indirection. This is necessary for enforcing isolation among * threads. * * Example: * --- * import std.stdio, std.concurrency; * * void f1(string str) * { * writeln(str); * } * * void f2(char[] str) * { * writeln(str); * } * * void main() * { * auto str = "Hello, world"; * * // Works: string is immutable. * auto tid1 = spawn(&f1, str); * * // Fails: char[] has mutable aliasing. * auto tid2 = spawn(&f2, str.dup); * * // New thread with anonymous function * spawn({ writeln("This is so great!"); }); * } * --- */ Tid spawn(F, T...)( F fn, T args ) if ( isSpawnable!(F, T) ) { static assert( !hasLocalAliasing!(T), "Aliases to mutable thread-local data not allowed." ); return _spawn( false, fn, args ); } /** * Starts fn(args) in a logical thread and will receive a LinkTerminated * message when the operation terminates. * * Executes the supplied function in a new logical thread represented by * Tid. This new thread is linked to the calling thread so that if either * it or the calling thread terminates a LinkTerminated message will be sent * to the other, causing a LinkTerminated exception to be thrown on receive(). * The owner relationship from spawn() is preserved as well, so if the link * between threads is broken, owner termination will still result in an * OwnerTerminated exception to be thrown on receive(). * * Params: * fn = The function to execute. * args = Arguments to the function. * * Returns: * A Tid representing the new thread. */ Tid spawnLinked(F, T...)( F fn, T args ) if ( isSpawnable!(F, T) ) { static assert( !hasLocalAliasing!(T), "Aliases to mutable thread-local data not allowed." ); return _spawn( true, fn, args ); } /* * */ private Tid _spawn(F, T...)( bool linked, F fn, T args ) if ( isSpawnable!(F, T) ) { // TODO: MessageList and &exec should be shared. auto spawnTid = Tid( new MessageBox ); auto ownerTid = thisTid; void exec() { thisInfo.ident = spawnTid; thisInfo.owner = ownerTid; fn( args ); } // TODO: MessageList and &exec should be shared. if( scheduler !is null ) scheduler.spawn( &exec ); else { auto t = new Thread( &exec ); t.start(); } thisInfo.links[spawnTid] = linked; return spawnTid; } unittest { void function() fn1; void function(int) fn2; static assert( __traits(compiles, spawn(fn1))); static assert( __traits(compiles, spawn(fn2, 2))); static assert(!__traits(compiles, spawn(fn1, 1))); static assert(!__traits(compiles, spawn(fn2))); void delegate(int) shared dg1; shared(void delegate(int)) dg2; shared(void delegate(long) shared) dg3; shared(void delegate(real, int , long) shared) dg4; void delegate(int) immutable dg5; void delegate(int) dg6; static assert( __traits(compiles, spawn(dg1, 1))); static assert( __traits(compiles, spawn(dg2, 2))); static assert( __traits(compiles, spawn(dg3, 3))); static assert( __traits(compiles, spawn(dg4, 4, 4, 4))); static assert( __traits(compiles, spawn(dg5, 5))); static assert(!__traits(compiles, spawn(dg6, 6))); auto callable1 = new class{ void opCall(int) shared {} }; auto callable2 = cast(shared)new class{ void opCall(int) shared {} }; auto callable3 = new class{ void opCall(int) immutable {} }; auto callable4 = cast(immutable)new class{ void opCall(int) immutable {} }; auto callable5 = new class{ void opCall(int) {} }; auto callable6 = cast(shared)new class{ void opCall(int) immutable {} }; auto callable7 = cast(immutable)new class{ void opCall(int) shared {} }; auto callable8 = cast(shared)new class{ void opCall(int) const shared {} }; auto callable9 = cast(const shared)new class{ void opCall(int) shared {} }; auto callable10 = cast(const shared)new class{ void opCall(int) const shared {} }; auto callable11 = cast(immutable)new class{ void opCall(int) const shared {} }; static assert(!__traits(compiles, spawn(callable1, 1))); static assert( __traits(compiles, spawn(callable2, 2))); static assert(!__traits(compiles, spawn(callable3, 3))); static assert( __traits(compiles, spawn(callable4, 4))); static assert(!__traits(compiles, spawn(callable5, 5))); static assert(!__traits(compiles, spawn(callable6, 6))); static assert(!__traits(compiles, spawn(callable7, 7))); static assert( __traits(compiles, spawn(callable8, 8))); static assert(!__traits(compiles, spawn(callable9, 9))); static assert( __traits(compiles, spawn(callable10, 10))); static assert( __traits(compiles, spawn(callable11, 11))); } ////////////////////////////////////////////////////////////////////////////// // Sending and Receiving Messages ////////////////////////////////////////////////////////////////////////////// /** * Places the values as a message at the back of tid's message queue. * * Sends the supplied value to the thread represented by tid. As with * $(XREF concurrency, spawn), $(D T) must not have unshared aliasing. */ void send(T...)( Tid tid, T vals ) { static assert( !hasLocalAliasing!(T), "Aliases to mutable thread-local data not allowed." ); _send( tid, vals ); } /** * Places the values as a message on the front of tid's message queue. * * Send a message to $(D tid) but place it at the front of $(D tid)'s message * queue instead of at the back. This function is typically used for * out-of-band communication, to signal exceptional conditions, etc. */ void prioritySend(T...)( Tid tid, T vals ) { static assert( !hasLocalAliasing!(T), "Aliases to mutable thread-local data not allowed." ); _send( MsgType.priority, tid, vals ); } /* * ditto */ private void _send(T...)( Tid tid, T vals ) { _send( MsgType.standard, tid, vals ); } /* * Implementation of send. This allows parameter checking to be different for * both Tid.send() and .send(). */ private void _send(T...)( MsgType type, Tid tid, T vals ) { auto msg = Message( type, vals ); tid.mbox.put( msg ); } /** * Receives a message from another thread. * * Receive a message from another thread, or block if no messages of the * specified types are available. This function works by pattern matching * a message against a set of delegates and executing the first match found. * * If a delegate that accepts a $(XREF variant, Variant) is included as * the last argument to $(D receive), it will match any message that was not * matched by an earlier delegate. If more than one argument is sent, * the $(D Variant) will contain a $(XREF typecons, Tuple) of all values * sent. * * Example: * --- * import std.stdio; * import std.variant; * import std.concurrency; * * void spawnedFunction() * { * receive( * (int i) { writeln("Received an int."); }, * (float f) { writeln("Received a float."); }, * (Variant v) { writeln("Received some other type."); } * ); * } * * void main() * { * auto tid = spawn(&spawnedFunction); * send(tid, 42); * } * --- */ void receive(T...)( T ops ) in { assert(thisInfo.ident.mbox !is null, "Cannot receive a message until a thread was spawned " ~ "or thisTid was passed to a running thread."); } body { checkops( ops ); thisInfo.ident.mbox.get( ops ); } unittest { assert( __traits( compiles, { receive( (Variant x) {} ); receive( (int x) {}, (Variant x) {} ); } ) ); assert( !__traits( compiles, { receive( (Variant x) {}, (int x) {} ); } ) ); assert( !__traits( compiles, { receive( (int x) {}, (int x) {} ); } ) ); } // Make sure receive() works with free functions as well. version (unittest) { private void receiveFunction(int x) {} } unittest { assert( __traits( compiles, { receive( &receiveFunction ); receive( &receiveFunction, (Variant x) {} ); } ) ); } private template receiveOnlyRet(T...) { static if( T.length == 1 ) alias receiveOnlyRet = T[0]; else alias receiveOnlyRet = Tuple!(T); } /** * Receives only messages with arguments of types $(D T). * * Throws: $(D MessageMismatch) if a message of types other than $(D T) * is received. * * Returns: The received message. If $(D T.length) is greater than one, * the message will be packed into a $(XREF typecons, Tuple). * * Example: * --- * import std.concurrency; * * void spawnedFunc() * { * auto msg = receiveOnly!(int, string)(); * assert(msg[0] == 42); * assert(msg[1] == "42"); * } * * void main() * { * auto tid = spawn(&spawnedFunc); * send(tid, 42, "42"); * } * --- */ receiveOnlyRet!(T) receiveOnly(T...)() in { assert(thisInfo.ident.mbox !is null, "Cannot receive a message until a thread was spawned " ~ "or thisTid was passed to a running thread."); } body { Tuple!(T) ret; thisInfo.ident.mbox.get( ( T val ) { static if( T.length ) ret.field = val; }, ( LinkTerminated e ) { throw e; }, ( OwnerTerminated e ) { throw e; }, ( Variant val ) { static if (T.length > 1) string exp = T.stringof; else string exp = T[0].stringof; throw new MessageMismatch( format("Unexpected message type: expected '%s', got '%s'", exp, val.type.toString())); } ); static if( T.length == 1 ) return ret[0]; else return ret; } unittest { static void t1(Tid mainTid) { try { receiveOnly!string(); mainTid.send(""); } catch (Throwable th) { mainTid.send(th.msg); } } auto tid = spawn(&t1, thisTid); tid.send(1); string result = receiveOnly!string(); assert(result == "Unexpected message type: expected 'string', got 'int'"); } /** * Tries to receive but will give up if no matches arrive within duration. * Won't wait at all if provided $(CXREF time, Duration) is negative. * * Same as $(D receive) except that rather than wait forever for a message, * it waits until either it receives a message or the given * $(CXREF time, Duration) has passed. It returns $(D true) if it received a * message and $(D false) if it timed out waiting for one. */ bool receiveTimeout(T...)( Duration duration, T ops ) in { assert(thisInfo.ident.mbox !is null, "Cannot receive a message until a thread was spawned " ~ "or thisTid was passed to a running thread."); } body { checkops( ops ); return thisInfo.ident.mbox.get( duration, ops ); } unittest { assert( __traits( compiles, { receiveTimeout( msecs(0), (Variant x) {} ); receiveTimeout( msecs(0), (int x) {}, (Variant x) {} ); } ) ); assert( !__traits( compiles, { receiveTimeout( msecs(0), (Variant x) {}, (int x) {} ); } ) ); assert( !__traits( compiles, { receiveTimeout( msecs(0), (int x) {}, (int x) {} ); } ) ); assert( __traits( compiles, { receiveTimeout( msecs(10), (int x) {}, (Variant x) {} ); } ) ); } ////////////////////////////////////////////////////////////////////////////// // MessageBox Limits ////////////////////////////////////////////////////////////////////////////// /** * These behaviors may be specified when a mailbox is full. */ enum OnCrowding { block, /// Wait until room is available. throwException, /// Throw a MailboxFull exception. ignore /// Abort the send and return. } private { bool onCrowdingBlock( Tid tid ) { return true; } bool onCrowdingThrow( Tid tid ) { throw new MailboxFull( tid ); } bool onCrowdingIgnore( Tid tid ) { return false; } } /** * Sets a maximum mailbox size. * * Sets a limit on the maximum number of user messages allowed in the mailbox. * If this limit is reached, the caller attempting to add a new message will * execute the behavior specified by doThis. If messages is zero, the mailbox * is unbounded. * * Params: * tid = The Tid of the thread for which this limit should be set. * messages = The maximum number of messages or zero if no limit. * doThis = The behavior executed when a message is sent to a full * mailbox. */ void setMaxMailboxSize( Tid tid, size_t messages, OnCrowding doThis ) { final switch( doThis ) { case OnCrowding.block: return tid.mbox.setMaxMsgs( messages, &onCrowdingBlock ); case OnCrowding.throwException: return tid.mbox.setMaxMsgs( messages, &onCrowdingThrow ); case OnCrowding.ignore: return tid.mbox.setMaxMsgs( messages, &onCrowdingIgnore ); } } /** * Sets a maximum mailbox size. * * Sets a limit on the maximum number of user messages allowed in the mailbox. * If this limit is reached, the caller attempting to add a new message will * execute onCrowdingDoThis. If messages is zero, the mailbox is unbounded. * * Params: * tid = The Tid of the thread for which this limit should be set. * messages = The maximum number of messages or zero if no limit. * onCrowdingDoThis = The routine called when a message is sent to a full * mailbox. */ void setMaxMailboxSize( Tid tid, size_t messages, bool function(Tid) onCrowdingDoThis ) { tid.mbox.setMaxMsgs( messages, onCrowdingDoThis ); } ////////////////////////////////////////////////////////////////////////////// // Name Registration ////////////////////////////////////////////////////////////////////////////// private { __gshared Tid[string] tidByName; __gshared string[][Tid] namesByTid; __gshared Mutex registryLock; } extern (C) void std_concurrency_static_this() { registryLock = new Mutex; } private void unregisterMe() { auto me = thisTid; synchronized( registryLock ) { if( auto allNames = me in namesByTid ) { foreach( name; *allNames ) tidByName.remove( name ); namesByTid.remove( me ); } } } /** * Associates name with tid. * * Associates name with tid in a process-local map. When the thread * represented by tid terminates, any names associated with it will be * automatically unregistered. * * Params: * name = The name to associate with tid. * tid = The tid register by name. * * Returns: * true if the name is available and tid is not known to represent a * defunct thread. */ bool register( string name, Tid tid ) { synchronized( registryLock ) { if( name in tidByName ) return false; if( tid.mbox.isClosed ) return false; namesByTid[tid] ~= name; tidByName[name] = tid; return true; } } /** * Removes the registered name associated with a tid. * * Params: * name = The name to unregister. * * Returns: * true if the name is registered, false if not. */ bool unregister( string name ) { synchronized( registryLock ) { if( auto tid = name in tidByName ) { auto allNames = *tid in namesByTid; auto pos = countUntil( *allNames, name ); remove!(SwapStrategy.unstable)( *allNames, pos ); tidByName.remove( name ); return true; } return false; } } /** * Gets the Tid associated with name. * * Params: * name = The name to locate within the registry. * * Returns: * The associated Tid or Tid.init if name is not registered. */ Tid locate( string name ) { synchronized( registryLock ) { if( auto tid = name in tidByName ) return *tid; return Tid.init; } } ////////////////////////////////////////////////////////////////////////////// // Scheduler ////////////////////////////////////////////////////////////////////////////// /** * Encapsulates all implementation-level data needed for scheduling. * * When definining a Scheduler, an instance of this struct must be associated * with each logical thread. It contains all implementation-level information * needed by the internal API. */ struct ThreadInfo { Tid ident; bool[Tid] links; Tid owner; /** * Gets a thread-local instance of ThreadInfo. * * Gets a thread-local instance of ThreadInfo, which should be used as the * default instance when info is requested for a thread not created by the * Scheduler. */ static @property ref thisInfo() nothrow { static ThreadInfo val; return val; } /** * Cleans up this ThreadInfo. * * This must be called when a scheduled thread terminates. It tears down * the messaging system for the thread and notifies interested parties of * the thread's termination. */ void cleanup() { if( ident.mbox !is null ) ident.mbox.close(); foreach( tid; links.keys ) _send( MsgType.linkDead, tid, ident ); if( owner != Tid.init ) _send( MsgType.linkDead, owner, ident ); unregisterMe(); // clean up registry entries } } /** * A Scheduler controls how threading is performed by spawn. * * Implementing a Scheduler allows the concurrency mechanism used by this * module to be customized according to different needs. By default, a call * to spawn will create a new kernel thread that executes the supplied routine * and terminates when finished. But it is possible to create Schedulers that * reuse threads, that multiplex Fibers (coroutines) across a single thread, * or any number of other approaches. By making the choice of Scheduler a * user-level option, std.concurrency may be used for far more types of * application than if this behavior were predefined. * * Example: * --- * import std.concurrency; * import std.stdio; * * void main() * { * scheduler = new FiberScheduler; * scheduler.start( * { * writeln("the rest of main goes here"); * }); * } * --- * * Some schedulers have a dispatching loop that must run if they are to work * properly, so for the sake of consistency, when using a scheduler, start() * must be called within main(). This yields control to the scheduler and * will ensure that any spawned threads are executed in an expected manner. */ interface Scheduler { /** * Spawns the supplied op and starts the Scheduler. * * This is intended to be called at the start of the program to yield all * scheduling to the active Scheduler instance. This is necessary for * schedulers that explicitly dispatch threads rather than simply relying * on the operating system to do so, and so start should always be called * within main() to begin normal program execution. * * Params: * op = A wrapper for whatever the main thread would have done in the * absence of a custom scheduler. It will be automatically executed * via a call to spawn by the Scheduler. */ void start( void delegate() op ); /** * Assigns a logical thread to execute the supplied op. * * This routine is called by spawn. It is expected to instantiate a new * logical thread and run the supplied operation. This thread must call * thisInfo.cleanup() when the thread terminates if the scheduled thread * is not a kernel thread--all kernel threads will have their ThreadInfo * cleaned up automatically by a thread-local destructor. * * Params: * op = The function to execute. This may be the actual function passed * by the user to spawn itself, or may be a wrapper function. */ void spawn( void delegate() op ); /** * Yields execution to another logical thread. * * This routine is called at various points within concurrency-aware APIs * to provide a scheduler a chance to yield execution when using some sort * of cooperative multithreading model. If this is not appropriate, such * as when each logical thread is backed by a dedicated kernel thread, * this routine may be a no-op. */ void yield() nothrow; /** * Returns an appropriate ThreadInfo instance. * * Returns an instance of ThreadInfo specific to the logical thread that * is calling this routine or, if the calling thread was not create by * this scheduler, returns ThreadInfo.thisInfo instead. */ @property ref ThreadInfo thisInfo() nothrow; /** * Creates a Condition variable analog for signaling. * * Creates a new Condition variable analog which is used to check for and * to signal the addition of messages to a thread's message queue. Like * yield, some schedulers may need to define custom behavior so that calls * to Condition.wait() yield to another thread when no new messages are * available instead of blocking. * * Params: * m = The Mutex that will be associated with this condition. It will be * locked prior to any operation on the condition, and so in some * cases a Scheduler may need to hold this reference and unlock the * mutex before yielding execution to another logical thread. */ Condition newCondition( Mutex m ) nothrow; } /** * An example Scheduler using kernel threads. * * This is an example Scheduler that mirrors the default scheduling behavior * of creating one kernel thread per call to spawn. It is fully functional * and may be instantiated and used, but is not a necessary part of the * default functioning of this module. */ class ThreadScheduler : Scheduler { /** * This simply runs op directly, since no real scheduling is needed by * this approach. */ void start( void delegate() op ) { op(); } /** * Creates a new kernel thread and assigns it to run the supplied op. */ void spawn( void delegate() op ) { auto t = new Thread( op ); t.start(); } /** * This scheduler does no explicit multiplexing, so this is a no-op. */ void yield() nothrow { // no explicit yield needed } /** * Returns ThreadInfo.thisInfo, since it is a thread-local instance of * ThreadInfo, which is the correct behavior for this scheduler. */ @property ref ThreadInfo thisInfo() nothrow { return ThreadInfo.thisInfo; } /** * Creates a new Condition variable. No custom behavior is needed here. */ Condition newCondition( Mutex m ) nothrow { return new Condition( m ); } } /** * An example Scheduler using Fibers. * * This is an example scheduler that creates a new Fiber per call to spawn * and multiplexes the execution of all fibers within the main thread. */ class FiberScheduler : Scheduler { /** * This creates a new Fiber for the supplied op and then starts the * dispatcher. */ void start( void delegate() op ) { create( op ); dispatch(); } /** * This created a new Fiber for the supplied op and adds it to the * dispatch list. */ void spawn( void delegate() op ) nothrow { create( op ); yield(); } /** * If the caller is a scheduled Fiber, this yields execution to another * scheduled Fiber. */ void yield() nothrow { // NOTE: It's possible that we should test whether the calling Fiber // is an InfoFiber before yielding, but I think it's reasonable // that any (non-Generator) fiber should yield here. if(Fiber.getThis()) Fiber.yield(); } /** * Returns an appropriate ThreadInfo instance. * * Returns a ThreadInfo instance specific to the calling Fiber if the * Fiber was created by this dispatcher, otherwise it returns * ThreadInfo.thisInfo. */ @property ref ThreadInfo thisInfo() nothrow { auto f = cast(InfoFiber) Fiber.getThis(); if( f !is null ) return f.info; return ThreadInfo.thisInfo; } /** * Returns a Condition analog that yields when wait or notify is called. */ Condition newCondition( Mutex m ) nothrow { return new FiberCondition( m ); } private: static class InfoFiber : Fiber { ThreadInfo info; this( void delegate() op ) nothrow { super( op ); } } class FiberCondition : Condition { this( Mutex m ) nothrow { super(m); notified = false; } override void wait() nothrow { scope(exit) notified = false; while( !notified ) switchContext(); } override bool wait( Duration period ) nothrow { import core.time; scope(exit) notified = false; for( auto limit = MonoTime.currTime + period; !notified && !period.isNegative; period = limit - MonoTime.currTime ) { yield(); } return notified; } override void notify() nothrow { notified = true; switchContext(); } override void notifyAll() nothrow { notified = true; switchContext(); } private: final void switchContext() nothrow { mutex_nothrow.unlock_nothrow(); scope(exit) mutex_nothrow.lock_nothrow(); yield(); } private bool notified; } private: final void dispatch() { import std.algorithm : remove; while( m_fibers.length > 0 ) { auto t = m_fibers[m_pos].call( Fiber.Rethrow.no ); if (t !is null && !(cast(OwnerTerminated) t)) throw t; if( m_fibers[m_pos].state == Fiber.State.TERM ) { if( m_pos >= (m_fibers = remove( m_fibers, m_pos )).length ) m_pos = 0; } else if( m_pos++ >= m_fibers.length - 1 ) { m_pos = 0; } } } final void create( void delegate() op ) nothrow { void wrap() { scope(exit) { thisInfo.cleanup(); } op(); } m_fibers ~= new InfoFiber( &wrap ); } private: Fiber[] m_fibers; size_t m_pos; } unittest { static void receive(Condition cond, ref size_t received) { while (true) { synchronized (cond.mutex) { cond.wait(); ++received; } } } static void send(Condition cond, ref size_t sent) { while (true) { synchronized (cond.mutex) { ++sent; cond.notify(); } } } auto fs = new FiberScheduler; auto mtx = new Mutex; auto cond = fs.newCondition(mtx); size_t received, sent; auto waiter = new Fiber({receive(cond, received);}), notifier = new Fiber({send(cond, sent);}); waiter.call(); assert(received == 0); notifier.call(); assert(sent == 1); assert(received == 0); waiter.call(); assert(received == 1); waiter.call(); assert(received == 1); } /** * Sets the Scheduler behavior within the program. * * This variable sets the Scheduler behavior within this program. Typically, * when setting a Scheduler, scheduler.start() should be called in main. This * routine will not return until program execution is complete. */ __gshared Scheduler scheduler; ////////////////////////////////////////////////////////////////////////////// // Generator ////////////////////////////////////////////////////////////////////////////// /** * If the caller is a Fiber and is not a Generator, this function will call * scheduler.yield() or Fiber.yield(), as appropriate. */ void yield() nothrow { auto fiber = Fiber.getThis(); if (!(cast(IsGenerator) fiber)) { if (scheduler is null) { if (fiber) return Fiber.yield(); } else scheduler.yield(); } } /// Used to determine whether a Generator is running. private interface IsGenerator {} /** * A Generator is a Fiber that periodically returns values of type T to the * caller via yield. This is represented as an InputRange. * * Example: * --- * import std.concurrency; * import std.stdio; * * * void main() * { * auto tid = spawn( * { * while (true) * { * writeln(receiveOnly!int()); * } * }); * * auto r = new Generator!int( * { * foreach (i; 1 .. 10) * yield(i); * }); * * foreach (e; r) * { * tid.send(e); * } * } * --- */ class Generator(T) : Fiber, IsGenerator { /** * Initializes a generator object which is associated with a static * D function. The function will be called once to prepare the range * for iteration. * * Params: * fn = The fiber function. * * In: * fn must not be null. */ this(void function() fn) { super(fn); call(); } /** * Initializes a generator object which is associated with a static * D function. The function will be called once to prepare the range * for iteration. * * Params: * fn = The fiber function. * sz = The stack size for this fiber. * * In: * fn must not be null. */ this(void function() fn, size_t sz) { super(fn, sz); call(); } /** * Initializes a generator object which is associated with a dynamic * D function. The function will be called once to prepare the range * for iteration. * * Params: * dg = The fiber function. * * In: * dg must not be null. */ this(void delegate() dg) { super(dg); call(); } /** * Initializes a generator object which is associated with a dynamic * D function. The function will be called once to prepare the range * for iteration. * * Params: * dg = The fiber function. * sz = The stack size for this fiber. * * In: * dg must not be null. */ this(void delegate() dg, size_t sz) { super(dg, sz); call(); } /** * Returns true if the generator is empty. */ final bool empty() @property { return m_value is null || state == State.TERM; } /** * Obtains the next value from the underlying function. */ final void popFront() { call(); } /** * Returns the most recently generated value. */ final T front() @property { return *m_value; } private: T* m_value; } /** * Yields a value of type T to the caller of the currently executing * generator. * * Params: * value = The value to yield. */ void yield(T)(ref T value) { Generator!T cur = cast(Generator!T) Fiber.getThis(); if (cur !is null && cur.state == Fiber.State.EXEC) { cur.m_value = &value; return Fiber.yield(); } throw new Exception("yield(T) called with no active generator for the supplied type"); } /// ditto void yield(T)(T value) { yield(value); } version (Win64) { // fibers are broken on Win64 } else version (Win32) { // fibers are broken in Win32 under server 2012: bug 13821 } else unittest { import core.exception; import std.exception; static void testScheduler(Scheduler s) { scheduler = s; scheduler.start( { auto tid = spawn( { int i; try { for (i = 1; i < 10; i++) { assertNotThrown!AssertError( assert(receiveOnly!int() == i)); } } catch (OwnerTerminated e) { } // i will advance 1 past the last value expected assert(i == 4); }); auto r = new Generator!int( { assertThrown!Exception(yield(2.0)); yield(); // ensure this is a no-op yield(1); yield(); // also once something has been yielded yield(2); yield(3); }); foreach (e; r) { tid.send(e); } }); scheduler = null; } testScheduler(new ThreadScheduler); testScheduler(new FiberScheduler); } ////////////////////////////////////////////////////////////////////////////// // MessageBox Implementation ////////////////////////////////////////////////////////////////////////////// private { /* * A MessageBox is a message queue for one thread. Other threads may send * messages to this owner by calling put(), and the owner receives them by * calling get(). The put() call is therefore effectively shared and the * get() call is effectively local. setMaxMsgs may be used by any thread * to limit the size of the message queue. */ class MessageBox { this() @trusted /* TODO: make @safe after relevant druntime PR gets merged */ { m_lock = new Mutex; m_closed = false; if( scheduler is null ) { m_putMsg = new Condition( m_lock ); m_notFull = new Condition( m_lock ); } else { m_putMsg = scheduler.newCondition( m_lock ); m_notFull = scheduler.newCondition( m_lock ); } } /// final @property bool isClosed() { synchronized( m_lock ) { return m_closed; } } /* * Sets a limit on the maximum number of user messages allowed in the * mailbox. If this limit is reached, the caller attempting to add * a new message will execute call. If num is zero, there is no limit * on the message queue. * * Params: * num = The maximum size of the queue or zero if the queue is * unbounded. * call = The routine to call when the queue is full. */ final void setMaxMsgs( size_t num, bool function(Tid) call ) { synchronized( m_lock ) { m_maxMsgs = num; m_onMaxMsgs = call; } } /* * If maxMsgs is not set, the message is added to the queue and the * owner is notified. If the queue is full, the message will still be * accepted if it is a control message, otherwise onCrowdingDoThis is * called. If the routine returns true, this call will block until * the owner has made space available in the queue. If it returns * false, this call will abort. * * Params: * msg = The message to put in the queue. * * Throws: * An exception if the queue is full and onCrowdingDoThis throws. */ final void put( ref Message msg ) { synchronized( m_lock ) { // TODO: Generate an error here if m_closed is true, or maybe // put a message in the caller's queue? if( !m_closed ) { while( true ) { if( isPriorityMsg( msg ) ) { m_sharedPty.put( msg ); m_putMsg.notify(); return; } if( !mboxFull() || isControlMsg( msg ) ) { m_sharedBox.put( msg ); m_putMsg.notify(); return; } if( m_onMaxMsgs !is null && !m_onMaxMsgs( thisTid ) ) { return; } m_putQueue++; m_notFull.wait(); m_putQueue--; } } } } /* * Matches ops against each message in turn until a match is found. * * Params: * ops = The operations to match. Each may return a bool to indicate * whether a message with a matching type is truly a match. * * Returns: * true if a message was retrieved and false if not (such as if a * timeout occurred). * * Throws: * LinkTerminated if a linked thread terminated, or OwnerTerminated * if the owner thread terminates and no existing messages match the * supplied ops. */ final bool get(T...)( scope T vals ) { static assert( T.length ); static if( isImplicitlyConvertible!(T[0], Duration) ) { alias Ops = AliasSeq!(T[1 .. $]); alias ops = vals[1 .. $]; assert( vals[0] >= msecs(0) ); enum timedWait = true; Duration period = vals[0]; } else { alias Ops = AliasSeq!(T); alias ops = vals[0 .. $]; enum timedWait = false; } bool onStandardMsg( ref Message msg ) { foreach( i, t; Ops ) { alias Args = Parameters!(t); auto op = ops[i]; if( msg.convertsTo!(Args) ) { static if( is( ReturnType!(t) == bool ) ) { return msg.map( op ); } else { msg.map( op ); return true; } } } return false; } bool onLinkDeadMsg( ref Message msg ) { assert( msg.convertsTo!(Tid) ); auto tid = msg.get!(Tid); if( bool* pDepends = (tid in thisInfo.links) ) { auto depends = *pDepends; thisInfo.links.remove( tid ); // Give the owner relationship precedence. if( depends && tid != thisInfo.owner ) { auto e = new LinkTerminated( tid ); auto m = Message( MsgType.standard, e ); if( onStandardMsg( m ) ) return true; throw e; } } if( tid == thisInfo.owner ) { thisInfo.owner = Tid.init; auto e = new OwnerTerminated( tid ); auto m = Message( MsgType.standard, e ); if( onStandardMsg( m ) ) return true; throw e; } return false; } bool onControlMsg( ref Message msg ) { switch( msg.type ) { case MsgType.linkDead: return onLinkDeadMsg( msg ); default: return false; } } bool scan( ref ListT list ) { for( auto range = list[]; !range.empty; ) { // Only the message handler will throw, so if this occurs // we can be certain that the message was handled. scope(failure) list.removeAt( range ); if( isControlMsg( range.front ) ) { if( onControlMsg( range.front ) ) { // Although the linkDead message is a control message, // it can be handled by the user. Since the linkDead // message throws if not handled, if we get here then // it has been handled and we can return from receive. // This is a weird special case that will have to be // handled in a more general way if more are added. if( !isLinkDeadMsg( range.front ) ) { list.removeAt( range ); continue; } list.removeAt( range ); return true; } range.popFront(); continue; } else { if( onStandardMsg( range.front ) ) { list.removeAt( range ); return true; } range.popFront(); continue; } } return false; } bool pty( ref ListT list ) { if( !list.empty ) { auto range = list[]; if( onStandardMsg( range.front ) ) { list.removeAt( range ); return true; } if( range.front.convertsTo!(Throwable) ) throw range.front.get!(Throwable); else if( range.front.convertsTo!(shared(Throwable)) ) throw range.front.get!(shared(Throwable)); else throw new PriorityMessageException( range.front.data ); } return false; } static if( timedWait ) { import core.time; auto limit = MonoTime.currTime + period; } while( true ) { ListT arrived; if( pty( m_localPty ) || scan( m_localBox ) ) { return true; } yield(); synchronized( m_lock ) { updateMsgCount(); while( m_sharedPty.empty && m_sharedBox.empty ) { // NOTE: We're notifying all waiters here instead of just // a few because the onCrowding behavior may have // changed and we don't want to block sender threads // unnecessarily if the new behavior is not to block. // This will admittedly result in spurious wakeups // in other situations, but what can you do? if( m_putQueue && !mboxFull() ) m_notFull.notifyAll(); static if( timedWait ) { if( period.isNegative || !m_putMsg.wait( period ) ) return false; } else { m_putMsg.wait(); } } m_localPty.put( m_sharedPty ); arrived.put( m_sharedBox ); } if( m_localPty.empty ) { scope(exit) m_localBox.put( arrived ); if( scan( arrived ) ) return true; else { static if( timedWait ) { period = limit - MonoTime.currTime; } continue; } } m_localBox.put( arrived ); pty( m_localPty ); return true; } } /* * Called on thread termination. This routine processes any remaining * control messages, clears out message queues, and sets a flag to * reject any future messages. */ final void close() { void onLinkDeadMsg( ref Message msg ) { assert( msg.convertsTo!(Tid) ); auto tid = msg.get!(Tid); thisInfo.links.remove( tid ); if( tid == thisInfo.owner ) thisInfo.owner = Tid.init; } void sweep( ref ListT list ) { for( auto range = list[]; !range.empty; range.popFront() ) { if( range.front.type == MsgType.linkDead ) onLinkDeadMsg( range.front ); } } ListT arrived; sweep( m_localBox ); synchronized( m_lock ) { arrived.put( m_sharedBox ); m_closed = true; } m_localBox.clear(); sweep( arrived ); } private: ////////////////////////////////////////////////////////////////////// // Routines involving shared data, m_lock must be held. ////////////////////////////////////////////////////////////////////// bool mboxFull() { return m_maxMsgs && m_maxMsgs <= m_localMsgs + m_sharedBox.length; } void updateMsgCount() { m_localMsgs = m_localBox.length; } private: ////////////////////////////////////////////////////////////////////// // Routines involving local data only, no lock needed. ////////////////////////////////////////////////////////////////////// pure final bool isControlMsg( ref Message msg ) { return msg.type != MsgType.standard && msg.type != MsgType.priority; } pure final bool isPriorityMsg( ref Message msg ) { return msg.type == MsgType.priority; } pure final bool isLinkDeadMsg( ref Message msg ) { return msg.type == MsgType.linkDead; } private: ////////////////////////////////////////////////////////////////////// // Type declarations. ////////////////////////////////////////////////////////////////////// alias OnMaxFn = bool function(Tid); alias ListT = List!(Message); private: ////////////////////////////////////////////////////////////////////// // Local data, no lock needed. ////////////////////////////////////////////////////////////////////// ListT m_localBox; ListT m_localPty; private: ////////////////////////////////////////////////////////////////////// // Shared data, m_lock must be held on access. ////////////////////////////////////////////////////////////////////// Mutex m_lock; Condition m_putMsg; Condition m_notFull; size_t m_putQueue; ListT m_sharedBox; ListT m_sharedPty; OnMaxFn m_onMaxMsgs; size_t m_localMsgs; size_t m_maxMsgs; bool m_closed; } /* * */ struct List(T) { struct Range { @property bool empty() const { return !m_prev.next; } @property ref T front() { enforce( m_prev.next, "invalid list node" ); return m_prev.next.val; } @property void front( T val ) { enforce( m_prev.next, "invalid list node" ); m_prev.next.val = val; } void popFront() { enforce( m_prev.next, "invalid list node" ); m_prev = m_prev.next; } //T moveFront() //{ // enforce( m_prev.next ); // return move( m_prev.next.val ); //} private this( Node* p ) { m_prev = p; } private Node* m_prev; } /* * */ void put( T val ) { put( newNode( val ) ); } /* * */ void put( ref List!(T) rhs ) { if( !rhs.empty ) { put( rhs.m_first ); while( m_last.next !is null ) { m_last = m_last.next; m_count++; } rhs.m_first = null; rhs.m_last = null; rhs.m_count = 0; } } /* * */ Range opSlice() { return Range( cast(Node*) &m_first ); } /* * */ void removeAt( Range r ) { assert( m_count ); Node* n = r.m_prev; enforce( n && n.next, "attempting to remove invalid list node" ); if( m_last is m_first ) m_last = null; else if( m_last is n.next ) m_last = n; Node* to_free = n.next; n.next = n.next.next; freeNode( to_free ); m_count--; } /* * */ @property size_t length() { return m_count; } /* * */ void clear() { m_first = m_last = null; m_count = 0; } /* * */ @property bool empty() { return m_first is null; } private: struct Node { Node* next; T val; this( T v ) { val = v; } } static shared struct SpinLock { void lock() { while (!cas(&locked, false, true)) { Thread.yield(); } } void unlock() { atomicStore!(MemoryOrder.rel)(locked, false); } bool locked; } static shared SpinLock sm_lock; static shared Node* sm_head; Node* newNode(T v) { Node *n; { sm_lock.lock(); scope (exit) sm_lock.unlock(); if (sm_head) { n = cast(Node*)sm_head; sm_head = sm_head.next; } } if (n) *n = Node(v); else n = new Node(v); return n; } void freeNode(Node* n) { // destroy val to free any owned GC memory destroy(n.val); sm_lock.lock(); scope (exit) sm_lock.unlock(); auto sn = cast(shared(Node)*)n; sn.next = sm_head; sm_head = sn; } /* * */ void put( Node* n ) { m_count++; if( !empty ) { m_last.next = n; m_last = n; return; } m_first = n; m_last = n; } Node* m_first; Node* m_last; size_t m_count; } } version( unittest ) { import std.stdio; void testfn( Tid tid ) { receive( (float val) { assert(0); }, (int val, int val2) { assert( val == 42 && val2 == 86 ); } ); receive( (Tuple!(int, int) val) { assert( val[0] == 42 && val[1] == 86 ); } ); receive( (Variant val) {} ); receive( (string val) { if( "the quick brown fox" != val ) return false; return true; }, (string val) { assert( false ); } ); prioritySend( tid, "done" ); } void runTest( Tid tid ) { send( tid, 42, 86 ); send( tid, tuple(42, 86) ); send( tid, "hello", "there" ); send( tid, "the quick brown fox" ); receive( (string val) { assert(val == "done"); } ); } void simpleTest() { auto tid = spawn( &testfn, thisTid ); runTest( tid ); // Run the test again with a limited mailbox size. tid = spawn( &testfn, thisTid ); setMaxMailboxSize( tid, 2, OnCrowding.block ); runTest( tid ); } unittest { simpleTest(); } unittest { scheduler = new ThreadScheduler; simpleTest(); scheduler = null; } } ////////////////////////////////////////////////////////////////////////////// // initOnce ////////////////////////////////////////////////////////////////////////////// private @property Mutex initOnceLock() { __gshared Mutex lock; if (auto mtx = atomicLoad!(MemoryOrder.acq)(*cast(shared)&lock)) return mtx; auto mtx = new Mutex; if (cas(cast(shared)&lock, cast(shared)null, cast(shared)mtx)) return mtx; return atomicLoad!(MemoryOrder.acq)(*cast(shared)&lock); } /** * Initializes $(D_PARAM var) with the lazy $(D_PARAM init) value in a * thread-safe manner. * * The implementation guarantees that all threads simultaneously calling * initOnce with the same $(D_PARAM var) argument block until $(D_PARAM var) is * fully initialized. All side-effects of $(D_PARAM init) are globally visible * afterwards. * * Params: * var = The variable to initialize * init = The lazy initializer value * * Returns: * A reference to the initialized variable */ auto ref initOnce(alias var)(lazy typeof(var) init) { return initOnce!var(init, initOnceLock); } /// A typical use-case is to perform lazy but thread-safe initialization. unittest { static class MySingleton { static MySingleton instance() { static __gshared MySingleton inst; return initOnce!inst(new MySingleton); } } assert(MySingleton.instance !is null); } unittest { static class MySingleton { static MySingleton instance() { static __gshared MySingleton inst; return initOnce!inst(new MySingleton); } private: this() { val = ++cnt; } size_t val; static __gshared size_t cnt; } foreach (_; 0 .. 10) spawn({ownerTid.send(MySingleton.instance.val);}); foreach (_; 0 .. 10) assert(receiveOnly!size_t == MySingleton.instance.val); assert(MySingleton.cnt == 1); } /** * Same as above, but takes a separate mutex instead of sharing one among * all initOnce instances. * * This should be used to avoid dead-locks when the $(D_PARAM init) * expression waits for the result of another thread that might also * call initOnce. Use with care. * * Params: * var = The variable to initialize * init = The lazy initializer value * mutex = A mutex to prevent race conditions * * Returns: * A reference to the initialized variable */ auto ref initOnce(alias var)(lazy typeof(var) init, Mutex mutex) { // check that var is global, can't take address of a TLS variable static assert(is(typeof({__gshared p = &var;})), "var must be 'static shared' or '__gshared'."); import core.atomic; static shared bool flag; if (!atomicLoad!(MemoryOrder.acq)(flag)) { synchronized (mutex) { if (!atomicLoad!(MemoryOrder.acq)(flag)) { var = init; atomicStore!(MemoryOrder.rel)(flag, true); } } } return var; } /// Use a separate mutex when init blocks on another thread that might also call initOnce. unittest { static shared bool varA, varB; __gshared Mutex m; m = new Mutex; spawn({ // use a different mutex for varB to avoid a dead-lock initOnce!varB(true, m); ownerTid.send(true); }); // init depends on the result of the spawned thread initOnce!varA(receiveOnly!bool); assert(varA == true); assert(varB == true); } unittest { static shared bool a; __gshared bool b; static bool c; bool d; initOnce!a(true); initOnce!b(true); static assert(!__traits(compiles, initOnce!c(true))); // TLS static assert(!__traits(compiles, initOnce!d(true))); // local variable } ldc-1.1.0-beta3-src/runtime/phobos/std/path.d0000664000175000017500000040101312776215007017006 0ustar kaikai// Written in the D programming language. /** This module is used to manipulate _path strings. All functions, with the exception of $(LREF expandTilde) (and in some cases $(LREF absolutePath) and $(LREF relativePath)), are pure string manipulation functions; they don't depend on any state outside the program, nor do they perform any actual file system actions. This has the consequence that the module does not make any distinction between a _path that points to a directory and a _path that points to a file, and it does not know whether or not the object pointed to by the _path actually exists in the file system. To differentiate between these cases, use $(XREF file,isDir) and $(XREF file,exists). Note that on Windows, both the backslash ($(D `\`)) and the slash ($(D `/`)) are in principle valid directory separators. This module treats them both on equal footing, but in cases where a $(I new) separator is added, a backslash will be used. Furthermore, the $(LREF buildNormalizedPath) function will replace all slashes with backslashes on that platform. In general, the functions in this module assume that the input paths are well-formed. (That is, they should not contain invalid characters, they should follow the file system's _path format, etc.) The result of calling a function on an ill-formed _path is undefined. When there is a chance that a _path or a file name is invalid (for instance, when it has been input by the user), it may sometimes be desirable to use the $(LREF isValidFilename) and $(LREF isValidPath) functions to check this. Most functions do not perform any memory allocations, and if a string is returned, it is usually a slice of an input string. If a function allocates, this is explicitly mentioned in the documentation. Upgrading: $(WEB digitalmars.com/d/1.0/phobos/std_path.html#fnmatch) can be replaced with $(D globMatch). Authors: Lars Tandle Kyllingstad, $(WEB digitalmars.com, Walter Bright), Grzegorz Adam Hankiewicz, Thomas K$(UUML)hne, $(WEB erdani.org, Andrei Alexandrescu) Copyright: Copyright (c) 2000-2014, the authors. All rights reserved. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0) Source: $(PHOBOSSRC std/_path.d) Macros: WIKI = Phobos/StdPath */ module std.path; // FIXME import std.file; //: getcwd; import std.range.primitives; import std.traits; static import std.meta; version (unittest) { private: struct TestAliasedString { string get() @safe @nogc pure nothrow { return _s; } alias get this; @disable this(this); string _s; } bool testAliasedString(alias func, Args...)(string s, Args args) { return func(TestAliasedString(s), args) == func(s, args); } } /** String used to separate directory names in a path. Under POSIX this is a slash, under Windows a backslash. */ version(Posix) enum string dirSeparator = "/"; else version(Windows) enum string dirSeparator = "\\"; else static assert (0, "unsupported platform"); /** Path separator string. A colon under POSIX, a semicolon under Windows. */ version(Posix) enum string pathSeparator = ":"; else version(Windows) enum string pathSeparator = ";"; else static assert (0, "unsupported platform"); /** Determines whether the given character is a directory separator. On Windows, this includes both $(D `\`) and $(D `/`). On POSIX, it's just $(D `/`). */ bool isDirSeparator(dchar c) @safe pure nothrow @nogc { if (c == '/') return true; version(Windows) if (c == '\\') return true; return false; } /* Determines whether the given character is a drive separator. On Windows, this is true if c is the ':' character that separates the drive letter from the rest of the path. On POSIX, this always returns false. */ private bool isDriveSeparator(dchar c) @safe pure nothrow @nogc { version(Windows) return c == ':'; else return false; } /* Combines the isDirSeparator and isDriveSeparator tests. */ version(Windows) private bool isSeparator(dchar c) @safe pure nothrow @nogc { return isDirSeparator(c) || isDriveSeparator(c); } version(Posix) private alias isSeparator = isDirSeparator; /* Helper function that determines the position of the last drive/directory separator in a string. Returns -1 if none is found. */ private ptrdiff_t lastSeparator(R)(R path) if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || isNarrowString!R) { auto i = (cast(ptrdiff_t) path.length) - 1; while (i >= 0 && !isSeparator(path[i])) --i; return i; } version (Windows) { private bool isUNC(R)(R path) if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || isNarrowString!R) { return path.length >= 3 && isDirSeparator(path[0]) && isDirSeparator(path[1]) && !isDirSeparator(path[2]); } private ptrdiff_t uncRootLength(R)(R path) if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || isNarrowString!R) in { assert (isUNC(path)); } body { ptrdiff_t i = 3; while (i < path.length && !isDirSeparator(path[i])) ++i; if (i < path.length) { auto j = i; do { ++j; } while (j < path.length && isDirSeparator(path[j])); if (j < path.length) { do { ++j; } while (j < path.length && !isDirSeparator(path[j])); i = j; } } return i; } private bool hasDrive(R)(R path) if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || isNarrowString!R) { return path.length >= 2 && isDriveSeparator(path[1]); } private bool isDriveRoot(R)(R path) if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || isNarrowString!R) { return path.length >= 3 && isDriveSeparator(path[1]) && isDirSeparator(path[2]); } } /* Helper functions that strip leading/trailing slashes and backslashes from a path. */ private auto ltrimDirSeparators(R)(R path) if (isInputRange!R && isSomeChar!(ElementType!R) || isNarrowString!R) { static if (isRandomAccessRange!R && hasSlicing!R || isNarrowString!R) { int i = 0; while (i < path.length && isDirSeparator(path[i])) ++i; return path[i .. path.length]; } else { while (!path.empty && isDirSeparator(path.front)) path.popFront(); return path; } } unittest { import std.array; import std.utf : byDchar; assert(ltrimDirSeparators("//abc//").array == "abc//"); assert(ltrimDirSeparators("//abc//"d).array == "abc//"d); assert(ltrimDirSeparators("//abc//".byDchar).array == "abc//"d); } private auto rtrimDirSeparators(R)(R path) if (isBidirectionalRange!R && isSomeChar!(ElementType!R) || isNarrowString!R) { static if (isRandomAccessRange!R && hasSlicing!R && hasLength!R || isNarrowString!R) { auto i = (cast(ptrdiff_t) path.length) - 1; while (i >= 0 && isDirSeparator(path[i])) --i; return path[0 .. i+1]; } else { while (!path.empty && isDirSeparator(path.back)) path.popBack(); return path; } } unittest { import std.array; import std.utf : byDchar; assert(rtrimDirSeparators("//abc//").array == "//abc"); assert(rtrimDirSeparators("//abc//"d).array == "//abc"d); assert(rtrimDirSeparators(MockBiRange!char("//abc//")).array == "//abc"); } private auto trimDirSeparators(R)(R path) if (isBidirectionalRange!R && isSomeChar!(ElementType!R) || isNarrowString!R) { return ltrimDirSeparators(rtrimDirSeparators(path)); } unittest { import std.array; import std.utf : byDchar; assert(trimDirSeparators("//abc//").array == "abc"); assert(trimDirSeparators("//abc//"d).array == "abc"d); assert(trimDirSeparators(MockBiRange!char("//abc//")).array == "abc"); } /** This $(D enum) is used as a template argument to functions which compare file names, and determines whether the comparison is case sensitive or not. */ enum CaseSensitive : bool { /// File names are case insensitive no = false, /// File names are case sensitive yes = true, /** The default (or most common) setting for the current platform. That is, $(D no) on Windows and Mac OS X, and $(D yes) on all POSIX systems except OS X (Linux, *BSD, etc.). */ osDefault = osDefaultCaseSensitivity } version (Windows) private enum osDefaultCaseSensitivity = false; else version (OSX) private enum osDefaultCaseSensitivity = false; else version (Posix) private enum osDefaultCaseSensitivity = true; else static assert (0); /** Params: cs = Whether or not suffix matching is case-sensitive. path = A path name. It can be a string, or any random-access range of characters. suffix = An optional suffix to be removed from the file name. Returns: The name of the file in the path name, without any leading directory and with an optional suffix chopped off. If $(D suffix) is specified, it will be compared to $(D path) using $(D filenameCmp!cs), where $(D cs) is an optional template parameter determining whether the comparison is case sensitive or not. See the $(LREF filenameCmp) documentation for details. Example: --- assert (baseName("dir/file.ext") == "file.ext"); assert (baseName("dir/file.ext", ".ext") == "file"); assert (baseName("dir/file.ext", ".xyz") == "file.ext"); assert (baseName("dir/filename", "name") == "file"); assert (baseName("dir/subdir/") == "subdir"); version (Windows) { assert (baseName(`d:file.ext`) == "file.ext"); assert (baseName(`d:\dir\file.ext`) == "file.ext"); } --- Note: This function $(I only) strips away the specified suffix, which doesn't necessarily have to represent an extension. To remove the extension from a path, regardless of what the extension is, use $(LREF stripExtension). To obtain the filename without leading directories and without an extension, combine the functions like this: --- assert (baseName(stripExtension("dir/file.ext")) == "file"); --- Standards: This function complies with $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/basename.html, the POSIX requirements for the 'basename' shell utility) (with suitable adaptations for Windows paths). */ auto baseName(R)(R path) if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) || is(StringTypeOf!R)) { auto p1 = stripDrive!(BaseOf!R)(path); if (p1.empty) { version (Windows) if (isUNC!(BaseOf!R)(path)) { return path[0..1]; } static if (is(StringTypeOf!R)) return StringTypeOf!R.init[]; // which is null else return p1; // which is empty } auto p2 = rtrimDirSeparators(p1); if (p2.empty) return p1[0 .. 1]; return p2[lastSeparator(p2)+1 .. p2.length]; } /// ditto inout(C)[] baseName(CaseSensitive cs = CaseSensitive.osDefault, C, C1) (inout(C)[] path, in C1[] suffix) @safe pure //TODO: nothrow (because of filenameCmp()) if (isSomeChar!C && isSomeChar!C1) { auto p = baseName(path); if (p.length > suffix.length && filenameCmp!cs(cast(const(C)[])p[$-suffix.length .. $], suffix) == 0) { return p[0 .. $-suffix.length]; } else return p; } unittest { assert (baseName("").empty); assert (baseName("file.ext"w) == "file.ext"); assert (baseName("file.ext"d, ".ext") == "file"); assert (baseName("file", "file"w.dup) == "file"); assert (baseName("dir/file.ext"d.dup) == "file.ext"); assert (baseName("dir/file.ext", ".ext"d) == "file"); assert (baseName("dir/file"w, "file"d) == "file"); assert (baseName("dir///subdir////") == "subdir"); assert (baseName("dir/subdir.ext/", ".ext") == "subdir"); assert (baseName("dir/subdir/".dup, "subdir") == "subdir"); assert (baseName("/"w.dup) == "/"); assert (baseName("//"d.dup) == "/"); assert (baseName("///") == "/"); assert (baseName!(CaseSensitive.yes)("file.ext", ".EXT") == "file.ext"); assert (baseName!(CaseSensitive.no)("file.ext", ".EXT") == "file"); { auto r = MockRange!(immutable(char))(`dir/file.ext`); auto s = r.baseName(); foreach (i, c; `file`) assert(s[i] == c); } version (Windows) { assert (baseName(`dir\file.ext`) == `file.ext`); assert (baseName(`dir\file.ext`, `.ext`) == `file`); assert (baseName(`dir\file`, `file`) == `file`); assert (baseName(`d:file.ext`) == `file.ext`); assert (baseName(`d:file.ext`, `.ext`) == `file`); assert (baseName(`d:file`, `file`) == `file`); assert (baseName(`dir\\subdir\\\`) == `subdir`); assert (baseName(`dir\subdir.ext\`, `.ext`) == `subdir`); assert (baseName(`dir\subdir\`, `subdir`) == `subdir`); assert (baseName(`\`) == `\`); assert (baseName(`\\`) == `\`); assert (baseName(`\\\`) == `\`); assert (baseName(`d:\`) == `\`); assert (baseName(`d:`).empty); assert (baseName(`\\server\share\file`) == `file`); assert (baseName(`\\server\share\`) == `\`); assert (baseName(`\\server\share`) == `\`); auto r = MockRange!(immutable(char))(`\\server\share`); auto s = r.baseName(); foreach (i, c; `\`) assert(s[i] == c); } assert (baseName(stripExtension("dir/file.ext")) == "file"); static assert (baseName("dir/file.ext") == "file.ext"); static assert (baseName("dir/file.ext", ".ext") == "file"); static struct DirEntry { string s; alias s this; } assert(baseName(DirEntry("dir/file.ext")) == "file.ext"); } /** Returns the directory part of a path. On Windows, this includes the drive letter if present. Params: path = A path name. Returns: A slice of $(D path) or ".". Standards: This function complies with $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html, the POSIX requirements for the 'dirname' shell utility) (with suitable adaptations for Windows paths). */ auto dirName(R)(R path) if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) || isNarrowString!R) && !isConvertibleToString!R) { static auto result(bool dot, typeof(path[0..1]) p) { static if (isSomeString!R) return dot ? "." : p; else { import std.range : choose, only; return choose(dot, only(cast(ElementEncodingType!R)'.'), p); } } if (path.empty) return result(true, path[0 .. 0]); auto p = rtrimDirSeparators(path); if (p.empty) return result(false, path[0 .. 1]); version (Windows) { if (isUNC(p) && uncRootLength(p) == p.length) return result(false, p); if (p.length == 2 && isDriveSeparator(p[1]) && path.length > 2) return result(false, path[0 .. 3]); } auto i = lastSeparator(p); if (i == -1) return result(true, p); if (i == 0) return result(false, p[0 .. 1]); version (Windows) { // If the directory part is either d: or d:\ // do not chop off the last symbol. if (isDriveSeparator(p[i]) || isDriveSeparator(p[i-1])) return result(false, p[0 .. i+1]); } // Remove any remaining trailing (back)slashes. return result(false, rtrimDirSeparators(p[0 .. i])); } /// unittest { assert (dirName("") == "."); assert (dirName("file"w) == "."); assert (dirName("dir/"d) == "."); assert (dirName("dir///") == "."); assert (dirName("dir/file"w.dup) == "dir"); assert (dirName("dir///file"d.dup) == "dir"); assert (dirName("dir/subdir/") == "dir"); assert (dirName("/dir/file"w) == "/dir"); assert (dirName("/file"d) == "/"); assert (dirName("/") == "/"); assert (dirName("///") == "/"); version (Windows) { assert (dirName(`dir\`) == `.`); assert (dirName(`dir\\\`) == `.`); assert (dirName(`dir\file`) == `dir`); assert (dirName(`dir\\\file`) == `dir`); assert (dirName(`dir\subdir\`) == `dir`); assert (dirName(`\dir\file`) == `\dir`); assert (dirName(`\file`) == `\`); assert (dirName(`\`) == `\`); assert (dirName(`\\\`) == `\`); assert (dirName(`d:`) == `d:`); assert (dirName(`d:file`) == `d:`); assert (dirName(`d:\`) == `d:\`); assert (dirName(`d:\file`) == `d:\`); assert (dirName(`d:\dir\file`) == `d:\dir`); assert (dirName(`\\server\share\dir\file`) == `\\server\share\dir`); assert (dirName(`\\server\share\file`) == `\\server\share`); assert (dirName(`\\server\share\`) == `\\server\share`); assert (dirName(`\\server\share`) == `\\server\share`); } } auto dirName(R)(auto ref R path) if (isConvertibleToString!R) { return dirName!(StringTypeOf!R)(path); } unittest { assert(testAliasedString!dirName("file")); } unittest { static assert (dirName("dir/file") == "dir"); import std.array; import std.utf : byChar, byWchar, byDchar; assert (dirName("".byChar).array == "."); assert (dirName("file"w.byWchar).array == "."w); assert (dirName("dir/"d.byDchar).array == "."d); assert (dirName("dir///".byChar).array == "."); assert (dirName("dir/subdir/".byChar).array == "dir"); assert (dirName("/dir/file"w.byWchar).array == "/dir"w); assert (dirName("/file"d.byDchar).array == "/"d); assert (dirName("/".byChar).array == "/"); assert (dirName("///".byChar).array == "/"); version (Windows) { assert (dirName(`dir\`.byChar).array == `.`); assert (dirName(`dir\\\`.byChar).array == `.`); assert (dirName(`dir\file`.byChar).array == `dir`); assert (dirName(`dir\\\file`.byChar).array == `dir`); assert (dirName(`dir\subdir\`.byChar).array == `dir`); assert (dirName(`\dir\file`.byChar).array == `\dir`); assert (dirName(`\file`.byChar).array == `\`); assert (dirName(`\`.byChar).array == `\`); assert (dirName(`\\\`.byChar).array == `\`); assert (dirName(`d:`.byChar).array == `d:`); assert (dirName(`d:file`.byChar).array == `d:`); assert (dirName(`d:\`.byChar).array == `d:\`); assert (dirName(`d:\file`.byChar).array == `d:\`); assert (dirName(`d:\dir\file`.byChar).array == `d:\dir`); assert (dirName(`\\server\share\dir\file`.byChar).array == `\\server\share\dir`); assert (dirName(`\\server\share\file`) == `\\server\share`); assert (dirName(`\\server\share\`.byChar).array == `\\server\share`); assert (dirName(`\\server\share`.byChar).array == `\\server\share`); } //static assert (dirName("dir/file".byChar).array == "dir"); } /** Returns the root directory of the specified path, or $(D null) if the path is not rooted. Params: path = A path name. Returns: A slice of $(D path). */ auto rootName(R)(R path) if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) || isNarrowString!R) && !isConvertibleToString!R) { if (path.empty) goto Lnull; version (Posix) { if (isDirSeparator(path[0])) return path[0 .. 1]; } else version (Windows) { if (isDirSeparator(path[0])) { if (isUNC(path)) return path[0 .. uncRootLength(path)]; else return path[0 .. 1]; } else if (path.length >= 3 && isDriveSeparator(path[1]) && isDirSeparator(path[2])) { return path[0 .. 3]; } } else static assert (0, "unsupported platform"); assert (!isRooted(path)); Lnull: static if (is(StringTypeOf!R)) return null; // legacy code may rely on null return rather than slice else return path[0..0]; } /// unittest { assert (rootName("") is null); assert (rootName("foo") is null); assert (rootName("/") == "/"); assert (rootName("/foo/bar") == "/"); version (Windows) { assert (rootName("d:foo") is null); assert (rootName(`d:\foo`) == `d:\`); assert (rootName(`\\server\share\foo`) == `\\server\share`); assert (rootName(`\\server\share`) == `\\server\share`); } } unittest { assert (testAliasedString!rootName("/foo/bar")); } unittest { import std.array; import std.utf : byChar; assert (rootName("".byChar).array == ""); assert (rootName("foo".byChar).array == ""); assert (rootName("/".byChar).array == "/"); assert (rootName("/foo/bar".byChar).array == "/"); version (Windows) { assert (rootName("d:foo".byChar).array == ""); assert (rootName(`d:\foo`.byChar).array == `d:\`); assert (rootName(`\\server\share\foo`.byChar).array == `\\server\share`); assert (rootName(`\\server\share`.byChar).array == `\\server\share`); } } auto rootName(R)(R path) if (isConvertibleToString!R) { return rootName!(StringTypeOf!R)(path); } /** Get the drive portion of a path. Params: path = string or range of characters Returns: A slice of $(D _path) that is the drive, or an empty range if the drive is not specified. In the case of UNC paths, the network share is returned. Always returns an empty range on POSIX. */ auto driveName(R)(R path) if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) || isNarrowString!R) && !isConvertibleToString!R) { version (Windows) { if (hasDrive(path)) return path[0 .. 2]; else if (isUNC(path)) return path[0 .. uncRootLength(path)]; } static if (isSomeString!R) return cast(ElementEncodingType!R[])null; // legacy code may rely on null return rather than slice else return path[0..0]; } /// unittest { version (Posix) assert (driveName("c:/foo").empty); version (Windows) { assert (driveName(`dir\file`).empty); assert (driveName(`d:file`) == "d:"); assert (driveName(`d:\file`) == "d:"); assert (driveName("d:") == "d:"); assert (driveName(`\\server\share\file`) == `\\server\share`); assert (driveName(`\\server\share\`) == `\\server\share`); assert (driveName(`\\server\share`) == `\\server\share`); static assert (driveName(`d:\file`) == "d:"); } } auto driveName(R)(auto ref R path) if (isConvertibleToString!R) { return driveName!(StringTypeOf!R)(path); } unittest { assert(testAliasedString!driveName(`d:\file`)); } unittest { import std.array; import std.utf : byChar; version (Posix) assert (driveName("c:/foo".byChar).empty); version (Windows) { assert (driveName(`dir\file`.byChar).empty); assert (driveName(`d:file`.byChar).array == "d:"); assert (driveName(`d:\file`.byChar).array == "d:"); assert (driveName("d:".byChar).array == "d:"); assert (driveName(`\\server\share\file`.byChar).array == `\\server\share`); assert (driveName(`\\server\share\`.byChar).array == `\\server\share`); assert (driveName(`\\server\share`.byChar).array == `\\server\share`); static assert (driveName(`d:\file`).array == "d:"); } } /** Strips the drive from a Windows path. On POSIX, the path is returned unaltered. Params: path = A pathname Returns: A slice of path without the drive component. */ auto stripDrive(R)(R path) if ((isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) || isNarrowString!R) && !isConvertibleToString!R) { version(Windows) { if (hasDrive!(BaseOf!R)(path)) return path[2 .. path.length]; else if (isUNC!(BaseOf!R)(path)) return path[uncRootLength!(BaseOf!R)(path) .. path.length]; } return path; } /// unittest { version (Windows) { assert (stripDrive(`d:\dir\file`) == `\dir\file`); assert (stripDrive(`\\server\share\dir\file`) == `\dir\file`); } } auto stripDrive(R)(auto ref R path) if (isConvertibleToString!R) { return stripDrive!(StringTypeOf!R)(path); } unittest { assert(testAliasedString!stripDrive(`d:\dir\file`)); } unittest { version(Windows) { assert (stripDrive(`d:\dir\file`) == `\dir\file`); assert (stripDrive(`\\server\share\dir\file`) == `\dir\file`); static assert (stripDrive(`d:\dir\file`) == `\dir\file`); auto r = MockRange!(immutable(char))(`d:\dir\file`); auto s = r.stripDrive(); foreach (i, c; `\dir\file`) assert(s[i] == c); } version(Posix) { assert (stripDrive(`d:\dir\file`) == `d:\dir\file`); auto r = MockRange!(immutable(char))(`d:\dir\file`); auto s = r.stripDrive(); foreach (i, c; `d:\dir\file`) assert(s[i] == c); } } /* Helper function that returns the position of the filename/extension separator dot in path. Params: path = file spec as string or indexable range Returns: index of extension separator (the dot), or -1 if not found */ private ptrdiff_t extSeparatorPos(R)(const R path) if (isRandomAccessRange!R && hasLength!R && isSomeChar!(ElementType!R) || isNarrowString!R) { for (auto i = path.length; i-- > 0 && !isSeparator(path[i]); ) { if (path[i] == '.' && i > 0 && !isSeparator(path[i-1])) return i; } return -1; } unittest { assert (extSeparatorPos("file") == -1); assert (extSeparatorPos("file.ext"w) == 4); assert (extSeparatorPos("file.ext1.ext2"d) == 9); assert (extSeparatorPos(".foo".dup) == -1); assert (extSeparatorPos(".foo.ext"w.dup) == 4); } unittest { assert (extSeparatorPos("dir/file"d.dup) == -1); assert (extSeparatorPos("dir/file.ext") == 8); assert (extSeparatorPos("dir/file.ext1.ext2"w) == 13); assert (extSeparatorPos("dir/.foo"d) == -1); assert (extSeparatorPos("dir/.foo.ext".dup) == 8); version(Windows) { assert (extSeparatorPos("dir\\file") == -1); assert (extSeparatorPos("dir\\file.ext") == 8); assert (extSeparatorPos("dir\\file.ext1.ext2") == 13); assert (extSeparatorPos("dir\\.foo") == -1); assert (extSeparatorPos("dir\\.foo.ext") == 8); assert (extSeparatorPos("d:file") == -1); assert (extSeparatorPos("d:file.ext") == 6); assert (extSeparatorPos("d:file.ext1.ext2") == 11); assert (extSeparatorPos("d:.foo") == -1); assert (extSeparatorPos("d:.foo.ext") == 6); } static assert (extSeparatorPos("file") == -1); static assert (extSeparatorPos("file.ext"w) == 4); } /** Params: path = A path name. Returns: The _extension part of a file name, including the dot. If there is no _extension, $(D null) is returned. */ auto extension(R)(R path) if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) || is(StringTypeOf!R)) { auto i = extSeparatorPos!(BaseOf!R)(path); if (i == -1) { static if (is(StringTypeOf!R)) return StringTypeOf!R.init[]; // which is null else return path[0 .. 0]; } else return path[i .. path.length]; } /// unittest { assert (extension("file").empty); assert (extension("file.") == "."); assert (extension("file.ext"w) == ".ext"); assert (extension("file.ext1.ext2"d) == ".ext2"); assert (extension(".foo".dup).empty); assert (extension(".foo.ext"w.dup) == ".ext"); static assert (extension("file").empty); static assert (extension("file.ext") == ".ext"); } unittest { { auto r = MockRange!(immutable(char))(`file.ext1.ext2`); auto s = r.extension(); foreach (i, c; `.ext2`) assert(s[i] == c); } static struct DirEntry { string s; alias s this; } assert (extension(DirEntry("file")).empty); } /** Remove extension from path. Params: path = string or range to be sliced Returns: slice of path with the extension (if any) stripped off */ auto stripExtension(R)(R path) if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) || isNarrowString!R) && !isConvertibleToString!R) { auto i = extSeparatorPos(path); return (i == -1) ? path : path[0 .. i]; } /// unittest { assert (stripExtension("file") == "file"); assert (stripExtension("file.ext") == "file"); assert (stripExtension("file.ext1.ext2") == "file.ext1"); assert (stripExtension("file.") == "file"); assert (stripExtension(".file") == ".file"); assert (stripExtension(".file.ext") == ".file"); assert (stripExtension("dir/file.ext") == "dir/file"); } auto stripExtension(R)(auto ref R path) if (isConvertibleToString!R) { return stripExtension!(StringTypeOf!R)(path); } unittest { assert (testAliasedString!stripExtension("file")); } unittest { assert (stripExtension("file.ext"w) == "file"); assert (stripExtension("file.ext1.ext2"d) == "file.ext1"); import std.array; import std.utf : byChar, byWchar, byDchar; assert (stripExtension("file".byChar).array == "file"); assert (stripExtension("file.ext"w.byWchar).array == "file"); assert (stripExtension("file.ext1.ext2"d.byDchar).array == "file.ext1"); } /** Params: path = A path name ext = The new extension Returns: A string containing the _path given by $(D path), but where the extension has been set to $(D ext). If the filename already has an extension, it is replaced. If not, the extension is simply appended to the filename. Including a leading dot in $(D ext) is optional. If the extension is empty, this function is equivalent to $(LREF stripExtension). This function normally allocates a new string (the possible exception being the case when path is immutable and doesn't already have an extension). See_Also: $(LREF withExtension) which does not allocate and returns a lazy range. */ immutable(Unqual!C1)[] setExtension(C1, C2)(in C1[] path, in C2[] ext) if (isSomeChar!C1 && !is(C1 == immutable) && is(Unqual!C1 == Unqual!C2)) { try { import std.conv : to; return withExtension(path, ext).to!(typeof(return)); } catch (Exception e) { assert(0); } } ///ditto immutable(C1)[] setExtension(C1, C2)(immutable(C1)[] path, const(C2)[] ext) if (isSomeChar!C1 && is(Unqual!C1 == Unqual!C2)) { if (ext.length == 0) return stripExtension(path); try { import std.conv : to; return withExtension(path, ext).to!(typeof(return)); } catch (Exception e) { assert(0); } } /// unittest { assert (setExtension("file", "ext") == "file.ext"); assert (setExtension("file"w, ".ext"w) == "file.ext"); assert (setExtension("file."d, "ext"d) == "file.ext"); assert (setExtension("file.", ".ext") == "file.ext"); assert (setExtension("file.old"w, "new"w) == "file.new"); assert (setExtension("file.old"d, ".new"d) == "file.new"); } unittest { assert (setExtension("file"w.dup, "ext"w) == "file.ext"); assert (setExtension("file"w.dup, ".ext"w) == "file.ext"); assert (setExtension("file."w, "ext"w.dup) == "file.ext"); assert (setExtension("file."w, ".ext"w.dup) == "file.ext"); assert (setExtension("file.old"d.dup, "new"d) == "file.new"); assert (setExtension("file.old"d.dup, ".new"d) == "file.new"); static assert (setExtension("file", "ext") == "file.ext"); static assert (setExtension("file.old", "new") == "file.new"); static assert (setExtension("file"w.dup, "ext"w) == "file.ext"); static assert (setExtension("file.old"d.dup, "new"d) == "file.new"); // Issue 10601 assert (setExtension("file", "") == "file"); assert (setExtension("file.ext", "") == "file"); } /************ * Replace existing extension on filespec with new one. * * Params: * path = string or random access range representing a filespec * ext = the new extension * Returns: * Range with $(D path)'s extension (if any) replaced with $(D ext). * The element encoding type of the returned range will be the same as $(D path)'s. * See_Also: * $(LREF setExtension) */ auto withExtension(R, C)(R path, C[] ext) if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) || isNarrowString!R) && !isConvertibleToString!R && isSomeChar!C) { import std.range : only, chain; import std.utf : byUTF; alias CR = Unqual!(ElementEncodingType!R); auto dot = only(CR('.')); if (ext.length == 0 || ext[0] == '.') dot.popFront(); // so dot is an empty range, too return chain(stripExtension(path).byUTF!CR, dot, ext.byUTF!CR); } /// unittest { import std.array; assert (withExtension("file", "ext").array == "file.ext"); assert (withExtension("file"w, ".ext"w).array == "file.ext"); assert (withExtension("file.ext"w, ".").array == "file."); import std.utf : byChar, byWchar; assert (withExtension("file".byChar, "ext").array == "file.ext"); assert (withExtension("file"w.byWchar, ".ext"w).array == "file.ext"w); assert (withExtension("file.ext"w.byWchar, ".").array == "file."w); } auto withExtension(R, C)(auto ref R path, C[] ext) if (isConvertibleToString!R) { return withExtension!(StringTypeOf!R)(path, ext); } unittest { assert (testAliasedString!withExtension("file", "ext")); } /** Params: path = A path name. ext = The default extension to use. Returns: The _path given by $(D path), with the extension given by $(D ext) appended if the path doesn't already have one. Including the dot in the extension is optional. This function always allocates a new string, except in the case when path is immutable and already has an extension. */ immutable(Unqual!C1)[] defaultExtension(C1, C2)(in C1[] path, in C2[] ext) if (isSomeChar!C1 && is(Unqual!C1 == Unqual!C2)) { import std.conv : to; return withDefaultExtension(path, ext).to!(typeof(return)); } /// unittest { assert (defaultExtension("file", "ext") == "file.ext"); assert (defaultExtension("file", ".ext") == "file.ext"); assert (defaultExtension("file.", "ext") == "file."); assert (defaultExtension("file.old", "new") == "file.old"); assert (defaultExtension("file.old", ".new") == "file.old"); } unittest { assert (defaultExtension("file"w.dup, "ext"w) == "file.ext"); assert (defaultExtension("file.old"d.dup, "new"d) == "file.old"); static assert (defaultExtension("file", "ext") == "file.ext"); static assert (defaultExtension("file.old", "new") == "file.old"); static assert (defaultExtension("file"w.dup, "ext"w) == "file.ext"); static assert (defaultExtension("file.old"d.dup, "new"d) == "file.old"); } /******************************** * Set the extension of $(D path) to $(D ext) if $(D path) doesn't have one. * * Params: * path = filespec as string or range * ext = extension, may have leading '.' * Returns: * range with the result */ auto withDefaultExtension(R, C)(R path, C[] ext) if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) || isNarrowString!R) && !isConvertibleToString!R && isSomeChar!C) { import std.range : only, chain; import std.utf : byUTF; alias CR = Unqual!(ElementEncodingType!R); auto dot = only(CR('.')); auto i = extSeparatorPos(path); if (i == -1) { if (ext.length > 0 && ext[0] == '.') ext = ext[1 .. $]; // remove any leading . from ext[] } else { // path already has an extension, so make these empty ext = ext[0 .. 0]; dot.popFront(); } return chain(path.byUTF!CR, dot, ext.byUTF!CR); } /// unittest { import std.array; assert (withDefaultExtension("file", "ext").array == "file.ext"); assert (withDefaultExtension("file"w, ".ext").array == "file.ext"w); assert (withDefaultExtension("file.", "ext").array == "file."); assert (withDefaultExtension("file", "").array == "file."); import std.utf : byChar, byWchar; assert (withDefaultExtension("file".byChar, "ext").array == "file.ext"); assert (withDefaultExtension("file"w.byWchar, ".ext").array == "file.ext"w); assert (withDefaultExtension("file.".byChar, "ext"d).array == "file."); assert (withDefaultExtension("file".byChar, "").array == "file."); } auto withDefaultExtension(R, C)(auto ref R path, C[] ext) if (isConvertibleToString!R) { return withDefaultExtension!(StringTypeOf!R, C)(path, ext); } unittest { assert (testAliasedString!withDefaultExtension("file", "ext")); } /** Combines one or more path segments. This function takes a set of path segments, given as an input range of string elements or as a set of string arguments, and concatenates them with each other. Directory separators are inserted between segments if necessary. If any of the path segments are absolute (as defined by $(LREF isAbsolute)), the preceding segments will be dropped. On Windows, if one of the path segments are rooted, but not absolute (e.g. $(D `\foo`)), all preceding path segments down to the previous root will be dropped. (See below for an example.) This function always allocates memory to hold the resulting path. The variadic overload is guaranteed to only perform a single allocation, as is the range version if $(D paths) is a forward range. Params: segments = An input range of segments to assemble the path from. Returns: The assembled path. */ immutable(ElementEncodingType!(ElementType!Range))[] buildPath(Range)(Range segments) if (isInputRange!Range && isSomeString!(ElementType!Range)) { if (segments.empty) return null; // If this is a forward range, we can pre-calculate a maximum length. static if (isForwardRange!Range) { auto segments2 = segments.save; size_t precalc = 0; foreach (segment; segments2) precalc += segment.length + 1; } // Otherwise, just venture a guess and resize later if necessary. else size_t precalc = 255; auto buf = new Unqual!(ElementEncodingType!(ElementType!Range))[](precalc); size_t pos = 0; foreach (segment; segments) { if (segment.empty) continue; static if (!isForwardRange!Range) { immutable neededLength = pos + segment.length + 1; if (buf.length < neededLength) buf.length = reserve(buf, neededLength + buf.length/2); } auto r = chainPath(buf[0 .. pos], segment); size_t i; foreach (c; r) { buf[i] = c; ++i; } pos = i; } static U trustedCast(U, V)(V v) @trusted pure nothrow { return cast(U) v; } return trustedCast!(typeof(return))(buf[0 .. pos]); } /// ditto immutable(C)[] buildPath(C)(const(C)[][] paths...) @safe pure nothrow if (isSomeChar!C) { return buildPath!(typeof(paths))(paths); } /// unittest { version (Posix) { assert (buildPath("foo", "bar", "baz") == "foo/bar/baz"); assert (buildPath("/foo/", "bar/baz") == "/foo/bar/baz"); assert (buildPath("/foo", "/bar") == "/bar"); } version (Windows) { assert (buildPath("foo", "bar", "baz") == `foo\bar\baz`); assert (buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`); assert (buildPath("foo", `d:\bar`) == `d:\bar`); assert (buildPath("foo", `\bar`) == `\bar`); assert (buildPath(`c:\foo`, `\bar`) == `c:\bar`); } } unittest // non-documented { import std.range; // ir() wraps an array in a plain (i.e. non-forward) input range, so that // we can test both code paths InputRange!(C[]) ir(C)(C[][] p...) { return inputRangeObject(p); } version (Posix) { assert (buildPath("foo") == "foo"); assert (buildPath("/foo/") == "/foo/"); assert (buildPath("foo", "bar") == "foo/bar"); assert (buildPath("foo", "bar", "baz") == "foo/bar/baz"); assert (buildPath("foo/".dup, "bar") == "foo/bar"); assert (buildPath("foo///", "bar".dup) == "foo///bar"); assert (buildPath("/foo"w, "bar"w) == "/foo/bar"); assert (buildPath("foo"w.dup, "/bar"w) == "/bar"); assert (buildPath("foo"w, "bar/"w.dup) == "foo/bar/"); assert (buildPath("/"d, "foo"d) == "/foo"); assert (buildPath(""d.dup, "foo"d) == "foo"); assert (buildPath("foo"d, ""d.dup) == "foo"); assert (buildPath("foo", "bar".dup, "baz") == "foo/bar/baz"); assert (buildPath("foo"w, "/bar"w, "baz"w.dup) == "/bar/baz"); static assert (buildPath("foo", "bar", "baz") == "foo/bar/baz"); static assert (buildPath("foo", "/bar", "baz") == "/bar/baz"); // The following are mostly duplicates of the above, except that the // range version does not accept mixed constness. assert (buildPath(ir("foo")) == "foo"); assert (buildPath(ir("/foo/")) == "/foo/"); assert (buildPath(ir("foo", "bar")) == "foo/bar"); assert (buildPath(ir("foo", "bar", "baz")) == "foo/bar/baz"); assert (buildPath(ir("foo/".dup, "bar".dup)) == "foo/bar"); assert (buildPath(ir("foo///".dup, "bar".dup)) == "foo///bar"); assert (buildPath(ir("/foo"w, "bar"w)) == "/foo/bar"); assert (buildPath(ir("foo"w.dup, "/bar"w.dup)) == "/bar"); assert (buildPath(ir("foo"w.dup, "bar/"w.dup)) == "foo/bar/"); assert (buildPath(ir("/"d, "foo"d)) == "/foo"); assert (buildPath(ir(""d.dup, "foo"d.dup)) == "foo"); assert (buildPath(ir("foo"d, ""d)) == "foo"); assert (buildPath(ir("foo", "bar", "baz")) == "foo/bar/baz"); assert (buildPath(ir("foo"w.dup, "/bar"w.dup, "baz"w.dup)) == "/bar/baz"); } version (Windows) { assert (buildPath("foo") == "foo"); assert (buildPath(`\foo/`) == `\foo/`); assert (buildPath("foo", "bar", "baz") == `foo\bar\baz`); assert (buildPath("foo", `\bar`) == `\bar`); assert (buildPath(`c:\foo`, "bar") == `c:\foo\bar`); assert (buildPath("foo"w, `d:\bar`w.dup) == `d:\bar`); assert (buildPath(`c:\foo\bar`, `\baz`) == `c:\baz`); assert (buildPath(`\\foo\bar\baz`d, `foo`d, `\bar`d) == `\\foo\bar\bar`d); static assert (buildPath("foo", "bar", "baz") == `foo\bar\baz`); static assert (buildPath("foo", `c:\bar`, "baz") == `c:\bar\baz`); assert (buildPath(ir("foo")) == "foo"); assert (buildPath(ir(`\foo/`)) == `\foo/`); assert (buildPath(ir("foo", "bar", "baz")) == `foo\bar\baz`); assert (buildPath(ir("foo", `\bar`)) == `\bar`); assert (buildPath(ir(`c:\foo`, "bar")) == `c:\foo\bar`); assert (buildPath(ir("foo"w.dup, `d:\bar`w.dup)) == `d:\bar`); assert (buildPath(ir(`c:\foo\bar`, `\baz`)) == `c:\baz`); assert (buildPath(ir(`\\foo\bar\baz`d, `foo`d, `\bar`d)) == `\\foo\bar\bar`d); } // Test that allocation works as it should. auto manyShort = "aaa".repeat(1000).array(); auto manyShortCombined = join(manyShort, dirSeparator); assert (buildPath(manyShort) == manyShortCombined); assert (buildPath(ir(manyShort)) == manyShortCombined); auto fewLong = 'b'.repeat(500).array().repeat(10).array(); auto fewLongCombined = join(fewLong, dirSeparator); assert (buildPath(fewLong) == fewLongCombined); assert (buildPath(ir(fewLong)) == fewLongCombined); } unittest { // Test for issue 7397 string[] ary = ["a", "b"]; version (Posix) { assert (buildPath(ary) == "a/b"); } else version (Windows) { assert (buildPath(ary) == `a\b`); } } /** * Concatenate path segments together to form one path. * * Params: * r1 = first segment * r2 = second segment * ranges = 0 or more segments * Returns: * Lazy range which is the concatenation of r1, r2 and ranges with path separators. * The resulting element type is that of r1. * See_Also: * $(LREF buildPath) */ auto chainPath(R1, R2, Ranges...)(R1 r1, R2 r2, Ranges ranges) if ((isRandomAccessRange!R1 && hasSlicing!R1 && hasLength!R1 && isSomeChar!(ElementType!R1) || isNarrowString!R1 && !isConvertibleToString!R1) && (isRandomAccessRange!R2 && hasSlicing!R2 && hasLength!R2 && isSomeChar!(ElementType!R2) || isNarrowString!R2 && !isConvertibleToString!R2) && (Ranges.length == 0 || is(typeof(chainPath(r2, ranges)))) ) { static if (Ranges.length) { return chainPath(chainPath(r1, r2), ranges); } else { import std.range : only, chain; import std.utf : byUTF; alias CR = Unqual!(ElementEncodingType!R1); auto sep = only(CR(dirSeparator[0])); bool usesep = false; auto pos = r1.length; if (pos) { if (isRooted(r2)) { version (Posix) { pos = 0; } else version (Windows) { if (isAbsolute(r2)) pos = 0; else { pos = rootName(r1).length; if (pos > 0 && isDirSeparator(r1[pos - 1])) --pos; } } else static assert(0); } else if (!isDirSeparator(r1[pos - 1])) usesep = true; } if (!usesep) sep.popFront(); // Return r1 ~ '/' ~ r2 return chain(r1[0 .. pos].byUTF!CR, sep, r2.byUTF!CR); } } /// unittest { import std.array; version (Posix) { assert (chainPath("foo", "bar", "baz").array == "foo/bar/baz"); assert (chainPath("/foo/", "bar/baz").array == "/foo/bar/baz"); assert (chainPath("/foo", "/bar").array == "/bar"); } version (Windows) { assert (chainPath("foo", "bar", "baz").array == `foo\bar\baz`); assert (chainPath(`c:\foo`, `bar\baz`).array == `c:\foo\bar\baz`); assert (chainPath("foo", `d:\bar`).array == `d:\bar`); assert (chainPath("foo", `\bar`).array == `\bar`); assert (chainPath(`c:\foo`, `\bar`).array == `c:\bar`); } import std.utf : byChar; version (Posix) { assert (chainPath("foo", "bar", "baz").array == "foo/bar/baz"); assert (chainPath("/foo/".byChar, "bar/baz").array == "/foo/bar/baz"); assert (chainPath("/foo", "/bar".byChar).array == "/bar"); } version (Windows) { assert (chainPath("foo", "bar", "baz").array == `foo\bar\baz`); assert (chainPath(`c:\foo`.byChar, `bar\baz`).array == `c:\foo\bar\baz`); assert (chainPath("foo", `d:\bar`).array == `d:\bar`); assert (chainPath("foo", `\bar`.byChar).array == `\bar`); assert (chainPath(`c:\foo`, `\bar`w).array == `c:\bar`); } } auto chainPath(Ranges...)(auto ref Ranges ranges) if (Ranges.length >= 2 && std.meta.anySatisfy!(isConvertibleToString, Ranges)) { import std.meta : staticMap; alias Types = staticMap!(convertToString, Ranges); return chainPath!Types(ranges); } unittest { assert(chainPath(TestAliasedString(null), TestAliasedString(null), TestAliasedString(null)).empty); assert(chainPath(TestAliasedString(null), TestAliasedString(null), "").empty); assert(chainPath(TestAliasedString(null), "", TestAliasedString(null)).empty); static struct S { string s; } static assert(!__traits(compiles, chainPath(TestAliasedString(null), S(""), TestAliasedString(null)))); } /** Performs the same task as $(LREF buildPath), while at the same time resolving current/parent directory symbols ($(D ".") and $(D "..")) and removing superfluous directory separators. It will return "." if the path leads to the starting directory. On Windows, slashes are replaced with backslashes. Using buildNormalizedPath on null paths will always return null. Note that this function does not resolve symbolic links. This function always allocates memory to hold the resulting path. Use $(LREF asNormalizedPath) to not allocate memory. Params: paths = An array of paths to assemble. Returns: The assembled path. */ immutable(C)[] buildNormalizedPath(C)(const(C[])[] paths...) @trusted pure nothrow if (isSomeChar!C) { import std.array; const(C)[] result; foreach (path; paths) { if (result) result = chainPath(result, path).array; else result = path; } result = asNormalizedPath(result).array; return cast(typeof(return)) result; } /// unittest { assert (buildNormalizedPath("foo", "..") == "."); version (Posix) { assert (buildNormalizedPath("/foo/./bar/..//baz/") == "/foo/baz"); assert (buildNormalizedPath("../foo/.") == "../foo"); assert (buildNormalizedPath("/foo", "bar/baz/") == "/foo/bar/baz"); assert (buildNormalizedPath("/foo", "/bar/..", "baz") == "/baz"); assert (buildNormalizedPath("foo/./bar", "../../", "../baz") == "../baz"); assert (buildNormalizedPath("/foo/./bar", "../../baz") == "/baz"); } version (Windows) { assert (buildNormalizedPath(`c:\foo\.\bar/..\\baz\`) == `c:\foo\baz`); assert (buildNormalizedPath(`..\foo\.`) == `..\foo`); assert (buildNormalizedPath(`c:\foo`, `bar\baz\`) == `c:\foo\bar\baz`); assert (buildNormalizedPath(`c:\foo`, `bar/..`) == `c:\foo`); assert (buildNormalizedPath(`\\server\share\foo`, `..\bar`) == `\\server\share\bar`); } } unittest { assert (buildNormalizedPath(".", ".") == "."); assert (buildNormalizedPath("foo", "..") == "."); assert (buildNormalizedPath("", "") is null); assert (buildNormalizedPath("", ".") == "."); assert (buildNormalizedPath(".", "") == "."); assert (buildNormalizedPath(null, "foo") == "foo"); assert (buildNormalizedPath("", "foo") == "foo"); assert (buildNormalizedPath("", "") == ""); assert (buildNormalizedPath("", null) == ""); assert (buildNormalizedPath(null, "") == ""); assert (buildNormalizedPath!(char)(null, null) == ""); version (Posix) { assert (buildNormalizedPath("/", "foo", "bar") == "/foo/bar"); assert (buildNormalizedPath("foo", "bar", "baz") == "foo/bar/baz"); assert (buildNormalizedPath("foo", "bar/baz") == "foo/bar/baz"); assert (buildNormalizedPath("foo", "bar//baz///") == "foo/bar/baz"); assert (buildNormalizedPath("/foo", "bar/baz") == "/foo/bar/baz"); assert (buildNormalizedPath("/foo", "/bar/baz") == "/bar/baz"); assert (buildNormalizedPath("/foo/..", "/bar/./baz") == "/bar/baz"); assert (buildNormalizedPath("/foo/..", "bar/baz") == "/bar/baz"); assert (buildNormalizedPath("/foo/../../", "bar/baz") == "/bar/baz"); assert (buildNormalizedPath("/foo/bar", "../baz") == "/foo/baz"); assert (buildNormalizedPath("/foo/bar", "../../baz") == "/baz"); assert (buildNormalizedPath("/foo/bar", ".././/baz/..", "wee/") == "/foo/wee"); assert (buildNormalizedPath("//foo/bar", "baz///wee") == "/foo/bar/baz/wee"); static assert (buildNormalizedPath("/foo/..", "/bar/./baz") == "/bar/baz"); } else version (Windows) { assert (buildNormalizedPath(`\`, `foo`, `bar`) == `\foo\bar`); assert (buildNormalizedPath(`foo`, `bar`, `baz`) == `foo\bar\baz`); assert (buildNormalizedPath(`foo`, `bar\baz`) == `foo\bar\baz`); assert (buildNormalizedPath(`foo`, `bar\\baz\\\`) == `foo\bar\baz`); assert (buildNormalizedPath(`\foo`, `bar\baz`) == `\foo\bar\baz`); assert (buildNormalizedPath(`\foo`, `\bar\baz`) == `\bar\baz`); assert (buildNormalizedPath(`\foo\..`, `\bar\.\baz`) == `\bar\baz`); assert (buildNormalizedPath(`\foo\..`, `bar\baz`) == `\bar\baz`); assert (buildNormalizedPath(`\foo\..\..\`, `bar\baz`) == `\bar\baz`); assert (buildNormalizedPath(`\foo\bar`, `..\baz`) == `\foo\baz`); assert (buildNormalizedPath(`\foo\bar`, `../../baz`) == `\baz`); assert (buildNormalizedPath(`\foo\bar`, `..\.\/baz\..`, `wee\`) == `\foo\wee`); assert (buildNormalizedPath(`c:\`, `foo`, `bar`) == `c:\foo\bar`); assert (buildNormalizedPath(`c:foo`, `bar`, `baz`) == `c:foo\bar\baz`); assert (buildNormalizedPath(`c:foo`, `bar\baz`) == `c:foo\bar\baz`); assert (buildNormalizedPath(`c:foo`, `bar\\baz\\\`) == `c:foo\bar\baz`); assert (buildNormalizedPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`); assert (buildNormalizedPath(`c:\foo`, `\bar\baz`) == `c:\bar\baz`); assert (buildNormalizedPath(`c:\foo\..`, `\bar\.\baz`) == `c:\bar\baz`); assert (buildNormalizedPath(`c:\foo\..`, `bar\baz`) == `c:\bar\baz`); assert (buildNormalizedPath(`c:\foo\..\..\`, `bar\baz`) == `c:\bar\baz`); assert (buildNormalizedPath(`c:\foo\bar`, `..\baz`) == `c:\foo\baz`); assert (buildNormalizedPath(`c:\foo\bar`, `..\..\baz`) == `c:\baz`); assert (buildNormalizedPath(`c:\foo\bar`, `..\.\\baz\..`, `wee\`) == `c:\foo\wee`); assert (buildNormalizedPath(`\\server\share`, `foo`, `bar`) == `\\server\share\foo\bar`); assert (buildNormalizedPath(`\\server\share\`, `foo`, `bar`) == `\\server\share\foo\bar`); assert (buildNormalizedPath(`\\server\share\foo`, `bar\baz`) == `\\server\share\foo\bar\baz`); assert (buildNormalizedPath(`\\server\share\foo`, `\bar\baz`) == `\\server\share\bar\baz`); assert (buildNormalizedPath(`\\server\share\foo\..`, `\bar\.\baz`) == `\\server\share\bar\baz`); assert (buildNormalizedPath(`\\server\share\foo\..`, `bar\baz`) == `\\server\share\bar\baz`); assert (buildNormalizedPath(`\\server\share\foo\..\..\`, `bar\baz`) == `\\server\share\bar\baz`); assert (buildNormalizedPath(`\\server\share\foo\bar`, `..\baz`) == `\\server\share\foo\baz`); assert (buildNormalizedPath(`\\server\share\foo\bar`, `..\..\baz`) == `\\server\share\baz`); assert (buildNormalizedPath(`\\server\share\foo\bar`, `..\.\\baz\..`, `wee\`) == `\\server\share\foo\wee`); static assert (buildNormalizedPath(`\foo\..\..\`, `bar\baz`) == `\bar\baz`); } else static assert (0); } unittest { // Test for issue 7397 string[] ary = ["a", "b"]; version (Posix) { assert (buildNormalizedPath(ary) == "a/b"); } else version (Windows) { assert (buildNormalizedPath(ary) == `a\b`); } } /** Normalize a path by resolving current/parent directory symbols ($(D ".") and $(D "..")) and removing superfluous directory separators. It will return "." if the path leads to the starting directory. On Windows, slashes are replaced with backslashes. Using asNormalizedPath on empty paths will always return an empty path. Does not resolve symbolic links. This function always allocates memory to hold the resulting path. Use $(LREF buildNormalizedPath) to allocate memory and return a string. Params: path = string or random access range representing the _path to normalize Returns: normalized path as a forward range */ auto asNormalizedPath(R)(R path) if (isSomeChar!(ElementEncodingType!R) && (isRandomAccessRange!R && hasSlicing!R && hasLength!R || isNarrowString!R) && !isConvertibleToString!R) { alias C = Unqual!(ElementEncodingType!R); alias S = typeof(path[0..0]); static struct Result { @property bool empty() { return c == c.init; } @property C front() { return c; } void popFront() { C lastc = c; c = c.init; if (!element.empty) { c = getElement0(); return; } L1: while (1) { if (elements.empty) { element = element[0..0]; return; } element = elements.front; elements.popFront(); if (isDot(element) || (rooted && isDotDot(element))) continue; if (rooted || !isDotDot(element)) { int n = 1; auto elements2 = elements.save; while (!elements2.empty) { auto e = elements2.front; elements2.popFront(); if (isDot(e)) continue; if (isDotDot(e)) { --n; if (n == 0) { elements = elements2; element = element[0..0]; continue L1; } } else ++n; } } break; } static assert(dirSeparator.length == 1); if (lastc == dirSeparator[0] || lastc == lastc.init) c = getElement0(); else c = dirSeparator[0]; } static if (isForwardRange!R) { @property auto save() { auto result = this; result.element = element.save; result.elements = elements.save; return result; } } private: this(R path) { element = rootName(path); auto i = element.length; while (i < path.length && isDirSeparator(path[i])) ++i; rooted = i > 0; elements = pathSplitter(path[i .. $]); popFront(); if (c == c.init && path.length) c = C('.'); } C getElement0() { static if (isNarrowString!S) // avoid autodecode { C c = element[0]; element = element[1 .. $]; } else { C c = element.front; element.popFront(); } version (Windows) { if (c == '/') // can appear in root element c = '\\'; // use native Windows directory separator } return c; } // See if elem is "." static bool isDot(S elem) { return elem.length == 1 && elem[0] == '.'; } // See if elem is ".." static bool isDotDot(S elem) { return elem.length == 2 && elem[0] == '.' && elem[1] == '.'; } bool rooted; // the path starts with a root directory C c; S element; typeof(pathSplitter(path[0..0])) elements; } return Result(path); } /// unittest { import std.array; assert (asNormalizedPath("foo/..").array == "."); version (Posix) { assert (asNormalizedPath("/foo/./bar/..//baz/").array == "/foo/baz"); assert (asNormalizedPath("../foo/.").array == "../foo"); assert (asNormalizedPath("/foo/bar/baz/").array == "/foo/bar/baz"); assert (asNormalizedPath("/foo/./bar/../../baz").array == "/baz"); } version (Windows) { assert (asNormalizedPath(`c:\foo\.\bar/..\\baz\`).array == `c:\foo\baz`); assert (asNormalizedPath(`..\foo\.`).array == `..\foo`); assert (asNormalizedPath(`c:\foo\bar\baz\`).array == `c:\foo\bar\baz`); assert (asNormalizedPath(`c:\foo\bar/..`).array == `c:\foo`); assert (asNormalizedPath(`\\server\share\foo\..\bar`).array == `\\server\share\bar`); } } auto asNormalizedPath(R)(auto ref R path) if (isConvertibleToString!R) { return asNormalizedPath!(StringTypeOf!R)(path); } unittest { assert(testAliasedString!asNormalizedPath(null)); } unittest { import std.array; import std.utf : byChar; assert (asNormalizedPath("").array is null); assert (asNormalizedPath("foo").array == "foo"); assert (asNormalizedPath(".").array == "."); assert (asNormalizedPath("./.").array == "."); assert (asNormalizedPath("foo/..").array == "."); auto save = asNormalizedPath("fob").save; save.popFront(); assert(save.front == 'o'); version (Posix) { assert (asNormalizedPath("/foo/bar").array == "/foo/bar"); assert (asNormalizedPath("foo/bar/baz").array == "foo/bar/baz"); assert (asNormalizedPath("foo/bar/baz").array == "foo/bar/baz"); assert (asNormalizedPath("foo/bar//baz///").array == "foo/bar/baz"); assert (asNormalizedPath("/foo/bar/baz").array == "/foo/bar/baz"); assert (asNormalizedPath("/foo/../bar/baz").array == "/bar/baz"); assert (asNormalizedPath("/foo/../..//bar/baz").array == "/bar/baz"); assert (asNormalizedPath("/foo/bar/../baz").array == "/foo/baz"); assert (asNormalizedPath("/foo/bar/../../baz").array == "/baz"); assert (asNormalizedPath("/foo/bar/.././/baz/../wee/").array == "/foo/wee"); assert (asNormalizedPath("//foo/bar/baz///wee").array == "/foo/bar/baz/wee"); assert (asNormalizedPath("foo//bar").array == "foo/bar"); assert (asNormalizedPath("foo/bar").array == "foo/bar"); //Curent dir path assert (asNormalizedPath("./").array == "."); assert (asNormalizedPath("././").array == "."); assert (asNormalizedPath("./foo/..").array == "."); assert (asNormalizedPath("foo/..").array == "."); } else version (Windows) { assert (asNormalizedPath(`\foo\bar`).array == `\foo\bar`); assert (asNormalizedPath(`foo\bar\baz`).array == `foo\bar\baz`); assert (asNormalizedPath(`foo\bar\baz`).array == `foo\bar\baz`); assert (asNormalizedPath(`foo\bar\\baz\\\`).array == `foo\bar\baz`); assert (asNormalizedPath(`\foo\bar\baz`).array == `\foo\bar\baz`); assert (asNormalizedPath(`\foo\..\\bar\.\baz`).array == `\bar\baz`); assert (asNormalizedPath(`\foo\..\bar\baz`).array == `\bar\baz`); assert (asNormalizedPath(`\foo\..\..\\bar\baz`).array == `\bar\baz`); assert (asNormalizedPath(`\foo\bar\..\baz`).array == `\foo\baz`); assert (asNormalizedPath(`\foo\bar\../../baz`).array == `\baz`); assert (asNormalizedPath(`\foo\bar\..\.\/baz\..\wee\`).array == `\foo\wee`); assert (asNormalizedPath(`c:\foo\bar`).array == `c:\foo\bar`); assert (asNormalizedPath(`c:foo\bar\baz`).array == `c:foo\bar\baz`); assert (asNormalizedPath(`c:foo\bar\baz`).array == `c:foo\bar\baz`); assert (asNormalizedPath(`c:foo\bar\\baz\\\`).array == `c:foo\bar\baz`); assert (asNormalizedPath(`c:\foo\bar\baz`).array == `c:\foo\bar\baz`); assert (asNormalizedPath(`c:\foo\..\\bar\.\baz`).array == `c:\bar\baz`); assert (asNormalizedPath(`c:\foo\..\bar\baz`).array == `c:\bar\baz`); assert (asNormalizedPath(`c:\foo\..\..\\bar\baz`).array == `c:\bar\baz`); assert (asNormalizedPath(`c:\foo\bar\..\baz`).array == `c:\foo\baz`); assert (asNormalizedPath(`c:\foo\bar\..\..\baz`).array == `c:\baz`); assert (asNormalizedPath(`c:\foo\bar\..\.\\baz\..\wee\`).array == `c:\foo\wee`); assert (asNormalizedPath(`\\server\share\foo\bar`).array == `\\server\share\foo\bar`); assert (asNormalizedPath(`\\server\share\\foo\bar`).array == `\\server\share\foo\bar`); assert (asNormalizedPath(`\\server\share\foo\bar\baz`).array == `\\server\share\foo\bar\baz`); assert (asNormalizedPath(`\\server\share\foo\..\\bar\.\baz`).array == `\\server\share\bar\baz`); assert (asNormalizedPath(`\\server\share\foo\..\bar\baz`).array == `\\server\share\bar\baz`); assert (asNormalizedPath(`\\server\share\foo\..\..\\bar\baz`).array == `\\server\share\bar\baz`); assert (asNormalizedPath(`\\server\share\foo\bar\..\baz`).array == `\\server\share\foo\baz`); assert (asNormalizedPath(`\\server\share\foo\bar\..\..\baz`).array == `\\server\share\baz`); assert (asNormalizedPath(`\\server\share\foo\bar\..\.\\baz\..\wee\`).array == `\\server\share\foo\wee`); static assert (asNormalizedPath(`\foo\..\..\\bar\baz`).array == `\bar\baz`); assert (asNormalizedPath("foo//bar").array == `foo\bar`); //Curent dir path assert (asNormalizedPath(`.\`).array == "."); assert (asNormalizedPath(`.\.\`).array == "."); assert (asNormalizedPath(`.\foo\..`).array == "."); assert (asNormalizedPath(`foo\..`).array == "."); } else static assert (0); } unittest { import std.array; version (Posix) { // Trivial assert (asNormalizedPath("").empty); assert (asNormalizedPath("foo/bar").array == "foo/bar"); // Correct handling of leading slashes assert (asNormalizedPath("/").array == "/"); assert (asNormalizedPath("///").array == "/"); assert (asNormalizedPath("////").array == "/"); assert (asNormalizedPath("/foo/bar").array == "/foo/bar"); assert (asNormalizedPath("//foo/bar").array == "/foo/bar"); assert (asNormalizedPath("///foo/bar").array == "/foo/bar"); assert (asNormalizedPath("////foo/bar").array == "/foo/bar"); // Correct handling of single-dot symbol (current directory) assert (asNormalizedPath("/./foo").array == "/foo"); assert (asNormalizedPath("/foo/./bar").array == "/foo/bar"); assert (asNormalizedPath("./foo").array == "foo"); assert (asNormalizedPath("././foo").array == "foo"); assert (asNormalizedPath("foo/././bar").array == "foo/bar"); // Correct handling of double-dot symbol (previous directory) assert (asNormalizedPath("/foo/../bar").array == "/bar"); assert (asNormalizedPath("/foo/../../bar").array == "/bar"); assert (asNormalizedPath("/../foo").array == "/foo"); assert (asNormalizedPath("/../../foo").array == "/foo"); assert (asNormalizedPath("/foo/..").array == "/"); assert (asNormalizedPath("/foo/../..").array == "/"); assert (asNormalizedPath("foo/../bar").array == "bar"); assert (asNormalizedPath("foo/../../bar").array == "../bar"); assert (asNormalizedPath("../foo").array == "../foo"); assert (asNormalizedPath("../../foo").array == "../../foo"); assert (asNormalizedPath("../foo/../bar").array == "../bar"); assert (asNormalizedPath(".././../foo").array == "../../foo"); assert (asNormalizedPath("foo/bar/..").array == "foo"); assert (asNormalizedPath("/foo/../..").array == "/"); // The ultimate path assert (asNormalizedPath("/foo/../bar//./../...///baz//").array == "/.../baz"); static assert (asNormalizedPath("/foo/../bar//./../...///baz//").array == "/.../baz"); } else version (Windows) { // Trivial assert (asNormalizedPath("").empty); assert (asNormalizedPath(`foo\bar`).array == `foo\bar`); assert (asNormalizedPath("foo/bar").array == `foo\bar`); // Correct handling of absolute paths assert (asNormalizedPath("/").array == `\`); assert (asNormalizedPath(`\`).array == `\`); assert (asNormalizedPath(`\\\`).array == `\`); assert (asNormalizedPath(`\\\\`).array == `\`); assert (asNormalizedPath(`\foo\bar`).array == `\foo\bar`); assert (asNormalizedPath(`\\foo`).array == `\\foo`); assert (asNormalizedPath(`\\foo\\`).array == `\\foo`); assert (asNormalizedPath(`\\foo/bar`).array == `\\foo\bar`); assert (asNormalizedPath(`\\\foo\bar`).array == `\foo\bar`); assert (asNormalizedPath(`\\\\foo\bar`).array == `\foo\bar`); assert (asNormalizedPath(`c:\`).array == `c:\`); assert (asNormalizedPath(`c:\foo\bar`).array == `c:\foo\bar`); assert (asNormalizedPath(`c:\\foo\bar`).array == `c:\foo\bar`); // Correct handling of single-dot symbol (current directory) assert (asNormalizedPath(`\./foo`).array == `\foo`); assert (asNormalizedPath(`\foo/.\bar`).array == `\foo\bar`); assert (asNormalizedPath(`.\foo`).array == `foo`); assert (asNormalizedPath(`./.\foo`).array == `foo`); assert (asNormalizedPath(`foo\.\./bar`).array == `foo\bar`); // Correct handling of double-dot symbol (previous directory) assert (asNormalizedPath(`\foo\..\bar`).array == `\bar`); assert (asNormalizedPath(`\foo\../..\bar`).array == `\bar`); assert (asNormalizedPath(`\..\foo`).array == `\foo`); assert (asNormalizedPath(`\..\..\foo`).array == `\foo`); assert (asNormalizedPath(`\foo\..`).array == `\`); assert (asNormalizedPath(`\foo\../..`).array == `\`); assert (asNormalizedPath(`foo\..\bar`).array == `bar`); assert (asNormalizedPath(`foo\..\../bar`).array == `..\bar`); assert (asNormalizedPath(`..\foo`).array == `..\foo`); assert (asNormalizedPath(`..\..\foo`).array == `..\..\foo`); assert (asNormalizedPath(`..\foo\..\bar`).array == `..\bar`); assert (asNormalizedPath(`..\.\..\foo`).array == `..\..\foo`); assert (asNormalizedPath(`foo\bar\..`).array == `foo`); assert (asNormalizedPath(`\foo\..\..`).array == `\`); assert (asNormalizedPath(`c:\foo\..\..`).array == `c:\`); // Correct handling of non-root path with drive specifier assert (asNormalizedPath(`c:foo`).array == `c:foo`); assert (asNormalizedPath(`c:..\foo\.\..\bar`).array == `c:..\bar`); // The ultimate path assert (asNormalizedPath(`c:\foo\..\bar\\.\..\...\\\baz\\`).array == `c:\...\baz`); static assert (asNormalizedPath(`c:\foo\..\bar\\.\..\...\\\baz\\`).array == `c:\...\baz`); } else static assert (false); } /** Slice up a path into its elements. Params: path = string or slicable random access range Returns: bidirectional range of slices of `path` */ auto pathSplitter(R)(R path) if ((isRandomAccessRange!R && hasSlicing!R || isNarrowString!R) && !isConvertibleToString!R) { static struct PathSplitter { @property bool empty() const { return pe == 0; } @property R front() { assert(!empty); return _path[fs .. fe]; } void popFront() { assert(!empty); if (ps == pe) { if (fs == bs && fe == be) { pe = 0; } else { fs = bs; fe = be; } } else { fs = ps; fe = fs; while (fe < pe && !isDirSeparator(_path[fe])) ++fe; ps = ltrim(fe, pe); } } @property R back() { assert(!empty); return _path[bs .. be]; } void popBack() { assert(!empty); if (ps == pe) { if (fs == bs && fe == be) { pe = 0; } else { bs = fs; be = fe; } } else { bs = pe; be = bs; while (bs > ps && !isDirSeparator(_path[bs - 1])) --bs; pe = rtrim(ps, bs); } } @property auto save() { return this; } private: R _path; size_t ps, pe; size_t fs, fe; size_t bs, be; this(R p) { if (p.empty) { pe = 0; return; } _path = p; ps = 0; pe = _path.length; // If path is rooted, first element is special version (Windows) { if (isUNC(_path)) { auto i = uncRootLength(_path); fs = 0; fe = i; ps = ltrim(fe, pe); } else if (isDriveRoot(_path)) { fs = 0; fe = 3; ps = ltrim(fe, pe); } else if (_path.length >= 1 && isDirSeparator(_path[0])) { fs = 0; fe = 1; ps = ltrim(fe, pe); } else { assert (!isRooted(_path)); popFront(); } } else version (Posix) { if (_path.length >= 1 && isDirSeparator(_path[0])) { fs = 0; fe = 1; ps = ltrim(fe, pe); } else { popFront(); } } else static assert (0); if (ps == pe) { bs = fs; be = fe; } else { pe = rtrim(ps, pe); popBack(); } } size_t ltrim(size_t s, size_t e) { while (s < e && isDirSeparator(_path[s])) ++s; return s; } size_t rtrim(size_t s, size_t e) { while (s < e && isDirSeparator(_path[e - 1])) --e; return e; } } return PathSplitter(path); } /// unittest { import std.algorithm.comparison : equal; import std.conv : to; assert (equal(pathSplitter("/"), ["/"])); assert (equal(pathSplitter("/foo/bar"), ["/", "foo", "bar"])); assert (equal(pathSplitter("foo/../bar//./"), ["foo", "..", "bar", "."])); version (Posix) { assert (equal(pathSplitter("//foo/bar"), ["/", "foo", "bar"])); } version (Windows) { assert (equal(pathSplitter(`foo\..\bar\/.\`), ["foo", "..", "bar", "."])); assert (equal(pathSplitter("c:"), ["c:"])); assert (equal(pathSplitter(`c:\foo\bar`), [`c:\`, "foo", "bar"])); assert (equal(pathSplitter(`c:foo\bar`), ["c:foo", "bar"])); } } auto pathSplitter(R)(auto ref R path) if (isConvertibleToString!R) { return pathSplitter!(StringTypeOf!R)(path); } unittest { import std.algorithm.comparison : equal; assert (testAliasedString!pathSplitter("/")); } unittest { // equal2 verifies that the range is the same both ways, i.e. // through front/popFront and back/popBack. import std.range; import std.algorithm; bool equal2(R1, R2)(R1 r1, R2 r2) { static assert (isBidirectionalRange!R1); return equal(r1, r2) && equal(retro(r1), retro(r2)); } assert (pathSplitter("").empty); // Root directories assert (equal2(pathSplitter("/"), ["/"])); assert (equal2(pathSplitter("//"), ["/"])); assert (equal2(pathSplitter("///"w), ["/"w])); // Absolute paths assert (equal2(pathSplitter("/foo/bar".dup), ["/", "foo", "bar"])); // General assert (equal2(pathSplitter("foo/bar"d.dup), ["foo"d, "bar"d])); assert (equal2(pathSplitter("foo//bar"), ["foo", "bar"])); assert (equal2(pathSplitter("foo/bar//"w), ["foo"w, "bar"w])); assert (equal2(pathSplitter("foo/../bar//./"d), ["foo"d, ".."d, "bar"d, "."d])); // save() auto ps1 = pathSplitter("foo/bar/baz"); auto ps2 = ps1.save; ps1.popFront(); assert (equal2(ps1, ["bar", "baz"])); assert (equal2(ps2, ["foo", "bar", "baz"])); // Platform specific version (Posix) { assert (equal2(pathSplitter("//foo/bar"w.dup), ["/"w, "foo"w, "bar"w])); } version (Windows) { assert (equal2(pathSplitter(`\`), [`\`])); assert (equal2(pathSplitter(`foo\..\bar\/.\`), ["foo", "..", "bar", "."])); assert (equal2(pathSplitter("c:"), ["c:"])); assert (equal2(pathSplitter(`c:\foo\bar`), [`c:\`, "foo", "bar"])); assert (equal2(pathSplitter(`c:foo\bar`), ["c:foo", "bar"])); assert (equal2(pathSplitter(`\\foo\bar`), [`\\foo\bar`])); assert (equal2(pathSplitter(`\\foo\bar\\`), [`\\foo\bar`])); assert (equal2(pathSplitter(`\\foo\bar\baz`), [`\\foo\bar`, "baz"])); } import std.exception; assertCTFEable!( { assert (equal(pathSplitter("/foo/bar".dup), ["/", "foo", "bar"])); }); static assert(is(typeof(pathSplitter!(const(char)[])(null).front) == const(char)[])); import std.utf : byDchar; assert (equal2(pathSplitter("foo/bar"d.byDchar), ["foo"d, "bar"d])); } /** Determines whether a path starts at a root directory. Params: path = A path name. Returns: Whether a path starts at a root directory. On POSIX, this function returns true if and only if the path starts with a slash (/). --- version (Posix) { assert (isRooted("/")); assert (isRooted("/foo")); assert (!isRooted("foo")); assert (!isRooted("../foo")); } --- On Windows, this function returns true if the path starts at the root directory of the current drive, of some other drive, or of a network drive. --- version (Windows) { assert (isRooted(`\`)); assert (isRooted(`\foo`)); assert (isRooted(`d:\foo`)); assert (isRooted(`\\foo\bar`)); assert (!isRooted("foo")); assert (!isRooted("d:foo")); } --- */ bool isRooted(R)(R path) if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || is(StringTypeOf!R)) { if (path.length >= 1 && isDirSeparator(path[0])) return true; version (Posix) return false; else version (Windows) return isAbsolute!(BaseOf!R)(path); } unittest { assert (isRooted("/")); assert (isRooted("/foo")); assert (!isRooted("foo")); assert (!isRooted("../foo")); version (Windows) { assert (isRooted(`\`)); assert (isRooted(`\foo`)); assert (isRooted(`d:\foo`)); assert (isRooted(`\\foo\bar`)); assert (!isRooted("foo")); assert (!isRooted("d:foo")); } static assert (isRooted("/foo")); static assert (!isRooted("foo")); static struct DirEntry { string s; alias s this; } assert (!isRooted(DirEntry("foo"))); } /** Determines whether a path is absolute or not. Params: path = A path name. Returns: Whether a path is absolute or not. Example: On POSIX, an absolute path starts at the root directory. (In fact, $(D _isAbsolute) is just an alias for $(LREF isRooted).) --- version (Posix) { assert (isAbsolute("/")); assert (isAbsolute("/foo")); assert (!isAbsolute("foo")); assert (!isAbsolute("../foo")); } --- On Windows, an absolute path starts at the root directory of a specific drive. Hence, it must start with $(D `d:\`) or $(D `d:/`), where $(D d) is the drive letter. Alternatively, it may be a network path, i.e. a path starting with a double (back)slash. --- version (Windows) { assert (isAbsolute(`d:\`)); assert (isAbsolute(`d:\foo`)); assert (isAbsolute(`\\foo\bar`)); assert (!isAbsolute(`\`)); assert (!isAbsolute(`\foo`)); assert (!isAbsolute("d:foo")); } --- */ version (StdDdoc) { bool isAbsolute(R)(R path) pure nothrow @safe if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || is(StringTypeOf!R)); } else version (Windows) { bool isAbsolute(R)(R path) if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || is(StringTypeOf!R)) { return isDriveRoot!(BaseOf!R)(path) || isUNC!(BaseOf!R)(path); } } else version (Posix) { alias isAbsolute = isRooted; } unittest { assert (!isAbsolute("foo")); assert (!isAbsolute("../foo"w)); static assert (!isAbsolute("foo")); version (Posix) { assert (isAbsolute("/"d)); assert (isAbsolute("/foo".dup)); static assert (isAbsolute("/foo")); } version (Windows) { assert (isAbsolute("d:\\"w)); assert (isAbsolute("d:\\foo"d)); assert (isAbsolute("\\\\foo\\bar")); assert (!isAbsolute("\\"w.dup)); assert (!isAbsolute("\\foo"d.dup)); assert (!isAbsolute("d:")); assert (!isAbsolute("d:foo")); static assert (isAbsolute(`d:\foo`)); } { auto r = MockRange!(immutable(char))(`../foo`); assert(!r.isAbsolute()); } static struct DirEntry { string s; alias s this; } assert(!isAbsolute(DirEntry("foo"))); } /** Tranforms $(D path) into an absolute _path. The following algorithm is used: $(OL $(LI If $(D path) is empty, return $(D null).) $(LI If $(D path) is already absolute, return it.) $(LI Otherwise, append $(D path) to $(D base) and return the result. If $(D base) is not specified, the current working directory is used.) ) The function allocates memory if and only if it gets to the third stage of this algorithm. Params: path = the relative path to transform base = the base directory of the relative path Returns: string of transformed path Throws: $(D Exception) if the specified _base directory is not absolute. See_Also: $(LREF asAbsolutePath) which does not allocate */ string absolutePath(string path, lazy string base = getcwd()) @safe pure { if (path.empty) return null; if (isAbsolute(path)) return path; auto baseVar = base; if (!isAbsolute(baseVar)) throw new Exception("Base directory must be absolute"); import std.array; return chainPath(baseVar, path).array; } /// unittest { version (Posix) { assert (absolutePath("some/file", "/foo/bar") == "/foo/bar/some/file"); assert (absolutePath("../file", "/foo/bar") == "/foo/bar/../file"); assert (absolutePath("/some/file", "/foo/bar") == "/some/file"); } version (Windows) { assert (absolutePath(`some\file`, `c:\foo\bar`) == `c:\foo\bar\some\file`); assert (absolutePath(`..\file`, `c:\foo\bar`) == `c:\foo\bar\..\file`); assert (absolutePath(`c:\some\file`, `c:\foo\bar`) == `c:\some\file`); assert (absolutePath(`\`, `c:\`) == `c:\`); assert (absolutePath(`\some\file`, `c:\foo\bar`) == `c:\some\file`); } } unittest { version (Posix) { static assert (absolutePath("some/file", "/foo/bar") == "/foo/bar/some/file"); } version (Windows) { static assert (absolutePath(`some\file`, `c:\foo\bar`) == `c:\foo\bar\some\file`); } import std.exception; assertThrown(absolutePath("bar", "foo")); } /** Tranforms $(D path) into an absolute _path. The following algorithm is used: $(OL $(LI If $(D path) is empty, return $(D null).) $(LI If $(D path) is already absolute, return it.) $(LI Otherwise, append $(D path) to the current working directory, which allocates memory.) ) Params: path = the relative path to transform Returns: the transformed path as a lazy range See_Also: $(LREF absolutePath) which returns an allocated string */ auto asAbsolutePath(R)(R path) if ((isRandomAccessRange!R && isSomeChar!(ElementType!R) || isNarrowString!R) && !isConvertibleToString!R) { import std.file : getcwd; string base = null; if (!path.empty && !isAbsolute(path)) base = getcwd(); return chainPath(base, path); } /// unittest { import std.array; assert(asAbsolutePath(cast(string)null).array == ""); version (Posix) { assert(asAbsolutePath("/foo").array == "/foo"); } version (Windows) { assert(asAbsolutePath("c:/foo").array == "c:/foo"); } asAbsolutePath("foo"); } auto asAbsolutePath(R)(auto ref R path) if (isConvertibleToString!R) { return asAbsolutePath!(StringTypeOf!R)(path); } unittest { assert(testAliasedString!asAbsolutePath(null)); } /** Translates $(D path) into a relative _path. The returned _path is relative to $(D base), which is by default taken to be the current working directory. If specified, $(D base) must be an absolute _path, and it is always assumed to refer to a directory. If $(D path) and $(D base) refer to the same directory, the function returns $(D `.`). The following algorithm is used: $(OL $(LI If $(D path) is a relative directory, return it unaltered.) $(LI Find a common root between $(D path) and $(D base). If there is no common root, return $(D path) unaltered.) $(LI Prepare a string with as many $(D `../`) or $(D `..\`) as necessary to reach the common root from base path.) $(LI Append the remaining segments of $(D path) to the string and return.) ) In the second step, path components are compared using $(D filenameCmp!cs), where $(D cs) is an optional template parameter determining whether the comparison is case sensitive or not. See the $(LREF filenameCmp) documentation for details. This function allocates memory. Params: cs = Whether matching path name components against the base path should be case-sensitive or not. path = A path name. base = The base path to construct the relative path from. Returns: The relative path. See_Also: $(LREF asRelativePath) which does not allocate memory Throws: $(D Exception) if the specified _base directory is not absolute. */ string relativePath(CaseSensitive cs = CaseSensitive.osDefault) (string path, lazy string base = getcwd()) { if (!isAbsolute(path)) return path; auto baseVar = base; if (!isAbsolute(baseVar)) throw new Exception("Base directory must be absolute"); import std.conv : to; return asRelativePath!cs(path, baseVar).to!string; } /// unittest { assert (relativePath("foo") == "foo"); version (Posix) { assert (relativePath("foo", "/bar") == "foo"); assert (relativePath("/foo/bar", "/foo/bar") == "."); assert (relativePath("/foo/bar", "/foo/baz") == "../bar"); assert (relativePath("/foo/bar/baz", "/foo/woo/wee") == "../../bar/baz"); assert (relativePath("/foo/bar/baz", "/foo/bar") == "baz"); } version (Windows) { assert (relativePath("foo", `c:\bar`) == "foo"); assert (relativePath(`c:\foo\bar`, `c:\foo\bar`) == "."); assert (relativePath(`c:\foo\bar`, `c:\foo\baz`) == `..\bar`); assert (relativePath(`c:\foo\bar\baz`, `c:\foo\woo\wee`) == `..\..\bar\baz`); assert (relativePath(`c:\foo\bar\baz`, `c:\foo\bar`) == "baz"); assert (relativePath(`c:\foo\bar`, `d:\foo`) == `c:\foo\bar`); } } unittest { import std.exception; assert (relativePath("foo") == "foo"); version (Posix) { relativePath("/foo"); assert (relativePath("/foo/bar", "/foo/baz") == "../bar"); assertThrown(relativePath("/foo", "bar")); } else version (Windows) { relativePath(`\foo`); assert (relativePath(`c:\foo\bar\baz`, `c:\foo\bar`) == "baz"); assertThrown(relativePath(`c:\foo`, "bar")); } else static assert (0); } /** Transforms `path` into a _path relative to `base`. The returned _path is relative to `base`, which is usually the current working directory. `base` must be an absolute _path, and it is always assumed to refer to a directory. If `path` and `base` refer to the same directory, the function returns `'.'`. The following algorithm is used: $(OL $(LI If `path` is a relative directory, return it unaltered.) $(LI Find a common root between `path` and `base`. If there is no common root, return `path` unaltered.) $(LI Prepare a string with as many `../` or `..\` as necessary to reach the common root from base path.) $(LI Append the remaining segments of `path` to the string and return.) ) In the second step, path components are compared using `filenameCmp!cs`, where `cs` is an optional template parameter determining whether the comparison is case sensitive or not. See the $(LREF filenameCmp) documentation for details. Params: path = _path to transform base = absolute path cs = whether filespec comparisons are sensitive or not; defaults to `CaseSensitive.osDefault` Returns: a random access range of the transformed _path See_Also: $(LREF relativePath) */ auto asRelativePath(CaseSensitive cs = CaseSensitive.osDefault, R1, R2) (R1 path, R2 base) if ((isNarrowString!R1 || (isRandomAccessRange!R1 && hasSlicing!R1 && isSomeChar!(ElementType!R1)) && !isConvertibleToString!R1) && (isNarrowString!R2 || (isRandomAccessRange!R2 && hasSlicing!R2 && isSomeChar!(ElementType!R2)) && !isConvertibleToString!R2)) { bool choosePath = !isAbsolute(path); // Find common root with current working directory auto basePS = pathSplitter(base); auto pathPS = pathSplitter(path); choosePath |= filenameCmp!cs(basePS.front, pathPS.front) != 0; basePS.popFront(); pathPS.popFront(); import std.range.primitives : walkLength; import std.range : repeat, chain, choose; import std.algorithm : mismatch, joiner; import std.array; import std.utf : byCodeUnit, byChar; // Remove matching prefix from basePS and pathPS auto tup = mismatch!((a, b) => filenameCmp!cs(a, b) == 0)(basePS, pathPS); basePS = tup[0]; pathPS = tup[1]; string sep; if (basePS.empty && pathPS.empty) sep = "."; // if base == path, this is the return else if (!basePS.empty && !pathPS.empty) sep = dirSeparator; // Append as many "../" as necessary to reach common base from path auto r1 = ".." .byChar .repeat(basePS.walkLength()) .joiner(dirSeparator.byChar); auto r2 = pathPS .joiner(dirSeparator.byChar) .byChar; // Return (r1 ~ sep ~ r2) return choose(choosePath, path.byCodeUnit, chain(r1, sep.byChar, r2)); } /// unittest { import std.array; version (Posix) { assert (asRelativePath("foo", "/bar").array == "foo"); assert (asRelativePath("/foo/bar", "/foo/bar").array == "."); assert (asRelativePath("/foo/bar", "/foo/baz").array == "../bar"); assert (asRelativePath("/foo/bar/baz", "/foo/woo/wee").array == "../../bar/baz"); assert (asRelativePath("/foo/bar/baz", "/foo/bar").array == "baz"); } else version (Windows) { assert (asRelativePath("foo", `c:\bar`).array == "foo"); assert (asRelativePath(`c:\foo\bar`, `c:\foo\bar`).array == "."); assert (asRelativePath(`c:\foo\bar`, `c:\foo\baz`).array == `..\bar`); assert (asRelativePath(`c:\foo\bar\baz`, `c:\foo\woo\wee`).array == `..\..\bar\baz`); assert (asRelativePath(`c:/foo/bar/baz`, `c:\foo\woo\wee`).array == `..\..\bar\baz`); assert (asRelativePath(`c:\foo\bar\baz`, `c:\foo\bar`).array == "baz"); assert (asRelativePath(`c:\foo\bar`, `d:\foo`).array == `c:\foo\bar`); assert (asRelativePath(`\\foo\bar`, `c:\foo`).array == `\\foo\bar`); } else static assert(0); } auto asRelativePath(CaseSensitive cs = CaseSensitive.osDefault, R1, R2) (auto ref R1 path, auto ref R2 base) if (isConvertibleToString!R1 || isConvertibleToString!R2) { import std.meta : staticMap; alias Types = staticMap!(convertToString, R1, R2); return asRelativePath!(cs, Types)(path, base); } unittest { import std.array; version (Posix) assert (asRelativePath(TestAliasedString("foo"), TestAliasedString("/bar")).array == "foo"); else version (Windows) assert (asRelativePath(TestAliasedString("foo"), TestAliasedString(`c:\bar`)).array == "foo"); assert(asRelativePath(TestAliasedString("foo"), "bar").array == "foo"); assert(asRelativePath("foo", TestAliasedString("bar")).array == "foo"); assert(asRelativePath(TestAliasedString("foo"), TestAliasedString("bar")).array == "foo"); import std.utf : byDchar; assert(asRelativePath("foo"d.byDchar, TestAliasedString("bar")).array == "foo"); } unittest { import std.array, std.utf : bCU=byCodeUnit; version (Posix) { assert (asRelativePath("/foo/bar/baz".bCU, "/foo/bar".bCU).array == "baz"); assert (asRelativePath("/foo/bar/baz"w.bCU, "/foo/bar"w.bCU).array == "baz"w); assert (asRelativePath("/foo/bar/baz"d.bCU, "/foo/bar"d.bCU).array == "baz"d); } else version (Windows) { assert (asRelativePath(`\\foo\bar`.bCU, `c:\foo`.bCU).array == `\\foo\bar`); assert (asRelativePath(`\\foo\bar`w.bCU, `c:\foo`w.bCU).array == `\\foo\bar`w); assert (asRelativePath(`\\foo\bar`d.bCU, `c:\foo`d.bCU).array == `\\foo\bar`d); } } /** Compares filename characters. This function can perform a case-sensitive or a case-insensitive comparison. This is controlled through the $(D cs) template parameter which, if not specified, is given by $(LREF CaseSensitive)$(D .osDefault). On Windows, the backslash and slash characters ($(D `\`) and $(D `/`)) are considered equal. Params: cs = Case-sensitivity of the comparison. a = A filename character. b = A filename character. Returns: $(D < 0) if $(D a < b), $(D 0) if $(D a == b), and $(D > 0) if $(D a > b). */ int filenameCharCmp(CaseSensitive cs = CaseSensitive.osDefault)(dchar a, dchar b) @safe pure nothrow { if (isDirSeparator(a) && isDirSeparator(b)) return 0; static if (!cs) { import std.uni; a = toLower(a); b = toLower(b); } return cast(int)(a - b); } /// unittest { assert (filenameCharCmp('a', 'a') == 0); assert (filenameCharCmp('a', 'b') < 0); assert (filenameCharCmp('b', 'a') > 0); version (linux) { // Same as calling filenameCharCmp!(CaseSensitive.yes)(a, b) assert (filenameCharCmp('A', 'a') < 0); assert (filenameCharCmp('a', 'A') > 0); } version (Windows) { // Same as calling filenameCharCmp!(CaseSensitive.no)(a, b) assert (filenameCharCmp('a', 'A') == 0); assert (filenameCharCmp('a', 'B') < 0); assert (filenameCharCmp('A', 'b') < 0); } } unittest { assert (filenameCharCmp!(CaseSensitive.yes)('A', 'a') < 0); assert (filenameCharCmp!(CaseSensitive.yes)('a', 'A') > 0); assert (filenameCharCmp!(CaseSensitive.no)('a', 'a') == 0); assert (filenameCharCmp!(CaseSensitive.no)('a', 'b') < 0); assert (filenameCharCmp!(CaseSensitive.no)('b', 'a') > 0); assert (filenameCharCmp!(CaseSensitive.no)('A', 'a') == 0); assert (filenameCharCmp!(CaseSensitive.no)('a', 'A') == 0); assert (filenameCharCmp!(CaseSensitive.no)('a', 'B') < 0); assert (filenameCharCmp!(CaseSensitive.no)('B', 'a') > 0); assert (filenameCharCmp!(CaseSensitive.no)('A', 'b') < 0); assert (filenameCharCmp!(CaseSensitive.no)('b', 'A') > 0); version (Posix) assert (filenameCharCmp('\\', '/') != 0); version (Windows) assert (filenameCharCmp('\\', '/') == 0); } /** Compares file names and returns Individual characters are compared using $(D filenameCharCmp!cs), where $(D cs) is an optional template parameter determining whether the comparison is case sensitive or not. Treatment of invalid UTF encodings is implementation defined. Params: cs = case sensitivity filename1 = range for first file name filename2 = range for second file name Returns: $(D < 0) if $(D filename1 < filename2), $(D 0) if $(D filename1 == filename2) and $(D > 0) if $(D filename1 > filename2). See_Also: $(LREF filenameCharCmp) */ int filenameCmp(CaseSensitive cs = CaseSensitive.osDefault, Range1, Range2) (Range1 filename1, Range2 filename2) if (isInputRange!Range1 && isSomeChar!(ElementEncodingType!Range1) && !isConvertibleToString!Range1 && isInputRange!Range2 && isSomeChar!(ElementEncodingType!Range2) && !isConvertibleToString!Range2) { alias C1 = Unqual!(ElementEncodingType!Range1); alias C2 = Unqual!(ElementEncodingType!Range2); static if (!cs && (C1.sizeof < 4 || C2.sizeof < 4) || C1.sizeof != C2.sizeof) { // Case insensitive - decode so case is checkable // Different char sizes - decode to bring to common type import std.utf : byDchar; return filenameCmp!cs(filename1.byDchar, filename2.byDchar); } else static if (isSomeString!Range1 && C1.sizeof < 4 || isSomeString!Range2 && C2.sizeof < 4) { // Avoid autodecoding import std.utf : byCodeUnit; return filenameCmp!cs(filename1.byCodeUnit, filename2.byCodeUnit); } else { for (;;) { if (filename1.empty) return -(cast(int) !filename2.empty); if (filename2.empty) return 1; const c = filenameCharCmp!cs(filename1.front, filename2.front); if (c != 0) return c; filename1.popFront(); filename2.popFront(); } } } /// unittest { assert (filenameCmp("abc", "abc") == 0); assert (filenameCmp("abc", "abd") < 0); assert (filenameCmp("abc", "abb") > 0); assert (filenameCmp("abc", "abcd") < 0); assert (filenameCmp("abcd", "abc") > 0); version (linux) { // Same as calling filenameCmp!(CaseSensitive.yes)(filename1, filename2) assert (filenameCmp("Abc", "abc") < 0); assert (filenameCmp("abc", "Abc") > 0); } version (Windows) { // Same as calling filenameCmp!(CaseSensitive.no)(filename1, filename2) assert (filenameCmp("Abc", "abc") == 0); assert (filenameCmp("abc", "Abc") == 0); assert (filenameCmp("Abc", "abD") < 0); assert (filenameCmp("abc", "AbB") > 0); } } int filenameCmp(CaseSensitive cs = CaseSensitive.osDefault, Range1, Range2) (auto ref Range1 filename1, auto ref Range2 filename2) if (isConvertibleToString!Range1 || isConvertibleToString!Range2) { import std.meta : staticMap; alias Types = staticMap!(convertToString, Range1, Range2); return filenameCmp!(cs, Types)(filename1, filename2); } unittest { assert (filenameCmp!(CaseSensitive.yes)(TestAliasedString("Abc"), "abc") < 0); assert (filenameCmp!(CaseSensitive.yes)("Abc", TestAliasedString("abc")) < 0); assert (filenameCmp!(CaseSensitive.yes)(TestAliasedString("Abc"), TestAliasedString("abc")) < 0); } unittest { assert (filenameCmp!(CaseSensitive.yes)("Abc", "abc") < 0); assert (filenameCmp!(CaseSensitive.yes)("abc", "Abc") > 0); assert (filenameCmp!(CaseSensitive.no)("abc", "abc") == 0); assert (filenameCmp!(CaseSensitive.no)("abc", "abd") < 0); assert (filenameCmp!(CaseSensitive.no)("abc", "abb") > 0); assert (filenameCmp!(CaseSensitive.no)("abc", "abcd") < 0); assert (filenameCmp!(CaseSensitive.no)("abcd", "abc") > 0); assert (filenameCmp!(CaseSensitive.no)("Abc", "abc") == 0); assert (filenameCmp!(CaseSensitive.no)("abc", "Abc") == 0); assert (filenameCmp!(CaseSensitive.no)("Abc", "abD") < 0); assert (filenameCmp!(CaseSensitive.no)("abc", "AbB") > 0); version (Posix) assert (filenameCmp(`abc\def`, `abc/def`) != 0); version (Windows) assert (filenameCmp(`abc\def`, `abc/def`) == 0); } /** Matches a pattern against a path. Some characters of pattern have a special meaning (they are $(I meta-characters)) and can't be escaped. These are: $(BOOKTABLE, $(TR $(TD $(D *)) $(TD Matches 0 or more instances of any character.)) $(TR $(TD $(D ?)) $(TD Matches exactly one instance of any character.)) $(TR $(TD $(D [)$(I chars)$(D ])) $(TD Matches one instance of any character that appears between the brackets.)) $(TR $(TD $(D [!)$(I chars)$(D ])) $(TD Matches one instance of any character that does not appear between the brackets after the exclamation mark.)) $(TR $(TD $(D {)$(I string1)$(D ,)$(I string2)$(D ,)…$(D })) $(TD Matches either of the specified strings.)) ) Individual characters are compared using $(D filenameCharCmp!cs), where $(D cs) is an optional template parameter determining whether the comparison is case sensitive or not. See the $(LREF filenameCharCmp) documentation for details. Note that directory separators and dots don't stop a meta-character from matching further portions of the path. Params: cs = Whether the matching should be case-sensitive path = The path to be matched against pattern = The glob pattern Returns: $(D true) if pattern matches path, $(D false) otherwise. See_also: $(LINK2 http://en.wikipedia.org/wiki/Glob_%28programming%29,Wikipedia: _glob (programming)) */ bool globMatch(CaseSensitive cs = CaseSensitive.osDefault, C, Range) (Range path, const(C)[] pattern) @safe pure nothrow if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range && isSomeChar!C && is(Unqual!C == Unqual!(ElementEncodingType!Range))) in { // Verify that pattern[] is valid import std.algorithm : balancedParens; assert(balancedParens(pattern, '[', ']', 0)); assert(balancedParens(pattern, '{', '}', 0)); } body { alias RC = Unqual!(ElementEncodingType!Range); static if (RC.sizeof == 1 && isSomeString!Range) { import std.utf : byChar; return globMatch!cs(path.byChar, pattern); } else static if (RC.sizeof == 2 && isSomeString!Range) { import std.utf : byWchar; return globMatch!cs(path.byWchar, pattern); } else { C[] pattmp; foreach (ref pi; 0 .. pattern.length) { const pc = pattern[pi]; switch (pc) { case '*': if (pi + 1 == pattern.length) return true; for (; !path.empty; path.popFront()) { auto p = path.save; if (globMatch!(cs, C)(p, pattern[pi + 1 .. pattern.length])) return true; } return false; case '?': if (path.empty) return false; path.popFront(); break; case '[': if (path.empty) return false; auto nc = path.front; path.popFront(); auto not = false; ++pi; if (pattern[pi] == '!') { not = true; ++pi; } auto anymatch = false; while (1) { const pc2 = pattern[pi]; if (pc2 == ']') break; if (!anymatch && (filenameCharCmp!cs(nc, pc2) == 0)) anymatch = true; ++pi; } if (anymatch == not) return false; break; case '{': // find end of {} section auto piRemain = pi; for (; piRemain < pattern.length && pattern[piRemain] != '}'; ++piRemain) { } if (piRemain < pattern.length) ++piRemain; ++pi; while (pi < pattern.length) { const pi0 = pi; C pc3 = pattern[pi]; // find end of current alternative for (; pi < pattern.length && pc3 != '}' && pc3 != ','; ++pi) { pc3 = pattern[pi]; } auto p = path.save; if (pi0 == pi) { if (globMatch!(cs, C)(p, pattern[piRemain..$])) { return true; } ++pi; } else { /* Match for: * pattern[pi0..pi-1] ~ pattern[piRemain..$] */ if (pattmp.ptr == null) // Allocate this only once per function invocation. // Should do it with malloc/free, but that would make it impure. pattmp = new C[pattern.length]; const len1 = pi - 1 - pi0; pattmp[0 .. len1] = pattern[pi0 .. pi - 1]; const len2 = pattern.length - piRemain; pattmp[len1 .. len1 + len2] = pattern[piRemain .. $]; if (globMatch!(cs, C)(p, pattmp[0 .. len1 + len2])) { return true; } } if (pc3 == '}') { break; } } return false; default: if (path.empty) return false; if (filenameCharCmp!cs(pc, path.front) != 0) return false; path.popFront(); break; } } return path.empty; } } /// unittest { assert (globMatch("foo.bar", "*")); assert (globMatch("foo.bar", "*.*")); assert (globMatch(`foo/foo\bar`, "f*b*r")); assert (globMatch("foo.bar", "f???bar")); assert (globMatch("foo.bar", "[fg]???bar")); assert (globMatch("foo.bar", "[!gh]*bar")); assert (globMatch("bar.fooz", "bar.{foo,bif}z")); assert (globMatch("bar.bifz", "bar.{foo,bif}z")); version (Windows) { // Same as calling globMatch!(CaseSensitive.no)(path, pattern) assert (globMatch("foo", "Foo")); assert (globMatch("Goo.bar", "[fg]???bar")); } version (linux) { // Same as calling globMatch!(CaseSensitive.yes)(path, pattern) assert (!globMatch("foo", "Foo")); assert (!globMatch("Goo.bar", "[fg]???bar")); } } bool globMatch(CaseSensitive cs = CaseSensitive.osDefault, C, Range) (auto ref Range path, const(C)[] pattern) @safe pure nothrow if (isConvertibleToString!Range) { return globMatch!(cs, C, StringTypeOf!Range)(path, pattern); } unittest { assert (testAliasedString!globMatch("foo.bar", "*")); } unittest { assert (globMatch!(CaseSensitive.no)("foo", "Foo")); assert (!globMatch!(CaseSensitive.yes)("foo", "Foo")); assert(globMatch("foo", "*")); assert(globMatch("foo.bar"w, "*"w)); assert(globMatch("foo.bar"d, "*.*"d)); assert(globMatch("foo.bar", "foo*")); assert(globMatch("foo.bar"w, "f*bar"w)); assert(globMatch("foo.bar"d, "f*b*r"d)); assert(globMatch("foo.bar", "f???bar")); assert(globMatch("foo.bar"w, "[fg]???bar"w)); assert(globMatch("foo.bar"d, "[!gh]*bar"d)); assert(!globMatch("foo", "bar")); assert(!globMatch("foo"w, "*.*"w)); assert(!globMatch("foo.bar"d, "f*baz"d)); assert(!globMatch("foo.bar", "f*b*x")); assert(!globMatch("foo.bar", "[gh]???bar")); assert(!globMatch("foo.bar"w, "[!fg]*bar"w)); assert(!globMatch("foo.bar"d, "[fg]???baz"d)); assert(!globMatch("foo.di", "*.d")); // test issue 6634: triggered bad assertion assert(globMatch("foo.bar", "{foo,bif}.bar")); assert(globMatch("bif.bar"w, "{foo,bif}.bar"w)); assert(globMatch("bar.foo"d, "bar.{foo,bif}"d)); assert(globMatch("bar.bif", "bar.{foo,bif}")); assert(globMatch("bar.fooz"w, "bar.{foo,bif}z"w)); assert(globMatch("bar.bifz"d, "bar.{foo,bif}z"d)); assert(globMatch("bar.foo", "bar.{biz,,baz}foo")); assert(globMatch("bar.foo"w, "bar.{biz,}foo"w)); assert(globMatch("bar.foo"d, "bar.{,biz}foo"d)); assert(globMatch("bar.foo", "bar.{}foo")); assert(globMatch("bar.foo"w, "bar.{ar,,fo}o"w)); assert(globMatch("bar.foo"d, "bar.{,ar,fo}o"d)); assert(globMatch("bar.o", "bar.{,ar,fo}o")); assert(!globMatch("foo", "foo?")); assert(!globMatch("foo", "foo[]")); assert(!globMatch("foo", "foob")); assert(!globMatch("foo", "foo{b}")); static assert(globMatch("foo.bar", "[!gh]*bar")); } /** Checks that the given file or directory name is valid. The maximum length of $(D filename) is given by the constant $(D core.stdc.stdio.FILENAME_MAX). (On Windows, this number is defined as the maximum number of UTF-16 code points, and the test will therefore only yield strictly correct results when $(D filename) is a string of $(D wchar)s.) On Windows, the following criteria must be satisfied ($(LINK2 http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx,source)): $(UL $(LI $(D filename) must not contain any characters whose integer representation is in the range 0-31.) $(LI $(D filename) must not contain any of the following $(I reserved characters): <>:"/\|?*) $(LI $(D filename) may not end with a space ($(D ' ')) or a period ($(D '.')).) ) On POSIX, $(D filename) may not contain a forward slash ($(D '/')) or the null character ($(D '\0')). Params: filename = string to check Returns: $(D true) if and only if $(D filename) is not empty, not too long, and does not contain invalid characters. */ bool isValidFilename(Range)(Range filename) if ((isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && isSomeChar!(ElementEncodingType!Range) || isNarrowString!Range) && !isConvertibleToString!Range) { import core.stdc.stdio : FILENAME_MAX; if (filename.length == 0 || filename.length >= FILENAME_MAX) return false; foreach (c; filename) { version (Windows) { switch (c) { case 0: .. case 31: case '<': case '>': case ':': case '"': case '/': case '\\': case '|': case '?': case '*': return false; default: break; } } else version (Posix) { if (c == 0 || c == '/') return false; } else static assert (0); } version (Windows) { auto last = filename[filename.length - 1]; if (last == '.' || last == ' ') return false; } // All criteria passed return true; } /// @safe pure @nogc nothrow unittest { import std.utf : byCodeUnit; assert(isValidFilename("hello.exe".byCodeUnit)); } bool isValidFilename(Range)(auto ref Range filename) if (isConvertibleToString!Range) { return isValidFilename!(StringTypeOf!Range)(filename); } unittest { assert(testAliasedString!isValidFilename("hello.exe")); } @safe pure unittest { import std.conv; auto valid = ["foo"]; auto invalid = ["", "foo\0bar", "foo/bar"]; auto pfdep = [`foo\bar`, "*.txt"]; version (Windows) invalid ~= pfdep; else version (Posix) valid ~= pfdep; else static assert (0); import std.meta : AliasSeq; foreach (T; AliasSeq!(char[], const(char)[], string, wchar[], const(wchar)[], wstring, dchar[], const(dchar)[], dstring)) { foreach (fn; valid) assert (isValidFilename(to!T(fn))); foreach (fn; invalid) assert (!isValidFilename(to!T(fn))); } { auto r = MockRange!(immutable(char))(`dir/file.d`); assert(!isValidFilename(r)); } static struct DirEntry { string s; alias s this; } assert(isValidFilename(DirEntry("file.ext"))); version (Windows) { immutable string cases = "<>:\"/\\|?*"; foreach (i; 0 .. 31 + cases.length) { char[3] buf; buf[0] = 'a'; buf[1] = i <= 31 ? cast(char)i : cases[i - 32]; buf[2] = 'b'; assert(!isValidFilename(buf[])); } } } /** Checks whether $(D path) is a valid _path. Generally, this function checks that $(D path) is not empty, and that each component of the path either satisfies $(LREF isValidFilename) or is equal to $(D ".") or $(D ".."). It does $(I not) check whether the _path points to an existing file or directory; use $(XREF file,exists) for this purpose. On Windows, some special rules apply: $(UL $(LI If the second character of $(D path) is a colon ($(D ':')), the first character is interpreted as a drive letter, and must be in the range A-Z (case insensitive).) $(LI If $(D path) is on the form $(D `\\$(I server)\$(I share)\...`) (UNC path), $(LREF isValidFilename) is applied to $(I server) and $(I share) as well.) $(LI If $(D path) starts with $(D `\\?\`) (long UNC path), the only requirement for the rest of the string is that it does not contain the null character.) $(LI If $(D path) starts with $(D `\\.\`) (Win32 device namespace) this function returns $(D false); such paths are beyond the scope of this module.) ) Params: path = string or Range of characters to check Returns: true if $(D path) is a valid _path. */ bool isValidPath(Range)(Range path) if ((isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && isSomeChar!(ElementEncodingType!Range) || isNarrowString!Range) && !isConvertibleToString!Range) { alias C = Unqual!(ElementEncodingType!Range); if (path.empty) return false; // Check whether component is "." or "..", or whether it satisfies // isValidFilename. bool isValidComponent(Range component) { assert (component.length > 0); if (component[0] == '.') { if (component.length == 1) return true; else if (component.length == 2 && component[1] == '.') return true; } return isValidFilename(component); } if (path.length == 1) return isDirSeparator(path[0]) || isValidComponent(path); Range remainder; version (Windows) { if (isDirSeparator(path[0]) && isDirSeparator(path[1])) { // Some kind of UNC path if (path.length < 5) { // All valid UNC paths must have at least 5 characters return false; } else if (path[2] == '?') { // Long UNC path if (!isDirSeparator(path[3])) return false; foreach (c; path[4 .. $]) { if (c == '\0') return false; } return true; } else if (path[2] == '.') { // Win32 device namespace not supported return false; } else { // Normal UNC path, i.e. \\server\share\... size_t i = 2; while (i < path.length && !isDirSeparator(path[i])) ++i; if (i == path.length || !isValidFilename(path[2 .. i])) return false; ++i; // Skip a single dir separator size_t j = i; while (j < path.length && !isDirSeparator(path[j])) ++j; if (!isValidFilename(path[i .. j])) return false; remainder = path[j .. $]; } } else if (isDriveSeparator(path[1])) { import std.ascii; if (!isAlpha(path[0])) return false; remainder = path[2 .. $]; } else { remainder = path; } } else version (Posix) { remainder = path; } else static assert (0); remainder = ltrimDirSeparators(remainder); // Check that each component satisfies isValidComponent. while (!remainder.empty) { size_t i = 0; while (i < remainder.length && !isDirSeparator(remainder[i])) ++i; assert (i > 0); if (!isValidComponent(remainder[0 .. i])) return false; remainder = ltrimDirSeparators(remainder[i .. $]); } // All criteria passed return true; } /// @safe pure @nogc nothrow unittest { assert (isValidPath("/foo/bar")); assert (!isValidPath("/foo\0/bar")); assert (isValidPath("/")); assert (isValidPath("a")); version (Windows) { assert (isValidPath(`c:\`)); assert (isValidPath(`c:\foo`)); assert (isValidPath(`c:\foo\.\bar\\\..\`)); assert (!isValidPath(`!:\foo`)); assert (!isValidPath(`c::\foo`)); assert (!isValidPath(`c:\foo?`)); assert (!isValidPath(`c:\foo.`)); assert (isValidPath(`\\server\share`)); assert (isValidPath(`\\server\share\foo`)); assert (isValidPath(`\\server\share\\foo`)); assert (!isValidPath(`\\\server\share\foo`)); assert (!isValidPath(`\\server\\share\foo`)); assert (!isValidPath(`\\ser*er\share\foo`)); assert (!isValidPath(`\\server\sha?e\foo`)); assert (!isValidPath(`\\server\share\|oo`)); assert (isValidPath(`\\?\<>:"?*|/\..\.`)); assert (!isValidPath("\\\\?\\foo\0bar")); assert (!isValidPath(`\\.\PhysicalDisk1`)); assert (!isValidPath(`\\`)); } import std.utf : byCodeUnit; assert (isValidPath("/foo/bar".byCodeUnit)); } bool isValidPath(Range)(auto ref Range path) if (isConvertibleToString!Range) { return isValidPath!(StringTypeOf!Range)(path); } unittest { assert(testAliasedString!isValidPath("/foo/bar")); } /** Performs tilde expansion in paths on POSIX systems. On Windows, this function does nothing. There are two ways of using tilde expansion in a path. One involves using the tilde alone or followed by a path separator. In this case, the tilde will be expanded with the value of the environment variable $(D HOME). The second way is putting a username after the tilde (i.e. $(D ~john/Mail)). Here, the username will be searched for in the user database (i.e. $(D /etc/passwd) on Unix systems) and will expand to whatever path is stored there. The username is considered the string after the tilde ending at the first instance of a path separator. Note that using the $(D ~user) syntax may give different values from just $(D ~) if the environment variable doesn't match the value stored in the user database. When the environment variable version is used, the path won't be modified if the environment variable doesn't exist or it is empty. When the database version is used, the path won't be modified if the user doesn't exist in the database or there is not enough memory to perform the query. This function performs several memory allocations. Params: inputPath = The path name to expand. Returns: $(D inputPath) with the tilde expanded, or just $(D inputPath) if it could not be expanded. For Windows, $(D expandTilde) merely returns its argument $(D inputPath). Example: ----- void processFile(string path) { // Allow calling this function with paths such as ~/foo auto fullPath = expandTilde(path); ... } ----- */ string expandTilde(string inputPath) nothrow { version(Posix) { import core.stdc.stdlib : malloc, free, realloc; import core.exception : onOutOfMemoryError; import core.stdc.errno : errno, ERANGE; /* Joins a path from a C string to the remainder of path. The last path separator from c_path is discarded. The result is joined to path[char_pos .. length] if char_pos is smaller than length, otherwise path is not appended to c_path. */ static string combineCPathWithDPath(char* c_path, string path, size_t char_pos) nothrow { import core.stdc.string : strlen; assert(c_path != null); assert(path.length > 0); assert(char_pos >= 0); // Search end of C string size_t end = strlen(c_path); // Remove trailing path separator, if any if (end && isDirSeparator(c_path[end - 1])) end--; // (this is the only GC allocation done in expandTilde()) string cp; if (char_pos < path.length) // Append something from path cp = cast(string)(c_path[0 .. end] ~ path[char_pos .. $]); else // Create our own copy, as lifetime of c_path is undocumented cp = c_path[0 .. end].idup; return cp; } // Replaces the tilde from path with the environment variable HOME. static string expandFromEnvironment(string path) nothrow { import core.stdc.stdlib : getenv; assert(path.length >= 1); assert(path[0] == '~'); // Get HOME and use that to replace the tilde. auto home = getenv("HOME"); if (home == null) return path; return combineCPathWithDPath(home, path, 1); } // Replaces the tilde from path with the path from the user database. static string expandFromDatabase(string path) nothrow { // bionic doesn't really support this, as getpwnam_r // isn't provided and getpwnam is basically just a stub version(CRuntime_Bionic) { return path; } else { import core.sys.posix.pwd : passwd, getpwnam_r; import std.string : indexOf; assert(path.length > 2 || (path.length == 2 && !isDirSeparator(path[1]))); assert(path[0] == '~'); // Extract username, searching for path separator. auto last_char = indexOf(path, dirSeparator[0]); size_t username_len = (last_char == -1) ? path.length : last_char; char* username = cast(char*)malloc(username_len * char.sizeof); if (!username) onOutOfMemoryError(); scope(exit) free(username); if (last_char == -1) { username[0 .. username_len - 1] = path[1 .. $]; last_char = path.length + 1; } else { username[0 .. username_len - 1] = path[1 .. last_char]; } username[username_len - 1] = 0; assert(last_char > 1); // Reserve C memory for the getpwnam_r() function. int extra_memory_size = 5 * 1024; char* extra_memory; scope(exit) free(extra_memory); passwd result; while (1) { extra_memory = cast(char*)realloc(extra_memory, extra_memory_size * char.sizeof); if (extra_memory == null) onOutOfMemoryError(); // Obtain info from database. passwd *verify; errno = 0; if (getpwnam_r(username, &result, extra_memory, extra_memory_size, &verify) == 0) { // Succeeded if verify points at result if (verify == &result) // username is found path = combineCPathWithDPath(result.pw_dir, path, last_char); break; } if (errno != ERANGE) onOutOfMemoryError(); // extra_memory isn't large enough extra_memory_size *= 2; } return path; } } // Return early if there is no tilde in path. if (inputPath.length < 1 || inputPath[0] != '~') return inputPath; if (inputPath.length == 1 || isDirSeparator(inputPath[1])) return expandFromEnvironment(inputPath); else return expandFromDatabase(inputPath); } else version(Windows) { // Put here real windows implementation. return inputPath; } else { static assert(0); // Guard. Implement on other platforms. } } version(unittest) import std.process: environment; unittest { version (Posix) { // Retrieve the current home variable. auto oldHome = environment.get("HOME"); // Testing when there is no environment variable. environment.remove("HOME"); assert(expandTilde("~/") == "~/"); assert(expandTilde("~") == "~"); // Testing when an environment variable is set. environment["HOME"] = "dmd/test"; assert(expandTilde("~/") == "dmd/test/"); assert(expandTilde("~") == "dmd/test"); // The same, but with a variable ending in a slash. environment["HOME"] = "dmd/test/"; assert(expandTilde("~/") == "dmd/test/"); assert(expandTilde("~") == "dmd/test"); // Recover original HOME variable before continuing. if (oldHome !is null) environment["HOME"] = oldHome; else environment.remove("HOME"); // Test user expansion for root, no /root on Android version (OSX) { assert(expandTilde("~root") == "/var/root", expandTilde("~root")); assert(expandTilde("~root/") == "/var/root/", expandTilde("~root/")); } else version (Android) { } else { assert(expandTilde("~root") == "/root", expandTilde("~root")); assert(expandTilde("~root/") == "/root/", expandTilde("~root/")); } assert(expandTilde("~Idontexist/hey") == "~Idontexist/hey"); } } version (unittest) { /* Define a mock RandomAccessRange to use for unittesting. */ struct MockRange(C) { this(C[] array) { this.array = array; } const { @property size_t length() { return array.length; } @property bool empty() { return array.length == 0; } @property C front() { return array[0]; } @property C back() { return array[$ - 1]; } @property size_t opDollar() { return length; } C opIndex(size_t i) { return array[i]; } } void popFront() { array = array[1 .. $]; } void popBack() { array = array[0 .. $-1]; } MockRange!C opSlice( size_t lwr, size_t upr) const { return MockRange!C(array[lwr .. upr]); } @property MockRange save() { return this; } private: C[] array; } static assert( isRandomAccessRange!(MockRange!(const(char))) ); } version (unittest) { /* Define a mock BidirectionalRange to use for unittesting. */ struct MockBiRange(C) { this(const(C)[] array) { this.array = array; } const { @property bool empty() { return array.length == 0; } @property C front() { return array[0]; } @property C back() { return array[$ - 1]; } @property size_t opDollar() { return array.length; } } void popFront() { array = array[1 .. $]; } void popBack() { array = array[0 .. $-1]; } @property MockBiRange save() { return this; } private: const(C)[] array; } static assert( isBidirectionalRange!(MockBiRange!(const(char))) ); } private template BaseOf(R) { static if (isRandomAccessRange!R && isSomeChar!(ElementType!R)) alias BaseOf = R; else alias BaseOf = StringTypeOf!R; } ldc-1.1.0-beta3-src/runtime/phobos/std/utf.d0000664000175000017500000032574112776215007016665 0ustar kaikai// Written in the D programming language. /++ Encode and decode UTF-8, UTF-16 and UTF-32 strings. UTF character support is restricted to $(D '\u0000' <= character <= '\U0010FFFF'). See_Also: $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)
$(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)
$(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335) Macros: WIKI = Phobos/StdUtf Copyright: Copyright Digital Mars 2000 - 2012. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB digitalmars.com, Walter Bright) and Jonathan M Davis Source: $(PHOBOSSRC std/_utf.d) +/ module std.utf; import std.meta; // AliasSeq import std.range.primitives; import std.traits; // isSomeChar, isSomeString import std.typecons; // Flag import std.exception; // basicExceptionCtors //debug=utf; // uncomment to turn on debugging printf's debug (utf) import core.stdc.stdio : printf; /++ Exception thrown on errors in std.utf functions. +/ class UTFException : Exception { import core.internal.string; uint[4] sequence; size_t len; @safe pure nothrow @nogc UTFException setSequence(uint[] data...) { assert(data.length <= 4); len = data.length < 4 ? data.length : 4; sequence[0 .. len] = data[0 .. len]; return this; } // FIXME: Use std.exception.basicExceptionCtors here once bug #11500 is fixed this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @nogc @safe pure nothrow { super(msg, file, line, next); } this(string msg, size_t index, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @safe pure nothrow { UnsignedStringBuf buf = void; msg ~= " (at index " ~ unsignedToTempString(index, buf, 10) ~ ")"; super(msg, file, line, next); } override string toString() { if (len == 0) return super.toString(); string result = "Invalid UTF sequence:"; foreach (i; sequence[0 .. len]) { UnsignedStringBuf buf = void; result ~= ' '; auto h = unsignedToTempString(i, buf, 16); if (h.length == 1) result ~= '0'; result ~= h; result ~= 'x'; } if (super.msg.length > 0) { result ~= " - "; result ~= super.msg; } return result; } } /* Provide array of invalidly encoded UTF strings. Useful for testing. Params: Char = char, wchar, or dchar Returns: an array of invalidly encoded UTF strings */ package auto invalidUTFstrings(Char)() @safe pure @nogc nothrow if (isSomeChar!Char) { static if (is(Char == char)) { enum x = 0xDC00; // invalid surrogate value enum y = 0x110000; // out of range static immutable string[8] result = [ "\x80", // not a start byte "\xC0", // truncated "\xC0\xC0", // invalid continuation "\xF0\x82\x82\xAC", // overlong [ 0xE0 | (x >> 12), 0x80 | ((x >> 6) & 0x3F), 0x80 | (x & 0x3F) ], [ cast(char)(0xF0 | (y >> 18)), cast(char)(0x80 | ((y >> 12) & 0x3F)), cast(char)(0x80 | ((y >> 6) & 0x3F)), cast(char)(0x80 | (y & 0x3F)) ], [ cast(char)(0xF8 | 3), // 5 byte encoding cast(char)(0x80 | 3), cast(char)(0x80 | 3), cast(char)(0x80 | 3), cast(char)(0x80 | 3), ], [ cast(char)(0xFC | 3), // 6 byte encoding cast(char)(0x80 | 3), cast(char)(0x80 | 3), cast(char)(0x80 | 3), cast(char)(0x80 | 3), cast(char)(0x80 | 3), ], ]; return result[]; } else static if (is(Char == wchar)) { static immutable wstring[5] result = [ [ cast(wchar)0xDC00, ], [ cast(wchar)0xDFFF, ], [ cast(wchar)0xDBFF, cast(wchar)0xDBFF, ], [ cast(wchar)0xDBFF, cast(wchar)0xE000, ], [ cast(wchar)0xD800, ], ]; return result[]; } else static if (is(Char == dchar)) { static immutable dstring[3] result = [ [ cast(dchar)0x110000 ], [ cast(dchar)0x00D800 ], [ cast(dchar)0x00DFFF ], ]; return result; } else static assert(0); } /++ Check whether the given Unicode code point is valid. Params: c = code point to check Returns: $(D true) iff $(D c) is a valid Unicode code point Note: $(D '\uFFFE') and $(D '\uFFFF') are considered valid by $(D isValidDchar), as they are permitted for internal use by an application, but they are not allowed for interchange by the Unicode standard. +/ bool isValidDchar(dchar c) pure nothrow @safe @nogc { /* Note: FFFE and FFFF are specifically permitted by the * Unicode standard for application internal use, but are not * allowed for interchange. * (thanks to Arcane Jill) */ return c < 0xD800 || (c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/); } pure nothrow @safe @nogc unittest { import std.exception; debug(utf) printf("utf.isValidDchar.unittest\n"); assertCTFEable!( { assert( isValidDchar(cast(dchar)'a') == true); assert( isValidDchar(cast(dchar)0x1FFFFF) == false); assert(!isValidDchar(cast(dchar)0x00D800)); assert(!isValidDchar(cast(dchar)0x00DBFF)); assert(!isValidDchar(cast(dchar)0x00DC00)); assert(!isValidDchar(cast(dchar)0x00DFFF)); assert( isValidDchar(cast(dchar)0x00FFFE)); assert( isValidDchar(cast(dchar)0x00FFFF)); assert( isValidDchar(cast(dchar)0x01FFFF)); assert( isValidDchar(cast(dchar)0x10FFFF)); assert(!isValidDchar(cast(dchar)0x110000)); }); } /++ Calculate the length of the UTF sequence starting at $(D index) in $(D str). Params: str = input range of UTF code units. Must be random access if $(D index) is passed index = starting index of UTF sequence (default: $(D 0)) Returns: The number of code units in the UTF sequence. For UTF-8, this is a value between 1 and 4 (as per $(WEB tools.ietf.org/html/rfc3629#section-3, RFC 3629$(COMMA) section 3)). For UTF-16, it is either 1 or 2. For UTF-32, it is always 1. Throws: May throw a $(D UTFException) if $(D str[index]) is not the start of a valid UTF sequence. Note: $(D stride) will only analyze the first $(D str[index]) element. It will not fully verify the validity of the UTF sequence, nor even verify the presence of the sequence: it will not actually guarantee that $(D index + stride(str, index) <= str.length). +/ uint stride(S)(auto ref S str, size_t index) if (is(S : const char[]) || (isRandomAccessRange!S && is(Unqual!(ElementType!S) == char))) { static if (is(typeof(str.length) : ulong)) assert(index < str.length, "Past the end of the UTF-8 sequence"); immutable c = str[index]; if (c < 0x80) return 1; else return strideImpl(c, index); } /// Ditto uint stride(S)(auto ref S str) if (is(S : const char[]) || (isInputRange!S && is(Unqual!(ElementType!S) == char))) { static if (is(S : const char[])) immutable c = str[0]; else immutable c = str.front; if (c < 0x80) return 1; else return strideImpl(c, 0); } private uint strideImpl(char c, size_t index) @trusted pure in { assert(c & 0x80); } body { import core.bitop : bsr; immutable msbs = 7 - bsr(~c); if (!~c || msbs < 2 || msbs > 4) throw new UTFException("Invalid UTF-8 sequence", index); return msbs; } unittest { import std.conv : to; import std.exception; import std.string : format; import core.exception : AssertError; static void test(string s, dchar c, size_t i = 0, size_t line = __LINE__) { enforce(stride(s, i) == codeLength!char(c), new AssertError(format("Unit test failure string: %s", s), __FILE__, line)); enforce(stride(RandomCU!char(s), i) == codeLength!char(c), new AssertError(format("Unit test failure range: %s", s), __FILE__, line)); auto refRandom = new RefRandomCU!char(s); immutable randLen = refRandom.length; enforce(stride(refRandom, i) == codeLength!char(c), new AssertError(format("Unit test failure rand ref range: %s", s), __FILE__, line)); enforce(refRandom.length == randLen, new AssertError(format("Unit test failure rand ref range length: %s", s), __FILE__, line)); if (i == 0) { enforce(stride(s) == codeLength!char(c), new AssertError(format("Unit test failure string 0: %s", s), __FILE__, line)); enforce(stride(InputCU!char(s)) == codeLength!char(c), new AssertError(format("Unit test failure range 0: %s", s), __FILE__, line)); auto refBidir = new RefBidirCU!char(s); immutable bidirLen = refBidir.length; enforce(stride(refBidir) == codeLength!char(c), new AssertError(format("Unit test failure bidir ref range code length: %s", s), __FILE__, line)); enforce(refBidir.length == bidirLen, new AssertError(format("Unit test failure bidir ref range length: %s", s), __FILE__, line)); } } assertCTFEable!( { test("a", 'a'); test(" ", ' '); test("\u2029", '\u2029'); //paraSep test("\u0100", '\u0100'); test("\u0430", '\u0430'); test("\U00010143", '\U00010143'); test("abcdefcdef", 'a'); test("hello\U00010143\u0100\U00010143", 'h', 0); test("hello\U00010143\u0100\U00010143", 'e', 1); test("hello\U00010143\u0100\U00010143", 'l', 2); test("hello\U00010143\u0100\U00010143", 'l', 3); test("hello\U00010143\u0100\U00010143", 'o', 4); test("hello\U00010143\u0100\U00010143", '\U00010143', 5); test("hello\U00010143\u0100\U00010143", '\u0100', 9); test("hello\U00010143\u0100\U00010143", '\U00010143', 11); foreach (S; AliasSeq!(char[], const char[], string)) { enum str = to!S("hello world"); static assert(isSafe!({ stride(str, 0); })); static assert(isSafe!({ stride(str); })); static assert((functionAttributes!({ stride(str, 0); }) & FunctionAttribute.pure_) != 0); static assert((functionAttributes!({ stride(str); }) & FunctionAttribute.pure_) != 0); } }); } unittest // invalid start bytes { import std.exception: assertThrown; immutable char[] invalidStartBytes = [ 0b1111_1000, // indicating a sequence length of 5 0b1111_1100, // 6 0b1111_1110, // 7 0b1111_1111, // 8 0b1000_0000, // continuation byte ]; foreach(c; invalidStartBytes) assertThrown!UTFException(stride([c])); } /// Ditto uint stride(S)(auto ref S str, size_t index) if (is(S : const wchar[]) || (isRandomAccessRange!S && is(Unqual!(ElementType!S) == wchar))) { static if (is(typeof(str.length) : ulong)) assert(index < str.length, "Past the end of the UTF-16 sequence"); immutable uint u = str[index]; return 1 + (u >= 0xD800 && u <= 0xDBFF); } /// Ditto uint stride(S)(auto ref S str) @safe pure if (is(S : const wchar[])) { return stride(str, 0); } /// Ditto uint stride(S)(auto ref S str) if (isInputRange!S && is(Unqual!(ElementType!S) == wchar)) { assert(!str.empty, "UTF-16 sequence is empty"); immutable uint u = str.front; return 1 + (u >= 0xD800 && u <= 0xDBFF); } unittest { import std.conv : to; import std.exception; import std.string : format; import core.exception : AssertError; static void test(wstring s, dchar c, size_t i = 0, size_t line = __LINE__) { enforce(stride(s, i) == codeLength!wchar(c), new AssertError(format("Unit test failure string: %s", s), __FILE__, line)); enforce(stride(RandomCU!wchar(s), i) == codeLength!wchar(c), new AssertError(format("Unit test failure range: %s", s), __FILE__, line)); auto refRandom = new RefRandomCU!wchar(s); immutable randLen = refRandom.length; enforce(stride(refRandom, i) == codeLength!wchar(c), new AssertError(format("Unit test failure rand ref range: %s", s), __FILE__, line)); enforce(refRandom.length == randLen, new AssertError(format("Unit test failure rand ref range length: %s", s), __FILE__, line)); if (i == 0) { enforce(stride(s) == codeLength!wchar(c), new AssertError(format("Unit test failure string 0: %s", s), __FILE__, line)); enforce(stride(InputCU!wchar(s)) == codeLength!wchar(c), new AssertError(format("Unit test failure range 0: %s", s), __FILE__, line)); auto refBidir = new RefBidirCU!wchar(s); immutable bidirLen = refBidir.length; enforce(stride(refBidir) == codeLength!wchar(c), new AssertError(format("Unit test failure bidir ref range code length: %s", s), __FILE__, line)); enforce(refBidir.length == bidirLen, new AssertError(format("Unit test failure bidir ref range length: %s", s), __FILE__, line)); } } assertCTFEable!( { test("a", 'a'); test(" ", ' '); test("\u2029", '\u2029'); //paraSep test("\u0100", '\u0100'); test("\u0430", '\u0430'); test("\U00010143", '\U00010143'); test("abcdefcdef", 'a'); test("hello\U00010143\u0100\U00010143", 'h', 0); test("hello\U00010143\u0100\U00010143", 'e', 1); test("hello\U00010143\u0100\U00010143", 'l', 2); test("hello\U00010143\u0100\U00010143", 'l', 3); test("hello\U00010143\u0100\U00010143", 'o', 4); test("hello\U00010143\u0100\U00010143", '\U00010143', 5); test("hello\U00010143\u0100\U00010143", '\u0100', 7); test("hello\U00010143\u0100\U00010143", '\U00010143', 8); foreach (S; AliasSeq!(wchar[], const wchar[], wstring)) { enum str = to!S("hello world"); static assert(isSafe!(() => stride(str, 0))); static assert(isSafe!(() => stride(str) )); static assert((functionAttributes!(() => stride(str, 0)) & FunctionAttribute.pure_) != 0); static assert((functionAttributes!(() => stride(str) ) & FunctionAttribute.pure_) != 0); } }); } /// Ditto uint stride(S)(auto ref S str, size_t index = 0) if (is(S : const dchar[]) || (isInputRange!S && is(Unqual!(ElementEncodingType!S) == dchar))) { static if (is(typeof(str.length) : ulong)) assert(index < str.length, "Past the end of the UTF-32 sequence"); else assert(!str.empty, "UTF-32 sequence is empty."); return 1; } unittest { import std.conv : to; import std.exception; import std.string : format; import core.exception : AssertError; static void test(dstring s, dchar c, size_t i = 0, size_t line = __LINE__) { enforce(stride(s, i) == codeLength!dchar(c), new AssertError(format("Unit test failure string: %s", s), __FILE__, line)); enforce(stride(RandomCU!dchar(s), i) == codeLength!dchar(c), new AssertError(format("Unit test failure range: %s", s), __FILE__, line)); auto refRandom = new RefRandomCU!dchar(s); immutable randLen = refRandom.length; enforce(stride(refRandom, i) == codeLength!dchar(c), new AssertError(format("Unit test failure rand ref range: %s", s), __FILE__, line)); enforce(refRandom.length == randLen, new AssertError(format("Unit test failure rand ref range length: %s", s), __FILE__, line)); if (i == 0) { enforce(stride(s) == codeLength!dchar(c), new AssertError(format("Unit test failure string 0: %s", s), __FILE__, line)); enforce(stride(InputCU!dchar(s)) == codeLength!dchar(c), new AssertError(format("Unit test failure range 0: %s", s), __FILE__, line)); auto refBidir = new RefBidirCU!dchar(s); immutable bidirLen = refBidir.length; enforce(stride(refBidir) == codeLength!dchar(c), new AssertError(format("Unit test failure bidir ref range code length: %s", s), __FILE__, line)); enforce(refBidir.length == bidirLen, new AssertError(format("Unit test failure bidir ref range length: %s", s), __FILE__, line)); } } assertCTFEable!( { test("a", 'a'); test(" ", ' '); test("\u2029", '\u2029'); //paraSep test("\u0100", '\u0100'); test("\u0430", '\u0430'); test("\U00010143", '\U00010143'); test("abcdefcdef", 'a'); test("hello\U00010143\u0100\U00010143", 'h', 0); test("hello\U00010143\u0100\U00010143", 'e', 1); test("hello\U00010143\u0100\U00010143", 'l', 2); test("hello\U00010143\u0100\U00010143", 'l', 3); test("hello\U00010143\u0100\U00010143", 'o', 4); test("hello\U00010143\u0100\U00010143", '\U00010143', 5); test("hello\U00010143\u0100\U00010143", '\u0100', 6); test("hello\U00010143\u0100\U00010143", '\U00010143', 7); foreach (S; AliasSeq!(dchar[], const dchar[], dstring)) { enum str = to!S("hello world"); static assert(isSafe!(() => stride(str, 0))); static assert(isSafe!(() => stride(str) )); static assert((functionAttributes!(() => stride(str, 0)) & FunctionAttribute.pure_) != 0); static assert((functionAttributes!(() => stride(str) ) & FunctionAttribute.pure_) != 0); } }); } /++ Calculate the length of the UTF sequence ending one code unit before $(D index) in $(D str). Params: str = bidirectional range of UTF code units. Must be random access if $(D index) is passed index = index one past end of UTF sequence (default: $(D str.length)) Returns: The number of code units in the UTF sequence. For UTF-8, this is a value between 1 and 4 (as per $(WEB tools.ietf.org/html/rfc3629#section-3, RFC 3629$(COMMA) section 3)). For UTF-16, it is either 1 or 2. For UTF-32, it is always 1. Throws: May throw a $(D UTFException) if $(D str[index]) is not one past the end of a valid UTF sequence. Note: $(D strideBack) will only analyze the element at $(D str[index - 1]) element. It will not fully verify the validity of the UTF sequence, nor even verify the presence of the sequence: it will not actually guarantee that $(D strideBack(str, index) <= index). +/ uint strideBack(S)(auto ref S str, size_t index) if (is(S : const char[]) || (isRandomAccessRange!S && is(Unqual!(ElementType!S) == char))) { static if (is(typeof(str.length) : ulong)) assert(index <= str.length, "Past the end of the UTF-8 sequence"); assert(index > 0, "Not the end of the UTF-8 sequence"); if ((str[index-1] & 0b1100_0000) != 0b1000_0000) return 1; if (index >= 4) //single verification for most common case { foreach (i; AliasSeq!(2, 3, 4)) { if ((str[index-i] & 0b1100_0000) != 0b1000_0000) return i; } } else { foreach (i; AliasSeq!(2, 3)) { if (index >= i && (str[index-i] & 0b1100_0000) != 0b1000_0000) return i; } } throw new UTFException("Not the end of the UTF sequence", index); } /// Ditto uint strideBack(S)(auto ref S str) if (is(S : const char[]) || (isRandomAccessRange!S && hasLength!S && is(Unqual!(ElementType!S) == char))) { return strideBack(str, str.length); } /// Ditto uint strideBack(S)(auto ref S str) if (isBidirectionalRange!S && is(Unqual!(ElementType!S) == char) && !isRandomAccessRange!S) { assert(!str.empty, "Past the end of the UTF-8 sequence"); auto temp = str.save; foreach (i; AliasSeq!(1, 2, 3, 4)) { if ((temp.back & 0b1100_0000) != 0b1000_0000) return i; temp.popBack(); if (temp.empty) break; } throw new UTFException("The last code unit is not the end of the UTF-8 sequence"); } unittest { import std.conv : to; import std.exception; import std.string : format; import core.exception : AssertError; static void test(string s, dchar c, size_t i = size_t.max, size_t line = __LINE__) { enforce(strideBack(s, i == size_t.max ? s.length : i) == codeLength!char(c), new AssertError(format("Unit test failure string: %s", s), __FILE__, line)); enforce(strideBack(RandomCU!char(s), i == size_t.max ? s.length : i) == codeLength!char(c), new AssertError(format("Unit test failure range: %s", s), __FILE__, line)); auto refRandom = new RefRandomCU!char(s); immutable randLen = refRandom.length; enforce(strideBack(refRandom, i == size_t.max ? s.length : i) == codeLength!char(c), new AssertError(format("Unit test failure rand ref range: %s", s), __FILE__, line)); enforce(refRandom.length == randLen, new AssertError(format("Unit test failure rand ref range length: %s", s), __FILE__, line)); if (i == size_t.max) { enforce(strideBack(s) == codeLength!char(c), new AssertError(format("Unit test failure string code length: %s", s), __FILE__, line)); enforce(strideBack(BidirCU!char(s)) == codeLength!char(c), new AssertError(format("Unit test failure range code length: %s", s), __FILE__, line)); auto refBidir = new RefBidirCU!char(s); immutable bidirLen = refBidir.length; enforce(strideBack(refBidir) == codeLength!char(c), new AssertError(format("Unit test failure bidir ref range code length: %s", s), __FILE__, line)); enforce(refBidir.length == bidirLen, new AssertError(format("Unit test failure bidir ref range length: %s", s), __FILE__, line)); } } assertCTFEable!( { test("a", 'a'); test(" ", ' '); test("\u2029", '\u2029'); //paraSep test("\u0100", '\u0100'); test("\u0430", '\u0430'); test("\U00010143", '\U00010143'); test("abcdefcdef", 'f'); test("\U00010143\u0100\U00010143hello", 'o', 15); test("\U00010143\u0100\U00010143hello", 'l', 14); test("\U00010143\u0100\U00010143hello", 'l', 13); test("\U00010143\u0100\U00010143hello", 'e', 12); test("\U00010143\u0100\U00010143hello", 'h', 11); test("\U00010143\u0100\U00010143hello", '\U00010143', 10); test("\U00010143\u0100\U00010143hello", '\u0100', 6); test("\U00010143\u0100\U00010143hello", '\U00010143', 4); foreach (S; AliasSeq!(char[], const char[], string)) { enum str = to!S("hello world"); static assert(isSafe!({ strideBack(str, 0); })); static assert(isSafe!({ strideBack(str); })); static assert((functionAttributes!({ strideBack(str, 0); }) & FunctionAttribute.pure_) != 0); static assert((functionAttributes!({ strideBack(str); }) & FunctionAttribute.pure_) != 0); } }); } //UTF-16 is self synchronizing: The length of strideBack can be found from //the value of a single wchar /// Ditto uint strideBack(S)(auto ref S str, size_t index) if (is(S : const wchar[]) || (isRandomAccessRange!S && is(Unqual!(ElementType!S) == wchar))) { static if (is(typeof(str.length) : ulong)) assert(index <= str.length, "Past the end of the UTF-16 sequence"); assert(index > 0, "Not the end of a UTF-16 sequence"); immutable c2 = str[index-1]; return 1 + (0xDC00 <= c2 && c2 < 0xE000); } /// Ditto uint strideBack(S)(auto ref S str) if (is(S : const wchar[]) || (isBidirectionalRange!S && is(Unqual!(ElementType!S) == wchar))) { assert(!str.empty, "UTF-16 sequence is empty"); static if (is(S : const(wchar)[])) immutable c2 = str[$ - 1]; else immutable c2 = str.back; return 1 + (0xDC00 <= c2 && c2 <= 0xE000); } unittest { import std.conv : to; import std.exception; import std.string : format; import core.exception : AssertError; static void test(wstring s, dchar c, size_t i = size_t.max, size_t line = __LINE__) { enforce(strideBack(s, i == size_t.max ? s.length : i) == codeLength!wchar(c), new AssertError(format("Unit test failure string: %s", s), __FILE__, line)); enforce(strideBack(RandomCU!wchar(s), i == size_t.max ? s.length : i) == codeLength!wchar(c), new AssertError(format("Unit test failure range: %s", s), __FILE__, line)); auto refRandom = new RefRandomCU!wchar(s); immutable randLen = refRandom.length; enforce(strideBack(refRandom, i == size_t.max ? s.length : i) == codeLength!wchar(c), new AssertError(format("Unit test failure rand ref range: %s", s), __FILE__, line)); enforce(refRandom.length == randLen, new AssertError(format("Unit test failure rand ref range length: %s", s), __FILE__, line)); if (i == size_t.max) { enforce(strideBack(s) == codeLength!wchar(c), new AssertError(format("Unit test failure string code length: %s", s), __FILE__, line)); enforce(strideBack(BidirCU!wchar(s)) == codeLength!wchar(c), new AssertError(format("Unit test failure range code length: %s", s), __FILE__, line)); auto refBidir = new RefBidirCU!wchar(s); immutable bidirLen = refBidir.length; enforce(strideBack(refBidir) == codeLength!wchar(c), new AssertError(format("Unit test failure bidir ref range code length: %s", s), __FILE__, line)); enforce(refBidir.length == bidirLen, new AssertError(format("Unit test failure bidir ref range length: %s", s), __FILE__, line)); } } assertCTFEable!( { test("a", 'a'); test(" ", ' '); test("\u2029", '\u2029'); //paraSep test("\u0100", '\u0100'); test("\u0430", '\u0430'); test("\U00010143", '\U00010143'); test("abcdefcdef", 'f'); test("\U00010143\u0100\U00010143hello", 'o', 10); test("\U00010143\u0100\U00010143hello", 'l', 9); test("\U00010143\u0100\U00010143hello", 'l', 8); test("\U00010143\u0100\U00010143hello", 'e', 7); test("\U00010143\u0100\U00010143hello", 'h', 6); test("\U00010143\u0100\U00010143hello", '\U00010143', 5); test("\U00010143\u0100\U00010143hello", '\u0100', 3); test("\U00010143\u0100\U00010143hello", '\U00010143', 2); foreach (S; AliasSeq!(wchar[], const wchar[], wstring)) { enum str = to!S("hello world"); static assert(isSafe!(() => strideBack(str, 0))); static assert(isSafe!(() => strideBack(str) )); static assert((functionAttributes!(() => strideBack(str, 0)) & FunctionAttribute.pure_) != 0); static assert((functionAttributes!(() => strideBack(str) ) & FunctionAttribute.pure_) != 0); } }); } /// Ditto uint strideBack(S)(auto ref S str, size_t index) if (isRandomAccessRange!S && is(Unqual!(ElementEncodingType!S) == dchar)) { static if (is(typeof(str.length) : ulong)) assert(index <= str.length, "Past the end of the UTF-32 sequence"); assert(index > 0, "Not the end of the UTF-32 sequence"); return 1; } /// Ditto uint strideBack(S)(auto ref S str) if (isBidirectionalRange!S && is(Unqual!(ElementEncodingType!S) == dchar)) { assert(!str.empty, "Empty UTF-32 sequence"); return 1; } unittest { import std.conv : to; import std.exception; import std.string : format; import core.exception : AssertError; static void test(dstring s, dchar c, size_t i = size_t.max, size_t line = __LINE__) { enforce(strideBack(s, i == size_t.max ? s.length : i) == codeLength!dchar(c), new AssertError(format("Unit test failure string: %s", s), __FILE__, line)); enforce(strideBack(RandomCU!dchar(s), i == size_t.max ? s.length : i) == codeLength!dchar(c), new AssertError(format("Unit test failure range: %s", s), __FILE__, line)); auto refRandom = new RefRandomCU!dchar(s); immutable randLen = refRandom.length; enforce(strideBack(refRandom, i == size_t.max ? s.length : i) == codeLength!dchar(c), new AssertError(format("Unit test failure rand ref range: %s", s), __FILE__, line)); enforce(refRandom.length == randLen, new AssertError(format("Unit test failure rand ref range length: %s", s), __FILE__, line)); if (i == size_t.max) { enforce(strideBack(s) == codeLength!dchar(c), new AssertError(format("Unit test failure string code length: %s", s), __FILE__, line)); enforce(strideBack(BidirCU!dchar(s)) == codeLength!dchar(c), new AssertError(format("Unit test failure range code length: %s", s), __FILE__, line)); auto refBidir = new RefBidirCU!dchar(s); immutable bidirLen = refBidir.length; enforce(strideBack(refBidir) == codeLength!dchar(c), new AssertError(format("Unit test failure bidir ref range code length: %s", s), __FILE__, line)); enforce(refBidir.length == bidirLen, new AssertError(format("Unit test failure bidir ref range length: %s", s), __FILE__, line)); } } assertCTFEable!( { test("a", 'a'); test(" ", ' '); test("\u2029", '\u2029'); //paraSep test("\u0100", '\u0100'); test("\u0430", '\u0430'); test("\U00010143", '\U00010143'); test("abcdefcdef", 'f'); test("\U00010143\u0100\U00010143hello", 'o', 8); test("\U00010143\u0100\U00010143hello", 'l', 7); test("\U00010143\u0100\U00010143hello", 'l', 6); test("\U00010143\u0100\U00010143hello", 'e', 5); test("\U00010143\u0100\U00010143hello", 'h', 4); test("\U00010143\u0100\U00010143hello", '\U00010143', 3); test("\U00010143\u0100\U00010143hello", '\u0100', 2); test("\U00010143\u0100\U00010143hello", '\U00010143', 1); foreach (S; AliasSeq!(dchar[], const dchar[], dstring)) { enum str = to!S("hello world"); static assert(isSafe!(() => strideBack(str, 0))); static assert(isSafe!(() => strideBack(str) )); static assert((functionAttributes!(() => strideBack(str, 0)) & FunctionAttribute.pure_) != 0); static assert((functionAttributes!(() => strideBack(str) ) & FunctionAttribute.pure_) != 0); } }); } /++ Given $(D index) into $(D str) and assuming that $(D index) is at the start of a UTF sequence, $(D toUCSindex) determines the number of UCS characters up to $(D index). So, $(D index) is the index of a code unit at the beginning of a code point, and the return value is how many code points into the string that that code point is. +/ size_t toUCSindex(C)(const(C)[] str, size_t index) @safe pure if (isSomeChar!C) { static if (is(Unqual!C == dchar)) return index; else { size_t n = 0; size_t j = 0; for (; j < index; ++n) j += stride(str, j); if (j > index) { static if (is(Unqual!C == char)) throw new UTFException("Invalid UTF-8 sequence", index); else throw new UTFException("Invalid UTF-16 sequence", index); } return n; } } /// unittest { assert(toUCSindex(`hello world`, 7) == 7); assert(toUCSindex(`hello world`w, 7) == 7); assert(toUCSindex(`hello world`d, 7) == 7); assert(toUCSindex(`Ma Chérie`, 7) == 6); assert(toUCSindex(`Ma Chérie`w, 7) == 7); assert(toUCSindex(`Ma Chérie`d, 7) == 7); assert(toUCSindex(`さいごの果実 / ミツバチと科学者`, 9) == 3); assert(toUCSindex(`さいごの果実 / ミツバチと科学者`w, 9) == 9); assert(toUCSindex(`さいごの果実 / ミツバチと科学者`d, 9) == 9); } /++ Given a UCS index $(D n) into $(D str), returns the UTF index. So, $(D n) is how many code points into the string the code point is, and the array index of the code unit is returned. +/ size_t toUTFindex(C)(const(C)[] str, size_t n) @safe pure if (isSomeChar!C) { static if (is(Unqual!C == dchar)) { return n; } else { size_t i; while (n--) { i += stride(str, i); } return i; } } /// unittest { assert(toUTFindex(`hello world`, 7) == 7); assert(toUTFindex(`hello world`w, 7) == 7); assert(toUTFindex(`hello world`d, 7) == 7); assert(toUTFindex(`Ma Chérie`, 6) == 7); assert(toUTFindex(`Ma Chérie`w, 7) == 7); assert(toUTFindex(`Ma Chérie`d, 7) == 7); assert(toUTFindex(`さいごの果実 / ミツバチと科学者`, 3) == 9); assert(toUTFindex(`さいごの果実 / ミツバチと科学者`w, 9) == 9); assert(toUTFindex(`さいごの果実 / ミツバチと科学者`d, 9) == 9); } /* =================== Decode ======================= */ /// Whether or not to replace invalid UTF with $(LREF replacementDchar) alias UseReplacementDchar = Flag!"useReplacementDchar"; /++ Decodes and returns the code point starting at $(D str[index]). $(D index) is advanced to one past the decoded code point. If the code point is not well-formed, then a $(D UTFException) is thrown and $(D index) remains unchanged. decode will only work with strings and random access ranges of code units with length and slicing, whereas $(LREF decodeFront) will work with any input range of code units. Params: useReplacementDchar = if invalid UTF, return replacementDchar rather than throwing str = input string or indexable Range index = starting index into s[]; incremented by number of code units processed Returns: decoded character Throws: $(LREF UTFException) if $(D str[index]) is not the start of a valid UTF sequence and useReplacementDchar is UseReplacementDchar.no +/ dchar decode(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no, S)(auto ref S str, ref size_t index) if (!isSomeString!S && isRandomAccessRange!S && hasSlicing!S && hasLength!S && isSomeChar!(ElementType!S)) in { assert(index < str.length, "Attempted to decode past the end of a string"); } out (result) { assert(isValidDchar(result)); } body { if (str[index] < codeUnitLimit!S) return str[index++]; else return decodeImpl!(true, useReplacementDchar)(str, index); } dchar decode(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no, S)(auto ref S str, ref size_t index) @trusted pure if (isSomeString!S) in { assert(index < str.length, "Attempted to decode past the end of a string"); } out (result) { assert(isValidDchar(result)); } body { if (str[index] < codeUnitLimit!S) return str[index++]; else return decodeImpl!(true, useReplacementDchar)(str, index); } /++ $(D decodeFront) is a variant of $(LREF decode) which specifically decodes the first code point. Unlike $(LREF decode), $(D decodeFront) accepts any input range of code units (rather than just a string or random access range). It also takes the range by $(D ref) and pops off the elements as it decodes them. If $(D numCodeUnits) is passed in, it gets set to the number of code units which were in the code point which was decoded. Params: useReplacementDchar = if invalid UTF, return replacementDchar rather than throwing str = input string or indexable Range numCodeUnits = set to number of code units processed Returns: decoded character Throws: $(LREF UTFException) if $(D str.front) is not the start of a valid UTF sequence. If an exception is thrown, then there is no guarantee as to the number of code units which were popped off, as it depends on the type of range being used and how many code units had to be popped off before the code point was determined to be invalid. +/ dchar decodeFront(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no, S)(ref S str, out size_t numCodeUnits) if (!isSomeString!S && isInputRange!S && isSomeChar!(ElementType!S)) in { assert(!str.empty); } out (result) { assert(isValidDchar(result)); } body { immutable fst = str.front; if (fst < codeUnitLimit!S) { str.popFront(); numCodeUnits = 1; return fst; } else { //@@@BUG@@@ 14447 forces canIndex to be done outside of decodeImpl, which //is undesirable, since not all overloads of decodeImpl need it. So, it //should be moved back into decodeImpl once bug# 8521 has been fixed. enum canIndex = isRandomAccessRange!S && hasSlicing!S && hasLength!S; immutable retval = decodeImpl!(canIndex, useReplacementDchar)(str, numCodeUnits); // The other range types were already popped by decodeImpl. static if (isRandomAccessRange!S && hasSlicing!S && hasLength!S) str = str[numCodeUnits .. str.length]; return retval; } } dchar decodeFront(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no, S)(ref S str, out size_t numCodeUnits) @trusted pure if (isSomeString!S) in { assert(!str.empty); } out (result) { assert(isValidDchar(result)); } body { if (str[0] < codeUnitLimit!S) { numCodeUnits = 1; immutable retval = str[0]; str = str[1 .. $]; return retval; } else { immutable retval = decodeImpl!(true, useReplacementDchar)(str, numCodeUnits); str = str[numCodeUnits .. $]; return retval; } } /++ Ditto +/ dchar decodeFront(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no, S)(ref S str) if (isInputRange!S && isSomeChar!(ElementType!S)) { size_t numCodeUnits; return decodeFront!useReplacementDchar(str, numCodeUnits); } // Gives the maximum value that a code unit for the given range type can hold. package template codeUnitLimit(S) if (isSomeChar!(ElementEncodingType!S)) { static if (is(Unqual!(ElementEncodingType!S) == char)) enum char codeUnitLimit = 0x80; else static if (is(Unqual!(ElementEncodingType!S) == wchar)) enum wchar codeUnitLimit = 0xD800; else enum dchar codeUnitLimit = 0xD800; } /* * For strings, this function does its own bounds checking to give a * more useful error message when attempting to decode past the end of a string. * Subsequently it uses a pointer instead of an array to avoid * redundant bounds checking. * * The three overloads of this operate on chars, wchars, and dchars. * * Params: * canIndex = if S is indexable * useReplacementDchar = if invalid UTF, return replacementDchar rather than throwing * str = input string or Range * index = starting index into s[]; incremented by number of code units processed * * Returns: * decoded character */ private dchar decodeImpl(bool canIndex, UseReplacementDchar useReplacementDchar = UseReplacementDchar.no, S)(auto ref S str, ref size_t index) if (is(S : const char[]) || (isInputRange!S && is(Unqual!(ElementEncodingType!S) == char))) { /* The following encodings are valid, except for the 5 and 6 byte * combinations: * 0xxxxxxx * 110xxxxx 10xxxxxx * 1110xxxx 10xxxxxx 10xxxxxx * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ /* Dchar bitmask for different numbers of UTF-8 code units. */ alias bitMask = AliasSeq!((1 << 7) - 1, (1 << 11) - 1, (1 << 16) - 1, (1 << 21) - 1); static if (is(S : const char[])) auto pstr = str.ptr + index; else static if (isRandomAccessRange!S && hasSlicing!S && hasLength!S) auto pstr = str[index .. str.length]; else alias pstr = str; //@@@BUG@@@ 14447 forces this to be done outside of decodeImpl //enum canIndex = is(S : const char[]) || (isRandomAccessRange!S && hasSlicing!S && hasLength!S); static if (canIndex) { immutable length = str.length - index; ubyte fst = pstr[0]; } else { ubyte fst = pstr.front; pstr.popFront(); } static if (!useReplacementDchar) { static if (canIndex) { static UTFException exception(S)(S str, string msg) { uint[4] sequence = void; size_t i; do { sequence[i] = str[i]; } while (++i < str.length && i < 4 && (str[i] & 0xC0) == 0x80); return new UTFException(msg, i).setSequence(sequence[0 .. i]); } } UTFException invalidUTF() { static if (canIndex) return exception(pstr[0 .. length], "Invalid UTF-8 sequence"); else { //We can't include the invalid sequence with input strings without //saving each of the code units along the way, and we can't do it with //forward ranges without saving the entire range. Both would incur a //cost for the decoding of every character just to provide a better //error message for the (hopefully) rare case when an invalid UTF-8 //sequence is encountered, so we don't bother trying to include the //invalid sequence here, unlike with strings and sliceable ranges. return new UTFException("Invalid UTF-8 sequence"); } } UTFException outOfBounds() { static if (canIndex) return exception(pstr[0 .. length], "Attempted to decode past the end of a string"); else return new UTFException("Attempted to decode past the end of a string"); } } if ((fst & 0b1100_0000) != 0b1100_0000) { static if (useReplacementDchar) { ++index; // always consume bad input to avoid infinite loops return replacementDchar; } else throw invalidUTF(); // starter must have at least 2 first bits set } ubyte tmp = void; dchar d = fst; // upper control bits are masked out later fst <<= 1; foreach (i; AliasSeq!(1, 2, 3)) { static if (canIndex) { if (i == length) { static if (useReplacementDchar) { index += i; return replacementDchar; } else throw outOfBounds(); } } else { if (pstr.empty) { static if (useReplacementDchar) { index += i; return replacementDchar; } else throw outOfBounds(); } } static if (canIndex) tmp = pstr[i]; else { tmp = pstr.front; pstr.popFront(); } if ((tmp & 0xC0) != 0x80) { static if (useReplacementDchar) { index += i + 1; return replacementDchar; } else throw invalidUTF(); } d = (d << 6) | (tmp & 0x3F); fst <<= 1; if (!(fst & 0x80)) // no more bytes { d &= bitMask[i]; // mask out control bits // overlong, could have been encoded with i bytes if ((d & ~bitMask[i - 1]) == 0) { static if (useReplacementDchar) { index += i + 1; return replacementDchar; } else throw invalidUTF(); } // check for surrogates only needed for 3 bytes static if (i == 2) { if (!isValidDchar(d)) { static if (useReplacementDchar) { index += i + 1; return replacementDchar; } else throw invalidUTF(); } } index += i + 1; static if (i == 3) { if (d > dchar.max) { static if (useReplacementDchar) d = replacementDchar; else throw invalidUTF(); } } return d; } } static if (useReplacementDchar) { index += 4; // read 4 chars by now return replacementDchar; } else throw invalidUTF(); } @safe pure @nogc nothrow unittest { // Add tests for useReplacemendDchar==yes path static struct R { @safe pure @nogc nothrow: this(string s) { this.s = s; } @property bool empty() { return idx == s.length; } @property char front() { return s[idx]; } void popFront() { ++idx; } size_t idx; string s; } foreach (s; invalidUTFstrings!char()) { auto r = R(s); size_t index; dchar dc = decodeImpl!(false, Flag!"useReplacementDchar".yes)(r, index); assert(dc == replacementDchar); assert(1 <= index && index <= s.length); } } private dchar decodeImpl(bool canIndex, UseReplacementDchar useReplacementDchar = UseReplacementDchar.no, S)(auto ref S str, ref size_t index) if (is(S : const wchar[]) || (isInputRange!S && is(Unqual!(ElementEncodingType!S) == wchar))) { static if (is(S : const wchar[])) auto pstr = str.ptr + index; else static if (isRandomAccessRange!S && hasSlicing!S && hasLength!S) auto pstr = str[index .. str.length]; else alias pstr = str; //@@@BUG@@@ 14447 forces this to be done outside of decodeImpl //enum canIndex = is(S : const wchar[]) || (isRandomAccessRange!S && hasSlicing!S && hasLength!S); static if (canIndex) { immutable length = str.length - index; uint u = pstr[0]; } else { uint u = pstr.front; pstr.popFront(); } static if (!useReplacementDchar) { UTFException exception(string msg) { static if (canIndex) return new UTFException(msg).setSequence(pstr[0]); else return new UTFException(msg); } } string msg; // The < case must be taken care of before decodeImpl is called. assert(u >= 0xD800); if (u <= 0xDBFF) { static if (canIndex) immutable onlyOneCodeUnit = length == 1; else immutable onlyOneCodeUnit = pstr.empty; if (onlyOneCodeUnit) { static if (useReplacementDchar) { ++index; return replacementDchar; } else throw exception("surrogate UTF-16 high value past end of string"); } static if (canIndex) immutable uint u2 = pstr[1]; else { immutable uint u2 = pstr.front; pstr.popFront(); } if (u2 < 0xDC00 || u2 > 0xDFFF) { static if (useReplacementDchar) u = replacementDchar; else throw exception("surrogate UTF-16 low value out of range"); } else u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); ++index; } else if (u >= 0xDC00 && u <= 0xDFFF) { static if (useReplacementDchar) u = replacementDchar; else throw exception("unpaired surrogate UTF-16 value"); } ++index; // Note: u+FFFE and u+FFFF are specifically permitted by the // Unicode standard for application internal use (see isValidDchar) return cast(dchar)u; } pure @nogc nothrow unittest { // Add tests for useReplacemendDchar==true path static struct R { @safe pure @nogc nothrow: this(wstring s) { this.s = s; } @property bool empty() { return idx == s.length; } @property wchar front() { return s[idx]; } void popFront() { ++idx; } size_t idx; wstring s; } foreach (s; invalidUTFstrings!wchar()) { auto r = R(s); size_t index; dchar dc = decodeImpl!(false, Flag!"useReplacementDchar".yes)(r, index); assert(dc == replacementDchar); assert(1 <= index && index <= s.length); } } private dchar decodeImpl(bool canIndex, UseReplacementDchar useReplacementDchar = UseReplacementDchar.no, S)(auto ref S str, ref size_t index) if (is(S : const dchar[]) || (isInputRange!S && is(Unqual!(ElementEncodingType!S) == dchar))) { static if (is(S : const dchar[])) auto pstr = str.ptr; else alias pstr = str; static if (is(S : const dchar[]) || isRandomAccessRange!S) { dchar dc = pstr[index]; if (!isValidDchar(dc)) { static if (useReplacementDchar) dc = replacementDchar; else throw new UTFException("Invalid UTF-32 value").setSequence(dc); } ++index; return dc; } else { dchar dc = pstr.front; if (!isValidDchar(dc)) { static if (useReplacementDchar) dc = replacementDchar; else throw new UTFException("Invalid UTF-32 value").setSequence(dc); } ++index; pstr.popFront(); return dc; } } pure @nogc nothrow unittest { // Add tests for useReplacemendDchar==true path static struct R { @safe pure @nogc nothrow: this(dstring s) { this.s = s; } @property bool empty() { return idx == s.length; } @property dchar front() { return s[idx]; } void popFront() { ++idx; } size_t idx; dstring s; } foreach (s; invalidUTFstrings!dchar()) { auto r = R(s); size_t index; dchar dc = decodeImpl!(false, Flag!"useReplacementDchar".yes)(r, index); assert(dc == replacementDchar); assert(1 <= index && index <= s.length); } } version(unittest) private void testDecode(R)(R range, size_t index, dchar expectedChar, size_t expectedIndex, size_t line = __LINE__) { import std.exception; import std.string : format; import core.exception : AssertError; static if (hasLength!R) immutable lenBefore = range.length; static if (isRandomAccessRange!R) { { immutable result = decode(range, index); enforce(result == expectedChar, new AssertError(format("decode: Wrong character: %s", result), __FILE__, line)); enforce(index == expectedIndex, new AssertError(format("decode: Wrong index: %s", index), __FILE__, line)); static if (hasLength!R) { enforce(range.length == lenBefore, new AssertError(format("decode: length changed: %s", range.length), __FILE__, line)); } } } } version(unittest) private void testDecodeFront(R)(ref R range, dchar expectedChar, size_t expectedNumCodeUnits, size_t line = __LINE__) { import std.exception; import std.string : format; import core.exception : AssertError; static if (hasLength!R) immutable lenBefore = range.length; size_t numCodeUnits; immutable result = decodeFront(range, numCodeUnits); enforce(result == expectedChar, new AssertError(format("decodeFront: Wrong character: %s", result), __FILE__, line)); enforce(numCodeUnits == expectedNumCodeUnits, new AssertError(format("decodeFront: Wrong numCodeUnits: %s", numCodeUnits), __FILE__, line)); static if (hasLength!R) { enforce(range.length == lenBefore - numCodeUnits, new AssertError(format("decodeFront: wrong length: %s", range.length), __FILE__, line)); } } version(unittest) private void testBothDecode(R)(R range, dchar expectedChar, size_t expectedIndex, size_t line = __LINE__) { testDecode(range, 0, expectedChar, expectedIndex, line); testDecodeFront(range, expectedChar, expectedIndex, line); } version(unittest) private void testBadDecode(R)(R range, size_t index, size_t line = __LINE__) { import std.exception; import std.string : format; import core.exception : AssertError; immutable initialIndex = index; static if (hasLength!R) immutable lenBefore = range.length; static if (isRandomAccessRange!R) { assertThrown!UTFException(decode(range, index), null, __FILE__, line); enforce(index == initialIndex, new AssertError(format("decode: Wrong index: %s", index), __FILE__, line)); static if (hasLength!R) { enforce(range.length == lenBefore, new AssertError(format("decode: length changed:", range.length), __FILE__, line)); } } if (initialIndex == 0) assertThrown!UTFException(decodeFront(range, index), null, __FILE__, line); } unittest { import std.conv : to; import std.exception; debug(utf) printf("utf.decode.unittest\n"); assertCTFEable!( { foreach (S; AliasSeq!(to!string, InputCU!char, RandomCU!char, (string s) => new RefBidirCU!char(s), (string s) => new RefRandomCU!char(s))) { enum sHasLength = hasLength!(typeof(S("abcd"))); { auto range = S("abcd"); testDecode(range, 0, 'a', 1); testDecode(range, 1, 'b', 2); testDecodeFront(range, 'a', 1); testDecodeFront(range, 'b', 1); assert(decodeFront(range) == 'c'); assert(decodeFront(range) == 'd'); } { auto range = S("ウェブサイト"); testDecode(range, 0, 'ウ', 3); testDecode(range, 3, 'ェ', 6); testDecodeFront(range, 'ウ', 3); testDecodeFront(range, 'ェ', 3); assert(decodeFront(range) == 'ブ'); assert(decodeFront(range) == 'サ'); } testBothDecode(S("\xC2\xA9"), '\u00A9', 2); testBothDecode(S("\xE2\x89\xA0"), '\u2260', 3); foreach (str; ["\xE2\x89", // too short "\xC0\x8A", "\xE0\x80\x8A", "\xF0\x80\x80\x8A", "\xF8\x80\x80\x80\x8A", "\xFC\x80\x80\x80\x80\x8A"]) { testBadDecode(S(str), 0); testBadDecode(S(str), 1); } //Invalid UTF-8 sequence where the first code unit is valid. testBothDecode(S("\xEF\xBF\xBE"), cast(dchar)0xFFFE, 3); testBothDecode(S("\xEF\xBF\xBF"), cast(dchar)0xFFFF, 3); //Invalid UTF-8 sequence where the first code unit isn't valid. testBadDecode(S("\xED\xA0\x80"), 0); testBadDecode(S("\xED\xAD\xBF"), 0); testBadDecode(S("\xED\xAE\x80"), 0); testBadDecode(S("\xED\xAF\xBF"), 0); testBadDecode(S("\xED\xB0\x80"), 0); testBadDecode(S("\xED\xBE\x80"), 0); testBadDecode(S("\xED\xBF\xBF"), 0); } }); } unittest { import std.conv : to; import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(to!wstring, InputCU!wchar, RandomCU!wchar, (wstring s) => new RefBidirCU!wchar(s), (wstring s) => new RefRandomCU!wchar(s))) { testBothDecode(S([cast(wchar)0x1111]), cast(dchar)0x1111, 1); testBothDecode(S([cast(wchar)0xD800, cast(wchar)0xDC00]), cast(dchar)0x10000, 2); testBothDecode(S([cast(wchar)0xDBFF, cast(wchar)0xDFFF]), cast(dchar)0x10FFFF, 2); testBothDecode(S([cast(wchar)0xFFFE]), cast(dchar)0xFFFE, 1); testBothDecode(S([cast(wchar)0xFFFF]), cast(dchar)0xFFFF, 1); testBadDecode(S([ cast(wchar)0xD801 ]), 0); testBadDecode(S([ cast(wchar)0xD800, cast(wchar)0x1200 ]), 0); { auto range = S("ウェブサイト"); testDecode(range, 0, 'ウ', 1); testDecode(range, 1, 'ェ', 2); testDecodeFront(range, 'ウ', 1); testDecodeFront(range, 'ェ', 1); assert(decodeFront(range) == 'ブ'); assert(decodeFront(range) == 'サ'); } } foreach (S; AliasSeq!(to!wstring, RandomCU!wchar, (wstring s) => new RefRandomCU!wchar(s))) { auto str = S([cast(wchar)0xD800, cast(wchar)0xDC00, cast(wchar)0x1400, cast(wchar)0xDAA7, cast(wchar)0xDDDE]); testDecode(str, 0, cast(dchar)0x10000, 2); testDecode(str, 2, cast(dchar)0x1400, 3); testDecode(str, 3, cast(dchar)0xB9DDE, 5); } }); } unittest { import std.conv : to; import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(to!dstring, RandomCU!dchar, InputCU!dchar, (dstring s) => new RefBidirCU!dchar(s), (dstring s) => new RefRandomCU!dchar(s))) { testBothDecode(S([cast(dchar)0x1111]), cast(dchar)0x1111, 1); testBothDecode(S([cast(dchar)0x10000]), cast(dchar)0x10000, 1); testBothDecode(S([cast(dchar)0x10FFFF]), cast(dchar)0x10FFFF, 1); testBothDecode(S([cast(dchar)0xFFFE]), cast(dchar)0xFFFE, 1); testBothDecode(S([cast(dchar)0xFFFF]), cast(dchar)0xFFFF, 1); testBadDecode(S([cast(dchar)0xD800]), 0); testBadDecode(S([cast(dchar)0xDFFE]), 0); testBadDecode(S([cast(dchar)0x110000]), 0); { auto range = S("ウェブサイト"); testDecode(range, 0, 'ウ', 1); testDecode(range, 1, 'ェ', 2); testDecodeFront(range, 'ウ', 1); testDecodeFront(range, 'ェ', 1); assert(decodeFront(range) == 'ブ'); assert(decodeFront(range) == 'サ'); } } foreach (S; AliasSeq!(to!dstring, RandomCU!dchar, (dstring s) => new RefRandomCU!dchar(s))) { auto str = S([cast(dchar)0x10000, cast(dchar)0x1400, cast(dchar)0xB9DDE]); testDecode(str, 0, 0x10000, 1); testDecode(str, 1, 0x1400, 2); testDecode(str, 2, 0xB9DDE, 3); } }); } unittest { import std.exception; assertCTFEable!( { foreach (S; AliasSeq!( char[], const( char)[], string, wchar[], const(wchar)[], wstring, dchar[], const(dchar)[], dstring)) { static assert(isSafe!({ S str; size_t i = 0; decode(str, i); })); static assert(isSafe!({ S str; size_t i = 0; decodeFront(str, i); })); static assert(isSafe!({ S str; decodeFront(str); })); static assert((functionAttributes!({ S str; size_t i = 0; decode(str, i); }) & FunctionAttribute.pure_) != 0); static assert((functionAttributes!({ S str; size_t i = 0; decodeFront(str, i); }) & FunctionAttribute.pure_) != 0); static assert((functionAttributes!({ S str; decodeFront(str); }) & FunctionAttribute.pure_) != 0); } }); } unittest { import std.exception; char[4] val; val[0] = 0b1111_0111; val[1] = 0b1011_1111; val[2] = 0b1011_1111; val[3] = 0b1011_1111; size_t i = 0; assertThrown!UTFException((){ dchar ch = decode(val[], i); }()); } /* =================== Encode ======================= */ private dchar _utfException(UseReplacementDchar useReplacementDchar)(string msg, dchar c) { static if (useReplacementDchar) return replacementDchar; else throw new UTFException(msg).setSequence(c); } /++ Encodes $(D c) into the static array, $(D buf), and returns the actual length of the encoded character (a number between $(D 1) and $(D 4) for $(D char[4]) buffers and a number between $(D 1) and $(D 2) for $(D wchar[2]) buffers). Throws: $(D UTFException) if $(D c) is not a valid UTF code point. +/ size_t encode(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no)( ref char[4] buf, dchar c) @safe pure { if (c <= 0x7F) { assert(isValidDchar(c)); buf[0] = cast(char)c; return 1; } if (c <= 0x7FF) { assert(isValidDchar(c)); buf[0] = cast(char)(0xC0 | (c >> 6)); buf[1] = cast(char)(0x80 | (c & 0x3F)); return 2; } if (c <= 0xFFFF) { if (0xD800 <= c && c <= 0xDFFF) c = _utfException!useReplacementDchar("Encoding a surrogate code point in UTF-8", c); assert(isValidDchar(c)); L3: buf[0] = cast(char)(0xE0 | (c >> 12)); buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[2] = cast(char)(0x80 | (c & 0x3F)); return 3; } if (c <= 0x10FFFF) { assert(isValidDchar(c)); buf[0] = cast(char)(0xF0 | (c >> 18)); buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[3] = cast(char)(0x80 | (c & 0x3F)); return 4; } assert(!isValidDchar(c)); c = _utfException!useReplacementDchar("Encoding an invalid code point in UTF-8", c); goto L3; } unittest { import std.exception; assertCTFEable!( { char[4] buf; assert(encode(buf, '\u0000') == 1 && buf[0 .. 1] == "\u0000"); assert(encode(buf, '\u007F') == 1 && buf[0 .. 1] == "\u007F"); assert(encode(buf, '\u0080') == 2 && buf[0 .. 2] == "\u0080"); assert(encode(buf, '\u07FF') == 2 && buf[0 .. 2] == "\u07FF"); assert(encode(buf, '\u0800') == 3 && buf[0 .. 3] == "\u0800"); assert(encode(buf, '\uD7FF') == 3 && buf[0 .. 3] == "\uD7FF"); assert(encode(buf, '\uE000') == 3 && buf[0 .. 3] == "\uE000"); assert(encode(buf, 0xFFFE) == 3 && buf[0 .. 3] == "\xEF\xBF\xBE"); assert(encode(buf, 0xFFFF) == 3 && buf[0 .. 3] == "\xEF\xBF\xBF"); assert(encode(buf, '\U00010000') == 4 && buf[0 .. 4] == "\U00010000"); assert(encode(buf, '\U0010FFFF') == 4 && buf[0 .. 4] == "\U0010FFFF"); assertThrown!UTFException(encode(buf, cast(dchar)0xD800)); assertThrown!UTFException(encode(buf, cast(dchar)0xDBFF)); assertThrown!UTFException(encode(buf, cast(dchar)0xDC00)); assertThrown!UTFException(encode(buf, cast(dchar)0xDFFF)); assertThrown!UTFException(encode(buf, cast(dchar)0x110000)); assert(encode!(UseReplacementDchar.yes)(buf, cast(dchar)0x110000) == buf.stride); assert(buf.front == replacementDchar); }); } /// Ditto size_t encode(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no)( ref wchar[2] buf, dchar c) @safe pure { if (c <= 0xFFFF) { if (0xD800 <= c && c <= 0xDFFF) c = _utfException!useReplacementDchar("Encoding an isolated surrogate code point in UTF-16", c); assert(isValidDchar(c)); L1: buf[0] = cast(wchar)c; return 1; } if (c <= 0x10FFFF) { assert(isValidDchar(c)); buf[0] = cast(wchar)((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); buf[1] = cast(wchar)(((c - 0x10000) & 0x3FF) + 0xDC00); return 2; } c = _utfException!useReplacementDchar("Encoding an invalid code point in UTF-16", c); goto L1; } unittest { import std.exception; assertCTFEable!( { wchar[2] buf; assert(encode(buf, '\u0000') == 1 && buf[0 .. 1] == "\u0000"); assert(encode(buf, '\uD7FF') == 1 && buf[0 .. 1] == "\uD7FF"); assert(encode(buf, '\uE000') == 1 && buf[0 .. 1] == "\uE000"); assert(encode(buf, 0xFFFE) == 1 && buf[0] == 0xFFFE); assert(encode(buf, 0xFFFF) == 1 && buf[0] == 0xFFFF); assert(encode(buf, '\U00010000') == 2 && buf[0 .. 2] == "\U00010000"); assert(encode(buf, '\U0010FFFF') == 2 && buf[0 .. 2] == "\U0010FFFF"); assertThrown!UTFException(encode(buf, cast(dchar)0xD800)); assertThrown!UTFException(encode(buf, cast(dchar)0xDBFF)); assertThrown!UTFException(encode(buf, cast(dchar)0xDC00)); assertThrown!UTFException(encode(buf, cast(dchar)0xDFFF)); assertThrown!UTFException(encode(buf, cast(dchar)0x110000)); assert(encode!(UseReplacementDchar.yes)(buf, cast(dchar)0x110000) == buf.stride); assert(buf.front == replacementDchar); }); } /// Ditto size_t encode(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no)( ref dchar[1] buf, dchar c) @safe pure { if ((0xD800 <= c && c <= 0xDFFF) || 0x10FFFF < c) c = _utfException!useReplacementDchar("Encoding an invalid code point in UTF-32", c); else assert(isValidDchar(c)); buf[0] = c; return 1; } unittest { import std.exception; assertCTFEable!( { dchar[1] buf; encode(buf, '\u0000'); assert(buf[0] == '\u0000'); encode(buf, '\uD7FF'); assert(buf[0] == '\uD7FF'); encode(buf, '\uE000'); assert(buf[0] == '\uE000'); encode(buf, 0xFFFE ); assert(buf[0] == 0xFFFE); encode(buf, 0xFFFF ); assert(buf[0] == 0xFFFF); encode(buf, '\U0010FFFF'); assert(buf[0] == '\U0010FFFF'); assertThrown!UTFException(encode(buf, cast(dchar)0xD800)); assertThrown!UTFException(encode(buf, cast(dchar)0xDBFF)); assertThrown!UTFException(encode(buf, cast(dchar)0xDC00)); assertThrown!UTFException(encode(buf, cast(dchar)0xDFFF)); assertThrown!UTFException(encode(buf, cast(dchar)0x110000)); assert(encode!(UseReplacementDchar.yes)(buf, cast(dchar)0x110000) == buf.stride); assert(buf.front == replacementDchar); }); } /++ Encodes $(D c) in $(D str)'s encoding and appends it to $(D str). Throws: $(D UTFException) if $(D c) is not a valid UTF code point. +/ void encode(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no)( ref char[] str, dchar c) @safe pure { char[] r = str; if (c <= 0x7F) { assert(isValidDchar(c)); r ~= cast(char)c; } else { char[4] buf; uint L; if (c <= 0x7FF) { assert(isValidDchar(c)); buf[0] = cast(char)(0xC0 | (c >> 6)); buf[1] = cast(char)(0x80 | (c & 0x3F)); L = 2; } else if (c <= 0xFFFF) { if (0xD800 <= c && c <= 0xDFFF) c = _utfException!useReplacementDchar("Encoding a surrogate code point in UTF-8", c); assert(isValidDchar(c)); L3: buf[0] = cast(char)(0xE0 | (c >> 12)); buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[2] = cast(char)(0x80 | (c & 0x3F)); L = 3; } else if (c <= 0x10FFFF) { assert(isValidDchar(c)); buf[0] = cast(char)(0xF0 | (c >> 18)); buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[3] = cast(char)(0x80 | (c & 0x3F)); L = 4; } else { assert(!isValidDchar(c)); c = _utfException!useReplacementDchar("Encoding an invalid code point in UTF-8", c); goto L3; } r ~= buf[0 .. L]; } str = r; } unittest { import std.exception; debug(utf) printf("utf.encode.unittest\n"); assertCTFEable!( { char[] s = "abcd".dup; encode(s, cast(dchar)'a'); assert(s.length == 5); assert(s == "abcda"); encode(s, cast(dchar)'\u00A9'); assert(s.length == 7); assert(s == "abcda\xC2\xA9"); //assert(s == "abcda\u00A9"); // BUG: fix compiler encode(s, cast(dchar)'\u2260'); assert(s.length == 10); assert(s == "abcda\xC2\xA9\xE2\x89\xA0"); }); } unittest { import std.exception; assertCTFEable!( { char[] buf; encode(buf, '\u0000'); assert(buf[0 .. $] == "\u0000"); encode(buf, '\u007F'); assert(buf[1 .. $] == "\u007F"); encode(buf, '\u0080'); assert(buf[2 .. $] == "\u0080"); encode(buf, '\u07FF'); assert(buf[4 .. $] == "\u07FF"); encode(buf, '\u0800'); assert(buf[6 .. $] == "\u0800"); encode(buf, '\uD7FF'); assert(buf[9 .. $] == "\uD7FF"); encode(buf, '\uE000'); assert(buf[12 .. $] == "\uE000"); encode(buf, 0xFFFE); assert(buf[15 .. $] == "\xEF\xBF\xBE"); encode(buf, 0xFFFF); assert(buf[18 .. $] == "\xEF\xBF\xBF"); encode(buf, '\U00010000'); assert(buf[21 .. $] == "\U00010000"); encode(buf, '\U0010FFFF'); assert(buf[25 .. $] == "\U0010FFFF"); assertThrown!UTFException(encode(buf, cast(dchar)0xD800)); assertThrown!UTFException(encode(buf, cast(dchar)0xDBFF)); assertThrown!UTFException(encode(buf, cast(dchar)0xDC00)); assertThrown!UTFException(encode(buf, cast(dchar)0xDFFF)); assertThrown!UTFException(encode(buf, cast(dchar)0x110000)); assert(buf.back != replacementDchar); encode!(UseReplacementDchar.yes)(buf, cast(dchar)0x110000); assert(buf.back == replacementDchar); }); } /// ditto void encode(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no)( ref wchar[] str, dchar c) @safe pure { wchar[] r = str; if (c <= 0xFFFF) { if (0xD800 <= c && c <= 0xDFFF) c = _utfException!useReplacementDchar("Encoding an isolated surrogate code point in UTF-16", c); assert(isValidDchar(c)); L1: r ~= cast(wchar)c; } else if (c <= 0x10FFFF) { wchar[2] buf; assert(isValidDchar(c)); buf[0] = cast(wchar)((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); buf[1] = cast(wchar)(((c - 0x10000) & 0x3FF) + 0xDC00); r ~= buf; } else { assert(!isValidDchar(c)); c = _utfException!useReplacementDchar("Encoding an invalid code point in UTF-16", c); goto L1; } str = r; } unittest { import std.exception; assertCTFEable!( { wchar[] buf; encode(buf, '\u0000'); assert(buf[0] == '\u0000'); encode(buf, '\uD7FF'); assert(buf[1] == '\uD7FF'); encode(buf, '\uE000'); assert(buf[2] == '\uE000'); encode(buf, 0xFFFE); assert(buf[3] == 0xFFFE); encode(buf, 0xFFFF); assert(buf[4] == 0xFFFF); encode(buf, '\U00010000'); assert(buf[5 .. $] == "\U00010000"); encode(buf, '\U0010FFFF'); assert(buf[7 .. $] == "\U0010FFFF"); assertThrown!UTFException(encode(buf, cast(dchar)0xD800)); assertThrown!UTFException(encode(buf, cast(dchar)0xDBFF)); assertThrown!UTFException(encode(buf, cast(dchar)0xDC00)); assertThrown!UTFException(encode(buf, cast(dchar)0xDFFF)); assertThrown!UTFException(encode(buf, cast(dchar)0x110000)); assert(buf.back != replacementDchar); encode!(UseReplacementDchar.yes)(buf, cast(dchar)0x110000); assert(buf.back == replacementDchar); }); } /// ditto void encode(UseReplacementDchar useReplacementDchar = UseReplacementDchar.no)( ref dchar[] str, dchar c) @safe pure { if ((0xD800 <= c && c <= 0xDFFF) || 0x10FFFF < c) c = _utfException!useReplacementDchar("Encoding an invalid code point in UTF-32", c); else assert(isValidDchar(c)); str ~= c; } unittest { import std.exception; assertCTFEable!( { dchar[] buf; encode(buf, '\u0000'); assert(buf[0] == '\u0000'); encode(buf, '\uD7FF'); assert(buf[1] == '\uD7FF'); encode(buf, '\uE000'); assert(buf[2] == '\uE000'); encode(buf, 0xFFFE ); assert(buf[3] == 0xFFFE); encode(buf, 0xFFFF ); assert(buf[4] == 0xFFFF); encode(buf, '\U0010FFFF'); assert(buf[5] == '\U0010FFFF'); assertThrown!UTFException(encode(buf, cast(dchar)0xD800)); assertThrown!UTFException(encode(buf, cast(dchar)0xDBFF)); assertThrown!UTFException(encode(buf, cast(dchar)0xDC00)); assertThrown!UTFException(encode(buf, cast(dchar)0xDFFF)); assertThrown!UTFException(encode(buf, cast(dchar)0x110000)); assert(buf.back != replacementDchar); encode!(UseReplacementDchar.yes)(buf, cast(dchar)0x110000); assert(buf.back == replacementDchar); }); } /++ Returns the number of code units that are required to encode the code point $(D c) when $(D C) is the character type used to encode it. +/ ubyte codeLength(C)(dchar c) @safe pure nothrow @nogc if (isSomeChar!C) { static if (C.sizeof == 1) { if (c <= 0x7F) return 1; if (c <= 0x7FF) return 2; if (c <= 0xFFFF) return 3; if (c <= 0x10FFFF) return 4; assert(false); } else static if (C.sizeof == 2) { return c <= 0xFFFF ? 1 : 2; } else { static assert(C.sizeof == 4); return 1; } } /// pure nothrow @nogc unittest { assert(codeLength!char('a') == 1); assert(codeLength!wchar('a') == 1); assert(codeLength!dchar('a') == 1); assert(codeLength!char('\U0010FFFF') == 4); assert(codeLength!wchar('\U0010FFFF') == 2); assert(codeLength!dchar('\U0010FFFF') == 1); } /++ Returns the number of code units that are required to encode $(D str) in a string whose character type is $(D C). This is particularly useful when slicing one string with the length of another and the two string types use different character types. +/ size_t codeLength(C, InputRange)(InputRange input) if (isInputRange!InputRange && is(ElementType!InputRange : dchar)) { alias EncType = Unqual!(ElementEncodingType!InputRange); static if (isSomeString!InputRange && is(EncType == C) && is(typeof(input.length))) return input.length; else { size_t total = 0; foreach (dchar c; input) total += codeLength!C(c); return total; } } /// unittest { import std.conv : to; assert(codeLength!char("hello world") == to!string("hello world").length); assert(codeLength!wchar("hello world") == to!wstring("hello world").length); assert(codeLength!dchar("hello world") == to!dstring("hello world").length); assert(codeLength!char(`プログラミング`) == to!string(`プログラミング`).length); assert(codeLength!wchar(`プログラミング`) == to!wstring(`プログラミング`).length); assert(codeLength!dchar(`プログラミング`) == to!dstring(`プログラミング`).length); string haystack = `Être sans la verité, ça, ce ne serait pas bien.`; wstring needle = `Être sans la verité`; assert(haystack[codeLength!char(needle) .. $] == `, ça, ce ne serait pas bien.`); } unittest { import std.conv : to; import std.exception; import std.algorithm : filter; assertCTFEable!( { foreach (S; AliasSeq!( char[], const char[], string, wchar[], const wchar[], wstring, dchar[], const dchar[], dstring)) { foreach (C; AliasSeq!(char, wchar, dchar)) { assert(codeLength!C(to!S("Walter Bright")) == to!(C[])("Walter Bright").length); assert(codeLength!C(to!S(`言語`)) == to!(C[])(`言語`).length); assert(codeLength!C(to!S(`ウェブサイト@La_Verité.com`)) == to!(C[])(`ウェブサイト@La_Verité.com`).length); assert(codeLength!C(to!S(`ウェブサイト@La_Verité.com`).filter!(x => true)()) == to!(C[])(`ウェブサイト@La_Verité.com`).length); } } }); } /+ Internal helper function: Returns true if it is safe to search for the Codepoint $(D c) inside code units, without decoding. This is a runtime check that is used an optimization in various functions, particularly, in $(D std.string). +/ package bool canSearchInCodeUnits(C)(dchar c) if (isSomeChar!C) { static if (C.sizeof == 1) return c <= 0x7F; else static if (C.sizeof == 2) return c <= 0xD7FF || (0xE000 <= c && c <= 0xFFFF); else static if (C.sizeof == 4) return true; else static assert(0); } unittest { assert( canSearchInCodeUnits! char('a')); assert( canSearchInCodeUnits!wchar('a')); assert( canSearchInCodeUnits!dchar('a')); assert(!canSearchInCodeUnits! char('ö')); //Important test: ö <= 0xFF assert(!canSearchInCodeUnits! char(cast(char)'ö')); //Important test: ö <= 0xFF assert( canSearchInCodeUnits!wchar('ö')); assert( canSearchInCodeUnits!dchar('ö')); assert(!canSearchInCodeUnits! char('日')); assert( canSearchInCodeUnits!wchar('日')); assert( canSearchInCodeUnits!dchar('日')); assert(!canSearchInCodeUnits!wchar(cast(wchar)0xDA00)); assert( canSearchInCodeUnits!dchar(cast(dchar)0xDA00)); assert(!canSearchInCodeUnits! char('\U00010001')); assert(!canSearchInCodeUnits!wchar('\U00010001')); assert( canSearchInCodeUnits!dchar('\U00010001')); } /* =================== Validation ======================= */ /++ Checks to see if $(D str) is well-formed unicode or not. Throws: $(D UTFException) if $(D str) is not well-formed. +/ void validate(S)(in S str) @safe pure if (isSomeString!S) { immutable len = str.length; for (size_t i = 0; i < len; ) { decode(str, i); } } unittest // bugzilla 12923 { import std.exception; assertThrown((){ char[3]a=[167, 133, 175]; validate(a[]); }()); } /* =================== Conversion to UTF8 ======================= */ pure { char[] toUTF8(return out char[4] buf, dchar c) nothrow @nogc @safe { if (c <= 0x7F) { buf[0] = cast(char)c; return buf[0 .. 1]; } else if (c <= 0x7FF) { buf[0] = cast(char)(0xC0 | (c >> 6)); buf[1] = cast(char)(0x80 | (c & 0x3F)); return buf[0 .. 2]; } else if (c <= 0xFFFF) { if (c >= 0xD800 && c <= 0xDFFF) c = replacementDchar; L3: buf[0] = cast(char)(0xE0 | (c >> 12)); buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[2] = cast(char)(0x80 | (c & 0x3F)); return buf[0 .. 3]; } else { if (c > 0x10FFFF) { c = replacementDchar; goto L3; } buf[0] = cast(char)(0xF0 | (c >> 18)); buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[3] = cast(char)(0x80 | (c & 0x3F)); return buf[0 .. 4]; } } /******************* * Encodes string $(D_PARAM s) into UTF-8 and returns the encoded string. */ string toUTF8(in char[] s) @safe { validate(s); return s.idup; } /// ditto string toUTF8(in wchar[] s) @safe { char[] r; size_t i; size_t slen = s.length; r.length = slen; for (i = 0; i < slen; i++) { wchar c = s[i]; if (c <= 0x7F) r[i] = cast(char)c; // fast path for ascii else { r.length = i; while (i < slen) encode(r, decode(s, i)); break; } } return r; } /// ditto string toUTF8(in dchar[] s) @safe { char[] r; size_t i; size_t slen = s.length; r.length = slen; for (i = 0; i < slen; i++) { dchar c = s[i]; if (c <= 0x7F) r[i] = cast(char)c; // fast path for ascii else { r.length = i; foreach (dchar d; s[i .. slen]) { encode(r, d); } break; } } return r; } /* =================== Conversion to UTF16 ======================= */ wchar[] toUTF16(return ref wchar[2] buf, dchar c) nothrow @nogc @safe in { assert(isValidDchar(c)); } body { if (c <= 0xFFFF) { buf[0] = cast(wchar)c; return buf[0 .. 1]; } else { buf[0] = cast(wchar)((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); buf[1] = cast(wchar)(((c - 0x10000) & 0x3FF) + 0xDC00); return buf[0 .. 2]; } } /**************** * Encodes string $(D s) into UTF-16 and returns the encoded string. */ wstring toUTF16(in char[] s) @safe { wchar[] r; size_t slen = s.length; r.length = slen; r.length = 0; for (size_t i = 0; i < slen; ) { dchar c = s[i]; if (c <= 0x7F) { i++; r ~= cast(wchar)c; } else { c = decode(s, i); encode(r, c); } } return r; } /// ditto wstring toUTF16(in wchar[] s) @safe { validate(s); return s.idup; } /// ditto wstring toUTF16(in dchar[] s) @safe { wchar[] r; size_t slen = s.length; r.length = slen; r.length = 0; for (size_t i = 0; i < slen; i++) { encode(r, s[i]); } return r; } /* =================== Conversion to UTF32 ======================= */ /***** * Encodes string $(D_PARAM s) into UTF-32 and returns the encoded string. */ dstring toUTF32(in char[] s) @safe { dchar[] r; size_t slen = s.length; size_t j = 0; r.length = slen; // r[] will never be longer than s[] for (size_t i = 0; i < slen; ) { dchar c = s[i]; if (c >= 0x80) c = decode(s, i); else i++; // c is ascii, no need for decode r[j++] = c; } return r[0 .. j]; } /// ditto dstring toUTF32(in wchar[] s) @safe { dchar[] r; size_t slen = s.length; size_t j = 0; r.length = slen; // r[] will never be longer than s[] for (size_t i = 0; i < slen; ) { dchar c = s[i]; if (c >= 0x80) c = decode(s, i); else i++; // c is ascii, no need for decode r[j++] = c; } return r[0 .. j]; } /// ditto dstring toUTF32(in dchar[] s) @safe { validate(s); return s.idup; } } // Convert functions are @safe /* =================== toUTFz ======================= */ /++ Returns a C-style zero-terminated string equivalent to $(D str). $(D str) must not contain embedded $(D '\0')'s as any C function will treat the first $(D '\0') that it sees as the end of the string. If $(D str.empty) is $(D true), then a string containing only $(D '\0') is returned. $(D toUTFz) accepts any type of string and is templated on the type of character pointer that you wish to convert to. It will avoid allocating a new string if it can, but there's a decent chance that it will end up having to allocate a new string - particularly when dealing with character types other than $(D char). $(RED Warning 1:) If the result of $(D toUTFz) equals $(D str.ptr), then if anything alters the character one past the end of $(D str) (which is the $(D '\0') character terminating the string), then the string won't be zero-terminated anymore. The most likely scenarios for that are if you append to $(D str) and no reallocation takes place or when $(D str) is a slice of a larger array, and you alter the character in the larger array which is one character past the end of $(D str). Another case where it could occur would be if you had a mutable character array immediately after $(D str) in memory (for example, if they're member variables in a user-defined type with one declared right after the other) and that character array happened to start with $(D '\0'). Such scenarios will never occur if you immediately use the zero-terminated string after calling $(D toUTFz) and the C function using it doesn't keep a reference to it. Also, they are unlikely to occur even if you save the zero-terminated string (the cases above would be among the few examples of where it could happen). However, if you save the zero-terminate string and want to be absolutely certain that the string stays zero-terminated, then simply append a $(D '\0') to the string and use its $(D ptr) property rather than calling $(D toUTFz). $(RED Warning 2:) When passing a character pointer to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may go away during a garbage collection cycle and cause a nasty bug when the C code tries to use it. +/ template toUTFz(P) { P toUTFz(S)(S str) @safe pure { return toUTFzImpl!(P, S)(str); } } /// @safe pure unittest { auto p1 = toUTFz!(char*)("hello world"); auto p2 = toUTFz!(const(char)*)("hello world"); auto p3 = toUTFz!(immutable(char)*)("hello world"); auto p4 = toUTFz!(char*)("hello world"d); auto p5 = toUTFz!(const(wchar)*)("hello world"); auto p6 = toUTFz!(immutable(dchar)*)("hello world"w); } private P toUTFzImpl(P, S)(S str) @safe pure if (isSomeString!S && isPointer!P && isSomeChar!(typeof(*P.init)) && is(Unqual!(typeof(*P.init)) == Unqual!(ElementEncodingType!S)) && is(immutable(Unqual!(ElementEncodingType!S)) == ElementEncodingType!S)) //immutable(C)[] -> C*, const(C)*, or immutable(C)* { if (str.empty) { typeof(*P.init)[] retval = ['\0']; return retval.ptr; } alias C = Unqual!(ElementEncodingType!S); //If the P is mutable, then we have to make a copy. static if (is(Unqual!(typeof(*P.init)) == typeof(*P.init))) { return toUTFzImpl!(P, const(C)[])(cast(const(C)[])str); } else { if (!__ctfe) { auto trustedPtrAdd(S s) @trusted { return s.ptr + s.length; } immutable p = trustedPtrAdd(str); // Peek past end of str, if it's 0, no conversion necessary. // Note that the compiler will put a 0 past the end of static // strings, and the storage allocator will put a 0 past the end // of newly allocated char[]'s. // Is p dereferenceable? A simple test: if the p points to an // address multiple of 4, then conservatively assume the pointer // might be pointing to a new block of memory, which might be // unreadable. Otherwise, it's definitely pointing to valid // memory. if ((cast(size_t)p & 3) && *p == '\0') return str.ptr; } return toUTFzImpl!(P, const(C)[])(cast(const(C)[])str); } } private P toUTFzImpl(P, S)(S str) @safe pure if (isSomeString!S && isPointer!P && isSomeChar!(typeof(*P.init)) && is(Unqual!(typeof(*P.init)) == Unqual!(ElementEncodingType!S)) && !is(immutable(Unqual!(ElementEncodingType!S)) == ElementEncodingType!S)) //C[] or const(C)[] -> C*, const(C)*, or immutable(C)* { alias InChar = ElementEncodingType!S; alias OutChar = typeof(*P.init); //const(C)[] -> const(C)* or //C[] -> C* or const(C)* static if (( is(const(Unqual!InChar) == InChar) && is(const(Unqual!OutChar) == OutChar)) || (!is(const(Unqual!InChar) == InChar) && !is(immutable(Unqual!OutChar) == OutChar))) { if (!__ctfe) { auto trustedPtrAdd(S s) @trusted { return s.ptr + s.length; } auto p = trustedPtrAdd(str); if ((cast(size_t)p & 3) && *p == '\0') return str.ptr; } str ~= '\0'; return str.ptr; } //const(C)[] -> C* or immutable(C)* or //C[] -> immutable(C)* else { import std.array : uninitializedArray; auto copy = uninitializedArray!(Unqual!OutChar[])(str.length + 1); copy[0 .. $ - 1] = str[]; copy[$ - 1] = '\0'; auto trustedCast(typeof(copy) c) @trusted { return cast(P)c.ptr; } return trustedCast(copy); } } private P toUTFzImpl(P, S)(S str) @safe pure if (isSomeString!S && isPointer!P && isSomeChar!(typeof(*P.init)) && !is(Unqual!(typeof(*P.init)) == Unqual!(ElementEncodingType!S))) //C1[], const(C1)[], or immutable(C1)[] -> C2*, const(C2)*, or immutable(C2)* { import std.array : appender; auto retval = appender!(typeof(*P.init)[])(); foreach (dchar c; str) retval.put(c); retval.put('\0'); return cast(P)retval.data.ptr; } @safe pure unittest { import std.conv : to; import std.exception; import std.string : format; import core.exception : AssertError; import std.algorithm; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { alias C = Unqual!(ElementEncodingType!S); auto s1 = to!S("hello\U00010143\u0100\U00010143"); auto temp = new C[](s1.length + 1); temp[0 .. $ - 1] = s1[0 .. $]; temp[$ - 1] = '\n'; --temp.length; auto trustedAssumeUnique(T)(T t) @trusted { return assumeUnique(t); } auto s2 = trustedAssumeUnique(temp); assert(s1 == s2); void trustedCStringAssert(P, S)(S s) @trusted { auto p = toUTFz!P(s); assert(p[0 .. s.length] == s); assert(p[s.length] == '\0'); } foreach (P; AliasSeq!(C*, const(C)*, immutable(C)*)) { trustedCStringAssert!P(s1); trustedCStringAssert!P(s2); } } }); static void test(P, S)(S s, size_t line = __LINE__) @trusted { static size_t zeroLen(C)(const(C)* ptr) @trusted { size_t len = 0; while (*ptr != '\0') { ++ptr; ++len; } return len; } auto p = toUTFz!P(s); immutable len = zeroLen(p); enforce(cmp(s, p[0 .. len]) == 0, new AssertError(format("Unit test failed: %s %s", P.stringof, S.stringof), __FILE__, line)); } assertCTFEable!( { foreach (P; AliasSeq!(wchar*, const(wchar)*, immutable(wchar)*, dchar*, const(dchar)*, immutable(dchar)*)) { test!P("hello\U00010143\u0100\U00010143"); } foreach (P; AliasSeq!( char*, const( char)*, immutable( char)*, dchar*, const(dchar)*, immutable(dchar)*)) { test!P("hello\U00010143\u0100\U00010143"w); } foreach (P; AliasSeq!( char*, const( char)*, immutable( char)*, wchar*, const(wchar)*, immutable(wchar)*)) { test!P("hello\U00010143\u0100\U00010143"d); } foreach (S; AliasSeq!( char[], const( char)[], wchar[], const(wchar)[], dchar[], const(dchar)[])) { auto s = to!S("hello\U00010143\u0100\U00010143"); foreach (P; AliasSeq!( char*, const( char)*, immutable( char)*, wchar*, const(wchar)*, immutable(wchar)*, dchar*, const(dchar)*, immutable(dchar)*)) { test!P(s); } } }); } /++ $(D toUTF16z) is a convenience function for $(D toUTFz!(const(wchar)*)). Encodes string $(D s) into UTF-16 and returns the encoded string. $(D toUTF16z) is suitable for calling the 'W' functions in the Win32 API that take an $(D LPWSTR) or $(D LPCWSTR) argument. +/ const(wchar)* toUTF16z(C)(const(C)[] str) @safe pure if (isSomeChar!C) { return toUTFz!(const(wchar)*)(str); } @safe pure unittest { import std.conv : to; //toUTFz is already thoroughly tested, so this will just verify that //toUTF16z compiles properly for the various string types. foreach (S; AliasSeq!(string, wstring, dstring)) assert(toUTF16z(to!S("hello world")) !is null); } /* ================================ tests ================================== */ pure unittest { import std.exception; debug(utf) printf("utf.toUTF.unittest\n"); assertCTFEable!( { assert(toUTF16("hello"c) == "hello"); assert(toUTF32("hello"c) == "hello"); assert(toUTF8 ("hello"w) == "hello"); assert(toUTF32("hello"w) == "hello"); assert(toUTF8 ("hello"d) == "hello"); assert(toUTF16("hello"d) == "hello"); assert(toUTF16("hel\u1234o"c) == "hel\u1234o"); assert(toUTF32("hel\u1234o"c) == "hel\u1234o"); assert(toUTF8 ("hel\u1234o"w) == "hel\u1234o"); assert(toUTF32("hel\u1234o"w) == "hel\u1234o"); assert(toUTF8 ("hel\u1234o"d) == "hel\u1234o"); assert(toUTF16("hel\u1234o"d) == "hel\u1234o"); assert(toUTF16("he\U0010AAAAllo"c) == "he\U0010AAAAllo"); assert(toUTF32("he\U0010AAAAllo"c) == "he\U0010AAAAllo"); assert(toUTF8 ("he\U0010AAAAllo"w) == "he\U0010AAAAllo"); assert(toUTF32("he\U0010AAAAllo"w) == "he\U0010AAAAllo"); assert(toUTF8 ("he\U0010AAAAllo"d) == "he\U0010AAAAllo"); assert(toUTF16("he\U0010AAAAllo"d) == "he\U0010AAAAllo"); }); } /++ Returns the total number of code points encoded in $(D str). Supercedes: This function supercedes $(LREF toUCSindex). Standards: Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252 Throws: $(D UTFException) if $(D str) is not well-formed. +/ size_t count(C)(const(C)[] str) @trusted pure nothrow @nogc if (isSomeChar!C) { return walkLength(str); } pure nothrow @nogc unittest { import std.exception; assertCTFEable!( { assert(count("") == 0); assert(count("a") == 1); assert(count("abc") == 3); assert(count("\u20AC100") == 4); }); } // Ranges of code units for testing. version(unittest) { struct InputCU(C) { import std.conv : to; @property bool empty() { return _str.empty; } @property C front() { return _str[0]; } void popFront() { _str = _str[1 .. $]; } this(inout(C)[] str) { _str = to!(C[])(str); } C[] _str; } struct BidirCU(C) { import std.conv : to; @property bool empty() { return _str.empty; } @property C front() { return _str[0]; } void popFront() { _str = _str[1 .. $]; } @property C back() { return _str[$ - 1]; } void popBack() { _str = _str[0 .. $ - 1]; } @property auto save() { return BidirCU(_str); } @property size_t length() { return _str.length; } this(inout(C)[] str) { _str = to!(C[])(str); } C[] _str; } struct RandomCU(C) { import std.conv : to; @property bool empty() { return _str.empty; } @property C front() { return _str[0]; } void popFront() { _str = _str[1 .. $]; } @property C back() { return _str[$ - 1]; } void popBack() { _str = _str[0 .. $ - 1]; } @property auto save() { return RandomCU(_str); } @property size_t length() { return _str.length; } C opIndex(size_t i) { return _str[i]; } auto opSlice(size_t i, size_t j) { return RandomCU(_str[i .. j]); } this(inout(C)[] str) { _str = to!(C[])(str); } C[] _str; } class RefBidirCU(C) { import std.conv : to; @property bool empty() { return _str.empty; } @property C front() { return _str[0]; } void popFront() { _str = _str[1 .. $]; } @property C back() { return _str[$ - 1]; } void popBack() { _str = _str[0 .. $ - 1]; } @property auto save() { return new RefBidirCU(_str); } @property size_t length() { return _str.length; } this(inout(C)[] str) { _str = to!(C[])(str); } C[] _str; } class RefRandomCU(C) { import std.conv : to; @property bool empty() { return _str.empty; } @property C front() { return _str[0]; } void popFront() { _str = _str[1 .. $]; } @property C back() { return _str[$ - 1]; } void popBack() { _str = _str[0 .. $ - 1]; } @property auto save() { return new RefRandomCU(_str); } @property size_t length() { return _str.length; } C opIndex(size_t i) { return _str[i]; } auto opSlice(size_t i, size_t j) { return new RefRandomCU(_str[i .. j]); } this(inout(C)[] str) { _str = to!(C[])(str); } C[] _str; } } /** * Inserted in place of invalid UTF sequences. * * References: * $(LINK http://en.wikipedia.org/wiki/Replacement_character#Replacement_character) */ enum dchar replacementDchar = '\uFFFD'; /******************************************** * Iterate a range of char, wchar, or dchars by code unit. * * The purpose is to bypass the special case decoding that * $(XREF array,front) does to character arrays. * Params: * r = input range of characters, or array of characters * Returns: * input range */ auto byCodeUnit(R)(R r) if (isAutodecodableString!R) { /* Turn an array into an InputRange. */ static struct ByCodeUnitImpl { pure nothrow @nogc: @property bool empty() const { return r.length == 0; } @property auto ref front() inout { return r[0]; } void popFront() { r = r[1 .. $]; } auto ref opIndex(size_t index) inout { return r[index]; } @property auto ref back() inout { return r[$ - 1]; } void popBack() { r = r[0 .. $-1]; } static if (!isAggregateType!R) { auto opSlice(size_t lower, size_t upper) { return ByCodeUnitImpl(r[lower..upper]); } } @property size_t length() const { return r.length; } alias opDollar = length; static if (!isAggregateType!R) { @property auto save() { return ByCodeUnitImpl(r.save); } } private: R r; } static assert(isAggregateType!R || isRandomAccessRange!ByCodeUnitImpl); return ByCodeUnitImpl(r); } /// Ditto auto ref byCodeUnit(R)(R r) if (!isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R)) { // byCodeUnit for ranges and dchar[] is a no-op return r; } pure nothrow @nogc unittest { import std.range; { char[5] s; int i; foreach (c; "hello".byCodeUnit().byCodeUnit()) { s[i++] = c; } assert(s == "hello"); } { wchar[5] s; int i; foreach (c; "hello"w.byCodeUnit().byCodeUnit()) { s[i++] = c; } assert(s == "hello"w); } { dchar[5] s; int i; foreach (c; "hello"d.byCodeUnit().byCodeUnit()) { s[i++] = c; } assert(s == "hello"d); } { auto r = "hello".byCodeUnit(); assert(r.length == 5); assert(r[3] == 'l'); assert(r[2..4][1] == 'l'); } { char[5] buff = "hello"; auto s = buff[].byCodeUnit(); s.front = 'H'; assert(s.front == 'H'); s[1] = 'E'; assert(s[1] == 'E'); } { auto r = "hello".byCodeUnit().byCodeUnit(); static assert(isForwardRange!(typeof(r))); auto s = r.save; r.popFront(); assert(s.front == 'h'); } { auto r = "hello".byCodeUnit(); static assert(hasSlicing!(typeof(r))); static assert(isBidirectionalRange!(typeof(r))); auto ret = r.retro; assert(ret.front == 'o'); ret.popFront(); assert(ret.front == 'l'); } { auto r = "κόσμε"w.byCodeUnit(); static assert(hasSlicing!(typeof(r))); static assert(isBidirectionalRange!(typeof(r))); auto ret = r.retro; assert(ret.front == 'ε'); ret.popFront(); assert(ret.front == 'μ'); } { static struct Stringish { string s; alias s this; } auto fn = Stringish("test.d"); auto x = fn.byCodeUnit(); assert(x.front == 't'); } } /**************************** * Iterate an input range of characters by char, wchar, or dchar. * These aliases simply forward to $(LREF byUTF) with the * corresponding C argument. * * Params: * r = input range of characters, or array of characters */ alias byChar = byUTF!char; /// Ditto alias byWchar = byUTF!wchar; /// Ditto alias byDchar = byUTF!dchar; pure nothrow @nogc unittest { { char[5] s; int i; foreach (c; "hello".byChar.byChar()) { //writefln("[%d] '%c'", i, c); s[i++] = c; } assert(s == "hello"); } { char[5+2+3+4+3+3] s; int i; dchar[10] a; a[0..8] = "hello\u07FF\uD7FF\U0010FFFF"d; a[8] = 0xD800; // invalid a[9] = cast(dchar)0x110000; // invalid foreach (c; a[].byChar()) { //writefln("[%d] '%c'", i, c); s[i++] = c; } assert(s == "hello\u07FF\uD7FF\U0010FFFF\uFFFD\uFFFD"); } { auto r = "hello"w.byChar(); r.popFront(); r.popFront(); assert(r.front == 'l'); } { auto r = "hello"d.byChar(); r.popFront(); r.popFront(); assert(r.front == 'l'); } { auto r = "hello"d.byChar(); assert(isForwardRange!(typeof(r))); auto s = r.save; r.popFront(); assert(s.front == 'h'); } } pure nothrow @nogc unittest { { wchar[11] s; int i; dchar[10] a; a[0..8] = "hello\u07FF\uD7FF\U0010FFFF"d; a[8] = 0xD800; // invalid a[9] = cast(dchar)0x110000; // invalid foreach (c; a[].byWchar()) { //writefln("[%d] '%c' x%x", i, c, c); s[i++] = c; } foreach (j, wchar c; "hello\u07FF\uD7FF\U0010FFFF\uFFFD\uFFFD"w) { //writefln("[%d] '%c' x%x", j, c, c); } assert(s == "hello\u07FF\uD7FF\U0010FFFF\uFFFD\uFFFD"w); } { auto r = "hello".byWchar(); r.popFront(); r.popFront(); assert(r.front == 'l'); } { auto r = "hello"d.byWchar(); r.popFront(); r.popFront(); assert(r.front == 'l'); } { auto r = "hello"d.byWchar(); assert(isForwardRange!(typeof(r))); auto s = r.save; r.popFront(); assert(s.front == 'h'); } } pure nothrow @nogc unittest { { dchar[9] s; int i; string a = "hello\u07FF\uD7FF\U00010000\U0010FFFF"; // 1,2,3,4 byte sequences foreach (c; a.byDchar()) { s[i++] = c; } assert(s == "hello\u07FF\uD7FF\U00010000\U0010FFFF"d); } { foreach (s; invalidUTFstrings!char()) { auto r = s.byDchar(); assert(!r.empty); assert(r.front == r.front); dchar c = r.front; assert(c == replacementDchar); } } { auto r = "hello".byDchar(); r.popFront(); r.popFront(); assert(r.front == 'l'); } { dchar[8] s; int i; wstring a = "hello\u07FF\uD7FF\U0010FFFF"w; foreach (c; a.byDchar()) { //writefln("[%d] '%c' x%x", i, c, c); s[i++] = c; } assert(s == "hello\u07FF\uD7FF\U0010FFFF"d); } { foreach (s; invalidUTFstrings!wchar()) { auto r = s.byDchar(); assert(!r.empty); assert(r.front == r.front); dchar c = r.front; assert(c == replacementDchar); } } { wchar[2] ws; ws[0] = 0xD800; ws[1] = 0xDD00; // correct surrogate pair auto r = ws[].byDchar(); assert(!r.empty); assert(r.front == r.front); dchar c = r.front; assert(c == '\U00010100'); } { auto r = "hello"w.byDchar(); r.popFront(); r.popFront(); assert(r.front == 'l'); } { dchar[5] s; int i; dstring a = "hello"d; foreach (c; a.byDchar.byDchar()) { //writefln("[%d] '%c' x%x", i, c, c); s[i++] = c; } assert(s == "hello"d); } { auto r = "hello".byDchar(); assert(isForwardRange!(typeof(r))); auto s = r.save; r.popFront(); assert(s.front == 'h'); } { auto r = "hello"w.byDchar(); assert(isForwardRange!(typeof(r))); auto s = r.save; r.popFront(); assert(s.front == 'h'); } } // test pure, @safe, nothrow, @nogc correctness of byChar/byWchar/byDchar, // which needs to support ranges with and without those attributes pure @safe nothrow @nogc unittest { dchar[5] s = "hello"d; foreach (c; s[].byChar()) { } foreach (c; s[].byWchar()) { } foreach (c; s[].byDchar()) { } } version(unittest) int impureVariable; @system unittest { static struct ImpureThrowingSystemRange(Char) { @property bool empty() const { return true; } @property Char front() const { return Char.init; } void popFront() { impureVariable++; throw new Exception("only for testing nothrow"); } } foreach (Char; AliasSeq!(char, wchar, dchar)) { ImpureThrowingSystemRange!Char range; foreach (c; range.byChar()) { } foreach (c; range.byWchar()) { } foreach (c; range.byDchar()) { } } } /**************************** * Iterate an input range of characters by char type C. * * UTF sequences that cannot be converted to UTF-8 are replaced by U+FFFD * per "5.22 Best Practice for U+FFFD Substitution" of the Unicode Standard 6.2. * Hence byUTF is not symmetric. * This algorithm is lazy, and does not allocate memory. * Purity, nothrow, and safety are inferred from the r parameter. * * Params: * C = char, wchar, or dchar * r = input range of characters, or array of characters * Returns: * input range of type C */ template byUTF(C) if (isSomeChar!C) { static if (!is(Unqual!C == C)) alias byUTF = byUTF!(Unqual!C); else: auto ref byUTF(R)(R r) if (isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R)) { return byUTF(r.byCodeUnit()); } auto ref byUTF(R)(R r) if (!isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R)) { alias RC = Unqual!(ElementEncodingType!R); static if (is(RC == C)) { return r.byCodeUnit(); } else { static struct Result { this(ref R r) { this.r = r; } @property bool empty() { return pos == fill && r.empty; } @property auto front() { if (pos == fill) { pos = 0; fill = cast(ushort)encode!(UseReplacementDchar.yes)( buf, decodeFront!(UseReplacementDchar.yes)(r)); } return buf[pos]; } void popFront() { if (pos == fill) front; ++pos; } static if (isForwardRange!R) { @property auto save() { auto ret = this; ret.r = r.save; return ret; } } private: R r; C[4 / C.sizeof] buf = void; ushort pos, fill; } return Result(r); } } } /// @safe pure nothrow @nogc unittest { foreach (c; "h".byUTF!char()) assert(c == 'h'); foreach (c; "h".byUTF!wchar()) assert(c == 'h'); foreach (c; "h".byUTF!dchar()) assert(c == 'h'); } ldc-1.1.0-beta3-src/runtime/phobos/std/mathspecial.d0000664000175000017500000002343512776215007020354 0ustar kaikai// Written in the D programming language. /** * Mathematical Special Functions * * The technical term 'Special Functions' includes several families of * transcendental functions, which have important applications in particular * branches of mathematics and physics. * * The gamma and related functions, and the error function are crucial for * mathematical statistics. * The Bessel and related functions arise in problems involving wave propagation * (especially in optics). * Other major categories of special functions include the elliptic integrals * (related to the arc length of an ellipse), and the hypergeometric functions. * * Status: * Many more functions will be added to this module. * The naming convention for the distribution functions (gammaIncomplete, etc) * is not yet finalized and will probably change. * * Macros: * WIKI = Phobos/StdMathSpecial * * TABLE_SV = * * $0
Special Values
* SVH = $(TR $(TH $1) $(TH $2)) * SV = $(TR $(TD $1) $(TD $2)) * * NAN = $(RED NAN) * SUP = $0 * GAMMA = Γ * THETA = θ * INTEGRAL = ∫ * INTEGRATE = $(BIG ∫$(SMALL $1)$2) * POWER = $1$2 * SUB = $1$2 * BIGSUM = $(BIG Σ $2$(SMALL $1)) * CHOOSE = $(BIG () $(SMALL $1)$(SMALL $2) $(BIG )) * PLUSMN = ± * INFIN = ∞ * PLUSMNINF = ±∞ * PI = π * LT = < * GT = > * SQRT = √ * HALF = ½ * * * Copyright: Based on the CEPHES math library, which is * Copyright (C) 1994 Stephen L. Moshier (moshier@world.std.com). * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Stephen L. Moshier (original C code). Conversion to D by Don Clugston * Source: $(PHOBOSSRC std/_mathspecial.d) */ module std.mathspecial; public import std.math; private import std.internal.math.gammafunction; private import std.internal.math.errorfunction; /* *********************************************** * GAMMA AND RELATED FUNCTIONS * * ***********************************************/ pure: nothrow: @safe: @nogc: /** The Gamma function, $(GAMMA)(x) * * $(GAMMA)(x) is a generalisation of the factorial function * to real and complex numbers. * Like x!, $(GAMMA)(x+1) = x * $(GAMMA)(x). * * Mathematically, if z.re > 0 then * $(GAMMA)(z) = $(INTEGRATE 0, $(INFIN)) $(POWER t, z-1)$(POWER e, -t) dt * * $(TABLE_SV * $(SVH x, $(GAMMA)(x) ) * $(SV $(NAN), $(NAN) ) * $(SV $(PLUSMN)0.0, $(PLUSMNINF)) * $(SV integer > 0, (x-1)! ) * $(SV integer < 0, $(NAN) ) * $(SV +$(INFIN), +$(INFIN) ) * $(SV -$(INFIN), $(NAN) ) * ) */ real gamma(real x) { return std.internal.math.gammafunction.gamma(x); } /** Natural logarithm of the gamma function, $(GAMMA)(x) * * Returns the base e (2.718...) logarithm of the absolute * value of the gamma function of the argument. * * For reals, logGamma is equivalent to log(fabs(gamma(x))). * * $(TABLE_SV * $(SVH x, logGamma(x) ) * $(SV $(NAN), $(NAN) ) * $(SV integer <= 0, +$(INFIN) ) * $(SV $(PLUSMNINF), +$(INFIN) ) * ) */ real logGamma(real x) { return std.internal.math.gammafunction.logGamma(x); } /** The sign of $(GAMMA)(x). * * Returns -1 if $(GAMMA)(x) < 0, +1 if $(GAMMA)(x) > 0, * $(NAN) if sign is indeterminate. * * Note that this function can be used in conjunction with logGamma(x) to * evaluate gamma for very large values of x. */ real sgnGamma(real x) { /* Author: Don Clugston. */ if (isNaN(x)) return x; if (x > 0) return 1.0; if (x < -1/real.epsilon) { // Large negatives lose all precision return real.nan; } long n = rndtol(x); if (x == n) { return x == 0 ? copysign(1, x) : real.nan; } return n & 1 ? 1.0 : -1.0; } unittest { assert(sgnGamma(5.0) == 1.0); assert(isNaN(sgnGamma(-3.0))); assert(sgnGamma(-0.1) == -1.0); assert(sgnGamma(-55.1) == 1.0); assert(isNaN(sgnGamma(-real.infinity))); assert(isIdentical(sgnGamma(NaN(0xABC)), NaN(0xABC))); } /** Beta function * * The beta function is defined as * * beta(x, y) = ($(GAMMA)(x) * $(GAMMA)(y)) / $(GAMMA)(x + y) */ real beta(real x, real y) { if ((x+y)> MAXGAMMA) { return exp(logGamma(x) + logGamma(y) - logGamma(x+y)); } else return gamma(x) * gamma(y) / gamma(x+y); } unittest { assert(isIdentical(beta(NaN(0xABC), 4), NaN(0xABC))); assert(isIdentical(beta(2, NaN(0xABC)), NaN(0xABC))); } /** Digamma function * * The digamma function is the logarithmic derivative of the gamma function. * * digamma(x) = d/dx logGamma(x) * * See_Also: $(LREF logmdigamma), $(LREF logmdigammaInverse). */ real digamma(real x) { return std.internal.math.gammafunction.digamma(x); } /** Log Minus Digamma function * * logmdigamma(x) = log(x) - digamma(x) * * See_Also: $(LREF digamma), $(LREF logmdigammaInverse). */ real logmdigamma(real x) { return std.internal.math.gammafunction.logmdigamma(x); } /** Inverse of the Log Minus Digamma function * * Given y, the function finds x such log(x) - digamma(x) = y. * * See_Also: $(LREF logmdigamma), $(LREF digamma). */ real logmdigammaInverse(real x) { return std.internal.math.gammafunction.logmdigammaInverse(x); } /** Incomplete beta integral * * Returns incomplete beta integral of the arguments, evaluated * from zero to x. The regularized incomplete beta function is defined as * * betaIncomplete(a, b, x) = $(GAMMA)(a + b) / ( $(GAMMA)(a) $(GAMMA)(b) ) * * $(INTEGRATE 0, x) $(POWER t, a-1)$(POWER (1-t), b-1) dt * * and is the same as the the cumulative distribution function. * * The domain of definition is 0 <= x <= 1. In this * implementation a and b are restricted to positive values. * The integral from x to 1 may be obtained by the symmetry * relation * * betaIncompleteCompl(a, b, x ) = betaIncomplete( b, a, 1-x ) * * The integral is evaluated by a continued fraction expansion * or, when b * x is small, by a power series. */ real betaIncomplete(real a, real b, real x ) { return std.internal.math.gammafunction.betaIncomplete(a, b, x); } /** Inverse of incomplete beta integral * * Given y, the function finds x such that * * betaIncomplete(a, b, x) == y * * Newton iterations or interval halving is used. */ real betaIncompleteInverse(real a, real b, real y ) { return std.internal.math.gammafunction.betaIncompleteInv(a, b, y); } /** Incomplete gamma integral and its complement * * These functions are defined by * * gammaIncomplete = ( $(INTEGRATE 0, x) $(POWER e, -t) $(POWER t, a-1) dt )/ $(GAMMA)(a) * * gammaIncompleteCompl(a,x) = 1 - gammaIncomplete(a,x) * = ($(INTEGRATE x, $(INFIN)) $(POWER e, -t) $(POWER t, a-1) dt )/ $(GAMMA)(a) * * In this implementation both arguments must be positive. * The integral is evaluated by either a power series or * continued fraction expansion, depending on the relative * values of a and x. */ real gammaIncomplete(real a, real x ) in { assert(x >= 0); assert(a > 0); } body { return std.internal.math.gammafunction.gammaIncomplete(a, x); } /** ditto */ real gammaIncompleteCompl(real a, real x ) in { assert(x >= 0); assert(a > 0); } body { return std.internal.math.gammafunction.gammaIncompleteCompl(a, x); } /** Inverse of complemented incomplete gamma integral * * Given a and p, the function finds x such that * * gammaIncompleteCompl( a, x ) = p. */ real gammaIncompleteComplInverse(real a, real p) in { assert(p >= 0 && p <= 1); assert(a > 0); } body { return std.internal.math.gammafunction.gammaIncompleteComplInv(a, p); } /* *********************************************** * ERROR FUNCTIONS & NORMAL DISTRIBUTION * * ***********************************************/ /** Error function * * The integral is * * erf(x) = 2/ $(SQRT)($(PI)) * $(INTEGRATE 0, x) exp( - $(POWER t, 2)) dt * * The magnitude of x is limited to about 106.56 for IEEE 80-bit * arithmetic; 1 or -1 is returned outside this range. */ real erf(real x) { return std.internal.math.errorfunction.erf(x); } /** Complementary error function * * erfc(x) = 1 - erf(x) * = 2/ $(SQRT)($(PI)) * $(INTEGRATE x, $(INFIN)) exp( - $(POWER t, 2)) dt * * This function has high relative accuracy for * values of x far from zero. (For values near zero, use erf(x)). */ real erfc(real x) { return std.internal.math.errorfunction.erfc(x); } /** Normal distribution function. * * The normal (or Gaussian, or bell-shaped) distribution is * defined as: * * normalDist(x) = 1/$(SQRT)(2$(PI)) $(INTEGRATE -$(INFIN), x) exp( - $(POWER t, 2)/2) dt * = 0.5 + 0.5 * erf(x/sqrt(2)) * = 0.5 * erfc(- x/sqrt(2)) * * To maintain accuracy at values of x near 1.0, use * normalDistribution(x) = 1.0 - normalDistribution(-x). * * References: * $(LINK http://www.netlib.org/cephes/ldoubdoc.html), * G. Marsaglia, "Evaluating the Normal Distribution", * Journal of Statistical Software 11, (July 2004). */ real normalDistribution(real x) { return std.internal.math.errorfunction.normalDistributionImpl(x); } /** Inverse of Normal distribution function * * Returns the argument, x, for which the area under the * Normal probability density function (integrated from * minus infinity to x) is equal to p. */ real normalDistributionInverse(real p) in { assert(p>=0.0L && p<=1.0L, "Domain error"); } body { return std.internal.math.errorfunction.normalDistributionInvImpl(p); } ldc-1.1.0-beta3-src/runtime/phobos/std/complex.d0000664000175000017500000005522612776215007017534 0ustar kaikai// Written in the D programming language. /** This module contains the $(LREF Complex) type, which is used to represent _complex numbers, along with related mathematical operations and functions. $(LREF Complex) will eventually $(DDLINK deprecate, Deprecated Features, replace) the built-in types $(D cfloat), $(D cdouble), $(D creal), $(D ifloat), $(D idouble), and $(D ireal). Authors: Lars Tandle Kyllingstad, Don Clugston Copyright: Copyright (c) 2010, Lars T. Kyllingstad. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0) Source: $(PHOBOSSRC std/_complex.d) */ module std.complex; import std.traits; /** Helper function that returns a _complex number with the specified real and imaginary parts. Params: R = (template parameter) type of real part of complex number I = (template parameter) type of imaginary part of complex number re = real part of complex number to be constructed im = (optional) imaginary part of complex number Returns: $(D Complex) instance with real and imaginary parts set to the values provided as input. If neither $(D re) nor $(D im) are floating-point numbers, the return type will be $(D Complex!double). Otherwise, the return type is deduced using $(D std.traits.CommonType!(R, I)). */ auto complex(R)(R re) @safe pure nothrow @nogc if (is(R : double)) { static if (isFloatingPoint!R) return Complex!R(re, 0); else return Complex!double(re, 0); } /// ditto auto complex(R, I)(R re, I im) @safe pure nothrow @nogc if (is(R : double) && is(I : double)) { static if (isFloatingPoint!R || isFloatingPoint!I) return Complex!(CommonType!(R, I))(re, im); else return Complex!double(re, im); } /// unittest { auto a = complex(1.0); static assert (is(typeof(a) == Complex!double)); assert (a.re == 1.0); assert (a.im == 0.0); auto b = complex(2.0L); static assert (is(typeof(b) == Complex!real)); assert (b.re == 2.0L); assert (b.im == 0.0L); auto c = complex(1.0, 2.0); static assert (is(typeof(c) == Complex!double)); assert (c.re == 1.0); assert (c.im == 2.0); auto d = complex(3.0, 4.0L); static assert (is(typeof(d) == Complex!real)); assert (d.re == 3.0); assert (d.im == 4.0L); auto e = complex(1); static assert (is(typeof(e) == Complex!double)); assert (e.re == 1); assert (e.im == 0); auto f = complex(1L, 2); static assert (is(typeof(f) == Complex!double)); assert (f.re == 1L); assert (f.im == 2); auto g = complex(3, 4.0L); static assert (is(typeof(g) == Complex!real)); assert (g.re == 3); assert (g.im == 4.0L); } /** A complex number parametrised by a type $(D T), which must be either $(D float), $(D double) or $(D real). */ struct Complex(T) if (isFloatingPoint!T) { import std.format : FormatSpec; /** The real part of the number. */ T re; /** The imaginary part of the number. */ T im; /** Converts the complex number to a string representation. The second form of this function is usually not called directly; instead, it is used via $(XREF string,format), as shown in the examples below. Supported format characters are 'e', 'f', 'g', 'a', and 's'. See the $(LINK2 std_format.html, std.format) and $(XREF string, format) documentation for more information. */ string toString() const /* TODO: @safe pure nothrow */ { import std.exception : assumeUnique; char[] buf; buf.reserve(100); auto fmt = FormatSpec!char("%s"); toString((const(char)[] s) { buf ~= s; }, fmt); return assumeUnique(buf); } static if (is(T == double)) /// unittest { auto c = complex(1.2, 3.4); // Vanilla toString formatting: assert(c.toString() == "1.2+3.4i"); // Formatting with std.string.format specs: the precision and width // specifiers apply to both the real and imaginary parts of the // complex number. import std.format : format; assert(format("%.2f", c) == "1.20+3.40i"); assert(format("%4.1f", c) == " 1.2+ 3.4i"); } /// ditto void toString(Char)(scope void delegate(const(Char)[]) sink, FormatSpec!Char formatSpec) const { import std.math : signbit; import std.format : formatValue; formatValue(sink, re, formatSpec); if (signbit(im) == 0) sink("+"); formatValue(sink, im, formatSpec); sink("i"); } @safe pure nothrow @nogc: this(R : T)(Complex!R z) { re = z.re; im = z.im; } this(Rx : T, Ry : T)(Rx x, Ry y) { re = x; im = y; } this(R : T)(R r) { re = r; im = 0; } // ASSIGNMENT OPERATORS // this = complex ref Complex opAssign(R : T)(Complex!R z) { re = z.re; im = z.im; return this; } // this = numeric ref Complex opAssign(R : T)(R r) { re = r; im = 0; return this; } // COMPARISON OPERATORS // this == complex bool opEquals(R : T)(Complex!R z) const { return re == z.re && im == z.im; } // this == numeric bool opEquals(R : T)(R r) const { return re == r && im == 0; } // UNARY OPERATORS // +complex Complex opUnary(string op)() const if (op == "+") { return this; } // -complex Complex opUnary(string op)() const if (op == "-") { return Complex(-re, -im); } // BINARY OPERATORS // complex op complex Complex!(CommonType!(T,R)) opBinary(string op, R)(Complex!R z) const { alias C = typeof(return); auto w = C(this.re, this.im); return w.opOpAssign!(op)(z); } // complex op numeric Complex!(CommonType!(T,R)) opBinary(string op, R)(R r) const if (isNumeric!R) { alias C = typeof(return); auto w = C(this.re, this.im); return w.opOpAssign!(op)(r); } // numeric + complex, numeric * complex Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) const if ((op == "+" || op == "*") && (isNumeric!R)) { return opBinary!(op)(r); } // numeric - complex Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) const if (op == "-" && isNumeric!R) { return Complex(r - re, -im); } // numeric / complex Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) const if (op == "/" && isNumeric!R) { import std.math : fabs; typeof(return) w = void; if (fabs(re) < fabs(im)) { immutable ratio = re/im; immutable rdivd = r/(re*ratio + im); w.re = rdivd*ratio; w.im = -rdivd; } else { immutable ratio = im/re; immutable rdivd = r/(re + im*ratio); w.re = rdivd; w.im = -rdivd*ratio; } return w; } // numeric ^^ complex Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R lhs) const if (op == "^^" && isNumeric!R) { import std.math : cos, exp, log, sin, PI; Unqual!(CommonType!(T, R)) ab = void, ar = void; if (lhs >= 0) { // r = lhs // theta = 0 ab = lhs ^^ this.re; ar = log(lhs) * this.im; } else { // r = -lhs // theta = PI ab = (-lhs) ^^ this.re * exp(-PI * this.im); ar = PI * this.re + log(-lhs) * this.im; } return typeof(return)(ab * cos(ar), ab * sin(ar)); } // OP-ASSIGN OPERATORS // complex += complex, complex -= complex ref Complex opOpAssign(string op, C)(C z) if ((op == "+" || op == "-") && is(C R == Complex!R)) { mixin ("re "~op~"= z.re;"); mixin ("im "~op~"= z.im;"); return this; } // complex *= complex ref Complex opOpAssign(string op, C)(C z) if (op == "*" && is(C R == Complex!R)) { auto temp = re*z.re - im*z.im; im = im*z.re + re*z.im; re = temp; return this; } // complex /= complex ref Complex opOpAssign(string op, C)(C z) if (op == "/" && is(C R == Complex!R)) { import std.math : fabs; if (fabs(z.re) < fabs(z.im)) { immutable ratio = z.re/z.im; immutable denom = z.re*ratio + z.im; immutable temp = (re*ratio + im)/denom; im = (im*ratio - re)/denom; re = temp; } else { immutable ratio = z.im/z.re; immutable denom = z.re + z.im*ratio; immutable temp = (re + im*ratio)/denom; im = (im - re*ratio)/denom; re = temp; } return this; } // complex ^^= complex ref Complex opOpAssign(string op, C)(C z) if (op == "^^" && is(C R == Complex!R)) { import std.math: exp, log, cos, sin; immutable r = abs(this); immutable t = arg(this); immutable ab = r^^z.re * exp(-t*z.im); immutable ar = t*z.re + log(r)*z.im; re = ab*cos(ar); im = ab*sin(ar); return this; } // complex += numeric, complex -= numeric ref Complex opOpAssign(string op, U : T)(U a) if (op == "+" || op == "-") { mixin ("re "~op~"= a;"); return this; } // complex *= numeric, complex /= numeric ref Complex opOpAssign(string op, U : T)(U a) if (op == "*" || op == "/") { mixin ("re "~op~"= a;"); mixin ("im "~op~"= a;"); return this; } // complex ^^= real ref Complex opOpAssign(string op, R)(R r) if (op == "^^" && isFloatingPoint!R) { import std.math: cos, sin; immutable ab = abs(this)^^r; immutable ar = arg(this)*r; re = ab*cos(ar); im = ab*sin(ar); return this; } // complex ^^= int ref Complex opOpAssign(string op, U)(U i) if (op == "^^" && isIntegral!U) { switch (i) { case 0: re = 1.0; im = 0.0; break; case 1: // identity; do nothing break; case 2: this *= this; break; case 3: auto z = this; this *= z; this *= z; break; default: this ^^= cast(real) i; } return this; } } unittest { import std.math; import std.complex; enum EPS = double.epsilon; auto c1 = complex(1.0, 1.0); // Check unary operations. auto c2 = Complex!double(0.5, 2.0); assert (c2 == +c2); assert ((-c2).re == -(c2.re)); assert ((-c2).im == -(c2.im)); assert (c2 == -(-c2)); // Check complex-complex operations. auto cpc = c1 + c2; assert (cpc.re == c1.re + c2.re); assert (cpc.im == c1.im + c2.im); auto cmc = c1 - c2; assert (cmc.re == c1.re - c2.re); assert (cmc.im == c1.im - c2.im); auto ctc = c1 * c2; assert (approxEqual(abs(ctc), abs(c1)*abs(c2), EPS)); assert (approxEqual(arg(ctc), arg(c1)+arg(c2), EPS)); auto cdc = c1 / c2; assert (approxEqual(abs(cdc), abs(c1)/abs(c2), EPS)); assert (approxEqual(arg(cdc), arg(c1)-arg(c2), EPS)); auto cec = c1^^c2; assert (approxEqual(cec.re, 0.11524131979943839881, EPS)); assert (approxEqual(cec.im, 0.21870790452746026696, EPS)); // Check complex-real operations. double a = 123.456; auto cpr = c1 + a; assert (cpr.re == c1.re + a); assert (cpr.im == c1.im); auto cmr = c1 - a; assert (cmr.re == c1.re - a); assert (cmr.im == c1.im); auto ctr = c1 * a; assert (ctr.re == c1.re*a); assert (ctr.im == c1.im*a); auto cdr = c1 / a; assert (approxEqual(abs(cdr), abs(c1)/a, EPS)); assert (approxEqual(arg(cdr), arg(c1), EPS)); auto cer = c1^^3.0; assert (approxEqual(abs(cer), abs(c1)^^3, EPS)); assert (approxEqual(arg(cer), arg(c1)*3, EPS)); auto rpc = a + c1; assert (rpc == cpr); auto rmc = a - c1; assert (rmc.re == a-c1.re); assert (rmc.im == -c1.im); auto rtc = a * c1; assert (rtc == ctr); auto rdc = a / c1; assert (approxEqual(abs(rdc), a/abs(c1), EPS)); assert (approxEqual(arg(rdc), -arg(c1), EPS)); auto rec1a = 1.0 ^^ c1; assert(rec1a.re == 1.0); assert(rec1a.im == 0.0); auto rec2a = 1.0 ^^ c2; assert(rec2a.re == 1.0); assert(rec2a.im == 0.0); auto rec1b = (-1.0) ^^ c1; assert(approxEqual(abs(rec1b), std.math.exp(-PI * c1.im), EPS)); auto arg1b = arg(rec1b); /* The argument _should_ be PI, but floating-point rounding error * means that in fact the imaginary part is very slightly negative. */ assert(approxEqual(arg1b, PI, EPS) || approxEqual(arg1b, -PI, EPS)); auto rec2b = (-1.0) ^^ c2; assert(approxEqual(abs(rec2b), std.math.exp(-2 * PI), EPS)); assert(approxEqual(arg(rec2b), PI_2, EPS)); auto rec3a = 0.79 ^^ complex(6.8, 5.7); auto rec3b = complex(0.79, 0.0) ^^ complex(6.8, 5.7); assert(approxEqual(rec3a.re, rec3b.re, EPS)); assert(approxEqual(rec3a.im, rec3b.im, EPS)); auto rec4a = (-0.79) ^^ complex(6.8, 5.7); auto rec4b = complex(-0.79, 0.0) ^^ complex(6.8, 5.7); assert(approxEqual(rec4a.re, rec4b.re, EPS)); assert(approxEqual(rec4a.im, rec4b.im, EPS)); auto rer = a ^^ complex(2.0, 0.0); auto rcheck = a ^^ 2.0; static assert(is(typeof(rcheck) == double)); assert(feqrel(rer.re, rcheck) == double.mant_dig); assert(isIdentical(rer.re, rcheck)); assert(rer.im == 0.0); auto rer2 = (-a) ^^ complex(2.0, 0.0); rcheck = (-a) ^^ 2.0; assert(feqrel(rer2.re, rcheck) == double.mant_dig); assert(isIdentical(rer2.re, rcheck)); assert(approxEqual(rer2.im, 0.0, EPS)); auto rer3 = (-a) ^^ complex(-2.0, 0.0); rcheck = (-a) ^^ (-2.0); assert(feqrel(rer3.re, rcheck) == double.mant_dig); assert(isIdentical(rer3.re, rcheck)); assert(approxEqual(rer3.im, 0.0, EPS)); auto rer4 = a ^^ complex(-2.0, 0.0); rcheck = a ^^ (-2.0); assert(feqrel(rer4.re, rcheck) == double.mant_dig); assert(isIdentical(rer4.re, rcheck)); assert(rer4.im == 0.0); // Check Complex-int operations. foreach (i; 0..6) { auto cei = c1^^i; assert (approxEqual(abs(cei), abs(c1)^^i, EPS)); // Use cos() here to deal with arguments that go outside // the (-pi,pi] interval (only an issue for i>3). assert (approxEqual(std.math.cos(arg(cei)), std.math.cos(arg(c1)*i), EPS)); } // Check operations between different complex types. auto cf = Complex!float(1.0, 1.0); auto cr = Complex!real(1.0, 1.0); auto c1pcf = c1 + cf; auto c1pcr = c1 + cr; static assert (is(typeof(c1pcf) == Complex!double)); static assert (is(typeof(c1pcr) == Complex!real)); assert (c1pcf.re == c1pcr.re); assert (c1pcf.im == c1pcr.im); } unittest { // Initialization Complex!double a = 1; assert (a.re == 1 && a.im == 0); Complex!double b = 1.0; assert (b.re == 1.0 && b.im == 0); Complex!double c = Complex!real(1.0, 2); assert (c.re == 1.0 && c.im == 2); } unittest { // Assignments and comparisons Complex!double z; z = 1; assert (z == 1); assert (z.re == 1.0 && z.im == 0.0); z = 2.0; assert (z == 2.0); assert (z.re == 2.0 && z.im == 0.0); z = 1.0L; assert (z == 1.0L); assert (z.re == 1.0 && z.im == 0.0); auto w = Complex!real(1.0, 1.0); z = w; assert (z == w); assert (z.re == 1.0 && z.im == 1.0); auto c = Complex!float(2.0, 2.0); z = c; assert (z == c); assert (z.re == 2.0 && z.im == 2.0); } /* Makes Complex!(Complex!T) fold to Complex!T. The rationale for this is that just like the real line is a subspace of the complex plane, the complex plane is a subspace of itself. Example of usage: --- Complex!T addI(T)(T x) { return x + Complex!T(0.0, 1.0); } --- The above will work if T is both real and complex. */ template Complex(T) if (is(T R == Complex!R)) { alias Complex = T; } unittest { static assert (is(Complex!(Complex!real) == Complex!real)); Complex!T addI(T)(T x) { return x + Complex!T(0.0, 1.0); } auto z1 = addI(1.0); assert (z1.re == 1.0 && z1.im == 1.0); enum one = Complex!double(1.0, 0.0); auto z2 = addI(one); assert (z1 == z2); } /** Params: z = A complex number. Returns: The absolute value (or modulus) of `z`. */ T abs(T)(Complex!T z) @safe pure nothrow @nogc { import std.math : hypot; return hypot(z.re, z.im); } /// unittest { static import std.math; assert (abs(complex(1.0)) == 1.0); assert (abs(complex(0.0, 1.0)) == 1.0); assert (abs(complex(1.0L, -2.0L)) == std.math.sqrt(5.0L)); } /++ Params: z = A complex number. x = A real number. Returns: The squared modulus of `z`. For genericity, if called on a real number, returns its square. +/ T sqAbs(T)(Complex!T z) @safe pure nothrow @nogc { return z.re*z.re + z.im*z.im; } /// unittest { import std.math; assert (sqAbs(complex(0.0)) == 0.0); assert (sqAbs(complex(1.0)) == 1.0); assert (sqAbs(complex(0.0, 1.0)) == 1.0); assert (approxEqual(sqAbs(complex(1.0L, -2.0L)), 5.0L)); assert (approxEqual(sqAbs(complex(-3.0L, 1.0L)), 10.0L)); assert (approxEqual(sqAbs(complex(1.0f,-1.0f)), 2.0f)); } /// ditto T sqAbs(T)(T x) @safe pure nothrow @nogc if (isFloatingPoint!T) { return x*x; } unittest { import std.math; assert (sqAbs(0.0) == 0.0); assert (sqAbs(-1.0) == 1.0); assert (approxEqual(sqAbs(-3.0L), 9.0L)); assert (approxEqual(sqAbs(-5.0f), 25.0f)); } /** Params: z = A complex number. Returns: The argument (or phase) of `z`. */ T arg(T)(Complex!T z) @safe pure nothrow @nogc { import std.math : atan2; return atan2(z.im, z.re); } /// unittest { import std.math; assert (arg(complex(1.0)) == 0.0); assert (arg(complex(0.0L, 1.0L)) == PI_2); assert (arg(complex(1.0L, 1.0L)) == PI_4); } /** Params: z = A complex number. Returns: The complex conjugate of `z`. */ Complex!T conj(T)(Complex!T z) @safe pure nothrow @nogc { return Complex!T(z.re, -z.im); } /// unittest { assert (conj(complex(1.0)) == complex(1.0)); assert (conj(complex(1.0, 2.0)) == complex(1.0, -2.0)); } /** Constructs a complex number given its absolute value and argument. Params: modulus = The modulus argument = The argument Returns: The complex number with the given modulus and argument. */ Complex!(CommonType!(T, U)) fromPolar(T, U)(T modulus, U argument) @safe pure nothrow @nogc { import std.math : sin, cos; return Complex!(CommonType!(T,U)) (modulus*cos(argument), modulus*sin(argument)); } /// unittest { import std.math; auto z = fromPolar(std.math.sqrt(2.0), PI_4); assert (approxEqual(z.re, 1.0L, real.epsilon)); assert (approxEqual(z.im, 1.0L, real.epsilon)); } /** Trigonometric functions on complex numbers. Params: z = A complex number. Returns: The sine and cosine of `z`, respectively. */ Complex!T sin(T)(Complex!T z) @safe pure nothrow @nogc { import std.math : expi, coshisinh; auto cs = expi(z.re); auto csh = coshisinh(z.im); return typeof(return)(cs.im * csh.re, cs.re * csh.im); } /// unittest { static import std.math; assert(sin(complex(0.0)) == 0.0); assert(sin(complex(2.0L, 0)) == std.math.sin(2.0L)); } /// ditto Complex!T cos(T)(Complex!T z) @safe pure nothrow @nogc { import std.math : expi, coshisinh; auto cs = expi(z.re); auto csh = coshisinh(z.im); return typeof(return)(cs.re * csh.re, - cs.im * csh.im); } /// unittest{ import std.math; import std.complex; assert(cos(complex(0.0)) == 1.0); assert(cos(complex(1.3L)) == std.math.cos(1.3L)); assert(cos(complex(0, 5.2L)) == cosh(5.2L)); } /** Params: y = A real number. Returns: The value of cos(y) + i sin(y). Note: $(D expi) is included here for convenience and for easy migration of code that uses $(XREF math,_expi). Unlike $(XREF math,_expi), which uses the x87 $(I fsincos) instruction when possible, this function is no faster than calculating cos(y) and sin(y) separately. */ Complex!real expi(real y) @trusted pure nothrow @nogc { import std.math : cos, sin; return Complex!real(cos(y), sin(y)); } /// unittest { static import std.math; assert(expi(1.3e5L) == complex(std.math.cos(1.3e5L), std.math.sin(1.3e5L))); assert(expi(0.0L) == 1.0L); auto z1 = expi(1.234); auto z2 = std.math.expi(1.234); assert(z1.re == z2.re && z1.im == z2.im); } /** Params: z = A complex number. Returns: The square root of `z`. */ Complex!T sqrt(T)(Complex!T z) @safe pure nothrow @nogc { static import std.math; typeof(return) c; real x,y,w,r; if (z == 0) { c = typeof(return)(0, 0); } else { real z_re = z.re; real z_im = z.im; x = std.math.fabs(z_re); y = std.math.fabs(z_im); if (x >= y) { r = y / x; w = std.math.sqrt(x) * std.math.sqrt(0.5 * (1 + std.math.sqrt(1 + r * r))); } else { r = x / y; w = std.math.sqrt(y) * std.math.sqrt(0.5 * (r + std.math.sqrt(1 + r * r))); } if (z_re >= 0) { c = typeof(return)(w, z_im / (w + w)); } else { if (z_im < 0) w = -w; c = typeof(return)(z_im / (w + w), w); } } return c; } /// unittest { static import std.math; assert (sqrt(complex(0.0)) == 0.0); assert (sqrt(complex(1.0L, 0)) == std.math.sqrt(1.0L)); assert (sqrt(complex(-1.0L, 0)) == complex(0, 1.0L)); } // Issue 10881: support %f formatting of complex numbers unittest { import std.format : format; auto x = complex(1.2, 3.4); assert(format("%.2f", x) == "1.20+3.40i"); auto y = complex(1.2, -3.4); assert(format("%.2f", y) == "1.20-3.40i"); } unittest { // Test wide string formatting import std.format; wstring wformat(T)(string format, Complex!T c) { import std.array : appender; auto w = appender!wstring(); auto n = formattedWrite(w, format, c); return w.data; } auto x = complex(1.2, 3.4); assert(wformat("%.2f", x) == "1.20+3.40i"w); } unittest { // Test ease of use (vanilla toString() should be supported) assert(complex(1.2, 3.4).toString() == "1.2+3.4i"); } ldc-1.1.0-beta3-src/runtime/phobos/std/uri.d0000664000175000017500000003567412776215007016671 0ustar kaikai// Written in the D programming language. /** * Encode and decode Uniform Resource Identifiers (URIs). * URIs are used in internet transfer protocols. * Valid URI characters consist of letters, digits, * and the characters $(B ;/?:@&=+$,-_.!~*'()) * Reserved URI characters are $(B ;/?:@&=+$,) * Escape sequences consist of $(B %) followed by two hex digits. * * See_Also: * $(LINK2 http://www.ietf.org/rfc/rfc3986.txt, RFC 3986)
* $(LINK2 http://en.wikipedia.org/wiki/Uniform_resource_identifier, Wikipedia) * Macros: * WIKI = Phobos/StdUri * * Copyright: Copyright Digital Mars 2000 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * Source: $(PHOBOSSRC std/_uri.d) */ /* Copyright Digital Mars 2000 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module std.uri; //debug=uri; // uncomment to turn on debugging writefln's debug(uri) private import std.stdio; /* ====================== URI Functions ================ */ private import std.ascii; private import core.stdc.stdlib; private import std.utf; private import std.traits : isSomeChar; import core.exception : OutOfMemoryError; import std.exception; /** This Exception is thrown if something goes wrong when encoding or decoding a URI. */ class URIException : Exception { mixin basicExceptionCtors; } private enum { URI_Alpha = 1, URI_Reserved = 2, URI_Mark = 4, URI_Digit = 8, URI_Hash = 0x10, // '#' } immutable char[16] hex2ascii = "0123456789ABCDEF"; immutable ubyte[128] uri_flags = // indexed by character ({ ubyte[128] uflags; // Compile time initialize uflags['#'] |= URI_Hash; foreach (c; 'A' .. 'Z' + 1) { uflags[c] |= URI_Alpha; uflags[c + 0x20] |= URI_Alpha; // lowercase letters } foreach (c; '0' .. '9' + 1) uflags[c] |= URI_Digit; foreach (c; ";/?:@&=+$,") uflags[c] |= URI_Reserved; foreach (c; "-_.!~*'()") uflags[c] |= URI_Mark; return uflags; })(); private string URI_Encode(dstring string, uint unescapedSet) { uint j; uint k; dchar V; dchar C; // result buffer char[50] buffer = void; char* R; uint Rlen; uint Rsize; // alloc'd size auto len = string.length; R = buffer.ptr; Rsize = buffer.length; Rlen = 0; for (k = 0; k != len; k++) { C = string[k]; // if (C in unescapedSet) if (C < uri_flags.length && uri_flags[C] & unescapedSet) { if (Rlen == Rsize) { char* R2; Rsize *= 2; if (Rsize > 1024) { R2 = (new char[Rsize]).ptr; } else { R2 = cast(char *)alloca(Rsize * char.sizeof); if (!R2) throw new OutOfMemoryError("Alloca failure"); } R2[0..Rlen] = R[0..Rlen]; R = R2; } R[Rlen] = cast(char)C; Rlen++; } else { char[6] Octet; uint L; V = C; // Transform V into octets if (V <= 0x7F) { Octet[0] = cast(char) V; L = 1; } else if (V <= 0x7FF) { Octet[0] = cast(char)(0xC0 | (V >> 6)); Octet[1] = cast(char)(0x80 | (V & 0x3F)); L = 2; } else if (V <= 0xFFFF) { Octet[0] = cast(char)(0xE0 | (V >> 12)); Octet[1] = cast(char)(0x80 | ((V >> 6) & 0x3F)); Octet[2] = cast(char)(0x80 | (V & 0x3F)); L = 3; } else if (V <= 0x1FFFFF) { Octet[0] = cast(char)(0xF0 | (V >> 18)); Octet[1] = cast(char)(0x80 | ((V >> 12) & 0x3F)); Octet[2] = cast(char)(0x80 | ((V >> 6) & 0x3F)); Octet[3] = cast(char)(0x80 | (V & 0x3F)); L = 4; } /+ else if (V <= 0x3FFFFFF) { Octet[0] = cast(char)(0xF8 | (V >> 24)); Octet[1] = cast(char)(0x80 | ((V >> 18) & 0x3F)); Octet[2] = cast(char)(0x80 | ((V >> 12) & 0x3F)); Octet[3] = cast(char)(0x80 | ((V >> 6) & 0x3F)); Octet[4] = cast(char)(0x80 | (V & 0x3F)); L = 5; } else if (V <= 0x7FFFFFFF) { Octet[0] = cast(char)(0xFC | (V >> 30)); Octet[1] = cast(char)(0x80 | ((V >> 24) & 0x3F)); Octet[2] = cast(char)(0x80 | ((V >> 18) & 0x3F)); Octet[3] = cast(char)(0x80 | ((V >> 12) & 0x3F)); Octet[4] = cast(char)(0x80 | ((V >> 6) & 0x3F)); Octet[5] = cast(char)(0x80 | (V & 0x3F)); L = 6; } +/ else { throw new URIException("Undefined UTF-32 code point"); } if (Rlen + L * 3 > Rsize) { char *R2; Rsize = 2 * (Rlen + L * 3); if (Rsize > 1024) { R2 = (new char[Rsize]).ptr; } else { R2 = cast(char *)alloca(Rsize * char.sizeof); if (!R2) throw new OutOfMemoryError("Alloca failure"); } R2[0..Rlen] = R[0..Rlen]; R = R2; } for (j = 0; j < L; j++) { R[Rlen] = '%'; R[Rlen + 1] = hex2ascii[Octet[j] >> 4]; R[Rlen + 2] = hex2ascii[Octet[j] & 15]; Rlen += 3; } } } return R[0..Rlen].idup; } uint ascii2hex(dchar c) { return (c <= '9') ? c - '0' : (c <= 'F') ? c - 'A' + 10 : c - 'a' + 10; } private dstring URI_Decode(Char)(in Char[] uri, uint reservedSet) if (isSomeChar!Char) { uint j; uint k; uint V; dchar C; // Result array, allocated on stack dchar* R; uint Rlen; auto len = uri.length; auto s = uri.ptr; // Preallocate result buffer R guaranteed to be large enough for result auto Rsize = len; if (Rsize > 1024 / dchar.sizeof) { R = (new dchar[Rsize]).ptr; } else { R = cast(dchar *)alloca(Rsize * dchar.sizeof); if (!R) throw new OutOfMemoryError("Alloca failure"); } Rlen = 0; for (k = 0; k != len; k++) { char B; uint start; C = s[k]; if (C != '%') { R[Rlen] = C; Rlen++; continue; } start = k; if (k + 2 >= len) throw new URIException("Unexpected end of URI"); if (!isHexDigit(s[k + 1]) || !isHexDigit(s[k + 2])) throw new URIException("Expected two hexadecimal digits after '%'"); B = cast(char)((ascii2hex(s[k + 1]) << 4) + ascii2hex(s[k + 2])); k += 2; if ((B & 0x80) == 0) { C = B; } else { uint n; for (n = 1; ; n++) { if (n > 4) throw new URIException("UTF-32 code point size too large"); if (((B << n) & 0x80) == 0) { if (n == 1) throw new URIException("UTF-32 code point size too small"); break; } } // Pick off (7 - n) significant bits of B from first byte of octet V = B & ((1 << (7 - n)) - 1); // (!!!) if (k + (3 * (n - 1)) >= len) throw new URIException("UTF-32 unaligned String"); for (j = 1; j != n; j++) { k++; if (s[k] != '%') throw new URIException("Expected: '%'"); if (!isHexDigit(s[k + 1]) || !isHexDigit(s[k + 2])) throw new URIException("Expected two hexadecimal digits after '%'"); B = cast(char)((ascii2hex(s[k + 1]) << 4) + ascii2hex(s[k + 2])); if ((B & 0xC0) != 0x80) throw new URIException("Incorrect UTF-32 multi-byte sequence"); k += 2; V = (V << 6) | (B & 0x3F); } if (V > 0x10FFFF) throw new URIException("Unknown UTF-32 code point"); C = V; } if (C < uri_flags.length && uri_flags[C] & reservedSet) { // R ~= s[start .. k + 1]; int width = (k + 1) - start; for (int ii = 0; ii < width; ii++) R[Rlen + ii] = s[start + ii]; Rlen += width; } else { R[Rlen] = C; Rlen++; } } assert(Rlen <= Rsize); // enforce our preallocation size guarantee // Copy array on stack to array in memory return R[0..Rlen].idup; } /************************************* * Decodes the URI string encodedURI into a UTF-8 string and returns it. * Escape sequences that resolve to reserved URI characters are not replaced. * Escape sequences that resolve to the '#' character are not replaced. */ string decode(Char)(in Char[] encodedURI) if (isSomeChar!Char) { auto s = URI_Decode(encodedURI, URI_Reserved | URI_Hash); return std.utf.toUTF8(s); } /******************************* * Decodes the URI string encodedURI into a UTF-8 string and returns it. All * escape sequences are decoded. */ string decodeComponent(Char)(in Char[] encodedURIComponent) if (isSomeChar!Char) { auto s = URI_Decode(encodedURIComponent, 0); return std.utf.toUTF8(s); } /***************************** * Encodes the UTF-8 string uri into a URI and returns that URI. Any character * not a valid URI character is escaped. The '#' character is not escaped. */ string encode(Char)(in Char[] uri) if (isSomeChar!Char) { auto s = std.utf.toUTF32(uri); return URI_Encode(s, URI_Reserved | URI_Hash | URI_Alpha | URI_Digit | URI_Mark); } /******************************** * Encodes the UTF-8 string uriComponent into a URI and returns that URI. * Any character not a letter, digit, or one of -_.!~*'() is escaped. */ string encodeComponent(Char)(in Char[] uriComponent) if (isSomeChar!Char) { auto s = std.utf.toUTF32(uriComponent); return URI_Encode(s, URI_Alpha | URI_Digit | URI_Mark); } /*************************** * Does string s[] start with a URL? * Returns: * -1 it does not * len it does, and s[0..len] is the slice of s[] that is that URL */ ptrdiff_t uriLength(Char)(in Char[] s) if (isSomeChar!Char) { /* Must start with one of: * http:// * https:// * www. */ import std.uni : icmp; ptrdiff_t i; if (s.length <= 4) return -1; if (s.length > 7 && icmp(s[0 .. 7], "http://") == 0) { i = 7; } else { if (s.length > 8 && icmp(s[0 .. 8], "https://") == 0) i = 8; else return -1; } // if (icmp(s[0 .. 4], "www.") == 0) // i = 4; ptrdiff_t lastdot; for (; i < s.length; i++) { auto c = s[i]; if (isAlphaNum(c)) continue; if (c == '-' || c == '_' || c == '?' || c == '=' || c == '%' || c == '&' || c == '/' || c == '+' || c == '#' || c == '~' || c == '$') continue; if (c == '.') { lastdot = i; continue; } break; } //if (!lastdot || (i - lastdot != 3 && i - lastdot != 4)) if (!lastdot) return -1; return i; } /// unittest { string s1 = "http://www.digitalmars.com/~fred/fredsRX.html#foo end!"; assert (uriLength(s1) == 49); string s2 = "no uri here"; assert (uriLength(s2) == -1); assert (uriLength("issue 14924") < 0); } /*************************** * Does string s[] start with an email address? * Returns: * -1 it does not * len it does, and s[0..i] is the slice of s[] that is that email address * References: * RFC2822 */ ptrdiff_t emailLength(Char)(in Char[] s) if (isSomeChar!Char) { ptrdiff_t i; if (!isAlpha(s[0])) return -1; for (i = 1; 1; i++) { if (i == s.length) return -1; auto c = s[i]; if (isAlphaNum(c)) continue; if (c == '-' || c == '_' || c == '.') continue; if (c != '@') return -1; i++; break; } /* Now do the part past the '@' */ ptrdiff_t lastdot; for (; i < s.length; i++) { auto c = s[i]; if (isAlphaNum(c)) continue; if (c == '-' || c == '_') continue; if (c == '.') { lastdot = i; continue; } break; } if (!lastdot || (i - lastdot != 3 && i - lastdot != 4)) return -1; return i; } /// unittest { string s1 = "my.e-mail@www.example-domain.com with garbage added"; assert (emailLength(s1) == 32); string s2 = "no email address here"; assert (emailLength(s2) == -1); assert (emailLength("issue 14924") < 0); } unittest { debug(uri) writeln("uri.encodeURI.unittest"); string source = "http://www.digitalmars.com/~fred/fred's RX.html#foo"; string target = "http://www.digitalmars.com/~fred/fred's%20RX.html#foo"; auto result = encode(source); debug(uri) writefln("result = '%s'", result); assert(result == target); result = decode(target); debug(uri) writefln("result = '%s'", result); assert(result == source); result = encode(decode("%E3%81%82%E3%81%82")); assert(result == "%E3%81%82%E3%81%82"); result = encodeComponent("c++"); assert(result == "c%2B%2B"); auto str = new char[10_000_000]; str[] = 'A'; result = encodeComponent(str); foreach (char c; result) assert(c == 'A'); result = decode("%41%42%43"); debug(uri) writeln(result); import std.meta : AliasSeq; foreach (StringType; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { import std.conv : to; StringType decoded1 = source.to!StringType; string encoded1 = encode(decoded1); assert(decoded1 == source.to!StringType); // check that `decoded1` wasn't changed assert(encoded1 == target); assert(decoded1 == decode(encoded1).to!StringType); StringType encoded2 = target.to!StringType; string decoded2 = decode(encoded2); assert(encoded2 == target.to!StringType); // check that `encoded2` wasn't changed assert(decoded2 == source); assert(encoded2 == encode(decoded2).to!StringType); } } ldc-1.1.0-beta3-src/runtime/phobos/std/algorithm/0000775000175000017500000000000012776215007017674 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/algorithm/comparison.d0000664000175000017500000017116312776215007022224 0ustar kaikai// Written in the D programming language. /** This is a submodule of $(LINK2 std_algorithm.html, std.algorithm). It contains generic _comparison algorithms. $(BOOKTABLE Cheat Sheet, $(TR $(TH Function Name) $(TH Description)) $(T2 among, Checks if a value is among a set of values, e.g. $(D if (v.among(1, 2, 3)) // `v` is 1, 2 or 3)) $(T2 castSwitch, $(D (new A()).castSwitch((A a)=>1,(B b)=>2)) returns $(D 1).) $(T2 clamp, $(D clamp(1, 3, 6)) returns $(D 3). $(D clamp(4, 3, 6)) returns $(D 4).) $(T2 cmp, $(D cmp("abc", "abcd")) is $(D -1), $(D cmp("abc", "aba")) is $(D 1), and $(D cmp("abc", "abc")) is $(D 0).) $(T2 either, Return first parameter $(D p) that passes an $(D if (p)) test, e.g. $(D either(0, 42, 43)) returns $(D 42).) $(T2 equal, Compares ranges for element-by-element equality, e.g. $(D equal([1, 2, 3], [1.0, 2.0, 3.0])) returns $(D true).) $(T2 isPermutation, $(D isPermutation([1, 2], [2, 1])) returns $(D true).) $(T2 isSameLength, $(D isSameLength([1, 2, 3], [4, 5, 6])) returns $(D true).) $(T2 levenshteinDistance, $(D levenshteinDistance("kitten", "sitting")) returns $(D 3) by using the $(LUCKY Levenshtein distance _algorithm).) $(T2 levenshteinDistanceAndPath, $(D levenshteinDistanceAndPath("kitten", "sitting")) returns $(D tuple(3, "snnnsni")) by using the $(LUCKY Levenshtein distance _algorithm).) $(T2 max, $(D max(3, 4, 2)) returns $(D 4).) $(T2 min, $(D min(3, 4, 2)) returns $(D 2).) $(T2 mismatch, $(D mismatch("oh hi", "ohayo")) returns $(D tuple(" hi", "ayo")).) $(T2 predSwitch, $(D 2.predSwitch(1, "one", 2, "two", 3, "three")) returns $(D "two").) ) Copyright: Andrei Alexandrescu 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/algorithm/_comparison.d) Macros: T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) */ module std.algorithm.comparison; // FIXME import std.functional; // : unaryFun, binaryFun; import std.range; import std.traits; // FIXME import std.typecons; // : tuple, Tuple, Flag; import std.meta : allSatisfy; /** Find $(D value) _among $(D values), returning the 1-based index of the first matching value in $(D values), or $(D 0) if $(D value) is not _among $(D values). The predicate $(D pred) is used to compare values, and uses equality by default. Params: pred = The predicate used to compare the values. value = The value to search for. values = The values to compare the value to. Returns: 0 if value was not found among the values, otherwise the index of the found value plus one is returned. See_Also: $(XREF_PACK_NAMED algorithm,searching,find,find) and $(XREF_PACK_NAMED algorithm,searching,canFind, canFind) for finding a value in a range. */ uint among(alias pred = (a, b) => a == b, Value, Values...) (Value value, Values values) if (Values.length != 0) { foreach (uint i, ref v; values) { import std.functional : binaryFun; if (binaryFun!pred(value, v)) return i + 1; } return 0; } /// Ditto template among(values...) if (isExpressionTuple!values) { uint among(Value)(Value value) if (!is(CommonType!(Value, values) == void)) { switch (value) { foreach (uint i, v; values) case v: return i + 1; default: return 0; } } } /// @safe unittest { assert(3.among(1, 42, 24, 3, 2)); if (auto pos = "bar".among("foo", "bar", "baz")) assert(pos == 2); else assert(false); // 42 is larger than 24 assert(42.among!((lhs, rhs) => lhs > rhs)(43, 24, 100) == 2); } /** Alternatively, $(D values) can be passed at compile-time, allowing for a more efficient search, but one that only supports matching on equality: */ @safe unittest { assert(3.among!(2, 3, 4)); assert("bar".among!("foo", "bar", "baz") == 2); } @safe unittest { import std.meta : AliasSeq; if (auto pos = 3.among(1, 2, 3)) assert(pos == 3); else assert(false); assert(!4.among(1, 2, 3)); auto position = "hello".among("hello", "world"); assert(position); assert(position == 1); alias values = AliasSeq!("foo", "bar", "baz"); auto arr = [values]; assert(arr[0 .. "foo".among(values)] == ["foo"]); assert(arr[0 .. "bar".among(values)] == ["foo", "bar"]); assert(arr[0 .. "baz".among(values)] == arr); assert("foobar".among(values) == 0); if (auto pos = 3.among!(1, 2, 3)) assert(pos == 3); else assert(false); assert(!4.among!(1, 2, 3)); position = "hello".among!("hello", "world"); assert(position); assert(position == 1); static assert(!__traits(compiles, "a".among!("a", 42))); static assert(!__traits(compiles, (Object.init).among!(42, "a"))); } // Used in castSwitch to find the first choice that overshadows the last choice // in a tuple. private template indexOfFirstOvershadowingChoiceOnLast(choices...) { alias firstParameterTypes = Parameters!(choices[0]); alias lastParameterTypes = Parameters!(choices[$ - 1]); static if (lastParameterTypes.length == 0) { // If the last is null-typed choice, check if the first is null-typed. enum isOvershadowing = firstParameterTypes.length == 0; } else static if (firstParameterTypes.length == 1) { // If the both first and last are not null-typed, check for overshadowing. enum isOvershadowing = is(firstParameterTypes[0] == Object) // Object overshadows all other classes!(this is needed for interfaces) || is(lastParameterTypes[0] : firstParameterTypes[0]); } else { // If the first is null typed and the last is not - the is no overshadowing. enum isOvershadowing = false; } static if (isOvershadowing) { enum indexOfFirstOvershadowingChoiceOnLast = 0; } else { enum indexOfFirstOvershadowingChoiceOnLast = 1 + indexOfFirstOvershadowingChoiceOnLast!(choices[1..$]); } } /** Executes and returns one of a collection of handlers based on the type of the switch object. The first choice that $(D switchObject) can be casted to the type of argument it accepts will be called with $(D switchObject) casted to that type, and the value it'll return will be returned by $(D castSwitch). If a choice's return type is void, the choice must throw an exception, unless all the choices are void. In that case, castSwitch itself will return void. Throws: If none of the choice matches, a $(D SwitchError) will be thrown. $(D SwitchError) will also be thrown if not all the choices are void and a void choice was executed without throwing anything. Params: choices = The $(D choices) needs to be composed of function or delegate handlers that accept one argument. There can also be a choice that accepts zero arguments. That choice will be invoked if the $(D switchObject) is null. switchObject = the object against which the tests are being made. Returns: The value of the selected choice. Note: $(D castSwitch) can only be used with object types. */ auto castSwitch(choices...)(Object switchObject) { import core.exception : SwitchError; // Check to see if all handlers return void. enum areAllHandlersVoidResult = { bool result = true; foreach (index, choice; choices) { result &= is(ReturnType!choice == void); } return result; }(); if (switchObject !is null) { // Checking for exact matches: ClassInfo classInfo = typeid(switchObject); foreach (index, choice; choices) { static assert(isCallable!choice, "A choice handler must be callable"); alias choiceParameterTypes = Parameters!choice; static assert(choiceParameterTypes.length <= 1, "A choice handler can not have more than one argument."); static if (choiceParameterTypes.length == 1) { alias CastClass = choiceParameterTypes[0]; static assert(is(CastClass == class) || is(CastClass == interface), "A choice handler can have only class or interface typed argument."); // Check for overshadowing: immutable indexOfOvershadowingChoice = indexOfFirstOvershadowingChoiceOnLast!(choices[0..index + 1]); static assert(indexOfOvershadowingChoice == index, "choice number %d(type %s) is overshadowed by choice number %d(type %s)".format( index + 1, CastClass.stringof, indexOfOvershadowingChoice + 1, Parameters!(choices[indexOfOvershadowingChoice])[0].stringof)); if (classInfo == typeid(CastClass)) { static if(is(ReturnType!(choice) == void)) { choice(cast(CastClass) switchObject); static if (areAllHandlersVoidResult) { return; } else { throw new SwitchError("Handlers that return void should throw"); } } else { return choice(cast(CastClass) switchObject); } } } } // Checking for derived matches: foreach (choice; choices) { alias choiceParameterTypes = Parameters!choice; static if (choiceParameterTypes.length == 1) { if (auto castedObject = cast(choiceParameterTypes[0]) switchObject) { static if(is(ReturnType!(choice) == void)) { choice(castedObject); static if (areAllHandlersVoidResult) { return; } else { throw new SwitchError("Handlers that return void should throw"); } } else { return choice(castedObject); } } } } } else // If switchObject is null: { // Checking for null matches: foreach (index, choice; choices) { static if (Parameters!(choice).length == 0) { immutable indexOfOvershadowingChoice = indexOfFirstOvershadowingChoiceOnLast!(choices[0..index + 1]); // Check for overshadowing: static assert(indexOfOvershadowingChoice == index, "choice number %d(null reference) is overshadowed by choice number %d(null reference)".format( index + 1, indexOfOvershadowingChoice + 1)); if (switchObject is null) { static if(is(ReturnType!(choice) == void)) { choice(); static if (areAllHandlersVoidResult) { return; } else { throw new SwitchError("Handlers that return void should throw"); } } else { return choice(); } } } } } // In case nothing matched: throw new SwitchError("Input not matched by any choice"); } /// unittest { import std.algorithm.iteration : map; import std.format : format; class A { int a; this(int a) {this.a = a;} @property int i() { return a; } } interface I { } class B : I { } Object[] arr = [new A(1), new B(), null]; auto results = arr.map!(castSwitch!( (A a) => "A with a value of %d".format(a.a), (I i) => "derived from I", () => "null reference", ))(); // A is handled directly: assert(results[0] == "A with a value of 1"); // B has no handler - it is handled by the handler of I: assert(results[1] == "derived from I"); // null is handled by the null handler: assert(results[2] == "null reference"); } /// Using with void handlers: unittest { import std.exception : assertThrown; class A { } class B { } // Void handlers are allowed if they throw: assertThrown!Exception( new B().castSwitch!( (A a) => 1, (B d) { throw new Exception("B is not allowed!"); } )() ); // Void handlers are also allowed if all the handlers are void: new A().castSwitch!( (A a) { assert(true); }, (B b) { assert(false); }, )(); } unittest { import core.exception : SwitchError; import std.exception : assertThrown; interface I { } class A : I { } class B { } // Nothing matches: assertThrown!SwitchError((new A()).castSwitch!( (B b) => 1, () => 2, )()); // Choices with multiple arguments are not allowed: static assert(!__traits(compiles, (new A()).castSwitch!( (A a, B b) => 0, )())); // Only callable handlers allowed: static assert(!__traits(compiles, (new A()).castSwitch!( 1234, )())); // Only object arguments allowed: static assert(!__traits(compiles, (new A()).castSwitch!( (int x) => 0, )())); // Object overshadows regular classes: static assert(!__traits(compiles, (new A()).castSwitch!( (Object o) => 0, (A a) => 1, )())); // Object overshadows interfaces: static assert(!__traits(compiles, (new A()).castSwitch!( (Object o) => 0, (I i) => 1, )())); // No multiple null handlers allowed: static assert(!__traits(compiles, (new A()).castSwitch!( () => 0, () => 1, )())); // No non-throwing void handlers allowed(when there are non-void handlers): assertThrown!SwitchError((new A()).castSwitch!( (A a) {}, (B b) => 2, )()); // All-void handlers work for the null case: null.castSwitch!( (Object o) { assert(false); }, () { assert(true); }, )(); // Throwing void handlers work for the null case: assertThrown!Exception(null.castSwitch!( (Object o) => 1, () { throw new Exception("null"); }, )()); } /** Clamps a value into the given bounds. This functions is equivalent to $(D max(lower, min(upper,val))). Params: val = The value to _clamp. lower = The _lower bound of the _clamp. upper = The _upper bound of the _clamp. Returns: Returns $(D val), if it is between $(D lower) and $(D upper). Otherwise returns the nearest of the two. */ auto clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper) in { import std.functional : greaterThan; assert(!lower.greaterThan(upper)); } body { return max(lower, min(upper, val)); } /// @safe unittest { assert(clamp(2, 1, 3) == 2); assert(clamp(0, 1, 3) == 1); assert(clamp(4, 1, 3) == 3); assert(clamp(1, 1, 1) == 1); assert(clamp(5, -1, 2u) == 2); } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int a = 1; short b = 6; double c = 2; static assert(is(typeof(clamp(c,a,b)) == double)); assert(clamp(c, a, b) == c); assert(clamp(a-c, a, b) == a); assert(clamp(b+c, a, b) == b); // mixed sign a = -5; uint f = 5; static assert(is(typeof(clamp(f, a, b)) == int)); assert(clamp(f, a, b) == f); // similar type deduction for (u)long static assert(is(typeof(clamp(-1L, -2L, 2UL)) == long)); // user-defined types import std.datetime : Date; assert(clamp(Date(1982, 1, 4), Date(1012, 12, 21), Date(2012, 12, 21)) == Date(1982, 1, 4)); assert(clamp(Date(1982, 1, 4), Date.min, Date.max) == Date(1982, 1, 4)); // UFCS style assert(Date(1982, 1, 4).clamp(Date.min, Date.max) == Date(1982, 1, 4)); } // cmp /********************************** Performs three-way lexicographical comparison on two input ranges according to predicate $(D pred). Iterating $(D r1) and $(D r2) in lockstep, $(D cmp) compares each element $(D e1) of $(D r1) with the corresponding element $(D e2) in $(D r2). If one of the ranges has been finished, $(D cmp) returns a negative value if $(D r1) has fewer elements than $(D r2), a positive value if $(D r1) has more elements than $(D r2), and $(D 0) if the ranges have the same number of elements. If the ranges are strings, $(D cmp) performs UTF decoding appropriately and compares the ranges one code point at a time. Params: pred = The predicate used for comparison. r1 = The first range. r2 = The second range. Returns: 0 if both ranges compare equal. -1 if the first differing element of $(D r1) is less than the corresponding element of $(D r2) according to $(D pred). 1 if the first differing element of $(D r2) is less than the corresponding element of $(D r1) according to $(D pred). */ int cmp(alias pred = "a < b", R1, R2)(R1 r1, R2 r2) if (isInputRange!R1 && isInputRange!R2 && !(isSomeString!R1 && isSomeString!R2)) { for (;; r1.popFront(), r2.popFront()) { if (r1.empty) return -cast(int)!r2.empty; if (r2.empty) return !r1.empty; auto a = r1.front, b = r2.front; if (binaryFun!pred(a, b)) return -1; if (binaryFun!pred(b, a)) return 1; } } /// ditto int cmp(alias pred = "a < b", R1, R2)(R1 r1, R2 r2) if (isSomeString!R1 && isSomeString!R2) { import core.stdc.string : memcmp; import std.utf : decode; static if (is(typeof(pred) : string)) enum isLessThan = pred == "a < b"; else enum isLessThan = false; // For speed only static int threeWay(size_t a, size_t b) { static if (size_t.sizeof == int.sizeof && isLessThan) return a - b; else return binaryFun!pred(b, a) ? 1 : binaryFun!pred(a, b) ? -1 : 0; } // For speed only // @@@BUG@@@ overloading should be allowed for nested functions static int threeWayInt(int a, int b) { static if (isLessThan) return a - b; else return binaryFun!pred(b, a) ? 1 : binaryFun!pred(a, b) ? -1 : 0; } static if (typeof(r1[0]).sizeof == typeof(r2[0]).sizeof && isLessThan) { static if (typeof(r1[0]).sizeof == 1) { immutable len = min(r1.length, r2.length); immutable result = __ctfe ? { foreach (i; 0 .. len) { if (r1[i] != r2[i]) return threeWayInt(r1[i], r2[i]); } return 0; }() : () @trusted { return memcmp(r1.ptr, r2.ptr, len); }(); if (result) return result; } else { auto p1 = r1.ptr, p2 = r2.ptr, pEnd = p1 + min(r1.length, r2.length); for (; p1 != pEnd; ++p1, ++p2) { if (*p1 != *p2) return threeWayInt(cast(int) *p1, cast(int) *p2); } } return threeWay(r1.length, r2.length); } else { for (size_t i1, i2;;) { if (i1 == r1.length) return threeWay(i2, r2.length); if (i2 == r2.length) return threeWay(r1.length, i1); immutable c1 = decode(r1, i1), c2 = decode(r2, i2); if (c1 != c2) return threeWayInt(cast(int) c1, cast(int) c2); } } } /// @safe unittest { int result; result = cmp("abc", "abc"); assert(result == 0); result = cmp("", ""); assert(result == 0); result = cmp("abc", "abcd"); assert(result < 0); result = cmp("abcd", "abc"); assert(result > 0); result = cmp("abc"d, "abd"); assert(result < 0); result = cmp("bbc", "abc"w); assert(result > 0); result = cmp("aaa", "aaaa"d); assert(result < 0); result = cmp("aaaa", "aaa"d); assert(result > 0); result = cmp("aaa", "aaa"d); assert(result == 0); result = cmp(cast(int[])[], cast(int[])[]); assert(result == 0); result = cmp([1, 2, 3], [1, 2, 3]); assert(result == 0); result = cmp([1, 3, 2], [1, 2, 3]); assert(result > 0); result = cmp([1, 2, 3], [1L, 2, 3, 4]); assert(result < 0); result = cmp([1L, 2, 3], [1, 2]); assert(result > 0); } // equal /** Compares two ranges for equality, as defined by predicate $(D pred) (which is $(D ==) by default). */ template equal(alias pred = "a == b") { /++ This function compares to ranges for equality. The ranges may have different element types, as long as $(D pred(a, b)) evaluates to $(D bool) for $(D a) in $(D r1) and $(D b) in $(D r2). Performs $(BIGOH min(r1.length, r2.length)) evaluations of $(D pred). Params: r1 = The first range to be compared. r2 = The second range to be compared. Returns: $(D true) if and only if the two ranges compare equal element for element, according to binary predicate $(D pred). See_Also: $(WEB sgi.com/tech/stl/_equal.html, STL's _equal) +/ bool equal(Range1, Range2)(Range1 r1, Range2 r2) if (isInputRange!Range1 && isInputRange!Range2 && is(typeof(binaryFun!pred(r1.front, r2.front)))) { //Start by detecting default pred and compatible dynamicarray. static if (is(typeof(pred) == string) && pred == "a == b" && isArray!Range1 && isArray!Range2 && is(typeof(r1 == r2))) { return r1 == r2; } //Try a fast implementation when the ranges have comparable lengths else static if (hasLength!Range1 && hasLength!Range2 && is(typeof(r1.length == r2.length))) { auto len1 = r1.length; auto len2 = r2.length; if (len1 != len2) return false; //Short circuit return //Lengths are the same, so we need to do an actual comparison //Good news is we can sqeeze out a bit of performance by not checking if r2 is empty for (; !r1.empty; r1.popFront(), r2.popFront()) { if (!binaryFun!(pred)(r1.front, r2.front)) return false; } return true; } else { //Generic case, we have to walk both ranges making sure neither is empty for (; !r1.empty; r1.popFront(), r2.popFront()) { if (r2.empty) return false; if (!binaryFun!(pred)(r1.front, r2.front)) return false; } return r2.empty; } } } /// @safe unittest { import std.math : approxEqual; import std.algorithm : equal; int[] a = [ 1, 2, 4, 3 ]; assert(!equal(a, a[1..$])); assert(equal(a, a)); // different types double[] b = [ 1.0, 2, 4, 3]; assert(!equal(a, b[1..$])); assert(equal(a, b)); // predicated: ensure that two vectors are approximately equal double[] c = [ 1.005, 2, 4, 3]; assert(equal!approxEqual(b, c)); } /++ Tip: $(D equal) can itself be used as a predicate to other functions. This can be very useful when the element type of a range is itself a range. In particular, $(D equal) can be its own predicate, allowing range of range (of range...) comparisons. +/ @safe unittest { import std.range : iota, chunks; import std.algorithm : equal; assert(equal!(equal!equal)( [[[0, 1], [2, 3]], [[4, 5], [6, 7]]], iota(0, 8).chunks(2).chunks(2) )); } @safe unittest { import std.algorithm.iteration : map; import std.math : approxEqual; import std.internal.test.dummyrange : ReferenceForwardRange, ReferenceInputRange, ReferenceInfiniteForwardRange; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); // various strings assert(equal("æøå", "æøå")); //UTF8 vs UTF8 assert(!equal("???", "æøå")); //UTF8 vs UTF8 assert(equal("æøå"w, "æøå"d)); //UTF16 vs UTF32 assert(!equal("???"w, "æøå"d));//UTF16 vs UTF32 assert(equal("æøå"d, "æøå"d)); //UTF32 vs UTF32 assert(!equal("???"d, "æøå"d));//UTF32 vs UTF32 assert(!equal("hello", "world")); // same strings, but "explicit non default" comparison (to test the non optimized array comparison) assert( equal!("a == b")("æøå", "æøå")); //UTF8 vs UTF8 assert(!equal!("a == b")("???", "æøå")); //UTF8 vs UTF8 assert( equal!("a == b")("æøå"w, "æøå"d)); //UTF16 vs UTF32 assert(!equal!("a == b")("???"w, "æøå"d));//UTF16 vs UTF32 assert( equal!("a == b")("æøå"d, "æøå"d)); //UTF32 vs UTF32 assert(!equal!("a == b")("???"d, "æøå"d));//UTF32 vs UTF32 assert(!equal!("a == b")("hello", "world")); //Array of string assert(equal(["hello", "world"], ["hello", "world"])); assert(!equal(["hello", "world"], ["hello"])); assert(!equal(["hello", "world"], ["hello", "Bob!"])); //Should not compile, because "string == dstring" is illegal static assert(!is(typeof(equal(["hello", "world"], ["hello"d, "world"d])))); //However, arrays of non-matching string can be compared using equal!equal. Neat-o! equal!equal(["hello", "world"], ["hello"d, "world"d]); //Tests, with more fancy map ranges int[] a = [ 1, 2, 4, 3 ]; assert(equal([2, 4, 8, 6], map!"a*2"(a))); double[] b = [ 1.0, 2, 4, 3]; double[] c = [ 1.005, 2, 4, 3]; assert(equal!approxEqual(map!"a*2"(b), map!"a*2"(c))); assert(!equal([2, 4, 1, 3], map!"a*2"(a))); assert(!equal([2, 4, 1], map!"a*2"(a))); assert(!equal!approxEqual(map!"a*3"(b), map!"a*2"(c))); //Tests with some fancy reference ranges. ReferenceInputRange!int cir = new ReferenceInputRange!int([1, 2, 4, 3]); ReferenceForwardRange!int cfr = new ReferenceForwardRange!int([1, 2, 4, 3]); assert(equal(cir, a)); cir = new ReferenceInputRange!int([1, 2, 4, 3]); assert(equal(cir, cfr.save)); assert(equal(cfr.save, cfr.save)); cir = new ReferenceInputRange!int([1, 2, 8, 1]); assert(!equal(cir, cfr)); //Test with an infinte range ReferenceInfiniteForwardRange!int ifr = new ReferenceInfiniteForwardRange!int; assert(!equal(a, ifr)); } // MaxType private template MaxType(T...) if (T.length >= 1) { static if (T.length == 1) { alias MaxType = T[0]; } else static if (T.length == 2) { static if (!is(typeof(T[0].min))) alias MaxType = CommonType!T; else static if (T[1].max > T[0].max) alias MaxType = T[1]; else alias MaxType = T[0]; } else { alias MaxType = MaxType!(MaxType!(T[0 .. ($+1)/2]), MaxType!(T[($+1)/2 .. $])); } } // levenshteinDistance /** Encodes $(WEB realityinteractive.com/rgrzywinski/archives/000249.html, edit operations) necessary to transform one sequence into another. Given sequences $(D s) (source) and $(D t) (target), a sequence of $(D EditOp) encodes the steps that need to be taken to convert $(D s) into $(D t). For example, if $(D s = "cat") and $(D "cars"), the minimal sequence that transforms $(D s) into $(D t) is: skip two characters, replace 't' with 'r', and insert an 's'. Working with edit operations is useful in applications such as spell-checkers (to find the closest word to a given misspelled word), approximate searches, diff-style programs that compute the difference between files, efficient encoding of patches, DNA sequence analysis, and plagiarism detection. */ enum EditOp : char { /** Current items are equal; no editing is necessary. */ none = 'n', /** Substitute current item in target with current item in source. */ substitute = 's', /** Insert current item from the source into the target. */ insert = 'i', /** Remove current item from the target. */ remove = 'r' } private struct Levenshtein(Range, alias equals, CostType = size_t) { EditOp[] path() { import std.algorithm.mutation : reverse; EditOp[] result; size_t i = rows - 1, j = cols - 1; // restore the path while (i || j) { auto cIns = j == 0 ? CostType.max : matrix(i,j - 1); auto cDel = i == 0 ? CostType.max : matrix(i - 1,j); auto cSub = i == 0 || j == 0 ? CostType.max : matrix(i - 1,j - 1); switch (min_index(cSub, cIns, cDel)) { case 0: result ~= matrix(i - 1,j - 1) == matrix(i,j) ? EditOp.none : EditOp.substitute; --i; --j; break; case 1: result ~= EditOp.insert; --j; break; default: result ~= EditOp.remove; --i; break; } } reverse(result); return result; } ~this() { FreeMatrix(); } private: CostType _deletionIncrement = 1, _insertionIncrement = 1, _substitutionIncrement = 1; CostType[] _matrix; size_t rows, cols; // Treat _matrix as a rectangular array ref CostType matrix(size_t row, size_t col) { return _matrix[row * cols + col]; } void AllocMatrix(size_t r, size_t c) @trusted { rows = r; cols = c; if (_matrix.length < r * c) { import core.stdc.stdlib : realloc; import core.exception : onOutOfMemoryError; auto m = cast(CostType *)realloc(_matrix.ptr, r * c * _matrix[0].sizeof); if (!m) onOutOfMemoryError(); _matrix = m[0 .. r * c]; InitMatrix(); } } void FreeMatrix() @trusted { import core.stdc.stdlib : free; free(_matrix.ptr); _matrix = null; } void InitMatrix() { foreach (r; 0 .. rows) matrix(r,0) = r * _deletionIncrement; foreach (c; 0 .. cols) matrix(0,c) = c * _insertionIncrement; } static uint min_index(CostType i0, CostType i1, CostType i2) { if (i0 <= i1) { return i0 <= i2 ? 0 : 2; } else { return i1 <= i2 ? 1 : 2; } } CostType distanceWithPath(Range s, Range t) { auto slen = walkLength(s.save), tlen = walkLength(t.save); AllocMatrix(slen + 1, tlen + 1); foreach (i; 1 .. rows) { auto sfront = s.front; auto tt = t.save; foreach (j; 1 .. cols) { auto cSub = matrix(i - 1,j - 1) + (equals(sfront, tt.front) ? 0 : _substitutionIncrement); tt.popFront(); auto cIns = matrix(i,j - 1) + _insertionIncrement; auto cDel = matrix(i - 1,j) + _deletionIncrement; switch (min_index(cSub, cIns, cDel)) { case 0: matrix(i,j) = cSub; break; case 1: matrix(i,j) = cIns; break; default: matrix(i,j) = cDel; break; } } s.popFront(); } return matrix(slen,tlen); } CostType distanceLowMem(Range s, Range t, CostType slen, CostType tlen) { CostType lastdiag, olddiag; AllocMatrix(slen + 1, 1); foreach (y; 1 .. slen + 1) { _matrix[y] = y; } foreach (x; 1 .. tlen + 1) { auto tfront = t.front; auto ss = s.save; _matrix[0] = x; lastdiag = x - 1; foreach (y; 1 .. rows) { olddiag = _matrix[y]; auto cSub = lastdiag + (equals(ss.front, tfront) ? 0 : _substitutionIncrement); ss.popFront(); auto cIns = _matrix[y - 1] + _insertionIncrement; auto cDel = _matrix[y] + _deletionIncrement; switch (min_index(cSub, cIns, cDel)) { case 0: _matrix[y] = cSub; break; case 1: _matrix[y] = cIns; break; default: _matrix[y] = cDel; break; } lastdiag = olddiag; } t.popFront(); } return _matrix[slen]; } } /** Returns the $(WEB wikipedia.org/wiki/Levenshtein_distance, Levenshtein distance) between $(D s) and $(D t). The Levenshtein distance computes the minimal amount of edit operations necessary to transform $(D s) into $(D t). Performs $(BIGOH s.length * t.length) evaluations of $(D equals) and occupies $(BIGOH s.length * t.length) storage. Params: equals = The binary predicate to compare the elements of the two ranges. s = The original range. t = The transformation target Returns: The minimal number of edits to transform s into t. Does not allocate GC memory. */ size_t levenshteinDistance(alias equals = (a,b) => a == b, Range1, Range2) (Range1 s, Range2 t) if (isForwardRange!(Range1) && isForwardRange!(Range2)) { alias eq = binaryFun!(equals); for (;;) { if (s.empty) return t.walkLength; if (t.empty) return s.walkLength; if (eq(s.front, t.front)) { s.popFront(); t.popFront(); continue; } static if (isBidirectionalRange!(Range1) && isBidirectionalRange!(Range2)) { if (eq(s.back, t.back)) { s.popBack(); t.popBack(); continue; } } break; } auto slen = walkLength(s.save); auto tlen = walkLength(t.save); if (slen == 1 && tlen == 1) { return eq(s.front, t.front) ? 0 : 1; } if (slen > tlen) { Levenshtein!(Range1, eq, size_t) lev; return lev.distanceLowMem(s, t, slen, tlen); } else { Levenshtein!(Range2, eq, size_t) lev; return lev.distanceLowMem(t, s, tlen, slen); } } /// @safe unittest { import std.algorithm.iteration : filter; import std.uni : toUpper; assert(levenshteinDistance("cat", "rat") == 1); assert(levenshteinDistance("parks", "spark") == 2); assert(levenshteinDistance("abcde", "abcde") == 0); assert(levenshteinDistance("abcde", "abCde") == 1); assert(levenshteinDistance("kitten", "sitting") == 3); assert(levenshteinDistance!((a, b) => toUpper(a) == toUpper(b)) ("parks", "SPARK") == 2); assert(levenshteinDistance("parks".filter!"true", "spark".filter!"true") == 2); assert(levenshteinDistance("ID", "I♥D") == 1); } @safe @nogc nothrow unittest { assert(levenshteinDistance("cat"d, "rat"d) == 1); } // compat overload for alias this strings size_t levenshteinDistance(alias equals = (a,b) => a == b, Range1, Range2) (auto ref Range1 s, auto ref Range2 t) if (isConvertibleToString!Range1 || isConvertibleToString!Range2) { import std.meta : staticMap; alias Types = staticMap!(convertToString, Range1, Range2); return levenshteinDistance!(equals, Types)(s, t); } @safe unittest { static struct S { string s; alias s this; } assert(levenshteinDistance(S("cat"), S("rat")) == 1); assert(levenshteinDistance("cat", S("rat")) == 1); assert(levenshteinDistance(S("cat"), "rat") == 1); } @safe @nogc nothrow unittest { static struct S { dstring s; alias s this; } assert(levenshteinDistance(S("cat"d), S("rat"d)) == 1); assert(levenshteinDistance("cat"d, S("rat"d)) == 1); assert(levenshteinDistance(S("cat"d), "rat"d) == 1); } /** Returns the Levenshtein distance and the edit path between $(D s) and $(D t). Params: equals = The binary predicate to compare the elements of the two ranges. s = The original range. t = The transformation target Returns: Tuple with the first element being the minimal amount of edits to transform s into t and the second element being the sequence of edits to effect this transformation. Allocates GC memory for the returned EditOp[] array. */ Tuple!(size_t, EditOp[]) levenshteinDistanceAndPath(alias equals = (a,b) => a == b, Range1, Range2) (Range1 s, Range2 t) if (isForwardRange!(Range1) && isForwardRange!(Range2)) { Levenshtein!(Range1, binaryFun!(equals)) lev; auto d = lev.distanceWithPath(s, t); return tuple(d, lev.path()); } /// @safe unittest { string a = "Saturday", b = "Sundays"; auto p = levenshteinDistanceAndPath(a, b); assert(p[0] == 4); assert(equal(p[1], "nrrnsnnni")); } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); assert(levenshteinDistance("a", "a") == 0); assert(levenshteinDistance("a", "b") == 1); assert(levenshteinDistance("aa", "ab") == 1); assert(levenshteinDistance("aa", "abc") == 2); assert(levenshteinDistance("Saturday", "Sunday") == 3); assert(levenshteinDistance("kitten", "sitting") == 3); } // compat overload for alias this strings Tuple!(size_t, EditOp[]) levenshteinDistanceAndPath(alias equals = (a,b) => a == b, Range1, Range2) (auto ref Range1 s, auto ref Range2 t) if (isConvertibleToString!Range1 || isConvertibleToString!Range2) { import std.meta : staticMap; alias Types = staticMap!(convertToString, Range1, Range2); return levenshteinDistanceAndPath!(equals, Types)(s, t); } @safe unittest { static struct S { string s; alias s this; } assert(levenshteinDistanceAndPath(S("cat"), S("rat"))[0] == 1); assert(levenshteinDistanceAndPath("cat", S("rat"))[0] == 1); assert(levenshteinDistanceAndPath(S("cat"), "rat")[0] == 1); } // max /** Iterates the passed arguments and return the maximum value. Params: args = The values to select the maximum from. At least two arguments must be passed. Returns: The maximum of the passed-in args. The type of the returned value is the type among the passed arguments that is able to store the largest value. */ MaxType!T max(T...)(T args) if (T.length >= 2) { //Get "a" static if (T.length <= 2) alias a = args[0]; else auto a = max(args[0 .. ($+1)/2]); alias T0 = typeof(a); //Get "b" static if (T.length <= 3) alias b = args[$-1]; else auto b = max(args[($+1)/2 .. $]); alias T1 = typeof(b); import std.algorithm.internal : algoFormat; static assert (is(typeof(a < b)), algoFormat("Invalid arguments: Cannot compare types %s and %s.", T0.stringof, T1.stringof)); //Do the "max" proper with a and b import std.functional : lessThan; immutable chooseB = lessThan!(T0, T1)(a, b); return cast(typeof(return)) (chooseB ? b : a); } /// @safe unittest { int a = 5; short b = 6; double c = 2; auto d = max(a, b); assert(is(typeof(d) == int)); assert(d == 6); auto e = min(a, b, c); assert(is(typeof(e) == double)); assert(e == 2); } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int a = 5; short b = 6; double c = 2; auto d = max(a, b); static assert(is(typeof(d) == int)); assert(d == 6); auto e = max(a, b, c); static assert(is(typeof(e) == double)); assert(e == 6); // mixed sign a = -5; uint f = 5; static assert(is(typeof(max(a, f)) == uint)); assert(max(a, f) == 5); //Test user-defined types import std.datetime : Date; assert(max(Date(2012, 12, 21), Date(1982, 1, 4)) == Date(2012, 12, 21)); assert(max(Date(1982, 1, 4), Date(2012, 12, 21)) == Date(2012, 12, 21)); assert(max(Date(1982, 1, 4), Date.min) == Date(1982, 1, 4)); assert(max(Date.min, Date(1982, 1, 4)) == Date(1982, 1, 4)); assert(max(Date(1982, 1, 4), Date.max) == Date.max); assert(max(Date.max, Date(1982, 1, 4)) == Date.max); assert(max(Date.min, Date.max) == Date.max); assert(max(Date.max, Date.min) == Date.max); } // MinType private template MinType(T...) if (T.length >= 1) { static if (T.length == 1) { alias MinType = T[0]; } else static if (T.length == 2) { static if (!is(typeof(T[0].min))) alias MinType = CommonType!T; else { enum hasMostNegative = is(typeof(mostNegative!(T[0]))) && is(typeof(mostNegative!(T[1]))); static if (hasMostNegative && mostNegative!(T[1]) < mostNegative!(T[0])) alias MinType = T[1]; else static if (hasMostNegative && mostNegative!(T[1]) > mostNegative!(T[0])) alias MinType = T[0]; else static if (T[1].max < T[0].max) alias MinType = T[1]; else alias MinType = T[0]; } } else { alias MinType = MinType!(MinType!(T[0 .. ($+1)/2]), MinType!(T[($+1)/2 .. $])); } } // min /** Iterates the passed arguments and returns the minimum value. Params: args = The values to select the minimum from. At least two arguments must be passed, and they must be comparable with `<`. Returns: The minimum of the passed-in values. */ MinType!T min(T...)(T args) if (T.length >= 2) { //Get "a" static if (T.length <= 2) alias a = args[0]; else auto a = min(args[0 .. ($+1)/2]); alias T0 = typeof(a); //Get "b" static if (T.length <= 3) alias b = args[$-1]; else auto b = min(args[($+1)/2 .. $]); alias T1 = typeof(b); import std.algorithm.internal : algoFormat; static assert (is(typeof(a < b)), algoFormat("Invalid arguments: Cannot compare types %s and %s.", T0.stringof, T1.stringof)); //Do the "min" proper with a and b import std.functional : lessThan; immutable chooseA = lessThan!(T0, T1)(a, b); return cast(typeof(return)) (chooseA ? a : b); } /// @safe unittest { int a = 5; short b = 6; double c = 2; auto d = min(a, b); static assert(is(typeof(d) == int)); assert(d == 5); auto e = min(a, b, c); static assert(is(typeof(e) == double)); assert(e == 2); // With arguments of mixed signedness, the return type is the one that can // store the lowest values. a = -10; uint f = 10; static assert(is(typeof(min(a, f)) == int)); assert(min(a, f) == -10); // User-defined types that support comparison with < are supported. import std.datetime; assert(min(Date(2012, 12, 21), Date(1982, 1, 4)) == Date(1982, 1, 4)); assert(min(Date(1982, 1, 4), Date(2012, 12, 21)) == Date(1982, 1, 4)); assert(min(Date(1982, 1, 4), Date.min) == Date.min); assert(min(Date.min, Date(1982, 1, 4)) == Date.min); assert(min(Date(1982, 1, 4), Date.max) == Date(1982, 1, 4)); assert(min(Date.max, Date(1982, 1, 4)) == Date(1982, 1, 4)); assert(min(Date.min, Date.max) == Date.min); assert(min(Date.max, Date.min) == Date.min); } // mismatch /** Sequentially compares elements in $(D r1) and $(D r2) in lockstep, and stops at the first mismatch (according to $(D pred), by default equality). Returns a tuple with the reduced ranges that start with the two mismatched values. Performs $(BIGOH min(r1.length, r2.length)) evaluations of $(D pred). See_Also: $(WEB sgi.com/tech/stl/_mismatch.html, STL's _mismatch) */ Tuple!(Range1, Range2) mismatch(alias pred = "a == b", Range1, Range2)(Range1 r1, Range2 r2) if (isInputRange!(Range1) && isInputRange!(Range2)) { for (; !r1.empty && !r2.empty; r1.popFront(), r2.popFront()) { if (!binaryFun!(pred)(r1.front, r2.front)) break; } return tuple(r1, r2); } /// @safe unittest { int[] x = [ 1, 5, 2, 7, 4, 3 ]; double[] y = [ 1.0, 5, 2, 7.3, 4, 8 ]; auto m = mismatch(x, y); assert(m[0] == x[3 .. $]); assert(m[1] == y[3 .. $]); } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 1, 2, 3 ]; int[] b = [ 1, 2, 4, 5 ]; auto mm = mismatch(a, b); assert(mm[0] == [3]); assert(mm[1] == [4, 5]); } /** Returns one of a collection of expressions based on the value of the switch expression. $(D choices) needs to be composed of pairs of test expressions and return expressions. Each test-expression is compared with $(D switchExpression) using $(D pred)($(D switchExpression) is the first argument) and if that yields true - the return expression is returned. Both the test and the return expressions are lazily evaluated. Params: switchExpression = The first argument for the predicate. choices = Pairs of test expressions and return expressions. The test expressions will be the second argument for the predicate, and the return expression will be returned if the predicate yields true with $(D switchExpression) and the test expression as arguments. May also have a default return expression, that needs to be the last expression without a test expression before it. A return expression may be of void type only if it always throws. Returns: The return expression associated with the first test expression that made the predicate yield true, or the default return expression if no test expression matched. Throws: If there is no default return expression and the predicate does not yield true with any test expression - $(D SwitchError) is thrown. $(D SwitchError) is also thrown if a void return expression was executed without throwing anything. */ auto predSwitch(alias pred = "a == b", T, R ...)(T switchExpression, lazy R choices) { import core.exception : SwitchError; alias predicate = binaryFun!(pred); foreach (index, ChoiceType; R) { //The even places in `choices` are for the predicate. static if (index % 2 == 1) { if (predicate(switchExpression, choices[index - 1]())) { static if (is(typeof(choices[index]()) == void)) { choices[index](); throw new SwitchError("Choices that return void should throw"); } else { return choices[index](); } } } } //In case nothing matched: static if (R.length % 2 == 1) //If there is a default return expression: { static if (is(typeof(choices[$ - 1]()) == void)) { choices[$ - 1](); throw new SwitchError("Choices that return void should throw"); } else { return choices[$ - 1](); } } else //If there is no default return expression: { throw new SwitchError("Input not matched by any pattern"); } } /// @safe unittest { string res = 2.predSwitch!"a < b"( 1, "less than 1", 5, "less than 5", 10, "less than 10", "greater or equal to 10"); assert(res == "less than 5"); //The arguments are lazy, which allows us to use predSwitch to create //recursive functions: int factorial(int n) { return n.predSwitch!"a <= b"( -1, {throw new Exception("Can not calculate n! for n < 0");}(), 0, 1, // 0! = 1 n * factorial(n - 1) // n! = n * (n - 1)! for n >= 0 ); } assert(factorial(3) == 6); //Void return expressions are allowed if they always throw: import std.exception : assertThrown; assertThrown!Exception(factorial(-9)); } unittest { import core.exception : SwitchError; import std.exception : assertThrown; //Nothing matches - with default return expression: assert(20.predSwitch!"a < b"( 1, "less than 1", 5, "less than 5", 10, "less than 10", "greater or equal to 10") == "greater or equal to 10"); //Nothing matches - without default return expression: assertThrown!SwitchError(20.predSwitch!"a < b"( 1, "less than 1", 5, "less than 5", 10, "less than 10", )); //Using the default predicate: assert(2.predSwitch( 1, "one", 2, "two", 3, "three", ) == "two"); //Void return expressions must always throw: assertThrown!SwitchError(1.predSwitch( 0, "zero", 1, {}(), //A void return expression that doesn't throw 2, "two", )); } /** Checks if the two ranges have the same number of elements. This function is optimized to always take advantage of the $(D length) member of either range if it exists. If both ranges have a length member, this function is $(BIGOH 1). Otherwise, this function is $(BIGOH min(r1.length, r2.length)). Params: r1 = a finite input range r2 = a finite input range Returns: $(D true) if both ranges have the same length, $(D false) otherwise. */ bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2) { static if (hasLength!(Range1) && hasLength!(Range2)) { return r1.length == r2.length; } else static if (hasLength!(Range1) && !hasLength!(Range2)) { size_t length; while (!r2.empty) { r2.popFront; if (++length > r1.length) { return false; } } return !(length < r1.length); } else static if (!hasLength!(Range1) && hasLength!(Range2)) { size_t length; while (!r1.empty) { r1.popFront; if (++length > r2.length) { return false; } } return !(length < r2.length); } else { while (!r1.empty) { if (r2.empty) { return false; } r1.popFront; r2.popFront; } return r2.empty; } } /// @safe nothrow pure unittest { assert(isSameLength([1, 2, 3], [4, 5, 6])); assert(isSameLength([0.3, 90.4, 23.7, 119.2], [42.6, 23.6, 95.5, 6.3])); assert(isSameLength("abc", "xyz")); int[] a; int[] b; assert(isSameLength(a, b)); assert(!isSameLength([1, 2, 3], [4, 5])); assert(!isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3])); assert(!isSameLength("abcd", "xyz")); } // Test CTFE @safe pure unittest { enum result1 = isSameLength([1, 2, 3], [4, 5, 6]); static assert(result1); enum result2 = isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3]); static assert(!result2); } @safe nothrow pure unittest { import std.internal.test.dummyrange; auto r1 = new ReferenceInputRange!int([1, 2, 3]); auto r2 = new ReferenceInputRange!int([4, 5, 6]); assert(isSameLength(r1, r2)); auto r3 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r4; assert(isSameLength(r3, r4)); DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r5; auto r6 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); assert(isSameLength(r5, r6)); auto r7 = new ReferenceInputRange!int([1, 2]); auto r8 = new ReferenceInputRange!int([4, 5, 6]); assert(!isSameLength(r7, r8)); auto r9 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8]); DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r10; assert(!isSameLength(r9, r10)); DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input) r11; auto r12 = new ReferenceInputRange!int([1, 2, 3, 4, 5, 6, 7, 8]); assert(!isSameLength(r11, r12)); } /// For convenience alias AllocateGC = Flag!"allocateGC"; /** Checks if both ranges are permutations of each other. This function can allocate if the $(D AllocateGC.yes) flag is passed. This has the benefit of have better complexity than the $(D AllocateGC.no) option. However, this option is only available for ranges whose equality can be determined via each element's $(D toHash) method. If customized equality is needed, then the $(D pred) template parameter can be passed, and the function will automatically switch to the non-allocating algorithm. See $(XREF functional,binaryFun) for more details on how to define $(D pred). Non-allocating forward range option: $(BIGOH n^2) Non-allocating forward range option with custom $(D pred): $(BIGOH n^2) Allocating forward range option: amortized $(BIGOH r1.length) + $(BIGOH r2.length) Params: pred = an optional parameter to change how equality is defined allocate_gc = AllocateGC.yes/no r1 = A finite forward range r2 = A finite forward range Returns: $(D true) if all of the elements in $(D r1) appear the same number of times in $(D r2). Otherwise, returns $(D false). */ bool isPermutation(AllocateGC allocate_gc, Range1, Range2) (Range1 r1, Range2 r2) if (allocate_gc == AllocateGC.yes && isForwardRange!Range1 && isForwardRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2) { alias E1 = Unqual!(ElementType!Range1); alias E2 = Unqual!(ElementType!Range2); if (!isSameLength(r1.save, r2.save)) { return false; } // Skip the elements at the beginning where r1.front == r2.front, // they are in the same order and don't need to be counted. while (!r1.empty && !r2.empty && r1.front == r2.front) { r1.popFront(); r2.popFront(); } if (r1.empty && r2.empty) { return true; } int[CommonType!(E1, E2)] counts; foreach (item; r1) { ++counts[item]; } foreach (item; r2) { if (--counts[item] < 0) { return false; } } return true; } /// ditto bool isPermutation(alias pred = "a == b", Range1, Range2) (Range1 r1, Range2 r2) if (is(typeof(binaryFun!(pred))) && isForwardRange!Range1 && isForwardRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2) { import std.algorithm.searching : count; alias predEquals = binaryFun!(pred); alias E1 = Unqual!(ElementType!Range1); alias E2 = Unqual!(ElementType!Range2); if (!isSameLength(r1.save, r2.save)) { return false; } // Skip the elements at the beginning where r1.front == r2.front, // they are in the same order and don't need to be counted. while (!r1.empty && !r2.empty && predEquals(r1.front, r2.front)) { r1.popFront(); r2.popFront(); } if (r1.empty && r2.empty) { return true; } size_t r1_count; size_t r2_count; // At each element item, when computing the count of item, scan it while // also keeping track of the scanning index. If the first occurrence // of item in the scanning loop has an index smaller than the current index, // then you know that the element has been seen before outloop: foreach (index, item; r1.save.enumerate) { r1_count = 0; r2_count = 0; foreach (i, e; r1.save.enumerate) { if (predEquals(e, item) && i < index) { continue outloop; } else if (predEquals(e, item)) { ++r1_count; } } r2_count = r2.save.count!pred(item); if (r1_count != r2_count) { return false; } } return true; } /// @safe pure unittest { assert(isPermutation([1, 2, 3], [3, 2, 1])); assert(isPermutation([1.1, 2.3, 3.5], [2.3, 3.5, 1.1])); assert(isPermutation("abc", "bca")); assert(!isPermutation([1, 2], [3, 4])); assert(!isPermutation([1, 1, 2, 3], [1, 2, 2, 3])); assert(!isPermutation([1, 1], [1, 1, 1])); // Faster, but allocates GC handled memory assert(isPermutation!(AllocateGC.yes)([1.1, 2.3, 3.5], [2.3, 3.5, 1.1])); assert(!isPermutation!(AllocateGC.yes)([1, 2], [3, 4])); } // Test @nogc inference @safe @nogc pure unittest { static immutable arr1 = [1, 2, 3]; static immutable arr2 = [3, 2, 1]; assert(isPermutation(arr1, arr2)); static immutable arr3 = [1, 1, 2, 3]; static immutable arr4 = [1, 2, 2, 3]; assert(!isPermutation(arr3, arr4)); } @safe pure unittest { import std.internal.test.dummyrange; auto r1 = new ReferenceForwardRange!int([1, 2, 3, 4]); auto r2 = new ReferenceForwardRange!int([1, 2, 4, 3]); assert(isPermutation(r1, r2)); auto r3 = new ReferenceForwardRange!int([1, 2, 3, 4]); auto r4 = new ReferenceForwardRange!int([4, 2, 1, 3]); assert(isPermutation!(AllocateGC.yes)(r3, r4)); auto r5 = new ReferenceForwardRange!int([1, 2, 3]); auto r6 = new ReferenceForwardRange!int([4, 2, 1, 3]); assert(!isPermutation(r5, r6)); auto r7 = new ReferenceForwardRange!int([4, 2, 1, 3]); auto r8 = new ReferenceForwardRange!int([1, 2, 3]); assert(!isPermutation!(AllocateGC.yes)(r7, r8)); DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r9; DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r10; assert(isPermutation(r9, r10)); DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r11; DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r12; assert(isPermutation!(AllocateGC.yes)(r11, r12)); alias mytuple = Tuple!(int, int); assert(isPermutation!"a[0] == b[0]"( [mytuple(1, 4), mytuple(2, 5)], [mytuple(2, 3), mytuple(1, 2)] )); } /** Get the _first argument `a` that passes an `if (unaryFun!pred(a))` test. If no argument passes the test, return the last argument. Similar to behaviour of the `or` operator in dynamic languages such as Lisp's `(or ...)` and Python's `a or b or ...` except that the last argument is returned upon no match. Simplifies logic, for instance, in parsing rules where a set of alternative matchers are tried. The _first one that matches returns it match result, typically as an abstract syntax tree (AST). Bugs: Lazy parameters are currently, too restrictively, inferred by DMD to always throw even though they don't need to be. This makes it impossible to currently mark `either` as `nothrow`. See issue at $(BUGZILLA 12647). Returns: The _first argument that passes the test `pred`. */ CommonType!(T, Ts) either(alias pred = a => a, T, Ts...)(T first, lazy Ts alternatives) if (alternatives.length >= 1 && !is(CommonType!(T, Ts) == void) && allSatisfy!(ifTestable, T, Ts)) { alias predFun = unaryFun!pred; if (predFun(first)) return first; foreach (e; alternatives[0 .. $ - 1]) if (predFun(e)) return e; return alternatives[$ - 1]; } /// @safe pure unittest { const a = 1; const b = 2; auto ab = either(a, b); static assert(is(typeof(ab) == const(int))); assert(ab == a); auto c = 2; const d = 3; auto cd = either!(a => a == 3)(c, d); // use predicate static assert(is(typeof(cd) == int)); assert(cd == d); auto e = 0; const f = 2; auto ef = either(e, f); static assert(is(typeof(ef) == int)); assert(ef == f); immutable p = 1; immutable q = 2; auto pq = either(p, q); static assert(is(typeof(pq) == immutable(int))); assert(pq == p); assert(either(3, 4) == 3); assert(either(0, 4) == 4); assert(either(0, 0) == 0); assert(either("", "a") == ""); string r = null; assert(either(r, "a") == "a"); assert(either("a", "") == "a"); immutable s = [1, 2]; assert(either(s, s) == s); assert(either([0, 1], [1, 2]) == [0, 1]); assert(either([0, 1], [1]) == [0, 1]); assert(either("a", "b") == "a"); static assert(!__traits(compiles, either(1, "a"))); static assert(!__traits(compiles, either(1.0, "a"))); static assert(!__traits(compiles, either('a', "a"))); } ldc-1.1.0-beta3-src/runtime/phobos/std/algorithm/package.d0000664000175000017500000001425212776215007021440 0ustar kaikai// Written in the D programming language. /** This package implements generic algorithms oriented towards the processing of sequences. Sequences processed by these functions define range-based interfaces. See also $(LINK2 std_range.html, Reference on ranges) and $(WEB ddili.org/ders/d.en/ranges.html, tutorial on ranges). $(SCRIPT inhibitQuickIndex = 1;) Algorithms are categorized into the following submodules: $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Submodule) $(TH Functions) ) $(TR $(TDNW Searching) $(TDNW $(SUBMODULE searching)) $(TD $(SUBREF searching, all) $(SUBREF searching, any) $(SUBREF searching, balancedParens) $(SUBREF searching, boyerMooreFinder) $(SUBREF searching, canFind) $(SUBREF searching, commonPrefix) $(SUBREF searching, count) $(SUBREF searching, countUntil) $(SUBREF searching, endsWith) $(SUBREF searching, find) $(SUBREF searching, findAdjacent) $(SUBREF searching, findAmong) $(SUBREF searching, findSkip) $(SUBREF searching, findSplit) $(SUBREF searching, findSplitAfter) $(SUBREF searching, findSplitBefore) $(SUBREF searching, minCount) $(SUBREF searching, maxCount) $(SUBREF searching, minPos) $(SUBREF searching, maxPos) $(SUBREF searching, skipOver) $(SUBREF searching, startsWith) $(SUBREF searching, until) ) ) $(TR $(TDNW Comparison) $(TDNW $(SUBMODULE comparison)) $(TD $(SUBREF comparison, among) $(SUBREF comparison, castSwitch) $(SUBREF comparison, clamp) $(SUBREF comparison, cmp) $(SUBREF comparison, either) $(SUBREF comparison, equal) $(SUBREF comparison, isPermutation) $(SUBREF comparison, isSameLength) $(SUBREF comparison, levenshteinDistance) $(SUBREF comparison, levenshteinDistanceAndPath) $(SUBREF comparison, max) $(SUBREF comparison, min) $(SUBREF comparison, mismatch) $(SUBREF comparison, predSwitch) ) ) $(TR $(TDNW Iteration) $(TDNW $(SUBMODULE iteration)) $(TD $(SUBREF iteration, cache) $(SUBREF iteration, cacheBidirectional) $(SUBREF iteration, chunkBy) $(SUBREF iteration, each) $(SUBREF iteration, filter) $(SUBREF iteration, filterBidirectional) $(SUBREF iteration, fold) $(SUBREF iteration, group) $(SUBREF iteration, joiner) $(SUBREF iteration, map) $(SUBREF iteration, permutations) $(SUBREF iteration, reduce) $(SUBREF iteration, splitter) $(SUBREF iteration, sum) $(SUBREF iteration, uniq) ) ) $(TR $(TDNW Sorting) $(TDNW $(SUBMODULE sorting)) $(TD $(SUBREF sorting, completeSort) $(SUBREF sorting, isPartitioned) $(SUBREF sorting, isSorted) $(SUBREF sorting, makeIndex) $(SUBREF sorting, multiSort) $(SUBREF sorting, nextEvenPermutation) $(SUBREF sorting, nextPermutation) $(SUBREF sorting, partialSort) $(SUBREF sorting, partition) $(SUBREF sorting, partition3) $(SUBREF sorting, schwartzSort) $(SUBREF sorting, sort) $(SUBREF sorting, topN) $(SUBREF sorting, topNCopy) $(SUBREF sorting, topNIndex) ) ) $(TR $(TDNW Set operations) $(TDNW $(SUBMODULE setops)) $(TD $(SUBREF setops, cartesianProduct) $(SUBREF setops, largestPartialIntersection) $(SUBREF setops, largestPartialIntersectionWeighted) $(SUBREF setops, nWayUnion) $(SUBREF setops, setDifference) $(SUBREF setops, setIntersection) $(SUBREF setops, setSymmetricDifference) $(SUBREF setops, setUnion) ) ) $(TR $(TDNW Mutation) $(TDNW $(SUBMODULE mutation)) $(TD $(SUBREF mutation, bringToFront) $(SUBREF mutation, copy) $(SUBREF mutation, fill) $(SUBREF mutation, initializeAll) $(SUBREF mutation, move) $(SUBREF mutation, moveAll) $(SUBREF mutation, moveSome) $(SUBREF mutation, remove) $(SUBREF mutation, reverse) $(SUBREF mutation, strip) $(SUBREF mutation, stripLeft) $(SUBREF mutation, stripRight) $(SUBREF mutation, swap) $(SUBREF mutation, swapRanges) $(SUBREF mutation, uninitializedFill) ) ) )) Many functions in this package are parameterized with a $(GLOSSARY predicate). The predicate may be any suitable callable type (a function, a delegate, a $(GLOSSARY functor), or a lambda), or a compile-time string. The string may consist of $(B any) legal D expression that uses the symbol $(D a) (for unary functions) or the symbols $(D a) and $(D b) (for binary functions). These names will NOT interfere with other homonym symbols in user code because they are evaluated in a different context. The default for all binary comparison predicates is $(D "a == b") for unordered operations and $(D "a < b") for ordered operations. Example: ---- int[] a = ...; static bool greater(int a, int b) { return a > b; } sort!(greater)(a); // predicate as alias sort!((a, b) => a > b)(a); // predicate as a lambda. sort!("a > b")(a); // predicate as string // (no ambiguity with array name) sort(a); // no predicate, "a < b" is implicit ---- Macros: WIKI = Phobos/StdAlgorithm SUBMODULE = $(LINK2 std_algorithm_$1.html, std.algorithm.$1) SUBREF = $(LINK2 std_algorithm_$1.html#.$2, $(TT $2))$(NBSP) Copyright: Andrei Alexandrescu 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/_algorithm/package.d) */ module std.algorithm; //debug = std_algorithm; public import std.algorithm.comparison; public import std.algorithm.iteration; public import std.algorithm.mutation; public import std.algorithm.setops; public import std.algorithm.searching; public import std.algorithm.sorting; static import std.functional; // Explicitly undocumented. It will be removed in March 2017. @@@DEPRECATED_2017-03@@@ deprecated("Please use std.functional.forward instead.") alias forward = std.functional.forward; ldc-1.1.0-beta3-src/runtime/phobos/std/algorithm/setops.d0000664000175000017500000011525712776215007021371 0ustar kaikai// Written in the D programming language. /** This is a submodule of $(LINK2 std_algorithm.html, std.algorithm). It contains generic algorithms that implement set operations. $(BOOKTABLE Cheat Sheet, $(TR $(TH Function Name) $(TH Description)) $(T2 cartesianProduct, Computes Cartesian product of two ranges.) $(T2 largestPartialIntersection, Copies out the values that occur most frequently in a range of ranges.) $(T2 largestPartialIntersectionWeighted, Copies out the values that occur most frequently (multiplied by per-value weights) in a range of ranges.) $(T2 nWayUnion, Computes the union of a set of sets implemented as a range of sorted ranges.) $(T2 setDifference, Lazily computes the set difference of two or more sorted ranges.) $(T2 setIntersection, Lazily computes the intersection of two or more sorted ranges.) $(T2 setSymmetricDifference, Lazily computes the symmetric set difference of two or more sorted ranges.) $(T2 setUnion, Lazily computes the set union of two or more sorted ranges.) ) Copyright: Andrei Alexandrescu 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/algorithm/_setops.d) Macros: T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) */ module std.algorithm.setops; import std.range.primitives; // FIXME import std.functional; // : unaryFun, binaryFun; import std.traits; // FIXME import std.meta; // : AliasSeq, staticMap, allSatisfy, anySatisfy; // cartesianProduct /** Lazily computes the Cartesian product of two or more ranges. The product is a _range of tuples of elements from each respective range. The conditions for the two-range case are as follows: If both ranges are finite, then one must be (at least) a forward range and the other an input range. If one _range is infinite and the other finite, then the finite _range must be a forward _range, and the infinite range can be an input _range. If both ranges are infinite, then both must be forward ranges. When there are more than two ranges, the above conditions apply to each adjacent pair of ranges. Params: range1 = The first range range2 = The second range ranges = Two or more non-infinite forward ranges otherRanges = Zero or more non-infinite forward ranges Returns: A forward range of $(XREF typecons,Tuple) representing elements of the cartesian product of the given ranges. */ auto cartesianProduct(R1, R2)(R1 range1, R2 range2) if (!allSatisfy!(isForwardRange, R1, R2) || anySatisfy!(isInfinite, R1, R2)) { import std.algorithm.iteration : map, joiner; static if (isInfinite!R1 && isInfinite!R2) { static if (isForwardRange!R1 && isForwardRange!R2) { import std.range : zip, repeat, take, chain, sequence; // This algorithm traverses the cartesian product by alternately // covering the right and bottom edges of an increasing square area // over the infinite table of combinations. This schedule allows us // to require only forward ranges. return zip(sequence!"n"(cast(size_t)0), range1.save, range2.save, repeat(range1), repeat(range2)) .map!(function(a) => chain( zip(repeat(a[1]), take(a[4].save, a[0])), zip(take(a[3].save, a[0]+1), repeat(a[2])) ))() .joiner(); } else static assert(0, "cartesianProduct of infinite ranges requires "~ "forward ranges"); } else static if (isInputRange!R1 && isForwardRange!R2 && !isInfinite!R2) { import std.range : zip, repeat; return joiner(map!((ElementType!R1 a) => zip(repeat(a), range2.save)) (range1)); } else static if (isInputRange!R2 && isForwardRange!R1 && !isInfinite!R1) { import std.range : zip, repeat; return joiner(map!((ElementType!R2 a) => zip(range1.save, repeat(a))) (range2)); } else static assert(0, "cartesianProduct involving finite ranges must "~ "have at least one finite forward range"); } /// @safe unittest { import std.algorithm.searching : canFind; import std.range; import std.typecons : tuple; auto N = sequence!"n"(0); // the range of natural numbers auto N2 = cartesianProduct(N, N); // the range of all pairs of natural numbers // Various arbitrary number pairs can be found in the range in finite time. assert(canFind(N2, tuple(0, 0))); assert(canFind(N2, tuple(123, 321))); assert(canFind(N2, tuple(11, 35))); assert(canFind(N2, tuple(279, 172))); } /// @safe unittest { import std.algorithm.searching : canFind; import std.typecons : tuple; auto B = [ 1, 2, 3 ]; auto C = [ 4, 5, 6 ]; auto BC = cartesianProduct(B, C); foreach (n; [[1, 4], [2, 4], [3, 4], [1, 5], [2, 5], [3, 5], [1, 6], [2, 6], [3, 6]]) { assert(canFind(BC, tuple(n[0], n[1]))); } } @safe unittest { // Test cartesian product of two infinite ranges import std.algorithm.searching : canFind; import std.range; import std.typecons : tuple; auto Even = sequence!"2*n"(0); auto Odd = sequence!"2*n+1"(0); auto EvenOdd = cartesianProduct(Even, Odd); foreach (pair; [[0, 1], [2, 1], [0, 3], [2, 3], [4, 1], [4, 3], [0, 5], [2, 5], [4, 5], [6, 1], [6, 3], [6, 5]]) { assert(canFind(EvenOdd, tuple(pair[0], pair[1]))); } // This should terminate in finite time assert(canFind(EvenOdd, tuple(124, 73))); assert(canFind(EvenOdd, tuple(0, 97))); assert(canFind(EvenOdd, tuple(42, 1))); } @safe unittest { // Test cartesian product of an infinite input range and a finite forward // range. import std.algorithm.searching : canFind; import std.range; import std.typecons : tuple; auto N = sequence!"n"(0); auto M = [100, 200, 300]; auto NM = cartesianProduct(N,M); foreach (pair; [[0, 100], [0, 200], [0, 300], [1, 100], [1, 200], [1, 300], [2, 100], [2, 200], [2, 300], [3, 100], [3, 200], [3, 300]]) { assert(canFind(NM, tuple(pair[0], pair[1]))); } // We can't solve the halting problem, so we can only check a finite // initial segment here. assert(!canFind(NM.take(100), tuple(100, 0))); assert(!canFind(NM.take(100), tuple(1, 1))); assert(!canFind(NM.take(100), tuple(100, 200))); auto MN = cartesianProduct(M,N); foreach (pair; [[100, 0], [200, 0], [300, 0], [100, 1], [200, 1], [300, 1], [100, 2], [200, 2], [300, 2], [100, 3], [200, 3], [300, 3]]) { assert(canFind(MN, tuple(pair[0], pair[1]))); } // We can't solve the halting problem, so we can only check a finite // initial segment here. assert(!canFind(MN.take(100), tuple(0, 100))); assert(!canFind(MN.take(100), tuple(0, 1))); assert(!canFind(MN.take(100), tuple(100, 200))); } @safe unittest { import std.algorithm.searching : canFind; import std.typecons : tuple; // Test cartesian product of two finite ranges. auto X = [1, 2, 3]; auto Y = [4, 5, 6]; auto XY = cartesianProduct(X, Y); auto Expected = [[1, 4], [1, 5], [1, 6], [2, 4], [2, 5], [2, 6], [3, 4], [3, 5], [3, 6]]; // Verify Expected ⊆ XY foreach (pair; Expected) { assert(canFind(XY, tuple(pair[0], pair[1]))); } // Verify XY ⊆ Expected foreach (pair; XY) { assert(canFind(Expected, [pair[0], pair[1]])); } // And therefore, by set comprehension, XY == Expected } @safe unittest { import std.algorithm.searching : canFind; import std.algorithm.comparison : equal; import std.algorithm.iteration : map; import std.typecons : tuple; import std.range; auto N = sequence!"n"(0); // To force the template to fall to the second case, we wrap N in a struct // that doesn't allow bidirectional access. struct FwdRangeWrapper(R) { R impl; // Input range API @property auto front() { return impl.front; } void popFront() { impl.popFront(); } static if (isInfinite!R) enum empty = false; else @property bool empty() { return impl.empty; } // Forward range API @property auto save() { return typeof(this)(impl.save); } } auto fwdWrap(R)(R range) { return FwdRangeWrapper!R(range); } // General test: two infinite bidirectional ranges auto N2 = cartesianProduct(N, N); assert(canFind(N2, tuple(0, 0))); assert(canFind(N2, tuple(123, 321))); assert(canFind(N2, tuple(11, 35))); assert(canFind(N2, tuple(279, 172))); // Test first case: forward range with bidirectional range auto fwdN = fwdWrap(N); auto N2_a = cartesianProduct(fwdN, N); assert(canFind(N2_a, tuple(0, 0))); assert(canFind(N2_a, tuple(123, 321))); assert(canFind(N2_a, tuple(11, 35))); assert(canFind(N2_a, tuple(279, 172))); // Test second case: bidirectional range with forward range auto N2_b = cartesianProduct(N, fwdN); assert(canFind(N2_b, tuple(0, 0))); assert(canFind(N2_b, tuple(123, 321))); assert(canFind(N2_b, tuple(11, 35))); assert(canFind(N2_b, tuple(279, 172))); // Test third case: finite forward range with (infinite) input range static struct InpRangeWrapper(R) { R impl; // Input range API @property auto front() { return impl.front; } void popFront() { impl.popFront(); } static if (isInfinite!R) enum empty = false; else @property bool empty() { return impl.empty; } } auto inpWrap(R)(R r) { return InpRangeWrapper!R(r); } auto inpN = inpWrap(N); auto B = [ 1, 2, 3 ]; auto fwdB = fwdWrap(B); auto BN = cartesianProduct(fwdB, inpN); assert(equal(map!"[a[0],a[1]]"(BN.take(10)), [[1, 0], [2, 0], [3, 0], [1, 1], [2, 1], [3, 1], [1, 2], [2, 2], [3, 2], [1, 3]])); // Test fourth case: (infinite) input range with finite forward range auto NB = cartesianProduct(inpN, fwdB); assert(equal(map!"[a[0],a[1]]"(NB.take(10)), [[0, 1], [0, 2], [0, 3], [1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1]])); // General finite range case auto C = [ 4, 5, 6 ]; auto BC = cartesianProduct(B, C); foreach (n; [[1, 4], [2, 4], [3, 4], [1, 5], [2, 5], [3, 5], [1, 6], [2, 6], [3, 6]]) { assert(canFind(BC, tuple(n[0], n[1]))); } } // Issue 13091 pure nothrow @safe @nogc unittest { import std.algorithm: cartesianProduct; int[1] a = [1]; foreach (t; cartesianProduct(a[], a[])) {} } /// ditto auto cartesianProduct(RR...)(RR ranges) if (ranges.length >= 2 && allSatisfy!(isForwardRange, RR) && !anySatisfy!(isInfinite, RR)) { // This overload uses a much less template-heavy implementation when // all ranges are finite forward ranges, which is the most common use // case, so that we don't run out of resources too quickly. // // For infinite ranges or non-forward ranges, we fall back to the old // implementation which expands an exponential number of templates. import std.typecons : tuple; static struct Result { RR ranges; RR current; bool empty = true; this(RR _ranges) { ranges = _ranges; empty = false; foreach (i, r; ranges) { current[i] = r.save; if (current[i].empty) empty = true; } } @property auto front() { import std.algorithm.internal : algoFormat; import std.range : iota; return mixin(algoFormat("tuple(%(current[%d].front%|,%))", iota(0, current.length))); } void popFront() { foreach_reverse (i, ref r; current) { r.popFront(); if (!r.empty) break; static if (i==0) empty = true; else r = ranges[i].save; // rollover } } @property Result save() { Result copy = this; foreach (i, r; ranges) { copy.ranges[i] = r.save; copy.current[i] = current[i].save; } return copy; } } static assert(isForwardRange!Result); return Result(ranges); } @safe unittest { // Issue 10693: cartesian product of empty ranges should be empty. int[] a, b, c, d, e; auto cprod = cartesianProduct(a,b,c,d,e); assert(cprod.empty); foreach (_; cprod) {} // should not crash // Test case where only one of the ranges is empty: the result should still // be empty. int[] p=[1], q=[]; auto cprod2 = cartesianProduct(p,p,p,q,p); assert(cprod2.empty); foreach (_; cprod2) {} // should not crash } @safe unittest { // .init value of cartesianProduct should be empty auto cprod = cartesianProduct([0,0], [1,1], [2,2]); assert(!cprod.empty); assert(cprod.init.empty); } @safe unittest { // Issue 13393 assert(!cartesianProduct([0],[0],[0]).save.empty); } /// ditto auto cartesianProduct(R1, R2, RR...)(R1 range1, R2 range2, RR otherRanges) if (!allSatisfy!(isForwardRange, R1, R2, RR) || anySatisfy!(isInfinite, R1, R2, RR)) { /* We implement the n-ary cartesian product by recursively invoking the * binary cartesian product. To make the resulting range nicer, we denest * one level of tuples so that a ternary cartesian product, for example, * returns 3-element tuples instead of nested 2-element tuples. */ import std.algorithm.internal : algoFormat; import std.algorithm.iteration : map; import std.range : iota; enum string denest = algoFormat("tuple(a[0], %(a[1][%d]%|,%))", iota(0, otherRanges.length+1)); return map!denest( cartesianProduct(range1, cartesianProduct(range2, otherRanges)) ); } @safe unittest { import std.algorithm.searching : canFind; import std.range; import std.typecons : tuple, Tuple; auto N = sequence!"n"(0); auto N3 = cartesianProduct(N, N, N); // Check that tuples are properly denested assert(is(ElementType!(typeof(N3)) == Tuple!(size_t,size_t,size_t))); assert(canFind(N3, tuple(0, 27, 7))); assert(canFind(N3, tuple(50, 23, 71))); assert(canFind(N3, tuple(9, 3, 0))); } @safe unittest { import std.algorithm.searching : canFind; import std.range; import std.typecons : tuple, Tuple; auto N = sequence!"n"(0); auto N4 = cartesianProduct(N, N, N, N); // Check that tuples are properly denested assert(is(ElementType!(typeof(N4)) == Tuple!(size_t,size_t,size_t,size_t))); assert(canFind(N4, tuple(1, 2, 3, 4))); assert(canFind(N4, tuple(4, 3, 2, 1))); assert(canFind(N4, tuple(10, 31, 7, 12))); } // Issue 9878 /// @safe unittest { import std.algorithm.comparison : equal; import std.typecons : tuple; auto A = [ 1, 2, 3 ]; auto B = [ 'a', 'b', 'c' ]; auto C = [ "x", "y", "z" ]; auto ABC = cartesianProduct(A, B, C); assert(ABC.equal([ tuple(1, 'a', "x"), tuple(1, 'a', "y"), tuple(1, 'a', "z"), tuple(1, 'b', "x"), tuple(1, 'b', "y"), tuple(1, 'b', "z"), tuple(1, 'c', "x"), tuple(1, 'c', "y"), tuple(1, 'c', "z"), tuple(2, 'a', "x"), tuple(2, 'a', "y"), tuple(2, 'a', "z"), tuple(2, 'b', "x"), tuple(2, 'b', "y"), tuple(2, 'b', "z"), tuple(2, 'c', "x"), tuple(2, 'c', "y"), tuple(2, 'c', "z"), tuple(3, 'a', "x"), tuple(3, 'a', "y"), tuple(3, 'a', "z"), tuple(3, 'b', "x"), tuple(3, 'b', "y"), tuple(3, 'b', "z"), tuple(3, 'c', "x"), tuple(3, 'c', "y"), tuple(3, 'c', "z") ])); } pure @safe nothrow @nogc unittest { int[2] A = [1,2]; auto C = cartesianProduct(A[], A[], A[]); assert(isForwardRange!(typeof(C))); C.popFront(); auto front1 = C.front; auto D = C.save; C.popFront(); assert(D.front == front1); } // Issue 13935 unittest { import std.algorithm.iteration : map; auto seq = [1, 2].map!(x => x); foreach (pair; cartesianProduct(seq, seq)) {} } // largestPartialIntersection /** Given a range of sorted forward ranges $(D ror), copies to $(D tgt) the elements that are common to most ranges, along with their number of occurrences. All ranges in $(D ror) are assumed to be sorted by $(D less). Only the most frequent $(D tgt.length) elements are returned. Params: less = The predicate the ranges are sorted by. ror = A range of forward ranges sorted by `less`. tgt = The target range to copy common elements to. sorted = Whether the elements copied should be in sorted order. The function $(D largestPartialIntersection) is useful for e.g. searching an $(LUCKY inverted index) for the documents most likely to contain some terms of interest. The complexity of the search is $(BIGOH n * log(tgt.length)), where $(D n) is the sum of lengths of all input ranges. This approach is faster than keeping an associative array of the occurrences and then selecting its top items, and also requires less memory ($(D largestPartialIntersection) builds its result directly in $(D tgt) and requires no extra memory). Warning: Because $(D largestPartialIntersection) does not allocate extra memory, it will leave $(D ror) modified. Namely, $(D largestPartialIntersection) assumes ownership of $(D ror) and discretionarily swaps and advances elements of it. If you want $(D ror) to preserve its contents after the call, you may want to pass a duplicate to $(D largestPartialIntersection) (and perhaps cache the duplicate in between calls). */ void largestPartialIntersection (alias less = "a < b", RangeOfRanges, Range) (RangeOfRanges ror, Range tgt, SortOutput sorted = SortOutput.no) { struct UnitWeights { static int opIndex(ElementType!(ElementType!RangeOfRanges)) { return 1; } } return largestPartialIntersectionWeighted!less(ror, tgt, UnitWeights(), sorted); } /// unittest { import std.typecons : tuple, Tuple; // Figure which number can be found in most arrays of the set of // arrays below. double[][] a = [ [ 1, 4, 7, 8 ], [ 1, 7 ], [ 1, 7, 8], [ 4 ], [ 7 ], ]; auto b = new Tuple!(double, uint)[1]; // it will modify the input range, hence we need to create a duplicate largestPartialIntersection(a.dup, b); // First member is the item, second is the occurrence count assert(b[0] == tuple(7.0, 4u)); // 7.0 occurs in 4 out of 5 inputs, more than any other number // If more of the top-frequent numbers are needed, just create a larger // tgt range auto c = new Tuple!(double, uint)[2]; largestPartialIntersection(a, c); assert(c[0] == tuple(1.0, 3u)); // 1.0 occurs in 3 inputs } import std.algorithm.sorting : SortOutput; // FIXME // largestPartialIntersectionWeighted /** Similar to $(D largestPartialIntersection), but associates a weight with each distinct element in the intersection. Params: less = The predicate the ranges are sorted by. ror = A range of forward ranges sorted by `less`. tgt = The target range to copy common elements to. weights = An associative array mapping elements to weights. sorted = Whether the elements copied should be in sorted order. */ void largestPartialIntersectionWeighted (alias less = "a < b", RangeOfRanges, Range, WeightsAA) (RangeOfRanges ror, Range tgt, WeightsAA weights, SortOutput sorted = SortOutput.no) { import std.algorithm.iteration : group; import std.algorithm.sorting : topNCopy; if (tgt.empty) return; alias InfoType = ElementType!Range; bool heapComp(InfoType a, InfoType b) { return weights[a[0]] * a[1] > weights[b[0]] * b[1]; } topNCopy!heapComp(group(nWayUnion!less(ror)), tgt, sorted); } /// unittest { import std.typecons : tuple, Tuple; // Figure which number can be found in most arrays of the set of // arrays below, with specific per-element weights double[][] a = [ [ 1, 4, 7, 8 ], [ 1, 7 ], [ 1, 7, 8], [ 4 ], [ 7 ], ]; auto b = new Tuple!(double, uint)[1]; double[double] weights = [ 1:1.2, 4:2.3, 7:1.1, 8:1.1 ]; largestPartialIntersectionWeighted(a, b, weights); // First member is the item, second is the occurrence count assert(b[0] == tuple(4.0, 2u)); // 4.0 occurs 2 times -> 4.6 (2 * 2.3) // 7.0 occurs 3 times -> 4.4 (3 * 1.1) } unittest { import std.conv : text; import std.typecons : tuple, Tuple; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); double[][] a = [ [ 1, 4, 7, 8 ], [ 1, 7 ], [ 1, 7, 8], [ 4 ], [ 7 ], ]; auto b = new Tuple!(double, uint)[2]; largestPartialIntersection(a, b, SortOutput.yes); //sort(b); //writeln(b); assert(b == [ tuple(7.0, 4u), tuple(1.0, 3u) ][], text(b)); assert(a[0].empty); } unittest { import std.conv : text; import std.typecons : tuple, Tuple; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); string[][] a = [ [ "1", "4", "7", "8" ], [ "1", "7" ], [ "1", "7", "8"], [ "4" ], [ "7" ], ]; auto b = new Tuple!(string, uint)[2]; largestPartialIntersection(a, b, SortOutput.yes); //writeln(b); assert(b == [ tuple("7", 4u), tuple("1", 3u) ][], text(b)); } unittest { import std.typecons : tuple, Tuple; //scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); // Figure which number can be found in most arrays of the set of // arrays below, with specific per-element weights double[][] a = [ [ 1, 4, 7, 8 ], [ 1, 7 ], [ 1, 7, 8], [ 4 ], [ 7 ], ]; auto b = new Tuple!(double, uint)[1]; double[double] weights = [ 1:1.2, 4:2.3, 7:1.1, 8:1.1 ]; largestPartialIntersectionWeighted(a, b, weights); // First member is the item, second is the occurrence count //writeln(b[0]); assert(b[0] == tuple(4.0, 2u)); } unittest { import std.container : Array; import std.typecons : Tuple; alias T = Tuple!(uint, uint); const Array!T arrayOne = Array!T( [ T(1,2), T(3,4) ] ); const Array!T arrayTwo = Array!T([ T(1,2), T(3,4) ] ); assert(arrayOne == arrayTwo); } // NWayUnion /** Computes the union of multiple sets. The input sets are passed as a range of ranges and each is assumed to be sorted by $(D less). Computation is done lazily, one union element at a time. The complexity of one $(D popFront) operation is $(BIGOH log(ror.length)). However, the length of $(D ror) decreases as ranges in it are exhausted, so the complexity of a full pass through $(D NWayUnion) is dependent on the distribution of the lengths of ranges contained within $(D ror). If all ranges have the same length $(D n) (worst case scenario), the complexity of a full pass through $(D NWayUnion) is $(BIGOH n * ror.length * log(ror.length)), i.e., $(D log(ror.length)) times worse than just spanning all ranges in turn. The output comes sorted (unstably) by $(D less). Params: less = Predicate the given ranges are sorted by. ror = A range of ranges sorted by `less` to compute the union for. Returns: A range of the union of the ranges in `ror`. Warning: Because $(D NWayUnion) does not allocate extra memory, it will leave $(D ror) modified. Namely, $(D NWayUnion) assumes ownership of $(D ror) and discretionarily swaps and advances elements of it. If you want $(D ror) to preserve its contents after the call, you may want to pass a duplicate to $(D NWayUnion) (and perhaps cache the duplicate in between calls). */ struct NWayUnion(alias less, RangeOfRanges) { import std.container : BinaryHeap; private alias ElementType = .ElementType!(.ElementType!RangeOfRanges); private alias comp = binaryFun!less; private RangeOfRanges _ror; static bool compFront(.ElementType!RangeOfRanges a, .ElementType!RangeOfRanges b) { // revert comparison order so we get the smallest elements first return comp(b.front, a.front); } BinaryHeap!(RangeOfRanges, compFront) _heap; this(RangeOfRanges ror) { import std.algorithm.mutation : remove, SwapStrategy; // Preemptively get rid of all empty ranges in the input // No need for stability either _ror = remove!("a.empty", SwapStrategy.unstable)(ror); //Build the heap across the range _heap.acquire(_ror); } @property bool empty() { return _ror.empty; } @property auto ref front() { return _heap.front.front; } void popFront() { _heap.removeFront(); // let's look at the guy just popped _ror.back.popFront(); if (_ror.back.empty) { _ror.popBack(); // nothing else to do: the empty range is not in the // heap and not in _ror return; } // Put the popped range back in the heap _heap.conditionalInsert(_ror.back) || assert(false); } } /// Ditto NWayUnion!(less, RangeOfRanges) nWayUnion (alias less = "a < b", RangeOfRanges) (RangeOfRanges ror) { return typeof(return)(ror); } /// unittest { import std.algorithm.comparison : equal; double[][] a = [ [ 1, 4, 7, 8 ], [ 1, 7 ], [ 1, 7, 8], [ 4 ], [ 7 ], ]; auto witness = [ 1, 1, 1, 4, 4, 7, 7, 7, 7, 8, 8 ]; assert(equal(nWayUnion(a), witness)); } /** Lazily computes the difference of $(D r1) and $(D r2). The two ranges are assumed to be sorted by $(D less). The element types of the two ranges must have a common type. Params: less = Predicate the given ranges are sorted by. r1 = The first range. r2 = The range to subtract from `r1`. Returns: A range of the difference of `r1` and `r2`. See_also: $(LREF setSymmetricDifference) */ struct SetDifference(alias less = "a < b", R1, R2) if (isInputRange!(R1) && isInputRange!(R2)) { private: R1 r1; R2 r2; alias comp = binaryFun!(less); void adjustPosition() { while (!r1.empty) { if (r2.empty || comp(r1.front, r2.front)) break; if (comp(r2.front, r1.front)) { r2.popFront(); } else { // both are equal r1.popFront(); r2.popFront(); } } } public: this(R1 r1, R2 r2) { this.r1 = r1; this.r2 = r2; // position to the first element adjustPosition(); } void popFront() { r1.popFront(); adjustPosition(); } @property auto ref front() { assert(!empty); return r1.front; } static if (isForwardRange!R1 && isForwardRange!R2) { @property typeof(this) save() { auto ret = this; ret.r1 = r1.save; ret.r2 = r2.save; return ret; } } @property bool empty() { return r1.empty; } } /// Ditto SetDifference!(less, R1, R2) setDifference(alias less = "a < b", R1, R2) (R1 r1, R2 r2) { return typeof(return)(r1, r2); } /// @safe unittest { import std.algorithm.comparison : equal; int[] a = [ 1, 2, 4, 5, 7, 9 ]; int[] b = [ 0, 1, 2, 4, 7, 8 ]; assert(equal(setDifference(a, b), [5, 9][])); static assert(isForwardRange!(typeof(setDifference(a, b)))); } @safe unittest // Issue 10460 { import std.algorithm.comparison : equal; int[] a = [1, 2, 3, 4, 5]; int[] b = [2, 4]; foreach (ref e; setDifference(a, b)) e = 0; assert(equal(a, [0, 2, 0, 4, 0])); } /** Lazily computes the intersection of two or more input ranges $(D ranges). The ranges are assumed to be sorted by $(D less). The element types of the ranges must have a common type. Params: less = Predicate the given ranges are sorted by. ranges = The ranges to compute the intersection for. Returns: A range containing the intersection of the given ranges. */ struct SetIntersection(alias less = "a < b", Rs...) if (Rs.length >= 2 && allSatisfy!(isInputRange, Rs) && !is(CommonType!(staticMap!(ElementType, Rs)) == void)) { private: Rs _input; alias comp = binaryFun!less; alias ElementType = CommonType!(staticMap!(.ElementType, Rs)); // Positions to the first elements that are all equal void adjustPosition() { if (empty) return; size_t done = Rs.length; static if (Rs.length > 1) while (true) { foreach (i, ref r; _input) { alias next = _input[(i + 1) % Rs.length]; if (comp(next.front, r.front)) { do { next.popFront(); if (next.empty) return; } while(comp(next.front, r.front)); done = Rs.length; } if (--done == 0) return; } } } public: this(Rs input) { this._input = input; // position to the first element adjustPosition(); } @property bool empty() { foreach (ref r; _input) { if (r.empty) return true; } return false; } void popFront() { assert(!empty); static if (Rs.length > 1) foreach (i, ref r; _input) { alias next = _input[(i + 1) % Rs.length]; assert(!comp(r.front, next.front)); } foreach (ref r; _input) { r.popFront(); } adjustPosition(); } @property ElementType front() { assert(!empty); return _input[0].front; } static if (allSatisfy!(isForwardRange, Rs)) { @property SetIntersection save() { auto ret = this; foreach (i, ref r; _input) { ret._input[i] = r.save; } return ret; } } } /// Ditto SetIntersection!(less, Rs) setIntersection(alias less = "a < b", Rs...)(Rs ranges) if (Rs.length >= 2 && allSatisfy!(isInputRange, Rs) && !is(CommonType!(staticMap!(ElementType, Rs)) == void)) { return typeof(return)(ranges); } /// @safe unittest { import std.algorithm.comparison : equal; int[] a = [ 1, 2, 4, 5, 7, 9 ]; int[] b = [ 0, 1, 2, 4, 7, 8 ]; int[] c = [ 0, 1, 4, 5, 7, 8 ]; assert(equal(setIntersection(a, a), a)); assert(equal(setIntersection(a, b), [1, 2, 4, 7])); assert(equal(setIntersection(a, b, c), [1, 4, 7])); } @safe unittest { import std.algorithm.comparison : equal; import std.algorithm.iteration : filter; int[] a = [ 1, 2, 4, 5, 7, 9 ]; int[] b = [ 0, 1, 2, 4, 7, 8 ]; int[] c = [ 0, 1, 4, 5, 7, 8 ]; int[] d = [ 1, 3, 4 ]; int[] e = [ 4, 5 ]; assert(equal(setIntersection(a, a), a)); assert(equal(setIntersection(a, a, a), a)); assert(equal(setIntersection(a, b), [1, 2, 4, 7])); assert(equal(setIntersection(a, b, c), [1, 4, 7])); assert(equal(setIntersection(a, b, c, d), [1, 4])); assert(equal(setIntersection(a, b, c, d, e), [4])); auto inpA = a.filter!(_ => true), inpB = b.filter!(_ => true); auto inpC = c.filter!(_ => true), inpD = d.filter!(_ => true); assert(equal(setIntersection(inpA, inpB, inpC, inpD), [1, 4])); assert(equal(setIntersection(a, b, b, a), [1, 2, 4, 7])); assert(equal(setIntersection(a, c, b), [1, 4, 7])); assert(equal(setIntersection(b, a, c), [1, 4, 7])); assert(equal(setIntersection(b, c, a), [1, 4, 7])); assert(equal(setIntersection(c, a, b), [1, 4, 7])); assert(equal(setIntersection(c, b, a), [1, 4, 7])); } /** Lazily computes the symmetric difference of $(D r1) and $(D r2), i.e. the elements that are present in exactly one of $(D r1) and $(D r2). The two ranges are assumed to be sorted by $(D less), and the output is also sorted by $(D less). The element types of the two ranges must have a common type. If both arguments are ranges of L-values of the same type then $(D SetSymmetricDifference) will also be a range of L-values of that type. Params: less = Predicate the given ranges are sorted by. r1 = The first range. r2 = The second range. Returns: A range of the symmetric difference between `r1` and `r2`. See_also: $(LREF setDifference) */ struct SetSymmetricDifference(alias less = "a < b", R1, R2) if (isInputRange!(R1) && isInputRange!(R2)) { private: R1 r1; R2 r2; //bool usingR2; alias comp = binaryFun!(less); void adjustPosition() { while (!r1.empty && !r2.empty) { if (comp(r1.front, r2.front) || comp(r2.front, r1.front)) { break; } // equal, pop both r1.popFront(); r2.popFront(); } } public: this(R1 r1, R2 r2) { this.r1 = r1; this.r2 = r2; // position to the first element adjustPosition(); } void popFront() { assert(!empty); if (r1.empty) r2.popFront(); else if (r2.empty) r1.popFront(); else { // neither is empty if (comp(r1.front, r2.front)) { r1.popFront(); } else { assert(comp(r2.front, r1.front)); r2.popFront(); } } adjustPosition(); } @property auto ref front() { assert(!empty); bool chooseR1 = r2.empty || !r1.empty && comp(r1.front, r2.front); assert(chooseR1 || r1.empty || comp(r2.front, r1.front)); return chooseR1 ? r1.front : r2.front; } static if (isForwardRange!R1 && isForwardRange!R2) { @property typeof(this) save() { auto ret = this; ret.r1 = r1.save; ret.r2 = r2.save; return ret; } } ref auto opSlice() { return this; } @property bool empty() { return r1.empty && r2.empty; } } /// Ditto SetSymmetricDifference!(less, R1, R2) setSymmetricDifference(alias less = "a < b", R1, R2) (R1 r1, R2 r2) { return typeof(return)(r1, r2); } /// @safe unittest { import std.algorithm.comparison : equal; int[] a = [ 1, 2, 4, 5, 7, 9 ]; int[] b = [ 0, 1, 2, 4, 7, 8 ]; assert(equal(setSymmetricDifference(a, b), [0, 5, 8, 9][])); static assert(isForwardRange!(typeof(setSymmetricDifference(a, b)))); } @safe unittest // Issue 10460 { int[] a = [1, 2]; double[] b = [2.0, 3.0]; int[] c = [2, 3]; alias R1 = typeof(setSymmetricDifference(a, b)); static assert(is(ElementType!R1 == double)); static assert(!hasLvalueElements!R1); alias R2 = typeof(setSymmetricDifference(a, c)); static assert(is(ElementType!R2 == int)); static assert(hasLvalueElements!R2); } /** Lazily computes the union of two or more ranges $(D rs). The ranges are assumed to be sorted by $(D less). Elements in the output are not unique; the length of the output is the sum of the lengths of the inputs. (The $(D length) member is offered if all ranges also have length.) The element types of all ranges must have a common type. Params: less = Predicate the given ranges are sorted by. rs = The ranges to compute the union for. Returns: A range containing the union of the given ranges. */ struct SetUnion(alias less = "a < b", Rs...) if (allSatisfy!(isInputRange, Rs)) { private: Rs _r; alias comp = binaryFun!(less); uint _crt; void adjustPosition(uint candidate = 0)() { static if (candidate == Rs.length) { _crt = _crt.max; } else { if (_r[candidate].empty) { adjustPosition!(candidate + 1)(); return; } foreach (i, U; Rs[candidate + 1 .. $]) { enum j = candidate + i + 1; if (_r[j].empty) continue; if (comp(_r[j].front, _r[candidate].front)) { // a new candidate was found adjustPosition!(j)(); return; } } // Found a successful candidate _crt = candidate; } } public: alias ElementType = CommonType!(staticMap!(.ElementType, Rs)); static assert(!is(CommonType!(staticMap!(.ElementType, Rs)) == void), typeof(this).stringof ~ ": incompatible element types."); this(Rs rs) { this._r = rs; adjustPosition(); } @property bool empty() { return _crt == _crt.max; } void popFront() { // Assumes _crt is correct assert(!empty); foreach (i, U; Rs) { if (i < _crt) continue; // found _crt assert(!_r[i].empty); _r[i].popFront(); adjustPosition(); return; } assert(false); } @property auto ref ElementType front() { assert(!empty); // Assume _crt is correct foreach (i, U; Rs) { if (i < _crt) continue; assert(!_r[i].empty); return _r[i].front; } assert(false); } static if (allSatisfy!(isForwardRange, Rs)) { @property auto save() { auto ret = this; foreach (ti, elem; _r) { ret._r[ti] = elem.save; } return ret; } } static if (allSatisfy!(hasLength, Rs)) { @property size_t length() { size_t result; foreach (i, U; Rs) { result += _r[i].length; } return result; } alias opDollar = length; } } /// Ditto SetUnion!(less, Rs) setUnion(alias less = "a < b", Rs...) (Rs rs) { return typeof(return)(rs); } /// @safe unittest { import std.algorithm.comparison : equal; int[] a = [ 1, 2, 4, 5, 7, 9 ]; int[] b = [ 0, 1, 2, 4, 7, 8 ]; double[] c = [ 10.5 ]; static assert(isForwardRange!(typeof(setUnion(a, b)))); assert(setUnion(a, b).length == a.length + b.length); assert(equal(setUnion(a, b), [0, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9][])); assert(equal(setUnion(a, c, b), [0, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9, 10.5][])); auto u = setUnion(a, b); u.front--; assert(equal(u, [-1, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9][])); } ldc-1.1.0-beta3-src/runtime/phobos/std/algorithm/sorting.d0000664000175000017500000026763112776215007021545 0ustar kaikai// Written in the D programming language. /** This is a submodule of $(LINK2 std_algorithm.html, std.algorithm). It contains generic _sorting algorithms. $(BOOKTABLE Cheat Sheet, $(TR $(TH Function Name) $(TH Description)) $(T2 completeSort, If $(D a = [10, 20, 30]) and $(D b = [40, 6, 15]), then $(D completeSort(a, b)) leaves $(D a = [6, 10, 15]) and $(D b = [20, 30, 40]). The range $(D a) must be sorted prior to the call, and as a result the combination $(D $(XREF range,chain)(a, b)) is sorted.) $(T2 isPartitioned, $(D isPartitioned!"a < 0"([-1, -2, 1, 0, 2])) returns $(D true) because the predicate is $(D true) for a portion of the range and $(D false) afterwards.) $(T2 isSorted, $(D isSorted([1, 1, 2, 3])) returns $(D true).) $(T2 ordered, $(D ordered(1, 1, 2, 3)) returns $(D true).) $(T2 strictlyOrdered, $(D strictlyOrdered(1, 1, 2, 3)) returns $(D false).) $(T2 makeIndex, Creates a separate index for a range.) $(T2 multiSort, Sorts by multiple keys.) $(T2 nextEvenPermutation, Computes the next lexicographically greater even permutation of a range in-place.) $(T2 nextPermutation, Computes the next lexicographically greater permutation of a range in-place.) $(T2 partialSort, If $(D a = [5, 4, 3, 2, 1]), then $(D partialSort(a, 3)) leaves $(D a[0 .. 3] = [1, 2, 3]). The other elements of $(D a) are left in an unspecified order.) $(T2 partition, Partitions a range according to a predicate.) $(T2 partition3, Partitions a range in three parts (less than, equal, greater than the given pivot).) $(T2 schwartzSort, Sorts with the help of the $(LUCKY Schwartzian transform).) $(T2 sort, Sorts.) $(T2 topN, Separates the top elements in a range.) $(T2 topNCopy, Copies out the top elements of a range.) $(T2 topNIndex, Builds an index of the top elements of a range.) ) Copyright: Andrei Alexandrescu 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/algorithm/_sorting.d) Macros: T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) */ module std.algorithm.sorting; import std.algorithm.mutation : SwapStrategy; import std.functional; // : unaryFun, binaryFun; import std.range.primitives; // FIXME import std.range; // : SortedRange; import std.traits; /** Specifies whether the output of certain algorithm is desired in sorted format. */ enum SortOutput { no, /// Don't sort output yes, /// Sort output } // completeSort /** Sorts the random-access range $(D chain(lhs, rhs)) according to predicate $(D less). The left-hand side of the range $(D lhs) is assumed to be already sorted; $(D rhs) is assumed to be unsorted. The exact strategy chosen depends on the relative sizes of $(D lhs) and $(D rhs). Performs $(BIGOH lhs.length + rhs.length * log(rhs.length)) (best case) to $(BIGOH (lhs.length + rhs.length) * log(lhs.length + rhs.length)) (worst-case) evaluations of $(D swap). Params: less = The predicate to sort by. ss = The swapping strategy to use. lhs = The sorted, left-hand side of the random access range to be sorted. rhs = The unsorted, right-hand side of the random access range to be sorted. */ void completeSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(SortedRange!(Range1, less) lhs, Range2 rhs) if (hasLength!(Range2) && hasSlicing!(Range2)) { import std.algorithm : bringToFront; // FIXME import std.range : chain, assumeSorted; // Probably this algorithm can be optimized by using in-place // merge auto lhsOriginal = lhs.release(); foreach (i; 0 .. rhs.length) { auto sortedSoFar = chain(lhsOriginal, rhs[0 .. i]); auto ub = assumeSorted!less(sortedSoFar).upperBound(rhs[i]); if (!ub.length) continue; bringToFront(ub.release(), rhs[i .. i + 1]); } } /// unittest { import std.range : assumeSorted; int[] a = [ 1, 2, 3 ]; int[] b = [ 4, 0, 6, 5 ]; completeSort(assumeSorted(a), b); assert(a == [ 0, 1, 2 ]); assert(b == [ 3, 4, 5, 6 ]); } // isSorted /** Checks whether a forward range is sorted according to the comparison operation $(D less). Performs $(BIGOH r.length) evaluations of $(D less). Params: less = Predicate the range should be sorted by. r = Forward range to check for sortedness. Returns: true if the range is sorted, false otherwise. */ bool isSorted(alias less = "a < b", Range)(Range r) if (isForwardRange!(Range)) { if (r.empty) return true; static if (isRandomAccessRange!Range && hasLength!Range) { immutable limit = r.length - 1; foreach (i; 0 .. limit) { if (!binaryFun!less(r[i + 1], r[i])) continue; assert( !binaryFun!less(r[i], r[i + 1]), "Predicate for isSorted is not antisymmetric. Both" ~ " pred(a, b) and pred(b, a) are true for certain values."); return false; } } else { auto ahead = r; ahead.popFront(); size_t i; for (; !ahead.empty; ahead.popFront(), r.popFront(), ++i) { if (!binaryFun!less(ahead.front, r.front)) continue; // Check for antisymmetric predicate assert( !binaryFun!less(r.front, ahead.front), "Predicate for isSorted is not antisymmetric. Both" ~ " pred(a, b) and pred(b, a) are true for certain values."); return false; } } return true; } /// @safe unittest { int[] arr = [4, 3, 2, 1]; assert(!isSorted(arr)); sort(arr); assert(isSorted(arr)); sort!("a > b")(arr); assert(isSorted!("a > b")(arr)); } @safe unittest { import std.conv : to; // Issue 9457 auto x = "abcd"; assert(isSorted(x)); auto y = "acbd"; assert(!isSorted(y)); int[] a = [1, 2, 3]; assert(isSorted(a)); int[] b = [1, 3, 2]; assert(!isSorted(b)); dchar[] ds = "コーヒーが好きです"d.dup; sort(ds); string s = to!string(ds); assert(isSorted(ds)); // random-access assert(isSorted(s)); // bidirectional } /** Like $(D isSorted), returns $(D true) if the given $(D values) are ordered according to the comparison operation $(D less). Unlike $(D isSorted), takes values directly instead of structured in a range. $(D ordered) allows repeated values, e.g. $(D ordered(1, 1, 2)) is $(D true). To verify that the values are ordered strictly monotonically, use $(D strictlyOrdered); $(D strictlyOrdered(1, 1, 2)) is $(D false). With either function, the predicate must be a strict ordering just like with $(D isSorted). For example, using $(D "a <= b") instead of $(D "a < b") is incorrect and will cause failed assertions. Params: values = The tested value less = The comparison predicate Returns: $(D true) if the values are ordered; $(D ordered) allows for duplicates, $(D strictlyOrdered) does not. */ bool ordered(alias less = "a < b", T...)(T values) if ((T.length == 2 && is(typeof(binaryFun!less(values[1], values[0])) : bool)) || (T.length > 2 && is(typeof(ordered!less(values[0 .. 1 + $ / 2]))) && is(typeof(ordered!less(values[$ / 2 .. $])))) ) { foreach (i, _; T[0 .. $ - 1]) { if (binaryFun!less(values[i + 1], values[i])) { assert(!binaryFun!less(values[i], values[i + 1]), __FUNCTION__ ~ ": incorrect non-strict predicate."); return false; } } return true; } /// ditto bool strictlyOrdered(alias less = "a < b", T...)(T values) if (is(typeof(ordered!less(values)))) { foreach (i, _; T[0 .. $ - 1]) { if (!binaryFun!less(values[i], values[i + 1])) { return false; } assert(!binaryFun!less(values[i + 1], values[i]), __FUNCTION__ ~ ": incorrect non-strict predicate."); } return true; } /// unittest { assert(ordered(42, 42, 43)); assert(!strictlyOrdered(43, 42, 45)); assert(ordered(42, 42, 43)); assert(!strictlyOrdered(42, 42, 43)); assert(!ordered(43, 42, 45)); // Ordered lexicographically assert(ordered("Jane", "Jim", "Joe")); assert(strictlyOrdered("Jane", "Jim", "Joe")); // Incidentally also ordered by length decreasing assert(ordered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe")); // ... but not strictly so: "Jim" and "Joe" have the same length assert(!strictlyOrdered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe")); } // partition /** Partitions a range in two using the given $(D predicate). Specifically, reorders the range $(D r = [left, right$(RPAREN)) using $(D swap) such that all elements $(D i) for which $(D predicate(i)) is $(D true) come before all elements $(D j) for which $(D predicate(j)) returns $(D false). Performs $(BIGOH r.length) (if unstable or semistable) or $(BIGOH r.length * log(r.length)) (if stable) evaluations of $(D less) and $(D swap). The unstable version computes the minimum possible evaluations of $(D swap) (roughly half of those performed by the semistable version). Params: predicate = The predicate to partition by. ss = The swapping strategy to employ. r = The random-access range to partition. Returns: The right part of $(D r) after partitioning. If $(D ss == SwapStrategy.stable), $(D partition) preserves the relative ordering of all elements $(D a), $(D b) in $(D r) for which $(D predicate(a) == predicate(b)). If $(D ss == SwapStrategy.semistable), $(D partition) preserves the relative ordering of all elements $(D a), $(D b) in the left part of $(D r) for which $(D predicate(a) == predicate(b)). See_Also: STL's $(WEB sgi.com/tech/stl/_partition.html, _partition)$(BR) STL's $(WEB sgi.com/tech/stl/stable_partition.html, stable_partition) */ Range partition(alias predicate, SwapStrategy ss = SwapStrategy.unstable, Range)(Range r) if ((ss == SwapStrategy.stable && isRandomAccessRange!(Range)) || (ss != SwapStrategy.stable && isForwardRange!(Range))) { import std.algorithm : bringToFront, swap; // FIXME; alias pred = unaryFun!(predicate); if (r.empty) return r; static if (ss == SwapStrategy.stable) { if (r.length == 1) { if (pred(r.front)) r.popFront(); return r; } const middle = r.length / 2; alias recurse = .partition!(pred, ss, Range); auto lower = recurse(r[0 .. middle]); auto upper = recurse(r[middle .. $]); bringToFront(lower, r[middle .. r.length - upper.length]); return r[r.length - lower.length - upper.length .. r.length]; } else static if (ss == SwapStrategy.semistable) { for (; !r.empty; r.popFront()) { // skip the initial portion of "correct" elements if (pred(r.front)) continue; // hit the first "bad" element auto result = r; for (r.popFront(); !r.empty; r.popFront()) { if (!pred(r.front)) continue; swap(result.front, r.front); result.popFront(); } return result; } return r; } else // ss == SwapStrategy.unstable { // Inspired from www.stepanovpapers.com/PAM3-partition_notes.pdf, // section "Bidirectional Partition Algorithm (Hoare)" static if (isDynamicArray!Range) { // For dynamic arrays prefer index-based manipulation if (!r.length) return r; size_t lo = 0, hi = r.length - 1; for (;;) { for (;;) { if (lo > hi) return r[lo .. $]; if (!pred(r[lo])) break; ++lo; } // found the left bound assert(lo <= hi); for (;;) { if (lo == hi) return r[lo .. $]; if (pred(r[hi])) break; --hi; } // found the right bound, swap & make progress swap(r[lo++], r[hi--]); } } else { auto result = r; for (;;) { for (;;) { if (r.empty) return result; if (!pred(r.front)) break; r.popFront(); result.popFront(); } // found the left bound assert(!r.empty); for (;;) { if (pred(r.back)) break; r.popBack(); if (r.empty) return result; } // found the right bound, swap & make progress static if (is(typeof(swap(r.front, r.back)))) { swap(r.front, r.back); } else { auto t1 = moveFront(r), t2 = moveBack(r); r.front = t2; r.back = t1; } r.popFront(); result.popFront(); r.popBack(); } } } } /// @safe unittest { import std.algorithm : count, find; // FIXME import std.conv : text; auto Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto arr = Arr.dup; static bool even(int a) { return (a & 1) == 0; } // Partition arr such that even numbers come first auto r = partition!(even)(arr); // Now arr is separated in evens and odds. // Numbers may have become shuffled due to instability assert(r == arr[5 .. $]); assert(count!(even)(arr[0 .. 5]) == 5); assert(find!(even)(r).empty); // Can also specify the predicate as a string. // Use 'a' as the predicate argument name arr[] = Arr[]; r = partition!(q{(a & 1) == 0})(arr); assert(r == arr[5 .. $]); // Now for a stable partition: arr[] = Arr[]; r = partition!(q{(a & 1) == 0}, SwapStrategy.stable)(arr); // Now arr is [2 4 6 8 10 1 3 5 7 9], and r points to 1 assert(arr == [2, 4, 6, 8, 10, 1, 3, 5, 7, 9] && r == arr[5 .. $]); // In case the predicate needs to hold its own state, use a delegate: arr[] = Arr[]; int x = 3; // Put stuff greater than 3 on the left bool fun(int a) { return a > x; } r = partition!(fun, SwapStrategy.semistable)(arr); // Now arr is [4 5 6 7 8 9 10 2 3 1] and r points to 2 assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1] && r == arr[7 .. $]); } @safe unittest { import std.algorithm.internal : rndstuff; static bool even(int a) { return (a & 1) == 0; } // test with random data auto a = rndstuff!int(); partition!even(a); assert(isPartitioned!even(a)); auto b = rndstuff!string(); partition!`a.length < 5`(b); assert(isPartitioned!`a.length < 5`(b)); } /** Params: pred = The predicate that the range should be partitioned by. r = The range to check. Returns: $(D true) if $(D r) is partitioned according to predicate $(D pred). */ bool isPartitioned(alias pred, Range)(Range r) if (isForwardRange!(Range)) { for (; !r.empty; r.popFront()) { if (unaryFun!(pred)(r.front)) continue; for (r.popFront(); !r.empty; r.popFront()) { if (unaryFun!(pred)(r.front)) return false; } break; } return true; } /// @safe unittest { int[] r = [ 1, 3, 5, 7, 8, 2, 4, ]; assert(isPartitioned!"a & 1"(r)); } // partition3 /** Rearranges elements in $(D r) in three adjacent ranges and returns them. The first and leftmost range only contains elements in $(D r) less than $(D pivot). The second and middle range only contains elements in $(D r) that are equal to $(D pivot). Finally, the third and rightmost range only contains elements in $(D r) that are greater than $(D pivot). The less-than test is defined by the binary function $(D less). Params: less = The predicate to use for the rearrangement. ss = The swapping strategy to use. r = The random-access range to rearrange. pivot = The pivot element. Returns: A $(XREF typecons,Tuple) of the three resulting ranges. These ranges are slices of the original range. BUGS: stable $(D partition3) has not been implemented yet. */ auto partition3(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, E) (Range r, E pivot) if (ss == SwapStrategy.unstable && isRandomAccessRange!Range && hasSwappableElements!Range && hasLength!Range && is(typeof(binaryFun!less(r.front, pivot)) == bool) && is(typeof(binaryFun!less(pivot, r.front)) == bool) && is(typeof(binaryFun!less(r.front, r.front)) == bool)) { // The algorithm is described in "Engineering a sort function" by // Jon Bentley et al, pp 1257. import std.algorithm : swap, swapRanges; // FIXME import std.algorithm.comparison : min; import std.typecons : tuple; alias lessFun = binaryFun!less; size_t i, j, k = r.length, l = k; bigloop: for (;;) { for (;; ++j) { if (j == k) break bigloop; assert(j < r.length); if (lessFun(r[j], pivot)) continue; if (lessFun(pivot, r[j])) break; swap(r[i++], r[j]); } assert(j < k); for (;;) { assert(k > 0); if (!lessFun(pivot, r[--k])) { if (lessFun(r[k], pivot)) break; swap(r[k], r[--l]); } if (j == k) break bigloop; } // Here we know r[j] > pivot && r[k] < pivot swap(r[j++], r[k]); } // Swap the equal ranges from the extremes into the middle auto strictlyLess = j - i, strictlyGreater = l - k; auto swapLen = min(i, strictlyLess); swapRanges(r[0 .. swapLen], r[j - swapLen .. j]); swapLen = min(r.length - l, strictlyGreater); swapRanges(r[k .. k + swapLen], r[r.length - swapLen .. r.length]); return tuple(r[0 .. strictlyLess], r[strictlyLess .. r.length - strictlyGreater], r[r.length - strictlyGreater .. r.length]); } /// @safe unittest { auto a = [ 8, 3, 4, 1, 4, 7, 4 ]; auto pieces = partition3(a, 4); assert(pieces[0] == [ 1, 3 ]); assert(pieces[1] == [ 4, 4, 4 ]); assert(pieces[2] == [ 8, 7 ]); } @safe unittest { import std.random : uniform; auto a = new int[](uniform(0, 100)); foreach (ref e; a) { e = uniform(0, 50); } auto pieces = partition3(a, 25); assert(pieces[0].length + pieces[1].length + pieces[2].length == a.length); foreach (e; pieces[0]) { assert(e < 25); } foreach (e; pieces[1]) { assert(e == 25); } foreach (e; pieces[2]) { assert(e > 25); } } // makeIndex /** Computes an index for $(D r) based on the comparison $(D less). The index is a sorted array of pointers or indices into the original range. This technique is similar to sorting, but it is more flexible because (1) it allows "sorting" of immutable collections, (2) allows binary search even if the original collection does not offer random access, (3) allows multiple indexes, each on a different predicate, and (4) may be faster when dealing with large objects. However, using an index may also be slower under certain circumstances due to the extra indirection, and is always larger than a sorting-based solution because it needs space for the index in addition to the original collection. The complexity is the same as $(D sort)'s. The first overload of $(D makeIndex) writes to a range containing pointers, and the second writes to a range containing offsets. The first overload requires $(D Range) to be a forward range, and the latter requires it to be a random-access range. $(D makeIndex) overwrites its second argument with the result, but never reallocates it. Params: less = The comparison to use. ss = The swapping strategy. r = The range to index. index = The resulting index. Returns: The pointer-based version returns a $(D SortedRange) wrapper over index, of type $(D SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b))) thus reflecting the ordering of the index. The index-based version returns $(D void) because the ordering relation involves not only $(D index) but also $(D r). Throws: If the second argument's length is less than that of the range indexed, an exception is thrown. */ SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b)) makeIndex( alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex) (Range r, RangeIndex index) if (isForwardRange!(Range) && isRandomAccessRange!(RangeIndex) && is(ElementType!(RangeIndex) : ElementType!(Range)*)) { import std.algorithm.internal : addressOf; import std.exception : enforce; // assume collection already ordered size_t i; for (; !r.empty; r.popFront(), ++i) index[i] = addressOf(r.front); enforce(index.length == i); // sort the index sort!((a, b) => binaryFun!less(*a, *b), ss)(index); return typeof(return)(index); } /// Ditto void makeIndex( alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex) (Range r, RangeIndex index) if (isRandomAccessRange!Range && !isInfinite!Range && isRandomAccessRange!RangeIndex && !isInfinite!RangeIndex && isIntegral!(ElementType!RangeIndex)) { import std.exception : enforce; import std.conv : to; alias IndexType = Unqual!(ElementType!RangeIndex); enforce(r.length == index.length, "r and index must be same length for makeIndex."); static if (IndexType.sizeof < size_t.sizeof) { enforce(r.length <= IndexType.max, "Cannot create an index with " ~ "element type " ~ IndexType.stringof ~ " with length " ~ to!string(r.length) ~ "."); } for (IndexType i = 0; i < r.length; ++i) { index[cast(size_t) i] = i; } // sort the index sort!((a, b) => binaryFun!less(r[cast(size_t) a], r[cast(size_t) b]), ss) (index); } /// unittest { immutable(int[]) arr = [ 2, 3, 1, 5, 0 ]; // index using pointers auto index1 = new immutable(int)*[arr.length]; makeIndex!("a < b")(arr, index1); assert(isSorted!("*a < *b")(index1)); // index using offsets auto index2 = new size_t[arr.length]; makeIndex!("a < b")(arr, index2); assert(isSorted! ((size_t a, size_t b){ return arr[a] < arr[b];}) (index2)); } unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); immutable(int)[] arr = [ 2, 3, 1, 5, 0 ]; // index using pointers auto index1 = new immutable(int)*[arr.length]; alias ImmRange = typeof(arr); alias ImmIndex = typeof(index1); static assert(isForwardRange!(ImmRange)); static assert(isRandomAccessRange!(ImmIndex)); static assert(!isIntegral!(ElementType!(ImmIndex))); static assert(is(ElementType!(ImmIndex) : ElementType!(ImmRange)*)); makeIndex!("a < b")(arr, index1); assert(isSorted!("*a < *b")(index1)); // index using offsets auto index2 = new long[arr.length]; makeIndex(arr, index2); assert(isSorted! ((long a, long b){ return arr[cast(size_t) a] < arr[cast(size_t) b]; })(index2)); // index strings using offsets string[] arr1 = ["I", "have", "no", "chocolate"]; auto index3 = new byte[arr1.length]; makeIndex(arr1, index3); assert(isSorted! ((byte a, byte b){ return arr1[a] < arr1[b];}) (index3)); } private template validPredicates(E, less...) { static if (less.length == 0) enum validPredicates = true; else static if (less.length == 1 && is(typeof(less[0]) == SwapStrategy)) enum validPredicates = true; else enum validPredicates = is(typeof((E a, E b){ bool r = binaryFun!(less[0])(a, b); })) && validPredicates!(E, less[1 .. $]); } /** $(D void multiSort(Range)(Range r) if (validPredicates!(ElementType!Range, less));) Sorts a range by multiple keys. The call $(D multiSort!("a.id < b.id", "a.date > b.date")(r)) sorts the range $(D r) by $(D id) ascending, and sorts elements that have the same $(D id) by $(D date) descending. Such a call is equivalent to $(D sort!"a.id != b.id ? a.id < b.id : a.date > b.date"(r)), but $(D multiSort) is faster because it does fewer comparisons (in addition to being more convenient). */ template multiSort(less...) //if (less.length > 1) { void multiSort(Range)(Range r) if (validPredicates!(ElementType!Range, less)) { static if (is(typeof(less[$ - 1]) == SwapStrategy)) { enum ss = less[$ - 1]; alias funs = less[0 .. $ - 1]; } else { alias ss = SwapStrategy.unstable; alias funs = less; } alias lessFun = binaryFun!(funs[0]); static if (funs.length > 1) { while (r.length > 1) { auto p = getPivot!lessFun(r); auto t = partition3!(less[0], ss)(r, r[p]); if (t[0].length <= t[2].length) { .multiSort!less(t[0]); .multiSort!(less[1 .. $])(t[1]); r = t[2]; } else { .multiSort!(less[1 .. $])(t[1]); .multiSort!less(t[2]); r = t[0]; } } } else { sort!(lessFun, ss)(r); } } } /// @safe unittest { static struct Point { int x, y; } auto pts1 = [ Point(0, 0), Point(5, 5), Point(0, 1), Point(0, 2) ]; auto pts2 = [ Point(0, 0), Point(0, 1), Point(0, 2), Point(5, 5) ]; multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts1); assert(pts1 == pts2); } @safe unittest { import std.algorithm.comparison : equal; import std.range; static struct Point { int x, y; } auto pts1 = [ Point(5, 6), Point(1, 0), Point(5, 7), Point(1, 1), Point(1, 2), Point(0, 1) ]; auto pts2 = [ Point(0, 1), Point(1, 0), Point(1, 1), Point(1, 2), Point(5, 6), Point(5, 7) ]; static assert(validPredicates!(Point, "a.x < b.x", "a.y < b.y")); multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts1); assert(pts1 == pts2); auto pts3 = indexed(pts1, iota(pts1.length)); multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts3); assert(equal(pts3, pts2)); } @safe unittest //issue 9160 (L-value only comparators) { static struct A { int x; int y; } static bool byX(const ref A lhs, const ref A rhs) { return lhs.x < rhs.x; } static bool byY(const ref A lhs, const ref A rhs) { return lhs.y < rhs.y; } auto points = [ A(4, 1), A(2, 4)]; multiSort!(byX, byY)(points); assert(points[0] == A(2, 4)); assert(points[1] == A(4, 1)); } private size_t getPivot(alias less, Range)(Range r) { import std.algorithm.mutation : swapAt; // This algorithm sorts the first, middle and last elements of r, // then returns the index of the middle element. In effect, it uses the // median-of-three heuristic. alias pred = binaryFun!(less); immutable len = r.length; immutable size_t mid = len / 2; immutable uint result = ((cast(uint) (pred(r[0], r[mid]))) << 2) | ((cast(uint) (pred(r[0], r[len - 1]))) << 1) | (cast(uint) (pred(r[mid], r[len - 1]))); switch(result) { case 0b001: swapAt(r, 0, len - 1); swapAt(r, 0, mid); break; case 0b110: swapAt(r, mid, len - 1); break; case 0b011: swapAt(r, 0, mid); break; case 0b100: swapAt(r, mid, len - 1); swapAt(r, 0, mid); break; case 0b000: swapAt(r, 0, len - 1); break; case 0b111: break; default: assert(0); } return mid; } private void optimisticInsertionSort(alias less, Range)(Range r) { import std.algorithm.mutation : swapAt; alias pred = binaryFun!(less); if (r.length < 2) { return; } immutable maxJ = r.length - 1; for (size_t i = r.length - 2; i != size_t.max; --i) { size_t j = i; static if (hasAssignableElements!Range) { auto temp = r[i]; for (; j < maxJ && pred(r[j + 1], temp); ++j) { r[j] = r[j + 1]; } r[j] = temp; } else { for (; j < maxJ && pred(r[j + 1], r[j]); ++j) { swapAt(r, j, j + 1); } } } } @safe unittest { import std.random : Random, uniform; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto rnd = Random(1); auto a = new int[uniform(100, 200, rnd)]; foreach (ref e; a) { e = uniform(-100, 100, rnd); } optimisticInsertionSort!(binaryFun!("a < b"), int[])(a); assert(isSorted(a)); } // sort /** Sorts a random-access range according to the predicate $(D less). Performs $(BIGOH r.length * log(r.length)) evaluations of $(D less). Stable sorting requires $(D hasAssignableElements!Range) to be true. $(D sort) returns a $(XREF range, SortedRange) over the original range, which functions that can take advantage of sorted data can then use to know that the range is sorted and adjust accordingly. The $(XREF range, SortedRange) is a wrapper around the original range, so both it and the original range are sorted, but other functions won't know that the original range has been sorted, whereas they $(I can) know that $(XREF range, SortedRange) has been sorted. The predicate is expected to satisfy certain rules in order for $(D sort) to behave as expected - otherwise, the program may fail on certain inputs (but not others) when not compiled in release mode, due to the cursory $(D assumeSorted) check. Specifically, $(D sort) expects $(D less(a,b) && less(b,c)) to imply $(D less(a,c)) (transitivity), and, conversely, $(D !less(a,b) && !less(b,c)) to imply $(D !less(a,c)). Note that the default predicate ($(D "a < b")) does not always satisfy these conditions for floating point types, because the expression will always be $(D false) when either $(D a) or $(D b) is NaN. Use $(XREF math, cmp) instead. If `less` involves expensive computations on the _sort key, it may be worthwhile to use $(LREF schwartzSort) instead. Params: less = The predicate to sort by. ss = The swapping strategy to use. r = The range to sort. Returns: The initial range wrapped as a $(D SortedRange) with the predicate $(D binaryFun!less). Algorithms: $(WEB en.wikipedia.org/wiki/Introsort) is used for unstable sorting and $(WEB en.wikipedia.org/wiki/Timsort, Timsort) is used for stable sorting. Each algorithm has benefits beyond stability. Introsort is generally faster but Timsort may achieve greater speeds on data with low entropy or if predicate calls are expensive. Introsort performs no allocations whereas Timsort will perform one or more allocations per call. Both algorithms have $(BIGOH n log n) worst-case time complexity. See_Also: $(XREF range, assumeSorted)$(BR) $(XREF range, SortedRange)$(BR) $(XREF_PACK algorithm,mutation,SwapStrategy)$(BR) $(XREF functional, binaryFun) */ SortedRange!(Range, less) sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r) if (((ss == SwapStrategy.unstable && (hasSwappableElements!Range || hasAssignableElements!Range)) || (ss != SwapStrategy.unstable && hasAssignableElements!Range)) && isRandomAccessRange!Range && hasSlicing!Range && hasLength!Range) /+ Unstable sorting uses the quicksort algorithm, which uses swapAt, which either uses swap(...), requiring swappable elements, or just swaps using assignment. Stable sorting uses TimSort, which needs to copy elements into a buffer, requiring assignable elements. +/ { import std.range : assumeSorted; alias lessFun = binaryFun!(less); alias LessRet = typeof(lessFun(r.front, r.front)); // instantiate lessFun static if (is(LessRet == bool)) { static if (ss == SwapStrategy.unstable) quickSortImpl!(lessFun)(r, r.length); else //use Tim Sort for semistable & stable TimSortImpl!(lessFun, Range).sort(r, null); enum maxLen = 8; assert(isSorted!lessFun(r), "Failed to sort range of type " ~ Range.stringof); } else { static assert(false, "Invalid predicate passed to sort: " ~ less.stringof); } return assumeSorted!less(r); } /// @safe pure nothrow unittest { int[] array = [ 1, 2, 3, 4 ]; // sort in descending order sort!("a > b")(array); assert(array == [ 4, 3, 2, 1 ]); // sort in ascending order sort(array); assert(array == [ 1, 2, 3, 4 ]); // sort with a delegate bool myComp(int x, int y) @safe pure nothrow { return x > y; } sort!(myComp)(array); assert(array == [ 4, 3, 2, 1 ]); } /// unittest { // Showcase stable sorting string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ]; sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words); assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]); } /// unittest { // Sorting floating-point numbers in presence of NaN double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan]; import std.math : cmp, isIdentical; import std.algorithm.comparison : equal; sort!((a, b) => cmp(a, b) < 0)(numbers); double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan]; assert(numbers.equal!isIdentical(sorted)); } unittest { import std.algorithm.internal : rndstuff; import std.algorithm : swapRanges; // FIXME import std.random : Random, unpredictableSeed, uniform; import std.uni : toUpper; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); // sort using delegate auto a = new int[100]; auto rnd = Random(unpredictableSeed); foreach (ref e; a) { e = uniform(-100, 100, rnd); } int i = 0; bool greater2(int a, int b) { return a + i > b + i; } bool delegate(int, int) greater = &greater2; sort!(greater)(a); assert(isSorted!(greater)(a)); // sort using string sort!("a < b")(a); assert(isSorted!("a < b")(a)); // sort using function; all elements equal foreach (ref e; a) { e = 5; } static bool less(int a, int b) { return a < b; } sort!(less)(a); assert(isSorted!(less)(a)); string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ]; bool lessi(string a, string b) { return toUpper(a) < toUpper(b); } sort!(lessi, SwapStrategy.stable)(words); assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]); // sort using ternary predicate //sort!("b - a")(a); //assert(isSorted!(less)(a)); a = rndstuff!(int)(); sort(a); assert(isSorted(a)); auto b = rndstuff!(string)(); sort!("toLower(a) < toLower(b)")(b); assert(isSorted!("toUpper(a) < toUpper(b)")(b)); { // Issue 10317 enum E_10317 { a, b } auto a_10317 = new E_10317[10]; sort(a_10317); } { // Issue 7767 // Unstable sort should complete without an excessive number of predicate calls // This would suggest it's running in quadratic time // Compilation error if predicate is not static, i.e. a nested function static uint comp; static bool pred(size_t a, size_t b) { ++comp; return a < b; } size_t[] arr; arr.length = 1024; foreach(k; 0..arr.length) arr[k] = k; swapRanges(arr[0..$/2], arr[$/2..$]); sort!(pred, SwapStrategy.unstable)(arr); assert(comp < 25_000); } { import std.algorithm : swap; // FIXME bool proxySwapCalled; struct S { int i; alias i this; void proxySwap(ref S other) { swap(i, other.i); proxySwapCalled = true; } @disable void opAssign(S value); } alias R = S[]; R r = [S(3), S(2), S(1)]; static assert(hasSwappableElements!R); static assert(!hasAssignableElements!R); r.sort(); assert(proxySwapCalled); } } private void quickSortImpl(alias less, Range)(Range r, size_t depth) { import std.algorithm : swap; // FIXME import std.algorithm.mutation : swapAt; import std.algorithm.comparison : min; alias Elem = ElementType!(Range); enum size_t optimisticInsertionSortGetsBetter = 25; static assert(optimisticInsertionSortGetsBetter >= 1); // partition while (r.length > optimisticInsertionSortGetsBetter) { if (depth == 0) { HeapOps!(less, Range).heapSort(r); return; } depth = depth >= depth.max / 2 ? (depth / 3) * 2 : (depth * 2) / 3; const pivotIdx = getPivot!(less)(r); auto pivot = r[pivotIdx]; alias pred = binaryFun!(less); // partition swapAt(r, pivotIdx, r.length - 1); size_t lessI = size_t.max, greaterI = r.length - 1; while (true) { while (pred(r[++lessI], pivot)) {} while (greaterI > 0 && pred(pivot, r[--greaterI])) {} if (lessI >= greaterI) { break; } swapAt(r, lessI, greaterI); } swapAt(r, r.length - 1, lessI); auto right = r[lessI + 1 .. r.length]; auto left = r[0 .. min(lessI, greaterI + 1)]; if (right.length > left.length) { swap(left, right); } .quickSortImpl!(less, Range)(right, depth); r = left; } // residual sort static if (optimisticInsertionSortGetsBetter > 1) { optimisticInsertionSort!(less, Range)(r); } } // Heap operations for random-access ranges package(std) template HeapOps(alias less, Range) { import std.algorithm.mutation : swapAt; static assert(isRandomAccessRange!Range); static assert(hasLength!Range); static assert(hasSwappableElements!Range || hasAssignableElements!Range); alias lessFun = binaryFun!less; //template because of @@@12410@@@ void heapSort()(Range r) { // If true, there is nothing to do if (r.length < 2) return; // Build Heap buildHeap(r); // Sort for (size_t i = r.length - 1; i > 0; --i) { r.swapAt(0, i); percolate(r, 0, i); } } //template because of @@@12410@@@ void buildHeap()(Range r) { immutable n = r.length; for (size_t i = n / 2; i-- > 0; ) { siftDown(r, i, n); } assert(isHeap(r)); } bool isHeap()(Range r) { size_t parent = 0; foreach (child; 1 .. r.length) { if (lessFun(r[parent], r[child])) return false; // Increment parent every other pass parent += !(child & 1); } return true; } // Sifts down r[parent] (which is initially assumed to be messed up) so the // heap property is restored for r[parent .. end]. // template because of @@@12410@@@ void siftDown()(Range r, size_t parent, immutable size_t end) { for (;;) { auto child = (parent + 1) * 2; if (child >= end) { // Leftover left child? if (child == end && lessFun(r[parent], r[--child])) r.swapAt(parent, child); break; } auto leftChild = child - 1; if (lessFun(r[child], r[leftChild])) child = leftChild; if (!lessFun(r[parent], r[child])) break; r.swapAt(parent, child); parent = child; } } // Alternate version of siftDown that performs fewer comparisons, see // https://en.wikipedia.org/wiki/Heapsort#Bottom-up_heapsort. The percolate // process first sifts the parent all the way down (without comparing it // against the leaves), and then a bit up until the heap property is // restored. So there are more swaps but fewer comparisons. Gains are made // when the final position is likely to end toward the bottom of the heap, // so not a lot of sifts back are performed. //template because of @@@12410@@@ void percolate()(Range r, size_t parent, immutable size_t end) { immutable root = parent; // Sift down for (;;) { auto child = (parent + 1) * 2; if (child >= end) { if (child == end) { // Leftover left node. --child; r.swapAt(parent, child); parent = child; } break; } auto leftChild = child - 1; if (lessFun(r[child], r[leftChild])) child = leftChild; r.swapAt(parent, child); parent = child; } // Sift up for (auto child = parent; child > root; child = parent) { parent = (child - 1) / 2; if (!lessFun(r[parent], r[child])) break; r.swapAt(parent, child); } } } // Tim Sort implementation private template TimSortImpl(alias pred, R) { import core.bitop : bsr; import std.array : uninitializedArray; static assert(isRandomAccessRange!R); static assert(hasLength!R); static assert(hasSlicing!R); static assert(hasAssignableElements!R); alias T = ElementType!R; alias less = binaryFun!pred; bool greater(T a, T b){ return less(b, a); } bool greaterEqual(T a, T b){ return !less(a, b); } bool lessEqual(T a, T b){ return !less(b, a); } enum minimalMerge = 128; enum minimalGallop = 7; enum minimalStorage = 256; enum stackSize = 40; struct Slice{ size_t base, length; } // Entry point for tim sort void sort(R range, T[] temp) { import std.algorithm.comparison : min; // Do insertion sort on small range if (range.length <= minimalMerge) { binaryInsertionSort(range); return; } immutable minRun = minRunLength(range.length); immutable minTemp = min(range.length / 2, minimalStorage); size_t minGallop = minimalGallop; Slice[stackSize] stack = void; size_t stackLen = 0; // Allocate temporary memory if not provided by user if (temp.length < minTemp) temp = uninitializedArray!(T[])(minTemp); for (size_t i = 0; i < range.length; ) { // Find length of first run in list size_t runLen = firstRun(range[i .. range.length]); // If run has less than minRun elements, extend using insertion sort if (runLen < minRun) { // Do not run farther than the length of the range immutable force = range.length - i > minRun ? minRun : range.length - i; binaryInsertionSort(range[i .. i + force], runLen); runLen = force; } // Push run onto stack stack[stackLen++] = Slice(i, runLen); i += runLen; // Collapse stack so that (e1 > e2 + e3 && e2 > e3) // STACK is | ... e1 e2 e3 > while (stackLen > 1) { immutable run4 = stackLen - 1; immutable run3 = stackLen - 2; immutable run2 = stackLen - 3; immutable run1 = stackLen - 4; if ( (stackLen > 2 && stack[run2].length <= stack[run3].length + stack[run4].length) || (stackLen > 3 && stack[run1].length <= stack[run3].length + stack[run2].length) ) { immutable at = stack[run2].length < stack[run4].length ? run2 : run3; mergeAt(range, stack[0 .. stackLen], at, minGallop, temp); } else if (stack[run3].length > stack[run4].length) break; else mergeAt(range, stack[0 .. stackLen], run3, minGallop, temp); stackLen -= 1; } // Assert that the code above established the invariant correctly version (assert) { if (stackLen == 2) assert(stack[0].length > stack[1].length); else if (stackLen > 2) { foreach(k; 2 .. stackLen) { assert(stack[k - 2].length > stack[k - 1].length + stack[k].length); assert(stack[k - 1].length > stack[k].length); } } } } // Force collapse stack until there is only one run left while (stackLen > 1) { immutable run3 = stackLen - 1; immutable run2 = stackLen - 2; immutable run1 = stackLen - 3; immutable at = stackLen >= 3 && stack[run1].length <= stack[run3].length ? run1 : run2; mergeAt(range, stack[0 .. stackLen], at, minGallop, temp); --stackLen; } } // Calculates optimal value for minRun: // take first 6 bits of n and add 1 if any lower bits are set pure size_t minRunLength(size_t n) { immutable shift = bsr(n)-5; auto result = (n>>shift) + !!(n & ~((1<lower; upper--) range[upper] = moveAt(range, upper-1); range[lower] = move(item); } } // Merge two runs in stack (at, at + 1) void mergeAt(R range, Slice[] stack, immutable size_t at, ref size_t minGallop, ref T[] temp) in { assert(stack.length >= 2); assert(stack.length - at == 2 || stack.length - at == 3); } body { immutable base = stack[at].base; immutable mid = stack[at].length; immutable len = stack[at + 1].length + mid; // Pop run from stack stack[at] = Slice(base, len); if (stack.length - at == 3) stack[$ - 2] = stack[$ - 1]; // Merge runs (at, at + 1) return merge(range[base .. base + len], mid, minGallop, temp); } // Merge two runs in a range. Mid is the starting index of the second run. // minGallop and temp are references; The calling function must receive the updated values. void merge(R range, size_t mid, ref size_t minGallop, ref T[] temp) in { if (!__ctfe) { assert(isSorted!pred(range[0 .. mid])); assert(isSorted!pred(range[mid .. range.length])); } } body { assert(mid < range.length); // Reduce range of elements immutable firstElement = gallopForwardUpper(range[0 .. mid], range[mid]); immutable lastElement = gallopReverseLower(range[mid .. range.length], range[mid - 1]) + mid; range = range[firstElement .. lastElement]; mid -= firstElement; if (mid == 0 || mid == range.length) return; // Call function which will copy smaller run into temporary memory if (mid <= range.length / 2) { temp = ensureCapacity(mid, temp); minGallop = mergeLo(range, mid, minGallop, temp); } else { temp = ensureCapacity(range.length - mid, temp); minGallop = mergeHi(range, mid, minGallop, temp); } } // Enlarge size of temporary memory if needed T[] ensureCapacity(size_t minCapacity, T[] temp) out(ret) { assert(ret.length >= minCapacity); } body { if (temp.length < minCapacity) { size_t newSize = 1<<(bsr(minCapacity)+1); //Test for overflow if (newSize < minCapacity) newSize = minCapacity; if (__ctfe) temp.length = newSize; else temp = uninitializedArray!(T[])(newSize); } return temp; } // Merge front to back. Returns new value of minGallop. // temp must be large enough to store range[0 .. mid] size_t mergeLo(R range, immutable size_t mid, size_t minGallop, T[] temp) out { if (!__ctfe) assert(isSorted!pred(range)); } body { import std.algorithm : copy; // FIXME assert(mid <= range.length); assert(temp.length >= mid); // Copy run into temporary memory temp = temp[0 .. mid]; copy(range[0 .. mid], temp); // Move first element into place range[0] = range[mid]; size_t i = 1, lef = 0, rig = mid + 1; size_t count_lef, count_rig; immutable lef_end = temp.length - 1; if (lef < lef_end && rig < range.length) outer: while(true) { count_lef = 0; count_rig = 0; // Linear merge while ((count_lef | count_rig) < minGallop) { if (lessEqual(temp[lef], range[rig])) { range[i++] = temp[lef++]; if(lef >= lef_end) break outer; ++count_lef; count_rig = 0; } else { range[i++] = range[rig++]; if(rig >= range.length) break outer; count_lef = 0; ++count_rig; } } // Gallop merge do { count_lef = gallopForwardUpper(temp[lef .. $], range[rig]); foreach (j; 0 .. count_lef) range[i++] = temp[lef++]; if(lef >= temp.length) break outer; count_rig = gallopForwardLower(range[rig .. range.length], temp[lef]); foreach (j; 0 .. count_rig) range[i++] = range[rig++]; if (rig >= range.length) while(true) { range[i++] = temp[lef++]; if(lef >= temp.length) break outer; } if (minGallop > 0) --minGallop; } while (count_lef >= minimalGallop || count_rig >= minimalGallop); minGallop += 2; } // Move remaining elements from right while (rig < range.length) range[i++] = range[rig++]; // Move remaining elements from left while (lef < temp.length) range[i++] = temp[lef++]; return minGallop > 0 ? minGallop : 1; } // Merge back to front. Returns new value of minGallop. // temp must be large enough to store range[mid .. range.length] size_t mergeHi(R range, immutable size_t mid, size_t minGallop, T[] temp) out { if (!__ctfe) assert(isSorted!pred(range)); } body { import std.algorithm : copy; // FIXME assert(mid <= range.length); assert(temp.length >= range.length - mid); // Copy run into temporary memory temp = temp[0 .. range.length - mid]; copy(range[mid .. range.length], temp); // Move first element into place range[range.length - 1] = range[mid - 1]; size_t i = range.length - 2, lef = mid - 2, rig = temp.length - 1; size_t count_lef, count_rig; outer: while(true) { count_lef = 0; count_rig = 0; // Linear merge while((count_lef | count_rig) < minGallop) { if(greaterEqual(temp[rig], range[lef])) { range[i--] = temp[rig]; if(rig == 1) { // Move remaining elements from left while(true) { range[i--] = range[lef]; if(lef == 0) break; --lef; } // Move last element into place range[i] = temp[0]; break outer; } --rig; count_lef = 0; ++count_rig; } else { range[i--] = range[lef]; if(lef == 0) while(true) { range[i--] = temp[rig]; if(rig == 0) break outer; --rig; } --lef; ++count_lef; count_rig = 0; } } // Gallop merge do { count_rig = rig - gallopReverseLower(temp[0 .. rig], range[lef]); foreach(j; 0 .. count_rig) { range[i--] = temp[rig]; if(rig == 0) break outer; --rig; } count_lef = lef - gallopReverseUpper(range[0 .. lef], temp[rig]); foreach(j; 0 .. count_lef) { range[i--] = range[lef]; if(lef == 0) while(true) { range[i--] = temp[rig]; if(rig == 0) break outer; --rig; } --lef; } if(minGallop > 0) --minGallop; } while(count_lef >= minimalGallop || count_rig >= minimalGallop); minGallop += 2; } return minGallop > 0 ? minGallop : 1; } // false = forward / lower, true = reverse / upper template gallopSearch(bool forwardReverse, bool lowerUpper) { // Gallop search on range according to attributes forwardReverse and lowerUpper size_t gallopSearch(R)(R range, T value) out(ret) { assert(ret <= range.length); } body { size_t lower = 0, center = 1, upper = range.length; alias gap = center; static if (forwardReverse) { static if (!lowerUpper) alias comp = lessEqual; // reverse lower static if (lowerUpper) alias comp = less; // reverse upper // Gallop Search Reverse while (gap <= upper) { if (comp(value, range[upper - gap])) { upper -= gap; gap *= 2; } else { lower = upper - gap; break; } } // Binary Search Reverse while (upper != lower) { center = lower + (upper - lower) / 2; if (comp(value, range[center])) upper = center; else lower = center + 1; } } else { static if (!lowerUpper) alias comp = greater; // forward lower static if (lowerUpper) alias comp = greaterEqual; // forward upper // Gallop Search Forward while (lower + gap < upper) { if (comp(value, range[lower + gap])) { lower += gap; gap *= 2; } else { upper = lower + gap; break; } } // Binary Search Forward while (lower != upper) { center = lower + (upper - lower) / 2; if (comp(value, range[center])) lower = center + 1; else upper = center; } } return lower; } } alias gallopForwardLower = gallopSearch!(false, false); alias gallopForwardUpper = gallopSearch!(false, true); alias gallopReverseLower = gallopSearch!( true, false); alias gallopReverseUpper = gallopSearch!( true, true); } unittest { import std.random : Random, uniform, randomShuffle; // Element type with two fields static struct E { size_t value, index; } // Generates data especially for testing sorting with Timsort static E[] genSampleData(uint seed) { import std.algorithm : swap, swapRanges; // FIXME auto rnd = Random(seed); E[] arr; arr.length = 64 * 64; // We want duplicate values for testing stability foreach(i, ref v; arr) v.value = i / 64; // Swap ranges at random middle point (test large merge operation) immutable mid = uniform(arr.length / 4, arr.length / 4 * 3, rnd); swapRanges(arr[0 .. mid], arr[mid .. $]); // Shuffle last 1/8 of the array (test insertion sort and linear merge) randomShuffle(arr[$ / 8 * 7 .. $], rnd); // Swap few random elements (test galloping mode) foreach(i; 0 .. arr.length / 64) { immutable a = uniform(0, arr.length, rnd), b = uniform(0, arr.length, rnd); swap(arr[a], arr[b]); } // Now that our test array is prepped, store original index value // This will allow us to confirm the array was sorted stably foreach(i, ref v; arr) v.index = i; return arr; } // Tests the Timsort function for correctness and stability static bool testSort(uint seed) { auto arr = genSampleData(seed); // Now sort the array! static bool comp(E a, E b) { return a.value < b.value; } sort!(comp, SwapStrategy.stable)(arr); // Test that the array was sorted correctly assert(isSorted!comp(arr)); // Test that the array was sorted stably foreach(i; 0 .. arr.length - 1) { if(arr[i].value == arr[i + 1].value) assert(arr[i].index < arr[i + 1].index); } return true; } enum seed = 310614065; testSort(seed); //@@BUG: Timsort fails with CTFE as of DMD 2.060 // enum result = testSort(seed); } unittest {//bugzilla 4584 assert(isSorted!"a < b"(sort!("a < b", SwapStrategy.stable)( [83, 42, 85, 86, 87, 22, 89, 30, 91, 46, 93, 94, 95, 6, 97, 14, 33, 10, 101, 102, 103, 26, 105, 106, 107, 6] ))); } unittest { //test stable sort + zip import std.range; auto x = [10, 50, 60, 60, 20]; dchar[] y = "abcde"d.dup; sort!("a[0] < b[0]", SwapStrategy.stable)(zip(x, y)); assert(x == [10, 20, 50, 60, 60]); assert(y == "aebcd"d); } unittest { // Issue 14223 import std.range, std.array; auto arr = chain(iota(0, 384), iota(0, 256), iota(0, 80), iota(0, 64), iota(0, 96)).array; sort!("a < b", SwapStrategy.stable)(arr); } // schwartzSort /** Alternative sorting method that should be used when comparing keys involves an expensive computation. Instead of using `less(a, b)` for comparing elements, `schwartzSort` uses `less(transform(a), transform(b))`. The values of the `transform` function are precomputed in a temporary array, thus saving on repeatedly computing it. Conversely, if the cost of `transform` is small compared to the cost of allocating and filling the precomputed array, `sort` may be faster and therefore preferable. This approach to sorting is akin to the $(WEB wikipedia.org/wiki/Schwartzian_transform, Schwartzian transform), also known as the decorate-sort-undecorate pattern in Python and Lisp. The complexity is the same as that of the corresponding `sort`, but `schwartzSort` evaluates `transform` only `r.length` times (less than half when compared to regular sorting). The usage can be best illustrated with an example. Example: ---- uint hashFun(string) { ... expensive computation ... } string[] array = ...; // Sort strings by hash, slow sort!((a, b) => hashFun(a) < hashFun(b))(array); // Sort strings by hash, fast (only computes arr.length hashes): schwartzSort!(hashFun, "a < b")(array); ---- The $(D schwartzSort) function might require less temporary data and be faster than the Perl idiom or the decorate-sort-undecorate idiom present in Python and Lisp. This is because sorting is done in-place and only minimal extra data (one array of transformed elements) is created. To check whether an array was sorted and benefit of the speedup of Schwartz sorting, a function $(D schwartzIsSorted) is not provided because the effect can be achieved by calling $(D isSorted!less(map!transform(r))). Params: transform = The transformation to apply. less = The predicate to sort by. ss = The swapping strategy to use. r = The range to sort. Returns: The initial range wrapped as a $(D SortedRange) with the predicate $(D (a, b) => binaryFun!less(transform(a), transform(b))). */ SortedRange!(R, ((a, b) => binaryFun!less(unaryFun!transform(a), unaryFun!transform(b)))) schwartzSort(alias transform, alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, R)(R r) if (isRandomAccessRange!R && hasLength!R) { import core.stdc.stdlib : malloc, free; import std.conv : emplace; import std.string : representation; import std.range : zip, SortedRange; alias T = typeof(unaryFun!transform(r.front)); auto xform1 = (cast(T*) malloc(r.length * T.sizeof))[0 .. r.length]; size_t length; scope(exit) { static if (hasElaborateDestructor!T) { foreach (i; 0 .. length) collectException(destroy(xform1[i])); } free(xform1.ptr); } for (; length != r.length; ++length) { emplace(xform1.ptr + length, unaryFun!transform(r[length])); } // Make sure we use ubyte[] and ushort[], not char[] and wchar[] // for the intermediate array, lest zip gets confused. static if (isNarrowString!(typeof(xform1))) { auto xform = xform1.representation(); } else { alias xform = xform1; } zip(xform, r).sort!((a, b) => binaryFun!less(a[0], b[0]), ss)(); return typeof(return)(r); } unittest { // issue 4909 import std.typecons : Tuple; Tuple!(char)[] chars; schwartzSort!"a[0]"(chars); } unittest { // issue 5924 import std.typecons : Tuple; Tuple!(char)[] chars; schwartzSort!((Tuple!(char) c){ return c[0]; })(chars); } unittest { import std.algorithm.iteration : map; import std.math : log2; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); static double entropy(double[] probs) { double result = 0; foreach (p; probs) { if (!p) continue; //enforce(p > 0 && p <= 1, "Wrong probability passed to entropy"); result -= p * log2(p); } return result; } auto lowEnt = [ 1.0, 0, 0 ], midEnt = [ 0.1, 0.1, 0.8 ], highEnt = [ 0.31, 0.29, 0.4 ]; auto arr = new double[][3]; arr[0] = midEnt; arr[1] = lowEnt; arr[2] = highEnt; schwartzSort!(entropy, q{a > b})(arr); assert(arr[0] == highEnt); assert(arr[1] == midEnt); assert(arr[2] == lowEnt); assert(isSorted!("a > b")(map!(entropy)(arr))); } unittest { import std.algorithm.iteration : map; import std.math : log2; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); static double entropy(double[] probs) { double result = 0; foreach (p; probs) { if (!p) continue; //enforce(p > 0 && p <= 1, "Wrong probability passed to entropy"); result -= p * log2(p); } return result; } auto lowEnt = [ 1.0, 0, 0 ], midEnt = [ 0.1, 0.1, 0.8 ], highEnt = [ 0.31, 0.29, 0.4 ]; auto arr = new double[][3]; arr[0] = midEnt; arr[1] = lowEnt; arr[2] = highEnt; schwartzSort!(entropy, q{a < b})(arr); assert(arr[0] == lowEnt); assert(arr[1] == midEnt); assert(arr[2] == highEnt); assert(isSorted!("a < b")(map!(entropy)(arr))); } // partialSort /** Reorders the random-access range $(D r) such that the range $(D r[0 .. mid]) is the same as if the entire $(D r) were sorted, and leaves the range $(D r[mid .. r.length]) in no particular order. Performs $(BIGOH r.length * log(mid)) evaluations of $(D pred). The implementation simply calls $(D topN!(less, ss)(r, n)) and then $(D sort!(less, ss)(r[0 .. n])). Params: less = The predicate to sort by. ss = The swapping strategy to use. r = The random-access range to reorder. n = The length of the initial segment of `r` to sort. */ void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r, size_t n) if (isRandomAccessRange!(Range) && hasLength!(Range) && hasSlicing!(Range)) { topN!(less, ss)(r, n); sort!(less, ss)(r[0 .. n]); } /// @safe unittest { int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]; partialSort(a, 5); assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]); } // topN /** Reorders the range $(D r) using $(D swap) such that $(D r[nth]) refers to the element that would fall there if the range were fully sorted. In addition, it also partitions $(D r) such that all elements $(D e1) from $(D r[0]) to $(D r[nth]) satisfy $(D !less(r[nth], e1)), and all elements $(D e2) from $(D r[nth]) to $(D r[r.length]) satisfy $(D !less(e2, r[nth])). Effectively, it finds the nth smallest (according to $(D less)) elements in $(D r). Performs an expected $(BIGOH r.length) (if unstable) or $(BIGOH r.length * log(r.length)) (if stable) evaluations of $(D less) and $(D swap). If $(D n >= r.length), the algorithm has no effect and returns `r[0 .. $]`. Params: less = The predicate to sort by. ss = The swapping strategy to use. r = The random-access range to reorder. nth = The index of the element that should be in sorted position after the function is done. See_Also: $(LREF topNIndex), $(WEB sgi.com/tech/stl/nth_element.html, STL's nth_element) BUGS: Stable topN has not been implemented yet. */ auto topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r, size_t nth) if (isRandomAccessRange!(Range) && hasLength!Range && hasSlicing!Range) { static assert(ss == SwapStrategy.unstable, "Stable topN not yet implemented"); if (nth >= r.length) return r[0 .. $]; auto ret = r[0 .. nth]; for (;;) { assert(nth < r.length); import std.algorithm.mutation : swap; import std.algorithm.searching : minPos; if (nth == 0) { // Special-case "min" swap(r.front, r.minPos!less.front); break; } if (nth + 1 == r.length) { // Special-case "max" swap(r.back, r.minPos!((a, b) => binaryFun!less(b, a)).front); break; } auto pivot = r.getPivot!less; assert(!binaryFun!less(r[pivot], r[pivot])); swap(r[pivot], r.back); auto right = r.partition!(a => binaryFun!less(a, r.back), ss); assert(right.length >= 1); pivot = r.length - right.length; if (pivot > nth) { // We don't care to swap the pivot back, won't be visited anymore assert(pivot < r.length); r = r[0 .. pivot]; continue; } // Swap the pivot to where it should be swap(right.front, r.back); if (pivot == nth) { // Found Waldo! break; } ++pivot; // skip the pivot r = r[pivot .. $]; nth -= pivot; } return ret; } /// @safe unittest { int[] v = [ 25, 7, 9, 2, 0, 5, 21 ]; topN!"a < b"(v, 100); assert(v == [ 25, 7, 9, 2, 0, 5, 21 ]); auto n = 4; topN!"a < b"(v, n); assert(v[n] == 9); } @safe unittest { import std.algorithm.comparison : max, min; import std.algorithm.iteration : reduce; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); //scope(failure) writeln(stderr, "Failure testing algorithm"); //auto v = [ 25, 7, 9, 2, 0, 5, 21 ]; int[] v = [ 7, 6, 5, 4, 3, 2, 1, 0 ]; ptrdiff_t n = 3; topN!("a < b")(v, n); assert(reduce!max(v[0 .. n]) <= v[n]); assert(reduce!min(v[n + 1 .. $]) >= v[n]); // v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5]; n = 3; topN(v, n); assert(reduce!max(v[0 .. n]) <= v[n]); assert(reduce!min(v[n + 1 .. $]) >= v[n]); // v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5]; n = 1; topN(v, n); assert(reduce!max(v[0 .. n]) <= v[n]); assert(reduce!min(v[n + 1 .. $]) >= v[n]); // v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5]; n = v.length - 1; topN(v, n); assert(v[n] == 7); // v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5]; n = 0; topN(v, n); assert(v[n] == 1); double[][] v1 = [[-10, -5], [-10, -3], [-10, -5], [-10, -4], [-10, -5], [-9, -5], [-9, -3], [-9, -5],]; // double[][] v1 = [ [-10, -5], [-10, -4], [-9, -5], [-9, -5], // [-10, -5], [-10, -3], [-10, -5], [-9, -3],]; double[]*[] idx = [ &v1[0], &v1[1], &v1[2], &v1[3], &v1[4], &v1[5], &v1[6], &v1[7], ]; auto mid = v1.length / 2; topN!((a, b){ return (*a)[1] < (*b)[1]; })(idx, mid); foreach (e; idx[0 .. mid]) assert((*e)[1] <= (*idx[mid])[1]); foreach (e; idx[mid .. $]) assert((*e)[1] >= (*idx[mid])[1]); } @safe unittest { import std.algorithm.comparison : max, min; import std.algorithm.iteration : reduce; import std.random : uniform; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = new int[uniform(1, 10000)]; foreach (ref e; a) e = uniform(-1000, 1000); auto k = uniform(0, a.length); topN(a, k); if (k > 0) { auto left = reduce!max(a[0 .. k]); assert(left <= a[k]); } if (k + 1 < a.length) { auto right = reduce!min(a[k + 1 .. $]); assert(right >= a[k]); } } // bug 12987 @safe unittest { int[] a = [ 25, 7, 9, 2, 0, 5, 21 ]; auto n = 4; auto t = topN(a, n); sort(t); assert(t == [0, 2, 5, 7]); } /** Stores the smallest elements of the two ranges in the left-hand range. Params: less = The predicate to sort by. ss = The swapping strategy to use. r1 = The first range. r2 = The second range. */ auto topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(Range1 r1, Range2 r2) if (isRandomAccessRange!(Range1) && hasLength!Range1 && isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2)) { import std.container : BinaryHeap; static assert(ss == SwapStrategy.unstable, "Stable topN not yet implemented"); auto heap = BinaryHeap!(Range1, less)(r1); for (; !r2.empty; r2.popFront()) { heap.conditionalInsert(r2.front); } return r1; } /// unittest { int[] a = [ 5, 7, 2, 6, 7 ]; int[] b = [ 2, 1, 5, 6, 7, 3, 0 ]; topN(a, b); sort(a); assert(a == [0, 1, 2, 2, 3]); } // bug 12987 unittest { int[] a = [ 5, 7, 2, 6, 7 ]; int[] b = [ 2, 1, 5, 6, 7, 3, 0 ]; auto t = topN(a, b); sort(t); assert(t == [ 0, 1, 2, 2, 3 ]); } // bug 15420 unittest { int[] a = [ 5, 7, 2, 6, 7 ]; int[] b = [ 2, 1, 5, 6, 7, 3, 0 ]; topN!"a > b"(a, b); sort!"a > b"(a); assert(a == [ 7, 7, 7, 6, 6 ]); } /** Copies the top $(D n) elements of the input range $(D source) into the random-access range $(D target), where $(D n = target.length). Elements of $(D source) are not touched. If $(D sorted) is $(D true), the target is sorted. Otherwise, the target respects the $(WEB en.wikipedia.org/wiki/Binary_heap, heap property). Params: less = The predicate to sort by. source = The source range. target = The target range. sorted = Whether to sort the elements copied into `target`. Returns: The slice of `target` containing the copied elements. */ TRange topNCopy(alias less = "a < b", SRange, TRange) (SRange source, TRange target, SortOutput sorted = SortOutput.no) if (isInputRange!(SRange) && isRandomAccessRange!(TRange) && hasLength!(TRange) && hasSlicing!(TRange)) { import std.container : BinaryHeap; if (target.empty) return target; auto heap = BinaryHeap!(TRange, less)(target, 0); foreach (e; source) heap.conditionalInsert(e); auto result = target[0 .. heap.length]; if (sorted == SortOutput.yes) { while (!heap.empty) heap.removeFront(); } return result; } /// unittest { int[] a = [ 10, 16, 2, 3, 1, 5, 0 ]; int[] b = new int[3]; topNCopy(a, b, SortOutput.yes); assert(b == [ 0, 1, 2 ]); } unittest { import std.random : Random, unpredictableSeed, uniform, randomShuffle; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto r = Random(unpredictableSeed); ptrdiff_t[] a = new ptrdiff_t[uniform(1, 1000, r)]; foreach (i, ref e; a) e = i; randomShuffle(a, r); auto n = uniform(0, a.length, r); ptrdiff_t[] b = new ptrdiff_t[n]; topNCopy!(binaryFun!("a < b"))(a, b, SortOutput.yes); assert(isSorted!(binaryFun!("a < b"))(b)); } /** Given a range of elements, constructs an index of its top $(I n) elements (i.e., the first $(I n) elements if the range were sorted). Similar to $(LREF topN), except that the range is not modified. Params: less = A binary predicate that defines the ordering of range elements. Defaults to $(D a < b). ss = $(RED (Not implemented yet.)) Specify the swapping strategy. r = A $(XREF_PACK_NAMED range,primitives,isRandomAccessRange,random-access range) of elements to make an index for. index = A $(XREF_PACK_NAMED range,primitives,isRandomAccessRange,random-access range) with assignable elements to build the index in. The length of this range determines how many top elements to index in $(D r). This index range can either have integral elements, in which case the constructed index will consist of zero-based numerical indices into $(D r); or it can have pointers to the element type of $(D r), in which case the constructed index will be pointers to the top elements in $(D r). sorted = Determines whether to sort the index by the elements they refer to. See_also: $(LREF topN), $(LREF topNCopy). BUGS: The swapping strategy parameter is not implemented yet; currently it is ignored. */ void topNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex) (Range r, RangeIndex index, SortOutput sorted = SortOutput.no) if (isRandomAccessRange!Range && isRandomAccessRange!RangeIndex && hasAssignableElements!RangeIndex && isIntegral!(ElementType!(RangeIndex))) { static assert(ss == SwapStrategy.unstable, "Stable swap strategy not implemented yet."); import std.container : BinaryHeap; import std.exception : enforce; if (index.empty) return; enforce(ElementType!(RangeIndex).max >= index.length, "Index type too small"); bool indirectLess(ElementType!(RangeIndex) a, ElementType!(RangeIndex) b) { return binaryFun!(less)(r[a], r[b]); } auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0); foreach (i; 0 .. r.length) { heap.conditionalInsert(cast(ElementType!RangeIndex) i); } if (sorted == SortOutput.yes) { while (!heap.empty) heap.removeFront(); } } /// ditto void topNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex) (Range r, RangeIndex index, SortOutput sorted = SortOutput.no) if (isRandomAccessRange!Range && isRandomAccessRange!RangeIndex && hasAssignableElements!RangeIndex && is(ElementType!(RangeIndex) == ElementType!(Range)*)) { static assert(ss == SwapStrategy.unstable, "Stable swap strategy not implemented yet."); import std.container : BinaryHeap; if (index.empty) return; static bool indirectLess(const ElementType!(RangeIndex) a, const ElementType!(RangeIndex) b) { return binaryFun!less(*a, *b); } auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0); foreach (i; 0 .. r.length) { heap.conditionalInsert(&r[i]); } if (sorted == SortOutput.yes) { while (!heap.empty) heap.removeFront(); } } /// unittest { // Construct index to top 3 elements using numerical indices: int[] a = [ 10, 2, 7, 5, 8, 1 ]; int[] index = new int[3]; topNIndex(a, index, SortOutput.yes); assert(index == [5, 1, 3]); // because a[5]==1, a[1]==2, a[3]==5 // Construct index to top 3 elements using pointer indices: int*[] ptrIndex = new int*[3]; topNIndex(a, ptrIndex, SortOutput.yes); assert(ptrIndex == [ &a[5], &a[1], &a[3] ]); } unittest { import std.conv : text; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); { int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ]; int*[] b = new int*[5]; topNIndex!("a > b")(a, b, SortOutput.yes); //foreach (e; b) writeln(*e); assert(b == [ &a[0], &a[2], &a[1], &a[6], &a[5]]); } { int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ]; auto b = new ubyte[5]; topNIndex!("a > b")(a, b, SortOutput.yes); //foreach (e; b) writeln(e, ":", a[e]); assert(b == [ cast(ubyte) 0, cast(ubyte)2, cast(ubyte)1, cast(ubyte)6, cast(ubyte)5], text(b)); } } // nextPermutation /** * Permutes $(D range) in-place to the next lexicographically greater * permutation. * * The predicate $(D less) defines the lexicographical ordering to be used on * the range. * * If the range is currently the lexicographically greatest permutation, it is * permuted back to the least permutation and false is returned. Otherwise, * true is returned. One can thus generate all permutations of a range by * sorting it according to $(D less), which produces the lexicographically * least permutation, and then calling nextPermutation until it returns false. * This is guaranteed to generate all distinct permutations of the range * exactly once. If there are $(I N) elements in the range and all of them are * unique, then $(I N)! permutations will be generated. Otherwise, if there are * some duplicated elements, fewer permutations will be produced. ---- // Enumerate all permutations int[] a = [1,2,3,4,5]; do { // use the current permutation and // proceed to the next permutation of the array. } while (nextPermutation(a)); ---- * Params: * less = The ordering to be used to determine lexicographical ordering of the * permutations. * range = The range to permute. * * Returns: false if the range was lexicographically the greatest, in which * case the range is reversed back to the lexicographically smallest * permutation; otherwise returns true. * See_Also: * $(XREF_PACK algorithm,iteration,permutations). */ bool nextPermutation(alias less="a < b", BidirectionalRange) (BidirectionalRange range) if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange) { import std.algorithm : find, reverse, swap; // FIXME import std.range : retro, takeExactly; // Ranges of 0 or 1 element have no distinct permutations. if (range.empty) return false; auto i = retro(range); auto last = i.save; // Find last occurring increasing pair of elements size_t n = 1; for (i.popFront(); !i.empty; i.popFront(), last.popFront(), n++) { if (binaryFun!less(i.front, last.front)) break; } if (i.empty) { // Entire range is decreasing: it's lexicographically the greatest. So // wrap it around. range.reverse(); return false; } // Find last element greater than i.front. auto j = find!((a) => binaryFun!less(i.front, a))( takeExactly(retro(range), n)); assert(!j.empty); // shouldn't happen since i.front < last.front swap(i.front, j.front); reverse(takeExactly(retro(range), n)); return true; } /// @safe unittest { // Step through all permutations of a sorted array in lexicographic order int[] a = [1,2,3]; assert(nextPermutation(a) == true); assert(a == [1,3,2]); assert(nextPermutation(a) == true); assert(a == [2,1,3]); assert(nextPermutation(a) == true); assert(a == [2,3,1]); assert(nextPermutation(a) == true); assert(a == [3,1,2]); assert(nextPermutation(a) == true); assert(a == [3,2,1]); assert(nextPermutation(a) == false); assert(a == [1,2,3]); } /// @safe unittest { // Step through permutations of an array containing duplicate elements: int[] a = [1,1,2]; assert(nextPermutation(a) == true); assert(a == [1,2,1]); assert(nextPermutation(a) == true); assert(a == [2,1,1]); assert(nextPermutation(a) == false); assert(a == [1,1,2]); } @safe unittest { // Boundary cases: arrays of 0 or 1 element. int[] a1 = []; assert(!nextPermutation(a1)); assert(a1 == []); int[] a2 = [1]; assert(!nextPermutation(a2)); assert(a2 == [1]); } @safe unittest { import std.algorithm.comparison : equal; auto a1 = [1, 2, 3, 4]; assert(nextPermutation(a1)); assert(equal(a1, [1, 2, 4, 3])); assert(nextPermutation(a1)); assert(equal(a1, [1, 3, 2, 4])); assert(nextPermutation(a1)); assert(equal(a1, [1, 3, 4, 2])); assert(nextPermutation(a1)); assert(equal(a1, [1, 4, 2, 3])); assert(nextPermutation(a1)); assert(equal(a1, [1, 4, 3, 2])); assert(nextPermutation(a1)); assert(equal(a1, [2, 1, 3, 4])); assert(nextPermutation(a1)); assert(equal(a1, [2, 1, 4, 3])); assert(nextPermutation(a1)); assert(equal(a1, [2, 3, 1, 4])); assert(nextPermutation(a1)); assert(equal(a1, [2, 3, 4, 1])); assert(nextPermutation(a1)); assert(equal(a1, [2, 4, 1, 3])); assert(nextPermutation(a1)); assert(equal(a1, [2, 4, 3, 1])); assert(nextPermutation(a1)); assert(equal(a1, [3, 1, 2, 4])); assert(nextPermutation(a1)); assert(equal(a1, [3, 1, 4, 2])); assert(nextPermutation(a1)); assert(equal(a1, [3, 2, 1, 4])); assert(nextPermutation(a1)); assert(equal(a1, [3, 2, 4, 1])); assert(nextPermutation(a1)); assert(equal(a1, [3, 4, 1, 2])); assert(nextPermutation(a1)); assert(equal(a1, [3, 4, 2, 1])); assert(nextPermutation(a1)); assert(equal(a1, [4, 1, 2, 3])); assert(nextPermutation(a1)); assert(equal(a1, [4, 1, 3, 2])); assert(nextPermutation(a1)); assert(equal(a1, [4, 2, 1, 3])); assert(nextPermutation(a1)); assert(equal(a1, [4, 2, 3, 1])); assert(nextPermutation(a1)); assert(equal(a1, [4, 3, 1, 2])); assert(nextPermutation(a1)); assert(equal(a1, [4, 3, 2, 1])); assert(!nextPermutation(a1)); assert(equal(a1, [1, 2, 3, 4])); } @safe unittest { // Test with non-default sorting order int[] a = [3,2,1]; assert(nextPermutation!"a > b"(a) == true); assert(a == [3,1,2]); assert(nextPermutation!"a > b"(a) == true); assert(a == [2,3,1]); assert(nextPermutation!"a > b"(a) == true); assert(a == [2,1,3]); assert(nextPermutation!"a > b"(a) == true); assert(a == [1,3,2]); assert(nextPermutation!"a > b"(a) == true); assert(a == [1,2,3]); assert(nextPermutation!"a > b"(a) == false); assert(a == [3,2,1]); } // Issue 13594 @safe unittest { int[3] a = [1,2,3]; assert(nextPermutation(a[])); assert(a == [1,3,2]); } // nextEvenPermutation /** * Permutes $(D range) in-place to the next lexicographically greater $(I even) * permutation. * * The predicate $(D less) defines the lexicographical ordering to be used on * the range. * * An even permutation is one which is produced by swapping an even number of * pairs of elements in the original range. The set of $(I even) permutations * is distinct from the set of $(I all) permutations only when there are no * duplicate elements in the range. If the range has $(I N) unique elements, * then there are exactly $(I N)!/2 even permutations. * * If the range is already the lexicographically greatest even permutation, it * is permuted back to the least even permutation and false is returned. * Otherwise, true is returned, and the range is modified in-place to be the * lexicographically next even permutation. * * One can thus generate the even permutations of a range with unique elements * by starting with the lexicographically smallest permutation, and repeatedly * calling nextEvenPermutation until it returns false. ---- // Enumerate even permutations int[] a = [1,2,3,4,5]; do { // use the current permutation and // proceed to the next even permutation of the array. } while (nextEvenPermutation(a)); ---- * One can also generate the $(I odd) permutations of a range by noting that * permutations obey the rule that even + even = even, and odd + even = odd. * Thus, by swapping the last two elements of a lexicographically least range, * it is turned into the first odd permutation. Then calling * nextEvenPermutation on this first odd permutation will generate the next * even permutation relative to this odd permutation, which is actually the * next odd permutation of the original range. Thus, by repeatedly calling * nextEvenPermutation until it returns false, one enumerates the odd * permutations of the original range. ---- // Enumerate odd permutations int[] a = [1,2,3,4,5]; swap(a[$-2], a[$-1]); // a is now the first odd permutation of [1,2,3,4,5] do { // use the current permutation and // proceed to the next odd permutation of the original array // (which is an even permutation of the first odd permutation). } while (nextEvenPermutation(a)); ---- * * Warning: Since even permutations are only distinct from all permutations * when the range elements are unique, this function assumes that there are no * duplicate elements under the specified ordering. If this is not _true, some * permutations may fail to be generated. When the range has non-unique * elements, you should use $(MYREF nextPermutation) instead. * * Params: * less = The ordering to be used to determine lexicographical ordering of the * permutations. * range = The range to permute. * * Returns: false if the range was lexicographically the greatest, in which * case the range is reversed back to the lexicographically smallest * permutation; otherwise returns true. */ bool nextEvenPermutation(alias less="a < b", BidirectionalRange) (BidirectionalRange range) if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange) { import std.algorithm : find, reverse, swap; // FIXME import std.range : retro, takeExactly; // Ranges of 0 or 1 element have no distinct permutations. if (range.empty) return false; bool oddParity = false; bool ret = true; do { auto i = retro(range); auto last = i.save; // Find last occurring increasing pair of elements size_t n = 1; for (i.popFront(); !i.empty; i.popFront(), last.popFront(), n++) { if (binaryFun!less(i.front, last.front)) break; } if (!i.empty) { // Find last element greater than i.front. auto j = find!((a) => binaryFun!less(i.front, a))( takeExactly(retro(range), n)); // shouldn't happen since i.front < last.front assert(!j.empty); swap(i.front, j.front); oddParity = !oddParity; } else { // Entire range is decreasing: it's lexicographically // the greatest. ret = false; } reverse(takeExactly(retro(range), n)); if ((n / 2) % 2 == 1) oddParity = !oddParity; } while(oddParity); return ret; } /// @safe unittest { // Step through even permutations of a sorted array in lexicographic order int[] a = [1,2,3]; assert(nextEvenPermutation(a) == true); assert(a == [2,3,1]); assert(nextEvenPermutation(a) == true); assert(a == [3,1,2]); assert(nextEvenPermutation(a) == false); assert(a == [1,2,3]); } @safe unittest { auto a3 = [ 1, 2, 3, 4 ]; int count = 1; while (nextEvenPermutation(a3)) count++; assert(count == 12); } @safe unittest { // Test with non-default sorting order auto a = [ 3, 2, 1 ]; assert(nextEvenPermutation!"a > b"(a) == true); assert(a == [ 2, 1, 3 ]); assert(nextEvenPermutation!"a > b"(a) == true); assert(a == [ 1, 3, 2 ]); assert(nextEvenPermutation!"a > b"(a) == false); assert(a == [ 3, 2, 1 ]); } @safe unittest { // Test various cases of rollover auto a = [ 3, 1, 2 ]; assert(nextEvenPermutation(a) == false); assert(a == [ 1, 2, 3 ]); auto b = [ 3, 2, 1 ]; assert(nextEvenPermutation(b) == false); assert(b == [ 1, 3, 2 ]); } @safe unittest { // Issue 13594 int[3] a = [1,2,3]; assert(nextEvenPermutation(a[])); assert(a == [2,3,1]); } /** Even permutations are useful for generating coordinates of certain geometric shapes. Here's a non-trivial example: */ @safe unittest { import std.math : sqrt; // Print the 60 vertices of a uniform truncated icosahedron (soccer ball) enum real Phi = (1.0 + sqrt(5.0)) / 2.0; // Golden ratio real[][] seeds = [ [0.0, 1.0, 3.0*Phi], [1.0, 2.0+Phi, 2.0*Phi], [Phi, 2.0, Phi^^3] ]; size_t n; foreach (seed; seeds) { // Loop over even permutations of each seed do { // Loop over all sign changes of each permutation size_t i; do { // Generate all possible sign changes for (i=0; i < seed.length; i++) { if (seed[i] != 0.0) { seed[i] = -seed[i]; if (seed[i] < 0.0) break; } } n++; } while (i < seed.length); } while (nextEvenPermutation(seed)); } assert(n == 60); } ldc-1.1.0-beta3-src/runtime/phobos/std/algorithm/internal.d0000664000175000017500000000363712776215007021666 0ustar kaikai// Written in the D programming language. /// Helper functions for std.algorithm package. module std.algorithm.internal; // Same as std.string.format, but "self-importing". // Helps reduce code and imports, particularly in static asserts. // Also helps with missing imports errors. package template algoFormat() { import std.format : format; alias algoFormat = format; } // Internal random array generators version(unittest) { package enum size_t maxArraySize = 50; package enum size_t minArraySize = maxArraySize - 1; package string[] rndstuff(T : string)() { import std.random : Random, unpredictableSeed, uniform; static Random rnd; static bool first = true; if (first) { rnd = Random(unpredictableSeed); first = false; } string[] result = new string[uniform(minArraySize, maxArraySize, rnd)]; string alpha = "abcdefghijABCDEFGHIJ"; foreach (ref s; result) { foreach (i; 0 .. uniform(0u, 20u, rnd)) { auto j = uniform(0, alpha.length - 1, rnd); s ~= alpha[j]; } } return result; } package int[] rndstuff(T : int)() { import std.random : Random, unpredictableSeed, uniform; static Random rnd; static bool first = true; if (first) { rnd = Random(unpredictableSeed); first = false; } int[] result = new int[uniform(minArraySize, maxArraySize, rnd)]; foreach (ref i; result) { i = uniform(-100, 100, rnd); } return result; } package double[] rndstuff(T : double)() { double[] result; foreach (i; rndstuff!(int)()) { result ~= i / 50.0; } return result; } } package(std) T* addressOf(T)(ref T val) { return &val; } ldc-1.1.0-beta3-src/runtime/phobos/std/algorithm/mutation.d0000664000175000017500000020724212776215007021710 0ustar kaikai// Written in the D programming language. /** This is a submodule of $(LINK2 std_algorithm.html, std.algorithm). It contains generic _mutation algorithms. $(BOOKTABLE Cheat Sheet, $(TR $(TH Function Name) $(TH Description)) $(T2 bringToFront, If $(D a = [1, 2, 3]) and $(D b = [4, 5, 6, 7]), $(D bringToFront(a, b)) leaves $(D a = [4, 5, 6]) and $(D b = [7, 1, 2, 3]).) $(T2 copy, Copies a range to another. If $(D a = [1, 2, 3]) and $(D b = new int[5]), then $(D copy(a, b)) leaves $(D b = [1, 2, 3, 0, 0]) and returns $(D b[3 .. $]).) $(T2 fill, Fills a range with a pattern, e.g., if $(D a = new int[3]), then $(D fill(a, 4)) leaves $(D a = [4, 4, 4]) and $(D fill(a, [3, 4])) leaves $(D a = [3, 4, 3]).) $(T2 initializeAll, If $(D a = [1.2, 3.4]), then $(D initializeAll(a)) leaves $(D a = [double.init, double.init]).) $(T2 move, $(D move(a, b)) moves $(D a) into $(D b). $(D move(a)) reads $(D a) destructively.) $(T2 moveAll, Moves all elements from one range to another.) $(T2 moveSome, Moves as many elements as possible from one range to another.) $(T2 remove, Removes elements from a range in-place, and returns the shortened range.) $(T2 reverse, If $(D a = [1, 2, 3]), $(D reverse(a)) changes it to $(D [3, 2, 1]).) $(T2 strip, Strips all leading and trailing elements equal to a value, or that satisfy a predicate. If $(D a = [1, 1, 0, 1, 1]), then $(D strip(a, 1)) and $(D strip!(e => e == 1)(a)) returns $(D [0]).) $(T2 stripLeft, Strips all leading elements equal to a value, or that satisfy a predicate. If $(D a = [1, 1, 0, 1, 1]), then $(D stripLeft(a, 1)) and $(D stripLeft!(e => e == 1)(a)) returns $(D [0, 1, 1]).) $(T2 stripRight, Strips all trailing elements equal to a value, or that satisfy a predicate. If $(D a = [1, 1, 0, 1, 1]), then $(D stripRight(a, 1)) and $(D stripRight!(e => e == 1)(a)) returns $(D [1, 1, 0]).) $(T2 swap, Swaps two values.) $(T2 swapRanges, Swaps all elements of two ranges.) $(T2 uninitializedFill, Fills a range (assumed uninitialized) with a value.) ) Copyright: Andrei Alexandrescu 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/algorithm/_mutation.d) Macros: T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) */ module std.algorithm.mutation; import std.range.primitives; import std.traits : isArray, isBlitAssignable, isNarrowString, Unqual; // FIXME import std.typecons; // : tuple, Tuple; // FIXME: somehow deleting this breaks the bringToFront() unittests. import std.range; // bringToFront /** The $(D bringToFront) function has considerable flexibility and usefulness. It can rotate elements in one buffer left or right, swap buffers of equal length, and even move elements across disjoint buffers of different types and different lengths. $(D bringToFront) takes two ranges $(D front) and $(D back), which may be of different types. Considering the concatenation of $(D front) and $(D back) one unified range, $(D bringToFront) rotates that unified range such that all elements in $(D back) are brought to the beginning of the unified range. The relative ordering of elements in $(D front) and $(D back), respectively, remains unchanged. Performs $(BIGOH max(front.length, back.length)) evaluations of $(D swap). Preconditions: Either $(D front) and $(D back) are disjoint, or $(D back) is reachable from $(D front) and $(D front) is not reachable from $(D back). Params: front = an input range back = a forward range Returns: The number of elements brought to the front, i.e., the length of $(D back). See_Also: $(WEB sgi.com/tech/stl/_rotate.html, STL's rotate) */ size_t bringToFront(Range1, Range2)(Range1 front, Range2 back) if (isInputRange!Range1 && isForwardRange!Range2) { import std.range: Take, take; enum bool sameHeadExists = is(typeof(front.sameHead(back))); size_t result; for (bool semidone; !front.empty && !back.empty; ) { static if (sameHeadExists) { if (front.sameHead(back)) break; // shortcut } // Swap elements until front and/or back ends. auto back0 = back.save; size_t nswaps; do { static if (sameHeadExists) { // Detect the stepping-over condition. if (front.sameHead(back0)) back0 = back.save; } swapFront(front, back); ++nswaps; front.popFront(); back.popFront(); } while (!front.empty && !back.empty); if (!semidone) result += nswaps; // Now deal with the remaining elements. if (back.empty) { if (front.empty) break; // Right side was shorter, which means that we've brought // all the back elements to the front. semidone = true; // Next pass: bringToFront(front, back0) to adjust the rest. back = back0; } else { assert(front.empty); // Left side was shorter. Let's step into the back. static if (is(Range1 == Take!Range2)) { front = take(back0, nswaps); } else { immutable subresult = bringToFront(take(back0, nswaps), back); if (!semidone) result += subresult; break; // done } } } return result; } /** The simplest use of $(D bringToFront) is for rotating elements in a buffer. For example: */ @safe unittest { auto arr = [4, 5, 6, 7, 1, 2, 3]; auto p = bringToFront(arr[0 .. 4], arr[4 .. $]); assert(p == arr.length - 4); assert(arr == [ 1, 2, 3, 4, 5, 6, 7 ]); } /** The $(D front) range may actually "step over" the $(D back) range. This is very useful with forward ranges that cannot compute comfortably right-bounded subranges like $(D arr[0 .. 4]) above. In the example below, $(D r2) is a right subrange of $(D r1). */ @safe unittest { import std.algorithm.comparison : equal; import std.container : SList; auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3); auto r1 = list[]; auto r2 = list[]; popFrontN(r2, 4); assert(equal(r2, [ 1, 2, 3 ])); bringToFront(r1, r2); assert(equal(list[], [ 1, 2, 3, 4, 5, 6, 7 ])); } /** Elements can be swapped across ranges of different types: */ @safe unittest { import std.algorithm.comparison : equal; import std.container : SList; auto list = SList!(int)(4, 5, 6, 7); auto vec = [ 1, 2, 3 ]; bringToFront(list[], vec); assert(equal(list[], [ 1, 2, 3, 4 ])); assert(equal(vec, [ 5, 6, 7 ])); } @safe unittest { import std.algorithm.comparison : equal; import std.conv : text; import std.random : Random, unpredictableSeed, uniform; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); // a more elaborate test { auto rnd = Random(unpredictableSeed); int[] a = new int[uniform(100, 200, rnd)]; int[] b = new int[uniform(100, 200, rnd)]; foreach (ref e; a) e = uniform(-100, 100, rnd); foreach (ref e; b) e = uniform(-100, 100, rnd); int[] c = a ~ b; // writeln("a= ", a); // writeln("b= ", b); auto n = bringToFront(c[0 .. a.length], c[a.length .. $]); //writeln("c= ", c); assert(n == b.length); assert(c == b ~ a, text(c, "\n", a, "\n", b)); } // different types, moveFront, no sameHead { static struct R(T) { T[] data; size_t i; @property { R save() { return this; } bool empty() { return i >= data.length; } T front() { return data[i]; } T front(real e) { return data[i] = cast(T) e; } } void popFront() { ++i; } } auto a = R!int([1, 2, 3, 4, 5]); auto b = R!real([6, 7, 8, 9]); auto n = bringToFront(a, b); assert(n == 4); assert(a.data == [6, 7, 8, 9, 1]); assert(b.data == [2, 3, 4, 5]); } // front steps over back { int[] arr, r1, r2; // back is shorter arr = [4, 5, 6, 7, 1, 2, 3]; r1 = arr; r2 = arr[4 .. $]; bringToFront(r1, r2) == 3 || assert(0); assert(equal(arr, [1, 2, 3, 4, 5, 6, 7])); // front is shorter arr = [5, 6, 7, 1, 2, 3, 4]; r1 = arr; r2 = arr[3 .. $]; bringToFront(r1, r2) == 4 || assert(0); assert(equal(arr, [1, 2, 3, 4, 5, 6, 7])); } } // Tests if types are arrays and support slice assign. private enum bool areCopyCompatibleArrays(T1, T2) = isArray!T1 && isArray!T2 && is(typeof(T2.init[] = T1.init[])); // copy /** Copies the content of $(D source) into $(D target) and returns the remaining (unfilled) part of $(D target). Preconditions: $(D target) shall have enough room to accommodate the entirety of $(D source). Params: source = an input range target = an output range Returns: The unfilled part of target See_Also: $(WEB sgi.com/tech/stl/_copy.html, STL's _copy) */ TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target) if (areCopyCompatibleArrays!(SourceRange, TargetRange)) { const tlen = target.length; const slen = source.length; assert(tlen >= slen, "Cannot copy a source range into a smaller target range."); immutable overlaps = () @trusted { return source.ptr < target.ptr + tlen && target.ptr < source.ptr + slen; }(); if (overlaps) { foreach (idx; 0 .. slen) target[idx] = source[idx]; return target[slen .. tlen]; } else { // Array specialization. This uses optimized memory copying // routines under the hood and is about 10-20x faster than the // generic implementation. target[0 .. slen] = source[]; return target[slen .. $]; } } /// ditto TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target) if (!areCopyCompatibleArrays!(SourceRange, TargetRange) && isInputRange!SourceRange && isOutputRange!(TargetRange, ElementType!SourceRange)) { // Specialize for 2 random access ranges. // Typically 2 random access ranges are faster iterated by common // index than by x.popFront(), y.popFront() pair static if (isRandomAccessRange!SourceRange && hasLength!SourceRange && hasSlicing!TargetRange && isRandomAccessRange!TargetRange && hasLength!TargetRange) { auto len = source.length; foreach (idx; 0 .. len) target[idx] = source[idx]; return target[len .. $]; } else { put(target, source); return target; } } /// @safe unittest { int[] a = [ 1, 5 ]; int[] b = [ 9, 8 ]; int[] buf = new int[](a.length + b.length + 10); auto rem = a.copy(buf); // copy a into buf rem = b.copy(rem); // copy b into remainder of buf assert(buf[0 .. a.length + b.length] == [1, 5, 9, 8]); assert(rem.length == 10); // unused slots in buf } /** As long as the target range elements support assignment from source range elements, different types of ranges are accepted: */ @safe unittest { float[] src = [ 1.0f, 5 ]; double[] dest = new double[src.length]; src.copy(dest); } /** To _copy at most $(D n) elements from a range, you may want to use $(XREF range, take): */ @safe unittest { import std.range; int[] src = [ 1, 5, 8, 9, 10 ]; auto dest = new int[](3); src.take(dest.length).copy(dest); assert(dest == [ 1, 5, 8 ]); } /** To _copy just those elements from a range that satisfy a predicate, use $(LREF filter): */ @safe unittest { import std.algorithm.iteration : filter; int[] src = [ 1, 5, 8, 9, 10, 1, 2, 0 ]; auto dest = new int[src.length]; auto rem = src .filter!(a => (a & 1) == 1) .copy(dest); assert(dest[0 .. $ - rem.length] == [ 1, 5, 9, 1 ]); } /** $(XREF range, retro) can be used to achieve behavior similar to $(WEB sgi.com/tech/stl/copy_backward.html, STL's copy_backward'): */ @safe unittest { import std.algorithm, std.range; int[] src = [1, 2, 4]; int[] dest = [0, 0, 0, 0, 0]; src.retro.copy(dest.retro); assert(dest == [0, 0, 1, 2, 4]); } @safe unittest { import std.algorithm.iteration : filter; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); { int[] a = [ 1, 5 ]; int[] b = [ 9, 8 ]; auto e = copy(filter!("a > 1")(a), b); assert(b[0] == 5 && e.length == 1); } { int[] a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; copy(a[5..10], a[4..9]); assert(a[4..9] == [6, 7, 8, 9, 10]); } { // Test for bug 7898 enum v = { import std.algorithm; int[] arr1 = [10, 20, 30, 40, 50]; int[] arr2 = arr1.dup; copy(arr1, arr2); return 35; }(); } } @safe unittest { // Issue 13650 import std.meta : AliasSeq; foreach (Char; AliasSeq!(char, wchar, dchar)) { Char[3] a1 = "123"; Char[6] a2 = "456789"; assert(copy(a1[], a2[]) is a2[3..$]); assert(a1[] == "123"); assert(a2[] == "123789"); } } /** Assigns $(D value) to each element of input _range $(D range). Params: range = An $(XREF_PACK_NAMED _range,primitives,isInputRange,input _range) that exposes references to its elements and has assignable elements value = Assigned to each element of range See_Also: $(LREF uninitializedFill) $(LREF initializeAll) */ void fill(Range, Value)(Range range, Value value) if (isInputRange!Range && is(typeof(range.front = value))) { alias T = ElementType!Range; static if (is(typeof(range[] = value))) { range[] = value; } else static if (is(typeof(range[] = T(value)))) { range[] = T(value); } else { for ( ; !range.empty; range.popFront() ) { range.front = value; } } } /// @safe unittest { int[] a = [ 1, 2, 3, 4 ]; fill(a, 5); assert(a == [ 5, 5, 5, 5 ]); } @safe unittest { import std.conv : text; import std.internal.test.dummyrange; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 1, 2, 3 ]; fill(a, 6); assert(a == [ 6, 6, 6 ], text(a)); void fun0() { foreach (i; 0 .. 1000) { foreach (ref e; a) e = 6; } } void fun1() { foreach (i; 0 .. 1000) fill(a, 6); } //void fun2() { foreach (i; 0 .. 1000) fill2(a, 6); } //writeln(benchmark!(fun0, fun1, fun2)(10000)); // fill should accept InputRange alias InputRange = DummyRange!(ReturnBy.Reference, Length.No, RangeType.Input); enum filler = uint.max; InputRange range; fill(range, filler); foreach (value; range.arr) assert(value == filler); } @safe unittest { //ER8638_1 IS_NOT self assignable static struct ER8638_1 { void opAssign(int){} } //ER8638_1 IS self assignable static struct ER8638_2 { void opAssign(ER8638_2){} void opAssign(int){} } auto er8638_1 = new ER8638_1[](10); auto er8638_2 = new ER8638_2[](10); er8638_1.fill(5); //generic case er8638_2.fill(5); //opSlice(T.init) case } @safe unittest { { int[] a = [1, 2, 3]; immutable(int) b = 0; a.fill(b); assert(a == [0, 0, 0]); } { double[] a = [1, 2, 3]; immutable(int) b = 0; a.fill(b); assert(a == [0, 0, 0]); } } /** Fills $(D range) with a pattern copied from $(D filler). The length of $(D range) does not have to be a multiple of the length of $(D filler). If $(D filler) is empty, an exception is thrown. Params: range = An $(XREF_PACK_NAMED _range,primitives,isInputRange,input _range) that exposes references to its elements and has assignable elements. filler = The $(XREF_PACK_NAMED _range,primitives,isForwardRange,forward _range) representing the _fill pattern. */ void fill(Range1, Range2)(Range1 range, Range2 filler) if (isInputRange!Range1 && (isForwardRange!Range2 || (isInputRange!Range2 && isInfinite!Range2)) && is(typeof(Range1.init.front = Range2.init.front))) { static if (isInfinite!Range2) { //Range2 is infinite, no need for bounds checking or saving static if (hasSlicing!Range2 && hasLength!Range1 && is(typeof(filler[0 .. range.length]))) { copy(filler[0 .. range.length], range); } else { //manual feed for ( ; !range.empty; range.popFront(), filler.popFront()) { range.front = filler.front; } } } else { import std.exception : enforce; enforce(!filler.empty, "Cannot fill range with an empty filler"); static if (hasLength!Range1 && hasLength!Range2 && is(typeof(range.length > filler.length))) { //Case we have access to length auto len = filler.length; //Start by bulk copies while (range.length > len) { range = copy(filler.save, range); } //and finally fill the partial range. No need to save here. static if (hasSlicing!Range2 && is(typeof(filler[0 .. range.length]))) { //use a quick copy auto len2 = range.length; range = copy(filler[0 .. len2], range); } else { //iterate. No need to check filler, it's length is longer than range's for (; !range.empty; range.popFront(), filler.popFront()) { range.front = filler.front; } } } else { //Most basic case. auto bck = filler.save; for (; !range.empty; range.popFront(), filler.popFront()) { if (filler.empty) filler = bck.save; range.front = filler.front; } } } } /// @safe unittest { int[] a = [ 1, 2, 3, 4, 5 ]; int[] b = [ 8, 9 ]; fill(a, b); assert(a == [ 8, 9, 8, 9, 8 ]); } @safe unittest { import std.exception : assertThrown; import std.internal.test.dummyrange; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 1, 2, 3, 4, 5 ]; int[] b = [1, 2]; fill(a, b); assert(a == [ 1, 2, 1, 2, 1 ]); // fill should accept InputRange alias InputRange = DummyRange!(ReturnBy.Reference, Length.No, RangeType.Input); InputRange range; fill(range,[1,2]); foreach (i,value;range.arr) assert(value == (i%2==0?1:2)); //test with a input being a "reference forward" range fill(a, new ReferenceForwardRange!int([8, 9])); assert(a == [8, 9, 8, 9, 8]); //test with a input being an "infinite input" range fill(a, new ReferenceInfiniteInputRange!int()); assert(a == [0, 1, 2, 3, 4]); //empty filler test assertThrown(fill(a, a[$..$])); } /** Initializes all elements of $(D range) with their $(D .init) value. Assumes that the elements of the range are uninitialized. Params: range = An $(XREF_PACK_NAMED _range,primitives,isInputRange,input _range) that exposes references to its elements and has assignable elements See_Also: $(LREF fill) $(LREF uninitializeFill) */ void initializeAll(Range)(Range range) if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range) { import core.stdc.string : memset, memcpy; import std.traits : hasElaborateAssign, isDynamicArray; alias T = ElementType!Range; static if (hasElaborateAssign!T) { import std.algorithm.internal : addressOf; //Elaborate opAssign. Must go the memcpy road. //We avoid calling emplace here, because our goal is to initialize to //the static state of T.init, //So we want to avoid any un-necassarilly CC'ing of T.init auto p = typeid(T).initializer().ptr; if (p) for ( ; !range.empty ; range.popFront() ) memcpy(addressOf(range.front), p, T.sizeof); else static if (isDynamicArray!Range) memset(range.ptr, 0, range.length * T.sizeof); else for ( ; !range.empty ; range.popFront() ) memset(addressOf(range.front), 0, T.sizeof); } else fill(range, T.init); } /// ditto void initializeAll(Range)(Range range) if (is(Range == char[]) || is(Range == wchar[])) { alias T = ElementEncodingType!Range; range[] = T.init; } /// unittest { import core.stdc.stdlib: malloc, free; struct S { int a = 10; } auto s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5]; initializeAll(s); assert(s == [S(10), S(10), S(10), S(10), S(10)]); scope(exit) free(s.ptr); } unittest { import std.algorithm.iteration : filter; import std.meta : AliasSeq; import std.traits : hasElaborateAssign; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); //Test strings: //Must work on narrow strings. //Must reject const char[3] a = void; a[].initializeAll(); assert(a[] == [char.init, char.init, char.init]); string s; assert(!__traits(compiles, s.initializeAll())); //Note: Cannot call uninitializedFill on narrow strings enum e {e1, e2} e[3] b1 = void; b1[].initializeAll(); assert(b1[] == [e.e1, e.e1, e.e1]); e[3] b2 = void; b2[].uninitializedFill(e.e2); assert(b2[] == [e.e2, e.e2, e.e2]); static struct S1 { int i; } static struct S2 { int i = 1; } static struct S3 { int i; this(this){} } static struct S4 { int i = 1; this(this){} } static assert (!hasElaborateAssign!S1); static assert (!hasElaborateAssign!S2); static assert ( hasElaborateAssign!S3); static assert ( hasElaborateAssign!S4); assert (!typeid(S1).initializer().ptr); assert ( typeid(S2).initializer().ptr); assert (!typeid(S3).initializer().ptr); assert ( typeid(S4).initializer().ptr); foreach(S; AliasSeq!(S1, S2, S3, S4)) { //initializeAll { //Array S[3] ss1 = void; ss1[].initializeAll(); assert(ss1[] == [S.init, S.init, S.init]); //Not array S[3] ss2 = void; auto sf = ss2[].filter!"true"(); sf.initializeAll(); assert(ss2[] == [S.init, S.init, S.init]); } //uninitializedFill { //Array S[3] ss1 = void; ss1[].uninitializedFill(S(2)); assert(ss1[] == [S(2), S(2), S(2)]); //Not array S[3] ss2 = void; auto sf = ss2[].filter!"true"(); sf.uninitializedFill(S(2)); assert(ss2[] == [S(2), S(2), S(2)]); } } } // move /** Moves $(D source) into $(D target) via a destructive copy. Params: source = Data to copy. If a destructor or postblit is defined, it is reset to its $(D .init) value after it is moved into target. Note that data with internal pointers that point to itself cannot be moved, and will trigger an assertion failure. target = Where to copy into. The destructor, if any, is invoked before the copy is performed. */ void move(T)(ref T source, ref T target) { // test @safe destructible static if (__traits(compiles, (T t) @safe {})) trustedMoveImpl(source, target); else moveImpl(source, target); } /// unittest { Object obj1 = new Object; Object obj2 = obj1; Object obj3; move(obj2, obj3); assert(obj3 is obj1); } /// pure nothrow @safe @nogc unittest { // Structs without destructors are simply copied struct S1 { int a = 1; int b = 2; } S1 s11 = { 10, 11 }; S1 s12; move(s11, s12); assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11); // But structs with destructors or postblits are reset to their .init value // after copying to the target. struct S2 { int a = 1; int b = 2; ~this() pure nothrow @safe @nogc { } } S2 s21 = { 3, 4 }; S2 s22; move(s21, s22); assert(s21.a == 1 && s21.b == 2 && s22.a == 3 && s22.b == 4); } unittest { import std.traits; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); import std.exception : assertCTFEable; assertCTFEable!((){ Object obj1 = new Object; Object obj2 = obj1; Object obj3; move(obj2, obj3); assert(obj3 is obj1); static struct S1 { int a = 1, b = 2; } S1 s11 = { 10, 11 }; S1 s12; move(s11, s12); assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11); static struct S2 { int a = 1; int * b; } S2 s21 = { 10, null }; s21.b = new int; S2 s22; move(s21, s22); assert(s21 == s22); }); // Issue 5661 test(1) static struct S3 { static struct X { int n = 0; ~this(){n = 0;} } X x; } static assert(hasElaborateDestructor!S3); S3 s31, s32; s31.x.n = 1; move(s31, s32); assert(s31.x.n == 0); assert(s32.x.n == 1); // Issue 5661 test(2) static struct S4 { static struct X { int n = 0; this(this){n = 0;} } X x; } static assert(hasElaborateCopyConstructor!S4); S4 s41, s42; s41.x.n = 1; move(s41, s42); assert(s41.x.n == 0); assert(s42.x.n == 1); // Issue 13990 test class S5; S5 s51; S5 s52 = s51; S5 s53; move(s52, s53); assert(s53 is s51); } /// Ditto T move(T)(ref T source) { // test @safe destructible static if (__traits(compiles, (T t) @safe {})) return trustedMoveImpl(source); else return moveImpl(source); } /// pure nothrow @safe @nogc unittest { struct S { @disable this(this); ~this() pure nothrow @safe @nogc {} } S s1; S s2 = move(s1); } private void trustedMoveImpl(T)(ref T source, ref T target) @trusted { moveImpl(source, target); } private void moveImpl(T)(ref T source, ref T target) { import std.traits : hasElaborateDestructor; static if (is(T == struct)) { if (&source == &target) return; // Destroy target before overwriting it static if (hasElaborateDestructor!T) target.__xdtor(); } // move and emplace source into target moveEmplace(source, target); } private T trustedMoveImpl(T)(ref T source) @trusted { return moveImpl(source); } private T moveImpl(T)(ref T source) { T result = void; moveEmplace(source, result); return result; } unittest { import std.traits; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); import std.exception : assertCTFEable; assertCTFEable!((){ Object obj1 = new Object; Object obj2 = obj1; Object obj3 = move(obj2); assert(obj3 is obj1); static struct S1 { int a = 1, b = 2; } S1 s11 = { 10, 11 }; S1 s12 = move(s11); assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11); static struct S2 { int a = 1; int * b; } S2 s21 = { 10, null }; s21.b = new int; S2 s22 = move(s21); assert(s21 == s22); }); // Issue 5661 test(1) static struct S3 { static struct X { int n = 0; ~this(){n = 0;} } X x; } static assert(hasElaborateDestructor!S3); S3 s31; s31.x.n = 1; S3 s32 = move(s31); assert(s31.x.n == 0); assert(s32.x.n == 1); // Issue 5661 test(2) static struct S4 { static struct X { int n = 0; this(this){n = 0;} } X x; } static assert(hasElaborateCopyConstructor!S4); S4 s41; s41.x.n = 1; S4 s42 = move(s41); assert(s41.x.n == 0); assert(s42.x.n == 1); // Issue 13990 test class S5; S5 s51; S5 s52 = s51; S5 s53; s53 = move(s52); assert(s53 is s51); } unittest { static struct S { int n = 0; ~this() @system { n = 0; } } S a, b; static assert(!__traits(compiles, () @safe { move(a, b); })); static assert(!__traits(compiles, () @safe { move(a); })); a.n = 1; () @trusted { move(a, b); }(); assert(a.n == 0); a.n = 1; () @trusted { move(a); }(); assert(a.n == 0); } unittest//Issue 6217 { import std.algorithm.iteration : map; auto x = map!"a"([1,2,3]); x = move(x); } unittest// Issue 8055 { static struct S { int x; ~this() { assert(x == 0); } } S foo(S s) { return move(s); } S a; a.x = 0; auto b = foo(a); assert(b.x == 0); } unittest// Issue 8057 { int n = 10; struct S { int x; ~this() { // Access to enclosing scope assert(n == 10); } } S foo(S s) { // Move nested struct return move(s); } S a; a.x = 1; auto b = foo(a); assert(b.x == 1); // Regression 8171 static struct Array(T) { // nested struct has no member struct Payload { ~this() {} } } Array!int.Payload x = void; move(x); move(x, x); } /** * Similar to $(LREF move) but assumes `target` is uninitialized. This * is more efficient because `source` can be blitted over `target` * without destroying or initializing it first. * * Params: * source = value to be moved into target * target = uninitialized value to be filled by source */ void moveEmplace(T)(ref T source, ref T target) @system { import core.stdc.string : memcpy, memset; import std.traits : hasAliasing, hasElaborateAssign, hasElaborateCopyConstructor, hasElaborateDestructor, isAssignable; static if (!is(T == class) && hasAliasing!T) if (!__ctfe) { import std.exception : doesPointTo; assert(!doesPointTo(source, source), "Cannot move object with internal pointer."); } static if (is(T == struct)) { assert(&source !is &target, "source and target must not be identical"); static if (hasElaborateAssign!T || !isAssignable!T) memcpy(&target, &source, T.sizeof); else target = source; // If the source defines a destructor or a postblit hook, we must obliterate the // object in order to avoid double freeing and undue aliasing static if (hasElaborateDestructor!T || hasElaborateCopyConstructor!T) { // If T is nested struct, keep original context pointer static if (__traits(isNested, T)) enum sz = T.sizeof - (void*).sizeof; else enum sz = T.sizeof; auto init = typeid(T).initializer(); if (init.ptr is null) // null ptr means initialize to 0s memset(&source, 0, sz); else memcpy(&source, init.ptr, sz); } } else { // Primitive data (including pointers and arrays) or class - // assignment works great target = source; } } /// pure nothrow @nogc unittest { static struct Foo { pure nothrow @nogc: this(int* ptr) { _ptr = ptr; } ~this() { if (_ptr) ++*_ptr; } int* _ptr; } int val; Foo foo1 = void; // uninitialized auto foo2 = Foo(&val); // initialized // Using `move(foo2, foo1)` has an undefined effect because it destroys the uninitialized foo1. // MoveEmplace directly overwrites foo1 without destroying or initializing it first. assert(foo2._ptr is &val); moveEmplace(foo2, foo1); assert(foo1._ptr is &val && foo2._ptr is null); } // moveAll /** For each element $(D a) in $(D src) and each element $(D b) in $(D tgt) in lockstep in increasing order, calls $(D move(a, b)). Preconditions: $(D walkLength(src) <= walkLength(tgt)). This precondition will be asserted. If you cannot ensure there is enough room in `tgt` to accommodate all of `src` use $(LREF moveSome) instead. Params: src = An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) with movable elements. tgt = An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) with elements that elements from $(D src) can be moved into. Returns: The leftover portion of $(D tgt) after all elements from $(D src) have been moved. */ Range2 moveAll(Range1, Range2)(Range1 src, Range2 tgt) if (isInputRange!Range1 && isInputRange!Range2 && is(typeof(move(src.front, tgt.front)))) { return moveAllImpl!move(src, tgt); } /// pure nothrow @safe @nogc unittest { int[3] a = [ 1, 2, 3 ]; int[5] b; assert(moveAll(a[], b[]) is b[3 .. $]); assert(a[] == b[0 .. 3]); int[3] cmp = [ 1, 2, 3 ]; assert(a[] == cmp[]); } /** * Similar to $(LREF moveAll) but assumes all elements in `target` are * uninitialized. Uses $(LREF moveEmplace) to move elements from * `source` over elements from `target`. */ Range2 moveEmplaceAll(Range1, Range2)(Range1 src, Range2 tgt) @system if (isInputRange!Range1 && isInputRange!Range2 && is(typeof(moveEmplace(src.front, tgt.front)))) { return moveAllImpl!moveEmplace(src, tgt); } /// pure nothrow @nogc unittest { static struct Foo { ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } int* _ptr; } int[3] refs = [0, 1, 2]; Foo[3] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2])]; Foo[5] dst = void; auto tail = moveEmplaceAll(src[], dst[]); // move 3 value from src over dst assert(tail.length == 2); // returns remaining uninitialized values initializeAll(tail); import std.algorithm.searching : all; assert(src[].all!(e => e._ptr is null)); assert(dst[0 .. 3].all!(e => e._ptr !is null)); } unittest { struct InputRange { ref int front() { return data[0]; } void popFront() { data.popFront; } bool empty() { return data.empty; } int[] data; } auto a = InputRange([ 1, 2, 3 ]); auto b = InputRange(new int[5]); moveAll(a, b); assert(a.data == b.data[0 .. 3]); assert(a.data == [ 1, 2, 3 ]); } private Range2 moveAllImpl(alias moveOp, Range1, Range2)( ref Range1 src, ref Range2 tgt) { import std.exception : enforce; static if (isRandomAccessRange!Range1 && hasLength!Range1 && hasLength!Range2 && hasSlicing!Range2 && isRandomAccessRange!Range2) { auto toMove = src.length; assert(toMove <= tgt.length); foreach (idx; 0 .. toMove) moveOp(src[idx], tgt[idx]); return tgt[toMove .. tgt.length]; } else { for (; !src.empty; src.popFront(), tgt.popFront()) { assert(!tgt.empty); moveOp(src.front, tgt.front); } return tgt; } } // moveSome /** For each element $(D a) in $(D src) and each element $(D b) in $(D tgt) in lockstep in increasing order, calls $(D move(a, b)). Stops when either $(D src) or $(D tgt) have been exhausted. Params: src = An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) with movable elements. tgt = An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) with elements that elements from $(D src) can be moved into. Returns: The leftover portions of the two ranges after one or the other of the ranges have been exhausted. */ Tuple!(Range1, Range2) moveSome(Range1, Range2)(Range1 src, Range2 tgt) if (isInputRange!Range1 && isInputRange!Range2 && is(typeof(move(src.front, tgt.front)))) { return moveSomeImpl!move(src, tgt); } /// pure nothrow @safe @nogc unittest { int[5] a = [ 1, 2, 3, 4, 5 ]; int[3] b; assert(moveSome(a[], b[])[0] is a[3 .. $]); assert(a[0 .. 3] == b); assert(a == [ 1, 2, 3, 4, 5 ]); } /** * Same as $(LREF moveSome) but assumes all elements in `target` are * uninitialized. Uses $(LREF moveEmplace) to move elements from * `source` over elements from `target`. */ Tuple!(Range1, Range2) moveEmplaceSome(Range1, Range2)(Range1 src, Range2 tgt) @system if (isInputRange!Range1 && isInputRange!Range2 && is(typeof(move(src.front, tgt.front)))) { return moveSomeImpl!moveEmplace(src, tgt); } /// pure nothrow @nogc unittest { static struct Foo { ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } int* _ptr; } int[4] refs = [0, 1, 2, 3]; Foo[4] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2]), Foo(&refs[3])]; Foo[3] dst = void; auto res = moveEmplaceSome(src[], dst[]); import std.algorithm.searching : all; assert(src[0 .. 3].all!(e => e._ptr is null)); assert(src[3]._ptr !is null); assert(dst[].all!(e => e._ptr !is null)); } private Tuple!(Range1, Range2) moveSomeImpl(alias moveOp, Range1, Range2)( ref Range1 src, ref Range2 tgt) { for (; !src.empty && !tgt.empty; src.popFront(), tgt.popFront()) moveOp(src.front, tgt.front); return tuple(src, tgt); } // SwapStrategy /** Defines the swapping strategy for algorithms that need to swap elements in a range (such as partition and sort). The strategy concerns the swapping of elements that are not the core concern of the algorithm. For example, consider an algorithm that sorts $(D [ "abc", "b", "aBc" ]) according to $(D toUpper(a) < toUpper(b)). That algorithm might choose to swap the two equivalent strings $(D "abc") and $(D "aBc"). That does not affect the sorting since both $(D [ "abc", "aBc", "b" ]) and $(D [ "aBc", "abc", "b" ]) are valid outcomes. Some situations require that the algorithm must NOT ever change the relative ordering of equivalent elements (in the example above, only $(D [ "abc", "aBc", "b" ]) would be the correct result). Such algorithms are called $(B stable). If the ordering algorithm may swap equivalent elements discretionarily, the ordering is called $(B unstable). Yet another class of algorithms may choose an intermediate tradeoff by being stable only on a well-defined subrange of the range. There is no established terminology for such behavior; this library calls it $(B semistable). Generally, the $(D stable) ordering strategy may be more costly in time and/or space than the other two because it imposes additional constraints. Similarly, $(D semistable) may be costlier than $(D unstable). As (semi-)stability is not needed very often, the ordering algorithms in this module parameterized by $(D SwapStrategy) all choose $(D SwapStrategy.unstable) as the default. */ enum SwapStrategy { /** Allows freely swapping of elements as long as the output satisfies the algorithm's requirements. */ unstable, /** In algorithms partitioning ranges in two, preserve relative ordering of elements only to the left of the partition point. */ semistable, /** Preserve the relative ordering of elements to the largest extent allowed by the algorithm's requirements. */ stable, } /** Eliminates elements at given offsets from $(D range) and returns the shortened range. In the simplest call, one element is removed. ---- int[] a = [ 3, 5, 7, 8 ]; assert(remove(a, 1) == [ 3, 7, 8 ]); assert(a == [ 3, 7, 8, 8 ]); ---- In the case above the element at offset $(D 1) is removed and $(D remove) returns the range smaller by one element. The original array has remained of the same length because all functions in $(D std.algorithm) only change $(I content), not $(I topology). The value $(D 8) is repeated because $(LREF move) was invoked to move elements around and on integers $(D move) simply copies the source to the destination. To replace $(D a) with the effect of the removal, simply assign $(D a = remove(a, 1)). The slice will be rebound to the shorter array and the operation completes with maximal efficiency. Multiple indices can be passed into $(D remove). In that case, elements at the respective indices are all removed. The indices must be passed in increasing order, otherwise an exception occurs. ---- int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove(a, 1, 3, 5) == [ 0, 2, 4, 6, 7, 8, 9, 10 ]); ---- (Note how all indices refer to slots in the $(I original) array, not in the array as it is being progressively shortened.) Finally, any combination of integral offsets and tuples composed of two integral offsets can be passed in. ---- int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove(a, 1, tuple(3, 5), 9) == [ 0, 2, 5, 6, 7, 8, 10 ]); ---- In this case, the slots at positions 1, 3, 4, and 9 are removed from the array. The tuple passes in a range closed to the left and open to the right (consistent with built-in slices), e.g. $(D tuple(3, 5)) means indices $(D 3) and $(D 4) but not $(D 5). If the need is to remove some elements in the range but the order of the remaining elements does not have to be preserved, you may want to pass $(D SwapStrategy.unstable) to $(D remove). ---- int[] a = [ 0, 1, 2, 3 ]; assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]); ---- In the case above, the element at slot $(D 1) is removed, but replaced with the last element of the range. Taking advantage of the relaxation of the stability requirement, $(D remove) moved elements from the end of the array over the slots to be removed. This way there is less data movement to be done which improves the execution time of the function. The function $(D remove) works on any forward range. The moving strategy is (listed from fastest to slowest): $(UL $(LI If $(D s == SwapStrategy.unstable && isRandomAccessRange!Range && hasLength!Range && hasLvalueElements!Range), then elements are moved from the end of the range into the slots to be filled. In this case, the absolute minimum of moves is performed.) $(LI Otherwise, if $(D s == SwapStrategy.unstable && isBidirectionalRange!Range && hasLength!Range && hasLvalueElements!Range), then elements are still moved from the end of the range, but time is spent on advancing between slots by repeated calls to $(D range.popFront).) $(LI Otherwise, elements are moved incrementally towards the front of $(D range); a given element is never moved several times, but more elements are moved than in the previous cases.)) Params: s = a SwapStrategy to determine if the original order needs to be preserved range = a bidirectional range with a length member offset = which element(s) to remove Returns: a range containing all of the elements of range with offset removed */ Range remove (SwapStrategy s = SwapStrategy.stable, Range, Offset...) (Range range, Offset offset) if (s != SwapStrategy.stable && isBidirectionalRange!Range && hasLvalueElements!Range && hasLength!Range && Offset.length >= 1) { import std.algorithm.comparison : min; Tuple!(size_t, "pos", size_t, "len")[offset.length] blackouts; foreach (i, v; offset) { static if (is(typeof(v[0]) : size_t) && is(typeof(v[1]) : size_t)) { blackouts[i].pos = v[0]; blackouts[i].len = v[1] - v[0]; } else { static assert(is(typeof(v) : size_t), typeof(v).stringof); blackouts[i].pos = v; blackouts[i].len = 1; } static if (i > 0) { import std.exception : enforce; enforce(blackouts[i - 1].pos + blackouts[i - 1].len <= blackouts[i].pos, "remove(): incorrect ordering of elements to remove"); } } size_t left = 0, right = offset.length - 1; auto tgt = range.save; size_t steps = 0; while (left <= right) { // Look for a blackout on the right if (blackouts[right].pos + blackouts[right].len >= range.length) { range.popBackExactly(blackouts[right].len); // Since right is unsigned, we must check for this case, otherwise // we might turn it into size_t.max and the loop condition will not // fail when it should. if (right > 0) { --right; continue; } else break; } // Advance to next blackout on the left assert(blackouts[left].pos >= steps); tgt.popFrontExactly(blackouts[left].pos - steps); steps = blackouts[left].pos; auto toMove = min( blackouts[left].len, range.length - (blackouts[right].pos + blackouts[right].len)); foreach (i; 0 .. toMove) { move(range.back, tgt.front); range.popBack(); tgt.popFront(); } steps += toMove; if (toMove == blackouts[left].len) { // Filled the entire left hole ++left; continue; } } return range; } // Ditto Range remove (SwapStrategy s = SwapStrategy.stable, Range, Offset...) (Range range, Offset offset) if (s == SwapStrategy.stable && isBidirectionalRange!Range && hasLvalueElements!Range && Offset.length >= 1) { auto result = range; auto src = range, tgt = range; size_t pos; foreach (pass, i; offset) { static if (is(typeof(i[0])) && is(typeof(i[1]))) { auto from = i[0], delta = i[1] - i[0]; } else { auto from = i; enum delta = 1; } static if (pass > 0) { import std.exception : enforce; enforce(pos <= from, "remove(): incorrect ordering of elements to remove"); for (; pos < from; ++pos, src.popFront(), tgt.popFront()) { move(src.front, tgt.front); } } else { src.popFrontExactly(from); tgt.popFrontExactly(from); pos = from; } // now skip source to the "to" position src.popFrontExactly(delta); result.popBackExactly(delta); pos += delta; } // leftover move moveAll(src, tgt); return result; } @safe unittest { import std.exception : assertThrown; import std.range; // http://d.puremagic.com/issues/show_bug.cgi?id=10173 int[] test = iota(0, 10).array(); assertThrown(remove!(SwapStrategy.stable)(test, tuple(2, 4), tuple(1, 3))); assertThrown(remove!(SwapStrategy.unstable)(test, tuple(2, 4), tuple(1, 3))); assertThrown(remove!(SwapStrategy.stable)(test, 2, 4, 1, 3)); assertThrown(remove!(SwapStrategy.unstable)(test, 2, 4, 1, 3)); } @safe unittest { import std.range; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; //writeln(remove!(SwapStrategy.stable)(a, 1)); a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove!(SwapStrategy.stable)(a, 1) == [ 0, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]); a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove!(SwapStrategy.unstable)(a, 0, 10) == [ 9, 1, 2, 3, 4, 5, 6, 7, 8 ]); a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove!(SwapStrategy.unstable)(a, 0, tuple(9, 11)) == [ 8, 1, 2, 3, 4, 5, 6, 7 ]); // http://d.puremagic.com/issues/show_bug.cgi?id=5224 a = [ 1, 2, 3, 4 ]; assert(remove!(SwapStrategy.unstable)(a, 2) == [ 1, 2, 4 ]); a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; //writeln(remove!(SwapStrategy.stable)(a, 1, 5)); a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove!(SwapStrategy.stable)(a, 1, 5) == [ 0, 2, 3, 4, 6, 7, 8, 9, 10 ]); a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; //writeln(remove!(SwapStrategy.stable)(a, 1, 3, 5)); a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove!(SwapStrategy.stable)(a, 1, 3, 5) == [ 0, 2, 4, 6, 7, 8, 9, 10]); a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; //writeln(remove!(SwapStrategy.stable)(a, 1, tuple(3, 5))); a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 5)) == [ 0, 2, 5, 6, 7, 8, 9, 10]); a = iota(0, 10).array(); assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4), tuple(6, 7)) == [0, 9, 8, 7, 4, 5]); } @safe unittest { // Issue 11576 auto arr = [1,2,3]; arr = arr.remove!(SwapStrategy.unstable)(2); assert(arr == [1,2]); } @safe unittest { import std.range; // Bug# 12889 int[1][] arr = [[0], [1], [2], [3], [4], [5], [6]]; auto orig = arr.dup; foreach (i; iota(arr.length)) { assert(orig == arr.remove!(SwapStrategy.unstable)(tuple(i,i))); assert(orig == arr.remove!(SwapStrategy.stable)(tuple(i,i))); } } /** Reduces the length of the bidirectional range $(D range) by removing elements that satisfy $(D pred). If $(D s = SwapStrategy.unstable), elements are moved from the right end of the range over the elements to eliminate. If $(D s = SwapStrategy.stable) (the default), elements are moved progressively to front such that their relative order is preserved. Returns the filtered range. Params: range = a bidirectional ranges with lvalue elements Returns: the range with all of the elements where $(D pred) is $(D true) removed */ Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range) (Range range) if (isBidirectionalRange!Range && hasLvalueElements!Range) { import std.functional : unaryFun; auto result = range; static if (s != SwapStrategy.stable) { for (;!range.empty;) { if (!unaryFun!pred(range.front)) { range.popFront(); continue; } move(range.back, range.front); range.popBack(); result.popBack(); } } else { auto tgt = range; for (; !range.empty; range.popFront()) { if (unaryFun!(pred)(range.front)) { // yank this guy result.popBack(); continue; } // keep this guy move(range.front, tgt.front); tgt.popFront(); } } return result; } /// @safe unittest { static immutable base = [1, 2, 3, 2, 4, 2, 5, 2]; int[] arr = base[].dup; // using a string-based predicate assert(remove!("a == 2")(arr) == [ 1, 3, 4, 5 ]); // The original array contents have been modified, // so we need to reset it to its original state. // The length is unmodified however. arr[] = base[]; // using a lambda predicate assert(remove!(a => a == 2)(arr) == [ 1, 3, 4, 5 ]); } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ]; assert(remove!("a == 2", SwapStrategy.unstable)(a) == [ 1, 6, 3, 5, 3, 4, 5 ]); a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ]; //writeln(remove!("a != 2", SwapStrategy.stable)(a)); assert(remove!("a == 2", SwapStrategy.stable)(a) == [ 1, 3, 3, 4, 5, 5, 6 ]); } // reverse /** Reverses $(D r) in-place. Performs $(D r.length / 2) evaluations of $(D swap). Params: r = a bidirectional range with swappable elements or a random access range with a length member See_Also: $(WEB sgi.com/tech/stl/_reverse.html, STL's _reverse) */ void reverse(Range)(Range r) if (isBidirectionalRange!Range && !isRandomAccessRange!Range && hasSwappableElements!Range) { while (!r.empty) { swap(r.front, r.back); r.popFront(); if (r.empty) break; r.popBack(); } } /// @safe unittest { int[] arr = [ 1, 2, 3 ]; reverse(arr); assert(arr == [ 3, 2, 1 ]); } ///ditto void reverse(Range)(Range r) if (isRandomAccessRange!Range && hasLength!Range) { //swapAt is in fact the only way to swap non lvalue ranges immutable last = r.length-1; immutable steps = r.length/2; for (size_t i = 0; i < steps; i++) { swapAt(r, i, last-i); } } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] range = null; reverse(range); range = [ 1 ]; reverse(range); assert(range == [1]); range = [1, 2]; reverse(range); assert(range == [2, 1]); range = [1, 2, 3]; reverse(range); assert(range == [3, 2, 1]); } /** Reverses $(D r) in-place, where $(D r) is a narrow string (having elements of type $(D char) or $(D wchar)). UTF sequences consisting of multiple code units are preserved properly. Params: s = a narrow string Bugs: When passing a sting with unicode modifiers on characters, such as $(D \u0301), this function will not properly keep the position of the modifier. For example, reversing $(D ba\u0301d) ("bád") will result in d\u0301ab ("d́ab") instead of $(D da\u0301b) ("dáb"). */ void reverse(Char)(Char[] s) if (isNarrowString!(Char[]) && !is(Char == const) && !is(Char == immutable)) { import std.string : representation; import std.utf : stride; auto r = representation(s); for (size_t i = 0; i < s.length; ) { immutable step = stride(s, i); if (step > 1) { .reverse(r[i .. i + step]); i += step; } else { ++i; } } reverse(r); } /// @safe unittest { char[] arr = "hello\U00010143\u0100\U00010143".dup; reverse(arr); assert(arr == "\U00010143\u0100\U00010143olleh"); } @safe unittest { void test(string a, string b) { auto c = a.dup; reverse(c); assert(c == b, c ~ " != " ~ b); } test("a", "a"); test(" ", " "); test("\u2029", "\u2029"); test("\u0100", "\u0100"); test("\u0430", "\u0430"); test("\U00010143", "\U00010143"); test("abcdefcdef", "fedcfedcba"); test("hello\U00010143\u0100\U00010143", "\U00010143\u0100\U00010143olleh"); } //private void swapAt(R)(R r, size_t i1, size_t i2) { static if (is(typeof(&r[i1]))) { swap(r[i1], r[i2]); } else { if (i1 == i2) return; auto t1 = moveAt(r, i1); auto t2 = moveAt(r, i2); r[i2] = t1; r[i1] = t2; } } /** The strip group of functions allow stripping of either leading, trailing, or both leading and trailing elements. The $(D stripLeft) function will strip the $(D front) of the range, the $(D stripRight) function will strip the $(D back) of the range, while the $(D strip) function will strip both the $(D front) and $(D back) of the range. Note that the $(D strip) and $(D stripRight) functions require the range to be a $(LREF BidirectionalRange) range. All of these functions come in two varieties: one takes a target element, where the range will be stripped as long as this element can be found. The other takes a lambda predicate, where the range will be stripped as long as the predicate returns true. Params: range = a bidirectional or input range element = the elements to remove Returns: a Range with all of range except element at the start and end */ Range strip(Range, E)(Range range, E element) if (isBidirectionalRange!Range && is(typeof(range.front == element) : bool)) { return range.stripLeft(element).stripRight(element); } /// ditto Range strip(alias pred, Range)(Range range) if (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool)) { return range.stripLeft!pred().stripRight!pred(); } /// ditto Range stripLeft(Range, E)(Range range, E element) if (isInputRange!Range && is(typeof(range.front == element) : bool)) { import std.algorithm.searching : find; return find!((auto ref a) => a != element)(range); } /// ditto Range stripLeft(alias pred, Range)(Range range) if (isInputRange!Range && is(typeof(pred(range.front)) : bool)) { import std.algorithm.searching : find; import std.functional : not; return find!(not!pred)(range); } /// ditto Range stripRight(Range, E)(Range range, E element) if (isBidirectionalRange!Range && is(typeof(range.back == element) : bool)) { for (; !range.empty; range.popBack()) { if (range.back != element) break; } return range; } /// ditto Range stripRight(alias pred, Range)(Range range) if (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool)) { for (; !range.empty; range.popBack()) { if (!pred(range.back)) break; } return range; } /// Strip leading and trailing elements equal to the target element. @safe pure unittest { assert(" foobar ".strip(' ') == "foobar"); assert("00223.444500".strip('0') == "223.4445"); assert("ëëêéüŗōpéêëë".strip('ë') == "êéüŗōpéê"); assert([1, 1, 0, 1, 1].strip(1) == [0]); assert([0.0, 0.01, 0.01, 0.0].strip(0).length == 2); } /// Strip leading and trailing elements while the predicate returns true. @safe pure unittest { assert(" foobar ".strip!(a => a == ' ')() == "foobar"); assert("00223.444500".strip!(a => a == '0')() == "223.4445"); assert("ëëêéüŗōpéêëë".strip!(a => a == 'ë')() == "êéüŗōpéê"); assert([1, 1, 0, 1, 1].strip!(a => a == 1)() == [0]); assert([0.0, 0.01, 0.5, 0.6, 0.01, 0.0].strip!(a => a < 0.4)().length == 2); } /// Strip leading elements equal to the target element. @safe pure unittest { assert(" foobar ".stripLeft(' ') == "foobar "); assert("00223.444500".stripLeft('0') == "223.444500"); assert("ůůűniçodêéé".stripLeft('ů') == "űniçodêéé"); assert([1, 1, 0, 1, 1].stripLeft(1) == [0, 1, 1]); assert([0.0, 0.01, 0.01, 0.0].stripLeft(0).length == 3); } /// Strip leading elements while the predicate returns true. @safe pure unittest { assert(" foobar ".stripLeft!(a => a == ' ')() == "foobar "); assert("00223.444500".stripLeft!(a => a == '0')() == "223.444500"); assert("ůůűniçodêéé".stripLeft!(a => a == 'ů')() == "űniçodêéé"); assert([1, 1, 0, 1, 1].stripLeft!(a => a == 1)() == [0, 1, 1]); assert([0.0, 0.01, 0.10, 0.5, 0.6].stripLeft!(a => a < 0.4)().length == 2); } /// Strip trailing elements equal to the target element. @safe pure unittest { assert(" foobar ".stripRight(' ') == " foobar"); assert("00223.444500".stripRight('0') == "00223.4445"); assert("ùniçodêéé".stripRight('é') == "ùniçodê"); assert([1, 1, 0, 1, 1].stripRight(1) == [1, 1, 0]); assert([0.0, 0.01, 0.01, 0.0].stripRight(0).length == 3); } /// Strip trailing elements while the predicate returns true. @safe pure unittest { assert(" foobar ".stripRight!(a => a == ' ')() == " foobar"); assert("00223.444500".stripRight!(a => a == '0')() == "00223.4445"); assert("ùniçodêéé".stripRight!(a => a == 'é')() == "ùniçodê"); assert([1, 1, 0, 1, 1].stripRight!(a => a == 1)() == [1, 1, 0]); assert([0.0, 0.01, 0.10, 0.5, 0.6].stripRight!(a => a > 0.4)().length == 3); } // swap /** Swaps $(D lhs) and $(D rhs). The instances $(D lhs) and $(D rhs) are moved in memory, without ever calling $(D opAssign), nor any other function. $(D T) need not be assignable at all to be swapped. If $(D lhs) and $(D rhs) reference the same instance, then nothing is done. $(D lhs) and $(D rhs) must be mutable. If $(D T) is a struct or union, then its fields must also all be (recursively) mutable. Params: lhs = Data to be swapped with $(D rhs). rhs = Data to be swapped with $(D lhs). */ void swap(T)(ref T lhs, ref T rhs) @trusted pure nothrow @nogc if (isBlitAssignable!T && !is(typeof(lhs.proxySwap(rhs)))) { import std.traits : hasAliasing, hasElaborateAssign, isAssignable, isStaticArray; static if (hasAliasing!T) if (!__ctfe) { import std.exception : doesPointTo; assert(!doesPointTo(lhs, lhs), "Swap: lhs internal pointer."); assert(!doesPointTo(rhs, rhs), "Swap: rhs internal pointer."); assert(!doesPointTo(lhs, rhs), "Swap: lhs points to rhs."); assert(!doesPointTo(rhs, lhs), "Swap: rhs points to lhs."); } static if (hasElaborateAssign!T || !isAssignable!T) { if (&lhs != &rhs) { // For structs with non-trivial assignment, move memory directly ubyte[T.sizeof] t = void; auto a = (cast(ubyte*) &lhs)[0 .. T.sizeof]; auto b = (cast(ubyte*) &rhs)[0 .. T.sizeof]; t[] = a[]; a[] = b[]; b[] = t[]; } } else { //Avoid assigning overlapping arrays. Dynamic arrays are fine, because //it's their ptr and length properties which get assigned rather //than their elements when assigning them, but static arrays are value //types and therefore all of their elements get copied as part of //assigning them, which would be assigning overlapping arrays if lhs //and rhs were the same array. static if (isStaticArray!T) { if (lhs.ptr == rhs.ptr) return; } // For non-struct types, suffice to do the classic swap auto tmp = lhs; lhs = rhs; rhs = tmp; } } /// @safe unittest { // Swapping POD (plain old data) types: int a = 42, b = 34; swap(a, b); assert(a == 34 && b == 42); // Swapping structs with indirection: static struct S { int x; char c; int[] y; } S s1 = { 0, 'z', [ 1, 2 ] }; S s2 = { 42, 'a', [ 4, 6 ] }; swap(s1, s2); assert(s1.x == 42); assert(s1.c == 'a'); assert(s1.y == [ 4, 6 ]); assert(s2.x == 0); assert(s2.c == 'z'); assert(s2.y == [ 1, 2 ]); // Immutables cannot be swapped: immutable int imm1, imm2; static assert(!__traits(compiles, swap(imm1, imm2))); } /// @safe unittest { // Non-copyable types can still be swapped. static struct NoCopy { this(this) { assert(0); } int n; string s; } NoCopy nc1, nc2; nc1.n = 127; nc1.s = "abc"; nc2.n = 513; nc2.s = "uvwxyz"; swap(nc1, nc2); assert(nc1.n == 513 && nc1.s == "uvwxyz"); assert(nc2.n == 127 && nc2.s == "abc"); swap(nc1, nc1); swap(nc2, nc2); assert(nc1.n == 513 && nc1.s == "uvwxyz"); assert(nc2.n == 127 && nc2.s == "abc"); // Types containing non-copyable fields can also be swapped. static struct NoCopyHolder { NoCopy noCopy; } NoCopyHolder h1, h2; h1.noCopy.n = 31; h1.noCopy.s = "abc"; h2.noCopy.n = 65; h2.noCopy.s = null; swap(h1, h2); assert(h1.noCopy.n == 65 && h1.noCopy.s == null); assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); swap(h1, h1); swap(h2, h2); assert(h1.noCopy.n == 65 && h1.noCopy.s == null); assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); // Const types cannot be swapped. const NoCopy const1, const2; static assert(!__traits(compiles, swap(const1, const2))); } @safe unittest { //Bug# 4789 int[1] s = [1]; swap(s, s); } @safe unittest { static struct NoAssign { int i; void opAssign(NoAssign) @disable; } auto s1 = NoAssign(1); auto s2 = NoAssign(2); swap(s1, s2); assert(s1.i == 2); assert(s2.i == 1); } @safe unittest { struct S { const int i; } S s; static assert(!__traits(compiles, swap(s, s))); } @safe unittest { //11853 import std.traits : isAssignable; alias T = Tuple!(int, double); static assert(isAssignable!T); } @safe unittest { // 12024 import std.datetime; SysTime a, b; } unittest // 9975 { import std.exception : doesPointTo, mayPointTo; static struct S2 { union { size_t sz; string s; } } S2 a , b; a.sz = -1; assert(!doesPointTo(a, b)); assert( mayPointTo(a, b)); swap(a, b); //Note: we can catch an error here, because there is no RAII in this test import std.exception : assertThrown; void* p, pp; p = &p; assertThrown!Error(move(p)); assertThrown!Error(move(p, pp)); assertThrown!Error(swap(p, pp)); } unittest { static struct A { int* x; this(this) { x = new int; } } A a1, a2; swap(a1, a2); static struct B { int* x; void opAssign(B) { x = new int; } } B b1, b2; swap(b1, b2); } // Not yet documented void swap(T)(ref T lhs, ref T rhs) if (is(typeof(lhs.proxySwap(rhs)))) { lhs.proxySwap(rhs); } void swapFront(R1, R2)(R1 r1, R2 r2) if (isInputRange!R1 && isInputRange!R2) { static if (is(typeof(swap(r1.front, r2.front)))) { swap(r1.front, r2.front); } else { auto t1 = moveFront(r1), t2 = moveFront(r2); r1.front = move(t2); r2.front = move(t1); } } // swapRanges /** Swaps all elements of $(D r1) with successive elements in $(D r2). Returns a tuple containing the remainder portions of $(D r1) and $(D r2) that were not swapped (one of them will be empty). The ranges may be of different types but must have the same element type and support swapping. Params: r1 = an $(XREF_PACK_NAMED _range,primitives,isInputRange,input _range) with swappable elements r2 = an $(XREF_PACK_NAMED _range,primitives,isInputRange,input _range) with swappable elements Returns: Tuple containing the remainder portions of r1 and r2 that were not swapped */ Tuple!(Range1, Range2) swapRanges(Range1, Range2)(Range1 r1, Range2 r2) if (isInputRange!(Range1) && isInputRange!(Range2) && hasSwappableElements!(Range1) && hasSwappableElements!(Range2) && is(ElementType!(Range1) == ElementType!(Range2))) { for (; !r1.empty && !r2.empty; r1.popFront(), r2.popFront()) { swap(r1.front, r2.front); } return tuple(r1, r2); } /// @safe unittest { int[] a = [ 100, 101, 102, 103 ]; int[] b = [ 0, 1, 2, 3 ]; auto c = swapRanges(a[1 .. 3], b[2 .. 4]); assert(c[0].empty && c[1].empty); assert(a == [ 100, 2, 3, 103 ]); assert(b == [ 0, 1, 101, 102 ]); } /** Initializes each element of $(D range) with $(D value). Assumes that the elements of the range are uninitialized. This is of interest for structs that define copy constructors (for all other types, $(LREF fill) and uninitializedFill are equivalent). Params: range = An $(XREF_PACK_NAMED _range,primitives,isInputRange,input _range) that exposes references to its elements and has assignable elements value = Assigned to each element of range See_Also: $(LREF fill) $(LREF initializeAll) */ void uninitializedFill(Range, Value)(Range range, Value value) if (isInputRange!Range && hasLvalueElements!Range && is(typeof(range.front = value))) { import std.traits : hasElaborateAssign; alias T = ElementType!Range; static if (hasElaborateAssign!T) { import std.conv : emplaceRef; // Must construct stuff by the book for (; !range.empty; range.popFront()) emplaceRef!T(range.front, value); } else // Doesn't matter whether fill is initialized or not return fill(range, value); } /// nothrow unittest { import core.stdc.stdlib : malloc, free; auto s = (cast(int*) malloc(5 * int.sizeof))[0 .. 5]; uninitializedFill(s, 42); assert(s == [ 42, 42, 42, 42, 42 ]); scope(exit) free(s.ptr); } ldc-1.1.0-beta3-src/runtime/phobos/std/algorithm/iteration.d0000664000175000017500000037225412776215007022054 0ustar kaikai// Written in the D programming language. /** This is a submodule of $(LINK2 std_algorithm.html, std.algorithm). It contains generic _iteration algorithms. $(BOOKTABLE Cheat Sheet, $(TR $(TH Function Name) $(TH Description)) $(T2 cache, Eagerly evaluates and caches another range's $(D front).) $(T2 cacheBidirectional, As above, but also provides $(D back) and $(D popBack).) $(T2 chunkBy, $(D chunkBy!((a,b) => a[1] == b[1])([[1, 1], [1, 2], [2, 2], [2, 1]])) returns a range containing 3 subranges: the first with just $(D [1, 1]); the second with the elements $(D [1, 2]) and $(D [2, 2]); and the third with just $(D [2, 1]).) $(T2 each, $(D each!writeln([1, 2, 3])) eagerly prints the numbers $(D 1), $(D 2) and $(D 3) on their own lines.) $(T2 filter, $(D filter!(a => a > 0)([1, -1, 2, 0, -3])) iterates over elements $(D 1) and $(D 2).) $(T2 filterBidirectional, Similar to $(D filter), but also provides $(D back) and $(D popBack) at a small increase in cost.) $(T2 fold, $(D fold!((a, b) => a + b)([1, 2, 3, 4])) returns $(D 10).) $(T2 group, $(D group([5, 2, 2, 3, 3])) returns a range containing the tuples $(D tuple(5, 1)), $(D tuple(2, 2)), and $(D tuple(3, 2)).) $(T2 joiner, $(D joiner(["hello", "world!"], "; ")) returns a range that iterates over the characters $(D "hello; world!"). No new string is created - the existing inputs are iterated.) $(T2 map, $(D map!(a => a * 2)([1, 2, 3])) lazily returns a range with the numbers $(D 2), $(D 4), $(D 6).) $(T2 permutations, Lazily computes all permutations using Heap's algorithm.) $(T2 reduce, $(D reduce!((a, b) => a + b)([1, 2, 3, 4])) returns $(D 10). This is the old implementation of `fold`.) $(T2 splitter, Lazily splits a range by a separator.) $(T2 sum, Same as $(D fold), but specialized for accurate summation.) $(T2 uniq, Iterates over the unique elements in a range, which is assumed sorted.) ) Copyright: Andrei Alexandrescu 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/algorithm/_iteration.d) Macros: T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) */ module std.algorithm.iteration; // FIXME import std.functional; // : unaryFun, binaryFun; import std.range.primitives; import std.traits; template aggregate(fun...) if (fun.length >= 1) { /* --Intentionally not ddoc-- * Aggregates elements in each subrange of the given range of ranges using * the given aggregating function(s). * Params: * fun = One or more aggregating functions (binary functions that return a * single _aggregate value of their arguments). * ror = A range of ranges to be aggregated. * * Returns: * A range representing the aggregated value(s) of each subrange * of the original range. If only one aggregating function is specified, * each element will be the aggregated value itself; if multiple functions * are specified, each element will be a tuple of the aggregated values of * each respective function. */ auto aggregate(RoR)(RoR ror) if (isInputRange!RoR && isIterable!(ElementType!RoR)) { return ror.map!(reduce!fun); } unittest { import std.algorithm.comparison : equal, max, min; auto data = [[4, 2, 1, 3], [4, 9, -1, 3, 2], [3]]; // Single aggregating function auto agg1 = data.aggregate!max; assert(agg1.equal([4, 9, 3])); // Multiple aggregating functions import std.typecons : tuple; auto agg2 = data.aggregate!(max, min); assert(agg2.equal([ tuple(4, 1), tuple(9, -1), tuple(3, 3) ])); } } /++ $(D cache) eagerly evaluates $(D front) of $(D range) on each construction or call to $(D popFront), to store the result in a cache. The result is then directly returned when $(D front) is called, rather than re-evaluated. This can be a useful function to place in a chain, after functions that have expensive evaluation, as a lazy alternative to $(XREF array,array). In particular, it can be placed after a call to $(D map), or before a call to $(D filter). $(D cache) may provide bidirectional iteration if needed, but since this comes at an increased cost, it must be explicitly requested via the call to $(D cacheBidirectional). Furthermore, a bidirectional cache will evaluate the "center" element twice, when there is only one element left in the range. $(D cache) does not provide random access primitives, as $(D cache) would be unable to cache the random accesses. If $(D Range) provides slicing primitives, then $(D cache) will provide the same slicing primitives, but $(D hasSlicing!Cache) will not yield true (as the $(XREF_PACK _range,primitives,hasSlicing) trait also checks for random access). Params: range = an input range Returns: an input range with the cached values of range +/ auto cache(Range)(Range range) if (isInputRange!Range) { return _Cache!(Range, false)(range); } /// ditto auto cacheBidirectional(Range)(Range range) if (isBidirectionalRange!Range) { return _Cache!(Range, true)(range); } /// @safe unittest { import std.algorithm.comparison : equal; import std.stdio, std.range; import std.typecons : tuple; ulong counter = 0; double fun(int x) { ++counter; // http://en.wikipedia.org/wiki/Quartic_function return ( (x + 4.0) * (x + 1.0) * (x - 1.0) * (x - 3.0) ) / 14.0 + 0.5; } // Without cache, with array (greedy) auto result1 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() .filter!(a => a[1] < 0)() .map!(a => a[0])() .array(); // the values of x that have a negative y are: assert(equal(result1, [-3, -2, 2])); // Check how many times fun was evaluated. // As many times as the number of items in both source and result. assert(counter == iota(-4, 5).length + result1.length); counter = 0; // Without array, with cache (lazy) auto result2 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() .cache() .filter!(a => a[1] < 0)() .map!(a => a[0])(); // the values of x that have a negative y are: assert(equal(result2, [-3, -2, 2])); // Check how many times fun was evaluated. // Only as many times as the number of items in source. assert(counter == iota(-4, 5).length); } /++ Tip: $(D cache) is eager when evaluating elements. If calling front on the underlying _range has a side effect, it will be observeable before calling front on the actual cached _range. Furthermore, care should be taken composing $(D cache) with $(XREF _range,take). By placing $(D take) before $(D cache), then $(D cache) will be "aware" of when the _range ends, and correctly stop caching elements when needed. If calling front has no side effect though, placing $(D take) after $(D cache) may yield a faster _range. Either way, the resulting ranges will be equivalent, but maybe not at the same cost or side effects. +/ @safe unittest { import std.algorithm.comparison : equal; import std.range; int i = 0; auto r = iota(0, 4).tee!((a){i = a;}, No.pipeOnPop); auto r1 = r.take(3).cache(); auto r2 = r.cache().take(3); assert(equal(r1, [0, 1, 2])); assert(i == 2); //The last "seen" element was 2. The data in cache has been cleared. assert(equal(r2, [0, 1, 2])); assert(i == 3); //cache has accessed 3. It is still stored internally by cache. } @safe unittest { import std.algorithm.comparison : equal; import std.range; auto a = [1, 2, 3, 4]; assert(equal(a.map!(a => (a - 1) * a)().cache(), [ 0, 2, 6, 12])); assert(equal(a.map!(a => (a - 1) * a)().cacheBidirectional().retro(), [12, 6, 2, 0])); auto r1 = [1, 2, 3, 4].cache() [1 .. $]; auto r2 = [1, 2, 3, 4].cacheBidirectional()[1 .. $]; assert(equal(r1, [2, 3, 4])); assert(equal(r2, [2, 3, 4])); } @safe unittest { import std.algorithm.comparison : equal; //immutable test static struct S { int i; this(int i) { //this.i = i; } } immutable(S)[] s = [S(1), S(2), S(3)]; assert(equal(s.cache(), s)); assert(equal(s.cacheBidirectional(), s)); } @safe pure nothrow unittest { import std.algorithm.comparison : equal; //safety etc auto a = [1, 2, 3, 4]; assert(equal(a.cache(), a)); assert(equal(a.cacheBidirectional(), a)); } @safe unittest { char[][] stringbufs = ["hello".dup, "world".dup]; auto strings = stringbufs.map!((a)=>a.idup)().cache(); assert(strings.front is strings.front); } @safe unittest { import std.range; auto c = [1, 2, 3].cycle().cache(); c = c[1 .. $]; auto d = c[0 .. 1]; } @safe unittest { static struct Range { bool initialized = false; bool front() @property {return initialized = true;} void popFront() {initialized = false;} enum empty = false; } auto r = Range().cache(); assert(r.source.initialized == true); } private struct _Cache(R, bool bidir) { import core.exception : RangeError; private { import std.algorithm.internal : algoFormat; import std.meta : AliasSeq; alias E = ElementType!R; alias UE = Unqual!E; R source; static if (bidir) alias CacheTypes = AliasSeq!(UE, UE); else alias CacheTypes = AliasSeq!UE; CacheTypes caches; static assert(isAssignable!(UE, E) && is(UE : E), algoFormat("Cannot instantiate range with %s because %s elements are not assignable to %s.", R.stringof, E.stringof, UE.stringof)); } this(R range) { source = range; if (!range.empty) { caches[0] = source.front; static if (bidir) caches[1] = source.back; } } static if (isInfinite!R) enum empty = false; else bool empty() @property { return source.empty; } static if (hasLength!R) auto length() @property { return source.length; } E front() @property { version(assert) if (empty) throw new RangeError(); return caches[0]; } static if (bidir) E back() @property { version(assert) if (empty) throw new RangeError(); return caches[1]; } void popFront() { version(assert) if (empty) throw new RangeError(); source.popFront(); if (!source.empty) caches[0] = source.front; else caches = CacheTypes.init; } static if (bidir) void popBack() { version(assert) if (empty) throw new RangeError(); source.popBack(); if (!source.empty) caches[1] = source.back; else caches = CacheTypes.init; } static if (isForwardRange!R) { private this(R source, ref CacheTypes caches) { this.source = source; this.caches = caches; } typeof(this) save() @property { return typeof(this)(source.save, caches); } } static if (hasSlicing!R) { enum hasEndSlicing = is(typeof(source[size_t.max .. $])); static if (hasEndSlicing) { private static struct DollarToken{} enum opDollar = DollarToken.init; auto opSlice(size_t low, DollarToken) { return typeof(this)(source[low .. $]); } } static if (!isInfinite!R) { typeof(this) opSlice(size_t low, size_t high) { return typeof(this)(source[low .. high]); } } else static if (hasEndSlicing) { auto opSlice(size_t low, size_t high) in { assert(low <= high); } body { import std.range : take; return this[low .. $].take(high - low); } } } } /** $(D auto map(Range)(Range r) if (isInputRange!(Unqual!Range));) Implements the homonym function (also known as $(D transform)) present in many languages of functional flavor. The call $(D map!(fun)(range)) returns a range of which elements are obtained by applying $(D fun(a)) left to right for all elements $(D a) in $(D range). The original ranges are not changed. Evaluation is done lazily. Params: fun = one or more functions r = an input range Returns: a range with each fun applied to all the elements. If there is more than one fun, the element type will be $(D Tuple) containing one element for each fun. See_Also: $(WEB en.wikipedia.org/wiki/Map_(higher-order_function), Map (higher-order function)) */ template map(fun...) if (fun.length >= 1) { auto map(Range)(Range r) if (isInputRange!(Unqual!Range)) { import std.meta : AliasSeq, staticMap; alias RE = ElementType!(Range); static if (fun.length > 1) { import std.functional : adjoin; import std.meta : staticIndexOf; alias _funs = staticMap!(unaryFun, fun); alias _fun = adjoin!_funs; // Once DMD issue #5710 is fixed, this validation loop can be moved into a template. foreach(f; _funs) { static assert(!is(typeof(f(RE.init)) == void), "Mapping function(s) must not return void: " ~ _funs.stringof); } } else { alias _fun = unaryFun!fun; alias _funs = AliasSeq!(_fun); // Do the validation separately for single parameters due to DMD issue #15777. static assert(!is(typeof(_fun(RE.init)) == void), "Mapping function(s) must not return void: " ~ _funs.stringof); } return MapResult!(_fun, Range)(r); } } /// @safe unittest { import std.algorithm.comparison : equal; import std.range : chain; int[] arr1 = [ 1, 2, 3, 4 ]; int[] arr2 = [ 5, 6 ]; auto squares = map!(a => a * a)(chain(arr1, arr2)); assert(equal(squares, [ 1, 4, 9, 16, 25, 36 ])); } /** Multiple functions can be passed to $(D map). In that case, the element type of $(D map) is a tuple containing one element for each function. */ @safe unittest { auto sums = [2, 4, 6, 8]; auto products = [1, 4, 9, 16]; size_t i = 0; foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a")) { assert(result[0] == sums[i]); assert(result[1] == products[i]); ++i; } } /** You may alias $(D map) with some function(s) to a symbol and use it separately: */ @safe unittest { import std.algorithm.comparison : equal; import std.conv : to; alias stringize = map!(to!string); assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ])); } @safe unittest { // Verify workaround for DMD #15777 import std.algorithm.mutation, std.string; auto foo(string[] args) { return args.map!strip; } } private struct MapResult(alias fun, Range) { alias R = Unqual!Range; R _input; static if (isBidirectionalRange!R) { @property auto ref back()() { return fun(_input.back); } void popBack()() { _input.popBack(); } } this(R input) { _input = input; } static if (isInfinite!R) { // Propagate infinite-ness. enum bool empty = false; } else { @property bool empty() { return _input.empty; } } void popFront() { _input.popFront(); } @property auto ref front() { return fun(_input.front); } static if (isRandomAccessRange!R) { static if (is(typeof(_input[ulong.max]))) private alias opIndex_t = ulong; else private alias opIndex_t = uint; auto ref opIndex(opIndex_t index) { return fun(_input[index]); } } static if (hasLength!R) { @property auto length() { return _input.length; } alias opDollar = length; } static if (hasSlicing!R) { static if (is(typeof(_input[ulong.max .. ulong.max]))) private alias opSlice_t = ulong; else private alias opSlice_t = uint; static if (hasLength!R) { auto opSlice(opSlice_t low, opSlice_t high) { return typeof(this)(_input[low .. high]); } } else static if (is(typeof(_input[opSlice_t.max .. $]))) { struct DollarToken{} enum opDollar = DollarToken.init; auto opSlice(opSlice_t low, DollarToken) { return typeof(this)(_input[low .. $]); } auto opSlice(opSlice_t low, opSlice_t high) { import std.range : take; return this[low .. $].take(high - low); } } } static if (isForwardRange!R) { @property auto save() { return typeof(this)(_input.save); } } } @safe unittest { import std.algorithm.comparison : equal; import std.conv : to; import std.functional : adjoin; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); alias stringize = map!(to!string); assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ])); uint counter; alias count = map!((a) { return counter++; }); assert(equal(count([ 10, 2, 30, 4 ]), [ 0, 1, 2, 3 ])); counter = 0; adjoin!((a) { return counter++; }, (a) { return counter++; })(1); alias countAndSquare = map!((a) { return counter++; }, (a) { return counter++; }); //assert(equal(countAndSquare([ 10, 2 ]), [ tuple(0u, 100), tuple(1u, 4) ])); } unittest { import std.algorithm.comparison : equal; import std.internal.test.dummyrange; import std.ascii : toUpper; import std.range; import std.typecons : tuple; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] arr1 = [ 1, 2, 3, 4 ]; const int[] arr1Const = arr1; int[] arr2 = [ 5, 6 ]; auto squares = map!("a * a")(arr1Const); assert(squares[$ - 1] == 16); assert(equal(squares, [ 1, 4, 9, 16 ][])); assert(equal(map!("a * a")(chain(arr1, arr2)), [ 1, 4, 9, 16, 25, 36 ][])); // Test the caching stuff. assert(squares.back == 16); auto squares2 = squares.save; assert(squares2.back == 16); assert(squares2.front == 1); squares2.popFront(); assert(squares2.front == 4); squares2.popBack(); assert(squares2.front == 4); assert(squares2.back == 9); assert(equal(map!("a * a")(chain(arr1, arr2)), [ 1, 4, 9, 16, 25, 36 ][])); uint i; foreach (e; map!("a", "a * a")(arr1)) { assert(e[0] == ++i); assert(e[1] == i * i); } // Test length. assert(squares.length == 4); assert(map!"a * a"(chain(arr1, arr2)).length == 6); // Test indexing. assert(squares[0] == 1); assert(squares[1] == 4); assert(squares[2] == 9); assert(squares[3] == 16); // Test slicing. auto squareSlice = squares[1..squares.length - 1]; assert(equal(squareSlice, [4, 9][])); assert(squareSlice.back == 9); assert(squareSlice[1] == 9); // Test on a forward range to make sure it compiles when all the fancy // stuff is disabled. auto fibsSquares = map!"a * a"(recurrence!("a[n-1] + a[n-2]")(1, 1)); assert(fibsSquares.front == 1); fibsSquares.popFront(); fibsSquares.popFront(); assert(fibsSquares.front == 4); fibsSquares.popFront(); assert(fibsSquares.front == 9); auto repeatMap = map!"a"(repeat(1)); static assert(isInfinite!(typeof(repeatMap))); auto intRange = map!"a"([1,2,3]); static assert(isRandomAccessRange!(typeof(intRange))); foreach (DummyType; AllDummyRanges) { DummyType d; auto m = map!"a * a"(d); static assert(propagatesRangeType!(typeof(m), DummyType)); assert(equal(m, [1,4,9,16,25,36,49,64,81,100])); } //Test string access string s1 = "hello world!"; dstring s2 = "日本語"; dstring s3 = "hello world!"d; auto ms1 = map!(std.ascii.toUpper)(s1); auto ms2 = map!(std.ascii.toUpper)(s2); auto ms3 = map!(std.ascii.toUpper)(s3); static assert(!is(ms1[0])); //narrow strings can't be indexed assert(ms2[0] == '日'); assert(ms3[0] == 'H'); static assert(!is(ms1[0..1])); //narrow strings can't be sliced assert(equal(ms2[0..2], "日本"w)); assert(equal(ms3[0..2], "HE")); // Issue 5753 static void voidFun(int) {} static int nonvoidFun(int) { return 0; } static assert(!__traits(compiles, map!voidFun([1]))); static assert(!__traits(compiles, map!(voidFun, voidFun)([1]))); static assert(!__traits(compiles, map!(nonvoidFun, voidFun)([1]))); static assert(!__traits(compiles, map!(voidFun, nonvoidFun)([1]))); static assert(!__traits(compiles, map!(a => voidFun(a))([1]))); // Phobos issue #15480 auto dd = map!(z => z * z, c => c * c * c)([ 1, 2, 3, 4 ]); assert(dd[0] == tuple(1, 1)); assert(dd[1] == tuple(4, 8)); assert(dd[2] == tuple(9, 27)); assert(dd[3] == tuple(16, 64)); assert(dd.length == 4); } @safe unittest { import std.algorithm.comparison : equal; import std.range; auto LL = iota(1L, 4L); auto m = map!"a*a"(LL); assert(equal(m, [1L, 4L, 9L])); } @safe unittest { import std.range : iota; // Issue #10130 - map of iota with const step. const step = 2; assert(map!(i => i)(iota(0, 10, step)).walkLength == 5); // Need these to all by const to repro the float case, due to the // CommonType template used in the float specialization of iota. const floatBegin = 0.0; const floatEnd = 1.0; const floatStep = 0.02; assert(map!(i => i)(iota(floatBegin, floatEnd, floatStep)).walkLength == 50); } @safe unittest { import std.algorithm.comparison : equal; import std.range; //slicing infinites auto rr = iota(0, 5).cycle().map!"a * a"(); alias RR = typeof(rr); static assert(hasSlicing!RR); rr = rr[6 .. $]; //Advances 1 cycle and 1 unit assert(equal(rr[0 .. 5], [1, 4, 9, 16, 0])); } @safe unittest { import std.range; struct S {int* p;} auto m = immutable(S).init.repeat().map!"a".save; } // each /** Eagerly iterates over $(D r) and calls $(D pred) over _each element. If no predicate is specified, $(D each) will default to doing nothing but consuming the entire range. $(D .front) will be evaluated, but this can be avoided by explicitly specifying a predicate lambda with a $(D lazy) parameter. $(D each) also supports $(D opApply)-based iterators, so it will work with e.g. $(XREF parallelism, parallel). Params: pred = predicate to apply to each element of the range r = range or iterable over which each iterates See_Also: $(XREF range,tee) */ template each(alias pred = "a") { import std.meta : AliasSeq; alias BinaryArgs = AliasSeq!(pred, "i", "a"); enum isRangeUnaryIterable(R) = is(typeof(unaryFun!pred(R.init.front))); enum isRangeBinaryIterable(R) = is(typeof(binaryFun!BinaryArgs(0, R.init.front))); enum isRangeIterable(R) = isInputRange!R && (isRangeUnaryIterable!R || isRangeBinaryIterable!R); enum isForeachUnaryIterable(R) = is(typeof((R r) { foreach (ref a; r) cast(void)unaryFun!pred(a); })); enum isForeachBinaryIterable(R) = is(typeof((R r) { foreach (i, ref a; r) cast(void)binaryFun!BinaryArgs(i, a); })); enum isForeachIterable(R) = (!isForwardRange!R || isDynamicArray!R) && (isForeachUnaryIterable!R || isForeachBinaryIterable!R); void each(Range)(Range r) if (isRangeIterable!Range && !isForeachIterable!Range) { debug(each) pragma(msg, "Using while for ", Range.stringof); static if (isRangeUnaryIterable!Range) { while (!r.empty) { cast(void)unaryFun!pred(r.front); r.popFront(); } } else // if (isRangeBinaryIterable!Range) { size_t i = 0; while (!r.empty) { cast(void)binaryFun!BinaryArgs(i, r.front); r.popFront(); i++; } } } void each(Iterable)(Iterable r) if (isForeachIterable!Iterable) { debug(each) pragma(msg, "Using foreach for ", Iterable.stringof); static if (isForeachUnaryIterable!Iterable) { foreach (ref e; r) cast(void)unaryFun!pred(e); } else // if (isForeachBinaryIterable!Iterable) { foreach (i, ref e; r) cast(void)binaryFun!BinaryArgs(i, e); } } } /// unittest { import std.range : iota; long[] arr; iota(5).each!(n => arr ~= n); assert(arr == [0, 1, 2, 3, 4]); // If the range supports it, the value can be mutated in place arr.each!((ref n) => n++); assert(arr == [1, 2, 3, 4, 5]); arr.each!"a++"; assert(arr == [2, 3, 4, 5, 6]); // by-ref lambdas are not allowed for non-ref ranges static assert(!is(typeof(arr.map!(n => n).each!((ref n) => n++)))); // The default predicate consumes the range auto m = arr.map!(n => n); (&m).each(); assert(m.empty); // Indexes are also available for in-place mutations arr[] = 0; arr.each!"a=i"(); assert(arr == [0, 1, 2, 3, 4]); // opApply iterators work as well static assert(is(typeof({ import std.parallelism; arr.parallel.each!"a++"; }))); } /** $(D auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range));) Implements the higher order _filter function. The predicate is passed to $(XREF functional,unaryFun), and can either accept a string, or any callable that can be executed via $(D pred(element)). Params: predicate = Function to apply to each element of range range = Input range of elements Returns: $(D filter!(predicate)(range)) returns a new range containing only elements $(D x) in $(D range) for which $(D predicate(x)) returns $(D true). See_Also: $(WEB en.wikipedia.org/wiki/Filter_(higher-order_function), Filter (higher-order function)) */ template filter(alias predicate) if (is(typeof(unaryFun!predicate))) { auto filter(Range)(Range range) if (isInputRange!(Unqual!Range)) { return FilterResult!(unaryFun!predicate, Range)(range); } } /// @safe unittest { import std.algorithm.comparison : equal; import std.math : approxEqual; import std.range; int[] arr = [ 1, 2, 3, 4, 5 ]; // Sum all elements auto small = filter!(a => a < 3)(arr); assert(equal(small, [ 1, 2 ])); // Sum again, but with Uniform Function Call Syntax (UFCS) auto sum = arr.filter!(a => a < 3); assert(equal(sum, [ 1, 2 ])); // In combination with chain() to span multiple ranges int[] a = [ 3, -2, 400 ]; int[] b = [ 100, -101, 102 ]; auto r = chain(a, b).filter!(a => a > 0); assert(equal(r, [ 3, 400, 100, 102 ])); // Mixing convertible types is fair game, too double[] c = [ 2.5, 3.0 ]; auto r1 = chain(c, a, b).filter!(a => cast(int) a != a); assert(approxEqual(r1, [ 2.5 ])); } private struct FilterResult(alias pred, Range) { alias R = Unqual!Range; R _input; this(R r) { _input = r; while (!_input.empty && !pred(_input.front)) { _input.popFront(); } } auto opSlice() { return this; } static if (isInfinite!Range) { enum bool empty = false; } else { @property bool empty() { return _input.empty; } } void popFront() { do { _input.popFront(); } while (!_input.empty && !pred(_input.front)); } @property auto ref front() { return _input.front; } static if (isForwardRange!R) { @property auto save() { return typeof(this)(_input.save); } } } @safe unittest { import std.algorithm.comparison : equal; import std.internal.test.dummyrange; import std.range; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 3, 4, 2 ]; auto r = filter!("a > 3")(a); static assert(isForwardRange!(typeof(r))); assert(equal(r, [ 4 ][])); a = [ 1, 22, 3, 42, 5 ]; auto under10 = filter!("a < 10")(a); assert(equal(under10, [1, 3, 5][])); static assert(isForwardRange!(typeof(under10))); under10.front = 4; assert(equal(under10, [4, 3, 5][])); under10.front = 40; assert(equal(under10, [40, 3, 5][])); under10.front = 1; auto infinite = filter!"a > 2"(repeat(3)); static assert(isInfinite!(typeof(infinite))); static assert(isForwardRange!(typeof(infinite))); foreach (DummyType; AllDummyRanges) { DummyType d; auto f = filter!"a & 1"(d); assert(equal(f, [1,3,5,7,9])); static if (isForwardRange!DummyType) { static assert(isForwardRange!(typeof(f))); } } // With delegates int x = 10; int overX(int a) { return a > x; } typeof(filter!overX(a)) getFilter() { return filter!overX(a); } auto r1 = getFilter(); assert(equal(r1, [22, 42])); // With chain auto nums = [0,1,2,3,4]; assert(equal(filter!overX(chain(a, nums)), [22, 42])); // With copying of inner struct Filter to Map auto arr = [1,2,3,4,5]; auto m = map!"a + 1"(filter!"a < 4"(arr)); } @safe unittest { import std.algorithm.comparison : equal; int[] a = [ 3, 4 ]; const aConst = a; auto r = filter!("a > 3")(aConst); assert(equal(r, [ 4 ][])); a = [ 1, 22, 3, 42, 5 ]; auto under10 = filter!("a < 10")(a); assert(equal(under10, [1, 3, 5][])); assert(equal(under10.save, [1, 3, 5][])); assert(equal(under10.save, under10)); // With copying of inner struct Filter to Map auto arr = [1,2,3,4,5]; auto m = map!"a + 1"(filter!"a < 4"(arr)); } @safe unittest { import std.algorithm.comparison : equal; import std.functional : compose, pipe; assert(equal(compose!(map!"2 * a", filter!"a & 1")([1,2,3,4,5]), [2,6,10])); assert(equal(pipe!(filter!"a & 1", map!"2 * a")([1,2,3,4,5]), [2,6,10])); } @safe unittest { import std.algorithm.comparison : equal; int x = 10; int underX(int a) { return a < x; } const(int)[] list = [ 1, 2, 10, 11, 3, 4 ]; assert(equal(filter!underX(list), [ 1, 2, 3, 4 ])); } /** * $(D auto filterBidirectional(Range)(Range r) if (isBidirectionalRange!(Unqual!Range));) * * Similar to $(D filter), except it defines a bidirectional * range. There is a speed disadvantage - the constructor spends time * finding the last element in the range that satisfies the filtering * condition (in addition to finding the first one). The advantage is * that the filtered range can be spanned from both directions. Also, * $(XREF range, retro) can be applied against the filtered range. * * The predicate is passed to $(XREF functional,unaryFun), and can either * accept a string, or any callable that can be executed via $(D pred(element)). * * Params: * pred = Function to apply to each element of range * r = Bidirectional range of elements * * Returns: * a new range containing only the elements in r for which pred returns $(D true). */ template filterBidirectional(alias pred) { auto filterBidirectional(Range)(Range r) if (isBidirectionalRange!(Unqual!Range)) { return FilterBidiResult!(unaryFun!pred, Range)(r); } } /// @safe unittest { import std.algorithm.comparison : equal; import std.range; int[] arr = [ 1, 2, 3, 4, 5 ]; auto small = filterBidirectional!("a < 3")(arr); static assert(isBidirectionalRange!(typeof(small))); assert(small.back == 2); assert(equal(small, [ 1, 2 ])); assert(equal(retro(small), [ 2, 1 ])); // In combination with chain() to span multiple ranges int[] a = [ 3, -2, 400 ]; int[] b = [ 100, -101, 102 ]; auto r = filterBidirectional!("a > 0")(chain(a, b)); assert(r.back == 102); } private struct FilterBidiResult(alias pred, Range) { alias R = Unqual!Range; R _input; this(R r) { _input = r; while (!_input.empty && !pred(_input.front)) _input.popFront(); while (!_input.empty && !pred(_input.back)) _input.popBack(); } @property bool empty() { return _input.empty; } void popFront() { do { _input.popFront(); } while (!_input.empty && !pred(_input.front)); } @property auto ref front() { return _input.front; } void popBack() { do { _input.popBack(); } while (!_input.empty && !pred(_input.back)); } @property auto ref back() { return _input.back; } @property auto save() { return typeof(this)(_input.save); } } // group struct Group(alias pred, R) if (isInputRange!R) { import std.typecons : Rebindable, tuple, Tuple; private alias comp = binaryFun!pred; private alias E = ElementType!R; static if ((is(E == class) || is(E == interface)) && (is(E == const) || is(E == immutable))) { private alias MutableE = Rebindable!E; } else static if (is(E : Unqual!E)) { private alias MutableE = Unqual!E; } else { private alias MutableE = E; } private R _input; private Tuple!(MutableE, uint) _current; this(R input) { _input = input; if (!_input.empty) popFront(); } void popFront() { if (_input.empty) { _current[1] = 0; } else { _current = tuple(_input.front, 1u); _input.popFront(); while (!_input.empty && comp(_current[0], _input.front)) { ++_current[1]; _input.popFront(); } } } static if (isInfinite!R) { enum bool empty = false; // Propagate infiniteness. } else { @property bool empty() { return _current[1] == 0; } } @property auto ref front() { assert(!empty); return _current; } static if (isForwardRange!R) { @property typeof(this) save() { typeof(this) ret = this; ret._input = this._input.save; ret._current = this._current; return ret; } } } /** Groups consecutively equivalent elements into a single tuple of the element and the number of its repetitions. Similarly to $(D uniq), $(D group) produces a range that iterates over unique consecutive elements of the given range. Each element of this range is a tuple of the element and the number of times it is repeated in the original range. Equivalence of elements is assessed by using the predicate $(D pred), which defaults to $(D "a == b"). The predicate is passed to $(XREF functional,binaryFun), and can either accept a string, or any callable that can be executed via $(D pred(element, element)). Params: pred = Binary predicate for determining equivalence of two elements. r = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) to iterate over. Returns: A range of elements of type $(D Tuple!(ElementType!R, uint)), representing each consecutively unique element and its respective number of occurrences in that run. This will be an input range if $(D R) is an input range, and a forward range in all other cases. */ Group!(pred, Range) group(alias pred = "a == b", Range)(Range r) { return typeof(return)(r); } /// @safe unittest { import std.algorithm.comparison : equal; import std.typecons : tuple, Tuple; int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u), tuple(4, 3u), tuple(5, 1u) ][])); } @safe unittest { import std.algorithm.comparison : equal; import std.internal.test.dummyrange; import std.typecons : tuple, Tuple; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u), tuple(4, 3u), tuple(5, 1u) ][])); static assert(isForwardRange!(typeof(group(arr)))); foreach (DummyType; AllDummyRanges) { DummyType d; auto g = group(d); static assert(d.rt == RangeType.Input || isForwardRange!(typeof(g))); assert(equal(g, [tuple(1, 1u), tuple(2, 1u), tuple(3, 1u), tuple(4, 1u), tuple(5, 1u), tuple(6, 1u), tuple(7, 1u), tuple(8, 1u), tuple(9, 1u), tuple(10, 1u)])); } } unittest { // Issue 13857 immutable(int)[] a1 = [1,1,2,2,2,3,4,4,5,6,6,7,8,9,9,9]; auto g1 = group(a1); // Issue 13162 immutable(ubyte)[] a2 = [1, 1, 1, 0, 0, 0]; auto g2 = a2.group; // Issue 10104 const a3 = [1, 1, 2, 2]; auto g3 = a3.group; interface I {} class C : I {} const C[] a4 = [new const C()]; auto g4 = a4.group!"a is b"; immutable I[] a5 = [new immutable C()]; auto g5 = a5.group!"a is b"; const(int[][]) a6 = [[1], [1]]; auto g6 = a6.group; } // Used by implementation of chunkBy for non-forward input ranges. private struct ChunkByChunkImpl(alias pred, Range) if (isInputRange!Range && !isForwardRange!Range) { alias fun = binaryFun!pred; private Range r; private ElementType!Range prev; this(Range range, ElementType!Range _prev) { r = range; prev = _prev; } @property bool empty() { return r.empty || !fun(prev, r.front); } @property ElementType!Range front() { return r.front; } void popFront() { r.popFront(); } } private template ChunkByImplIsUnary(alias pred, Range) { static if (is(typeof(binaryFun!pred(ElementType!Range.init, ElementType!Range.init)) : bool)) enum ChunkByImplIsUnary = false; else static if (is(typeof( unaryFun!pred(ElementType!Range.init) == unaryFun!pred(ElementType!Range.init)))) enum ChunkByImplIsUnary = true; else static assert(0, "chunkBy expects either a binary predicate or "~ "a unary predicate on range elements of type: "~ ElementType!Range.stringof); } // Implementation of chunkBy for non-forward input ranges. private struct ChunkByImpl(alias pred, Range) if (isInputRange!Range && !isForwardRange!Range) { enum bool isUnary = ChunkByImplIsUnary!(pred, Range); static if (isUnary) alias eq = binaryFun!((a, b) => unaryFun!pred(a) == unaryFun!pred(b)); else alias eq = binaryFun!pred; private Range r; private ElementType!Range _prev; this(Range _r) { r = _r; if (!empty) { // Check reflexivity if predicate is claimed to be an equivalence // relation. assert(eq(r.front, r.front), "predicate is not reflexive"); // _prev's type may be a nested struct, so must be initialized // directly in the constructor (cannot call savePred()). _prev = r.front; } else { // We won't use _prev, but must be initialized. _prev = typeof(_prev).init; } } @property bool empty() { return r.empty; } @property auto front() { static if (isUnary) { import std.typecons : tuple; return tuple(unaryFun!pred(_prev), ChunkByChunkImpl!(eq, Range)(r, _prev)); } else { return ChunkByChunkImpl!(eq, Range)(r, _prev); } } void popFront() { while (!r.empty) { if (!eq(_prev, r.front)) { _prev = r.front; break; } r.popFront(); } } } // Single-pass implementation of chunkBy for forward ranges. private struct ChunkByImpl(alias pred, Range) if (isForwardRange!Range) { import std.typecons : RefCounted; enum bool isUnary = ChunkByImplIsUnary!(pred, Range); static if (isUnary) alias eq = binaryFun!((a, b) => unaryFun!pred(a) == unaryFun!pred(b)); else alias eq = binaryFun!pred; // Outer range static struct Impl { size_t groupNum; Range current; Range next; } // Inner range static struct Group { private size_t groupNum; private Range start; private Range current; private RefCounted!Impl mothership; this(RefCounted!Impl origin) { groupNum = origin.groupNum; start = origin.current.save; current = origin.current.save; assert(!start.empty); mothership = origin; // Note: this requires reflexivity. assert(eq(start.front, current.front), "predicate is not reflexive"); } @property bool empty() { return groupNum == size_t.max; } @property auto ref front() { return current.front; } void popFront() { current.popFront(); // Note: this requires transitivity. if (current.empty || !eq(start.front, current.front)) { if (groupNum == mothership.groupNum) { // If parent range hasn't moved on yet, help it along by // saving location of start of next Group. mothership.next = current.save; } groupNum = size_t.max; } } @property auto save() { auto copy = this; copy.current = current.save; return copy; } } static assert(isForwardRange!Group); private RefCounted!Impl impl; this(Range r) { impl = RefCounted!Impl(0, r, r.save); } @property bool empty() { return impl.current.empty; } @property auto front() { static if (isUnary) { import std.typecons : tuple; return tuple(unaryFun!pred(impl.current.front), Group(impl)); } else { return Group(impl); } } void popFront() { // Scan for next group. If we're lucky, one of our Groups would have // already set .next to the start of the next group, in which case the // loop is skipped. while (!impl.next.empty && eq(impl.current.front, impl.next.front)) { impl.next.popFront(); } impl.current = impl.next.save; // Indicate to any remaining Groups that we have moved on. impl.groupNum++; } @property auto save() { // Note: the new copy of the range will be detached from any existing // satellite Groups, and will not benefit from the .next acceleration. return typeof(this)(impl.current.save); } static assert(isForwardRange!(typeof(this))); } unittest { import std.algorithm.comparison : equal; size_t popCount = 0; class RefFwdRange { int[] impl; this(int[] data) { impl = data; } @property bool empty() { return impl.empty; } @property auto ref front() { return impl.front; } void popFront() { impl.popFront(); popCount++; } @property auto save() { return new RefFwdRange(impl); } } static assert(isForwardRange!RefFwdRange); auto testdata = new RefFwdRange([1, 3, 5, 2, 4, 7, 6, 8, 9]); auto groups = testdata.chunkBy!((a,b) => (a % 2) == (b % 2)); auto outerSave1 = groups.save; // Sanity test assert(groups.equal!equal([[1, 3, 5], [2, 4], [7], [6, 8], [9]])); assert(groups.empty); // Performance test for single-traversal use case: popFront should not have // been called more times than there are elements if we traversed the // segmented range exactly once. assert(popCount == 9); // Outer range .save test groups = outerSave1.save; assert(!groups.empty); // Inner range .save test auto grp1 = groups.front.save; auto grp1b = grp1.save; assert(grp1b.equal([1, 3, 5])); assert(grp1.save.equal([1, 3, 5])); // Inner range should remain consistent after outer range has moved on. groups.popFront(); assert(grp1.save.equal([1, 3, 5])); // Inner range should not be affected by subsequent inner ranges. assert(groups.front.equal([2, 4])); assert(grp1.save.equal([1, 3, 5])); } /** * Chunks an input range into subranges of equivalent adjacent elements. * * Equivalence is defined by the predicate $(D pred), which can be either * binary, which is passed to $(XREF functional,binaryFun), or unary, which is * passed to $(XREF functional,unaryFun). In the binary form, two _range elements * $(D a) and $(D b) are considered equivalent if $(D pred(a,b)) is true. In * unary form, two elements are considered equivalent if $(D pred(a) == pred(b)) * is true. * * This predicate must be an equivalence relation, that is, it must be * reflexive ($(D pred(x,x)) is always true), symmetric * ($(D pred(x,y) == pred(y,x))), and transitive ($(D pred(x,y) && pred(y,z)) * implies $(D pred(x,z))). If this is not the case, the range returned by * chunkBy may assert at runtime or behave erratically. * * Params: * pred = Predicate for determining equivalence. * r = The range to be chunked. * * Returns: With a binary predicate, a range of ranges is returned in which * all elements in a given subrange are equivalent under the given predicate. * With a unary predicate, a range of tuples is returned, with the tuple * consisting of the result of the unary predicate for each subrange, and the * subrange itself. * * Notes: * * Equivalent elements separated by an intervening non-equivalent element will * appear in separate subranges; this function only considers adjacent * equivalence. Elements in the subranges will always appear in the same order * they appear in the original range. * * See_also: * $(LREF group), which collapses adjacent equivalent elements into a single * element. */ auto chunkBy(alias pred, Range)(Range r) if (isInputRange!Range) { return ChunkByImpl!(pred, Range)(r); } /// Showing usage with binary predicate: /*FIXME: @safe*/ unittest { import std.algorithm.comparison : equal; // Grouping by particular attribute of each element: auto data = [ [1, 1], [1, 2], [2, 2], [2, 3] ]; auto r1 = data.chunkBy!((a,b) => a[0] == b[0]); assert(r1.equal!equal([ [[1, 1], [1, 2]], [[2, 2], [2, 3]] ])); auto r2 = data.chunkBy!((a,b) => a[1] == b[1]); assert(r2.equal!equal([ [[1, 1]], [[1, 2], [2, 2]], [[2, 3]] ])); } version(none) // this example requires support for non-equivalence relations unittest { auto data = [ [1, 1], [1, 2], [2, 2], [2, 3] ]; version(none) { // Grouping by maximum adjacent difference: import std.math : abs; auto r3 = [1, 3, 2, 5, 4, 9, 10].chunkBy!((a, b) => abs(a-b) < 3); assert(r3.equal!equal([ [1, 3, 2], [5, 4], [9, 10] ])); } } /// Showing usage with unary predicate: /* FIXME: pure @safe nothrow*/ unittest { import std.algorithm.comparison : equal; import std.typecons : tuple; // Grouping by particular attribute of each element: auto range = [ [1, 1], [1, 1], [1, 2], [2, 2], [2, 3], [2, 3], [3, 3] ]; auto byX = chunkBy!(a => a[0])(range); auto expected1 = [ tuple(1, [[1, 1], [1, 1], [1, 2]]), tuple(2, [[2, 2], [2, 3], [2, 3]]), tuple(3, [[3, 3]]) ]; foreach (e; byX) { assert(!expected1.empty); assert(e[0] == expected1.front[0]); assert(e[1].equal(expected1.front[1])); expected1.popFront(); } auto byY = chunkBy!(a => a[1])(range); auto expected2 = [ tuple(1, [[1, 1], [1, 1]]), tuple(2, [[1, 2], [2, 2]]), tuple(3, [[2, 3], [2, 3], [3, 3]]) ]; foreach (e; byY) { assert(!expected2.empty); assert(e[0] == expected2.front[0]); assert(e[1].equal(expected2.front[1])); expected2.popFront(); } } /*FIXME: pure @safe nothrow*/ unittest { import std.algorithm.comparison : equal; import std.typecons : tuple; struct Item { int x, y; } // Force R to have only an input range API with reference semantics, so // that we're not unknowingly making use of array semantics outside of the // range API. class RefInputRange(R) { R data; this(R _data) pure @safe nothrow { data = _data; } @property bool empty() pure @safe nothrow { return data.empty; } @property auto front() pure @safe nothrow { return data.front; } void popFront() pure @safe nothrow { data.popFront(); } } auto refInputRange(R)(R range) { return new RefInputRange!R(range); } { auto arr = [ Item(1,2), Item(1,3), Item(2,3) ]; static assert(isForwardRange!(typeof(arr))); auto byX = chunkBy!(a => a.x)(arr); static assert(isForwardRange!(typeof(byX))); auto byX_subrange1 = byX.front[1].save; auto byX_subrange2 = byX.front[1].save; static assert(isForwardRange!(typeof(byX_subrange1))); static assert(isForwardRange!(typeof(byX_subrange2))); byX.popFront(); assert(byX_subrange1.equal([ Item(1,2), Item(1,3) ])); byX_subrange1.popFront(); assert(byX_subrange1.equal([ Item(1,3) ])); assert(byX_subrange2.equal([ Item(1,2), Item(1,3) ])); auto byY = chunkBy!(a => a.y)(arr); static assert(isForwardRange!(typeof(byY))); auto byY2 = byY.save; static assert(is(typeof(byY) == typeof(byY2))); byY.popFront(); assert(byY.front[0] == 3); assert(byY.front[1].equal([ Item(1,3), Item(2,3) ])); assert(byY2.front[0] == 2); assert(byY2.front[1].equal([ Item(1,2) ])); } // Test non-forward input ranges. { auto range = refInputRange([ Item(1,1), Item(1,2), Item(2,2) ]); auto byX = chunkBy!(a => a.x)(range); assert(byX.front[0] == 1); assert(byX.front[1].equal([ Item(1,1), Item(1,2) ])); byX.popFront(); assert(byX.front[0] == 2); assert(byX.front[1].equal([ Item(2,2) ])); byX.popFront(); assert(byX.empty); assert(range.empty); range = refInputRange([ Item(1,1), Item(1,2), Item(2,2) ]); auto byY = chunkBy!(a => a.y)(range); assert(byY.front[0] == 1); assert(byY.front[1].equal([ Item(1,1) ])); byY.popFront(); assert(byY.front[0] == 2); assert(byY.front[1].equal([ Item(1,2), Item(2,2) ])); byY.popFront(); assert(byY.empty); assert(range.empty); } } // Issue 13595 version(none) // This requires support for non-equivalence relations unittest { import std.algorithm.comparison : equal; auto r = [1, 2, 3, 4, 5, 6, 7, 8, 9].chunkBy!((x, y) => ((x*y) % 3) == 0); assert(r.equal!equal([ [1], [2, 3, 4], [5, 6, 7], [8, 9] ])); } // Issue 13805 unittest { [""].map!((s) => s).chunkBy!((x, y) => true); } // joiner /** Lazily joins a range of ranges with a separator. The separator itself is a range. If a separator is not provided, then the ranges are joined directly without anything in between them (often called $(D flatten) in other languages). Params: r = An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) of input ranges to be joined. sep = A $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) of element(s) to serve as separators in the joined range. Returns: A range of elements in the joined range. This will be a forward range if both outer and inner ranges of $(D RoR) are forward ranges; otherwise it will be only an input range. See_also: $(XREF range,chain), which chains a sequence of ranges with compatible elements into a single range. */ auto joiner(RoR, Separator)(RoR r, Separator sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!Separator && is(ElementType!Separator : ElementType!(ElementType!RoR))) { static struct Result { private RoR _items; private ElementType!RoR _current; private Separator _sep, _currentSep; // This is a mixin instead of a function for the following reason (as // explained by Kenji Hara): "This is necessary from 2.061. If a // struct has a nested struct member, it must be directly initialized // in its constructor to avoid leaving undefined state. If you change // setItem to a function, the initialization of _current field is // wrapped into private member function, then compiler could not detect // that is correctly initialized while constructing. To avoid the // compiler error check, string mixin is used." private enum setItem = q{ if (!_items.empty) { // If we're exporting .save, we must not consume any of the // subranges, since RoR.save does not guarantee that the states // of the subranges are also saved. static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) _current = _items.front.save; else _current = _items.front; } }; private void useSeparator() { // Separator must always come after an item. assert(_currentSep.empty && !_items.empty, "joiner: internal error"); _items.popFront(); // If there are no more items, we're done, since separators are not // terminators. if (_items.empty) return; if (_sep.empty) { // Advance to the next range in the // input while (_items.front.empty) { _items.popFront(); if (_items.empty) return; } mixin(setItem); } else { _currentSep = _sep.save; assert(!_currentSep.empty); } } private enum useItem = q{ // FIXME: this will crash if either _currentSep or _current are // class objects, because .init is null when the ctor invokes this // mixin. //assert(_currentSep.empty && _current.empty, // "joiner: internal error"); // Use the input if (_items.empty) return; mixin(setItem); if (_current.empty) { // No data in the current item - toggle to use the separator useSeparator(); } }; this(RoR items, Separator sep) { _items = items; _sep = sep; //mixin(useItem); // _current should be initialized in place if (_items.empty) _current = _current.init; // set invalid state else { // If we're exporting .save, we must not consume any of the // subranges, since RoR.save does not guarantee that the states // of the subranges are also saved. static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) _current = _items.front.save; else _current = _items.front; if (_current.empty) { // No data in the current item - toggle to use the separator useSeparator(); } } } @property auto empty() { return _items.empty; } @property ElementType!(ElementType!RoR) front() { if (!_currentSep.empty) return _currentSep.front; assert(!_current.empty); return _current.front; } void popFront() { assert(!_items.empty); // Using separator? if (!_currentSep.empty) { _currentSep.popFront(); if (!_currentSep.empty) return; mixin(useItem); } else { // we're using the range _current.popFront(); if (!_current.empty) return; useSeparator(); } } static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) { @property auto save() { Result copy = this; copy._items = _items.save; copy._current = _current.save; copy._sep = _sep.save; copy._currentSep = _currentSep.save; return copy; } } } return Result(r, sep); } /// @safe unittest { import std.algorithm.comparison : equal; import std.conv : text; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); static assert(isInputRange!(typeof(joiner([""], "")))); static assert(isForwardRange!(typeof(joiner([""], "")))); assert(equal(joiner([""], "xyz"), ""), text(joiner([""], "xyz"))); assert(equal(joiner(["", ""], "xyz"), "xyz"), text(joiner(["", ""], "xyz"))); assert(equal(joiner(["", "abc"], "xyz"), "xyzabc")); assert(equal(joiner(["abc", ""], "xyz"), "abcxyz")); assert(equal(joiner(["abc", "def"], "xyz"), "abcxyzdef")); assert(equal(joiner(["Mary", "has", "a", "little", "lamb"], "..."), "Mary...has...a...little...lamb")); assert(equal(joiner(["abc", "def"]), "abcdef")); } unittest { import std.algorithm.comparison : equal; import std.range.primitives; import std.range.interfaces; // joiner() should work for non-forward ranges too. auto r = inputRangeObject(["abc", "def"]); assert (equal(joiner(r, "xyz"), "abcxyzdef")); } unittest { import std.algorithm.comparison : equal; import std.range; // Related to issue 8061 auto r = joiner([ inputRangeObject("abc"), inputRangeObject("def"), ], "-*-"); assert(equal(r, "abc-*-def")); // Test case where separator is specified but is empty. auto s = joiner([ inputRangeObject("abc"), inputRangeObject("def"), ], ""); assert(equal(s, "abcdef")); // Test empty separator with some empty elements auto t = joiner([ inputRangeObject("abc"), inputRangeObject(""), inputRangeObject("def"), inputRangeObject(""), ], ""); assert(equal(t, "abcdef")); // Test empty elements with non-empty separator auto u = joiner([ inputRangeObject(""), inputRangeObject("abc"), inputRangeObject(""), inputRangeObject("def"), inputRangeObject(""), ], "+-"); assert(equal(u, "+-abc+-+-def+-")); // Issue 13441: only(x) as separator string[][] lines = [null]; lines .joiner(only("b")) .array(); } @safe unittest { import std.algorithm.comparison : equal; // Transience correctness test struct TransientRange { @safe: int[][] src; int[] buf; this(int[][] _src) { src = _src; buf.length = 100; } @property bool empty() { return src.empty; } @property int[] front() { assert(src.front.length <= buf.length); buf[0 .. src.front.length] = src.front[0..$]; return buf[0 .. src.front.length]; } void popFront() { src.popFront(); } } // Test embedded empty elements auto tr1 = TransientRange([[], [1,2,3], [], [4]]); assert(equal(joiner(tr1, [0]), [0,1,2,3,0,0,4])); // Test trailing empty elements auto tr2 = TransientRange([[], [1,2,3], []]); assert(equal(joiner(tr2, [0]), [0,1,2,3,0])); // Test no empty elements auto tr3 = TransientRange([[1,2], [3,4]]); assert(equal(joiner(tr3, [0,1]), [1,2,0,1,3,4])); // Test consecutive empty elements auto tr4 = TransientRange([[1,2], [], [], [], [3,4]]); assert(equal(joiner(tr4, [0,1]), [1,2,0,1,0,1,0,1,0,1,3,4])); // Test consecutive trailing empty elements auto tr5 = TransientRange([[1,2], [3,4], [], []]); assert(equal(joiner(tr5, [0,1]), [1,2,0,1,3,4,0,1,0,1])); } /// Ditto auto joiner(RoR)(RoR r) if (isInputRange!RoR && isInputRange!(ElementType!RoR)) { static struct Result { private: RoR _items; ElementType!RoR _current; enum prepare = q{ // Skip over empty subranges. if (_items.empty) return; while (_items.front.empty) { _items.popFront(); if (_items.empty) return; } // We cannot export .save method unless we ensure subranges are not // consumed when a .save'd copy of ourselves is iterated over. So // we need to .save each subrange we traverse. static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) _current = _items.front.save; else _current = _items.front; }; public: this(RoR r) { _items = r; //mixin(prepare); // _current should be initialized in place // Skip over empty subranges. while (!_items.empty && _items.front.empty) _items.popFront(); if (_items.empty) _current = _current.init; // set invalid state else { // We cannot export .save method unless we ensure subranges are not // consumed when a .save'd copy of ourselves is iterated over. So // we need to .save each subrange we traverse. static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) _current = _items.front.save; else _current = _items.front; } } static if (isInfinite!RoR) { enum bool empty = false; } else { @property auto empty() { return _items.empty; } } @property auto ref front() { assert(!empty); return _current.front; } void popFront() { assert(!_current.empty); _current.popFront(); if (_current.empty) { assert(!_items.empty); _items.popFront(); mixin(prepare); } } static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) { @property auto save() { Result copy = this; copy._items = _items.save; copy._current = _current.save; return copy; } } } return Result(r); } unittest { import std.algorithm.comparison : equal; import std.range.interfaces; import std.range : repeat; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); static assert(isInputRange!(typeof(joiner([""])))); static assert(isForwardRange!(typeof(joiner([""])))); assert(equal(joiner([""]), "")); assert(equal(joiner(["", ""]), "")); assert(equal(joiner(["", "abc"]), "abc")); assert(equal(joiner(["abc", ""]), "abc")); assert(equal(joiner(["abc", "def"]), "abcdef")); assert(equal(joiner(["Mary", "has", "a", "little", "lamb"]), "Maryhasalittlelamb")); assert(equal(joiner(std.range.repeat("abc", 3)), "abcabcabc")); // joiner allows in-place mutation! auto a = [ [1, 2, 3], [42, 43] ]; auto j = joiner(a); j.front = 44; assert(a == [ [44, 2, 3], [42, 43] ]); // bugzilla 8240 assert(equal(joiner([inputRangeObject("")]), "")); // issue 8792 auto b = [[1], [2], [3]]; auto jb = joiner(b); auto js = jb.save; assert(equal(jb, js)); auto js2 = jb.save; jb.popFront(); assert(!equal(jb, js)); assert(equal(js2, js)); js.popFront(); assert(equal(jb, js)); assert(!equal(js2, js)); } @safe unittest { import std.algorithm.comparison : equal; struct TransientRange { @safe: int[] _buf; int[][] _values; this(int[][] values) { _values = values; _buf = new int[128]; } @property bool empty() { return _values.length == 0; } @property auto front() { foreach (i; 0 .. _values.front.length) { _buf[i] = _values[0][i]; } return _buf[0 .. _values.front.length]; } void popFront() { _values = _values[1 .. $]; } } auto rr = TransientRange([[1,2], [3,4,5], [], [6,7]]); // Can't use array() or equal() directly because they fail with transient // .front. int[] result; foreach (c; rr.joiner()) { result ~= c; } assert(equal(result, [1,2,3,4,5,6,7])); } @safe unittest { import std.algorithm.internal : algoFormat; import std.algorithm.comparison : equal; struct TransientRange { @safe: dchar[] _buf; dstring[] _values; this(dstring[] values) { _buf.length = 128; _values = values; } @property bool empty() { return _values.length == 0; } @property auto front() { foreach (i; 0 .. _values.front.length) { _buf[i] = _values[0][i]; } return _buf[0 .. _values.front.length]; } void popFront() { _values = _values[1 .. $]; } } auto rr = TransientRange(["abc"d, "12"d, "def"d, "34"d]); // Can't use array() or equal() directly because they fail with transient // .front. dchar[] result; foreach (c; rr.joiner()) { result ~= c; } import std.conv : to; assert(equal(result, "abc12def34"d), //Convert to string for assert's message to!string("Unexpected result: '%s'"d.algoFormat(result))); } // Issue 8061 unittest { import std.range.interfaces; import std.conv : to; auto r = joiner([inputRangeObject("ab"), inputRangeObject("cd")]); assert(isForwardRange!(typeof(r))); auto str = to!string(r); assert(str == "abcd"); } /++ Implements the homonym function (also known as $(D accumulate), $(D compress), $(D inject), or $(D foldl)) present in various programming languages of functional flavor. There is also $(LREF fold) which does the same thing but with the opposite parameter order. The call $(D reduce!(fun)(seed, range)) first assigns $(D seed) to an internal variable $(D result), also called the accumulator. Then, for each element $(D x) in $(D range), $(D result = fun(result, x)) gets evaluated. Finally, $(D result) is returned. The one-argument version $(D reduce!(fun)(range)) works similarly, but it uses the first element of the range as the seed (the range must be non-empty). Returns: the accumulated $(D result) See_Also: $(WEB en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function)) $(LREF fold) is functionally equivalent to $(LREF reduce) with the argument order reversed, and without the need to use $(LREF tuple) for multiple seeds. This makes it easier to use in UFCS chains. $(LREF sum) is similar to $(D reduce!((a, b) => a + b)) that offers precise summing of floating point numbers. +/ template reduce(fun...) if (fun.length >= 1) { import std.meta : staticMap; alias binfuns = staticMap!(binaryFun, fun); static if (fun.length > 1) import std.typecons : tuple, isTuple; /++ No-seed version. The first element of $(D r) is used as the seed's value. For each function $(D f) in $(D fun), the corresponding seed type $(D S) is $(D Unqual!(typeof(f(e, e)))), where $(D e) is an element of $(D r): $(D ElementType!R) for ranges, and $(D ForeachType!R) otherwise. Once S has been determined, then $(D S s = e;) and $(D s = f(s, e);) must both be legal. If $(D r) is empty, an $(D Exception) is thrown. Params: fun = one or more functions r = an iterable value as defined by $(D isIterable) Returns: the final result of the accumulator applied to the iterable +/ auto reduce(R)(R r) if (isIterable!R) { import std.exception : enforce; alias E = Select!(isInputRange!R, ElementType!R, ForeachType!R); alias Args = staticMap!(ReduceSeedType!E, binfuns); static if (isInputRange!R) { enforce(!r.empty, "Cannot reduce an empty input range w/o an explicit seed value."); Args result = r.front; r.popFront(); return reduceImpl!false(r, result); } else { auto result = Args.init; return reduceImpl!true(r, result); } } /++ Seed version. The seed should be a single value if $(D fun) is a single function. If $(D fun) is multiple functions, then $(D seed) should be a $(XREF typecons,Tuple), with one field per function in $(D f). For convenience, if the seed is const, or has qualified fields, then $(D reduce) will operate on an unqualified copy. If this happens then the returned type will not perfectly match $(D S). Use $(D fold) instead of $(D reduce) to use the seed version in a UFCS chain. Params: fun = one or more functions seed = the initial value of the accumulator r = an iterable value as defined by $(D isIterable) Returns: the final result of the accumulator applied to the iterable +/ auto reduce(S, R)(S seed, R r) if (isIterable!R) { static if (fun.length == 1) return reducePreImpl(r, seed); else { import std.algorithm.internal : algoFormat; static assert(isTuple!S, algoFormat("Seed %s should be a Tuple", S.stringof)); return reducePreImpl(r, seed.expand); } } private auto reducePreImpl(R, Args...)(R r, ref Args args) { alias Result = staticMap!(Unqual, Args); static if (is(Result == Args)) alias result = args; else Result result = args; return reduceImpl!false(r, result); } private auto reduceImpl(bool mustInitialize, R, Args...)(R r, ref Args args) if (isIterable!R) { import std.algorithm.internal : algoFormat; static assert(Args.length == fun.length, algoFormat("Seed %s does not have the correct amount of fields (should be %s)", Args.stringof, fun.length)); alias E = Select!(isInputRange!R, ElementType!R, ForeachType!R); static if (mustInitialize) bool initialized = false; foreach (/+auto ref+/ E e; r) // @@@4707@@@ { foreach (i, f; binfuns) { static assert(!is(typeof(f(args[i], e))) || is(typeof(args[i] = f(args[i], e))), algoFormat("Incompatible function/seed/element: %s/%s/%s", fullyQualifiedName!f, Args[i].stringof, E.stringof)); } static if (mustInitialize) if (initialized == false) { import std.conv : emplaceRef; foreach (i, f; binfuns) emplaceRef!(Args[i])(args[i], e); initialized = true; continue; } foreach (i, f; binfuns) args[i] = f(args[i], e); } static if (mustInitialize) if (!initialized) throw new Exception("Cannot reduce an empty iterable w/o an explicit seed value."); static if (Args.length == 1) return args[0]; else return tuple(args); } } /** Many aggregate range operations turn out to be solved with $(D reduce) quickly and easily. The example below illustrates $(D reduce)'s remarkable power and flexibility. */ @safe unittest { import std.algorithm.comparison : max, min; import std.math : approxEqual; import std.range; int[] arr = [ 1, 2, 3, 4, 5 ]; // Sum all elements auto sum = reduce!((a,b) => a + b)(0, arr); assert(sum == 15); // Sum again, using a string predicate with "a" and "b" sum = reduce!"a + b"(0, arr); assert(sum == 15); // Compute the maximum of all elements auto largest = reduce!(max)(arr); assert(largest == 5); // Max again, but with Uniform Function Call Syntax (UFCS) largest = arr.reduce!(max); assert(largest == 5); // Compute the number of odd elements auto odds = reduce!((a,b) => a + (b & 1))(0, arr); assert(odds == 3); // Compute the sum of squares auto ssquares = reduce!((a,b) => a + b * b)(0, arr); assert(ssquares == 55); // Chain multiple ranges into seed int[] a = [ 3, 4 ]; int[] b = [ 100 ]; auto r = reduce!("a + b")(chain(a, b)); assert(r == 107); // Mixing convertible types is fair game, too double[] c = [ 2.5, 3.0 ]; auto r1 = reduce!("a + b")(chain(a, b, c)); assert(approxEqual(r1, 112.5)); // To minimize nesting of parentheses, Uniform Function Call Syntax can be used auto r2 = chain(a, b, c).reduce!("a + b"); assert(approxEqual(r2, 112.5)); } /** Sometimes it is very useful to compute multiple aggregates in one pass. One advantage is that the computation is faster because the looping overhead is shared. That's why $(D reduce) accepts multiple functions. If two or more functions are passed, $(D reduce) returns a $(XREF typecons, Tuple) object with one member per passed-in function. The number of seeds must be correspondingly increased. */ @safe unittest { import std.algorithm.comparison : max, min; import std.math : approxEqual, sqrt; import std.typecons : tuple, Tuple; double[] a = [ 3.0, 4, 7, 11, 3, 2, 5 ]; // Compute minimum and maximum in one pass auto r = reduce!(min, max)(a); // The type of r is Tuple!(int, int) assert(approxEqual(r[0], 2)); // minimum assert(approxEqual(r[1], 11)); // maximum // Compute sum and sum of squares in one pass r = reduce!("a + b", "a + b * b")(tuple(0.0, 0.0), a); assert(approxEqual(r[0], 35)); // sum assert(approxEqual(r[1], 233)); // sum of squares // Compute average and standard deviation from the above auto avg = r[0] / a.length; auto stdev = sqrt(r[1] / a.length - avg * avg); } unittest { import std.algorithm.comparison : max, min; import std.exception : assertThrown; import std.range; import std.typecons : tuple, Tuple; double[] a = [ 3, 4 ]; auto r = reduce!("a + b")(0.0, a); assert(r == 7); r = reduce!("a + b")(a); assert(r == 7); r = reduce!(min)(a); assert(r == 3); double[] b = [ 100 ]; auto r1 = reduce!("a + b")(chain(a, b)); assert(r1 == 107); // two funs auto r2 = reduce!("a + b", "a - b")(tuple(0.0, 0.0), a); assert(r2[0] == 7 && r2[1] == -7); auto r3 = reduce!("a + b", "a - b")(a); assert(r3[0] == 7 && r3[1] == -1); a = [ 1, 2, 3, 4, 5 ]; // Stringize with commas string rep = reduce!("a ~ `, ` ~ to!(string)(b)")("", a); assert(rep[2 .. $] == "1, 2, 3, 4, 5", "["~rep[2 .. $]~"]"); // Test the opApply case. static struct OpApply { bool actEmpty; int opApply(int delegate(ref int) dg) { int res; if (actEmpty) return res; foreach (i; 0..100) { res = dg(i); if (res) break; } return res; } } OpApply oa; auto hundredSum = reduce!"a + b"(iota(100)); assert(reduce!"a + b"(5, oa) == hundredSum + 5); assert(reduce!"a + b"(oa) == hundredSum); assert(reduce!("a + b", max)(oa) == tuple(hundredSum, 99)); assert(reduce!("a + b", max)(tuple(5, 0), oa) == tuple(hundredSum + 5, 99)); // Test for throwing on empty range plus no seed. assertThrown(reduce!"a + b"([1, 2][0..0])); oa.actEmpty = true; assertThrown(reduce!"a + b"(oa)); } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); const float a = 0.0; const float[] b = [ 1.2, 3, 3.3 ]; float[] c = [ 1.2, 3, 3.3 ]; auto r = reduce!"a + b"(a, b); r = reduce!"a + b"(a, c); } @safe unittest { // Issue #10408 - Two-function reduce of a const array. import std.algorithm.comparison : max, min; import std.typecons : tuple, Tuple; const numbers = [10, 30, 20]; immutable m = reduce!(min)(numbers); assert(m == 10); immutable minmax = reduce!(min, max)(numbers); assert(minmax == tuple(10, 30)); } @safe unittest { //10709 import std.typecons : tuple, Tuple; enum foo = "a + 0.5 * b"; auto r = [0, 1, 2, 3]; auto r1 = reduce!foo(r); auto r2 = reduce!(foo, foo)(r); assert(r1 == 3); assert(r2 == tuple(3, 3)); } unittest { int i = 0; static struct OpApply { int opApply(int delegate(ref int) dg) { int[] a = [1, 2, 3]; int res = 0; foreach (ref e; a) { res = dg(e); if (res) break; } return res; } } //test CTFE and functions with context int fun(int a, int b){return a + b + 1;} auto foo() { import std.algorithm.comparison : max; import std.typecons : tuple, Tuple; auto a = reduce!(fun)([1, 2, 3]); auto b = reduce!(fun, fun)([1, 2, 3]); auto c = reduce!(fun)(0, [1, 2, 3]); auto d = reduce!(fun, fun)(tuple(0, 0), [1, 2, 3]); auto e = reduce!(fun)(0, OpApply()); auto f = reduce!(fun, fun)(tuple(0, 0), OpApply()); return max(a, b.expand, c, d.expand); } auto a = foo(); enum b = foo(); } @safe unittest { import std.algorithm.comparison : max, min; import std.typecons : tuple, Tuple; //http://forum.dlang.org/post/oghtttkopzjshsuflelk@forum.dlang.org //Seed is tuple of const. static auto minmaxElement(alias F = min, alias G = max, R)(in R range) @safe pure nothrow if (isInputRange!R) { return reduce!(F, G)(tuple(ElementType!R.max, ElementType!R.min), range); } assert(minmaxElement([1, 2, 3])== tuple(1, 3)); } @safe unittest //12569 { import std.algorithm.comparison : max, min; import std.typecons: tuple; dchar c = 'a'; reduce!(min, max)(tuple(c, c), "hello"); // OK static assert(!is(typeof(reduce!(min, max)(tuple(c), "hello")))); static assert(!is(typeof(reduce!(min, max)(tuple(c, c, c), "hello")))); //"Seed dchar should be a Tuple" static assert(!is(typeof(reduce!(min, max)(c, "hello")))); //"Seed (dchar) does not have the correct amount of fields (should be 2)" static assert(!is(typeof(reduce!(min, max)(tuple(c), "hello")))); //"Seed (dchar, dchar, dchar) does not have the correct amount of fields (should be 2)" static assert(!is(typeof(reduce!(min, max)(tuple(c, c, c), "hello")))); //"Incompatable function/seed/element: all(alias pred = "a")/int/dchar" static assert(!is(typeof(reduce!all(1, "hello")))); static assert(!is(typeof(reduce!(all, all)(tuple(1, 1), "hello")))); } @safe unittest //13304 { int[] data; static assert(is(typeof(reduce!((a, b)=>a+b)(data)))); } //Helper for Reduce private template ReduceSeedType(E) { static template ReduceSeedType(alias fun) { import std.algorithm.internal : algoFormat; alias ReduceSeedType = Unqual!(typeof(fun(lvalueOf!E, lvalueOf!E))); //Check the Seed type is useable. ReduceSeedType s = ReduceSeedType.init; static assert(is(typeof({ReduceSeedType s = lvalueOf!E;})) && is(typeof(lvalueOf!ReduceSeedType = fun(lvalueOf!ReduceSeedType, lvalueOf!E))), algoFormat("Unable to deduce an acceptable seed type for %s with element type %s.", fullyQualifiedName!fun, E.stringof)); } } /++ Implements the homonym function (also known as $(D accumulate), $(D compress), $(D inject), or $(D foldl)) present in various programming languages of functional flavor. The call $(D fold!(fun)(range, seed)) first assigns $(D seed) to an internal variable $(D result), also called the accumulator. Then, for each element $(D x) in $(D range), $(D result = fun(result, x)) gets evaluated. Finally, $(D result) is returned. The one-argument version $(D fold!(fun)(range)) works similarly, but it uses the first element of the range as the seed (the range must be non-empty). Returns: the accumulated $(D result) See_Also: $(WEB en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function)) $(LREF sum) is similar to $(D fold!((a, b) => a + b)) that offers precise summing of floating point numbers. This is functionally equivalent to $(LREF reduce) with the argument order reversed, and without the need to use $(LREF tuple) for multiple seeds. +/ template fold(fun...) if (fun.length >= 1) { auto fold(R, S...)(R r, S seed) { static if (S.length < 2) { return reduce!fun(seed, r); } else { import std.typecons: tuple; return reduce!fun(tuple(seed), r); } } } /// @safe pure unittest { immutable arr = [1, 2, 3, 4, 5]; // Sum all elements assert(arr.fold!((a, b) => a + b) == 15); // Sum all elements with explicit seed assert(arr.fold!((a, b) => a + b)(6) == 21); import std.algorithm.comparison: min, max; import std.typecons: tuple; // Compute minimum and maximum at the same time assert(arr.fold!(min, max) == tuple(1, 5)); // Compute minimum and maximum at the same time with seeds assert(arr.fold!(min, max)(0, 7) == tuple(0, 7)); // Can be used in a UFCS chain assert(arr.map!(a => a + 1).fold!((a, b) => a + b) == 20); } @safe @nogc pure nothrow unittest { int[1] arr; static assert(!is(typeof(arr.fold!()))); static assert(!is(typeof(arr.fold!(a => a)))); static assert(is(typeof(arr.fold!((a, b) => a)))); static assert(is(typeof(arr.fold!((a, b) => a)(1)))); } // splitter /** Lazily splits a range using an element as a separator. This can be used with any narrow string type or sliceable range type, but is most popular with string types. Two adjacent separators are considered to surround an empty element in the split range. Use $(D filter!(a => !a.empty)) on the result to compress empty elements. The predicate is passed to $(XREF functional,binaryFun), and can either accept a string, or any callable that can be executed via $(D pred(element, s)). If the empty range is given, the result is a range with one empty element. If a range with one separator is given, the result is a range with two empty elements. If splitting a string on whitespace and token compression is desired, consider using $(D splitter) without specifying a separator (see fourth overload below). Params: pred = The predicate for comparing each element with the separator, defaulting to $(D "a == b"). r = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) to be split. Must support slicing and $(D .length). s = The element to be treated as the separator between range segments to be split. Constraints: The predicate $(D pred) needs to accept an element of $(D r) and the separator $(D s). Returns: An input range of the subranges of elements between separators. If $(D r) is a forward range or bidirectional range, the returned range will be likewise. See_Also: $(XREF regex, _splitter) for a version that splits using a regular expression defined separator. */ auto splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s) if (is(typeof(binaryFun!pred(r.front, s)) : bool) && ((hasSlicing!Range && hasLength!Range) || isNarrowString!Range)) { import std.algorithm.searching : find; import std.conv : unsigned; static struct Result { private: Range _input; Separator _separator; // Do we need hasLength!Range? popFront uses _input.length... alias IndexType = typeof(unsigned(_input.length)); enum IndexType _unComputed = IndexType.max - 1, _atEnd = IndexType.max; IndexType _frontLength = _unComputed; IndexType _backLength = _unComputed; static if (isNarrowString!Range) { size_t _separatorLength; } else { enum _separatorLength = 1; } static if (isBidirectionalRange!Range) { static IndexType lastIndexOf(Range haystack, Separator needle) { import std.range : retro; auto r = haystack.retro().find!pred(needle); return r.retro().length - 1; } } public: this(Range input, Separator separator) { _input = input; _separator = separator; static if (isNarrowString!Range) { import std.utf : codeLength; _separatorLength = codeLength!(ElementEncodingType!Range)(separator); } if (_input.empty) _frontLength = _atEnd; } static if (isInfinite!Range) { enum bool empty = false; } else { @property bool empty() { return _frontLength == _atEnd; } } @property Range front() { assert(!empty); if (_frontLength == _unComputed) { auto r = _input.find!pred(_separator); _frontLength = _input.length - r.length; } return _input[0 .. _frontLength]; } void popFront() { assert(!empty); if (_frontLength == _unComputed) { front; } assert(_frontLength <= _input.length); if (_frontLength == _input.length) { // no more input and need to fetch => done _frontLength = _atEnd; // Probably don't need this, but just for consistency: _backLength = _atEnd; } else { _input = _input[_frontLength + _separatorLength .. _input.length]; _frontLength = _unComputed; } } static if (isForwardRange!Range) { @property typeof(this) save() { auto ret = this; ret._input = _input.save; return ret; } } static if (isBidirectionalRange!Range) { @property Range back() { assert(!empty); if (_backLength == _unComputed) { immutable lastIndex = lastIndexOf(_input, _separator); if (lastIndex == -1) { _backLength = _input.length; } else { _backLength = _input.length - lastIndex - 1; } } return _input[_input.length - _backLength .. _input.length]; } void popBack() { assert(!empty); if (_backLength == _unComputed) { // evaluate back to make sure it's computed back; } assert(_backLength <= _input.length); if (_backLength == _input.length) { // no more input and need to fetch => done _frontLength = _atEnd; _backLength = _atEnd; } else { _input = _input[0 .. _input.length - _backLength - _separatorLength]; _backLength = _unComputed; } } } } return Result(r, s); } /// @safe unittest { import std.algorithm.comparison : equal; assert(equal(splitter("hello world", ' '), [ "hello", "", "world" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [], [3], [4, 5], [] ]; assert(equal(splitter(a, 0), w)); a = [ 0 ]; assert(equal(splitter(a, 0), [ (int[]).init, (int[]).init ])); a = [ 0, 1 ]; assert(equal(splitter(a, 0), [ [], [1] ])); w = [ [0], [1], [2] ]; assert(equal(splitter!"a.front == b"(w, 1), [ [[0]], [[2]] ])); } @safe unittest { import std.internal.test.dummyrange; import std.algorithm; import std.array : array; import std.range : retro; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); assert(equal(splitter("hello world", ' '), [ "hello", "", "world" ])); assert(equal(splitter("žlutoučkýřkůň", 'ř'), [ "žlutoučký", "kůň" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [], [3], [4, 5], [] ]; static assert(isForwardRange!(typeof(splitter(a, 0)))); // foreach (x; splitter(a, 0)) { // writeln("[", x, "]"); // } assert(equal(splitter(a, 0), w)); a = null; assert(equal(splitter(a, 0), (int[][]).init)); a = [ 0 ]; assert(equal(splitter(a, 0), [ (int[]).init, (int[]).init ][])); a = [ 0, 1 ]; assert(equal(splitter(a, 0), [ [], [1] ][])); // Thoroughly exercise the bidirectional stuff. auto str = "abc abcd abcde ab abcdefg abcdefghij ab ac ar an at ada"; assert(equal( retro(splitter(str, 'a')), retro(array(splitter(str, 'a'))) )); // Test interleaving front and back. auto split = splitter(str, 'a'); assert(split.front == ""); assert(split.back == ""); split.popBack(); assert(split.back == "d"); split.popFront(); assert(split.front == "bc "); assert(split.back == "d"); split.popFront(); split.popBack(); assert(split.back == "t "); split.popBack(); split.popBack(); split.popFront(); split.popFront(); assert(split.front == "b "); assert(split.back == "r "); foreach (DummyType; AllDummyRanges) { // Bug 4408 static if (isRandomAccessRange!DummyType) { static assert(isBidirectionalRange!DummyType); DummyType d; auto s = splitter(d, 5); assert(equal(s.front, [1,2,3,4])); assert(equal(s.back, [6,7,8,9,10])); auto s2 = splitter(d, [4, 5]); assert(equal(s2.front, [1,2,3])); } } } @safe unittest { import std.algorithm; import std.range; auto L = retro(iota(1L, 10L)); auto s = splitter(L, 5L); assert(equal(s.front, [9L, 8L, 7L, 6L])); s.popFront(); assert(equal(s.front, [4L, 3L, 2L, 1L])); s.popFront(); assert(s.empty); } /** Similar to the previous overload of $(D splitter), except this one uses another range as a separator. This can be used with any narrow string type or sliceable range type, but is most popular with string types. The predicate is passed to $(XREF functional,binaryFun), and can either accept a string, or any callable that can be executed via $(D pred(r.front, s.front)). Two adjacent separators are considered to surround an empty element in the split range. Use $(D filter!(a => !a.empty)) on the result to compress empty elements. Params: pred = The predicate for comparing each element with the separator, defaulting to $(D "a == b"). r = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) to be split. s = The $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) to be treated as the separator between segments of $(D r) to be split. Constraints: The predicate $(D pred) needs to accept an element of $(D r) and an element of $(D s). Returns: An input range of the subranges of elements between separators. If $(D r) is a forward range or bidirectional range, the returned range will be likewise. See_Also: $(XREF regex, _splitter) for a version that splits using a regular expression defined separator. */ auto splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s) if (is(typeof(binaryFun!pred(r.front, s.front)) : bool) && (hasSlicing!Range || isNarrowString!Range) && isForwardRange!Separator && (hasLength!Separator || isNarrowString!Separator)) { import std.algorithm.searching : find; import std.conv : unsigned; static struct Result { private: Range _input; Separator _separator; alias RIndexType = typeof(unsigned(_input.length)); // _frontLength == size_t.max means empty RIndexType _frontLength = RIndexType.max; static if (isBidirectionalRange!Range) RIndexType _backLength = RIndexType.max; @property auto separatorLength() { return _separator.length; } void ensureFrontLength() { if (_frontLength != _frontLength.max) return; assert(!_input.empty); // compute front length _frontLength = (_separator.empty) ? 1 : _input.length - find!pred(_input, _separator).length; static if (isBidirectionalRange!Range) if (_frontLength == _input.length) _backLength = _frontLength; } void ensureBackLength() { static if (isBidirectionalRange!Range) if (_backLength != _backLength.max) return; assert(!_input.empty); // compute back length static if (isBidirectionalRange!Range && isBidirectionalRange!Separator) { import std.range : retro; _backLength = _input.length - find!pred(retro(_input), retro(_separator)).source.length; } } public: this(Range input, Separator separator) { _input = input; _separator = separator; } @property Range front() { assert(!empty); ensureFrontLength(); return _input[0 .. _frontLength]; } static if (isInfinite!Range) { enum bool empty = false; // Propagate infiniteness } else { @property bool empty() { return _frontLength == RIndexType.max && _input.empty; } } void popFront() { assert(!empty); ensureFrontLength(); if (_frontLength == _input.length) { // done, there's no separator in sight _input = _input[_frontLength .. _frontLength]; _frontLength = _frontLength.max; static if (isBidirectionalRange!Range) _backLength = _backLength.max; return; } if (_frontLength + separatorLength == _input.length) { // Special case: popping the first-to-last item; there is // an empty item right after this. _input = _input[_input.length .. _input.length]; _frontLength = 0; static if (isBidirectionalRange!Range) _backLength = 0; return; } // Normal case, pop one item and the separator, get ready for // reading the next item _input = _input[_frontLength + separatorLength .. _input.length]; // mark _frontLength as uninitialized _frontLength = _frontLength.max; } static if (isForwardRange!Range) { @property typeof(this) save() { auto ret = this; ret._input = _input.save; return ret; } } } return Result(r, s); } /// @safe unittest { import std.algorithm.comparison : equal; assert(equal(splitter("hello world", " "), [ "hello", "world" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ]; assert(equal(splitter(a, [0, 0]), w)); a = [ 0, 0 ]; assert(equal(splitter(a, [0, 0]), [ (int[]).init, (int[]).init ])); a = [ 0, 0, 1 ]; assert(equal(splitter(a, [0, 0]), [ [], [1] ])); } @safe unittest { import std.algorithm.comparison : equal; import std.typecons : Tuple; alias C = Tuple!(int, "x", int, "y"); auto a = [C(1,0), C(2,0), C(3,1), C(4,0)]; assert(equal(splitter!"a.x == b"(a, [2, 3]), [ [C(1,0)], [C(4,0)] ])); } @safe unittest { import std.algorithm.comparison : equal; import std.conv : text; import std.array : split; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto s = ",abc, de, fg,hi,"; auto sp0 = splitter(s, ','); // //foreach (e; sp0) writeln("[", e, "]"); assert(equal(sp0, ["", "abc", " de", " fg", "hi", ""][])); auto s1 = ", abc, de, fg, hi, "; auto sp1 = splitter(s1, ", "); //foreach (e; sp1) writeln("[", e, "]"); assert(equal(sp1, ["", "abc", "de", " fg", "hi", ""][])); static assert(isForwardRange!(typeof(sp1))); int[] a = [ 1, 2, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [3], [4, 5], [] ]; uint i; foreach (e; splitter(a, 0)) { assert(i < w.length); assert(e == w[i++]); } assert(i == w.length); // // Now go back // auto s2 = splitter(a, 0); // foreach (e; retro(s2)) // { // assert(i > 0); // assert(equal(e, w[--i]), text(e)); // } // assert(i == 0); wstring names = ",peter,paul,jerry,"; auto words = split(names, ","); assert(walkLength(words) == 5, text(walkLength(words))); } @safe unittest { int[][] a = [ [1], [2], [0], [3], [0], [4], [5], [0] ]; int[][][] w = [ [[1], [2]], [[3]], [[4], [5]], [] ]; uint i; foreach (e; splitter!"a.front == 0"(a, 0)) { assert(i < w.length); assert(e == w[i++]); } assert(i == w.length); } @safe unittest { import std.algorithm.comparison : equal; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto s6 = ","; auto sp6 = splitter(s6, ','); foreach (e; sp6) { //writeln("{", e, "}"); } assert(equal(sp6, ["", ""][])); } @safe unittest { import std.algorithm.comparison : equal; // Issue 10773 auto s = splitter("abc", ""); assert(s.equal(["a", "b", "c"])); } @safe unittest { import std.algorithm.comparison : equal; // Test by-reference separator class RefSep { @safe: string _impl; this(string s) { _impl = s; } @property empty() { return _impl.empty; } @property auto front() { return _impl.front; } void popFront() { _impl = _impl[1..$]; } @property RefSep save() { return new RefSep(_impl); } @property auto length() { return _impl.length; } } auto sep = new RefSep("->"); auto data = "i->am->pointing"; auto words = splitter(data, sep); assert(words.equal([ "i", "am", "pointing" ])); } /** Similar to the previous overload of $(D splitter), except this one does not use a separator. Instead, the predicate is an unary function on the input range's element type. The $(D isTerminator) predicate is passed to $(XREF functional,unaryFun) and can either accept a string, or any callable that can be executed via $(D pred(element, s)). Two adjacent separators are considered to surround an empty element in the split range. Use $(D filter!(a => !a.empty)) on the result to compress empty elements. Params: isTerminator = The predicate for deciding where to split the range. input = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) to be split. Constraints: The predicate $(D isTerminator) needs to accept an element of $(D input). Returns: An input range of the subranges of elements between separators. If $(D input) is a forward range or bidirectional range, the returned range will be likewise. See_Also: $(XREF regex, _splitter) for a version that splits using a regular expression defined separator. */ auto splitter(alias isTerminator, Range)(Range input) if (isForwardRange!Range && is(typeof(unaryFun!isTerminator(input.front)))) { return SplitterResult!(unaryFun!isTerminator, Range)(input); } /// @safe unittest { import std.algorithm.comparison : equal; assert(equal(splitter!(a => a == ' ')("hello world"), [ "hello", "", "world" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [], [3], [4, 5], [] ]; assert(equal(splitter!(a => a == 0)(a), w)); a = [ 0 ]; assert(equal(splitter!(a => a == 0)(a), [ (int[]).init, (int[]).init ])); a = [ 0, 1 ]; assert(equal(splitter!(a => a == 0)(a), [ [], [1] ])); w = [ [0], [1], [2] ]; assert(equal(splitter!(a => a.front == 1)(w), [ [[0]], [[2]] ])); } private struct SplitterResult(alias isTerminator, Range) { import std.algorithm.searching : find; enum fullSlicing = (hasLength!Range && hasSlicing!Range) || isSomeString!Range; private Range _input; private size_t _end = 0; static if(!fullSlicing) private Range _next; private void findTerminator() { static if (fullSlicing) { auto r = find!isTerminator(_input.save); _end = _input.length - r.length; } else for ( _end = 0; !_next.empty ; _next.popFront) { if (isTerminator(_next.front)) break; ++_end; } } this(Range input) { _input = input; static if(!fullSlicing) _next = _input.save; if (!_input.empty) findTerminator(); else _end = size_t.max; } static if (isInfinite!Range) { enum bool empty = false; // Propagate infiniteness. } else { @property bool empty() { return _end == size_t.max; } } @property auto front() { version(assert) { import core.exception : RangeError; if (empty) throw new RangeError(); } static if (fullSlicing) return _input[0 .. _end]; else { import std.range : takeExactly; return _input.takeExactly(_end); } } void popFront() { version(assert) { import core.exception : RangeError; if (empty) throw new RangeError(); } static if (fullSlicing) { _input = _input[_end .. _input.length]; if (_input.empty) { _end = size_t.max; return; } _input.popFront(); } else { if (_next.empty) { _input = _next; _end = size_t.max; return; } _next.popFront(); _input = _next.save; } findTerminator(); } @property typeof(this) save() { auto ret = this; ret._input = _input.save; static if (!fullSlicing) ret._next = _next.save; return ret; } } @safe unittest { import std.algorithm.comparison : equal; import std.range : iota; auto L = iota(1L, 10L); auto s = splitter(L, [5L, 6L]); assert(equal(s.front, [1L, 2L, 3L, 4L])); s.popFront(); assert(equal(s.front, [7L, 8L, 9L])); s.popFront(); assert(s.empty); } @safe unittest { import std.algorithm.internal : algoFormat; import std.algorithm.comparison : equal; import std.internal.test.dummyrange; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); void compare(string sentence, string[] witness) { auto r = splitter!"a == ' '"(sentence); assert(equal(r.save, witness), algoFormat("got: %(%s, %) expected: %(%s, %)", r, witness)); } compare(" Mary has a little lamb. ", ["", "Mary", "", "has", "a", "little", "lamb.", "", "", ""]); compare("Mary has a little lamb. ", ["Mary", "", "has", "a", "little", "lamb.", "", "", ""]); compare("Mary has a little lamb.", ["Mary", "", "has", "a", "little", "lamb."]); compare("", (string[]).init); compare(" ", ["", ""]); static assert(isForwardRange!(typeof(splitter!"a == ' '"("ABC")))); foreach (DummyType; AllDummyRanges) { static if (isRandomAccessRange!DummyType) { auto rangeSplit = splitter!"a == 5"(DummyType.init); assert(equal(rangeSplit.front, [1,2,3,4])); rangeSplit.popFront(); assert(equal(rangeSplit.front, [6,7,8,9,10])); } } } @safe unittest { import std.algorithm.internal : algoFormat; import std.algorithm.comparison : equal; import std.range; struct Entry { int low; int high; int[][] result; } Entry[] entries = [ Entry(0, 0, []), Entry(0, 1, [[0]]), Entry(1, 2, [[], []]), Entry(2, 7, [[2], [4], [6]]), Entry(1, 8, [[], [2], [4], [6], []]), ]; foreach ( entry ; entries ) { auto a = iota(entry.low, entry.high).filter!"true"(); auto b = splitter!"a%2"(a); assert(equal!equal(b.save, entry.result), algoFormat("got: %(%s, %) expected: %(%s, %)", b, entry.result)); } } @safe unittest { import std.algorithm.comparison : equal; import std.uni : isWhite; //@@@6791@@@ assert(equal(splitter("là dove terminava quella valle"), ["là", "dove", "terminava", "quella", "valle"])); assert(equal(splitter!(std.uni.isWhite)("là dove terminava quella valle"), ["là", "dove", "terminava", "quella", "valle"])); assert(equal(splitter!"a=='本'"("日本語"), ["日", "語"])); } /++ Lazily splits the string $(D s) into words, using whitespace as the delimiter. This function is string specific and, contrary to $(D splitter!(std.uni.isWhite)), runs of whitespace will be merged together (no empty tokens will be produced). Params: s = The string to be split. Returns: An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) of slices of the original string split by whitespace. +/ auto splitter(C)(C[] s) if (isSomeChar!C) { import std.algorithm.searching : find; static struct Result { private: import core.exception; C[] _s; size_t _frontLength; void getFirst() pure @safe { import std.uni : isWhite; auto r = find!(isWhite)(_s); _frontLength = _s.length - r.length; } public: this(C[] s) pure @safe { import std.string : strip; _s = s.strip(); getFirst(); } @property C[] front() pure @safe { version(assert) if (empty) throw new RangeError(); return _s[0 .. _frontLength]; } void popFront() pure @safe { import std.string : stripLeft; version(assert) if (empty) throw new RangeError(); _s = _s[_frontLength .. $].stripLeft(); getFirst(); } @property bool empty() const @safe pure nothrow { return _s.empty; } @property inout(Result) save() inout @safe pure nothrow { return this; } } return Result(s); } /// @safe pure unittest { import std.algorithm.comparison : equal; auto a = " a bcd ef gh "; assert(equal(splitter(a), ["a", "bcd", "ef", "gh"][])); } @safe pure unittest { import std.algorithm.comparison : equal; import std.meta : AliasSeq; foreach(S; AliasSeq!(string, wstring, dstring)) { import std.conv : to; S a = " a bcd ef gh "; assert(equal(splitter(a), [to!S("a"), to!S("bcd"), to!S("ef"), to!S("gh")])); a = ""; assert(splitter(a).empty); } immutable string s = " a bcd ef gh "; assert(equal(splitter(s), ["a", "bcd", "ef", "gh"][])); } @safe unittest { import std.conv : to; import std.string : strip; // TDPL example, page 8 uint[string] dictionary; char[][3] lines; lines[0] = "line one".dup; lines[1] = "line \ttwo".dup; lines[2] = "yah last line\ryah".dup; foreach (line; lines) { foreach (word; splitter(strip(line))) { if (word in dictionary) continue; // Nothing to do auto newID = dictionary.length; dictionary[to!string(word)] = cast(uint)newID; } } assert(dictionary.length == 5); assert(dictionary["line"]== 0); assert(dictionary["one"]== 1); assert(dictionary["two"]== 2); assert(dictionary["yah"]== 3); assert(dictionary["last"]== 4); } @safe unittest { import std.algorithm.internal : algoFormat; import std.algorithm.comparison : equal; import std.conv : text; import std.array : split; // Check consistency: // All flavors of split should produce the same results foreach (input; [(int[]).init, [0], [0, 1, 0], [1, 1, 0, 0, 1, 1], ]) { foreach (s; [0, 1]) { auto result = split(input, s); assert(equal(result, split(input, [s])), algoFormat(`"[%(%s,%)]"`, split(input, [s]))); //assert(equal(result, split(input, [s].filter!"true"()))); //Not yet implemented assert(equal(result, split!((a) => a == s)(input)), text(split!((a) => a == s)(input))); //assert(equal!equal(result, split(input.filter!"true"(), s))); //Not yet implemented //assert(equal!equal(result, split(input.filter!"true"(), [s]))); //Not yet implemented //assert(equal!equal(result, split(input.filter!"true"(), [s].filter!"true"()))); //Not yet implemented assert(equal!equal(result, split!((a) => a == s)(input.filter!"true"()))); assert(equal(result, splitter(input, s))); assert(equal(result, splitter(input, [s]))); //assert(equal(result, splitter(input, [s].filter!"true"()))); //Not yet implemented assert(equal(result, splitter!((a) => a == s)(input))); //assert(equal!equal(result, splitter(input.filter!"true"(), s))); //Not yet implemented //assert(equal!equal(result, splitter(input.filter!"true"(), [s]))); //Not yet implemented //assert(equal!equal(result, splitter(input.filter!"true"(), [s].filter!"true"()))); //Not yet implemented assert(equal!equal(result, splitter!((a) => a == s)(input.filter!"true"()))); } } foreach (input; [string.init, " ", " hello ", "hello hello", " hello what heck this ? " ]) { foreach (s; [' ', 'h']) { auto result = split(input, s); assert(equal(result, split(input, [s]))); //assert(equal(result, split(input, [s].filter!"true"()))); //Not yet implemented assert(equal(result, split!((a) => a == s)(input))); //assert(equal!equal(result, split(input.filter!"true"(), s))); //Not yet implemented //assert(equal!equal(result, split(input.filter!"true"(), [s]))); //Not yet implemented //assert(equal!equal(result, split(input.filter!"true"(), [s].filter!"true"()))); //Not yet implemented assert(equal!equal(result, split!((a) => a == s)(input.filter!"true"()))); assert(equal(result, splitter(input, s))); assert(equal(result, splitter(input, [s]))); //assert(equal(result, splitter(input, [s].filter!"true"()))); //Not yet implemented assert(equal(result, splitter!((a) => a == s)(input))); //assert(equal!equal(result, splitter(input.filter!"true"(), s))); //Not yet implemented //assert(equal!equal(result, splitter(input.filter!"true"(), [s]))); //Not yet implemented //assert(equal!equal(result, splitter(input.filter!"true"(), [s].filter!"true"()))); //Not yet implemented assert(equal!equal(result, splitter!((a) => a == s)(input.filter!"true"()))); } } } // sum /** Sums elements of $(D r), which must be a finite $(XREF_PACK_NAMED range,primitives,isInputRange,input range). Although conceptually $(D sum(r)) is equivalent to $(LREF fold)!((a, b) => a + b)(r, 0), $(D sum) uses specialized algorithms to maximize accuracy, as follows. $(UL $(LI If $(D $(XREF_PACK range,primitives,ElementType)!R) is a floating-point type and $(D R) is a $(XREF_PACK_NAMED range,primitives,isRandomAccessRange,random-access range) with length and slicing, then $(D sum) uses the $(WEB en.wikipedia.org/wiki/Pairwise_summation, pairwise summation) algorithm.) $(LI If $(D ElementType!R) is a floating-point type and $(D R) is a finite input range (but not a random-access range with slicing), then $(D sum) uses the $(WEB en.wikipedia.org/wiki/Kahan_summation, Kahan summation) algorithm.) $(LI In all other cases, a simple element by element addition is done.) ) For floating point inputs, calculations are made in $(DDLINK spec/type, Types, $(D real)) precision for $(D real) inputs and in $(D double) precision otherwise (Note this is a special case that deviates from $(D fold)'s behavior, which would have kept $(D float) precision for a $(D float) range). For all other types, the calculations are done in the same type obtained from from adding two elements of the range, which may be a different type from the elements themselves (for example, in case of $(DDSUBLINK spec/type,integer-promotions, integral promotion)). A seed may be passed to $(D sum). Not only will this seed be used as an initial value, but its type will override all the above, and determine the algorithm and precision used for summation. Note that these specialized summing algorithms execute more primitive operations than vanilla summation. Therefore, if in certain cases maximum speed is required at expense of precision, one can use $(D fold!((a, b) => a + b)(r, 0)), which is not specialized for summation. Params: seed = the initial value of the summation r = a finite input range Returns: The sum of all the elements in the range r. */ auto sum(R)(R r) if (isInputRange!R && !isInfinite!R && is(typeof(r.front + r.front))) { alias E = Unqual!(ElementType!R); static if (isFloatingPoint!E) alias Seed = typeof(E.init + 0.0); //biggest of double/real else alias Seed = typeof(r.front + r.front); return sum(r, Unqual!Seed(0)); } /// ditto auto sum(R, E)(R r, E seed) if (isInputRange!R && !isInfinite!R && is(typeof(seed = seed + r.front))) { static if (isFloatingPoint!E) { static if (hasLength!R && hasSlicing!R) return seed + sumPairwise!E(r); else return sumKahan!E(seed, r); } else { return reduce!"a + b"(seed, r); } } // Pairwise summation http://en.wikipedia.org/wiki/Pairwise_summation private auto sumPairwise(Result, R)(R r) { static assert (isFloatingPoint!Result); switch (r.length) { case 0: return cast(Result) 0; case 1: return cast(Result) r.front; case 2: return cast(Result) r[0] + cast(Result) r[1]; default: return sumPairwise!Result(r[0 .. $ / 2]) + sumPairwise!Result(r[$ / 2 .. $]); } } // Kahan algo http://en.wikipedia.org/wiki/Kahan_summation_algorithm private auto sumKahan(Result, R)(Result result, R r) { static assert (isFloatingPoint!Result && isMutable!Result); Result c = 0; for (; !r.empty; r.popFront()) { auto y = r.front - c; auto t = result + y; c = (t - result) - y; result = t; } return result; } /// Ditto @safe pure nothrow unittest { import std.range; //simple integral sumation assert(sum([ 1, 2, 3, 4]) == 10); //with integral promotion assert(sum([false, true, true, false, true]) == 3); assert(sum(ubyte.max.repeat(100)) == 25500); //The result may overflow assert(uint.max.repeat(3).sum() == 4294967293U ); //But a seed can be used to change the sumation primitive assert(uint.max.repeat(3).sum(ulong.init) == 12884901885UL); //Floating point sumation assert(sum([1.0, 2.0, 3.0, 4.0]) == 10); //Floating point operations have double precision minimum static assert(is(typeof(sum([1F, 2F, 3F, 4F])) == double)); assert(sum([1F, 2, 3, 4]) == 10); //Force pair-wise floating point sumation on large integers import std.math : approxEqual; assert(iota(ulong.max / 2, ulong.max / 2 + 4096).sum(0.0) .approxEqual((ulong.max / 2) * 4096.0 + 4096^^2 / 2)); } @safe pure nothrow unittest { static assert(is(typeof(sum([cast( byte)1])) == int)); static assert(is(typeof(sum([cast(ubyte)1])) == int)); static assert(is(typeof(sum([ 1, 2, 3, 4])) == int)); static assert(is(typeof(sum([ 1U, 2U, 3U, 4U])) == uint)); static assert(is(typeof(sum([ 1L, 2L, 3L, 4L])) == long)); static assert(is(typeof(sum([1UL, 2UL, 3UL, 4UL])) == ulong)); int[] empty; assert(sum(empty) == 0); assert(sum([42]) == 42); assert(sum([42, 43]) == 42 + 43); assert(sum([42, 43, 44]) == 42 + 43 + 44); assert(sum([42, 43, 44, 45]) == 42 + 43 + 44 + 45); } @safe pure nothrow unittest { static assert(is(typeof(sum([1.0, 2.0, 3.0, 4.0])) == double)); static assert(is(typeof(sum([ 1F, 2F, 3F, 4F])) == double)); const(float[]) a = [1F, 2F, 3F, 4F]; static assert(is(typeof(sum(a)) == double)); const(float)[] b = [1F, 2F, 3F, 4F]; static assert(is(typeof(sum(a)) == double)); double[] empty; assert(sum(empty) == 0); assert(sum([42.]) == 42); assert(sum([42., 43.]) == 42 + 43); assert(sum([42., 43., 44.]) == 42 + 43 + 44); assert(sum([42., 43., 44., 45.5]) == 42 + 43 + 44 + 45.5); } @safe pure nothrow unittest { import std.container; static assert(is(typeof(sum(SList!float()[])) == double)); static assert(is(typeof(sum(SList!double()[])) == double)); static assert(is(typeof(sum(SList!real()[])) == real)); assert(sum(SList!double()[]) == 0); assert(sum(SList!double(1)[]) == 1); assert(sum(SList!double(1, 2)[]) == 1 + 2); assert(sum(SList!double(1, 2, 3)[]) == 1 + 2 + 3); assert(sum(SList!double(1, 2, 3, 4)[]) == 10); } @safe pure nothrow unittest // 12434 { immutable a = [10, 20]; auto s1 = sum(a); // Error auto s2 = a.map!(x => x).sum; // Error } unittest { import std.bigint; import std.range; immutable BigInt[] a = BigInt("1_000_000_000_000_000_000").repeat(10).array(); immutable ulong[] b = (ulong.max/2).repeat(10).array(); auto sa = a.sum(); auto sb = b.sum(BigInt(0)); //reduce ulongs into bigint assert(sa == BigInt("10_000_000_000_000_000_000")); assert(sb == (BigInt(ulong.max/2) * 10)); } // uniq /** Lazily iterates unique consecutive elements of the given range (functionality akin to the $(WEB wikipedia.org/wiki/_Uniq, _uniq) system utility). Equivalence of elements is assessed by using the predicate $(D pred), by default $(D "a == b"). The predicate is passed to $(XREF functional,binaryFun), and can either accept a string, or any callable that can be executed via $(D pred(element, element)). If the given range is bidirectional, $(D uniq) also yields a bidirectional range. Params: pred = Predicate for determining equivalence between range elements. r = An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) of elements to filter. Returns: An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) of consecutively unique elements in the original range. If $(D r) is also a forward range or bidirectional range, the returned range will be likewise. */ auto uniq(alias pred = "a == b", Range)(Range r) if (isInputRange!Range && is(typeof(binaryFun!pred(r.front, r.front)) == bool)) { return UniqResult!(binaryFun!pred, Range)(r); } /// @safe unittest { import std.algorithm.mutation : copy; import std.algorithm.comparison : equal; int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][])); // Filter duplicates in-place using copy arr.length -= arr.uniq().copy(arr).length; assert(arr == [ 1, 2, 3, 4, 5 ]); // Note that uniqueness is only determined consecutively; duplicated // elements separated by an intervening different element will not be // eliminated: assert(equal(uniq([ 1, 1, 2, 1, 1, 3, 1]), [1, 2, 1, 3, 1])); } private struct UniqResult(alias pred, Range) { Range _input; this(Range input) { _input = input; } auto opSlice() { return this; } void popFront() { auto last = _input.front; do { _input.popFront(); } while (!_input.empty && pred(last, _input.front)); } @property ElementType!Range front() { return _input.front; } static if (isBidirectionalRange!Range) { void popBack() { auto last = _input.back; do { _input.popBack(); } while (!_input.empty && pred(last, _input.back)); } @property ElementType!Range back() { return _input.back; } } static if (isInfinite!Range) { enum bool empty = false; // Propagate infiniteness. } else { @property bool empty() { return _input.empty; } } static if (isForwardRange!Range) { @property typeof(this) save() { return typeof(this)(_input.save); } } } @safe unittest { import std.algorithm.comparison : equal; import std.internal.test.dummyrange; import std.range; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; auto r = uniq(arr); static assert(isForwardRange!(typeof(r))); assert(equal(r, [ 1, 2, 3, 4, 5 ][])); assert(equal(retro(r), retro([ 1, 2, 3, 4, 5 ][]))); foreach (DummyType; AllDummyRanges) { DummyType d; auto u = uniq(d); assert(equal(u, [1,2,3,4,5,6,7,8,9,10])); static assert(d.rt == RangeType.Input || isForwardRange!(typeof(u))); static if (d.rt >= RangeType.Bidirectional) { assert(equal(retro(u), [10,9,8,7,6,5,4,3,2,1])); } } } // permutations struct Permutations(Range) if (isRandomAccessRange!Range && hasLength!Range) { size_t[] indices, state; Range r; this(Range r) { import std.range : iota; import std.array : array; this.r = r; state = r.length ? new size_t[r.length-1] : null; indices = iota(size_t(r.length)).array; empty = r.length == 0; } bool empty; @property auto front() { import std.range : indexed; return r.indexed(indices); } void popFront() { void next(int n) { import std.algorithm.mutation : swap; if (n > indices.length) { empty = true; return; } if (n % 2 == 1) swap(indices[0], indices[n-1]); else swap(indices[state[n-2]], indices[n-1]); if (++state[n-2] == n) { state[n-2] = 0; next(n+1); } } next(2); } } /** Lazily computes all _permutations of $(D r) using $(WEB en.wikipedia.org/wiki/Heap%27s_algorithm, Heap's algorithm). Returns: A forward range the elements of which are an $(XREF range, indexed) view into $(D r). See_Also: $(XREF_PACK algorithm,sorting,nextPermutation). */ Permutations!Range permutations(Range)(Range r) if (isRandomAccessRange!Range && hasLength!Range) { return typeof(return)(r); } /// unittest { import std.algorithm.comparison : equal; import std.range : iota; assert(equal!equal(iota(3).permutations, [[0, 1, 2], [1, 0, 2], [2, 0, 1], [0, 2, 1], [1, 2, 0], [2, 1, 0]])); } ldc-1.1.0-beta3-src/runtime/phobos/std/algorithm/searching.d0000664000175000017500000035354012776215007022016 0ustar kaikai// Written in the D programming language. /** This is a submodule of $(LINK2 std_algorithm.html, std.algorithm). It contains generic _searching algorithms. $(BOOKTABLE Cheat Sheet, $(TR $(TH Function Name) $(TH Description)) $(T2 all, $(D all!"a > 0"([1, 2, 3, 4])) returns $(D true) because all elements are positive) $(T2 any, $(D any!"a > 0"([1, 2, -3, -4])) returns $(D true) because at least one element is positive) $(T2 balancedParens, $(D balancedParens("((1 + 1) / 2)")) returns $(D true) because the string has balanced parentheses.) $(T2 boyerMooreFinder, $(D find("hello world", boyerMooreFinder("or"))) returns $(D "orld") using the $(LUCKY Boyer-Moore _algorithm).) $(T2 canFind, $(D canFind("hello world", "or")) returns $(D true).) $(T2 count, Counts elements that are equal to a specified value or satisfy a predicate. $(D count([1, 2, 1], 1)) returns $(D 2) and $(D count!"a < 0"([1, -3, 0])) returns $(D 1).) $(T2 countUntil, $(D countUntil(a, b)) returns the number of steps taken in $(D a) to reach $(D b); for example, $(D countUntil("hello!", "o")) returns $(D 4).) $(T2 commonPrefix, $(D commonPrefix("parakeet", "parachute")) returns $(D "para").) $(T2 endsWith, $(D endsWith("rocks", "ks")) returns $(D true).) $(T2 find, $(D find("hello world", "or")) returns $(D "orld") using linear search. (For binary search refer to $(XREF range,sortedRange).)) $(T2 findAdjacent, $(D findAdjacent([1, 2, 3, 3, 4])) returns the subrange starting with two equal adjacent elements, i.e. $(D [3, 3, 4]).) $(T2 findAmong, $(D findAmong("abcd", "qcx")) returns $(D "cd") because $(D 'c') is among $(D "qcx").) $(T2 findSkip, If $(D a = "abcde"), then $(D findSkip(a, "x")) returns $(D false) and leaves $(D a) unchanged, whereas $(D findSkip(a, "c")) advances $(D a) to $(D "de") and returns $(D true).) $(T2 findSplit, $(D findSplit("abcdefg", "de")) returns the three ranges $(D "abc"), $(D "de"), and $(D "fg").) $(T2 findSplitAfter, $(D findSplitAfter("abcdefg", "de")) returns the two ranges $(D "abcde") and $(D "fg").) $(T2 findSplitBefore, $(D findSplitBefore("abcdefg", "de")) returns the two ranges $(D "abc") and $(D "defg").) $(T2 minCount, $(D minCount([2, 1, 1, 4, 1])) returns $(D tuple(1, 3)).) $(T2 maxCount, $(D maxCount([2, 4, 1, 4, 1])) returns $(D tuple(4, 2)).) $(T2 minPos, $(D minPos([2, 3, 1, 3, 4, 1])) returns the subrange $(D [1, 3, 4, 1]), i.e., positions the range at the first occurrence of its minimal element.) $(T2 maxPos, $(D maxPos([2, 3, 1, 3, 4, 1])) returns the subrange $(D [4, 1]), i.e., positions the range at the first occurrence of its maximal element.) $(T2 mismatch, $(D mismatch("parakeet", "parachute")) returns the two ranges $(D "keet") and $(D "chute").) $(T2 skipOver, Assume $(D a = "blah"). Then $(D skipOver(a, "bi")) leaves $(D a) unchanged and returns $(D false), whereas $(D skipOver(a, "bl")) advances $(D a) to refer to $(D "ah") and returns $(D true).) $(T2 startsWith, $(D startsWith("hello, world", "hello")) returns $(D true).) $(T2 until, Lazily iterates a range until a specific value is found.) ) Copyright: Andrei Alexandrescu 2008-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/algorithm/_searching.d) Macros: T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) */ module std.algorithm.searching; // FIXME import std.functional; // : unaryFun, binaryFun; import std.range.primitives; import std.traits; // FIXME import std.typecons; // : Tuple; /++ Checks if $(I _all) of the elements verify $(D pred). +/ template all(alias pred = "a") { /++ Returns $(D true) if and only if $(I _all) values $(D v) found in the input _range $(D range) satisfy the predicate $(D pred). Performs (at most) $(BIGOH range.length) evaluations of $(D pred). +/ bool all(Range)(Range range) if (isInputRange!Range && is(typeof(unaryFun!pred(range.front)))) { import std.functional : not; return find!(not!(unaryFun!pred))(range).empty; } } /// @safe unittest { assert( all!"a & 1"([1, 3, 5, 7, 9])); assert(!all!"a & 1"([1, 2, 3, 5, 7, 9])); } /++ $(D all) can also be used without a predicate, if its items can be evaluated to true or false in a conditional statement. This can be a convenient way to quickly evaluate that $(I _all) of the elements of a range are true. +/ @safe unittest { int[3] vals = [5, 3, 18]; assert( all(vals[])); } @safe unittest { int x = 1; assert(all!(a => a > x)([2, 3])); } /++ Checks if $(I _any) of the elements verifies $(D pred). $(D !any) can be used to verify that $(I none) of the elements verify $(D pred). +/ template any(alias pred = "a") { /++ Returns $(D true) if and only if $(I _any) value $(D v) found in the input _range $(D range) satisfies the predicate $(D pred). Performs (at most) $(BIGOH range.length) evaluations of $(D pred). +/ bool any(Range)(Range range) if (isInputRange!Range && is(typeof(unaryFun!pred(range.front)))) { return !find!pred(range).empty; } } /// @safe unittest { import std.ascii : isWhite; assert( all!(any!isWhite)(["a a", "b b"])); assert(!any!(all!isWhite)(["a a", "b b"])); } /++ $(D any) can also be used without a predicate, if its items can be evaluated to true or false in a conditional statement. $(D !any) can be a convenient way to quickly test that $(I none) of the elements of a range evaluate to true. +/ @safe unittest { int[3] vals1 = [0, 0, 0]; assert(!any(vals1[])); //none of vals1 evaluate to true int[3] vals2 = [2, 0, 2]; assert( any(vals2[])); assert(!all(vals2[])); int[3] vals3 = [3, 3, 3]; assert( any(vals3[])); assert( all(vals3[])); } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto a = [ 1, 2, 0, 4 ]; assert(any!"a == 2"(a)); } // balancedParens /** Checks whether $(D r) has "balanced parentheses", i.e. all instances of $(D lPar) are closed by corresponding instances of $(D rPar). The parameter $(D maxNestingLevel) controls the nesting level allowed. The most common uses are the default or $(D 0). In the latter case, no nesting is allowed. Params: r = The range to check. lPar = The element corresponding with a left (opening) parenthesis. rPar = The element corresponding with a right (closing) parenthesis. maxNestingLevel = The maximum allowed nesting level. Returns: true if the given range has balanced parenthesis within the given maximum nesting level; false otherwise. */ bool balancedParens(Range, E)(Range r, E lPar, E rPar, size_t maxNestingLevel = size_t.max) if (isInputRange!(Range) && is(typeof(r.front == lPar))) { size_t count; for (; !r.empty; r.popFront()) { if (r.front == lPar) { if (count > maxNestingLevel) return false; ++count; } else if (r.front == rPar) { if (!count) return false; --count; } } return count == 0; } /// @safe unittest { auto s = "1 + (2 * (3 + 1 / 2)"; assert(!balancedParens(s, '(', ')')); s = "1 + (2 * (3 + 1) / 2)"; assert(balancedParens(s, '(', ')')); s = "1 + (2 * (3 + 1) / 2)"; assert(!balancedParens(s, '(', ')', 0)); s = "1 + (2 * 3 + 1) / (2 - 5)"; assert(balancedParens(s, '(', ')', 0)); } /** * Sets up Boyer-Moore matching for use with $(D find) below. * By default, elements are compared for equality. * * $(D BoyerMooreFinder) allocates GC memory. * * Params: * pred = Predicate used to compare elements. * needle = A random-access range with length and slicing. * * Returns: * An instance of $(D BoyerMooreFinder) that can be used with $(D find()) to * invoke the Boyer-Moore matching algorithm for finding of $(D needle) in a * given haystack. */ BoyerMooreFinder!(binaryFun!(pred), Range) boyerMooreFinder (alias pred = "a == b", Range) (Range needle) if (isRandomAccessRange!(Range) || isSomeString!Range) { return typeof(return)(needle); } /// Ditto struct BoyerMooreFinder(alias pred, Range) { private: size_t[] skip; // GC allocated ptrdiff_t[ElementType!(Range)] occ; // GC allocated Range needle; ptrdiff_t occurrence(ElementType!(Range) c) { auto p = c in occ; return p ? *p : -1; } /* This helper function checks whether the last "portion" bytes of "needle" (which is "nlen" bytes long) exist within the "needle" at offset "offset" (counted from the end of the string), and whether the character preceding "offset" is not a match. Notice that the range being checked may reach beyond the beginning of the string. Such range is ignored. */ static bool needlematch(R)(R needle, size_t portion, size_t offset) { import std.algorithm.comparison : equal; ptrdiff_t virtual_begin = needle.length - offset - portion; ptrdiff_t ignore = 0; if (virtual_begin < 0) { ignore = -virtual_begin; virtual_begin = 0; } if (virtual_begin > 0 && needle[virtual_begin - 1] == needle[$ - portion - 1]) return 0; immutable delta = portion - ignore; return equal(needle[needle.length - delta .. needle.length], needle[virtual_begin .. virtual_begin + delta]); } public: this(Range needle) { if (!needle.length) return; this.needle = needle; /* Populate table with the analysis of the needle */ /* But ignoring the last letter */ foreach (i, n ; needle[0 .. $ - 1]) { this.occ[n] = i; } /* Preprocess #2: init skip[] */ /* Note: This step could be made a lot faster. * A simple implementation is shown here. */ this.skip = new size_t[needle.length]; foreach (a; 0 .. needle.length) { size_t value = 0; while (value < needle.length && !needlematch(needle, a, value)) { ++value; } this.skip[needle.length - a - 1] = value; } } Range beFound(Range haystack) { import std.algorithm.comparison : max; if (!needle.length) return haystack; if (needle.length > haystack.length) return haystack[$ .. $]; /* Search: */ auto limit = haystack.length - needle.length; for (size_t hpos = 0; hpos <= limit; ) { size_t npos = needle.length - 1; while (pred(needle[npos], haystack[npos+hpos])) { if (npos == 0) return haystack[hpos .. $]; --npos; } hpos += max(skip[npos], cast(sizediff_t) npos - occurrence(haystack[npos+hpos])); } return haystack[$ .. $]; } @property size_t length() { return needle.length; } alias opDollar = length; } /** Returns the common prefix of two ranges. Params: pred = The predicate to use in comparing elements for commonality. Defaults to equality $(D "a == b"). r1 = A $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) of elements. r2 = An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) of elements. Returns: A slice of $(D r1) which contains the characters that both ranges start with, if the first argument is a string; otherwise, the same as the result of $(D takeExactly(r1, n)), where $(D n) is the number of elements in the common prefix of both ranges. See_Also: $(XREF range, takeExactly) */ auto commonPrefix(alias pred = "a == b", R1, R2)(R1 r1, R2 r2) if (isForwardRange!R1 && isInputRange!R2 && !isNarrowString!R1 && is(typeof(binaryFun!pred(r1.front, r2.front)))) { import std.algorithm.comparison : min; static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && hasLength!R1 && hasLength!R2 && hasSlicing!R1) { immutable limit = min(r1.length, r2.length); foreach (i; 0 .. limit) { if (!binaryFun!pred(r1[i], r2[i])) { return r1[0 .. i]; } } return r1[0 .. limit]; } else { import std.range : takeExactly; auto result = r1.save; size_t i = 0; for (; !r1.empty && !r2.empty && binaryFun!pred(r1.front, r2.front); ++i, r1.popFront(), r2.popFront()) {} return takeExactly(result, i); } } /// @safe unittest { assert(commonPrefix("hello, world", "hello, there") == "hello, "); } /// ditto auto commonPrefix(alias pred, R1, R2)(R1 r1, R2 r2) if (isNarrowString!R1 && isInputRange!R2 && is(typeof(binaryFun!pred(r1.front, r2.front)))) { import std.utf : decode; auto result = r1.save; immutable len = r1.length; size_t i = 0; for (size_t j = 0; i < len && !r2.empty; r2.popFront(), i = j) { immutable f = decode(r1, j); if (!binaryFun!pred(f, r2.front)) break; } return result[0 .. i]; } /// ditto auto commonPrefix(R1, R2)(R1 r1, R2 r2) if (isNarrowString!R1 && isInputRange!R2 && !isNarrowString!R2 && is(typeof(r1.front == r2.front))) { return commonPrefix!"a == b"(r1, r2); } /// ditto auto commonPrefix(R1, R2)(R1 r1, R2 r2) if (isNarrowString!R1 && isNarrowString!R2) { import std.algorithm.comparison : min; static if (ElementEncodingType!R1.sizeof == ElementEncodingType!R2.sizeof) { import std.utf : stride, UTFException; immutable limit = min(r1.length, r2.length); for (size_t i = 0; i < limit;) { immutable codeLen = stride(r1, i); size_t j = 0; for (; j < codeLen && i < limit; ++i, ++j) { if (r1[i] != r2[i]) return r1[0 .. i - j]; } if (i == limit && j < codeLen) throw new UTFException("Invalid UTF-8 sequence", i); } return r1[0 .. limit]; } else return commonPrefix!"a == b"(r1, r2); } @safe unittest { import std.algorithm.comparison : equal; import std.algorithm.iteration : filter; import std.conv : to; import std.exception : assertThrown; import std.meta : AliasSeq; import std.range; import std.utf : UTFException; assert(commonPrefix([1, 2, 3], [1, 2, 3, 4, 5]) == [1, 2, 3]); assert(commonPrefix([1, 2, 3, 4, 5], [1, 2, 3]) == [1, 2, 3]); assert(commonPrefix([1, 2, 3, 4], [1, 2, 3, 4]) == [1, 2, 3, 4]); assert(commonPrefix([1, 2, 3], [7, 2, 3, 4, 5]).empty); assert(commonPrefix([7, 2, 3, 4, 5], [1, 2, 3]).empty); assert(commonPrefix([1, 2, 3], cast(int[])null).empty); assert(commonPrefix(cast(int[])null, [1, 2, 3]).empty); assert(commonPrefix(cast(int[])null, cast(int[])null).empty); foreach (S; AliasSeq!(char[], const(char)[], string, wchar[], const(wchar)[], wstring, dchar[], const(dchar)[], dstring)) { foreach(T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(commonPrefix(to!S(""), to!T("")).empty); assert(commonPrefix(to!S(""), to!T("hello")).empty); assert(commonPrefix(to!S("hello"), to!T("")).empty); assert(commonPrefix(to!S("hello, world"), to!T("hello, there")) == to!S("hello, ")); assert(commonPrefix(to!S("hello, there"), to!T("hello, world")) == to!S("hello, ")); assert(commonPrefix(to!S("hello, "), to!T("hello, world")) == to!S("hello, ")); assert(commonPrefix(to!S("hello, world"), to!T("hello, ")) == to!S("hello, ")); assert(commonPrefix(to!S("hello, world"), to!T("hello, world")) == to!S("hello, world")); //Bug# 8890 assert(commonPrefix(to!S("Пиво"), to!T("Пони"))== to!S("П")); assert(commonPrefix(to!S("Пони"), to!T("Пиво"))== to!S("П")); assert(commonPrefix(to!S("Пиво"), to!T("Пиво"))== to!S("Пиво")); assert(commonPrefix(to!S("\U0010FFFF\U0010FFFB\U0010FFFE"), to!T("\U0010FFFF\U0010FFFB\U0010FFFC")) == to!S("\U0010FFFF\U0010FFFB")); assert(commonPrefix(to!S("\U0010FFFF\U0010FFFB\U0010FFFC"), to!T("\U0010FFFF\U0010FFFB\U0010FFFE")) == to!S("\U0010FFFF\U0010FFFB")); assert(commonPrefix!"a != b"(to!S("Пиво"), to!T("онво")) == to!S("Пи")); assert(commonPrefix!"a != b"(to!S("онво"), to!T("Пиво")) == to!S("он")); }(); static assert(is(typeof(commonPrefix(to!S("Пиво"), filter!"true"("Пони"))) == S)); assert(equal(commonPrefix(to!S("Пиво"), filter!"true"("Пони")), to!S("П"))); static assert(is(typeof(commonPrefix(filter!"true"("Пиво"), to!S("Пони"))) == typeof(takeExactly(filter!"true"("П"), 1)))); assert(equal(commonPrefix(filter!"true"("Пиво"), to!S("Пони")), takeExactly(filter!"true"("П"), 1))); } assertThrown!UTFException(commonPrefix("\U0010FFFF\U0010FFFB", "\U0010FFFF\U0010FFFB"[0 .. $ - 1])); assert(commonPrefix("12345"d, [49, 50, 51, 60, 60]) == "123"d); assert(commonPrefix([49, 50, 51, 60, 60], "12345" ) == [49, 50, 51]); assert(commonPrefix([49, 50, 51, 60, 60], "12345"d) == [49, 50, 51]); assert(commonPrefix!"a == ('0' + b)"("12345" , [1, 2, 3, 9, 9]) == "123"); assert(commonPrefix!"a == ('0' + b)"("12345"d, [1, 2, 3, 9, 9]) == "123"d); assert(commonPrefix!"('0' + a) == b"([1, 2, 3, 9, 9], "12345" ) == [1, 2, 3]); assert(commonPrefix!"('0' + a) == b"([1, 2, 3, 9, 9], "12345"d) == [1, 2, 3]); } // count /** The first version counts the number of elements $(D x) in $(D r) for which $(D pred(x, value)) is $(D true). $(D pred) defaults to equality. Performs $(BIGOH haystack.length) evaluations of $(D pred). The second version returns the number of times $(D needle) occurs in $(D haystack). Throws an exception if $(D needle.empty), as the _count of the empty range in any range would be infinite. Overlapped counts are not considered, for example $(D count("aaa", "aa")) is $(D 1), not $(D 2). The third version counts the elements for which $(D pred(x)) is $(D true). Performs $(BIGOH haystack.length) evaluations of $(D pred). Note: Regardless of the overload, $(D count) will not accept infinite ranges for $(D haystack). Params: pred = The predicate to evaluate. haystack = The range to _count. needle = The element or sub-range to _count in the `haystack`. Returns: The number of positions in the `haystack` for which `pred` returned true. */ size_t count(alias pred = "a == b", Range, E)(Range haystack, E needle) if (isInputRange!Range && !isInfinite!Range && is(typeof(binaryFun!pred(haystack.front, needle)) : bool)) { bool pred2(ElementType!Range a) { return binaryFun!pred(a, needle); } return count!pred2(haystack); } /// @safe unittest { import std.uni : toLower; // count elements in range int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; assert(count(a, 2) == 3); assert(count!("a > b")(a, 2) == 5); // count range in range assert(count("abcadfabf", "ab") == 2); assert(count("ababab", "abab") == 1); assert(count("ababab", "abx") == 0); // fuzzy count range in range assert(count!((a, b) => std.uni.toLower(a) == std.uni.toLower(b))("AbcAdFaBf", "ab") == 2); // count predicate in range assert(count!("a > 1")(a) == 8); } @safe unittest { import std.conv : text; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; assert(count(a, 2) == 3, text(count(a, 2))); assert(count!("a > b")(a, 2) == 5, text(count!("a > b")(a, 2))); // check strings assert(count("日本語") == 3); assert(count("日本語"w) == 3); assert(count("日本語"d) == 3); assert(count!("a == '日'")("日本語") == 1); assert(count!("a == '本'")("日本語"w) == 1); assert(count!("a == '語'")("日本語"d) == 1); } @safe unittest { debug(std_algorithm) printf("algorithm.count.unittest\n"); string s = "This is a fofofof list"; string sub = "fof"; assert(count(s, sub) == 2); } /// Ditto size_t count(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && !isInfinite!R1 && isForwardRange!R2 && is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool)) { assert(!needle.empty, "Cannot count occurrences of an empty range"); static if (isInfinite!R2) { //Note: This is the special case of looking for an infinite inside a finite... //"How many instances of the Fibonacci sequence can you count in [1, 2, 3]?" - "None." return 0; } else { size_t result; //Note: haystack is not saved, because findskip is designed to modify it for ( ; findSkip!pred(haystack, needle.save) ; ++result) {} return result; } } /// Ditto size_t count(alias pred = "true", R)(R haystack) if (isInputRange!R && !isInfinite!R && is(typeof(unaryFun!pred(haystack.front)) : bool)) { size_t result; alias T = ElementType!R; //For narrow strings forces dchar iteration foreach (T elem; haystack) if (unaryFun!pred(elem)) ++result; return result; } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; assert(count!("a == 3")(a) == 2); assert(count("日本語") == 3); } // Issue 11253 @safe nothrow unittest { assert([1, 2, 3].count([2, 3]) == 1); } /++ Counts elements in the given $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) until the given predicate is true for one of the given $(D needles). Params: pred = The predicate for determining when to stop counting. haystack = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) to be counted. needles = Either a single element, or a $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) of elements, to be evaluated in turn against each element in $(D haystack) under the given predicate. Returns: The number of elements which must be popped from the front of $(D haystack) before reaching an element for which $(D startsWith!pred(haystack, needles)) is $(D true). If $(D startsWith!pred(haystack, needles)) is not $(D true) for any element in $(D haystack), then $(D -1) is returned. +/ ptrdiff_t countUntil(alias pred = "a == b", R, Rs...)(R haystack, Rs needles) if (isForwardRange!R && Rs.length > 0 && isForwardRange!(Rs[0]) == isInputRange!(Rs[0]) && is(typeof(startsWith!pred(haystack, needles[0]))) && (Rs.length == 1 || is(typeof(countUntil!pred(haystack, needles[1 .. $]))))) { typeof(return) result; static if (needles.length == 1) { static if (hasLength!R) //Note: Narrow strings don't have length. { //We delegate to find because find is very efficient. //We store the length of the haystack so we don't have to save it. auto len = haystack.length; auto r2 = find!pred(haystack, needles[0]); if (!r2.empty) return cast(typeof(return)) (len - r2.length); } else { import std.range : dropOne; if (needles[0].empty) return 0; //Default case, slower route doing startsWith iteration for ( ; !haystack.empty ; ++result ) { //We compare the first elements of the ranges here before //forwarding to startsWith. This avoids making useless saves to //haystack/needle if they aren't even going to be mutated anyways. //It also cuts down on the amount of pops on haystack. if (binaryFun!pred(haystack.front, needles[0].front)) { //Here, we need to save the needle before popping it. //haystack we pop in all paths, so we do that, and then save. haystack.popFront(); if (startsWith!pred(haystack.save, needles[0].save.dropOne())) return result; } else haystack.popFront(); } } } else { foreach (i, Ri; Rs) { static if (isForwardRange!Ri) { if (needles[i].empty) return 0; } } Tuple!Rs t; foreach (i, Ri; Rs) { static if (!isForwardRange!Ri) { t[i] = needles[i]; } } for (; !haystack.empty ; ++result, haystack.popFront()) { foreach (i, Ri; Rs) { static if (isForwardRange!Ri) { t[i] = needles[i].save; } } if (startsWith!pred(haystack.save, t.expand)) { return result; } } } //Because of @@@8804@@@: Avoids both "unreachable code" or "no return statement" static if (isInfinite!R) assert(0); else return -1; } /// ditto ptrdiff_t countUntil(alias pred = "a == b", R, N)(R haystack, N needle) if (isInputRange!R && is(typeof(binaryFun!pred(haystack.front, needle)) : bool)) { bool pred2(ElementType!R a) { return binaryFun!pred(a, needle); } return countUntil!pred2(haystack); } /// @safe unittest { assert(countUntil("hello world", "world") == 6); assert(countUntil("hello world", 'r') == 8); assert(countUntil("hello world", "programming") == -1); assert(countUntil("日本語", "本語") == 1); assert(countUntil("日本語", '語') == 2); assert(countUntil("日本語", "五") == -1); assert(countUntil("日本語", '五') == -1); assert(countUntil([0, 7, 12, 22, 9], [12, 22]) == 2); assert(countUntil([0, 7, 12, 22, 9], 9) == 4); assert(countUntil!"a > b"([0, 7, 12, 22, 9], 20) == 3); } @safe unittest { import std.algorithm.iteration : filter; import std.internal.test.dummyrange; assert(countUntil("日本語", "") == 0); assert(countUntil("日本語"d, "") == 0); assert(countUntil("", "") == 0); assert(countUntil("".filter!"true"(), "") == 0); auto rf = [0, 20, 12, 22, 9].filter!"true"(); assert(rf.countUntil!"a > b"((int[]).init) == 0); assert(rf.countUntil!"a > b"(20) == 3); assert(rf.countUntil!"a > b"([20, 8]) == 3); assert(rf.countUntil!"a > b"([20, 10]) == -1); assert(rf.countUntil!"a > b"([20, 8, 0]) == -1); auto r = new ReferenceForwardRange!int([0, 1, 2, 3, 4, 5, 6]); auto r2 = new ReferenceForwardRange!int([3, 4]); auto r3 = new ReferenceForwardRange!int([3, 5]); assert(r.save.countUntil(3) == 3); assert(r.save.countUntil(r2) == 3); assert(r.save.countUntil(7) == -1); assert(r.save.countUntil(r3) == -1); } @safe unittest { assert(countUntil("hello world", "world", "asd") == 6); assert(countUntil("hello world", "world", "ello") == 1); assert(countUntil("hello world", "world", "") == 0); assert(countUntil("hello world", "world", 'l') == 2); } /++ Similar to the previous overload of $(D countUntil), except that this one evaluates only the predicate $(D pred). Params: pred = Predicate to when to stop counting. haystack = An $(XREF_PACK_NAMED range,primitives,isInputRange,input range) of elements to be counted. Returns: The number of elements which must be popped from $(D haystack) before $(D pred(haystack.front)) is $(D true). +/ ptrdiff_t countUntil(alias pred, R)(R haystack) if (isInputRange!R && is(typeof(unaryFun!pred(haystack.front)) : bool)) { typeof(return) i; static if (isRandomAccessRange!R) { //Optimized RA implementation. Since we want to count *and* iterate at //the same time, it is more efficient this way. static if (hasLength!R) { immutable len = cast(typeof(return)) haystack.length; for ( ; i < len ; ++i ) if (unaryFun!pred(haystack[i])) return i; } else //if (isInfinite!R) { for ( ; ; ++i ) if (unaryFun!pred(haystack[i])) return i; } } else static if (hasLength!R) { //For those odd ranges that have a length, but aren't RA. //It is faster to quick find, and then compare the lengths auto r2 = find!pred(haystack.save); if (!r2.empty) return cast(typeof(return)) (haystack.length - r2.length); } else //Everything else { alias T = ElementType!R; //For narrow strings forces dchar iteration foreach (T elem; haystack) { if (unaryFun!pred(elem)) return i; ++i; } } //Because of @@@8804@@@: Avoids both "unreachable code" or "no return statement" static if (isInfinite!R) assert(0); else return -1; } /// @safe unittest { import std.ascii : isDigit; import std.uni : isWhite; assert(countUntil!(std.uni.isWhite)("hello world") == 5); assert(countUntil!(std.ascii.isDigit)("hello world") == -1); assert(countUntil!"a > 20"([0, 7, 12, 22, 9]) == 3); } @safe unittest { import std.internal.test.dummyrange; // References { // input ReferenceInputRange!int r; r = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6]); assert(r.countUntil(3) == 3); r = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6]); assert(r.countUntil(7) == -1); } { // forward auto r = new ReferenceForwardRange!int([0, 1, 2, 3, 4, 5, 6]); assert(r.save.countUntil([3, 4]) == 3); assert(r.save.countUntil(3) == 3); assert(r.save.countUntil([3, 7]) == -1); assert(r.save.countUntil(7) == -1); } { // infinite forward auto r = new ReferenceInfiniteForwardRange!int(0); assert(r.save.countUntil([3, 4]) == 3); assert(r.save.countUntil(3) == 3); } } /** Checks if the given range ends with (one of) the given needle(s). The reciprocal of $(D startsWith). Params: pred = The predicate to use for comparing elements between the range and the needle(s). doesThisEnd = The $(XREF_PACK_NAMED range,primitives,isBidirectionalRange,bidirectional range) to check. withOneOfThese = The needles to check against, which may be single elements, or bidirectional ranges of elements. withThis = The single element to check. Returns: 0 if the needle(s) do not occur at the end of the given range; otherwise the position of the matching needle, that is, 1 if the range ends with $(D withOneOfThese[0]), 2 if it ends with $(D withOneOfThese[1]), and so on. In the case when no needle parameters are given, return $(D true) iff back of $(D doesThisStart) fulfils predicate $(D pred). */ uint endsWith(alias pred = "a == b", Range, Needles...)(Range doesThisEnd, Needles withOneOfThese) if (isBidirectionalRange!Range && Needles.length > 1 && is(typeof(.endsWith!pred(doesThisEnd, withOneOfThese[0])) : bool) && is(typeof(.endsWith!pred(doesThisEnd, withOneOfThese[1 .. $])) : uint)) { alias haystack = doesThisEnd; alias needles = withOneOfThese; // Make one pass looking for empty ranges in needles foreach (i, Unused; Needles) { // Empty range matches everything static if (!is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool)) { if (needles[i].empty) return i + 1; } } for (; !haystack.empty; haystack.popBack()) { foreach (i, Unused; Needles) { static if (is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool)) { // Single-element if (binaryFun!pred(haystack.back, needles[i])) { // found, but continue to account for one-element // range matches (consider endsWith("ab", "b", // 'b') should return 1, not 2). continue; } } else { if (binaryFun!pred(haystack.back, needles[i].back)) continue; } // This code executed on failure to match // Out with this guy, check for the others uint result = endsWith!pred(haystack, needles[0 .. i], needles[i + 1 .. $]); if (result > i) ++result; return result; } // If execution reaches this point, then the back matches for all // needles ranges. What we need to do now is to lop off the back of // all ranges involved and recurse. foreach (i, Unused; Needles) { static if (is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool)) { // Test has passed in the previous loop return i + 1; } else { needles[i].popBack(); if (needles[i].empty) return i + 1; } } } return 0; } /// Ditto bool endsWith(alias pred = "a == b", R1, R2)(R1 doesThisEnd, R2 withThis) if (isBidirectionalRange!R1 && isBidirectionalRange!R2 && is(typeof(binaryFun!pred(doesThisEnd.back, withThis.back)) : bool)) { alias haystack = doesThisEnd; alias needle = withThis; static if (is(typeof(pred) : string)) enum isDefaultPred = pred == "a == b"; else enum isDefaultPred = false; static if (isDefaultPred && isArray!R1 && isArray!R2 && is(Unqual!(ElementEncodingType!R1) == Unqual!(ElementEncodingType!R2))) { if (haystack.length < needle.length) return false; return haystack[$ - needle.length .. $] == needle; } else { import std.range : retro; return startsWith!pred(retro(doesThisEnd), retro(withThis)); } } /// Ditto bool endsWith(alias pred = "a == b", R, E)(R doesThisEnd, E withThis) if (isBidirectionalRange!R && is(typeof(binaryFun!pred(doesThisEnd.back, withThis)) : bool)) { return doesThisEnd.empty ? false : binaryFun!pred(doesThisEnd.back, withThis); } /// Ditto bool endsWith(alias pred, R)(R doesThisEnd) if (isInputRange!R && ifTestable!(typeof(doesThisEnd.front), unaryFun!pred)) { return !doesThisEnd.empty && unaryFun!pred(doesThisEnd.back); } /// @safe unittest { import std.ascii : isAlpha; assert("abc".endsWith!(a => a.isAlpha)); assert("abc".endsWith!isAlpha); assert(!"ab1".endsWith!(a => a.isAlpha)); assert(!"ab1".endsWith!isAlpha); assert(!"".endsWith!(a => a.isAlpha)); import std.algorithm.comparison : among; assert("abc".endsWith!(a => a.among('c', 'd') != 0)); assert(!"abc".endsWith!(a => a.among('a', 'b') != 0)); assert(endsWith("abc", "")); assert(!endsWith("abc", "b")); assert(endsWith("abc", "a", 'c') == 2); assert(endsWith("abc", "c", "a") == 1); assert(endsWith("abc", "c", "c") == 1); assert(endsWith("abc", "bc", "c") == 2); assert(endsWith("abc", "x", "c", "b") == 2); assert(endsWith("abc", "x", "aa", "bc") == 3); assert(endsWith("abc", "x", "aaa", "sab") == 0); assert(endsWith("abc", "x", "aaa", 'c', "sab") == 3); } @safe unittest { import std.algorithm.iteration : filterBidirectional; import std.meta : AliasSeq; import std.conv : to; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { assert(!endsWith(to!S("abc"), 'a')); assert(endsWith(to!S("abc"), 'a', 'c') == 2); assert(!endsWith(to!S("abc"), 'x', 'n', 'b')); assert(endsWith(to!S("abc"), 'x', 'n', 'c') == 3); assert(endsWith(to!S("abc\uFF28"), 'a', '\uFF28', 'c') == 2); foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 //Lots of strings assert(endsWith(to!S("abc"), to!T(""))); assert(!endsWith(to!S("abc"), to!T("a"))); assert(!endsWith(to!S("abc"), to!T("b"))); assert(endsWith(to!S("abc"), to!T("bc"), 'c') == 2); assert(endsWith(to!S("abc"), to!T("a"), "c") == 2); assert(endsWith(to!S("abc"), to!T("c"), "a") == 1); assert(endsWith(to!S("abc"), to!T("c"), "c") == 1); assert(endsWith(to!S("abc"), to!T("x"), 'c', "b") == 2); assert(endsWith(to!S("abc"), 'x', to!T("aa"), "bc") == 3); assert(endsWith(to!S("abc"), to!T("x"), "aaa", "sab") == 0); assert(endsWith(to!S("abc"), to!T("x"), "aaa", "c", "sab") == 3); assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co"))); assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2); //Unicode assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co"))); assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2); assert(endsWith(to!S("日本語"), to!T("本語"))); assert(endsWith(to!S("日本語"), to!T("日本語"))); assert(!endsWith(to!S("本語"), to!T("日本語"))); //Empty assert(endsWith(to!S(""), T.init)); assert(!endsWith(to!S(""), 'a')); assert(endsWith(to!S("a"), T.init)); assert(endsWith(to!S("a"), T.init, "") == 1); assert(endsWith(to!S("a"), T.init, 'a') == 1); assert(endsWith(to!S("a"), 'a', T.init) == 2); }(); } foreach (T; AliasSeq!(int, short)) { immutable arr = cast(T[])[0, 1, 2, 3, 4, 5]; //RA range assert(endsWith(arr, cast(int[])null)); assert(!endsWith(arr, 0)); assert(!endsWith(arr, 4)); assert(endsWith(arr, 5)); assert(endsWith(arr, 0, 4, 5) == 3); assert(endsWith(arr, [5])); assert(endsWith(arr, [4, 5])); assert(endsWith(arr, [4, 5], 7) == 1); assert(!endsWith(arr, [2, 4, 5])); assert(endsWith(arr, [2, 4, 5], [3, 4, 5]) == 2); //Normal input range assert(!endsWith(filterBidirectional!"true"(arr), 4)); assert(endsWith(filterBidirectional!"true"(arr), 5)); assert(endsWith(filterBidirectional!"true"(arr), [5])); assert(endsWith(filterBidirectional!"true"(arr), [4, 5])); assert(endsWith(filterBidirectional!"true"(arr), [4, 5], 7) == 1); assert(!endsWith(filterBidirectional!"true"(arr), [2, 4, 5])); assert(endsWith(filterBidirectional!"true"(arr), [2, 4, 5], [3, 4, 5]) == 2); assert(endsWith(arr, filterBidirectional!"true"([4, 5]))); assert(endsWith(arr, filterBidirectional!"true"([4, 5]), 7) == 1); assert(!endsWith(arr, filterBidirectional!"true"([2, 4, 5]))); assert(endsWith(arr, [2, 4, 5], filterBidirectional!"true"([3, 4, 5])) == 2); //Non-default pred assert(endsWith!("a%10 == b%10")(arr, [14, 15])); assert(!endsWith!("a%10 == b%10")(arr, [15, 14])); } } // find /** Finds an individual element in an input range. Elements of $(D haystack) are compared with $(D needle) by using predicate $(D pred). Performs $(BIGOH walkLength(haystack)) evaluations of $(D pred). To _find the last occurrence of $(D needle) in $(D haystack), call $(D find(retro(haystack), needle)). See $(XREF range, retro). Params: pred = The predicate for comparing each element with the needle, defaulting to $(D "a == b"). The negated predicate $(D "a != b") can be used to search instead for the first element $(I not) matching the needle. haystack = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) searched in. needle = The element searched for. Constraints: $(D isInputRange!InputRange && is(typeof(binaryFun!pred(haystack.front, needle) : bool))) Returns: $(D haystack) advanced such that the front element is the one searched for; that is, until $(D binaryFun!pred(haystack.front, needle)) is $(D true). If no such position exists, returns an empty $(D haystack). See_Also: $(WEB sgi.com/tech/stl/_find.html, STL's _find) */ InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, Element needle) if (isInputRange!InputRange && is (typeof(binaryFun!pred(haystack.front, needle)) : bool)) { alias R = InputRange; alias E = Element; alias predFun = binaryFun!pred; static if (is(typeof(pred == "a == b"))) enum isDefaultPred = pred == "a == b"; else enum isDefaultPred = false; enum isIntegralNeedle = isSomeChar!E || isIntegral!E || isBoolean!E; alias EType = ElementType!R; static if (isNarrowString!R) { alias EEType = ElementEncodingType!R; alias UEEType = Unqual!EEType; //These are two special cases which can search without decoding the UTF stream. static if (isDefaultPred && isIntegralNeedle) { import std.utf : canSearchInCodeUnits; //This special case deals with UTF8 search, when the needle //is represented by a single code point. //Note: "needle <= 0x7F" properly handles sign via unsigned promotion static if (is(UEEType == char)) { if (!__ctfe && canSearchInCodeUnits!char(needle)) { static R trustedMemchr(ref R haystack, ref E needle) @trusted nothrow pure { import core.stdc.string : memchr; auto ptr = memchr(haystack.ptr, needle, haystack.length); return ptr ? haystack[ptr - haystack.ptr .. $] : haystack[$ .. $]; } return trustedMemchr(haystack, needle); } } //Ditto, but for UTF16 static if (is(UEEType == wchar)) { if (canSearchInCodeUnits!wchar(needle)) { foreach (i, ref EEType e; haystack) { if (e == needle) return haystack[i .. $]; } return haystack[$ .. $]; } } } //Previous conditonal optimizations did not succeed. Fallback to //unconditional implementations static if (isDefaultPred) { import std.utf : encode; //In case of default pred, it is faster to do string/string search. UEEType[is(UEEType == char) ? 4 : 2] buf; size_t len = encode(buf, needle); return find(haystack, buf[0 .. len]); } else { import std.utf : decode; //Explicit pred: we must test each character by the book. //We choose a manual decoding approach, because it is faster than //the built-in foreach, or doing a front/popFront for-loop. immutable len = haystack.length; size_t i = 0, next = 0; while (next < len) { if (predFun(decode(haystack, next), needle)) return haystack[i .. $]; i = next; } return haystack[$ .. $]; } } else static if (isArray!R) { //10403 optimization static if (isDefaultPred && isIntegral!EType && EType.sizeof == 1 && isIntegralNeedle) { import std.algorithm.comparison : max, min; R findHelper(ref R haystack, ref E needle) @trusted nothrow pure { import core.stdc.string : memchr; EType* ptr = null; //Note: we use "min/max" to handle sign mismatch. if (min(EType.min, needle) == EType.min && max(EType.max, needle) == EType.max) { ptr = cast(EType*) memchr(haystack.ptr, needle, haystack.length); } return ptr ? haystack[ptr - haystack.ptr .. $] : haystack[$ .. $]; } if (!__ctfe) return findHelper(haystack, needle); } //Default implementation. foreach (i, ref e; haystack) if (predFun(e, needle)) return haystack[i .. $]; return haystack[$ .. $]; } else { //Everything else. Walk. for ( ; !haystack.empty; haystack.popFront() ) { if (predFun(haystack.front, needle)) break; } return haystack; } } /// @safe unittest { import std.algorithm.comparison : equal; import std.container : SList; assert(find("hello, world", ',') == ", world"); assert(find([1, 2, 3, 5], 4) == []); assert(equal(find(SList!int(1, 2, 3, 4, 5)[], 4), SList!int(4, 5)[])); assert(find!"a > b"([1, 2, 3, 5], 2) == [3, 5]); auto a = [ 1, 2, 3 ]; assert(find(a, 5).empty); // not found assert(!find(a, 2).empty); // found // Case-insensitive find of a string string[] s = [ "Hello", "world", "!" ]; assert(!find!("toLower(a) == b")(s, "hello").empty); } @safe unittest { import std.algorithm.comparison : equal; import std.container : SList; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto lst = SList!int(1, 2, 5, 7, 3); assert(lst.front == 1); auto r = find(lst[], 5); assert(equal(r, SList!int(5, 7, 3)[])); assert(find([1, 2, 3, 5], 4).empty); assert(equal(find!"a > b"("hello", 'k'), "llo")); } @safe pure nothrow unittest { int[] a1 = [1, 2, 3]; assert(!find ([1, 2, 3], 2).empty); assert(!find!((a,b)=>a==b)([1, 2, 3], 2).empty); ubyte[] a2 = [1, 2, 3]; ubyte b2 = 2; assert(!find ([1, 2, 3], 2).empty); assert(!find!((a,b)=>a==b)([1, 2, 3], 2).empty); } @safe pure unittest { import std.meta : AliasSeq; foreach(R; AliasSeq!(string, wstring, dstring)) { foreach(E; AliasSeq!(char, wchar, dchar)) { R r1 = "hello world"; E e1 = 'w'; assert(find ("hello world", 'w') == "world"); assert(find!((a,b)=>a==b)("hello world", 'w') == "world"); R r2 = "日c語"; E e2 = 'c'; assert(find ("日c語", 'c') == "c語"); assert(find!((a,b)=>a==b)("日c語", 'c') == "c語"); static if (E.sizeof >= 2) { R r3 = "hello world"; E e3 = 'w'; assert(find ("日本語", '本') == "本語"); assert(find!((a,b)=>a==b)("日本語", '本') == "本語"); } } } } @safe unittest { //CTFE static assert (find("abc", 'b') == "bc"); static assert (find("日b語", 'b') == "b語"); static assert (find("日本語", '本') == "本語"); static assert (find([1, 2, 3], 2) == [2, 3]); int[] a1 = [1, 2, 3]; static assert(find ([1, 2, 3], 2)); static assert(find!((a,b)=>a==b)([1, 2, 3], 2)); ubyte[] a2 = [1, 2, 3]; ubyte b2 = 2; static assert(find ([1, 2, 3], 2)); static assert(find!((a,b)=>a==b)([1, 2, 3], 2)); } @safe unittest { import std.exception : assertCTFEable; import std.meta : AliasSeq; void dg() @safe pure nothrow { byte[] sarr = [1, 2, 3, 4]; ubyte[] uarr = [1, 2, 3, 4]; foreach(arr; AliasSeq!(sarr, uarr)) { foreach(T; AliasSeq!(byte, ubyte, int, uint)) { assert(find(arr, cast(T) 3) == arr[2 .. $]); assert(find(arr, cast(T) 9) == arr[$ .. $]); } assert(find(arr, 256) == arr[$ .. $]); } } dg(); assertCTFEable!dg; } @safe unittest { // Bugzilla 11603 enum Foo : ubyte { A } assert([Foo.A].find(Foo.A).empty == false); ubyte x = 0; assert([x].find(x).empty == false); } /** Advances the input range $(D haystack) by calling $(D haystack.popFront) until either $(D pred(haystack.front)), or $(D haystack.empty). Performs $(BIGOH haystack.length) evaluations of $(D pred). To _find the last element of a bidirectional $(D haystack) satisfying $(D pred), call $(D find!(pred)(retro(haystack))). See $(XREF range, retro). Params: pred = The predicate for determining if a given element is the one being searched for. haystack = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) to search in. Returns: $(D haystack) advanced such that the front element is the one searched for; that is, until $(D binaryFun!pred(haystack.front, needle)) is $(D true). If no such position exists, returns an empty $(D haystack). See_Also: $(WEB sgi.com/tech/stl/find_if.html, STL's find_if) */ InputRange find(alias pred, InputRange)(InputRange haystack) if (isInputRange!InputRange) { alias R = InputRange; alias predFun = unaryFun!pred; static if (isNarrowString!R) { import std.utf : decode; immutable len = haystack.length; size_t i = 0, next = 0; while (next < len) { if (predFun(decode(haystack, next))) return haystack[i .. $]; i = next; } return haystack[$ .. $]; } else static if (!isInfinite!R && hasSlicing!R && is(typeof(haystack[cast(size_t)0 .. $]))) { size_t i = 0; for (auto h = haystack.save; !h.empty; h.popFront()) { if (predFun(h.front)) return haystack[i .. $]; ++i; } return haystack[$ .. $]; } else { //standard range for ( ; !haystack.empty; haystack.popFront() ) { if (predFun(haystack.front)) break; } return haystack; } } /// @safe unittest { auto arr = [ 1, 2, 3, 4, 1 ]; assert(find!("a > 2")(arr) == [ 3, 4, 1 ]); // with predicate alias bool pred(int x) { return x + 1 > 1.5; } assert(find!(pred)(arr) == arr); } @safe pure unittest { //scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] r = [ 1, 2, 3 ]; assert(find!(a=>a > 2)(r) == [3]); bool pred(int x) { return x + 1 > 1.5; } assert(find!(pred)(r) == r); assert(find!(a=>a > 'v')("hello world") == "world"); assert(find!(a=>a%4 == 0)("日本語") == "本語"); } /** Finds the first occurrence of a forward range in another forward range. Performs $(BIGOH walkLength(haystack) * walkLength(needle)) comparisons in the worst case. There are specializations that improve performance by taking advantage of bidirectional or random access in the given ranges (where possible), depending on the statistics of the two ranges' content. Params: pred = The predicate to use for comparing respective elements from the haystack and the needle. Defaults to simple equality $(D "a == b"). haystack = The $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) searched in. needle = The $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) searched for. Returns: $(D haystack) advanced such that $(D needle) is a prefix of it (if no such position exists, returns $(D haystack) advanced to termination). */ R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2 && is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool) && !isRandomAccessRange!R1) { static if (is(typeof(pred == "a == b")) && pred == "a == b" && isSomeString!R1 && isSomeString!R2 && haystack[0].sizeof == needle[0].sizeof) { //return cast(R1) find(representation(haystack), representation(needle)); // Specialization for simple string search alias Representation = Select!(haystack[0].sizeof == 1, ubyte[], Select!(haystack[0].sizeof == 2, ushort[], uint[])); // Will use the array specialization static TO force(TO, T)(T r) @trusted { return cast(TO)r; } return force!R1(.find!(pred, Representation, Representation) (force!Representation(haystack), force!Representation(needle))); } else { return simpleMindedFind!pred(haystack, needle); } } /// @safe unittest { import std.container : SList; assert(find("hello, world", "World").empty); assert(find("hello, world", "wo") == "world"); assert([1, 2, 3, 4].find(SList!int(2, 3)[]) == [2, 3, 4]); alias C = Tuple!(int, "x", int, "y"); auto a = [C(1,0), C(2,0), C(3,1), C(4,0)]; assert(a.find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]); assert(a[1 .. $].find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]); } @safe unittest { import std.container : SList; alias C = Tuple!(int, "x", int, "y"); assert([C(1,0), C(2,0), C(3,1), C(4,0)].find!"a.x == b"(SList!int(2, 3)[]) == [C(2,0), C(3,1), C(4,0)]); } @safe unittest { import std.algorithm.comparison : equal; import std.container : SList; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto lst = SList!int(1, 2, 5, 7, 3); static assert(isForwardRange!(int[])); static assert(isForwardRange!(typeof(lst[]))); auto r = find(lst[], [2, 5]); assert(equal(r, SList!int(2, 5, 7, 3)[])); } // Specialization for searching a random-access range for a // bidirectional range R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isRandomAccessRange!R1 && isBidirectionalRange!R2 && is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool)) { if (needle.empty) return haystack; const needleLength = walkLength(needle.save); if (needleLength > haystack.length) { // @@@BUG@@@ //return haystack[$ .. $]; return haystack[haystack.length .. haystack.length]; } // @@@BUG@@@ // auto needleBack = moveBack(needle); // Stage 1: find the step size_t step = 1; auto needleBack = needle.back; needle.popBack(); for (auto i = needle.save; !i.empty && i.back != needleBack; i.popBack(), ++step) { } // Stage 2: linear find size_t scout = needleLength - 1; for (;;) { if (scout >= haystack.length) { return haystack[haystack.length .. haystack.length]; } if (!binaryFun!pred(haystack[scout], needleBack)) { ++scout; continue; } // Found a match with the last element in the needle auto cand = haystack[scout + 1 - needleLength .. haystack.length]; if (startsWith!pred(cand, needle)) { // found return cand; } // Continue with the stride scout += step; } } @safe unittest { //scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); // @@@BUG@@@ removing static below makes unittest fail static struct BiRange { int[] payload; @property bool empty() { return payload.empty; } @property BiRange save() { return this; } @property ref int front() { return payload[0]; } @property ref int back() { return payload[$ - 1]; } void popFront() { return payload.popFront(); } void popBack() { return payload.popBack(); } } //static assert(isBidirectionalRange!BiRange); auto r = BiRange([1, 2, 3, 10, 11, 4]); //assert(equal(find(r, [3, 10]), BiRange([3, 10, 11, 4]))); //assert(find("abc", "bc").length == 2); debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); //assert(find!"a == b"("abc", "bc").length == 2); } // Leftover specialization: searching a random-access range for a // non-bidirectional forward range R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isRandomAccessRange!R1 && isForwardRange!R2 && !isBidirectionalRange!R2 && is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool)) { static if (!is(ElementType!R1 == ElementType!R2)) { return simpleMindedFind!pred(haystack, needle); } else { // Prepare the search with needle's first element if (needle.empty) return haystack; haystack = .find!pred(haystack, needle.front); static if (hasLength!R1 && hasLength!R2 && is(typeof(takeNone(haystack)) == R1)) { if (needle.length > haystack.length) return takeNone(haystack); } else { if (haystack.empty) return haystack; } needle.popFront(); size_t matchLen = 1; // Loop invariant: haystack[0 .. matchLen] matches everything in // the initial needle that was popped out of needle. for (;;) { // Extend matchLength as much as possible for (;;) { import std.range : takeNone; if (needle.empty || haystack.empty) return haystack; static if (hasLength!R1 && is(typeof(takeNone(haystack)) == R1)) { if (matchLen == haystack.length) return takeNone(haystack); } if (!binaryFun!pred(haystack[matchLen], needle.front)) break; ++matchLen; needle.popFront(); } auto bestMatch = haystack[0 .. matchLen]; haystack.popFront(); haystack = .find!pred(haystack, bestMatch); } } } @safe unittest { import std.container : SList; assert(find([ 1, 2, 3 ], SList!int(2, 3)[]) == [ 2, 3 ]); assert(find([ 1, 2, 1, 2, 3, 3 ], SList!int(2, 3)[]) == [ 2, 3, 3 ]); } //Bug# 8334 @safe unittest { import std.algorithm.iteration : filter; import std.range; auto haystack = [1, 2, 3, 4, 1, 9, 12, 42]; auto needle = [12, 42, 27]; //different overload of find, but it's the base case. assert(find(haystack, needle).empty); assert(find(haystack, takeExactly(filter!"true"(needle), 3)).empty); assert(find(haystack, filter!"true"(needle)).empty); } // Internally used by some find() overloads above. Can't make it // private due to bugs in the compiler. /*private*/ R1 simpleMindedFind(alias pred, R1, R2)(R1 haystack, R2 needle) { enum estimateNeedleLength = hasLength!R1 && !hasLength!R2; static if (hasLength!R1) { static if (!hasLength!R2) size_t estimatedNeedleLength = 0; else immutable size_t estimatedNeedleLength = needle.length; } bool haystackTooShort() { static if (estimateNeedleLength) { return haystack.length < estimatedNeedleLength; } else { return haystack.empty; } } searching: for (;; haystack.popFront()) { if (haystackTooShort()) { // Failed search static if (hasLength!R1) { static if (is(typeof(haystack[haystack.length .. haystack.length]) : R1)) return haystack[haystack.length .. haystack.length]; else return R1.init; } else { assert(haystack.empty); return haystack; } } static if (estimateNeedleLength) size_t matchLength = 0; for (auto h = haystack.save, n = needle.save; !n.empty; h.popFront(), n.popFront()) { if (h.empty || !binaryFun!pred(h.front, n.front)) { // Failed searching n in h static if (estimateNeedleLength) { if (estimatedNeedleLength < matchLength) estimatedNeedleLength = matchLength; } continue searching; } static if (estimateNeedleLength) ++matchLength; } break; } return haystack; } @safe unittest { // Test simpleMindedFind for the case where both haystack and needle have // length. debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); struct CustomString { @safe: string _impl; // This is what triggers issue 7992. @property size_t length() const { return _impl.length; } @property void length(size_t len) { _impl.length = len; } // This is for conformance to the forward range API (we deliberately // make it non-random access so that we will end up in // simpleMindedFind). @property bool empty() const { return _impl.empty; } @property dchar front() const { return _impl.front; } void popFront() { _impl.popFront(); } @property CustomString save() { return this; } } // If issue 7992 occurs, this will throw an exception from calling // popFront() on an empty range. auto r = find(CustomString("a"), CustomString("b")); } /** Finds two or more $(D needles) into a $(D haystack). The predicate $(D pred) is used throughout to compare elements. By default, elements are compared for equality. Params: pred = The predicate to use for comparing elements. haystack = The target of the search. Must be an input range. If any of $(D needles) is a range with elements comparable to elements in $(D haystack), then $(D haystack) must be a forward range such that the search can backtrack. needles = One or more items to search for. Each of $(D needles) must be either comparable to one element in $(D haystack), or be itself a forward range with elements comparable with elements in $(D haystack). Returns: A tuple containing $(D haystack) positioned to match one of the needles and also the 1-based index of the matching element in $(D needles) (0 if none of $(D needles) matched, 1 if $(D needles[0]) matched, 2 if $(D needles[1]) matched...). The first needle to be found will be the one that matches. If multiple needles are found at the same spot in the range, then the shortest one is the one which matches (if multiple needles of the same length are found at the same spot (e.g $(D "a") and $(D 'a')), then the left-most of them in the argument list matches). The relationship between $(D haystack) and $(D needles) simply means that one can e.g. search for individual $(D int)s or arrays of $(D int)s in an array of $(D int)s. In addition, if elements are individually comparable, searches of heterogeneous types are allowed as well: a $(D double[]) can be searched for an $(D int) or a $(D short[]), and conversely a $(D long) can be searched for a $(D float) or a $(D double[]). This makes for efficient searches without the need to coerce one side of the comparison into the other's side type. The complexity of the search is $(BIGOH haystack.length * max(needles.length)). (For needles that are individual items, length is considered to be 1.) The strategy used in searching several subranges at once maximizes cache usage by moving in $(D haystack) as few times as possible. */ Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...) (Range haystack, Ranges needles) if (Ranges.length > 1 && is(typeof(startsWith!pred(haystack, needles)))) { for (;; haystack.popFront()) { size_t r = startsWith!pred(haystack, needles); if (r || haystack.empty) { return tuple(haystack, r); } } } /// @safe unittest { int[] a = [ 1, 4, 2, 3 ]; assert(find(a, 4) == [ 4, 2, 3 ]); assert(find(a, [ 1, 4 ]) == [ 1, 4, 2, 3 ]); assert(find(a, [ 1, 3 ], 4) == tuple([ 4, 2, 3 ], 2)); // Mixed types allowed if comparable assert(find(a, 5, [ 1.2, 3.5 ], 2.0) == tuple([ 2, 3 ], 3)); } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto s1 = "Mary has a little lamb"; //writeln(find(s1, "has a", "has an")); assert(find(s1, "has a", "has an") == tuple("has a little lamb", 1)); assert(find(s1, 't', "has a", "has an") == tuple("has a little lamb", 2)); assert(find(s1, 't', "has a", 'y', "has an") == tuple("y has a little lamb", 3)); assert(find("abc", "bc").length == 2); } @safe unittest { import std.algorithm.internal : rndstuff; import std.meta : AliasSeq; import std.uni : toUpper; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 1, 2, 3 ]; assert(find(a, 5).empty); assert(find(a, 2) == [2, 3]); foreach (T; AliasSeq!(int, double)) { auto b = rndstuff!(T)(); if (!b.length) continue; b[$ / 2] = 200; b[$ / 4] = 200; assert(find(b, 200).length == b.length - b.length / 4); } // Case-insensitive find of a string string[] s = [ "Hello", "world", "!" ]; //writeln(find!("toUpper(a) == toUpper(b)")(s, "hello")); assert(find!("toUpper(a) == toUpper(b)")(s, "hello").length == 3); static bool f(string a, string b) { return toUpper(a) == toUpper(b); } assert(find!(f)(s, "hello").length == 3); } @safe unittest { import std.algorithm.internal : rndstuff; import std.algorithm.comparison : equal; import std.meta : AliasSeq; import std.range : retro; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 1, 2, 3, 2, 6 ]; assert(find(retro(a), 5).empty); assert(equal(find(retro(a), 2), [ 2, 3, 2, 1 ][])); foreach (T; AliasSeq!(int, double)) { auto b = rndstuff!(T)(); if (!b.length) continue; b[$ / 2] = 200; b[$ / 4] = 200; assert(find(retro(b), 200).length == b.length - (b.length - 1) / 2); } } @safe unittest { import std.algorithm.comparison : equal; import std.internal.test.dummyrange; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; int[] b = [ 1, 2, 3 ]; assert(find(a, b) == [ 1, 2, 3, 4, 5 ]); assert(find(b, a).empty); foreach (DummyType; AllDummyRanges) { DummyType d; auto findRes = find(d, 5); assert(equal(findRes, [5,6,7,8,9,10])); } } /** * Finds $(D needle) in $(D haystack) efficiently using the * $(LUCKY Boyer-Moore) method. * * Params: * haystack = A random-access range with length and slicing. * needle = A $(LREF BoyerMooreFinder). * * Returns: * $(D haystack) advanced such that $(D needle) is a prefix of it (if no * such position exists, returns $(D haystack) advanced to termination). */ Range1 find(Range1, alias pred, Range2)( Range1 haystack, BoyerMooreFinder!(pred, Range2) needle) { return needle.beFound(haystack); } @safe unittest { debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); string h = "/homes/aalexand/d/dmd/bin/../lib/libphobos.a(dmain2.o)"~ "(.gnu.linkonce.tmain+0x74): In function `main' undefined reference"~ " to `_Dmain':"; string[] ns = ["libphobos", "function", " undefined", "`", ":"]; foreach (n ; ns) { auto p = find(h, boyerMooreFinder(n)); assert(!p.empty); } } /// @safe unittest { int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; int[] b = [ 1, 2, 3 ]; assert(find(a, boyerMooreFinder(b)) == [ 1, 2, 3, 4, 5 ]); assert(find(b, boyerMooreFinder(a)).empty); } @safe unittest { auto bm = boyerMooreFinder("for"); auto match = find("Moor", bm); assert(match.empty); } // canFind /++ Convenience function. Like find, but only returns whether or not the search was successful. See_Also: $(LREF among) for checking a value against multiple possibilities. +/ template canFind(alias pred="a == b") { import std.meta : allSatisfy; /++ Returns $(D true) if and only if any value $(D v) found in the input range $(D range) satisfies the predicate $(D pred). Performs (at most) $(BIGOH haystack.length) evaluations of $(D pred). +/ bool canFind(Range)(Range haystack) if (is(typeof(find!pred(haystack)))) { return any!pred(haystack); } /++ Returns $(D true) if and only if $(D needle) can be found in $(D range). Performs $(BIGOH haystack.length) evaluations of $(D pred). +/ bool canFind(Range, Element)(Range haystack, Element needle) if (is(typeof(find!pred(haystack, needle)))) { return !find!pred(haystack, needle).empty; } /++ Returns the 1-based index of the first needle found in $(D haystack). If no needle is found, then $(D 0) is returned. So, if used directly in the condition of an if statement or loop, the result will be $(D true) if one of the needles is found and $(D false) if none are found, whereas if the result is used elsewhere, it can either be cast to $(D bool) for the same effect or used to get which needle was found first without having to deal with the tuple that $(D LREF find) returns for the same operation. +/ size_t canFind(Range, Ranges...)(Range haystack, Ranges needles) if (Ranges.length > 1 && allSatisfy!(isForwardRange, Ranges) && is(typeof(find!pred(haystack, needles)))) { return find!pred(haystack, needles)[1]; } } /// @safe unittest { assert(canFind([0, 1, 2, 3], 2) == true); assert(canFind([0, 1, 2, 3], [1, 2], [2, 3])); assert(canFind([0, 1, 2, 3], [1, 2], [2, 3]) == 1); assert(canFind([0, 1, 2, 3], [1, 7], [2, 3])); assert(canFind([0, 1, 2, 3], [1, 7], [2, 3]) == 2); assert(canFind([0, 1, 2, 3], 4) == false); assert(!canFind([0, 1, 2, 3], [1, 3], [2, 4])); assert(canFind([0, 1, 2, 3], [1, 3], [2, 4]) == 0); } /** * Example using a custom predicate. * Note that the needle appears as the second argument of the predicate. */ @safe unittest { auto words = [ "apple", "beeswax", "cardboard" ]; assert(!canFind(words, "bees")); assert( canFind!((string a, string b) => a.startsWith(b))(words, "bees")); } @safe unittest { import std.algorithm.internal : rndstuff; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto a = rndstuff!(int)(); if (a.length) { auto b = a[a.length / 2]; assert(canFind(a, b)); } } @safe unittest { import std.algorithm.comparison : equal; assert(equal!(canFind!"a < b")([[1, 2, 3], [7, 8, 9]], [2, 8])); } // findAdjacent /** Advances $(D r) until it finds the first two adjacent elements $(D a), $(D b) that satisfy $(D pred(a, b)). Performs $(BIGOH r.length) evaluations of $(D pred). Params: pred = The predicate to satisfy. r = A $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) to search in. Returns: $(D r) advanced to the first occurrence of two adjacent elements that satisfy the given predicate. If there are no such two elements, returns $(D r) advanced until empty. See_Also: $(WEB sgi.com/tech/stl/adjacent_find.html, STL's adjacent_find) */ Range findAdjacent(alias pred = "a == b", Range)(Range r) if (isForwardRange!(Range)) { auto ahead = r.save; if (!ahead.empty) { for (ahead.popFront(); !ahead.empty; r.popFront(), ahead.popFront()) { if (binaryFun!(pred)(r.front, ahead.front)) return r; } } static if (!isInfinite!Range) return ahead; } /// @safe unittest { int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ]; auto r = findAdjacent(a); assert(r == [ 10, 10, 9, 8, 8, 7, 8, 9 ]); auto p = findAdjacent!("a < b")(a); assert(p == [ 7, 8, 9 ]); } @safe unittest { import std.algorithm.comparison : equal; import std.internal.test.dummyrange; import std.range; //scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ]; auto p = findAdjacent(a); assert(p == [10, 10, 9, 8, 8, 7, 8, 9 ]); p = findAdjacent!("a < b")(a); assert(p == [7, 8, 9]); // empty a = []; p = findAdjacent(a); assert(p.empty); // not found a = [ 1, 2, 3, 4, 5 ]; p = findAdjacent(a); assert(p.empty); p = findAdjacent!"a > b"(a); assert(p.empty); ReferenceForwardRange!int rfr = new ReferenceForwardRange!int([1, 2, 3, 2, 2, 3]); assert(equal(findAdjacent(rfr), [2, 2, 3])); // Issue 9350 assert(!repeat(1).findAdjacent().empty); } // findAmong /** Searches the given range for an element that matches one of the given choices. Advances $(D seq) by calling $(D seq.popFront) until either $(D find!(pred)(choices, seq.front)) is $(D true), or $(D seq) becomes empty. Performs $(BIGOH seq.length * choices.length) evaluations of $(D pred). Params: pred = The predicate to use for determining a match. seq = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) to search. choices = A $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) of possible choices. Returns: $(D seq) advanced to the first matching element, or until empty if there are no matching elements. See_Also: $(WEB sgi.com/tech/stl/find_first_of.html, STL's find_first_of) */ Range1 findAmong(alias pred = "a == b", Range1, Range2)( Range1 seq, Range2 choices) if (isInputRange!Range1 && isForwardRange!Range2) { for (; !seq.empty && find!pred(choices, seq.front).empty; seq.popFront()) { } return seq; } /// @safe unittest { int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; int[] b = [ 3, 1, 2 ]; assert(findAmong(a, b) == a[2 .. $]); } @safe unittest { //scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ -1, 0, 2, 1, 2, 3, 4, 5 ]; int[] b = [ 1, 2, 3 ]; assert(findAmong(a, b) == [2, 1, 2, 3, 4, 5 ]); assert(findAmong(b, [ 4, 6, 7 ][]).empty); assert(findAmong!("a == b")(a, b).length == a.length - 2); assert(findAmong!("a == b")(b, [ 4, 6, 7 ][]).empty); } // findSkip /** * Finds $(D needle) in $(D haystack) and positions $(D haystack) * right after the first occurrence of $(D needle). * * Params: * haystack = The * $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) to search * in. * needle = The * $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) to search * for. * * Returns: $(D true) if the needle was found, in which case $(D haystack) is * positioned after the end of the first occurrence of $(D needle); otherwise * $(D false), leaving $(D haystack) untouched. */ bool findSkip(alias pred = "a == b", R1, R2)(ref R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2 && is(typeof(binaryFun!pred(haystack.front, needle.front)))) { auto parts = findSplit!pred(haystack, needle); if (parts[1].empty) return false; // found haystack = parts[2]; return true; } /// @safe unittest { // Needle is found; s is replaced by the substring following the first // occurrence of the needle. string s = "abcdef"; assert(findSkip(s, "cd") && s == "ef"); // Needle is not found; s is left untouched. s = "abcdef"; assert(!findSkip(s, "cxd") && s == "abcdef"); // If the needle occurs at the end of the range, the range is left empty. s = "abcdef"; assert(findSkip(s, "def") && s.empty); } /** These functions find the first occurrence of `needle` in `haystack` and then split `haystack` as follows. `findSplit` returns a tuple `result` containing $(I three) ranges. `result[0]` is the portion of `haystack` before `needle`, `result[1]` is the portion of `haystack` that matches `needle`, and `result[2]` is the portion of `haystack` after the match. If `needle` was not found, `result[0]` comprehends `haystack` entirely and `result[1]` and `result[2]` are empty. `findSplitBefore` returns a tuple `result` containing two ranges. `result[0]` is the portion of `haystack` before `needle`, and `result[1]` is the balance of `haystack` starting with the match. If `needle` was not found, `result[0]` comprehends `haystack` entirely and `result[1]` is empty. `findSplitAfter` returns a tuple `result` containing two ranges. `result[0]` is the portion of `haystack` up to and including the match, and `result[1]` is the balance of `haystack` starting after the match. If `needle` was not found, `result[0]` is empty and `result[1]` is `haystack`. In all cases, the concatenation of the returned ranges spans the entire `haystack`. If `haystack` is a random-access range, all three components of the tuple have the same type as `haystack`. Otherwise, `haystack` must be a forward range and the type of `result[0]` and `result[1]` is the same as $(XREF range,takeExactly). Params: pred = Predicate to use for comparing needle against haystack. haystack = The range to search. needle = What to look for. Returns: A sub-type of `Tuple!()` of the split portions of `haystack` (see above for details). This sub-type of `Tuple!()` has `opCast` defined for `bool`. This `opCast` returns `true` when the separating `needle` was found (`!result[1].empty`) and `false` otherwise. This enables the convenient idiom shown in the following example. Example: --- if (const split = haystack.findSplit(needle)) { doSomethingWithSplit(split); } --- */ auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2) { static struct Result(S1, S2) if (isForwardRange!S1 && isForwardRange!S2) { this(S1 pre, S1 separator, S2 post) { asTuple = typeof(asTuple)(pre, separator, post); } Tuple!(S1, S1, S2) asTuple; bool opCast(T : bool)() { return !asTuple[1].empty; } alias asTuple this; } static if (isSomeString!R1 && isSomeString!R2 || isRandomAccessRange!R1 && hasLength!R2) { auto balance = find!pred(haystack, needle); immutable pos1 = haystack.length - balance.length; immutable pos2 = balance.empty ? pos1 : pos1 + needle.length; return Result!(typeof(haystack[0 .. pos1]), typeof(haystack[pos2 .. haystack.length]))(haystack[0 .. pos1], haystack[pos1 .. pos2], haystack[pos2 .. haystack.length]); } else { import std.range : takeExactly; auto original = haystack.save; auto h = haystack.save; auto n = needle.save; size_t pos1, pos2; while (!n.empty && !h.empty) { if (binaryFun!pred(h.front, n.front)) { h.popFront(); n.popFront(); ++pos2; } else { haystack.popFront(); n = needle.save; h = haystack.save; pos2 = ++pos1; } } return Result!(typeof(takeExactly(original, pos1)), typeof(h))(takeExactly(original, pos1), takeExactly(haystack, pos2 - pos1), h); } } /// Ditto auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2) { static struct Result(S1, S2) if (isForwardRange!S1 && isForwardRange!S2) { this(S1 pre, S2 post) { asTuple = typeof(asTuple)(pre, post); } Tuple!(S1, S2) asTuple; bool opCast(T : bool)() { return !asTuple[0].empty; } alias asTuple this; } static if (isSomeString!R1 && isSomeString!R2 || isRandomAccessRange!R1 && hasLength!R2) { auto balance = find!pred(haystack, needle); immutable pos = haystack.length - balance.length; return Result!(typeof(haystack[0 .. pos]), typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos], haystack[pos .. haystack.length]); } else { import std.range : takeExactly; auto original = haystack.save; auto h = haystack.save; auto n = needle.save; size_t pos; while (!n.empty && !h.empty) { if (binaryFun!pred(h.front, n.front)) { h.popFront(); n.popFront(); } else { haystack.popFront(); n = needle.save; h = haystack.save; ++pos; } } return Result!(typeof(takeExactly(original, pos)), typeof(haystack))(takeExactly(original, pos), haystack); } } /// Ditto auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2) { static struct Result(S1, S2) if (isForwardRange!S1 && isForwardRange!S2) { this(S1 pre, S2 post) { asTuple = typeof(asTuple)(pre, post); } Tuple!(S1, S2) asTuple; bool opCast(T : bool)() { return !asTuple[1].empty; } alias asTuple this; } static if (isSomeString!R1 && isSomeString!R2 || isRandomAccessRange!R1 && hasLength!R2) { auto balance = find!pred(haystack, needle); immutable pos = balance.empty ? 0 : haystack.length - balance.length + needle.length; return Result!(typeof(haystack[0 .. pos]), typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos], haystack[pos .. haystack.length]); } else { import std.range : takeExactly; auto original = haystack.save; auto h = haystack.save; auto n = needle.save; size_t pos1, pos2; while (!n.empty) { if (h.empty) { // Failed search return Result!(typeof(takeExactly(original, 0)), typeof(original))(takeExactly(original, 0), original); } if (binaryFun!pred(h.front, n.front)) { h.popFront(); n.popFront(); ++pos2; } else { haystack.popFront(); n = needle.save; h = haystack.save; pos2 = ++pos1; } } return Result!(typeof(takeExactly(original, pos2)), typeof(h))(takeExactly(original, pos2), h); } } /// @safe unittest { auto a = "Carl Sagan Memorial Station"; auto r = findSplit(a, "Velikovsky"); import std.typecons : isTuple; static assert(isTuple!(typeof(r.asTuple))); static assert(isTuple!(typeof(r))); assert(!r); assert(r[0] == a); assert(r[1].empty); assert(r[2].empty); r = findSplit(a, " "); assert(r[0] == "Carl"); assert(r[1] == " "); assert(r[2] == "Sagan Memorial Station"); auto r1 = findSplitBefore(a, "Sagan"); assert(r1); assert(r1[0] == "Carl ", r1[0]); assert(r1[1] == "Sagan Memorial Station"); auto r2 = findSplitAfter(a, "Sagan"); assert(r2); assert(r2[0] == "Carl Sagan"); assert(r2[1] == " Memorial Station"); } @safe unittest { auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; auto r = findSplit(a, [9, 1]); assert(!r); assert(r[0] == a); assert(r[1].empty); assert(r[2].empty); r = findSplit(a, [3]); assert(r); assert(r[0] == a[0 .. 2]); assert(r[1] == a[2 .. 3]); assert(r[2] == a[3 .. $]); auto r1 = findSplitBefore(a, [9, 1]); assert(r1); assert(r1[0] == a); assert(r1[1].empty); r1 = findSplitBefore(a, [3, 4]); assert(r1); assert(r1[0] == a[0 .. 2]); assert(r1[1] == a[2 .. $]); auto r2 = findSplitAfter(a, [9, 1]); assert(r2); assert(r2[0].empty); assert(r2[1] == a); r2 = findSplitAfter(a, [3, 4]); assert(r2); assert(r2[0] == a[0 .. 4]); assert(r2[1] == a[4 .. $]); } @safe unittest { import std.algorithm.comparison : equal; import std.algorithm.iteration : filter; auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; auto fwd = filter!"a > 0"(a); auto r = findSplit(fwd, [9, 1]); assert(!r); assert(equal(r[0], a)); assert(r[1].empty); assert(r[2].empty); r = findSplit(fwd, [3]); assert(r); assert(equal(r[0], a[0 .. 2])); assert(equal(r[1], a[2 .. 3])); assert(equal(r[2], a[3 .. $])); auto r1 = findSplitBefore(fwd, [9, 1]); assert(r1); assert(equal(r1[0], a)); assert(r1[1].empty); r1 = findSplitBefore(fwd, [3, 4]); assert(r1); assert(equal(r1[0], a[0 .. 2])); assert(equal(r1[1], a[2 .. $])); auto r2 = findSplitAfter(fwd, [9, 1]); assert(r2); assert(r2[0].empty); assert(equal(r2[1], a)); r2 = findSplitAfter(fwd, [3, 4]); assert(r2); assert(equal(r2[0], a[0 .. 4])); assert(equal(r2[1], a[4 .. $])); } // minCount /** Computes the minimum (respectively maximum) of `range` along with its number of occurrences. Formally, the minimum is a value `x` in `range` such that $(D pred(a, x)) is `false` for all values `a` in `range`. Conversely, the maximum is a value `x` in `range` such that $(D pred(x, a)) is `false` for all values `a` in `range` (note the swapped arguments to `pred`). These functions may be used for computing arbitrary extrema by choosing `pred` appropriately. For corrrect functioning, `pred` must be a strict partial order, i.e. transitive (if $(D pred(a, b) && pred(b, c)) then $(D pred(a, c))) and irreflexive ($(D pred(a, a)) is `false`). The $(LUCKY trichotomy property of inequality) is not required: these algoritms consider elements `a` and `b` equal (for the purpose of counting) if `pred` puts them in the same equivalence class, i.e. $(D !pred(a, b) && !pred(b, a)). Params: pred = The ordering predicate to use to determine the extremum (minimum or maximum). range = The input range to count. Returns: The minimum, respectively maximum element of a range together with the number it occurs in the range. Throws: `Exception` if `range.empty`. */ Tuple!(ElementType!Range, size_t) minCount(alias pred = "a < b", Range)(Range range) if (isInputRange!Range && !isInfinite!Range && is(typeof(binaryFun!pred(range.front, range.front)))) { import std.algorithm.internal : algoFormat; import std.exception : enforce; alias T = ElementType!Range; alias UT = Unqual!T; alias RetType = Tuple!(T, size_t); static assert (is(typeof(RetType(range.front, 1))), algoFormat("Error: Cannot call minCount on a %s, because it is not possible "~ "to copy the result value (a %s) into a Tuple.", Range.stringof, T.stringof)); enforce(!range.empty, "Can't count elements from an empty range"); size_t occurrences = 1; static if (isForwardRange!Range) { Range least = range.save; for (range.popFront(); !range.empty; range.popFront()) { if (binaryFun!pred(least.front, range.front)) { assert(!binaryFun!pred(range.front, least.front), "min/maxPos: predicate must be a strict partial order."); continue; } if (binaryFun!pred(range.front, least.front)) { // change the min least = range.save; occurrences = 1; } else ++occurrences; } return RetType(least.front, occurrences); } else static if (isAssignable!(UT, T) || (!hasElaborateAssign!UT && isAssignable!UT)) { UT v = UT.init; static if (isAssignable!(UT, T)) v = range.front; else v = cast(UT)range.front; for (range.popFront(); !range.empty; range.popFront()) { if (binaryFun!pred(*cast(T*)&v, range.front)) continue; if (binaryFun!pred(range.front, *cast(T*)&v)) { // change the min static if (isAssignable!(UT, T)) v = range.front; else v = cast(UT)range.front; //Safe because !hasElaborateAssign!UT occurrences = 1; } else ++occurrences; } return RetType(*cast(T*)&v, occurrences); } else static if (hasLvalueElements!Range) { import std.algorithm.internal : addressOf; T* p = addressOf(range.front); for (range.popFront(); !range.empty; range.popFront()) { if (binaryFun!pred(*p, range.front)) continue; if (binaryFun!pred(range.front, *p)) { // change the min p = addressOf(range.front); occurrences = 1; } else ++occurrences; } return RetType(*p, occurrences); } else static assert(false, algoFormat("Sorry, can't find the minCount of a %s: Don't know how "~ "to keep track of the smallest %s element.", Range.stringof, T.stringof)); } /// Ditto Tuple!(ElementType!Range, size_t) maxCount(alias pred = "a < b", Range)(Range range) if (isInputRange!Range && !isInfinite!Range && is(typeof(binaryFun!pred(range.front, range.front)))) { return range.minCount!((a, b) => binaryFun!pred(b, a)); } /// unittest { import std.conv : text; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; // Minimum is 1 and occurs 3 times assert(a.minCount == tuple(1, 3)); // Maximum is 4 and occurs 2 times assert(a.maxCount == tuple(4, 2)); } unittest { import std.conv : text; import std.exception : assertThrown; import std.internal.test.dummyrange; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[][] b = [ [4], [2, 4], [4], [4] ]; auto c = minCount!("a[0] < b[0]")(b); assert(c == tuple([2, 4], 1), text(c[0])); //Test empty range assertThrown(minCount(b[$..$])); //test with reference ranges. Test both input and forward. assert(minCount(new ReferenceInputRange!int([1, 2, 1, 0, 2, 0])) == tuple(0, 2)); assert(minCount(new ReferenceForwardRange!int([1, 2, 1, 0, 2, 0])) == tuple(0, 2)); } unittest { import std.conv : text; import std.meta : AliasSeq; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); static struct R(T) //input range { T[] arr; alias arr this; } immutable a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; R!(immutable int) b = R!(immutable int)(a); assert(minCount(a) == tuple(1, 3)); assert(minCount(b) == tuple(1, 3)); assert(minCount!((ref immutable int a, ref immutable int b) => (a > b))(a) == tuple(4, 2)); assert(minCount!((ref immutable int a, ref immutable int b) => (a > b))(b) == tuple(4, 2)); immutable(int[])[] c = [ [4], [2, 4], [4], [4] ]; assert(minCount!("a[0] < b[0]")(c) == tuple([2, 4], 1), text(c[0])); static struct S1 { int i; } alias IS1 = immutable(S1); static assert( isAssignable!S1); static assert( isAssignable!(S1, IS1)); static struct S2 { int* p; this(ref immutable int i) immutable {p = &i;} this(ref int i) {p = &i;} @property ref inout(int) i() inout {return *p;} bool opEquals(const S2 other) const {return i == other.i;} } alias IS2 = immutable(S2); static assert( isAssignable!S2); static assert(!isAssignable!(S2, IS2)); static assert(!hasElaborateAssign!S2); static struct S3 { int i; void opAssign(ref S3 other) @disable; } static assert(!isAssignable!S3); foreach (Type; AliasSeq!(S1, IS1, S2, IS2, S3)) { static if (is(Type == immutable)) alias V = immutable int; else alias V = int; V one = 1, two = 2; auto r1 = [Type(two), Type(one), Type(one)]; auto r2 = R!Type(r1); assert(minCount!"a.i < b.i"(r1) == tuple(Type(one), 2)); assert(minCount!"a.i < b.i"(r2) == tuple(Type(one), 2)); assert(one == 1 && two == 2); } } // minPos /** Computes a subrange of `range` starting at the first occurrence of `range`'s minimum (respectively maximum) and with the same ending as `range`, or the empty range if `range` itself is empty. Formally, the minimum is a value `x` in `range` such that $(D pred(a, x)) is `false` for all values `a` in `range`. Conversely, the maximum is a value `x` in `range` such that $(D pred(x, a)) is `false` for all values `a` in `range` (note the swapped arguments to `pred`). These functions may be used for computing arbitrary extrema by choosing `pred` appropriately. For corrrect functioning, `pred` must be a strict partial order, i.e. transitive (if $(D pred(a, b) && pred(b, c)) then $(D pred(a, c))) and irreflexive ($(D pred(a, a)) is `false`). Params: pred = The ordering predicate to use to determine the extremum (minimum or maximum) element. range = The input range to search. Returns: The position of the minimum (respectively maximum) element of forward range `range`, i.e. a subrange of `range` starting at the position of its smallest (respectively largest) element and with the same ending as `range`. */ Range minPos(alias pred = "a < b", Range)(Range range) if (isForwardRange!Range && !isInfinite!Range && is(typeof(binaryFun!pred(range.front, range.front)))) { static if (hasSlicing!Range && isRandomAccessRange!Range && hasLength!Range) { // Prefer index-based access size_t pos = 0; foreach (i; 1 .. range.length) { if (binaryFun!pred(range[i], range[pos])) { pos = i; } } return range[pos .. $]; } else { auto result = range.save; if (range.empty) return result; for (range.popFront(); !range.empty; range.popFront()) { // Note: Unlike minCount, we do not care to find equivalence, so a // single pred call is enough. if (binaryFun!pred(range.front, result.front)) { // change the min result = range.save; } } return result; } } /// Ditto Range maxPos(alias pred = "a < b", Range)(Range range) if (isForwardRange!Range && !isInfinite!Range && is(typeof(binaryFun!pred(range.front, range.front)))) { return range.minPos!((a, b) => binaryFun!pred(b, a)); } /// @safe unittest { int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; // Minimum is 1 and first occurs in position 3 assert(a.minPos == [ 1, 2, 4, 1, 1, 2 ]); // Maximum is 4 and first occurs in position 2 assert(a.maxPos == [ 4, 1, 2, 4, 1, 1, 2 ]); } @safe unittest { import std.algorithm.comparison : equal; import std.internal.test.dummyrange; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; //Test that an empty range works int[] b = a[$..$]; assert(equal(minPos(b), b)); //test with reference range. assert( equal( minPos(new ReferenceForwardRange!int([1, 2, 1, 0, 2, 0])), [0, 2, 0] ) ); } unittest { //Rvalue range import std.algorithm.comparison : equal; import std.container : Array; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); assert(Array!int(2, 3, 4, 1, 2, 4, 1, 1, 2) [] .minPos() .equal([ 1, 2, 4, 1, 1, 2 ])); } @safe unittest { //BUG 9299 debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); immutable a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; // Minimum is 1 and first occurs in position 3 assert(minPos(a) == [ 1, 2, 4, 1, 1, 2 ]); // Maximum is 4 and first occurs in position 5 assert(minPos!("a > b")(a) == [ 4, 1, 2, 4, 1, 1, 2 ]); immutable(int[])[] b = [ [4], [2, 4], [4], [4] ]; assert(minPos!("a[0] < b[0]")(b) == [ [2, 4], [4], [4] ]); } /** Skip over the initial portion of the first given range that matches the second range, or do nothing if there is no match. Params: pred = The predicate that determines whether elements from each respective range match. Defaults to equality $(D "a == b"). r1 = The $(XREF_PACK_NAMED range,primitives,isForwardRange,forward range) to move forward. r2 = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) representing the initial segment of $(D r1) to skip over. Returns: true if the initial segment of $(D r1) matches $(D r2), and $(D r1) has been advanced to the point past this segment; otherwise false, and $(D r1) is left in its original position. */ bool skipOver(R1, R2)(ref R1 r1, R2 r2) if (isForwardRange!R1 && isInputRange!R2 && is(typeof(r1.front == r2.front))) { static if (is(typeof(r1[0 .. $] == r2) : bool) && is(typeof(r2.length > r1.length) : bool) && is(typeof(r1 = r1[r2.length .. $]))) { if (r2.length > r1.length || r1[0 .. r2.length] != r2) { return false; } r1 = r1[r2.length .. $]; return true; } else { return skipOver!((a, b) => a == b)(r1, r2); } } /// Ditto bool skipOver(alias pred, R1, R2)(ref R1 r1, R2 r2) if (is(typeof(binaryFun!pred(r1.front, r2.front))) && isForwardRange!R1 && isInputRange!R2) { static if (hasLength!R1 && hasLength!R2) { // Shortcut opportunity! if (r2.length > r1.length) return false; } auto r = r1.save; while (!r2.empty && !r.empty && binaryFun!pred(r.front, r2.front)) { r.popFront(); r2.popFront(); } if (r2.empty) r1 = r; return r2.empty; } /// @safe unittest { import std.algorithm.comparison : equal; auto s1 = "Hello world"; assert(!skipOver(s1, "Ha")); assert(s1 == "Hello world"); assert(skipOver(s1, "Hell") && s1 == "o world"); string[] r1 = ["abc", "def", "hij"]; dstring[] r2 = ["abc"d]; assert(!skipOver!((a, b) => a.equal(b))(r1, ["def"d])); assert(r1 == ["abc", "def", "hij"]); assert(skipOver!((a, b) => a.equal(b))(r1, r2)); assert(r1 == ["def", "hij"]); } /** Skip over the first element of the given range if it matches the given element, otherwise do nothing. Params: pred = The predicate that determines whether an element from the range matches the given element. r = The $(XREF_PACK_NAMED range,primitives,isInputRange,input range) to skip over. e = The element to match. Returns: true if the first element matches the given element according to the given predicate, and the range has been advanced by one element; otherwise false, and the range is left untouched. */ bool skipOver(R, E)(ref R r, E e) if (isInputRange!R && is(typeof(r.front == e) : bool)) { return skipOver!((a, b) => a == b)(r, e); } /// Ditto bool skipOver(alias pred, R, E)(ref R r, E e) if (is(typeof(binaryFun!pred(r.front, e))) && isInputRange!R) { if (r.empty || !binaryFun!pred(r.front, e)) return false; r.popFront(); return true; } /// @safe unittest { import std.algorithm.comparison : equal; auto s1 = "Hello world"; assert(!skipOver(s1, 'a')); assert(s1 == "Hello world"); assert(skipOver(s1, 'H') && s1 == "ello world"); string[] r = ["abc", "def", "hij"]; dstring e = "abc"d; assert(!skipOver!((a, b) => a.equal(b))(r, "def"d)); assert(r == ["abc", "def", "hij"]); assert(skipOver!((a, b) => a.equal(b))(r, e)); assert(r == ["def", "hij"]); auto s2 = ""; assert(!s2.skipOver('a')); } /** Checks whether the given $(XREF_PACK_NAMED range,primitives,isInputRange,input range) starts with (one of) the given needle(s) or, if no needles are given, if its front element fulfils predicate $(D pred). Params: pred = Predicate to use in comparing the elements of the haystack and the needle(s). Mandatory if no needles are given. doesThisStart = The input range to check. withOneOfThese = The needles against which the range is to be checked, which may be individual elements or input ranges of elements. withThis = The single needle to check, which may be either a single element or an input range of elements. Returns: 0 if the needle(s) do not occur at the beginning of the given range; otherwise the position of the matching needle, that is, 1 if the range starts with $(D withOneOfThese[0]), 2 if it starts with $(D withOneOfThese[1]), and so on. In the case where $(D doesThisStart) starts with multiple of the ranges or elements in $(D withOneOfThese), then the shortest one matches (if there are two which match which are of the same length (e.g. $(D "a") and $(D 'a')), then the left-most of them in the argument list matches). In the case when no needle parameters are given, return $(D true) iff front of $(D doesThisStart) fulfils predicate $(D pred). */ uint startsWith(alias pred = "a == b", Range, Needles...)(Range doesThisStart, Needles withOneOfThese) if (isInputRange!Range && Needles.length > 1 && is(typeof(.startsWith!pred(doesThisStart, withOneOfThese[0])) : bool ) && is(typeof(.startsWith!pred(doesThisStart, withOneOfThese[1 .. $])) : uint)) { alias haystack = doesThisStart; alias needles = withOneOfThese; // Make one pass looking for empty ranges in needles foreach (i, Unused; Needles) { // Empty range matches everything static if (!is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool)) { if (needles[i].empty) return i + 1; } } for (; !haystack.empty; haystack.popFront()) { foreach (i, Unused; Needles) { static if (is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool)) { // Single-element if (binaryFun!pred(haystack.front, needles[i])) { // found, but instead of returning, we just stop searching. // This is to account for one-element // range matches (consider startsWith("ab", "a", // 'a') should return 1, not 2). break; } } else { if (binaryFun!pred(haystack.front, needles[i].front)) { continue; } } // This code executed on failure to match // Out with this guy, check for the others uint result = startsWith!pred(haystack, needles[0 .. i], needles[i + 1 .. $]); if (result > i) ++result; return result; } // If execution reaches this point, then the front matches for all // needle ranges, or a needle element has been matched. // What we need to do now is iterate, lopping off the front of // the range and checking if the result is empty, or finding an // element needle and returning. // If neither happens, we drop to the end and loop. foreach (i, Unused; Needles) { static if (is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool)) { // Test has passed in the previous loop return i + 1; } else { needles[i].popFront(); if (needles[i].empty) return i + 1; } } } return 0; } /// Ditto bool startsWith(alias pred = "a == b", R1, R2)(R1 doesThisStart, R2 withThis) if (isInputRange!R1 && isInputRange!R2 && is(typeof(binaryFun!pred(doesThisStart.front, withThis.front)) : bool)) { alias haystack = doesThisStart; alias needle = withThis; static if (is(typeof(pred) : string)) enum isDefaultPred = pred == "a == b"; else enum isDefaultPred = false; //Note: While narrow strings don't have a "true" length, for a narrow string to start with another //narrow string *of the same type*, it must have *at least* as many code units. static if ((hasLength!R1 && hasLength!R2) || (isNarrowString!R1 && isNarrowString!R2 && ElementEncodingType!R1.sizeof == ElementEncodingType!R2.sizeof)) { if (haystack.length < needle.length) return false; } static if (isDefaultPred && isArray!R1 && isArray!R2 && is(Unqual!(ElementEncodingType!R1) == Unqual!(ElementEncodingType!R2))) { //Array slice comparison mode return haystack[0 .. needle.length] == needle; } else static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && hasLength!R2) { //RA dual indexing mode foreach (j; 0 .. needle.length) { if (!binaryFun!pred(haystack[j], needle[j])) // not found return false; } // found! return true; } else { //Standard input range mode if (needle.empty) return true; static if (hasLength!R1 && hasLength!R2) { //We have previously checked that haystack.length > needle.length, //So no need to check haystack.empty during iteration for ( ; ; haystack.popFront() ) { if (!binaryFun!pred(haystack.front, needle.front)) break; needle.popFront(); if (needle.empty) return true; } } else { for ( ; !haystack.empty ; haystack.popFront() ) { if (!binaryFun!pred(haystack.front, needle.front)) break; needle.popFront(); if (needle.empty) return true; } } return false; } } /// Ditto bool startsWith(alias pred = "a == b", R, E)(R doesThisStart, E withThis) if (isInputRange!R && is(typeof(binaryFun!pred(doesThisStart.front, withThis)) : bool)) { return doesThisStart.empty ? false : binaryFun!pred(doesThisStart.front, withThis); } /// Ditto bool startsWith(alias pred, R)(R doesThisStart) if (isInputRange!R && ifTestable!(typeof(doesThisStart.front), unaryFun!pred)) { return !doesThisStart.empty && unaryFun!pred(doesThisStart.front); } /// @safe unittest { import std.ascii : isAlpha; assert("abc".startsWith!(a => a.isAlpha)); assert("abc".startsWith!isAlpha); assert(!"1ab".startsWith!(a => a.isAlpha)); assert(!"".startsWith!(a => a.isAlpha)); import std.algorithm.comparison : among; assert("abc".startsWith!(a => a.among('a', 'b') != 0)); assert(!"abc".startsWith!(a => a.among('b', 'c') != 0)); assert(startsWith("abc", "")); assert(startsWith("abc", "a")); assert(!startsWith("abc", "b")); assert(startsWith("abc", 'a', "b") == 1); assert(startsWith("abc", "b", "a") == 2); assert(startsWith("abc", "a", "a") == 1); assert(startsWith("abc", "ab", "a") == 2); assert(startsWith("abc", "x", "a", "b") == 2); assert(startsWith("abc", "x", "aa", "ab") == 3); assert(startsWith("abc", "x", "aaa", "sab") == 0); assert(startsWith("abc", "x", "aaa", "a", "sab") == 3); alias C = Tuple!(int, "x", int, "y"); assert(startsWith!"a.x == b"([ C(1,1), C(1,2), C(2,2) ], [1, 1])); assert(startsWith!"a.x == b"([ C(1,1), C(2,1), C(2,2) ], [1, 1], [1, 2], [1, 3]) == 2); } @safe unittest { import std.algorithm.iteration : filter; import std.conv : to; import std.meta : AliasSeq; import std.range; debug(std_algorithm) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { assert(!startsWith(to!S("abc"), 'c')); assert(startsWith(to!S("abc"), 'a', 'c') == 1); assert(!startsWith(to!S("abc"), 'x', 'n', 'b')); assert(startsWith(to!S("abc"), 'x', 'n', 'a') == 3); assert(startsWith(to!S("\uFF28abc"), 'a', '\uFF28', 'c') == 2); foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 //Lots of strings assert(startsWith(to!S("abc"), to!T(""))); assert(startsWith(to!S("ab"), to!T("a"))); assert(startsWith(to!S("abc"), to!T("a"))); assert(!startsWith(to!S("abc"), to!T("b"))); assert(!startsWith(to!S("abc"), to!T("b"), "bc", "abcd", "xyz")); assert(startsWith(to!S("abc"), to!T("ab"), 'a') == 2); assert(startsWith(to!S("abc"), to!T("a"), "b") == 1); assert(startsWith(to!S("abc"), to!T("b"), "a") == 2); assert(startsWith(to!S("abc"), to!T("a"), 'a') == 1); assert(startsWith(to!S("abc"), 'a', to!T("a")) == 1); assert(startsWith(to!S("abc"), to!T("x"), "a", "b") == 2); assert(startsWith(to!S("abc"), to!T("x"), "aa", "ab") == 3); assert(startsWith(to!S("abc"), to!T("x"), "aaa", "sab") == 0); assert(startsWith(to!S("abc"), 'a')); assert(!startsWith(to!S("abc"), to!T("sab"))); assert(startsWith(to!S("abc"), 'x', to!T("aaa"), 'a', "sab") == 3); //Unicode assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("\uFF28el"))); assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("Hel"), to!T("\uFF28el")) == 2); assert(startsWith(to!S("日本語"), to!T("日本"))); assert(startsWith(to!S("日本語"), to!T("日本語"))); assert(!startsWith(to!S("日本"), to!T("日本語"))); //Empty assert(startsWith(to!S(""), T.init)); assert(!startsWith(to!S(""), 'a')); assert(startsWith(to!S("a"), T.init)); assert(startsWith(to!S("a"), T.init, "") == 1); assert(startsWith(to!S("a"), T.init, 'a') == 1); assert(startsWith(to!S("a"), 'a', T.init) == 2); }(); } //Length but no RA assert(!startsWith("abc".takeExactly(3), "abcd".takeExactly(4))); assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(3))); assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(1))); foreach (T; AliasSeq!(int, short)) { immutable arr = cast(T[])[0, 1, 2, 3, 4, 5]; //RA range assert(startsWith(arr, cast(int[])null)); assert(!startsWith(arr, 5)); assert(!startsWith(arr, 1)); assert(startsWith(arr, 0)); assert(startsWith(arr, 5, 0, 1) == 2); assert(startsWith(arr, [0])); assert(startsWith(arr, [0, 1])); assert(startsWith(arr, [0, 1], 7) == 1); assert(!startsWith(arr, [0, 1, 7])); assert(startsWith(arr, [0, 1, 7], [0, 1, 2]) == 2); //Normal input range assert(!startsWith(filter!"true"(arr), 1)); assert(startsWith(filter!"true"(arr), 0)); assert(startsWith(filter!"true"(arr), [0])); assert(startsWith(filter!"true"(arr), [0, 1])); assert(startsWith(filter!"true"(arr), [0, 1], 7) == 1); assert(!startsWith(filter!"true"(arr), [0, 1, 7])); assert(startsWith(filter!"true"(arr), [0, 1, 7], [0, 1, 2]) == 2); assert(startsWith(arr, filter!"true"([0, 1]))); assert(startsWith(arr, filter!"true"([0, 1]), 7) == 1); assert(!startsWith(arr, filter!"true"([0, 1, 7]))); assert(startsWith(arr, [0, 1, 7], filter!"true"([0, 1, 2])) == 2); //Non-default pred assert(startsWith!("a%10 == b%10")(arr, [10, 11])); assert(!startsWith!("a%10 == b%10")(arr, [10, 12])); } } /* (Not yet documented.) Consume all elements from $(D r) that are equal to one of the elements $(D es). */ void skipAll(alias pred = "a == b", R, Es...)(ref R r, Es es) //if (is(typeof(binaryFun!pred(r1.front, es[0])))) { loop: for (; !r.empty; r.popFront()) { foreach (i, E; Es) { if (binaryFun!pred(r.front, es[i])) { continue loop; } } break; } } @safe unittest { //scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); auto s1 = "Hello world"; skipAll(s1, 'H', 'e'); assert(s1 == "llo world"); } /** Interval option specifier for $(D until) (below) and others. */ enum OpenRight { no, /// Interval is closed to the right (last element included) yes /// Interval is open to the right (last element is not included) } struct Until(alias pred, Range, Sentinel) if (isInputRange!Range) { private Range _input; static if (!is(Sentinel == void)) private Sentinel _sentinel; // mixin(bitfields!( // OpenRight, "_openRight", 1, // bool, "_done", 1, // uint, "", 6)); // OpenRight, "_openRight", 1, // bool, "_done", 1, OpenRight _openRight; bool _done; static if (!is(Sentinel == void)) this(Range input, Sentinel sentinel, OpenRight openRight = OpenRight.yes) { _input = input; _sentinel = sentinel; _openRight = openRight; _done = _input.empty || openRight && predSatisfied(); } else this(Range input, OpenRight openRight = OpenRight.yes) { _input = input; _openRight = openRight; _done = _input.empty || openRight && predSatisfied(); } @property bool empty() { return _done; } @property auto ref front() { assert(!empty); return _input.front; } private bool predSatisfied() { static if (is(Sentinel == void)) return cast(bool) unaryFun!pred(_input.front); else return cast(bool) startsWith!pred(_input, _sentinel); } void popFront() { assert(!empty); if (!_openRight) { _done = predSatisfied(); _input.popFront(); _done = _done || _input.empty; } else { _input.popFront(); _done = _input.empty || predSatisfied(); } } static if (isForwardRange!Range) { static if (!is(Sentinel == void)) @property Until save() { Until result = this; result._input = _input.save; result._sentinel = _sentinel; result._openRight = _openRight; result._done = _done; return result; } else @property Until save() { Until result = this; result._input = _input.save; result._openRight = _openRight; result._done = _done; return result; } } } /** Lazily iterates $(D range) _until the element $(D e) for which $(D pred(e, sentinel)) is true. Params: pred = Predicate to determine when to stop. range = The $(XREF_PACK_NAMED _range,primitives,isInputRange,input _range) to iterate over. sentinel = The element to stop at. openRight = Determines whether the element for which the given predicate is true should be included in the resulting range ($(D OpenRight.no)), or not ($(D OpenRight.yes)). Returns: An $(XREF_PACK_NAMED _range,primitives,isInputRange,input _range) that iterates over the original range's elements, but ends when the specified predicate becomes true. If the original range is a $(XREF_PACK_NAMED _range,primitives,isForwardRange,forward _range) or higher, this range will be a forward range. */ Until!(pred, Range, Sentinel) until(alias pred = "a == b", Range, Sentinel) (Range range, Sentinel sentinel, OpenRight openRight = OpenRight.yes) if (!is(Sentinel == OpenRight)) { return typeof(return)(range, sentinel, openRight); } /// Ditto Until!(pred, Range, void) until(alias pred, Range) (Range range, OpenRight openRight = OpenRight.yes) { return typeof(return)(range, openRight); } /// @safe unittest { import std.algorithm.comparison : equal; int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5]; assert(equal(a.until(7), [1, 2, 4][])); assert(equal(a.until(7, OpenRight.no), [1, 2, 4, 7][])); } @safe unittest { import std.algorithm.comparison : equal; //scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " done."); int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5]; static assert(isForwardRange!(typeof(a.until(7)))); static assert(isForwardRange!(typeof(until!"a == 2"(a, OpenRight.no)))); assert(equal(a.until(7), [1, 2, 4][])); assert(equal(a.until([7, 2]), [1, 2, 4, 7][])); assert(equal(a.until(7, OpenRight.no), [1, 2, 4, 7][])); assert(equal(until!"a == 2"(a, OpenRight.no), [1, 2][])); } unittest // bugzilla 13171 { import std.algorithm.comparison : equal; import std.range; auto a = [1, 2, 3, 4]; assert(equal(refRange(&a).until(3, OpenRight.no), [1, 2, 3])); assert(a == [4]); } @safe unittest // Issue 10460 { import std.algorithm.comparison : equal; auto a = [1, 2, 3, 4]; foreach (ref e; a.until(3)) e = 0; assert(equal(a, [0, 0, 3, 4])); } unittest // Issue 13124 { import std.algorithm.comparison : among; auto s = "hello how\nare you"; s.until!(c => c.among!('\n', '\r')); } ldc-1.1.0-beta3-src/runtime/phobos/std/net/0000775000175000017500000000000012776215007016474 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/net/curl.d0000664000175000017500000043721412776215007017621 0ustar kaikai// Written in the D programming language. /** Networking client functionality as provided by $(WEB _curl.haxx.se/libcurl, libcurl). The libcurl library must be installed on the system in order to use this module. $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Functions) ) $(TR $(TDNW High level) $(TD $(MYREF download) $(MYREF upload) $(MYREF get) $(MYREF post) $(MYREF put) $(MYREF del) $(MYREF options) $(MYREF trace) $(MYREF connect) $(MYREF byLine) $(MYREF byChunk) $(MYREF byLineAsync) $(MYREF byChunkAsync) ) ) $(TR $(TDNW Low level) $(TD $(MYREF HTTP) $(MYREF FTP) $(MYREF SMTP) ) ) ) ) Note: You may need to link to the $(B curl) library, e.g. by adding $(D "libs": ["curl"]) to your $(B dub.json) file if you are using $(LINK2 http://code.dlang.org, DUB). Windows x86 note: A DMD compatible libcurl static library can be downloaded from the dlang.org $(LINK2 http://dlang.org/download.html, download page). Compared to using libcurl directly this module allows simpler client code for common uses, requires no unsafe operations, and integrates better with the rest of the language. Futhermore it provides $(D range) access to protocols supported by libcurl both synchronously and asynchronously. A high level and a low level API are available. The high level API is built entirely on top of the low level one. The high level API is for commonly used functionality such as HTTP/FTP get. The $(LREF byLineAsync) and $(LREF byChunkAsync) provides asynchronous $(D ranges) that performs the request in another thread while handling a line/chunk in the current thread. The low level API allows for streaming and other advanced features. $(BOOKTABLE Cheat Sheet, $(TR $(TH Function Name) $(TH Description) ) $(LEADINGROW High level) $(TR $(TDNW $(LREF download)) $(TD $(D download("ftp.digitalmars.com/sieve.ds", "/tmp/downloaded-ftp-file")) downloads file from URL to file system.) ) $(TR $(TDNW $(LREF upload)) $(TD $(D upload("/tmp/downloaded-ftp-file", "ftp.digitalmars.com/sieve.ds");) uploads file from file system to URL.) ) $(TR $(TDNW $(LREF get)) $(TD $(D get("dlang.org")) returns a char[] containing the dlang.org web page.) ) $(TR $(TDNW $(LREF put)) $(TD $(D put("dlang.org", "Hi")) returns a char[] containing the dlang.org web page. after a HTTP PUT of "hi") ) $(TR $(TDNW $(LREF post)) $(TD $(D post("dlang.org", "Hi")) returns a char[] containing the dlang.org web page. after a HTTP POST of "hi") ) $(TR $(TDNW $(LREF byLine)) $(TD $(D byLine("dlang.org")) returns a range of char[] containing the dlang.org web page.) ) $(TR $(TDNW $(LREF byChunk)) $(TD $(D byChunk("dlang.org", 10)) returns a range of ubyte[10] containing the dlang.org web page.) ) $(TR $(TDNW $(LREF byLineAsync)) $(TD $(D byLineAsync("dlang.org")) returns a range of char[] containing the dlang.org web page asynchronously.) ) $(TR $(TDNW $(LREF byChunkAsync)) $(TD $(D byChunkAsync("dlang.org", 10)) returns a range of ubyte[10] containing the dlang.org web page asynchronously.) ) $(LEADINGROW Low level ) $(TR $(TDNW $(LREF HTTP)) $(TD $(D HTTP) struct for advanced usage)) $(TR $(TDNW $(LREF FTP)) $(TD $(D FTP) struct for advanced usage)) $(TR $(TDNW $(LREF SMTP)) $(TD $(D SMTP) struct for advanced usage)) ) Example: --- import std.net.curl, std.stdio; // Return a char[] containing the content specified by an URL auto content = get("dlang.org"); // Post data and return a char[] containing the content specified by an URL auto content = post("mydomain.com/here.cgi", "post data"); // Get content of file from ftp server auto content = get("ftp.digitalmars.com/sieve.ds"); // Post and print out content line by line. The request is done in another thread. foreach (line; byLineAsync("dlang.org", "Post data")) writeln(line); // Get using a line range and proxy settings auto client = HTTP(); client.proxy = "1.2.3.4"; foreach (line; byLine("dlang.org", client)) writeln(line); --- For more control than the high level functions provide, use the low level API: Example: --- import std.net.curl, std.stdio; // GET with custom data receivers auto http = HTTP("dlang.org"); http.onReceiveHeader = (in char[] key, in char[] value) { writeln(key, ": ", value); }; http.onReceive = (ubyte[] data) { /+ drop +/ return data.length; }; http.perform(); --- First, an instance of the reference-counted HTTP struct is created. Then the custom delegates are set. These will be called whenever the HTTP instance receives a header and a data buffer, respectively. In this simple example, the headers are written to stdout and the data is ignored. If the request should be stopped before it has finished then return something less than data.length from the onReceive callback. See $(LREF onReceiveHeader)/$(LREF onReceive) for more information. Finally the HTTP request is effected by calling perform(), which is synchronous. Source: $(PHOBOSSRC std/net/_curl.d) Copyright: Copyright Jonas Drewsen 2011-2012 License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jonas Drewsen. Some of the SMTP code contributed by Jimmy Cao. Credits: The functionally is based on $(WEB _curl.haxx.se/libcurl, libcurl). LibCurl is licensed under an MIT/X derivative license. */ /* Copyright Jonas Drewsen 2011 - 2012. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.net.curl; import core.thread; import etc.c.curl; import std.algorithm; import std.array; import std.concurrency; import std.conv; import std.datetime; import std.encoding; import std.exception; import std.meta; import std.regex; import std.socket : InternetAddress; import std.string; import std.traits; import std.typecons; import std.internal.cstring; public import etc.c.curl : CurlOption; version(unittest) { // Run unit test with the PHOBOS_TEST_ALLOW_NET=1 set in order to // allow net traffic import std.stdio; import std.range; import std.process : environment; import std.file : deleteme; import std.path : buildPath; import std.socket : Address, INADDR_LOOPBACK, Socket, TcpSocket; private struct TestServer { string addr() { return _addr; } void handle(void function(Socket s) dg) { tid.send(dg); } private: string _addr; Tid tid; static void loop(shared TcpSocket listener) { try while (true) { void function(Socket) handler = void; try handler = receiveOnly!(typeof(handler)); catch (OwnerTerminated) return; handler((cast()listener).accept); } catch (Throwable e) { import core.stdc.stdlib : exit, EXIT_FAILURE; stderr.writeln(e); exit(EXIT_FAILURE); // Bugzilla 7018 } } } private TestServer startServer() { auto sock = new TcpSocket; sock.bind(new InternetAddress(INADDR_LOOPBACK, InternetAddress.PORT_ANY)); sock.listen(1); auto addr = sock.localAddress.toString(); auto tid = spawn(&TestServer.loop, cast(shared)sock); return TestServer(addr, tid); } private ref TestServer testServer() { __gshared TestServer server; return initOnce!server(startServer()); } private struct Request(T) { string hdrs; immutable(T)[] bdy; } private Request!T recvReq(T=char)(Socket s) { ubyte[1024] tmp=void; ubyte[] buf; while (true) { auto nbytes = s.receive(tmp[]); assert(nbytes >= 0); immutable beg = buf.length > 3 ? buf.length - 3 : 0; buf ~= tmp[0 .. nbytes]; auto bdy = buf[beg .. $].find(cast(ubyte[])"\r\n\r\n"); if (bdy.empty) continue; auto hdrs = cast(string)buf[0 .. $ - bdy.length]; bdy.popFrontN(4); // no support for chunked transfer-encoding if (auto m = hdrs.matchFirst(ctRegex!(`Content-Length: ([0-9]+)`, "i"))) { import std.uni : asUpperCase; if (hdrs.asUpperCase.canFind("EXPECT: 100-CONTINUE")) s.send(httpContinue); size_t remain = m.captures[1].to!size_t - bdy.length; while (remain) { nbytes = s.receive(tmp[0 .. min(remain, $)]); assert(nbytes >= 0); buf ~= tmp[0 .. nbytes]; remain -= nbytes; } } else { assert(bdy.empty); } bdy = buf[hdrs.length + 4 .. $]; return typeof(return)(hdrs, cast(immutable(T)[])bdy); } } private string httpOK(string msg) { return "HTTP/1.1 200 OK\r\n"~ "Content-Type: text/plain\r\n"~ "Content-Length: "~msg.length.to!string~"\r\n" "\r\n"~ msg; } private string httpOK() { return "HTTP/1.1 200 OK\r\n"~ "Content-Length: 0\r\n"~ "\r\n"; } private string httpNotFound() { return "HTTP/1.1 404 Not Found\r\n"~ "Content-Length: 0\r\n"~ "\r\n"; } private enum httpContinue = "HTTP/1.1 100 Continue\r\n\r\n"; } version(StdDdoc) import std.stdio; extern (C) void exit(int); // Default data timeout for Protocols private enum _defaultDataTimeout = dur!"minutes"(2); /** Macros: CALLBACK_PARAMS = $(TABLE , $(DDOC_PARAM_ROW $(DDOC_PARAM_ID $(DDOC_PARAM dlTotal)) $(DDOC_PARAM_DESC total bytes to download) ) $(DDOC_PARAM_ROW $(DDOC_PARAM_ID $(DDOC_PARAM dlNow)) $(DDOC_PARAM_DESC currently downloaded bytes) ) $(DDOC_PARAM_ROW $(DDOC_PARAM_ID $(DDOC_PARAM ulTotal)) $(DDOC_PARAM_DESC total bytes to upload) ) $(DDOC_PARAM_ROW $(DDOC_PARAM_ID $(DDOC_PARAM ulNow)) $(DDOC_PARAM_DESC currently uploaded bytes) ) ) */ /** Connection type used when the URL should be used to auto detect the protocol. * * This struct is used as placeholder for the connection parameter when calling * the high level API and the connection type (HTTP/FTP) should be guessed by * inspecting the URL parameter. * * The rules for guessing the protocol are: * 1, if URL starts with ftp://, ftps:// or ftp. then FTP connection is assumed. * 2, HTTP connection otherwise. * * Example: * --- * import std.net.curl; * // Two requests below will do the same. * string content; * * // Explicit connection provided * content = get!HTTP("dlang.org"); * * // Guess connection type by looking at the URL * content = get!AutoProtocol("ftp://foo.com/file"); * // and since AutoProtocol is default this is the same as * connect = get("ftp://foo.com/file"); * // and will end up detecting FTP from the url and be the same as * connect = get!FTP("ftp://foo.com/file"); * --- */ struct AutoProtocol { } // Returns true if the url points to an FTP resource private bool isFTPUrl(const(char)[] url) { return startsWith(url.toLower(), "ftp://", "ftps://", "ftp.") != 0; } // Is true if the Conn type is a valid Curl Connection type. private template isCurlConn(Conn) { enum auto isCurlConn = is(Conn : HTTP) || is(Conn : FTP) || is(Conn : AutoProtocol); } /** HTTP/FTP download to local file system. * * Params: * url = resource to download * saveToPath = path to store the downloaded content on local disk * conn = connection to use e.g. FTP or HTTP. The default AutoProtocol will * guess connection type and create a new instance for this call only. * * Example: * ---- * import std.net.curl; * download("d-lang.appspot.com/testUrl2", "/tmp/downloaded-http-file"); * ---- */ void download(Conn = AutoProtocol)(const(char)[] url, string saveToPath, Conn conn = Conn()) if (isCurlConn!Conn) { static if (is(Conn : HTTP) || is(Conn : FTP)) { import std.stdio : File; conn.url = url; auto f = File(saveToPath, "wb"); conn.onReceive = (ubyte[] data) { f.rawWrite(data); return data.length; }; conn.perform(); } else { if (isFTPUrl(url)) return download!FTP(url, saveToPath, FTP()); else return download!HTTP(url, saveToPath, HTTP()); } } unittest { static import std.file; foreach (host; [testServer.addr, "http://"~testServer.addr]) { testServer.handle((s) { assert(s.recvReq.hdrs.canFind("GET /")); s.send(httpOK("Hello world")); }); auto fn = std.file.deleteme; scope (exit) std.file.remove(fn); download(host, fn); assert(std.file.readText(fn) == "Hello world"); } } /** Upload file from local files system using the HTTP or FTP protocol. * * Params: * loadFromPath = path load data from local disk. * url = resource to upload to * conn = connection to use e.g. FTP or HTTP. The default AutoProtocol will * guess connection type and create a new instance for this call only. * * Example: * ---- * import std.net.curl; * upload("/tmp/downloaded-ftp-file", "ftp.digitalmars.com/sieve.ds"); * upload("/tmp/downloaded-http-file", "d-lang.appspot.com/testUrl2"); * ---- */ void upload(Conn = AutoProtocol)(string loadFromPath, const(char)[] url, Conn conn = Conn()) if (isCurlConn!Conn) { static if (is(Conn : HTTP)) { conn.url = url; conn.method = HTTP.Method.put; } else static if (is(Conn : FTP)) { conn.url = url; conn.handle.set(CurlOption.upload, 1L); } else { if (isFTPUrl(url)) return upload!FTP(loadFromPath, url, FTP()); else return upload!HTTP(loadFromPath, url, HTTP()); } static if (is(Conn : HTTP) || is(Conn : FTP)) { import std.stdio : File; auto f = File(loadFromPath, "rb"); conn.onSend = buf => f.rawRead(buf).length; auto sz = f.size; if (sz != ulong.max) conn.contentLength = sz; conn.perform(); } } unittest { static import std.file; foreach (host; [testServer.addr, "http://"~testServer.addr]) { auto fn = std.file.deleteme; scope (exit) std.file.remove(fn); std.file.write(fn, "upload data\n"); testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("PUT /path")); assert(req.bdy.canFind("upload data")); s.send(httpOK()); }); upload(fn, host ~ "/path"); } } /** HTTP/FTP get content. * * Params: * url = resource to get * conn = connection to use e.g. FTP or HTTP. The default AutoProtocol will * guess connection type and create a new instance for this call only. * * The template parameter $(D T) specifies the type to return. Possible values * are $(D char) and $(D ubyte) to return $(D char[]) or $(D ubyte[]). If asking * for $(D char), content will be converted from the connection character set * (specified in HTTP response headers or FTP connection properties, both ISO-8859-1 * by default) to UTF-8. * * Example: * ---- * import std.net.curl; * auto content = get("d-lang.appspot.com/testUrl2"); * ---- * * Returns: * A T[] range containing the content of the resource pointed to by the URL. * * Throws: * * $(D CurlException) on error. * * See_Also: $(LREF HTTP.Method) */ T[] get(Conn = AutoProtocol, T = char)(const(char)[] url, Conn conn = Conn()) if ( isCurlConn!Conn && (is(T == char) || is(T == ubyte)) ) { static if (is(Conn : HTTP)) { conn.method = HTTP.Method.get; return _basicHTTP!(T)(url, "", conn); } else static if (is(Conn : FTP)) { return _basicFTP!(T)(url, "", conn); } else { if (isFTPUrl(url)) return get!(FTP,T)(url, FTP()); else return get!(HTTP,T)(url, HTTP()); } } unittest { foreach (host; [testServer.addr, "http://"~testServer.addr]) { testServer.handle((s) { assert(s.recvReq.hdrs.canFind("GET /path")); s.send(httpOK("GETRESPONSE")); }); auto res = get(host ~ "/path"); assert(res == "GETRESPONSE"); } } /** HTTP post content. * * Params: * url = resource to post to * postData = data to send as the body of the request. An array * of an arbitrary type is accepted and will be cast to ubyte[] * before sending it. * conn = HTTP connection to use * * The template parameter $(D T) specifies the type to return. Possible values * are $(D char) and $(D ubyte) to return $(D char[]) or $(D ubyte[]). If asking * for $(D char), content will be converted from the connection character set * (specified in HTTP response headers or FTP connection properties, both ISO-8859-1 * by default) to UTF-8. * * Example: * ---- * import std.net.curl; * auto content = post("d-lang.appspot.com/testUrl2", [1,2,3,4]); * ---- * * Returns: * A T[] range containing the content of the resource pointed to by the URL. * * See_Also: $(LREF HTTP.Method) */ T[] post(T = char, PostUnit)(const(char)[] url, const(PostUnit)[] postData, HTTP conn = HTTP()) if (is(T == char) || is(T == ubyte)) { conn.method = HTTP.Method.post; return _basicHTTP!(T)(url, postData, conn); } unittest { foreach (host; [testServer.addr, "http://"~testServer.addr]) { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("POST /path")); assert(req.bdy.canFind("POSTBODY")); s.send(httpOK("POSTRESPONSE")); }); auto res = post(host ~ "/path", "POSTBODY"); assert(res == "POSTRESPONSE"); } } unittest { auto data = new ubyte[](256); foreach (i, ref ub; data) ub = cast(ubyte)i; testServer.handle((s) { auto req = s.recvReq!ubyte; assert(req.bdy.canFind(cast(ubyte[])[0, 1, 2, 3, 4])); assert(req.bdy.canFind(cast(ubyte[])[253, 254, 255])); s.send(httpOK(cast(ubyte[])[17, 27, 35, 41])); }); auto res = post!ubyte(testServer.addr, data); assert(res == cast(ubyte[])[17, 27, 35, 41]); } /** HTTP/FTP put content. * * Params: * url = resource to put * putData = data to send as the body of the request. An array * of an arbitrary type is accepted and will be cast to ubyte[] * before sending it. * conn = connection to use e.g. FTP or HTTP. The default AutoProtocol will * guess connection type and create a new instance for this call only. * * The template parameter $(D T) specifies the type to return. Possible values * are $(D char) and $(D ubyte) to return $(D char[]) or $(D ubyte[]). If asking * for $(D char), content will be converted from the connection character set * (specified in HTTP response headers or FTP connection properties, both ISO-8859-1 * by default) to UTF-8. * * Example: * ---- * import std.net.curl; * auto content = put("d-lang.appspot.com/testUrl2", * "Putting this data"); * ---- * * Returns: * A T[] range containing the content of the resource pointed to by the URL. * * See_Also: $(LREF HTTP.Method) */ T[] put(Conn = AutoProtocol, T = char, PutUnit)(const(char)[] url, const(PutUnit)[] putData, Conn conn = Conn()) if ( isCurlConn!Conn && (is(T == char) || is(T == ubyte)) ) { static if (is(Conn : HTTP)) { conn.method = HTTP.Method.put; return _basicHTTP!(T)(url, putData, conn); } else static if (is(Conn : FTP)) { return _basicFTP!(T)(url, putData, conn); } else { if (isFTPUrl(url)) return put!(FTP,T)(url, putData, FTP()); else return put!(HTTP,T)(url, putData, HTTP()); } } unittest { foreach (host; [testServer.addr, "http://"~testServer.addr]) { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("PUT /path")); assert(req.bdy.canFind("PUTBODY")); s.send(httpOK("PUTRESPONSE")); }); auto res = put(host ~ "/path", "PUTBODY"); assert(res == "PUTRESPONSE"); } } /** HTTP/FTP delete content. * * Params: * url = resource to delete * conn = connection to use e.g. FTP or HTTP. The default AutoProtocol will * guess connection type and create a new instance for this call only. * * Example: * ---- * import std.net.curl; * del("d-lang.appspot.com/testUrl2"); * ---- * * See_Also: $(LREF HTTP.Method) */ void del(Conn = AutoProtocol)(const(char)[] url, Conn conn = Conn()) if (isCurlConn!Conn) { static if (is(Conn : HTTP)) { conn.method = HTTP.Method.del; _basicHTTP!char(url, cast(void[]) null, conn); } else static if (is(Conn : FTP)) { auto trimmed = url.findSplitAfter("ftp://")[1]; auto t = trimmed.findSplitAfter("/"); enum minDomainNameLength = 3; enforce!CurlException(t[0].length > minDomainNameLength, text("Invalid FTP URL for delete ", url)); conn.url = t[0]; enforce!CurlException(!t[1].empty, text("No filename specified to delete for URL ", url)); conn.addCommand("DELE " ~ t[1]); conn.perform(); } else { if (isFTPUrl(url)) return del!FTP(url, FTP()); else return del!HTTP(url, HTTP()); } } unittest { foreach (host; [testServer.addr, "http://"~testServer.addr]) { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("DELETE /path")); s.send(httpOK()); }); del(host ~ "/path"); } } /** HTTP options request. * * Params: * url = resource make a option call to * conn = connection to use e.g. FTP or HTTP. The default AutoProtocol will * guess connection type and create a new instance for this call only. * * The template parameter $(D T) specifies the type to return. Possible values * are $(D char) and $(D ubyte) to return $(D char[]) or $(D ubyte[]). * * Example: * ---- * import std.net.curl; * auto http = HTTP(); * options("d-lang.appspot.com/testUrl2", http); * writeln("Allow set to " ~ http.responseHeaders["Allow"]); * ---- * * Returns: * A T[] range containing the options of the resource pointed to by the URL. * * See_Also: $(LREF HTTP.Method) */ T[] options(T = char)(const(char)[] url, HTTP conn = HTTP()) if (is(T == char) || is(T == ubyte)) { conn.method = HTTP.Method.options; return _basicHTTP!(T)(url, null, conn); } // Explicitly undocumented. It will be removed in February 2017. @@@DEPRECATED_2017-02@@@ deprecated("options does not send any data") T[] options(T = char, OptionsUnit)(const(char)[] url, const(OptionsUnit)[] optionsData = null, HTTP conn = HTTP()) if (is(T == char) || is(T == ubyte)) { return options!T(url, conn); } unittest { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("OPTIONS /path")); s.send(httpOK("OPTIONSRESPONSE")); }); auto res = options(testServer.addr ~ "/path"); assert(res == "OPTIONSRESPONSE"); } /** HTTP trace request. * * Params: * url = resource make a trace call to * conn = connection to use e.g. FTP or HTTP. The default AutoProtocol will * guess connection type and create a new instance for this call only. * * The template parameter $(D T) specifies the type to return. Possible values * are $(D char) and $(D ubyte) to return $(D char[]) or $(D ubyte[]). * * Example: * ---- * import std.net.curl; * trace("d-lang.appspot.com/testUrl1"); * ---- * * Returns: * A T[] range containing the trace info of the resource pointed to by the URL. * * See_Also: $(LREF HTTP.Method) */ T[] trace(T = char)(const(char)[] url, HTTP conn = HTTP()) if (is(T == char) || is(T == ubyte)) { conn.method = HTTP.Method.trace; return _basicHTTP!(T)(url, cast(void[]) null, conn); } unittest { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("TRACE /path")); s.send(httpOK("TRACERESPONSE")); }); auto res = trace(testServer.addr ~ "/path"); assert(res == "TRACERESPONSE"); } /** HTTP connect request. * * Params: * url = resource make a connect to * conn = HTTP connection to use * * The template parameter $(D T) specifies the type to return. Possible values * are $(D char) and $(D ubyte) to return $(D char[]) or $(D ubyte[]). * * Example: * ---- * import std.net.curl; * connect("d-lang.appspot.com/testUrl1"); * ---- * * Returns: * A T[] range containing the connect info of the resource pointed to by the URL. * * See_Also: $(LREF HTTP.Method) */ T[] connect(T = char)(const(char)[] url, HTTP conn = HTTP()) if (is(T == char) || is(T == ubyte)) { conn.method = HTTP.Method.connect; return _basicHTTP!(T)(url, cast(void[]) null, conn); } unittest { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("CONNECT /path")); s.send(httpOK("CONNECTRESPONSE")); }); auto res = connect(testServer.addr ~ "/path"); assert(res == "CONNECTRESPONSE"); } /** HTTP patch content. * * Params: * url = resource to patch * patchData = data to send as the body of the request. An array * of an arbitrary type is accepted and will be cast to ubyte[] * before sending it. * conn = HTTP connection to use * * The template parameter $(D T) specifies the type to return. Possible values * are $(D char) and $(D ubyte) to return $(D char[]) or $(D ubyte[]). * * Example: * ---- * auto http = HTTP(); * http.addRequestHeader("Content-Type", "application/json"); * auto content = patch("d-lang.appspot.com/testUrl2", `{"title": "Patched Title"}`, http); * ---- * * Returns: * A T[] range containing the content of the resource pointed to by the URL. * * See_Also: $(LREF HTTP.Method) */ T[] patch(T = char, PatchUnit)(const(char)[] url, const(PatchUnit)[] patchData, HTTP conn = HTTP()) if (is(T == char) || is(T == ubyte)) { conn.method = HTTP.Method.patch; return _basicHTTP!(T)(url, patchData, conn); } unittest { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("PATCH /path")); assert(req.bdy.canFind("PATCHBODY")); s.send(httpOK("PATCHRESPONSE")); }); auto res = patch(testServer.addr ~ "/path", "PATCHBODY"); assert(res == "PATCHRESPONSE"); } /* * Helper function for the high level interface. * * It performs an HTTP request using the client which must have * been setup correctly before calling this function. */ private auto _basicHTTP(T)(const(char)[] url, const(void)[] sendData, HTTP client) { immutable doSend = sendData !is null && (client.method == HTTP.Method.post || client.method == HTTP.Method.put || client.method == HTTP.Method.patch); scope (exit) { client.onReceiveHeader = null; client.onReceiveStatusLine = null; client.onReceive = null; if (doSend) { client.onSend = null; client.handle.onSeek = null; client.contentLength = 0; } } client.url = url; HTTP.StatusLine statusLine; import std.array : appender; auto content = appender!(ubyte[])(); string[string] headers; client.onReceive = (ubyte[] data) { content ~= data; return data.length; }; if (doSend) { client.contentLength = sendData.length; auto remainingData = sendData; client.onSend = delegate size_t(void[] buf) { size_t minLen = min(buf.length, remainingData.length); if (minLen == 0) return 0; buf[0..minLen] = remainingData[0..minLen]; remainingData = remainingData[minLen..$]; return minLen; }; client.handle.onSeek = delegate(long offset, CurlSeekPos mode) { switch (mode) { case CurlSeekPos.set: remainingData = sendData[cast(size_t)offset..$]; return CurlSeek.ok; default: // As of curl 7.18.0, libcurl will not pass // anything other than CurlSeekPos.set. return CurlSeek.cantseek; } }; } client.onReceiveHeader = (in char[] key, in char[] value) { if (key == "content-length") { import std.conv : to; content.reserve(value.to!size_t); } if (auto v = key in headers) { *v ~= ", "; *v ~= value; } else headers[key] = value.idup; }; client.onReceiveStatusLine = (HTTP.StatusLine l) { statusLine = l; }; client.perform(); enforce!CurlException(statusLine.code / 100 == 2, format("HTTP request returned status code %d (%s)", statusLine.code, statusLine.reason)); // Default charset defined in HTTP RFC auto charset = "ISO-8859-1"; if (auto v = "content-type" in headers) { auto m = match(cast(char[]) (*v), regex("charset=([^;,]*)")); if (!m.empty && m.captures.length > 1) { charset = m.captures[1].idup; } } return _decodeContent!T(content.data, charset); } unittest { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("GET /path")); s.send(httpNotFound()); }); auto e = collectException!CurlException(get(testServer.addr ~ "/path")); assert(e.msg == "HTTP request returned status code 404 (Not Found)"); } // Bugzilla 14760 - content length must be reset after post unittest { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("POST /")); assert(req.bdy.canFind("POSTBODY")); s.send(httpOK("POSTRESPONSE")); req = s.recvReq; assert(req.hdrs.canFind("TRACE /")); assert(req.bdy.empty); s.blocking = false; ubyte[6] buf = void; assert(s.receive(buf[]) < 0); s.send(httpOK("TRACERESPONSE")); }); auto http = HTTP(); auto res = post(testServer.addr, "POSTBODY", http); assert(res == "POSTRESPONSE"); res = trace(testServer.addr, http); assert(res == "TRACERESPONSE"); } /* * Helper function for the high level interface. * * It performs an FTP request using the client which must have * been setup correctly before calling this function. */ private auto _basicFTP(T)(const(char)[] url, const(void)[] sendData, FTP client) { scope (exit) { client.onReceive = null; if (!sendData.empty) client.onSend = null; } ubyte[] content; if (client.encoding.empty) client.encoding = "ISO-8859-1"; client.url = url; client.onReceive = (ubyte[] data) { content ~= data; return data.length; }; if (!sendData.empty) { client.handle.set(CurlOption.upload, 1L); client.onSend = delegate size_t(void[] buf) { size_t minLen = min(buf.length, sendData.length); if (minLen == 0) return 0; buf[0..minLen] = sendData[0..minLen]; sendData = sendData[minLen..$]; return minLen; }; } client.perform(); return _decodeContent!T(content, client.encoding); } /* Used by _basicHTTP() and _basicFTP() to decode ubyte[] to * correct string format */ private auto _decodeContent(T)(ubyte[] content, string encoding) { static if (is(T == ubyte)) { return content; } else { // Optimally just return the utf8 encoded content if (encoding == "UTF-8") return cast(char[])(content); // The content has to be re-encoded to utf8 auto scheme = EncodingScheme.create(encoding); enforce!CurlException(scheme !is null, format("Unknown encoding '%s'", encoding)); auto strInfo = decodeString(content, scheme); enforce!CurlException(strInfo[0] != size_t.max, format("Invalid encoding sequence for encoding '%s'", encoding)); return strInfo[1]; } } alias KeepTerminator = Flag!"keepTerminator"; /+ struct ByLineBuffer(Char) { bool linePresent; bool EOF; Char[] buffer; ubyte[] decodeRemainder; bool append(const(ubyte)[] data) { byLineBuffer ~= data; } @property bool linePresent() { return byLinePresent; } Char[] get() { if (!linePresent) { // Decode ubyte[] into Char[] until a Terminator is found. // If not Terminator is found and EOF is false then raise an // exception. } return byLineBuffer; } } ++/ /** HTTP/FTP fetch content as a range of lines. * * A range of lines is returned when the request is complete. If the method or * other request properties is to be customized then set the $(D conn) parameter * with a HTTP/FTP instance that has these properties set. * * Example: * ---- * import std.net.curl, std.stdio; * foreach (line; byLine("dlang.org")) * writeln(line); * ---- * * Params: * url = The url to receive content from * keepTerminator = KeepTerminator.yes signals that the line terminator should be * returned as part of the lines in the range. * terminator = The character that terminates a line * conn = The connection to use e.g. HTTP or FTP. * * Returns: * A range of Char[] with the content of the resource pointer to by the URL */ auto byLine(Conn = AutoProtocol, Terminator = char, Char = char) (const(char)[] url, KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\n', Conn conn = Conn()) if (isCurlConn!Conn && isSomeChar!Char && isSomeChar!Terminator) { static struct SyncLineInputRange { private Char[] lines; private Char[] current; private bool currentValid; private bool keepTerminator; private Terminator terminator; this(Char[] lines, bool kt, Terminator terminator) { this.lines = lines; this.keepTerminator = kt; this.terminator = terminator; currentValid = true; popFront(); } @property @safe bool empty() { return !currentValid; } @property @safe Char[] front() { enforce!CurlException(currentValid, "Cannot call front() on empty range"); return current; } void popFront() { enforce!CurlException(currentValid, "Cannot call popFront() on empty range"); if (lines.empty) { currentValid = false; return; } if (keepTerminator) { auto r = findSplitAfter(lines, [ terminator ]); if (r[0].empty) { current = r[1]; lines = r[0]; } else { current = r[0]; lines = r[1]; } } else { auto r = findSplit(lines, [ terminator ]); current = r[0]; lines = r[2]; } } } auto result = _getForRange!Char(url, conn); return SyncLineInputRange(result, keepTerminator == KeepTerminator.yes, terminator); } unittest { foreach (host; [testServer.addr, "http://"~testServer.addr]) { testServer.handle((s) { auto req = s.recvReq; s.send(httpOK("Line1\nLine2\nLine3")); }); assert(byLine(host).equal(["Line1", "Line2", "Line3"])); } } /** HTTP/FTP fetch content as a range of chunks. * * A range of chunks is returned when the request is complete. If the method or * other request properties is to be customized then set the $(D conn) parameter * with a HTTP/FTP instance that has these properties set. * * Example: * ---- * import std.net.curl, std.stdio; * foreach (chunk; byChunk("dlang.org", 100)) * writeln(chunk); // chunk is ubyte[100] * ---- * * Params: * url = The url to receive content from * chunkSize = The size of each chunk * conn = The connection to use e.g. HTTP or FTP. * * Returns: * A range of ubyte[chunkSize] with the content of the resource pointer to by the URL */ auto byChunk(Conn = AutoProtocol) (const(char)[] url, size_t chunkSize = 1024, Conn conn = Conn()) if (isCurlConn!(Conn)) { static struct SyncChunkInputRange { private size_t chunkSize; private ubyte[] _bytes; private size_t offset; this(ubyte[] bytes, size_t chunkSize) { this._bytes = bytes; this.chunkSize = chunkSize; } @property @safe auto empty() { return offset == _bytes.length; } @property ubyte[] front() { size_t nextOffset = offset + chunkSize; if (nextOffset > _bytes.length) nextOffset = _bytes.length; return _bytes[offset..nextOffset]; } @safe void popFront() { offset += chunkSize; if (offset > _bytes.length) offset = _bytes.length; } } auto result = _getForRange!ubyte(url, conn); return SyncChunkInputRange(result, chunkSize); } unittest { foreach (host; [testServer.addr, "http://"~testServer.addr]) { testServer.handle((s) { auto req = s.recvReq; s.send(httpOK(cast(ubyte[])[0, 1, 2, 3, 4, 5])); }); assert(byChunk(host, 2).equal([[0, 1], [2, 3], [4, 5]])); } } private T[] _getForRange(T,Conn)(const(char)[] url, Conn conn) { static if (is(Conn : HTTP)) { conn.method = conn.method == HTTP.Method.undefined ? HTTP.Method.get : conn.method; return _basicHTTP!(T)(url, null, conn); } else static if (is(Conn : FTP)) { return _basicFTP!(T)(url, null, conn); } else { if (isFTPUrl(url)) return get!(FTP,T)(url, FTP()); else return get!(HTTP,T)(url, HTTP()); } } /* Main thread part of the message passing protocol used for all async curl protocols. */ private mixin template WorkerThreadProtocol(Unit, alias units) { @property bool empty() { tryEnsureUnits(); return state == State.done; } @property Unit[] front() { tryEnsureUnits(); assert(state == State.gotUnits, format("Expected %s but got $s", State.gotUnits, state)); return units; } void popFront() { tryEnsureUnits(); assert(state == State.gotUnits, format("Expected %s but got $s", State.gotUnits, state)); state = State.needUnits; // Send to worker thread for buffer reuse workerTid.send(cast(immutable(Unit)[]) units); units = null; } /** Wait for duration or until data is available and return true if data is available */ bool wait(Duration d) { if (state == State.gotUnits) return true; enum noDur = dur!"hnsecs"(0); StopWatch sw; sw.start(); while (state != State.gotUnits && d > noDur) { final switch (state) { case State.needUnits: receiveTimeout(d, (Tid origin, CurlMessage!(immutable(Unit)[]) _data) { if (origin != workerTid) return false; units = cast(Unit[]) _data.data; state = State.gotUnits; return true; }, (Tid origin, CurlMessage!bool f) { if (origin != workerTid) return false; state = state.done; return true; } ); break; case State.gotUnits: return true; case State.done: return false; } d -= sw.peek(); sw.reset(); } return state == State.gotUnits; } enum State { needUnits, gotUnits, done } State state; void tryEnsureUnits() { while (true) { final switch (state) { case State.needUnits: receive( (Tid origin, CurlMessage!(immutable(Unit)[]) _data) { if (origin != workerTid) return false; units = cast(Unit[]) _data.data; state = State.gotUnits; return true; }, (Tid origin, CurlMessage!bool f) { if (origin != workerTid) return false; state = state.done; return true; } ); break; case State.gotUnits: return; case State.done: return; } } } } // Workaround bug #2458 // It should really be defined inside the byLineAsync method. // Do not create instances of this struct since it will be // moved when the bug has been fixed. // Range that reads one line at a time asynchronously. static struct AsyncLineInputRange(Char) { private Char[] line; mixin WorkerThreadProtocol!(Char, line); private Tid workerTid; private State running; private this(Tid tid, size_t transmitBuffers, size_t bufferSize) { workerTid = tid; state = State.needUnits; // Send buffers to other thread for it to use. Since no mechanism is in // place for moving ownership a cast to shared is done here and casted // back to non-shared in the receiving end. foreach (i ; 0..transmitBuffers) { auto arr = new Char[](bufferSize); workerTid.send(cast(immutable(Char[]))arr); } } } /** HTTP/FTP fetch content as a range of lines asynchronously. * * A range of lines is returned immediately and the request that fetches the * lines is performed in another thread. If the method or other request * properties is to be customized then set the $(D conn) parameter with a * HTTP/FTP instance that has these properties set. * * If $(D postData) is non-_null the method will be set to $(D post) for HTTP * requests. * * The background thread will buffer up to transmitBuffers number of lines * before it stops receiving data from network. When the main thread reads the * lines from the range it frees up buffers and allows for the background thread * to receive more data from the network. * * If no data is available and the main thread accesses the range it will block * until data becomes available. An exception to this is the $(D wait(Duration)) method on * the $(LREF AsyncLineInputRange). This method will wait at maximum for the * specified duration and return true if data is available. * * Example: * ---- * import std.net.curl, std.stdio; * // Get some pages in the background * auto range1 = byLineAsync("www.google.com"); * auto range2 = byLineAsync("www.wikipedia.org"); * foreach (line; byLineAsync("dlang.org")) * writeln(line); * * // Lines already fetched in the background and ready * foreach (line; range1) writeln(line); * foreach (line; range2) writeln(line); * ---- * * ---- * import std.net.curl, std.stdio; * // Get a line in a background thread and wait in * // main thread for 2 seconds for it to arrive. * auto range3 = byLineAsync("dlang.com"); * if (range.wait(dur!"seconds"(2))) * writeln(range.front); * else * writeln("No line received after 2 seconds!"); * ---- * * Params: * url = The url to receive content from * postData = Data to HTTP Post * keepTerminator = KeepTerminator.yes signals that the line terminator should be * returned as part of the lines in the range. * terminator = The character that terminates a line * transmitBuffers = The number of lines buffered asynchronously * conn = The connection to use e.g. HTTP or FTP. * * Returns: * A range of Char[] with the content of the resource pointer to by the * URL. */ auto byLineAsync(Conn = AutoProtocol, Terminator = char, Char = char, PostUnit) (const(char)[] url, const(PostUnit)[] postData, KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\n', size_t transmitBuffers = 10, Conn conn = Conn()) if (isCurlConn!Conn && isSomeChar!Char && isSomeChar!Terminator) { static if (is(Conn : AutoProtocol)) { if (isFTPUrl(url)) return byLineAsync(url, postData, keepTerminator, terminator, transmitBuffers, FTP()); else return byLineAsync(url, postData, keepTerminator, terminator, transmitBuffers, HTTP()); } else { // 50 is just an arbitrary number for now setMaxMailboxSize(thisTid, 50, OnCrowding.block); auto tid = spawn(&_spawnAsync!(Conn, Char, Terminator)); tid.send(thisTid); tid.send(terminator); tid.send(keepTerminator == KeepTerminator.yes); _asyncDuplicateConnection(url, conn, postData, tid); return AsyncLineInputRange!Char(tid, transmitBuffers, Conn.defaultAsyncStringBufferSize); } } /// ditto auto byLineAsync(Conn = AutoProtocol, Terminator = char, Char = char) (const(char)[] url, KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\n', size_t transmitBuffers = 10, Conn conn = Conn()) { static if (is(Conn : AutoProtocol)) { if (isFTPUrl(url)) return byLineAsync(url, cast(void[])null, keepTerminator, terminator, transmitBuffers, FTP()); else return byLineAsync(url, cast(void[])null, keepTerminator, terminator, transmitBuffers, HTTP()); } else { return byLineAsync(url, cast(void[])null, keepTerminator, terminator, transmitBuffers, conn); } } unittest { foreach (host; [testServer.addr, "http://"~testServer.addr]) { testServer.handle((s) { auto req = s.recvReq; s.send(httpOK("Line1\nLine2\nLine3")); }); assert(byLineAsync(host).equal(["Line1", "Line2", "Line3"])); } } // Workaround bug #2458 // It should really be defined inside the byLineAsync method. // Do not create instances of this struct since it will be // moved when the bug has been fixed. // Range that reads one chunk at a time asynchronously. static struct AsyncChunkInputRange { private ubyte[] chunk; mixin WorkerThreadProtocol!(ubyte, chunk); private Tid workerTid; private State running; private this(Tid tid, size_t transmitBuffers, size_t chunkSize) { workerTid = tid; state = State.needUnits; // Send buffers to other thread for it to use. Since no mechanism is in // place for moving ownership a cast to shared is done here and a cast // back to non-shared in the receiving end. foreach (i ; 0..transmitBuffers) { ubyte[] arr = new ubyte[](chunkSize); workerTid.send(cast(immutable(ubyte[]))arr); } } } /** HTTP/FTP fetch content as a range of chunks asynchronously. * * A range of chunks is returned immediately and the request that fetches the * chunks is performed in another thread. If the method or other request * properties is to be customized then set the $(D conn) parameter with a * HTTP/FTP instance that has these properties set. * * If $(D postData) is non-_null the method will be set to $(D post) for HTTP * requests. * * The background thread will buffer up to transmitBuffers number of chunks * before is stops receiving data from network. When the main thread reads the * chunks from the range it frees up buffers and allows for the background * thread to receive more data from the network. * * If no data is available and the main thread access the range it will block * until data becomes available. An exception to this is the $(D wait(Duration)) * method on the $(LREF AsyncChunkInputRange). This method will wait at maximum for the specified * duration and return true if data is available. * * Example: * ---- * import std.net.curl, std.stdio; * // Get some pages in the background * auto range1 = byChunkAsync("www.google.com", 100); * auto range2 = byChunkAsync("www.wikipedia.org"); * foreach (chunk; byChunkAsync("dlang.org")) * writeln(chunk); // chunk is ubyte[100] * * // Chunks already fetched in the background and ready * foreach (chunk; range1) writeln(chunk); * foreach (chunk; range2) writeln(chunk); * ---- * * ---- * import std.net.curl, std.stdio; * // Get a line in a background thread and wait in * // main thread for 2 seconds for it to arrive. * auto range3 = byChunkAsync("dlang.com", 10); * if (range.wait(dur!"seconds"(2))) * writeln(range.front); * else * writeln("No chunk received after 2 seconds!"); * ---- * * Params: * url = The url to receive content from * postData = Data to HTTP Post * chunkSize = The size of the chunks * transmitBuffers = The number of chunks buffered asynchronously * conn = The connection to use e.g. HTTP or FTP. * * Returns: * A range of ubyte[chunkSize] with the content of the resource pointer to by * the URL. */ auto byChunkAsync(Conn = AutoProtocol, PostUnit) (const(char)[] url, const(PostUnit)[] postData, size_t chunkSize = 1024, size_t transmitBuffers = 10, Conn conn = Conn()) if (isCurlConn!(Conn)) { static if (is(Conn : AutoProtocol)) { if (isFTPUrl(url)) return byChunkAsync(url, postData, chunkSize, transmitBuffers, FTP()); else return byChunkAsync(url, postData, chunkSize, transmitBuffers, HTTP()); } else { // 50 is just an arbitrary number for now setMaxMailboxSize(thisTid, 50, OnCrowding.block); auto tid = spawn(&_spawnAsync!(Conn, ubyte)); tid.send(thisTid); _asyncDuplicateConnection(url, conn, postData, tid); return AsyncChunkInputRange(tid, transmitBuffers, chunkSize); } } /// ditto auto byChunkAsync(Conn = AutoProtocol) (const(char)[] url, size_t chunkSize = 1024, size_t transmitBuffers = 10, Conn conn = Conn()) if (isCurlConn!(Conn)) { static if (is(Conn : AutoProtocol)) { if (isFTPUrl(url)) return byChunkAsync(url, cast(void[])null, chunkSize, transmitBuffers, FTP()); else return byChunkAsync(url, cast(void[])null, chunkSize, transmitBuffers, HTTP()); } else { return byChunkAsync(url, cast(void[])null, chunkSize, transmitBuffers, conn); } } unittest { foreach (host; [testServer.addr, "http://"~testServer.addr]) { testServer.handle((s) { auto req = s.recvReq; s.send(httpOK(cast(ubyte[])[0, 1, 2, 3, 4, 5])); }); assert(byChunkAsync(host, 2).equal([[0, 1], [2, 3], [4, 5]])); } } /* Used by byLineAsync/byChunkAsync to duplicate an existing connection * that can be used exclusively in a spawned thread. */ private void _asyncDuplicateConnection(Conn, PostData) (const(char)[] url, Conn conn, PostData postData, Tid tid) { // no move semantic available in std.concurrency ie. must use casting. auto connDup = conn.dup(); connDup.url = url; static if ( is(Conn : HTTP) ) { connDup.p.headersOut = null; connDup.method = conn.method == HTTP.Method.undefined ? HTTP.Method.get : conn.method; if (postData !is null) { if (connDup.method == HTTP.Method.put) { connDup.handle.set(CurlOption.infilesize_large, postData.length); } else { // post connDup.method = HTTP.Method.post; connDup.handle.set(CurlOption.postfieldsize_large, postData.length); } connDup.handle.set(CurlOption.copypostfields, cast(void*) postData.ptr); } tid.send(cast(ulong)connDup.handle.handle); tid.send(connDup.method); } else { enforce!CurlException(postData is null, "Cannot put ftp data using byLineAsync()"); tid.send(cast(ulong)connDup.handle.handle); tid.send(HTTP.Method.undefined); } connDup.p.curl.handle = null; // make sure handle is not freed } /* Mixin template for all supported curl protocols. This is the commom functionallity such as timeouts and network interface settings. This should really be in the HTTP/FTP/SMTP structs but the documentation tool does not support a mixin to put its doc strings where a mixin is done. Therefore docs in this template is copied into each of HTTP/FTP/SMTP below. */ private mixin template Protocol() { /// Value to return from $(D onSend)/$(D onReceive) delegates in order to /// pause a request alias requestPause = CurlReadFunc.pause; /// Value to return from onSend delegate in order to abort a request alias requestAbort = CurlReadFunc.abort; static uint defaultAsyncStringBufferSize = 100; /** The curl handle used by this connection. */ @property ref Curl handle() return { return p.curl; } /** True if the instance is stopped. A stopped instance is not usable. */ @property bool isStopped() { return p.curl.stopped; } /// Stop and invalidate this instance. void shutdown() { p.curl.shutdown(); } /** Set verbose. This will print request information to stderr. */ @property void verbose(bool on) { p.curl.set(CurlOption.verbose, on ? 1L : 0L); } // Connection settings /// Set timeout for activity on connection. @property void dataTimeout(Duration d) { p.curl.set(CurlOption.low_speed_limit, 1); p.curl.set(CurlOption.low_speed_time, d.total!"seconds"); } /** Set maximum time an operation is allowed to take. This includes dns resolution, connecting, data transfer, etc. */ @property void operationTimeout(Duration d) { p.curl.set(CurlOption.timeout_ms, d.total!"msecs"); } /// Set timeout for connecting. @property void connectTimeout(Duration d) { p.curl.set(CurlOption.connecttimeout_ms, d.total!"msecs"); } // Network settings /** Proxy * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY, _proxy) */ @property void proxy(const(char)[] host) { p.curl.set(CurlOption.proxy, host); } /** Proxy port * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXYPORT, _proxy_port) */ @property void proxyPort(ushort port) { p.curl.set(CurlOption.proxyport, cast(long) port); } /// Type of proxy alias CurlProxy = etc.c.curl.CurlProxy; /** Proxy type * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY, _proxy_type) */ @property void proxyType(CurlProxy type) { p.curl.set(CurlOption.proxytype, cast(long) type); } /// DNS lookup timeout. @property void dnsTimeout(Duration d) { p.curl.set(CurlOption.dns_cache_timeout, d.total!"msecs"); } /** * The network interface to use in form of the the IP of the interface. * * Example: * ---- * theprotocol.netInterface = "192.168.1.32"; * theprotocol.netInterface = [ 192, 168, 1, 32 ]; * ---- * * See: $(XREF socket, InternetAddress) */ @property void netInterface(const(char)[] i) { p.curl.set(CurlOption.intrface, i); } /// ditto @property void netInterface(const(ubyte)[4] i) { auto str = format("%d.%d.%d.%d", i[0], i[1], i[2], i[3]); netInterface = str; } /// ditto @property void netInterface(InternetAddress i) { netInterface = i.toAddrString(); } /** Set the local outgoing port to use. Params: port = the first outgoing port number to try and use */ @property void localPort(ushort port) { p.curl.set(CurlOption.localport, cast(long)port); } /** Set the local outgoing port range to use. This can be used together with the localPort property. Params: range = if the first port is occupied then try this many port number forwards */ @property void localPortRange(ushort range) { p.curl.set(CurlOption.localportrange, cast(long)range); } /** Set the tcp no-delay socket option on or off. See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTTCPNODELAY, nodelay) */ @property void tcpNoDelay(bool on) { p.curl.set(CurlOption.tcp_nodelay, cast(long) (on ? 1 : 0) ); } /** Sets whether SSL peer certificates should be verified. See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTSSLVERIFYPEER, verifypeer) */ @property void verifyPeer(bool on) { p.curl.set(CurlOption.ssl_verifypeer, on ? 1 : 0); } /** Sets whether the host within an SSL certificate should be verified. See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTSSLVERIFYHOST, verifypeer) */ @property void verifyHost(bool on) { p.curl.set(CurlOption.ssl_verifyhost, on ? 2 : 0); } // Authentication settings /** Set the user name, password and optionally domain for authentication purposes. Some protocols may need authentication in some cases. Use this function to provide credentials. Params: username = the username password = the password domain = used for NTLM authentication only and is set to the NTLM domain name */ void setAuthentication(const(char)[] username, const(char)[] password, const(char)[] domain = "") { if (!domain.empty) username = format("%s/%s", domain, username); p.curl.set(CurlOption.userpwd, format("%s:%s", username, password)); } unittest { testServer.handle((s) { auto req = s.recvReq; assert(req.hdrs.canFind("GET /")); assert(req.hdrs.canFind("Basic dXNlcjpwYXNz")); s.send(httpOK()); }); auto http = HTTP(testServer.addr); http.onReceive = (ubyte[] data) { return data.length; }; http.setAuthentication("user", "pass"); http.perform(); } /** Set the user name and password for proxy authentication. Params: username = the username password = the password */ void setProxyAuthentication(const(char)[] username, const(char)[] password) { p.curl.set(CurlOption.proxyuserpwd, format("%s:%s", username.replace(":", "%3A"), password.replace(":", "%3A")) ); } /** * The event handler that gets called when data is needed for sending. The * length of the $(D void[]) specifies the maximum number of bytes that can * be sent. * * Returns: * The callback returns the number of elements in the buffer that have been * filled and are ready to send. * The special value $(D .abortRequest) can be returned in order to abort the * current request. * The special value $(D .pauseRequest) can be returned in order to pause the * current request. * * Example: * ---- * import std.net.curl; * string msg = "Hello world"; * auto client = HTTP("dlang.org"); * client.onSend = delegate size_t(void[] data) * { * auto m = cast(void[])msg; * size_t length = m.length > data.length ? data.length : m.length; * if (length == 0) return 0; * data[0..length] = m[0..length]; * msg = msg[length..$]; * return length; * }; * client.perform(); * ---- */ @property void onSend(size_t delegate(void[]) callback) { p.curl.clear(CurlOption.postfields); // cannot specify data when using callback p.curl.onSend = callback; } /** * The event handler that receives incoming data. Be sure to copy the * incoming ubyte[] since it is not guaranteed to be valid after the * callback returns. * * Returns: * The callback returns the number of incoming bytes read. If the entire array is * not read the request will abort. * The special value .pauseRequest can be returned in order to pause the * current request. * * Example: * ---- * import std.net.curl, std.stdio; * auto client = HTTP("dlang.org"); * client.onReceive = (ubyte[] data) * { * writeln("Got data", to!(const(char)[])(data)); * return data.length; * }; * client.perform(); * ---- */ @property void onReceive(size_t delegate(ubyte[]) callback) { p.curl.onReceive = callback; } /** * The event handler that gets called to inform of upload/download progress. * * Params: * dlTotal = total bytes to download * dlNow = currently downloaded bytes * ulTotal = total bytes to upload * ulNow = currently uploaded bytes * * Returns: * Return 0 from the callback to signal success, return non-zero to abort * transfer * * Example: * ---- * import std.net.curl, std.stdio; * auto client = HTTP("dlang.org"); * client.onProgress = delegate int(size_t dl, size_t dln, size_t ul, size_t ult) * { * writeln("Progress: downloaded ", dln, " of ", dl); * writeln("Progress: uploaded ", uln, " of ", ul); * }; * client.perform(); * ---- */ @property void onProgress(int delegate(size_t dlTotal, size_t dlNow, size_t ulTotal, size_t ulNow) callback) { p.curl.onProgress = callback; } } /* Decode $(D ubyte[]) array using the provided EncodingScheme up to maxChars Returns: Tuple of ubytes read and the $(D Char[]) characters decoded. Not all ubytes are guaranteed to be read in case of decoding error. */ private Tuple!(size_t,Char[]) decodeString(Char = char)(const(ubyte)[] data, EncodingScheme scheme, size_t maxChars = size_t.max) { Char[] res; auto startLen = data.length; size_t charsDecoded = 0; while (data.length && charsDecoded < maxChars) { dchar dc = scheme.safeDecode(data); if (dc == INVALID_SEQUENCE) { return typeof(return)(size_t.max, cast(Char[])null); } charsDecoded++; res ~= dc; } return typeof(return)(startLen-data.length, res); } /* Decode $(D ubyte[]) array using the provided $(D EncodingScheme) until a the line terminator specified is found. The basesrc parameter is effectively prepended to src as the first thing. This function is used for decoding as much of the src buffer as possible until either the terminator is found or decoding fails. If it fails as the last data in the src it may mean that the src buffer were missing some bytes in order to represent a correct code point. Upon the next call to this function more bytes have been received from net and the failing bytes should be given as the basesrc parameter. It is done this way to minimize data copying. Returns: true if a terminator was found Not all ubytes are guaranteed to be read in case of decoding error. any decoded chars will be inserted into dst. */ private bool decodeLineInto(Terminator, Char = char)(ref const(ubyte)[] basesrc, ref const(ubyte)[] src, ref Char[] dst, EncodingScheme scheme, Terminator terminator) { auto startLen = src.length; size_t charsDecoded = 0; // if there is anything in the basesrc then try to decode that // first. if (basesrc.length != 0) { // Try to ensure 4 entries in the basesrc by copying from src. auto blen = basesrc.length; size_t len = (basesrc.length + src.length) >= 4 ? 4 : basesrc.length + src.length; basesrc.length = len; dchar dc = scheme.safeDecode(basesrc); if (dc == INVALID_SEQUENCE) { enforce!CurlException(len != 4, "Invalid code sequence"); return false; } dst ~= dc; src = src[len-basesrc.length-blen .. $]; // remove used ubytes from src basesrc.length = 0; } while (src.length) { auto lsrc = src; dchar dc = scheme.safeDecode(src); if (dc == INVALID_SEQUENCE) { if (src.empty) { // The invalid sequence was in the end of the src. Maybe there // just need to be more bytes available so these last bytes are // put back to src for later use. src = lsrc; return false; } dc = '?'; } dst ~= dc; if (dst.endsWith(terminator)) return true; } return false; // no terminator found } /** * HTTP client functionality. * * Example: * --- * import std.net.curl, std.stdio; * * // Get with custom data receivers * auto http = HTTP("dlang.org"); * http.onReceiveHeader = * (in char[] key, in char[] value) { writeln(key ~ ": " ~ value); }; * http.onReceive = (ubyte[] data) { /+ drop +/ return data.length; }; * http.perform(); * * // Put with data senders * auto msg = "Hello world"; * http.contentLength = msg.length; * http.onSend = (void[] data) * { * auto m = cast(void[])msg; * size_t len = m.length > data.length ? data.length : m.length; * if (len == 0) return len; * data[0..len] = m[0..len]; * msg = msg[len..$]; * return len; * }; * http.perform(); * * // Track progress * http.method = HTTP.Method.get; * http.url = "http://upload.wikimedia.org/wikipedia/commons/" * "5/53/Wikipedia-logo-en-big.png"; * http.onReceive = (ubyte[] data) { return data.length; }; * http.onProgress = (size_t dltotal, size_t dlnow, * size_t ultotal, size_t ulnow) * { * writeln("Progress ", dltotal, ", ", dlnow, ", ", ultotal, ", ", ulnow); * return 0; * }; * http.perform(); * --- * * See_Also: $(WEB www.ietf.org/rfc/rfc2616.txt, RFC2616) * */ struct HTTP { mixin Protocol; /// Authentication method equal to $(ECXREF curl, CurlAuth) alias AuthMethod = CurlAuth; static private uint defaultMaxRedirects = 10; private struct Impl { ~this() { if (headersOut !is null) Curl.curl.slist_free_all(headersOut); if (curl.handle !is null) // work around RefCounted/emplace bug curl.shutdown(); } Curl curl; curl_slist* headersOut; string[string] headersIn; string charset; /// The status line of the final sub-request in a request. StatusLine status; private void delegate(StatusLine) onReceiveStatusLine; /// The HTTP method to use. Method method = Method.undefined; @property void onReceiveHeader(void delegate(in char[] key, in char[] value) callback) { // Wrap incoming callback in order to separate http status line from // http headers. On redirected requests there may be several such // status lines. The last one is the one recorded. auto dg = (in char[] header) { import std.utf : UTFException; try { if (header.empty) { // header delimiter return; } if (header.startsWith("HTTP/")) { string[string] empty; headersIn = empty; // clear auto m = match(header, regex(r"^HTTP/(\d+)\.(\d+) (\d+) (.*)$")); if (m.empty) { // Invalid status line } else { status.majorVersion = to!ushort(m.captures[1]); status.minorVersion = to!ushort(m.captures[2]); status.code = to!ushort(m.captures[3]); status.reason = m.captures[4].idup; if (onReceiveStatusLine != null) onReceiveStatusLine(status); } return; } // Normal http header auto m = match(cast(char[]) header, regex("(.*?): (.*)$")); auto fieldName = m.captures[1].toLower().idup; if (fieldName == "content-type") { auto mct = match(cast(char[]) m.captures[2], regex("charset=([^;]*)")); if (!mct.empty && mct.captures.length > 1) charset = mct.captures[1].idup; } if (!m.empty && callback !is null) callback(fieldName, m.captures[2]); headersIn[fieldName] = m.captures[2].idup; } catch(UTFException e) { //munch it - a header should be all ASCII, any "wrong UTF" is broken header } }; curl.onReceiveHeader = dg; } } private RefCounted!Impl p; /** Time condition enumeration as an alias of $(ECXREF curl, CurlTimeCond) $(WEB www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25, _RFC2616 Section 14.25) */ alias TimeCond = CurlTimeCond; /** Constructor taking the url as parameter. */ static HTTP opCall(const(char)[] url) { HTTP http; http.initialize(); http.url = url; return http; } static HTTP opCall() { HTTP http; http.initialize(); return http; } HTTP dup() { HTTP copy; copy.initialize(); copy.p.method = p.method; curl_slist* cur = p.headersOut; curl_slist* newlist = null; while (cur) { newlist = Curl.curl.slist_append(newlist, cur.data); cur = cur.next; } copy.p.headersOut = newlist; copy.p.curl.set(CurlOption.httpheader, copy.p.headersOut); copy.p.curl = p.curl.dup(); copy.dataTimeout = _defaultDataTimeout; copy.onReceiveHeader = null; return copy; } private void initialize() { p.curl.initialize(); maxRedirects = HTTP.defaultMaxRedirects; p.charset = "ISO-8859-1"; // Default charset defined in HTTP RFC p.method = Method.undefined; setUserAgent(HTTP.defaultUserAgent); dataTimeout = _defaultDataTimeout; onReceiveHeader = null; verifyPeer = true; verifyHost = true; } /** Perform a http request. After the HTTP client has been setup and possibly assigned callbacks the $(D perform()) method will start performing the request towards the specified server. Params: throwOnError = whether to throw an exception or return a CurlCode on error */ CurlCode perform(ThrowOnError throwOnError = ThrowOnError.yes) { p.status.reset(); CurlOption opt; final switch (p.method) { case Method.head: p.curl.set(CurlOption.nobody, 1L); opt = CurlOption.nobody; break; case Method.undefined: case Method.get: p.curl.set(CurlOption.httpget, 1L); opt = CurlOption.httpget; break; case Method.post: p.curl.set(CurlOption.post, 1L); opt = CurlOption.post; break; case Method.put: p.curl.set(CurlOption.upload, 1L); opt = CurlOption.upload; break; case Method.del: p.curl.set(CurlOption.customrequest, "DELETE"); opt = CurlOption.customrequest; break; case Method.options: p.curl.set(CurlOption.customrequest, "OPTIONS"); opt = CurlOption.customrequest; break; case Method.trace: p.curl.set(CurlOption.customrequest, "TRACE"); opt = CurlOption.customrequest; break; case Method.connect: p.curl.set(CurlOption.customrequest, "CONNECT"); opt = CurlOption.customrequest; break; case Method.patch: p.curl.set(CurlOption.customrequest, "PATCH"); opt = CurlOption.customrequest; break; } scope (exit) p.curl.clear(opt); return p.curl.perform(throwOnError); } /// The URL to specify the location of the resource. @property void url(const(char)[] url) { if (!startsWith(url.toLower(), "http://", "https://")) url = "http://" ~ url; p.curl.set(CurlOption.url, url); } /// Set the CA certificate bundle file to use for SSL peer verification @property void caInfo(const(char)[] caFile) { p.curl.set(CurlOption.cainfo, caFile); } // This is a workaround for mixed in content not having its // docs mixed in. version (StdDdoc) { /// Value to return from $(D onSend)/$(D onReceive) delegates in order to /// pause a request alias requestPause = CurlReadFunc.pause; /// Value to return from onSend delegate in order to abort a request alias requestAbort = CurlReadFunc.abort; /** True if the instance is stopped. A stopped instance is not usable. */ @property bool isStopped(); /// Stop and invalidate this instance. void shutdown(); /** Set verbose. This will print request information to stderr. */ @property void verbose(bool on); // Connection settings /// Set timeout for activity on connection. @property void dataTimeout(Duration d); /** Set maximum time an operation is allowed to take. This includes dns resolution, connecting, data transfer, etc. */ @property void operationTimeout(Duration d); /// Set timeout for connecting. @property void connectTimeout(Duration d); // Network settings /** Proxy * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY, _proxy) */ @property void proxy(const(char)[] host); /** Proxy port * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXYPORT, _proxy_port) */ @property void proxyPort(ushort port); /// Type of proxy alias CurlProxy = etc.c.curl.CurlProxy; /** Proxy type * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY, _proxy_type) */ @property void proxyType(CurlProxy type); /// DNS lookup timeout. @property void dnsTimeout(Duration d); /** * The network interface to use in form of the the IP of the interface. * * Example: * ---- * theprotocol.netInterface = "192.168.1.32"; * theprotocol.netInterface = [ 192, 168, 1, 32 ]; * ---- * * See: $(XREF socket, InternetAddress) */ @property void netInterface(const(char)[] i); /// ditto @property void netInterface(const(ubyte)[4] i); /// ditto @property void netInterface(InternetAddress i); /** Set the local outgoing port to use. Params: port = the first outgoing port number to try and use */ @property void localPort(ushort port); /** Set the local outgoing port range to use. This can be used together with the localPort property. Params: range = if the first port is occupied then try this many port number forwards */ @property void localPortRange(ushort range); /** Set the tcp no-delay socket option on or off. See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTTCPNODELAY, nodelay) */ @property void tcpNoDelay(bool on); // Authentication settings /** Set the user name, password and optionally domain for authentication purposes. Some protocols may need authentication in some cases. Use this function to provide credentials. Params: username = the username password = the password domain = used for NTLM authentication only and is set to the NTLM domain name */ void setAuthentication(const(char)[] username, const(char)[] password, const(char)[] domain = ""); /** Set the user name and password for proxy authentication. Params: username = the username password = the password */ void setProxyAuthentication(const(char)[] username, const(char)[] password); /** * The event handler that gets called when data is needed for sending. The * length of the $(D void[]) specifies the maximum number of bytes that can * be sent. * * Returns: * The callback returns the number of elements in the buffer that have been * filled and are ready to send. * The special value $(D .abortRequest) can be returned in order to abort the * current request. * The special value $(D .pauseRequest) can be returned in order to pause the * current request. * * Example: * ---- * import std.net.curl; * string msg = "Hello world"; * auto client = HTTP("dlang.org"); * client.onSend = delegate size_t(void[] data) * { * auto m = cast(void[])msg; * size_t length = m.length > data.length ? data.length : m.length; * if (length == 0) return 0; * data[0..length] = m[0..length]; * msg = msg[length..$]; * return length; * }; * client.perform(); * ---- */ @property void onSend(size_t delegate(void[]) callback); /** * The event handler that receives incoming data. Be sure to copy the * incoming ubyte[] since it is not guaranteed to be valid after the * callback returns. * * Returns: * The callback returns the incoming bytes read. If not the entire array is * the request will abort. * The special value .pauseRequest can be returned in order to pause the * current request. * * Example: * ---- * import std.net.curl, std.stdio; * auto client = HTTP("dlang.org"); * client.onReceive = (ubyte[] data) * { * writeln("Got data", to!(const(char)[])(data)); * return data.length; * }; * client.perform(); * ---- */ @property void onReceive(size_t delegate(ubyte[]) callback); /** * Register an event handler that gets called to inform of * upload/download progress. * * Callback_parameters: * $(CALLBACK_PARAMS) * * Callback_returns: Return 0 to signal success, return non-zero to * abort transfer. * * Example: * ---- * import std.net.curl, std.stdio; * auto client = HTTP("dlang.org"); * client.onProgress = delegate int(size_t dl, size_t dln, size_t ul, size_t ult) * { * writeln("Progress: downloaded ", dln, " of ", dl); * writeln("Progress: uploaded ", uln, " of ", ul); * }; * client.perform(); * ---- */ @property void onProgress(int delegate(size_t dlTotal, size_t dlNow, size_t ulTotal, size_t ulNow) callback); } /** Clear all outgoing headers. */ void clearRequestHeaders() { if (p.headersOut !is null) Curl.curl.slist_free_all(p.headersOut); p.headersOut = null; p.curl.clear(CurlOption.httpheader); } /** Add a header e.g. "X-CustomField: Something is fishy". * * There is no remove header functionality. Do a $(LREF clearRequestHeaders) * and set the needed headers instead. * * Example: * --- * import std.net.curl; * auto client = HTTP(); * client.addRequestHeader("X-Custom-ABC", "This is the custom value"); * auto content = get("dlang.org", client); * --- */ void addRequestHeader(const(char)[] name, const(char)[] value) { if (icmp(name, "User-Agent") == 0) return setUserAgent(value); string nv = format("%s: %s", name, value); p.headersOut = Curl.curl.slist_append(p.headersOut, nv.tempCString().buffPtr); p.curl.set(CurlOption.httpheader, p.headersOut); } /** * The default "User-Agent" value send with a request. * It has the form "Phobos-std.net.curl/$(I PHOBOS_VERSION) (libcurl/$(I CURL_VERSION))" */ static string defaultUserAgent() @property { import std.compiler : version_major, version_minor; // http://curl.haxx.se/docs/versions.html enum fmt = "Phobos-std.net.curl/%d.%03d (libcurl/%d.%d.%d)"; enum maxLen = fmt.length - "%d%03d%d%d%d".length + 10 + 10 + 3 + 3 + 3; static char[maxLen] buf = void; static string userAgent; if (!userAgent.length) { auto curlVer = Curl.curl.version_info(CURLVERSION_NOW).version_num; userAgent = cast(immutable)sformat( buf, fmt, version_major, version_minor, curlVer >> 16 & 0xFF, curlVer >> 8 & 0xFF, curlVer & 0xFF); } return userAgent; } /** Set the value of the user agent request header field. * * By default a request has it's "User-Agent" field set to $(LREF * defaultUserAgent) even if $(D setUserAgent) was never called. Pass * an empty string to suppress the "User-Agent" field altogether. */ void setUserAgent(const(char)[] userAgent) { p.curl.set(CurlOption.useragent, userAgent); } /** The headers read from a successful response. * */ @property string[string] responseHeaders() { return p.headersIn; } /// HTTP method used. @property void method(Method m) { p.method = m; } /// ditto @property Method method() { return p.method; } /** HTTP status line of last response. One call to perform may result in several requests because of redirection. */ @property StatusLine statusLine() { return p.status; } /// Set the active cookie string e.g. "name1=value1;name2=value2" void setCookie(const(char)[] cookie) { p.curl.set(CurlOption.cookie, cookie); } /// Set a file path to where a cookie jar should be read/stored. void setCookieJar(const(char)[] path) { p.curl.set(CurlOption.cookiefile, path); if (path.length) p.curl.set(CurlOption.cookiejar, path); } /// Flush cookie jar to disk. void flushCookieJar() { p.curl.set(CurlOption.cookielist, "FLUSH"); } /// Clear session cookies. void clearSessionCookies() { p.curl.set(CurlOption.cookielist, "SESS"); } /// Clear all cookies. void clearAllCookies() { p.curl.set(CurlOption.cookielist, "ALL"); } /** Set time condition on the request. Params: cond = $(D CurlTimeCond.{none,ifmodsince,ifunmodsince,lastmod}) timestamp = Timestamp for the condition $(WEB www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25, _RFC2616 Section 14.25) */ void setTimeCondition(HTTP.TimeCond cond, SysTime timestamp) { p.curl.set(CurlOption.timecondition, cond); p.curl.set(CurlOption.timevalue, timestamp.toUnixTime()); } /** Specifying data to post when not using the onSend callback. * * The data is NOT copied by the library. Content-Type will default to * application/octet-stream. Data is not converted or encoded by this * method. * * Example: * ---- * import std.net.curl, std.stdio; * auto http = HTTP("http://www.mydomain.com"); * http.onReceive = (ubyte[] data) { writeln(to!(const(char)[])(data)); return data.length; }; * http.postData = [1,2,3,4,5]; * http.perform(); * ---- */ @property void postData(const(void)[] data) { setPostData(data, "application/octet-stream"); } /** Specifying data to post when not using the onSend callback. * * The data is NOT copied by the library. Content-Type will default to * text/plain. Data is not converted or encoded by this method. * * Example: * ---- * import std.net.curl, std.stdio; * auto http = HTTP("http://www.mydomain.com"); * http.onReceive = (ubyte[] data) { writeln(to!(const(char)[])(data)); return data.length; }; * http.postData = "The quick...."; * http.perform(); * ---- */ @property void postData(const(char)[] data) { setPostData(data, "text/plain"); } /** * Specify data to post when not using the onSend callback, with * user-specified Content-Type. * Params: * data = Data to post. * contentType = MIME type of the data, for example, "text/plain" or * "application/octet-stream". See also: * $(LINK2 http://en.wikipedia.org/wiki/Internet_media_type, * Internet media type) on Wikipedia. * ----- * import std.net.curl; * auto http = HTTP("http://onlineform.example.com"); * auto data = "app=login&username=bob&password=s00perS3kret"; * http.setPostData(data, "application/x-www-form-urlencoded"); * http.onReceive = (ubyte[] data) { return data.length; }; * http.perform(); * ----- */ void setPostData(const(void)[] data, string contentType) { // cannot use callback when specifying data directly so it is disabled here. p.curl.clear(CurlOption.readfunction); addRequestHeader("Content-Type", contentType); p.curl.set(CurlOption.postfields, cast(void*)data.ptr); p.curl.set(CurlOption.postfieldsize, data.length); if (method == Method.undefined) method = Method.post; } unittest { testServer.handle((s) { auto req = s.recvReq!ubyte; assert(req.hdrs.canFind("POST /path")); assert(req.bdy.canFind(cast(ubyte[])[0, 1, 2, 3, 4])); assert(req.bdy.canFind(cast(ubyte[])[253, 254, 255])); s.send(httpOK(cast(ubyte[])[17, 27, 35, 41])); }); auto data = new ubyte[](256); foreach (i, ref ub; data) ub = cast(ubyte)i; auto http = HTTP(testServer.addr~"/path"); http.postData = data; ubyte[] res; http.onReceive = (data) { res ~= data; return data.length; }; http.perform(); assert(res == cast(ubyte[])[17, 27, 35, 41]); } /** * Set the event handler that receives incoming headers. * * The callback will receive a header field key, value as parameter. The * $(D const(char)[]) arrays are not valid after the delegate has returned. * * Example: * ---- * import std.net.curl, std.stdio; * auto http = HTTP("dlang.org"); * http.onReceive = (ubyte[] data) { writeln(to!(const(char)[])(data)); return data.length; }; * http.onReceiveHeader = (in char[] key, in char[] value) { writeln(key, " = ", value); }; * http.perform(); * ---- */ @property void onReceiveHeader(void delegate(in char[] key, in char[] value) callback) { p.onReceiveHeader = callback; } /** Callback for each received StatusLine. Notice that several callbacks can be done for each call to $(D perform()) due to redirections. See_Also: $(LREF StatusLine) */ @property void onReceiveStatusLine(void delegate(StatusLine) callback) { p.onReceiveStatusLine = callback; } /** The content length in bytes when using request that has content e.g. POST/PUT and not using chunked transfer. Is set as the "Content-Length" header. Set to ulong.max to reset to chunked transfer. */ @property void contentLength(ulong len) { CurlOption lenOpt; // Force post if necessary if (p.method != Method.put && p.method != Method.post && p.method != Method.patch) p.method = Method.post; if (p.method == Method.post || p.method == Method.patch) lenOpt = CurlOption.postfieldsize_large; else lenOpt = CurlOption.infilesize_large; if (size_t.max != ulong.max && len == size_t.max) len = ulong.max; // check size_t.max for backwards compat, turn into error if (len == ulong.max) { // HTTP 1.1 supports requests with no length header set. addRequestHeader("Transfer-Encoding", "chunked"); addRequestHeader("Expect", "100-continue"); } else { p.curl.set(lenOpt, to!curl_off_t(len)); } } /** Authentication method as specified in $(LREF AuthMethod). */ @property void authenticationMethod(AuthMethod authMethod) { p.curl.set(CurlOption.httpauth, cast(long) authMethod); } /** Set max allowed redirections using the location header. uint.max for infinite. */ @property void maxRedirects(uint maxRedirs) { if (maxRedirs == uint.max) { // Disable p.curl.set(CurlOption.followlocation, 0); } else { p.curl.set(CurlOption.followlocation, 1); p.curl.set(CurlOption.maxredirs, maxRedirs); } } /** The standard HTTP methods : * $(WEB www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1, _RFC2616 Section 5.1.1) */ enum Method { undefined, head, /// get, /// post, /// put, /// del, /// options, /// trace, /// connect, /// patch, /// } /** HTTP status line ie. the first line returned in an HTTP response. If authentication or redirections are done then the status will be for the last response received. */ struct StatusLine { ushort majorVersion; /// Major HTTP version ie. 1 in HTTP/1.0. ushort minorVersion; /// Minor HTTP version ie. 0 in HTTP/1.0. ushort code; /// HTTP status line code e.g. 200. string reason; /// HTTP status line reason string. /// Reset this status line @safe void reset() { majorVersion = 0; minorVersion = 0; code = 0; reason = ""; } /// string toString() { return format("%s %s (%s.%s)", code, reason, majorVersion, minorVersion); } } } // HTTP /** FTP client functionality. See_Also: $(WEB tools.ietf.org/html/rfc959, RFC959) */ struct FTP { mixin Protocol; private struct Impl { ~this() { if (commands !is null) Curl.curl.slist_free_all(commands); if (curl.handle !is null) // work around RefCounted/emplace bug curl.shutdown(); } curl_slist* commands; Curl curl; string encoding; } private RefCounted!Impl p; /** FTP access to the specified url. */ static FTP opCall(const(char)[] url) { FTP ftp; ftp.initialize(); ftp.url = url; return ftp; } static FTP opCall() { FTP ftp; ftp.initialize(); return ftp; } FTP dup() { FTP copy = FTP(); copy.initialize(); copy.p.encoding = p.encoding; copy.p.curl = p.curl.dup(); curl_slist* cur = p.commands; curl_slist* newlist = null; while (cur) { newlist = Curl.curl.slist_append(newlist, cur.data); cur = cur.next; } copy.p.commands = newlist; copy.p.curl.set(CurlOption.postquote, copy.p.commands); copy.dataTimeout = _defaultDataTimeout; return copy; } private void initialize() { p.curl.initialize(); p.encoding = "ISO-8859-1"; dataTimeout = _defaultDataTimeout; } /** Performs the ftp request as it has been configured. After a FTP client has been setup and possibly assigned callbacks the $(D perform()) method will start performing the actual communication with the server. Params: throwOnError = whether to throw an exception or return a CurlCode on error */ CurlCode perform(ThrowOnError throwOnError = ThrowOnError.yes) { return p.curl.perform(throwOnError); } /// The URL to specify the location of the resource. @property void url(const(char)[] url) { if (!startsWith(url.toLower(), "ftp://", "ftps://")) url = "ftp://" ~ url; p.curl.set(CurlOption.url, url); } // This is a workaround for mixed in content not having its // docs mixed in. version (StdDdoc) { /// Value to return from $(D onSend)/$(D onReceive) delegates in order to /// pause a request alias requestPause = CurlReadFunc.pause; /// Value to return from onSend delegate in order to abort a request alias requestAbort = CurlReadFunc.abort; /** True if the instance is stopped. A stopped instance is not usable. */ @property bool isStopped(); /// Stop and invalidate this instance. void shutdown(); /** Set verbose. This will print request information to stderr. */ @property void verbose(bool on); // Connection settings /// Set timeout for activity on connection. @property void dataTimeout(Duration d); /** Set maximum time an operation is allowed to take. This includes dns resolution, connecting, data transfer, etc. */ @property void operationTimeout(Duration d); /// Set timeout for connecting. @property void connectTimeout(Duration d); // Network settings /** Proxy * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY, _proxy) */ @property void proxy(const(char)[] host); /** Proxy port * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXYPORT, _proxy_port) */ @property void proxyPort(ushort port); /// Type of proxy alias CurlProxy = etc.c.curl.CurlProxy; /** Proxy type * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY, _proxy_type) */ @property void proxyType(CurlProxy type); /// DNS lookup timeout. @property void dnsTimeout(Duration d); /** * The network interface to use in form of the the IP of the interface. * * Example: * ---- * theprotocol.netInterface = "192.168.1.32"; * theprotocol.netInterface = [ 192, 168, 1, 32 ]; * ---- * * See: $(XREF socket, InternetAddress) */ @property void netInterface(const(char)[] i); /// ditto @property void netInterface(const(ubyte)[4] i); /// ditto @property void netInterface(InternetAddress i); /** Set the local outgoing port to use. Params: port = the first outgoing port number to try and use */ @property void localPort(ushort port); /** Set the local outgoing port range to use. This can be used together with the localPort property. Params: range = if the first port is occupied then try this many port number forwards */ @property void localPortRange(ushort range); /** Set the tcp no-delay socket option on or off. See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTTCPNODELAY, nodelay) */ @property void tcpNoDelay(bool on); // Authentication settings /** Set the user name, password and optionally domain for authentication purposes. Some protocols may need authentication in some cases. Use this function to provide credentials. Params: username = the username password = the password domain = used for NTLM authentication only and is set to the NTLM domain name */ void setAuthentication(const(char)[] username, const(char)[] password, const(char)[] domain = ""); /** Set the user name and password for proxy authentication. Params: username = the username password = the password */ void setProxyAuthentication(const(char)[] username, const(char)[] password); /** * The event handler that gets called when data is needed for sending. The * length of the $(D void[]) specifies the maximum number of bytes that can * be sent. * * Returns: * The callback returns the number of elements in the buffer that have been * filled and are ready to send. * The special value $(D .abortRequest) can be returned in order to abort the * current request. * The special value $(D .pauseRequest) can be returned in order to pause the * current request. * */ @property void onSend(size_t delegate(void[]) callback); /** * The event handler that receives incoming data. Be sure to copy the * incoming ubyte[] since it is not guaranteed to be valid after the * callback returns. * * Returns: * The callback returns the incoming bytes read. If not the entire array is * the request will abort. * The special value .pauseRequest can be returned in order to pause the * current request. * */ @property void onReceive(size_t delegate(ubyte[]) callback); /** * The event handler that gets called to inform of upload/download progress. * * Callback_parameters: * $(CALLBACK_PARAMS) * * Callback_returns: * Return 0 from the callback to signal success, return non-zero to * abort transfer. */ @property void onProgress(int delegate(size_t dlTotal, size_t dlNow, size_t ulTotal, size_t ulNow) callback); } /** Clear all commands send to ftp server. */ void clearCommands() { if (p.commands !is null) Curl.curl.slist_free_all(p.commands); p.commands = null; p.curl.clear(CurlOption.postquote); } /** Add a command to send to ftp server. * * There is no remove command functionality. Do a $(LREF clearCommands) and * set the needed commands instead. * * Example: * --- * import std.net.curl; * auto client = FTP(); * client.addCommand("RNFR my_file.txt"); * client.addCommand("RNTO my_renamed_file.txt"); * upload("my_file.txt", "ftp.digitalmars.com", client); * --- */ void addCommand(const(char)[] command) { p.commands = Curl.curl.slist_append(p.commands, command.tempCString().buffPtr); p.curl.set(CurlOption.postquote, p.commands); } /// Connection encoding. Defaults to ISO-8859-1. @property void encoding(string name) { p.encoding = name; } /// ditto @property string encoding() { return p.encoding; } /** The content length in bytes of the ftp data. */ @property void contentLength(ulong len) { p.curl.set(CurlOption.infilesize_large, to!curl_off_t(len)); } } /** * Basic SMTP protocol support. * * Example: * --- * import std.net.curl; * * // Send an email with SMTPS * auto smtp = SMTP("smtps://smtp.gmail.com"); * smtp.setAuthentication("from.addr@gmail.com", "password"); * smtp.mailTo = [""]; * smtp.mailFrom = ""; * smtp.message = "Example Message"; * smtp.perform(); * --- * * See_Also: $(WEB www.ietf.org/rfc/rfc2821.txt, RFC2821) */ struct SMTP { mixin Protocol; private struct Impl { ~this() { if (curl.handle !is null) // work around RefCounted/emplace bug curl.shutdown(); } Curl curl; @property void message(string msg) { auto _message = msg; /** This delegate reads the message text and copies it. */ curl.onSend = delegate size_t(void[] data) { if (!msg.length) return 0; auto m = cast(void[])msg; size_t to_copy = min(data.length, _message.length); data[0..to_copy] = (cast(void[])_message)[0..to_copy]; _message = _message[to_copy..$]; return to_copy; }; } } private RefCounted!Impl p; /** Sets to the URL of the SMTP server. */ static SMTP opCall(const(char)[] url) { SMTP smtp; smtp.initialize(); smtp.url = url; return smtp; } static SMTP opCall() { SMTP smtp; smtp.initialize(); return smtp; } /+ TODO: The other structs have this function. SMTP dup() { SMTP copy = SMTP(); copy.initialize(); copy.p.encoding = p.encoding; copy.p.curl = p.curl.dup(); curl_slist* cur = p.commands; curl_slist* newlist = null; while (cur) { newlist = Curl.curl.slist_append(newlist, cur.data); cur = cur.next; } copy.p.commands = newlist; copy.p.curl.set(CurlOption.postquote, copy.p.commands); copy.dataTimeout = _defaultDataTimeout; return copy; } +/ /** Performs the request as configured. Params: throwOnError = whether to throw an exception or return a CurlCode on error */ CurlCode perform(ThrowOnError throwOnError = ThrowOnError.yes) { return p.curl.perform(throwOnError); } /// The URL to specify the location of the resource. @property void url(const(char)[] url) { auto lowered = url.toLower(); if (lowered.startsWith("smtps://")) { p.curl.set(CurlOption.use_ssl, CurlUseSSL.all); } else { enforce!CurlException(lowered.startsWith("smtp://"), "The url must be for the smtp protocol."); } p.curl.set(CurlOption.url, url); } private void initialize() { p.curl.initialize(); p.curl.set(CurlOption.upload, 1L); dataTimeout = _defaultDataTimeout; verifyPeer = true; verifyHost = true; } // This is a workaround for mixed in content not having its // docs mixed in. version (StdDdoc) { /// Value to return from $(D onSend)/$(D onReceive) delegates in order to /// pause a request alias requestPause = CurlReadFunc.pause; /// Value to return from onSend delegate in order to abort a request alias requestAbort = CurlReadFunc.abort; /** True if the instance is stopped. A stopped instance is not usable. */ @property bool isStopped(); /// Stop and invalidate this instance. void shutdown(); /** Set verbose. This will print request information to stderr. */ @property void verbose(bool on); // Connection settings /// Set timeout for activity on connection. @property void dataTimeout(Duration d); /** Set maximum time an operation is allowed to take. This includes dns resolution, connecting, data transfer, etc. */ @property void operationTimeout(Duration d); /// Set timeout for connecting. @property void connectTimeout(Duration d); // Network settings /** Proxy * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY, _proxy) */ @property void proxy(const(char)[] host); /** Proxy port * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXYPORT, _proxy_port) */ @property void proxyPort(ushort port); /// Type of proxy alias CurlProxy = etc.c.curl.CurlProxy; /** Proxy type * See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY, _proxy_type) */ @property void proxyType(CurlProxy type); /// DNS lookup timeout. @property void dnsTimeout(Duration d); /** * The network interface to use in form of the the IP of the interface. * * Example: * ---- * theprotocol.netInterface = "192.168.1.32"; * theprotocol.netInterface = [ 192, 168, 1, 32 ]; * ---- * * See: $(XREF socket, InternetAddress) */ @property void netInterface(const(char)[] i); /// ditto @property void netInterface(const(ubyte)[4] i); /// ditto @property void netInterface(InternetAddress i); /** Set the local outgoing port to use. Params: port = the first outgoing port number to try and use */ @property void localPort(ushort port); /** Set the local outgoing port range to use. This can be used together with the localPort property. Params: range = if the first port is occupied then try this many port number forwards */ @property void localPortRange(ushort range); /** Set the tcp no-delay socket option on or off. See: $(WEB curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTTCPNODELAY, nodelay) */ @property void tcpNoDelay(bool on); // Authentication settings /** Set the user name, password and optionally domain for authentication purposes. Some protocols may need authentication in some cases. Use this function to provide credentials. Params: username = the username password = the password domain = used for NTLM authentication only and is set to the NTLM domain name */ void setAuthentication(const(char)[] username, const(char)[] password, const(char)[] domain = ""); /** Set the user name and password for proxy authentication. Params: username = the username password = the password */ void setProxyAuthentication(const(char)[] username, const(char)[] password); /** * The event handler that gets called when data is needed for sending. The * length of the $(D void[]) specifies the maximum number of bytes that can * be sent. * * Returns: * The callback returns the number of elements in the buffer that have been * filled and are ready to send. * The special value $(D .abortRequest) can be returned in order to abort the * current request. * The special value $(D .pauseRequest) can be returned in order to pause the * current request. */ @property void onSend(size_t delegate(void[]) callback); /** * The event handler that receives incoming data. Be sure to copy the * incoming ubyte[] since it is not guaranteed to be valid after the * callback returns. * * Returns: * The callback returns the incoming bytes read. If not the entire array is * the request will abort. * The special value .pauseRequest can be returned in order to pause the * current request. */ @property void onReceive(size_t delegate(ubyte[]) callback); /** * The event handler that gets called to inform of upload/download progress. * * Callback_parameters: * $(CALLBACK_PARAMS) * * Callback_returns: * Return 0 from the callback to signal success, return non-zero to * abort transfer. */ @property void onProgress(int delegate(size_t dlTotal, size_t dlNow, size_t ulTotal, size_t ulNow) callback); } /** Setter for the sender's email address. */ @property void mailFrom()(const(char)[] sender) { assert(!sender.empty, "Sender must not be empty"); p.curl.set(CurlOption.mail_from, sender); } /** Setter for the recipient email addresses. */ void mailTo()(const(char)[][] recipients...) { assert(!recipients.empty, "Recipient must not be empty"); curl_slist* recipients_list = null; foreach(recipient; recipients) { recipients_list = Curl.curl.slist_append(recipients_list, recipient.tempCString().buffPtr); } p.curl.set(CurlOption.mail_rcpt, recipients_list); } /** Sets the message body text. */ @property void message(string msg) { p.message = msg; } } /++ Exception thrown on errors in std.net.curl functions. +/ class CurlException : Exception { /++ Params: msg = The message for the exception. file = The file where the exception occurred. line = The line number where the exception occurred. next = The previous exception in the chain of exceptions, if any. +/ @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(msg, file, line, next); } } /++ Exception thrown on timeout errors in std.net.curl functions. +/ class CurlTimeoutException : CurlException { /++ Params: msg = The message for the exception. file = The file where the exception occurred. line = The line number where the exception occurred. next = The previous exception in the chain of exceptions, if any. +/ @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(msg, file, line, next); } } /// Equal to $(ECXREF curl, CURLcode) alias CurlCode = CURLcode; import std.typecons : Flag; /// Flag to specify whether or not an exception is thrown on error. alias ThrowOnError = Flag!"throwOnError"; private struct CurlAPI { static struct API { extern(C): import core.stdc.config : c_long; CURLcode function(c_long flags) global_init; void function() global_cleanup; curl_version_info_data * function(CURLversion) version_info; CURL* function() easy_init; CURLcode function(CURL *curl, CURLoption option,...) easy_setopt; CURLcode function(CURL *curl) easy_perform; CURL* function(CURL *curl) easy_duphandle; char* function(CURLcode) easy_strerror; CURLcode function(CURL *handle, int bitmask) easy_pause; void function(CURL *curl) easy_cleanup; curl_slist* function(curl_slist *, char *) slist_append; void function(curl_slist *) slist_free_all; } __gshared API _api; __gshared void* _handle; static ref API instance() @property { import std.concurrency; initOnce!_handle(loadAPI()); return _api; } static void* loadAPI() { version (Posix) { import core.sys.posix.dlfcn; alias loadSym = dlsym; } else version (Windows) { import core.sys.windows.windows; alias loadSym = GetProcAddress; } else static assert(0, "unimplemented"); void* handle; version (Posix) handle = dlopen(null, RTLD_LAZY); else version (Windows) handle = GetModuleHandleA(null); assert(handle !is null); // try to load curl from the executable to allow static linking if (loadSym(handle, "curl_global_init") is null) { version (Posix) dlclose(handle); version (OSX) static immutable names = ["libcurl.4.dylib"]; else version (Posix) static immutable names = ["libcurl.so", "libcurl.so.4", "libcurl-gnutls.so.4", "libcurl-nss.so.4", "libcurl.so.3"]; else version (Windows) static immutable names = ["libcurl.dll", "curl.dll"]; foreach (name; names) { version (Posix) handle = dlopen(name.ptr, RTLD_LAZY); else version (Windows) handle = LoadLibraryA(name.ptr); if (handle !is null) break; } enforce!CurlException(handle !is null, "Failed to load curl, tried %(%s, %).".format(names)); } foreach (i, FP; typeof(API.tupleof)) { enum name = __traits(identifier, _api.tupleof[i]); auto p = enforce!CurlException(loadSym(handle, "curl_"~name), "Couldn't load curl_"~name~" from libcurl."); _api.tupleof[i] = cast(FP) p; } enforce!CurlException(!_api.global_init(CurlGlobal.all), "Failed to initialize libcurl"); return handle; } shared static ~this() { if (_handle is null) return; _api.global_cleanup(); version (Posix) { import core.sys.posix.dlfcn; dlclose(_handle); } else version (Windows) { import core.sys.windows.windows; FreeLibrary(_handle); } else static assert(0, "unimplemented"); _api = API.init; _handle = null; } } /** Wrapper to provide a better interface to libcurl than using the plain C API. It is recommended to use the $(D HTTP)/$(D FTP) etc. structs instead unless raw access to libcurl is needed. Warning: This struct uses interior pointers for callbacks. Only allocate it on the stack if you never move or copy it. This also means passing by reference when passing Curl to other functions. Otherwise always allocate on the heap. */ struct Curl { alias OutData = void[]; alias InData = ubyte[]; bool stopped; private static auto ref curl() @property { return CurlAPI.instance; } // A handle should not be used by two threads simultaneously private CURL* handle; // May also return $(D CURL_READFUNC_ABORT) or $(D CURL_READFUNC_PAUSE) private size_t delegate(OutData) _onSend; private size_t delegate(InData) _onReceive; private void delegate(in char[]) _onReceiveHeader; private CurlSeek delegate(long,CurlSeekPos) _onSeek; private int delegate(curl_socket_t,CurlSockType) _onSocketOption; private int delegate(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow) _onProgress; alias requestPause = CurlReadFunc.pause; alias requestAbort = CurlReadFunc.abort; /** Initialize the instance by creating a working curl handle. */ void initialize() { enforce!CurlException(!handle, "Curl instance already initialized"); handle = curl.easy_init(); enforce!CurlException(handle, "Curl instance couldn't be initialized"); stopped = false; set(CurlOption.nosignal, 1); } /** Duplicate this handle. The new handle will have all options set as the one it was duplicated from. An exception to this is that all options that cannot be shared across threads are reset thereby making it safe to use the duplicate in a new thread. */ Curl dup() { Curl copy; copy.handle = curl.easy_duphandle(handle); copy.stopped = false; with (CurlOption) { auto tt = AliasSeq!(file, writefunction, writeheader, headerfunction, infile, readfunction, ioctldata, ioctlfunction, seekdata, seekfunction, sockoptdata, sockoptfunction, opensocketdata, opensocketfunction, progressdata, progressfunction, debugdata, debugfunction, interleavedata, interleavefunction, chunk_data, chunk_bgn_function, chunk_end_function, fnmatch_data, fnmatch_function, cookiejar, postfields); foreach(option; tt) copy.clear(option); } // The options are only supported by libcurl when it has been built // against certain versions of OpenSSL - if your libcurl uses an old // OpenSSL, or uses an entirely different SSL engine, attempting to // clear these normally will raise an exception copy.clearIfSupported(CurlOption.ssl_ctx_function); copy.clearIfSupported(CurlOption.ssh_keydata); // Enable for curl version > 7.21.7 static if (LIBCURL_VERSION_MAJOR >= 7 && LIBCURL_VERSION_MINOR >= 21 && LIBCURL_VERSION_PATCH >= 7) { copy.clear(CurlOption.closesocketdata); copy.clear(CurlOption.closesocketfunction); } copy.set(CurlOption.nosignal, 1); // copy.clear(CurlOption.ssl_ctx_data); Let ssl function be shared // copy.clear(CurlOption.ssh_keyfunction); Let key function be shared /* Allow sharing of conv functions copy.clear(CurlOption.conv_to_network_function); copy.clear(CurlOption.conv_from_network_function); copy.clear(CurlOption.conv_from_utf8_function); */ return copy; } private void _check(CurlCode code) { enforce!CurlTimeoutException(code != CurlError.operation_timedout, errorString(code)); enforce!CurlException(code == CurlError.ok, errorString(code)); } private string errorString(CurlCode code) { import core.stdc.string : strlen; auto msgZ = curl.easy_strerror(code); // doing the following (instead of just using std.conv.to!string) avoids 1 allocation return format("%s on handle %s", msgZ[0 .. strlen(msgZ)], handle); } private void throwOnStopped(string message = null) { auto def = "Curl instance called after being cleaned up"; enforce!CurlException(!stopped, message == null ? def : message); } /** Stop and invalidate this curl instance. Warning: Do not call this from inside a callback handler e.g. $(D onReceive). */ void shutdown() { throwOnStopped(); stopped = true; curl.easy_cleanup(this.handle); this.handle = null; } /** Pausing and continuing transfers. */ void pause(bool sendingPaused, bool receivingPaused) { throwOnStopped(); _check(curl.easy_pause(this.handle, (sendingPaused ? CurlPause.send_cont : CurlPause.send) | (receivingPaused ? CurlPause.recv_cont : CurlPause.recv))); } /** Set a string curl option. Params: option = A $(ECXREF curl, CurlOption) as found in the curl documentation value = The string */ void set(CurlOption option, const(char)[] value) { throwOnStopped(); _check(curl.easy_setopt(this.handle, option, value.tempCString().buffPtr)); } /** Set a long curl option. Params: option = A $(ECXREF curl, CurlOption) as found in the curl documentation value = The long */ void set(CurlOption option, long value) { throwOnStopped(); _check(curl.easy_setopt(this.handle, option, value)); } /** Set a void* curl option. Params: option = A $(ECXREF curl, CurlOption) as found in the curl documentation value = The pointer */ void set(CurlOption option, void* value) { throwOnStopped(); _check(curl.easy_setopt(this.handle, option, value)); } /** Clear a pointer option. Params: option = A $(ECXREF curl, CurlOption) as found in the curl documentation */ void clear(CurlOption option) { throwOnStopped(); _check(curl.easy_setopt(this.handle, option, null)); } /** Clear a pointer option. Does not raise an exception if the underlying libcurl does not support the option. Use sparingly. Params: option = A $(ECXREF curl, CurlOption) as found in the curl documentation */ void clearIfSupported(CurlOption option) { throwOnStopped(); auto rval = curl.easy_setopt(this.handle, option, null); if (rval != CurlError.unknown_option && rval != CurlError.not_built_in) _check(rval); } /** perform the curl request by doing the HTTP,FTP etc. as it has been setup beforehand. Params: throwOnError = whether to throw an exception or return a CurlCode on error */ CurlCode perform(ThrowOnError throwOnError = ThrowOnError.yes) { throwOnStopped(); CurlCode code = curl.easy_perform(this.handle); if (throwOnError) _check(code); return code; } /** * The event handler that receives incoming data. * * Params: * callback = the callback that receives the $(D ubyte[]) data. * Be sure to copy the incoming data and not store * a slice. * * Returns: * The callback returns the incoming bytes read. If not the entire array is * the request will abort. * The special value HTTP.pauseRequest can be returned in order to pause the * current request. * * Example: * ---- * import std.net.curl, std.stdio; * Curl curl; * curl.initialize(); * curl.set(CurlOption.url, "http://dlang.org"); * curl.onReceive = (ubyte[] data) { writeln("Got data", to!(const(char)[])(data)); return data.length;}; * curl.perform(); * ---- */ @property void onReceive(size_t delegate(InData) callback) { _onReceive = (InData id) { throwOnStopped("Receive callback called on cleaned up Curl instance"); return callback(id); }; set(CurlOption.file, cast(void*) &this); set(CurlOption.writefunction, cast(void*) &Curl._receiveCallback); } /** * The event handler that receives incoming headers for protocols * that uses headers. * * Params: * callback = the callback that receives the header string. * Make sure the callback copies the incoming params if * it needs to store it because they are references into * the backend and may very likely change. * * Example: * ---- * import std.net.curl, std.stdio; * Curl curl; * curl.initialize(); * curl.set(CurlOption.url, "http://dlang.org"); * curl.onReceiveHeader = (in char[] header) { writeln(header); }; * curl.perform(); * ---- */ @property void onReceiveHeader(void delegate(in char[]) callback) { _onReceiveHeader = (in char[] od) { throwOnStopped("Receive header callback called on "~ "cleaned up Curl instance"); callback(od); }; set(CurlOption.writeheader, cast(void*) &this); set(CurlOption.headerfunction, cast(void*) &Curl._receiveHeaderCallback); } /** * The event handler that gets called when data is needed for sending. * * Params: * callback = the callback that has a $(D void[]) buffer to be filled * * Returns: * The callback returns the number of elements in the buffer that have been * filled and are ready to send. * The special value $(D Curl.abortRequest) can be returned in * order to abort the current request. * The special value $(D Curl.pauseRequest) can be returned in order to * pause the current request. * * Example: * ---- * import std.net.curl; * Curl curl; * curl.initialize(); * curl.set(CurlOption.url, "http://dlang.org"); * * string msg = "Hello world"; * curl.onSend = (void[] data) * { * auto m = cast(void[])msg; * size_t length = m.length > data.length ? data.length : m.length; * if (length == 0) return 0; * data[0..length] = m[0..length]; * msg = msg[length..$]; * return length; * }; * curl.perform(); * ---- */ @property void onSend(size_t delegate(OutData) callback) { _onSend = (OutData od) { throwOnStopped("Send callback called on cleaned up Curl instance"); return callback(od); }; set(CurlOption.infile, cast(void*) &this); set(CurlOption.readfunction, cast(void*) &Curl._sendCallback); } /** * The event handler that gets called when the curl backend needs to seek * the data to be sent. * * Params: * callback = the callback that receives a seek offset and a seek position * $(ECXREF curl, CurlSeekPos) * * Returns: * The callback returns the success state of the seeking * $(ECXREF curl, CurlSeek) * * Example: * ---- * import std.net.curl; * Curl curl; * curl.initialize(); * curl.set(CurlOption.url, "http://dlang.org"); * curl.onSeek = (long p, CurlSeekPos sp) * { * return CurlSeek.cantseek; * }; * curl.perform(); * ---- */ @property void onSeek(CurlSeek delegate(long, CurlSeekPos) callback) { _onSeek = (long ofs, CurlSeekPos sp) { throwOnStopped("Seek callback called on cleaned up Curl instance"); return callback(ofs, sp); }; set(CurlOption.seekdata, cast(void*) &this); set(CurlOption.seekfunction, cast(void*) &Curl._seekCallback); } /** * The event handler that gets called when the net socket has been created * but a $(D connect()) call has not yet been done. This makes it possible to set * misc. socket options. * * Params: * callback = the callback that receives the socket and socket type * $(ECXREF curl, CurlSockType) * * Returns: * Return 0 from the callback to signal success, return 1 to signal error * and make curl close the socket * * Example: * ---- * import std.net.curl; * Curl curl; * curl.initialize(); * curl.set(CurlOption.url, "http://dlang.org"); * curl.onSocketOption = delegate int(curl_socket_t s, CurlSockType t) { /+ do stuff +/ }; * curl.perform(); * ---- */ @property void onSocketOption(int delegate(curl_socket_t, CurlSockType) callback) { _onSocketOption = (curl_socket_t sock, CurlSockType st) { throwOnStopped("Socket option callback called on "~ "cleaned up Curl instance"); return callback(sock, st); }; set(CurlOption.sockoptdata, cast(void*) &this); set(CurlOption.sockoptfunction, cast(void*) &Curl._socketOptionCallback); } /** * The event handler that gets called to inform of upload/download progress. * * Params: * callback = the callback that receives the (total bytes to download, * currently downloaded bytes, total bytes to upload, currently uploaded * bytes). * * Returns: * Return 0 from the callback to signal success, return non-zero to abort * transfer * * Example: * ---- * import std.net.curl; * Curl curl; * curl.initialize(); * curl.set(CurlOption.url, "http://dlang.org"); * curl.onProgress = delegate int(size_t dltotal, size_t dlnow, size_t ultotal, size_t uln) * { * writeln("Progress: downloaded bytes ", dlnow, " of ", dltotal); * writeln("Progress: uploaded bytes ", ulnow, " of ", ultotal); * curl.perform(); * }; * ---- */ @property void onProgress(int delegate(size_t dlTotal, size_t dlNow, size_t ulTotal, size_t ulNow) callback) { _onProgress = (size_t dlt, size_t dln, size_t ult, size_t uln) { throwOnStopped("Progress callback called on cleaned "~ "up Curl instance"); return callback(dlt, dln, ult, uln); }; set(CurlOption.noprogress, 0); set(CurlOption.progressdata, cast(void*) &this); set(CurlOption.progressfunction, cast(void*) &Curl._progressCallback); } // Internal C callbacks to register with libcurl extern (C) private static size_t _receiveCallback(const char* str, size_t size, size_t nmemb, void* ptr) { auto b = cast(Curl*) ptr; if (b._onReceive != null) return b._onReceive(cast(InData)(str[0..size*nmemb])); return size*nmemb; } extern (C) private static size_t _receiveHeaderCallback(const char* str, size_t size, size_t nmemb, void* ptr) { auto b = cast(Curl*) ptr; auto s = str[0..size*nmemb].chomp(); if (b._onReceiveHeader != null) b._onReceiveHeader(s); return size*nmemb; } extern (C) private static size_t _sendCallback(char *str, size_t size, size_t nmemb, void *ptr) { Curl* b = cast(Curl*) ptr; auto a = cast(void[]) str[0..size*nmemb]; if (b._onSend == null) return 0; return b._onSend(a); } extern (C) private static int _seekCallback(void *ptr, curl_off_t offset, int origin) { auto b = cast(Curl*) ptr; if (b._onSeek == null) return CurlSeek.cantseek; // origin: CurlSeekPos.set/current/end // return: CurlSeek.ok/fail/cantseek return b._onSeek(cast(long) offset, cast(CurlSeekPos) origin); } extern (C) private static int _socketOptionCallback(void *ptr, curl_socket_t curlfd, curlsocktype purpose) { auto b = cast(Curl*) ptr; if (b._onSocketOption == null) return 0; // return: 0 ok, 1 fail return b._onSocketOption(curlfd, cast(CurlSockType) purpose); } extern (C) private static int _progressCallback(void *ptr, double dltotal, double dlnow, double ultotal, double ulnow) { auto b = cast(Curl*) ptr; if (b._onProgress == null) return 0; // return: 0 ok, 1 fail return b._onProgress(cast(size_t)dltotal, cast(size_t)dlnow, cast(size_t)ultotal, cast(size_t)ulnow); } } // Internal messages send between threads. // The data is wrapped in this struct in order to ensure that // other std.concurrency.receive calls does not pick up our messages // by accident. private struct CurlMessage(T) { public T data; } private static CurlMessage!T curlMessage(T)(T data) { return CurlMessage!T(data); } // Pool of to be used for reusing buffers private struct Pool(Data) { private struct Entry { Data data; Entry* next; } private Entry* root; private Entry* freeList; @safe @property bool empty() { return root == null; } @safe nothrow void push(Data d) { if (freeList == null) { // Allocate new Entry since there is no one // available in the freeList freeList = new Entry; } freeList.data = d; Entry* oldroot = root; root = freeList; freeList = freeList.next; root.next = oldroot; } @safe Data pop() { enforce!Exception(root != null, "pop() called on empty pool"); auto d = root.data; auto n = root.next; root.next = freeList; freeList = root; root = n; return d; } } // Shared function for reading incoming chunks of data and // sending the to a parent thread private static size_t _receiveAsyncChunks(ubyte[] data, ref ubyte[] outdata, Pool!(ubyte[]) freeBuffers, ref ubyte[] buffer, Tid fromTid, ref bool aborted) { immutable datalen = data.length; // Copy data to fill active buffer while (!data.empty) { // Make sure a buffer is present while ( outdata.empty && freeBuffers.empty) { // Active buffer is invalid and there are no // available buffers in the pool. Wait for buffers // to return from main thread in order to reuse // them. receive((immutable(ubyte)[] buf) { buffer = cast(ubyte[])buf; outdata = buffer[]; }, (bool flag) { aborted = true; } ); if (aborted) return cast(size_t)0; } if (outdata.empty) { buffer = freeBuffers.pop(); outdata = buffer[]; } // Copy data auto copyBytes = outdata.length < data.length ? outdata.length : data.length; outdata[0..copyBytes] = data[0..copyBytes]; outdata = outdata[copyBytes..$]; data = data[copyBytes..$]; if (outdata.empty) fromTid.send(thisTid, curlMessage(cast(immutable(ubyte)[])buffer)); } return datalen; } // ditto private static void _finalizeAsyncChunks(ubyte[] outdata, ref ubyte[] buffer, Tid fromTid) { if (!outdata.empty) { // Resize the last buffer buffer.length = buffer.length - outdata.length; fromTid.send(thisTid, curlMessage(cast(immutable(ubyte)[])buffer)); } } // Shared function for reading incoming lines of data and sending the to a // parent thread private static size_t _receiveAsyncLines(Terminator, Unit) (const(ubyte)[] data, ref EncodingScheme encodingScheme, bool keepTerminator, Terminator terminator, ref const(ubyte)[] leftOverBytes, ref bool bufferValid, ref Pool!(Unit[]) freeBuffers, ref Unit[] buffer, Tid fromTid, ref bool aborted) { immutable datalen = data.length; // Terminator is specified and buffers should be resized as determined by // the terminator // Copy data to active buffer until terminator is found. // Decode as many lines as possible while (true) { // Make sure a buffer is present while (!bufferValid && freeBuffers.empty) { // Active buffer is invalid and there are no available buffers in // the pool. Wait for buffers to return from main thread in order to // reuse them. receive((immutable(Unit)[] buf) { buffer = cast(Unit[])buf; buffer.length = 0; buffer.assumeSafeAppend(); bufferValid = true; }, (bool flag) { aborted = true; } ); if (aborted) return cast(size_t)0; } if (!bufferValid) { buffer = freeBuffers.pop(); bufferValid = true; } // Try to read a line from left over bytes from last onReceive plus the // newly received bytes. try { if (decodeLineInto(leftOverBytes, data, buffer, encodingScheme, terminator)) { if (keepTerminator) { fromTid.send(thisTid, curlMessage(cast(immutable(Unit)[])buffer)); } else { static if (isArray!Terminator) fromTid.send(thisTid, curlMessage(cast(immutable(Unit)[]) buffer[0..$-terminator.length])); else fromTid.send(thisTid, curlMessage(cast(immutable(Unit)[]) buffer[0..$-1])); } bufferValid = false; } else { // Could not decode an entire line. Save // bytes left in data for next call to // onReceive. Can be up to a max of 4 bytes. enforce!CurlException(data.length <= 4, format( "Too many bytes left not decoded %s"~ " > 4. Maybe the charset specified in"~ " headers does not match "~ "the actual content downloaded?", data.length)); leftOverBytes ~= data; break; } } catch (CurlException ex) { prioritySend(fromTid, cast(immutable(CurlException))ex); return cast(size_t)0; } } return datalen; } // ditto private static void _finalizeAsyncLines(Unit)(bool bufferValid, Unit[] buffer, Tid fromTid) { if (bufferValid && buffer.length != 0) fromTid.send(thisTid, curlMessage(cast(immutable(Unit)[])buffer[0..$])); } // Spawn a thread for handling the reading of incoming data in the // background while the delegate is executing. This will optimize // throughput by allowing simultaneous input (this struct) and // output (e.g. AsyncHTTPLineOutputRange). private static void _spawnAsync(Conn, Unit, Terminator = void)() { Tid fromTid = receiveOnly!Tid(); // Get buffer to read into Pool!(Unit[]) freeBuffers; // Free list of buffer objects // Number of bytes filled into active buffer Unit[] buffer; bool aborted = false; EncodingScheme encodingScheme; static if ( !is(Terminator == void)) { // Only lines reading will receive a terminator auto terminator = receiveOnly!Terminator(); auto keepTerminator = receiveOnly!bool(); // max number of bytes to carry over from an onReceive // callback. This is 4 because it is the max code units to // decode a code point in the supported encodings. auto leftOverBytes = new const(ubyte)[4]; leftOverBytes.length = 0; auto bufferValid = false; } else { Unit[] outdata; } // no move semantic available in std.concurrency ie. must use casting. auto connDup = cast(CURL*)receiveOnly!ulong(); auto client = Conn(); client.p.curl.handle = connDup; // receive a method for both ftp and http but just use it for http auto method = receiveOnly!(HTTP.Method)(); client.onReceive = (ubyte[] data) { // If no terminator is specified the chunk size is fixed. static if ( is(Terminator == void) ) return _receiveAsyncChunks(data, outdata, freeBuffers, buffer, fromTid, aborted); else return _receiveAsyncLines(data, encodingScheme, keepTerminator, terminator, leftOverBytes, bufferValid, freeBuffers, buffer, fromTid, aborted); }; static if ( is(Conn == HTTP) ) { client.method = method; // register dummy header handler client.onReceiveHeader = (in char[] key, in char[] value) { if (key == "content-type") encodingScheme = EncodingScheme.create(client.p.charset); }; } else { encodingScheme = EncodingScheme.create(client.encoding); } // Start the request CurlCode code; try { code = client.perform(ThrowOnError.no); } catch (Exception ex) { prioritySend(fromTid, cast(immutable(Exception)) ex); fromTid.send(thisTid, curlMessage(true)); // signal done return; } if (code != CurlError.ok) { if (aborted && (code == CurlError.aborted_by_callback || code == CurlError.write_error)) { fromTid.send(thisTid, curlMessage(true)); // signal done return; } prioritySend(fromTid, cast(immutable(CurlException)) new CurlException(client.p.curl.errorString(code))); fromTid.send(thisTid, curlMessage(true)); // signal done return; } // Send remaining data that is not a full chunk size static if ( is(Terminator == void) ) _finalizeAsyncChunks(outdata, buffer, fromTid); else _finalizeAsyncLines(bufferValid, buffer, fromTid); fromTid.send(thisTid, curlMessage(true)); // signal done } ldc-1.1.0-beta3-src/runtime/phobos/std/net/isemail.d0000664000175000017500000024306612776215007020277 0ustar kaikai/** * Validates an email address according to RFCs 5321, 5322 and others. * * Authors: Dominic Sayers $(LT)dominic@sayers.cc$(GT), Jacob Carlborg * Copyright: Dominic Sayers, Jacob Carlborg 2008-. * Test schema documentation: Copyright © 2011, Daniel Marschall * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) * Version: 3.0.13 - Version 3.0 of the original PHP implementation: $(LINK http://www.dominicsayers.com/isemail) * * Standards: * $(UL * $(LI RFC 5321) * $(LI RFC 5322) * ) * * References: * $(UL * $(LI $(LINK http://www.dominicsayers.com/isemail)) * $(LI $(LINK http://tools.ietf.org/html/rfc5321)) * $(LI $(LINK http://tools.ietf.org/html/rfc5322)) * ) * * Source: $(PHOBOSSRC std/net/_isemail.d) */ module std.net.isemail; // FIXME import std.range.primitives; // : ElementType; import std.traits; /** * Check that an email address conforms to RFCs 5321, 5322 and others. * * As of Version 3.0, we are now distinguishing clearly between a Mailbox as defined * by RFC 5321 and an addr-spec as defined by RFC 5322. Depending on the context, * either can be regarded as a valid email address. The RFC 5321 Mailbox specification * is more restrictive (comments, white space and obsolete forms are not allowed). * * Note: The DNS check is currently not implemented. * * Params: * email = The email address to check * checkDNS = If CheckDns.yes then a DNS check for MX records will be made * errorLevel = Determines the boundary between valid and invalid addresses. * Status codes above this number will be returned as-is, * status codes below will be returned as EmailStatusCode.valid. * Thus the calling program can simply look for EmailStatusCode.valid * if it is only interested in whether an address is valid or not. The * $(D_PARAM errorLevel) will determine how "picky" isEmail() is about * the address. * * If omitted or passed as EmailStatusCode.none then isEmail() will * not perform any finer grained error checking and an address is * either considered valid or not. Email status code will either be * EmailStatusCode.valid or EmailStatusCode.error. * * Returns: an EmailStatus, indicating the status of the email address. */ EmailStatus isEmail (Char) (const(Char)[] email, CheckDns checkDNS = CheckDns.no, EmailStatusCode errorLevel = EmailStatusCode.none) if (isSomeChar!(Char)) { import std.algorithm : uniq, canFind; import std.exception : enforce; import std.array : array, split; import std.conv : to; import std.regex : match, regex; import std.string : indexOf, lastIndexOf; import std.uni : isNumber; alias tstring = const(Char)[]; enum defaultThreshold = 16; int threshold; bool diagnose; if (errorLevel == EmailStatusCode.any || errorLevel == EmailStatusCode.none) { threshold = EmailStatusCode.valid; diagnose = errorLevel == EmailStatusCode.any; } else { diagnose = true; switch (errorLevel) { case EmailStatusCode.warning: threshold = defaultThreshold; break; case EmailStatusCode.error: threshold = EmailStatusCode.valid; break; default: threshold = errorLevel; } } auto returnStatus = [EmailStatusCode.valid]; auto context = EmailPart.componentLocalPart; auto contextStack = [context]; auto contextPrior = context; tstring token = ""; tstring tokenPrior = ""; tstring[EmailPart] parseData = [EmailPart.componentLocalPart : "", EmailPart.componentDomain : ""]; tstring[][EmailPart] atomList = [EmailPart.componentLocalPart : [""], EmailPart.componentDomain : [""]]; auto elementCount = 0; auto elementLength = 0; auto hyphenFlag = false; auto endOrDie = false; auto crlfCount = int.min; // int.min == not defined foreach (ref i, e ; email) { token = email.get(i, e); switch (context) { case EmailPart.componentLocalPart: switch (token) { case Token.openParenthesis: if (elementLength == 0) returnStatus ~= elementCount == 0 ? EmailStatusCode.comment : EmailStatusCode.deprecatedComment; else { returnStatus ~= EmailStatusCode.comment; endOrDie = true; } contextStack ~= context; context = EmailPart.contextComment; break; case Token.dot: if (elementLength == 0) returnStatus ~= elementCount == 0 ? EmailStatusCode.errorDotStart : EmailStatusCode.errorConsecutiveDots; else { if (endOrDie) returnStatus ~= EmailStatusCode.deprecatedLocalPart; } endOrDie = false; elementLength = 0; elementCount++; parseData[EmailPart.componentLocalPart] ~= token; if (elementCount >= atomList[EmailPart.componentLocalPart].length) atomList[EmailPart.componentLocalPart] ~= ""; else atomList[EmailPart.componentLocalPart][elementCount] = ""; break; case Token.doubleQuote: if (elementLength == 0) { returnStatus ~= elementCount == 0 ? EmailStatusCode.rfc5321QuotedString : EmailStatusCode.deprecatedLocalPart; parseData[EmailPart.componentLocalPart] ~= token; atomList[EmailPart.componentLocalPart][elementCount] ~= token; elementLength++; endOrDie = true; contextStack ~= context; context = EmailPart.contextQuotedString; } else returnStatus ~= EmailStatusCode.errorExpectingText; break; case Token.cr: case Token.space: case Token.tab: if ((token == Token.cr) && ((++i == email.length) || (email.get(i, e) != Token.lf))) { returnStatus ~= EmailStatusCode.errorCrNoLf; break; } if (elementLength == 0) returnStatus ~= elementCount == 0 ? EmailStatusCode.foldingWhitespace : EmailStatusCode.deprecatedFoldingWhitespace; else endOrDie = true; contextStack ~= context; context = EmailPart.contextFoldingWhitespace; tokenPrior = token; break; case Token.at: enforce(contextStack.length == 1, "Unexpected item on context stack"); if (parseData[EmailPart.componentLocalPart] == "") returnStatus ~= EmailStatusCode.errorNoLocalPart; else if (elementLength == 0) returnStatus ~= EmailStatusCode.errorDotEnd; else if (parseData[EmailPart.componentLocalPart].length > 64) returnStatus ~= EmailStatusCode.rfc5322LocalTooLong; else if (contextPrior == EmailPart.contextComment || contextPrior == EmailPart.contextFoldingWhitespace) returnStatus ~= EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt; context = EmailPart.componentDomain; contextStack = [context]; elementCount = 0; elementLength = 0; endOrDie = false; break; default: if (endOrDie) { switch (contextPrior) { case EmailPart.contextComment: case EmailPart.contextFoldingWhitespace: returnStatus ~= EmailStatusCode.errorTextAfterCommentFoldingWhitespace; break; case EmailPart.contextQuotedString: returnStatus ~= EmailStatusCode.errorTextAfterQuotedString; break; default: throw new Exception("More text found where none is allowed, but unrecognised prior " ~ "context: " ~ to!(string)(contextPrior)); } } else { contextPrior = context; auto c = token.front; if (c < '!' || c > '~' || c == '\n' || Token.specials.canFind(token)) returnStatus ~= EmailStatusCode.errorExpectingText; parseData[EmailPart.componentLocalPart] ~= token; atomList[EmailPart.componentLocalPart][elementCount] ~= token; elementLength++; } } break; case EmailPart.componentDomain: switch (token) { case Token.openParenthesis: if (elementLength == 0) returnStatus ~= elementCount == 0 ? EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt : EmailStatusCode.deprecatedComment; else { returnStatus ~= EmailStatusCode.comment; endOrDie = true; } contextStack ~= context; context = EmailPart.contextComment; break; case Token.dot: if (elementLength == 0) returnStatus ~= elementCount == 0 ? EmailStatusCode.errorDotStart : EmailStatusCode.errorConsecutiveDots; else if (hyphenFlag) returnStatus ~= EmailStatusCode.errorDomainHyphenEnd; else { if (elementLength > 63) returnStatus ~= EmailStatusCode.rfc5322LabelTooLong; } endOrDie = false; elementLength = 0; elementCount++; //atomList[EmailPart.componentDomain][elementCount] = ""; atomList[EmailPart.componentDomain] ~= ""; parseData[EmailPart.componentDomain] ~= token; break; case Token.openBracket: if (parseData[EmailPart.componentDomain] == "") { endOrDie = true; elementLength++; contextStack ~= context; context = EmailPart.componentLiteral; parseData[EmailPart.componentDomain] ~= token; atomList[EmailPart.componentDomain][elementCount] ~= token; parseData[EmailPart.componentLiteral] = ""; } else returnStatus ~= EmailStatusCode.errorExpectingText; break; case Token.cr: case Token.space: case Token.tab: if (token == Token.cr && (++i == email.length || email.get(i, e) != Token.lf)) { returnStatus ~= EmailStatusCode.errorCrNoLf; break; } if (elementLength == 0) returnStatus ~= elementCount == 0 ? EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt : EmailStatusCode.deprecatedFoldingWhitespace; else { returnStatus ~= EmailStatusCode.foldingWhitespace; endOrDie = true; } contextStack ~= context; context = EmailPart.contextFoldingWhitespace; tokenPrior = token; break; default: if (endOrDie) { switch (contextPrior) { case EmailPart.contextComment: case EmailPart.contextFoldingWhitespace: returnStatus ~= EmailStatusCode.errorTextAfterCommentFoldingWhitespace; break; case EmailPart.componentLiteral: returnStatus ~= EmailStatusCode.errorTextAfterDomainLiteral; break; default: throw new Exception("More text found where none is allowed, but unrecognised prior " ~ "context: " ~ to!(string)(contextPrior)); } } auto c = token.front; hyphenFlag = false; if (c < '!' || c > '~' || Token.specials.canFind(token)) returnStatus ~= EmailStatusCode.errorExpectingText; else if (token == Token.hyphen) { if (elementLength == 0) returnStatus ~= EmailStatusCode.errorDomainHyphenStart; hyphenFlag = true; } else if (!((c > '/' && c < ':') || (c > '@' && c < '[') || (c > '`' && c < '{'))) returnStatus ~= EmailStatusCode.rfc5322Domain; parseData[EmailPart.componentDomain] ~= token; atomList[EmailPart.componentDomain][elementCount] ~= token; elementLength++; } break; case EmailPart.componentLiteral: switch (token) { case Token.closeBracket: if (returnStatus.max() < EmailStatusCode.deprecated_) { auto maxGroups = 8; size_t index = -1; auto addressLiteral = parseData[EmailPart.componentLiteral]; enum regexStr = `\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}`~ `(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`; auto matchesIp = array(addressLiteral.match(regex!tstring(regexStr)).captures); if (!matchesIp.empty) { index = addressLiteral.lastIndexOf(matchesIp.front); if (index != 0) addressLiteral = addressLiteral.substr(0, index) ~ "0:0"; } if (index == 0) returnStatus ~= EmailStatusCode.rfc5321AddressLiteral; else if (addressLiteral.compareFirstN(Token.ipV6Tag, 5, true)) returnStatus ~= EmailStatusCode.rfc5322DomainLiteral; else { auto ipV6 = addressLiteral.substr(5); matchesIp = ipV6.split(Token.colon); auto groupCount = matchesIp.length; index = ipV6.indexOf(Token.doubleColon); if (index == -1) { if (groupCount != maxGroups) returnStatus ~= EmailStatusCode.rfc5322IpV6GroupCount; } else { if (index != ipV6.lastIndexOf(Token.doubleColon)) returnStatus ~= EmailStatusCode.rfc5322IpV6TooManyDoubleColons; else { if (index == 0 || index == (ipV6.length - 2)) maxGroups++; if (groupCount > maxGroups) returnStatus ~= EmailStatusCode.rfc5322IpV6MaxGroups; else if (groupCount == maxGroups) returnStatus ~= EmailStatusCode.rfc5321IpV6Deprecated; } } if (ipV6.substr(0, 1) == Token.colon && ipV6.substr(1, 1) != Token.colon) returnStatus ~= EmailStatusCode.rfc5322IpV6ColonStart; else if (ipV6.substr(-1) == Token.colon && ipV6.substr(-2, -1) != Token.colon) returnStatus ~= EmailStatusCode.rfc5322IpV6ColonEnd; else if (!matchesIp.grep(regex!(tstring)(`^[0-9A-Fa-f]{0,4}$`), true).empty) returnStatus ~= EmailStatusCode.rfc5322IpV6BadChar; else returnStatus ~= EmailStatusCode.rfc5321AddressLiteral; } } else returnStatus ~= EmailStatusCode.rfc5322DomainLiteral; parseData[EmailPart.componentDomain] ~= token; atomList[EmailPart.componentDomain][elementCount] ~= token; elementLength++; contextPrior = context; context = contextStack.pop(); break; case Token.backslash: returnStatus ~= EmailStatusCode.rfc5322DomainLiteralObsoleteText; contextStack ~= context; context = EmailPart.contextQuotedPair; break; case Token.cr: case Token.space: case Token.tab: if (token == Token.cr && (++i == email.length || email.get(i, e) != Token.lf)) { returnStatus ~= EmailStatusCode.errorCrNoLf; break; } returnStatus ~= EmailStatusCode.foldingWhitespace; contextStack ~= context; context = EmailPart.contextFoldingWhitespace; tokenPrior = token; break; default: auto c = token.front; if (c > AsciiToken.delete_ || c == '\0' || token == Token.openBracket) { returnStatus ~= EmailStatusCode.errorExpectingDomainText; break; } else if (c < '!' || c == AsciiToken.delete_ ) returnStatus ~= EmailStatusCode.rfc5322DomainLiteralObsoleteText; parseData[EmailPart.componentLiteral] ~= token; parseData[EmailPart.componentDomain] ~= token; atomList[EmailPart.componentDomain][elementCount] ~= token; elementLength++; } break; case EmailPart.contextQuotedString: switch (token) { case Token.backslash: contextStack ~= context; context = EmailPart.contextQuotedPair; break; case Token.cr: case Token.tab: if (token == Token.cr && (++i == email.length || email.get(i, e) != Token.lf)) { returnStatus ~= EmailStatusCode.errorCrNoLf; break; } parseData[EmailPart.componentLocalPart] ~= Token.space; atomList[EmailPart.componentLocalPart][elementCount] ~= Token.space; elementLength++; returnStatus ~= EmailStatusCode.foldingWhitespace; contextStack ~= context; context = EmailPart.contextFoldingWhitespace; tokenPrior = token; break; case Token.doubleQuote: parseData[EmailPart.componentLocalPart] ~= token; atomList[EmailPart.componentLocalPart][elementCount] ~= token; elementLength++; contextPrior = context; context = contextStack.pop(); break; default: auto c = token.front; if (c > AsciiToken.delete_ || c == '\0' || c == '\n') returnStatus ~= EmailStatusCode.errorExpectingQuotedText; else if (c < ' ' || c == AsciiToken.delete_) returnStatus ~= EmailStatusCode.deprecatedQuotedText; parseData[EmailPart.componentLocalPart] ~= token; atomList[EmailPart.componentLocalPart][elementCount] ~= token; elementLength++; } break; case EmailPart.contextQuotedPair: auto c = token.front; if (c > AsciiToken.delete_) returnStatus ~= EmailStatusCode.errorExpectingQuotedPair; else if (c < AsciiToken.unitSeparator && c != AsciiToken.horizontalTab || c == AsciiToken.delete_) returnStatus ~= EmailStatusCode.deprecatedQuotedPair; contextPrior = context; context = contextStack.pop(); token = Token.backslash ~ token; switch (context) { case EmailPart.contextComment: break; case EmailPart.contextQuotedString: parseData[EmailPart.componentLocalPart] ~= token; atomList[EmailPart.componentLocalPart][elementCount] ~= token; elementLength += 2; break; case EmailPart.componentLiteral: parseData[EmailPart.componentDomain] ~= token; atomList[EmailPart.componentDomain][elementCount] ~= token; elementLength += 2; break; default: throw new Exception("Quoted pair logic invoked in an invalid context: " ~ to!(string)(context)); } break; case EmailPart.contextComment: switch (token) { case Token.openParenthesis: contextStack ~= context; context = EmailPart.contextComment; break; case Token.closeParenthesis: contextPrior = context; context = contextStack.pop(); break; case Token.backslash: contextStack ~= context; context = EmailPart.contextQuotedPair; break; case Token.cr: case Token.space: case Token.tab: if (token == Token.cr && (++i == email.length || email.get(i, e) != Token.lf)) { returnStatus ~= EmailStatusCode.errorCrNoLf; break; } returnStatus ~= EmailStatusCode.foldingWhitespace; contextStack ~= context; context = EmailPart.contextFoldingWhitespace; tokenPrior = token; break; default: auto c = token.front; if (c > AsciiToken.delete_ || c == '\0' || c == '\n') { returnStatus ~= EmailStatusCode.errorExpectingCommentText; break; } else if (c < ' ' || c == AsciiToken.delete_) returnStatus ~= EmailStatusCode.deprecatedCommentText; } break; case EmailPart.contextFoldingWhitespace: if (tokenPrior == Token.cr) { if (token == Token.cr) { returnStatus ~= EmailStatusCode.errorFoldingWhitespaceCrflX2; break; } if (crlfCount != int.min) // int.min == not defined { if (++crlfCount > 1) returnStatus ~= EmailStatusCode.deprecatedFoldingWhitespace; } else crlfCount = 1; } switch (token) { case Token.cr: if (++i == email.length || email.get(i, e) != Token.lf) returnStatus ~= EmailStatusCode.errorCrNoLf; break; case Token.space: case Token.tab: break; default: if (tokenPrior == Token.cr) { returnStatus ~= EmailStatusCode.errorFoldingWhitespaceCrLfEnd; break; } crlfCount = int.min; // int.min == not defined contextPrior = context; context = contextStack.pop(); i--; break; } tokenPrior = token; break; default: throw new Exception("Unkown context: " ~ to!(string)(context)); } if (returnStatus.max() > EmailStatusCode.rfc5322) break; } if (returnStatus.max() < EmailStatusCode.rfc5322) { if (context == EmailPart.contextQuotedString) returnStatus ~= EmailStatusCode.errorUnclosedQuotedString; else if (context == EmailPart.contextQuotedPair) returnStatus ~= EmailStatusCode.errorBackslashEnd; else if (context == EmailPart.contextComment) returnStatus ~= EmailStatusCode.errorUnclosedComment; else if (context == EmailPart.componentLiteral) returnStatus ~= EmailStatusCode.errorUnclosedDomainLiteral; else if (token == Token.cr) returnStatus ~= EmailStatusCode.errorFoldingWhitespaceCrLfEnd; else if (parseData[EmailPart.componentDomain] == "") returnStatus ~= EmailStatusCode.errorNoDomain; else if (elementLength == 0) returnStatus ~= EmailStatusCode.errorDotEnd; else if (hyphenFlag) returnStatus ~= EmailStatusCode.errorDomainHyphenEnd; else if (parseData[EmailPart.componentDomain].length > 255) returnStatus ~= EmailStatusCode.rfc5322DomainTooLong; else if ((parseData[EmailPart.componentLocalPart] ~ Token.at ~ parseData[EmailPart.componentDomain]).length > 254) returnStatus ~= EmailStatusCode.rfc5322TooLong; else if (elementLength > 63) returnStatus ~= EmailStatusCode.rfc5322LabelTooLong; } auto dnsChecked = false; if (checkDNS == CheckDns.yes && returnStatus.max() < EmailStatusCode.dnsWarning) { assert(false, "DNS check is currently not implemented"); } if (!dnsChecked && returnStatus.max() < EmailStatusCode.dnsWarning) { if (elementCount == 0) returnStatus ~= EmailStatusCode.rfc5321TopLevelDomain; if (isNumber(atomList[EmailPart.componentDomain][elementCount].front)) returnStatus ~= EmailStatusCode.rfc5321TopLevelDomainNumeric; } returnStatus = array(uniq(returnStatus)); auto finalStatus = returnStatus.max(); if (returnStatus.length != 1) returnStatus.popFront(); parseData[EmailPart.status] = to!(tstring)(returnStatus); if (finalStatus < threshold) finalStatus = EmailStatusCode.valid; if (!diagnose) finalStatus = finalStatus < threshold ? EmailStatusCode.valid : EmailStatusCode.error; auto valid = finalStatus == EmailStatusCode.valid; tstring localPart = ""; tstring domainPart = ""; if (auto value = EmailPart.componentLocalPart in parseData) localPart = *value; if (auto value = EmailPart.componentDomain in parseData) domainPart = *value; return EmailStatus(valid, to!(string)(localPart), to!(string)(domainPart), finalStatus); } unittest { assert(``.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoDomain); assert(`test`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoDomain); assert(`@`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoLocalPart); assert(`test@`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoDomain); // assert(`test@io`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid, // `io. currently has an MX-record (Feb 2011). Some DNS setups seem to find it, some don't.` // ` If you don't see the MX for io. then try setting your DNS server to 8.8.8.8 (the Google DNS server)`); assert(`@io`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoLocalPart, `io. currently has an MX-record (Feb 2011)`); assert(`@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoLocalPart); assert(`test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); assert(`test@nominet.org.uk`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); assert(`test@about.museum`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); assert(`a@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); //assert(`test@e.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.dnsWarningNoRecord); // DNS check is currently not implemented //assert(`test@iana.a`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.dnsWarningNoRecord); // DNS check is currently not implemented assert(`test.test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); assert(`.test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDotStart); assert(`test.@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDotEnd); assert(`test..iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorConsecutiveDots); assert(`test_exa-mple.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoDomain); assert("!#$%&`*+/=?^`{|}~@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); assert(`test\@test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert(`123@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); assert(`test@123.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); assert(`test@iana.123`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321TopLevelDomainNumeric); assert(`test@255.255.255.255`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321TopLevelDomainNumeric); assert(`abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); assert(`abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklmn@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322LocalTooLong); // assert(`test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.com`.isEmail(CheckDns.no, // EmailStatusCode.any).statusCode == EmailStatusCode.dnsWarningNoRecord); // DNS check is currently not implemented assert(`test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322LabelTooLong); assert(`test@mason-dixon.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); assert(`test@-iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDomainHyphenStart); assert(`test@iana-.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDomainHyphenEnd); assert(`test@g--a.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid); //assert(`test@iana.co-uk`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == //EmailStatusCode.dnsWarningNoRecord); // DNS check is currently not implemented assert(`test@.iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDotStart); assert(`test@iana.org.`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDotEnd); assert(`test@iana..com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorConsecutiveDots); //assert(`a@a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z` // `.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z` // `.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == // EmailStatusCode.dnsWarningNoRecord); // DNS check is currently not implemented // assert(`abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyz` // `abcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.` // `abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi`.isEmail(CheckDns.no, // EmailStatusCode.any).statusCode == EmailStatusCode.dnsWarningNoRecord); // DNS check is currently not implemented assert((`abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyz`~ `abcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.`~ `abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij`).isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322TooLong); assert((`a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyz`~ `abcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.`~ `abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hij`).isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322TooLong); assert((`a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyz`~ `abcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.`~ `abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hijk`).isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainTooLong); assert(`"test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString); assert(`""@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString); assert(`"""@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert(`"\a"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString); assert(`"\""@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString); assert(`"\"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedQuotedString); assert(`"\\"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString); assert(`test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert(`"test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedQuotedString); assert(`"test"test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorTextAfterQuotedString); assert(`test"text"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert(`"test""test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert(`"test"."test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedLocalPart); assert(`"test\ test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString); assert(`"test".test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedLocalPart); assert("\"test\u0000\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingQuotedText); assert("\"test\\\u0000\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedQuotedPair); assert(`"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghj"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322LocalTooLong, `Quotes are still part of the length restriction`); assert(`"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefg\h"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322LocalTooLong, `Quoted pair is still part of the length restriction`); assert(`test@[255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321AddressLiteral); assert(`test@a[255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert(`test@[255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteral); assert(`test@[255.255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteral); assert(`test@[255.255.255.256]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteral); assert(`test@[1111:2222:3333:4444:5555:6666:7777:8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteral); assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6GroupCount); assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321AddressLiteral); assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6GroupCount); assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777:888G]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6BadChar); assert(`test@[IPv6:1111:2222:3333:4444:5555:6666::8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321IpV6Deprecated); assert(`test@[IPv6:1111:2222:3333:4444:5555::8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321AddressLiteral); assert(`test@[IPv6:1111:2222:3333:4444:5555:6666::7777:8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6MaxGroups); assert(`test@[IPv6::3333:4444:5555:6666:7777:8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6ColonStart); assert(`test@[IPv6:::3333:4444:5555:6666:7777:8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321AddressLiteral); assert(`test@[IPv6:1111::4444:5555::8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6TooManyDoubleColons); assert(`test@[IPv6:::]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321AddressLiteral); assert(`test@[IPv6:1111:2222:3333:4444:5555:255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6GroupCount); assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321AddressLiteral); assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777:255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6GroupCount); assert(`test@[IPv6:1111:2222:3333:4444::255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321AddressLiteral); assert(`test@[IPv6:1111:2222:3333:4444:5555:6666::255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6MaxGroups); assert(`test@[IPv6:1111:2222:3333:4444:::255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6TooManyDoubleColons); assert(`test@[IPv6::255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6ColonStart); assert(` test @iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt); assert(`test@ iana .com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt); assert(`test . test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedFoldingWhitespace); assert("\u000D\u000A test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.foldingWhitespace, `Folding whitespace`); assert("\u000D\u000A \u000D\u000A test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedFoldingWhitespace, `FWS with one line composed entirely of WSP`~ ` -- only allowed as obsolete FWS (someone might allow only non-obsolete FWS)`); assert(`(comment)test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.comment); assert(`((comment)test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedComment); assert(`(comment(comment))test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.comment); assert(`test@(comment)iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt); assert(`test(comment)test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorTextAfterCommentFoldingWhitespace); assert(`test@(comment)[255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt); assert(`(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.comment); assert(`test@(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt); assert((`(comment)test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghik.abcdefghijklmnopqrstuvwxyz`~ `abcdefghijklmnopqrstuvwxyzabcdefghik.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.`~ `abcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstu`).isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.comment); assert("test@iana.org\u000A".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert(`test@xn--hxajbheg2az3al.xn--jxalpdlp`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid, `A valid IDN from ICANN's `~ `IDN TLD evaluation gateway`); assert(`xn--test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid, `RFC 3490: "unless the email standards are revised to invite the use of IDNA for local parts, a domain label`~ ` that holds the local part of an email address SHOULD NOT begin with the ACE prefix, and even if it does,`~ ` it is to be interpreted literally as a local part that happens to begin with the ACE prefix"`); assert(`test@iana.org-`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDomainHyphenEnd); assert(`"test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedQuotedString); assert(`(test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedComment); assert(`test@(iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedComment); assert(`test@[1.2.3.4`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedDomainLiteral); assert(`"test\"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedQuotedString); assert(`(comment\)test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedComment); assert(`test@iana.org(comment\)`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedComment); assert(`test@iana.org(comment\`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorBackslashEnd); assert(`test@[RFC-5322-domain-literal]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteral); assert(`test@[RFC-5322]-domain-literal]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorTextAfterDomainLiteral); assert(`test@[RFC-5322-[domain-literal]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingDomainText); assert("test@[RFC-5322-\\\u0007-domain-literal]".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteralObsoleteText, `obs-dtext and obs-qp`); assert("test@[RFC-5322-\\\u0009-domain-literal]".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteralObsoleteText); assert(`test@[RFC-5322-\]-domain-literal]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteralObsoleteText); assert(`test@[RFC-5322-domain-literal\]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorUnclosedDomainLiteral); assert(`test@[RFC-5322-domain-literal\`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorBackslashEnd); assert(`test@[RFC 5322 domain literal]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteral, `Spaces are FWS in a domain literal`); assert(`test@[RFC-5322-domain-literal] (comment)`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainLiteral); assert("\u007F@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert("test@\u007F.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert("\"\u007F\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedQuotedText); assert("\"\\\u007F\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedQuotedPair); assert("(\u007F)test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedCommentText); assert("test@iana.org\u000D".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorCrNoLf, `No LF after the CR`); assert("\u000Dtest@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorCrNoLf, `No LF after the CR`); assert("\"\u000Dtest\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorCrNoLf ,`No LF after the CR`); assert("(\u000D)test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorCrNoLf, `No LF after the CR`); assert("(\u000D".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorCrNoLf, `No LF after the CR`); assert("test@iana.org(\u000D)".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorCrNoLf, `No LF after the CR`); assert("\u000Atest@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert("\"\u000A\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingQuotedText); assert("\"\\\u000A\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedQuotedPair); assert("(\u000A)test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingCommentText); assert("\u0007@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert("test@\u0007.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText); assert("\"\u0007\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedQuotedText); assert("\"\\\u0007\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedQuotedPair); assert("(\u0007)test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedCommentText); assert("\u000D\u000Atest@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrLfEnd, `Not FWS because no actual white space`); assert("\u000D\u000A \u000D\u000Atest@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrLfEnd, `Not obs-FWS because there must be white space on each "fold"`); assert(" \u000D\u000Atest@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrLfEnd, `Not FWS because no white space after the fold`); assert(" \u000D\u000A test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.foldingWhitespace, `FWS`); assert(" \u000D\u000A \u000D\u000Atest@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrLfEnd, `Not FWS because no white space after the second fold`); assert(" \u000D\u000A\u000D\u000Atest@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrflX2, `Not FWS because no white space after either fold`); assert(" \u000D\u000A\u000D\u000A test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrflX2, `Not FWS because no white space after the first fold`); assert("test@iana.org\u000D\u000A ".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.foldingWhitespace, `FWS`); assert("test@iana.org\u000D\u000A \u000D\u000A ".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedFoldingWhitespace, `FWS with one line composed entirely of WSP -- `~ `only allowed as obsolete FWS (someone might allow only non-obsolete FWS)`); assert("test@iana.org\u000D\u000A".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrLfEnd, `Not FWS because no actual white space`); assert("test@iana.org\u000D\u000A \u000D\u000A".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrLfEnd, `Not obs-FWS because there must be white space on each "fold"`); assert("test@iana.org \u000D\u000A".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrLfEnd, `Not FWS because no white space after the fold`); assert("test@iana.org \u000D\u000A ".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.foldingWhitespace, `FWS`); assert("test@iana.org \u000D\u000A \u000D\u000A".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrLfEnd, `Not FWS because no white space after the second fold`); assert("test@iana.org \u000D\u000A\u000D\u000A".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrflX2, `Not FWS because no white space after either fold`); assert("test@iana.org \u000D\u000A\u000D\u000A ".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorFoldingWhitespaceCrflX2, `Not FWS because no white space after the first fold`); assert(" test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.foldingWhitespace); assert(`test@iana.org `.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.foldingWhitespace); assert(`test@[IPv6:1::2:]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6ColonEnd); assert("\"test\\\u00A9\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingQuotedPair); assert(`test@iana/icann.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322Domain); assert(`test.(comment)test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedComment); assert(`test@org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321TopLevelDomain); // assert(`test@test.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == //EmailStatusCode.dnsWarningNoMXRecord, `test.com has an A-record but not an MX-record`); // DNS check is currently not implemented // // assert(`test@nic.no`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.dnsWarningNoRecord, // `nic.no currently has no MX-records or A-records (Feb 2011). If you are seeing an A-record for nic.io then` // ` try setting your DNS server to 8.8.8.8 (the Google DNS server) - your DNS server may be faking an A-record` // ` (OpenDNS does this, for instance).`); // DNS check is currently not implemented } /// Enum for indicating if the isEmail function should perform a DNS check or not. enum CheckDns { /// Does not perform DNS checking no, /// Performs DNS checking yes } /// This struct represents the status of an email address struct EmailStatus { private { bool valid_; string localPart_; string domainPart_; EmailStatusCode statusCode_; } /// alias valid this; /* * Params: * valid = indicates if the email address is valid or not * localPart = the local part of the email address * domainPart = the domain part of the email address * statusCode = the status code */ private this (bool valid, string localPart, string domainPart, EmailStatusCode statusCode) { this.valid_ = valid; this.localPart_ = localPart; this.domainPart_ = domainPart; this.statusCode_ = statusCode; } /// Indicates if the email address is valid or not. @property bool valid () const { return valid_; } /// The local part of the email address, that is, the part before the @ sign. @property string localPart () const { return localPart_; } /// The domain part of the email address, that is, the part after the @ sign. @property string domainPart () const { return domainPart_; } /// The email status code @property EmailStatusCode statusCode () const { return statusCode_; } /// Returns a describing string of the status code @property string status () const { return statusCodeDescription(statusCode_); } /// Returns a textual representation of the email status string toString () const { import std.format : format; return format("EmailStatus\n{\n\tvalid: %s\n\tlocalPart: %s\n\tdomainPart: %s\n\tstatusCode: %s\n}", valid, localPart, domainPart, statusCode); } } /// Returns a describing string of the given status code string statusCodeDescription (EmailStatusCode statusCode) { final switch (statusCode) { // Categories case EmailStatusCode.validCategory: return "Address is valid"; case EmailStatusCode.dnsWarning: return "Address is valid but a DNS check was not successful"; case EmailStatusCode.rfc5321: return "Address is valid for SMTP but has unusual elements"; case EmailStatusCode.cFoldingWhitespace: return "Address is valid within the message but cannot be used"~ " unmodified for the envelope"; case EmailStatusCode.deprecated_: return "Address contains deprecated elements but may still be valid in"~ " restricted contexts"; case EmailStatusCode.rfc5322: return "The address is only valid according to the broad definition of RFC 5322."~ " It is otherwise invalid"; case EmailStatusCode.any: return ""; case EmailStatusCode.none: return ""; case EmailStatusCode.warning: return ""; case EmailStatusCode.error: return "Address is invalid for any purpose"; // Diagnoses case EmailStatusCode.valid: return "Address is valid"; // Address is valid but a DNS check was not successful case EmailStatusCode.dnsWarningNoMXRecord: return "Could not find an MX record for this domain but an A-record"~ " does exist"; case EmailStatusCode.dnsWarningNoRecord: return "Could not find an MX record or an A-record for this domain"; // Address is valid for SMTP but has unusual elements case EmailStatusCode.rfc5321TopLevelDomain: return "Address is valid but at a Top Level Domain"; case EmailStatusCode.rfc5321TopLevelDomainNumeric: return "Address is valid but the Top Level Domain begins"~ " with a number"; case EmailStatusCode.rfc5321QuotedString: return "Address is valid but contains a quoted string"; case EmailStatusCode.rfc5321AddressLiteral: return "Address is valid but at a literal address not a domain"; case EmailStatusCode.rfc5321IpV6Deprecated: return "Address is valid but contains a :: that only elides one"~ " zero group"; // Address is valid within the message but cannot be used unmodified for the envelope case EmailStatusCode.comment: return "Address contains comments"; case EmailStatusCode.foldingWhitespace: return "Address contains Folding White Space"; // Address contains deprecated elements but may still be valid in restricted contexts case EmailStatusCode.deprecatedLocalPart: return "The local part is in a deprecated form"; case EmailStatusCode.deprecatedFoldingWhitespace: return "Address contains an obsolete form of"~ " Folding White Space"; case EmailStatusCode.deprecatedQuotedText: return "A quoted string contains a deprecated character"; case EmailStatusCode.deprecatedQuotedPair: return "A quoted pair contains a deprecated character"; case EmailStatusCode.deprecatedComment: return "Address contains a comment in a position that is deprecated"; case EmailStatusCode.deprecatedCommentText: return "A comment contains a deprecated character"; case EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt: return "Address contains a comment or"~ " Folding White Space around the @ sign"; // The address is only valid according to the broad definition of RFC 5322 case EmailStatusCode.rfc5322Domain: return "Address is RFC 5322 compliant but contains domain characters that"~ " are not allowed by DNS"; case EmailStatusCode.rfc5322TooLong: return "Address is too long"; case EmailStatusCode.rfc5322LocalTooLong: return "The local part of the address is too long"; case EmailStatusCode.rfc5322DomainTooLong: return "The domain part is too long"; case EmailStatusCode.rfc5322LabelTooLong: return "The domain part contains an element that is too long"; case EmailStatusCode.rfc5322DomainLiteral: return "The domain literal is not a valid RFC 5321 address literal"; case EmailStatusCode.rfc5322DomainLiteralObsoleteText: return "The domain literal is not a valid RFC 5321"~ " address literal and it contains obsolete characters"; case EmailStatusCode.rfc5322IpV6GroupCount: return "The IPv6 literal address contains the wrong number of groups"; case EmailStatusCode.rfc5322IpV6TooManyDoubleColons: return "The IPv6 literal address contains too many :: sequences"; case EmailStatusCode.rfc5322IpV6BadChar: return "The IPv6 address contains an illegal group of characters"; case EmailStatusCode.rfc5322IpV6MaxGroups: return "The IPv6 address has too many groups"; case EmailStatusCode.rfc5322IpV6ColonStart: return "IPv6 address starts with a single colon"; case EmailStatusCode.rfc5322IpV6ColonEnd: return "IPv6 address ends with a single colon"; // Address is invalid for any purpose case EmailStatusCode.errorExpectingDomainText: return "A domain literal contains a character that is not allowed"; case EmailStatusCode.errorNoLocalPart: return "Address has no local part"; case EmailStatusCode.errorNoDomain: return "Address has no domain part"; case EmailStatusCode.errorConsecutiveDots: return "The address may not contain consecutive dots"; case EmailStatusCode.errorTextAfterCommentFoldingWhitespace: return "Address contains text after a comment or Folding White Space"; case EmailStatusCode.errorTextAfterQuotedString: return "Address contains text after a quoted string"; case EmailStatusCode.errorTextAfterDomainLiteral: return "Extra characters were found after the end of"~ " the domain literal"; case EmailStatusCode.errorExpectingQuotedPair: return "The address contains a character that is not allowed in a quoted pair"; case EmailStatusCode.errorExpectingText: return "Address contains a character that is not allowed"; case EmailStatusCode.errorExpectingQuotedText: return "A quoted string contains a character that is not allowed"; case EmailStatusCode.errorExpectingCommentText: return "A comment contains a character that is not allowed"; case EmailStatusCode.errorBackslashEnd: return "The address cannot end with a backslash"; case EmailStatusCode.errorDotStart: return "Neither part of the address may begin with a dot"; case EmailStatusCode.errorDotEnd: return "Neither part of the address may end with a dot"; case EmailStatusCode.errorDomainHyphenStart: return "A domain or subdomain cannot begin with a hyphen"; case EmailStatusCode.errorDomainHyphenEnd: return "A domain or subdomain cannot end with a hyphen"; case EmailStatusCode.errorUnclosedQuotedString: return "Unclosed quoted string"; case EmailStatusCode.errorUnclosedComment: return "Unclosed comment"; case EmailStatusCode.errorUnclosedDomainLiteral: return "Domain literal is missing its closing bracket"; case EmailStatusCode.errorFoldingWhitespaceCrflX2: return "Folding White Space contains consecutive CRLF sequences"; case EmailStatusCode.errorFoldingWhitespaceCrLfEnd: return "Folding White Space ends with a CRLF sequence"; case EmailStatusCode.errorCrNoLf: return "Address contains a carriage return that is not followed by a line feed"; } } /** * An email status code, indicating if an email address is valid or not. * If it is invalid it also indicates why. */ enum EmailStatusCode { // Categories /// Address is valid validCategory = 1, /// Address is valid but a DNS check was not successful dnsWarning = 7, /// Address is valid for SMTP but has unusual elements rfc5321 = 15, /// Address is valid within the message but cannot be used unmodified for the envelope cFoldingWhitespace = 31, /// Address contains deprecated elements but may still be valid in restricted contexts deprecated_ = 63, /// The address is only valid according to the broad definition of RFC 5322. It is otherwise invalid rfc5322 = 127, /** * All finer grained error checking is turned on. Address containing errors or * warnings is considered invalid. A specific email status code will be * returned indicating the error/warning of the address. */ any = 252, /** * Address is either considered valid or not, no finer grained error checking * is performed. Returned email status code will be either Error or Valid. */ none = 253, /** * Address containing warnings is considered valid, that is, * any status code below 16 is considered valid. */ warning = 254, /// Address is invalid for any purpose error = 255, // Diagnoses /// Address is valid valid = 0, // Address is valid but a DNS check was not successful /// Could not find an MX record for this domain but an A-record does exist dnsWarningNoMXRecord = 5, /// Could not find an MX record or an A-record for this domain dnsWarningNoRecord = 6, // Address is valid for SMTP but has unusual elements /// Address is valid but at a Top Level Domain rfc5321TopLevelDomain = 9, /// Address is valid but the Top Level Domain begins with a number rfc5321TopLevelDomainNumeric = 10, /// Address is valid but contains a quoted string rfc5321QuotedString = 11, /// Address is valid but at a literal address not a domain rfc5321AddressLiteral = 12, /// Address is valid but contains a :: that only elides one zero group rfc5321IpV6Deprecated = 13, // Address is valid within the message but cannot be used unmodified for the envelope /// Address contains comments comment = 17, /// Address contains Folding White Space foldingWhitespace = 18, // Address contains deprecated elements but may still be valid in restricted contexts /// The local part is in a deprecated form deprecatedLocalPart = 33, /// Address contains an obsolete form of Folding White Space deprecatedFoldingWhitespace = 34, /// A quoted string contains a deprecated character deprecatedQuotedText = 35, /// A quoted pair contains a deprecated character deprecatedQuotedPair = 36, /// Address contains a comment in a position that is deprecated deprecatedComment = 37, /// A comment contains a deprecated character deprecatedCommentText = 38, /// Address contains a comment or Folding White Space around the @ sign deprecatedCommentFoldingWhitespaceNearAt = 49, // The address is only valid according to the broad definition of RFC 5322 /// Address is RFC 5322 compliant but contains domain characters that are not allowed by DNS rfc5322Domain = 65, /// Address is too long rfc5322TooLong = 66, /// The local part of the address is too long rfc5322LocalTooLong = 67, /// The domain part is too long rfc5322DomainTooLong = 68, /// The domain part contains an element that is too long rfc5322LabelTooLong = 69, /// The domain literal is not a valid RFC 5321 address literal rfc5322DomainLiteral = 70, /// The domain literal is not a valid RFC 5321 address literal and it contains obsolete characters rfc5322DomainLiteralObsoleteText = 71, /// The IPv6 literal address contains the wrong number of groups rfc5322IpV6GroupCount = 72, /// The IPv6 literal address contains too many :: sequences rfc5322IpV6TooManyDoubleColons = 73, /// The IPv6 address contains an illegal group of characters rfc5322IpV6BadChar = 74, /// The IPv6 address has too many groups rfc5322IpV6MaxGroups = 75, /// IPv6 address starts with a single colon rfc5322IpV6ColonStart = 76, /// IPv6 address ends with a single colon rfc5322IpV6ColonEnd = 77, // Address is invalid for any purpose /// A domain literal contains a character that is not allowed errorExpectingDomainText = 129, /// Address has no local part errorNoLocalPart = 130, /// Address has no domain part errorNoDomain = 131, /// The address may not contain consecutive dots errorConsecutiveDots = 132, /// Address contains text after a comment or Folding White Space errorTextAfterCommentFoldingWhitespace = 133, /// Address contains text after a quoted string errorTextAfterQuotedString = 134, /// Extra characters were found after the end of the domain literal errorTextAfterDomainLiteral = 135, /// The address contains a character that is not allowed in a quoted pair errorExpectingQuotedPair = 136, /// Address contains a character that is not allowed errorExpectingText = 137, /// A quoted string contains a character that is not allowed errorExpectingQuotedText = 138, /// A comment contains a character that is not allowed errorExpectingCommentText = 139, /// The address cannot end with a backslash errorBackslashEnd = 140, /// Neither part of the address may begin with a dot errorDotStart = 141, /// Neither part of the address may end with a dot errorDotEnd = 142, /// A domain or subdomain cannot begin with a hyphen errorDomainHyphenStart = 143, /// A domain or subdomain cannot end with a hyphen errorDomainHyphenEnd = 144, /// Unclosed quoted string errorUnclosedQuotedString = 145, /// Unclosed comment errorUnclosedComment = 146, /// Domain literal is missing its closing bracket errorUnclosedDomainLiteral = 147, /// Folding White Space contains consecutive CRLF sequences errorFoldingWhitespaceCrflX2 = 148, /// Folding White Space ends with a CRLF sequence errorFoldingWhitespaceCrLfEnd = 149, /// Address contains a carriage return that is not followed by a line feed errorCrNoLf = 150, } private: // Email parts for the isEmail function enum EmailPart { // The local part of the email address, that is, the part before the @ sign componentLocalPart, // The domain part of the email address, that is, the part after the @ sign. componentDomain, componentLiteral, contextComment, contextFoldingWhitespace, contextQuotedString, contextQuotedPair, status } // Miscellaneous string constants struct Token { enum { at = "@", backslash = `\`, dot = ".", doubleQuote = `"`, openParenthesis = "(", closeParenthesis = ")", openBracket = "[", closeBracket = "]", hyphen = "-", colon = ":", doubleColon = "::", space = " ", tab = "\t", cr = "\r", lf = "\n", ipV6Tag = "IPV6:", // US-ASCII visible characters not valid for atext (http://tools.ietf.org/html/rfc5322#section-3.2.3) specials = `()<>[]:;@\\,."` } } enum AsciiToken { horizontalTab = 9, unitSeparator = 31, delete_ = 127 } /* * Returns the maximum of the values in the given array. * * Params: * arr = the array containing the values to return the maximum of * * Returns: the maximum value */ T max (T) (T[] arr) { import std.algorithm/* : max*/; auto max = arr.front; foreach (i ; 0 .. arr.length - 1) max = std.algorithm.max(max, arr[i + 1]); return max; } /// unittest { assert([1, 2, 3, 4].max() == 4); assert([3, 5, 9, 2, 5].max() == 9); assert([7, 13, 9, 12, 0].max() == 13); } /* * Returns the portion of string specified by the $(D_PARAM start) and * $(D_PARAM length) parameters. * * Params: * str = the input string. Must be one character or longer. * start = if $(D_PARAM start) is non-negative, the returned string will start at the * $(D_PARAM start)'th position in $(D_PARAM str), counting from zero. * For instance, in the string "abcdef", the character at position 0 is 'a', * the character at position 2 is 'c', and so forth. * * If $(D_PARAM start) is negative, the returned string will start at the * $(D_PARAM start)'th character from the end of $(D_PARAM str). * * If $(D_PARAM str) is less than or equal to $(D_PARAM start) characters long, * $(D_KEYWORD true) will be returned. * * length = if $(D_PARAM length) is given and is positive, the string returned will * contain at most $(D_PARAM length) characters beginning from $(D_PARAM start) * (depending on the length of string). * * If $(D_PARAM length) is given and is negative, then that many characters * will be omitted from the end of string (after the start position has been * calculated when a $(D_PARAM start) is negative). If $(D_PARAM start) * denotes the position of this truncation or beyond, $(D_KEYWORD false) * will be returned. * * If $(D_PARAM length) is given and is 0, an empty string will be returned. * * If $(D_PARAM length) is omitted, the substring starting from $(D_PARAM start) * until the end of the string will be returned. * * Returns: the extracted part of string, or an empty string. */ T[] substr (T) (T[] str, ptrdiff_t start = 0, ptrdiff_t length = ptrdiff_t.min) { ptrdiff_t end = length; if (start < 0) { start = str.length + start; if (end < 0) { if (end == ptrdiff_t.min) end = 0; end = str.length + end; } else end = start + end; } else { if (end == ptrdiff_t.min) end = str.length; if (end < 0) end = str.length + end; else end = start + end; } if (start > end) end = start; if (end > str.length) end = str.length; return str[start .. end]; } /// unittest { assert("abcdef".substr(-1) == "f"); assert("abcdef".substr(-2) == "ef"); assert("abcdef".substr(-3, 1) == "d"); } unittest { assert("abcdef".substr(0, -1) == "abcde"); assert("abcdef".substr(2, -1) == "cde"); assert("abcdef".substr(4, -4) == []); assert("abcdef".substr(-3, -1) == "de"); assert("abcdef".substr(1, 1) == "b"); assert("abcdef".substr(-1, -1) == []); } /* * Compare the two given strings lexicographically. An upper limit of the number of * characters, that will be used in the comparison, can be specified. Supports both * case-sensitive and case-insensitive comparison. * * Params: * s1 = the first string to be compared * s2 = the second string to be compared * length = the length of strings to be used in the comparison. * caseInsensitive = if true, a case-insensitive comparison will be made, * otherwise a case-sensitive comparison will be made * * Returns: (for $(D pred = "a < b")): * * $(BOOKTABLE, * $(TR $(TD $(D < 0)) $(TD $(D s1 < s2) )) * $(TR $(TD $(D = 0)) $(TD $(D s1 == s2))) * $(TR $(TD $(D > 0)) $(TD $(D s1 > s2))) * ) */ int compareFirstN (alias pred = "a < b", S1, S2) (S1 s1, S2 s2, size_t length, bool caseInsensitive = false) if (is(Unqual!(ElementType!(S1)) == dchar) && is(Unqual!(ElementType!(S2)) == dchar)) { import std.uni : icmp; import std.algorithm : cmp; auto s1End = length <= s1.length ? length : s1.length; auto s2End = length <= s2.length ? length : s2.length; auto slice1 = s1[0 .. s1End]; auto slice2 = s2[0 .. s2End]; return caseInsensitive ? slice1.icmp(slice2) : slice1.cmp(slice2); } /// unittest { assert("abc".compareFirstN("abcdef", 3) == 0); assert("abc".compareFirstN("Abc", 3, true) == 0); assert("abc".compareFirstN("abcdef", 6) < 0); assert("abcdef".compareFirstN("abc", 6) > 0); } /* * Returns a range consisting of the elements of the $(D_PARAM input) range that * matches the given $(D_PARAM pattern). * * Params: * input = the input range * pattern = the regular expression pattern to search for * invert = if $(D_KEYWORD true), this function returns the elements of the * input range that do $(B not) match the given $(D_PARAM pattern). * * Returns: a range containing the matched elements */ auto grep (Range, Regex) (Range input, Regex pattern, bool invert = false) { import std.regex : match; import std.algorithm : filter; auto dg = invert ? (ElementType!(Range) e) { return e.match(pattern).empty; } : (ElementType!(Range) e) { return !e.match(pattern).empty; }; return filter!(dg)(input); } /// unittest { import std.algorithm : equal; import std.regex; assert(equal(["ab", "0a", "cd", "1b"].grep(regex(`\d\w`)), ["0a", "1b"])); assert(equal(["abc", "0123", "defg", "4567"].grep(regex(`4567`), true), ["abc", "0123", "defg"])); } /* * Pops the last element of the given range and returns the element. * * Params: * range = the range to pop the element from * * Returns: the popped element */ ElementType!(A) pop (A) (ref A a) if (isDynamicArray!(A) && !isNarrowString!(A) && isMutable!(A) && !is(A == void[])) { auto e = a.back; a.popBack(); return e; } /// unittest { auto array = [0, 1, 2, 3]; auto result = array.pop(); assert(array == [0, 1, 2]); assert(result == 3); } /* * Returns the character at the given index as a string. The returned string will be a * slice of the original string. * * Params: * str = the string to get the character from * index = the index of the character to get * c = the character to return, or any other of the same length * * Returns: the character at the given index as a string */ const(T)[] get (T) (const(T)[] str, size_t index, dchar c) { import std.utf : codeLength; return str[index .. index + codeLength!(T)(c)]; } unittest { assert("abc".get(1, 'b') == "b"); assert("löv".get(1, 'ö') == "ö"); } unittest { assert("abc".get(1, 'b') == "b"); assert("löv".get(1, 'ö') == "ö"); } ldc-1.1.0-beta3-src/runtime/phobos/std/exception.d0000664000175000017500000020243412776215007020056 0ustar kaikai// Written in the D programming language. /++ This module defines functions related to exceptions and general error handling. It also defines functions intended to aid in unit testing. Synopsis of some of std.exception's functions: -------------------- string synopsis() { FILE* f = enforce(fopen("some/file")); // f is not null from here on FILE* g = enforce!WriteException(fopen("some/other/file", "w")); // g is not null from here on Exception e = collectException(write(g, readln(f))); if (e) { ... an exception occurred... ... We have the exception to play around with... } string msg = collectExceptionMsg(write(g, readln(f))); if (msg) { ... an exception occurred... ... We have the message from the exception but not the exception... } char[] line; enforce(readln(f, line)); return assumeUnique(line); } -------------------- Macros: WIKI = Phobos/StdException Copyright: Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0) Authors: $(WEB erdani.org, Andrei Alexandrescu) and Jonathan M Davis Source: $(PHOBOSSRC std/_exception.d) +/ module std.exception; import std.range; import std.traits; import core.stdc.errno; import core.stdc.string; /++ Asserts that the given expression does $(I not) throw the given type of $(D Throwable). If a $(D Throwable) of the given type is thrown, it is caught and does not escape assertNotThrown. Rather, an $(D AssertError) is thrown. However, any other $(D Throwable)s will escape. Params: T = The $(D Throwable) to test for. expression = The expression to test. msg = Optional message to output on test failure. If msg is empty, and the thrown exception has a non-empty msg field, the exception's msg field will be output on test failure. file = The file where the error occurred. Defaults to $(D __FILE__). line = The line where the error occurred. Defaults to $(D __LINE__). Throws: $(D AssertError) if the given $(D Throwable) is thrown. Returns: the result of `expression`. +/ auto assertNotThrown(T : Throwable = Exception, E) (lazy E expression, string msg = null, string file = __FILE__, size_t line = __LINE__) { import core.exception : AssertError; try { return expression(); } catch (T t) { immutable message = msg.length == 0 ? t.msg : msg; immutable tail = message.length == 0 ? "." : ": " ~ message; throw new AssertError("assertNotThrown failed: " ~ T.stringof ~ " was thrown" ~ tail, file, line, t); } } /// unittest { import core.exception : AssertError; import std.string; assertNotThrown!StringException(enforce!StringException(true, "Error!")); //Exception is the default. assertNotThrown(enforce!StringException(true, "Error!")); assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( enforce!StringException(false, "Error!"))) == `assertNotThrown failed: StringException was thrown: Error!`); } unittest { import core.exception : AssertError; import std.string; assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( enforce!StringException(false, ""), "Error!")) == `assertNotThrown failed: StringException was thrown: Error!`); assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( enforce!StringException(false, ""))) == `assertNotThrown failed: StringException was thrown.`); assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( enforce!StringException(false, ""), "")) == `assertNotThrown failed: StringException was thrown.`); } unittest { import core.exception : AssertError; void throwEx(Throwable t) { throw t; } bool nothrowEx() { return true; } try { assert(assertNotThrown!Exception(nothrowEx())); } catch (AssertError) assert(0); try { assert(assertNotThrown!Exception(nothrowEx(), "It's a message")); } catch (AssertError) assert(0); try { assert(assertNotThrown!AssertError(nothrowEx())); } catch (AssertError) assert(0); try { assert(assertNotThrown!AssertError(nothrowEx(), "It's a message")); } catch (AssertError) assert(0); { bool thrown = false; try { assertNotThrown!Exception( throwEx(new Exception("It's an Exception"))); } catch (AssertError) thrown = true; assert(thrown); } { bool thrown = false; try { assertNotThrown!Exception( throwEx(new Exception("It's an Exception")), "It's a message"); } catch (AssertError) thrown = true; assert(thrown); } { bool thrown = false; try { assertNotThrown!AssertError( throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__))); } catch (AssertError) thrown = true; assert(thrown); } { bool thrown = false; try { assertNotThrown!AssertError( throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)), "It's a message"); } catch (AssertError) thrown = true; assert(thrown); } } /++ Asserts that the given expression throws the given type of $(D Throwable). The $(D Throwable) is caught and does not escape assertThrown. However, any other $(D Throwable)s $(I will) escape, and if no $(D Throwable) of the given type is thrown, then an $(D AssertError) is thrown. Params: T = The $(D Throwable) to test for. expression = The expression to test. msg = Optional message to output on test failure. file = The file where the error occurred. Defaults to $(D __FILE__). line = The line where the error occurred. Defaults to $(D __LINE__). Throws: $(D AssertError) if the given $(D Throwable) is not thrown. +/ void assertThrown(T : Throwable = Exception, E) (lazy E expression, string msg = null, string file = __FILE__, size_t line = __LINE__) { import core.exception : AssertError; try expression(); catch (T) return; throw new AssertError("assertThrown failed: No " ~ T.stringof ~ " was thrown" ~ (msg.length == 0 ? "." : ": ") ~ msg, file, line); } /// unittest { import core.exception : AssertError; import std.string; assertThrown!StringException(enforce!StringException(false, "Error!")); //Exception is the default. assertThrown(enforce!StringException(false, "Error!")); assert(collectExceptionMsg!AssertError(assertThrown!StringException( enforce!StringException(true, "Error!"))) == `assertThrown failed: No StringException was thrown.`); } unittest { import core.exception : AssertError; void throwEx(Throwable t) { throw t; } void nothrowEx() { } try { assertThrown!Exception(throwEx(new Exception("It's an Exception"))); } catch (AssertError) assert(0); try { assertThrown!Exception(throwEx(new Exception("It's an Exception")), "It's a message"); } catch(AssertError) assert(0); try { assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__))); } catch (AssertError) assert(0); try { assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)), "It's a message"); } catch (AssertError) assert(0); { bool thrown = false; try assertThrown!Exception(nothrowEx()); catch(AssertError) thrown = true; assert(thrown); } { bool thrown = false; try assertThrown!Exception(nothrowEx(), "It's a message"); catch(AssertError) thrown = true; assert(thrown); } { bool thrown = false; try assertThrown!AssertError(nothrowEx()); catch(AssertError) thrown = true; assert(thrown); } { bool thrown = false; try assertThrown!AssertError(nothrowEx(), "It's a message"); catch(AssertError) thrown = true; assert(thrown); } } /++ Enforces that the given value is true. Params: value = The value to test. E = Exception type to throw if the value evalues to false. msg = The error message to put in the exception if it is thrown. file = The source file of the caller. line = The line number of the caller. Returns: $(D value), if `cast(bool)value` is true. Otherwise, $(D new Exception(msg)) is thrown. Note: $(D enforce) is used to throw exceptions and is therefore intended to aid in error handling. It is $(I not) intended for verifying the logic of your program. That is what $(D assert) is for. Also, do not use $(D enforce) inside of contracts (i.e. inside of $(D in) and $(D out) blocks and $(D invariant)s), because they will be compiled out when compiling with $(I -release). Use $(D assert) in contracts. Example: -------------------- auto f = enforce(fopen("data.txt")); auto line = readln(f); enforce(line.length, "Expected a non-empty line."); -------------------- +/ T enforce(E : Throwable = Exception, T)(T value, lazy const(char)[] msg = null, string file = __FILE__, size_t line = __LINE__) if (is(typeof({ if (!value) {} }))) { if (!value) bailOut!E(file, line, msg); return value; } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Use the overload of enforce that takes file and line as function arguments.") T enforce(T, string file, size_t line = __LINE__) (T value, lazy const(char)[] msg = null) if (is(typeof({ if (!value) {} }))) { if (!value) bailOut(file, line, msg); return value; } /++ Enforces that the given value is true. Params: value = The value to test. dg = The delegate to be called if the value evaluates to false. file = The source file of the caller. line = The line number of the caller. Returns: $(D value), if `cast(bool)value` is true. Otherwise, the given delegate is called. The safety and purity of this function are inferred from $(D Dg)'s safety and purity. +/ T enforce(T, Dg, string file = __FILE__, size_t line = __LINE__) (T value, scope Dg dg) if (isSomeFunction!Dg && is(typeof( dg() )) && is(typeof({ if (!value) {} }))) { version(LDC) pragma(inline, true); // Must inline because of __FILE__ as template parameter if (!value) dg(); return value; } private void bailOut(E : Throwable = Exception)(string file, size_t line, in char[] msg) { static if (is(typeof(new E(string.init, string.init, size_t.init)))) { throw new E(msg.ptr ? msg.idup : "Enforcement failed", file, line); } else static if (is(typeof(new E(string.init, size_t.init)))) { throw new E(file, line); } else { static assert(0, "Expected this(string, string, size_t) or this(string, size_t)" ~ " constructor for " ~ __traits(identifier, E)); } } unittest { assert (enforce(123) == 123); try { enforce(false, "error"); assert (false); } catch (Exception e) { assert (e.msg == "error"); assert (e.file == __FILE__); assert (e.line == __LINE__-7); } } unittest { // Issue 10510 extern(C) void cFoo() { } enforce(false, &cFoo); } // purity and safety inference test unittest { import std.meta : AliasSeq; foreach (EncloseSafe; AliasSeq!(false, true)) foreach (EnclosePure; AliasSeq!(false, true)) { foreach (BodySafe; AliasSeq!(false, true)) foreach (BodyPure; AliasSeq!(false, true)) { enum code = "delegate void() " ~ (EncloseSafe ? "@safe " : "") ~ (EnclosePure ? "pure " : "") ~ "{ enforce(true, { " ~ "int n; " ~ (BodySafe ? "" : "auto p = &n + 10; " ) ~ // unsafe code (BodyPure ? "" : "static int g; g = 10; ") ~ // impure code "}); " ~ "}"; enum expect = (BodySafe || !EncloseSafe) && (!EnclosePure || BodyPure); version(none) pragma(msg, "safe = ", EncloseSafe?1:0, "/", BodySafe?1:0, ", ", "pure = ", EnclosePure?1:0, "/", BodyPure?1:0, ", ", "expect = ", expect?"OK":"NG", ", ", "code = ", code); static assert(__traits(compiles, mixin(code)()) == expect); } } } // Test for bugzilla 8637 unittest { struct S { static int g; ~this() {} // impure & unsafe destructor bool opCast(T:bool)() { int* p = cast(int*)0; // unsafe operation int n = g; // impure operation return true; } } S s; enforce(s); enforce(s, {}); enforce(s, new Exception("")); errnoEnforce(s); alias E1 = Exception; static class E2 : Exception { this(string fn, size_t ln) { super("", fn, ln); } } static class E3 : Exception { this(string msg) { super(msg, __FILE__, __LINE__); } } enforce!E1(s); enforce!E2(s); } deprecated unittest { struct S { static int g; ~this() {} // impure & unsafe destructor bool opCast(T:bool)() { int* p = cast(int*)0; // unsafe operation int n = g; // impure operation return true; } } S s; enforce!(S, __FILE__, __LINE__)(s, ""); } unittest { // Issue 14685 class E : Exception { this() { super("Not found"); } } static assert(!__traits(compiles, { enforce!E(false); })); } /++ Enforces that the given value is true. Params: value = The value to test. ex = The exception to throw if the value evaluates to false. Returns: $(D value), if `cast(bool)value` is true. Otherwise, $(D ex) is thrown. Example: -------------------- auto f = enforce(fopen("data.txt")); auto line = readln(f); enforce(line.length, new IOException); // expect a non-empty line -------------------- +/ T enforce(T)(T value, lazy Throwable ex) { if (!value) throw ex(); return value; } unittest { assertNotThrown(enforce(true, new Exception("this should not be thrown"))); assertThrown(enforce(false, new Exception("this should be thrown"))); } /++ Enforces that the given value is true, throwing an `ErrnoException` if it is not. Params: value = The value to test. msg = The message to include in the `ErrnoException` if it is thrown. Returns: $(D value), if `cast(bool)value` is true. Otherwise, $(D new ErrnoException(msg)) is thrown. It is assumed that the last operation set $(D errno) to an error code corresponding with the failed condition. Example: -------------------- auto f = errnoEnforce(fopen("data.txt")); auto line = readln(f); enforce(line.length); // expect a non-empty line -------------------- +/ T errnoEnforce(T, string file = __FILE__, size_t line = __LINE__) (T value, lazy string msg = null) { version(LDC) pragma(inline, true); // Must inline because of __FILE__ as template parameter if (!value) throw new ErrnoException(msg, file, line); return value; } /++ If $(D !value) is $(D false), $(D value) is returned. Otherwise, $(D new E(msg, file, line)) is thrown. Or if $(D E) doesn't take a message and can be constructed with $(D new E(file, line)), then $(D new E(file, line)) will be thrown. This is legacy name, it is recommended to use $(D enforce!E) instead. Example: -------------------- auto f = enforceEx!FileMissingException(fopen("data.txt")); auto line = readln(f); enforceEx!DataCorruptionException(line.length); -------------------- +/ template enforceEx(E : Throwable) if (is(typeof(new E("", __FILE__, __LINE__)))) { /++ Ditto +/ T enforceEx(T)(T value, lazy string msg = "", string file = __FILE__, size_t line = __LINE__) { if (!value) throw new E(msg, file, line); return value; } } /++ Ditto +/ template enforceEx(E : Throwable) if (is(typeof(new E(__FILE__, __LINE__))) && !is(typeof(new E("", __FILE__, __LINE__)))) { /++ Ditto +/ T enforceEx(T)(T value, string file = __FILE__, size_t line = __LINE__) { if (!value) throw new E(file, line); return value; } } unittest { import std.array : empty; import core.exception : OutOfMemoryError; assertNotThrown(enforceEx!Exception(true)); assertNotThrown(enforceEx!Exception(true, "blah")); assertNotThrown(enforceEx!OutOfMemoryError(true)); { auto e = collectException(enforceEx!Exception(false)); assert(e !is null); assert(e.msg.empty); assert(e.file == __FILE__); assert(e.line == __LINE__ - 4); } { auto e = collectException(enforceEx!Exception(false, "hello", "file", 42)); assert(e !is null); assert(e.msg == "hello"); assert(e.file == "file"); assert(e.line == 42); } { auto e = collectException!Error(enforceEx!OutOfMemoryError(false)); assert(e !is null); assert(e.msg == "Memory allocation failed"); assert(e.file == __FILE__); assert(e.line == __LINE__ - 4); } { auto e = collectException!Error(enforceEx!OutOfMemoryError(false, "file", 42)); assert(e !is null); assert(e.msg == "Memory allocation failed"); assert(e.file == "file"); assert(e.line == 42); } static assert(!is(typeof(enforceEx!int(true)))); } unittest { alias enf = enforceEx!Exception; assertNotThrown(enf(true)); assertThrown(enf(false, "blah")); } /++ Catches and returns the exception thrown from the given expression. If no exception is thrown, then null is returned and $(D result) is set to the result of the expression. Note that while $(D collectException) $(I can) be used to collect any $(D Throwable) and not just $(D Exception)s, it is generally ill-advised to catch anything that is neither an $(D Exception) nor a type derived from $(D Exception). So, do not use $(D collectException) to collect non-$(D Exception)s unless you're sure that that's what you really want to do. Params: T = The type of exception to catch. expression = The expression which may throw an exception. result = The result of the expression if no exception is thrown. +/ T collectException(T = Exception, E)(lazy E expression, ref E result) { try { result = expression(); } catch (T e) { return e; } return null; } /// unittest { int b; int foo() { throw new Exception("blah"); } assert(collectException(foo(), b)); int[] a = new int[3]; import core.exception : RangeError; assert(collectException!RangeError(a[4], b)); } /++ Catches and returns the exception thrown from the given expression. If no exception is thrown, then null is returned. $(D E) can be $(D void). Note that while $(D collectException) $(I can) be used to collect any $(D Throwable) and not just $(D Exception)s, it is generally ill-advised to catch anything that is neither an $(D Exception) nor a type derived from $(D Exception). So, do not use $(D collectException) to collect non-$(D Exception)s unless you're sure that that's what you really want to do. Params: T = The type of exception to catch. expression = The expression which may throw an exception. +/ T collectException(T : Throwable = Exception, E)(lazy E expression) { try { expression(); } catch (T t) { return t; } return null; } unittest { int foo() { throw new Exception("blah"); } assert(collectException(foo())); } /++ Catches the exception thrown from the given expression and returns the msg property of that exception. If no exception is thrown, then null is returned. $(D E) can be $(D void). If an exception is thrown but it has an empty message, then $(D emptyExceptionMsg) is returned. Note that while $(D collectExceptionMsg) $(I can) be used to collect any $(D Throwable) and not just $(D Exception)s, it is generally ill-advised to catch anything that is neither an $(D Exception) nor a type derived from $(D Exception). So, do not use $(D collectExceptionMsg) to collect non-$(D Exception)s unless you're sure that that's what you really want to do. Params: T = The type of exception to catch. expression = The expression which may throw an exception. +/ string collectExceptionMsg(T = Exception, E)(lazy E expression) { import std.array : empty; try { expression(); return cast(string)null; } catch(T e) return e.msg.empty ? emptyExceptionMsg : e.msg; } /// unittest { void throwFunc() { throw new Exception("My Message."); } assert(collectExceptionMsg(throwFunc()) == "My Message."); void nothrowFunc() {} assert(collectExceptionMsg(nothrowFunc()) is null); void throwEmptyFunc() { throw new Exception(""); } assert(collectExceptionMsg(throwEmptyFunc()) == emptyExceptionMsg); } /++ Value that collectExceptionMsg returns when it catches an exception with an empty exception message. +/ enum emptyExceptionMsg = ""; /** * Casts a mutable array to an immutable array in an idiomatic * manner. Technically, $(D assumeUnique) just inserts a cast, * but its name documents assumptions on the part of the * caller. $(D assumeUnique(arr)) should only be called when * there are no more active mutable aliases to elements of $(D * arr). To strengthen this assumption, $(D assumeUnique(arr)) * also clears $(D arr) before returning. Essentially $(D * assumeUnique(arr)) indicates commitment from the caller that there * is no more mutable access to any of $(D arr)'s elements * (transitively), and that all future accesses will be done through * the immutable array returned by $(D assumeUnique). * * Typically, $(D assumeUnique) is used to return arrays from * functions that have allocated and built them. * * Params: * array = The array to cast to immutable. * * Returns: The immutable array. * * Example: * * ---- * string letters() * { * char[] result = new char['z' - 'a' + 1]; * foreach (i, ref e; result) * { * e = cast(char)('a' + i); * } * return assumeUnique(result); * } * ---- * * The use in the example above is correct because $(D result) * was private to $(D letters) and is inaccessible in writing * after the function returns. The following example shows an * incorrect use of $(D assumeUnique). * * Bad: * * ---- * private char[] buffer; * string letters(char first, char last) * { * if (first >= last) return null; // fine * auto sneaky = buffer; * sneaky.length = last - first + 1; * foreach (i, ref e; sneaky) * { * e = cast(char)('a' + i); * } * return assumeUnique(sneaky); // BAD * } * ---- * * The example above wreaks havoc on client code because it is * modifying arrays that callers considered immutable. To obtain an * immutable array from the writable array $(D buffer), replace * the last line with: * ---- * return to!(string)(sneaky); // not that sneaky anymore * ---- * * The call will duplicate the array appropriately. * * Note that checking for uniqueness during compilation is * possible in certain cases, especially when a function is * marked as a pure function. The following example does not * need to call assumeUnique because the compiler can infer the * uniqueness of the array in the pure function: * ---- * string letters() pure * { * char[] result = new char['z' - 'a' + 1]; * foreach (i, ref e; result) * { * e = cast(char)('a' + i); * } * return result; * } * ---- * * For more on infering uniqueness see the $(B unique) and * $(B lent) keywords in the * $(WEB archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf, ArchJava) * language. * * The downside of using $(D assumeUnique)'s * convention-based usage is that at this time there is no * formal checking of the correctness of the assumption; * on the upside, the idiomatic use of $(D assumeUnique) is * simple and rare enough to be tolerable. * */ immutable(T)[] assumeUnique(T)(T[] array) pure nothrow { return .assumeUnique(array); // call ref version } /// ditto immutable(T)[] assumeUnique(T)(ref T[] array) pure nothrow { auto result = cast(immutable(T)[]) array; array = null; return result; } unittest { int[] arr = new int[1]; auto arr1 = assumeUnique(arr); assert(is(typeof(arr1) == immutable(int)[]) && arr == null); } immutable(T[U]) assumeUnique(T, U)(ref T[U] array) pure nothrow { auto result = cast(immutable(T[U])) array; array = null; return result; } // @@@BUG@@@ version(none) unittest { int[string] arr = ["a":1]; auto arr1 = assumeUnique(arr); assert(is(typeof(arr1) == immutable(int[string])) && arr == null); } /** * Wraps a possibly-throwing expression in a $(D nothrow) wrapper so that it * can be called by a $(D nothrow) function. * * This wrapper function documents commitment on the part of the caller that * the appropriate steps have been taken to avoid whatever conditions may * trigger an exception during the evaluation of $(D expr). If it turns out * that the expression $(I does) throw at runtime, the wrapper will throw an * $(D AssertError). * * (Note that $(D Throwable) objects such as $(D AssertError) that do not * subclass $(D Exception) may be thrown even from $(D nothrow) functions, * since they are considered to be serious runtime problems that cannot be * recovered from.) * * Params: * expr = The expression asserted not to throw. * msg = The message to include in the `AssertError` if the assumption turns * out to be false. * file = The source file name of the caller. * line = The line number of the caller. * * Returns: * The value of `expr`, if any. */ T assumeWontThrow(T)(lazy T expr, string msg = null, string file = __FILE__, size_t line = __LINE__) nothrow { import core.exception : AssertError; try { return expr; } catch(Exception e) { import std.range.primitives : empty; immutable tail = msg.empty ? "." : ": " ~ msg; throw new AssertError("assumeWontThrow failed: Expression did throw" ~ tail, file, line); } } /// unittest { import std.math : sqrt; // This function may throw. int squareRoot(int x) { if (x < 0) throw new Exception("Tried to take root of negative number"); return cast(int)sqrt(cast(double)x); } // This function never throws. int computeLength(int x, int y) nothrow { // Since x*x + y*y is always positive, we can safely assume squareRoot // won't throw, and use it to implement this nothrow function. If it // does throw (e.g., if x*x + y*y overflows a 32-bit value), then the // program will terminate. return assumeWontThrow(squareRoot(x*x + y*y)); } assert(computeLength(3, 4) == 5); } unittest { import core.exception : AssertError; void alwaysThrows() { throw new Exception("I threw up"); } void bad() nothrow { assumeWontThrow(alwaysThrows()); } assertThrown!AssertError(bad()); } /** Checks whether a given source object contains pointers or references to a given target object. Params: source = The source object target = The target object Returns: $(D true) if $(D source)'s representation embeds a pointer that points to $(D target)'s representation or somewhere inside it. If $(D source) is or contains a dynamic array, then, then these functions will check if there is overlap between the dynamic array and $(D target)'s representation. If $(D source) is a class, then it will be handled as a pointer. If $(D target) is a pointer, a dynamic array or a class, then these functions will only check if $(D source) points to $(D target), $(I not) what $(D target) references. If $(D source) is or contains a union, then there may be either false positives or false negatives: $(D doesPointTo) will return $(D true) if it is absolutely certain $(D source) points to $(D target). It may produce false negatives, but never false positives. This function should be prefered when trying to validate input data. $(D mayPointTo) will return $(D false) if it is absolutely certain $(D source) does not point to $(D target). It may produce false positives, but never false negatives. This function should be prefered for defensively choosing a code path. Note: Evaluating $(D doesPointTo(x, x)) checks whether $(D x) has internal pointers. This should only be done as an assertive test, as the language is free to assume objects don't have internal pointers (TDPL 7.1.3.5). */ bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow if (__traits(isRef, source) || isDynamicArray!S || isPointer!S || is(S == class)) { static if (isPointer!S || is(S == class) || is(S == interface)) { const m = *cast(void**) &source; const b = cast(void*) ⌖ const e = b + target.sizeof; return b <= m && m < e; } else static if (is(S == struct) || is(S == union)) { foreach (i, Subobj; typeof(source.tupleof)) static if (!isUnionAliased!(S, i)) if (doesPointTo(source.tupleof[i], target)) return true; return false; } else static if (isStaticArray!S) { foreach (size_t i; 0 .. S.length) if (doesPointTo(source[i], target)) return true; return false; } else static if (isDynamicArray!S) { import std.array : overlap; return overlap(cast(void[])source, cast(void[])(&target)[0 .. 1]).length != 0; } else { return false; } } // for shared objects /// ditto bool doesPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow { return doesPointTo!(shared S, shared T, void)(source, target); } /// ditto bool mayPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow if (__traits(isRef, source) || isDynamicArray!S || isPointer!S || is(S == class)) { static if (isPointer!S || is(S == class) || is(S == interface)) { const m = *cast(void**) &source; const b = cast(void*) ⌖ const e = b + target.sizeof; return b <= m && m < e; } else static if (is(S == struct) || is(S == union)) { foreach (i, Subobj; typeof(source.tupleof)) if (mayPointTo(source.tupleof[i], target)) return true; return false; } else static if (isStaticArray!S) { foreach (size_t i; 0 .. S.length) if (mayPointTo(source[i], target)) return true; return false; } else static if (isDynamicArray!S) { import std.array : overlap; return overlap(cast(void[])source, cast(void[])(&target)[0 .. 1]).length != 0; } else { return false; } } // for shared objects /// ditto bool mayPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow { return mayPointTo!(shared S, shared T, void)(source, target); } /// Pointers unittest { int i = 0; int* p = null; assert(!p.doesPointTo(i)); p = &i; assert( p.doesPointTo(i)); } /// Structs and Unions unittest { struct S { int v; int* p; } int i; auto s = S(0, &i); // structs and unions "own" their members // pointsTo will answer true if one of the members pointsTo. assert(!s.doesPointTo(s.v)); //s.v is just v member of s, so not pointed. assert( s.p.doesPointTo(i)); //i is pointed by s.p. assert( s .doesPointTo(i)); //which means i is pointed by s itself. // Unions will behave exactly the same. Points to will check each "member" // individually, even if they share the same memory } /// Arrays (dynamic and static) unittest { int i; int[] slice = [0, 1, 2, 3, 4]; int[5] arr = [0, 1, 2, 3, 4]; int*[] slicep = [&i]; int*[1] arrp = [&i]; // A slice points to all of its members: assert( slice.doesPointTo(slice[3])); assert(!slice[0 .. 2].doesPointTo(slice[3])); // Object 3 is outside of the // slice [0 .. 2] // Note that a slice will not take into account what its members point to. assert( slicep[0].doesPointTo(i)); assert(!slicep .doesPointTo(i)); // static arrays are objects that own their members, just like structs: assert(!arr.doesPointTo(arr[0])); // arr[0] is just a member of arr, so not // pointed. assert( arrp[0].doesPointTo(i)); // i is pointed by arrp[0]. assert( arrp .doesPointTo(i)); // which means i is pointed by arrp // itself. // Notice the difference between static and dynamic arrays: assert(!arr .doesPointTo(arr[0])); assert( arr[].doesPointTo(arr[0])); assert( arrp .doesPointTo(i)); assert(!arrp[].doesPointTo(i)); } /// Classes unittest { class C { this(int* p){this.p = p;} int* p; } int i; C a = new C(&i); C b = a; // Classes are a bit particular, as they are treated like simple pointers // to a class payload. assert( a.p.doesPointTo(i)); // a.p points to i. assert(!a .doesPointTo(i)); // Yet a itself does not point i. //To check the class payload itself, iterate on its members: () { foreach (index, _; Fields!C) if (doesPointTo(a.tupleof[index], i)) return; assert(0); }(); // To check if a class points a specific payload, a direct memmory check // can be done: auto aLoc = cast(ubyte[__traits(classInstanceSize, C)]*) a; assert(b.doesPointTo(*aLoc)); // b points to where a is pointing } unittest { struct S1 { int a; S1 * b; } S1 a1; S1 * p = &a1; assert(doesPointTo(p, a1)); S1 a2; a2.b = &a1; assert(doesPointTo(a2, a1)); struct S3 { int[10] a; } S3 a3; auto a4 = a3.a[2 .. 3]; assert(doesPointTo(a4, a3)); auto a5 = new double[4]; auto a6 = a5[1 .. 2]; assert(!doesPointTo(a5, a6)); auto a7 = new double[3]; auto a8 = new double[][1]; a8[0] = a7; assert(!doesPointTo(a8[0], a8[0])); // don't invoke postblit on subobjects { static struct NoCopy { this(this) { assert(0); } } static struct Holder { NoCopy a, b, c; } Holder h; cast(void)doesPointTo(h, h); } shared S3 sh3; shared sh3sub = sh3.a[]; assert(doesPointTo(sh3sub, sh3)); int[] darr = [1, 2, 3, 4]; //dynamic arrays don't point to each other, or slices of themselves assert(!doesPointTo(darr, darr)); assert(!doesPointTo(darr[0 .. 1], darr)); //But they do point their elements foreach (i; 0 .. 4) assert(doesPointTo(darr, darr[i])); assert(doesPointTo(darr[0..3], darr[2])); assert(!doesPointTo(darr[0..3], darr[3])); } unittest { //tests with static arrays //Static arrays themselves are just objects, and don't really *point* to anything. //They aggregate their contents, much the same way a structure aggregates its attributes. //*However* The elements inside the static array may themselves point to stuff. //Standard array int[2] k; assert(!doesPointTo(k, k)); //an array doesn't point to itself //Technically, k doesn't point its elements, although it does alias them assert(!doesPointTo(k, k[0])); assert(!doesPointTo(k, k[1])); //But an extracted slice will point to the same array. assert(doesPointTo(k[], k)); assert(doesPointTo(k[], k[1])); //An array of pointers int*[2] pp; int a; int b; pp[0] = &a; assert( doesPointTo(pp, a)); //The array contains a pointer to a assert(!doesPointTo(pp, b)); //The array does NOT contain a pointer to b assert(!doesPointTo(pp, pp)); //The array does not point itslef //A struct containing a static array of pointers static struct S { int*[2] p; } S s; s.p[0] = &a; assert( doesPointTo(s, a)); //The struct contains an array that points a assert(!doesPointTo(s, b)); //But doesn't point b assert(!doesPointTo(s, s)); //The struct doesn't actually point itslef. //An array containing structs that have pointers static struct SS { int* p; } SS[2] ss = [SS(&a), SS(null)]; assert( doesPointTo(ss, a)); //The array contains a struct that points to a assert(!doesPointTo(ss, b)); //The array doesn't contains a struct that points to b assert(!doesPointTo(ss, ss)); //The array doesn't point itself. } unittest //Unions { int i; union U //Named union { size_t asInt = 0; int* asPointer; } struct S { union //Anonymous union { size_t asInt = 0; int* asPointer; } } U u; S s; assert(!doesPointTo(u, i)); assert(!doesPointTo(s, i)); assert(!mayPointTo(u, i)); assert(!mayPointTo(s, i)); u.asPointer = &i; s.asPointer = &i; assert(!doesPointTo(u, i)); assert(!doesPointTo(s, i)); assert( mayPointTo(u, i)); assert( mayPointTo(s, i)); u.asInt = cast(size_t)&i; s.asInt = cast(size_t)&i; assert(!doesPointTo(u, i)); assert(!doesPointTo(s, i)); assert( mayPointTo(u, i)); assert( mayPointTo(s, i)); } unittest //Classes { int i; static class A { int* p; } A a = new A, b = a; assert(!doesPointTo(a, b)); //a does not point to b a.p = &i; assert(!doesPointTo(a, i)); //a does not point to i } unittest //alias this test { static int i; static int j; struct S { int* p; @property int* foo(){return &i;} alias foo this; } assert(is(S : int*)); S s = S(&j); assert(!doesPointTo(s, i)); assert( doesPointTo(s, j)); assert( doesPointTo(cast(int*)s, i)); assert(!doesPointTo(cast(int*)s, j)); } unittest //more alias this opCast { void* p; class A { void* opCast(T)() if (is(T == void*)) { return p; } alias foo = opCast!(void*); alias foo this; } assert(!doesPointTo(A.init, p)); assert(!mayPointTo(A.init, p)); } // Explicitly undocumented. It will be removed in May 2016. @@@DEPRECATED_2016-05@@@ deprecated ("pointsTo is ambiguous. Please use either of doesPointTo or mayPointTo") alias pointsTo = doesPointTo; /+ Returns true if the field at index $(D i) in ($D T) shares its address with another field. Note: This does not merelly check if the field is a member of an union, but also that it is not a single child. +/ package enum isUnionAliased(T, size_t i) = isUnionAliasedImpl!T(T.tupleof[i].offsetof); private bool isUnionAliasedImpl(T)(size_t offset) { int count = 0; foreach (i, U; typeof(T.tupleof)) if (T.tupleof[i].offsetof == offset) ++count; return count >= 2; } // unittest { static struct S { int a0; //Not aliased union { int a1; //Not aliased } union { int a2; //Aliased int a3; //Aliased } union A4 { int b0; //Not aliased } A4 a4; union A5 { int b0; //Aliased int b1; //Aliased } A5 a5; } static assert(!isUnionAliased!(S, 0)); //a0; static assert(!isUnionAliased!(S, 1)); //a1; static assert( isUnionAliased!(S, 2)); //a2; static assert( isUnionAliased!(S, 3)); //a3; static assert(!isUnionAliased!(S, 4)); //a4; static assert(!isUnionAliased!(S.A4, 0)); //a4.b0; static assert(!isUnionAliased!(S, 5)); //a5; static assert( isUnionAliased!(S.A5, 0)); //a5.b0; static assert( isUnionAliased!(S.A5, 1)); //a5.b1; } /********************* * Thrown if errors that set $(D errno) occur. */ class ErrnoException : Exception { final @property uint errno() { return _errno; } /// Operating system error code. private uint _errno; this(string msg, string file = null, size_t line = 0) @trusted { _errno = .errno; version (CRuntime_Glibc) { char[1024] buf = void; auto s = core.stdc.string.strerror_r(errno, buf.ptr, buf.length); } else { auto s = core.stdc.string.strerror(errno); } super(msg ~ " (" ~ s[0..s.strlen].idup ~ ")", file, line); } } /++ ML-style functional exception handling. Runs the supplied expression and returns its result. If the expression throws a $(D Throwable), runs the supplied error handler instead and return its result. The error handler's type must be the same as the expression's type. Params: E = The type of $(D Throwable)s to catch. Defaults to $(D Exception) T1 = The type of the expression. T2 = The return type of the error handler. expression = The expression to run and return its result. errorHandler = The handler to run if the expression throwed. Returns: expression, if it does not throw. Otherwise, returns the result of errorHandler. Example: -------------------- //Revert to a default value upon an error: assert("x".to!int().ifThrown(0) == 0); -------------------- You can also chain multiple calls to ifThrown, each capturing errors from the entire preceding expression. Example: -------------------- //Chaining multiple calls to ifThrown to attempt multiple things in a row: string s="true"; assert(s.to!int(). ifThrown(cast(int)s.to!double()). ifThrown(cast(int)s.to!bool()) == 1); //Respond differently to different types of errors assert(enforce("x".to!int() < 1).to!string() .ifThrown!ConvException("not a number") .ifThrown!Exception("number too small") == "not a number"); -------------------- The expression and the errorHandler must have a common type they can both be implicitly casted to, and that type will be the type of the compound expression. Example: -------------------- //null and new Object have a common type(Object). static assert(is(typeof(null.ifThrown(new Object())) == Object)); static assert(is(typeof((new Object()).ifThrown(null)) == Object)); //1 and new Object do not have a common type. static assert(!__traits(compiles, 1.ifThrown(new Object()))); static assert(!__traits(compiles, (new Object()).ifThrown(1))); -------------------- If you need to use the actual thrown exception, you can use a delegate. Example: -------------------- //Use a lambda to get the thrown object. assert("%s".format().ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException"); -------------------- +/ //lazy version CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler) { static assert(!is(typeof(return) == void), "The error handler's return value(" ~ T2.stringof ~ ") does not have a common type with the expression(" ~ T1.stringof ~ ")."); try { return expression(); } catch(E) { return errorHandler(); } } ///ditto //delegate version CommonType!(T1, T2) ifThrown(E : Throwable, T1, T2)(lazy scope T1 expression, scope T2 delegate(E) errorHandler) { static assert(!is(typeof(return) == void), "The error handler's return value(" ~ T2.stringof ~ ") does not have a common type with the expression(" ~ T1.stringof ~ ")."); try { return expression(); } catch(E e) { return errorHandler(e); } } ///ditto //delegate version, general overload to catch any Exception CommonType!(T1, T2) ifThrown(T1, T2)(lazy scope T1 expression, scope T2 delegate(Exception) errorHandler) { static assert(!is(typeof(return) == void), "The error handler's return value(" ~ T2.stringof ~ ") does not have a common type with the expression(" ~ T1.stringof ~ ")."); try { return expression(); } catch(Exception e) { return errorHandler(e); } } //Verify Examples unittest { import std.string; import std.conv; //Revert to a default value upon an error: assert("x".to!int().ifThrown(0) == 0); //Chaining multiple calls to ifThrown to attempt multiple things in a row: string s="true"; assert(s.to!int(). ifThrown(cast(int)s.to!double()). ifThrown(cast(int)s.to!bool()) == 1); //Respond differently to different types of errors assert(enforce("x".to!int() < 1).to!string() .ifThrown!ConvException("not a number") .ifThrown!Exception("number too small") == "not a number"); //null and new Object have a common type(Object). static assert(is(typeof(null.ifThrown(new Object())) == Object)); static assert(is(typeof((new Object()).ifThrown(null)) == Object)); //1 and new Object do not have a common type. static assert(!__traits(compiles, 1.ifThrown(new Object()))); static assert(!__traits(compiles, (new Object()).ifThrown(1))); //Use a lambda to get the thrown object. assert("%s".format().ifThrown(e => e.classinfo.name) == "std.format.FormatException"); } unittest { import std.string; import std.conv; import core.exception; //Basic behaviour - all versions. assert("1".to!int().ifThrown(0) == 1); assert("x".to!int().ifThrown(0) == 0); assert("1".to!int().ifThrown!ConvException(0) == 1); assert("x".to!int().ifThrown!ConvException(0) == 0); assert("1".to!int().ifThrown(e=>0) == 1); assert("x".to!int().ifThrown(e=>0) == 0); static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled { assert("1".to!int().ifThrown!ConvException(e=>0) == 1); assert("x".to!int().ifThrown!ConvException(e=>0) == 0); } //Exceptions other than stated not caught. assert("x".to!int().ifThrown!StringException(0).collectException!ConvException() !is null); static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled { assert("x".to!int().ifThrown!StringException(e=>0).collectException!ConvException() !is null); } //Default does not include errors. int throwRangeError() { throw new RangeError; } assert(throwRangeError().ifThrown(0).collectException!RangeError() !is null); assert(throwRangeError().ifThrown(e=>0).collectException!RangeError() !is null); //Incompatible types are not accepted. static assert(!__traits(compiles, 1.ifThrown(new Object()))); static assert(!__traits(compiles, (new Object()).ifThrown(1))); static assert(!__traits(compiles, 1.ifThrown(e=>new Object()))); static assert(!__traits(compiles, (new Object()).ifThrown(e=>1))); } version(unittest) package @property void assertCTFEable(alias dg)() { static assert({ cast(void)dg(); return true; }()); cast(void)dg(); } /** This $(D enum) is used to select the primitives of the range to handle by the $(LREF handle) range wrapper. The values of the $(D enum) can be $(D OR)'d to select multiple primitives to be handled. $(D RangePrimitive.access) is a shortcut for the access primitives; $(D front), $(D back) and $(D opIndex). $(D RangePrimitive.pop) is a shortcut for the mutating primitives; $(D popFront) and $(D popBack). */ enum RangePrimitive { front = 0b00_0000_0001, /// back = 0b00_0000_0010, /// Ditto popFront = 0b00_0000_0100, /// Ditto popBack = 0b00_0000_1000, /// Ditto empty = 0b00_0001_0000, /// Ditto save = 0b00_0010_0000, /// Ditto length = 0b00_0100_0000, /// Ditto opDollar = 0b00_1000_0000, /// Ditto opIndex = 0b01_0000_0000, /// Ditto opSlice = 0b10_0000_0000, /// Ditto access = front | back | opIndex, /// Ditto pop = popFront | popBack, /// Ditto } /** Handle exceptions thrown from range primitives. Use the $(LREF RangePrimitive) enum to specify which primitives to _handle. Multiple range primitives can be handled at once by using the $(D OR) operator or the pseudo-primitives $(D RangePrimitive.access) and $(D RangePrimitive.pop). All handled primitives must have return types or values compatible with the user-supplied handler. Params: E = The type of $(D Throwable) to _handle. primitivesToHandle = Set of range primitives to _handle. handler = The callable that is called when a handled primitive throws a $(D Throwable) of type $(D E). The handler must accept arguments of the form $(D E, ref IRange) and its return value is used as the primitive's return value whenever $(D E) is thrown. For $(D opIndex), the handler can optionally recieve a third argument; the index that caused the exception. input = The range to _handle. Returns: A wrapper $(D struct) that preserves the range interface of $(D input). opSlice: Infinite ranges with slicing support must return an instance of $(XREF range, Take) when sliced with a specific lower and upper bound (see $(XREF_PACK range,primitives,hasSlicing)); $(D handle) deals with this by $(D take)ing 0 from the return value of the handler function and returning that when an exception is caught. */ auto handle(E : Throwable, RangePrimitive primitivesToHandle, alias handler, Range)(Range input) if (isInputRange!Range) { static struct Handler { private Range range; static if (isForwardRange!Range) { @property typeof(this) save() { static if (primitivesToHandle & RangePrimitive.save) { try { return typeof(this)(range.save); } catch(E exception) { return typeof(this)(handler(exception, this.range)); } } else return typeof(this)(range.save); } } static if (isInfinite!Range) { enum bool empty = false; } else { @property bool empty() { static if (primitivesToHandle & RangePrimitive.empty) { try { return this.range.empty; } catch(E exception) { return handler(exception, this.range); } } else return this.range.empty; } } @property auto ref front() { static if (primitivesToHandle & RangePrimitive.front) { try { return this.range.front; } catch(E exception) { return handler(exception, this.range); } } else return this.range.front; } void popFront() { static if (primitivesToHandle & RangePrimitive.popFront) { try { this.range.popFront(); } catch(E exception) { handler(exception, this.range); } } else this.range.popFront(); } static if (isBidirectionalRange!Range) { @property auto ref back() { static if (primitivesToHandle & RangePrimitive.back) { try { return this.range.back; } catch(E exception) { return handler(exception, this.range); } } else return this.range.back; } void popBack() { static if (primitivesToHandle & RangePrimitive.popBack) { try { this.range.popBack(); } catch(E exception) { handler(exception, this.range); } } else this.range.popBack(); } } static if (isRandomAccessRange!Range) { auto ref opIndex(size_t index) { static if (primitivesToHandle & RangePrimitive.opIndex) { try { return this.range[index]; } catch(E exception) { static if (__traits(compiles, handler(exception, this.range, index))) return handler(exception, this.range, index); else return handler(exception, this.range); } } else return this.range[index]; } } static if (hasLength!Range) { @property auto length() { static if (primitivesToHandle & RangePrimitive.length) { try { return this.range.length; } catch(E exception) { return handler(exception, this.range); } } else return this.range.length; } } static if (hasSlicing!Range) { static if (hasLength!Range) { typeof(this) opSlice(size_t lower, size_t upper) { static if (primitivesToHandle & RangePrimitive.opSlice) { try { return typeof(this)(this.range[lower .. upper]); } catch(E exception) { return typeof(this)(handler(exception, this.range)); } } else return typeof(this)(this.range[lower .. upper]); } } else static if (is(typeof(Range.init[size_t.init .. $]))) { static struct DollarToken {} enum opDollar = DollarToken.init; typeof(this) opSlice(size_t lower, DollarToken) { static if (primitivesToHandle & RangePrimitive.opSlice) { try { return typeof(this)(this.range[lower .. $]); } catch(E exception) { return typeof(this)(handler(exception, this.range)); } } else return typeof(this)(this.range[lower .. $]); } Take!Handler opSlice(size_t lower, size_t upper) { static if (primitivesToHandle & RangePrimitive.opSlice) { try { return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1); } catch(E exception) { return takeExactly(typeof(this)(handler(exception, this.range)), 0); } } else return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1); } } } } return Handler(input); } /// pure @safe unittest { import std.algorithm : equal, map, splitter; import std.conv : to, ConvException; auto s = "12,1337z32,54,2,7,9,1z,6,8"; // The next line composition will throw when iterated // as some elements of the input do not convert to integer auto r = s.splitter(',').map!(a => to!int(a)); // Substitute 0 for cases of ConvException auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); } /// pure @safe unittest { import std.algorithm : equal; import std.range : retro; import std.utf : UTFException; auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit auto handled = str.handle!(UTFException, RangePrimitive.access, (e, r) => ' '); // Replace invalid code points with spaces assert(handled.equal("hello world")); // `front` is handled, assert(handled.retro.equal("dlrow olleh")); // as well as `back` } pure nothrow @safe unittest { static struct ThrowingRange { pure @safe: @property bool empty() { throw new Exception("empty has thrown"); } @property int front() { throw new Exception("front has thrown"); } @property int back() { throw new Exception("back has thrown"); } void popFront() { throw new Exception("popFront has thrown"); } void popBack() { throw new Exception("popBack has thrown"); } int opIndex(size_t) { throw new Exception("opIndex has thrown"); } ThrowingRange opSlice(size_t, size_t) { throw new Exception("opSlice has thrown"); } @property size_t length() { throw new Exception("length has thrown"); } alias opDollar = length; @property ThrowingRange save() { throw new Exception("save has thrown"); } } static assert(isInputRange!ThrowingRange); static assert(isForwardRange!ThrowingRange); static assert(isBidirectionalRange!ThrowingRange); static assert(hasSlicing!ThrowingRange); static assert(hasLength!ThrowingRange); auto f = ThrowingRange(); auto fb = f.handle!(Exception, RangePrimitive.front | RangePrimitive.back, (e, r) => -1)(); assert(fb.front == -1); assert(fb.back == -1); assertThrown(fb.popFront()); assertThrown(fb.popBack()); assertThrown(fb.empty); assertThrown(fb.save); assertThrown(fb[0]); auto accessRange = f.handle!(Exception, RangePrimitive.access, (e, r) => -1); assert(accessRange.front == -1); assert(accessRange.back == -1); assert(accessRange[0] == -1); assertThrown(accessRange.popFront()); assertThrown(accessRange.popBack()); auto pfb = f.handle!(Exception, RangePrimitive.pop, (e, r) => -1)(); pfb.popFront(); // this would throw otherwise pfb.popBack(); // this would throw otherwise auto em = f.handle!(Exception, RangePrimitive.empty, (e, r) => false)(); assert(!em.empty); auto arr = f.handle!(Exception, RangePrimitive.opIndex, (e, r) => 1337)(); assert(arr[0] == 1337); auto arr2 = f.handle!(Exception, RangePrimitive.opIndex, (e, r, i) => i)(); assert(arr2[0] == 0); assert(arr2[1337] == 1337); auto save = f.handle!(Exception, RangePrimitive.save, function(Exception e, ref ThrowingRange r) { return ThrowingRange(); })(); save.save; auto slice = f.handle!(Exception, RangePrimitive.opSlice, (e, r) => ThrowingRange())(); auto sliced = slice[0 .. 1337]; // this would throw otherwise static struct Infinite { pure @safe: enum bool empty = false; int front() { assert(false); } void popFront() { assert(false); } Infinite save() @property { assert(false); } static struct DollarToken {} enum opDollar = DollarToken.init; Take!Infinite opSlice(size_t, size_t) { assert(false); } Infinite opSlice(size_t, DollarToken) { throw new Exception("opSlice has thrown"); } } static assert(isInputRange!Infinite); static assert(isInfinite!Infinite); static assert(hasSlicing!Infinite); assertThrown(Infinite()[0 .. $]); auto infinite = Infinite.init.handle!(Exception, RangePrimitive.opSlice, (e, r) => Infinite())(); auto infSlice = infinite[0 .. $]; // this would throw otherwise } /++ Convenience mixin for trivially sub-classing exceptions Even trivially sub-classing an exception involves writing boilerplate code for the constructor to: 1) correctly pass in the source file and line number the exception was thrown from; 2) be usable with $(LREF enforce) which expects exception constructors to take arguments in a fixed order. This mixin provides that boilerplate code. Note however that you need to mark the $(B mixin) line with at least a minimal (i.e. just $(B ///)) DDoc comment if you want the mixed-in constructors to be documented in the newly created Exception subclass. $(RED Current limitation): Due to $(LINK2 https://issues.dlang.org/show_bug.cgi?id=11500, bug #11500), currently the constructors specified in this mixin cannot be overloaded with any other custom constructors. Thus this mixin can currently only be used when no such custom constructors need to be explicitly specified. +/ mixin template basicExceptionCtors() { /++ Params: msg = The message for the exception. file = The file where the exception occurred. line = The line number where the exception occurred. next = The previous exception in the chain of exceptions, if any. +/ this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @nogc @safe pure nothrow { super(msg, file, line, next); } /++ Params: msg = The message for the exception. next = The previous exception in the chain of exceptions. file = The file where the exception occurred. line = The line number where the exception occurred. +/ this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @nogc @safe pure nothrow { super(msg, file, line, next); } } /// unittest { class MeaCulpa: Exception { /// mixin basicExceptionCtors; } try throw new MeaCulpa("test"); catch (MeaCulpa e) { assert(e.msg == "test"); assert(e.file == __FILE__); assert(e.line == __LINE__ - 5); } } @safe pure nothrow unittest { class TestException : Exception { mixin basicExceptionCtors; } auto e = new Exception("msg"); auto te1 = new TestException("foo"); auto te2 = new TestException("foo", e); } unittest { class TestException : Exception { mixin basicExceptionCtors; } auto e = new Exception("!!!"); auto te1 = new TestException("message", "file", 42, e); assert(te1.msg == "message"); assert(te1.file == "file"); assert(te1.line == 42); assert(te1.next is e); auto te2 = new TestException("message", e, "file", 42); assert(te2.msg == "message"); assert(te2.file == "file"); assert(te2.line == 42); assert(te2.next is e); auto te3 = new TestException("foo"); assert(te3.msg == "foo"); assert(te3.file == __FILE__); assert(te3.line == __LINE__ - 3); assert(te3.next is null); auto te4 = new TestException("foo", e); assert(te4.msg == "foo"); assert(te4.file == __FILE__); assert(te4.line == __LINE__ - 3); assert(te4.next is e); } ldc-1.1.0-beta3-src/runtime/phobos/std/json.d0000664000175000017500000013115112776215007017026 0ustar kaikai// Written in the D programming language. /** JavaScript Object Notation Synopsis: ---- //parse a file or string of json into a usable structure string s = "{ \"language\": \"D\", \"rating\": 3.14, \"code\": \"42\" }"; JSONValue j = parseJSON(s); writeln("Language: ", j["language"].str(), " Rating: ", j["rating"].floating() ); // j and j["language"] return JSONValue, // j["language"].str returns a string //check a type long x; if (const(JSONValue)* code = "code" in j) { if (code.type() == JSON_TYPE.INTEGER) x = code.integer; else x = to!int(code.str); } // create a json struct JSONValue jj = [ "language": "D" ]; // rating doesnt exist yet, so use .object to assign jj.object["rating"] = JSONValue(3.14); // create an array to assign to list jj.object["list"] = JSONValue( ["a", "b", "c"] ); // list already exists, so .object optional jj["list"].array ~= JSONValue("D"); s = j.toString(); writeln(s); ---- Copyright: Copyright Jeremie Pelletier 2008 - 2009. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jeremie Pelletier, David Herberth References: $(LINK http://json.org/) Source: $(PHOBOSSRC std/_json.d) */ /* Copyright Jeremie Pelletier 2008 - 2009. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.json; import std.conv; import std.range.primitives; import std.array; import std.traits; /** String literals used to represent special float values within JSON strings. */ enum JSONFloatLiteral : string { nan = "NaN", /// string representation of floating-point NaN inf = "Infinite", /// string representation of floating-point Infinity negativeInf = "-Infinite", /// string representation of floating-point negative Infinity } /** Flags that control how json is encoded and parsed. */ enum JSONOptions { none, /// standard parsing specialFloatLiterals = 0x1, /// encode NaN and Inf float values as strings } /** JSON type enumeration */ enum JSON_TYPE : byte { /// Indicates the type of a $(D JSONValue). NULL, STRING, /// ditto INTEGER, /// ditto UINTEGER,/// ditto FLOAT, /// ditto OBJECT, /// ditto ARRAY, /// ditto TRUE, /// ditto FALSE /// ditto } /** JSON value node */ struct JSONValue { import std.exception : enforceEx, enforce; union Store { string str; long integer; ulong uinteger; double floating; JSONValue[string] object; JSONValue[] array; } private Store store; private JSON_TYPE type_tag; /** Returns the JSON_TYPE of the value stored in this structure. */ @property JSON_TYPE type() const pure nothrow @safe @nogc { return type_tag; } /// unittest { string s = "{ \"language\": \"D\" }"; JSONValue j = parseJSON(s); assert(j.type == JSON_TYPE.OBJECT); assert(j["language"].type == JSON_TYPE.STRING); } // Explicitly undocumented. It will be removed in June 2016. @@@DEPRECATED_2016-06@@@ deprecated("Please assign the value with the adequate type to JSONValue directly.") @property JSON_TYPE type(JSON_TYPE newType) { if (type_tag != newType && ((type_tag != JSON_TYPE.INTEGER && type_tag != JSON_TYPE.UINTEGER) || (newType != JSON_TYPE.INTEGER && newType != JSON_TYPE.UINTEGER))) { final switch (newType) { case JSON_TYPE.STRING: store.str = store.str.init; break; case JSON_TYPE.INTEGER: store.integer = store.integer.init; break; case JSON_TYPE.UINTEGER: store.uinteger = store.uinteger.init; break; case JSON_TYPE.FLOAT: store.floating = store.floating.init; break; case JSON_TYPE.OBJECT: store.object = store.object.init; break; case JSON_TYPE.ARRAY: store.array = store.array.init; break; case JSON_TYPE.TRUE: case JSON_TYPE.FALSE: case JSON_TYPE.NULL: break; } } return type_tag = newType; } /// Value getter/setter for $(D JSON_TYPE.STRING). /// Throws: $(D JSONException) for read access if $(D type) is not /// $(D JSON_TYPE.STRING). @property inout(string) str() inout pure { enforce!JSONException(type == JSON_TYPE.STRING, "JSONValue is not a string"); return store.str; } /// ditto @property string str(string v) pure nothrow @nogc { assign(v); return store.str; } /// unittest { JSONValue j = [ "language": "D" ]; // get value assert(j["language"].str == "D"); // change existing key to new string j["language"].str = "Perl"; assert(j["language"].str == "Perl"); } /// Value getter/setter for $(D JSON_TYPE.INTEGER). /// Throws: $(D JSONException) for read access if $(D type) is not /// $(D JSON_TYPE.INTEGER). @property inout(long) integer() inout pure @safe { enforce!JSONException(type == JSON_TYPE.INTEGER, "JSONValue is not an integer"); return store.integer; } /// ditto @property long integer(long v) pure nothrow @safe @nogc { assign(v); return store.integer; } /// Value getter/setter for $(D JSON_TYPE.UINTEGER). /// Throws: $(D JSONException) for read access if $(D type) is not /// $(D JSON_TYPE.UINTEGER). @property inout(ulong) uinteger() inout pure @safe { enforce!JSONException(type == JSON_TYPE.UINTEGER, "JSONValue is not an unsigned integer"); return store.uinteger; } /// ditto @property ulong uinteger(ulong v) pure nothrow @safe @nogc { assign(v); return store.uinteger; } /// Value getter/setter for $(D JSON_TYPE.FLOAT). /// Throws: $(D JSONException) for read access if $(D type) is not /// $(D JSON_TYPE.FLOAT). @property inout(double) floating() inout pure @safe { enforce!JSONException(type == JSON_TYPE.FLOAT, "JSONValue is not a floating type"); return store.floating; } /// ditto @property double floating(double v) pure nothrow @safe @nogc { assign(v); return store.floating; } /// Value getter/setter for $(D JSON_TYPE.OBJECT). /// Throws: $(D JSONException) for read access if $(D type) is not /// $(D JSON_TYPE.OBJECT). @property ref inout(JSONValue[string]) object() inout pure { enforce!JSONException(type == JSON_TYPE.OBJECT, "JSONValue is not an object"); return store.object; } /// ditto @property JSONValue[string] object(JSONValue[string] v) pure nothrow @nogc { assign(v); return store.object; } /// Value getter/setter for $(D JSON_TYPE.ARRAY). /// Throws: $(D JSONException) for read access if $(D type) is not /// $(D JSON_TYPE.ARRAY). @property ref inout(JSONValue[]) array() inout pure { enforce!JSONException(type == JSON_TYPE.ARRAY, "JSONValue is not an array"); return store.array; } /// ditto @property JSONValue[] array(JSONValue[] v) pure nothrow @nogc { assign(v); return store.array; } /// Test whether the type is $(D JSON_TYPE.NULL) @property bool isNull() const pure nothrow @safe @nogc { return type == JSON_TYPE.NULL; } private void assign(T)(T arg) { static if(is(T : typeof(null))) { type_tag = JSON_TYPE.NULL; } else static if(is(T : string)) { type_tag = JSON_TYPE.STRING; store.str = arg; } else static if(is(T : bool)) { type_tag = arg ? JSON_TYPE.TRUE : JSON_TYPE.FALSE; } else static if(is(T : ulong) && isUnsigned!T) { type_tag = JSON_TYPE.UINTEGER; store.uinteger = arg; } else static if(is(T : long)) { type_tag = JSON_TYPE.INTEGER; store.integer = arg; } else static if(isFloatingPoint!T) { type_tag = JSON_TYPE.FLOAT; store.floating = arg; } else static if(is(T : Value[Key], Key, Value)) { static assert(is(Key : string), "AA key must be string"); type_tag = JSON_TYPE.OBJECT; static if(is(Value : JSONValue)) { store.object = arg; } else { JSONValue[string] aa; foreach(key, value; arg) aa[key] = JSONValue(value); store.object = aa; } } else static if(isArray!T) { type_tag = JSON_TYPE.ARRAY; static if(is(ElementEncodingType!T : JSONValue)) { store.array = arg; } else { JSONValue[] new_arg = new JSONValue[arg.length]; foreach(i, e; arg) new_arg[i] = JSONValue(e); store.array = new_arg; } } else static if(is(T : JSONValue)) { type_tag = arg.type; store = arg.store; } else { static assert(false, text(`unable to convert type "`, T.stringof, `" to json`)); } } private void assignRef(T)(ref T arg) if(isStaticArray!T) { type_tag = JSON_TYPE.ARRAY; static if(is(ElementEncodingType!T : JSONValue)) { store.array = arg; } else { JSONValue[] new_arg = new JSONValue[arg.length]; foreach(i, e; arg) new_arg[i] = JSONValue(e); store.array = new_arg; } } /** * Constructor for $(D JSONValue). If $(D arg) is a $(D JSONValue) * its value and type will be copied to the new $(D JSONValue). * Note that this is a shallow copy: if type is $(D JSON_TYPE.OBJECT) * or $(D JSON_TYPE.ARRAY) then only the reference to the data will * be copied. * Otherwise, $(D arg) must be implicitly convertible to one of the * following types: $(D typeof(null)), $(D string), $(D ulong), * $(D long), $(D double), an associative array $(D V[K]) for any $(D V) * and $(D K) i.e. a JSON object, any array or $(D bool). The type will * be set accordingly. */ this(T)(T arg) if(!isStaticArray!T) { assign(arg); } /// Ditto this(T)(ref T arg) if(isStaticArray!T) { assignRef(arg); } /// Ditto this(T : JSONValue)(inout T arg) inout { store = arg.store; type_tag = arg.type; } /// unittest { JSONValue j = JSONValue( "a string" ); j = JSONValue(42); j = JSONValue( [1, 2, 3] ); assert(j.type == JSON_TYPE.ARRAY); j = JSONValue( ["language": "D"] ); assert(j.type == JSON_TYPE.OBJECT); } void opAssign(T)(T arg) if(!isStaticArray!T && !is(T : JSONValue)) { assign(arg); } void opAssign(T)(ref T arg) if(isStaticArray!T) { assignRef(arg); } /// Array syntax for json arrays. /// Throws: $(D JSONException) if $(D type) is not $(D JSON_TYPE.ARRAY). ref inout(JSONValue) opIndex(size_t i) inout pure { enforce!JSONException(type == JSON_TYPE.ARRAY, "JSONValue is not an array"); enforceEx!JSONException(i < store.array.length, "JSONValue array index is out of range"); return store.array[i]; } /// unittest { JSONValue j = JSONValue( [42, 43, 44] ); assert( j[0].integer == 42 ); assert( j[1].integer == 43 ); } /// Hash syntax for json objects. /// Throws: $(D JSONException) if $(D type) is not $(D JSON_TYPE.OBJECT). ref inout(JSONValue) opIndex(string k) inout pure { enforce!JSONException(type == JSON_TYPE.OBJECT, "JSONValue is not an object"); return *enforce!JSONException(k in store.object, "Key not found: " ~ k); } /// unittest { JSONValue j = JSONValue( ["language": "D"] ); assert( j["language"].str == "D" ); } /// Operator sets $(D value) for element of JSON object by $(D key). /// /// If JSON value is null, then operator initializes it with object and then /// sets $(D value) for it. /// /// Throws: $(D JSONException) if $(D type) is not $(D JSON_TYPE.OBJECT) /// or $(D JSON_TYPE.NULL). void opIndexAssign(T)(auto ref T value, string key) pure { enforceEx!JSONException(type == JSON_TYPE.OBJECT || type == JSON_TYPE.NULL, "JSONValue must be object or null"); if(type == JSON_TYPE.NULL) this = (JSONValue[string]).init; store.object[key] = value; } /// unittest { JSONValue j = JSONValue( ["language": "D"] ); j["language"].str = "Perl"; assert( j["language"].str == "Perl" ); } void opIndexAssign(T)(T arg, size_t i) pure { enforceEx!JSONException(type == JSON_TYPE.ARRAY, "JSONValue is not an array"); enforceEx!JSONException(i < store.array.length, "JSONValue array index is out of range"); store.array[i] = arg; } /// unittest { JSONValue j = JSONValue( ["Perl", "C"] ); j[1].str = "D"; assert( j[1].str == "D" ); } JSONValue opBinary(string op : "~", T)(T arg) { enforceEx!JSONException(type == JSON_TYPE.ARRAY, "JSONValue is not an array"); static if(isArray!T) { JSONValue newArray = JSONValue(this.store.array.dup); newArray.store.array ~= JSONValue(arg).store.array; return newArray; } else static if(is(T : JSONValue)) { enforceEx!JSONException(arg.type == JSON_TYPE.ARRAY, "JSONValue is not an array"); JSONValue newArray = JSONValue(this.store.array.dup); newArray.store.array ~= arg.store.array; return newArray; } else { static assert(false, "argument is not an array or a JSONValue array"); } } void opOpAssign(string op : "~", T)(T arg) { enforceEx!JSONException(type == JSON_TYPE.ARRAY, "JSONValue is not an array"); static if(isArray!T) { store.array ~= JSONValue(arg).store.array; } else static if(is(T : JSONValue)) { enforceEx!JSONException(arg.type == JSON_TYPE.ARRAY, "JSONValue is not an array"); store.array ~= arg.store.array; } else { static assert(false, "argument is not an array or a JSONValue array"); } } /** * Support for the $(D in) operator. * * Tests wether a key can be found in an object. * * Returns: * when found, the $(D const(JSONValue)*) that matches to the key, * otherwise $(D null). * * Throws: $(D JSONException) if the right hand side argument $(D JSON_TYPE) * is not $(D OBJECT). */ auto opBinaryRight(string op : "in")(string k) const { enforce!JSONException(type == JSON_TYPE.OBJECT, "JSONValue is not an object"); return k in store.object; } /// unittest { JSONValue j = [ "language": "D", "author": "walter" ]; string a = ("author" in j).str; } bool opEquals(const JSONValue rhs) const pure nothrow @nogc { return opEquals(rhs); } bool opEquals(ref const JSONValue rhs) const pure nothrow @nogc { // Default doesn't work well since store is a union. Compare only // what should be in store. if (type_tag != rhs.type_tag) return false; final switch (type_tag) { case JSON_TYPE.STRING: return store.str == rhs.store.str; case JSON_TYPE.INTEGER: return store.integer == rhs.store.integer; case JSON_TYPE.UINTEGER: return store.uinteger == rhs.store.uinteger; case JSON_TYPE.FLOAT: return store.floating == rhs.store.floating; case JSON_TYPE.OBJECT: return store.object == rhs.store.object; case JSON_TYPE.ARRAY: return store.array == rhs.store.array; case JSON_TYPE.TRUE: case JSON_TYPE.FALSE: case JSON_TYPE.NULL: return true; } } /// Implements the foreach $(D opApply) interface for json arrays. int opApply(int delegate(size_t index, ref JSONValue) dg) { enforce!JSONException(type == JSON_TYPE.ARRAY, "JSONValue is not an array"); int result; foreach(size_t index, ref value; store.array) { result = dg(index, value); if(result) break; } return result; } /// Implements the foreach $(D opApply) interface for json objects. int opApply(int delegate(string key, ref JSONValue) dg) { enforce!JSONException(type == JSON_TYPE.OBJECT, "JSONValue is not an object"); int result; foreach(string key, ref value; store.object) { result = dg(key, value); if(result) break; } return result; } /// Implicitly calls $(D toJSON) on this JSONValue. /// /// $(I options) can be used to tweak the conversion behavior. string toString(in JSONOptions options = JSONOptions.none) const { return toJSON(&this, false, options); } /// Implicitly calls $(D toJSON) on this JSONValue, like $(D toString), but /// also passes $(I true) as $(I pretty) argument. /// /// $(I options) can be used to tweak the conversion behavior string toPrettyString(in JSONOptions options = JSONOptions.none) const { return toJSON(&this, true, options); } } /** Parses a serialized string and returns a tree of JSON values. Throws: $(XREF json,JSONException) if the depth exceeds the max depth. Params: json = json-formatted string to parse maxDepth = maximum depth of nesting allowed, -1 disables depth checking options = enable decoding string representations of NaN/Inf as float values */ JSONValue parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none) if(isInputRange!T) { import std.ascii : isWhite, isDigit, isHexDigit, toUpper, toLower; import std.utf : toUTF8; JSONValue root = void; root.type_tag = JSON_TYPE.NULL; if(json.empty) return root; int depth = -1; dchar next = 0; int line = 1, pos = 0; void error(string msg) { throw new JSONException(msg, line, pos); } dchar popChar() { if (json.empty) error("Unexpected end of data."); dchar c = json.front; json.popFront(); if(c == '\n') { line++; pos = 0; } else { pos++; } return c; } dchar peekChar() { if(!next) { if(json.empty) return '\0'; next = popChar(); } return next; } void skipWhitespace() { while(isWhite(peekChar())) next = 0; } dchar getChar(bool SkipWhitespace = false)() { static if(SkipWhitespace) skipWhitespace(); dchar c = void; if(next) { c = next; next = 0; } else c = popChar(); return c; } void checkChar(bool SkipWhitespace = true, bool CaseSensitive = true)(char c) { static if(SkipWhitespace) skipWhitespace(); auto c2 = getChar(); static if(!CaseSensitive) c2 = toLower(c2); if(c2 != c) error(text("Found '", c2, "' when expecting '", c, "'.")); } bool testChar(bool SkipWhitespace = true, bool CaseSensitive = true)(char c) { static if(SkipWhitespace) skipWhitespace(); auto c2 = peekChar(); static if (!CaseSensitive) c2 = toLower(c2); if(c2 != c) return false; getChar(); return true; } string parseString() { auto str = appender!string(); Next: switch(peekChar()) { case '"': getChar(); break; case '\\': getChar(); auto c = getChar(); switch(c) { case '"': str.put('"'); break; case '\\': str.put('\\'); break; case '/': str.put('/'); break; case 'b': str.put('\b'); break; case 'f': str.put('\f'); break; case 'n': str.put('\n'); break; case 'r': str.put('\r'); break; case 't': str.put('\t'); break; case 'u': dchar val = 0; foreach_reverse(i; 0 .. 4) { auto hex = toUpper(getChar()); if(!isHexDigit(hex)) error("Expecting hex character"); val += (isDigit(hex) ? hex - '0' : hex - ('A' - 10)) << (4 * i); } char[4] buf = void; str.put(toUTF8(buf, val)); break; default: error(text("Invalid escape sequence '\\", c, "'.")); } goto Next; default: auto c = getChar(); appendJSONChar(&str, c, &error); goto Next; } return str.data.length ? str.data : ""; } bool tryGetSpecialFloat(string str, out double val) { switch(str) { case JSONFloatLiteral.nan: val = double.nan; return true; case JSONFloatLiteral.inf: val = double.infinity; return true; case JSONFloatLiteral.negativeInf: val = -double.infinity; return true; default: return false; } } void parseValue(out JSONValue value) { depth++; if(maxDepth != -1 && depth > maxDepth) error("Nesting too deep."); auto c = getChar!true(); switch(c) { case '{': value.type_tag = JSON_TYPE.OBJECT; value.store.object = null; if(testChar('}')) break; do { checkChar('"'); string name = parseString(); checkChar(':'); JSONValue member = void; parseValue(member); value.store.object[name] = member; } while(testChar(',')); checkChar('}'); break; case '[': value.type_tag = JSON_TYPE.ARRAY; if(testChar(']')) { value.store.array = cast(JSONValue[]) ""; break; } value.store.array = null; do { JSONValue element = void; parseValue(element); value.store.array ~= element; } while(testChar(',')); checkChar(']'); break; case '"': auto str = parseString(); // if special float parsing is enabled, check if string represents NaN/Inf if ((options & JSONOptions.specialFloatLiterals) && tryGetSpecialFloat(str, value.store.floating)) { // found a special float, its value was placed in value.store.floating value.type_tag = JSON_TYPE.FLOAT; break; } value.type_tag = JSON_TYPE.STRING; value.store.str = str; break; case '0': .. case '9': case '-': auto number = appender!string(); bool isFloat, isNegative; void readInteger() { if(!isDigit(c)) error("Digit expected"); Next: number.put(c); if(isDigit(peekChar())) { c = getChar(); goto Next; } } if(c == '-') { number.put('-'); c = getChar(); isNegative = true; } readInteger(); if(testChar('.')) { isFloat = true; number.put('.'); c = getChar(); readInteger(); } if(testChar!(false, false)('e')) { isFloat = true; number.put('e'); if(testChar('+')) number.put('+'); else if(testChar('-')) number.put('-'); c = getChar(); readInteger(); } string data = number.data; if(isFloat) { value.type_tag = JSON_TYPE.FLOAT; value.store.floating = parse!double(data); } else { if (isNegative) value.store.integer = parse!long(data); else value.store.uinteger = parse!ulong(data); value.type_tag = !isNegative && value.store.uinteger & (1UL << 63) ? JSON_TYPE.UINTEGER : JSON_TYPE.INTEGER; } break; case 't': case 'T': value.type_tag = JSON_TYPE.TRUE; checkChar!(false, false)('r'); checkChar!(false, false)('u'); checkChar!(false, false)('e'); break; case 'f': case 'F': value.type_tag = JSON_TYPE.FALSE; checkChar!(false, false)('a'); checkChar!(false, false)('l'); checkChar!(false, false)('s'); checkChar!(false, false)('e'); break; case 'n': case 'N': value.type_tag = JSON_TYPE.NULL; checkChar!(false, false)('u'); checkChar!(false, false)('l'); checkChar!(false, false)('l'); break; default: error(text("Unexpected character '", c, "'.")); } depth--; } parseValue(root); return root; } unittest { enum issue15742objectOfObject = `{ "key1": { "key2": 1 }}`; static assert(parseJSON(issue15742objectOfObject).type == JSON_TYPE.OBJECT); enum issue15742arrayOfArray = `[[1]]`; static assert(parseJSON(issue15742arrayOfArray).type == JSON_TYPE.ARRAY); } /** Parses a serialized string and returns a tree of JSON values. Throws: $(XREF json,JSONException) if the depth exceeds the max depth. Params: json = json-formatted string to parse options = enable decoding string representations of NaN/Inf as float values */ JSONValue parseJSON(T)(T json, JSONOptions options) if(isInputRange!T) { return parseJSON!T(json, -1, options); } /** Takes a tree of JSON values and returns the serialized string. Any Object types will be serialized in a key-sorted order. If $(D pretty) is false no whitespaces are generated. If $(D pretty) is true serialized string is formatted to be human-readable. Set the $(specialFloatLiterals) flag is set in $(D options) to encode NaN/Infinity as strings. */ string toJSON(in JSONValue* root, in bool pretty = false, in JSONOptions options = JSONOptions.none) { auto json = appender!string(); void toString(string str) { json.put('"'); foreach (dchar c; str) { switch(c) { case '"': json.put("\\\""); break; case '\\': json.put("\\\\"); break; case '/': json.put("\\/"); break; case '\b': json.put("\\b"); break; case '\f': json.put("\\f"); break; case '\n': json.put("\\n"); break; case '\r': json.put("\\r"); break; case '\t': json.put("\\t"); break; default: appendJSONChar(&json, c, (msg) { throw new JSONException(msg); }); } } json.put('"'); } void toValue(in JSONValue* value, ulong indentLevel) { void putTabs(ulong additionalIndent = 0) { if(pretty) foreach(i; 0 .. indentLevel + additionalIndent) json.put(" "); } void putEOL() { if(pretty) json.put('\n'); } void putCharAndEOL(char ch) { json.put(ch); putEOL(); } final switch(value.type) { case JSON_TYPE.OBJECT: if(!value.store.object.length) { json.put("{}"); } else { putCharAndEOL('{'); bool first = true; void emit(R)(R names) { foreach (name; names) { auto member = value.store.object[name]; if(!first) putCharAndEOL(','); first = false; putTabs(1); toString(name); json.put(':'); if(pretty) json.put(' '); toValue(&member, indentLevel + 1); } } import std.algorithm : sort; auto names = value.store.object.keys; sort(names); emit(names); putEOL(); putTabs(); json.put('}'); } break; case JSON_TYPE.ARRAY: if(value.store.array.empty) { json.put("[]"); } else { putCharAndEOL('['); foreach (i, ref el; value.store.array) { if(i) putCharAndEOL(','); putTabs(1); toValue(&el, indentLevel + 1); } putEOL(); putTabs(); json.put(']'); } break; case JSON_TYPE.STRING: toString(value.store.str); break; case JSON_TYPE.INTEGER: json.put(to!string(value.store.integer)); break; case JSON_TYPE.UINTEGER: json.put(to!string(value.store.uinteger)); break; case JSON_TYPE.FLOAT: import std.math : isNaN, isInfinity; auto val = value.store.floating; if (val.isNaN) { if (options & JSONOptions.specialFloatLiterals) { toString(JSONFloatLiteral.nan); } else { throw new JSONException( "Cannot encode NaN. Consider passing the specialFloatLiterals flag."); } } else if (val.isInfinity) { if (options & JSONOptions.specialFloatLiterals) { toString((val > 0) ? JSONFloatLiteral.inf : JSONFloatLiteral.negativeInf); } else { throw new JSONException( "Cannot encode Infinity. Consider passing the specialFloatLiterals flag."); } } else { json.put(to!string(val)); } break; case JSON_TYPE.TRUE: json.put("true"); break; case JSON_TYPE.FALSE: json.put("false"); break; case JSON_TYPE.NULL: json.put("null"); break; } } toValue(root, 0); return json.data; } private void appendJSONChar(Appender!string* dst, dchar c, scope void delegate(string) error) { import std.uni : isControl; if(isControl(c)) { dst.put("\\u"); foreach_reverse (i; 0 .. 4) { char ch = (c >>> (4 * i)) & 0x0f; ch += ch < 10 ? '0' : 'A' - 10; dst.put(ch); } } else { dst.put(c); } } /** Exception thrown on JSON errors */ class JSONException : Exception { this(string msg, int line = 0, int pos = 0) pure nothrow @safe { if(line) super(text(msg, " (Line ", line, ":", pos, ")")); else super(msg); } this(string msg, string file, size_t line) pure nothrow @safe { super(msg, file, line); } } unittest { import std.exception; JSONValue jv = "123"; assert(jv.type == JSON_TYPE.STRING); assertNotThrown(jv.str); assertThrown!JSONException(jv.integer); assertThrown!JSONException(jv.uinteger); assertThrown!JSONException(jv.floating); assertThrown!JSONException(jv.object); assertThrown!JSONException(jv.array); assertThrown!JSONException(jv["aa"]); assertThrown!JSONException(jv[2]); jv = -3; assert(jv.type == JSON_TYPE.INTEGER); assertNotThrown(jv.integer); jv = cast(uint)3; assert(jv.type == JSON_TYPE.UINTEGER); assertNotThrown(jv.uinteger); jv = 3.0f; assert(jv.type == JSON_TYPE.FLOAT); assertNotThrown(jv.floating); jv = ["key" : "value"]; assert(jv.type == JSON_TYPE.OBJECT); assertNotThrown(jv.object); assertNotThrown(jv["key"]); assert("key" in jv); assert("notAnElement" !in jv); assertThrown!JSONException(jv["notAnElement"]); const cjv = jv; assert("key" in cjv); assertThrown!JSONException(cjv["notAnElement"]); foreach(string key, value; jv) { static assert(is(typeof(value) == JSONValue)); assert(key == "key"); assert(value.type == JSON_TYPE.STRING); assertNotThrown(value.str); assert(value.str == "value"); } jv = [3, 4, 5]; assert(jv.type == JSON_TYPE.ARRAY); assertNotThrown(jv.array); assertNotThrown(jv[2]); foreach(size_t index, value; jv) { static assert(is(typeof(value) == JSONValue)); assert(value.type == JSON_TYPE.INTEGER); assertNotThrown(value.integer); assert(index == (value.integer-3)); } jv = null; assert(jv.type == JSON_TYPE.NULL); assert(jv.isNull); jv = "foo"; assert(!jv.isNull); jv = JSONValue("value"); assert(jv.type == JSON_TYPE.STRING); assert(jv.str == "value"); JSONValue jv2 = JSONValue("value"); assert(jv2.type == JSON_TYPE.STRING); assert(jv2.str == "value"); JSONValue jv3 = JSONValue("\u001c"); assert(jv3.type == JSON_TYPE.STRING); assert(jv3.str == "\u001C"); } unittest { // Bugzilla 11504 JSONValue jv = 1; assert(jv.type == JSON_TYPE.INTEGER); jv.str = "123"; assert(jv.type == JSON_TYPE.STRING); assert(jv.str == "123"); jv.integer = 1; assert(jv.type == JSON_TYPE.INTEGER); assert(jv.integer == 1); jv.uinteger = 2u; assert(jv.type == JSON_TYPE.UINTEGER); assert(jv.uinteger == 2u); jv.floating = 1.5f; assert(jv.type == JSON_TYPE.FLOAT); assert(jv.floating == 1.5f); jv.object = ["key" : JSONValue("value")]; assert(jv.type == JSON_TYPE.OBJECT); assert(jv.object == ["key" : JSONValue("value")]); jv.array = [JSONValue(1), JSONValue(2), JSONValue(3)]; assert(jv.type == JSON_TYPE.ARRAY); assert(jv.array == [JSONValue(1), JSONValue(2), JSONValue(3)]); jv = true; assert(jv.type == JSON_TYPE.TRUE); jv = false; assert(jv.type == JSON_TYPE.FALSE); enum E{True = true} jv = E.True; assert(jv.type == JSON_TYPE.TRUE); } pure unittest { // Adding new json element via array() / object() directly JSONValue jarr = JSONValue([10]); foreach (i; 0..9) jarr.array ~= JSONValue(i); assert(jarr.array.length == 10); JSONValue jobj = JSONValue(["key" : JSONValue("value")]); foreach (i; 0..9) jobj.object[text("key", i)] = JSONValue(text("value", i)); assert(jobj.object.length == 10); } pure unittest { // Adding new json element without array() / object() access JSONValue jarr = JSONValue([10]); foreach (i; 0..9) jarr ~= [JSONValue(i)]; assert(jarr.array.length == 10); JSONValue jobj = JSONValue(["key" : JSONValue("value")]); foreach (i; 0..9) jobj[text("key", i)] = JSONValue(text("value", i)); assert(jobj.object.length == 10); // No array alias auto jarr2 = jarr ~ [1,2,3]; jarr2[0] = 999; assert(jarr[0] == JSONValue(10)); } unittest { import std.exception; // An overly simple test suite, if it can parse a serializated string and // then use the resulting values tree to generate an identical // serialization, both the decoder and encoder works. auto jsons = [ `null`, `true`, `false`, `0`, `123`, `-4321`, `0.23`, `-0.23`, `""`, `"hello\nworld"`, `"\"\\\/\b\f\n\r\t"`, `[]`, `[12,"foo",true,false]`, `{}`, `{"a":1,"b":null}`, `{"goodbye":[true,"or",false,["test",42,{"nested":{"a":23.54,"b":0.0012}}]],"hello":{"array":[12,null,{}],"json":"is great"}}`, ]; version (MinGW) jsons ~= `1.223e+024`; else jsons ~= `1.223e+24`; JSONValue val; string result; foreach (json; jsons) { try { val = parseJSON(json); enum pretty = false; result = toJSON(&val, pretty); assert(result == json, text(result, " should be ", json)); } catch (JSONException e) { import std.stdio : writefln; writefln(text(json, "\n", e.toString())); } } // Should be able to correctly interpret unicode entities val = parseJSON(`"\u003C\u003E"`); assert(toJSON(&val) == "\"\<\>\""); assert(val.to!string() == "\"\<\>\""); val = parseJSON(`"\u0391\u0392\u0393"`); assert(toJSON(&val) == "\"\Α\Β\Γ\""); assert(val.to!string() == "\"\Α\Β\Γ\""); val = parseJSON(`"\u2660\u2666"`); assert(toJSON(&val) == "\"\♠\♦\""); assert(val.to!string() == "\"\♠\♦\""); //0x7F is a control character (see Unicode spec) val = parseJSON(`"\u007F"`); assert(toJSON(&val) == "\"\\u007F\""); assert(val.to!string() == "\"\\u007F\""); with(parseJSON(`""`)) assert(str == "" && str !is null); with(parseJSON(`[]`)) assert(!array.length && array !is null); // Formatting val = parseJSON(`{"a":[null,{"x":1},{},[]]}`); assert(toJSON(&val, true) == `{ "a": [ null, { "x": 1 }, {}, [] ] }`); } unittest { auto json = `"hello\nworld"`; const jv = parseJSON(json); assert(jv.toString == json); assert(jv.toPrettyString == json); } deprecated unittest { // Bugzilla 12332 import std.exception; JSONValue jv; jv.type = JSON_TYPE.INTEGER; jv = 1; assert(jv.type == JSON_TYPE.INTEGER); assert(jv.integer == 1); jv.type = JSON_TYPE.UINTEGER; assert(jv.uinteger == 1); jv.type = JSON_TYPE.STRING; assertThrown!JSONException(jv.integer == 1); assert(jv.str is null); jv.str = "123"; assert(jv.str == "123"); jv.type = JSON_TYPE.STRING; assert(jv.str == "123"); jv.type = JSON_TYPE.TRUE; assert(jv.type == JSON_TYPE.TRUE); } pure unittest { // Bugzilla 12969 JSONValue jv; jv["int"] = 123; assert(jv.type == JSON_TYPE.OBJECT); assert("int" in jv); assert(jv["int"].integer == 123); jv["array"] = [1, 2, 3, 4, 5]; assert(jv["array"].type == JSON_TYPE.ARRAY); assert(jv["array"][2].integer == 3); jv["str"] = "D language"; assert(jv["str"].type == JSON_TYPE.STRING); assert(jv["str"].str == "D language"); jv["bool"] = false; assert(jv["bool"].type == JSON_TYPE.FALSE); assert(jv.object.length == 4); jv = [5, 4, 3, 2, 1]; assert( jv.type == JSON_TYPE.ARRAY ); assert( jv[3].integer == 2 ); } unittest { auto s = q"EOF [ 1, 2, 3, potato ] EOF"; import std.exception; auto e = collectException!JSONException(parseJSON(s)); assert(e.msg == "Unexpected character 'p'. (Line 5:3)", e.msg); } // handling of special float values (NaN, Inf, -Inf) unittest { import std.math : isNaN, isInfinity; import std.exception : assertThrown; // expected representations of NaN and Inf enum { nanString = '"' ~ JSONFloatLiteral.nan ~ '"', infString = '"' ~ JSONFloatLiteral.inf ~ '"', negativeInfString = '"' ~ JSONFloatLiteral.negativeInf ~ '"', } // with the specialFloatLiterals option, encode NaN/Inf as strings assert(JSONValue(float.nan).toString(JSONOptions.specialFloatLiterals) == nanString); assert(JSONValue(double.infinity).toString(JSONOptions.specialFloatLiterals) == infString); assert(JSONValue(-real.infinity).toString(JSONOptions.specialFloatLiterals) == negativeInfString); // without the specialFloatLiterals option, throw on encoding NaN/Inf assertThrown!JSONException(JSONValue(float.nan).toString); assertThrown!JSONException(JSONValue(double.infinity).toString); assertThrown!JSONException(JSONValue(-real.infinity).toString); // when parsing json with specialFloatLiterals option, decode special strings as floats JSONValue jvNan = parseJSON(nanString, JSONOptions.specialFloatLiterals); JSONValue jvInf = parseJSON(infString, JSONOptions.specialFloatLiterals); JSONValue jvNegInf = parseJSON(negativeInfString, JSONOptions.specialFloatLiterals); assert(jvNan.floating.isNaN); assert(jvInf.floating.isInfinity && jvInf.floating > 0); assert(jvNegInf.floating.isInfinity && jvNegInf.floating < 0); // when parsing json without the specialFloatLiterals option, decode special strings as strings jvNan = parseJSON(nanString); jvInf = parseJSON(infString); jvNegInf = parseJSON(negativeInfString); assert(jvNan.str == JSONFloatLiteral.nan); assert(jvInf.str == JSONFloatLiteral.inf); assert(jvNegInf.str == JSONFloatLiteral.negativeInf); } pure nothrow @safe @nogc unittest { JSONValue testVal; testVal = "test"; testVal = 10; testVal = 10u; testVal = 1.0; testVal = (JSONValue[string]).init; testVal = JSONValue[].init; testVal = null; assert(testVal.isNull); } ldc-1.1.0-beta3-src/runtime/phobos/std/datetime.d0000664000175000017500000542545712776215007017675 0ustar kaikai//Written in the D programming language /++ Module containing Date/Time functionality. This module provides: $(UL $(LI Types to represent points in time: $(LREF SysTime), $(LREF Date), $(LREF TimeOfDay), and $(LREF2 .DateTime, DateTime).) $(LI Types to represent intervals of time.) $(LI Types to represent ranges over intervals of time.) $(LI Types to represent time zones (used by $(LREF SysTime)).) $(LI A platform-independent, high precision stopwatch type: $(LREF StopWatch)) $(LI Benchmarking functions.) $(LI Various helper functions.) ) Closely related to std.datetime is $(D core.time), and some of the time types used in std.datetime come from there - such as $(CXREF time, Duration), $(CXREF time, TickDuration), and $(CXREF time, FracSec). core.time is publically imported into std.datetime, it isn't necessary to import it separately. Three of the main concepts used in this module are time points, time durations, and time intervals. A time point is a specific point in time. e.g. January 5th, 2010 or 5:00. A time duration is a length of time with units. e.g. 5 days or 231 seconds. A time interval indicates a period of time associated with a fixed point in time. It is either two time points associated with each other, indicating the time starting at the first point up to, but not including, the second point - e.g. [January 5th, 2010 - March 10th, 2010$(RPAREN) - or it is a time point and a time duration associated with one another. e.g. January 5th, 2010 and 5 days, indicating [January 5th, 2010 - January 10th, 2010$(RPAREN). Various arithmetic operations are supported between time points and durations (e.g. the difference between two time points is a time duration), and ranges can be gotten from time intervals, so range-based operations may be done on a series of time points. The types that the typical user is most likely to be interested in are $(LREF Date) (if they want dates but don't care about time), $(LREF DateTime) (if they want dates and times but don't care about time zones), $(LREF SysTime) (if they want the date and time from the OS and/or do care about time zones), and StopWatch (a platform-independent, high precision stop watch). $(LREF Date) and $(LREF DateTime) are optimized for calendar-based operations, while $(LREF SysTime) is designed for dealing with time from the OS. Check out their specific documentation for more details. To get the current time, use $(LREF2 .Clock.currTime, Clock.currTime). It will return the current time as a $(LREF SysTime). To print it, $(D toString) is sufficient, but if using $(D toISOString), $(D toISOExtString), or $(D toSimpleString), use the corresponding $(D fromISOString), $(D fromISOExtString), or $(D fromSimpleString) to create a $(LREF SysTime) from the string. -------------------- auto currentTime = Clock.currTime(); auto timeString = currentTime.toISOExtString(); auto restoredTime = SysTime.fromISOExtString(timeString); -------------------- Various functions take a string (or strings) to represent a unit of time (e.g. $(D convert!("days", "hours")(numDays))). The valid strings to use with such functions are $(D "years"), $(D "months"), $(D "weeks"), $(D "days"), $(D "hours"), $(D "minutes"), $(D "seconds"), $(D "msecs") (milliseconds), $(D "usecs") (microseconds), $(D "hnsecs") (hecto-nanoseconds - i.e. 100 ns), or some subset thereof. There are a few functions in core.time which take $(D "nsecs"), but because nothing in std.datetime has precision greater than hnsecs, and very little in core.time does, no functions in std.datetime accept $(D "nsecs"). To remember which units are abbreviated and which aren't, all units seconds and greater use their full names, and all sub-second units are abbreviated (since they'd be rather long if they weren't). Note: $(LREF DateTimeException) is an alias for $(CXREF time, TimeException), so you don't need to worry about core.time functions and std.datetime functions throwing different exception types (except in the rare case that they throw something other than $(CXREF time, TimeException) or $(LREF DateTimeException)). See_Also: $(DDLINK intro-to-_datetime, Introduction to std.datetime, Introduction to std._datetime)
$(WEB en.wikipedia.org/wiki/ISO_8601, ISO 8601)
$(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ Database)
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of Time Zones)
Copyright: Copyright 2010 - 2015 License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jonathan M Davis and Kato Shoichi Source: $(PHOBOSSRC std/_datetime.d) Macros: LREF2=$(D $2) +/ module std.datetime; public import core.time; import core.exception; import core.stdc.time; import std.exception; import std.range.primitives; import std.traits; // FIXME import std.functional; //: unaryFun; version(Windows) { import core.sys.windows.windows; import core.sys.windows.winsock2; import std.windows.registry; // Uncomment and run unittests to print missing Windows TZ translations. // Please subscribe to Microsoft Daylight Saving Time & Time Zone Blog // (https://blogs.technet.microsoft.com/dst2007/) if you feel responsible // for updating the translations. // version = UpdateWindowsTZTranslations; } else version(Posix) { import core.sys.posix.stdlib; import core.sys.posix.sys.time; } version(unittest) { import std.stdio; } unittest { initializeTests(); } //Verify module example. unittest { auto currentTime = Clock.currTime(); auto timeString = currentTime.toISOExtString(); auto restoredTime = SysTime.fromISOExtString(timeString); } //Verify Examples for core.time.Duration which couldn't be in core.time. unittest { assert(std.datetime.Date(2010, 9, 7) + dur!"days"(5) == std.datetime.Date(2010, 9, 12)); assert(std.datetime.Date(2010, 9, 7) - std.datetime.Date(2010, 10, 3) == dur!"days"(-26)); } //============================================================================== // Section with public enums and constants. //============================================================================== /++ Represents the 12 months of the Gregorian year (January is 1). +/ enum Month : ubyte { jan = 1, /// feb, /// mar, /// apr, /// may, /// jun, /// jul, /// aug, /// sep, /// oct, /// nov, /// dec /// } /++ Represents the 7 days of the Gregorian week (Sunday is 0). +/ enum DayOfWeek : ubyte { sun = 0, /// mon, /// tue, /// wed, /// thu, /// fri, /// sat /// } /++ In some date calculations, adding months or years can cause the date to fall on a day of the month which is not valid (e.g. February 29th 2001 or June 31st 2000). If overflow is allowed (as is the default), then the month will be incremented accordingly (so, February 29th 2001 would become March 1st 2001, and June 31st 2000 would become July 1st 2000). If overflow is not allowed, then the day will be adjusted to the last valid day in that month (so, February 29th 2001 would become February 28th 2001 and June 31st 2000 would become June 30th 2000). AllowDayOverflow only applies to calculations involving months or years. +/ enum AllowDayOverflow { /// No, don't allow day overflow. no, /// Yes, allow day overflow. yes } /++ Indicates a direction in time. One example of its use is $(LREF2 .Interval, Interval)'s $(LREF expand, expand) function which uses it to indicate whether the interval should be expanded backwards (into the past), forwards (into the future), or both. +/ enum Direction { /// Backward. bwd, /// Forward. fwd, /// Both backward and forward. both } /++ Used to indicate whether $(D popFront) should be called immediately upon creating a range. The idea is that for some functions used to generate a range for an interval, $(D front) is not necessarily a time point which would ever be generated by the range. To get the first time point in the range to match what the function generates, then use $(D PopFirst.yes) to indicate that the range should have $(D popFront) called on it before the range is returned so that $(D front) is a time point which the function would generate. For instance, if the function used to generate a range of time points generated successive Easters (i.e. you're iterating over all of the Easters within the interval), the initial date probably isn't an Easter. Using $(D PopFirst.yes) would tell the function which returned the range that $(D popFront) was to be called so that front would then be an Easter - the next one generated by the function (which when iterating forward would be the Easter following the original $(D front), while when iterating backward, it would be the Easter prior to the original $(D front)). If $(D PopFirst.no) were used, then $(D front) would remain the original time point and it would not necessarily be a time point which would be generated by the range-generating function (which in many cases is exactly what is desired - e.g. if iterating over every day starting at the beginning of the interval). +/ enum PopFirst { /// No, don't call popFront() before returning the range. no, /// Yes, call popFront() before returning the range. yes } /++ Used by StopWatch to indicate whether it should start immediately upon construction. +/ enum AutoStart { /// No, don't start the StopWatch when it is constructed. no, /// Yes, do start the StopWatch when it is constructed. yes } /++ Array of the strings representing time units, starting with the smallest unit and going to the largest. It does not include $(D "nsecs"). Includes $(D "hnsecs") (hecto-nanoseconds (100 ns)), $(D "usecs") (microseconds), $(D "msecs") (milliseconds), $(D "seconds"), $(D "minutes"), $(D "hours"), $(D "days"), $(D "weeks"), $(D "months"), and $(D "years") +/ immutable string[] timeStrings = ["hnsecs", "usecs", "msecs", "seconds", "minutes", "hours", "days", "weeks", "months", "years"]; //============================================================================== // Section with other types. //============================================================================== /++ Exception type used by std.datetime. It's an alias to $(CXREF time, TimeException). Either can be caught without concern about which module it came from. +/ alias DateTimeException = TimeException; /++ Effectively a namespace to make it clear that the methods it contains are getting the time from the system clock. It cannot be instantiated. +/ final class Clock { public: /++ Returns the current time in the given time zone. Params: clockType = The $(CXREF time, ClockType) indicates which system clock to use to get the current time. Very few programs need to use anything other than the default. tz = The time zone for the SysTime that's returned. Throws: $(LREF DateTimeException) if it fails to get the time. +/ static SysTime currTime(ClockType clockType = ClockType.normal)(immutable TimeZone tz = LocalTime()) @safe { return SysTime(currStdTime!clockType, tz); } unittest { import std.format : format; assert(currTime().timezone is LocalTime()); assert(currTime(UTC()).timezone is UTC()); // core.stdc.time.time does not always use unix time on Windows systems. // In particular, dmc does not use unix time. If we can guarantee that // the MS runtime uses unix time, then we may be able run this test // then, but for now, we're just not going to run this test on Windows. version(Posix) { static import std.math; immutable unixTimeD = currTime().toUnixTime(); immutable unixTimeC = core.stdc.time.time(null); assert(std.math.abs(unixTimeC - unixTimeD) <= 2); } auto norm1 = Clock.currTime; auto norm2 = Clock.currTime(UTC()); assert(norm1 <= norm2, format("%s %s", norm1, norm2)); assert(abs(norm1 - norm2) <= seconds(2)); import std.meta : AliasSeq; foreach(ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second)) { scope(failure) writefln("ClockType.%s", ct); auto value1 = Clock.currTime!ct; auto value2 = Clock.currTime!ct(UTC()); assert(value1 <= value2, format("%s %s", value1, value2)); assert(abs(value1 - value2) <= seconds(2)); } } /++ Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the current time. Params: clockType = The $(CXREF time, ClockType) indicates which system clock to use to get the current time. Very few programs need to use anything other than the default. Throws: $(LREF DateTimeException) if it fails to get the time. +/ static @property long currStdTime(ClockType clockType = ClockType.normal)() @trusted { static if(clockType != ClockType.coarse && clockType != ClockType.normal && clockType != ClockType.precise && clockType != ClockType.second) { import std.format : format; static assert(0, format("ClockType.%s is not supported by Clock.currTime or Clock.currStdTime", clockType)); } version(Windows) { FILETIME fileTime; GetSystemTimeAsFileTime(&fileTime); immutable result = FILETIMEToStdTime(&fileTime); static if(clockType == ClockType.second) { // Ideally, this would use core.std.time.time, but the C runtime // has to be using unix time for that to work, and that's not // guaranteed on Windows. Digital Mars does not use unix time. // MS may or may not. If it does, then this can be made to use // core.stdc.time for MS, but for now, we'll leave it like this. return convert!("seconds", "hnsecs")(convert!("hnsecs", "seconds")(result)); } else return result; } else version(Posix) { enum hnsecsToUnixEpoch = unixTimeToStdTime(0); version(OSX) { static if(clockType == ClockType.second) return unixTimeToStdTime(core.stdc.time.time(null)); else { timeval tv; if(gettimeofday(&tv, null) != 0) throw new TimeException("Call to gettimeofday() failed"); return convert!("seconds", "hnsecs")(tv.tv_sec) + convert!("usecs", "hnsecs")(tv.tv_usec) + hnsecsToUnixEpoch; } } else version(linux) { static if(clockType == ClockType.second) return unixTimeToStdTime(core.stdc.time.time(null)); else { import core.sys.linux.time; static if(clockType == ClockType.coarse) alias clockArg = CLOCK_REALTIME_COARSE; else static if(clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME; else static if(clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME; else static assert(0, "Previous static if is wrong."); timespec ts; if(clock_gettime(clockArg, &ts) != 0) throw new TimeException("Call to clock_gettime() failed"); return convert!("seconds", "hnsecs")(ts.tv_sec) + ts.tv_nsec / 100 + hnsecsToUnixEpoch; } } else version(FreeBSD) { import core.sys.freebsd.time; static if(clockType == ClockType.coarse) alias clockArg = CLOCK_REALTIME_FAST; else static if(clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME; else static if(clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE; else static if(clockType == ClockType.second) alias clockArg = CLOCK_SECOND; else static assert(0, "Previous static if is wrong."); timespec ts; if(clock_gettime(clockArg, &ts) != 0) throw new TimeException("Call to clock_gettime() failed"); return convert!("seconds", "hnsecs")(ts.tv_sec) + ts.tv_nsec / 100 + hnsecsToUnixEpoch; } else version(NetBSD) { static if(clockType == ClockType.second) return unixTimeToStdTime(core.stdc.time.time(null)); else { timeval tv; if(gettimeofday(&tv, null) != 0) throw new TimeException("Call to gettimeofday() failed"); return convert!("seconds", "hnsecs")(tv.tv_sec) + convert!("usecs", "hnsecs")(tv.tv_usec) + hnsecsToUnixEpoch; } } else version(Solaris) { static if(clockType == ClockType.second) return unixTimeToStdTime(core.stdc.time.time(null)); else { import core.sys.solaris.time; static if(clockType == ClockType.coarse) alias clockArg = CLOCK_REALTIME; else static if(clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME; else static if(clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME; else static assert(0, "Previous static if is wrong."); timespec ts; if(clock_gettime(clockArg, &ts) != 0) throw new TimeException("Call to clock_gettime() failed"); return convert!("seconds", "hnsecs")(ts.tv_sec) + ts.tv_nsec / 100 + hnsecsToUnixEpoch; } } else static assert(0, "Unsupported OS"); } else static assert(0, "Unsupported OS"); } unittest { import std.math : abs; import std.format : format; enum limit = convert!("seconds", "hnsecs")(2); auto norm1 = Clock.currStdTime; auto norm2 = Clock.currStdTime; assert(norm1 <= norm2, format("%s %s", norm1, norm2)); assert(abs(norm1 - norm2) <= limit); import std.meta : AliasSeq; foreach(ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second)) { scope(failure) writefln("ClockType.%s", ct); auto value1 = Clock.currStdTime!ct; auto value2 = Clock.currStdTime!ct; assert(value1 <= value2, format("%s %s", value1, value2)); assert(abs(value1 - value2) <= limit); } } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime). Use $(D MonoTime.currTime) instead. currSystemTick will be removed in January 2017.) The current system tick. The number of ticks per second varies from system to system. currSystemTick uses a monotonic clock, so it's intended for precision timing by comparing relative time values, not for getting the current system time. Warning: On some systems, the monotonic clock may stop counting when the computer goes to sleep or hibernates. So, the monotonic clock could be off if that occurs. This is known to happen on Mac OS X. It has not been tested whether it occurs on either Windows or Linux. Throws: $(LREF DateTimeException) if it fails to get the time. +/ deprecated("Use core.time.MonoTime.currTime instead") static @property TickDuration currSystemTick() @safe nothrow { return TickDuration.currSystemTick; } deprecated unittest { assert(Clock.currSystemTick.length > 0); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime). To duplicate the behavior of currAppTick with $(D MonoTime), store the value of $(D MonoTime.currTime) when the program starts, and then subtract it from the current value of $(D MonoTime.currTime) in order to determine how long the program has been running. currAppTick will be removed in January 2017.) -------------------- immutable MonoTime startupTime; shared static this() { startupTime = MonoTime.currTime; } Duration timeSinceProgramStarted() { return MonoTime.currTime - startupTime; } -------------------- The current number of system ticks since the application started. The number of ticks per second varies from system to system. This uses a monotonic clock. Warning: On some systems, the monotonic clock may stop counting when the computer goes to sleep or hibernates. So, the monotonic clock could be off if that occurs. This is known to happen on Mac OS X. It has not been tested whether it occurs on either Windows or on Linux. Throws: $(LREF DateTimeException) if it fails to get the time. +/ deprecated("Use core.time.MonoTime instead. See currAppTick's documentation for details.") static @property TickDuration currAppTick() @safe { return currSystemTick - TickDuration.appOrigin; } deprecated unittest { auto a = Clock.currSystemTick; auto b = Clock.currAppTick; assert(a.length); assert(b.length); assert(a > b); } private: @disable this() {} } //============================================================================== // Section with time points. //============================================================================== /++ $(D SysTime) is the type used to get the current time from the system or doing anything that involves time zones. Unlike $(LREF DateTime), the time zone is an integral part of $(D SysTime) (though for local time applications, time zones can be ignored and it will work, since it defaults to using the local time zone). It holds its internal time in std time (hnsecs since midnight, January 1st, 1 A.D. UTC), so it interfaces well with the system time. However, that means that, unlike $(LREF DateTime), it is not optimized for calendar-based operations, and getting individual units from it such as years or days is going to involve conversions and be less efficient. For calendar-based operations that don't care about time zones, then $(LREF DateTime) would be the type to use. For system time, use $(D SysTime). $(LREF2 .Clock.currTime, Clock.currTime) will return the current time as a $(D SysTime). To convert a $(D SysTime) to a $(LREF Date) or $(LREF DateTime), simply cast it. To convert a $(LREF Date) or $(LREF DateTime) to a $(D SysTime), use $(D SysTime)'s constructor, and pass in the intended time zone with it (or don't pass in a $(LREF2 .TimeZone, TimeZone), and the local time zone will be used). Be aware, however, that converting from a $(LREF DateTime) to a $(D SysTime) will not necessarily be 100% accurate due to DST (one hour of the year doesn't exist and another occurs twice). To not risk any conversion errors, keep times as $(D SysTime)s. Aside from DST though, there shouldn't be any conversion problems. For using time zones other than local time or UTC, use $(LREF PosixTimeZone) on Posix systems (or on Windows, if providing the TZ Database files), and use $(LREF WindowsTimeZone) on Windows systems. The time in $(D SysTime) is kept internally in hnsecs from midnight, January 1st, 1 A.D. UTC. Conversion error cannot happen when changing the time zone of a $(D SysTime). $(LREF LocalTime) is the $(LREF2 .TimeZone, TimeZone) class which represents the local time, and $(D UTC) is the $(LREF2 .TimeZone, TimeZone) class which represents UTC. $(D SysTime) uses $(LREF LocalTime) if no $(LREF2 .TimeZone, TimeZone) is provided. For more details on time zones, see the documentation for $(LREF2 .TimeZone, TimeZone), $(LREF PosixTimeZone), and $(LREF WindowsTimeZone). $(D SysTime)'s range is from approximately 29,000 B.C. to approximately 29,000 A.D. +/ struct SysTime { import std.typecons : Rebindable; public: /++ Params: dateTime = The $(LREF DateTime) to use to set this $(LREF SysTime)'s internal std time. As $(LREF DateTime) has no concept of time zone, tz is used as its time zone. tz = The $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null, $(LREF LocalTime) will be used. The given $(LREF DateTime) is assumed to be in the given time zone. +/ this(in DateTime dateTime, immutable TimeZone tz = null) @safe nothrow { try this(dateTime, Duration.zero, tz); catch(Exception e) assert(0, "SysTime's constructor threw when it shouldn't have."); } unittest { import std.format : format; static void test(DateTime dt, immutable TimeZone tz, long expected) { auto sysTime = SysTime(dt, tz); assert(sysTime._stdTime == expected); assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given DateTime: %s", dt)); } test(DateTime.init, UTC(), 0); test(DateTime(1, 1, 1, 12, 30, 33), UTC(), 450_330_000_000L); test(DateTime(0, 12, 31, 12, 30, 33), UTC(), -413_670_000_000L); test(DateTime(1, 1, 1, 0, 0, 0), UTC(), 0); test(DateTime(1, 1, 1, 0, 0, 1), UTC(), 10_000_000L); test(DateTime(0, 12, 31, 23, 59, 59), UTC(), -10_000_000L); test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(-60)), 36_000_000_000L); test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(Duration.zero), 0); test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(60)), -36_000_000_000L); } /++ Params: dateTime = The $(LREF DateTime) to use to set this $(LREF SysTime)'s internal std time. As $(LREF DateTime) has no concept of time zone, tz is used as its time zone. fracSecs = The fractional seconds portion of the time. tz = The $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null, $(LREF LocalTime) will be used. The given $(LREF DateTime) is assumed to be in the given time zone. Throws: $(LREF DateTimeException) if $(D fracSecs) is negative or if it's greater than or equal to one second. +/ this(in DateTime dateTime, in Duration fracSecs, immutable TimeZone tz = null) @safe { enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds.")); enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second.")); auto nonNullTZ = tz is null ? LocalTime() : tz; immutable dateDiff = dateTime.date - Date.init; immutable todDiff = dateTime.timeOfDay - TimeOfDay.init; immutable adjustedTime = dateDiff + todDiff + fracSecs; immutable standardTime = nonNullTZ.tzToUTC(adjustedTime.total!"hnsecs"); this(standardTime, nonNullTZ); } unittest { import std.format : format; static void test(DateTime dt, Duration fracSecs, immutable TimeZone tz, long expected) { auto sysTime = SysTime(dt, fracSecs, tz); assert(sysTime._stdTime == expected); assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given DateTime: %s, Given Duration: %s", dt, fracSecs)); } test(DateTime.init, Duration.zero, UTC(), 0); test(DateTime(1, 1, 1, 12, 30, 33), Duration.zero, UTC(), 450_330_000_000L); test(DateTime(0, 12, 31, 12, 30, 33), Duration.zero, UTC(), -413_670_000_000L); test(DateTime(1, 1, 1, 0, 0, 0), msecs(1), UTC(), 10_000L); test(DateTime(0, 12, 31, 23, 59, 59), msecs(999), UTC(), -10_000L); test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC(), -1); test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC(), -9_999_999); test(DateTime(0, 12, 31, 23, 59, 59), Duration.zero, UTC(), -10_000_000); assertThrown!DateTimeException(SysTime(DateTime.init, hnsecs(-1), UTC())); assertThrown!DateTimeException(SysTime(DateTime.init, seconds(1), UTC())); } // @@@DEPRECATED_2016-08@@@ /++ $(RED Deprecated. Please use the overload which takes a $(CXREF time, Duration) for the fractional seconds. This overload will be removed in August 2016.) Params: dateTime = The $(LREF DateTime) to use to set this $(LREF SysTime)'s internal std time. As $(LREF DateTime) has no concept of time zone, tz is used as its time zone. fracSec = The fractional seconds portion of the time. tz = The $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null, $(LREF LocalTime) will be used. The given $(LREF DateTime) is assumed to be in the given time zone. Throws: $(LREF DateTimeException) if $(D fracSec) is negative. +/ deprecated("Please use the overload which takes a Duration instead of a FracSec.") this(in DateTime dateTime, in FracSec fracSec, immutable TimeZone tz = null) @safe { immutable fracHNSecs = fracSec.hnsecs; enforce(fracHNSecs >= 0, new DateTimeException("A SysTime cannot have negative fractional seconds.")); _timezone = tz is null ? LocalTime() : tz; try { immutable dateDiff = (dateTime.date - Date(1, 1, 1)).total!"hnsecs"; immutable todDiff = (dateTime.timeOfDay - TimeOfDay(0, 0, 0)).total!"hnsecs"; immutable adjustedTime = dateDiff + todDiff + fracHNSecs; immutable standardTime = _timezone.tzToUTC(adjustedTime); this(standardTime, _timezone); } catch(Exception e) assert(0, "Date, TimeOfDay, or DateTime's constructor threw when it shouldn't have."); } deprecated unittest { import std.format : format; static void test(DateTime dt, FracSec fracSec, immutable TimeZone tz, long expected) { auto sysTime = SysTime(dt, fracSec, tz); assert(sysTime._stdTime == expected); assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given DateTime: %s, Given FracSec: %s", dt, fracSec)); } test(DateTime.init, FracSec.init, UTC(), 0); test(DateTime(1, 1, 1, 12, 30, 33), FracSec.init, UTC(), 450_330_000_000L); test(DateTime(0, 12, 31, 12, 30, 33), FracSec.init, UTC(), -413_670_000_000L); test(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(1), UTC(), 10_000L); test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"msecs"(999), UTC(), -10_000L); test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999), UTC(), -1); test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1), UTC(), -9_999_999); test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0), UTC(), -10_000_000); assertThrown!DateTimeException(SysTime(DateTime.init, FracSec.from!"hnsecs"(-1), UTC())); } /++ Params: date = The $(LREF Date) to use to set this $(LREF SysTime)'s internal std time. As $(LREF Date) has no concept of time zone, tz is used as its time zone. tz = The $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null, $(LREF LocalTime) will be used. The given $(LREF Date) is assumed to be in the given time zone. +/ this(in Date date, immutable TimeZone tz = null) @safe nothrow { _timezone = tz is null ? LocalTime() : tz; try { immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs"; immutable standardTime = _timezone.tzToUTC(adjustedTime); this(standardTime, _timezone); } catch(Exception e) assert(0, "Date's constructor through when it shouldn't have."); } unittest { static void test(Date d, immutable TimeZone tz, long expected) { import std.format : format; auto sysTime = SysTime(d, tz); assert(sysTime._stdTime == expected); assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given Date: %s", d)); } test(Date.init, UTC(), 0); test(Date(1, 1, 1), UTC(), 0); test(Date(1, 1, 2), UTC(), 864000000000); test(Date(0, 12, 31), UTC(), -864000000000); } /++ Note: Whereas the other constructors take in the given date/time, assume that it's in the given time zone, and convert it to hnsecs in UTC since midnight, January 1st, 1 A.D. UTC - i.e. std time - this constructor takes a std time, which is specifically already in UTC, so no conversion takes place. Of course, the various getter properties and functions will use the given time zone's conversion function to convert the results to that time zone, but no conversion of the arguments to this constructor takes place. Params: stdTime = The number of hnsecs since midnight, January 1st, 1 A.D. UTC. tz = The $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null, $(LREF LocalTime) will be used. +/ this(long stdTime, immutable TimeZone tz = null) @safe pure nothrow { _stdTime = stdTime; _timezone = tz is null ? LocalTime() : tz; } unittest { static void test(long stdTime, immutable TimeZone tz) { import std.format : format; auto sysTime = SysTime(stdTime, tz); assert(sysTime._stdTime == stdTime); assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given stdTime: %s", stdTime)); } foreach(stdTime; [-1234567890L, -250, 0, 250, 1235657390L]) { foreach(tz; testTZs) test(stdTime, tz); } } /++ Params: rhs = The $(LREF SysTime) to assign to this one. +/ ref SysTime opAssign(const ref SysTime rhs) return @safe pure nothrow { _stdTime = rhs._stdTime; _timezone = rhs._timezone; return this; } /++ Params: rhs = The $(LREF SysTime) to assign to this one. +/ ref SysTime opAssign(SysTime rhs) return @safe pure nothrow { _stdTime = rhs._stdTime; _timezone = rhs._timezone; return this; } /++ Checks for equality between this $(LREF SysTime) and the given $(LREF SysTime). Note that the time zone is ignored. Only the internal std times (which are in UTC) are compared. +/ bool opEquals(const SysTime rhs) @safe const pure nothrow { return opEquals(rhs); } /// ditto bool opEquals(const ref SysTime rhs) @safe const pure nothrow { return _stdTime == rhs._stdTime; } unittest { import std.range; assert(SysTime(DateTime.init, UTC()) == SysTime(0, UTC())); assert(SysTime(DateTime.init, UTC()) == SysTime(0)); assert(SysTime(Date.init, UTC()) == SysTime(0)); assert(SysTime(0) == SysTime(0)); static void test(DateTime dt, immutable TimeZone tz1, immutable TimeZone tz2) { auto st1 = SysTime(dt); st1.timezone = tz1; auto st2 = SysTime(dt); st2.timezone = tz2; assert(st1 == st2); } foreach(tz1; testTZs) { foreach(tz2; testTZs) { foreach(dt; chain(testDateTimesBC, testDateTimesAD)) test(dt, tz1, tz2); } } auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30)); const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30)); assert(st == st); assert(st == cst); //assert(st == ist); assert(cst == st); assert(cst == cst); //assert(cst == ist); //assert(ist == st); //assert(ist == cst); //assert(ist == ist); } /++ Compares this $(LREF SysTime) with the given $(LREF SysTime). Time zone is irrelevant when comparing $(LREF SysTime)s. Returns: $(BOOKTABLE, $(TR $(TD this < rhs) $(TD < 0)) $(TR $(TD this == rhs) $(TD 0)) $(TR $(TD this > rhs) $(TD > 0)) ) +/ int opCmp(in SysTime rhs) @safe const pure nothrow { if(_stdTime < rhs._stdTime) return -1; if(_stdTime > rhs._stdTime) return 1; return 0; } unittest { import std.range; assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0, UTC())) == 0); assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0)) == 0); assert(SysTime(Date.init, UTC()).opCmp(SysTime(0)) == 0); assert(SysTime(0).opCmp(SysTime(0)) == 0); static void testEqual(SysTime st, immutable TimeZone tz1, immutable TimeZone tz2) { auto st1 = st; st1.timezone = tz1; auto st2 = st; st2.timezone = tz2; assert(st1.opCmp(st2) == 0); } auto sts = array(map!SysTime(chain(testDateTimesBC, testDateTimesAD))); foreach(st; sts) foreach(tz1; testTZs) foreach(tz2; testTZs) testEqual(st, tz1, tz2); static void testCmp(SysTime st1, immutable TimeZone tz1, SysTime st2, immutable TimeZone tz2) { st1.timezone = tz1; st2.timezone = tz2; assert(st1.opCmp(st2) < 0); assert(st2.opCmp(st1) > 0); } foreach(si, st1; sts) foreach(st2; sts[si+1 .. $]) foreach(tz1; testTZs) foreach(tz2; testTZs) testCmp(st1, tz1, st2, tz2); auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30)); const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30)); assert(st.opCmp(st) == 0); assert(st.opCmp(cst) == 0); //assert(st.opCmp(ist) == 0); assert(cst.opCmp(st) == 0); assert(cst.opCmp(cst) == 0); //assert(cst.opCmp(ist) == 0); //assert(ist.opCmp(st) == 0); //assert(ist.opCmp(cst) == 0); //assert(ist.opCmp(ist) == 0); } /++ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C. +/ @property short year() @safe const nothrow { return (cast(Date)this).year; } unittest { import std.range; static void test(SysTime sysTime, long expected) { import std.format : format; assert(sysTime.year == expected, format("Value given: %s", sysTime)); } test(SysTime(0, UTC()), 1); test(SysTime(1, UTC()), 1); test(SysTime(-1, UTC()), 0); foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) { foreach(tod; testTODs) { auto dt = DateTime(Date(year, md.month, md.day), tod); foreach(tz; testTZs) { foreach(fs; testFracSecs) test(SysTime(dt, fs, tz), year); } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.year == 1999); //assert(ist.year == 1999); } /++ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C. Params: year = The year to set this $(LREF SysTime)'s year to. Throws: $(LREF DateTimeException) if the new year is not a leap year and the resulting date would be on February 29th. +/ @property void year(int year) @safe { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } auto date = Date(cast(int)days); date.year = year; immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1); adjTime = newDaysHNSecs + hnsecs; } /// unittest { assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999); assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010); assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7); } unittest { import std.range; static void test(SysTime st, int year, in SysTime expected) { st.year = year; assert(st == expected); } foreach(st; chain(testSysTimesBC, testSysTimesAD)) { auto dt = cast(DateTime)st; foreach(year; chain(testYearsBC, testYearsAD)) { auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second), st.fracSecs, st.timezone); test(st, year, e); } } foreach(fs; testFracSecs) { foreach(tz; testTZs) { foreach(tod; testTODs) { test(SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz), 2000, SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz)); test(SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz), 1999, SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz)); } foreach(tod; testTODsThrown) { auto st = SysTime(DateTime(Date(2000, 2, 29), tod), fs, tz); assertThrown!DateTimeException(st.year = 1999); } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.year = 7)); //static assert(!__traits(compiles, ist.year = 7)); } /++ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. Throws: $(LREF DateTimeException) if $(D isAD) is true. +/ @property ushort yearBC() @safe const { return (cast(Date)this).yearBC; } /// unittest { assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1); assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2); assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101); } unittest { import std.format : format; foreach(st; testSysTimesBC) { auto msg = format("SysTime: %s", st); assertNotThrown!DateTimeException(st.yearBC, msg); assert(st.yearBC == (st.year * -1) + 1, msg); } foreach(st; [testSysTimesAD[0], testSysTimesAD[$/2], testSysTimesAD[$-1]]) assertThrown!DateTimeException(st.yearBC, format("SysTime: %s", st)); auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); st.year = 12; assert(st.year == 12); static assert(!__traits(compiles, cst.year = 12)); //static assert(!__traits(compiles, ist.year = 12)); } /++ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. Params: year = The year B.C. to set this $(LREF SysTime)'s year to. Throws: $(LREF DateTimeException) if a non-positive value is given. +/ @property void yearBC(int year) @safe { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } auto date = Date(cast(int)days); date.yearBC = year; immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1); adjTime = newDaysHNSecs + hnsecs; } unittest { auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0)); st.yearBC = 1; assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0))); st.yearBC = 10; assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0))); } unittest { import std.range; static void test(SysTime st, int year, in SysTime expected) { import std.format : format; st.yearBC = year; assert(st == expected, format("SysTime: %s", st)); } foreach(st; chain(testSysTimesBC, testSysTimesAD)) { auto dt = cast(DateTime)st; foreach(year; testYearsBC) { auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second), st.fracSecs, st.timezone); test(st, (year * -1) + 1, e); } } foreach(st; [testSysTimesBC[0], testSysTimesBC[$ - 1], testSysTimesAD[0], testSysTimesAD[$ - 1]]) { foreach(year; testYearsBC) assertThrown!DateTimeException(st.yearBC = year); } foreach(fs; testFracSecs) { foreach(tz; testTZs) { foreach(tod; testTODs) { test(SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz), 2001, SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz)); test(SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz), 2000, SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz)); } foreach(tod; testTODsThrown) { auto st = SysTime(DateTime(Date(-2000, 2, 29), tod), fs, tz); assertThrown!DateTimeException(st.year = -1999); } } } auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); st.yearBC = 12; assert(st.yearBC == 12); static assert(!__traits(compiles, cst.yearBC = 12)); //static assert(!__traits(compiles, ist.yearBC = 12)); } /++ Month of a Gregorian Year. +/ @property Month month() @safe const nothrow { return (cast(Date)this).month; } /// unittest { assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7); assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10); assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4); } unittest { import std.range; static void test(SysTime sysTime, Month expected) { import std.format : format; assert(sysTime.month == expected, format("Value given: %s", sysTime)); } test(SysTime(0, UTC()), Month.jan); test(SysTime(1, UTC()), Month.jan); test(SysTime(-1, UTC()), Month.dec); foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) { foreach(tod; testTODs) { auto dt = DateTime(Date(year, md.month, md.day), tod); foreach(fs; testFracSecs) { foreach(tz; testTZs) test(SysTime(dt, fs, tz), md.month); } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.month == 7); //assert(ist.month == 7); } /++ Month of a Gregorian Year. Params: month = The month to set this $(LREF SysTime)'s month to. Throws: $(LREF DateTimeException) if the given month is not a valid month. +/ @property void month(Month month) @safe { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } auto date = Date(cast(int)days); date.month = month; immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1); adjTime = newDaysHNSecs + hnsecs; } unittest { import std.range; static void test(SysTime st, Month month, in SysTime expected) { st.month = cast(Month)month; assert(st == expected); } foreach(st; chain(testSysTimesBC, testSysTimesAD)) { auto dt = cast(DateTime)st; foreach(md; testMonthDays) { if(st.day > maxDay(dt.year, md.month)) continue; auto e = SysTime(DateTime(dt.year, md.month, dt.day, dt.hour, dt.minute, dt.second), st.fracSecs, st.timezone); test(st, md.month, e); } } foreach(fs; testFracSecs) { foreach(tz; testTZs) { foreach(tod; testTODs) { foreach(year; filter!((a){return yearIsLeapYear(a);}) (chain(testYearsBC, testYearsAD))) { test(SysTime(DateTime(Date(year, 1, 29), tod), fs, tz), Month.feb, SysTime(DateTime(Date(year, 2, 29), tod), fs, tz)); } foreach(year; chain(testYearsBC, testYearsAD)) { test(SysTime(DateTime(Date(year, 1, 28), tod), fs, tz), Month.feb, SysTime(DateTime(Date(year, 2, 28), tod), fs, tz)); test(SysTime(DateTime(Date(year, 7, 30), tod), fs, tz), Month.jun, SysTime(DateTime(Date(year, 6, 30), tod), fs, tz)); } } } } foreach(fs; [testFracSecs[0], testFracSecs[$-1]]) { foreach(tz; testTZs) { foreach(tod; testTODsThrown) { foreach(year; [testYearsBC[$-3], testYearsBC[$-2], testYearsBC[$-2], testYearsAD[0], testYearsAD[$-2], testYearsAD[$-1]]) { auto day = yearIsLeapYear(year) ? 30 : 29; auto st1 = SysTime(DateTime(Date(year, 1, day), tod), fs, tz); assertThrown!DateTimeException(st1.month = Month.feb); auto st2 = SysTime(DateTime(Date(year, 7, 31), tod), fs, tz); assertThrown!DateTimeException(st2.month = Month.jun); } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.month = 12)); //static assert(!__traits(compiles, ist.month = 12)); } /++ Day of a Gregorian Month. +/ @property ubyte day() @safe const nothrow { return (cast(Date)this).day; } /// unittest { assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6); assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4); assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5); } unittest { import std.range; static void test(SysTime sysTime, int expected) { import std.format : format; assert(sysTime.day == expected, format("Value given: %s", sysTime)); } test(SysTime(0, UTC()), 1); test(SysTime(1, UTC()), 1); test(SysTime(-1, UTC()), 31); foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) { foreach(tod; testTODs) { auto dt = DateTime(Date(year, md.month, md.day), tod); foreach(tz; testTZs) { foreach(fs; testFracSecs) test(SysTime(dt, fs, tz), md.day); } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.day == 6); //assert(ist.day == 6); } /++ Day of a Gregorian Month. Params: day = The day of the month to set this $(LREF SysTime)'s day to. Throws: $(LREF DateTimeException) if the given day is not a valid day of the current month. +/ @property void day(int day) @safe { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } auto date = Date(cast(int)days); date.day = day; immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1); adjTime = newDaysHNSecs + hnsecs; } unittest { import std.format : format; import std.range; foreach(day; chain(testDays)) { foreach(st; chain(testSysTimesBC, testSysTimesAD)) { auto dt = cast(DateTime)st; if(day > maxDay(dt.year, dt.month)) continue; auto expected = SysTime(DateTime(dt.year, dt.month, day, dt.hour, dt.minute, dt.second), st.fracSecs, st.timezone); st.day = day; assert(st == expected, format("[%s] [%s]", st, expected)); } } foreach(tz; testTZs) { foreach(tod; testTODs) { foreach(fs; testFracSecs) { foreach(year; chain(testYearsBC, testYearsAD)) { foreach(month; EnumMembers!Month) { auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz); immutable max = maxDay(year, month); auto expected = SysTime(DateTime(Date(year, month, max), tod), fs, tz); st.day = max; assert(st == expected, format("[%s] [%s]", st, expected)); } } } } } foreach(tz; testTZs) { foreach(tod; testTODsThrown) { foreach(fs; [testFracSecs[0], testFracSecs[$-1]]) { foreach(year; [testYearsBC[$-3], testYearsBC[$-2], testYearsBC[$-2], testYearsAD[0], testYearsAD[$-2], testYearsAD[$-1]]) { foreach(month; EnumMembers!Month) { auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz); immutable max = maxDay(year, month); assertThrown!DateTimeException(st.day = max + 1); } } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.day = 27)); //static assert(!__traits(compiles, ist.day = 27)); } /++ Hours past midnight. +/ @property ubyte hour() @safe const nothrow { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } return cast(ubyte)getUnitsFromHNSecs!"hours"(hnsecs); } unittest { import std.range; import std.format : format; static void test(SysTime sysTime, int expected) { assert(sysTime.hour == expected, format("Value given: %s", sysTime)); } test(SysTime(0, UTC()), 0); test(SysTime(1, UTC()), 0); test(SysTime(-1, UTC()), 23); foreach(tz; testTZs) { foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) { foreach(hour; testHours) { foreach(minute; testMinSecs) { foreach(second; testMinSecs) { auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second)); foreach(fs; testFracSecs) test(SysTime(dt, fs, tz), hour); } } } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.hour == 12); //assert(ist.hour == 12); } /++ Hours past midnight. Params: hour = The hours to set this $(LREF SysTime)'s hour to. Throws: $(LREF DateTimeException) if the given hour are not a valid hour of the day. +/ @property void hour(int hour) @safe { enforceValid!"hours"(hour); auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs); immutable daysHNSecs = convert!("days", "hnsecs")(days); immutable negative = hnsecs < 0; if(negative) hnsecs += convert!("hours", "hnsecs")(24); hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs); hnsecs += convert!("hours", "hnsecs")(hour); if(negative) hnsecs -= convert!("hours", "hnsecs")(24); adjTime = daysHNSecs + hnsecs; } unittest { import std.range; import std.format : format; foreach(hour; chain(testHours)) { foreach(st; chain(testSysTimesBC, testSysTimesAD)) { auto dt = cast(DateTime)st; auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, hour, dt.minute, dt.second), st.fracSecs, st.timezone); st.hour = hour; assert(st == expected, format("[%s] [%s]", st, expected)); } } auto st = testSysTimesAD[0]; assertThrown!DateTimeException(st.hour = -1); assertThrown!DateTimeException(st.hour = 60); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.hour = 27)); //static assert(!__traits(compiles, ist.hour = 27)); } /++ Minutes past the current hour. +/ @property ubyte minute() @safe const nothrow { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs); return cast(ubyte)getUnitsFromHNSecs!"minutes"(hnsecs); } unittest { import std.range; import std.format : format; static void test(SysTime sysTime, int expected) { assert(sysTime.minute == expected, format("Value given: %s", sysTime)); } test(SysTime(0, UTC()), 0); test(SysTime(1, UTC()), 0); test(SysTime(-1, UTC()), 59); foreach(tz; testTZs) { foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) { foreach(hour; testHours) { foreach(minute; testMinSecs) { foreach(second; testMinSecs) { auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second)); foreach(fs; testFracSecs) test(SysTime(dt, fs, tz), minute); } } } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.minute == 30); //assert(ist.minute == 30); } /++ Minutes past the current hour. Params: minute = The minute to set this $(LREF SysTime)'s minute to. Throws: $(LREF DateTimeException) if the given minute are not a valid minute of an hour. +/ @property void minute(int minute) @safe { enforceValid!"minutes"(minute); auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs); immutable daysHNSecs = convert!("days", "hnsecs")(days); immutable negative = hnsecs < 0; if(negative) hnsecs += convert!("hours", "hnsecs")(24); immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs); hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs); hnsecs += convert!("hours", "hnsecs")(hour); hnsecs += convert!("minutes", "hnsecs")(minute); if(negative) hnsecs -= convert!("hours", "hnsecs")(24); adjTime = daysHNSecs + hnsecs; } unittest { import std.range; import std.format : format; foreach(minute; testMinSecs) { foreach(st; chain(testSysTimesBC, testSysTimesAD)) { auto dt = cast(DateTime)st; auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, minute, dt.second), st.fracSecs, st.timezone); st.minute = minute; assert(st == expected, format("[%s] [%s]", st, expected)); } } auto st = testSysTimesAD[0]; assertThrown!DateTimeException(st.minute = -1); assertThrown!DateTimeException(st.minute = 60); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.minute = 27)); //static assert(!__traits(compiles, ist.minute = 27)); } /++ Seconds past the current minute. +/ @property ubyte second() @safe const nothrow { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs); hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs); return cast(ubyte)getUnitsFromHNSecs!"seconds"(hnsecs); } unittest { import std.range; import std.format : format; static void test(SysTime sysTime, int expected) { assert(sysTime.second == expected, format("Value given: %s", sysTime)); } test(SysTime(0, UTC()), 0); test(SysTime(1, UTC()), 0); test(SysTime(-1, UTC()), 59); foreach(tz; testTZs) { foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) { foreach(hour; testHours) { foreach(minute; testMinSecs) { foreach(second; testMinSecs) { auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second)); foreach(fs; testFracSecs) test(SysTime(dt, fs, tz), second); } } } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.second == 33); //assert(ist.second == 33); } /++ Seconds past the current minute. Params: second = The second to set this $(LREF SysTime)'s second to. Throws: $(LREF DateTimeException) if the given second are not a valid second of a minute. +/ @property void second(int second) @safe { enforceValid!"seconds"(second); auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs); immutable daysHNSecs = convert!("days", "hnsecs")(days); immutable negative = hnsecs < 0; if(negative) hnsecs += convert!("hours", "hnsecs")(24); immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs); immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs); hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs); hnsecs += convert!("hours", "hnsecs")(hour); hnsecs += convert!("minutes", "hnsecs")(minute); hnsecs += convert!("seconds", "hnsecs")(second); if(negative) hnsecs -= convert!("hours", "hnsecs")(24); adjTime = daysHNSecs + hnsecs; } unittest { import std.range; import std.format : format; foreach(second; testMinSecs) { foreach(st; chain(testSysTimesBC, testSysTimesAD)) { auto dt = cast(DateTime)st; auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, second), st.fracSecs, st.timezone); st.second = second; assert(st == expected, format("[%s] [%s]", st, expected)); } } auto st = testSysTimesAD[0]; assertThrown!DateTimeException(st.second = -1); assertThrown!DateTimeException(st.second = 60); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.seconds = 27)); //static assert(!__traits(compiles, ist.seconds = 27)); } /++ Fractional seconds past the second (i.e. the portion of a $(LREF SysTime) which is less than a second). +/ @property Duration fracSecs() @safe const nothrow { auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime); if(hnsecs < 0) hnsecs += convert!("hours", "hnsecs")(24); return dur!"hnsecs"(removeUnitsFromHNSecs!"seconds"(hnsecs)); } /// unittest { auto dt = DateTime(1982, 4, 1, 20, 59, 22); assert(SysTime(dt, msecs(213)).fracSecs == msecs(213)); assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202)); assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567)); // SysTime and Duration both have a precision of hnsecs (100 ns), // so nsecs are going to be truncated. assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700)); } unittest { import std.range; assert(SysTime(0, UTC()).fracSecs == Duration.zero); assert(SysTime(1, UTC()).fracSecs == hnsecs(1)); assert(SysTime(-1, UTC()).fracSecs == hnsecs(9_999_999)); foreach(tz; testTZs) { foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) { foreach(hour; testHours) { foreach(minute; testMinSecs) { foreach(second; testMinSecs) { auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second)); foreach(fs; testFracSecs) assert(SysTime(dt, fs, tz).fracSecs == fs); } } } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.fracSecs == Duration.zero); //assert(ist.fracSecs == Duration.zero); } /++ Fractional seconds past the second (i.e. the portion of a $(LREF SysTime) which is less than a second). Params: fracSecs = The duration to set this $(LREF SysTime)'s fractional seconds to. Throws: $(LREF DateTimeException) if the given duration is negative or if it's greater than or equal to one second. +/ @property void fracSecs(Duration fracSecs) @safe { enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds.")); enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second.")); auto oldHNSecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(oldHNSecs); immutable daysHNSecs = convert!("days", "hnsecs")(days); immutable negative = oldHNSecs < 0; if(negative) oldHNSecs += convert!("hours", "hnsecs")(24); immutable seconds = splitUnitsFromHNSecs!"seconds"(oldHNSecs); immutable secondsHNSecs = convert!("seconds", "hnsecs")(seconds); auto newHNSecs = fracSecs.total!"hnsecs" + secondsHNSecs; if(negative) newHNSecs -= convert!("hours", "hnsecs")(24); adjTime = daysHNSecs + newHNSecs; } /// unittest { auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22)); assert(st.fracSecs == Duration.zero); st.fracSecs = msecs(213); assert(st.fracSecs == msecs(213)); st.fracSecs = hnsecs(1234567); assert(st.fracSecs == hnsecs(1234567)); // SysTime has a precision of hnsecs (100 ns), so nsecs are // going to be truncated. st.fracSecs = nsecs(123456789); assert(st.fracSecs == hnsecs(1234567)); } unittest { import std.range; import std.format : format; foreach(fracSec; testFracSecs) { foreach(st; chain(testSysTimesBC, testSysTimesAD)) { auto dt = cast(DateTime)st; auto expected = SysTime(dt, fracSec, st.timezone); st.fracSecs = fracSec; assert(st == expected, format("[%s] [%s]", st, expected)); } } auto st = testSysTimesAD[0]; assertThrown!DateTimeException(st.fracSecs = hnsecs(-1)); assertThrown!DateTimeException(st.fracSecs = seconds(1)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.fracSecs = msecs(7))); //static assert(!__traits(compiles, ist.fracSecs = msecs(7))); } // @@@DEPRECATED_2016-08@@@ /++ $(RED Deprecated. Please use $(LREF fracSecs) instead of fracSec. It uses a $(CXREF time, Duration) to represent the fractional seconds instead of a $(CXREF time, FracSec). This overload will be removed in August 2016.) Fractional seconds past the second. +/ deprecated("Please use fracSecs (with an s) rather than fracSec (without an s). It returns a Duration instead of a FracSec, as FracSec is being deprecated.") @property FracSec fracSec() @safe const nothrow { try { auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime); if(hnsecs < 0) hnsecs += convert!("hours", "hnsecs")(24); hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs); return FracSec.from!"hnsecs"(cast(int)hnsecs); } catch(Exception e) assert(0, "FracSec.from!\"hnsecs\"() threw."); } deprecated unittest { import std.range; import std.format : format; static void test(SysTime sysTime, FracSec expected, size_t line = __LINE__) { if(sysTime.fracSec != expected) throw new AssertError(format("Value given: %s", sysTime.fracSec), __FILE__, line); } test(SysTime(0, UTC()), FracSec.from!"hnsecs"(0)); test(SysTime(1, UTC()), FracSec.from!"hnsecs"(1)); test(SysTime(-1, UTC()), FracSec.from!"hnsecs"(9_999_999)); foreach(tz; testTZs) { foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) { foreach(hour; testHours) { foreach(minute; testMinSecs) { foreach(second; testMinSecs) { auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second)); foreach(fs; testFracSecs) test(SysTime(dt, fs, tz), FracSec.from!"hnsecs"(fs.total!"hnsecs")); } } } } } } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.fracSec == FracSec.zero); //assert(ist.fracSec == FracSec.zero); } // @@@DEPRECATED_2016-08@@@ /++ $(RED Deprecated. Please use $(LREF fracSecs) instead of fracSec. It uses a $(CXREF time, Duration) to represent the fractional seconds instead of a $(CXREF time, FracSec). This overload will be removed in August 2016.) Fractional seconds past the second. Params: fracSec = The fractional seconds to set this $(LREF SysTime)'s fractional seconds to. Throws: $(LREF DateTimeException) if $(D fracSec) is negative. +/ deprecated("Please use fracSecs (with an s) rather than fracSec (without an s). It takes a Duration instead of a FracSec, as FracSec is being deprecated.") @property void fracSec(FracSec fracSec) @safe { immutable fracHNSecs = fracSec.hnsecs; enforce(fracHNSecs >= 0, new DateTimeException("A SysTime cannot have negative fractional seconds.")); auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs); immutable daysHNSecs = convert!("days", "hnsecs")(days); immutable negative = hnsecs < 0; if(negative) hnsecs += convert!("hours", "hnsecs")(24); immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs); immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs); immutable second = getUnitsFromHNSecs!"seconds"(hnsecs); hnsecs = fracHNSecs; hnsecs += convert!("hours", "hnsecs")(hour); hnsecs += convert!("minutes", "hnsecs")(minute); hnsecs += convert!("seconds", "hnsecs")(second); if(negative) hnsecs -= convert!("hours", "hnsecs")(24); adjTime = daysHNSecs + hnsecs; } deprecated unittest { import std.range; import std.format : format; foreach(fracSec; testFracSecs) { foreach(st; chain(testSysTimesBC, testSysTimesAD)) { auto dt = cast(DateTime)st; auto expected = SysTime(dt, fracSec, st.timezone); st.fracSec = FracSec.from!"hnsecs"(fracSec.total!"hnsecs"); assert(st == expected, format("[%s] [%s]", st, expected)); } } auto st = testSysTimesAD[0]; assertThrown!DateTimeException(st.fracSec = FracSec.from!"hnsecs"(-1)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.fracSec = FracSec.from!"msecs"(7))); //static assert(!__traits(compiles, ist.fracSec = FracSec.from!"msecs"(7))); } /++ The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the internal representation of $(LREF SysTime). +/ @property long stdTime() @safe const pure nothrow { return _stdTime; } unittest { assert(SysTime(0).stdTime == 0); assert(SysTime(1).stdTime == 1); assert(SysTime(-1).stdTime == -1); assert(SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()).stdTime == 330_000_502L); assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()).stdTime == 621_355_968_000_000_000L); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.stdTime > 0); //assert(ist.stdTime > 0); } /++ The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the internal representation of $(LREF SysTime). Params: stdTime = The number of hnsecs since January 1st, 1 A.D. UTC. +/ @property void stdTime(long stdTime) @safe pure nothrow { _stdTime = stdTime; } unittest { static void test(long stdTime, in SysTime expected, size_t line = __LINE__) { auto st = SysTime(0, UTC()); st.stdTime = stdTime; assert(st == expected); } test(0, SysTime(Date(1, 1, 1), UTC())); test(1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC())); test(-1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC())); test(330_000_502L, SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC())); test(621_355_968_000_000_000L, SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC())); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.stdTime = 27)); //static assert(!__traits(compiles, ist.stdTime = 27)); } /++ The current time zone of this $(LREF SysTime). Its internal time is always kept in UTC, so there are no conversion issues between time zones due to DST. Functions which return all or part of the time - such as hours - adjust the time to this $(LREF SysTime)'s time zone before returning. +/ @property immutable(TimeZone) timezone() @safe const pure nothrow { return _timezone; } /++ The current time zone of this $(LREF SysTime). It's internal time is always kept in UTC, so there are no conversion issues between time zones due to DST. Functions which return all or part of the time - such as hours - adjust the time to this $(LREF SysTime)'s time zone before returning. Params: timezone = The $(LREF2 .TimeZone, TimeZone) to set this $(LREF SysTime)'s time zone to. +/ @property void timezone(immutable TimeZone timezone) @safe pure nothrow { if(timezone is null) _timezone = LocalTime(); else _timezone = timezone; } /++ Returns whether DST is in effect for this $(LREF SysTime). +/ @property bool dstInEffect() @safe const nothrow { return _timezone.dstInEffect(_stdTime); //This function's unit testing is done in the time zone classes. } /++ Returns what the offset from UTC is for this $(LREF SysTime). It includes the DST offset in effect at that time (if any). +/ @property Duration utcOffset() @safe const nothrow { return _timezone.utcOffsetAt(_stdTime); } /++ Returns a $(LREF SysTime) with the same std time as this one, but with $(LREF LocalTime) as its time zone. +/ SysTime toLocalTime() @safe const pure nothrow { return SysTime(_stdTime, LocalTime()); } unittest { { auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27)); assert(sysTime == sysTime.toLocalTime()); assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime); assert(sysTime.toLocalTime().timezone is LocalTime()); assert(sysTime.toLocalTime().timezone is sysTime.timezone); assert(sysTime.toLocalTime().timezone !is UTC()); } { auto stz = new immutable SimpleTimeZone(dur!"minutes"(-3 * 60)); auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27), stz); assert(sysTime == sysTime.toLocalTime()); assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime); assert(sysTime.toLocalTime().timezone is LocalTime()); assert(sysTime.toLocalTime().timezone !is UTC()); assert(sysTime.toLocalTime().timezone !is stz); } } /++ Returns a $(LREF SysTime) with the same std time as this one, but with $(D UTC) as its time zone. +/ SysTime toUTC() @safe const pure nothrow { return SysTime(_stdTime, UTC()); } unittest { auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27)); assert(sysTime == sysTime.toUTC()); assert(sysTime._stdTime == sysTime.toUTC()._stdTime); assert(sysTime.toUTC().timezone is UTC()); assert(sysTime.toUTC().timezone !is LocalTime()); assert(sysTime.toUTC().timezone !is sysTime.timezone); } /++ Returns a $(LREF SysTime) with the same std time as this one, but with given time zone as its time zone. +/ SysTime toOtherTZ(immutable TimeZone tz) @safe const pure nothrow { if(tz is null) return SysTime(_stdTime, LocalTime()); else return SysTime(_stdTime, tz); } unittest { auto stz = new immutable SimpleTimeZone(dur!"minutes"(11 * 60)); auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27)); assert(sysTime == sysTime.toOtherTZ(stz)); assert(sysTime._stdTime == sysTime.toOtherTZ(stz)._stdTime); assert(sysTime.toOtherTZ(stz).timezone is stz); assert(sysTime.toOtherTZ(stz).timezone !is LocalTime()); assert(sysTime.toOtherTZ(stz).timezone !is UTC()); } /++ Converts this $(LREF SysTime) to unix time (i.e. seconds from midnight, January 1st, 1970 in UTC). The C standard does not specify the representation of time_t, so it is implementation defined. On POSIX systems, unix time is equivalent to time_t, but that's not necessarily true on other systems (e.g. it is not true for the Digital Mars C runtime). So, be careful when using unix time with C functions on non-POSIX systems. By default, the return type is time_t (which is normally an alias for int on 32-bit systems and long on 64-bit systems), but if a different size is required than either int or long can be passed as a template argument to get the desired size. If the return type is int, and the result can't fit in an int, then the closest value that can be held in 32 bits will be used (so $(D int.max) if it goes over and $(D int.min) if it goes under). However, no attempt is made to deal with integer overflow if the return type is long. Params: T = The return type (int or long). It defaults to time_t, which is normally 32 bits on a 32-bit system and 64 bits on a 64-bit system. Returns: A signed integer representing the unix time which is equivalent to this SysTime. +/ T toUnixTime(T = time_t)() @safe const pure nothrow if(is(T == int) || is(T == long)) { return stdTimeToUnixTime!T(_stdTime); } /// unittest { assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0); auto pst = new immutable SimpleTimeZone(hours(-8)); assert(SysTime(DateTime(1970, 1, 1), pst).toUnixTime() == 28800); auto utc = SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()); assert(utc.toUnixTime() == 1_198_311_285); auto ca = SysTime(DateTime(2007, 12, 22, 8, 14, 45), pst); assert(ca.toUnixTime() == 1_198_340_085); } unittest { assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0); import std.meta : AliasSeq; foreach(units; AliasSeq!("hnsecs", "usecs", "msecs")) assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), dur!units(1), UTC()).toUnixTime() == 0); assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime() == 1); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toUnixTime() == 0); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toUnixTime() == 0); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toUnixTime() == 0); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toUnixTime() == -1); } /++ Converts from unix time (i.e. seconds from midnight, January 1st, 1970 in UTC) to a $(LREF SysTime). The C standard does not specify the representation of time_t, so it is implementation defined. On POSIX systems, unix time is equivalent to time_t, but that's not necessarily true on other systems (e.g. it is not true for the Digital Mars C runtime). So, be careful when using unix time with C functions on non-POSIX systems. Params: unixTime = Seconds from midnight, January 1st, 1970 in UTC. tz = The time zone for the SysTime that's returned. +/ static SysTime fromUnixTime(long unixTime, immutable TimeZone tz = LocalTime()) @safe pure nothrow { return SysTime(unixTimeToStdTime(unixTime), tz); } /// unittest { assert(SysTime.fromUnixTime(0) == SysTime(DateTime(1970, 1, 1), UTC())); auto pst = new immutable SimpleTimeZone(hours(-8)); assert(SysTime.fromUnixTime(28800) == SysTime(DateTime(1970, 1, 1), pst)); auto st1 = SysTime.fromUnixTime(1_198_311_285, UTC()); assert(st1 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC())); assert(st1.timezone is UTC()); assert(st1 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst)); auto st2 = SysTime.fromUnixTime(1_198_311_285, pst); assert(st2 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC())); assert(st2.timezone is pst); assert(st2 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst)); } unittest { assert(SysTime.fromUnixTime(0) == SysTime(DateTime(1970, 1, 1), UTC())); assert(SysTime.fromUnixTime(1) == SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC())); assert(SysTime.fromUnixTime(-1) == SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC())); auto st = SysTime.fromUnixTime(0); auto dt = cast(DateTime)st; assert(dt <= DateTime(1970, 2, 1) && dt >= DateTime(1969, 12, 31)); assert(st.timezone is LocalTime()); auto aest = new immutable SimpleTimeZone(hours(10)); assert(SysTime.fromUnixTime(-36000) == SysTime(DateTime(1970, 1, 1), aest)); } /++ Returns a $(D timeval) which represents this $(LREF SysTime). Note that like all conversions in std.datetime, this is a truncating conversion. If $(D timeval.tv_sec) is int, and the result can't fit in an int, then the closest value that can be held in 32 bits will be used for $(D tv_sec). (so $(D int.max) if it goes over and $(D int.min) if it goes under). +/ timeval toTimeVal() @safe const pure nothrow { immutable tv_sec = toUnixTime!(typeof(timeval.tv_sec))(); immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L); immutable tv_usec = cast(typeof(timeval.tv_usec))convert!("hnsecs", "usecs")(fracHNSecs); return timeval(tv_sec, tv_usec); } unittest { assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeVal() == timeval(0, 0)); assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeVal() == timeval(0, 0)); assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeVal() == timeval(0, 1)); assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeVal() == timeval(0, 7)); assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeVal() == timeval(1, 0)); assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeVal() == timeval(1, 0)); assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeVal() == timeval(1, 1)); assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeVal() == timeval(1, 7)); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeVal() == timeval(0, 0)); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeVal() == timeval(0, -1)); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeVal() == timeval(0, -1)); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeVal() == timeval(0, -999_001)); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeVal() == timeval(0, -1000)); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeVal() == timeval(-1, 0)); assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeVal() == timeval(-1, -999_983)); } /++ Returns a $(D tm) which represents this $(LREF SysTime). +/ tm toTM() @safe const nothrow { auto dateTime = cast(DateTime)this; tm timeInfo; timeInfo.tm_sec = dateTime.second; timeInfo.tm_min = dateTime.minute; timeInfo.tm_hour = dateTime.hour; timeInfo.tm_mday = dateTime.day; timeInfo.tm_mon = dateTime.month - 1; timeInfo.tm_year = dateTime.year - 1900; timeInfo.tm_wday = dateTime.dayOfWeek; timeInfo.tm_yday = dateTime.dayOfYear - 1; timeInfo.tm_isdst = _timezone.dstInEffect(_stdTime); version(Posix) { import std.utf : toUTFz; timeInfo.tm_gmtoff = cast(int)convert!("hnsecs", "seconds")(adjTime - _stdTime); auto zone = (timeInfo.tm_isdst ? _timezone.dstName : _timezone.stdName); timeInfo.tm_zone = zone.toUTFz!(char*)(); } return timeInfo; } unittest { import std.conv : to; version(Posix) { scope(exit) clearTZEnvVar(); setTZEnvVar("America/Los_Angeles"); } { auto timeInfo = SysTime(DateTime(1970, 1, 1)).toTM(); assert(timeInfo.tm_sec == 0); assert(timeInfo.tm_min == 0); assert(timeInfo.tm_hour == 0); assert(timeInfo.tm_mday == 1); assert(timeInfo.tm_mon == 0); assert(timeInfo.tm_year == 70); assert(timeInfo.tm_wday == 4); assert(timeInfo.tm_yday == 0); version(Posix) assert(timeInfo.tm_isdst == 0); else version(Windows) assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1); version(Posix) { assert(timeInfo.tm_gmtoff == -8 * 60 * 60); assert(to!string(timeInfo.tm_zone) == "PST"); } } { auto timeInfo = SysTime(DateTime(2010, 7, 4, 12, 15, 7), hnsecs(15)).toTM(); assert(timeInfo.tm_sec == 7); assert(timeInfo.tm_min == 15); assert(timeInfo.tm_hour == 12); assert(timeInfo.tm_mday == 4); assert(timeInfo.tm_mon == 6); assert(timeInfo.tm_year == 110); assert(timeInfo.tm_wday == 0); assert(timeInfo.tm_yday == 184); version(Posix) assert(timeInfo.tm_isdst == 1); else version(Windows) assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1); version(Posix) { assert(timeInfo.tm_gmtoff == -7 * 60 * 60); assert(to!string(timeInfo.tm_zone) == "PDT"); } } } /++ Adds the given number of years or months to this $(LREF SysTime). A negative number will subtract. Note that if day overflow is allowed, and the date with the adjusted year/month overflows the number of days in the new month, then the month will be incremented by one, and the day set to the number of days overflowed. (e.g. if the day were 31 and the new month were June, then the month would be incremented to July, and the new day would be 1). If day overflow is not allowed, then the day will be set to the last valid day in the month (e.g. June 31st would become June 30th). Params: units = The type of units to add ("years" or "months"). value = The number of months or years to add to this $(LREF SysTime). allowOverflow = Whether the days should be allowed to overflow, causing the month to increment. +/ ref SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow if(units == "years" || units == "months") { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } auto date = Date(cast(int)days); date.add!units(value, allowOverflow); days = date.dayOfGregorianCal - 1; if(days < 0) { hnsecs -= convert!("hours", "hnsecs")(24); ++days; } immutable newDaysHNSecs = convert!("days", "hnsecs")(days); adjTime = newDaysHNSecs + hnsecs; return this; } unittest { auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30, 33)); st1.add!"months"(11); assert(st1 == SysTime(DateTime(2010, 12, 1, 12, 30, 33))); auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30, 33)); st2.add!"months"(-11); assert(st2 == SysTime(DateTime(2009, 2, 1, 12, 30, 33))); auto st3 = SysTime(DateTime(2000, 2, 29, 12, 30, 33)); st3.add!"years"(1); assert(st3 == SysTime(DateTime(2001, 3, 1, 12, 30, 33))); auto st4 = SysTime(DateTime(2000, 2, 29, 12, 30, 33)); st4.add!"years"(1, AllowDayOverflow.no); assert(st4 == SysTime(DateTime(2001, 2, 28, 12, 30, 33))); } //Test add!"years"() with AllowDayOverlow.yes unittest { //Test A.D. { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.add!"years"(7); assert(sysTime == SysTime(Date(2006, 7, 6))); sysTime.add!"years"(-9); assert(sysTime == SysTime(Date(1997, 7, 6))); } { auto sysTime = SysTime(Date(1999, 2, 28)); sysTime.add!"years"(1); assert(sysTime == SysTime(Date(2000, 2, 28))); } { auto sysTime = SysTime(Date(2000, 2, 29)); sysTime.add!"years"(-1); assert(sysTime == SysTime(Date(1999, 3, 1))); } { auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234)); sysTime.add!"years"(7); assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234))); sysTime.add!"years"(-9); assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234))); } { auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207)); sysTime.add!"years"(1); assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207))); } { auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207)); sysTime.add!"years"(-1); assert(sysTime == SysTime(DateTime(1999, 3, 1, 0, 7, 2), usecs(1207))); } //Test B.C. { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.add!"years"(-7); assert(sysTime == SysTime(Date(-2006, 7, 6))); sysTime.add!"years"(9); assert(sysTime == SysTime(Date(-1997, 7, 6))); } { auto sysTime = SysTime(Date(-1999, 2, 28)); sysTime.add!"years"(-1); assert(sysTime == SysTime(Date(-2000, 2, 28))); } { auto sysTime = SysTime(Date(-2000, 2, 29)); sysTime.add!"years"(1); assert(sysTime == SysTime(Date(-1999, 3, 1))); } { auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234)); sysTime.add!"years"(-7); assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234))); sysTime.add!"years"(9); assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234))); } { auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3)); sysTime.add!"years"(-1); assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3))); } { auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3)); sysTime.add!"years"(1); assert(sysTime == SysTime(DateTime(-1999, 3, 1, 3, 3, 3), hnsecs(3))); } //Test Both { auto sysTime = SysTime(Date(4, 7, 6)); sysTime.add!"years"(-5); assert(sysTime == SysTime(Date(-1, 7, 6))); sysTime.add!"years"(5); assert(sysTime == SysTime(Date(4, 7, 6))); } { auto sysTime = SysTime(Date(-4, 7, 6)); sysTime.add!"years"(5); assert(sysTime == SysTime(Date(1, 7, 6))); sysTime.add!"years"(-5); assert(sysTime == SysTime(Date(-4, 7, 6))); } { auto sysTime = SysTime(Date(4, 7, 6)); sysTime.add!"years"(-8); assert(sysTime == SysTime(Date(-4, 7, 6))); sysTime.add!"years"(8); assert(sysTime == SysTime(Date(4, 7, 6))); } { auto sysTime = SysTime(Date(-4, 7, 6)); sysTime.add!"years"(8); assert(sysTime == SysTime(Date(4, 7, 6))); sysTime.add!"years"(-8); assert(sysTime == SysTime(Date(-4, 7, 6))); } { auto sysTime = SysTime(Date(-4, 2, 29)); sysTime.add!"years"(5); assert(sysTime == SysTime(Date(1, 3, 1))); } { auto sysTime = SysTime(Date(4, 2, 29)); sysTime.add!"years"(-5); assert(sysTime == SysTime(Date(-1, 3, 1))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.add!"years"(-1); assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0))); sysTime.add!"years"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.add!"years"(-1); assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.add!"years"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0)); sysTime.add!"years"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); sysTime.add!"years"(-1); assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.add!"years"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.add!"years"(-1); assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)); sysTime.add!"years"(-5); assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329))); sysTime.add!"years"(5); assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329))); } { auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)); sysTime.add!"years"(5); assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329))); sysTime.add!"years"(-5); assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329))); } { auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555)); sysTime.add!"years"(5); assert(sysTime == SysTime(DateTime(1, 3, 1, 5, 5, 5), msecs(555))); } { auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555)); sysTime.add!"years"(-5); assert(sysTime == SysTime(DateTime(-1, 3, 1, 5, 5, 5), msecs(555))); } { auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555)); sysTime.add!"years"(-5).add!"years"(7); assert(sysTime == SysTime(DateTime(6, 3, 1, 5, 5, 5), msecs(555))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.add!"years"(4))); //static assert(!__traits(compiles, ist.add!"years"(4))); } //Test add!"years"() with AllowDayOverlow.no unittest { //Test A.D. { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.add!"years"(7, AllowDayOverflow.no); assert(sysTime == SysTime(Date(2006, 7, 6))); sysTime.add!"years"(-9, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1997, 7, 6))); } { auto sysTime = SysTime(Date(1999, 2, 28)); sysTime.add!"years"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(2000, 2, 28))); } { auto sysTime = SysTime(Date(2000, 2, 29)); sysTime.add!"years"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 2, 28))); } { auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234)); sysTime.add!"years"(7, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234))); sysTime.add!"years"(-9, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234))); } { auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207)); sysTime.add!"years"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207))); } { auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207)); sysTime.add!"years"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207))); } //Test B.C. { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.add!"years"(-7, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2006, 7, 6))); sysTime.add!"years"(9, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1997, 7, 6))); } { auto sysTime = SysTime(Date(-1999, 2, 28)); sysTime.add!"years"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2000, 2, 28))); } { auto sysTime = SysTime(Date(-2000, 2, 29)); sysTime.add!"years"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 2, 28))); } { auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234)); sysTime.add!"years"(-7, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234))); sysTime.add!"years"(9, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234))); } { auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3)); sysTime.add!"years"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3))); } { auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3)); sysTime.add!"years"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3))); } //Test Both { auto sysTime = SysTime(Date(4, 7, 6)); sysTime.add!"years"(-5, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1, 7, 6))); sysTime.add!"years"(5, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 7, 6))); } { auto sysTime = SysTime(Date(-4, 7, 6)); sysTime.add!"years"(5, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1, 7, 6))); sysTime.add!"years"(-5, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-4, 7, 6))); } { auto sysTime = SysTime(Date(4, 7, 6)); sysTime.add!"years"(-8, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-4, 7, 6))); sysTime.add!"years"(8, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 7, 6))); } { auto sysTime = SysTime(Date(-4, 7, 6)); sysTime.add!"years"(8, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 7, 6))); sysTime.add!"years"(-8, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-4, 7, 6))); } { auto sysTime = SysTime(Date(-4, 2, 29)); sysTime.add!"years"(5, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1, 2, 28))); } { auto sysTime = SysTime(Date(4, 2, 29)); sysTime.add!"years"(-5, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1, 2, 28))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.add!"years"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0))); sysTime.add!"years"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.add!"years"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.add!"years"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0)); sysTime.add!"years"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); sysTime.add!"years"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.add!"years"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.add!"years"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)); sysTime.add!"years"(-5); assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329))); sysTime.add!"years"(5); assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329))); } { auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)); sysTime.add!"years"(-5, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329))); sysTime.add!"years"(5, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329))); } { auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)); sysTime.add!"years"(5, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329))); sysTime.add!"years"(-5, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329))); } { auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555)); sysTime.add!"years"(5, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 2, 28, 5, 5, 5), msecs(555))); } { auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555)); sysTime.add!"years"(-5, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-1, 2, 28, 5, 5, 5), msecs(555))); } { auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555)); sysTime.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(6, 2, 28, 5, 5, 5), msecs(555))); } } //Test add!"months"() with AllowDayOverlow.yes unittest { //Test A.D. { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.add!"months"(3); assert(sysTime == SysTime(Date(1999, 10, 6))); sysTime.add!"months"(-4); assert(sysTime == SysTime(Date(1999, 6, 6))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.add!"months"(6); assert(sysTime == SysTime(Date(2000, 1, 6))); sysTime.add!"months"(-6); assert(sysTime == SysTime(Date(1999, 7, 6))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.add!"months"(27); assert(sysTime == SysTime(Date(2001, 10, 6))); sysTime.add!"months"(-28); assert(sysTime == SysTime(Date(1999, 6, 6))); } { auto sysTime = SysTime(Date(1999, 5, 31)); sysTime.add!"months"(1); assert(sysTime == SysTime(Date(1999, 7, 1))); } { auto sysTime = SysTime(Date(1999, 5, 31)); sysTime.add!"months"(-1); assert(sysTime == SysTime(Date(1999, 5, 1))); } { auto sysTime = SysTime(Date(1999, 2, 28)); sysTime.add!"months"(12); assert(sysTime == SysTime(Date(2000, 2, 28))); } { auto sysTime = SysTime(Date(2000, 2, 29)); sysTime.add!"months"(12); assert(sysTime == SysTime(Date(2001, 3, 1))); } { auto sysTime = SysTime(Date(1999, 7, 31)); sysTime.add!"months"(1); assert(sysTime == SysTime(Date(1999, 8, 31))); sysTime.add!"months"(1); assert(sysTime == SysTime(Date(1999, 10, 1))); } { auto sysTime = SysTime(Date(1998, 8, 31)); sysTime.add!"months"(13); assert(sysTime == SysTime(Date(1999, 10, 1))); sysTime.add!"months"(-13); assert(sysTime == SysTime(Date(1998, 9, 1))); } { auto sysTime = SysTime(Date(1997, 12, 31)); sysTime.add!"months"(13); assert(sysTime == SysTime(Date(1999, 1, 31))); sysTime.add!"months"(-13); assert(sysTime == SysTime(Date(1997, 12, 31))); } { auto sysTime = SysTime(Date(1997, 12, 31)); sysTime.add!"months"(14); assert(sysTime == SysTime(Date(1999, 3, 3))); sysTime.add!"months"(-14); assert(sysTime == SysTime(Date(1998, 1, 3))); } { auto sysTime = SysTime(Date(1998, 12, 31)); sysTime.add!"months"(14); assert(sysTime == SysTime(Date(2000, 3, 2))); sysTime.add!"months"(-14); assert(sysTime == SysTime(Date(1999, 1, 2))); } { auto sysTime = SysTime(Date(1999, 12, 31)); sysTime.add!"months"(14); assert(sysTime == SysTime(Date(2001, 3, 3))); sysTime.add!"months"(-14); assert(sysTime == SysTime(Date(2000, 1, 3))); } { auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007)); sysTime.add!"months"(3); assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007))); sysTime.add!"months"(-4); assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007))); } { auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.add!"months"(14); assert(sysTime == SysTime(DateTime(2000, 3, 2, 7, 7, 7), hnsecs(422202))); sysTime.add!"months"(-14); assert(sysTime == SysTime(DateTime(1999, 1, 2, 7, 7, 7), hnsecs(422202))); } { auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.add!"months"(14); assert(sysTime == SysTime(DateTime(2001, 3, 3, 7, 7, 7), hnsecs(422202))); sysTime.add!"months"(-14); assert(sysTime == SysTime(DateTime(2000, 1, 3, 7, 7, 7), hnsecs(422202))); } //Test B.C. { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.add!"months"(3); assert(sysTime == SysTime(Date(-1999, 10, 6))); sysTime.add!"months"(-4); assert(sysTime == SysTime(Date(-1999, 6, 6))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.add!"months"(6); assert(sysTime == SysTime(Date(-1998, 1, 6))); sysTime.add!"months"(-6); assert(sysTime == SysTime(Date(-1999, 7, 6))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.add!"months"(-27); assert(sysTime == SysTime(Date(-2001, 4, 6))); sysTime.add!"months"(28); assert(sysTime == SysTime(Date(-1999, 8, 6))); } { auto sysTime = SysTime(Date(-1999, 5, 31)); sysTime.add!"months"(1); assert(sysTime == SysTime(Date(-1999, 7, 1))); } { auto sysTime = SysTime(Date(-1999, 5, 31)); sysTime.add!"months"(-1); assert(sysTime == SysTime(Date(-1999, 5, 1))); } { auto sysTime = SysTime(Date(-1999, 2, 28)); sysTime.add!"months"(-12); assert(sysTime == SysTime(Date(-2000, 2, 28))); } { auto sysTime = SysTime(Date(-2000, 2, 29)); sysTime.add!"months"(-12); assert(sysTime == SysTime(Date(-2001, 3, 1))); } { auto sysTime = SysTime(Date(-1999, 7, 31)); sysTime.add!"months"(1); assert(sysTime == SysTime(Date(-1999, 8, 31))); sysTime.add!"months"(1); assert(sysTime == SysTime(Date(-1999, 10, 1))); } { auto sysTime = SysTime(Date(-1998, 8, 31)); sysTime.add!"months"(13); assert(sysTime == SysTime(Date(-1997, 10, 1))); sysTime.add!"months"(-13); assert(sysTime == SysTime(Date(-1998, 9, 1))); } { auto sysTime = SysTime(Date(-1997, 12, 31)); sysTime.add!"months"(13); assert(sysTime == SysTime(Date(-1995, 1, 31))); sysTime.add!"months"(-13); assert(sysTime == SysTime(Date(-1997, 12, 31))); } { auto sysTime = SysTime(Date(-1997, 12, 31)); sysTime.add!"months"(14); assert(sysTime == SysTime(Date(-1995, 3, 3))); sysTime.add!"months"(-14); assert(sysTime == SysTime(Date(-1996, 1, 3))); } { auto sysTime = SysTime(Date(-2002, 12, 31)); sysTime.add!"months"(14); assert(sysTime == SysTime(Date(-2000, 3, 2))); sysTime.add!"months"(-14); assert(sysTime == SysTime(Date(-2001, 1, 2))); } { auto sysTime = SysTime(Date(-2001, 12, 31)); sysTime.add!"months"(14); assert(sysTime == SysTime(Date(-1999, 3, 3))); sysTime.add!"months"(-14); assert(sysTime == SysTime(Date(-2000, 1, 3))); } { auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007)); sysTime.add!"months"(3); assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007))); sysTime.add!"months"(-4); assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007))); } { auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.add!"months"(14); assert(sysTime == SysTime(DateTime(-2000, 3, 2, 7, 7, 7), hnsecs(422202))); sysTime.add!"months"(-14); assert(sysTime == SysTime(DateTime(-2001, 1, 2, 7, 7, 7), hnsecs(422202))); } { auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.add!"months"(14); assert(sysTime == SysTime(DateTime(-1999, 3, 3, 7, 7, 7), hnsecs(422202))); sysTime.add!"months"(-14); assert(sysTime == SysTime(DateTime(-2000, 1, 3, 7, 7, 7), hnsecs(422202))); } //Test Both { auto sysTime = SysTime(Date(1, 1, 1)); sysTime.add!"months"(-1); assert(sysTime == SysTime(Date(0, 12, 1))); sysTime.add!"months"(1); assert(sysTime == SysTime(Date(1, 1, 1))); } { auto sysTime = SysTime(Date(4, 1, 1)); sysTime.add!"months"(-48); assert(sysTime == SysTime(Date(0, 1, 1))); sysTime.add!"months"(48); assert(sysTime == SysTime(Date(4, 1, 1))); } { auto sysTime = SysTime(Date(4, 3, 31)); sysTime.add!"months"(-49); assert(sysTime == SysTime(Date(0, 3, 2))); sysTime.add!"months"(49); assert(sysTime == SysTime(Date(4, 4, 2))); } { auto sysTime = SysTime(Date(4, 3, 31)); sysTime.add!"months"(-85); assert(sysTime == SysTime(Date(-3, 3, 3))); sysTime.add!"months"(85); assert(sysTime == SysTime(Date(4, 4, 3))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.add!"months"(-1); assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0))); sysTime.add!"months"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.add!"months"(-1); assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.add!"months"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0)); sysTime.add!"months"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); sysTime.add!"months"(-1); assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.add!"months"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.add!"months"(-1); assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)); sysTime.add!"months"(-1); assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17))); sysTime.add!"months"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17))); } { auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9)); sysTime.add!"months"(-85); assert(sysTime == SysTime(DateTime(-3, 3, 3, 12, 11, 10), msecs(9))); sysTime.add!"months"(85); assert(sysTime == SysTime(DateTime(4, 4, 3, 12, 11, 10), msecs(9))); } { auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9)); sysTime.add!"months"(85); assert(sysTime == SysTime(DateTime(4, 5, 1, 12, 11, 10), msecs(9))); sysTime.add!"months"(-85); assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9))); } { auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9)); sysTime.add!"months"(85).add!"months"(-83); assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.add!"months"(4))); //static assert(!__traits(compiles, ist.add!"months"(4))); } //Test add!"months"() with AllowDayOverlow.no unittest { //Test A.D. { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.add!"months"(3, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 10, 6))); sysTime.add!"months"(-4, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 6, 6))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.add!"months"(6, AllowDayOverflow.no); assert(sysTime == SysTime(Date(2000, 1, 6))); sysTime.add!"months"(-6, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 7, 6))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.add!"months"(27, AllowDayOverflow.no); assert(sysTime == SysTime(Date(2001, 10, 6))); sysTime.add!"months"(-28, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 6, 6))); } { auto sysTime = SysTime(Date(1999, 5, 31)); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 6, 30))); } { auto sysTime = SysTime(Date(1999, 5, 31)); sysTime.add!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 4, 30))); } { auto sysTime = SysTime(Date(1999, 2, 28)); sysTime.add!"months"(12, AllowDayOverflow.no); assert(sysTime == SysTime(Date(2000, 2, 28))); } { auto sysTime = SysTime(Date(2000, 2, 29)); sysTime.add!"months"(12, AllowDayOverflow.no); assert(sysTime == SysTime(Date(2001, 2, 28))); } { auto sysTime = SysTime(Date(1999, 7, 31)); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 8, 31))); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 9, 30))); } { auto sysTime = SysTime(Date(1998, 8, 31)); sysTime.add!"months"(13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 9, 30))); sysTime.add!"months"(-13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1998, 8, 30))); } { auto sysTime = SysTime(Date(1997, 12, 31)); sysTime.add!"months"(13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 1, 31))); sysTime.add!"months"(-13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1997, 12, 31))); } { auto sysTime = SysTime(Date(1997, 12, 31)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 2, 28))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1997, 12, 28))); } { auto sysTime = SysTime(Date(1998, 12, 31)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(2000, 2, 29))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1998, 12, 29))); } { auto sysTime = SysTime(Date(1999, 12, 31)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(2001, 2, 28))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 12, 28))); } { auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007)); sysTime.add!"months"(3, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007))); sysTime.add!"months"(-4, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007))); } { auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(2000, 2, 29, 7, 7, 7), hnsecs(422202))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1998, 12, 29, 7, 7, 7), hnsecs(422202))); } { auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(2001, 2, 28, 7, 7, 7), hnsecs(422202))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202))); } //Test B.C. { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.add!"months"(3, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 10, 6))); sysTime.add!"months"(-4, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 6, 6))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.add!"months"(6, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1998, 1, 6))); sysTime.add!"months"(-6, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 7, 6))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.add!"months"(-27, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2001, 4, 6))); sysTime.add!"months"(28, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 8, 6))); } { auto sysTime = SysTime(Date(-1999, 5, 31)); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 6, 30))); } { auto sysTime = SysTime(Date(-1999, 5, 31)); sysTime.add!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 4, 30))); } { auto sysTime = SysTime(Date(-1999, 2, 28)); sysTime.add!"months"(-12, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2000, 2, 28))); } { auto sysTime = SysTime(Date(-2000, 2, 29)); sysTime.add!"months"(-12, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2001, 2, 28))); } { auto sysTime = SysTime(Date(-1999, 7, 31)); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 8, 31))); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 9, 30))); } { auto sysTime = SysTime(Date(-1998, 8, 31)); sysTime.add!"months"(13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1997, 9, 30))); sysTime.add!"months"(-13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1998, 8, 30))); } { auto sysTime = SysTime(Date(-1997, 12, 31)); sysTime.add!"months"(13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1995, 1, 31))); sysTime.add!"months"(-13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1997, 12, 31))); } { auto sysTime = SysTime(Date(-1997, 12, 31)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1995, 2, 28))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1997, 12, 28))); } { auto sysTime = SysTime(Date(-2002, 12, 31)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2000, 2, 29))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2002, 12, 29))); } { auto sysTime = SysTime(Date(-2001, 12, 31)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 2, 28))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2001, 12, 28))); } { auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007)); sysTime.add!"months"(3, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007))); sysTime.add!"months"(-4, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007))); } { auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-2000, 2, 29, 7, 7, 7), hnsecs(422202))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-2002, 12, 29, 7, 7, 7), hnsecs(422202))); } { auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.add!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 7, 7), hnsecs(422202))); sysTime.add!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202))); } //Test Both { auto sysTime = SysTime(Date(1, 1, 1)); sysTime.add!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(0, 12, 1))); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1, 1, 1))); } { auto sysTime = SysTime(Date(4, 1, 1)); sysTime.add!"months"(-48, AllowDayOverflow.no); assert(sysTime == SysTime(Date(0, 1, 1))); sysTime.add!"months"(48, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 1, 1))); } { auto sysTime = SysTime(Date(4, 3, 31)); sysTime.add!"months"(-49, AllowDayOverflow.no); assert(sysTime == SysTime(Date(0, 2, 29))); sysTime.add!"months"(49, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 3, 29))); } { auto sysTime = SysTime(Date(4, 3, 31)); sysTime.add!"months"(-85, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-3, 2, 28))); sysTime.add!"months"(85, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 3, 28))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.add!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0))); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.add!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0)); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); sysTime.add!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.add!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)); sysTime.add!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17))); sysTime.add!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17))); } { auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9)); sysTime.add!"months"(-85, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-3, 2, 28, 12, 11, 10), msecs(9))); sysTime.add!"months"(85, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(4, 3, 28, 12, 11, 10), msecs(9))); } { auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9)); sysTime.add!"months"(85, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(4, 4, 30, 12, 11, 10), msecs(9))); sysTime.add!"months"(-85, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9))); } { auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9)); sysTime.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9))); } } /++ Adds the given number of years or months to this $(LREF SysTime). A negative number will subtract. The difference between rolling and adding is that rolling does not affect larger units. Rolling a $(LREF SysTime) 12 months gets the exact same $(LREF SysTime). However, the days can still be affected due to the differing number of days in each month. Because there are no units larger than years, there is no difference between adding and rolling years. Params: units = The type of units to add ("years" or "months"). value = The number of months or years to add to this $(LREF SysTime). allowOverflow = Whether the days should be allowed to overflow, causing the month to increment. +/ ref SysTime roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow if(units == "years") { return add!"years"(value, allowOverflow); } /// unittest { auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33)); st1.roll!"months"(1); assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33))); auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33)); st2.roll!"months"(-1); assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33))); auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33)); st3.roll!"months"(1); assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33))); auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33)); st4.roll!"months"(1, AllowDayOverflow.no); assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33))); auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33)); st5.roll!"years"(1); assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33))); auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33)); st6.roll!"years"(1, AllowDayOverflow.no); assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33))); } unittest { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); st.roll!"years"(4); static assert(!__traits(compiles, cst.roll!"years"(4))); //static assert(!__traits(compiles, ist.roll!"years"(4))); } //Shares documentation with "years" overload. ref SysTime roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow if(units == "months") { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } auto date = Date(cast(int)days); date.roll!"months"(value, allowOverflow); days = date.dayOfGregorianCal - 1; if(days < 0) { hnsecs -= convert!("hours", "hnsecs")(24); ++days; } immutable newDaysHNSecs = convert!("days", "hnsecs")(days); adjTime = newDaysHNSecs + hnsecs; return this; } //Test roll!"months"() with AllowDayOverlow.yes unittest { //Test A.D. { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.roll!"months"(3); assert(sysTime == SysTime(Date(1999, 10, 6))); sysTime.roll!"months"(-4); assert(sysTime == SysTime(Date(1999, 6, 6))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.roll!"months"(6); assert(sysTime == SysTime(Date(1999, 1, 6))); sysTime.roll!"months"(-6); assert(sysTime == SysTime(Date(1999, 7, 6))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.roll!"months"(27); assert(sysTime == SysTime(Date(1999, 10, 6))); sysTime.roll!"months"(-28); assert(sysTime == SysTime(Date(1999, 6, 6))); } { auto sysTime = SysTime(Date(1999, 5, 31)); sysTime.roll!"months"(1); assert(sysTime == SysTime(Date(1999, 7, 1))); } { auto sysTime = SysTime(Date(1999, 5, 31)); sysTime.roll!"months"(-1); assert(sysTime == SysTime(Date(1999, 5, 1))); } { auto sysTime = SysTime(Date(1999, 2, 28)); sysTime.roll!"months"(12); assert(sysTime == SysTime(Date(1999, 2, 28))); } { auto sysTime = SysTime(Date(2000, 2, 29)); sysTime.roll!"months"(12); assert(sysTime == SysTime(Date(2000, 2, 29))); } { auto sysTime = SysTime(Date(1999, 7, 31)); sysTime.roll!"months"(1); assert(sysTime == SysTime(Date(1999, 8, 31))); sysTime.roll!"months"(1); assert(sysTime == SysTime(Date(1999, 10, 1))); } { auto sysTime = SysTime(Date(1998, 8, 31)); sysTime.roll!"months"(13); assert(sysTime == SysTime(Date(1998, 10, 1))); sysTime.roll!"months"(-13); assert(sysTime == SysTime(Date(1998, 9, 1))); } { auto sysTime = SysTime(Date(1997, 12, 31)); sysTime.roll!"months"(13); assert(sysTime == SysTime(Date(1997, 1, 31))); sysTime.roll!"months"(-13); assert(sysTime == SysTime(Date(1997, 12, 31))); } { auto sysTime = SysTime(Date(1997, 12, 31)); sysTime.roll!"months"(14); assert(sysTime == SysTime(Date(1997, 3, 3))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(Date(1997, 1, 3))); } { auto sysTime = SysTime(Date(1998, 12, 31)); sysTime.roll!"months"(14); assert(sysTime == SysTime(Date(1998, 3, 3))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(Date(1998, 1, 3))); } { auto sysTime = SysTime(Date(1999, 12, 31)); sysTime.roll!"months"(14); assert(sysTime == SysTime(Date(1999, 3, 3))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(Date(1999, 1, 3))); } { auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007)); sysTime.roll!"months"(3); assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007))); sysTime.roll!"months"(-4); assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007))); } { auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.roll!"months"(14); assert(sysTime == SysTime(DateTime(1998, 3, 3, 7, 7, 7), hnsecs(422202))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(DateTime(1998, 1, 3, 7, 7, 7), hnsecs(422202))); } { auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.roll!"months"(14); assert(sysTime == SysTime(DateTime(1999, 3, 3, 7, 7, 7), hnsecs(422202))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(DateTime(1999, 1, 3, 7, 7, 7), hnsecs(422202))); } //Test B.C. { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.roll!"months"(3); assert(sysTime == SysTime(Date(-1999, 10, 6))); sysTime.roll!"months"(-4); assert(sysTime == SysTime(Date(-1999, 6, 6))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.roll!"months"(6); assert(sysTime == SysTime(Date(-1999, 1, 6))); sysTime.roll!"months"(-6); assert(sysTime == SysTime(Date(-1999, 7, 6))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.roll!"months"(-27); assert(sysTime == SysTime(Date(-1999, 4, 6))); sysTime.roll!"months"(28); assert(sysTime == SysTime(Date(-1999, 8, 6))); } { auto sysTime = SysTime(Date(-1999, 5, 31)); sysTime.roll!"months"(1); assert(sysTime == SysTime(Date(-1999, 7, 1))); } { auto sysTime = SysTime(Date(-1999, 5, 31)); sysTime.roll!"months"(-1); assert(sysTime == SysTime(Date(-1999, 5, 1))); } { auto sysTime = SysTime(Date(-1999, 2, 28)); sysTime.roll!"months"(-12); assert(sysTime == SysTime(Date(-1999, 2, 28))); } { auto sysTime = SysTime(Date(-2000, 2, 29)); sysTime.roll!"months"(-12); assert(sysTime == SysTime(Date(-2000, 2, 29))); } { auto sysTime = SysTime(Date(-1999, 7, 31)); sysTime.roll!"months"(1); assert(sysTime == SysTime(Date(-1999, 8, 31))); sysTime.roll!"months"(1); assert(sysTime == SysTime(Date(-1999, 10, 1))); } { auto sysTime = SysTime(Date(-1998, 8, 31)); sysTime.roll!"months"(13); assert(sysTime == SysTime(Date(-1998, 10, 1))); sysTime.roll!"months"(-13); assert(sysTime == SysTime(Date(-1998, 9, 1))); } { auto sysTime = SysTime(Date(-1997, 12, 31)); sysTime.roll!"months"(13); assert(sysTime == SysTime(Date(-1997, 1, 31))); sysTime.roll!"months"(-13); assert(sysTime == SysTime(Date(-1997, 12, 31))); } { auto sysTime = SysTime(Date(-1997, 12, 31)); sysTime.roll!"months"(14); assert(sysTime == SysTime(Date(-1997, 3, 3))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(Date(-1997, 1, 3))); } { auto sysTime = SysTime(Date(-2002, 12, 31)); sysTime.roll!"months"(14); assert(sysTime == SysTime(Date(-2002, 3, 3))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(Date(-2002, 1, 3))); } { auto sysTime = SysTime(Date(-2001, 12, 31)); sysTime.roll!"months"(14); assert(sysTime == SysTime(Date(-2001, 3, 3))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(Date(-2001, 1, 3))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.roll!"months"(-1); assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0))); sysTime.roll!"months"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"months"(-1); assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.roll!"months"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0)); sysTime.roll!"months"(1); assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0))); sysTime.roll!"months"(-1); assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"months"(1); assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.roll!"months"(-1); assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), hnsecs(5007)); sysTime.roll!"months"(3); assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), hnsecs(5007))); sysTime.roll!"months"(-4); assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), hnsecs(5007))); } { auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.roll!"months"(14); assert(sysTime == SysTime(DateTime(-2002, 3, 3, 7, 7, 7), hnsecs(422202))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(DateTime(-2002, 1, 3, 7, 7, 7), hnsecs(422202))); } { auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.roll!"months"(14); assert(sysTime == SysTime(DateTime(-2001, 3, 3, 7, 7, 7), hnsecs(422202))); sysTime.roll!"months"(-14); assert(sysTime == SysTime(DateTime(-2001, 1, 3, 7, 7, 7), hnsecs(422202))); } //Test Both { auto sysTime = SysTime(Date(1, 1, 1)); sysTime.roll!"months"(-1); assert(sysTime == SysTime(Date(1, 12, 1))); sysTime.roll!"months"(1); assert(sysTime == SysTime(Date(1, 1, 1))); } { auto sysTime = SysTime(Date(4, 1, 1)); sysTime.roll!"months"(-48); assert(sysTime == SysTime(Date(4, 1, 1))); sysTime.roll!"months"(48); assert(sysTime == SysTime(Date(4, 1, 1))); } { auto sysTime = SysTime(Date(4, 3, 31)); sysTime.roll!"months"(-49); assert(sysTime == SysTime(Date(4, 3, 2))); sysTime.roll!"months"(49); assert(sysTime == SysTime(Date(4, 4, 2))); } { auto sysTime = SysTime(Date(4, 3, 31)); sysTime.roll!"months"(-85); assert(sysTime == SysTime(Date(4, 3, 2))); sysTime.roll!"months"(85); assert(sysTime == SysTime(Date(4, 4, 2))); } { auto sysTime = SysTime(Date(-1, 1, 1)); sysTime.roll!"months"(-1); assert(sysTime == SysTime(Date(-1, 12, 1))); sysTime.roll!"months"(1); assert(sysTime == SysTime(Date(-1, 1, 1))); } { auto sysTime = SysTime(Date(-4, 1, 1)); sysTime.roll!"months"(-48); assert(sysTime == SysTime(Date(-4, 1, 1))); sysTime.roll!"months"(48); assert(sysTime == SysTime(Date(-4, 1, 1))); } { auto sysTime = SysTime(Date(-4, 3, 31)); sysTime.roll!"months"(-49); assert(sysTime == SysTime(Date(-4, 3, 2))); sysTime.roll!"months"(49); assert(sysTime == SysTime(Date(-4, 4, 2))); } { auto sysTime = SysTime(Date(-4, 3, 31)); sysTime.roll!"months"(-85); assert(sysTime == SysTime(Date(-4, 3, 2))); sysTime.roll!"months"(85); assert(sysTime == SysTime(Date(-4, 4, 2))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)); sysTime.roll!"months"(-1); assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17))); sysTime.roll!"months"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17))); } { auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9)); sysTime.roll!"months"(-85); assert(sysTime == SysTime(DateTime(4, 3, 2, 12, 11, 10), msecs(9))); sysTime.roll!"months"(85); assert(sysTime == SysTime(DateTime(4, 4, 2, 12, 11, 10), msecs(9))); } { auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9)); sysTime.roll!"months"(85); assert(sysTime == SysTime(DateTime(-3, 5, 1, 12, 11, 10), msecs(9))); sysTime.roll!"months"(-85); assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9))); } { auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9)); sysTime.roll!"months"(85).roll!"months"(-83); assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.roll!"months"(4))); //static assert(!__traits(compiles, ist.roll!"months"(4))); } //Test roll!"months"() with AllowDayOverlow.no unittest { //Test A.D. { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.roll!"months"(3, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 10, 6))); sysTime.roll!"months"(-4, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 6, 6))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.roll!"months"(6, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 1, 6))); sysTime.roll!"months"(-6, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 7, 6))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.roll!"months"(27, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 10, 6))); sysTime.roll!"months"(-28, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 6, 6))); } { auto sysTime = SysTime(Date(1999, 5, 31)); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 6, 30))); } { auto sysTime = SysTime(Date(1999, 5, 31)); sysTime.roll!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 4, 30))); } { auto sysTime = SysTime(Date(1999, 2, 28)); sysTime.roll!"months"(12, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 2, 28))); } { auto sysTime = SysTime(Date(2000, 2, 29)); sysTime.roll!"months"(12, AllowDayOverflow.no); assert(sysTime == SysTime(Date(2000, 2, 29))); } { auto sysTime = SysTime(Date(1999, 7, 31)); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 8, 31))); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 9, 30))); } { auto sysTime = SysTime(Date(1998, 8, 31)); sysTime.roll!"months"(13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1998, 9, 30))); sysTime.roll!"months"(-13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1998, 8, 30))); } { auto sysTime = SysTime(Date(1997, 12, 31)); sysTime.roll!"months"(13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1997, 1, 31))); sysTime.roll!"months"(-13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1997, 12, 31))); } { auto sysTime = SysTime(Date(1997, 12, 31)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1997, 2, 28))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1997, 12, 28))); } { auto sysTime = SysTime(Date(1998, 12, 31)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1998, 2, 28))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1998, 12, 28))); } { auto sysTime = SysTime(Date(1999, 12, 31)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 2, 28))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1999, 12, 28))); } { auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007)); sysTime.roll!"months"(3, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007))); sysTime.roll!"months"(-4, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007))); } { auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1998, 2, 28, 7, 7, 7), hnsecs(422202))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1998, 12, 28, 7, 7, 7), hnsecs(422202))); } { auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 7, 7), hnsecs(422202))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202))); } //Test B.C. { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.roll!"months"(3, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 10, 6))); sysTime.roll!"months"(-4, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 6, 6))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.roll!"months"(6, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 1, 6))); sysTime.roll!"months"(-6, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 7, 6))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.roll!"months"(-27, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 4, 6))); sysTime.roll!"months"(28, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 8, 6))); } { auto sysTime = SysTime(Date(-1999, 5, 31)); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 6, 30))); } { auto sysTime = SysTime(Date(-1999, 5, 31)); sysTime.roll!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 4, 30))); } { auto sysTime = SysTime(Date(-1999, 2, 28)); sysTime.roll!"months"(-12, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 2, 28))); } { auto sysTime = SysTime(Date(-2000, 2, 29)); sysTime.roll!"months"(-12, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2000, 2, 29))); } { auto sysTime = SysTime(Date(-1999, 7, 31)); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 8, 31))); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1999, 9, 30))); } { auto sysTime = SysTime(Date(-1998, 8, 31)); sysTime.roll!"months"(13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1998, 9, 30))); sysTime.roll!"months"(-13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1998, 8, 30))); } { auto sysTime = SysTime(Date(-1997, 12, 31)); sysTime.roll!"months"(13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1997, 1, 31))); sysTime.roll!"months"(-13, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1997, 12, 31))); } { auto sysTime = SysTime(Date(-1997, 12, 31)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1997, 2, 28))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1997, 12, 28))); } { auto sysTime = SysTime(Date(-2002, 12, 31)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2002, 2, 28))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2002, 12, 28))); } { auto sysTime = SysTime(Date(-2001, 12, 31)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2001, 2, 28))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-2001, 12, 28))); } { auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007)); sysTime.roll!"months"(3, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007))); sysTime.roll!"months"(-4, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007))); } { auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-2002, 2, 28, 7, 7, 7), hnsecs(422202))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-2002, 12, 28, 7, 7, 7), hnsecs(422202))); } { auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202)); sysTime.roll!"months"(14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-2001, 2, 28, 7, 7, 7), hnsecs(422202))); sysTime.roll!"months"(-14, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202))); } //Test Both { auto sysTime = SysTime(Date(1, 1, 1)); sysTime.roll!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1, 12, 1))); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(1, 1, 1))); } { auto sysTime = SysTime(Date(4, 1, 1)); sysTime.roll!"months"(-48, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 1, 1))); sysTime.roll!"months"(48, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 1, 1))); } { auto sysTime = SysTime(Date(4, 3, 31)); sysTime.roll!"months"(-49, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 2, 29))); sysTime.roll!"months"(49, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 3, 29))); } { auto sysTime = SysTime(Date(4, 3, 31)); sysTime.roll!"months"(-85, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 2, 29))); sysTime.roll!"months"(85, AllowDayOverflow.no); assert(sysTime == SysTime(Date(4, 3, 29))); } { auto sysTime = SysTime(Date(-1, 1, 1)); sysTime.roll!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1, 12, 1))); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-1, 1, 1))); } { auto sysTime = SysTime(Date(-4, 1, 1)); sysTime.roll!"months"(-48, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-4, 1, 1))); sysTime.roll!"months"(48, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-4, 1, 1))); } { auto sysTime = SysTime(Date(-4, 3, 31)); sysTime.roll!"months"(-49, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-4, 2, 29))); sysTime.roll!"months"(49, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-4, 3, 29))); } { auto sysTime = SysTime(Date(-4, 3, 31)); sysTime.roll!"months"(-85, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-4, 2, 29))); sysTime.roll!"months"(85, AllowDayOverflow.no); assert(sysTime == SysTime(Date(-4, 3, 29))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.roll!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0))); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0)); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0))); sysTime.roll!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.roll!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)); sysTime.roll!"months"(-1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17))); sysTime.roll!"months"(1, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17))); } { auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9)); sysTime.roll!"months"(-85, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(4, 2, 29, 12, 11, 10), msecs(9))); sysTime.roll!"months"(85, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(4, 3, 29, 12, 11, 10), msecs(9))); } { auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9)); sysTime.roll!"months"(85, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-3, 4, 30, 12, 11, 10), msecs(9))); sysTime.roll!"months"(-85, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9))); } { auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9)); sysTime.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no); assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9))); } } /++ Adds the given number of units to this $(LREF SysTime). A negative number will subtract. The difference between rolling and adding is that rolling does not affect larger units. For instance, rolling a $(LREF SysTime) one year's worth of days gets the exact same $(LREF SysTime). Accepted units are $(D "days"), $(D "minutes"), $(D "hours"), $(D "minutes"), $(D "seconds"), $(D "msecs"), $(D "usecs"), and $(D "hnsecs"). Note that when rolling msecs, usecs or hnsecs, they all add up to a second. So, for example, rolling 1000 msecs is exactly the same as rolling 100,000 usecs. Params: units = The units to add. value = The number of $(D_PARAM units) to add to this $(LREF SysTime). +/ ref SysTime roll(string units)(long value) @safe nothrow if(units == "days") { auto hnsecs = adjTime; auto gdays = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --gdays; } auto date = Date(cast(int)gdays); date.roll!"days"(value); gdays = date.dayOfGregorianCal - 1; if(gdays < 0) { hnsecs -= convert!("hours", "hnsecs")(24); ++gdays; } immutable newDaysHNSecs = convert!("days", "hnsecs")(gdays); adjTime = newDaysHNSecs + hnsecs; return this; } /// unittest { auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12)); st1.roll!"days"(1); assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12))); st1.roll!"days"(365); assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12))); st1.roll!"days"(-32); assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12))); auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0)); st2.roll!"hours"(1); assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0))); auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0)); st3.roll!"hours"(-1); assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0))); auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0)); st4.roll!"minutes"(1); assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0))); auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0)); st5.roll!"minutes"(-1); assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0))); auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0)); st6.roll!"seconds"(1); assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1))); auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0)); st7.roll!"seconds"(-1); assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59))); auto dt = DateTime(2010, 1, 1, 0, 0, 0); auto st8 = SysTime(dt); st8.roll!"msecs"(1); assert(st8 == SysTime(dt, msecs(1))); auto st9 = SysTime(dt); st9.roll!"msecs"(-1); assert(st9 == SysTime(dt, msecs(999))); auto st10 = SysTime(dt); st10.roll!"hnsecs"(1); assert(st10 == SysTime(dt, hnsecs(1))); auto st11 = SysTime(dt); st11.roll!"hnsecs"(-1); assert(st11 == SysTime(dt, hnsecs(9_999_999))); } unittest { //Test A.D. { auto sysTime = SysTime(Date(1999, 2, 28)); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(1999, 2, 1))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(1999, 2, 28))); } { auto sysTime = SysTime(Date(2000, 2, 28)); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(2000, 2, 29))); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(2000, 2, 1))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(2000, 2, 29))); } { auto sysTime = SysTime(Date(1999, 6, 30)); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(1999, 6, 1))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(1999, 6, 30))); } { auto sysTime = SysTime(Date(1999, 7, 31)); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(1999, 7, 1))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(1999, 7, 31))); } { auto sysTime = SysTime(Date(1999, 1, 1)); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(1999, 1, 31))); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(1999, 1, 1))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.roll!"days"(9); assert(sysTime == SysTime(Date(1999, 7, 15))); sysTime.roll!"days"(-11); assert(sysTime == SysTime(Date(1999, 7, 4))); sysTime.roll!"days"(30); assert(sysTime == SysTime(Date(1999, 7, 3))); sysTime.roll!"days"(-3); assert(sysTime == SysTime(Date(1999, 7, 31))); } { auto sysTime = SysTime(Date(1999, 7, 6)); sysTime.roll!"days"(365); assert(sysTime == SysTime(Date(1999, 7, 30))); sysTime.roll!"days"(-365); assert(sysTime == SysTime(Date(1999, 7, 6))); sysTime.roll!"days"(366); assert(sysTime == SysTime(Date(1999, 7, 31))); sysTime.roll!"days"(730); assert(sysTime == SysTime(Date(1999, 7, 17))); sysTime.roll!"days"(-1096); assert(sysTime == SysTime(Date(1999, 7, 6))); } { auto sysTime = SysTime(Date(1999, 2, 6)); sysTime.roll!"days"(365); assert(sysTime == SysTime(Date(1999, 2, 7))); sysTime.roll!"days"(-365); assert(sysTime == SysTime(Date(1999, 2, 6))); sysTime.roll!"days"(366); assert(sysTime == SysTime(Date(1999, 2, 8))); sysTime.roll!"days"(730); assert(sysTime == SysTime(Date(1999, 2, 10))); sysTime.roll!"days"(-1096); assert(sysTime == SysTime(Date(1999, 2, 6))); } { auto sysTime = SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578)); sysTime.roll!"days"(1); assert(sysTime == SysTime(DateTime(1999, 2, 1, 7, 9, 2), usecs(234578))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578))); } { auto sysTime = SysTime(DateTime(1999, 7, 6, 7, 9, 2), usecs(234578)); sysTime.roll!"days"(9); assert(sysTime == SysTime(DateTime(1999, 7, 15, 7, 9, 2), usecs(234578))); sysTime.roll!"days"(-11); assert(sysTime == SysTime(DateTime(1999, 7, 4, 7, 9, 2), usecs(234578))); sysTime.roll!"days"(30); assert(sysTime == SysTime(DateTime(1999, 7, 3, 7, 9, 2), usecs(234578))); sysTime.roll!"days"(-3); assert(sysTime == SysTime(DateTime(1999, 7, 31, 7, 9, 2), usecs(234578))); } //Test B.C. { auto sysTime = SysTime(Date(-1999, 2, 28)); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(-1999, 2, 1))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(-1999, 2, 28))); } { auto sysTime = SysTime(Date(-2000, 2, 28)); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(-2000, 2, 29))); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(-2000, 2, 1))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(-2000, 2, 29))); } { auto sysTime = SysTime(Date(-1999, 6, 30)); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(-1999, 6, 1))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(-1999, 6, 30))); } { auto sysTime = SysTime(Date(-1999, 7, 31)); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(-1999, 7, 1))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(-1999, 7, 31))); } { auto sysTime = SysTime(Date(-1999, 1, 1)); sysTime.roll!"days"(-1); assert(sysTime == SysTime(Date(-1999, 1, 31))); sysTime.roll!"days"(1); assert(sysTime == SysTime(Date(-1999, 1, 1))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.roll!"days"(9); assert(sysTime == SysTime(Date(-1999, 7, 15))); sysTime.roll!"days"(-11); assert(sysTime == SysTime(Date(-1999, 7, 4))); sysTime.roll!"days"(30); assert(sysTime == SysTime(Date(-1999, 7, 3))); sysTime.roll!"days"(-3); assert(sysTime == SysTime(Date(-1999, 7, 31))); } { auto sysTime = SysTime(Date(-1999, 7, 6)); sysTime.roll!"days"(365); assert(sysTime == SysTime(Date(-1999, 7, 30))); sysTime.roll!"days"(-365); assert(sysTime == SysTime(Date(-1999, 7, 6))); sysTime.roll!"days"(366); assert(sysTime == SysTime(Date(-1999, 7, 31))); sysTime.roll!"days"(730); assert(sysTime == SysTime(Date(-1999, 7, 17))); sysTime.roll!"days"(-1096); assert(sysTime == SysTime(Date(-1999, 7, 6))); } { auto sysTime = SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578)); sysTime.roll!"days"(1); assert(sysTime == SysTime(DateTime(-1999, 2, 1, 7, 9, 2), usecs(234578))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578))); } { auto sysTime = SysTime(DateTime(-1999, 7, 6, 7, 9, 2), usecs(234578)); sysTime.roll!"days"(9); assert(sysTime == SysTime(DateTime(-1999, 7, 15, 7, 9, 2), usecs(234578))); sysTime.roll!"days"(-11); assert(sysTime == SysTime(DateTime(-1999, 7, 4, 7, 9, 2), usecs(234578))); sysTime.roll!"days"(30); assert(sysTime == SysTime(DateTime(-1999, 7, 3, 7, 9, 2), usecs(234578))); sysTime.roll!"days"(-3); } //Test Both { auto sysTime = SysTime(Date(1, 7, 6)); sysTime.roll!"days"(-365); assert(sysTime == SysTime(Date(1, 7, 13))); sysTime.roll!"days"(365); assert(sysTime == SysTime(Date(1, 7, 6))); sysTime.roll!"days"(-731); assert(sysTime == SysTime(Date(1, 7, 19))); sysTime.roll!"days"(730); assert(sysTime == SysTime(Date(1, 7, 5))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.roll!"days"(-1); assert(sysTime == SysTime(DateTime(1, 1, 31, 0, 0, 0))); sysTime.roll!"days"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"days"(-1); assert(sysTime == SysTime(DateTime(1, 1, 31, 23, 59, 59), hnsecs(9_999_999))); sysTime.roll!"days"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 0, 0, 0)); sysTime.roll!"days"(1); assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"days"(1); assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.roll!"days"(-1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22)); sysTime.roll!"days"(-365); assert(sysTime == SysTime(DateTime(1, 7, 13, 13, 13, 9), msecs(22))); sysTime.roll!"days"(365); assert(sysTime == SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22))); sysTime.roll!"days"(-731); assert(sysTime == SysTime(DateTime(1, 7, 19, 13, 13, 9), msecs(22))); sysTime.roll!"days"(730); assert(sysTime == SysTime(DateTime(1, 7, 5, 13, 13, 9), msecs(22))); } { auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22)); sysTime.roll!"days"(-365); assert(sysTime == SysTime(DateTime(0, 7, 13, 13, 13, 9), msecs(22))); sysTime.roll!"days"(365); assert(sysTime == SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22))); sysTime.roll!"days"(-731); assert(sysTime == SysTime(DateTime(0, 7, 19, 13, 13, 9), msecs(22))); sysTime.roll!"days"(730); assert(sysTime == SysTime(DateTime(0, 7, 5, 13, 13, 9), msecs(22))); } { auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22)); sysTime.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730); assert(sysTime == SysTime(DateTime(0, 7, 8, 13, 13, 9), msecs(22))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.roll!"days"(4))); //static assert(!__traits(compiles, ist.roll!"days"(4))); } //Shares documentation with "days" version. ref SysTime roll(string units)(long value) @safe nothrow if(units == "hours" || units == "minutes" || units == "seconds") { try { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs); immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs); immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs); auto dateTime = DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second)); dateTime.roll!units(value); --days; hnsecs += convert!("hours", "hnsecs")(dateTime.hour); hnsecs += convert!("minutes", "hnsecs")(dateTime.minute); hnsecs += convert!("seconds", "hnsecs")(dateTime.second); if(days < 0) { hnsecs -= convert!("hours", "hnsecs")(24); ++days; } immutable newDaysHNSecs = convert!("days", "hnsecs")(days); adjTime = newDaysHNSecs + hnsecs; return this; } catch(Exception e) assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw."); } //Test roll!"hours"(). unittest { static void testST(SysTime orig, int hours, in SysTime expected, size_t line = __LINE__) { import std.format : format; orig.roll!"hours"(hours); if(orig != expected) throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line); } //Test A.D. immutable d = msecs(45); auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d); testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d)); testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d)); testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d)); testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d)); testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d)); testST(beforeAD, 6, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d)); testST(beforeAD, 7, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d)); testST(beforeAD, 8, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d)); testST(beforeAD, 9, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d)); testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d)); testST(beforeAD, 11, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d)); testST(beforeAD, 12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d)); testST(beforeAD, 13, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d)); testST(beforeAD, 14, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d)); testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d)); testST(beforeAD, 16, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d)); testST(beforeAD, 17, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d)); testST(beforeAD, 18, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d)); testST(beforeAD, 19, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d)); testST(beforeAD, 20, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d)); testST(beforeAD, 21, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d)); testST(beforeAD, 22, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d)); testST(beforeAD, 23, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d)); testST(beforeAD, 24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, 25, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d)); testST(beforeAD, 50, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d)); testST(beforeAD, 10_000, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d)); testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d)); testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d)); testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d)); testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d)); testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d)); testST(beforeAD, -6, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d)); testST(beforeAD, -7, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d)); testST(beforeAD, -8, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d)); testST(beforeAD, -9, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d)); testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d)); testST(beforeAD, -11, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d)); testST(beforeAD, -12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d)); testST(beforeAD, -13, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d)); testST(beforeAD, -14, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d)); testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d)); testST(beforeAD, -16, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d)); testST(beforeAD, -17, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d)); testST(beforeAD, -18, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d)); testST(beforeAD, -19, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d)); testST(beforeAD, -20, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d)); testST(beforeAD, -21, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d)); testST(beforeAD, -22, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d)); testST(beforeAD, -23, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d)); testST(beforeAD, -24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, -25, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d)); testST(beforeAD, -50, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d)); testST(beforeAD, -10_000, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d)); testST(SysTime(DateTime(1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 31, 0, 30, 33), d)); testST(SysTime(DateTime(1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(1999, 8, 1, 23, 30, 33), d)); testST(SysTime(DateTime(1999, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 12, 31, 0, 30, 33), d)); testST(SysTime(DateTime(2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(2000, 1, 1, 23, 30, 33), d)); testST(SysTime(DateTime(1999, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(1999, 2, 28, 0, 30, 33), d)); testST(SysTime(DateTime(1999, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(1999, 3, 2, 23, 30, 33), d)); testST(SysTime(DateTime(2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(2000, 2, 28, 0, 30, 33), d)); testST(SysTime(DateTime(2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(2000, 3, 1, 23, 30, 33), d)); //Test B.C. auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d); testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d)); testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d)); testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d)); testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d)); testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d)); testST(beforeBC, 6, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d)); testST(beforeBC, 7, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d)); testST(beforeBC, 8, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d)); testST(beforeBC, 9, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d)); testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d)); testST(beforeBC, 11, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d)); testST(beforeBC, 12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d)); testST(beforeBC, 13, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d)); testST(beforeBC, 14, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d)); testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d)); testST(beforeBC, 16, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d)); testST(beforeBC, 17, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d)); testST(beforeBC, 18, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d)); testST(beforeBC, 19, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d)); testST(beforeBC, 20, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d)); testST(beforeBC, 21, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d)); testST(beforeBC, 22, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d)); testST(beforeBC, 23, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d)); testST(beforeBC, 24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, 25, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d)); testST(beforeBC, 50, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d)); testST(beforeBC, 10_000, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d)); testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d)); testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d)); testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d)); testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d)); testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d)); testST(beforeBC, -6, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d)); testST(beforeBC, -7, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d)); testST(beforeBC, -8, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d)); testST(beforeBC, -9, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d)); testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d)); testST(beforeBC, -11, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d)); testST(beforeBC, -12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d)); testST(beforeBC, -13, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d)); testST(beforeBC, -14, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d)); testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d)); testST(beforeBC, -16, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d)); testST(beforeBC, -17, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d)); testST(beforeBC, -18, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d)); testST(beforeBC, -19, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d)); testST(beforeBC, -20, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d)); testST(beforeBC, -21, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d)); testST(beforeBC, -22, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d)); testST(beforeBC, -23, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d)); testST(beforeBC, -24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, -25, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d)); testST(beforeBC, -50, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d)); testST(beforeBC, -10_000, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d)); testST(SysTime(DateTime(-1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 31, 0, 30, 33), d)); testST(SysTime(DateTime(-1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 8, 1, 23, 30, 33), d)); testST(SysTime(DateTime(-2001, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(-2001, 12, 31, 0, 30, 33), d)); testST(SysTime(DateTime(-2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(-2000, 1, 1, 23, 30, 33), d)); testST(SysTime(DateTime(-2001, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2001, 2, 28, 0, 30, 33), d)); testST(SysTime(DateTime(-2001, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(-2001, 3, 2, 23, 30, 33), d)); testST(SysTime(DateTime(-2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2000, 2, 28, 0, 30, 33), d)); testST(SysTime(DateTime(-2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(-2000, 3, 1, 23, 30, 33), d)); //Test Both testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 17_546, SysTime(DateTime(-1, 1, 1, 13, 30, 33), d)); testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -17_546, SysTime(DateTime(1, 1, 1, 11, 30, 33), d)); { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.roll!"hours"(-1); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 0, 0))); sysTime.roll!"hours"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)); sysTime.roll!"hours"(-1); assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); sysTime.roll!"hours"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 0, 0)); sysTime.roll!"hours"(1); assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0))); sysTime.roll!"hours"(-1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"hours"(1); assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 59, 59), hnsecs(9_999_999))); sysTime.roll!"hours"(-1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"hours"(1).roll!"hours"(-67); assert(sysTime == SysTime(DateTime(0, 12, 31, 5, 59, 59), hnsecs(9_999_999))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.roll!"hours"(4))); //static assert(!__traits(compiles, ist.roll!"hours"(4))); } //Test roll!"minutes"(). unittest { static void testST(SysTime orig, int minutes, in SysTime expected, size_t line = __LINE__) { import std.format : format; orig.roll!"minutes"(minutes); if(orig != expected) throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line); } //Test A.D. immutable d = usecs(7203); auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d); testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d)); testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 32, 33), d)); testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 33, 33), d)); testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 34, 33), d)); testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 35, 33), d)); testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 40, 33), d)); testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d)); testST(beforeAD, 29, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d)); testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d)); testST(beforeAD, 45, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d)); testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, 75, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d)); testST(beforeAD, 90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d)); testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 10, 33), d)); testST(beforeAD, 689, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d)); testST(beforeAD, 690, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d)); testST(beforeAD, 691, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d)); testST(beforeAD, 960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, 1439, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d)); testST(beforeAD, 1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, 1441, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d)); testST(beforeAD, 2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d)); testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 28, 33), d)); testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 27, 33), d)); testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 26, 33), d)); testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 25, 33), d)); testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 20, 33), d)); testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d)); testST(beforeAD, -29, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d)); testST(beforeAD, -30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d)); testST(beforeAD, -45, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d)); testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, -75, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d)); testST(beforeAD, -90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d)); testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 50, 33), d)); testST(beforeAD, -749, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d)); testST(beforeAD, -750, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d)); testST(beforeAD, -751, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d)); testST(beforeAD, -960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, -1439, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d)); testST(beforeAD, -1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, -1441, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d)); testST(beforeAD, -2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(1999, 7, 6, 11, 0, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(1999, 7, 6, 11, 59, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(1999, 7, 6, 11, 58, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 1, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 33), d)); testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 0, 59, 33), d)); testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(1999, 7, 5, 23, 0, 33), d)); testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 33), d)); testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(1999, 7, 5, 23, 58, 33), d)); testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(1998, 12, 31, 23, 0, 33), d)); testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 33), d)); testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(1998, 12, 31, 23, 58, 33), d)); //Test B.C. auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d); testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d)); testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 32, 33), d)); testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 33, 33), d)); testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 34, 33), d)); testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 35, 33), d)); testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 40, 33), d)); testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d)); testST(beforeBC, 29, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d)); testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d)); testST(beforeBC, 45, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d)); testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, 75, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d)); testST(beforeBC, 90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d)); testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 10, 33), d)); testST(beforeBC, 689, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d)); testST(beforeBC, 690, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d)); testST(beforeBC, 691, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d)); testST(beforeBC, 960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, 1439, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d)); testST(beforeBC, 1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, 1441, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d)); testST(beforeBC, 2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d)); testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 28, 33), d)); testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 27, 33), d)); testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 26, 33), d)); testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 25, 33), d)); testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 20, 33), d)); testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d)); testST(beforeBC, -29, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d)); testST(beforeBC, -30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d)); testST(beforeBC, -45, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d)); testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, -75, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d)); testST(beforeBC, -90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d)); testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 50, 33), d)); testST(beforeBC, -749, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d)); testST(beforeBC, -750, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d)); testST(beforeBC, -751, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d)); testST(beforeBC, -960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, -1439, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d)); testST(beforeBC, -1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, -1441, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d)); testST(beforeBC, -2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 11, 0, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 11, 58, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 1, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d)); testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 59, 33), d)); testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 0, 33), d)); testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d)); testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 58, 33), d)); testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 0, 33), d)); testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d)); testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 58, 33), d)); //Test Both testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(1, 1, 1, 0, 59, 0))); testST(SysTime(DateTime(0, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(0, 12, 31, 23, 0, 0))); testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(0, 1, 1, 0, 59, 0))); testST(SysTime(DateTime(-1, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(-1, 12, 31, 23, 0, 0))); testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_760, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d)); testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -1_052_760, SysTime(DateTime(1, 1, 1, 13, 30, 33), d)); testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_782, SysTime(DateTime(-1, 1, 1, 11, 52, 33), d)); testST(SysTime(DateTime(1, 1, 1, 13, 52, 33), d), -1_052_782, SysTime(DateTime(1, 1, 1, 13, 30, 33), d)); { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.roll!"minutes"(-1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 0))); sysTime.roll!"minutes"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)); sysTime.roll!"minutes"(-1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999))); sysTime.roll!"minutes"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 0)); sysTime.roll!"minutes"(1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0))); sysTime.roll!"minutes"(-1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"minutes"(1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 59), hnsecs(9_999_999))); sysTime.roll!"minutes"(-1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"minutes"(1).roll!"minutes"(-79); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 41, 59), hnsecs(9_999_999))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.roll!"minutes"(4))); //static assert(!__traits(compiles, ist.roll!"minutes"(4))); } //Test roll!"seconds"(). unittest { static void testST(SysTime orig, int seconds, in SysTime expected, size_t line = __LINE__) { import std.format : format; orig.roll!"seconds"(seconds); if(orig != expected) throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line); } //Test A.D. immutable d = msecs(274); auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d); testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d)); testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 35), d)); testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 30, 36), d)); testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 30, 37), d)); testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 30, 38), d)); testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 43), d)); testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 30, 48), d)); testST(beforeAD, 26, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d)); testST(beforeAD, 27, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d)); testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 30, 3), d)); testST(beforeAD, 59, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d)); testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, 61, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d)); testST(beforeAD, 1766, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d)); testST(beforeAD, 1767, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d)); testST(beforeAD, 1768, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d)); testST(beforeAD, 2007, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d)); testST(beforeAD, 3599, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d)); testST(beforeAD, 3600, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, 3601, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d)); testST(beforeAD, 7200, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d)); testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 31), d)); testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 30, 30), d)); testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 30, 29), d)); testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 30, 28), d)); testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 23), d)); testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 30, 18), d)); testST(beforeAD, -33, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d)); testST(beforeAD, -34, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d)); testST(beforeAD, -35, SysTime(DateTime(1999, 7, 6, 12, 30, 58), d)); testST(beforeAD, -59, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d)); testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d)); testST(beforeAD, -61, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d)); testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d)); testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d)); testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d)); testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 0, 1), d)); testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 0), d)); testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 0, 59), d)); testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 0, 0, 1), d)); testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 0), d)); testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 0, 0, 59), d)); testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(1999, 7, 5, 23, 59, 0), d)); testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 59), d)); testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(1999, 7, 5, 23, 59, 58), d)); testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(1998, 12, 31, 23, 59, 0), d)); testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 59), d)); testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(1998, 12, 31, 23, 59, 58), d)); //Test B.C. auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d); testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d)); testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 35), d)); testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 30, 36), d)); testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 30, 37), d)); testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 30, 38), d)); testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 43), d)); testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 30, 48), d)); testST(beforeBC, 26, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d)); testST(beforeBC, 27, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d)); testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 30, 3), d)); testST(beforeBC, 59, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d)); testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, 61, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d)); testST(beforeBC, 1766, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d)); testST(beforeBC, 1767, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d)); testST(beforeBC, 1768, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d)); testST(beforeBC, 2007, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d)); testST(beforeBC, 3599, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d)); testST(beforeBC, 3600, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, 3601, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d)); testST(beforeBC, 7200, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d)); testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 31), d)); testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 30, 30), d)); testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 30, 29), d)); testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 30, 28), d)); testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 23), d)); testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 30, 18), d)); testST(beforeBC, -33, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d)); testST(beforeBC, -34, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d)); testST(beforeBC, -35, SysTime(DateTime(-1999, 7, 6, 12, 30, 58), d)); testST(beforeBC, -59, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d)); testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d)); testST(beforeBC, -61, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d)); testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d)); testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d)); testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d)); testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 0, 1), d)); testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d)); testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 0, 59), d)); testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 0, 1), d)); testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d)); testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 0, 59), d)); testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 59, 0), d)); testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d)); testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 59, 58), d)); testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 59, 0), d)); testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d)); testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 59, 58), d)); //Test Both testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(1, 1, 1, 0, 0, 59), d)); testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(0, 12, 31, 23, 59, 0), d)); testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(0, 1, 1, 0, 0, 59), d)); testST(SysTime(DateTime(-1, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-1, 12, 31, 23, 59, 0), d)); testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_600L, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d)); testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -63_165_600L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d)); testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_617L, SysTime(DateTime(-1, 1, 1, 11, 30, 50), d)); testST(SysTime(DateTime(1, 1, 1, 13, 30, 50), d), -63_165_617L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d)); { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0)); sysTime.roll!"seconds"(-1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59))); sysTime.roll!"seconds"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0))); } { auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)); sysTime.roll!"seconds"(-1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999))); sysTime.roll!"seconds"(1); assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59)); sysTime.roll!"seconds"(1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0))); sysTime.roll!"seconds"(-1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"seconds"(1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0), hnsecs(9_999_999))); sysTime.roll!"seconds"(-1); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); } { auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); sysTime.roll!"seconds"(1).roll!"seconds"(-102); assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 18), hnsecs(9_999_999))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.roll!"seconds"(4))); //static assert(!__traits(compiles, ist.roll!"seconds"(4))); } //Shares documentation with "days" version. ref SysTime roll(string units)(long value) @safe nothrow if(units == "msecs" || units == "usecs" || units == "hnsecs") { auto hnsecs = adjTime; immutable days = splitUnitsFromHNSecs!"days"(hnsecs); immutable negative = hnsecs < 0; if(negative) hnsecs += convert!("hours", "hnsecs")(24); immutable seconds = splitUnitsFromHNSecs!"seconds"(hnsecs); hnsecs += convert!(units, "hnsecs")(value); hnsecs %= convert!("seconds", "hnsecs")(1); if(hnsecs < 0) hnsecs += convert!("seconds", "hnsecs")(1); hnsecs += convert!("seconds", "hnsecs")(seconds); if(negative) hnsecs -= convert!("hours", "hnsecs")(24); immutable newDaysHNSecs = convert!("days", "hnsecs")(days); adjTime = newDaysHNSecs + hnsecs; return this; } //Test roll!"msecs"(). unittest { static void testST(SysTime orig, int milliseconds, in SysTime expected, size_t line = __LINE__) { import std.format : format; orig.roll!"msecs"(milliseconds); if(orig != expected) throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line); } //Test A.D. auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)); testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275))); testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(276))); testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(284))); testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(374))); testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33))); testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275))); testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33))); testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(1))); testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33))); testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273))); testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(272))); testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(264))); testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(174))); testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33))); testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273))); testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33))); testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33))); testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999))); //Test B.C. auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)); testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275))); testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(276))); testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(284))); testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(374))); testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275))); testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(1))); testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273))); testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(272))); testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(264))); testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(174))); testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273))); testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274))); testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999))); testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999))); //Test Both auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0)); testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(1))); testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(999))); testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(998))); testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(445))); auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_989_999))); testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999))); testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999))); testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(5_549_999))); { auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); st.roll!"msecs"(1202).roll!"msecs"(-703); assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(4_989_999))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.addMSecs(4))); //static assert(!__traits(compiles, ist.addMSecs(4))); } //Test roll!"usecs"(). unittest { static void testST(SysTime orig, long microseconds, in SysTime expected, size_t line = __LINE__) { import std.format : format; orig.roll!"usecs"(microseconds); if(orig != expected) throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line); } //Test A.D. auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)); testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(275))); testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(276))); testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(284))); testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(374))); testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999))); testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1000))); testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1274))); testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1275))); testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(2274))); testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(26_999))); testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_000))); testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_001))); testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(766_999))); testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(767_000))); testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(273))); testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(272))); testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(264))); testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(174))); testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33))); testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_999))); testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_274))); testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_273))); testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(998_274))); testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(967_000))); testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(966_999))); testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(167_000))); testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(166_999))); testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274))); //Test B.C. auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)); testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(275))); testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(276))); testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(284))); testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(374))); testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999))); testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1000))); testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1274))); testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1275))); testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(2274))); testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(26_999))); testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_000))); testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_001))); testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(766_999))); testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(767_000))); testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(273))); testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(272))); testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(264))); testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(174))); testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_999))); testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_274))); testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_273))); testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(998_274))); testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(967_000))); testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(966_999))); testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(167_000))); testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(166_999))); testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274))); testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274))); //Test Both auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0)); testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(1))); testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_999))); testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_998))); testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_000))); testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(998_000))); testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(997_445))); testST(beforeBoth1, -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth1, -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth1, -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(666_667))); auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_989))); testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9))); testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19))); testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999))); testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999))); testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(25_549))); testST(beforeBoth2, 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth2, 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth2, 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(3_333_329))); { auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); st.roll!"usecs"(9_020_027); assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(200_269))); } { auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); st.roll!"usecs"(9_020_027).roll!"usecs"(-70_034); assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_499_929))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.roll!"usecs"(4))); //static assert(!__traits(compiles, ist.roll!"usecs"(4))); } //Test roll!"hnsecs"(). unittest { static void testST(SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__) { import std.format : format; orig.roll!"hnsecs"(hnsecs); if(orig != expected) throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line); } //Test A.D. auto dtAD = DateTime(1999, 7, 6, 12, 30, 33); auto beforeAD = SysTime(dtAD, hnsecs(274)); testST(beforeAD, 0, SysTime(dtAD, hnsecs(274))); testST(beforeAD, 1, SysTime(dtAD, hnsecs(275))); testST(beforeAD, 2, SysTime(dtAD, hnsecs(276))); testST(beforeAD, 10, SysTime(dtAD, hnsecs(284))); testST(beforeAD, 100, SysTime(dtAD, hnsecs(374))); testST(beforeAD, 725, SysTime(dtAD, hnsecs(999))); testST(beforeAD, 726, SysTime(dtAD, hnsecs(1000))); testST(beforeAD, 1000, SysTime(dtAD, hnsecs(1274))); testST(beforeAD, 1001, SysTime(dtAD, hnsecs(1275))); testST(beforeAD, 2000, SysTime(dtAD, hnsecs(2274))); testST(beforeAD, 26_725, SysTime(dtAD, hnsecs(26_999))); testST(beforeAD, 26_726, SysTime(dtAD, hnsecs(27_000))); testST(beforeAD, 26_727, SysTime(dtAD, hnsecs(27_001))); testST(beforeAD, 1_766_725, SysTime(dtAD, hnsecs(1_766_999))); testST(beforeAD, 1_766_726, SysTime(dtAD, hnsecs(1_767_000))); testST(beforeAD, 1_000_000, SysTime(dtAD, hnsecs(1_000_274))); testST(beforeAD, 60_000_000L, SysTime(dtAD, hnsecs(274))); testST(beforeAD, 3_600_000_000L, SysTime(dtAD, hnsecs(274))); testST(beforeAD, 600_000_000L, SysTime(dtAD, hnsecs(274))); testST(beforeAD, 36_000_000_000L, SysTime(dtAD, hnsecs(274))); testST(beforeAD, -1, SysTime(dtAD, hnsecs(273))); testST(beforeAD, -2, SysTime(dtAD, hnsecs(272))); testST(beforeAD, -10, SysTime(dtAD, hnsecs(264))); testST(beforeAD, -100, SysTime(dtAD, hnsecs(174))); testST(beforeAD, -274, SysTime(dtAD)); testST(beforeAD, -275, SysTime(dtAD, hnsecs(9_999_999))); testST(beforeAD, -1000, SysTime(dtAD, hnsecs(9_999_274))); testST(beforeAD, -1001, SysTime(dtAD, hnsecs(9_999_273))); testST(beforeAD, -2000, SysTime(dtAD, hnsecs(9_998_274))); testST(beforeAD, -33_274, SysTime(dtAD, hnsecs(9_967_000))); testST(beforeAD, -33_275, SysTime(dtAD, hnsecs(9_966_999))); testST(beforeAD, -1_833_274, SysTime(dtAD, hnsecs(8_167_000))); testST(beforeAD, -1_833_275, SysTime(dtAD, hnsecs(8_166_999))); testST(beforeAD, -1_000_000, SysTime(dtAD, hnsecs(9_000_274))); testST(beforeAD, -60_000_000L, SysTime(dtAD, hnsecs(274))); testST(beforeAD, -3_600_000_000L, SysTime(dtAD, hnsecs(274))); testST(beforeAD, -600_000_000L, SysTime(dtAD, hnsecs(274))); testST(beforeAD, -36_000_000_000L, SysTime(dtAD, hnsecs(274))); //Test B.C. auto dtBC = DateTime(-1999, 7, 6, 12, 30, 33); auto beforeBC = SysTime(dtBC, hnsecs(274)); testST(beforeBC, 0, SysTime(dtBC, hnsecs(274))); testST(beforeBC, 1, SysTime(dtBC, hnsecs(275))); testST(beforeBC, 2, SysTime(dtBC, hnsecs(276))); testST(beforeBC, 10, SysTime(dtBC, hnsecs(284))); testST(beforeBC, 100, SysTime(dtBC, hnsecs(374))); testST(beforeBC, 725, SysTime(dtBC, hnsecs(999))); testST(beforeBC, 726, SysTime(dtBC, hnsecs(1000))); testST(beforeBC, 1000, SysTime(dtBC, hnsecs(1274))); testST(beforeBC, 1001, SysTime(dtBC, hnsecs(1275))); testST(beforeBC, 2000, SysTime(dtBC, hnsecs(2274))); testST(beforeBC, 26_725, SysTime(dtBC, hnsecs(26_999))); testST(beforeBC, 26_726, SysTime(dtBC, hnsecs(27_000))); testST(beforeBC, 26_727, SysTime(dtBC, hnsecs(27_001))); testST(beforeBC, 1_766_725, SysTime(dtBC, hnsecs(1_766_999))); testST(beforeBC, 1_766_726, SysTime(dtBC, hnsecs(1_767_000))); testST(beforeBC, 1_000_000, SysTime(dtBC, hnsecs(1_000_274))); testST(beforeBC, 60_000_000L, SysTime(dtBC, hnsecs(274))); testST(beforeBC, 3_600_000_000L, SysTime(dtBC, hnsecs(274))); testST(beforeBC, 600_000_000L, SysTime(dtBC, hnsecs(274))); testST(beforeBC, 36_000_000_000L, SysTime(dtBC, hnsecs(274))); testST(beforeBC, -1, SysTime(dtBC, hnsecs(273))); testST(beforeBC, -2, SysTime(dtBC, hnsecs(272))); testST(beforeBC, -10, SysTime(dtBC, hnsecs(264))); testST(beforeBC, -100, SysTime(dtBC, hnsecs(174))); testST(beforeBC, -274, SysTime(dtBC)); testST(beforeBC, -275, SysTime(dtBC, hnsecs(9_999_999))); testST(beforeBC, -1000, SysTime(dtBC, hnsecs(9_999_274))); testST(beforeBC, -1001, SysTime(dtBC, hnsecs(9_999_273))); testST(beforeBC, -2000, SysTime(dtBC, hnsecs(9_998_274))); testST(beforeBC, -33_274, SysTime(dtBC, hnsecs(9_967_000))); testST(beforeBC, -33_275, SysTime(dtBC, hnsecs(9_966_999))); testST(beforeBC, -1_833_274, SysTime(dtBC, hnsecs(8_167_000))); testST(beforeBC, -1_833_275, SysTime(dtBC, hnsecs(8_166_999))); testST(beforeBC, -1_000_000, SysTime(dtBC, hnsecs(9_000_274))); testST(beforeBC, -60_000_000L, SysTime(dtBC, hnsecs(274))); testST(beforeBC, -3_600_000_000L, SysTime(dtBC, hnsecs(274))); testST(beforeBC, -600_000_000L, SysTime(dtBC, hnsecs(274))); testST(beforeBC, -36_000_000_000L, SysTime(dtBC, hnsecs(274))); //Test Both auto dtBoth1 = DateTime(1, 1, 1, 0, 0, 0); auto beforeBoth1 = SysTime(dtBoth1); testST(beforeBoth1, 1, SysTime(dtBoth1, hnsecs(1))); testST(beforeBoth1, 0, SysTime(dtBoth1)); testST(beforeBoth1, -1, SysTime(dtBoth1, hnsecs(9_999_999))); testST(beforeBoth1, -2, SysTime(dtBoth1, hnsecs(9_999_998))); testST(beforeBoth1, -1000, SysTime(dtBoth1, hnsecs(9_999_000))); testST(beforeBoth1, -2000, SysTime(dtBoth1, hnsecs(9_998_000))); testST(beforeBoth1, -2555, SysTime(dtBoth1, hnsecs(9_997_445))); testST(beforeBoth1, -1_000_000, SysTime(dtBoth1, hnsecs(9_000_000))); testST(beforeBoth1, -2_000_000, SysTime(dtBoth1, hnsecs(8_000_000))); testST(beforeBoth1, -2_333_333, SysTime(dtBoth1, hnsecs(7_666_667))); testST(beforeBoth1, -10_000_000, SysTime(dtBoth1)); testST(beforeBoth1, -20_000_000, SysTime(dtBoth1)); testST(beforeBoth1, -20_888_888, SysTime(dtBoth1, hnsecs(9_111_112))); auto dtBoth2 = DateTime(0, 12, 31, 23, 59, 59); auto beforeBoth2 = SysTime(dtBoth2, hnsecs(9_999_999)); testST(beforeBoth2, -1, SysTime(dtBoth2, hnsecs(9_999_998))); testST(beforeBoth2, 0, SysTime(dtBoth2, hnsecs(9_999_999))); testST(beforeBoth2, 1, SysTime(dtBoth2)); testST(beforeBoth2, 2, SysTime(dtBoth2, hnsecs(1))); testST(beforeBoth2, 1000, SysTime(dtBoth2, hnsecs(999))); testST(beforeBoth2, 2000, SysTime(dtBoth2, hnsecs(1999))); testST(beforeBoth2, 2555, SysTime(dtBoth2, hnsecs(2554))); testST(beforeBoth2, 1_000_000, SysTime(dtBoth2, hnsecs(999_999))); testST(beforeBoth2, 2_000_000, SysTime(dtBoth2, hnsecs(1_999_999))); testST(beforeBoth2, 2_333_333, SysTime(dtBoth2, hnsecs(2_333_332))); testST(beforeBoth2, 10_000_000, SysTime(dtBoth2, hnsecs(9_999_999))); testST(beforeBoth2, 20_000_000, SysTime(dtBoth2, hnsecs(9_999_999))); testST(beforeBoth2, 20_888_888, SysTime(dtBoth2, hnsecs(888_887))); { auto st = SysTime(dtBoth2, hnsecs(9_999_999)); st.roll!"hnsecs"(70_777_222).roll!"hnsecs"(-222_555_292); assert(st == SysTime(dtBoth2, hnsecs(8_221_929))); } const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.roll!"hnsecs"(4))); //static assert(!__traits(compiles, ist.roll!"hnsecs"(4))); } /++ Gives the result of adding or subtracting a $(CXREF time, Duration) from this $(LREF SysTime). The legal types of arithmetic for $(LREF SysTime) using this operator are $(BOOKTABLE, $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime)) $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime)) ) Params: duration = The $(CXREF time, Duration) to add to or subtract from this $(LREF SysTime). +/ SysTime opBinary(string op)(Duration duration) @safe const pure nothrow if(op == "+" || op == "-") { SysTime retval = SysTime(this._stdTime, this._timezone); immutable hnsecs = duration.total!"hnsecs"; mixin("retval._stdTime " ~ op ~ "= hnsecs;"); return retval; } /// unittest { assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) == SysTime(DateTime(2016, 1, 1, 0, 0, 0))); assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) == SysTime(DateTime(2016, 1, 1, 0, 59, 59))); assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) == SysTime(DateTime(2015, 12, 31, 23, 59, 59))); assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) == SysTime(DateTime(2015, 12, 31, 23, 59, 59))); } unittest { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678)); assert(st + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678))); assert(st + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678))); assert(st + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678))); assert(st + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678))); assert(st + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678))); assert(st + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678))); assert(st + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678))); assert(st + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678))); assert(st + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678))); assert(st + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678))); assert(st + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678))); assert(st + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678))); assert(st + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748))); assert(st + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608))); assert(st + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685))); assert(st + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671))); assert(st - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678))); assert(st - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678))); assert(st - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678))); assert(st - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678))); assert(st - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678))); assert(st - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678))); assert(st - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678))); assert(st - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678))); assert(st - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678))); assert(st - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678))); assert(st - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678))); assert(st - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678))); assert(st - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748))); assert(st - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608))); assert(st - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685))); assert(st - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671))); static void testST(in SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__) { import std.format : format; auto result = orig + dur!"hnsecs"(hnsecs); if(result != expected) throw new AssertError(format("Failed. actual [%s] != expected [%s]", result, expected), __FILE__, line); } //Test A.D. auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)); testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274))); testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275))); testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276))); testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284))); testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374))); testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999))); testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000))); testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274))); testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275))); testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274))); testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999))); testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000))); testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001))); testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999))); testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000))); testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274))); testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274))); testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274))); testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274))); testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274))); testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273))); testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272))); testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264))); testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174))); testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33))); testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999))); testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274))); testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273))); testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274))); testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000))); testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999))); testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000))); testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999))); testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274))); testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274))); testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274))); testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274))); testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274))); //Test B.C. auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)); testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274))); testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275))); testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276))); testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284))); testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374))); testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999))); testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000))); testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274))); testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275))); testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274))); testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999))); testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000))); testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001))); testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999))); testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000))); testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274))); testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274))); testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274))); testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274))); testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274))); testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273))); testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272))); testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264))); testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174))); testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999))); testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274))); testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273))); testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274))); testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000))); testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999))); testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000))); testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999))); testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274))); testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274))); testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274))); testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274))); testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274))); //Test Both auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0)); testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1))); testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998))); testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000))); testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000))); testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445))); testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000))); testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000))); testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667))); testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59))); testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58))); testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112))); auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998))); testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1))); testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999))); testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999))); testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554))); testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999))); testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999))); testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332))); testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999))); testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999))); testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887))); auto duration = dur!"seconds"(12); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45))); //assert(ist + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45))); assert(cst - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21))); //assert(ist - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21))); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime) and $(CXREF time, Duration). Use $(D Duration) instead. This overload will be removed in January 2017.) Defines + and - with $(CXREF time, TickDuration). +/ deprecated("Use Duration instead of TickDuration.") SysTime opBinary(string op)(TickDuration td) @safe const pure nothrow if(op == "+" || op == "-") { SysTime retval = SysTime(this._stdTime, this._timezone); immutable hnsecs = td.hnsecs; mixin("retval._stdTime " ~ op ~ "= hnsecs;"); return retval; } deprecated unittest { //This probably only runs in cases where gettimeofday() is used, but it's //hard to do this test correctly with variable ticksPerSec. if(TickDuration.ticksPerSec == 1_000_000) { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678)); assert(st + TickDuration.from!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748))); assert(st + TickDuration.from!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608))); assert(st - TickDuration.from!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748))); assert(st - TickDuration.from!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608))); } } /++ Gives the result of adding or subtracting a $(CXREF time, Duration) from this $(LREF SysTime), as well as assigning the result to this $(LREF SysTime). The legal types of arithmetic for $(LREF SysTime) using this operator are $(BOOKTABLE, $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime)) $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime)) ) Params: duration = The $(CXREF time, Duration) to add to or subtract from this $(LREF SysTime). +/ ref SysTime opOpAssign(string op)(Duration duration) @safe pure nothrow if(op == "+" || op == "-") { immutable hnsecs = duration.total!"hnsecs"; mixin("_stdTime " ~ op ~ "= hnsecs;"); return this; } unittest { auto before = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(before + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33))); assert(before + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33))); assert(before + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33))); assert(before + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33))); assert(before + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33))); assert(before + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33))); assert(before + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33))); assert(before + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33))); assert(before + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40))); assert(before + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26))); assert(before + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7))); assert(before + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993))); assert(before + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7))); assert(before + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993))); assert(before + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7))); assert(before + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993))); assert(before - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33))); assert(before - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33))); assert(before - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33))); assert(before - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33))); assert(before - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33))); assert(before - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33))); assert(before - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33))); assert(before - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33))); assert(before - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40))); assert(before - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26))); assert(before - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7))); assert(before - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993))); assert(before - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7))); assert(before - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993))); assert(before - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7))); assert(before - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993))); static void testST(SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__) { import std.format : format; auto r = orig += dur!"hnsecs"(hnsecs); if(orig != expected) throw new AssertError(format("Failed 1. actual [%s] != expected [%s]", orig, expected), __FILE__, line); if(r != expected) throw new AssertError(format("Failed 2. actual [%s] != expected [%s]", r, expected), __FILE__, line); } //Test A.D. auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)); testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274))); testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275))); testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276))); testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284))); testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374))); testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999))); testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000))); testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274))); testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275))); testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274))); testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999))); testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000))); testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001))); testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999))); testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000))); testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274))); testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274))); testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274))); testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274))); testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274))); testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273))); testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272))); testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264))); testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174))); testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33))); testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999))); testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274))); testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273))); testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274))); testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000))); testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999))); testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000))); testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999))); testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274))); testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274))); testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274))); testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274))); testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274))); //Test B.C. auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)); testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274))); testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275))); testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276))); testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284))); testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374))); testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999))); testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000))); testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274))); testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275))); testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274))); testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999))); testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000))); testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001))); testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999))); testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000))); testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274))); testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274))); testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274))); testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274))); testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274))); testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273))); testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272))); testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264))); testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174))); testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999))); testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274))); testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273))); testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274))); testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000))); testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999))); testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000))); testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999))); testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274))); testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274))); testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274))); testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274))); testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274))); //Test Both auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0)); testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1))); testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998))); testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000))); testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000))); testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445))); testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000))); testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000))); testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667))); testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59))); testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58))); testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112))); auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998))); testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1))); testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999))); testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999))); testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554))); testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999))); testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999))); testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332))); testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999))); testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999))); testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887))); { auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)); (st += dur!"hnsecs"(52)) += dur!"seconds"(-907); assert(st == SysTime(DateTime(0, 12, 31, 23, 44, 53), hnsecs(51))); } auto duration = dur!"seconds"(12); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst += duration)); //static assert(!__traits(compiles, ist += duration)); static assert(!__traits(compiles, cst -= duration)); //static assert(!__traits(compiles, ist -= duration)); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime) and $(CXREF time, Duration). Use $(D Duration) instead. This overload will be removed in January 2017.) Defines += and -= with $(CXREF time, TickDuration). +/ deprecated("Use Duration instead of TickDuration.") ref SysTime opOpAssign(string op)(TickDuration td) @safe pure nothrow if(op == "+" || op == "-") { immutable hnsecs = td.hnsecs; mixin("_stdTime " ~ op ~ "= hnsecs;"); return this; } deprecated unittest { //This probably only runs in cases where gettimeofday() is used, but it's //hard to do this test correctly with variable ticksPerSec. if(TickDuration.ticksPerSec == 1_000_000) { { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678)); st += TickDuration.from!"usecs"(7); assert(st == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748))); } { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678)); st += TickDuration.from!"usecs"(-7); assert(st == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608))); } { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678)); st -= TickDuration.from!"usecs"(-7); assert(st == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748))); } { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678)); st -= TickDuration.from!"usecs"(7); assert(st == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608))); } } } /++ Gives the difference between two $(LREF SysTime)s. The legal types of arithmetic for $(LREF SysTime) using this operator are $(BOOKTABLE, $(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration)) ) +/ Duration opBinary(string op)(in SysTime rhs) @safe const pure nothrow if(op == "-") { return dur!"hnsecs"(_stdTime - rhs._stdTime); } unittest { assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)) == dur!"seconds"(31_536_000)); assert(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) == dur!"seconds"(-31_536_000)); assert(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) == dur!"seconds"(26_78_400)); assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)) == dur!"seconds"(-26_78_400)); assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)) == dur!"seconds"(86_400)); assert(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) == dur!"seconds"(-86_400)); assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)) == dur!"seconds"(3600)); assert(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) == dur!"seconds"(-3600)); assert(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) == dur!"seconds"(60)); assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)) == dur!"seconds"(-60)); assert(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) == dur!"seconds"(1)); assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)) == dur!"seconds"(-1)); { auto dt = DateTime(1999, 7, 6, 12, 30, 33); assert(SysTime(dt, msecs(532)) - SysTime(dt) == msecs(532)); assert(SysTime(dt) - SysTime(dt, msecs(532)) == msecs(-532)); assert(SysTime(dt, usecs(333_347)) - SysTime(dt) == usecs(333_347)); assert(SysTime(dt) - SysTime(dt, usecs(333_347)) == usecs(-333_347)); assert(SysTime(dt, hnsecs(1_234_567)) - SysTime(dt) == hnsecs(1_234_567)); assert(SysTime(dt) - SysTime(dt, hnsecs(1_234_567)) == hnsecs(-1_234_567)); } assert(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(45033)); assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)) == dur!"seconds"(-45033)); assert(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(-41367)); assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)) == dur!"seconds"(41367)); assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) == dur!"hnsecs"(1)); assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"hnsecs"(-1)); auto tz = TimeZone.getTimeZone("America/Los_Angeles"); { auto dt = DateTime(2011, 1, 13, 8, 17, 2); auto d = msecs(296); assert(SysTime(dt, d, tz) - SysTime(dt, d, tz) == Duration.zero); assert(SysTime(dt, d, tz) - SysTime(dt, d, UTC()) == hours(8)); assert(SysTime(dt, d, UTC()) - SysTime(dt, d, tz) == hours(-8)); } auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(st - st == Duration.zero); assert(cst - st == Duration.zero); //assert(ist - st == Duration.zero); assert(st - cst == Duration.zero); assert(cst - cst == Duration.zero); //assert(ist - cst == Duration.zero); //assert(st - ist == Duration.zero); //assert(cst - ist == Duration.zero); //assert(ist - ist == Duration.zero); } /++ Returns the difference between the two $(LREF SysTime)s in months. To get the difference in years, subtract the year property of two $(LREF SysTime)s. To get the difference in days or weeks, subtract the $(LREF SysTime)s themselves and use the $(CXREF time, Duration) that results. Because converting between months and smaller units requires a specific date (which $(CXREF time, Duration)s don't have), getting the difference in months requires some math using both the year and month properties, so this is a convenience function for getting the difference in months. Note that the number of days in the months or how far into the month either date is is irrelevant. It is the difference in the month property combined with the difference in years * 12. So, for instance, December 31st and January 1st are one month apart just as December 1st and January 31st are one month apart. Params: rhs = The $(LREF SysTime) to subtract from this one. +/ int diffMonths(in SysTime rhs) @safe const nothrow { return (cast(Date)this).diffMonths(cast(Date)rhs); } /// unittest { assert(SysTime(Date(1999, 2, 1)).diffMonths( SysTime(Date(1999, 1, 31))) == 1); assert(SysTime(Date(1999, 1, 31)).diffMonths( SysTime(Date(1999, 2, 1))) == -1); assert(SysTime(Date(1999, 3, 1)).diffMonths( SysTime(Date(1999, 1, 1))) == 2); assert(SysTime(Date(1999, 1, 1)).diffMonths( SysTime(Date(1999, 3, 31))) == -2); } unittest { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(st.diffMonths(st) == 0); assert(cst.diffMonths(st) == 0); //assert(ist.diffMonths(st) == 0); assert(st.diffMonths(cst) == 0); assert(cst.diffMonths(cst) == 0); //assert(ist.diffMonths(cst) == 0); //assert(st.diffMonths(ist) == 0); //assert(cst.diffMonths(ist) == 0); //assert(ist.diffMonths(ist) == 0); } /++ Whether this $(LREF SysTime) is in a leap year. +/ @property bool isLeapYear() @safe const nothrow { return (cast(Date)this).isLeapYear; } unittest { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(!st.isLeapYear); assert(!cst.isLeapYear); //assert(!ist.isLeapYear); } /++ Day of the week this $(LREF SysTime) is on. +/ @property DayOfWeek dayOfWeek() @safe const nothrow { return getDayOfWeek(dayOfGregorianCal); } unittest { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(st.dayOfWeek == DayOfWeek.tue); assert(cst.dayOfWeek == DayOfWeek.tue); //assert(ist.dayOfWeek == DayOfWeek.tue); } /++ Day of the year this $(LREF SysTime) is on. +/ @property ushort dayOfYear() @safe const nothrow { return (cast(Date)this).dayOfYear; } /// unittest { assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1); assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365); assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366); } unittest { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(st.dayOfYear == 187); assert(cst.dayOfYear == 187); //assert(ist.dayOfYear == 187); } /++ Day of the year. Params: day = The day of the year to set which day of the year this $(LREF SysTime) is on. +/ @property void dayOfYear(int day) @safe { immutable hnsecs = adjTime; immutable days = convert!("hnsecs", "days")(hnsecs); immutable theRest = hnsecs - convert!("days", "hnsecs")(days); auto date = Date(cast(int)days); date.dayOfYear = day; immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1); adjTime = newDaysHNSecs + theRest; } unittest { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); st.dayOfYear = 12; assert(st.dayOfYear == 12); static assert(!__traits(compiles, cst.dayOfYear = 12)); //static assert(!__traits(compiles, ist.dayOfYear = 12)); } /++ The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on. +/ @property int dayOfGregorianCal() @safe const nothrow { immutable adjustedTime = adjTime; //We have to add one because 0 would be midnight, January 1st, 1 A.D., //which would be the 1st day of the Gregorian Calendar, not the 0th. So, //simply casting to days is one day off. if(adjustedTime > 0) return cast(int)getUnitsFromHNSecs!"days"(adjustedTime) + 1; long hnsecs = adjustedTime; immutable days = cast(int)splitUnitsFromHNSecs!"days"(hnsecs); return hnsecs == 0 ? days + 1 : days; } /// unittest { assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1); assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365); assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366); assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0); assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365); assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366); assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120); assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137); } unittest { //Test A.D. assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1); assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 1); assert(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 1); assert(SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1); assert(SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)).dayOfGregorianCal == 2); assert(SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 32); assert(SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 366); assert(SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 731); assert(SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1096); assert(SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1462); assert(SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 17_898); assert(SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 35_065); assert(SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_160); assert(SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_525); assert(SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 37_986); assert(SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 72_684); assert(SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 73_049); assert(SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_208); assert(SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_573); assert(SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 145_732); assert(SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 146_098); assert(SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_257); assert(SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_622); assert(SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 364_878); assert(SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 365_243); assert(SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_023); assert(SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_389); assert(SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_596); assert(SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_961); assert(SysTime(DateTime(1945, 11, 12, 12, 2, 9), msecs(212)).dayOfGregorianCal == 710_347); assert(SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 729_755); assert(SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_120); assert(SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_486); assert(SysTime(DateTime(2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_773); assert(SysTime(DateTime(2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_803); assert(SysTime(DateTime(2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_804); assert(SysTime(DateTime(2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_831); assert(SysTime(DateTime(2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_832); assert(SysTime(DateTime(2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_862); assert(SysTime(DateTime(2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_863); assert(SysTime(DateTime(2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_892); assert(SysTime(DateTime(2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_893); assert(SysTime(DateTime(2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_923); assert(SysTime(DateTime(2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_924); assert(SysTime(DateTime(2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_953); assert(SysTime(DateTime(2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_954); assert(SysTime(DateTime(2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_984); assert(SysTime(DateTime(2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_985); assert(SysTime(DateTime(2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_015); assert(SysTime(DateTime(2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_016); assert(SysTime(DateTime(2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_045); assert(SysTime(DateTime(2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_046); assert(SysTime(DateTime(2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_076); assert(SysTime(DateTime(2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_077); assert(SysTime(DateTime(2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_106); assert(SysTime(DateTime(2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_107); assert(SysTime(DateTime(2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_137); assert(SysTime(DateTime(2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == 734_534); assert(SysTime(DateTime(2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == 734_561); assert(SysTime(DateTime(2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == 734_562); assert(SysTime(DateTime(2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == 734_563); //Test B.C. assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 0); assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == 0); assert(SysTime(DateTime(0, 12, 31, 23, 59, 59)).dayOfGregorianCal == 0); assert(SysTime(DateTime(0, 12, 31, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 0); assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).dayOfGregorianCal == 0); assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == -366); assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == -366); assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59)).dayOfGregorianCal == -366); assert(SysTime(DateTime(-1, 12, 31, 0, 0, 0)).dayOfGregorianCal == -366); assert(SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == 0); assert(SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1); assert(SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -30); assert(SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -31); assert(SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -366); assert(SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -367); assert(SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730); assert(SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731); assert(SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1095); assert(SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1096); assert(SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1460); assert(SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1461); assert(SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1826); assert(SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1827); assert(SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -2191); assert(SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -3652); assert(SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_262); assert(SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_627); assert(SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -35_794); assert(SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_160); assert(SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_524); assert(SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_889); assert(SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -37_254); assert(SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -38_715); assert(SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_413); assert(SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_778); assert(SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -109_937); assert(SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -110_302); assert(SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_097); assert(SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_462); assert(SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_827); assert(SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_621); assert(SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_986); assert(SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -183_351); assert(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_607); assert(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_972); assert(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_387); assert(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_388); assert(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_753); assert(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -585_118); assert(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_325); assert(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_690); assert(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_484); assert(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_485); assert(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_850); assert(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731_215); assert(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_502); assert(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_472); assert(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_471); assert(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_444); assert(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_443); assert(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_413); assert(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_412); assert(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_383); assert(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_382); assert(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_352); assert(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_351); assert(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_322); assert(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_321); assert(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_291); assert(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_290); assert(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_260); assert(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_259); assert(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_230); assert(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_229); assert(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_199); assert(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_198); assert(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_169); assert(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_168); assert(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_138); assert(SysTime(DateTime(-2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == -735_202); assert(SysTime(DateTime(-2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == -735_175); assert(SysTime(DateTime(-2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == -735_174); assert(SysTime(DateTime(-2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == -735_173); // Start of Hebrew Calendar assert(SysTime(DateTime(-3760, 9, 7, 0, 0, 0)).dayOfGregorianCal == -1_373_427); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.dayOfGregorianCal == 729_941); //assert(ist.dayOfGregorianCal == 729_941); } //Test that the logic for the day of the Gregorian Calendar is consistent //between Date and SysTime. unittest { void test(Date date, SysTime st, size_t line = __LINE__) { import std.format : format; if(date.dayOfGregorianCal != st.dayOfGregorianCal) { throw new AssertError(format("Date [%s] SysTime [%s]", date.dayOfGregorianCal, st.dayOfGregorianCal), __FILE__, line); } } //Test A.D. test(Date(1, 1, 1), SysTime(DateTime(1, 1, 1, 0, 0, 0))); test(Date(1, 1, 2), SysTime(DateTime(1, 1, 2, 0, 0, 0), hnsecs(500))); test(Date(1, 2, 1), SysTime(DateTime(1, 2, 1, 0, 0, 0), hnsecs(50_000))); test(Date(2, 1, 1), SysTime(DateTime(2, 1, 1, 0, 0, 0), hnsecs(9_999_999))); test(Date(3, 1, 1), SysTime(DateTime(3, 1, 1, 12, 13, 14))); test(Date(4, 1, 1), SysTime(DateTime(4, 1, 1, 12, 13, 14), hnsecs(500))); test(Date(5, 1, 1), SysTime(DateTime(5, 1, 1, 12, 13, 14), hnsecs(50_000))); test(Date(50, 1, 1), SysTime(DateTime(50, 1, 1, 12, 13, 14), hnsecs(9_999_999))); test(Date(97, 1, 1), SysTime(DateTime(97, 1, 1, 23, 59, 59))); test(Date(100, 1, 1), SysTime(DateTime(100, 1, 1, 23, 59, 59), hnsecs(500))); test(Date(101, 1, 1), SysTime(DateTime(101, 1, 1, 23, 59, 59), hnsecs(50_000))); test(Date(105, 1, 1), SysTime(DateTime(105, 1, 1, 23, 59, 59), hnsecs(9_999_999))); test(Date(200, 1, 1), SysTime(DateTime(200, 1, 1, 0, 0, 0))); test(Date(201, 1, 1), SysTime(DateTime(201, 1, 1, 0, 0, 0), hnsecs(500))); test(Date(300, 1, 1), SysTime(DateTime(300, 1, 1, 0, 0, 0), hnsecs(50_000))); test(Date(301, 1, 1), SysTime(DateTime(301, 1, 1, 0, 0, 0), hnsecs(9_999_999))); test(Date(400, 1, 1), SysTime(DateTime(400, 1, 1, 12, 13, 14))); test(Date(401, 1, 1), SysTime(DateTime(401, 1, 1, 12, 13, 14), hnsecs(500))); test(Date(500, 1, 1), SysTime(DateTime(500, 1, 1, 12, 13, 14), hnsecs(50_000))); test(Date(501, 1, 1), SysTime(DateTime(501, 1, 1, 12, 13, 14), hnsecs(9_999_999))); test(Date(1000, 1, 1), SysTime(DateTime(1000, 1, 1, 23, 59, 59))); test(Date(1001, 1, 1), SysTime(DateTime(1001, 1, 1, 23, 59, 59), hnsecs(500))); test(Date(1600, 1, 1), SysTime(DateTime(1600, 1, 1, 23, 59, 59), hnsecs(50_000))); test(Date(1601, 1, 1), SysTime(DateTime(1601, 1, 1, 23, 59, 59), hnsecs(9_999_999))); test(Date(1900, 1, 1), SysTime(DateTime(1900, 1, 1, 0, 0, 0))); test(Date(1901, 1, 1), SysTime(DateTime(1901, 1, 1, 0, 0, 0), hnsecs(500))); test(Date(1945, 11, 12), SysTime(DateTime(1945, 11, 12, 0, 0, 0), hnsecs(50_000))); test(Date(1999, 1, 1), SysTime(DateTime(1999, 1, 1, 0, 0, 0), hnsecs(9_999_999))); test(Date(1999, 7, 6), SysTime(DateTime(1999, 7, 6, 12, 13, 14))); test(Date(2000, 1, 1), SysTime(DateTime(2000, 1, 1, 12, 13, 14), hnsecs(500))); test(Date(2001, 1, 1), SysTime(DateTime(2001, 1, 1, 12, 13, 14), hnsecs(50_000))); test(Date(2010, 1, 1), SysTime(DateTime(2010, 1, 1, 12, 13, 14), hnsecs(9_999_999))); test(Date(2010, 1, 31), SysTime(DateTime(2010, 1, 31, 23, 0, 0))); test(Date(2010, 2, 1), SysTime(DateTime(2010, 2, 1, 23, 59, 59), hnsecs(500))); test(Date(2010, 2, 28), SysTime(DateTime(2010, 2, 28, 23, 59, 59), hnsecs(50_000))); test(Date(2010, 3, 1), SysTime(DateTime(2010, 3, 1, 23, 59, 59), hnsecs(9_999_999))); test(Date(2010, 3, 31), SysTime(DateTime(2010, 3, 31, 0, 0, 0))); test(Date(2010, 4, 1), SysTime(DateTime(2010, 4, 1, 0, 0, 0), hnsecs(500))); test(Date(2010, 4, 30), SysTime(DateTime(2010, 4, 30, 0, 0, 0), hnsecs(50_000))); test(Date(2010, 5, 1), SysTime(DateTime(2010, 5, 1, 0, 0, 0), hnsecs(9_999_999))); test(Date(2010, 5, 31), SysTime(DateTime(2010, 5, 31, 12, 13, 14))); test(Date(2010, 6, 1), SysTime(DateTime(2010, 6, 1, 12, 13, 14), hnsecs(500))); test(Date(2010, 6, 30), SysTime(DateTime(2010, 6, 30, 12, 13, 14), hnsecs(50_000))); test(Date(2010, 7, 1), SysTime(DateTime(2010, 7, 1, 12, 13, 14), hnsecs(9_999_999))); test(Date(2010, 7, 31), SysTime(DateTime(2010, 7, 31, 23, 59, 59))); test(Date(2010, 8, 1), SysTime(DateTime(2010, 8, 1, 23, 59, 59), hnsecs(500))); test(Date(2010, 8, 31), SysTime(DateTime(2010, 8, 31, 23, 59, 59), hnsecs(50_000))); test(Date(2010, 9, 1), SysTime(DateTime(2010, 9, 1, 23, 59, 59), hnsecs(9_999_999))); test(Date(2010, 9, 30), SysTime(DateTime(2010, 9, 30, 12, 0, 0))); test(Date(2010, 10, 1), SysTime(DateTime(2010, 10, 1, 0, 12, 0), hnsecs(500))); test(Date(2010, 10, 31), SysTime(DateTime(2010, 10, 31, 0, 0, 12), hnsecs(50_000))); test(Date(2010, 11, 1), SysTime(DateTime(2010, 11, 1, 23, 0, 0), hnsecs(9_999_999))); test(Date(2010, 11, 30), SysTime(DateTime(2010, 11, 30, 0, 59, 0))); test(Date(2010, 12, 1), SysTime(DateTime(2010, 12, 1, 0, 0, 59), hnsecs(500))); test(Date(2010, 12, 31), SysTime(DateTime(2010, 12, 31, 0, 59, 59), hnsecs(50_000))); test(Date(2012, 2, 1), SysTime(DateTime(2012, 2, 1, 23, 0, 59), hnsecs(9_999_999))); test(Date(2012, 2, 28), SysTime(DateTime(2012, 2, 28, 23, 59, 0))); test(Date(2012, 2, 29), SysTime(DateTime(2012, 2, 29, 7, 7, 7), hnsecs(7))); test(Date(2012, 3, 1), SysTime(DateTime(2012, 3, 1, 7, 7, 7), hnsecs(7))); //Test B.C. test(Date(0, 12, 31), SysTime(DateTime(0, 12, 31, 0, 0, 0))); test(Date(0, 12, 30), SysTime(DateTime(0, 12, 30, 0, 0, 0), hnsecs(500))); test(Date(0, 12, 1), SysTime(DateTime(0, 12, 1, 0, 0, 0), hnsecs(50_000))); test(Date(0, 11, 30), SysTime(DateTime(0, 11, 30, 0, 0, 0), hnsecs(9_999_999))); test(Date(-1, 12, 31), SysTime(DateTime(-1, 12, 31, 12, 13, 14))); test(Date(-1, 12, 30), SysTime(DateTime(-1, 12, 30, 12, 13, 14), hnsecs(500))); test(Date(-1, 1, 1), SysTime(DateTime(-1, 1, 1, 12, 13, 14), hnsecs(50_000))); test(Date(-2, 12, 31), SysTime(DateTime(-2, 12, 31, 12, 13, 14), hnsecs(9_999_999))); test(Date(-2, 1, 1), SysTime(DateTime(-2, 1, 1, 23, 59, 59))); test(Date(-3, 12, 31), SysTime(DateTime(-3, 12, 31, 23, 59, 59), hnsecs(500))); test(Date(-3, 1, 1), SysTime(DateTime(-3, 1, 1, 23, 59, 59), hnsecs(50_000))); test(Date(-4, 12, 31), SysTime(DateTime(-4, 12, 31, 23, 59, 59), hnsecs(9_999_999))); test(Date(-4, 1, 1), SysTime(DateTime(-4, 1, 1, 0, 0, 0))); test(Date(-5, 12, 31), SysTime(DateTime(-5, 12, 31, 0, 0, 0), hnsecs(500))); test(Date(-5, 1, 1), SysTime(DateTime(-5, 1, 1, 0, 0, 0), hnsecs(50_000))); test(Date(-9, 1, 1), SysTime(DateTime(-9, 1, 1, 0, 0, 0), hnsecs(9_999_999))); test(Date(-49, 1, 1), SysTime(DateTime(-49, 1, 1, 12, 13, 14))); test(Date(-50, 1, 1), SysTime(DateTime(-50, 1, 1, 12, 13, 14), hnsecs(500))); test(Date(-97, 1, 1), SysTime(DateTime(-97, 1, 1, 12, 13, 14), hnsecs(50_000))); test(Date(-99, 12, 31), SysTime(DateTime(-99, 12, 31, 12, 13, 14), hnsecs(9_999_999))); test(Date(-99, 1, 1), SysTime(DateTime(-99, 1, 1, 23, 59, 59))); test(Date(-100, 1, 1), SysTime(DateTime(-100, 1, 1, 23, 59, 59), hnsecs(500))); test(Date(-101, 1, 1), SysTime(DateTime(-101, 1, 1, 23, 59, 59), hnsecs(50_000))); test(Date(-105, 1, 1), SysTime(DateTime(-105, 1, 1, 23, 59, 59), hnsecs(9_999_999))); test(Date(-200, 1, 1), SysTime(DateTime(-200, 1, 1, 0, 0, 0))); test(Date(-201, 1, 1), SysTime(DateTime(-201, 1, 1, 0, 0, 0), hnsecs(500))); test(Date(-300, 1, 1), SysTime(DateTime(-300, 1, 1, 0, 0, 0), hnsecs(50_000))); test(Date(-301, 1, 1), SysTime(DateTime(-301, 1, 1, 0, 0, 0), hnsecs(9_999_999))); test(Date(-400, 12, 31), SysTime(DateTime(-400, 12, 31, 12, 13, 14))); test(Date(-400, 1, 1), SysTime(DateTime(-400, 1, 1, 12, 13, 14), hnsecs(500))); test(Date(-401, 1, 1), SysTime(DateTime(-401, 1, 1, 12, 13, 14), hnsecs(50_000))); test(Date(-499, 1, 1), SysTime(DateTime(-499, 1, 1, 12, 13, 14), hnsecs(9_999_999))); test(Date(-500, 1, 1), SysTime(DateTime(-500, 1, 1, 23, 59, 59))); test(Date(-501, 1, 1), SysTime(DateTime(-501, 1, 1, 23, 59, 59), hnsecs(500))); test(Date(-1000, 1, 1), SysTime(DateTime(-1000, 1, 1, 23, 59, 59), hnsecs(50_000))); test(Date(-1001, 1, 1), SysTime(DateTime(-1001, 1, 1, 23, 59, 59), hnsecs(9_999_999))); test(Date(-1599, 1, 1), SysTime(DateTime(-1599, 1, 1, 0, 0, 0))); test(Date(-1600, 12, 31), SysTime(DateTime(-1600, 12, 31, 0, 0, 0), hnsecs(500))); test(Date(-1600, 1, 1), SysTime(DateTime(-1600, 1, 1, 0, 0, 0), hnsecs(50_000))); test(Date(-1601, 1, 1), SysTime(DateTime(-1601, 1, 1, 0, 0, 0), hnsecs(9_999_999))); test(Date(-1900, 1, 1), SysTime(DateTime(-1900, 1, 1, 12, 13, 14))); test(Date(-1901, 1, 1), SysTime(DateTime(-1901, 1, 1, 12, 13, 14), hnsecs(500))); test(Date(-1999, 1, 1), SysTime(DateTime(-1999, 1, 1, 12, 13, 14), hnsecs(50_000))); test(Date(-1999, 7, 6), SysTime(DateTime(-1999, 7, 6, 12, 13, 14), hnsecs(9_999_999))); test(Date(-2000, 12, 31), SysTime(DateTime(-2000, 12, 31, 23, 59, 59))); test(Date(-2000, 1, 1), SysTime(DateTime(-2000, 1, 1, 23, 59, 59), hnsecs(500))); test(Date(-2001, 1, 1), SysTime(DateTime(-2001, 1, 1, 23, 59, 59), hnsecs(50_000))); test(Date(-2010, 1, 1), SysTime(DateTime(-2010, 1, 1, 23, 59, 59), hnsecs(9_999_999))); test(Date(-2010, 1, 31), SysTime(DateTime(-2010, 1, 31, 0, 0, 0))); test(Date(-2010, 2, 1), SysTime(DateTime(-2010, 2, 1, 0, 0, 0), hnsecs(500))); test(Date(-2010, 2, 28), SysTime(DateTime(-2010, 2, 28, 0, 0, 0), hnsecs(50_000))); test(Date(-2010, 3, 1), SysTime(DateTime(-2010, 3, 1, 0, 0, 0), hnsecs(9_999_999))); test(Date(-2010, 3, 31), SysTime(DateTime(-2010, 3, 31, 12, 13, 14))); test(Date(-2010, 4, 1), SysTime(DateTime(-2010, 4, 1, 12, 13, 14), hnsecs(500))); test(Date(-2010, 4, 30), SysTime(DateTime(-2010, 4, 30, 12, 13, 14), hnsecs(50_000))); test(Date(-2010, 5, 1), SysTime(DateTime(-2010, 5, 1, 12, 13, 14), hnsecs(9_999_999))); test(Date(-2010, 5, 31), SysTime(DateTime(-2010, 5, 31, 23, 59, 59))); test(Date(-2010, 6, 1), SysTime(DateTime(-2010, 6, 1, 23, 59, 59), hnsecs(500))); test(Date(-2010, 6, 30), SysTime(DateTime(-2010, 6, 30, 23, 59, 59), hnsecs(50_000))); test(Date(-2010, 7, 1), SysTime(DateTime(-2010, 7, 1, 23, 59, 59), hnsecs(9_999_999))); test(Date(-2010, 7, 31), SysTime(DateTime(-2010, 7, 31, 0, 0, 0))); test(Date(-2010, 8, 1), SysTime(DateTime(-2010, 8, 1, 0, 0, 0), hnsecs(500))); test(Date(-2010, 8, 31), SysTime(DateTime(-2010, 8, 31, 0, 0, 0), hnsecs(50_000))); test(Date(-2010, 9, 1), SysTime(DateTime(-2010, 9, 1, 0, 0, 0), hnsecs(9_999_999))); test(Date(-2010, 9, 30), SysTime(DateTime(-2010, 9, 30, 12, 0, 0))); test(Date(-2010, 10, 1), SysTime(DateTime(-2010, 10, 1, 0, 12, 0), hnsecs(500))); test(Date(-2010, 10, 31), SysTime(DateTime(-2010, 10, 31, 0, 0, 12), hnsecs(50_000))); test(Date(-2010, 11, 1), SysTime(DateTime(-2010, 11, 1, 23, 0, 0), hnsecs(9_999_999))); test(Date(-2010, 11, 30), SysTime(DateTime(-2010, 11, 30, 0, 59, 0))); test(Date(-2010, 12, 1), SysTime(DateTime(-2010, 12, 1, 0, 0, 59), hnsecs(500))); test(Date(-2010, 12, 31), SysTime(DateTime(-2010, 12, 31, 0, 59, 59), hnsecs(50_000))); test(Date(-2012, 2, 1), SysTime(DateTime(-2012, 2, 1, 23, 0, 59), hnsecs(9_999_999))); test(Date(-2012, 2, 28), SysTime(DateTime(-2012, 2, 28, 23, 59, 0))); test(Date(-2012, 2, 29), SysTime(DateTime(-2012, 2, 29, 7, 7, 7), hnsecs(7))); test(Date(-2012, 3, 1), SysTime(DateTime(-2012, 3, 1, 7, 7, 7), hnsecs(7))); test(Date(-3760, 9, 7), SysTime(DateTime(-3760, 9, 7, 0, 0, 0))); } /++ The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on. Setting this property does not affect the time portion of $(LREF SysTime). Params: days = The day of the Gregorian Calendar to set this $(LREF SysTime) to. +/ @property void dayOfGregorianCal(int days) @safe nothrow { auto hnsecs = adjTime; hnsecs = removeUnitsFromHNSecs!"days"(hnsecs); if(hnsecs < 0) hnsecs += convert!("hours", "hnsecs")(24); if(--days < 0) { hnsecs -= convert!("hours", "hnsecs")(24); ++days; } immutable newDaysHNSecs = convert!("days", "hnsecs")(days); adjTime = newDaysHNSecs + hnsecs; } /// unittest { auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0)); st.dayOfGregorianCal = 1; assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0))); st.dayOfGregorianCal = 365; assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0))); st.dayOfGregorianCal = 366; assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0))); st.dayOfGregorianCal = 0; assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0))); st.dayOfGregorianCal = -365; assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0))); st.dayOfGregorianCal = -366; assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0))); st.dayOfGregorianCal = 730_120; assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0))); st.dayOfGregorianCal = 734_137; assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0))); } unittest { void testST(SysTime orig, int day, in SysTime expected, size_t line = __LINE__) { import std.format : format; orig.dayOfGregorianCal = day; if(orig != expected) throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line); } //Test A.D. testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1))); testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 1, SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); //Test B.C. testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0))); testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(1)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1))); testST(SysTime(DateTime(0, 1, 1, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59))); //Test Both. testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0))); testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1))); testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), hnsecs(9_999_999)), 1, SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999))); testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0))); testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), hnsecs(9_999_999)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999))); testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), hnsecs(1)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1))); testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59))); auto st = SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)); void testST2(int day, in SysTime expected, size_t line = __LINE__) { import std.format : format; st.dayOfGregorianCal = day; if(st != expected) throw new AssertError(format("Failed. actual [%s] != expected [%s]", st, expected), __FILE__, line); } //Test A.D. testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212))); testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212))); testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212))); testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212))); testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212))); testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212))); testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212))); testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212))); testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212))); testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212))); testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212))); testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212))); testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212))); testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212))); testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212))); testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212))); testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212))); testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212))); testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212))); testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212))); testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212))); testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212))); testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212))); testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212))); testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212))); testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212))); testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212))); testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212))); testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212))); testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), msecs(212))); testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), msecs(212))); testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), msecs(212))); testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), msecs(212))); testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), msecs(212))); testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), msecs(212))); testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), msecs(212))); testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), msecs(212))); testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), msecs(212))); testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), msecs(212))); testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), msecs(212))); testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), msecs(212))); testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), msecs(212))); testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), msecs(212))); testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), msecs(212))); testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), msecs(212))); testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), msecs(212))); testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), msecs(212))); testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), msecs(212))); testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), msecs(212))); testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), msecs(212))); testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), msecs(212))); testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), msecs(212))); testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), msecs(212))); testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212))); testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212))); testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212))); testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212))); testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212))); testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212))); testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212))); testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212))); //Test B.C. testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212))); testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212))); testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212))); testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212))); testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212))); testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212))); testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212))); testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212))); testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212))); testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212))); testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212))); testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212))); testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212))); testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212))); testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212))); testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212))); testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212))); testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212))); testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212))); testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212))); testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212))); testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212))); testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212))); testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212))); testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212))); testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212))); testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212))); testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212))); testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212))); testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212))); testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212))); testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212))); testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212))); testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212))); testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212))); testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212))); testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212))); testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212))); testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212))); testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212))); testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212))); testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212))); testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212))); testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212))); testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212))); testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212))); testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), msecs(212))); testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), msecs(212))); testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), msecs(212))); testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), msecs(212))); testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), msecs(212))); testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), msecs(212))); testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), msecs(212))); testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), msecs(212))); testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), msecs(212))); testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), msecs(212))); testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), msecs(212))); testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), msecs(212))); testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), msecs(212))); testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), msecs(212))); testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), msecs(212))); testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), msecs(212))); testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), msecs(212))); testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), msecs(212))); testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), msecs(212))); testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), msecs(212))); testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), msecs(212))); testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), msecs(212))); testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), msecs(212))); testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), msecs(212))); testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), msecs(212))); testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), msecs(212))); testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), msecs(212))); testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), msecs(212))); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); static assert(!__traits(compiles, cst.dayOfGregorianCal = 7)); //static assert(!__traits(compiles, ist.dayOfGregorianCal = 7)); } /++ The ISO 8601 week of the year that this $(LREF SysTime) is in. See_Also: $(WEB en.wikipedia.org/wiki/ISO_week_date, ISO Week Date). +/ @property ubyte isoWeek() @safe const nothrow { return (cast(Date)this).isoWeek; } unittest { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(st.isoWeek == 27); assert(cst.isoWeek == 27); //assert(ist.isoWeek == 27); } /++ $(LREF SysTime) for the last day in the month that this Date is in. The time portion of endOfMonth is always 23:59:59.9999999. +/ @property SysTime endOfMonth() @safe const nothrow { immutable hnsecs = adjTime; immutable days = getUnitsFromHNSecs!"days"(hnsecs); auto date = Date(cast(int)days + 1).endOfMonth; auto newDays = date.dayOfGregorianCal - 1; long theTimeHNSecs; if(newDays < 0) { theTimeHNSecs = -1; ++newDays; } else theTimeHNSecs = convert!("days", "hnsecs")(1) - 1; immutable newDaysHNSecs = convert!("days", "hnsecs")(newDays); auto retval = SysTime(this._stdTime, this._timezone); retval.adjTime = newDaysHNSecs + theTimeHNSecs; return retval; } /// unittest { assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth == SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999))); } unittest { //Test A.D. assert(SysTime(Date(1999, 1, 1)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 2, 1)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(2000, 2, 1)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 3, 1)).endOfMonth == SysTime(DateTime(1999, 3, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 4, 1)).endOfMonth == SysTime(DateTime(1999, 4, 30, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 5, 1)).endOfMonth == SysTime(DateTime(1999, 5, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 6, 1)).endOfMonth == SysTime(DateTime(1999, 6, 30, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 7, 1)).endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 8, 1)).endOfMonth == SysTime(DateTime(1999, 8, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 9, 1)).endOfMonth == SysTime(DateTime(1999, 9, 30, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 10, 1)).endOfMonth == SysTime(DateTime(1999, 10, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 11, 1)).endOfMonth == SysTime(DateTime(1999, 11, 30, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(1999, 12, 1)).endOfMonth == SysTime(DateTime(1999, 12, 31, 23, 59, 59), hnsecs(9_999_999))); //Test B.C. assert(SysTime(Date(-1999, 1, 1)).endOfMonth == SysTime(DateTime(-1999, 1, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 2, 1)).endOfMonth == SysTime(DateTime(-1999, 2, 28, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-2000, 2, 1)).endOfMonth == SysTime(DateTime(-2000, 2, 29, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 3, 1)).endOfMonth == SysTime(DateTime(-1999, 3, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 4, 1)).endOfMonth == SysTime(DateTime(-1999, 4, 30, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 5, 1)).endOfMonth == SysTime(DateTime(-1999, 5, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 6, 1)).endOfMonth == SysTime(DateTime(-1999, 6, 30, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 7, 1)).endOfMonth == SysTime(DateTime(-1999, 7, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 8, 1)).endOfMonth == SysTime(DateTime(-1999, 8, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 9, 1)).endOfMonth == SysTime(DateTime(-1999, 9, 30, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 10, 1)).endOfMonth == SysTime(DateTime(-1999, 10, 31, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 11, 1)).endOfMonth == SysTime(DateTime(-1999, 11, 30, 23, 59, 59), hnsecs(9_999_999))); assert(SysTime(Date(-1999, 12, 1)).endOfMonth == SysTime(DateTime(-1999, 12, 31, 23, 59, 59), hnsecs(9_999_999))); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999))); //assert(ist.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999))); } /++ The last day in the month that this $(LREF SysTime) is in. +/ @property ubyte daysInMonth() @safe const nothrow { return Date(dayOfGregorianCal).daysInMonth; } /// unittest { assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31); assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28); assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29); assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30); } unittest { //Test A.D. assert(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).daysInMonth == 31); assert(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).daysInMonth == 28); assert(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).daysInMonth == 29); assert(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).daysInMonth == 31); assert(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).daysInMonth == 30); assert(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).daysInMonth == 31); assert(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).daysInMonth == 30); assert(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).daysInMonth == 31); assert(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).daysInMonth == 31); assert(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).daysInMonth == 30); assert(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).daysInMonth == 31); assert(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).daysInMonth == 30); assert(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).daysInMonth == 31); //Test B.C. assert(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).daysInMonth == 31); assert(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).daysInMonth == 28); assert(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).daysInMonth == 29); assert(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).daysInMonth == 31); assert(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).daysInMonth == 30); assert(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).daysInMonth == 31); assert(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).daysInMonth == 30); assert(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).daysInMonth == 31); assert(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).daysInMonth == 31); assert(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).daysInMonth == 30); assert(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).daysInMonth == 31); assert(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).daysInMonth == 30); assert(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).daysInMonth == 31); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.daysInMonth == 31); //assert(ist.daysInMonth == 31); } /++ Whether the current year is a date in A.D. +/ @property bool isAD() @safe const nothrow { return adjTime >= 0; } /// unittest { assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD); assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD); assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD); assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD); } unittest { assert(SysTime(DateTime(2010, 7, 4, 12, 0, 9)).isAD); assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).isAD); assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD); assert(!SysTime(DateTime(0, 1, 1, 23, 59, 59)).isAD); assert(!SysTime(DateTime(-1, 1, 1, 23 ,59 ,59)).isAD); assert(!SysTime(DateTime(-2010, 7, 4, 12, 2, 2)).isAD); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.isAD); //assert(ist.isAD); } /++ The $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for this $(LREF SysTime) at the given time. For example, prior to noon, 1996-03-31 would be the Julian day number 2_450_173, so this function returns 2_450_173, while from noon onward, the Julian day number would be 2_450_174, so this function returns 2_450_174. +/ @property long julianDay() @safe const nothrow { immutable jd = dayOfGregorianCal + 1_721_425; return hour < 12 ? jd - 1 : jd; } unittest { assert(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay == -1); assert(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay == 0); assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay == 1_721_424); assert(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay == 1_721_425); assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay == 1_721_425); assert(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay == 1_721_426); assert(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay == 2_299_160); assert(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay == 2_299_161); assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay == 2_400_000); assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay == 2_400_001); assert(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay == 2_444_973); assert(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay == 2_444_974); assert(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay == 2_450_173); assert(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay == 2_450_174); assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay == 2_455_432); assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).julianDay == 2_455_433); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.julianDay == 2_451_366); //assert(ist.julianDay == 2_451_366); } /++ The modified $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for any time on this date (since, the modified Julian day changes at midnight). +/ @property long modJulianDay() @safe const nothrow { return (dayOfGregorianCal + 1_721_425) - 2_400_001; } unittest { assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay == 0); assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay == 0); assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay == 55_432); assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).modJulianDay == 55_432); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cst.modJulianDay == 51_365); //assert(ist.modJulianDay == 51_365); } /++ Returns a $(LREF Date) equivalent to this $(LREF SysTime). +/ Date opCast(T)() @safe const nothrow if(is(Unqual!T == Date)) { return Date(dayOfGregorianCal); } unittest { assert(cast(Date)SysTime(Date(1999, 7, 6)) == Date(1999, 7, 6)); assert(cast(Date)SysTime(Date(2000, 12, 31)) == Date(2000, 12, 31)); assert(cast(Date)SysTime(Date(2001, 1, 1)) == Date(2001, 1, 1)); assert(cast(Date)SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == Date(1999, 7, 6)); assert(cast(Date)SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == Date(2000, 12, 31)); assert(cast(Date)SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == Date(2001, 1, 1)); assert(cast(Date)SysTime(Date(-1999, 7, 6)) == Date(-1999, 7, 6)); assert(cast(Date)SysTime(Date(-2000, 12, 31)) == Date(-2000, 12, 31)); assert(cast(Date)SysTime(Date(-2001, 1, 1)) == Date(-2001, 1, 1)); assert(cast(Date)SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == Date(-1999, 7, 6)); assert(cast(Date)SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == Date(-2000, 12, 31)); assert(cast(Date)SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == Date(-2001, 1, 1)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cast(Date)cst != Date.init); //assert(cast(Date)ist != Date.init); } /++ Returns a $(LREF DateTime) equivalent to this $(LREF SysTime). +/ DateTime opCast(T)() @safe const nothrow if(is(Unqual!T == DateTime)) { try { auto hnsecs = adjTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs); immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs); immutable second = getUnitsFromHNSecs!"seconds"(hnsecs); return DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second)); } catch(Exception e) assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw."); } unittest { assert(cast(DateTime)SysTime(DateTime(1, 1, 6, 7, 12, 22)) == DateTime(1, 1, 6, 7, 12, 22)); assert(cast(DateTime)SysTime(DateTime(1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(1, 1, 6, 7, 12, 22)); assert(cast(DateTime)SysTime(Date(1999, 7, 6)) == DateTime(1999, 7, 6, 0, 0, 0)); assert(cast(DateTime)SysTime(Date(2000, 12, 31)) == DateTime(2000, 12, 31, 0, 0, 0)); assert(cast(DateTime)SysTime(Date(2001, 1, 1)) == DateTime(2001, 1, 1, 0, 0, 0)); assert(cast(DateTime)SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == DateTime(1999, 7, 6, 12, 10, 9)); assert(cast(DateTime)SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == DateTime(2000, 12, 31, 13, 11, 10)); assert(cast(DateTime)SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == DateTime(2001, 1, 1, 14, 12, 11)); assert(cast(DateTime)SysTime(DateTime(-1, 1, 6, 7, 12, 22)) == DateTime(-1, 1, 6, 7, 12, 22)); assert(cast(DateTime)SysTime(DateTime(-1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(-1, 1, 6, 7, 12, 22)); assert(cast(DateTime)SysTime(Date(-1999, 7, 6)) == DateTime(-1999, 7, 6, 0, 0, 0)); assert(cast(DateTime)SysTime(Date(-2000, 12, 31)) == DateTime(-2000, 12, 31, 0, 0, 0)); assert(cast(DateTime)SysTime(Date(-2001, 1, 1)) == DateTime(-2001, 1, 1, 0, 0, 0)); assert(cast(DateTime)SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == DateTime(-1999, 7, 6, 12, 10, 9)); assert(cast(DateTime)SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == DateTime(-2000, 12, 31, 13, 11, 10)); assert(cast(DateTime)SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == DateTime(-2001, 1, 1, 14, 12, 11)); assert(cast(DateTime)SysTime(DateTime(2011, 1, 13, 8, 17, 2), msecs(296), LocalTime()) == DateTime(2011, 1, 13, 8, 17, 2)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cast(DateTime)cst != DateTime.init); //assert(cast(DateTime)ist != DateTime.init); } /++ Returns a $(LREF TimeOfDay) equivalent to this $(LREF SysTime). +/ TimeOfDay opCast(T)() @safe const nothrow if(is(Unqual!T == TimeOfDay)) { try { auto hnsecs = adjTime; hnsecs = removeUnitsFromHNSecs!"days"(hnsecs); if(hnsecs < 0) hnsecs += convert!("hours", "hnsecs")(24); immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs); immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs); immutable second = getUnitsFromHNSecs!"seconds"(hnsecs); return TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second); } catch(Exception e) assert(0, "TimeOfDay's constructor threw."); } unittest { assert(cast(TimeOfDay)SysTime(Date(1999, 7, 6)) == TimeOfDay(0, 0, 0)); assert(cast(TimeOfDay)SysTime(Date(2000, 12, 31)) == TimeOfDay(0, 0, 0)); assert(cast(TimeOfDay)SysTime(Date(2001, 1, 1)) == TimeOfDay(0, 0, 0)); assert(cast(TimeOfDay)SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9)); assert(cast(TimeOfDay)SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10)); assert(cast(TimeOfDay)SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11)); assert(cast(TimeOfDay)SysTime(Date(-1999, 7, 6)) == TimeOfDay(0, 0, 0)); assert(cast(TimeOfDay)SysTime(Date(-2000, 12, 31)) == TimeOfDay(0, 0, 0)); assert(cast(TimeOfDay)SysTime(Date(-2001, 1, 1)) == TimeOfDay(0, 0, 0)); assert(cast(TimeOfDay)SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9)); assert(cast(TimeOfDay)SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10)); assert(cast(TimeOfDay)SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cast(TimeOfDay)cst != TimeOfDay.init); //assert(cast(TimeOfDay)ist != TimeOfDay.init); } //Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=4867 is fixed. //This allows assignment from const(SysTime) to SysTime. //It may be a good idea to keep it though, since casting from a type to itself //should be allowed, and it doesn't work without this opCast() since opCast() //has already been defined for other types. SysTime opCast(T)() @safe const pure nothrow if(is(Unqual!T == SysTime)) { return SysTime(_stdTime, _timezone); } /++ Converts this $(LREF SysTime) to a string with the format YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ is time zone). Note that the number of digits in the fractional seconds varies with the number of fractional seconds. It's a maximum of 7 (which would be hnsecs), but only has as many as are necessary to hold the correct value (so no trailing zeroes), and if there are no fractional seconds, then there is no decimal point. If this $(LREF SysTime)'s time zone is $(LREF LocalTime), then TZ is empty. If its time zone is $(D UTC), then it is "Z". Otherwise, it is the offset from UTC (e.g. +0100 or -0700). Note that the offset from UTC is $(I not) enough to uniquely identify the time zone. Time zone offsets will be in the form +HHMM or -HHMM. $(RED Warning: Previously, toISOString did the same as $(LREF toISOExtString) and generated +HH:MM or -HH:MM for the time zone when it was not $(LREF LocalTime) or $(LREF UTC), which is not in conformance with ISO 9601 for the non-extended string format. This has now been fixed. However, for now, fromISOString will continue to accept the extended format for the time zone so that any code which has been writing out the result of toISOString to read in later will continue to work.) +/ string toISOString() @safe const nothrow { import std.format : format; try { immutable adjustedTime = adjTime; long hnsecs = adjustedTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } auto hour = splitUnitsFromHNSecs!"hours"(hnsecs); auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs); auto second = splitUnitsFromHNSecs!"seconds"(hnsecs); auto dateTime = DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second)); auto fracSecStr = fracSecsToISOString(cast(int)hnsecs); if(_timezone is LocalTime()) return dateTime.toISOString() ~ fracSecsToISOString(cast(int)hnsecs); if(_timezone is UTC()) return dateTime.toISOString() ~ fracSecsToISOString(cast(int)hnsecs) ~ "Z"; immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime); return format("%s%s%s", dateTime.toISOString(), fracSecsToISOString(cast(int)hnsecs), SimpleTimeZone.toISOExtString(utcOffset)); } catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() == "20100704T070612"); assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() == "19981225T021500.024"); assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() == "00000105T230959"); assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() == "-00040105T000002.052092"); } unittest { //Test A.D. assert(SysTime(DateTime.init, UTC()).toISOString() == "00010101T000000Z"); assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOString() == "00010101T000000.0000001Z"); assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString() == "00091204T000000"); assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString() == "00991204T050612"); assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString() == "09991204T134459"); assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString() == "99990704T235959"); assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString() == "+100001020T010101"); assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "00091204T000000.042"); assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "00991204T050612.1"); assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "09991204T134459.04502"); assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "99990704T235959.0000012"); assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "+100001020T010101.050789"); assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12), new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOString() == "20121221T121212-06:00"); assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12), new immutable SimpleTimeZone(dur!"minutes"(420))).toISOString() == "20121221T121212+07:00"); //Test B.C. assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOString() == "00001231T235959.9999999Z"); assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOString() == "00001231T235959.0000001Z"); assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString() == "00001231T235959Z"); assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString() == "00001204T001204"); assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString() == "-00091204T000000"); assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString() == "-00991204T050612"); assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString() == "-09991204T134459"); assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString() == "-99990704T235959"); assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString() == "-100001020T010101"); assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOString() == "00001204T000000.007"); assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "-00091204T000000.042"); assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "-00991204T050612.1"); assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "-09991204T134459.04502"); assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "-99990704T235959.0000012"); assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "-100001020T010101.050789"); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cast(TimeOfDay)cst != TimeOfDay.init); //assert(cast(TimeOfDay)ist != TimeOfDay.init); } /++ Converts this $(LREF SysTime) to a string with the format YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ is the time zone). Note that the number of digits in the fractional seconds varies with the number of fractional seconds. It's a maximum of 7 (which would be hnsecs), but only has as many as are necessary to hold the correct value (so no trailing zeroes), and if there are no fractional seconds, then there is no decimal point. If this $(LREF SysTime)'s time zone is $(LREF LocalTime), then TZ is empty. If its time zone is $(D UTC), then it is "Z". Otherwise, it is the offset from UTC (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not) enough to uniquely identify the time zone. Time zone offsets will be in the form +HH:MM or -HH:MM. +/ string toISOExtString() @safe const nothrow { import std.format : format; try { immutable adjustedTime = adjTime; long hnsecs = adjustedTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } auto hour = splitUnitsFromHNSecs!"hours"(hnsecs); auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs); auto second = splitUnitsFromHNSecs!"seconds"(hnsecs); auto dateTime = DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second)); auto fracSecStr = fracSecsToISOString(cast(int)hnsecs); if(_timezone is LocalTime()) return dateTime.toISOExtString() ~ fracSecsToISOString(cast(int)hnsecs); if(_timezone is UTC()) return dateTime.toISOExtString() ~ fracSecsToISOString(cast(int)hnsecs) ~ "Z"; immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime); return format("%s%s%s", dateTime.toISOExtString(), fracSecsToISOString(cast(int)hnsecs), SimpleTimeZone.toISOExtString(utcOffset)); } catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() == "2010-07-04T07:06:12"); assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() == "1998-12-25T02:15:00.024"); assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() == "0000-01-05T23:09:59"); assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() == "-0004-01-05T00:00:02.052092"); } unittest { //Test A.D. assert(SysTime(DateTime.init, UTC()).toISOExtString() == "0001-01-01T00:00:00Z"); assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOExtString() == "0001-01-01T00:00:00.0000001Z"); assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00"); assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12"); assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59"); assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59"); assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01"); assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "0009-12-04T00:00:00.042"); assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "0099-12-04T05:06:12.1"); assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "0999-12-04T13:44:59.04502"); assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "9999-07-04T23:59:59.0000012"); assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() == "+10000-10-20T01:01:01.050789"); assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12), new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOExtString() == "2012-12-21T12:12:12-06:00"); assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12), new immutable SimpleTimeZone(dur!"minutes"(420))).toISOExtString() == "2012-12-21T12:12:12+07:00"); //Test B.C. assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOExtString() == "0000-12-31T23:59:59.9999999Z"); assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOExtString() == "0000-12-31T23:59:59.0000001Z"); assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtString() == "0000-12-31T23:59:59Z"); assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04"); assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00"); assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12"); assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59"); assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59"); assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01"); assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOExtString() == "0000-12-04T00:00:00.007"); assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "-0009-12-04T00:00:00.042"); assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "-0099-12-04T05:06:12.1"); assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "-0999-12-04T13:44:59.04502"); assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "-9999-07-04T23:59:59.0000012"); assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() == "-10000-10-20T01:01:01.050789"); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cast(TimeOfDay)cst != TimeOfDay.init); //assert(cast(TimeOfDay)ist != TimeOfDay.init); } /++ Converts this $(LREF SysTime) to a string with the format YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ is the time zone). Note that the number of digits in the fractional seconds varies with the number of fractional seconds. It's a maximum of 7 (which would be hnsecs), but only has as many as are necessary to hold the correct value (so no trailing zeroes), and if there are no fractional seconds, then there is no decimal point. If this $(LREF SysTime)'s time zone is $(LREF LocalTime), then TZ is empty. If its time zone is $(D UTC), then it is "Z". Otherwise, it is the offset from UTC (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not) enough to uniquely identify the time zone. Time zone offsets will be in the form +HH:MM or -HH:MM. +/ string toSimpleString() @safe const nothrow { import std.format : format; try { immutable adjustedTime = adjTime; long hnsecs = adjustedTime; auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; if(hnsecs < 0) { hnsecs += convert!("hours", "hnsecs")(24); --days; } auto hour = splitUnitsFromHNSecs!"hours"(hnsecs); auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs); auto second = splitUnitsFromHNSecs!"seconds"(hnsecs); auto dateTime = DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second)); auto fracSecStr = fracSecsToISOString(cast(int)hnsecs); if(_timezone is LocalTime()) return dateTime.toSimpleString() ~ fracSecsToISOString(cast(int)hnsecs); if(_timezone is UTC()) return dateTime.toSimpleString() ~ fracSecsToISOString(cast(int)hnsecs) ~ "Z"; immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime); return format("%s%s%s", dateTime.toSimpleString(), fracSecsToISOString(cast(int)hnsecs), SimpleTimeZone.toISOExtString(utcOffset)); } catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() == "2010-Jul-04 07:06:12"); assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() == "1998-Dec-25 02:15:00.024"); assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() == "0000-Jan-05 23:09:59"); assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() == "-0004-Jan-05 00:00:02.052092"); } unittest { //Test A.D. assert(SysTime(DateTime.init, UTC()).toString() == "0001-Jan-01 00:00:00Z"); assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toString() == "0001-Jan-01 00:00:00.0000001Z"); assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00"); assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12"); assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59"); assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59"); assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01"); assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "0009-Dec-04 00:00:00.042"); assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "0099-Dec-04 05:06:12.1"); assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() == "0999-Dec-04 13:44:59.04502"); assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() == "9999-Jul-04 23:59:59.0000012"); assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() == "+10000-Oct-20 01:01:01.050789"); assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12), new immutable SimpleTimeZone(dur!"minutes"(-360))).toSimpleString() == "2012-Dec-21 12:12:12-06:00"); assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12), new immutable SimpleTimeZone(dur!"minutes"(420))).toSimpleString() == "2012-Dec-21 12:12:12+07:00"); //Test B.C. assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toSimpleString() == "0000-Dec-31 23:59:59.9999999Z"); assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toSimpleString() == "0000-Dec-31 23:59:59.0000001Z"); assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString() == "0000-Dec-31 23:59:59Z"); assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04"); assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00"); assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12"); assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59"); assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59"); assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01"); assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toSimpleString() == "0000-Dec-04 00:00:00.007"); assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "-0009-Dec-04 00:00:00.042"); assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "-0099-Dec-04 05:06:12.1"); assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() == "-0999-Dec-04 13:44:59.04502"); assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() == "-9999-Jul-04 23:59:59.0000012"); assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() == "-10000-Oct-20 01:01:01.050789"); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(cast(TimeOfDay)cst != TimeOfDay.init); //assert(cast(TimeOfDay)ist != TimeOfDay.init); } /++ Converts this $(LREF SysTime) to a string. +/ string toString() @safe const nothrow { return toSimpleString(); } unittest { auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33)); assert(st.toString()); assert(cst.toString()); //assert(ist.toString()); } /++ Creates a $(LREF SysTime) from a string with the format YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds is the time zone). Whitespace is stripped from the given string. The exact format is exactly as described in $(D toISOString) except that trailing zeroes are permitted - including having fractional seconds with all zeroes. However, a decimal point with nothing following it is invalid. If there is no time zone in the string, then $(LREF LocalTime) is used. If the time zone is "Z", then $(D UTC) is used. Otherwise, a $(LREF SimpleTimeZone) which corresponds to the given offset from UTC is used. To get the returned $(LREF SysTime) to be a particular time zone, pass in that time zone and the $(LREF SysTime) to be returned will be converted to that time zone (though it will still be read in as whatever time zone is in its string). The accepted formats for time zone offsets are +HH, -HH, +HHMM, and -HHMM. $(RED Warning: Previously, $(LREF toISOString) did the same as $(LREF toISOExtString) and generated +HH:MM or -HH:MM for the time zone when it was not $(LREF LocalTime) or $(LREF UTC), which is not in conformance with ISO 9601 for the non-extended string format. This has now been fixed. However, for now, fromISOString will continue to accept the extended format for the time zone so that any code which has been writing out the result of toISOString to read in later will continue to work.) Params: isoString = A string formatted in the ISO format for dates and times. tz = The time zone to convert the given time to (no conversion occurs if null). Throws: $(LREF DateTimeException) if the given string is not in the ISO format or if the resulting $(LREF SysTime) would not be valid. +/ static SysTime fromISOString(S)(in S isoString, immutable TimeZone tz = null) @safe if(isSomeString!S) { import std.string : strip; import std.conv : to; import std.algorithm : startsWith, find; import std.format : format; auto dstr = to!dstring(strip(isoString)); immutable skipFirst = dstr.startsWith('+', '-') != 0; auto found = (skipFirst ? dstr[1..$] : dstr).find('.', 'Z', '+', '-'); auto dateTimeStr = dstr[0 .. $ - found[0].length]; dstring fracSecStr; dstring zoneStr; if(found[1] != 0) { if(found[1] == 1) { auto foundTZ = found[0].find('Z', '+', '-'); if(foundTZ[1] != 0) { fracSecStr = found[0][0 .. $ - foundTZ[0].length]; zoneStr = foundTZ[0]; } else fracSecStr = found[0]; } else zoneStr = found[0]; } try { auto dateTime = DateTime.fromISOString(dateTimeStr); auto fracSec = fracSecsFromISOString(fracSecStr); Rebindable!(immutable TimeZone) parsedZone; if(zoneStr.empty) parsedZone = LocalTime(); else if(zoneStr == "Z") parsedZone = UTC(); else { try parsedZone = SimpleTimeZone.fromISOString(zoneStr); catch(DateTimeException dte) parsedZone = SimpleTimeZone.fromISOExtString(zoneStr); } auto retval = SysTime(dateTime, fracSec, parsedZone); if(tz !is null) retval.timezone = tz; return retval; } catch(DateTimeException dte) throw new DateTimeException(format("Invalid ISO String: %s", isoString)); } /// unittest { assert(SysTime.fromISOString("20100704T070612") == SysTime(DateTime(2010, 7, 4, 7, 6, 12))); assert(SysTime.fromISOString("19981225T021500.007") == SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7))); assert(SysTime.fromISOString("00000105T230959.00002") == SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20))); assert(SysTime.fromISOString("-00040105T000002") == SysTime(DateTime(-4, 1, 5, 0, 0, 2))); assert(SysTime.fromISOString(" 20100704T070612 ") == SysTime(DateTime(2010, 7, 4, 7, 6, 12))); assert(SysTime.fromISOString("20100704T070612Z") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC())); assert(SysTime.fromISOString("20100704T070612-0800") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new immutable SimpleTimeZone(hours(-8)))); assert(SysTime.fromISOString("20100704T070612+0800") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new immutable SimpleTimeZone(hours(8)))); } unittest { import std.format: format; foreach(str; ["", "20100704000000", "20100704 000000", "20100704t000000", "20100704T000000.", "20100704T000000.A", "20100704T000000.Z", "20100704T000000.00000000", "20100704T000000.00000000", "20100704T000000+", "20100704T000000-", "20100704T000000:", "20100704T000000-:", "20100704T000000+:", "20100704T000000-1:", "20100704T000000+1:", "20100704T000000+1:0", "20100704T000000-12.00", "20100704T000000+12.00", "20100704T000000-8", "20100704T000000+8", "20100704T000000-800", "20100704T000000+800", "20100704T000000-080", "20100704T000000+080", "20100704T000000-2400", "20100704T000000+2400", "20100704T000000-1260", "20100704T000000+1260", "20100704T000000.0-8", "20100704T000000.0+8", "20100704T000000.0-800", "20100704T000000.0+800", "20100704T000000.0-080", "20100704T000000.0+080", "20100704T000000.0-2400", "20100704T000000.0+2400", "20100704T000000.0-1260", "20100704T000000.0+1260", "20100704T000000-8:00", "20100704T000000+8:00", "20100704T000000-08:0", "20100704T000000+08:0", "20100704T000000-24:00", "20100704T000000+24:00", "20100704T000000-12:60", "20100704T000000+12:60", "20100704T000000.0-8:00", "20100704T000000.0+8:00", "20100704T000000.0-08:0", "20100704T000000.0+08:0", "20100704T000000.0-24:00", "20100704T000000.0+24:00", "20100704T000000.0-12:60", "20100704T000000.0+12:60", "2010-07-0400:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00", "2010-07-04T00:00:00.", "2010-Jul-0400:00:00", "2010-Jul-04 00:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00", "2010-Jul-04 00:00:00.", "2010-12-22T172201", "2010-Dec-22 17:22:01"]) { assertThrown!DateTimeException(SysTime.fromISOString(str), format("[%s]", str)); } static void test(string str, SysTime st, size_t line = __LINE__) { if(SysTime.fromISOString(str) != st) throw new AssertError("unittest failure", __FILE__, line); } test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 01))); test("19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test("-19990706T123033", SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); test("+019990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test("19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test(" 19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test(" 19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test("19070707T121212.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12))); test("19070707T121212.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12))); test("19070707T121212.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1))); test("19070707T121212.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1))); test("19070707T121212.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1))); test("19070707T121212.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1))); test("19070707T121212.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1))); auto west60 = new immutable SimpleTimeZone(hours(-1)); auto west90 = new immutable SimpleTimeZone(minutes(-90)); auto west480 = new immutable SimpleTimeZone(hours(-8)); auto east60 = new immutable SimpleTimeZone(hours(1)); auto east90 = new immutable SimpleTimeZone(minutes(90)); auto east480 = new immutable SimpleTimeZone(hours(8)); test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC())); test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60)); test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60)); test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90)); test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480)); test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90)); test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480)); test("20101103T065106.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC())); test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC())); test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60)); test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60)); test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90)); test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480)); test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60)); test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90)); test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480)); // @@@DEPRECATED_2017-07@@@ // This isn't deprecated per se, but that text will make it so that it // pops up when deprecations are moved along around July 2017. At that // time, the notice on the documentation should be removed, and we may // or may not change the behavior of fromISOString to no longer accept // ISO extended time zones (the concern being that programs will have // written out strings somewhere to read in again that they'll still be // reading in for years to come and may not be able to fix, even if the // code is fixed). If/when we do change the behavior, these tests will // start failing and will need to be updated accordingly. test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60)); test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90)); test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480)); test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90)); test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480)); test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60)); test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90)); test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480)); test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60)); test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90)); test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480)); } /++ Creates a $(LREF SysTime) from a string with the format YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the time zone). Whitespace is stripped from the given string. The exact format is exactly as described in $(D toISOExtString) except that trailing zeroes are permitted - including having fractional seconds with all zeroes. However, a decimal point with nothing following it is invalid. If there is no time zone in the string, then $(LREF LocalTime) is used. If the time zone is "Z", then $(D UTC) is used. Otherwise, a $(LREF SimpleTimeZone) which corresponds to the given offset from UTC is used. To get the returned $(LREF SysTime) to be a particular time zone, pass in that time zone and the $(LREF SysTime) to be returned will be converted to that time zone (though it will still be read in as whatever time zone is in its string). The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and -HH:MM. Params: isoExtString = A string formatted in the ISO Extended format for dates and times. tz = The time zone to convert the given time to (no conversion occurs if null). Throws: $(LREF DateTimeException) if the given string is not in the ISO format or if the resulting $(LREF SysTime) would not be valid. +/ static SysTime fromISOExtString(S)(in S isoExtString, immutable TimeZone tz = null) @safe if(isSomeString!(S)) { import std.string : strip; import std.conv : to; import std.algorithm : countUntil, find; import std.format : format; auto dstr = to!dstring(strip(isoExtString)); auto tIndex = dstr.countUntil('T'); enforce(tIndex != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); auto found = dstr[tIndex + 1 .. $].find('.', 'Z', '+', '-'); auto dateTimeStr = dstr[0 .. $ - found[0].length]; dstring fracSecStr; dstring zoneStr; if(found[1] != 0) { if(found[1] == 1) { auto foundTZ = found[0].find('Z', '+', '-'); if(foundTZ[1] != 0) { fracSecStr = found[0][0 .. $ - foundTZ[0].length]; zoneStr = foundTZ[0]; } else fracSecStr = found[0]; } else zoneStr = found[0]; } try { auto dateTime = DateTime.fromISOExtString(dateTimeStr); auto fracSec = fracSecsFromISOString(fracSecStr); Rebindable!(immutable TimeZone) parsedZone; if(zoneStr.empty) parsedZone = LocalTime(); else if(zoneStr == "Z") parsedZone = UTC(); else parsedZone = SimpleTimeZone.fromISOExtString(zoneStr); auto retval = SysTime(dateTime, fracSec, parsedZone); if(tz !is null) retval.timezone = tz; return retval; } catch(DateTimeException dte) throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)); } /// unittest { assert(SysTime.fromISOExtString("2010-07-04T07:06:12") == SysTime(DateTime(2010, 7, 4, 7, 6, 12))); assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") == SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7))); assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") == SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20))); assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") == SysTime(DateTime(-4, 1, 5, 0, 0, 2))); assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") == SysTime(DateTime(2010, 7, 4, 7, 6, 12))); assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC())); assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new immutable SimpleTimeZone(hours(-8)))); assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new immutable SimpleTimeZone(hours(8)))); } unittest { import std.format : format; foreach(str; ["", "20100704000000", "20100704 000000", "20100704t000000", "20100704T000000.", "20100704T000000.0", "2010-07:0400:00:00", "2010-07-04 00:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00", "2010-07-04T00:00:00.", "2010-07-04T00:00:00.A", "2010-07-04T00:00:00.Z", "2010-07-04T00:00:00.00000000", "2010-07-04T00:00:00.00000000", "2010-07-04T00:00:00+", "2010-07-04T00:00:00-", "2010-07-04T00:00:00:", "2010-07-04T00:00:00-:", "2010-07-04T00:00:00+:", "2010-07-04T00:00:00-1:", "2010-07-04T00:00:00+1:", "2010-07-04T00:00:00+1:0", "2010-07-04T00:00:00-12.00", "2010-07-04T00:00:00+12.00", "2010-07-04T00:00:00-8", "2010-07-04T00:00:00+8", "20100704T000000-800", "20100704T000000+800", "20100704T000000-080", "20100704T000000+080", "20100704T000000-2400", "20100704T000000+2400", "20100704T000000-1260", "20100704T000000+1260", "20100704T000000.0-800", "20100704T000000.0+800", "20100704T000000.0-8", "20100704T000000.0+8", "20100704T000000.0-080", "20100704T000000.0+080", "20100704T000000.0-2400", "20100704T000000.0+2400", "20100704T000000.0-1260", "20100704T000000.0+1260", "2010-07-04T00:00:00-8:00", "2010-07-04T00:00:00+8:00", "2010-07-04T00:00:00-24:00", "2010-07-04T00:00:00+24:00", "2010-07-04T00:00:00-12:60", "2010-07-04T00:00:00+12:60", "2010-07-04T00:00:00.0-8:00", "2010-07-04T00:00:00.0+8:00", "2010-07-04T00:00:00.0-8", "2010-07-04T00:00:00.0+8", "2010-07-04T00:00:00.0-24:00", "2010-07-04T00:00:00.0+24:00", "2010-07-04T00:00:00.0-12:60", "2010-07-04T00:00:00.0+12:60", "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.0", "20101222T172201", "2010-Dec-22 17:22:01"]) { assertThrown!DateTimeException(SysTime.fromISOExtString(str), format("[%s]", str)); } static void test(string str, SysTime st, size_t line = __LINE__) { if(SysTime.fromISOExtString(str) != st) throw new AssertError("unittest failure", __FILE__, line); } test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01))); test("1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test("-1999-07-06T12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); test("+01999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test("1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test(" 1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test(" 1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12))); test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12))); test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1))); test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1))); test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1))); test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1))); test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1))); auto west60 = new immutable SimpleTimeZone(hours(-1)); auto west90 = new immutable SimpleTimeZone(minutes(-90)); auto west480 = new immutable SimpleTimeZone(hours(-8)); auto east60 = new immutable SimpleTimeZone(hours(1)); auto east90 = new immutable SimpleTimeZone(minutes(90)); auto east480 = new immutable SimpleTimeZone(hours(8)); test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC())); test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60)); test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60)); test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90)); test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480)); test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90)); test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480)); test("2010-11-03T06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC())); test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC())); test("2010-12-22T17:22:01.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60)); test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60)); test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90)); test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480)); test("2010-12-22T17:22:01.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60)); test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90)); test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480)); } /++ Creates a $(LREF SysTime) from a string with the format YYYY-MM-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the time zone). Whitespace is stripped from the given string. The exact format is exactly as described in $(D toSimpleString) except that trailing zeroes are permitted - including having fractional seconds with all zeroes. However, a decimal point with nothing following it is invalid. If there is no time zone in the string, then $(LREF LocalTime) is used. If the time zone is "Z", then $(D UTC) is used. Otherwise, a $(LREF SimpleTimeZone) which corresponds to the given offset from UTC is used. To get the returned $(LREF SysTime) to be a particular time zone, pass in that time zone and the $(LREF SysTime) to be returned will be converted to that time zone (though it will still be read in as whatever time zone is in its string). The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and -HH:MM. Params: simpleString = A string formatted in the way that $(D toSimpleString) formats dates and times. tz = The time zone to convert the given time to (no conversion occurs if null). Throws: $(LREF DateTimeException) if the given string is not in the ISO format or if the resulting $(LREF SysTime) would not be valid. +/ static SysTime fromSimpleString(S)(in S simpleString, immutable TimeZone tz = null) @safe if(isSomeString!(S)) { import std.string : strip; import std.conv : to; import std.algorithm : countUntil, find; import std.format : format; auto dstr = to!dstring(strip(simpleString)); auto spaceIndex = dstr.countUntil(' '); enforce(spaceIndex != -1, new DateTimeException(format("Invalid Simple String: %s", simpleString))); auto found = dstr[spaceIndex + 1 .. $].find('.', 'Z', '+', '-'); auto dateTimeStr = dstr[0 .. $ - found[0].length]; dstring fracSecStr; dstring zoneStr; if(found[1] != 0) { if(found[1] == 1) { auto foundTZ = found[0].find('Z', '+', '-'); if(foundTZ[1] != 0) { fracSecStr = found[0][0 .. $ - foundTZ[0].length]; zoneStr = foundTZ[0]; } else fracSecStr = found[0]; } else zoneStr = found[0]; } try { auto dateTime = DateTime.fromSimpleString(dateTimeStr); auto fracSec = fracSecsFromISOString(fracSecStr); Rebindable!(immutable TimeZone) parsedZone; if(zoneStr.empty) parsedZone = LocalTime(); else if(zoneStr == "Z") parsedZone = UTC(); else parsedZone = SimpleTimeZone.fromISOExtString(zoneStr); auto retval = SysTime(dateTime, fracSec, parsedZone); if(tz !is null) retval.timezone = tz; return retval; } catch(DateTimeException dte) throw new DateTimeException(format("Invalid Simple String: %s", simpleString)); } /// unittest { assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") == SysTime(DateTime(2010, 7, 4, 7, 6, 12))); assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") == SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7))); assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") == SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20))); assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") == SysTime(DateTime(-4, 1, 5, 0, 0, 2))); assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == SysTime(DateTime(2010, 7, 4, 7, 6, 12))); assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC())); assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new immutable SimpleTimeZone(hours(-8)))); assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new immutable SimpleTimeZone(hours(8)))); } unittest { import std.format : format; foreach(str; ["", "20100704000000", "20100704 000000", "20100704t000000", "20100704T000000.", "20100704T000000.0", "2010-07-0400:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00", "2010-07-04T00:00:00.", "2010-07-04T00:00:00.0", "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00", "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.A", "2010-Jul-04 00:00:00.Z", "2010-Jul-04 00:00:00.00000000", "2010-Jul-04 00:00:00.00000000", "2010-Jul-04 00:00:00+", "2010-Jul-04 00:00:00-", "2010-Jul-04 00:00:00:", "2010-Jul-04 00:00:00-:", "2010-Jul-04 00:00:00+:", "2010-Jul-04 00:00:00-1:", "2010-Jul-04 00:00:00+1:", "2010-Jul-04 00:00:00+1:0", "2010-Jul-04 00:00:00-12.00", "2010-Jul-04 00:00:00+12.00", "2010-Jul-04 00:00:00-8", "2010-Jul-04 00:00:00+8", "20100704T000000-800", "20100704T000000+800", "20100704T000000-080", "20100704T000000+080", "20100704T000000-2400", "20100704T000000+2400", "20100704T000000-1260", "20100704T000000+1260", "20100704T000000.0-800", "20100704T000000.0+800", "20100704T000000.0-8", "20100704T000000.0+8", "20100704T000000.0-080", "20100704T000000.0+080", "20100704T000000.0-2400", "20100704T000000.0+2400", "20100704T000000.0-1260", "20100704T000000.0+1260", "2010-Jul-04 00:00:00-8:00", "2010-Jul-04 00:00:00+8:00", "2010-Jul-04 00:00:00-08:0", "2010-Jul-04 00:00:00+08:0", "2010-Jul-04 00:00:00-24:00", "2010-Jul-04 00:00:00+24:00", "2010-Jul-04 00:00:00-12:60", "2010-Jul-04 00:00:00+24:60", "2010-Jul-04 00:00:00.0-8:00", "2010-Jul-04 00:00:00+8:00", "2010-Jul-04 00:00:00.0-8", "2010-Jul-04 00:00:00.0+8", "2010-Jul-04 00:00:00.0-08:0", "2010-Jul-04 00:00:00.0+08:0", "2010-Jul-04 00:00:00.0-24:00", "2010-Jul-04 00:00:00.0+24:00", "2010-Jul-04 00:00:00.0-12:60", "2010-Jul-04 00:00:00.0+24:60", "20101222T172201", "2010-12-22T172201"]) { assertThrown!DateTimeException(SysTime.fromSimpleString(str), format("[%s]", str)); } static void test(string str, SysTime st, size_t line = __LINE__) { if(SysTime.fromSimpleString(str) != st) throw new AssertError("unittest failure", __FILE__, line); } test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01))); test("1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test("-1999-Jul-06 12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33))); test("+01999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test("1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test(" 1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test(" 1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33))); test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12))); test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12))); test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1))); test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1))); test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1))); test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1))); test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1))); auto west60 = new immutable SimpleTimeZone(hours(-1)); auto west90 = new immutable SimpleTimeZone(minutes(-90)); auto west480 = new immutable SimpleTimeZone(hours(-8)); auto east60 = new immutable SimpleTimeZone(hours(1)); auto east90 = new immutable SimpleTimeZone(minutes(90)); auto east480 = new immutable SimpleTimeZone(hours(8)); test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC())); test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60)); test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60)); test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90)); test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480)); test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90)); test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480)); test("2010-Nov-03 06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC())); test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC())); test("2010-Dec-22 17:22:01.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60)); test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60)); test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90)); test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480)); test("2010-Dec-22 17:22:01.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60)); test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60)); test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90)); test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480)); } /++ Returns the $(LREF SysTime) farthest in the past which is representable by $(LREF SysTime). The $(LREF SysTime) which is returned is in UTC. +/ @property static SysTime min() @safe pure nothrow { return SysTime(long.min, UTC()); } unittest { assert(SysTime.min.year < 0); assert(SysTime.min < SysTime.max); } /++ Returns the $(LREF SysTime) farthest in the future which is representable by $(LREF SysTime). The $(LREF SysTime) which is returned is in UTC. +/ @property static SysTime max() @safe pure nothrow { return SysTime(long.max, UTC()); } unittest { assert(SysTime.max.year > 0); assert(SysTime.max > SysTime.min); } private: /+ Returns $(D stdTime) converted to $(LREF SysTime)'s time zone. +/ @property long adjTime() @safe const nothrow { return _timezone.utcToTZ(_stdTime); } /+ Converts the given hnsecs from $(LREF SysTime)'s time zone to std time. +/ @property void adjTime(long adjTime) @safe nothrow { _stdTime = _timezone.tzToUTC(adjTime); } //Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5058 /+ invariant() { assert(_timezone !is null, "Invariant Failure: timezone is null. Were you foolish enough to use SysTime.init? (since timezone for SysTime.init can't be set at compile time)."); } +/ long _stdTime; Rebindable!(immutable TimeZone) _timezone; } /++ Represents a date in the $(WEB en.wikipedia.org/wiki/Proleptic_Gregorian_calendar, Proleptic Gregorian Calendar) ranging from 32,768 B.C. to 32,767 A.D. Positive years are A.D. Non-positive years are B.C. Year, month, and day are kept separately internally so that $(D Date) is optimized for calendar-based operations. $(D Date) uses the Proleptic Gregorian Calendar, so it assumes the Gregorian leap year calculations for its entire length. As per $(WEB en.wikipedia.org/wiki/ISO_8601, ISO 8601), it treats 1 B.C. as year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use $(LREF yearBC) to use B.C. as a positive integer with 1 B.C. being the year prior to 1 A.D. Year 0 is a leap year. +/ struct Date { public: /++ Throws: $(LREF DateTimeException) if the resulting $(LREF Date) would not be valid. Params: year = Year of the Gregorian Calendar. Positive values are A.D. Non-positive values are B.C. with year 0 being the year prior to 1 A.D. month = Month of the year. day = Day of the month. +/ this(int year, int month, int day) @safe pure { enforceValid!"months"(cast(Month)month); enforceValid!"days"(year, cast(Month)month, day); _year = cast(short)year; _month = cast(Month)month; _day = cast(ubyte)day; } unittest { assert(Date(1, 1, 1) == Date.init); static void testDate(in Date date, int year, int month, int day) { assert(date._year == year); assert(date._month == month); assert(date._day == day); } testDate(Date(1999, 1 , 1), 1999, Month.jan, 1); testDate(Date(1999, 7 , 1), 1999, Month.jul, 1); testDate(Date(1999, 7 , 6), 1999, Month.jul, 6); //Test A.D. assertThrown!DateTimeException(Date(1, 0, 1)); assertThrown!DateTimeException(Date(1, 1, 0)); assertThrown!DateTimeException(Date(1999, 13, 1)); assertThrown!DateTimeException(Date(1999, 1, 32)); assertThrown!DateTimeException(Date(1999, 2, 29)); assertThrown!DateTimeException(Date(2000, 2, 30)); assertThrown!DateTimeException(Date(1999, 3, 32)); assertThrown!DateTimeException(Date(1999, 4, 31)); assertThrown!DateTimeException(Date(1999, 5, 32)); assertThrown!DateTimeException(Date(1999, 6, 31)); assertThrown!DateTimeException(Date(1999, 7, 32)); assertThrown!DateTimeException(Date(1999, 8, 32)); assertThrown!DateTimeException(Date(1999, 9, 31)); assertThrown!DateTimeException(Date(1999, 10, 32)); assertThrown!DateTimeException(Date(1999, 11, 31)); assertThrown!DateTimeException(Date(1999, 12, 32)); assertNotThrown!DateTimeException(Date(1999, 1, 31)); assertNotThrown!DateTimeException(Date(1999, 2, 28)); assertNotThrown!DateTimeException(Date(2000, 2, 29)); assertNotThrown!DateTimeException(Date(1999, 3, 31)); assertNotThrown!DateTimeException(Date(1999, 4, 30)); assertNotThrown!DateTimeException(Date(1999, 5, 31)); assertNotThrown!DateTimeException(Date(1999, 6, 30)); assertNotThrown!DateTimeException(Date(1999, 7, 31)); assertNotThrown!DateTimeException(Date(1999, 8, 31)); assertNotThrown!DateTimeException(Date(1999, 9, 30)); assertNotThrown!DateTimeException(Date(1999, 10, 31)); assertNotThrown!DateTimeException(Date(1999, 11, 30)); assertNotThrown!DateTimeException(Date(1999, 12, 31)); //Test B.C. assertNotThrown!DateTimeException(Date(0, 1, 1)); assertNotThrown!DateTimeException(Date(-1, 1, 1)); assertNotThrown!DateTimeException(Date(-1, 12, 31)); assertNotThrown!DateTimeException(Date(-1, 2, 28)); assertNotThrown!DateTimeException(Date(-4, 2, 29)); assertThrown!DateTimeException(Date(-1, 2, 29)); assertThrown!DateTimeException(Date(-2, 2, 29)); assertThrown!DateTimeException(Date(-3, 2, 29)); } /++ Params: day = The Xth day of the Gregorian Calendar that the constructed $(LREF Date) will be for. +/ this(int day) @safe pure nothrow { if(day > 0) { int years = (day / daysIn400Years) * 400 + 1; day %= daysIn400Years; { immutable tempYears = day / daysIn100Years; if(tempYears == 4) { years += 300; day -= daysIn100Years * 3; } else { years += tempYears * 100; day %= daysIn100Years; } } years += (day / daysIn4Years) * 4; day %= daysIn4Years; { immutable tempYears = day / daysInYear; if(tempYears == 4) { years += 3; day -= daysInYear * 3; } else { years += tempYears; day %= daysInYear; } } if(day == 0) { _year = cast(short)(years - 1); _month = Month.dec; _day = 31; } else { _year = cast(short)years; try dayOfYear = day; catch(Exception e) assert(0, "dayOfYear assignment threw."); } } else if(day <= 0 && -day < daysInLeapYear) { _year = 0; try dayOfYear = (daysInLeapYear + day); catch(Exception e) assert(0, "dayOfYear assignment threw."); } else { day += daysInLeapYear - 1; int years = (day / daysIn400Years) * 400 - 1; day %= daysIn400Years; { immutable tempYears = day / daysIn100Years; if(tempYears == -4) { years -= 300; day += daysIn100Years * 3; } else { years += tempYears * 100; day %= daysIn100Years; } } years += (day / daysIn4Years) * 4; day %= daysIn4Years; { immutable tempYears = day / daysInYear; if(tempYears == -4) { years -= 3; day += daysInYear * 3; } else { years += tempYears; day %= daysInYear; } } if(day == 0) { _year = cast(short)(years + 1); _month = Month.jan; _day = 1; } else { _year = cast(short)years; immutable newDoY = (yearIsLeapYear(_year) ? daysInLeapYear : daysInYear) + day + 1; try dayOfYear = newDoY; catch(Exception e) assert(0, "dayOfYear assignment threw."); } } } unittest { import std.range; //Test A.D. foreach(gd; chain(testGregDaysBC, testGregDaysAD)) assert(Date(gd.day) == gd.date); } /++ Compares this $(LREF Date) with the given $(LREF Date). Returns: $(BOOKTABLE, $(TR $(TD this < rhs) $(TD < 0)) $(TR $(TD this == rhs) $(TD 0)) $(TR $(TD this > rhs) $(TD > 0)) ) +/ int opCmp(in Date rhs) @safe const pure nothrow { if(_year < rhs._year) return -1; if(_year > rhs._year) return 1; if(_month < rhs._month) return -1; if(_month > rhs._month) return 1; if(_day < rhs._day) return -1; if(_day > rhs._day) return 1; return 0; } unittest { //Test A.D. assert(Date(1, 1, 1).opCmp(Date.init) == 0); assert(Date(1999, 1, 1).opCmp(Date(1999, 1, 1)) == 0); assert(Date(1, 7, 1).opCmp(Date(1, 7, 1)) == 0); assert(Date(1, 1, 6).opCmp(Date(1, 1, 6)) == 0); assert(Date(1999, 7, 1).opCmp(Date(1999, 7, 1)) == 0); assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 6)) == 0); assert(Date(1, 7, 6).opCmp(Date(1, 7, 6)) == 0); assert(Date(1999, 7, 6).opCmp(Date(2000, 7, 6)) < 0); assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 6)) > 0); assert(Date(1999, 7, 6).opCmp(Date(1999, 8, 6)) < 0); assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 6)) > 0); assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 7)) < 0); assert(Date(1999, 7, 7).opCmp(Date(1999, 7, 6)) > 0); assert(Date(1999, 8, 7).opCmp(Date(2000, 7, 6)) < 0); assert(Date(2000, 8, 6).opCmp(Date(1999, 7, 7)) > 0); assert(Date(1999, 7, 7).opCmp(Date(2000, 7, 6)) < 0); assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 7)) > 0); assert(Date(1999, 7, 7).opCmp(Date(1999, 8, 6)) < 0); assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 7)) > 0); //Test B.C. assert(Date(0, 1, 1).opCmp(Date(0, 1, 1)) == 0); assert(Date(-1, 1, 1).opCmp(Date(-1, 1, 1)) == 0); assert(Date(-1, 7, 1).opCmp(Date(-1, 7, 1)) == 0); assert(Date(-1, 1, 6).opCmp(Date(-1, 1, 6)) == 0); assert(Date(-1999, 7, 1).opCmp(Date(-1999, 7, 1)) == 0); assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 6)) == 0); assert(Date(-1, 7, 6).opCmp(Date(-1, 7, 6)) == 0); assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 6)) < 0); assert(Date(-1999, 7, 6).opCmp(Date(-2000, 7, 6)) > 0); assert(Date(-1999, 7, 6).opCmp(Date(-1999, 8, 6)) < 0); assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 6)) > 0); assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); assert(Date(-1999, 7, 7).opCmp(Date(-1999, 7, 6)) > 0); assert(Date(-2000, 8, 6).opCmp(Date(-1999, 7, 7)) < 0); assert(Date(-1999, 8, 7).opCmp(Date(-2000, 7, 6)) > 0); assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); assert(Date(-1999, 7, 7).opCmp(Date(-2000, 7, 6)) > 0); assert(Date(-1999, 7, 7).opCmp(Date(-1999, 8, 6)) < 0); assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 7)) > 0); //Test Both assert(Date(-1999, 7, 6).opCmp(Date(1999, 7, 6)) < 0); assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 6)) > 0); assert(Date(-1999, 8, 6).opCmp(Date(1999, 7, 6)) < 0); assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 6)) > 0); assert(Date(-1999, 7, 7).opCmp(Date(1999, 7, 6)) < 0); assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 7)) > 0); assert(Date(-1999, 8, 7).opCmp(Date(1999, 7, 6)) < 0); assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 7)) > 0); assert(Date(-1999, 8, 6).opCmp(Date(1999, 6, 6)) < 0); assert(Date(1999, 6, 8).opCmp(Date(-1999, 7, 6)) > 0); auto date = Date(1999, 7, 6); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(date.opCmp(date) == 0); assert(date.opCmp(cdate) == 0); assert(date.opCmp(idate) == 0); assert(cdate.opCmp(date) == 0); assert(cdate.opCmp(cdate) == 0); assert(cdate.opCmp(idate) == 0); assert(idate.opCmp(date) == 0); assert(idate.opCmp(cdate) == 0); assert(idate.opCmp(idate) == 0); } /++ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C. +/ @property short year() @safe const pure nothrow { return _year; } /// unittest { assert(Date(1999, 7, 6).year == 1999); assert(Date(2010, 10, 4).year == 2010); assert(Date(-7, 4, 5).year == -7); } unittest { assert(Date.init.year == 1); assert(Date(1999, 7, 6).year == 1999); assert(Date(-1999, 7, 6).year == -1999); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.year == 1999); assert(idate.year == 1999); } /++ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C. Params: year = The year to set this Date's year to. Throws: $(LREF DateTimeException) if the new year is not a leap year and the resulting date would be on February 29th. +/ @property void year(int year) @safe pure { enforceValid!"days"(year, _month, _day); _year = cast(short)year; } /// unittest { assert(Date(1999, 7, 6).year == 1999); assert(Date(2010, 10, 4).year == 2010); assert(Date(-7, 4, 5).year == -7); } unittest { static void testDateInvalid(Date date, int year) { date.year = year; } static void testDate(Date date, int year, in Date expected) { date.year = year; assert(date == expected); } assertThrown!DateTimeException(testDateInvalid(Date(4, 2, 29), 1)); testDate(Date(1, 1, 1), 1999, Date(1999, 1, 1)); testDate(Date(1, 1, 1), 0, Date(0, 1, 1)); testDate(Date(1, 1, 1), -1999, Date(-1999, 1, 1)); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.year = 1999)); static assert(!__traits(compiles, idate.year = 1999)); } /++ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. Throws: $(LREF DateTimeException) if $(D isAD) is true. +/ @property ushort yearBC() @safe const pure { import std.format : format; if(isAD) throw new DateTimeException(format("Year %s is A.D.", _year)); return cast(ushort)((_year * -1) + 1); } /// unittest { assert(Date(0, 1, 1).yearBC == 1); assert(Date(-1, 1, 1).yearBC == 2); assert(Date(-100, 1, 1).yearBC == 101); } unittest { assertThrown!DateTimeException((in Date date){date.yearBC;}(Date(1, 1, 1))); auto date = Date(0, 7, 6); const cdate = Date(0, 7, 6); immutable idate = Date(0, 7, 6); assert(date.yearBC == 1); assert(cdate.yearBC == 1); assert(idate.yearBC == 1); } /++ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. Params: year = The year B.C. to set this $(LREF Date)'s year to. Throws: $(LREF DateTimeException) if a non-positive value is given. +/ @property void yearBC(int year) @safe pure { if(year <= 0) throw new DateTimeException("The given year is not a year B.C."); _year = cast(short)((year - 1) * -1); } /// unittest { auto date = Date(2010, 1, 1); date.yearBC = 1; assert(date == Date(0, 1, 1)); date.yearBC = 10; assert(date == Date(-9, 1, 1)); } unittest { assertThrown!DateTimeException((Date date){date.yearBC = -1;}(Date(1, 1, 1))); auto date = Date(0, 7, 6); const cdate = Date(0, 7, 6); immutable idate = Date(0, 7, 6); date.yearBC = 7; assert(date.yearBC == 7); static assert(!__traits(compiles, cdate.yearBC = 7)); static assert(!__traits(compiles, idate.yearBC = 7)); } /++ Month of a Gregorian Year. +/ @property Month month() @safe const pure nothrow { return _month; } /// unittest { assert(Date(1999, 7, 6).month == 7); assert(Date(2010, 10, 4).month == 10); assert(Date(-7, 4, 5).month == 4); } unittest { assert(Date.init.month == 1); assert(Date(1999, 7, 6).month == 7); assert(Date(-1999, 7, 6).month == 7); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.month == 7); assert(idate.month == 7); } /++ Month of a Gregorian Year. Params: month = The month to set this $(LREF Date)'s month to. Throws: $(LREF DateTimeException) if the given month is not a valid month or if the current day would not be valid in the given month. +/ @property void month(Month month) @safe pure { enforceValid!"months"(month); enforceValid!"days"(_year, month, _day); _month = cast(Month)month; } unittest { static void testDate(Date date, Month month, in Date expected = Date.init) { date.month = month; assert(expected != Date.init); assert(date == expected); } assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month)0)); assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month)13)); assertThrown!DateTimeException(testDate(Date(1, 1, 29), cast(Month)2)); assertThrown!DateTimeException(testDate(Date(0, 1, 30), cast(Month)2)); testDate(Date(1, 1, 1), cast(Month)7, Date(1, 7, 1)); testDate(Date(-1, 1, 1), cast(Month)7, Date(-1, 7, 1)); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.month = 7)); static assert(!__traits(compiles, idate.month = 7)); } /++ Day of a Gregorian Month. +/ @property ubyte day() @safe const pure nothrow { return _day; } /// unittest { assert(Date(1999, 7, 6).day == 6); assert(Date(2010, 10, 4).day == 4); assert(Date(-7, 4, 5).day == 5); } unittest { import std.range; import std.format : format; static void test(Date date, int expected) { assert(date.day == expected, format("Value given: %s", date)); } foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) test(Date(year, md.month, md.day), md.day); } const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.day == 6); assert(idate.day == 6); } /++ Day of a Gregorian Month. Params: day = The day of the month to set this $(LREF Date)'s day to. Throws: $(LREF DateTimeException) if the given day is not a valid day of the current month. +/ @property void day(int day) @safe pure { enforceValid!"days"(_year, _month, day); _day = cast(ubyte)day; } unittest { static void testDate(Date date, int day) { date.day = day; } //Test A.D. assertThrown!DateTimeException(testDate(Date(1, 1, 1), 0)); assertThrown!DateTimeException(testDate(Date(1, 1, 1), 32)); assertThrown!DateTimeException(testDate(Date(1, 2, 1), 29)); assertThrown!DateTimeException(testDate(Date(4, 2, 1), 30)); assertThrown!DateTimeException(testDate(Date(1, 3, 1), 32)); assertThrown!DateTimeException(testDate(Date(1, 4, 1), 31)); assertThrown!DateTimeException(testDate(Date(1, 5, 1), 32)); assertThrown!DateTimeException(testDate(Date(1, 6, 1), 31)); assertThrown!DateTimeException(testDate(Date(1, 7, 1), 32)); assertThrown!DateTimeException(testDate(Date(1, 8, 1), 32)); assertThrown!DateTimeException(testDate(Date(1, 9, 1), 31)); assertThrown!DateTimeException(testDate(Date(1, 10, 1), 32)); assertThrown!DateTimeException(testDate(Date(1, 11, 1), 31)); assertThrown!DateTimeException(testDate(Date(1, 12, 1), 32)); assertNotThrown!DateTimeException(testDate(Date(1, 1, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(1, 2, 1), 28)); assertNotThrown!DateTimeException(testDate(Date(4, 2, 1), 29)); assertNotThrown!DateTimeException(testDate(Date(1, 3, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(1, 4, 1), 30)); assertNotThrown!DateTimeException(testDate(Date(1, 5, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(1, 6, 1), 30)); assertNotThrown!DateTimeException(testDate(Date(1, 7, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(1, 8, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(1, 9, 1), 30)); assertNotThrown!DateTimeException(testDate(Date(1, 10, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(1, 11, 1), 30)); assertNotThrown!DateTimeException(testDate(Date(1, 12, 1), 31)); { auto date = Date(1, 1, 1); date.day = 6; assert(date == Date(1, 1, 6)); } //Test B.C. assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 0)); assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 32)); assertThrown!DateTimeException(testDate(Date(-1, 2, 1), 29)); assertThrown!DateTimeException(testDate(Date(0, 2, 1), 30)); assertThrown!DateTimeException(testDate(Date(-1, 3, 1), 32)); assertThrown!DateTimeException(testDate(Date(-1, 4, 1), 31)); assertThrown!DateTimeException(testDate(Date(-1, 5, 1), 32)); assertThrown!DateTimeException(testDate(Date(-1, 6, 1), 31)); assertThrown!DateTimeException(testDate(Date(-1, 7, 1), 32)); assertThrown!DateTimeException(testDate(Date(-1, 8, 1), 32)); assertThrown!DateTimeException(testDate(Date(-1, 9, 1), 31)); assertThrown!DateTimeException(testDate(Date(-1, 10, 1), 32)); assertThrown!DateTimeException(testDate(Date(-1, 11, 1), 31)); assertThrown!DateTimeException(testDate(Date(-1, 12, 1), 32)); assertNotThrown!DateTimeException(testDate(Date(-1, 1, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(-1, 2, 1), 28)); assertNotThrown!DateTimeException(testDate(Date(0, 2, 1), 29)); assertNotThrown!DateTimeException(testDate(Date(-1, 3, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(-1, 4, 1), 30)); assertNotThrown!DateTimeException(testDate(Date(-1, 5, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(-1, 6, 1), 30)); assertNotThrown!DateTimeException(testDate(Date(-1, 7, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(-1, 8, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(-1, 9, 1), 30)); assertNotThrown!DateTimeException(testDate(Date(-1, 10, 1), 31)); assertNotThrown!DateTimeException(testDate(Date(-1, 11, 1), 30)); assertNotThrown!DateTimeException(testDate(Date(-1, 12, 1), 31)); { auto date = Date(-1, 1, 1); date.day = 6; assert(date == Date(-1, 1, 6)); } const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.day = 6)); static assert(!__traits(compiles, idate.day = 6)); } /++ Adds the given number of years or months to this $(LREF Date). A negative number will subtract. Note that if day overflow is allowed, and the date with the adjusted year/month overflows the number of days in the new month, then the month will be incremented by one, and the day set to the number of days overflowed. (e.g. if the day were 31 and the new month were June, then the month would be incremented to July, and the new day would be 1). If day overflow is not allowed, then the day will be set to the last valid day in the month (e.g. June 31st would become June 30th). Params: units = The type of units to add ("years" or "months"). value = The number of months or years to add to this $(LREF Date). allowOverflow = Whether the day should be allowed to overflow, causing the month to increment. +/ ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow if(units == "years") { immutable newYear = _year + value; _year += value; if(_month == Month.feb && _day == 29 && !yearIsLeapYear(_year)) { if(allowOverflow == AllowDayOverflow.yes) { _month = Month.mar; _day = 1; } else _day = 28; } return this; } /// unittest { auto d1 = Date(2010, 1, 1); d1.add!"months"(11); assert(d1 == Date(2010, 12, 1)); auto d2 = Date(2010, 1, 1); d2.add!"months"(-11); assert(d2 == Date(2009, 2, 1)); auto d3 = Date(2000, 2, 29); d3.add!"years"(1); assert(d3 == Date(2001, 3, 1)); auto d4 = Date(2000, 2, 29); d4.add!"years"(1, AllowDayOverflow.no); assert(d4 == Date(2001, 2, 28)); } //Test add!"years"() with AllowDayOverlow.yes unittest { //Test A.D. { auto date = Date(1999, 7, 6); date.add!"years"(7); assert(date == Date(2006, 7, 6)); date.add!"years"(-9); assert(date == Date(1997, 7, 6)); } { auto date = Date(1999, 2, 28); date.add!"years"(1); assert(date == Date(2000, 2, 28)); } { auto date = Date(2000, 2, 29); date.add!"years"(-1); assert(date == Date(1999, 3, 1)); } //Test B.C. { auto date = Date(-1999, 7, 6); date.add!"years"(-7); assert(date == Date(-2006, 7, 6)); date.add!"years"(9); assert(date == Date(-1997, 7, 6)); } { auto date = Date(-1999, 2, 28); date.add!"years"(-1); assert(date == Date(-2000, 2, 28)); } { auto date = Date(-2000, 2, 29); date.add!"years"(1); assert(date == Date(-1999, 3, 1)); } //Test Both { auto date = Date(4, 7, 6); date.add!"years"(-5); assert(date == Date(-1, 7, 6)); date.add!"years"(5); assert(date == Date(4, 7, 6)); } { auto date = Date(-4, 7, 6); date.add!"years"(5); assert(date == Date(1, 7, 6)); date.add!"years"(-5); assert(date == Date(-4, 7, 6)); } { auto date = Date(4, 7, 6); date.add!"years"(-8); assert(date == Date(-4, 7, 6)); date.add!"years"(8); assert(date == Date(4, 7, 6)); } { auto date = Date(-4, 7, 6); date.add!"years"(8); assert(date == Date(4, 7, 6)); date.add!"years"(-8); assert(date == Date(-4, 7, 6)); } { auto date = Date(-4, 2, 29); date.add!"years"(5); assert(date == Date(1, 3, 1)); } { auto date = Date(4, 2, 29); date.add!"years"(-5); assert(date == Date(-1, 3, 1)); } { auto date = Date(4, 2, 29); date.add!"years"(-5).add!"years"(7); assert(date == Date(6, 3, 1)); } const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.add!"years"(7))); static assert(!__traits(compiles, idate.add!"years"(7))); } //Test add!"years"() with AllowDayOverlow.no unittest { //Test A.D. { auto date = Date(1999, 7, 6); date.add!"years"(7, AllowDayOverflow.no); assert(date == Date(2006, 7, 6)); date.add!"years"(-9, AllowDayOverflow.no); assert(date == Date(1997, 7, 6)); } { auto date = Date(1999, 2, 28); date.add!"years"(1, AllowDayOverflow.no); assert(date == Date(2000, 2, 28)); } { auto date = Date(2000, 2, 29); date.add!"years"(-1, AllowDayOverflow.no); assert(date == Date(1999, 2, 28)); } //Test B.C. { auto date = Date(-1999, 7, 6); date.add!"years"(-7, AllowDayOverflow.no); assert(date == Date(-2006, 7, 6)); date.add!"years"(9, AllowDayOverflow.no); assert(date == Date(-1997, 7, 6)); } { auto date = Date(-1999, 2, 28); date.add!"years"(-1, AllowDayOverflow.no); assert(date == Date(-2000, 2, 28)); } { auto date = Date(-2000, 2, 29); date.add!"years"(1, AllowDayOverflow.no); assert(date == Date(-1999, 2, 28)); } //Test Both { auto date = Date(4, 7, 6); date.add!"years"(-5, AllowDayOverflow.no); assert(date == Date(-1, 7, 6)); date.add!"years"(5, AllowDayOverflow.no); assert(date == Date(4, 7, 6)); } { auto date = Date(-4, 7, 6); date.add!"years"(5, AllowDayOverflow.no); assert(date == Date(1, 7, 6)); date.add!"years"(-5, AllowDayOverflow.no); assert(date == Date(-4, 7, 6)); } { auto date = Date(4, 7, 6); date.add!"years"(-8, AllowDayOverflow.no); assert(date == Date(-4, 7, 6)); date.add!"years"(8, AllowDayOverflow.no); assert(date == Date(4, 7, 6)); } { auto date = Date(-4, 7, 6); date.add!"years"(8, AllowDayOverflow.no); assert(date == Date(4, 7, 6)); date.add!"years"(-8, AllowDayOverflow.no); assert(date == Date(-4, 7, 6)); } { auto date = Date(-4, 2, 29); date.add!"years"(5, AllowDayOverflow.no); assert(date == Date(1, 2, 28)); } { auto date = Date(4, 2, 29); date.add!"years"(-5, AllowDayOverflow.no); assert(date == Date(-1, 2, 28)); } { auto date = Date(4, 2, 29); date.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no); assert(date == Date(6, 2, 28)); } } //Shares documentation with "years" version. ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow if(units == "months") { auto years = months / 12; months %= 12; auto newMonth = _month + months; if(months < 0) { if(newMonth < 1) { newMonth += 12; --years; } } else if(newMonth > 12) { newMonth -= 12; ++years; } _year += years; _month = cast(Month)newMonth; immutable currMaxDay = maxDay(_year, _month); immutable overflow = _day - currMaxDay; if(overflow > 0) { if(allowOverflow == AllowDayOverflow.yes) { ++_month; _day = cast(ubyte)overflow; } else _day = cast(ubyte)currMaxDay; } return this; } //Test add!"months"() with AllowDayOverlow.yes unittest { //Test A.D. { auto date = Date(1999, 7, 6); date.add!"months"(3); assert(date == Date(1999, 10, 6)); date.add!"months"(-4); assert(date == Date(1999, 6, 6)); } { auto date = Date(1999, 7, 6); date.add!"months"(6); assert(date == Date(2000, 1, 6)); date.add!"months"(-6); assert(date == Date(1999, 7, 6)); } { auto date = Date(1999, 7, 6); date.add!"months"(27); assert(date == Date(2001, 10, 6)); date.add!"months"(-28); assert(date == Date(1999, 6, 6)); } { auto date = Date(1999, 5, 31); date.add!"months"(1); assert(date == Date(1999, 7, 1)); } { auto date = Date(1999, 5, 31); date.add!"months"(-1); assert(date == Date(1999, 5, 1)); } { auto date = Date(1999, 2, 28); date.add!"months"(12); assert(date == Date(2000, 2, 28)); } { auto date = Date(2000, 2, 29); date.add!"months"(12); assert(date == Date(2001, 3, 1)); } { auto date = Date(1999, 7, 31); date.add!"months"(1); assert(date == Date(1999, 8, 31)); date.add!"months"(1); assert(date == Date(1999, 10, 1)); } { auto date = Date(1998, 8, 31); date.add!"months"(13); assert(date == Date(1999, 10, 1)); date.add!"months"(-13); assert(date == Date(1998, 9, 1)); } { auto date = Date(1997, 12, 31); date.add!"months"(13); assert(date == Date(1999, 1, 31)); date.add!"months"(-13); assert(date == Date(1997, 12, 31)); } { auto date = Date(1997, 12, 31); date.add!"months"(14); assert(date == Date(1999, 3, 3)); date.add!"months"(-14); assert(date == Date(1998, 1, 3)); } { auto date = Date(1998, 12, 31); date.add!"months"(14); assert(date == Date(2000, 3, 2)); date.add!"months"(-14); assert(date == Date(1999, 1, 2)); } { auto date = Date(1999, 12, 31); date.add!"months"(14); assert(date == Date(2001, 3, 3)); date.add!"months"(-14); assert(date == Date(2000, 1, 3)); } //Test B.C. { auto date = Date(-1999, 7, 6); date.add!"months"(3); assert(date == Date(-1999, 10, 6)); date.add!"months"(-4); assert(date == Date(-1999, 6, 6)); } { auto date = Date(-1999, 7, 6); date.add!"months"(6); assert(date == Date(-1998, 1, 6)); date.add!"months"(-6); assert(date == Date(-1999, 7, 6)); } { auto date = Date(-1999, 7, 6); date.add!"months"(-27); assert(date == Date(-2001, 4, 6)); date.add!"months"(28); assert(date == Date(-1999, 8, 6)); } { auto date = Date(-1999, 5, 31); date.add!"months"(1); assert(date == Date(-1999, 7, 1)); } { auto date = Date(-1999, 5, 31); date.add!"months"(-1); assert(date == Date(-1999, 5, 1)); } { auto date = Date(-1999, 2, 28); date.add!"months"(-12); assert(date == Date(-2000, 2, 28)); } { auto date = Date(-2000, 2, 29); date.add!"months"(-12); assert(date == Date(-2001, 3, 1)); } { auto date = Date(-1999, 7, 31); date.add!"months"(1); assert(date == Date(-1999, 8, 31)); date.add!"months"(1); assert(date == Date(-1999, 10, 1)); } { auto date = Date(-1998, 8, 31); date.add!"months"(13); assert(date == Date(-1997, 10, 1)); date.add!"months"(-13); assert(date == Date(-1998, 9, 1)); } { auto date = Date(-1997, 12, 31); date.add!"months"(13); assert(date == Date(-1995, 1, 31)); date.add!"months"(-13); assert(date == Date(-1997, 12, 31)); } { auto date = Date(-1997, 12, 31); date.add!"months"(14); assert(date == Date(-1995, 3, 3)); date.add!"months"(-14); assert(date == Date(-1996, 1, 3)); } { auto date = Date(-2002, 12, 31); date.add!"months"(14); assert(date == Date(-2000, 3, 2)); date.add!"months"(-14); assert(date == Date(-2001, 1, 2)); } { auto date = Date(-2001, 12, 31); date.add!"months"(14); assert(date == Date(-1999, 3, 3)); date.add!"months"(-14); assert(date == Date(-2000, 1, 3)); } //Test Both { auto date = Date(1, 1, 1); date.add!"months"(-1); assert(date == Date(0, 12, 1)); date.add!"months"(1); assert(date == Date(1, 1, 1)); } { auto date = Date(4, 1, 1); date.add!"months"(-48); assert(date == Date(0, 1, 1)); date.add!"months"(48); assert(date == Date(4, 1, 1)); } { auto date = Date(4, 3, 31); date.add!"months"(-49); assert(date == Date(0, 3, 2)); date.add!"months"(49); assert(date == Date(4, 4, 2)); } { auto date = Date(4, 3, 31); date.add!"months"(-85); assert(date == Date(-3, 3, 3)); date.add!"months"(85); assert(date == Date(4, 4, 3)); } { auto date = Date(-3, 3, 31); date.add!"months"(85).add!"months"(-83); assert(date == Date(-3, 6, 1)); } const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.add!"months"(3))); static assert(!__traits(compiles, idate.add!"months"(3))); } //Test add!"months"() with AllowDayOverlow.no unittest { //Test A.D. { auto date = Date(1999, 7, 6); date.add!"months"(3, AllowDayOverflow.no); assert(date == Date(1999, 10, 6)); date.add!"months"(-4, AllowDayOverflow.no); assert(date == Date(1999, 6, 6)); } { auto date = Date(1999, 7, 6); date.add!"months"(6, AllowDayOverflow.no); assert(date == Date(2000, 1, 6)); date.add!"months"(-6, AllowDayOverflow.no); assert(date == Date(1999, 7, 6)); } { auto date = Date(1999, 7, 6); date.add!"months"(27, AllowDayOverflow.no); assert(date == Date(2001, 10, 6)); date.add!"months"(-28, AllowDayOverflow.no); assert(date == Date(1999, 6, 6)); } { auto date = Date(1999, 5, 31); date.add!"months"(1, AllowDayOverflow.no); assert(date == Date(1999, 6, 30)); } { auto date = Date(1999, 5, 31); date.add!"months"(-1, AllowDayOverflow.no); assert(date == Date(1999, 4, 30)); } { auto date = Date(1999, 2, 28); date.add!"months"(12, AllowDayOverflow.no); assert(date == Date(2000, 2, 28)); } { auto date = Date(2000, 2, 29); date.add!"months"(12, AllowDayOverflow.no); assert(date == Date(2001, 2, 28)); } { auto date = Date(1999, 7, 31); date.add!"months"(1, AllowDayOverflow.no); assert(date == Date(1999, 8, 31)); date.add!"months"(1, AllowDayOverflow.no); assert(date == Date(1999, 9, 30)); } { auto date = Date(1998, 8, 31); date.add!"months"(13, AllowDayOverflow.no); assert(date == Date(1999, 9, 30)); date.add!"months"(-13, AllowDayOverflow.no); assert(date == Date(1998, 8, 30)); } { auto date = Date(1997, 12, 31); date.add!"months"(13, AllowDayOverflow.no); assert(date == Date(1999, 1, 31)); date.add!"months"(-13, AllowDayOverflow.no); assert(date == Date(1997, 12, 31)); } { auto date = Date(1997, 12, 31); date.add!"months"(14, AllowDayOverflow.no); assert(date == Date(1999, 2, 28)); date.add!"months"(-14, AllowDayOverflow.no); assert(date == Date(1997, 12, 28)); } { auto date = Date(1998, 12, 31); date.add!"months"(14, AllowDayOverflow.no); assert(date == Date(2000, 2, 29)); date.add!"months"(-14, AllowDayOverflow.no); assert(date == Date(1998, 12, 29)); } { auto date = Date(1999, 12, 31); date.add!"months"(14, AllowDayOverflow.no); assert(date == Date(2001, 2, 28)); date.add!"months"(-14, AllowDayOverflow.no); assert(date == Date(1999, 12, 28)); } //Test B.C. { auto date = Date(-1999, 7, 6); date.add!"months"(3, AllowDayOverflow.no); assert(date == Date(-1999, 10, 6)); date.add!"months"(-4, AllowDayOverflow.no); assert(date == Date(-1999, 6, 6)); } { auto date = Date(-1999, 7, 6); date.add!"months"(6, AllowDayOverflow.no); assert(date == Date(-1998, 1, 6)); date.add!"months"(-6, AllowDayOverflow.no); assert(date == Date(-1999, 7, 6)); } { auto date = Date(-1999, 7, 6); date.add!"months"(-27, AllowDayOverflow.no); assert(date == Date(-2001, 4, 6)); date.add!"months"(28, AllowDayOverflow.no); assert(date == Date(-1999, 8, 6)); } { auto date = Date(-1999, 5, 31); date.add!"months"(1, AllowDayOverflow.no); assert(date == Date(-1999, 6, 30)); } { auto date = Date(-1999, 5, 31); date.add!"months"(-1, AllowDayOverflow.no); assert(date == Date(-1999, 4, 30)); } { auto date = Date(-1999, 2, 28); date.add!"months"(-12, AllowDayOverflow.no); assert(date == Date(-2000, 2, 28)); } { auto date = Date(-2000, 2, 29); date.add!"months"(-12, AllowDayOverflow.no); assert(date == Date(-2001, 2, 28)); } { auto date = Date(-1999, 7, 31); date.add!"months"(1, AllowDayOverflow.no); assert(date == Date(-1999, 8, 31)); date.add!"months"(1, AllowDayOverflow.no); assert(date == Date(-1999, 9, 30)); } { auto date = Date(-1998, 8, 31); date.add!"months"(13, AllowDayOverflow.no); assert(date == Date(-1997, 9, 30)); date.add!"months"(-13, AllowDayOverflow.no); assert(date == Date(-1998, 8, 30)); } { auto date = Date(-1997, 12, 31); date.add!"months"(13, AllowDayOverflow.no); assert(date == Date(-1995, 1, 31)); date.add!"months"(-13, AllowDayOverflow.no); assert(date == Date(-1997, 12, 31)); } { auto date = Date(-1997, 12, 31); date.add!"months"(14, AllowDayOverflow.no); assert(date == Date(-1995, 2, 28)); date.add!"months"(-14, AllowDayOverflow.no); assert(date == Date(-1997, 12, 28)); } { auto date = Date(-2002, 12, 31); date.add!"months"(14, AllowDayOverflow.no); assert(date == Date(-2000, 2, 29)); date.add!"months"(-14, AllowDayOverflow.no); assert(date == Date(-2002, 12, 29)); } { auto date = Date(-2001, 12, 31); date.add!"months"(14, AllowDayOverflow.no); assert(date == Date(-1999, 2, 28)); date.add!"months"(-14, AllowDayOverflow.no); assert(date == Date(-2001, 12, 28)); } //Test Both { auto date = Date(1, 1, 1); date.add!"months"(-1, AllowDayOverflow.no); assert(date == Date(0, 12, 1)); date.add!"months"(1, AllowDayOverflow.no); assert(date == Date(1, 1, 1)); } { auto date = Date(4, 1, 1); date.add!"months"(-48, AllowDayOverflow.no); assert(date == Date(0, 1, 1)); date.add!"months"(48, AllowDayOverflow.no); assert(date == Date(4, 1, 1)); } { auto date = Date(4, 3, 31); date.add!"months"(-49, AllowDayOverflow.no); assert(date == Date(0, 2, 29)); date.add!"months"(49, AllowDayOverflow.no); assert(date == Date(4, 3, 29)); } { auto date = Date(4, 3, 31); date.add!"months"(-85, AllowDayOverflow.no); assert(date == Date(-3, 2, 28)); date.add!"months"(85, AllowDayOverflow.no); assert(date == Date(4, 3, 28)); } { auto date = Date(-3, 3, 31); date.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no); assert(date == Date(-3, 5, 30)); } } /++ Adds the given number of years or months to this $(LREF Date). A negative number will subtract. The difference between rolling and adding is that rolling does not affect larger units. Rolling a $(LREF Date) 12 months gets the exact same $(LREF Date). However, the days can still be affected due to the differing number of days in each month. Because there are no units larger than years, there is no difference between adding and rolling years. Params: units = The type of units to add ("years" or "months"). value = The number of months or years to add to this $(LREF Date). allowOverflow = Whether the day should be allowed to overflow, causing the month to increment. +/ ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow if(units == "years") { return add!"years"(value, allowOverflow); } /// unittest { auto d1 = Date(2010, 1, 1); d1.roll!"months"(1); assert(d1 == Date(2010, 2, 1)); auto d2 = Date(2010, 1, 1); d2.roll!"months"(-1); assert(d2 == Date(2010, 12, 1)); auto d3 = Date(1999, 1, 29); d3.roll!"months"(1); assert(d3 == Date(1999, 3, 1)); auto d4 = Date(1999, 1, 29); d4.roll!"months"(1, AllowDayOverflow.no); assert(d4 == Date(1999, 2, 28)); auto d5 = Date(2000, 2, 29); d5.roll!"years"(1); assert(d5 == Date(2001, 3, 1)); auto d6 = Date(2000, 2, 29); d6.roll!"years"(1, AllowDayOverflow.no); assert(d6 == Date(2001, 2, 28)); } unittest { const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.roll!"years"(3))); static assert(!__traits(compiles, idate.rolYears(3))); } //Shares documentation with "years" version. ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow if(units == "months") { months %= 12; auto newMonth = _month + months; if(months < 0) { if(newMonth < 1) newMonth += 12; } else { if(newMonth > 12) newMonth -= 12; } _month = cast(Month)newMonth; immutable currMaxDay = maxDay(_year, _month); immutable overflow = _day - currMaxDay; if(overflow > 0) { if(allowOverflow == AllowDayOverflow.yes) { ++_month; _day = cast(ubyte)overflow; } else _day = cast(ubyte)currMaxDay; } return this; } //Test roll!"months"() with AllowDayOverlow.yes unittest { //Test A.D. { auto date = Date(1999, 7, 6); date.roll!"months"(3); assert(date == Date(1999, 10, 6)); date.roll!"months"(-4); assert(date == Date(1999, 6, 6)); } { auto date = Date(1999, 7, 6); date.roll!"months"(6); assert(date == Date(1999, 1, 6)); date.roll!"months"(-6); assert(date == Date(1999, 7, 6)); } { auto date = Date(1999, 7, 6); date.roll!"months"(27); assert(date == Date(1999, 10, 6)); date.roll!"months"(-28); assert(date == Date(1999, 6, 6)); } { auto date = Date(1999, 5, 31); date.roll!"months"(1); assert(date == Date(1999, 7, 1)); } { auto date = Date(1999, 5, 31); date.roll!"months"(-1); assert(date == Date(1999, 5, 1)); } { auto date = Date(1999, 2, 28); date.roll!"months"(12); assert(date == Date(1999, 2, 28)); } { auto date = Date(2000, 2, 29); date.roll!"months"(12); assert(date == Date(2000, 2, 29)); } { auto date = Date(1999, 7, 31); date.roll!"months"(1); assert(date == Date(1999, 8, 31)); date.roll!"months"(1); assert(date == Date(1999, 10, 1)); } { auto date = Date(1998, 8, 31); date.roll!"months"(13); assert(date == Date(1998, 10, 1)); date.roll!"months"(-13); assert(date == Date(1998, 9, 1)); } { auto date = Date(1997, 12, 31); date.roll!"months"(13); assert(date == Date(1997, 1, 31)); date.roll!"months"(-13); assert(date == Date(1997, 12, 31)); } { auto date = Date(1997, 12, 31); date.roll!"months"(14); assert(date == Date(1997, 3, 3)); date.roll!"months"(-14); assert(date == Date(1997, 1, 3)); } { auto date = Date(1998, 12, 31); date.roll!"months"(14); assert(date == Date(1998, 3, 3)); date.roll!"months"(-14); assert(date == Date(1998, 1, 3)); } { auto date = Date(1999, 12, 31); date.roll!"months"(14); assert(date == Date(1999, 3, 3)); date.roll!"months"(-14); assert(date == Date(1999, 1, 3)); } //Test B.C. { auto date = Date(-1999, 7, 6); date.roll!"months"(3); assert(date == Date(-1999, 10, 6)); date.roll!"months"(-4); assert(date == Date(-1999, 6, 6)); } { auto date = Date(-1999, 7, 6); date.roll!"months"(6); assert(date == Date(-1999, 1, 6)); date.roll!"months"(-6); assert(date == Date(-1999, 7, 6)); } { auto date = Date(-1999, 7, 6); date.roll!"months"(-27); assert(date == Date(-1999, 4, 6)); date.roll!"months"(28); assert(date == Date(-1999, 8, 6)); } { auto date = Date(-1999, 5, 31); date.roll!"months"(1); assert(date == Date(-1999, 7, 1)); } { auto date = Date(-1999, 5, 31); date.roll!"months"(-1); assert(date == Date(-1999, 5, 1)); } { auto date = Date(-1999, 2, 28); date.roll!"months"(-12); assert(date == Date(-1999, 2, 28)); } { auto date = Date(-2000, 2, 29); date.roll!"months"(-12); assert(date == Date(-2000, 2, 29)); } { auto date = Date(-1999, 7, 31); date.roll!"months"(1); assert(date == Date(-1999, 8, 31)); date.roll!"months"(1); assert(date == Date(-1999, 10, 1)); } { auto date = Date(-1998, 8, 31); date.roll!"months"(13); assert(date == Date(-1998, 10, 1)); date.roll!"months"(-13); assert(date == Date(-1998, 9, 1)); } { auto date = Date(-1997, 12, 31); date.roll!"months"(13); assert(date == Date(-1997, 1, 31)); date.roll!"months"(-13); assert(date == Date(-1997, 12, 31)); } { auto date = Date(-1997, 12, 31); date.roll!"months"(14); assert(date == Date(-1997, 3, 3)); date.roll!"months"(-14); assert(date == Date(-1997, 1, 3)); } { auto date = Date(-2002, 12, 31); date.roll!"months"(14); assert(date == Date(-2002, 3, 3)); date.roll!"months"(-14); assert(date == Date(-2002, 1, 3)); } { auto date = Date(-2001, 12, 31); date.roll!"months"(14); assert(date == Date(-2001, 3, 3)); date.roll!"months"(-14); assert(date == Date(-2001, 1, 3)); } //Test Both { auto date = Date(1, 1, 1); date.roll!"months"(-1); assert(date == Date(1, 12, 1)); date.roll!"months"(1); assert(date == Date(1, 1, 1)); } { auto date = Date(4, 1, 1); date.roll!"months"(-48); assert(date == Date(4, 1, 1)); date.roll!"months"(48); assert(date == Date(4, 1, 1)); } { auto date = Date(4, 3, 31); date.roll!"months"(-49); assert(date == Date(4, 3, 2)); date.roll!"months"(49); assert(date == Date(4, 4, 2)); } { auto date = Date(4, 3, 31); date.roll!"months"(-85); assert(date == Date(4, 3, 2)); date.roll!"months"(85); assert(date == Date(4, 4, 2)); } { auto date = Date(-1, 1, 1); date.roll!"months"(-1); assert(date == Date(-1, 12, 1)); date.roll!"months"(1); assert(date == Date(-1, 1, 1)); } { auto date = Date(-4, 1, 1); date.roll!"months"(-48); assert(date == Date(-4, 1, 1)); date.roll!"months"(48); assert(date == Date(-4, 1, 1)); } { auto date = Date(-4, 3, 31); date.roll!"months"(-49); assert(date == Date(-4, 3, 2)); date.roll!"months"(49); assert(date == Date(-4, 4, 2)); } { auto date = Date(-4, 3, 31); date.roll!"months"(-85); assert(date == Date(-4, 3, 2)); date.roll!"months"(85); assert(date == Date(-4, 4, 2)); } { auto date = Date(-3, 3, 31); date.roll!"months"(85).roll!"months"(-83); assert(date == Date(-3, 6, 1)); } const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.roll!"months"(3))); static assert(!__traits(compiles, idate.roll!"months"(3))); } //Test roll!"months"() with AllowDayOverlow.no unittest { //Test A.D. { auto date = Date(1999, 7, 6); date.roll!"months"(3, AllowDayOverflow.no); assert(date == Date(1999, 10, 6)); date.roll!"months"(-4, AllowDayOverflow.no); assert(date == Date(1999, 6, 6)); } { auto date = Date(1999, 7, 6); date.roll!"months"(6, AllowDayOverflow.no); assert(date == Date(1999, 1, 6)); date.roll!"months"(-6, AllowDayOverflow.no); assert(date == Date(1999, 7, 6)); } { auto date = Date(1999, 7, 6); date.roll!"months"(27, AllowDayOverflow.no); assert(date == Date(1999, 10, 6)); date.roll!"months"(-28, AllowDayOverflow.no); assert(date == Date(1999, 6, 6)); } { auto date = Date(1999, 5, 31); date.roll!"months"(1, AllowDayOverflow.no); assert(date == Date(1999, 6, 30)); } { auto date = Date(1999, 5, 31); date.roll!"months"(-1, AllowDayOverflow.no); assert(date == Date(1999, 4, 30)); } { auto date = Date(1999, 2, 28); date.roll!"months"(12, AllowDayOverflow.no); assert(date == Date(1999, 2, 28)); } { auto date = Date(2000, 2, 29); date.roll!"months"(12, AllowDayOverflow.no); assert(date == Date(2000, 2, 29)); } { auto date = Date(1999, 7, 31); date.roll!"months"(1, AllowDayOverflow.no); assert(date == Date(1999, 8, 31)); date.roll!"months"(1, AllowDayOverflow.no); assert(date == Date(1999, 9, 30)); } { auto date = Date(1998, 8, 31); date.roll!"months"(13, AllowDayOverflow.no); assert(date == Date(1998, 9, 30)); date.roll!"months"(-13, AllowDayOverflow.no); assert(date == Date(1998, 8, 30)); } { auto date = Date(1997, 12, 31); date.roll!"months"(13, AllowDayOverflow.no); assert(date == Date(1997, 1, 31)); date.roll!"months"(-13, AllowDayOverflow.no); assert(date == Date(1997, 12, 31)); } { auto date = Date(1997, 12, 31); date.roll!"months"(14, AllowDayOverflow.no); assert(date == Date(1997, 2, 28)); date.roll!"months"(-14, AllowDayOverflow.no); assert(date == Date(1997, 12, 28)); } { auto date = Date(1998, 12, 31); date.roll!"months"(14, AllowDayOverflow.no); assert(date == Date(1998, 2, 28)); date.roll!"months"(-14, AllowDayOverflow.no); assert(date == Date(1998, 12, 28)); } { auto date = Date(1999, 12, 31); date.roll!"months"(14, AllowDayOverflow.no); assert(date == Date(1999, 2, 28)); date.roll!"months"(-14, AllowDayOverflow.no); assert(date == Date(1999, 12, 28)); } //Test B.C. { auto date = Date(-1999, 7, 6); date.roll!"months"(3, AllowDayOverflow.no); assert(date == Date(-1999, 10, 6)); date.roll!"months"(-4, AllowDayOverflow.no); assert(date == Date(-1999, 6, 6)); } { auto date = Date(-1999, 7, 6); date.roll!"months"(6, AllowDayOverflow.no); assert(date == Date(-1999, 1, 6)); date.roll!"months"(-6, AllowDayOverflow.no); assert(date == Date(-1999, 7, 6)); } { auto date = Date(-1999, 7, 6); date.roll!"months"(-27, AllowDayOverflow.no); assert(date == Date(-1999, 4, 6)); date.roll!"months"(28, AllowDayOverflow.no); assert(date == Date(-1999, 8, 6)); } { auto date = Date(-1999, 5, 31); date.roll!"months"(1, AllowDayOverflow.no); assert(date == Date(-1999, 6, 30)); } { auto date = Date(-1999, 5, 31); date.roll!"months"(-1, AllowDayOverflow.no); assert(date == Date(-1999, 4, 30)); } { auto date = Date(-1999, 2, 28); date.roll!"months"(-12, AllowDayOverflow.no); assert(date == Date(-1999, 2, 28)); } { auto date = Date(-2000, 2, 29); date.roll!"months"(-12, AllowDayOverflow.no); assert(date == Date(-2000, 2, 29)); } { auto date = Date(-1999, 7, 31); date.roll!"months"(1, AllowDayOverflow.no); assert(date == Date(-1999, 8, 31)); date.roll!"months"(1, AllowDayOverflow.no); assert(date == Date(-1999, 9, 30)); } { auto date = Date(-1998, 8, 31); date.roll!"months"(13, AllowDayOverflow.no); assert(date == Date(-1998, 9, 30)); date.roll!"months"(-13, AllowDayOverflow.no); assert(date == Date(-1998, 8, 30)); } { auto date = Date(-1997, 12, 31); date.roll!"months"(13, AllowDayOverflow.no); assert(date == Date(-1997, 1, 31)); date.roll!"months"(-13, AllowDayOverflow.no); assert(date == Date(-1997, 12, 31)); } { auto date = Date(-1997, 12, 31); date.roll!"months"(14, AllowDayOverflow.no); assert(date == Date(-1997, 2, 28)); date.roll!"months"(-14, AllowDayOverflow.no); assert(date == Date(-1997, 12, 28)); } { auto date = Date(-2002, 12, 31); date.roll!"months"(14, AllowDayOverflow.no); assert(date == Date(-2002, 2, 28)); date.roll!"months"(-14, AllowDayOverflow.no); assert(date == Date(-2002, 12, 28)); } { auto date = Date(-2001, 12, 31); date.roll!"months"(14, AllowDayOverflow.no); assert(date == Date(-2001, 2, 28)); date.roll!"months"(-14, AllowDayOverflow.no); assert(date == Date(-2001, 12, 28)); } //Test Both { auto date = Date(1, 1, 1); date.roll!"months"(-1, AllowDayOverflow.no); assert(date == Date(1, 12, 1)); date.roll!"months"(1, AllowDayOverflow.no); assert(date == Date(1, 1, 1)); } { auto date = Date(4, 1, 1); date.roll!"months"(-48, AllowDayOverflow.no); assert(date == Date(4, 1, 1)); date.roll!"months"(48, AllowDayOverflow.no); assert(date == Date(4, 1, 1)); } { auto date = Date(4, 3, 31); date.roll!"months"(-49, AllowDayOverflow.no); assert(date == Date(4, 2, 29)); date.roll!"months"(49, AllowDayOverflow.no); assert(date == Date(4, 3, 29)); } { auto date = Date(4, 3, 31); date.roll!"months"(-85, AllowDayOverflow.no); assert(date == Date(4, 2, 29)); date.roll!"months"(85, AllowDayOverflow.no); assert(date == Date(4, 3, 29)); } { auto date = Date(-1, 1, 1); date.roll!"months"(-1, AllowDayOverflow.no); assert(date == Date(-1, 12, 1)); date.roll!"months"(1, AllowDayOverflow.no); assert(date == Date(-1, 1, 1)); } { auto date = Date(-4, 1, 1); date.roll!"months"(-48, AllowDayOverflow.no); assert(date == Date(-4, 1, 1)); date.roll!"months"(48, AllowDayOverflow.no); assert(date == Date(-4, 1, 1)); } { auto date = Date(-4, 3, 31); date.roll!"months"(-49, AllowDayOverflow.no); assert(date == Date(-4, 2, 29)); date.roll!"months"(49, AllowDayOverflow.no); assert(date == Date(-4, 3, 29)); } { auto date = Date(-4, 3, 31); date.roll!"months"(-85, AllowDayOverflow.no); assert(date == Date(-4, 2, 29)); date.roll!"months"(85, AllowDayOverflow.no); assert(date == Date(-4, 3, 29)); } { auto date = Date(-3, 3, 31); date.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no); assert(date == Date(-3, 5, 30)); } } /++ Adds the given number of units to this $(LREF Date). A negative number will subtract. The difference between rolling and adding is that rolling does not affect larger units. For instance, rolling a $(LREF Date) one year's worth of days gets the exact same $(LREF Date). The only accepted units are $(D "days"). Params: units = The units to add. Must be $(D "days"). days = The number of days to add to this $(LREF Date). +/ ref Date roll(string units)(long days) @safe pure nothrow if(units == "days") { immutable limit = maxDay(_year, _month); days %= limit; auto newDay = _day + days; if(days < 0) { if(newDay < 1) newDay += limit; } else if(newDay > limit) newDay -= limit; _day = cast(ubyte)newDay; return this; } /// unittest { auto d = Date(2010, 1, 1); d.roll!"days"(1); assert(d == Date(2010, 1, 2)); d.roll!"days"(365); assert(d == Date(2010, 1, 26)); d.roll!"days"(-32); assert(d == Date(2010, 1, 25)); } unittest { //Test A.D. { auto date = Date(1999, 2, 28); date.roll!"days"(1); assert(date == Date(1999, 2, 1)); date.roll!"days"(-1); assert(date == Date(1999, 2, 28)); } { auto date = Date(2000, 2, 28); date.roll!"days"(1); assert(date == Date(2000, 2, 29)); date.roll!"days"(1); assert(date == Date(2000, 2, 1)); date.roll!"days"(-1); assert(date == Date(2000, 2, 29)); } { auto date = Date(1999, 6, 30); date.roll!"days"(1); assert(date == Date(1999, 6, 1)); date.roll!"days"(-1); assert(date == Date(1999, 6, 30)); } { auto date = Date(1999, 7, 31); date.roll!"days"(1); assert(date == Date(1999, 7, 1)); date.roll!"days"(-1); assert(date == Date(1999, 7, 31)); } { auto date = Date(1999, 1, 1); date.roll!"days"(-1); assert(date == Date(1999, 1, 31)); date.roll!"days"(1); assert(date == Date(1999, 1, 1)); } { auto date = Date(1999, 7, 6); date.roll!"days"(9); assert(date == Date(1999, 7, 15)); date.roll!"days"(-11); assert(date == Date(1999, 7, 4)); date.roll!"days"(30); assert(date == Date(1999, 7, 3)); date.roll!"days"(-3); assert(date == Date(1999, 7, 31)); } { auto date = Date(1999, 7, 6); date.roll!"days"(365); assert(date == Date(1999, 7, 30)); date.roll!"days"(-365); assert(date == Date(1999, 7, 6)); date.roll!"days"(366); assert(date == Date(1999, 7, 31)); date.roll!"days"(730); assert(date == Date(1999, 7, 17)); date.roll!"days"(-1096); assert(date == Date(1999, 7, 6)); } { auto date = Date(1999, 2, 6); date.roll!"days"(365); assert(date == Date(1999, 2, 7)); date.roll!"days"(-365); assert(date == Date(1999, 2, 6)); date.roll!"days"(366); assert(date == Date(1999, 2, 8)); date.roll!"days"(730); assert(date == Date(1999, 2, 10)); date.roll!"days"(-1096); assert(date == Date(1999, 2, 6)); } //Test B.C. { auto date = Date(-1999, 2, 28); date.roll!"days"(1); assert(date == Date(-1999, 2, 1)); date.roll!"days"(-1); assert(date == Date(-1999, 2, 28)); } { auto date = Date(-2000, 2, 28); date.roll!"days"(1); assert(date == Date(-2000, 2, 29)); date.roll!"days"(1); assert(date == Date(-2000, 2, 1)); date.roll!"days"(-1); assert(date == Date(-2000, 2, 29)); } { auto date = Date(-1999, 6, 30); date.roll!"days"(1); assert(date == Date(-1999, 6, 1)); date.roll!"days"(-1); assert(date == Date(-1999, 6, 30)); } { auto date = Date(-1999, 7, 31); date.roll!"days"(1); assert(date == Date(-1999, 7, 1)); date.roll!"days"(-1); assert(date == Date(-1999, 7, 31)); } { auto date = Date(-1999, 1, 1); date.roll!"days"(-1); assert(date == Date(-1999, 1, 31)); date.roll!"days"(1); assert(date == Date(-1999, 1, 1)); } { auto date = Date(-1999, 7, 6); date.roll!"days"(9); assert(date == Date(-1999, 7, 15)); date.roll!"days"(-11); assert(date == Date(-1999, 7, 4)); date.roll!"days"(30); assert(date == Date(-1999, 7, 3)); date.roll!"days"(-3); assert(date == Date(-1999, 7, 31)); } { auto date = Date(-1999, 7, 6); date.roll!"days"(365); assert(date == Date(-1999, 7, 30)); date.roll!"days"(-365); assert(date == Date(-1999, 7, 6)); date.roll!"days"(366); assert(date == Date(-1999, 7, 31)); date.roll!"days"(730); assert(date == Date(-1999, 7, 17)); date.roll!"days"(-1096); assert(date == Date(-1999, 7, 6)); } //Test Both { auto date = Date(1, 7, 6); date.roll!"days"(-365); assert(date == Date(1, 7, 13)); date.roll!"days"(365); assert(date == Date(1, 7, 6)); date.roll!"days"(-731); assert(date == Date(1, 7, 19)); date.roll!"days"(730); assert(date == Date(1, 7, 5)); } { auto date = Date(0, 7, 6); date.roll!"days"(-365); assert(date == Date(0, 7, 13)); date.roll!"days"(365); assert(date == Date(0, 7, 6)); date.roll!"days"(-731); assert(date == Date(0, 7, 19)); date.roll!"days"(730); assert(date == Date(0, 7, 5)); } { auto date = Date(0, 7, 6); date.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730); assert(date == Date(0, 7, 8)); } const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.roll!"days"(12))); static assert(!__traits(compiles, idate.roll!"days"(12))); } /++ Gives the result of adding or subtracting a $(CXREF tiem, Duration) from this $(LREF Date). The legal types of arithmetic for $(LREF Date) using this operator are $(BOOKTABLE, $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) ) Params: duration = The $(CXREF time, Duration) to add to or subtract from this $(LREF Date). +/ Date opBinary(string op)(Duration duration) @safe const pure nothrow if(op == "+" || op == "-") { Date retval = this; immutable days = duration.total!"days"; mixin("return retval._addDays(" ~ op ~ "days);"); } /// unittest { assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1)); assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1)); assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31)); assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26)); } unittest { auto date = Date(1999, 7, 6); assert(date + dur!"weeks"(7) == Date(1999, 8, 24)); assert(date + dur!"weeks"(-7) == Date(1999, 5, 18)); assert(date + dur!"days"(7) == Date(1999, 7, 13)); assert(date + dur!"days"(-7) == Date(1999, 6, 29)); assert(date + dur!"hours"(24) == Date(1999, 7, 7)); assert(date + dur!"hours"(-24) == Date(1999, 7, 5)); assert(date + dur!"minutes"(1440) == Date(1999, 7, 7)); assert(date + dur!"minutes"(-1440) == Date(1999, 7, 5)); assert(date + dur!"seconds"(86_400) == Date(1999, 7, 7)); assert(date + dur!"seconds"(-86_400) == Date(1999, 7, 5)); assert(date + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); assert(date + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); assert(date + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); assert(date + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); assert(date + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); assert(date + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); assert(date - dur!"weeks"(-7) == Date(1999, 8, 24)); assert(date - dur!"weeks"(7) == Date(1999, 5, 18)); assert(date - dur!"days"(-7) == Date(1999, 7, 13)); assert(date - dur!"days"(7) == Date(1999, 6, 29)); assert(date - dur!"hours"(-24) == Date(1999, 7, 7)); assert(date - dur!"hours"(24) == Date(1999, 7, 5)); assert(date - dur!"minutes"(-1440) == Date(1999, 7, 7)); assert(date - dur!"minutes"(1440) == Date(1999, 7, 5)); assert(date - dur!"seconds"(-86_400) == Date(1999, 7, 7)); assert(date - dur!"seconds"(86_400) == Date(1999, 7, 5)); assert(date - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); assert(date - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); assert(date - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); assert(date - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); assert(date - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); assert(date - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); auto duration = dur!"days"(12); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(date + duration == Date(1999, 7, 18)); assert(cdate + duration == Date(1999, 7, 18)); assert(idate + duration == Date(1999, 7, 18)); assert(date - duration == Date(1999, 6, 24)); assert(cdate - duration == Date(1999, 6, 24)); assert(idate - duration == Date(1999, 6, 24)); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime) and $(CXREF time, Duration). Use $(D Duration) instead. This overload will be removed in January 2017.) Defines + and - with $(CXREF time, TickDuration). +/ deprecated("Use Duration instead of TickDuration.") Date opBinary(string op)(TickDuration td) @safe const pure nothrow if(op == "+" || op == "-") { Date retval = this; immutable days = convert!("hnsecs", "days")(td.hnsecs); mixin("return retval._addDays(" ~ op ~ "days);"); } deprecated unittest { //This probably only runs in cases where gettimeofday() is used, but it's //hard to do this test correctly with variable ticksPerSec. if(TickDuration.ticksPerSec == 1_000_000) { auto date = Date(1999, 7, 6); assert(date + TickDuration.from!"usecs"(86_400_000_000) == Date(1999, 7, 7)); assert(date + TickDuration.from!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); assert(date - TickDuration.from!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); assert(date - TickDuration.from!"usecs"(86_400_000_000) == Date(1999, 7, 5)); } } /++ Gives the result of adding or subtracting a $(CXREF time, Duration) from this $(LREF Date), as well as assigning the result to this $(LREF Date). The legal types of arithmetic for $(LREF Date) using this operator are $(BOOKTABLE, $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) ) Params: duration = The $(CXREF time, Duration) to add to or subtract from this $(LREF Date). +/ ref Date opOpAssign(string op)(Duration duration) @safe pure nothrow if(op == "+" || op == "-") { immutable days = duration.total!"days"; mixin("return _addDays(" ~ op ~ "days);"); } unittest { assert(Date(1999, 7, 6) + dur!"weeks"(7) == Date(1999, 8, 24)); assert(Date(1999, 7, 6) + dur!"weeks"(-7) == Date(1999, 5, 18)); assert(Date(1999, 7, 6) + dur!"days"(7) == Date(1999, 7, 13)); assert(Date(1999, 7, 6) + dur!"days"(-7) == Date(1999, 6, 29)); assert(Date(1999, 7, 6) + dur!"hours"(24) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) + dur!"hours"(-24) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) + dur!"minutes"(1440) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) + dur!"minutes"(-1440) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) + dur!"seconds"(86_400) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) + dur!"seconds"(-86_400) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) - dur!"weeks"(-7) == Date(1999, 8, 24)); assert(Date(1999, 7, 6) - dur!"weeks"(7) == Date(1999, 5, 18)); assert(Date(1999, 7, 6) - dur!"days"(-7) == Date(1999, 7, 13)); assert(Date(1999, 7, 6) - dur!"days"(7) == Date(1999, 6, 29)); assert(Date(1999, 7, 6) - dur!"hours"(-24) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) - dur!"hours"(24) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) - dur!"minutes"(-1440) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) - dur!"minutes"(1440) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) - dur!"seconds"(-86_400) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) - dur!"seconds"(86_400) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); assert(Date(1999, 7, 6) - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); assert(Date(1999, 7, 6) - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); { auto date = Date(0, 1, 31); (date += dur!"days"(507)) += dur!"days"(-2); assert(date == Date(1, 6, 19)); } auto duration = dur!"days"(12); auto date = Date(1999, 7, 6); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); date += duration; static assert(!__traits(compiles, cdate += duration)); static assert(!__traits(compiles, idate += duration)); date -= duration; static assert(!__traits(compiles, cdate -= duration)); static assert(!__traits(compiles, idate -= duration)); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime) and $(CXREF time, Duration). Use $(D Duration) instead. This overload will be removed in January 2017.) Defines += and -= with $(CXREF time, TickDuration). +/ deprecated("Use Duration instead of TickDuration.") ref Date opOpAssign(string op)(TickDuration td) @safe pure nothrow if(op == "+" || op == "-") { immutable days = convert!("seconds", "days")(td.seconds); mixin("return _addDays(" ~ op ~ "days);"); } deprecated unittest { //This probably only runs in cases where gettimeofday() is used, but it's //hard to do this test correctly with variable ticksPerSec. if(TickDuration.ticksPerSec == 1_000_000) { { auto date = Date(1999, 7, 6); date += TickDuration.from!"usecs"(86_400_000_000); assert(date == Date(1999, 7, 7)); } { auto date = Date(1999, 7, 6); date += TickDuration.from!"usecs"(-86_400_000_000); assert(date == Date(1999, 7, 5)); } { auto date = Date(1999, 7, 6); date -= TickDuration.from!"usecs"(-86_400_000_000); assert(date == Date(1999, 7, 7)); } { auto date = Date(1999, 7, 6); date -= TickDuration.from!"usecs"(86_400_000_000); assert(date == Date(1999, 7, 5)); } } } /++ Gives the difference between two $(LREF Date)s. The legal types of arithmetic for $(LREF Date) using this operator are $(BOOKTABLE, $(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration)) ) +/ Duration opBinary(string op)(in Date rhs) @safe const pure nothrow if(op == "-") { return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal); } unittest { auto date = Date(1999, 7, 6); assert(Date(1999, 7, 6) - Date(1998, 7, 6) == dur!"days"(365)); assert(Date(1998, 7, 6) - Date(1999, 7, 6) == dur!"days"(-365)); assert(Date(1999, 6, 6) - Date(1999, 5, 6) == dur!"days"(31)); assert(Date(1999, 5, 6) - Date(1999, 6, 6) == dur!"days"(-31)); assert(Date(1999, 1, 1) - Date(1998, 12, 31) == dur!"days"(1)); assert(Date(1998, 12, 31) - Date(1999, 1, 1) == dur!"days"(-1)); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(date - date == Duration.zero); assert(cdate - date == Duration.zero); assert(idate - date == Duration.zero); assert(date - cdate == Duration.zero); assert(cdate - cdate == Duration.zero); assert(idate - cdate == Duration.zero); assert(date - idate == Duration.zero); assert(cdate - idate == Duration.zero); assert(idate - idate == Duration.zero); } /++ Returns the difference between the two $(LREF Date)s in months. To get the difference in years, subtract the year property of two $(LREF SysTime)s. To get the difference in days or weeks, subtract the $(LREF SysTime)s themselves and use the $(CXREF time, Duration) that results. Because converting between months and smaller units requires a specific date (which $(CXREF time, Duration)s don't have), getting the difference in months requires some math using both the year and month properties, so this is a convenience function for getting the difference in months. Note that the number of days in the months or how far into the month either $(LREF Date) is is irrelevant. It is the difference in the month property combined with the difference in years * 12. So, for instance, December 31st and January 1st are one month apart just as December 1st and January 31st are one month apart. Params: rhs = The $(LREF Date) to subtract from this one. +/ int diffMonths(in Date rhs) @safe const pure nothrow { immutable yearDiff = _year - rhs._year; immutable monthDiff = _month - rhs._month; return yearDiff * 12 + monthDiff; } /// unittest { assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1); assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1); assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2); assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2); } unittest { auto date = Date(1999, 7, 6); //Test A.D. assert(date.diffMonths(Date(1998, 6, 5)) == 13); assert(date.diffMonths(Date(1998, 7, 5)) == 12); assert(date.diffMonths(Date(1998, 8, 5)) == 11); assert(date.diffMonths(Date(1998, 9, 5)) == 10); assert(date.diffMonths(Date(1998, 10, 5)) == 9); assert(date.diffMonths(Date(1998, 11, 5)) == 8); assert(date.diffMonths(Date(1998, 12, 5)) == 7); assert(date.diffMonths(Date(1999, 1, 5)) == 6); assert(date.diffMonths(Date(1999, 2, 6)) == 5); assert(date.diffMonths(Date(1999, 3, 6)) == 4); assert(date.diffMonths(Date(1999, 4, 6)) == 3); assert(date.diffMonths(Date(1999, 5, 6)) == 2); assert(date.diffMonths(Date(1999, 6, 6)) == 1); assert(date.diffMonths(date) == 0); assert(date.diffMonths(Date(1999, 8, 6)) == -1); assert(date.diffMonths(Date(1999, 9, 6)) == -2); assert(date.diffMonths(Date(1999, 10, 6)) == -3); assert(date.diffMonths(Date(1999, 11, 6)) == -4); assert(date.diffMonths(Date(1999, 12, 6)) == -5); assert(date.diffMonths(Date(2000, 1, 6)) == -6); assert(date.diffMonths(Date(2000, 2, 6)) == -7); assert(date.diffMonths(Date(2000, 3, 6)) == -8); assert(date.diffMonths(Date(2000, 4, 6)) == -9); assert(date.diffMonths(Date(2000, 5, 6)) == -10); assert(date.diffMonths(Date(2000, 6, 6)) == -11); assert(date.diffMonths(Date(2000, 7, 6)) == -12); assert(date.diffMonths(Date(2000, 8, 6)) == -13); assert(Date(1998, 6, 5).diffMonths(date) == -13); assert(Date(1998, 7, 5).diffMonths(date) == -12); assert(Date(1998, 8, 5).diffMonths(date) == -11); assert(Date(1998, 9, 5).diffMonths(date) == -10); assert(Date(1998, 10, 5).diffMonths(date) == -9); assert(Date(1998, 11, 5).diffMonths(date) == -8); assert(Date(1998, 12, 5).diffMonths(date) == -7); assert(Date(1999, 1, 5).diffMonths(date) == -6); assert(Date(1999, 2, 6).diffMonths(date) == -5); assert(Date(1999, 3, 6).diffMonths(date) == -4); assert(Date(1999, 4, 6).diffMonths(date) == -3); assert(Date(1999, 5, 6).diffMonths(date) == -2); assert(Date(1999, 6, 6).diffMonths(date) == -1); assert(Date(1999, 8, 6).diffMonths(date) == 1); assert(Date(1999, 9, 6).diffMonths(date) == 2); assert(Date(1999, 10, 6).diffMonths(date) == 3); assert(Date(1999, 11, 6).diffMonths(date) == 4); assert(Date(1999, 12, 6).diffMonths(date) == 5); assert(Date(2000, 1, 6).diffMonths(date) == 6); assert(Date(2000, 2, 6).diffMonths(date) == 7); assert(Date(2000, 3, 6).diffMonths(date) == 8); assert(Date(2000, 4, 6).diffMonths(date) == 9); assert(Date(2000, 5, 6).diffMonths(date) == 10); assert(Date(2000, 6, 6).diffMonths(date) == 11); assert(Date(2000, 7, 6).diffMonths(date) == 12); assert(Date(2000, 8, 6).diffMonths(date) == 13); assert(date.diffMonths(Date(1999, 6, 30)) == 1); assert(date.diffMonths(Date(1999, 7, 1)) == 0); assert(date.diffMonths(Date(1999, 7, 6)) == 0); assert(date.diffMonths(Date(1999, 7, 11)) == 0); assert(date.diffMonths(Date(1999, 7, 16)) == 0); assert(date.diffMonths(Date(1999, 7, 21)) == 0); assert(date.diffMonths(Date(1999, 7, 26)) == 0); assert(date.diffMonths(Date(1999, 7, 31)) == 0); assert(date.diffMonths(Date(1999, 8, 1)) == -1); assert(date.diffMonths(Date(1990, 6, 30)) == 109); assert(date.diffMonths(Date(1990, 7, 1)) == 108); assert(date.diffMonths(Date(1990, 7, 6)) == 108); assert(date.diffMonths(Date(1990, 7, 11)) == 108); assert(date.diffMonths(Date(1990, 7, 16)) == 108); assert(date.diffMonths(Date(1990, 7, 21)) == 108); assert(date.diffMonths(Date(1990, 7, 26)) == 108); assert(date.diffMonths(Date(1990, 7, 31)) == 108); assert(date.diffMonths(Date(1990, 8, 1)) == 107); assert(Date(1999, 6, 30).diffMonths(date) == -1); assert(Date(1999, 7, 1).diffMonths(date) == 0); assert(Date(1999, 7, 6).diffMonths(date) == 0); assert(Date(1999, 7, 11).diffMonths(date) == 0); assert(Date(1999, 7, 16).diffMonths(date) == 0); assert(Date(1999, 7, 21).diffMonths(date) == 0); assert(Date(1999, 7, 26).diffMonths(date) == 0); assert(Date(1999, 7, 31).diffMonths(date) == 0); assert(Date(1999, 8, 1).diffMonths(date) == 1); assert(Date(1990, 6, 30).diffMonths(date) == -109); assert(Date(1990, 7, 1).diffMonths(date) == -108); assert(Date(1990, 7, 6).diffMonths(date) == -108); assert(Date(1990, 7, 11).diffMonths(date) == -108); assert(Date(1990, 7, 16).diffMonths(date) == -108); assert(Date(1990, 7, 21).diffMonths(date) == -108); assert(Date(1990, 7, 26).diffMonths(date) == -108); assert(Date(1990, 7, 31).diffMonths(date) == -108); assert(Date(1990, 8, 1).diffMonths(date) == -107); //Test B.C. auto dateBC = Date(-1999, 7, 6); assert(dateBC.diffMonths(Date(-2000, 6, 5)) == 13); assert(dateBC.diffMonths(Date(-2000, 7, 5)) == 12); assert(dateBC.diffMonths(Date(-2000, 8, 5)) == 11); assert(dateBC.diffMonths(Date(-2000, 9, 5)) == 10); assert(dateBC.diffMonths(Date(-2000, 10, 5)) == 9); assert(dateBC.diffMonths(Date(-2000, 11, 5)) == 8); assert(dateBC.diffMonths(Date(-2000, 12, 5)) == 7); assert(dateBC.diffMonths(Date(-1999, 1, 5)) == 6); assert(dateBC.diffMonths(Date(-1999, 2, 6)) == 5); assert(dateBC.diffMonths(Date(-1999, 3, 6)) == 4); assert(dateBC.diffMonths(Date(-1999, 4, 6)) == 3); assert(dateBC.diffMonths(Date(-1999, 5, 6)) == 2); assert(dateBC.diffMonths(Date(-1999, 6, 6)) == 1); assert(dateBC.diffMonths(dateBC) == 0); assert(dateBC.diffMonths(Date(-1999, 8, 6)) == -1); assert(dateBC.diffMonths(Date(-1999, 9, 6)) == -2); assert(dateBC.diffMonths(Date(-1999, 10, 6)) == -3); assert(dateBC.diffMonths(Date(-1999, 11, 6)) == -4); assert(dateBC.diffMonths(Date(-1999, 12, 6)) == -5); assert(dateBC.diffMonths(Date(-1998, 1, 6)) == -6); assert(dateBC.diffMonths(Date(-1998, 2, 6)) == -7); assert(dateBC.diffMonths(Date(-1998, 3, 6)) == -8); assert(dateBC.diffMonths(Date(-1998, 4, 6)) == -9); assert(dateBC.diffMonths(Date(-1998, 5, 6)) == -10); assert(dateBC.diffMonths(Date(-1998, 6, 6)) == -11); assert(dateBC.diffMonths(Date(-1998, 7, 6)) == -12); assert(dateBC.diffMonths(Date(-1998, 8, 6)) == -13); assert(Date(-2000, 6, 5).diffMonths(dateBC) == -13); assert(Date(-2000, 7, 5).diffMonths(dateBC) == -12); assert(Date(-2000, 8, 5).diffMonths(dateBC) == -11); assert(Date(-2000, 9, 5).diffMonths(dateBC) == -10); assert(Date(-2000, 10, 5).diffMonths(dateBC) == -9); assert(Date(-2000, 11, 5).diffMonths(dateBC) == -8); assert(Date(-2000, 12, 5).diffMonths(dateBC) == -7); assert(Date(-1999, 1, 5).diffMonths(dateBC) == -6); assert(Date(-1999, 2, 6).diffMonths(dateBC) == -5); assert(Date(-1999, 3, 6).diffMonths(dateBC) == -4); assert(Date(-1999, 4, 6).diffMonths(dateBC) == -3); assert(Date(-1999, 5, 6).diffMonths(dateBC) == -2); assert(Date(-1999, 6, 6).diffMonths(dateBC) == -1); assert(Date(-1999, 8, 6).diffMonths(dateBC) == 1); assert(Date(-1999, 9, 6).diffMonths(dateBC) == 2); assert(Date(-1999, 10, 6).diffMonths(dateBC) == 3); assert(Date(-1999, 11, 6).diffMonths(dateBC) == 4); assert(Date(-1999, 12, 6).diffMonths(dateBC) == 5); assert(Date(-1998, 1, 6).diffMonths(dateBC) == 6); assert(Date(-1998, 2, 6).diffMonths(dateBC) == 7); assert(Date(-1998, 3, 6).diffMonths(dateBC) == 8); assert(Date(-1998, 4, 6).diffMonths(dateBC) == 9); assert(Date(-1998, 5, 6).diffMonths(dateBC) == 10); assert(Date(-1998, 6, 6).diffMonths(dateBC) == 11); assert(Date(-1998, 7, 6).diffMonths(dateBC) == 12); assert(Date(-1998, 8, 6).diffMonths(dateBC) == 13); assert(dateBC.diffMonths(Date(-1999, 6, 30)) == 1); assert(dateBC.diffMonths(Date(-1999, 7, 1)) == 0); assert(dateBC.diffMonths(Date(-1999, 7, 6)) == 0); assert(dateBC.diffMonths(Date(-1999, 7, 11)) == 0); assert(dateBC.diffMonths(Date(-1999, 7, 16)) == 0); assert(dateBC.diffMonths(Date(-1999, 7, 21)) == 0); assert(dateBC.diffMonths(Date(-1999, 7, 26)) == 0); assert(dateBC.diffMonths(Date(-1999, 7, 31)) == 0); assert(dateBC.diffMonths(Date(-1999, 8, 1)) == -1); assert(dateBC.diffMonths(Date(-2008, 6, 30)) == 109); assert(dateBC.diffMonths(Date(-2008, 7, 1)) == 108); assert(dateBC.diffMonths(Date(-2008, 7, 6)) == 108); assert(dateBC.diffMonths(Date(-2008, 7, 11)) == 108); assert(dateBC.diffMonths(Date(-2008, 7, 16)) == 108); assert(dateBC.diffMonths(Date(-2008, 7, 21)) == 108); assert(dateBC.diffMonths(Date(-2008, 7, 26)) == 108); assert(dateBC.diffMonths(Date(-2008, 7, 31)) == 108); assert(dateBC.diffMonths(Date(-2008, 8, 1)) == 107); assert(Date(-1999, 6, 30).diffMonths(dateBC) == -1); assert(Date(-1999, 7, 1).diffMonths(dateBC) == 0); assert(Date(-1999, 7, 6).diffMonths(dateBC) == 0); assert(Date(-1999, 7, 11).diffMonths(dateBC) == 0); assert(Date(-1999, 7, 16).diffMonths(dateBC) == 0); assert(Date(-1999, 7, 21).diffMonths(dateBC) == 0); assert(Date(-1999, 7, 26).diffMonths(dateBC) == 0); assert(Date(-1999, 7, 31).diffMonths(dateBC) == 0); assert(Date(-1999, 8, 1).diffMonths(dateBC) == 1); assert(Date(-2008, 6, 30).diffMonths(dateBC) == -109); assert(Date(-2008, 7, 1).diffMonths(dateBC) == -108); assert(Date(-2008, 7, 6).diffMonths(dateBC) == -108); assert(Date(-2008, 7, 11).diffMonths(dateBC) == -108); assert(Date(-2008, 7, 16).diffMonths(dateBC) == -108); assert(Date(-2008, 7, 21).diffMonths(dateBC) == -108); assert(Date(-2008, 7, 26).diffMonths(dateBC) == -108); assert(Date(-2008, 7, 31).diffMonths(dateBC) == -108); assert(Date(-2008, 8, 1).diffMonths(dateBC) == -107); //Test Both assert(Date(3, 3, 3).diffMonths(Date(-5, 5, 5)) == 94); assert(Date(-5, 5, 5).diffMonths(Date(3, 3, 3)) == -94); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(date.diffMonths(date) == 0); assert(cdate.diffMonths(date) == 0); assert(idate.diffMonths(date) == 0); assert(date.diffMonths(cdate) == 0); assert(cdate.diffMonths(cdate) == 0); assert(idate.diffMonths(cdate) == 0); assert(date.diffMonths(idate) == 0); assert(cdate.diffMonths(idate) == 0); assert(idate.diffMonths(idate) == 0); } /++ Whether this $(LREF Date) is in a leap year. +/ @property bool isLeapYear() @safe const pure nothrow { return yearIsLeapYear(_year); } unittest { auto date = Date(1999, 7, 6); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, date.isLeapYear = true)); static assert(!__traits(compiles, cdate.isLeapYear = true)); static assert(!__traits(compiles, idate.isLeapYear = true)); } /++ Day of the week this $(LREF Date) is on. +/ @property DayOfWeek dayOfWeek() @safe const pure nothrow { return getDayOfWeek(dayOfGregorianCal); } unittest { const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.dayOfWeek == DayOfWeek.tue); static assert(!__traits(compiles, cdate.dayOfWeek = DayOfWeek.sun)); assert(idate.dayOfWeek == DayOfWeek.tue); static assert(!__traits(compiles, idate.dayOfWeek = DayOfWeek.sun)); } /++ Day of the year this $(LREF Date) is on. +/ @property ushort dayOfYear() @safe const pure nothrow { if (_month >= Month.jan && _month <= Month.dec) { immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; auto monthIndex = _month - Month.jan; return cast(ushort)(lastDay[monthIndex] + _day); } assert(0, "Invalid month."); } /// unittest { assert(Date(1999, 1, 1).dayOfYear == 1); assert(Date(1999, 12, 31).dayOfYear == 365); assert(Date(2000, 12, 31).dayOfYear == 366); } unittest { import std.range; foreach(year; filter!((a){return !yearIsLeapYear(a);}) (chain(testYearsBC, testYearsAD))) { foreach(doy; testDaysOfYear) { assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); } } foreach(year; filter!((a){return yearIsLeapYear(a);}) (chain(testYearsBC, testYearsAD))) { foreach(doy; testDaysOfLeapYear) { assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); } } const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.dayOfYear == 187); assert(idate.dayOfYear == 187); } /++ Day of the year. Params: day = The day of the year to set which day of the year this $(LREF Date) is on. Throws: $(LREF DateTimeException) if the given day is an invalid day of the year. +/ @property void dayOfYear(int day) @safe pure { immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; if(day <= 0 || day > (isLeapYear ? daysInLeapYear : daysInYear) ) throw new DateTimeException("Invalid day of the year."); foreach (i; 1..lastDay.length) { if (day <= lastDay[i]) { _month = cast(Month)(cast(int)Month.jan + i - 1); _day = cast(ubyte)(day - lastDay[i - 1]); return; } } assert(0, "Invalid day of the year."); } unittest { static void test(Date date, int day, MonthDay expected, size_t line = __LINE__) { date.dayOfYear = day; assert(date.month == expected.month); assert(date.day == expected.day); } foreach(doy; testDaysOfYear) { test(Date(1999, 1, 1), doy.day, doy.md); test(Date(-1, 1, 1), doy.day, doy.md); } foreach(doy; testDaysOfLeapYear) { test(Date(2000, 1, 1), doy.day, doy.md); test(Date(-4, 1, 1), doy.day, doy.md); } const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.dayOfYear = 187)); static assert(!__traits(compiles, idate.dayOfYear = 187)); } /++ The Xth day of the Gregorian Calendar that this $(LREF Date) is on. +/ @property int dayOfGregorianCal() @safe const pure nothrow { if(isAD) { if(_year == 1) return dayOfYear; int years = _year - 1; auto days = (years / 400) * daysIn400Years; years %= 400; days += (years / 100) * daysIn100Years; years %= 100; days += (years / 4) * daysIn4Years; years %= 4; days += years * daysInYear; days += dayOfYear; return days; } else if(_year == 0) return dayOfYear - daysInLeapYear; else { int years = _year; auto days = (years / 400) * daysIn400Years; years %= 400; days += (years / 100) * daysIn100Years; years %= 100; days += (years / 4) * daysIn4Years; years %= 4; if(years < 0) { days -= daysInLeapYear; ++years; days += years * daysInYear; days -= daysInYear - dayOfYear; } else days -= daysInLeapYear - dayOfYear; return days; } } /// unittest { assert(Date(1, 1, 1).dayOfGregorianCal == 1); assert(Date(1, 12, 31).dayOfGregorianCal == 365); assert(Date(2, 1, 1).dayOfGregorianCal == 366); assert(Date(0, 12, 31).dayOfGregorianCal == 0); assert(Date(0, 1, 1).dayOfGregorianCal == -365); assert(Date(-1, 12, 31).dayOfGregorianCal == -366); assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120); assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137); } unittest { import std.range; foreach(gd; chain(testGregDaysBC, testGregDaysAD)) assert(gd.date.dayOfGregorianCal == gd.day); auto date = Date(1999, 7, 6); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(date.dayOfGregorianCal == 729_941); assert(cdate.dayOfGregorianCal == 729_941); assert(idate.dayOfGregorianCal == 729_941); } /++ The Xth day of the Gregorian Calendar that this $(LREF Date) is on. Params: day = The day of the Gregorian Calendar to set this $(LREF Date) to. +/ @property void dayOfGregorianCal(int day) @safe pure nothrow { this = Date(day); } /// unittest { auto date = Date.init; date.dayOfGregorianCal = 1; assert(date == Date(1, 1, 1)); date.dayOfGregorianCal = 365; assert(date == Date(1, 12, 31)); date.dayOfGregorianCal = 366; assert(date == Date(2, 1, 1)); date.dayOfGregorianCal = 0; assert(date == Date(0, 12, 31)); date.dayOfGregorianCal = -365; assert(date == Date(-0, 1, 1)); date.dayOfGregorianCal = -366; assert(date == Date(-1, 12, 31)); date.dayOfGregorianCal = 730_120; assert(date == Date(2000, 1, 1)); date.dayOfGregorianCal = 734_137; assert(date == Date(2010, 12, 31)); } unittest { auto date = Date(1999, 7, 6); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); date.dayOfGregorianCal = 187; assert(date.dayOfGregorianCal == 187); static assert(!__traits(compiles, cdate.dayOfGregorianCal = 187)); static assert(!__traits(compiles, idate.dayOfGregorianCal = 187)); } /++ The ISO 8601 week of the year that this $(LREF Date) is in. See_Also: $(WEB en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) +/ @property ubyte isoWeek() @safe const pure nothrow { immutable weekday = dayOfWeek; immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday; immutable week = (dayOfYear - adjustedWeekday + 10) / 7; try { if(week == 53) { switch(Date(_year + 1, 1, 1).dayOfWeek) { case DayOfWeek.mon: case DayOfWeek.tue: case DayOfWeek.wed: case DayOfWeek.thu: return 1; case DayOfWeek.fri: case DayOfWeek.sat: case DayOfWeek.sun: return 53; default: assert(0, "Invalid ISO Week"); } } else if(week > 0) return cast(ubyte)week; else return Date(_year - 1, 12, 31).isoWeek; } catch(Exception e) assert(0, "Date's constructor threw."); } unittest { //Test A.D. assert(Date(2009, 12, 28).isoWeek == 53); assert(Date(2009, 12, 29).isoWeek == 53); assert(Date(2009, 12, 30).isoWeek == 53); assert(Date(2009, 12, 31).isoWeek == 53); assert(Date(2010, 1, 1).isoWeek == 53); assert(Date(2010, 1, 2).isoWeek == 53); assert(Date(2010, 1, 3).isoWeek == 53); assert(Date(2010, 1, 4).isoWeek == 1); assert(Date(2010, 1, 5).isoWeek == 1); assert(Date(2010, 1, 6).isoWeek == 1); assert(Date(2010, 1, 7).isoWeek == 1); assert(Date(2010, 1, 8).isoWeek == 1); assert(Date(2010, 1, 9).isoWeek == 1); assert(Date(2010, 1, 10).isoWeek == 1); assert(Date(2010, 1, 11).isoWeek == 2); assert(Date(2010, 12, 31).isoWeek == 52); assert(Date(2004, 12, 26).isoWeek == 52); assert(Date(2004, 12, 27).isoWeek == 53); assert(Date(2004, 12, 28).isoWeek == 53); assert(Date(2004, 12, 29).isoWeek == 53); assert(Date(2004, 12, 30).isoWeek == 53); assert(Date(2004, 12, 31).isoWeek == 53); assert(Date(2005, 1, 1).isoWeek == 53); assert(Date(2005, 1, 2).isoWeek == 53); assert(Date(2005, 12, 31).isoWeek == 52); assert(Date(2007, 1, 1).isoWeek == 1); assert(Date(2007, 12, 30).isoWeek == 52); assert(Date(2007, 12, 31).isoWeek == 1); assert(Date(2008, 1, 1).isoWeek == 1); assert(Date(2008, 12, 28).isoWeek == 52); assert(Date(2008, 12, 29).isoWeek == 1); assert(Date(2008, 12, 30).isoWeek == 1); assert(Date(2008, 12, 31).isoWeek == 1); assert(Date(2009, 1, 1).isoWeek == 1); assert(Date(2009, 1, 2).isoWeek == 1); assert(Date(2009, 1, 3).isoWeek == 1); assert(Date(2009, 1, 4).isoWeek == 1); //Test B.C. //The algorithm should work identically for both A.D. and B.C. since //it doesn't really take the year into account, so B.C. testing //probably isn't really needed. assert(Date(0, 12, 31).isoWeek == 52); assert(Date(0, 1, 4).isoWeek == 1); assert(Date(0, 1, 1).isoWeek == 52); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.isoWeek == 27); static assert(!__traits(compiles, cdate.isoWeek = 3)); assert(idate.isoWeek == 27); static assert(!__traits(compiles, idate.isoWeek = 3)); } /++ $(LREF Date) for the last day in the month that this $(LREF Date) is in. +/ @property Date endOfMonth() @safe const pure nothrow { try return Date(_year, _month, maxDay(_year, _month)); catch(Exception e) assert(0, "Date's constructor threw."); } /// unittest { assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31)); assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28)); assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29)); assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30)); } unittest { //Test A.D. assert(Date(1999, 1, 1).endOfMonth == Date(1999, 1, 31)); assert(Date(1999, 2, 1).endOfMonth == Date(1999, 2, 28)); assert(Date(2000, 2, 1).endOfMonth == Date(2000, 2, 29)); assert(Date(1999, 3, 1).endOfMonth == Date(1999, 3, 31)); assert(Date(1999, 4, 1).endOfMonth == Date(1999, 4, 30)); assert(Date(1999, 5, 1).endOfMonth == Date(1999, 5, 31)); assert(Date(1999, 6, 1).endOfMonth == Date(1999, 6, 30)); assert(Date(1999, 7, 1).endOfMonth == Date(1999, 7, 31)); assert(Date(1999, 8, 1).endOfMonth == Date(1999, 8, 31)); assert(Date(1999, 9, 1).endOfMonth == Date(1999, 9, 30)); assert(Date(1999, 10, 1).endOfMonth == Date(1999, 10, 31)); assert(Date(1999, 11, 1).endOfMonth == Date(1999, 11, 30)); assert(Date(1999, 12, 1).endOfMonth == Date(1999, 12, 31)); //Test B.C. assert(Date(-1999, 1, 1).endOfMonth == Date(-1999, 1, 31)); assert(Date(-1999, 2, 1).endOfMonth == Date(-1999, 2, 28)); assert(Date(-2000, 2, 1).endOfMonth == Date(-2000, 2, 29)); assert(Date(-1999, 3, 1).endOfMonth == Date(-1999, 3, 31)); assert(Date(-1999, 4, 1).endOfMonth == Date(-1999, 4, 30)); assert(Date(-1999, 5, 1).endOfMonth == Date(-1999, 5, 31)); assert(Date(-1999, 6, 1).endOfMonth == Date(-1999, 6, 30)); assert(Date(-1999, 7, 1).endOfMonth == Date(-1999, 7, 31)); assert(Date(-1999, 8, 1).endOfMonth == Date(-1999, 8, 31)); assert(Date(-1999, 9, 1).endOfMonth == Date(-1999, 9, 30)); assert(Date(-1999, 10, 1).endOfMonth == Date(-1999, 10, 31)); assert(Date(-1999, 11, 1).endOfMonth == Date(-1999, 11, 30)); assert(Date(-1999, 12, 1).endOfMonth == Date(-1999, 12, 31)); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.endOfMonth = Date(1999, 7, 30))); static assert(!__traits(compiles, idate.endOfMonth = Date(1999, 7, 30))); } /++ The last day in the month that this $(LREF Date) is in. +/ @property ubyte daysInMonth() @safe const pure nothrow { return maxDay(_year, _month); } /// unittest { assert(Date(1999, 1, 6).daysInMonth == 31); assert(Date(1999, 2, 7).daysInMonth == 28); assert(Date(2000, 2, 7).daysInMonth == 29); assert(Date(2000, 6, 4).daysInMonth == 30); } unittest { //Test A.D. assert(Date(1999, 1, 1).daysInMonth == 31); assert(Date(1999, 2, 1).daysInMonth == 28); assert(Date(2000, 2, 1).daysInMonth == 29); assert(Date(1999, 3, 1).daysInMonth == 31); assert(Date(1999, 4, 1).daysInMonth == 30); assert(Date(1999, 5, 1).daysInMonth == 31); assert(Date(1999, 6, 1).daysInMonth == 30); assert(Date(1999, 7, 1).daysInMonth == 31); assert(Date(1999, 8, 1).daysInMonth == 31); assert(Date(1999, 9, 1).daysInMonth == 30); assert(Date(1999, 10, 1).daysInMonth == 31); assert(Date(1999, 11, 1).daysInMonth == 30); assert(Date(1999, 12, 1).daysInMonth == 31); //Test B.C. assert(Date(-1999, 1, 1).daysInMonth == 31); assert(Date(-1999, 2, 1).daysInMonth == 28); assert(Date(-2000, 2, 1).daysInMonth == 29); assert(Date(-1999, 3, 1).daysInMonth == 31); assert(Date(-1999, 4, 1).daysInMonth == 30); assert(Date(-1999, 5, 1).daysInMonth == 31); assert(Date(-1999, 6, 1).daysInMonth == 30); assert(Date(-1999, 7, 1).daysInMonth == 31); assert(Date(-1999, 8, 1).daysInMonth == 31); assert(Date(-1999, 9, 1).daysInMonth == 30); assert(Date(-1999, 10, 1).daysInMonth == 31); assert(Date(-1999, 11, 1).daysInMonth == 30); assert(Date(-1999, 12, 1).daysInMonth == 31); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate.daysInMonth = 30)); static assert(!__traits(compiles, idate.daysInMonth = 30)); } /++ Whether the current year is a date in A.D. +/ @property bool isAD() @safe const pure nothrow { return _year > 0; } /// unittest { assert(Date(1, 1, 1).isAD); assert(Date(2010, 12, 31).isAD); assert(!Date(0, 12, 31).isAD); assert(!Date(-2010, 1, 1).isAD); } unittest { assert(Date(2010, 7, 4).isAD); assert(Date(1, 1, 1).isAD); assert(!Date(0, 1, 1).isAD); assert(!Date(-1, 1, 1).isAD); assert(!Date(-2010, 7, 4).isAD); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.isAD); assert(idate.isAD); } /++ The $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for this $(LREF Date) at noon (since the Julian day changes at noon). +/ @property long julianDay() @safe const pure nothrow { return dayOfGregorianCal + 1_721_425; } unittest { assert(Date(-4713, 11, 24).julianDay == 0); assert(Date(0, 12, 31).julianDay == 1_721_425); assert(Date(1, 1, 1).julianDay == 1_721_426); assert(Date(1582, 10, 15).julianDay == 2_299_161); assert(Date(1858, 11, 17).julianDay == 2_400_001); assert(Date(1982, 1, 4).julianDay == 2_444_974); assert(Date(1996, 3, 31).julianDay == 2_450_174); assert(Date(2010, 8, 24).julianDay == 2_455_433); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.julianDay == 2_451_366); assert(idate.julianDay == 2_451_366); } /++ The modified $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for any time on this date (since, the modified Julian day changes at midnight). +/ @property long modJulianDay() @safe const pure nothrow { return julianDay - 2_400_001; } unittest { assert(Date(1858, 11, 17).modJulianDay == 0); assert(Date(2010, 8, 24).modJulianDay == 55_432); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.modJulianDay == 51_365); assert(idate.modJulianDay == 51_365); } /++ Converts this $(LREF Date) to a string with the format YYYYMMDD. +/ string toISOString() @safe const pure nothrow { import std.format : format; try { if(_year >= 0) { if(_year < 10_000) return format("%04d%02d%02d", _year, _month, _day); else return format("+%05d%02d%02d", _year, _month, _day); } else if(_year > -10_000) return format("%05d%02d%02d", _year, _month, _day); else return format("%06d%02d%02d", _year, _month, _day); } catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(Date(2010, 7, 4).toISOString() == "20100704"); assert(Date(1998, 12, 25).toISOString() == "19981225"); assert(Date(0, 1, 5).toISOString() == "00000105"); assert(Date(-4, 1, 5).toISOString() == "-00040105"); } unittest { //Test A.D. assert(Date(9, 12, 4).toISOString() == "00091204"); assert(Date(99, 12, 4).toISOString() == "00991204"); assert(Date(999, 12, 4).toISOString() == "09991204"); assert(Date(9999, 7, 4).toISOString() == "99990704"); assert(Date(10000, 10, 20).toISOString() == "+100001020"); //Test B.C. assert(Date(0, 12, 4).toISOString() == "00001204"); assert(Date(-9, 12, 4).toISOString() == "-00091204"); assert(Date(-99, 12, 4).toISOString() == "-00991204"); assert(Date(-999, 12, 4).toISOString() == "-09991204"); assert(Date(-9999, 7, 4).toISOString() == "-99990704"); assert(Date(-10000, 10, 20).toISOString() == "-100001020"); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.toISOString() == "19990706"); assert(idate.toISOString() == "19990706"); } /++ Converts this $(LREF Date) to a string with the format YYYY-MM-DD. +/ string toISOExtString() @safe const pure nothrow { import std.format : format; try { if(_year >= 0) { if(_year < 10_000) return format("%04d-%02d-%02d", _year, _month, _day); else return format("+%05d-%02d-%02d", _year, _month, _day); } else if(_year > -10_000) return format("%05d-%02d-%02d", _year, _month, _day); else return format("%06d-%02d-%02d", _year, _month, _day); } catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04"); assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25"); assert(Date(0, 1, 5).toISOExtString() == "0000-01-05"); assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05"); } unittest { //Test A.D. assert(Date(9, 12, 4).toISOExtString() == "0009-12-04"); assert(Date(99, 12, 4).toISOExtString() == "0099-12-04"); assert(Date(999, 12, 4).toISOExtString() == "0999-12-04"); assert(Date(9999, 7, 4).toISOExtString() == "9999-07-04"); assert(Date(10000, 10, 20).toISOExtString() == "+10000-10-20"); //Test B.C. assert(Date(0, 12, 4).toISOExtString() == "0000-12-04"); assert(Date(-9, 12, 4).toISOExtString() == "-0009-12-04"); assert(Date(-99, 12, 4).toISOExtString() == "-0099-12-04"); assert(Date(-999, 12, 4).toISOExtString() == "-0999-12-04"); assert(Date(-9999, 7, 4).toISOExtString() == "-9999-07-04"); assert(Date(-10000, 10, 20).toISOExtString() == "-10000-10-20"); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.toISOExtString() == "1999-07-06"); assert(idate.toISOExtString() == "1999-07-06"); } /++ Converts this $(LREF Date) to a string with the format YYYY-Mon-DD. +/ string toSimpleString() @safe const pure nothrow { import std.format : format; try { if(_year >= 0) { if(_year < 10_000) return format("%04d-%s-%02d", _year, monthToString(_month), _day); else return format("+%05d-%s-%02d", _year, monthToString(_month), _day); } else if(_year > -10_000) return format("%05d-%s-%02d", _year, monthToString(_month), _day); else return format("%06d-%s-%02d", _year, monthToString(_month), _day); } catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04"); assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25"); assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05"); assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05"); } unittest { //Test A.D. assert(Date(9, 12, 4).toSimpleString() == "0009-Dec-04"); assert(Date(99, 12, 4).toSimpleString() == "0099-Dec-04"); assert(Date(999, 12, 4).toSimpleString() == "0999-Dec-04"); assert(Date(9999, 7, 4).toSimpleString() == "9999-Jul-04"); assert(Date(10000, 10, 20).toSimpleString() == "+10000-Oct-20"); //Test B.C. assert(Date(0, 12, 4).toSimpleString() == "0000-Dec-04"); assert(Date(-9, 12, 4).toSimpleString() == "-0009-Dec-04"); assert(Date(-99, 12, 4).toSimpleString() == "-0099-Dec-04"); assert(Date(-999, 12, 4).toSimpleString() == "-0999-Dec-04"); assert(Date(-9999, 7, 4).toSimpleString() == "-9999-Jul-04"); assert(Date(-10000, 10, 20).toSimpleString() == "-10000-Oct-20"); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(cdate.toSimpleString() == "1999-Jul-06"); assert(idate.toSimpleString() == "1999-Jul-06"); } /++ Converts this $(LREF Date) to a string. +/ string toString() @safe const pure nothrow { return toSimpleString(); } unittest { auto date = Date(1999, 7, 6); const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); assert(date.toString()); assert(cdate.toString()); assert(idate.toString()); } /++ Creates a $(LREF Date) from a string with the format YYYYMMDD. Whitespace is stripped from the given string. Params: isoString = A string formatted in the ISO format for dates. Throws: $(LREF DateTimeException) if the given string is not in the ISO format or if the resulting $(LREF Date) would not be valid. +/ static Date fromISOString(S)(in S isoString) @safe pure if(isSomeString!S) { import std.ascii : isDigit; import std.string : strip; import std.conv : to; import std.algorithm : all, startsWith; import std.format : format; auto dstr = to!dstring(strip(isoString)); enforce(dstr.length >= 8, new DateTimeException(format("Invalid ISO String: %s", isoString))); auto day = dstr[$-2 .. $]; auto month = dstr[$-4 .. $-2]; auto year = dstr[0 .. $-4]; enforce(all!isDigit(day), new DateTimeException(format("Invalid ISO String: %s", isoString))); enforce(all!isDigit(month), new DateTimeException(format("Invalid ISO String: %s", isoString))); if(year.length > 4) { enforce(year.startsWith('-', '+'), new DateTimeException(format("Invalid ISO String: %s", isoString))); enforce(all!isDigit(year[1..$]), new DateTimeException(format("Invalid ISO String: %s", isoString))); } else enforce(all!isDigit(year), new DateTimeException(format("Invalid ISO String: %s", isoString))); return Date(to!short(year), to!ubyte(month), to!ubyte(day)); } /// unittest { assert(Date.fromISOString("20100704") == Date(2010, 7, 4)); assert(Date.fromISOString("19981225") == Date(1998, 12, 25)); assert(Date.fromISOString("00000105") == Date(0, 1, 5)); assert(Date.fromISOString("-00040105") == Date(-4, 1, 5)); assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4)); } unittest { assertThrown!DateTimeException(Date.fromISOString("")); assertThrown!DateTimeException(Date.fromISOString("990704")); assertThrown!DateTimeException(Date.fromISOString("0100704")); assertThrown!DateTimeException(Date.fromISOString("2010070")); assertThrown!DateTimeException(Date.fromISOString("2010070 ")); assertThrown!DateTimeException(Date.fromISOString("120100704")); assertThrown!DateTimeException(Date.fromISOString("-0100704")); assertThrown!DateTimeException(Date.fromISOString("+0100704")); assertThrown!DateTimeException(Date.fromISOString("2010070a")); assertThrown!DateTimeException(Date.fromISOString("20100a04")); assertThrown!DateTimeException(Date.fromISOString("2010a704")); assertThrown!DateTimeException(Date.fromISOString("99-07-04")); assertThrown!DateTimeException(Date.fromISOString("010-07-04")); assertThrown!DateTimeException(Date.fromISOString("2010-07-0")); assertThrown!DateTimeException(Date.fromISOString("2010-07-0 ")); assertThrown!DateTimeException(Date.fromISOString("12010-07-04")); assertThrown!DateTimeException(Date.fromISOString("-010-07-04")); assertThrown!DateTimeException(Date.fromISOString("+010-07-04")); assertThrown!DateTimeException(Date.fromISOString("2010-07-0a")); assertThrown!DateTimeException(Date.fromISOString("2010-0a-04")); assertThrown!DateTimeException(Date.fromISOString("2010-a7-04")); assertThrown!DateTimeException(Date.fromISOString("2010/07/04")); assertThrown!DateTimeException(Date.fromISOString("2010/7/04")); assertThrown!DateTimeException(Date.fromISOString("2010/7/4")); assertThrown!DateTimeException(Date.fromISOString("2010/07/4")); assertThrown!DateTimeException(Date.fromISOString("2010-7-04")); assertThrown!DateTimeException(Date.fromISOString("2010-7-4")); assertThrown!DateTimeException(Date.fromISOString("2010-07-4")); assertThrown!DateTimeException(Date.fromISOString("99Jul04")); assertThrown!DateTimeException(Date.fromISOString("010Jul04")); assertThrown!DateTimeException(Date.fromISOString("2010Jul0")); assertThrown!DateTimeException(Date.fromISOString("2010Jul0 ")); assertThrown!DateTimeException(Date.fromISOString("12010Jul04")); assertThrown!DateTimeException(Date.fromISOString("-010Jul04")); assertThrown!DateTimeException(Date.fromISOString("+010Jul04")); assertThrown!DateTimeException(Date.fromISOString("2010Jul0a")); assertThrown!DateTimeException(Date.fromISOString("2010Jua04")); assertThrown!DateTimeException(Date.fromISOString("2010aul04")); assertThrown!DateTimeException(Date.fromISOString("99-Jul-04")); assertThrown!DateTimeException(Date.fromISOString("010-Jul-04")); assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0")); assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0 ")); assertThrown!DateTimeException(Date.fromISOString("12010-Jul-04")); assertThrown!DateTimeException(Date.fromISOString("-010-Jul-04")); assertThrown!DateTimeException(Date.fromISOString("+010-Jul-04")); assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0a")); assertThrown!DateTimeException(Date.fromISOString("2010-Jua-04")); assertThrown!DateTimeException(Date.fromISOString("2010-Jal-04")); assertThrown!DateTimeException(Date.fromISOString("2010-aul-04")); assertThrown!DateTimeException(Date.fromISOString("2010-07-04")); assertThrown!DateTimeException(Date.fromISOString("2010-Jul-04")); assert(Date.fromISOString("19990706") == Date(1999, 7, 6)); assert(Date.fromISOString("-19990706") == Date(-1999, 7, 6)); assert(Date.fromISOString("+019990706") == Date(1999, 7, 6)); assert(Date.fromISOString("19990706 ") == Date(1999, 7, 6)); assert(Date.fromISOString(" 19990706") == Date(1999, 7, 6)); assert(Date.fromISOString(" 19990706 ") == Date(1999, 7, 6)); } /++ Creates a $(LREF Date) from a string with the format YYYY-MM-DD. Whitespace is stripped from the given string. Params: isoExtString = A string formatted in the ISO Extended format for dates. Throws: $(LREF DateTimeException) if the given string is not in the ISO Extended format or if the resulting $(LREF Date) would not be valid. +/ static Date fromISOExtString(S)(in S isoExtString) @safe pure if(isSomeString!(S)) { import std.ascii : isDigit; import std.string : strip; import std.conv : to; import std.algorithm : all, startsWith; import std.format : format; auto dstr = to!dstring(strip(isoExtString)); enforce(dstr.length >= 10, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); auto day = dstr[$-2 .. $]; auto month = dstr[$-5 .. $-3]; auto year = dstr[0 .. $-6]; enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); enforce(dstr[$-6] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); enforce(all!isDigit(day), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); enforce(all!isDigit(month), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); if(year.length > 4) { enforce(year.startsWith('-', '+'), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); enforce(all!isDigit(year[1..$]), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); } else enforce(all!isDigit(year), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); return Date(to!short(year), to!ubyte(month), to!ubyte(day)); } /// unittest { assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4)); assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25)); assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5)); assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5)); assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4)); } unittest { assertThrown!DateTimeException(Date.fromISOExtString("")); assertThrown!DateTimeException(Date.fromISOExtString("990704")); assertThrown!DateTimeException(Date.fromISOExtString("0100704")); assertThrown!DateTimeException(Date.fromISOExtString("2010070")); assertThrown!DateTimeException(Date.fromISOExtString("2010070 ")); assertThrown!DateTimeException(Date.fromISOExtString("120100704")); assertThrown!DateTimeException(Date.fromISOExtString("-0100704")); assertThrown!DateTimeException(Date.fromISOExtString("+0100704")); assertThrown!DateTimeException(Date.fromISOExtString("2010070a")); assertThrown!DateTimeException(Date.fromISOExtString("20100a04")); assertThrown!DateTimeException(Date.fromISOExtString("2010a704")); assertThrown!DateTimeException(Date.fromISOExtString("99-07-04")); assertThrown!DateTimeException(Date.fromISOExtString("010-07-04")); assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0")); assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0 ")); assertThrown!DateTimeException(Date.fromISOExtString("12010-07-04")); assertThrown!DateTimeException(Date.fromISOExtString("-010-07-04")); assertThrown!DateTimeException(Date.fromISOExtString("+010-07-04")); assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0a")); assertThrown!DateTimeException(Date.fromISOExtString("2010-0a-04")); assertThrown!DateTimeException(Date.fromISOExtString("2010-a7-04")); assertThrown!DateTimeException(Date.fromISOExtString("2010/07/04")); assertThrown!DateTimeException(Date.fromISOExtString("2010/7/04")); assertThrown!DateTimeException(Date.fromISOExtString("2010/7/4")); assertThrown!DateTimeException(Date.fromISOExtString("2010/07/4")); assertThrown!DateTimeException(Date.fromISOExtString("2010-7-04")); assertThrown!DateTimeException(Date.fromISOExtString("2010-7-4")); assertThrown!DateTimeException(Date.fromISOExtString("2010-07-4")); assertThrown!DateTimeException(Date.fromISOExtString("99Jul04")); assertThrown!DateTimeException(Date.fromISOExtString("010Jul04")); assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0")); assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0 ")); assertThrown!DateTimeException(Date.fromISOExtString("12010Jul04")); assertThrown!DateTimeException(Date.fromISOExtString("-010Jul04")); assertThrown!DateTimeException(Date.fromISOExtString("+010Jul04")); assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0a")); assertThrown!DateTimeException(Date.fromISOExtString("2010Jua04")); assertThrown!DateTimeException(Date.fromISOExtString("2010aul04")); assertThrown!DateTimeException(Date.fromISOExtString("99-Jul-04")); assertThrown!DateTimeException(Date.fromISOExtString("010-Jul-04")); assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0")); assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0 ")); assertThrown!DateTimeException(Date.fromISOExtString("12010-Jul-04")); assertThrown!DateTimeException(Date.fromISOExtString("-010-Jul-04")); assertThrown!DateTimeException(Date.fromISOExtString("+010-Jul-04")); assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0a")); assertThrown!DateTimeException(Date.fromISOExtString("2010-Jua-04")); assertThrown!DateTimeException(Date.fromISOExtString("2010-Jal-04")); assertThrown!DateTimeException(Date.fromISOExtString("2010-aul-04")); assertThrown!DateTimeException(Date.fromISOExtString("20100704")); assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-04")); assert(Date.fromISOExtString("1999-07-06") == Date(1999, 7, 6)); assert(Date.fromISOExtString("-1999-07-06") == Date(-1999, 7, 6)); assert(Date.fromISOExtString("+01999-07-06") == Date(1999, 7, 6)); assert(Date.fromISOExtString("1999-07-06 ") == Date(1999, 7, 6)); assert(Date.fromISOExtString(" 1999-07-06") == Date(1999, 7, 6)); assert(Date.fromISOExtString(" 1999-07-06 ") == Date(1999, 7, 6)); } /++ Creates a $(LREF Date) from a string with the format YYYY-Mon-DD. Whitespace is stripped from the given string. Params: simpleString = A string formatted in the way that toSimpleString formats dates. Throws: $(LREF DateTimeException) if the given string is not in the correct format or if the resulting $(LREF Date) would not be valid. +/ static Date fromSimpleString(S)(in S simpleString) @safe pure if(isSomeString!(S)) { import std.ascii : isDigit; import std.string : strip; import std.conv : to; import std.algorithm : all, startsWith; import std.format : format; auto dstr = to!dstring(strip(simpleString)); enforce(dstr.length >= 11, new DateTimeException(format("Invalid string format: %s", simpleString))); auto day = dstr[$-2 .. $]; auto month = monthFromString(to!string(dstr[$-6 .. $-3])); auto year = dstr[0 .. $-7]; enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid string format: %s", simpleString))); enforce(dstr[$-7] == '-', new DateTimeException(format("Invalid string format: %s", simpleString))); enforce(all!isDigit(day), new DateTimeException(format("Invalid string format: %s", simpleString))); if(year.length > 4) { enforce(year.startsWith('-', '+'), new DateTimeException(format("Invalid string format: %s", simpleString))); enforce(all!isDigit(year[1..$]), new DateTimeException(format("Invalid string format: %s", simpleString))); } else enforce(all!isDigit(year), new DateTimeException(format("Invalid string format: %s", simpleString))); return Date(to!short(year), month, to!ubyte(day)); } /// unittest { assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4)); assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25)); assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5)); assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5)); assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4)); } unittest { assertThrown!DateTimeException(Date.fromSimpleString("")); assertThrown!DateTimeException(Date.fromSimpleString("990704")); assertThrown!DateTimeException(Date.fromSimpleString("0100704")); assertThrown!DateTimeException(Date.fromSimpleString("2010070")); assertThrown!DateTimeException(Date.fromSimpleString("2010070 ")); assertThrown!DateTimeException(Date.fromSimpleString("120100704")); assertThrown!DateTimeException(Date.fromSimpleString("-0100704")); assertThrown!DateTimeException(Date.fromSimpleString("+0100704")); assertThrown!DateTimeException(Date.fromSimpleString("2010070a")); assertThrown!DateTimeException(Date.fromSimpleString("20100a04")); assertThrown!DateTimeException(Date.fromSimpleString("2010a704")); assertThrown!DateTimeException(Date.fromSimpleString("99-07-04")); assertThrown!DateTimeException(Date.fromSimpleString("010-07-04")); assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0")); assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0 ")); assertThrown!DateTimeException(Date.fromSimpleString("12010-07-04")); assertThrown!DateTimeException(Date.fromSimpleString("-010-07-04")); assertThrown!DateTimeException(Date.fromSimpleString("+010-07-04")); assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0a")); assertThrown!DateTimeException(Date.fromSimpleString("2010-0a-04")); assertThrown!DateTimeException(Date.fromSimpleString("2010-a7-04")); assertThrown!DateTimeException(Date.fromSimpleString("2010/07/04")); assertThrown!DateTimeException(Date.fromSimpleString("2010/7/04")); assertThrown!DateTimeException(Date.fromSimpleString("2010/7/4")); assertThrown!DateTimeException(Date.fromSimpleString("2010/07/4")); assertThrown!DateTimeException(Date.fromSimpleString("2010-7-04")); assertThrown!DateTimeException(Date.fromSimpleString("2010-7-4")); assertThrown!DateTimeException(Date.fromSimpleString("2010-07-4")); assertThrown!DateTimeException(Date.fromSimpleString("99Jul04")); assertThrown!DateTimeException(Date.fromSimpleString("010Jul04")); assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0")); assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0 ")); assertThrown!DateTimeException(Date.fromSimpleString("12010Jul04")); assertThrown!DateTimeException(Date.fromSimpleString("-010Jul04")); assertThrown!DateTimeException(Date.fromSimpleString("+010Jul04")); assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0a")); assertThrown!DateTimeException(Date.fromSimpleString("2010Jua04")); assertThrown!DateTimeException(Date.fromSimpleString("2010aul04")); assertThrown!DateTimeException(Date.fromSimpleString("99-Jul-04")); assertThrown!DateTimeException(Date.fromSimpleString("010-Jul-04")); assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0")); assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0 ")); assertThrown!DateTimeException(Date.fromSimpleString("12010-Jul-04")); assertThrown!DateTimeException(Date.fromSimpleString("-010-Jul-04")); assertThrown!DateTimeException(Date.fromSimpleString("+010-Jul-04")); assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0a")); assertThrown!DateTimeException(Date.fromSimpleString("2010-Jua-04")); assertThrown!DateTimeException(Date.fromSimpleString("2010-Jal-04")); assertThrown!DateTimeException(Date.fromSimpleString("2010-aul-04")); assertThrown!DateTimeException(Date.fromSimpleString("20100704")); assertThrown!DateTimeException(Date.fromSimpleString("2010-07-04")); assert(Date.fromSimpleString("1999-Jul-06") == Date(1999, 7, 6)); assert(Date.fromSimpleString("-1999-Jul-06") == Date(-1999, 7, 6)); assert(Date.fromSimpleString("+01999-Jul-06") == Date(1999, 7, 6)); assert(Date.fromSimpleString("1999-Jul-06 ") == Date(1999, 7, 6)); assert(Date.fromSimpleString(" 1999-Jul-06") == Date(1999, 7, 6)); assert(Date.fromSimpleString(" 1999-Jul-06 ") == Date(1999, 7, 6)); } /++ Returns the $(LREF Date) farthest in the past which is representable by $(LREF Date). +/ @property static Date min() @safe pure nothrow { auto date = Date.init; date._year = short.min; date._month = Month.jan; date._day = 1; return date; } unittest { assert(Date.min.year < 0); assert(Date.min < Date.max); } /++ Returns the $(LREF Date) farthest in the future which is representable by $(LREF Date). +/ @property static Date max() @safe pure nothrow { auto date = Date.init; date._year = short.max; date._month = Month.dec; date._day = 31; return date; } unittest { assert(Date.max.year > 0); assert(Date.max > Date.min); } private: /+ Whether the given values form a valid date. Params: year = The year to test. month = The month of the Gregorian Calendar to test. day = The day of the month to test. +/ static bool _valid(int year, int month, int day) @safe pure nothrow { if(!valid!"months"(month)) return false; return valid!"days"(year, month, day); } /+ Adds the given number of days to this $(LREF Date). A negative number will subtract. The month will be adjusted along with the day if the number of days added (or subtracted) would overflow (or underflow) the current month. The year will be adjusted along with the month if the increase (or decrease) to the month would cause it to overflow (or underflow) the current year. $(D _addDays(numDays)) is effectively equivalent to $(D date.dayOfGregorianCal = date.dayOfGregorianCal + days). Params: days = The number of days to add to this Date. +/ ref Date _addDays(long days) return @safe pure nothrow { dayOfGregorianCal = cast(int)(dayOfGregorianCal + days); return this; } unittest { //Test A.D. { auto date = Date(1999, 2, 28); date._addDays(1); assert(date == Date(1999, 3, 1)); date._addDays(-1); assert(date == Date(1999, 2, 28)); } { auto date = Date(2000, 2, 28); date._addDays(1); assert(date == Date(2000, 2, 29)); date._addDays(1); assert(date == Date(2000, 3, 1)); date._addDays(-1); assert(date == Date(2000, 2, 29)); } { auto date = Date(1999, 6, 30); date._addDays(1); assert(date == Date(1999, 7, 1)); date._addDays(-1); assert(date == Date(1999, 6, 30)); } { auto date = Date(1999, 7, 31); date._addDays(1); assert(date == Date(1999, 8, 1)); date._addDays(-1); assert(date == Date(1999, 7, 31)); } { auto date = Date(1999, 1, 1); date._addDays(-1); assert(date == Date(1998, 12, 31)); date._addDays(1); assert(date == Date(1999, 1, 1)); } { auto date = Date(1999, 7, 6); date._addDays(9); assert(date == Date(1999, 7, 15)); date._addDays(-11); assert(date == Date(1999, 7, 4)); date._addDays(30); assert(date == Date(1999, 8, 3)); date._addDays(-3); assert(date == Date(1999, 7, 31)); } { auto date = Date(1999, 7, 6); date._addDays(365); assert(date == Date(2000, 7, 5)); date._addDays(-365); assert(date == Date(1999, 7, 6)); date._addDays(366); assert(date == Date(2000, 7, 6)); date._addDays(730); assert(date == Date(2002, 7, 6)); date._addDays(-1096); assert(date == Date(1999, 7, 6)); } //Test B.C. { auto date = Date(-1999, 2, 28); date._addDays(1); assert(date == Date(-1999, 3, 1)); date._addDays(-1); assert(date == Date(-1999, 2, 28)); } { auto date = Date(-2000, 2, 28); date._addDays(1); assert(date == Date(-2000, 2, 29)); date._addDays(1); assert(date == Date(-2000, 3, 1)); date._addDays(-1); assert(date == Date(-2000, 2, 29)); } { auto date = Date(-1999, 6, 30); date._addDays(1); assert(date == Date(-1999, 7, 1)); date._addDays(-1); assert(date == Date(-1999, 6, 30)); } { auto date = Date(-1999, 7, 31); date._addDays(1); assert(date == Date(-1999, 8, 1)); date._addDays(-1); assert(date == Date(-1999, 7, 31)); } { auto date = Date(-1999, 1, 1); date._addDays(-1); assert(date == Date(-2000, 12, 31)); date._addDays(1); assert(date == Date(-1999, 1, 1)); } { auto date = Date(-1999, 7, 6); date._addDays(9); assert(date == Date(-1999, 7, 15)); date._addDays(-11); assert(date == Date(-1999, 7, 4)); date._addDays(30); assert(date == Date(-1999, 8, 3)); date._addDays(-3); } { auto date = Date(-1999, 7, 6); date._addDays(365); assert(date == Date(-1998, 7, 6)); date._addDays(-365); assert(date == Date(-1999, 7, 6)); date._addDays(366); assert(date == Date(-1998, 7, 7)); date._addDays(730); assert(date == Date(-1996, 7, 6)); date._addDays(-1096); assert(date == Date(-1999, 7, 6)); } //Test Both { auto date = Date(1, 7, 6); date._addDays(-365); assert(date == Date(0, 7, 6)); date._addDays(365); assert(date == Date(1, 7, 6)); date._addDays(-731); assert(date == Date(-1, 7, 6)); date._addDays(730); assert(date == Date(1, 7, 5)); } const cdate = Date(1999, 7, 6); immutable idate = Date(1999, 7, 6); static assert(!__traits(compiles, cdate._addDays(12))); static assert(!__traits(compiles, idate._addDays(12))); } @safe pure invariant() { import std.format : format; assert(valid!"months"(_month), format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); assert(valid!"days"(_year, _month, _day), format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); } short _year = 1; Month _month = Month.jan; ubyte _day = 1; } /++ Represents a time of day with hours, minutes, and seconds. It uses 24 hour time. +/ struct TimeOfDay { public: /++ Params: hour = Hour of the day [0 - 24$(RPAREN). minute = Minute of the hour [0 - 60$(RPAREN). second = Second of the minute [0 - 60$(RPAREN). Throws: $(LREF DateTimeException) if the resulting $(LREF TimeOfDay) would be not be valid. +/ this(int hour, int minute, int second = 0) @safe pure { enforceValid!"hours"(hour); enforceValid!"minutes"(minute); enforceValid!"seconds"(second); _hour = cast(ubyte)hour; _minute = cast(ubyte)minute; _second = cast(ubyte)second; } unittest { assert(TimeOfDay(0, 0) == TimeOfDay.init); { auto tod = TimeOfDay(0, 0); assert(tod._hour == 0); assert(tod._minute == 0); assert(tod._second == 0); } { auto tod = TimeOfDay(12, 30, 33); assert(tod._hour == 12); assert(tod._minute == 30); assert(tod._second == 33); } { auto tod = TimeOfDay(23, 59, 59); assert(tod._hour == 23); assert(tod._minute == 59); assert(tod._second == 59); } assertThrown!DateTimeException(TimeOfDay(24, 0, 0)); assertThrown!DateTimeException(TimeOfDay(0, 60, 0)); assertThrown!DateTimeException(TimeOfDay(0, 0, 60)); } /++ Compares this $(LREF TimeOfDay) with the given $(LREF TimeOfDay). Returns: $(BOOKTABLE, $(TR $(TD this < rhs) $(TD < 0)) $(TR $(TD this == rhs) $(TD 0)) $(TR $(TD this > rhs) $(TD > 0)) ) +/ int opCmp(in TimeOfDay rhs) @safe const pure nothrow { if(_hour < rhs._hour) return -1; if(_hour > rhs._hour) return 1; if(_minute < rhs._minute) return -1; if(_minute > rhs._minute) return 1; if(_second < rhs._second) return -1; if(_second > rhs._second) return 1; return 0; } unittest { assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay.init) == 0); assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay(0, 0, 0)) == 0); assert(TimeOfDay(12, 0, 0).opCmp(TimeOfDay(12, 0, 0)) == 0); assert(TimeOfDay(0, 30, 0).opCmp(TimeOfDay(0, 30, 0)) == 0); assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); assert(TimeOfDay(12, 30, 0).opCmp(TimeOfDay(12, 30, 0)) == 0); assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 33)) == 0); assert(TimeOfDay(0, 30, 33).opCmp(TimeOfDay(0, 30, 33)) == 0); assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 31, 33)) < 0); assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 34)) < 0); assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 30, 33)) > 0); assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(13, 30, 33)) < 0); assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 31, 33)) > 0); assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 31, 33)) < 0); const ctod = TimeOfDay(12, 30, 33); immutable itod = TimeOfDay(12, 30, 33); assert(ctod.opCmp(itod) == 0); assert(itod.opCmp(ctod) == 0); } /++ Hours past midnight. +/ @property ubyte hour() @safe const pure nothrow { return _hour; } unittest { assert(TimeOfDay.init.hour == 0); assert(TimeOfDay(12, 0, 0).hour == 12); const ctod = TimeOfDay(12, 0, 0); immutable itod = TimeOfDay(12, 0, 0); assert(ctod.hour == 12); assert(itod.hour == 12); } /++ Hours past midnight. Params: hour = The hour of the day to set this $(LREF TimeOfDay)'s hour to. Throws: $(LREF DateTimeException) if the given hour would result in an invalid $(LREF TimeOfDay). +/ @property void hour(int hour) @safe pure { enforceValid!"hours"(hour); _hour = cast(ubyte)hour; } unittest { assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).hour = 24;}()); auto tod = TimeOfDay(0, 0, 0); tod.hour = 12; assert(tod == TimeOfDay(12, 0, 0)); const ctod = TimeOfDay(0, 0, 0); immutable itod = TimeOfDay(0, 0, 0); static assert(!__traits(compiles, ctod.hour = 12)); static assert(!__traits(compiles, itod.hour = 12)); } /++ Minutes past the hour. +/ @property ubyte minute() @safe const pure nothrow { return _minute; } unittest { assert(TimeOfDay.init.minute == 0); assert(TimeOfDay(0, 30, 0).minute == 30); const ctod = TimeOfDay(0, 30, 0); immutable itod = TimeOfDay(0, 30, 0); assert(ctod.minute == 30); assert(itod.minute == 30); } /++ Minutes past the hour. Params: minute = The minute to set this $(LREF TimeOfDay)'s minute to. Throws: $(LREF DateTimeException) if the given minute would result in an invalid $(LREF TimeOfDay). +/ @property void minute(int minute) @safe pure { enforceValid!"minutes"(minute); _minute = cast(ubyte)minute; } unittest { assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).minute = 60;}()); auto tod = TimeOfDay(0, 0, 0); tod.minute = 30; assert(tod == TimeOfDay(0, 30, 0)); const ctod = TimeOfDay(0, 0, 0); immutable itod = TimeOfDay(0, 0, 0); static assert(!__traits(compiles, ctod.minute = 30)); static assert(!__traits(compiles, itod.minute = 30)); } /++ Seconds past the minute. +/ @property ubyte second() @safe const pure nothrow { return _second; } unittest { assert(TimeOfDay.init.second == 0); assert(TimeOfDay(0, 0, 33).second == 33); const ctod = TimeOfDay(0, 0, 33); immutable itod = TimeOfDay(0, 0, 33); assert(ctod.second == 33); assert(itod.second == 33); } /++ Seconds past the minute. Params: second = The second to set this $(LREF TimeOfDay)'s second to. Throws: $(LREF DateTimeException) if the given second would result in an invalid $(LREF TimeOfDay). +/ @property void second(int second) @safe pure { enforceValid!"seconds"(second); _second = cast(ubyte)second; } unittest { assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).second = 60;}()); auto tod = TimeOfDay(0, 0, 0); tod.second = 33; assert(tod == TimeOfDay(0, 0, 33)); const ctod = TimeOfDay(0, 0, 0); immutable itod = TimeOfDay(0, 0, 0); static assert(!__traits(compiles, ctod.second = 33)); static assert(!__traits(compiles, itod.second = 33)); } /++ Adds the given number of units to this $(LREF TimeOfDay). A negative number will subtract. The difference between rolling and adding is that rolling does not affect larger units. For instance, rolling a $(LREF TimeOfDay) one hours's worth of minutes gets the exact same $(LREF TimeOfDay). Accepted units are $(D "hours"), $(D "minutes"), and $(D "seconds"). Params: units = The units to add. value = The number of $(D_PARAM units) to add to this $(LREF TimeOfDay). +/ ref TimeOfDay roll(string units)(long value) @safe pure nothrow if(units == "hours") { return this += dur!"hours"(value); } /// unittest { auto tod1 = TimeOfDay(7, 12, 0); tod1.roll!"hours"(1); assert(tod1 == TimeOfDay(8, 12, 0)); auto tod2 = TimeOfDay(7, 12, 0); tod2.roll!"hours"(-1); assert(tod2 == TimeOfDay(6, 12, 0)); auto tod3 = TimeOfDay(23, 59, 0); tod3.roll!"minutes"(1); assert(tod3 == TimeOfDay(23, 0, 0)); auto tod4 = TimeOfDay(0, 0, 0); tod4.roll!"minutes"(-1); assert(tod4 == TimeOfDay(0, 59, 0)); auto tod5 = TimeOfDay(23, 59, 59); tod5.roll!"seconds"(1); assert(tod5 == TimeOfDay(23, 59, 0)); auto tod6 = TimeOfDay(0, 0, 0); tod6.roll!"seconds"(-1); assert(tod6 == TimeOfDay(0, 0, 59)); } unittest { auto tod = TimeOfDay(12, 27, 2); tod.roll!"hours"(22).roll!"hours"(-7); assert(tod == TimeOfDay(3, 27, 2)); const ctod = TimeOfDay(0, 0, 0); immutable itod = TimeOfDay(0, 0, 0); static assert(!__traits(compiles, ctod.roll!"hours"(53))); static assert(!__traits(compiles, itod.roll!"hours"(53))); } //Shares documentation with "hours" version. ref TimeOfDay roll(string units)(long value) @safe pure nothrow if(units == "minutes" || units == "seconds") { import std.format : format; enum memberVarStr = units[0 .. $ - 1]; value %= 60; mixin(format("auto newVal = cast(ubyte)(_%s) + value;", memberVarStr)); if(value < 0) { if(newVal < 0) newVal += 60; } else if(newVal >= 60) newVal -= 60; mixin(format("_%s = cast(ubyte)newVal;", memberVarStr)); return this; } //Test roll!"minutes"(). unittest { static void testTOD(TimeOfDay orig, int minutes, in TimeOfDay expected, size_t line = __LINE__) { orig.roll!"minutes"(minutes); assert(orig == expected); } testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 31, 33)); testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 32, 33)); testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 33, 33)); testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 34, 33)); testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 35, 33)); testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 40, 33)); testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 45, 33)); testTOD(TimeOfDay(12, 30, 33), 29, TimeOfDay(12, 59, 33)); testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 0, 33)); testTOD(TimeOfDay(12, 30, 33), 45, TimeOfDay(12, 15, 33)); testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), 75, TimeOfDay(12, 45, 33)); testTOD(TimeOfDay(12, 30, 33), 90, TimeOfDay(12, 0, 33)); testTOD(TimeOfDay(12, 30, 33), 100, TimeOfDay(12, 10, 33)); testTOD(TimeOfDay(12, 30, 33), 689, TimeOfDay(12, 59, 33)); testTOD(TimeOfDay(12, 30, 33), 690, TimeOfDay(12, 0, 33)); testTOD(TimeOfDay(12, 30, 33), 691, TimeOfDay(12, 1, 33)); testTOD(TimeOfDay(12, 30, 33), 960, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), 1439, TimeOfDay(12, 29, 33)); testTOD(TimeOfDay(12, 30, 33), 1440, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), 1441, TimeOfDay(12, 31, 33)); testTOD(TimeOfDay(12, 30, 33), 2880, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 29, 33)); testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 28, 33)); testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 27, 33)); testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 26, 33)); testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 25, 33)); testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 20, 33)); testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 15, 33)); testTOD(TimeOfDay(12, 30, 33), -29, TimeOfDay(12, 1, 33)); testTOD(TimeOfDay(12, 30, 33), -30, TimeOfDay(12, 0, 33)); testTOD(TimeOfDay(12, 30, 33), -45, TimeOfDay(12, 45, 33)); testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), -75, TimeOfDay(12, 15, 33)); testTOD(TimeOfDay(12, 30, 33), -90, TimeOfDay(12, 0, 33)); testTOD(TimeOfDay(12, 30, 33), -100, TimeOfDay(12, 50, 33)); testTOD(TimeOfDay(12, 30, 33), -749, TimeOfDay(12, 1, 33)); testTOD(TimeOfDay(12, 30, 33), -750, TimeOfDay(12, 0, 33)); testTOD(TimeOfDay(12, 30, 33), -751, TimeOfDay(12, 59, 33)); testTOD(TimeOfDay(12, 30, 33), -960, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), -1439, TimeOfDay(12, 31, 33)); testTOD(TimeOfDay(12, 30, 33), -1440, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), -1441, TimeOfDay(12, 29, 33)); testTOD(TimeOfDay(12, 30, 33), -2880, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 0, 33), 1, TimeOfDay(12, 1, 33)); testTOD(TimeOfDay(12, 0, 33), 0, TimeOfDay(12, 0, 33)); testTOD(TimeOfDay(12, 0, 33), -1, TimeOfDay(12, 59, 33)); testTOD(TimeOfDay(11, 59, 33), 1, TimeOfDay(11, 0, 33)); testTOD(TimeOfDay(11, 59, 33), 0, TimeOfDay(11, 59, 33)); testTOD(TimeOfDay(11, 59, 33), -1, TimeOfDay(11, 58, 33)); testTOD(TimeOfDay(0, 0, 33), 1, TimeOfDay(0, 1, 33)); testTOD(TimeOfDay(0, 0, 33), 0, TimeOfDay(0, 0, 33)); testTOD(TimeOfDay(0, 0, 33), -1, TimeOfDay(0, 59, 33)); testTOD(TimeOfDay(23, 59, 33), 1, TimeOfDay(23, 0, 33)); testTOD(TimeOfDay(23, 59, 33), 0, TimeOfDay(23, 59, 33)); testTOD(TimeOfDay(23, 59, 33), -1, TimeOfDay(23, 58, 33)); auto tod = TimeOfDay(12, 27, 2); tod.roll!"minutes"(97).roll!"minutes"(-102); assert(tod == TimeOfDay(12, 22, 2)); const ctod = TimeOfDay(0, 0, 0); immutable itod = TimeOfDay(0, 0, 0); static assert(!__traits(compiles, ctod.roll!"minutes"(7))); static assert(!__traits(compiles, itod.roll!"minutes"(7))); } //Test roll!"seconds"(). unittest { static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__) { orig.roll!"seconds"(seconds); assert(orig == expected); } testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 30, 0)); testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 30, 3)); testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 30, 32)); testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 30, 34)); testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 30, 59)); testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(12, 30, 0)); testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(12, 30, 1)); testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(12, 30, 0)); testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(12, 30, 32)); testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(12, 30, 34)); testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 30, 59)); testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 30, 58)); testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 30, 34)); testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 30, 32)); testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 30, 59)); testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(12, 0, 59)); testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(0, 0, 59)); testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(23, 59, 0)); testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); auto tod = TimeOfDay(12, 27, 2); tod.roll!"seconds"(105).roll!"seconds"(-77); assert(tod == TimeOfDay(12, 27, 30)); const ctod = TimeOfDay(0, 0, 0); immutable itod = TimeOfDay(0, 0, 0); static assert(!__traits(compiles, ctod.roll!"seconds"(7))); static assert(!__traits(compiles, itod.roll!"seconds"(7))); } /++ Gives the result of adding or subtracting a $(CXREF time, Duration) from this $(LREF TimeOfDay). The legal types of arithmetic for $(LREF TimeOfDay) using this operator are $(BOOKTABLE, $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) ) Params: duration = The $(CXREF time, Duration) to add to or subtract from this $(LREF TimeOfDay). +/ TimeOfDay opBinary(string op)(Duration duration) @safe const pure nothrow if(op == "+" || op == "-") { TimeOfDay retval = this; immutable seconds = duration.total!"seconds"; mixin("return retval._addSeconds(" ~ op ~ "seconds);"); } /// unittest { assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13)); assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12)); assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12)); assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0)); assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11)); assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12)); assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12)); assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59)); } unittest { auto tod = TimeOfDay(12, 30, 33); assert(tod + dur!"hours"(7) == TimeOfDay(19, 30, 33)); assert(tod + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); assert(tod + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); assert(tod + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); assert(tod + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); assert(tod + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); assert(tod + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); assert(tod + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); assert(tod + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); assert(tod + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); assert(tod + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); assert(tod + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); assert(tod - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); assert(tod - dur!"hours"(7) == TimeOfDay(5, 30, 33)); assert(tod - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); assert(tod - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); assert(tod - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); assert(tod - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); assert(tod - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); assert(tod - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); assert(tod - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); assert(tod - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); assert(tod - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); assert(tod - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); auto duration = dur!"hours"(11); const ctod = TimeOfDay(12, 30, 33); immutable itod = TimeOfDay(12, 30, 33); assert(tod + duration == TimeOfDay(23, 30, 33)); assert(ctod + duration == TimeOfDay(23, 30, 33)); assert(itod + duration == TimeOfDay(23, 30, 33)); assert(tod - duration == TimeOfDay(1, 30, 33)); assert(ctod - duration == TimeOfDay(1, 30, 33)); assert(itod - duration == TimeOfDay(1, 30, 33)); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime) and $(CXREF time, Duration). Use $(D Duration) instead. This overload will be removed in January 2017.) Defines + and - with $(CXREF time, TickDuration). +/ deprecated("Use Duration instead of TickDuration.") TimeOfDay opBinary(string op)(TickDuration td) @safe const pure nothrow if(op == "+" || op == "-") { TimeOfDay retval = this; immutable seconds = td.seconds; mixin("return retval._addSeconds(" ~ op ~ "seconds);"); } deprecated unittest { //This probably only runs in cases where gettimeofday() is used, but it's //hard to do this test correctly with variable ticksPerSec. if(TickDuration.ticksPerSec == 1_000_000) { auto tod = TimeOfDay(12, 30, 33); assert(tod + TickDuration.from!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); assert(tod + TickDuration.from!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); assert(tod - TickDuration.from!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); assert(tod - TickDuration.from!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); } } /++ Gives the result of adding or subtracting a $(CXREF time, Duration) from this $(LREF TimeOfDay), as well as assigning the result to this $(LREF TimeOfDay). The legal types of arithmetic for $(LREF TimeOfDay) using this operator are $(BOOKTABLE, $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) ) Params: duration = The $(CXREF time, Duration) to add to or subtract from this $(LREF TimeOfDay). +/ ref TimeOfDay opOpAssign(string op)(Duration duration) @safe pure nothrow if(op == "+" || op == "-") { immutable seconds = duration.total!"seconds"; mixin("return _addSeconds(" ~ op ~ "seconds);"); } unittest { auto duration = dur!"hours"(12); assert(TimeOfDay(12, 30, 33) + dur!"hours"(7) == TimeOfDay(19, 30, 33)); assert(TimeOfDay(12, 30, 33) + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); assert(TimeOfDay(12, 30, 33) + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); assert(TimeOfDay(12, 30, 33) + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); assert(TimeOfDay(12, 30, 33) + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); assert(TimeOfDay(12, 30, 33) + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); assert(TimeOfDay(12, 30, 33) + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); assert(TimeOfDay(12, 30, 33) + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); assert(TimeOfDay(12, 30, 33) + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); assert(TimeOfDay(12, 30, 33) + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); assert(TimeOfDay(12, 30, 33) - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); assert(TimeOfDay(12, 30, 33) - dur!"hours"(7) == TimeOfDay(5, 30, 33)); assert(TimeOfDay(12, 30, 33) - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); assert(TimeOfDay(12, 30, 33) - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); assert(TimeOfDay(12, 30, 33) - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); assert(TimeOfDay(12, 30, 33) - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); assert(TimeOfDay(12, 30, 33) - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); assert(TimeOfDay(12, 30, 33) - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); assert(TimeOfDay(12, 30, 33) - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); assert(TimeOfDay(12, 30, 33) - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); auto tod = TimeOfDay(19, 17, 22); (tod += dur!"seconds"(9)) += dur!"seconds"(-7292); assert(tod == TimeOfDay(17, 15, 59)); const ctod = TimeOfDay(12, 33, 30); immutable itod = TimeOfDay(12, 33, 30); static assert(!__traits(compiles, ctod += duration)); static assert(!__traits(compiles, itod += duration)); static assert(!__traits(compiles, ctod -= duration)); static assert(!__traits(compiles, itod -= duration)); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime) and $(CXREF time, Duration). Use $(D Duration) instead. This overload will be removed in January 2017.) Defines += and -= with $(CXREF time, TickDuration). +/ deprecated("Use Duration instead of TickDuration.") ref TimeOfDay opOpAssign(string op)(TickDuration td) @safe pure nothrow if(op == "+" || op == "-") { immutable seconds = td.seconds; mixin("return _addSeconds(" ~ op ~ "seconds);"); } deprecated unittest { //This probably only runs in cases where gettimeofday() is used, but it's //hard to do this test correctly with variable ticksPerSec. if(TickDuration.ticksPerSec == 1_000_000) { { auto tod = TimeOfDay(12, 30, 33); tod += TickDuration.from!"usecs"(7_000_000); assert(tod == TimeOfDay(12, 30, 40)); } { auto tod = TimeOfDay(12, 30, 33); tod += TickDuration.from!"usecs"(-7_000_000); assert(tod == TimeOfDay(12, 30, 26)); } { auto tod = TimeOfDay(12, 30, 33); tod -= TickDuration.from!"usecs"(-7_000_000); assert(tod == TimeOfDay(12, 30, 40)); } { auto tod = TimeOfDay(12, 30, 33); tod -= TickDuration.from!"usecs"(7_000_000); assert(tod == TimeOfDay(12, 30, 26)); } } } /++ Gives the difference between two $(LREF TimeOfDay)s. The legal types of arithmetic for $(LREF TimeOfDay) using this operator are $(BOOKTABLE, $(TR $(TD TimeOfDay) $(TD -) $(TD TimeOfDay) $(TD -->) $(TD duration)) ) Params: rhs = The $(LREF TimeOfDay) to subtract from this one. +/ Duration opBinary(string op)(in TimeOfDay rhs) @safe const pure nothrow if(op == "-") { immutable lhsSec = _hour * 3600 + _minute * 60 + _second; immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second; return dur!"seconds"(lhsSec - rhsSec); } unittest { auto tod = TimeOfDay(12, 30, 33); assert(TimeOfDay(7, 12, 52) - TimeOfDay(12, 30, 33) == dur!"seconds"(-19_061)); assert(TimeOfDay(12, 30, 33) - TimeOfDay(7, 12, 52) == dur!"seconds"(19_061)); assert(TimeOfDay(12, 30, 33) - TimeOfDay(14, 30, 33) == dur!"seconds"(-7200)); assert(TimeOfDay(14, 30, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(7200)); assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 34, 33) == dur!"seconds"(-240)); assert(TimeOfDay(12, 34, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(240)); assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 30, 34) == dur!"seconds"(-1)); assert(TimeOfDay(12, 30, 34) - TimeOfDay(12, 30, 33) == dur!"seconds"(1)); const ctod = TimeOfDay(12, 30, 33); immutable itod = TimeOfDay(12, 30, 33); assert(tod - tod == Duration.zero); assert(ctod - tod == Duration.zero); assert(itod - tod == Duration.zero); assert(tod - ctod == Duration.zero); assert(ctod - ctod == Duration.zero); assert(itod - ctod == Duration.zero); assert(tod - itod == Duration.zero); assert(ctod - itod == Duration.zero); assert(itod - itod == Duration.zero); } /++ Converts this $(LREF TimeOfDay) to a string with the format HHMMSS. +/ string toISOString() @safe const pure nothrow { import std.format : format; try return format("%02d%02d%02d", _hour, _minute, _second); catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(TimeOfDay(0, 0, 0).toISOString() == "000000"); assert(TimeOfDay(12, 30, 33).toISOString() == "123033"); } unittest { auto tod = TimeOfDay(12, 30, 33); const ctod = TimeOfDay(12, 30, 33); immutable itod = TimeOfDay(12, 30, 33); assert(tod.toISOString() == "123033"); assert(ctod.toISOString() == "123033"); assert(itod.toISOString() == "123033"); } /++ Converts this $(LREF TimeOfDay) to a string with the format HH:MM:SS. +/ string toISOExtString() @safe const pure nothrow { import std.format : format; try return format("%02d:%02d:%02d", _hour, _minute, _second); catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00"); assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33"); } unittest { auto tod = TimeOfDay(12, 30, 33); const ctod = TimeOfDay(12, 30, 33); immutable itod = TimeOfDay(12, 30, 33); assert(tod.toISOExtString() == "12:30:33"); assert(ctod.toISOExtString() == "12:30:33"); assert(itod.toISOExtString() == "12:30:33"); } /++ Converts this TimeOfDay to a string. +/ string toString() @safe const pure nothrow { return toISOExtString(); } unittest { auto tod = TimeOfDay(12, 30, 33); const ctod = TimeOfDay(12, 30, 33); immutable itod = TimeOfDay(12, 30, 33); assert(tod.toString()); assert(ctod.toString()); assert(itod.toString()); } /++ Creates a $(LREF TimeOfDay) from a string with the format HHMMSS. Whitespace is stripped from the given string. Params: isoString = A string formatted in the ISO format for times. Throws: $(LREF DateTimeException) if the given string is not in the ISO format or if the resulting $(LREF TimeOfDay) would not be valid. +/ static TimeOfDay fromISOString(S)(in S isoString) @safe pure if(isSomeString!S) { import std.ascii : isDigit; import std.string : strip; import std.conv : to; import std.algorithm : all; import std.format : format; auto dstr = to!dstring(strip(isoString)); enforce(dstr.length == 6, new DateTimeException(format("Invalid ISO String: %s", isoString))); auto hours = dstr[0 .. 2]; auto minutes = dstr[2 .. 4]; auto seconds = dstr[4 .. $]; enforce(all!isDigit(hours), new DateTimeException(format("Invalid ISO String: %s", isoString))); enforce(all!isDigit(minutes), new DateTimeException(format("Invalid ISO String: %s", isoString))); enforce(all!isDigit(seconds), new DateTimeException(format("Invalid ISO String: %s", isoString))); return TimeOfDay(to!int(hours), to!int(minutes), to!int(seconds)); } /// unittest { assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0)); assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33)); assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33)); } unittest { assertThrown!DateTimeException(TimeOfDay.fromISOString("")); assertThrown!DateTimeException(TimeOfDay.fromISOString("0")); assertThrown!DateTimeException(TimeOfDay.fromISOString("00")); assertThrown!DateTimeException(TimeOfDay.fromISOString("000")); assertThrown!DateTimeException(TimeOfDay.fromISOString("0000")); assertThrown!DateTimeException(TimeOfDay.fromISOString("00000")); assertThrown!DateTimeException(TimeOfDay.fromISOString("13033")); assertThrown!DateTimeException(TimeOfDay.fromISOString("1277")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12707")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12070")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12303a")); assertThrown!DateTimeException(TimeOfDay.fromISOString("1230a3")); assertThrown!DateTimeException(TimeOfDay.fromISOString("123a33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12a033")); assertThrown!DateTimeException(TimeOfDay.fromISOString("1a0033")); assertThrown!DateTimeException(TimeOfDay.fromISOString("a20033")); assertThrown!DateTimeException(TimeOfDay.fromISOString("1200330")); assertThrown!DateTimeException(TimeOfDay.fromISOString("0120033")); assertThrown!DateTimeException(TimeOfDay.fromISOString("-120033")); assertThrown!DateTimeException(TimeOfDay.fromISOString("+120033")); assertThrown!DateTimeException(TimeOfDay.fromISOString("120033am")); assertThrown!DateTimeException(TimeOfDay.fromISOString("120033pm")); assertThrown!DateTimeException(TimeOfDay.fromISOString("0::")); assertThrown!DateTimeException(TimeOfDay.fromISOString(":0:")); assertThrown!DateTimeException(TimeOfDay.fromISOString("::0")); assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:0")); assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:00")); assertThrown!DateTimeException(TimeOfDay.fromISOString("0:00:0")); assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:0")); assertThrown!DateTimeException(TimeOfDay.fromISOString("00:00:0")); assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:00")); assertThrown!DateTimeException(TimeOfDay.fromISOString("13:0:33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:7")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:07")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:07:0")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:3a")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:a3")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:3a:33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:a0:33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("1a:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("a2:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:003:30")); assertThrown!DateTimeException(TimeOfDay.fromISOString("120:03:30")); assertThrown!DateTimeException(TimeOfDay.fromISOString("012:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("01:200:33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("-12:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("+12:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33am")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33pm")); assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33")); assert(TimeOfDay.fromISOString("011217") == TimeOfDay(1, 12, 17)); assert(TimeOfDay.fromISOString("001412") == TimeOfDay(0, 14, 12)); assert(TimeOfDay.fromISOString("000007") == TimeOfDay(0, 0, 7)); assert(TimeOfDay.fromISOString("011217 ") == TimeOfDay(1, 12, 17)); assert(TimeOfDay.fromISOString(" 011217") == TimeOfDay(1, 12, 17)); assert(TimeOfDay.fromISOString(" 011217 ") == TimeOfDay(1, 12, 17)); } /++ Creates a $(LREF TimeOfDay) from a string with the format HH:MM:SS. Whitespace is stripped from the given string. Params: isoExtString = A string formatted in the ISO Extended format for times. Throws: $(LREF DateTimeException) if the given string is not in the ISO Extended format or if the resulting $(LREF TimeOfDay) would not be valid. +/ static TimeOfDay fromISOExtString(S)(in S isoExtString) @safe pure if(isSomeString!S) { import std.ascii : isDigit; import std.string : strip; import std.conv : to; import std.algorithm : all; import std.format : format; auto dstr = to!dstring(strip(isoExtString)); enforce(dstr.length == 8, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); auto hours = dstr[0 .. 2]; auto minutes = dstr[3 .. 5]; auto seconds = dstr[6 .. $]; enforce(dstr[2] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); enforce(dstr[5] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); enforce(all!isDigit(hours), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); enforce(all!isDigit(minutes), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); enforce(all!isDigit(seconds), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); return TimeOfDay(to!int(hours), to!int(minutes), to!int(seconds)); } /// unittest { assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0)); assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33)); assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33)); } unittest { assertThrown!DateTimeException(TimeOfDay.fromISOExtString("")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("000")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0000")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00000")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13033")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1277")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12707")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12070")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12303a")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1230a3")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("123a33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12a033")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a0033")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a20033")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1200330")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0120033")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-120033")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+120033")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033am")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033pm")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0::")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString(":0:")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("::0")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:0")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:00")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:00:0")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:0")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:00:0")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:00")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13:0:33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:7")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:07")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:07:0")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:3a")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:a3")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:3a:33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:a0:33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a2:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:003:30")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120:03:30")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("012:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("01:200:33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-12:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+12:00:33")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33am")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33pm")); assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033")); assert(TimeOfDay.fromISOExtString("01:12:17") == TimeOfDay(1, 12, 17)); assert(TimeOfDay.fromISOExtString("00:14:12") == TimeOfDay(0, 14, 12)); assert(TimeOfDay.fromISOExtString("00:00:07") == TimeOfDay(0, 0, 7)); assert(TimeOfDay.fromISOExtString("01:12:17 ") == TimeOfDay(1, 12, 17)); assert(TimeOfDay.fromISOExtString(" 01:12:17") == TimeOfDay(1, 12, 17)); assert(TimeOfDay.fromISOExtString(" 01:12:17 ") == TimeOfDay(1, 12, 17)); } /++ Returns midnight. +/ @property static TimeOfDay min() @safe pure nothrow { return TimeOfDay.init; } unittest { assert(TimeOfDay.min.hour == 0); assert(TimeOfDay.min.minute == 0); assert(TimeOfDay.min.second == 0); assert(TimeOfDay.min < TimeOfDay.max); } /++ Returns one second short of midnight. +/ @property static TimeOfDay max() @safe pure nothrow { auto tod = TimeOfDay.init; tod._hour = maxHour; tod._minute = maxMinute; tod._second = maxSecond; return tod; } unittest { assert(TimeOfDay.max.hour == 23); assert(TimeOfDay.max.minute == 59); assert(TimeOfDay.max.second == 59); assert(TimeOfDay.max > TimeOfDay.min); } private: /+ Add seconds to the time of day. Negative values will subtract. If the number of seconds overflows (or underflows), then the seconds will wrap, increasing (or decreasing) the number of minutes accordingly. If the number of minutes overflows (or underflows), then the minutes will wrap. If the number of minutes overflows(or underflows), then the hour will wrap. (e.g. adding 90 seconds to 23:59:00 would result in 00:00:30). Params: seconds = The number of seconds to add to this TimeOfDay. +/ ref TimeOfDay _addSeconds(long seconds) return @safe pure nothrow { long hnsecs = convert!("seconds", "hnsecs")(seconds); hnsecs += convert!("hours", "hnsecs")(_hour); hnsecs += convert!("minutes", "hnsecs")(_minute); hnsecs += convert!("seconds", "hnsecs")(_second); hnsecs %= convert!("days", "hnsecs")(1); if(hnsecs < 0) hnsecs += convert!("days", "hnsecs")(1); immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); _hour = cast(ubyte)newHours; _minute = cast(ubyte)newMinutes; _second = cast(ubyte)newSeconds; return this; } unittest { static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__) { orig._addSeconds(seconds); assert(orig == expected); } testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 31, 0)); testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 31, 3)); testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 31, 32)); testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 31, 33)); testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 31, 34)); testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 59, 59)); testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(13, 0, 0)); testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(13, 0, 1)); testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(13, 4, 0)); testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(13, 30, 32)); testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(13, 30, 33)); testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(13, 30, 34)); testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(14, 30, 33)); testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 29, 59)); testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 29, 58)); testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 29, 34)); testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 29, 33)); testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 29, 32)); testTOD(TimeOfDay(12, 30, 33), -1833, TimeOfDay(12, 0, 0)); testTOD(TimeOfDay(12, 30, 33), -1834, TimeOfDay(11, 59, 59)); testTOD(TimeOfDay(12, 30, 33), -3600, TimeOfDay(11, 30, 33)); testTOD(TimeOfDay(12, 30, 33), -3601, TimeOfDay(11, 30, 32)); testTOD(TimeOfDay(12, 30, 33), -5134, TimeOfDay(11, 4, 59)); testTOD(TimeOfDay(12, 30, 33), -7200, TimeOfDay(10, 30, 33)); testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 29, 59)); testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(11, 59, 59)); testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(23, 59, 59)); testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(0, 0, 0)); testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); const ctod = TimeOfDay(0, 0, 0); immutable itod = TimeOfDay(0, 0, 0); static assert(!__traits(compiles, ctod._addSeconds(7))); static assert(!__traits(compiles, itod._addSeconds(7))); } /+ Whether the given values form a valid $(LREF TimeOfDay). +/ static bool _valid(int hour, int minute, int second) @safe pure nothrow { return valid!"hours"(hour) && valid!"minutes"(minute) && valid!"seconds"(second); } @safe pure invariant() { import std.format : format; assert(_valid(_hour, _minute, _second), format("Invariant Failure: hour [%s] minute [%s] second [%s]", _hour, _minute, _second)); } ubyte _hour; ubyte _minute; ubyte _second; enum ubyte maxHour = 24 - 1; enum ubyte maxMinute = 60 - 1; enum ubyte maxSecond = 60 - 1; } /++ Combines the $(LREF Date) and $(LREF TimeOfDay) structs to give an object which holds both the date and the time. It is optimized for calendar-based operations and has no concept of time zone. For an object which is optimized for time operations based on the system time, use $(LREF SysTime). $(LREF SysTime) has a concept of time zone and has much higher precision (hnsecs). $(D DateTime) is intended primarily for calendar-based uses rather than precise time operations. +/ struct DateTime { public: /++ Params: date = The date portion of $(LREF DateTime). tod = The time portion of $(LREF DateTime). +/ this(in Date date, in TimeOfDay tod = TimeOfDay.init) @safe pure nothrow { _date = date; _tod = tod; } unittest { { auto dt = DateTime.init; assert(dt._date == Date.init); assert(dt._tod == TimeOfDay.init); } { auto dt = DateTime(Date(1999, 7 ,6)); assert(dt._date == Date(1999, 7, 6)); assert(dt._tod == TimeOfDay.init); } { auto dt = DateTime(Date(1999, 7 ,6), TimeOfDay(12, 30, 33)); assert(dt._date == Date(1999, 7, 6)); assert(dt._tod == TimeOfDay(12, 30, 33)); } } /++ Params: year = The year portion of the date. month = The month portion of the date. day = The day portion of the date. hour = The hour portion of the time; minute = The minute portion of the time; second = The second portion of the time; +/ this(int year, int month, int day, int hour = 0, int minute = 0, int second = 0) @safe pure { _date = Date(year, month, day); _tod = TimeOfDay(hour, minute, second); } unittest { { auto dt = DateTime(1999, 7 ,6); assert(dt._date == Date(1999, 7, 6)); assert(dt._tod == TimeOfDay.init); } { auto dt = DateTime(1999, 7 ,6, 12, 30, 33); assert(dt._date == Date(1999, 7, 6)); assert(dt._tod == TimeOfDay(12, 30, 33)); } } /++ Compares this $(LREF DateTime) with the given $(D DateTime.). Returns: $(BOOKTABLE, $(TR $(TD this < rhs) $(TD < 0)) $(TR $(TD this == rhs) $(TD 0)) $(TR $(TD this > rhs) $(TD > 0)) ) +/ int opCmp(in DateTime rhs) @safe const pure nothrow { immutable dateResult = _date.opCmp(rhs._date); if(dateResult != 0) return dateResult; return _tod.opCmp(rhs._tod); } unittest { //Test A.D. assert(DateTime(Date.init, TimeOfDay.init).opCmp(DateTime.init) == 0); assert(DateTime(Date(1999, 1, 1)).opCmp(DateTime(Date(1999, 1, 1))) == 0); assert(DateTime(Date(1, 7, 1)).opCmp(DateTime(Date(1, 7, 1))) == 0); assert(DateTime(Date(1, 1, 6)).opCmp(DateTime(Date(1, 1, 6))) == 0); assert(DateTime(Date(1999, 7, 1)).opCmp(DateTime(Date(1999, 7, 1))) == 0); assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) == 0); assert(DateTime(Date(1, 7, 6)).opCmp(DateTime(Date(1, 7, 6))) == 0); assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(2000, 7, 6))) < 0); assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0); assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 8, 6))) < 0); assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0); assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) < 0); assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 7, 6))) > 0); assert(DateTime(Date(1999, 8, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0); assert(DateTime(Date(2000, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0); assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0); assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0); assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 8, 6))) < 0); assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))) == 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))) == 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0))) == 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))) == 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) == 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))) == 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( DateTime(Date(1999, 7, 7), TimeOfDay(12, 31, 33))) < 0); assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); //Test B.C. assert(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33))) == 0); assert(DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))) == 0); assert(DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33))) == 0); assert(DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33))) == 0); assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) == 0); assert(DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33))) == 0); assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(-2000, 8, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0); //Test Both assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33))) > 0); assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(1999, 6, 6), TimeOfDay(12, 30, 33))) < 0); assert(DateTime(Date(1999, 6, 8), TimeOfDay(12, 30, 33)).opCmp( DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30)); assert(dt.opCmp(dt) == 0); assert(dt.opCmp(cdt) == 0); assert(dt.opCmp(idt) == 0); assert(cdt.opCmp(dt) == 0); assert(cdt.opCmp(cdt) == 0); assert(cdt.opCmp(idt) == 0); assert(idt.opCmp(dt) == 0); assert(idt.opCmp(cdt) == 0); assert(idt.opCmp(idt) == 0); } /++ The date portion of $(LREF DateTime). +/ @property Date date() @safe const pure nothrow { return _date; } unittest { { auto dt = DateTime.init; assert(dt.date == Date.init); } { auto dt = DateTime(Date(1999, 7, 6)); assert(dt.date == Date(1999, 7, 6)); } const cdt = DateTime(1999, 7, 6); immutable idt = DateTime(1999, 7, 6); assert(cdt.date == Date(1999, 7, 6)); assert(idt.date == Date(1999, 7, 6)); } /++ The date portion of $(LREF DateTime). Params: date = The Date to set this $(LREF DateTime)'s date portion to. +/ @property void date(in Date date) @safe pure nothrow { _date = date; } unittest { auto dt = DateTime.init; dt.date = Date(1999, 7, 6); assert(dt._date == Date(1999, 7, 6)); assert(dt._tod == TimeOfDay.init); const cdt = DateTime(1999, 7, 6); immutable idt = DateTime(1999, 7, 6); static assert(!__traits(compiles, cdt.date = Date(2010, 1, 1))); static assert(!__traits(compiles, idt.date = Date(2010, 1, 1))); } /++ The time portion of $(LREF DateTime). +/ @property TimeOfDay timeOfDay() @safe const pure nothrow { return _tod; } unittest { { auto dt = DateTime.init; assert(dt.timeOfDay == TimeOfDay.init); } { auto dt = DateTime(Date.init, TimeOfDay(12, 30, 33)); assert(dt.timeOfDay == TimeOfDay(12, 30, 33)); } const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(cdt.timeOfDay == TimeOfDay(12, 30, 33)); assert(idt.timeOfDay == TimeOfDay(12, 30, 33)); } /++ The time portion of $(LREF DateTime). Params: tod = The $(LREF TimeOfDay) to set this $(LREF DateTime)'s time portion to. +/ @property void timeOfDay(in TimeOfDay tod) @safe pure nothrow { _tod = tod; } unittest { auto dt = DateTime.init; dt.timeOfDay = TimeOfDay(12, 30, 33); assert(dt._date == Date.init); assert(dt._tod == TimeOfDay(12, 30, 33)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.timeOfDay = TimeOfDay(12, 30, 33))); static assert(!__traits(compiles, idt.timeOfDay = TimeOfDay(12, 30, 33))); } /++ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C. +/ @property short year() @safe const pure nothrow { return _date.year; } unittest { assert(Date.init.year == 1); assert(Date(1999, 7, 6).year == 1999); assert(Date(-1999, 7, 6).year == -1999); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(idt.year == 1999); assert(idt.year == 1999); } /++ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C. Params: year = The year to set this $(LREF DateTime)'s year to. Throws: $(LREF DateTimeException) if the new year is not a leap year and if the resulting date would be on February 29th. +/ @property void year(int year) @safe pure { _date.year = year; } /// unittest { assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).year == 1999); assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).year == 2010); assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).year == -7); } unittest { static void testDT(DateTime dt, int year, in DateTime expected, size_t line = __LINE__) { dt.year = year; assert(dt == expected); } testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), 1999, DateTime(Date(1999, 1, 1), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), 0, DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), -1999, DateTime(Date(-1999, 1, 1), TimeOfDay(12, 30, 33))); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.year = 7)); static assert(!__traits(compiles, idt.year = 7)); } /++ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. Throws: $(LREF DateTimeException) if $(D isAD) is true. +/ @property short yearBC() @safe const pure { return _date.yearBC; } /// unittest { assert(DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)).yearBC == 1); assert(DateTime(Date(-1, 1, 1), TimeOfDay(10, 7, 2)).yearBC == 2); assert(DateTime(Date(-100, 1, 1), TimeOfDay(4, 59, 0)).yearBC == 101); } unittest { assertThrown!DateTimeException((in DateTime dt){dt.yearBC;}(DateTime(Date(1, 1, 1)))); auto dt = DateTime(1999, 7, 6, 12, 30, 33); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); dt.yearBC = 12; assert(dt.yearBC == 12); static assert(!__traits(compiles, cdt.yearBC = 12)); static assert(!__traits(compiles, idt.yearBC = 12)); } /++ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. Params: year = The year B.C. to set this $(LREF DateTime)'s year to. Throws: $(LREF DateTimeException) if a non-positive value is given. +/ @property void yearBC(int year) @safe pure { _date.yearBC = year; } /// unittest { auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(7, 30, 0)); dt.yearBC = 1; assert(dt == DateTime(Date(0, 1, 1), TimeOfDay(7, 30, 0))); dt.yearBC = 10; assert(dt == DateTime(Date(-9, 1, 1), TimeOfDay(7, 30, 0))); } unittest { assertThrown!DateTimeException((DateTime dt){dt.yearBC = -1;}(DateTime(Date(1, 1, 1)))); auto dt = DateTime(1999, 7, 6, 12, 30, 33); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); dt.yearBC = 12; assert(dt.yearBC == 12); static assert(!__traits(compiles, cdt.yearBC = 12)); static assert(!__traits(compiles, idt.yearBC = 12)); } /++ Month of a Gregorian Year. +/ @property Month month() @safe const pure nothrow { return _date.month; } /// unittest { assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).month == 7); assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).month == 10); assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).month == 4); } unittest { assert(DateTime.init.month == 1); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).month == 7); assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).month == 7); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(cdt.month == 7); assert(idt.month == 7); } /++ Month of a Gregorian Year. Params: month = The month to set this $(LREF DateTime)'s month to. Throws: $(LREF DateTimeException) if the given month is not a valid month. +/ @property void month(Month month) @safe pure { _date.month = month; } unittest { static void testDT(DateTime dt, Month month, in DateTime expected = DateTime.init, size_t line = __LINE__) { dt.month = month; assert(expected != DateTime.init); assert(dt == expected); } assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month)0)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month)13)); testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month)7, DateTime(Date(1, 7, 1), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month)7, DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.month = 12)); static assert(!__traits(compiles, idt.month = 12)); } /++ Day of a Gregorian Month. +/ @property ubyte day() @safe const pure nothrow { return _date.day; } /// unittest { assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).day == 6); assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).day == 4); assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).day == 5); } unittest { import std.range; import std.format : format; static void test(DateTime dateTime, int expected) { assert(dateTime.day == expected, format("Value given: %s", dateTime)); } foreach(year; chain(testYearsBC, testYearsAD)) { foreach(md; testMonthDays) { foreach(tod; testTODs) test(DateTime(Date(year, md.month, md.day), tod), md.day); } } const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(cdt.day == 6); assert(idt.day == 6); } /++ Day of a Gregorian Month. Params: day = The day of the month to set this $(LREF DateTime)'s day to. Throws: $(LREF DateTimeException) if the given day is not a valid day of the current month. +/ @property void day(int day) @safe pure { _date.day = day; } unittest { static void testDT(DateTime dt, int day) { dt.day = day; } //Test A.D. assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 0)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 29)); assertThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 30)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 31)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 31)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 31)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 31)); assertThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 32)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 28)); assertNotThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 29)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 30)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 30)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 30)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 30)); assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 31)); { auto dt = DateTime(Date(1, 1, 1), TimeOfDay(7, 12, 22)); dt.day = 6; assert(dt == DateTime(Date(1, 1, 6), TimeOfDay(7, 12, 22))); } //Test B.C. assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 0)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 29)); assertThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 30)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 31)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 31)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 31)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 32)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 31)); assertThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 32)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 28)); assertNotThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 29)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 30)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 30)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 30)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 31)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 30)); assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 31)); auto dt = DateTime(Date(-1, 1, 1), TimeOfDay(7, 12, 22)); dt.day = 6; assert(dt == DateTime(Date(-1, 1, 6), TimeOfDay(7, 12, 22))); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.day = 27)); static assert(!__traits(compiles, idt.day = 27)); } /++ Hours past midnight. +/ @property ubyte hour() @safe const pure nothrow { return _tod.hour; } unittest { assert(DateTime.init.hour == 0); assert(DateTime(Date.init, TimeOfDay(12, 0, 0)).hour == 12); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(cdt.hour == 12); assert(idt.hour == 12); } /++ Hours past midnight. Params: hour = The hour of the day to set this $(LREF DateTime)'s hour to. Throws: $(LREF DateTimeException) if the given hour would result in an invalid $(LREF DateTime). +/ @property void hour(int hour) @safe pure { _tod.hour = hour; } unittest { assertThrown!DateTimeException((){DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).hour = 24;}()); auto dt = DateTime.init; dt.hour = 12; assert(dt == DateTime(1, 1, 1, 12, 0, 0)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.hour = 27)); static assert(!__traits(compiles, idt.hour = 27)); } /++ Minutes past the hour. +/ @property ubyte minute() @safe const pure nothrow { return _tod.minute; } unittest { assert(DateTime.init.minute == 0); assert(DateTime(1, 1, 1, 0, 30, 0).minute == 30); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(cdt.minute == 30); assert(idt.minute == 30); } /++ Minutes past the hour. Params: minute = The minute to set this $(LREF DateTime)'s minute to. Throws: $(LREF DateTimeException) if the given minute would result in an invalid $(LREF DateTime). +/ @property void minute(int minute) @safe pure { _tod.minute = minute; } unittest { assertThrown!DateTimeException((){DateTime.init.minute = 60;}()); auto dt = DateTime.init; dt.minute = 30; assert(dt == DateTime(1, 1, 1, 0, 30, 0)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.minute = 27)); static assert(!__traits(compiles, idt.minute = 27)); } /++ Seconds past the minute. +/ @property ubyte second() @safe const pure nothrow { return _tod.second; } unittest { assert(DateTime.init.second == 0); assert(DateTime(1, 1, 1, 0, 0, 33).second == 33); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(cdt.second == 33); assert(idt.second == 33); } /++ Seconds past the minute. Params: second = The second to set this $(LREF DateTime)'s second to. Throws: $(LREF DateTimeException) if the given seconds would result in an invalid $(LREF DateTime). +/ @property void second(int second) @safe pure { _tod.second = second; } unittest { assertThrown!DateTimeException((){DateTime.init.second = 60;}()); auto dt = DateTime.init; dt.second = 33; assert(dt == DateTime(1, 1, 1, 0, 0, 33)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.second = 27)); static assert(!__traits(compiles, idt.second = 27)); } /++ Adds the given number of years or months to this $(LREF DateTime). A negative number will subtract. Note that if day overflow is allowed, and the date with the adjusted year/month overflows the number of days in the new month, then the month will be incremented by one, and the day set to the number of days overflowed. (e.g. if the day were 31 and the new month were June, then the month would be incremented to July, and the new day would be 1). If day overflow is not allowed, then the day will be set to the last valid day in the month (e.g. June 31st would become June 30th). Params: units = The type of units to add ("years" or "months"). value = The number of months or years to add to this $(LREF DateTime). allowOverflow = Whether the days should be allowed to overflow, causing the month to increment. +/ ref DateTime add(string units) (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow if(units == "years" || units == "months") { _date.add!units(value, allowOverflow); return this; } /// unittest { auto dt1 = DateTime(2010, 1, 1, 12, 30, 33); dt1.add!"months"(11); assert(dt1 == DateTime(2010, 12, 1, 12, 30, 33)); auto dt2 = DateTime(2010, 1, 1, 12, 30, 33); dt2.add!"months"(-11); assert(dt2 == DateTime(2009, 2, 1, 12, 30, 33)); auto dt3 = DateTime(2000, 2, 29, 12, 30, 33); dt3.add!"years"(1); assert(dt3 == DateTime(2001, 3, 1, 12, 30, 33)); auto dt4 = DateTime(2000, 2, 29, 12, 30, 33); dt4.add!"years"(1, AllowDayOverflow.no); assert(dt4 == DateTime(2001, 2, 28, 12, 30, 33)); } unittest { auto dt = DateTime(2000, 1, 31); dt.add!"years"(7).add!"months"(-4); assert(dt == DateTime(2006, 10, 1)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.add!"years"(4))); static assert(!__traits(compiles, idt.add!"years"(4))); static assert(!__traits(compiles, cdt.add!"months"(4))); static assert(!__traits(compiles, idt.add!"months"(4))); } /++ Adds the given number of years or months to this $(LREF DateTime). A negative number will subtract. The difference between rolling and adding is that rolling does not affect larger units. Rolling a $(LREF DateTime) 12 months gets the exact same $(LREF DateTime). However, the days can still be affected due to the differing number of days in each month. Because there are no units larger than years, there is no difference between adding and rolling years. Params: units = The type of units to add ("years" or "months"). value = The number of months or years to add to this $(LREF DateTime). allowOverflow = Whether the days should be allowed to overflow, causing the month to increment. +/ ref DateTime roll(string units) (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow if(units == "years" || units == "months") { _date.roll!units(value, allowOverflow); return this; } /// unittest { auto dt1 = DateTime(2010, 1, 1, 12, 33, 33); dt1.roll!"months"(1); assert(dt1 == DateTime(2010, 2, 1, 12, 33, 33)); auto dt2 = DateTime(2010, 1, 1, 12, 33, 33); dt2.roll!"months"(-1); assert(dt2 == DateTime(2010, 12, 1, 12, 33, 33)); auto dt3 = DateTime(1999, 1, 29, 12, 33, 33); dt3.roll!"months"(1); assert(dt3 == DateTime(1999, 3, 1, 12, 33, 33)); auto dt4 = DateTime(1999, 1, 29, 12, 33, 33); dt4.roll!"months"(1, AllowDayOverflow.no); assert(dt4 == DateTime(1999, 2, 28, 12, 33, 33)); auto dt5 = DateTime(2000, 2, 29, 12, 30, 33); dt5.roll!"years"(1); assert(dt5 == DateTime(2001, 3, 1, 12, 30, 33)); auto dt6 = DateTime(2000, 2, 29, 12, 30, 33); dt6.roll!"years"(1, AllowDayOverflow.no); assert(dt6 == DateTime(2001, 2, 28, 12, 30, 33)); } unittest { auto dt = DateTime(2000, 1, 31); dt.roll!"years"(7).roll!"months"(-4); assert(dt == DateTime(2007, 10, 1)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.roll!"years"(4))); static assert(!__traits(compiles, idt.roll!"years"(4))); static assert(!__traits(compiles, cdt.roll!"months"(4))); static assert(!__traits(compiles, idt.roll!"months"(4))); } /++ Adds the given number of units to this $(LREF DateTime). A negative number will subtract. The difference between rolling and adding is that rolling does not affect larger units. For instance, rolling a $(LREF DateTime) one year's worth of days gets the exact same $(LREF DateTime). Accepted units are $(D "days"), $(D "minutes"), $(D "hours"), $(D "minutes"), and $(D "seconds"). Params: units = The units to add. value = The number of $(D_PARAM units) to add to this $(LREF DateTime). +/ ref DateTime roll(string units)(long value) @safe pure nothrow if(units == "days") { _date.roll!"days"(value); return this; } /// unittest { auto dt1 = DateTime(2010, 1, 1, 11, 23, 12); dt1.roll!"days"(1); assert(dt1 == DateTime(2010, 1, 2, 11, 23, 12)); dt1.roll!"days"(365); assert(dt1 == DateTime(2010, 1, 26, 11, 23, 12)); dt1.roll!"days"(-32); assert(dt1 == DateTime(2010, 1, 25, 11, 23, 12)); auto dt2 = DateTime(2010, 7, 4, 12, 0, 0); dt2.roll!"hours"(1); assert(dt2 == DateTime(2010, 7, 4, 13, 0, 0)); auto dt3 = DateTime(2010, 1, 1, 0, 0, 0); dt3.roll!"seconds"(-1); assert(dt3 == DateTime(2010, 1, 1, 0, 0, 59)); } unittest { auto dt = DateTime(2000, 1, 31); dt.roll!"days"(7).roll!"days"(-4); assert(dt == DateTime(2000, 1, 3)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.roll!"days"(4))); static assert(!__traits(compiles, idt.roll!"days"(4))); } //Shares documentation with "days" version. ref DateTime roll(string units)(long value) @safe pure nothrow if(units == "hours" || units == "minutes" || units == "seconds") { _tod.roll!units(value); return this; } //Test roll!"hours"(). unittest { static void testDT(DateTime orig, int hours, in DateTime expected, size_t line = __LINE__) { orig.roll!"hours"(hours); assert(orig == expected); } //Test A.D. testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 6, DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7, DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 8, DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 9, DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 11, DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 12, DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 13, DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 14, DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 16, DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 17, DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 18, DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 19, DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 20, DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 21, DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 22, DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 23, DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 24, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 25, DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -6, DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -7, DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -8, DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -9, DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -11, DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -12, DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -13, DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -14, DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -16, DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -17, DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -18, DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -19, DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -20, DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -21, DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -22, DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -23, DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -24, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -25, DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33))); testDT(DateTime(Date(1999, 7, 31), TimeOfDay(23, 30, 33)), 1, DateTime(Date(1999, 7, 31), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(1999, 8, 1), TimeOfDay(0, 30, 33)), -1, DateTime(Date(1999, 8, 1), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(1999, 12, 31), TimeOfDay(23, 30, 33)), 1, DateTime(Date(1999, 12, 31), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(2000, 1, 1), TimeOfDay(0, 30, 33)), -1, DateTime(Date(2000, 1, 1), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(1999, 2, 28), TimeOfDay(23, 30, 33)), 25, DateTime(Date(1999, 2, 28), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(1999, 3, 2), TimeOfDay(0, 30, 33)), -25, DateTime(Date(1999, 3, 2), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(2000, 2, 28), TimeOfDay(23, 30, 33)), 25, DateTime(Date(2000, 2, 28), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(2000, 3, 1), TimeOfDay(0, 30, 33)), -25, DateTime(Date(2000, 3, 1), TimeOfDay(23, 30, 33))); //Test B.C. testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 6, DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7, DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 8, DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 9, DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 11, DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 12, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 13, DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 14, DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 16, DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 17, DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 18, DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 19, DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 20, DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 21, DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 22, DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 23, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 24, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 25, DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -6, DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -7, DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -8, DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -9, DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -11, DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -12, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -13, DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -14, DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -16, DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -17, DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -18, DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -19, DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -20, DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -21, DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -22, DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -23, DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -24, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -25, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33))); testDT(DateTime(Date(-1999, 7, 31), TimeOfDay(23, 30, 33)), 1, DateTime(Date(-1999, 7, 31), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(-1999, 8, 1), TimeOfDay(0, 30, 33)), -1, DateTime(Date(-1999, 8, 1), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(-2001, 12, 31), TimeOfDay(23, 30, 33)), 1, DateTime(Date(-2001, 12, 31), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(-2000, 1, 1), TimeOfDay(0, 30, 33)), -1, DateTime(Date(-2000, 1, 1), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(-2001, 2, 28), TimeOfDay(23, 30, 33)), 25, DateTime(Date(-2001, 2, 28), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(-2001, 3, 2), TimeOfDay(0, 30, 33)), -25, DateTime(Date(-2001, 3, 2), TimeOfDay(23, 30, 33))); testDT(DateTime(Date(-2000, 2, 28), TimeOfDay(23, 30, 33)), 25, DateTime(Date(-2000, 2, 28), TimeOfDay(0, 30, 33))); testDT(DateTime(Date(-2000, 3, 1), TimeOfDay(0, 30, 33)), -25, DateTime(Date(-2000, 3, 1), TimeOfDay(23, 30, 33))); //Test Both testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 17_546, DateTime(Date(-1, 1, 1), TimeOfDay(13, 30, 33))); testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -17_546, DateTime(Date(1, 1, 1), TimeOfDay(11, 30, 33))); auto dt = DateTime(2000, 1, 31, 9, 7, 6); dt.roll!"hours"(27).roll!"hours"(-9); assert(dt == DateTime(2000, 1, 31, 3, 7, 6)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.roll!"hours"(4))); static assert(!__traits(compiles, idt.roll!"hours"(4))); } //Test roll!"minutes"(). unittest { static void testDT(DateTime orig, int minutes, in DateTime expected, size_t line = __LINE__) { orig.roll!"minutes"(minutes); assert(orig == expected); } //Test A.D. testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(1999, 7, 6), TimeOfDay(12, 32, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(1999, 7, 6), TimeOfDay(12, 34, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(1999, 7, 6), TimeOfDay(12, 35, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(1999, 7, 6), TimeOfDay(12, 40, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 29, DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 45, DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 75, DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 90, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 100, DateTime(Date(1999, 7, 6), TimeOfDay(12, 10, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 689, DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 690, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 691, DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 960, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1439, DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1440, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1441, DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2880, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(1999, 7, 6), TimeOfDay(12, 28, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(1999, 7, 6), TimeOfDay(12, 27, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(1999, 7, 6), TimeOfDay(12, 26, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(1999, 7, 6), TimeOfDay(12, 25, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(1999, 7, 6), TimeOfDay(12, 20, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -29, DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -30, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -45, DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -75, DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -90, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -100, DateTime(Date(1999, 7, 6), TimeOfDay(12, 50, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -749, DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -750, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -751, DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -960, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1439, DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1440, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1441, DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2880, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(11, 0, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(11, 58, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 1, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 59, 33))); testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 1, DateTime(Date(1999, 7, 5), TimeOfDay(23, 0, 33))); testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 0, DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33))); testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), -1, DateTime(Date(1999, 7, 5), TimeOfDay(23, 58, 33))); testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 1, DateTime(Date(1998, 12, 31), TimeOfDay(23, 0, 33))); testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 0, DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33))); testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), -1, DateTime(Date(1998, 12, 31), TimeOfDay(23, 58, 33))); //Test B.C. testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 32, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 33, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 34, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 35, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 40, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 29, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 45, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 75, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 90, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 100, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 10, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 689, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 690, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 691, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 960, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1439, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1440, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1441, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2880, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 28, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 27, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 26, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 25, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 20, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -29, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -30, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -45, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -75, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -90, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -100, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 50, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -749, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -750, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -751, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -960, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1439, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1440, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1441, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2880, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 0, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 58, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 1, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 59, 33))); testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 1, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 0, 33))); testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 0, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33))); testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), -1, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 58, 33))); testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 1, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 0, 33))); testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 0, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33))); testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), -1, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 58, 33))); //Test Both testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1, DateTime(Date(1, 1, 1), TimeOfDay(0, 59, 0))); testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0)), 1, DateTime(Date(0, 12, 31), TimeOfDay(23, 0, 0))); testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1, DateTime(Date(0, 1, 1), TimeOfDay(0, 59, 0))); testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0)), 1, DateTime(Date(-1, 12, 31), TimeOfDay(23, 0, 0))); testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_760, DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33))); testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -1_052_760, DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_782, DateTime(Date(-1, 1, 1), TimeOfDay(11, 52, 33))); testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 52, 33)), -1_052_782, DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); auto dt = DateTime(2000, 1, 31, 9, 7, 6); dt.roll!"minutes"(92).roll!"minutes"(-292); assert(dt == DateTime(2000, 1, 31, 9, 47, 6)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.roll!"minutes"(4))); static assert(!__traits(compiles, idt.roll!"minutes"(4))); } //Test roll!"seconds"(). unittest { static void testDT(DateTime orig, int seconds, in DateTime expected, size_t line = __LINE__) { orig.roll!"seconds"(seconds); assert(orig == expected); } //Test A.D. testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 35))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 36))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 37))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 38))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 43))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 48))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 26, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 27, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 3))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 59, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 61, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1766, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1767, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1768, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2007, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3599, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3600, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3601, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7200, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 31))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 30))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 29))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 28))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 23))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 18))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -33, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -34, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -35, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 58))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -59, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -61, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 1))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 59))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 1))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))); testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 59))); testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 1, DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 0))); testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 0, DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59))); testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), -1, DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 58))); testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 1, DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 0))); testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 0, DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59))); testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), -1, DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 58))); //Test B.C. testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 35))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 36))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 37))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 38))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 43))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 48))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 26, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 27, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 3))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 59, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 61, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1766, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1767, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1768, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2007, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3599, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3600, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3601, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7200, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 31))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 30))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 29))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 28))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 23))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 18))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -33, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -34, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -35, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 58))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -59, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -61, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 1))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 59))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 1))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0))); testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 59))); testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 1, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 0))); testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 0, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59))); testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), -1, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 58))); testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 1, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 0))); testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 0, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59))); testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), -1, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 58))); //Test Both testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1, DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 59))); testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)), 1, DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0))); testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1, DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 59))); testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 59)), 1, DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0))); testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_600L, DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33))); testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -63_165_600L, DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_617L, DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 50))); testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 50)), -63_165_617L, DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); auto dt = DateTime(2000, 1, 31, 9, 7, 6); dt.roll!"seconds"(92).roll!"seconds"(-292); assert(dt == DateTime(2000, 1, 31, 9, 7, 46)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt.roll!"seconds"(4))); static assert(!__traits(compiles, idt.roll!"seconds"(4))); } /++ Gives the result of adding or subtracting a $(CXREF time, Duration) from this $(LREF DateTime). The legal types of arithmetic for $(LREF DateTime) using this operator are $(BOOKTABLE, $(TR $(TD DateTime) $(TD +) $(TD Duration) $(TD -->) $(TD DateTime)) $(TR $(TD DateTime) $(TD -) $(TD Duration) $(TD -->) $(TD DateTime)) ) Params: duration = The $(CXREF time, Duration) to add to or subtract from this $(LREF DateTime). +/ DateTime opBinary(string op)(Duration duration) @safe const pure nothrow if(op == "+" || op == "-") { DateTime retval = this; immutable seconds = duration.total!"seconds"; mixin("return retval._addSeconds(" ~ op ~ "seconds);"); } /// unittest { assert(DateTime(2015, 12, 31, 23, 59, 59) + seconds(1) == DateTime(2016, 1, 1, 0, 0, 0)); assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) == DateTime(2016, 1, 1, 0, 59, 59)); assert(DateTime(2016, 1, 1, 0, 0, 0) - seconds(1) == DateTime(2015, 12, 31, 23, 59, 59)); assert(DateTime(2016, 1, 1, 0, 59, 59) - hours(1) == DateTime(2015, 12, 31, 23, 59, 59)); } unittest { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(dt + dur!"weeks"(7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); assert(dt + dur!"weeks"(-7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); assert(dt + dur!"days"(7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); assert(dt + dur!"days"(-7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); assert(dt + dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); assert(dt + dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); assert(dt + dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); assert(dt + dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); assert(dt + dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt + dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(dt + dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt + dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(dt + dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt + dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(dt + dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt + dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(dt - dur!"weeks"(-7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); assert(dt - dur!"weeks"(7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); assert(dt - dur!"days"(-7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); assert(dt - dur!"days"(7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); assert(dt - dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); assert(dt - dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); assert(dt - dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); assert(dt - dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); assert(dt - dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt - dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(dt - dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt - dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(dt - dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt - dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(dt - dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt - dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); auto duration = dur!"seconds"(12); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(cdt + duration == DateTime(1999, 7, 6, 12, 30, 45)); assert(idt + duration == DateTime(1999, 7, 6, 12, 30, 45)); assert(cdt - duration == DateTime(1999, 7, 6, 12, 30, 21)); assert(idt - duration == DateTime(1999, 7, 6, 12, 30, 21)); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime) and $(CXREF time, Duration). Use $(D Duration) instead. This overload will be removed in January 2017.) Defines + and - with $(CXREF time, TickDuration). +/ deprecated("Use Duration instead of TickDuration.") DateTime opBinary(string op)(in TickDuration td) @safe const pure nothrow if(op == "+" || op == "-") { DateTime retval = this; immutable seconds = td.seconds; mixin("return retval._addSeconds(" ~ op ~ "seconds);"); } deprecated unittest { //This probably only runs in cases where gettimeofday() is used, but it's //hard to do this test correctly with variable ticksPerSec. if(TickDuration.ticksPerSec == 1_000_000) { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(dt + TickDuration.from!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt + TickDuration.from!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(dt - TickDuration.from!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(dt - TickDuration.from!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); } } /++ Gives the result of adding or subtracting a duration from this $(LREF DateTime), as well as assigning the result to this $(LREF DateTime). The legal types of arithmetic for $(LREF DateTime) using this operator are $(BOOKTABLE, $(TR $(TD DateTime) $(TD +) $(TD duration) $(TD -->) $(TD DateTime)) $(TR $(TD DateTime) $(TD -) $(TD duration) $(TD -->) $(TD DateTime)) ) Params: duration = The duration to add to or subtract from this $(LREF DateTime). +/ ref DateTime opOpAssign(string op, D)(in D duration) @safe pure nothrow if((op == "+" || op == "-") && (is(Unqual!D == Duration) || is(Unqual!D == TickDuration))) { import std.format : format; DateTime retval = this; static if(is(Unqual!D == Duration)) immutable hnsecs = duration.total!"hnsecs"; else static if(is(Unqual!D == TickDuration)) immutable hnsecs = duration.hnsecs; mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op)); } unittest { assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(-7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(-7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(-7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(-7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); auto dt = DateTime(2000, 1, 31, 9, 7, 6); (dt += dur!"seconds"(92)) -= dur!"days"(-500); assert(dt == DateTime(2001, 6, 14, 9, 8, 38)); auto duration = dur!"seconds"(12); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); static assert(!__traits(compiles, cdt += duration)); static assert(!__traits(compiles, idt += duration)); static assert(!__traits(compiles, cdt -= duration)); static assert(!__traits(compiles, idt -= duration)); } // @@@DEPRECATED_2017-01@@@ /++ $(RED Deprecated. $(CXREF time, TickDuration) is going to be deprecated in favor of $(CXREF time, MonoTime) and $(CXREF time, Duration). Use $(D Duration) instead. This overload will be removed in January 2017.) Defines += and -= with $(CXREF time, TickDuration). +/ deprecated("Use Duration instead of TickDuration.") ref DateTime opOpAssign(string op)(TickDuration td) @safe pure nothrow if(op == "+" || op == "-") { DateTime retval = this; immutable seconds = td.seconds; mixin("return _addSeconds(" ~ op ~ "seconds);"); } deprecated unittest { //This probably only runs in cases where gettimeofday() is used, but it's //hard to do this test correctly with variable ticksPerSec. if(TickDuration.ticksPerSec == 1_000_000) { { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); dt += TickDuration.from!"usecs"(7_000_000); assert(dt == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); } { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); dt += TickDuration.from!"usecs"(-7_000_000); assert(dt == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); } { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); dt -= TickDuration.from!"usecs"(-7_000_000); assert(dt == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); } { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); dt -= TickDuration.from!"usecs"(7_000_000); assert(dt == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); } } } /++ Gives the difference between two $(LREF DateTime)s. The legal types of arithmetic for $(LREF DateTime) using this operator are $(BOOKTABLE, $(TR $(TD DateTime) $(TD -) $(TD DateTime) $(TD -->) $(TD duration)) ) +/ Duration opBinary(string op)(in DateTime rhs) @safe const pure nothrow if(op == "-") { immutable dateResult = _date - rhs.date; immutable todResult = _tod - rhs._tod; return dur!"hnsecs"(dateResult.total!"hnsecs" + todResult.total!"hnsecs"); } unittest { auto dt = DateTime(1999, 7, 6, 12, 30, 33); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) == dur!"seconds"(31_536_000)); assert(DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == dur!"seconds"(-31_536_000)); assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == dur!"seconds"(26_78_400)); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) == dur!"seconds"(-26_78_400)); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) == dur!"seconds"(86_400)); assert(DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == dur!"seconds"(-86_400)); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) == dur!"seconds"(3600)); assert(DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == dur!"seconds"(-3600)); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == dur!"seconds"(60)); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) == dur!"seconds"(-60)); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == dur!"seconds"(1)); assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) == dur!"seconds"(-1)); assert(DateTime(1, 1, 1, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(45033)); assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(1, 1, 1, 12, 30, 33) == dur!"seconds"(-45033)); assert(DateTime(0, 12, 31, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(-41367)); assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(0, 12, 31, 12, 30, 33) == dur!"seconds"(41367)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(dt - dt == Duration.zero); assert(cdt - dt == Duration.zero); assert(idt - dt == Duration.zero); assert(dt - cdt == Duration.zero); assert(cdt - cdt == Duration.zero); assert(idt - cdt == Duration.zero); assert(dt - idt == Duration.zero); assert(cdt - idt == Duration.zero); assert(idt - idt == Duration.zero); } /++ Returns the difference between the two $(LREF DateTime)s in months. To get the difference in years, subtract the year property of two $(LREF SysTime)s. To get the difference in days or weeks, subtract the $(LREF SysTime)s themselves and use the $(CXREF time, Duration) that results. Because converting between months and smaller units requires a specific date (which $(CXREF time, Duration)s don't have), getting the difference in months requires some math using both the year and month properties, so this is a convenience function for getting the difference in months. Note that the number of days in the months or how far into the month either date is is irrelevant. It is the difference in the month property combined with the difference in years * 12. So, for instance, December 31st and January 1st are one month apart just as December 1st and January 31st are one month apart. Params: rhs = The $(LREF DateTime) to subtract from this one. +/ int diffMonths(in DateTime rhs) @safe const pure nothrow { return _date.diffMonths(rhs._date); } /// unittest { assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths( DateTime(1999, 1, 31, 23, 59, 59)) == 1); assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths( DateTime(1999, 2, 1, 12, 3, 42)) == -1); assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths( DateTime(1999, 1, 1, 2, 4, 7)) == 2); assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths( DateTime(1999, 3, 31, 0, 30, 58)) == -2); } unittest { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(dt.diffMonths(dt) == 0); assert(cdt.diffMonths(dt) == 0); assert(idt.diffMonths(dt) == 0); assert(dt.diffMonths(cdt) == 0); assert(cdt.diffMonths(cdt) == 0); assert(idt.diffMonths(cdt) == 0); assert(dt.diffMonths(idt) == 0); assert(cdt.diffMonths(idt) == 0); assert(idt.diffMonths(idt) == 0); } /++ Whether this $(LREF DateTime) is in a leap year. +/ @property bool isLeapYear() @safe const pure nothrow { return _date.isLeapYear; } unittest { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(!dt.isLeapYear); assert(!cdt.isLeapYear); assert(!idt.isLeapYear); } /++ Day of the week this $(LREF DateTime) is on. +/ @property DayOfWeek dayOfWeek() @safe const pure nothrow { return _date.dayOfWeek; } unittest { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(dt.dayOfWeek == DayOfWeek.tue); assert(cdt.dayOfWeek == DayOfWeek.tue); assert(idt.dayOfWeek == DayOfWeek.tue); } /++ Day of the year this $(LREF DateTime) is on. +/ @property ushort dayOfYear() @safe const pure nothrow { return _date.dayOfYear; } /// unittest { assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1); assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365); assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366); } unittest { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(dt.dayOfYear == 187); assert(cdt.dayOfYear == 187); assert(idt.dayOfYear == 187); } /++ Day of the year. Params: day = The day of the year to set which day of the year this $(LREF DateTime) is on. +/ @property void dayOfYear(int day) @safe pure { _date.dayOfYear = day; } unittest { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); dt.dayOfYear = 12; assert(dt.dayOfYear == 12); static assert(!__traits(compiles, cdt.dayOfYear = 12)); static assert(!__traits(compiles, idt.dayOfYear = 12)); } /++ The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. +/ @property int dayOfGregorianCal() @safe const pure nothrow { return _date.dayOfGregorianCal; } /// unittest { assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1); assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365); assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366); assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0); assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365); assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366); assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120); assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137); } unittest { const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(cdt.dayOfGregorianCal == 729_941); assert(idt.dayOfGregorianCal == 729_941); } /++ The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. Setting this property does not affect the time portion of $(LREF DateTime). Params: days = The day of the Gregorian Calendar to set this $(LREF DateTime) to. +/ @property void dayOfGregorianCal(int days) @safe pure nothrow { _date.dayOfGregorianCal = days; } /// unittest { auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0)); dt.dayOfGregorianCal = 1; assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0))); dt.dayOfGregorianCal = 365; assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0))); dt.dayOfGregorianCal = 366; assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0))); dt.dayOfGregorianCal = 0; assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0))); dt.dayOfGregorianCal = -365; assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0))); dt.dayOfGregorianCal = -366; assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0))); dt.dayOfGregorianCal = 730_120; assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0))); dt.dayOfGregorianCal = 734_137; assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0))); } unittest { const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); static assert(!__traits(compiles, cdt.dayOfGregorianCal = 7)); static assert(!__traits(compiles, idt.dayOfGregorianCal = 7)); } /++ The ISO 8601 week of the year that this $(LREF DateTime) is in. See_Also: $(WEB en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) +/ @property ubyte isoWeek() @safe const pure nothrow { return _date.isoWeek; } unittest { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(dt.isoWeek == 27); assert(cdt.isoWeek == 27); assert(idt.isoWeek == 27); } /++ $(LREF DateTime) for the last day in the month that this $(LREF DateTime) is in. The time portion of endOfMonth is always 23:59:59. +/ @property DateTime endOfMonth() @safe const pure nothrow { try return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59)); catch(Exception e) assert(0, "DateTime constructor threw."); } /// unittest { assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth == DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59))); assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth == DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59))); assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth == DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59))); assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth == DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59))); } unittest { //Test A.D. assert(DateTime(1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(1999, 1, 31, 23, 59, 59)); assert(DateTime(1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(1999, 2, 28, 23, 59, 59)); assert(DateTime(2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(2000, 2, 29, 23, 59, 59)); assert(DateTime(1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(1999, 3, 31, 23, 59, 59)); assert(DateTime(1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(1999, 4, 30, 23, 59, 59)); assert(DateTime(1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(1999, 5, 31, 23, 59, 59)); assert(DateTime(1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(1999, 6, 30, 23, 59, 59)); assert(DateTime(1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); assert(DateTime(1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(1999, 8, 31, 23, 59, 59)); assert(DateTime(1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(1999, 9, 30, 23, 59, 59)); assert(DateTime(1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(1999, 10, 31, 23, 59, 59)); assert(DateTime(1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(1999, 11, 30, 23, 59, 59)); assert(DateTime(1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(1999, 12, 31, 23, 59, 59)); //Test B.C. assert(DateTime(-1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(-1999, 1, 31, 23, 59, 59)); assert(DateTime(-1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(-1999, 2, 28, 23, 59, 59)); assert(DateTime(-2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(-2000, 2, 29, 23, 59, 59)); assert(DateTime(-1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(-1999, 3, 31, 23, 59, 59)); assert(DateTime(-1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(-1999, 4, 30, 23, 59, 59)); assert(DateTime(-1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(-1999, 5, 31, 23, 59, 59)); assert(DateTime(-1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(-1999, 6, 30, 23, 59, 59)); assert(DateTime(-1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(-1999, 7, 31, 23, 59, 59)); assert(DateTime(-1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(-1999, 8, 31, 23, 59, 59)); assert(DateTime(-1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(-1999, 9, 30, 23, 59, 59)); assert(DateTime(-1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(-1999, 10, 31, 23, 59, 59)); assert(DateTime(-1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(-1999, 11, 30, 23, 59, 59)); assert(DateTime(-1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(-1999, 12, 31, 23, 59, 59)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(cdt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); assert(idt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); } /++ The last day in the month that this $(LREF DateTime) is in. +/ @property ubyte daysInMonth() @safe const pure nothrow { return _date.daysInMonth; } /// unittest { assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31); assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28); assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29); assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30); } unittest { const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(cdt.daysInMonth == 31); assert(idt.daysInMonth == 31); } /++ Whether the current year is a date in A.D. +/ @property bool isAD() @safe const pure nothrow { return _date.isAD; } /// unittest { assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD); assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD); assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD); assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD); } unittest { const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(cdt.isAD); assert(idt.isAD); } /++ The $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for this $(LREF DateTime) at the given time. For example, prior to noon, 1996-03-31 would be the Julian day number 2_450_173, so this function returns 2_450_173, while from noon onward, the julian day number would be 2_450_174, so this function returns 2_450_174. +/ @property long julianDay() @safe const pure nothrow { if(_tod._hour < 12) return _date.julianDay - 1; else return _date.julianDay; } unittest { assert(DateTime(Date(-4713, 11, 24), TimeOfDay(0, 0, 0)).julianDay == -1); assert(DateTime(Date(-4713, 11, 24), TimeOfDay(12, 0, 0)).julianDay == 0); assert(DateTime(Date(0, 12, 31), TimeOfDay(0, 0, 0)).julianDay == 1_721_424); assert(DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)).julianDay == 1_721_425); assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).julianDay == 1_721_425); assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)).julianDay == 1_721_426); assert(DateTime(Date(1582, 10, 15), TimeOfDay(0, 0, 0)).julianDay == 2_299_160); assert(DateTime(Date(1582, 10, 15), TimeOfDay(12, 0, 0)).julianDay == 2_299_161); assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).julianDay == 2_400_000); assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).julianDay == 2_400_001); assert(DateTime(Date(1982, 1, 4), TimeOfDay(0, 0, 0)).julianDay == 2_444_973); assert(DateTime(Date(1982, 1, 4), TimeOfDay(12, 0, 0)).julianDay == 2_444_974); assert(DateTime(Date(1996, 3, 31), TimeOfDay(0, 0, 0)).julianDay == 2_450_173); assert(DateTime(Date(1996, 3, 31), TimeOfDay(12, 0, 0)).julianDay == 2_450_174); assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).julianDay == 2_455_432); assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).julianDay == 2_455_433); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(cdt.julianDay == 2_451_366); assert(idt.julianDay == 2_451_366); } /++ The modified $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for any time on this date (since, the modified Julian day changes at midnight). +/ @property long modJulianDay() @safe const pure nothrow { return _date.modJulianDay; } unittest { assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).modJulianDay == 0); assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).modJulianDay == 0); assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).modJulianDay == 55_432); assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).modJulianDay == 55_432); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(cdt.modJulianDay == 51_365); assert(idt.modJulianDay == 51_365); } /++ Converts this $(LREF DateTime) to a string with the format YYYYMMDDTHHMMSS. +/ string toISOString() @safe const pure nothrow { import std.format : format; try return format("%sT%s", _date.toISOString(), _tod.toISOString()); catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() == "20100704T070612"); assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() == "19981225T021500"); assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() == "00000105T230959"); assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() == "-00040105T000002"); } unittest { //Test A.D. assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "00091204T000000"); assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "00991204T050612"); assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "09991204T134459"); assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "99990704T235959"); assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "+100001020T010101"); //Test B.C. assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOString() == "00001204T001204"); assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "-00091204T000000"); assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "-00991204T050612"); assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "-09991204T134459"); assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "-99990704T235959"); assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "-100001020T010101"); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(cdt.toISOString() == "19990706T123033"); assert(idt.toISOString() == "19990706T123033"); } /++ Converts this $(LREF DateTime) to a string with the format YYYY-MM-DDTHH:MM:SS. +/ string toISOExtString() @safe const pure nothrow { import std.format : format; try return format("%sT%s", _date.toISOExtString(), _tod.toISOExtString()); catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() == "2010-07-04T07:06:12"); assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() == "1998-12-25T02:15:00"); assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() == "0000-01-05T23:09:59"); assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() == "-0004-01-05T00:00:02"); } unittest { //Test A.D. assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00"); assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12"); assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59"); assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59"); assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01"); //Test B.C. assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04"); assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00"); assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12"); assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59"); assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59"); assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01"); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(cdt.toISOExtString() == "1999-07-06T12:30:33"); assert(idt.toISOExtString() == "1999-07-06T12:30:33"); } /++ Converts this $(LREF DateTime) to a string with the format YYYY-Mon-DD HH:MM:SS. +/ string toSimpleString() @safe const pure nothrow { import std.format : format; try return format("%s %s", _date.toSimpleString(), _tod.toString()); catch(Exception e) assert(0, "format() threw."); } /// unittest { assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() == "2010-Jul-04 07:06:12"); assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() == "1998-Dec-25 02:15:00"); assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() == "0000-Jan-05 23:09:59"); assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() == "-0004-Jan-05 00:00:02"); } unittest { //Test A.D. assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00"); assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12"); assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59"); assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59"); assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01"); //Test B.C. assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04"); assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00"); assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12"); assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59"); assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59"); assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01"); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); assert(cdt.toSimpleString() == "1999-Jul-06 12:30:33"); assert(idt.toSimpleString() == "1999-Jul-06 12:30:33"); } /++ Converts this $(LREF DateTime) to a string. +/ string toString() @safe const pure nothrow { return toSimpleString(); } unittest { auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); assert(dt.toString()); assert(cdt.toString()); assert(idt.toString()); } /++ Creates a $(LREF DateTime) from a string with the format YYYYMMDDTHHMMSS. Whitespace is stripped from the given string. Params: isoString = A string formatted in the ISO format for dates and times. Throws: $(LREF DateTimeException) if the given string is not in the ISO format or if the resulting $(LREF DateTime) would not be valid. +/ static DateTime fromISOString(S)(in S isoString) @safe pure if(isSomeString!S) { import std.string : strip; import std.conv : to; import std.algorithm : countUntil; import std.format : format; immutable dstr = to!dstring(strip(isoString)); enforce(dstr.length >= 15, new DateTimeException(format("Invalid ISO String: %s", isoString))); auto t = dstr.countUntil('T'); enforce(t != -1, new DateTimeException(format("Invalid ISO String: %s", isoString))); immutable date = Date.fromISOString(dstr[0..t]); immutable tod = TimeOfDay.fromISOString(dstr[t+1 .. $]); return DateTime(date, tod); } /// unittest { assert(DateTime.fromISOString("20100704T070612") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); assert(DateTime.fromISOString("19981225T021500") == DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); assert(DateTime.fromISOString("00000105T230959") == DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); assert(DateTime.fromISOString("-00040105T000002") == DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); assert(DateTime.fromISOString(" 20100704T070612 ") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); } unittest { assertThrown!DateTimeException(DateTime.fromISOString("")); assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); assertThrown!DateTimeException(DateTime.fromISOString("2010-12-22T172201")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Dec-22 17:22:01")); assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01))); assert(DateTime.fromISOString("19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOString("-19990706T123033") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOString("+019990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOString("19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOString(" 19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOString(" 19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); } /++ Creates a $(LREF DateTime) from a string with the format YYYY-MM-DDTHH:MM:SS. Whitespace is stripped from the given string. Params: isoExtString = A string formatted in the ISO Extended format for dates and times. Throws: $(LREF DateTimeException) if the given string is not in the ISO Extended format or if the resulting $(LREF DateTime) would not be valid. +/ static DateTime fromISOExtString(S)(in S isoExtString) @safe pure if(isSomeString!(S)) { import std.string : strip; import std.conv : to; import std.algorithm : countUntil; import std.format : format; immutable dstr = to!dstring(strip(isoExtString)); enforce(dstr.length >= 15, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); auto t = dstr.countUntil('T'); enforce(t != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); immutable date = Date.fromISOExtString(dstr[0..t]); immutable tod = TimeOfDay.fromISOExtString(dstr[t+1 .. $]); return DateTime(date, tod); } /// unittest { assert(DateTime.fromISOExtString("2010-07-04T07:06:12") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); assert(DateTime.fromISOExtString("1998-12-25T02:15:00") == DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); assert(DateTime.fromISOExtString("0000-01-05T23:09:59") == DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") == DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); } unittest { assertThrown!DateTimeException(DateTime.fromISOExtString("")); assertThrown!DateTimeException(DateTime.fromISOExtString("20100704000000")); assertThrown!DateTimeException(DateTime.fromISOExtString("20100704 000000")); assertThrown!DateTimeException(DateTime.fromISOExtString("20100704t000000")); assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.")); assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.0")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07:0400:00:00")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04t00:00:00")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.0")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-0400:00:00")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04t00:00:00")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.0")); assertThrown!DateTimeException(DateTime.fromISOExtString("20101222T172201")); assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Dec-22 17:22:01")); assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01))); assert(DateTime.fromISOExtString("1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOExtString("-1999-07-06T12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOExtString("+01999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOExtString("1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); } /++ Creates a $(LREF DateTime) from a string with the format YYYY-Mon-DD HH:MM:SS. Whitespace is stripped from the given string. Params: simpleString = A string formatted in the way that toSimpleString formats dates and times. Throws: $(LREF DateTimeException) if the given string is not in the correct format or if the resulting $(LREF DateTime) would not be valid. +/ static DateTime fromSimpleString(S)(in S simpleString) @safe pure if(isSomeString!(S)) { import std.string : strip; import std.conv : to; import std.algorithm : countUntil; import std.format : format; immutable dstr = to!dstring(strip(simpleString)); enforce(dstr.length >= 15, new DateTimeException(format("Invalid string format: %s", simpleString))); auto t = dstr.countUntil(' '); enforce(t != -1, new DateTimeException(format("Invalid string format: %s", simpleString))); immutable date = Date.fromSimpleString(dstr[0..t]); immutable tod = TimeOfDay.fromISOExtString(dstr[t+1 .. $]); return DateTime(date, tod); } /// unittest { assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") == DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") == DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") == DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); } unittest { assertThrown!DateTimeException(DateTime.fromISOString("")); assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); assertThrown!DateTimeException(DateTime.fromSimpleString("20101222T172201")); assertThrown!DateTimeException(DateTime.fromSimpleString("2010-12-22T172201")); assert(DateTime.fromSimpleString("2010-Dec-22 17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01))); assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromSimpleString("-1999-Jul-06 12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromSimpleString("+01999-Jul-06 12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); } /++ Returns the $(LREF DateTime) farthest in the past which is representable by $(LREF DateTime). +/ @property static DateTime min() @safe pure nothrow out(result) { assert(result._date == Date.min); assert(result._tod == TimeOfDay.min); } body { auto dt = DateTime.init; dt._date._year = short.min; dt._date._month = Month.jan; dt._date._day = 1; return dt; } unittest { assert(DateTime.min.year < 0); assert(DateTime.min < DateTime.max); } /++ Returns the $(LREF DateTime) farthest in the future which is representable by $(LREF DateTime). +/ @property static DateTime max() @safe pure nothrow out(result) { assert(result._date == Date.max); assert(result._tod == TimeOfDay.max); } body { auto dt = DateTime.init; dt._date._year = short.max; dt._date._month = Month.dec; dt._date._day = 31; dt._tod._hour = TimeOfDay.maxHour; dt._tod._minute = TimeOfDay.maxMinute; dt._tod._second = TimeOfDay.maxSecond; return dt; } unittest { assert(DateTime.max.year > 0); assert(DateTime.max > DateTime.min); } private: /+ Add seconds to the time of day. Negative values will subtract. If the number of seconds overflows (or underflows), then the seconds will wrap, increasing (or decreasing) the number of minutes accordingly. The same goes for any larger units. Params: seconds = The number of seconds to add to this $(LREF DateTime). +/ ref DateTime _addSeconds(long seconds) return @safe pure nothrow { long hnsecs = convert!("seconds", "hnsecs")(seconds); hnsecs += convert!("hours", "hnsecs")(_tod._hour); hnsecs += convert!("minutes", "hnsecs")(_tod._minute); hnsecs += convert!("seconds", "hnsecs")(_tod._second); auto days = splitUnitsFromHNSecs!"days"(hnsecs); if(hnsecs < 0) { hnsecs += convert!("days", "hnsecs")(1); --days; } _date._addDays(days); immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); _tod._hour = cast(ubyte)newHours; _tod._minute = cast(ubyte)newMinutes; _tod._second = cast(ubyte)newSeconds; return this; } unittest { static void testDT(DateTime orig, int seconds, in DateTime expected, size_t line = __LINE__) { orig._addSeconds(seconds); assert(orig == expected); } //Test A.D. testDT(DateTime(1999, 7, 6, 12, 30, 33), 0, DateTime(1999, 7, 6, 12, 30, 33)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 1, DateTime(1999, 7, 6, 12, 30, 34)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 2, DateTime(1999, 7, 6, 12, 30, 35)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 3, DateTime(1999, 7, 6, 12, 30, 36)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 4, DateTime(1999, 7, 6, 12, 30, 37)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 5, DateTime(1999, 7, 6, 12, 30, 38)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 10, DateTime(1999, 7, 6, 12, 30, 43)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 15, DateTime(1999, 7, 6, 12, 30, 48)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 26, DateTime(1999, 7, 6, 12, 30, 59)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 27, DateTime(1999, 7, 6, 12, 31, 0)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 30, DateTime(1999, 7, 6, 12, 31, 3)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 59, DateTime(1999, 7, 6, 12, 31, 32)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 60, DateTime(1999, 7, 6, 12, 31, 33)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 61, DateTime(1999, 7, 6, 12, 31, 34)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 1766, DateTime(1999, 7, 6, 12, 59, 59)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 1767, DateTime(1999, 7, 6, 13, 0, 0)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 1768, DateTime(1999, 7, 6, 13, 0, 1)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 2007, DateTime(1999, 7, 6, 13, 4, 0)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 3599, DateTime(1999, 7, 6, 13, 30, 32)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 3600, DateTime(1999, 7, 6, 13, 30, 33)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 3601, DateTime(1999, 7, 6, 13, 30, 34)); testDT(DateTime(1999, 7, 6, 12, 30, 33), 7200, DateTime(1999, 7, 6, 14, 30, 33)); testDT(DateTime(1999, 7, 6, 23, 0, 0), 432_123, DateTime(1999, 7, 11, 23, 2, 3)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -1, DateTime(1999, 7, 6, 12, 30, 32)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -2, DateTime(1999, 7, 6, 12, 30, 31)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -3, DateTime(1999, 7, 6, 12, 30, 30)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -4, DateTime(1999, 7, 6, 12, 30, 29)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -5, DateTime(1999, 7, 6, 12, 30, 28)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -10, DateTime(1999, 7, 6, 12, 30, 23)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -15, DateTime(1999, 7, 6, 12, 30, 18)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -33, DateTime(1999, 7, 6, 12, 30, 0)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -34, DateTime(1999, 7, 6, 12, 29, 59)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -35, DateTime(1999, 7, 6, 12, 29, 58)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -59, DateTime(1999, 7, 6, 12, 29, 34)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -60, DateTime(1999, 7, 6, 12, 29, 33)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -61, DateTime(1999, 7, 6, 12, 29, 32)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -1833, DateTime(1999, 7, 6, 12, 0, 0)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -1834, DateTime(1999, 7, 6, 11, 59, 59)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -3600, DateTime(1999, 7, 6, 11, 30, 33)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -3601, DateTime(1999, 7, 6, 11, 30, 32)); testDT(DateTime(1999, 7, 6, 12, 30, 33), -5134, DateTime(1999, 7, 6, 11, 4, 59)); testDT(DateTime(1999, 7, 6, 23, 0, 0), -432_123, DateTime(1999, 7, 1, 22, 57, 57)); testDT(DateTime(1999, 7, 6, 12, 30, 0), 1, DateTime(1999, 7, 6, 12, 30, 1)); testDT(DateTime(1999, 7, 6, 12, 30, 0), 0, DateTime(1999, 7, 6, 12, 30, 0)); testDT(DateTime(1999, 7, 6, 12, 30, 0), -1, DateTime(1999, 7, 6, 12, 29, 59)); testDT(DateTime(1999, 7, 6, 12, 0, 0), 1, DateTime(1999, 7, 6, 12, 0, 1)); testDT(DateTime(1999, 7, 6, 12, 0, 0), 0, DateTime(1999, 7, 6, 12, 0, 0)); testDT(DateTime(1999, 7, 6, 12, 0, 0), -1, DateTime(1999, 7, 6, 11, 59, 59)); testDT(DateTime(1999, 7, 6, 0, 0, 0), 1, DateTime(1999, 7, 6, 0, 0, 1)); testDT(DateTime(1999, 7, 6, 0, 0, 0), 0, DateTime(1999, 7, 6, 0, 0, 0)); testDT(DateTime(1999, 7, 6, 0, 0, 0), -1, DateTime(1999, 7, 5, 23, 59, 59)); testDT(DateTime(1999, 7, 5, 23, 59, 59), 1, DateTime(1999, 7, 6, 0, 0, 0)); testDT(DateTime(1999, 7, 5, 23, 59, 59), 0, DateTime(1999, 7, 5, 23, 59, 59)); testDT(DateTime(1999, 7, 5, 23, 59, 59), -1, DateTime(1999, 7, 5, 23, 59, 58)); testDT(DateTime(1998, 12, 31, 23, 59, 59), 1, DateTime(1999, 1, 1, 0, 0, 0)); testDT(DateTime(1998, 12, 31, 23, 59, 59), 0, DateTime(1998, 12, 31, 23, 59, 59)); testDT(DateTime(1998, 12, 31, 23, 59, 59), -1, DateTime(1998, 12, 31, 23, 59, 58)); testDT(DateTime(1998, 1, 1, 0, 0, 0), 1, DateTime(1998, 1, 1, 0, 0, 1)); testDT(DateTime(1998, 1, 1, 0, 0, 0), 0, DateTime(1998, 1, 1, 0, 0, 0)); testDT(DateTime(1998, 1, 1, 0, 0, 0), -1, DateTime(1997, 12, 31, 23, 59, 59)); //Test B.C. testDT(DateTime(-1999, 7, 6, 12, 30, 33), 0, DateTime(-1999, 7, 6, 12, 30, 33)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1, DateTime(-1999, 7, 6, 12, 30, 34)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2, DateTime(-1999, 7, 6, 12, 30, 35)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3, DateTime(-1999, 7, 6, 12, 30, 36)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 4, DateTime(-1999, 7, 6, 12, 30, 37)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 5, DateTime(-1999, 7, 6, 12, 30, 38)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 10, DateTime(-1999, 7, 6, 12, 30, 43)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 15, DateTime(-1999, 7, 6, 12, 30, 48)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 26, DateTime(-1999, 7, 6, 12, 30, 59)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 27, DateTime(-1999, 7, 6, 12, 31, 0)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 30, DateTime(-1999, 7, 6, 12, 31, 3)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 59, DateTime(-1999, 7, 6, 12, 31, 32)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 60, DateTime(-1999, 7, 6, 12, 31, 33)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 61, DateTime(-1999, 7, 6, 12, 31, 34)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1766, DateTime(-1999, 7, 6, 12, 59, 59)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1767, DateTime(-1999, 7, 6, 13, 0, 0)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1768, DateTime(-1999, 7, 6, 13, 0, 1)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2007, DateTime(-1999, 7, 6, 13, 4, 0)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3599, DateTime(-1999, 7, 6, 13, 30, 32)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3600, DateTime(-1999, 7, 6, 13, 30, 33)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3601, DateTime(-1999, 7, 6, 13, 30, 34)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), 7200, DateTime(-1999, 7, 6, 14, 30, 33)); testDT(DateTime(-1999, 7, 6, 23, 0, 0), 432_123, DateTime(-1999, 7, 11, 23, 2, 3)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1, DateTime(-1999, 7, 6, 12, 30, 32)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -2, DateTime(-1999, 7, 6, 12, 30, 31)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3, DateTime(-1999, 7, 6, 12, 30, 30)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -4, DateTime(-1999, 7, 6, 12, 30, 29)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5, DateTime(-1999, 7, 6, 12, 30, 28)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -10, DateTime(-1999, 7, 6, 12, 30, 23)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -15, DateTime(-1999, 7, 6, 12, 30, 18)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -33, DateTime(-1999, 7, 6, 12, 30, 0)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -34, DateTime(-1999, 7, 6, 12, 29, 59)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -35, DateTime(-1999, 7, 6, 12, 29, 58)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -59, DateTime(-1999, 7, 6, 12, 29, 34)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -60, DateTime(-1999, 7, 6, 12, 29, 33)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -61, DateTime(-1999, 7, 6, 12, 29, 32)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1833, DateTime(-1999, 7, 6, 12, 0, 0)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1834, DateTime(-1999, 7, 6, 11, 59, 59)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3600, DateTime(-1999, 7, 6, 11, 30, 33)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3601, DateTime(-1999, 7, 6, 11, 30, 32)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5134, DateTime(-1999, 7, 6, 11, 4, 59)); testDT(DateTime(-1999, 7, 6, 12, 30, 33), -7200, DateTime(-1999, 7, 6, 10, 30, 33)); testDT(DateTime(-1999, 7, 6, 23, 0, 0), -432_123, DateTime(-1999, 7, 1, 22, 57, 57)); testDT(DateTime(-1999, 7, 6, 12, 30, 0), 1, DateTime(-1999, 7, 6, 12, 30, 1)); testDT(DateTime(-1999, 7, 6, 12, 30, 0), 0, DateTime(-1999, 7, 6, 12, 30, 0)); testDT(DateTime(-1999, 7, 6, 12, 30, 0), -1, DateTime(-1999, 7, 6, 12, 29, 59)); testDT(DateTime(-1999, 7, 6, 12, 0, 0), 1, DateTime(-1999, 7, 6, 12, 0, 1)); testDT(DateTime(-1999, 7, 6, 12, 0, 0), 0, DateTime(-1999, 7, 6, 12, 0, 0)); testDT(DateTime(-1999, 7, 6, 12, 0, 0), -1, DateTime(-1999, 7, 6, 11, 59, 59)); testDT(DateTime(-1999, 7, 6, 0, 0, 0), 1, DateTime(-1999, 7, 6, 0, 0, 1)); testDT(DateTime(-1999, 7, 6, 0, 0, 0), 0, DateTime(-1999, 7, 6, 0, 0, 0)); testDT(DateTime(-1999, 7, 6, 0, 0, 0), -1, DateTime(-1999, 7, 5, 23, 59, 59)); testDT(DateTime(-1999, 7, 5, 23, 59, 59), 1, DateTime(-1999, 7, 6, 0, 0, 0)); testDT(DateTime(-1999, 7, 5, 23, 59, 59), 0, DateTime(-1999, 7, 5, 23, 59, 59)); testDT(DateTime(-1999, 7, 5, 23, 59, 59), -1, DateTime(-1999, 7, 5, 23, 59, 58)); testDT(DateTime(-2000, 12, 31, 23, 59, 59), 1, DateTime(-1999, 1, 1, 0, 0, 0)); testDT(DateTime(-2000, 12, 31, 23, 59, 59), 0, DateTime(-2000, 12, 31, 23, 59, 59)); testDT(DateTime(-2000, 12, 31, 23, 59, 59), -1, DateTime(-2000, 12, 31, 23, 59, 58)); testDT(DateTime(-2000, 1, 1, 0, 0, 0), 1, DateTime(-2000, 1, 1, 0, 0, 1)); testDT(DateTime(-2000, 1, 1, 0, 0, 0), 0, DateTime(-2000, 1, 1, 0, 0, 0)); testDT(DateTime(-2000, 1, 1, 0, 0, 0), -1, DateTime(-2001, 12, 31, 23, 59, 59)); //Test Both testDT(DateTime(1, 1, 1, 0, 0, 0), -1, DateTime(0, 12, 31, 23, 59, 59)); testDT(DateTime(0, 12, 31, 23, 59, 59), 1, DateTime(1, 1, 1, 0, 0, 0)); testDT(DateTime(0, 1, 1, 0, 0, 0), -1, DateTime(-1, 12, 31, 23, 59, 59)); testDT(DateTime(-1, 12, 31, 23, 59, 59), 1, DateTime(0, 1, 1, 0, 0, 0)); testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_600L, DateTime(1, 1, 1, 13, 30, 33)); testDT(DateTime(1, 1, 1, 13, 30, 33), -63_165_600L, DateTime(-1, 1, 1, 11, 30, 33)); testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_617L, DateTime(1, 1, 1, 13, 30, 50)); testDT(DateTime(1, 1, 1, 13, 30, 50), -63_165_617L, DateTime(-1, 1, 1, 11, 30, 33)); const cdt = DateTime(1999, 7, 6, 12, 30, 33); immutable idt = DateTime(1999, 7, 6, 12, 30, 33); static assert(!__traits(compiles, cdt._addSeconds(4))); static assert(!__traits(compiles, idt._addSeconds(4))); } Date _date; TimeOfDay _tod; } //============================================================================== // Section with intervals. //============================================================================== /++ Represents an interval of time. An $(D Interval) has a starting point and an end point. The interval of time is therefore the time starting at the starting point up to, but not including, the end point. e.g. $(BOOKTABLE, $(TR $(TD [January 5th, 2010 - March 10th, 2010$(RPAREN))) $(TR $(TD [05:00:30 - 12:00:00$(RPAREN))) $(TR $(TD [1982-01-04T08:59:00 - 2010-07-04T12:00:00$(RPAREN))) ) A range can be obtained from an $(D Interval), allowing iteration over that interval, with the exact time points which are iterated over depending on the function which generates the range. +/ struct Interval(TP) { public: /++ Params: begin = The time point which begins the interval. end = The time point which ends (but is not included in) the interval. Throws: $(LREF DateTimeException) if $(D_PARAM end) is before $(D_PARAM begin). Example: -------------------- Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); -------------------- +/ this(U)(in TP begin, in U end) pure if(is(Unqual!TP == Unqual!U)) { if(!_valid(begin, end)) throw new DateTimeException("Arguments would result in an invalid Interval."); _begin = cast(TP)begin; _end = cast(TP)end; } /++ Params: begin = The time point which begins the interval. duration = The duration from the starting point to the end point. Throws: $(LREF DateTimeException) if the resulting $(D end) is before $(D begin). Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), dur!"days"(3)) == Interval!Date(Date(1996, 1, 2), Date(1996, 1, 5))); -------------------- +/ this(D)(in TP begin, in D duration) pure if(__traits(compiles, begin + duration)) { _begin = cast(TP)begin; _end = begin + duration; if(!_valid(_begin, _end)) throw new DateTimeException("Arguments would result in an invalid Interval."); } /++ Params: rhs = The $(LREF2 .Interval, Interval) to assign to this one. +/ ref Interval opAssign(const ref Interval rhs) pure nothrow { _begin = cast(TP)rhs._begin; _end = cast(TP)rhs._end; return this; } /++ Params: rhs = The $(LREF2 .Interval, Interval) to assign to this one. +/ ref Interval opAssign(Interval rhs) pure nothrow { _begin = cast(TP)rhs._begin; _end = cast(TP)rhs._end; return this; } /++ The starting point of the interval. It is included in the interval. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).begin == Date(1996, 1, 2)); -------------------- +/ @property TP begin() const pure nothrow { return cast(TP)_begin; } /++ The starting point of the interval. It is included in the interval. Params: timePoint = The time point to set $(D begin) to. Throws: $(LREF DateTimeException) if the resulting interval would be invalid. +/ @property void begin(TP timePoint) pure { if(!_valid(timePoint, _end)) throw new DateTimeException("Arguments would result in an invalid Interval."); _begin = timePoint; } /++ The end point of the interval. It is excluded from the interval. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).end == Date(2012, 3, 1)); -------------------- +/ @property TP end() const pure nothrow { return cast(TP)_end; } /++ The end point of the interval. It is excluded from the interval. Params: timePoint = The time point to set end to. Throws: $(LREF DateTimeException) if the resulting interval would be invalid. +/ @property void end(TP timePoint) pure { if(!_valid(_begin, timePoint)) throw new DateTimeException("Arguments would result in an invalid Interval."); _end = timePoint; } /++ Returns the duration between $(D begin) and $(D end). Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).length == dur!"days"(5903)); -------------------- +/ @property auto length() const pure nothrow { return _end - _begin; } /++ Whether the interval's length is 0, that is, whether $(D begin == end). Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(1996, 1, 2)).empty); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).empty); -------------------- +/ @property bool empty() const pure nothrow { return _begin == _end; } /++ Whether the given time point is within this interval. Params: timePoint = The time point to check for inclusion in this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains( Date(1994, 12, 24))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains( Date(2000, 1, 5))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains( Date(2012, 3, 1))); -------------------- +/ bool contains(in TP timePoint) const pure { _enforceNotEmpty(); return timePoint >= _begin && timePoint < _end; } /++ Whether the given interval is completely within this interval. Params: interval = The interval to check for inclusion in this interval. Throws: $(LREF DateTimeException) if either interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains( Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1)))); -------------------- +/ bool contains(in Interval interval) const pure { _enforceNotEmpty(); interval._enforceNotEmpty(); return interval._begin >= _begin && interval._begin < _end && interval._end <= _end; } /++ Whether the given interval is completely within this interval. Always returns false (unless this interval is empty), because an interval going to positive infinity can never be contained in a finite interval. Params: interval = The interval to check for inclusion in this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains( PosInfInterval!Date(Date(1999, 5, 4)))); -------------------- +/ bool contains(in PosInfInterval!TP interval) const pure { _enforceNotEmpty(); return false; } /++ Whether the given interval is completely within this interval. Always returns false (unless this interval is empty), because an interval beginning at negative infinity can never be contained in a finite interval. Params: interval = The interval to check for inclusion in this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains( NegInfInterval!Date(Date(1996, 5, 4)))); -------------------- +/ bool contains(in NegInfInterval!TP interval) const pure { _enforceNotEmpty(); return false; } /++ Whether this interval is before the given time point. Params: timePoint = The time point to check whether this interval is before it. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore( Date(1994, 12, 24))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore( Date(2000, 1, 5))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore( Date(2012, 3, 1))); -------------------- +/ bool isBefore(in TP timePoint) const pure { _enforceNotEmpty(); return _end <= timePoint; } /++ Whether this interval is before the given interval and does not intersect with it. Params: interval = The interval to check for against this interval. Throws: $(LREF DateTimeException) if either interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore( Interval!Date(Date(2012, 3, 1), Date(2013, 5, 1)))); -------------------- +/ bool isBefore(in Interval interval) const pure { _enforceNotEmpty(); interval._enforceNotEmpty(); return _end <= interval._begin; } /++ Whether this interval is before the given interval and does not intersect with it. Params: interval = The interval to check for against this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore( PosInfInterval!Date(Date(1999, 5, 4)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore( PosInfInterval!Date(Date(2013, 3, 7)))); -------------------- +/ bool isBefore(in PosInfInterval!TP interval) const pure { _enforceNotEmpty(); return _end <= interval._begin; } /++ Whether this interval is before the given interval and does not intersect with it. Always returns false (unless this interval is empty) because a finite interval can never be before an interval beginning at negative infinity. Params: interval = The interval to check for against this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore( NegInfInterval!Date(Date(1996, 5, 4)))); -------------------- +/ bool isBefore(in NegInfInterval!TP interval) const pure { _enforceNotEmpty(); return false; } /++ Whether this interval is after the given time point. Params: timePoint = The time point to check whether this interval is after it. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter( Date(1994, 12, 24))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter( Date(2000, 1, 5))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter( Date(2012, 3, 1))); -------------------- +/ bool isAfter(in TP timePoint) const pure { _enforceNotEmpty(); return timePoint < _begin; } /++ Whether this interval is after the given interval and does not intersect it. Params: interval = The interval to check against this interval. Throws: $(LREF DateTimeException) if either interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter( Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); -------------------- +/ bool isAfter(in Interval interval) const pure { _enforceNotEmpty(); interval._enforceNotEmpty(); return _begin >= interval._end; } /++ Whether this interval is after the given interval and does not intersect it. Always returns false (unless this interval is empty) because a finite interval can never be after an interval going to positive infinity. Params: interval = The interval to check against this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter( PosInfInterval!Date(Date(1999, 5, 4)))); -------------------- +/ bool isAfter(in PosInfInterval!TP interval) const pure { _enforceNotEmpty(); return false; } /++ Whether this interval is after the given interval and does not intersect it. Params: interval = The interval to check against this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter( NegInfInterval!Date(Date(1996, 1, 2)))); -------------------- +/ bool isAfter(in NegInfInterval!TP interval) const pure { _enforceNotEmpty(); return _begin >= interval._end; } /++ Whether the given interval overlaps this interval. Params: interval = The interval to check for intersection with this interval. Throws: $(LREF DateTimeException) if either interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects( Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); -------------------- +/ bool intersects(in Interval interval) const pure { _enforceNotEmpty(); interval._enforceNotEmpty(); return interval._begin < _end && interval._end > _begin; } /++ Whether the given interval overlaps this interval. Params: interval = The interval to check for intersection with this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects( PosInfInterval!Date(Date(1999, 5, 4)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects( PosInfInterval!Date(Date(2012, 3, 1)))); -------------------- +/ bool intersects(in PosInfInterval!TP interval) const pure { _enforceNotEmpty(); return _end > interval._begin; } /++ Whether the given interval overlaps this interval. Params: interval = The interval to check for intersection with this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects( NegInfInterval!Date(Date(1996, 1, 2)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects( NegInfInterval!Date(Date(2000, 1, 2)))); -------------------- +/ bool intersects(in NegInfInterval!TP interval) const pure { _enforceNotEmpty(); return _begin < interval._end; } /++ Returns the intersection of two intervals Params: interval = The interval to intersect with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect or if either interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17))); -------------------- +/ Interval intersection(in Interval interval) const { import std.format : format; enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval))); auto begin = _begin > interval._begin ? _begin : interval._begin; auto end = _end < interval._end ? _end : interval._end; return Interval(begin, end); } /++ Returns the intersection of two intervals Params: interval = The interval to intersect with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect or if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection( PosInfInterval!Date(Date(1990, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection( PosInfInterval!Date(Date(1999, 1, 12))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1))); -------------------- +/ Interval intersection(in PosInfInterval!TP interval) const { import std.format : format; enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval))); return Interval(_begin > interval._begin ? _begin : interval._begin, _end); } /++ Returns the intersection of two intervals Params: interval = The interval to intersect with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect or if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection( NegInfInterval!Date(Date(1999, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection( NegInfInterval!Date(Date(2013, 1, 12))) == Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1))); -------------------- +/ Interval intersection(in NegInfInterval!TP interval) const { import std.format : format; enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval))); return Interval(_begin, _end < interval._end ? _end : interval._end); } /++ Whether the given interval is adjacent to this interval. Params: interval = The interval to check whether its adjecent to this interval. Throws: $(LREF DateTimeException) if either interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent( Interval!Date(Date(1990, 7, 6), Date(1996, 1, 2)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent( Interval!Date(Date(2012, 3, 1), Date(2013, 9, 17)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent( Interval!Date(Date(1989, 3, 1), Date(2012, 3, 1)))); -------------------- +/ bool isAdjacent(in Interval interval) const pure { _enforceNotEmpty(); interval._enforceNotEmpty(); return _begin == interval._end || _end == interval._begin; } /++ Whether the given interval is adjacent to this interval. Params: interval = The interval to check whether its adjecent to this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent( PosInfInterval!Date(Date(1999, 5, 4)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent( PosInfInterval!Date(Date(2012, 3, 1)))); -------------------- +/ bool isAdjacent(in PosInfInterval!TP interval) const pure { _enforceNotEmpty(); return _end == interval._begin; } /++ Whether the given interval is adjacent to this interval. Params: interval = The interval to check whether its adjecent to this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent( NegInfInterval!Date(Date(1996, 1, 2)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent( NegInfInterval!Date(Date(2000, 1, 2)))); -------------------- +/ bool isAdjacent(in NegInfInterval!TP interval) const pure { _enforceNotEmpty(); return _begin == interval._end; } /++ Returns the union of two intervals Params: interval = The interval to merge with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect and are not adjacent or if either interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge( Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7))); -------------------- +/ Interval merge(in Interval interval) const { import std.format : format; enforce(this.isAdjacent(interval) || this.intersects(interval), new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval))); auto begin = _begin < interval._begin ? _begin : interval._begin; auto end = _end > interval._end ? _end : interval._end; return Interval(begin, end); } /++ Returns the union of two intervals Params: interval = The interval to merge with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect and are not adjacent or if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge( PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge( PosInfInterval!Date(Date(2012, 3, 1))) == PosInfInterval!Date(Date(1996, 1 , 2))); -------------------- +/ PosInfInterval!TP merge(in PosInfInterval!TP interval) const { import std.format : format; enforce(this.isAdjacent(interval) || this.intersects(interval), new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval))); return PosInfInterval!TP(_begin < interval._begin ? _begin : interval._begin); } /++ Returns the union of two intervals Params: interval = The interval to merge with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect and are not adjacent or if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge( NegInfInterval!Date(Date(1996, 1, 2))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge( NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12))); -------------------- +/ NegInfInterval!TP merge(in NegInfInterval!TP interval) const { import std.format : format; enforce(this.isAdjacent(interval) || this.intersects(interval), new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval))); return NegInfInterval!TP(_end > interval._end ? _end : interval._end); } /++ Returns an interval that covers from the earliest time point of two intervals up to (but not including) the latest time point of two intervals. Params: interval = The interval to create a span together with this interval. Throws: $(LREF DateTimeException) if either interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span( Interval!Date(Date(1990, 7, 6), Date(1991, 1, 8))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span( Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7))); -------------------- +/ Interval span(in Interval interval) const pure { _enforceNotEmpty(); interval._enforceNotEmpty(); auto begin = _begin < interval._begin ? _begin : interval._begin; auto end = _end > interval._end ? _end : interval._end; return Interval(begin, end); } /++ Returns an interval that covers from the earliest time point of two intervals up to (but not including) the latest time point of two intervals. Params: interval = The interval to create a span together with this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span( PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span( PosInfInterval!Date(Date(2050, 1, 1))) == PosInfInterval!Date(Date(1996, 1 , 2))); -------------------- +/ PosInfInterval!TP span(in PosInfInterval!TP interval) const pure { _enforceNotEmpty(); return PosInfInterval!TP(_begin < interval._begin ? _begin : interval._begin); } /++ Returns an interval that covers from the earliest time point of two intervals up to (but not including) the latest time point of two intervals. Params: interval = The interval to create a span together with this interval. Throws: $(LREF DateTimeException) if this interval is empty. Example: -------------------- assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span( NegInfInterval!Date(Date(1602, 5, 21))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span( NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12))); -------------------- +/ NegInfInterval!TP span(in NegInfInterval!TP interval) const pure { _enforceNotEmpty(); return NegInfInterval!TP(_end > interval._end ? _end : interval._end); } /++ Shifts the interval forward or backwards in time by the given duration (a positive duration shifts the interval forward; a negative duration shifts it backward). Effectively, it does $(D begin += duration) and $(D end += duration). Params: duration = The duration to shift the interval by. Throws: $(LREF DateTimeException) this interval is empty or if the resulting interval would be invalid. Example: -------------------- auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5)); auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5)); interval1.shift(dur!"days"(50)); assert(interval1 == Interval!Date(Date(1996, 2, 21), Date(2012, 5, 25))); interval2.shift(dur!"days"(-50)); assert(interval2 == Interval!Date(Date(1995, 11, 13), Date(2012, 2, 15))); -------------------- +/ void shift(D)(D duration) pure if(__traits(compiles, begin + duration)) { _enforceNotEmpty(); auto begin = _begin + duration; auto end = _end + duration; if(!_valid(begin, end)) throw new DateTimeException("Argument would result in an invalid Interval."); _begin = begin; _end = end; } static if(__traits(compiles, begin.add!"months"(1)) && __traits(compiles, begin.add!"years"(1))) { /++ Shifts the interval forward or backwards in time by the given number of years and/or months (a positive number of years and months shifts the interval forward; a negative number shifts it backward). It adds the years the given years and months to both begin and end. It effectively calls $(D add!"years"()) and then $(D add!"months"()) on begin and end with the given number of years and months. Params: years = The number of years to shift the interval by. months = The number of months to shift the interval by. allowOverflow = Whether the days should be allowed to overflow on $(D begin) and $(D end), causing their month to increment. Throws: $(LREF DateTimeException) if this interval is empty or if the resulting interval would be invalid. Example: -------------------- auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); interval1.shift(2); assert(interval1 == Interval!Date(Date(1998, 1, 2), Date(2014, 3, 1))); interval2.shift(-2); assert(interval2 == Interval!Date(Date(1994, 1, 2), Date(2010, 3, 1))); -------------------- +/ void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) if(isIntegral!T) { _enforceNotEmpty(); auto begin = _begin; auto end = _end; begin.add!"years"(years, allowOverflow); begin.add!"months"(months, allowOverflow); end.add!"years"(years, allowOverflow); end.add!"months"(months, allowOverflow); enforce(_valid(begin, end), new DateTimeException("Argument would result in an invalid Interval.")); _begin = begin; _end = end; } } /++ Expands the interval forwards and/or backwards in time. Effectively, it does $(D begin -= duration) and/or $(D end += duration). Whether it expands forwards and/or backwards in time is determined by $(D_PARAM dir). Params: duration = The duration to expand the interval by. dir = The direction in time to expand the interval. Throws: $(LREF DateTimeException) this interval is empty or if the resulting interval would be invalid. Example: -------------------- auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); interval1.expand(2); assert(interval1 == Interval!Date(Date(1994, 1, 2), Date(2014, 3, 1))); interval2.expand(-2); assert(interval2 == Interval!Date(Date(1998, 1, 2), Date(2010, 3, 1))); -------------------- +/ void expand(D)(D duration, Direction dir = Direction.both) pure if(__traits(compiles, begin + duration)) { _enforceNotEmpty(); switch(dir) { case Direction.both: { auto begin = _begin - duration; auto end = _end + duration; if(!_valid(begin, end)) throw new DateTimeException("Argument would result in an invalid Interval."); _begin = begin; _end = end; return; } case Direction.fwd: { auto end = _end + duration; if(!_valid(_begin, end)) throw new DateTimeException("Argument would result in an invalid Interval."); _end = end; return; } case Direction.bwd: { auto begin = _begin - duration; if(!_valid(begin, _end)) throw new DateTimeException("Argument would result in an invalid Interval."); _begin = begin; return; } default: assert(0, "Invalid Direction."); } } static if(__traits(compiles, begin.add!"months"(1)) && __traits(compiles, begin.add!"years"(1))) { /++ Expands the interval forwards and/or backwards in time. Effectively, it subtracts the given number of months/years from $(D begin) and adds them to $(D end). Whether it expands forwards and/or backwards in time is determined by $(D_PARAM dir). Params: years = The number of years to expand the interval by. months = The number of months to expand the interval by. allowOverflow = Whether the days should be allowed to overflow on $(D begin) and $(D end), causing their month to increment. dir = The direction in time to expand the interval. Throws: $(LREF DateTimeException) if this interval is empty or if the resulting interval would be invalid. Example: -------------------- auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); interval1.expand(2); assert(interval1 == Interval!Date(Date(1994, 1, 2), Date(2014, 3, 1))); interval2.expand(-2); assert(interval2 == Interval!Date(Date(1998, 1, 2), Date(2010, 3, 1))); -------------------- +/ void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes, Direction dir = Direction.both) if(isIntegral!T) { _enforceNotEmpty(); switch(dir) { case Direction.both: { auto begin = _begin; auto end = _end; begin.add!"years"(-years, allowOverflow); begin.add!"months"(-months, allowOverflow); end.add!"years"(years, allowOverflow); end.add!"months"(months, allowOverflow); enforce(_valid(begin, end), new DateTimeException("Argument would result in an invalid Interval.")); _begin = begin; _end = end; return; } case Direction.fwd: { auto end = _end; end.add!"years"(years, allowOverflow); end.add!"months"(months, allowOverflow); enforce(_valid(_begin, end), new DateTimeException("Argument would result in an invalid Interval.")); _end = end; return; } case Direction.bwd: { auto begin = _begin; begin.add!"years"(-years, allowOverflow); begin.add!"months"(-months, allowOverflow); enforce(_valid(begin, _end), new DateTimeException("Argument would result in an invalid Interval.")); _begin = begin; return; } default: assert(0, "Invalid Direction."); } } } /++ Returns a range which iterates forward over the interval, starting at $(D begin), using $(D_PARAM func) to generate each successive time point. The range's $(D front) is the interval's $(D begin). $(D_PARAM func) is used to generate the next $(D front) when $(D popFront) is called. If $(D_PARAM popFirst) is $(D PopFirst.yes), then $(D popFront) is called before the range is returned (so that $(D front) is a time point which $(D_PARAM func) would generate). If $(D_PARAM func) ever generates a time point less than or equal to the current $(D front) of the range, then a $(LREF DateTimeException) will be thrown. The range will be empty and iteration complete when $(D_PARAM func) generates a time point equal to or beyond the $(D end) of the interval. There are helper functions in this module which generate common delegates to pass to $(D fwdRange). Their documentation starts with "Range-generating function," making them easily searchable. Params: func = The function used to generate the time points of the range over the interval. popFirst = Whether $(D popFront) should be called on the range before returning it. Throws: $(LREF DateTimeException) if this interval is empty. Warning: $(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func) would be a function pointer to a pure function, but forcing $(D_PARAM func) to be pure is far too restrictive to be useful, and in order to have the ease of use of having functions which generate functions to pass to $(D fwdRange), $(D_PARAM func) must be a delegate. If $(D_PARAM func) retains state which changes as it is called, then some algorithms will not work correctly, because the range's $(D save) will have failed to have really saved the range's state. To avoid such bugs, don't pass a delegate which is not logically pure to $(D fwdRange). If $(D_PARAM func) is given the same time point with two different calls, it must return the same result both times. Of course, none of the functions in this module have this problem, so it's only relevant if when creating a custom delegate. Example: -------------------- auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9)); auto func = delegate (in Date date) //For iterating over even-numbered days. { if((date.day & 1) == 0) return date + dur!"days"(2); return date + dur!"days"(1); }; auto range = interval.fwdRange(func); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2). assert(range.front == Date(2010, 9, 1)); range.popFront(); assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(range.front == Date(2010, 9, 4)); range.popFront(); assert(range.front == Date(2010, 9, 6)); range.popFront(); assert(range.front == Date(2010, 9, 8)); range.popFront(); assert(range.empty); -------------------- +/ IntervalRange!(TP, Direction.fwd) fwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no) const { _enforceNotEmpty(); auto range = IntervalRange!(TP, Direction.fwd)(this, func); if(popFirst == PopFirst.yes) range.popFront(); return range; } /++ Returns a range which iterates backwards over the interval, starting at $(D end), using $(D_PARAM func) to generate each successive time point. The range's $(D front) is the interval's $(D end). $(D_PARAM func) is used to generate the next $(D front) when $(D popFront) is called. If $(D_PARAM popFirst) is $(D PopFirst.yes), then $(D popFront) is called before the range is returned (so that $(D front) is a time point which $(D_PARAM func) would generate). If $(D_PARAM func) ever generates a time point greater than or equal to the current $(D front) of the range, then a $(LREF DateTimeException) will be thrown. The range will be empty and iteration complete when $(D_PARAM func) generates a time point equal to or less than the $(D begin) of the interval. There are helper functions in this module which generate common delegates to pass to $(D bwdRange). Their documentation starts with "Range-generating function," making them easily searchable. Params: func = The function used to generate the time points of the range over the interval. popFirst = Whether $(D popFront) should be called on the range before returning it. Throws: $(LREF DateTimeException) if this interval is empty. Warning: $(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func) would be a function pointer to a pure function, but forcing $(D_PARAM func) to be pure is far too restrictive to be useful, and in order to have the ease of use of having functions which generate functions to pass to $(D fwdRange), $(D_PARAM func) must be a delegate. If $(D_PARAM func) retains state which changes as it is called, then some algorithms will not work correctly, because the range's $(D save) will have failed to have really saved the range's state. To avoid such bugs, don't pass a delegate which is not logically pure to $(D fwdRange). If $(D_PARAM func) is given the same time point with two different calls, it must return the same result both times. Of course, none of the functions in this module have this problem, so it's only relevant for custom delegates. Example: -------------------- auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9)); auto func = delegate (in Date date) //For iterating over even-numbered days. { if((date.day & 1) == 0) return date - dur!"days"(2); return date - dur!"days"(1); }; auto range = interval.bwdRange(func); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8). assert(range.front == Date(2010, 9, 9)); range.popFront(); assert(range.front == Date(2010, 9, 8)); range.popFront(); assert(range.front == Date(2010, 9, 6)); range.popFront(); assert(range.front == Date(2010, 9, 4)); range.popFront(); assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(range.empty); -------------------- +/ IntervalRange!(TP, Direction.bwd) bwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no) const { _enforceNotEmpty(); auto range = IntervalRange!(TP, Direction.bwd)(this, func); if(popFirst == PopFirst.yes) range.popFront(); return range; } /+ Converts this interval to a string. +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() { return _toStringImpl(); } /++ Converts this interval to a string. +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() const nothrow { return _toStringImpl(); } private: /+ Since we have two versions of toString, we have _toStringImpl so that they can share implementations. +/ string _toStringImpl() const nothrow { import std.format : format; try return format("[%s - %s)", _begin, _end); catch(Exception e) assert(0, "format() threw."); } /+ Throws: $(LREF DateTimeException) if this interval is empty. +/ void _enforceNotEmpty(size_t line = __LINE__) const pure { if(empty) throw new DateTimeException("Invalid operation for an empty Interval.", __FILE__, line); } /+ Whether the given values form a valid time interval. Params: begin = The starting point of the interval. end = The end point of the interval. +/ static bool _valid(in TP begin, in TP end) pure nothrow { return begin <= end; } pure invariant() { assert(_valid(_begin, _end), "Invariant Failure: begin is not before or equal to end."); } TP _begin; TP _end; } //Test Interval's constructors. unittest { assertThrown!DateTimeException(Interval!Date(Date(2010, 1, 1), Date(1, 1, 1))); Interval!Date(Date.init, Date.init); Interval!TimeOfDay(TimeOfDay.init, TimeOfDay.init); Interval!DateTime(DateTime.init, DateTime.init); Interval!SysTime(SysTime(0), SysTime(0)); Interval!DateTime(DateTime.init, dur!"days"(7)); //Verify Examples. Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); assert(Interval!Date(Date(1996, 1, 2), dur!"weeks"(3)) == Interval!Date(Date(1996, 1, 2), Date(1996, 1, 23))); assert(Interval!Date(Date(1996, 1, 2), dur!"days"(3)) == Interval!Date(Date(1996, 1, 2), Date(1996, 1, 5))); assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"hours"(3)) == Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 15, 0, 0))); assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"minutes"(3)) == Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 12, 3, 0))); assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"seconds"(3)) == Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 12, 0, 3))); assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"msecs"(3000)) == Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 12, 0, 3))); } //Test Interval's begin. unittest { assert(Interval!Date(Date(1, 1, 1), Date(2010, 1, 1)).begin == Date(1, 1, 1)); assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).begin == Date(2010, 1, 1)); assert(Interval!Date(Date(1997, 12, 31), Date(1998, 1, 1)).begin == Date(1997, 12, 31)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(cInterval.begin == Date(2010, 7, 4)); assert(iInterval.begin == Date(2010, 7, 4)); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).begin == Date(1996, 1, 2)); } //Test Interval's end. unittest { assert(Interval!Date(Date(1, 1, 1), Date(2010, 1, 1)).end == Date(2010, 1, 1)); assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).end == Date(2010, 1, 1)); assert(Interval!Date(Date(1997, 12, 31), Date(1998, 1, 1)).end == Date(1998, 1, 1)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(cInterval.end == Date(2012, 1, 7)); assert(iInterval.end == Date(2012, 1, 7)); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).end == Date(2012, 3, 1)); } //Test Interval's length. unittest { assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).length == dur!"days"(0)); assert(Interval!Date(Date(2010, 1, 1), Date(2010, 4, 1)).length == dur!"days"(90)); assert(Interval!TimeOfDay(TimeOfDay(0, 30, 0), TimeOfDay(12, 22, 7)).length == dur!"seconds"(42_727)); assert(Interval!DateTime(DateTime(2010, 1, 1, 0, 30, 0), DateTime(2010, 1, 2, 12, 22, 7)).length == dur!"seconds"(129_127)); assert(Interval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0)), SysTime(DateTime(2010, 1, 2, 12, 22, 7))).length == dur!"seconds"(129_127)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(cInterval.length != Duration.zero); assert(iInterval.length != Duration.zero); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).length == dur!"days"(5903)); } //Test Interval's empty. unittest { assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).empty); assert(!Interval!Date(Date(2010, 1, 1), Date(2010, 4, 1)).empty); assert(!Interval!TimeOfDay(TimeOfDay(0, 30, 0), TimeOfDay(12, 22, 7)).empty); assert(!Interval!DateTime(DateTime(2010, 1, 1, 0, 30, 0), DateTime(2010, 1, 2, 12, 22, 7)).empty); assert(!Interval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0)), SysTime(DateTime(2010, 1, 2, 12, 22, 7))).empty); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(!cInterval.empty); assert(!iInterval.empty); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(1996, 1, 2)).empty); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).empty); } //Test Interval's contains(time point). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).contains(Date(2010, 7, 4))); assert(!interval.contains(Date(2009, 7, 4))); assert(!interval.contains(Date(2010, 7, 3))); assert(interval.contains(Date(2010, 7, 4))); assert(interval.contains(Date(2010, 7, 5))); assert(interval.contains(Date(2011, 7, 1))); assert(interval.contains(Date(2012, 1, 6))); assert(!interval.contains(Date(2012, 1, 7))); assert(!interval.contains(Date(2012, 1, 8))); assert(!interval.contains(Date(2013, 1, 7))); const cdate = Date(2010, 7, 6); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(interval.contains(cdate)); assert(cInterval.contains(cdate)); assert(iInterval.contains(cdate)); //Verify Examples. assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(1994, 12, 24))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(2000, 1, 5))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(2012, 3, 1))); } //Test Interval's contains(Interval). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assertThrown!DateTimeException(interval.contains(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).contains(interval)); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).contains(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(interval.contains(interval)); assert(!interval.contains(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!interval.contains(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(interval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(interval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(interval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!interval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(!interval.contains(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!interval.contains(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).contains(interval)); assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).contains(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).contains(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).contains(interval)); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).contains(interval)); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).contains(interval)); assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).contains(interval)); assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).contains(interval)); assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).contains(interval)); assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).contains(interval)); assert(!Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).contains(interval)); assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).contains(interval)); assert(!interval.contains(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!interval.contains(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!interval.contains(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!interval.contains(PosInfInterval!Date(Date(2012, 1, 6)))); assert(!interval.contains(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!interval.contains(PosInfInterval!Date(Date(2012, 1, 8)))); assert(!interval.contains(NegInfInterval!Date(Date(2010, 7, 3)))); assert(!interval.contains(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!interval.contains(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!interval.contains(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!interval.contains(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!interval.contains(NegInfInterval!Date(Date(2012, 1, 8)))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(interval.contains(interval)); assert(interval.contains(cInterval)); assert(interval.contains(iInterval)); assert(!interval.contains(posInfInterval)); assert(!interval.contains(cPosInfInterval)); assert(!interval.contains(iPosInfInterval)); assert(!interval.contains(negInfInterval)); assert(!interval.contains(cNegInfInterval)); assert(!interval.contains(iNegInfInterval)); assert(cInterval.contains(interval)); assert(cInterval.contains(cInterval)); assert(cInterval.contains(iInterval)); assert(!cInterval.contains(posInfInterval)); assert(!cInterval.contains(cPosInfInterval)); assert(!cInterval.contains(iPosInfInterval)); assert(!cInterval.contains(negInfInterval)); assert(!cInterval.contains(cNegInfInterval)); assert(!cInterval.contains(iNegInfInterval)); assert(iInterval.contains(interval)); assert(iInterval.contains(cInterval)); assert(iInterval.contains(iInterval)); assert(!iInterval.contains(posInfInterval)); assert(!iInterval.contains(cPosInfInterval)); assert(!iInterval.contains(iPosInfInterval)); assert(!iInterval.contains(negInfInterval)); assert(!iInterval.contains(cNegInfInterval)); assert(!iInterval.contains(iNegInfInterval)); //Verify Examples. assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(PosInfInterval!Date(Date(1999, 5, 4)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(1996, 5, 4)))); } //Test Interval's isBefore(time point). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isBefore(Date(2010, 7, 4))); assert(!interval.isBefore(Date(2009, 7, 3))); assert(!interval.isBefore(Date(2010, 7, 3))); assert(!interval.isBefore(Date(2010, 7, 4))); assert(!interval.isBefore(Date(2010, 7, 5))); assert(!interval.isBefore(Date(2011, 7, 1))); assert(!interval.isBefore(Date(2012, 1, 6))); assert(interval.isBefore(Date(2012, 1, 7))); assert(interval.isBefore(Date(2012, 1, 8))); assert(interval.isBefore(Date(2013, 1, 7))); const cdate = Date(2010, 7, 6); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(!interval.isBefore(cdate)); assert(!cInterval.isBefore(cdate)); assert(!iInterval.isBefore(cdate)); //Verify Examples. assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(1994, 12, 24))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(2000, 1, 5))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(2012, 3, 1))); } //Test Interval's isBefore(Interval). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assertThrown!DateTimeException(interval.isBefore(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isBefore(interval)); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isBefore(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(!interval.isBefore(interval)); assert(!interval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!interval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(!interval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(!interval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(!interval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!interval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(interval.isBefore(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(interval.isBefore(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).isBefore(interval)); assert(!Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).isBefore(interval)); assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).isBefore(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).isBefore(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).isBefore(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).isBefore(interval)); assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).isBefore(interval)); assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).isBefore(interval)); assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).isBefore(interval)); assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).isBefore(interval)); assert(!Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).isBefore(interval)); assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).isBefore(interval)); assert(!interval.isBefore(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!interval.isBefore(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!interval.isBefore(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!interval.isBefore(PosInfInterval!Date(Date(2012, 1, 6)))); assert(interval.isBefore(PosInfInterval!Date(Date(2012, 1, 7)))); assert(interval.isBefore(PosInfInterval!Date(Date(2012, 1, 8)))); assert(!interval.isBefore(NegInfInterval!Date(Date(2010, 7, 3)))); assert(!interval.isBefore(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!interval.isBefore(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!interval.isBefore(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!interval.isBefore(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!interval.isBefore(NegInfInterval!Date(Date(2012, 1, 8)))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!interval.isBefore(interval)); assert(!interval.isBefore(cInterval)); assert(!interval.isBefore(iInterval)); assert(!interval.isBefore(posInfInterval)); assert(!interval.isBefore(cPosInfInterval)); assert(!interval.isBefore(iPosInfInterval)); assert(!interval.isBefore(negInfInterval)); assert(!interval.isBefore(cNegInfInterval)); assert(!interval.isBefore(iNegInfInterval)); assert(!cInterval.isBefore(interval)); assert(!cInterval.isBefore(cInterval)); assert(!cInterval.isBefore(iInterval)); assert(!cInterval.isBefore(posInfInterval)); assert(!cInterval.isBefore(cPosInfInterval)); assert(!cInterval.isBefore(iPosInfInterval)); assert(!cInterval.isBefore(negInfInterval)); assert(!cInterval.isBefore(cNegInfInterval)); assert(!cInterval.isBefore(iNegInfInterval)); assert(!iInterval.isBefore(interval)); assert(!iInterval.isBefore(cInterval)); assert(!iInterval.isBefore(iInterval)); assert(!iInterval.isBefore(posInfInterval)); assert(!iInterval.isBefore(cPosInfInterval)); assert(!iInterval.isBefore(iPosInfInterval)); assert(!iInterval.isBefore(negInfInterval)); assert(!iInterval.isBefore(cNegInfInterval)); assert(!iInterval.isBefore(iNegInfInterval)); //Verify Examples. assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 1)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(1999, 5, 4)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(2013, 3, 7)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(1996, 5, 4)))); } //Test Interval's isAfter(time point). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isAfter(Date(2010, 7, 4))); assert(interval.isAfter(Date(2009, 7, 4))); assert(interval.isAfter(Date(2010, 7, 3))); assert(!interval.isAfter(Date(2010, 7, 4))); assert(!interval.isAfter(Date(2010, 7, 5))); assert(!interval.isAfter(Date(2011, 7, 1))); assert(!interval.isAfter(Date(2012, 1, 6))); assert(!interval.isAfter(Date(2012, 1, 7))); assert(!interval.isAfter(Date(2012, 1, 8))); assert(!interval.isAfter(Date(2013, 1, 7))); const cdate = Date(2010, 7, 6); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(!interval.isAfter(cdate)); assert(!cInterval.isAfter(cdate)); assert(!iInterval.isAfter(cdate)); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(1994, 12, 24))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(2000, 1, 5))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(2012, 3, 1))); } //Test Interval's isAfter(Interval). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assertThrown!DateTimeException(interval.isAfter(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isAfter(interval)); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isAfter(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(!interval.isAfter(interval)); assert(interval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!interval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(!interval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(!interval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(!interval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!interval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(!interval.isAfter(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!interval.isAfter(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).isAfter(interval)); assert(!Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).isAfter(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).isAfter(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).isAfter(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).isAfter(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).isAfter(interval)); assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).isAfter(interval)); assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).isAfter(interval)); assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).isAfter(interval)); assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).isAfter(interval)); assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).isAfter(interval)); assert(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).isAfter(interval)); assert(!interval.isAfter(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!interval.isAfter(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!interval.isAfter(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!interval.isAfter(PosInfInterval!Date(Date(2012, 1, 6)))); assert(!interval.isAfter(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!interval.isAfter(PosInfInterval!Date(Date(2012, 1, 8)))); assert(interval.isAfter(NegInfInterval!Date(Date(2010, 7, 3)))); assert(interval.isAfter(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!interval.isAfter(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!interval.isAfter(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!interval.isAfter(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!interval.isAfter(NegInfInterval!Date(Date(2012, 1, 8)))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!interval.isAfter(interval)); assert(!interval.isAfter(cInterval)); assert(!interval.isAfter(iInterval)); assert(!interval.isAfter(posInfInterval)); assert(!interval.isAfter(cPosInfInterval)); assert(!interval.isAfter(iPosInfInterval)); assert(!interval.isAfter(negInfInterval)); assert(!interval.isAfter(cNegInfInterval)); assert(!interval.isAfter(iNegInfInterval)); assert(!cInterval.isAfter(interval)); assert(!cInterval.isAfter(cInterval)); assert(!cInterval.isAfter(iInterval)); assert(!cInterval.isAfter(posInfInterval)); assert(!cInterval.isAfter(cPosInfInterval)); assert(!cInterval.isAfter(iPosInfInterval)); assert(!cInterval.isAfter(negInfInterval)); assert(!cInterval.isAfter(cNegInfInterval)); assert(!cInterval.isAfter(iNegInfInterval)); assert(!iInterval.isAfter(interval)); assert(!iInterval.isAfter(cInterval)); assert(!iInterval.isAfter(iInterval)); assert(!iInterval.isAfter(posInfInterval)); assert(!iInterval.isAfter(cPosInfInterval)); assert(!iInterval.isAfter(iPosInfInterval)); assert(!iInterval.isAfter(negInfInterval)); assert(!iInterval.isAfter(cNegInfInterval)); assert(!iInterval.isAfter(iNegInfInterval)); //Verify Examples. assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(1999, 5, 4)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(1996, 1, 2)))); } //Test Interval's intersects(). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assertThrown!DateTimeException(interval.intersects(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersects(interval)); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersects(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(interval.intersects(interval)); assert(!interval.intersects(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(interval.intersects(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(!interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(interval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(interval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(interval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(interval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(!interval.intersects(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!interval.intersects(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).intersects(interval)); assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).intersects(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).intersects(interval)); assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).intersects(interval)); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).intersects(interval)); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).intersects(interval)); assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).intersects(interval)); assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).intersects(interval)); assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).intersects(interval)); assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).intersects(interval)); assert(!Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).intersects(interval)); assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).intersects(interval)); assert(interval.intersects(PosInfInterval!Date(Date(2010, 7, 3)))); assert(interval.intersects(PosInfInterval!Date(Date(2010, 7, 4)))); assert(interval.intersects(PosInfInterval!Date(Date(2010, 7, 5)))); assert(interval.intersects(PosInfInterval!Date(Date(2012, 1, 6)))); assert(!interval.intersects(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!interval.intersects(PosInfInterval!Date(Date(2012, 1, 8)))); assert(!interval.intersects(NegInfInterval!Date(Date(2010, 7, 3)))); assert(!interval.intersects(NegInfInterval!Date(Date(2010, 7, 4)))); assert(interval.intersects(NegInfInterval!Date(Date(2010, 7, 5)))); assert(interval.intersects(NegInfInterval!Date(Date(2012, 1, 6)))); assert(interval.intersects(NegInfInterval!Date(Date(2012, 1, 7)))); assert(interval.intersects(NegInfInterval!Date(Date(2012, 1, 8)))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(interval.intersects(interval)); assert(interval.intersects(cInterval)); assert(interval.intersects(iInterval)); assert(interval.intersects(posInfInterval)); assert(interval.intersects(cPosInfInterval)); assert(interval.intersects(iPosInfInterval)); assert(interval.intersects(negInfInterval)); assert(interval.intersects(cNegInfInterval)); assert(interval.intersects(iNegInfInterval)); assert(cInterval.intersects(interval)); assert(cInterval.intersects(cInterval)); assert(cInterval.intersects(iInterval)); assert(cInterval.intersects(posInfInterval)); assert(cInterval.intersects(cPosInfInterval)); assert(cInterval.intersects(iPosInfInterval)); assert(cInterval.intersects(negInfInterval)); assert(cInterval.intersects(cNegInfInterval)); assert(cInterval.intersects(iNegInfInterval)); assert(iInterval.intersects(interval)); assert(iInterval.intersects(cInterval)); assert(iInterval.intersects(iInterval)); assert(iInterval.intersects(posInfInterval)); assert(iInterval.intersects(cPosInfInterval)); assert(iInterval.intersects(iPosInfInterval)); assert(iInterval.intersects(negInfInterval)); assert(iInterval.intersects(cNegInfInterval)); assert(iInterval.intersects(iNegInfInterval)); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(1999, 5, 4)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(2012, 3, 1)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(1996, 1, 2)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(2000, 1, 2)))); } //Test Interval's intersection(). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersection(interval)); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersection(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).intersection(interval)); assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).intersection(interval)); assertThrown!DateTimeException(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).intersection(interval)); assertThrown!DateTimeException(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).intersection(interval)); assertThrown!DateTimeException(interval.intersection(PosInfInterval!Date(Date(2012, 1, 7)))); assertThrown!DateTimeException(interval.intersection(PosInfInterval!Date(Date(2012, 1, 8)))); assertThrown!DateTimeException(interval.intersection(NegInfInterval!Date(Date(2010, 7, 3)))); assertThrown!DateTimeException(interval.intersection(NegInfInterval!Date(Date(2010, 7, 4)))); assert(interval.intersection(interval) == interval); assert(interval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) == Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5))); assert(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) == Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))); assert(interval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))); assert(interval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) == Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))); assert(interval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) == Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).intersection(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).intersection(interval) == Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5))); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).intersection(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).intersection(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).intersection(interval) == Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))); assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).intersection(interval) == Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))); assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).intersection(interval) == Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))); assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).intersection(interval) == Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))); assert(interval.intersection(PosInfInterval!Date(Date(2010, 7, 3))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.intersection(PosInfInterval!Date(Date(2010, 7, 4))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.intersection(PosInfInterval!Date(Date(2010, 7, 5))) == Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))); assert(interval.intersection(PosInfInterval!Date(Date(2012, 1, 6))) == Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))); assert(interval.intersection(NegInfInterval!Date(Date(2010, 7, 5))) == Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5))); assert(interval.intersection(NegInfInterval!Date(Date(2012, 1, 6))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 6))); assert(interval.intersection(NegInfInterval!Date(Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.intersection(NegInfInterval!Date(Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!interval.intersection(interval).empty); assert(!interval.intersection(cInterval).empty); assert(!interval.intersection(iInterval).empty); assert(!interval.intersection(posInfInterval).empty); assert(!interval.intersection(cPosInfInterval).empty); assert(!interval.intersection(iPosInfInterval).empty); assert(!interval.intersection(negInfInterval).empty); assert(!interval.intersection(cNegInfInterval).empty); assert(!interval.intersection(iNegInfInterval).empty); assert(!cInterval.intersection(interval).empty); assert(!cInterval.intersection(cInterval).empty); assert(!cInterval.intersection(iInterval).empty); assert(!cInterval.intersection(posInfInterval).empty); assert(!cInterval.intersection(cPosInfInterval).empty); assert(!cInterval.intersection(iPosInfInterval).empty); assert(!cInterval.intersection(negInfInterval).empty); assert(!cInterval.intersection(cNegInfInterval).empty); assert(!cInterval.intersection(iNegInfInterval).empty); assert(!iInterval.intersection(interval).empty); assert(!iInterval.intersection(cInterval).empty); assert(!iInterval.intersection(iInterval).empty); assert(!iInterval.intersection(posInfInterval).empty); assert(!iInterval.intersection(cPosInfInterval).empty); assert(!iInterval.intersection(iPosInfInterval).empty); assert(!iInterval.intersection(negInfInterval).empty); assert(!iInterval.intersection(cNegInfInterval).empty); assert(!iInterval.intersection(iNegInfInterval).empty); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) == Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1))); } //Test Interval's isAdjacent(). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); static void testInterval(in Interval!Date interval1, in Interval!Date interval2) { interval1.isAdjacent(interval2); } assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), interval)); assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(!interval.isAdjacent(interval)); assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(!interval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!interval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(interval.isAdjacent(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!interval.isAdjacent(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).isAdjacent(interval)); assert(!Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).isAdjacent(interval)); assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).isAdjacent(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).isAdjacent(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).isAdjacent(interval)); assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).isAdjacent(interval)); assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).isAdjacent(interval)); assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).isAdjacent(interval)); assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).isAdjacent(interval)); assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).isAdjacent(interval)); assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).isAdjacent(interval)); assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).isAdjacent(interval)); assert(!interval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!interval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!interval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!interval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 6)))); assert(interval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!interval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 8)))); assert(!interval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 3)))); assert(interval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!interval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!interval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!interval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!interval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 8)))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!interval.isAdjacent(interval)); assert(!interval.isAdjacent(cInterval)); assert(!interval.isAdjacent(iInterval)); assert(!interval.isAdjacent(posInfInterval)); assert(!interval.isAdjacent(cPosInfInterval)); assert(!interval.isAdjacent(iPosInfInterval)); assert(!interval.isAdjacent(negInfInterval)); assert(!interval.isAdjacent(cNegInfInterval)); assert(!interval.isAdjacent(iNegInfInterval)); assert(!cInterval.isAdjacent(interval)); assert(!cInterval.isAdjacent(cInterval)); assert(!cInterval.isAdjacent(iInterval)); assert(!cInterval.isAdjacent(posInfInterval)); assert(!cInterval.isAdjacent(cPosInfInterval)); assert(!cInterval.isAdjacent(iPosInfInterval)); assert(!cInterval.isAdjacent(negInfInterval)); assert(!cInterval.isAdjacent(cNegInfInterval)); assert(!cInterval.isAdjacent(iNegInfInterval)); assert(!iInterval.isAdjacent(interval)); assert(!iInterval.isAdjacent(cInterval)); assert(!iInterval.isAdjacent(iInterval)); assert(!iInterval.isAdjacent(posInfInterval)); assert(!iInterval.isAdjacent(cPosInfInterval)); assert(!iInterval.isAdjacent(iPosInfInterval)); assert(!iInterval.isAdjacent(negInfInterval)); assert(!iInterval.isAdjacent(cNegInfInterval)); assert(!iInterval.isAdjacent(iNegInfInterval)); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1990, 7, 6), Date(1996, 1, 2)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2012, 3, 1), Date(2013, 9, 17)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1989, 3, 1), Date(2012, 3, 1)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(1999, 5, 4)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(2012, 3, 1)))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(1996, 1, 2)))); assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(2000, 1, 2)))); } //Test Interval's merge(). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); static void testInterval(I)(in Interval!Date interval1, in I interval2) { interval1.merge(interval2); } assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), interval)); assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)), interval)); assertThrown!DateTimeException(testInterval(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)), interval)); assertThrown!DateTimeException(testInterval(interval, PosInfInterval!Date(Date(2012, 1, 8)))); assertThrown!DateTimeException(testInterval(interval, NegInfInterval!Date(Date(2010, 7, 3)))); assert(interval.merge(interval) == interval); assert(interval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) == Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))); assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))); assert(interval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); assert(interval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).merge(interval) == Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))); assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).merge(interval) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).merge(interval) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).merge(interval) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).merge(interval) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))); assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).merge(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).merge(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).merge(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).merge(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).merge(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); assert(interval.merge(PosInfInterval!Date(Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(interval.merge(PosInfInterval!Date(Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(interval.merge(PosInfInterval!Date(Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(interval.merge(PosInfInterval!Date(Date(2012, 1, 6))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(interval.merge(PosInfInterval!Date(Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(interval.merge(NegInfInterval!Date(Date(2010, 7, 4))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(interval.merge(NegInfInterval!Date(Date(2010, 7, 5))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(interval.merge(NegInfInterval!Date(Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(interval.merge(NegInfInterval!Date(Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(interval.merge(NegInfInterval!Date(Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!interval.merge(interval).empty); assert(!interval.merge(cInterval).empty); assert(!interval.merge(iInterval).empty); assert(!interval.merge(posInfInterval).empty); assert(!interval.merge(cPosInfInterval).empty); assert(!interval.merge(iPosInfInterval).empty); assert(!interval.merge(negInfInterval).empty); assert(!interval.merge(cNegInfInterval).empty); assert(!interval.merge(iNegInfInterval).empty); assert(!cInterval.merge(interval).empty); assert(!cInterval.merge(cInterval).empty); assert(!cInterval.merge(iInterval).empty); assert(!cInterval.merge(posInfInterval).empty); assert(!cInterval.merge(cPosInfInterval).empty); assert(!cInterval.merge(iPosInfInterval).empty); assert(!cInterval.merge(negInfInterval).empty); assert(!cInterval.merge(cNegInfInterval).empty); assert(!cInterval.merge(iNegInfInterval).empty); assert(!iInterval.merge(interval).empty); assert(!iInterval.merge(cInterval).empty); assert(!iInterval.merge(iInterval).empty); assert(!iInterval.merge(posInfInterval).empty); assert(!iInterval.merge(cPosInfInterval).empty); assert(!iInterval.merge(iPosInfInterval).empty); assert(!iInterval.merge(negInfInterval).empty); assert(!iInterval.merge(cNegInfInterval).empty); assert(!iInterval.merge(iNegInfInterval).empty); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(PosInfInterval!Date(Date(2012, 3, 1))) == PosInfInterval!Date(Date(1996, 1 , 2))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(1996, 1, 2))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12))); } //Test Interval's span(). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); static void testInterval(in Interval!Date interval1, in Interval!Date interval2) { interval1.span(interval2); } assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), interval)); assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(interval.span(interval) == interval); assert(interval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) == Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7))); assert(interval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) == Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))); assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))); assert(interval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(interval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); assert(interval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); assert(interval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 9))); assert(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).span(interval) == Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).span(interval) == Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))); assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).span(interval) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).span(interval) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).span(interval) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).span(interval) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))); assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).span(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).span(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).span(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).span(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).span(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); assert(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).span(interval) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 9))); assert(interval.span(PosInfInterval!Date(Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(interval.span(PosInfInterval!Date(Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(interval.span(PosInfInterval!Date(Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(interval.span(PosInfInterval!Date(Date(2012, 1, 6))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(interval.span(PosInfInterval!Date(Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(interval.span(PosInfInterval!Date(Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(interval.span(NegInfInterval!Date(Date(2010, 7, 3))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(interval.span(NegInfInterval!Date(Date(2010, 7, 4))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(interval.span(NegInfInterval!Date(Date(2010, 7, 5))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(interval.span(NegInfInterval!Date(Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(interval.span(NegInfInterval!Date(Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(interval.span(NegInfInterval!Date(Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!interval.span(interval).empty); assert(!interval.span(cInterval).empty); assert(!interval.span(iInterval).empty); assert(!interval.span(posInfInterval).empty); assert(!interval.span(cPosInfInterval).empty); assert(!interval.span(iPosInfInterval).empty); assert(!interval.span(negInfInterval).empty); assert(!interval.span(cNegInfInterval).empty); assert(!interval.span(iNegInfInterval).empty); assert(!cInterval.span(interval).empty); assert(!cInterval.span(cInterval).empty); assert(!cInterval.span(iInterval).empty); assert(!cInterval.span(posInfInterval).empty); assert(!cInterval.span(cPosInfInterval).empty); assert(!cInterval.span(iPosInfInterval).empty); assert(!cInterval.span(negInfInterval).empty); assert(!cInterval.span(cNegInfInterval).empty); assert(!cInterval.span(iNegInfInterval).empty); assert(!iInterval.span(interval).empty); assert(!iInterval.span(cInterval).empty); assert(!iInterval.span(iInterval).empty); assert(!iInterval.span(posInfInterval).empty); assert(!iInterval.span(cPosInfInterval).empty); assert(!iInterval.span(iPosInfInterval).empty); assert(!iInterval.span(negInfInterval).empty); assert(!iInterval.span(cNegInfInterval).empty); assert(!iInterval.span(iNegInfInterval).empty); //Verify Examples. assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(Interval!Date(Date(1990, 7, 6), Date(1991, 1, 8))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(PosInfInterval!Date(Date(2050, 1, 1))) == PosInfInterval!Date(Date(1996, 1 , 2))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(NegInfInterval!Date(Date(1602, 5, 21))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12))); } //Test Interval's shift(duration). unittest { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); static void testIntervalFail(Interval!Date interval, in Duration duration) { interval.shift(duration); } assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), dur!"days"(1))); static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__) { interval.shift(duration); assert(interval == expected); } testInterval(interval, dur!"days"(22), Interval!Date(Date(2010, 7, 26), Date(2012, 1, 29))); testInterval(interval, dur!"days"(-22), Interval!Date(Date(2010, 6, 12), Date(2011, 12, 16))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); static assert(!__traits(compiles, cInterval.shift(dur!"days"(5)))); static assert(!__traits(compiles, iInterval.shift(dur!"days"(5)))); //Verify Examples. auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5)); auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5)); interval1.shift(dur!"days"(50)); assert(interval1 == Interval!Date(Date(1996, 2, 21), Date(2012, 5, 25))); interval2.shift(dur!"days"(-50)); assert(interval2 == Interval!Date(Date(1995, 11, 13), Date(2012, 2, 15))); } //Test Interval's shift(int, int, AllowDayOverflow). unittest { { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); static void testIntervalFail(Interval!Date interval, int years, int months) { interval.shift(years, months); } assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), 1, 0)); static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__) { interval.shift(years, months, allow); assert(interval == expected); } testInterval(interval, 5, 0, AllowDayOverflow.yes, Interval!Date(Date(2015, 7, 4), Date(2017, 1, 7))); testInterval(interval, -5, 0, AllowDayOverflow.yes, Interval!Date(Date(2005, 7, 4), Date(2007, 1, 7))); auto interval2 = Interval!Date(Date(2000, 1, 29), Date(2010, 5, 31)); testInterval(interval2, 1, 1, AllowDayOverflow.yes, Interval!Date(Date(2001, 3, 1), Date(2011, 7, 1))); testInterval(interval2, 1, -1, AllowDayOverflow.yes, Interval!Date(Date(2000, 12, 29), Date(2011, 5, 1))); testInterval(interval2, -1, -1, AllowDayOverflow.yes, Interval!Date(Date(1998, 12, 29), Date(2009, 5, 1))); testInterval(interval2, -1, 1, AllowDayOverflow.yes, Interval!Date(Date(1999, 3, 1), Date(2009, 7, 1))); testInterval(interval2, 1, 1, AllowDayOverflow.no, Interval!Date(Date(2001, 2, 28), Date(2011, 6, 30))); testInterval(interval2, 1, -1, AllowDayOverflow.no, Interval!Date(Date(2000, 12, 29), Date(2011, 4, 30))); testInterval(interval2, -1, -1, AllowDayOverflow.no, Interval!Date(Date(1998, 12, 29), Date(2009, 4, 30))); testInterval(interval2, -1, 1, AllowDayOverflow.no, Interval!Date(Date(1999, 2, 28), Date(2009, 6, 30))); } const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); static assert(!__traits(compiles, cInterval.shift(5))); static assert(!__traits(compiles, iInterval.shift(5))); //Verify Examples. auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); interval1.shift(2); assert(interval1 == Interval!Date(Date(1998, 1, 2), Date(2014, 3, 1))); interval2.shift(-2); assert(interval2 == Interval!Date(Date(1994, 1, 2), Date(2010, 3, 1))); } //Test Interval's expand(Duration). unittest { auto interval = Interval!Date(Date(2000, 7, 4), Date(2012, 1, 7)); static void testIntervalFail(I)(I interval, in Duration duration) { interval.expand(duration); } assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), dur!"days"(1))); assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)), dur!"days"(-5))); static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__) { interval.expand(duration); assert(interval == expected); } testInterval(interval, dur!"days"(22), Interval!Date(Date(2000, 6, 12), Date(2012, 1, 29))); testInterval(interval, dur!"days"(-22), Interval!Date(Date(2000, 7, 26), Date(2011, 12, 16))); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); static assert(!__traits(compiles, cInterval.expand(dur!"days"(5)))); static assert(!__traits(compiles, iInterval.expand(dur!"days"(5)))); //Verify Examples. auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); interval1.expand(dur!"days"(2)); assert(interval1 == Interval!Date(Date(1995, 12, 31), Date(2012, 3, 3))); interval2.expand(dur!"days"(-2)); assert(interval2 == Interval!Date(Date(1996, 1, 4), Date(2012, 2, 28))); } //Test Interval's expand(int, int, AllowDayOverflow, Direction) unittest { { auto interval = Interval!Date(Date(2000, 7, 4), Date(2012, 1, 7)); static void testIntervalFail(Interval!Date interval, int years, int months) { interval.expand(years, months); } assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), 1, 0)); assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)), -5, 0)); static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, Direction dir, in I expected, size_t line = __LINE__) { interval.expand(years, months, allow, dir); assert(interval == expected); } testInterval(interval, 5, 0, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(1995, 7, 4), Date(2017, 1, 7))); testInterval(interval, -5, 0, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(2005, 7, 4), Date(2007, 1, 7))); testInterval(interval, 5, 0, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 7, 4), Date(2017, 1, 7))); testInterval(interval, -5, 0, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 7, 4), Date(2007, 1, 7))); testInterval(interval, 5, 0, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(1995, 7, 4), Date(2012, 1, 7))); testInterval(interval, -5, 0, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(2005, 7, 4), Date(2012, 1, 7))); auto interval2 = Interval!Date(Date(2000, 1, 29), Date(2010, 5, 31)); testInterval(interval2, 1, 1, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(1998, 12, 29), Date(2011, 7, 1))); testInterval(interval2, 1, -1, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(1999, 3, 1), Date(2011, 5, 1))); testInterval(interval2, -1, -1, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(2001, 3, 1), Date(2009, 5, 1))); testInterval(interval2, -1, 1, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(2000, 12, 29), Date(2009, 7, 1))); testInterval(interval2, 1, 1, AllowDayOverflow.no, Direction.both, Interval!Date(Date(1998, 12, 29), Date(2011, 6, 30))); testInterval(interval2, 1, -1, AllowDayOverflow.no, Direction.both, Interval!Date(Date(1999, 2, 28), Date(2011, 4, 30))); testInterval(interval2, -1, -1, AllowDayOverflow.no, Direction.both, Interval!Date(Date(2001, 2, 28), Date(2009, 4, 30))); testInterval(interval2, -1, 1, AllowDayOverflow.no, Direction.both, Interval!Date(Date(2000, 12, 29), Date(2009, 6, 30))); testInterval(interval2, 1, 1, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2011, 7, 1))); testInterval(interval2, 1, -1, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2011, 5, 1))); testInterval(interval2, -1, -1, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2009, 5, 1))); testInterval(interval2, -1, 1, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2009, 7, 1))); testInterval(interval2, 1, 1, AllowDayOverflow.no, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2011, 6, 30))); testInterval(interval2, 1, -1, AllowDayOverflow.no, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2011, 4, 30))); testInterval(interval2, -1, -1, AllowDayOverflow.no, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2009, 4, 30))); testInterval(interval2, -1, 1, AllowDayOverflow.no, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2009, 6, 30))); testInterval(interval2, 1, 1, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(1998, 12, 29), Date(2010, 5, 31))); testInterval(interval2, 1, -1, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(1999, 3, 1), Date(2010, 5, 31))); testInterval(interval2, -1, -1, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(2001, 3, 1), Date(2010, 5, 31))); testInterval(interval2, -1, 1, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(2000, 12, 29), Date(2010, 5, 31))); testInterval(interval2, 1, 1, AllowDayOverflow.no, Direction.bwd, Interval!Date(Date(1998, 12, 29), Date(2010, 5, 31))); testInterval(interval2, 1, -1, AllowDayOverflow.no, Direction.bwd, Interval!Date(Date(1999, 2, 28), Date(2010, 5, 31))); testInterval(interval2, -1, -1, AllowDayOverflow.no, Direction.bwd, Interval!Date(Date(2001, 2, 28), Date(2010, 5, 31))); testInterval(interval2, -1, 1, AllowDayOverflow.no, Direction.bwd, Interval!Date(Date(2000, 12, 29), Date(2010, 5, 31))); } const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); static assert(!__traits(compiles, cInterval.expand(5))); static assert(!__traits(compiles, iInterval.expand(5))); //Verify Examples. auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)); interval1.expand(2); assert(interval1 == Interval!Date(Date(1994, 1, 2), Date(2014, 3, 1))); interval2.expand(-2); assert(interval2 == Interval!Date(Date(1998, 1, 2), Date(2010, 3, 1))); } //Test Interval's fwdRange. unittest { { auto interval = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21)); static void testInterval1(Interval!Date interval) { interval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)); } assertThrown!DateTimeException(testInterval1(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); static void testInterval2(Interval!Date interval) { interval.fwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).popFront(); } assertThrown!DateTimeException(testInterval2(interval)); assert(!interval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty); assert(interval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri), PopFirst.yes).empty); assert(Interval!Date(Date(2010, 9, 12), Date(2010, 10, 1)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).front == Date(2010, 9, 12)); assert(Interval!Date(Date(2010, 9, 12), Date(2010, 10, 1)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri), PopFirst.yes).front == Date(2010, 9, 17)); } //Verify Examples. { auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9)); auto func = delegate (in Date date) { if((date.day & 1) == 0) return date + dur!"days"(2); return date + dur!"days"(1); }; auto range = interval.fwdRange(func); assert(range.front == Date(2010, 9, 1)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2). range.popFront(); assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(range.front == Date(2010, 9, 4)); range.popFront(); assert(range.front == Date(2010, 9, 6)); range.popFront(); assert(range.front == Date(2010, 9, 8)); range.popFront(); assert(range.empty); } const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(!cInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty); assert(!iInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty); } //Test Interval's bwdRange. unittest { { auto interval = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21)); static void testInterval1(Interval!Date interval) { interval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)); } assertThrown!DateTimeException(testInterval1(Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); static void testInterval2(Interval!Date interval) { interval.bwdRange(everyDayOfWeek!(Date, Direction.fwd)(DayOfWeek.fri)).popFront(); } assertThrown!DateTimeException(testInterval2(interval)); assert(!interval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).empty); assert(interval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri), PopFirst.yes).empty); assert(Interval!Date(Date(2010, 9, 19), Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).front == Date(2010, 10, 1)); assert(Interval!Date(Date(2010, 9, 19), Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri), PopFirst.yes).front == Date(2010, 9, 24)); } //Verify Examples. { auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9)); auto func = delegate (in Date date) { if((date.day & 1) == 0) return date - dur!"days"(2); return date - dur!"days"(1); }; auto range = interval.bwdRange(func); assert(range.front == Date(2010, 9, 9)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8). range.popFront(); assert(range.front == Date(2010, 9, 8)); range.popFront(); assert(range.front == Date(2010, 9, 6)); range.popFront(); assert(range.front == Date(2010, 9, 4)); range.popFront(); assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(range.empty); } const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(!cInterval.bwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty); assert(!iInterval.bwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty); } //Test Interval's toString(). unittest { assert(Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).toString() == "[2010-Jul-04 - 2012-Jan-07)"); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(cInterval.toString()); assert(iInterval.toString()); } /++ Represents an interval of time which has positive infinity as its end point. Any ranges which iterate over a $(D PosInfInterval) are infinite. So, the main purpose of using $(D PosInfInterval) is to create an infinite range which starts at a fixed point in time and goes to positive infinity. +/ struct PosInfInterval(TP) { public: /++ Params: begin = The time point which begins the interval. Example: -------------------- auto interval = PosInfInterval!Date(Date(1996, 1, 2)); -------------------- +/ this(in TP begin) pure nothrow { _begin = cast(TP)begin; } /++ Params: rhs = The $(D PosInfInterval) to assign to this one. +/ ref PosInfInterval opAssign(const ref PosInfInterval rhs) pure nothrow { _begin = cast(TP)rhs._begin; return this; } /++ Params: rhs = The $(D PosInfInterval) to assign to this one. +/ ref PosInfInterval opAssign(PosInfInterval rhs) pure nothrow { _begin = cast(TP)rhs._begin; return this; } /++ The starting point of the interval. It is included in the interval. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).begin == Date(1996, 1, 2)); -------------------- +/ @property TP begin() const pure nothrow { return cast(TP)_begin; } /++ The starting point of the interval. It is included in the interval. Params: timePoint = The time point to set $(D begin) to. +/ @property void begin(TP timePoint) pure nothrow { _begin = timePoint; } /++ Whether the interval's length is 0. Always returns false. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).empty); -------------------- +/ @property bool empty() const pure nothrow { return false; } /++ Whether the given time point is within this interval. Params: timePoint = The time point to check for inclusion in this interval. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(1994, 12, 24))); assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(2000, 1, 5))); -------------------- +/ bool contains(TP timePoint) const pure nothrow { return timePoint >= _begin; } /++ Whether the given interval is completely within this interval. Params: interval = The interval to check for inclusion in this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).contains( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).contains( Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1)))); -------------------- +/ bool contains(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return interval._begin >= _begin; } /++ Whether the given interval is completely within this interval. Params: interval = The interval to check for inclusion in this interval. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).contains( PosInfInterval!Date(Date(1999, 5, 4)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains( PosInfInterval!Date(Date(1995, 7, 2)))); -------------------- +/ bool contains(in PosInfInterval interval) const pure nothrow { return interval._begin >= _begin; } /++ Whether the given interval is completely within this interval. Always returns false because an interval going to positive infinity can never contain an interval beginning at negative infinity. Params: interval = The interval to check for inclusion in this interval. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains( NegInfInterval!Date(Date(1996, 5, 4)))); -------------------- +/ bool contains(in NegInfInterval!TP interval) const pure nothrow { return false; } /++ Whether this interval is before the given time point. Always returns false because an interval going to positive infinity can never be before any time point. Params: timePoint = The time point to check whether this interval is before it. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(1994, 12, 24))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(2000, 1, 5))); -------------------- +/ bool isBefore(in TP timePoint) const pure nothrow { return false; } /++ Whether this interval is before the given interval and does not intersect it. Always returns false (unless the given interval is empty) because an interval going to positive infinity can never be before any other interval. Params: interval = The interval to check for against this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); -------------------- +/ bool isBefore(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return false; } /++ Whether this interval is before the given interval and does not intersect it. Always returns false because an interval going to positive infinity can never be before any other interval. Params: interval = The interval to check for against this interval. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore( PosInfInterval!Date(Date(1992, 5, 4)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore( PosInfInterval!Date(Date(2013, 3, 7)))); -------------------- +/ bool isBefore(in PosInfInterval interval) const pure nothrow { return false; } /++ Whether this interval is before the given interval and does not intersect it. Always returns false because an interval going to positive infinity can never be before any other interval. Params: interval = The interval to check for against this interval. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore( NegInfInterval!Date(Date(1996, 5, 4)))); -------------------- +/ bool isBefore(in NegInfInterval!TP interval) const pure nothrow { return false; } /++ Whether this interval is after the given time point. Params: timePoint = The time point to check whether this interval is after it. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(1994, 12, 24))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(2000, 1, 5))); -------------------- +/ bool isAfter(in TP timePoint) const pure nothrow { return timePoint < _begin; } /++ Whether this interval is after the given interval and does not intersect it. Params: interval = The interval to check against this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter( Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); -------------------- +/ bool isAfter(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return _begin >= interval._end; } /++ Whether this interval is after the given interval and does not intersect it. Always returns false because an interval going to positive infinity can never be after another interval going to positive infinity. Params: interval = The interval to check against this interval. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter( PosInfInterval!Date(Date(1990, 1, 7)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter( PosInfInterval!Date(Date(1999, 5, 4)))); -------------------- +/ bool isAfter(in PosInfInterval interval) const pure nothrow { return false; } /++ Whether this interval is after the given interval and does not intersect it. Params: interval = The interval to check against this interval. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter( NegInfInterval!Date(Date(1996, 1, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter( NegInfInterval!Date(Date(2000, 7, 1)))); -------------------- +/ bool isAfter(in NegInfInterval!TP interval) const pure nothrow { return _begin >= interval._end; } /++ Whether the given interval overlaps this interval. Params: interval = The interval to check for intersection with this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects( Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); -------------------- +/ bool intersects(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return interval._end > _begin; } /++ Whether the given interval overlaps this interval. Always returns true because two intervals going to positive infinity always overlap. Params: interval = The interval to check for intersection with this interval. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects( PosInfInterval!Date(Date(1990, 1, 7)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects( PosInfInterval!Date(Date(1999, 5, 4)))); -------------------- +/ bool intersects(in PosInfInterval interval) const pure nothrow { return true; } /++ Whether the given interval overlaps this interval. Params: interval = The interval to check for intersection with this interval. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects( NegInfInterval!Date(Date(1996, 1, 2)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects( NegInfInterval!Date(Date(2000, 7, 1)))); -------------------- +/ bool intersects(in NegInfInterval!TP interval) const pure nothrow { return _begin < interval._end; } /++ Returns the intersection of two intervals Params: interval = The interval to intersect with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect or if the given interval is empty. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17))); -------------------- +/ Interval!TP intersection(in Interval!TP interval) const { import std.format : format; enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval))); auto begin = _begin > interval._begin ? _begin : interval._begin; return Interval!TP(begin, interval._end); } /++ Returns the intersection of two intervals Params: interval = The interval to intersect with this interval. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection( PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1996, 1 , 2))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection( PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1999, 1 , 12))); -------------------- +/ PosInfInterval intersection(in PosInfInterval interval) const pure nothrow { return PosInfInterval(_begin < interval._begin ? interval._begin : _begin); } /++ Returns the intersection of two intervals Params: interval = The interval to intersect with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection( NegInfInterval!Date(Date(1999, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection( NegInfInterval!Date(Date(2013, 1, 12))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 1, 12))); -------------------- +/ Interval!TP intersection(in NegInfInterval!TP interval) const { import std.format : format; enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval))); return Interval!TP(_begin, interval._end); } /++ Whether the given interval is adjacent to this interval. Params: interval = The interval to check whether its adjecent to this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent( Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); assert(!PosInfInterval!Date(Date(1999, 1, 12)).isAdjacent( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); -------------------- +/ bool isAdjacent(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return _begin == interval._end; } /++ Whether the given interval is adjacent to this interval. Always returns false because two intervals going to positive infinity can never be adjacent to one another. Params: interval = The interval to check whether its adjecent to this interval. Example: -------------------- assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent( PosInfInterval!Date(Date(1990, 1, 7)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent( PosInfInterval!Date(Date(1996, 1, 2)))); -------------------- +/ bool isAdjacent(in PosInfInterval interval) const pure nothrow { return false; } /++ Whether the given interval is adjacent to this interval. Params: interval = The interval to check whether its adjecent to this interval. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent( NegInfInterval!Date(Date(1996, 1, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent( NegInfInterval!Date(Date(2000, 7, 1)))); -------------------- +/ bool isAdjacent(in NegInfInterval!TP interval) const pure nothrow { return _begin == interval._end; } /++ Returns the union of two intervals Params: interval = The interval to merge with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect and are not adjacent or if the given interval is empty. Note: There is no overload for $(D merge) which takes a $(D NegInfInterval), because an interval going from negative infinity to positive infinity is not possible. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).merge( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).merge( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == PosInfInterval!Date(Date(1996, 1 , 2))); -------------------- +/ PosInfInterval merge(in Interval!TP interval) const { import std.format : format; enforce(this.isAdjacent(interval) || this.intersects(interval), new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval))); return PosInfInterval(_begin < interval._begin ? _begin : interval._begin); } /++ Returns the union of two intervals Params: interval = The interval to merge with this interval. Note: There is no overload for $(D merge) which takes a $(D NegInfInterval), because an interval going from negative infinity to positive infinity is not possible. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).merge( PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).merge( PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1996, 1 , 2))); -------------------- +/ PosInfInterval merge(in PosInfInterval interval) const pure nothrow { return PosInfInterval(_begin < interval._begin ? _begin : interval._begin); } /++ Returns an interval that covers from the earliest time point of two intervals up to (but not including) the latest time point of two intervals. Params: interval = The interval to create a span together with this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Note: There is no overload for $(D span) which takes a $(D NegInfInterval), because an interval going from negative infinity to positive infinity is not possible. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).span( Interval!Date(Date(500, 8, 9), Date(1602, 1, 31))) == PosInfInterval!Date(Date(500, 8, 9))); assert(PosInfInterval!Date(Date(1996, 1, 2)).span( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).span( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == PosInfInterval!Date(Date(1996, 1 , 2))); -------------------- +/ PosInfInterval span(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return PosInfInterval(_begin < interval._begin ? _begin : interval._begin); } /++ Returns an interval that covers from the earliest time point of two intervals up to (but not including) the latest time point of two intervals. Params: interval = The interval to create a span together with this interval. Note: There is no overload for $(D span) which takes a $(D NegInfInterval), because an interval going from negative infinity to positive infinity is not possible. Example: -------------------- assert(PosInfInterval!Date(Date(1996, 1, 2)).span( PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).span( PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1996, 1 , 2))); -------------------- +/ PosInfInterval span(in PosInfInterval interval) const pure nothrow { return PosInfInterval(_begin < interval._begin ? _begin : interval._begin); } /++ Shifts the $(D begin) of this interval forward or backwards in time by the given duration (a positive duration shifts the interval forward; a negative duration shifts it backward). Effectively, it does $(D begin += duration). Params: duration = The duration to shift the interval by. Example: -------------------- auto interval1 = PosInfInterval!Date(Date(1996, 1, 2)); auto interval2 = PosInfInterval!Date(Date(1996, 1, 2)); interval1.shift(dur!"days"(50)); assert(interval1 == PosInfInterval!Date(Date(1996, 2, 21))); interval2.shift(dur!"days"(-50)); assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13))); -------------------- +/ void shift(D)(D duration) pure nothrow if(__traits(compiles, begin + duration)) { _begin += duration; } static if(__traits(compiles, begin.add!"months"(1)) && __traits(compiles, begin.add!"years"(1))) { /++ Shifts the $(D begin) of this interval forward or backwards in time by the given number of years and/or months (a positive number of years and months shifts the interval forward; a negative number shifts it backward). It adds the years the given years and months to $(D begin). It effectively calls $(D add!"years"()) and then $(D add!"months"()) on $(D begin) with the given number of years and months. Params: years = The number of years to shift the interval by. months = The number of months to shift the interval by. allowOverflow = Whether the days should be allowed to overflow on $(D begin), causing its month to increment. Throws: $(LREF DateTimeException) if this interval is empty or if the resulting interval would be invalid. Example: -------------------- auto interval1 = PosInfInterval!Date(Date(1996, 1, 2)); auto interval2 = PosInfInterval!Date(Date(1996, 1, 2)); interval1.shift(dur!"days"(50)); assert(interval1 == PosInfInterval!Date(Date(1996, 2, 21))); interval2.shift(dur!"days"(-50)); assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13))); -------------------- +/ void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) if(isIntegral!T) { auto begin = _begin; begin.add!"years"(years, allowOverflow); begin.add!"months"(months, allowOverflow); _begin = begin; } } /++ Expands the interval backwards in time. Effectively, it does $(D begin -= duration). Params: duration = The duration to expand the interval by. Example: -------------------- auto interval1 = PosInfInterval!Date(Date(1996, 1, 2)); auto interval2 = PosInfInterval!Date(Date(1996, 1, 2)); interval1.expand(dur!"days"(2)); assert(interval1 == PosInfInterval!Date(Date(1995, 12, 31))); interval2.expand(dur!"days"(-2)); assert(interval2 == PosInfInterval!Date(Date(1996, 1, 4))); -------------------- +/ void expand(D)(D duration) pure nothrow if(__traits(compiles, begin + duration)) { _begin -= duration; } static if(__traits(compiles, begin.add!"months"(1)) && __traits(compiles, begin.add!"years"(1))) { /++ Expands the interval forwards and/or backwards in time. Effectively, it subtracts the given number of months/years from $(D begin). Params: years = The number of years to expand the interval by. months = The number of months to expand the interval by. allowOverflow = Whether the days should be allowed to overflow on $(D begin), causing its month to increment. Throws: $(LREF DateTimeException) if this interval is empty or if the resulting interval would be invalid. Example: -------------------- auto interval1 = PosInfInterval!Date(Date(1996, 1, 2)); auto interval2 = PosInfInterval!Date(Date(1996, 1, 2)); interval1.expand(2); assert(interval1 == PosInfInterval!Date(Date(1994, 1, 2))); interval2.expand(-2); assert(interval2 == PosInfInterval!Date(Date(1998, 1, 2))); -------------------- +/ void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) if(isIntegral!T) { auto begin = _begin; begin.add!"years"(-years, allowOverflow); begin.add!"months"(-months, allowOverflow); _begin = begin; return; } } /++ Returns a range which iterates forward over the interval, starting at $(D begin), using $(D_PARAM func) to generate each successive time point. The range's $(D front) is the interval's $(D begin). $(D_PARAM func) is used to generate the next $(D front) when $(D popFront) is called. If $(D_PARAM popFirst) is $(D PopFirst.yes), then $(D popFront) is called before the range is returned (so that $(D front) is a time point which $(D_PARAM func) would generate). If $(D_PARAM func) ever generates a time point less than or equal to the current $(D front) of the range, then a $(LREF DateTimeException) will be thrown. There are helper functions in this module which generate common delegates to pass to $(D fwdRange). Their documentation starts with "Range-generating function," to make them easily searchable. Params: func = The function used to generate the time points of the range over the interval. popFirst = Whether $(D popFront) should be called on the range before returning it. Throws: $(LREF DateTimeException) if this interval is empty. Warning: $(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func) would be a function pointer to a pure function, but forcing $(D_PARAM func) to be pure is far too restrictive to be useful, and in order to have the ease of use of having functions which generate functions to pass to $(D fwdRange), $(D_PARAM func) must be a delegate. If $(D_PARAM func) retains state which changes as it is called, then some algorithms will not work correctly, because the range's $(D save) will have failed to have really saved the range's state. To avoid such bugs, don't pass a delegate which is not logically pure to $(D fwdRange). If $(D_PARAM func) is given the same time point with two different calls, it must return the same result both times. Of course, none of the functions in this module have this problem, so it's only relevant for custom delegates. Example: -------------------- auto interval = PosInfInterval!Date(Date(2010, 9, 1)); auto func = delegate (in Date date) //For iterating over even-numbered days. { if((date.day & 1) == 0) return date + dur!"days"(2); return date + dur!"days"(1); }; auto range = interval.fwdRange(func); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2). assert(range.front == Date(2010, 9, 1)); range.popFront(); assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(range.front == Date(2010, 9, 4)); range.popFront(); assert(range.front == Date(2010, 9, 6)); range.popFront(); assert(range.front == Date(2010, 9, 8)); range.popFront(); assert(!range.empty); -------------------- +/ PosInfIntervalRange!(TP) fwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no) const { auto range = PosInfIntervalRange!(TP)(this, func); if(popFirst == PopFirst.yes) range.popFront(); return range; } /+ Converts this interval to a string. +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() { return _toStringImpl(); } /++ Converts this interval to a string. +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() const nothrow { return _toStringImpl(); } private: /+ Since we have two versions of toString(), we have _toStringImpl() so that they can share implementations. +/ string _toStringImpl() const nothrow { import std.format : format; try return format("[%s - ∞)", _begin); catch(Exception e) assert(0, "format() threw."); } TP _begin; } //Test PosInfInterval's constructor. unittest { PosInfInterval!Date(Date.init); PosInfInterval!TimeOfDay(TimeOfDay.init); PosInfInterval!DateTime(DateTime.init); PosInfInterval!SysTime(SysTime(0)); //Verify Examples. auto interval = PosInfInterval!Date(Date(1996, 1, 2)); } //Test PosInfInterval's begin. unittest { assert(PosInfInterval!Date(Date(1, 1, 1)).begin == Date(1, 1, 1)); assert(PosInfInterval!Date(Date(2010, 1, 1)).begin == Date(2010, 1, 1)); assert(PosInfInterval!Date(Date(1997, 12, 31)).begin == Date(1997, 12, 31)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); assert(cPosInfInterval.begin != Date.init); assert(iPosInfInterval.begin != Date.init); //Verify Examples. assert(PosInfInterval!Date(Date(1996, 1, 2)).begin == Date(1996, 1, 2)); } //Test PosInfInterval's empty. unittest { assert(!PosInfInterval!Date(Date(2010, 1, 1)).empty); assert(!PosInfInterval!TimeOfDay(TimeOfDay(0, 30, 0)).empty); assert(!PosInfInterval!DateTime(DateTime(2010, 1, 1, 0, 30, 0)).empty); assert(!PosInfInterval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0))).empty); const cPosInfInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iPosInfInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); assert(!cPosInfInterval.empty); assert(!iPosInfInterval.empty); //Verify Examples. assert(!PosInfInterval!Date(Date(1996, 1, 2)).empty); } //Test PosInfInterval's contains(time point). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); assert(!posInfInterval.contains(Date(2009, 7, 4))); assert(!posInfInterval.contains(Date(2010, 7, 3))); assert(posInfInterval.contains(Date(2010, 7, 4))); assert(posInfInterval.contains(Date(2010, 7, 5))); assert(posInfInterval.contains(Date(2011, 7, 1))); assert(posInfInterval.contains(Date(2012, 1, 6))); assert(posInfInterval.contains(Date(2012, 1, 7))); assert(posInfInterval.contains(Date(2012, 1, 8))); assert(posInfInterval.contains(Date(2013, 1, 7))); const cdate = Date(2010, 7, 6); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); assert(posInfInterval.contains(cdate)); assert(cPosInfInterval.contains(cdate)); assert(iPosInfInterval.contains(cdate)); //Verify Examples. assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(1994, 12, 24))); assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(2000, 1, 5))); } //Test PosInfInterval's contains(Interval). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval) { posInfInterval.contains(interval); } assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(posInfInterval.contains(posInfInterval)); assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(posInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(posInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!posInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 3)))); assert(posInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 4)))); assert(posInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 5)))); assert(posInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 6)))); assert(posInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 7)))); assert(posInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 8)))); assert(PosInfInterval!Date(Date(2010, 7, 3)).contains(posInfInterval)); assert(PosInfInterval!Date(Date(2010, 7, 4)).contains(posInfInterval)); assert(!PosInfInterval!Date(Date(2010, 7, 5)).contains(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 6)).contains(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 7)).contains(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 8)).contains(posInfInterval)); assert(!posInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 3)))); assert(!posInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!posInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!posInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!posInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!posInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(posInfInterval.contains(interval)); assert(posInfInterval.contains(cInterval)); assert(posInfInterval.contains(iInterval)); assert(posInfInterval.contains(posInfInterval)); assert(posInfInterval.contains(cPosInfInterval)); assert(posInfInterval.contains(iPosInfInterval)); assert(!posInfInterval.contains(negInfInterval)); assert(!posInfInterval.contains(cNegInfInterval)); assert(!posInfInterval.contains(iNegInfInterval)); assert(cPosInfInterval.contains(interval)); assert(cPosInfInterval.contains(cInterval)); assert(cPosInfInterval.contains(iInterval)); assert(cPosInfInterval.contains(posInfInterval)); assert(cPosInfInterval.contains(cPosInfInterval)); assert(cPosInfInterval.contains(iPosInfInterval)); assert(!cPosInfInterval.contains(negInfInterval)); assert(!cPosInfInterval.contains(cNegInfInterval)); assert(!cPosInfInterval.contains(iNegInfInterval)); assert(iPosInfInterval.contains(interval)); assert(iPosInfInterval.contains(cInterval)); assert(iPosInfInterval.contains(iInterval)); assert(iPosInfInterval.contains(posInfInterval)); assert(iPosInfInterval.contains(cPosInfInterval)); assert(iPosInfInterval.contains(iPosInfInterval)); assert(!iPosInfInterval.contains(negInfInterval)); assert(!iPosInfInterval.contains(cNegInfInterval)); assert(!iPosInfInterval.contains(iNegInfInterval)); //Verify Examples. assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(PosInfInterval!Date(Date(1999, 5, 4)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(PosInfInterval!Date(Date(1995, 7, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(NegInfInterval!Date(Date(1996, 5, 4)))); } //Test PosInfInterval's isBefore(time point). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); assert(!posInfInterval.isBefore(Date(2009, 7, 3))); assert(!posInfInterval.isBefore(Date(2010, 7, 3))); assert(!posInfInterval.isBefore(Date(2010, 7, 4))); assert(!posInfInterval.isBefore(Date(2010, 7, 5))); assert(!posInfInterval.isBefore(Date(2011, 7, 1))); assert(!posInfInterval.isBefore(Date(2012, 1, 6))); assert(!posInfInterval.isBefore(Date(2012, 1, 7))); assert(!posInfInterval.isBefore(Date(2012, 1, 8))); assert(!posInfInterval.isBefore(Date(2013, 1, 7))); const cdate = Date(2010, 7, 6); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); assert(!posInfInterval.isBefore(cdate)); assert(!cPosInfInterval.isBefore(cdate)); assert(!iPosInfInterval.isBefore(cdate)); //Verify Examples. assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(1994, 12, 24))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(2000, 1, 5))); } //Test PosInfInterval's isBefore(Interval). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval) { posInfInterval.isBefore(interval); } assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(!posInfInterval.isBefore(posInfInterval)); assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 6)))); assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 8)))); assert(!PosInfInterval!Date(Date(2010, 7, 3)).isBefore(posInfInterval)); assert(!PosInfInterval!Date(Date(2010, 7, 4)).isBefore(posInfInterval)); assert(!PosInfInterval!Date(Date(2010, 7, 5)).isBefore(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 6)).isBefore(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 7)).isBefore(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 8)).isBefore(posInfInterval)); assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 3)))); assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!posInfInterval.isBefore(interval)); assert(!posInfInterval.isBefore(cInterval)); assert(!posInfInterval.isBefore(iInterval)); assert(!posInfInterval.isBefore(posInfInterval)); assert(!posInfInterval.isBefore(cPosInfInterval)); assert(!posInfInterval.isBefore(iPosInfInterval)); assert(!posInfInterval.isBefore(negInfInterval)); assert(!posInfInterval.isBefore(cNegInfInterval)); assert(!posInfInterval.isBefore(iNegInfInterval)); assert(!cPosInfInterval.isBefore(interval)); assert(!cPosInfInterval.isBefore(cInterval)); assert(!cPosInfInterval.isBefore(iInterval)); assert(!cPosInfInterval.isBefore(posInfInterval)); assert(!cPosInfInterval.isBefore(cPosInfInterval)); assert(!cPosInfInterval.isBefore(iPosInfInterval)); assert(!cPosInfInterval.isBefore(negInfInterval)); assert(!cPosInfInterval.isBefore(cNegInfInterval)); assert(!cPosInfInterval.isBefore(iNegInfInterval)); assert(!iPosInfInterval.isBefore(interval)); assert(!iPosInfInterval.isBefore(cInterval)); assert(!iPosInfInterval.isBefore(iInterval)); assert(!iPosInfInterval.isBefore(posInfInterval)); assert(!iPosInfInterval.isBefore(cPosInfInterval)); assert(!iPosInfInterval.isBefore(iPosInfInterval)); assert(!iPosInfInterval.isBefore(negInfInterval)); assert(!iPosInfInterval.isBefore(cNegInfInterval)); assert(!iPosInfInterval.isBefore(iNegInfInterval)); //Verify Examples. assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(PosInfInterval!Date(Date(1992, 5, 4)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(PosInfInterval!Date(Date(2013, 3, 7)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(NegInfInterval!Date(Date(1996, 5, 4)))); } //Test PosInfInterval's isAfter(time point). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); assert(posInfInterval.isAfter(Date(2009, 7, 3))); assert(posInfInterval.isAfter(Date(2010, 7, 3))); assert(!posInfInterval.isAfter(Date(2010, 7, 4))); assert(!posInfInterval.isAfter(Date(2010, 7, 5))); assert(!posInfInterval.isAfter(Date(2011, 7, 1))); assert(!posInfInterval.isAfter(Date(2012, 1, 6))); assert(!posInfInterval.isAfter(Date(2012, 1, 7))); assert(!posInfInterval.isAfter(Date(2012, 1, 8))); assert(!posInfInterval.isAfter(Date(2013, 1, 7))); const cdate = Date(2010, 7, 6); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); assert(!posInfInterval.isAfter(cdate)); assert(!cPosInfInterval.isAfter(cdate)); assert(!iPosInfInterval.isAfter(cdate)); //Verify Examples. assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(1994, 12, 24))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(2000, 1, 5))); } //Test PosInfInterval's isAfter(Interval). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval) { posInfInterval.isAfter(interval); } assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(!posInfInterval.isAfter(posInfInterval)); assert(posInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 6)))); assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 8)))); assert(!PosInfInterval!Date(Date(2010, 7, 3)).isAfter(posInfInterval)); assert(!PosInfInterval!Date(Date(2010, 7, 4)).isAfter(posInfInterval)); assert(!PosInfInterval!Date(Date(2010, 7, 5)).isAfter(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 6)).isAfter(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 7)).isAfter(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 8)).isAfter(posInfInterval)); assert(posInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 3)))); assert(posInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!posInfInterval.isAfter(interval)); assert(!posInfInterval.isAfter(cInterval)); assert(!posInfInterval.isAfter(iInterval)); assert(!posInfInterval.isAfter(posInfInterval)); assert(!posInfInterval.isAfter(cPosInfInterval)); assert(!posInfInterval.isAfter(iPosInfInterval)); assert(!posInfInterval.isAfter(negInfInterval)); assert(!posInfInterval.isAfter(cNegInfInterval)); assert(!posInfInterval.isAfter(iNegInfInterval)); assert(!cPosInfInterval.isAfter(interval)); assert(!cPosInfInterval.isAfter(cInterval)); assert(!cPosInfInterval.isAfter(iInterval)); assert(!cPosInfInterval.isAfter(posInfInterval)); assert(!cPosInfInterval.isAfter(cPosInfInterval)); assert(!cPosInfInterval.isAfter(iPosInfInterval)); assert(!cPosInfInterval.isAfter(negInfInterval)); assert(!cPosInfInterval.isAfter(cNegInfInterval)); assert(!cPosInfInterval.isAfter(iNegInfInterval)); assert(!iPosInfInterval.isAfter(interval)); assert(!iPosInfInterval.isAfter(cInterval)); assert(!iPosInfInterval.isAfter(iInterval)); assert(!iPosInfInterval.isAfter(posInfInterval)); assert(!iPosInfInterval.isAfter(cPosInfInterval)); assert(!iPosInfInterval.isAfter(iPosInfInterval)); assert(!iPosInfInterval.isAfter(negInfInterval)); assert(!iPosInfInterval.isAfter(cNegInfInterval)); assert(!iPosInfInterval.isAfter(iNegInfInterval)); //Verify Examples. assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(PosInfInterval!Date(Date(1990, 1, 7)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(PosInfInterval!Date(Date(1999, 5, 4)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(NegInfInterval!Date(Date(1996, 1, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(NegInfInterval!Date(Date(2000, 7, 1)))); } //Test PosInfInterval's intersects(). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval) { posInfInterval.intersects(interval); } assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(posInfInterval.intersects(posInfInterval)); assert(!posInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(!posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(posInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 3)))); assert(posInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 4)))); assert(posInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 5)))); assert(posInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 6)))); assert(posInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 7)))); assert(posInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 8)))); assert(PosInfInterval!Date(Date(2010, 7, 3)).intersects(posInfInterval)); assert(PosInfInterval!Date(Date(2010, 7, 4)).intersects(posInfInterval)); assert(PosInfInterval!Date(Date(2010, 7, 5)).intersects(posInfInterval)); assert(PosInfInterval!Date(Date(2012, 1, 6)).intersects(posInfInterval)); assert(PosInfInterval!Date(Date(2012, 1, 7)).intersects(posInfInterval)); assert(PosInfInterval!Date(Date(2012, 1, 8)).intersects(posInfInterval)); assert(!posInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 3)))); assert(!posInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 4)))); assert(posInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 5)))); assert(posInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 6)))); assert(posInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 7)))); assert(posInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(posInfInterval.intersects(interval)); assert(posInfInterval.intersects(cInterval)); assert(posInfInterval.intersects(iInterval)); assert(posInfInterval.intersects(posInfInterval)); assert(posInfInterval.intersects(cPosInfInterval)); assert(posInfInterval.intersects(iPosInfInterval)); assert(posInfInterval.intersects(negInfInterval)); assert(posInfInterval.intersects(cNegInfInterval)); assert(posInfInterval.intersects(iNegInfInterval)); assert(cPosInfInterval.intersects(interval)); assert(cPosInfInterval.intersects(cInterval)); assert(cPosInfInterval.intersects(iInterval)); assert(cPosInfInterval.intersects(posInfInterval)); assert(cPosInfInterval.intersects(cPosInfInterval)); assert(cPosInfInterval.intersects(iPosInfInterval)); assert(cPosInfInterval.intersects(negInfInterval)); assert(cPosInfInterval.intersects(cNegInfInterval)); assert(cPosInfInterval.intersects(iNegInfInterval)); assert(iPosInfInterval.intersects(interval)); assert(iPosInfInterval.intersects(cInterval)); assert(iPosInfInterval.intersects(iInterval)); assert(iPosInfInterval.intersects(posInfInterval)); assert(iPosInfInterval.intersects(cPosInfInterval)); assert(iPosInfInterval.intersects(iPosInfInterval)); assert(iPosInfInterval.intersects(negInfInterval)); assert(iPosInfInterval.intersects(cNegInfInterval)); assert(iPosInfInterval.intersects(iNegInfInterval)); //Verify Examples. assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(PosInfInterval!Date(Date(1990, 1, 7)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(PosInfInterval!Date(Date(1999, 5, 4)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(NegInfInterval!Date(Date(1996, 1, 2)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(NegInfInterval!Date(Date(2000, 7, 1)))); } //Test PosInfInterval's intersection(). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(I, J)(in I interval1, in J interval2) { interval1.intersection(interval2); } assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assertThrown!DateTimeException(testInterval(posInfInterval, NegInfInterval!Date(Date(2010, 7, 3)))); assertThrown!DateTimeException(testInterval(posInfInterval, NegInfInterval!Date(Date(2010, 7, 4)))); assert(posInfInterval.intersection(posInfInterval) == posInfInterval); assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) == Interval!Date(Date(2010, 7, 4), Date(2013, 7, 3))); assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) == Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5))); assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) == Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))); assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))); assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) == Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))); assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) == Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))); assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) == Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))); assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) == Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))); assert(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 5))); assert(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 6))) == PosInfInterval!Date(Date(2012, 1, 6))); assert(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 7))) == PosInfInterval!Date(Date(2012, 1, 7))); assert(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 8))) == PosInfInterval!Date(Date(2012, 1, 8))); assert(PosInfInterval!Date(Date(2010, 7, 3)).intersection(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2010, 7, 4)).intersection(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2010, 7, 5)).intersection(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 5))); assert(PosInfInterval!Date(Date(2012, 1, 6)).intersection(posInfInterval) == PosInfInterval!Date(Date(2012, 1, 6))); assert(PosInfInterval!Date(Date(2012, 1, 7)).intersection(posInfInterval) == PosInfInterval!Date(Date(2012, 1, 7))); assert(PosInfInterval!Date(Date(2012, 1, 8)).intersection(posInfInterval) == PosInfInterval!Date(Date(2012, 1, 8))); assert(posInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 5))) == Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5))); assert(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 6))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 6))); assert(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7))); assert(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!posInfInterval.intersection(interval).empty); assert(!posInfInterval.intersection(cInterval).empty); assert(!posInfInterval.intersection(iInterval).empty); assert(!posInfInterval.intersection(posInfInterval).empty); assert(!posInfInterval.intersection(cPosInfInterval).empty); assert(!posInfInterval.intersection(iPosInfInterval).empty); assert(!posInfInterval.intersection(negInfInterval).empty); assert(!posInfInterval.intersection(cNegInfInterval).empty); assert(!posInfInterval.intersection(iNegInfInterval).empty); assert(!cPosInfInterval.intersection(interval).empty); assert(!cPosInfInterval.intersection(cInterval).empty); assert(!cPosInfInterval.intersection(iInterval).empty); assert(!cPosInfInterval.intersection(posInfInterval).empty); assert(!cPosInfInterval.intersection(cPosInfInterval).empty); assert(!cPosInfInterval.intersection(iPosInfInterval).empty); assert(!cPosInfInterval.intersection(negInfInterval).empty); assert(!cPosInfInterval.intersection(cNegInfInterval).empty); assert(!cPosInfInterval.intersection(iNegInfInterval).empty); assert(!iPosInfInterval.intersection(interval).empty); assert(!iPosInfInterval.intersection(cInterval).empty); assert(!iPosInfInterval.intersection(iInterval).empty); assert(!iPosInfInterval.intersection(posInfInterval).empty); assert(!iPosInfInterval.intersection(cPosInfInterval).empty); assert(!iPosInfInterval.intersection(iPosInfInterval).empty); assert(!iPosInfInterval.intersection(negInfInterval).empty); assert(!iPosInfInterval.intersection(cNegInfInterval).empty); assert(!iPosInfInterval.intersection(iNegInfInterval).empty); //Verify Examples. assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1996, 1 , 2))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1999, 1 , 12))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 1, 12))); } //Test PosInfInterval's isAdjacent(). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval) { posInfInterval.isAdjacent(interval); } assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(!posInfInterval.isAdjacent(posInfInterval)); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 6)))); assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 8)))); assert(!PosInfInterval!Date(Date(2010, 7, 3)).isAdjacent(posInfInterval)); assert(!PosInfInterval!Date(Date(2010, 7, 4)).isAdjacent(posInfInterval)); assert(!PosInfInterval!Date(Date(2010, 7, 5)).isAdjacent(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 6)).isAdjacent(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 7)).isAdjacent(posInfInterval)); assert(!PosInfInterval!Date(Date(2012, 1, 8)).isAdjacent(posInfInterval)); assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 3)))); assert(posInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!posInfInterval.isAdjacent(interval)); assert(!posInfInterval.isAdjacent(cInterval)); assert(!posInfInterval.isAdjacent(iInterval)); assert(!posInfInterval.isAdjacent(posInfInterval)); assert(!posInfInterval.isAdjacent(cPosInfInterval)); assert(!posInfInterval.isAdjacent(iPosInfInterval)); assert(!posInfInterval.isAdjacent(negInfInterval)); assert(!posInfInterval.isAdjacent(cNegInfInterval)); assert(!posInfInterval.isAdjacent(iNegInfInterval)); assert(!cPosInfInterval.isAdjacent(interval)); assert(!cPosInfInterval.isAdjacent(cInterval)); assert(!cPosInfInterval.isAdjacent(iInterval)); assert(!cPosInfInterval.isAdjacent(posInfInterval)); assert(!cPosInfInterval.isAdjacent(cPosInfInterval)); assert(!cPosInfInterval.isAdjacent(iPosInfInterval)); assert(!cPosInfInterval.isAdjacent(negInfInterval)); assert(!cPosInfInterval.isAdjacent(cNegInfInterval)); assert(!cPosInfInterval.isAdjacent(iNegInfInterval)); assert(!iPosInfInterval.isAdjacent(interval)); assert(!iPosInfInterval.isAdjacent(cInterval)); assert(!iPosInfInterval.isAdjacent(iInterval)); assert(!iPosInfInterval.isAdjacent(posInfInterval)); assert(!iPosInfInterval.isAdjacent(cPosInfInterval)); assert(!iPosInfInterval.isAdjacent(iPosInfInterval)); assert(!iPosInfInterval.isAdjacent(negInfInterval)); assert(!iPosInfInterval.isAdjacent(cNegInfInterval)); assert(!iPosInfInterval.isAdjacent(iNegInfInterval)); //Verify Examples. assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2)))); assert(!PosInfInterval!Date(Date(1999, 1, 12)).isAdjacent(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(PosInfInterval!Date(Date(1990, 1, 7)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(PosInfInterval!Date(Date(1996, 1, 2)))); assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(NegInfInterval!Date(Date(1996, 1, 2)))); assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(NegInfInterval!Date(Date(2000, 7, 1)))); } //Test PosInfInterval's merge(). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval) { posInfInterval.merge(interval); } assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(posInfInterval.merge(posInfInterval) == posInfInterval); assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 1))); assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 6))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2010, 7, 3)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 3))); assert(PosInfInterval!Date(Date(2010, 7, 4)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2010, 7, 5)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2012, 1, 6)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2012, 1, 7)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2012, 1, 8)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 3))))); static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 4))))); static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 5))))); static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 6))))); static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 7))))); static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 8))))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!posInfInterval.merge(interval).empty); assert(!posInfInterval.merge(cInterval).empty); assert(!posInfInterval.merge(iInterval).empty); assert(!posInfInterval.merge(posInfInterval).empty); assert(!posInfInterval.merge(cPosInfInterval).empty); assert(!posInfInterval.merge(iPosInfInterval).empty); static assert(!__traits(compiles, posInfInterval.merge(negInfInterval))); static assert(!__traits(compiles, posInfInterval.merge(cNegInfInterval))); static assert(!__traits(compiles, posInfInterval.merge(iNegInfInterval))); assert(!cPosInfInterval.merge(interval).empty); assert(!cPosInfInterval.merge(cInterval).empty); assert(!cPosInfInterval.merge(iInterval).empty); assert(!cPosInfInterval.merge(posInfInterval).empty); assert(!cPosInfInterval.merge(cPosInfInterval).empty); assert(!cPosInfInterval.merge(iPosInfInterval).empty); static assert(!__traits(compiles, cPosInfInterval.merge(negInfInterval))); static assert(!__traits(compiles, cPosInfInterval.merge(cNegInfInterval))); static assert(!__traits(compiles, cPosInfInterval.merge(iNegInfInterval))); assert(!iPosInfInterval.merge(interval).empty); assert(!iPosInfInterval.merge(cInterval).empty); assert(!iPosInfInterval.merge(iInterval).empty); assert(!iPosInfInterval.merge(posInfInterval).empty); assert(!iPosInfInterval.merge(cPosInfInterval).empty); assert(!iPosInfInterval.merge(iPosInfInterval).empty); static assert(!__traits(compiles, iPosInfInterval.merge(negInfInterval))); static assert(!__traits(compiles, iPosInfInterval.merge(cNegInfInterval))); static assert(!__traits(compiles, iPosInfInterval.merge(iNegInfInterval))); //Verify Examples. assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == PosInfInterval!Date(Date(1996, 1 , 2))); assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1996, 1 , 2))); } //Test PosInfInterval's span(). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval) { posInfInterval.span(interval); } assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(posInfInterval.span(posInfInterval) == posInfInterval); assert(posInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 1))); assert(posInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 1))); assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 3))); assert(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 6))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2010, 7, 3)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 3))); assert(PosInfInterval!Date(Date(2010, 7, 4)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2010, 7, 5)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2012, 1, 6)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2012, 1, 7)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); assert(PosInfInterval!Date(Date(2012, 1, 8)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4))); static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2010, 7, 3))))); static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2010, 7, 4))))); static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2010, 7, 5))))); static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2012, 1, 6))))); static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2012, 1, 7))))); static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2012, 1, 8))))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!posInfInterval.span(interval).empty); assert(!posInfInterval.span(cInterval).empty); assert(!posInfInterval.span(iInterval).empty); assert(!posInfInterval.span(posInfInterval).empty); assert(!posInfInterval.span(cPosInfInterval).empty); assert(!posInfInterval.span(iPosInfInterval).empty); static assert(!__traits(compiles, posInfInterval.span(negInfInterval))); static assert(!__traits(compiles, posInfInterval.span(cNegInfInterval))); static assert(!__traits(compiles, posInfInterval.span(iNegInfInterval))); assert(!cPosInfInterval.span(interval).empty); assert(!cPosInfInterval.span(cInterval).empty); assert(!cPosInfInterval.span(iInterval).empty); assert(!cPosInfInterval.span(posInfInterval).empty); assert(!cPosInfInterval.span(cPosInfInterval).empty); assert(!cPosInfInterval.span(iPosInfInterval).empty); static assert(!__traits(compiles, cPosInfInterval.span(negInfInterval))); static assert(!__traits(compiles, cPosInfInterval.span(cNegInfInterval))); static assert(!__traits(compiles, cPosInfInterval.span(iNegInfInterval))); assert(!iPosInfInterval.span(interval).empty); assert(!iPosInfInterval.span(cInterval).empty); assert(!iPosInfInterval.span(iInterval).empty); assert(!iPosInfInterval.span(posInfInterval).empty); assert(!iPosInfInterval.span(cPosInfInterval).empty); assert(!iPosInfInterval.span(iPosInfInterval).empty); static assert(!__traits(compiles, iPosInfInterval.span(negInfInterval))); static assert(!__traits(compiles, iPosInfInterval.span(cNegInfInterval))); static assert(!__traits(compiles, iPosInfInterval.span(iNegInfInterval))); //Verify Examples. assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(500, 8, 9), Date(1602, 1, 31))) == PosInfInterval!Date(Date(500, 8, 9))); assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == PosInfInterval!Date(Date(1996, 1 , 2))); assert(PosInfInterval!Date(Date(1996, 1, 2)).span(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6))); assert(PosInfInterval!Date(Date(1996, 1, 2)).span(PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1996, 1 , 2))); } //Test PosInfInterval's shift(). unittest { auto interval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__) { interval.shift(duration); assert(interval == expected); } testInterval(interval, dur!"days"(22), PosInfInterval!Date(Date(2010, 7, 26))); testInterval(interval, dur!"days"(-22), PosInfInterval!Date(Date(2010, 6, 12))); const cInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iInterval = PosInfInterval!Date(Date(2010, 7, 4)); static assert(!__traits(compiles, cInterval.shift(dur!"days"(5)))); static assert(!__traits(compiles, iInterval.shift(dur!"days"(5)))); //Verify Examples. auto interval1 = PosInfInterval!Date(Date(1996, 1, 2)); auto interval2 = PosInfInterval!Date(Date(1996, 1, 2)); interval1.shift(dur!"days"(50)); assert(interval1 == PosInfInterval!Date(Date(1996, 2, 21))); interval2.shift(dur!"days"(-50)); assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13))); } //Test PosInfInterval's shift(int, int, AllowDayOverflow). unittest { { auto interval = PosInfInterval!Date(Date(2010, 7, 4)); static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__) { interval.shift(years, months, allow); assert(interval == expected); } testInterval(interval, 5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(2015, 7, 4))); testInterval(interval, -5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(2005, 7, 4))); auto interval2 = PosInfInterval!Date(Date(2000, 1, 29)); testInterval(interval2, 1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2001, 3, 1))); testInterval(interval2, 1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2000, 12, 29))); testInterval(interval2, -1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1998, 12, 29))); testInterval(interval2, -1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1999, 3, 1))); testInterval(interval2, 1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(2001, 2, 28))); testInterval(interval2, 1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(2000, 12, 29))); testInterval(interval2, -1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(1998, 12, 29))); testInterval(interval2, -1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(1999, 2, 28))); } const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static assert(!__traits(compiles, cPosInfInterval.shift(1))); static assert(!__traits(compiles, iPosInfInterval.shift(1))); //Verify Examples. auto interval1 = PosInfInterval!Date(Date(1996, 1, 2)); auto interval2 = PosInfInterval!Date(Date(1996, 1, 2)); interval1.shift(2); assert(interval1 == PosInfInterval!Date(Date(1998, 1, 2))); interval2.shift(-2); assert(interval2 == PosInfInterval!Date(Date(1994, 1, 2))); } //Test PosInfInterval's expand(). unittest { auto interval = PosInfInterval!Date(Date(2000, 7, 4)); static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__) { interval.expand(duration); assert(interval == expected); } testInterval(interval, dur!"days"(22), PosInfInterval!Date(Date(2000, 6, 12))); testInterval(interval, dur!"days"(-22), PosInfInterval!Date(Date(2000, 7, 26))); const cInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iInterval = PosInfInterval!Date(Date(2010, 7, 4)); static assert(!__traits(compiles, cInterval.expand(dur!"days"(5)))); static assert(!__traits(compiles, iInterval.expand(dur!"days"(5)))); //Verify Examples. auto interval1 = PosInfInterval!Date(Date(1996, 1, 2)); auto interval2 = PosInfInterval!Date(Date(1996, 1, 2)); interval1.expand(dur!"days"(2)); assert(interval1 == PosInfInterval!Date(Date(1995, 12, 31))); interval2.expand(dur!"days"(-2)); assert(interval2 == PosInfInterval!Date(Date(1996, 1, 4))); } //Test PosInfInterval's expand(int, int, AllowDayOverflow). unittest { { auto interval = PosInfInterval!Date(Date(2000, 7, 4)); static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__) { interval.expand(years, months, allow); assert(interval == expected); } testInterval(interval, 5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(1995, 7, 4))); testInterval(interval, -5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(2005, 7, 4))); auto interval2 = PosInfInterval!Date(Date(2000, 1, 29)); testInterval(interval2, 1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1998, 12, 29))); testInterval(interval2, 1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1999, 3, 1))); testInterval(interval2, -1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2001, 3, 1))); testInterval(interval2, -1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2000, 12, 29))); testInterval(interval2, 1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(1998, 12, 29))); testInterval(interval2, 1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(1999, 2, 28))); testInterval(interval2, -1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(2001, 2, 28))); testInterval(interval2, -1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(2000, 12, 29))); } const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); static assert(!__traits(compiles, cPosInfInterval.expand(1))); static assert(!__traits(compiles, iPosInfInterval.expand(1))); //Verify Examples. auto interval1 = PosInfInterval!Date(Date(1996, 1, 2)); auto interval2 = PosInfInterval!Date(Date(1996, 1, 2)); interval1.expand(2); assert(interval1 == PosInfInterval!Date(Date(1994, 1, 2))); interval2.expand(-2); assert(interval2 == PosInfInterval!Date(Date(1998, 1, 2))); } //Test PosInfInterval's fwdRange(). unittest { auto posInfInterval = PosInfInterval!Date(Date(2010, 9, 19)); static void testInterval(PosInfInterval!Date posInfInterval) { posInfInterval.fwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).popFront(); } assertThrown!DateTimeException(testInterval(posInfInterval)); assert(PosInfInterval!Date(Date(2010, 9, 12)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).front == Date(2010, 9, 12)); assert(PosInfInterval!Date(Date(2010, 9, 12)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri), PopFirst.yes).front == Date(2010, 9, 17)); //Verify Examples. auto interval = PosInfInterval!Date(Date(2010, 9, 1)); auto func = delegate (in Date date) { if((date.day & 1) == 0) return date + dur!"days"(2); return date + dur!"days"(1); }; auto range = interval.fwdRange(func); assert(range.front == Date(2010, 9, 1)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2). range.popFront(); assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(range.front == Date(2010, 9, 4)); range.popFront(); assert(range.front == Date(2010, 9, 6)); range.popFront(); assert(range.front == Date(2010, 9, 8)); range.popFront(); assert(!range.empty); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); assert(!cPosInfInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty); assert(!iPosInfInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty); } //Test PosInfInterval's toString(). unittest { assert(PosInfInterval!Date(Date(2010, 7, 4)).toString() == "[2010-Jul-04 - ∞)"); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); assert(cPosInfInterval.toString()); assert(iPosInfInterval.toString()); } /++ Represents an interval of time which has negative infinity as its starting point. Any ranges which iterate over a $(D NegInfInterval) are infinite. So, the main purpose of using $(D NegInfInterval) is to create an infinite range which starts at negative infinity and goes to a fixed end point. Iterate over it in reverse. +/ struct NegInfInterval(TP) { public: /++ Params: end = The time point which ends the interval. Example: -------------------- auto interval = PosInfInterval!Date(Date(1996, 1, 2)); -------------------- +/ this(in TP end) pure nothrow { _end = cast(TP)end; } /++ Params: rhs = The $(D NegInfInterval) to assign to this one. +/ ref NegInfInterval opAssign(const ref NegInfInterval rhs) pure nothrow { _end = cast(TP)rhs._end; return this; } /++ Params: rhs = The $(D NegInfInterval) to assign to this one. +/ ref NegInfInterval opAssign(NegInfInterval rhs) pure nothrow { _end = cast(TP)rhs._end; return this; } /++ The end point of the interval. It is excluded from the interval. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).end == Date(2012, 3, 1)); -------------------- +/ @property TP end() const pure nothrow { return cast(TP)_end; } /++ The end point of the interval. It is excluded from the interval. Params: timePoint = The time point to set end to. +/ @property void end(TP timePoint) pure nothrow { _end = timePoint; } /++ Whether the interval's length is 0. Always returns false. Example: -------------------- assert(!NegInfInterval!Date(Date(1996, 1, 2)).empty); -------------------- +/ @property bool empty() const pure nothrow { return false; } /++ Whether the given time point is within this interval. Params: timePoint = The time point to check for inclusion in this interval. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(1994, 12, 24))); assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2000, 1, 5))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2012, 3, 1))); -------------------- +/ bool contains(TP timePoint) const pure nothrow { return timePoint < _end; } /++ Whether the given interval is completely within this interval. Params: interval = The interval to check for inclusion in this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).contains( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).contains( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains( Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1)))); -------------------- +/ bool contains(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return interval._end <= _end; } /++ Whether the given interval is completely within this interval. Always returns false because an interval beginning at negative infinity can never contain an interval going to positive infinity. Params: interval = The interval to check for inclusion in this interval. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains( PosInfInterval!Date(Date(1999, 5, 4)))); -------------------- +/ bool contains(in PosInfInterval!TP interval) const pure nothrow { return false; } /++ Whether the given interval is completely within this interval. Params: interval = The interval to check for inclusion in this interval. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).contains( NegInfInterval!Date(Date(1996, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains( NegInfInterval!Date(Date(2013, 7, 9)))); -------------------- +/ bool contains(in NegInfInterval interval) const pure nothrow { return interval._end <= _end; } /++ Whether this interval is before the given time point. Params: timePoint = The time point to check whether this interval is before it. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(1994, 12, 24))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2000, 1, 5))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2012, 3, 1))); -------------------- +/ bool isBefore(in TP timePoint) const pure nothrow { return timePoint >= _end; } /++ Whether this interval is before the given interval and does not intersect it. Params: interval = The interval to check for against this interval. Throws: $(LREF DateTimeException) if the given interval is empty Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore( Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3)))); -------------------- +/ bool isBefore(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return _end <= interval._begin; } /++ Whether this interval is before the given interval and does not intersect it. Params: interval = The interval to check for against this interval. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore( PosInfInterval!Date(Date(1999, 5, 4)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore( PosInfInterval!Date(Date(2012, 3, 1)))); -------------------- +/ bool isBefore(in PosInfInterval!TP interval) const pure nothrow { return _end <= interval._begin; } /++ Whether this interval is before the given interval and does not intersect it. Always returns false because an interval beginning at negative infinity can never be before another interval beginning at negative infinity. Params: interval = The interval to check for against this interval. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore( NegInfInterval!Date(Date(1996, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore( NegInfInterval!Date(Date(2013, 7, 9)))); -------------------- +/ bool isBefore(in NegInfInterval interval) const pure nothrow { return false; } /++ Whether this interval is after the given time point. Always returns false because an interval beginning at negative infinity can never be after any time point. Params: timePoint = The time point to check whether this interval is after it. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(1994, 12, 24))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2000, 1, 5))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2012, 3, 1))); -------------------- +/ bool isAfter(in TP timePoint) const pure nothrow { return false; } /++ Whether this interval is after the given interval and does not intersect it. Always returns false (unless the given interval is empty) because an interval beginning at negative infinity can never be after any other interval. Params: interval = The interval to check against this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter( Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3)))); -------------------- +/ bool isAfter(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return false; } /++ Whether this interval is after the given interval and does not intersect it. Always returns false because an interval beginning at negative infinity can never be after any other interval. Params: interval = The interval to check against this interval. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter( PosInfInterval!Date(Date(1999, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter( PosInfInterval!Date(Date(2012, 3, 1)))); -------------------- +/ bool isAfter(in PosInfInterval!TP interval) const pure nothrow { return false; } /++ Whether this interval is after the given interval and does not intersect it. Always returns false because an interval beginning at negative infinity can never be after any other interval. Params: interval = The interval to check against this interval. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter( NegInfInterval!Date(Date(1996, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter( NegInfInterval!Date(Date(2013, 7, 9)))); -------------------- +/ bool isAfter(in NegInfInterval interval) const pure nothrow { return false; } /++ Whether the given interval overlaps this interval. Params: interval = The interval to check for intersection with this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects( Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects( Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3)))); -------------------- +/ bool intersects(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return interval._begin < _end; } /++ Whether the given interval overlaps this interval. Params: interval = The interval to check for intersection with this interval. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects( PosInfInterval!Date(Date(1999, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects( PosInfInterval!Date(Date(2012, 3, 1)))); -------------------- +/ bool intersects(in PosInfInterval!TP interval) const pure nothrow { return interval._begin < _end; } /++ Whether the given interval overlaps this interval. Always returns true because two intervals beginning at negative infinity always overlap. Params: interval = The interval to check for intersection with this interval. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects( NegInfInterval!Date(Date(1996, 5, 4)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects( NegInfInterval!Date(Date(2013, 7, 9)))); -------------------- +/ bool intersects(in NegInfInterval!TP interval) const pure nothrow { return true; } /++ Returns the intersection of two intervals Params: interval = The interval to intersect with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect or if the given interval is empty. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1990, 7 , 6), Date(2000, 8, 2))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection( Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1))); -------------------- +/ Interval!TP intersection(in Interval!TP interval) const { import std.format : format; enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval))); auto end = _end < interval._end ? _end : interval._end; return Interval!TP(interval._begin, end); } /++ Returns the intersection of two intervals Params: interval = The interval to intersect with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection( PosInfInterval!Date(Date(1990, 7, 6))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection( PosInfInterval!Date(Date(1999, 1, 12))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1))); -------------------- +/ Interval!TP intersection(in PosInfInterval!TP interval) const { import std.format : format; enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval))); return Interval!TP(interval._begin, _end); } /++ Returns the intersection of two intervals Params: interval = The interval to intersect with this interval. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection( NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(1999, 7 , 6))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection( NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2012, 3 , 1))); -------------------- +/ NegInfInterval intersection(in NegInfInterval interval) const nothrow { return NegInfInterval(_end < interval._end ? _end : interval._end); } /++ Whether the given interval is adjacent to this interval. Params: interval = The interval to check whether its adjecent to this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent( Interval!Date(Date(1999, 1, 12), Date(2012, 3, 1)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent( Interval!Date(Date(2012, 3, 1), Date(2019, 2, 2)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent( Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3)))); -------------------- +/ bool isAdjacent(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return interval._begin == _end; } /++ Whether the given interval is adjacent to this interval. Params: interval = The interval to check whether its adjecent to this interval. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent( PosInfInterval!Date(Date(1999, 5, 4)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent( PosInfInterval!Date(Date(2012, 3, 1)))); -------------------- +/ bool isAdjacent(in PosInfInterval!TP interval) const pure nothrow { return interval._begin == _end; } /++ Whether the given interval is adjacent to this interval. Always returns false because two intervals beginning at negative infinity can never be adjacent to one another. Params: interval = The interval to check whether its adjecent to this interval. Example: -------------------- assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent( NegInfInterval!Date(Date(1996, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent( NegInfInterval!Date(Date(2012, 3, 1)))); -------------------- +/ bool isAdjacent(in NegInfInterval interval) const pure nothrow { return false; } /++ Returns the union of two intervals Params: interval = The interval to merge with this interval. Throws: $(LREF DateTimeException) if the two intervals do not intersect and are not adjacent or if the given interval is empty. Note: There is no overload for $(D merge) which takes a $(D PosInfInterval), because an interval going from negative infinity to positive infinity is not possible. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).merge( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).merge( Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == NegInfInterval!Date(Date(2015, 9 , 2))); -------------------- +/ NegInfInterval merge(in Interval!TP interval) const { import std.format : format; enforce(this.isAdjacent(interval) || this.intersects(interval), new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval))); return NegInfInterval(_end > interval._end ? _end : interval._end); } /++ Returns the union of two intervals Params: interval = The interval to merge with this interval. Note: There is no overload for $(D merge) which takes a $(D PosInfInterval), because an interval going from negative infinity to positive infinity is not possible. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).merge( NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).merge( NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12))); -------------------- +/ NegInfInterval merge(in NegInfInterval interval) const pure nothrow { return NegInfInterval(_end > interval._end ? _end : interval._end); } /++ Returns an interval that covers from the earliest time point of two intervals up to (but not including) the latest time point of two intervals. Params: interval = The interval to create a span together with this interval. Throws: $(LREF DateTimeException) if the given interval is empty. Note: There is no overload for $(D span) which takes a $(D PosInfInterval), because an interval going from negative infinity to positive infinity is not possible. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).span( Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).span( Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == NegInfInterval!Date(Date(2015, 9 , 2))); assert(NegInfInterval!Date(Date(1600, 1, 7)).span( Interval!Date(Date(2012, 3, 11), Date(2017, 7, 1))) == NegInfInterval!Date(Date(2017, 7 , 1))); -------------------- +/ NegInfInterval span(in Interval!TP interval) const pure { interval._enforceNotEmpty(); return NegInfInterval(_end > interval._end ? _end : interval._end); } /++ Returns an interval that covers from the earliest time point of two intervals up to (but not including) the latest time point of two intervals. Params: interval = The interval to create a span together with this interval. Note: There is no overload for $(D span) which takes a $(D PosInfInterval), because an interval going from negative infinity to positive infinity is not possible. Example: -------------------- assert(NegInfInterval!Date(Date(2012, 3, 1)).span( NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).span( NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12))); -------------------- +/ NegInfInterval span(in NegInfInterval interval) const pure nothrow { return NegInfInterval(_end > interval._end ? _end : interval._end); } /++ Shifts the $(D end) of this interval forward or backwards in time by the given duration (a positive duration shifts the interval forward; a negative duration shifts it backward). Effectively, it does $(D end += duration). Params: duration = The duration to shift the interval by. Example: -------------------- auto interval1 = NegInfInterval!Date(Date(2012, 4, 5)); auto interval2 = NegInfInterval!Date(Date(2012, 4, 5)); interval1.shift(dur!"days"(50)); assert(interval1 == NegInfInterval!Date(Date(2012, 5, 25))); interval2.shift(dur!"days"(-50)); assert(interval2 == NegInfInterval!Date( Date(2012, 2, 15))); -------------------- +/ void shift(D)(D duration) pure nothrow if(__traits(compiles, end + duration)) { _end += duration; } static if(__traits(compiles, end.add!"months"(1)) && __traits(compiles, end.add!"years"(1))) { /++ Shifts the $(D end) of this interval forward or backwards in time by the given number of years and/or months (a positive number of years and months shifts the interval forward; a negative number shifts it backward). It adds the years the given years and months to end. It effectively calls $(D add!"years"()) and then $(D add!"months"()) on end with the given number of years and months. Params: years = The number of years to shift the interval by. months = The number of months to shift the interval by. allowOverflow = Whether the days should be allowed to overflow on $(D end), causing its month to increment. Throws: $(LREF DateTimeException) if empty is true or if the resulting interval would be invalid. Example: -------------------- auto interval1 = NegInfInterval!Date(Date(2012, 3, 1)); auto interval2 = NegInfInterval!Date(Date(2012, 3, 1)); interval1.shift(2); assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1))); interval2.shift(-2); assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1))); -------------------- +/ void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) if(isIntegral!T) { auto end = _end; end.add!"years"(years, allowOverflow); end.add!"months"(months, allowOverflow); _end = end; } } /++ Expands the interval forwards in time. Effectively, it does $(D end += duration). Params: duration = The duration to expand the interval by. Example: -------------------- auto interval1 = NegInfInterval!Date(Date(2012, 3, 1)); auto interval2 = NegInfInterval!Date(Date(2012, 3, 1)); interval1.expand(dur!"days"(2)); assert(interval1 == NegInfInterval!Date(Date(2012, 3, 3))); interval2.expand(dur!"days"(-2)); assert(interval2 == NegInfInterval!Date(Date(2012, 2, 28))); -------------------- +/ void expand(D)(D duration) pure nothrow if(__traits(compiles, end + duration)) { _end += duration; } static if(__traits(compiles, end.add!"months"(1)) && __traits(compiles, end.add!"years"(1))) { /++ Expands the interval forwards and/or backwards in time. Effectively, it adds the given number of months/years to end. Params: years = The number of years to expand the interval by. months = The number of months to expand the interval by. allowOverflow = Whether the days should be allowed to overflow on $(D end), causing their month to increment. Throws: $(LREF DateTimeException) if empty is true or if the resulting interval would be invalid. Example: -------------------- auto interval1 = NegInfInterval!Date(Date(2012, 3, 1)); auto interval2 = NegInfInterval!Date(Date(2012, 3, 1)); interval1.expand(2); assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1))); interval2.expand(-2); assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1))); -------------------- +/ void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) if(isIntegral!T) { auto end = _end; end.add!"years"(years, allowOverflow); end.add!"months"(months, allowOverflow); _end = end; return; } } /++ Returns a range which iterates backwards over the interval, starting at $(D end), using $(D_PARAM func) to generate each successive time point. The range's $(D front) is the interval's $(D end). $(D_PARAM func) is used to generate the next $(D front) when $(D popFront) is called. If $(D_PARAM popFirst) is $(D PopFirst.yes), then $(D popFront) is called before the range is returned (so that $(D front) is a time point which $(D_PARAM func) would generate). If $(D_PARAM func) ever generates a time point greater than or equal to the current $(D front) of the range, then a $(LREF DateTimeException) will be thrown. There are helper functions in this module which generate common delegates to pass to $(D bwdRange). Their documentation starts with "Range-generating function," to make them easily searchable. Params: func = The function used to generate the time points of the range over the interval. popFirst = Whether $(D popFront) should be called on the range before returning it. Throws: $(LREF DateTimeException) if this interval is empty. Warning: $(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func) would be a function pointer to a pure function, but forcing $(D_PARAM func) to be pure is far too restrictive to be useful, and in order to have the ease of use of having functions which generate functions to pass to $(D fwdRange), $(D_PARAM func) must be a delegate. If $(D_PARAM func) retains state which changes as it is called, then some algorithms will not work correctly, because the range's $(D save) will have failed to have really saved the range's state. To avoid such bugs, don't pass a delegate which is not logically pure to $(D fwdRange). If $(D_PARAM func) is given the same time point with two different calls, it must return the same result both times. Of course, none of the functions in this module have this problem, so it's only relevant for custom delegates. Example: -------------------- auto interval = NegInfInterval!Date(Date(2010, 9, 9)); auto func = delegate (in Date date) //For iterating over even-numbered days. { if((date.day & 1) == 0) return date - dur!"days"(2); return date - dur!"days"(1); }; auto range = interval.bwdRange(func); assert(range.front == Date(2010, 9, 9)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8). range.popFront(); assert(range.front == Date(2010, 9, 8)); range.popFront(); assert(range.front == Date(2010, 9, 6)); range.popFront(); assert(range.front == Date(2010, 9, 4)); range.popFront(); assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(!range.empty); -------------------- +/ NegInfIntervalRange!(TP) bwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no) const { auto range = NegInfIntervalRange!(TP)(this, func); if(popFirst == PopFirst.yes) range.popFront(); return range; } /+ Converts this interval to a string. +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() { return _toStringImpl(); } /++ Converts this interval to a string. +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() const nothrow { return _toStringImpl(); } private: /+ Since we have two versions of toString(), we have _toStringImpl() so that they can share implementations. +/ string _toStringImpl() const nothrow { import std.format : format; try return format("[-∞ - %s)", _end); catch(Exception e) assert(0, "format() threw."); } TP _end; } //Test NegInfInterval's constructor. unittest { NegInfInterval!Date(Date.init); NegInfInterval!TimeOfDay(TimeOfDay.init); NegInfInterval!DateTime(DateTime.init); NegInfInterval!SysTime(SysTime(0)); } //Test NegInfInterval's end. unittest { assert(NegInfInterval!Date(Date(2010, 1, 1)).end == Date(2010, 1, 1)); assert(NegInfInterval!Date(Date(2010, 1, 1)).end == Date(2010, 1, 1)); assert(NegInfInterval!Date(Date(1998, 1, 1)).end == Date(1998, 1, 1)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(cNegInfInterval.end != Date.init); assert(iNegInfInterval.end != Date.init); //Verify Examples. assert(NegInfInterval!Date(Date(2012, 3, 1)).end == Date(2012, 3, 1)); } //Test NegInfInterval's empty. unittest { assert(!NegInfInterval!Date(Date(2010, 1, 1)).empty); assert(!NegInfInterval!TimeOfDay(TimeOfDay(0, 30, 0)).empty); assert(!NegInfInterval!DateTime(DateTime(2010, 1, 1, 0, 30, 0)).empty); assert(!NegInfInterval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0))).empty); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!cNegInfInterval.empty); assert(!iNegInfInterval.empty); //Verify Examples. assert(!NegInfInterval!Date(Date(1996, 1, 2)).empty); } //Test NegInfInterval's contains(time point). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(negInfInterval.contains(Date(2009, 7, 4))); assert(negInfInterval.contains(Date(2010, 7, 3))); assert(negInfInterval.contains(Date(2010, 7, 4))); assert(negInfInterval.contains(Date(2010, 7, 5))); assert(negInfInterval.contains(Date(2011, 7, 1))); assert(negInfInterval.contains(Date(2012, 1, 6))); assert(!negInfInterval.contains(Date(2012, 1, 7))); assert(!negInfInterval.contains(Date(2012, 1, 8))); assert(!negInfInterval.contains(Date(2013, 1, 7))); const cdate = Date(2010, 7, 6); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(negInfInterval.contains(cdate)); assert(cNegInfInterval.contains(cdate)); assert(iNegInfInterval.contains(cdate)); //Verify Examples. assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(1994, 12, 24))); assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2000, 1, 5))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2012, 3, 1))); } //Test NegInfInterval's contains(Interval). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval) { negInfInterval.contains(interval); } assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(negInfInterval.contains(negInfInterval)); assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!negInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(negInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!negInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(!negInfInterval.contains(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!negInfInterval.contains(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(negInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 3)))); assert(negInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 4)))); assert(negInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 5)))); assert(negInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 6)))); assert(negInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!negInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 8)))); assert(!NegInfInterval!Date(Date(2010, 7, 3)).contains(negInfInterval)); assert(!NegInfInterval!Date(Date(2010, 7, 4)).contains(negInfInterval)); assert(!NegInfInterval!Date(Date(2010, 7, 5)).contains(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 6)).contains(negInfInterval)); assert(NegInfInterval!Date(Date(2012, 1, 7)).contains(negInfInterval)); assert(NegInfInterval!Date(Date(2012, 1, 8)).contains(negInfInterval)); assert(!negInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!negInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!negInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!negInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 6)))); assert(!negInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!negInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(negInfInterval.contains(interval)); assert(negInfInterval.contains(cInterval)); assert(negInfInterval.contains(iInterval)); assert(!negInfInterval.contains(posInfInterval)); assert(!negInfInterval.contains(cPosInfInterval)); assert(!negInfInterval.contains(iPosInfInterval)); assert(negInfInterval.contains(negInfInterval)); assert(negInfInterval.contains(cNegInfInterval)); assert(negInfInterval.contains(iNegInfInterval)); assert(cNegInfInterval.contains(interval)); assert(cNegInfInterval.contains(cInterval)); assert(cNegInfInterval.contains(iInterval)); assert(!cNegInfInterval.contains(posInfInterval)); assert(!cNegInfInterval.contains(cPosInfInterval)); assert(!cNegInfInterval.contains(iPosInfInterval)); assert(cNegInfInterval.contains(negInfInterval)); assert(cNegInfInterval.contains(cNegInfInterval)); assert(cNegInfInterval.contains(iNegInfInterval)); assert(iNegInfInterval.contains(interval)); assert(iNegInfInterval.contains(cInterval)); assert(iNegInfInterval.contains(iInterval)); assert(!iNegInfInterval.contains(posInfInterval)); assert(!iNegInfInterval.contains(cPosInfInterval)); assert(!iNegInfInterval.contains(iPosInfInterval)); assert(iNegInfInterval.contains(negInfInterval)); assert(iNegInfInterval.contains(cNegInfInterval)); assert(iNegInfInterval.contains(iNegInfInterval)); //Verify Examples. assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(PosInfInterval!Date(Date(1999, 5, 4)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(1996, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(2013, 7, 9)))); } //Test NegInfInterval's isBefore(time point). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.isBefore(Date(2009, 7, 4))); assert(!negInfInterval.isBefore(Date(2010, 7, 3))); assert(!negInfInterval.isBefore(Date(2010, 7, 4))); assert(!negInfInterval.isBefore(Date(2010, 7, 5))); assert(!negInfInterval.isBefore(Date(2011, 7, 1))); assert(!negInfInterval.isBefore(Date(2012, 1, 6))); assert(negInfInterval.isBefore(Date(2012, 1, 7))); assert(negInfInterval.isBefore(Date(2012, 1, 8))); assert(negInfInterval.isBefore(Date(2013, 1, 7))); const cdate = Date(2010, 7, 6); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.isBefore(cdate)); assert(!cNegInfInterval.isBefore(cdate)); assert(!iNegInfInterval.isBefore(cdate)); //Verify Examples. assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(1994, 12, 24))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2000, 1, 5))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2012, 3, 1))); } //Test NegInfInterval's isBefore(Interval). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval) { negInfInterval.isBefore(interval); } assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(!negInfInterval.isBefore(negInfInterval)); assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(!negInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!negInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(negInfInterval.isBefore(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(negInfInterval.isBefore(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 3)))); assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 8)))); assert(!NegInfInterval!Date(Date(2010, 7, 3)).isBefore(negInfInterval)); assert(!NegInfInterval!Date(Date(2010, 7, 4)).isBefore(negInfInterval)); assert(!NegInfInterval!Date(Date(2010, 7, 5)).isBefore(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 6)).isBefore(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 7)).isBefore(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 8)).isBefore(negInfInterval)); assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 6)))); assert(negInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 7)))); assert(negInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.isBefore(interval)); assert(!negInfInterval.isBefore(cInterval)); assert(!negInfInterval.isBefore(iInterval)); assert(!negInfInterval.isBefore(posInfInterval)); assert(!negInfInterval.isBefore(cPosInfInterval)); assert(!negInfInterval.isBefore(iPosInfInterval)); assert(!negInfInterval.isBefore(negInfInterval)); assert(!negInfInterval.isBefore(cNegInfInterval)); assert(!negInfInterval.isBefore(iNegInfInterval)); assert(!cNegInfInterval.isBefore(interval)); assert(!cNegInfInterval.isBefore(cInterval)); assert(!cNegInfInterval.isBefore(iInterval)); assert(!cNegInfInterval.isBefore(posInfInterval)); assert(!cNegInfInterval.isBefore(cPosInfInterval)); assert(!cNegInfInterval.isBefore(iPosInfInterval)); assert(!cNegInfInterval.isBefore(negInfInterval)); assert(!cNegInfInterval.isBefore(cNegInfInterval)); assert(!cNegInfInterval.isBefore(iNegInfInterval)); assert(!iNegInfInterval.isBefore(interval)); assert(!iNegInfInterval.isBefore(cInterval)); assert(!iNegInfInterval.isBefore(iInterval)); assert(!iNegInfInterval.isBefore(posInfInterval)); assert(!iNegInfInterval.isBefore(cPosInfInterval)); assert(!iNegInfInterval.isBefore(iPosInfInterval)); assert(!iNegInfInterval.isBefore(negInfInterval)); assert(!iNegInfInterval.isBefore(cNegInfInterval)); assert(!iNegInfInterval.isBefore(iNegInfInterval)); //Verify Examples. assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(1999, 5, 4)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(2012, 3, 1)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(1996, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(2013, 7, 9)))); } //Test NegInfInterval's isAfter(time point). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.isAfter(Date(2009, 7, 4))); assert(!negInfInterval.isAfter(Date(2010, 7, 3))); assert(!negInfInterval.isAfter(Date(2010, 7, 4))); assert(!negInfInterval.isAfter(Date(2010, 7, 5))); assert(!negInfInterval.isAfter(Date(2011, 7, 1))); assert(!negInfInterval.isAfter(Date(2012, 1, 6))); assert(!negInfInterval.isAfter(Date(2012, 1, 7))); assert(!negInfInterval.isAfter(Date(2012, 1, 8))); assert(!negInfInterval.isAfter(Date(2013, 1, 7))); const cdate = Date(2010, 7, 6); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.isAfter(cdate)); assert(!cNegInfInterval.isAfter(cdate)); assert(!iNegInfInterval.isAfter(cdate)); } //Test NegInfInterval's isAfter(Interval). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval) { negInfInterval.isAfter(interval); } assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(!negInfInterval.isAfter(negInfInterval)); assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 3)))); assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 8)))); assert(!NegInfInterval!Date(Date(2010, 7, 3)).isAfter(negInfInterval)); assert(!NegInfInterval!Date(Date(2010, 7, 4)).isAfter(negInfInterval)); assert(!NegInfInterval!Date(Date(2010, 7, 5)).isAfter(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 6)).isAfter(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 7)).isAfter(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 8)).isAfter(negInfInterval)); assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 6)))); assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.isAfter(interval)); assert(!negInfInterval.isAfter(cInterval)); assert(!negInfInterval.isAfter(iInterval)); assert(!negInfInterval.isAfter(posInfInterval)); assert(!negInfInterval.isAfter(cPosInfInterval)); assert(!negInfInterval.isAfter(iPosInfInterval)); assert(!negInfInterval.isAfter(negInfInterval)); assert(!negInfInterval.isAfter(cNegInfInterval)); assert(!negInfInterval.isAfter(iNegInfInterval)); assert(!cNegInfInterval.isAfter(interval)); assert(!cNegInfInterval.isAfter(cInterval)); assert(!cNegInfInterval.isAfter(iInterval)); assert(!cNegInfInterval.isAfter(posInfInterval)); assert(!cNegInfInterval.isAfter(cPosInfInterval)); assert(!cNegInfInterval.isAfter(iPosInfInterval)); assert(!cNegInfInterval.isAfter(negInfInterval)); assert(!cNegInfInterval.isAfter(cNegInfInterval)); assert(!cNegInfInterval.isAfter(iNegInfInterval)); assert(!iNegInfInterval.isAfter(interval)); assert(!iNegInfInterval.isAfter(cInterval)); assert(!iNegInfInterval.isAfter(iInterval)); assert(!iNegInfInterval.isAfter(posInfInterval)); assert(!iNegInfInterval.isAfter(cPosInfInterval)); assert(!iNegInfInterval.isAfter(iPosInfInterval)); assert(!iNegInfInterval.isAfter(negInfInterval)); assert(!iNegInfInterval.isAfter(cNegInfInterval)); assert(!iNegInfInterval.isAfter(iNegInfInterval)); //Verify Examples. assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(1994, 12, 24))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2000, 1, 5))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2012, 3, 1))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(1999, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(2012, 3, 1)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(1996, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(2013, 7, 9)))); } //Test NegInfInterval's intersects(). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval) { negInfInterval.intersects(interval); } assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(negInfInterval.intersects(negInfInterval)); assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(negInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(negInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(!negInfInterval.intersects(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!negInfInterval.intersects(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(negInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 3)))); assert(negInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 4)))); assert(negInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 5)))); assert(negInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 6)))); assert(negInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 7)))); assert(negInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 8)))); assert(NegInfInterval!Date(Date(2010, 7, 3)).intersects(negInfInterval)); assert(NegInfInterval!Date(Date(2010, 7, 4)).intersects(negInfInterval)); assert(NegInfInterval!Date(Date(2010, 7, 5)).intersects(negInfInterval)); assert(NegInfInterval!Date(Date(2012, 1, 6)).intersects(negInfInterval)); assert(NegInfInterval!Date(Date(2012, 1, 7)).intersects(negInfInterval)); assert(NegInfInterval!Date(Date(2012, 1, 8)).intersects(negInfInterval)); assert(negInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 3)))); assert(negInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 4)))); assert(negInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 5)))); assert(negInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 6)))); assert(!negInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!negInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(negInfInterval.intersects(interval)); assert(negInfInterval.intersects(cInterval)); assert(negInfInterval.intersects(iInterval)); assert(negInfInterval.intersects(posInfInterval)); assert(negInfInterval.intersects(cPosInfInterval)); assert(negInfInterval.intersects(iPosInfInterval)); assert(negInfInterval.intersects(negInfInterval)); assert(negInfInterval.intersects(cNegInfInterval)); assert(negInfInterval.intersects(iNegInfInterval)); assert(cNegInfInterval.intersects(interval)); assert(cNegInfInterval.intersects(cInterval)); assert(cNegInfInterval.intersects(iInterval)); assert(cNegInfInterval.intersects(posInfInterval)); assert(cNegInfInterval.intersects(cPosInfInterval)); assert(cNegInfInterval.intersects(iPosInfInterval)); assert(cNegInfInterval.intersects(negInfInterval)); assert(cNegInfInterval.intersects(cNegInfInterval)); assert(cNegInfInterval.intersects(iNegInfInterval)); assert(iNegInfInterval.intersects(interval)); assert(iNegInfInterval.intersects(cInterval)); assert(iNegInfInterval.intersects(iInterval)); assert(iNegInfInterval.intersects(posInfInterval)); assert(iNegInfInterval.intersects(cPosInfInterval)); assert(iNegInfInterval.intersects(iPosInfInterval)); assert(iNegInfInterval.intersects(negInfInterval)); assert(iNegInfInterval.intersects(cNegInfInterval)); assert(iNegInfInterval.intersects(iNegInfInterval)); //Verify Examples. assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(1999, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(2012, 3, 1)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(1996, 5, 4)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(2013, 7, 9)))); } //Test NegInfInterval's intersection(). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(I, J)(in I interval1, in J interval2) { interval1.intersection(interval2); } assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assertThrown!DateTimeException(testInterval(negInfInterval, PosInfInterval!Date(Date(2012, 1, 7)))); assertThrown!DateTimeException(testInterval(negInfInterval, PosInfInterval!Date(Date(2012, 1, 8)))); assert(negInfInterval.intersection(negInfInterval) == negInfInterval); assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) == Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))); assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) == Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7))); assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) == Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))); assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) == Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))); assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))); assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) == Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))); assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) == Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))); assert(negInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) == Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))); assert(negInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) == Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))); assert(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 3))) == NegInfInterval!Date(Date(2010, 7, 3))); assert(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 4))) == NegInfInterval!Date(Date(2010, 7, 4))); assert(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 5))) == NegInfInterval!Date(Date(2010, 7, 5))); assert(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 6))); assert(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2010, 7, 3)).intersection(negInfInterval) == NegInfInterval!Date(Date(2010, 7, 3))); assert(NegInfInterval!Date(Date(2010, 7, 4)).intersection(negInfInterval) == NegInfInterval!Date(Date(2010, 7, 4))); assert(NegInfInterval!Date(Date(2010, 7, 5)).intersection(negInfInterval) == NegInfInterval!Date(Date(2010, 7, 5))); assert(NegInfInterval!Date(Date(2012, 1, 6)).intersection(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 6))); assert(NegInfInterval!Date(Date(2012, 1, 7)).intersection(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2012, 1, 8)).intersection(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 3))) == Interval!Date(Date(2010, 7, 3), Date(2012, 1 ,7))); assert(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 4))) == Interval!Date(Date(2010, 7, 4), Date(2012, 1 ,7))); assert(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 5))) == Interval!Date(Date(2010, 7, 5), Date(2012, 1 ,7))); assert(negInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 6))) == Interval!Date(Date(2012, 1, 6), Date(2012, 1 ,7))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.intersection(interval).empty); assert(!negInfInterval.intersection(cInterval).empty); assert(!negInfInterval.intersection(iInterval).empty); assert(!negInfInterval.intersection(posInfInterval).empty); assert(!negInfInterval.intersection(cPosInfInterval).empty); assert(!negInfInterval.intersection(iPosInfInterval).empty); assert(!negInfInterval.intersection(negInfInterval).empty); assert(!negInfInterval.intersection(cNegInfInterval).empty); assert(!negInfInterval.intersection(iNegInfInterval).empty); assert(!cNegInfInterval.intersection(interval).empty); assert(!cNegInfInterval.intersection(cInterval).empty); assert(!cNegInfInterval.intersection(iInterval).empty); assert(!cNegInfInterval.intersection(posInfInterval).empty); assert(!cNegInfInterval.intersection(cPosInfInterval).empty); assert(!cNegInfInterval.intersection(iPosInfInterval).empty); assert(!cNegInfInterval.intersection(negInfInterval).empty); assert(!cNegInfInterval.intersection(cNegInfInterval).empty); assert(!cNegInfInterval.intersection(iNegInfInterval).empty); assert(!iNegInfInterval.intersection(interval).empty); assert(!iNegInfInterval.intersection(cInterval).empty); assert(!iNegInfInterval.intersection(iInterval).empty); assert(!iNegInfInterval.intersection(posInfInterval).empty); assert(!iNegInfInterval.intersection(cPosInfInterval).empty); assert(!iNegInfInterval.intersection(iPosInfInterval).empty); assert(!iNegInfInterval.intersection(negInfInterval).empty); assert(!iNegInfInterval.intersection(cNegInfInterval).empty); assert(!iNegInfInterval.intersection(iNegInfInterval).empty); //Verify Examples. assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1990, 7 , 6), Date(2000, 8, 2))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(1999, 7 , 6))); assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2012, 3 , 1))); } //Test NegInfInterval's isAdjacent(). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval) { negInfInterval.isAdjacent(interval); } assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(!negInfInterval.isAdjacent(negInfInterval)); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)))); assert(negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)))); assert(!negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 3)))); assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 4)))); assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 5)))); assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 6)))); assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 7)))); assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 8)))); assert(!NegInfInterval!Date(Date(2010, 7, 3)).isAdjacent(negInfInterval)); assert(!NegInfInterval!Date(Date(2010, 7, 4)).isAdjacent(negInfInterval)); assert(!NegInfInterval!Date(Date(2010, 7, 5)).isAdjacent(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 6)).isAdjacent(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 7)).isAdjacent(negInfInterval)); assert(!NegInfInterval!Date(Date(2012, 1, 8)).isAdjacent(negInfInterval)); assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 3)))); assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 4)))); assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 5)))); assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 6)))); assert(negInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 7)))); assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 8)))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.isAdjacent(interval)); assert(!negInfInterval.isAdjacent(cInterval)); assert(!negInfInterval.isAdjacent(iInterval)); assert(!negInfInterval.isAdjacent(posInfInterval)); assert(!negInfInterval.isAdjacent(cPosInfInterval)); assert(!negInfInterval.isAdjacent(iPosInfInterval)); assert(!negInfInterval.isAdjacent(negInfInterval)); assert(!negInfInterval.isAdjacent(cNegInfInterval)); assert(!negInfInterval.isAdjacent(iNegInfInterval)); assert(!cNegInfInterval.isAdjacent(interval)); assert(!cNegInfInterval.isAdjacent(cInterval)); assert(!cNegInfInterval.isAdjacent(iInterval)); assert(!cNegInfInterval.isAdjacent(posInfInterval)); assert(!cNegInfInterval.isAdjacent(cPosInfInterval)); assert(!cNegInfInterval.isAdjacent(iPosInfInterval)); assert(!cNegInfInterval.isAdjacent(negInfInterval)); assert(!cNegInfInterval.isAdjacent(cNegInfInterval)); assert(!cNegInfInterval.isAdjacent(iNegInfInterval)); assert(!iNegInfInterval.isAdjacent(interval)); assert(!iNegInfInterval.isAdjacent(cInterval)); assert(!iNegInfInterval.isAdjacent(iInterval)); assert(!iNegInfInterval.isAdjacent(posInfInterval)); assert(!iNegInfInterval.isAdjacent(cPosInfInterval)); assert(!iNegInfInterval.isAdjacent(iPosInfInterval)); assert(!iNegInfInterval.isAdjacent(negInfInterval)); assert(!iNegInfInterval.isAdjacent(cNegInfInterval)); assert(!iNegInfInterval.isAdjacent(iNegInfInterval)); //Verify Examples. assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1999, 1, 12), Date(2012, 3, 1)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2012, 3, 1), Date(2019, 2, 2)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(1999, 5, 4)))); assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(2012, 3, 1)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(1996, 5, 4)))); assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(2012, 3, 1)))); } //Test NegInfInterval's merge(). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(I, J)(in I interval1, in J interval2) { interval1.merge(interval2); } assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)))); assert(negInfInterval.merge(negInfInterval) == negInfInterval); assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) == NegInfInterval!Date(Date(2013, 7, 3))); assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); assert(negInfInterval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); assert(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 3))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 4))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 5))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); assert(NegInfInterval!Date(Date(2010, 7, 3)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2010, 7, 4)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2010, 7, 5)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2012, 1, 6)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2012, 1, 7)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2012, 1, 8)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 8))); static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 3))))); static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 4))))); static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 5))))); static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 6))))); static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 7))))); static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 8))))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.merge(interval).empty); assert(!negInfInterval.merge(cInterval).empty); assert(!negInfInterval.merge(iInterval).empty); static assert(!__traits(compiles, negInfInterval.merge(posInfInterval))); static assert(!__traits(compiles, negInfInterval.merge(cPosInfInterval))); static assert(!__traits(compiles, negInfInterval.merge(iPosInfInterval))); assert(!negInfInterval.merge(negInfInterval).empty); assert(!negInfInterval.merge(cNegInfInterval).empty); assert(!negInfInterval.merge(iNegInfInterval).empty); assert(!cNegInfInterval.merge(interval).empty); assert(!cNegInfInterval.merge(cInterval).empty); assert(!cNegInfInterval.merge(iInterval).empty); static assert(!__traits(compiles, cNegInfInterval.merge(posInfInterval))); static assert(!__traits(compiles, cNegInfInterval.merge(cPosInfInterval))); static assert(!__traits(compiles, cNegInfInterval.merge(iPosInfInterval))); assert(!cNegInfInterval.merge(negInfInterval).empty); assert(!cNegInfInterval.merge(cNegInfInterval).empty); assert(!cNegInfInterval.merge(iNegInfInterval).empty); assert(!iNegInfInterval.merge(interval).empty); assert(!iNegInfInterval.merge(cInterval).empty); assert(!iNegInfInterval.merge(iInterval).empty); static assert(!__traits(compiles, iNegInfInterval.merge(posInfInterval))); static assert(!__traits(compiles, iNegInfInterval.merge(cPosInfInterval))); static assert(!__traits(compiles, iNegInfInterval.merge(iPosInfInterval))); assert(!iNegInfInterval.merge(negInfInterval).empty); assert(!iNegInfInterval.merge(cNegInfInterval).empty); assert(!iNegInfInterval.merge(iNegInfInterval).empty); //Verify Examples. assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == NegInfInterval!Date(Date(2015, 9 , 2))); assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12))); } //Test NegInfInterval's span(). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(I, J)(in I interval1, in J interval2) { interval1.span(interval2); } assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0)))); assert(negInfInterval.span(negInfInterval) == negInfInterval); assert(negInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) == NegInfInterval!Date(Date(2013, 7, 3))); assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); assert(negInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); assert(negInfInterval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); assert(negInfInterval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) == NegInfInterval!Date(Date(2012, 1, 9))); assert(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 3))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 4))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 5))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7))); assert(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8))); assert(NegInfInterval!Date(Date(2010, 7, 3)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2010, 7, 4)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2010, 7, 5)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2012, 1, 6)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2012, 1, 7)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7))); assert(NegInfInterval!Date(Date(2012, 1, 8)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 8))); static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2010, 7, 3))))); static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2010, 7, 4))))); static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2010, 7, 5))))); static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2012, 1, 6))))); static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2012, 1, 7))))); static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2012, 1, 8))))); auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!negInfInterval.span(interval).empty); assert(!negInfInterval.span(cInterval).empty); assert(!negInfInterval.span(iInterval).empty); static assert(!__traits(compiles, negInfInterval.span(posInfInterval))); static assert(!__traits(compiles, negInfInterval.span(cPosInfInterval))); static assert(!__traits(compiles, negInfInterval.span(iPosInfInterval))); assert(!negInfInterval.span(negInfInterval).empty); assert(!negInfInterval.span(cNegInfInterval).empty); assert(!negInfInterval.span(iNegInfInterval).empty); assert(!cNegInfInterval.span(interval).empty); assert(!cNegInfInterval.span(cInterval).empty); assert(!cNegInfInterval.span(iInterval).empty); static assert(!__traits(compiles, cNegInfInterval.span(posInfInterval))); static assert(!__traits(compiles, cNegInfInterval.span(cPosInfInterval))); static assert(!__traits(compiles, cNegInfInterval.span(iPosInfInterval))); assert(!cNegInfInterval.span(negInfInterval).empty); assert(!cNegInfInterval.span(cNegInfInterval).empty); assert(!cNegInfInterval.span(iNegInfInterval).empty); assert(!iNegInfInterval.span(interval).empty); assert(!iNegInfInterval.span(cInterval).empty); assert(!iNegInfInterval.span(iInterval).empty); static assert(!__traits(compiles, iNegInfInterval.span(posInfInterval))); static assert(!__traits(compiles, iNegInfInterval.span(cPosInfInterval))); static assert(!__traits(compiles, iNegInfInterval.span(iPosInfInterval))); assert(!iNegInfInterval.span(negInfInterval).empty); assert(!iNegInfInterval.span(cNegInfInterval).empty); assert(!iNegInfInterval.span(iNegInfInterval).empty); //Verify Examples. assert(NegInfInterval!Date(Date(2012, 3, 1)).span(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).span(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == NegInfInterval!Date(Date(2015, 9 , 2))); assert(NegInfInterval!Date(Date(1600, 1, 7)).span(Interval!Date(Date(2012, 3, 11), Date(2017, 7, 1))) == NegInfInterval!Date(Date(2017, 7 , 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).span(NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(2012, 3 , 1))); assert(NegInfInterval!Date(Date(2012, 3, 1)).span(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12))); } //Test NegInfInterval's shift(). unittest { auto interval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__) { interval.shift(duration); assert(interval == expected); } testInterval(interval, dur!"days"(22), NegInfInterval!Date(Date(2012, 1, 29))); testInterval(interval, dur!"days"(-22), NegInfInterval!Date(Date(2011, 12, 16))); const cInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iInterval = NegInfInterval!Date(Date(2012, 1, 7)); static assert(!__traits(compiles, cInterval.shift(dur!"days"(5)))); static assert(!__traits(compiles, iInterval.shift(dur!"days"(5)))); //Verify Examples. auto interval1 = NegInfInterval!Date(Date(2012, 4, 5)); auto interval2 = NegInfInterval!Date(Date(2012, 4, 5)); interval1.shift(dur!"days"(50)); assert(interval1 == NegInfInterval!Date(Date(2012, 5, 25))); interval2.shift(dur!"days"(-50)); assert(interval2 == NegInfInterval!Date( Date(2012, 2, 15))); } //Test NegInfInterval's shift(int, int, AllowDayOverflow). unittest { { auto interval = NegInfInterval!Date(Date(2012, 1, 7)); static void testIntervalFail(I)(I interval, int years, int months) { interval.shift(years, months); } static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__) { interval.shift(years, months, allow); assert(interval == expected); } testInterval(interval, 5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2017, 1, 7))); testInterval(interval, -5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2007, 1, 7))); auto interval2 = NegInfInterval!Date(Date(2010, 5, 31)); testInterval(interval2, 1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 7, 1))); testInterval(interval2, 1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 5, 1))); testInterval(interval2, -1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 5, 1))); testInterval(interval2, -1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 7, 1))); testInterval(interval2, 1, 1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 6, 30))); testInterval(interval2, 1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 4, 30))); testInterval(interval2, -1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2009, 4, 30))); testInterval(interval2, -1, 1, AllowDayOverflow.no, NegInfInterval!Date(Date(2009, 6, 30))); } const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static assert(!__traits(compiles, cNegInfInterval.shift(1))); static assert(!__traits(compiles, iNegInfInterval.shift(1))); //Verify Examples. auto interval1 = NegInfInterval!Date(Date(2012, 3, 1)); auto interval2 = NegInfInterval!Date(Date(2012, 3, 1)); interval1.shift(2); assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1))); interval2.shift(-2); assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1))); } //Test NegInfInterval's expand(). unittest { auto interval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__) { interval.expand(duration); assert(interval == expected); } testInterval(interval, dur!"days"(22), NegInfInterval!Date(Date(2012, 1, 29))); testInterval(interval, dur!"days"(-22), NegInfInterval!Date(Date(2011, 12, 16))); const cInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iInterval = NegInfInterval!Date(Date(2012, 1, 7)); static assert(!__traits(compiles, cInterval.expand(dur!"days"(5)))); static assert(!__traits(compiles, iInterval.expand(dur!"days"(5)))); //Verify Examples. auto interval1 = NegInfInterval!Date(Date(2012, 3, 1)); auto interval2 = NegInfInterval!Date(Date(2012, 3, 1)); interval1.expand(dur!"days"(2)); assert(interval1 == NegInfInterval!Date(Date(2012, 3, 3))); interval2.expand(dur!"days"(-2)); assert(interval2 == NegInfInterval!Date(Date(2012, 2, 28))); } //Test NegInfInterval's expand(int, int, AllowDayOverflow). unittest { { auto interval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__) { interval.expand(years, months, allow); assert(interval == expected); } testInterval(interval, 5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2017, 1, 7))); testInterval(interval, -5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2007, 1, 7))); auto interval2 = NegInfInterval!Date(Date(2010, 5, 31)); testInterval(interval2, 1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 7, 1))); testInterval(interval2, 1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 5, 1))); testInterval(interval2, -1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 5, 1))); testInterval(interval2, -1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 7, 1))); testInterval(interval2, 1, 1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 6, 30))); testInterval(interval2, 1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 4, 30))); testInterval(interval2, -1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2009, 4, 30))); testInterval(interval2, -1, 1, AllowDayOverflow.no, NegInfInterval!Date( Date(2009, 6, 30))); } const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static assert(!__traits(compiles, cNegInfInterval.expand(1))); static assert(!__traits(compiles, iNegInfInterval.expand(1))); //Verify Examples. auto interval1 = NegInfInterval!Date(Date(2012, 3, 1)); auto interval2 = NegInfInterval!Date(Date(2012, 3, 1)); interval1.expand(2); assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1))); interval2.expand(-2); assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1))); } //Test NegInfInterval's bwdRange(). unittest { auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); static void testInterval(NegInfInterval!Date negInfInterval) { negInfInterval.bwdRange(everyDayOfWeek!(Date, Direction.fwd)(DayOfWeek.fri)).popFront(); } assertThrown!DateTimeException(testInterval(negInfInterval)); assert(NegInfInterval!Date(Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).front == Date(2010, 10, 1)); assert(NegInfInterval!Date(Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri), PopFirst.yes).front == Date(2010, 9, 24)); //Verify Examples. auto interval = NegInfInterval!Date(Date(2010, 9, 9)); auto func = delegate (in Date date) { if((date.day & 1) == 0) return date - dur!"days"(2); return date - dur!"days"(1); }; auto range = interval.bwdRange(func); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8). assert(range.front == Date(2010, 9, 9)); range.popFront(); assert(range.front == Date(2010, 9, 8)); range.popFront(); assert(range.front == Date(2010, 9, 6)); range.popFront(); assert(range.front == Date(2010, 9, 4)); range.popFront(); assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(!range.empty); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(!cNegInfInterval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).empty); assert(!iNegInfInterval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).empty); } //Test NegInfInterval's toString(). unittest { assert(NegInfInterval!Date(Date(2012, 1, 7)).toString() == "[-∞ - 2012-Jan-07)"); const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); assert(cNegInfInterval.toString()); assert(iNegInfInterval.toString()); } /++ Range-generating function. Returns a delegate which returns the next time point with the given $(D DayOfWeek) in a range. Using this delegate allows iteration over successive time points which are all the same day of the week. e.g. passing $(D DayOfWeek.mon) to $(D everyDayOfWeek) would result in a delegate which could be used to iterate over all of the Mondays in a range. Params: dir = The direction to iterate in. If passing the return value to $(D fwdRange), use $(D Direction.fwd). If passing it to $(D bwdRange), use $(D Direction.bwd). dayOfWeek = The week that each time point in the range will be. +/ static TP delegate(in TP) everyDayOfWeek(TP, Direction dir = Direction.fwd)(DayOfWeek dayOfWeek) nothrow if(isTimePoint!TP && (dir == Direction.fwd || dir == Direction.bwd) && __traits(hasMember, TP, "dayOfWeek") && !__traits(isStaticFunction, TP.dayOfWeek) && is(typeof(TP.dayOfWeek) == DayOfWeek)) { TP func(in TP tp) { TP retval = cast(TP)tp; immutable days = daysToDayOfWeek(retval.dayOfWeek, dayOfWeek); static if(dir == Direction.fwd) immutable adjustedDays = days == 0 ? 7 : days; else immutable adjustedDays = days == 0 ? -7 : days - 7; return retval += dur!"days"(adjustedDays); } return &func; } /// unittest { auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27)); auto func = everyDayOfWeek!Date(DayOfWeek.mon); auto range = interval.fwdRange(func); //A Thursday. Using PopFirst.yes would have made this Date(2010, 9, 6). assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(range.front == Date(2010, 9, 6)); range.popFront(); assert(range.front == Date(2010, 9, 13)); range.popFront(); assert(range.front == Date(2010, 9, 20)); range.popFront(); assert(range.empty); } unittest { auto funcFwd = everyDayOfWeek!Date(DayOfWeek.mon); auto funcBwd = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.mon); assert(funcFwd(Date(2010, 8, 28)) == Date(2010, 8, 30)); assert(funcFwd(Date(2010, 8, 29)) == Date(2010, 8, 30)); assert(funcFwd(Date(2010, 8, 30)) == Date(2010, 9, 6)); assert(funcFwd(Date(2010, 8, 31)) == Date(2010, 9, 6)); assert(funcFwd(Date(2010, 9, 1)) == Date(2010, 9, 6)); assert(funcFwd(Date(2010, 9, 2)) == Date(2010, 9, 6)); assert(funcFwd(Date(2010, 9, 3)) == Date(2010, 9, 6)); assert(funcFwd(Date(2010, 9, 4)) == Date(2010, 9, 6)); assert(funcFwd(Date(2010, 9, 5)) == Date(2010, 9, 6)); assert(funcFwd(Date(2010, 9, 6)) == Date(2010, 9, 13)); assert(funcFwd(Date(2010, 9, 7)) == Date(2010, 9, 13)); assert(funcBwd(Date(2010, 8, 28)) == Date(2010, 8, 23)); assert(funcBwd(Date(2010, 8, 29)) == Date(2010, 8, 23)); assert(funcBwd(Date(2010, 8, 30)) == Date(2010, 8, 23)); assert(funcBwd(Date(2010, 8, 31)) == Date(2010, 8, 30)); assert(funcBwd(Date(2010, 9, 1)) == Date(2010, 8, 30)); assert(funcBwd(Date(2010, 9, 2)) == Date(2010, 8, 30)); assert(funcBwd(Date(2010, 9, 3)) == Date(2010, 8, 30)); assert(funcBwd(Date(2010, 9, 4)) == Date(2010, 8, 30)); assert(funcBwd(Date(2010, 9, 5)) == Date(2010, 8, 30)); assert(funcBwd(Date(2010, 9, 6)) == Date(2010, 8, 30)); assert(funcBwd(Date(2010, 9, 7)) == Date(2010, 9, 6)); static assert(!__traits(compiles, everyDayOfWeek!(TimeOfDay)(DayOfWeek.mon))); assert(everyDayOfWeek!(DateTime)(DayOfWeek.mon) !is null); assert(everyDayOfWeek!(SysTime)(DayOfWeek.mon) !is null); } /++ Range-generating function. Returns a delegate which returns the next time point with the given month which would be reached by adding months to the given time point. So, using this delegate allows iteration over successive time points which are in the same month but different years. For example, iterate over each successive December 25th in an interval by starting with a date which had the 25th as its day and passed $(D Month.dec) to $(D everyMonth) to create the delegate. Since it wouldn't really make sense to be iterating over a specific month and end up with some of the time points in the succeeding month or two years after the previous time point, $(D AllowDayOverflow.no) is always used when calculating the next time point. Params: dir = The direction to iterate in. If passing the return value to $(D fwdRange), use $(D Direction.fwd). If passing it to $(D bwdRange), use $(D Direction.bwd). month = The month that each time point in the range will be in. +/ static TP delegate(in TP) everyMonth(TP, Direction dir = Direction.fwd)(int month) if(isTimePoint!TP && (dir == Direction.fwd || dir == Direction.bwd) && __traits(hasMember, TP, "month") && !__traits(isStaticFunction, TP.month) && is(typeof(TP.month) == Month)) { enforceValid!"months"(month); TP func(in TP tp) { TP retval = cast(TP)tp; immutable months = monthsToMonth(retval.month, month); static if(dir == Direction.fwd) immutable adjustedMonths = months == 0 ? 12 : months; else immutable adjustedMonths = months == 0 ? -12 : months - 12; retval.add!"months"(adjustedMonths, AllowDayOverflow.no); if(retval.month != month) { retval.add!"months"(-1); assert(retval.month == month); } return retval; } return &func; } /// unittest { auto interval = Interval!Date(Date(2000, 1, 30), Date(2004, 8, 5)); auto func = everyMonth!(Date)(Month.feb); auto range = interval.fwdRange(func); //Using PopFirst.yes would have made this Date(2010, 2, 29). assert(range.front == Date(2000, 1, 30)); range.popFront(); assert(range.front == Date(2000, 2, 29)); range.popFront(); assert(range.front == Date(2001, 2, 28)); range.popFront(); assert(range.front == Date(2002, 2, 28)); range.popFront(); assert(range.front == Date(2003, 2, 28)); range.popFront(); assert(range.front == Date(2004, 2, 28)); range.popFront(); assert(range.empty); } unittest { auto funcFwd = everyMonth!Date(Month.jun); auto funcBwd = everyMonth!(Date, Direction.bwd)(Month.jun); assert(funcFwd(Date(2010, 5, 31)) == Date(2010, 6, 30)); assert(funcFwd(Date(2010, 6, 30)) == Date(2011, 6, 30)); assert(funcFwd(Date(2010, 7, 31)) == Date(2011, 6, 30)); assert(funcFwd(Date(2010, 8, 31)) == Date(2011, 6, 30)); assert(funcFwd(Date(2010, 9, 30)) == Date(2011, 6, 30)); assert(funcFwd(Date(2010, 10, 31)) == Date(2011, 6, 30)); assert(funcFwd(Date(2010, 11, 30)) == Date(2011, 6, 30)); assert(funcFwd(Date(2010, 12, 31)) == Date(2011, 6, 30)); assert(funcFwd(Date(2011, 1, 31)) == Date(2011, 6, 30)); assert(funcFwd(Date(2011, 2, 28)) == Date(2011, 6, 28)); assert(funcFwd(Date(2011, 3, 31)) == Date(2011, 6, 30)); assert(funcFwd(Date(2011, 4, 30)) == Date(2011, 6, 30)); assert(funcFwd(Date(2011, 5, 31)) == Date(2011, 6, 30)); assert(funcFwd(Date(2011, 6, 30)) == Date(2012, 6, 30)); assert(funcFwd(Date(2011, 7, 31)) == Date(2012, 6, 30)); assert(funcBwd(Date(2010, 5, 31)) == Date(2009, 6, 30)); assert(funcBwd(Date(2010, 6, 30)) == Date(2009, 6, 30)); assert(funcBwd(Date(2010, 7, 31)) == Date(2010, 6, 30)); assert(funcBwd(Date(2010, 8, 31)) == Date(2010, 6, 30)); assert(funcBwd(Date(2010, 9, 30)) == Date(2010, 6, 30)); assert(funcBwd(Date(2010, 10, 31)) == Date(2010, 6, 30)); assert(funcBwd(Date(2010, 11, 30)) == Date(2010, 6, 30)); assert(funcBwd(Date(2010, 12, 31)) == Date(2010, 6, 30)); assert(funcBwd(Date(2011, 1, 31)) == Date(2010, 6, 30)); assert(funcBwd(Date(2011, 2, 28)) == Date(2010, 6, 28)); assert(funcBwd(Date(2011, 3, 31)) == Date(2010, 6, 30)); assert(funcBwd(Date(2011, 4, 30)) == Date(2010, 6, 30)); assert(funcBwd(Date(2011, 5, 31)) == Date(2010, 6, 30)); assert(funcBwd(Date(2011, 6, 30)) == Date(2010, 6, 30)); assert(funcBwd(Date(2011, 7, 30)) == Date(2011, 6, 30)); static assert(!__traits(compiles, everyMonth!(TimeOfDay)(Month.jan))); assert(everyMonth!(DateTime)(Month.jan) !is null); assert(everyMonth!(SysTime)(Month.jan) !is null); } /++ Range-generating function. Returns a delegate which returns the next time point which is the given duration later. Using this delegate allows iteration over successive time points which are apart by the given duration e.g. passing $(D dur!"days"(3)) to $(D everyDuration) would result in a delegate which could be used to iterate over a range of days which are each 3 days apart. Params: dir = The direction to iterate in. If passing the return value to $(D fwdRange), use $(D Direction.fwd). If passing it to $(D bwdRange), use $(D Direction.bwd). duration = The duration which separates each successive time point in the range. +/ static TP delegate(in TP) everyDuration(TP, Direction dir = Direction.fwd, D) (D duration) nothrow if(isTimePoint!TP && __traits(compiles, TP.init + duration) && (dir == Direction.fwd || dir == Direction.bwd)) { TP func(in TP tp) { static if(dir == Direction.fwd) return tp + duration; else return tp - duration; } return &func; } /// unittest { auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27)); auto func = everyDuration!Date(dur!"days"(8)); auto range = interval.fwdRange(func); //Using PopFirst.yes would have made this Date(2010, 9, 10). assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(range.front == Date(2010, 9, 10)); range.popFront(); assert(range.front == Date(2010, 9, 18)); range.popFront(); assert(range.front == Date(2010, 9, 26)); range.popFront(); assert(range.empty); } unittest { auto funcFwd = everyDuration!Date(dur!"days"(27)); auto funcBwd = everyDuration!(Date, Direction.bwd)(dur!"days"(27)); assert(funcFwd(Date(2009, 12, 25)) == Date(2010, 1, 21)); assert(funcFwd(Date(2009, 12, 26)) == Date(2010, 1, 22)); assert(funcFwd(Date(2009, 12, 27)) == Date(2010, 1, 23)); assert(funcFwd(Date(2009, 12, 28)) == Date(2010, 1, 24)); assert(funcBwd(Date(2010, 1, 21)) == Date(2009, 12, 25)); assert(funcBwd(Date(2010, 1, 22)) == Date(2009, 12, 26)); assert(funcBwd(Date(2010, 1, 23)) == Date(2009, 12, 27)); assert(funcBwd(Date(2010, 1, 24)) == Date(2009, 12, 28)); assert(everyDuration!Date(dur!"hnsecs"(1)) !is null); assert(everyDuration!TimeOfDay(dur!"hnsecs"(1)) !is null); assert(everyDuration!DateTime(dur!"hnsecs"(1)) !is null); assert(everyDuration!SysTime(dur!"hnsecs"(1)) !is null); } /++ Range-generating function. Returns a delegate which returns the next time point which is the given number of years, month, and duration later. The difference between this version of $(D everyDuration) and the version which just takes a $(CXREF time, Duration) is that this one also takes the number of years and months (along with an $(D AllowDayOverflow) to indicate whether adding years and months should allow the days to overflow). Note that if iterating forward, $(D add!"years"()) is called on the given time point, then $(D add!"months"()), and finally the duration is added to it. However, if iterating backwards, the duration is added first, then $(D add!"months"()) is called, and finally $(D add!"years"()) is called. That way, going backwards generates close to the same time points that iterating forward does, but since adding years and months is not entirely reversible (due to possible day overflow, regardless of whether $(D AllowDayOverflow.yes) or $(D AllowDayOverflow.no) is used), it can't be guaranteed that iterating backwards will give the same time points as iterating forward would have (even assuming that the end of the range is a time point which would be returned by the delegate when iterating forward from $(D begin)). Params: dir = The direction to iterate in. If passing the return value to $(D fwdRange), use $(D Direction.fwd). If passing it to $(D bwdRange), use $(D Direction.bwd). years = The number of years to add to the time point passed to the delegate. months = The number of months to add to the time point passed to the delegate. allowOverflow = Whether the days should be allowed to overflow on $(D begin) and $(D end), causing their month to increment. duration = The duration to add to the time point passed to the delegate. +/ static TP delegate(in TP) everyDuration(TP, Direction dir = Direction.fwd, D) (int years, int months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes, D duration = dur!"days"(0)) nothrow if(isTimePoint!TP && __traits(compiles, TP.init + duration) && __traits(compiles, TP.init.add!"years"(years)) && __traits(compiles, TP.init.add!"months"(months)) && (dir == Direction.fwd || dir == Direction.bwd)) { TP func(in TP tp) { static if(dir == Direction.fwd) { TP retval = cast(TP)tp; retval.add!"years"(years, allowOverflow); retval.add!"months"(months, allowOverflow); return retval + duration; } else { TP retval = tp - duration; retval.add!"months"(-months, allowOverflow); retval.add!"years"(-years, allowOverflow); return retval; } } return &func; } /// unittest { auto interval = Interval!Date(Date(2010, 9, 2), Date(2025, 9, 27)); auto func = everyDuration!Date(4, 1, AllowDayOverflow.yes, dur!"days"(2)); auto range = interval.fwdRange(func); //Using PopFirst.yes would have made this Date(2014, 10, 12). assert(range.front == Date(2010, 9, 2)); range.popFront(); assert(range.front == Date(2014, 10, 4)); range.popFront(); assert(range.front == Date(2018, 11, 6)); range.popFront(); assert(range.front == Date(2022, 12, 8)); range.popFront(); assert(range.empty); } unittest { { auto funcFwd = everyDuration!Date(1, 2, AllowDayOverflow.yes, dur!"days"(3)); auto funcBwd = everyDuration!(Date, Direction.bwd)(1, 2, AllowDayOverflow.yes, dur!"days"(3)); assert(funcFwd(Date(2009, 12, 25)) == Date(2011, 2, 28)); assert(funcFwd(Date(2009, 12, 26)) == Date(2011, 3, 1)); assert(funcFwd(Date(2009, 12, 27)) == Date(2011, 3, 2)); assert(funcFwd(Date(2009, 12, 28)) == Date(2011, 3, 3)); assert(funcFwd(Date(2009, 12, 29)) == Date(2011, 3, 4)); assert(funcBwd(Date(2011, 2, 28)) == Date(2009, 12, 25)); assert(funcBwd(Date(2011, 3, 1)) == Date(2009, 12, 26)); assert(funcBwd(Date(2011, 3, 2)) == Date(2009, 12, 27)); assert(funcBwd(Date(2011, 3, 3)) == Date(2009, 12, 28)); assert(funcBwd(Date(2011, 3, 4)) == Date(2010, 1, 1)); } { auto funcFwd = everyDuration!Date(1, 2, AllowDayOverflow.no, dur!"days"(3)); auto funcBwd = everyDuration!(Date, Direction.bwd)(1, 2, AllowDayOverflow.yes, dur!"days"(3)); assert(funcFwd(Date(2009, 12, 25)) == Date(2011, 2, 28)); assert(funcFwd(Date(2009, 12, 26)) == Date(2011, 3, 1)); assert(funcFwd(Date(2009, 12, 27)) == Date(2011, 3, 2)); assert(funcFwd(Date(2009, 12, 28)) == Date(2011, 3, 3)); assert(funcFwd(Date(2009, 12, 29)) == Date(2011, 3, 3)); assert(funcBwd(Date(2011, 2, 28)) == Date(2009, 12, 25)); assert(funcBwd(Date(2011, 3, 1)) == Date(2009, 12, 26)); assert(funcBwd(Date(2011, 3, 2)) == Date(2009, 12, 27)); assert(funcBwd(Date(2011, 3, 3)) == Date(2009, 12, 28)); assert(funcBwd(Date(2011, 3, 4)) == Date(2010, 1, 1)); } assert(everyDuration!Date(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1)) !is null); static assert(!__traits(compiles, everyDuration!TimeOfDay(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1)))); assert(everyDuration!DateTime(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1)) !is null); assert(everyDuration!SysTime(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1)) !is null); } //TODO Add function to create a range generating function based on a date recurrence pattern string. // This may or may not involve creating a date recurrence pattern class of some sort - probably // yes if we want to make it easy to build them. However, there is a standard recurrence // pattern string format which we'd want to support with a range generator (though if we have // the class/struct, we'd probably want a version of the range generating function which took // that rather than a string). //============================================================================== // Section with ranges. //============================================================================== /++ A range over an $(LREF2 .Interval, Interval). $(D IntervalRange) is only ever constructed by $(LREF2 .Interval, Interval). However, when it is constructed, it is given a function, $(D func), which is used to generate the time points which are iterated over. $(D func) takes a time point and returns a time point of the same type. For instance, to iterate over all of the days in the interval $(D Interval!Date), pass a function to $(LREF2 .Interval, Interval)'s $(D fwdRange) where that function took a $(LREF Date) and returned a $(LREF Date) which was one day later. That function would then be used by $(D IntervalRange)'s $(D popFront) to iterate over the $(LREF Date)s in the interval. If $(D dir == Direction.fwd), then a range iterates forward in time, whereas if $(D dir == Direction.bwd), then it iterates backwards in time. So, if $(D dir == Direction.fwd) then $(D front == interval.begin), whereas if $(D dir == Direction.bwd) then $(D front == interval.end). $(D func) must generate a time point going in the proper direction of iteration, or a $(LREF DateTimeException) will be thrown. So, to iterate forward in time, the time point that $(D func) generates must be later in time than the one passed to it. If it's either identical or earlier in time, then a $(LREF DateTimeException) will be thrown. To iterate backwards, then the generated time point must be before the time point which was passed in. If the generated time point is ever passed the edge of the range in the proper direction, then the edge of that range will be used instead. So, if iterating forward, and the generated time point is past the interval's $(D end), then $(D front) becomes $(D end). If iterating backwards, and the generated time point is before $(D begin), then $(D front) becomes $(D begin). In either case, the range would then be empty. Also note that while normally the $(D begin) of an interval is included in it and its $(D end) is excluded from it, if $(D dir == Direction.bwd), then $(D begin) is treated as excluded and $(D end) is treated as included. This allows for the same behavior in both directions. This works because none of $(LREF2 .Interval, Interval)'s functions which care about whether $(D begin) or $(D end) is included or excluded are ever called by $(D IntervalRange). $(D interval) returns a normal interval, regardless of whether $(D dir == Direction.fwd) or if $(D dir == Direction.bwd), so any $(LREF2 .Interval, Interval) functions which are called on it which care about whether $(D begin) or $(D end) are included or excluded will treat $(D begin) as included and $(D end) as excluded. +/ struct IntervalRange(TP, Direction dir) if(isTimePoint!TP && dir != Direction.both) { public: /++ Params: rhs = The $(D IntervalRange) to assign to this one. +/ ref IntervalRange opAssign(ref IntervalRange rhs) pure nothrow { _interval = rhs._interval; _func = rhs._func; return this; } /++ Ditto +/ ref IntervalRange opAssign(IntervalRange rhs) pure nothrow { return this = rhs; } /++ Whether this $(D IntervalRange) is empty. +/ @property bool empty() const pure nothrow { return _interval.empty; } /++ The first time point in the range. Throws: $(LREF DateTimeException) if the range is empty. +/ @property TP front() const pure { _enforceNotEmpty(); static if(dir == Direction.fwd) return _interval.begin; else return _interval.end; } /++ Pops $(D front) from the range, using $(D func) to generate the next time point in the range. If the generated time point is beyond the edge of the range, then $(D front) is set to that edge, and the range is then empty. So, if iterating forwards, and the generated time point is greater than the interval's $(D end), then $(D front) is set to $(D end). If iterating backwards, and the generated time point is less than the interval's $(D begin), then $(D front) is set to $(D begin). Throws: $(LREF DateTimeException) if the range is empty or if the generated time point is in the wrong direction (i.e. if iterating forward and the generated time point is before $(D front), or if iterating backwards and the generated time point is after $(D front)). +/ void popFront() { _enforceNotEmpty(); static if(dir == Direction.fwd) { auto begin = _func(_interval.begin); if(begin > _interval.end) begin = _interval.end; _enforceCorrectDirection(begin); _interval.begin = begin; } else { auto end = _func(_interval.end); if(end < _interval.begin) end = _interval.begin; _enforceCorrectDirection(end); _interval.end = end; } } /++ Returns a copy of $(D this). +/ @property IntervalRange save() pure nothrow { return this; } /++ The interval that this $(D IntervalRange) currently covers. +/ @property Interval!TP interval() const pure nothrow { return cast(Interval!TP)_interval; } /++ The function used to generate the next time point in the range. +/ TP delegate(in TP) func() pure nothrow @property { return _func; } /++ The $(D Direction) that this range iterates in. +/ @property Direction direction() const pure nothrow { return dir; } private: /+ Params: interval = The interval that this range covers. func = The function used to generate the time points which are iterated over. +/ this(in Interval!TP interval, TP delegate(in TP) func) pure nothrow { _func = func; _interval = interval; } /+ Throws: $(LREF DateTimeException) if this interval is empty. +/ void _enforceNotEmpty(size_t line = __LINE__) const pure { if(empty) throw new DateTimeException("Invalid operation for an empty IntervalRange.", __FILE__, line); } /+ Throws: $(LREF DateTimeException) if $(D_PARAM newTP) is in the wrong direction. +/ void _enforceCorrectDirection(in TP newTP, size_t line = __LINE__) const { import std.format : format; static if(dir == Direction.fwd) { enforce(newTP > _interval._begin, new DateTimeException(format("Generated time point is before previous begin: prev [%s] new [%s]", interval._begin, newTP), __FILE__, line)); } else { enforce(newTP < _interval._end, new DateTimeException(format("Generated time point is after previous end: prev [%s] new [%s]", interval._end, newTP), __FILE__, line)); } } Interval!TP _interval; TP delegate(in TP) _func; } //Test that IntervalRange satisfies the range predicates that it's supposed to satisfy. unittest { static assert(isInputRange!(IntervalRange!(Date, Direction.fwd))); static assert(isForwardRange!(IntervalRange!(Date, Direction.fwd))); //Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=4895 //static assert(!isOutputRange!(IntervalRange!(Date, Direction.fwd), Date)); static assert(!isBidirectionalRange!(IntervalRange!(Date, Direction.fwd))); static assert(!isRandomAccessRange!(IntervalRange!(Date, Direction.fwd))); static assert(!hasSwappableElements!(IntervalRange!(Date, Direction.fwd))); static assert(!hasAssignableElements!(IntervalRange!(Date, Direction.fwd))); static assert(!hasLength!(IntervalRange!(Date, Direction.fwd))); static assert(!isInfinite!(IntervalRange!(Date, Direction.fwd))); static assert(!hasSlicing!(IntervalRange!(Date, Direction.fwd))); static assert(is(ElementType!(IntervalRange!(Date, Direction.fwd)) == Date)); static assert(is(ElementType!(IntervalRange!(TimeOfDay, Direction.fwd)) == TimeOfDay)); static assert(is(ElementType!(IntervalRange!(DateTime, Direction.fwd)) == DateTime)); static assert(is(ElementType!(IntervalRange!(SysTime, Direction.fwd)) == SysTime)); } //Test construction of IntervalRange. unittest { { Date dateFunc(in Date date) { return date; } auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto ir = IntervalRange!(Date, Direction.fwd)(interval, &dateFunc); } { TimeOfDay todFunc(in TimeOfDay tod) { return tod; } auto interval = Interval!TimeOfDay(TimeOfDay(12, 1, 7), TimeOfDay(14, 0, 0)); auto ir = IntervalRange!(TimeOfDay, Direction.fwd)(interval, &todFunc); } { DateTime dtFunc(in DateTime dt) { return dt; } auto interval = Interval!DateTime(DateTime(2010, 7, 4, 12, 1, 7), DateTime(2012, 1, 7, 14, 0, 0)); auto ir = IntervalRange!(DateTime, Direction.fwd)(interval, &dtFunc); } { SysTime stFunc(in SysTime st) { return cast(SysTime)st; } auto interval = Interval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)), SysTime(DateTime(2012, 1, 7, 14, 0, 0))); auto ir = IntervalRange!(SysTime, Direction.fwd)(interval, &stFunc); } } //Test IntervalRange's empty(). unittest { //fwd { auto range = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)); assert(!range.empty); range.popFront(); assert(range.empty); const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)); assert(!cRange.empty); //Apparently, creating an immutable IntervalRange!Date doesn't work, so we can't test if //empty works with it. However, since an immutable range is pretty useless, it's no great loss. } //bwd { auto range = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)); assert(!range.empty); range.popFront(); assert(range.empty); const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)); assert(!cRange.empty); //Apparently, creating an immutable IntervalRange!Date doesn't work, so we can't test if //empty works with it. However, since an immutable range is pretty useless, it's no great loss. } } //Test IntervalRange's front. unittest { //fwd { auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes); assertThrown!DateTimeException((in IntervalRange!(Date, Direction.fwd) range){range.front;}(emptyRange)); auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed)); assert(range.front == Date(2010, 7, 4)); auto poppedRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes); assert(poppedRange.front == Date(2010, 7, 7)); const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)); assert(cRange.front != Date.init); } //bwd { auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes); assertThrown!DateTimeException((in IntervalRange!(Date, Direction.bwd) range){range.front;}(emptyRange)); auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed)); assert(range.front == Date(2012, 1, 7)); auto poppedRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes); assert(poppedRange.front == Date(2012, 1, 4)); const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)); assert(cRange.front != Date.init); } } //Test IntervalRange's popFront(). unittest { //fwd { auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes); assertThrown!DateTimeException((IntervalRange!(Date, Direction.fwd) range){range.popFront();}(emptyRange)); auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes); auto expected = range.front; foreach(date; range) { assert(date == expected); expected += dur!"days"(7); } assert(walkLength(range) == 79); const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)); assert(cRange.front != Date.init); } //bwd { auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes); assertThrown!DateTimeException((IntervalRange!(Date, Direction.bwd) range){range.popFront();}(emptyRange)); auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes); auto expected = range.front; foreach(date; range) { assert(date == expected); expected += dur!"days"(-7); } assert(walkLength(range) == 79); const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)); static assert(!__traits(compiles, cRange.popFront())); } } //Test IntervalRange's save. unittest { //fwd { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto func = everyDayOfWeek!Date(DayOfWeek.fri); auto range = interval.fwdRange(func); assert(range.save == range); } //bwd { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri); auto range = interval.bwdRange(func); assert(range.save == range); } } //Test IntervalRange's interval. unittest { //fwd { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto func = everyDayOfWeek!Date(DayOfWeek.fri); auto range = interval.fwdRange(func); assert(range.interval == interval); const cRange = range; assert(!cRange.interval.empty); } //bwd { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri); auto range = interval.bwdRange(func); assert(range.interval == interval); const cRange = range; assert(!cRange.interval.empty); } } //Test IntervalRange's func. unittest { //fwd { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto func = everyDayOfWeek!Date(DayOfWeek.fri); auto range = interval.fwdRange(func); assert(range.func == func); } //bwd { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri); auto range = interval.bwdRange(func); assert(range.func == func); } } //Test IntervalRange's direction. unittest { //fwd { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto func = everyDayOfWeek!Date(DayOfWeek.fri); auto range = interval.fwdRange(func); assert(range.direction == Direction.fwd); const cRange = range; assert(cRange.direction == Direction.fwd); } //bwd { auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)); auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri); auto range = interval.bwdRange(func); assert(range.direction == Direction.bwd); const cRange = range; assert(cRange.direction == Direction.bwd); } } /++ A range over a $(D PosInfInterval). It is an infinite range. $(D PosInfIntervalRange) is only ever constructed by $(D PosInfInterval). However, when it is constructed, it is given a function, $(D func), which is used to generate the time points which are iterated over. $(D func) takes a time point and returns a time point of the same type. For instance, to iterate over all of the days in the interval $(D PosInfInterval!Date), pass a function to $(D PosInfInterval)'s $(D fwdRange) where that function took a $(LREF Date) and returned a $(LREF Date) which was one day later. That function would then be used by $(D PosInfIntervalRange)'s $(D popFront) to iterate over the $(LREF Date)s in the interval - though obviously, since the range is infinite, use a function such as $(D std.range.take) with it rather than iterating over $(I all) of the dates. As the interval goes to positive infinity, the range is always iterated over forwards, never backwards. $(D func) must generate a time point going in the proper direction of iteration, or a $(LREF DateTimeException) will be thrown. So, the time points that $(D func) generates must be later in time than the one passed to it. If it's either identical or earlier in time, then a $(LREF DateTimeException) will be thrown. +/ struct PosInfIntervalRange(TP) if(isTimePoint!TP) { public: /++ Params: rhs = The $(D PosInfIntervalRange) to assign to this one. +/ ref PosInfIntervalRange opAssign(ref PosInfIntervalRange rhs) pure nothrow { _interval = rhs._interval; _func = rhs._func; return this; } /++ Ditto +/ ref PosInfIntervalRange opAssign(PosInfIntervalRange rhs) pure nothrow { return this = rhs; } /++ This is an infinite range, so it is never empty. +/ enum bool empty = false; /++ The first time point in the range. +/ @property TP front() const pure nothrow { return _interval.begin; } /++ Pops $(D front) from the range, using $(D func) to generate the next time point in the range. Throws: $(LREF DateTimeException) if the generated time point is less than $(D front). +/ void popFront() { auto begin = _func(_interval.begin); _enforceCorrectDirection(begin); _interval.begin = begin; } /++ Returns a copy of $(D this). +/ @property PosInfIntervalRange save() pure nothrow { return this; } /++ The interval that this range currently covers. +/ @property PosInfInterval!TP interval() const pure nothrow { return cast(PosInfInterval!TP)_interval; } /++ The function used to generate the next time point in the range. +/ TP delegate(in TP) func() pure nothrow @property { return _func; } private: /+ Params: interval = The interval that this range covers. func = The function used to generate the time points which are iterated over. +/ this(in PosInfInterval!TP interval, TP delegate(in TP) func) pure nothrow { _func = func; _interval = interval; } /+ Throws: $(LREF DateTimeException) if $(D_PARAME newTP) is in the wrong direction. +/ void _enforceCorrectDirection(in TP newTP, size_t line = __LINE__) const { import std.format : format; enforce(newTP > _interval._begin, new DateTimeException(format("Generated time point is before previous begin: prev [%s] new [%s]", interval._begin, newTP), __FILE__, line)); } PosInfInterval!TP _interval; TP delegate(in TP) _func; } //Test that PosInfIntervalRange satisfies the range predicates that it's supposed to satisfy. unittest { static assert(isInputRange!(PosInfIntervalRange!Date)); static assert(isForwardRange!(PosInfIntervalRange!Date)); static assert(isInfinite!(PosInfIntervalRange!Date)); //Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=4895 //static assert(!isOutputRange!(PosInfIntervalRange!Date, Date)); static assert(!isBidirectionalRange!(PosInfIntervalRange!Date)); static assert(!isRandomAccessRange!(PosInfIntervalRange!Date)); static assert(!hasSwappableElements!(PosInfIntervalRange!Date)); static assert(!hasAssignableElements!(PosInfIntervalRange!Date)); static assert(!hasLength!(PosInfIntervalRange!Date)); static assert(!hasSlicing!(PosInfIntervalRange!Date)); static assert(is(ElementType!(PosInfIntervalRange!Date) == Date)); static assert(is(ElementType!(PosInfIntervalRange!TimeOfDay) == TimeOfDay)); static assert(is(ElementType!(PosInfIntervalRange!DateTime) == DateTime)); static assert(is(ElementType!(PosInfIntervalRange!SysTime) == SysTime)); } //Test construction of PosInfIntervalRange. unittest { { Date dateFunc(in Date date) { return date; } auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4)); auto ir = PosInfIntervalRange!Date(posInfInterval, &dateFunc); } { TimeOfDay todFunc(in TimeOfDay tod) { return tod; } auto posInfInterval = PosInfInterval!TimeOfDay(TimeOfDay(12, 1, 7)); auto ir = PosInfIntervalRange!(TimeOfDay)(posInfInterval, &todFunc); } { DateTime dtFunc(in DateTime dt) { return dt; } auto posInfInterval = PosInfInterval!DateTime(DateTime(2010, 7, 4, 12, 1, 7)); auto ir = PosInfIntervalRange!(DateTime)(posInfInterval, &dtFunc); } { SysTime stFunc(in SysTime st) { return cast(SysTime)st; } auto posInfInterval = PosInfInterval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7))); auto ir = PosInfIntervalRange!(SysTime)(posInfInterval, &stFunc); } } //Test PosInfIntervalRange's front. unittest { auto range = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed)); assert(range.front == Date(2010, 7, 4)); auto poppedRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes); assert(poppedRange.front == Date(2010, 7, 7)); const cRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)); assert(cRange.front != Date.init); } //Test PosInfIntervalRange's popFront(). unittest { import std.range; auto range = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes); auto expected = range.front; foreach(date; take(range, 79)) { assert(date == expected); expected += dur!"days"(7); } const cRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)); static assert(!__traits(compiles, cRange.popFront())); } //Test PosInfIntervalRange's save. unittest { auto interval = PosInfInterval!Date(Date(2010, 7, 4)); auto func = everyDayOfWeek!Date(DayOfWeek.fri); auto range = interval.fwdRange(func); assert(range.save == range); } //Test PosInfIntervalRange's interval. unittest { auto interval = PosInfInterval!Date(Date(2010, 7, 4)); auto func = everyDayOfWeek!Date(DayOfWeek.fri); auto range = interval.fwdRange(func); assert(range.interval == interval); const cRange = range; assert(!cRange.interval.empty); } //Test PosInfIntervalRange's func. unittest { auto interval = PosInfInterval!Date(Date(2010, 7, 4)); auto func = everyDayOfWeek!Date(DayOfWeek.fri); auto range = interval.fwdRange(func); assert(range.func == func); } /++ A range over a $(D NegInfInterval). It is an infinite range. $(D NegInfIntervalRange) is only ever constructed by $(D NegInfInterval). However, when it is constructed, it is given a function, $(D func), which is used to generate the time points which are iterated over. $(D func) takes a time point and returns a time point of the same type. For instance, to iterate over all of the days in the interval $(D NegInfInterval!Date), pass a function to $(D NegInfInterval)'s $(D bwdRange) where that function took a $(LREF Date) and returned a $(LREF Date) which was one day earlier. That function would then be used by $(D NegInfIntervalRange)'s $(D popFront) to iterate over the $(LREF Date)s in the interval - though obviously, since the range is infinite, use a function such as $(D std.range.take) with it rather than iterating over $(I all) of the dates. As the interval goes to negative infinity, the range is always iterated over backwards, never forwards. $(D func) must generate a time point going in the proper direction of iteration, or a $(LREF DateTimeException) will be thrown. So, the time points that $(D func) generates must be earlier in time than the one passed to it. If it's either identical or later in time, then a $(LREF DateTimeException) will be thrown. Also note that while normally the $(D end) of an interval is excluded from it, $(D NegInfIntervalRange) treats it as if it were included. This allows for the same behavior as with $(D PosInfIntervalRange). This works because none of $(D NegInfInterval)'s functions which care about whether $(D end) is included or excluded are ever called by $(D NegInfIntervalRange). $(D interval) returns a normal interval, so any $(D NegInfInterval) functions which are called on it which care about whether $(D end) is included or excluded will treat $(D end) as excluded. +/ struct NegInfIntervalRange(TP) if(isTimePoint!TP) { public: /++ Params: rhs = The $(D NegInfIntervalRange) to assign to this one. +/ ref NegInfIntervalRange opAssign(ref NegInfIntervalRange rhs) pure nothrow { _interval = rhs._interval; _func = rhs._func; return this; } /++ Ditto +/ ref NegInfIntervalRange opAssign(NegInfIntervalRange rhs) pure nothrow { return this = rhs; } /++ This is an infinite range, so it is never empty. +/ enum bool empty = false; /++ The first time point in the range. +/ @property TP front() const pure nothrow { return _interval.end; } /++ Pops $(D front) from the range, using $(D func) to generate the next time point in the range. Throws: $(LREF DateTimeException) if the generated time point is greater than $(D front). +/ void popFront() { auto end = _func(_interval.end); _enforceCorrectDirection(end); _interval.end = end; } /++ Returns a copy of $(D this). +/ @property NegInfIntervalRange save() pure nothrow { return this; } /++ The interval that this range currently covers. +/ @property NegInfInterval!TP interval() const pure nothrow { return cast(NegInfInterval!TP)_interval; } /++ The function used to generate the next time point in the range. +/ TP delegate(in TP) func() pure nothrow @property { return _func; } private: /+ Params: interval = The interval that this range covers. func = The function used to generate the time points which are iterated over. +/ this(in NegInfInterval!TP interval, TP delegate(in TP) func) pure nothrow { _func = func; _interval = interval; } /+ Throws: $(LREF DateTimeException) if $(D_PARAM newTP) is in the wrong direction. +/ void _enforceCorrectDirection(in TP newTP, size_t line = __LINE__) const { import std.format : format; enforce(newTP < _interval._end, new DateTimeException(format("Generated time point is before previous end: prev [%s] new [%s]", interval._end, newTP), __FILE__, line)); } NegInfInterval!TP _interval; TP delegate(in TP) _func; } //Test that NegInfIntervalRange satisfies the range predicates that it's supposed to satisfy. unittest { static assert(isInputRange!(NegInfIntervalRange!Date)); static assert(isForwardRange!(NegInfIntervalRange!Date)); static assert(isInfinite!(NegInfIntervalRange!Date)); //Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=4895 //static assert(!isOutputRange!(NegInfIntervalRange!Date, Date)); static assert(!isBidirectionalRange!(NegInfIntervalRange!Date)); static assert(!isRandomAccessRange!(NegInfIntervalRange!Date)); static assert(!hasSwappableElements!(NegInfIntervalRange!Date)); static assert(!hasAssignableElements!(NegInfIntervalRange!Date)); static assert(!hasLength!(NegInfIntervalRange!Date)); static assert(!hasSlicing!(NegInfIntervalRange!Date)); static assert(is(ElementType!(NegInfIntervalRange!Date) == Date)); static assert(is(ElementType!(NegInfIntervalRange!TimeOfDay) == TimeOfDay)); static assert(is(ElementType!(NegInfIntervalRange!DateTime) == DateTime)); } //Test construction of NegInfIntervalRange. unittest { { Date dateFunc(in Date date) { return date; } auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7)); auto ir = NegInfIntervalRange!Date(negInfInterval, &dateFunc); } { TimeOfDay todFunc(in TimeOfDay tod) { return tod; } auto negInfInterval = NegInfInterval!TimeOfDay(TimeOfDay(14, 0, 0)); auto ir = NegInfIntervalRange!(TimeOfDay)(negInfInterval, &todFunc); } { DateTime dtFunc(in DateTime dt) { return dt; } auto negInfInterval = NegInfInterval!DateTime(DateTime(2012, 1, 7, 14, 0, 0)); auto ir = NegInfIntervalRange!(DateTime)(negInfInterval, &dtFunc); } { SysTime stFunc(in SysTime st) { return cast(SysTime)(st); } auto negInfInterval = NegInfInterval!SysTime(SysTime(DateTime(2012, 1, 7, 14, 0, 0))); auto ir = NegInfIntervalRange!(SysTime)(negInfInterval, &stFunc); } } //Test NegInfIntervalRange's front. unittest { auto range = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed)); assert(range.front == Date(2012, 1, 7)); auto poppedRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes); assert(poppedRange.front == Date(2012, 1, 4)); const cRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)); assert(cRange.front != Date.init); } //Test NegInfIntervalRange's popFront(). unittest { import std.range; auto range = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes); auto expected = range.front; foreach(date; take(range, 79)) { assert(date == expected); expected += dur!"days"(-7); } const cRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)); static assert(!__traits(compiles, cRange.popFront())); } //Test NegInfIntervalRange's save. unittest { auto interval = NegInfInterval!Date(Date(2012, 1, 7)); auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri); auto range = interval.bwdRange(func); assert(range.save == range); } //Test NegInfIntervalRange's interval. unittest { auto interval = NegInfInterval!Date(Date(2012, 1, 7)); auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri); auto range = interval.bwdRange(func); assert(range.interval == interval); const cRange = range; assert(!cRange.interval.empty); } //Test NegInfIntervalRange's func. unittest { auto interval = NegInfInterval!Date(Date(2012, 1, 7)); auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri); auto range = interval.bwdRange(func); assert(range.func == func); } //============================================================================== // Section with time zones. //============================================================================== /++ Represents a time zone. It is used with $(LREF SysTime) to indicate the time zone of a $(LREF SysTime). +/ abstract class TimeZone { public: /++ The name of the time zone per the TZ Database. This is the name used to get a $(LREF2 .TimeZone, TimeZone) by name with $(D TimeZone.getTimeZone). See_Also: $(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ Database)
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of Time Zones) +/ @property string name() @safe const nothrow { return _name; } /++ Typically, the abbreviation (generally 3 or 4 letters) for the time zone when DST is $(I not) in effect (e.g. PST). It is not necessarily unique. However, on Windows, it may be the unabbreviated name (e.g. Pacific Standard Time). Regardless, it is not the same as name. +/ @property string stdName() @safe const nothrow { return _stdName; } /++ Typically, the abbreviation (generally 3 or 4 letters) for the time zone when DST $(I is) in effect (e.g. PDT). It is not necessarily unique. However, on Windows, it may be the unabbreviated name (e.g. Pacific Daylight Time). Regardless, it is not the same as name. +/ @property string dstName() @safe const nothrow { return _dstName; } /++ Whether this time zone has Daylight Savings Time at any point in time. Note that for some time zone types it may not have DST for current dates but will still return true for $(D hasDST) because the time zone did at some point have DST. +/ @property abstract bool hasDST() @safe const nothrow; /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in UTC time (i.e. std time) and returns whether DST is effect in this time zone at the given point in time. Params: stdTime = The UTC time that needs to be checked for DST in this time zone. +/ abstract bool dstInEffect(long stdTime) @safe const nothrow; /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in UTC time (i.e. std time) and converts it to this time zone's time. Params: stdTime = The UTC time that needs to be adjusted to this time zone's time. +/ abstract long utcToTZ(long stdTime) @safe const nothrow; /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in this time zone's time and converts it to UTC (i.e. std time). Params: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ abstract long tzToUTC(long adjTime) @safe const nothrow; /++ Returns what the offset from UTC is at the given std time. It includes the DST offset in effect at that time (if any). Params: stdTime = The UTC time for which to get the offset from UTC for this time zone. +/ Duration utcOffsetAt(long stdTime) @safe const nothrow { return dur!"hnsecs"(utcToTZ(stdTime) - stdTime); } /++ $(RED Please use either PosixTimeZone.getTimeZone or WindowsTimeZone.getTimeZone ($(LREF parseTZConversions) can be used to convert time zone names if necessary). This function will be deprecated in 2.072, because Microsoft changes their time zones too often for us to compile the conversions into Phobos and have them be properly up-to-date.) Returns a $(LREF2 .TimeZone, TimeZone) with the give name per the TZ Database. This returns a $(LREF PosixTimeZone) on Posix systems and a $(LREF WindowsTimeZone) on Windows systems. For $(LREF PosixTimeZone) on Windows, call $(D PosixTimeZone.getTimeZone) directly and give it the location of the TZ Database time zone files on disk. On Windows, the given TZ Database name is converted to the corresponding time zone name on Windows prior to calling $(D WindowsTimeZone.getTimeZone). This function allows for the same time zone names on both Windows and Posix systems. See_Also: $(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ Database)
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of Time Zones)
$(WEB unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html, Windows <-> TZ Database Name Conversion Table) Params: name = The TZ Database name of the desired time zone Throws: $(LREF DateTimeException) if the given time zone could not be found. +/ static immutable(TimeZone) getTimeZone(string name) @safe { version(Posix) return PosixTimeZone.getTimeZone(name); else version(Windows) { import std.format : format; auto windowsTZName = tzDatabaseNameToWindowsTZName(name); if(windowsTZName != null) { try return WindowsTimeZone.getTimeZone(windowsTZName); catch(DateTimeException dte) { auto oldName = _getOldName(windowsTZName); if(oldName != null) return WindowsTimeZone.getTimeZone(oldName); throw dte; } } else throw new DateTimeException(format("%s does not have an equivalent Windows time zone.", name)); } } /// unittest { auto tz = TimeZone.getTimeZone("America/Los_Angeles"); } // The purpose of this is to handle the case where a Windows time zone is // new and exists on an up-to-date Windows box but does not exist on Windows // boxes which have not been properly updated. The "date added" is included // on the theory that we'll be able to remove them at some point in the // the future once enough time has passed, and that way, we know how much // time has passed. private static string _getOldName(string windowsTZName) @safe pure nothrow { switch(windowsTZName) { case "Belarus Standard Time": return "Kaliningrad Standard Time"; // Added 2014-10-08 case "Russia Time Zone 10": return "Magadan Standard Time"; // Added 2014-10-08 case "Russia Time Zone 11": return "Magadan Standard Time"; // Added 2014-10-08 case "Russia Time Zone 3": return "Russian Standard Time"; // Added 2014-10-08 default: return null; } } //Since reading in the time zone files could be expensive, most unit tests //are consolidated into this one unittest block which minimizes how often it //reads a time zone file. unittest { import std.path : chainPath; import std.file : exists, isFile; import std.conv : to; import std.format : format; version(Posix) scope(exit) clearTZEnvVar(); static immutable(TimeZone) testTZ(string tzName, string stdName, string dstName, Duration utcOffset, Duration dstOffset, bool north = true) { scope(failure) writefln("Failed time zone: %s", tzName); immutable tz = TimeZone.getTimeZone(tzName); immutable hasDST = dstOffset != dur!"hnsecs"(0); version(Posix) assert(tz.name == tzName); else version(Windows) assert(tz.name == stdName); //assert(tz.stdName == stdName); //Locale-dependent //assert(tz.dstName == dstName); //Locale-dependent assert(tz.hasDST == hasDST); immutable stdDate = DateTime(2010, north ? 1 : 7, 1, 6, 0, 0); immutable dstDate = DateTime(2010, north ? 7 : 1, 1, 6, 0, 0); auto std = SysTime(stdDate, tz); auto dst = SysTime(dstDate, tz); auto stdUTC = SysTime(stdDate - utcOffset, UTC()); auto dstUTC = SysTime(stdDate - utcOffset + dstOffset, UTC()); assert(!std.dstInEffect); assert(dst.dstInEffect == hasDST); assert(tz.utcOffsetAt(std.stdTime) == utcOffset); assert(tz.utcOffsetAt(dst.stdTime) == utcOffset + dstOffset); assert(cast(DateTime)std == stdDate); assert(cast(DateTime)dst == dstDate); assert(std == stdUTC); version(Posix) { setTZEnvVar(tzName); static void testTM(in SysTime st) { time_t unixTime = st.toUnixTime(); tm* osTimeInfo = localtime(&unixTime); tm ourTimeInfo = st.toTM(); assert(ourTimeInfo.tm_sec == osTimeInfo.tm_sec); assert(ourTimeInfo.tm_min == osTimeInfo.tm_min); assert(ourTimeInfo.tm_hour == osTimeInfo.tm_hour); assert(ourTimeInfo.tm_mday == osTimeInfo.tm_mday); assert(ourTimeInfo.tm_mon == osTimeInfo.tm_mon); assert(ourTimeInfo.tm_year == osTimeInfo.tm_year); assert(ourTimeInfo.tm_wday == osTimeInfo.tm_wday); assert(ourTimeInfo.tm_yday == osTimeInfo.tm_yday); assert(ourTimeInfo.tm_isdst == osTimeInfo.tm_isdst); assert(ourTimeInfo.tm_gmtoff == osTimeInfo.tm_gmtoff); assert(to!string(ourTimeInfo.tm_zone) == to!string(osTimeInfo.tm_zone)); } testTM(std); testTM(dst); //Apparently, right/ does not exist on Mac OS X. I don't know //whether or not it exists on FreeBSD. It's rather pointless //normally, since the Posix standard requires that leap seconds //be ignored, so it does make some sense that right/ wouldn't //be there, but since PosixTimeZone _does_ use leap seconds if //the time zone file does, we'll test that functionality if the //appropriate files exist. if (chainPath(PosixTimeZone.defaultTZDatabaseDir, "right", tzName).exists) { auto leapTZ = PosixTimeZone.getTimeZone("right/" ~ tzName); assert(leapTZ.name == "right/" ~ tzName); //assert(leapTZ.stdName == stdName); //Locale-dependent //assert(leapTZ.dstName == dstName); //Locale-dependent assert(leapTZ.hasDST == hasDST); auto leapSTD = SysTime(std.stdTime, leapTZ); auto leapDST = SysTime(dst.stdTime, leapTZ); assert(!leapSTD.dstInEffect); assert(leapDST.dstInEffect == hasDST); assert(leapSTD.stdTime == std.stdTime); assert(leapDST.stdTime == dst.stdTime); //Whenever a leap second is added/removed, //this will have to be adjusted. //enum leapDiff = convert!("seconds", "hnsecs")(25); //assert(leapSTD.adjTime - leapDiff == std.adjTime); //assert(leapDST.adjTime - leapDiff == dst.adjTime); } } return tz; } auto dstSwitches = [/+America/Los_Angeles+/ tuple(DateTime(2012, 3, 11), DateTime(2012, 11, 4), 2, 2), /+America/New_York+/ tuple(DateTime(2012, 3, 11), DateTime(2012, 11, 4), 2, 2), ///+America/Santiago+/ tuple(DateTime(2011, 8, 21), DateTime(2011, 5, 8), 0, 0), /+Europe/London+/ tuple(DateTime(2012, 3, 25), DateTime(2012, 10, 28), 1, 2), /+Europe/Paris+/ tuple(DateTime(2012, 3, 25), DateTime(2012, 10, 28), 2, 3), /+Australia/Adelaide+/ tuple(DateTime(2012, 10, 7), DateTime(2012, 4, 1), 2, 3)]; version(Posix) { version(FreeBSD) enum utcZone = "Etc/UTC"; else version(NetBSD) enum utcZone = "UTC"; else version(linux) enum utcZone = "UTC"; else version(OSX) enum utcZone = "UTC"; else version(Solaris) enum utcZone = "UTC"; else static assert(0, "The location of the UTC timezone file on this Posix platform must be set."); auto tzs = [testTZ("America/Los_Angeles", "PST", "PDT", dur!"hours"(-8), dur!"hours"(1)), testTZ("America/New_York", "EST", "EDT", dur!"hours"(-5), dur!"hours"(1)), //testTZ("America/Santiago", "CLT", "CLST", dur!"hours"(-4), dur!"hours"(1), false), testTZ("Europe/London", "GMT", "BST", dur!"hours"(0), dur!"hours"(1)), testTZ("Europe/Paris", "CET", "CEST", dur!"hours"(1), dur!"hours"(1)), //Per www.timeanddate.com, it should be "CST" and "CDT", //but the OS insists that it's "CST" for both. We should //probably figure out how to report an error in the TZ //database and report it. testTZ("Australia/Adelaide", "CST", "CST", dur!"hours"(9) + dur!"minutes"(30), dur!"hours"(1), false)]; testTZ(utcZone, "UTC", "UTC", dur!"hours"(0), dur!"hours"(0)); assertThrown!DateTimeException(PosixTimeZone.getTimeZone("hello_world")); } else version(Windows) { auto tzs = [testTZ("America/Los_Angeles", "Pacific Standard Time", "Pacific Daylight Time", dur!"hours"(-8), dur!"hours"(1)), testTZ("America/New_York", "Eastern Standard Time", "Eastern Daylight Time", dur!"hours"(-5), dur!"hours"(1)), //testTZ("America/Santiago", "Pacific SA Standard Time", //"Pacific SA Daylight Time", dur!"hours"(-4), dur!"hours"(1), false), testTZ("Europe/London", "GMT Standard Time", "GMT Daylight Time", dur!"hours"(0), dur!"hours"(1)), testTZ("Europe/Paris", "Romance Standard Time", "Romance Daylight Time", dur!"hours"(1), dur!"hours"(1)), testTZ("Australia/Adelaide", "Cen. Australia Standard Time", "Cen. Australia Daylight Time", dur!"hours"(9) + dur!"minutes"(30), dur!"hours"(1), false)]; testTZ("Atlantic/Reykjavik", "Greenwich Standard Time", "Greenwich Daylight Time", dur!"hours"(0), dur!"hours"(0)); assertThrown!DateTimeException(WindowsTimeZone.getTimeZone("hello_world")); } else assert(0, "OS not supported."); foreach(i; 0 .. tzs.length) { auto tz = tzs[i]; immutable spring = dstSwitches[i][2]; immutable fall = dstSwitches[i][3]; auto stdOffset = SysTime(dstSwitches[i][0] + dur!"days"(-1), tz).utcOffset; auto dstOffset = stdOffset + dur!"hours"(1); //Verify that creating a SysTime in the given time zone results //in a SysTime with the correct std time during and surrounding //a DST switch. foreach(hour; -12 .. 13) { auto st = SysTime(dstSwitches[i][0] + dur!"hours"(hour), tz); immutable targetHour = hour < 0 ? hour + 24 : hour; static void testHour(SysTime st, int hour, string tzName, size_t line = __LINE__) { enforce(st.hour == hour, new AssertError(format("[%s] [%s]: [%s] [%s]", st, tzName, st.hour, hour), __FILE__, line)); } void testOffset1(Duration offset, bool dstInEffect, size_t line = __LINE__) { AssertError msg(string tag) { return new AssertError(format("%s [%s] [%s]: [%s] [%s] [%s]", tag, st, tz.name, st.utcOffset, stdOffset, dstOffset), __FILE__, line); } enforce(st.dstInEffect == dstInEffect, msg("1")); enforce(st.utcOffset == offset, msg("2")); enforce((st + dur!"minutes"(1)).utcOffset == offset, msg("3")); } if(hour == spring) { testHour(st, spring + 1, tz.name); testHour(st + dur!"minutes"(1), spring + 1, tz.name); } else { testHour(st, targetHour, tz.name); testHour(st + dur!"minutes"(1), targetHour, tz.name); } if(hour < spring) testOffset1(stdOffset, false); else testOffset1(dstOffset, true); st = SysTime(dstSwitches[i][1] + dur!"hours"(hour), tz); testHour(st, targetHour, tz.name); //Verify that 01:00 is the first 01:00 (or whatever hour before the switch is). if(hour == fall - 1) testHour(st + dur!"hours"(1), targetHour, tz.name); if(hour < fall) testOffset1(dstOffset, true); else testOffset1(stdOffset, false); } //Verify that converting a time in UTC to a time in another //time zone results in the correct time during and surrounding //a DST switch. bool first = true; auto springSwitch = SysTime(dstSwitches[i][0] + dur!"hours"(spring), UTC()) - stdOffset; auto fallSwitch = SysTime(dstSwitches[i][1] + dur!"hours"(fall), UTC()) - dstOffset; //@@@BUG@@@ 3659 makes this necessary. auto fallSwitchMinus1 = fallSwitch - dur!"hours"(1); foreach(hour; -24 .. 25) { auto utc = SysTime(dstSwitches[i][0] + dur!"hours"(hour), UTC()); auto local = utc.toOtherTZ(tz); void testOffset2(Duration offset, size_t line = __LINE__) { AssertError msg(string tag) { return new AssertError(format("%s [%s] [%s]: [%s] [%s]", tag, hour, tz.name, utc, local), __FILE__, line); } enforce((utc + offset).hour == local.hour, msg("1")); enforce((utc + offset + dur!"minutes"(1)).hour == local.hour, msg("2")); } if(utc < springSwitch) testOffset2(stdOffset); else testOffset2(dstOffset); utc = SysTime(dstSwitches[i][1] + dur!"hours"(hour), UTC()); local = utc.toOtherTZ(tz); if(utc == fallSwitch || utc == fallSwitchMinus1) { if(first) { testOffset2(dstOffset); first = false; } else testOffset2(stdOffset); } else if(utc > fallSwitch) testOffset2(stdOffset); else testOffset2(dstOffset); } } } /++ Returns a list of the names of the time zones installed on the system. Providing a sub-name narrows down the list of time zones (which can number in the thousands). For example, passing in "America" as the sub-name returns only the time zones which begin with "America". On Windows, this function will convert the Windows time zone names to the corresponding TZ Database names with $(D windowsTZNameToTZDatabaseName). To get the actual Windows time zone names, use $(D WindowsTimeZone.getInstalledTZNames) directly. Params: subName = The first part of the time zones desired. Throws: $(D FileException) on Posix systems if it fails to read from disk. $(LREF DateTimeException) on Windows systems if it fails to read the registry. +/ static string[] getInstalledTZNames(string subName = "") @safe { version(Posix) return PosixTimeZone.getInstalledTZNames(subName); else version(Windows) { import std.array : appender; import std.algorithm : startsWith, sort; auto windowsNames = WindowsTimeZone.getInstalledTZNames(); auto retval = appender!(string[])(); foreach(winName; windowsNames) { auto tzName = windowsTZNameToTZDatabaseName(winName); if(tzName !is null && tzName.startsWith(subName)) retval.put(tzName); } sort(retval.data); return retval.data; } } unittest { static void testPZSuccess(string tzName) { scope(failure) writefln("TZName which threw: %s", tzName); TimeZone.getTimeZone(tzName); } auto tzNames = getInstalledTZNames(); // This was not previously tested, and it's currently failing, so I'm // leaving it commented out until I can sort it out. //assert(equal(tzNames, tzNames.uniq())); foreach(tzName; tzNames) assertNotThrown!DateTimeException(testPZSuccess(tzName)); } private: /+ Params: name = The TZ Database name for the time zone. stdName = The abbreviation for the time zone during std time. dstName = The abbreviation for the time zone during DST. +/ this(string name, string stdName, string dstName) @safe immutable pure { _name = name; _stdName = stdName; _dstName = dstName; } immutable string _name; immutable string _stdName; immutable string _dstName; } /++ A TimeZone which represents the current local time zone on the system running your program. This uses the underlying C calls to adjust the time rather than using specific D code based off of system settings to calculate the time such as $(LREF PosixTimeZone) and $(LREF WindowsTimeZone) do. That also means that it will use whatever the current time zone is on the system, even if the system's time zone changes while the program is running. +/ final class LocalTime : TimeZone { public: /++ $(LREF LocalTime) is a singleton class. $(LREF LocalTime) returns its only instance. +/ static immutable(LocalTime) opCall() @trusted pure nothrow { alias FuncType = @safe pure nothrow immutable(LocalTime) function(); return (cast(FuncType)&singleton)(); } version(StdDdoc) { /++ The name of the time zone per the TZ Database. This is the name used to get a $(LREF2 .TimeZone, TimeZone) by name with $(D TimeZone.getTimeZone). Note that this always returns the empty string. This is because time zones cannot be uniquely identified by the attributes given by the OS (such as the $(D stdName) and $(D dstName)), and neither Posix systems nor Windows systems provide an easy way to get the TZ Database name of the local time zone. See_Also: $(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ Database)
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of Time Zones) +/ @property override string name() @safe const nothrow; } /++ Typically, the abbreviation (generally 3 or 4 letters) for the time zone when DST is $(I not) in effect (e.g. PST). It is not necessarily unique. However, on Windows, it may be the unabbreviated name (e.g. Pacific Standard Time). Regardless, it is not the same as name. This property is overridden because the local time of the system could change while the program is running and we need to determine it dynamically rather than it being fixed like it would be with most time zones. +/ @property override string stdName() @trusted const nothrow { version(Posix) { import std.conv : to; try return to!string(tzname[0]); catch(Exception e) assert(0, "to!string(tzname[0]) failed."); } else version(Windows) { TIME_ZONE_INFORMATION tzInfo; GetTimeZoneInformation(&tzInfo); //Cannot use to!string() like this should, probably due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5016 //return to!string(tzInfo.StandardName); wchar[32] str; foreach(i, ref wchar c; str) c = tzInfo.StandardName[i]; string retval; try { foreach(dchar c; str) { if(c == '\0') break; retval ~= c; } return retval; } catch(Exception e) assert(0, "GetTimeZoneInformation() returned invalid UTF-16."); } } unittest { assert(LocalTime().stdName !is null); version(Posix) { scope(exit) clearTZEnvVar(); setTZEnvVar("America/Los_Angeles"); assert(LocalTime().stdName == "PST"); setTZEnvVar("America/New_York"); assert(LocalTime().stdName == "EST"); } } /++ Typically, the abbreviation (generally 3 or 4 letters) for the time zone when DST $(I is) in effect (e.g. PDT). It is not necessarily unique. However, on Windows, it may be the unabbreviated name (e.g. Pacific Daylight Time). Regardless, it is not the same as name. This property is overridden because the local time of the system could change while the program is running and we need to determine it dynamically rather than it being fixed like it would be with most time zones. +/ @property override string dstName() @trusted const nothrow { version(Posix) { import std.conv : to; try return to!string(tzname[1]); catch(Exception e) assert(0, "to!string(tzname[1]) failed."); } else version(Windows) { TIME_ZONE_INFORMATION tzInfo; GetTimeZoneInformation(&tzInfo); //Cannot use to!string() like this should, probably due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5016 //return to!string(tzInfo.DaylightName); wchar[32] str; foreach(i, ref wchar c; str) c = tzInfo.DaylightName[i]; string retval; try { foreach(dchar c; str) { if(c == '\0') break; retval ~= c; } return retval; } catch(Exception e) assert(0, "GetTimeZoneInformation() returned invalid UTF-16."); } } unittest { assert(LocalTime().dstName !is null); version(Posix) { scope(exit) clearTZEnvVar(); version(FreeBSD) { // A bug on FreeBSD 9+ makes it so that this test fails. // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=168862 } else version(NetBSD) { // The same bug on NetBSD 7+ } else { setTZEnvVar("America/Los_Angeles"); assert(LocalTime().dstName == "PDT"); } setTZEnvVar("America/New_York"); assert(LocalTime().dstName == "EDT"); } } /++ Whether this time zone has Daylight Savings Time at any point in time. Note that for some time zone types it may not have DST for current dates but will still return true for $(D hasDST) because the time zone did at some point have DST. +/ @property override bool hasDST() @trusted const nothrow { version(Posix) { static if(is(typeof(daylight))) return cast(bool)(daylight); else { try { auto currYear = (cast(Date)Clock.currTime()).year; auto janOffset = SysTime(Date(currYear, 1, 4), cast(immutable)this).stdTime - SysTime(Date(currYear, 1, 4), UTC()).stdTime; auto julyOffset = SysTime(Date(currYear, 7, 4), cast(immutable)this).stdTime - SysTime(Date(currYear, 7, 4), UTC()).stdTime; return janOffset != julyOffset; } catch(Exception e) assert(0, "Clock.currTime() threw."); } } else version(Windows) { TIME_ZONE_INFORMATION tzInfo; GetTimeZoneInformation(&tzInfo); return tzInfo.DaylightDate.wMonth != 0; } } unittest { LocalTime().hasDST; version(Posix) { scope(exit) clearTZEnvVar(); setTZEnvVar("America/Los_Angeles"); assert(LocalTime().hasDST); setTZEnvVar("America/New_York"); assert(LocalTime().hasDST); setTZEnvVar("UTC"); assert(!LocalTime().hasDST); } } /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in UTC time (i.e. std time) and returns whether DST is in effect in this time zone at the given point in time. Params: stdTime = The UTC time that needs to be checked for DST in this time zone. +/ override bool dstInEffect(long stdTime) @trusted const nothrow { time_t unixTime = stdTimeToUnixTime(stdTime); version(Posix) { tm* timeInfo = localtime(&unixTime); return cast(bool)(timeInfo.tm_isdst); } else version(Windows) { //Apparently Windows isn't smart enough to deal with negative time_t. if(unixTime >= 0) { tm* timeInfo = localtime(&unixTime); if(timeInfo) return cast(bool)(timeInfo.tm_isdst); } TIME_ZONE_INFORMATION tzInfo; GetTimeZoneInformation(&tzInfo); return WindowsTimeZone._dstInEffect(&tzInfo, stdTime); } } unittest { auto currTime = Clock.currStdTime; LocalTime().dstInEffect(currTime); } /++ Returns hnsecs in the local time zone using the standard C function calls on Posix systems and the standard Windows system calls on Windows systems to adjust the time to the appropriate time zone from std time. Params: stdTime = The UTC time that needs to be adjusted to this time zone's time. See_Also: $(D TimeZone.utcToTZ) +/ override long utcToTZ(long stdTime) @trusted const nothrow { version(Posix) { time_t unixTime = stdTimeToUnixTime(stdTime); tm* timeInfo = localtime(&unixTime); return stdTime + convert!("seconds", "hnsecs")(timeInfo.tm_gmtoff); } else version(Windows) { TIME_ZONE_INFORMATION tzInfo; GetTimeZoneInformation(&tzInfo); return WindowsTimeZone._utcToTZ(&tzInfo, stdTime, hasDST); } } unittest { LocalTime().utcToTZ(0); } /++ Returns std time using the standard C function calls on Posix systems and the standard Windows system calls on Windows systems to adjust the time to UTC from the appropriate time zone. See_Also: $(D TimeZone.tzToUTC) Params: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ override long tzToUTC(long adjTime) @trusted const nothrow { version(Posix) { time_t unixTime = stdTimeToUnixTime(adjTime); immutable past = unixTime - cast(time_t)convert!("days", "seconds")(1); tm* timeInfo = localtime(past < unixTime ? &past : &unixTime); immutable pastOffset = timeInfo.tm_gmtoff; immutable future = unixTime + cast(time_t)convert!("days", "seconds")(1); timeInfo = localtime(future > unixTime ? &future : &unixTime); immutable futureOffset = timeInfo.tm_gmtoff; if(pastOffset == futureOffset) return adjTime - convert!("seconds", "hnsecs")(pastOffset); if(pastOffset < futureOffset) unixTime -= cast(time_t)convert!("hours", "seconds")(1); unixTime -= pastOffset; timeInfo = localtime(&unixTime); return adjTime - convert!("seconds", "hnsecs")(timeInfo.tm_gmtoff); } else version(Windows) { TIME_ZONE_INFORMATION tzInfo; GetTimeZoneInformation(&tzInfo); return WindowsTimeZone._tzToUTC(&tzInfo, adjTime, hasDST); } } unittest { import std.format : format; assert(LocalTime().tzToUTC(LocalTime().utcToTZ(0)) == 0); assert(LocalTime().utcToTZ(LocalTime().tzToUTC(0)) == 0); assert(LocalTime().tzToUTC(LocalTime().utcToTZ(0)) == 0); assert(LocalTime().utcToTZ(LocalTime().tzToUTC(0)) == 0); version(Posix) { scope(exit) clearTZEnvVar(); auto tzInfos = [tuple("America/Los_Angeles", DateTime(2012, 3, 11), DateTime(2012, 11, 4), 2, 2), tuple("America/New_York", DateTime(2012, 3, 11), DateTime(2012, 11, 4), 2, 2), //tuple("America/Santiago", DateTime(2011, 8, 21), DateTime(2011, 5, 8), 0, 0), tuple("Atlantic/Azores", DateTime(2011, 3, 27), DateTime(2011, 10, 30), 0, 1), tuple("Europe/London", DateTime(2012, 3, 25), DateTime(2012, 10, 28), 1, 2), tuple("Europe/Paris", DateTime(2012, 3, 25), DateTime(2012, 10, 28), 2, 3), tuple("Australia/Adelaide", DateTime(2012, 10, 7), DateTime(2012, 4, 1), 2, 3)]; foreach(i; 0 .. tzInfos.length) { auto tzName = tzInfos[i][0]; setTZEnvVar(tzName); immutable spring = tzInfos[i][3]; immutable fall = tzInfos[i][4]; auto stdOffset = SysTime(tzInfos[i][1] + dur!"hours"(-12)).utcOffset; auto dstOffset = stdOffset + dur!"hours"(1); //Verify that creating a SysTime in the given time zone results //in a SysTime with the correct std time during and surrounding //a DST switch. foreach(hour; -12 .. 13) { auto st = SysTime(tzInfos[i][1] + dur!"hours"(hour)); immutable targetHour = hour < 0 ? hour + 24 : hour; static void testHour(SysTime st, int hour, string tzName, size_t line = __LINE__) { enforce(st.hour == hour, new AssertError(format("[%s] [%s]: [%s] [%s]", st, tzName, st.hour, hour), __FILE__, line)); } void testOffset1(Duration offset, bool dstInEffect, size_t line = __LINE__) { AssertError msg(string tag) { return new AssertError(format("%s [%s] [%s]: [%s] [%s] [%s]", tag, st, tzName, st.utcOffset, stdOffset, dstOffset), __FILE__, line); } enforce(st.dstInEffect == dstInEffect, msg("1")); enforce(st.utcOffset == offset, msg("2")); enforce((st + dur!"minutes"(1)).utcOffset == offset, msg("3")); } if(hour == spring) { testHour(st, spring + 1, tzName); testHour(st + dur!"minutes"(1), spring + 1, tzName); } else { testHour(st, targetHour, tzName); testHour(st + dur!"minutes"(1), targetHour, tzName); } if(hour < spring) testOffset1(stdOffset, false); else testOffset1(dstOffset, true); st = SysTime(tzInfos[i][2] + dur!"hours"(hour)); testHour(st, targetHour, tzName); //Verify that 01:00 is the first 01:00 (or whatever hour before the switch is). if(hour == fall - 1) testHour(st + dur!"hours"(1), targetHour, tzName); if(hour < fall) testOffset1(dstOffset, true); else testOffset1(stdOffset, false); } //Verify that converting a time in UTC to a time in another //time zone results in the correct time during and surrounding //a DST switch. bool first = true; auto springSwitch = SysTime(tzInfos[i][1] + dur!"hours"(spring), UTC()) - stdOffset; auto fallSwitch = SysTime(tzInfos[i][2] + dur!"hours"(fall), UTC()) - dstOffset; //@@@BUG@@@ 3659 makes this necessary. auto fallSwitchMinus1 = fallSwitch - dur!"hours"(1); foreach(hour; -24 .. 25) { auto utc = SysTime(tzInfos[i][1] + dur!"hours"(hour), UTC()); auto local = utc.toLocalTime(); void testOffset2(Duration offset, size_t line = __LINE__) { AssertError msg(string tag) { return new AssertError(format("%s [%s] [%s]: [%s] [%s]", tag, hour, tzName, utc, local), __FILE__, line); } enforce((utc + offset).hour == local.hour, msg("1")); enforce((utc + offset + dur!"minutes"(1)).hour == local.hour, msg("2")); } if(utc < springSwitch) testOffset2(stdOffset); else testOffset2(dstOffset); utc = SysTime(tzInfos[i][2] + dur!"hours"(hour), UTC()); local = utc.toLocalTime(); if(utc == fallSwitch || utc == fallSwitchMinus1) { if(first) { testOffset2(dstOffset); first = false; } else testOffset2(stdOffset); } else if(utc > fallSwitch) testOffset2(stdOffset); else testOffset2(dstOffset); } } } } private: this() @safe immutable pure { super("", "", ""); } // This is done so that we can maintain purity in spite of doing an impure // operation the first time that LocalTime() is called. static immutable(LocalTime) singleton() @trusted { import std.concurrency : initOnce; static instance = new immutable(LocalTime)(); static shared bool guard; initOnce!guard({tzset(); return true;}()); return instance; } } /++ A $(LREF2 .TimeZone, TimeZone) which represents UTC. +/ final class UTC : TimeZone { public: /++ $(D UTC) is a singleton class. $(D UTC) returns its only instance. +/ static immutable(UTC) opCall() @safe pure nothrow { return _utc; } /++ Always returns false. +/ @property override bool hasDST() @safe const nothrow { return false; } /++ Always returns false. +/ override bool dstInEffect(long stdTime) @safe const nothrow { return false; } /++ Returns the given hnsecs without changing them at all. Params: stdTime = The UTC time that needs to be adjusted to this time zone's time. See_Also: $(D TimeZone.utcToTZ) +/ override long utcToTZ(long stdTime) @safe const nothrow { return stdTime; } unittest { assert(UTC().utcToTZ(0) == 0); version(Posix) { scope(exit) clearTZEnvVar(); setTZEnvVar("UTC"); auto std = SysTime(Date(2010, 1, 1)); auto dst = SysTime(Date(2010, 7, 1)); assert(UTC().utcToTZ(std.stdTime) == std.stdTime); assert(UTC().utcToTZ(dst.stdTime) == dst.stdTime); } } /++ Returns the given hnsecs without changing them at all. See_Also: $(D TimeZone.tzToUTC) Params: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ override long tzToUTC(long adjTime) @safe const nothrow { return adjTime; } unittest { assert(UTC().tzToUTC(0) == 0); version(Posix) { scope(exit) clearTZEnvVar(); setTZEnvVar("UTC"); auto std = SysTime(Date(2010, 1, 1)); auto dst = SysTime(Date(2010, 7, 1)); assert(UTC().tzToUTC(std.stdTime) == std.stdTime); assert(UTC().tzToUTC(dst.stdTime) == dst.stdTime); } } /++ Returns a $(CXREF time, Duration) of 0. Params: stdTime = The UTC time for which to get the offset from UTC for this time zone. +/ override Duration utcOffsetAt(long stdTime) @safe const nothrow { return dur!"hnsecs"(0); } private: this() @safe immutable pure { super("UTC", "UTC", "UTC"); } static immutable UTC _utc = new immutable(UTC)(); } /++ Represents a time zone with an offset (in minutes, west is negative) from UTC but no DST. It's primarily used as the time zone in the result of $(LREF SysTime)'s $(D fromISOString), $(D fromISOExtString), and $(D fromSimpleString). $(D name) and $(D dstName) are always the empty string since this time zone has no DST, and while it may be meant to represent a time zone which is in the TZ Database, obviously it's not likely to be following the exact rules of any of the time zones in the TZ Database, so it makes no sense to set it. +/ final class SimpleTimeZone : TimeZone { public: /++ Always returns false. +/ @property override bool hasDST() @safe const nothrow { return false; } /++ Always returns false. +/ override bool dstInEffect(long stdTime) @safe const nothrow { return false; } /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in UTC time (i.e. std time) and converts it to this time zone's time. Params: stdTime = The UTC time that needs to be adjusted to this time zone's time. +/ override long utcToTZ(long stdTime) @safe const nothrow { return stdTime + _utcOffset.total!"hnsecs"; } unittest { auto west = new immutable SimpleTimeZone(dur!"hours"(-8)); auto east = new immutable SimpleTimeZone(dur!"hours"(8)); assert(west.utcToTZ(0) == -288_000_000_000L); assert(east.utcToTZ(0) == 288_000_000_000L); assert(west.utcToTZ(54_321_234_567_890L) == 54_033_234_567_890L); const cstz = west; assert(cstz.utcToTZ(50002) == west.utcToTZ(50002)); } /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in this time zone's time and converts it to UTC (i.e. std time). Params: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ override long tzToUTC(long adjTime) @safe const nothrow { return adjTime - _utcOffset.total!"hnsecs"; } unittest { auto west = new immutable SimpleTimeZone(dur!"hours"(-8)); auto east = new immutable SimpleTimeZone(dur!"hours"(8)); assert(west.tzToUTC(-288_000_000_000L) == 0); assert(east.tzToUTC(288_000_000_000L) == 0); assert(west.tzToUTC(54_033_234_567_890L) == 54_321_234_567_890L); const cstz = west; assert(cstz.tzToUTC(20005) == west.tzToUTC(20005)); } /++ Returns utcOffset as a $(CXREF time, Duration). Params: stdTime = The UTC time for which to get the offset from UTC for this time zone. +/ override Duration utcOffsetAt(long stdTime) @safe const nothrow { return _utcOffset; } /++ Params: utcOffset = This time zone's offset from UTC with west of UTC being negative (it is added to UTC to get the adjusted time). stdName = The $(D stdName) for this time zone. +/ this(Duration utcOffset, string stdName = "") @safe immutable pure { //FIXME This probably needs to be changed to something like (-12 - 13). enforce!DateTimeException(abs(utcOffset) < dur!"minutes"(1440), "Offset from UTC must be within range (-24:00 - 24:00)."); super("", stdName, ""); this._utcOffset = utcOffset; } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Please use the overload which takes a Duration.") this(int utcOffset, string stdName = "") @safe immutable pure { this(dur!"minutes"(utcOffset), stdName); } unittest { auto stz = new immutable SimpleTimeZone(dur!"hours"(-8), "PST"); assert(stz.name == ""); assert(stz.stdName == "PST"); assert(stz.dstName == ""); assert(stz.utcOffset == dur!"hours"(-8)); } /++ The amount of time the offset from UTC is (negative is west of UTC, positive is east). +/ @property Duration utcOffset() @safe const pure nothrow { return _utcOffset; } private: /+ Returns a time zone as a string with an offset from UTC. Time zone offsets will be in the form +HHMM or -HHMM. Params: utcOffset = The number of minutes offset from UTC (negative means west). +/ static string toISOString(Duration utcOffset) @safe pure { import std.format : format; immutable absOffset = abs(utcOffset); enforce!DateTimeException(absOffset < dur!"minutes"(1440), "Offset from UTC must be within range (-24:00 - 24:00)."); int hours; int minutes; absOffset.split!("hours", "minutes")(hours, minutes); return format(utcOffset < Duration.zero ? "-%02d%02d" : "+%02d%02d", hours, minutes); } unittest { static string testSTZInvalid(Duration offset) { return SimpleTimeZone.toISOString(offset); } assertThrown!DateTimeException(testSTZInvalid(dur!"minutes"(1440))); assertThrown!DateTimeException(testSTZInvalid(dur!"minutes"(-1440))); assert(toISOString(dur!"minutes"(0)) == "+0000"); assert(toISOString(dur!"minutes"(1)) == "+0001"); assert(toISOString(dur!"minutes"(10)) == "+0010"); assert(toISOString(dur!"minutes"(59)) == "+0059"); assert(toISOString(dur!"minutes"(60)) == "+0100"); assert(toISOString(dur!"minutes"(90)) == "+0130"); assert(toISOString(dur!"minutes"(120)) == "+0200"); assert(toISOString(dur!"minutes"(480)) == "+0800"); assert(toISOString(dur!"minutes"(1439)) == "+2359"); assert(toISOString(dur!"minutes"(-1)) == "-0001"); assert(toISOString(dur!"minutes"(-10)) == "-0010"); assert(toISOString(dur!"minutes"(-59)) == "-0059"); assert(toISOString(dur!"minutes"(-60)) == "-0100"); assert(toISOString(dur!"minutes"(-90)) == "-0130"); assert(toISOString(dur!"minutes"(-120)) == "-0200"); assert(toISOString(dur!"minutes"(-480)) == "-0800"); assert(toISOString(dur!"minutes"(-1439)) == "-2359"); } /+ Returns a time zone as a string with an offset from UTC. Time zone offsets will be in the form +HH:MM or -HH:MM. Params: utcOffset = The number of minutes offset from UTC (negative means west). +/ static string toISOExtString(Duration utcOffset) @safe pure { import std.format : format; immutable absOffset = abs(utcOffset); enforce!DateTimeException(absOffset < dur!"minutes"(1440), "Offset from UTC must be within range (-24:00 - 24:00)."); int hours; int minutes; absOffset.split!("hours", "minutes")(hours, minutes); return format(utcOffset < Duration.zero ? "-%02d:%02d" : "+%02d:%02d", hours, minutes); } unittest { static string testSTZInvalid(Duration offset) { return SimpleTimeZone.toISOExtString(offset); } assertThrown!DateTimeException(testSTZInvalid(dur!"minutes"(1440))); assertThrown!DateTimeException(testSTZInvalid(dur!"minutes"(-1440))); assert(toISOExtString(dur!"minutes"(0)) == "+00:00"); assert(toISOExtString(dur!"minutes"(1)) == "+00:01"); assert(toISOExtString(dur!"minutes"(10)) == "+00:10"); assert(toISOExtString(dur!"minutes"(59)) == "+00:59"); assert(toISOExtString(dur!"minutes"(60)) == "+01:00"); assert(toISOExtString(dur!"minutes"(90)) == "+01:30"); assert(toISOExtString(dur!"minutes"(120)) == "+02:00"); assert(toISOExtString(dur!"minutes"(480)) == "+08:00"); assert(toISOExtString(dur!"minutes"(1439)) == "+23:59"); assert(toISOExtString(dur!"minutes"(-1)) == "-00:01"); assert(toISOExtString(dur!"minutes"(-10)) == "-00:10"); assert(toISOExtString(dur!"minutes"(-59)) == "-00:59"); assert(toISOExtString(dur!"minutes"(-60)) == "-01:00"); assert(toISOExtString(dur!"minutes"(-90)) == "-01:30"); assert(toISOExtString(dur!"minutes"(-120)) == "-02:00"); assert(toISOExtString(dur!"minutes"(-480)) == "-08:00"); assert(toISOExtString(dur!"minutes"(-1439)) == "-23:59"); } /+ Takes a time zone as a string with an offset from UTC and returns a $(LREF SimpleTimeZone) which matches. The accepted formats for time zone offsets are +HH, -HH, +HHMM, and -HHMM. Params: isoString = A string which represents a time zone in the ISO format. +/ static immutable(SimpleTimeZone) fromISOString(S)(S isoString) @safe pure if(isSomeString!S) { import std.ascii : isDigit; import std.conv : to; import std.algorithm : startsWith, countUntil, all; import std.format : format; auto dstr = to!dstring(isoString); enforce!DateTimeException(dstr.startsWith('-', '+'), "Invalid ISO String"); auto sign = dstr.startsWith('-') ? -1 : 1; dstr.popFront(); enforce!DateTimeException(all!isDigit(dstr), format("Invalid ISO String: %s", dstr)); int hours; int minutes; if(dstr.length == 2) hours = to!int(dstr); else if(dstr.length == 4) { hours = to!int(dstr[0 .. 2]); minutes = to!int(dstr[2 .. 4]); } else throw new DateTimeException(format("Invalid ISO String: %s", dstr)); enforce!DateTimeException(hours < 24 && minutes < 60, format("Invalid ISO String: %s", dstr)); return new immutable SimpleTimeZone(sign * (dur!"hours"(hours) + dur!"minutes"(minutes))); } unittest { import std.format : format; foreach(str; ["", "Z", "-", "+", "-:", "+:", "-1:", "+1:", "+1", "-1", "-24:00", "+24:00", "-24", "+24", "-2400", "+2400", "1", "+1", "-1", "+9", "-9", "+1:0", "+01:0", "+1:00", "+01:000", "+01:60", "-1:0", "-01:0", "-1:00", "-01:000", "-01:60", "000", "00000", "0160", "-0160", " +08:00", "+ 08:00", "+08 :00", "+08: 00", "+08:00 ", " -08:00", "- 08:00", "-08 :00", "-08: 00", "-08:00 ", " +0800", "+ 0800", "+08 00", "+08 00", "+0800 ", " -0800", "- 0800", "-08 00", "-08 00", "-0800 ", "+ab:cd", "+abcd", "+0Z:00", "+Z", "+00Z", "-ab:cd", "+abcd", "-0Z:00", "-Z", "-00Z", "01:00", "12:00", "23:59"]) { assertThrown!DateTimeException(SimpleTimeZone.fromISOString(str), format("[%s]", str)); } static void test(string str, Duration utcOffset, size_t line = __LINE__) { if(SimpleTimeZone.fromISOString(str).utcOffset != (new immutable SimpleTimeZone(utcOffset)).utcOffset) { throw new AssertError("unittest failure", __FILE__, line); } } test("+0000", Duration.zero); test("+0001", minutes(1)); test("+0010", minutes(10)); test("+0059", minutes(59)); test("+0100", hours(1)); test("+0130", hours(1) + minutes(30)); test("+0200", hours(2)); test("+0800", hours(8)); test("+2359", hours(23) + minutes(59)); test("-0001", minutes(-1)); test("-0010", minutes(-10)); test("-0059", minutes(-59)); test("-0100", hours(-1)); test("-0130", hours(-1) - minutes(30)); test("-0200", hours(-2)); test("-0800", hours(-8)); test("-2359", hours(-23) - minutes(59)); test("+00", Duration.zero); test("+01", hours(1)); test("+02", hours(2)); test("+12", hours(12)); test("+23", hours(23)); test("-00", Duration.zero); test("-01", hours(-1)); test("-02", hours(-2)); test("-12", hours(-12)); test("-23", hours(-23)); } unittest { import std.format : format; static void test(in string isoString, int expectedOffset, size_t line = __LINE__) { auto stz = SimpleTimeZone.fromISOExtString(isoString); if(stz.utcOffset != dur!"minutes"(expectedOffset)) throw new AssertError(format("unittest failure: wrong offset [%s]", stz.utcOffset), __FILE__, line); auto result = SimpleTimeZone.toISOExtString(stz.utcOffset); if(result != isoString) throw new AssertError(format("unittest failure: [%s] != [%s]", result, isoString), __FILE__, line); } test("+00:00", 0); test("+00:01", 1); test("+00:10", 10); test("+00:59", 59); test("+01:00", 60); test("+01:30", 90); test("+02:00", 120); test("+08:00", 480); test("+08:00", 480); test("+23:59", 1439); test("-00:01", -1); test("-00:10", -10); test("-00:59", -59); test("-01:00", -60); test("-01:30", -90); test("-02:00", -120); test("-08:00", -480); test("-08:00", -480); test("-23:59", -1439); } /+ Takes a time zone as a string with an offset from UTC and returns a $(LREF SimpleTimeZone) which matches. The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and -HH:MM. Params: isoExtString = A string which represents a time zone in the ISO format. +/ static immutable(SimpleTimeZone) fromISOExtString(S)(S isoExtString) @safe pure if(isSomeString!S) { import std.ascii : isDigit; import std.conv : to; import std.algorithm : startsWith, countUntil, all; import std.format : format; auto dstr = to!dstring(isoExtString); enforce!DateTimeException(dstr.startsWith('-', '+'), "Invalid ISO String"); auto sign = dstr.startsWith('-') ? -1 : 1; dstr.popFront(); enforce!DateTimeException(!dstr.empty, "Invalid ISO String"); immutable colon = dstr.countUntil(':'); dstring hoursStr; dstring minutesStr; if(colon != -1) { hoursStr = dstr[0 .. colon]; minutesStr = dstr[colon + 1 .. $]; enforce!DateTimeException(minutesStr.length == 2, format("Invalid ISO String: %s", dstr)); } else hoursStr = dstr; enforce!DateTimeException(hoursStr.length == 2, format("Invalid ISO String: %s", dstr)); enforce!DateTimeException(all!isDigit(hoursStr), format("Invalid ISO String: %s", dstr)); enforce!DateTimeException(all!isDigit(minutesStr), format("Invalid ISO String: %s", dstr)); immutable hours = to!int(hoursStr); immutable minutes = minutesStr.empty ? 0 : to!int(minutesStr); enforce!DateTimeException(hours < 24 && minutes < 60, format("Invalid ISO String: %s", dstr)); return new immutable SimpleTimeZone(sign * (dur!"hours"(hours) + dur!"minutes"(minutes))); } unittest { import std.format : format; foreach(str; ["", "Z", "-", "+", "-:", "+:", "-1:", "+1:", "+1", "-1", "-24:00", "+24:00", "-24", "+24", "-2400", "-2400", "1", "+1", "-1", "+9", "-9", "+1:0", "+01:0", "+1:00", "+01:000", "+01:60", "-1:0", "-01:0", "-1:00", "-01:000", "-01:60", "000", "00000", "0160", "-0160", " +08:00", "+ 08:00", "+08 :00", "+08: 00", "+08:00 ", " -08:00", "- 08:00", "-08 :00", "-08: 00", "-08:00 ", " +0800", "+ 0800", "+08 00", "+08 00", "+0800 ", " -0800", "- 0800", "-08 00", "-08 00", "-0800 ", "+ab:cd", "abcd", "+0Z:00", "+Z", "+00Z", "-ab:cd", "abcd", "-0Z:00", "-Z", "-00Z", "0100", "1200", "2359"]) { assertThrown!DateTimeException(SimpleTimeZone.fromISOExtString(str), format("[%s]", str)); } static void test(string str, Duration utcOffset, size_t line = __LINE__) { if(SimpleTimeZone.fromISOExtString(str).utcOffset != (new immutable SimpleTimeZone(utcOffset)).utcOffset) { throw new AssertError("unittest failure", __FILE__, line); } } test("+00:00", Duration.zero); test("+00:01", minutes(1)); test("+00:10", minutes(10)); test("+00:59", minutes(59)); test("+01:00", hours(1)); test("+01:30", hours(1) + minutes(30)); test("+02:00", hours(2)); test("+08:00", hours(8)); test("+23:59", hours(23) + minutes(59)); test("-00:01", minutes(-1)); test("-00:10", minutes(-10)); test("-00:59", minutes(-59)); test("-01:00", hours(-1)); test("-01:30", hours(-1) - minutes(30)); test("-02:00", hours(-2)); test("-08:00", hours(-8)); test("-23:59", hours(-23) - minutes(59)); test("+00", Duration.zero); test("+01", hours(1)); test("+02", hours(2)); test("+12", hours(12)); test("+23", hours(23)); test("-00", Duration.zero); test("-01", hours(-1)); test("-02", hours(-2)); test("-12", hours(-12)); test("-23", hours(-23)); } unittest { import std.format : format; static void test(in string isoExtString, int expectedOffset, size_t line = __LINE__) { auto stz = SimpleTimeZone.fromISOExtString(isoExtString); if(stz.utcOffset != dur!"minutes"(expectedOffset)) throw new AssertError(format("unittest failure: wrong offset [%s]", stz.utcOffset), __FILE__, line); auto result = SimpleTimeZone.toISOExtString(stz.utcOffset); if(result != isoExtString) throw new AssertError(format("unittest failure: [%s] != [%s]", result, isoExtString), __FILE__, line); } test("+00:00", 0); test("+00:01", 1); test("+00:10", 10); test("+00:59", 59); test("+01:00", 60); test("+01:30", 90); test("+02:00", 120); test("+08:00", 480); test("+08:00", 480); test("+23:59", 1439); test("-00:01", -1); test("-00:10", -10); test("-00:59", -59); test("-01:00", -60); test("-01:30", -90); test("-02:00", -120); test("-08:00", -480); test("-08:00", -480); test("-23:59", -1439); } immutable Duration _utcOffset; } /++ Represents a time zone from a TZ Database time zone file. Files from the TZ Database are how Posix systems hold their time zone information. Unfortunately, Windows does not use the TZ Database. To use the TZ Database, use $(D PosixTimeZone) (which reads its information from the TZ Database files on disk) on Windows by providing the TZ Database files and telling $(D PosixTimeZone.getTimeZone) where the directory holding them is. To get a $(D PosixTimeZone), either call $(D PosixTimeZone.getTimeZone) (which allows specifying the location the time zone files) or call $(D TimeZone.getTimeZone) (which will give a $(D PosixTimeZone) on Posix systems and a $(LREF WindowsTimeZone) on Windows systems). Note: Unless your system's local time zone deals with leap seconds (which is highly unlikely), then the only way to get a time zone which takes leap seconds into account is to use $(D PosixTimeZone) with a time zone whose name starts with "right/". Those time zone files do include leap seconds, and $(D PosixTimeZone) will take them into account (though posix systems which use a "right/" time zone as their local time zone will $(I not) take leap seconds into account even though they're in the file). See_Also: $(WEB www.iana.org/time-zones, Home of the TZ Database files)
$(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ Database)
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of Time Zones) +/ final class PosixTimeZone : TimeZone { import std.stdio : File; import std.path : extension; import std.file : isDir, isFile, exists, dirEntries, SpanMode, DirEntry; import std.string : strip, representation; import std.algorithm : countUntil, canFind, startsWith; public: /++ Whether this time zone has Daylight Savings Time at any point in time. Note that for some time zone types it may not have DST for current dates but will still return true for $(D hasDST) because the time zone did at some point have DST. +/ @property override bool hasDST() @safe const nothrow { return _hasDST; } /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in UTC time (i.e. std time) and returns whether DST is in effect in this time zone at the given point in time. Params: stdTime = The UTC time that needs to be checked for DST in this time zone. +/ override bool dstInEffect(long stdTime) @safe const nothrow { assert(!_transitions.empty); immutable unixTime = stdTimeToUnixTime(stdTime); immutable found = countUntil!"b < a.timeT"(_transitions, unixTime); if(found == -1) return _transitions.back.ttInfo.isDST; immutable transition = found == 0 ? _transitions[0] : _transitions[found - 1]; return transition.ttInfo.isDST; } /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in UTC time (i.e. std time) and converts it to this time zone's time. Params: stdTime = The UTC time that needs to be adjusted to this time zone's time. +/ override long utcToTZ(long stdTime) @safe const nothrow { assert(!_transitions.empty); immutable leapSecs = calculateLeapSeconds(stdTime); immutable unixTime = stdTimeToUnixTime(stdTime); immutable found = countUntil!"b < a.timeT"(_transitions, unixTime); if(found == -1) return stdTime + convert!("seconds", "hnsecs")(_transitions.back.ttInfo.utcOffset + leapSecs); immutable transition = found == 0 ? _transitions[0] : _transitions[found - 1]; return stdTime + convert!("seconds", "hnsecs")(transition.ttInfo.utcOffset + leapSecs); } /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in this time zone's time and converts it to UTC (i.e. std time). Params: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ override long tzToUTC(long adjTime) @safe const nothrow { assert(!_transitions.empty); immutable leapSecs = calculateLeapSeconds(adjTime); time_t unixTime = stdTimeToUnixTime(adjTime); immutable past = unixTime - convert!("days", "seconds")(1); immutable future = unixTime + convert!("days", "seconds")(1); immutable pastFound = countUntil!"b < a.timeT"(_transitions, past); if(pastFound == -1) return adjTime - convert!("seconds", "hnsecs")(_transitions.back.ttInfo.utcOffset + leapSecs); immutable futureFound = countUntil!"b < a.timeT"(_transitions[pastFound .. $], future); immutable pastTrans = pastFound == 0 ? _transitions[0] : _transitions[pastFound - 1]; if(futureFound == 0) return adjTime - convert!("seconds", "hnsecs")(pastTrans.ttInfo.utcOffset + leapSecs); immutable futureTrans = futureFound == -1 ? _transitions.back : _transitions[pastFound + futureFound - 1]; immutable pastOffset = pastTrans.ttInfo.utcOffset; if(pastOffset < futureTrans.ttInfo.utcOffset) unixTime -= convert!("hours", "seconds")(1); immutable found = countUntil!"b < a.timeT"(_transitions[pastFound .. $], unixTime - pastOffset); if(found == -1) return adjTime - convert!("seconds", "hnsecs")(_transitions.back.ttInfo.utcOffset + leapSecs); immutable transition = found == 0 ? pastTrans : _transitions[pastFound + found - 1]; return adjTime - convert!("seconds", "hnsecs")(transition.ttInfo.utcOffset + leapSecs); } version(Android) { // Android concatenates all time zone data into a single file and stores it here. enum defaultTZDatabaseDir = "/system/usr/share/zoneinfo/"; } else version(Solaris) { /++ The default directory where the TZ Database files are. +/ enum defaultTZDatabaseDir = "/usr/share/lib/zoneinfo/"; } else version(Posix) { /++ The default directory where the TZ Database files are. It's empty for Windows, since Windows doesn't have them. +/ enum defaultTZDatabaseDir = "/usr/share/zoneinfo/"; } else version(Windows) { /++ The default directory where the TZ Database files are. It's empty for Windows, since Windows doesn't have them. +/ enum defaultTZDatabaseDir = ""; } /++ Returns a $(LREF2 .TimeZone, TimeZone) with the give name per the TZ Database. The time zone information is fetched from the TZ Database time zone files in the given directory. See_Also: $(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ Database)
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of Time Zones) Params: name = The TZ Database name of the desired time zone tzDatabaseDir = The directory where the TZ Database files are located. Because these files are not located on Windows systems, provide them and give their location here to use $(LREF PosixTimeZone)s. Throws: $(LREF DateTimeException) if the given time zone could not be found or $(D FileException) if the TZ Database file could not be opened. +/ //TODO make it possible for tzDatabaseDir to be gzipped tar file rather than an uncompressed // directory. static immutable(PosixTimeZone) getTimeZone(string name, string tzDatabaseDir = defaultTZDatabaseDir) @trusted { import std.algorithm : sort; import std.range : retro; import std.format : format; import std.path : asNormalizedPath, chainPath; import std.conv : to; name = strip(name); enforce(tzDatabaseDir.exists(), new DateTimeException(format("Directory %s does not exist.", tzDatabaseDir))); enforce(tzDatabaseDir.isDir, new DateTimeException(format("%s is not a directory.", tzDatabaseDir))); version(Android) { auto tzfileOffset = name in tzdataIndex(tzDatabaseDir); enforce(tzfileOffset, new DateTimeException(format("The time zone %s is not listed.", name))); string tzFilename = separate_index ? "zoneinfo.dat" : "tzdata"; const file = asNormalizedPath(chainPath(tzDatabaseDir, tzFilename)).to!string; } else const file = asNormalizedPath(chainPath(tzDatabaseDir, name)).to!string; enforce(file.exists(), new DateTimeException(format("File %s does not exist.", file))); enforce(file.isFile, new DateTimeException(format("%s is not a file.", file))); auto tzFile = File(file); version(Android) tzFile.seek(*tzfileOffset); immutable gmtZone = name.representation().canFind("GMT"); try { _enforceValidTZFile(readVal!(char[])(tzFile, 4) == "TZif"); immutable char tzFileVersion = readVal!char(tzFile); _enforceValidTZFile(tzFileVersion == '\0' || tzFileVersion == '2' || tzFileVersion == '3'); { auto zeroBlock = readVal!(ubyte[])(tzFile, 15); bool allZeroes = true; foreach(val; zeroBlock) { if(val != 0) { allZeroes = false; break; } } _enforceValidTZFile(allZeroes); } //The number of UTC/local indicators stored in the file. auto tzh_ttisgmtcnt = readVal!int(tzFile); //The number of standard/wall indicators stored in the file. auto tzh_ttisstdcnt = readVal!int(tzFile); //The number of leap seconds for which data is stored in the file. auto tzh_leapcnt = readVal!int(tzFile); //The number of "transition times" for which data is stored in the file. auto tzh_timecnt = readVal!int(tzFile); //The number of "local time types" for which data is stored in the file (must not be zero). auto tzh_typecnt = readVal!int(tzFile); _enforceValidTZFile(tzh_typecnt != 0); //The number of characters of "timezone abbreviation strings" stored in the file. auto tzh_charcnt = readVal!int(tzFile); //time_ts where DST transitions occur. auto transitionTimeTs = new long[](tzh_timecnt); foreach(ref transition; transitionTimeTs) transition = readVal!int(tzFile); //Indices into ttinfo structs indicating the changes //to be made at the corresponding DST transition. auto ttInfoIndices = new ubyte[](tzh_timecnt); foreach(ref ttInfoIndex; ttInfoIndices) ttInfoIndex = readVal!ubyte(tzFile); //ttinfos which give info on DST transitions. auto tempTTInfos = new TempTTInfo[](tzh_typecnt); foreach(ref ttInfo; tempTTInfos) ttInfo = readVal!TempTTInfo(tzFile); //The array of time zone abbreviation characters. auto tzAbbrevChars = readVal!(char[])(tzFile, tzh_charcnt); auto leapSeconds = new LeapSecond[](tzh_leapcnt); foreach(ref leapSecond; leapSeconds) { //The time_t when the leap second occurs. auto timeT = readVal!int(tzFile); //The total number of leap seconds to be applied after //the corresponding leap second. auto total = readVal!int(tzFile); leapSecond = LeapSecond(timeT, total); } //Indicate whether each corresponding DST transition were specified //in standard time or wall clock time. auto transitionIsStd = new bool[](tzh_ttisstdcnt); foreach(ref isStd; transitionIsStd) isStd = readVal!bool(tzFile); //Indicate whether each corresponding DST transition associated with //local time types are specified in UTC or local time. auto transitionInUTC = new bool[](tzh_ttisgmtcnt); foreach(ref inUTC; transitionInUTC) inUTC = readVal!bool(tzFile); _enforceValidTZFile(!tzFile.eof); //If version 2 or 3, the information is duplicated in 64-bit. if(tzFileVersion == '2' || tzFileVersion == '3') { _enforceValidTZFile(readVal!(char[])(tzFile, 4) == "TZif"); immutable char tzFileVersion2 = readVal!(char)(tzFile); _enforceValidTZFile(tzFileVersion2 == '2' || tzFileVersion2 == '3'); { auto zeroBlock = readVal!(ubyte[])(tzFile, 15); bool allZeroes = true; foreach(val; zeroBlock) { if(val != 0) { allZeroes = false; break; } } _enforceValidTZFile(allZeroes); } //The number of UTC/local indicators stored in the file. tzh_ttisgmtcnt = readVal!int(tzFile); //The number of standard/wall indicators stored in the file. tzh_ttisstdcnt = readVal!int(tzFile); //The number of leap seconds for which data is stored in the file. tzh_leapcnt = readVal!int(tzFile); //The number of "transition times" for which data is stored in the file. tzh_timecnt = readVal!int(tzFile); //The number of "local time types" for which data is stored in the file (must not be zero). tzh_typecnt = readVal!int(tzFile); _enforceValidTZFile(tzh_typecnt != 0); //The number of characters of "timezone abbreviation strings" stored in the file. tzh_charcnt = readVal!int(tzFile); //time_ts where DST transitions occur. transitionTimeTs = new long[](tzh_timecnt); foreach(ref transition; transitionTimeTs) transition = readVal!long(tzFile); //Indices into ttinfo structs indicating the changes //to be made at the corresponding DST transition. ttInfoIndices = new ubyte[](tzh_timecnt); foreach(ref ttInfoIndex; ttInfoIndices) ttInfoIndex = readVal!ubyte(tzFile); //ttinfos which give info on DST transitions. tempTTInfos = new TempTTInfo[](tzh_typecnt); foreach(ref ttInfo; tempTTInfos) ttInfo = readVal!TempTTInfo(tzFile); //The array of time zone abbreviation characters. tzAbbrevChars = readVal!(char[])(tzFile, tzh_charcnt); leapSeconds = new LeapSecond[](tzh_leapcnt); foreach(ref leapSecond; leapSeconds) { //The time_t when the leap second occurs. auto timeT = readVal!long(tzFile); //The total number of leap seconds to be applied after //the corresponding leap second. auto total = readVal!int(tzFile); leapSecond = LeapSecond(timeT, total); } //Indicate whether each corresponding DST transition were specified //in standard time or wall clock time. transitionIsStd = new bool[](tzh_ttisstdcnt); foreach(ref isStd; transitionIsStd) isStd = readVal!bool(tzFile); //Indicate whether each corresponding DST transition associated with //local time types are specified in UTC or local time. transitionInUTC = new bool[](tzh_ttisgmtcnt); foreach(ref inUTC; transitionInUTC) inUTC = readVal!bool(tzFile); } _enforceValidTZFile(tzFile.readln().strip().empty); auto posixEnvStr = tzFile.readln().strip(); version(Android) { // Android uses a single file for all timezone data, so the file // doesn't end here. } else { _enforceValidTZFile(tzFile.readln().strip().empty); _enforceValidTZFile(tzFile.eof); } auto transitionTypes = new TransitionType*[](tempTTInfos.length); foreach(i, ref ttype; transitionTypes) { bool isStd = false; if(i < transitionIsStd.length && !transitionIsStd.empty) isStd = transitionIsStd[i]; bool inUTC = false; if(i < transitionInUTC.length && !transitionInUTC.empty) inUTC = transitionInUTC[i]; ttype = new TransitionType(isStd, inUTC); } auto ttInfos = new immutable(TTInfo)*[](tempTTInfos.length); foreach(i, ref ttInfo; ttInfos) { auto tempTTInfo = tempTTInfos[i]; if(gmtZone) tempTTInfo.tt_gmtoff = -tempTTInfo.tt_gmtoff; auto abbrevChars = tzAbbrevChars[tempTTInfo.tt_abbrind .. $]; string abbrev = abbrevChars[0 .. abbrevChars.countUntil('\0')].idup; ttInfo = new immutable(TTInfo)(tempTTInfos[i], abbrev); } auto tempTransitions = new TempTransition[](transitionTimeTs.length); foreach(i, ref tempTransition; tempTransitions) { immutable ttiIndex = ttInfoIndices[i]; auto transitionTimeT = transitionTimeTs[i]; auto ttype = transitionTypes[ttiIndex]; auto ttInfo = ttInfos[ttiIndex]; tempTransition = TempTransition(transitionTimeT, ttInfo, ttype); } if(tempTransitions.empty) { _enforceValidTZFile(ttInfos.length == 1 && transitionTypes.length == 1); tempTransitions ~= TempTransition(0, ttInfos[0], transitionTypes[0]); } sort!"a.timeT < b.timeT"(tempTransitions); sort!"a.timeT < b.timeT"(leapSeconds); auto transitions = new Transition[](tempTransitions.length); foreach(i, ref transition; transitions) { auto tempTransition = tempTransitions[i]; auto transitionTimeT = tempTransition.timeT; auto ttInfo = tempTransition.ttInfo; auto ttype = tempTransition.ttype; _enforceValidTZFile(i == 0 || transitionTimeT > tempTransitions[i - 1].timeT); transition = Transition(transitionTimeT, ttInfo); } string stdName; string dstName; bool hasDST = false; foreach(transition; retro(transitions)) { auto ttInfo = transition.ttInfo; if(ttInfo.isDST) { if(dstName.empty) dstName = ttInfo.abbrev; hasDST = true; } else { if(stdName.empty) stdName = ttInfo.abbrev; } if(!stdName.empty && !dstName.empty) break; } return new immutable PosixTimeZone(transitions.idup, leapSeconds.idup, name, stdName, dstName, hasDST); } catch(DateTimeException dte) throw dte; catch(Exception e) throw new DateTimeException("Not a valid TZ data file", __FILE__, __LINE__, e); } /// unittest { version(Posix) { auto tz = PosixTimeZone.getTimeZone("America/Los_Angeles"); assert(tz.name == "America/Los_Angeles"); assert(tz.stdName == "PST"); assert(tz.dstName == "PDT"); } } /++ Returns a list of the names of the time zones installed on the system. Providing a sub-name narrows down the list of time zones (which can number in the thousands). For example, passing in "America" as the sub-name returns only the time zones which begin with "America". Params: subName = The first part of the desired time zones. tzDatabaseDir = The directory where the TZ Database files are located. Throws: $(D FileException) if it fails to read from disk. +/ static string[] getInstalledTZNames(string subName = "", string tzDatabaseDir = defaultTZDatabaseDir) @trusted { import std.array : appender; import std.algorithm : sort; import std.format : format; version(Posix) subName = strip(subName); else version(Windows) { import std.array : replace; import std.path : dirSeparator; subName = replace(strip(subName), "/", dirSeparator); } enforce(tzDatabaseDir.exists(), new DateTimeException(format("Directory %s does not exist.", tzDatabaseDir))); enforce(tzDatabaseDir.isDir, new DateTimeException(format("%s is not a directory.", tzDatabaseDir))); auto timezones = appender!(string[])(); version(Android) { import std.algorithm : copy, filter; tzdataIndex(tzDatabaseDir) .byKey .filter!(a => a.startsWith(subName)) .copy(timezones); } else { foreach(DirEntry dentry; dirEntries(tzDatabaseDir, SpanMode.depth)) { if(dentry.isFile) { auto tzName = dentry.name[tzDatabaseDir.length .. $]; if(!tzName.extension().empty || !tzName.startsWith(subName) || tzName == "leapseconds" || tzName == "+VERSION") { continue; } timezones.put(tzName); } } } sort(timezones.data); return timezones.data; } version(Posix) unittest { static void testPTZSuccess(string tzName) { scope(failure) writefln("TZName which threw: %s", tzName); PosixTimeZone.getTimeZone(tzName); } static void testPTZFailure(string tzName) { scope(success) writefln("TZName which was supposed to throw: %s", tzName); PosixTimeZone.getTimeZone(tzName); } auto tzNames = getInstalledTZNames(); foreach(tzName; tzNames) assertNotThrown!DateTimeException(testPTZSuccess(tzName)); // No timezone directories on Android, just a single tzdata file version(Android) {} else foreach(DirEntry dentry; dirEntries(defaultTZDatabaseDir, SpanMode.depth)) { if(dentry.isFile) { auto tzName = dentry.name[defaultTZDatabaseDir.length .. $]; if(!canFind(tzNames, tzName)) assertThrown!DateTimeException(testPTZFailure(tzName)); } } } private: /+ Holds information on when a time transition occures (usually a transition to or from DST) as well as a pointer to the $(D TTInfo) which holds information on the utc offset past the transition. +/ struct Transition { this(long timeT, immutable (TTInfo)* ttInfo) @safe pure { this.timeT = timeT; this.ttInfo = ttInfo; } long timeT; immutable (TTInfo)* ttInfo; } /+ Holds information on when a leap second occurs. +/ struct LeapSecond { this(long timeT, int total) @safe pure { this.timeT = timeT; this.total = total; } long timeT; int total; } /+ Holds information on the utc offset after a transition as well as whether DST is in effect after that transition. +/ struct TTInfo { this(in TempTTInfo tempTTInfo, string abbrev) @safe immutable pure { utcOffset = tempTTInfo.tt_gmtoff; isDST = tempTTInfo.tt_isdst; this.abbrev = abbrev; } immutable int utcOffset; /// Offset from UTC. immutable bool isDST; /// Whether DST is in effect. immutable string abbrev; /// The current abbreviation for the time zone. } /+ Struct used to hold information relating to $(D TTInfo) while organizing the time zone information prior to putting it in its final form. +/ struct TempTTInfo { this(int gmtOff, bool isDST, ubyte abbrInd) @safe pure { tt_gmtoff = gmtOff; tt_isdst = isDST; tt_abbrind = abbrInd; } int tt_gmtoff; bool tt_isdst; ubyte tt_abbrind; } /+ Struct used to hold information relating to $(D Transition) while organizing the time zone information prior to putting it in its final form. +/ struct TempTransition { this(long timeT, immutable (TTInfo)* ttInfo, TransitionType* ttype) @safe pure { this.timeT = timeT; this.ttInfo = ttInfo; this.ttype = ttype; } long timeT; immutable (TTInfo)* ttInfo; TransitionType* ttype; } /+ Struct used to hold information relating to $(D Transition) and $(D TTInfo) while organizing the time zone information prior to putting it in its final form. +/ struct TransitionType { this(bool isStd, bool inUTC) @safe pure { this.isStd = isStd; this.inUTC = inUTC; } /// Whether the transition is in std time (as opposed to wall clock time). bool isStd; /// Whether the transition is in UTC (as opposed to local time). bool inUTC; } /+ Reads an int from a TZ file. +/ static T readVal(T)(ref File tzFile) @trusted if((isIntegral!T || isSomeChar!T) || is(Unqual!T == bool)) { import std.bitmanip; T[1] buff; _enforceValidTZFile(!tzFile.eof); tzFile.rawRead(buff); return bigEndianToNative!T(cast(ubyte[T.sizeof])buff); } /+ Reads an array of values from a TZ file. +/ static T readVal(T)(ref File tzFile, size_t length) @trusted if(isArray!T) { auto buff = new T(length); _enforceValidTZFile(!tzFile.eof); tzFile.rawRead(buff); return buff; } /+ Reads a $(D TempTTInfo) from a TZ file. +/ static T readVal(T)(ref File tzFile) @safe if(is(T == TempTTInfo)) { return TempTTInfo(readVal!int(tzFile), readVal!bool(tzFile), readVal!ubyte(tzFile)); } /+ Throws: $(LREF DateTimeException) if $(D result) is false. +/ static void _enforceValidTZFile(bool result, size_t line = __LINE__) @safe pure { if(!result) throw new DateTimeException("Not a valid tzdata file.", __FILE__, line); } int calculateLeapSeconds(long stdTime) @safe const pure nothrow { if(_leapSeconds.empty) return 0; immutable unixTime = stdTimeToUnixTime(stdTime); if(_leapSeconds.front.timeT >= unixTime) return 0; immutable found = countUntil!"b < a.timeT"(_leapSeconds, unixTime); if(found == -1) return _leapSeconds.back.total; immutable leapSecond = found == 0 ? _leapSeconds[0] : _leapSeconds[found - 1]; return leapSecond.total; } this(immutable Transition[] transitions, immutable LeapSecond[] leapSeconds, string name, string stdName, string dstName, bool hasDST) @safe immutable pure { if(dstName.empty && !stdName.empty) dstName = stdName; else if(stdName.empty && !dstName.empty) stdName = dstName; super(name, stdName, dstName); if(!transitions.empty) { foreach(i, transition; transitions[0 .. $-1]) _enforceValidTZFile(transition.timeT < transitions[i + 1].timeT); } foreach(i, leapSecond; leapSeconds) _enforceValidTZFile(i == leapSeconds.length - 1 || leapSecond.timeT < leapSeconds[i + 1].timeT); _transitions = transitions; _leapSeconds = leapSeconds; _hasDST = hasDST; } // Android concatenates the usual timezone directories into a single file, // tzdata, along with an index to jump to each timezone's offset. In older // versions of Android, the index was stored in a separate file, zoneinfo.idx, // whereas now it's stored at the beginning of tzdata. version(Android) { // Keep track of whether there's a separate index, zoneinfo.idx. Only // check this after calling tzdataIndex, as it's initialized there. static shared bool separate_index; // Extracts the name of each time zone and the offset where its data is // located in the tzdata file from the index and caches it for later. static const(uint[string]) tzdataIndex(string tzDir) { import std.concurrency : initOnce; static __gshared uint[string] _tzIndex; // _tzIndex is initialized once and then shared across all threads. initOnce!_tzIndex( { import std.conv : to; import std.format : format; import std.path : asNormalizedPath, chainPath; enum indexEntrySize = 52; const combinedFile = asNormalizedPath(chainPath(tzDir, "tzdata")).to!string; const indexFile = asNormalizedPath(chainPath(tzDir, "zoneinfo.idx")).to!string; File tzFile; uint indexEntries, dataOffset; uint[string] initIndex; // Check for the combined file tzdata, which stores the index // and the time zone data together. if(combinedFile.exists() && combinedFile.isFile) { tzFile = File(combinedFile); _enforceValidTZFile(readVal!(char[])(tzFile, 6) == "tzdata"); auto tzDataVersion = readVal!(char[])(tzFile, 6); _enforceValidTZFile(tzDataVersion[5] == '\0'); uint indexOffset = readVal!uint(tzFile); dataOffset = readVal!uint(tzFile); readVal!uint(tzFile); indexEntries = (dataOffset - indexOffset)/indexEntrySize; separate_index = false; } else if(indexFile.exists() && indexFile.isFile) { tzFile = File(indexFile); indexEntries = to!(uint)(tzFile.size/indexEntrySize); separate_index = true; } else throw new DateTimeException(format("Both timezone files %s and %s do not exist.", combinedFile, indexFile)); foreach(Unused; 0 .. indexEntries) { string tzName = to!string(readVal!(char[])(tzFile, 40).ptr); uint tzOffset = readVal!uint(tzFile); readVal!(uint[])(tzFile, 2); initIndex[tzName] = dataOffset + tzOffset; } initIndex.rehash; return initIndex; }()); return _tzIndex; } } /// List of times when the utc offset changes. immutable Transition[] _transitions; /// List of leap second occurrences. immutable LeapSecond[] _leapSeconds; /// Whether DST is in effect for this time zone at any point in time. immutable bool _hasDST; } version(StdDdoc) { /++ $(BLUE This class is Windows-Only.) Represents a time zone from the Windows registry. Unfortunately, Windows does not use the TZ Database. To use the TZ Database, use $(LREF PosixTimeZone) (which reads its information from the TZ Database files on disk) on Windows by providing the TZ Database files and telling $(D PosixTimeZone.getTimeZone) where the directory holding them is. The TZ Database files and Windows' time zone information frequently do not match. Windows has many errors with regards to when DST switches occur (especially for historical dates). Also, the TZ Database files include far more time zones than Windows does. So, for accurate time zone information, use the TZ Database files with $(LREF PosixTimeZone) rather than $(D WindowsTimeZone). However, because $(D WindowsTimeZone) uses Windows system calls to deal with the time, it's far more likely to match the behavior of other Windows programs. Be aware of the differences when selecting a method. $(D WindowsTimeZone) does not exist on Posix systems. To get a $(D WindowsTimeZone), either call $(D WindowsTimeZone.getTimeZone) or call $(D TimeZone.getTimeZone) (which will give a $(LREF PosixTimeZone) on Posix systems and a $(D WindowsTimeZone) on Windows systems). See_Also: $(WEB www.iana.org/time-zones, Home of the TZ Database files) +/ final class WindowsTimeZone : TimeZone { public: /++ Whether this time zone has Daylight Savings Time at any point in time. Note that for some time zone types it may not have DST for current dates but will still return true for $(D hasDST) because the time zone did at some point have DST. +/ @property override bool hasDST() @safe const nothrow; /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in UTC time (i.e. std time) and returns whether DST is in effect in this time zone at the given point in time. Params: stdTime = The UTC time that needs to be checked for DST in this time zone. +/ override bool dstInEffect(long stdTime) @safe const nothrow; /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in UTC time (i.e. std time) and converts it to this time zone's time. Params: stdTime = The UTC time that needs to be adjusted to this time zone's time. +/ override long utcToTZ(long stdTime) @safe const nothrow; /++ Takes the number of hnsecs (100 ns) since midnight, January 1st, 1 A.D. in this time zone's time and converts it to UTC (i.e. std time). Params: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ override long tzToUTC(long adjTime) @safe const nothrow; /++ Returns a $(LREF2 .TimeZone, TimeZone) with the given name per the Windows time zone names. The time zone information is fetched from the Windows registry. See_Also: $(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ Database)
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of Time Zones) Params: name = The TZ Database name of the desired time zone. Throws: $(LREF DateTimeException) if the given time zone could not be found. Example: -------------------- auto tz = TimeZone.getTimeZone("America/Los_Angeles"); -------------------- +/ static immutable(WindowsTimeZone) getTimeZone(string name) @safe; /++ Returns a list of the names of the time zones installed on the system. The list returned by WindowsTimeZone contains the Windows TZ names, not the TZ Database names. However, $(D TimeZone.getinstalledTZNames) will return the TZ Database names which are equivalent to the Windows TZ names. +/ static string[] getInstalledTZNames() @safe; private: version(Windows) {} else alias TIME_ZONE_INFORMATION = void*; static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) nothrow; static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) nothrow; static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) nothrow; this() immutable pure { super("", "", ""); } } } else version(Windows) { final class WindowsTimeZone : TimeZone { import std.format : format; import std.conv : to; import std.algorithm : sort; import std.array : appender; public: @property override bool hasDST() @safe const nothrow { return _tzInfo.DaylightDate.wMonth != 0; } override bool dstInEffect(long stdTime) @safe const nothrow { return _dstInEffect(&_tzInfo, stdTime); } override long utcToTZ(long stdTime) @safe const nothrow { return _utcToTZ(&_tzInfo, stdTime, hasDST); } override long tzToUTC(long adjTime) @safe const nothrow { return _tzToUTC(&_tzInfo, adjTime, hasDST); } static immutable(WindowsTimeZone) getTimeZone(string name) @trusted { import std.utf : toUTF16; scope baseKey = Registry.localMachine.getKey(`Software\Microsoft\Windows NT\CurrentVersion\Time Zones`); foreach (tzKeyName; baseKey.keyNames) { if (tzKeyName != name) continue; scope tzKey = baseKey.getKey(tzKeyName); scope stdVal = tzKey.getValue("Std"); auto stdName = stdVal.value_SZ; scope dstVal = tzKey.getValue("Dlt"); auto dstName = dstVal.value_SZ; scope tziVal = tzKey.getValue("TZI"); auto binVal = tziVal.value_BINARY; assert(binVal.length == REG_TZI_FORMAT.sizeof); auto tziFmt = cast(REG_TZI_FORMAT*)binVal.ptr; TIME_ZONE_INFORMATION tzInfo; auto wstdName = toUTF16(stdName); auto wdstName = toUTF16(dstName); auto wstdNameLen = wstdName.length > 32 ? 32 : wstdName.length; auto wdstNameLen = wdstName.length > 32 ? 32 : wdstName.length; tzInfo.Bias = tziFmt.Bias; tzInfo.StandardName[0 .. wstdNameLen] = wstdName[0 .. wstdNameLen]; tzInfo.StandardName[wstdNameLen .. $] = '\0'; tzInfo.StandardDate = tziFmt.StandardDate; tzInfo.StandardBias = tziFmt.StandardBias; tzInfo.DaylightName[0 .. wdstNameLen] = wdstName[0 .. wdstNameLen]; tzInfo.DaylightName[wdstNameLen .. $] = '\0'; tzInfo.DaylightDate = tziFmt.DaylightDate; tzInfo.DaylightBias = tziFmt.DaylightBias; return new immutable WindowsTimeZone(name, tzInfo); } throw new DateTimeException(format("Failed to find time zone: %s", name)); } static string[] getInstalledTZNames() @trusted { auto timezones = appender!(string[])(); scope baseKey = Registry.localMachine.getKey(`Software\Microsoft\Windows NT\CurrentVersion\Time Zones`); foreach (tzKeyName; baseKey.keyNames) { timezones.put(tzKeyName); } sort(timezones.data); return timezones.data; } unittest { static void testWTZSuccess(string tzName) { scope(failure) writefln("TZName which threw: %s", tzName); WindowsTimeZone.getTimeZone(tzName); } auto tzNames = getInstalledTZNames(); foreach(tzName; tzNames) assertNotThrown!DateTimeException(testWTZSuccess(tzName)); } private: static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) @trusted nothrow { try { if(tzInfo.DaylightDate.wMonth == 0) return false; auto utcDateTime = cast(DateTime)SysTime(stdTime, UTC()); //The limits of what SystemTimeToTzSpecificLocalTime will accept. if(utcDateTime.year < 1601) { if(utcDateTime.month == Month.feb && utcDateTime.day == 29) utcDateTime.day = 28; utcDateTime.year = 1601; } else if(utcDateTime.year > 30_827) { if(utcDateTime.month == Month.feb && utcDateTime.day == 29) utcDateTime.day = 28; utcDateTime.year = 30_827; } //SystemTimeToTzSpecificLocalTime doesn't act correctly at the //beginning or end of the year (bleh). Unless some bizarre time //zone changes DST on January 1st or December 31st, this should //fix the problem. if(utcDateTime.month == Month.jan) { if(utcDateTime.day == 1) utcDateTime.day = 2; } else if(utcDateTime.month == Month.dec && utcDateTime.day == 31) utcDateTime.day = 30; SYSTEMTIME utcTime = void; SYSTEMTIME otherTime = void; utcTime.wYear = utcDateTime.year; utcTime.wMonth = utcDateTime.month; utcTime.wDay = utcDateTime.day; utcTime.wHour = utcDateTime.hour; utcTime.wMinute = utcDateTime.minute; utcTime.wSecond = utcDateTime.second; utcTime.wMilliseconds = 0; immutable result = SystemTimeToTzSpecificLocalTime(cast(TIME_ZONE_INFORMATION*)tzInfo, &utcTime, &otherTime); assert(result); immutable otherDateTime = DateTime(otherTime.wYear, otherTime.wMonth, otherTime.wDay, otherTime.wHour, otherTime.wMinute, otherTime.wSecond); immutable diff = utcDateTime - otherDateTime; immutable minutes = diff.total!"minutes" - tzInfo.Bias; if(minutes == tzInfo.DaylightBias) return true; assert(minutes == tzInfo.StandardBias); return false; } catch(Exception e) assert(0, "DateTime's constructor threw."); } unittest { TIME_ZONE_INFORMATION tzInfo; GetTimeZoneInformation(&tzInfo); foreach(year; [1600, 1601, 30_827, 30_828]) WindowsTimeZone._dstInEffect(&tzInfo, SysTime(DateTime(year, 1, 1)).stdTime); } static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) @safe nothrow { if(hasDST && WindowsTimeZone._dstInEffect(tzInfo, stdTime)) return stdTime - convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.DaylightBias); return stdTime - convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.StandardBias); } static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) @trusted nothrow { if(hasDST) { try { bool dstInEffectForLocalDateTime(DateTime localDateTime) { //The limits of what SystemTimeToTzSpecificLocalTime will accept. if(localDateTime.year < 1601) { if(localDateTime.month == Month.feb && localDateTime.day == 29) localDateTime.day = 28; localDateTime.year = 1601; } else if(localDateTime.year > 30_827) { if(localDateTime.month == Month.feb && localDateTime.day == 29) localDateTime.day = 28; localDateTime.year = 30_827; } //SystemTimeToTzSpecificLocalTime doesn't act correctly at the //beginning or end of the year (bleh). Unless some bizarre time //zone changes DST on January 1st or December 31st, this should //fix the problem. if(localDateTime.month == Month.jan) { if(localDateTime.day == 1) localDateTime.day = 2; } else if(localDateTime.month == Month.dec && localDateTime.day == 31) localDateTime.day = 30; SYSTEMTIME utcTime = void; SYSTEMTIME localTime = void; localTime.wYear = localDateTime.year; localTime.wMonth = localDateTime.month; localTime.wDay = localDateTime.day; localTime.wHour = localDateTime.hour; localTime.wMinute = localDateTime.minute; localTime.wSecond = localDateTime.second; localTime.wMilliseconds = 0; immutable result = TzSpecificLocalTimeToSystemTime(cast(TIME_ZONE_INFORMATION*)tzInfo, &localTime, &utcTime); assert(result); immutable utcDateTime = DateTime(utcTime.wYear, utcTime.wMonth, utcTime.wDay, utcTime.wHour, utcTime.wMinute, utcTime.wSecond); immutable diff = localDateTime - utcDateTime; immutable minutes = -tzInfo.Bias - diff.total!"minutes"; if(minutes == tzInfo.DaylightBias) return true; assert(minutes == tzInfo.StandardBias); return false; } auto localDateTime = cast(DateTime)SysTime(adjTime, UTC()); auto localDateTimeBefore = localDateTime - dur!"hours"(1); auto localDateTimeAfter = localDateTime + dur!"hours"(1); auto dstInEffectNow = dstInEffectForLocalDateTime(localDateTime); auto dstInEffectBefore = dstInEffectForLocalDateTime(localDateTimeBefore); auto dstInEffectAfter = dstInEffectForLocalDateTime(localDateTimeAfter); bool isDST; if(dstInEffectBefore && dstInEffectNow && dstInEffectAfter) isDST = true; else if(!dstInEffectBefore && !dstInEffectNow && !dstInEffectAfter) isDST = false; else if(!dstInEffectBefore && dstInEffectAfter) isDST = false; else if(dstInEffectBefore && !dstInEffectAfter) isDST = dstInEffectNow; else assert(0, "Bad Logic."); if(isDST) return adjTime + convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.DaylightBias); } catch(Exception e) assert(0, "SysTime's constructor threw."); } return adjTime + convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.StandardBias); } this(string name, TIME_ZONE_INFORMATION tzInfo) @safe immutable pure { super(name, to!string(tzInfo.StandardName.ptr), to!string(tzInfo.DaylightName.ptr)); _tzInfo = tzInfo; } TIME_ZONE_INFORMATION _tzInfo; } } version(StdDdoc) { /++ $(BLUE This function is Posix-Only.) Sets the local time zone on Posix systems with the TZ Database name by setting the TZ environment variable. Unfortunately, there is no way to do it on Windows using the TZ Database name, so this function only exists on Posix systems. +/ void setTZEnvVar(string tzDatabaseName) @safe nothrow; /++ $(BLUE This function is Posix-Only.) Clears the TZ environment variable. +/ void clearTZEnvVar() @safe nothrow; } else version(Posix) { void setTZEnvVar(string tzDatabaseName) @trusted nothrow { import std.internal.cstring : tempCString; import std.path : asNormalizedPath, chainPath; import core.sys.posix.stdlib : setenv; import core.sys.posix.time : tzset; version(Android) auto value = asNormalizedPath(tzDatabaseName); else auto value = asNormalizedPath(chainPath(PosixTimeZone.defaultTZDatabaseDir, tzDatabaseName)); setenv("TZ", value.tempCString(), 1); tzset(); } void clearTZEnvVar() @trusted nothrow { import core.sys.posix.stdlib : unsetenv; import core.sys.posix.time : tzset; unsetenv("TZ"); tzset(); } } /++ Provides the conversions between the IANA time zone database time zone names (which POSIX systems use) and the time zone names that Windows uses. Windows uses a different set of time zone names than the IANA time zone database does, and how they correspond to one another changes over time (particularly when Microsoft updates Windows). $(WEB http://unicode.org/cldr/data/common/supplemental/windowsZones.xml, windowsZones.xml) provides the current conversions (which may or may not match up with what's on a particular Windows box depending on how up-to-date it is), and parseTZConversions reads in those conversions from windowsZones.xml so that a D program can use those conversions. However, it should be noted that the time zone information on Windows is frequently less accurate than that in the IANA time zone database, and if someone really wants accurate time zone information, they should use the IANA time zone database files with $(LREF PosixTimeZone) on Windows rather than $(LREF WindowsTimeZone), whereas $(LREF WindowsTimeZone) makes more sense when trying to match what Windows will think the time is in a specific time zone. Also, the IANA time zone database has a lot more time zones than Windows does. Params: windowsZonesXMLFileText The text from $(WEB http://unicode.org/cldr/data/common/supplemental/windowsZones.xml, windowsZones.xml) Throws: Exception if there is an error while parsing the given XML. -------------------- // Parse the conversions from a local file. auto text = std.file.readText("path/to/windowsZones.xml"); auto conversions = parseTZConversions(text); // Alternatively, grab the XML file from the web at runtime // and parse it so that it's guaranteed to be up-to-date, though // that has the downside that the code needs to worry about the // site being down or unicode.org changing the URL. auto url = "http://unicode.org/cldr/data/common/supplemental/windowsZones.xml"; auto conversions2 = parseTZConversions(std.net.curl.get(url)); -------------------- +/ struct TZConversions { /++ The key is the Windows time zone name, and the value is a list of IANA TZ database names which are close (currently only ever one, but it allows for multiple in case it's ever necessary). +/ string[][string] toWindows; /++ The key is the IANA time zone database name, and the value is a list of Windows time zone names which are close (usually only one, but it could be multiple). +/ string[][string] fromWindows; } /++ ditto +/ TZConversions parseTZConversions(string windowsZonesXMLText) @safe pure { // This is a bit hacky, since it doesn't properly read XML, but it avoids // needing to pull in std.xml (which we're theoretically replacing at some // point anyway. import std.algorithm : find, sort, uniq; import std.array : array, split; import std.string : lineSplitter; string[][string] win2Nix; string[][string] nix2Win; immutable f1 = ` line = line.find(f1); if(line.empty) continue; line = line[f1.length .. $]; auto next = line.find('"'); enforce(!next.empty, "Error parsing. Text does not appear to be from windowsZones.xml"); auto win = line[0 .. $ - next.length]; line = next.find(f2); enforce(!line.empty, "Error parsing. Text does not appear to be from windowsZones.xml"); line = line[f2.length .. $]; next = line.find('"'); enforce(!next.empty, "Error parsing. Text does not appear to be from windowsZones.xml"); auto nixes = line[0 .. $ - next.length].split(); if(auto n = win in win2Nix) *n ~= nixes; else win2Nix[win] = nixes; foreach(nix; nixes) { if(auto w = nix in nix2Win) *w ~= win; else nix2Win[nix] = [win]; } } foreach(key, ref value; nix2Win) value = value.sort().uniq().array(); foreach(key, ref value; win2Nix) value = value.sort().uniq().array(); return TZConversions(nix2Win, win2Nix); } unittest { import std.algorithm; // Reduced text from http://unicode.org/cldr/data/common/supplemental/windowsZones.xml auto sampleFileText = ` `; auto tzConversions = parseTZConversions(sampleFileText); assert(tzConversions.toWindows.length == 15); assert(tzConversions.toWindows["America/Anchorage"] == ["Alaskan Standard Time"]); assert(tzConversions.toWindows["America/Juneau"] == ["Alaskan Standard Time"]); assert(tzConversions.toWindows["America/Nome"] == ["Alaskan Standard Time"]); assert(tzConversions.toWindows["America/Sitka"] == ["Alaskan Standard Time"]); assert(tzConversions.toWindows["America/Yakutat"] == ["Alaskan Standard Time"]); assert(tzConversions.toWindows["Etc/GMT+10"] == ["Hawaiian Standard Time"]); assert(tzConversions.toWindows["Etc/GMT+11"] == ["UTC-11"]); assert(tzConversions.toWindows["Etc/GMT+12"] == ["Dateline Standard Time"]); assert(tzConversions.toWindows["Pacific/Honolulu"] == ["Hawaiian Standard Time"]); assert(tzConversions.toWindows["Pacific/Johnston"] == ["Hawaiian Standard Time"]); assert(tzConversions.toWindows["Pacific/Midway"] == ["UTC-11"]); assert(tzConversions.toWindows["Pacific/Niue"] == ["UTC-11"]); assert(tzConversions.toWindows["Pacific/Pago_Pago"] == ["UTC-11"]); assert(tzConversions.toWindows["Pacific/Rarotonga"] == ["Hawaiian Standard Time"]); assert(tzConversions.toWindows["Pacific/Tahiti"] == ["Hawaiian Standard Time"]); assert(tzConversions.fromWindows.length == 4); assert(tzConversions.fromWindows["Alaskan Standard Time"] == ["America/Anchorage", "America/Juneau", "America/Nome", "America/Sitka", "America/Yakutat"]); assert(tzConversions.fromWindows["Dateline Standard Time"] == ["Etc/GMT+12"]); assert(tzConversions.fromWindows["Hawaiian Standard Time"] == ["Etc/GMT+10", "Pacific/Honolulu", "Pacific/Johnston", "Pacific/Rarotonga", "Pacific/Tahiti"]); assert(tzConversions.fromWindows["UTC-11"] == ["Etc/GMT+11", "Pacific/Midway", "Pacific/Niue", "Pacific/Pago_Pago"]); foreach(key, value; tzConversions.fromWindows) { assert(value.isSorted, key); assert(equal(value.uniq(), value), key); } } /++ $(RED Please use $(LREF parseTZConversions) instead. This function will be deprecated in 2.072, because Microsoft changes their time zones too often for us to compile the conversions into Phobos and have them be properly up-to-date.) Converts the given TZ Database name to the corresponding Windows time zone name. Note that in a few cases, a TZ Dabatase name corresponds to two different Windows time zone names. So, while in most cases converting from one to the other and back again will result in the same time zone name started with, in a few case, it'll get a different name. Also, there are far more TZ Database names than Windows time zones, so some of the more exotic TZ Database names don't have corresponding Windows time zone names. Returns null if the given time zone name cannot be converted. See_Also: $(WEB unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html, Windows <-> TZ Database Name Conversion Table) Params: tzName = The TZ Database name to convert. +/ string tzDatabaseNameToWindowsTZName(string tzName) @safe pure nothrow @nogc { switch(tzName) { case "Africa/Abidjan": return "Greenwich Standard Time"; case "Africa/Accra": return "Greenwich Standard Time"; case "Africa/Addis_Ababa": return "E. Africa Standard Time"; case "Africa/Algiers": return "W. Central Africa Standard Time"; case "Africa/Asmera": return "E. Africa Standard Time"; case "Africa/Bamako": return "Greenwich Standard Time"; case "Africa/Bangui": return "W. Central Africa Standard Time"; case "Africa/Banjul": return "Greenwich Standard Time"; case "Africa/Bissau": return "Greenwich Standard Time"; case "Africa/Blantyre": return "South Africa Standard Time"; case "Africa/Brazzaville": return "W. Central Africa Standard Time"; case "Africa/Bujumbura": return "South Africa Standard Time"; case "Africa/Cairo": return "Egypt Standard Time"; case "Africa/Casablanca": return "Morocco Standard Time"; case "Africa/Ceuta": return "Romance Standard Time"; case "Africa/Conakry": return "Greenwich Standard Time"; case "Africa/Dakar": return "Greenwich Standard Time"; case "Africa/Dar_es_Salaam": return "E. Africa Standard Time"; case "Africa/Djibouti": return "E. Africa Standard Time"; case "Africa/Douala": return "W. Central Africa Standard Time"; case "Africa/El_Aaiun": return "Morocco Standard Time"; case "Africa/Freetown": return "Greenwich Standard Time"; case "Africa/Gaborone": return "South Africa Standard Time"; case "Africa/Harare": return "South Africa Standard Time"; case "Africa/Johannesburg": return "South Africa Standard Time"; case "Africa/Juba": return "E. Africa Standard Time"; case "Africa/Kampala": return "E. Africa Standard Time"; case "Africa/Khartoum": return "E. Africa Standard Time"; case "Africa/Kigali": return "South Africa Standard Time"; case "Africa/Kinshasa": return "W. Central Africa Standard Time"; case "Africa/Lagos": return "W. Central Africa Standard Time"; case "Africa/Libreville": return "W. Central Africa Standard Time"; case "Africa/Lome": return "Greenwich Standard Time"; case "Africa/Luanda": return "W. Central Africa Standard Time"; case "Africa/Lubumbashi": return "South Africa Standard Time"; case "Africa/Lusaka": return "South Africa Standard Time"; case "Africa/Malabo": return "W. Central Africa Standard Time"; case "Africa/Maputo": return "South Africa Standard Time"; case "Africa/Maseru": return "South Africa Standard Time"; case "Africa/Mbabane": return "South Africa Standard Time"; case "Africa/Mogadishu": return "E. Africa Standard Time"; case "Africa/Monrovia": return "Greenwich Standard Time"; case "Africa/Nairobi": return "E. Africa Standard Time"; case "Africa/Ndjamena": return "W. Central Africa Standard Time"; case "Africa/Niamey": return "W. Central Africa Standard Time"; case "Africa/Nouakchott": return "Greenwich Standard Time"; case "Africa/Ouagadougou": return "Greenwich Standard Time"; case "Africa/Porto-Novo": return "W. Central Africa Standard Time"; case "Africa/Sao_Tome": return "Greenwich Standard Time"; case "Africa/Tripoli": return "Libya Standard Time"; case "Africa/Tunis": return "W. Central Africa Standard Time"; case "Africa/Windhoek": return "Namibia Standard Time"; case "America/Anchorage": return "Alaskan Standard Time"; case "America/Anguilla": return "SA Western Standard Time"; case "America/Antigua": return "SA Western Standard Time"; case "America/Araguaina": return "SA Eastern Standard Time"; case "America/Argentina/La_Rioja": return "Argentina Standard Time"; case "America/Argentina/Rio_Gallegos": return "Argentina Standard Time"; case "America/Argentina/Salta": return "Argentina Standard Time"; case "America/Argentina/San_Juan": return "Argentina Standard Time"; case "America/Argentina/San_Luis": return "Argentina Standard Time"; case "America/Argentina/Tucuman": return "Argentina Standard Time"; case "America/Argentina/Ushuaia": return "Argentina Standard Time"; case "America/Aruba": return "SA Western Standard Time"; case "America/Asuncion": return "Paraguay Standard Time"; case "America/Bahia": return "Bahia Standard Time"; case "America/Bahia_Banderas": return "Central Standard Time (Mexico)"; case "America/Barbados": return "SA Western Standard Time"; case "America/Belem": return "SA Eastern Standard Time"; case "America/Belize": return "Central America Standard Time"; case "America/Blanc-Sablon": return "SA Western Standard Time"; case "America/Boa_Vista": return "SA Western Standard Time"; case "America/Bogota": return "SA Pacific Standard Time"; case "America/Boise": return "Mountain Standard Time"; case "America/Buenos_Aires": return "Argentina Standard Time"; case "America/Cambridge_Bay": return "Mountain Standard Time"; case "America/Campo_Grande": return "Central Brazilian Standard Time"; case "America/Cancun": return "Eastern Standard Time (Mexico)"; case "America/Caracas": return "Venezuela Standard Time"; case "America/Catamarca": return "Argentina Standard Time"; case "America/Cayenne": return "SA Eastern Standard Time"; case "America/Cayman": return "SA Pacific Standard Time"; case "America/Chicago": return "Central Standard Time"; case "America/Chihuahua": return "Mountain Standard Time (Mexico)"; case "America/Coral_Harbour": return "SA Pacific Standard Time"; case "America/Cordoba": return "Argentina Standard Time"; case "America/Costa_Rica": return "Central America Standard Time"; case "America/Creston": return "US Mountain Standard Time"; case "America/Cuiaba": return "Central Brazilian Standard Time"; case "America/Curacao": return "SA Western Standard Time"; case "America/Danmarkshavn": return "UTC"; case "America/Dawson": return "Pacific Standard Time"; case "America/Dawson_Creek": return "US Mountain Standard Time"; case "America/Denver": return "Mountain Standard Time"; case "America/Detroit": return "Eastern Standard Time"; case "America/Dominica": return "SA Western Standard Time"; case "America/Edmonton": return "Mountain Standard Time"; case "America/Eirunepe": return "SA Pacific Standard Time"; case "America/El_Salvador": return "Central America Standard Time"; case "America/Fortaleza": return "SA Eastern Standard Time"; case "America/Glace_Bay": return "Atlantic Standard Time"; case "America/Godthab": return "Greenland Standard Time"; case "America/Goose_Bay": return "Atlantic Standard Time"; case "America/Grand_Turk": return "SA Western Standard Time"; case "America/Grenada": return "SA Western Standard Time"; case "America/Guadeloupe": return "SA Western Standard Time"; case "America/Guatemala": return "Central America Standard Time"; case "America/Guayaquil": return "SA Pacific Standard Time"; case "America/Guyana": return "SA Western Standard Time"; case "America/Halifax": return "Atlantic Standard Time"; case "America/Havana": return "Eastern Standard Time"; case "America/Hermosillo": return "US Mountain Standard Time"; case "America/Indiana/Knox": return "Central Standard Time"; case "America/Indiana/Marengo": return "US Eastern Standard Time"; case "America/Indiana/Petersburg": return "Eastern Standard Time"; case "America/Indiana/Tell_City": return "Central Standard Time"; case "America/Indiana/Vevay": return "US Eastern Standard Time"; case "America/Indiana/Vincennes": return "Eastern Standard Time"; case "America/Indiana/Winamac": return "Eastern Standard Time"; case "America/Indianapolis": return "US Eastern Standard Time"; case "America/Inuvik": return "Mountain Standard Time"; case "America/Iqaluit": return "Eastern Standard Time"; case "America/Jamaica": return "SA Pacific Standard Time"; case "America/Jujuy": return "Argentina Standard Time"; case "America/Juneau": return "Alaskan Standard Time"; case "America/Kentucky/Monticello": return "Eastern Standard Time"; case "America/Kralendijk": return "SA Western Standard Time"; case "America/La_Paz": return "SA Western Standard Time"; case "America/Lima": return "SA Pacific Standard Time"; case "America/Los_Angeles": return "Pacific Standard Time"; case "America/Louisville": return "Eastern Standard Time"; case "America/Lower_Princes": return "SA Western Standard Time"; case "America/Maceio": return "SA Eastern Standard Time"; case "America/Managua": return "Central America Standard Time"; case "America/Manaus": return "SA Western Standard Time"; case "America/Marigot": return "SA Western Standard Time"; case "America/Martinique": return "SA Western Standard Time"; case "America/Matamoros": return "Central Standard Time"; case "America/Mazatlan": return "Mountain Standard Time (Mexico)"; case "America/Mendoza": return "Argentina Standard Time"; case "America/Menominee": return "Central Standard Time"; case "America/Merida": return "Central Standard Time (Mexico)"; case "America/Mexico_City": return "Central Standard Time (Mexico)"; case "America/Moncton": return "Atlantic Standard Time"; case "America/Monterrey": return "Central Standard Time (Mexico)"; case "America/Montevideo": return "Montevideo Standard Time"; case "America/Montreal": return "Eastern Standard Time"; case "America/Montserrat": return "SA Western Standard Time"; case "America/Nassau": return "Eastern Standard Time"; case "America/New_York": return "Eastern Standard Time"; case "America/Nipigon": return "Eastern Standard Time"; case "America/Nome": return "Alaskan Standard Time"; case "America/Noronha": return "UTC-02"; case "America/North_Dakota/Beulah": return "Central Standard Time"; case "America/North_Dakota/Center": return "Central Standard Time"; case "America/North_Dakota/New_Salem": return "Central Standard Time"; case "America/Ojinaga": return "Mountain Standard Time"; case "America/Panama": return "SA Pacific Standard Time"; case "America/Pangnirtung": return "Eastern Standard Time"; case "America/Paramaribo": return "SA Eastern Standard Time"; case "America/Phoenix": return "US Mountain Standard Time"; case "America/Port-au-Prince": return "Haiti Standard Time"; case "America/Port_of_Spain": return "SA Western Standard Time"; case "America/Porto_Velho": return "SA Western Standard Time"; case "America/Puerto_Rico": return "SA Western Standard Time"; case "America/Rainy_River": return "Central Standard Time"; case "America/Rankin_Inlet": return "Central Standard Time"; case "America/Recife": return "SA Eastern Standard Time"; case "America/Regina": return "Canada Central Standard Time"; case "America/Resolute": return "Central Standard Time"; case "America/Rio_Branco": return "SA Pacific Standard Time"; case "America/Santa_Isabel": return "Pacific Standard Time (Mexico)"; case "America/Santarem": return "SA Eastern Standard Time"; case "America/Santiago": return "Pacific SA Standard Time"; case "America/Santo_Domingo": return "SA Western Standard Time"; case "America/Sao_Paulo": return "E. South America Standard Time"; case "America/Scoresbysund": return "Azores Standard Time"; case "America/Sitka": return "Alaskan Standard Time"; case "America/St_Barthelemy": return "SA Western Standard Time"; case "America/St_Johns": return "Newfoundland Standard Time"; case "America/St_Kitts": return "SA Western Standard Time"; case "America/St_Lucia": return "SA Western Standard Time"; case "America/St_Thomas": return "SA Western Standard Time"; case "America/St_Vincent": return "SA Western Standard Time"; case "America/Swift_Current": return "Canada Central Standard Time"; case "America/Tegucigalpa": return "Central America Standard Time"; case "America/Thule": return "Atlantic Standard Time"; case "America/Thunder_Bay": return "Eastern Standard Time"; case "America/Tijuana": return "Pacific Standard Time"; case "America/Toronto": return "Eastern Standard Time"; case "America/Tortola": return "SA Western Standard Time"; case "America/Vancouver": return "Pacific Standard Time"; case "America/Whitehorse": return "Pacific Standard Time"; case "America/Winnipeg": return "Central Standard Time"; case "America/Yakutat": return "Alaskan Standard Time"; case "America/Yellowknife": return "Mountain Standard Time"; case "Antarctica/Casey": return "W. Australia Standard Time"; case "Antarctica/Davis": return "SE Asia Standard Time"; case "Antarctica/DumontDUrville": return "West Pacific Standard Time"; case "Antarctica/Macquarie": return "Central Pacific Standard Time"; case "Antarctica/Mawson": return "West Asia Standard Time"; case "Antarctica/McMurdo": return "New Zealand Standard Time"; case "Antarctica/Palmer": return "Pacific SA Standard Time"; case "Antarctica/Rothera": return "SA Eastern Standard Time"; case "Antarctica/Syowa": return "E. Africa Standard Time"; case "Antarctica/Vostok": return "Central Asia Standard Time"; case "Arctic/Longyearbyen": return "W. Europe Standard Time"; case "Asia/Aden": return "Arab Standard Time"; case "Asia/Almaty": return "Central Asia Standard Time"; case "Asia/Amman": return "Jordan Standard Time"; case "Asia/Anadyr": return "Russia Time Zone 11"; case "Asia/Aqtau": return "West Asia Standard Time"; case "Asia/Aqtobe": return "West Asia Standard Time"; case "Asia/Ashgabat": return "West Asia Standard Time"; case "Asia/Baghdad": return "Arabic Standard Time"; case "Asia/Bahrain": return "Arab Standard Time"; case "Asia/Baku": return "Azerbaijan Standard Time"; case "Asia/Bangkok": return "SE Asia Standard Time"; case "Asia/Barnaul": return "Altai Standard Time"; case "Asia/Beirut": return "Middle East Standard Time"; case "Asia/Bishkek": return "Central Asia Standard Time"; case "Asia/Brunei": return "Singapore Standard Time"; case "Asia/Calcutta": return "India Standard Time"; case "Asia/Chita": return "Transbaikal Standard Time"; case "Asia/Choibalsan": return "Ulaanbaatar Standard Time"; case "Asia/Colombo": return "Sri Lanka Standard Time"; case "Asia/Damascus": return "Syria Standard Time"; case "Asia/Dhaka": return "Bangladesh Standard Time"; case "Asia/Dili": return "Tokyo Standard Time"; case "Asia/Dubai": return "Arabian Standard Time"; case "Asia/Dushanbe": return "West Asia Standard Time"; case "Asia/Hong_Kong": return "China Standard Time"; case "Asia/Hovd": return "SE Asia Standard Time"; case "Asia/Irkutsk": return "North Asia East Standard Time"; case "Asia/Jakarta": return "SE Asia Standard Time"; case "Asia/Jayapura": return "Tokyo Standard Time"; case "Asia/Jerusalem": return "Israel Standard Time"; case "Asia/Kabul": return "Afghanistan Standard Time"; case "Asia/Kamchatka": return "Russia Time Zone 11"; case "Asia/Karachi": return "Pakistan Standard Time"; case "Asia/Katmandu": return "Nepal Standard Time"; case "Asia/Khandyga": return "Yakutsk Standard Time"; case "Asia/Krasnoyarsk": return "North Asia Standard Time"; case "Asia/Kuala_Lumpur": return "Singapore Standard Time"; case "Asia/Kuching": return "Singapore Standard Time"; case "Asia/Kuwait": return "Arab Standard Time"; case "Asia/Macau": return "China Standard Time"; case "Asia/Magadan": return "Magadan Standard Time"; case "Asia/Makassar": return "Singapore Standard Time"; case "Asia/Manila": return "Singapore Standard Time"; case "Asia/Muscat": return "Arabian Standard Time"; case "Asia/Nicosia": return "GTB Standard Time"; case "Asia/Novokuznetsk": return "North Asia Standard Time"; case "Asia/Novosibirsk": return "N. Central Asia Standard Time"; case "Asia/Omsk": return "N. Central Asia Standard Time"; case "Asia/Oral": return "West Asia Standard Time"; case "Asia/Phnom_Penh": return "SE Asia Standard Time"; case "Asia/Pontianak": return "SE Asia Standard Time"; case "Asia/Pyongyang": return "North Korea Standard Time"; case "Asia/Qatar": return "Arab Standard Time"; case "Asia/Qyzylorda": return "Central Asia Standard Time"; case "Asia/Rangoon": return "Myanmar Standard Time"; case "Asia/Riyadh": return "Arab Standard Time"; case "Asia/Saigon": return "SE Asia Standard Time"; case "Asia/Sakhalin": return "Sakhalin Standard Time"; case "Asia/Samarkand": return "West Asia Standard Time"; case "Asia/Seoul": return "Korea Standard Time"; case "Asia/Shanghai": return "China Standard Time"; case "Asia/Singapore": return "Singapore Standard Time"; case "Asia/Srednekolymsk": return "Russia Time Zone 10"; case "Asia/Taipei": return "Taipei Standard Time"; case "Asia/Tashkent": return "West Asia Standard Time"; case "Asia/Tbilisi": return "Georgian Standard Time"; case "Asia/Tehran": return "Iran Standard Time"; case "Asia/Thimphu": return "Bangladesh Standard Time"; case "Asia/Tokyo": return "Tokyo Standard Time"; case "Asia/Ulaanbaatar": return "Ulaanbaatar Standard Time"; case "Asia/Urumqi": return "Central Asia Standard Time"; case "Asia/Ust-Nera": return "Vladivostok Standard Time"; case "Asia/Vientiane": return "SE Asia Standard Time"; case "Asia/Vladivostok": return "Vladivostok Standard Time"; case "Asia/Yakutsk": return "Yakutsk Standard Time"; case "Asia/Yekaterinburg": return "Ekaterinburg Standard Time"; case "Asia/Yerevan": return "Caucasus Standard Time"; case "Atlantic/Azores": return "Azores Standard Time"; case "Atlantic/Bermuda": return "Atlantic Standard Time"; case "Atlantic/Canary": return "GMT Standard Time"; case "Atlantic/Cape_Verde": return "Cape Verde Standard Time"; case "Atlantic/Faeroe": return "GMT Standard Time"; case "Atlantic/Madeira": return "GMT Standard Time"; case "Atlantic/Reykjavik": return "Greenwich Standard Time"; case "Atlantic/South_Georgia": return "UTC-02"; case "Atlantic/St_Helena": return "Greenwich Standard Time"; case "Atlantic/Stanley": return "SA Eastern Standard Time"; case "Australia/Adelaide": return "Cen. Australia Standard Time"; case "Australia/Brisbane": return "E. Australia Standard Time"; case "Australia/Broken_Hill": return "Cen. Australia Standard Time"; case "Australia/Currie": return "Tasmania Standard Time"; case "Australia/Darwin": return "AUS Central Standard Time"; case "Australia/Hobart": return "Tasmania Standard Time"; case "Australia/Lindeman": return "E. Australia Standard Time"; case "Australia/Melbourne": return "AUS Eastern Standard Time"; case "Australia/Perth": return "W. Australia Standard Time"; case "Australia/Sydney": return "AUS Eastern Standard Time"; case "CST6CDT": return "Central Standard Time"; case "EST5EDT": return "Eastern Standard Time"; case "Etc/GMT": return "UTC"; case "Etc/GMT+1": return "Cape Verde Standard Time"; case "Etc/GMT+10": return "Hawaiian Standard Time"; case "Etc/GMT+11": return "UTC-11"; case "Etc/GMT+12": return "Dateline Standard Time"; case "Etc/GMT+2": return "UTC-02"; case "Etc/GMT+3": return "SA Eastern Standard Time"; case "Etc/GMT+4": return "SA Western Standard Time"; case "Etc/GMT+5": return "SA Pacific Standard Time"; case "Etc/GMT+6": return "Central America Standard Time"; case "Etc/GMT+7": return "US Mountain Standard Time"; case "Etc/GMT-1": return "W. Central Africa Standard Time"; case "Etc/GMT-10": return "West Pacific Standard Time"; case "Etc/GMT-11": return "Central Pacific Standard Time"; case "Etc/GMT-12": return "UTC+12"; case "Etc/GMT-13": return "Tonga Standard Time"; case "Etc/GMT-14": return "Line Islands Standard Time"; case "Etc/GMT-2": return "South Africa Standard Time"; case "Etc/GMT-3": return "E. Africa Standard Time"; case "Etc/GMT-4": return "Arabian Standard Time"; case "Etc/GMT-5": return "West Asia Standard Time"; case "Etc/GMT-6": return "Central Asia Standard Time"; case "Etc/GMT-7": return "SE Asia Standard Time"; case "Etc/GMT-8": return "Singapore Standard Time"; case "Etc/GMT-9": return "Tokyo Standard Time"; case "Europe/Amsterdam": return "W. Europe Standard Time"; case "Europe/Andorra": return "W. Europe Standard Time"; case "Europe/Astrakhan": return "Astrakhan Standard Time"; case "Europe/Athens": return "GTB Standard Time"; case "Europe/Belgrade": return "Central Europe Standard Time"; case "Europe/Berlin": return "W. Europe Standard Time"; case "Europe/Bratislava": return "Central Europe Standard Time"; case "Europe/Brussels": return "Romance Standard Time"; case "Europe/Bucharest": return "GTB Standard Time"; case "Europe/Budapest": return "Central Europe Standard Time"; case "Europe/Busingen": return "W. Europe Standard Time"; case "Europe/Chisinau": return "GTB Standard Time"; case "Europe/Copenhagen": return "Romance Standard Time"; case "Europe/Dublin": return "GMT Standard Time"; case "Europe/Gibraltar": return "W. Europe Standard Time"; case "Europe/Guernsey": return "GMT Standard Time"; case "Europe/Helsinki": return "FLE Standard Time"; case "Europe/Isle_of_Man": return "GMT Standard Time"; case "Europe/Istanbul": return "Turkey Standard Time"; case "Europe/Jersey": return "GMT Standard Time"; case "Europe/Kaliningrad": return "Kaliningrad Standard Time"; case "Europe/Kiev": return "FLE Standard Time"; case "Europe/Lisbon": return "GMT Standard Time"; case "Europe/Ljubljana": return "Central Europe Standard Time"; case "Europe/London": return "GMT Standard Time"; case "Europe/Luxembourg": return "W. Europe Standard Time"; case "Europe/Madrid": return "Romance Standard Time"; case "Europe/Malta": return "W. Europe Standard Time"; case "Europe/Mariehamn": return "FLE Standard Time"; case "Europe/Minsk": return "Belarus Standard Time"; case "Europe/Monaco": return "W. Europe Standard Time"; case "Europe/Moscow": return "Russian Standard Time"; case "Europe/Oslo": return "W. Europe Standard Time"; case "Europe/Paris": return "Romance Standard Time"; case "Europe/Podgorica": return "Central Europe Standard Time"; case "Europe/Prague": return "Central Europe Standard Time"; case "Europe/Riga": return "FLE Standard Time"; case "Europe/Rome": return "W. Europe Standard Time"; case "Europe/Samara": return "Russia Time Zone 3"; case "Europe/San_Marino": return "W. Europe Standard Time"; case "Europe/Sarajevo": return "Central European Standard Time"; case "Europe/Simferopol": return "Russian Standard Time"; case "Europe/Skopje": return "Central European Standard Time"; case "Europe/Sofia": return "FLE Standard Time"; case "Europe/Stockholm": return "W. Europe Standard Time"; case "Europe/Tallinn": return "FLE Standard Time"; case "Europe/Tirane": return "Central Europe Standard Time"; case "Europe/Uzhgorod": return "FLE Standard Time"; case "Europe/Vaduz": return "W. Europe Standard Time"; case "Europe/Vatican": return "W. Europe Standard Time"; case "Europe/Vienna": return "W. Europe Standard Time"; case "Europe/Vilnius": return "FLE Standard Time"; case "Europe/Volgograd": return "Russian Standard Time"; case "Europe/Warsaw": return "Central European Standard Time"; case "Europe/Zagreb": return "Central European Standard Time"; case "Europe/Zaporozhye": return "FLE Standard Time"; case "Europe/Zurich": return "W. Europe Standard Time"; case "Indian/Antananarivo": return "E. Africa Standard Time"; case "Indian/Chagos": return "Central Asia Standard Time"; case "Indian/Christmas": return "SE Asia Standard Time"; case "Indian/Cocos": return "Myanmar Standard Time"; case "Indian/Comoro": return "E. Africa Standard Time"; case "Indian/Kerguelen": return "West Asia Standard Time"; case "Indian/Mahe": return "Mauritius Standard Time"; case "Indian/Maldives": return "West Asia Standard Time"; case "Indian/Mauritius": return "Mauritius Standard Time"; case "Indian/Mayotte": return "E. Africa Standard Time"; case "Indian/Reunion": return "Mauritius Standard Time"; case "MST7MDT": return "Mountain Standard Time"; case "PST8PDT": return "Pacific Standard Time"; case "Pacific/Apia": return "Samoa Standard Time"; case "Pacific/Auckland": return "New Zealand Standard Time"; case "Pacific/Bougainville": return "Central Pacific Standard Time"; case "Pacific/Easter": return "Easter Island Standard Time"; case "Pacific/Efate": return "Central Pacific Standard Time"; case "Pacific/Enderbury": return "Tonga Standard Time"; case "Pacific/Fakaofo": return "Tonga Standard Time"; case "Pacific/Fiji": return "Fiji Standard Time"; case "Pacific/Funafuti": return "UTC+12"; case "Pacific/Galapagos": return "Central America Standard Time"; case "Pacific/Guadalcanal": return "Central Pacific Standard Time"; case "Pacific/Guam": return "West Pacific Standard Time"; case "Pacific/Honolulu": return "Hawaiian Standard Time"; case "Pacific/Johnston": return "Hawaiian Standard Time"; case "Pacific/Kiritimati": return "Line Islands Standard Time"; case "Pacific/Kosrae": return "Central Pacific Standard Time"; case "Pacific/Kwajalein": return "UTC+12"; case "Pacific/Majuro": return "UTC+12"; case "Pacific/Midway": return "UTC-11"; case "Pacific/Nauru": return "UTC+12"; case "Pacific/Niue": return "UTC-11"; case "Pacific/Noumea": return "Central Pacific Standard Time"; case "Pacific/Pago_Pago": return "UTC-11"; case "Pacific/Palau": return "Tokyo Standard Time"; case "Pacific/Ponape": return "Central Pacific Standard Time"; case "Pacific/Port_Moresby": return "West Pacific Standard Time"; case "Pacific/Rarotonga": return "Hawaiian Standard Time"; case "Pacific/Saipan": return "West Pacific Standard Time"; case "Pacific/Tahiti": return "Hawaiian Standard Time"; case "Pacific/Tarawa": return "UTC+12"; case "Pacific/Tongatapu": return "Tonga Standard Time"; case "Pacific/Truk": return "West Pacific Standard Time"; case "Pacific/Wake": return "UTC+12"; case "Pacific/Wallis": return "UTC+12"; default: return null; } } version(Windows) version(UpdateWindowsTZTranslations) unittest { import std.stdio : stderr; foreach(tzName; TimeZone.getInstalledTZNames()) { if (tzDatabaseNameToWindowsTZName(tzName) is null) stderr.writeln("Missing TZName to Windows translation: ", tzName); } } /++ $(RED Please use $(LREF parseTZConversions) instead. This function will be deprecated in 2.072, because Microsoft changes their time zones too often for us to compile the conversions into Phobos and have them be properly up-to-date.) Converts the given Windows time zone name to a corresponding TZ Database name. Returns null if the given time zone name cannot be converted. See_Also: $(WEB unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html, Windows <-> TZ Database Name Conversion Table) Params: tzName = The TZ Database name to convert. +/ string windowsTZNameToTZDatabaseName(string tzName) @safe pure nothrow @nogc { switch(tzName) { case "AUS Central Standard Time": return "Australia/Darwin"; case "AUS Eastern Standard Time": return "Australia/Sydney"; case "Afghanistan Standard Time": return "Asia/Kabul"; case "Haiti Standard Time": return "America/Port-au-Prince"; case "Alaskan Standard Time": return "America/Anchorage"; case "Altai Standard Time": return "Asia/Barnaul"; case "Arab Standard Time": return "Asia/Riyadh"; case "Arabian Standard Time": return "Asia/Dubai"; case "Arabic Standard Time": return "Asia/Baghdad"; case "Argentina Standard Time": return "America/Buenos_Aires"; case "Astrakhan Standard Time": return "Europe/Astrakhan"; case "Atlantic Standard Time": return "America/Halifax"; case "Azerbaijan Standard Time": return "Asia/Baku"; case "Azores Standard Time": return "Atlantic/Azores"; case "Bahia Standard Time": return "America/Bahia"; case "Bangladesh Standard Time": return "Asia/Dhaka"; case "Belarus Standard Time": return "Europe/Minsk"; case "Canada Central Standard Time": return "America/Regina"; case "Cape Verde Standard Time": return "Atlantic/Cape_Verde"; case "Caucasus Standard Time": return "Asia/Yerevan"; case "Cen. Australia Standard Time": return "Australia/Adelaide"; case "Central America Standard Time": return "America/Guatemala"; case "Central Asia Standard Time": return "Asia/Almaty"; case "Central Brazilian Standard Time": return "America/Cuiaba"; case "Central Europe Standard Time": return "Europe/Budapest"; case "Central European Standard Time": return "Europe/Warsaw"; case "Central Pacific Standard Time": return "Pacific/Guadalcanal"; case "Central Standard Time": return "America/Chicago"; case "Central Standard Time (Mexico)": return "America/Mexico_City"; case "China Standard Time": return "Asia/Shanghai"; case "Dateline Standard Time": return "Etc/GMT+12"; case "E. Africa Standard Time": return "Africa/Nairobi"; case "E. Australia Standard Time": return "Australia/Brisbane"; // This doesn't appear to be in the current stuff from MS, but the autotester // is failing without it (probably because its time zone data hasn't been // updated recently enough). case "E. Europe Standard Time": return "Europe/Minsk"; case "E. South America Standard Time": return "America/Sao_Paulo"; case "Easter Island Standard Time": return "Pacific/Easter"; case "Eastern Standard Time": return "America/New_York"; case "Eastern Standard Time (Mexico)": return "America/Cancun"; case "Egypt Standard Time": return "Africa/Cairo"; case "Ekaterinburg Standard Time": return "Asia/Yekaterinburg"; case "FLE Standard Time": return "Europe/Kiev"; case "Fiji Standard Time": return "Pacific/Fiji"; case "GMT Standard Time": return "Europe/London"; case "GTB Standard Time": return "Europe/Athens"; case "Georgian Standard Time": return "Asia/Tbilisi"; case "Greenland Standard Time": return "America/Godthab"; case "Greenwich Standard Time": return "Atlantic/Reykjavik"; case "Hawaiian Standard Time": return "Pacific/Honolulu"; case "India Standard Time": return "Asia/Calcutta"; case "Iran Standard Time": return "Asia/Tehran"; case "Israel Standard Time": return "Asia/Jerusalem"; case "Jordan Standard Time": return "Asia/Amman"; case "Kaliningrad Standard Time": return "Europe/Kaliningrad"; // Same as with E. Europe Standard Time. case "Kamchatka Standard Time": return "Asia/Kamchatka"; case "Korea Standard Time": return "Asia/Seoul"; case "Libya Standard Time": return "Africa/Tripoli"; case "Line Islands Standard Time": return "Pacific/Kiritimati"; case "Magadan Standard Time": return "Asia/Magadan"; case "Mauritius Standard Time": return "Indian/Mauritius"; // Same as with E. Europe Standard Time. case "Mexico Standard Time": return "America/Mexico_City"; // Same as with E. Europe Standard Time. case "Mexico Standard Time 2": return "America/Chihuahua"; // Same as with E. Europe Standard Time. case "Mid-Atlantic Standard Time": return "Etc/GMT+2"; case "Middle East Standard Time": return "Asia/Beirut"; case "Montevideo Standard Time": return "America/Montevideo"; case "Morocco Standard Time": return "Africa/Casablanca"; case "Mountain Standard Time": return "America/Denver"; case "Mountain Standard Time (Mexico)": return "America/Chihuahua"; case "Myanmar Standard Time": return "Asia/Rangoon"; case "N. Central Asia Standard Time": return "Asia/Novosibirsk"; case "Namibia Standard Time": return "Africa/Windhoek"; case "Nepal Standard Time": return "Asia/Katmandu"; case "New Zealand Standard Time": return "Pacific/Auckland"; case "Newfoundland Standard Time": return "America/St_Johns"; case "North Asia East Standard Time": return "Asia/Irkutsk"; case "North Asia Standard Time": return "Asia/Krasnoyarsk"; case "North Korea Standard Time": return "Asia/Pyongyang"; case "Pacific SA Standard Time": return "America/Santiago"; case "Pacific Standard Time": return "America/Los_Angeles"; case "Pacific Standard Time (Mexico)": return "America/Santa_Isabel"; case "Pakistan Standard Time": return "Asia/Karachi"; case "Paraguay Standard Time": return "America/Asuncion"; case "Romance Standard Time": return "Europe/Paris"; case "Russia Time Zone 10": return "Asia/Srednekolymsk"; case "Russia Time Zone 11": return "Asia/Anadyr"; case "Russia Time Zone 3": return "Europe/Samara"; case "Russian Standard Time": return "Europe/Moscow"; case "SA Eastern Standard Time": return "America/Cayenne"; case "SA Pacific Standard Time": return "America/Bogota"; case "SA Western Standard Time": return "America/La_Paz"; case "SE Asia Standard Time": return "Asia/Bangkok"; case "Sakhalin Standard Time": return "Asia/Sakhalin"; case "Samoa Standard Time": return "Pacific/Apia"; case "Singapore Standard Time": return "Asia/Singapore"; case "South Africa Standard Time": return "Africa/Johannesburg"; case "Sri Lanka Standard Time": return "Asia/Colombo"; case "Syria Standard Time": return "Asia/Damascus"; case "Taipei Standard Time": return "Asia/Taipei"; case "Tasmania Standard Time": return "Australia/Hobart"; case "Tokyo Standard Time": return "Asia/Tokyo"; case "Tonga Standard Time": return "Pacific/Tongatapu"; case "Transbaikal Standard Time": return "Asia/Chita"; case "Turkey Standard Time": return "Europe/Istanbul"; case "US Eastern Standard Time": return "America/Indianapolis"; case "US Mountain Standard Time": return "America/Phoenix"; case "UTC": return "Etc/GMT"; case "UTC+12": return "Etc/GMT-12"; case "UTC-02": return "Etc/GMT+2"; case "UTC-11": return "Etc/GMT+11"; case "Ulaanbaatar Standard Time": return "Asia/Ulaanbaatar"; case "Venezuela Standard Time": return "America/Caracas"; case "Vladivostok Standard Time": return "Asia/Vladivostok"; case "W. Australia Standard Time": return "Australia/Perth"; case "W. Central Africa Standard Time": return "Africa/Lagos"; case "W. Europe Standard Time": return "Europe/Berlin"; case "West Asia Standard Time": return "Asia/Tashkent"; case "West Pacific Standard Time": return "Pacific/Port_Moresby"; case "Yakutsk Standard Time": return "Asia/Yakutsk"; default: return null; } } version(Windows) version(UpdateWindowsTZTranslations) unittest { import std.stdio : stderr; foreach(winName; WindowsTimeZone.getInstalledTZNames()) { if (windowsTZNameToTZDatabaseName(winName) is null) stderr.writeln("Missing Windows to TZName translation: ", winName); } } //============================================================================== // Section with StopWatch and Benchmark Code. //============================================================================== /++ $(D StopWatch) measures time as precisely as possible. This class uses a high-performance counter. On Windows systems, it uses $(D QueryPerformanceCounter), and on Posix systems, it uses $(D clock_gettime) if available, and $(D gettimeofday) otherwise. But the precision of $(D StopWatch) differs from system to system. It is impossible to for it to be the same from system to system since the precision of the system clock varies from system to system, and other system-dependent and situation-dependent stuff (such as the overhead of a context switch between threads) can also affect $(D StopWatch)'s accuracy. +/ @safe struct StopWatch { public: /++ Auto start with constructor. +/ this(AutoStart autostart) { if(autostart) start(); } @safe unittest { auto sw = StopWatch(AutoStart.yes); sw.stop(); } /// bool opEquals(const StopWatch rhs) const pure nothrow { return opEquals(rhs); } /// ditto bool opEquals(const ref StopWatch rhs) const pure nothrow { return _timeStart == rhs._timeStart && _timeMeasured == rhs._timeMeasured; } /++ Resets the stop watch. +/ void reset() { if(_flagStarted) { // Set current system time if StopWatch is measuring. _timeStart = TickDuration.currSystemTick; } else { // Set zero if StopWatch is not measuring. _timeStart.length = 0; } _timeMeasured.length = 0; } /// @safe unittest { StopWatch sw; sw.start(); sw.stop(); sw.reset(); assert(sw.peek().to!("seconds", real)() == 0); } /++ Starts the stop watch. +/ void start() { assert(!_flagStarted); _flagStarted = true; _timeStart = TickDuration.currSystemTick; } @trusted unittest { StopWatch sw; sw.start(); auto t1 = sw.peek(); bool doublestart = true; try sw.start(); catch(AssertError e) doublestart = false; assert(!doublestart); sw.stop(); assert((t1 - sw.peek()).to!("seconds", real)() <= 0); } /++ Stops the stop watch. +/ void stop() { assert(_flagStarted); _flagStarted = false; _timeMeasured += TickDuration.currSystemTick - _timeStart; } @trusted unittest { StopWatch sw; sw.start(); sw.stop(); auto t1 = sw.peek(); bool doublestop = true; try sw.stop(); catch(AssertError e) doublestop = false; assert(!doublestop); assert((t1 - sw.peek()).to!("seconds", real)() == 0); } /++ Peek at the amount of time which has passed since the stop watch was started. +/ TickDuration peek() const { if(_flagStarted) return TickDuration.currSystemTick - _timeStart + _timeMeasured; return _timeMeasured; } @safe unittest { StopWatch sw; sw.start(); auto t1 = sw.peek(); sw.stop(); auto t2 = sw.peek(); auto t3 = sw.peek(); assert(t1 <= t2); assert(t2 == t3); } /++ Set the amount of time which has been measured since the stop watch was started. +/ void setMeasured(TickDuration d) { reset(); _timeMeasured = d; } @safe unittest { StopWatch sw; TickDuration t0; t0.length = 100; sw.setMeasured(t0); auto t1 = sw.peek(); assert(t0 == t1); } /++ Confirm whether this stopwatch is measuring time. +/ bool running() @property const pure nothrow { return _flagStarted; } @safe unittest { StopWatch sw1; assert(!sw1.running); sw1.start(); assert(sw1.running); sw1.stop(); assert(!sw1.running); StopWatch sw2 = AutoStart.yes; assert(sw2.running); sw2.stop(); assert(!sw2.running); sw2.start(); assert(sw2.running); } private: // true if observing. bool _flagStarted = false; // TickDuration at the time of StopWatch starting measurement. TickDuration _timeStart; // Total time that StopWatch ran. TickDuration _timeMeasured; } /// @safe unittest { void writeln(S...)(S args){} static void bar() {} StopWatch sw; enum n = 100; TickDuration[n] times; TickDuration last = TickDuration.from!"seconds"(0); foreach(i; 0..n) { sw.start(); //start/resume mesuring. foreach(unused; 0..1_000_000) bar(); sw.stop(); //stop/pause measuring. //Return value of peek() after having stopped are the always same. writeln((i + 1) * 1_000_000, " times done, lap time: ", sw.peek().msecs, "[ms]"); times[i] = sw.peek() - last; last = sw.peek(); } real sum = 0; // To get the number of seconds, // use properties of TickDuration. // (seconds, msecs, usecs, hnsecs) foreach(t; times) sum += t.hnsecs; writeln("Average time: ", sum/n, " hnsecs"); } /++ Benchmarks code for speed assessment and comparison. Params: fun = aliases of callable objects (e.g. function names). Each should take no arguments. n = The number of times each function is to be executed. Returns: The amount of time (as a $(CXREF time, TickDuration)) that it took to call each function $(D n) times. The first value is the length of time that it took to call $(D fun[0]) $(D n) times. The second value is the length of time it took to call $(D fun[1]) $(D n) times. Etc. Note that casting the TickDurations to $(CXREF time, Duration)s will make the results easier to deal with (and it may change in the future that benchmark will return an array of Durations rather than TickDurations). See_Also: $(LREF measureTime) +/ TickDuration[fun.length] benchmark(fun...)(uint n) { TickDuration[fun.length] result; StopWatch sw; sw.start(); foreach(i, unused; fun) { sw.reset(); foreach(j; 0 .. n) fun[i](); result[i] = sw.peek(); } return result; } /// unittest { import std.conv : to; int a; void f0() {} void f1() {auto b = a;} void f2() {auto b = to!string(a);} auto r = benchmark!(f0, f1, f2)(10_000); auto f0Result = to!Duration(r[0]); // time f0 took to run 10,000 times auto f1Result = to!Duration(r[1]); // time f1 took to run 10,000 times auto f2Result = to!Duration(r[2]); // time f2 took to run 10,000 times } @safe unittest { int a; void f0() {} //void f1() {auto b = to!(string)(a);} void f2() {auto b = (a);} auto r = benchmark!(f0, f2)(100); } /++ Return value of benchmark with two functions comparing. +/ @safe struct ComparingBenchmarkResult { /++ Evaluation value This returns the evaluation value of performance as the ratio of baseFunc's time over targetFunc's time. If performance is high, this returns a high value. +/ @property real point() const pure nothrow { return _baseTime.length / cast(const real)_targetTime.length; } /++ The time required of the base function +/ @property public TickDuration baseTime() const pure nothrow { return _baseTime; } /++ The time required of the target function +/ @property public TickDuration targetTime() const pure nothrow { return _targetTime; } private: this(TickDuration baseTime, TickDuration targetTime) pure nothrow { _baseTime = baseTime; _targetTime = targetTime; } TickDuration _baseTime; TickDuration _targetTime; } /++ Benchmark with two functions comparing. Params: baseFunc = The function to become the base of the speed. targetFunc = The function that wants to measure speed. times = The number of times each function is to be executed. +/ ComparingBenchmarkResult comparingBenchmark(alias baseFunc, alias targetFunc, int times = 0xfff)() { auto t = benchmark!(baseFunc, targetFunc)(times); return ComparingBenchmarkResult(t[0], t[1]); } /// @safe unittest { void f1x() {} void f2x() {} @safe void f1o() {} @safe void f2o() {} auto b1 = comparingBenchmark!(f1o, f2o, 1)(); // OK //writeln(b1.point); } //Bug# 8450 unittest { @safe void safeFunc() {} @trusted void trustFunc() {} @system void sysFunc() {} auto safeResult = comparingBenchmark!((){safeFunc();}, (){safeFunc();})(); auto trustResult = comparingBenchmark!((){trustFunc();}, (){trustFunc();})(); auto sysResult = comparingBenchmark!((){sysFunc();}, (){sysFunc();})(); auto mixedResult1 = comparingBenchmark!((){safeFunc();}, (){trustFunc();})(); auto mixedResult2 = comparingBenchmark!((){trustFunc();}, (){sysFunc();})(); auto mixedResult3 = comparingBenchmark!((){safeFunc();}, (){sysFunc();})(); } //============================================================================== // Section with public helper functions and templates. //============================================================================== /++ Whether the given type defines all of the necessary functions for it to function as a time point. 1. $(D T) must define a static property named $(D min) which is the smallest value of $(D T) as $(Unqual!T). 2. $(D T) must define a static property named $(D max) which is the largest value of $(D T) as $(Unqual!T). 3. $(D T) must define an $(D opBinary) for addition and subtraction that accepts $(CXREF time, Duration) and returns $(D Unqual!T). 4. $(D T) must define an $(D opOpAssign) for addition and subtraction that accepts $(CXREF time, Duration) and returns $(D ref Unqual!T). 5. $(D T) must define a $(D opBinary) for subtraction which accepts $(D T) and returns returns $(CXREF time, Duration). +/ template isTimePoint(T) { enum isTimePoint = hasMin && hasMax && hasOverloadedOpBinaryWithDuration && hasOverloadedOpAssignWithDuration && hasOverloadedOpBinaryWithSelf && !is(U == Duration); private: alias U = Unqual!T; enum hasMin = __traits(hasMember, T, "min") && is(typeof(T.min) == U) && is(typeof({static assert(__traits(isStaticFunction, T.min));})); enum hasMax = __traits(hasMember, T, "max") && is(typeof(T.max) == U) && is(typeof({static assert(__traits(isStaticFunction, T.max));})); enum hasOverloadedOpBinaryWithDuration = is(typeof(T.init + Duration.init) == U) && is(typeof(T.init - Duration.init) == U); enum hasOverloadedOpAssignWithDuration = is(typeof(U.init += Duration.init) == U) && is(typeof(U.init -= Duration.init) == U) && is(typeof( { // Until the overload with TickDuration is removed, this is ambiguous. //alias add = U.opOpAssign!"+"; //alias sub = U.opOpAssign!"-"; U u; auto ref add() { return u += Duration.init; } auto ref sub() { return u -= Duration.init; } alias FA = FunctionAttribute; static assert((functionAttributes!add & FA.ref_) != 0); static assert((functionAttributes!sub & FA.ref_) != 0); })); enum hasOverloadedOpBinaryWithSelf = is(typeof(T.init - T.init) == Duration); } /// unittest { static assert(isTimePoint!Date); static assert(isTimePoint!DateTime); static assert(isTimePoint!SysTime); static assert(isTimePoint!TimeOfDay); static assert(!isTimePoint!int); static assert(!isTimePoint!Duration); static assert(!isTimePoint!(Interval!SysTime)); } unittest { import std.meta : AliasSeq; foreach(TP; AliasSeq!(Date, DateTime, SysTime, TimeOfDay)) { static assert(isTimePoint!(const TP), TP.stringof); static assert(isTimePoint!(immutable TP), TP.stringof); } foreach(T; AliasSeq!(float, string, Duration, Interval!Date, PosInfInterval!Date, NegInfInterval!Date)) static assert(!isTimePoint!T, T.stringof); } /++ Whether the given Gregorian Year is a leap year. Params: year = The year to to be tested. +/ static bool yearIsLeapYear(int year) @safe pure nothrow { if(year % 400 == 0) return true; if(year % 100 == 0) return false; return year % 4 == 0; } unittest { import std.format : format; foreach(year; [1, 2, 3, 5, 6, 7, 100, 200, 300, 500, 600, 700, 1998, 1999, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011]) { assert(!yearIsLeapYear(year), format("year: %s.", year)); assert(!yearIsLeapYear(-year), format("year: %s.", year)); } foreach(year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) { assert(yearIsLeapYear(year), format("year: %s.", year)); assert(yearIsLeapYear(-year), format("year: %s.", year)); } } /++ Converts from unix time (which uses midnight, January 1st, 1970 UTC as its epoch and seconds as its units) to "std time" (which uses midnight, January 1st, 1 A.D. UTC and hnsecs as its units). The C standard does not specify the representation of time_t, so it is implementation defined. On POSIX systems, unix time is equivalent to time_t, but that's not necessarily true on other systems (e.g. it is not true for the Digital Mars C runtime). So, be careful when using unix time with C functions on non-POSIX systems. "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO 8601 and is what $(LREF SysTime) uses internally. However, holding the time as an integer in hnescs since that epoch technically isn't actually part of the standard, much as it's based on it, so the name "std time" isn't particularly good, but there isn't an official name for it. C# uses "ticks" for the same thing, but they aren't actually clock ticks, and the term "ticks" $(I is) used for actual clock ticks for $(CXREF time, MonoTime), so it didn't make sense to use the term ticks here. So, for better or worse, std.datetime uses the term "std time" for this. Params: unixTime = The unix time to convert. See_Also: SysTime.fromUnixTime +/ long unixTimeToStdTime(long unixTime) @safe pure nothrow { return 621_355_968_000_000_000L + convert!("seconds", "hnsecs")(unixTime); } /// unittest { // Midnight, January 1st, 1970 assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L); assert(SysTime(unixTimeToStdTime(0)) == SysTime(DateTime(1970, 1, 1), UTC())); assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L); assert(SysTime(unixTimeToStdTime(int.max)) == SysTime(DateTime(2038, 1, 19, 3, 14, 07), UTC())); assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L); assert(SysTime(unixTimeToStdTime(-127_127)) == SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC())); } unittest { // Midnight, January 2nd, 1970 assert(unixTimeToStdTime(86_400) == 621_355_968_000_000_000L + 864_000_000_000L); // Midnight, December 31st, 1969 assert(unixTimeToStdTime(-86_400) == 621_355_968_000_000_000L - 864_000_000_000L); assert(unixTimeToStdTime(0) == (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs"); assert(unixTimeToStdTime(0) == (DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs"); foreach(dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)]) assert(unixTimeToStdTime((dt - DateTime(1970, 1, 1)).total!"seconds") == (dt - DateTime.init).total!"hnsecs"); } /++ Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch and hnsecs as its units) to unix time (which uses midnight, January 1st, 1970 UTC as its epoch and seconds as its units). The C standard does not specify the representation of time_t, so it is implementation defined. On POSIX systems, unix time is equivalent to time_t, but that's not necessarily true on other systems (e.g. it is not true for the Digital Mars C runtime). So, be careful when using unix time with C functions on non-POSIX systems. "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO 8601 and is what $(LREF SysTime) uses internally. However, holding the time as an integer in hnescs since that epoch technically isn't actually part of the standard, much as it's based on it, so the name "std time" isn't particularly good, but there isn't an official name for it. C# uses "ticks" for the same thing, but they aren't actually clock ticks, and the term "ticks" $(I is) used for actual clock ticks for $(CXREF time, MonoTime), so it didn't make sense to use the term ticks here. So, for better or worse, std.datetime uses the term "std time" for this. By default, the return type is time_t (which is normally an alias for int on 32-bit systems and long on 64-bit systems), but if a different size is required than either int or long can be passed as a template argument to get the desired size. If the return type is int, and the result can't fit in an int, then the closest value that can be held in 32 bits will be used (so $(D int.max) if it goes over and $(D int.min) if it goes under). However, no attempt is made to deal with integer overflow if the return type is long. Params: T = The return type (int or long). It defaults to time_t, which is normally 32 bits on a 32-bit system and 64 bits on a 64-bit system. stdTime = The std time to convert. Returns: A signed integer representing the unix time which is equivalent to the given std time. See_Also: SysTime.toUnixTime +/ T stdTimeToUnixTime(T = time_t)(long stdTime) @safe pure nothrow if(is(T == int) || is(T == long)) { immutable unixTime = convert!("hnsecs", "seconds")(stdTime - 621_355_968_000_000_000L); static assert(is(time_t == int) || is(time_t == long), "Currently, std.datetime only supports systems where time_t is int or long"); static if(is(T == long)) return unixTime; else static if(is(T == int)) { if(unixTime > int.max) return int.max; return unixTime < int.min ? int.min : cast(int)unixTime; } else static assert(0, "Bug in template constraint. Only int and long allowed."); } /// unittest { // Midnight, January 1st, 1970 UTC assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0); // 2038-01-19 03:14:07 UTC assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max); } unittest { enum unixEpochAsStdTime = (Date(1970, 1, 1) - Date.init).total!"hnsecs"; assert(stdTimeToUnixTime(unixEpochAsStdTime) == 0); //Midnight, January 1st, 1970 assert(stdTimeToUnixTime(unixEpochAsStdTime + 864_000_000_000L) == 86_400); //Midnight, January 2nd, 1970 assert(stdTimeToUnixTime(unixEpochAsStdTime - 864_000_000_000L) == -86_400); //Midnight, December 31st, 1969 assert(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs") == 0); assert(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs") == 0); foreach(dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)]) assert(stdTimeToUnixTime((dt - DateTime.init).total!"hnsecs") == (dt - DateTime(1970, 1, 1)).total!"seconds"); enum max = convert!("seconds", "hnsecs")(int.max); enum min = convert!("seconds", "hnsecs")(int.min); enum one = convert!("seconds", "hnsecs")(1); assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max) == int.max); assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max) == int.max); assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + one) == int.max + 1L); assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + one) == int.max); assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + 9_999_999) == int.max); assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + 9_999_999) == int.max); assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min) == int.min); assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min) == int.min); assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - one) == int.min - 1L); assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - one) == int.min); assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - 9_999_999) == int.min); assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - 9_999_999) == int.min); } version(StdDdoc) { version(Windows) {} else { alias SYSTEMTIME = void*; alias FILETIME = void*; } /++ $(BLUE This function is Windows-Only.) Converts a $(D SYSTEMTIME) struct to a $(LREF SysTime). Params: st = The $(D SYSTEMTIME) struct to convert. tz = The time zone that the time in the $(D SYSTEMTIME) struct is assumed to be (if the $(D SYSTEMTIME) was supplied by a Windows system call, the $(D SYSTEMTIME) will either be in local time or UTC, depending on the call). Throws: $(LREF DateTimeException) if the given $(D SYSTEMTIME) will not fit in a $(LREF SysTime), which is highly unlikely to happen given that $(D SysTime.max) is in 29,228 A.D. and the maximum $(D SYSTEMTIME) is in 30,827 A.D. +/ SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe; /++ $(BLUE This function is Windows-Only.) Converts a $(LREF SysTime) to a $(D SYSTEMTIME) struct. The $(D SYSTEMTIME) which is returned will be set using the given $(LREF SysTime)'s time zone, so to get the $(D SYSTEMTIME) in UTC, set the $(LREF SysTime)'s time zone to UTC. Params: sysTime = The $(LREF SysTime) to convert. Throws: $(LREF DateTimeException) if the given $(LREF SysTime) will not fit in a $(D SYSTEMTIME). This will only happen if the $(LREF SysTime)'s date is prior to 1601 A.D. +/ SYSTEMTIME SysTimeToSYSTEMTIME(in SysTime sysTime) @safe; /++ $(BLUE This function is Windows-Only.) Converts a $(D FILETIME) struct to the number of hnsecs since midnight, January 1st, 1 A.D. Params: ft = The $(D FILETIME) struct to convert. Throws: $(LREF DateTimeException) if the given $(D FILETIME) cannot be represented as the return value. +/ long FILETIMEToStdTime(const FILETIME* ft) @safe; /++ $(BLUE This function is Windows-Only.) Converts a $(D FILETIME) struct to a $(LREF SysTime). Params: ft = The $(D FILETIME) struct to convert. tz = The time zone that the $(LREF SysTime) will be in ($(D FILETIME)s are in UTC). Throws: $(LREF DateTimeException) if the given $(D FILETIME) will not fit in a $(LREF SysTime). +/ SysTime FILETIMEToSysTime(const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe; /++ $(BLUE This function is Windows-Only.) Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a $(D FILETIME) struct. Params: stdTime = The number of hnsecs since midnight, January 1st, 1 A.D. UTC. Throws: $(LREF DateTimeException) if the given value will not fit in a $(D FILETIME). +/ FILETIME stdTimeToFILETIME(long stdTime) @safe; /++ $(BLUE This function is Windows-Only.) Converts a $(LREF SysTime) to a $(D FILETIME) struct. $(D FILETIME)s are always in UTC. Params: sysTime = The $(LREF SysTime) to convert. Throws: $(LREF DateTimeException) if the given $(LREF SysTime) will not fit in a $(D FILETIME). +/ FILETIME SysTimeToFILETIME(SysTime sysTime) @safe; } else version(Windows) { SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe { const max = SysTime.max; static void throwLaterThanMax() { throw new DateTimeException("The given SYSTEMTIME is for a date greater than SysTime.max."); } if(st.wYear > max.year) throwLaterThanMax(); else if(st.wYear == max.year) { if(st.wMonth > max.month) throwLaterThanMax(); else if(st.wMonth == max.month) { if(st.wDay > max.day) throwLaterThanMax(); else if(st.wDay == max.day) { if(st.wHour > max.hour) throwLaterThanMax(); else if(st.wHour == max.hour) { if(st.wMinute > max.minute) throwLaterThanMax(); else if(st.wMinute == max.minute) { if(st.wSecond > max.second) throwLaterThanMax(); else if(st.wSecond == max.second) { if(st.wMilliseconds > max.fracSecs.total!"msecs") throwLaterThanMax(); } } } } } } auto dt = DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); return SysTime(dt, msecs(st.wMilliseconds), tz); } unittest { auto sysTime = Clock.currTime(UTC()); SYSTEMTIME st = void; GetSystemTime(&st); auto converted = SYSTEMTIMEToSysTime(&st, UTC()); assert(abs((converted - sysTime)) <= dur!"seconds"(2)); } SYSTEMTIME SysTimeToSYSTEMTIME(in SysTime sysTime) @safe { immutable dt = cast(DateTime)sysTime; if(dt.year < 1601) throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601."); SYSTEMTIME st; st.wYear = dt.year; st.wMonth = dt.month; st.wDayOfWeek = dt.dayOfWeek; st.wDay = dt.day; st.wHour = dt.hour; st.wMinute = dt.minute; st.wSecond = dt.second; st.wMilliseconds = cast(ushort)sysTime.fracSecs.total!"msecs"; return st; } unittest { SYSTEMTIME st = void; GetSystemTime(&st); auto sysTime = SYSTEMTIMEToSysTime(&st, UTC()); SYSTEMTIME result = SysTimeToSYSTEMTIME(sysTime); assert(st.wYear == result.wYear); assert(st.wMonth == result.wMonth); assert(st.wDayOfWeek == result.wDayOfWeek); assert(st.wDay == result.wDay); assert(st.wHour == result.wHour); assert(st.wMinute == result.wMinute); assert(st.wSecond == result.wSecond); assert(st.wMilliseconds == result.wMilliseconds); } private enum hnsecsFrom1601 = 504_911_232_000_000_000L; long FILETIMEToStdTime(const FILETIME* ft) @safe { ULARGE_INTEGER ul; ul.HighPart = ft.dwHighDateTime; ul.LowPart = ft.dwLowDateTime; ulong tempHNSecs = ul.QuadPart; if(tempHNSecs > long.max - hnsecsFrom1601) throw new DateTimeException("The given FILETIME cannot be represented as a stdTime value."); return cast(long)tempHNSecs + hnsecsFrom1601; } SysTime FILETIMEToSysTime(const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe { auto sysTime = SysTime(FILETIMEToStdTime(ft), UTC()); sysTime.timezone = tz; return sysTime; } unittest { auto sysTime = Clock.currTime(UTC()); SYSTEMTIME st = void; GetSystemTime(&st); FILETIME ft = void; SystemTimeToFileTime(&st, &ft); auto converted = FILETIMEToSysTime(&ft); assert(abs((converted - sysTime)) <= dur!"seconds"(2)); } FILETIME stdTimeToFILETIME(long stdTime) @safe { if(stdTime < hnsecsFrom1601) throw new DateTimeException("The given stdTime value cannot be represented as a FILETIME."); ULARGE_INTEGER ul; ul.QuadPart = cast(ulong)stdTime - hnsecsFrom1601; FILETIME ft; ft.dwHighDateTime = ul.HighPart; ft.dwLowDateTime = ul.LowPart; return ft; } FILETIME SysTimeToFILETIME(SysTime sysTime) @safe { return stdTimeToFILETIME(sysTime.stdTime); } unittest { SYSTEMTIME st = void; GetSystemTime(&st); FILETIME ft = void; SystemTimeToFileTime(&st, &ft); auto sysTime = FILETIMEToSysTime(&ft, UTC()); FILETIME result = SysTimeToFILETIME(sysTime); assert(ft.dwLowDateTime == result.dwLowDateTime); assert(ft.dwHighDateTime == result.dwHighDateTime); } } /++ Type representing the DOS file date/time format. +/ alias DosFileTime = uint; /++ Converts from DOS file date/time to $(LREF SysTime). Params: dft = The DOS file time to convert. tz = The time zone which the DOS file time is assumed to be in. Throws: $(LREF DateTimeException) if the $(D DosFileTime) is invalid. +/ SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime()) @safe { uint dt = cast(uint)dft; if(dt == 0) throw new DateTimeException("Invalid DosFileTime."); int year = ((dt >> 25) & 0x7F) + 1980; int month = ((dt >> 21) & 0x0F); // 1..12 int dayOfMonth = ((dt >> 16) & 0x1F); // 1..31 int hour = (dt >> 11) & 0x1F; // 0..23 int minute = (dt >> 5) & 0x3F; // 0..59 int second = (dt << 1) & 0x3E; // 0..58 (in 2 second increments) try return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz); catch(DateTimeException dte) throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte); } unittest { assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0))); assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58))); assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44))); } /++ Converts from $(LREF SysTime) to DOS file date/time. Params: sysTime = The $(LREF SysTime) to convert. Throws: $(LREF DateTimeException) if the given $(LREF SysTime) cannot be converted to a $(D DosFileTime). +/ DosFileTime SysTimeToDosFileTime(SysTime sysTime) @safe { auto dateTime = cast(DateTime)sysTime; if(dateTime.year < 1980) throw new DateTimeException("DOS File Times cannot hold dates prior to 1980."); if(dateTime.year > 2107) throw new DateTimeException("DOS File Times cannot hold dates past 2107."); uint retval = 0; retval = (dateTime.year - 1980) << 25; retval |= (dateTime.month & 0x0F) << 21; retval |= (dateTime.day & 0x1F) << 16; retval |= (dateTime.hour & 0x1F) << 11; retval |= (dateTime.minute & 0x3F) << 5; retval |= (dateTime.second >> 1) & 0x1F; return cast(DosFileTime)retval; } unittest { assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000); assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101); assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456); } /++ The given array of $(D char) or random-access range of $(D char) or $(D ubyte) is expected to be in the format specified in $(WEB tools.ietf.org/html/rfc5322, RFC 5322) section 3.3 with the grammar rule $(I date-time). It is the date-time format commonly used in internet messages such as e-mail and HTTP. The corresponding $(LREF SysTime) will be returned. RFC 822 was the original spec (hence the function's name), whereas RFC 5322 is the current spec. The day of the week is ignored beyond verifying that it's a valid day of the week, as the day of the week can be inferred from the date. It is not checked whether the given day of the week matches the actual day of the week of the given date (though it is technically invalid per the spec if the day of the week doesn't match the actual day of the week of the given date). If the time zone is $(D "-0000") (or considered to be equivalent to $(D "-0000") by section 4.3 of the spec), a $(LREF SimpleTimeZone) with a utc offset of $(D 0) is used rather than $(LREF UTC), whereas $(D "+0000") uses $(LREF UTC). Note that because $(LREF SysTime) does not currently support having a second value of 60 (as is sometimes done for leap seconds), if the date-time value does have a value of 60 for the seconds, it is treated as 59. The one area in which this function violates RFC 5322 is that it accepts $(D "\n") in folding whitespace in the place of $(D "\r\n"), because the HTTP spec requires it. Throws: $(LREF DateTimeException) if the given string doesn't follow the grammar for a date-time field or if the resulting $(LREF SysTime) is invalid. +/ SysTime parseRFC822DateTime()(in char[] value) @safe { import std.string : representation; return parseRFC822DateTime(value.representation); } /++ Ditto +/ SysTime parseRFC822DateTime(R)(R value) @safe if(isRandomAccessRange!R && hasSlicing!R && hasLength!R && (is(Unqual!(ElementType!R) == char) || is(Unqual!(ElementType!R) == ubyte))) { import std.functional : not; import std.ascii : isDigit, isAlpha, isPrintable; import std.typecons : Rebindable; import std.string : capitalize, format; import std.conv : to; import std.algorithm : find, all; void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__) { value = _stripCFWS(valueBefore); if(value.length < minLen) throw new DateTimeException("date-time value too short", __FILE__, line); } stripAndCheckLen(value, "7Dec1200:00A".length); static if(isArray!R && (is(ElementEncodingType!R == char) || is(ElementEncodingType!R == ubyte))) { static string sliceAsString(R str) @trusted { return cast(string)str; } } else { char[4] temp; char[] sliceAsString(R str) @trusted { size_t i = 0; foreach(c; str) temp[i++] = cast(char)c; return temp[0 .. str.length]; } } // day-of-week if(isAlpha(value[0])) { auto dowStr = sliceAsString(value[0 .. 3]); switch(dowStr) { foreach(dow; EnumMembers!DayOfWeek) { enum dowC = capitalize(to!string(dow)); case dowC: goto afterDoW; } default: throw new DateTimeException(format("Invalid day-of-week: %s", dowStr)); } afterDoW: stripAndCheckLen(value[3 .. value.length], ",7Dec1200:00A".length); if(value[0] != ',') throw new DateTimeException("day-of-week missing comma"); stripAndCheckLen(value[1 .. value.length], "7Dec1200:00A".length); } // day immutable digits = isDigit(value[1]) ? 2 : 1; immutable day = _convDigits!short(value[0 .. digits]); if(day == -1) throw new DateTimeException("Invalid day"); stripAndCheckLen(value[digits .. value.length], "Dec1200:00A".length); // month Month month; { auto monStr = sliceAsString(value[0 .. 3]); switch(monStr) { foreach(mon; EnumMembers!Month) { enum monC = capitalize(to!string(mon)); case monC: { month = mon; goto afterMon; } } default: throw new DateTimeException(format("Invalid month: %s", monStr)); } afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length); } // year auto found = value[2 .. value.length].find!(not!(std.ascii.isDigit))(); size_t yearLen = value.length - found.length; if(found.length == 0) throw new DateTimeException("Invalid year"); if(found[0] == ':') yearLen -= 2; auto year = _convDigits!short(value[0 .. yearLen]); if(year < 1900) { if(year == -1) throw new DateTimeException("Invalid year"); if(yearLen < 4) { if(yearLen == 3) year += 1900; else if(yearLen == 2) year += year < 50 ? 2000 : 1900; else throw new DateTimeException("Invalid year. Too few digits."); } else throw new DateTimeException("Invalid year. Cannot be earlier than 1900."); } stripAndCheckLen(value[yearLen .. value.length], "00:00A".length); // hour immutable hour = _convDigits!short(value[0 .. 2]); stripAndCheckLen(value[2 .. value.length], ":00A".length); if(value[0] != ':') throw new DateTimeException("Invalid hour"); stripAndCheckLen(value[1 .. value.length], "00A".length); // minute immutable minute = _convDigits!short(value[0 .. 2]); stripAndCheckLen(value[2 .. value.length], "A".length); // second short second; if(value[0] == ':') { stripAndCheckLen(value[1 .. value.length], "00A".length); second = _convDigits!short(value[0 .. 2]); // this is just if/until SysTime is sorted out to fully support leap seconds if(second == 60) second = 59; stripAndCheckLen(value[2 .. value.length], "A".length); } immutable(TimeZone) parseTZ(int sign) { if(value.length < 5) throw new DateTimeException("Invalid timezone"); immutable zoneHours = _convDigits!short(value[1 .. 3]); immutable zoneMinutes = _convDigits!short(value[3 .. 5]); if(zoneHours == -1 || zoneMinutes == -1 || zoneMinutes > 59) throw new DateTimeException("Invalid timezone"); value = value[5 .. value.length]; immutable utcOffset = (dur!"hours"(zoneHours) + dur!"minutes"(zoneMinutes)) * sign; if(utcOffset == Duration.zero) { return sign == 1 ? cast(immutable(TimeZone))UTC() : cast(immutable(TimeZone))new immutable SimpleTimeZone(Duration.zero); } return new immutable(SimpleTimeZone)(utcOffset); } // zone Rebindable!(immutable TimeZone) tz; if(value[0] == '-') tz = parseTZ(-1); else if(value[0] == '+') tz = parseTZ(1); else { // obs-zone immutable tzLen = value.length - find(value, ' ', '\t', '(')[0].length; switch(sliceAsString(value[0 .. tzLen <= 4 ? tzLen : 4])) { case "UT": case "GMT": tz = UTC(); break; case "EST": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break; case "EDT": tz = new immutable SimpleTimeZone(dur!"hours"(-4)); break; case "CST": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break; case "CDT": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break; case "MST": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break; case "MDT": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break; case "PST": tz = new immutable SimpleTimeZone(dur!"hours"(-8)); break; case "PDT": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break; case "J": case "j": throw new DateTimeException("Invalid timezone"); default: { if(all!(std.ascii.isAlpha)(value[0 .. tzLen])) { tz = new immutable SimpleTimeZone(Duration.zero); break; } throw new DateTimeException("Invalid timezone"); } } value = value[tzLen .. value.length]; } // This is kind of arbitrary. Technically, nothing but CFWS is legal past // the end of the timezone, but we don't want to be picky about that in a // function that's just parsing rather than validating. So, the idea here is // that if the next character is printable (and not part of CFWS), then it // might be part of the timezone and thus affect what the timezone was // supposed to be, so we'll throw, but otherwise, we'll just ignore it. if(!value.empty && isPrintable(value[0]) && value[0] != ' ' && value[0] != '(') throw new DateTimeException("Invalid timezone"); try return SysTime(DateTime(year, month, day, hour, minute, second), tz); catch(DateTimeException dte) throw new DateTimeException("date-time format is correct, but the resulting SysTime is invalid.", dte); } /// unittest { auto tz = new immutable SimpleTimeZone(hours(-8)); assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") == SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz)); assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") == SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC())); auto badStr = "29 Feb 2001 12:17:16 +0200"; assertThrown!DateTimeException(parseRFC822DateTime(badStr)); } version(unittest) void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__) { import std.string; import std.format : format; auto value = cr(str); auto result = parseRFC822DateTime(value); if(result != expected) throw new AssertError(format("wrong result. expected [%s], actual[%s]", expected, result), __FILE__, line); } version(unittest) void testBadParse822(alias cr)(string str, size_t line = __LINE__) { try parseRFC822DateTime(cr(str)); catch(DateTimeException) return; throw new AssertError("No DateTimeException was thrown", __FILE__, line); } unittest { import std.algorithm; import std.ascii; import std.format : format; import std.meta; import std.range; import std.string; import std.typecons; static struct Rand3Letters { enum empty = false; @property auto front() { return _mon; } void popFront() { import std.random; _mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique(); } string _mon; static auto start() { Rand3Letters retval; retval.popFront(); return retval; } } foreach(cr; AliasSeq!(function(string a){return cast(char[])a;}, function(string a){return cast(ubyte[])a;}, function(string a){return a;}, function(string a){return map!(b => cast(char)b)(a.representation);})) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 scope(failure) writeln(typeof(cr).stringof); alias test = testParse822!cr; alias testBad = testBadParse822!cr; immutable std1 = DateTime(2012, 12, 21, 13, 14, 15); immutable std2 = DateTime(2012, 12, 21, 13, 14, 0); immutable dst1 = DateTime(1976, 7, 4, 5, 4, 22); immutable dst2 = DateTime(1976, 7, 4, 5, 4, 0); test("21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC())); test("21 Dec 2012 13:14 +0000", SysTime(std2, UTC())); test("Fri, 21 Dec 2012 13:14 +0000", SysTime(std2, UTC())); test("Fri, 21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC())); test("04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC())); test("04 Jul 1976 05:04 +0000", SysTime(dst2, UTC())); test("Sun, 04 Jul 1976 05:04 +0000", SysTime(dst2, UTC())); test("Sun, 04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC())); test("4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC())); test("4 Jul 1976 05:04 +0000", SysTime(dst2, UTC())); test("Sun, 4 Jul 1976 05:04 +0000", SysTime(dst2, UTC())); test("Sun, 4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC())); auto badTZ = new immutable SimpleTimeZone(Duration.zero); test("21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ)); test("21 Dec 2012 13:14 -0000", SysTime(std2, badTZ)); test("Fri, 21 Dec 2012 13:14 -0000", SysTime(std2, badTZ)); test("Fri, 21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ)); test("04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ)); test("04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ)); test("Sun, 04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ)); test("Sun, 04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ)); test("4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ)); test("4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ)); test("Sun, 4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ)); test("Sun, 4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ)); auto pst = new immutable SimpleTimeZone(dur!"hours"(-8)); auto pdt = new immutable SimpleTimeZone(dur!"hours"(-7)); test("21 Dec 2012 13:14:15 -0800", SysTime(std1, pst)); test("21 Dec 2012 13:14 -0800", SysTime(std2, pst)); test("Fri, 21 Dec 2012 13:14 -0800", SysTime(std2, pst)); test("Fri, 21 Dec 2012 13:14:15 -0800", SysTime(std1, pst)); test("04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt)); test("04 Jul 1976 05:04 -0700", SysTime(dst2, pdt)); test("Sun, 04 Jul 1976 05:04 -0700", SysTime(dst2, pdt)); test("Sun, 04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt)); test("4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt)); test("4 Jul 1976 05:04 -0700", SysTime(dst2, pdt)); test("Sun, 4 Jul 1976 05:04 -0700", SysTime(dst2, pdt)); test("Sun, 4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt)); auto cet = new immutable SimpleTimeZone(dur!"hours"(1)); auto cest = new immutable SimpleTimeZone(dur!"hours"(2)); test("21 Dec 2012 13:14:15 +0100", SysTime(std1, cet)); test("21 Dec 2012 13:14 +0100", SysTime(std2, cet)); test("Fri, 21 Dec 2012 13:14 +0100", SysTime(std2, cet)); test("Fri, 21 Dec 2012 13:14:15 +0100", SysTime(std1, cet)); test("04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest)); test("04 Jul 1976 05:04 +0200", SysTime(dst2, cest)); test("Sun, 04 Jul 1976 05:04 +0200", SysTime(dst2, cest)); test("Sun, 04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest)); test("4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest)); test("4 Jul 1976 05:04 +0200", SysTime(dst2, cest)); test("Sun, 4 Jul 1976 05:04 +0200", SysTime(dst2, cest)); test("Sun, 4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest)); // dst and std times are switched in the Southern Hemisphere which is why the // time zone names and DateTime variables don't match. auto cstStd = new immutable SimpleTimeZone(dur!"hours"(9) + dur!"minutes"(30)); auto cstDST = new immutable SimpleTimeZone(dur!"hours"(10) + dur!"minutes"(30)); test("21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST)); test("21 Dec 2012 13:14 +1030", SysTime(std2, cstDST)); test("Fri, 21 Dec 2012 13:14 +1030", SysTime(std2, cstDST)); test("Fri, 21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST)); test("04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd)); test("04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd)); test("Sun, 04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd)); test("Sun, 04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd)); test("4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd)); test("4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd)); test("Sun, 4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd)); test("Sun, 4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd)); foreach(int i, mon; _monthNames) { test(format("17 %s 2012 00:05:02 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 2), UTC())); test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC())); } import std.uni; foreach(mon; chain(_monthNames[].map!(a => toLower(a))(), _monthNames[].map!(a => toUpper(a))(), ["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy", "Jum", "Jbn", "Jup", "Jal", "Aur", "Apg", "Sem", "Sap", "Ocm", "Odt", "Nom", "Nav", "Dem", "Dac"], Rand3Letters.start().take(20))) { scope(failure) writefln("Month: %s", mon); testBad(format("17 %s 2012 00:05:02 +0000", mon)); testBad(format("17 %s 2012 00:05 +0000", mon)); } immutable string[7] daysOfWeekNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; { auto start = SysTime(DateTime(2012, 11, 11, 9, 42, 0), UTC()); int day = 11; foreach(int i, dow; daysOfWeekNames) { auto curr = start + dur!"days"(i); test(format("%s, %s Nov 2012 09:42:00 +0000", dow, day), curr); test(format("%s, %s Nov 2012 09:42 +0000", dow, day++), curr); // Whether the day of the week matches the date is ignored. test(format("%s, 11 Nov 2012 09:42:00 +0000", dow), start); test(format("%s, 11 Nov 2012 09:42 +0000", dow), start); } } foreach(dow; chain(daysOfWeekNames[].map!(a => toLower(a))(), daysOfWeekNames[].map!(a => toUpper(a))(), ["Sum", "Spn", "Mom", "Man", "Tuf", "Tae", "Wem", "Wdd", "The", "Tur", "Fro", "Fai", "San", "Sut"], Rand3Letters.start().take(20))) { scope(failure) writefln("Day of Week: %s", dow); testBad(format("%s, 11 Nov 2012 09:42:00 +0000", dow)); testBad(format("%s, 11 Nov 2012 09:42 +0000", dow)); } testBad("31 Dec 1899 23:59:59 +0000"); test("01 Jan 1900 00:00:00 +0000", SysTime(Date(1900, 1, 1), UTC())); test("01 Jan 1900 00:00:00 -0000", SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(Duration.zero))); test("01 Jan 1900 00:00:00 -0700", SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-7)))); { auto st1 = SysTime(Date(1900, 1, 1), UTC()); auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11))); foreach(i; 1900 .. 2102) { test(format("1 Jan %05d 00:00 +0000", i), st1); test(format("1 Jan %05d 00:00 -1100", i), st2); st1.add!"years"(1); st2.add!"years"(1); } st1.year = 9998; st2.year = 9998; foreach(i; 9998 .. 11_002) { test(format("1 Jan %05d 00:00 +0000", i), st1); test(format("1 Jan %05d 00:00 -1100", i), st2); st1.add!"years"(1); st2.add!"years"(1); } } testBad("12 Feb 1907 23:17:09 0000"); testBad("12 Feb 1907 23:17:09 +000"); testBad("12 Feb 1907 23:17:09 -000"); testBad("12 Feb 1907 23:17:09 +00000"); testBad("12 Feb 1907 23:17:09 -00000"); testBad("12 Feb 1907 23:17:09 +A"); testBad("12 Feb 1907 23:17:09 +PST"); testBad("12 Feb 1907 23:17:09 -A"); testBad("12 Feb 1907 23:17:09 -PST"); // test trailing stuff that gets ignored { foreach(c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1))) { scope(failure) writefln("c: %d", c); test(format("21 Dec 2012 13:14:15 +0000%c", cast(char)c), SysTime(std1, UTC())); test(format("21 Dec 2012 13:14:15 +0000%c ", cast(char)c), SysTime(std1, UTC())); test(format("21 Dec 2012 13:14:15 +0000%chello", cast(char)c), SysTime(std1, UTC())); } } // test trailing stuff that doesn't get ignored { foreach(c; chain(iota(33, '('), iota('(' + 1, 127))) { scope(failure) writefln("c: %d", c); testBad(format("21 Dec 2012 13:14:15 +0000%c", cast(char)c)); testBad(format("21 Dec 2012 13:14:15 +0000%c ", cast(char)c)); testBad(format("21 Dec 2012 13:14:15 +0000%chello", cast(char)c)); } } testBad("32 Jan 2012 12:13:14 -0800"); testBad("31 Jan 2012 24:13:14 -0800"); testBad("31 Jan 2012 12:60:14 -0800"); testBad("31 Jan 2012 12:13:61 -0800"); testBad("31 Jan 2012 12:13:14 -0860"); test("31 Jan 2012 12:13:14 -0859", SysTime(DateTime(2012, 1, 31, 12, 13, 14), new immutable SimpleTimeZone(dur!"hours"(-8) + dur!"minutes"(-59)))); // leap-seconds test("21 Dec 2012 15:59:60 -0800", SysTime(DateTime(2012, 12, 21, 15, 59, 59), pst)); // FWS test("Sun,4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd)); test("Sun,4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd)); test("Sun,4 Jul 1976 05:04 +0930 (foo)", SysTime(dst2, cstStd)); test("Sun,4 Jul 1976 05:04:22 +0930 (foo)", SysTime(dst1, cstStd)); test("Sun,4 \r\n Jul \r\n 1976 \r\n 05:04 \r\n +0930 \r\n (foo)", SysTime(dst2, cstStd)); test("Sun,4 \r\n Jul \r\n 1976 \r\n 05:04:22 \r\n +0930 \r\n (foo)", SysTime(dst1, cstStd)); auto str = "01 Jan 2012 12:13:14 -0800 "; test(str, SysTime(DateTime(2012, 1, 1, 12, 13, 14), new immutable SimpleTimeZone(hours(-8)))); foreach(i; 0 .. str.length) { auto currStr = str.dup; currStr[i] = 'x'; scope(failure) writefln("failed: %s", currStr); testBad(cast(string)currStr); } foreach(i; 2 .. str.length) { auto currStr = str[0 .. $ - i]; scope(failure) writefln("failed: %s", currStr); testBad(cast(string)currStr); testBad((cast(string)currStr) ~ " "); } }(); } // Obsolete Format per section 4.3 of RFC 5322. unittest { import std.algorithm; import std.ascii; import std.format : format; import std.meta; import std.range; import std.string; import std.typecons; auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC()); auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC()); auto std3 = SysTime(DateTime(1912, 12, 21, 13, 14, 15), UTC()); auto std4 = SysTime(DateTime(1912, 12, 21, 13, 14, 0), UTC()); auto dst1 = SysTime(DateTime(1976, 7, 4, 5, 4, 22), UTC()); auto dst2 = SysTime(DateTime(1976, 7, 4, 5, 4, 0), UTC()); auto tooLate1 = SysTime(Date(10_000, 1, 1), UTC()); auto tooLate2 = SysTime(DateTime(12_007, 12, 31, 12, 22, 19), UTC()); foreach(cr; AliasSeq!(function(string a){return cast(char[])a;}, function(string a){return cast(ubyte[])a;}, function(string a){return a;}, function(string a){return map!(b => cast(char)b)(a.representation);})) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 scope(failure) writeln(typeof(cr).stringof); alias test = testParse822!cr; { auto list = ["", " ", " \r\n\t", "\t\r\n (hello world( frien(dog)) silly \r\n ) \t\t \r\n ()", " \n ", "\t\n\t", " \n\t (foo) \n (bar) \r\n (baz) \n "]; foreach(i, cfws; list) { scope(failure) writefln("i: %s", i); test(format("%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1); test(format("%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2); test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2); test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1); test(format("%1$s04%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04:22 +0000%1$s", cfws), dst1); test(format("%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1); test(format("%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2); test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2); test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1); test(format("%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s4%1$sJul%1$s76 05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s4%1$sJul%1$s76 05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3); test(format("%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4); test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4); test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3); test(format("%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2); test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1); test(format("%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1); test(format("%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2); test(format("%1$sSat%1$s,%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1); test(format("%1$sSun%1$s,%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2); } } // test years of 1, 2, and 3 digits. { auto st1 = SysTime(Date(2000, 1, 1), UTC()); auto st2 = SysTime(Date(2000, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12))); foreach(i; 0 .. 50) { test(format("1 Jan %02d 00:00 GMT", i), st1); test(format("1 Jan %02d 00:00 -1200", i), st2); st1.add!"years"(1); st2.add!"years"(1); } } { auto st1 = SysTime(Date(1950, 1, 1), UTC()); auto st2 = SysTime(Date(1950, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12))); foreach(i; 50 .. 100) { test(format("1 Jan %02d 00:00 GMT", i), st1); test(format("1 Jan %02d 00:00 -1200", i), st2); st1.add!"years"(1); st2.add!"years"(1); } } { auto st1 = SysTime(Date(1900, 1, 1), UTC()); auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11))); foreach(i; 0 .. 1000) { test(format("1 Jan %03d 00:00 GMT", i), st1); test(format("1 Jan %03d 00:00 -1100", i), st2); st1.add!"years"(1); st2.add!"years"(1); } } foreach(i; 0 .. 10) { auto str1 = cr(format("1 Jan %d 00:00 GMT", i)); auto str2 = cr(format("1 Jan %d 00:00 -1200", i)); assertThrown!DateTimeException(parseRFC822DateTime(str1)); assertThrown!DateTimeException(parseRFC822DateTime(str1)); } // test time zones { auto dt = DateTime(1982, 05, 03, 12, 22, 04); test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC())); test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC())); test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5)))); test("Wed, 03 May 1982 12:22:04 EDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-4)))); test("Wed, 03 May 1982 12:22:04 CST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6)))); test("Wed, 03 May 1982 12:22:04 CDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5)))); test("Wed, 03 May 1982 12:22:04 MST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7)))); test("Wed, 03 May 1982 12:22:04 MDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6)))); test("Wed, 03 May 1982 12:22:04 PST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-8)))); test("Wed, 03 May 1982 12:22:04 PDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7)))); auto badTZ = new immutable SimpleTimeZone(Duration.zero); foreach(dchar c; filter!(a => a != 'j' && a != 'J')(letters)) { scope(failure) writefln("c: %s", c); test(format("Wed, 03 May 1982 12:22:04 %s", c), SysTime(dt, badTZ)); test(format("Wed, 03 May 1982 12:22:04%s", c), SysTime(dt, badTZ)); } foreach(dchar c; ['j', 'J']) { scope(failure) writefln("c: %s", c); assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04 %s", c)))); assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04%s", c)))); } foreach(string s; ["AAA", "GQW", "DDT", "PDA", "GT", "GM"]) { scope(failure) writefln("s: %s", s); test(format("Wed, 03 May 1982 12:22:04 %s", s), SysTime(dt, badTZ)); } // test trailing stuff that gets ignored { foreach(c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1))) { scope(failure) writefln("c: %d", c); test(format("21Dec1213:14:15+0000%c", cast(char)c), std1); test(format("21Dec1213:14:15+0000%c ", cast(char)c), std1); test(format("21Dec1213:14:15+0000%chello", cast(char)c), std1); } } // test trailing stuff that doesn't get ignored { foreach(c; chain(iota(33, '('), iota('(' + 1, 127))) { scope(failure) writefln("c: %d", c); assertThrown!DateTimeException(parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c", cast(char)c)))); assertThrown!DateTimeException(parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c ", cast(char)c)))); assertThrown!DateTimeException(parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%chello", cast(char)c)))); } } } // test that the checks for minimum length work correctly and avoid // any RangeErrors. test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00), new immutable SimpleTimeZone(Duration.zero))); test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00), new immutable SimpleTimeZone(Duration.zero))); test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00), new immutable SimpleTimeZone(Duration.zero))); test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00), new immutable SimpleTimeZone(Duration.zero))); auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime("")); foreach(str; ["Fri,7Dec1200:00:00", "7Dec1200:00:00"]) { foreach(i; 0 .. str.length) { auto value = str[0 .. $ - i]; scope(failure) writeln(value); assert(collectExceptionMsg!DateTimeException(parseRFC822DateTime(value)) == tooShortMsg); } } }(); } /++ Whether all of the given strings are valid units of time. $(D "nsecs") is not considered a valid unit of time. Nothing in std.datetime can handle precision greater than hnsecs, and the few functions in core.time which deal with "nsecs" deal with it explicitly. +/ bool validTimeUnits(string[] units...) @safe pure nothrow { import std.algorithm : canFind; foreach(str; units) { if(!canFind(timeStrings[], str)) return false; } return true; } /++ Compares two time unit strings. $(D "years") are the largest units and $(D "hnsecs") are the smallest. Returns: $(BOOKTABLE, $(TR $(TD this < rhs) $(TD < 0)) $(TR $(TD this == rhs) $(TD 0)) $(TR $(TD this > rhs) $(TD > 0)) ) Throws: $(LREF DateTimeException) if either of the given strings is not a valid time unit string. +/ int cmpTimeUnits(string lhs, string rhs) @safe pure { import std.format : format; import std.algorithm : countUntil; auto tstrings = timeStrings; immutable indexOfLHS = countUntil(tstrings, lhs); immutable indexOfRHS = countUntil(tstrings, rhs); enforce(indexOfLHS != -1, format("%s is not a valid TimeString", lhs)); enforce(indexOfRHS != -1, format("%s is not a valid TimeString", rhs)); if(indexOfLHS < indexOfRHS) return -1; if(indexOfLHS > indexOfRHS) return 1; return 0; } unittest { foreach(i, outerUnits; timeStrings) { assert(cmpTimeUnits(outerUnits, outerUnits) == 0); //For some reason, $ won't compile. foreach(innerUnits; timeStrings[i+1 .. timeStrings.length]) assert(cmpTimeUnits(outerUnits, innerUnits) == -1); } foreach(i, outerUnits; timeStrings) { foreach(innerUnits; timeStrings[0 .. i]) assert(cmpTimeUnits(outerUnits, innerUnits) == 1); } } /++ Compares two time unit strings at compile time. $(D "years") are the largest units and $(D "hnsecs") are the smallest. This template is used instead of $(D cmpTimeUnits) because exceptions can't be thrown at compile time and $(D cmpTimeUnits) must enforce that the strings it's given are valid time unit strings. This template uses a template constraint instead. Returns: $(BOOKTABLE, $(TR $(TD this < rhs) $(TD < 0)) $(TR $(TD this == rhs) $(TD 0)) $(TR $(TD this > rhs) $(TD > 0)) ) +/ template CmpTimeUnits(string lhs, string rhs) if(validTimeUnits(lhs, rhs)) { enum CmpTimeUnits = cmpTimeUnitsCTFE(lhs, rhs); } /+ Helper function for $(D CmpTimeUnits). +/ private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow { import std.algorithm : countUntil; auto tstrings = timeStrings; immutable indexOfLHS = countUntil(tstrings, lhs); immutable indexOfRHS = countUntil(tstrings, rhs); if(indexOfLHS < indexOfRHS) return -1; if(indexOfLHS > indexOfRHS) return 1; return 0; } unittest { import std.format : format; import std.meta; import std.string; import std.typecons; static string genTest(size_t index) { auto currUnits = timeStrings[index]; auto test = format(`assert(CmpTimeUnits!("%s", "%s") == 0);`, currUnits, currUnits); foreach(units; timeStrings[index + 1 .. $]) test ~= format(`assert(CmpTimeUnits!("%s", "%s") == -1);`, currUnits, units); foreach(units; timeStrings[0 .. index]) test ~= format(`assert(CmpTimeUnits!("%s", "%s") == 1);`, currUnits, units); return test; } static assert(timeStrings.length == 10); foreach(n; AliasSeq!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) mixin(genTest(n)); } /++ Returns whether the given value is valid for the given unit type when in a time point. Naturally, a duration is not held to a particular range, but the values in a time point are (e.g. a month must be in the range of 1 - 12 inclusive). Params: units = The units of time to validate. value = The number to validate. +/ bool valid(string units)(int value) @safe pure nothrow if(units == "months" || units == "hours" || units == "minutes" || units == "seconds") { static if(units == "months") return value >= Month.jan && value <= Month.dec; else static if(units == "hours") return value >= 0 && value <= TimeOfDay.maxHour; else static if(units == "minutes") return value >= 0 && value <= TimeOfDay.maxMinute; else static if(units == "seconds") return value >= 0 && value <= TimeOfDay.maxSecond; } /// unittest { assert(valid!"hours"(12)); assert(!valid!"hours"(32)); assert(valid!"months"(12)); assert(!valid!"months"(13)); } /++ Returns whether the given day is valid for the given year and month. Params: units = The units of time to validate. year = The year of the day to validate. month = The month of the day to validate. day = The day to validate. +/ bool valid(string units)(int year, int month, int day) @safe pure nothrow if(units == "days") { return day > 0 && day <= maxDay(year, month); } /++ Params: units = The units of time to validate. value = The number to validate. file = The file that the $(LREF DateTimeException) will list if thrown. line = The line number that the $(LREF DateTimeException) will list if thrown. Throws: $(LREF DateTimeException) if $(D valid!units(value)) is false. +/ void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__) @safe pure if(units == "months" || units == "hours" || units == "minutes" || units == "seconds") { import std.format : format; static if(units == "months") { if(!valid!units(value)) throw new DateTimeException(format("%s is not a valid month of the year.", value), file, line); } else static if(units == "hours") { if(!valid!units(value)) throw new DateTimeException(format("%s is not a valid hour of the day.", value), file, line); } else static if(units == "minutes") { if(!valid!units(value)) throw new DateTimeException(format("%s is not a valid minute of an hour.", value), file, line); } else static if(units == "seconds") { if(!valid!units(value)) throw new DateTimeException(format("%s is not a valid second of a minute.", value), file, line); } } /++ Params: units = The units of time to validate. year = The year of the day to validate. month = The month of the day to validate. day = The day to validate. file = The file that the $(LREF DateTimeException) will list if thrown. line = The line number that the $(LREF DateTimeException) will list if thrown. Throws: $(LREF DateTimeException) if $(D valid!"days"(year, month, day)) is false. +/ void enforceValid(string units) (int year, Month month, int day, string file = __FILE__, size_t line = __LINE__) @safe pure if(units == "days") { import std.format : format; if(!valid!"days"(year, month, day)) throw new DateTimeException(format("%s is not a valid day in %s in %s", day, month, year), file, line); } /++ Returns the number of months from the current months of the year to the given month of the year. If they are the same, then the result is 0. Params: currMonth = The current month of the year. month = The month of the year to get the number of months to. +/ static int monthsToMonth(int currMonth, int month) @safe pure { enforceValid!"months"(currMonth); enforceValid!"months"(month); if(currMonth == month) return 0; if(currMonth < month) return month - currMonth; return (Month.dec - currMonth) + month; } unittest { assert(monthsToMonth(Month.jan, Month.jan) == 0); assert(monthsToMonth(Month.jan, Month.feb) == 1); assert(monthsToMonth(Month.jan, Month.mar) == 2); assert(monthsToMonth(Month.jan, Month.apr) == 3); assert(monthsToMonth(Month.jan, Month.may) == 4); assert(monthsToMonth(Month.jan, Month.jun) == 5); assert(monthsToMonth(Month.jan, Month.jul) == 6); assert(monthsToMonth(Month.jan, Month.aug) == 7); assert(monthsToMonth(Month.jan, Month.sep) == 8); assert(monthsToMonth(Month.jan, Month.oct) == 9); assert(monthsToMonth(Month.jan, Month.nov) == 10); assert(monthsToMonth(Month.jan, Month.dec) == 11); assert(monthsToMonth(Month.may, Month.jan) == 8); assert(monthsToMonth(Month.may, Month.feb) == 9); assert(monthsToMonth(Month.may, Month.mar) == 10); assert(monthsToMonth(Month.may, Month.apr) == 11); assert(monthsToMonth(Month.may, Month.may) == 0); assert(monthsToMonth(Month.may, Month.jun) == 1); assert(monthsToMonth(Month.may, Month.jul) == 2); assert(monthsToMonth(Month.may, Month.aug) == 3); assert(monthsToMonth(Month.may, Month.sep) == 4); assert(monthsToMonth(Month.may, Month.oct) == 5); assert(monthsToMonth(Month.may, Month.nov) == 6); assert(monthsToMonth(Month.may, Month.dec) == 7); assert(monthsToMonth(Month.oct, Month.jan) == 3); assert(monthsToMonth(Month.oct, Month.feb) == 4); assert(monthsToMonth(Month.oct, Month.mar) == 5); assert(monthsToMonth(Month.oct, Month.apr) == 6); assert(monthsToMonth(Month.oct, Month.may) == 7); assert(monthsToMonth(Month.oct, Month.jun) == 8); assert(monthsToMonth(Month.oct, Month.jul) == 9); assert(monthsToMonth(Month.oct, Month.aug) == 10); assert(monthsToMonth(Month.oct, Month.sep) == 11); assert(monthsToMonth(Month.oct, Month.oct) == 0); assert(monthsToMonth(Month.oct, Month.nov) == 1); assert(monthsToMonth(Month.oct, Month.dec) == 2); assert(monthsToMonth(Month.dec, Month.jan) == 1); assert(monthsToMonth(Month.dec, Month.feb) == 2); assert(monthsToMonth(Month.dec, Month.mar) == 3); assert(monthsToMonth(Month.dec, Month.apr) == 4); assert(monthsToMonth(Month.dec, Month.may) == 5); assert(monthsToMonth(Month.dec, Month.jun) == 6); assert(monthsToMonth(Month.dec, Month.jul) == 7); assert(monthsToMonth(Month.dec, Month.aug) == 8); assert(monthsToMonth(Month.dec, Month.sep) == 9); assert(monthsToMonth(Month.dec, Month.oct) == 10); assert(monthsToMonth(Month.dec, Month.nov) == 11); assert(monthsToMonth(Month.dec, Month.dec) == 0); } /++ Returns the number of days from the current day of the week to the given day of the week. If they are the same, then the result is 0. Params: currDoW = The current day of the week. dow = The day of the week to get the number of days to. +/ static int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow) @safe pure nothrow { if(currDoW == dow) return 0; if(currDoW < dow) return dow - currDoW; return (DayOfWeek.sat - currDoW) + dow + 1; } unittest { assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sun) == 0); assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.mon) == 1); assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.tue) == 2); assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.wed) == 3); assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.thu) == 4); assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.fri) == 5); assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sat) == 6); assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.tue) == 1); assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.thu) == 3); assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.fri) == 4); assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sat) == 5); assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sun) == 5); assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.mon) == 6); assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.tue) == 0); assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.wed) == 1); assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.thu) == 2); assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.fri) == 3); assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sat) == 4); assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sun) == 4); assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.mon) == 5); assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.tue) == 6); assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.wed) == 0); assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.thu) == 1); assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.fri) == 2); assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sat) == 3); assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sun) == 3); assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.mon) == 4); assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.tue) == 5); assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.wed) == 6); assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.thu) == 0); assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.fri) == 1); assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sat) == 2); assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sun) == 2); assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.mon) == 3); assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.tue) == 4); assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.wed) == 5); assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.thu) == 6); assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.fri) == 0); assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sat) == 1); assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sun) == 1); assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.mon) == 2); assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.tue) == 3); assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.wed) == 4); assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.thu) == 5); assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.fri) == 6); assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sat) == 0); } version(StdDdoc) { /++ Function for starting to a stop watch time when the function is called and stopping it when its return value goes out of scope and is destroyed. When the value that is returned by this function is destroyed, $(D func) will run. $(D func) is a unary function that takes a $(CXREF time, TickDuration). Example: -------------------- { auto mt = measureTime!((TickDuration a) { /+ do something when the scope is exited +/ }); // do something that needs to be timed } -------------------- which is functionally equivalent to -------------------- { auto sw = StopWatch(AutoStart.yes); scope(exit) { TickDuration a = sw.peek(); /+ do something when the scope is exited +/ } // do something that needs to be timed } -------------------- See_Also: $(LREF benchmark) +/ auto measureTime(alias func)(); } else { @safe auto measureTime(alias func)() if(isSafe!((){StopWatch sw; unaryFun!func(sw.peek());})) { struct Result { private StopWatch _sw = void; this(AutoStart as) { _sw = StopWatch(as); } ~this() { unaryFun!(func)(_sw.peek()); } } return Result(AutoStart.yes); } auto measureTime(alias func)() if(!isSafe!((){StopWatch sw; unaryFun!func(sw.peek());})) { struct Result { private StopWatch _sw = void; this(AutoStart as) { _sw = StopWatch(as); } ~this() { unaryFun!(func)(_sw.peek()); } } return Result(AutoStart.yes); } } // Verify Example. unittest { { auto mt = measureTime!((TickDuration a) { /+ do something when the scope is exited +/ }); // do something that needs to be timed } { auto sw = StopWatch(AutoStart.yes); scope(exit) { TickDuration a = sw.peek(); /+ do something when the scope is exited +/ } // do something that needs to be timed } } @safe unittest { import std.math : isNaN; @safe static void func(TickDuration td) { assert(!td.to!("seconds", real)().isNaN()); } auto mt = measureTime!(func)(); /+ with (measureTime!((a){assert(a.seconds);})) { // doSomething(); // @@@BUG@@@ doesn't work yet. } +/ } unittest { import std.math : isNaN; static void func(TickDuration td) { assert(!td.to!("seconds", real)().isNaN()); } auto mt = measureTime!(func)(); /+ with (measureTime!((a){assert(a.seconds);})) { // doSomething(); // @@@BUG@@@ doesn't work yet. } +/ } //Bug# 8450 unittest { @safe void safeFunc() {} @trusted void trustFunc() {} @system void sysFunc() {} auto safeResult = measureTime!((a){safeFunc();})(); auto trustResult = measureTime!((a){trustFunc();})(); auto sysResult = measureTime!((a){sysFunc();})(); } //============================================================================== // Private Section. //============================================================================== private: //============================================================================== // Section with private enums and constants. //============================================================================== enum daysInYear = 365; // The number of days in a non-leap year. enum daysInLeapYear = 366; // The numbef or days in a leap year. enum daysIn4Years = daysInYear * 3 + daysInLeapYear; /// Number of days in 4 years. enum daysIn100Years = daysIn4Years * 25 - 1; // The number of days in 100 years. enum daysIn400Years = daysIn100Years * 4 + 1; // The number of days in 400 years. /+ Array of integers representing the last days of each month in a year. +/ immutable int[13] lastDayNonLeap = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; /+ Array of integers representing the last days of each month in a leap year. +/ immutable int[13] lastDayLeap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; /+ Array of the short (three letter) names of each month. +/ immutable string[12] _monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; //============================================================================== // Section with private helper functions and templates. //============================================================================== /+ Template to help with converting between time units. +/ template hnsecsPer(string units) if(CmpTimeUnits!(units, "months") < 0) { static if(units == "hnsecs") enum hnsecsPer = 1L; else static if(units == "usecs") enum hnsecsPer = 10L; else static if(units == "msecs") enum hnsecsPer = 1000 * hnsecsPer!"usecs"; else static if(units == "seconds") enum hnsecsPer = 1000 * hnsecsPer!"msecs"; else static if(units == "minutes") enum hnsecsPer = 60 * hnsecsPer!"seconds"; else static if(units == "hours") enum hnsecsPer = 60 * hnsecsPer!"minutes"; else static if(units == "days") enum hnsecsPer = 24 * hnsecsPer!"hours"; else static if(units == "weeks") enum hnsecsPer = 7 * hnsecsPer!"days"; } /+ Splits out a particular unit from hnsecs and gives the value for that unit and the remaining hnsecs. It really shouldn't be used unless unless all units larger than the given units have already been split out. Params: units = The units to split out. hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left after splitting out the given units. Returns: The number of the given units from converting hnsecs to those units. +/ long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow if(validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0) { immutable value = convert!("hnsecs", units)(hnsecs); hnsecs -= convert!(units, "hnsecs")(value); return value; } unittest { auto hnsecs = 2595000000007L; immutable days = splitUnitsFromHNSecs!"days"(hnsecs); assert(days == 3); assert(hnsecs == 3000000007); immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); assert(minutes == 5); assert(hnsecs == 7); } /+ This function is used to split out the units without getting the remaining hnsecs. See_Also: $(LREF splitUnitsFromHNSecs) Params: units = The units to split out. hnsecs = The current total hnsecs. Returns: The split out value. +/ long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow if(validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0) { return convert!("hnsecs", units)(hnsecs); } unittest { auto hnsecs = 2595000000007L; immutable days = getUnitsFromHNSecs!"days"(hnsecs); assert(days == 3); assert(hnsecs == 2595000000007L); } /+ This function is used to split out the units without getting the units but just the remaining hnsecs. See_Also: $(LREF splitUnitsFromHNSecs) Params: units = The units to split out. hnsecs = The current total hnsecs. Returns: The remaining hnsecs. +/ long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow if(validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0) { immutable value = convert!("hnsecs", units)(hnsecs); return hnsecs - convert!(units, "hnsecs")(value); } unittest { auto hnsecs = 2595000000007L; auto returned = removeUnitsFromHNSecs!"days"(hnsecs); assert(returned == 3000000007); assert(hnsecs == 2595000000007L); } /+ The maximum valid Day in the given month in the given year. Params: year = The year to get the day for. month = The month of the Gregorian Calendar to get the day for. +/ static ubyte maxDay(int year, int month) @safe pure nothrow in { assert(valid!"months"(month)); } body { switch(month) { case Month.jan, Month.mar, Month.may, Month.jul, Month.aug, Month.oct, Month.dec: return 31; case Month.feb: return yearIsLeapYear(year) ? 29 : 28; case Month.apr, Month.jun, Month.sep, Month.nov: return 30; default: assert(0, "Invalid month."); } } unittest { //Test A.D. assert(maxDay(1999, 1) == 31); assert(maxDay(1999, 2) == 28); assert(maxDay(1999, 3) == 31); assert(maxDay(1999, 4) == 30); assert(maxDay(1999, 5) == 31); assert(maxDay(1999, 6) == 30); assert(maxDay(1999, 7) == 31); assert(maxDay(1999, 8) == 31); assert(maxDay(1999, 9) == 30); assert(maxDay(1999, 10) == 31); assert(maxDay(1999, 11) == 30); assert(maxDay(1999, 12) == 31); assert(maxDay(2000, 1) == 31); assert(maxDay(2000, 2) == 29); assert(maxDay(2000, 3) == 31); assert(maxDay(2000, 4) == 30); assert(maxDay(2000, 5) == 31); assert(maxDay(2000, 6) == 30); assert(maxDay(2000, 7) == 31); assert(maxDay(2000, 8) == 31); assert(maxDay(2000, 9) == 30); assert(maxDay(2000, 10) == 31); assert(maxDay(2000, 11) == 30); assert(maxDay(2000, 12) == 31); //Test B.C. assert(maxDay(-1999, 1) == 31); assert(maxDay(-1999, 2) == 28); assert(maxDay(-1999, 3) == 31); assert(maxDay(-1999, 4) == 30); assert(maxDay(-1999, 5) == 31); assert(maxDay(-1999, 6) == 30); assert(maxDay(-1999, 7) == 31); assert(maxDay(-1999, 8) == 31); assert(maxDay(-1999, 9) == 30); assert(maxDay(-1999, 10) == 31); assert(maxDay(-1999, 11) == 30); assert(maxDay(-1999, 12) == 31); assert(maxDay(-2000, 1) == 31); assert(maxDay(-2000, 2) == 29); assert(maxDay(-2000, 3) == 31); assert(maxDay(-2000, 4) == 30); assert(maxDay(-2000, 5) == 31); assert(maxDay(-2000, 6) == 30); assert(maxDay(-2000, 7) == 31); assert(maxDay(-2000, 8) == 31); assert(maxDay(-2000, 9) == 30); assert(maxDay(-2000, 10) == 31); assert(maxDay(-2000, 11) == 30); assert(maxDay(-2000, 12) == 31); } /+ Returns the day of the week for the given day of the Gregorian Calendar. Params: day = The day of the Gregorian Calendar for which to get the day of the week. +/ DayOfWeek getDayOfWeek(int day) @safe pure nothrow { //January 1st, 1 A.D. was a Monday if(day >= 0) return cast(DayOfWeek)(day % 7); else { immutable dow = cast(DayOfWeek)((day % 7) + 7); if(dow == 7) return DayOfWeek.sun; else return dow; } } unittest { //Test A.D. assert(getDayOfWeek(SysTime(Date(1, 1, 1)).dayOfGregorianCal) == DayOfWeek.mon); assert(getDayOfWeek(SysTime(Date(1, 1, 2)).dayOfGregorianCal) == DayOfWeek.tue); assert(getDayOfWeek(SysTime(Date(1, 1, 3)).dayOfGregorianCal) == DayOfWeek.wed); assert(getDayOfWeek(SysTime(Date(1, 1, 4)).dayOfGregorianCal) == DayOfWeek.thu); assert(getDayOfWeek(SysTime(Date(1, 1, 5)).dayOfGregorianCal) == DayOfWeek.fri); assert(getDayOfWeek(SysTime(Date(1, 1, 6)).dayOfGregorianCal) == DayOfWeek.sat); assert(getDayOfWeek(SysTime(Date(1, 1, 7)).dayOfGregorianCal) == DayOfWeek.sun); assert(getDayOfWeek(SysTime(Date(1, 1, 8)).dayOfGregorianCal) == DayOfWeek.mon); assert(getDayOfWeek(SysTime(Date(1, 1, 9)).dayOfGregorianCal) == DayOfWeek.tue); assert(getDayOfWeek(SysTime(Date(2, 1, 1)).dayOfGregorianCal) == DayOfWeek.tue); assert(getDayOfWeek(SysTime(Date(3, 1, 1)).dayOfGregorianCal) == DayOfWeek.wed); assert(getDayOfWeek(SysTime(Date(4, 1, 1)).dayOfGregorianCal) == DayOfWeek.thu); assert(getDayOfWeek(SysTime(Date(5, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); assert(getDayOfWeek(SysTime(Date(2000, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); assert(getDayOfWeek(SysTime(Date(2010, 8, 22)).dayOfGregorianCal) == DayOfWeek.sun); assert(getDayOfWeek(SysTime(Date(2010, 8, 23)).dayOfGregorianCal) == DayOfWeek.mon); assert(getDayOfWeek(SysTime(Date(2010, 8, 24)).dayOfGregorianCal) == DayOfWeek.tue); assert(getDayOfWeek(SysTime(Date(2010, 8, 25)).dayOfGregorianCal) == DayOfWeek.wed); assert(getDayOfWeek(SysTime(Date(2010, 8, 26)).dayOfGregorianCal) == DayOfWeek.thu); assert(getDayOfWeek(SysTime(Date(2010, 8, 27)).dayOfGregorianCal) == DayOfWeek.fri); assert(getDayOfWeek(SysTime(Date(2010, 8, 28)).dayOfGregorianCal) == DayOfWeek.sat); assert(getDayOfWeek(SysTime(Date(2010, 8, 29)).dayOfGregorianCal) == DayOfWeek.sun); //Test B.C. assert(getDayOfWeek(SysTime(Date(0, 12, 31)).dayOfGregorianCal) == DayOfWeek.sun); assert(getDayOfWeek(SysTime(Date(0, 12, 30)).dayOfGregorianCal) == DayOfWeek.sat); assert(getDayOfWeek(SysTime(Date(0, 12, 29)).dayOfGregorianCal) == DayOfWeek.fri); assert(getDayOfWeek(SysTime(Date(0, 12, 28)).dayOfGregorianCal) == DayOfWeek.thu); assert(getDayOfWeek(SysTime(Date(0, 12, 27)).dayOfGregorianCal) == DayOfWeek.wed); assert(getDayOfWeek(SysTime(Date(0, 12, 26)).dayOfGregorianCal) == DayOfWeek.tue); assert(getDayOfWeek(SysTime(Date(0, 12, 25)).dayOfGregorianCal) == DayOfWeek.mon); assert(getDayOfWeek(SysTime(Date(0, 12, 24)).dayOfGregorianCal) == DayOfWeek.sun); assert(getDayOfWeek(SysTime(Date(0, 12, 23)).dayOfGregorianCal) == DayOfWeek.sat); } /+ Returns the string representation of the given month. +/ string monthToString(Month month) @safe pure { import std.format : format; assert(month >= Month.jan && month <= Month.dec, format("Invalid month: %s", month)); return _monthNames[month - Month.jan]; } unittest { assert(monthToString(Month.jan) == "Jan"); assert(monthToString(Month.feb) == "Feb"); assert(monthToString(Month.mar) == "Mar"); assert(monthToString(Month.apr) == "Apr"); assert(monthToString(Month.may) == "May"); assert(monthToString(Month.jun) == "Jun"); assert(monthToString(Month.jul) == "Jul"); assert(monthToString(Month.aug) == "Aug"); assert(monthToString(Month.sep) == "Sep"); assert(monthToString(Month.oct) == "Oct"); assert(monthToString(Month.nov) == "Nov"); assert(monthToString(Month.dec) == "Dec"); } /+ Returns the Month corresponding to the given string. Params: monthStr = The string representation of the month to get the Month for. Throws: $(LREF DateTimeException) if the given month is not a valid month string. +/ Month monthFromString(string monthStr) @safe pure { import std.format : format; switch(monthStr) { case "Jan": return Month.jan; case "Feb": return Month.feb; case "Mar": return Month.mar; case "Apr": return Month.apr; case "May": return Month.may; case "Jun": return Month.jun; case "Jul": return Month.jul; case "Aug": return Month.aug; case "Sep": return Month.sep; case "Oct": return Month.oct; case "Nov": return Month.nov; case "Dec": return Month.dec; default: throw new DateTimeException(format("Invalid month %s", monthStr)); } } unittest { foreach(badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY", "JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"]) { scope(failure) writeln(badStr); assertThrown!DateTimeException(monthFromString(badStr)); } foreach(month; EnumMembers!Month) { scope(failure) writeln(month); assert(monthFromString(monthToString(month)) == month); } } /+ The time units which are one step smaller than the given units. +/ template nextSmallerTimeUnits(string units) if(validTimeUnits(units) && timeStrings.front != units) { import std.algorithm : countUntil; enum nextSmallerTimeUnits = timeStrings[countUntil(timeStrings, units) - 1]; } unittest { assert(nextSmallerTimeUnits!"years" == "months"); assert(nextSmallerTimeUnits!"months" == "weeks"); assert(nextSmallerTimeUnits!"weeks" == "days"); assert(nextSmallerTimeUnits!"days" == "hours"); assert(nextSmallerTimeUnits!"hours" == "minutes"); assert(nextSmallerTimeUnits!"minutes" == "seconds"); assert(nextSmallerTimeUnits!"seconds" == "msecs"); assert(nextSmallerTimeUnits!"msecs" == "usecs"); assert(nextSmallerTimeUnits!"usecs" == "hnsecs"); static assert(!__traits(compiles, nextSmallerTimeUnits!"hnsecs")); } /+ The time units which are one step larger than the given units. +/ template nextLargerTimeUnits(string units) if(validTimeUnits(units) && timeStrings.back != units) { import std.algorithm : countUntil; enum nextLargerTimeUnits = timeStrings[countUntil(timeStrings, units) + 1]; } unittest { assert(nextLargerTimeUnits!"hnsecs" == "usecs"); assert(nextLargerTimeUnits!"usecs" == "msecs"); assert(nextLargerTimeUnits!"msecs" == "seconds"); assert(nextLargerTimeUnits!"seconds" == "minutes"); assert(nextLargerTimeUnits!"minutes" == "hours"); assert(nextLargerTimeUnits!"hours" == "days"); assert(nextLargerTimeUnits!"days" == "weeks"); assert(nextLargerTimeUnits!"weeks" == "months"); assert(nextLargerTimeUnits!"months" == "years"); static assert(!__traits(compiles, nextLargerTimeUnits!"years")); } /+ Returns the given hnsecs as an ISO string of fractional seconds. +/ static string fracSecsToISOString(int hnsecs) @safe pure nothrow { import std.format : format; assert(hnsecs >= 0); try { if(hnsecs == 0) return ""; string isoString = format(".%07d", hnsecs); while(isoString[$ - 1] == '0') isoString.popBack(); return isoString; } catch(Exception e) assert(0, "format() threw."); } unittest { assert(fracSecsToISOString(0) == ""); assert(fracSecsToISOString(1) == ".0000001"); assert(fracSecsToISOString(10) == ".000001"); assert(fracSecsToISOString(100) == ".00001"); assert(fracSecsToISOString(1000) == ".0001"); assert(fracSecsToISOString(10_000) == ".001"); assert(fracSecsToISOString(100_000) == ".01"); assert(fracSecsToISOString(1_000_000) == ".1"); assert(fracSecsToISOString(1_000_001) == ".1000001"); assert(fracSecsToISOString(1_001_001) == ".1001001"); assert(fracSecsToISOString(1_071_601) == ".1071601"); assert(fracSecsToISOString(1_271_641) == ".1271641"); assert(fracSecsToISOString(9_999_999) == ".9999999"); assert(fracSecsToISOString(9_999_990) == ".999999"); assert(fracSecsToISOString(9_999_900) == ".99999"); assert(fracSecsToISOString(9_999_000) == ".9999"); assert(fracSecsToISOString(9_990_000) == ".999"); assert(fracSecsToISOString(9_900_000) == ".99"); assert(fracSecsToISOString(9_000_000) == ".9"); assert(fracSecsToISOString(999) == ".0000999"); assert(fracSecsToISOString(9990) == ".000999"); assert(fracSecsToISOString(99_900) == ".00999"); assert(fracSecsToISOString(999_000) == ".0999"); } /+ Returns a Duration corresponding to to the given ISO string of fractional seconds. +/ static Duration fracSecsFromISOString(S)(in S isoString) @trusted pure if(isSomeString!S) { import std.ascii : isDigit; import std.string : representation; import std.conv : to; import std.algorithm : all; if(isoString.empty) return Duration.zero; auto str = isoString.representation; enforce(str[0] == '.', new DateTimeException("Invalid ISO String")); str.popFront(); enforce(!str.empty && str.length <= 7, new DateTimeException("Invalid ISO String")); enforce(all!isDigit(str), new DateTimeException("Invalid ISO String")); dchar[7] fullISOString = void; foreach(i, ref dchar c; fullISOString) { if(i < str.length) c = str[i]; else c = '0'; } return hnsecs(to!int(fullISOString[])); } unittest { static void testFSInvalid(string isoString) { fracSecsFromISOString(isoString); } assertThrown!DateTimeException(testFSInvalid(".")); assertThrown!DateTimeException(testFSInvalid("0.")); assertThrown!DateTimeException(testFSInvalid("0")); assertThrown!DateTimeException(testFSInvalid("0000000")); assertThrown!DateTimeException(testFSInvalid(".00000000")); assertThrown!DateTimeException(testFSInvalid(".00000001")); assertThrown!DateTimeException(testFSInvalid("T")); assertThrown!DateTimeException(testFSInvalid("T.")); assertThrown!DateTimeException(testFSInvalid(".T")); assert(fracSecsFromISOString("") == Duration.zero); assert(fracSecsFromISOString(".0000001") == hnsecs(1)); assert(fracSecsFromISOString(".000001") == hnsecs(10)); assert(fracSecsFromISOString(".00001") == hnsecs(100)); assert(fracSecsFromISOString(".0001") == hnsecs(1000)); assert(fracSecsFromISOString(".001") == hnsecs(10_000)); assert(fracSecsFromISOString(".01") == hnsecs(100_000)); assert(fracSecsFromISOString(".1") == hnsecs(1_000_000)); assert(fracSecsFromISOString(".1000001") == hnsecs(1_000_001)); assert(fracSecsFromISOString(".1001001") == hnsecs(1_001_001)); assert(fracSecsFromISOString(".1071601") == hnsecs(1_071_601)); assert(fracSecsFromISOString(".1271641") == hnsecs(1_271_641)); assert(fracSecsFromISOString(".9999999") == hnsecs(9_999_999)); assert(fracSecsFromISOString(".9999990") == hnsecs(9_999_990)); assert(fracSecsFromISOString(".999999") == hnsecs(9_999_990)); assert(fracSecsFromISOString(".9999900") == hnsecs(9_999_900)); assert(fracSecsFromISOString(".99999") == hnsecs(9_999_900)); assert(fracSecsFromISOString(".9999000") == hnsecs(9_999_000)); assert(fracSecsFromISOString(".9999") == hnsecs(9_999_000)); assert(fracSecsFromISOString(".9990000") == hnsecs(9_990_000)); assert(fracSecsFromISOString(".999") == hnsecs(9_990_000)); assert(fracSecsFromISOString(".9900000") == hnsecs(9_900_000)); assert(fracSecsFromISOString(".9900") == hnsecs(9_900_000)); assert(fracSecsFromISOString(".99") == hnsecs(9_900_000)); assert(fracSecsFromISOString(".9000000") == hnsecs(9_000_000)); assert(fracSecsFromISOString(".9") == hnsecs(9_000_000)); assert(fracSecsFromISOString(".0000999") == hnsecs(999)); assert(fracSecsFromISOString(".0009990") == hnsecs(9990)); assert(fracSecsFromISOString(".000999") == hnsecs(9990)); assert(fracSecsFromISOString(".0099900") == hnsecs(99_900)); assert(fracSecsFromISOString(".00999") == hnsecs(99_900)); assert(fracSecsFromISOString(".0999000") == hnsecs(999_000)); assert(fracSecsFromISOString(".0999") == hnsecs(999_000)); } /+ Strips what RFC 5322, section 3.2.2 refers to as CFWS from the left-hand side of the given range (it strips comments delimited by $(D '(') and $(D ')') as well as folding whitespace). It is assumed that the given range contains the value of a header field and no terminating CRLF for the line (though the CRLF for folding whitespace is of course expected and stripped) and thus that the only case of CR or LF is in folding whitespace. If a comment does not terminate correctly (e.g. mismatched parens) or if the the FWS is malformed, then the range will be empty when stripCWFS is done. However, only minimal validation of the content is done (e.g. quoted pairs within a comment aren't validated beyond \$LPAREN or \$RPAREN, because they're inside a comment, and thus their value doesn't matter anyway). It's only when the content does not conform to the grammar rules for FWS and thus literally cannot be parsed that content is considered invalid, and an empty range is returned. Note that _stripCFWS is eager, not lazy. It does not create a new range. Rather, it pops off the CFWS from the range and returns it. +/ R _stripCFWS(R)(R range) if(isRandomAccessRange!R && hasSlicing!R && hasLength!R && (is(Unqual!(ElementType!R) == char) || is(Unqual!(ElementType!R) == ubyte))) { immutable e = range.length; outer: for(size_t i = 0; i < e; ) { switch(range[i]) { case ' ': case '\t': { ++i; break; } case '\r': { if(i + 2 < e && range[i + 1] == '\n' && (range[i + 2] == ' ' || range[i + 2] == '\t')) { i += 3; break; } break outer; } case '\n': { if(i + 1 < e && (range[i + 1] == ' ' || range[i + 1] == '\t')) { i += 2; break; } break outer; } case '(': { ++i; size_t commentLevel = 1; while(i < e) { if(range[i] == '(') ++commentLevel; else if(range[i] == ')') { ++i; if(--commentLevel == 0) continue outer; continue; } else if(range[i] == '\\') { if(++i == e) break outer; } ++i; } break outer; } default: return range[i .. e]; } } return range[e .. e]; } unittest { import std.algorithm; import std.meta; import std.string; import std.typecons; foreach(cr; AliasSeq!(function(string a){return cast(ubyte[])a;}, function(string a){return map!(b => cast(char)b)(a.representation);})) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 scope(failure) writeln(typeof(cr).stringof); assert(_stripCFWS(cr("")).empty); assert(_stripCFWS(cr("\r")).empty); assert(_stripCFWS(cr("\r\n")).empty); assert(_stripCFWS(cr("\r\n ")).empty); assert(_stripCFWS(cr(" \t\r\n")).empty); assert(equal(_stripCFWS(cr(" \t\r\n hello")), cr("hello"))); assert(_stripCFWS(cr(" \t\r\nhello")).empty); assert(_stripCFWS(cr(" \t\r\n\v")).empty); assert(equal(_stripCFWS(cr("\v \t\r\n\v")), cr("\v \t\r\n\v"))); assert(_stripCFWS(cr("()")).empty); assert(_stripCFWS(cr("(hello world)")).empty); assert(_stripCFWS(cr("(hello world)(hello world)")).empty); assert(_stripCFWS(cr("(hello world\r\n foo\r where's\nwaldo)")).empty); assert(_stripCFWS(cr(" \t (hello \tworld\r\n foo\r where's\nwaldo)\t\t ")).empty); assert(_stripCFWS(cr(" ")).empty); assert(_stripCFWS(cr("\t\t\t")).empty); assert(_stripCFWS(cr("\t \r\n\r \n")).empty); assert(_stripCFWS(cr("(hello world) (can't find waldo) (he's lost)")).empty); assert(_stripCFWS(cr("(hello\\) world) (can't \\(find waldo) (he's \\(\\)lost)")).empty); assert(_stripCFWS(cr("(((((")).empty); assert(_stripCFWS(cr("(((()))")).empty); assert(_stripCFWS(cr("(((())))")).empty); assert(equal(_stripCFWS(cr("(((()))))")), cr(")"))); assert(equal(_stripCFWS(cr(")))))")), cr(")))))"))); assert(equal(_stripCFWS(cr("()))))")), cr("))))"))); assert(equal(_stripCFWS(cr(" hello hello ")), cr("hello hello "))); assert(equal(_stripCFWS(cr("\thello (world)")), cr("hello (world)"))); assert(equal(_stripCFWS(cr(" \r\n \\((\\)) foo")), cr("\\((\\)) foo"))); assert(equal(_stripCFWS(cr(" \r\n (\\((\\))) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" \r\n (\\(())) foo")), cr(") foo"))); assert(_stripCFWS(cr(" \r\n (((\\))) foo")).empty); assert(_stripCFWS(cr("(hello)(hello)")).empty); assert(_stripCFWS(cr(" \r\n (hello)\r\n (hello)")).empty); assert(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n ")).empty); assert(_stripCFWS(cr("\t\t\t\t(hello)\t\t\t\t(hello)\t\t\t\t")).empty); assert(equal(_stripCFWS(cr(" \r\n (hello)\r\n (hello) \r\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\r\n\t(hello)\t\r\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\t\r\n\t(hello)\t\r\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n \r\n (hello) \r\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n \r\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \r\n \r\n (hello)\t\r\n (hello) \r\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \r\n\t\r\n\t(hello)\t\r\n (hello) \r\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" (\r\n ( \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" (\t\r\n ( \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" (\r\n\t( \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n (\t\r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n (\r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n (\r\n\t) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\t\r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n\t) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) \r\n foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\t\r\n foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\r\n foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" (\t\r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" (\r\n \r\n\t( \r\n \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" (\r\n \r\n( \r\n \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n\t) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\t\r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n bar \r\n ( \r\n bar \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n () \r\n ( \r\n () \r\n ) \r\n ) foo")), cr("foo"))); assert(equal(_stripCFWS(cr(" ( \r\n \\\\ \r\n ( \r\n \\\\ \r\n ) \r\n ) foo")), cr("foo"))); assert(_stripCFWS(cr("(hello)(hello)")).empty); assert(_stripCFWS(cr(" \n (hello)\n (hello) \n ")).empty); assert(_stripCFWS(cr(" \n (hello) \n (hello) \n ")).empty); assert(equal(_stripCFWS(cr(" \n (hello)\n (hello) \n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n hello")), cr("hello"))); assert(equal(_stripCFWS(cr("\t\n\t(hello)\n\t(hello)\t\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr("\t\n\t(hello)\t\n\t(hello)\t\n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \n (hello) \n \n (hello) \n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n \n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \n \n (hello)\t\n (hello) \n hello")), cr("hello"))); assert(equal(_stripCFWS(cr(" \n\t\n\t(hello)\t\n (hello) \n hello")), cr("hello"))); }(); } // This is so that we don't have to worry about std.conv.to throwing. It also // doesn't have to worry about quite as many cases as std.conv.to, since it // doesn't have to worry about a sign on the value or about whether it fits. T _convDigits(T, R)(R str) if(isIntegral!T && isSigned!T) // The constraints on R were already covered by parseRFC822DateTime. { import std.ascii : isDigit; assert(!str.empty); T num = 0; foreach(i; 0 .. str.length) { if(i != 0) num *= 10; if(!isDigit(str[i])) return -1; num += str[i] - '0'; } return num; } unittest { import std.conv : to; import std.range; foreach(i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999])) { scope(failure) writeln(i); assert(_convDigits!int(to!string(i)) == i); } foreach(str; ["-42", "+42", "1a", "1 ", " ", " 42 "]) { scope(failure) writeln(str); assert(_convDigits!int(str) == -1); } } version(unittest) { import std.typecons; import std.algorithm; //Variables to help in testing. Duration currLocalDiffFromUTC; immutable (TimeZone)[] testTZs; //All of these helper arrays are sorted in ascending order. auto testYearsBC = [-1999, -1200, -600, -4, -1, 0]; auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012]; //I'd use a Tuple, but I get forward reference errors if I try. struct MonthDay { Month month; short day; this(int m, short d) { month = cast(Month)m; day = d; } } MonthDay[] testMonthDays = [MonthDay(1, 1), MonthDay(1, 2), MonthDay(3, 17), MonthDay(7, 4), MonthDay(10, 27), MonthDay(12, 30), MonthDay(12, 31)]; auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31]; auto testTODs = [TimeOfDay(0, 0, 0), TimeOfDay(0, 0, 1), TimeOfDay(0, 1, 0), TimeOfDay(1, 0, 0), TimeOfDay(13, 13, 13), TimeOfDay(23, 59, 59)]; auto testHours = [0, 1, 12, 22, 23]; auto testMinSecs = [0, 1, 30, 58, 59]; //Throwing exceptions is incredibly expensive, so we want to use a smaller //set of values for tests using assertThrown. auto testTODsThrown = [TimeOfDay(0, 0, 0), TimeOfDay(13, 13, 13), TimeOfDay(23, 59, 59)]; Date[] testDatesBC; Date[] testDatesAD; DateTime[] testDateTimesBC; DateTime[] testDateTimesAD; Duration[] testFracSecs; SysTime[] testSysTimesBC; SysTime[] testSysTimesAD; //I'd use a Tuple, but I get forward reference errors if I try. struct GregDay { int day; Date date; } auto testGregDaysBC = [GregDay(-1_373_427, Date(-3760, 9, 7)), //Start of the Hebrew Calendar GregDay(-735_233, Date(-2012, 1, 1)), GregDay(-735_202, Date(-2012, 2, 1)), GregDay(-735_175, Date(-2012, 2, 28)), GregDay(-735_174, Date(-2012, 2, 29)), GregDay(-735_173, Date(-2012, 3, 1)), GregDay(-734_502, Date(-2010, 1, 1)), GregDay(-734_472, Date(-2010, 1, 31)), GregDay(-734_471, Date(-2010, 2, 1)), GregDay(-734_444, Date(-2010, 2, 28)), GregDay(-734_443, Date(-2010, 3, 1)), GregDay(-734_413, Date(-2010, 3, 31)), GregDay(-734_412, Date(-2010, 4, 1)), GregDay(-734_383, Date(-2010, 4, 30)), GregDay(-734_382, Date(-2010, 5, 1)), GregDay(-734_352, Date(-2010, 5, 31)), GregDay(-734_351, Date(-2010, 6, 1)), GregDay(-734_322, Date(-2010, 6, 30)), GregDay(-734_321, Date(-2010, 7, 1)), GregDay(-734_291, Date(-2010, 7, 31)), GregDay(-734_290, Date(-2010, 8, 1)), GregDay(-734_260, Date(-2010, 8, 31)), GregDay(-734_259, Date(-2010, 9, 1)), GregDay(-734_230, Date(-2010, 9, 30)), GregDay(-734_229, Date(-2010, 10, 1)), GregDay(-734_199, Date(-2010, 10, 31)), GregDay(-734_198, Date(-2010, 11, 1)), GregDay(-734_169, Date(-2010, 11, 30)), GregDay(-734_168, Date(-2010, 12, 1)), GregDay(-734_139, Date(-2010, 12, 30)), GregDay(-734_138, Date(-2010, 12, 31)), GregDay(-731_215, Date(-2001, 1, 1)), GregDay(-730_850, Date(-2000, 1, 1)), GregDay(-730_849, Date(-2000, 1, 2)), GregDay(-730_486, Date(-2000, 12, 30)), GregDay(-730_485, Date(-2000, 12, 31)), GregDay(-730_484, Date(-1999, 1, 1)), GregDay(-694_690, Date(-1901, 1, 1)), GregDay(-694_325, Date(-1900, 1, 1)), GregDay(-585_118, Date(-1601, 1, 1)), GregDay(-584_753, Date(-1600, 1, 1)), GregDay(-584_388, Date(-1600, 12, 31)), GregDay(-584_387, Date(-1599, 1, 1)), GregDay(-365_972, Date(-1001, 1, 1)), GregDay(-365_607, Date(-1000, 1, 1)), GregDay(-183_351, Date(-501, 1, 1)), GregDay(-182_986, Date(-500, 1, 1)), GregDay(-182_621, Date(-499, 1, 1)), GregDay(-146_827, Date(-401, 1, 1)), GregDay(-146_462, Date(-400, 1, 1)), GregDay(-146_097, Date(-400, 12, 31)), GregDay(-110_302, Date(-301, 1, 1)), GregDay(-109_937, Date(-300, 1, 1)), GregDay(-73_778, Date(-201, 1, 1)), GregDay(-73_413, Date(-200, 1, 1)), GregDay(-38_715, Date(-105, 1, 1)), GregDay(-37_254, Date(-101, 1, 1)), GregDay(-36_889, Date(-100, 1, 1)), GregDay(-36_524, Date(-99, 1, 1)), GregDay(-36_160, Date(-99, 12, 31)), GregDay(-35_794, Date(-97, 1, 1)), GregDay(-18_627, Date(-50, 1, 1)), GregDay(-18_262, Date(-49, 1, 1)), GregDay(-3652, Date(-9, 1, 1)), GregDay(-2191, Date(-5, 1, 1)), GregDay(-1827, Date(-5, 12, 31)), GregDay(-1826, Date(-4, 1, 1)), GregDay(-1825, Date(-4, 1, 2)), GregDay(-1462, Date(-4, 12, 30)), GregDay(-1461, Date(-4, 12, 31)), GregDay(-1460, Date(-3, 1, 1)), GregDay(-1096, Date(-3, 12, 31)), GregDay(-1095, Date(-2, 1, 1)), GregDay(-731, Date(-2, 12, 31)), GregDay(-730, Date(-1, 1, 1)), GregDay(-367, Date(-1, 12, 30)), GregDay(-366, Date(-1, 12, 31)), GregDay(-365, Date(0, 1, 1)), GregDay(-31, Date(0, 11, 30)), GregDay(-30, Date(0, 12, 1)), GregDay(-1, Date(0, 12, 30)), GregDay(0, Date(0, 12, 31))]; auto testGregDaysAD = [GregDay(1, Date(1, 1, 1)), GregDay(2, Date(1, 1, 2)), GregDay(32, Date(1, 2, 1)), GregDay(365, Date(1, 12, 31)), GregDay(366, Date(2, 1, 1)), GregDay(731, Date(3, 1, 1)), GregDay(1096, Date(4, 1, 1)), GregDay(1097, Date(4, 1, 2)), GregDay(1460, Date(4, 12, 30)), GregDay(1461, Date(4, 12, 31)), GregDay(1462, Date(5, 1, 1)), GregDay(17_898, Date(50, 1, 1)), GregDay(35_065, Date(97, 1, 1)), GregDay(36_160, Date(100, 1, 1)), GregDay(36_525, Date(101, 1, 1)), GregDay(37_986, Date(105, 1, 1)), GregDay(72_684, Date(200, 1, 1)), GregDay(73_049, Date(201, 1, 1)), GregDay(109_208, Date(300, 1, 1)), GregDay(109_573, Date(301, 1, 1)), GregDay(145_732, Date(400, 1, 1)), GregDay(146_098, Date(401, 1, 1)), GregDay(182_257, Date(500, 1, 1)), GregDay(182_622, Date(501, 1, 1)), GregDay(364_878, Date(1000, 1, 1)), GregDay(365_243, Date(1001, 1, 1)), GregDay(584_023, Date(1600, 1, 1)), GregDay(584_389, Date(1601, 1, 1)), GregDay(693_596, Date(1900, 1, 1)), GregDay(693_961, Date(1901, 1, 1)), GregDay(729_755, Date(1999, 1, 1)), GregDay(730_120, Date(2000, 1, 1)), GregDay(730_121, Date(2000, 1, 2)), GregDay(730_484, Date(2000, 12, 30)), GregDay(730_485, Date(2000, 12, 31)), GregDay(730_486, Date(2001, 1, 1)), GregDay(733_773, Date(2010, 1, 1)), GregDay(733_774, Date(2010, 1, 2)), GregDay(733_803, Date(2010, 1, 31)), GregDay(733_804, Date(2010, 2, 1)), GregDay(733_831, Date(2010, 2, 28)), GregDay(733_832, Date(2010, 3, 1)), GregDay(733_862, Date(2010, 3, 31)), GregDay(733_863, Date(2010, 4, 1)), GregDay(733_892, Date(2010, 4, 30)), GregDay(733_893, Date(2010, 5, 1)), GregDay(733_923, Date(2010, 5, 31)), GregDay(733_924, Date(2010, 6, 1)), GregDay(733_953, Date(2010, 6, 30)), GregDay(733_954, Date(2010, 7, 1)), GregDay(733_984, Date(2010, 7, 31)), GregDay(733_985, Date(2010, 8, 1)), GregDay(734_015, Date(2010, 8, 31)), GregDay(734_016, Date(2010, 9, 1)), GregDay(734_045, Date(2010, 9, 30)), GregDay(734_046, Date(2010, 10, 1)), GregDay(734_076, Date(2010, 10, 31)), GregDay(734_077, Date(2010, 11, 1)), GregDay(734_106, Date(2010, 11, 30)), GregDay(734_107, Date(2010, 12, 1)), GregDay(734_136, Date(2010, 12, 30)), GregDay(734_137, Date(2010, 12, 31)), GregDay(734_503, Date(2012, 1, 1)), GregDay(734_534, Date(2012, 2, 1)), GregDay(734_561, Date(2012, 2, 28)), GregDay(734_562, Date(2012, 2, 29)), GregDay(734_563, Date(2012, 3, 1)), GregDay(734_858, Date(2012, 12, 21))]; //I'd use a Tuple, but I get forward reference errors if I try. struct DayOfYear { int day; MonthDay md; } auto testDaysOfYear = [DayOfYear(1, MonthDay(1, 1)), DayOfYear(2, MonthDay(1, 2)), DayOfYear(3, MonthDay(1, 3)), DayOfYear(31, MonthDay(1, 31)), DayOfYear(32, MonthDay(2, 1)), DayOfYear(59, MonthDay(2, 28)), DayOfYear(60, MonthDay(3, 1)), DayOfYear(90, MonthDay(3, 31)), DayOfYear(91, MonthDay(4, 1)), DayOfYear(120, MonthDay(4, 30)), DayOfYear(121, MonthDay(5, 1)), DayOfYear(151, MonthDay(5, 31)), DayOfYear(152, MonthDay(6, 1)), DayOfYear(181, MonthDay(6, 30)), DayOfYear(182, MonthDay(7, 1)), DayOfYear(212, MonthDay(7, 31)), DayOfYear(213, MonthDay(8, 1)), DayOfYear(243, MonthDay(8, 31)), DayOfYear(244, MonthDay(9, 1)), DayOfYear(273, MonthDay(9, 30)), DayOfYear(274, MonthDay(10, 1)), DayOfYear(304, MonthDay(10, 31)), DayOfYear(305, MonthDay(11, 1)), DayOfYear(334, MonthDay(11, 30)), DayOfYear(335, MonthDay(12, 1)), DayOfYear(363, MonthDay(12, 29)), DayOfYear(364, MonthDay(12, 30)), DayOfYear(365, MonthDay(12, 31))]; auto testDaysOfLeapYear = [DayOfYear(1, MonthDay(1, 1)), DayOfYear(2, MonthDay(1, 2)), DayOfYear(3, MonthDay(1, 3)), DayOfYear(31, MonthDay(1, 31)), DayOfYear(32, MonthDay(2, 1)), DayOfYear(59, MonthDay(2, 28)), DayOfYear(60, MonthDay(2, 29)), DayOfYear(61, MonthDay(3, 1)), DayOfYear(91, MonthDay(3, 31)), DayOfYear(92, MonthDay(4, 1)), DayOfYear(121, MonthDay(4, 30)), DayOfYear(122, MonthDay(5, 1)), DayOfYear(152, MonthDay(5, 31)), DayOfYear(153, MonthDay(6, 1)), DayOfYear(182, MonthDay(6, 30)), DayOfYear(183, MonthDay(7, 1)), DayOfYear(213, MonthDay(7, 31)), DayOfYear(214, MonthDay(8, 1)), DayOfYear(244, MonthDay(8, 31)), DayOfYear(245, MonthDay(9, 1)), DayOfYear(274, MonthDay(9, 30)), DayOfYear(275, MonthDay(10, 1)), DayOfYear(305, MonthDay(10, 31)), DayOfYear(306, MonthDay(11, 1)), DayOfYear(335, MonthDay(11, 30)), DayOfYear(336, MonthDay(12, 1)), DayOfYear(364, MonthDay(12, 29)), DayOfYear(365, MonthDay(12, 30)), DayOfYear(366, MonthDay(12, 31))]; void initializeTests() { immutable lt = LocalTime().utcToTZ(0); currLocalDiffFromUTC = dur!"hnsecs"(lt); immutable otherTZ = lt < 0 ? TimeZone.getTimeZone("Australia/Sydney") : TimeZone.getTimeZone("America/Denver"); immutable ot = otherTZ.utcToTZ(0); auto diffs = [0L, lt, ot]; auto diffAA = [0L : Rebindable!(immutable TimeZone)(UTC())]; diffAA[lt] = Rebindable!(immutable TimeZone)(LocalTime()); diffAA[ot] = Rebindable!(immutable TimeZone)(otherTZ); sort(diffs); testTZs = [diffAA[diffs[0]], diffAA[diffs[1]], diffAA[diffs[2]]]; testFracSecs = [Duration.zero, hnsecs(1), hnsecs(5007), hnsecs(9999999)]; foreach(year; testYearsBC) { foreach(md; testMonthDays) testDatesBC ~= Date(year, md.month, md.day); } foreach(year; testYearsAD) { foreach(md; testMonthDays) testDatesAD ~= Date(year, md.month, md.day); } foreach(dt; testDatesBC) { foreach(tod; testTODs) testDateTimesBC ~= DateTime(dt, tod); } foreach(dt; testDatesAD) { foreach(tod; testTODs) testDateTimesAD ~= DateTime(dt, tod); } foreach(dt; testDateTimesBC) { foreach(tz; testTZs) { foreach(fs; testFracSecs) testSysTimesBC ~= SysTime(dt, fs, tz); } } foreach(dt; testDateTimesAD) { foreach(tz; testTZs) { foreach(fs; testFracSecs) testSysTimesAD ~= SysTime(dt, fs, tz); } } } } unittest { /* Issue 6642 */ static assert(!hasUnsharedAliasing!Date); static assert(!hasUnsharedAliasing!TimeOfDay); static assert(!hasUnsharedAliasing!DateTime); static assert(!hasUnsharedAliasing!SysTime); } // This script is for regenerating tzDatabaseNameToWindowsTZName and // windowsTZNameToTZDatabaseName from // http://unicode.org/cldr/data/common/supplemental/windowsZones.xml /+ #!/bin/rdmd import std.algorithm; import std.array; import std.conv; import std.datetime; import std.exception; import std.path; import std.stdio; import std.string; int main(string[] args) { if(args.length != 4 || args[1].baseName != "windowsZones.xml") { stderr.writeln("genTZs.d windowsZones.xml "); return -1; } string[][string] win2Nix; string[][string] nix2Win; immutable f1 = ` %s", nix, wins)); // We'll try to eliminate multiples by favoring a conversion if it's already // in Phobos, but if it's new, then the correct one will have to be chosen // manually from the results. string[] haveMultiple; foreach(win, nixes; win2Nix) { if(nixes.length > 1) haveMultiple ~= win; } bool[string] haveConflicts; foreach(win; haveMultiple) { if(auto curr = windowsTZNameToTZDatabaseName(win)) { if(auto other = curr in nix2Win) { if((*other)[0] == win) { win2Nix[win] = [curr]; continue; } } } haveConflicts[win] = true; writefln("Warning: %s -> %s", win, win2Nix[win]); } string[] nix2WinLines = [ `string tzDatabaseNameToWindowsTZName(string tzName) @safe pure nothrow @nogc`, `{`, ` switch(tzName)`, ` {`]; foreach(nix; nix2Win.keys.sort()) nix2WinLines ~= format(` case "%s": return "%s";`, nix, nix2Win[nix][0]); nix2WinLines ~= [ ` default: return null;`, ` }`, `}`]; string[] win2NixLines = [ `string windowsTZNameToTZDatabaseName(string tzName) @safe pure nothrow @nogc`, `{`, ` switch(tzName)`, ` {`]; foreach(win; win2Nix.keys.sort()) { immutable hasMultiple = cast(bool)(win in haveConflicts); foreach(nix; win2Nix[win]) win2NixLines ~= format(` case "%s": return "%s";%s`, win, nix, hasMultiple ? " FIXME" : ""); } win2NixLines ~= [ ` default: return null;`, ` }`, `}`]; auto nix2WinFile = args[2]; std.file.write(nix2WinFile, nix2WinLines.join("\n")); auto win2NixFile = args[3]; std.file.write(win2NixFile, win2NixLines.join("\n")); return 0; } +/ ldc-1.1.0-beta3-src/runtime/phobos/std/internal/0000775000175000017500000000000012776215007017522 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/internal/unicode_norm.d0000664000175000017500000010663212776215007022360 0ustar kaikaimodule std.internal.unicode_norm; import std.internal.unicode_tables; static if(size_t.sizeof == 8) { //1600 bytes enum nfcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x60], [ 0x100, 0x100, 0x1a00], [ 0x302020202020100, 0x205020202020204, 0x602020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000, 0x200000000, 0x5000400030000, 0x8000000070006, 0xa0009, 0x0, 0xb000000000000, 0xc000000000000, 0xf0000000e000d, 0x0, 0x1000000000, 0x0, 0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14001300120000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x160015, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x170000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1800120012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10361f8081a9fdf, 0x401000000000003f, 0x80, 0x0, 0x0, 0x380000, 0x0, 0x0, 0x1000000000000000, 0xff000000, 0x4000000000000000, 0xb0800000, 0x48000000000000, 0x4e000000, 0x0, 0x0, 0x4000000000000000, 0x30c00000, 0x4000000000000000, 0x800000, 0x0, 0x400000, 0x0, 0x600004, 0x4000000000000000, 0x800000, 0x0, 0x80008400, 0x0, 0x168020010842008, 0x200108420080002, 0x0, 0x400000000000, 0x0, 0x0, 0x0, 0x0, 0x3ffffe00000000, 0xffffff0000000000, 0x7, 0x20000000000000, 0x0, 0x0, 0x0, 0x0, 0x2aaa000000000000, 0x4800000000000000, 0x2a00c80808080a00, 0x3, 0x0, 0x0, 0x0, 0xc4000000000, 0x0, 0x0, 0x0, 0x60000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0x0, 0x0, 0x6000000, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffc657fe53fff, 0xffff3fffffffffff, 0xffffffffffffffff, 0x3ffffff, 0x5f7ffc00a0000000, 0x7fdb, 0x0, 0x0, 0x0, 0x0, 0x400000000000000, 0x0, 0x8000000000, 0x0, 0x0, 0x0, 0x0, 0x1fc0000000, 0xf800000000000000, 0x1, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //1920 bytes enum nfdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x70], [ 0x100, 0x140, 0x2000], [ 0x504030202020100, 0x207020202020206, 0x802020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x5000600050004, 0x9000800070005, 0xc0005000b000a, 0x500050005000d, 0x5000500050005, 0xe000500050005, 0x10000f00050005, 0x14001300120011, 0x5000500050005, 0x5001500050005, 0x5000500050005, 0x5000500050016, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x17001700170017, 0x17001700170017, 0x17001700170017, 0x17001700170017, 0x17001700170017, 0x17001700170017, 0x17001700170017, 0x17001700170017, 0x17001700170017, 0x17001700170017, 0x18001700170017, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x1a001900170005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x50005001c001b, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x50005001d0005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5001e00170017, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x5000500050005, 0x0, 0x0, 0x0, 0xbe7effbf3e7effbf, 0x7ef1ff3ffffcffff, 0x7fffff3ffff3f1f8, 0x1800300000000, 0xff31ffcfdfffe000, 0xfffc0cfffffff, 0x0, 0x0, 0x0, 0x0, 0x401000000000001b, 0x1fc000001d7e0, 0x187c00, 0x20000000200708b, 0xc00000708b0000, 0x0, 0x33ffcfcfccf0006, 0x0, 0x0, 0x0, 0x0, 0x7c00000000, 0x0, 0x0, 0x80005, 0x12020000000000, 0xff000000, 0x0, 0xb0001800, 0x48000000000000, 0x4e000000, 0x0, 0x0, 0x0, 0x30001900, 0x100000, 0x1c00, 0x0, 0x100, 0x0, 0xd81, 0x0, 0x1c00, 0x0, 0x74000000, 0x0, 0x168020010842008, 0x200108420080002, 0x0, 0x4000000000, 0x0, 0x0, 0x0, 0x2800000000045540, 0xb, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0bffffff, 0x3ffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x3fdcffffefcfffde, 0x3, 0x0, 0x0, 0x0, 0xc4000000000, 0x0, 0x40000c000000, 0xe000, 0x5000001210, 0x333e00500000292, 0xf00000000333, 0x3c0f00000000, 0x60000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0x0, 0x36db02a555555000, 0x5555500040100000, 0x4790000036db02a5, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffff, 0x0, 0xfffffc657fe53fff, 0xffff3fffffffffff, 0xffffffffffffffff, 0x3ffffff, 0x5f7ffc00a0000000, 0x7fdb, 0x0, 0x0, 0x0, 0x0, 0x80014000000, 0x0, 0xc00000000000, 0x0, 0x0, 0x0, 0x0, 0x1fc0000000, 0xf800000000000000, 0x1, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2560 bytes enum nfkcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x70], [ 0x100, 0x140, 0x3400], [ 0x402030202020100, 0x706020202020205, 0x802020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x4000600050004, 0x9000800070004, 0xd000c000b000a, 0x40004000f000e, 0x4000400040004, 0x10000400040004, 0x13001200110004, 0x17001600150014, 0x4000400040018, 0x4001900040004, 0x1d001c001b001a, 0x210020001f001e, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x22000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x24002300210004, 0x27002600250021, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400290028, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x40004002a0004, 0x2e002d002c002b, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4002f00040004, 0x4003100300004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4003200210021, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x4000400040004, 0x0, 0x0, 0x773c850100000000, 0x0, 0x800c000000000000, 0x8000000000000201, 0x0, 0xe000000001ff0, 0x0, 0x0, 0x1ff000000000000, 0x1f3f000000, 0x10361f8081a9fdf, 0x441000000000003f, 0xb0, 0x2370000007f0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x1e0000000380000, 0x0, 0x0, 0x1000000000000000, 0xff000000, 0x4000000000000000, 0xb0800000, 0x48000000000000, 0x4e000000, 0x0, 0x0, 0x4000000000000000, 0x30c00000, 0x4000000000000000, 0x800000, 0x0, 0x400000, 0x0, 0x600004, 0x4000000000000000, 0x800000, 0x0, 0x80008400, 0x8000000000000, 0x0, 0x8000000000000, 0x30000000, 0x1000, 0x3e8020010842008, 0x200108420080002, 0x0, 0x400000000000, 0x0, 0x0, 0x1000000000000000, 0x0, 0x3ffffe00000000, 0xffffff0000000000, 0x7, 0x20000000000000, 0x0, 0x0, 0x0, 0xf7ff700000000000, 0x10007ffffffbfff, 0xfffffffff8000000, 0x0, 0x0, 0x0, 0xc000000, 0x0, 0x0, 0x2aaa000000000000, 0xe800000000000000, 0x6a00e808e808ea03, 0x50d88070008207ff, 0xfff3000080800380, 0x1001fff7fff, 0x0, 0xfbfbbd573e6ffeef, 0xffffffffffff03e1, 0x200, 0x0, 0x1b00000000000, 0x0, 0x0, 0x0, 0x60000000000, 0x0, 0x0, 0x0, 0x0, 0xffffffff00000000, 0xffffffffffffffff, 0x7ffffffffff, 0x1000, 0x70000000000000, 0x0, 0x10000000, 0x0, 0x3000000000000000, 0x0, 0x0, 0x0, 0x800000000000, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x8000000000000, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffff, 0x740000000000001, 0x0, 0x9e000000, 0x8000000000000000, 0xfffe000000000000, 0xffffffffffffffff, 0xfffc7fff, 0x0, 0xffffffff7fffffff, 0x7fffffffffff00ff, 0xffffffffffffffff, 0x7fffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0x1000000000000, 0x0, 0x300000000000000, 0xfffffc657fe53fff, 0xffff3fffffffffff, 0xffffffffffffffff, 0x3ffffff, 0x5f7fffffa0f8007f, 0xffffffffffffffdb, 0x3ffffffffffff, 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, 0x1fff0000000000ff, 0xffff000003ff0000, 0xffd70f7ffff7ff9f, 0xffffffffffffffff, 0x1fffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff, 0x7fffffffffffffff, 0x7f7f1cfcfcfc, 0x0, 0x0, 0x400000000000000, 0x0, 0x8000000000, 0x0, 0x0, 0x0, 0x0, 0x1fc0000000, 0xf800000000000000, 0x1, 0xffffffffffffffff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffff3fffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffcfff, 0xaf7fe96ffffffef, 0x5ef7f796aa96ea84, 0xffffbee0ffffbff, 0x0, 0xffff7fffffff07ff, 0xc000000ffff, 0x10000, 0x0, 0x7ffffffffff0007, 0x301ff, 0x0, 0x0, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2656 bytes enum nfkdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x78], [ 0x100, 0x160, 0x3500], [ 0x504030202020100, 0x807020202020206, 0x902020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x7000600050004, 0xa000900080007, 0xe000d000c000b, 0x700070007000f, 0x7000700070007, 0x10000700070007, 0x13001200110007, 0x17001600150014, 0x7000700070018, 0x7001900070007, 0x1d001c001b001a, 0x210020001f001e, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x22000700070007, 0x7000700070007, 0x21002100210021, 0x21002100210021, 0x21002100210021, 0x21002100210021, 0x21002100210021, 0x21002100210021, 0x21002100210021, 0x21002100210021, 0x21002100210021, 0x21002100210021, 0x23002100210021, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x25002400210007, 0x28002700260021, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x70007002a0029, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x70007002b0007, 0x2f002e002d002c, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7003000070007, 0x7003200310007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7003300210021, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x0, 0x0, 0x773c850100000000, 0xbe7effbf3e7effbf, 0xfefdff3ffffcffff, 0xffffff3ffff3f3f9, 0x1800300000000, 0xff3fffcfdffffff0, 0xfffc0cfffffff, 0x0, 0x1ff000000000000, 0x1f3f000000, 0x0, 0x441000000000001b, 0x1fc000001d7f0, 0x2370000007f7c00, 0x20000000200708b, 0xc00000708b0000, 0x0, 0x33ffcfcfccf0006, 0x0, 0x0, 0x80, 0x0, 0x7c00000000, 0x1e0000000000000, 0x0, 0x80005, 0x0, 0x0, 0x0, 0x0, 0x12020000000000, 0xff000000, 0x0, 0xb0001800, 0x48000000000000, 0x4e000000, 0x0, 0x0, 0x0, 0x30001900, 0x100000, 0x1c00, 0x0, 0x100, 0x0, 0xd81, 0x0, 0x1c00, 0x0, 0x74000000, 0x8000000000000, 0x0, 0x8000000000000, 0x30000000, 0x1000, 0x3e8020010842008, 0x200108420080002, 0x0, 0x4000000000, 0x0, 0x0, 0x1000000000000000, 0x2800000000045540, 0xb, 0x0, 0x0, 0xf7ff700000000000, 0x10007ffffffbfff, 0xfffffffff8000000, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0fffffff, 0x3ffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0xffdfffffffffffff, 0x7fdcffffefcfffdf, 0x50d88070008207ff, 0xfff3000080800380, 0x1001fff7fff, 0x0, 0xfbfbbd573e6ffeef, 0xffffffffffff03e1, 0x40000c000200, 0xe000, 0x1b05000001210, 0x333e00500000292, 0xf00000000333, 0x3c0f00000000, 0x60000000000, 0x0, 0x0, 0x0, 0x0, 0xffffffff00000000, 0xffffffffffffffff, 0x7ffffffffff, 0x1000, 0x70000000000000, 0x0, 0x10000000, 0x0, 0x3000000000000000, 0x0, 0x0, 0x0, 0x800000000000, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x8000000000000, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffff, 0x740000000000001, 0x36db02a555555000, 0x55555000d8100000, 0xc790000036db02a5, 0xfffe000000000000, 0xffffffffffffffff, 0xfffc7fff, 0x0, 0xffffffff7fffffff, 0x7fffffffffff00ff, 0xffffffffffffffff, 0x7fffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0x1000000000000, 0x0, 0x300000000000000, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffff, 0x0, 0xfffffc657fe53fff, 0xffff3fffffffffff, 0xffffffffffffffff, 0x3ffffff, 0x5f7fffffa0f8007f, 0xffffffffffffffdb, 0x3ffffffffffff, 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, 0x1fff0000000000ff, 0xffff000003ff0000, 0xffd70f7ffff7ff9f, 0xffffffffffffffff, 0x1fffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff, 0x7fffffffffffffff, 0x7f7f1cfcfcfc, 0x0, 0x0, 0x80014000000, 0x0, 0xc00000000000, 0x0, 0x0, 0x0, 0x0, 0x1fc0000000, 0xf800000000000000, 0x1, 0xffffffffffffffff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffff3fffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffcfff, 0xaf7fe96ffffffef, 0x5ef7f796aa96ea84, 0xffffbee0ffffbff, 0x0, 0xffff7fffffff07ff, 0xc000000ffff, 0x10000, 0x0, 0x7ffffffffff0007, 0x301ff, 0x0, 0x0, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); } static if(size_t.sizeof == 4) { //1600 bytes enum nfcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xc0], [ 0x100, 0x100, 0x1a00], [ 0x2020100, 0x3020202, 0x2020204, 0x2050202, 0x2020202, 0x6020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x0, 0x2, 0x30000, 0x50004, 0x70006, 0x80000, 0xa0009, 0x0, 0x0, 0x0, 0x0, 0xb0000, 0x0, 0xc0000, 0xe000d, 0xf0000, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x120000, 0x140013, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x160015, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x170000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x120012, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x81a9fdf, 0x10361f8, 0x3f, 0x40100000, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x380000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0xff000000, 0x0, 0x0, 0x40000000, 0xb0800000, 0x0, 0x0, 0x480000, 0x4e000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000, 0x30c00000, 0x0, 0x0, 0x40000000, 0x800000, 0x0, 0x0, 0x0, 0x400000, 0x0, 0x0, 0x0, 0x600004, 0x0, 0x0, 0x40000000, 0x800000, 0x0, 0x0, 0x0, 0x80008400, 0x0, 0x0, 0x0, 0x10842008, 0x1680200, 0x20080002, 0x2001084, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ffffe, 0x0, 0xffffff00, 0x7, 0x0, 0x0, 0x200000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2aaa0000, 0x0, 0x48000000, 0x8080a00, 0x2a00c808, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000000, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fe53fff, 0xfffffc65, 0xffffffff, 0xffff3fff, 0xffffffff, 0xffffffff, 0x3ffffff, 0x0, 0xa0000000, 0x5f7ffc00, 0x7fdb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x1f, 0x0, 0xf8000000, 0x1, 0x0, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //1920 bytes enum nfdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xe0], [ 0x100, 0x140, 0x2000], [ 0x2020100, 0x5040302, 0x2020206, 0x2070202, 0x2020202, 0x8020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x50006, 0x70005, 0x90008, 0xb000a, 0xc0005, 0x5000d, 0x50005, 0x50005, 0x50005, 0x50005, 0xe0005, 0x50005, 0x10000f, 0x120011, 0x140013, 0x50005, 0x50005, 0x50005, 0x50015, 0x50005, 0x50005, 0x50016, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x170017, 0x180017, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x170005, 0x1a0019, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x1c001b, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x1d0005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x170017, 0x5001e, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x50005, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e7effbf, 0xbe7effbf, 0xfffcffff, 0x7ef1ff3f, 0xfff3f1f8, 0x7fffff3f, 0x0, 0x18003, 0xdfffe000, 0xff31ffcf, 0xcfffffff, 0xfffc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x40100000, 0x1d7e0, 0x1fc00, 0x187c00, 0x0, 0x200708b, 0x2000000, 0x708b0000, 0xc00000, 0x0, 0x0, 0xfccf0006, 0x33ffcfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 0x0, 0x0, 0x80005, 0x0, 0x0, 0x120200, 0xff000000, 0x0, 0x0, 0x0, 0xb0001800, 0x0, 0x0, 0x480000, 0x4e000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30001900, 0x0, 0x100000, 0x0, 0x1c00, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0, 0x0, 0xd81, 0x0, 0x0, 0x0, 0x1c00, 0x0, 0x0, 0x0, 0x74000000, 0x0, 0x0, 0x0, 0x10842008, 0x1680200, 0x20080002, 0x2001084, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x45540, 0x28000000, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xbffffff, 0xffffffff, 0xffffffff, 0x3ffffff, 0x3f3fffff, 0xffffffff, 0xaaff3f3f, 0x3fffffff, 0xffffffff, 0x5fdfffff, 0xefcfffde, 0x3fdcffff, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc40, 0x0, 0x0, 0xc000000, 0x4000, 0xe000, 0x0, 0x1210, 0x50, 0x292, 0x333e005, 0x333, 0xf000, 0x0, 0x3c0f, 0x0, 0x600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0x0, 0x0, 0x0, 0x55555000, 0x36db02a5, 0x40100000, 0x55555000, 0x36db02a5, 0x47900000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf, 0x0, 0x0, 0x7fe53fff, 0xfffffc65, 0xffffffff, 0xffff3fff, 0xffffffff, 0xffffffff, 0x3ffffff, 0x0, 0xa0000000, 0x5f7ffc00, 0x7fdb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14000000, 0x800, 0x0, 0x0, 0x0, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x1f, 0x0, 0xf8000000, 0x1, 0x0, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2560 bytes enum nfkcQCTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xe0], [ 0x100, 0x140, 0x3400], [ 0x2020100, 0x4020302, 0x2020205, 0x7060202, 0x2020202, 0x8020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x40006, 0x70004, 0x90008, 0xb000a, 0xd000c, 0xf000e, 0x40004, 0x40004, 0x40004, 0x40004, 0x100004, 0x110004, 0x130012, 0x150014, 0x170016, 0x40018, 0x40004, 0x40004, 0x40019, 0x1b001a, 0x1d001c, 0x1f001e, 0x210020, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x220004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x210004, 0x240023, 0x250021, 0x270026, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x290028, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x2a0004, 0x40004, 0x2c002b, 0x2e002d, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x4002f, 0x300004, 0x40031, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x210021, 0x40032, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x40004, 0x0, 0x0, 0x0, 0x0, 0x0, 0x773c8501, 0x0, 0x0, 0x0, 0x800c0000, 0x201, 0x80000000, 0x0, 0x0, 0x1ff0, 0xe0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1ff0000, 0x3f000000, 0x1f, 0x81a9fdf, 0x10361f8, 0x3f, 0x44100000, 0xb0, 0x0, 0x7f0000, 0x2370000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x380000, 0x1e00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0xff000000, 0x0, 0x0, 0x40000000, 0xb0800000, 0x0, 0x0, 0x480000, 0x4e000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000, 0x30c00000, 0x0, 0x0, 0x40000000, 0x800000, 0x0, 0x0, 0x0, 0x400000, 0x0, 0x0, 0x0, 0x600004, 0x0, 0x0, 0x40000000, 0x800000, 0x0, 0x0, 0x0, 0x80008400, 0x0, 0x0, 0x80000, 0x0, 0x0, 0x0, 0x80000, 0x30000000, 0x0, 0x1000, 0x0, 0x10842008, 0x3e80200, 0x20080002, 0x2001084, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0x0, 0x0, 0x0, 0x3ffffe, 0x0, 0xffffff00, 0x7, 0x0, 0x0, 0x200000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf7ff7000, 0xffffbfff, 0x10007ff, 0xf8000000, 0xffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2aaa0000, 0x0, 0xe8000000, 0xe808ea03, 0x6a00e808, 0x8207ff, 0x50d88070, 0x80800380, 0xfff30000, 0x1fff7fff, 0x100, 0x0, 0x0, 0x3e6ffeef, 0xfbfbbd57, 0xffff03e1, 0xffffffff, 0x200, 0x0, 0x0, 0x0, 0x0, 0x1b000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ff, 0x1000, 0x0, 0x0, 0x700000, 0x0, 0x0, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x30000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0x80000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffff, 0x0, 0x1, 0x7400000, 0x0, 0x0, 0x9e000000, 0x0, 0x0, 0x80000000, 0x0, 0xfffe0000, 0xffffffff, 0xffffffff, 0xfffc7fff, 0x0, 0x0, 0x0, 0x7fffffff, 0xffffffff, 0xffff00ff, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x0, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x3000000, 0x7fe53fff, 0xfffffc65, 0xffffffff, 0xffff3fff, 0xffffffff, 0xffffffff, 0x3ffffff, 0x0, 0xa0f8007f, 0x5f7fffff, 0xffffffdb, 0xffffffff, 0xffffffff, 0x3ffff, 0xfff80000, 0xffffffff, 0xffffffff, 0x3fffffff, 0xffff0000, 0xffffffff, 0xfffcffff, 0xffffffff, 0xff, 0x1fff0000, 0x3ff0000, 0xffff0000, 0xfff7ff9f, 0xffd70f7f, 0xffffffff, 0xffffffff, 0xffffffff, 0x1fffffff, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff, 0x1cfcfcfc, 0x7f7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x1f, 0x0, 0xf8000000, 0x1, 0x0, 0xffffffff, 0xffffffff, 0xffdfffff, 0xffffffff, 0xdfffffff, 0xebffde64, 0xffffffef, 0xffffffff, 0xdfdfe7bf, 0x7bffffff, 0xfffdfc5f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff3f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffcfff, 0xffffffff, 0xffffffef, 0xaf7fe96, 0xaa96ea84, 0x5ef7f796, 0xffffbff, 0xffffbee, 0x0, 0x0, 0xffff07ff, 0xffff7fff, 0xffff, 0xc00, 0x10000, 0x0, 0x0, 0x0, 0xffff0007, 0x7ffffff, 0x301ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2656 bytes enum nfkdQCTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xf0], [ 0x100, 0x160, 0x3500], [ 0x2020100, 0x5040302, 0x2020206, 0x8070202, 0x2020202, 0x9020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x80007, 0xa0009, 0xc000b, 0xe000d, 0x7000f, 0x70007, 0x70007, 0x70007, 0x70007, 0x100007, 0x110007, 0x130012, 0x150014, 0x170016, 0x70018, 0x70007, 0x70007, 0x70019, 0x1b001a, 0x1d001c, 0x1f001e, 0x210020, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x220007, 0x70007, 0x70007, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x210021, 0x230021, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x210007, 0x250024, 0x260021, 0x280027, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x2a0029, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x2b0007, 0x70007, 0x2d002c, 0x2f002e, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70030, 0x310007, 0x70032, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x210021, 0x70033, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x0, 0x0, 0x0, 0x0, 0x0, 0x773c8501, 0x3e7effbf, 0xbe7effbf, 0xfffcffff, 0xfefdff3f, 0xfff3f3f9, 0xffffff3f, 0x0, 0x18003, 0xdffffff0, 0xff3fffcf, 0xcfffffff, 0xfffc0, 0x0, 0x0, 0x0, 0x1ff0000, 0x3f000000, 0x1f, 0x0, 0x0, 0x1b, 0x44100000, 0x1d7f0, 0x1fc00, 0x7f7c00, 0x2370000, 0x200708b, 0x2000000, 0x708b0000, 0xc00000, 0x0, 0x0, 0xfccf0006, 0x33ffcfc, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x1e00000, 0x0, 0x0, 0x80005, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x120200, 0xff000000, 0x0, 0x0, 0x0, 0xb0001800, 0x0, 0x0, 0x480000, 0x4e000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30001900, 0x0, 0x100000, 0x0, 0x1c00, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0, 0x0, 0xd81, 0x0, 0x0, 0x0, 0x1c00, 0x0, 0x0, 0x0, 0x74000000, 0x0, 0x0, 0x80000, 0x0, 0x0, 0x0, 0x80000, 0x30000000, 0x0, 0x1000, 0x0, 0x10842008, 0x3e80200, 0x20080002, 0x2001084, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000, 0x45540, 0x28000000, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf7ff7000, 0xffffbfff, 0x10007ff, 0xf8000000, 0xffffffff, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffff, 0xffffffff, 0xffffffff, 0x3ffffff, 0x3f3fffff, 0xffffffff, 0xaaff3f3f, 0x3fffffff, 0xffffffff, 0xffdfffff, 0xefcfffdf, 0x7fdcffff, 0x8207ff, 0x50d88070, 0x80800380, 0xfff30000, 0x1fff7fff, 0x100, 0x0, 0x0, 0x3e6ffeef, 0xfbfbbd57, 0xffff03e1, 0xffffffff, 0xc000200, 0x4000, 0xe000, 0x0, 0x1210, 0x1b050, 0x292, 0x333e005, 0x333, 0xf000, 0x0, 0x3c0f, 0x0, 0x600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ff, 0x1000, 0x0, 0x0, 0x700000, 0x0, 0x0, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x30000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0x80000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffff, 0x0, 0x1, 0x7400000, 0x55555000, 0x36db02a5, 0xd8100000, 0x55555000, 0x36db02a5, 0xc7900000, 0x0, 0xfffe0000, 0xffffffff, 0xffffffff, 0xfffc7fff, 0x0, 0x0, 0x0, 0x7fffffff, 0xffffffff, 0xffff00ff, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x0, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x3000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf, 0x0, 0x0, 0x7fe53fff, 0xfffffc65, 0xffffffff, 0xffff3fff, 0xffffffff, 0xffffffff, 0x3ffffff, 0x0, 0xa0f8007f, 0x5f7fffff, 0xffffffdb, 0xffffffff, 0xffffffff, 0x3ffff, 0xfff80000, 0xffffffff, 0xffffffff, 0x3fffffff, 0xffff0000, 0xffffffff, 0xfffcffff, 0xffffffff, 0xff, 0x1fff0000, 0x3ff0000, 0xffff0000, 0xfff7ff9f, 0xffd70f7f, 0xffffffff, 0xffffffff, 0xffffffff, 0x1fffffff, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff, 0x1cfcfcfc, 0x7f7f, 0x0, 0x0, 0x0, 0x0, 0x14000000, 0x800, 0x0, 0x0, 0x0, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x1f, 0x0, 0xf8000000, 0x1, 0x0, 0xffffffff, 0xffffffff, 0xffdfffff, 0xffffffff, 0xdfffffff, 0xebffde64, 0xffffffef, 0xffffffff, 0xdfdfe7bf, 0x7bffffff, 0xfffdfc5f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff3f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffcfff, 0xffffffff, 0xffffffef, 0xaf7fe96, 0xaa96ea84, 0x5ef7f796, 0xffffbff, 0xffffbee, 0x0, 0x0, 0xffff07ff, 0xffff7fff, 0xffff, 0xc00, 0x10000, 0x0, 0x0, 0x0, 0xffff0007, 0x7ffffff, 0x301ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/test/0000775000175000017500000000000012776215007020501 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/internal/test/dummyrange.d0000664000175000017500000003253712776215007023030 0ustar kaikai/** For testing only. Used with the dummy ranges for testing higher order ranges. */ module std.internal.test.dummyrange; import std.meta; import std.typecons; import std.range.primitives; enum RangeType { Input, Forward, Bidirectional, Random } enum Length { Yes, No } enum ReturnBy { Reference, Value } import std.traits : isArray; // Range that's useful for testing other higher order ranges, // can be parametrized with attributes. It just dumbs down an array of // numbers 1..10. struct DummyRange(ReturnBy _r, Length _l, RangeType _rt, T = uint[]) if (isArray!T) { private enum uinttestData = [1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U]; // These enums are so that the template params are visible outside // this instantiation. enum r = _r; enum l = _l; enum rt = _rt; static if (is(T == uint[])) { T arr = uinttestData; } else { T arr; } alias RetType = ElementType!(T); alias RetTypeNoAutoDecoding = ElementEncodingType!(T); void reinit() { // Workaround for DMD bug 4378 static if (is(T == uint[])) { arr = uinttestData; } } void popFront() { arr = arr[1..$]; } @property bool empty() const { return arr.length == 0; } static if (r == ReturnBy.Reference) { @property ref inout(RetType) front() inout { return arr[0]; } } else { @property RetType front() const { return arr[0]; } @property void front(RetTypeNoAutoDecoding val) { arr[0] = val; } } static if (rt >= RangeType.Forward) { @property typeof(this) save() { return this; } } static if (rt >= RangeType.Bidirectional) { void popBack() { arr = arr[0..$ - 1]; } static if (r == ReturnBy.Reference) { @property ref inout(RetType) back() inout { return arr[$ - 1]; } } else { @property RetType back() const { return arr[$ - 1]; } @property void back(RetTypeNoAutoDecoding val) { arr[$ - 1] = val; } } } static if (rt >= RangeType.Random) { static if (r == ReturnBy.Reference) { ref inout(RetType) opIndex(size_t index) inout { return arr[index]; } } else { RetType opIndex(size_t index) const { return arr[index]; } RetType opIndexAssign(RetTypeNoAutoDecoding val, size_t index) { return arr[index] = val; } RetType opIndexOpAssign(string op)(RetTypeNoAutoDecoding value, size_t index) { mixin("return arr[index] " ~ op ~ "= value;"); } RetType opIndexUnary(string op)(size_t index) { mixin("return " ~ op ~ "arr[index];"); } } typeof(this) opSlice(size_t lower, size_t upper) { auto ret = this; ret.arr = arr[lower..upper]; return ret; } } static if (l == Length.Yes) { @property size_t length() const { return arr.length; } alias opDollar = length; } } enum dummyLength = 10; alias AllDummyRanges = AliasSeq!( DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward), DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional), DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random), DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward), DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional), DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input), DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward), DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional), DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random), DummyRange!(ReturnBy.Value, Length.No, RangeType.Input), DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward), DummyRange!(ReturnBy.Value, Length.No, RangeType.Bidirectional) ); template AllDummyRangesType(T) { alias AllDummyRangesType = AliasSeq!( DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward, T), DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional, T), DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, T), DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward, T), DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional, T), DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input, T), DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward, T), DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional, T), DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random, T), DummyRange!(ReturnBy.Value, Length.No, RangeType.Input, T), DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward, T), DummyRange!(ReturnBy.Value, Length.No, RangeType.Bidirectional, T) ); } /** Tests whether forward, bidirectional and random access properties are propagated properly from the base range(s) R to the higher order range H. Useful in combination with DummyRange for testing several higher order ranges. */ template propagatesRangeType(H, R...) { static if (allSatisfy!(isRandomAccessRange, R)) enum bool propagatesRangeType = isRandomAccessRange!H; else static if (allSatisfy!(isBidirectionalRange, R)) enum bool propagatesRangeType = isBidirectionalRange!H; else static if (allSatisfy!(isForwardRange, R)) enum bool propagatesRangeType = isForwardRange!H; else enum bool propagatesRangeType = isInputRange!H; } template propagatesLength(H, R...) { static if (allSatisfy!(hasLength, R)) enum bool propagatesLength = hasLength!H; else enum bool propagatesLength = !hasLength!H; } /** Reference type input range */ class ReferenceInputRange(T) { import std.array : array; this(Range)(Range r) if (isInputRange!Range) {_payload = array(r);} final @property ref T front(){return _payload.front;} final void popFront(){_payload.popFront();} final @property bool empty(){return _payload.empty;} protected T[] _payload; } /** Infinite input range */ class ReferenceInfiniteInputRange(T) { this(T first = T.init) {_val = first;} final @property T front(){return _val;} final void popFront(){++_val;} enum bool empty = false; protected T _val; } /** Reference forward range */ class ReferenceForwardRange(T) : ReferenceInputRange!T { this(Range)(Range r) if (isInputRange!Range) {super(r);} final @property auto save(this This)() {return new This( _payload);} } /** Infinite forward range */ class ReferenceInfiniteForwardRange(T) : ReferenceInfiniteInputRange!T { this(T first = T.init) {super(first);} final @property ReferenceInfiniteForwardRange save() {return new ReferenceInfiniteForwardRange!T(_val);} } /** Reference bidirectional range */ class ReferenceBidirectionalRange(T) : ReferenceForwardRange!T { this(Range)(Range r) if (isInputRange!Range) {super(r);} final @property ref T back(){return _payload.back;} final void popBack(){_payload.popBack();} } unittest { static assert(isInputRange!(ReferenceInputRange!int)); static assert(isInputRange!(ReferenceInfiniteInputRange!int)); static assert(isForwardRange!(ReferenceForwardRange!int)); static assert(isForwardRange!(ReferenceInfiniteForwardRange!int)); static assert(isBidirectionalRange!(ReferenceBidirectionalRange!int)); } private: pure struct Cmp(T) if (is(T == uint)) { static auto iota(size_t low = 1, size_t high = 11) { import std.range : iota; return iota(cast(uint)low, cast(uint)high); } static void init(ref uint[] arr) { import std.array : array; arr = iota().array; } static bool function(uint,uint) cmp = function(uint a, uint b) { return a == b; }; enum dummyValue = 1337U; enum dummyValueRslt = 1337U * 2; } pure struct Cmp(T) if (is(T == double)) { import std.math : approxEqual; static auto iota(size_t low = 1, size_t high = 11) { import std.range : iota; return iota(cast(double)low, cast(double)high, 1.0); } static void init(ref double[] arr) { import std.array : array; arr = iota().array; } alias cmp = approxEqual!(double,double); enum dummyValue = 1337.0; enum dummyValueRslt = 1337.0 * 2.0; } struct TestFoo { int a; bool opEquals(const ref TestFoo other) const { return this.a == other.a; } TestFoo opBinary(string op)(TestFoo other) { TestFoo ret = this; mixin("ret.a " ~ op ~ "= other.a;"); return ret; } TestFoo opOpAssign(string op)(TestFoo other) { mixin("this.a " ~ op ~ "= other.a;"); return this; } } pure struct Cmp(T) if (is(T == TestFoo)) { import std.math : approxEqual; static auto iota(size_t low = 1, size_t high = 11) { import std.range : iota; import std.algorithm.iteration : map; return iota(cast(int)low, cast(int)high).map!(a => TestFoo(a)); } static void init(ref TestFoo[] arr) { import std.array : array; arr = iota().array; } static bool function(TestFoo,TestFoo) cmp = function(TestFoo a, TestFoo b) { return a.a == b.a; }; @property static TestFoo dummyValue() { return TestFoo(1337); } @property static TestFoo dummyValueRslt() { return TestFoo(1337 * 2); } } unittest { import std.algorithm.comparison : equal; import std.range : iota, retro, repeat; import std.traits : Unqual; static void testInputRange(T,Cmp)() { T it; Cmp.init(it.arr); for (size_t numRuns = 0; numRuns < 2; ++numRuns) { if (numRuns == 1) { static if (is(Unqual!(ElementType!(T)) == uint)) { it.reinit(); } Cmp.init(it.arr); } assert(equal!(Cmp.cmp)(it, Cmp.iota(1, 11))); static if (hasLength!T) { assert(it.length == 10); } assert(!Cmp.cmp(it.front, Cmp.dummyValue)); auto s = it.front; it.front = Cmp.dummyValue; assert(Cmp.cmp(it.front, Cmp.dummyValue)); it.front = s; auto cmp = Cmp.iota(1,11); size_t jdx = 0; while (!it.empty && !cmp.empty) { static if (hasLength!T) { assert(it.length == 10 - jdx); } assert(Cmp.cmp(it.front, cmp.front)); it.popFront(); cmp.popFront(); ++jdx; } assert(it.empty); assert(cmp.empty); } } static void testForwardRange(T,Cmp)() { T it; Cmp.init(it.arr); auto s = it.save(); s.popFront(); assert(!Cmp.cmp(s.front, it.front)); } static void testBidirectionalRange(T,Cmp)() { T it; Cmp.init(it.arr); assert(equal!(Cmp.cmp)(it.retro, Cmp.iota().retro)); auto s = it.back; assert(!Cmp.cmp(s, Cmp.dummyValue)); it.back = Cmp.dummyValue; assert( Cmp.cmp(it.back, Cmp.dummyValue)); it.back = s; } static void testRandomAccessRange(T,Cmp)() { T it; Cmp.init(it.arr); size_t idx = 0; foreach (jt; it) { assert(it[idx] == jt); T copy = it[idx .. $]; auto cmp = Cmp.iota(idx + 1, it.length + 1); assert(equal!(Cmp.cmp)(copy, cmp)); ++idx; } { auto copy = it; copy.arr = it.arr.dup; for (size_t i = 0; i < copy.length; ++i) { copy[i] = Cmp.dummyValue; copy[i] += Cmp.dummyValue; } assert(equal!(Cmp.cmp)(copy, Cmp.dummyValueRslt.repeat(copy.length))); } static if (it.r == ReturnBy.Reference) { T copy; copy.arr = it.arr.dup; for (size_t i = 0; i < copy.length; ++i) { copy[i] = Cmp.dummyValue; copy[i] += Cmp.dummyValue; } assert(equal!(Cmp.cmp)(copy, Cmp.dummyValueRslt.repeat(copy.length))); } } import std.meta : AliasSeq; foreach (S; AliasSeq!(uint, double, TestFoo)) { foreach (T; AllDummyRangesType!(S[])) { testInputRange!(T,Cmp!S)(); static if (isForwardRange!T) { testForwardRange!(T,Cmp!S)(); } static if (isBidirectionalRange!T) { testBidirectionalRange!(T,Cmp!S)(); } static if (isRandomAccessRange!T) { testRandomAccessRange!(T,Cmp!S)(); } } } } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/test/uda.d0000664000175000017500000000042112776215007021414 0ustar kaikai/** For testing only. Provides a struct with UDA's defined in an external module. Useful for validating behavior with member privacy. */ module std.internal.test.uda; enum Attr; struct HasPrivateMembers { @Attr int a; int b; @Attr private int c; private int d; } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/cstring.d0000664000175000017500000001506112776215007021343 0ustar kaikai/** Helper functions for working with $(I C strings). This module is intended to provide fast, safe and garbage free way to work with $(I C strings). Copyright: Denis Shelomovskij 2013-2014 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Denis Shelomovskij Macros: COREREF = $(HTTP dlang.org/phobos/core_$1.html#$2, $(D core.$1.$2)) */ module std.internal.cstring; /// unittest { version(Posix) { import core.stdc.stdlib: free; import core.sys.posix.stdlib: setenv; import std.exception: enforce; void setEnvironment(in char[] name, in char[] value) { enforce(setenv(name.tempCString(), value.tempCString(), 1) != -1); } } version(Windows) { import core.sys.windows.windows: SetEnvironmentVariableW; import std.exception: enforce; void setEnvironment(in char[] name, in char[] value) { enforce(SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW())); } } } import std.traits; import std.range; version(unittest) @property inout(C)[] asArray(C)(inout C* cstr) pure nothrow @nogc @trusted if(isSomeChar!C) in { assert(cstr); } body { size_t length = 0; while(cstr[length]) ++length; return cstr[0 .. length]; } /** Creates temporary 0-terminated $(I C string) with copy of passed text. Params: To = character type of returned C string str = string or input range to be converted Returns: The value returned is implicitly convertible to $(D const To*) and has two properties: $(D ptr) to access $(I C string) as $(D const To*) and $(D buffPtr) to access it as $(D To*). The temporary $(I C string) is valid unless returned object is destroyed. Thus if returned object is assigned to a variable the temporary is valid unless the variable goes out of scope. If returned object isn't assigned to a variable it will be destroyed at the end of creating primary expression. Implementation_note: For small strings tempCString will use stack allocated buffer, for large strings (approximately 250 characters and more) it will allocate temporary one using C's $(D malloc). Note: This function is intended to be used in function call expression (like $(D strlen(str.tempCString()))). Incorrect usage of this function may lead to memory corruption. See $(RED WARNING) in $(B Examples) section. */ auto tempCString(To = char, From)(From str) if (isSomeChar!To && (isInputRange!From || isSomeString!From) && isSomeChar!(ElementEncodingType!From)) { alias CF = Unqual!(ElementEncodingType!From); enum To* useStack = () @trusted { return cast(To*)size_t.max; }(); static struct Res { @trusted: nothrow @nogc: @disable this(); @disable this(this); alias ptr this; @property inout(To)* buffPtr() inout pure { return _ptr == useStack ? _buff.ptr : _ptr; } @property const(To)* ptr() const pure { return buffPtr; } ~this() { if (_ptr != useStack) { import core.stdc.stdlib : free; free(_ptr); } } private: To* _ptr; version (unittest) { enum buffLength = 16 / To.sizeof; // smaller size to trigger reallocations } else { enum buffLength = 256 / To.sizeof; // production size } To[256 / To.sizeof] _buff; // the 'small string optimization' static Res trustedVoidInit() { Res res = void; return res; } } Res res = Res.trustedVoidInit(); // expensive to fill _buff[] // Note: res._ptr can't point to res._buff as structs are movable. To[] p = res._buff[0 .. Res.buffLength]; size_t i; static To[] trustedRealloc(To[] buf, size_t i, To* resptr, size_t strLength) @trusted @nogc nothrow { pragma(inline, false); // because it's rarely called import core.exception : onOutOfMemoryError; import core.stdc.string : memcpy; import core.stdc.stdlib : malloc, realloc; auto ptr = buf.ptr; auto len = buf.length; if (len >= size_t.max / (2 * To.sizeof)) onOutOfMemoryError(); size_t newlen = len * 3 / 2; if (ptr == resptr) { if (newlen <= strLength) newlen = strLength + 1; // +1 for terminating 0 ptr = cast(To*)malloc(newlen * To.sizeof); if (!ptr) onOutOfMemoryError(); memcpy(ptr, resptr, i * To.sizeof); } else { ptr = cast(To*)realloc(ptr, newlen * To.sizeof); if (!ptr) onOutOfMemoryError(); } return ptr[0 .. newlen]; } size_t strLength; static if (hasLength!From) { strLength = str.length; } import std.utf : byUTF; static if (isSomeString!From) { auto r = cast(const(CF)[])str; // because inout(CF) causes problems with byUTF if (r is null) // Bugzilla 14980 { res._ptr = null; return res; } } else alias r = str; foreach (const c; byUTF!(Unqual!To)(r)) { if (i + 1 == p.length) { p = trustedRealloc(p, i, res._buff.ptr, strLength); } p[i++] = c; } p[i] = 0; res._ptr = (p.ptr == res._buff.ptr) ? useStack : p.ptr; return res; } /// nothrow @nogc unittest { import core.stdc.string; string str = "abc"; // Intended usage assert(strlen(str.tempCString()) == 3); // Correct usage auto tmp = str.tempCString(); assert(strlen(tmp) == 3); // or `tmp.ptr`, or `tmp.buffPtr` // $(RED WARNING): $(RED Incorrect usage) auto pInvalid1 = str.tempCString().ptr; const char* pInvalid2 = str.tempCString(); // Both pointers refer to invalid memory here as // returned values aren't assigned to a variable and // both primary expressions are ended. } @safe nothrow @nogc unittest { assert("abc".tempCString().asArray == "abc"); assert("abc"d.tempCString().ptr.asArray == "abc"); assert("abc".tempCString!wchar().buffPtr.asArray == "abc"w); import std.utf : byChar, byWchar; char[300] abc = 'a'; assert(tempCString(abc[].byChar).buffPtr.asArray == abc); assert(tempCString(abc[].byWchar).buffPtr.asArray == abc); } // Bugzilla 14980 nothrow @nogc unittest { const(char[]) str = null; auto res = tempCString(str); const char* ptr = res; assert(ptr is null); } version(Windows) alias tempCStringW = tempCString!(wchar, const(char)[]); ldc-1.1.0-beta3-src/runtime/phobos/std/internal/digest/0000775000175000017500000000000012776215007021001 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/internal/digest/sha_SSSE3.d0000664000175000017500000005717012776215007022653 0ustar kaikai// Written in the D programming language. /** * Computes SHA1 digests of arbitrary data, using an optimized algorithm with SSSE3 instructions. * * Authors: * The general idea is described by Dean Gaudet. * Another important observation is published by Max Locktyukhin. * (Both implementations are public domain.) * Translation to X86 and D by Kai Nacke * * References: * $(LINK2 http://arctic.org/~dean/crypto/sha1.html) * $(LINK2 http://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1/, Fast implementation of SHA1) */ module std.internal.digest.sha_SSSE3; version(D_PIC) { // Do not use (Bug9378). } else version(D_InlineAsm_X86) { private version = USE_SSSE3; private version = _32Bit; } else version(D_InlineAsm_X86_64) { private version = USE_SSSE3; private version = _64Bit; } /* * The idea is quite simple. The SHA-1 specification defines the following message schedule: * W[i] = (W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]) rol 1 * * To employ SSE, simply write down the formula four times: * W[i ] = (W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]) rol 1 * W[i+1] = (W[i-2] ^ W[i-7] ^ W[i-13] ^ W[i-15]) rol 1 * W[i+2] = (W[i-1] ^ W[i-6] ^ W[i-12] ^ W[i-14]) rol 1 * W[i+3] = (W[i ] ^ W[i-5] ^ W[i-11] ^ W[i-13]) rol 1 * The last formula requires value W[i] computed with the first formula. * Because the xor operation and the rotate operation are commutative, we can replace the * last formula with * W[i+3] = ( 0 ^ W[i-5] ^ W[i-11] ^ W[i-13]) rol 1 * and then calculate * W[i+3] ^= W[i] rol 1 * which unfortunately requires many additional operations. This approach was described by * Dean Gaudet. * * Max Locktyukhin observed that * W[i] = W[i-A] ^ W[i-B] * is equivalent to * W[i] = W[i-2*A] ^ W[i-2*B] * (if the indices are still in valid ranges). Using this observation, the formula is * translated to * W[i] = (W[i-6] ^ W[i-16] ^ W[i-28] ^ W[i-32]) rol 2 * Again, to employ SSE the formula is used four times. * * Later on, the expression W[i] + K(i) is used. (K(i) is the constant used in round i.) * Once the 4 W[i] are calculated, we can also add the four K(i) values with one SSE instruction. * * The 32bit and 64bit implementations are almost identical. The main difference is that there * are only 8 XMM registers in 32bit mode. Therefore, space on the stack is needed to save * computed values. */ version(USE_SSSE3) { /* * The general idea is to use the XMM registers as a sliding window over * message schedule. XMM0 to XMM7 are used to store the last 64 byte of * the message schedule. In 64 bit mode this is fine because of the number of * registers. The main difference of the 32 bit code is that a part of the * calculated message schedule is saved on the stack because 2 temporary * registers are needed. */ /* Number of message words we are precalculating. */ private immutable int PRECALC_AHEAD = 16; /* T1 and T2 are used for intermediate results of computations. */ private immutable string T1 = "EAX"; private immutable string T2 = "EBX"; /* The registers used for the SHA-1 variables. */ private immutable string A = "ECX"; private immutable string B = "ESI"; private immutable string C = "EDI"; private immutable string D = "EBP"; private immutable string E = "EDX"; /* */ version(_32Bit) { private immutable string SP = "ESP"; private immutable string BUFFER_PTR = "EAX"; private immutable string STATE_PTR = "EBX"; // Control byte for shuffle instruction (only used in round 0-15) private immutable string X_SHUFFLECTL = "XMM6"; // Round constant (only used in round 0-15) private immutable string X_CONSTANT = "XMM7"; } version(_64Bit) { private immutable string SP = "RSP"; private immutable string BUFFER_PTR = "R9"; private immutable string STATE_PTR = "R8"; // Registers for temporary results (XMM10 and XMM11 are also used temporary) private immutable string W_TMP = "XMM8"; private immutable string W_TMP2 = "XMM9"; // Control byte for shuffle instruction (only used in round 0-15) private immutable string X_SHUFFLECTL = "XMM12"; // Round constant private immutable string X_CONSTANT = "XMM13"; } /* The control words for the byte shuffle instruction. */ align(16) private immutable uint[4] bswap_shufb_ctl = [ 0x0001_0203, 0x0405_0607, 0x0809_0a0b, 0x0c0d_0e0f ]; /* The round constants. */ align(16) private immutable uint[16] constants = [ // Constants for round 0-19 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, // Constants for round 20-39 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, // Constants for round 40-59 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, // Constants for round 60-79 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6 ]; /** Simple version to produce numbers < 100 as string. */ private nothrow pure string to_string(uint i) { if (i < 10) return "0123456789"[i .. i + 1]; assert(i < 100); char[2] s; s[0] = cast(char)(i / 10 + '0'); s[1] = cast(char)(i % 10 + '0'); return s.idup; } /** Returns the reference to constant used in round i. */ private nothrow pure string constant(uint i) { return "[constants + 16*"~to_string(i/20)~"]"; } /** Returns the XMM register number used in round i */ private nothrow pure uint regno(uint i) { return (i/4)&7; } /** Returns reference to storage of vector W[i..i+4]. */ private nothrow pure string WiV(uint i) { return "["~SP~" + WI_PTR + "~to_string((i/4)&7)~"*16]"; } /** Returns reference to storage of vector (W + K)[i..i+4]. */ private nothrow pure string WiKiV(uint i) { return "["~SP~" + WI_PLUS_KI_PTR + "~to_string((i/4)&3)~"*16]"; } /** Returns reference to storage of value W[i] + K[i]. */ private nothrow pure string WiKi(uint i) { return "["~SP~" + WI_PLUS_KI_PTR + 4*"~to_string(i&15)~"]"; } /** * Chooses the instruction sequence based on the 32bit or 64bit model. */ private nothrow pure string[] swt3264(string[] insn32, string[] insn64) { version(_32Bit) { return insn32; } version(_64Bit) { return insn64; } } /** * Flattens the instruction sequence and wraps it in an asm block. */ private nothrow pure string wrap(string[] insn) { string s = "asm pure nothrow @nogc {"; foreach (t; insn) s ~= (t ~ "; \n"); s ~= "}"; return s; // Is not CTFE: // return "asm pure nothrow @nogc { " ~ join(insn, "; \n") ~ "}"; } /** * Weaves the 2 instruction sequences together. */ private nothrow pure string[] weave(string[] seq1, string[] seq2, uint dist = 1) { string[] res = []; auto i1 = 0, i2 = 0; while (i1 < seq1.length || i2 < seq2.length) { if (i2 < seq2.length) { res ~= seq2[i2..i2+1]; i2 += 1; } if (i1 < seq1.length) { import std.algorithm.comparison : min; res ~= seq1[i1 .. min(i1+dist, $)]; i1 += dist; } } return res; } /** * Generates instructions to load state from memory into registers. */ private nothrow pure string[] loadstate(string base, string a, string b, string c, string d, string e) { return ["mov "~a~",["~base~" + 0*4]", "mov "~b~",["~base~" + 1*4]", "mov "~c~",["~base~" + 2*4]", "mov "~d~",["~base~" + 3*4]", "mov "~e~",["~base~" + 4*4]" ]; } /** * Generates instructions to update state from registers, saving result in memory. */ private nothrow pure string[] savestate(string base, string a, string b, string c, string d, string e) { return ["add ["~base~" + 0*4],"~a, "add ["~base~" + 1*4],"~b, "add ["~base~" + 2*4],"~c, "add ["~base~" + 3*4],"~d, "add ["~base~" + 4*4],"~e ]; } /** Calculates Ch(x, y, z) = z ^ (x & (y ^ z)) */ private nothrow pure string[] Ch(string x, string y, string z) { return ["mov "~T1~","~y, "xor "~T1~","~z, "and "~T1~","~x, "xor "~T1~","~z ]; } /** Calculates Parity(x, y, z) = x ^ y ^ z */ private nothrow pure string[] Parity(string x, string y, string z) { return ["mov "~T1~","~z, "xor "~T1~","~y, "xor "~T1~","~x ]; } /** Calculates Maj(x, y, z) = (x & y) | (z & (x ^ y)) */ private nothrow pure string[] Maj(string x, string y, string z) { return ["mov "~T1~","~y, "mov "~T2~","~x, "or "~T1~","~x, "and "~T2~","~y, "and "~T1~","~z, "or "~T1~","~T2 ]; } /** Returns function for round i. Function returns result in T1 and may destroy T2. */ private nothrow pure string[] F(int i, string b, string c, string d) { string[] insn; if (i >= 0 && i <= 19) insn = Ch(b, c, d); else if (i >= 20 && i <= 39) insn = Parity(b, c, d); else if (i >= 40 && i <= 59) insn = Maj(b, c, d); else if (i >= 60 && i <= 79) insn = Parity(b, c, d); else assert(false, "Coding error"); return insn; } /** Returns instruction used to setup a round. */ private nothrow pure string[] xsetup(int i) { if (i == 0) { return swt3264(["movdqa "~X_SHUFFLECTL~",[bswap_shufb_ctl]", "movdqa "~X_CONSTANT~","~constant(i)], ["movdqa "~X_SHUFFLECTL~",[bswap_shufb_ctl]", "movdqa "~X_CONSTANT~","~constant(i)]); } version(_64Bit) { if (i%20 == 0) { return ["movdqa "~X_CONSTANT~","~constant(i)]; } } return []; } /** * Loads the message words and performs the little to big endian conversion. * Requires that the shuffle control word and the round constant is loaded * into required XMM register. The BUFFER_PTR register must point to the * buffer. */ private nothrow pure string[] precalc_00_15(int i) { int regno = regno(i); string W = "XMM" ~ to_string(regno); version(_32Bit) { string W_TMP = "XMM" ~ to_string(regno+2); } version(_64Bit) { string W_TMP = "XMM" ~ to_string(regno+8); } if ((i & 3) == 0) { return ["movdqu "~W~",["~BUFFER_PTR~" + "~to_string(regno)~"*16]"]; } else if ((i & 3) == 1) { return ["pshufb "~W~","~X_SHUFFLECTL] ~ swt3264(["movdqa "~WiV(i)~","~W], []); } else if ((i & 3) == 2) { return ["movdqa "~W_TMP~","~W, "paddd "~W_TMP~","~X_CONSTANT, ]; } else { return ["movdqa "~WiKiV(i)~","~W_TMP, ]; } } /** * Done on 4 consequtive W[i] values in a single XMM register * W[i ] = (W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]) rol 1 * W[i+1] = (W[i-2] ^ W[i-7] ^ W[i-13] ^ W[i-15]) rol 1 * W[i+2] = (W[i-1] ^ W[i-6] ^ W[i-12] ^ W[i-14]) rol 1 * W[i+3] = ( 0 ^ W[i-5] ^ W[i-11] ^ W[i-13]) rol 1 * * This additional calculation unfortunately requires many additional operations * W[i+3] ^= W[i] rol 1 * * Once we have 4 W[i] values in XMM we can also add four K values with one instruction * W[i:i+3] += {K,K,K,K} */ private nothrow pure string[] precalc_16_31(int i) { int regno = regno(i); string W = "XMM" ~ to_string(regno); string W_minus_4 = "XMM" ~ to_string((regno-1)&7); string W_minus_8 = "XMM" ~ to_string((regno-2)&7); string W_minus_12 = "XMM" ~ to_string((regno-3)&7); string W_minus_16 = "XMM" ~ to_string((regno-4)&7); version(_32Bit) { string W_TMP = "XMM" ~ to_string((regno+1)&7); string W_TMP2 = "XMM" ~ to_string((regno+2)&7); } if ((i & 3) == 0) { return ["movdqa "~W~","~W_minus_12, "palignr "~W~","~W_minus_16~",8", // W[i] = W[i-14] "pxor "~W~","~W_minus_16, // W[i] ^= W[i-16] "pxor "~W~","~W_minus_8, // W[i] ^= W[i-8] "movdqa "~W_TMP~","~W_minus_4, ]; } else if ((i & 3) == 1) { return ["psrldq "~W_TMP~",4", // W[i-3] "pxor "~W~","~W_TMP, // W[i] ^= W[i-3] "movdqa "~W_TMP~","~W, "psrld "~W~",31", "pslld "~W_TMP~",1", ]; } else if ((i & 3) == 2) { return ["por "~W~","~W_TMP, "movdqa "~W_TMP~","~W, "pslldq "~W_TMP~",12", "movdqa "~W_TMP2~","~W_TMP, "pslld "~W_TMP~",1", ]; } else { return ["psrld "~W_TMP2~",31", "por "~W_TMP~","~W_TMP2, "pxor "~W~","~W_TMP, "movdqa "~W_TMP~","~W ] ~ swt3264(["movdqa "~WiV(i)~","~W, "paddd "~W_TMP~","~constant(i) ], ["paddd "~W_TMP~","~X_CONSTANT ]) ~ ["movdqa "~WiKiV(i)~","~W_TMP]; } } /** Performs the main calculation as decribed above. */ private nothrow pure string[] precalc_32_79(int i) { int regno = regno(i); string W = "XMM" ~ to_string(regno); string W_minus_4 = "XMM" ~ to_string((regno-1)&7); string W_minus_8 = "XMM" ~ to_string((regno-2)&7); string W_minus_16 = "XMM" ~ to_string((regno-4)&7); version(_32Bit) { string W_minus_28 = "[ESP + WI_PTR + "~ to_string((regno-7)&7)~"*16]"; string W_minus_32 = "[ESP + WI_PTR + "~ to_string((regno-8)&7)~"*16]"; string W_TMP = "XMM" ~ to_string((regno+1)&7); string W_TMP2 = "XMM" ~ to_string((regno+2)&7); } version(_64Bit) { string W_minus_28 = "XMM" ~ to_string((regno-7)&7); string W_minus_32 = "XMM" ~ to_string((regno-8)&7); } if ((i & 3) == 0) { return swt3264(["movdqa "~W~","~W_minus_32], []) ~ ["movdqa "~W_TMP~","~W_minus_4, "pxor "~W~","~W_minus_28, // W is W_minus_32 before xor "palignr "~W_TMP~","~W_minus_8~",8", ]; } else if ((i & 3) == 1) { return ["pxor "~W~","~W_minus_16, "pxor "~W~","~W_TMP, "movdqa "~W_TMP~","~W, ]; } else if ((i & 3) == 2) { return ["psrld "~W~",30", "pslld "~W_TMP~",2", "por "~W_TMP~","~W, ]; } else { if (i < 76) return ["movdqa "~W~","~W_TMP] ~ swt3264(["movdqa "~WiV(i)~","~W, "paddd "~W_TMP~","~constant(i)], ["paddd "~W_TMP~","~X_CONSTANT]) ~ ["movdqa "~WiKiV(i)~","~W_TMP]; else return swt3264(["paddd "~W_TMP~","~constant(i)], ["paddd "~W_TMP~","~X_CONSTANT]) ~ ["movdqa "~WiKiV(i)~","~W_TMP]; } } /** Choose right precalc method. */ private nothrow pure string[] precalc(int i) { if (i >= 0 && i < 16) return precalc_00_15(i); if (i >= 16 && i < 32) return precalc_16_31(i); if (i >= 32 && i < 80) return precalc_32_79(i); return []; } /** * Return code for round i and i+1. * Performs the following rotation: * in=>out: A=>D, B=>E, C=>A, D=>B, E=>C */ private nothrow pure string[] round(int i, string a, string b, string c, string d, string e) { return xsetup(PRECALC_AHEAD + i) ~ weave(F(i, b, c, d) ~ // Returns result in T1; may destroy T2 ["add "~e~","~WiKi(i), "ror "~b~",2", "mov "~T2~","~a, "add "~d~","~WiKi(i+1), "rol "~T2~",5", "add "~e~","~T1 ], precalc(PRECALC_AHEAD + i), 2) ~ weave( ["add "~T2~","~e, // T2 = (A <<< 5) + F(B, C, D) + Wi + Ki + E "mov "~e~","~T2, "rol "~T2~",5", "add "~d~","~T2 ] ~ F(i+1, a, b, c) ~ // Returns result in T1; may destroy T2 ["add "~d~","~T1, "ror "~a~",2"], precalc(PRECALC_AHEAD + i+1), 2); } // Offset into stack (see below) version(_32Bit) { private enum { STATE_OFS = 4, WI_PLUS_KI_PTR = 8, WI_PTR = 72 }; } version(_64Bit) { private enum { WI_PLUS_KI_PTR = 0 }; } /** The prologue sequence. */ private nothrow pure string[] prologue() { version(_32Bit) { /* * Parameters: * EAX contains pointer to input buffer * * Stack layout as follows: * +----------------+ * | ptr to state | * +----------------+ * | return address | * +----------------+ * | EBP | * +----------------+ * | ESI | * +----------------+ * | EDI | * +----------------+ * | EBX | * +----------------+ * | Space for | * | Wi | <- ESP+72 * +----------------+ * | Space for | * | Wi+Ki | <- ESP+8 * +----------------+ <- 16byte aligned * | ptr to state | <- ESP+4 * +----------------+ * | old ESP | <- ESP * +----------------+ */ static assert(BUFFER_PTR == "EAX"); static assert(STATE_PTR == "EBX"); return [// Save registers according to calling convention "push EBP", "push ESI", "push EDI", "push EBX", // Load parameters "mov EBX, [ESP + 5*4]", //pointer to state // Align stack "mov EBP, ESP", "sub ESP, 4*16 + 8*16", "and ESP, 0xffff_fff0", "push EBX", "push EBP", ]; } version(_64Bit) { /* * Parameters: * RSI contains pointer to state * RDI contains pointer to input buffer * * Stack layout as follows: * +----------------+ * | return address | * +----------------+ * | RBP | * +----------------+ * | RBX | * +----------------+ * | Unused | * +----------------+ * | Space for | * | Wi+Ki | <- RSP * +----------------+ <- 16byte aligned */ return [// Save registers according to calling convention "push RBP", "push RBX", // Save parameters "mov "~STATE_PTR~", RSI", //pointer to state "mov "~BUFFER_PTR~", RDI", //pointer to buffer // Align stack "sub RSP, 4*16+8", ]; } } /** * The epilogue sequence. Just pop the saved registers from stack and return to caller. */ private nothrow pure string[] epilogue() { version(_32Bit) { return ["pop ESP", "pop EBX", "pop EDI", "pop ESI", "pop EBP", "ret 4", ]; } version(_64Bit) { return ["add RSP,4*16+8", "pop RBX", "pop RBP", "ret 0", ]; } } /** * */ public void transformSSSE3(uint[5]* state, const(ubyte[64])* buffer) pure nothrow @nogc { mixin(wrap(["naked;"] ~ prologue())); // Precalc first 4*16=64 bytes mixin(wrap(xsetup(0))); mixin(wrap(weave(precalc(0)~precalc(1)~precalc(2)~precalc(3), precalc(4)~precalc(5)~precalc(6)~precalc(7)))); mixin(wrap(weave(loadstate(STATE_PTR, A, B, C, D, E), weave(precalc(8)~precalc(9)~precalc(10)~precalc(11), precalc(12)~precalc(13)~precalc(14)~precalc(15))))); // Round 1 mixin(wrap(round( 0, A, B, C, D, E))); mixin(wrap(round( 2, D, E, A, B, C))); mixin(wrap(round( 4, B, C, D, E, A))); mixin(wrap(round( 6, E, A, B, C, D))); mixin(wrap(round( 8, C, D, E, A, B))); mixin(wrap(round(10, A, B, C, D, E))); mixin(wrap(round(12, D, E, A, B, C))); mixin(wrap(round(14, B, C, D, E, A))); mixin(wrap(round(16, E, A, B, C, D))); mixin(wrap(round(18, C, D, E, A, B))); // Round 2 mixin(wrap(round(20, A, B, C, D, E))); mixin(wrap(round(22, D, E, A, B, C))); mixin(wrap(round(24, B, C, D, E, A))); mixin(wrap(round(26, E, A, B, C, D))); mixin(wrap(round(28, C, D, E, A, B))); mixin(wrap(round(30, A, B, C, D, E))); mixin(wrap(round(32, D, E, A, B, C))); mixin(wrap(round(34, B, C, D, E, A))); mixin(wrap(round(36, E, A, B, C, D))); mixin(wrap(round(38, C, D, E, A, B))); // Round 3 mixin(wrap(round(40, A, B, C, D, E))); mixin(wrap(round(42, D, E, A, B, C))); mixin(wrap(round(44, B, C, D, E, A))); mixin(wrap(round(46, E, A, B, C, D))); mixin(wrap(round(48, C, D, E, A, B))); mixin(wrap(round(50, A, B, C, D, E))); mixin(wrap(round(52, D, E, A, B, C))); mixin(wrap(round(54, B, C, D, E, A))); mixin(wrap(round(56, E, A, B, C, D))); mixin(wrap(round(58, C, D, E, A, B))); // Round 4 mixin(wrap(round(60, A, B, C, D, E))); mixin(wrap(round(62, D, E, A, B, C))); mixin(wrap(round(64, B, C, D, E, A))); mixin(wrap(round(66, E, A, B, C, D))); mixin(wrap(round(68, C, D, E, A, B))); mixin(wrap(round(70, A, B, C, D, E))); mixin(wrap(round(72, D, E, A, B, C))); mixin(wrap(round(74, B, C, D, E, A))); mixin(wrap(round(76, E, A, B, C, D))); mixin(wrap(round(78, C, D, E, A, B))); version(_32Bit) { // Load pointer to state mixin(wrap(["mov "~STATE_PTR~",[ESP + STATE_OFS]"])); } mixin(wrap(savestate(STATE_PTR, A, B, C, D, E))); mixin(wrap(epilogue())); } } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/unicode_tables.d0000664000175000017500000270230612776215007022661 0ustar kaikai//Written in the D programming language /** * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). * * Authors: Dmitry Olshansky * */ //Automatically generated from Unicode Character Database files module std.internal.unicode_tables; @safe pure nothrow @nogc: struct SimpleCaseEntry { uint ch; ubyte n, bucket;// n - number in bucket pure nothrow @nogc: @property ubyte size() const { return bucket & 0x3F; } @property auto isLower() const { return bucket & 0x40; } @property auto isUpper() const { return bucket & 0x80; } } struct FullCaseEntry { dchar[3] seq; ubyte n, size;// n number in batch, size - size of batch ubyte entry_len; @property auto value() const @trusted pure nothrow @nogc return { return seq[0..entry_len]; } } struct CompEntry { dchar rhs, composed; } struct UnicodeProperty { string name; ubyte[] compressed; } struct TrieEntry(T...) { size_t[] offsets; size_t[] sizes; size_t[] data; } @property immutable(SimpleCaseEntry[]) simpleCaseTable() { alias SCE = SimpleCaseEntry; static immutable SCE[] t = [ SCE(0x2c00, 0, 0x82), SCE(0x2c30, 1, 0x42),SCE(0x24c3, 0, 0x82),SCE(0x24dd, 1, 0x42),SCE(0x2c01, 0, 0x82), SCE(0x2c31, 1, 0x42),SCE(0x2c1d, 0, 0x82),SCE(0x2c4d, 1, 0x42),SCE(0x2c02, 0, 0x82), SCE(0x2c32, 1, 0x42),SCE(0x2c03, 0, 0x82),SCE(0x2c33, 1, 0x42),SCE(0x2c04, 0, 0x82), SCE(0x2c34, 1, 0x42),SCE(0x2c05, 0, 0x82),SCE(0x2c35, 1, 0x42),SCE(0x2c06, 0, 0x82), SCE(0x2c36, 1, 0x42),SCE(0x10400, 0, 0x82),SCE(0x10428, 1, 0x42),SCE(0x2cc2, 0, 0x82), SCE(0x2cc3, 1, 0x42),SCE(0x2c07, 0, 0x82),SCE(0x2c37, 1, 0x42),SCE(0x2c08, 0, 0x82), SCE(0x2c38, 1, 0x42),SCE(0x2c09, 0, 0x82),SCE(0x2c39, 1, 0x42),SCE(0x2c0a, 0, 0x82), SCE(0x2c3a, 1, 0x42),SCE(0xa68c, 0, 0x82),SCE(0xa68d, 1, 0x42),SCE(0x0041, 0, 0x82), SCE(0x0061, 1, 0x42),SCE(0x0042, 0, 0x82),SCE(0x0062, 1, 0x42),SCE(0x0043, 0, 0x82), SCE(0x0063, 1, 0x42),SCE(0x0044, 0, 0x82),SCE(0x0064, 1, 0x42),SCE(0x0045, 0, 0x82), SCE(0x0065, 1, 0x42),SCE(0x0046, 0, 0x82),SCE(0x0066, 1, 0x42),SCE(0x0047, 0, 0x82), SCE(0x0067, 1, 0x42),SCE(0x0048, 0, 0x82),SCE(0x0068, 1, 0x42),SCE(0x0049, 0, 0x82), SCE(0x0069, 1, 0x42),SCE(0x004a, 0, 0x82),SCE(0x006a, 1, 0x42),SCE(0x004b, 0, 0x83), SCE(0x006b, 1, 0x43),SCE(0x212a, 2, 0x83),SCE(0x004c, 0, 0x82),SCE(0x006c, 1, 0x42), SCE(0x004d, 0, 0x82),SCE(0x006d, 1, 0x42),SCE(0x004e, 0, 0x82),SCE(0x006e, 1, 0x42), SCE(0x004f, 0, 0x82),SCE(0x006f, 1, 0x42),SCE(0x0050, 0, 0x82),SCE(0x0070, 1, 0x42), SCE(0x0051, 0, 0x82),SCE(0x0071, 1, 0x42),SCE(0x0052, 0, 0x82),SCE(0x0072, 1, 0x42), SCE(0x0053, 0, 0x83),SCE(0x0073, 1, 0x43),SCE(0x017f, 2, 0x43),SCE(0x0054, 0, 0x82), SCE(0x0074, 1, 0x42),SCE(0x0055, 0, 0x82),SCE(0x0075, 1, 0x42),SCE(0x0056, 0, 0x82), SCE(0x0076, 1, 0x42),SCE(0x0057, 0, 0x82),SCE(0x0077, 1, 0x42),SCE(0x0058, 0, 0x82), SCE(0x0078, 1, 0x42),SCE(0x0059, 0, 0x82),SCE(0x0079, 1, 0x42),SCE(0x005a, 0, 0x82), SCE(0x007a, 1, 0x42),SCE(0x2c0f, 0, 0x82),SCE(0x2c3f, 1, 0x42),SCE(0x2c10, 0, 0x82), SCE(0x2c40, 1, 0x42),SCE(0x10402, 0, 0x82),SCE(0x1042a, 1, 0x42),SCE(0x2cc4, 0, 0x82), SCE(0x2cc5, 1, 0x42),SCE(0x2166, 0, 0x82),SCE(0x2176, 1, 0x42),SCE(0x2c11, 0, 0x82), SCE(0x2c41, 1, 0x42),SCE(0x2c12, 0, 0x82),SCE(0x2c42, 1, 0x42),SCE(0x2168, 0, 0x82), SCE(0x2178, 1, 0x42),SCE(0x2c13, 0, 0x82),SCE(0x2c43, 1, 0x42),SCE(0xa682, 0, 0x82), SCE(0xa683, 1, 0x42),SCE(0x2c14, 0, 0x82),SCE(0x2c44, 1, 0x42),SCE(0x216a, 0, 0x82), SCE(0x217a, 1, 0x42),SCE(0x24c7, 0, 0x82),SCE(0x24e1, 1, 0x42),SCE(0x2c15, 0, 0x82), SCE(0x2c45, 1, 0x42),SCE(0x10403, 0, 0x82),SCE(0x1042b, 1, 0x42),SCE(0x2c16, 0, 0x82), SCE(0x2c46, 1, 0x42),SCE(0x216c, 0, 0x82),SCE(0x217c, 1, 0x42),SCE(0x2c17, 0, 0x82), SCE(0x2c47, 1, 0x42),SCE(0xff38, 0, 0x82),SCE(0xff58, 1, 0x42),SCE(0x2c18, 0, 0x82), SCE(0x2c48, 1, 0x42),SCE(0x216e, 0, 0x82),SCE(0x217e, 1, 0x42),SCE(0x2c19, 0, 0x82), SCE(0x2c49, 1, 0x42),SCE(0x2c1a, 0, 0x82),SCE(0x2c4a, 1, 0x42),SCE(0x2c1e, 0, 0x82), SCE(0x2c4e, 1, 0x42),SCE(0x10a0, 0, 0x82),SCE(0x2d00, 1, 0x42),SCE(0x10a1, 0, 0x82), SCE(0x2d01, 1, 0x42),SCE(0x10a2, 0, 0x82),SCE(0x2d02, 1, 0x42),SCE(0x10a3, 0, 0x82), SCE(0x2d03, 1, 0x42),SCE(0x10a4, 0, 0x82),SCE(0x2d04, 1, 0x42),SCE(0x10a5, 0, 0x82), SCE(0x2d05, 1, 0x42),SCE(0x10a6, 0, 0x82),SCE(0x2d06, 1, 0x42),SCE(0x10a7, 0, 0x82), SCE(0x2d07, 1, 0x42),SCE(0x10a8, 0, 0x82),SCE(0x2d08, 1, 0x42),SCE(0x10a9, 0, 0x82), SCE(0x2d09, 1, 0x42),SCE(0x10aa, 0, 0x82),SCE(0x2d0a, 1, 0x42),SCE(0x10ab, 0, 0x82), SCE(0x2d0b, 1, 0x42),SCE(0x10ac, 0, 0x82),SCE(0x2d0c, 1, 0x42),SCE(0x10ad, 0, 0x82), SCE(0x2d0d, 1, 0x42),SCE(0x10ae, 0, 0x82),SCE(0x2d0e, 1, 0x42),SCE(0x10af, 0, 0x82), SCE(0x2d0f, 1, 0x42),SCE(0x10b0, 0, 0x82),SCE(0x2d10, 1, 0x42),SCE(0x10b1, 0, 0x82), SCE(0x2d11, 1, 0x42),SCE(0x10b2, 0, 0x82),SCE(0x2d12, 1, 0x42),SCE(0x10b3, 0, 0x82), SCE(0x2d13, 1, 0x42),SCE(0x10b4, 0, 0x82),SCE(0x2d14, 1, 0x42),SCE(0x10b5, 0, 0x82), SCE(0x2d15, 1, 0x42),SCE(0x10b6, 0, 0x82),SCE(0x2d16, 1, 0x42),SCE(0x10b7, 0, 0x82), SCE(0x2d17, 1, 0x42),SCE(0x10b8, 0, 0x82),SCE(0x2d18, 1, 0x42),SCE(0x10b9, 0, 0x82), SCE(0x2d19, 1, 0x42),SCE(0x10ba, 0, 0x82),SCE(0x2d1a, 1, 0x42),SCE(0x10bb, 0, 0x82), SCE(0x2d1b, 1, 0x42),SCE(0x10bc, 0, 0x82),SCE(0x2d1c, 1, 0x42),SCE(0x10bd, 0, 0x82), SCE(0x2d1d, 1, 0x42),SCE(0x10be, 0, 0x82),SCE(0x2d1e, 1, 0x42),SCE(0x10bf, 0, 0x82), SCE(0x2d1f, 1, 0x42),SCE(0x00c0, 0, 0x82),SCE(0x00e0, 1, 0x42),SCE(0x00c1, 0, 0x82), SCE(0x00e1, 1, 0x42),SCE(0x10c2, 0, 0x82),SCE(0x2d22, 1, 0x42),SCE(0x00c3, 0, 0x82), SCE(0x00e3, 1, 0x42),SCE(0x10c4, 0, 0x82),SCE(0x2d24, 1, 0x42),SCE(0x00c5, 0, 0x83), SCE(0x00e5, 1, 0x43),SCE(0x212b, 2, 0x83),SCE(0x00c6, 0, 0x82),SCE(0x00e6, 1, 0x42), SCE(0x00c7, 0, 0x82),SCE(0x00e7, 1, 0x42),SCE(0x00c8, 0, 0x82),SCE(0x00e8, 1, 0x42), SCE(0x00c9, 0, 0x82),SCE(0x00e9, 1, 0x42),SCE(0x00ca, 0, 0x82),SCE(0x00ea, 1, 0x42), SCE(0x00cb, 0, 0x82),SCE(0x00eb, 1, 0x42),SCE(0x00cc, 0, 0x82),SCE(0x00ec, 1, 0x42), SCE(0x00cd, 0, 0x82),SCE(0x00ed, 1, 0x42),SCE(0x00ce, 0, 0x82),SCE(0x00ee, 1, 0x42), SCE(0x00cf, 0, 0x82),SCE(0x00ef, 1, 0x42),SCE(0x00d0, 0, 0x82),SCE(0x00f0, 1, 0x42), SCE(0x00d1, 0, 0x82),SCE(0x00f1, 1, 0x42),SCE(0x00d2, 0, 0x82),SCE(0x00f2, 1, 0x42), SCE(0x00d3, 0, 0x82),SCE(0x00f3, 1, 0x42),SCE(0x00d4, 0, 0x82),SCE(0x00f4, 1, 0x42), SCE(0x00d5, 0, 0x82),SCE(0x00f5, 1, 0x42),SCE(0x00d6, 0, 0x82),SCE(0x00f6, 1, 0x42), SCE(0x00d8, 0, 0x82),SCE(0x00f8, 1, 0x42),SCE(0x00d9, 0, 0x82),SCE(0x00f9, 1, 0x42), SCE(0x00da, 0, 0x82),SCE(0x00fa, 1, 0x42),SCE(0x00db, 0, 0x82),SCE(0x00fb, 1, 0x42), SCE(0x00dc, 0, 0x82),SCE(0x00fc, 1, 0x42),SCE(0x00dd, 0, 0x82),SCE(0x00fd, 1, 0x42), SCE(0x00de, 0, 0x82),SCE(0x00fe, 1, 0x42),SCE(0x2c25, 0, 0x82),SCE(0x2c55, 1, 0x42), SCE(0x2c26, 0, 0x82),SCE(0x2c56, 1, 0x42),SCE(0x2c27, 0, 0x82),SCE(0x2c57, 1, 0x42), SCE(0x2c28, 0, 0x82),SCE(0x2c58, 1, 0x42),SCE(0x1040f, 0, 0x82),SCE(0x10437, 1, 0x42), SCE(0x24cb, 0, 0x82),SCE(0x24e5, 1, 0x42),SCE(0x2c29, 0, 0x82),SCE(0x2c59, 1, 0x42), SCE(0x10407, 0, 0x82),SCE(0x1042f, 1, 0x42),SCE(0x2c2a, 0, 0x82),SCE(0x2c5a, 1, 0x42), SCE(0x0100, 0, 0x82),SCE(0x0101, 1, 0x42),SCE(0x0102, 0, 0x82),SCE(0x0103, 1, 0x42), SCE(0x2c2b, 0, 0x82),SCE(0x2c5b, 1, 0x42),SCE(0x0104, 0, 0x82),SCE(0x0105, 1, 0x42), SCE(0x0106, 0, 0x82),SCE(0x0107, 1, 0x42),SCE(0x0108, 0, 0x82),SCE(0x0109, 1, 0x42), SCE(0x2c2c, 0, 0x82),SCE(0x2c5c, 1, 0x42),SCE(0x010a, 0, 0x82),SCE(0x010b, 1, 0x42), SCE(0x010c, 0, 0x82),SCE(0x010d, 1, 0x42),SCE(0x010e, 0, 0x82),SCE(0x010f, 1, 0x42), SCE(0x2c2d, 0, 0x82),SCE(0x2c5d, 1, 0x42),SCE(0x0110, 0, 0x82),SCE(0x0111, 1, 0x42), SCE(0x0112, 0, 0x82),SCE(0x0113, 1, 0x42),SCE(0x0114, 0, 0x82),SCE(0x0115, 1, 0x42), SCE(0x2c2e, 0, 0x82),SCE(0x2c5e, 1, 0x42),SCE(0x0116, 0, 0x82),SCE(0x0117, 1, 0x42), SCE(0x0118, 0, 0x82),SCE(0x0119, 1, 0x42),SCE(0x011a, 0, 0x82),SCE(0x011b, 1, 0x42), SCE(0x011c, 0, 0x82),SCE(0x011d, 1, 0x42),SCE(0x011e, 0, 0x82),SCE(0x011f, 1, 0x42), SCE(0x0120, 0, 0x82),SCE(0x0121, 1, 0x42),SCE(0x0122, 0, 0x82),SCE(0x0123, 1, 0x42), SCE(0x0124, 0, 0x82),SCE(0x0125, 1, 0x42),SCE(0x0126, 0, 0x82),SCE(0x0127, 1, 0x42), SCE(0x0128, 0, 0x82),SCE(0x0129, 1, 0x42),SCE(0x012a, 0, 0x82),SCE(0x012b, 1, 0x42), SCE(0x00c5, 0, 0x83),SCE(0x00e5, 1, 0x43),SCE(0x212b, 2, 0x83),SCE(0x012c, 0, 0x82), SCE(0x012d, 1, 0x42),SCE(0x012e, 0, 0x82),SCE(0x012f, 1, 0x42),SCE(0x0132, 0, 0x82), SCE(0x0133, 1, 0x42),SCE(0x0134, 0, 0x82),SCE(0x0135, 1, 0x42),SCE(0x0136, 0, 0x82), SCE(0x0137, 1, 0x42),SCE(0x0139, 0, 0x82),SCE(0x013a, 1, 0x42),SCE(0x013b, 0, 0x82), SCE(0x013c, 1, 0x42),SCE(0x2cde, 0, 0x82),SCE(0x2cdf, 1, 0x42),SCE(0x013d, 0, 0x82), SCE(0x013e, 1, 0x42),SCE(0x013f, 0, 0x82),SCE(0x0140, 1, 0x42),SCE(0x0141, 0, 0x82), SCE(0x0142, 1, 0x42),SCE(0x0143, 0, 0x82),SCE(0x0144, 1, 0x42),SCE(0x0145, 0, 0x82), SCE(0x0146, 1, 0x42),SCE(0x0147, 0, 0x82),SCE(0x0148, 1, 0x42),SCE(0x014a, 0, 0x82), SCE(0x014b, 1, 0x42),SCE(0x014c, 0, 0x82),SCE(0x014d, 1, 0x42),SCE(0x014e, 0, 0x82), SCE(0x014f, 1, 0x42),SCE(0x0150, 0, 0x82),SCE(0x0151, 1, 0x42),SCE(0x0152, 0, 0x82), SCE(0x0153, 1, 0x42),SCE(0x0154, 0, 0x82),SCE(0x0155, 1, 0x42),SCE(0x0156, 0, 0x82), SCE(0x0157, 1, 0x42),SCE(0x0158, 0, 0x82),SCE(0x0159, 1, 0x42),SCE(0x015a, 0, 0x82), SCE(0x015b, 1, 0x42),SCE(0x015c, 0, 0x82),SCE(0x015d, 1, 0x42),SCE(0x015e, 0, 0x82), SCE(0x015f, 1, 0x42),SCE(0x0160, 0, 0x82),SCE(0x0161, 1, 0x42),SCE(0x2161, 0, 0x82), SCE(0x2171, 1, 0x42),SCE(0x0162, 0, 0x82),SCE(0x0163, 1, 0x42),SCE(0x2163, 0, 0x82), SCE(0x2173, 1, 0x42),SCE(0x0164, 0, 0x82),SCE(0x0165, 1, 0x42),SCE(0x2165, 0, 0x82), SCE(0x2175, 1, 0x42),SCE(0x0166, 0, 0x82),SCE(0x0167, 1, 0x42),SCE(0x2167, 0, 0x82), SCE(0x2177, 1, 0x42),SCE(0x0168, 0, 0x82),SCE(0x0169, 1, 0x42),SCE(0x2169, 0, 0x82), SCE(0x2179, 1, 0x42),SCE(0x016a, 0, 0x82),SCE(0x016b, 1, 0x42),SCE(0x216b, 0, 0x82), SCE(0x217b, 1, 0x42),SCE(0x016c, 0, 0x82),SCE(0x016d, 1, 0x42),SCE(0x216d, 0, 0x82), SCE(0x217d, 1, 0x42),SCE(0x016e, 0, 0x82),SCE(0x016f, 1, 0x42),SCE(0x216f, 0, 0x82), SCE(0x217f, 1, 0x42),SCE(0x0170, 0, 0x82),SCE(0x0171, 1, 0x42),SCE(0x2ccc, 0, 0x82), SCE(0x2ccd, 1, 0x42),SCE(0x0172, 0, 0x82),SCE(0x0173, 1, 0x42),SCE(0x0174, 0, 0x82), SCE(0x0175, 1, 0x42),SCE(0x0176, 0, 0x82),SCE(0x0177, 1, 0x42),SCE(0x00ff, 0, 0x42), SCE(0x0178, 1, 0x82),SCE(0x0179, 0, 0x82),SCE(0x017a, 1, 0x42),SCE(0x017b, 0, 0x82), SCE(0x017c, 1, 0x42),SCE(0x017d, 0, 0x82),SCE(0x017e, 1, 0x42),SCE(0x0053, 0, 0x83), SCE(0x0073, 1, 0x43),SCE(0x017f, 2, 0x43),SCE(0x0181, 0, 0x82),SCE(0x0253, 1, 0x42), SCE(0x0182, 0, 0x82),SCE(0x0183, 1, 0x42),SCE(0x2183, 0, 0x82),SCE(0x2184, 1, 0x42), SCE(0x0184, 0, 0x82),SCE(0x0185, 1, 0x42),SCE(0x0186, 0, 0x82),SCE(0x0254, 1, 0x42), SCE(0x0187, 0, 0x82),SCE(0x0188, 1, 0x42),SCE(0x0189, 0, 0x82),SCE(0x0256, 1, 0x42), SCE(0x018a, 0, 0x82),SCE(0x0257, 1, 0x42),SCE(0x018b, 0, 0x82),SCE(0x018c, 1, 0x42), SCE(0x018e, 0, 0x82),SCE(0x01dd, 1, 0x42),SCE(0x018f, 0, 0x82),SCE(0x0259, 1, 0x42), SCE(0x0190, 0, 0x82),SCE(0x025b, 1, 0x42),SCE(0x0191, 0, 0x82),SCE(0x0192, 1, 0x42), SCE(0x0193, 0, 0x82),SCE(0x0260, 1, 0x42),SCE(0x0194, 0, 0x82),SCE(0x0263, 1, 0x42), SCE(0x0196, 0, 0x82),SCE(0x0269, 1, 0x42),SCE(0x0197, 0, 0x82),SCE(0x0268, 1, 0x42), SCE(0x0198, 0, 0x82),SCE(0x0199, 1, 0x42),SCE(0x019c, 0, 0x82),SCE(0x026f, 1, 0x42), SCE(0x019d, 0, 0x82),SCE(0x0272, 1, 0x42),SCE(0x019f, 0, 0x82),SCE(0x0275, 1, 0x42), SCE(0x01a0, 0, 0x82),SCE(0x01a1, 1, 0x42),SCE(0x01a2, 0, 0x82),SCE(0x01a3, 1, 0x42), SCE(0x01a4, 0, 0x82),SCE(0x01a5, 1, 0x42),SCE(0x01a6, 0, 0x82),SCE(0x0280, 1, 0x42), SCE(0x01a7, 0, 0x82),SCE(0x01a8, 1, 0x42),SCE(0x01a9, 0, 0x82),SCE(0x0283, 1, 0x42), SCE(0x01ac, 0, 0x82),SCE(0x01ad, 1, 0x42),SCE(0x01ae, 0, 0x82),SCE(0x0288, 1, 0x42), SCE(0x01af, 0, 0x82),SCE(0x01b0, 1, 0x42),SCE(0x01b1, 0, 0x82),SCE(0x028a, 1, 0x42), SCE(0x01b2, 0, 0x82),SCE(0x028b, 1, 0x42),SCE(0x01b3, 0, 0x82),SCE(0x01b4, 1, 0x42), SCE(0x01b5, 0, 0x82),SCE(0x01b6, 1, 0x42),SCE(0x01b7, 0, 0x82),SCE(0x0292, 1, 0x42), SCE(0x01b8, 0, 0x82),SCE(0x01b9, 1, 0x42),SCE(0x01bc, 0, 0x82),SCE(0x01bd, 1, 0x42), SCE(0x01c4, 0, 0x83),SCE(0x01c5, 1, 0x3),SCE(0x01c6, 2, 0x43),SCE(0x01c4, 0, 0x83), SCE(0x01c5, 1, 0x3),SCE(0x01c6, 2, 0x43),SCE(0x01c7, 0, 0x83),SCE(0x01c8, 1, 0x3), SCE(0x01c9, 2, 0x43),SCE(0x01c7, 0, 0x83),SCE(0x01c8, 1, 0x3),SCE(0x01c9, 2, 0x43), SCE(0x01ca, 0, 0x83),SCE(0x01cb, 1, 0x3),SCE(0x01cc, 2, 0x43),SCE(0x01ca, 0, 0x83), SCE(0x01cb, 1, 0x3),SCE(0x01cc, 2, 0x43),SCE(0x01cd, 0, 0x82),SCE(0x01ce, 1, 0x42), SCE(0x01cf, 0, 0x82),SCE(0x01d0, 1, 0x42),SCE(0x01d1, 0, 0x82),SCE(0x01d2, 1, 0x42), SCE(0x01d3, 0, 0x82),SCE(0x01d4, 1, 0x42),SCE(0x01d5, 0, 0x82),SCE(0x01d6, 1, 0x42), SCE(0x01d7, 0, 0x82),SCE(0x01d8, 1, 0x42),SCE(0x01d9, 0, 0x82),SCE(0x01da, 1, 0x42), SCE(0x01db, 0, 0x82),SCE(0x01dc, 1, 0x42),SCE(0x01de, 0, 0x82),SCE(0x01df, 1, 0x42), SCE(0xff36, 0, 0x82),SCE(0xff56, 1, 0x42),SCE(0x01e0, 0, 0x82),SCE(0x01e1, 1, 0x42), SCE(0x01e2, 0, 0x82),SCE(0x01e3, 1, 0x42),SCE(0x01e4, 0, 0x82),SCE(0x01e5, 1, 0x42), SCE(0x01e6, 0, 0x82),SCE(0x01e7, 1, 0x42),SCE(0x01e8, 0, 0x82),SCE(0x01e9, 1, 0x42), SCE(0x01ea, 0, 0x82),SCE(0x01eb, 1, 0x42),SCE(0x01ec, 0, 0x82),SCE(0x01ed, 1, 0x42), SCE(0x01ee, 0, 0x82),SCE(0x01ef, 1, 0x42),SCE(0x01f1, 0, 0x83),SCE(0x01f2, 1, 0x3), SCE(0x01f3, 2, 0x43),SCE(0x01f1, 0, 0x83),SCE(0x01f2, 1, 0x3),SCE(0x01f3, 2, 0x43), SCE(0x01f4, 0, 0x82),SCE(0x01f5, 1, 0x42),SCE(0x0195, 0, 0x42),SCE(0x01f6, 1, 0x82), SCE(0x01bf, 0, 0x42),SCE(0x01f7, 1, 0x82),SCE(0x01f8, 0, 0x82),SCE(0x01f9, 1, 0x42), SCE(0x1041d, 0, 0x82),SCE(0x10445, 1, 0x42),SCE(0x01fa, 0, 0x82),SCE(0x01fb, 1, 0x42), SCE(0x01fc, 0, 0x82),SCE(0x01fd, 1, 0x42),SCE(0x01fe, 0, 0x82),SCE(0x01ff, 1, 0x42), SCE(0x0200, 0, 0x82),SCE(0x0201, 1, 0x42),SCE(0x0202, 0, 0x82),SCE(0x0203, 1, 0x42), SCE(0x0204, 0, 0x82),SCE(0x0205, 1, 0x42),SCE(0x0206, 0, 0x82),SCE(0x0207, 1, 0x42), SCE(0x0208, 0, 0x82),SCE(0x0209, 1, 0x42),SCE(0x020a, 0, 0x82),SCE(0x020b, 1, 0x42), SCE(0x020c, 0, 0x82),SCE(0x020d, 1, 0x42),SCE(0x020e, 0, 0x82),SCE(0x020f, 1, 0x42), SCE(0x0210, 0, 0x82),SCE(0x0211, 1, 0x42),SCE(0x0212, 0, 0x82),SCE(0x0213, 1, 0x42), SCE(0x0214, 0, 0x82),SCE(0x0215, 1, 0x42),SCE(0x0216, 0, 0x82),SCE(0x0217, 1, 0x42), SCE(0x0218, 0, 0x82),SCE(0x0219, 1, 0x42),SCE(0x021a, 0, 0x82),SCE(0x021b, 1, 0x42), SCE(0x021c, 0, 0x82),SCE(0x021d, 1, 0x42),SCE(0x021e, 0, 0x82),SCE(0x021f, 1, 0x42), SCE(0x019e, 0, 0x42),SCE(0x0220, 1, 0x82),SCE(0x0222, 0, 0x82),SCE(0x0223, 1, 0x42), SCE(0x0224, 0, 0x82),SCE(0x0225, 1, 0x42),SCE(0x0226, 0, 0x82),SCE(0x0227, 1, 0x42), SCE(0x0228, 0, 0x82),SCE(0x0229, 1, 0x42),SCE(0x022a, 0, 0x82),SCE(0x022b, 1, 0x42), SCE(0x022c, 0, 0x82),SCE(0x022d, 1, 0x42),SCE(0x022e, 0, 0x82),SCE(0x022f, 1, 0x42), SCE(0x0230, 0, 0x82),SCE(0x0231, 1, 0x42),SCE(0x0232, 0, 0x82),SCE(0x0233, 1, 0x42), SCE(0xa684, 0, 0x82),SCE(0xa685, 1, 0x42),SCE(0x023a, 0, 0x82),SCE(0x2c65, 1, 0x42), SCE(0x023b, 0, 0x82),SCE(0x023c, 1, 0x42),SCE(0x019a, 0, 0x42),SCE(0x023d, 1, 0x82), SCE(0x023e, 0, 0x82),SCE(0x2c66, 1, 0x42),SCE(0x0241, 0, 0x82),SCE(0x0242, 1, 0x42), SCE(0x10412, 0, 0x82),SCE(0x1043a, 1, 0x42),SCE(0x0180, 0, 0x42),SCE(0x0243, 1, 0x82), SCE(0x0244, 0, 0x82),SCE(0x0289, 1, 0x42),SCE(0x0245, 0, 0x82),SCE(0x028c, 1, 0x42), SCE(0x0246, 0, 0x82),SCE(0x0247, 1, 0x42),SCE(0x0248, 0, 0x82),SCE(0x0249, 1, 0x42), SCE(0x024a, 0, 0x82),SCE(0x024b, 1, 0x42),SCE(0x024c, 0, 0x82),SCE(0x024d, 1, 0x42), SCE(0x2c1b, 0, 0x82),SCE(0x2c4b, 1, 0x42),SCE(0x024e, 0, 0x82),SCE(0x024f, 1, 0x42), SCE(0x1040a, 0, 0x82),SCE(0x10432, 1, 0x42),SCE(0x2160, 0, 0x82),SCE(0x2170, 1, 0x42), SCE(0xa692, 0, 0x82),SCE(0xa693, 1, 0x42),SCE(0x027d, 0, 0x42),SCE(0x2c64, 1, 0x82), SCE(0x10410, 0, 0x82),SCE(0x10438, 1, 0x42),SCE(0x2c21, 0, 0x82),SCE(0x2c51, 1, 0x42), SCE(0x2c69, 0, 0x82),SCE(0x2c6a, 1, 0x42),SCE(0x10409, 0, 0x82),SCE(0x10431, 1, 0x42), SCE(0x10414, 0, 0x82),SCE(0x1043c, 1, 0x42),SCE(0x2162, 0, 0x82),SCE(0x2172, 1, 0x42), SCE(0x1041e, 0, 0x82),SCE(0x10446, 1, 0x42),SCE(0x0271, 0, 0x42),SCE(0x2c6e, 1, 0x82), SCE(0x10415, 0, 0x82),SCE(0x1043d, 1, 0x42),SCE(0x0252, 0, 0x42),SCE(0x2c70, 1, 0x82), SCE(0x2c72, 0, 0x82),SCE(0x2c73, 1, 0x42),SCE(0x2c0b, 0, 0x82),SCE(0x2c3b, 1, 0x42), SCE(0x10416, 0, 0x82),SCE(0x1043e, 1, 0x42),SCE(0x2c75, 0, 0x82),SCE(0x2c76, 1, 0x42), SCE(0x2164, 0, 0x82),SCE(0x2174, 1, 0x42),SCE(0xa640, 0, 0x82),SCE(0xa641, 1, 0x42), SCE(0xff22, 0, 0x82),SCE(0xff42, 1, 0x42),SCE(0x2c0c, 0, 0x82),SCE(0x2c3c, 1, 0x42), SCE(0x10417, 0, 0x82),SCE(0x1043f, 1, 0x42),SCE(0xff24, 0, 0x82),SCE(0xff44, 1, 0x42), SCE(0xff25, 0, 0x82),SCE(0xff45, 1, 0x42),SCE(0xff26, 0, 0x82),SCE(0xff46, 1, 0x42), SCE(0x2c0d, 0, 0x82),SCE(0x2c3d, 1, 0x42),SCE(0x24c1, 0, 0x82),SCE(0x24db, 1, 0x42), SCE(0xa728, 0, 0x82),SCE(0xa729, 1, 0x42),SCE(0x023f, 0, 0x42),SCE(0x2c7e, 1, 0x82), SCE(0x10411, 0, 0x82),SCE(0x10439, 1, 0x42),SCE(0xff29, 0, 0x82),SCE(0xff49, 1, 0x42), SCE(0x1040b, 0, 0x82),SCE(0x10433, 1, 0x42),SCE(0xa72a, 0, 0x82),SCE(0xa72b, 1, 0x42), SCE(0x2c80, 0, 0x82),SCE(0x2c81, 1, 0x42),SCE(0xff2b, 0, 0x82),SCE(0xff4b, 1, 0x42), SCE(0xa72c, 0, 0x82),SCE(0xa72d, 1, 0x42),SCE(0x2c0e, 0, 0x82),SCE(0x2c3e, 1, 0x42), SCE(0xff2d, 0, 0x82),SCE(0xff4d, 1, 0x42),SCE(0x10419, 0, 0x82),SCE(0x10441, 1, 0x42), SCE(0xa72e, 0, 0x82),SCE(0xa72f, 1, 0x42),SCE(0x1040d, 0, 0x82),SCE(0x10435, 1, 0x42), SCE(0xff2f, 0, 0x82),SCE(0xff4f, 1, 0x42),SCE(0xff31, 0, 0x82),SCE(0xff51, 1, 0x42), SCE(0xff32, 0, 0x82),SCE(0xff52, 1, 0x42),SCE(0x1041a, 0, 0x82),SCE(0x10442, 1, 0x42), SCE(0xff34, 0, 0x82),SCE(0xff54, 1, 0x42),SCE(0x2c98, 0, 0x82),SCE(0x2c99, 1, 0x42), SCE(0x2c8a, 0, 0x82),SCE(0x2c8b, 1, 0x42),SCE(0x0345, 0, 0x44),SCE(0x0399, 1, 0x84), SCE(0x03b9, 2, 0x44),SCE(0x1fbe, 3, 0x44),SCE(0x2c8c, 0, 0x82),SCE(0x2c8d, 1, 0x42), SCE(0xff37, 0, 0x82),SCE(0xff57, 1, 0x42),SCE(0xa656, 0, 0x82),SCE(0xa657, 1, 0x42), SCE(0x1041b, 0, 0x82),SCE(0x10443, 1, 0x42),SCE(0xa738, 0, 0x82),SCE(0xa739, 1, 0x42), SCE(0x2c8e, 0, 0x82),SCE(0x2c8f, 1, 0x42),SCE(0xff39, 0, 0x82),SCE(0xff59, 1, 0x42), SCE(0x10404, 0, 0x82),SCE(0x1042c, 1, 0x42),SCE(0xa73a, 0, 0x82),SCE(0xa73b, 1, 0x42), SCE(0x2c90, 0, 0x82),SCE(0x2c91, 1, 0x42),SCE(0xa73c, 0, 0x82),SCE(0xa73d, 1, 0x42), SCE(0x2c92, 0, 0x82),SCE(0x2c93, 1, 0x42),SCE(0x1041c, 0, 0x82),SCE(0x10444, 1, 0x42), SCE(0x0370, 0, 0x82),SCE(0x0371, 1, 0x42),SCE(0x0372, 0, 0x82),SCE(0x0373, 1, 0x42), SCE(0xa73e, 0, 0x82),SCE(0xa73f, 1, 0x42),SCE(0x0376, 0, 0x82),SCE(0x0377, 1, 0x42), SCE(0x2c94, 0, 0x82),SCE(0x2c95, 1, 0x42),SCE(0x2c96, 0, 0x82),SCE(0x2c97, 1, 0x42), SCE(0x0386, 0, 0x82),SCE(0x03ac, 1, 0x42),SCE(0x10405, 0, 0x82),SCE(0x1042d, 1, 0x42), SCE(0x0388, 0, 0x82),SCE(0x03ad, 1, 0x42),SCE(0x0389, 0, 0x82),SCE(0x03ae, 1, 0x42), SCE(0x038a, 0, 0x82),SCE(0x03af, 1, 0x42),SCE(0x038c, 0, 0x82),SCE(0x03cc, 1, 0x42), SCE(0x038e, 0, 0x82),SCE(0x03cd, 1, 0x42),SCE(0x038f, 0, 0x82),SCE(0x03ce, 1, 0x42), SCE(0x0391, 0, 0x82),SCE(0x03b1, 1, 0x42),SCE(0x0392, 0, 0x83),SCE(0x03b2, 1, 0x43), SCE(0x03d0, 2, 0x43),SCE(0x0393, 0, 0x82),SCE(0x03b3, 1, 0x42),SCE(0x0394, 0, 0x82), SCE(0x03b4, 1, 0x42),SCE(0x0395, 0, 0x83),SCE(0x03b5, 1, 0x43),SCE(0x03f5, 2, 0x43), SCE(0x0396, 0, 0x82),SCE(0x03b6, 1, 0x42),SCE(0x0397, 0, 0x82),SCE(0x03b7, 1, 0x42), SCE(0x0398, 0, 0x84),SCE(0x03b8, 1, 0x44),SCE(0x03d1, 2, 0x44),SCE(0x03f4, 3, 0x84), SCE(0x0345, 0, 0x44),SCE(0x0399, 1, 0x84),SCE(0x03b9, 2, 0x44),SCE(0x1fbe, 3, 0x44), SCE(0x039a, 0, 0x83),SCE(0x03ba, 1, 0x43),SCE(0x03f0, 2, 0x43),SCE(0x039b, 0, 0x82), SCE(0x03bb, 1, 0x42),SCE(0x00b5, 0, 0x43),SCE(0x039c, 1, 0x83),SCE(0x03bc, 2, 0x43), SCE(0x039d, 0, 0x82),SCE(0x03bd, 1, 0x42),SCE(0x039e, 0, 0x82),SCE(0x03be, 1, 0x42), SCE(0x039f, 0, 0x82),SCE(0x03bf, 1, 0x42),SCE(0x03a0, 0, 0x83),SCE(0x03c0, 1, 0x43), SCE(0x03d6, 2, 0x43),SCE(0x03a1, 0, 0x83),SCE(0x03c1, 1, 0x43),SCE(0x03f1, 2, 0x43), SCE(0x03a3, 0, 0x83),SCE(0x03c2, 1, 0x43),SCE(0x03c3, 2, 0x43),SCE(0x03a4, 0, 0x82), SCE(0x03c4, 1, 0x42),SCE(0x03a5, 0, 0x82),SCE(0x03c5, 1, 0x42),SCE(0x03a6, 0, 0x83), SCE(0x03c6, 1, 0x43),SCE(0x03d5, 2, 0x43),SCE(0x03a7, 0, 0x82),SCE(0x03c7, 1, 0x42), SCE(0x03a8, 0, 0x82),SCE(0x03c8, 1, 0x42),SCE(0x03a9, 0, 0x83),SCE(0x03c9, 1, 0x43), SCE(0x2126, 2, 0x83),SCE(0x03aa, 0, 0x82),SCE(0x03ca, 1, 0x42),SCE(0x03ab, 0, 0x82), SCE(0x03cb, 1, 0x42),SCE(0x24c9, 0, 0x82),SCE(0x24e3, 1, 0x42),SCE(0x2ce0, 0, 0x82), SCE(0x2ce1, 1, 0x42),SCE(0xa748, 0, 0x82),SCE(0xa749, 1, 0x42),SCE(0x2c9c, 0, 0x82), SCE(0x2c9d, 1, 0x42),SCE(0x2c9e, 0, 0x82),SCE(0x2c9f, 1, 0x42),SCE(0xa74a, 0, 0x82), SCE(0xa74b, 1, 0x42),SCE(0x2ca0, 0, 0x82),SCE(0x2ca1, 1, 0x42),SCE(0x03a3, 0, 0x83), SCE(0x03c2, 1, 0x43),SCE(0x03c3, 2, 0x43),SCE(0x1041f, 0, 0x82),SCE(0x10447, 1, 0x42), SCE(0xa74c, 0, 0x82),SCE(0xa74d, 1, 0x42),SCE(0xa68a, 0, 0x82),SCE(0xa68b, 1, 0x42), SCE(0x2ca2, 0, 0x82),SCE(0x2ca3, 1, 0x42),SCE(0x03cf, 0, 0x82),SCE(0x03d7, 1, 0x42), SCE(0x0392, 0, 0x83),SCE(0x03b2, 1, 0x43),SCE(0x03d0, 2, 0x43),SCE(0x0398, 0, 0x84), SCE(0x03b8, 1, 0x44),SCE(0x03d1, 2, 0x44),SCE(0x03f4, 3, 0x84),SCE(0x03a6, 0, 0x83), SCE(0x03c6, 1, 0x43),SCE(0x03d5, 2, 0x43),SCE(0x03a0, 0, 0x83),SCE(0x03c0, 1, 0x43), SCE(0x03d6, 2, 0x43),SCE(0x03d8, 0, 0x82),SCE(0x03d9, 1, 0x42),SCE(0x2ca4, 0, 0x82), SCE(0x2ca5, 1, 0x42),SCE(0x03da, 0, 0x82),SCE(0x03db, 1, 0x42),SCE(0x03dc, 0, 0x82), SCE(0x03dd, 1, 0x42),SCE(0x03de, 0, 0x82),SCE(0x03df, 1, 0x42),SCE(0x03e0, 0, 0x82), SCE(0x03e1, 1, 0x42),SCE(0x03e2, 0, 0x82),SCE(0x03e3, 1, 0x42),SCE(0x03e4, 0, 0x82), SCE(0x03e5, 1, 0x42),SCE(0x2ca6, 0, 0x82),SCE(0x2ca7, 1, 0x42),SCE(0x03e6, 0, 0x82), SCE(0x03e7, 1, 0x42),SCE(0x10420, 0, 0x82),SCE(0x10448, 1, 0x42),SCE(0x03e8, 0, 0x82), SCE(0x03e9, 1, 0x42),SCE(0x2ce2, 0, 0x82),SCE(0x2ce3, 1, 0x42),SCE(0x03ea, 0, 0x82), SCE(0x03eb, 1, 0x42),SCE(0x03ec, 0, 0x82),SCE(0x03ed, 1, 0x42),SCE(0x03ee, 0, 0x82), SCE(0x03ef, 1, 0x42),SCE(0x039a, 0, 0x83),SCE(0x03ba, 1, 0x43),SCE(0x03f0, 2, 0x43), SCE(0x03a1, 0, 0x83),SCE(0x03c1, 1, 0x43),SCE(0x03f1, 2, 0x43),SCE(0x0398, 0, 0x84), SCE(0x03b8, 1, 0x44),SCE(0x03d1, 2, 0x44),SCE(0x03f4, 3, 0x84),SCE(0x0395, 0, 0x83), SCE(0x03b5, 1, 0x43),SCE(0x03f5, 2, 0x43),SCE(0x03f7, 0, 0x82),SCE(0x03f8, 1, 0x42), SCE(0x03f2, 0, 0x42),SCE(0x03f9, 1, 0x82),SCE(0x03fa, 0, 0x82),SCE(0x03fb, 1, 0x42), SCE(0x037b, 0, 0x42),SCE(0x03fd, 1, 0x82),SCE(0x037c, 0, 0x42),SCE(0x03fe, 1, 0x82), SCE(0x037d, 0, 0x42),SCE(0x03ff, 1, 0x82),SCE(0x0400, 0, 0x82),SCE(0x0450, 1, 0x42), SCE(0x0401, 0, 0x82),SCE(0x0451, 1, 0x42),SCE(0x0402, 0, 0x82),SCE(0x0452, 1, 0x42), SCE(0x0403, 0, 0x82),SCE(0x0453, 1, 0x42),SCE(0x0404, 0, 0x82),SCE(0x0454, 1, 0x42), SCE(0x0405, 0, 0x82),SCE(0x0455, 1, 0x42),SCE(0x0406, 0, 0x82),SCE(0x0456, 1, 0x42), SCE(0x0407, 0, 0x82),SCE(0x0457, 1, 0x42),SCE(0x0408, 0, 0x82),SCE(0x0458, 1, 0x42), SCE(0x0409, 0, 0x82),SCE(0x0459, 1, 0x42),SCE(0x040a, 0, 0x82),SCE(0x045a, 1, 0x42), SCE(0x040b, 0, 0x82),SCE(0x045b, 1, 0x42),SCE(0x040c, 0, 0x82),SCE(0x045c, 1, 0x42), SCE(0x040d, 0, 0x82),SCE(0x045d, 1, 0x42),SCE(0x040e, 0, 0x82),SCE(0x045e, 1, 0x42), SCE(0x040f, 0, 0x82),SCE(0x045f, 1, 0x42),SCE(0x0410, 0, 0x82),SCE(0x0430, 1, 0x42), SCE(0x0411, 0, 0x82),SCE(0x0431, 1, 0x42),SCE(0x0412, 0, 0x82),SCE(0x0432, 1, 0x42), SCE(0x0413, 0, 0x82),SCE(0x0433, 1, 0x42),SCE(0x0414, 0, 0x82),SCE(0x0434, 1, 0x42), SCE(0x0415, 0, 0x82),SCE(0x0435, 1, 0x42),SCE(0x0416, 0, 0x82),SCE(0x0436, 1, 0x42), SCE(0x0417, 0, 0x82),SCE(0x0437, 1, 0x42),SCE(0x0418, 0, 0x82),SCE(0x0438, 1, 0x42), SCE(0x0419, 0, 0x82),SCE(0x0439, 1, 0x42),SCE(0x041a, 0, 0x82),SCE(0x043a, 1, 0x42), SCE(0x041b, 0, 0x82),SCE(0x043b, 1, 0x42),SCE(0x041c, 0, 0x82),SCE(0x043c, 1, 0x42), SCE(0x041d, 0, 0x82),SCE(0x043d, 1, 0x42),SCE(0x041e, 0, 0x82),SCE(0x043e, 1, 0x42), SCE(0x041f, 0, 0x82),SCE(0x043f, 1, 0x42),SCE(0x0420, 0, 0x82),SCE(0x0440, 1, 0x42), SCE(0x0421, 0, 0x82),SCE(0x0441, 1, 0x42),SCE(0x0422, 0, 0x82),SCE(0x0442, 1, 0x42), SCE(0x0423, 0, 0x82),SCE(0x0443, 1, 0x42),SCE(0x0424, 0, 0x82),SCE(0x0444, 1, 0x42), SCE(0x0425, 0, 0x82),SCE(0x0445, 1, 0x42),SCE(0x0426, 0, 0x82),SCE(0x0446, 1, 0x42), SCE(0x0427, 0, 0x82),SCE(0x0447, 1, 0x42),SCE(0x0428, 0, 0x82),SCE(0x0448, 1, 0x42), SCE(0x0429, 0, 0x82),SCE(0x0449, 1, 0x42),SCE(0x042a, 0, 0x82),SCE(0x044a, 1, 0x42), SCE(0x042b, 0, 0x82),SCE(0x044b, 1, 0x42),SCE(0x042c, 0, 0x82),SCE(0x044c, 1, 0x42), SCE(0x042d, 0, 0x82),SCE(0x044d, 1, 0x42),SCE(0x042e, 0, 0x82),SCE(0x044e, 1, 0x42), SCE(0x042f, 0, 0x82),SCE(0x044f, 1, 0x42),SCE(0xff3a, 0, 0x82),SCE(0xff5a, 1, 0x42), SCE(0x2cb4, 0, 0x82),SCE(0x2cb5, 1, 0x42),SCE(0x00b5, 0, 0x43),SCE(0x039c, 1, 0x83), SCE(0x03bc, 2, 0x43),SCE(0x10423, 0, 0x82),SCE(0x1044b, 1, 0x42),SCE(0x24b6, 0, 0x82), SCE(0x24d0, 1, 0x42),SCE(0x24b8, 0, 0x82),SCE(0x24d2, 1, 0x42),SCE(0xff2c, 0, 0x82), SCE(0xff4c, 1, 0x42),SCE(0x10421, 0, 0x82),SCE(0x10449, 1, 0x42),SCE(0x24ba, 0, 0x82), SCE(0x24d4, 1, 0x42),SCE(0x10424, 0, 0x82),SCE(0x1044c, 1, 0x42),SCE(0x0460, 0, 0x82), SCE(0x0461, 1, 0x42),SCE(0x0462, 0, 0x82),SCE(0x0463, 1, 0x42),SCE(0x1d7d, 0, 0x42), SCE(0x2c63, 1, 0x82),SCE(0x0464, 0, 0x82),SCE(0x0465, 1, 0x42),SCE(0x0466, 0, 0x82), SCE(0x0467, 1, 0x42),SCE(0x2c67, 0, 0x82),SCE(0x2c68, 1, 0x42),SCE(0x0468, 0, 0x82), SCE(0x0469, 1, 0x42),SCE(0x24bc, 0, 0x82),SCE(0x24d6, 1, 0x42),SCE(0x046a, 0, 0x82), SCE(0x046b, 1, 0x42),SCE(0x2c6b, 0, 0x82),SCE(0x2c6c, 1, 0x42),SCE(0x046c, 0, 0x82), SCE(0x046d, 1, 0x42),SCE(0x0251, 0, 0x42),SCE(0x2c6d, 1, 0x82),SCE(0x046e, 0, 0x82), SCE(0x046f, 1, 0x42),SCE(0x0250, 0, 0x42),SCE(0x2c6f, 1, 0x82),SCE(0x0470, 0, 0x82), SCE(0x0471, 1, 0x42),SCE(0xa768, 0, 0x82),SCE(0xa769, 1, 0x42),SCE(0x0472, 0, 0x82), SCE(0x0473, 1, 0x42),SCE(0x0474, 0, 0x82),SCE(0x0475, 1, 0x42),SCE(0x24be, 0, 0x82), SCE(0x24d8, 1, 0x42),SCE(0x0476, 0, 0x82),SCE(0x0477, 1, 0x42),SCE(0x0478, 0, 0x82), SCE(0x0479, 1, 0x42),SCE(0x047a, 0, 0x82),SCE(0x047b, 1, 0x42),SCE(0x047c, 0, 0x82), SCE(0x047d, 1, 0x42),SCE(0xa76a, 0, 0x82),SCE(0xa76b, 1, 0x42),SCE(0x047e, 0, 0x82), SCE(0x047f, 1, 0x42),SCE(0x0240, 0, 0x42),SCE(0x2c7f, 1, 0x82),SCE(0x0480, 0, 0x82), SCE(0x0481, 1, 0x42),SCE(0x10c0, 0, 0x82),SCE(0x2d20, 1, 0x42),SCE(0x2c82, 0, 0x82), SCE(0x2c83, 1, 0x42),SCE(0x2c84, 0, 0x82),SCE(0x2c85, 1, 0x42),SCE(0x2c86, 0, 0x82), SCE(0x2c87, 1, 0x42),SCE(0x10c1, 0, 0x82),SCE(0x2d21, 1, 0x42),SCE(0x2c88, 0, 0x82), SCE(0x2c89, 1, 0x42),SCE(0xa76c, 0, 0x82),SCE(0xa76d, 1, 0x42),SCE(0x048a, 0, 0x82), SCE(0x048b, 1, 0x42),SCE(0x048c, 0, 0x82),SCE(0x048d, 1, 0x42),SCE(0x00c2, 0, 0x82), SCE(0x00e2, 1, 0x42),SCE(0x048e, 0, 0x82),SCE(0x048f, 1, 0x42),SCE(0x0490, 0, 0x82), SCE(0x0491, 1, 0x42),SCE(0x0492, 0, 0x82),SCE(0x0493, 1, 0x42),SCE(0x10c3, 0, 0x82), SCE(0x2d23, 1, 0x42),SCE(0x0494, 0, 0x82),SCE(0x0495, 1, 0x42),SCE(0xa76e, 0, 0x82), SCE(0xa76f, 1, 0x42),SCE(0x0496, 0, 0x82),SCE(0x0497, 1, 0x42),SCE(0x0498, 0, 0x82), SCE(0x0499, 1, 0x42),SCE(0x00c4, 0, 0x82),SCE(0x00e4, 1, 0x42),SCE(0x049a, 0, 0x82), SCE(0x049b, 1, 0x42),SCE(0x10426, 0, 0x82),SCE(0x1044e, 1, 0x42),SCE(0x049c, 0, 0x82), SCE(0x049d, 1, 0x42),SCE(0x049e, 0, 0x82),SCE(0x049f, 1, 0x42),SCE(0x10c5, 0, 0x82), SCE(0x2d25, 1, 0x42),SCE(0x04a0, 0, 0x82),SCE(0x04a1, 1, 0x42),SCE(0x04a2, 0, 0x82), SCE(0x04a3, 1, 0x42),SCE(0x04a4, 0, 0x82),SCE(0x04a5, 1, 0x42),SCE(0x2cc6, 0, 0x82), SCE(0x2cc7, 1, 0x42),SCE(0x04a6, 0, 0x82),SCE(0x04a7, 1, 0x42),SCE(0x04a8, 0, 0x82), SCE(0x04a9, 1, 0x42),SCE(0x2c60, 0, 0x82),SCE(0x2c61, 1, 0x42),SCE(0x04aa, 0, 0x82), SCE(0x04ab, 1, 0x42),SCE(0x10c7, 0, 0x82),SCE(0x2d27, 1, 0x42),SCE(0x04ac, 0, 0x82), SCE(0x04ad, 1, 0x42),SCE(0x10413, 0, 0x82),SCE(0x1043b, 1, 0x42),SCE(0x04ae, 0, 0x82), SCE(0x04af, 1, 0x42),SCE(0x04b0, 0, 0x82),SCE(0x04b1, 1, 0x42),SCE(0x2cc8, 0, 0x82), SCE(0x2cc9, 1, 0x42),SCE(0x04b2, 0, 0x82),SCE(0x04b3, 1, 0x42),SCE(0x04b4, 0, 0x82), SCE(0x04b5, 1, 0x42),SCE(0x04b6, 0, 0x82),SCE(0x04b7, 1, 0x42),SCE(0x24b7, 0, 0x82), SCE(0x24d1, 1, 0x42),SCE(0x04b8, 0, 0x82),SCE(0x04b9, 1, 0x42),SCE(0x24b9, 0, 0x82), SCE(0x24d3, 1, 0x42),SCE(0x04ba, 0, 0x82),SCE(0x04bb, 1, 0x42),SCE(0x24bb, 0, 0x82), SCE(0x24d5, 1, 0x42),SCE(0x04bc, 0, 0x82),SCE(0x04bd, 1, 0x42),SCE(0x24bd, 0, 0x82), SCE(0x24d7, 1, 0x42),SCE(0x04be, 0, 0x82),SCE(0x04bf, 1, 0x42),SCE(0x24bf, 0, 0x82), SCE(0x24d9, 1, 0x42),SCE(0x04c0, 0, 0x82),SCE(0x04cf, 1, 0x42),SCE(0x04c1, 0, 0x82), SCE(0x04c2, 1, 0x42),SCE(0x24c2, 0, 0x82),SCE(0x24dc, 1, 0x42),SCE(0x04c3, 0, 0x82), SCE(0x04c4, 1, 0x42),SCE(0x24c4, 0, 0x82),SCE(0x24de, 1, 0x42),SCE(0x04c5, 0, 0x82), SCE(0x04c6, 1, 0x42),SCE(0x24c6, 0, 0x82),SCE(0x24e0, 1, 0x42),SCE(0x04c7, 0, 0x82), SCE(0x04c8, 1, 0x42),SCE(0x24c8, 0, 0x82),SCE(0x24e2, 1, 0x42),SCE(0x04c9, 0, 0x82), SCE(0x04ca, 1, 0x42),SCE(0x24ca, 0, 0x82),SCE(0x24e4, 1, 0x42),SCE(0x04cb, 0, 0x82), SCE(0x04cc, 1, 0x42),SCE(0x24cc, 0, 0x82),SCE(0x24e6, 1, 0x42),SCE(0x04cd, 0, 0x82), SCE(0x04ce, 1, 0x42),SCE(0x24ce, 0, 0x82),SCE(0x24e8, 1, 0x42),SCE(0x10cd, 0, 0x82), SCE(0x2d2d, 1, 0x42),SCE(0x04d0, 0, 0x82),SCE(0x04d1, 1, 0x42),SCE(0x04d2, 0, 0x82), SCE(0x04d3, 1, 0x42),SCE(0x04d4, 0, 0x82),SCE(0x04d5, 1, 0x42),SCE(0x2cce, 0, 0x82), SCE(0x2ccf, 1, 0x42),SCE(0x04d6, 0, 0x82),SCE(0x04d7, 1, 0x42),SCE(0xa779, 0, 0x82), SCE(0xa77a, 1, 0x42),SCE(0x04d8, 0, 0x82),SCE(0x04d9, 1, 0x42),SCE(0x04da, 0, 0x82), SCE(0x04db, 1, 0x42),SCE(0x24cf, 0, 0x82),SCE(0x24e9, 1, 0x42),SCE(0x04dc, 0, 0x82), SCE(0x04dd, 1, 0x42),SCE(0x04de, 0, 0x82),SCE(0x04df, 1, 0x42),SCE(0x04e0, 0, 0x82), SCE(0x04e1, 1, 0x42),SCE(0x2cd0, 0, 0x82),SCE(0x2cd1, 1, 0x42),SCE(0x04e2, 0, 0x82), SCE(0x04e3, 1, 0x42),SCE(0x04e4, 0, 0x82),SCE(0x04e5, 1, 0x42),SCE(0x026b, 0, 0x42), SCE(0x2c62, 1, 0x82),SCE(0x04e6, 0, 0x82),SCE(0x04e7, 1, 0x42),SCE(0x04e8, 0, 0x82), SCE(0x04e9, 1, 0x42),SCE(0x04ea, 0, 0x82),SCE(0x04eb, 1, 0x42),SCE(0x2132, 0, 0x82), SCE(0x214e, 1, 0x42),SCE(0x04ec, 0, 0x82),SCE(0x04ed, 1, 0x42),SCE(0x2cd2, 0, 0x82), SCE(0x2cd3, 1, 0x42),SCE(0x04ee, 0, 0x82),SCE(0x04ef, 1, 0x42),SCE(0x04f0, 0, 0x82), SCE(0x04f1, 1, 0x42),SCE(0x10422, 0, 0x82),SCE(0x1044a, 1, 0x42),SCE(0x04f2, 0, 0x82), SCE(0x04f3, 1, 0x42),SCE(0x04f4, 0, 0x82),SCE(0x04f5, 1, 0x42),SCE(0x04f6, 0, 0x82), SCE(0x04f7, 1, 0x42),SCE(0x04f8, 0, 0x82),SCE(0x04f9, 1, 0x42),SCE(0x2cd4, 0, 0x82), SCE(0x2cd5, 1, 0x42),SCE(0x04fa, 0, 0x82),SCE(0x04fb, 1, 0x42),SCE(0x04fc, 0, 0x82), SCE(0x04fd, 1, 0x42),SCE(0x04fe, 0, 0x82),SCE(0x04ff, 1, 0x42),SCE(0x0500, 0, 0x82), SCE(0x0501, 1, 0x42),SCE(0x0502, 0, 0x82),SCE(0x0503, 1, 0x42),SCE(0x0504, 0, 0x82), SCE(0x0505, 1, 0x42),SCE(0x2cd6, 0, 0x82),SCE(0x2cd7, 1, 0x42),SCE(0x0506, 0, 0x82), SCE(0x0507, 1, 0x42),SCE(0x0508, 0, 0x82),SCE(0x0509, 1, 0x42),SCE(0x050a, 0, 0x82), SCE(0x050b, 1, 0x42),SCE(0x050c, 0, 0x82),SCE(0x050d, 1, 0x42),SCE(0x050e, 0, 0x82), SCE(0x050f, 1, 0x42),SCE(0x0510, 0, 0x82),SCE(0x0511, 1, 0x42),SCE(0x2cd8, 0, 0x82), SCE(0x2cd9, 1, 0x42),SCE(0x0512, 0, 0x82),SCE(0x0513, 1, 0x42),SCE(0x0514, 0, 0x82), SCE(0x0515, 1, 0x42),SCE(0x0516, 0, 0x82),SCE(0x0517, 1, 0x42),SCE(0x0518, 0, 0x82), SCE(0x0519, 1, 0x42),SCE(0x051a, 0, 0x82),SCE(0x051b, 1, 0x42),SCE(0x2ca8, 0, 0x82), SCE(0x2ca9, 1, 0x42),SCE(0x051c, 0, 0x82),SCE(0x051d, 1, 0x42),SCE(0x2cda, 0, 0x82), SCE(0x2cdb, 1, 0x42),SCE(0x051e, 0, 0x82),SCE(0x051f, 1, 0x42),SCE(0x0520, 0, 0x82), SCE(0x0521, 1, 0x42),SCE(0x0522, 0, 0x82),SCE(0x0523, 1, 0x42),SCE(0x0524, 0, 0x82), SCE(0x0525, 1, 0x42),SCE(0x0526, 0, 0x82),SCE(0x0527, 1, 0x42),SCE(0x2c20, 0, 0x82), SCE(0x2c50, 1, 0x42),SCE(0x2cdc, 0, 0x82),SCE(0x2cdd, 1, 0x42),SCE(0x0531, 0, 0x82), SCE(0x0561, 1, 0x42),SCE(0x0532, 0, 0x82),SCE(0x0562, 1, 0x42),SCE(0x0533, 0, 0x82), SCE(0x0563, 1, 0x42),SCE(0x0534, 0, 0x82),SCE(0x0564, 1, 0x42),SCE(0x0535, 0, 0x82), SCE(0x0565, 1, 0x42),SCE(0x0536, 0, 0x82),SCE(0x0566, 1, 0x42),SCE(0x0537, 0, 0x82), SCE(0x0567, 1, 0x42),SCE(0x0538, 0, 0x82),SCE(0x0568, 1, 0x42),SCE(0x0539, 0, 0x82), SCE(0x0569, 1, 0x42),SCE(0x053a, 0, 0x82),SCE(0x056a, 1, 0x42),SCE(0x053b, 0, 0x82), SCE(0x056b, 1, 0x42),SCE(0x053c, 0, 0x82),SCE(0x056c, 1, 0x42),SCE(0x053d, 0, 0x82), SCE(0x056d, 1, 0x42),SCE(0x053e, 0, 0x82),SCE(0x056e, 1, 0x42),SCE(0x053f, 0, 0x82), SCE(0x056f, 1, 0x42),SCE(0x0540, 0, 0x82),SCE(0x0570, 1, 0x42),SCE(0x0541, 0, 0x82), SCE(0x0571, 1, 0x42),SCE(0x0542, 0, 0x82),SCE(0x0572, 1, 0x42),SCE(0x0543, 0, 0x82), SCE(0x0573, 1, 0x42),SCE(0x0544, 0, 0x82),SCE(0x0574, 1, 0x42),SCE(0x0545, 0, 0x82), SCE(0x0575, 1, 0x42),SCE(0x0546, 0, 0x82),SCE(0x0576, 1, 0x42),SCE(0x0547, 0, 0x82), SCE(0x0577, 1, 0x42),SCE(0x0548, 0, 0x82),SCE(0x0578, 1, 0x42),SCE(0x0549, 0, 0x82), SCE(0x0579, 1, 0x42),SCE(0x054a, 0, 0x82),SCE(0x057a, 1, 0x42),SCE(0x054b, 0, 0x82), SCE(0x057b, 1, 0x42),SCE(0x054c, 0, 0x82),SCE(0x057c, 1, 0x42),SCE(0x054d, 0, 0x82), SCE(0x057d, 1, 0x42),SCE(0x054e, 0, 0x82),SCE(0x057e, 1, 0x42),SCE(0x054f, 0, 0x82), SCE(0x057f, 1, 0x42),SCE(0x0550, 0, 0x82),SCE(0x0580, 1, 0x42),SCE(0x0551, 0, 0x82), SCE(0x0581, 1, 0x42),SCE(0x0552, 0, 0x82),SCE(0x0582, 1, 0x42),SCE(0x0553, 0, 0x82), SCE(0x0583, 1, 0x42),SCE(0x0554, 0, 0x82),SCE(0x0584, 1, 0x42),SCE(0x0555, 0, 0x82), SCE(0x0585, 1, 0x42),SCE(0x0556, 0, 0x82),SCE(0x0586, 1, 0x42),SCE(0x2caa, 0, 0x82), SCE(0x2cab, 1, 0x42),SCE(0x2c22, 0, 0x82),SCE(0x2c52, 1, 0x42),SCE(0x2c23, 0, 0x82), SCE(0x2c53, 1, 0x42),SCE(0x2ceb, 0, 0x82),SCE(0x2cec, 1, 0x42),SCE(0x2cca, 0, 0x82), SCE(0x2ccb, 1, 0x42),SCE(0xa642, 0, 0x82),SCE(0xa643, 1, 0x42),SCE(0x2ced, 0, 0x82), SCE(0x2cee, 1, 0x42),SCE(0x2cac, 0, 0x82),SCE(0x2cad, 1, 0x42),SCE(0xa644, 0, 0x82), SCE(0xa645, 1, 0x42),SCE(0x2c24, 0, 0x82),SCE(0x2c54, 1, 0x42),SCE(0xa646, 0, 0x82), SCE(0xa647, 1, 0x42),SCE(0x2cf2, 0, 0x82),SCE(0x2cf3, 1, 0x42),SCE(0x10408, 0, 0x82), SCE(0x10430, 1, 0x42),SCE(0xa648, 0, 0x82),SCE(0xa649, 1, 0x42),SCE(0xa64a, 0, 0x82), SCE(0xa64b, 1, 0x42),SCE(0xa64c, 0, 0x82),SCE(0xa64d, 1, 0x42),SCE(0x2cae, 0, 0x82), SCE(0x2caf, 1, 0x42),SCE(0xa64e, 0, 0x82),SCE(0xa64f, 1, 0x42),SCE(0xa650, 0, 0x82), SCE(0xa651, 1, 0x42),SCE(0xa78b, 0, 0x82),SCE(0xa78c, 1, 0x42),SCE(0xa652, 0, 0x82), SCE(0xa653, 1, 0x42),SCE(0xa7a8, 0, 0x82),SCE(0xa7a9, 1, 0x42),SCE(0xa654, 0, 0x82), SCE(0xa655, 1, 0x42),SCE(0x0266, 0, 0x42),SCE(0xa7aa, 1, 0x82),SCE(0x1e00, 0, 0x82), SCE(0x1e01, 1, 0x42),SCE(0x1e02, 0, 0x82),SCE(0x1e03, 1, 0x42),SCE(0x1e04, 0, 0x82), SCE(0x1e05, 1, 0x42),SCE(0x2c1f, 0, 0x82),SCE(0x2c4f, 1, 0x42),SCE(0x1e06, 0, 0x82), SCE(0x1e07, 1, 0x42),SCE(0x1040e, 0, 0x82),SCE(0x10436, 1, 0x42),SCE(0x1e08, 0, 0x82), SCE(0x1e09, 1, 0x42),SCE(0x1e0a, 0, 0x82),SCE(0x1e0b, 1, 0x42),SCE(0x2cb0, 0, 0x82), SCE(0x2cb1, 1, 0x42),SCE(0x1e0c, 0, 0x82),SCE(0x1e0d, 1, 0x42),SCE(0x1e0e, 0, 0x82), SCE(0x1e0f, 1, 0x42),SCE(0x1e10, 0, 0x82),SCE(0x1e11, 1, 0x42),SCE(0xa658, 0, 0x82), SCE(0xa659, 1, 0x42),SCE(0x1e12, 0, 0x82),SCE(0x1e13, 1, 0x42),SCE(0x1e14, 0, 0x82), SCE(0x1e15, 1, 0x42),SCE(0x24cd, 0, 0x82),SCE(0x24e7, 1, 0x42),SCE(0x1e16, 0, 0x82), SCE(0x1e17, 1, 0x42),SCE(0x1e18, 0, 0x82),SCE(0x1e19, 1, 0x42),SCE(0x1e1a, 0, 0x82), SCE(0x1e1b, 1, 0x42),SCE(0x1e1c, 0, 0x82),SCE(0x1e1d, 1, 0x42),SCE(0xa65a, 0, 0x82), SCE(0xa65b, 1, 0x42),SCE(0x1e1e, 0, 0x82),SCE(0x1e1f, 1, 0x42),SCE(0x1e20, 0, 0x82), SCE(0x1e21, 1, 0x42),SCE(0x1e22, 0, 0x82),SCE(0x1e23, 1, 0x42),SCE(0x1e24, 0, 0x82), SCE(0x1e25, 1, 0x42),SCE(0x1e26, 0, 0x82),SCE(0x1e27, 1, 0x42),SCE(0x1e28, 0, 0x82), SCE(0x1e29, 1, 0x42),SCE(0xa65c, 0, 0x82),SCE(0xa65d, 1, 0x42),SCE(0x1e2a, 0, 0x82), SCE(0x1e2b, 1, 0x42),SCE(0x1e2c, 0, 0x82),SCE(0x1e2d, 1, 0x42),SCE(0x1e2e, 0, 0x82), SCE(0x1e2f, 1, 0x42),SCE(0x1e30, 0, 0x82),SCE(0x1e31, 1, 0x42),SCE(0x1e32, 0, 0x82), SCE(0x1e33, 1, 0x42),SCE(0x1e34, 0, 0x82),SCE(0x1e35, 1, 0x42),SCE(0xa65e, 0, 0x82), SCE(0xa65f, 1, 0x42),SCE(0x1e36, 0, 0x82),SCE(0x1e37, 1, 0x42),SCE(0x1e38, 0, 0x82), SCE(0x1e39, 1, 0x42),SCE(0x1e3a, 0, 0x82),SCE(0x1e3b, 1, 0x42),SCE(0x1e3c, 0, 0x82), SCE(0x1e3d, 1, 0x42),SCE(0x1e3e, 0, 0x82),SCE(0x1e3f, 1, 0x42),SCE(0x1e40, 0, 0x82), SCE(0x1e41, 1, 0x42),SCE(0xa660, 0, 0x82),SCE(0xa661, 1, 0x42),SCE(0x1e42, 0, 0x82), SCE(0x1e43, 1, 0x42),SCE(0x1e44, 0, 0x82),SCE(0x1e45, 1, 0x42),SCE(0x1e46, 0, 0x82), SCE(0x1e47, 1, 0x42),SCE(0x2cb2, 0, 0x82),SCE(0x2cb3, 1, 0x42),SCE(0x1e48, 0, 0x82), SCE(0x1e49, 1, 0x42),SCE(0x2cc0, 0, 0x82),SCE(0x2cc1, 1, 0x42),SCE(0x1e4a, 0, 0x82), SCE(0x1e4b, 1, 0x42),SCE(0x1e4c, 0, 0x82),SCE(0x1e4d, 1, 0x42),SCE(0xa662, 0, 0x82), SCE(0xa663, 1, 0x42),SCE(0x1e4e, 0, 0x82),SCE(0x1e4f, 1, 0x42),SCE(0x1e50, 0, 0x82), SCE(0x1e51, 1, 0x42),SCE(0x1e52, 0, 0x82),SCE(0x1e53, 1, 0x42),SCE(0x1e54, 0, 0x82), SCE(0x1e55, 1, 0x42),SCE(0x1e56, 0, 0x82),SCE(0x1e57, 1, 0x42),SCE(0x1e58, 0, 0x82), SCE(0x1e59, 1, 0x42),SCE(0xa664, 0, 0x82),SCE(0xa665, 1, 0x42),SCE(0x1e5a, 0, 0x82), SCE(0x1e5b, 1, 0x42),SCE(0x1e5c, 0, 0x82),SCE(0x1e5d, 1, 0x42),SCE(0x1e5e, 0, 0x82), SCE(0x1e5f, 1, 0x42),SCE(0x1e60, 0, 0x83),SCE(0x1e61, 1, 0x43),SCE(0x1e9b, 2, 0x43), SCE(0x1e62, 0, 0x82),SCE(0x1e63, 1, 0x42),SCE(0x1e64, 0, 0x82),SCE(0x1e65, 1, 0x42), SCE(0xa666, 0, 0x82),SCE(0xa667, 1, 0x42),SCE(0x1e66, 0, 0x82),SCE(0x1e67, 1, 0x42), SCE(0x1e68, 0, 0x82),SCE(0x1e69, 1, 0x42),SCE(0x1e6a, 0, 0x82),SCE(0x1e6b, 1, 0x42), SCE(0x1e6c, 0, 0x82),SCE(0x1e6d, 1, 0x42),SCE(0x1e6e, 0, 0x82),SCE(0x1e6f, 1, 0x42), SCE(0x1e70, 0, 0x82),SCE(0x1e71, 1, 0x42),SCE(0xa668, 0, 0x82),SCE(0xa669, 1, 0x42), SCE(0x1e72, 0, 0x82),SCE(0x1e73, 1, 0x42),SCE(0x1e74, 0, 0x82),SCE(0x1e75, 1, 0x42), SCE(0x1e76, 0, 0x82),SCE(0x1e77, 1, 0x42),SCE(0x2cbe, 0, 0x82),SCE(0x2cbf, 1, 0x42), SCE(0x1e78, 0, 0x82),SCE(0x1e79, 1, 0x42),SCE(0x1e7a, 0, 0x82),SCE(0x1e7b, 1, 0x42), SCE(0x1e7c, 0, 0x82),SCE(0x1e7d, 1, 0x42),SCE(0xa66a, 0, 0x82),SCE(0xa66b, 1, 0x42), SCE(0x1e7e, 0, 0x82),SCE(0x1e7f, 1, 0x42),SCE(0x1e80, 0, 0x82),SCE(0x1e81, 1, 0x42), SCE(0x1e82, 0, 0x82),SCE(0x1e83, 1, 0x42),SCE(0x1e84, 0, 0x82),SCE(0x1e85, 1, 0x42), SCE(0x1e86, 0, 0x82),SCE(0x1e87, 1, 0x42),SCE(0x1e88, 0, 0x82),SCE(0x1e89, 1, 0x42), SCE(0xa66c, 0, 0x82),SCE(0xa66d, 1, 0x42),SCE(0x1e8a, 0, 0x82),SCE(0x1e8b, 1, 0x42), SCE(0x1e8c, 0, 0x82),SCE(0x1e8d, 1, 0x42),SCE(0x1e8e, 0, 0x82),SCE(0x1e8f, 1, 0x42), SCE(0x1e90, 0, 0x82),SCE(0x1e91, 1, 0x42),SCE(0x1e92, 0, 0x82),SCE(0x1e93, 1, 0x42), SCE(0x1e94, 0, 0x82),SCE(0x1e95, 1, 0x42),SCE(0xa696, 0, 0x82),SCE(0xa697, 1, 0x42), SCE(0x10406, 0, 0x82),SCE(0x1042e, 1, 0x42),SCE(0x1e60, 0, 0x83),SCE(0x1e61, 1, 0x43), SCE(0x1e9b, 2, 0x43),SCE(0x00df, 0, 0x42),SCE(0x1e9e, 1, 0x82),SCE(0x1ea0, 0, 0x82), SCE(0x1ea1, 1, 0x42),SCE(0x1ea2, 0, 0x82),SCE(0x1ea3, 1, 0x42),SCE(0x1ea4, 0, 0x82), SCE(0x1ea5, 1, 0x42),SCE(0x24c5, 0, 0x82),SCE(0x24df, 1, 0x42),SCE(0x1ea6, 0, 0x82), SCE(0x1ea7, 1, 0x42),SCE(0x1ea8, 0, 0x82),SCE(0x1ea9, 1, 0x42),SCE(0x1eaa, 0, 0x82), SCE(0x1eab, 1, 0x42),SCE(0x1eac, 0, 0x82),SCE(0x1ead, 1, 0x42),SCE(0x1eae, 0, 0x82), SCE(0x1eaf, 1, 0x42),SCE(0xff28, 0, 0x82),SCE(0xff48, 1, 0x42),SCE(0x1eb0, 0, 0x82), SCE(0x1eb1, 1, 0x42),SCE(0x1eb2, 0, 0x82),SCE(0x1eb3, 1, 0x42),SCE(0x10425, 0, 0x82), SCE(0x1044d, 1, 0x42),SCE(0x1eb4, 0, 0x82),SCE(0x1eb5, 1, 0x42),SCE(0x1eb6, 0, 0x82), SCE(0x1eb7, 1, 0x42),SCE(0x1eb8, 0, 0x82),SCE(0x1eb9, 1, 0x42),SCE(0x1eba, 0, 0x82), SCE(0x1ebb, 1, 0x42),SCE(0x1ebc, 0, 0x82),SCE(0x1ebd, 1, 0x42),SCE(0x1ebe, 0, 0x82), SCE(0x1ebf, 1, 0x42),SCE(0x2cb6, 0, 0x82),SCE(0x2cb7, 1, 0x42),SCE(0x1ec0, 0, 0x82), SCE(0x1ec1, 1, 0x42),SCE(0x1ec2, 0, 0x82),SCE(0x1ec3, 1, 0x42),SCE(0x2c9a, 0, 0x82), SCE(0x2c9b, 1, 0x42),SCE(0x1ec4, 0, 0x82),SCE(0x1ec5, 1, 0x42),SCE(0x1ec6, 0, 0x82), SCE(0x1ec7, 1, 0x42),SCE(0x1ec8, 0, 0x82),SCE(0x1ec9, 1, 0x42),SCE(0x1eca, 0, 0x82), SCE(0x1ecb, 1, 0x42),SCE(0x1ecc, 0, 0x82),SCE(0x1ecd, 1, 0x42),SCE(0x1ece, 0, 0x82), SCE(0x1ecf, 1, 0x42),SCE(0x1ed0, 0, 0x82),SCE(0x1ed1, 1, 0x42),SCE(0x1ed2, 0, 0x82), SCE(0x1ed3, 1, 0x42),SCE(0x1ed4, 0, 0x82),SCE(0x1ed5, 1, 0x42),SCE(0x1ed6, 0, 0x82), SCE(0x1ed7, 1, 0x42),SCE(0x1ed8, 0, 0x82),SCE(0x1ed9, 1, 0x42),SCE(0x1eda, 0, 0x82), SCE(0x1edb, 1, 0x42),SCE(0x1edc, 0, 0x82),SCE(0x1edd, 1, 0x42),SCE(0x1ede, 0, 0x82), SCE(0x1edf, 1, 0x42),SCE(0x1ee0, 0, 0x82),SCE(0x1ee1, 1, 0x42),SCE(0x1ee2, 0, 0x82), SCE(0x1ee3, 1, 0x42),SCE(0x1ee4, 0, 0x82),SCE(0x1ee5, 1, 0x42),SCE(0x03a9, 0, 0x83), SCE(0x03c9, 1, 0x43),SCE(0x2126, 2, 0x83),SCE(0x1ee6, 0, 0x82),SCE(0x1ee7, 1, 0x42), SCE(0x1ee8, 0, 0x82),SCE(0x1ee9, 1, 0x42),SCE(0x1eea, 0, 0x82),SCE(0x1eeb, 1, 0x42), SCE(0xff2a, 0, 0x82),SCE(0xff4a, 1, 0x42),SCE(0x1eec, 0, 0x82),SCE(0x1eed, 1, 0x42), SCE(0x1eee, 0, 0x82),SCE(0x1eef, 1, 0x42),SCE(0x1ef0, 0, 0x82),SCE(0x1ef1, 1, 0x42), SCE(0x1ef2, 0, 0x82),SCE(0x1ef3, 1, 0x42),SCE(0x1ef4, 0, 0x82),SCE(0x1ef5, 1, 0x42), SCE(0x1ef6, 0, 0x82),SCE(0x1ef7, 1, 0x42),SCE(0x1ef8, 0, 0x82),SCE(0x1ef9, 1, 0x42), SCE(0x1efa, 0, 0x82),SCE(0x1efb, 1, 0x42),SCE(0x2cb8, 0, 0x82),SCE(0x2cb9, 1, 0x42), SCE(0x1efc, 0, 0x82),SCE(0x1efd, 1, 0x42),SCE(0x004b, 0, 0x83),SCE(0x006b, 1, 0x43), SCE(0x212a, 2, 0x83),SCE(0x1efe, 0, 0x82),SCE(0x1eff, 1, 0x42),SCE(0xa680, 0, 0x82), SCE(0xa681, 1, 0x42),SCE(0x1f00, 0, 0x42),SCE(0x1f08, 1, 0x82),SCE(0x1f01, 0, 0x42), SCE(0x1f09, 1, 0x82),SCE(0x1f02, 0, 0x42),SCE(0x1f0a, 1, 0x82),SCE(0x1f03, 0, 0x42), SCE(0x1f0b, 1, 0x82),SCE(0x1f04, 0, 0x42),SCE(0x1f0c, 1, 0x82),SCE(0x1f05, 0, 0x42), SCE(0x1f0d, 1, 0x82),SCE(0x1f06, 0, 0x42),SCE(0x1f0e, 1, 0x82),SCE(0x1f07, 0, 0x42), SCE(0x1f0f, 1, 0x82),SCE(0x10418, 0, 0x82),SCE(0x10440, 1, 0x42),SCE(0x0265, 0, 0x42), SCE(0xa78d, 1, 0x82),SCE(0x1f10, 0, 0x42),SCE(0x1f18, 1, 0x82),SCE(0x1f11, 0, 0x42), SCE(0x1f19, 1, 0x82),SCE(0x1f12, 0, 0x42),SCE(0x1f1a, 1, 0x82),SCE(0x1f13, 0, 0x42), SCE(0x1f1b, 1, 0x82),SCE(0x1f14, 0, 0x42),SCE(0x1f1c, 1, 0x82),SCE(0x1f15, 0, 0x42), SCE(0x1f1d, 1, 0x82),SCE(0xff21, 0, 0x82),SCE(0xff41, 1, 0x42),SCE(0xa722, 0, 0x82), SCE(0xa723, 1, 0x42),SCE(0xff23, 0, 0x82),SCE(0xff43, 1, 0x42),SCE(0xa724, 0, 0x82), SCE(0xa725, 1, 0x42),SCE(0xa686, 0, 0x82),SCE(0xa687, 1, 0x42),SCE(0xa726, 0, 0x82), SCE(0xa727, 1, 0x42),SCE(0xff27, 0, 0x82),SCE(0xff47, 1, 0x42),SCE(0x1f20, 0, 0x42), SCE(0x1f28, 1, 0x82),SCE(0x1f21, 0, 0x42),SCE(0x1f29, 1, 0x82),SCE(0x1f22, 0, 0x42), SCE(0x1f2a, 1, 0x82),SCE(0x1f23, 0, 0x42),SCE(0x1f2b, 1, 0x82),SCE(0x1f24, 0, 0x42), SCE(0x1f2c, 1, 0x82),SCE(0x1f25, 0, 0x42),SCE(0x1f2d, 1, 0x82),SCE(0x1f26, 0, 0x42), SCE(0x1f2e, 1, 0x82),SCE(0x1f27, 0, 0x42),SCE(0x1f2f, 1, 0x82),SCE(0xff30, 0, 0x82), SCE(0xff50, 1, 0x42),SCE(0xa688, 0, 0x82),SCE(0xa689, 1, 0x42),SCE(0xa732, 0, 0x82), SCE(0xa733, 1, 0x42),SCE(0xff33, 0, 0x82),SCE(0xff53, 1, 0x42),SCE(0xa734, 0, 0x82), SCE(0xa735, 1, 0x42),SCE(0xff35, 0, 0x82),SCE(0xff55, 1, 0x42),SCE(0xa736, 0, 0x82), SCE(0xa737, 1, 0x42),SCE(0x2cba, 0, 0x82),SCE(0x2cbb, 1, 0x42),SCE(0x1f30, 0, 0x42), SCE(0x1f38, 1, 0x82),SCE(0x1f31, 0, 0x42),SCE(0x1f39, 1, 0x82),SCE(0x1f32, 0, 0x42), SCE(0x1f3a, 1, 0x82),SCE(0x1f33, 0, 0x42),SCE(0x1f3b, 1, 0x82),SCE(0x1f34, 0, 0x42), SCE(0x1f3c, 1, 0x82),SCE(0x1f35, 0, 0x42),SCE(0x1f3d, 1, 0x82),SCE(0x1f36, 0, 0x42), SCE(0x1f3e, 1, 0x82),SCE(0x1f37, 0, 0x42),SCE(0x1f3f, 1, 0x82),SCE(0xa740, 0, 0x82), SCE(0xa741, 1, 0x42),SCE(0xa742, 0, 0x82),SCE(0xa743, 1, 0x42),SCE(0xa744, 0, 0x82), SCE(0xa745, 1, 0x42),SCE(0xa746, 0, 0x82),SCE(0xa747, 1, 0x42),SCE(0x1f40, 0, 0x42), SCE(0x1f48, 1, 0x82),SCE(0x1f41, 0, 0x42),SCE(0x1f49, 1, 0x82),SCE(0x1f42, 0, 0x42), SCE(0x1f4a, 1, 0x82),SCE(0x1f43, 0, 0x42),SCE(0x1f4b, 1, 0x82),SCE(0x1f44, 0, 0x42), SCE(0x1f4c, 1, 0x82),SCE(0x1f45, 0, 0x42),SCE(0x1f4d, 1, 0x82),SCE(0xa74e, 0, 0x82), SCE(0xa74f, 1, 0x42),SCE(0xa750, 0, 0x82),SCE(0xa751, 1, 0x42),SCE(0xa752, 0, 0x82), SCE(0xa753, 1, 0x42),SCE(0xa754, 0, 0x82),SCE(0xa755, 1, 0x42),SCE(0xa68e, 0, 0x82), SCE(0xa68f, 1, 0x42),SCE(0xa756, 0, 0x82),SCE(0xa757, 1, 0x42),SCE(0xa758, 0, 0x82), SCE(0xa759, 1, 0x42),SCE(0x1f51, 0, 0x42),SCE(0x1f59, 1, 0x82),SCE(0xa75a, 0, 0x82), SCE(0xa75b, 1, 0x42),SCE(0x1f53, 0, 0x42),SCE(0x1f5b, 1, 0x82),SCE(0xa75c, 0, 0x82), SCE(0xa75d, 1, 0x42),SCE(0x1f55, 0, 0x42),SCE(0x1f5d, 1, 0x82),SCE(0xa75e, 0, 0x82), SCE(0xa75f, 1, 0x42),SCE(0x1f57, 0, 0x42),SCE(0x1f5f, 1, 0x82),SCE(0xa760, 0, 0x82), SCE(0xa761, 1, 0x42),SCE(0xa690, 0, 0x82),SCE(0xa691, 1, 0x42),SCE(0xa762, 0, 0x82), SCE(0xa763, 1, 0x42),SCE(0xff2e, 0, 0x82),SCE(0xff4e, 1, 0x42),SCE(0xa764, 0, 0x82), SCE(0xa765, 1, 0x42),SCE(0xa766, 0, 0x82),SCE(0xa767, 1, 0x42),SCE(0x1f60, 0, 0x42), SCE(0x1f68, 1, 0x82),SCE(0x1f61, 0, 0x42),SCE(0x1f69, 1, 0x82),SCE(0x1f62, 0, 0x42), SCE(0x1f6a, 1, 0x82),SCE(0x1f63, 0, 0x42),SCE(0x1f6b, 1, 0x82),SCE(0x1f64, 0, 0x42), SCE(0x1f6c, 1, 0x82),SCE(0x1f65, 0, 0x42),SCE(0x1f6d, 1, 0x82),SCE(0x1f66, 0, 0x42), SCE(0x1f6e, 1, 0x82),SCE(0x1f67, 0, 0x42),SCE(0x1f6f, 1, 0x82),SCE(0x2c1c, 0, 0x82), SCE(0x2c4c, 1, 0x42),SCE(0x2cbc, 0, 0x82),SCE(0x2cbd, 1, 0x42),SCE(0xa694, 0, 0x82), SCE(0xa695, 1, 0x42),SCE(0xa77b, 0, 0x82),SCE(0xa77c, 1, 0x42),SCE(0x1d79, 0, 0x42), SCE(0xa77d, 1, 0x82),SCE(0xa77e, 0, 0x82),SCE(0xa77f, 1, 0x42),SCE(0xa780, 0, 0x82), SCE(0xa781, 1, 0x42),SCE(0xa782, 0, 0x82),SCE(0xa783, 1, 0x42),SCE(0xa784, 0, 0x82), SCE(0xa785, 1, 0x42),SCE(0xa786, 0, 0x82),SCE(0xa787, 1, 0x42),SCE(0x1f80, 0, 0x42), SCE(0x1f88, 1, 0x2),SCE(0x1f81, 0, 0x42),SCE(0x1f89, 1, 0x2),SCE(0x1f82, 0, 0x42), SCE(0x1f8a, 1, 0x2),SCE(0x1f83, 0, 0x42),SCE(0x1f8b, 1, 0x2),SCE(0x1f84, 0, 0x42), SCE(0x1f8c, 1, 0x2),SCE(0x1f85, 0, 0x42),SCE(0x1f8d, 1, 0x2),SCE(0x1f86, 0, 0x42), SCE(0x1f8e, 1, 0x2),SCE(0x1f87, 0, 0x42),SCE(0x1f8f, 1, 0x2),SCE(0xa790, 0, 0x82), SCE(0xa791, 1, 0x42),SCE(0xa792, 0, 0x82),SCE(0xa793, 1, 0x42),SCE(0x1f90, 0, 0x42), SCE(0x1f98, 1, 0x2),SCE(0x1f91, 0, 0x42),SCE(0x1f99, 1, 0x2),SCE(0x1f92, 0, 0x42), SCE(0x1f9a, 1, 0x2),SCE(0x1f93, 0, 0x42),SCE(0x1f9b, 1, 0x2),SCE(0x1f94, 0, 0x42), SCE(0x1f9c, 1, 0x2),SCE(0x1f95, 0, 0x42),SCE(0x1f9d, 1, 0x2),SCE(0x1f96, 0, 0x42), SCE(0x1f9e, 1, 0x2),SCE(0x1f97, 0, 0x42),SCE(0x1f9f, 1, 0x2),SCE(0xa7a0, 0, 0x82), SCE(0xa7a1, 1, 0x42),SCE(0xa7a2, 0, 0x82),SCE(0xa7a3, 1, 0x42),SCE(0xa7a4, 0, 0x82), SCE(0xa7a5, 1, 0x42),SCE(0xa7a6, 0, 0x82),SCE(0xa7a7, 1, 0x42),SCE(0x1fa0, 0, 0x42), SCE(0x1fa8, 1, 0x2),SCE(0x1fa1, 0, 0x42),SCE(0x1fa9, 1, 0x2),SCE(0x1fa2, 0, 0x42), SCE(0x1faa, 1, 0x2),SCE(0x1fa3, 0, 0x42),SCE(0x1fab, 1, 0x2),SCE(0x1fa4, 0, 0x42), SCE(0x1fac, 1, 0x2),SCE(0x1fa5, 0, 0x42),SCE(0x1fad, 1, 0x2),SCE(0x1fa6, 0, 0x42), SCE(0x1fae, 1, 0x2),SCE(0x1fa7, 0, 0x42),SCE(0x1faf, 1, 0x2),SCE(0x1fb0, 0, 0x42), SCE(0x1fb8, 1, 0x82),SCE(0x1fb1, 0, 0x42),SCE(0x1fb9, 1, 0x82),SCE(0x1f70, 0, 0x42), SCE(0x1fba, 1, 0x82),SCE(0x1f71, 0, 0x42),SCE(0x1fbb, 1, 0x82),SCE(0x1fb3, 0, 0x42), SCE(0x1fbc, 1, 0x2),SCE(0x0345, 0, 0x44),SCE(0x0399, 1, 0x84),SCE(0x03b9, 2, 0x44), SCE(0x1fbe, 3, 0x44),SCE(0x1f72, 0, 0x42),SCE(0x1fc8, 1, 0x82),SCE(0x1f73, 0, 0x42), SCE(0x1fc9, 1, 0x82),SCE(0x1f74, 0, 0x42),SCE(0x1fca, 1, 0x82),SCE(0x1f75, 0, 0x42), SCE(0x1fcb, 1, 0x82),SCE(0x1fc3, 0, 0x42),SCE(0x1fcc, 1, 0x2),SCE(0x1fd0, 0, 0x42), SCE(0x1fd8, 1, 0x82),SCE(0x1fd1, 0, 0x42),SCE(0x1fd9, 1, 0x82),SCE(0x1f76, 0, 0x42), SCE(0x1fda, 1, 0x82),SCE(0x1f77, 0, 0x42),SCE(0x1fdb, 1, 0x82),SCE(0x10427, 0, 0x82), SCE(0x1044f, 1, 0x42),SCE(0x1fe0, 0, 0x42),SCE(0x1fe8, 1, 0x82),SCE(0x1fe1, 0, 0x42), SCE(0x1fe9, 1, 0x82),SCE(0x1f7a, 0, 0x42),SCE(0x1fea, 1, 0x82),SCE(0x1f7b, 0, 0x42), SCE(0x1feb, 1, 0x82),SCE(0x1fe5, 0, 0x42),SCE(0x1fec, 1, 0x82),SCE(0x10401, 0, 0x82), SCE(0x10429, 1, 0x42),SCE(0x1040c, 0, 0x82),SCE(0x10434, 1, 0x42),SCE(0x1f78, 0, 0x42), SCE(0x1ff8, 1, 0x82),SCE(0x1f79, 0, 0x42),SCE(0x1ff9, 1, 0x82),SCE(0x1f7c, 0, 0x42), SCE(0x1ffa, 1, 0x82),SCE(0x1f7d, 0, 0x42),SCE(0x1ffb, 1, 0x82),SCE(0x1ff3, 0, 0x42), SCE(0x1ffc, 1, 0x2),SCE(0x24c0, 0, 0x82),SCE(0x24da, 1, 0x42),]; return t; } @property immutable(FullCaseEntry[]) fullCaseTable() { alias FCE = FullCaseEntry; static immutable FCE[] t = [ FCE("Ⰰ", 0, 2, 1), FCE("ⰰ", 1, 2, 1),FCE("Ⓝ", 0, 2, 1),FCE("ⓝ", 1, 2, 1),FCE("Ⰱ", 0, 2, 1), FCE("ⰱ", 1, 2, 1),FCE("Ⱍ", 0, 2, 1),FCE("ⱍ", 1, 2, 1),FCE("Ⰲ", 0, 2, 1), FCE("ⰲ", 1, 2, 1),FCE("Ⰳ", 0, 2, 1),FCE("ⰳ", 1, 2, 1),FCE("Ⰴ", 0, 2, 1), FCE("ⰴ", 1, 2, 1),FCE("Ⰵ", 0, 2, 1),FCE("ⰵ", 1, 2, 1),FCE("Ⰶ", 0, 2, 1), FCE("ⰶ", 1, 2, 1),FCE("𐐀", 0, 2, 1),FCE("𐐨", 1, 2, 1),FCE("Ⳃ", 0, 2, 1), FCE("ⳃ", 1, 2, 1),FCE("Ⰷ", 0, 2, 1),FCE("ⰷ", 1, 2, 1),FCE("Ⰸ", 0, 2, 1), FCE("ⰸ", 1, 2, 1),FCE("Ⰹ", 0, 2, 1),FCE("ⰹ", 1, 2, 1),FCE("Ⰺ", 0, 2, 1), FCE("ⰺ", 1, 2, 1),FCE("Ꚍ", 0, 2, 1),FCE("ꚍ", 1, 2, 1),FCE("A", 0, 2, 1), FCE("a", 1, 2, 1),FCE("B", 0, 2, 1),FCE("b", 1, 2, 1),FCE("C", 0, 2, 1), FCE("c", 1, 2, 1),FCE("D", 0, 2, 1),FCE("d", 1, 2, 1),FCE("E", 0, 2, 1), FCE("e", 1, 2, 1),FCE("F", 0, 2, 1),FCE("f", 1, 2, 1),FCE("G", 0, 2, 1), FCE("g", 1, 2, 1),FCE("H", 0, 2, 1),FCE("h", 1, 2, 1),FCE("I", 0, 2, 1), FCE("i", 1, 2, 1),FCE("J", 0, 2, 1),FCE("j", 1, 2, 1),FCE("K", 0, 3, 1), FCE("k", 1, 3, 1),FCE("K", 2, 3, 1),FCE("L", 0, 2, 1),FCE("l", 1, 2, 1), FCE("M", 0, 2, 1),FCE("m", 1, 2, 1),FCE("N", 0, 2, 1),FCE("n", 1, 2, 1), FCE("O", 0, 2, 1),FCE("o", 1, 2, 1),FCE("P", 0, 2, 1),FCE("p", 1, 2, 1), FCE("Q", 0, 2, 1),FCE("q", 1, 2, 1),FCE("R", 0, 2, 1),FCE("r", 1, 2, 1), FCE("S", 0, 3, 1),FCE("s", 1, 3, 1),FCE("ſ", 2, 3, 1),FCE("T", 0, 2, 1), FCE("t", 1, 2, 1),FCE("U", 0, 2, 1),FCE("u", 1, 2, 1),FCE("V", 0, 2, 1), FCE("v", 1, 2, 1),FCE("W", 0, 2, 1),FCE("w", 1, 2, 1),FCE("X", 0, 2, 1), FCE("x", 1, 2, 1),FCE("Y", 0, 2, 1),FCE("y", 1, 2, 1),FCE("Z", 0, 2, 1), FCE("z", 1, 2, 1),FCE("Ⰿ", 0, 2, 1),FCE("ⰿ", 1, 2, 1),FCE("Ⱀ", 0, 2, 1), FCE("ⱀ", 1, 2, 1),FCE("𐐂", 0, 2, 1),FCE("𐐪", 1, 2, 1),FCE("Ⳅ", 0, 2, 1), FCE("ⳅ", 1, 2, 1),FCE("Ⅶ", 0, 2, 1),FCE("ⅶ", 1, 2, 1),FCE("Ⱁ", 0, 2, 1), FCE("ⱁ", 1, 2, 1),FCE("Ⱂ", 0, 2, 1),FCE("ⱂ", 1, 2, 1),FCE("Ⅸ", 0, 2, 1), FCE("ⅸ", 1, 2, 1),FCE("Ⱃ", 0, 2, 1),FCE("ⱃ", 1, 2, 1),FCE("Ꚃ", 0, 2, 1), FCE("ꚃ", 1, 2, 1),FCE("Ⱄ", 0, 2, 1),FCE("ⱄ", 1, 2, 1),FCE("Ⅺ", 0, 2, 1), FCE("ⅺ", 1, 2, 1),FCE("Ⓡ", 0, 2, 1),FCE("ⓡ", 1, 2, 1),FCE("Ⱅ", 0, 2, 1), FCE("ⱅ", 1, 2, 1),FCE("𐐃", 0, 2, 1),FCE("𐐫", 1, 2, 1),FCE("Ⱆ", 0, 2, 1), FCE("ⱆ", 1, 2, 1),FCE("Ⅼ", 0, 2, 1),FCE("ⅼ", 1, 2, 1),FCE("Ⱇ", 0, 2, 1), FCE("ⱇ", 1, 2, 1),FCE("X", 0, 2, 1),FCE("x", 1, 2, 1),FCE("Ⱈ", 0, 2, 1), FCE("ⱈ", 1, 2, 1),FCE("Ⅾ", 0, 2, 1),FCE("ⅾ", 1, 2, 1),FCE("Ⱉ", 0, 2, 1), FCE("ⱉ", 1, 2, 1),FCE("Ⱊ", 0, 2, 1),FCE("ⱊ", 1, 2, 1),FCE("Ⱎ", 0, 2, 1), FCE("ⱎ", 1, 2, 1),FCE("Ⴀ", 0, 2, 1),FCE("ⴀ", 1, 2, 1),FCE("Ⴁ", 0, 2, 1), FCE("ⴁ", 1, 2, 1),FCE("Ⴂ", 0, 2, 1),FCE("ⴂ", 1, 2, 1),FCE("Ⴃ", 0, 2, 1), FCE("ⴃ", 1, 2, 1),FCE("Ⴄ", 0, 2, 1),FCE("ⴄ", 1, 2, 1),FCE("Ⴅ", 0, 2, 1), FCE("ⴅ", 1, 2, 1),FCE("Ⴆ", 0, 2, 1),FCE("ⴆ", 1, 2, 1),FCE("Ⴇ", 0, 2, 1), FCE("ⴇ", 1, 2, 1),FCE("Ⴈ", 0, 2, 1),FCE("ⴈ", 1, 2, 1),FCE("Ⴉ", 0, 2, 1), FCE("ⴉ", 1, 2, 1),FCE("Ⴊ", 0, 2, 1),FCE("ⴊ", 1, 2, 1),FCE("Ⴋ", 0, 2, 1), FCE("ⴋ", 1, 2, 1),FCE("Ⴌ", 0, 2, 1),FCE("ⴌ", 1, 2, 1),FCE("Ⴍ", 0, 2, 1), FCE("ⴍ", 1, 2, 1),FCE("Ⴎ", 0, 2, 1),FCE("ⴎ", 1, 2, 1),FCE("Ⴏ", 0, 2, 1), FCE("ⴏ", 1, 2, 1),FCE("Ⴐ", 0, 2, 1),FCE("ⴐ", 1, 2, 1),FCE("Ⴑ", 0, 2, 1), FCE("ⴑ", 1, 2, 1),FCE("Ⴒ", 0, 2, 1),FCE("ⴒ", 1, 2, 1),FCE("Ⴓ", 0, 2, 1), FCE("ⴓ", 1, 2, 1),FCE("Ⴔ", 0, 2, 1),FCE("ⴔ", 1, 2, 1),FCE("Ⴕ", 0, 2, 1), FCE("ⴕ", 1, 2, 1),FCE("Ⴖ", 0, 2, 1),FCE("ⴖ", 1, 2, 1),FCE("Ⴗ", 0, 2, 1), FCE("ⴗ", 1, 2, 1),FCE("Ⴘ", 0, 2, 1),FCE("ⴘ", 1, 2, 1),FCE("Ⴙ", 0, 2, 1), FCE("ⴙ", 1, 2, 1),FCE("Ⴚ", 0, 2, 1),FCE("ⴚ", 1, 2, 1),FCE("Ⴛ", 0, 2, 1), FCE("ⴛ", 1, 2, 1),FCE("Ⴜ", 0, 2, 1),FCE("ⴜ", 1, 2, 1),FCE("Ⴝ", 0, 2, 1), FCE("ⴝ", 1, 2, 1),FCE("Ⴞ", 0, 2, 1),FCE("ⴞ", 1, 2, 1),FCE("Ⴟ", 0, 2, 1), FCE("ⴟ", 1, 2, 1),FCE("À", 0, 2, 1),FCE("à", 1, 2, 1),FCE("Á", 0, 2, 1), FCE("á", 1, 2, 1),FCE("Ⴢ", 0, 2, 1),FCE("ⴢ", 1, 2, 1),FCE("Ã", 0, 2, 1), FCE("ã", 1, 2, 1),FCE("Ⴤ", 0, 2, 1),FCE("ⴤ", 1, 2, 1),FCE("Å", 0, 3, 1), FCE("å", 1, 3, 1),FCE("Å", 2, 3, 1),FCE("Æ", 0, 2, 1),FCE("æ", 1, 2, 1), FCE("Ç", 0, 2, 1),FCE("ç", 1, 2, 1),FCE("È", 0, 2, 1),FCE("è", 1, 2, 1), FCE("É", 0, 2, 1),FCE("é", 1, 2, 1),FCE("Ê", 0, 2, 1),FCE("ê", 1, 2, 1), FCE("Ë", 0, 2, 1),FCE("ë", 1, 2, 1),FCE("Ì", 0, 2, 1),FCE("ì", 1, 2, 1), FCE("Í", 0, 2, 1),FCE("í", 1, 2, 1),FCE("Î", 0, 2, 1),FCE("î", 1, 2, 1), FCE("Ï", 0, 2, 1),FCE("ï", 1, 2, 1),FCE("Ð", 0, 2, 1),FCE("ð", 1, 2, 1), FCE("Ñ", 0, 2, 1),FCE("ñ", 1, 2, 1),FCE("Ò", 0, 2, 1),FCE("ò", 1, 2, 1), FCE("Ó", 0, 2, 1),FCE("ó", 1, 2, 1),FCE("Ô", 0, 2, 1),FCE("ô", 1, 2, 1), FCE("Õ", 0, 2, 1),FCE("õ", 1, 2, 1),FCE("Ö", 0, 2, 1),FCE("ö", 1, 2, 1), FCE("Ø", 0, 2, 1),FCE("ø", 1, 2, 1),FCE("Ù", 0, 2, 1),FCE("ù", 1, 2, 1), FCE("Ú", 0, 2, 1),FCE("ú", 1, 2, 1),FCE("Û", 0, 2, 1),FCE("û", 1, 2, 1), FCE("Ü", 0, 2, 1),FCE("ü", 1, 2, 1),FCE("Ý", 0, 2, 1),FCE("ý", 1, 2, 1), FCE("Þ", 0, 2, 1),FCE("þ", 1, 2, 1),FCE("ß", 0, 3, 1),FCE("ẞ", 1, 3, 1), FCE("ss", 2, 3, 2),FCE("Ⱖ", 0, 2, 1),FCE("ⱖ", 1, 2, 1),FCE("Ⱗ", 0, 2, 1), FCE("ⱗ", 1, 2, 1),FCE("Ⱘ", 0, 2, 1),FCE("ⱘ", 1, 2, 1),FCE("𐐆", 0, 2, 1), FCE("𐐮", 1, 2, 1),FCE("𐐏", 0, 2, 1),FCE("𐐷", 1, 2, 1),FCE("Ⓥ", 0, 2, 1), FCE("ⓥ", 1, 2, 1),FCE("Ⱙ", 0, 2, 1),FCE("ⱙ", 1, 2, 1),FCE("𐐇", 0, 2, 1), FCE("𐐯", 1, 2, 1),FCE("Ⱚ", 0, 2, 1),FCE("ⱚ", 1, 2, 1),FCE("Ā", 0, 2, 1), FCE("ā", 1, 2, 1),FCE("Ă", 0, 2, 1),FCE("ă", 1, 2, 1),FCE("Ⱛ", 0, 2, 1), FCE("ⱛ", 1, 2, 1),FCE("Ą", 0, 2, 1),FCE("ą", 1, 2, 1),FCE("Ć", 0, 2, 1), FCE("ć", 1, 2, 1),FCE("Ĉ", 0, 2, 1),FCE("ĉ", 1, 2, 1),FCE("Ⱜ", 0, 2, 1), FCE("ⱜ", 1, 2, 1),FCE("Ċ", 0, 2, 1),FCE("ċ", 1, 2, 1),FCE("Č", 0, 2, 1), FCE("č", 1, 2, 1),FCE("Ď", 0, 2, 1),FCE("ď", 1, 2, 1),FCE("Ⱝ", 0, 2, 1), FCE("ⱝ", 1, 2, 1),FCE("Đ", 0, 2, 1),FCE("đ", 1, 2, 1),FCE("Ē", 0, 2, 1), FCE("ē", 1, 2, 1),FCE("Ĕ", 0, 2, 1),FCE("ĕ", 1, 2, 1),FCE("Ⱞ", 0, 2, 1), FCE("ⱞ", 1, 2, 1),FCE("Ė", 0, 2, 1),FCE("ė", 1, 2, 1),FCE("Ę", 0, 2, 1), FCE("ę", 1, 2, 1),FCE("Ě", 0, 2, 1),FCE("ě", 1, 2, 1),FCE("Ĝ", 0, 2, 1), FCE("ĝ", 1, 2, 1),FCE("Ğ", 0, 2, 1),FCE("ğ", 1, 2, 1),FCE("Ġ", 0, 2, 1), FCE("ġ", 1, 2, 1),FCE("Ģ", 0, 2, 1),FCE("ģ", 1, 2, 1),FCE("K", 0, 2, 1), FCE("k", 1, 2, 1),FCE("Ĥ", 0, 2, 1),FCE("ĥ", 1, 2, 1),FCE("Ħ", 0, 2, 1), FCE("ħ", 1, 2, 1),FCE("Ĩ", 0, 2, 1),FCE("ĩ", 1, 2, 1),FCE("Ī", 0, 2, 1), FCE("ī", 1, 2, 1),FCE("Å", 0, 3, 1),FCE("å", 1, 3, 1),FCE("Å", 2, 3, 1), FCE("Ĭ", 0, 2, 1),FCE("ĭ", 1, 2, 1),FCE("Į", 0, 2, 1),FCE("į", 1, 2, 1), FCE("İ", 0, 2, 1),FCE("i̇", 1, 2, 2),FCE("IJ", 0, 2, 1),FCE("ij", 1, 2, 1), FCE("Ĵ", 0, 2, 1),FCE("ĵ", 1, 2, 1),FCE("Ķ", 0, 2, 1),FCE("ķ", 1, 2, 1), FCE("Ĺ", 0, 2, 1),FCE("ĺ", 1, 2, 1),FCE("Ļ", 0, 2, 1),FCE("ļ", 1, 2, 1), FCE("Ⳟ", 0, 2, 1),FCE("ⳟ", 1, 2, 1),FCE("Ľ", 0, 2, 1),FCE("ľ", 1, 2, 1), FCE("Ŀ", 0, 2, 1),FCE("ŀ", 1, 2, 1),FCE("Ł", 0, 2, 1),FCE("ł", 1, 2, 1), FCE("Ń", 0, 2, 1),FCE("ń", 1, 2, 1),FCE("Ņ", 0, 2, 1),FCE("ņ", 1, 2, 1), FCE("Ň", 0, 2, 1),FCE("ň", 1, 2, 1),FCE("ʼn", 0, 2, 1),FCE("ʼn", 1, 2, 2), FCE("Ŋ", 0, 2, 1),FCE("ŋ", 1, 2, 1),FCE("Ō", 0, 2, 1),FCE("ō", 1, 2, 1), FCE("Ŏ", 0, 2, 1),FCE("ŏ", 1, 2, 1),FCE("Ő", 0, 2, 1),FCE("ő", 1, 2, 1), FCE("Œ", 0, 2, 1),FCE("œ", 1, 2, 1),FCE("Ŕ", 0, 2, 1),FCE("ŕ", 1, 2, 1), FCE("Ŗ", 0, 2, 1),FCE("ŗ", 1, 2, 1),FCE("Ř", 0, 2, 1),FCE("ř", 1, 2, 1), FCE("Ś", 0, 2, 1),FCE("ś", 1, 2, 1),FCE("Ŝ", 0, 2, 1),FCE("ŝ", 1, 2, 1), FCE("Ş", 0, 2, 1),FCE("ş", 1, 2, 1),FCE("Š", 0, 2, 1),FCE("š", 1, 2, 1), FCE("Ⅱ", 0, 2, 1),FCE("ⅱ", 1, 2, 1),FCE("Ţ", 0, 2, 1),FCE("ţ", 1, 2, 1), FCE("Ⅳ", 0, 2, 1),FCE("ⅳ", 1, 2, 1),FCE("Ť", 0, 2, 1),FCE("ť", 1, 2, 1), FCE("Ⅵ", 0, 2, 1),FCE("ⅵ", 1, 2, 1),FCE("Ŧ", 0, 2, 1),FCE("ŧ", 1, 2, 1), FCE("Ⅷ", 0, 2, 1),FCE("ⅷ", 1, 2, 1),FCE("Ũ", 0, 2, 1),FCE("ũ", 1, 2, 1), FCE("Ⅹ", 0, 2, 1),FCE("ⅹ", 1, 2, 1),FCE("Ū", 0, 2, 1),FCE("ū", 1, 2, 1), FCE("Ⅻ", 0, 2, 1),FCE("ⅻ", 1, 2, 1),FCE("Ŭ", 0, 2, 1),FCE("ŭ", 1, 2, 1), FCE("Ⅽ", 0, 2, 1),FCE("ⅽ", 1, 2, 1),FCE("Ů", 0, 2, 1),FCE("ů", 1, 2, 1), FCE("Ⅿ", 0, 2, 1),FCE("ⅿ", 1, 2, 1),FCE("Ű", 0, 2, 1),FCE("ű", 1, 2, 1), FCE("Ⳍ", 0, 2, 1),FCE("ⳍ", 1, 2, 1),FCE("Ų", 0, 2, 1),FCE("ų", 1, 2, 1), FCE("Ŵ", 0, 2, 1),FCE("ŵ", 1, 2, 1),FCE("Ŷ", 0, 2, 1),FCE("ŷ", 1, 2, 1), FCE("ÿ", 0, 2, 1),FCE("Ÿ", 1, 2, 1),FCE("Ź", 0, 2, 1),FCE("ź", 1, 2, 1), FCE("Ż", 0, 2, 1),FCE("ż", 1, 2, 1),FCE("Ž", 0, 2, 1),FCE("ž", 1, 2, 1), FCE("S", 0, 3, 1),FCE("s", 1, 3, 1),FCE("ſ", 2, 3, 1),FCE("Ɓ", 0, 2, 1), FCE("ɓ", 1, 2, 1),FCE("Ƃ", 0, 2, 1),FCE("ƃ", 1, 2, 1),FCE("Ↄ", 0, 2, 1), FCE("ↄ", 1, 2, 1),FCE("Ƅ", 0, 2, 1),FCE("ƅ", 1, 2, 1),FCE("Ɔ", 0, 2, 1), FCE("ɔ", 1, 2, 1),FCE("Ƈ", 0, 2, 1),FCE("ƈ", 1, 2, 1),FCE("Ɖ", 0, 2, 1), FCE("ɖ", 1, 2, 1),FCE("Ɗ", 0, 2, 1),FCE("ɗ", 1, 2, 1),FCE("Ƌ", 0, 2, 1), FCE("ƌ", 1, 2, 1),FCE("Ǝ", 0, 2, 1),FCE("ǝ", 1, 2, 1),FCE("Ə", 0, 2, 1), FCE("ə", 1, 2, 1),FCE("Ɛ", 0, 2, 1),FCE("ɛ", 1, 2, 1),FCE("Ƒ", 0, 2, 1), FCE("ƒ", 1, 2, 1),FCE("Ɠ", 0, 2, 1),FCE("ɠ", 1, 2, 1),FCE("Ɣ", 0, 2, 1), FCE("ɣ", 1, 2, 1),FCE("Ɩ", 0, 2, 1),FCE("ɩ", 1, 2, 1),FCE("Ɨ", 0, 2, 1), FCE("ɨ", 1, 2, 1),FCE("Ƙ", 0, 2, 1),FCE("ƙ", 1, 2, 1),FCE("Ɯ", 0, 2, 1), FCE("ɯ", 1, 2, 1),FCE("Ɲ", 0, 2, 1),FCE("ɲ", 1, 2, 1),FCE("Ꙋ", 0, 2, 1), FCE("ꙋ", 1, 2, 1),FCE("Ɵ", 0, 2, 1),FCE("ɵ", 1, 2, 1),FCE("Ơ", 0, 2, 1), FCE("ơ", 1, 2, 1),FCE("Ƣ", 0, 2, 1),FCE("ƣ", 1, 2, 1),FCE("Ƥ", 0, 2, 1), FCE("ƥ", 1, 2, 1),FCE("Ʀ", 0, 2, 1),FCE("ʀ", 1, 2, 1),FCE("Ƨ", 0, 2, 1), FCE("ƨ", 1, 2, 1),FCE("Ʃ", 0, 2, 1),FCE("ʃ", 1, 2, 1),FCE("Ƭ", 0, 2, 1), FCE("ƭ", 1, 2, 1),FCE("Ʈ", 0, 2, 1),FCE("ʈ", 1, 2, 1),FCE("Ư", 0, 2, 1), FCE("ư", 1, 2, 1),FCE("Ʊ", 0, 2, 1),FCE("ʊ", 1, 2, 1),FCE("Ʋ", 0, 2, 1), FCE("ʋ", 1, 2, 1),FCE("Ƴ", 0, 2, 1),FCE("ƴ", 1, 2, 1),FCE("Ƶ", 0, 2, 1), FCE("ƶ", 1, 2, 1),FCE("Ʒ", 0, 2, 1),FCE("ʒ", 1, 2, 1),FCE("Ƹ", 0, 2, 1), FCE("ƹ", 1, 2, 1),FCE("Ƽ", 0, 2, 1),FCE("ƽ", 1, 2, 1),FCE("DŽ", 0, 3, 1), FCE("Dž", 1, 3, 1),FCE("dž", 2, 3, 1),FCE("DŽ", 0, 3, 1),FCE("Dž", 1, 3, 1), FCE("dž", 2, 3, 1),FCE("LJ", 0, 3, 1),FCE("Lj", 1, 3, 1),FCE("lj", 2, 3, 1), FCE("LJ", 0, 3, 1),FCE("Lj", 1, 3, 1),FCE("lj", 2, 3, 1),FCE("NJ", 0, 3, 1), FCE("Nj", 1, 3, 1),FCE("nj", 2, 3, 1),FCE("NJ", 0, 3, 1),FCE("Nj", 1, 3, 1), FCE("nj", 2, 3, 1),FCE("Ǎ", 0, 2, 1),FCE("ǎ", 1, 2, 1),FCE("Ǐ", 0, 2, 1), FCE("ǐ", 1, 2, 1),FCE("Ǒ", 0, 2, 1),FCE("ǒ", 1, 2, 1),FCE("Ǔ", 0, 2, 1), FCE("ǔ", 1, 2, 1),FCE("Ǖ", 0, 2, 1),FCE("ǖ", 1, 2, 1),FCE("Ǘ", 0, 2, 1), FCE("ǘ", 1, 2, 1),FCE("Ǚ", 0, 2, 1),FCE("ǚ", 1, 2, 1),FCE("Ǜ", 0, 2, 1), FCE("ǜ", 1, 2, 1),FCE("Ǟ", 0, 2, 1),FCE("ǟ", 1, 2, 1),FCE("V", 0, 2, 1), FCE("v", 1, 2, 1),FCE("Ǡ", 0, 2, 1),FCE("ǡ", 1, 2, 1),FCE("Ǣ", 0, 2, 1), FCE("ǣ", 1, 2, 1),FCE("Ǥ", 0, 2, 1),FCE("ǥ", 1, 2, 1),FCE("Ǧ", 0, 2, 1), FCE("ǧ", 1, 2, 1),FCE("Ǩ", 0, 2, 1),FCE("ǩ", 1, 2, 1),FCE("Ǫ", 0, 2, 1), FCE("ǫ", 1, 2, 1),FCE("Ǭ", 0, 2, 1),FCE("ǭ", 1, 2, 1),FCE("Ǯ", 0, 2, 1), FCE("ǯ", 1, 2, 1),FCE("ǰ", 0, 2, 1),FCE("ǰ", 1, 2, 2),FCE("DZ", 0, 3, 1), FCE("Dz", 1, 3, 1),FCE("dz", 2, 3, 1),FCE("DZ", 0, 3, 1),FCE("Dz", 1, 3, 1), FCE("dz", 2, 3, 1),FCE("Ǵ", 0, 2, 1),FCE("ǵ", 1, 2, 1),FCE("ƕ", 0, 2, 1), FCE("Ƕ", 1, 2, 1),FCE("ƿ", 0, 2, 1),FCE("Ƿ", 1, 2, 1),FCE("Ǹ", 0, 2, 1), FCE("ǹ", 1, 2, 1),FCE("𐐝", 0, 2, 1),FCE("𐑅", 1, 2, 1),FCE("Ǻ", 0, 2, 1), FCE("ǻ", 1, 2, 1),FCE("Ǽ", 0, 2, 1),FCE("ǽ", 1, 2, 1),FCE("Ǿ", 0, 2, 1), FCE("ǿ", 1, 2, 1),FCE("Ȁ", 0, 2, 1),FCE("ȁ", 1, 2, 1),FCE("Ȃ", 0, 2, 1), FCE("ȃ", 1, 2, 1),FCE("Ȅ", 0, 2, 1),FCE("ȅ", 1, 2, 1),FCE("Ȇ", 0, 2, 1), FCE("ȇ", 1, 2, 1),FCE("fi", 0, 2, 1),FCE("fi", 1, 2, 2),FCE("Ȉ", 0, 2, 1), FCE("ȉ", 1, 2, 1),FCE("Ȋ", 0, 2, 1),FCE("ȋ", 1, 2, 1),FCE("Ȍ", 0, 2, 1), FCE("ȍ", 1, 2, 1),FCE("Ȏ", 0, 2, 1),FCE("ȏ", 1, 2, 1),FCE("Ȑ", 0, 2, 1), FCE("ȑ", 1, 2, 1),FCE("Ȓ", 0, 2, 1),FCE("ȓ", 1, 2, 1),FCE("Ȕ", 0, 2, 1), FCE("ȕ", 1, 2, 1),FCE("Ȗ", 0, 2, 1),FCE("ȗ", 1, 2, 1),FCE("Ș", 0, 2, 1), FCE("ș", 1, 2, 1),FCE("Ț", 0, 2, 1),FCE("ț", 1, 2, 1),FCE("Ȝ", 0, 2, 1), FCE("ȝ", 1, 2, 1),FCE("Ȟ", 0, 2, 1),FCE("ȟ", 1, 2, 1),FCE("ƞ", 0, 2, 1), FCE("Ƞ", 1, 2, 1),FCE("Ȣ", 0, 2, 1),FCE("ȣ", 1, 2, 1),FCE("Ȥ", 0, 2, 1), FCE("ȥ", 1, 2, 1),FCE("Ȧ", 0, 2, 1),FCE("ȧ", 1, 2, 1),FCE("Ȩ", 0, 2, 1), FCE("ȩ", 1, 2, 1),FCE("Ꝗ", 0, 2, 1),FCE("ꝗ", 1, 2, 1),FCE("Ȫ", 0, 2, 1), FCE("ȫ", 1, 2, 1),FCE("Ȭ", 0, 2, 1),FCE("ȭ", 1, 2, 1),FCE("Ȯ", 0, 2, 1), FCE("ȯ", 1, 2, 1),FCE("Ȱ", 0, 2, 1),FCE("ȱ", 1, 2, 1),FCE("Ȳ", 0, 2, 1), FCE("ȳ", 1, 2, 1),FCE("Ꚅ", 0, 2, 1),FCE("ꚅ", 1, 2, 1),FCE("Ⱥ", 0, 2, 1), FCE("ⱥ", 1, 2, 1),FCE("Ȼ", 0, 2, 1),FCE("ȼ", 1, 2, 1),FCE("ƚ", 0, 2, 1), FCE("Ƚ", 1, 2, 1),FCE("Ⱦ", 0, 2, 1),FCE("ⱦ", 1, 2, 1),FCE("Ɂ", 0, 2, 1), FCE("ɂ", 1, 2, 1),FCE("𐐒", 0, 2, 1),FCE("𐐺", 1, 2, 1),FCE("ƀ", 0, 2, 1), FCE("Ƀ", 1, 2, 1),FCE("Ʉ", 0, 2, 1),FCE("ʉ", 1, 2, 1),FCE("Ʌ", 0, 2, 1), FCE("ʌ", 1, 2, 1),FCE("Ɇ", 0, 2, 1),FCE("ɇ", 1, 2, 1),FCE("Ɉ", 0, 2, 1), FCE("ɉ", 1, 2, 1),FCE("Ɋ", 0, 2, 1),FCE("ɋ", 1, 2, 1),FCE("Ɍ", 0, 2, 1), FCE("ɍ", 1, 2, 1),FCE("Ⱋ", 0, 2, 1),FCE("ⱋ", 1, 2, 1),FCE("Ɏ", 0, 2, 1), FCE("ɏ", 1, 2, 1),FCE("𐐊", 0, 2, 1),FCE("𐐲", 1, 2, 1),FCE("Ⅰ", 0, 2, 1), FCE("ⅰ", 1, 2, 1),FCE("Ꚓ", 0, 2, 1),FCE("ꚓ", 1, 2, 1),FCE("ɽ", 0, 2, 1), FCE("Ɽ", 1, 2, 1),FCE("𐐐", 0, 2, 1),FCE("𐐸", 1, 2, 1),FCE("Ⱑ", 0, 2, 1), FCE("ⱑ", 1, 2, 1),FCE("Ⱪ", 0, 2, 1),FCE("ⱪ", 1, 2, 1),FCE("𐐉", 0, 2, 1), FCE("𐐱", 1, 2, 1),FCE("𐐔", 0, 2, 1),FCE("𐐼", 1, 2, 1),FCE("ﬕ", 0, 2, 1), FCE("մի", 1, 2, 2),FCE("Ⅲ", 0, 2, 1),FCE("ⅲ", 1, 2, 1),FCE("𐐞", 0, 2, 1), FCE("𐑆", 1, 2, 1),FCE("ɱ", 0, 2, 1),FCE("Ɱ", 1, 2, 1),FCE("𐐕", 0, 2, 1), FCE("𐐽", 1, 2, 1),FCE("ɒ", 0, 2, 1),FCE("Ɒ", 1, 2, 1),FCE("Ⱳ", 0, 2, 1), FCE("ⱳ", 1, 2, 1),FCE("Ⰻ", 0, 2, 1),FCE("ⰻ", 1, 2, 1),FCE("𐐖", 0, 2, 1), FCE("𐐾", 1, 2, 1),FCE("Ꚗ", 0, 2, 1),FCE("ꚗ", 1, 2, 1),FCE("Ⱶ", 0, 2, 1), FCE("ⱶ", 1, 2, 1),FCE("Ⅴ", 0, 2, 1),FCE("ⅴ", 1, 2, 1),FCE("Ꙁ", 0, 2, 1), FCE("ꙁ", 1, 2, 1),FCE("B", 0, 2, 1),FCE("b", 1, 2, 1),FCE("Ⰼ", 0, 2, 1), FCE("ⰼ", 1, 2, 1),FCE("𐐗", 0, 2, 1),FCE("𐐿", 1, 2, 1),FCE("D", 0, 2, 1), FCE("d", 1, 2, 1),FCE("E", 0, 2, 1),FCE("e", 1, 2, 1),FCE("F", 0, 2, 1), FCE("f", 1, 2, 1),FCE("Ⰽ", 0, 2, 1),FCE("ⰽ", 1, 2, 1),FCE("Ⓛ", 0, 2, 1), FCE("ⓛ", 1, 2, 1),FCE("Ꜩ", 0, 2, 1),FCE("ꜩ", 1, 2, 1),FCE("ȿ", 0, 2, 1), FCE("Ȿ", 1, 2, 1),FCE("𐐑", 0, 2, 1),FCE("𐐹", 1, 2, 1),FCE("I", 0, 2, 1), FCE("i", 1, 2, 1),FCE("𐐋", 0, 2, 1),FCE("𐐳", 1, 2, 1),FCE("Ꜫ", 0, 2, 1), FCE("ꜫ", 1, 2, 1),FCE("ff", 0, 2, 1),FCE("ff", 1, 2, 2),FCE("Ⲁ", 0, 2, 1), FCE("ⲁ", 1, 2, 1),FCE("fl", 0, 2, 1),FCE("fl", 1, 2, 2),FCE("ffi", 0, 2, 1), FCE("ffi", 1, 2, 3),FCE("ffl", 0, 2, 1),FCE("ffl", 1, 2, 3),FCE("ſt", 0, 3, 1), FCE("st", 1, 3, 1),FCE("st", 2, 3, 2),FCE("ſt", 0, 3, 1),FCE("st", 1, 3, 1), FCE("st", 2, 3, 2),FCE("Ꜭ", 0, 2, 1),FCE("ꜭ", 1, 2, 1),FCE("Ⰾ", 0, 2, 1), FCE("ⰾ", 1, 2, 1),FCE("M", 0, 2, 1),FCE("m", 1, 2, 1),FCE("ﬓ", 0, 2, 1), FCE("մն", 1, 2, 2),FCE("ﬔ", 0, 2, 1),FCE("մե", 1, 2, 2),FCE("Ꜯ", 0, 2, 1), FCE("ꜯ", 1, 2, 1),FCE("ﬖ", 0, 2, 1),FCE("վն", 1, 2, 2),FCE("ﬗ", 0, 2, 1), FCE("մխ", 1, 2, 2),FCE("𐐍", 0, 2, 1),FCE("𐐵", 1, 2, 1),FCE("O", 0, 2, 1), FCE("o", 1, 2, 1),FCE("Q", 0, 2, 1),FCE("q", 1, 2, 1),FCE("R", 0, 2, 1), FCE("r", 1, 2, 1),FCE("𐐚", 0, 2, 1),FCE("𐑂", 1, 2, 1),FCE("T", 0, 2, 1), FCE("t", 1, 2, 1),FCE("Ⲙ", 0, 2, 1),FCE("ⲙ", 1, 2, 1),FCE("Ⲋ", 0, 2, 1), FCE("ⲋ", 1, 2, 1),FCE("ͅ", 0, 4, 1),FCE("Ι", 1, 4, 1),FCE("ι", 2, 4, 1), FCE("ι", 3, 4, 1),FCE("Ⲍ", 0, 2, 1),FCE("ⲍ", 1, 2, 1),FCE("W", 0, 2, 1), FCE("w", 1, 2, 1),FCE("Ꙗ", 0, 2, 1),FCE("ꙗ", 1, 2, 1),FCE("𐐛", 0, 2, 1), FCE("𐑃", 1, 2, 1),FCE("Ꜹ", 0, 2, 1),FCE("ꜹ", 1, 2, 1),FCE("Ⲏ", 0, 2, 1), FCE("ⲏ", 1, 2, 1),FCE("Y", 0, 2, 1),FCE("y", 1, 2, 1),FCE("𐐄", 0, 2, 1), FCE("𐐬", 1, 2, 1),FCE("Ꜻ", 0, 2, 1),FCE("ꜻ", 1, 2, 1),FCE("Ⲑ", 0, 2, 1), FCE("ⲑ", 1, 2, 1),FCE("Ꜽ", 0, 2, 1),FCE("ꜽ", 1, 2, 1),FCE("Ⲓ", 0, 2, 1), FCE("ⲓ", 1, 2, 1),FCE("𐐜", 0, 2, 1),FCE("𐑄", 1, 2, 1),FCE("Ͱ", 0, 2, 1), FCE("ͱ", 1, 2, 1),FCE("Ͳ", 0, 2, 1),FCE("ͳ", 1, 2, 1),FCE("Ꜿ", 0, 2, 1), FCE("ꜿ", 1, 2, 1),FCE("Ͷ", 0, 2, 1),FCE("ͷ", 1, 2, 1),FCE("Ⲕ", 0, 2, 1), FCE("ⲕ", 1, 2, 1),FCE("Ⲗ", 0, 2, 1),FCE("ⲗ", 1, 2, 1),FCE("Ά", 0, 2, 1), FCE("ά", 1, 2, 1),FCE("𐐅", 0, 2, 1),FCE("𐐭", 1, 2, 1),FCE("Έ", 0, 2, 1), FCE("έ", 1, 2, 1),FCE("Ή", 0, 2, 1),FCE("ή", 1, 2, 1),FCE("Ί", 0, 2, 1), FCE("ί", 1, 2, 1),FCE("Ό", 0, 2, 1),FCE("ό", 1, 2, 1),FCE("Ύ", 0, 2, 1), FCE("ύ", 1, 2, 1),FCE("Ώ", 0, 2, 1),FCE("ώ", 1, 2, 1),FCE("ΐ", 0, 3, 1), FCE("ΐ", 1, 3, 1),FCE("ΐ", 2, 3, 3),FCE("Α", 0, 2, 1),FCE("α", 1, 2, 1), FCE("Β", 0, 3, 1),FCE("β", 1, 3, 1),FCE("ϐ", 2, 3, 1),FCE("Γ", 0, 2, 1), FCE("γ", 1, 2, 1),FCE("Δ", 0, 2, 1),FCE("δ", 1, 2, 1),FCE("Ε", 0, 3, 1), FCE("ε", 1, 3, 1),FCE("ϵ", 2, 3, 1),FCE("Ζ", 0, 2, 1),FCE("ζ", 1, 2, 1), FCE("Η", 0, 2, 1),FCE("η", 1, 2, 1),FCE("Θ", 0, 4, 1),FCE("θ", 1, 4, 1), FCE("ϑ", 2, 4, 1),FCE("ϴ", 3, 4, 1),FCE("ͅ", 0, 4, 1),FCE("Ι", 1, 4, 1), FCE("ι", 2, 4, 1),FCE("ι", 3, 4, 1),FCE("Κ", 0, 3, 1),FCE("κ", 1, 3, 1), FCE("ϰ", 2, 3, 1),FCE("Λ", 0, 2, 1),FCE("λ", 1, 2, 1),FCE("µ", 0, 3, 1), FCE("Μ", 1, 3, 1),FCE("μ", 2, 3, 1),FCE("Ν", 0, 2, 1),FCE("ν", 1, 2, 1), FCE("Ξ", 0, 2, 1),FCE("ξ", 1, 2, 1),FCE("Ο", 0, 2, 1),FCE("ο", 1, 2, 1), FCE("Π", 0, 3, 1),FCE("π", 1, 3, 1),FCE("ϖ", 2, 3, 1),FCE("Ρ", 0, 3, 1), FCE("ρ", 1, 3, 1),FCE("ϱ", 2, 3, 1),FCE("Σ", 0, 3, 1),FCE("ς", 1, 3, 1), FCE("σ", 2, 3, 1),FCE("Τ", 0, 2, 1),FCE("τ", 1, 2, 1),FCE("Υ", 0, 2, 1), FCE("υ", 1, 2, 1),FCE("Φ", 0, 3, 1),FCE("φ", 1, 3, 1),FCE("ϕ", 2, 3, 1), FCE("Χ", 0, 2, 1),FCE("χ", 1, 2, 1),FCE("Ψ", 0, 2, 1),FCE("ψ", 1, 2, 1), FCE("Ω", 0, 3, 1),FCE("ω", 1, 3, 1),FCE("Ω", 2, 3, 1),FCE("Ϊ", 0, 2, 1), FCE("ϊ", 1, 2, 1),FCE("Ϋ", 0, 2, 1),FCE("ϋ", 1, 2, 1),FCE("Ⓣ", 0, 2, 1), FCE("ⓣ", 1, 2, 1),FCE("Ⳡ", 0, 2, 1),FCE("ⳡ", 1, 2, 1),FCE("ΰ", 0, 3, 1), FCE("ΰ", 1, 3, 1),FCE("ΰ", 2, 3, 3),FCE("Ꝉ", 0, 2, 1),FCE("ꝉ", 1, 2, 1), FCE("Ⲝ", 0, 2, 1),FCE("ⲝ", 1, 2, 1),FCE("Ⲟ", 0, 2, 1),FCE("ⲟ", 1, 2, 1), FCE("Ꝋ", 0, 2, 1),FCE("ꝋ", 1, 2, 1),FCE("Ⲡ", 0, 2, 1),FCE("ⲡ", 1, 2, 1), FCE("Σ", 0, 3, 1),FCE("ς", 1, 3, 1),FCE("σ", 2, 3, 1),FCE("𐐟", 0, 2, 1), FCE("𐑇", 1, 2, 1),FCE("Ꝍ", 0, 2, 1),FCE("ꝍ", 1, 2, 1),FCE("Ꚋ", 0, 2, 1), FCE("ꚋ", 1, 2, 1),FCE("Ⲣ", 0, 2, 1),FCE("ⲣ", 1, 2, 1),FCE("Ϗ", 0, 2, 1), FCE("ϗ", 1, 2, 1),FCE("Β", 0, 3, 1),FCE("β", 1, 3, 1),FCE("ϐ", 2, 3, 1), FCE("Θ", 0, 4, 1),FCE("θ", 1, 4, 1),FCE("ϑ", 2, 4, 1),FCE("ϴ", 3, 4, 1), FCE("Φ", 0, 3, 1),FCE("φ", 1, 3, 1),FCE("ϕ", 2, 3, 1),FCE("Π", 0, 3, 1), FCE("π", 1, 3, 1),FCE("ϖ", 2, 3, 1),FCE("Ϙ", 0, 2, 1),FCE("ϙ", 1, 2, 1), FCE("Ⲥ", 0, 2, 1),FCE("ⲥ", 1, 2, 1),FCE("Ϛ", 0, 2, 1),FCE("ϛ", 1, 2, 1), FCE("Ϝ", 0, 2, 1),FCE("ϝ", 1, 2, 1),FCE("Ϟ", 0, 2, 1),FCE("ϟ", 1, 2, 1), FCE("Ϡ", 0, 2, 1),FCE("ϡ", 1, 2, 1),FCE("Ꝑ", 0, 2, 1),FCE("ꝑ", 1, 2, 1), FCE("Ϣ", 0, 2, 1),FCE("ϣ", 1, 2, 1),FCE("Ϥ", 0, 2, 1),FCE("ϥ", 1, 2, 1), FCE("Ⲧ", 0, 2, 1),FCE("ⲧ", 1, 2, 1),FCE("Ϧ", 0, 2, 1),FCE("ϧ", 1, 2, 1), FCE("𐐠", 0, 2, 1),FCE("𐑈", 1, 2, 1),FCE("Ϩ", 0, 2, 1),FCE("ϩ", 1, 2, 1), FCE("Ⳣ", 0, 2, 1),FCE("ⳣ", 1, 2, 1),FCE("Ϫ", 0, 2, 1),FCE("ϫ", 1, 2, 1), FCE("Ϭ", 0, 2, 1),FCE("ϭ", 1, 2, 1),FCE("Ꝓ", 0, 2, 1),FCE("ꝓ", 1, 2, 1), FCE("Ϯ", 0, 2, 1),FCE("ϯ", 1, 2, 1),FCE("Κ", 0, 3, 1),FCE("κ", 1, 3, 1), FCE("ϰ", 2, 3, 1),FCE("Ρ", 0, 3, 1),FCE("ρ", 1, 3, 1),FCE("ϱ", 2, 3, 1), FCE("Θ", 0, 4, 1),FCE("θ", 1, 4, 1),FCE("ϑ", 2, 4, 1),FCE("ϴ", 3, 4, 1), FCE("Ε", 0, 3, 1),FCE("ε", 1, 3, 1),FCE("ϵ", 2, 3, 1),FCE("Ϸ", 0, 2, 1), FCE("ϸ", 1, 2, 1),FCE("ϲ", 0, 2, 1),FCE("Ϲ", 1, 2, 1),FCE("Ϻ", 0, 2, 1), FCE("ϻ", 1, 2, 1),FCE("ͻ", 0, 2, 1),FCE("Ͻ", 1, 2, 1),FCE("ͼ", 0, 2, 1), FCE("Ͼ", 1, 2, 1),FCE("ͽ", 0, 2, 1),FCE("Ͽ", 1, 2, 1),FCE("Ѐ", 0, 2, 1), FCE("ѐ", 1, 2, 1),FCE("Ё", 0, 2, 1),FCE("ё", 1, 2, 1),FCE("Ђ", 0, 2, 1), FCE("ђ", 1, 2, 1),FCE("Ѓ", 0, 2, 1),FCE("ѓ", 1, 2, 1),FCE("Є", 0, 2, 1), FCE("є", 1, 2, 1),FCE("Ѕ", 0, 2, 1),FCE("ѕ", 1, 2, 1),FCE("І", 0, 2, 1), FCE("і", 1, 2, 1),FCE("Ї", 0, 2, 1),FCE("ї", 1, 2, 1),FCE("Ј", 0, 2, 1), FCE("ј", 1, 2, 1),FCE("Љ", 0, 2, 1),FCE("љ", 1, 2, 1),FCE("Њ", 0, 2, 1), FCE("њ", 1, 2, 1),FCE("Ћ", 0, 2, 1),FCE("ћ", 1, 2, 1),FCE("Ќ", 0, 2, 1), FCE("ќ", 1, 2, 1),FCE("Ѝ", 0, 2, 1),FCE("ѝ", 1, 2, 1),FCE("Ў", 0, 2, 1), FCE("ў", 1, 2, 1),FCE("Џ", 0, 2, 1),FCE("џ", 1, 2, 1),FCE("А", 0, 2, 1), FCE("а", 1, 2, 1),FCE("Б", 0, 2, 1),FCE("б", 1, 2, 1),FCE("В", 0, 2, 1), FCE("в", 1, 2, 1),FCE("Г", 0, 2, 1),FCE("г", 1, 2, 1),FCE("Д", 0, 2, 1), FCE("д", 1, 2, 1),FCE("Е", 0, 2, 1),FCE("е", 1, 2, 1),FCE("Ж", 0, 2, 1), FCE("ж", 1, 2, 1),FCE("З", 0, 2, 1),FCE("з", 1, 2, 1),FCE("И", 0, 2, 1), FCE("и", 1, 2, 1),FCE("Й", 0, 2, 1),FCE("й", 1, 2, 1),FCE("К", 0, 2, 1), FCE("к", 1, 2, 1),FCE("Л", 0, 2, 1),FCE("л", 1, 2, 1),FCE("М", 0, 2, 1), FCE("м", 1, 2, 1),FCE("Н", 0, 2, 1),FCE("н", 1, 2, 1),FCE("О", 0, 2, 1), FCE("о", 1, 2, 1),FCE("П", 0, 2, 1),FCE("п", 1, 2, 1),FCE("Р", 0, 2, 1), FCE("р", 1, 2, 1),FCE("С", 0, 2, 1),FCE("с", 1, 2, 1),FCE("Т", 0, 2, 1), FCE("т", 1, 2, 1),FCE("У", 0, 2, 1),FCE("у", 1, 2, 1),FCE("Ф", 0, 2, 1), FCE("ф", 1, 2, 1),FCE("Х", 0, 2, 1),FCE("х", 1, 2, 1),FCE("Ц", 0, 2, 1), FCE("ц", 1, 2, 1),FCE("Ч", 0, 2, 1),FCE("ч", 1, 2, 1),FCE("Ш", 0, 2, 1), FCE("ш", 1, 2, 1),FCE("Щ", 0, 2, 1),FCE("щ", 1, 2, 1),FCE("Ъ", 0, 2, 1), FCE("ъ", 1, 2, 1),FCE("Ы", 0, 2, 1),FCE("ы", 1, 2, 1),FCE("Ь", 0, 2, 1), FCE("ь", 1, 2, 1),FCE("Э", 0, 2, 1),FCE("э", 1, 2, 1),FCE("Ю", 0, 2, 1), FCE("ю", 1, 2, 1),FCE("Я", 0, 2, 1),FCE("я", 1, 2, 1),FCE("Z", 0, 2, 1), FCE("z", 1, 2, 1),FCE("Ⲵ", 0, 2, 1),FCE("ⲵ", 1, 2, 1),FCE("µ", 0, 3, 1), FCE("Μ", 1, 3, 1),FCE("μ", 2, 3, 1),FCE("𐐣", 0, 2, 1),FCE("𐑋", 1, 2, 1), FCE("Ⓐ", 0, 2, 1),FCE("ⓐ", 1, 2, 1),FCE("Ⓒ", 0, 2, 1),FCE("ⓒ", 1, 2, 1), FCE("L", 0, 2, 1),FCE("l", 1, 2, 1),FCE("𐐡", 0, 2, 1),FCE("𐑉", 1, 2, 1), FCE("Ⓔ", 0, 2, 1),FCE("ⓔ", 1, 2, 1),FCE("𐐙", 0, 2, 1),FCE("𐑁", 1, 2, 1), FCE("Ѡ", 0, 2, 1),FCE("ѡ", 1, 2, 1),FCE("Ѣ", 0, 2, 1),FCE("ѣ", 1, 2, 1), FCE("ᵽ", 0, 2, 1),FCE("Ᵽ", 1, 2, 1),FCE("Ѥ", 0, 2, 1),FCE("ѥ", 1, 2, 1), FCE("Ѧ", 0, 2, 1),FCE("ѧ", 1, 2, 1),FCE("Ⱨ", 0, 2, 1),FCE("ⱨ", 1, 2, 1), FCE("Ѩ", 0, 2, 1),FCE("ѩ", 1, 2, 1),FCE("Ⓖ", 0, 2, 1),FCE("ⓖ", 1, 2, 1), FCE("Ѫ", 0, 2, 1),FCE("ѫ", 1, 2, 1),FCE("Ⱬ", 0, 2, 1),FCE("ⱬ", 1, 2, 1), FCE("Ѭ", 0, 2, 1),FCE("ѭ", 1, 2, 1),FCE("ɑ", 0, 2, 1),FCE("Ɑ", 1, 2, 1), FCE("Ѯ", 0, 2, 1),FCE("ѯ", 1, 2, 1),FCE("ɐ", 0, 2, 1),FCE("Ɐ", 1, 2, 1), FCE("Ѱ", 0, 2, 1),FCE("ѱ", 1, 2, 1),FCE("Ꝩ", 0, 2, 1),FCE("ꝩ", 1, 2, 1), FCE("Ѳ", 0, 2, 1),FCE("ѳ", 1, 2, 1),FCE("Ѵ", 0, 2, 1),FCE("ѵ", 1, 2, 1), FCE("Ⓘ", 0, 2, 1),FCE("ⓘ", 1, 2, 1),FCE("Ѷ", 0, 2, 1),FCE("ѷ", 1, 2, 1), FCE("Ѹ", 0, 2, 1),FCE("ѹ", 1, 2, 1),FCE("Ѻ", 0, 2, 1),FCE("ѻ", 1, 2, 1), FCE("Ѽ", 0, 2, 1),FCE("ѽ", 1, 2, 1),FCE("Ꝫ", 0, 2, 1),FCE("ꝫ", 1, 2, 1), FCE("Ѿ", 0, 2, 1),FCE("ѿ", 1, 2, 1),FCE("ɀ", 0, 2, 1),FCE("Ɀ", 1, 2, 1), FCE("Ҁ", 0, 2, 1),FCE("ҁ", 1, 2, 1),FCE("Ⴠ", 0, 2, 1),FCE("ⴠ", 1, 2, 1), FCE("Ⲃ", 0, 2, 1),FCE("ⲃ", 1, 2, 1),FCE("Ⲅ", 0, 2, 1),FCE("ⲅ", 1, 2, 1), FCE("Ⲇ", 0, 2, 1),FCE("ⲇ", 1, 2, 1),FCE("Ⴡ", 0, 2, 1),FCE("ⴡ", 1, 2, 1), FCE("Ⲉ", 0, 2, 1),FCE("ⲉ", 1, 2, 1),FCE("Ꝭ", 0, 2, 1),FCE("ꝭ", 1, 2, 1), FCE("Ҋ", 0, 2, 1),FCE("ҋ", 1, 2, 1),FCE("Ҍ", 0, 2, 1),FCE("ҍ", 1, 2, 1), FCE("Â", 0, 2, 1),FCE("â", 1, 2, 1),FCE("Ҏ", 0, 2, 1),FCE("ҏ", 1, 2, 1), FCE("Ґ", 0, 2, 1),FCE("ґ", 1, 2, 1),FCE("Ғ", 0, 2, 1),FCE("ғ", 1, 2, 1), FCE("Ⴣ", 0, 2, 1),FCE("ⴣ", 1, 2, 1),FCE("Ҕ", 0, 2, 1),FCE("ҕ", 1, 2, 1), FCE("Ꝯ", 0, 2, 1),FCE("ꝯ", 1, 2, 1),FCE("Җ", 0, 2, 1),FCE("җ", 1, 2, 1), FCE("Ҙ", 0, 2, 1),FCE("ҙ", 1, 2, 1),FCE("Ä", 0, 2, 1),FCE("ä", 1, 2, 1), FCE("Қ", 0, 2, 1),FCE("қ", 1, 2, 1),FCE("𐐦", 0, 2, 1),FCE("𐑎", 1, 2, 1), FCE("Ҝ", 0, 2, 1),FCE("ҝ", 1, 2, 1),FCE("Ҟ", 0, 2, 1),FCE("ҟ", 1, 2, 1), FCE("Ⴥ", 0, 2, 1),FCE("ⴥ", 1, 2, 1),FCE("Ҡ", 0, 2, 1),FCE("ҡ", 1, 2, 1), FCE("Ң", 0, 2, 1),FCE("ң", 1, 2, 1),FCE("Ҥ", 0, 2, 1),FCE("ҥ", 1, 2, 1), FCE("Ⳇ", 0, 2, 1),FCE("ⳇ", 1, 2, 1),FCE("Ҧ", 0, 2, 1),FCE("ҧ", 1, 2, 1), FCE("Ҩ", 0, 2, 1),FCE("ҩ", 1, 2, 1),FCE("Ⱡ", 0, 2, 1),FCE("ⱡ", 1, 2, 1), FCE("Ҫ", 0, 2, 1),FCE("ҫ", 1, 2, 1),FCE("Ⴧ", 0, 2, 1),FCE("ⴧ", 1, 2, 1), FCE("Ҭ", 0, 2, 1),FCE("ҭ", 1, 2, 1),FCE("𐐓", 0, 2, 1),FCE("𐐻", 1, 2, 1), FCE("Ү", 0, 2, 1),FCE("ү", 1, 2, 1),FCE("Ұ", 0, 2, 1),FCE("ұ", 1, 2, 1), FCE("Ⳉ", 0, 2, 1),FCE("ⳉ", 1, 2, 1),FCE("Ҳ", 0, 2, 1),FCE("ҳ", 1, 2, 1), FCE("Ҵ", 0, 2, 1),FCE("ҵ", 1, 2, 1),FCE("Ҷ", 0, 2, 1),FCE("ҷ", 1, 2, 1), FCE("Ⓑ", 0, 2, 1),FCE("ⓑ", 1, 2, 1),FCE("Ҹ", 0, 2, 1),FCE("ҹ", 1, 2, 1), FCE("Ⓓ", 0, 2, 1),FCE("ⓓ", 1, 2, 1),FCE("Һ", 0, 2, 1),FCE("һ", 1, 2, 1), FCE("Ⓕ", 0, 2, 1),FCE("ⓕ", 1, 2, 1),FCE("Ҽ", 0, 2, 1),FCE("ҽ", 1, 2, 1), FCE("Ⓗ", 0, 2, 1),FCE("ⓗ", 1, 2, 1),FCE("Ҿ", 0, 2, 1),FCE("ҿ", 1, 2, 1), FCE("Ⓙ", 0, 2, 1),FCE("ⓙ", 1, 2, 1),FCE("Ӏ", 0, 2, 1),FCE("ӏ", 1, 2, 1), FCE("Ӂ", 0, 2, 1),FCE("ӂ", 1, 2, 1),FCE("Ⓜ", 0, 2, 1),FCE("ⓜ", 1, 2, 1), FCE("Ӄ", 0, 2, 1),FCE("ӄ", 1, 2, 1),FCE("Ⓞ", 0, 2, 1),FCE("ⓞ", 1, 2, 1), FCE("Ӆ", 0, 2, 1),FCE("ӆ", 1, 2, 1),FCE("Ⓠ", 0, 2, 1),FCE("ⓠ", 1, 2, 1), FCE("Ӈ", 0, 2, 1),FCE("ӈ", 1, 2, 1),FCE("Ⓢ", 0, 2, 1),FCE("ⓢ", 1, 2, 1), FCE("Ӊ", 0, 2, 1),FCE("ӊ", 1, 2, 1),FCE("Ⓤ", 0, 2, 1),FCE("ⓤ", 1, 2, 1), FCE("Ӌ", 0, 2, 1),FCE("ӌ", 1, 2, 1),FCE("Ⓦ", 0, 2, 1),FCE("ⓦ", 1, 2, 1), FCE("Ӎ", 0, 2, 1),FCE("ӎ", 1, 2, 1),FCE("Ⓨ", 0, 2, 1),FCE("ⓨ", 1, 2, 1), FCE("Ⴭ", 0, 2, 1),FCE("ⴭ", 1, 2, 1),FCE("Ӑ", 0, 2, 1),FCE("ӑ", 1, 2, 1), FCE("Ӓ", 0, 2, 1),FCE("ӓ", 1, 2, 1),FCE("Ӕ", 0, 2, 1),FCE("ӕ", 1, 2, 1), FCE("Ⳏ", 0, 2, 1),FCE("ⳏ", 1, 2, 1),FCE("Ӗ", 0, 2, 1),FCE("ӗ", 1, 2, 1), FCE("Ꝺ", 0, 2, 1),FCE("ꝺ", 1, 2, 1),FCE("Ә", 0, 2, 1),FCE("ә", 1, 2, 1), FCE("Ӛ", 0, 2, 1),FCE("ӛ", 1, 2, 1),FCE("Ⓩ", 0, 2, 1),FCE("ⓩ", 1, 2, 1), FCE("Ӝ", 0, 2, 1),FCE("ӝ", 1, 2, 1),FCE("Ӟ", 0, 2, 1),FCE("ӟ", 1, 2, 1), FCE("Ӡ", 0, 2, 1),FCE("ӡ", 1, 2, 1),FCE("Ⳑ", 0, 2, 1),FCE("ⳑ", 1, 2, 1), FCE("Ӣ", 0, 2, 1),FCE("ӣ", 1, 2, 1),FCE("Ӥ", 0, 2, 1),FCE("ӥ", 1, 2, 1), FCE("ɫ", 0, 2, 1),FCE("Ɫ", 1, 2, 1),FCE("Ӧ", 0, 2, 1),FCE("ӧ", 1, 2, 1), FCE("Ө", 0, 2, 1),FCE("ө", 1, 2, 1),FCE("Ӫ", 0, 2, 1),FCE("ӫ", 1, 2, 1), FCE("Ⅎ", 0, 2, 1),FCE("ⅎ", 1, 2, 1),FCE("Ӭ", 0, 2, 1),FCE("ӭ", 1, 2, 1), FCE("Ⳓ", 0, 2, 1),FCE("ⳓ", 1, 2, 1),FCE("Ӯ", 0, 2, 1),FCE("ӯ", 1, 2, 1), FCE("Ӱ", 0, 2, 1),FCE("ӱ", 1, 2, 1),FCE("𐐢", 0, 2, 1),FCE("𐑊", 1, 2, 1), FCE("Ӳ", 0, 2, 1),FCE("ӳ", 1, 2, 1),FCE("Ӵ", 0, 2, 1),FCE("ӵ", 1, 2, 1), FCE("Ӷ", 0, 2, 1),FCE("ӷ", 1, 2, 1),FCE("Ӹ", 0, 2, 1),FCE("ӹ", 1, 2, 1), FCE("Ⳕ", 0, 2, 1),FCE("ⳕ", 1, 2, 1),FCE("Ӻ", 0, 2, 1),FCE("ӻ", 1, 2, 1), FCE("Ӽ", 0, 2, 1),FCE("ӽ", 1, 2, 1),FCE("Ӿ", 0, 2, 1),FCE("ӿ", 1, 2, 1), FCE("Ԁ", 0, 2, 1),FCE("ԁ", 1, 2, 1),FCE("Ꞁ", 0, 2, 1),FCE("ꞁ", 1, 2, 1), FCE("Ԃ", 0, 2, 1),FCE("ԃ", 1, 2, 1),FCE("Ԅ", 0, 2, 1),FCE("ԅ", 1, 2, 1), FCE("Ⳗ", 0, 2, 1),FCE("ⳗ", 1, 2, 1),FCE("Ԇ", 0, 2, 1),FCE("ԇ", 1, 2, 1), FCE("Ԉ", 0, 2, 1),FCE("ԉ", 1, 2, 1),FCE("Ԋ", 0, 2, 1),FCE("ԋ", 1, 2, 1), FCE("Ԍ", 0, 2, 1),FCE("ԍ", 1, 2, 1),FCE("Ꞃ", 0, 2, 1),FCE("ꞃ", 1, 2, 1), FCE("Ԏ", 0, 2, 1),FCE("ԏ", 1, 2, 1),FCE("Ԑ", 0, 2, 1),FCE("ԑ", 1, 2, 1), FCE("Ⳙ", 0, 2, 1),FCE("ⳙ", 1, 2, 1),FCE("Ԓ", 0, 2, 1),FCE("ԓ", 1, 2, 1), FCE("Ԕ", 0, 2, 1),FCE("ԕ", 1, 2, 1),FCE("Ԗ", 0, 2, 1),FCE("ԗ", 1, 2, 1), FCE("Ԙ", 0, 2, 1),FCE("ԙ", 1, 2, 1),FCE("Ꞅ", 0, 2, 1),FCE("ꞅ", 1, 2, 1), FCE("Ԛ", 0, 2, 1),FCE("ԛ", 1, 2, 1),FCE("Ⲩ", 0, 2, 1),FCE("ⲩ", 1, 2, 1), FCE("Ԝ", 0, 2, 1),FCE("ԝ", 1, 2, 1),FCE("Ⳛ", 0, 2, 1),FCE("ⳛ", 1, 2, 1), FCE("Ԟ", 0, 2, 1),FCE("ԟ", 1, 2, 1),FCE("Ԡ", 0, 2, 1),FCE("ԡ", 1, 2, 1), FCE("Ԣ", 0, 2, 1),FCE("ԣ", 1, 2, 1),FCE("Ԥ", 0, 2, 1),FCE("ԥ", 1, 2, 1), FCE("Ꞇ", 0, 2, 1),FCE("ꞇ", 1, 2, 1),FCE("Ԧ", 0, 2, 1),FCE("ԧ", 1, 2, 1), FCE("Ⱐ", 0, 2, 1),FCE("ⱐ", 1, 2, 1),FCE("Ⳝ", 0, 2, 1),FCE("ⳝ", 1, 2, 1), FCE("Ա", 0, 2, 1),FCE("ա", 1, 2, 1),FCE("Բ", 0, 2, 1),FCE("բ", 1, 2, 1), FCE("Գ", 0, 2, 1),FCE("գ", 1, 2, 1),FCE("Դ", 0, 2, 1),FCE("դ", 1, 2, 1), FCE("Ե", 0, 2, 1),FCE("ե", 1, 2, 1),FCE("Զ", 0, 2, 1),FCE("զ", 1, 2, 1), FCE("Է", 0, 2, 1),FCE("է", 1, 2, 1),FCE("Ը", 0, 2, 1),FCE("ը", 1, 2, 1), FCE("Թ", 0, 2, 1),FCE("թ", 1, 2, 1),FCE("Ժ", 0, 2, 1),FCE("ժ", 1, 2, 1), FCE("Ի", 0, 2, 1),FCE("ի", 1, 2, 1),FCE("Լ", 0, 2, 1),FCE("լ", 1, 2, 1), FCE("Խ", 0, 2, 1),FCE("խ", 1, 2, 1),FCE("Ծ", 0, 2, 1),FCE("ծ", 1, 2, 1), FCE("Կ", 0, 2, 1),FCE("կ", 1, 2, 1),FCE("Հ", 0, 2, 1),FCE("հ", 1, 2, 1), FCE("Ձ", 0, 2, 1),FCE("ձ", 1, 2, 1),FCE("Ղ", 0, 2, 1),FCE("ղ", 1, 2, 1), FCE("Ճ", 0, 2, 1),FCE("ճ", 1, 2, 1),FCE("Մ", 0, 2, 1),FCE("մ", 1, 2, 1), FCE("Յ", 0, 2, 1),FCE("յ", 1, 2, 1),FCE("Ն", 0, 2, 1),FCE("ն", 1, 2, 1), FCE("Շ", 0, 2, 1),FCE("շ", 1, 2, 1),FCE("Ո", 0, 2, 1),FCE("ո", 1, 2, 1), FCE("Չ", 0, 2, 1),FCE("չ", 1, 2, 1),FCE("Պ", 0, 2, 1),FCE("պ", 1, 2, 1), FCE("Ջ", 0, 2, 1),FCE("ջ", 1, 2, 1),FCE("Ռ", 0, 2, 1),FCE("ռ", 1, 2, 1), FCE("Ս", 0, 2, 1),FCE("ս", 1, 2, 1),FCE("Վ", 0, 2, 1),FCE("վ", 1, 2, 1), FCE("Տ", 0, 2, 1),FCE("տ", 1, 2, 1),FCE("Ր", 0, 2, 1),FCE("ր", 1, 2, 1), FCE("Ց", 0, 2, 1),FCE("ց", 1, 2, 1),FCE("Ւ", 0, 2, 1),FCE("ւ", 1, 2, 1), FCE("Փ", 0, 2, 1),FCE("փ", 1, 2, 1),FCE("Ք", 0, 2, 1),FCE("ք", 1, 2, 1), FCE("Օ", 0, 2, 1),FCE("օ", 1, 2, 1),FCE("Ֆ", 0, 2, 1),FCE("ֆ", 1, 2, 1), FCE("Ⲫ", 0, 2, 1),FCE("ⲫ", 1, 2, 1),FCE("Ꞑ", 0, 2, 1),FCE("ꞑ", 1, 2, 1), FCE("Ⱒ", 0, 2, 1),FCE("ⱒ", 1, 2, 1),FCE("Ꞓ", 0, 2, 1),FCE("ꞓ", 1, 2, 1), FCE("Ⱓ", 0, 2, 1),FCE("ⱓ", 1, 2, 1),FCE("Ⳬ", 0, 2, 1),FCE("ⳬ", 1, 2, 1), FCE("Ⳋ", 0, 2, 1),FCE("ⳋ", 1, 2, 1),FCE("և", 0, 2, 1),FCE("եւ", 1, 2, 2), FCE("Ꙃ", 0, 2, 1),FCE("ꙃ", 1, 2, 1),FCE("Ⳮ", 0, 2, 1),FCE("ⳮ", 1, 2, 1), FCE("Ⲭ", 0, 2, 1),FCE("ⲭ", 1, 2, 1),FCE("Ꙅ", 0, 2, 1),FCE("ꙅ", 1, 2, 1), FCE("Ⱔ", 0, 2, 1),FCE("ⱔ", 1, 2, 1),FCE("Ꝕ", 0, 2, 1),FCE("ꝕ", 1, 2, 1), FCE("Ꙇ", 0, 2, 1),FCE("ꙇ", 1, 2, 1),FCE("Ⳳ", 0, 2, 1),FCE("ⳳ", 1, 2, 1), FCE("𐐈", 0, 2, 1),FCE("𐐰", 1, 2, 1),FCE("Ꙉ", 0, 2, 1),FCE("ꙉ", 1, 2, 1), FCE("Ⱕ", 0, 2, 1),FCE("ⱕ", 1, 2, 1),FCE("Ꞡ", 0, 2, 1),FCE("ꞡ", 1, 2, 1), FCE("Ꙍ", 0, 2, 1),FCE("ꙍ", 1, 2, 1),FCE("Ꞣ", 0, 2, 1),FCE("ꞣ", 1, 2, 1), FCE("Ⲯ", 0, 2, 1),FCE("ⲯ", 1, 2, 1),FCE("Ꙏ", 0, 2, 1),FCE("ꙏ", 1, 2, 1), FCE("Ꞥ", 0, 2, 1),FCE("ꞥ", 1, 2, 1),FCE("Ꙑ", 0, 2, 1),FCE("ꙑ", 1, 2, 1), FCE("Ꞧ", 0, 2, 1),FCE("ꞧ", 1, 2, 1),FCE("Ꞌ", 0, 2, 1),FCE("ꞌ", 1, 2, 1), FCE("Ꙓ", 0, 2, 1),FCE("ꙓ", 1, 2, 1),FCE("Ꞩ", 0, 2, 1),FCE("ꞩ", 1, 2, 1), FCE("Ꙕ", 0, 2, 1),FCE("ꙕ", 1, 2, 1),FCE("ɦ", 0, 2, 1),FCE("Ɦ", 1, 2, 1), FCE("Ḁ", 0, 2, 1),FCE("ḁ", 1, 2, 1),FCE("Ḃ", 0, 2, 1),FCE("ḃ", 1, 2, 1), FCE("Ḅ", 0, 2, 1),FCE("ḅ", 1, 2, 1),FCE("Ⱏ", 0, 2, 1),FCE("ⱏ", 1, 2, 1), FCE("Ḇ", 0, 2, 1),FCE("ḇ", 1, 2, 1),FCE("𐐎", 0, 2, 1),FCE("𐐶", 1, 2, 1), FCE("Ḉ", 0, 2, 1),FCE("ḉ", 1, 2, 1),FCE("Ḋ", 0, 2, 1),FCE("ḋ", 1, 2, 1), FCE("Ⲱ", 0, 2, 1),FCE("ⲱ", 1, 2, 1),FCE("Ḍ", 0, 2, 1),FCE("ḍ", 1, 2, 1), FCE("Ḏ", 0, 2, 1),FCE("ḏ", 1, 2, 1),FCE("Ḑ", 0, 2, 1),FCE("ḑ", 1, 2, 1), FCE("Ꙙ", 0, 2, 1),FCE("ꙙ", 1, 2, 1),FCE("Ḓ", 0, 2, 1),FCE("ḓ", 1, 2, 1), FCE("Ḕ", 0, 2, 1),FCE("ḕ", 1, 2, 1),FCE("Ⓧ", 0, 2, 1),FCE("ⓧ", 1, 2, 1), FCE("Ḗ", 0, 2, 1),FCE("ḗ", 1, 2, 1),FCE("Ḙ", 0, 2, 1),FCE("ḙ", 1, 2, 1), FCE("Ḛ", 0, 2, 1),FCE("ḛ", 1, 2, 1),FCE("Ḝ", 0, 2, 1),FCE("ḝ", 1, 2, 1), FCE("Ꙛ", 0, 2, 1),FCE("ꙛ", 1, 2, 1),FCE("Ḟ", 0, 2, 1),FCE("ḟ", 1, 2, 1), FCE("Ḡ", 0, 2, 1),FCE("ḡ", 1, 2, 1),FCE("Ḣ", 0, 2, 1),FCE("ḣ", 1, 2, 1), FCE("Ḥ", 0, 2, 1),FCE("ḥ", 1, 2, 1),FCE("Ḧ", 0, 2, 1),FCE("ḧ", 1, 2, 1), FCE("Ḩ", 0, 2, 1),FCE("ḩ", 1, 2, 1),FCE("Ꙝ", 0, 2, 1),FCE("ꙝ", 1, 2, 1), FCE("Ḫ", 0, 2, 1),FCE("ḫ", 1, 2, 1),FCE("Ḭ", 0, 2, 1),FCE("ḭ", 1, 2, 1), FCE("Ḯ", 0, 2, 1),FCE("ḯ", 1, 2, 1),FCE("Ḱ", 0, 2, 1),FCE("ḱ", 1, 2, 1), FCE("Ḳ", 0, 2, 1),FCE("ḳ", 1, 2, 1),FCE("Ḵ", 0, 2, 1),FCE("ḵ", 1, 2, 1), FCE("Ꙟ", 0, 2, 1),FCE("ꙟ", 1, 2, 1),FCE("Ḷ", 0, 2, 1),FCE("ḷ", 1, 2, 1), FCE("Ḹ", 0, 2, 1),FCE("ḹ", 1, 2, 1),FCE("Ḻ", 0, 2, 1),FCE("ḻ", 1, 2, 1), FCE("Ḽ", 0, 2, 1),FCE("ḽ", 1, 2, 1),FCE("Ḿ", 0, 2, 1),FCE("ḿ", 1, 2, 1), FCE("Ṁ", 0, 2, 1),FCE("ṁ", 1, 2, 1),FCE("Ꙡ", 0, 2, 1),FCE("ꙡ", 1, 2, 1), FCE("Ṃ", 0, 2, 1),FCE("ṃ", 1, 2, 1),FCE("Ṅ", 0, 2, 1),FCE("ṅ", 1, 2, 1), FCE("Ṇ", 0, 2, 1),FCE("ṇ", 1, 2, 1),FCE("Ⲳ", 0, 2, 1),FCE("ⲳ", 1, 2, 1), FCE("Ṉ", 0, 2, 1),FCE("ṉ", 1, 2, 1),FCE("Ⳁ", 0, 2, 1),FCE("ⳁ", 1, 2, 1), FCE("Ṋ", 0, 2, 1),FCE("ṋ", 1, 2, 1),FCE("Ṍ", 0, 2, 1),FCE("ṍ", 1, 2, 1), FCE("Ꙣ", 0, 2, 1),FCE("ꙣ", 1, 2, 1),FCE("Ṏ", 0, 2, 1),FCE("ṏ", 1, 2, 1), FCE("Ṑ", 0, 2, 1),FCE("ṑ", 1, 2, 1),FCE("Ṓ", 0, 2, 1),FCE("ṓ", 1, 2, 1), FCE("Ṕ", 0, 2, 1),FCE("ṕ", 1, 2, 1),FCE("Ṗ", 0, 2, 1),FCE("ṗ", 1, 2, 1), FCE("Ṙ", 0, 2, 1),FCE("ṙ", 1, 2, 1),FCE("Ꙥ", 0, 2, 1),FCE("ꙥ", 1, 2, 1), FCE("Ṛ", 0, 2, 1),FCE("ṛ", 1, 2, 1),FCE("Ṝ", 0, 2, 1),FCE("ṝ", 1, 2, 1), FCE("Ṟ", 0, 2, 1),FCE("ṟ", 1, 2, 1),FCE("Ṡ", 0, 3, 1),FCE("ṡ", 1, 3, 1), FCE("ẛ", 2, 3, 1),FCE("Ṣ", 0, 2, 1),FCE("ṣ", 1, 2, 1),FCE("𐐤", 0, 2, 1), FCE("𐑌", 1, 2, 1),FCE("Ṥ", 0, 2, 1),FCE("ṥ", 1, 2, 1),FCE("Ꙧ", 0, 2, 1), FCE("ꙧ", 1, 2, 1),FCE("Ṧ", 0, 2, 1),FCE("ṧ", 1, 2, 1),FCE("Ṩ", 0, 2, 1), FCE("ṩ", 1, 2, 1),FCE("Ṫ", 0, 2, 1),FCE("ṫ", 1, 2, 1),FCE("Ṭ", 0, 2, 1), FCE("ṭ", 1, 2, 1),FCE("Ṯ", 0, 2, 1),FCE("ṯ", 1, 2, 1),FCE("Ṱ", 0, 2, 1), FCE("ṱ", 1, 2, 1),FCE("Ꙩ", 0, 2, 1),FCE("ꙩ", 1, 2, 1),FCE("Ṳ", 0, 2, 1), FCE("ṳ", 1, 2, 1),FCE("Ṵ", 0, 2, 1),FCE("ṵ", 1, 2, 1),FCE("Ṷ", 0, 2, 1), FCE("ṷ", 1, 2, 1),FCE("Ⲿ", 0, 2, 1),FCE("ⲿ", 1, 2, 1),FCE("Ṹ", 0, 2, 1), FCE("ṹ", 1, 2, 1),FCE("Ṻ", 0, 2, 1),FCE("ṻ", 1, 2, 1),FCE("Ṽ", 0, 2, 1), FCE("ṽ", 1, 2, 1),FCE("Ꙫ", 0, 2, 1),FCE("ꙫ", 1, 2, 1),FCE("Ṿ", 0, 2, 1), FCE("ṿ", 1, 2, 1),FCE("Ẁ", 0, 2, 1),FCE("ẁ", 1, 2, 1),FCE("Ẃ", 0, 2, 1), FCE("ẃ", 1, 2, 1),FCE("Ẅ", 0, 2, 1),FCE("ẅ", 1, 2, 1),FCE("Ẇ", 0, 2, 1), FCE("ẇ", 1, 2, 1),FCE("Ẉ", 0, 2, 1),FCE("ẉ", 1, 2, 1),FCE("Ꙭ", 0, 2, 1), FCE("ꙭ", 1, 2, 1),FCE("Ẋ", 0, 2, 1),FCE("ẋ", 1, 2, 1),FCE("Ẍ", 0, 2, 1), FCE("ẍ", 1, 2, 1),FCE("Ẏ", 0, 2, 1),FCE("ẏ", 1, 2, 1),FCE("Ẑ", 0, 2, 1), FCE("ẑ", 1, 2, 1),FCE("Ẓ", 0, 2, 1),FCE("ẓ", 1, 2, 1),FCE("Ẕ", 0, 2, 1), FCE("ẕ", 1, 2, 1),FCE("ẖ", 0, 2, 1),FCE("ẖ", 1, 2, 2),FCE("ẗ", 0, 2, 1), FCE("ẗ", 1, 2, 2),FCE("ẘ", 0, 2, 1),FCE("ẘ", 1, 2, 2),FCE("ẙ", 0, 2, 1), FCE("ẙ", 1, 2, 2),FCE("ẚ", 0, 2, 1),FCE("aʾ", 1, 2, 2),FCE("Ṡ", 0, 3, 1), FCE("ṡ", 1, 3, 1),FCE("ẛ", 2, 3, 1),FCE("ß", 0, 3, 1),FCE("ẞ", 1, 3, 1), FCE("ss", 2, 3, 2),FCE("Ạ", 0, 2, 1),FCE("ạ", 1, 2, 1),FCE("Ả", 0, 2, 1), FCE("ả", 1, 2, 1),FCE("Ấ", 0, 2, 1),FCE("ấ", 1, 2, 1),FCE("Ⓟ", 0, 2, 1), FCE("ⓟ", 1, 2, 1),FCE("Ầ", 0, 2, 1),FCE("ầ", 1, 2, 1),FCE("Ẩ", 0, 2, 1), FCE("ẩ", 1, 2, 1),FCE("Ẫ", 0, 2, 1),FCE("ẫ", 1, 2, 1),FCE("Ậ", 0, 2, 1), FCE("ậ", 1, 2, 1),FCE("Ắ", 0, 2, 1),FCE("ắ", 1, 2, 1),FCE("H", 0, 2, 1), FCE("h", 1, 2, 1),FCE("Ằ", 0, 2, 1),FCE("ằ", 1, 2, 1),FCE("Ẳ", 0, 2, 1), FCE("ẳ", 1, 2, 1),FCE("𐐥", 0, 2, 1),FCE("𐑍", 1, 2, 1),FCE("Ẵ", 0, 2, 1), FCE("ẵ", 1, 2, 1),FCE("Ặ", 0, 2, 1),FCE("ặ", 1, 2, 1),FCE("Ẹ", 0, 2, 1), FCE("ẹ", 1, 2, 1),FCE("Ẻ", 0, 2, 1),FCE("ẻ", 1, 2, 1),FCE("Ẽ", 0, 2, 1), FCE("ẽ", 1, 2, 1),FCE("Ế", 0, 2, 1),FCE("ế", 1, 2, 1),FCE("Ⲷ", 0, 2, 1), FCE("ⲷ", 1, 2, 1),FCE("Ề", 0, 2, 1),FCE("ề", 1, 2, 1),FCE("Ể", 0, 2, 1), FCE("ể", 1, 2, 1),FCE("Ⲛ", 0, 2, 1),FCE("ⲛ", 1, 2, 1),FCE("Ễ", 0, 2, 1), FCE("ễ", 1, 2, 1),FCE("Ệ", 0, 2, 1),FCE("ệ", 1, 2, 1),FCE("Ỉ", 0, 2, 1), FCE("ỉ", 1, 2, 1),FCE("Ị", 0, 2, 1),FCE("ị", 1, 2, 1),FCE("Ọ", 0, 2, 1), FCE("ọ", 1, 2, 1),FCE("Ỏ", 0, 2, 1),FCE("ỏ", 1, 2, 1),FCE("Ố", 0, 2, 1), FCE("ố", 1, 2, 1),FCE("Ồ", 0, 2, 1),FCE("ồ", 1, 2, 1),FCE("Ổ", 0, 2, 1), FCE("ổ", 1, 2, 1),FCE("Ỗ", 0, 2, 1),FCE("ỗ", 1, 2, 1),FCE("Ộ", 0, 2, 1), FCE("ộ", 1, 2, 1),FCE("Ớ", 0, 2, 1),FCE("ớ", 1, 2, 1),FCE("Ờ", 0, 2, 1), FCE("ờ", 1, 2, 1),FCE("Ở", 0, 2, 1),FCE("ở", 1, 2, 1),FCE("Ỡ", 0, 2, 1), FCE("ỡ", 1, 2, 1),FCE("Ợ", 0, 2, 1),FCE("ợ", 1, 2, 1),FCE("Ụ", 0, 2, 1), FCE("ụ", 1, 2, 1),FCE("Ω", 0, 3, 1),FCE("ω", 1, 3, 1),FCE("Ω", 2, 3, 1), FCE("Ủ", 0, 2, 1),FCE("ủ", 1, 2, 1),FCE("Ứ", 0, 2, 1),FCE("ứ", 1, 2, 1), FCE("Ừ", 0, 2, 1),FCE("ừ", 1, 2, 1),FCE("J", 0, 2, 1),FCE("j", 1, 2, 1), FCE("Ử", 0, 2, 1),FCE("ử", 1, 2, 1),FCE("Ữ", 0, 2, 1),FCE("ữ", 1, 2, 1), FCE("Ự", 0, 2, 1),FCE("ự", 1, 2, 1),FCE("Ỳ", 0, 2, 1),FCE("ỳ", 1, 2, 1), FCE("Ỵ", 0, 2, 1),FCE("ỵ", 1, 2, 1),FCE("Ỷ", 0, 2, 1),FCE("ỷ", 1, 2, 1), FCE("Ỹ", 0, 2, 1),FCE("ỹ", 1, 2, 1),FCE("Ỻ", 0, 2, 1),FCE("ỻ", 1, 2, 1), FCE("Ⲹ", 0, 2, 1),FCE("ⲹ", 1, 2, 1),FCE("Ỽ", 0, 2, 1),FCE("ỽ", 1, 2, 1), FCE("K", 0, 3, 1),FCE("k", 1, 3, 1),FCE("K", 2, 3, 1),FCE("Ỿ", 0, 2, 1), FCE("ỿ", 1, 2, 1),FCE("Ꚁ", 0, 2, 1),FCE("ꚁ", 1, 2, 1),FCE("ἀ", 0, 2, 1), FCE("Ἀ", 1, 2, 1),FCE("ἁ", 0, 2, 1),FCE("Ἁ", 1, 2, 1),FCE("ἂ", 0, 2, 1), FCE("Ἂ", 1, 2, 1),FCE("ἃ", 0, 2, 1),FCE("Ἃ", 1, 2, 1),FCE("ἄ", 0, 2, 1), FCE("Ἄ", 1, 2, 1),FCE("ἅ", 0, 2, 1),FCE("Ἅ", 1, 2, 1),FCE("ἆ", 0, 2, 1), FCE("Ἆ", 1, 2, 1),FCE("ἇ", 0, 2, 1),FCE("Ἇ", 1, 2, 1),FCE("𐐘", 0, 2, 1), FCE("𐑀", 1, 2, 1),FCE("ɥ", 0, 2, 1),FCE("Ɥ", 1, 2, 1),FCE("ἐ", 0, 2, 1), FCE("Ἐ", 1, 2, 1),FCE("ἑ", 0, 2, 1),FCE("Ἑ", 1, 2, 1),FCE("ἒ", 0, 2, 1), FCE("Ἒ", 1, 2, 1),FCE("ἓ", 0, 2, 1),FCE("Ἓ", 1, 2, 1),FCE("ἔ", 0, 2, 1), FCE("Ἔ", 1, 2, 1),FCE("ἕ", 0, 2, 1),FCE("Ἕ", 1, 2, 1),FCE("A", 0, 2, 1), FCE("a", 1, 2, 1),FCE("Ꜣ", 0, 2, 1),FCE("ꜣ", 1, 2, 1),FCE("C", 0, 2, 1), FCE("c", 1, 2, 1),FCE("Ꜥ", 0, 2, 1),FCE("ꜥ", 1, 2, 1),FCE("Ꚇ", 0, 2, 1), FCE("ꚇ", 1, 2, 1),FCE("Ꜧ", 0, 2, 1),FCE("ꜧ", 1, 2, 1),FCE("G", 0, 2, 1), FCE("g", 1, 2, 1),FCE("ἠ", 0, 2, 1),FCE("Ἠ", 1, 2, 1),FCE("ἡ", 0, 2, 1), FCE("Ἡ", 1, 2, 1),FCE("ἢ", 0, 2, 1),FCE("Ἢ", 1, 2, 1),FCE("ἣ", 0, 2, 1), FCE("Ἣ", 1, 2, 1),FCE("ἤ", 0, 2, 1),FCE("Ἤ", 1, 2, 1),FCE("ἥ", 0, 2, 1), FCE("Ἥ", 1, 2, 1),FCE("ἦ", 0, 2, 1),FCE("Ἦ", 1, 2, 1),FCE("ἧ", 0, 2, 1), FCE("Ἧ", 1, 2, 1),FCE("P", 0, 2, 1),FCE("p", 1, 2, 1),FCE("Ꚉ", 0, 2, 1), FCE("ꚉ", 1, 2, 1),FCE("Ꜳ", 0, 2, 1),FCE("ꜳ", 1, 2, 1),FCE("S", 0, 2, 1), FCE("s", 1, 2, 1),FCE("Ꜵ", 0, 2, 1),FCE("ꜵ", 1, 2, 1),FCE("U", 0, 2, 1), FCE("u", 1, 2, 1),FCE("Ꜷ", 0, 2, 1),FCE("ꜷ", 1, 2, 1),FCE("Ⲻ", 0, 2, 1), FCE("ⲻ", 1, 2, 1),FCE("ἰ", 0, 2, 1),FCE("Ἰ", 1, 2, 1),FCE("ἱ", 0, 2, 1), FCE("Ἱ", 1, 2, 1),FCE("ἲ", 0, 2, 1),FCE("Ἲ", 1, 2, 1),FCE("ἳ", 0, 2, 1), FCE("Ἳ", 1, 2, 1),FCE("ἴ", 0, 2, 1),FCE("Ἴ", 1, 2, 1),FCE("ἵ", 0, 2, 1), FCE("Ἵ", 1, 2, 1),FCE("ἶ", 0, 2, 1),FCE("Ἶ", 1, 2, 1),FCE("ἷ", 0, 2, 1), FCE("Ἷ", 1, 2, 1),FCE("Ꝁ", 0, 2, 1),FCE("ꝁ", 1, 2, 1),FCE("Ꝃ", 0, 2, 1), FCE("ꝃ", 1, 2, 1),FCE("Ꝅ", 0, 2, 1),FCE("ꝅ", 1, 2, 1),FCE("Ꝇ", 0, 2, 1), FCE("ꝇ", 1, 2, 1),FCE("ὀ", 0, 2, 1),FCE("Ὀ", 1, 2, 1),FCE("ὁ", 0, 2, 1), FCE("Ὁ", 1, 2, 1),FCE("ὂ", 0, 2, 1),FCE("Ὂ", 1, 2, 1),FCE("ὃ", 0, 2, 1), FCE("Ὃ", 1, 2, 1),FCE("ὄ", 0, 2, 1),FCE("Ὄ", 1, 2, 1),FCE("ὅ", 0, 2, 1), FCE("Ὅ", 1, 2, 1),FCE("Ꝏ", 0, 2, 1),FCE("ꝏ", 1, 2, 1),FCE("ὐ", 0, 2, 1), FCE("ὐ", 1, 2, 2),FCE("ὒ", 0, 2, 1),FCE("ὒ", 1, 2, 3),FCE("ὔ", 0, 2, 1), FCE("ὔ", 1, 2, 3),FCE("Ꚏ", 0, 2, 1),FCE("ꚏ", 1, 2, 1),FCE("ὖ", 0, 2, 1), FCE("ὖ", 1, 2, 3),FCE("Ꝙ", 0, 2, 1),FCE("ꝙ", 1, 2, 1),FCE("ὑ", 0, 2, 1), FCE("Ὑ", 1, 2, 1),FCE("Ꝛ", 0, 2, 1),FCE("ꝛ", 1, 2, 1),FCE("ὓ", 0, 2, 1), FCE("Ὓ", 1, 2, 1),FCE("Ꝝ", 0, 2, 1),FCE("ꝝ", 1, 2, 1),FCE("ὕ", 0, 2, 1), FCE("Ὕ", 1, 2, 1),FCE("Ꝟ", 0, 2, 1),FCE("ꝟ", 1, 2, 1),FCE("ὗ", 0, 2, 1), FCE("Ὗ", 1, 2, 1),FCE("Ꝡ", 0, 2, 1),FCE("ꝡ", 1, 2, 1),FCE("Ꚑ", 0, 2, 1), FCE("ꚑ", 1, 2, 1),FCE("Ꝣ", 0, 2, 1),FCE("ꝣ", 1, 2, 1),FCE("N", 0, 2, 1), FCE("n", 1, 2, 1),FCE("Ꝥ", 0, 2, 1),FCE("ꝥ", 1, 2, 1),FCE("Ꝧ", 0, 2, 1), FCE("ꝧ", 1, 2, 1),FCE("ὠ", 0, 2, 1),FCE("Ὠ", 1, 2, 1),FCE("ὡ", 0, 2, 1), FCE("Ὡ", 1, 2, 1),FCE("ὢ", 0, 2, 1),FCE("Ὢ", 1, 2, 1),FCE("ὣ", 0, 2, 1), FCE("Ὣ", 1, 2, 1),FCE("ὤ", 0, 2, 1),FCE("Ὤ", 1, 2, 1),FCE("ὥ", 0, 2, 1), FCE("Ὥ", 1, 2, 1),FCE("ὦ", 0, 2, 1),FCE("Ὦ", 1, 2, 1),FCE("ὧ", 0, 2, 1), FCE("Ὧ", 1, 2, 1),FCE("Ⱌ", 0, 2, 1),FCE("ⱌ", 1, 2, 1),FCE("Ⲽ", 0, 2, 1), FCE("ⲽ", 1, 2, 1),FCE("Ꚕ", 0, 2, 1),FCE("ꚕ", 1, 2, 1),FCE("Ꝼ", 0, 2, 1), FCE("ꝼ", 1, 2, 1),FCE("ᵹ", 0, 2, 1),FCE("Ᵹ", 1, 2, 1),FCE("Ꝿ", 0, 2, 1), FCE("ꝿ", 1, 2, 1),FCE("ᾀ", 0, 3, 1),FCE("ᾈ", 1, 3, 1),FCE("ἀι", 2, 3, 2), FCE("ᾁ", 0, 3, 1),FCE("ᾉ", 1, 3, 1),FCE("ἁι", 2, 3, 2),FCE("ᾂ", 0, 3, 1), FCE("ᾊ", 1, 3, 1),FCE("ἂι", 2, 3, 2),FCE("ᾃ", 0, 3, 1),FCE("ᾋ", 1, 3, 1), FCE("ἃι", 2, 3, 2),FCE("ᾄ", 0, 3, 1),FCE("ᾌ", 1, 3, 1),FCE("ἄι", 2, 3, 2), FCE("ᾅ", 0, 3, 1),FCE("ᾍ", 1, 3, 1),FCE("ἅι", 2, 3, 2),FCE("ᾆ", 0, 3, 1), FCE("ᾎ", 1, 3, 1),FCE("ἆι", 2, 3, 2),FCE("ᾇ", 0, 3, 1),FCE("ᾏ", 1, 3, 1), FCE("ἇι", 2, 3, 2),FCE("ᾀ", 0, 3, 1),FCE("ᾈ", 1, 3, 1),FCE("ἀι", 2, 3, 2), FCE("ᾁ", 0, 3, 1),FCE("ᾉ", 1, 3, 1),FCE("ἁι", 2, 3, 2),FCE("ᾂ", 0, 3, 1), FCE("ᾊ", 1, 3, 1),FCE("ἂι", 2, 3, 2),FCE("ᾃ", 0, 3, 1),FCE("ᾋ", 1, 3, 1), FCE("ἃι", 2, 3, 2),FCE("ᾄ", 0, 3, 1),FCE("ᾌ", 1, 3, 1),FCE("ἄι", 2, 3, 2), FCE("ᾅ", 0, 3, 1),FCE("ᾍ", 1, 3, 1),FCE("ἅι", 2, 3, 2),FCE("ᾆ", 0, 3, 1), FCE("ᾎ", 1, 3, 1),FCE("ἆι", 2, 3, 2),FCE("ᾇ", 0, 3, 1),FCE("ᾏ", 1, 3, 1), FCE("ἇι", 2, 3, 2),FCE("ᾐ", 0, 3, 1),FCE("ᾘ", 1, 3, 1),FCE("ἠι", 2, 3, 2), FCE("ᾑ", 0, 3, 1),FCE("ᾙ", 1, 3, 1),FCE("ἡι", 2, 3, 2),FCE("ᾒ", 0, 3, 1), FCE("ᾚ", 1, 3, 1),FCE("ἢι", 2, 3, 2),FCE("ᾓ", 0, 3, 1),FCE("ᾛ", 1, 3, 1), FCE("ἣι", 2, 3, 2),FCE("ᾔ", 0, 3, 1),FCE("ᾜ", 1, 3, 1),FCE("ἤι", 2, 3, 2), FCE("ᾕ", 0, 3, 1),FCE("ᾝ", 1, 3, 1),FCE("ἥι", 2, 3, 2),FCE("ᾖ", 0, 3, 1), FCE("ᾞ", 1, 3, 1),FCE("ἦι", 2, 3, 2),FCE("ᾗ", 0, 3, 1),FCE("ᾟ", 1, 3, 1), FCE("ἧι", 2, 3, 2),FCE("ᾐ", 0, 3, 1),FCE("ᾘ", 1, 3, 1),FCE("ἠι", 2, 3, 2), FCE("ᾑ", 0, 3, 1),FCE("ᾙ", 1, 3, 1),FCE("ἡι", 2, 3, 2),FCE("ᾒ", 0, 3, 1), FCE("ᾚ", 1, 3, 1),FCE("ἢι", 2, 3, 2),FCE("ᾓ", 0, 3, 1),FCE("ᾛ", 1, 3, 1), FCE("ἣι", 2, 3, 2),FCE("ᾔ", 0, 3, 1),FCE("ᾜ", 1, 3, 1),FCE("ἤι", 2, 3, 2), FCE("ᾕ", 0, 3, 1),FCE("ᾝ", 1, 3, 1),FCE("ἥι", 2, 3, 2),FCE("ᾖ", 0, 3, 1), FCE("ᾞ", 1, 3, 1),FCE("ἦι", 2, 3, 2),FCE("ᾗ", 0, 3, 1),FCE("ᾟ", 1, 3, 1), FCE("ἧι", 2, 3, 2),FCE("ᾠ", 0, 3, 1),FCE("ᾨ", 1, 3, 1),FCE("ὠι", 2, 3, 2), FCE("ᾡ", 0, 3, 1),FCE("ᾩ", 1, 3, 1),FCE("ὡι", 2, 3, 2),FCE("ᾢ", 0, 3, 1), FCE("ᾪ", 1, 3, 1),FCE("ὢι", 2, 3, 2),FCE("ᾣ", 0, 3, 1),FCE("ᾫ", 1, 3, 1), FCE("ὣι", 2, 3, 2),FCE("ᾤ", 0, 3, 1),FCE("ᾬ", 1, 3, 1),FCE("ὤι", 2, 3, 2), FCE("ᾥ", 0, 3, 1),FCE("ᾭ", 1, 3, 1),FCE("ὥι", 2, 3, 2),FCE("ᾦ", 0, 3, 1), FCE("ᾮ", 1, 3, 1),FCE("ὦι", 2, 3, 2),FCE("ᾧ", 0, 3, 1),FCE("ᾯ", 1, 3, 1), FCE("ὧι", 2, 3, 2),FCE("ᾠ", 0, 3, 1),FCE("ᾨ", 1, 3, 1),FCE("ὠι", 2, 3, 2), FCE("ᾡ", 0, 3, 1),FCE("ᾩ", 1, 3, 1),FCE("ὡι", 2, 3, 2),FCE("ᾢ", 0, 3, 1), FCE("ᾪ", 1, 3, 1),FCE("ὢι", 2, 3, 2),FCE("ᾣ", 0, 3, 1),FCE("ᾫ", 1, 3, 1), FCE("ὣι", 2, 3, 2),FCE("ᾤ", 0, 3, 1),FCE("ᾬ", 1, 3, 1),FCE("ὤι", 2, 3, 2), FCE("ᾥ", 0, 3, 1),FCE("ᾭ", 1, 3, 1),FCE("ὥι", 2, 3, 2),FCE("ᾦ", 0, 3, 1), FCE("ᾮ", 1, 3, 1),FCE("ὦι", 2, 3, 2),FCE("ᾧ", 0, 3, 1),FCE("ᾯ", 1, 3, 1), FCE("ὧι", 2, 3, 2),FCE("ᾲ", 0, 2, 1),FCE("ὰι", 1, 2, 2),FCE("ᾳ", 0, 3, 1), FCE("ᾼ", 1, 3, 1),FCE("αι", 2, 3, 2),FCE("ᾴ", 0, 2, 1),FCE("άι", 1, 2, 2), FCE("ᾶ", 0, 2, 1),FCE("ᾶ", 1, 2, 2),FCE("ᾷ", 0, 2, 1),FCE("ᾶι", 1, 2, 3), FCE("ᾰ", 0, 2, 1),FCE("Ᾰ", 1, 2, 1),FCE("ᾱ", 0, 2, 1),FCE("Ᾱ", 1, 2, 1), FCE("ὰ", 0, 2, 1),FCE("Ὰ", 1, 2, 1),FCE("ά", 0, 2, 1),FCE("Ά", 1, 2, 1), FCE("ᾳ", 0, 3, 1),FCE("ᾼ", 1, 3, 1),FCE("αι", 2, 3, 2),FCE("ͅ", 0, 4, 1), FCE("Ι", 1, 4, 1),FCE("ι", 2, 4, 1),FCE("ι", 3, 4, 1),FCE("ῂ", 0, 2, 1), FCE("ὴι", 1, 2, 2),FCE("ῃ", 0, 3, 1),FCE("ῌ", 1, 3, 1),FCE("ηι", 2, 3, 2), FCE("ῄ", 0, 2, 1),FCE("ήι", 1, 2, 2),FCE("𐐌", 0, 2, 1),FCE("𐐴", 1, 2, 1), FCE("ῆ", 0, 2, 1),FCE("ῆ", 1, 2, 2),FCE("ῇ", 0, 2, 1),FCE("ῆι", 1, 2, 3), FCE("ὲ", 0, 2, 1),FCE("Ὲ", 1, 2, 1),FCE("έ", 0, 2, 1),FCE("Έ", 1, 2, 1), FCE("ὴ", 0, 2, 1),FCE("Ὴ", 1, 2, 1),FCE("ή", 0, 2, 1),FCE("Ή", 1, 2, 1), FCE("ῃ", 0, 3, 1),FCE("ῌ", 1, 3, 1),FCE("ηι", 2, 3, 2),FCE("ῒ", 0, 2, 1), FCE("ῒ", 1, 2, 3),FCE("ΐ", 0, 3, 1),FCE("ΐ", 1, 3, 1),FCE("ΐ", 2, 3, 3), FCE("ῖ", 0, 2, 1),FCE("ῖ", 1, 2, 2),FCE("ῗ", 0, 2, 1),FCE("ῗ", 1, 2, 3), FCE("ῐ", 0, 2, 1),FCE("Ῐ", 1, 2, 1),FCE("ῑ", 0, 2, 1),FCE("Ῑ", 1, 2, 1), FCE("ὶ", 0, 2, 1),FCE("Ὶ", 1, 2, 1),FCE("ί", 0, 2, 1),FCE("Ί", 1, 2, 1), FCE("𐐧", 0, 2, 1),FCE("𐑏", 1, 2, 1),FCE("ῢ", 0, 2, 1),FCE("ῢ", 1, 2, 3), FCE("ΰ", 0, 3, 1),FCE("ΰ", 1, 3, 1),FCE("ΰ", 2, 3, 3),FCE("ῤ", 0, 2, 1), FCE("ῤ", 1, 2, 2),FCE("ῦ", 0, 2, 1),FCE("ῦ", 1, 2, 2),FCE("ῧ", 0, 2, 1), FCE("ῧ", 1, 2, 3),FCE("ῠ", 0, 2, 1),FCE("Ῠ", 1, 2, 1),FCE("ῡ", 0, 2, 1), FCE("Ῡ", 1, 2, 1),FCE("ὺ", 0, 2, 1),FCE("Ὺ", 1, 2, 1),FCE("ύ", 0, 2, 1), FCE("Ύ", 1, 2, 1),FCE("ῥ", 0, 2, 1),FCE("Ῥ", 1, 2, 1),FCE("𐐁", 0, 2, 1), FCE("𐐩", 1, 2, 1),FCE("ῲ", 0, 2, 1),FCE("ὼι", 1, 2, 2),FCE("ῳ", 0, 3, 1), FCE("ῼ", 1, 3, 1),FCE("ωι", 2, 3, 2),FCE("ῴ", 0, 2, 1),FCE("ώι", 1, 2, 2), FCE("ῶ", 0, 2, 1),FCE("ῶ", 1, 2, 2),FCE("ῷ", 0, 2, 1),FCE("ῶι", 1, 2, 3), FCE("ὸ", 0, 2, 1),FCE("Ὸ", 1, 2, 1),FCE("ό", 0, 2, 1),FCE("Ό", 1, 2, 1), FCE("ὼ", 0, 2, 1),FCE("Ὼ", 1, 2, 1),FCE("ώ", 0, 2, 1),FCE("Ώ", 1, 2, 1), FCE("ῳ", 0, 3, 1),FCE("ῼ", 1, 3, 1),FCE("ωι", 2, 3, 2),FCE("Ⓚ", 0, 2, 1), FCE("ⓚ", 1, 2, 1),]; return t; } struct uniProps { private alias _U = immutable(UnicodeProperty); @property static _U[] tab() pure { return _tab; } static immutable: private alias _T = ubyte[]; _T So = [0x80, 0xa6, 0x1, 0x2, 0x1, 0x4, 0x1, 0x1, 0x1, 0x83, 0xd1, 0x1, 0x81, 0x8b, 0x2, 0x80, 0xce, 0x1, 0xa, 0x1, 0x13, 0x2, 0x80, 0xf7, 0x1, 0x82, 0x3, 0x1, 0x81, 0x75, 0x1, 0x80, 0x82, 0x6, 0x1, 0x1, 0x80, 0x84, 0x1, 0x80, 0xf9, 0x1, 0x81, 0x87, 0x3, 0xf, 0x1, 0x1, 0x3, 0x2, 0x6, 0x14, 0x1, 0x1, 0x1, 0x1, 0x1, 0x80, 0x85, 0x8, 0x1, 0x6, 0x1, 0x2, 0x5, 0x4, 0x80, 0xc5, 0x2, 0x82, 0xf0, 0xa, 0x85, 0xa6, 0x1, 0x80, 0x9d, 0x22, 0x81, 0x61, 0xa, 0x9, 0x9, 0x85, 0x83, 0x2, 0x1, 0x4, 0x1, 0x2, 0xa, 0x1, 0x1, 0x2, 0x6, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0xb, 0x2, 0xe, 0x1, 0x1, 0x2, 0x1, 0x1, 0x45, 0x5, 0x2, 0x4, 0x1, 0x2, 0x1, 0x2, 0x1, 0x7, 0x1, 0x1f, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1f, 0x81, 0xc, 0x8, 0x4, 0x14, 0x2, 0x7, 0x2, 0x51, 0x1, 0x1e, 0x19, 0x28, 0x6, 0x12, 0xc, 0x27, 0x19, 0xb, 0x51, 0x4e, 0x16, 0x80, 0xb7, 0x1, 0x9, 0x1, 0x36, 0x8, 0x6f, 0x1, 0x80, 0x90, 0x1, 0x67, 0x2c, 0x2c, 0x40, 0x81, 0x0, 0x82, 0x0, 0x30, 0x15, 0x2, 0x9, 0xa, 0x81, 0x8b, 0x6, 0x81, 0x95, 0x1a, 0x1, 0x59, 0xc, 0x80, 0xd6, 0x1a, 0xc, 0x8, 0x1, 0xd, 0x2, 0xc, 0x1, 0x15, 0x2, 0x6, 0x2, 0x81, 0x50, 0x2, 0x4, 0xa, 0x20, 0x24, 0x1c, 0x1f, 0xb, 0x1e, 0x8, 0x1, 0xf, 0x20, 0xa, 0x27, 0xf, 0x3f, 0x1, 0x81, 0x0, 0x99, 0xc0, 0x40, 0xa0, 0x56, 0x90, 0x37, 0x83, 0x61, 0x4, 0xa, 0x2, 0x1, 0x1, 0x82, 0x3d, 0x3, 0xa0, 0x53, 0x83, 0x1, 0x81, 0xe6, 0x1, 0x3, 0x1, 0x4, 0x2, 0xd, 0x2, 0x81, 0x39, 0x9, 0x39, 0x11, 0x6, 0xc, 0x34, 0x2d, 0xa0, 0xce, 0x3, 0x80, 0xf6, 0xa, 0x27, 0x2, 0x3c, 0x5, 0x3, 0x16, 0x2, 0x7, 0x1e, 0x4, 0x30, 0x22, 0x42, 0x3, 0x1, 0x80, 0xba, 0x57, 0x9c, 0xa9, 0x2c, 0x4, 0x64, 0xc, 0xf, 0x2, 0xe, 0x2, 0xf, 0x1, 0xf, 0x30, 0x1f, 0x1, 0x3c, 0x4, 0x2b, 0x4b, 0x1d, 0xd, 0x2b, 0x5, 0x9, 0x7, 0x2, 0x80, 0xae, 0x21, 0xf, 0x6, 0x1, 0x46, 0x3, 0x14, 0xc, 0x25, 0x1, 0x5, 0x15, 0x11, 0xf, 0x3f, 0x1, 0x1, 0x1, 0x80, 0xb6, 0x1, 0x4, 0x3, 0x3e, 0x2, 0x4, 0xc, 0x18, 0x80, 0x93, 0x46, 0x4, 0xb, 0x30, 0x46, 0x3a, 0x74]; _T Pf = [0x80, 0xbb, 0x1, 0x9f, 0x5d, 0x1, 0x3, 0x1, 0x1c, 0x1, 0x8d, 0xc8, 0x1, 0x1, 0x1, 0x4, 0x1, 0x2, 0x1, 0xf, 0x1, 0x3, 0x1]; _T Bidi_Control = [0x86, 0x1c, 0x1, 0x99, 0xf1, 0x2, 0x1a, 0x5, 0x37, 0x4]; _T Hex_Digit = [0x30, 0xa, 0x7, 0x6, 0x1a, 0x6, 0xa0, 0xfe, 0xa9, 0xa, 0x7, 0x6, 0x1a, 0x6]; _T Other_Lowercase = [0x80, 0xaa, 0x1, 0xf, 0x1, 0x81, 0xf5, 0x9, 0x7, 0x2, 0x1e, 0x5, 0x60, 0x1, 0x34, 0x1, 0x99, 0xb1, 0x3f, 0xd, 0x1, 0x22, 0x25, 0x82, 0xb1, 0x1, 0xd, 0x1, 0x10, 0xd, 0x80, 0xd3, 0x10, 0x83, 0x50, 0x1a, 0x87, 0x92, 0x2, 0xa0, 0x7a, 0xf2, 0x1, 0x80, 0x87, 0x2]; _T Quotation_Mark = [0x22, 0x1, 0x4, 0x1, 0x80, 0x83, 0x1, 0xf, 0x1, 0x9f, 0x5c, 0x8, 0x19, 0x2, 0x8f, 0xd1, 0x4, 0xd, 0x3, 0xa0, 0xce, 0x21, 0x4, 0x80, 0xbd, 0x1, 0x4, 0x1, 0x5a, 0x2]; _T XID_Start = [0x41, 0x1a, 0x6, 0x1a, 0x2f, 0x1, 0xa, 0x1, 0x4, 0x1, 0x5, 0x17, 0x1, 0x1f, 0x1, 0x81, 0xca, 0x4, 0xc, 0xe, 0x5, 0x7, 0x1, 0x1, 0x1, 0x80, 0x81, 0x5, 0x1, 0x2, 0x3, 0x3, 0x8, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x14, 0x1, 0x53, 0x1, 0x80, 0x8b, 0x8, 0x80, 0x9e, 0x9, 0x26, 0x2, 0x1, 0x7, 0x27, 0x48, 0x1b, 0x5, 0x3, 0x2d, 0x2b, 0x23, 0x2, 0x1, 0x63, 0x1, 0x1, 0xf, 0x2, 0x7, 0x2, 0xa, 0x3, 0x2, 0x1, 0x10, 0x1, 0x1, 0x1e, 0x1d, 0x59, 0xb, 0x1, 0x18, 0x21, 0x9, 0x2, 0x4, 0x1, 0x5, 0x16, 0x4, 0x1, 0x9, 0x1, 0x3, 0x1, 0x17, 0x19, 0x47, 0x1, 0x1, 0xb, 0x57, 0x36, 0x3, 0x1, 0x12, 0x1, 0x7, 0xa, 0xf, 0x7, 0x1, 0x7, 0x5, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x1, 0x3, 0x4, 0x3, 0x1, 0x10, 0x1, 0xd, 0x2, 0x1, 0x3, 0xe, 0x2, 0x13, 0x6, 0x4, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1f, 0x4, 0x1, 0x1, 0x13, 0x3, 0x10, 0x9, 0x1, 0x3, 0x1, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x1, 0x12, 0x1, 0xf, 0x2, 0x23, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x1, 0x1e, 0x2, 0x1, 0x3, 0xf, 0x1, 0x11, 0x1, 0x1, 0x6, 0x3, 0x3, 0x1, 0x4, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0xc, 0x16, 0x1, 0x34, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x1, 0x1a, 0x2, 0x6, 0x2, 0x23, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x1, 0x20, 0x1, 0x1, 0x2, 0xf, 0x2, 0x12, 0x8, 0x1, 0x3, 0x1, 0x29, 0x2, 0x1, 0x10, 0x1, 0x11, 0x2, 0x18, 0x6, 0x5, 0x12, 0x3, 0x18, 0x1, 0x9, 0x1, 0x1, 0x2, 0x7, 0x3a, 0x30, 0x1, 0x1, 0xd, 0x7, 0x3a, 0x2, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x6, 0x4, 0x1, 0x7, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0x4, 0x1, 0x1, 0xa, 0x1, 0x2, 0x5, 0x1, 0x1, 0x15, 0x4, 0x20, 0x1, 0x3f, 0x8, 0x1, 0x24, 0x1b, 0x5, 0x73, 0x2b, 0x14, 0x1, 0x10, 0x6, 0x4, 0x4, 0x3, 0x1, 0x3, 0x2, 0x7, 0x3, 0x4, 0xd, 0xc, 0x1, 0x11, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x2b, 0x1, 0x81, 0x4d, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0x29, 0x1, 0x4, 0x2, 0x21, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0xf, 0x1, 0x39, 0x1, 0x4, 0x2, 0x43, 0x25, 0x10, 0x10, 0x55, 0xc, 0x82, 0x6c, 0x2, 0x11, 0x1, 0x1a, 0x5, 0x4b, 0x3, 0x3, 0xf, 0xd, 0x1, 0x4, 0xe, 0x12, 0xe, 0x12, 0xe, 0xd, 0x1, 0x3, 0xf, 0x34, 0x23, 0x1, 0x4, 0x1, 0x43, 0x58, 0x8, 0x29, 0x1, 0x1, 0x5, 0x46, 0xa, 0x1d, 0x33, 0x1e, 0x2, 0x5, 0xb, 0x2c, 0x15, 0x7, 0x38, 0x17, 0x9, 0x35, 0x52, 0x1, 0x5d, 0x2f, 0x11, 0x7, 0x37, 0x1e, 0xd, 0x2, 0xa, 0x2c, 0x1a, 0x24, 0x29, 0x3, 0xa, 0x24, 0x6b, 0x4, 0x1, 0x4, 0x3, 0x2, 0x9, 0x80, 0xc0, 0x40, 0x81, 0x16, 0x2, 0x6, 0x2, 0x26, 0x2, 0x6, 0x2, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1f, 0x2, 0x35, 0x1, 0x7, 0x1, 0x1, 0x3, 0x3, 0x1, 0x7, 0x3, 0x4, 0x2, 0x6, 0x4, 0xd, 0x5, 0x3, 0x1, 0x7, 0x74, 0x1, 0xd, 0x1, 0x10, 0xd, 0x65, 0x1, 0x4, 0x1, 0x2, 0xa, 0x1, 0x1, 0x2, 0x6, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x10, 0x2, 0x4, 0x5, 0x5, 0x4, 0x1, 0x11, 0x29, 0x8a, 0x77, 0x2f, 0x1, 0x2f, 0x1, 0x80, 0x85, 0x6, 0x4, 0x3, 0x2, 0xc, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x38, 0x7, 0x1, 0x10, 0x17, 0x9, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x82, 0x26, 0x3, 0x19, 0x9, 0x7, 0x5, 0x2, 0x5, 0x4, 0x56, 0x6, 0x3, 0x1, 0x5a, 0x1, 0x4, 0x5, 0x29, 0x3, 0x5e, 0x11, 0x1b, 0x35, 0x10, 0x82, 0x0, 0x99, 0xb6, 0x4a, 0xa0, 0x51, 0xcd, 0x33, 0x84, 0x8d, 0x43, 0x2e, 0x2, 0x81, 0xd, 0x3, 0x10, 0xa, 0x2, 0x14, 0x2f, 0x10, 0x19, 0x8, 0x50, 0x27, 0x9, 0x2, 0x67, 0x2, 0x4, 0x1, 0x4, 0xc, 0xb, 0x4d, 0xa, 0x1, 0x3, 0x1, 0x4, 0x1, 0x17, 0x1d, 0x34, 0xe, 0x32, 0x3e, 0x6, 0x3, 0x1, 0xe, 0x1c, 0xa, 0x17, 0x19, 0x1d, 0x7, 0x2f, 0x1c, 0x1, 0x30, 0x29, 0x17, 0x3, 0x1, 0x8, 0x14, 0x17, 0x3, 0x1, 0x5, 0x30, 0x1, 0x1, 0x3, 0x2, 0x2, 0x5, 0x2, 0x1, 0x1, 0x1, 0x18, 0x3, 0x2, 0xb, 0x7, 0x3, 0xc, 0x6, 0x2, 0x6, 0x2, 0x6, 0x9, 0x7, 0x1, 0x7, 0x80, 0x91, 0x23, 0x1d, 0xa0, 0x2b, 0xa4, 0xc, 0x17, 0x4, 0x31, 0xa0, 0x21, 0x4, 0x81, 0x6e, 0x2, 0x6a, 0x26, 0x7, 0xc, 0x5, 0x5, 0x1, 0x1, 0xa, 0x1, 0xd, 0x1, 0x5, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x6c, 0x21, 0x80, 0x8b, 0x6, 0x80, 0xda, 0x12, 0x40, 0x2, 0x36, 0x28, 0xa, 0x77, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x7e, 0x24, 0x1a, 0x6, 0x1a, 0xb, 0x38, 0x2, 0x1f, 0x3, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x3, 0x23, 0xc, 0x1, 0x1a, 0x1, 0x13, 0x1, 0x2, 0x1, 0xf, 0x2, 0xe, 0x22, 0x7b, 0x45, 0x35, 0x81, 0xb, 0x1d, 0x3, 0x31, 0x2f, 0x1f, 0x11, 0x1b, 0x35, 0x1e, 0x2, 0x24, 0x4, 0x8, 0x1, 0x5, 0x2a, 0x80, 0x9e, 0x83, 0x62, 0x6, 0x2, 0x1, 0x1, 0x2c, 0x1, 0x2, 0x3, 0x1, 0x2, 0x17, 0x80, 0xaa, 0x16, 0xa, 0x1a, 0x46, 0x38, 0x6, 0x2, 0x40, 0x1, 0xf, 0x4, 0x1, 0x3, 0x1, 0x1b, 0x2c, 0x1d, 0x80, 0x83, 0x36, 0xa, 0x16, 0xa, 0x13, 0x80, 0x8d, 0x49, 0x83, 0xba, 0x35, 0x4b, 0x2d, 0x20, 0x19, 0x1a, 0x24, 0x5c, 0x30, 0xe, 0x4, 0x84, 0xbb, 0x2b, 0x89, 0x55, 0x83, 0x6f, 0x80, 0x91, 0x63, 0x8b, 0x9d, 0x84, 0x2f, 0xa0, 0x33, 0xd1, 0x82, 0x39, 0x84, 0xc7, 0x45, 0xb, 0x1, 0x42, 0xd, 0xa0, 0x40, 0x60, 0x2, 0xa0, 0x23, 0xfe, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x19, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x8, 0x96, 0x34, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x91, 0x44, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e]; _T Terminal_Punctuation = [0x21, 0x1, 0xa, 0x1, 0x1, 0x1, 0xb, 0x2, 0x3, 0x1, 0x83, 0x3e, 0x1, 0x8, 0x1, 0x82, 0x1, 0x1, 0x39, 0x1, 0x48, 0x1, 0xe, 0x1, 0x3, 0x1, 0x80, 0xb4, 0x1, 0x2b, 0xb, 0x1, 0x1, 0x80, 0xeb, 0x2, 0x36, 0xf, 0x1f, 0x1, 0x81, 0x5, 0x2, 0x84, 0xf4, 0x2, 0x80, 0xac, 0x1, 0x4, 0x6, 0x81, 0x37, 0x2, 0x83, 0x15, 0x8, 0x83, 0x4, 0x2, 0x7c, 0x3, 0x80, 0xe6, 0x3, 0x3, 0x1, 0x27, 0x4, 0x2, 0x2, 0x81, 0x3a, 0x2, 0x81, 0x62, 0x4, 0x80, 0xae, 0x2, 0x1, 0x3, 0x80, 0xdb, 0x5, 0x3e, 0x2, 0x83, 0xbc, 0x2, 0x9, 0x3, 0x8d, 0xe4, 0x1, 0x81, 0xd2, 0x2, 0xa0, 0x74, 0xfb, 0x2, 0x81, 0xd, 0x3, 0x80, 0xe3, 0x5, 0x81, 0x7e, 0x2, 0x56, 0x2, 0x5f, 0x1, 0x80, 0x97, 0x3, 0x80, 0x93, 0x3, 0x7f, 0x1, 0x10, 0x2, 0x80, 0xf9, 0x1, 0xa0, 0x52, 0x64, 0x3, 0x1, 0x4, 0x80, 0xa9, 0x1, 0xa, 0x1, 0x1, 0x1, 0xb, 0x2, 0x3, 0x1, 0x41, 0x1, 0x2, 0x1, 0x84, 0x3a, 0x1, 0x30, 0x1, 0x84, 0x86, 0x1, 0x80, 0xc7, 0x1, 0x82, 0x1a, 0x6, 0x85, 0x7, 0x7, 0x70, 0x4, 0x7f, 0x3, 0x80, 0x81, 0x2, 0x92, 0xa9, 0x4]; _T Math = [0x2b, 0x1, 0x10, 0x3, 0x1f, 0x1, 0x1d, 0x1, 0x1, 0x1, 0x2d, 0x1, 0x4, 0x1, 0x25, 0x1, 0x1f, 0x1, 0x82, 0xd8, 0x3, 0x2, 0x1, 0x1a, 0x2, 0x2, 0x3, 0x82, 0xf, 0x3, 0x9a, 0xd, 0x1, 0x1b, 0x3, 0xb, 0x1, 0x3, 0x1, 0xd, 0x1, 0xe, 0x4, 0x15, 0x5, 0xb, 0x5, 0x41, 0xd, 0x4, 0x1, 0x3, 0x2, 0x4, 0x5, 0x12, 0x1, 0x4, 0x1, 0x2, 0xa, 0x1, 0x1, 0x2, 0x6, 0x6, 0x1, 0x3, 0x2, 0x2, 0x2, 0x1, 0x3, 0x1, 0x6, 0x3, 0xe, 0x1, 0x1, 0x44, 0x18, 0x1, 0x6, 0x1, 0x2, 0x4, 0x2, 0x4, 0x20, 0x1, 0x1, 0x6, 0x2, 0xe, 0x81, 0xc, 0x8, 0x4, 0x14, 0x2, 0x5a, 0x1, 0x1e, 0x1b, 0x1, 0x1, 0x18, 0x1, 0xb, 0x7, 0x81, 0xbd, 0x2, 0xc, 0xa, 0x4, 0x6, 0x4, 0x2, 0x2, 0x2, 0x3, 0x5, 0xe, 0x1, 0x1, 0x1, 0x2, 0x6, 0xb, 0x8, 0x5, 0x2, 0x39, 0x1, 0x1, 0x1, 0x1d, 0x4, 0x9, 0x3, 0x81, 0x50, 0x40, 0x81, 0x0, 0x82, 0x0, 0x30, 0x15, 0x2, 0x6, 0xa0, 0xcf, 0xdc, 0x1, 0x83, 0x37, 0x6, 0x1, 0x1, 0x80, 0xa2, 0x1, 0x10, 0x3, 0x1d, 0x1, 0x1, 0x1, 0x1d, 0x1, 0x1, 0x1, 0x80, 0x83, 0x1, 0x6, 0x4, 0xa0, 0xd4, 0x13, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x81, 0x24, 0x2, 0x32, 0x96, 0x0, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x34, 0x2]; _T Lu = [0x41, 0x1a, 0x65, 0x17, 0x1, 0x7, 0x21, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x3, 0x2, 0x4, 0x1, 0x2, 0x1, 0x3, 0x3, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x3, 0x1, 0x1, 0x1, 0x2, 0x3, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x7, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x81, 0x21, 0x1, 0x1, 0x1, 0x3, 0x1, 0xf, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x2, 0x1, 0x11, 0x1, 0x9, 0x23, 0x1, 0x2, 0x3, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x5, 0x1, 0x2, 0x1, 0x1, 0x2, 0x2, 0x33, 0x30, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xa, 0x26, 0x8b, 0x49, 0x26, 0x1, 0x1, 0x5, 0x1, 0x8d, 0x32, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x8, 0x8, 0x6, 0xa, 0x8, 0x8, 0x8, 0x8, 0x6, 0xb, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x8, 0x8, 0x48, 0x4, 0xc, 0x4, 0xc, 0x4, 0xc, 0x5, 0xb, 0x4, 0x81, 0x6, 0x1, 0x4, 0x1, 0x3, 0x3, 0x2, 0x3, 0x2, 0x1, 0x3, 0x5, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x2, 0x4, 0xa, 0x2, 0x5, 0x1, 0x3d, 0x1, 0x8a, 0x7c, 0x2f, 0x31, 0x1, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x2, 0x1, 0x8, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x8, 0x1, 0x1, 0x1, 0x4, 0x1, 0xa0, 0x79, 0x4d, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x13, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x80, 0x8b, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xa, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0xd, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xa0, 0x57, 0x76, 0x1a, 0x84, 0xc5, 0x28, 0xa0, 0xcf, 0xd8, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0x8, 0x1a, 0x1a, 0x1a, 0x2, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1b, 0x2, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1b, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1e, 0x19, 0x21, 0x19, 0x21, 0x19, 0x21, 0x19, 0x21, 0x19, 0x21, 0x1]; _T Other_Uppercase = [0xa0, 0x21, 0x60, 0x10, 0x83, 0x46, 0x1a]; _T Sk = [0x5e, 0x1, 0x1, 0x1, 0x47, 0x1, 0x6, 0x1, 0x4, 0x1, 0x3, 0x1, 0x82, 0x9, 0x4, 0xc, 0xe, 0x5, 0x7, 0x1, 0x1, 0x1, 0x11, 0x75, 0x1, 0xe, 0x2, 0x9c, 0x37, 0x1, 0x1, 0x3, 0xb, 0x3, 0xd, 0x3, 0xd, 0x3, 0xd, 0x2, 0x90, 0x9c, 0x2, 0xa0, 0x76, 0x63, 0x17, 0x9, 0x2, 0x67, 0x2, 0xa0, 0x54, 0x27, 0x10, 0x83, 0x7c, 0x1, 0x1, 0x1, 0x80, 0xa2, 0x1]; _T Other_ID_Start = [0xa0, 0x21, 0x18, 0x1, 0x15, 0x1, 0x8f, 0x6c, 0x2]; _T Nl = [0x96, 0xee, 0x3, 0x8a, 0x6f, 0x23, 0x2, 0x4, 0x8e, 0x7e, 0x1, 0x19, 0x9, 0xe, 0x3, 0xa0, 0x76, 0xab, 0xa, 0xa0, 0x5a, 0x50, 0x35, 0x81, 0xcc, 0x1, 0x8, 0x1, 0x80, 0x86, 0x5, 0xa0, 0x20, 0x2a, 0x63]; _T Other_Alphabetic = [0x83, 0x45, 0x1, 0x82, 0x6a, 0xe, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x48, 0xb, 0x30, 0xd, 0x1, 0x7, 0x10, 0x1, 0x65, 0x7, 0x4, 0x4, 0x2, 0x2, 0x4, 0x1, 0x23, 0x1, 0x1e, 0x10, 0x66, 0xb, 0x65, 0x2, 0x3, 0x9, 0x1, 0x3, 0x1, 0x4, 0x80, 0xb7, 0x6, 0x6, 0xf, 0x1, 0x4, 0x36, 0x2, 0x2, 0xf, 0x1, 0x2, 0x5, 0x3, 0xa, 0x2, 0x1d, 0x3, 0x3a, 0x7, 0x2, 0x2, 0x2, 0x2, 0xa, 0x1, 0xa, 0x2, 0x1d, 0x3, 0x3a, 0x5, 0x4, 0x2, 0x2, 0x2, 0x4, 0x1, 0x1e, 0x2, 0x3, 0x1, 0xb, 0x3, 0x3a, 0x8, 0x1, 0x3, 0x1, 0x2, 0x15, 0x2, 0x1d, 0x3, 0x3a, 0x7, 0x2, 0x2, 0x2, 0x2, 0x9, 0x2, 0xa, 0x2, 0x1e, 0x1, 0x3b, 0x5, 0x3, 0x3, 0x1, 0x3, 0xa, 0x1, 0x29, 0x3, 0x3a, 0x7, 0x1, 0x3, 0x1, 0x3, 0x8, 0x2, 0xb, 0x2, 0x1e, 0x2, 0x3a, 0x7, 0x1, 0x3, 0x1, 0x3, 0x8, 0x2, 0xb, 0x2, 0x1e, 0x2, 0x3a, 0x7, 0x1, 0x3, 0x1, 0x3, 0xa, 0x1, 0xa, 0x2, 0x1e, 0x2, 0x4b, 0x6, 0x1, 0x1, 0x1, 0x8, 0x12, 0x2, 0x3d, 0x1, 0x2, 0x7, 0x12, 0x1, 0x63, 0x1, 0x2, 0x6, 0x1, 0x2, 0x10, 0x1, 0x80, 0xa3, 0x11, 0xb, 0xb, 0x1, 0x24, 0x6e, 0xc, 0x1, 0x1, 0x2, 0x4, 0x17, 0x4, 0x4, 0x3, 0x1, 0x1, 0x4, 0x2, 0x8, 0x4, 0xd, 0x5, 0x15, 0x2, 0x82, 0xc1, 0x1, 0x83, 0xb2, 0x2, 0x1e, 0x2, 0x1e, 0x2, 0x1e, 0x2, 0x42, 0x13, 0x80, 0xe0, 0x1, 0x76, 0xc, 0x4, 0x9, 0x77, 0x11, 0x7, 0x2, 0x4d, 0x5, 0x39, 0xa, 0x2, 0x14, 0x80, 0x8b, 0x5, 0x30, 0xf, 0x3c, 0x3, 0x1e, 0x9, 0x2, 0x2, 0x39, 0xb, 0x32, 0x12, 0x80, 0xbc, 0x2, 0x87, 0xc2, 0x34, 0x88, 0xf6, 0x20, 0xa0, 0x78, 0x74, 0x8, 0x23, 0x1, 0x81, 0x83, 0x5, 0x58, 0x2, 0x32, 0x10, 0x62, 0x5, 0x1c, 0xc, 0x2d, 0x4, 0x30, 0xc, 0x69, 0xe, 0xc, 0x1, 0x8, 0x2, 0x62, 0x1, 0x1, 0x3, 0x2, 0x2, 0x5, 0x1, 0x2c, 0x5, 0x5, 0x1, 0x80, 0xed, 0x8, 0xa0, 0x4f, 0x33, 0x1, 0x8e, 0xe2, 0x3, 0x1, 0x2, 0x5, 0x4, 0x85, 0xf0, 0x3, 0x35, 0xe, 0x3c, 0x1, 0x2d, 0x9, 0x47, 0x3, 0x24, 0xc, 0x4d, 0x3, 0x30, 0xd, 0x84, 0xeb, 0xb, 0xa0, 0x58, 0x9b, 0x2e]; _T Alphabetic = [0x41, 0x1a, 0x6, 0x1a, 0x2f, 0x1, 0xa, 0x1, 0x4, 0x1, 0x5, 0x17, 0x1, 0x1f, 0x1, 0x81, 0xca, 0x4, 0xc, 0xe, 0x5, 0x7, 0x1, 0x1, 0x1, 0x56, 0x1, 0x2a, 0x5, 0x1, 0x2, 0x2, 0x4, 0x8, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x14, 0x1, 0x53, 0x1, 0x80, 0x8b, 0x8, 0x80, 0x9e, 0x9, 0x26, 0x2, 0x1, 0x7, 0x27, 0x28, 0xe, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x8, 0x1b, 0x5, 0x3, 0x1d, 0xb, 0x5, 0x38, 0x1, 0x7, 0xe, 0x66, 0x1, 0x8, 0x4, 0x8, 0x4, 0x3, 0xa, 0x3, 0x2, 0x1, 0x10, 0x30, 0xd, 0x65, 0x18, 0x21, 0x9, 0x2, 0x4, 0x1, 0x5, 0x18, 0x2, 0x13, 0x13, 0x19, 0x47, 0x1, 0x1, 0xb, 0x37, 0x6, 0x6, 0xf, 0x1, 0x3c, 0x1, 0x10, 0x1, 0x3, 0x4, 0xf, 0xd, 0x7, 0x1, 0x7, 0x1, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x1, 0x3, 0x4, 0x3, 0x8, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x8, 0x1, 0x4, 0x2, 0x1, 0x5, 0xc, 0x2, 0xf, 0x3, 0x1, 0x6, 0x4, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x4, 0x5, 0x4, 0x2, 0x2, 0x2, 0x4, 0x1, 0x7, 0x4, 0x1, 0x1, 0x11, 0x6, 0xb, 0x3, 0x1, 0x9, 0x1, 0x3, 0x1, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x9, 0x1, 0x3, 0x1, 0x2, 0x3, 0x1, 0xf, 0x4, 0x1d, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x8, 0x2, 0x2, 0x2, 0x2, 0x9, 0x2, 0x4, 0x2, 0x1, 0x5, 0xd, 0x1, 0x10, 0x2, 0x1, 0x6, 0x3, 0x3, 0x1, 0x4, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0xc, 0x4, 0x5, 0x3, 0x3, 0x1, 0x3, 0x3, 0x1, 0x6, 0x1, 0x29, 0x3, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x8, 0x1, 0x3, 0x1, 0x3, 0x8, 0x2, 0x1, 0x2, 0x6, 0x4, 0x1e, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x8, 0x1, 0x3, 0x1, 0x3, 0x8, 0x2, 0x7, 0x1, 0x1, 0x4, 0xd, 0x2, 0xf, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x29, 0x2, 0x8, 0x1, 0x3, 0x1, 0x3, 0x1, 0x1, 0x8, 0x1, 0x8, 0x4, 0x16, 0x6, 0x2, 0x2, 0x1, 0x12, 0x3, 0x18, 0x1, 0x9, 0x1, 0x1, 0x2, 0x7, 0x8, 0x6, 0x1, 0x1, 0x1, 0x8, 0x12, 0x2, 0xd, 0x3a, 0x5, 0x7, 0x6, 0x1, 0x33, 0x2, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x6, 0x4, 0x1, 0x7, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0xd, 0x1, 0x3, 0x2, 0x5, 0x1, 0x1, 0x6, 0x1, 0xe, 0x4, 0x20, 0x1, 0x3f, 0x8, 0x1, 0x24, 0x4, 0x11, 0x6, 0x10, 0x1, 0x24, 0x43, 0x37, 0x1, 0x1, 0x2, 0x5, 0x10, 0x13, 0x2, 0x4, 0x5, 0x19, 0x7, 0x1, 0xd, 0x2, 0x2, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x2b, 0x1, 0x81, 0x4d, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0x29, 0x1, 0x4, 0x2, 0x21, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0xf, 0x1, 0x39, 0x1, 0x4, 0x2, 0x43, 0x4, 0x1, 0x20, 0x10, 0x10, 0x55, 0xc, 0x82, 0x6c, 0x2, 0x11, 0x1, 0x1a, 0x5, 0x4b, 0x3, 0x3, 0xf, 0xd, 0x1, 0x6, 0xc, 0x14, 0xc, 0x14, 0xc, 0xd, 0x1, 0x3, 0x1, 0x2, 0xc, 0x34, 0x2, 0x13, 0xe, 0x1, 0x4, 0x1, 0x43, 0x58, 0x8, 0x2b, 0x5, 0x46, 0xa, 0x1d, 0x3, 0xc, 0x4, 0x9, 0x17, 0x1e, 0x2, 0x5, 0xb, 0x2c, 0x4, 0x1a, 0x36, 0x1c, 0x4, 0x3f, 0x2, 0x14, 0x32, 0x1, 0x58, 0x34, 0x1, 0xf, 0x1, 0x7, 0x34, 0x2a, 0x2, 0x4, 0xa, 0x2c, 0x1, 0xb, 0xe, 0x36, 0x17, 0x3, 0xa, 0x24, 0x6b, 0x4, 0x1, 0x6, 0x1, 0x2, 0x9, 0x80, 0xc0, 0x40, 0x81, 0x16, 0x2, 0x6, 0x2, 0x26, 0x2, 0x6, 0x2, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1f, 0x2, 0x35, 0x1, 0x7, 0x1, 0x1, 0x3, 0x3, 0x1, 0x7, 0x3, 0x4, 0x2, 0x6, 0x4, 0xd, 0x5, 0x3, 0x1, 0x7, 0x74, 0x1, 0xd, 0x1, 0x10, 0xd, 0x65, 0x1, 0x4, 0x1, 0x2, 0xa, 0x1, 0x1, 0x3, 0x5, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0xb, 0x2, 0x4, 0x5, 0x5, 0x4, 0x1, 0x11, 0x29, 0x83, 0x2d, 0x34, 0x87, 0x16, 0x2f, 0x1, 0x2f, 0x1, 0x80, 0x85, 0x6, 0x4, 0x3, 0x2, 0xc, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x38, 0x7, 0x1, 0x10, 0x17, 0x9, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x20, 0x2f, 0x1, 0x81, 0xd5, 0x3, 0x19, 0x9, 0x7, 0x5, 0x2, 0x5, 0x4, 0x56, 0x6, 0x3, 0x1, 0x5a, 0x1, 0x4, 0x5, 0x29, 0x3, 0x5e, 0x11, 0x1b, 0x35, 0x10, 0x82, 0x0, 0x99, 0xb6, 0x4a, 0xa0, 0x51, 0xcd, 0x33, 0x84, 0x8d, 0x43, 0x2e, 0x2, 0x81, 0xd, 0x3, 0x10, 0xa, 0x2, 0x14, 0x2f, 0x5, 0x8, 0x3, 0x19, 0x7, 0x51, 0x27, 0x9, 0x2, 0x67, 0x2, 0x4, 0x1, 0x4, 0xc, 0xb, 0x4d, 0xa, 0x1, 0x3, 0x1, 0x4, 0x1, 0x1c, 0x18, 0x34, 0xc, 0x44, 0x2e, 0x6, 0x3, 0x1, 0xe, 0x21, 0x5, 0x23, 0xd, 0x1d, 0x3, 0x33, 0x1, 0xc, 0xf, 0x1, 0x30, 0x37, 0x9, 0xe, 0x12, 0x17, 0x3, 0x1, 0x5, 0x3f, 0x1, 0x1, 0x1, 0x1, 0x18, 0x3, 0x2, 0x10, 0x2, 0x4, 0xb, 0x6, 0x2, 0x6, 0x2, 0x6, 0x9, 0x7, 0x1, 0x7, 0x80, 0x91, 0x2b, 0x15, 0xa0, 0x2b, 0xa4, 0xc, 0x17, 0x4, 0x31, 0xa0, 0x21, 0x4, 0x81, 0x6e, 0x2, 0x6a, 0x26, 0x7, 0xc, 0x5, 0x5, 0xc, 0x1, 0xd, 0x1, 0x5, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x6c, 0x21, 0x81, 0x6b, 0x12, 0x40, 0x2, 0x36, 0x28, 0xc, 0x74, 0x5, 0x1, 0x80, 0x87, 0x24, 0x1a, 0x6, 0x1a, 0xb, 0x59, 0x3, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x3, 0x23, 0xc, 0x1, 0x1a, 0x1, 0x13, 0x1, 0x2, 0x1, 0xf, 0x2, 0xe, 0x22, 0x7b, 0x45, 0x35, 0x81, 0xb, 0x1d, 0x3, 0x31, 0x2f, 0x1f, 0x11, 0x1b, 0x35, 0x1e, 0x2, 0x24, 0x4, 0x8, 0x1, 0x5, 0x2a, 0x80, 0x9e, 0x83, 0x62, 0x6, 0x2, 0x1, 0x1, 0x2c, 0x1, 0x2, 0x3, 0x1, 0x2, 0x17, 0x80, 0xaa, 0x16, 0xa, 0x1a, 0x46, 0x38, 0x6, 0x2, 0x40, 0x4, 0x1, 0x2, 0x5, 0x8, 0x1, 0x3, 0x1, 0x1b, 0x2c, 0x1d, 0x80, 0x83, 0x36, 0xa, 0x16, 0xa, 0x13, 0x80, 0x8d, 0x49, 0x83, 0xb7, 0x46, 0x3c, 0x37, 0x17, 0x19, 0x17, 0x33, 0x4d, 0x40, 0x1, 0x4, 0x84, 0xbb, 0x36, 0x89, 0x4a, 0x83, 0x6f, 0x80, 0x91, 0x63, 0x8b, 0x9d, 0x84, 0x2f, 0xa0, 0x33, 0xd1, 0x82, 0x39, 0x84, 0xc7, 0x45, 0xb, 0x2f, 0x14, 0xd, 0xa0, 0x40, 0x60, 0x2, 0xa0, 0x23, 0xfe, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x19, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x8, 0x96, 0x34, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x91, 0x44, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e]; _T Zs = [0x20, 0x1, 0x7f, 0x1, 0x95, 0xdf, 0x1, 0x89, 0x7f, 0xb, 0x24, 0x1, 0x2f, 0x1, 0x8f, 0xa0, 0x1]; _T Variation_Selector = [0x98, 0xb, 0x3, 0xa0, 0xe5, 0xf2, 0x10, 0xad, 0x2, 0xf0, 0x80, 0xf0]; _T Other_Default_Ignorable_Code_Point = [0x83, 0x4f, 0x1, 0x8e, 0xf, 0x2, 0x86, 0x53, 0x2, 0x88, 0xaf, 0x1, 0x90, 0xfe, 0x1, 0xa0, 0xce, 0x3b, 0x1, 0x4f, 0x9, 0xad, 0x0, 0x7, 0x1, 0x1, 0x1e, 0x60, 0x80, 0x80, 0x80, 0xf0, 0x8e, 0x10]; _T IDS_Binary_Operator = [0xa0, 0x2f, 0xf0, 0x2, 0x2, 0x8]; _T Grapheme_Base = [0x20, 0x5f, 0x21, 0xd, 0x1, 0x82, 0x52, 0x70, 0x8, 0x2, 0x5, 0x5, 0x7, 0x1, 0x1, 0x1, 0x14, 0x1, 0x80, 0xe0, 0x7, 0x80, 0x9e, 0x9, 0x26, 0x2, 0x7, 0x1, 0x27, 0x1, 0x2, 0x4, 0x1, 0x2e, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x9, 0x1b, 0x5, 0x5, 0x11, 0xa, 0xb, 0x1, 0x2, 0x2d, 0x15, 0x10, 0x1, 0x65, 0x8, 0x1, 0x6, 0x2, 0x2, 0x1, 0x4, 0x20, 0x2, 0x1, 0x1, 0x1e, 0x1d, 0x59, 0xb, 0x1, 0xe, 0x2b, 0x9, 0x7, 0x5, 0x16, 0x4, 0x1, 0x9, 0x1, 0x3, 0x1, 0x7, 0xf, 0x1, 0x19, 0x5, 0x1, 0x41, 0x1, 0x1, 0xb, 0x56, 0x37, 0x1, 0x1, 0x1, 0x4, 0x8, 0x4, 0x1, 0x3, 0x7, 0xa, 0x2, 0x14, 0x1, 0x7, 0x2, 0x2, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x1, 0x3, 0x4, 0x3, 0x1, 0x1, 0x2, 0x6, 0x2, 0x2, 0x2, 0x1, 0x1, 0xd, 0x2, 0x1, 0x3, 0x4, 0x16, 0x7, 0x1, 0x1, 0x6, 0x4, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x4, 0x3, 0x18, 0x4, 0x1, 0x1, 0x7, 0xa, 0x2, 0x3, 0xe, 0x1, 0x1, 0x9, 0x1, 0x3, 0x1, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x4, 0x8, 0x1, 0x1, 0x2, 0x3, 0x1, 0xf, 0x2, 0x4, 0xc, 0x10, 0x2, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x1, 0x2, 0x1, 0x6, 0x2, 0x2, 0x2, 0xf, 0x2, 0x1, 0x3, 0x4, 0x12, 0xb, 0x1, 0x1, 0x6, 0x3, 0x3, 0x1, 0x4, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0xc, 0x5, 0x1, 0x1, 0x2, 0x3, 0x3, 0x1, 0x3, 0x3, 0x1, 0x15, 0x15, 0x6, 0x3, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x1, 0x3, 0x4, 0x13, 0x2, 0x6, 0x2, 0x4, 0xa, 0x8, 0x8, 0x2, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x2, 0x1, 0x2, 0x1, 0x2, 0x2, 0x2, 0x1, 0x2, 0x12, 0x1, 0x1, 0x2, 0x4, 0xa, 0x1, 0x2, 0xf, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x29, 0x2, 0x1, 0x1, 0x2, 0x5, 0x3, 0x1, 0x3, 0x1, 0x1, 0x11, 0x2, 0x4, 0x10, 0x3, 0x7, 0x2, 0x2, 0x1, 0x12, 0x3, 0x18, 0x1, 0x9, 0x1, 0x1, 0x2, 0x7, 0x9, 0x2, 0x6, 0x7, 0x13, 0x3, 0xc, 0x30, 0x1, 0x2, 0xb, 0x8, 0x8, 0xd, 0x25, 0x2, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x6, 0x4, 0x1, 0x7, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0x4, 0x1, 0x2, 0x9, 0x1, 0x2, 0x5, 0x1, 0x1, 0x9, 0xa, 0x2, 0x4, 0x20, 0x18, 0x2, 0x1b, 0x1, 0x1, 0x1, 0x1, 0x1, 0xe, 0x1, 0x24, 0x12, 0x1, 0x5, 0x1, 0x2, 0x5, 0x31, 0x8, 0x1, 0x6, 0x1, 0xd, 0x25, 0x2d, 0x4, 0x1, 0x6, 0x1, 0x2, 0x2, 0x2, 0x19, 0x2, 0x4, 0x3, 0x10, 0x4, 0xd, 0x1, 0x2, 0x2, 0x6, 0x1, 0xf, 0x1, 0x28, 0x1, 0x1, 0x5, 0x1, 0x2, 0x81, 0x79, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0x29, 0x1, 0x4, 0x2, 0x21, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0xf, 0x1, 0x39, 0x1, 0x4, 0x2, 0x43, 0x5, 0x1d, 0x3, 0x1a, 0x6, 0x55, 0xb, 0x82, 0x9d, 0x3, 0x51, 0xf, 0xd, 0x1, 0x4, 0xe, 0x12, 0x3, 0x2, 0x9, 0x12, 0xe, 0xd, 0x1, 0x3, 0xf, 0x34, 0x2, 0x1, 0x7, 0x8, 0x1, 0x2, 0xb, 0x9, 0x3, 0xa, 0x6, 0xa, 0x6, 0xb, 0x5, 0xa, 0x6, 0x58, 0x8, 0x29, 0x1, 0x1, 0x5, 0x46, 0xa, 0x1d, 0x6, 0x4, 0x2, 0x3, 0x4, 0x2, 0x1, 0x6, 0x7, 0x1, 0x3, 0x2a, 0x2, 0x5, 0xb, 0x2c, 0x4, 0x1a, 0x6, 0xb, 0x3, 0x39, 0x2, 0x2, 0x3, 0x38, 0x1, 0x1, 0x9, 0x1, 0x1, 0x2, 0x8, 0x6, 0xd, 0xa, 0x6, 0xa, 0x6, 0xe, 0x56, 0x30, 0x1, 0x1, 0x5, 0x1, 0x1, 0x5, 0x1, 0x9, 0x4, 0x1b, 0x9, 0x9, 0x5, 0x20, 0x4, 0x2, 0x2, 0x1, 0x1, 0x3a, 0x1, 0x1, 0x2, 0x3, 0x1, 0x1, 0x3, 0x2, 0x8, 0x30, 0x8, 0x2, 0x5, 0xf, 0x3, 0x33, 0x40, 0x8, 0xb, 0x1, 0xd, 0x1, 0x7, 0x4, 0x1, 0x6, 0x1, 0x2, 0x9, 0x80, 0xc0, 0x40, 0x81, 0x16, 0x2, 0x6, 0x2, 0x26, 0x2, 0x6, 0x2, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1f, 0x2, 0x35, 0x1, 0xf, 0x1, 0xe, 0x2, 0x6, 0x1, 0x13, 0x2, 0x3, 0x1, 0x9, 0x1, 0xb, 0x5, 0x18, 0x7, 0x31, 0x10, 0x2, 0x2, 0x1b, 0x1, 0xd, 0x3, 0x1b, 0x45, 0x80, 0x8a, 0x6, 0x82, 0x64, 0xc, 0x27, 0x19, 0xb, 0x15, 0x82, 0xa0, 0x1, 0x84, 0x4c, 0x3, 0xa, 0x80, 0xa6, 0x2f, 0x1, 0x2f, 0x1, 0x80, 0x8f, 0x3, 0x2, 0x5, 0x2d, 0x1, 0x1, 0x5, 0x1, 0x2, 0x38, 0x7, 0x2, 0xf, 0x17, 0x9, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x21, 0x3c, 0x44, 0x1a, 0x1, 0x59, 0xc, 0x80, 0xd6, 0x1a, 0xc, 0x4, 0x2a, 0x6, 0x10, 0x1, 0x56, 0x4, 0x65, 0x5, 0x29, 0x3, 0x5e, 0x1, 0x2b, 0x5, 0x24, 0xc, 0x2f, 0x1, 0x80, 0xdf, 0x1, 0x9a, 0xb6, 0xa, 0xa0, 0x52, 0xd, 0x33, 0x84, 0x8d, 0x3, 0x37, 0x9, 0x81, 0x5c, 0x14, 0x2f, 0x4, 0x1, 0xa, 0x1a, 0x8, 0x50, 0x2, 0x6, 0x8, 0x80, 0x8f, 0x1, 0x4, 0xc, 0xb, 0x4d, 0xa, 0x1, 0x3, 0x1, 0x4, 0x1, 0x19, 0x2, 0x5, 0x4, 0xa, 0x6, 0x38, 0x8, 0x44, 0xa, 0xc, 0x18, 0xa, 0x4, 0x26, 0x8, 0x19, 0xb, 0x2, 0xb, 0x1e, 0x6, 0x30, 0x1, 0x2, 0x4, 0x2, 0x1, 0x11, 0x1, 0xb, 0x4, 0x2, 0x20, 0x29, 0x6, 0x2, 0x2, 0x2, 0xb, 0x3, 0x1, 0x8, 0x1, 0x1, 0x2, 0xa, 0x2, 0x20, 0x4, 0x30, 0x1, 0x1, 0x3, 0x2, 0x2, 0x5, 0x2, 0x1, 0x1, 0x1, 0x18, 0x11, 0x2, 0x8, 0xb, 0x6, 0x2, 0x6, 0x2, 0x6, 0x9, 0x7, 0x1, 0x7, 0x80, 0x91, 0x25, 0x1, 0x2, 0x1, 0x4, 0x3, 0xa, 0x6, 0xa0, 0x2b, 0xa4, 0xc, 0x17, 0x4, 0x31, 0xa0, 0x21, 0x4, 0x81, 0x6e, 0x2, 0x6a, 0x26, 0x7, 0xc, 0x5, 0x5, 0x1, 0x1, 0x18, 0x1, 0x5, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x7c, 0x11, 0x81, 0x6d, 0x10, 0x40, 0x2, 0x36, 0x28, 0xe, 0x12, 0xa, 0x16, 0x23, 0x1, 0x13, 0x1, 0x4, 0x4, 0x5, 0x1, 0x80, 0x87, 0x4, 0x80, 0x9d, 0x2, 0x1f, 0x3, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x3, 0x3, 0x7, 0x1, 0x7, 0xd, 0x2, 0x2, 0xc, 0x1, 0x1a, 0x1, 0x13, 0x1, 0x2, 0x1, 0xf, 0x2, 0xe, 0x22, 0x7b, 0x5, 0x3, 0x4, 0x2d, 0x3, 0x54, 0x5, 0xc, 0x34, 0x2d, 0x80, 0x83, 0x1d, 0x3, 0x31, 0x2f, 0x1f, 0x1, 0x4, 0xc, 0x1b, 0x35, 0x1e, 0x1, 0x25, 0x4, 0xe, 0x2a, 0x80, 0x9e, 0x2, 0xa, 0x83, 0x56, 0x6, 0x2, 0x1, 0x1, 0x2c, 0x1, 0x2, 0x3, 0x1, 0x2, 0x17, 0x1, 0x9, 0x80, 0xa0, 0x1c, 0x3, 0x1b, 0x5, 0x1, 0x40, 0x38, 0x6, 0x2, 0x40, 0x1, 0xf, 0x4, 0x1, 0x3, 0x1, 0x1b, 0xc, 0x8, 0x8, 0x9, 0x7, 0x20, 0x80, 0x80, 0x36, 0x3, 0x1d, 0x2, 0x1b, 0x5, 0x8, 0x80, 0x80, 0x49, 0x82, 0x17, 0x1f, 0x81, 0x81, 0x1, 0x1, 0x36, 0xf, 0x7, 0x4, 0x1e, 0x12, 0x31, 0x4, 0x2, 0x2, 0x2, 0x1, 0x4, 0xe, 0x19, 0x7, 0xa, 0x9, 0x24, 0x5, 0x1, 0x9, 0xe, 0x3e, 0x34, 0x9, 0xa, 0x7, 0xa, 0x84, 0xa6, 0x2b, 0x1, 0x1, 0x1, 0x2, 0x6, 0x1, 0x9, 0xa, 0x89, 0x36, 0x83, 0x6f, 0x80, 0x91, 0x63, 0xd, 0x4, 0x8b, 0x8c, 0x84, 0x2f, 0xa0, 0x33, 0xd1, 0x82, 0x39, 0x84, 0xc7, 0x45, 0xb, 0x2f, 0x14, 0xd, 0xa0, 0x40, 0x60, 0x2, 0x9f, 0xfe, 0x80, 0xf6, 0xa, 0x27, 0x2, 0x3c, 0x1, 0x1, 0x3, 0x4, 0x15, 0x2, 0x7, 0x1e, 0x4, 0x30, 0x22, 0x42, 0x3, 0x1, 0x80, 0xba, 0x57, 0x9, 0x12, 0x80, 0x8e, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x81, 0x24, 0x2, 0x32, 0x96, 0x0, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x34, 0x2, 0x81, 0xe, 0x2c, 0x4, 0x64, 0xc, 0xf, 0x2, 0xe, 0x2, 0xf, 0x1, 0xf, 0x20, 0xb, 0x5, 0x1f, 0x1, 0x3c, 0x4, 0x2b, 0x4b, 0x1d, 0xd, 0x2b, 0x5, 0x9, 0x7, 0x2, 0x80, 0xae, 0x21, 0xf, 0x6, 0x1, 0x46, 0x3, 0x14, 0xc, 0x25, 0x1, 0x5, 0x15, 0x11, 0xf, 0x3f, 0x1, 0x1, 0x1, 0x80, 0xb6, 0x1, 0x4, 0x3, 0x3e, 0x2, 0x4, 0xc, 0x18, 0x80, 0x93, 0x46, 0x4, 0xb, 0x30, 0x46, 0x3a, 0x74, 0x88, 0x8c, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e]; _T Case_Ignorable = [0x27, 0x1, 0x6, 0x1, 0xb, 0x1, 0x23, 0x1, 0x1, 0x1, 0x47, 0x1, 0x4, 0x1, 0x1, 0x1, 0x4, 0x1, 0x2, 0x2, 0x81, 0xf7, 0x80, 0xc0, 0x4, 0x2, 0x4, 0x1, 0x9, 0x2, 0x1, 0x1, 0x80, 0xfb, 0x7, 0x80, 0xcf, 0x1, 0x37, 0x2d, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x2c, 0x1, 0xb, 0x5, 0xb, 0xb, 0x1, 0x1, 0x23, 0x1, 0xa, 0x15, 0x10, 0x1, 0x65, 0x8, 0x1, 0xa, 0x1, 0x4, 0x21, 0x1, 0x1, 0x1, 0x1e, 0x1b, 0x5b, 0xb, 0x3a, 0xb, 0x4, 0x1, 0x1b, 0x18, 0x2b, 0x3, 0x80, 0x88, 0x1b, 0x1, 0x3, 0x37, 0x1, 0x1, 0x1, 0x4, 0x8, 0x4, 0x1, 0x3, 0x7, 0xa, 0x2, 0xd, 0x1, 0xf, 0x1, 0x3a, 0x1, 0x4, 0x4, 0x8, 0x1, 0x14, 0x2, 0x1d, 0x2, 0x39, 0x1, 0x4, 0x2, 0x4, 0x2, 0x2, 0x3, 0x3, 0x1, 0x1e, 0x2, 0x3, 0x1, 0xb, 0x2, 0x39, 0x1, 0x4, 0x5, 0x1, 0x2, 0x4, 0x1, 0x14, 0x2, 0x1d, 0x1, 0x3a, 0x1, 0x2, 0x1, 0x1, 0x4, 0x8, 0x1, 0x8, 0x1, 0xb, 0x2, 0x1e, 0x1, 0x3d, 0x1, 0xc, 0x1, 0x70, 0x3, 0x5, 0x3, 0x1, 0x4, 0x7, 0x2, 0xb, 0x2, 0x58, 0x1, 0x2, 0x1, 0x6, 0x1, 0x5, 0x2, 0x14, 0x2, 0x5d, 0x4, 0x8, 0x1, 0x14, 0x2, 0x66, 0x1, 0x7, 0x3, 0x1, 0x1, 0x5a, 0x1, 0x2, 0x7, 0xb, 0x9, 0x62, 0x1, 0x2, 0x6, 0x1, 0x2, 0x9, 0x1, 0x1, 0x6, 0x4a, 0x2, 0x1b, 0x1, 0x1, 0x1, 0x1, 0x1, 0x37, 0xe, 0x1, 0x5, 0x1, 0x2, 0x5, 0xb, 0x1, 0x24, 0x9, 0x1, 0x66, 0x4, 0x1, 0x6, 0x1, 0x2, 0x2, 0x2, 0x19, 0x2, 0x4, 0x3, 0x10, 0x4, 0xd, 0x1, 0x2, 0x2, 0x6, 0x1, 0xf, 0x1, 0x5e, 0x1, 0x82, 0x60, 0x3, 0x83, 0xb2, 0x3, 0x1d, 0x3, 0x1d, 0x2, 0x1e, 0x2, 0x40, 0x2, 0x1, 0x7, 0x8, 0x1, 0x2, 0xb, 0x3, 0x1, 0x5, 0x1, 0x2d, 0x4, 0x34, 0x1, 0x65, 0x1, 0x76, 0x3, 0x4, 0x2, 0x9, 0x1, 0x6, 0x3, 0x80, 0xdb, 0x2, 0x2, 0x1, 0x3a, 0x1, 0x1, 0x7, 0x1, 0x1, 0x1, 0x1, 0x2, 0x8, 0x6, 0xa, 0x2, 0x1, 0x27, 0x1, 0x58, 0x4, 0x30, 0x1, 0x1, 0x5, 0x1, 0x1, 0x5, 0x1, 0x28, 0x9, 0xc, 0x2, 0x20, 0x4, 0x2, 0x2, 0x1, 0x1, 0x3a, 0x1, 0x1, 0x2, 0x3, 0x1, 0x1, 0x3, 0x3a, 0x8, 0x2, 0x2, 0x40, 0x6, 0x52, 0x3, 0x1, 0xd, 0x1, 0x7, 0x4, 0x1, 0x6, 0x1, 0x37, 0x3f, 0xd, 0x1, 0x22, 0x4c, 0x15, 0x4, 0x81, 0xbd, 0x1, 0x1, 0x3, 0xb, 0x3, 0xd, 0x3, 0xd, 0x3, 0xd, 0x2, 0xc, 0x5, 0x8, 0x2, 0xa, 0x1, 0x2, 0x1, 0x2, 0x5, 0x31, 0x5, 0x1, 0xa, 0x1, 0x1, 0xd, 0x1, 0x10, 0xd, 0x33, 0x21, 0x8b, 0x8b, 0x2, 0x71, 0x3, 0x7d, 0x1, 0xf, 0x1, 0x60, 0x20, 0x2f, 0x1, 0x81, 0xd5, 0x1, 0x24, 0x4, 0x3, 0x5, 0x5, 0x1, 0x5d, 0x6, 0x5d, 0x3, 0xa0, 0x6f, 0x16, 0x1, 0x84, 0xe2, 0x6, 0x81, 0xe, 0x1, 0x62, 0x4, 0x1, 0xa, 0x1, 0x1, 0x1f, 0x1, 0x50, 0x2, 0xe, 0x22, 0x4e, 0x1, 0x17, 0x3, 0x6d, 0x2, 0x8, 0x1, 0x3, 0x1, 0x4, 0x1, 0x19, 0x2, 0x80, 0x9d, 0x1, 0x1b, 0x12, 0x34, 0x8, 0x19, 0xb, 0x2e, 0x3, 0x30, 0x1, 0x2, 0x4, 0x2, 0x1, 0x12, 0x1, 0x59, 0x6, 0x2, 0x2, 0x2, 0x2, 0xc, 0x1, 0x8, 0x1, 0x23, 0x1, 0x3f, 0x1, 0x1, 0x3, 0x2, 0x2, 0x5, 0x2, 0x1, 0x1, 0x1b, 0x1, 0xe, 0x2, 0x5, 0x2, 0x1, 0x1, 0x80, 0xee, 0x1, 0x2, 0x1, 0x4, 0x1, 0xa0, 0x4f, 0x30, 0x1, 0x80, 0x93, 0x10, 0x82, 0x3e, 0x10, 0x3, 0x1, 0xc, 0x7, 0x2b, 0x1, 0x2, 0x1, 0x80, 0xa9, 0x1, 0x7, 0x1, 0x6, 0x1, 0xb, 0x1, 0x23, 0x1, 0x1, 0x1, 0x2f, 0x1, 0x2d, 0x2, 0x43, 0x1, 0x15, 0x3, 0x82, 0x1, 0x1, 0x88, 0x3, 0x3, 0x1, 0x2, 0x5, 0x4, 0x28, 0x3, 0x4, 0x1, 0x85, 0xc1, 0x1, 0x36, 0xf, 0x39, 0x2, 0x31, 0x4, 0x2, 0x2, 0x2, 0x1, 0x42, 0x3, 0x24, 0x5, 0x1, 0x8, 0x4b, 0x2, 0x34, 0x9, 0x84, 0xec, 0x1, 0x1, 0x1, 0x2, 0x6, 0x1, 0x1, 0xa0, 0x58, 0xd7, 0x11, 0xa0, 0x61, 0xc7, 0x3, 0x9, 0x10, 0x2, 0x7, 0x1e, 0x4, 0x80, 0x94, 0x3, 0xac, 0x2d, 0xbc, 0x1, 0x1e, 0x60, 0x80, 0x80, 0x80, 0xf0]; _T STerm = [0x21, 0x1, 0xc, 0x1, 0x10, 0x1, 0x85, 0x1c, 0x1, 0x1, 0x1, 0x2a, 0x1, 0x80, 0x95, 0x1, 0x80, 0xb4, 0x1, 0x2b, 0x3, 0x80, 0xf6, 0x1, 0x81, 0x6a, 0x2, 0x86, 0xe4, 0x2, 0x83, 0x16, 0x1, 0x4, 0x2, 0x83, 0x5, 0x1, 0x80, 0xc6, 0x2, 0x80, 0xcc, 0x1, 0x5, 0x1, 0x81, 0x3a, 0x2, 0x81, 0x62, 0x4, 0x80, 0xae, 0x2, 0x2, 0x2, 0x80, 0xdb, 0x2, 0x41, 0x2, 0x83, 0xbc, 0x2, 0x9, 0x3, 0x8d, 0xe4, 0x1, 0x81, 0xd3, 0x1, 0xa0, 0x74, 0xfc, 0x1, 0x81, 0xe, 0x2, 0x80, 0xe3, 0x1, 0x3, 0x1, 0x81, 0x7e, 0x2, 0x56, 0x2, 0x5f, 0x1, 0x80, 0x98, 0x2, 0x80, 0x93, 0x3, 0x80, 0x90, 0x2, 0x80, 0xf9, 0x1, 0xa0, 0x52, 0x66, 0x1, 0x3, 0x2, 0x80, 0xa9, 0x1, 0xc, 0x1, 0x10, 0x1, 0x41, 0x1, 0x8a, 0xf4, 0x2, 0x85, 0xef, 0x2, 0x75, 0x4, 0x7f, 0x3, 0x80, 0x81, 0x2]; _T Diacritic = [0x5e, 0x1, 0x1, 0x1, 0x47, 0x1, 0x6, 0x1, 0x4, 0x1, 0x2, 0x2, 0x81, 0xf7, 0x80, 0x9f, 0x1, 0x8, 0x5, 0x6, 0x11, 0x2, 0x4, 0x1, 0x9, 0x2, 0x80, 0xfd, 0x5, 0x80, 0xd1, 0x1, 0x37, 0x11, 0x1, 0x1b, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x80, 0x86, 0x8, 0x4, 0x2, 0x80, 0x86, 0x2, 0x4, 0x2, 0x3, 0x3, 0x43, 0x1b, 0x5b, 0xb, 0x3a, 0xb, 0x22, 0x2, 0x80, 0xca, 0x1b, 0x3d, 0x1, 0x10, 0x1, 0x3, 0x4, 0x1c, 0x1, 0x4a, 0x1, 0x10, 0x1, 0x6e, 0x1, 0x10, 0x1, 0x6e, 0x1, 0x10, 0x1, 0x6e, 0x1, 0x10, 0x1, 0x7f, 0x1, 0x7f, 0x1, 0x6e, 0x1, 0x10, 0x1, 0x7f, 0x1, 0x7c, 0x1, 0x7c, 0x6, 0x1, 0x1, 0x79, 0x5, 0x4b, 0x2, 0x1b, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x2, 0x42, 0x3, 0x1, 0x2, 0x3e, 0x1, 0x70, 0x1, 0x1, 0x2, 0x4c, 0x7, 0x1, 0x1, 0xa, 0x2, 0x87, 0x2d, 0xb, 0x9, 0x1, 0x81, 0x5b, 0x3, 0x81, 0x39, 0x8, 0x2, 0x1, 0x80, 0xb4, 0x1, 0xf, 0x1, 0x26, 0x9, 0x36, 0x2, 0x80, 0x8a, 0x2, 0x40, 0x6, 0x52, 0x19, 0x4, 0x1, 0x6, 0x1, 0x37, 0x3f, 0x59, 0xc, 0x2d, 0x3, 0x81, 0xbd, 0x1, 0x1, 0x3, 0xb, 0x3, 0xd, 0x3, 0xd, 0x3, 0xd, 0x2, 0x8c, 0xf0, 0x3, 0x81, 0x3d, 0x1, 0x81, 0xfa, 0x6, 0x69, 0x4, 0x5f, 0x1, 0xa0, 0x75, 0x72, 0x1, 0xc, 0x2, 0x1, 0x1, 0x70, 0x2, 0x25, 0xb, 0x66, 0x1, 0x6f, 0x2, 0x80, 0xca, 0x1, 0x1b, 0x12, 0x39, 0x4, 0x24, 0x1, 0x5f, 0x1, 0xc, 0x1, 0x80, 0xba, 0x1, 0x43, 0x4, 0x33, 0x1, 0x80, 0xf5, 0x2, 0xa0, 0x4f, 0x30, 0x1, 0x83, 0x1, 0x7, 0x81, 0x17, 0x1, 0x1, 0x1, 0x2f, 0x1, 0x2d, 0x2, 0x43, 0x1, 0x90, 0xd5, 0x2, 0x78, 0x2, 0x80, 0x8b, 0x1, 0x84, 0xf5, 0x2, 0xa0, 0x58, 0xd7, 0x11, 0xa0, 0x61, 0xc7, 0x3, 0x3, 0x6, 0x8, 0x8, 0x2, 0x7, 0x1e, 0x4]; _T Lm = [0x82, 0xb0, 0x12, 0x4, 0xc, 0xe, 0x5, 0x7, 0x1, 0x1, 0x1, 0x80, 0x85, 0x1, 0x5, 0x1, 0x81, 0xde, 0x1, 0x80, 0xe6, 0x1, 0x80, 0xa4, 0x2, 0x81, 0xd, 0x2, 0x4, 0x1, 0x1f, 0x1, 0x9, 0x1, 0x3, 0x1, 0x81, 0x48, 0x1, 0x84, 0xd4, 0x1, 0x7f, 0x1, 0x82, 0x35, 0x1, 0x86, 0xda, 0x1, 0x6b, 0x1, 0x82, 0x63, 0x1, 0x81, 0xd0, 0x6, 0x80, 0xae, 0x3f, 0xd, 0x1, 0x22, 0x25, 0x82, 0xb1, 0x1, 0xd, 0x1, 0x10, 0xd, 0x8b, 0xdf, 0x2, 0x80, 0xf1, 0x1, 0x80, 0xbf, 0x1, 0x81, 0xd5, 0x1, 0x2b, 0x5, 0x5, 0x1, 0x61, 0x2, 0x5d, 0x3, 0xa0, 0x6f, 0x16, 0x1, 0x84, 0xe2, 0x6, 0x81, 0xe, 0x1, 0x72, 0x1, 0x80, 0x97, 0x9, 0x50, 0x1, 0x17, 0x1, 0x6f, 0x2, 0x81, 0xd5, 0x1, 0x80, 0xa0, 0x1, 0x6c, 0x1, 0x15, 0x2, 0xa0, 0x54, 0x7b, 0x1, 0x2d, 0x2, 0xa0, 0x6f, 0xf3, 0xd]; _T Mc = [0x89, 0x3, 0x1, 0x37, 0x1, 0x2, 0x3, 0x8, 0x4, 0x1, 0x2, 0x32, 0x2, 0x3a, 0x3, 0x6, 0x2, 0x2, 0x2, 0xa, 0x1, 0x2b, 0x1, 0x3a, 0x3, 0x42, 0x1, 0x3a, 0x3, 0x8, 0x1, 0x1, 0x2, 0x35, 0x2, 0x3a, 0x1, 0x1, 0x1, 0x6, 0x2, 0x2, 0x2, 0xa, 0x1, 0x66, 0x2, 0x1, 0x2, 0x3, 0x3, 0x1, 0x3, 0xa, 0x1, 0x29, 0x3, 0x3d, 0x4, 0x3d, 0x2, 0x3a, 0x1, 0x1, 0x5, 0x2, 0x2, 0x1, 0x2, 0x9, 0x2, 0x2b, 0x2, 0x3a, 0x3, 0x5, 0x3, 0x1, 0x3, 0xa, 0x1, 0x2a, 0x2, 0x4b, 0x3, 0x6, 0x8, 0x12, 0x2, 0x81, 0x4a, 0x2, 0x3f, 0x1, 0x80, 0xab, 0x2, 0x4, 0x1, 0x6, 0x1, 0x2, 0x2, 0x19, 0x2, 0xa, 0x3, 0x2, 0x7, 0x15, 0x2, 0x2, 0x6, 0x2, 0x1, 0xa, 0x3, 0x87, 0x19, 0x1, 0x7, 0x8, 0x1, 0x2, 0x81, 0x5a, 0x4, 0x2, 0x3, 0x4, 0x2, 0x1, 0x6, 0x77, 0x11, 0x7, 0x2, 0x4f, 0x2, 0x3a, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x2, 0x8, 0x6, 0x80, 0x91, 0x1, 0x30, 0x1, 0x5, 0x1, 0x1, 0x5, 0x1, 0x2, 0x3d, 0x1, 0x1e, 0x1, 0x4, 0x2, 0x2, 0x1, 0x1, 0x2, 0x39, 0x1, 0x2, 0x3, 0x1, 0x1, 0x3, 0x2, 0x30, 0x8, 0x8, 0x2, 0x80, 0xab, 0x1, 0x10, 0x2, 0x93, 0x3a, 0x2, 0xa0, 0x77, 0xf3, 0x2, 0x2, 0x1, 0x58, 0x2, 0x32, 0x10, 0x80, 0x8e, 0x2, 0x2f, 0x1, 0x30, 0x2, 0x4, 0x2, 0x1, 0x4, 0x6e, 0x2, 0x2, 0x2, 0x18, 0x1, 0x2d, 0x1, 0x6f, 0x1, 0x2, 0x2, 0x5, 0x1, 0x80, 0xed, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0xa0, 0x64, 0x13, 0x1, 0x1, 0x1, 0x7f, 0x1, 0x2d, 0x3, 0x4, 0x2, 0x73, 0x1, 0x55, 0x1, 0x30, 0x3, 0x9, 0x2, 0x84, 0xeb, 0x1, 0x1, 0x2, 0x6, 0x1, 0xa0, 0x58, 0x9a, 0x2e, 0xa0, 0x61, 0xe6, 0x2, 0x6, 0x6]; _T Lo = [0x80, 0xaa, 0x1, 0xf, 0x1, 0x81, 0x0, 0x1, 0x4, 0x4, 0x80, 0xd0, 0x1, 0x83, 0x3b, 0x1b, 0x5, 0x3, 0x2d, 0x20, 0x1, 0xa, 0x23, 0x2, 0x1, 0x63, 0x1, 0x1, 0x18, 0x2, 0xa, 0x3, 0x2, 0x1, 0x10, 0x1, 0x1, 0x1e, 0x1d, 0x59, 0xb, 0x1, 0x18, 0x21, 0x15, 0x16, 0x2a, 0x19, 0x47, 0x1, 0x1, 0xb, 0x57, 0x36, 0x3, 0x1, 0x12, 0x1, 0x7, 0xa, 0x10, 0x6, 0x1, 0x7, 0x5, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x1, 0x3, 0x4, 0x3, 0x1, 0x10, 0x1, 0xd, 0x2, 0x1, 0x3, 0xe, 0x2, 0x13, 0x6, 0x4, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1f, 0x4, 0x1, 0x1, 0x13, 0x3, 0x10, 0x9, 0x1, 0x3, 0x1, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x1, 0x12, 0x1, 0xf, 0x2, 0x23, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x1, 0x1e, 0x2, 0x1, 0x3, 0xf, 0x1, 0x11, 0x1, 0x1, 0x6, 0x3, 0x3, 0x1, 0x4, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0xc, 0x16, 0x1, 0x34, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x1, 0x1a, 0x2, 0x6, 0x2, 0x23, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x1, 0x20, 0x1, 0x1, 0x2, 0xf, 0x2, 0x12, 0x8, 0x1, 0x3, 0x1, 0x29, 0x2, 0x1, 0x10, 0x1, 0x11, 0x2, 0x18, 0x6, 0x5, 0x12, 0x3, 0x18, 0x1, 0x9, 0x1, 0x1, 0x2, 0x7, 0x3a, 0x30, 0x1, 0x2, 0xc, 0x6, 0x3b, 0x2, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x6, 0x4, 0x1, 0x7, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0x4, 0x1, 0x2, 0x9, 0x1, 0x2, 0x5, 0x17, 0x4, 0x20, 0x1, 0x3f, 0x8, 0x1, 0x24, 0x1b, 0x5, 0x73, 0x2b, 0x14, 0x1, 0x10, 0x6, 0x4, 0x4, 0x3, 0x1, 0x3, 0x2, 0x7, 0x3, 0x4, 0xd, 0xc, 0x1, 0x41, 0x2b, 0x2, 0x81, 0x4c, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0x29, 0x1, 0x4, 0x2, 0x21, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0xf, 0x1, 0x39, 0x1, 0x4, 0x2, 0x43, 0x25, 0x10, 0x10, 0x55, 0xc, 0x82, 0x6c, 0x2, 0x11, 0x1, 0x1a, 0x5, 0x4b, 0x15, 0xd, 0x1, 0x4, 0xe, 0x12, 0xe, 0x12, 0xe, 0xd, 0x1, 0x3, 0xf, 0x34, 0x28, 0x1, 0x43, 0x23, 0x1, 0x34, 0x8, 0x29, 0x1, 0x1, 0x5, 0x46, 0xa, 0x1d, 0x33, 0x1e, 0x2, 0x5, 0xb, 0x2c, 0x15, 0x7, 0x38, 0x17, 0x9, 0x35, 0x80, 0xb0, 0x2f, 0x11, 0x7, 0x37, 0x1e, 0xd, 0x2, 0xa, 0x2c, 0x1a, 0x24, 0x29, 0x3, 0xa, 0x1e, 0x71, 0x4, 0x1, 0x4, 0x3, 0x2, 0x84, 0x3e, 0x4, 0x8b, 0xf7, 0x38, 0x18, 0x17, 0x9, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x82, 0x27, 0x1, 0x35, 0x1, 0x4, 0x56, 0x8, 0x1, 0x1, 0x5a, 0x4, 0x1, 0x5, 0x29, 0x3, 0x5e, 0x11, 0x1b, 0x35, 0x10, 0x82, 0x0, 0x99, 0xb6, 0x4a, 0xa0, 0x51, 0xcd, 0x33, 0x15, 0x1, 0x84, 0x77, 0x43, 0x28, 0x8, 0x81, 0xc, 0x4, 0x10, 0xa, 0x2, 0x42, 0x1, 0x31, 0x46, 0x81, 0x15, 0x7, 0x1, 0x3, 0x1, 0x4, 0x1, 0x17, 0x1d, 0x34, 0xe, 0x32, 0x3e, 0x6, 0x3, 0x1, 0xe, 0x1c, 0xa, 0x17, 0x19, 0x1d, 0x7, 0x2f, 0x4d, 0x29, 0x17, 0x3, 0x1, 0x8, 0x14, 0x10, 0x1, 0x6, 0x3, 0x1, 0x5, 0x30, 0x1, 0x1, 0x3, 0x2, 0x2, 0x5, 0x2, 0x1, 0x1, 0x1, 0x18, 0x2, 0x3, 0xb, 0x7, 0x1, 0xe, 0x6, 0x2, 0x6, 0x2, 0x6, 0x9, 0x7, 0x1, 0x7, 0x80, 0x91, 0x23, 0x1d, 0xa0, 0x2b, 0xa4, 0xc, 0x17, 0x4, 0x31, 0xa0, 0x21, 0x4, 0x81, 0x6e, 0x2, 0x6a, 0x43, 0x1, 0x1, 0xa, 0x1, 0xd, 0x1, 0x5, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x6c, 0x21, 0x81, 0x6b, 0x12, 0x40, 0x2, 0x36, 0x28, 0xc, 0x74, 0x5, 0x1, 0x80, 0x87, 0x69, 0xa, 0x1, 0x2d, 0x2, 0x1f, 0x3, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x3, 0x23, 0xc, 0x1, 0x1a, 0x1, 0x13, 0x1, 0x2, 0x1, 0xf, 0x2, 0xe, 0x22, 0x7b, 0x81, 0x85, 0x1d, 0x3, 0x31, 0x2f, 0x1f, 0x11, 0x11, 0x1, 0x8, 0x36, 0x1e, 0x2, 0x24, 0x4, 0x8, 0x80, 0x80, 0x4e, 0x83, 0x62, 0x6, 0x2, 0x1, 0x1, 0x2c, 0x1, 0x2, 0x3, 0x1, 0x2, 0x17, 0x80, 0xaa, 0x16, 0xa, 0x1a, 0x46, 0x38, 0x6, 0x2, 0x40, 0x1, 0xf, 0x4, 0x1, 0x3, 0x1, 0x1b, 0x2c, 0x1d, 0x80, 0x83, 0x36, 0xa, 0x16, 0xa, 0x13, 0x80, 0x8d, 0x49, 0x83, 0xba, 0x35, 0x4b, 0x2d, 0x20, 0x19, 0x1a, 0x24, 0x5c, 0x30, 0xe, 0x4, 0x84, 0xbb, 0x2b, 0x89, 0x55, 0x83, 0x6f, 0x8c, 0x91, 0x84, 0x2f, 0xa0, 0x33, 0xd1, 0x82, 0x39, 0x84, 0xc7, 0x45, 0xb, 0x1, 0xa0, 0x40, 0xaf, 0x2, 0xa0, 0x3d, 0xfe, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x91, 0x44, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e]; _T Me = [0x84, 0x88, 0x2, 0x9c, 0x53, 0x4, 0x1, 0x3, 0xa0, 0x85, 0x8b, 0x3]; _T ID_Start = [0x41, 0x1a, 0x6, 0x1a, 0x2f, 0x1, 0xa, 0x1, 0x4, 0x1, 0x5, 0x17, 0x1, 0x1f, 0x1, 0x81, 0xca, 0x4, 0xc, 0xe, 0x5, 0x7, 0x1, 0x1, 0x1, 0x80, 0x81, 0x5, 0x1, 0x2, 0x2, 0x4, 0x8, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x14, 0x1, 0x53, 0x1, 0x80, 0x8b, 0x8, 0x80, 0x9e, 0x9, 0x26, 0x2, 0x1, 0x7, 0x27, 0x48, 0x1b, 0x5, 0x3, 0x2d, 0x2b, 0x23, 0x2, 0x1, 0x63, 0x1, 0x1, 0xf, 0x2, 0x7, 0x2, 0xa, 0x3, 0x2, 0x1, 0x10, 0x1, 0x1, 0x1e, 0x1d, 0x59, 0xb, 0x1, 0x18, 0x21, 0x9, 0x2, 0x4, 0x1, 0x5, 0x16, 0x4, 0x1, 0x9, 0x1, 0x3, 0x1, 0x17, 0x19, 0x47, 0x1, 0x1, 0xb, 0x57, 0x36, 0x3, 0x1, 0x12, 0x1, 0x7, 0xa, 0xf, 0x7, 0x1, 0x7, 0x5, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x1, 0x3, 0x4, 0x3, 0x1, 0x10, 0x1, 0xd, 0x2, 0x1, 0x3, 0xe, 0x2, 0x13, 0x6, 0x4, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1f, 0x4, 0x1, 0x1, 0x13, 0x3, 0x10, 0x9, 0x1, 0x3, 0x1, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x1, 0x12, 0x1, 0xf, 0x2, 0x23, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x3, 0x1, 0x1e, 0x2, 0x1, 0x3, 0xf, 0x1, 0x11, 0x1, 0x1, 0x6, 0x3, 0x3, 0x1, 0x4, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0xc, 0x16, 0x1, 0x34, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x1, 0x1a, 0x2, 0x6, 0x2, 0x23, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x1, 0x20, 0x1, 0x1, 0x2, 0xf, 0x2, 0x12, 0x8, 0x1, 0x3, 0x1, 0x29, 0x2, 0x1, 0x10, 0x1, 0x11, 0x2, 0x18, 0x6, 0x5, 0x12, 0x3, 0x18, 0x1, 0x9, 0x1, 0x1, 0x2, 0x7, 0x3a, 0x30, 0x1, 0x2, 0xc, 0x7, 0x3a, 0x2, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x6, 0x4, 0x1, 0x7, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0x4, 0x1, 0x2, 0x9, 0x1, 0x2, 0x5, 0x1, 0x1, 0x15, 0x4, 0x20, 0x1, 0x3f, 0x8, 0x1, 0x24, 0x1b, 0x5, 0x73, 0x2b, 0x14, 0x1, 0x10, 0x6, 0x4, 0x4, 0x3, 0x1, 0x3, 0x2, 0x7, 0x3, 0x4, 0xd, 0xc, 0x1, 0x11, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x2b, 0x1, 0x81, 0x4d, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0x29, 0x1, 0x4, 0x2, 0x21, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0xf, 0x1, 0x39, 0x1, 0x4, 0x2, 0x43, 0x25, 0x10, 0x10, 0x55, 0xc, 0x82, 0x6c, 0x2, 0x11, 0x1, 0x1a, 0x5, 0x4b, 0x3, 0x3, 0xf, 0xd, 0x1, 0x4, 0xe, 0x12, 0xe, 0x12, 0xe, 0xd, 0x1, 0x3, 0xf, 0x34, 0x23, 0x1, 0x4, 0x1, 0x43, 0x58, 0x8, 0x29, 0x1, 0x1, 0x5, 0x46, 0xa, 0x1d, 0x33, 0x1e, 0x2, 0x5, 0xb, 0x2c, 0x15, 0x7, 0x38, 0x17, 0x9, 0x35, 0x52, 0x1, 0x5d, 0x2f, 0x11, 0x7, 0x37, 0x1e, 0xd, 0x2, 0xa, 0x2c, 0x1a, 0x24, 0x29, 0x3, 0xa, 0x24, 0x6b, 0x4, 0x1, 0x4, 0x3, 0x2, 0x9, 0x80, 0xc0, 0x40, 0x81, 0x16, 0x2, 0x6, 0x2, 0x26, 0x2, 0x6, 0x2, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1f, 0x2, 0x35, 0x1, 0x7, 0x1, 0x1, 0x3, 0x3, 0x1, 0x7, 0x3, 0x4, 0x2, 0x6, 0x4, 0xd, 0x5, 0x3, 0x1, 0x7, 0x74, 0x1, 0xd, 0x1, 0x10, 0xd, 0x65, 0x1, 0x4, 0x1, 0x2, 0xa, 0x1, 0x1, 0x2, 0x6, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x10, 0x2, 0x4, 0x5, 0x5, 0x4, 0x1, 0x11, 0x29, 0x8a, 0x77, 0x2f, 0x1, 0x2f, 0x1, 0x80, 0x85, 0x6, 0x4, 0x3, 0x2, 0xc, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x38, 0x7, 0x1, 0x10, 0x17, 0x9, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x82, 0x26, 0x3, 0x19, 0x9, 0x7, 0x5, 0x2, 0x5, 0x4, 0x56, 0x4, 0x5, 0x1, 0x5a, 0x1, 0x4, 0x5, 0x29, 0x3, 0x5e, 0x11, 0x1b, 0x35, 0x10, 0x82, 0x0, 0x99, 0xb6, 0x4a, 0xa0, 0x51, 0xcd, 0x33, 0x84, 0x8d, 0x43, 0x2e, 0x2, 0x81, 0xd, 0x3, 0x10, 0xa, 0x2, 0x14, 0x2f, 0x10, 0x19, 0x8, 0x50, 0x27, 0x9, 0x2, 0x67, 0x2, 0x4, 0x1, 0x4, 0xc, 0xb, 0x4d, 0xa, 0x1, 0x3, 0x1, 0x4, 0x1, 0x17, 0x1d, 0x34, 0xe, 0x32, 0x3e, 0x6, 0x3, 0x1, 0xe, 0x1c, 0xa, 0x17, 0x19, 0x1d, 0x7, 0x2f, 0x1c, 0x1, 0x30, 0x29, 0x17, 0x3, 0x1, 0x8, 0x14, 0x17, 0x3, 0x1, 0x5, 0x30, 0x1, 0x1, 0x3, 0x2, 0x2, 0x5, 0x2, 0x1, 0x1, 0x1, 0x18, 0x3, 0x2, 0xb, 0x7, 0x3, 0xc, 0x6, 0x2, 0x6, 0x2, 0x6, 0x9, 0x7, 0x1, 0x7, 0x80, 0x91, 0x23, 0x1d, 0xa0, 0x2b, 0xa4, 0xc, 0x17, 0x4, 0x31, 0xa0, 0x21, 0x4, 0x81, 0x6e, 0x2, 0x6a, 0x26, 0x7, 0xc, 0x5, 0x5, 0x1, 0x1, 0xa, 0x1, 0xd, 0x1, 0x5, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x6c, 0x21, 0x81, 0x6b, 0x12, 0x40, 0x2, 0x36, 0x28, 0xc, 0x74, 0x5, 0x1, 0x80, 0x87, 0x24, 0x1a, 0x6, 0x1a, 0xb, 0x59, 0x3, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x3, 0x23, 0xc, 0x1, 0x1a, 0x1, 0x13, 0x1, 0x2, 0x1, 0xf, 0x2, 0xe, 0x22, 0x7b, 0x45, 0x35, 0x81, 0xb, 0x1d, 0x3, 0x31, 0x2f, 0x1f, 0x11, 0x1b, 0x35, 0x1e, 0x2, 0x24, 0x4, 0x8, 0x1, 0x5, 0x2a, 0x80, 0x9e, 0x83, 0x62, 0x6, 0x2, 0x1, 0x1, 0x2c, 0x1, 0x2, 0x3, 0x1, 0x2, 0x17, 0x80, 0xaa, 0x16, 0xa, 0x1a, 0x46, 0x38, 0x6, 0x2, 0x40, 0x1, 0xf, 0x4, 0x1, 0x3, 0x1, 0x1b, 0x2c, 0x1d, 0x80, 0x83, 0x36, 0xa, 0x16, 0xa, 0x13, 0x80, 0x8d, 0x49, 0x83, 0xba, 0x35, 0x4b, 0x2d, 0x20, 0x19, 0x1a, 0x24, 0x5c, 0x30, 0xe, 0x4, 0x84, 0xbb, 0x2b, 0x89, 0x55, 0x83, 0x6f, 0x80, 0x91, 0x63, 0x8b, 0x9d, 0x84, 0x2f, 0xa0, 0x33, 0xd1, 0x82, 0x39, 0x84, 0xc7, 0x45, 0xb, 0x1, 0x42, 0xd, 0xa0, 0x40, 0x60, 0x2, 0xa0, 0x23, 0xfe, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x19, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x8, 0x96, 0x34, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x91, 0x44, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e]; _T Other_Grapheme_Extend = [0x89, 0xbe, 0x1, 0x18, 0x1, 0x81, 0x66, 0x1, 0x18, 0x1, 0x66, 0x1, 0x18, 0x1, 0x80, 0xea, 0x1, 0x12, 0x2, 0x67, 0x1, 0x18, 0x1, 0x77, 0x1, 0xf, 0x1, 0x92, 0x2c, 0x2, 0x90, 0x20, 0x2, 0xa0, 0xcf, 0x6e, 0x2, 0xa0, 0xd1, 0xc5, 0x1, 0x8, 0x5]; _T Lt = [0x81, 0xc5, 0x1, 0x2, 0x1, 0x2, 0x1, 0x26, 0x1, 0x9d, 0x95, 0x8, 0x8, 0x8, 0x8, 0x8, 0xc, 0x1, 0xf, 0x1, 0x2f, 0x1]; _T Pattern_White_Space = [0x9, 0x5, 0x12, 0x1, 0x64, 0x1, 0x9f, 0x88, 0x2, 0x18, 0x2]; _T Cased = [0x41, 0x1a, 0x6, 0x1a, 0x2f, 0x1, 0xa, 0x1, 0x4, 0x1, 0x5, 0x17, 0x1, 0x1f, 0x1, 0x80, 0xc3, 0x1, 0x4, 0x4, 0x80, 0xd0, 0x1, 0x24, 0x7, 0x2, 0x1e, 0x5, 0x60, 0x1, 0x2a, 0x4, 0x2, 0x2, 0x2, 0x4, 0x8, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x14, 0x1, 0x53, 0x1, 0x80, 0x8b, 0x8, 0x80, 0x9e, 0x9, 0x26, 0xa, 0x27, 0x8b, 0x18, 0x26, 0x1, 0x1, 0x5, 0x1, 0x8c, 0x32, 0x80, 0xc0, 0x40, 0x81, 0x16, 0x2, 0x6, 0x2, 0x26, 0x2, 0x6, 0x2, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1f, 0x2, 0x35, 0x1, 0x7, 0x1, 0x1, 0x3, 0x3, 0x1, 0x7, 0x3, 0x4, 0x2, 0x6, 0x4, 0xd, 0x5, 0x3, 0x1, 0x7, 0x74, 0x1, 0xd, 0x1, 0x10, 0xd, 0x65, 0x1, 0x4, 0x1, 0x2, 0xa, 0x1, 0x1, 0x3, 0x5, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0x6, 0x4, 0x1, 0x2, 0x4, 0x5, 0x5, 0x4, 0x1, 0x11, 0x20, 0x3, 0x2, 0x83, 0x31, 0x34, 0x87, 0x16, 0x2f, 0x1, 0x2f, 0x1, 0x80, 0x85, 0x6, 0x4, 0x3, 0x2, 0xc, 0x26, 0x1, 0x1, 0x5, 0x1, 0xa0, 0x79, 0x12, 0x2e, 0x12, 0x18, 0x80, 0x8a, 0x66, 0x3, 0x4, 0x1, 0x4, 0xc, 0xb, 0x4d, 0x3, 0xa0, 0x53, 0x5, 0x7, 0xc, 0x5, 0x84, 0x9, 0x1a, 0x6, 0x1a, 0x84, 0xa5, 0x50, 0xa0, 0xcf, 0xb0, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x19, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x8]; _T Mn = [0x83, 0x0, 0x70, 0x81, 0x13, 0x5, 0x81, 0x9, 0x2d, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x48, 0xb, 0x30, 0x15, 0x10, 0x1, 0x65, 0x7, 0x2, 0x6, 0x2, 0x2, 0x1, 0x4, 0x23, 0x1, 0x1e, 0x1b, 0x5b, 0xb, 0x3a, 0x9, 0x22, 0x4, 0x1, 0x9, 0x1, 0x3, 0x1, 0x5, 0x2b, 0x3, 0x80, 0x88, 0x1b, 0x1, 0x3, 0x37, 0x1, 0x1, 0x1, 0x4, 0x8, 0x4, 0x1, 0x3, 0x7, 0xa, 0x2, 0x1d, 0x1, 0x3a, 0x1, 0x4, 0x4, 0x8, 0x1, 0x14, 0x2, 0x1d, 0x2, 0x39, 0x1, 0x4, 0x2, 0x4, 0x2, 0x2, 0x3, 0x3, 0x1, 0x1e, 0x2, 0x3, 0x1, 0xb, 0x2, 0x39, 0x1, 0x4, 0x5, 0x1, 0x2, 0x4, 0x1, 0x14, 0x2, 0x1d, 0x1, 0x3a, 0x1, 0x2, 0x1, 0x1, 0x4, 0x8, 0x1, 0x8, 0x1, 0xb, 0x2, 0x1e, 0x1, 0x3d, 0x1, 0xc, 0x1, 0x70, 0x3, 0x5, 0x3, 0x1, 0x4, 0x7, 0x2, 0xb, 0x2, 0x58, 0x1, 0x2, 0x1, 0x6, 0x1, 0x5, 0x2, 0x14, 0x2, 0x5d, 0x4, 0x8, 0x1, 0x14, 0x2, 0x66, 0x1, 0x7, 0x3, 0x1, 0x1, 0x5a, 0x1, 0x2, 0x7, 0xc, 0x8, 0x62, 0x1, 0x2, 0x6, 0x1, 0x2, 0xb, 0x6, 0x4a, 0x2, 0x1b, 0x1, 0x1, 0x1, 0x1, 0x1, 0x37, 0xe, 0x1, 0x5, 0x1, 0x2, 0x5, 0xb, 0x1, 0x24, 0x9, 0x1, 0x66, 0x4, 0x1, 0x6, 0x1, 0x2, 0x2, 0x2, 0x19, 0x2, 0x4, 0x3, 0x10, 0x4, 0xd, 0x1, 0x2, 0x2, 0x6, 0x1, 0xf, 0x1, 0x82, 0xbf, 0x3, 0x83, 0xb2, 0x3, 0x1d, 0x3, 0x1d, 0x2, 0x1e, 0x2, 0x40, 0x2, 0x1, 0x7, 0x8, 0x1, 0x2, 0xb, 0x9, 0x1, 0x2d, 0x3, 0x80, 0x9b, 0x1, 0x76, 0x3, 0x4, 0x2, 0x9, 0x1, 0x6, 0x3, 0x80, 0xdb, 0x2, 0x2, 0x1, 0x3a, 0x1, 0x1, 0x7, 0x1, 0x1, 0x1, 0x1, 0x2, 0x8, 0x6, 0xa, 0x2, 0x1, 0x80, 0x80, 0x4, 0x30, 0x1, 0x1, 0x5, 0x1, 0x1, 0x5, 0x1, 0x28, 0x9, 0xc, 0x2, 0x20, 0x4, 0x2, 0x2, 0x1, 0x1, 0x3a, 0x1, 0x1, 0x2, 0x3, 0x1, 0x1, 0x3, 0x3a, 0x8, 0x2, 0x2, 0x80, 0x98, 0x3, 0x1, 0xd, 0x1, 0x7, 0x4, 0x1, 0x6, 0x1, 0x80, 0xcb, 0x27, 0x15, 0x4, 0x82, 0xd0, 0xd, 0x4, 0x1, 0x3, 0xc, 0x8b, 0xfe, 0x3, 0x80, 0x8d, 0x1, 0x60, 0x20, 0x82, 0x2a, 0x4, 0x6b, 0x2, 0xa0, 0x75, 0xd4, 0x1, 0x4, 0xa, 0x21, 0x1, 0x50, 0x2, 0x81, 0x10, 0x1, 0x3, 0x1, 0x4, 0x1, 0x19, 0x2, 0x80, 0x9d, 0x1, 0x1b, 0x12, 0x34, 0x8, 0x19, 0xb, 0x2e, 0x3, 0x30, 0x1, 0x2, 0x4, 0x2, 0x1, 0x6c, 0x6, 0x2, 0x2, 0x2, 0x2, 0xc, 0x1, 0x8, 0x1, 0x63, 0x1, 0x1, 0x3, 0x2, 0x2, 0x5, 0x2, 0x1, 0x1, 0x2a, 0x2, 0x8, 0x1, 0x80, 0xee, 0x1, 0x2, 0x1, 0x4, 0x1, 0xa0, 0x4f, 0x30, 0x1, 0x82, 0xe1, 0x10, 0x10, 0x7, 0x83, 0xd6, 0x1, 0x88, 0x3, 0x3, 0x1, 0x2, 0x5, 0x4, 0x28, 0x3, 0x4, 0x1, 0x85, 0xc1, 0x1, 0x36, 0xf, 0x39, 0x2, 0x31, 0x4, 0x2, 0x2, 0x45, 0x3, 0x24, 0x5, 0x1, 0x8, 0x4b, 0x2, 0x34, 0x9, 0x84, 0xec, 0x1, 0x1, 0x1, 0x2, 0x6, 0x1, 0x1, 0xa0, 0x58, 0xd7, 0x4, 0xa0, 0x61, 0xd4, 0x3, 0x11, 0x8, 0x2, 0x7, 0x1e, 0x4, 0x80, 0x94, 0x3, 0xac, 0x2e, 0xbb, 0x80, 0xf0]; _T Dash = [0x2d, 0x1, 0x85, 0x5c, 0x1, 0x33, 0x1, 0x8e, 0x41, 0x1, 0x84, 0x5, 0x1, 0x88, 0x9, 0x6, 0x3d, 0x1, 0x27, 0x1, 0xf, 0x1, 0x81, 0x86, 0x1, 0x8c, 0x4, 0x1, 0x2, 0x1, 0x1f, 0x2, 0x81, 0xe0, 0x1, 0x13, 0x1, 0x6f, 0x1, 0xa0, 0xcd, 0x90, 0x2, 0x25, 0x1, 0xa, 0x1, 0x80, 0xa9, 0x1]; _T ID_Continue = [0x30, 0xa, 0x7, 0x1a, 0x4, 0x1, 0x1, 0x1a, 0x2f, 0x1, 0xa, 0x1, 0x1, 0x1, 0x2, 0x1, 0x5, 0x17, 0x1, 0x1f, 0x1, 0x81, 0xca, 0x4, 0xc, 0xe, 0x5, 0x7, 0x1, 0x1, 0x1, 0x11, 0x75, 0x1, 0x2, 0x2, 0x4, 0x8, 0x5, 0x1, 0x1, 0x1, 0x14, 0x1, 0x53, 0x1, 0x80, 0x8b, 0x1, 0x5, 0x2, 0x80, 0x9e, 0x9, 0x26, 0x2, 0x1, 0x7, 0x27, 0x9, 0x2d, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x8, 0x1b, 0x5, 0x3, 0x1d, 0xb, 0x5, 0x4a, 0x4, 0x66, 0x1, 0x8, 0x2, 0xa, 0x1, 0x13, 0x2, 0x1, 0x10, 0x3b, 0x2, 0x65, 0xe, 0x36, 0x4, 0x1, 0x5, 0x2e, 0x12, 0x1c, 0x44, 0x1, 0x1, 0xb, 0x37, 0x1b, 0x1, 0x64, 0x2, 0xa, 0x1, 0x7, 0x1, 0x7, 0x1, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x1, 0x3, 0x4, 0x2, 0x9, 0x2, 0x2, 0x2, 0x4, 0x8, 0x1, 0x4, 0x2, 0x1, 0x5, 0x2, 0xc, 0xf, 0x3, 0x1, 0x6, 0x4, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x5, 0x4, 0x2, 0x2, 0x3, 0x3, 0x1, 0x7, 0x4, 0x1, 0x1, 0x7, 0x10, 0xb, 0x3, 0x1, 0x9, 0x1, 0x3, 0x1, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x2, 0xa, 0x1, 0x3, 0x1, 0x3, 0x2, 0x1, 0xf, 0x4, 0x2, 0xa, 0x11, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x2, 0x9, 0x2, 0x2, 0x2, 0x3, 0x8, 0x2, 0x4, 0x2, 0x1, 0x5, 0x2, 0xa, 0x1, 0x1, 0x10, 0x2, 0x1, 0x6, 0x3, 0x3, 0x1, 0x4, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0xc, 0x4, 0x5, 0x3, 0x3, 0x1, 0x4, 0x2, 0x1, 0x6, 0x1, 0xe, 0xa, 0x11, 0x3, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x8, 0x1, 0x3, 0x1, 0x4, 0x7, 0x2, 0x1, 0x2, 0x6, 0x4, 0x2, 0xa, 0x12, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x2, 0x9, 0x1, 0x3, 0x1, 0x4, 0x7, 0x2, 0x7, 0x1, 0x1, 0x4, 0x2, 0xa, 0x1, 0x2, 0xf, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x29, 0x2, 0x8, 0x1, 0x3, 0x1, 0x5, 0x8, 0x1, 0x8, 0x4, 0x2, 0xa, 0xa, 0x6, 0x2, 0x2, 0x1, 0x12, 0x3, 0x18, 0x1, 0x9, 0x1, 0x1, 0x2, 0x7, 0x3, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x8, 0x12, 0x2, 0xd, 0x3a, 0x5, 0xf, 0x1, 0xa, 0x27, 0x2, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x6, 0x4, 0x1, 0x7, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0xd, 0x1, 0x3, 0x2, 0x5, 0x1, 0x1, 0x1, 0x6, 0x2, 0xa, 0x2, 0x4, 0x20, 0x1, 0x17, 0x2, 0x6, 0xa, 0xb, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0xa, 0x1, 0x24, 0x4, 0x14, 0x1, 0x12, 0x1, 0x24, 0x9, 0x1, 0x39, 0x4a, 0x6, 0x4e, 0x2, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x2b, 0x1, 0x81, 0x4d, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0x29, 0x1, 0x4, 0x2, 0x21, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0xf, 0x1, 0x39, 0x1, 0x4, 0x2, 0x43, 0x2, 0x3, 0x9, 0x9, 0xe, 0x10, 0x10, 0x55, 0xc, 0x82, 0x6c, 0x2, 0x11, 0x1, 0x1a, 0x5, 0x4b, 0x3, 0x3, 0xf, 0xd, 0x1, 0x7, 0xb, 0x15, 0xb, 0x14, 0xc, 0xd, 0x1, 0x3, 0x1, 0x2, 0xc, 0x54, 0x3, 0x1, 0x4, 0x2, 0x2, 0xa, 0x21, 0x3, 0x2, 0xa, 0x6, 0x58, 0x8, 0x2b, 0x5, 0x46, 0xa, 0x1d, 0x3, 0xc, 0x4, 0xc, 0xa, 0x28, 0x2, 0x5, 0xb, 0x2c, 0x4, 0x1a, 0x6, 0xb, 0x25, 0x1c, 0x4, 0x3f, 0x1, 0x1d, 0x2, 0xb, 0x6, 0xa, 0xd, 0x1, 0x58, 0x4c, 0x4, 0xa, 0x11, 0x9, 0xc, 0x74, 0xc, 0x38, 0x8, 0xa, 0x3, 0x31, 0x52, 0x3, 0x1, 0x23, 0x9, 0x80, 0xe7, 0x15, 0x81, 0x1a, 0x2, 0x6, 0x2, 0x26, 0x2, 0x6, 0x2, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1f, 0x2, 0x35, 0x1, 0x7, 0x1, 0x1, 0x3, 0x3, 0x1, 0x7, 0x3, 0x4, 0x2, 0x6, 0x4, 0xd, 0x5, 0x3, 0x1, 0x7, 0x42, 0x2, 0x13, 0x1, 0x1c, 0x1, 0xd, 0x1, 0x10, 0xd, 0x33, 0xd, 0x4, 0x1, 0x3, 0xc, 0x11, 0x1, 0x4, 0x1, 0x2, 0xa, 0x1, 0x1, 0x2, 0x6, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x10, 0x2, 0x4, 0x5, 0x5, 0x4, 0x1, 0x11, 0x29, 0x8a, 0x77, 0x2f, 0x1, 0x2f, 0x1, 0x80, 0x85, 0x6, 0x9, 0xc, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x38, 0x7, 0x1, 0xf, 0x18, 0x9, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x20, 0x82, 0x5, 0x3, 0x19, 0xf, 0x1, 0x5, 0x2, 0x5, 0x4, 0x56, 0x2, 0x7, 0x1, 0x5a, 0x1, 0x4, 0x5, 0x29, 0x3, 0x5e, 0x11, 0x1b, 0x35, 0x10, 0x82, 0x0, 0x99, 0xb6, 0x4a, 0xa0, 0x51, 0xcd, 0x33, 0x84, 0x8d, 0x43, 0x2e, 0x2, 0x81, 0xd, 0x3, 0x1c, 0x14, 0x30, 0x4, 0xa, 0x1, 0x19, 0x7, 0x53, 0x25, 0x9, 0x2, 0x67, 0x2, 0x4, 0x1, 0x4, 0xc, 0xb, 0x4d, 0x30, 0x18, 0x34, 0xc, 0x45, 0xb, 0xa, 0x6, 0x18, 0x3, 0x1, 0x4, 0x2e, 0x2, 0x24, 0xc, 0x1d, 0x3, 0x41, 0xe, 0xb, 0x26, 0x37, 0x9, 0xe, 0x2, 0xa, 0x6, 0x17, 0x3, 0x2, 0x4, 0x43, 0x18, 0x3, 0x2, 0x10, 0x2, 0x5, 0xa, 0x6, 0x2, 0x6, 0x2, 0x6, 0x9, 0x7, 0x1, 0x7, 0x80, 0x91, 0x2b, 0x1, 0x2, 0x2, 0xa, 0x6, 0xa0, 0x2b, 0xa4, 0xc, 0x17, 0x4, 0x31, 0xa0, 0x21, 0x4, 0x81, 0x6e, 0x2, 0x6a, 0x26, 0x7, 0xc, 0x5, 0x5, 0xc, 0x1, 0xd, 0x1, 0x5, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x6c, 0x21, 0x81, 0x6b, 0x12, 0x40, 0x2, 0x36, 0x28, 0xc, 0x4, 0x10, 0x10, 0x7, 0xc, 0x2, 0x18, 0x3, 0x20, 0x5, 0x1, 0x80, 0x87, 0x13, 0xa, 0x7, 0x1a, 0x4, 0x1, 0x1, 0x1a, 0xb, 0x59, 0x3, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x3, 0x23, 0xc, 0x1, 0x1a, 0x1, 0x13, 0x1, 0x2, 0x1, 0xf, 0x2, 0xe, 0x22, 0x7b, 0x45, 0x35, 0x80, 0x88, 0x1, 0x80, 0x82, 0x1d, 0x3, 0x31, 0x2f, 0x1f, 0x11, 0x1b, 0x35, 0x1e, 0x2, 0x24, 0x4, 0x8, 0x1, 0x5, 0x2a, 0x80, 0x9e, 0x2, 0xa, 0x83, 0x56, 0x6, 0x2, 0x1, 0x1, 0x2c, 0x1, 0x2, 0x3, 0x1, 0x2, 0x17, 0x80, 0xaa, 0x16, 0xa, 0x1a, 0x46, 0x38, 0x6, 0x2, 0x40, 0x4, 0x1, 0x2, 0x5, 0x8, 0x1, 0x3, 0x1, 0x1b, 0x4, 0x3, 0x4, 0x1, 0x20, 0x1d, 0x80, 0x83, 0x36, 0xa, 0x16, 0xa, 0x13, 0x80, 0x8d, 0x49, 0x83, 0xb7, 0x47, 0x1f, 0xa, 0x10, 0x3b, 0x15, 0x19, 0x7, 0xa, 0x6, 0x35, 0x1, 0xa, 0x40, 0x45, 0xb, 0xa, 0x84, 0xa6, 0x38, 0x8, 0xa, 0x89, 0x36, 0x83, 0x6f, 0x80, 0x91, 0x63, 0x8b, 0x9d, 0x84, 0x2f, 0xa0, 0x33, 0xd1, 0x82, 0x39, 0x84, 0xc7, 0x45, 0xb, 0x2f, 0x10, 0x11, 0xa0, 0x40, 0x60, 0x2, 0xa0, 0x21, 0x63, 0x5, 0x3, 0x6, 0x8, 0x8, 0x2, 0x7, 0x1e, 0x4, 0x80, 0x94, 0x3, 0x81, 0xbb, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x19, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x8, 0x2, 0x32, 0x96, 0x0, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x91, 0x44, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e, 0xab, 0x6, 0xe2, 0x80, 0xf0]; _T White_Space = [0x9, 0x5, 0x12, 0x1, 0x64, 0x1, 0x1a, 0x1, 0x95, 0xdf, 0x1, 0x89, 0x7f, 0xb, 0x1d, 0x2, 0x5, 0x1, 0x2f, 0x1, 0x8f, 0xa0, 0x1]; _T Grapheme_Link = [0x89, 0x4d, 0x1, 0x7f, 0x1, 0x7f, 0x1, 0x7f, 0x1, 0x7f, 0x1, 0x7f, 0x1, 0x7f, 0x1, 0x7f, 0x1, 0x7f, 0x1, 0x7c, 0x1, 0x6f, 0x1, 0x81, 0x49, 0x1, 0x80, 0xb4, 0x2, 0x86, 0xd9, 0x1, 0x1f, 0x1, 0x80, 0x9d, 0x1, 0x82, 0x8d, 0x1, 0x80, 0xe3, 0x1, 0x65, 0x2, 0x46, 0x2, 0x91, 0x8b, 0x1, 0xa0, 0x7a, 0x86, 0x1, 0x80, 0xbd, 0x1, 0x80, 0x8e, 0x1, 0x6c, 0x1, 0x81, 0x35, 0x1, 0x80, 0xf6, 0x1, 0xa0, 0x5e, 0x51, 0x1, 0x86, 0x6, 0x1, 0x72, 0x1, 0x79, 0x2, 0x80, 0x8b, 0x1, 0x84, 0xf5, 0x1]; _T Ll = [0x61, 0x1a, 0x3a, 0x1, 0x29, 0x18, 0x1, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x3, 0x2, 0x4, 0x1, 0x2, 0x1, 0x3, 0x3, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x3, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x3, 0x6, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x7, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x45, 0x1, 0x1b, 0x80, 0xc1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x3, 0x3, 0x12, 0x1, 0x1b, 0x23, 0x1, 0x2, 0x3, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x5, 0x1, 0x1, 0x2, 0x1, 0x2, 0x2, 0x33, 0x30, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x39, 0x27, 0x97, 0x78, 0x2c, 0x3f, 0xd, 0x1, 0x22, 0x66, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x8, 0x6, 0xa, 0x8, 0x8, 0x8, 0x8, 0x6, 0xa, 0x8, 0x8, 0x8, 0x8, 0xe, 0x2, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x5, 0x1, 0x2, 0x6, 0x1, 0x3, 0x3, 0x1, 0x2, 0x8, 0x4, 0x2, 0x2, 0x8, 0x8, 0xa, 0x3, 0x1, 0x2, 0x81, 0x12, 0x1, 0x3, 0x2, 0x3, 0x1, 0x1b, 0x1, 0x4, 0x1, 0x4, 0x1, 0x2, 0x2, 0x8, 0x4, 0x4, 0x1, 0x35, 0x1, 0x8a, 0xab, 0x2f, 0x2, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x2, 0x1, 0x6, 0x5, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x1, 0xc, 0x26, 0x1, 0x1, 0x5, 0x1, 0xa0, 0x79, 0x13, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x13, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x80, 0x8b, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x8, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0xd, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x50, 0x1, 0xa0, 0x53, 0x5, 0x7, 0xc, 0x5, 0x84, 0x29, 0x1a, 0x84, 0xcd, 0x28, 0xa0, 0xcf, 0xca, 0x1a, 0x1a, 0x7, 0x1, 0x12, 0x1a, 0x1a, 0x1a, 0x4, 0x1, 0x1, 0x1, 0x7, 0x1, 0xb, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1c, 0x1c, 0x19, 0x1, 0x6, 0x1a, 0x19, 0x1, 0x6, 0x1a, 0x19, 0x1, 0x6, 0x1a, 0x19, 0x1, 0x6, 0x1a, 0x19, 0x1, 0x6, 0x1, 0x1]; _T Cc = [0x0, 0x20, 0x5f, 0x21]; _T Pattern_Syntax = [0x21, 0xf, 0xa, 0x7, 0x1a, 0x4, 0x1, 0x1, 0x1a, 0x4, 0x22, 0x7, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x2, 0x4, 0x1, 0x4, 0x1, 0x3, 0x1, 0x17, 0x1, 0x1f, 0x1, 0x9f, 0x18, 0x18, 0x8, 0xf, 0x2, 0x13, 0x1, 0xa, 0x81, 0x31, 0x82, 0xd0, 0x80, 0xa0, 0x82, 0x76, 0x1e, 0x84, 0x6c, 0x82, 0x0, 0x80, 0x80, 0x81, 0x81, 0x3, 0x4, 0x19, 0xf, 0x1, 0xa0, 0xcd, 0xd, 0x2, 0x81, 0x5, 0x2]; _T XID_Continue = [0x30, 0xa, 0x7, 0x1a, 0x4, 0x1, 0x1, 0x1a, 0x2f, 0x1, 0xa, 0x1, 0x1, 0x1, 0x2, 0x1, 0x5, 0x17, 0x1, 0x1f, 0x1, 0x81, 0xca, 0x4, 0xc, 0xe, 0x5, 0x7, 0x1, 0x1, 0x1, 0x11, 0x75, 0x1, 0x2, 0x3, 0x3, 0x8, 0x5, 0x1, 0x1, 0x1, 0x14, 0x1, 0x53, 0x1, 0x80, 0x8b, 0x1, 0x5, 0x2, 0x80, 0x9e, 0x9, 0x26, 0x2, 0x1, 0x7, 0x27, 0x9, 0x2d, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x8, 0x1b, 0x5, 0x3, 0x1d, 0xb, 0x5, 0x4a, 0x4, 0x66, 0x1, 0x8, 0x2, 0xa, 0x1, 0x13, 0x2, 0x1, 0x10, 0x3b, 0x2, 0x65, 0xe, 0x36, 0x4, 0x1, 0x5, 0x2e, 0x12, 0x1c, 0x44, 0x1, 0x1, 0xb, 0x37, 0x1b, 0x1, 0x64, 0x2, 0xa, 0x1, 0x7, 0x1, 0x7, 0x1, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x1, 0x3, 0x4, 0x2, 0x9, 0x2, 0x2, 0x2, 0x4, 0x8, 0x1, 0x4, 0x2, 0x1, 0x5, 0x2, 0xc, 0xf, 0x3, 0x1, 0x6, 0x4, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x5, 0x4, 0x2, 0x2, 0x3, 0x3, 0x1, 0x7, 0x4, 0x1, 0x1, 0x7, 0x10, 0xb, 0x3, 0x1, 0x9, 0x1, 0x3, 0x1, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x2, 0xa, 0x1, 0x3, 0x1, 0x3, 0x2, 0x1, 0xf, 0x4, 0x2, 0xa, 0x11, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x2, 0x9, 0x2, 0x2, 0x2, 0x3, 0x8, 0x2, 0x4, 0x2, 0x1, 0x5, 0x2, 0xa, 0x1, 0x1, 0x10, 0x2, 0x1, 0x6, 0x3, 0x3, 0x1, 0x4, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0xc, 0x4, 0x5, 0x3, 0x3, 0x1, 0x4, 0x2, 0x1, 0x6, 0x1, 0xe, 0xa, 0x11, 0x3, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x8, 0x1, 0x3, 0x1, 0x4, 0x7, 0x2, 0x1, 0x2, 0x6, 0x4, 0x2, 0xa, 0x12, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x2, 0x9, 0x1, 0x3, 0x1, 0x4, 0x7, 0x2, 0x7, 0x1, 0x1, 0x4, 0x2, 0xa, 0x1, 0x2, 0xf, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x29, 0x2, 0x8, 0x1, 0x3, 0x1, 0x5, 0x8, 0x1, 0x8, 0x4, 0x2, 0xa, 0xa, 0x6, 0x2, 0x2, 0x1, 0x12, 0x3, 0x18, 0x1, 0x9, 0x1, 0x1, 0x2, 0x7, 0x3, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x8, 0x12, 0x2, 0xd, 0x3a, 0x5, 0xf, 0x1, 0xa, 0x27, 0x2, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x6, 0x4, 0x1, 0x7, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0xd, 0x1, 0x3, 0x2, 0x5, 0x1, 0x1, 0x1, 0x6, 0x2, 0xa, 0x2, 0x4, 0x20, 0x1, 0x17, 0x2, 0x6, 0xa, 0xb, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0xa, 0x1, 0x24, 0x4, 0x14, 0x1, 0x12, 0x1, 0x24, 0x9, 0x1, 0x39, 0x4a, 0x6, 0x4e, 0x2, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x2b, 0x1, 0x81, 0x4d, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0x29, 0x1, 0x4, 0x2, 0x21, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0xf, 0x1, 0x39, 0x1, 0x4, 0x2, 0x43, 0x2, 0x3, 0x9, 0x9, 0xe, 0x10, 0x10, 0x55, 0xc, 0x82, 0x6c, 0x2, 0x11, 0x1, 0x1a, 0x5, 0x4b, 0x3, 0x3, 0xf, 0xd, 0x1, 0x7, 0xb, 0x15, 0xb, 0x14, 0xc, 0xd, 0x1, 0x3, 0x1, 0x2, 0xc, 0x54, 0x3, 0x1, 0x4, 0x2, 0x2, 0xa, 0x21, 0x3, 0x2, 0xa, 0x6, 0x58, 0x8, 0x2b, 0x5, 0x46, 0xa, 0x1d, 0x3, 0xc, 0x4, 0xc, 0xa, 0x28, 0x2, 0x5, 0xb, 0x2c, 0x4, 0x1a, 0x6, 0xb, 0x25, 0x1c, 0x4, 0x3f, 0x1, 0x1d, 0x2, 0xb, 0x6, 0xa, 0xd, 0x1, 0x58, 0x4c, 0x4, 0xa, 0x11, 0x9, 0xc, 0x74, 0xc, 0x38, 0x8, 0xa, 0x3, 0x31, 0x52, 0x3, 0x1, 0x23, 0x9, 0x80, 0xe7, 0x15, 0x81, 0x1a, 0x2, 0x6, 0x2, 0x26, 0x2, 0x6, 0x2, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1f, 0x2, 0x35, 0x1, 0x7, 0x1, 0x1, 0x3, 0x3, 0x1, 0x7, 0x3, 0x4, 0x2, 0x6, 0x4, 0xd, 0x5, 0x3, 0x1, 0x7, 0x42, 0x2, 0x13, 0x1, 0x1c, 0x1, 0xd, 0x1, 0x10, 0xd, 0x33, 0xd, 0x4, 0x1, 0x3, 0xc, 0x11, 0x1, 0x4, 0x1, 0x2, 0xa, 0x1, 0x1, 0x2, 0x6, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x10, 0x2, 0x4, 0x5, 0x5, 0x4, 0x1, 0x11, 0x29, 0x8a, 0x77, 0x2f, 0x1, 0x2f, 0x1, 0x80, 0x85, 0x6, 0x9, 0xc, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x38, 0x7, 0x1, 0xf, 0x18, 0x9, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x20, 0x82, 0x5, 0x3, 0x19, 0xf, 0x1, 0x5, 0x2, 0x5, 0x4, 0x56, 0x2, 0x2, 0x2, 0x3, 0x1, 0x5a, 0x1, 0x4, 0x5, 0x29, 0x3, 0x5e, 0x11, 0x1b, 0x35, 0x10, 0x82, 0x0, 0x99, 0xb6, 0x4a, 0xa0, 0x51, 0xcd, 0x33, 0x84, 0x8d, 0x43, 0x2e, 0x2, 0x81, 0xd, 0x3, 0x1c, 0x14, 0x30, 0x4, 0xa, 0x1, 0x19, 0x7, 0x53, 0x25, 0x9, 0x2, 0x67, 0x2, 0x4, 0x1, 0x4, 0xc, 0xb, 0x4d, 0x30, 0x18, 0x34, 0xc, 0x45, 0xb, 0xa, 0x6, 0x18, 0x3, 0x1, 0x4, 0x2e, 0x2, 0x24, 0xc, 0x1d, 0x3, 0x41, 0xe, 0xb, 0x26, 0x37, 0x9, 0xe, 0x2, 0xa, 0x6, 0x17, 0x3, 0x2, 0x4, 0x43, 0x18, 0x3, 0x2, 0x10, 0x2, 0x5, 0xa, 0x6, 0x2, 0x6, 0x2, 0x6, 0x9, 0x7, 0x1, 0x7, 0x80, 0x91, 0x2b, 0x1, 0x2, 0x2, 0xa, 0x6, 0xa0, 0x2b, 0xa4, 0xc, 0x17, 0x4, 0x31, 0xa0, 0x21, 0x4, 0x81, 0x6e, 0x2, 0x6a, 0x26, 0x7, 0xc, 0x5, 0x5, 0xc, 0x1, 0xd, 0x1, 0x5, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x6c, 0x21, 0x80, 0x8b, 0x6, 0x80, 0xda, 0x12, 0x40, 0x2, 0x36, 0x28, 0xa, 0x6, 0x10, 0x10, 0x7, 0xc, 0x2, 0x18, 0x3, 0x21, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x7e, 0x13, 0xa, 0x7, 0x1a, 0x4, 0x1, 0x1, 0x1a, 0xb, 0x59, 0x3, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x3, 0x23, 0xc, 0x1, 0x1a, 0x1, 0x13, 0x1, 0x2, 0x1, 0xf, 0x2, 0xe, 0x22, 0x7b, 0x45, 0x35, 0x80, 0x88, 0x1, 0x80, 0x82, 0x1d, 0x3, 0x31, 0x2f, 0x1f, 0x11, 0x1b, 0x35, 0x1e, 0x2, 0x24, 0x4, 0x8, 0x1, 0x5, 0x2a, 0x80, 0x9e, 0x2, 0xa, 0x83, 0x56, 0x6, 0x2, 0x1, 0x1, 0x2c, 0x1, 0x2, 0x3, 0x1, 0x2, 0x17, 0x80, 0xaa, 0x16, 0xa, 0x1a, 0x46, 0x38, 0x6, 0x2, 0x40, 0x4, 0x1, 0x2, 0x5, 0x8, 0x1, 0x3, 0x1, 0x1b, 0x4, 0x3, 0x4, 0x1, 0x20, 0x1d, 0x80, 0x83, 0x36, 0xa, 0x16, 0xa, 0x13, 0x80, 0x8d, 0x49, 0x83, 0xb7, 0x47, 0x1f, 0xa, 0x10, 0x3b, 0x15, 0x19, 0x7, 0xa, 0x6, 0x35, 0x1, 0xa, 0x40, 0x45, 0xb, 0xa, 0x84, 0xa6, 0x38, 0x8, 0xa, 0x89, 0x36, 0x83, 0x6f, 0x80, 0x91, 0x63, 0x8b, 0x9d, 0x84, 0x2f, 0xa0, 0x33, 0xd1, 0x82, 0x39, 0x84, 0xc7, 0x45, 0xb, 0x2f, 0x10, 0x11, 0xa0, 0x40, 0x60, 0x2, 0xa0, 0x21, 0x63, 0x5, 0x3, 0x6, 0x8, 0x8, 0x2, 0x7, 0x1e, 0x4, 0x80, 0x94, 0x3, 0x81, 0xbb, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x19, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x8, 0x2, 0x32, 0x96, 0x0, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x91, 0x44, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e, 0xab, 0x6, 0xe2, 0x80, 0xf0]; _T Lowercase = [0x61, 0x1a, 0x2f, 0x1, 0xa, 0x1, 0x4, 0x1, 0x24, 0x18, 0x1, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x3, 0x2, 0x4, 0x1, 0x2, 0x1, 0x3, 0x3, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x3, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x3, 0x6, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x7, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x45, 0x1, 0x24, 0x7, 0x2, 0x1e, 0x5, 0x60, 0x1, 0x2b, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x4, 0x12, 0x1, 0x1b, 0x23, 0x1, 0x2, 0x3, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x5, 0x1, 0x1, 0x2, 0x1, 0x2, 0x2, 0x33, 0x30, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x39, 0x27, 0x97, 0x78, 0x80, 0xc0, 0x41, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x8, 0x6, 0xa, 0x8, 0x8, 0x8, 0x8, 0x6, 0xa, 0x8, 0x8, 0x8, 0x8, 0xe, 0x2, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x5, 0x1, 0x2, 0x6, 0x1, 0x3, 0x3, 0x1, 0x2, 0x8, 0x4, 0x2, 0x2, 0x8, 0x8, 0xa, 0x3, 0x1, 0x2, 0x79, 0x1, 0xd, 0x1, 0x10, 0xd, 0x6d, 0x1, 0x3, 0x2, 0x3, 0x1, 0x1b, 0x1, 0x4, 0x1, 0x4, 0x1, 0x2, 0x2, 0x8, 0x4, 0x4, 0x1, 0x21, 0x10, 0x4, 0x1, 0x83, 0x4b, 0x1a, 0x87, 0x46, 0x2f, 0x2, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x2, 0x1, 0x8, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x1, 0xc, 0x26, 0x1, 0x1, 0x5, 0x1, 0xa0, 0x79, 0x13, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x13, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x80, 0x8b, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xa, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0xd, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4e, 0x3, 0xa0, 0x53, 0x5, 0x7, 0xc, 0x5, 0x84, 0x29, 0x1a, 0x84, 0xcd, 0x28, 0xa0, 0xcf, 0xca, 0x1a, 0x1a, 0x7, 0x1, 0x12, 0x1a, 0x1a, 0x1a, 0x4, 0x1, 0x1, 0x1, 0x7, 0x1, 0xb, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1c, 0x1c, 0x19, 0x1, 0x6, 0x1a, 0x19, 0x1, 0x6, 0x1a, 0x19, 0x1, 0x6, 0x1a, 0x19, 0x1, 0x6, 0x1a, 0x19, 0x1, 0x6, 0x1, 0x1]; _T Zl = [0xa0, 0x20, 0x28, 0x1]; _T Zp = [0xa0, 0x20, 0x29, 0x1]; _T Radical = [0xa0, 0x2e, 0x80, 0x1a, 0x1, 0x59, 0xc, 0x80, 0xd6]; _T Extender = [0x80, 0xb7, 0x1, 0x82, 0x18, 0x2, 0x83, 0x6e, 0x1, 0x81, 0xb9, 0x1, 0x86, 0x4b, 0x1, 0x7f, 0x1, 0x89, 0x43, 0x1, 0x38, 0x1, 0x82, 0x63, 0x1, 0x81, 0x8e, 0x1, 0x44, 0x1, 0x93, 0x89, 0x1, 0x2b, 0x5, 0x67, 0x2, 0x5d, 0x3, 0xa0, 0x6f, 0x16, 0x1, 0x85, 0xf6, 0x1, 0x83, 0xc2, 0x1, 0x80, 0xa0, 0x1, 0x6c, 0x1, 0x15, 0x2, 0xa0, 0x54, 0x7b, 0x1]; _T Co = [0xa0, 0xe0, 0x0, 0x99, 0x0, 0xae, 0x7, 0x0, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe]; _T Unified_Ideograph = [0xa0, 0x34, 0x0, 0x99, 0xb6, 0x4a, 0xa0, 0x51, 0xcd, 0xa0, 0x5a, 0x41, 0x2, 0x1, 0x1, 0x1, 0x2, 0xa, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x3, 0xa1, 0x5, 0xd6, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde]; _T Pc = [0x5f, 0x1, 0x9f, 0xdf, 0x2, 0x13, 0x1, 0xa0, 0xdd, 0xde, 0x2, 0x18, 0x3, 0x80, 0xef, 0x1]; _T Cs = [0xa0, 0xd8, 0x0, 0x88, 0x0]; _T Noncharacter_Code_Point = [0xa0, 0xfd, 0xd0, 0x20, 0x82, 0xe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe]; _T Uppercase = [0x41, 0x1a, 0x65, 0x17, 0x1, 0x7, 0x21, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x3, 0x2, 0x4, 0x1, 0x2, 0x1, 0x3, 0x3, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x3, 0x1, 0x1, 0x1, 0x2, 0x3, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x7, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x81, 0x21, 0x1, 0x1, 0x1, 0x3, 0x1, 0xf, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x2, 0x1, 0x11, 0x1, 0x9, 0x23, 0x1, 0x2, 0x3, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x5, 0x1, 0x2, 0x1, 0x1, 0x2, 0x2, 0x33, 0x30, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xa, 0x26, 0x8b, 0x49, 0x26, 0x1, 0x1, 0x5, 0x1, 0x8d, 0x32, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x8, 0x8, 0x6, 0xa, 0x8, 0x8, 0x8, 0x8, 0x6, 0xb, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x8, 0x8, 0x48, 0x4, 0xc, 0x4, 0xc, 0x4, 0xc, 0x5, 0xb, 0x4, 0x81, 0x6, 0x1, 0x4, 0x1, 0x3, 0x3, 0x2, 0x3, 0x2, 0x1, 0x3, 0x5, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x2, 0x4, 0xa, 0x2, 0x5, 0x1, 0x1a, 0x10, 0x13, 0x1, 0x83, 0x32, 0x1a, 0x87, 0x30, 0x2f, 0x31, 0x1, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x2, 0x1, 0x8, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x8, 0x1, 0x1, 0x1, 0x4, 0x1, 0xa0, 0x79, 0x4d, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x13, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x80, 0x8b, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xa, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0xd, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xa0, 0x57, 0x76, 0x1a, 0x84, 0xc5, 0x28, 0xa0, 0xcf, 0xd8, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0x8, 0x1a, 0x1a, 0x1a, 0x2, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1b, 0x2, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1b, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1e, 0x19, 0x21, 0x19, 0x21, 0x19, 0x21, 0x19, 0x21, 0x19, 0x21, 0x1]; _T IDS_Trinary_Operator = [0xa0, 0x2f, 0xf2, 0x2]; _T Logical_Order_Exception = [0x8e, 0x40, 0x5, 0x7b, 0x5, 0xa0, 0x9b, 0xf0, 0x2, 0x2, 0x1, 0x1, 0x2]; _T Pi = [0x80, 0xab, 0x1, 0x9f, 0x6c, 0x1, 0x2, 0x2, 0x2, 0x1, 0x19, 0x1, 0x8d, 0xc8, 0x1, 0x1, 0x1, 0x4, 0x1, 0x2, 0x1, 0xf, 0x1, 0x3, 0x1]; _T Soft_Dotted = [0x69, 0x2, 0x80, 0xc4, 0x1, 0x81, 0x19, 0x1, 0x1e, 0x1, 0x34, 0x1, 0x14, 0x1, 0x81, 0x40, 0x1, 0x62, 0x1, 0x1, 0x1, 0x99, 0x9, 0x1, 0x33, 0x1, 0xd, 0x1, 0x3, 0x1, 0x80, 0x84, 0x1, 0x80, 0x9d, 0x1, 0x81, 0xa5, 0x1, 0x80, 0xd6, 0x2, 0x8b, 0x32, 0x1, 0xa1, 0xa7, 0xa5, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2, 0x32, 0x2]; _T Po = [0x21, 0x3, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x1, 0x2, 0xa, 0x2, 0x3, 0x2, 0x1b, 0x1, 0x44, 0x1, 0x5, 0x1, 0xe, 0x2, 0x7, 0x1, 0x82, 0xbe, 0x1, 0x8, 0x1, 0x81, 0xd2, 0x6, 0x29, 0x1, 0x36, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2c, 0x2, 0x14, 0x2, 0x1, 0x2, 0xd, 0x1, 0x2, 0x2, 0x4a, 0x4, 0x66, 0x1, 0x2b, 0xe, 0x80, 0xe9, 0x3, 0x36, 0xf, 0x1f, 0x1, 0x81, 0x5, 0x2, 0xa, 0x1, 0x81, 0x7f, 0x1, 0x83, 0x3, 0x1, 0x5a, 0x1, 0xa, 0x2, 0x80, 0xa8, 0xf, 0x1, 0x1, 0x70, 0x1, 0x4a, 0x5, 0x4, 0x2, 0x6f, 0x6, 0x80, 0xab, 0x1, 0x82, 0x64, 0x9, 0x83, 0x4, 0x2, 0x7c, 0x3, 0x47, 0x2, 0x80, 0x9d, 0x3, 0x1, 0x3, 0x25, 0x6, 0x1, 0x4, 0x81, 0x39, 0x2, 0x80, 0xd8, 0x2, 0x80, 0x80, 0x7, 0x1, 0x6, 0x80, 0xac, 0x7, 0x80, 0x9b, 0x4, 0x3b, 0x5, 0x3e, 0x2, 0x40, 0x8, 0xb, 0x1, 0x83, 0x42, 0x2, 0x8, 0x8, 0x8, 0x9, 0x2, 0x4, 0x2, 0x3, 0x3, 0xb, 0x1, 0x1, 0x1, 0xa, 0x8c, 0x9a, 0x4, 0x1, 0x2, 0x70, 0x1, 0x80, 0x8f, 0x2, 0x4, 0x3, 0x2, 0x1, 0x2, 0x9, 0x1, 0x2, 0x1, 0x1, 0x2, 0x2, 0xa, 0x5, 0x1, 0xa, 0x81, 0xc7, 0x3, 0x39, 0x1, 0x80, 0xbd, 0x1, 0xa0, 0x74, 0x2, 0x2, 0x81, 0xd, 0x3, 0x63, 0x1, 0xa, 0x1, 0x73, 0x6, 0x81, 0x7c, 0x4, 0x56, 0x2, 0x28, 0x3, 0x33, 0x2, 0x2f, 0x1, 0x61, 0xd, 0x10, 0x2, 0x7c, 0x4, 0x7e, 0x2, 0x10, 0x2, 0x80, 0xf9, 0x1, 0xa0, 0x52, 0x24, 0x7, 0x2, 0x1, 0x16, 0x1, 0x14, 0x2, 0x2, 0x4, 0x3, 0x3, 0x1, 0x4, 0x7, 0x3, 0x6, 0x1, 0x1, 0x2, 0x80, 0x95, 0x3, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x1, 0x2, 0xa, 0x2, 0x3, 0x2, 0x1b, 0x1, 0x24, 0x1, 0x2, 0x2, 0x81, 0x9a, 0x3, 0x82, 0x9c, 0x1, 0x30, 0x1, 0x84, 0x86, 0x1, 0x80, 0xc7, 0x1, 0x1f, 0x1, 0x81, 0x10, 0x9, 0x26, 0x1, 0x80, 0xb9, 0x7, 0x85, 0x7, 0x7, 0x6d, 0x2, 0x1, 0x4, 0x7e, 0x4, 0x80, 0x81, 0x4, 0x92, 0xa7, 0x4]; _T Cn = [0x83, 0x78, 0x2, 0x5, 0x5, 0x7, 0x1, 0x1, 0x1, 0x14, 0x1, 0x81, 0x85, 0x9, 0x26, 0x2, 0x7, 0x1, 0x27, 0x1, 0x2, 0x4, 0x1, 0x1, 0x37, 0x8, 0x1b, 0x5, 0x5, 0xb, 0x5, 0x1, 0x17, 0x1, 0x80, 0xf0, 0x1, 0x3c, 0x2, 0x65, 0xe, 0x3b, 0x5, 0x2e, 0x2, 0xf, 0x1, 0x1c, 0x2, 0x1, 0x41, 0x1, 0x1, 0xb, 0x37, 0x1b, 0x1, 0x78, 0x1, 0x7, 0x1, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x1, 0x3, 0x4, 0x2, 0x9, 0x2, 0x2, 0x2, 0x4, 0x8, 0x1, 0x4, 0x2, 0x1, 0x5, 0x2, 0x16, 0x5, 0x3, 0x1, 0x6, 0x4, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x5, 0x4, 0x2, 0x2, 0x3, 0x3, 0x1, 0x7, 0x4, 0x1, 0x1, 0x7, 0x10, 0xb, 0x3, 0x1, 0x9, 0x1, 0x3, 0x1, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x2, 0xa, 0x1, 0x3, 0x1, 0x3, 0x2, 0x1, 0xf, 0x4, 0x2, 0xc, 0xf, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x2, 0x9, 0x2, 0x2, 0x2, 0x3, 0x8, 0x2, 0x4, 0x2, 0x1, 0x5, 0x2, 0x12, 0xa, 0x2, 0x1, 0x6, 0x3, 0x3, 0x1, 0x4, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0xc, 0x4, 0x5, 0x3, 0x3, 0x1, 0x4, 0x2, 0x1, 0x6, 0x1, 0xe, 0x15, 0x6, 0x3, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x8, 0x1, 0x3, 0x1, 0x4, 0x7, 0x2, 0x1, 0x2, 0x6, 0x4, 0x2, 0xa, 0x8, 0x8, 0x2, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x2, 0x9, 0x1, 0x3, 0x1, 0x4, 0x7, 0x2, 0x7, 0x1, 0x1, 0x4, 0x2, 0xa, 0x1, 0x2, 0xf, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x29, 0x2, 0x8, 0x1, 0x3, 0x1, 0x5, 0x8, 0x1, 0x8, 0x4, 0x2, 0x10, 0x3, 0x7, 0x2, 0x2, 0x1, 0x12, 0x3, 0x18, 0x1, 0x9, 0x1, 0x1, 0x2, 0x7, 0x3, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x8, 0x12, 0x3, 0xc, 0x3a, 0x4, 0x1d, 0x25, 0x2, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x6, 0x4, 0x1, 0x7, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0xd, 0x1, 0x3, 0x2, 0x5, 0x1, 0x1, 0x1, 0x6, 0x2, 0xa, 0x2, 0x4, 0x20, 0x48, 0x1, 0x24, 0x4, 0x27, 0x1, 0x24, 0x1, 0xf, 0x1, 0xd, 0x25, 0x80, 0xc6, 0x1, 0x1, 0x5, 0x1, 0x2, 0x81, 0x79, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0x29, 0x1, 0x4, 0x2, 0x21, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0xf, 0x1, 0x39, 0x1, 0x4, 0x2, 0x43, 0x2, 0x20, 0x3, 0x1a, 0x6, 0x55, 0xb, 0x82, 0x9d, 0x3, 0x51, 0xf, 0xd, 0x1, 0x7, 0xb, 0x17, 0x9, 0x14, 0xc, 0xd, 0x1, 0x3, 0x1, 0x2, 0xc, 0x5e, 0x2, 0xa, 0x6, 0xa, 0x6, 0xf, 0x1, 0xa, 0x6, 0x58, 0x8, 0x2b, 0x5, 0x46, 0xa, 0x1d, 0x3, 0xc, 0x4, 0xc, 0x4, 0x1, 0x3, 0x2a, 0x2, 0x5, 0xb, 0x2c, 0x4, 0x1a, 0x6, 0xb, 0x3, 0x3e, 0x2, 0x41, 0x1, 0x1d, 0x2, 0xb, 0x6, 0xa, 0x6, 0xe, 0x52, 0x4c, 0x4, 0x2d, 0x3, 0x74, 0x8, 0x3c, 0x3, 0xf, 0x3, 0x33, 0x40, 0x8, 0x8, 0x27, 0x9, 0x80, 0xe7, 0x15, 0x81, 0x1a, 0x2, 0x6, 0x2, 0x26, 0x2, 0x6, 0x2, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1f, 0x2, 0x35, 0x1, 0xf, 0x1, 0xe, 0x2, 0x6, 0x1, 0x13, 0x2, 0x3, 0x1, 0x9, 0x1, 0x65, 0x1, 0xc, 0x2, 0x1b, 0x1, 0xd, 0x3, 0x1b, 0x15, 0x21, 0xf, 0x80, 0x8a, 0x6, 0x82, 0x64, 0xc, 0x27, 0x19, 0xb, 0x15, 0x82, 0xa0, 0x1, 0x84, 0x4c, 0x3, 0xa, 0x80, 0xa6, 0x2f, 0x1, 0x2f, 0x1, 0x80, 0x94, 0x5, 0x2d, 0x1, 0x1, 0x5, 0x1, 0x2, 0x38, 0x7, 0x2, 0xe, 0x18, 0x9, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x5c, 0x44, 0x1a, 0x1, 0x59, 0xc, 0x80, 0xd6, 0x1a, 0xc, 0x4, 0x40, 0x1, 0x56, 0x2, 0x67, 0x5, 0x29, 0x3, 0x5e, 0x1, 0x2b, 0x5, 0x24, 0xc, 0x2f, 0x1, 0x80, 0xdf, 0x1, 0x9a, 0xb6, 0xa, 0xa0, 0x52, 0xd, 0x33, 0x84, 0x8d, 0x3, 0x37, 0x9, 0x81, 0x5c, 0x14, 0x58, 0x7, 0x59, 0x8, 0x80, 0x8f, 0x1, 0x4, 0xc, 0xb, 0x4d, 0x34, 0x4, 0xa, 0x6, 0x38, 0x8, 0x45, 0x9, 0xc, 0x6, 0x1c, 0x4, 0x54, 0xb, 0x1e, 0x3, 0x4e, 0x1, 0xb, 0x4, 0x2, 0x20, 0x37, 0x9, 0xe, 0x2, 0xa, 0x2, 0x20, 0x4, 0x43, 0x18, 0x1c, 0xa, 0x6, 0x2, 0x6, 0x2, 0x6, 0x9, 0x7, 0x1, 0x7, 0x80, 0x91, 0x2e, 0x2, 0xa, 0x6, 0xa0, 0x2b, 0xa4, 0xc, 0x17, 0x4, 0x31, 0x4, 0xa0, 0x22, 0x6e, 0x2, 0x6a, 0x26, 0x7, 0xc, 0x5, 0x5, 0x1a, 0x1, 0x5, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x7c, 0x11, 0x81, 0x6d, 0x10, 0x40, 0x2, 0x36, 0x28, 0xe, 0x2, 0x1a, 0x6, 0x7, 0x9, 0x23, 0x1, 0x13, 0x1, 0x4, 0x4, 0x5, 0x1, 0x80, 0x87, 0x2, 0x1, 0x1, 0x80, 0xbe, 0x3, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x3, 0x3, 0x7, 0x1, 0x7, 0xa, 0x5, 0x2, 0xc, 0x1, 0x1a, 0x1, 0x13, 0x1, 0x2, 0x1, 0xf, 0x2, 0xe, 0x22, 0x7b, 0x5, 0x3, 0x4, 0x2d, 0x3, 0x54, 0x5, 0xc, 0x34, 0x2e, 0x80, 0x82, 0x1d, 0x3, 0x31, 0x2f, 0x1f, 0x1, 0x4, 0xc, 0x1b, 0x35, 0x1e, 0x1, 0x25, 0x4, 0xe, 0x2a, 0x80, 0x9e, 0x2, 0xa, 0x83, 0x56, 0x6, 0x2, 0x1, 0x1, 0x2c, 0x1, 0x2, 0x3, 0x1, 0x2, 0x17, 0x1, 0x9, 0x80, 0xa0, 0x1c, 0x3, 0x1b, 0x5, 0x1, 0x40, 0x38, 0x6, 0x2, 0x40, 0x4, 0x1, 0x2, 0x5, 0x8, 0x1, 0x3, 0x1, 0x1b, 0x4, 0x3, 0x4, 0x9, 0x8, 0x9, 0x7, 0x20, 0x80, 0x80, 0x36, 0x3, 0x1d, 0x2, 0x1b, 0x5, 0x8, 0x80, 0x80, 0x49, 0x82, 0x17, 0x1f, 0x81, 0x81, 0x4e, 0x4, 0x1e, 0x10, 0x42, 0xe, 0x19, 0x7, 0xa, 0x6, 0x35, 0x1, 0xe, 0x3c, 0x49, 0x7, 0xa, 0x84, 0xa6, 0x38, 0x8, 0xa, 0x89, 0x36, 0x83, 0x6f, 0x80, 0x91, 0x63, 0xd, 0x4, 0x8b, 0x8c, 0x84, 0x2f, 0xa0, 0x33, 0xd1, 0x82, 0x39, 0x84, 0xc7, 0x45, 0xb, 0x2f, 0x10, 0x11, 0xa0, 0x40, 0x60, 0x2, 0x9f, 0xfe, 0x80, 0xf6, 0xa, 0x27, 0x2, 0x80, 0xb5, 0x22, 0x46, 0x80, 0xba, 0x57, 0x9, 0x12, 0x80, 0x8e, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x81, 0x24, 0x2, 0x32, 0x96, 0x0, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x34, 0x2, 0x81, 0xe, 0x2c, 0x4, 0x64, 0xc, 0xf, 0x2, 0xe, 0x2, 0xf, 0x1, 0xf, 0x20, 0xb, 0x5, 0x1f, 0x1, 0x3c, 0x4, 0x2b, 0x4b, 0x1d, 0xd, 0x2b, 0x5, 0x9, 0x7, 0x2, 0x80, 0xae, 0x21, 0xf, 0x6, 0x1, 0x46, 0x3, 0x14, 0xc, 0x25, 0x1, 0x5, 0x15, 0x11, 0xf, 0x3f, 0x1, 0x1, 0x1, 0x80, 0xb6, 0x1, 0x4, 0x3, 0x3e, 0x2, 0x4, 0xc, 0x18, 0x80, 0x93, 0x46, 0x4, 0xb, 0x30, 0x46, 0x3a, 0x74, 0x88, 0x8c, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e, 0xab, 0x5, 0xe3, 0x1, 0x1e, 0x60, 0x80, 0x80, 0x80, 0xf0, 0xa0, 0xfe, 0x10, 0xa0, 0xff, 0xfe, 0x2, 0xa0, 0xff, 0xfe]; _T Ps = [0x28, 0x1, 0x32, 0x1, 0x1f, 0x1, 0x8e, 0xbe, 0x1, 0x1, 0x1, 0x87, 0x5e, 0x1, 0x89, 0x7e, 0x1, 0x3, 0x1, 0x26, 0x1, 0x37, 0x1, 0xf, 0x1, 0x82, 0x7a, 0x1, 0x1, 0x1, 0x1e, 0x1, 0x84, 0x3e, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x50, 0x1, 0x20, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x81, 0x94, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x40, 0x1, 0x1, 0x1, 0x21, 0x1, 0x84, 0x25, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x81, 0xdf, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0xa0, 0xcd, 0x20, 0x1, 0x80, 0xd8, 0x1, 0x1d, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x11, 0x1, 0x1, 0x1, 0x1, 0x1, 0x80, 0xaa, 0x1, 0x32, 0x1, 0x1f, 0x1, 0x3, 0x1, 0x2, 0x1]; _T ASCII_Hex_Digit = [0x30, 0xa, 0x7, 0x6, 0x1a, 0x6]; _T No = [0x80, 0xb2, 0x2, 0x5, 0x1, 0x2, 0x3, 0x89, 0x35, 0x6, 0x81, 0x78, 0x6, 0x78, 0x3, 0x80, 0x85, 0x7, 0x80, 0xf1, 0x6, 0x81, 0xb4, 0xa, 0x84, 0x35, 0x14, 0x84, 0x73, 0xa, 0x81, 0xe0, 0x1, 0x86, 0x95, 0x1, 0x3, 0x6, 0x6, 0xa, 0x80, 0xc6, 0x10, 0x29, 0x1, 0x82, 0xd6, 0x3c, 0x4e, 0x16, 0x82, 0x76, 0x1e, 0x85, 0x69, 0x1, 0x84, 0x94, 0x4, 0x80, 0x8a, 0xa, 0x1e, 0x8, 0x1, 0xf, 0x20, 0xa, 0x27, 0xf, 0xa0, 0x75, 0x70, 0x6, 0xa0, 0x58, 0xd1, 0x2d, 0x41, 0x4, 0x11, 0x1, 0x81, 0x95, 0x4, 0x85, 0x34, 0x8, 0x80, 0xb6, 0x6, 0x81, 0x24, 0x8, 0x35, 0x2, 0x80, 0xd9, 0x8, 0x18, 0x8, 0x82, 0xe0, 0x1f, 0x81, 0xd3, 0x14, 0xa0, 0xc2, 0xfa, 0x12, 0x9d, 0x8e, 0xb]; _T Sm = [0x2b, 0x1, 0x10, 0x3, 0x3d, 0x1, 0x1, 0x1, 0x2d, 0x1, 0x4, 0x1, 0x25, 0x1, 0x1f, 0x1, 0x82, 0xfe, 0x1, 0x82, 0xf, 0x3, 0x9a, 0x3b, 0x1, 0xd, 0x1, 0x27, 0x3, 0xd, 0x3, 0x80, 0x8b, 0x1, 0x27, 0x5, 0x6, 0x1, 0x44, 0x5, 0x5, 0x2, 0x4, 0x1, 0x2, 0x1, 0x2, 0x1, 0x7, 0x1, 0x1f, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1f, 0x81, 0xc, 0x20, 0x2, 0x5a, 0x1, 0x1e, 0x19, 0x28, 0x6, 0x81, 0xd5, 0x1, 0x9, 0x1, 0x36, 0x8, 0x6f, 0x1, 0x81, 0x50, 0x5, 0x2, 0x1f, 0xa, 0x10, 0x81, 0x0, 0x80, 0x83, 0x16, 0x3f, 0x4, 0x20, 0x2, 0x81, 0x2, 0x30, 0x15, 0x2, 0x6, 0xa0, 0xcf, 0xdc, 0x1, 0x83, 0x38, 0x1, 0x1, 0x3, 0x80, 0xa4, 0x1, 0x10, 0x3, 0x3d, 0x1, 0x1, 0x1, 0x80, 0x83, 0x1, 0x6, 0x4, 0xa0, 0xd6, 0xd4, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x97, 0x2c, 0x2]; _T Other_Math = [0x5e, 0x1, 0x83, 0x71, 0x3, 0x2, 0x1, 0x1a, 0x2, 0x2, 0x2, 0x9c, 0x20, 0x1, 0x1b, 0x3, 0xb, 0x1, 0x20, 0x4, 0x18, 0x2, 0xe, 0x2, 0x41, 0xd, 0x4, 0x1, 0x3, 0x2, 0x4, 0x5, 0x12, 0x1, 0x4, 0x1, 0x2, 0xa, 0x1, 0x1, 0x3, 0x5, 0x6, 0x1, 0x3, 0x2, 0x2, 0x2, 0x1, 0x3, 0x1, 0x6, 0x3, 0x4, 0x5, 0x5, 0x4b, 0x5, 0x2, 0x4, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x5, 0x2, 0x2, 0x4, 0x2, 0x4, 0x12, 0x2, 0x2, 0x1, 0x1, 0x1, 0x7, 0x1, 0x1, 0x6, 0x2, 0x81, 0x22, 0x4, 0x80, 0xa8, 0x2, 0x1, 0x1, 0x18, 0x1, 0x11, 0x1, 0x81, 0xbd, 0x2, 0xc, 0x9, 0x5, 0x5, 0x5, 0x2, 0x2, 0x2, 0x3, 0x5, 0xe, 0x1, 0x1, 0x1, 0x2, 0x6, 0x18, 0x2, 0x39, 0x1, 0x1, 0x1, 0x1d, 0x4, 0x9, 0x2, 0x81, 0x56, 0x2, 0x1f, 0xa, 0x81, 0x93, 0x16, 0x3f, 0x4, 0x20, 0x2, 0xa0, 0xd4, 0x63, 0x1, 0x1, 0x1, 0x4, 0x1, 0x80, 0xd3, 0x1, 0x1, 0x1, 0xa0, 0xd4, 0xc1, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x19, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x1f, 0x1, 0x19, 0x1, 0x8, 0x2, 0x32, 0x96, 0x0, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11]; _T Join_Control = [0xa0, 0x20, 0xc, 0x2]; _T Cf = [0x80, 0xad, 0x1, 0x85, 0x52, 0x5, 0x17, 0x1, 0x80, 0xc0, 0x1, 0x31, 0x1, 0x90, 0xfe, 0x1, 0x87, 0xfc, 0x5, 0x1a, 0x5, 0x31, 0x5, 0x1, 0xa, 0xa0, 0xde, 0x8f, 0x1, 0x80, 0xf9, 0x3, 0x90, 0xc1, 0x1, 0xa0, 0xc0, 0xb5, 0x8, 0xac, 0x2e, 0x86, 0x1, 0x1e, 0x60]; _T Ideographic = [0xa0, 0x30, 0x6, 0x2, 0x19, 0x9, 0xe, 0x3, 0x83, 0xc5, 0x99, 0xb6, 0x4a, 0xa0, 0x51, 0xcd, 0xa0, 0x59, 0x33, 0x81, 0x6e, 0x2, 0x6a, 0xa1, 0x5, 0x26, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e]; _T Sc = [0x24, 0x1, 0x7d, 0x4, 0x84, 0xe9, 0x1, 0x7b, 0x1, 0x83, 0xe6, 0x2, 0x7, 0x1, 0x80, 0xf5, 0x1, 0x81, 0x7, 0x1, 0x82, 0x45, 0x1, 0x89, 0x9b, 0x1, 0x88, 0xc4, 0x1b, 0xa0, 0x87, 0x7d, 0x1, 0xa0, 0x55, 0xc3, 0x1, 0x6c, 0x1, 0x80, 0x9a, 0x1, 0x80, 0xdb, 0x2, 0x3, 0x2]; _T Nd = [0x30, 0xa, 0x86, 0x26, 0xa, 0x80, 0x86, 0xa, 0x80, 0xc6, 0xa, 0x81, 0x9c, 0xa, 0x76, 0xa, 0x76, 0xa, 0x76, 0xa, 0x76, 0xa, 0x76, 0xa, 0x76, 0xa, 0x76, 0xa, 0x76, 0xa, 0x80, 0xe0, 0xa, 0x76, 0xa, 0x46, 0xa, 0x81, 0x16, 0xa, 0x46, 0xa, 0x87, 0x46, 0xa, 0x26, 0xa, 0x81, 0x2c, 0xa, 0x80, 0x80, 0xa, 0x80, 0xa6, 0xa, 0x6, 0xa, 0x80, 0xb6, 0xa, 0x56, 0xa, 0x80, 0x86, 0xa, 0x6, 0xa, 0xa0, 0x89, 0xc6, 0xa, 0x82, 0xa6, 0xa, 0x26, 0xa, 0x80, 0xc6, 0xa, 0x76, 0xa, 0x81, 0x96, 0xa, 0xa0, 0x53, 0x16, 0xa, 0x85, 0x86, 0xa, 0x8b, 0xbc, 0xa, 0x80, 0x80, 0xa, 0x3c, 0xa, 0x80, 0x90, 0xa, 0x84, 0xe6, 0xa, 0xa0, 0xc1, 0x4, 0x32]; _T Default_Ignorable_Code_Point = [0x80, 0xad, 0x1, 0x82, 0xa1, 0x1, 0x82, 0xcc, 0x1, 0x8b, 0x42, 0x2, 0x86, 0x53, 0x2, 0x55, 0x4, 0x87, 0xfc, 0x5, 0x1a, 0x5, 0x31, 0x10, 0x90, 0xf4, 0x1, 0xa0, 0xcc, 0x9b, 0x10, 0x80, 0xef, 0x1, 0x80, 0xa0, 0x1, 0x4f, 0x9, 0xa0, 0xd1, 0x7a, 0x8, 0xac, 0x2e, 0x85, 0x90, 0x0]; _T Other_ID_Continue = [0x80, 0xb7, 0x1, 0x82, 0xcf, 0x1, 0x8f, 0xe1, 0x9, 0x86, 0x68, 0x1]; _T Pd = [0x2d, 0x1, 0x85, 0x5c, 0x1, 0x33, 0x1, 0x8e, 0x41, 0x1, 0x84, 0x5, 0x1, 0x88, 0x9, 0x6, 0x8e, 0x1, 0x1, 0x2, 0x1, 0x1f, 0x2, 0x81, 0xe0, 0x1, 0x13, 0x1, 0x6f, 0x1, 0xa0, 0xcd, 0x90, 0x2, 0x25, 0x1, 0xa, 0x1, 0x80, 0xa9, 0x1]; _T Deprecated = [0x81, 0x49, 0x1, 0x85, 0x29, 0x1, 0x89, 0x3, 0x1, 0x1, 0x1, 0x88, 0x29, 0x2, 0x88, 0xc5, 0x6, 0x82, 0xb9, 0x2, 0xad, 0xdc, 0xd6, 0x1, 0x1e, 0x60]; _T Grapheme_Extend = [0x83, 0x0, 0x70, 0x81, 0x13, 0x7, 0x81, 0x7, 0x2d, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x1, 0x48, 0xb, 0x30, 0x15, 0x10, 0x1, 0x65, 0x7, 0x2, 0x6, 0x2, 0x2, 0x1, 0x4, 0x23, 0x1, 0x1e, 0x1b, 0x5b, 0xb, 0x3a, 0x9, 0x22, 0x4, 0x1, 0x9, 0x1, 0x3, 0x1, 0x5, 0x2b, 0x3, 0x80, 0x88, 0x1b, 0x1, 0x3, 0x37, 0x1, 0x1, 0x1, 0x4, 0x8, 0x4, 0x1, 0x3, 0x7, 0xa, 0x2, 0x1d, 0x1, 0x3a, 0x1, 0x1, 0x1, 0x2, 0x4, 0x8, 0x1, 0x9, 0x1, 0xa, 0x2, 0x1d, 0x2, 0x39, 0x1, 0x4, 0x2, 0x4, 0x2, 0x2, 0x3, 0x3, 0x1, 0x1e, 0x2, 0x3, 0x1, 0xb, 0x2, 0x39, 0x1, 0x4, 0x5, 0x1, 0x2, 0x4, 0x1, 0x14, 0x2, 0x1d, 0x1, 0x3a, 0x1, 0x1, 0x2, 0x1, 0x4, 0x8, 0x1, 0x8, 0x2, 0xa, 0x2, 0x1e, 0x1, 0x3b, 0x1, 0x1, 0x1, 0xc, 0x1, 0x9, 0x1, 0x66, 0x3, 0x5, 0x3, 0x1, 0x4, 0x7, 0x2, 0xb, 0x2, 0x58, 0x1, 0x2, 0x1, 0x2, 0x1, 0x3, 0x1, 0x5, 0x2, 0x7, 0x2, 0xb, 0x2, 0x5a, 0x1, 0x2, 0x4, 0x8, 0x1, 0x9, 0x1, 0xa, 0x2, 0x66, 0x1, 0x4, 0x1, 0x2, 0x3, 0x1, 0x1, 0x8, 0x1, 0x51, 0x1, 0x2, 0x7, 0xc, 0x8, 0x62, 0x1, 0x2, 0x6, 0x1, 0x2, 0xb, 0x6, 0x4a, 0x2, 0x1b, 0x1, 0x1, 0x1, 0x1, 0x1, 0x37, 0xe, 0x1, 0x5, 0x1, 0x2, 0x5, 0xb, 0x1, 0x24, 0x9, 0x1, 0x66, 0x4, 0x1, 0x6, 0x1, 0x2, 0x2, 0x2, 0x19, 0x2, 0x4, 0x3, 0x10, 0x4, 0xd, 0x1, 0x2, 0x2, 0x6, 0x1, 0xf, 0x1, 0x82, 0xbf, 0x3, 0x83, 0xb2, 0x3, 0x1d, 0x3, 0x1d, 0x2, 0x1e, 0x2, 0x40, 0x2, 0x1, 0x7, 0x8, 0x1, 0x2, 0xb, 0x9, 0x1, 0x2d, 0x3, 0x80, 0x9b, 0x1, 0x76, 0x3, 0x4, 0x2, 0x9, 0x1, 0x6, 0x3, 0x80, 0xdb, 0x2, 0x2, 0x1, 0x3a, 0x1, 0x1, 0x7, 0x1, 0x1, 0x1, 0x1, 0x2, 0x8, 0x6, 0xa, 0x2, 0x1, 0x80, 0x80, 0x4, 0x30, 0x1, 0x1, 0x5, 0x1, 0x1, 0x5, 0x1, 0x28, 0x9, 0xc, 0x2, 0x20, 0x4, 0x2, 0x2, 0x1, 0x1, 0x3a, 0x1, 0x1, 0x2, 0x3, 0x1, 0x1, 0x3, 0x3a, 0x8, 0x2, 0x2, 0x80, 0x98, 0x3, 0x1, 0xd, 0x1, 0x7, 0x4, 0x1, 0x6, 0x1, 0x80, 0xcb, 0x27, 0x15, 0x4, 0x82, 0xc, 0x2, 0x80, 0xc2, 0x21, 0x8b, 0xfe, 0x3, 0x80, 0x8d, 0x1, 0x60, 0x20, 0x82, 0x2a, 0x6, 0x69, 0x2, 0xa0, 0x75, 0xd4, 0x4, 0x1, 0xa, 0x21, 0x1, 0x50, 0x2, 0x81, 0x10, 0x1, 0x3, 0x1, 0x4, 0x1, 0x19, 0x2, 0x80, 0x9d, 0x1, 0x1b, 0x12, 0x34, 0x8, 0x19, 0xb, 0x2e, 0x3, 0x30, 0x1, 0x2, 0x4, 0x2, 0x1, 0x6c, 0x6, 0x2, 0x2, 0x2, 0x2, 0xc, 0x1, 0x8, 0x1, 0x63, 0x1, 0x1, 0x3, 0x2, 0x2, 0x5, 0x2, 0x1, 0x1, 0x2a, 0x2, 0x8, 0x1, 0x80, 0xee, 0x1, 0x2, 0x1, 0x4, 0x1, 0xa0, 0x4f, 0x30, 0x1, 0x82, 0xe1, 0x10, 0x10, 0x7, 0x81, 0x77, 0x2, 0x82, 0x5d, 0x1, 0x88, 0x3, 0x3, 0x1, 0x2, 0x5, 0x4, 0x28, 0x3, 0x4, 0x1, 0x85, 0xc1, 0x1, 0x36, 0xf, 0x39, 0x2, 0x31, 0x4, 0x2, 0x2, 0x45, 0x3, 0x24, 0x5, 0x1, 0x8, 0x4b, 0x2, 0x34, 0x9, 0x84, 0xec, 0x1, 0x1, 0x1, 0x2, 0x6, 0x1, 0x1, 0xa0, 0x58, 0xd7, 0x4, 0xa0, 0x61, 0xd2, 0x1, 0x1, 0x3, 0x4, 0x5, 0x8, 0x8, 0x2, 0x7, 0x1e, 0x4, 0x80, 0x94, 0x3, 0xac, 0x2e, 0xbb, 0x80, 0xf0]; _T Hyphen = [0x2d, 0x1, 0x7f, 0x1, 0x84, 0xdc, 0x1, 0x92, 0x7b, 0x1, 0x88, 0x9, 0x2, 0x8e, 0x5, 0x1, 0x82, 0xe3, 0x1, 0xa0, 0xcd, 0x67, 0x1, 0x80, 0xa9, 0x1, 0x57, 0x1]; _T Pe = [0x29, 0x1, 0x33, 0x1, 0x1f, 0x1, 0x8e, 0xbd, 0x1, 0x1, 0x1, 0x87, 0x5e, 0x1, 0x89, 0xa9, 0x1, 0x37, 0x1, 0xf, 0x1, 0x82, 0x7a, 0x1, 0x1, 0x1, 0x1e, 0x1, 0x84, 0x3e, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x50, 0x1, 0x20, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x81, 0x94, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x40, 0x1, 0x1, 0x1, 0x21, 0x1, 0x84, 0x25, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x81, 0xdf, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0xa0, 0xcd, 0x1f, 0x1, 0x80, 0xd8, 0x1, 0x1d, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x11, 0x1, 0x1, 0x1, 0x1, 0x1, 0x80, 0xaa, 0x1, 0x33, 0x1, 0x1f, 0x1, 0x2, 0x1, 0x2, 0x1]; _U[] _tab = [ _U("Alphabetic", Alphabetic), _U("ASCII_Hex_Digit", ASCII_Hex_Digit), _U("Bidi_Control", Bidi_Control), _U("Cased", Cased), _U("Case_Ignorable", Case_Ignorable), _U("Cc", Cc), _U("Cf", Cf), _U("Close_Punctuation", Pe), _U("Cn", Cn), _U("Co", Co), _U("Connector_Punctuation", Pc), _U("Control", Cc), _U("Cs", Cs), _U("Currency_Symbol", Sc), _U("Dash", Dash), _U("Dash_Punctuation", Pd), _U("Decimal_Number", Nd), _U("Default_Ignorable_Code_Point", Default_Ignorable_Code_Point), _U("Deprecated", Deprecated), _U("Diacritic", Diacritic), _U("Enclosing_Mark", Me), _U("Extender", Extender), _U("Final_Punctuation", Pf), _U("Format", Cf), _U("Grapheme_Base", Grapheme_Base), _U("Grapheme_Extend", Grapheme_Extend), _U("Grapheme_Link", Grapheme_Link), _U("Hex_Digit", Hex_Digit), _U("Hyphen", Hyphen), _U("ID_Continue", ID_Continue), _U("Ideographic", Ideographic), _U("IDS_Binary_Operator", IDS_Binary_Operator), _U("ID_Start", ID_Start), _U("IDS_Trinary_Operator", IDS_Trinary_Operator), _U("Initial_Punctuation", Pi), _U("Join_Control", Join_Control), _U("Letter_Number", Nl), _U("Line_Separator", Zl), _U("Ll", Ll), _U("Lm", Lm), _U("Lo", Lo), _U("Logical_Order_Exception", Logical_Order_Exception), _U("Lowercase", Lowercase), _U("Lowercase_Letter", Ll), _U("Lt", Lt), _U("Lu", Lu), _U("Math", Math), _U("Math_Symbol", Sm), _U("Mc", Mc), _U("Me", Me), _U("Mn", Mn), _U("Modifier_Letter", Lm), _U("Modifier_Symbol", Sk), _U("Nd", Nd), _U("Nl", Nl), _U("No", No), _U("Noncharacter_Code_Point", Noncharacter_Code_Point), _U("Nonspacing_Mark", Mn), _U("Open_Punctuation", Ps), _U("Other_Alphabetic", Other_Alphabetic), _U("Other_Default_Ignorable_Code_Point", Other_Default_Ignorable_Code_Point), _U("Other_Grapheme_Extend", Other_Grapheme_Extend), _U("Other_ID_Continue", Other_ID_Continue), _U("Other_ID_Start", Other_ID_Start), _U("Other_Letter", Lo), _U("Other_Lowercase", Other_Lowercase), _U("Other_Math", Other_Math), _U("Other_Number", No), _U("Other_Punctuation", Po), _U("Other_Symbol", So), _U("Other_Uppercase", Other_Uppercase), _U("Paragraph_Separator", Zp), _U("Pattern_Syntax", Pattern_Syntax), _U("Pattern_White_Space", Pattern_White_Space), _U("Pc", Pc), _U("Pd", Pd), _U("Pe", Pe), _U("Pf", Pf), _U("Pi", Pi), _U("Po", Po), _U("Private_Use", Co), _U("Ps", Ps), _U("Quotation_Mark", Quotation_Mark), _U("Radical", Radical), _U("Sc", Sc), _U("Sk", Sk), _U("Sm", Sm), _U("So", So), _U("Soft_Dotted", Soft_Dotted), _U("Space_Separator", Zs), _U("Spacing_Mark", Mc), _U("STerm", STerm), _U("Surrogate", Cs), _U("Terminal_Punctuation", Terminal_Punctuation), _U("Titlecase_Letter", Lt), _U("Unassigned", Cn), _U("Unified_Ideograph", Unified_Ideograph), _U("Uppercase", Uppercase), _U("Uppercase_Letter", Lu), _U("Variation_Selector", Variation_Selector), _U("White_Space", White_Space), _U("XID_Continue", XID_Continue), _U("XID_Start", XID_Start), _U("Zl", Zl), _U("Zp", Zp), _U("Zs", Zs), ]; } struct blocks { private alias _U = immutable(UnicodeProperty); @property static _U[] tab() pure { return _tab; } static immutable: private alias _T = ubyte[]; _T Number_Forms = [0xa0, 0x21, 0x50, 0x40]; _T Sinhala = [0x8d, 0x80, 0x80, 0x80]; _T Domino_Tiles = [0xa1, 0xf0, 0x30, 0x70]; _T Oriya = [0x8b, 0x0, 0x80, 0x80]; _T Thaana = [0x87, 0x80, 0x40]; _T New_Tai_Lue = [0x99, 0x80, 0x60]; _T Byzantine_Musical_Symbols = [0xa1, 0xd0, 0x0, 0x81, 0x0]; _T Cham = [0xa0, 0xaa, 0x0, 0x60]; _T IPA_Extensions = [0x82, 0x50, 0x60]; _T Bopomofo = [0xa0, 0x31, 0x0, 0x30]; _T Katakana_Phonetic_Extensions = [0xa0, 0x31, 0xf0, 0x10]; _T Khmer_Symbols = [0x99, 0xe0, 0x20]; _T Hebrew = [0x85, 0x90, 0x70]; _T Saurashtra = [0xa0, 0xa8, 0x80, 0x60]; _T Inscriptional_Parthian = [0xa1, 0xb, 0x40, 0x20]; _T Lisu = [0xa0, 0xa4, 0xd0, 0x30]; _T Latin_1_Supplement = [0x80, 0x80, 0x80, 0x80]; _T Arabic_Extended_A = [0x88, 0xa0, 0x60]; _T Tai_Tham = [0x9a, 0x20, 0x80, 0x90]; _T Latin_Extended_A = [0x81, 0x0, 0x80, 0x80]; _T Latin_Extended_B = [0x81, 0x80, 0x80, 0xd0]; _T Latin_Extended_C = [0xa0, 0x2c, 0x60, 0x20]; _T Latin_Extended_D = [0xa0, 0xa7, 0x20, 0x80, 0xe0]; _T CJK_Radicals_Supplement = [0xa0, 0x2e, 0x80, 0x80, 0x80]; _T Meroitic_Hieroglyphs = [0xa1, 0x9, 0x80, 0x20]; _T Linear_B_Syllabary = [0xa1, 0x0, 0x0, 0x80, 0x80]; _T Phonetic_Extensions_Supplement = [0x9d, 0x80, 0x40]; _T Meroitic_Cursive = [0xa1, 0x9, 0xa0, 0x60]; _T Enclosed_Ideographic_Supplement = [0xa1, 0xf2, 0x0, 0x81, 0x0]; _T Halfwidth_and_Fullwidth_Forms = [0xa0, 0xff, 0x0, 0x80, 0xf0]; _T Takri = [0xa1, 0x16, 0x80, 0x50]; _T Supplemental_Punctuation = [0xa0, 0x2e, 0x0, 0x80, 0x80]; _T Malayalam = [0x8d, 0x0, 0x80, 0x80]; _T Lepcha = [0x9c, 0x0, 0x50]; _T Miscellaneous_Symbols_And_Pictographs = [0xa1, 0xf3, 0x0, 0x83, 0x0]; _T Arabic_Presentation_Forms_A = [0xa0, 0xfb, 0x50, 0x82, 0xb0]; _T Sora_Sompeng = [0xa1, 0x10, 0xd0, 0x30]; _T Lydian = [0xa1, 0x9, 0x20, 0x20]; _T Hangul_Jamo_Extended_B = [0xa0, 0xd7, 0xb0, 0x50]; _T Private_Use_Area = [0xa0, 0xe0, 0x0, 0x99, 0x0]; _T Coptic = [0xa0, 0x2c, 0x80, 0x80, 0x80]; _T Phaistos_Disc = [0xa1, 0x1, 0xd0, 0x30]; _T Batak = [0x9b, 0xc0, 0x40]; _T Khmer = [0x97, 0x80, 0x80, 0x80]; _T Counting_Rod_Numerals = [0xa1, 0xd3, 0x60, 0x20]; _T Old_South_Arabian = [0xa1, 0xa, 0x60, 0x20]; _T Kannada = [0x8c, 0x80, 0x80, 0x80]; _T Arrows = [0xa0, 0x21, 0x90, 0x70]; _T CJK_Compatibility_Ideographs_Supplement = [0xa2, 0xf8, 0x0, 0x82, 0x20]; _T Combining_Half_Marks = [0xa0, 0xfe, 0x20, 0x10]; _T Miscellaneous_Technical = [0xa0, 0x23, 0x0, 0x81, 0x0]; _T Thai = [0x8e, 0x0, 0x80, 0x80]; _T Alphabetic_Presentation_Forms = [0xa0, 0xfb, 0x0, 0x50]; _T CJK_Unified_Ideographs = [0xa0, 0x4e, 0x0, 0xa0, 0x52, 0x0]; _T Phonetic_Extensions = [0x9d, 0x0, 0x80, 0x80]; _T Kayah_Li = [0xa0, 0xa9, 0x0, 0x30]; _T Supplementary_Private_Use_Area_B = [0xb0, 0x0, 0x0]; _T Gujarati = [0x8a, 0x80, 0x80, 0x80]; _T Unified_Canadian_Aboriginal_Syllabics_Extended = [0x98, 0xb0, 0x50]; _T Hangul_Syllables = [0xa0, 0xac, 0x0, 0xa0, 0x2b, 0xb0]; _T Vertical_Forms = [0xa0, 0xfe, 0x10, 0x10]; _T Inscriptional_Pahlavi = [0xa1, 0xb, 0x60, 0x20]; _T Control_Pictures = [0xa0, 0x24, 0x0, 0x40]; _T Carian = [0xa1, 0x2, 0xa0, 0x40]; _T Mahjong_Tiles = [0xa1, 0xf0, 0x0, 0x30]; _T Geometric_Shapes = [0xa0, 0x25, 0xa0, 0x60]; _T Cherokee = [0x93, 0xa0, 0x60]; _T Imperial_Aramaic = [0xa1, 0x8, 0x40, 0x20]; _T Rumi_Numeral_Symbols = [0xa1, 0xe, 0x60, 0x20]; _T Combining_Diacritical_Marks = [0x83, 0x0, 0x70]; _T Specials = [0xa0, 0xff, 0xf0, 0x10]; _T Greek_Extended = [0x9f, 0x0, 0x81, 0x0]; _T Ethiopic_Supplement = [0x93, 0x80, 0x20]; _T Limbu = [0x99, 0x0, 0x50]; _T Basic_Latin = [0x0, 0x80, 0x80]; _T Enclosed_Alphanumeric_Supplement = [0xa1, 0xf1, 0x0, 0x81, 0x0]; _T Cyrillic_Supplement = [0x85, 0x0, 0x30]; _T Hangul_Compatibility_Jamo = [0xa0, 0x31, 0x30, 0x60]; _T Supplemental_Arrows_A = [0xa0, 0x27, 0xf0, 0x10]; _T Supplemental_Arrows_B = [0xa0, 0x29, 0x0, 0x80, 0x80]; _T Katakana = [0xa0, 0x30, 0xa0, 0x60]; _T Ancient_Greek_Musical_Notation = [0xa1, 0xd2, 0x0, 0x50]; _T CJK_Compatibility = [0xa0, 0x33, 0x0, 0x81, 0x0]; _T Old_Persian = [0xa1, 0x3, 0xa0, 0x40]; _T Small_Form_Variants = [0xa0, 0xfe, 0x50, 0x20]; _T General_Punctuation = [0xa0, 0x20, 0x0, 0x70]; _T Miscellaneous_Mathematical_Symbols_A = [0xa0, 0x27, 0xc0, 0x30]; _T Latin_Extended_Additional = [0x9e, 0x0, 0x81, 0x0]; _T Playing_Cards = [0xa1, 0xf0, 0xa0, 0x60]; _T Syriac = [0x87, 0x0, 0x50]; _T Alchemical_Symbols = [0xa1, 0xf7, 0x0, 0x80, 0x80]; _T Tibetan = [0x8f, 0x0, 0x81, 0x0]; _T CJK_Strokes = [0xa0, 0x31, 0xc0, 0x30]; _T Tamil = [0x8b, 0x80, 0x80, 0x80]; _T Balinese = [0x9b, 0x0, 0x80, 0x80]; _T Shavian = [0xa1, 0x4, 0x50, 0x30]; _T Greek_and_Coptic = [0x83, 0x70, 0x80, 0x90]; _T Telugu = [0x8c, 0x0, 0x80, 0x80]; _T Runic = [0x96, 0xa0, 0x60]; _T Javanese = [0xa0, 0xa9, 0x80, 0x60]; _T Bopomofo_Extended = [0xa0, 0x31, 0xa0, 0x20]; _T Ideographic_Description_Characters = [0xa0, 0x2f, 0xf0, 0x10]; _T Old_Turkic = [0xa1, 0xc, 0x0, 0x50]; _T Unified_Canadian_Aboriginal_Syllabics = [0x94, 0x0, 0x82, 0x80]; _T Ugaritic = [0xa1, 0x3, 0x80, 0x20]; _T Egyptian_Hieroglyphs = [0xa1, 0x30, 0x0, 0x84, 0x30]; _T Buginese = [0x9a, 0x0, 0x20]; _T Kangxi_Radicals = [0xa0, 0x2f, 0x0, 0x80, 0xe0]; _T Cuneiform = [0xa1, 0x20, 0x0, 0x84, 0x0]; _T NKo = [0x87, 0xc0, 0x40]; _T Sundanese_Supplement = [0x9c, 0xc0, 0x10]; _T Buhid = [0x97, 0x40, 0x20]; _T Modifier_Tone_Letters = [0xa0, 0xa7, 0x0, 0x20]; _T Kanbun = [0xa0, 0x31, 0x90, 0x10]; _T Superscripts_and_Subscripts = [0xa0, 0x20, 0x70, 0x30]; _T Lao = [0x8e, 0x80, 0x80, 0x80]; _T Ol_Chiki = [0x9c, 0x50, 0x30]; _T Common_Indic_Number_Forms = [0xa0, 0xa8, 0x30, 0x10]; _T Hangul_Jamo_Extended_A = [0xa0, 0xa9, 0x60, 0x20]; _T Arabic_Presentation_Forms_B = [0xa0, 0xfe, 0x70, 0x80, 0x90]; _T Sharada = [0xa1, 0x11, 0x80, 0x60]; _T Miscellaneous_Symbols = [0xa0, 0x26, 0x0, 0x81, 0x0]; _T Variation_Selectors_Supplement = [0xae, 0x1, 0x0, 0x80, 0xf0]; _T Rejang = [0xa0, 0xa9, 0x30, 0x30]; _T Georgian_Supplement = [0xa0, 0x2d, 0x0, 0x30]; _T Braille_Patterns = [0xa0, 0x28, 0x0, 0x81, 0x0]; _T Lycian = [0xa1, 0x2, 0x80, 0x20]; _T Tai_Le = [0x99, 0x50, 0x30]; _T Miscellaneous_Mathematical_Symbols_B = [0xa0, 0x29, 0x80, 0x80, 0x80]; _T Musical_Symbols = [0xa1, 0xd1, 0x0, 0x81, 0x0]; _T Avestan = [0xa1, 0xb, 0x0, 0x40]; _T Ethiopic = [0x92, 0x0, 0x81, 0x80]; _T Arabic_Supplement = [0x87, 0x50, 0x30]; _T Samaritan = [0x88, 0x0, 0x40]; _T Cuneiform_Numbers_and_Punctuation = [0xa1, 0x24, 0x0, 0x80, 0x80]; _T Mongolian = [0x98, 0x0, 0x80, 0xb0]; _T Arabic = [0x86, 0x0, 0x81, 0x0]; _T Vai = [0xa0, 0xa5, 0x0, 0x81, 0x40]; _T Tifinagh = [0xa0, 0x2d, 0x30, 0x50]; _T Bamum_Supplement = [0xa1, 0x68, 0x0, 0x82, 0x40]; _T Tai_Viet = [0xa0, 0xaa, 0x80, 0x60]; _T Mandaic = [0x88, 0x40, 0x20]; _T Sundanese = [0x9b, 0x80, 0x40]; _T Block_Elements = [0xa0, 0x25, 0x80, 0x20]; _T Phoenician = [0xa1, 0x9, 0x0, 0x20]; _T Hanunoo = [0x97, 0x20, 0x20]; _T Supplemental_Mathematical_Operators = [0xa0, 0x2a, 0x0, 0x81, 0x0]; _T Deseret = [0xa1, 0x4, 0x0, 0x50]; _T Brahmi = [0xa1, 0x10, 0x0, 0x80, 0x80]; _T Devanagari_Extended = [0xa0, 0xa8, 0xe0, 0x20]; _T Supplementary_Private_Use_Area_A = [0xaf, 0x0, 0x0, 0xa1, 0x0, 0x0]; _T Box_Drawing = [0xa0, 0x25, 0x0, 0x80, 0x80]; _T Mathematical_Operators = [0xa0, 0x22, 0x0, 0x81, 0x0]; _T Ogham = [0x96, 0x80, 0x20]; _T Meetei_Mayek_Extensions = [0xa0, 0xaa, 0xe0, 0x20]; _T Hangul_Jamo = [0x91, 0x0, 0x81, 0x0]; _T Miao = [0xa1, 0x6f, 0x0, 0x80, 0xa0]; _T Emoticons = [0xa1, 0xf6, 0x0, 0x50]; _T Tags = [0xae, 0x0, 0x0, 0x80, 0x80]; _T Yi_Syllables = [0xa0, 0xa0, 0x0, 0x84, 0x90]; _T Gurmukhi = [0x8a, 0x0, 0x80, 0x80]; _T Syloti_Nagri = [0xa0, 0xa8, 0x0, 0x30]; _T Spacing_Modifier_Letters = [0x82, 0xb0, 0x50]; _T Yi_Radicals = [0xa0, 0xa4, 0x90, 0x40]; _T Ancient_Greek_Numbers = [0xa1, 0x1, 0x40, 0x50]; _T Glagolitic = [0xa0, 0x2c, 0x0, 0x60]; _T Georgian = [0x90, 0xa0, 0x60]; _T Osmanya = [0xa1, 0x4, 0x80, 0x30]; _T Variation_Selectors = [0xa0, 0xfe, 0x0, 0x10]; _T Mathematical_Alphanumeric_Symbols = [0xa1, 0xd4, 0x0, 0x84, 0x0]; _T Yijing_Hexagram_Symbols = [0xa0, 0x4d, 0xc0, 0x40]; _T Ethiopic_Extended = [0xa0, 0x2d, 0x80, 0x60]; _T Transport_And_Map_Symbols = [0xa1, 0xf6, 0x80, 0x80, 0x80]; _T High_Private_Use_Surrogates = [0xa0, 0xdb, 0x80, 0x80, 0x80]; _T Meetei_Mayek = [0xa0, 0xab, 0xc0, 0x40]; _T CJK_Compatibility_Forms = [0xa0, 0xfe, 0x30, 0x20]; _T Enclosed_Alphanumerics = [0xa0, 0x24, 0x60, 0x80, 0xa0]; _T Ancient_Symbols = [0xa1, 0x1, 0x90, 0x40]; _T Ethiopic_Extended_A = [0xa0, 0xab, 0x0, 0x30]; _T Bengali = [0x89, 0x80, 0x80, 0x80]; _T Currency_Symbols = [0xa0, 0x20, 0xa0, 0x30]; _T Myanmar = [0x90, 0x0, 0x80, 0xa0]; _T Cyrillic_Extended_A = [0xa0, 0x2d, 0xe0, 0x20]; _T Cyrillic_Extended_B = [0xa0, 0xa6, 0x40, 0x60]; _T Myanmar_Extended_A = [0xa0, 0xaa, 0x60, 0x20]; _T Hiragana = [0xa0, 0x30, 0x40, 0x60]; _T Dingbats = [0xa0, 0x27, 0x0, 0x80, 0xc0]; _T Armenian = [0x85, 0x30, 0x60]; _T Tai_Xuan_Jing_Symbols = [0xa1, 0xd3, 0x0, 0x60]; _T Linear_B_Ideograms = [0xa1, 0x0, 0x80, 0x80, 0x80]; _T Kharoshthi = [0xa1, 0xa, 0x0, 0x60]; _T Optical_Character_Recognition = [0xa0, 0x24, 0x40, 0x20]; _T Enclosed_CJK_Letters_and_Months = [0xa0, 0x32, 0x0, 0x81, 0x0]; _T Cypriot_Syllabary = [0xa1, 0x8, 0x0, 0x40]; _T Vedic_Extensions = [0x9c, 0xd0, 0x30]; _T Kaithi = [0xa1, 0x10, 0x80, 0x50]; _T Low_Surrogates = [0xa0, 0xdc, 0x0, 0x84, 0x0]; _T Letterlike_Symbols = [0xa0, 0x21, 0x0, 0x50]; _T Combining_Diacritical_Marks_for_Symbols = [0xa0, 0x20, 0xd0, 0x30]; _T Aegean_Numbers = [0xa1, 0x1, 0x0, 0x40]; _T High_Surrogates = [0xa0, 0xd8, 0x0, 0x83, 0x80]; _T CJK_Compatibility_Ideographs = [0xa0, 0xf9, 0x0, 0x82, 0x0]; _T CJK_Symbols_and_Punctuation = [0xa0, 0x30, 0x0, 0x40]; _T Gothic = [0xa1, 0x3, 0x30, 0x20]; _T Combining_Diacritical_Marks_Supplement = [0x9d, 0xc0, 0x40]; _T Phags_pa = [0xa0, 0xa8, 0x40, 0x40]; _T Miscellaneous_Symbols_and_Arrows = [0xa0, 0x2b, 0x0, 0x81, 0x0]; _T Bamum = [0xa0, 0xa6, 0xa0, 0x60]; _T Chakma = [0xa1, 0x11, 0x0, 0x50]; _T Kana_Supplement = [0xa1, 0xb0, 0x0, 0x81, 0x0]; _T Tagalog = [0x97, 0x0, 0x20]; _T Tagbanwa = [0x97, 0x60, 0x20]; _T Devanagari = [0x89, 0x0, 0x80, 0x80]; _T Old_Italic = [0xa1, 0x3, 0x0, 0x30]; _T Arabic_Mathematical_Alphabetic_Symbols = [0xa1, 0xee, 0x0, 0x81, 0x0]; _T CJK_Unified_Ideographs_Extension_D = [0xa2, 0xb7, 0x40, 0x80, 0xe0]; _T CJK_Unified_Ideographs_Extension_A = [0xa0, 0x34, 0x0, 0x99, 0xc0]; _T CJK_Unified_Ideographs_Extension_B = [0xa2, 0x0, 0x0, 0xa0, 0xa6, 0xe0]; _T CJK_Unified_Ideographs_Extension_C = [0xa2, 0xa7, 0x0, 0x90, 0x40]; _T Cyrillic = [0x84, 0x0, 0x81, 0x0]; _U[] _tab = [ _U("Aegean Numbers", Aegean_Numbers), _U("Alchemical Symbols", Alchemical_Symbols), _U("Alphabetic Presentation Forms", Alphabetic_Presentation_Forms), _U("Ancient Greek Musical Notation", Ancient_Greek_Musical_Notation), _U("Ancient Greek Numbers", Ancient_Greek_Numbers), _U("Ancient Symbols", Ancient_Symbols), _U("Arabic", Arabic), _U("Arabic Extended-A", Arabic_Extended_A), _U("Arabic Mathematical Alphabetic Symbols", Arabic_Mathematical_Alphabetic_Symbols), _U("Arabic Presentation Forms-A", Arabic_Presentation_Forms_A), _U("Arabic Presentation Forms-B", Arabic_Presentation_Forms_B), _U("Arabic Supplement", Arabic_Supplement), _U("Armenian", Armenian), _U("Arrows", Arrows), _U("Avestan", Avestan), _U("Balinese", Balinese), _U("Bamum", Bamum), _U("Bamum Supplement", Bamum_Supplement), _U("Basic Latin", Basic_Latin), _U("Batak", Batak), _U("Bengali", Bengali), _U("Block Elements", Block_Elements), _U("Bopomofo", Bopomofo), _U("Bopomofo Extended", Bopomofo_Extended), _U("Box Drawing", Box_Drawing), _U("Brahmi", Brahmi), _U("Braille Patterns", Braille_Patterns), _U("Buginese", Buginese), _U("Buhid", Buhid), _U("Byzantine Musical Symbols", Byzantine_Musical_Symbols), _U("Carian", Carian), _U("Chakma", Chakma), _U("Cham", Cham), _U("Cherokee", Cherokee), _U("CJK Compatibility", CJK_Compatibility), _U("CJK Compatibility Forms", CJK_Compatibility_Forms), _U("CJK Compatibility Ideographs", CJK_Compatibility_Ideographs), _U("CJK Compatibility Ideographs Supplement", CJK_Compatibility_Ideographs_Supplement), _U("CJK Radicals Supplement", CJK_Radicals_Supplement), _U("CJK Strokes", CJK_Strokes), _U("CJK Symbols and Punctuation", CJK_Symbols_and_Punctuation), _U("CJK Unified Ideographs", CJK_Unified_Ideographs), _U("CJK Unified Ideographs Extension A", CJK_Unified_Ideographs_Extension_A), _U("CJK Unified Ideographs Extension B", CJK_Unified_Ideographs_Extension_B), _U("CJK Unified Ideographs Extension C", CJK_Unified_Ideographs_Extension_C), _U("CJK Unified Ideographs Extension D", CJK_Unified_Ideographs_Extension_D), _U("Combining Diacritical Marks", Combining_Diacritical_Marks), _U("Combining Diacritical Marks for Symbols", Combining_Diacritical_Marks_for_Symbols), _U("Combining Diacritical Marks Supplement", Combining_Diacritical_Marks_Supplement), _U("Combining Half Marks", Combining_Half_Marks), _U("Common Indic Number Forms", Common_Indic_Number_Forms), _U("Control Pictures", Control_Pictures), _U("Coptic", Coptic), _U("Counting Rod Numerals", Counting_Rod_Numerals), _U("Cuneiform", Cuneiform), _U("Cuneiform Numbers and Punctuation", Cuneiform_Numbers_and_Punctuation), _U("Currency Symbols", Currency_Symbols), _U("Cypriot Syllabary", Cypriot_Syllabary), _U("Cyrillic", Cyrillic), _U("Cyrillic Extended-A", Cyrillic_Extended_A), _U("Cyrillic Extended-B", Cyrillic_Extended_B), _U("Cyrillic Supplement", Cyrillic_Supplement), _U("Deseret", Deseret), _U("Devanagari", Devanagari), _U("Devanagari Extended", Devanagari_Extended), _U("Dingbats", Dingbats), _U("Domino Tiles", Domino_Tiles), _U("Egyptian Hieroglyphs", Egyptian_Hieroglyphs), _U("Emoticons", Emoticons), _U("Enclosed Alphanumerics", Enclosed_Alphanumerics), _U("Enclosed Alphanumeric Supplement", Enclosed_Alphanumeric_Supplement), _U("Enclosed CJK Letters and Months", Enclosed_CJK_Letters_and_Months), _U("Enclosed Ideographic Supplement", Enclosed_Ideographic_Supplement), _U("Ethiopic", Ethiopic), _U("Ethiopic Extended", Ethiopic_Extended), _U("Ethiopic Extended-A", Ethiopic_Extended_A), _U("Ethiopic Supplement", Ethiopic_Supplement), _U("General Punctuation", General_Punctuation), _U("Geometric Shapes", Geometric_Shapes), _U("Georgian", Georgian), _U("Georgian Supplement", Georgian_Supplement), _U("Glagolitic", Glagolitic), _U("Gothic", Gothic), _U("Greek and Coptic", Greek_and_Coptic), _U("Greek Extended", Greek_Extended), _U("Gujarati", Gujarati), _U("Gurmukhi", Gurmukhi), _U("Halfwidth and Fullwidth Forms", Halfwidth_and_Fullwidth_Forms), _U("Hangul Compatibility Jamo", Hangul_Compatibility_Jamo), _U("Hangul Jamo", Hangul_Jamo), _U("Hangul Jamo Extended-A", Hangul_Jamo_Extended_A), _U("Hangul Jamo Extended-B", Hangul_Jamo_Extended_B), _U("Hangul Syllables", Hangul_Syllables), _U("Hanunoo", Hanunoo), _U("Hebrew", Hebrew), _U("High Private Use Surrogates", High_Private_Use_Surrogates), _U("High Surrogates", High_Surrogates), _U("Hiragana", Hiragana), _U("Ideographic Description Characters", Ideographic_Description_Characters), _U("Imperial Aramaic", Imperial_Aramaic), _U("Inscriptional Pahlavi", Inscriptional_Pahlavi), _U("Inscriptional Parthian", Inscriptional_Parthian), _U("IPA Extensions", IPA_Extensions), _U("Javanese", Javanese), _U("Kaithi", Kaithi), _U("Kana Supplement", Kana_Supplement), _U("Kanbun", Kanbun), _U("Kangxi Radicals", Kangxi_Radicals), _U("Kannada", Kannada), _U("Katakana", Katakana), _U("Katakana Phonetic Extensions", Katakana_Phonetic_Extensions), _U("Kayah Li", Kayah_Li), _U("Kharoshthi", Kharoshthi), _U("Khmer", Khmer), _U("Khmer Symbols", Khmer_Symbols), _U("Lao", Lao), _U("Latin-1 Supplement", Latin_1_Supplement), _U("Latin Extended-A", Latin_Extended_A), _U("Latin Extended Additional", Latin_Extended_Additional), _U("Latin Extended-B", Latin_Extended_B), _U("Latin Extended-C", Latin_Extended_C), _U("Latin Extended-D", Latin_Extended_D), _U("Lepcha", Lepcha), _U("Letterlike Symbols", Letterlike_Symbols), _U("Limbu", Limbu), _U("Linear B Ideograms", Linear_B_Ideograms), _U("Linear B Syllabary", Linear_B_Syllabary), _U("Lisu", Lisu), _U("Low Surrogates", Low_Surrogates), _U("Lycian", Lycian), _U("Lydian", Lydian), _U("Mahjong Tiles", Mahjong_Tiles), _U("Malayalam", Malayalam), _U("Mandaic", Mandaic), _U("Mathematical Alphanumeric Symbols", Mathematical_Alphanumeric_Symbols), _U("Mathematical Operators", Mathematical_Operators), _U("Meetei Mayek", Meetei_Mayek), _U("Meetei Mayek Extensions", Meetei_Mayek_Extensions), _U("Meroitic Cursive", Meroitic_Cursive), _U("Meroitic Hieroglyphs", Meroitic_Hieroglyphs), _U("Miao", Miao), _U("Miscellaneous Mathematical Symbols-A", Miscellaneous_Mathematical_Symbols_A), _U("Miscellaneous Mathematical Symbols-B", Miscellaneous_Mathematical_Symbols_B), _U("Miscellaneous Symbols", Miscellaneous_Symbols), _U("Miscellaneous Symbols and Arrows", Miscellaneous_Symbols_and_Arrows), _U("Miscellaneous Symbols And Pictographs", Miscellaneous_Symbols_And_Pictographs), _U("Miscellaneous Technical", Miscellaneous_Technical), _U("Modifier Tone Letters", Modifier_Tone_Letters), _U("Mongolian", Mongolian), _U("Musical Symbols", Musical_Symbols), _U("Myanmar", Myanmar), _U("Myanmar Extended-A", Myanmar_Extended_A), _U("New Tai Lue", New_Tai_Lue), _U("NKo", NKo), _U("Number Forms", Number_Forms), _U("Ogham", Ogham), _U("Ol Chiki", Ol_Chiki), _U("Old Italic", Old_Italic), _U("Old Persian", Old_Persian), _U("Old South Arabian", Old_South_Arabian), _U("Old Turkic", Old_Turkic), _U("Optical Character Recognition", Optical_Character_Recognition), _U("Oriya", Oriya), _U("Osmanya", Osmanya), _U("Phags-pa", Phags_pa), _U("Phaistos Disc", Phaistos_Disc), _U("Phoenician", Phoenician), _U("Phonetic Extensions", Phonetic_Extensions), _U("Phonetic Extensions Supplement", Phonetic_Extensions_Supplement), _U("Playing Cards", Playing_Cards), _U("Private Use Area", Private_Use_Area), _U("Rejang", Rejang), _U("Rumi Numeral Symbols", Rumi_Numeral_Symbols), _U("Runic", Runic), _U("Samaritan", Samaritan), _U("Saurashtra", Saurashtra), _U("Sharada", Sharada), _U("Shavian", Shavian), _U("Sinhala", Sinhala), _U("Small Form Variants", Small_Form_Variants), _U("Sora Sompeng", Sora_Sompeng), _U("Spacing Modifier Letters", Spacing_Modifier_Letters), _U("Specials", Specials), _U("Sundanese", Sundanese), _U("Sundanese Supplement", Sundanese_Supplement), _U("Superscripts and Subscripts", Superscripts_and_Subscripts), _U("Supplemental Arrows-A", Supplemental_Arrows_A), _U("Supplemental Arrows-B", Supplemental_Arrows_B), _U("Supplemental Mathematical Operators", Supplemental_Mathematical_Operators), _U("Supplemental Punctuation", Supplemental_Punctuation), _U("Supplementary Private Use Area-A", Supplementary_Private_Use_Area_A), _U("Supplementary Private Use Area-B", Supplementary_Private_Use_Area_B), _U("Syloti Nagri", Syloti_Nagri), _U("Syriac", Syriac), _U("Tagalog", Tagalog), _U("Tagbanwa", Tagbanwa), _U("Tags", Tags), _U("Tai Le", Tai_Le), _U("Tai Tham", Tai_Tham), _U("Tai Viet", Tai_Viet), _U("Tai Xuan Jing Symbols", Tai_Xuan_Jing_Symbols), _U("Takri", Takri), _U("Tamil", Tamil), _U("Telugu", Telugu), _U("Thaana", Thaana), _U("Thai", Thai), _U("Tibetan", Tibetan), _U("Tifinagh", Tifinagh), _U("Transport And Map Symbols", Transport_And_Map_Symbols), _U("Ugaritic", Ugaritic), _U("Unified Canadian Aboriginal Syllabics", Unified_Canadian_Aboriginal_Syllabics), _U("Unified Canadian Aboriginal Syllabics Extended", Unified_Canadian_Aboriginal_Syllabics_Extended), _U("Vai", Vai), _U("Variation Selectors", Variation_Selectors), _U("Variation Selectors Supplement", Variation_Selectors_Supplement), _U("Vedic Extensions", Vedic_Extensions), _U("Vertical Forms", Vertical_Forms), _U("Yijing Hexagram Symbols", Yijing_Hexagram_Symbols), _U("Yi Radicals", Yi_Radicals), _U("Yi Syllables", Yi_Syllables), ]; } struct scripts { private alias _U = immutable(UnicodeProperty); @property static _U[] tab() pure nothrow @nogc { return _tab; } static immutable: private alias _T = ubyte[]; _T Buhid = [0x97, 0x40, 0x14]; _T Sinhala = [0x8d, 0x82, 0x2, 0x1, 0x12, 0x3, 0x18, 0x1, 0x9, 0x1, 0x1, 0x2, 0x7, 0x3, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x8, 0x12, 0x3]; _T Phags_Pa = [0xa0, 0xa8, 0x40, 0x38]; _T Old_Turkic = [0xa1, 0xc, 0x0, 0x49]; _T Oriya = [0x8b, 0x1, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x2, 0x9, 0x2, 0x2, 0x2, 0x3, 0x8, 0x2, 0x4, 0x2, 0x1, 0x5, 0x2, 0x12]; _T Thaana = [0x87, 0x80, 0x32]; _T Inherited = [0x83, 0x0, 0x70, 0x81, 0x15, 0x2, 0x81, 0xc4, 0xb, 0x1a, 0x1, 0x82, 0xe0, 0x2, 0x93, 0x7d, 0x3, 0x1, 0xd, 0x1, 0x7, 0x4, 0x1, 0x6, 0x1, 0x80, 0xcb, 0x27, 0x15, 0x4, 0x82, 0xc, 0x2, 0x80, 0xc2, 0x21, 0x8f, 0x39, 0x4, 0x6b, 0x2, 0xa0, 0xcd, 0x65, 0x10, 0x10, 0x7, 0x83, 0xd6, 0x1, 0xa0, 0xcf, 0x69, 0x3, 0x11, 0x8, 0x2, 0x7, 0x1e, 0x4, 0xac, 0x2f, 0x52, 0x80, 0xf0]; _T Sharada = [0xa1, 0x11, 0x80, 0x49, 0x7, 0xa]; _T Rejang = [0xa0, 0xa9, 0x30, 0x24, 0xb, 0x1]; _T Imperial_Aramaic = [0xa1, 0x8, 0x40, 0x16, 0x1, 0x9]; _T Cham = [0xa0, 0xaa, 0x0, 0x37, 0x9, 0xe, 0x2, 0xa, 0x2, 0x4]; _T Kaithi = [0xa1, 0x10, 0x80, 0x42]; _T Bopomofo = [0x82, 0xea, 0x2, 0xa0, 0x2e, 0x19, 0x29, 0x72, 0x1b]; _T Deseret = [0xa1, 0x4, 0x0, 0x50]; _T Syloti_Nagri = [0xa0, 0xa8, 0x0, 0x2c]; _T Lycian = [0xa1, 0x2, 0x80, 0x1d]; _T Linear_B = [0xa1, 0x0, 0x0, 0xc, 0x1, 0x1a, 0x1, 0x13, 0x1, 0x2, 0x1, 0xf, 0x2, 0xe, 0x22, 0x7b]; _T Hebrew = [0x85, 0x91, 0x37, 0x8, 0x1b, 0x5, 0x5, 0xa0, 0xf5, 0x28, 0x1a, 0x1, 0x5, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0xa]; _T Saurashtra = [0xa0, 0xa8, 0x80, 0x45, 0x9, 0xc]; _T Avestan = [0xa1, 0xb, 0x0, 0x36, 0x3, 0x7]; _T Ethiopic = [0x92, 0x0, 0x49, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0x29, 0x1, 0x4, 0x2, 0x21, 0x1, 0x4, 0x2, 0x7, 0x1, 0x1, 0x1, 0x4, 0x2, 0xf, 0x1, 0x39, 0x1, 0x4, 0x2, 0x43, 0x2, 0x20, 0x3, 0x1a, 0x99, 0xe6, 0x17, 0x9, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0x1, 0x7, 0xa0, 0x7d, 0x22, 0x6, 0x2, 0x6, 0x2, 0x6, 0x9, 0x7, 0x1, 0x7]; _T Braille = [0xa0, 0x28, 0x0, 0x81, 0x0]; _T Lisu = [0xa0, 0xa4, 0xd0, 0x30]; _T Samaritan = [0x88, 0x0, 0x2e, 0x2, 0xf]; _T Mongolian = [0x98, 0x0, 0x2, 0x2, 0x1, 0x1, 0x9, 0x1, 0xa, 0x6, 0x58, 0x8, 0x2b]; _T Hangul = [0x91, 0x0, 0x81, 0x0, 0x9e, 0x2e, 0x2, 0x81, 0x1, 0x5e, 0x71, 0x1f, 0x41, 0x1f, 0xa0, 0x76, 0xe1, 0x1d, 0x82, 0x83, 0xa0, 0x2b, 0xa4, 0xc, 0x17, 0x4, 0x31, 0xa0, 0x27, 0xa4, 0x1f, 0x3, 0x6, 0x2, 0x6, 0x2, 0x6, 0x2, 0x3]; _T Takri = [0xa1, 0x16, 0x80, 0x38, 0x8, 0xa]; _T Phoenician = [0xa1, 0x9, 0x0, 0x1c, 0x3, 0x1]; _T Vai = [0xa0, 0xa5, 0x0, 0x81, 0x2c]; _T Batak = [0x9b, 0xc0, 0x34, 0x8, 0x4]; _T Yi = [0xa0, 0xa0, 0x0, 0x84, 0x8d, 0x3, 0x37]; _T Tifinagh = [0xa0, 0x2d, 0x30, 0x38, 0x7, 0x2, 0xe, 0x1]; _T Glagolitic = [0xa0, 0x2c, 0x0, 0x2f, 0x1, 0x2f]; _T Tai_Tham = [0x9a, 0x20, 0x3f, 0x1, 0x1d, 0x2, 0xb, 0x6, 0xa, 0x6, 0xe]; _T Canadian_Aboriginal = [0x94, 0x0, 0x82, 0x80, 0x82, 0x30, 0x46]; _T Meetei_Mayek = [0xa0, 0xaa, 0xe0, 0x17, 0x80, 0xc9, 0x2e, 0x2, 0xa]; _T Balinese = [0x9b, 0x0, 0x4c, 0x4, 0x2d]; _T Kayah_Li = [0xa0, 0xa9, 0x0, 0x30]; _T Kharoshthi = [0xa1, 0xa, 0x0, 0x4, 0x1, 0x2, 0x5, 0x8, 0x1, 0x3, 0x1, 0x1b, 0x4, 0x3, 0x4, 0x9, 0x8, 0x9]; _T Lepcha = [0x9c, 0x0, 0x38, 0x3, 0xf, 0x3, 0x3]; _T New_Tai_Lue = [0x99, 0x80, 0x2c, 0x4, 0x1a, 0x6, 0xb, 0x3, 0x2]; _T Sora_Sompeng = [0xa1, 0x10, 0xd0, 0x19, 0x7, 0xa]; _T Arabic = [0x86, 0x0, 0x5, 0x1, 0x6, 0x1, 0xe, 0x1, 0x1, 0x1, 0x1, 0x1, 0x20, 0x1, 0xa, 0xb, 0xa, 0xa, 0x6, 0x1, 0x6c, 0x1, 0x22, 0x50, 0x30, 0x81, 0x20, 0x1, 0x1, 0xb, 0x37, 0x1b, 0xa0, 0xf2, 0x51, 0x72, 0x11, 0x81, 0x6b, 0x12, 0x40, 0x2, 0x36, 0x28, 0xd, 0x73, 0x5, 0x1, 0x80, 0x87, 0x8f, 0x63, 0x1f, 0xa0, 0xdf, 0x81, 0x4, 0x1, 0x1b, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0xa, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x4, 0x1, 0x7, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1, 0x1, 0xa, 0x1, 0x11, 0x5, 0x3, 0x1, 0x5, 0x1, 0x11, 0x34, 0x2]; _T Hanunoo = [0x97, 0x20, 0x15]; _T Lydian = [0xa1, 0x9, 0x20, 0x1a, 0x5, 0x1]; _T Tai_Viet = [0xa0, 0xaa, 0x80, 0x43, 0x18, 0x5]; _T Coptic = [0x83, 0xe2, 0xe, 0xa0, 0x28, 0x90, 0x74, 0x5, 0x7]; _T Brahmi = [0xa1, 0x10, 0x0, 0x4e, 0x4, 0x1e]; _T Runic = [0x96, 0xa0, 0x4b, 0x3, 0x3]; _T Egyptian_Hieroglyphs = [0xa1, 0x30, 0x0, 0x84, 0x2f]; _T Khmer = [0x97, 0x80, 0x5e, 0x2, 0xa, 0x6, 0xa, 0x81, 0xe6, 0x20]; _T Ogham = [0x96, 0x80, 0x1d]; _T Gothic = [0xa1, 0x3, 0x30, 0x1b]; _T Katakana = [0xa0, 0x30, 0xa1, 0x5a, 0x2, 0x3, 0x80, 0xf0, 0x10, 0x80, 0xd0, 0x2f, 0x1, 0x58, 0xa0, 0xcc, 0xe, 0xa, 0x1, 0x2d, 0xa0, 0xb0, 0x62, 0x1]; _T Miao = [0xa1, 0x6f, 0x0, 0x45, 0xb, 0x2f, 0x10, 0x11]; _T Meroitic_Hieroglyphs = [0xa1, 0x9, 0x80, 0x20]; _T Thai = [0x8e, 0x1, 0x3a, 0x5, 0x1c]; _T Cypriot = [0xa1, 0x8, 0x0, 0x6, 0x2, 0x1, 0x1, 0x2c, 0x1, 0x2, 0x3, 0x1, 0x2, 0x1]; _T Meroitic_Cursive = [0xa1, 0x9, 0xa0, 0x18, 0x6, 0x2]; _T Gujarati = [0x8a, 0x81, 0x3, 0x1, 0x9, 0x1, 0x3, 0x1, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x5, 0x2, 0xa, 0x1, 0x3, 0x1, 0x3, 0x2, 0x1, 0xf, 0x4, 0x2, 0xc]; _T Lao = [0x8e, 0x81, 0x2, 0x1, 0x1, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x6, 0x4, 0x1, 0x7, 0x1, 0x3, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x1, 0xd, 0x1, 0x3, 0x2, 0x5, 0x1, 0x1, 0x1, 0x6, 0x2, 0xa, 0x2, 0x4]; _T Georgian = [0x90, 0xa0, 0x26, 0x1, 0x1, 0x5, 0x1, 0x2, 0x2b, 0x1, 0x4, 0x9c, 0x0, 0x26, 0x1, 0x1, 0x5, 0x1]; _T Osmanya = [0xa1, 0x4, 0x80, 0x1e, 0x2, 0xa]; _T Inscriptional_Pahlavi = [0xa1, 0xb, 0x60, 0x13, 0x5, 0x8]; _T Shavian = [0xa1, 0x4, 0x50, 0x30]; _T Carian = [0xa1, 0x2, 0xa0, 0x31]; _T Cherokee = [0x93, 0xa0, 0x55]; _T Mandaic = [0x88, 0x40, 0x1c, 0x2, 0x1]; _T Han = [0xa0, 0x2e, 0x80, 0x1a, 0x1, 0x59, 0xc, 0x80, 0xd6, 0x2f, 0x1, 0x1, 0x1, 0x19, 0x9, 0xe, 0x4, 0x83, 0xc4, 0x99, 0xb6, 0x4a, 0xa0, 0x51, 0xcd, 0xa0, 0x59, 0x33, 0x81, 0x6e, 0x2, 0x6a, 0xa1, 0x5, 0x26, 0xa0, 0xa6, 0xd7, 0x29, 0x90, 0x35, 0xb, 0x80, 0xde, 0xa0, 0x3f, 0xe2, 0x82, 0x1e]; _T Latin = [0x41, 0x1a, 0x6, 0x1a, 0x2f, 0x1, 0xf, 0x1, 0x5, 0x17, 0x1, 0x1f, 0x1, 0x81, 0xc1, 0x27, 0x5, 0x9a, 0x1b, 0x26, 0x6, 0x31, 0x5, 0x4, 0x5, 0xd, 0x1, 0x46, 0x41, 0x81, 0x0, 0x81, 0x71, 0x1, 0xd, 0x1, 0x10, 0xd, 0x80, 0x8d, 0x2, 0x6, 0x1, 0x1b, 0x1, 0x11, 0x29, 0x8a, 0xd7, 0x20, 0xa0, 0x7a, 0xa2, 0x66, 0x3, 0x4, 0x1, 0x4, 0xc, 0xb, 0x4d, 0x8, 0xa0, 0x53, 0x0, 0x7, 0x84, 0x1a, 0x1a, 0x6, 0x1a]; _T Limbu = [0x99, 0x0, 0x1d, 0x3, 0xc, 0x4, 0xc, 0x4, 0x1, 0x3, 0xc]; _T Ol_Chiki = [0x9c, 0x50, 0x30]; _T Bengali = [0x89, 0x81, 0x3, 0x1, 0x8, 0x2, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x1, 0x3, 0x4, 0x2, 0x9, 0x2, 0x2, 0x2, 0x4, 0x8, 0x1, 0x4, 0x2, 0x1, 0x5, 0x2, 0x16]; _T Myanmar = [0x90, 0x0, 0x80, 0xa0, 0xa0, 0x99, 0xc0, 0x1c]; _T Malayalam = [0x8d, 0x2, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x29, 0x2, 0x8, 0x1, 0x3, 0x1, 0x5, 0x8, 0x1, 0x8, 0x4, 0x2, 0x10, 0x3, 0x7]; _T Hiragana = [0xa0, 0x30, 0x41, 0x56, 0x6, 0x3, 0xa1, 0x7f, 0x61, 0x1, 0xa0, 0x41, 0xfe, 0x1]; _T Kannada = [0x8c, 0x82, 0x2, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x2, 0x9, 0x1, 0x3, 0x1, 0x4, 0x7, 0x2, 0x7, 0x1, 0x1, 0x4, 0x2, 0xa, 0x1, 0x2]; _T Armenian = [0x85, 0x31, 0x26, 0x2, 0x7, 0x1, 0x27, 0x2, 0x1, 0x4, 0x1, 0xa0, 0xf5, 0x83, 0x5]; _T Common = [0x0, 0x41, 0x1a, 0x6, 0x1a, 0x2f, 0x1, 0xf, 0x1, 0x5, 0x17, 0x1, 0x1f, 0x1, 0x81, 0xc1, 0x27, 0x5, 0x5, 0x2, 0x14, 0x74, 0x1, 0x9, 0x1, 0x6, 0x1, 0x1, 0x1, 0x82, 0x1, 0x1, 0x80, 0x82, 0x1, 0xe, 0x1, 0x3, 0x1, 0x20, 0x1, 0x1f, 0xa, 0x73, 0x1, 0x82, 0x86, 0x2, 0x84, 0xd9, 0x1, 0x81, 0x95, 0x4, 0x81, 0x22, 0x1, 0x85, 0xef, 0x3, 0x47, 0x2, 0x80, 0xcb, 0x2, 0x1, 0x1, 0x84, 0xcd, 0x1, 0xd, 0x1, 0x7, 0x4, 0x1, 0x6, 0x1, 0x2, 0x83, 0x9, 0xc, 0x2, 0x57, 0x1, 0xb, 0x3, 0xb, 0x1, 0xf, 0x11, 0x1b, 0x45, 0x26, 0x1, 0x3, 0x2, 0x6, 0x1, 0x1b, 0x1, 0x11, 0x29, 0x1, 0x6, 0x82, 0x64, 0xc, 0x27, 0x19, 0xb, 0x15, 0x82, 0xa0, 0x1, 0x80, 0xff, 0x81, 0x0, 0x82, 0x4d, 0x3, 0xa, 0x82, 0xa6, 0x3c, 0x81, 0xb4, 0xc, 0x4, 0x5, 0x1, 0x1, 0x1, 0x19, 0xf, 0x8, 0x4, 0x4, 0x5b, 0x2, 0x3, 0x1, 0x5a, 0x2, 0x80, 0x93, 0x10, 0x20, 0x24, 0x3c, 0x40, 0x1f, 0x51, 0x80, 0x88, 0x80, 0xa8, 0x99, 0xc0, 0x40, 0xa0, 0x59, 0x0, 0x22, 0x66, 0x3, 0x80, 0xa5, 0xa, 0x81, 0x95, 0x1, 0xa0, 0x53, 0x6e, 0x2, 0x80, 0xbd, 0x1, 0x12, 0xa, 0x16, 0x23, 0x1, 0x13, 0x1, 0x4, 0x80, 0x93, 0x1, 0x1, 0x20, 0x1a, 0x6, 0x1a, 0xb, 0xa, 0x1, 0x2d, 0x2, 0x40, 0x7, 0x1, 0x7, 0xa, 0x5, 0x81, 0x2, 0x3, 0x4, 0x2d, 0x3, 0x9, 0x50, 0xc, 0x34, 0x2d, 0xa0, 0xce, 0x3, 0x80, 0xf6, 0xa, 0x27, 0x2, 0x3e, 0x3, 0x11, 0x8, 0x2, 0x7, 0x1e, 0x4, 0x30, 0x81, 0x22, 0x57, 0x9, 0x12, 0x80, 0x8e, 0x55, 0x1, 0x47, 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x2, 0x4, 0x1, 0xc, 0x1, 0x1, 0x1, 0x7, 0x1, 0x41, 0x1, 0x4, 0x2, 0x8, 0x1, 0x7, 0x1, 0x1c, 0x1, 0x4, 0x1, 0x5, 0x1, 0x1, 0x3, 0x7, 0x1, 0x81, 0x54, 0x2, 0x81, 0x24, 0x2, 0x32, 0x98, 0x0, 0x2c, 0x4, 0x64, 0xc, 0xf, 0x2, 0xe, 0x2, 0xf, 0x1, 0xf, 0x20, 0xb, 0x5, 0x1f, 0x1, 0x3c, 0x4, 0x2b, 0x4b, 0x1a, 0x1, 0x2, 0xd, 0x2b, 0x5, 0x9, 0x7, 0x2, 0x80, 0xae, 0x21, 0xf, 0x6, 0x1, 0x46, 0x3, 0x14, 0xc, 0x25, 0x1, 0x5, 0x15, 0x11, 0xf, 0x3f, 0x1, 0x1, 0x1, 0x80, 0xb6, 0x1, 0x4, 0x3, 0x3e, 0x2, 0x4, 0xc, 0x18, 0x80, 0x93, 0x46, 0x4, 0xb, 0x30, 0x46, 0x3a, 0x74, 0xac, 0x8, 0x8d, 0x1, 0x1e, 0x60]; _T Old_Italic = [0xa1, 0x3, 0x0, 0x1f, 0x1, 0x4]; _T Old_Persian = [0xa1, 0x3, 0xa0, 0x24, 0x4, 0xe]; _T Greek = [0x83, 0x70, 0x4, 0x1, 0x3, 0x2, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x14, 0x1, 0x3f, 0xe, 0x10, 0x99, 0x26, 0x5, 0x32, 0x5, 0x4, 0x5, 0x54, 0x1, 0x81, 0x40, 0x16, 0x2, 0x6, 0x2, 0x26, 0x2, 0x6, 0x2, 0x8, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1f, 0x2, 0x35, 0x1, 0xf, 0x1, 0xe, 0x2, 0x6, 0x1, 0x13, 0x2, 0x3, 0x1, 0x9, 0x81, 0x27, 0x1, 0xa0, 0xe0, 0x19, 0x4b, 0xa0, 0xd0, 0x75, 0x46]; _T Sundanese = [0x9b, 0x80, 0x40, 0x81, 0x0, 0x8]; _T Syriac = [0x87, 0x0, 0xe, 0x1, 0x3c, 0x2, 0x3]; _T Gurmukhi = [0x8a, 0x1, 0x3, 0x1, 0x6, 0x4, 0x2, 0x2, 0x16, 0x1, 0x7, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x2, 0x1, 0x1, 0x5, 0x4, 0x2, 0x2, 0x3, 0x3, 0x1, 0x7, 0x4, 0x1, 0x1, 0x7, 0x10]; _T Tibetan = [0x8f, 0x0, 0x48, 0x1, 0x24, 0x4, 0x27, 0x1, 0x24, 0x1, 0xf, 0x1, 0x7, 0x4, 0x2]; _T Tamil = [0x8b, 0x82, 0x2, 0x1, 0x6, 0x3, 0x3, 0x1, 0x4, 0x3, 0x2, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0xc, 0x4, 0x5, 0x3, 0x3, 0x1, 0x4, 0x2, 0x1, 0x6, 0x1, 0xe, 0x15]; _T Telugu = [0x8c, 0x1, 0x3, 0x1, 0x8, 0x1, 0x3, 0x1, 0x17, 0x1, 0xa, 0x1, 0x5, 0x3, 0x8, 0x1, 0x3, 0x1, 0x4, 0x7, 0x2, 0x1, 0x2, 0x6, 0x4, 0x2, 0xa, 0x8, 0x8]; _T Inscriptional_Parthian = [0xa1, 0xb, 0x40, 0x16, 0x2, 0x8]; _T Nko = [0x87, 0xc0, 0x3b]; _T Javanese = [0xa0, 0xa9, 0x80, 0x4e, 0x2, 0xa, 0x4, 0x2]; _T Tai_Le = [0x99, 0x50, 0x1e, 0x2, 0x5]; _T Old_South_Arabian = [0xa1, 0xa, 0x60, 0x20]; _T Bamum = [0xa0, 0xa6, 0xa0, 0x58, 0xa0, 0xc1, 0x8, 0x82, 0x39]; _T Chakma = [0xa1, 0x11, 0x0, 0x35, 0x1, 0xe]; _T Ugaritic = [0xa1, 0x3, 0x80, 0x1e, 0x1, 0x1]; _T Tagalog = [0x97, 0x0, 0xd, 0x1, 0x7]; _T Tagbanwa = [0x97, 0x60, 0xd, 0x1, 0x3, 0x1, 0x2]; _T Devanagari = [0x89, 0x0, 0x51, 0x2, 0x11, 0x2, 0x12, 0x1, 0x7, 0xa0, 0x9f, 0x60, 0x1c]; _T Buginese = [0x9a, 0x0, 0x1c, 0x2, 0x2]; _T Cuneiform = [0xa1, 0x20, 0x0, 0x83, 0x6f, 0x80, 0x91, 0x63, 0xd, 0x4]; _T Cyrillic = [0x84, 0x0, 0x80, 0x85, 0x2, 0x80, 0xa1, 0x98, 0x3, 0x1, 0x4c, 0x1, 0x90, 0x67, 0x20, 0xa0, 0x78, 0x40, 0x58, 0x7, 0x1]; _U[] _tab = [ _U("Arabic", Arabic), _U("Armenian", Armenian), _U("Avestan", Avestan), _U("Balinese", Balinese), _U("Bamum", Bamum), _U("Batak", Batak), _U("Bengali", Bengali), _U("Bopomofo", Bopomofo), _U("Brahmi", Brahmi), _U("Braille", Braille), _U("Buginese", Buginese), _U("Buhid", Buhid), _U("Canadian_Aboriginal", Canadian_Aboriginal), _U("Carian", Carian), _U("Chakma", Chakma), _U("Cham", Cham), _U("Cherokee", Cherokee), _U("Common", Common), _U("Coptic", Coptic), _U("Cuneiform", Cuneiform), _U("Cypriot", Cypriot), _U("Cyrillic", Cyrillic), _U("Deseret", Deseret), _U("Devanagari", Devanagari), _U("Egyptian_Hieroglyphs", Egyptian_Hieroglyphs), _U("Ethiopic", Ethiopic), _U("Georgian", Georgian), _U("Glagolitic", Glagolitic), _U("Gothic", Gothic), _U("Greek", Greek), _U("Gujarati", Gujarati), _U("Gurmukhi", Gurmukhi), _U("Han", Han), _U("Hangul", Hangul), _U("Hanunoo", Hanunoo), _U("Hebrew", Hebrew), _U("Hiragana", Hiragana), _U("Imperial_Aramaic", Imperial_Aramaic), _U("Inherited", Inherited), _U("Inscriptional_Pahlavi", Inscriptional_Pahlavi), _U("Inscriptional_Parthian", Inscriptional_Parthian), _U("Javanese", Javanese), _U("Kaithi", Kaithi), _U("Kannada", Kannada), _U("Katakana", Katakana), _U("Kayah_Li", Kayah_Li), _U("Kharoshthi", Kharoshthi), _U("Khmer", Khmer), _U("Lao", Lao), _U("Latin", Latin), _U("Lepcha", Lepcha), _U("Limbu", Limbu), _U("Linear_B", Linear_B), _U("Lisu", Lisu), _U("Lycian", Lycian), _U("Lydian", Lydian), _U("Malayalam", Malayalam), _U("Mandaic", Mandaic), _U("Meetei_Mayek", Meetei_Mayek), _U("Meroitic_Cursive", Meroitic_Cursive), _U("Meroitic_Hieroglyphs", Meroitic_Hieroglyphs), _U("Miao", Miao), _U("Mongolian", Mongolian), _U("Myanmar", Myanmar), _U("New_Tai_Lue", New_Tai_Lue), _U("Nko", Nko), _U("Ogham", Ogham), _U("Ol_Chiki", Ol_Chiki), _U("Old_Italic", Old_Italic), _U("Old_Persian", Old_Persian), _U("Old_South_Arabian", Old_South_Arabian), _U("Old_Turkic", Old_Turkic), _U("Oriya", Oriya), _U("Osmanya", Osmanya), _U("Phags_Pa", Phags_Pa), _U("Phoenician", Phoenician), _U("Rejang", Rejang), _U("Runic", Runic), _U("Samaritan", Samaritan), _U("Saurashtra", Saurashtra), _U("Sharada", Sharada), _U("Shavian", Shavian), _U("Sinhala", Sinhala), _U("Sora_Sompeng", Sora_Sompeng), _U("Sundanese", Sundanese), _U("Syloti_Nagri", Syloti_Nagri), _U("Syriac", Syriac), _U("Tagalog", Tagalog), _U("Tagbanwa", Tagbanwa), _U("Tai_Le", Tai_Le), _U("Tai_Tham", Tai_Tham), _U("Tai_Viet", Tai_Viet), _U("Takri", Takri), _U("Tamil", Tamil), _U("Telugu", Telugu), _U("Thaana", Thaana), _U("Thai", Thai), _U("Tibetan", Tibetan), _U("Tifinagh", Tifinagh), _U("Ugaritic", Ugaritic), _U("Vai", Vai), _U("Yi", Yi), ]; } struct hangul { private alias _U = immutable(UnicodeProperty); @property static _U[] tab() pure nothrow @nogc { return _tab; } static immutable: private alias _T = ubyte[]; _T LVT = [0xa0, 0xac, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b]; _T T = [0x91, 0xa8, 0x58, 0xa0, 0xc5, 0xcb, 0x31]; _T V = [0x91, 0x60, 0x48, 0xa0, 0xc6, 0x8, 0x17]; _T LV = [0xa0, 0xac, 0x0, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1, 0x1b, 0x1]; _T L = [0x91, 0x0, 0x60, 0xa0, 0x98, 0x0, 0x1d]; _U[] _tab = [ _U("L", L), _U("Leading_Jamo", L), _U("LV", LV), _U("LV_Syllable", LV), _U("LVT", LVT), _U("LVT_Syllable", LVT), _U("T", T), _U("Trailing_Jamo", T), _U("V", V), _U("Vowel_Jamo", V), ]; } bool isFormatGen(dchar ch) @safe pure nothrow { if(ch < 8288) { if(ch < 1807) { if(ch < 1564) { if(ch == 173) return true; if(ch < 1536) return false; if(ch < 1541) return true; return false; } else if (ch < 1565) return true; else { if(ch == 1757) return true; return false; } } else if (ch < 1808) return true; else { if(ch < 8203) { if(ch == 6158) return true; return false; } else if (ch < 8208) return true; else { if(ch < 8234) return false; if(ch < 8239) return true; return false; } } } else if (ch < 8293) return true; else { if(ch < 69821) { if(ch < 65279) { if(ch < 8294) return false; if(ch < 8304) return true; return false; } else if (ch < 65280) return true; else { if(ch < 65529) return false; if(ch < 65532) return true; return false; } } else if (ch < 69822) return true; else { if(ch < 917505) { if(ch < 119155) return false; if(ch < 119163) return true; return false; } else if (ch < 917506) return true; else { if(ch < 917536) return false; if(ch < 917632) return true; return false; } } } } bool isControlGen(dchar ch) @safe pure nothrow { if(ch < 32) return true; if(ch < 127) return false; if(ch < 160) return true; return false; } bool isSpaceGen(dchar ch) @safe pure nothrow { if(ch < 160) { if(ch == 32) return true; return false; } else if (ch < 161) return true; else { if(ch < 8239) { if(ch == 5760) return true; if(ch < 8192) return false; if(ch < 8203) return true; return false; } else if (ch < 8240) return true; else { if(ch == 8287) return true; if(ch == 12288) return true; return false; } } } bool isWhiteGen(dchar ch) @safe pure nothrow @nogc { if(ch < 133) { if(ch < 9) return false; if(ch < 14) return true; if(ch == 32) return true; return false; } else if (ch < 134) return true; else { if(ch < 8232) { if(ch < 5760) { if(ch == 160) return true; return false; } else if (ch < 5761) return true; else { if(ch < 8192) return false; if(ch < 8203) return true; return false; } } else if (ch < 8234) return true; else { if(ch < 8287) { if(ch == 8239) return true; return false; } else if (ch < 8288) return true; else { if(ch == 12288) return true; return false; } } } } bool isHangL(dchar ch) @safe pure nothrow { if(ch < 4352) return false; if(ch < 4448) return true; if(ch < 43360) return false; if(ch < 43389) return true; return false; } bool isHangV(dchar ch) @safe pure nothrow { if(ch < 4448) return false; if(ch < 4520) return true; if(ch < 55216) return false; if(ch < 55239) return true; return false; } bool isHangT(dchar ch) @safe pure nothrow { if(ch < 4520) return false; if(ch < 4608) return true; if(ch < 55243) return false; if(ch < 55292) return true; return false; } static if(size_t.sizeof == 8) { //1536 bytes enum lowerCaseTrieEntries = TrieEntry!(bool, 8, 4, 9)([ 0x0, 0x20, 0x40], [ 0x100, 0x80, 0x2000], [ 0x402030202020100, 0x206020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x3000300030003, 0x3000300030003, 0x5000400030003, 0x3000700030006, 0x3000800030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x9000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0xb0003000a0003, 0x3000c00030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0xe000d00030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x0, 0x7fffffe00000000, 0x420040000000000, 0xff7fffff80000000, 0x55aaaaaaaaaaaaaa, 0xd4aaaaaaaaaaab55, 0xe6512d2a4e243129, 0xaa29aaaab5555240, 0x93faaaaaaaaaaaaa, 0xffffffffffffaa85, 0x1ffffffffefffff, 0x1f00000003, 0x0, 0x3c8a000000000020, 0xfffff00000010000, 0x192faaaaaae37fff, 0xffff000000000000, 0xaaaaaaaaffffffff, 0xaaaaaaaaaaaaa802, 0xaaaaaaaaaaaad554, 0xaaaaaaaaaa, 0xfffffffe00000000, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaabfeaaaaa, 0xaaaaaaaaaaaaaaaa, 0xff00ff003f00ff, 0x3fff00ff00ff003f, 0x40df00ff00ff00ff, 0xdc00ff00cf00dc, 0x0, 0x8002000000000000, 0x1fff0000, 0x0, 0x321080000008c400, 0xffff0000000043c0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x3ffffff0000, 0x0, 0x0, 0x0, 0x0, 0xffff000000000000, 0x3fda15627fffffff, 0xaaaaaaaaaaaaaaaa, 0x8501aaaaaaaaa, 0x20bfffffffff, 0x0, 0x0, 0x0, 0x0, 0x2aaaaaaaaaaa, 0xaaaaaa, 0x0, 0xaaabaaa800000000, 0x95ffaaaaaaaaaaaa, 0x2aa000a50aa, 0x700000000000000, 0x0, 0x0, 0x0, 0x0, 0xf8007f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7fffffe, 0x0, 0x0, 0xffffff0000000000, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffc000000, 0xffffdfc000, 0xebc000000ffffffc, 0xfffffc000000ffef, 0xffffffc000000f, 0xffffffc0000, 0xfc000000ffffffc0, 0xffffc000000fffff, 0xffffffc000000ff, 0xffffffc00000, 0x3ffffffc00, 0xf0000003f7fffffc, 0xffc000000fdfffff, 0xffff0000003f7fff, 0xfffffc000000fdff, 0xbf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //1472 bytes enum upperCaseTrieEntries = TrieEntry!(bool, 8, 4, 9)([ 0x0, 0x20, 0x40], [ 0x100, 0x80, 0x1e00], [ 0x402030202020100, 0x206020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x3000300030003, 0x3000300030004, 0x5000300030003, 0x3000700030006, 0x3000800030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x9000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0xa000300030003, 0x3000b00030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0xd000c00030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x3000300030003, 0x0, 0x7fffffe, 0x0, 0x7f7fffff, 0xaa55555555555555, 0x2b555555555554aa, 0x11aed2d5b1dbced6, 0x55d255554aaaa490, 0x6c05555555555555, 0x557a, 0x0, 0x0, 0x0, 0x45000000000000, 0xffbfffed740, 0xe6905555551c8000, 0xffffffffffff, 0x5555555500000000, 0x5555555555555401, 0x5555555555552aab, 0xfffe005555555555, 0x7fffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff00000000, 0x20bf, 0x0, 0x0, 0x0, 0x0, 0x5555555555555555, 0x5555555555555555, 0x5555555540155555, 0x5555555555555555, 0xff00ff003f00ff00, 0xff00aa003f00, 0xf00000000000000, 0xf001f000f000f00, 0x0, 0x0, 0x0, 0x0, 0xc00f3d503e273884, 0xffff00000020, 0x8, 0x0, 0x0, 0x0, 0xffc0000000000000, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x7fffffffffff, 0xc025ea9d00000000, 0x5555555555555555, 0x4280555555555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x155555555555, 0x555555, 0x0, 0x5554555400000000, 0x6a00555555555555, 0x55500052855, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7fffffe00000000, 0x0, 0x0, 0x0, 0xffffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfff0000003ffffff, 0xffffff0000003fff, 0x3fde64d0000003, 0x3ffffff0000, 0x7b0000001fdfe7b0, 0xfffff0000001fc5f, 0x3ffffff0000003f, 0x3ffffff00000, 0xf0000003ffffff00, 0xffff0000003fffff, 0xffffff00000003ff, 0x7fffffc00000001, 0x1ffffff0000000, 0x7fffffc00000, 0x1ffffff0000, 0x400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //8704 bytes enum simpleCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x20, 0x100], [ 0x100, 0x380, 0xd00], [ 0x402030202020100, 0x202020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x3000200010000, 0x7000600050004, 0xa00090008, 0xd000c000b0000, 0x110010000f000e, 0x1400130012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16001500000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x170000, 0x1b001a00190018, 0x1f001e001d001c, 0x0, 0x2200210020, 0x0, 0x0, 0x24002300000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x28002700260025, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b002a0000, 0x2e002d002c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30002f, 0x0, 0x0, 0x0, 0x0, 0x320031, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2400220020ffff, 0x2c002a00280026, 0x72f00320030002e, 0x3d003b00390037, 0x1b000430041003f, 0x4e004c004a0048, 0xffff005400520050, 0xffffffffffffffff, 0x2500230021ffff, 0x2d002b00290027, 0x73000330031002f, 0x3e003c003a0038, 0x1b1004400420040, 0x4f004d004b0049, 0xffff005500530051, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff043fffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xcc049800c800c6, 0xd500d3014904aa, 0xdd00db00d900d7, 0xe500e300e100df, 0xed00eb00e900e7, 0xffff00f300f100ef, 0xfb00f900f700f5, 0x6be010100ff00fd, 0xcd049900c900c7, 0xd600d4014a04ab, 0xde00dc00da00d8, 0xe600e400e200e0, 0xee00ec00ea00e8, 0xffff00f400f200f0, 0xfc00fa00f800f6, 0x1a80102010000fe, 0x118011701160115, 0x11e011d011c011b, 0x12401230120011f, 0x128012701260125, 0x12e012d012c012b, 0x13401330130012f, 0x138013701360135, 0x13c013b013a0139, 0x140013f013e013d, 0x144014301420141, 0x148014701460145, 0x14f014e014d014c, 0x1510150ffffffff, 0x155015401530152, 0x15801570156ffff, 0x15e015d015c0159, 0x16201610160015f, 0x166016501640163, 0x1690168ffff0167, 0x16d016c016b016a, 0x1710170016f016e, 0x175017401730172, 0x179017801770176, 0x17d017c017b017a, 0x1830182017f017e, 0x18b018a01870186, 0x1930192018f018e, 0x19b019a01970196, 0x1a301a2019f019e, 0x1a701a601a501a4, 0x1ac01ab01aa01a9, 0x1b201af01ae01ad, 0x1b601b501b3028b, 0x1bd01bb01ba01b9, 0x1c301c101bf01be, 0x1c701c5ffff01c4, 0x1cd01cc01cb01c9, 0x1d301d1023b01cf, 0xffff028301d601d5, 0x1db026901d901d7, 0x1e001df01de01dd, 0x1e501e301e201e1, 0xffffffff01e701e6, 0x1ed01eb01ea01e9, 0x1f301f101ef01ee, 0x1f701f601f501f4, 0xffffffff01fa01f9, 0x23dffff01fc01fb, 0xffffffffffffffff, 0x206020202010200, 0x20d020c02080207, 0x2110210020f020e, 0x215021402130212, 0x219021802170216, 0x21d021c021b021a, 0x220021f01c6021e, 0x226022502240223, 0x22a022902280227, 0x22e022d022c022b, 0x23202310230022f, 0x23802370236ffff, 0x23e023c023a0239, 0x24402430240023f, 0x248024702460245, 0x24c024b024a0249, 0x250024f024e024d, 0x254025302520251, 0x258025702560255, 0x25c025b025a0259, 0x260025f025e025d, 0x264026302620261, 0x268026702660265, 0x26c026bffff026a, 0x270026f026e026d, 0x274027302720271, 0x278027702760275, 0x27c027b027a0279, 0xffffffffffffffff, 0x281027fffffffff, 0x2d7028502840282, 0x28c028802870482, 0x2920291028f028d, 0x296029502940293, 0x29c029b02980297, 0x1b402b70466046a, 0x1c201c0ffff01bc, 0x1caffff01c8ffff, 0xffffffffffffffff, 0x1d0ffffffff01ce, 0xffff05fa0748ffff, 0x528ffff01d201d4, 0x1d8ffffffffffff, 0xffff01da02b3ffff, 0xffffffff01dcffff, 0xffffffffffffffff, 0xffffffff02a3ffff, 0x1e8ffffffff01e4, 0xffffffffffffffff, 0x1f201f0028e01ec, 0xffffffffffff0290, 0xffff01f8ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff083affff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x320031f031e031d, 0x3240323ffffffff, 0x3d5ffffffffffff, 0xffffffff03d903d7, 0xffffffffffffffff, 0xffff0329ffffffff, 0xffff0331032f032d, 0x3370335ffff0333, 0x33e03950339ffff, 0x347034503cc0340, 0x35403c2083b03c8, 0x35d035b03590440, 0x388ffff03c5039f, 0x36f039c036a0368, 0x378037607100371, 0x3320330032e032a, 0x33f0396033affff, 0x348034603cd0341, 0x35503c3083c03c9, 0x35e035c035a0441, 0x38a038903c603a0, 0x370039d036b0369, 0x379037707110372, 0x393033803360334, 0xffffffff03ca0397, 0x39403a1039effff, 0x3a703a603a303a2, 0x3ab03aa03a903a8, 0x3af03ae03ad03ac, 0x3b503b403b103b0, 0x3bd03bc03b903b8, 0x3c103c003bf03be, 0xffff03d103c703c4, 0x3cfffff03ce03cb, 0x3d403d303d203d0, 0x3da03d803d6ffff, 0x3e103df03dd03db, 0x3e903e703e503e3, 0x3f103ef03ed03eb, 0x3f903f703f503f3, 0x40103ff03fd03fb, 0x409040704050403, 0x411040f040d040b, 0x419041704150413, 0x421041f041d041b, 0x429042704250423, 0x431042f042d042b, 0x439043704350433, 0x402040003fe03fc, 0x40a040804060404, 0x4120410040e040c, 0x41a041804160414, 0x4220420041e041c, 0x42a042804260424, 0x4320430042e042c, 0x43a043804360434, 0x3e203e003de03dc, 0x3ea03e803e603e4, 0x3f203f003ee03ec, 0x3fa03f803f603f4, 0x453045204510450, 0x459045804570456, 0x4610460045d045c, 0x469046804650464, 0x4710470046d046c, 0x477047604730472, 0x47b047a04790478, 0x4810480047d047c, 0xffffffff04850484, 0xffffffffffffffff, 0x4950494ffffffff, 0x49b049a04970496, 0x49f049e049d049c, 0x4a704a604a304a2, 0x4ad04ac04a904a8, 0x4b304b204b104b0, 0x4b904b804b704b6, 0x4bf04be04bb04ba, 0x4c504c404c104c0, 0x4cd04cc04c904c8, 0x4d304d204cf04ce, 0x4d704d604d504d4, 0x4df04de04db04da, 0x4e704e604e304e2, 0x4f004ed04ec04ea, 0x4f804f504f404f1, 0x50004fd04fc04f9, 0x4eb050505040501, 0x50d050c050b050a, 0x5130512050f050e, 0x519051805170516, 0x51f051e051d051c, 0x525052405210520, 0x52b052a05270526, 0x52f052e052d052c, 0x537053605330532, 0x53d053c05390538, 0x5410540053f053e, 0x547054605430542, 0x54b054a05490548, 0x54f054e054d054c, 0x555055405510550, 0x559055805570556, 0x55d055c055b055a, 0x5630562055f055e, 0x567056605650564, 0x56b056a05690568, 0x5730572056f056e, 0x577057605750574, 0x57b057a05790578, 0xffffffffffffffff, 0xffffffffffffffff, 0x58405820580ffff, 0x58c058a05880586, 0x59405920590058e, 0x59c059a05980596, 0x5a405a205a0059e, 0x5ac05aa05a805a6, 0x5b405b205b005ae, 0x5bc05ba05b805b6, 0x5c405c205c005be, 0xffff05ca05c805c6, 0xffffffffffffffff, 0xffffffffffffffff, 0x58505830581ffff, 0x58d058b05890587, 0x59505930591058f, 0x59d059b05990597, 0x5a505a305a1059f, 0x5ad05ab05a905a7, 0x5b505b305b105af, 0x5bd05bb05b905b7, 0x5c505c305c105bf, 0xffff05cb05c905c7, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x8c008a00880086, 0x9400920090008e, 0x9c009a00980096, 0xa400a200a0009e, 0xac00aa00a800a6, 0xb400b200b000ae, 0xbc00ba00b800b6, 0xc400c200c000be, 0x4a000ca048e0486, 0x4c6ffff04b400ce, 0xffffffffffffffff, 0xffffffff0508ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff07e8ffff, 0xffffffff0454ffff, 0x5ff05fe05fd05fc, 0x605060406010600, 0x60b060a06090608, 0x6110610060f060e, 0x617061606130612, 0x61d061c06190618, 0x6210620061f061e, 0x627062606230622, 0x62b062a06290628, 0x62f062e062d062c, 0x635063406310630, 0x639063806370636, 0x63d063c063b063a, 0x6430642063f063e, 0x647064606450644, 0x64b064a06490648, 0x6510650064d064c, 0x655065406530652, 0x65d065c06590658, 0x6630662065f065e, 0x667066606650664, 0x66b066a06690668, 0x6710670066d066c, 0x675067406730672, 0x67a067906bc06bb, 0x680067f067c067b, 0x684068306820681, 0x688068706860685, 0x68e068d068a0689, 0x69206910690068f, 0x698069706960695, 0x69e069d069a0699, 0x6a206a106a0069f, 0x6a606a506a406a3, 0x6ac06ab06a806a7, 0x6b006af06ae06ad, 0x6b406b306b206b1, 0xffffffff06b606b5, 0x6bdffffffffffff, 0xffff06bfffffffff, 0x6c306c206c106c0, 0x6c906c806c506c4, 0x6cd06cc06cb06ca, 0x6d106d006cf06ce, 0x6d706d606d506d4, 0x6dd06dc06db06da, 0x6e106e006df06de, 0x6e506e406e306e2, 0x6eb06ea06e906e8, 0x6f106f006ef06ee, 0x6f506f406f306f2, 0x6f906f806f706f6, 0x6fd06fc06fb06fa, 0x701070006ff06fe, 0x705070407030702, 0x709070807070706, 0x70d070c070b070a, 0x7140713070f070e, 0x718071707160715, 0x71e071d071c071b, 0x72207210720071f, 0x726072507240723, 0x72a072907280727, 0x7330732072e072d, 0x73c073a07380736, 0x74407420740073e, 0x73d073b07390737, 0x74507430741073f, 0x750074e074c074a, 0xffffffff07540752, 0x751074f074d074b, 0xffffffff07550753, 0x76a076807660764, 0x7720770076e076c, 0x76b076907670765, 0x7730771076f076d, 0x78a078807860784, 0x7920790078e078c, 0x78b078907870785, 0x7930791078f078d, 0x7a207a0079e079c, 0xffffffff07a607a4, 0x7a307a1079f079d, 0xffffffff07a707a5, 0x7baffff07b6ffff, 0x7c2ffff07beffff, 0x7bbffff07b7ffff, 0x7c3ffff07bfffff, 0x7d607d407d207d0, 0x7de07dc07da07d8, 0x7d707d507d307d1, 0x7df07dd07db07d9, 0x840083e08360834, 0x84e084c08440842, 0x858085608620860, 0xffffffff08660864, 0x7fa07f807f607f4, 0x802080007fe07fc, 0x7fb07f907f707f5, 0x803080107ff07fd, 0x80e080c080a0808, 0x816081408120810, 0x80f080d080b0809, 0x817081508130811, 0x826082408220820, 0x82e082c082a0828, 0x827082508230821, 0x82f082d082b0829, 0x838ffff08320830, 0xffffffffffffffff, 0x837083508330831, 0xffff083dffff0839, 0x846ffffffffffff, 0xffffffffffffffff, 0x84508430841083f, 0xffffffffffff0847, 0xffffffff084a0848, 0xffffffffffffffff, 0x84f084d084b0849, 0xffffffffffffffff, 0xffffffff08540852, 0xffffffff085affff, 0x859085708550853, 0xffffffffffff085b, 0x868ffffffffffff, 0xffffffffffffffff, 0x867086508630861, 0xffffffffffff0869, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0712ffffffff, 0x14b0731ffffffff, 0xffffffffffffffff, 0xffff0530ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0531ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x18402af0180029f, 0x18c005e018802c1, 0x194006c01900064, 0x19c007e01980076, 0x18502b0018102a0, 0x18d005f018902c2, 0x195006d01910065, 0x19d007f01990077, 0x1b7ffffffffffff, 0xffffffffffff01b8, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x4d80444ffffffff, 0x4e0044c04dc0446, 0x4e8047404e4045e, 0x204ee02d3086a, 0x6e04f606c604f2, 0x10d04fe037a04fa, 0x51a0506061a0502, 0x4dd044704d90445, 0x4e5045f04e1044d, 0x2d4086b04e90475, 0x6c704f3000304ef, 0x37b04fb006f04f7, 0x61b0503010e04ff, 0xffffffff051b0507, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xa000800040000, 0x160010000e000c, 0x2bb001c001a0018, 0x5602e702d102c7, 0x66006200600058, 0x7800740070006a, 0x29900820080007c, 0x6020084000607e0, 0x5d005ce02a7057c, 0x1070105010305de, 0x1190113010f0109, 0xffff013101290121, 0xb000900050001, 0x170011000f000d, 0x2bc001d001b0019, 0x5702e802d202c8, 0x67006300610059, 0x7900750071006b, 0x29a00830081007d, 0x6030085000707e1, 0x5d105cf02a8057d, 0x1080106010405df, 0x11a01140110010a, 0xffff0132012a0122, 0x455052904c304c2, 0x45a0286028002a4, 0x46202aa02a9045b, 0x46b02b404670463, 0x2ba02b9ffff02b8, 0xffff02c002bfffff, 0xffffffffffffffff, 0x48302d8ffffffff, 0x489048802e202e1, 0x48d048c048b048a, 0x2fe02fd04910490, 0x30e030d03040303, 0x31a031903160315, 0x328032703260325, 0x6ed06ec02fc02fb, 0x383038203810380, 0x392039103870386, 0x3b303b203a503a4, 0x5cd05cc056d056c, 0x5ed05ec05db05da, 0x6570656060d060c, 0x6e706e6043e043d, 0x7830782072c072b, 0x694069307e307e2, 0x150014065b065a, 0x4bd04bc005d005c, 0x5d505d404d104d0, 0x511051001a101a0, 0x535053405230522, 0x553055205450544, 0x571057005610560, 0x15b015a057f057e, 0x3bb03ba037d037c, 0xffffffffffffffff, 0x5d2ffffffffffff, 0xffff05d905d805d3, 0x5e305e2ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x8d008b00890087, 0x9500930091008f, 0x9d009b00990097, 0xa500a300a1009f, 0xad00ab00a900a7, 0xb500b300b100af, 0xbd00bb00b900b7, 0xc500c300c100bf, 0x4a100cb048f0487, 0x4c7ffff04b500cf, 0xffffffffffffffff, 0xffffffff0509ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x5d705d602c402c3, 0x5e105e005dd05dc, 0x5e905e805e705e6, 0x5ef05ee05eb05ea, 0x5f505f405f105f0, 0x308030705f905f8, 0x625062406150614, 0x641064006330632, 0x6610660064f064e, 0x67e067d066f066e, 0x69c069b068c068b, 0xffffffff06aa06a9, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x69006807350734, 0x75f075e027e027d, 0x390038f07770776, 0x7b107b0001f001e, 0x2a202a107c707c6, 0x6b806b707e507e4, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x7590758ffffffff, 0x7610760075d075c, 0x2e002df02d602d5, 0x2ee02ed02e602e5, 0x7790778ffffffff, 0x7810780077d077c, 0x3140313030c030b, 0x322032103180317, 0x797079607950794, 0x79b079a07990798, 0x3850384037f037e, 0x7a907a8038e038d, 0x7ad07ac07ab07aa, 0x7b307b207af07ae, 0x7b907b807b507b4, 0x7c107c007bd07bc, 0x7c907c807c507c4, 0x7cf07ce07cd07cc, 0x47f047e046f046e, 0x4a504a404930492, 0xffffffffffffffff, 0xffffffffffffffff, 0x7e605150514ffff, 0x7eb07ea07e907e7, 0x7ef07ee07ed07ec, 0x7f307f207f107f0, 0x5f2ffffffffffff, 0xffffffff074905f3, 0x807080608050804, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x81b081a08190818, 0x81f081e081d081c, 0xffff05fb05f705f6, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x75a02c50756ffff, 0x76202cf02cd02cb, 0x2e3071902db06d2, 0x2f107ca02e90448, 0x77a02f502f30774, 0x3050221077e02f9, 0xffff043b030f007a, 0xffffffffffffffff, 0x75b02c60757ffff, 0x76302d002ce02cc, 0x2e4071a02dc06d3, 0x2f207cb02ea0449, 0x77b02f602f40775, 0x3060222077f02fa, 0xffff043c0310007b, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x72005a085c0012, 0x11106b9032b0311, 0x2dd029d02ab05e4, 0x10b060602ef085e, 0x4ca028902d902a5, 0x2c902bd02b502ad, 0x30902f702eb0746, 0x38b02b10241031b, 0x442053a044a03b6, 0x85004ae06d8044e, 0x73005b085d0013, 0x11206ba032c0312, 0x2de029e02ac05e5, 0x10c060702f0085f, 0x4cb028a02da02a6, 0x2ca02be02b602ae, 0x30a02f802ec0747, 0x38c02b20242031c, 0x443053b044b03b7, 0x85104af06d9044f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff]); //8832 bytes enum fullCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x20, 0x100], [ 0x100, 0x380, 0xd40], [ 0x402030202020100, 0x202020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x3000200010000, 0x7000600050004, 0xa00090008, 0xd000c000b0000, 0x110010000f000e, 0x1400130012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16001500000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x170000, 0x1b001a00190018, 0x1f001e001d001c, 0x0, 0x2200210020, 0x0, 0x0, 0x24002300000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x28002700260025, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b002a0000, 0x2e002d002c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x0, 0x310030, 0x0, 0x0, 0x0, 0x0, 0x330032, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2400220020ffff, 0x2c002a00280026, 0x78100320030002e, 0x3d003b00390037, 0x1b900430041003f, 0x4e004c004a0048, 0xffff005400520050, 0xffffffffffffffff, 0x2500230021ffff, 0x2d002b00290027, 0x78200330031002f, 0x3e003c003a0038, 0x1ba004400420040, 0x4f004d004b0049, 0xffff005500530051, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0470ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xcc04c900c800c6, 0xd500d3014e04db, 0xdd00db00d900d7, 0xe500e300e100df, 0xed00eb00e900e7, 0xffff00f300f100ef, 0xfb00f900f700f5, 0x70f010100ff00fd, 0xcd04ca00c900c7, 0xd600d4014f04dc, 0xde00dc00da00d8, 0xe600e400e200e0, 0xee00ec00ea00e8, 0xffff00f400f200f0, 0xfc00fa00f800f6, 0x1b10102010000fe, 0x11b011a01190118, 0x1210120011f011e, 0x127012601230122, 0x12b012a01290128, 0x1310130012f012e, 0x137013601330132, 0x13b013a01390138, 0x13f013e013d013c, 0x143014201410140, 0x149014801470146, 0x14d014c014b014a, 0x154015301520151, 0x1580157ffff0155, 0x15c015b015a0159, 0x15f015e015dffff, 0x165016401630160, 0x169016801670166, 0x16d016c016b016a, 0x1720171016f016e, 0x176017501740173, 0x17a017901780177, 0x17e017d017c017b, 0x18201810180017f, 0x186018501840183, 0x18c018b01880187, 0x19401930190018f, 0x19c019b01980197, 0x1a401a301a0019f, 0x1ac01ab01a801a7, 0x1b001af01ae01ad, 0x1b501b401b301b2, 0x1bb01b801b701b6, 0x1bf01be01bc029c, 0x1c601c401c301c2, 0x1cc01ca01c801c7, 0x1d001ceffff01cd, 0x1d601d501d401d2, 0x1dc01da024801d8, 0xffff029401df01de, 0x1e6027801e201e0, 0x1eb01ea01e901e8, 0x1f001ee01ed01ec, 0xffffffff01f201f1, 0x1f801f601f501f4, 0x1fe01fc01fa01f9, 0x2020201020001ff, 0xffffffff02050204, 0x24affff02070206, 0xffffffffffffffff, 0x211020d020c020b, 0x218021702130212, 0x21c021b021a0219, 0x220021f021e021d, 0x224022302220221, 0x228022702260225, 0x22b022a01cf0229, 0x2310230022f022e, 0x235023402330232, 0x239023802370236, 0x23d023c023b023a, 0x24502440243023e, 0x24b024902470246, 0x2510250024d024c, 0x255025402530252, 0x259025802570256, 0x25d025c025b025a, 0x263026202610260, 0x267026602650264, 0x26b026a02690268, 0x26f026e026d026c, 0x273027202710270, 0x277027602750274, 0x27b027affff0279, 0x27f027e027d027c, 0x285028402810280, 0x289028802870286, 0x28d028c028b028a, 0xffffffffffffffff, 0x2920290ffffffff, 0x2ec029602950293, 0x29d0299029804b3, 0x2a302a202a0029e, 0x2a702a602a502a4, 0x2ad02ac02a902a8, 0x1bd02ca0497049b, 0x1cb01c9ffff01c5, 0x1d3ffff01d1ffff, 0xffffffffffffffff, 0x1d9ffffffff01d7, 0xffff0643079affff, 0x559ffff01db01dd, 0x1e1ffffffffffff, 0xffff01e302c6ffff, 0xffffffff01e7ffff, 0xffffffffffffffff, 0xffffffff02b4ffff, 0x1f3ffffffff01ef, 0xffffffffffffffff, 0x1fd01fb029f01f7, 0xffffffffffff02a1, 0xffff0203ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff08e4ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x347034603450344, 0x34b034affffffff, 0x406ffffffffffff, 0xffffffff040a0408, 0xffffffffffffffff, 0xffff0350ffffffff, 0xffff035803560354, 0x35e035cffff035a, 0x36803c203630902, 0x371036f03fd036a, 0x37e03f308e503f9, 0x387038503830471, 0x3b5ffff03f603cc, 0x39903c903940392, 0x3a203a00762039b, 0x359035703550351, 0x36903c303640915, 0x372037003fe036b, 0x37f03f408e603fa, 0x388038603840472, 0x3b703b603f703cd, 0x39a03ca03950393, 0x3a303a10763039c, 0x3c0035f035d035b, 0xffffffff03fb03c4, 0x3c103ce03cbffff, 0x3d403d303d003cf, 0x3d803d703d603d5, 0x3de03dd03da03d9, 0x3e403e303e003df, 0x3ec03eb03e803e7, 0x3f203f103ee03ed, 0xffff040203f803f5, 0x400ffff03ff03fc, 0x405040404030401, 0x40b04090407ffff, 0x4120410040e040c, 0x41a041804160414, 0x4220420041e041c, 0x42a042804260424, 0x4320430042e042c, 0x43a043804360434, 0x4420440043e043c, 0x44a044804460444, 0x4520450044e044c, 0x45a045804560454, 0x4620460045e045c, 0x46a046804660464, 0x4330431042f042d, 0x43b043904370435, 0x4430441043f043d, 0x44b044904470445, 0x4530451044f044d, 0x45b045904570455, 0x4630461045f045d, 0x46b046904670465, 0x4130411040f040d, 0x41b041904170415, 0x4230421041f041d, 0x42b042904270425, 0x484048304820481, 0x48a048904880487, 0x4920491048e048d, 0x49a049904960495, 0x4a204a1049e049d, 0x4a804a704a404a3, 0x4ac04ab04aa04a9, 0x4b204b104ae04ad, 0xffffffff04b604b5, 0xffffffffffffffff, 0x4c604c5ffffffff, 0x4cc04cb04c804c7, 0x4d004cf04ce04cd, 0x4d804d704d404d3, 0x4de04dd04da04d9, 0x4e404e304e204e1, 0x4ea04e904e804e7, 0x4f004ef04ec04eb, 0x4f604f504f204f1, 0x4fe04fd04fa04f9, 0x5040503050004ff, 0x508050705060505, 0x510050f050c050b, 0x518051705140513, 0x521051e051d051b, 0x529052605250522, 0x531052e052d052a, 0x51c053605350532, 0x53e053d053c053b, 0x54405430540053f, 0x54a054905480547, 0x550054f054e054d, 0x556055505520551, 0x55c055b05580557, 0x560055f055e055d, 0x568056705640563, 0x56e056d056a0569, 0x57205710570056f, 0x578057705740573, 0x57c057b057a0579, 0x5820581057e057d, 0x588058705840583, 0x58c058b058a0589, 0x5920591058e058d, 0x598059705940593, 0x59c059b059a0599, 0x5a205a1059e059d, 0x5aa05a905a605a5, 0x5ae05ad05ac05ab, 0x5b405b305b005af, 0xffffffffffffffff, 0xffffffffffffffff, 0x5bd05bb05b9ffff, 0x5c505c305c105bf, 0x5cd05cb05c905c7, 0x5d505d305d105cf, 0x5dd05db05d905d7, 0x5e505e305e105df, 0x5ed05eb05e905e7, 0x5f505f305f105ef, 0x5fd05fb05f905f7, 0xffff0603060105ff, 0xffffffffffffffff, 0xffffffffffffffff, 0x5be05bc05baffff, 0x5c605c405c205c0, 0x5ce05cc05ca05c8, 0x5d605d405d205d0, 0x5de05dc05da05d8, 0x5e605e405e205e0, 0x5ee05ec05ea05e8, 0x5f605f405f205f0, 0x5fe05fc05fa05f8, 0x613060406020600, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x8c008a00880086, 0x9400920090008e, 0x9c009a00980096, 0xa400a200a0009e, 0xac00aa00a800a6, 0xb400b200b000ae, 0xbc00ba00b800b6, 0xc400c200c000be, 0x4d100ca04bf04b7, 0x4f7ffff04e500ce, 0xffffffffffffffff, 0xffffffff0539ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff083affff, 0xffffffff0485ffff, 0x648064706460645, 0x64e064d064a0649, 0x654065306520651, 0x65a065906580657, 0x660065f065c065b, 0x666066506620661, 0x66a066906680667, 0x670066f066c066b, 0x674067306720671, 0x678067706760675, 0x67e067d067a0679, 0x68206810680067f, 0x686068506840683, 0x68c068b06880687, 0x690068f068e068d, 0x694069306920691, 0x69a069906960695, 0x69e069d069c069b, 0x6a606a506a206a1, 0x6ac06ab06a806a7, 0x6b006af06ae06ad, 0x6b406b306b206b1, 0x6ba06b906b606b5, 0x6be06bd06bc06bb, 0x6c306c2070d070c, 0x6cb06ca06c706c6, 0x6cf06ce06cd06cc, 0x6d306d206d106d0, 0x6d906d806d506d4, 0x6dd06dc06db06da, 0x6e306e206e106e0, 0x6e906e806e506e4, 0x6ed06ec06eb06ea, 0x6f106f006ef06ee, 0x6f706f606f306f2, 0x6fb06fa06f906f8, 0x6ff06fe06fd06fc, 0x704070207010700, 0x70e070a07080706, 0xffff0710ffffffff, 0x715071407130712, 0x71b071a07170716, 0x71f071e071d071c, 0x723072207210720, 0x729072807270726, 0x72f072e072d072c, 0x733073207310730, 0x737073607350734, 0x73d073c073b073a, 0x743074207410740, 0x747074607450744, 0x74b074a07490748, 0x74f074e074d074c, 0x753075207510750, 0x757075607550754, 0x75b075a07590758, 0x75f075e075d075c, 0x766076507610760, 0x76a076907680767, 0x770076f076e076d, 0x774077307720771, 0x778077707760775, 0x77c077b077a0779, 0x78507840780077f, 0x78e078c078a0788, 0x796079407920790, 0x78f078d078b0789, 0x797079507930791, 0x7a207a0079e079c, 0xffffffff07a607a4, 0x7a307a1079f079d, 0xffffffff07a707a5, 0x7bc07ba07b807b6, 0x7c407c207c007be, 0x7bd07bb07b907b7, 0x7c507c307c107bf, 0x7dc07da07d807d6, 0x7e407e207e007de, 0x7dd07db07d907d7, 0x7e507e307e107df, 0x7f407f207f007ee, 0xffffffff07f807f6, 0x7f507f307f107ef, 0xffffffff07f907f7, 0x80c07fe080807fc, 0x814080408100800, 0x80dffff0809ffff, 0x815ffff0811ffff, 0x828082608240822, 0x830082e082c082a, 0x829082708250823, 0x831082f082d082b, 0x8f708f508df08dd, 0x90f090d08fb08f9, 0x924092209370935, 0xffffffff093b0939, 0x85f085c08590856, 0x86b086808650862, 0x860085d085a0857, 0x86c086908660863, 0x88f088c08890886, 0x89b089808950892, 0x890088d088a0887, 0x89c089908960893, 0x8bf08bc08b908b6, 0x8cb08c808c508c2, 0x8c008bd08ba08b7, 0x8cc08c908c608c3, 0x8e108ce08db08d9, 0x8d708d5ffff08d3, 0x8e008de08dc08da, 0xffff08e7ffff08e2, 0x8fd08e8ffffffff, 0x8f308f1ffff08ed, 0x8fc08fa08f808f6, 0xffffffffffff08fe, 0x9030900090b0909, 0x9070905ffffffff, 0x910090e090c090a, 0xffffffffffffffff, 0x91609130920091e, 0x91c091a09260918, 0x92509230921091f, 0xffffffffffff0927, 0x93d092affffffff, 0x9330931ffff092f, 0x93c093a09380936, 0xffffffffffff093e, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0764ffffffff, 0x1500783ffffffff, 0xffffffffffffffff, 0xffff0561ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0562ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x18d02c2018902b0, 0x195005e019102d6, 0x19d006c01990064, 0x1a5007e01a10076, 0x18e02c3018a02b1, 0x196005f019202d7, 0x19e006d019a0065, 0x1a6007f01a20077, 0x1c0ffffffffffff, 0xffffffffffff01c1, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x5090475ffffffff, 0x511047d050d0477, 0x51904a50515048f, 0x2051f02e80940, 0x6e052707180523, 0x110052f03a4052b, 0x54b053706630533, 0x50e0478050a0476, 0x51604900512047e, 0x2e90941051a04a6, 0x719052400030520, 0x3a5052c006f0528, 0x664053401110530, 0xffffffff054c0538, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xa000800040000, 0x160010000e000c, 0x2ce001c001a0018, 0x56030802e602dc, 0x66006200600058, 0x7800740070006a, 0x2aa00820080007c, 0x64b008400060832, 0x60d060902b805b5, 0x10801060629061d, 0x11c01160112010a, 0xffff0134012c0124, 0xb000900050001, 0x170011000f000d, 0x2cf001d001b0019, 0x57030902e702dd, 0x67006300610059, 0x7900750071006b, 0x2ab00830081007d, 0x64c008500070833, 0x60e060a02b905b6, 0x1090107062a061e, 0x11d01170113010b, 0xffff0135012d0125, 0x486055a04f404f3, 0x48b0297029102b5, 0x49302bb02ba048c, 0x49c02c704980494, 0x2cd02ccffff02cb, 0xffff02d502d4ffff, 0xffffffffffffffff, 0x4b402edffffffff, 0x4ba04b902f902f8, 0x4be04bd04bc04bb, 0x325032404c204c1, 0x3350334032b032a, 0x3410340033d033c, 0x34f034e034d034c, 0x73f073e03230322, 0x3b003af03ae03ad, 0x3bf03be03b403b3, 0x3e203e103d203d1, 0x606060505a405a3, 0x6320631061a0619, 0x6a0069f06560655, 0x7390738046f046e, 0x7d507d4077e077d, 0x6df06de08350834, 0x15001406a406a3, 0x4ee04ed005d005c, 0x612061105020501, 0x542054101aa01a9, 0x566056505540553, 0x586058505760575, 0x5a805a705960595, 0x162016105b805b7, 0x3ea03e903a703a6, 0xffffffffffffffff, 0x60fffffffffffff, 0xffff061806170610, 0x6240623ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x8d008b00890087, 0x9500930091008f, 0x9d009b00990097, 0xa500a300a1009f, 0xad00ab00a900a7, 0xb500b300b100af, 0xbd00bb00b900b7, 0xc500c300c100bf, 0x4d200cb04c004b8, 0x4f8ffff04e600cf, 0xffffffffffffffff, 0xffffffff053affff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x616061502d902d8, 0x6220621061c061b, 0x1e501e406280627, 0x6340633062e062d, 0x63e063d06380637, 0x32f032e06420641, 0x66e066d065e065d, 0x68a0689067c067b, 0x6aa06a906980697, 0x6c906c806b806b7, 0x6e706e606d706d6, 0xffffffff06f506f4, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x69006807870786, 0x7b107b0028f028e, 0x3bd03bc07c907c8, 0x8030802001f001e, 0x2b302b208190818, 0x2d302d208370836, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x7ab07aaffffffff, 0x7b307b207af07ae, 0x2f502f402eb02ea, 0x311031003070306, 0x7cb07caffffffff, 0x7d307d207cf07ce, 0x33b033a03330332, 0x3490348033f033e, 0x7e907e807e707e6, 0x7ed07ec07eb07ea, 0x3b203b103ac03ab, 0x7fb07fa03bb03ba, 0x3f003ef03dc03db, 0x28302820620061f, 0x80b080a08070806, 0x8130812080f080e, 0x81b081a08170816, 0x8210820081f081e, 0x4b004af04a0049f, 0x4d604d504c404c3, 0xffffffffffffffff, 0xffffffffffffffff, 0x83805460545ffff, 0x83d083c083b0839, 0x590058f0580057f, 0x5b205b105a0059f, 0x63bffffffffffff, 0xffffffff079b063c, 0x60c060b06080607, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x630062f062c062b, 0x63a063906360635, 0xffff06440640063f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2fc02fa025e02f6, 0xffff0304030302fe, 0xffffffffffffffff, 0xffffffffffffffff, 0x30cffffffffffff, 0x314031202c0030e, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x7ac02da07a8ffff, 0x7b402e402e202e0, 0x144076b02f00724, 0x318081c030a0479, 0x7cc031c031a07c6, 0x32c022c07d00320, 0xffff046c0336007a, 0xffffffffffffffff, 0x7ad02db07a9ffff, 0x7b502e502e302e1, 0x145076c02f10725, 0x319081d030b047a, 0x7cd031d031b07c7, 0x32d022d07d10321, 0xffff046d0337007b, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x72005a09280012, 0x114010c03520338, 0x2f202ae02bc0625, 0x10e064f031608ef, 0x4fb029a02ee02b6, 0x2de02d002c802be, 0x330031e047f0798, 0x3b802c4024e0342, 0x473056b047b03e5, 0x91104df072a06c4, 0x73005b09290013, 0x115010d03530339, 0x2f302af02bd0626, 0x10f0650031708f0, 0x4fc029b02ef02b7, 0x2df02d102c902bf, 0x331031f04800799, 0x3b902c5024f0343, 0x474056c047c03e6, 0x91204e0072b06c5, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff]); //4000 bytes enum alphaTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0xb0], [ 0x100, 0x240, 0x5100], [ 0x706050403020100, 0xe0d0c0a0b0a0908, 0x100a0f0303030303, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x7000600050004, 0xb000a00090008, 0xf000e000d000c, 0x12001100010010, 0x15001400010013, 0x19001800170016, 0x1c0001001b001a, 0x1f001f001e001d, 0x1f001f001f0020, 0x1f001f001f001f, 0x1f002300220021, 0x1f001f00250024, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100260001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x27000100010001, 0x1000100010001, 0x2a002900010028, 0x2e002d002c002b, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x2f000100010001, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x3100300001001f, 0x34003300320001, 0x38003700360035, 0x1f001f001f0039, 0x3d003c003b003a, 0x1f001f001f003e, 0x1f001f0040003f, 0x1f0041001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x42000100010001, 0x1f001f001f0043, 0x1f001f001f001f, 0x1f001f001f001f, 0x1000100010001, 0x1f001f001f0044, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f004500010001, 0x46001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f0047, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x4b004a00490048, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f004c001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1000100010001, 0x1004d00010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x4e000100010001, 0x1f001f001f004f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f004f00010001, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x1f001f001f001f, 0x0, 0x7fffffe07fffffe, 0x420040000000000, 0xff7fffffff7fffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x501f0003ffc3, 0x0, 0x3cdf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, 0xfffe00ffffffffff, 0xfffffffe027fffff, 0xbfff0000000000ff, 0x707ffffff00b6, 0xffffffff07ff0000, 0xffffc000feffffff, 0xffffffffffffffff, 0x9c00e1fe1fefffff, 0xffffffffffff0000, 0xffffffffffffe000, 0x3ffffffffffff, 0x43007fffffffc00, 0x1ffffcffffff, 0x1ffffff, 0x1ffd00000000, 0x7fff03f000000000, 0xefffffffffffffff, 0xfefe000fffe1dfff, 0xe3c5fdfffff99fee, 0x3000fb080599f, 0xc36dfdfffff987ee, 0x3f00005e021987, 0xe3edfdfffffbbfee, 0xf00011bbf, 0xe3edfdfffff99fee, 0x2000fb0c0199f, 0xc3ffc718d63dc7ec, 0x811dc7, 0xe3effdfffffddfee, 0xf03601ddf, 0xe3effdfffffddfec, 0x6000f40601ddf, 0xe7fffffffffddfec, 0xfc00000f00805ddf, 0x2ffbfffffc7fffec, 0xc0000ff5f807f, 0x7fffffffffffffe, 0x207f, 0x3bffecaefef02596, 0xf000205f, 0x1, 0xfffe1ffffffffeff, 0x1ffffffffeffff03, 0x0, 0xf97fffffffffffff, 0xffffc1e7ffff0000, 0xffffffff3000407f, 0xf7ffffffffff20bf, 0xffffffffffffffff, 0xffffffff3d7f3dff, 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x87ffffff, 0xffffffff0000ffff, 0x1fffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x1c7ffffffffff, 0xfffff000fdfff, 0xddfff000fffff, 0xffcfffffffffffff, 0x108001ff, 0xffffffff00000000, 0xffffffffffffff, 0xffff07ffffffffff, 0x3fffffffffffff, 0x1ff0fff1fffffff, 0x1f3fffffff0000, 0xffff0fffffffffff, 0x3ff, 0xffffffff0fffffff, 0x1ffffe7fffffff, 0x8000000000, 0x0, 0xffefffffffffffff, 0xfef, 0xfc00f3ffffffffff, 0x3ffbfffffffff, 0x3fffffffffffff, 0x3ffffffffc00e000, 0x0, 0x6fde0000000000, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x0, 0x8002000000000000, 0x1fff0000, 0x0, 0xf3ffbd503e2ffc84, 0xffffffff000043e0, 0x1ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000000000000, 0x3ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0xffffffffffffffff, 0xc781fffffffff, 0xffff20bfffffffff, 0x80ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, 0x800000000000, 0x0, 0x0, 0x0, 0x1f3e03fe000000e0, 0xfffffffffffffffe, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe3fffffffffe0, 0xffffffffffffffff, 0x7ffffff00007fff, 0xffff000000000000, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffff, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1fff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1fff, 0x3fffffffffff0000, 0xc00ffff1fff, 0x8ff07fffffffffff, 0xffffffff80ffffff, 0xffffffffffff, 0xfffffffcff800000, 0xffffffffffffffff, 0x7ff000f79ff, 0xff00000000000000, 0xfffffff7bb, 0xfffffffffffff, 0xffffffffffffffff, 0x8fc00000000000f, 0xffff07fffffffc00, 0x1fffffff0007ffff, 0xfff7ffffffffffff, 0x8000, 0x7fffffffffffff, 0x47fffff00003fff, 0x7fffffffffffffff, 0x3cffff38000005, 0x7f7f007e7e7e, 0x0, 0x0, 0x7ffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff000fffffffff, 0xffffffffffff87f, 0xffffffffffffffff, 0xffff3fffffffffff, 0xffffffffffffffff, 0x3ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0x3ffffffffffff, 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, 0xfff0000000000ff, 0x0, 0xffdf000000000000, 0xffffffffffffffff, 0x1fffffffffffffff, 0x7fffffe00000000, 0xffffffc007fffffe, 0x7fffffffffffffff, 0x1cfcfcfc, 0xb7ffff7fffffefff, 0x3fff3fff, 0xffffffffffffffff, 0x7ffffffffffffff, 0x0, 0x1fffffffffffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff1fffffff, 0x1ffff, 0xffff00007fffffff, 0x7ff, 0xffffffff3fffffff, 0x3eff0f, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffff, 0x0, 0x91bffffffffffd3f, 0x3fffff, 0x0, 0x0, 0x3ffffff003fffff, 0x0, 0xc0ffffffffffffff, 0x0, 0xffffffeeff06f, 0x1fffffff00000000, 0x0, 0x0, 0x3fffffffffffff, 0x7ffff003fffff, 0x0, 0x0, 0xffffffffffffffff, 0x1ff, 0x0, 0x0, 0xffffffffffffffff, 0x3f, 0x1fffffffffffffc, 0x1ffffff0000, 0x7ffffffffffff, 0x0, 0xffffffffffffffff, 0x1e, 0x0, 0x0, 0x3fffffffffffff, 0x0, 0xffffffffffffffff, 0x7fffffffffff, 0x0, 0x0, 0xffffffffffffffff, 0x7ffffffff, 0x0, 0x0, 0x7fffffffffff, 0x0, 0x0, 0x0, 0x1ffffffffffffff, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0x7fffffffffff001f, 0xfff80000, 0x0, 0x3, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0xff7, 0xaf7fe96ffffffef, 0x5ef7f796aa96ea84, 0xffffbee0ffffbff, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffff, 0x1fffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffff, 0x0, 0x0, 0x0, 0x3fffffff, 0x0, 0x0, 0x0]); //2304 bytes enum markTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x70], [ 0x100, 0x140, 0x2c00], [ 0x402030202020100, 0x207020206020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020208, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000, 0x5000400030002, 0x9000800070006, 0xd000c000b000a, 0xf00000000000e, 0x10000000000000, 0x14001300120011, 0x160015, 0x17, 0x0, 0x0, 0x190018, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b00000000, 0x1f001e001d001c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000000, 0x2100000000, 0x220000, 0x0, 0x2300000000, 0x0, 0x250024, 0x2600000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x27000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2900280000, 0x0, 0x0, 0x0, 0x2a0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffff, 0x0, 0x0, 0x0, 0x0, 0x3f8, 0x0, 0x0, 0x0, 0xbffffffffffe0000, 0xb6, 0x7ff0000, 0x10000fffff800, 0x0, 0x3d9f9fc00000, 0xffff000000020000, 0x7ff, 0x1ffc000000000, 0xff80000000000, 0x3eeffbc00000, 0xe000000, 0x0, 0x7ffffff000000000, 0xdc0000000000000f, 0xc00feffff, 0xd00000000000000e, 0xc0080399f, 0xd00000000000000e, 0x23000000023987, 0xd00000000000000e, 0xc00003bbf, 0xd00000000000000e, 0xc00c0399f, 0xc000000000000004, 0x803dc7, 0xc00000000000000e, 0xc00603ddf, 0xd00000000000000c, 0xc00603ddf, 0xc00000000000000c, 0xc00803ddf, 0xc, 0xc0000ff5f8400, 0x7f2000000000000, 0x7f80, 0x1bf2000000000000, 0x3f00, 0xc2a0000003000000, 0xfffe000000000000, 0x1ffffffffeffe0df, 0x40, 0x7ffff80000000000, 0x1e3f9dc3c00000, 0x3c00bffc, 0x0, 0x0, 0xe0000000, 0x0, 0x0, 0x1c0000001c0000, 0xc0000000c0000, 0xfff0000000000000, 0x200fffff, 0x3800, 0x0, 0x20000000000, 0x0, 0xfff0fff00000000, 0x0, 0xffff000000000000, 0x301, 0xf800000, 0x9fffffff7fe00000, 0x0, 0x0, 0xfff000000000001f, 0xff8000000001f, 0x3ffe00000007, 0xfffc000000000, 0xfffff000000000, 0x0, 0x0, 0x1c21fffff70000, 0x0, 0x0, 0x0, 0xf000007fffffffff, 0x0, 0x0, 0x0, 0x1ffffffff0000, 0x0, 0x0, 0x0, 0x3800000000000, 0x0, 0x8000000000000000, 0x0, 0xffffffff00000000, 0xfc0000000000, 0x0, 0x6000000, 0x0, 0x0, 0x3ff7800000000000, 0x80000000, 0x3000000000000, 0xf800000844, 0x0, 0xfff0000000000003, 0x3ffff0000001f, 0x3fc000000000, 0xfff80, 0xfff800000000000f, 0x1, 0x7ffe0000000000, 0x800000000003008, 0xc19d000000000000, 0x60f80000000002, 0x0, 0x0, 0x0, 0x37f800000000, 0x40000000, 0x0, 0x0, 0x0, 0x7f0000ffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000000000, 0x870000000000f06e, 0x0, 0x0, 0x0, 0xff00000000000007, 0x7f, 0x7ff000000000007, 0x0, 0x1fff8000000007, 0x0, 0xfff8000000000007, 0x1, 0x0, 0x0, 0xfff80000000000, 0x0, 0x0, 0x7ffffffffffe0000, 0x78000, 0x0, 0x0, 0xf807e3e000000000, 0x3c0000000fe7, 0x0, 0x0, 0x1c, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff, 0x0, 0x0, 0x0, 0x0]); //2384 bytes enum numberTrieEntries = TrieEntry!(bool, 8, 6, 7)([ 0x0, 0x20, 0xc0], [ 0x100, 0x280, 0x1a80], [ 0x402030202020100, 0x807020202020605, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000200010000, 0x2000200020002, 0x2000200020002, 0x5000200040003, 0x7000600020002, 0x9000800060006, 0x2000b0006000a, 0x2000d000c000c, 0x20002000e0005, 0x2000f00020002, 0x2000200020002, 0x11000200100002, 0x1300120002000e, 0xc00140002, 0x2000200020015, 0x2000200020002, 0x19001800170016, 0x2000200020002, 0x20002001b001a, 0x1d001c00020002, 0x2000200020002, 0x2000200020002, 0x20002001e0002, 0x2000200020002, 0x2000020002001f, 0x2000200220021, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200060023, 0xc0017000c0024, 0x400020002000c, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000e00020002, 0x26002500020002, 0x28002700020002, 0x2000200230002, 0x2000200020002, 0x2002a00020029, 0x2002c0002002b, 0x2000200020002, 0x200020002002d, 0xc002f0004002e, 0x2000200020002, 0x2000200020002, 0x2000200050002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020030, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2003100020002, 0x2000200020002, 0x32000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2003300020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x2000200020002, 0x3ff000000000000, 0x0, 0x720c000000000000, 0x0, 0x0, 0x0, 0x0, 0x3ff00000000, 0x0, 0x3ff000000000000, 0x0, 0x3ff, 0x0, 0xffc000000000, 0x0, 0x3f0ffc000000000, 0x0, 0xfcffc000000000, 0x0, 0x7ffc000000000, 0x0, 0x7f00ffc000000000, 0x0, 0x3fffc000000000, 0x0, 0x3ff0000, 0xfffff00000000, 0x0, 0x3ff0000, 0x0, 0x0, 0x1ffffe0000000000, 0x0, 0x1c00000000000, 0x0, 0x3ff03ff00000000, 0x0, 0xffc0, 0x0, 0x7ff0000, 0x3ff03ff, 0x0, 0x0, 0x3ff03ff, 0x0, 0x3f1000000000000, 0x3ff, 0x0, 0x0, 0xffffffffffff0000, 0x3e7, 0x0, 0x0, 0xffffffff00000000, 0xfffffff, 0xfffffc0000000000, 0x0, 0xffc0000000000000, 0xfffff, 0x0, 0x0, 0x2000000000000000, 0x70003fe00000080, 0x0, 0x3c0000, 0x0, 0x3ff00000000, 0xfffeff00, 0xfffe0000000003ff, 0x0, 0x3ff00000000, 0x0, 0x3f000000000000, 0x0, 0xfffffffffff80, 0x1ffffffffffffff, 0x400, 0x0, 0xf00000000, 0x402, 0x0, 0x3e0000, 0x0, 0xff000000, 0xfc00000, 0x0, 0x0, 0x60000000000000ff, 0x0, 0xff000000ff000000, 0x0, 0x7fffffff00000000, 0x0, 0xfffffffc0000, 0xffc0000000000000, 0x0, 0xffffffffffffffff, 0x7ffffffff, 0x0, 0x3ffff00000000, 0x0, 0xffffffffffffc000, 0x7ff, 0x0, 0x0, 0x0]); //2336 bytes enum punctuationTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x60], [ 0x100, 0x100, 0x3100], [ 0x402030202020100, 0x202020202020605, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000100010000, 0x5000400030001, 0x1000800070006, 0xb000a00090001, 0xd00010001000c, 0x10000f0001000e, 0x14001300120011, 0x1000100010015, 0x17000100010016, 0x18000100010001, 0x1000100190001, 0x1001c001b001a, 0x100010001001d, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1001f0001001e, 0x23002200210020, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x26002500240001, 0x28000100270001, 0x1000100010001, 0x2c002b002a0029, 0x1000100010001, 0x10001002e002d, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x100010001002f, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x8c00f7ee00000000, 0x28000000b8000001, 0x88c0088200000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000000000, 0x80, 0x0, 0x0, 0xfc000000, 0x4000000000000600, 0x18000000000049, 0xc8003600, 0x3c0000000000, 0x0, 0x100000, 0x3fff, 0x0, 0x0, 0x380000000000000, 0x7fff000000000000, 0x40000000, 0x0, 0x0, 0x0, 0x1003000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000, 0x0, 0x0, 0x0, 0x10000000000000, 0x0, 0xc008000, 0x0, 0x0, 0x3c0000000017fff0, 0x0, 0x20, 0x61f0000, 0x0, 0xfc00, 0x0, 0x800000000000000, 0x0, 0x1ff00000000, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x600000000000, 0x18000000, 0x380000000000, 0x60000000000000, 0x0, 0x0, 0x7700000, 0x7ff, 0x0, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0xc0000000, 0x0, 0x3f7f00000000, 0x0, 0x0, 0x1fc000000, 0x0, 0xf000000000000000, 0xf800000000000000, 0xc000000000000000, 0x0, 0x800ff, 0xffff00ffffff0000, 0x600000007ffbffef, 0x6000, 0x0, 0x60000000f00, 0x0, 0x0, 0x0, 0x0, 0x3fff0000000000, 0x0, 0xffc000000060, 0x0, 0x0, 0x1fffff8, 0x300000000f000000, 0x0, 0x0, 0x0, 0xde00000000000000, 0x0, 0x1000000000000, 0x0, 0x0, 0xfff7fffffffffff, 0x0, 0x0, 0x0, 0x20010000fff3ff0e, 0x0, 0x100000000, 0x800000000000000, 0x0, 0x0, 0x0, 0xc000000000000000, 0xe000, 0x4008000000000000, 0x0, 0xfc000000000000, 0x0, 0xf0000000000000, 0x0, 0x70000000000c000, 0xc00000000000, 0x80000000, 0x0, 0xc0003ffe, 0x0, 0xf0000000, 0x0, 0x30000c0000000, 0x0, 0x0, 0x0, 0x80000000000, 0xc000000000000000, 0x0, 0x0, 0x0, 0xffff000003ff0000, 0xd0bfff7ffff, 0x0, 0x0, 0xb80000018c00f7ee, 0x3fa8000000, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x10000, 0x0, 0x800000, 0x0, 0x0, 0x8000000080000000, 0x0, 0x0, 0x0, 0x0, 0x8000000001ff0000, 0x0, 0x0, 0xfe00000000000000, 0x0, 0x0, 0x0, 0x0, 0x3f80, 0xd800000000000000, 0x3, 0x0, 0xf, 0x0, 0x1e0, 0x0, 0xf000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2848 bytes enum symbolTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x70], [ 0x100, 0x140, 0x3d00], [ 0x503040303020100, 0x807030303030306, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x303030303030303, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x7000600050004, 0xa000900080001, 0xe000d000c000b, 0x1000010001000f, 0x11000100010001, 0x13000100120001, 0x14000100010001, 0x18001700160015, 0x1a001700170019, 0x1c0017001b0017, 0x1f001e0001001d, 0x17002200210020, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100230001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x25000100010024, 0x1002700010026, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x28000100010001, 0x2b002a00290001, 0x10001002c0001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x30002f002e002d, 0x32003100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1003300010001, 0x37003600350034, 0x3b003a00390038, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x7000081000000000, 0x5000000140000000, 0x113d37c00000000, 0x80000000800000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffafe0fffc003c, 0x0, 0x20000000000000, 0x30, 0x40000000000000, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x8000, 0x0, 0xc9c0, 0x0, 0x0, 0x6000020040000000, 0x0, 0x0, 0x0, 0x40000000000000, 0x0, 0x0, 0x0, 0xc0c000000000000, 0x0, 0x0, 0x0, 0x2000000000000, 0x0, 0x1000000000000, 0x0, 0x7f8000000000000, 0x0, 0x8000000000000000, 0x0, 0x0, 0x0, 0x200000000000000, 0x0, 0x0, 0x8000000000000000, 0x0, 0x0, 0x0, 0x1500000fce8000e, 0x0, 0xc000000000000000, 0x1e0dfbf, 0x0, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x3ff0000, 0x0, 0x0, 0x0, 0x0, 0x8000000, 0x0, 0x1, 0x0, 0xffffffffc0000000, 0x0, 0x1ff007fe00000000, 0x0, 0x0, 0x0, 0x0, 0xa000000000000000, 0x6000e000e000e003, 0x0, 0x1c00000000040010, 0x7ffffff00001c00, 0x0, 0xc0042afc1d0037b, 0xbc1f, 0xffffffffffff0000, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffff9fffffff0ff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffff, 0x7fffffffff, 0x7ff, 0xfffffffff0000000, 0x3ffffffffff, 0xfffffffffffffffe, 0xffffffffff, 0xfffffffffff00000, 0xffff003fffffff9f, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffe000007, 0xcffffffff0ffffff, 0xffffffffffffffff, 0x3ff1fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e000000000, 0x0, 0x0, 0xfffffffffbffffff, 0xfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfff0000003fffff, 0xc0c00001000c0010, 0x0, 0x18000000, 0x0, 0x0, 0x0, 0xffc30000, 0xfffffffff, 0xfffffc007fffffff, 0xffffffff000100ff, 0x1fffffffffc00, 0x7fffffffffffffff, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0x0, 0x0, 0xffffffffffff0000, 0x7f, 0x3007fffff, 0x0, 0x600, 0x0, 0x3c00f0000000000, 0x0, 0x0, 0x0, 0x0, 0x380000000000000, 0x0, 0x0, 0x20000000000, 0x0, 0xfffc000000000000, 0x3, 0x0, 0x0, 0x0, 0x3000000000000000, 0x0, 0x27400000000, 0x0, 0x0, 0x4000000070000810, 0x50000001, 0x0, 0x30007f7f00000000, 0xff80000000000000, 0xfe00000000000000, 0xfff03ff, 0x1fffffffffff0000, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffff, 0xfffffe7fffffffff, 0x1c1fffffffff, 0xffffc3fffffff018, 0x3fffffff, 0xffffffffffffffff, 0x23, 0x0, 0x0, 0xffffffffffffffff, 0x7fffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800000008000002, 0x20000000200000, 0x800000008000, 0x20000000200, 0x8, 0x0, 0x0, 0x0, 0x3000000000000, 0xffff0fffffffffff, 0xffffffffffffffff, 0x7ffe7fff000fffff, 0xfffefffe, 0xffff7fffffff0000, 0xffff0fffffffffff, 0x7ffffff, 0xffffffc000000000, 0x7ffffffffff0007, 0x301ff, 0x0, 0x0, 0xffbf0001ffffffff, 0x1fffffffffffffff, 0xffffffff000fffff, 0x1ffff000007df, 0x7fffffffffffffff, 0xfffffffffffffffd, 0xffffffffffffffff, 0x1effffffffffffff, 0x3fffffffffffffff, 0xffffff000f, 0x0, 0xf800000000000000, 0xffffffffffffffff, 0xffe1, 0xffffffffffffffff, 0x3f, 0xffffffffffffffff, 0xfffffffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //4576 bytes enum graphicalTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0xb8], [ 0x100, 0x260, 0x6100], [ 0x706050403020100, 0xe0d0c0a0b0a0908, 0x100a0f0303030303, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a11, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000100010000, 0x5000400030001, 0x9000800070006, 0xd000c000b000a, 0x10000f0001000e, 0x12001100010001, 0x16001500140013, 0x19000100180017, 0x1c0001001b001a, 0x1e00010001001d, 0x1f000100010001, 0x23002200210020, 0x1002600250024, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100270001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x28000100010001, 0x1000100010001, 0x2b002a00010029, 0x2f002e002d002c, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x30000100010001, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x33003200010031, 0x36003500340001, 0x3a003900380037, 0x3100310031003b, 0x3f003e003d003c, 0x31004100310040, 0x31003100430042, 0x31004400310031, 0x31003100310031, 0x31003100310031, 0x45000100010001, 0x31003100310046, 0x31003100310031, 0x31003100310031, 0x1000100010001, 0x31003100310047, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31004800010001, 0x49003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x3100310031004a, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x4e004d004c004b, 0x5200510050004f, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31005300310031, 0x57005600550054, 0x5b005a00590058, 0x31003100310031, 0x31003100310031, 0x1000100010001, 0x1005c00010001, 0x1000100010001, 0x1000100010001, 0x1000100010001, 0x5d000100010001, 0x3100310031005e, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31005e00010001, 0x31003100310031, 0x310031005f0031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0x31003100310031, 0xffffffff00000000, 0x7fffffffffffffff, 0xffffdfff00000000, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x7cffffffffffffff, 0xfffffffbffffd7f0, 0xffffffffffffffff, 0xfffe00ffffffffff, 0xfffffffefe7fffff, 0xfffffffffffe86ff, 0x1f07ffffff00ff, 0xffffffffcfffffc0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffdfffffff, 0xffffffffffff3fff, 0xffffffffffffe7ff, 0x3ffffffffffff, 0x7ffffffffffffff, 0x7fff3fffffffffff, 0x4fffffff, 0x1ffd00000000, 0x7ffffff000000000, 0xffffffffffffffff, 0xfeffffffffffffff, 0xf3c5fdfffff99fee, 0xfffffcfb080799f, 0xd36dfdfffff987ee, 0x3fffc05e023987, 0xf3edfdfffffbbfee, 0x3ffcf00013bbf, 0xf3edfdfffff99fee, 0xffffcfb0c0399f, 0xc3ffc718d63dc7ec, 0x7ffffc000813dc7, 0xe3effdfffffddfee, 0xff00ffcf03603ddf, 0xf3effdfffffddfec, 0x6ffcf40603ddf, 0xe7fffffffffddfec, 0xfe3fffcf00807ddf, 0x2ffbfffffc7fffec, 0x1c0000ff5f847f, 0x87fffffffffffffe, 0xfffffff, 0x3bffecaefef02596, 0xf3ff3f5f, 0xffffffffffffffff, 0xfffe1ffffffffeff, 0xdffffffffeffffff, 0x7ffdfff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff20bf, 0xffffffffffffffff, 0xffffffff3d7f3dff, 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x1fffffffe7ffffff, 0xffffffff03ffffff, 0x1fffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff1fffffff, 0x1ffffffffffff, 0x7fffff001fdfff, 0xddfff000fffff, 0xffffffffffffffff, 0x3ff03ff3fffffff, 0xffffffff03ff3fff, 0xffffffffffffff, 0xffff07ffffffffff, 0x3fffffffffffff, 0xfff0fff1fffffff, 0x1f3ffffffffff1, 0xffff0fffffffffff, 0xffffffffc7ff03ff, 0xffffffffcfffffff, 0x9fffffff7fffffff, 0x3fff03ff03ff, 0x0, 0xffffffffffffffff, 0x1fffffffffff0fff, 0xffffffffffffffff, 0xf00fffffffffffff, 0xf8ffffffffffffff, 0xffffffffffffe3ff, 0x0, 0x7fffffffff00ff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xf000007fffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0xffdfffffffffffff, 0x7fdcffffefcfffdf, 0xffff80ffffff07ff, 0xfff30000ffffffff, 0x7ffffff1fff7fff, 0x1ffffffff0000, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff03ff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffff, 0x7fffffffff, 0xffffffff000007ff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3ff1fff, 0x0, 0x0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0xffffffffffffffff, 0xfe0fffffffffffff, 0xffff20bfffffffff, 0x800180ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, 0xfffffffffffffff, 0x0, 0xfffffffffbffffff, 0xfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfff0000003fffff, 0xffffffffffffffff, 0xfffffffffffffffe, 0xfffffffffe7fffff, 0xffffffffffffffff, 0xfffe3fffffffffe0, 0xffffffffffffffff, 0x7ffffffffff7fff, 0xffff000fffffffff, 0xffffffff7fffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1fff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff1fff, 0xffffffffffff007f, 0xfffffffffff, 0xffffffffffffffff, 0xffffffff80ffffff, 0xffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x7ff000f7fff, 0xff00000000000000, 0x3ff0fffffffffff, 0xffffffffffffff, 0xffffffffffffffff, 0xfffffff03ffc01f, 0xffffffffffffffff, 0x1fffffff800fffff, 0xffffffffffffffff, 0xc3ffbfff, 0x7fffffffffffff, 0xffffffff3ff3fff, 0xffffffffffffffff, 0x7ffffff8000007, 0x7f7f007e7e7e, 0x0, 0x0, 0x3ff3fffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff000fffffffff, 0xffffffffffff87f, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffff3fffffffffff, 0xffffffffffffffff, 0x3ffffff, 0x5f7fffffe0f8007f, 0xffffffffffffffdb, 0xffffffffffffffff, 0xfffffffffff80003, 0xffffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, 0x3fff0000000000ff, 0xffff007f03ffffff, 0xffdf0f7ffff7ffff, 0xffffffffffffffff, 0x1fffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff, 0x7fffffffffffffff, 0x30007f7f1cfcfcfc, 0xb7ffff7fffffefff, 0x3fff3fff, 0xffffffffffffffff, 0x7ffffffffffffff, 0xff8fffffffffff87, 0xffffffffffffffff, 0xfff07ff, 0x3fffffffffff0000, 0x0, 0x0, 0xffffffff1fffffff, 0x1ffff, 0xffff000f7fffffff, 0x7ff, 0xffffffffbfffffff, 0x3fff0f, 0xffffffffffffffff, 0xffffffffffffffff, 0x3ff3fffffff, 0x0, 0x91bffffffffffd3f, 0xffbfffff, 0x0, 0x0, 0x83ffffff8fffffff, 0x0, 0xc0ffffffffffffff, 0x0, 0x870ffffffeeff06f, 0xffffffff01ff00ff, 0x0, 0x0, 0xfe3fffffffffffff, 0xff07ffffff3fffff, 0x0, 0x0, 0xffffffffffffffff, 0x1ff, 0x0, 0x0, 0x0, 0x7fffffff00000000, 0x0, 0x0, 0xffffffffffffffff, 0xfffffffc3fff, 0xdfffffffffffffff, 0x3ff01ffffff0003, 0xffdfffffffffffff, 0xf, 0xffffffffffffffff, 0x3ff01ff, 0x0, 0x0, 0xffffffffffffff, 0x3ff, 0xffffffffffffffff, 0x7fffffffffff, 0x0, 0x0, 0xffffffffffffffff, 0xf0007ffffffff, 0x0, 0x0, 0x7fffffffffff, 0x0, 0x0, 0x0, 0x1ffffffffffffff, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0x7fffffffffff001f, 0xffff8000, 0x0, 0x3, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffff, 0xfffffe7fffffffff, 0xf807ffffffffffff, 0xffffffffffffffff, 0x3fffffff, 0xffffffffffffffff, 0x3f, 0x0, 0x0, 0xffffffffffffffff, 0x3ffff007fffff, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffff3fffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffcfff, 0xaf7fe96ffffffef, 0x5ef7f796aa96ea84, 0xffffbee0ffffbff, 0x3000000000000, 0xffff0fffffffffff, 0xffffffffffffffff, 0x7ffe7fff000fffff, 0xfffefffe, 0xffff7fffffff07ff, 0xffff0fffffffffff, 0x7ffffff, 0xffffffc000000000, 0x7ffffffffff0007, 0x301ff, 0x0, 0x0, 0xffbf0001ffffffff, 0x1fffffffffffffff, 0xffffffff000fffff, 0x1ffff000007df, 0x7fffffffffffffff, 0xfffffffffffffffd, 0xffffffffffffffff, 0x1effffffffffffff, 0x3fffffffffffffff, 0xffffff000f, 0x0, 0xf800000000000000, 0xffffffffffffffff, 0xffe1, 0xffffffffffffffff, 0x3f, 0xffffffffffffffff, 0xfffffffffffff, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffff, 0x1fffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffff, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff, 0x0, 0x0, 0x0, 0x0]); //3664 bytes enum nonCharacterTrieEntries = TrieEntry!(bool, 7, 4, 4, 6)([ 0x0, 0x10, 0x4c, 0x104], [ 0x80, 0xf0, 0x2e0, 0x3180], [ 0x706050403020100, 0xb0b0b0b0a090808, 0xb0b0b0b0b0b0b0b, 0xb0b0b0b0b0b0b0b, 0xb0b0b0b0b0b0b0b, 0xb0b0b0b0b0b0b0b, 0xb0b0b0b0b0b0b0b, 0xd0808080b0b0b0c, 0xd080808, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x7000600050004, 0xb000a00090008, 0xd000d000d000c, 0xe000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0xf000d000d000d, 0xd00110010000d, 0xd000d000d000d, 0xd000d000d000d, 0xd000d0012000d, 0xd000d000d000d, 0x140013000d000d, 0x18001700160015, 0x1b001b001a0019, 0x1b001b001d001c, 0x1b001b001e000d, 0x1b001b001b001b, 0x1b001b001b001b, 0x20001f001b001b, 0x1b001b001b001b, 0x1b001b001b001b, 0x1b001b001b001b, 0x1b001b001b001b, 0x1b001b001b0021, 0x1b001b001b001b, 0x1b001b00230022, 0x24001b001b001b, 0x1b001b00260025, 0xd000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0xd000d0027000d, 0x1b00290028000d, 0x1b001b001b001b, 0x1b001b001b001b, 0x1b001b001b001b, 0x1b002a001b001b, 0x1b001b001b001b, 0x1b001b001b001b, 0x1b001b001b001b, 0x1b001b001b001b, 0x1b001b001b002b, 0x1b001b001b001b, 0x1b001b001b001b, 0x1b001b001b001b, 0xd000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0x2c000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0xd000d000d000d, 0x2c000d000d000d, 0x0, 0x0, 0x0, 0x200010000, 0x0, 0x6000500040003, 0x7, 0xb000a00090008, 0xf000e000d000c, 0x12001100100000, 0x16001500140013, 0x1a001900180017, 0x1e001d001c001b, 0x2200210020001f, 0x26002500240023, 0x29002800270000, 0x2a000000000000, 0x0, 0x2d002c002b0000, 0x310030002f002e, 0x0, 0x0, 0x33003200000000, 0x36000000350034, 0x3a003900380037, 0x3e003d003c003b, 0x4200410040003f, 0x44000000430000, 0x47004200460045, 0x48000000000000, 0x0, 0x4c004b004a0049, 0x4f004e004d0000, 0x5000000000, 0x0, 0x51000000000000, 0x530052, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x42004200550000, 0x58000000570056, 0x5c005b005a0059, 0x51005e0042005d, 0x5f000000000000, 0x6000540000, 0x63006200000061, 0x64000000000057, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x65000000000000, 0x67006600000000, 0x0, 0x38006900000068, 0x6b006a00000000, 0x6d00000038006c, 0x6f0000006e0000, 0x72000000710070, 0x74004200420073, 0x0, 0x0, 0x0, 0x75006300000000, 0x0, 0x0, 0x77000000760000, 0x7a000000790078, 0x0, 0x7d007c007b0000, 0x800000007f007e, 0x81006400000054, 0xb000000830082, 0x86008500000084, 0x87003200420042, 0x8b008a00890088, 0x42008c00000000, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x420042008e008d, 0x4200900042008f, 0x42004200920091, 0x42004200940093, 0x42004200950000, 0x42004200420042, 0x42004200960042, 0x42004200420042, 0x98000000970000, 0x9a00000099004b, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x9b003800420042, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x0, 0x0, 0x0, 0x420042009c0000, 0x420042009d0000, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x4200420042009c, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x0, 0x0, 0x4200420042009e, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x4200a0009f0000, 0x420042004200a1, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x3a000000000000, 0xa30000000000a2, 0x42004200a40000, 0x42004200a50000, 0xa800a700a60000, 0xaa00a9, 0xab00000000, 0xac000000000000, 0x42004200420042, 0x42004200420042, 0xb000af00ae00ad, 0x42004200420042, 0xb200b10000003d, 0xb500b4003d00b3, 0x42004200b700b6, 0xbb00ba00b900b8, 0xbd000000bc0064, 0xc0004200bf00be, 0xa4000000c10000, 0x42004200510000, 0x0, 0x0, 0xc2000000000000, 0x0, 0x0, 0x0, 0x0, 0x31, 0x420042004200a3, 0x42004200420042, 0x42004200420042, 0x42004200420042, 0x0, 0x0, 0x420042004200a3, 0x42004200420042, 0x420042000000c3, 0xc4000000000000, 0x42004200420042, 0x42004200420042, 0x0, 0x0, 0x0, 0xbe000000000000, 0x0, 0x0, 0x0, 0xbe000000000000, 0x0, 0x8300000000000000, 0x40000280f, 0x1ff0000000000, 0x101800000, 0x17900, 0xffe0f8000000ff00, 0x20000020, 0x4000, 0x1800, 0xfffc000000000000, 0xf800000000000000, 0x8000c00000000000, 0xffffffffb0000000, 0xffffe002ffffffff, 0x8000000fffffffff, 0x100000000000000, 0xc3a020000066011, 0xf00000304f7f8660, 0x2c92020000067811, 0xffc0003fa1fdc678, 0xc12020000044011, 0xfffc0030fffec440, 0xc12020000066011, 0xff0000304f3fc660, 0x3c0038e729c23813, 0xf800003fff7ec238, 0x1c10020000022011, 0xff0030fc9fc220, 0xc10020000022013, 0xfff90030bf9fc220, 0x1800000000022013, 0x1c00030ff7f8220, 0xd004000003800013, 0xffe3ffff00a07b80, 0x7800000000000001, 0xfffffffff0000000, 0xc4001351010fda69, 0xffffffff0c00c0a0, 0x1e00000000100, 0x2000000001000000, 0xfffffffff8002000, 0xdf40, 0xc280c200, 0x80c200000000c200, 0x8000c2, 0xc20000, 0xe000000018000000, 0xfc000000, 0xffe0000000000000, 0xe0000000, 0xfffe000000000000, 0xff800000ffe02000, 0xfff22000fff00000, 0xfc00fc00c0000000, 0xfc008000, 0xff00000000000000, 0xf80000000000, 0xffc0000000000000, 0xf000f000e0000000, 0xffe0c0000000000e, 0xf00000000000, 0x3800fc00, 0x30000000, 0x6000000080000000, 0xffffc000fc00fc00, 0xffffffffffffffff, 0xe00000000000f000, 0xff0000000000000, 0x700000000000000, 0x1c00, 0xff8000000000ff00, 0xfffff8000000000, 0xc0c00000, 0xc00000005500c0c0, 0x20000000000000, 0x8023000010300020, 0xc002000000000, 0xf8000000e0008000, 0xfffe00000000ffff, 0xfc00, 0xfff0000000000000, 0xffffff8000000000, 0xfffff800, 0x1, 0xfffffffffc00e000, 0x800000000000, 0x80000000, 0x1f0000000000000, 0xdf4000000000, 0x7ffe7f0000000000, 0x80808080ff800000, 0x80808080, 0xf000000000000000, 0x4000000, 0xf000ffffffc00000, 0x1800000, 0x1c0000000001f, 0xf800000000008000, 0xfff000000000, 0x8000000000000000, 0xffffffffffffe000, 0xe000, 0xff80, 0xfffff00000000000, 0x7f000000, 0xfffff800fff08000, 0xffffffffffffff, 0xfc00f00000000000, 0xf0000000fc003fe0, 0xe00000007ff00000, 0xffffffff3c004000, 0xff80000000000000, 0xf00000000c00c000, 0xff80000007fffff8, 0xffff8080ff818181, 0xfc00c00000000000, 0xf000000000000780, 0xc00000000000, 0xfffffffffc000000, 0xa08000001f07ff80, 0x24, 0x7fffc, 0xffff, 0x30000, 0xc000ffffffffff00, 0xff80fc000000, 0x20f08000080000, 0x6000000000000000, 0xc1ff8080e3030303, 0x4800008000001000, 0xffffffffc000c000, 0x70000000000078, 0xfffffffff000f800, 0xc00000000000ffff, 0xfffffffffffe0000, 0xfff080000000, 0xfffffffffffff800, 0x40000000, 0xffffffffffc000f0, 0xfffffc00c0000000, 0x6e400000000002c0, 0xffffffff00400000, 0x7c00000070000000, 0x3f00000000000000, 0x78f0000001100f90, 0xfe00ff00, 0x1c0000000000000, 0xf8000000c00000, 0xfffffffffffffe00, 0x80000000ffffffff, 0xffff00000003c000, 0xfc00fe000000fffc, 0xfffffffffffffff0, 0xfffffffffc00fe00, 0xfffffffffffffc00, 0xffff800000000000, 0xfff0fff800000000, 0xfe00000000000000, 0x800000000000ffe0, 0xffffffff00007fff, 0xfffffffffffffffc, 0x18000000000, 0xffffffffc0000000, 0xffffffffffffffc0, 0xfffc0000ff800000, 0x200000, 0x1400219b20000000, 0x10, 0x8400000020201840, 0x203a0, 0xc000000000, 0x3000, 0xf508016900000010, 0xa10808695569157b, 0xf0000411f0000400, 0xfffcffffffffffff, 0x80018000fff00000, 0xffffffff00010001, 0x80000000f800, 0xfffffffff8000000, 0x3fffffffff, 0xf80000000000fff8, 0xfffffffffffcfe00, 0x40fffe00000000, 0xe000000000000000, 0xfff00000, 0xfffe0000fffff820, 0x2, 0xe100000000000000, 0xc000000000000000, 0xffffff000000fff0, 0x7ffffffffffffff, 0xffffffffffff001e, 0xffffffffff800000, 0xfffffffd, 0xffff000000000000, 0xc000000000000000]); enum MAX_SIMPLE_LOWER = 1043; enum MAX_SIMPLE_UPPER = 1051; enum MAX_SIMPLE_TITLE = 1055; //8192 bytes enum toUpperIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x20, 0x100], [ 0x100, 0x380, 0xc00], [ 0x402030202020100, 0x202020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x3000200010000, 0x7000600050004, 0xa00090008, 0xd000c000b0000, 0x110010000f000e, 0x1400130012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150000, 0x19001800170016, 0x1d001c001b001a, 0x0, 0x1f001e0000, 0x0, 0x0, 0x20000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24002300220021, 0x25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2700260000, 0x2a00290028, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b, 0x0, 0x0, 0x0, 0x2c0000, 0x0, 0x0, 0x0, 0x0, 0x2e002d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x200010000ffff, 0x6000500040003, 0xa000900080007, 0xe000d000c000b, 0x1200110010000f, 0x16001500140013, 0xffff001900180017, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff001affff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x41bffffffffffff, 0x1e001d001c001b, 0x2200210020001f, 0x26002500240023, 0x2a002900280027, 0x2e002d002c002b, 0xffff00310030002f, 0x35003400330032, 0x39003800370036, 0x3bffff003affff, 0x3dffff003cffff, 0x3fffff003effff, 0x41ffff0040ffff, 0x43ffff0042ffff, 0x45ffff0044ffff, 0x47ffff0046ffff, 0x49ffff0048ffff, 0x4bffff004affff, 0x4dffff004cffff, 0x4fffff004effff, 0x51ffff0050ffff, 0x53ffff0052041d, 0x55ffff0054ffff, 0xffff0056ffffffff, 0xffff0058ffff0057, 0xffff005affff0059, 0xffff005cffff005b, 0x5effff043a005d, 0x60ffff005fffff, 0x62ffff0061ffff, 0x64ffff0063ffff, 0x66ffff0065ffff, 0x68ffff0067ffff, 0x6affff0069ffff, 0x6cffff006bffff, 0x6effff006dffff, 0x70ffff006fffff, 0x72ffff0071ffff, 0x74ffff0073ffff, 0xffff0075ffffffff, 0x780077ffff0076, 0x7affffffff0079, 0xffffffff007bffff, 0xffffffffffff007c, 0xffffffffffff007d, 0xffff007effffffff, 0xffffffff007fffff, 0xffff00810080ffff, 0xffff0082ffffffff, 0x84ffff0083ffff, 0xffffffff0085ffff, 0xffffffffffff0086, 0xffffffff0087ffff, 0xffffffffffff0088, 0xffff008affff0089, 0xffffffff008bffff, 0x8dffff008cffff, 0xffffffffffffffff, 0xffff008f008effff, 0x92ffff00910090, 0xffff0094ffff0093, 0xffff0096ffff0095, 0xffff0098ffff0097, 0xffff009affff0099, 0x9dffff009c009b, 0x9fffff009effff, 0xa1ffff00a0ffff, 0xa3ffff00a2ffff, 0xa5ffff00a4ffff, 0xa700a6ffff0442, 0xffffffff00a8ffff, 0xaaffff00a9ffff, 0xacffff00abffff, 0xaeffff00adffff, 0xb0ffff00afffff, 0xb2ffff00b1ffff, 0xb4ffff00b3ffff, 0xb6ffff00b5ffff, 0xb8ffff00b7ffff, 0xbaffff00b9ffff, 0xbcffff00bbffff, 0xbdffffffffffff, 0xbfffff00beffff, 0xc1ffff00c0ffff, 0xc3ffff00c2ffff, 0xc5ffff00c4ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xc7ffffffff00c6, 0xffff00c9ffff00c8, 0xcaffffffffffff, 0xccffff00cbffff, 0xceffff00cdffff, 0xd200d100d000cf, 0xd500d4ffff00d3, 0xd7ffff00d6ffff, 0xffffffffffffffff, 0xd9ffffffff00d8, 0xffff00db00daffff, 0xdeffff00dd00dc, 0xdfffffffffffff, 0xffff00e100e0ffff, 0xffffffff00e2ffff, 0xffffffffffffffff, 0xffffffff00e3ffff, 0xe5ffffffff00e4, 0xffffffffffffffff, 0xe900e800e700e6, 0xffffffffffff00ea, 0xffff00ebffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff00ecffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xeeffff00edffff, 0xefffffffffffff, 0xf0ffffffffffff, 0xffffffff00f200f1, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff043c, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xf600f500f400f3, 0xf900f800f7043f, 0xfd00fc00fb00fa, 0x101010000ff00fe, 0x105010401030102, 0x109010801070106, 0x10d010c010b010a, 0x1110110010f010e, 0xffff011401130112, 0xffffffff01160115, 0x11901180117ffff, 0x11bffff011affff, 0x11dffff011cffff, 0x11fffff011effff, 0x121ffff0120ffff, 0x123ffff0122ffff, 0x125ffff0124ffff, 0xffff012801270126, 0xffffffff0129ffff, 0x12bffffffff012a, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x12f012e012d012c, 0x133013201310130, 0x137013601350134, 0x13b013a01390138, 0x13f013e013d013c, 0x143014201410140, 0x147014601450144, 0x14b014a01490148, 0x14f014e014d014c, 0x153015201510150, 0x157015601550154, 0x15b015a01590158, 0x15dffff015cffff, 0x15fffff015effff, 0x161ffff0160ffff, 0x163ffff0162ffff, 0x165ffff0164ffff, 0x167ffff0166ffff, 0x169ffff0168ffff, 0x16bffff016affff, 0xffffffff016cffff, 0xffffffffffffffff, 0x16dffffffffffff, 0x16fffff016effff, 0x171ffff0170ffff, 0x173ffff0172ffff, 0x175ffff0174ffff, 0x177ffff0176ffff, 0x179ffff0178ffff, 0x17bffff017affff, 0x17dffff017cffff, 0x17fffff017effff, 0x181ffff0180ffff, 0x183ffff0182ffff, 0x185ffff0184ffff, 0x187ffff0186ffff, 0xffff0188ffffffff, 0xffff018affff0189, 0xffff018cffff018b, 0x18f018effff018d, 0x191ffff0190ffff, 0x193ffff0192ffff, 0x195ffff0194ffff, 0x197ffff0196ffff, 0x199ffff0198ffff, 0x19bffff019affff, 0x19dffff019cffff, 0x19fffff019effff, 0x1a1ffff01a0ffff, 0x1a3ffff01a2ffff, 0x1a5ffff01a4ffff, 0x1a7ffff01a6ffff, 0x1a9ffff01a8ffff, 0x1abffff01aaffff, 0x1adffff01acffff, 0x1afffff01aeffff, 0x1b1ffff01b0ffff, 0x1b3ffff01b2ffff, 0x1b5ffff01b4ffff, 0x1b7ffff01b6ffff, 0x1b9ffff01b8ffff, 0x1bbffff01baffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1be01bd01bcffff, 0x1c201c101c001bf, 0x1c601c501c401c3, 0x1ca01c901c801c7, 0x1ce01cd01cc01cb, 0x1d201d101d001cf, 0x1d601d501d401d3, 0x1da01d901d801d7, 0x1de01dd01dc01db, 0x42e01e101e001df, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff01e2ffff, 0xffffffff01e3ffff, 0x1e5ffff01e4ffff, 0x1e7ffff01e6ffff, 0x1e9ffff01e8ffff, 0x1ebffff01eaffff, 0x1edffff01ecffff, 0x1efffff01eeffff, 0x1f1ffff01f0ffff, 0x1f3ffff01f2ffff, 0x1f5ffff01f4ffff, 0x1f7ffff01f6ffff, 0x1f9ffff01f8ffff, 0x1fbffff01faffff, 0x1fdffff01fcffff, 0x1ffffff01feffff, 0x201ffff0200ffff, 0x203ffff0202ffff, 0x205ffff0204ffff, 0x207ffff0206ffff, 0x209ffff0208ffff, 0x20bffff020affff, 0x20dffff020cffff, 0x20fffff020effff, 0x211ffff0210ffff, 0x213ffff0212ffff, 0x215ffff0214ffff, 0x217ffff0216ffff, 0x219ffff0218ffff, 0x21bffff021affff, 0x21dffff021cffff, 0x21fffff021effff, 0x221ffff0220ffff, 0x223ffff0222ffff, 0x225ffff0224ffff, 0x227ffff0226ffff, 0x229ffff0228ffff, 0x22bffff022affff, 0x22dffff022cffff, 0x4460444022effff, 0x22f044c044a0448, 0xffffffffffffffff, 0x231ffff0230ffff, 0x233ffff0232ffff, 0x235ffff0234ffff, 0x237ffff0236ffff, 0x239ffff0238ffff, 0x23bffff023affff, 0x23dffff023cffff, 0x23fffff023effff, 0x241ffff0240ffff, 0x243ffff0242ffff, 0x245ffff0244ffff, 0x247ffff0246ffff, 0x249ffff0248ffff, 0x24bffff024affff, 0x24dffff024cffff, 0x24fffff024effff, 0x251ffff0250ffff, 0x253ffff0252ffff, 0x255ffff0254ffff, 0x257ffff0256ffff, 0x259ffff0258ffff, 0x25bffff025affff, 0x25dffff025cffff, 0x25fffff025effff, 0x263026202610260, 0x267026602650264, 0xffffffffffffffff, 0xffffffffffffffff, 0x26b026a02690268, 0xffffffff026d026c, 0xffffffffffffffff, 0xffffffffffffffff, 0x2710270026f026e, 0x275027402730272, 0xffffffffffffffff, 0xffffffffffffffff, 0x279027802770276, 0x27d027c027b027a, 0xffffffffffffffff, 0xffffffffffffffff, 0x2810280027f027e, 0xffffffff02830282, 0xffffffffffffffff, 0xffffffffffffffff, 0x28504500284044e, 0x287045602860453, 0xffffffffffffffff, 0xffffffffffffffff, 0x28b028a02890288, 0x28f028e028d028c, 0xffffffffffffffff, 0xffffffffffffffff, 0x293029202910290, 0x297029602950294, 0x29b029a02990298, 0xffffffff029d029c, 0x47d047b04790477, 0x48504830481047f, 0x48d048b04890487, 0x49504930491048f, 0x49d049b04990497, 0x4a504a304a1049f, 0x4ad04ab04a904a7, 0x4b504b304b104af, 0x4bd04bb04b904b7, 0x4c504c304c104bf, 0x4cd04cb04c904c7, 0x4d504d304d104cf, 0x4d704e302b702b6, 0x4ef0459ffff04e5, 0xffffffffffffffff, 0xffff02b9ffff04d9, 0x4db04e7ffffffff, 0x4f2045bffff04e9, 0xffffffffffffffff, 0xffffffffffff04dd, 0x460045d02bc02bb, 0x4650463ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x46b046802be02bd, 0x472047002bf046e, 0xffffffffffffffff, 0xffffffffffffffff, 0x4df04ebffffffff, 0x4f50475ffff04ed, 0xffffffffffffffff, 0xffffffffffff04e1, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff02c1ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2c502c402c302c2, 0x2c902c802c702c6, 0x2cd02cc02cb02ca, 0x2d102d002cf02ce, 0xffffffffffffffff, 0xffffffffffff02d2, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2d602d502d402d3, 0x2da02d902d802d7, 0x2de02dd02dc02db, 0x2e202e102e002df, 0x2e602e502e402e3, 0x2ea02e902e802e7, 0xffffffff02ec02eb, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2f002ef02ee02ed, 0x2f402f302f202f1, 0x2f802f702f602f5, 0x2fc02fb02fa02f9, 0x30002ff02fe02fd, 0x304030303020301, 0x308030703060305, 0x30c030b030a0309, 0x310030f030e030d, 0x314031303120311, 0x318031703160315, 0xffff031b031a0319, 0xffffffff031cffff, 0xffff031e031dffff, 0xffff0320ffff031f, 0xffffffffffff0321, 0x322ffffffffffff, 0xffff0323ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x325ffff0324ffff, 0x327ffff0326ffff, 0x329ffff0328ffff, 0x32bffff032affff, 0x32dffff032cffff, 0x32fffff032effff, 0x331ffff0330ffff, 0x333ffff0332ffff, 0x335ffff0334ffff, 0x337ffff0336ffff, 0x339ffff0338ffff, 0x33bffff033affff, 0x33dffff033cffff, 0x33fffff033effff, 0x341ffff0340ffff, 0x343ffff0342ffff, 0x345ffff0344ffff, 0x347ffff0346ffff, 0x349ffff0348ffff, 0x34bffff034affff, 0x34dffff034cffff, 0x34fffff034effff, 0x351ffff0350ffff, 0x353ffff0352ffff, 0x355ffff0354ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0357ffff0356, 0x358ffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x35c035b035a0359, 0x360035f035e035d, 0x364036303620361, 0x368036703660365, 0x36c036b036a0369, 0x370036f036e036d, 0x374037303720371, 0x378037703760375, 0x37c037b037a0379, 0x37fffff037e037d, 0xffffffffffffffff, 0xffffffff0380ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x382ffff0381ffff, 0x384ffff0383ffff, 0x386ffff0385ffff, 0x388ffff0387ffff, 0x38affff0389ffff, 0x38cffff038bffff, 0x38effff038dffff, 0x390ffff038fffff, 0x392ffff0391ffff, 0x394ffff0393ffff, 0x396ffff0395ffff, 0xffffffff0397ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x399ffff0398ffff, 0x39bffff039affff, 0x39dffff039cffff, 0x39fffff039effff, 0x3a1ffff03a0ffff, 0x3a3ffff03a2ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3a4ffffffffffff, 0x3a6ffff03a5ffff, 0x3a8ffff03a7ffff, 0x3aaffff03a9ffff, 0x3abffffffffffff, 0x3adffff03acffff, 0x3afffff03aeffff, 0x3b1ffff03b0ffff, 0x3b3ffff03b2ffff, 0x3b5ffff03b4ffff, 0x3b7ffff03b6ffff, 0x3b9ffff03b8ffff, 0x3bbffff03baffff, 0x3bdffff03bcffff, 0x3bfffff03beffff, 0x3c1ffff03c0ffff, 0x3c3ffff03c2ffff, 0x3c5ffff03c4ffff, 0x3c7ffff03c6ffff, 0x3c9ffff03c8ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff03caffffffff, 0x3ccffffffff03cb, 0x3ceffff03cdffff, 0x3d0ffff03cfffff, 0xffffffffffffffff, 0xffffffffffff03d1, 0x3d3ffff03d2ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3d5ffff03d4ffff, 0x3d7ffff03d6ffff, 0xffffffff03d8ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x42404220420041e, 0xffff042c042a0427, 0xffffffffffffffff, 0xffffffffffffffff, 0x430ffffffffffff, 0x438043604340432, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3db03da03d9ffff, 0x3df03de03dd03dc, 0x3e303e203e103e0, 0x3e703e603e503e4, 0x3eb03ea03e903e8, 0x3ef03ee03ed03ec, 0xffff03f203f103f0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3f603f503f403f3, 0x3fa03f903f803f7, 0x3fe03fd03fc03fb, 0x4020401040003ff, 0x406040504040403, 0x40a040904080407, 0x40e040d040c040b, 0x41204110410040f, 0x416041504140413, 0x41a041904180417, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff]); //8064 bytes enum toLowerIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x20, 0x100], [ 0x100, 0x380, 0xbc0], [ 0x402030202020100, 0x202020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x2000000010000, 0x6000500040003, 0x80007, 0xb000a00090000, 0xf000e000d000c, 0x1200110010, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14001300000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18001700160015, 0x1c001b001a0019, 0x0, 0x1f001e001d, 0x0, 0x0, 0x21002000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25002400230022, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2700260000, 0x2a00290028, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b, 0x0, 0x0, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x200010000ffff, 0x6000500040003, 0xa000900080007, 0xe000d000c000b, 0x1200110010000f, 0x16001500140013, 0xffff001900180017, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1d001c001b001a, 0x210020001f001e, 0x25002400230022, 0x29002800270026, 0x2d002c002b002a, 0xffff0030002f002e, 0x34003300320031, 0x413003700360035, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0039ffff0038, 0xffff003bffff003a, 0xffff003dffff003c, 0xffff003fffff003e, 0xffff0041ffff0040, 0xffff0043ffff0042, 0xffff0045ffff0044, 0xffff0047ffff0046, 0xffff0049ffff0048, 0xffff004bffff004a, 0xffff004dffff004c, 0xffff004fffff004e, 0xffff0051ffff0414, 0xffff0053ffff0052, 0x55ffff0054ffff, 0x57ffff0056ffff, 0x59ffff0058ffff, 0x5bffff005affff, 0xffff005c0423ffff, 0xffff005effff005d, 0xffff0060ffff005f, 0xffff0062ffff0061, 0xffff0064ffff0063, 0xffff0066ffff0065, 0xffff0068ffff0067, 0xffff006affff0069, 0xffff006cffff006b, 0xffff006effff006d, 0xffff0070ffff006f, 0xffff0072ffff0071, 0x75ffff00740073, 0xffffffff0076ffff, 0xffff00780077ffff, 0x7b007affff0079, 0x7e007d007cffff, 0x80007fffffffff, 0x83ffff00820081, 0x860085ffff0084, 0xffffffffffff0087, 0x8affff00890088, 0xffff008cffff008b, 0x8f008effff008d, 0xffffffff0090ffff, 0x930092ffff0091, 0x9600950094ffff, 0x98ffff0097ffff, 0xffffffffffff0099, 0xffffffffffff009a, 0xffffffffffffffff, 0x9dffff009c009b, 0xa0009fffff009e, 0xa2ffff00a1ffff, 0xa4ffff00a3ffff, 0xa6ffff00a5ffff, 0xa8ffff00a7ffff, 0xffff00a9ffffffff, 0xffff00abffff00aa, 0xffff00adffff00ac, 0xffff00afffff00ae, 0xffff00b1ffff00b0, 0xffff00b300b20426, 0xb600b5ffff00b4, 0xffff00b8ffff00b7, 0xffff00baffff00b9, 0xffff00bcffff00bb, 0xffff00beffff00bd, 0xffff00c0ffff00bf, 0xffff00c2ffff00c1, 0xffff00c4ffff00c3, 0xffff00c6ffff00c5, 0xffff00c8ffff00c7, 0xffff00caffff00c9, 0xffff00ccffff00cb, 0xffff00ceffff00cd, 0xffff00d0ffff00cf, 0xffff00d2ffff00d1, 0xffff00d4ffff00d3, 0xffffffffffffffff, 0xd600d5ffffffff, 0xffff00d800d7ffff, 0xdaffff00d9ffff, 0xffff00dd00dc00db, 0xffff00dfffff00de, 0xffff00e1ffff00e0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff00e3ffff00e2, 0xffff00e4ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff00e5ffffffff, 0xffff00e800e700e6, 0xeb00eaffff00e9, 0xee00ed00ec0424, 0xf200f100f000ef, 0xf600f500f400f3, 0xfa00f900f800f7, 0xfdffff00fc00fb, 0x101010000ff00fe, 0x105010401030102, 0xffffffffffffffff, 0xffffffffffff0425, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x106ffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0108ffff0107, 0xffff010affff0109, 0xffff010cffff010b, 0xffff010effff010d, 0xffff0110ffff010f, 0xffff0112ffff0111, 0xffffffffffffffff, 0x114ffffffff0113, 0xffff01160115ffff, 0x11901180117ffff, 0x11d011c011b011a, 0x1210120011f011e, 0x125012401230122, 0x129012801270126, 0x12d012c012b012a, 0x1310130012f012e, 0x135013401330132, 0x139013801370136, 0x13d013c013b013a, 0x1410140013f013e, 0x145014401430142, 0x149014801470146, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff014bffff014a, 0xffff014dffff014c, 0xffff014fffff014e, 0xffff0151ffff0150, 0xffff0153ffff0152, 0xffff0155ffff0154, 0xffff0157ffff0156, 0xffff0159ffff0158, 0xffffffffffff015a, 0xffffffffffffffff, 0xffff015bffffffff, 0xffff015dffff015c, 0xffff015fffff015e, 0xffff0161ffff0160, 0xffff0163ffff0162, 0xffff0165ffff0164, 0xffff0167ffff0166, 0xffff0169ffff0168, 0xffff016bffff016a, 0xffff016dffff016c, 0xffff016fffff016e, 0xffff0171ffff0170, 0xffff0173ffff0172, 0xffff0175ffff0174, 0x178ffff01770176, 0x17affff0179ffff, 0x17cffff017bffff, 0xffffffff017dffff, 0xffff017fffff017e, 0xffff0181ffff0180, 0xffff0183ffff0182, 0xffff0185ffff0184, 0xffff0187ffff0186, 0xffff0189ffff0188, 0xffff018bffff018a, 0xffff018dffff018c, 0xffff018fffff018e, 0xffff0191ffff0190, 0xffff0193ffff0192, 0xffff0195ffff0194, 0xffff0197ffff0196, 0xffff0199ffff0198, 0xffff019bffff019a, 0xffff019dffff019c, 0xffff019fffff019e, 0xffff01a1ffff01a0, 0xffff01a3ffff01a2, 0xffff01a5ffff01a4, 0xffff01a7ffff01a6, 0xffff01a9ffff01a8, 0xffffffffffffffff, 0xffffffffffffffff, 0x1ac01ab01aaffff, 0x1b001af01ae01ad, 0x1b401b301b201b1, 0x1b801b701b601b5, 0x1bc01bb01ba01b9, 0x1c001bf01be01bd, 0x1c401c301c201c1, 0x1c801c701c601c5, 0x1cc01cb01ca01c9, 0xffff01cf01ce01cd, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x41dffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1d301d201d101d0, 0x1d701d601d501d4, 0x1db01da01d901d8, 0x1df01de01dd01dc, 0x1e301e201e101e0, 0x1e701e601e501e4, 0x1eb01ea01e901e8, 0x1ef01ee01ed01ec, 0x1f301f201f101f0, 0x1f6ffff01f501f4, 0xffffffffffffffff, 0xffffffff01f7ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff01f9ffff01f8, 0xffff01fbffff01fa, 0xffff01fdffff01fc, 0xffff01ffffff01fe, 0xffff0201ffff0200, 0xffff0203ffff0202, 0xffff0205ffff0204, 0xffff0207ffff0206, 0xffff0209ffff0208, 0xffff020bffff020a, 0xffff020dffff020c, 0xffff020fffff020e, 0xffff0211ffff0210, 0xffff0213ffff0212, 0xffff0215ffff0214, 0xffff0217ffff0216, 0xffff0219ffff0218, 0xffff021bffff021a, 0xffff021dffff021c, 0xffff021fffff021e, 0xffff0221ffff0220, 0xffff0223ffff0222, 0xffff0225ffff0224, 0xffff0227ffff0226, 0xffff0229ffff0228, 0xffff022bffff022a, 0xffff022dffff022c, 0xffff022fffff022e, 0xffff0231ffff0230, 0xffff0233ffff0232, 0xffff0235ffff0234, 0xffff0237ffff0236, 0xffff0239ffff0238, 0xffff023bffff023a, 0xffff023dffff023c, 0xffff023fffff023e, 0xffff0241ffff0240, 0x4280427ffff0242, 0xffff042b042a0429, 0xffff0243ffffffff, 0xffff0245ffff0244, 0xffff0247ffff0246, 0xffff0249ffff0248, 0xffff024bffff024a, 0xffff024dffff024c, 0xffff024fffff024e, 0xffff0251ffff0250, 0xffff0253ffff0252, 0xffff0255ffff0254, 0xffff0257ffff0256, 0xffff0259ffff0258, 0xffff025bffff025a, 0xffff025dffff025c, 0xffff025fffff025e, 0xffff0261ffff0260, 0xffff0263ffff0262, 0xffff0265ffff0264, 0xffff0267ffff0266, 0xffff0269ffff0268, 0xffff026bffff026a, 0xffff026dffff026c, 0xffff026fffff026e, 0xffff0271ffff0270, 0xffff0273ffff0272, 0xffffffffffffffff, 0xffffffffffffffff, 0x277027602750274, 0x27b027a02790278, 0xffffffffffffffff, 0xffffffffffffffff, 0x27f027e027d027c, 0xffffffff02810280, 0xffffffffffffffff, 0xffffffffffffffff, 0x285028402830282, 0x289028802870286, 0xffffffffffffffff, 0xffffffffffffffff, 0x28d028c028b028a, 0x2910290028f028e, 0xffffffffffffffff, 0xffffffffffffffff, 0x295029402930292, 0xffffffff02970296, 0xffff042dffff042c, 0xffff042fffff042e, 0x299ffff0298ffff, 0x29bffff029affff, 0xffffffffffffffff, 0xffffffffffffffff, 0x29f029e029d029c, 0x2a302a202a102a0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x43f043e043d043c, 0x443044204410440, 0x447044604450444, 0x44b044a04490448, 0x44f044e044d044c, 0x453045204510450, 0x457045604550454, 0x45b045a04590458, 0x45f045e045d045c, 0x463046204610460, 0x467046604650464, 0x46b046a04690468, 0x46c0472ffffffff, 0x4780430ffff0473, 0x2bf02be02bd02bc, 0xffffffffffff046d, 0x46e0474ffffffff, 0x4790431ffff0475, 0x2c402c302c202c1, 0xffffffffffff046f, 0x4330432ffffffff, 0x4350434ffffffff, 0x2c902c802c702c6, 0xffffffffffffffff, 0x4370436ffffffff, 0x43a0439ffff0438, 0x2cd02cc02cb02ca, 0xffffffffffff02ce, 0x4700476ffffffff, 0x47a043bffff0477, 0x2d202d102d002cf, 0xffffffffffff0471, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff02d4ffffffff, 0x2d602d5ffffffff, 0xffffffffffffffff, 0xffff02d7ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2db02da02d902d8, 0x2df02de02dd02dc, 0x2e302e202e102e0, 0x2e702e602e502e4, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2e8ffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2ea02e9ffffffff, 0x2ee02ed02ec02eb, 0x2f202f102f002ef, 0x2f602f502f402f3, 0x2fa02f902f802f7, 0x2fe02fd02fc02fb, 0x3020301030002ff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x306030503040303, 0x30a030903080307, 0x30e030d030c030b, 0x31203110310030f, 0x316031503140313, 0x31a031903180317, 0x31e031d031c031b, 0x32203210320031f, 0x326032503240323, 0x32a032903280327, 0x32e032d032c032b, 0xffff03310330032f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3340333ffff0332, 0x336ffffffff0335, 0x338ffff0337ffff, 0x33b033a0339ffff, 0xffff033dffff033c, 0xffffffff033effff, 0xffffffffffffffff, 0x340033fffffffff, 0xffff0342ffff0341, 0xffff0344ffff0343, 0xffff0346ffff0345, 0xffff0348ffff0347, 0xffff034affff0349, 0xffff034cffff034b, 0xffff034effff034d, 0xffff0350ffff034f, 0xffff0352ffff0351, 0xffff0354ffff0353, 0xffff0356ffff0355, 0xffff0358ffff0357, 0xffff035affff0359, 0xffff035cffff035b, 0xffff035effff035d, 0xffff0360ffff035f, 0xffff0362ffff0361, 0xffff0364ffff0363, 0xffff0366ffff0365, 0xffff0368ffff0367, 0xffff036affff0369, 0xffff036cffff036b, 0xffff036effff036d, 0xffff0370ffff036f, 0xffff0372ffff0371, 0xffffffffffffffff, 0x373ffffffffffff, 0xffffffff0374ffff, 0xffff0375ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0377ffff0376, 0xffff0379ffff0378, 0xffff037bffff037a, 0xffff037dffff037c, 0xffff037fffff037e, 0xffff0381ffff0380, 0xffff0383ffff0382, 0xffff0385ffff0384, 0xffff0387ffff0386, 0xffff0389ffff0388, 0xffff038bffff038a, 0xffffffffffff038c, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff038effff038d, 0xffff0390ffff038f, 0xffff0392ffff0391, 0xffff0394ffff0393, 0xffff0396ffff0395, 0xffff0398ffff0397, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0399ffffffff, 0xffff039bffff039a, 0xffff039dffff039c, 0xffff039fffff039e, 0xffff03a0ffffffff, 0xffff03a2ffff03a1, 0xffff03a4ffff03a3, 0xffff03a6ffff03a5, 0xffff03a8ffff03a7, 0xffff03aaffff03a9, 0xffff03acffff03ab, 0xffff03aeffff03ad, 0xffff03b0ffff03af, 0xffff03b2ffff03b1, 0xffff03b4ffff03b3, 0xffff03b6ffff03b5, 0xffff03b8ffff03b7, 0xffff03baffff03b9, 0xffff03bcffff03bb, 0xffff03beffff03bd, 0xffffffffffffffff, 0xffffffffffffffff, 0x3c0ffff03bfffff, 0xffff03c203c1ffff, 0xffff03c4ffff03c3, 0xffff03c6ffff03c5, 0x3c7ffffffffffff, 0xffffffff03c8ffff, 0xffff03caffff03c9, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff03ccffff03cb, 0xffff03ceffff03cd, 0xffff03d0ffff03cf, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x419041804170416, 0xffff041c041b041a, 0xffffffffffffffff, 0xffffffffffffffff, 0x41effffffffffff, 0x42204210420041f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3d303d203d1ffff, 0x3d703d603d503d4, 0x3db03da03d903d8, 0x3df03de03dd03dc, 0x3e303e203e103e0, 0x3e703e603e503e4, 0xffff03ea03e903e8, 0xffffffffffffffff, 0x3ee03ed03ec03eb, 0x3f203f103f003ef, 0x3f603f503f403f3, 0x3fa03f903f803f7, 0x3fe03fd03fc03fb, 0x4020401040003ff, 0x406040504040403, 0x40a040904080407, 0x40e040d040c040b, 0x41204110410040f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff]); //8192 bytes enum toTitleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x20, 0x100], [ 0x100, 0x380, 0xc00], [ 0x402030202020100, 0x202020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x3000200010000, 0x7000600050004, 0xa00090008, 0xd000c000b0000, 0x110010000f000e, 0x1400130012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150000, 0x19001800170016, 0x1d001c001b001a, 0x0, 0x1f001e0000, 0x0, 0x0, 0x20000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24002300220021, 0x25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2700260000, 0x2a00290028, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b, 0x0, 0x0, 0x0, 0x2c0000, 0x0, 0x0, 0x0, 0x0, 0x2e002d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x200010000ffff, 0x6000500040003, 0xa000900080007, 0xe000d000c000b, 0x1200110010000f, 0x16001500140013, 0xffff001900180017, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff001affff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x41fffffffffffff, 0x1e001d001c001b, 0x2200210020001f, 0x26002500240023, 0x2a002900280027, 0x2e002d002c002b, 0xffff00310030002f, 0x35003400330032, 0x39003800370036, 0x3bffff003affff, 0x3dffff003cffff, 0x3fffff003effff, 0x41ffff0040ffff, 0x43ffff0042ffff, 0x45ffff0044ffff, 0x47ffff0046ffff, 0x49ffff0048ffff, 0x4bffff004affff, 0x4dffff004cffff, 0x4fffff004effff, 0x51ffff0050ffff, 0x53ffff00520421, 0x55ffff0054ffff, 0xffff0056ffffffff, 0xffff0058ffff0057, 0xffff005affff0059, 0xffff005cffff005b, 0x5effff043e005d, 0x60ffff005fffff, 0x62ffff0061ffff, 0x64ffff0063ffff, 0x66ffff0065ffff, 0x68ffff0067ffff, 0x6affff0069ffff, 0x6cffff006bffff, 0x6effff006dffff, 0x70ffff006fffff, 0x72ffff0071ffff, 0x74ffff0073ffff, 0xffff0075ffffffff, 0x780077ffff0076, 0x7affffffff0079, 0xffffffff007bffff, 0xffffffffffff007c, 0xffffffffffff007d, 0xffff007effffffff, 0xffffffff007fffff, 0xffff00810080ffff, 0xffff0082ffffffff, 0x84ffff0083ffff, 0xffffffff0085ffff, 0xffffffffffff0086, 0xffffffff0087ffff, 0xffffffffffff0088, 0xffff008affff0089, 0xffffffff008bffff, 0x8dffff008cffff, 0xffffffffffffffff, 0x910090008f008e, 0x95009400930092, 0xffff0097ffff0096, 0xffff0099ffff0098, 0xffff009bffff009a, 0xffff009dffff009c, 0xa0ffff009f009e, 0xa2ffff00a1ffff, 0xa4ffff00a3ffff, 0xa6ffff00a5ffff, 0xa8ffff00a7ffff, 0xab00aa00a90446, 0xffffffff00acffff, 0xaeffff00adffff, 0xb0ffff00afffff, 0xb2ffff00b1ffff, 0xb4ffff00b3ffff, 0xb6ffff00b5ffff, 0xb8ffff00b7ffff, 0xbaffff00b9ffff, 0xbcffff00bbffff, 0xbeffff00bdffff, 0xc0ffff00bfffff, 0xc1ffffffffffff, 0xc3ffff00c2ffff, 0xc5ffff00c4ffff, 0xc7ffff00c6ffff, 0xc9ffff00c8ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xcbffffffff00ca, 0xffff00cdffff00cc, 0xceffffffffffff, 0xd0ffff00cfffff, 0xd2ffff00d1ffff, 0xd600d500d400d3, 0xd900d8ffff00d7, 0xdbffff00daffff, 0xffffffffffffffff, 0xddffffffff00dc, 0xffff00df00deffff, 0xe2ffff00e100e0, 0xe3ffffffffffff, 0xffff00e500e4ffff, 0xffffffff00e6ffff, 0xffffffffffffffff, 0xffffffff00e7ffff, 0xe9ffffffff00e8, 0xffffffffffffffff, 0xed00ec00eb00ea, 0xffffffffffff00ee, 0xffff00efffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff00f0ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xf2ffff00f1ffff, 0xf3ffffffffffff, 0xf4ffffffffffff, 0xffffffff00f600f5, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff0440, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfa00f900f800f7, 0xfd00fc00fb0443, 0x101010000ff00fe, 0x105010401030102, 0x109010801070106, 0x10d010c010b010a, 0x1110110010f010e, 0x115011401130112, 0xffff011801170116, 0xffffffff011a0119, 0x11d011c011bffff, 0x11fffff011effff, 0x121ffff0120ffff, 0x123ffff0122ffff, 0x125ffff0124ffff, 0x127ffff0126ffff, 0x129ffff0128ffff, 0xffff012c012b012a, 0xffffffff012dffff, 0x12fffffffff012e, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x133013201310130, 0x137013601350134, 0x13b013a01390138, 0x13f013e013d013c, 0x143014201410140, 0x147014601450144, 0x14b014a01490148, 0x14f014e014d014c, 0x153015201510150, 0x157015601550154, 0x15b015a01590158, 0x15f015e015d015c, 0x161ffff0160ffff, 0x163ffff0162ffff, 0x165ffff0164ffff, 0x167ffff0166ffff, 0x169ffff0168ffff, 0x16bffff016affff, 0x16dffff016cffff, 0x16fffff016effff, 0xffffffff0170ffff, 0xffffffffffffffff, 0x171ffffffffffff, 0x173ffff0172ffff, 0x175ffff0174ffff, 0x177ffff0176ffff, 0x179ffff0178ffff, 0x17bffff017affff, 0x17dffff017cffff, 0x17fffff017effff, 0x181ffff0180ffff, 0x183ffff0182ffff, 0x185ffff0184ffff, 0x187ffff0186ffff, 0x189ffff0188ffff, 0x18bffff018affff, 0xffff018cffffffff, 0xffff018effff018d, 0xffff0190ffff018f, 0x1930192ffff0191, 0x195ffff0194ffff, 0x197ffff0196ffff, 0x199ffff0198ffff, 0x19bffff019affff, 0x19dffff019cffff, 0x19fffff019effff, 0x1a1ffff01a0ffff, 0x1a3ffff01a2ffff, 0x1a5ffff01a4ffff, 0x1a7ffff01a6ffff, 0x1a9ffff01a8ffff, 0x1abffff01aaffff, 0x1adffff01acffff, 0x1afffff01aeffff, 0x1b1ffff01b0ffff, 0x1b3ffff01b2ffff, 0x1b5ffff01b4ffff, 0x1b7ffff01b6ffff, 0x1b9ffff01b8ffff, 0x1bbffff01baffff, 0x1bdffff01bcffff, 0x1bfffff01beffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1c201c101c0ffff, 0x1c601c501c401c3, 0x1ca01c901c801c7, 0x1ce01cd01cc01cb, 0x1d201d101d001cf, 0x1d601d501d401d3, 0x1da01d901d801d7, 0x1de01dd01dc01db, 0x1e201e101e001df, 0x43201e501e401e3, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff01e6ffff, 0xffffffff01e7ffff, 0x1e9ffff01e8ffff, 0x1ebffff01eaffff, 0x1edffff01ecffff, 0x1efffff01eeffff, 0x1f1ffff01f0ffff, 0x1f3ffff01f2ffff, 0x1f5ffff01f4ffff, 0x1f7ffff01f6ffff, 0x1f9ffff01f8ffff, 0x1fbffff01faffff, 0x1fdffff01fcffff, 0x1ffffff01feffff, 0x201ffff0200ffff, 0x203ffff0202ffff, 0x205ffff0204ffff, 0x207ffff0206ffff, 0x209ffff0208ffff, 0x20bffff020affff, 0x20dffff020cffff, 0x20fffff020effff, 0x211ffff0210ffff, 0x213ffff0212ffff, 0x215ffff0214ffff, 0x217ffff0216ffff, 0x219ffff0218ffff, 0x21bffff021affff, 0x21dffff021cffff, 0x21fffff021effff, 0x221ffff0220ffff, 0x223ffff0222ffff, 0x225ffff0224ffff, 0x227ffff0226ffff, 0x229ffff0228ffff, 0x22bffff022affff, 0x22dffff022cffff, 0x22fffff022effff, 0x231ffff0230ffff, 0x44a04480232ffff, 0x2330450044e044c, 0xffffffffffffffff, 0x235ffff0234ffff, 0x237ffff0236ffff, 0x239ffff0238ffff, 0x23bffff023affff, 0x23dffff023cffff, 0x23fffff023effff, 0x241ffff0240ffff, 0x243ffff0242ffff, 0x245ffff0244ffff, 0x247ffff0246ffff, 0x249ffff0248ffff, 0x24bffff024affff, 0x24dffff024cffff, 0x24fffff024effff, 0x251ffff0250ffff, 0x253ffff0252ffff, 0x255ffff0254ffff, 0x257ffff0256ffff, 0x259ffff0258ffff, 0x25bffff025affff, 0x25dffff025cffff, 0x25fffff025effff, 0x261ffff0260ffff, 0x263ffff0262ffff, 0x267026602650264, 0x26b026a02690268, 0xffffffffffffffff, 0xffffffffffffffff, 0x26f026e026d026c, 0xffffffff02710270, 0xffffffffffffffff, 0xffffffffffffffff, 0x275027402730272, 0x279027802770276, 0xffffffffffffffff, 0xffffffffffffffff, 0x27d027c027b027a, 0x2810280027f027e, 0xffffffffffffffff, 0xffffffffffffffff, 0x285028402830282, 0xffffffff02870286, 0xffffffffffffffff, 0xffffffffffffffff, 0x289045402880452, 0x28b045a028a0457, 0xffffffffffffffff, 0xffffffffffffffff, 0x28f028e028d028c, 0x293029202910290, 0xffffffffffffffff, 0xffffffffffffffff, 0x297029602950294, 0x29b029a02990298, 0x29f029e029d029c, 0xffffffff02a102a0, 0x47e047d047c047b, 0x48204810480047f, 0x486048504840483, 0x48a048904880487, 0x48e048d048c048b, 0x49204910490048f, 0x496049504940493, 0x49a049904980497, 0x49e049d049c049b, 0x4a204a104a0049f, 0x4a604a504a404a3, 0x4aa04a904a804a7, 0x4ab04b102bb02ba, 0x4bd045dffff04b3, 0xffffffffffffffff, 0xffff02bdffff04ac, 0x4ad04b5ffffffff, 0x4c0045fffff04b7, 0xffffffffffffffff, 0xffffffffffff04ae, 0x464046102c002bf, 0x4690467ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x46f046c02c202c1, 0x476047402c30472, 0xffffffffffffffff, 0xffffffffffffffff, 0x4af04b9ffffffff, 0x4c30479ffff04bb, 0xffffffffffffffff, 0xffffffffffff04b0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff02c5ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2c902c802c702c6, 0x2cd02cc02cb02ca, 0x2d102d002cf02ce, 0x2d502d402d302d2, 0xffffffffffffffff, 0xffffffffffff02d6, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2da02d902d802d7, 0x2de02dd02dc02db, 0x2e202e102e002df, 0x2e602e502e402e3, 0x2ea02e902e802e7, 0x2ee02ed02ec02eb, 0xffffffff02f002ef, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2f402f302f202f1, 0x2f802f702f602f5, 0x2fc02fb02fa02f9, 0x30002ff02fe02fd, 0x304030303020301, 0x308030703060305, 0x30c030b030a0309, 0x310030f030e030d, 0x314031303120311, 0x318031703160315, 0x31c031b031a0319, 0xffff031f031e031d, 0xffffffff0320ffff, 0xffff03220321ffff, 0xffff0324ffff0323, 0xffffffffffff0325, 0x326ffffffffffff, 0xffff0327ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x329ffff0328ffff, 0x32bffff032affff, 0x32dffff032cffff, 0x32fffff032effff, 0x331ffff0330ffff, 0x333ffff0332ffff, 0x335ffff0334ffff, 0x337ffff0336ffff, 0x339ffff0338ffff, 0x33bffff033affff, 0x33dffff033cffff, 0x33fffff033effff, 0x341ffff0340ffff, 0x343ffff0342ffff, 0x345ffff0344ffff, 0x347ffff0346ffff, 0x349ffff0348ffff, 0x34bffff034affff, 0x34dffff034cffff, 0x34fffff034effff, 0x351ffff0350ffff, 0x353ffff0352ffff, 0x355ffff0354ffff, 0x357ffff0356ffff, 0x359ffff0358ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff035bffff035a, 0x35cffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x360035f035e035d, 0x364036303620361, 0x368036703660365, 0x36c036b036a0369, 0x370036f036e036d, 0x374037303720371, 0x378037703760375, 0x37c037b037a0379, 0x380037f037e037d, 0x383ffff03820381, 0xffffffffffffffff, 0xffffffff0384ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x386ffff0385ffff, 0x388ffff0387ffff, 0x38affff0389ffff, 0x38cffff038bffff, 0x38effff038dffff, 0x390ffff038fffff, 0x392ffff0391ffff, 0x394ffff0393ffff, 0x396ffff0395ffff, 0x398ffff0397ffff, 0x39affff0399ffff, 0xffffffff039bffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x39dffff039cffff, 0x39fffff039effff, 0x3a1ffff03a0ffff, 0x3a3ffff03a2ffff, 0x3a5ffff03a4ffff, 0x3a7ffff03a6ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3a8ffffffffffff, 0x3aaffff03a9ffff, 0x3acffff03abffff, 0x3aeffff03adffff, 0x3afffffffffffff, 0x3b1ffff03b0ffff, 0x3b3ffff03b2ffff, 0x3b5ffff03b4ffff, 0x3b7ffff03b6ffff, 0x3b9ffff03b8ffff, 0x3bbffff03baffff, 0x3bdffff03bcffff, 0x3bfffff03beffff, 0x3c1ffff03c0ffff, 0x3c3ffff03c2ffff, 0x3c5ffff03c4ffff, 0x3c7ffff03c6ffff, 0x3c9ffff03c8ffff, 0x3cbffff03caffff, 0x3cdffff03ccffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff03ceffffffff, 0x3d0ffffffff03cf, 0x3d2ffff03d1ffff, 0x3d4ffff03d3ffff, 0xffffffffffffffff, 0xffffffffffff03d5, 0x3d7ffff03d6ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3d9ffff03d8ffff, 0x3dbffff03daffff, 0xffffffff03dcffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x428042604240422, 0xffff0430042e042b, 0xffffffffffffffff, 0xffffffffffffffff, 0x434ffffffffffff, 0x43c043a04380436, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3df03de03ddffff, 0x3e303e203e103e0, 0x3e703e603e503e4, 0x3eb03ea03e903e8, 0x3ef03ee03ed03ec, 0x3f303f203f103f0, 0xffff03f603f503f4, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fa03f903f803f7, 0x3fe03fd03fc03fb, 0x4020401040003ff, 0x406040504040403, 0x40a040904080407, 0x40e040d040c040b, 0x41204110410040f, 0x416041504140413, 0x41a041904180417, 0x41e041d041c041b, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff]); //8064 bytes enum toUpperSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x20, 0x100], [ 0x100, 0x380, 0xbc0], [ 0x402030202020100, 0x202020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x3000200010000, 0x7000600050004, 0xa00090008, 0xd000c000b0000, 0x110010000f000e, 0x1400130012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150000, 0x19001800170016, 0x1d001c001b001a, 0x0, 0x1f001e0000, 0x0, 0x0, 0x20000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24002300220021, 0x25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2700260000, 0x2a00290028, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b0000, 0x0, 0x0, 0x0, 0x0, 0x2d002c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x200010000ffff, 0x6000500040003, 0xa000900080007, 0xe000d000c000b, 0x1200110010000f, 0x16001500140013, 0xffff001900180017, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff001affff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1e001d001c001b, 0x2200210020001f, 0x26002500240023, 0x2a002900280027, 0x2e002d002c002b, 0xffff00310030002f, 0x35003400330032, 0x39003800370036, 0x3bffff003affff, 0x3dffff003cffff, 0x3fffff003effff, 0x41ffff0040ffff, 0x43ffff0042ffff, 0x45ffff0044ffff, 0x47ffff0046ffff, 0x49ffff0048ffff, 0x4bffff004affff, 0x4dffff004cffff, 0x4fffff004effff, 0x51ffff0050ffff, 0x53ffff0052ffff, 0x55ffff0054ffff, 0xffff0056ffffffff, 0xffff0058ffff0057, 0xffff005affff0059, 0xffff005cffff005b, 0x5effffffff005d, 0x60ffff005fffff, 0x62ffff0061ffff, 0x64ffff0063ffff, 0x66ffff0065ffff, 0x68ffff0067ffff, 0x6affff0069ffff, 0x6cffff006bffff, 0x6effff006dffff, 0x70ffff006fffff, 0x72ffff0071ffff, 0x74ffff0073ffff, 0xffff0075ffffffff, 0x780077ffff0076, 0x7affffffff0079, 0xffffffff007bffff, 0xffffffffffff007c, 0xffffffffffff007d, 0xffff007effffffff, 0xffffffff007fffff, 0xffff00810080ffff, 0xffff0082ffffffff, 0x84ffff0083ffff, 0xffffffff0085ffff, 0xffffffffffff0086, 0xffffffff0087ffff, 0xffffffffffff0088, 0xffff008affff0089, 0xffffffff008bffff, 0x8dffff008cffff, 0xffffffffffffffff, 0xffff008f008effff, 0x92ffff00910090, 0xffff0094ffff0093, 0xffff0096ffff0095, 0xffff0098ffff0097, 0xffff009affff0099, 0x9dffff009c009b, 0x9fffff009effff, 0xa1ffff00a0ffff, 0xa3ffff00a2ffff, 0xa5ffff00a4ffff, 0xa700a6ffffffff, 0xffffffff00a8ffff, 0xaaffff00a9ffff, 0xacffff00abffff, 0xaeffff00adffff, 0xb0ffff00afffff, 0xb2ffff00b1ffff, 0xb4ffff00b3ffff, 0xb6ffff00b5ffff, 0xb8ffff00b7ffff, 0xbaffff00b9ffff, 0xbcffff00bbffff, 0xbdffffffffffff, 0xbfffff00beffff, 0xc1ffff00c0ffff, 0xc3ffff00c2ffff, 0xc5ffff00c4ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xc7ffffffff00c6, 0xffff00c9ffff00c8, 0xcaffffffffffff, 0xccffff00cbffff, 0xceffff00cdffff, 0xd200d100d000cf, 0xd500d4ffff00d3, 0xd7ffff00d6ffff, 0xffffffffffffffff, 0xd9ffffffff00d8, 0xffff00db00daffff, 0xdeffff00dd00dc, 0xdfffffffffffff, 0xffff00e100e0ffff, 0xffffffff00e2ffff, 0xffffffffffffffff, 0xffffffff00e3ffff, 0xe5ffffffff00e4, 0xffffffffffffffff, 0xe900e800e700e6, 0xffffffffffff00ea, 0xffff00ebffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff00ecffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xeeffff00edffff, 0xefffffffffffff, 0xf0ffffffffffff, 0xffffffff00f200f1, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xf600f500f400f3, 0xf900f800f7ffff, 0xfd00fc00fb00fa, 0x101010000ff00fe, 0x105010401030102, 0x109010801070106, 0x10d010c010b010a, 0x1110110010f010e, 0xffff011401130112, 0xffffffff01160115, 0x11901180117ffff, 0x11bffff011affff, 0x11dffff011cffff, 0x11fffff011effff, 0x121ffff0120ffff, 0x123ffff0122ffff, 0x125ffff0124ffff, 0xffff012801270126, 0xffffffff0129ffff, 0x12bffffffff012a, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x12f012e012d012c, 0x133013201310130, 0x137013601350134, 0x13b013a01390138, 0x13f013e013d013c, 0x143014201410140, 0x147014601450144, 0x14b014a01490148, 0x14f014e014d014c, 0x153015201510150, 0x157015601550154, 0x15b015a01590158, 0x15dffff015cffff, 0x15fffff015effff, 0x161ffff0160ffff, 0x163ffff0162ffff, 0x165ffff0164ffff, 0x167ffff0166ffff, 0x169ffff0168ffff, 0x16bffff016affff, 0xffffffff016cffff, 0xffffffffffffffff, 0x16dffffffffffff, 0x16fffff016effff, 0x171ffff0170ffff, 0x173ffff0172ffff, 0x175ffff0174ffff, 0x177ffff0176ffff, 0x179ffff0178ffff, 0x17bffff017affff, 0x17dffff017cffff, 0x17fffff017effff, 0x181ffff0180ffff, 0x183ffff0182ffff, 0x185ffff0184ffff, 0x187ffff0186ffff, 0xffff0188ffffffff, 0xffff018affff0189, 0xffff018cffff018b, 0x18f018effff018d, 0x191ffff0190ffff, 0x193ffff0192ffff, 0x195ffff0194ffff, 0x197ffff0196ffff, 0x199ffff0198ffff, 0x19bffff019affff, 0x19dffff019cffff, 0x19fffff019effff, 0x1a1ffff01a0ffff, 0x1a3ffff01a2ffff, 0x1a5ffff01a4ffff, 0x1a7ffff01a6ffff, 0x1a9ffff01a8ffff, 0x1abffff01aaffff, 0x1adffff01acffff, 0x1afffff01aeffff, 0x1b1ffff01b0ffff, 0x1b3ffff01b2ffff, 0x1b5ffff01b4ffff, 0x1b7ffff01b6ffff, 0x1b9ffff01b8ffff, 0x1bbffff01baffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1be01bd01bcffff, 0x1c201c101c001bf, 0x1c601c501c401c3, 0x1ca01c901c801c7, 0x1ce01cd01cc01cb, 0x1d201d101d001cf, 0x1d601d501d401d3, 0x1da01d901d801d7, 0x1de01dd01dc01db, 0xffff01e101e001df, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff01e2ffff, 0xffffffff01e3ffff, 0x1e5ffff01e4ffff, 0x1e7ffff01e6ffff, 0x1e9ffff01e8ffff, 0x1ebffff01eaffff, 0x1edffff01ecffff, 0x1efffff01eeffff, 0x1f1ffff01f0ffff, 0x1f3ffff01f2ffff, 0x1f5ffff01f4ffff, 0x1f7ffff01f6ffff, 0x1f9ffff01f8ffff, 0x1fbffff01faffff, 0x1fdffff01fcffff, 0x1ffffff01feffff, 0x201ffff0200ffff, 0x203ffff0202ffff, 0x205ffff0204ffff, 0x207ffff0206ffff, 0x209ffff0208ffff, 0x20bffff020affff, 0x20dffff020cffff, 0x20fffff020effff, 0x211ffff0210ffff, 0x213ffff0212ffff, 0x215ffff0214ffff, 0x217ffff0216ffff, 0x219ffff0218ffff, 0x21bffff021affff, 0x21dffff021cffff, 0x21fffff021effff, 0x221ffff0220ffff, 0x223ffff0222ffff, 0x225ffff0224ffff, 0x227ffff0226ffff, 0x229ffff0228ffff, 0x22bffff022affff, 0x22dffff022cffff, 0xffffffff022effff, 0x22fffffffffffff, 0xffffffffffffffff, 0x231ffff0230ffff, 0x233ffff0232ffff, 0x235ffff0234ffff, 0x237ffff0236ffff, 0x239ffff0238ffff, 0x23bffff023affff, 0x23dffff023cffff, 0x23fffff023effff, 0x241ffff0240ffff, 0x243ffff0242ffff, 0x245ffff0244ffff, 0x247ffff0246ffff, 0x249ffff0248ffff, 0x24bffff024affff, 0x24dffff024cffff, 0x24fffff024effff, 0x251ffff0250ffff, 0x253ffff0252ffff, 0x255ffff0254ffff, 0x257ffff0256ffff, 0x259ffff0258ffff, 0x25bffff025affff, 0x25dffff025cffff, 0x25fffff025effff, 0x263026202610260, 0x267026602650264, 0xffffffffffffffff, 0xffffffffffffffff, 0x26b026a02690268, 0xffffffff026d026c, 0xffffffffffffffff, 0xffffffffffffffff, 0x2710270026f026e, 0x275027402730272, 0xffffffffffffffff, 0xffffffffffffffff, 0x279027802770276, 0x27d027c027b027a, 0xffffffffffffffff, 0xffffffffffffffff, 0x2810280027f027e, 0xffffffff02830282, 0xffffffffffffffff, 0xffffffffffffffff, 0x285ffff0284ffff, 0x287ffff0286ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x28b028a02890288, 0x28f028e028d028c, 0xffffffffffffffff, 0xffffffffffffffff, 0x293029202910290, 0x297029602950294, 0x29b029a02990298, 0xffffffff029d029c, 0x2a102a0029f029e, 0x2a502a402a302a2, 0xffffffffffffffff, 0xffffffffffffffff, 0x2a902a802a702a6, 0x2ad02ac02ab02aa, 0xffffffffffffffff, 0xffffffffffffffff, 0x2b102b002af02ae, 0x2b502b402b302b2, 0xffffffffffffffff, 0xffffffffffffffff, 0x2b8ffff02b702b6, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff02b9ffffffff, 0x2baffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff02bc02bb, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff02be02bd, 0xffffffff02bfffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2c0ffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff02c1ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2c502c402c302c2, 0x2c902c802c702c6, 0x2cd02cc02cb02ca, 0x2d102d002cf02ce, 0xffffffffffffffff, 0xffffffffffff02d2, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2d602d502d402d3, 0x2da02d902d802d7, 0x2de02dd02dc02db, 0x2e202e102e002df, 0x2e602e502e402e3, 0x2ea02e902e802e7, 0xffffffff02ec02eb, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2f002ef02ee02ed, 0x2f402f302f202f1, 0x2f802f702f602f5, 0x2fc02fb02fa02f9, 0x30002ff02fe02fd, 0x304030303020301, 0x308030703060305, 0x30c030b030a0309, 0x310030f030e030d, 0x314031303120311, 0x318031703160315, 0xffff031b031a0319, 0xffffffff031cffff, 0xffff031e031dffff, 0xffff0320ffff031f, 0xffffffffffff0321, 0x322ffffffffffff, 0xffff0323ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x325ffff0324ffff, 0x327ffff0326ffff, 0x329ffff0328ffff, 0x32bffff032affff, 0x32dffff032cffff, 0x32fffff032effff, 0x331ffff0330ffff, 0x333ffff0332ffff, 0x335ffff0334ffff, 0x337ffff0336ffff, 0x339ffff0338ffff, 0x33bffff033affff, 0x33dffff033cffff, 0x33fffff033effff, 0x341ffff0340ffff, 0x343ffff0342ffff, 0x345ffff0344ffff, 0x347ffff0346ffff, 0x349ffff0348ffff, 0x34bffff034affff, 0x34dffff034cffff, 0x34fffff034effff, 0x351ffff0350ffff, 0x353ffff0352ffff, 0x355ffff0354ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0357ffff0356, 0x358ffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x35c035b035a0359, 0x360035f035e035d, 0x364036303620361, 0x368036703660365, 0x36c036b036a0369, 0x370036f036e036d, 0x374037303720371, 0x378037703760375, 0x37c037b037a0379, 0x37fffff037e037d, 0xffffffffffffffff, 0xffffffff0380ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x382ffff0381ffff, 0x384ffff0383ffff, 0x386ffff0385ffff, 0x388ffff0387ffff, 0x38affff0389ffff, 0x38cffff038bffff, 0x38effff038dffff, 0x390ffff038fffff, 0x392ffff0391ffff, 0x394ffff0393ffff, 0x396ffff0395ffff, 0xffffffff0397ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x399ffff0398ffff, 0x39bffff039affff, 0x39dffff039cffff, 0x39fffff039effff, 0x3a1ffff03a0ffff, 0x3a3ffff03a2ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3a4ffffffffffff, 0x3a6ffff03a5ffff, 0x3a8ffff03a7ffff, 0x3aaffff03a9ffff, 0x3abffffffffffff, 0x3adffff03acffff, 0x3afffff03aeffff, 0x3b1ffff03b0ffff, 0x3b3ffff03b2ffff, 0x3b5ffff03b4ffff, 0x3b7ffff03b6ffff, 0x3b9ffff03b8ffff, 0x3bbffff03baffff, 0x3bdffff03bcffff, 0x3bfffff03beffff, 0x3c1ffff03c0ffff, 0x3c3ffff03c2ffff, 0x3c5ffff03c4ffff, 0x3c7ffff03c6ffff, 0x3c9ffff03c8ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff03caffffffff, 0x3ccffffffff03cb, 0x3ceffff03cdffff, 0x3d0ffff03cfffff, 0xffffffffffffffff, 0xffffffffffff03d1, 0x3d3ffff03d2ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3d5ffff03d4ffff, 0x3d7ffff03d6ffff, 0xffffffff03d8ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3db03da03d9ffff, 0x3df03de03dd03dc, 0x3e303e203e103e0, 0x3e703e603e503e4, 0x3eb03ea03e903e8, 0x3ef03ee03ed03ec, 0xffff03f203f103f0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3f603f503f403f3, 0x3fa03f903f803f7, 0x3fe03fd03fc03fb, 0x4020401040003ff, 0x406040504040403, 0x40a040904080407, 0x40e040d040c040b, 0x41204110410040f, 0x416041504140413, 0x41a041904180417, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff]); //7808 bytes enum toLowerSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x20, 0x100], [ 0x100, 0x380, 0xb40], [ 0x402030202020100, 0x202020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x2000000010000, 0x6000500040003, 0x80007, 0xb000a00090000, 0xf000e000d000c, 0x110010, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13001200000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x17001600150014, 0x1b001a00190018, 0x0, 0x1e001d001c, 0x0, 0x0, 0x20001f00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24002300220021, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2600250000, 0x2900280027, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x2b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x200010000ffff, 0x6000500040003, 0xa000900080007, 0xe000d000c000b, 0x1200110010000f, 0x16001500140013, 0xffff001900180017, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1d001c001b001a, 0x210020001f001e, 0x25002400230022, 0x29002800270026, 0x2d002c002b002a, 0xffff0030002f002e, 0x34003300320031, 0xffff003700360035, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0039ffff0038, 0xffff003bffff003a, 0xffff003dffff003c, 0xffff003fffff003e, 0xffff0041ffff0040, 0xffff0043ffff0042, 0xffff0045ffff0044, 0xffff0047ffff0046, 0xffff0049ffff0048, 0xffff004bffff004a, 0xffff004dffff004c, 0xffff004fffff004e, 0xffff0051ffff0050, 0xffff0053ffff0052, 0x55ffff0054ffff, 0x57ffff0056ffff, 0x59ffff0058ffff, 0x5bffff005affff, 0xffff005cffffffff, 0xffff005effff005d, 0xffff0060ffff005f, 0xffff0062ffff0061, 0xffff0064ffff0063, 0xffff0066ffff0065, 0xffff0068ffff0067, 0xffff006affff0069, 0xffff006cffff006b, 0xffff006effff006d, 0xffff0070ffff006f, 0xffff0072ffff0071, 0x75ffff00740073, 0xffffffff0076ffff, 0xffff00780077ffff, 0x7b007affff0079, 0x7e007d007cffff, 0x80007fffffffff, 0x83ffff00820081, 0x860085ffff0084, 0xffffffffffff0087, 0x8affff00890088, 0xffff008cffff008b, 0x8f008effff008d, 0xffffffff0090ffff, 0x930092ffff0091, 0x9600950094ffff, 0x98ffff0097ffff, 0xffffffffffff0099, 0xffffffffffff009a, 0xffffffffffffffff, 0x9dffff009c009b, 0xa0009fffff009e, 0xa2ffff00a1ffff, 0xa4ffff00a3ffff, 0xa6ffff00a5ffff, 0xa8ffff00a7ffff, 0xffff00a9ffffffff, 0xffff00abffff00aa, 0xffff00adffff00ac, 0xffff00afffff00ae, 0xffff00b1ffff00b0, 0xffff00b300b2ffff, 0xb600b5ffff00b4, 0xffff00b8ffff00b7, 0xffff00baffff00b9, 0xffff00bcffff00bb, 0xffff00beffff00bd, 0xffff00c0ffff00bf, 0xffff00c2ffff00c1, 0xffff00c4ffff00c3, 0xffff00c6ffff00c5, 0xffff00c8ffff00c7, 0xffff00caffff00c9, 0xffff00ccffff00cb, 0xffff00ceffff00cd, 0xffff00d0ffff00cf, 0xffff00d2ffff00d1, 0xffff00d4ffff00d3, 0xffffffffffffffff, 0xd600d5ffffffff, 0xffff00d800d7ffff, 0xdaffff00d9ffff, 0xffff00dd00dc00db, 0xffff00dfffff00de, 0xffff00e1ffff00e0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff00e3ffff00e2, 0xffff00e4ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff00e5ffffffff, 0xffff00e800e700e6, 0xeb00eaffff00e9, 0xee00ed00ecffff, 0xf200f100f000ef, 0xf600f500f400f3, 0xfa00f900f800f7, 0xfdffff00fc00fb, 0x101010000ff00fe, 0x105010401030102, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x106ffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0108ffff0107, 0xffff010affff0109, 0xffff010cffff010b, 0xffff010effff010d, 0xffff0110ffff010f, 0xffff0112ffff0111, 0xffffffffffffffff, 0x114ffffffff0113, 0xffff01160115ffff, 0x11901180117ffff, 0x11d011c011b011a, 0x1210120011f011e, 0x125012401230122, 0x129012801270126, 0x12d012c012b012a, 0x1310130012f012e, 0x135013401330132, 0x139013801370136, 0x13d013c013b013a, 0x1410140013f013e, 0x145014401430142, 0x149014801470146, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff014bffff014a, 0xffff014dffff014c, 0xffff014fffff014e, 0xffff0151ffff0150, 0xffff0153ffff0152, 0xffff0155ffff0154, 0xffff0157ffff0156, 0xffff0159ffff0158, 0xffffffffffff015a, 0xffffffffffffffff, 0xffff015bffffffff, 0xffff015dffff015c, 0xffff015fffff015e, 0xffff0161ffff0160, 0xffff0163ffff0162, 0xffff0165ffff0164, 0xffff0167ffff0166, 0xffff0169ffff0168, 0xffff016bffff016a, 0xffff016dffff016c, 0xffff016fffff016e, 0xffff0171ffff0170, 0xffff0173ffff0172, 0xffff0175ffff0174, 0x178ffff01770176, 0x17affff0179ffff, 0x17cffff017bffff, 0xffffffff017dffff, 0xffff017fffff017e, 0xffff0181ffff0180, 0xffff0183ffff0182, 0xffff0185ffff0184, 0xffff0187ffff0186, 0xffff0189ffff0188, 0xffff018bffff018a, 0xffff018dffff018c, 0xffff018fffff018e, 0xffff0191ffff0190, 0xffff0193ffff0192, 0xffff0195ffff0194, 0xffff0197ffff0196, 0xffff0199ffff0198, 0xffff019bffff019a, 0xffff019dffff019c, 0xffff019fffff019e, 0xffff01a1ffff01a0, 0xffff01a3ffff01a2, 0xffff01a5ffff01a4, 0xffff01a7ffff01a6, 0xffff01a9ffff01a8, 0xffffffffffffffff, 0xffffffffffffffff, 0x1ac01ab01aaffff, 0x1b001af01ae01ad, 0x1b401b301b201b1, 0x1b801b701b601b5, 0x1bc01bb01ba01b9, 0x1c001bf01be01bd, 0x1c401c301c201c1, 0x1c801c701c601c5, 0x1cc01cb01ca01c9, 0xffff01cf01ce01cd, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1d301d201d101d0, 0x1d701d601d501d4, 0x1db01da01d901d8, 0x1df01de01dd01dc, 0x1e301e201e101e0, 0x1e701e601e501e4, 0x1eb01ea01e901e8, 0x1ef01ee01ed01ec, 0x1f301f201f101f0, 0x1f6ffff01f501f4, 0xffffffffffffffff, 0xffffffff01f7ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff01f9ffff01f8, 0xffff01fbffff01fa, 0xffff01fdffff01fc, 0xffff01ffffff01fe, 0xffff0201ffff0200, 0xffff0203ffff0202, 0xffff0205ffff0204, 0xffff0207ffff0206, 0xffff0209ffff0208, 0xffff020bffff020a, 0xffff020dffff020c, 0xffff020fffff020e, 0xffff0211ffff0210, 0xffff0213ffff0212, 0xffff0215ffff0214, 0xffff0217ffff0216, 0xffff0219ffff0218, 0xffff021bffff021a, 0xffff021dffff021c, 0xffff021fffff021e, 0xffff0221ffff0220, 0xffff0223ffff0222, 0xffff0225ffff0224, 0xffff0227ffff0226, 0xffff0229ffff0228, 0xffff022bffff022a, 0xffff022dffff022c, 0xffff022fffff022e, 0xffff0231ffff0230, 0xffff0233ffff0232, 0xffff0235ffff0234, 0xffff0237ffff0236, 0xffff0239ffff0238, 0xffff023bffff023a, 0xffff023dffff023c, 0xffff023fffff023e, 0xffff0241ffff0240, 0xffffffffffff0242, 0xffffffffffffffff, 0xffff0243ffffffff, 0xffff0245ffff0244, 0xffff0247ffff0246, 0xffff0249ffff0248, 0xffff024bffff024a, 0xffff024dffff024c, 0xffff024fffff024e, 0xffff0251ffff0250, 0xffff0253ffff0252, 0xffff0255ffff0254, 0xffff0257ffff0256, 0xffff0259ffff0258, 0xffff025bffff025a, 0xffff025dffff025c, 0xffff025fffff025e, 0xffff0261ffff0260, 0xffff0263ffff0262, 0xffff0265ffff0264, 0xffff0267ffff0266, 0xffff0269ffff0268, 0xffff026bffff026a, 0xffff026dffff026c, 0xffff026fffff026e, 0xffff0271ffff0270, 0xffff0273ffff0272, 0xffffffffffffffff, 0xffffffffffffffff, 0x277027602750274, 0x27b027a02790278, 0xffffffffffffffff, 0xffffffffffffffff, 0x27f027e027d027c, 0xffffffff02810280, 0xffffffffffffffff, 0xffffffffffffffff, 0x285028402830282, 0x289028802870286, 0xffffffffffffffff, 0xffffffffffffffff, 0x28d028c028b028a, 0x2910290028f028e, 0xffffffffffffffff, 0xffffffffffffffff, 0x295029402930292, 0xffffffff02970296, 0xffffffffffffffff, 0xffffffffffffffff, 0x299ffff0298ffff, 0x29bffff029affff, 0xffffffffffffffff, 0xffffffffffffffff, 0x29f029e029d029c, 0x2a302a202a102a0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2a702a602a502a4, 0x2ab02aa02a902a8, 0xffffffffffffffff, 0xffffffffffffffff, 0x2af02ae02ad02ac, 0x2b302b202b102b0, 0xffffffffffffffff, 0xffffffffffffffff, 0x2b702b602b502b4, 0x2bb02ba02b902b8, 0xffffffffffffffff, 0xffffffffffffffff, 0x2bf02be02bd02bc, 0xffffffffffff02c0, 0xffffffffffffffff, 0xffffffffffffffff, 0x2c402c302c202c1, 0xffffffffffff02c5, 0xffffffffffffffff, 0xffffffffffffffff, 0x2c902c802c702c6, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2cd02cc02cb02ca, 0xffffffffffff02ce, 0xffffffffffffffff, 0xffffffffffffffff, 0x2d202d102d002cf, 0xffffffffffff02d3, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff02d4ffffffff, 0x2d602d5ffffffff, 0xffffffffffffffff, 0xffff02d7ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2db02da02d902d8, 0x2df02de02dd02dc, 0x2e302e202e102e0, 0x2e702e602e502e4, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2e8ffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2ea02e9ffffffff, 0x2ee02ed02ec02eb, 0x2f202f102f002ef, 0x2f602f502f402f3, 0x2fa02f902f802f7, 0x2fe02fd02fc02fb, 0x3020301030002ff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x306030503040303, 0x30a030903080307, 0x30e030d030c030b, 0x31203110310030f, 0x316031503140313, 0x31a031903180317, 0x31e031d031c031b, 0x32203210320031f, 0x326032503240323, 0x32a032903280327, 0x32e032d032c032b, 0xffff03310330032f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3340333ffff0332, 0x336ffffffff0335, 0x338ffff0337ffff, 0x33b033a0339ffff, 0xffff033dffff033c, 0xffffffff033effff, 0xffffffffffffffff, 0x340033fffffffff, 0xffff0342ffff0341, 0xffff0344ffff0343, 0xffff0346ffff0345, 0xffff0348ffff0347, 0xffff034affff0349, 0xffff034cffff034b, 0xffff034effff034d, 0xffff0350ffff034f, 0xffff0352ffff0351, 0xffff0354ffff0353, 0xffff0356ffff0355, 0xffff0358ffff0357, 0xffff035affff0359, 0xffff035cffff035b, 0xffff035effff035d, 0xffff0360ffff035f, 0xffff0362ffff0361, 0xffff0364ffff0363, 0xffff0366ffff0365, 0xffff0368ffff0367, 0xffff036affff0369, 0xffff036cffff036b, 0xffff036effff036d, 0xffff0370ffff036f, 0xffff0372ffff0371, 0xffffffffffffffff, 0x373ffffffffffff, 0xffffffff0374ffff, 0xffff0375ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0377ffff0376, 0xffff0379ffff0378, 0xffff037bffff037a, 0xffff037dffff037c, 0xffff037fffff037e, 0xffff0381ffff0380, 0xffff0383ffff0382, 0xffff0385ffff0384, 0xffff0387ffff0386, 0xffff0389ffff0388, 0xffff038bffff038a, 0xffffffffffff038c, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff038effff038d, 0xffff0390ffff038f, 0xffff0392ffff0391, 0xffff0394ffff0393, 0xffff0396ffff0395, 0xffff0398ffff0397, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0399ffffffff, 0xffff039bffff039a, 0xffff039dffff039c, 0xffff039fffff039e, 0xffff03a0ffffffff, 0xffff03a2ffff03a1, 0xffff03a4ffff03a3, 0xffff03a6ffff03a5, 0xffff03a8ffff03a7, 0xffff03aaffff03a9, 0xffff03acffff03ab, 0xffff03aeffff03ad, 0xffff03b0ffff03af, 0xffff03b2ffff03b1, 0xffff03b4ffff03b3, 0xffff03b6ffff03b5, 0xffff03b8ffff03b7, 0xffff03baffff03b9, 0xffff03bcffff03bb, 0xffff03beffff03bd, 0xffffffffffffffff, 0xffffffffffffffff, 0x3c0ffff03bfffff, 0xffff03c203c1ffff, 0xffff03c4ffff03c3, 0xffff03c6ffff03c5, 0x3c7ffffffffffff, 0xffffffff03c8ffff, 0xffff03caffff03c9, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff03ccffff03cb, 0xffff03ceffff03cd, 0xffff03d0ffff03cf, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3d303d203d1ffff, 0x3d703d603d503d4, 0x3db03da03d903d8, 0x3df03de03dd03dc, 0x3e303e203e103e0, 0x3e703e603e503e4, 0xffff03ea03e903e8, 0xffffffffffffffff, 0x3ee03ed03ec03eb, 0x3f203f103f003ef, 0x3f603f503f403f3, 0x3fa03f903f803f7, 0x3fe03fd03fc03fb, 0x4020401040003ff, 0x406040504040403, 0x40a040904080407, 0x40e040d040c040b, 0x41204110410040f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff]); //8064 bytes enum toTitleSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x20, 0x100], [ 0x100, 0x380, 0xbc0], [ 0x402030202020100, 0x202020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x3000200010000, 0x7000600050004, 0xa00090008, 0xd000c000b0000, 0x110010000f000e, 0x1400130012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150000, 0x19001800170016, 0x1d001c001b001a, 0x0, 0x1f001e0000, 0x0, 0x0, 0x20000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24002300220021, 0x25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2700260000, 0x2a00290028, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b0000, 0x0, 0x0, 0x0, 0x0, 0x2d002c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x200010000ffff, 0x6000500040003, 0xa000900080007, 0xe000d000c000b, 0x1200110010000f, 0x16001500140013, 0xffff001900180017, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff001affff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1e001d001c001b, 0x2200210020001f, 0x26002500240023, 0x2a002900280027, 0x2e002d002c002b, 0xffff00310030002f, 0x35003400330032, 0x39003800370036, 0x3bffff003affff, 0x3dffff003cffff, 0x3fffff003effff, 0x41ffff0040ffff, 0x43ffff0042ffff, 0x45ffff0044ffff, 0x47ffff0046ffff, 0x49ffff0048ffff, 0x4bffff004affff, 0x4dffff004cffff, 0x4fffff004effff, 0x51ffff0050ffff, 0x53ffff0052ffff, 0x55ffff0054ffff, 0xffff0056ffffffff, 0xffff0058ffff0057, 0xffff005affff0059, 0xffff005cffff005b, 0x5effffffff005d, 0x60ffff005fffff, 0x62ffff0061ffff, 0x64ffff0063ffff, 0x66ffff0065ffff, 0x68ffff0067ffff, 0x6affff0069ffff, 0x6cffff006bffff, 0x6effff006dffff, 0x70ffff006fffff, 0x72ffff0071ffff, 0x74ffff0073ffff, 0xffff0075ffffffff, 0x780077ffff0076, 0x7affffffff0079, 0xffffffff007bffff, 0xffffffffffff007c, 0xffffffffffff007d, 0xffff007effffffff, 0xffffffff007fffff, 0xffff00810080ffff, 0xffff0082ffffffff, 0x84ffff0083ffff, 0xffffffff0085ffff, 0xffffffffffff0086, 0xffffffff0087ffff, 0xffffffffffff0088, 0xffff008affff0089, 0xffffffff008bffff, 0x8dffff008cffff, 0xffffffffffffffff, 0x910090008f008e, 0x95009400930092, 0xffff0097ffff0096, 0xffff0099ffff0098, 0xffff009bffff009a, 0xffff009dffff009c, 0xa0ffff009f009e, 0xa2ffff00a1ffff, 0xa4ffff00a3ffff, 0xa6ffff00a5ffff, 0xa8ffff00a7ffff, 0xab00aa00a9ffff, 0xffffffff00acffff, 0xaeffff00adffff, 0xb0ffff00afffff, 0xb2ffff00b1ffff, 0xb4ffff00b3ffff, 0xb6ffff00b5ffff, 0xb8ffff00b7ffff, 0xbaffff00b9ffff, 0xbcffff00bbffff, 0xbeffff00bdffff, 0xc0ffff00bfffff, 0xc1ffffffffffff, 0xc3ffff00c2ffff, 0xc5ffff00c4ffff, 0xc7ffff00c6ffff, 0xc9ffff00c8ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xcbffffffff00ca, 0xffff00cdffff00cc, 0xceffffffffffff, 0xd0ffff00cfffff, 0xd2ffff00d1ffff, 0xd600d500d400d3, 0xd900d8ffff00d7, 0xdbffff00daffff, 0xffffffffffffffff, 0xddffffffff00dc, 0xffff00df00deffff, 0xe2ffff00e100e0, 0xe3ffffffffffff, 0xffff00e500e4ffff, 0xffffffff00e6ffff, 0xffffffffffffffff, 0xffffffff00e7ffff, 0xe9ffffffff00e8, 0xffffffffffffffff, 0xed00ec00eb00ea, 0xffffffffffff00ee, 0xffff00efffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff00f0ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xf2ffff00f1ffff, 0xf3ffffffffffff, 0xf4ffffffffffff, 0xffffffff00f600f5, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfa00f900f800f7, 0xfd00fc00fbffff, 0x101010000ff00fe, 0x105010401030102, 0x109010801070106, 0x10d010c010b010a, 0x1110110010f010e, 0x115011401130112, 0xffff011801170116, 0xffffffff011a0119, 0x11d011c011bffff, 0x11fffff011effff, 0x121ffff0120ffff, 0x123ffff0122ffff, 0x125ffff0124ffff, 0x127ffff0126ffff, 0x129ffff0128ffff, 0xffff012c012b012a, 0xffffffff012dffff, 0x12fffffffff012e, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x133013201310130, 0x137013601350134, 0x13b013a01390138, 0x13f013e013d013c, 0x143014201410140, 0x147014601450144, 0x14b014a01490148, 0x14f014e014d014c, 0x153015201510150, 0x157015601550154, 0x15b015a01590158, 0x15f015e015d015c, 0x161ffff0160ffff, 0x163ffff0162ffff, 0x165ffff0164ffff, 0x167ffff0166ffff, 0x169ffff0168ffff, 0x16bffff016affff, 0x16dffff016cffff, 0x16fffff016effff, 0xffffffff0170ffff, 0xffffffffffffffff, 0x171ffffffffffff, 0x173ffff0172ffff, 0x175ffff0174ffff, 0x177ffff0176ffff, 0x179ffff0178ffff, 0x17bffff017affff, 0x17dffff017cffff, 0x17fffff017effff, 0x181ffff0180ffff, 0x183ffff0182ffff, 0x185ffff0184ffff, 0x187ffff0186ffff, 0x189ffff0188ffff, 0x18bffff018affff, 0xffff018cffffffff, 0xffff018effff018d, 0xffff0190ffff018f, 0x1930192ffff0191, 0x195ffff0194ffff, 0x197ffff0196ffff, 0x199ffff0198ffff, 0x19bffff019affff, 0x19dffff019cffff, 0x19fffff019effff, 0x1a1ffff01a0ffff, 0x1a3ffff01a2ffff, 0x1a5ffff01a4ffff, 0x1a7ffff01a6ffff, 0x1a9ffff01a8ffff, 0x1abffff01aaffff, 0x1adffff01acffff, 0x1afffff01aeffff, 0x1b1ffff01b0ffff, 0x1b3ffff01b2ffff, 0x1b5ffff01b4ffff, 0x1b7ffff01b6ffff, 0x1b9ffff01b8ffff, 0x1bbffff01baffff, 0x1bdffff01bcffff, 0x1bfffff01beffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1c201c101c0ffff, 0x1c601c501c401c3, 0x1ca01c901c801c7, 0x1ce01cd01cc01cb, 0x1d201d101d001cf, 0x1d601d501d401d3, 0x1da01d901d801d7, 0x1de01dd01dc01db, 0x1e201e101e001df, 0xffff01e501e401e3, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff01e6ffff, 0xffffffff01e7ffff, 0x1e9ffff01e8ffff, 0x1ebffff01eaffff, 0x1edffff01ecffff, 0x1efffff01eeffff, 0x1f1ffff01f0ffff, 0x1f3ffff01f2ffff, 0x1f5ffff01f4ffff, 0x1f7ffff01f6ffff, 0x1f9ffff01f8ffff, 0x1fbffff01faffff, 0x1fdffff01fcffff, 0x1ffffff01feffff, 0x201ffff0200ffff, 0x203ffff0202ffff, 0x205ffff0204ffff, 0x207ffff0206ffff, 0x209ffff0208ffff, 0x20bffff020affff, 0x20dffff020cffff, 0x20fffff020effff, 0x211ffff0210ffff, 0x213ffff0212ffff, 0x215ffff0214ffff, 0x217ffff0216ffff, 0x219ffff0218ffff, 0x21bffff021affff, 0x21dffff021cffff, 0x21fffff021effff, 0x221ffff0220ffff, 0x223ffff0222ffff, 0x225ffff0224ffff, 0x227ffff0226ffff, 0x229ffff0228ffff, 0x22bffff022affff, 0x22dffff022cffff, 0x22fffff022effff, 0x231ffff0230ffff, 0xffffffff0232ffff, 0x233ffffffffffff, 0xffffffffffffffff, 0x235ffff0234ffff, 0x237ffff0236ffff, 0x239ffff0238ffff, 0x23bffff023affff, 0x23dffff023cffff, 0x23fffff023effff, 0x241ffff0240ffff, 0x243ffff0242ffff, 0x245ffff0244ffff, 0x247ffff0246ffff, 0x249ffff0248ffff, 0x24bffff024affff, 0x24dffff024cffff, 0x24fffff024effff, 0x251ffff0250ffff, 0x253ffff0252ffff, 0x255ffff0254ffff, 0x257ffff0256ffff, 0x259ffff0258ffff, 0x25bffff025affff, 0x25dffff025cffff, 0x25fffff025effff, 0x261ffff0260ffff, 0x263ffff0262ffff, 0x267026602650264, 0x26b026a02690268, 0xffffffffffffffff, 0xffffffffffffffff, 0x26f026e026d026c, 0xffffffff02710270, 0xffffffffffffffff, 0xffffffffffffffff, 0x275027402730272, 0x279027802770276, 0xffffffffffffffff, 0xffffffffffffffff, 0x27d027c027b027a, 0x2810280027f027e, 0xffffffffffffffff, 0xffffffffffffffff, 0x285028402830282, 0xffffffff02870286, 0xffffffffffffffff, 0xffffffffffffffff, 0x289ffff0288ffff, 0x28bffff028affff, 0xffffffffffffffff, 0xffffffffffffffff, 0x28f028e028d028c, 0x293029202910290, 0xffffffffffffffff, 0xffffffffffffffff, 0x297029602950294, 0x29b029a02990298, 0x29f029e029d029c, 0xffffffff02a102a0, 0x2a502a402a302a2, 0x2a902a802a702a6, 0xffffffffffffffff, 0xffffffffffffffff, 0x2ad02ac02ab02aa, 0x2b102b002af02ae, 0xffffffffffffffff, 0xffffffffffffffff, 0x2b502b402b302b2, 0x2b902b802b702b6, 0xffffffffffffffff, 0xffffffffffffffff, 0x2bcffff02bb02ba, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff02bdffffffff, 0x2beffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff02c002bf, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff02c202c1, 0xffffffff02c3ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2c4ffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff02c5ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2c902c802c702c6, 0x2cd02cc02cb02ca, 0x2d102d002cf02ce, 0x2d502d402d302d2, 0xffffffffffffffff, 0xffffffffffff02d6, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2da02d902d802d7, 0x2de02dd02dc02db, 0x2e202e102e002df, 0x2e602e502e402e3, 0x2ea02e902e802e7, 0x2ee02ed02ec02eb, 0xffffffff02f002ef, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x2f402f302f202f1, 0x2f802f702f602f5, 0x2fc02fb02fa02f9, 0x30002ff02fe02fd, 0x304030303020301, 0x308030703060305, 0x30c030b030a0309, 0x310030f030e030d, 0x314031303120311, 0x318031703160315, 0x31c031b031a0319, 0xffff031f031e031d, 0xffffffff0320ffff, 0xffff03220321ffff, 0xffff0324ffff0323, 0xffffffffffff0325, 0x326ffffffffffff, 0xffff0327ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x329ffff0328ffff, 0x32bffff032affff, 0x32dffff032cffff, 0x32fffff032effff, 0x331ffff0330ffff, 0x333ffff0332ffff, 0x335ffff0334ffff, 0x337ffff0336ffff, 0x339ffff0338ffff, 0x33bffff033affff, 0x33dffff033cffff, 0x33fffff033effff, 0x341ffff0340ffff, 0x343ffff0342ffff, 0x345ffff0344ffff, 0x347ffff0346ffff, 0x349ffff0348ffff, 0x34bffff034affff, 0x34dffff034cffff, 0x34fffff034effff, 0x351ffff0350ffff, 0x353ffff0352ffff, 0x355ffff0354ffff, 0x357ffff0356ffff, 0x359ffff0358ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff035bffff035a, 0x35cffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x360035f035e035d, 0x364036303620361, 0x368036703660365, 0x36c036b036a0369, 0x370036f036e036d, 0x374037303720371, 0x378037703760375, 0x37c037b037a0379, 0x380037f037e037d, 0x383ffff03820381, 0xffffffffffffffff, 0xffffffff0384ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x386ffff0385ffff, 0x388ffff0387ffff, 0x38affff0389ffff, 0x38cffff038bffff, 0x38effff038dffff, 0x390ffff038fffff, 0x392ffff0391ffff, 0x394ffff0393ffff, 0x396ffff0395ffff, 0x398ffff0397ffff, 0x39affff0399ffff, 0xffffffff039bffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x39dffff039cffff, 0x39fffff039effff, 0x3a1ffff03a0ffff, 0x3a3ffff03a2ffff, 0x3a5ffff03a4ffff, 0x3a7ffff03a6ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3a8ffffffffffff, 0x3aaffff03a9ffff, 0x3acffff03abffff, 0x3aeffff03adffff, 0x3afffffffffffff, 0x3b1ffff03b0ffff, 0x3b3ffff03b2ffff, 0x3b5ffff03b4ffff, 0x3b7ffff03b6ffff, 0x3b9ffff03b8ffff, 0x3bbffff03baffff, 0x3bdffff03bcffff, 0x3bfffff03beffff, 0x3c1ffff03c0ffff, 0x3c3ffff03c2ffff, 0x3c5ffff03c4ffff, 0x3c7ffff03c6ffff, 0x3c9ffff03c8ffff, 0x3cbffff03caffff, 0x3cdffff03ccffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff03ceffffffff, 0x3d0ffffffff03cf, 0x3d2ffff03d1ffff, 0x3d4ffff03d3ffff, 0xffffffffffffffff, 0xffffffffffff03d5, 0x3d7ffff03d6ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3d9ffff03d8ffff, 0x3dbffff03daffff, 0xffffffff03dcffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3df03de03ddffff, 0x3e303e203e103e0, 0x3e703e603e503e4, 0x3eb03ea03e903e8, 0x3ef03ee03ed03ec, 0x3f303f203f103f0, 0xffff03f603f503f4, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fa03f903f803f7, 0x3fe03fd03fc03fb, 0x4020401040003ff, 0x406040504040403, 0x40a040904080407, 0x40e040d040c040b, 0x41204110410040f, 0x416041504140413, 0x41a041904180417, 0x41e041d041c041b, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff]); @property { private alias _IUA = immutable(uint[]); _IUA toUpperTable() { static _IUA t = [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x39c, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11a, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12a, 0x12c, 0x12e, 0x49, 0x132, 0x134, 0x136, 0x139, 0x13b, 0x13d, 0x13f, 0x141, 0x143, 0x145, 0x147, 0x14a, 0x14c, 0x14e, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15a, 0x15c, 0x15e, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16a, 0x16c, 0x16e, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17b, 0x17d, 0x53, 0x243, 0x182, 0x184, 0x187, 0x18b, 0x191, 0x1f6, 0x198, 0x23d, 0x220, 0x1a0, 0x1a2, 0x1a4, 0x1a7, 0x1ac, 0x1af, 0x1b3, 0x1b5, 0x1b8, 0x1bc, 0x1f7, 0x1c4, 0x1c4, 0x1c7, 0x1c7, 0x1ca, 0x1ca, 0x1cd, 0x1cf, 0x1d1, 0x1d3, 0x1d5, 0x1d7, 0x1d9, 0x1db, 0x18e, 0x1de, 0x1e0, 0x1e2, 0x1e4, 0x1e6, 0x1e8, 0x1ea, 0x1ec, 0x1ee, 0x1f1, 0x1f1, 0x1f4, 0x1f8, 0x1fa, 0x1fc, 0x1fe, 0x200, 0x202, 0x204, 0x206, 0x208, 0x20a, 0x20c, 0x20e, 0x210, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21c, 0x21e, 0x222, 0x224, 0x226, 0x228, 0x22a, 0x22c, 0x22e, 0x230, 0x232, 0x23b, 0x2c7e, 0x2c7f, 0x241, 0x246, 0x248, 0x24a, 0x24c, 0x24e, 0x2c6f, 0x2c6d, 0x2c70, 0x181, 0x186, 0x189, 0x18a, 0x18f, 0x190, 0x193, 0x194, 0xa78d, 0xa7aa, 0x197, 0x196, 0x2c62, 0x19c, 0x2c6e, 0x19d, 0x19f, 0x2c64, 0x1a6, 0x1a9, 0x1ae, 0x244, 0x1b1, 0x1b2, 0x245, 0x1b7, 0x399, 0x370, 0x372, 0x376, 0x3fd, 0x3fe, 0x3ff, 0x386, 0x388, 0x389, 0x38a, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39a, 0x39b, 0x39c, 0x39d, 0x39e, 0x39f, 0x3a0, 0x3a1, 0x3a3, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, 0x3a8, 0x3a9, 0x3aa, 0x3ab, 0x38c, 0x38e, 0x38f, 0x392, 0x398, 0x3a6, 0x3a0, 0x3cf, 0x3d8, 0x3da, 0x3dc, 0x3de, 0x3e0, 0x3e2, 0x3e4, 0x3e6, 0x3e8, 0x3ea, 0x3ec, 0x3ee, 0x39a, 0x3a1, 0x3f9, 0x395, 0x3f7, 0x3fa, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41a, 0x41b, 0x41c, 0x41d, 0x41e, 0x41f, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42a, 0x42b, 0x42c, 0x42d, 0x42e, 0x42f, 0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f, 0x460, 0x462, 0x464, 0x466, 0x468, 0x46a, 0x46c, 0x46e, 0x470, 0x472, 0x474, 0x476, 0x478, 0x47a, 0x47c, 0x47e, 0x480, 0x48a, 0x48c, 0x48e, 0x490, 0x492, 0x494, 0x496, 0x498, 0x49a, 0x49c, 0x49e, 0x4a0, 0x4a2, 0x4a4, 0x4a6, 0x4a8, 0x4aa, 0x4ac, 0x4ae, 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba, 0x4bc, 0x4be, 0x4c1, 0x4c3, 0x4c5, 0x4c7, 0x4c9, 0x4cb, 0x4cd, 0x4c0, 0x4d0, 0x4d2, 0x4d4, 0x4d6, 0x4d8, 0x4da, 0x4dc, 0x4de, 0x4e0, 0x4e2, 0x4e4, 0x4e6, 0x4e8, 0x4ea, 0x4ec, 0x4ee, 0x4f0, 0x4f2, 0x4f4, 0x4f6, 0x4f8, 0x4fa, 0x4fc, 0x4fe, 0x500, 0x502, 0x504, 0x506, 0x508, 0x50a, 0x50c, 0x50e, 0x510, 0x512, 0x514, 0x516, 0x518, 0x51a, 0x51c, 0x51e, 0x520, 0x522, 0x524, 0x526, 0x531, 0x532, 0x533, 0x534, 0x535, 0x536, 0x537, 0x538, 0x539, 0x53a, 0x53b, 0x53c, 0x53d, 0x53e, 0x53f, 0x540, 0x541, 0x542, 0x543, 0x544, 0x545, 0x546, 0x547, 0x548, 0x549, 0x54a, 0x54b, 0x54c, 0x54d, 0x54e, 0x54f, 0x550, 0x551, 0x552, 0x553, 0x554, 0x555, 0x556, 0xa77d, 0x2c63, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, 0x1e0c, 0x1e0e, 0x1e10, 0x1e12, 0x1e14, 0x1e16, 0x1e18, 0x1e1a, 0x1e1c, 0x1e1e, 0x1e20, 0x1e22, 0x1e24, 0x1e26, 0x1e28, 0x1e2a, 0x1e2c, 0x1e2e, 0x1e30, 0x1e32, 0x1e34, 0x1e36, 0x1e38, 0x1e3a, 0x1e3c, 0x1e3e, 0x1e40, 0x1e42, 0x1e44, 0x1e46, 0x1e48, 0x1e4a, 0x1e4c, 0x1e4e, 0x1e50, 0x1e52, 0x1e54, 0x1e56, 0x1e58, 0x1e5a, 0x1e5c, 0x1e5e, 0x1e60, 0x1e62, 0x1e64, 0x1e66, 0x1e68, 0x1e6a, 0x1e6c, 0x1e6e, 0x1e70, 0x1e72, 0x1e74, 0x1e76, 0x1e78, 0x1e7a, 0x1e7c, 0x1e7e, 0x1e80, 0x1e82, 0x1e84, 0x1e86, 0x1e88, 0x1e8a, 0x1e8c, 0x1e8e, 0x1e90, 0x1e92, 0x1e94, 0x1e60, 0x1ea0, 0x1ea2, 0x1ea4, 0x1ea6, 0x1ea8, 0x1eaa, 0x1eac, 0x1eae, 0x1eb0, 0x1eb2, 0x1eb4, 0x1eb6, 0x1eb8, 0x1eba, 0x1ebc, 0x1ebe, 0x1ec0, 0x1ec2, 0x1ec4, 0x1ec6, 0x1ec8, 0x1eca, 0x1ecc, 0x1ece, 0x1ed0, 0x1ed2, 0x1ed4, 0x1ed6, 0x1ed8, 0x1eda, 0x1edc, 0x1ede, 0x1ee0, 0x1ee2, 0x1ee4, 0x1ee6, 0x1ee8, 0x1eea, 0x1eec, 0x1eee, 0x1ef0, 0x1ef2, 0x1ef4, 0x1ef6, 0x1ef8, 0x1efa, 0x1efc, 0x1efe, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0x1f59, 0x1f5b, 0x1f5d, 0x1f5f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, 0x1ffa, 0x1ffb, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fb8, 0x1fb9, 0x1fbc, 0x399, 0x1fcc, 0x1fd8, 0x1fd9, 0x1fe8, 0x1fe9, 0x1fec, 0x1ffc, 0x2132, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, 0x216c, 0x216d, 0x216e, 0x216f, 0x2183, 0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, 0x24bb, 0x24bc, 0x24bd, 0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, 0x24c3, 0x24c4, 0x24c5, 0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, 0x24cb, 0x24cc, 0x24cd, 0x24ce, 0x24cf, 0x2c00, 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x2c08, 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x2c10, 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, 0x2c18, 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, 0x2c20, 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, 0x2c28, 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x2c60, 0x23a, 0x23e, 0x2c67, 0x2c69, 0x2c6b, 0x2c72, 0x2c75, 0x2c80, 0x2c82, 0x2c84, 0x2c86, 0x2c88, 0x2c8a, 0x2c8c, 0x2c8e, 0x2c90, 0x2c92, 0x2c94, 0x2c96, 0x2c98, 0x2c9a, 0x2c9c, 0x2c9e, 0x2ca0, 0x2ca2, 0x2ca4, 0x2ca6, 0x2ca8, 0x2caa, 0x2cac, 0x2cae, 0x2cb0, 0x2cb2, 0x2cb4, 0x2cb6, 0x2cb8, 0x2cba, 0x2cbc, 0x2cbe, 0x2cc0, 0x2cc2, 0x2cc4, 0x2cc6, 0x2cc8, 0x2cca, 0x2ccc, 0x2cce, 0x2cd0, 0x2cd2, 0x2cd4, 0x2cd6, 0x2cd8, 0x2cda, 0x2cdc, 0x2cde, 0x2ce0, 0x2ce2, 0x2ceb, 0x2ced, 0x2cf2, 0x10a0, 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0, 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8, 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0, 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0x10c7, 0x10cd, 0xa640, 0xa642, 0xa644, 0xa646, 0xa648, 0xa64a, 0xa64c, 0xa64e, 0xa650, 0xa652, 0xa654, 0xa656, 0xa658, 0xa65a, 0xa65c, 0xa65e, 0xa660, 0xa662, 0xa664, 0xa666, 0xa668, 0xa66a, 0xa66c, 0xa680, 0xa682, 0xa684, 0xa686, 0xa688, 0xa68a, 0xa68c, 0xa68e, 0xa690, 0xa692, 0xa694, 0xa696, 0xa722, 0xa724, 0xa726, 0xa728, 0xa72a, 0xa72c, 0xa72e, 0xa732, 0xa734, 0xa736, 0xa738, 0xa73a, 0xa73c, 0xa73e, 0xa740, 0xa742, 0xa744, 0xa746, 0xa748, 0xa74a, 0xa74c, 0xa74e, 0xa750, 0xa752, 0xa754, 0xa756, 0xa758, 0xa75a, 0xa75c, 0xa75e, 0xa760, 0xa762, 0xa764, 0xa766, 0xa768, 0xa76a, 0xa76c, 0xa76e, 0xa779, 0xa77b, 0xa77e, 0xa780, 0xa782, 0xa784, 0xa786, 0xa78b, 0xa790, 0xa792, 0xa7a0, 0xa7a2, 0xa7a4, 0xa7a6, 0xa7a8, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, 0xff3a, 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407, 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f, 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417, 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f, 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427, 0x2000053, 0x53, 0x130, 0x2000046, 0x46, 0x2000046, 0x49, 0x2000046, 0x4c, 0x3000046, 0x46, 0x49, 0x3000046, 0x46, 0x4c, 0x2000053, 0x54, 0x2000053, 0x54, 0x2000535, 0x552, 0x2000544, 0x546, 0x2000544, 0x535, 0x2000544, 0x53b, 0x200054e, 0x546, 0x2000544, 0x53d, 0x20002bc, 0x4e, 0x3000399, 0x308, 0x301, 0x30003a5, 0x308, 0x301, 0x200004a, 0x30c, 0x2000048, 0x331, 0x2000054, 0x308, 0x2000057, 0x30a, 0x2000059, 0x30a, 0x2000041, 0x2be, 0x20003a5, 0x313, 0x30003a5, 0x313, 0x300, 0x30003a5, 0x313, 0x301, 0x30003a5, 0x313, 0x342, 0x2000391, 0x342, 0x2000397, 0x342, 0x3000399, 0x308, 0x300, 0x3000399, 0x308, 0x301, 0x2000399, 0x342, 0x3000399, 0x308, 0x342, 0x30003a5, 0x308, 0x300, 0x30003a5, 0x308, 0x301, 0x20003a1, 0x313, 0x20003a5, 0x342, 0x30003a5, 0x308, 0x342, 0x20003a9, 0x342, 0x2001f08, 0x399, 0x2001f09, 0x399, 0x2001f0a, 0x399, 0x2001f0b, 0x399, 0x2001f0c, 0x399, 0x2001f0d, 0x399, 0x2001f0e, 0x399, 0x2001f0f, 0x399, 0x2001f08, 0x399, 0x2001f09, 0x399, 0x2001f0a, 0x399, 0x2001f0b, 0x399, 0x2001f0c, 0x399, 0x2001f0d, 0x399, 0x2001f0e, 0x399, 0x2001f0f, 0x399, 0x2001f28, 0x399, 0x2001f29, 0x399, 0x2001f2a, 0x399, 0x2001f2b, 0x399, 0x2001f2c, 0x399, 0x2001f2d, 0x399, 0x2001f2e, 0x399, 0x2001f2f, 0x399, 0x2001f28, 0x399, 0x2001f29, 0x399, 0x2001f2a, 0x399, 0x2001f2b, 0x399, 0x2001f2c, 0x399, 0x2001f2d, 0x399, 0x2001f2e, 0x399, 0x2001f2f, 0x399, 0x2001f68, 0x399, 0x2001f69, 0x399, 0x2001f6a, 0x399, 0x2001f6b, 0x399, 0x2001f6c, 0x399, 0x2001f6d, 0x399, 0x2001f6e, 0x399, 0x2001f6f, 0x399, 0x2001f68, 0x399, 0x2001f69, 0x399, 0x2001f6a, 0x399, 0x2001f6b, 0x399, 0x2001f6c, 0x399, 0x2001f6d, 0x399, 0x2001f6e, 0x399, 0x2001f6f, 0x399, 0x2000391, 0x399, 0x2000391, 0x399, 0x2000397, 0x399, 0x2000397, 0x399, 0x20003a9, 0x399, 0x20003a9, 0x399, 0x2001fba, 0x399, 0x2000386, 0x399, 0x2001fca, 0x399, 0x2000389, 0x399, 0x2001ffa, 0x399, 0x200038f, 0x399, 0x3000391, 0x342, 0x399, 0x3000397, 0x342, 0x399, 0x30003a9, 0x342, 0x399]; return t; } _IUA toLowerTable() { static _IUA t = [ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10b, 0x10d, 0x10f, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11b, 0x11d, 0x11f, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12b, 0x12d, 0x12f, 0x69, 0x133, 0x135, 0x137, 0x13a, 0x13c, 0x13e, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14b, 0x14d, 0x14f, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15b, 0x15d, 0x15f, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16b, 0x16d, 0x16f, 0x171, 0x173, 0x175, 0x177, 0xff, 0x17a, 0x17c, 0x17e, 0x253, 0x183, 0x185, 0x254, 0x188, 0x256, 0x257, 0x18c, 0x1dd, 0x259, 0x25b, 0x192, 0x260, 0x263, 0x269, 0x268, 0x199, 0x26f, 0x272, 0x275, 0x1a1, 0x1a3, 0x1a5, 0x280, 0x1a8, 0x283, 0x1ad, 0x288, 0x1b0, 0x28a, 0x28b, 0x1b4, 0x1b6, 0x292, 0x1b9, 0x1bd, 0x1c6, 0x1c6, 0x1c9, 0x1c9, 0x1cc, 0x1cc, 0x1ce, 0x1d0, 0x1d2, 0x1d4, 0x1d6, 0x1d8, 0x1da, 0x1dc, 0x1df, 0x1e1, 0x1e3, 0x1e5, 0x1e7, 0x1e9, 0x1eb, 0x1ed, 0x1ef, 0x1f3, 0x1f3, 0x1f5, 0x195, 0x1bf, 0x1f9, 0x1fb, 0x1fd, 0x1ff, 0x201, 0x203, 0x205, 0x207, 0x209, 0x20b, 0x20d, 0x20f, 0x211, 0x213, 0x215, 0x217, 0x219, 0x21b, 0x21d, 0x21f, 0x19e, 0x223, 0x225, 0x227, 0x229, 0x22b, 0x22d, 0x22f, 0x231, 0x233, 0x2c65, 0x23c, 0x19a, 0x2c66, 0x242, 0x180, 0x289, 0x28c, 0x247, 0x249, 0x24b, 0x24d, 0x24f, 0x371, 0x373, 0x377, 0x3ac, 0x3ad, 0x3ae, 0x3af, 0x3cc, 0x3cd, 0x3ce, 0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b7, 0x3b8, 0x3b9, 0x3ba, 0x3bb, 0x3bc, 0x3bd, 0x3be, 0x3bf, 0x3c0, 0x3c1, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7, 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x3d7, 0x3d9, 0x3db, 0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e5, 0x3e7, 0x3e9, 0x3eb, 0x3ed, 0x3ef, 0x3b8, 0x3f8, 0x3f2, 0x3fb, 0x37b, 0x37c, 0x37d, 0x450, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45a, 0x45b, 0x45c, 0x45d, 0x45e, 0x45f, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43a, 0x43b, 0x43c, 0x43d, 0x43e, 0x43f, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44a, 0x44b, 0x44c, 0x44d, 0x44e, 0x44f, 0x461, 0x463, 0x465, 0x467, 0x469, 0x46b, 0x46d, 0x46f, 0x471, 0x473, 0x475, 0x477, 0x479, 0x47b, 0x47d, 0x47f, 0x481, 0x48b, 0x48d, 0x48f, 0x491, 0x493, 0x495, 0x497, 0x499, 0x49b, 0x49d, 0x49f, 0x4a1, 0x4a3, 0x4a5, 0x4a7, 0x4a9, 0x4ab, 0x4ad, 0x4af, 0x4b1, 0x4b3, 0x4b5, 0x4b7, 0x4b9, 0x4bb, 0x4bd, 0x4bf, 0x4cf, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4cc, 0x4ce, 0x4d1, 0x4d3, 0x4d5, 0x4d7, 0x4d9, 0x4db, 0x4dd, 0x4df, 0x4e1, 0x4e3, 0x4e5, 0x4e7, 0x4e9, 0x4eb, 0x4ed, 0x4ef, 0x4f1, 0x4f3, 0x4f5, 0x4f7, 0x4f9, 0x4fb, 0x4fd, 0x4ff, 0x501, 0x503, 0x505, 0x507, 0x509, 0x50b, 0x50d, 0x50f, 0x511, 0x513, 0x515, 0x517, 0x519, 0x51b, 0x51d, 0x51f, 0x521, 0x523, 0x525, 0x527, 0x561, 0x562, 0x563, 0x564, 0x565, 0x566, 0x567, 0x568, 0x569, 0x56a, 0x56b, 0x56c, 0x56d, 0x56e, 0x56f, 0x570, 0x571, 0x572, 0x573, 0x574, 0x575, 0x576, 0x577, 0x578, 0x579, 0x57a, 0x57b, 0x57c, 0x57d, 0x57e, 0x57f, 0x580, 0x581, 0x582, 0x583, 0x584, 0x585, 0x586, 0x2d00, 0x2d01, 0x2d02, 0x2d03, 0x2d04, 0x2d05, 0x2d06, 0x2d07, 0x2d08, 0x2d09, 0x2d0a, 0x2d0b, 0x2d0c, 0x2d0d, 0x2d0e, 0x2d0f, 0x2d10, 0x2d11, 0x2d12, 0x2d13, 0x2d14, 0x2d15, 0x2d16, 0x2d17, 0x2d18, 0x2d19, 0x2d1a, 0x2d1b, 0x2d1c, 0x2d1d, 0x2d1e, 0x2d1f, 0x2d20, 0x2d21, 0x2d22, 0x2d23, 0x2d24, 0x2d25, 0x2d27, 0x2d2d, 0x1e01, 0x1e03, 0x1e05, 0x1e07, 0x1e09, 0x1e0b, 0x1e0d, 0x1e0f, 0x1e11, 0x1e13, 0x1e15, 0x1e17, 0x1e19, 0x1e1b, 0x1e1d, 0x1e1f, 0x1e21, 0x1e23, 0x1e25, 0x1e27, 0x1e29, 0x1e2b, 0x1e2d, 0x1e2f, 0x1e31, 0x1e33, 0x1e35, 0x1e37, 0x1e39, 0x1e3b, 0x1e3d, 0x1e3f, 0x1e41, 0x1e43, 0x1e45, 0x1e47, 0x1e49, 0x1e4b, 0x1e4d, 0x1e4f, 0x1e51, 0x1e53, 0x1e55, 0x1e57, 0x1e59, 0x1e5b, 0x1e5d, 0x1e5f, 0x1e61, 0x1e63, 0x1e65, 0x1e67, 0x1e69, 0x1e6b, 0x1e6d, 0x1e6f, 0x1e71, 0x1e73, 0x1e75, 0x1e77, 0x1e79, 0x1e7b, 0x1e7d, 0x1e7f, 0x1e81, 0x1e83, 0x1e85, 0x1e87, 0x1e89, 0x1e8b, 0x1e8d, 0x1e8f, 0x1e91, 0x1e93, 0x1e95, 0xdf, 0x1ea1, 0x1ea3, 0x1ea5, 0x1ea7, 0x1ea9, 0x1eab, 0x1ead, 0x1eaf, 0x1eb1, 0x1eb3, 0x1eb5, 0x1eb7, 0x1eb9, 0x1ebb, 0x1ebd, 0x1ebf, 0x1ec1, 0x1ec3, 0x1ec5, 0x1ec7, 0x1ec9, 0x1ecb, 0x1ecd, 0x1ecf, 0x1ed1, 0x1ed3, 0x1ed5, 0x1ed7, 0x1ed9, 0x1edb, 0x1edd, 0x1edf, 0x1ee1, 0x1ee3, 0x1ee5, 0x1ee7, 0x1ee9, 0x1eeb, 0x1eed, 0x1eef, 0x1ef1, 0x1ef3, 0x1ef5, 0x1ef7, 0x1ef9, 0x1efb, 0x1efd, 0x1eff, 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f51, 0x1f53, 0x1f55, 0x1f57, 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0x3c9, 0x6b, 0xe5, 0x214e, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, 0x2184, 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9, 0x2c30, 0x2c31, 0x2c32, 0x2c33, 0x2c34, 0x2c35, 0x2c36, 0x2c37, 0x2c38, 0x2c39, 0x2c3a, 0x2c3b, 0x2c3c, 0x2c3d, 0x2c3e, 0x2c3f, 0x2c40, 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2c48, 0x2c49, 0x2c4a, 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c50, 0x2c51, 0x2c52, 0x2c53, 0x2c54, 0x2c55, 0x2c56, 0x2c57, 0x2c58, 0x2c59, 0x2c5a, 0x2c5b, 0x2c5c, 0x2c5d, 0x2c5e, 0x2c61, 0x26b, 0x1d7d, 0x27d, 0x2c68, 0x2c6a, 0x2c6c, 0x251, 0x271, 0x250, 0x252, 0x2c73, 0x2c76, 0x23f, 0x240, 0x2c81, 0x2c83, 0x2c85, 0x2c87, 0x2c89, 0x2c8b, 0x2c8d, 0x2c8f, 0x2c91, 0x2c93, 0x2c95, 0x2c97, 0x2c99, 0x2c9b, 0x2c9d, 0x2c9f, 0x2ca1, 0x2ca3, 0x2ca5, 0x2ca7, 0x2ca9, 0x2cab, 0x2cad, 0x2caf, 0x2cb1, 0x2cb3, 0x2cb5, 0x2cb7, 0x2cb9, 0x2cbb, 0x2cbd, 0x2cbf, 0x2cc1, 0x2cc3, 0x2cc5, 0x2cc7, 0x2cc9, 0x2ccb, 0x2ccd, 0x2ccf, 0x2cd1, 0x2cd3, 0x2cd5, 0x2cd7, 0x2cd9, 0x2cdb, 0x2cdd, 0x2cdf, 0x2ce1, 0x2ce3, 0x2cec, 0x2cee, 0x2cf3, 0xa641, 0xa643, 0xa645, 0xa647, 0xa649, 0xa64b, 0xa64d, 0xa64f, 0xa651, 0xa653, 0xa655, 0xa657, 0xa659, 0xa65b, 0xa65d, 0xa65f, 0xa661, 0xa663, 0xa665, 0xa667, 0xa669, 0xa66b, 0xa66d, 0xa681, 0xa683, 0xa685, 0xa687, 0xa689, 0xa68b, 0xa68d, 0xa68f, 0xa691, 0xa693, 0xa695, 0xa697, 0xa723, 0xa725, 0xa727, 0xa729, 0xa72b, 0xa72d, 0xa72f, 0xa733, 0xa735, 0xa737, 0xa739, 0xa73b, 0xa73d, 0xa73f, 0xa741, 0xa743, 0xa745, 0xa747, 0xa749, 0xa74b, 0xa74d, 0xa74f, 0xa751, 0xa753, 0xa755, 0xa757, 0xa759, 0xa75b, 0xa75d, 0xa75f, 0xa761, 0xa763, 0xa765, 0xa767, 0xa769, 0xa76b, 0xa76d, 0xa76f, 0xa77a, 0xa77c, 0x1d79, 0xa77f, 0xa781, 0xa783, 0xa785, 0xa787, 0xa78c, 0x265, 0xa791, 0xa793, 0xa7a1, 0xa7a3, 0xa7a5, 0xa7a7, 0xa7a9, 0x266, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, 0xff58, 0xff59, 0xff5a, 0x10428, 0x10429, 0x1042a, 0x1042b, 0x1042c, 0x1042d, 0x1042e, 0x1042f, 0x10430, 0x10431, 0x10432, 0x10433, 0x10434, 0x10435, 0x10436, 0x10437, 0x10438, 0x10439, 0x1043a, 0x1043b, 0x1043c, 0x1043d, 0x1043e, 0x1043f, 0x10440, 0x10441, 0x10442, 0x10443, 0x10444, 0x10445, 0x10446, 0x10447, 0x10448, 0x10449, 0x1044a, 0x1044b, 0x1044c, 0x1044d, 0x1044e, 0x1044f, 0xdf, 0x2000069, 0x307, 0xfb00, 0xfb01, 0xfb02, 0xfb03, 0xfb04, 0xfb05, 0xfb06, 0x587, 0xfb13, 0xfb14, 0xfb15, 0xfb16, 0xfb17, 0x149, 0x390, 0x3b0, 0x1f0, 0x1e96, 0x1e97, 0x1e98, 0x1e99, 0x1e9a, 0x1f50, 0x1f52, 0x1f54, 0x1f56, 0x1fb6, 0x1fc6, 0x1fd2, 0x1fd3, 0x1fd6, 0x1fd7, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe6, 0x1fe7, 0x1ff6, 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, 0x1fb3, 0x1fb3, 0x1fc3, 0x1fc3, 0x1ff3, 0x1ff3, 0x1fb2, 0x1fb4, 0x1fc2, 0x1fc4, 0x1ff2, 0x1ff4, 0x1fb7, 0x1fc7, 0x1ff7]; return t; } _IUA toTitleTable() { static _IUA t = [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x39c, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11a, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12a, 0x12c, 0x12e, 0x49, 0x132, 0x134, 0x136, 0x139, 0x13b, 0x13d, 0x13f, 0x141, 0x143, 0x145, 0x147, 0x14a, 0x14c, 0x14e, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15a, 0x15c, 0x15e, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16a, 0x16c, 0x16e, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17b, 0x17d, 0x53, 0x243, 0x182, 0x184, 0x187, 0x18b, 0x191, 0x1f6, 0x198, 0x23d, 0x220, 0x1a0, 0x1a2, 0x1a4, 0x1a7, 0x1ac, 0x1af, 0x1b3, 0x1b5, 0x1b8, 0x1bc, 0x1f7, 0x1c5, 0x1c5, 0x1c5, 0x1c8, 0x1c8, 0x1c8, 0x1cb, 0x1cb, 0x1cb, 0x1cd, 0x1cf, 0x1d1, 0x1d3, 0x1d5, 0x1d7, 0x1d9, 0x1db, 0x18e, 0x1de, 0x1e0, 0x1e2, 0x1e4, 0x1e6, 0x1e8, 0x1ea, 0x1ec, 0x1ee, 0x1f2, 0x1f2, 0x1f2, 0x1f4, 0x1f8, 0x1fa, 0x1fc, 0x1fe, 0x200, 0x202, 0x204, 0x206, 0x208, 0x20a, 0x20c, 0x20e, 0x210, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21c, 0x21e, 0x222, 0x224, 0x226, 0x228, 0x22a, 0x22c, 0x22e, 0x230, 0x232, 0x23b, 0x2c7e, 0x2c7f, 0x241, 0x246, 0x248, 0x24a, 0x24c, 0x24e, 0x2c6f, 0x2c6d, 0x2c70, 0x181, 0x186, 0x189, 0x18a, 0x18f, 0x190, 0x193, 0x194, 0xa78d, 0xa7aa, 0x197, 0x196, 0x2c62, 0x19c, 0x2c6e, 0x19d, 0x19f, 0x2c64, 0x1a6, 0x1a9, 0x1ae, 0x244, 0x1b1, 0x1b2, 0x245, 0x1b7, 0x399, 0x370, 0x372, 0x376, 0x3fd, 0x3fe, 0x3ff, 0x386, 0x388, 0x389, 0x38a, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39a, 0x39b, 0x39c, 0x39d, 0x39e, 0x39f, 0x3a0, 0x3a1, 0x3a3, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, 0x3a8, 0x3a9, 0x3aa, 0x3ab, 0x38c, 0x38e, 0x38f, 0x392, 0x398, 0x3a6, 0x3a0, 0x3cf, 0x3d8, 0x3da, 0x3dc, 0x3de, 0x3e0, 0x3e2, 0x3e4, 0x3e6, 0x3e8, 0x3ea, 0x3ec, 0x3ee, 0x39a, 0x3a1, 0x3f9, 0x395, 0x3f7, 0x3fa, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41a, 0x41b, 0x41c, 0x41d, 0x41e, 0x41f, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42a, 0x42b, 0x42c, 0x42d, 0x42e, 0x42f, 0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f, 0x460, 0x462, 0x464, 0x466, 0x468, 0x46a, 0x46c, 0x46e, 0x470, 0x472, 0x474, 0x476, 0x478, 0x47a, 0x47c, 0x47e, 0x480, 0x48a, 0x48c, 0x48e, 0x490, 0x492, 0x494, 0x496, 0x498, 0x49a, 0x49c, 0x49e, 0x4a0, 0x4a2, 0x4a4, 0x4a6, 0x4a8, 0x4aa, 0x4ac, 0x4ae, 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba, 0x4bc, 0x4be, 0x4c1, 0x4c3, 0x4c5, 0x4c7, 0x4c9, 0x4cb, 0x4cd, 0x4c0, 0x4d0, 0x4d2, 0x4d4, 0x4d6, 0x4d8, 0x4da, 0x4dc, 0x4de, 0x4e0, 0x4e2, 0x4e4, 0x4e6, 0x4e8, 0x4ea, 0x4ec, 0x4ee, 0x4f0, 0x4f2, 0x4f4, 0x4f6, 0x4f8, 0x4fa, 0x4fc, 0x4fe, 0x500, 0x502, 0x504, 0x506, 0x508, 0x50a, 0x50c, 0x50e, 0x510, 0x512, 0x514, 0x516, 0x518, 0x51a, 0x51c, 0x51e, 0x520, 0x522, 0x524, 0x526, 0x531, 0x532, 0x533, 0x534, 0x535, 0x536, 0x537, 0x538, 0x539, 0x53a, 0x53b, 0x53c, 0x53d, 0x53e, 0x53f, 0x540, 0x541, 0x542, 0x543, 0x544, 0x545, 0x546, 0x547, 0x548, 0x549, 0x54a, 0x54b, 0x54c, 0x54d, 0x54e, 0x54f, 0x550, 0x551, 0x552, 0x553, 0x554, 0x555, 0x556, 0xa77d, 0x2c63, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, 0x1e0c, 0x1e0e, 0x1e10, 0x1e12, 0x1e14, 0x1e16, 0x1e18, 0x1e1a, 0x1e1c, 0x1e1e, 0x1e20, 0x1e22, 0x1e24, 0x1e26, 0x1e28, 0x1e2a, 0x1e2c, 0x1e2e, 0x1e30, 0x1e32, 0x1e34, 0x1e36, 0x1e38, 0x1e3a, 0x1e3c, 0x1e3e, 0x1e40, 0x1e42, 0x1e44, 0x1e46, 0x1e48, 0x1e4a, 0x1e4c, 0x1e4e, 0x1e50, 0x1e52, 0x1e54, 0x1e56, 0x1e58, 0x1e5a, 0x1e5c, 0x1e5e, 0x1e60, 0x1e62, 0x1e64, 0x1e66, 0x1e68, 0x1e6a, 0x1e6c, 0x1e6e, 0x1e70, 0x1e72, 0x1e74, 0x1e76, 0x1e78, 0x1e7a, 0x1e7c, 0x1e7e, 0x1e80, 0x1e82, 0x1e84, 0x1e86, 0x1e88, 0x1e8a, 0x1e8c, 0x1e8e, 0x1e90, 0x1e92, 0x1e94, 0x1e60, 0x1ea0, 0x1ea2, 0x1ea4, 0x1ea6, 0x1ea8, 0x1eaa, 0x1eac, 0x1eae, 0x1eb0, 0x1eb2, 0x1eb4, 0x1eb6, 0x1eb8, 0x1eba, 0x1ebc, 0x1ebe, 0x1ec0, 0x1ec2, 0x1ec4, 0x1ec6, 0x1ec8, 0x1eca, 0x1ecc, 0x1ece, 0x1ed0, 0x1ed2, 0x1ed4, 0x1ed6, 0x1ed8, 0x1eda, 0x1edc, 0x1ede, 0x1ee0, 0x1ee2, 0x1ee4, 0x1ee6, 0x1ee8, 0x1eea, 0x1eec, 0x1eee, 0x1ef0, 0x1ef2, 0x1ef4, 0x1ef6, 0x1ef8, 0x1efa, 0x1efc, 0x1efe, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0x1f59, 0x1f5b, 0x1f5d, 0x1f5f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, 0x1ffa, 0x1ffb, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fb8, 0x1fb9, 0x1fbc, 0x399, 0x1fcc, 0x1fd8, 0x1fd9, 0x1fe8, 0x1fe9, 0x1fec, 0x1ffc, 0x2132, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, 0x216c, 0x216d, 0x216e, 0x216f, 0x2183, 0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, 0x24bb, 0x24bc, 0x24bd, 0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, 0x24c3, 0x24c4, 0x24c5, 0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, 0x24cb, 0x24cc, 0x24cd, 0x24ce, 0x24cf, 0x2c00, 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x2c08, 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x2c10, 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, 0x2c18, 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, 0x2c20, 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, 0x2c28, 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x2c60, 0x23a, 0x23e, 0x2c67, 0x2c69, 0x2c6b, 0x2c72, 0x2c75, 0x2c80, 0x2c82, 0x2c84, 0x2c86, 0x2c88, 0x2c8a, 0x2c8c, 0x2c8e, 0x2c90, 0x2c92, 0x2c94, 0x2c96, 0x2c98, 0x2c9a, 0x2c9c, 0x2c9e, 0x2ca0, 0x2ca2, 0x2ca4, 0x2ca6, 0x2ca8, 0x2caa, 0x2cac, 0x2cae, 0x2cb0, 0x2cb2, 0x2cb4, 0x2cb6, 0x2cb8, 0x2cba, 0x2cbc, 0x2cbe, 0x2cc0, 0x2cc2, 0x2cc4, 0x2cc6, 0x2cc8, 0x2cca, 0x2ccc, 0x2cce, 0x2cd0, 0x2cd2, 0x2cd4, 0x2cd6, 0x2cd8, 0x2cda, 0x2cdc, 0x2cde, 0x2ce0, 0x2ce2, 0x2ceb, 0x2ced, 0x2cf2, 0x10a0, 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0, 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8, 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0, 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0x10c7, 0x10cd, 0xa640, 0xa642, 0xa644, 0xa646, 0xa648, 0xa64a, 0xa64c, 0xa64e, 0xa650, 0xa652, 0xa654, 0xa656, 0xa658, 0xa65a, 0xa65c, 0xa65e, 0xa660, 0xa662, 0xa664, 0xa666, 0xa668, 0xa66a, 0xa66c, 0xa680, 0xa682, 0xa684, 0xa686, 0xa688, 0xa68a, 0xa68c, 0xa68e, 0xa690, 0xa692, 0xa694, 0xa696, 0xa722, 0xa724, 0xa726, 0xa728, 0xa72a, 0xa72c, 0xa72e, 0xa732, 0xa734, 0xa736, 0xa738, 0xa73a, 0xa73c, 0xa73e, 0xa740, 0xa742, 0xa744, 0xa746, 0xa748, 0xa74a, 0xa74c, 0xa74e, 0xa750, 0xa752, 0xa754, 0xa756, 0xa758, 0xa75a, 0xa75c, 0xa75e, 0xa760, 0xa762, 0xa764, 0xa766, 0xa768, 0xa76a, 0xa76c, 0xa76e, 0xa779, 0xa77b, 0xa77e, 0xa780, 0xa782, 0xa784, 0xa786, 0xa78b, 0xa790, 0xa792, 0xa7a0, 0xa7a2, 0xa7a4, 0xa7a6, 0xa7a8, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, 0xff3a, 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407, 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f, 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417, 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f, 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427, 0x2000053, 0x73, 0x130, 0x2000046, 0x66, 0x2000046, 0x69, 0x2000046, 0x6c, 0x3000046, 0x66, 0x69, 0x3000046, 0x66, 0x6c, 0x2000053, 0x74, 0x2000053, 0x74, 0x2000535, 0x582, 0x2000544, 0x576, 0x2000544, 0x565, 0x2000544, 0x56b, 0x200054e, 0x576, 0x2000544, 0x56d, 0x20002bc, 0x4e, 0x3000399, 0x308, 0x301, 0x30003a5, 0x308, 0x301, 0x200004a, 0x30c, 0x2000048, 0x331, 0x2000054, 0x308, 0x2000057, 0x30a, 0x2000059, 0x30a, 0x2000041, 0x2be, 0x20003a5, 0x313, 0x30003a5, 0x313, 0x300, 0x30003a5, 0x313, 0x301, 0x30003a5, 0x313, 0x342, 0x2000391, 0x342, 0x2000397, 0x342, 0x3000399, 0x308, 0x300, 0x3000399, 0x308, 0x301, 0x2000399, 0x342, 0x3000399, 0x308, 0x342, 0x30003a5, 0x308, 0x300, 0x30003a5, 0x308, 0x301, 0x20003a1, 0x313, 0x20003a5, 0x342, 0x30003a5, 0x308, 0x342, 0x20003a9, 0x342, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fbc, 0x1fbc, 0x1fcc, 0x1fcc, 0x1ffc, 0x1ffc, 0x2001fba, 0x345, 0x2000386, 0x345, 0x2001fca, 0x345, 0x2000389, 0x345, 0x2001ffa, 0x345, 0x200038f, 0x345, 0x3000391, 0x342, 0x345, 0x3000397, 0x342, 0x345, 0x30003a9, 0x342, 0x345]; return t; } } } static if(size_t.sizeof == 4) { //1536 bytes enum lowerCaseTrieEntries = TrieEntry!(bool, 8, 4, 9)([ 0x0, 0x40, 0x80], [ 0x100, 0x80, 0x2000], [ 0x2020100, 0x4020302, 0x2020205, 0x2060202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x50004, 0x30006, 0x30007, 0x30003, 0x30008, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x90003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0xa0003, 0xb0003, 0x30003, 0x3000c, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0xe000d, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x0, 0x0, 0x0, 0x7fffffe, 0x0, 0x4200400, 0x80000000, 0xff7fffff, 0xaaaaaaaa, 0x55aaaaaa, 0xaaaaab55, 0xd4aaaaaa, 0x4e243129, 0xe6512d2a, 0xb5555240, 0xaa29aaaa, 0xaaaaaaaa, 0x93faaaaa, 0xffffaa85, 0xffffffff, 0xffefffff, 0x1ffffff, 0x3, 0x1f, 0x0, 0x0, 0x20, 0x3c8a0000, 0x10000, 0xfffff000, 0xaae37fff, 0x192faaaa, 0x0, 0xffff0000, 0xffffffff, 0xaaaaaaaa, 0xaaaaa802, 0xaaaaaaaa, 0xaaaad554, 0xaaaaaaaa, 0xaaaaaaaa, 0xaa, 0x0, 0xfffffffe, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x0, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xbfeaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0x3f00ff, 0xff00ff, 0xff003f, 0x3fff00ff, 0xff00ff, 0x40df00ff, 0xcf00dc, 0xdc00ff, 0x0, 0x0, 0x0, 0x80020000, 0x1fff0000, 0x0, 0x0, 0x0, 0x8c400, 0x32108000, 0x43c0, 0xffff0000, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff0000, 0x3ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff0000, 0x7fffffff, 0x3fda1562, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0x8501a, 0xffffffff, 0x20bf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaaaaaaaa, 0x2aaa, 0xaaaaaa, 0x0, 0x0, 0x0, 0x0, 0xaaabaaa8, 0xaaaaaaaa, 0x95ffaaaa, 0xa50aa, 0x2aa, 0x0, 0x7000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf8007f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7fffffe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffff00, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc000000, 0xfffff, 0xffdfc000, 0xff, 0xffffffc, 0xebc00000, 0xffef, 0xfffffc00, 0xc000000f, 0xffffff, 0xfffc0000, 0xfff, 0xffffffc0, 0xfc000000, 0xfffff, 0xffffc000, 0xff, 0xffffffc, 0xffc00000, 0xffff, 0xfffffc00, 0x3f, 0xf7fffffc, 0xf0000003, 0xfdfffff, 0xffc00000, 0x3f7fff, 0xffff0000, 0xfdff, 0xfffffc00, 0xbf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //1472 bytes enum upperCaseTrieEntries = TrieEntry!(bool, 8, 4, 9)([ 0x0, 0x40, 0x80], [ 0x100, 0x80, 0x1e00], [ 0x2020100, 0x4020302, 0x2020205, 0x2060202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x30003, 0x30003, 0x30004, 0x30003, 0x30003, 0x50003, 0x30006, 0x30007, 0x30003, 0x30008, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x90003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0xa0003, 0x30003, 0x3000b, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0xd000c, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x30003, 0x0, 0x0, 0x7fffffe, 0x0, 0x0, 0x0, 0x7f7fffff, 0x0, 0x55555555, 0xaa555555, 0x555554aa, 0x2b555555, 0xb1dbced6, 0x11aed2d5, 0x4aaaa490, 0x55d25555, 0x55555555, 0x6c055555, 0x557a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x450000, 0xfffed740, 0xffb, 0x551c8000, 0xe6905555, 0xffffffff, 0xffff, 0x0, 0x55555555, 0x55555401, 0x55555555, 0x55552aab, 0x55555555, 0x55555555, 0xfffe0055, 0x7fffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x20bf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x40155555, 0x55555555, 0x55555555, 0x55555555, 0x3f00ff00, 0xff00ff00, 0xaa003f00, 0xff00, 0x0, 0xf000000, 0xf000f00, 0xf001f00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e273884, 0xc00f3d50, 0x20, 0xffff, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc00000, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x7fff, 0x0, 0xc025ea9d, 0x55555555, 0x55555555, 0x55555555, 0x42805, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55555555, 0x1555, 0x555555, 0x0, 0x0, 0x0, 0x0, 0x55545554, 0x55555555, 0x6a005555, 0x52855, 0x555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7fffffe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ffffff, 0xfff00000, 0x3fff, 0xffffff00, 0xd0000003, 0x3fde64, 0xffff0000, 0x3ff, 0x1fdfe7b0, 0x7b000000, 0x1fc5f, 0xfffff000, 0x3f, 0x3ffffff, 0xfff00000, 0x3fff, 0xffffff00, 0xf0000003, 0x3fffff, 0xffff0000, 0x3ff, 0xffffff00, 0x1, 0x7fffffc, 0xf0000000, 0x1fffff, 0xffc00000, 0x7fff, 0xffff0000, 0x1ff, 0x400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //8704 bytes enum simpleCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x40, 0x200], [ 0x100, 0x380, 0xd00], [ 0x2020100, 0x4020302, 0x2020205, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xa, 0xb0000, 0xd000c, 0xf000e, 0x110010, 0x130012, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x160015, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x170000, 0x0, 0x190018, 0x1b001a, 0x1d001c, 0x1f001e, 0x0, 0x0, 0x210020, 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x240023, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x260025, 0x280027, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a0000, 0x2b, 0x2d002c, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30002f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x320031, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x20ffff, 0x240022, 0x280026, 0x2c002a, 0x30002e, 0x72f0032, 0x390037, 0x3d003b, 0x41003f, 0x1b00043, 0x4a0048, 0x4e004c, 0x520050, 0xffff0054, 0xffffffff, 0xffffffff, 0x21ffff, 0x250023, 0x290027, 0x2d002b, 0x31002f, 0x7300033, 0x3a0038, 0x3e003c, 0x420040, 0x1b10044, 0x4b0049, 0x4f004d, 0x530051, 0xffff0055, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x43fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc800c6, 0xcc0498, 0x14904aa, 0xd500d3, 0xd900d7, 0xdd00db, 0xe100df, 0xe500e3, 0xe900e7, 0xed00eb, 0xf100ef, 0xffff00f3, 0xf700f5, 0xfb00f9, 0xff00fd, 0x6be0101, 0xc900c7, 0xcd0499, 0x14a04ab, 0xd600d4, 0xda00d8, 0xde00dc, 0xe200e0, 0xe600e4, 0xea00e8, 0xee00ec, 0xf200f0, 0xffff00f4, 0xf800f6, 0xfc00fa, 0x10000fe, 0x1a80102, 0x1160115, 0x1180117, 0x11c011b, 0x11e011d, 0x120011f, 0x1240123, 0x1260125, 0x1280127, 0x12c012b, 0x12e012d, 0x130012f, 0x1340133, 0x1360135, 0x1380137, 0x13a0139, 0x13c013b, 0x13e013d, 0x140013f, 0x1420141, 0x1440143, 0x1460145, 0x1480147, 0x14d014c, 0x14f014e, 0xffffffff, 0x1510150, 0x1530152, 0x1550154, 0x156ffff, 0x1580157, 0x15c0159, 0x15e015d, 0x160015f, 0x1620161, 0x1640163, 0x1660165, 0xffff0167, 0x1690168, 0x16b016a, 0x16d016c, 0x16f016e, 0x1710170, 0x1730172, 0x1750174, 0x1770176, 0x1790178, 0x17b017a, 0x17d017c, 0x17f017e, 0x1830182, 0x1870186, 0x18b018a, 0x18f018e, 0x1930192, 0x1970196, 0x19b019a, 0x19f019e, 0x1a301a2, 0x1a501a4, 0x1a701a6, 0x1aa01a9, 0x1ac01ab, 0x1ae01ad, 0x1b201af, 0x1b3028b, 0x1b601b5, 0x1ba01b9, 0x1bd01bb, 0x1bf01be, 0x1c301c1, 0xffff01c4, 0x1c701c5, 0x1cb01c9, 0x1cd01cc, 0x23b01cf, 0x1d301d1, 0x1d601d5, 0xffff0283, 0x1d901d7, 0x1db0269, 0x1de01dd, 0x1e001df, 0x1e201e1, 0x1e501e3, 0x1e701e6, 0xffffffff, 0x1ea01e9, 0x1ed01eb, 0x1ef01ee, 0x1f301f1, 0x1f501f4, 0x1f701f6, 0x1fa01f9, 0xffffffff, 0x1fc01fb, 0x23dffff, 0xffffffff, 0xffffffff, 0x2010200, 0x2060202, 0x2080207, 0x20d020c, 0x20f020e, 0x2110210, 0x2130212, 0x2150214, 0x2170216, 0x2190218, 0x21b021a, 0x21d021c, 0x1c6021e, 0x220021f, 0x2240223, 0x2260225, 0x2280227, 0x22a0229, 0x22c022b, 0x22e022d, 0x230022f, 0x2320231, 0x236ffff, 0x2380237, 0x23a0239, 0x23e023c, 0x240023f, 0x2440243, 0x2460245, 0x2480247, 0x24a0249, 0x24c024b, 0x24e024d, 0x250024f, 0x2520251, 0x2540253, 0x2560255, 0x2580257, 0x25a0259, 0x25c025b, 0x25e025d, 0x260025f, 0x2620261, 0x2640263, 0x2660265, 0x2680267, 0xffff026a, 0x26c026b, 0x26e026d, 0x270026f, 0x2720271, 0x2740273, 0x2760275, 0x2780277, 0x27a0279, 0x27c027b, 0xffffffff, 0xffffffff, 0xffffffff, 0x281027f, 0x2840282, 0x2d70285, 0x2870482, 0x28c0288, 0x28f028d, 0x2920291, 0x2940293, 0x2960295, 0x2980297, 0x29c029b, 0x466046a, 0x1b402b7, 0xffff01bc, 0x1c201c0, 0x1c8ffff, 0x1caffff, 0xffffffff, 0xffffffff, 0xffff01ce, 0x1d0ffff, 0x748ffff, 0xffff05fa, 0x1d201d4, 0x528ffff, 0xffffffff, 0x1d8ffff, 0x2b3ffff, 0xffff01da, 0x1dcffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2a3ffff, 0xffffffff, 0xffff01e4, 0x1e8ffff, 0xffffffff, 0xffffffff, 0x28e01ec, 0x1f201f0, 0xffff0290, 0xffffffff, 0xffffffff, 0xffff01f8, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x83affff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x31e031d, 0x320031f, 0xffffffff, 0x3240323, 0xffffffff, 0x3d5ffff, 0x3d903d7, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0329, 0x32f032d, 0xffff0331, 0xffff0333, 0x3370335, 0x339ffff, 0x33e0395, 0x3cc0340, 0x3470345, 0x83b03c8, 0x35403c2, 0x3590440, 0x35d035b, 0x3c5039f, 0x388ffff, 0x36a0368, 0x36f039c, 0x7100371, 0x3780376, 0x32e032a, 0x3320330, 0x33affff, 0x33f0396, 0x3cd0341, 0x3480346, 0x83c03c9, 0x35503c3, 0x35a0441, 0x35e035c, 0x3c603a0, 0x38a0389, 0x36b0369, 0x370039d, 0x7110372, 0x3790377, 0x3360334, 0x3930338, 0x3ca0397, 0xffffffff, 0x39effff, 0x39403a1, 0x3a303a2, 0x3a703a6, 0x3a903a8, 0x3ab03aa, 0x3ad03ac, 0x3af03ae, 0x3b103b0, 0x3b503b4, 0x3b903b8, 0x3bd03bc, 0x3bf03be, 0x3c103c0, 0x3c703c4, 0xffff03d1, 0x3ce03cb, 0x3cfffff, 0x3d203d0, 0x3d403d3, 0x3d6ffff, 0x3da03d8, 0x3dd03db, 0x3e103df, 0x3e503e3, 0x3e903e7, 0x3ed03eb, 0x3f103ef, 0x3f503f3, 0x3f903f7, 0x3fd03fb, 0x40103ff, 0x4050403, 0x4090407, 0x40d040b, 0x411040f, 0x4150413, 0x4190417, 0x41d041b, 0x421041f, 0x4250423, 0x4290427, 0x42d042b, 0x431042f, 0x4350433, 0x4390437, 0x3fe03fc, 0x4020400, 0x4060404, 0x40a0408, 0x40e040c, 0x4120410, 0x4160414, 0x41a0418, 0x41e041c, 0x4220420, 0x4260424, 0x42a0428, 0x42e042c, 0x4320430, 0x4360434, 0x43a0438, 0x3de03dc, 0x3e203e0, 0x3e603e4, 0x3ea03e8, 0x3ee03ec, 0x3f203f0, 0x3f603f4, 0x3fa03f8, 0x4510450, 0x4530452, 0x4570456, 0x4590458, 0x45d045c, 0x4610460, 0x4650464, 0x4690468, 0x46d046c, 0x4710470, 0x4730472, 0x4770476, 0x4790478, 0x47b047a, 0x47d047c, 0x4810480, 0x4850484, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x4950494, 0x4970496, 0x49b049a, 0x49d049c, 0x49f049e, 0x4a304a2, 0x4a704a6, 0x4a904a8, 0x4ad04ac, 0x4b104b0, 0x4b304b2, 0x4b704b6, 0x4b904b8, 0x4bb04ba, 0x4bf04be, 0x4c104c0, 0x4c504c4, 0x4c904c8, 0x4cd04cc, 0x4cf04ce, 0x4d304d2, 0x4d504d4, 0x4d704d6, 0x4db04da, 0x4df04de, 0x4e304e2, 0x4e704e6, 0x4ec04ea, 0x4f004ed, 0x4f404f1, 0x4f804f5, 0x4fc04f9, 0x50004fd, 0x5040501, 0x4eb0505, 0x50b050a, 0x50d050c, 0x50f050e, 0x5130512, 0x5170516, 0x5190518, 0x51d051c, 0x51f051e, 0x5210520, 0x5250524, 0x5270526, 0x52b052a, 0x52d052c, 0x52f052e, 0x5330532, 0x5370536, 0x5390538, 0x53d053c, 0x53f053e, 0x5410540, 0x5430542, 0x5470546, 0x5490548, 0x54b054a, 0x54d054c, 0x54f054e, 0x5510550, 0x5550554, 0x5570556, 0x5590558, 0x55b055a, 0x55d055c, 0x55f055e, 0x5630562, 0x5650564, 0x5670566, 0x5690568, 0x56b056a, 0x56f056e, 0x5730572, 0x5750574, 0x5770576, 0x5790578, 0x57b057a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x580ffff, 0x5840582, 0x5880586, 0x58c058a, 0x590058e, 0x5940592, 0x5980596, 0x59c059a, 0x5a0059e, 0x5a405a2, 0x5a805a6, 0x5ac05aa, 0x5b005ae, 0x5b405b2, 0x5b805b6, 0x5bc05ba, 0x5c005be, 0x5c405c2, 0x5c805c6, 0xffff05ca, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x581ffff, 0x5850583, 0x5890587, 0x58d058b, 0x591058f, 0x5950593, 0x5990597, 0x59d059b, 0x5a1059f, 0x5a505a3, 0x5a905a7, 0x5ad05ab, 0x5b105af, 0x5b505b3, 0x5b905b7, 0x5bd05bb, 0x5c105bf, 0x5c505c3, 0x5c905c7, 0xffff05cb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x880086, 0x8c008a, 0x90008e, 0x940092, 0x980096, 0x9c009a, 0xa0009e, 0xa400a2, 0xa800a6, 0xac00aa, 0xb000ae, 0xb400b2, 0xb800b6, 0xbc00ba, 0xc000be, 0xc400c2, 0x48e0486, 0x4a000ca, 0x4b400ce, 0x4c6ffff, 0xffffffff, 0xffffffff, 0x508ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7e8ffff, 0xffffffff, 0x454ffff, 0xffffffff, 0x5fd05fc, 0x5ff05fe, 0x6010600, 0x6050604, 0x6090608, 0x60b060a, 0x60f060e, 0x6110610, 0x6130612, 0x6170616, 0x6190618, 0x61d061c, 0x61f061e, 0x6210620, 0x6230622, 0x6270626, 0x6290628, 0x62b062a, 0x62d062c, 0x62f062e, 0x6310630, 0x6350634, 0x6370636, 0x6390638, 0x63b063a, 0x63d063c, 0x63f063e, 0x6430642, 0x6450644, 0x6470646, 0x6490648, 0x64b064a, 0x64d064c, 0x6510650, 0x6530652, 0x6550654, 0x6590658, 0x65d065c, 0x65f065e, 0x6630662, 0x6650664, 0x6670666, 0x6690668, 0x66b066a, 0x66d066c, 0x6710670, 0x6730672, 0x6750674, 0x6bc06bb, 0x67a0679, 0x67c067b, 0x680067f, 0x6820681, 0x6840683, 0x6860685, 0x6880687, 0x68a0689, 0x68e068d, 0x690068f, 0x6920691, 0x6960695, 0x6980697, 0x69a0699, 0x69e069d, 0x6a0069f, 0x6a206a1, 0x6a406a3, 0x6a606a5, 0x6a806a7, 0x6ac06ab, 0x6ae06ad, 0x6b006af, 0x6b206b1, 0x6b406b3, 0x6b606b5, 0xffffffff, 0xffffffff, 0x6bdffff, 0xffffffff, 0xffff06bf, 0x6c106c0, 0x6c306c2, 0x6c506c4, 0x6c906c8, 0x6cb06ca, 0x6cd06cc, 0x6cf06ce, 0x6d106d0, 0x6d506d4, 0x6d706d6, 0x6db06da, 0x6dd06dc, 0x6df06de, 0x6e106e0, 0x6e306e2, 0x6e506e4, 0x6e906e8, 0x6eb06ea, 0x6ef06ee, 0x6f106f0, 0x6f306f2, 0x6f506f4, 0x6f706f6, 0x6f906f8, 0x6fb06fa, 0x6fd06fc, 0x6ff06fe, 0x7010700, 0x7030702, 0x7050704, 0x7070706, 0x7090708, 0x70b070a, 0x70d070c, 0x70f070e, 0x7140713, 0x7160715, 0x7180717, 0x71c071b, 0x71e071d, 0x720071f, 0x7220721, 0x7240723, 0x7260725, 0x7280727, 0x72a0729, 0x72e072d, 0x7330732, 0x7380736, 0x73c073a, 0x740073e, 0x7440742, 0x7390737, 0x73d073b, 0x741073f, 0x7450743, 0x74c074a, 0x750074e, 0x7540752, 0xffffffff, 0x74d074b, 0x751074f, 0x7550753, 0xffffffff, 0x7660764, 0x76a0768, 0x76e076c, 0x7720770, 0x7670765, 0x76b0769, 0x76f076d, 0x7730771, 0x7860784, 0x78a0788, 0x78e078c, 0x7920790, 0x7870785, 0x78b0789, 0x78f078d, 0x7930791, 0x79e079c, 0x7a207a0, 0x7a607a4, 0xffffffff, 0x79f079d, 0x7a307a1, 0x7a707a5, 0xffffffff, 0x7b6ffff, 0x7baffff, 0x7beffff, 0x7c2ffff, 0x7b7ffff, 0x7bbffff, 0x7bfffff, 0x7c3ffff, 0x7d207d0, 0x7d607d4, 0x7da07d8, 0x7de07dc, 0x7d307d1, 0x7d707d5, 0x7db07d9, 0x7df07dd, 0x8360834, 0x840083e, 0x8440842, 0x84e084c, 0x8620860, 0x8580856, 0x8660864, 0xffffffff, 0x7f607f4, 0x7fa07f8, 0x7fe07fc, 0x8020800, 0x7f707f5, 0x7fb07f9, 0x7ff07fd, 0x8030801, 0x80a0808, 0x80e080c, 0x8120810, 0x8160814, 0x80b0809, 0x80f080d, 0x8130811, 0x8170815, 0x8220820, 0x8260824, 0x82a0828, 0x82e082c, 0x8230821, 0x8270825, 0x82b0829, 0x82f082d, 0x8320830, 0x838ffff, 0xffffffff, 0xffffffff, 0x8330831, 0x8370835, 0xffff0839, 0xffff083d, 0xffffffff, 0x846ffff, 0xffffffff, 0xffffffff, 0x841083f, 0x8450843, 0xffff0847, 0xffffffff, 0x84a0848, 0xffffffff, 0xffffffff, 0xffffffff, 0x84b0849, 0x84f084d, 0xffffffff, 0xffffffff, 0x8540852, 0xffffffff, 0x85affff, 0xffffffff, 0x8550853, 0x8590857, 0xffff085b, 0xffffffff, 0xffffffff, 0x868ffff, 0xffffffff, 0xffffffff, 0x8630861, 0x8670865, 0xffff0869, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0712, 0xffffffff, 0x14b0731, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0530, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0531, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x180029f, 0x18402af, 0x18802c1, 0x18c005e, 0x1900064, 0x194006c, 0x1980076, 0x19c007e, 0x18102a0, 0x18502b0, 0x18902c2, 0x18d005f, 0x1910065, 0x195006d, 0x1990077, 0x19d007f, 0xffffffff, 0x1b7ffff, 0xffff01b8, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x4d80444, 0x4dc0446, 0x4e0044c, 0x4e4045e, 0x4e80474, 0x2d3086a, 0x204ee, 0x6c604f2, 0x6e04f6, 0x37a04fa, 0x10d04fe, 0x61a0502, 0x51a0506, 0x4d90445, 0x4dd0447, 0x4e1044d, 0x4e5045f, 0x4e90475, 0x2d4086b, 0x304ef, 0x6c704f3, 0x6f04f7, 0x37b04fb, 0x10e04ff, 0x61b0503, 0x51b0507, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40000, 0xa0008, 0xe000c, 0x160010, 0x1a0018, 0x2bb001c, 0x2d102c7, 0x5602e7, 0x600058, 0x660062, 0x70006a, 0x780074, 0x80007c, 0x2990082, 0x607e0, 0x6020084, 0x2a7057c, 0x5d005ce, 0x10305de, 0x1070105, 0x10f0109, 0x1190113, 0x1290121, 0xffff0131, 0x50001, 0xb0009, 0xf000d, 0x170011, 0x1b0019, 0x2bc001d, 0x2d202c8, 0x5702e8, 0x610059, 0x670063, 0x71006b, 0x790075, 0x81007d, 0x29a0083, 0x707e1, 0x6030085, 0x2a8057d, 0x5d105cf, 0x10405df, 0x1080106, 0x110010a, 0x11a0114, 0x12a0122, 0xffff0132, 0x4c304c2, 0x4550529, 0x28002a4, 0x45a0286, 0x2a9045b, 0x46202aa, 0x4670463, 0x46b02b4, 0xffff02b8, 0x2ba02b9, 0x2bfffff, 0xffff02c0, 0xffffffff, 0xffffffff, 0xffffffff, 0x48302d8, 0x2e202e1, 0x4890488, 0x48b048a, 0x48d048c, 0x4910490, 0x2fe02fd, 0x3040303, 0x30e030d, 0x3160315, 0x31a0319, 0x3260325, 0x3280327, 0x2fc02fb, 0x6ed06ec, 0x3810380, 0x3830382, 0x3870386, 0x3920391, 0x3a503a4, 0x3b303b2, 0x56d056c, 0x5cd05cc, 0x5db05da, 0x5ed05ec, 0x60d060c, 0x6570656, 0x43e043d, 0x6e706e6, 0x72c072b, 0x7830782, 0x7e307e2, 0x6940693, 0x65b065a, 0x150014, 0x5d005c, 0x4bd04bc, 0x4d104d0, 0x5d505d4, 0x1a101a0, 0x5110510, 0x5230522, 0x5350534, 0x5450544, 0x5530552, 0x5610560, 0x5710570, 0x57f057e, 0x15b015a, 0x37d037c, 0x3bb03ba, 0xffffffff, 0xffffffff, 0xffffffff, 0x5d2ffff, 0x5d805d3, 0xffff05d9, 0xffffffff, 0x5e305e2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x890087, 0x8d008b, 0x91008f, 0x950093, 0x990097, 0x9d009b, 0xa1009f, 0xa500a3, 0xa900a7, 0xad00ab, 0xb100af, 0xb500b3, 0xb900b7, 0xbd00bb, 0xc100bf, 0xc500c3, 0x48f0487, 0x4a100cb, 0x4b500cf, 0x4c7ffff, 0xffffffff, 0xffffffff, 0x509ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c402c3, 0x5d705d6, 0x5dd05dc, 0x5e105e0, 0x5e705e6, 0x5e905e8, 0x5eb05ea, 0x5ef05ee, 0x5f105f0, 0x5f505f4, 0x5f905f8, 0x3080307, 0x6150614, 0x6250624, 0x6330632, 0x6410640, 0x64f064e, 0x6610660, 0x66f066e, 0x67e067d, 0x68c068b, 0x69c069b, 0x6aa06a9, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7350734, 0x690068, 0x27e027d, 0x75f075e, 0x7770776, 0x390038f, 0x1f001e, 0x7b107b0, 0x7c707c6, 0x2a202a1, 0x7e507e4, 0x6b806b7, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7590758, 0x75d075c, 0x7610760, 0x2d602d5, 0x2e002df, 0x2e602e5, 0x2ee02ed, 0xffffffff, 0x7790778, 0x77d077c, 0x7810780, 0x30c030b, 0x3140313, 0x3180317, 0x3220321, 0x7950794, 0x7970796, 0x7990798, 0x79b079a, 0x37f037e, 0x3850384, 0x38e038d, 0x7a907a8, 0x7ab07aa, 0x7ad07ac, 0x7af07ae, 0x7b307b2, 0x7b507b4, 0x7b907b8, 0x7bd07bc, 0x7c107c0, 0x7c507c4, 0x7c907c8, 0x7cd07cc, 0x7cf07ce, 0x46f046e, 0x47f047e, 0x4930492, 0x4a504a4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x514ffff, 0x7e60515, 0x7e907e7, 0x7eb07ea, 0x7ed07ec, 0x7ef07ee, 0x7f107f0, 0x7f307f2, 0xffffffff, 0x5f2ffff, 0x74905f3, 0xffffffff, 0x8050804, 0x8070806, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x8190818, 0x81b081a, 0x81d081c, 0x81f081e, 0x5f705f6, 0xffff05fb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x756ffff, 0x75a02c5, 0x2cd02cb, 0x76202cf, 0x2db06d2, 0x2e30719, 0x2e90448, 0x2f107ca, 0x2f30774, 0x77a02f5, 0x77e02f9, 0x3050221, 0x30f007a, 0xffff043b, 0xffffffff, 0xffffffff, 0x757ffff, 0x75b02c6, 0x2ce02cc, 0x76302d0, 0x2dc06d3, 0x2e4071a, 0x2ea0449, 0x2f207cb, 0x2f40775, 0x77b02f6, 0x77f02fa, 0x3060222, 0x310007b, 0xffff043c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x85c0012, 0x72005a, 0x32b0311, 0x11106b9, 0x2ab05e4, 0x2dd029d, 0x2ef085e, 0x10b0606, 0x2d902a5, 0x4ca0289, 0x2b502ad, 0x2c902bd, 0x2eb0746, 0x30902f7, 0x241031b, 0x38b02b1, 0x44a03b6, 0x442053a, 0x6d8044e, 0x85004ae, 0x85d0013, 0x73005b, 0x32c0312, 0x11206ba, 0x2ac05e5, 0x2de029e, 0x2f0085f, 0x10c0607, 0x2da02a6, 0x4cb028a, 0x2b602ae, 0x2ca02be, 0x2ec0747, 0x30a02f8, 0x242031c, 0x38c02b2, 0x44b03b7, 0x443053b, 0x6d9044f, 0x85104af, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); //8832 bytes enum fullCaseTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x40, 0x200], [ 0x100, 0x380, 0xd40], [ 0x2020100, 0x4020302, 0x2020205, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xa, 0xb0000, 0xd000c, 0xf000e, 0x110010, 0x130012, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x160015, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x170000, 0x0, 0x190018, 0x1b001a, 0x1d001c, 0x1f001e, 0x0, 0x0, 0x210020, 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x240023, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x260025, 0x280027, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a0000, 0x2b, 0x2d002c, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x310030, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x330032, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x20ffff, 0x240022, 0x280026, 0x2c002a, 0x30002e, 0x7810032, 0x390037, 0x3d003b, 0x41003f, 0x1b90043, 0x4a0048, 0x4e004c, 0x520050, 0xffff0054, 0xffffffff, 0xffffffff, 0x21ffff, 0x250023, 0x290027, 0x2d002b, 0x31002f, 0x7820033, 0x3a0038, 0x3e003c, 0x420040, 0x1ba0044, 0x4b0049, 0x4f004d, 0x530051, 0xffff0055, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x470ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc800c6, 0xcc04c9, 0x14e04db, 0xd500d3, 0xd900d7, 0xdd00db, 0xe100df, 0xe500e3, 0xe900e7, 0xed00eb, 0xf100ef, 0xffff00f3, 0xf700f5, 0xfb00f9, 0xff00fd, 0x70f0101, 0xc900c7, 0xcd04ca, 0x14f04dc, 0xd600d4, 0xda00d8, 0xde00dc, 0xe200e0, 0xe600e4, 0xea00e8, 0xee00ec, 0xf200f0, 0xffff00f4, 0xf800f6, 0xfc00fa, 0x10000fe, 0x1b10102, 0x1190118, 0x11b011a, 0x11f011e, 0x1210120, 0x1230122, 0x1270126, 0x1290128, 0x12b012a, 0x12f012e, 0x1310130, 0x1330132, 0x1370136, 0x1390138, 0x13b013a, 0x13d013c, 0x13f013e, 0x1410140, 0x1430142, 0x1470146, 0x1490148, 0x14b014a, 0x14d014c, 0x1520151, 0x1540153, 0xffff0155, 0x1580157, 0x15a0159, 0x15c015b, 0x15dffff, 0x15f015e, 0x1630160, 0x1650164, 0x1670166, 0x1690168, 0x16b016a, 0x16d016c, 0x16f016e, 0x1720171, 0x1740173, 0x1760175, 0x1780177, 0x17a0179, 0x17c017b, 0x17e017d, 0x180017f, 0x1820181, 0x1840183, 0x1860185, 0x1880187, 0x18c018b, 0x190018f, 0x1940193, 0x1980197, 0x19c019b, 0x1a0019f, 0x1a401a3, 0x1a801a7, 0x1ac01ab, 0x1ae01ad, 0x1b001af, 0x1b301b2, 0x1b501b4, 0x1b701b6, 0x1bb01b8, 0x1bc029c, 0x1bf01be, 0x1c301c2, 0x1c601c4, 0x1c801c7, 0x1cc01ca, 0xffff01cd, 0x1d001ce, 0x1d401d2, 0x1d601d5, 0x24801d8, 0x1dc01da, 0x1df01de, 0xffff0294, 0x1e201e0, 0x1e60278, 0x1e901e8, 0x1eb01ea, 0x1ed01ec, 0x1f001ee, 0x1f201f1, 0xffffffff, 0x1f501f4, 0x1f801f6, 0x1fa01f9, 0x1fe01fc, 0x20001ff, 0x2020201, 0x2050204, 0xffffffff, 0x2070206, 0x24affff, 0xffffffff, 0xffffffff, 0x20c020b, 0x211020d, 0x2130212, 0x2180217, 0x21a0219, 0x21c021b, 0x21e021d, 0x220021f, 0x2220221, 0x2240223, 0x2260225, 0x2280227, 0x1cf0229, 0x22b022a, 0x22f022e, 0x2310230, 0x2330232, 0x2350234, 0x2370236, 0x2390238, 0x23b023a, 0x23d023c, 0x243023e, 0x2450244, 0x2470246, 0x24b0249, 0x24d024c, 0x2510250, 0x2530252, 0x2550254, 0x2570256, 0x2590258, 0x25b025a, 0x25d025c, 0x2610260, 0x2630262, 0x2650264, 0x2670266, 0x2690268, 0x26b026a, 0x26d026c, 0x26f026e, 0x2710270, 0x2730272, 0x2750274, 0x2770276, 0xffff0279, 0x27b027a, 0x27d027c, 0x27f027e, 0x2810280, 0x2850284, 0x2870286, 0x2890288, 0x28b028a, 0x28d028c, 0xffffffff, 0xffffffff, 0xffffffff, 0x2920290, 0x2950293, 0x2ec0296, 0x29804b3, 0x29d0299, 0x2a0029e, 0x2a302a2, 0x2a502a4, 0x2a702a6, 0x2a902a8, 0x2ad02ac, 0x497049b, 0x1bd02ca, 0xffff01c5, 0x1cb01c9, 0x1d1ffff, 0x1d3ffff, 0xffffffff, 0xffffffff, 0xffff01d7, 0x1d9ffff, 0x79affff, 0xffff0643, 0x1db01dd, 0x559ffff, 0xffffffff, 0x1e1ffff, 0x2c6ffff, 0xffff01e3, 0x1e7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2b4ffff, 0xffffffff, 0xffff01ef, 0x1f3ffff, 0xffffffff, 0xffffffff, 0x29f01f7, 0x1fd01fb, 0xffff02a1, 0xffffffff, 0xffffffff, 0xffff0203, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x8e4ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3450344, 0x3470346, 0xffffffff, 0x34b034a, 0xffffffff, 0x406ffff, 0x40a0408, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0350, 0x3560354, 0xffff0358, 0xffff035a, 0x35e035c, 0x3630902, 0x36803c2, 0x3fd036a, 0x371036f, 0x8e503f9, 0x37e03f3, 0x3830471, 0x3870385, 0x3f603cc, 0x3b5ffff, 0x3940392, 0x39903c9, 0x762039b, 0x3a203a0, 0x3550351, 0x3590357, 0x3640915, 0x36903c3, 0x3fe036b, 0x3720370, 0x8e603fa, 0x37f03f4, 0x3840472, 0x3880386, 0x3f703cd, 0x3b703b6, 0x3950393, 0x39a03ca, 0x763039c, 0x3a303a1, 0x35d035b, 0x3c0035f, 0x3fb03c4, 0xffffffff, 0x3cbffff, 0x3c103ce, 0x3d003cf, 0x3d403d3, 0x3d603d5, 0x3d803d7, 0x3da03d9, 0x3de03dd, 0x3e003df, 0x3e403e3, 0x3e803e7, 0x3ec03eb, 0x3ee03ed, 0x3f203f1, 0x3f803f5, 0xffff0402, 0x3ff03fc, 0x400ffff, 0x4030401, 0x4050404, 0x407ffff, 0x40b0409, 0x40e040c, 0x4120410, 0x4160414, 0x41a0418, 0x41e041c, 0x4220420, 0x4260424, 0x42a0428, 0x42e042c, 0x4320430, 0x4360434, 0x43a0438, 0x43e043c, 0x4420440, 0x4460444, 0x44a0448, 0x44e044c, 0x4520450, 0x4560454, 0x45a0458, 0x45e045c, 0x4620460, 0x4660464, 0x46a0468, 0x42f042d, 0x4330431, 0x4370435, 0x43b0439, 0x43f043d, 0x4430441, 0x4470445, 0x44b0449, 0x44f044d, 0x4530451, 0x4570455, 0x45b0459, 0x45f045d, 0x4630461, 0x4670465, 0x46b0469, 0x40f040d, 0x4130411, 0x4170415, 0x41b0419, 0x41f041d, 0x4230421, 0x4270425, 0x42b0429, 0x4820481, 0x4840483, 0x4880487, 0x48a0489, 0x48e048d, 0x4920491, 0x4960495, 0x49a0499, 0x49e049d, 0x4a204a1, 0x4a404a3, 0x4a804a7, 0x4aa04a9, 0x4ac04ab, 0x4ae04ad, 0x4b204b1, 0x4b604b5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x4c604c5, 0x4c804c7, 0x4cc04cb, 0x4ce04cd, 0x4d004cf, 0x4d404d3, 0x4d804d7, 0x4da04d9, 0x4de04dd, 0x4e204e1, 0x4e404e3, 0x4e804e7, 0x4ea04e9, 0x4ec04eb, 0x4f004ef, 0x4f204f1, 0x4f604f5, 0x4fa04f9, 0x4fe04fd, 0x50004ff, 0x5040503, 0x5060505, 0x5080507, 0x50c050b, 0x510050f, 0x5140513, 0x5180517, 0x51d051b, 0x521051e, 0x5250522, 0x5290526, 0x52d052a, 0x531052e, 0x5350532, 0x51c0536, 0x53c053b, 0x53e053d, 0x540053f, 0x5440543, 0x5480547, 0x54a0549, 0x54e054d, 0x550054f, 0x5520551, 0x5560555, 0x5580557, 0x55c055b, 0x55e055d, 0x560055f, 0x5640563, 0x5680567, 0x56a0569, 0x56e056d, 0x570056f, 0x5720571, 0x5740573, 0x5780577, 0x57a0579, 0x57c057b, 0x57e057d, 0x5820581, 0x5840583, 0x5880587, 0x58a0589, 0x58c058b, 0x58e058d, 0x5920591, 0x5940593, 0x5980597, 0x59a0599, 0x59c059b, 0x59e059d, 0x5a205a1, 0x5a605a5, 0x5aa05a9, 0x5ac05ab, 0x5ae05ad, 0x5b005af, 0x5b405b3, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x5b9ffff, 0x5bd05bb, 0x5c105bf, 0x5c505c3, 0x5c905c7, 0x5cd05cb, 0x5d105cf, 0x5d505d3, 0x5d905d7, 0x5dd05db, 0x5e105df, 0x5e505e3, 0x5e905e7, 0x5ed05eb, 0x5f105ef, 0x5f505f3, 0x5f905f7, 0x5fd05fb, 0x60105ff, 0xffff0603, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x5baffff, 0x5be05bc, 0x5c205c0, 0x5c605c4, 0x5ca05c8, 0x5ce05cc, 0x5d205d0, 0x5d605d4, 0x5da05d8, 0x5de05dc, 0x5e205e0, 0x5e605e4, 0x5ea05e8, 0x5ee05ec, 0x5f205f0, 0x5f605f4, 0x5fa05f8, 0x5fe05fc, 0x6020600, 0x6130604, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x880086, 0x8c008a, 0x90008e, 0x940092, 0x980096, 0x9c009a, 0xa0009e, 0xa400a2, 0xa800a6, 0xac00aa, 0xb000ae, 0xb400b2, 0xb800b6, 0xbc00ba, 0xc000be, 0xc400c2, 0x4bf04b7, 0x4d100ca, 0x4e500ce, 0x4f7ffff, 0xffffffff, 0xffffffff, 0x539ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x83affff, 0xffffffff, 0x485ffff, 0xffffffff, 0x6460645, 0x6480647, 0x64a0649, 0x64e064d, 0x6520651, 0x6540653, 0x6580657, 0x65a0659, 0x65c065b, 0x660065f, 0x6620661, 0x6660665, 0x6680667, 0x66a0669, 0x66c066b, 0x670066f, 0x6720671, 0x6740673, 0x6760675, 0x6780677, 0x67a0679, 0x67e067d, 0x680067f, 0x6820681, 0x6840683, 0x6860685, 0x6880687, 0x68c068b, 0x68e068d, 0x690068f, 0x6920691, 0x6940693, 0x6960695, 0x69a0699, 0x69c069b, 0x69e069d, 0x6a206a1, 0x6a606a5, 0x6a806a7, 0x6ac06ab, 0x6ae06ad, 0x6b006af, 0x6b206b1, 0x6b406b3, 0x6b606b5, 0x6ba06b9, 0x6bc06bb, 0x6be06bd, 0x70d070c, 0x6c306c2, 0x6c706c6, 0x6cb06ca, 0x6cd06cc, 0x6cf06ce, 0x6d106d0, 0x6d306d2, 0x6d506d4, 0x6d906d8, 0x6db06da, 0x6dd06dc, 0x6e106e0, 0x6e306e2, 0x6e506e4, 0x6e906e8, 0x6eb06ea, 0x6ed06ec, 0x6ef06ee, 0x6f106f0, 0x6f306f2, 0x6f706f6, 0x6f906f8, 0x6fb06fa, 0x6fd06fc, 0x6ff06fe, 0x7010700, 0x7040702, 0x7080706, 0x70e070a, 0xffffffff, 0xffff0710, 0x7130712, 0x7150714, 0x7170716, 0x71b071a, 0x71d071c, 0x71f071e, 0x7210720, 0x7230722, 0x7270726, 0x7290728, 0x72d072c, 0x72f072e, 0x7310730, 0x7330732, 0x7350734, 0x7370736, 0x73b073a, 0x73d073c, 0x7410740, 0x7430742, 0x7450744, 0x7470746, 0x7490748, 0x74b074a, 0x74d074c, 0x74f074e, 0x7510750, 0x7530752, 0x7550754, 0x7570756, 0x7590758, 0x75b075a, 0x75d075c, 0x75f075e, 0x7610760, 0x7660765, 0x7680767, 0x76a0769, 0x76e076d, 0x770076f, 0x7720771, 0x7740773, 0x7760775, 0x7780777, 0x77a0779, 0x77c077b, 0x780077f, 0x7850784, 0x78a0788, 0x78e078c, 0x7920790, 0x7960794, 0x78b0789, 0x78f078d, 0x7930791, 0x7970795, 0x79e079c, 0x7a207a0, 0x7a607a4, 0xffffffff, 0x79f079d, 0x7a307a1, 0x7a707a5, 0xffffffff, 0x7b807b6, 0x7bc07ba, 0x7c007be, 0x7c407c2, 0x7b907b7, 0x7bd07bb, 0x7c107bf, 0x7c507c3, 0x7d807d6, 0x7dc07da, 0x7e007de, 0x7e407e2, 0x7d907d7, 0x7dd07db, 0x7e107df, 0x7e507e3, 0x7f007ee, 0x7f407f2, 0x7f807f6, 0xffffffff, 0x7f107ef, 0x7f507f3, 0x7f907f7, 0xffffffff, 0x80807fc, 0x80c07fe, 0x8100800, 0x8140804, 0x809ffff, 0x80dffff, 0x811ffff, 0x815ffff, 0x8240822, 0x8280826, 0x82c082a, 0x830082e, 0x8250823, 0x8290827, 0x82d082b, 0x831082f, 0x8df08dd, 0x8f708f5, 0x8fb08f9, 0x90f090d, 0x9370935, 0x9240922, 0x93b0939, 0xffffffff, 0x8590856, 0x85f085c, 0x8650862, 0x86b0868, 0x85a0857, 0x860085d, 0x8660863, 0x86c0869, 0x8890886, 0x88f088c, 0x8950892, 0x89b0898, 0x88a0887, 0x890088d, 0x8960893, 0x89c0899, 0x8b908b6, 0x8bf08bc, 0x8c508c2, 0x8cb08c8, 0x8ba08b7, 0x8c008bd, 0x8c608c3, 0x8cc08c9, 0x8db08d9, 0x8e108ce, 0xffff08d3, 0x8d708d5, 0x8dc08da, 0x8e008de, 0xffff08e2, 0xffff08e7, 0xffffffff, 0x8fd08e8, 0xffff08ed, 0x8f308f1, 0x8f808f6, 0x8fc08fa, 0xffff08fe, 0xffffffff, 0x90b0909, 0x9030900, 0xffffffff, 0x9070905, 0x90c090a, 0x910090e, 0xffffffff, 0xffffffff, 0x920091e, 0x9160913, 0x9260918, 0x91c091a, 0x921091f, 0x9250923, 0xffff0927, 0xffffffff, 0xffffffff, 0x93d092a, 0xffff092f, 0x9330931, 0x9380936, 0x93c093a, 0xffff093e, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0764, 0xffffffff, 0x1500783, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0561, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0562, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x18902b0, 0x18d02c2, 0x19102d6, 0x195005e, 0x1990064, 0x19d006c, 0x1a10076, 0x1a5007e, 0x18a02b1, 0x18e02c3, 0x19202d7, 0x196005f, 0x19a0065, 0x19e006d, 0x1a20077, 0x1a6007f, 0xffffffff, 0x1c0ffff, 0xffff01c1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x5090475, 0x50d0477, 0x511047d, 0x515048f, 0x51904a5, 0x2e80940, 0x2051f, 0x7180523, 0x6e0527, 0x3a4052b, 0x110052f, 0x6630533, 0x54b0537, 0x50a0476, 0x50e0478, 0x512047e, 0x5160490, 0x51a04a6, 0x2e90941, 0x30520, 0x7190524, 0x6f0528, 0x3a5052c, 0x1110530, 0x6640534, 0x54c0538, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40000, 0xa0008, 0xe000c, 0x160010, 0x1a0018, 0x2ce001c, 0x2e602dc, 0x560308, 0x600058, 0x660062, 0x70006a, 0x780074, 0x80007c, 0x2aa0082, 0x60832, 0x64b0084, 0x2b805b5, 0x60d0609, 0x629061d, 0x1080106, 0x112010a, 0x11c0116, 0x12c0124, 0xffff0134, 0x50001, 0xb0009, 0xf000d, 0x170011, 0x1b0019, 0x2cf001d, 0x2e702dd, 0x570309, 0x610059, 0x670063, 0x71006b, 0x790075, 0x81007d, 0x2ab0083, 0x70833, 0x64c0085, 0x2b905b6, 0x60e060a, 0x62a061e, 0x1090107, 0x113010b, 0x11d0117, 0x12d0125, 0xffff0135, 0x4f404f3, 0x486055a, 0x29102b5, 0x48b0297, 0x2ba048c, 0x49302bb, 0x4980494, 0x49c02c7, 0xffff02cb, 0x2cd02cc, 0x2d4ffff, 0xffff02d5, 0xffffffff, 0xffffffff, 0xffffffff, 0x4b402ed, 0x2f902f8, 0x4ba04b9, 0x4bc04bb, 0x4be04bd, 0x4c204c1, 0x3250324, 0x32b032a, 0x3350334, 0x33d033c, 0x3410340, 0x34d034c, 0x34f034e, 0x3230322, 0x73f073e, 0x3ae03ad, 0x3b003af, 0x3b403b3, 0x3bf03be, 0x3d203d1, 0x3e203e1, 0x5a405a3, 0x6060605, 0x61a0619, 0x6320631, 0x6560655, 0x6a0069f, 0x46f046e, 0x7390738, 0x77e077d, 0x7d507d4, 0x8350834, 0x6df06de, 0x6a406a3, 0x150014, 0x5d005c, 0x4ee04ed, 0x5020501, 0x6120611, 0x1aa01a9, 0x5420541, 0x5540553, 0x5660565, 0x5760575, 0x5860585, 0x5960595, 0x5a805a7, 0x5b805b7, 0x1620161, 0x3a703a6, 0x3ea03e9, 0xffffffff, 0xffffffff, 0xffffffff, 0x60fffff, 0x6170610, 0xffff0618, 0xffffffff, 0x6240623, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x890087, 0x8d008b, 0x91008f, 0x950093, 0x990097, 0x9d009b, 0xa1009f, 0xa500a3, 0xa900a7, 0xad00ab, 0xb100af, 0xb500b3, 0xb900b7, 0xbd00bb, 0xc100bf, 0xc500c3, 0x4c004b8, 0x4d200cb, 0x4e600cf, 0x4f8ffff, 0xffffffff, 0xffffffff, 0x53affff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2d902d8, 0x6160615, 0x61c061b, 0x6220621, 0x6280627, 0x1e501e4, 0x62e062d, 0x6340633, 0x6380637, 0x63e063d, 0x6420641, 0x32f032e, 0x65e065d, 0x66e066d, 0x67c067b, 0x68a0689, 0x6980697, 0x6aa06a9, 0x6b806b7, 0x6c906c8, 0x6d706d6, 0x6e706e6, 0x6f506f4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7870786, 0x690068, 0x28f028e, 0x7b107b0, 0x7c907c8, 0x3bd03bc, 0x1f001e, 0x8030802, 0x8190818, 0x2b302b2, 0x8370836, 0x2d302d2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ab07aa, 0x7af07ae, 0x7b307b2, 0x2eb02ea, 0x2f502f4, 0x3070306, 0x3110310, 0xffffffff, 0x7cb07ca, 0x7cf07ce, 0x7d307d2, 0x3330332, 0x33b033a, 0x33f033e, 0x3490348, 0x7e707e6, 0x7e907e8, 0x7eb07ea, 0x7ed07ec, 0x3ac03ab, 0x3b203b1, 0x3bb03ba, 0x7fb07fa, 0x3dc03db, 0x3f003ef, 0x620061f, 0x2830282, 0x8070806, 0x80b080a, 0x80f080e, 0x8130812, 0x8170816, 0x81b081a, 0x81f081e, 0x8210820, 0x4a0049f, 0x4b004af, 0x4c404c3, 0x4d604d5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x545ffff, 0x8380546, 0x83b0839, 0x83d083c, 0x580057f, 0x590058f, 0x5a0059f, 0x5b205b1, 0xffffffff, 0x63bffff, 0x79b063c, 0xffffffff, 0x6080607, 0x60c060b, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x62c062b, 0x630062f, 0x6360635, 0x63a0639, 0x640063f, 0xffff0644, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x25e02f6, 0x2fc02fa, 0x30302fe, 0xffff0304, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x30cffff, 0x2c0030e, 0x3140312, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7a8ffff, 0x7ac02da, 0x2e202e0, 0x7b402e4, 0x2f00724, 0x144076b, 0x30a0479, 0x318081c, 0x31a07c6, 0x7cc031c, 0x7d00320, 0x32c022c, 0x336007a, 0xffff046c, 0xffffffff, 0xffffffff, 0x7a9ffff, 0x7ad02db, 0x2e302e1, 0x7b502e5, 0x2f10725, 0x145076c, 0x30b047a, 0x319081d, 0x31b07c7, 0x7cd031d, 0x7d10321, 0x32d022d, 0x337007b, 0xffff046d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x9280012, 0x72005a, 0x3520338, 0x114010c, 0x2bc0625, 0x2f202ae, 0x31608ef, 0x10e064f, 0x2ee02b6, 0x4fb029a, 0x2c802be, 0x2de02d0, 0x47f0798, 0x330031e, 0x24e0342, 0x3b802c4, 0x47b03e5, 0x473056b, 0x72a06c4, 0x91104df, 0x9290013, 0x73005b, 0x3530339, 0x115010d, 0x2bd0626, 0x2f302af, 0x31708f0, 0x10f0650, 0x2ef02b7, 0x4fc029b, 0x2c902bf, 0x2df02d1, 0x4800799, 0x331031f, 0x24f0343, 0x3b902c5, 0x47c03e6, 0x474056c, 0x72b06c5, 0x91204e0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); //4000 bytes enum alphaTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x160], [ 0x100, 0x240, 0x5100], [ 0x3020100, 0x7060504, 0xb0a0908, 0xe0d0c0a, 0x3030303, 0x100a0f03, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xb000a, 0xd000c, 0xf000e, 0x10010, 0x120011, 0x10013, 0x150014, 0x170016, 0x190018, 0x1b001a, 0x1c0001, 0x1e001d, 0x1f001f, 0x1f0020, 0x1f001f, 0x1f001f, 0x1f001f, 0x220021, 0x1f0023, 0x250024, 0x1f001f, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x260001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x270001, 0x10001, 0x10001, 0x10028, 0x2a0029, 0x2c002b, 0x2e002d, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x2f0001, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1001f, 0x310030, 0x320001, 0x340033, 0x360035, 0x380037, 0x1f0039, 0x1f001f, 0x3b003a, 0x3d003c, 0x1f003e, 0x1f001f, 0x40003f, 0x1f001f, 0x1f001f, 0x1f0041, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x10001, 0x420001, 0x1f0043, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x10001, 0x10001, 0x1f0044, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x10001, 0x1f0045, 0x1f001f, 0x46001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f0047, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x490048, 0x4b004a, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f004c, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x10001, 0x10001, 0x10001, 0x1004d, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x4e0001, 0x1f004f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x10001, 0x1f004f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x1f001f, 0x0, 0x0, 0x7fffffe, 0x7fffffe, 0x0, 0x4200400, 0xff7fffff, 0xff7fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3ffc3, 0x501f, 0x0, 0x0, 0x20, 0x3cdf0000, 0xffffd740, 0xfffffffb, 0xffffffff, 0xffbfffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffc03, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffe00ff, 0x27fffff, 0xfffffffe, 0xff, 0xbfff0000, 0xffff00b6, 0x707ff, 0x7ff0000, 0xffffffff, 0xfeffffff, 0xffffc000, 0xffffffff, 0xffffffff, 0x1fefffff, 0x9c00e1fe, 0xffff0000, 0xffffffff, 0xffffe000, 0xffffffff, 0xffffffff, 0x3ffff, 0xfffffc00, 0x43007ff, 0xfcffffff, 0x1fff, 0x1ffffff, 0x0, 0x0, 0x1ffd, 0x0, 0x7fff03f0, 0xffffffff, 0xefffffff, 0xffe1dfff, 0xfefe000f, 0xfff99fee, 0xe3c5fdff, 0xb080599f, 0x3000f, 0xfff987ee, 0xc36dfdff, 0x5e021987, 0x3f0000, 0xfffbbfee, 0xe3edfdff, 0x11bbf, 0xf, 0xfff99fee, 0xe3edfdff, 0xb0c0199f, 0x2000f, 0xd63dc7ec, 0xc3ffc718, 0x811dc7, 0x0, 0xfffddfee, 0xe3effdff, 0x3601ddf, 0xf, 0xfffddfec, 0xe3effdff, 0x40601ddf, 0x6000f, 0xfffddfec, 0xe7ffffff, 0x805ddf, 0xfc00000f, 0xfc7fffec, 0x2ffbffff, 0xff5f807f, 0xc0000, 0xfffffffe, 0x7ffffff, 0x207f, 0x0, 0xfef02596, 0x3bffecae, 0xf000205f, 0x0, 0x1, 0x0, 0xfffffeff, 0xfffe1fff, 0xfeffff03, 0x1fffffff, 0x0, 0x0, 0xffffffff, 0xf97fffff, 0xffff0000, 0xffffc1e7, 0x3000407f, 0xffffffff, 0xffff20bf, 0xf7ffffff, 0xffffffff, 0xffffffff, 0x3d7f3dff, 0xffffffff, 0xffff3dff, 0x7f3dffff, 0xff7fff3d, 0xffffffff, 0xff3dffff, 0xffffffff, 0x87ffffff, 0x0, 0xffff, 0xffffffff, 0xffffffff, 0x1fffff, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff9fff, 0x7fffffe, 0xffffffff, 0xffffffff, 0x1c7ff, 0xfdfff, 0xfffff, 0xfffff, 0xddfff, 0xffffffff, 0xffcfffff, 0x108001ff, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffff, 0xffffffff, 0xffff07ff, 0xffffffff, 0x3fffff, 0x1fffffff, 0x1ff0fff, 0xffff0000, 0x1f3fff, 0xffffffff, 0xffff0fff, 0x3ff, 0x0, 0xfffffff, 0xffffffff, 0x7fffffff, 0x1ffffe, 0x0, 0x80, 0x0, 0x0, 0xffffffff, 0xffefffff, 0xfef, 0x0, 0xffffffff, 0xfc00f3ff, 0xffffffff, 0x3ffbf, 0xffffffff, 0x3fffff, 0xfc00e000, 0x3fffffff, 0x0, 0x0, 0x0, 0x6fde00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0, 0x0, 0x3f3fffff, 0xffffffff, 0xaaff3f3f, 0x3fffffff, 0xffffffff, 0x5fdfffff, 0xfcf1fdc, 0x1fdc1fff, 0x0, 0x0, 0x0, 0x80020000, 0x1fff0000, 0x0, 0x0, 0x0, 0x3e2ffc84, 0xf3ffbd50, 0x43e0, 0xffffffff, 0x1ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc00000, 0xffffffff, 0x3ff, 0xffffffff, 0xffff7fff, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xc781f, 0xffffffff, 0xffff20bf, 0xffffffff, 0x80ff, 0x7fffff, 0x7f7f7f7f, 0x7f7f7f7f, 0xffffffff, 0x0, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x1f3e03fe, 0xfffffffe, 0xffffffff, 0xe07fffff, 0xfffffffe, 0xffffffff, 0xf7ffffff, 0xffffffe0, 0xfffe3fff, 0xffffffff, 0xffffffff, 0x7fff, 0x7ffffff, 0x0, 0xffff0000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffff, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1fff, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1fff, 0x0, 0xffff0000, 0x3fffffff, 0xffff1fff, 0xc00, 0xffffffff, 0x8ff07fff, 0x80ffffff, 0xffffffff, 0xffffffff, 0xffff, 0xff800000, 0xfffffffc, 0xffffffff, 0xffffffff, 0xf79ff, 0x7ff, 0x0, 0xff000000, 0xfffff7bb, 0xff, 0xffffffff, 0xfffff, 0xffffffff, 0xffffffff, 0xf, 0x8fc0000, 0xfffffc00, 0xffff07ff, 0x7ffff, 0x1fffffff, 0xffffffff, 0xfff7ffff, 0x8000, 0x0, 0xffffffff, 0x7fffff, 0x3fff, 0x47fffff, 0xffffffff, 0x7fffffff, 0x38000005, 0x3cffff, 0x7e7e7e, 0x7f7f, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x7ff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff000f, 0xfffff87f, 0xfffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff3fff, 0xffffffff, 0xffffffff, 0x3ffffff, 0x0, 0xe0f8007f, 0x5f7ffdff, 0xffffffdb, 0xffffffff, 0xffffffff, 0x3ffff, 0xfff80000, 0xffffffff, 0xffffffff, 0x3fffffff, 0xffff0000, 0xffffffff, 0xfffcffff, 0xffffffff, 0xff, 0xfff0000, 0x0, 0x0, 0x0, 0xffdf0000, 0xffffffff, 0xffffffff, 0xffffffff, 0x1fffffff, 0x0, 0x7fffffe, 0x7fffffe, 0xffffffc0, 0xffffffff, 0x7fffffff, 0x1cfcfcfc, 0x0, 0xffffefff, 0xb7ffff7f, 0x3fff3fff, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffff, 0x0, 0x0, 0xffffffff, 0x1fffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1fffffff, 0xffffffff, 0x1ffff, 0x0, 0x7fffffff, 0xffff0000, 0x7ff, 0x0, 0x3fffffff, 0xffffffff, 0x3eff0f, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffffff, 0x0, 0x0, 0x0, 0xfffffd3f, 0x91bfffff, 0x3fffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fffff, 0x3ffffff, 0x0, 0x0, 0xffffffff, 0xc0ffffff, 0x0, 0x0, 0xfeeff06f, 0xfffff, 0x0, 0x1fffffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x3fffff, 0x3fffff, 0x7ffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0x1ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0x3f, 0x0, 0xfffffffc, 0x1ffffff, 0xffff0000, 0x1ff, 0xffffffff, 0x7ffff, 0x0, 0x0, 0xffffffff, 0xffffffff, 0x1e, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x3fffff, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0x7, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x7fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x1ffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffff001f, 0x7fffffff, 0xfff80000, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffdfffff, 0xffffffff, 0xdfffffff, 0xebffde64, 0xffffffef, 0xffffffff, 0xdfdfe7bf, 0x7bffffff, 0xfffdfc5f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff3f, 0xf7fffffd, 0xf7ffffff, 0xffdfffff, 0xffdfffff, 0xffff7fff, 0xffff7fff, 0xfffffdff, 0xfffffdff, 0xff7, 0x0, 0xffffffef, 0xaf7fe96, 0xaa96ea84, 0x5ef7f796, 0xffffbff, 0xffffbee, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffff, 0x0, 0xffffffff, 0x1fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2304 bytes enum markTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xe0], [ 0x100, 0x140, 0x2c00], [ 0x2020100, 0x4020302, 0x6020205, 0x2070202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020208, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xb000a, 0xd000c, 0xe, 0xf0000, 0x0, 0x100000, 0x120011, 0x140013, 0x160015, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x190018, 0x0, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x1d001c, 0x1f001e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x21, 0x220000, 0x0, 0x0, 0x0, 0x0, 0x23, 0x0, 0x0, 0x250024, 0x0, 0x0, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x270000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x280000, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, 0xbfffffff, 0xb6, 0x0, 0x7ff0000, 0x0, 0xfffff800, 0x10000, 0x0, 0x0, 0x9fc00000, 0x3d9f, 0x20000, 0xffff0000, 0x7ff, 0x0, 0x0, 0x1ffc0, 0x0, 0xff800, 0xfbc00000, 0x3eef, 0xe000000, 0x0, 0x0, 0x0, 0x0, 0x7ffffff0, 0xf, 0xdc000000, 0xfeffff, 0xc, 0xe, 0xd0000000, 0x80399f, 0xc, 0xe, 0xd0000000, 0x23987, 0x230000, 0xe, 0xd0000000, 0x3bbf, 0xc, 0xe, 0xd0000000, 0xc0399f, 0xc, 0x4, 0xc0000000, 0x803dc7, 0x0, 0xe, 0xc0000000, 0x603ddf, 0xc, 0xc, 0xd0000000, 0x603ddf, 0xc, 0xc, 0xc0000000, 0x803ddf, 0xc, 0xc, 0x0, 0xff5f8400, 0xc0000, 0x0, 0x7f20000, 0x7f80, 0x0, 0x0, 0x1bf20000, 0x3f00, 0x0, 0x3000000, 0xc2a00000, 0x0, 0xfffe0000, 0xfeffe0df, 0x1fffffff, 0x40, 0x0, 0x0, 0x7ffff800, 0xc3c00000, 0x1e3f9d, 0x3c00bffc, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c0000, 0x1c0000, 0xc0000, 0xc0000, 0x0, 0xfff00000, 0x200fffff, 0x0, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x200, 0x0, 0x0, 0x0, 0xfff0fff, 0x0, 0x0, 0x0, 0xffff0000, 0x301, 0x0, 0xf800000, 0x0, 0x7fe00000, 0x9fffffff, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfff00000, 0x1f, 0xff800, 0x7, 0x3ffe, 0x0, 0xfffc0, 0x0, 0xfffff0, 0x0, 0x0, 0x0, 0x0, 0xfff70000, 0x1c21ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xf000007f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff0000, 0x1ffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38000, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0xffffffff, 0x0, 0xfc00, 0x0, 0x0, 0x6000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff78000, 0x80000000, 0x0, 0x0, 0x30000, 0x844, 0xf8, 0x0, 0x0, 0x3, 0xfff00000, 0x1f, 0x3ffff, 0x0, 0x3fc0, 0xfff80, 0x0, 0xf, 0xfff80000, 0x1, 0x0, 0x0, 0x7ffe00, 0x3008, 0x8000000, 0x0, 0xc19d0000, 0x2, 0x60f800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x37f8, 0x40000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000, 0xf06e, 0x87000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff000000, 0x7f, 0x0, 0x7, 0x7ff0000, 0x0, 0x0, 0x7, 0x1fff80, 0x0, 0x0, 0x7, 0xfff80000, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfff800, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, 0x7fffffff, 0x78000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf807e3e0, 0xfe7, 0x3c00, 0x0, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2384 bytes enum numberTrieEntries = TrieEntry!(bool, 8, 6, 7)([ 0x0, 0x40, 0x180], [ 0x100, 0x280, 0x1a80], [ 0x2020100, 0x4020302, 0x2020605, 0x8070202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x40003, 0x50002, 0x20002, 0x70006, 0x60006, 0x90008, 0x6000a, 0x2000b, 0xc000c, 0x2000d, 0xe0005, 0x20002, 0x20002, 0x2000f, 0x20002, 0x20002, 0x100002, 0x110002, 0x2000e, 0x130012, 0x140002, 0xc, 0x20015, 0x20002, 0x20002, 0x20002, 0x170016, 0x190018, 0x20002, 0x20002, 0x1b001a, 0x20002, 0x20002, 0x1d001c, 0x20002, 0x20002, 0x20002, 0x20002, 0x1e0002, 0x20002, 0x20002, 0x20002, 0x2001f, 0x200002, 0x220021, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x60023, 0x20002, 0xc0024, 0xc0017, 0x2000c, 0x40002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x2000e, 0x20002, 0x260025, 0x20002, 0x280027, 0x230002, 0x20002, 0x20002, 0x20002, 0x20029, 0x2002a, 0x2002b, 0x2002c, 0x20002, 0x20002, 0x2002d, 0x20002, 0x4002e, 0xc002f, 0x20002, 0x20002, 0x20002, 0x20002, 0x50002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20030, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20031, 0x20002, 0x20002, 0x20002, 0x320002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20033, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x20002, 0x0, 0x3ff0000, 0x0, 0x0, 0x0, 0x720c0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x0, 0x0, 0x0, 0x3ff0000, 0x0, 0x0, 0x3ff, 0x0, 0x0, 0x0, 0x0, 0xffc0, 0x0, 0x0, 0x0, 0x3f0ffc0, 0x0, 0x0, 0x0, 0xfcffc0, 0x0, 0x0, 0x0, 0x7ffc0, 0x0, 0x0, 0x0, 0x7f00ffc0, 0x0, 0x0, 0x0, 0x3fffc0, 0x0, 0x0, 0x3ff0000, 0x0, 0x0, 0xfffff, 0x0, 0x0, 0x3ff0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1ffffe00, 0x0, 0x0, 0x0, 0x1c000, 0x0, 0x0, 0x0, 0x3ff03ff, 0x0, 0x0, 0xffc0, 0x0, 0x0, 0x0, 0x7ff0000, 0x0, 0x3ff03ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff03ff, 0x0, 0x0, 0x0, 0x0, 0x3f10000, 0x3ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff0000, 0xffffffff, 0x3e7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xfffffff, 0x0, 0x0, 0xfffffc00, 0x0, 0x0, 0x0, 0xffc00000, 0xfffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000, 0x80, 0x70003fe, 0x0, 0x0, 0x3c0000, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0xfffeff00, 0x0, 0x3ff, 0xfffe0000, 0x0, 0x0, 0x0, 0x3ff, 0x0, 0x0, 0x0, 0x3f0000, 0x0, 0x0, 0xffffff80, 0xfffff, 0xffffffff, 0x1ffffff, 0x400, 0x0, 0x0, 0x0, 0x0, 0xf, 0x402, 0x0, 0x0, 0x0, 0x3e0000, 0x0, 0x0, 0x0, 0xff000000, 0x0, 0xfc00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x60000000, 0x0, 0x0, 0xff000000, 0xff000000, 0x0, 0x0, 0x0, 0x7fffffff, 0x0, 0x0, 0xfffc0000, 0xffff, 0x0, 0xffc00000, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0x7, 0x0, 0x0, 0x0, 0x3ffff, 0x0, 0x0, 0xffffc000, 0xffffffff, 0x7ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2336 bytes enum punctuationTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xc0], [ 0x100, 0x100, 0x3100], [ 0x2020100, 0x4020302, 0x2020605, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x20001, 0x30001, 0x50004, 0x70006, 0x10008, 0x90001, 0xb000a, 0x1000c, 0xd0001, 0x1000e, 0x10000f, 0x120011, 0x140013, 0x10015, 0x10001, 0x10016, 0x170001, 0x10001, 0x180001, 0x190001, 0x10001, 0x1b001a, 0x1001c, 0x1001d, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x1001e, 0x1001f, 0x210020, 0x230022, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x240001, 0x260025, 0x270001, 0x280001, 0x10001, 0x10001, 0x2a0029, 0x2c002b, 0x10001, 0x10001, 0x2e002d, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x1002f, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x0, 0x8c00f7ee, 0xb8000001, 0x28000000, 0x0, 0x88c00882, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc000000, 0x0, 0x600, 0x40000000, 0x49, 0x180000, 0xc8003600, 0x0, 0x0, 0x3c00, 0x0, 0x0, 0x100000, 0x0, 0x3fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3800000, 0x0, 0x7fff0000, 0x40000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10030, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000, 0x0, 0x0, 0xc008000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x17fff0, 0x3c000000, 0x0, 0x0, 0x20, 0x0, 0x61f0000, 0x0, 0x0, 0x0, 0xfc00, 0x0, 0x0, 0x0, 0x0, 0x8000000, 0x0, 0x0, 0x0, 0x1ff, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6000, 0x18000000, 0x0, 0x0, 0x3800, 0x0, 0x600000, 0x0, 0x0, 0x0, 0x0, 0x7700000, 0x0, 0x7ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x0, 0x3f7f, 0x0, 0x0, 0x0, 0x0, 0xfc000000, 0x1, 0x0, 0x0, 0x0, 0xf0000000, 0x0, 0xf8000000, 0x0, 0xc0000000, 0x0, 0x0, 0x800ff, 0x0, 0xffff0000, 0xffff00ff, 0x7ffbffef, 0x60000000, 0x6000, 0x0, 0x0, 0x0, 0xf00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff00, 0x0, 0x0, 0x60, 0xffc0, 0x0, 0x0, 0x0, 0x0, 0x1fffff8, 0x0, 0xf000000, 0x30000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xde000000, 0x0, 0x0, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xfff7fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfff3ff0e, 0x20010000, 0x0, 0x0, 0x0, 0x1, 0x0, 0x8000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0xe000, 0x0, 0x0, 0x40080000, 0x0, 0x0, 0x0, 0xfc0000, 0x0, 0x0, 0x0, 0xf00000, 0x0, 0x0, 0xc000, 0x7000000, 0x0, 0xc000, 0x80000000, 0x0, 0x0, 0x0, 0xc0003ffe, 0x0, 0x0, 0x0, 0xf0000000, 0x0, 0x0, 0x0, 0xc0000000, 0x30000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff0000, 0xffff0000, 0xfff7ffff, 0xd0b, 0x0, 0x0, 0x0, 0x0, 0x8c00f7ee, 0xb8000001, 0xa8000000, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x800000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x80000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1ff0000, 0x80000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f80, 0x0, 0x0, 0xd8000000, 0x3, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x1e0, 0x0, 0x0, 0x0, 0x0, 0xf0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2848 bytes enum symbolTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xe0], [ 0x100, 0x140, 0x3d00], [ 0x3020100, 0x5030403, 0x3030306, 0x8070303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x3030303, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x80001, 0xa0009, 0xc000b, 0xe000d, 0x1000f, 0x100001, 0x10001, 0x110001, 0x120001, 0x130001, 0x10001, 0x140001, 0x160015, 0x180017, 0x170019, 0x1a0017, 0x1b0017, 0x1c0017, 0x1001d, 0x1f001e, 0x210020, 0x170022, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x230001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10024, 0x250001, 0x10026, 0x10027, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x280001, 0x290001, 0x2b002a, 0x2c0001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x2e002d, 0x30002f, 0x10001, 0x320031, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10033, 0x350034, 0x370036, 0x390038, 0x3b003a, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x0, 0x70000810, 0x40000000, 0x50000001, 0x0, 0x113d37c, 0x800000, 0x800000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffc003c, 0xffffafe0, 0x0, 0x0, 0x0, 0x200000, 0x30, 0x0, 0x0, 0x400000, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000, 0x0, 0x0, 0x0, 0xc9c0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000, 0x60000200, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0c0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000, 0x0, 0x0, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x7f80000, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfce8000e, 0x1500000, 0x0, 0x0, 0x0, 0xc0000000, 0x1e0dfbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc0000000, 0xffffffff, 0x0, 0x0, 0x0, 0x1ff007fe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa0000000, 0xe000e003, 0x6000e000, 0x0, 0x0, 0x40010, 0x1c000000, 0x1c00, 0x7ffffff, 0x0, 0x0, 0xc1d0037b, 0xc0042af, 0xbc1f, 0x0, 0xffff0000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff0ff, 0xfffff9ff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff, 0xffffffff, 0x7f, 0x7ff, 0x0, 0xf0000000, 0xffffffff, 0xffffffff, 0x3ff, 0xfffffffe, 0xffffffff, 0xffffffff, 0xff, 0xfff00000, 0xffffffff, 0xffffff9f, 0xffff003f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfe000007, 0xffffffff, 0xf0ffffff, 0xcfffffff, 0xffffffff, 0xffffffff, 0x3ff1fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e0, 0x0, 0x0, 0x0, 0x0, 0xfbffffff, 0xffffffff, 0xffffffff, 0xfffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffff, 0xfff0000, 0xc0010, 0xc0c00001, 0x0, 0x0, 0x18000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc30000, 0x0, 0xffffffff, 0xf, 0x7fffffff, 0xfffffc00, 0x100ff, 0xffffffff, 0xfffffc00, 0x1ffff, 0xffffffff, 0x7fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0x0, 0x0, 0x0, 0x0, 0xffff0000, 0xffffffff, 0x7f, 0x0, 0x7fffff, 0x3, 0x0, 0x0, 0x600, 0x0, 0x0, 0x0, 0x0, 0x3c00f00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3800000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200, 0x0, 0x0, 0x0, 0xfffc0000, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30000000, 0x0, 0x0, 0x0, 0x274, 0x0, 0x0, 0x0, 0x0, 0x70000810, 0x40000000, 0x50000001, 0x0, 0x0, 0x0, 0x0, 0x30007f7f, 0x0, 0xff800000, 0x0, 0xfe000000, 0xfff03ff, 0x0, 0xffff0000, 0x1fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffff, 0xffffffff, 0xfffffe7f, 0xffffffff, 0x1c1f, 0xfffff018, 0xffffc3ff, 0x3fffffff, 0x0, 0xffffffff, 0xffffffff, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0x7fffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000002, 0x8000000, 0x200000, 0x200000, 0x8000, 0x8000, 0x200, 0x200, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30000, 0xffffffff, 0xffff0fff, 0xffffffff, 0xffffffff, 0xfffff, 0x7ffe7fff, 0xfffefffe, 0x0, 0xffff0000, 0xffff7fff, 0xffffffff, 0xffff0fff, 0x7ffffff, 0x0, 0x0, 0xffffffc0, 0xffff0007, 0x7ffffff, 0x301ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffbf0001, 0xffffffff, 0x1fffffff, 0xfffff, 0xffffffff, 0x7df, 0x1ffff, 0xffffffff, 0x7fffffff, 0xfffffffd, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1effffff, 0xffffffff, 0x3fffffff, 0xffff000f, 0xff, 0x0, 0x0, 0x0, 0xf8000000, 0xffffffff, 0xffffffff, 0xffe1, 0x0, 0xffffffff, 0xffffffff, 0x3f, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //4576 bytes enum graphicalTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x170], [ 0x100, 0x260, 0x6100], [ 0x3020100, 0x7060504, 0xb0a0908, 0xe0d0c0a, 0x3030303, 0x100a0f03, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a11, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0xa0a0a0a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x20001, 0x30001, 0x50004, 0x70006, 0x90008, 0xb000a, 0xd000c, 0x1000e, 0x10000f, 0x10001, 0x120011, 0x140013, 0x160015, 0x180017, 0x190001, 0x1b001a, 0x1c0001, 0x1001d, 0x1e0001, 0x10001, 0x1f0001, 0x210020, 0x230022, 0x250024, 0x10026, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x270001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x280001, 0x10001, 0x10001, 0x10029, 0x2b002a, 0x2d002c, 0x2f002e, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x300001, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x10031, 0x330032, 0x340001, 0x360035, 0x380037, 0x3a0039, 0x31003b, 0x310031, 0x3d003c, 0x3f003e, 0x310040, 0x310041, 0x430042, 0x310031, 0x310031, 0x310044, 0x310031, 0x310031, 0x310031, 0x310031, 0x10001, 0x450001, 0x310046, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x10001, 0x10001, 0x310047, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x10001, 0x310048, 0x310031, 0x490031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x31004a, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x4c004b, 0x4e004d, 0x50004f, 0x520051, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310053, 0x550054, 0x570056, 0x590058, 0x5b005a, 0x310031, 0x310031, 0x310031, 0x310031, 0x10001, 0x10001, 0x10001, 0x1005c, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x5d0001, 0x31005e, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x10001, 0x31005e, 0x310031, 0x310031, 0x5f0031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x310031, 0x0, 0xffffffff, 0xffffffff, 0x7fffffff, 0x0, 0xffffdfff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7cffffff, 0xffffd7f0, 0xfffffffb, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffe00ff, 0xfe7fffff, 0xfffffffe, 0xfffe86ff, 0xffffffff, 0xffff00ff, 0x1f07ff, 0xcfffffc0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdfffffff, 0xffffffff, 0xffff3fff, 0xffffffff, 0xffffe7ff, 0xffffffff, 0xffffffff, 0x3ffff, 0xffffffff, 0x7ffffff, 0xffffffff, 0x7fff3fff, 0x4fffffff, 0x0, 0x0, 0x1ffd, 0x0, 0x7ffffff0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfeffffff, 0xfff99fee, 0xf3c5fdff, 0xb080799f, 0xfffffcf, 0xfff987ee, 0xd36dfdff, 0x5e023987, 0x3fffc0, 0xfffbbfee, 0xf3edfdff, 0x13bbf, 0x3ffcf, 0xfff99fee, 0xf3edfdff, 0xb0c0399f, 0xffffcf, 0xd63dc7ec, 0xc3ffc718, 0x813dc7, 0x7ffffc0, 0xfffddfee, 0xe3effdff, 0x3603ddf, 0xff00ffcf, 0xfffddfec, 0xf3effdff, 0x40603ddf, 0x6ffcf, 0xfffddfec, 0xe7ffffff, 0x807ddf, 0xfe3fffcf, 0xfc7fffec, 0x2ffbffff, 0xff5f847f, 0x1c0000, 0xfffffffe, 0x87ffffff, 0xfffffff, 0x0, 0xfef02596, 0x3bffecae, 0xf3ff3f5f, 0x0, 0xffffffff, 0xffffffff, 0xfffffeff, 0xfffe1fff, 0xfeffffff, 0xdfffffff, 0x7ffdfff, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff20bf, 0xffffffff, 0xffffffff, 0xffffffff, 0x3d7f3dff, 0xffffffff, 0xffff3dff, 0x7f3dffff, 0xff7fff3d, 0xffffffff, 0xff3dffff, 0xffffffff, 0xe7ffffff, 0x1fffffff, 0x3ffffff, 0xffffffff, 0xffffffff, 0x1fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1fffffff, 0xffffffff, 0xffffffff, 0x1ffff, 0x1fdfff, 0x7fffff, 0xfffff, 0xddfff, 0xffffffff, 0xffffffff, 0x3fffffff, 0x3ff03ff, 0x3ff3fff, 0xffffffff, 0xffffffff, 0xffffff, 0xffffffff, 0xffff07ff, 0xffffffff, 0x3fffff, 0x1fffffff, 0xfff0fff, 0xfffffff1, 0x1f3fff, 0xffffffff, 0xffff0fff, 0xc7ff03ff, 0xffffffff, 0xcfffffff, 0xffffffff, 0x7fffffff, 0x9fffffff, 0x3ff03ff, 0x3fff, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffff0fff, 0x1fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf00fffff, 0xffffffff, 0xf8ffffff, 0xffffe3ff, 0xffffffff, 0x0, 0x0, 0xffff00ff, 0x7fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf000007f, 0x3f3fffff, 0xffffffff, 0xaaff3f3f, 0x3fffffff, 0xffffffff, 0xffdfffff, 0xefcfffdf, 0x7fdcffff, 0xffff07ff, 0xffff80ff, 0xffffffff, 0xfff30000, 0x1fff7fff, 0x7ffffff, 0xffff0000, 0x1ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff03ff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff, 0xffffffff, 0x7f, 0x7ff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3ff1fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffff7fff, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfe0fffff, 0xffffffff, 0xffff20bf, 0xffffffff, 0x800180ff, 0x7fffff, 0x7f7f7f7f, 0x7f7f7f7f, 0xffffffff, 0xffffffff, 0xfffffff, 0x0, 0x0, 0xfbffffff, 0xffffffff, 0xffffffff, 0xfffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffff, 0xfff0000, 0xffffffff, 0xffffffff, 0xfffffffe, 0xffffffff, 0xfe7fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffe0, 0xfffe3fff, 0xffffffff, 0xffffffff, 0xffff7fff, 0x7ffffff, 0xffffffff, 0xffff000f, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1fff, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff1fff, 0xffffffff, 0xffff007f, 0xffffffff, 0xffffffff, 0xfff, 0xffffffff, 0xffffffff, 0x80ffffff, 0xffffffff, 0xffffffff, 0xffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf7fff, 0x7ff, 0x0, 0xff000000, 0xffffffff, 0x3ff0fff, 0xffffffff, 0xffffff, 0xffffffff, 0xffffffff, 0x3ffc01f, 0xfffffff, 0xffffffff, 0xffffffff, 0x800fffff, 0x1fffffff, 0xffffffff, 0xffffffff, 0xc3ffbfff, 0x0, 0xffffffff, 0x7fffff, 0xf3ff3fff, 0xfffffff, 0xffffffff, 0xffffffff, 0xf8000007, 0x7fffff, 0x7e7e7e, 0x7f7f, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x3ff3fff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff000f, 0xfffff87f, 0xfffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff3fff, 0xffffffff, 0xffffffff, 0x3ffffff, 0x0, 0xe0f8007f, 0x5f7fffff, 0xffffffdb, 0xffffffff, 0xffffffff, 0xffffffff, 0xfff80003, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000, 0xffffffff, 0xfffcffff, 0xffffffff, 0xff, 0x3fff0000, 0x3ffffff, 0xffff007f, 0xfff7ffff, 0xffdf0f7f, 0xffffffff, 0xffffffff, 0xffffffff, 0x1fffffff, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff, 0x1cfcfcfc, 0x30007f7f, 0xffffefff, 0xb7ffff7f, 0x3fff3fff, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffff, 0xffffff87, 0xff8fffff, 0xffffffff, 0xffffffff, 0xfff07ff, 0x0, 0xffff0000, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x1fffffff, 0xffffffff, 0x1ffff, 0x0, 0x7fffffff, 0xffff000f, 0x7ff, 0x0, 0xbfffffff, 0xffffffff, 0x3fff0f, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffffff, 0x3ff, 0x0, 0x0, 0xfffffd3f, 0x91bfffff, 0xffbfffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8fffffff, 0x83ffffff, 0x0, 0x0, 0xffffffff, 0xc0ffffff, 0x0, 0x0, 0xfeeff06f, 0x870fffff, 0x1ff00ff, 0xffffffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xfe3fffff, 0xff3fffff, 0xff07ffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0x1ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7fffffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xfffc3fff, 0xffff, 0xffffffff, 0xdfffffff, 0xffff0003, 0x3ff01ff, 0xffffffff, 0xffdfffff, 0xf, 0x0, 0xffffffff, 0xffffffff, 0x3ff01ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffff, 0x3ff, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xf0007, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x7fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0x1ffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffff001f, 0x7fffffff, 0xffff8000, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffff, 0xffffffff, 0xfffffe7f, 0xffffffff, 0xf807ffff, 0xffffffff, 0xffffffff, 0x3fffffff, 0x0, 0xffffffff, 0xffffffff, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0x7fffff, 0x3ffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffdfffff, 0xffffffff, 0xdfffffff, 0xebffde64, 0xffffffef, 0xffffffff, 0xdfdfe7bf, 0x7bffffff, 0xfffdfc5f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff3f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffcfff, 0xffffffff, 0xffffffef, 0xaf7fe96, 0xaa96ea84, 0x5ef7f796, 0xffffbff, 0xffffbee, 0x0, 0x30000, 0xffffffff, 0xffff0fff, 0xffffffff, 0xffffffff, 0xfffff, 0x7ffe7fff, 0xfffefffe, 0x0, 0xffff07ff, 0xffff7fff, 0xffffffff, 0xffff0fff, 0x7ffffff, 0x0, 0x0, 0xffffffc0, 0xffff0007, 0x7ffffff, 0x301ff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffbf0001, 0xffffffff, 0x1fffffff, 0xfffff, 0xffffffff, 0x7df, 0x1ffff, 0xffffffff, 0x7fffffff, 0xfffffffd, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1effffff, 0xffffffff, 0x3fffffff, 0xffff000f, 0xff, 0x0, 0x0, 0x0, 0xf8000000, 0xffffffff, 0xffffffff, 0xffe1, 0x0, 0xffffffff, 0xffffffff, 0x3f, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffff, 0x0, 0xffffffff, 0x1fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //3664 bytes enum nonCharacterTrieEntries = TrieEntry!(bool, 7, 4, 4, 6)([ 0x0, 0x20, 0x98, 0x208], [ 0x80, 0xf0, 0x2e0, 0x3180], [ 0x3020100, 0x7060504, 0xa090808, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0b, 0xb0b0b0c, 0xd080808, 0xd080808, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xb000a, 0xd000c, 0xd000d, 0xd000d, 0xe000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xf000d, 0x10000d, 0xd0011, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0x12000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0x140013, 0x160015, 0x180017, 0x1a0019, 0x1b001b, 0x1d001c, 0x1b001b, 0x1e000d, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x20001f, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b0021, 0x1b001b, 0x1b001b, 0x1b001b, 0x230022, 0x1b001b, 0x1b001b, 0x24001b, 0x260025, 0x1b001b, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0x27000d, 0xd000d, 0x28000d, 0x1b0029, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b002a, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b002b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0x1b001b, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0x2c000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0xd000d, 0x2c000d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x2, 0x0, 0x0, 0x40003, 0x60005, 0x7, 0x0, 0x90008, 0xb000a, 0xd000c, 0xf000e, 0x100000, 0x120011, 0x140013, 0x160015, 0x180017, 0x1a0019, 0x1c001b, 0x1e001d, 0x20001f, 0x220021, 0x240023, 0x260025, 0x270000, 0x290028, 0x0, 0x2a0000, 0x0, 0x0, 0x2b0000, 0x2d002c, 0x2f002e, 0x310030, 0x0, 0x0, 0x0, 0x0, 0x0, 0x330032, 0x350034, 0x360000, 0x380037, 0x3a0039, 0x3c003b, 0x3e003d, 0x40003f, 0x420041, 0x430000, 0x440000, 0x460045, 0x470042, 0x0, 0x480000, 0x0, 0x0, 0x4a0049, 0x4c004b, 0x4d0000, 0x4f004e, 0x0, 0x50, 0x0, 0x0, 0x0, 0x510000, 0x530052, 0x0, 0x0, 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x550000, 0x420042, 0x570056, 0x580000, 0x5a0059, 0x5c005b, 0x42005d, 0x51005e, 0x0, 0x5f0000, 0x540000, 0x60, 0x61, 0x630062, 0x57, 0x640000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x650000, 0x0, 0x670066, 0x0, 0x0, 0x68, 0x380069, 0x0, 0x6b006a, 0x38006c, 0x6d0000, 0x6e0000, 0x6f0000, 0x710070, 0x720000, 0x420073, 0x740042, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x750063, 0x0, 0x0, 0x0, 0x0, 0x760000, 0x770000, 0x790078, 0x7a0000, 0x0, 0x0, 0x7b0000, 0x7d007c, 0x7f007e, 0x800000, 0x54, 0x810064, 0x830082, 0xb0000, 0x84, 0x860085, 0x420042, 0x870032, 0x890088, 0x8b008a, 0x0, 0x42008c, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x8e008d, 0x420042, 0x42008f, 0x420090, 0x920091, 0x420042, 0x940093, 0x420042, 0x950000, 0x420042, 0x420042, 0x420042, 0x960042, 0x420042, 0x420042, 0x420042, 0x970000, 0x980000, 0x99004b, 0x9a0000, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x9b0038, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9c0000, 0x420042, 0x9d0000, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x42009c, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x0, 0x0, 0x0, 0x0, 0x42009e, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x9f0000, 0x4200a0, 0x4200a1, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x0, 0x3a0000, 0xa2, 0xa30000, 0xa40000, 0x420042, 0xa50000, 0x420042, 0xa60000, 0xa800a7, 0xaa00a9, 0x0, 0x0, 0xab, 0x0, 0xac0000, 0x420042, 0x420042, 0x420042, 0x420042, 0xae00ad, 0xb000af, 0x420042, 0x420042, 0x3d, 0xb200b1, 0x3d00b3, 0xb500b4, 0xb700b6, 0x420042, 0xb900b8, 0xbb00ba, 0xbc0064, 0xbd0000, 0xbf00be, 0xc00042, 0xc10000, 0xa40000, 0x510000, 0x420042, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc20000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x0, 0x4200a3, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x420042, 0x0, 0x0, 0x0, 0x0, 0x4200a3, 0x420042, 0x420042, 0x420042, 0xc3, 0x420042, 0x0, 0xc40000, 0x420042, 0x420042, 0x420042, 0x420042, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbe0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbe0000, 0x0, 0x0, 0x0, 0x83000000, 0x280f, 0x4, 0x0, 0x1ff00, 0x1800000, 0x1, 0x17900, 0x0, 0xff00, 0xffe0f800, 0x20000020, 0x0, 0x4000, 0x0, 0x1800, 0x0, 0x0, 0xfffc0000, 0x0, 0xf8000000, 0x0, 0x8000c000, 0xb0000000, 0xffffffff, 0xffffffff, 0xffffe002, 0xffffffff, 0x8000000f, 0x0, 0x1000000, 0x66011, 0xc3a0200, 0x4f7f8660, 0xf0000030, 0x67811, 0x2c920200, 0xa1fdc678, 0xffc0003f, 0x44011, 0xc120200, 0xfffec440, 0xfffc0030, 0x66011, 0xc120200, 0x4f3fc660, 0xff000030, 0x29c23813, 0x3c0038e7, 0xff7ec238, 0xf800003f, 0x22011, 0x1c100200, 0xfc9fc220, 0xff0030, 0x22013, 0xc100200, 0xbf9fc220, 0xfff90030, 0x22013, 0x18000000, 0xff7f8220, 0x1c00030, 0x3800013, 0xd0040000, 0xa07b80, 0xffe3ffff, 0x1, 0x78000000, 0xf0000000, 0xffffffff, 0x10fda69, 0xc4001351, 0xc00c0a0, 0xffffffff, 0x100, 0x1e000, 0x1000000, 0x20000000, 0xf8002000, 0xffffffff, 0xdf40, 0x0, 0xc280c200, 0x0, 0xc200, 0x80c20000, 0x8000c2, 0x0, 0xc20000, 0x0, 0x18000000, 0xe0000000, 0xfc000000, 0x0, 0x0, 0xffe00000, 0xe0000000, 0x0, 0x0, 0xfffe0000, 0xffe02000, 0xff800000, 0xfff00000, 0xfff22000, 0xc0000000, 0xfc00fc00, 0xfc008000, 0x0, 0x0, 0xff000000, 0x0, 0xf800, 0x0, 0xffc00000, 0xe0000000, 0xf000f000, 0xe, 0xffe0c000, 0x0, 0xf000, 0x3800fc00, 0x0, 0x30000000, 0x0, 0x80000000, 0x60000000, 0xfc00fc00, 0xffffc000, 0xffffffff, 0xffffffff, 0xf000, 0xe0000000, 0x0, 0xff00000, 0x0, 0x7000000, 0x1c00, 0x0, 0xff00, 0xff800000, 0x0, 0xfffff80, 0xc0c00000, 0x0, 0x5500c0c0, 0xc0000000, 0x0, 0x200000, 0x10300020, 0x80230000, 0x0, 0xc0020, 0xe0008000, 0xf8000000, 0xffff, 0xfffe0000, 0xfc00, 0x0, 0x0, 0xfff00000, 0x0, 0xffffff80, 0xfffff800, 0x0, 0x1, 0x0, 0xfc00e000, 0xffffffff, 0x0, 0x8000, 0x80000000, 0x0, 0x0, 0x1f00000, 0x0, 0xdf40, 0x0, 0x7ffe7f00, 0xff800000, 0x80808080, 0x80808080, 0x0, 0x0, 0xf0000000, 0x4000000, 0x0, 0xffc00000, 0xf000ffff, 0x1800000, 0x0, 0x1f, 0x1c000, 0x8000, 0xf8000000, 0x0, 0xfff0, 0x0, 0x80000000, 0xffffe000, 0xffffffff, 0xe000, 0x0, 0xff80, 0x0, 0x0, 0xfffff000, 0x7f000000, 0x0, 0xfff08000, 0xfffff800, 0xffffffff, 0xffffff, 0x0, 0xfc00f000, 0xfc003fe0, 0xf0000000, 0x7ff00000, 0xe0000000, 0x3c004000, 0xffffffff, 0x0, 0xff800000, 0xc00c000, 0xf0000000, 0x7fffff8, 0xff800000, 0xff818181, 0xffff8080, 0x0, 0xfc00c000, 0x780, 0xf0000000, 0x0, 0xc000, 0xfc000000, 0xffffffff, 0x1f07ff80, 0xa0800000, 0x24, 0x0, 0x7fffc, 0x0, 0xffff, 0x0, 0x30000, 0x0, 0xffffff00, 0xc000ffff, 0xfc000000, 0xff80, 0x80000, 0x20f080, 0x0, 0x60000000, 0xe3030303, 0xc1ff8080, 0x1000, 0x48000080, 0xc000c000, 0xffffffff, 0x78, 0x700000, 0xf000f800, 0xffffffff, 0xffff, 0xc0000000, 0xfffe0000, 0xffffffff, 0x80000000, 0xfff0, 0xfffff800, 0xffffffff, 0x40000000, 0x0, 0xffc000f0, 0xffffffff, 0xc0000000, 0xfffffc00, 0x2c0, 0x6e400000, 0x400000, 0xffffffff, 0x70000000, 0x7c000000, 0x0, 0x3f000000, 0x1100f90, 0x78f00000, 0xfe00ff00, 0x0, 0x0, 0x1c00000, 0xc00000, 0xf80000, 0xfffffe00, 0xffffffff, 0xffffffff, 0x80000000, 0x3c000, 0xffff0000, 0xfffc, 0xfc00fe00, 0xfffffff0, 0xffffffff, 0xfc00fe00, 0xffffffff, 0xfffffc00, 0xffffffff, 0x0, 0xffff8000, 0x0, 0xfff0fff8, 0x0, 0xfe000000, 0xffe0, 0x80000000, 0x7fff, 0xffffffff, 0xfffffffc, 0xffffffff, 0x0, 0x180, 0xc0000000, 0xffffffff, 0xffffffc0, 0xffffffff, 0xff800000, 0xfffc0000, 0x200000, 0x0, 0x20000000, 0x1400219b, 0x10, 0x0, 0x20201840, 0x84000000, 0x203a0, 0x0, 0x0, 0xc0, 0x3000, 0x0, 0x10, 0xf5080169, 0x5569157b, 0xa1080869, 0xf0000400, 0xf0000411, 0xffffffff, 0xfffcffff, 0xfff00000, 0x80018000, 0x10001, 0xffffffff, 0xf800, 0x8000, 0xf8000000, 0xffffffff, 0xffffffff, 0x3f, 0xfff8, 0xf8000000, 0xfffcfe00, 0xffffffff, 0x0, 0x40fffe, 0x0, 0xe0000000, 0xfff00000, 0x0, 0xfffff820, 0xfffe0000, 0x2, 0x0, 0x0, 0xe1000000, 0x0, 0xc0000000, 0xfff0, 0xffffff00, 0xffffffff, 0x7ffffff, 0xffff001e, 0xffffffff, 0xff800000, 0xffffffff, 0xfffffffd, 0x0, 0x0, 0xffff0000, 0x0, 0xc0000000]); enum MAX_SIMPLE_LOWER = 1043; enum MAX_SIMPLE_UPPER = 1051; enum MAX_SIMPLE_TITLE = 1055; //8192 bytes enum toUpperIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x40, 0x200], [ 0x100, 0x380, 0xc00], [ 0x2020100, 0x4020302, 0x2020205, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xa, 0xb0000, 0xd000c, 0xf000e, 0x110010, 0x130012, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150000, 0x0, 0x170016, 0x190018, 0x1b001a, 0x1d001c, 0x0, 0x0, 0x1e0000, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x220021, 0x240023, 0x25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x260000, 0x27, 0x290028, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e002d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x20001, 0x40003, 0x60005, 0x80007, 0xa0009, 0xc000b, 0xe000d, 0x10000f, 0x120011, 0x140013, 0x160015, 0x180017, 0xffff0019, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1affff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x41bffff, 0x1c001b, 0x1e001d, 0x20001f, 0x220021, 0x240023, 0x260025, 0x280027, 0x2a0029, 0x2c002b, 0x2e002d, 0x30002f, 0xffff0031, 0x330032, 0x350034, 0x370036, 0x390038, 0x3affff, 0x3bffff, 0x3cffff, 0x3dffff, 0x3effff, 0x3fffff, 0x40ffff, 0x41ffff, 0x42ffff, 0x43ffff, 0x44ffff, 0x45ffff, 0x46ffff, 0x47ffff, 0x48ffff, 0x49ffff, 0x4affff, 0x4bffff, 0x4cffff, 0x4dffff, 0x4effff, 0x4fffff, 0x50ffff, 0x51ffff, 0x52041d, 0x53ffff, 0x54ffff, 0x55ffff, 0xffffffff, 0xffff0056, 0xffff0057, 0xffff0058, 0xffff0059, 0xffff005a, 0xffff005b, 0xffff005c, 0x43a005d, 0x5effff, 0x5fffff, 0x60ffff, 0x61ffff, 0x62ffff, 0x63ffff, 0x64ffff, 0x65ffff, 0x66ffff, 0x67ffff, 0x68ffff, 0x69ffff, 0x6affff, 0x6bffff, 0x6cffff, 0x6dffff, 0x6effff, 0x6fffff, 0x70ffff, 0x71ffff, 0x72ffff, 0x73ffff, 0x74ffff, 0xffffffff, 0xffff0075, 0xffff0076, 0x780077, 0xffff0079, 0x7affff, 0x7bffff, 0xffffffff, 0xffff007c, 0xffffffff, 0xffff007d, 0xffffffff, 0xffffffff, 0xffff007e, 0x7fffff, 0xffffffff, 0x80ffff, 0xffff0081, 0xffffffff, 0xffff0082, 0x83ffff, 0x84ffff, 0x85ffff, 0xffffffff, 0xffff0086, 0xffffffff, 0x87ffff, 0xffffffff, 0xffff0088, 0xffffffff, 0xffff0089, 0xffff008a, 0x8bffff, 0xffffffff, 0x8cffff, 0x8dffff, 0xffffffff, 0xffffffff, 0x8effff, 0xffff008f, 0x910090, 0x92ffff, 0xffff0093, 0xffff0094, 0xffff0095, 0xffff0096, 0xffff0097, 0xffff0098, 0xffff0099, 0xffff009a, 0x9c009b, 0x9dffff, 0x9effff, 0x9fffff, 0xa0ffff, 0xa1ffff, 0xa2ffff, 0xa3ffff, 0xa4ffff, 0xa5ffff, 0xffff0442, 0xa700a6, 0xa8ffff, 0xffffffff, 0xa9ffff, 0xaaffff, 0xabffff, 0xacffff, 0xadffff, 0xaeffff, 0xafffff, 0xb0ffff, 0xb1ffff, 0xb2ffff, 0xb3ffff, 0xb4ffff, 0xb5ffff, 0xb6ffff, 0xb7ffff, 0xb8ffff, 0xb9ffff, 0xbaffff, 0xbbffff, 0xbcffff, 0xffffffff, 0xbdffff, 0xbeffff, 0xbfffff, 0xc0ffff, 0xc1ffff, 0xc2ffff, 0xc3ffff, 0xc4ffff, 0xc5ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff00c6, 0xc7ffff, 0xffff00c8, 0xffff00c9, 0xffffffff, 0xcaffff, 0xcbffff, 0xccffff, 0xcdffff, 0xceffff, 0xd000cf, 0xd200d1, 0xffff00d3, 0xd500d4, 0xd6ffff, 0xd7ffff, 0xffffffff, 0xffffffff, 0xffff00d8, 0xd9ffff, 0xdaffff, 0xffff00db, 0xdd00dc, 0xdeffff, 0xffffffff, 0xdfffff, 0xe0ffff, 0xffff00e1, 0xe2ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe3ffff, 0xffffffff, 0xffff00e4, 0xe5ffff, 0xffffffff, 0xffffffff, 0xe700e6, 0xe900e8, 0xffff00ea, 0xffffffff, 0xffffffff, 0xffff00eb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xecffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xedffff, 0xeeffff, 0xffffffff, 0xefffff, 0xffffffff, 0xf0ffff, 0xf200f1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff043c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf400f3, 0xf600f5, 0xf7043f, 0xf900f8, 0xfb00fa, 0xfd00fc, 0xff00fe, 0x1010100, 0x1030102, 0x1050104, 0x1070106, 0x1090108, 0x10b010a, 0x10d010c, 0x10f010e, 0x1110110, 0x1130112, 0xffff0114, 0x1160115, 0xffffffff, 0x117ffff, 0x1190118, 0x11affff, 0x11bffff, 0x11cffff, 0x11dffff, 0x11effff, 0x11fffff, 0x120ffff, 0x121ffff, 0x122ffff, 0x123ffff, 0x124ffff, 0x125ffff, 0x1270126, 0xffff0128, 0x129ffff, 0xffffffff, 0xffff012a, 0x12bffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x12d012c, 0x12f012e, 0x1310130, 0x1330132, 0x1350134, 0x1370136, 0x1390138, 0x13b013a, 0x13d013c, 0x13f013e, 0x1410140, 0x1430142, 0x1450144, 0x1470146, 0x1490148, 0x14b014a, 0x14d014c, 0x14f014e, 0x1510150, 0x1530152, 0x1550154, 0x1570156, 0x1590158, 0x15b015a, 0x15cffff, 0x15dffff, 0x15effff, 0x15fffff, 0x160ffff, 0x161ffff, 0x162ffff, 0x163ffff, 0x164ffff, 0x165ffff, 0x166ffff, 0x167ffff, 0x168ffff, 0x169ffff, 0x16affff, 0x16bffff, 0x16cffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x16dffff, 0x16effff, 0x16fffff, 0x170ffff, 0x171ffff, 0x172ffff, 0x173ffff, 0x174ffff, 0x175ffff, 0x176ffff, 0x177ffff, 0x178ffff, 0x179ffff, 0x17affff, 0x17bffff, 0x17cffff, 0x17dffff, 0x17effff, 0x17fffff, 0x180ffff, 0x181ffff, 0x182ffff, 0x183ffff, 0x184ffff, 0x185ffff, 0x186ffff, 0x187ffff, 0xffffffff, 0xffff0188, 0xffff0189, 0xffff018a, 0xffff018b, 0xffff018c, 0xffff018d, 0x18f018e, 0x190ffff, 0x191ffff, 0x192ffff, 0x193ffff, 0x194ffff, 0x195ffff, 0x196ffff, 0x197ffff, 0x198ffff, 0x199ffff, 0x19affff, 0x19bffff, 0x19cffff, 0x19dffff, 0x19effff, 0x19fffff, 0x1a0ffff, 0x1a1ffff, 0x1a2ffff, 0x1a3ffff, 0x1a4ffff, 0x1a5ffff, 0x1a6ffff, 0x1a7ffff, 0x1a8ffff, 0x1a9ffff, 0x1aaffff, 0x1abffff, 0x1acffff, 0x1adffff, 0x1aeffff, 0x1afffff, 0x1b0ffff, 0x1b1ffff, 0x1b2ffff, 0x1b3ffff, 0x1b4ffff, 0x1b5ffff, 0x1b6ffff, 0x1b7ffff, 0x1b8ffff, 0x1b9ffff, 0x1baffff, 0x1bbffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1bcffff, 0x1be01bd, 0x1c001bf, 0x1c201c1, 0x1c401c3, 0x1c601c5, 0x1c801c7, 0x1ca01c9, 0x1cc01cb, 0x1ce01cd, 0x1d001cf, 0x1d201d1, 0x1d401d3, 0x1d601d5, 0x1d801d7, 0x1da01d9, 0x1dc01db, 0x1de01dd, 0x1e001df, 0x42e01e1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1e2ffff, 0xffffffff, 0x1e3ffff, 0xffffffff, 0x1e4ffff, 0x1e5ffff, 0x1e6ffff, 0x1e7ffff, 0x1e8ffff, 0x1e9ffff, 0x1eaffff, 0x1ebffff, 0x1ecffff, 0x1edffff, 0x1eeffff, 0x1efffff, 0x1f0ffff, 0x1f1ffff, 0x1f2ffff, 0x1f3ffff, 0x1f4ffff, 0x1f5ffff, 0x1f6ffff, 0x1f7ffff, 0x1f8ffff, 0x1f9ffff, 0x1faffff, 0x1fbffff, 0x1fcffff, 0x1fdffff, 0x1feffff, 0x1ffffff, 0x200ffff, 0x201ffff, 0x202ffff, 0x203ffff, 0x204ffff, 0x205ffff, 0x206ffff, 0x207ffff, 0x208ffff, 0x209ffff, 0x20affff, 0x20bffff, 0x20cffff, 0x20dffff, 0x20effff, 0x20fffff, 0x210ffff, 0x211ffff, 0x212ffff, 0x213ffff, 0x214ffff, 0x215ffff, 0x216ffff, 0x217ffff, 0x218ffff, 0x219ffff, 0x21affff, 0x21bffff, 0x21cffff, 0x21dffff, 0x21effff, 0x21fffff, 0x220ffff, 0x221ffff, 0x222ffff, 0x223ffff, 0x224ffff, 0x225ffff, 0x226ffff, 0x227ffff, 0x228ffff, 0x229ffff, 0x22affff, 0x22bffff, 0x22cffff, 0x22dffff, 0x22effff, 0x4460444, 0x44a0448, 0x22f044c, 0xffffffff, 0xffffffff, 0x230ffff, 0x231ffff, 0x232ffff, 0x233ffff, 0x234ffff, 0x235ffff, 0x236ffff, 0x237ffff, 0x238ffff, 0x239ffff, 0x23affff, 0x23bffff, 0x23cffff, 0x23dffff, 0x23effff, 0x23fffff, 0x240ffff, 0x241ffff, 0x242ffff, 0x243ffff, 0x244ffff, 0x245ffff, 0x246ffff, 0x247ffff, 0x248ffff, 0x249ffff, 0x24affff, 0x24bffff, 0x24cffff, 0x24dffff, 0x24effff, 0x24fffff, 0x250ffff, 0x251ffff, 0x252ffff, 0x253ffff, 0x254ffff, 0x255ffff, 0x256ffff, 0x257ffff, 0x258ffff, 0x259ffff, 0x25affff, 0x25bffff, 0x25cffff, 0x25dffff, 0x25effff, 0x25fffff, 0x2610260, 0x2630262, 0x2650264, 0x2670266, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2690268, 0x26b026a, 0x26d026c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x26f026e, 0x2710270, 0x2730272, 0x2750274, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2770276, 0x2790278, 0x27b027a, 0x27d027c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x27f027e, 0x2810280, 0x2830282, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x284044e, 0x2850450, 0x2860453, 0x2870456, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2890288, 0x28b028a, 0x28d028c, 0x28f028e, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2910290, 0x2930292, 0x2950294, 0x2970296, 0x2990298, 0x29b029a, 0x29d029c, 0xffffffff, 0x4790477, 0x47d047b, 0x481047f, 0x4850483, 0x4890487, 0x48d048b, 0x491048f, 0x4950493, 0x4990497, 0x49d049b, 0x4a1049f, 0x4a504a3, 0x4a904a7, 0x4ad04ab, 0x4b104af, 0x4b504b3, 0x4b904b7, 0x4bd04bb, 0x4c104bf, 0x4c504c3, 0x4c904c7, 0x4cd04cb, 0x4d104cf, 0x4d504d3, 0x2b702b6, 0x4d704e3, 0xffff04e5, 0x4ef0459, 0xffffffff, 0xffffffff, 0xffff04d9, 0xffff02b9, 0xffffffff, 0x4db04e7, 0xffff04e9, 0x4f2045b, 0xffffffff, 0xffffffff, 0xffff04dd, 0xffffffff, 0x2bc02bb, 0x460045d, 0xffffffff, 0x4650463, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2be02bd, 0x46b0468, 0x2bf046e, 0x4720470, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x4df04eb, 0xffff04ed, 0x4f50475, 0xffffffff, 0xffffffff, 0xffff04e1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02c1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c302c2, 0x2c502c4, 0x2c702c6, 0x2c902c8, 0x2cb02ca, 0x2cd02cc, 0x2cf02ce, 0x2d102d0, 0xffffffff, 0xffffffff, 0xffff02d2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2d402d3, 0x2d602d5, 0x2d802d7, 0x2da02d9, 0x2dc02db, 0x2de02dd, 0x2e002df, 0x2e202e1, 0x2e402e3, 0x2e602e5, 0x2e802e7, 0x2ea02e9, 0x2ec02eb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2ee02ed, 0x2f002ef, 0x2f202f1, 0x2f402f3, 0x2f602f5, 0x2f802f7, 0x2fa02f9, 0x2fc02fb, 0x2fe02fd, 0x30002ff, 0x3020301, 0x3040303, 0x3060305, 0x3080307, 0x30a0309, 0x30c030b, 0x30e030d, 0x310030f, 0x3120311, 0x3140313, 0x3160315, 0x3180317, 0x31a0319, 0xffff031b, 0x31cffff, 0xffffffff, 0x31dffff, 0xffff031e, 0xffff031f, 0xffff0320, 0xffff0321, 0xffffffff, 0xffffffff, 0x322ffff, 0xffffffff, 0xffff0323, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x324ffff, 0x325ffff, 0x326ffff, 0x327ffff, 0x328ffff, 0x329ffff, 0x32affff, 0x32bffff, 0x32cffff, 0x32dffff, 0x32effff, 0x32fffff, 0x330ffff, 0x331ffff, 0x332ffff, 0x333ffff, 0x334ffff, 0x335ffff, 0x336ffff, 0x337ffff, 0x338ffff, 0x339ffff, 0x33affff, 0x33bffff, 0x33cffff, 0x33dffff, 0x33effff, 0x33fffff, 0x340ffff, 0x341ffff, 0x342ffff, 0x343ffff, 0x344ffff, 0x345ffff, 0x346ffff, 0x347ffff, 0x348ffff, 0x349ffff, 0x34affff, 0x34bffff, 0x34cffff, 0x34dffff, 0x34effff, 0x34fffff, 0x350ffff, 0x351ffff, 0x352ffff, 0x353ffff, 0x354ffff, 0x355ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0356, 0xffff0357, 0xffffffff, 0x358ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x35a0359, 0x35c035b, 0x35e035d, 0x360035f, 0x3620361, 0x3640363, 0x3660365, 0x3680367, 0x36a0369, 0x36c036b, 0x36e036d, 0x370036f, 0x3720371, 0x3740373, 0x3760375, 0x3780377, 0x37a0379, 0x37c037b, 0x37e037d, 0x37fffff, 0xffffffff, 0xffffffff, 0x380ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x381ffff, 0x382ffff, 0x383ffff, 0x384ffff, 0x385ffff, 0x386ffff, 0x387ffff, 0x388ffff, 0x389ffff, 0x38affff, 0x38bffff, 0x38cffff, 0x38dffff, 0x38effff, 0x38fffff, 0x390ffff, 0x391ffff, 0x392ffff, 0x393ffff, 0x394ffff, 0x395ffff, 0x396ffff, 0x397ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x398ffff, 0x399ffff, 0x39affff, 0x39bffff, 0x39cffff, 0x39dffff, 0x39effff, 0x39fffff, 0x3a0ffff, 0x3a1ffff, 0x3a2ffff, 0x3a3ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3a4ffff, 0x3a5ffff, 0x3a6ffff, 0x3a7ffff, 0x3a8ffff, 0x3a9ffff, 0x3aaffff, 0xffffffff, 0x3abffff, 0x3acffff, 0x3adffff, 0x3aeffff, 0x3afffff, 0x3b0ffff, 0x3b1ffff, 0x3b2ffff, 0x3b3ffff, 0x3b4ffff, 0x3b5ffff, 0x3b6ffff, 0x3b7ffff, 0x3b8ffff, 0x3b9ffff, 0x3baffff, 0x3bbffff, 0x3bcffff, 0x3bdffff, 0x3beffff, 0x3bfffff, 0x3c0ffff, 0x3c1ffff, 0x3c2ffff, 0x3c3ffff, 0x3c4ffff, 0x3c5ffff, 0x3c6ffff, 0x3c7ffff, 0x3c8ffff, 0x3c9ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff03ca, 0xffff03cb, 0x3ccffff, 0x3cdffff, 0x3ceffff, 0x3cfffff, 0x3d0ffff, 0xffffffff, 0xffffffff, 0xffff03d1, 0xffffffff, 0x3d2ffff, 0x3d3ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3d4ffff, 0x3d5ffff, 0x3d6ffff, 0x3d7ffff, 0x3d8ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x420041e, 0x4240422, 0x42a0427, 0xffff042c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x430ffff, 0x4340432, 0x4380436, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3d9ffff, 0x3db03da, 0x3dd03dc, 0x3df03de, 0x3e103e0, 0x3e303e2, 0x3e503e4, 0x3e703e6, 0x3e903e8, 0x3eb03ea, 0x3ed03ec, 0x3ef03ee, 0x3f103f0, 0xffff03f2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3f403f3, 0x3f603f5, 0x3f803f7, 0x3fa03f9, 0x3fc03fb, 0x3fe03fd, 0x40003ff, 0x4020401, 0x4040403, 0x4060405, 0x4080407, 0x40a0409, 0x40c040b, 0x40e040d, 0x410040f, 0x4120411, 0x4140413, 0x4160415, 0x4180417, 0x41a0419, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); //8064 bytes enum toLowerIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x40, 0x200], [ 0x100, 0x380, 0xbc0], [ 0x2020100, 0x4020302, 0x2020205, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x10000, 0x20000, 0x40003, 0x60005, 0x80007, 0x0, 0x90000, 0xb000a, 0xd000c, 0xf000e, 0x110010, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x140013, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x160015, 0x180017, 0x1a0019, 0x1c001b, 0x0, 0x0, 0x1e001d, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x210020, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x230022, 0x250024, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x260000, 0x27, 0x290028, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x20001, 0x40003, 0x60005, 0x80007, 0xa0009, 0xc000b, 0xe000d, 0x10000f, 0x120011, 0x140013, 0x160015, 0x180017, 0xffff0019, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1b001a, 0x1d001c, 0x1f001e, 0x210020, 0x230022, 0x250024, 0x270026, 0x290028, 0x2b002a, 0x2d002c, 0x2f002e, 0xffff0030, 0x320031, 0x340033, 0x360035, 0x4130037, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0038, 0xffff0039, 0xffff003a, 0xffff003b, 0xffff003c, 0xffff003d, 0xffff003e, 0xffff003f, 0xffff0040, 0xffff0041, 0xffff0042, 0xffff0043, 0xffff0044, 0xffff0045, 0xffff0046, 0xffff0047, 0xffff0048, 0xffff0049, 0xffff004a, 0xffff004b, 0xffff004c, 0xffff004d, 0xffff004e, 0xffff004f, 0xffff0414, 0xffff0051, 0xffff0052, 0xffff0053, 0x54ffff, 0x55ffff, 0x56ffff, 0x57ffff, 0x58ffff, 0x59ffff, 0x5affff, 0x5bffff, 0x423ffff, 0xffff005c, 0xffff005d, 0xffff005e, 0xffff005f, 0xffff0060, 0xffff0061, 0xffff0062, 0xffff0063, 0xffff0064, 0xffff0065, 0xffff0066, 0xffff0067, 0xffff0068, 0xffff0069, 0xffff006a, 0xffff006b, 0xffff006c, 0xffff006d, 0xffff006e, 0xffff006f, 0xffff0070, 0xffff0071, 0xffff0072, 0x740073, 0x75ffff, 0x76ffff, 0xffffffff, 0x77ffff, 0xffff0078, 0xffff0079, 0x7b007a, 0x7cffff, 0x7e007d, 0xffffffff, 0x80007f, 0x820081, 0x83ffff, 0xffff0084, 0x860085, 0xffff0087, 0xffffffff, 0x890088, 0x8affff, 0xffff008b, 0xffff008c, 0xffff008d, 0x8f008e, 0x90ffff, 0xffffffff, 0xffff0091, 0x930092, 0x94ffff, 0x960095, 0x97ffff, 0x98ffff, 0xffff0099, 0xffffffff, 0xffff009a, 0xffffffff, 0xffffffff, 0xffffffff, 0x9c009b, 0x9dffff, 0xffff009e, 0xa0009f, 0xa1ffff, 0xa2ffff, 0xa3ffff, 0xa4ffff, 0xa5ffff, 0xa6ffff, 0xa7ffff, 0xa8ffff, 0xffffffff, 0xffff00a9, 0xffff00aa, 0xffff00ab, 0xffff00ac, 0xffff00ad, 0xffff00ae, 0xffff00af, 0xffff00b0, 0xffff00b1, 0xb20426, 0xffff00b3, 0xffff00b4, 0xb600b5, 0xffff00b7, 0xffff00b8, 0xffff00b9, 0xffff00ba, 0xffff00bb, 0xffff00bc, 0xffff00bd, 0xffff00be, 0xffff00bf, 0xffff00c0, 0xffff00c1, 0xffff00c2, 0xffff00c3, 0xffff00c4, 0xffff00c5, 0xffff00c6, 0xffff00c7, 0xffff00c8, 0xffff00c9, 0xffff00ca, 0xffff00cb, 0xffff00cc, 0xffff00cd, 0xffff00ce, 0xffff00cf, 0xffff00d0, 0xffff00d1, 0xffff00d2, 0xffff00d3, 0xffff00d4, 0xffffffff, 0xffffffff, 0xffffffff, 0xd600d5, 0xd7ffff, 0xffff00d8, 0xd9ffff, 0xdaffff, 0xdc00db, 0xffff00dd, 0xffff00de, 0xffff00df, 0xffff00e0, 0xffff00e1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff00e2, 0xffff00e3, 0xffffffff, 0xffff00e4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff00e5, 0xe700e6, 0xffff00e8, 0xffff00e9, 0xeb00ea, 0xec0424, 0xee00ed, 0xf000ef, 0xf200f1, 0xf400f3, 0xf600f5, 0xf800f7, 0xfa00f9, 0xfc00fb, 0xfdffff, 0xff00fe, 0x1010100, 0x1030102, 0x1050104, 0xffffffff, 0xffffffff, 0xffff0425, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x106ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0107, 0xffff0108, 0xffff0109, 0xffff010a, 0xffff010b, 0xffff010c, 0xffff010d, 0xffff010e, 0xffff010f, 0xffff0110, 0xffff0111, 0xffff0112, 0xffffffff, 0xffffffff, 0xffff0113, 0x114ffff, 0x115ffff, 0xffff0116, 0x117ffff, 0x1190118, 0x11b011a, 0x11d011c, 0x11f011e, 0x1210120, 0x1230122, 0x1250124, 0x1270126, 0x1290128, 0x12b012a, 0x12d012c, 0x12f012e, 0x1310130, 0x1330132, 0x1350134, 0x1370136, 0x1390138, 0x13b013a, 0x13d013c, 0x13f013e, 0x1410140, 0x1430142, 0x1450144, 0x1470146, 0x1490148, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff014a, 0xffff014b, 0xffff014c, 0xffff014d, 0xffff014e, 0xffff014f, 0xffff0150, 0xffff0151, 0xffff0152, 0xffff0153, 0xffff0154, 0xffff0155, 0xffff0156, 0xffff0157, 0xffff0158, 0xffff0159, 0xffff015a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff015b, 0xffff015c, 0xffff015d, 0xffff015e, 0xffff015f, 0xffff0160, 0xffff0161, 0xffff0162, 0xffff0163, 0xffff0164, 0xffff0165, 0xffff0166, 0xffff0167, 0xffff0168, 0xffff0169, 0xffff016a, 0xffff016b, 0xffff016c, 0xffff016d, 0xffff016e, 0xffff016f, 0xffff0170, 0xffff0171, 0xffff0172, 0xffff0173, 0xffff0174, 0xffff0175, 0x1770176, 0x178ffff, 0x179ffff, 0x17affff, 0x17bffff, 0x17cffff, 0x17dffff, 0xffffffff, 0xffff017e, 0xffff017f, 0xffff0180, 0xffff0181, 0xffff0182, 0xffff0183, 0xffff0184, 0xffff0185, 0xffff0186, 0xffff0187, 0xffff0188, 0xffff0189, 0xffff018a, 0xffff018b, 0xffff018c, 0xffff018d, 0xffff018e, 0xffff018f, 0xffff0190, 0xffff0191, 0xffff0192, 0xffff0193, 0xffff0194, 0xffff0195, 0xffff0196, 0xffff0197, 0xffff0198, 0xffff0199, 0xffff019a, 0xffff019b, 0xffff019c, 0xffff019d, 0xffff019e, 0xffff019f, 0xffff01a0, 0xffff01a1, 0xffff01a2, 0xffff01a3, 0xffff01a4, 0xffff01a5, 0xffff01a6, 0xffff01a7, 0xffff01a8, 0xffff01a9, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1aaffff, 0x1ac01ab, 0x1ae01ad, 0x1b001af, 0x1b201b1, 0x1b401b3, 0x1b601b5, 0x1b801b7, 0x1ba01b9, 0x1bc01bb, 0x1be01bd, 0x1c001bf, 0x1c201c1, 0x1c401c3, 0x1c601c5, 0x1c801c7, 0x1ca01c9, 0x1cc01cb, 0x1ce01cd, 0xffff01cf, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x41dffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1d101d0, 0x1d301d2, 0x1d501d4, 0x1d701d6, 0x1d901d8, 0x1db01da, 0x1dd01dc, 0x1df01de, 0x1e101e0, 0x1e301e2, 0x1e501e4, 0x1e701e6, 0x1e901e8, 0x1eb01ea, 0x1ed01ec, 0x1ef01ee, 0x1f101f0, 0x1f301f2, 0x1f501f4, 0x1f6ffff, 0xffffffff, 0xffffffff, 0x1f7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff01f8, 0xffff01f9, 0xffff01fa, 0xffff01fb, 0xffff01fc, 0xffff01fd, 0xffff01fe, 0xffff01ff, 0xffff0200, 0xffff0201, 0xffff0202, 0xffff0203, 0xffff0204, 0xffff0205, 0xffff0206, 0xffff0207, 0xffff0208, 0xffff0209, 0xffff020a, 0xffff020b, 0xffff020c, 0xffff020d, 0xffff020e, 0xffff020f, 0xffff0210, 0xffff0211, 0xffff0212, 0xffff0213, 0xffff0214, 0xffff0215, 0xffff0216, 0xffff0217, 0xffff0218, 0xffff0219, 0xffff021a, 0xffff021b, 0xffff021c, 0xffff021d, 0xffff021e, 0xffff021f, 0xffff0220, 0xffff0221, 0xffff0222, 0xffff0223, 0xffff0224, 0xffff0225, 0xffff0226, 0xffff0227, 0xffff0228, 0xffff0229, 0xffff022a, 0xffff022b, 0xffff022c, 0xffff022d, 0xffff022e, 0xffff022f, 0xffff0230, 0xffff0231, 0xffff0232, 0xffff0233, 0xffff0234, 0xffff0235, 0xffff0236, 0xffff0237, 0xffff0238, 0xffff0239, 0xffff023a, 0xffff023b, 0xffff023c, 0xffff023d, 0xffff023e, 0xffff023f, 0xffff0240, 0xffff0241, 0xffff0242, 0x4280427, 0x42a0429, 0xffff042b, 0xffffffff, 0xffff0243, 0xffff0244, 0xffff0245, 0xffff0246, 0xffff0247, 0xffff0248, 0xffff0249, 0xffff024a, 0xffff024b, 0xffff024c, 0xffff024d, 0xffff024e, 0xffff024f, 0xffff0250, 0xffff0251, 0xffff0252, 0xffff0253, 0xffff0254, 0xffff0255, 0xffff0256, 0xffff0257, 0xffff0258, 0xffff0259, 0xffff025a, 0xffff025b, 0xffff025c, 0xffff025d, 0xffff025e, 0xffff025f, 0xffff0260, 0xffff0261, 0xffff0262, 0xffff0263, 0xffff0264, 0xffff0265, 0xffff0266, 0xffff0267, 0xffff0268, 0xffff0269, 0xffff026a, 0xffff026b, 0xffff026c, 0xffff026d, 0xffff026e, 0xffff026f, 0xffff0270, 0xffff0271, 0xffff0272, 0xffff0273, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2750274, 0x2770276, 0x2790278, 0x27b027a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x27d027c, 0x27f027e, 0x2810280, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2830282, 0x2850284, 0x2870286, 0x2890288, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x28b028a, 0x28d028c, 0x28f028e, 0x2910290, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2930292, 0x2950294, 0x2970296, 0xffffffff, 0xffff042c, 0xffff042d, 0xffff042e, 0xffff042f, 0x298ffff, 0x299ffff, 0x29affff, 0x29bffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x29d029c, 0x29f029e, 0x2a102a0, 0x2a302a2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x43d043c, 0x43f043e, 0x4410440, 0x4430442, 0x4450444, 0x4470446, 0x4490448, 0x44b044a, 0x44d044c, 0x44f044e, 0x4510450, 0x4530452, 0x4550454, 0x4570456, 0x4590458, 0x45b045a, 0x45d045c, 0x45f045e, 0x4610460, 0x4630462, 0x4650464, 0x4670466, 0x4690468, 0x46b046a, 0xffffffff, 0x46c0472, 0xffff0473, 0x4780430, 0x2bd02bc, 0x2bf02be, 0xffff046d, 0xffffffff, 0xffffffff, 0x46e0474, 0xffff0475, 0x4790431, 0x2c202c1, 0x2c402c3, 0xffff046f, 0xffffffff, 0xffffffff, 0x4330432, 0xffffffff, 0x4350434, 0x2c702c6, 0x2c902c8, 0xffffffff, 0xffffffff, 0xffffffff, 0x4370436, 0xffff0438, 0x43a0439, 0x2cb02ca, 0x2cd02cc, 0xffff02ce, 0xffffffff, 0xffffffff, 0x4700476, 0xffff0477, 0x47a043b, 0x2d002cf, 0x2d202d1, 0xffff0471, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02d4, 0xffffffff, 0x2d602d5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02d7, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2d902d8, 0x2db02da, 0x2dd02dc, 0x2df02de, 0x2e102e0, 0x2e302e2, 0x2e502e4, 0x2e702e6, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2e8ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2ea02e9, 0x2ec02eb, 0x2ee02ed, 0x2f002ef, 0x2f202f1, 0x2f402f3, 0x2f602f5, 0x2f802f7, 0x2fa02f9, 0x2fc02fb, 0x2fe02fd, 0x30002ff, 0x3020301, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3040303, 0x3060305, 0x3080307, 0x30a0309, 0x30c030b, 0x30e030d, 0x310030f, 0x3120311, 0x3140313, 0x3160315, 0x3180317, 0x31a0319, 0x31c031b, 0x31e031d, 0x320031f, 0x3220321, 0x3240323, 0x3260325, 0x3280327, 0x32a0329, 0x32c032b, 0x32e032d, 0x330032f, 0xffff0331, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0332, 0x3340333, 0xffff0335, 0x336ffff, 0x337ffff, 0x338ffff, 0x339ffff, 0x33b033a, 0xffff033c, 0xffff033d, 0x33effff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x340033f, 0xffff0341, 0xffff0342, 0xffff0343, 0xffff0344, 0xffff0345, 0xffff0346, 0xffff0347, 0xffff0348, 0xffff0349, 0xffff034a, 0xffff034b, 0xffff034c, 0xffff034d, 0xffff034e, 0xffff034f, 0xffff0350, 0xffff0351, 0xffff0352, 0xffff0353, 0xffff0354, 0xffff0355, 0xffff0356, 0xffff0357, 0xffff0358, 0xffff0359, 0xffff035a, 0xffff035b, 0xffff035c, 0xffff035d, 0xffff035e, 0xffff035f, 0xffff0360, 0xffff0361, 0xffff0362, 0xffff0363, 0xffff0364, 0xffff0365, 0xffff0366, 0xffff0367, 0xffff0368, 0xffff0369, 0xffff036a, 0xffff036b, 0xffff036c, 0xffff036d, 0xffff036e, 0xffff036f, 0xffff0370, 0xffff0371, 0xffff0372, 0xffffffff, 0xffffffff, 0xffffffff, 0x373ffff, 0x374ffff, 0xffffffff, 0xffffffff, 0xffff0375, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0376, 0xffff0377, 0xffff0378, 0xffff0379, 0xffff037a, 0xffff037b, 0xffff037c, 0xffff037d, 0xffff037e, 0xffff037f, 0xffff0380, 0xffff0381, 0xffff0382, 0xffff0383, 0xffff0384, 0xffff0385, 0xffff0386, 0xffff0387, 0xffff0388, 0xffff0389, 0xffff038a, 0xffff038b, 0xffff038c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff038d, 0xffff038e, 0xffff038f, 0xffff0390, 0xffff0391, 0xffff0392, 0xffff0393, 0xffff0394, 0xffff0395, 0xffff0396, 0xffff0397, 0xffff0398, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0399, 0xffff039a, 0xffff039b, 0xffff039c, 0xffff039d, 0xffff039e, 0xffff039f, 0xffffffff, 0xffff03a0, 0xffff03a1, 0xffff03a2, 0xffff03a3, 0xffff03a4, 0xffff03a5, 0xffff03a6, 0xffff03a7, 0xffff03a8, 0xffff03a9, 0xffff03aa, 0xffff03ab, 0xffff03ac, 0xffff03ad, 0xffff03ae, 0xffff03af, 0xffff03b0, 0xffff03b1, 0xffff03b2, 0xffff03b3, 0xffff03b4, 0xffff03b5, 0xffff03b6, 0xffff03b7, 0xffff03b8, 0xffff03b9, 0xffff03ba, 0xffff03bb, 0xffff03bc, 0xffff03bd, 0xffff03be, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3bfffff, 0x3c0ffff, 0x3c1ffff, 0xffff03c2, 0xffff03c3, 0xffff03c4, 0xffff03c5, 0xffff03c6, 0xffffffff, 0x3c7ffff, 0x3c8ffff, 0xffffffff, 0xffff03c9, 0xffff03ca, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff03cb, 0xffff03cc, 0xffff03cd, 0xffff03ce, 0xffff03cf, 0xffff03d0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x4170416, 0x4190418, 0x41b041a, 0xffff041c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x41effff, 0x420041f, 0x4220421, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3d1ffff, 0x3d303d2, 0x3d503d4, 0x3d703d6, 0x3d903d8, 0x3db03da, 0x3dd03dc, 0x3df03de, 0x3e103e0, 0x3e303e2, 0x3e503e4, 0x3e703e6, 0x3e903e8, 0xffff03ea, 0xffffffff, 0xffffffff, 0x3ec03eb, 0x3ee03ed, 0x3f003ef, 0x3f203f1, 0x3f403f3, 0x3f603f5, 0x3f803f7, 0x3fa03f9, 0x3fc03fb, 0x3fe03fd, 0x40003ff, 0x4020401, 0x4040403, 0x4060405, 0x4080407, 0x40a0409, 0x40c040b, 0x40e040d, 0x410040f, 0x4120411, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); //8192 bytes enum toTitleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x40, 0x200], [ 0x100, 0x380, 0xc00], [ 0x2020100, 0x4020302, 0x2020205, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xa, 0xb0000, 0xd000c, 0xf000e, 0x110010, 0x130012, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150000, 0x0, 0x170016, 0x190018, 0x1b001a, 0x1d001c, 0x0, 0x0, 0x1e0000, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x220021, 0x240023, 0x25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x260000, 0x27, 0x290028, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e002d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x20001, 0x40003, 0x60005, 0x80007, 0xa0009, 0xc000b, 0xe000d, 0x10000f, 0x120011, 0x140013, 0x160015, 0x180017, 0xffff0019, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1affff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x41fffff, 0x1c001b, 0x1e001d, 0x20001f, 0x220021, 0x240023, 0x260025, 0x280027, 0x2a0029, 0x2c002b, 0x2e002d, 0x30002f, 0xffff0031, 0x330032, 0x350034, 0x370036, 0x390038, 0x3affff, 0x3bffff, 0x3cffff, 0x3dffff, 0x3effff, 0x3fffff, 0x40ffff, 0x41ffff, 0x42ffff, 0x43ffff, 0x44ffff, 0x45ffff, 0x46ffff, 0x47ffff, 0x48ffff, 0x49ffff, 0x4affff, 0x4bffff, 0x4cffff, 0x4dffff, 0x4effff, 0x4fffff, 0x50ffff, 0x51ffff, 0x520421, 0x53ffff, 0x54ffff, 0x55ffff, 0xffffffff, 0xffff0056, 0xffff0057, 0xffff0058, 0xffff0059, 0xffff005a, 0xffff005b, 0xffff005c, 0x43e005d, 0x5effff, 0x5fffff, 0x60ffff, 0x61ffff, 0x62ffff, 0x63ffff, 0x64ffff, 0x65ffff, 0x66ffff, 0x67ffff, 0x68ffff, 0x69ffff, 0x6affff, 0x6bffff, 0x6cffff, 0x6dffff, 0x6effff, 0x6fffff, 0x70ffff, 0x71ffff, 0x72ffff, 0x73ffff, 0x74ffff, 0xffffffff, 0xffff0075, 0xffff0076, 0x780077, 0xffff0079, 0x7affff, 0x7bffff, 0xffffffff, 0xffff007c, 0xffffffff, 0xffff007d, 0xffffffff, 0xffffffff, 0xffff007e, 0x7fffff, 0xffffffff, 0x80ffff, 0xffff0081, 0xffffffff, 0xffff0082, 0x83ffff, 0x84ffff, 0x85ffff, 0xffffffff, 0xffff0086, 0xffffffff, 0x87ffff, 0xffffffff, 0xffff0088, 0xffffffff, 0xffff0089, 0xffff008a, 0x8bffff, 0xffffffff, 0x8cffff, 0x8dffff, 0xffffffff, 0xffffffff, 0x8f008e, 0x910090, 0x930092, 0x950094, 0xffff0096, 0xffff0097, 0xffff0098, 0xffff0099, 0xffff009a, 0xffff009b, 0xffff009c, 0xffff009d, 0x9f009e, 0xa0ffff, 0xa1ffff, 0xa2ffff, 0xa3ffff, 0xa4ffff, 0xa5ffff, 0xa6ffff, 0xa7ffff, 0xa8ffff, 0xa90446, 0xab00aa, 0xacffff, 0xffffffff, 0xadffff, 0xaeffff, 0xafffff, 0xb0ffff, 0xb1ffff, 0xb2ffff, 0xb3ffff, 0xb4ffff, 0xb5ffff, 0xb6ffff, 0xb7ffff, 0xb8ffff, 0xb9ffff, 0xbaffff, 0xbbffff, 0xbcffff, 0xbdffff, 0xbeffff, 0xbfffff, 0xc0ffff, 0xffffffff, 0xc1ffff, 0xc2ffff, 0xc3ffff, 0xc4ffff, 0xc5ffff, 0xc6ffff, 0xc7ffff, 0xc8ffff, 0xc9ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff00ca, 0xcbffff, 0xffff00cc, 0xffff00cd, 0xffffffff, 0xceffff, 0xcfffff, 0xd0ffff, 0xd1ffff, 0xd2ffff, 0xd400d3, 0xd600d5, 0xffff00d7, 0xd900d8, 0xdaffff, 0xdbffff, 0xffffffff, 0xffffffff, 0xffff00dc, 0xddffff, 0xdeffff, 0xffff00df, 0xe100e0, 0xe2ffff, 0xffffffff, 0xe3ffff, 0xe4ffff, 0xffff00e5, 0xe6ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe7ffff, 0xffffffff, 0xffff00e8, 0xe9ffff, 0xffffffff, 0xffffffff, 0xeb00ea, 0xed00ec, 0xffff00ee, 0xffffffff, 0xffffffff, 0xffff00ef, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf0ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf1ffff, 0xf2ffff, 0xffffffff, 0xf3ffff, 0xffffffff, 0xf4ffff, 0xf600f5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0440, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf800f7, 0xfa00f9, 0xfb0443, 0xfd00fc, 0xff00fe, 0x1010100, 0x1030102, 0x1050104, 0x1070106, 0x1090108, 0x10b010a, 0x10d010c, 0x10f010e, 0x1110110, 0x1130112, 0x1150114, 0x1170116, 0xffff0118, 0x11a0119, 0xffffffff, 0x11bffff, 0x11d011c, 0x11effff, 0x11fffff, 0x120ffff, 0x121ffff, 0x122ffff, 0x123ffff, 0x124ffff, 0x125ffff, 0x126ffff, 0x127ffff, 0x128ffff, 0x129ffff, 0x12b012a, 0xffff012c, 0x12dffff, 0xffffffff, 0xffff012e, 0x12fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1310130, 0x1330132, 0x1350134, 0x1370136, 0x1390138, 0x13b013a, 0x13d013c, 0x13f013e, 0x1410140, 0x1430142, 0x1450144, 0x1470146, 0x1490148, 0x14b014a, 0x14d014c, 0x14f014e, 0x1510150, 0x1530152, 0x1550154, 0x1570156, 0x1590158, 0x15b015a, 0x15d015c, 0x15f015e, 0x160ffff, 0x161ffff, 0x162ffff, 0x163ffff, 0x164ffff, 0x165ffff, 0x166ffff, 0x167ffff, 0x168ffff, 0x169ffff, 0x16affff, 0x16bffff, 0x16cffff, 0x16dffff, 0x16effff, 0x16fffff, 0x170ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x171ffff, 0x172ffff, 0x173ffff, 0x174ffff, 0x175ffff, 0x176ffff, 0x177ffff, 0x178ffff, 0x179ffff, 0x17affff, 0x17bffff, 0x17cffff, 0x17dffff, 0x17effff, 0x17fffff, 0x180ffff, 0x181ffff, 0x182ffff, 0x183ffff, 0x184ffff, 0x185ffff, 0x186ffff, 0x187ffff, 0x188ffff, 0x189ffff, 0x18affff, 0x18bffff, 0xffffffff, 0xffff018c, 0xffff018d, 0xffff018e, 0xffff018f, 0xffff0190, 0xffff0191, 0x1930192, 0x194ffff, 0x195ffff, 0x196ffff, 0x197ffff, 0x198ffff, 0x199ffff, 0x19affff, 0x19bffff, 0x19cffff, 0x19dffff, 0x19effff, 0x19fffff, 0x1a0ffff, 0x1a1ffff, 0x1a2ffff, 0x1a3ffff, 0x1a4ffff, 0x1a5ffff, 0x1a6ffff, 0x1a7ffff, 0x1a8ffff, 0x1a9ffff, 0x1aaffff, 0x1abffff, 0x1acffff, 0x1adffff, 0x1aeffff, 0x1afffff, 0x1b0ffff, 0x1b1ffff, 0x1b2ffff, 0x1b3ffff, 0x1b4ffff, 0x1b5ffff, 0x1b6ffff, 0x1b7ffff, 0x1b8ffff, 0x1b9ffff, 0x1baffff, 0x1bbffff, 0x1bcffff, 0x1bdffff, 0x1beffff, 0x1bfffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1c0ffff, 0x1c201c1, 0x1c401c3, 0x1c601c5, 0x1c801c7, 0x1ca01c9, 0x1cc01cb, 0x1ce01cd, 0x1d001cf, 0x1d201d1, 0x1d401d3, 0x1d601d5, 0x1d801d7, 0x1da01d9, 0x1dc01db, 0x1de01dd, 0x1e001df, 0x1e201e1, 0x1e401e3, 0x43201e5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1e6ffff, 0xffffffff, 0x1e7ffff, 0xffffffff, 0x1e8ffff, 0x1e9ffff, 0x1eaffff, 0x1ebffff, 0x1ecffff, 0x1edffff, 0x1eeffff, 0x1efffff, 0x1f0ffff, 0x1f1ffff, 0x1f2ffff, 0x1f3ffff, 0x1f4ffff, 0x1f5ffff, 0x1f6ffff, 0x1f7ffff, 0x1f8ffff, 0x1f9ffff, 0x1faffff, 0x1fbffff, 0x1fcffff, 0x1fdffff, 0x1feffff, 0x1ffffff, 0x200ffff, 0x201ffff, 0x202ffff, 0x203ffff, 0x204ffff, 0x205ffff, 0x206ffff, 0x207ffff, 0x208ffff, 0x209ffff, 0x20affff, 0x20bffff, 0x20cffff, 0x20dffff, 0x20effff, 0x20fffff, 0x210ffff, 0x211ffff, 0x212ffff, 0x213ffff, 0x214ffff, 0x215ffff, 0x216ffff, 0x217ffff, 0x218ffff, 0x219ffff, 0x21affff, 0x21bffff, 0x21cffff, 0x21dffff, 0x21effff, 0x21fffff, 0x220ffff, 0x221ffff, 0x222ffff, 0x223ffff, 0x224ffff, 0x225ffff, 0x226ffff, 0x227ffff, 0x228ffff, 0x229ffff, 0x22affff, 0x22bffff, 0x22cffff, 0x22dffff, 0x22effff, 0x22fffff, 0x230ffff, 0x231ffff, 0x232ffff, 0x44a0448, 0x44e044c, 0x2330450, 0xffffffff, 0xffffffff, 0x234ffff, 0x235ffff, 0x236ffff, 0x237ffff, 0x238ffff, 0x239ffff, 0x23affff, 0x23bffff, 0x23cffff, 0x23dffff, 0x23effff, 0x23fffff, 0x240ffff, 0x241ffff, 0x242ffff, 0x243ffff, 0x244ffff, 0x245ffff, 0x246ffff, 0x247ffff, 0x248ffff, 0x249ffff, 0x24affff, 0x24bffff, 0x24cffff, 0x24dffff, 0x24effff, 0x24fffff, 0x250ffff, 0x251ffff, 0x252ffff, 0x253ffff, 0x254ffff, 0x255ffff, 0x256ffff, 0x257ffff, 0x258ffff, 0x259ffff, 0x25affff, 0x25bffff, 0x25cffff, 0x25dffff, 0x25effff, 0x25fffff, 0x260ffff, 0x261ffff, 0x262ffff, 0x263ffff, 0x2650264, 0x2670266, 0x2690268, 0x26b026a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x26d026c, 0x26f026e, 0x2710270, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2730272, 0x2750274, 0x2770276, 0x2790278, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x27b027a, 0x27d027c, 0x27f027e, 0x2810280, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2830282, 0x2850284, 0x2870286, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2880452, 0x2890454, 0x28a0457, 0x28b045a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x28d028c, 0x28f028e, 0x2910290, 0x2930292, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2950294, 0x2970296, 0x2990298, 0x29b029a, 0x29d029c, 0x29f029e, 0x2a102a0, 0xffffffff, 0x47c047b, 0x47e047d, 0x480047f, 0x4820481, 0x4840483, 0x4860485, 0x4880487, 0x48a0489, 0x48c048b, 0x48e048d, 0x490048f, 0x4920491, 0x4940493, 0x4960495, 0x4980497, 0x49a0499, 0x49c049b, 0x49e049d, 0x4a0049f, 0x4a204a1, 0x4a404a3, 0x4a604a5, 0x4a804a7, 0x4aa04a9, 0x2bb02ba, 0x4ab04b1, 0xffff04b3, 0x4bd045d, 0xffffffff, 0xffffffff, 0xffff04ac, 0xffff02bd, 0xffffffff, 0x4ad04b5, 0xffff04b7, 0x4c0045f, 0xffffffff, 0xffffffff, 0xffff04ae, 0xffffffff, 0x2c002bf, 0x4640461, 0xffffffff, 0x4690467, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c202c1, 0x46f046c, 0x2c30472, 0x4760474, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x4af04b9, 0xffff04bb, 0x4c30479, 0xffffffff, 0xffffffff, 0xffff04b0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02c5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c702c6, 0x2c902c8, 0x2cb02ca, 0x2cd02cc, 0x2cf02ce, 0x2d102d0, 0x2d302d2, 0x2d502d4, 0xffffffff, 0xffffffff, 0xffff02d6, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2d802d7, 0x2da02d9, 0x2dc02db, 0x2de02dd, 0x2e002df, 0x2e202e1, 0x2e402e3, 0x2e602e5, 0x2e802e7, 0x2ea02e9, 0x2ec02eb, 0x2ee02ed, 0x2f002ef, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2f202f1, 0x2f402f3, 0x2f602f5, 0x2f802f7, 0x2fa02f9, 0x2fc02fb, 0x2fe02fd, 0x30002ff, 0x3020301, 0x3040303, 0x3060305, 0x3080307, 0x30a0309, 0x30c030b, 0x30e030d, 0x310030f, 0x3120311, 0x3140313, 0x3160315, 0x3180317, 0x31a0319, 0x31c031b, 0x31e031d, 0xffff031f, 0x320ffff, 0xffffffff, 0x321ffff, 0xffff0322, 0xffff0323, 0xffff0324, 0xffff0325, 0xffffffff, 0xffffffff, 0x326ffff, 0xffffffff, 0xffff0327, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x328ffff, 0x329ffff, 0x32affff, 0x32bffff, 0x32cffff, 0x32dffff, 0x32effff, 0x32fffff, 0x330ffff, 0x331ffff, 0x332ffff, 0x333ffff, 0x334ffff, 0x335ffff, 0x336ffff, 0x337ffff, 0x338ffff, 0x339ffff, 0x33affff, 0x33bffff, 0x33cffff, 0x33dffff, 0x33effff, 0x33fffff, 0x340ffff, 0x341ffff, 0x342ffff, 0x343ffff, 0x344ffff, 0x345ffff, 0x346ffff, 0x347ffff, 0x348ffff, 0x349ffff, 0x34affff, 0x34bffff, 0x34cffff, 0x34dffff, 0x34effff, 0x34fffff, 0x350ffff, 0x351ffff, 0x352ffff, 0x353ffff, 0x354ffff, 0x355ffff, 0x356ffff, 0x357ffff, 0x358ffff, 0x359ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff035a, 0xffff035b, 0xffffffff, 0x35cffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x35e035d, 0x360035f, 0x3620361, 0x3640363, 0x3660365, 0x3680367, 0x36a0369, 0x36c036b, 0x36e036d, 0x370036f, 0x3720371, 0x3740373, 0x3760375, 0x3780377, 0x37a0379, 0x37c037b, 0x37e037d, 0x380037f, 0x3820381, 0x383ffff, 0xffffffff, 0xffffffff, 0x384ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x385ffff, 0x386ffff, 0x387ffff, 0x388ffff, 0x389ffff, 0x38affff, 0x38bffff, 0x38cffff, 0x38dffff, 0x38effff, 0x38fffff, 0x390ffff, 0x391ffff, 0x392ffff, 0x393ffff, 0x394ffff, 0x395ffff, 0x396ffff, 0x397ffff, 0x398ffff, 0x399ffff, 0x39affff, 0x39bffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x39cffff, 0x39dffff, 0x39effff, 0x39fffff, 0x3a0ffff, 0x3a1ffff, 0x3a2ffff, 0x3a3ffff, 0x3a4ffff, 0x3a5ffff, 0x3a6ffff, 0x3a7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3a8ffff, 0x3a9ffff, 0x3aaffff, 0x3abffff, 0x3acffff, 0x3adffff, 0x3aeffff, 0xffffffff, 0x3afffff, 0x3b0ffff, 0x3b1ffff, 0x3b2ffff, 0x3b3ffff, 0x3b4ffff, 0x3b5ffff, 0x3b6ffff, 0x3b7ffff, 0x3b8ffff, 0x3b9ffff, 0x3baffff, 0x3bbffff, 0x3bcffff, 0x3bdffff, 0x3beffff, 0x3bfffff, 0x3c0ffff, 0x3c1ffff, 0x3c2ffff, 0x3c3ffff, 0x3c4ffff, 0x3c5ffff, 0x3c6ffff, 0x3c7ffff, 0x3c8ffff, 0x3c9ffff, 0x3caffff, 0x3cbffff, 0x3ccffff, 0x3cdffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff03ce, 0xffff03cf, 0x3d0ffff, 0x3d1ffff, 0x3d2ffff, 0x3d3ffff, 0x3d4ffff, 0xffffffff, 0xffffffff, 0xffff03d5, 0xffffffff, 0x3d6ffff, 0x3d7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3d8ffff, 0x3d9ffff, 0x3daffff, 0x3dbffff, 0x3dcffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x4240422, 0x4280426, 0x42e042b, 0xffff0430, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x434ffff, 0x4380436, 0x43c043a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3ddffff, 0x3df03de, 0x3e103e0, 0x3e303e2, 0x3e503e4, 0x3e703e6, 0x3e903e8, 0x3eb03ea, 0x3ed03ec, 0x3ef03ee, 0x3f103f0, 0x3f303f2, 0x3f503f4, 0xffff03f6, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3f803f7, 0x3fa03f9, 0x3fc03fb, 0x3fe03fd, 0x40003ff, 0x4020401, 0x4040403, 0x4060405, 0x4080407, 0x40a0409, 0x40c040b, 0x40e040d, 0x410040f, 0x4120411, 0x4140413, 0x4160415, 0x4180417, 0x41a0419, 0x41c041b, 0x41e041d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); //8064 bytes enum toUpperSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x40, 0x200], [ 0x100, 0x380, 0xbc0], [ 0x2020100, 0x4020302, 0x2020205, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xa, 0xb0000, 0xd000c, 0xf000e, 0x110010, 0x130012, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150000, 0x0, 0x170016, 0x190018, 0x1b001a, 0x1d001c, 0x0, 0x0, 0x1e0000, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x220021, 0x240023, 0x25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x260000, 0x27, 0x290028, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d002c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x20001, 0x40003, 0x60005, 0x80007, 0xa0009, 0xc000b, 0xe000d, 0x10000f, 0x120011, 0x140013, 0x160015, 0x180017, 0xffff0019, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1affff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1c001b, 0x1e001d, 0x20001f, 0x220021, 0x240023, 0x260025, 0x280027, 0x2a0029, 0x2c002b, 0x2e002d, 0x30002f, 0xffff0031, 0x330032, 0x350034, 0x370036, 0x390038, 0x3affff, 0x3bffff, 0x3cffff, 0x3dffff, 0x3effff, 0x3fffff, 0x40ffff, 0x41ffff, 0x42ffff, 0x43ffff, 0x44ffff, 0x45ffff, 0x46ffff, 0x47ffff, 0x48ffff, 0x49ffff, 0x4affff, 0x4bffff, 0x4cffff, 0x4dffff, 0x4effff, 0x4fffff, 0x50ffff, 0x51ffff, 0x52ffff, 0x53ffff, 0x54ffff, 0x55ffff, 0xffffffff, 0xffff0056, 0xffff0057, 0xffff0058, 0xffff0059, 0xffff005a, 0xffff005b, 0xffff005c, 0xffff005d, 0x5effff, 0x5fffff, 0x60ffff, 0x61ffff, 0x62ffff, 0x63ffff, 0x64ffff, 0x65ffff, 0x66ffff, 0x67ffff, 0x68ffff, 0x69ffff, 0x6affff, 0x6bffff, 0x6cffff, 0x6dffff, 0x6effff, 0x6fffff, 0x70ffff, 0x71ffff, 0x72ffff, 0x73ffff, 0x74ffff, 0xffffffff, 0xffff0075, 0xffff0076, 0x780077, 0xffff0079, 0x7affff, 0x7bffff, 0xffffffff, 0xffff007c, 0xffffffff, 0xffff007d, 0xffffffff, 0xffffffff, 0xffff007e, 0x7fffff, 0xffffffff, 0x80ffff, 0xffff0081, 0xffffffff, 0xffff0082, 0x83ffff, 0x84ffff, 0x85ffff, 0xffffffff, 0xffff0086, 0xffffffff, 0x87ffff, 0xffffffff, 0xffff0088, 0xffffffff, 0xffff0089, 0xffff008a, 0x8bffff, 0xffffffff, 0x8cffff, 0x8dffff, 0xffffffff, 0xffffffff, 0x8effff, 0xffff008f, 0x910090, 0x92ffff, 0xffff0093, 0xffff0094, 0xffff0095, 0xffff0096, 0xffff0097, 0xffff0098, 0xffff0099, 0xffff009a, 0x9c009b, 0x9dffff, 0x9effff, 0x9fffff, 0xa0ffff, 0xa1ffff, 0xa2ffff, 0xa3ffff, 0xa4ffff, 0xa5ffff, 0xffffffff, 0xa700a6, 0xa8ffff, 0xffffffff, 0xa9ffff, 0xaaffff, 0xabffff, 0xacffff, 0xadffff, 0xaeffff, 0xafffff, 0xb0ffff, 0xb1ffff, 0xb2ffff, 0xb3ffff, 0xb4ffff, 0xb5ffff, 0xb6ffff, 0xb7ffff, 0xb8ffff, 0xb9ffff, 0xbaffff, 0xbbffff, 0xbcffff, 0xffffffff, 0xbdffff, 0xbeffff, 0xbfffff, 0xc0ffff, 0xc1ffff, 0xc2ffff, 0xc3ffff, 0xc4ffff, 0xc5ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff00c6, 0xc7ffff, 0xffff00c8, 0xffff00c9, 0xffffffff, 0xcaffff, 0xcbffff, 0xccffff, 0xcdffff, 0xceffff, 0xd000cf, 0xd200d1, 0xffff00d3, 0xd500d4, 0xd6ffff, 0xd7ffff, 0xffffffff, 0xffffffff, 0xffff00d8, 0xd9ffff, 0xdaffff, 0xffff00db, 0xdd00dc, 0xdeffff, 0xffffffff, 0xdfffff, 0xe0ffff, 0xffff00e1, 0xe2ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe3ffff, 0xffffffff, 0xffff00e4, 0xe5ffff, 0xffffffff, 0xffffffff, 0xe700e6, 0xe900e8, 0xffff00ea, 0xffffffff, 0xffffffff, 0xffff00eb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xecffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xedffff, 0xeeffff, 0xffffffff, 0xefffff, 0xffffffff, 0xf0ffff, 0xf200f1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf400f3, 0xf600f5, 0xf7ffff, 0xf900f8, 0xfb00fa, 0xfd00fc, 0xff00fe, 0x1010100, 0x1030102, 0x1050104, 0x1070106, 0x1090108, 0x10b010a, 0x10d010c, 0x10f010e, 0x1110110, 0x1130112, 0xffff0114, 0x1160115, 0xffffffff, 0x117ffff, 0x1190118, 0x11affff, 0x11bffff, 0x11cffff, 0x11dffff, 0x11effff, 0x11fffff, 0x120ffff, 0x121ffff, 0x122ffff, 0x123ffff, 0x124ffff, 0x125ffff, 0x1270126, 0xffff0128, 0x129ffff, 0xffffffff, 0xffff012a, 0x12bffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x12d012c, 0x12f012e, 0x1310130, 0x1330132, 0x1350134, 0x1370136, 0x1390138, 0x13b013a, 0x13d013c, 0x13f013e, 0x1410140, 0x1430142, 0x1450144, 0x1470146, 0x1490148, 0x14b014a, 0x14d014c, 0x14f014e, 0x1510150, 0x1530152, 0x1550154, 0x1570156, 0x1590158, 0x15b015a, 0x15cffff, 0x15dffff, 0x15effff, 0x15fffff, 0x160ffff, 0x161ffff, 0x162ffff, 0x163ffff, 0x164ffff, 0x165ffff, 0x166ffff, 0x167ffff, 0x168ffff, 0x169ffff, 0x16affff, 0x16bffff, 0x16cffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x16dffff, 0x16effff, 0x16fffff, 0x170ffff, 0x171ffff, 0x172ffff, 0x173ffff, 0x174ffff, 0x175ffff, 0x176ffff, 0x177ffff, 0x178ffff, 0x179ffff, 0x17affff, 0x17bffff, 0x17cffff, 0x17dffff, 0x17effff, 0x17fffff, 0x180ffff, 0x181ffff, 0x182ffff, 0x183ffff, 0x184ffff, 0x185ffff, 0x186ffff, 0x187ffff, 0xffffffff, 0xffff0188, 0xffff0189, 0xffff018a, 0xffff018b, 0xffff018c, 0xffff018d, 0x18f018e, 0x190ffff, 0x191ffff, 0x192ffff, 0x193ffff, 0x194ffff, 0x195ffff, 0x196ffff, 0x197ffff, 0x198ffff, 0x199ffff, 0x19affff, 0x19bffff, 0x19cffff, 0x19dffff, 0x19effff, 0x19fffff, 0x1a0ffff, 0x1a1ffff, 0x1a2ffff, 0x1a3ffff, 0x1a4ffff, 0x1a5ffff, 0x1a6ffff, 0x1a7ffff, 0x1a8ffff, 0x1a9ffff, 0x1aaffff, 0x1abffff, 0x1acffff, 0x1adffff, 0x1aeffff, 0x1afffff, 0x1b0ffff, 0x1b1ffff, 0x1b2ffff, 0x1b3ffff, 0x1b4ffff, 0x1b5ffff, 0x1b6ffff, 0x1b7ffff, 0x1b8ffff, 0x1b9ffff, 0x1baffff, 0x1bbffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1bcffff, 0x1be01bd, 0x1c001bf, 0x1c201c1, 0x1c401c3, 0x1c601c5, 0x1c801c7, 0x1ca01c9, 0x1cc01cb, 0x1ce01cd, 0x1d001cf, 0x1d201d1, 0x1d401d3, 0x1d601d5, 0x1d801d7, 0x1da01d9, 0x1dc01db, 0x1de01dd, 0x1e001df, 0xffff01e1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1e2ffff, 0xffffffff, 0x1e3ffff, 0xffffffff, 0x1e4ffff, 0x1e5ffff, 0x1e6ffff, 0x1e7ffff, 0x1e8ffff, 0x1e9ffff, 0x1eaffff, 0x1ebffff, 0x1ecffff, 0x1edffff, 0x1eeffff, 0x1efffff, 0x1f0ffff, 0x1f1ffff, 0x1f2ffff, 0x1f3ffff, 0x1f4ffff, 0x1f5ffff, 0x1f6ffff, 0x1f7ffff, 0x1f8ffff, 0x1f9ffff, 0x1faffff, 0x1fbffff, 0x1fcffff, 0x1fdffff, 0x1feffff, 0x1ffffff, 0x200ffff, 0x201ffff, 0x202ffff, 0x203ffff, 0x204ffff, 0x205ffff, 0x206ffff, 0x207ffff, 0x208ffff, 0x209ffff, 0x20affff, 0x20bffff, 0x20cffff, 0x20dffff, 0x20effff, 0x20fffff, 0x210ffff, 0x211ffff, 0x212ffff, 0x213ffff, 0x214ffff, 0x215ffff, 0x216ffff, 0x217ffff, 0x218ffff, 0x219ffff, 0x21affff, 0x21bffff, 0x21cffff, 0x21dffff, 0x21effff, 0x21fffff, 0x220ffff, 0x221ffff, 0x222ffff, 0x223ffff, 0x224ffff, 0x225ffff, 0x226ffff, 0x227ffff, 0x228ffff, 0x229ffff, 0x22affff, 0x22bffff, 0x22cffff, 0x22dffff, 0x22effff, 0xffffffff, 0xffffffff, 0x22fffff, 0xffffffff, 0xffffffff, 0x230ffff, 0x231ffff, 0x232ffff, 0x233ffff, 0x234ffff, 0x235ffff, 0x236ffff, 0x237ffff, 0x238ffff, 0x239ffff, 0x23affff, 0x23bffff, 0x23cffff, 0x23dffff, 0x23effff, 0x23fffff, 0x240ffff, 0x241ffff, 0x242ffff, 0x243ffff, 0x244ffff, 0x245ffff, 0x246ffff, 0x247ffff, 0x248ffff, 0x249ffff, 0x24affff, 0x24bffff, 0x24cffff, 0x24dffff, 0x24effff, 0x24fffff, 0x250ffff, 0x251ffff, 0x252ffff, 0x253ffff, 0x254ffff, 0x255ffff, 0x256ffff, 0x257ffff, 0x258ffff, 0x259ffff, 0x25affff, 0x25bffff, 0x25cffff, 0x25dffff, 0x25effff, 0x25fffff, 0x2610260, 0x2630262, 0x2650264, 0x2670266, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2690268, 0x26b026a, 0x26d026c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x26f026e, 0x2710270, 0x2730272, 0x2750274, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2770276, 0x2790278, 0x27b027a, 0x27d027c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x27f027e, 0x2810280, 0x2830282, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x284ffff, 0x285ffff, 0x286ffff, 0x287ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2890288, 0x28b028a, 0x28d028c, 0x28f028e, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2910290, 0x2930292, 0x2950294, 0x2970296, 0x2990298, 0x29b029a, 0x29d029c, 0xffffffff, 0x29f029e, 0x2a102a0, 0x2a302a2, 0x2a502a4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2a702a6, 0x2a902a8, 0x2ab02aa, 0x2ad02ac, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2af02ae, 0x2b102b0, 0x2b302b2, 0x2b502b4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2b702b6, 0x2b8ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02b9, 0xffffffff, 0x2baffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2bc02bb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2be02bd, 0xffffffff, 0x2bfffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c0ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02c1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c302c2, 0x2c502c4, 0x2c702c6, 0x2c902c8, 0x2cb02ca, 0x2cd02cc, 0x2cf02ce, 0x2d102d0, 0xffffffff, 0xffffffff, 0xffff02d2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2d402d3, 0x2d602d5, 0x2d802d7, 0x2da02d9, 0x2dc02db, 0x2de02dd, 0x2e002df, 0x2e202e1, 0x2e402e3, 0x2e602e5, 0x2e802e7, 0x2ea02e9, 0x2ec02eb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2ee02ed, 0x2f002ef, 0x2f202f1, 0x2f402f3, 0x2f602f5, 0x2f802f7, 0x2fa02f9, 0x2fc02fb, 0x2fe02fd, 0x30002ff, 0x3020301, 0x3040303, 0x3060305, 0x3080307, 0x30a0309, 0x30c030b, 0x30e030d, 0x310030f, 0x3120311, 0x3140313, 0x3160315, 0x3180317, 0x31a0319, 0xffff031b, 0x31cffff, 0xffffffff, 0x31dffff, 0xffff031e, 0xffff031f, 0xffff0320, 0xffff0321, 0xffffffff, 0xffffffff, 0x322ffff, 0xffffffff, 0xffff0323, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x324ffff, 0x325ffff, 0x326ffff, 0x327ffff, 0x328ffff, 0x329ffff, 0x32affff, 0x32bffff, 0x32cffff, 0x32dffff, 0x32effff, 0x32fffff, 0x330ffff, 0x331ffff, 0x332ffff, 0x333ffff, 0x334ffff, 0x335ffff, 0x336ffff, 0x337ffff, 0x338ffff, 0x339ffff, 0x33affff, 0x33bffff, 0x33cffff, 0x33dffff, 0x33effff, 0x33fffff, 0x340ffff, 0x341ffff, 0x342ffff, 0x343ffff, 0x344ffff, 0x345ffff, 0x346ffff, 0x347ffff, 0x348ffff, 0x349ffff, 0x34affff, 0x34bffff, 0x34cffff, 0x34dffff, 0x34effff, 0x34fffff, 0x350ffff, 0x351ffff, 0x352ffff, 0x353ffff, 0x354ffff, 0x355ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0356, 0xffff0357, 0xffffffff, 0x358ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x35a0359, 0x35c035b, 0x35e035d, 0x360035f, 0x3620361, 0x3640363, 0x3660365, 0x3680367, 0x36a0369, 0x36c036b, 0x36e036d, 0x370036f, 0x3720371, 0x3740373, 0x3760375, 0x3780377, 0x37a0379, 0x37c037b, 0x37e037d, 0x37fffff, 0xffffffff, 0xffffffff, 0x380ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x381ffff, 0x382ffff, 0x383ffff, 0x384ffff, 0x385ffff, 0x386ffff, 0x387ffff, 0x388ffff, 0x389ffff, 0x38affff, 0x38bffff, 0x38cffff, 0x38dffff, 0x38effff, 0x38fffff, 0x390ffff, 0x391ffff, 0x392ffff, 0x393ffff, 0x394ffff, 0x395ffff, 0x396ffff, 0x397ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x398ffff, 0x399ffff, 0x39affff, 0x39bffff, 0x39cffff, 0x39dffff, 0x39effff, 0x39fffff, 0x3a0ffff, 0x3a1ffff, 0x3a2ffff, 0x3a3ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3a4ffff, 0x3a5ffff, 0x3a6ffff, 0x3a7ffff, 0x3a8ffff, 0x3a9ffff, 0x3aaffff, 0xffffffff, 0x3abffff, 0x3acffff, 0x3adffff, 0x3aeffff, 0x3afffff, 0x3b0ffff, 0x3b1ffff, 0x3b2ffff, 0x3b3ffff, 0x3b4ffff, 0x3b5ffff, 0x3b6ffff, 0x3b7ffff, 0x3b8ffff, 0x3b9ffff, 0x3baffff, 0x3bbffff, 0x3bcffff, 0x3bdffff, 0x3beffff, 0x3bfffff, 0x3c0ffff, 0x3c1ffff, 0x3c2ffff, 0x3c3ffff, 0x3c4ffff, 0x3c5ffff, 0x3c6ffff, 0x3c7ffff, 0x3c8ffff, 0x3c9ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff03ca, 0xffff03cb, 0x3ccffff, 0x3cdffff, 0x3ceffff, 0x3cfffff, 0x3d0ffff, 0xffffffff, 0xffffffff, 0xffff03d1, 0xffffffff, 0x3d2ffff, 0x3d3ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3d4ffff, 0x3d5ffff, 0x3d6ffff, 0x3d7ffff, 0x3d8ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3d9ffff, 0x3db03da, 0x3dd03dc, 0x3df03de, 0x3e103e0, 0x3e303e2, 0x3e503e4, 0x3e703e6, 0x3e903e8, 0x3eb03ea, 0x3ed03ec, 0x3ef03ee, 0x3f103f0, 0xffff03f2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3f403f3, 0x3f603f5, 0x3f803f7, 0x3fa03f9, 0x3fc03fb, 0x3fe03fd, 0x40003ff, 0x4020401, 0x4040403, 0x4060405, 0x4080407, 0x40a0409, 0x40c040b, 0x40e040d, 0x410040f, 0x4120411, 0x4140413, 0x4160415, 0x4180417, 0x41a0419, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); //7808 bytes enum toLowerSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x40, 0x200], [ 0x100, 0x380, 0xb40], [ 0x2020100, 0x4020302, 0x2020205, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x10000, 0x20000, 0x40003, 0x60005, 0x80007, 0x0, 0x90000, 0xb000a, 0xd000c, 0xf000e, 0x110010, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x130012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150014, 0x170016, 0x190018, 0x1b001a, 0x0, 0x0, 0x1d001c, 0x1e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20001f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x220021, 0x240023, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x250000, 0x26, 0x280027, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x20001, 0x40003, 0x60005, 0x80007, 0xa0009, 0xc000b, 0xe000d, 0x10000f, 0x120011, 0x140013, 0x160015, 0x180017, 0xffff0019, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1b001a, 0x1d001c, 0x1f001e, 0x210020, 0x230022, 0x250024, 0x270026, 0x290028, 0x2b002a, 0x2d002c, 0x2f002e, 0xffff0030, 0x320031, 0x340033, 0x360035, 0xffff0037, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0038, 0xffff0039, 0xffff003a, 0xffff003b, 0xffff003c, 0xffff003d, 0xffff003e, 0xffff003f, 0xffff0040, 0xffff0041, 0xffff0042, 0xffff0043, 0xffff0044, 0xffff0045, 0xffff0046, 0xffff0047, 0xffff0048, 0xffff0049, 0xffff004a, 0xffff004b, 0xffff004c, 0xffff004d, 0xffff004e, 0xffff004f, 0xffff0050, 0xffff0051, 0xffff0052, 0xffff0053, 0x54ffff, 0x55ffff, 0x56ffff, 0x57ffff, 0x58ffff, 0x59ffff, 0x5affff, 0x5bffff, 0xffffffff, 0xffff005c, 0xffff005d, 0xffff005e, 0xffff005f, 0xffff0060, 0xffff0061, 0xffff0062, 0xffff0063, 0xffff0064, 0xffff0065, 0xffff0066, 0xffff0067, 0xffff0068, 0xffff0069, 0xffff006a, 0xffff006b, 0xffff006c, 0xffff006d, 0xffff006e, 0xffff006f, 0xffff0070, 0xffff0071, 0xffff0072, 0x740073, 0x75ffff, 0x76ffff, 0xffffffff, 0x77ffff, 0xffff0078, 0xffff0079, 0x7b007a, 0x7cffff, 0x7e007d, 0xffffffff, 0x80007f, 0x820081, 0x83ffff, 0xffff0084, 0x860085, 0xffff0087, 0xffffffff, 0x890088, 0x8affff, 0xffff008b, 0xffff008c, 0xffff008d, 0x8f008e, 0x90ffff, 0xffffffff, 0xffff0091, 0x930092, 0x94ffff, 0x960095, 0x97ffff, 0x98ffff, 0xffff0099, 0xffffffff, 0xffff009a, 0xffffffff, 0xffffffff, 0xffffffff, 0x9c009b, 0x9dffff, 0xffff009e, 0xa0009f, 0xa1ffff, 0xa2ffff, 0xa3ffff, 0xa4ffff, 0xa5ffff, 0xa6ffff, 0xa7ffff, 0xa8ffff, 0xffffffff, 0xffff00a9, 0xffff00aa, 0xffff00ab, 0xffff00ac, 0xffff00ad, 0xffff00ae, 0xffff00af, 0xffff00b0, 0xffff00b1, 0xb2ffff, 0xffff00b3, 0xffff00b4, 0xb600b5, 0xffff00b7, 0xffff00b8, 0xffff00b9, 0xffff00ba, 0xffff00bb, 0xffff00bc, 0xffff00bd, 0xffff00be, 0xffff00bf, 0xffff00c0, 0xffff00c1, 0xffff00c2, 0xffff00c3, 0xffff00c4, 0xffff00c5, 0xffff00c6, 0xffff00c7, 0xffff00c8, 0xffff00c9, 0xffff00ca, 0xffff00cb, 0xffff00cc, 0xffff00cd, 0xffff00ce, 0xffff00cf, 0xffff00d0, 0xffff00d1, 0xffff00d2, 0xffff00d3, 0xffff00d4, 0xffffffff, 0xffffffff, 0xffffffff, 0xd600d5, 0xd7ffff, 0xffff00d8, 0xd9ffff, 0xdaffff, 0xdc00db, 0xffff00dd, 0xffff00de, 0xffff00df, 0xffff00e0, 0xffff00e1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff00e2, 0xffff00e3, 0xffffffff, 0xffff00e4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff00e5, 0xe700e6, 0xffff00e8, 0xffff00e9, 0xeb00ea, 0xecffff, 0xee00ed, 0xf000ef, 0xf200f1, 0xf400f3, 0xf600f5, 0xf800f7, 0xfa00f9, 0xfc00fb, 0xfdffff, 0xff00fe, 0x1010100, 0x1030102, 0x1050104, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x106ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0107, 0xffff0108, 0xffff0109, 0xffff010a, 0xffff010b, 0xffff010c, 0xffff010d, 0xffff010e, 0xffff010f, 0xffff0110, 0xffff0111, 0xffff0112, 0xffffffff, 0xffffffff, 0xffff0113, 0x114ffff, 0x115ffff, 0xffff0116, 0x117ffff, 0x1190118, 0x11b011a, 0x11d011c, 0x11f011e, 0x1210120, 0x1230122, 0x1250124, 0x1270126, 0x1290128, 0x12b012a, 0x12d012c, 0x12f012e, 0x1310130, 0x1330132, 0x1350134, 0x1370136, 0x1390138, 0x13b013a, 0x13d013c, 0x13f013e, 0x1410140, 0x1430142, 0x1450144, 0x1470146, 0x1490148, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff014a, 0xffff014b, 0xffff014c, 0xffff014d, 0xffff014e, 0xffff014f, 0xffff0150, 0xffff0151, 0xffff0152, 0xffff0153, 0xffff0154, 0xffff0155, 0xffff0156, 0xffff0157, 0xffff0158, 0xffff0159, 0xffff015a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff015b, 0xffff015c, 0xffff015d, 0xffff015e, 0xffff015f, 0xffff0160, 0xffff0161, 0xffff0162, 0xffff0163, 0xffff0164, 0xffff0165, 0xffff0166, 0xffff0167, 0xffff0168, 0xffff0169, 0xffff016a, 0xffff016b, 0xffff016c, 0xffff016d, 0xffff016e, 0xffff016f, 0xffff0170, 0xffff0171, 0xffff0172, 0xffff0173, 0xffff0174, 0xffff0175, 0x1770176, 0x178ffff, 0x179ffff, 0x17affff, 0x17bffff, 0x17cffff, 0x17dffff, 0xffffffff, 0xffff017e, 0xffff017f, 0xffff0180, 0xffff0181, 0xffff0182, 0xffff0183, 0xffff0184, 0xffff0185, 0xffff0186, 0xffff0187, 0xffff0188, 0xffff0189, 0xffff018a, 0xffff018b, 0xffff018c, 0xffff018d, 0xffff018e, 0xffff018f, 0xffff0190, 0xffff0191, 0xffff0192, 0xffff0193, 0xffff0194, 0xffff0195, 0xffff0196, 0xffff0197, 0xffff0198, 0xffff0199, 0xffff019a, 0xffff019b, 0xffff019c, 0xffff019d, 0xffff019e, 0xffff019f, 0xffff01a0, 0xffff01a1, 0xffff01a2, 0xffff01a3, 0xffff01a4, 0xffff01a5, 0xffff01a6, 0xffff01a7, 0xffff01a8, 0xffff01a9, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1aaffff, 0x1ac01ab, 0x1ae01ad, 0x1b001af, 0x1b201b1, 0x1b401b3, 0x1b601b5, 0x1b801b7, 0x1ba01b9, 0x1bc01bb, 0x1be01bd, 0x1c001bf, 0x1c201c1, 0x1c401c3, 0x1c601c5, 0x1c801c7, 0x1ca01c9, 0x1cc01cb, 0x1ce01cd, 0xffff01cf, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1d101d0, 0x1d301d2, 0x1d501d4, 0x1d701d6, 0x1d901d8, 0x1db01da, 0x1dd01dc, 0x1df01de, 0x1e101e0, 0x1e301e2, 0x1e501e4, 0x1e701e6, 0x1e901e8, 0x1eb01ea, 0x1ed01ec, 0x1ef01ee, 0x1f101f0, 0x1f301f2, 0x1f501f4, 0x1f6ffff, 0xffffffff, 0xffffffff, 0x1f7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff01f8, 0xffff01f9, 0xffff01fa, 0xffff01fb, 0xffff01fc, 0xffff01fd, 0xffff01fe, 0xffff01ff, 0xffff0200, 0xffff0201, 0xffff0202, 0xffff0203, 0xffff0204, 0xffff0205, 0xffff0206, 0xffff0207, 0xffff0208, 0xffff0209, 0xffff020a, 0xffff020b, 0xffff020c, 0xffff020d, 0xffff020e, 0xffff020f, 0xffff0210, 0xffff0211, 0xffff0212, 0xffff0213, 0xffff0214, 0xffff0215, 0xffff0216, 0xffff0217, 0xffff0218, 0xffff0219, 0xffff021a, 0xffff021b, 0xffff021c, 0xffff021d, 0xffff021e, 0xffff021f, 0xffff0220, 0xffff0221, 0xffff0222, 0xffff0223, 0xffff0224, 0xffff0225, 0xffff0226, 0xffff0227, 0xffff0228, 0xffff0229, 0xffff022a, 0xffff022b, 0xffff022c, 0xffff022d, 0xffff022e, 0xffff022f, 0xffff0230, 0xffff0231, 0xffff0232, 0xffff0233, 0xffff0234, 0xffff0235, 0xffff0236, 0xffff0237, 0xffff0238, 0xffff0239, 0xffff023a, 0xffff023b, 0xffff023c, 0xffff023d, 0xffff023e, 0xffff023f, 0xffff0240, 0xffff0241, 0xffff0242, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0243, 0xffff0244, 0xffff0245, 0xffff0246, 0xffff0247, 0xffff0248, 0xffff0249, 0xffff024a, 0xffff024b, 0xffff024c, 0xffff024d, 0xffff024e, 0xffff024f, 0xffff0250, 0xffff0251, 0xffff0252, 0xffff0253, 0xffff0254, 0xffff0255, 0xffff0256, 0xffff0257, 0xffff0258, 0xffff0259, 0xffff025a, 0xffff025b, 0xffff025c, 0xffff025d, 0xffff025e, 0xffff025f, 0xffff0260, 0xffff0261, 0xffff0262, 0xffff0263, 0xffff0264, 0xffff0265, 0xffff0266, 0xffff0267, 0xffff0268, 0xffff0269, 0xffff026a, 0xffff026b, 0xffff026c, 0xffff026d, 0xffff026e, 0xffff026f, 0xffff0270, 0xffff0271, 0xffff0272, 0xffff0273, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2750274, 0x2770276, 0x2790278, 0x27b027a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x27d027c, 0x27f027e, 0x2810280, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2830282, 0x2850284, 0x2870286, 0x2890288, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x28b028a, 0x28d028c, 0x28f028e, 0x2910290, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2930292, 0x2950294, 0x2970296, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x298ffff, 0x299ffff, 0x29affff, 0x29bffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x29d029c, 0x29f029e, 0x2a102a0, 0x2a302a2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2a502a4, 0x2a702a6, 0x2a902a8, 0x2ab02aa, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2ad02ac, 0x2af02ae, 0x2b102b0, 0x2b302b2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2b502b4, 0x2b702b6, 0x2b902b8, 0x2bb02ba, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2bd02bc, 0x2bf02be, 0xffff02c0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c202c1, 0x2c402c3, 0xffff02c5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c702c6, 0x2c902c8, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2cb02ca, 0x2cd02cc, 0xffff02ce, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2d002cf, 0x2d202d1, 0xffff02d3, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02d4, 0xffffffff, 0x2d602d5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02d7, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2d902d8, 0x2db02da, 0x2dd02dc, 0x2df02de, 0x2e102e0, 0x2e302e2, 0x2e502e4, 0x2e702e6, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2e8ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2ea02e9, 0x2ec02eb, 0x2ee02ed, 0x2f002ef, 0x2f202f1, 0x2f402f3, 0x2f602f5, 0x2f802f7, 0x2fa02f9, 0x2fc02fb, 0x2fe02fd, 0x30002ff, 0x3020301, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3040303, 0x3060305, 0x3080307, 0x30a0309, 0x30c030b, 0x30e030d, 0x310030f, 0x3120311, 0x3140313, 0x3160315, 0x3180317, 0x31a0319, 0x31c031b, 0x31e031d, 0x320031f, 0x3220321, 0x3240323, 0x3260325, 0x3280327, 0x32a0329, 0x32c032b, 0x32e032d, 0x330032f, 0xffff0331, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0332, 0x3340333, 0xffff0335, 0x336ffff, 0x337ffff, 0x338ffff, 0x339ffff, 0x33b033a, 0xffff033c, 0xffff033d, 0x33effff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x340033f, 0xffff0341, 0xffff0342, 0xffff0343, 0xffff0344, 0xffff0345, 0xffff0346, 0xffff0347, 0xffff0348, 0xffff0349, 0xffff034a, 0xffff034b, 0xffff034c, 0xffff034d, 0xffff034e, 0xffff034f, 0xffff0350, 0xffff0351, 0xffff0352, 0xffff0353, 0xffff0354, 0xffff0355, 0xffff0356, 0xffff0357, 0xffff0358, 0xffff0359, 0xffff035a, 0xffff035b, 0xffff035c, 0xffff035d, 0xffff035e, 0xffff035f, 0xffff0360, 0xffff0361, 0xffff0362, 0xffff0363, 0xffff0364, 0xffff0365, 0xffff0366, 0xffff0367, 0xffff0368, 0xffff0369, 0xffff036a, 0xffff036b, 0xffff036c, 0xffff036d, 0xffff036e, 0xffff036f, 0xffff0370, 0xffff0371, 0xffff0372, 0xffffffff, 0xffffffff, 0xffffffff, 0x373ffff, 0x374ffff, 0xffffffff, 0xffffffff, 0xffff0375, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0376, 0xffff0377, 0xffff0378, 0xffff0379, 0xffff037a, 0xffff037b, 0xffff037c, 0xffff037d, 0xffff037e, 0xffff037f, 0xffff0380, 0xffff0381, 0xffff0382, 0xffff0383, 0xffff0384, 0xffff0385, 0xffff0386, 0xffff0387, 0xffff0388, 0xffff0389, 0xffff038a, 0xffff038b, 0xffff038c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff038d, 0xffff038e, 0xffff038f, 0xffff0390, 0xffff0391, 0xffff0392, 0xffff0393, 0xffff0394, 0xffff0395, 0xffff0396, 0xffff0397, 0xffff0398, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0399, 0xffff039a, 0xffff039b, 0xffff039c, 0xffff039d, 0xffff039e, 0xffff039f, 0xffffffff, 0xffff03a0, 0xffff03a1, 0xffff03a2, 0xffff03a3, 0xffff03a4, 0xffff03a5, 0xffff03a6, 0xffff03a7, 0xffff03a8, 0xffff03a9, 0xffff03aa, 0xffff03ab, 0xffff03ac, 0xffff03ad, 0xffff03ae, 0xffff03af, 0xffff03b0, 0xffff03b1, 0xffff03b2, 0xffff03b3, 0xffff03b4, 0xffff03b5, 0xffff03b6, 0xffff03b7, 0xffff03b8, 0xffff03b9, 0xffff03ba, 0xffff03bb, 0xffff03bc, 0xffff03bd, 0xffff03be, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3bfffff, 0x3c0ffff, 0x3c1ffff, 0xffff03c2, 0xffff03c3, 0xffff03c4, 0xffff03c5, 0xffff03c6, 0xffffffff, 0x3c7ffff, 0x3c8ffff, 0xffffffff, 0xffff03c9, 0xffff03ca, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff03cb, 0xffff03cc, 0xffff03cd, 0xffff03ce, 0xffff03cf, 0xffff03d0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3d1ffff, 0x3d303d2, 0x3d503d4, 0x3d703d6, 0x3d903d8, 0x3db03da, 0x3dd03dc, 0x3df03de, 0x3e103e0, 0x3e303e2, 0x3e503e4, 0x3e703e6, 0x3e903e8, 0xffff03ea, 0xffffffff, 0xffffffff, 0x3ec03eb, 0x3ee03ed, 0x3f003ef, 0x3f203f1, 0x3f403f3, 0x3f603f5, 0x3f803f7, 0x3fa03f9, 0x3fc03fb, 0x3fe03fd, 0x40003ff, 0x4020401, 0x4040403, 0x4060405, 0x4080407, 0x40a0409, 0x40c040b, 0x40e040d, 0x410040f, 0x4120411, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); //8064 bytes enum toTitleSimpleIndexTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x40, 0x200], [ 0x100, 0x380, 0xbc0], [ 0x2020100, 0x4020302, 0x2020205, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xa, 0xb0000, 0xd000c, 0xf000e, 0x110010, 0x130012, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150000, 0x0, 0x170016, 0x190018, 0x1b001a, 0x1d001c, 0x0, 0x0, 0x1e0000, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x220021, 0x240023, 0x25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x260000, 0x27, 0x290028, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d002c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x20001, 0x40003, 0x60005, 0x80007, 0xa0009, 0xc000b, 0xe000d, 0x10000f, 0x120011, 0x140013, 0x160015, 0x180017, 0xffff0019, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1affff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1c001b, 0x1e001d, 0x20001f, 0x220021, 0x240023, 0x260025, 0x280027, 0x2a0029, 0x2c002b, 0x2e002d, 0x30002f, 0xffff0031, 0x330032, 0x350034, 0x370036, 0x390038, 0x3affff, 0x3bffff, 0x3cffff, 0x3dffff, 0x3effff, 0x3fffff, 0x40ffff, 0x41ffff, 0x42ffff, 0x43ffff, 0x44ffff, 0x45ffff, 0x46ffff, 0x47ffff, 0x48ffff, 0x49ffff, 0x4affff, 0x4bffff, 0x4cffff, 0x4dffff, 0x4effff, 0x4fffff, 0x50ffff, 0x51ffff, 0x52ffff, 0x53ffff, 0x54ffff, 0x55ffff, 0xffffffff, 0xffff0056, 0xffff0057, 0xffff0058, 0xffff0059, 0xffff005a, 0xffff005b, 0xffff005c, 0xffff005d, 0x5effff, 0x5fffff, 0x60ffff, 0x61ffff, 0x62ffff, 0x63ffff, 0x64ffff, 0x65ffff, 0x66ffff, 0x67ffff, 0x68ffff, 0x69ffff, 0x6affff, 0x6bffff, 0x6cffff, 0x6dffff, 0x6effff, 0x6fffff, 0x70ffff, 0x71ffff, 0x72ffff, 0x73ffff, 0x74ffff, 0xffffffff, 0xffff0075, 0xffff0076, 0x780077, 0xffff0079, 0x7affff, 0x7bffff, 0xffffffff, 0xffff007c, 0xffffffff, 0xffff007d, 0xffffffff, 0xffffffff, 0xffff007e, 0x7fffff, 0xffffffff, 0x80ffff, 0xffff0081, 0xffffffff, 0xffff0082, 0x83ffff, 0x84ffff, 0x85ffff, 0xffffffff, 0xffff0086, 0xffffffff, 0x87ffff, 0xffffffff, 0xffff0088, 0xffffffff, 0xffff0089, 0xffff008a, 0x8bffff, 0xffffffff, 0x8cffff, 0x8dffff, 0xffffffff, 0xffffffff, 0x8f008e, 0x910090, 0x930092, 0x950094, 0xffff0096, 0xffff0097, 0xffff0098, 0xffff0099, 0xffff009a, 0xffff009b, 0xffff009c, 0xffff009d, 0x9f009e, 0xa0ffff, 0xa1ffff, 0xa2ffff, 0xa3ffff, 0xa4ffff, 0xa5ffff, 0xa6ffff, 0xa7ffff, 0xa8ffff, 0xa9ffff, 0xab00aa, 0xacffff, 0xffffffff, 0xadffff, 0xaeffff, 0xafffff, 0xb0ffff, 0xb1ffff, 0xb2ffff, 0xb3ffff, 0xb4ffff, 0xb5ffff, 0xb6ffff, 0xb7ffff, 0xb8ffff, 0xb9ffff, 0xbaffff, 0xbbffff, 0xbcffff, 0xbdffff, 0xbeffff, 0xbfffff, 0xc0ffff, 0xffffffff, 0xc1ffff, 0xc2ffff, 0xc3ffff, 0xc4ffff, 0xc5ffff, 0xc6ffff, 0xc7ffff, 0xc8ffff, 0xc9ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff00ca, 0xcbffff, 0xffff00cc, 0xffff00cd, 0xffffffff, 0xceffff, 0xcfffff, 0xd0ffff, 0xd1ffff, 0xd2ffff, 0xd400d3, 0xd600d5, 0xffff00d7, 0xd900d8, 0xdaffff, 0xdbffff, 0xffffffff, 0xffffffff, 0xffff00dc, 0xddffff, 0xdeffff, 0xffff00df, 0xe100e0, 0xe2ffff, 0xffffffff, 0xe3ffff, 0xe4ffff, 0xffff00e5, 0xe6ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe7ffff, 0xffffffff, 0xffff00e8, 0xe9ffff, 0xffffffff, 0xffffffff, 0xeb00ea, 0xed00ec, 0xffff00ee, 0xffffffff, 0xffffffff, 0xffff00ef, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf0ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf1ffff, 0xf2ffff, 0xffffffff, 0xf3ffff, 0xffffffff, 0xf4ffff, 0xf600f5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf800f7, 0xfa00f9, 0xfbffff, 0xfd00fc, 0xff00fe, 0x1010100, 0x1030102, 0x1050104, 0x1070106, 0x1090108, 0x10b010a, 0x10d010c, 0x10f010e, 0x1110110, 0x1130112, 0x1150114, 0x1170116, 0xffff0118, 0x11a0119, 0xffffffff, 0x11bffff, 0x11d011c, 0x11effff, 0x11fffff, 0x120ffff, 0x121ffff, 0x122ffff, 0x123ffff, 0x124ffff, 0x125ffff, 0x126ffff, 0x127ffff, 0x128ffff, 0x129ffff, 0x12b012a, 0xffff012c, 0x12dffff, 0xffffffff, 0xffff012e, 0x12fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1310130, 0x1330132, 0x1350134, 0x1370136, 0x1390138, 0x13b013a, 0x13d013c, 0x13f013e, 0x1410140, 0x1430142, 0x1450144, 0x1470146, 0x1490148, 0x14b014a, 0x14d014c, 0x14f014e, 0x1510150, 0x1530152, 0x1550154, 0x1570156, 0x1590158, 0x15b015a, 0x15d015c, 0x15f015e, 0x160ffff, 0x161ffff, 0x162ffff, 0x163ffff, 0x164ffff, 0x165ffff, 0x166ffff, 0x167ffff, 0x168ffff, 0x169ffff, 0x16affff, 0x16bffff, 0x16cffff, 0x16dffff, 0x16effff, 0x16fffff, 0x170ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x171ffff, 0x172ffff, 0x173ffff, 0x174ffff, 0x175ffff, 0x176ffff, 0x177ffff, 0x178ffff, 0x179ffff, 0x17affff, 0x17bffff, 0x17cffff, 0x17dffff, 0x17effff, 0x17fffff, 0x180ffff, 0x181ffff, 0x182ffff, 0x183ffff, 0x184ffff, 0x185ffff, 0x186ffff, 0x187ffff, 0x188ffff, 0x189ffff, 0x18affff, 0x18bffff, 0xffffffff, 0xffff018c, 0xffff018d, 0xffff018e, 0xffff018f, 0xffff0190, 0xffff0191, 0x1930192, 0x194ffff, 0x195ffff, 0x196ffff, 0x197ffff, 0x198ffff, 0x199ffff, 0x19affff, 0x19bffff, 0x19cffff, 0x19dffff, 0x19effff, 0x19fffff, 0x1a0ffff, 0x1a1ffff, 0x1a2ffff, 0x1a3ffff, 0x1a4ffff, 0x1a5ffff, 0x1a6ffff, 0x1a7ffff, 0x1a8ffff, 0x1a9ffff, 0x1aaffff, 0x1abffff, 0x1acffff, 0x1adffff, 0x1aeffff, 0x1afffff, 0x1b0ffff, 0x1b1ffff, 0x1b2ffff, 0x1b3ffff, 0x1b4ffff, 0x1b5ffff, 0x1b6ffff, 0x1b7ffff, 0x1b8ffff, 0x1b9ffff, 0x1baffff, 0x1bbffff, 0x1bcffff, 0x1bdffff, 0x1beffff, 0x1bfffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1c0ffff, 0x1c201c1, 0x1c401c3, 0x1c601c5, 0x1c801c7, 0x1ca01c9, 0x1cc01cb, 0x1ce01cd, 0x1d001cf, 0x1d201d1, 0x1d401d3, 0x1d601d5, 0x1d801d7, 0x1da01d9, 0x1dc01db, 0x1de01dd, 0x1e001df, 0x1e201e1, 0x1e401e3, 0xffff01e5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1e6ffff, 0xffffffff, 0x1e7ffff, 0xffffffff, 0x1e8ffff, 0x1e9ffff, 0x1eaffff, 0x1ebffff, 0x1ecffff, 0x1edffff, 0x1eeffff, 0x1efffff, 0x1f0ffff, 0x1f1ffff, 0x1f2ffff, 0x1f3ffff, 0x1f4ffff, 0x1f5ffff, 0x1f6ffff, 0x1f7ffff, 0x1f8ffff, 0x1f9ffff, 0x1faffff, 0x1fbffff, 0x1fcffff, 0x1fdffff, 0x1feffff, 0x1ffffff, 0x200ffff, 0x201ffff, 0x202ffff, 0x203ffff, 0x204ffff, 0x205ffff, 0x206ffff, 0x207ffff, 0x208ffff, 0x209ffff, 0x20affff, 0x20bffff, 0x20cffff, 0x20dffff, 0x20effff, 0x20fffff, 0x210ffff, 0x211ffff, 0x212ffff, 0x213ffff, 0x214ffff, 0x215ffff, 0x216ffff, 0x217ffff, 0x218ffff, 0x219ffff, 0x21affff, 0x21bffff, 0x21cffff, 0x21dffff, 0x21effff, 0x21fffff, 0x220ffff, 0x221ffff, 0x222ffff, 0x223ffff, 0x224ffff, 0x225ffff, 0x226ffff, 0x227ffff, 0x228ffff, 0x229ffff, 0x22affff, 0x22bffff, 0x22cffff, 0x22dffff, 0x22effff, 0x22fffff, 0x230ffff, 0x231ffff, 0x232ffff, 0xffffffff, 0xffffffff, 0x233ffff, 0xffffffff, 0xffffffff, 0x234ffff, 0x235ffff, 0x236ffff, 0x237ffff, 0x238ffff, 0x239ffff, 0x23affff, 0x23bffff, 0x23cffff, 0x23dffff, 0x23effff, 0x23fffff, 0x240ffff, 0x241ffff, 0x242ffff, 0x243ffff, 0x244ffff, 0x245ffff, 0x246ffff, 0x247ffff, 0x248ffff, 0x249ffff, 0x24affff, 0x24bffff, 0x24cffff, 0x24dffff, 0x24effff, 0x24fffff, 0x250ffff, 0x251ffff, 0x252ffff, 0x253ffff, 0x254ffff, 0x255ffff, 0x256ffff, 0x257ffff, 0x258ffff, 0x259ffff, 0x25affff, 0x25bffff, 0x25cffff, 0x25dffff, 0x25effff, 0x25fffff, 0x260ffff, 0x261ffff, 0x262ffff, 0x263ffff, 0x2650264, 0x2670266, 0x2690268, 0x26b026a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x26d026c, 0x26f026e, 0x2710270, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2730272, 0x2750274, 0x2770276, 0x2790278, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x27b027a, 0x27d027c, 0x27f027e, 0x2810280, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2830282, 0x2850284, 0x2870286, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x288ffff, 0x289ffff, 0x28affff, 0x28bffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x28d028c, 0x28f028e, 0x2910290, 0x2930292, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2950294, 0x2970296, 0x2990298, 0x29b029a, 0x29d029c, 0x29f029e, 0x2a102a0, 0xffffffff, 0x2a302a2, 0x2a502a4, 0x2a702a6, 0x2a902a8, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2ab02aa, 0x2ad02ac, 0x2af02ae, 0x2b102b0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2b302b2, 0x2b502b4, 0x2b702b6, 0x2b902b8, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2bb02ba, 0x2bcffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02bd, 0xffffffff, 0x2beffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c002bf, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c202c1, 0xffffffff, 0x2c3ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c4ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff02c5, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2c702c6, 0x2c902c8, 0x2cb02ca, 0x2cd02cc, 0x2cf02ce, 0x2d102d0, 0x2d302d2, 0x2d502d4, 0xffffffff, 0xffffffff, 0xffff02d6, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2d802d7, 0x2da02d9, 0x2dc02db, 0x2de02dd, 0x2e002df, 0x2e202e1, 0x2e402e3, 0x2e602e5, 0x2e802e7, 0x2ea02e9, 0x2ec02eb, 0x2ee02ed, 0x2f002ef, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x2f202f1, 0x2f402f3, 0x2f602f5, 0x2f802f7, 0x2fa02f9, 0x2fc02fb, 0x2fe02fd, 0x30002ff, 0x3020301, 0x3040303, 0x3060305, 0x3080307, 0x30a0309, 0x30c030b, 0x30e030d, 0x310030f, 0x3120311, 0x3140313, 0x3160315, 0x3180317, 0x31a0319, 0x31c031b, 0x31e031d, 0xffff031f, 0x320ffff, 0xffffffff, 0x321ffff, 0xffff0322, 0xffff0323, 0xffff0324, 0xffff0325, 0xffffffff, 0xffffffff, 0x326ffff, 0xffffffff, 0xffff0327, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x328ffff, 0x329ffff, 0x32affff, 0x32bffff, 0x32cffff, 0x32dffff, 0x32effff, 0x32fffff, 0x330ffff, 0x331ffff, 0x332ffff, 0x333ffff, 0x334ffff, 0x335ffff, 0x336ffff, 0x337ffff, 0x338ffff, 0x339ffff, 0x33affff, 0x33bffff, 0x33cffff, 0x33dffff, 0x33effff, 0x33fffff, 0x340ffff, 0x341ffff, 0x342ffff, 0x343ffff, 0x344ffff, 0x345ffff, 0x346ffff, 0x347ffff, 0x348ffff, 0x349ffff, 0x34affff, 0x34bffff, 0x34cffff, 0x34dffff, 0x34effff, 0x34fffff, 0x350ffff, 0x351ffff, 0x352ffff, 0x353ffff, 0x354ffff, 0x355ffff, 0x356ffff, 0x357ffff, 0x358ffff, 0x359ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff035a, 0xffff035b, 0xffffffff, 0x35cffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x35e035d, 0x360035f, 0x3620361, 0x3640363, 0x3660365, 0x3680367, 0x36a0369, 0x36c036b, 0x36e036d, 0x370036f, 0x3720371, 0x3740373, 0x3760375, 0x3780377, 0x37a0379, 0x37c037b, 0x37e037d, 0x380037f, 0x3820381, 0x383ffff, 0xffffffff, 0xffffffff, 0x384ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x385ffff, 0x386ffff, 0x387ffff, 0x388ffff, 0x389ffff, 0x38affff, 0x38bffff, 0x38cffff, 0x38dffff, 0x38effff, 0x38fffff, 0x390ffff, 0x391ffff, 0x392ffff, 0x393ffff, 0x394ffff, 0x395ffff, 0x396ffff, 0x397ffff, 0x398ffff, 0x399ffff, 0x39affff, 0x39bffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x39cffff, 0x39dffff, 0x39effff, 0x39fffff, 0x3a0ffff, 0x3a1ffff, 0x3a2ffff, 0x3a3ffff, 0x3a4ffff, 0x3a5ffff, 0x3a6ffff, 0x3a7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3a8ffff, 0x3a9ffff, 0x3aaffff, 0x3abffff, 0x3acffff, 0x3adffff, 0x3aeffff, 0xffffffff, 0x3afffff, 0x3b0ffff, 0x3b1ffff, 0x3b2ffff, 0x3b3ffff, 0x3b4ffff, 0x3b5ffff, 0x3b6ffff, 0x3b7ffff, 0x3b8ffff, 0x3b9ffff, 0x3baffff, 0x3bbffff, 0x3bcffff, 0x3bdffff, 0x3beffff, 0x3bfffff, 0x3c0ffff, 0x3c1ffff, 0x3c2ffff, 0x3c3ffff, 0x3c4ffff, 0x3c5ffff, 0x3c6ffff, 0x3c7ffff, 0x3c8ffff, 0x3c9ffff, 0x3caffff, 0x3cbffff, 0x3ccffff, 0x3cdffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff03ce, 0xffff03cf, 0x3d0ffff, 0x3d1ffff, 0x3d2ffff, 0x3d3ffff, 0x3d4ffff, 0xffffffff, 0xffffffff, 0xffff03d5, 0xffffffff, 0x3d6ffff, 0x3d7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3d8ffff, 0x3d9ffff, 0x3daffff, 0x3dbffff, 0x3dcffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3ddffff, 0x3df03de, 0x3e103e0, 0x3e303e2, 0x3e503e4, 0x3e703e6, 0x3e903e8, 0x3eb03ea, 0x3ed03ec, 0x3ef03ee, 0x3f103f0, 0x3f303f2, 0x3f503f4, 0xffff03f6, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3f803f7, 0x3fa03f9, 0x3fc03fb, 0x3fe03fd, 0x40003ff, 0x4020401, 0x4040403, 0x4060405, 0x4080407, 0x40a0409, 0x40c040b, 0x40e040d, 0x410040f, 0x4120411, 0x4140413, 0x4160415, 0x4180417, 0x41a0419, 0x41c041b, 0x41e041d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); @property { private alias _IUA = immutable(uint[]); _IUA toUpperTable() { static _IUA t = [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x39c, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11a, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12a, 0x12c, 0x12e, 0x49, 0x132, 0x134, 0x136, 0x139, 0x13b, 0x13d, 0x13f, 0x141, 0x143, 0x145, 0x147, 0x14a, 0x14c, 0x14e, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15a, 0x15c, 0x15e, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16a, 0x16c, 0x16e, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17b, 0x17d, 0x53, 0x243, 0x182, 0x184, 0x187, 0x18b, 0x191, 0x1f6, 0x198, 0x23d, 0x220, 0x1a0, 0x1a2, 0x1a4, 0x1a7, 0x1ac, 0x1af, 0x1b3, 0x1b5, 0x1b8, 0x1bc, 0x1f7, 0x1c4, 0x1c4, 0x1c7, 0x1c7, 0x1ca, 0x1ca, 0x1cd, 0x1cf, 0x1d1, 0x1d3, 0x1d5, 0x1d7, 0x1d9, 0x1db, 0x18e, 0x1de, 0x1e0, 0x1e2, 0x1e4, 0x1e6, 0x1e8, 0x1ea, 0x1ec, 0x1ee, 0x1f1, 0x1f1, 0x1f4, 0x1f8, 0x1fa, 0x1fc, 0x1fe, 0x200, 0x202, 0x204, 0x206, 0x208, 0x20a, 0x20c, 0x20e, 0x210, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21c, 0x21e, 0x222, 0x224, 0x226, 0x228, 0x22a, 0x22c, 0x22e, 0x230, 0x232, 0x23b, 0x2c7e, 0x2c7f, 0x241, 0x246, 0x248, 0x24a, 0x24c, 0x24e, 0x2c6f, 0x2c6d, 0x2c70, 0x181, 0x186, 0x189, 0x18a, 0x18f, 0x190, 0x193, 0x194, 0xa78d, 0xa7aa, 0x197, 0x196, 0x2c62, 0x19c, 0x2c6e, 0x19d, 0x19f, 0x2c64, 0x1a6, 0x1a9, 0x1ae, 0x244, 0x1b1, 0x1b2, 0x245, 0x1b7, 0x399, 0x370, 0x372, 0x376, 0x3fd, 0x3fe, 0x3ff, 0x386, 0x388, 0x389, 0x38a, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39a, 0x39b, 0x39c, 0x39d, 0x39e, 0x39f, 0x3a0, 0x3a1, 0x3a3, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, 0x3a8, 0x3a9, 0x3aa, 0x3ab, 0x38c, 0x38e, 0x38f, 0x392, 0x398, 0x3a6, 0x3a0, 0x3cf, 0x3d8, 0x3da, 0x3dc, 0x3de, 0x3e0, 0x3e2, 0x3e4, 0x3e6, 0x3e8, 0x3ea, 0x3ec, 0x3ee, 0x39a, 0x3a1, 0x3f9, 0x395, 0x3f7, 0x3fa, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41a, 0x41b, 0x41c, 0x41d, 0x41e, 0x41f, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42a, 0x42b, 0x42c, 0x42d, 0x42e, 0x42f, 0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f, 0x460, 0x462, 0x464, 0x466, 0x468, 0x46a, 0x46c, 0x46e, 0x470, 0x472, 0x474, 0x476, 0x478, 0x47a, 0x47c, 0x47e, 0x480, 0x48a, 0x48c, 0x48e, 0x490, 0x492, 0x494, 0x496, 0x498, 0x49a, 0x49c, 0x49e, 0x4a0, 0x4a2, 0x4a4, 0x4a6, 0x4a8, 0x4aa, 0x4ac, 0x4ae, 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba, 0x4bc, 0x4be, 0x4c1, 0x4c3, 0x4c5, 0x4c7, 0x4c9, 0x4cb, 0x4cd, 0x4c0, 0x4d0, 0x4d2, 0x4d4, 0x4d6, 0x4d8, 0x4da, 0x4dc, 0x4de, 0x4e0, 0x4e2, 0x4e4, 0x4e6, 0x4e8, 0x4ea, 0x4ec, 0x4ee, 0x4f0, 0x4f2, 0x4f4, 0x4f6, 0x4f8, 0x4fa, 0x4fc, 0x4fe, 0x500, 0x502, 0x504, 0x506, 0x508, 0x50a, 0x50c, 0x50e, 0x510, 0x512, 0x514, 0x516, 0x518, 0x51a, 0x51c, 0x51e, 0x520, 0x522, 0x524, 0x526, 0x531, 0x532, 0x533, 0x534, 0x535, 0x536, 0x537, 0x538, 0x539, 0x53a, 0x53b, 0x53c, 0x53d, 0x53e, 0x53f, 0x540, 0x541, 0x542, 0x543, 0x544, 0x545, 0x546, 0x547, 0x548, 0x549, 0x54a, 0x54b, 0x54c, 0x54d, 0x54e, 0x54f, 0x550, 0x551, 0x552, 0x553, 0x554, 0x555, 0x556, 0xa77d, 0x2c63, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, 0x1e0c, 0x1e0e, 0x1e10, 0x1e12, 0x1e14, 0x1e16, 0x1e18, 0x1e1a, 0x1e1c, 0x1e1e, 0x1e20, 0x1e22, 0x1e24, 0x1e26, 0x1e28, 0x1e2a, 0x1e2c, 0x1e2e, 0x1e30, 0x1e32, 0x1e34, 0x1e36, 0x1e38, 0x1e3a, 0x1e3c, 0x1e3e, 0x1e40, 0x1e42, 0x1e44, 0x1e46, 0x1e48, 0x1e4a, 0x1e4c, 0x1e4e, 0x1e50, 0x1e52, 0x1e54, 0x1e56, 0x1e58, 0x1e5a, 0x1e5c, 0x1e5e, 0x1e60, 0x1e62, 0x1e64, 0x1e66, 0x1e68, 0x1e6a, 0x1e6c, 0x1e6e, 0x1e70, 0x1e72, 0x1e74, 0x1e76, 0x1e78, 0x1e7a, 0x1e7c, 0x1e7e, 0x1e80, 0x1e82, 0x1e84, 0x1e86, 0x1e88, 0x1e8a, 0x1e8c, 0x1e8e, 0x1e90, 0x1e92, 0x1e94, 0x1e60, 0x1ea0, 0x1ea2, 0x1ea4, 0x1ea6, 0x1ea8, 0x1eaa, 0x1eac, 0x1eae, 0x1eb0, 0x1eb2, 0x1eb4, 0x1eb6, 0x1eb8, 0x1eba, 0x1ebc, 0x1ebe, 0x1ec0, 0x1ec2, 0x1ec4, 0x1ec6, 0x1ec8, 0x1eca, 0x1ecc, 0x1ece, 0x1ed0, 0x1ed2, 0x1ed4, 0x1ed6, 0x1ed8, 0x1eda, 0x1edc, 0x1ede, 0x1ee0, 0x1ee2, 0x1ee4, 0x1ee6, 0x1ee8, 0x1eea, 0x1eec, 0x1eee, 0x1ef0, 0x1ef2, 0x1ef4, 0x1ef6, 0x1ef8, 0x1efa, 0x1efc, 0x1efe, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0x1f59, 0x1f5b, 0x1f5d, 0x1f5f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, 0x1ffa, 0x1ffb, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fb8, 0x1fb9, 0x1fbc, 0x399, 0x1fcc, 0x1fd8, 0x1fd9, 0x1fe8, 0x1fe9, 0x1fec, 0x1ffc, 0x2132, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, 0x216c, 0x216d, 0x216e, 0x216f, 0x2183, 0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, 0x24bb, 0x24bc, 0x24bd, 0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, 0x24c3, 0x24c4, 0x24c5, 0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, 0x24cb, 0x24cc, 0x24cd, 0x24ce, 0x24cf, 0x2c00, 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x2c08, 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x2c10, 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, 0x2c18, 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, 0x2c20, 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, 0x2c28, 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x2c60, 0x23a, 0x23e, 0x2c67, 0x2c69, 0x2c6b, 0x2c72, 0x2c75, 0x2c80, 0x2c82, 0x2c84, 0x2c86, 0x2c88, 0x2c8a, 0x2c8c, 0x2c8e, 0x2c90, 0x2c92, 0x2c94, 0x2c96, 0x2c98, 0x2c9a, 0x2c9c, 0x2c9e, 0x2ca0, 0x2ca2, 0x2ca4, 0x2ca6, 0x2ca8, 0x2caa, 0x2cac, 0x2cae, 0x2cb0, 0x2cb2, 0x2cb4, 0x2cb6, 0x2cb8, 0x2cba, 0x2cbc, 0x2cbe, 0x2cc0, 0x2cc2, 0x2cc4, 0x2cc6, 0x2cc8, 0x2cca, 0x2ccc, 0x2cce, 0x2cd0, 0x2cd2, 0x2cd4, 0x2cd6, 0x2cd8, 0x2cda, 0x2cdc, 0x2cde, 0x2ce0, 0x2ce2, 0x2ceb, 0x2ced, 0x2cf2, 0x10a0, 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0, 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8, 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0, 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0x10c7, 0x10cd, 0xa640, 0xa642, 0xa644, 0xa646, 0xa648, 0xa64a, 0xa64c, 0xa64e, 0xa650, 0xa652, 0xa654, 0xa656, 0xa658, 0xa65a, 0xa65c, 0xa65e, 0xa660, 0xa662, 0xa664, 0xa666, 0xa668, 0xa66a, 0xa66c, 0xa680, 0xa682, 0xa684, 0xa686, 0xa688, 0xa68a, 0xa68c, 0xa68e, 0xa690, 0xa692, 0xa694, 0xa696, 0xa722, 0xa724, 0xa726, 0xa728, 0xa72a, 0xa72c, 0xa72e, 0xa732, 0xa734, 0xa736, 0xa738, 0xa73a, 0xa73c, 0xa73e, 0xa740, 0xa742, 0xa744, 0xa746, 0xa748, 0xa74a, 0xa74c, 0xa74e, 0xa750, 0xa752, 0xa754, 0xa756, 0xa758, 0xa75a, 0xa75c, 0xa75e, 0xa760, 0xa762, 0xa764, 0xa766, 0xa768, 0xa76a, 0xa76c, 0xa76e, 0xa779, 0xa77b, 0xa77e, 0xa780, 0xa782, 0xa784, 0xa786, 0xa78b, 0xa790, 0xa792, 0xa7a0, 0xa7a2, 0xa7a4, 0xa7a6, 0xa7a8, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, 0xff3a, 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407, 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f, 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417, 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f, 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427, 0x2000053, 0x53, 0x130, 0x2000046, 0x46, 0x2000046, 0x49, 0x2000046, 0x4c, 0x3000046, 0x46, 0x49, 0x3000046, 0x46, 0x4c, 0x2000053, 0x54, 0x2000053, 0x54, 0x2000535, 0x552, 0x2000544, 0x546, 0x2000544, 0x535, 0x2000544, 0x53b, 0x200054e, 0x546, 0x2000544, 0x53d, 0x20002bc, 0x4e, 0x3000399, 0x308, 0x301, 0x30003a5, 0x308, 0x301, 0x200004a, 0x30c, 0x2000048, 0x331, 0x2000054, 0x308, 0x2000057, 0x30a, 0x2000059, 0x30a, 0x2000041, 0x2be, 0x20003a5, 0x313, 0x30003a5, 0x313, 0x300, 0x30003a5, 0x313, 0x301, 0x30003a5, 0x313, 0x342, 0x2000391, 0x342, 0x2000397, 0x342, 0x3000399, 0x308, 0x300, 0x3000399, 0x308, 0x301, 0x2000399, 0x342, 0x3000399, 0x308, 0x342, 0x30003a5, 0x308, 0x300, 0x30003a5, 0x308, 0x301, 0x20003a1, 0x313, 0x20003a5, 0x342, 0x30003a5, 0x308, 0x342, 0x20003a9, 0x342, 0x2001f08, 0x399, 0x2001f09, 0x399, 0x2001f0a, 0x399, 0x2001f0b, 0x399, 0x2001f0c, 0x399, 0x2001f0d, 0x399, 0x2001f0e, 0x399, 0x2001f0f, 0x399, 0x2001f08, 0x399, 0x2001f09, 0x399, 0x2001f0a, 0x399, 0x2001f0b, 0x399, 0x2001f0c, 0x399, 0x2001f0d, 0x399, 0x2001f0e, 0x399, 0x2001f0f, 0x399, 0x2001f28, 0x399, 0x2001f29, 0x399, 0x2001f2a, 0x399, 0x2001f2b, 0x399, 0x2001f2c, 0x399, 0x2001f2d, 0x399, 0x2001f2e, 0x399, 0x2001f2f, 0x399, 0x2001f28, 0x399, 0x2001f29, 0x399, 0x2001f2a, 0x399, 0x2001f2b, 0x399, 0x2001f2c, 0x399, 0x2001f2d, 0x399, 0x2001f2e, 0x399, 0x2001f2f, 0x399, 0x2001f68, 0x399, 0x2001f69, 0x399, 0x2001f6a, 0x399, 0x2001f6b, 0x399, 0x2001f6c, 0x399, 0x2001f6d, 0x399, 0x2001f6e, 0x399, 0x2001f6f, 0x399, 0x2001f68, 0x399, 0x2001f69, 0x399, 0x2001f6a, 0x399, 0x2001f6b, 0x399, 0x2001f6c, 0x399, 0x2001f6d, 0x399, 0x2001f6e, 0x399, 0x2001f6f, 0x399, 0x2000391, 0x399, 0x2000391, 0x399, 0x2000397, 0x399, 0x2000397, 0x399, 0x20003a9, 0x399, 0x20003a9, 0x399, 0x2001fba, 0x399, 0x2000386, 0x399, 0x2001fca, 0x399, 0x2000389, 0x399, 0x2001ffa, 0x399, 0x200038f, 0x399, 0x3000391, 0x342, 0x399, 0x3000397, 0x342, 0x399, 0x30003a9, 0x342, 0x399]; return t; } _IUA toLowerTable() { static _IUA t = [ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10b, 0x10d, 0x10f, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11b, 0x11d, 0x11f, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12b, 0x12d, 0x12f, 0x69, 0x133, 0x135, 0x137, 0x13a, 0x13c, 0x13e, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14b, 0x14d, 0x14f, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15b, 0x15d, 0x15f, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16b, 0x16d, 0x16f, 0x171, 0x173, 0x175, 0x177, 0xff, 0x17a, 0x17c, 0x17e, 0x253, 0x183, 0x185, 0x254, 0x188, 0x256, 0x257, 0x18c, 0x1dd, 0x259, 0x25b, 0x192, 0x260, 0x263, 0x269, 0x268, 0x199, 0x26f, 0x272, 0x275, 0x1a1, 0x1a3, 0x1a5, 0x280, 0x1a8, 0x283, 0x1ad, 0x288, 0x1b0, 0x28a, 0x28b, 0x1b4, 0x1b6, 0x292, 0x1b9, 0x1bd, 0x1c6, 0x1c6, 0x1c9, 0x1c9, 0x1cc, 0x1cc, 0x1ce, 0x1d0, 0x1d2, 0x1d4, 0x1d6, 0x1d8, 0x1da, 0x1dc, 0x1df, 0x1e1, 0x1e3, 0x1e5, 0x1e7, 0x1e9, 0x1eb, 0x1ed, 0x1ef, 0x1f3, 0x1f3, 0x1f5, 0x195, 0x1bf, 0x1f9, 0x1fb, 0x1fd, 0x1ff, 0x201, 0x203, 0x205, 0x207, 0x209, 0x20b, 0x20d, 0x20f, 0x211, 0x213, 0x215, 0x217, 0x219, 0x21b, 0x21d, 0x21f, 0x19e, 0x223, 0x225, 0x227, 0x229, 0x22b, 0x22d, 0x22f, 0x231, 0x233, 0x2c65, 0x23c, 0x19a, 0x2c66, 0x242, 0x180, 0x289, 0x28c, 0x247, 0x249, 0x24b, 0x24d, 0x24f, 0x371, 0x373, 0x377, 0x3ac, 0x3ad, 0x3ae, 0x3af, 0x3cc, 0x3cd, 0x3ce, 0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b7, 0x3b8, 0x3b9, 0x3ba, 0x3bb, 0x3bc, 0x3bd, 0x3be, 0x3bf, 0x3c0, 0x3c1, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7, 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x3d7, 0x3d9, 0x3db, 0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e5, 0x3e7, 0x3e9, 0x3eb, 0x3ed, 0x3ef, 0x3b8, 0x3f8, 0x3f2, 0x3fb, 0x37b, 0x37c, 0x37d, 0x450, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45a, 0x45b, 0x45c, 0x45d, 0x45e, 0x45f, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43a, 0x43b, 0x43c, 0x43d, 0x43e, 0x43f, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44a, 0x44b, 0x44c, 0x44d, 0x44e, 0x44f, 0x461, 0x463, 0x465, 0x467, 0x469, 0x46b, 0x46d, 0x46f, 0x471, 0x473, 0x475, 0x477, 0x479, 0x47b, 0x47d, 0x47f, 0x481, 0x48b, 0x48d, 0x48f, 0x491, 0x493, 0x495, 0x497, 0x499, 0x49b, 0x49d, 0x49f, 0x4a1, 0x4a3, 0x4a5, 0x4a7, 0x4a9, 0x4ab, 0x4ad, 0x4af, 0x4b1, 0x4b3, 0x4b5, 0x4b7, 0x4b9, 0x4bb, 0x4bd, 0x4bf, 0x4cf, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4cc, 0x4ce, 0x4d1, 0x4d3, 0x4d5, 0x4d7, 0x4d9, 0x4db, 0x4dd, 0x4df, 0x4e1, 0x4e3, 0x4e5, 0x4e7, 0x4e9, 0x4eb, 0x4ed, 0x4ef, 0x4f1, 0x4f3, 0x4f5, 0x4f7, 0x4f9, 0x4fb, 0x4fd, 0x4ff, 0x501, 0x503, 0x505, 0x507, 0x509, 0x50b, 0x50d, 0x50f, 0x511, 0x513, 0x515, 0x517, 0x519, 0x51b, 0x51d, 0x51f, 0x521, 0x523, 0x525, 0x527, 0x561, 0x562, 0x563, 0x564, 0x565, 0x566, 0x567, 0x568, 0x569, 0x56a, 0x56b, 0x56c, 0x56d, 0x56e, 0x56f, 0x570, 0x571, 0x572, 0x573, 0x574, 0x575, 0x576, 0x577, 0x578, 0x579, 0x57a, 0x57b, 0x57c, 0x57d, 0x57e, 0x57f, 0x580, 0x581, 0x582, 0x583, 0x584, 0x585, 0x586, 0x2d00, 0x2d01, 0x2d02, 0x2d03, 0x2d04, 0x2d05, 0x2d06, 0x2d07, 0x2d08, 0x2d09, 0x2d0a, 0x2d0b, 0x2d0c, 0x2d0d, 0x2d0e, 0x2d0f, 0x2d10, 0x2d11, 0x2d12, 0x2d13, 0x2d14, 0x2d15, 0x2d16, 0x2d17, 0x2d18, 0x2d19, 0x2d1a, 0x2d1b, 0x2d1c, 0x2d1d, 0x2d1e, 0x2d1f, 0x2d20, 0x2d21, 0x2d22, 0x2d23, 0x2d24, 0x2d25, 0x2d27, 0x2d2d, 0x1e01, 0x1e03, 0x1e05, 0x1e07, 0x1e09, 0x1e0b, 0x1e0d, 0x1e0f, 0x1e11, 0x1e13, 0x1e15, 0x1e17, 0x1e19, 0x1e1b, 0x1e1d, 0x1e1f, 0x1e21, 0x1e23, 0x1e25, 0x1e27, 0x1e29, 0x1e2b, 0x1e2d, 0x1e2f, 0x1e31, 0x1e33, 0x1e35, 0x1e37, 0x1e39, 0x1e3b, 0x1e3d, 0x1e3f, 0x1e41, 0x1e43, 0x1e45, 0x1e47, 0x1e49, 0x1e4b, 0x1e4d, 0x1e4f, 0x1e51, 0x1e53, 0x1e55, 0x1e57, 0x1e59, 0x1e5b, 0x1e5d, 0x1e5f, 0x1e61, 0x1e63, 0x1e65, 0x1e67, 0x1e69, 0x1e6b, 0x1e6d, 0x1e6f, 0x1e71, 0x1e73, 0x1e75, 0x1e77, 0x1e79, 0x1e7b, 0x1e7d, 0x1e7f, 0x1e81, 0x1e83, 0x1e85, 0x1e87, 0x1e89, 0x1e8b, 0x1e8d, 0x1e8f, 0x1e91, 0x1e93, 0x1e95, 0xdf, 0x1ea1, 0x1ea3, 0x1ea5, 0x1ea7, 0x1ea9, 0x1eab, 0x1ead, 0x1eaf, 0x1eb1, 0x1eb3, 0x1eb5, 0x1eb7, 0x1eb9, 0x1ebb, 0x1ebd, 0x1ebf, 0x1ec1, 0x1ec3, 0x1ec5, 0x1ec7, 0x1ec9, 0x1ecb, 0x1ecd, 0x1ecf, 0x1ed1, 0x1ed3, 0x1ed5, 0x1ed7, 0x1ed9, 0x1edb, 0x1edd, 0x1edf, 0x1ee1, 0x1ee3, 0x1ee5, 0x1ee7, 0x1ee9, 0x1eeb, 0x1eed, 0x1eef, 0x1ef1, 0x1ef3, 0x1ef5, 0x1ef7, 0x1ef9, 0x1efb, 0x1efd, 0x1eff, 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f51, 0x1f53, 0x1f55, 0x1f57, 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0x3c9, 0x6b, 0xe5, 0x214e, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, 0x2184, 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9, 0x2c30, 0x2c31, 0x2c32, 0x2c33, 0x2c34, 0x2c35, 0x2c36, 0x2c37, 0x2c38, 0x2c39, 0x2c3a, 0x2c3b, 0x2c3c, 0x2c3d, 0x2c3e, 0x2c3f, 0x2c40, 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2c48, 0x2c49, 0x2c4a, 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c50, 0x2c51, 0x2c52, 0x2c53, 0x2c54, 0x2c55, 0x2c56, 0x2c57, 0x2c58, 0x2c59, 0x2c5a, 0x2c5b, 0x2c5c, 0x2c5d, 0x2c5e, 0x2c61, 0x26b, 0x1d7d, 0x27d, 0x2c68, 0x2c6a, 0x2c6c, 0x251, 0x271, 0x250, 0x252, 0x2c73, 0x2c76, 0x23f, 0x240, 0x2c81, 0x2c83, 0x2c85, 0x2c87, 0x2c89, 0x2c8b, 0x2c8d, 0x2c8f, 0x2c91, 0x2c93, 0x2c95, 0x2c97, 0x2c99, 0x2c9b, 0x2c9d, 0x2c9f, 0x2ca1, 0x2ca3, 0x2ca5, 0x2ca7, 0x2ca9, 0x2cab, 0x2cad, 0x2caf, 0x2cb1, 0x2cb3, 0x2cb5, 0x2cb7, 0x2cb9, 0x2cbb, 0x2cbd, 0x2cbf, 0x2cc1, 0x2cc3, 0x2cc5, 0x2cc7, 0x2cc9, 0x2ccb, 0x2ccd, 0x2ccf, 0x2cd1, 0x2cd3, 0x2cd5, 0x2cd7, 0x2cd9, 0x2cdb, 0x2cdd, 0x2cdf, 0x2ce1, 0x2ce3, 0x2cec, 0x2cee, 0x2cf3, 0xa641, 0xa643, 0xa645, 0xa647, 0xa649, 0xa64b, 0xa64d, 0xa64f, 0xa651, 0xa653, 0xa655, 0xa657, 0xa659, 0xa65b, 0xa65d, 0xa65f, 0xa661, 0xa663, 0xa665, 0xa667, 0xa669, 0xa66b, 0xa66d, 0xa681, 0xa683, 0xa685, 0xa687, 0xa689, 0xa68b, 0xa68d, 0xa68f, 0xa691, 0xa693, 0xa695, 0xa697, 0xa723, 0xa725, 0xa727, 0xa729, 0xa72b, 0xa72d, 0xa72f, 0xa733, 0xa735, 0xa737, 0xa739, 0xa73b, 0xa73d, 0xa73f, 0xa741, 0xa743, 0xa745, 0xa747, 0xa749, 0xa74b, 0xa74d, 0xa74f, 0xa751, 0xa753, 0xa755, 0xa757, 0xa759, 0xa75b, 0xa75d, 0xa75f, 0xa761, 0xa763, 0xa765, 0xa767, 0xa769, 0xa76b, 0xa76d, 0xa76f, 0xa77a, 0xa77c, 0x1d79, 0xa77f, 0xa781, 0xa783, 0xa785, 0xa787, 0xa78c, 0x265, 0xa791, 0xa793, 0xa7a1, 0xa7a3, 0xa7a5, 0xa7a7, 0xa7a9, 0x266, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, 0xff58, 0xff59, 0xff5a, 0x10428, 0x10429, 0x1042a, 0x1042b, 0x1042c, 0x1042d, 0x1042e, 0x1042f, 0x10430, 0x10431, 0x10432, 0x10433, 0x10434, 0x10435, 0x10436, 0x10437, 0x10438, 0x10439, 0x1043a, 0x1043b, 0x1043c, 0x1043d, 0x1043e, 0x1043f, 0x10440, 0x10441, 0x10442, 0x10443, 0x10444, 0x10445, 0x10446, 0x10447, 0x10448, 0x10449, 0x1044a, 0x1044b, 0x1044c, 0x1044d, 0x1044e, 0x1044f, 0xdf, 0x2000069, 0x307, 0xfb00, 0xfb01, 0xfb02, 0xfb03, 0xfb04, 0xfb05, 0xfb06, 0x587, 0xfb13, 0xfb14, 0xfb15, 0xfb16, 0xfb17, 0x149, 0x390, 0x3b0, 0x1f0, 0x1e96, 0x1e97, 0x1e98, 0x1e99, 0x1e9a, 0x1f50, 0x1f52, 0x1f54, 0x1f56, 0x1fb6, 0x1fc6, 0x1fd2, 0x1fd3, 0x1fd6, 0x1fd7, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe6, 0x1fe7, 0x1ff6, 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, 0x1fb3, 0x1fb3, 0x1fc3, 0x1fc3, 0x1ff3, 0x1ff3, 0x1fb2, 0x1fb4, 0x1fc2, 0x1fc4, 0x1ff2, 0x1ff4, 0x1fb7, 0x1fc7, 0x1ff7]; return t; } _IUA toTitleTable() { static _IUA t = [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x39c, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11a, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12a, 0x12c, 0x12e, 0x49, 0x132, 0x134, 0x136, 0x139, 0x13b, 0x13d, 0x13f, 0x141, 0x143, 0x145, 0x147, 0x14a, 0x14c, 0x14e, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15a, 0x15c, 0x15e, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16a, 0x16c, 0x16e, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17b, 0x17d, 0x53, 0x243, 0x182, 0x184, 0x187, 0x18b, 0x191, 0x1f6, 0x198, 0x23d, 0x220, 0x1a0, 0x1a2, 0x1a4, 0x1a7, 0x1ac, 0x1af, 0x1b3, 0x1b5, 0x1b8, 0x1bc, 0x1f7, 0x1c5, 0x1c5, 0x1c5, 0x1c8, 0x1c8, 0x1c8, 0x1cb, 0x1cb, 0x1cb, 0x1cd, 0x1cf, 0x1d1, 0x1d3, 0x1d5, 0x1d7, 0x1d9, 0x1db, 0x18e, 0x1de, 0x1e0, 0x1e2, 0x1e4, 0x1e6, 0x1e8, 0x1ea, 0x1ec, 0x1ee, 0x1f2, 0x1f2, 0x1f2, 0x1f4, 0x1f8, 0x1fa, 0x1fc, 0x1fe, 0x200, 0x202, 0x204, 0x206, 0x208, 0x20a, 0x20c, 0x20e, 0x210, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21c, 0x21e, 0x222, 0x224, 0x226, 0x228, 0x22a, 0x22c, 0x22e, 0x230, 0x232, 0x23b, 0x2c7e, 0x2c7f, 0x241, 0x246, 0x248, 0x24a, 0x24c, 0x24e, 0x2c6f, 0x2c6d, 0x2c70, 0x181, 0x186, 0x189, 0x18a, 0x18f, 0x190, 0x193, 0x194, 0xa78d, 0xa7aa, 0x197, 0x196, 0x2c62, 0x19c, 0x2c6e, 0x19d, 0x19f, 0x2c64, 0x1a6, 0x1a9, 0x1ae, 0x244, 0x1b1, 0x1b2, 0x245, 0x1b7, 0x399, 0x370, 0x372, 0x376, 0x3fd, 0x3fe, 0x3ff, 0x386, 0x388, 0x389, 0x38a, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39a, 0x39b, 0x39c, 0x39d, 0x39e, 0x39f, 0x3a0, 0x3a1, 0x3a3, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, 0x3a8, 0x3a9, 0x3aa, 0x3ab, 0x38c, 0x38e, 0x38f, 0x392, 0x398, 0x3a6, 0x3a0, 0x3cf, 0x3d8, 0x3da, 0x3dc, 0x3de, 0x3e0, 0x3e2, 0x3e4, 0x3e6, 0x3e8, 0x3ea, 0x3ec, 0x3ee, 0x39a, 0x3a1, 0x3f9, 0x395, 0x3f7, 0x3fa, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41a, 0x41b, 0x41c, 0x41d, 0x41e, 0x41f, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42a, 0x42b, 0x42c, 0x42d, 0x42e, 0x42f, 0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f, 0x460, 0x462, 0x464, 0x466, 0x468, 0x46a, 0x46c, 0x46e, 0x470, 0x472, 0x474, 0x476, 0x478, 0x47a, 0x47c, 0x47e, 0x480, 0x48a, 0x48c, 0x48e, 0x490, 0x492, 0x494, 0x496, 0x498, 0x49a, 0x49c, 0x49e, 0x4a0, 0x4a2, 0x4a4, 0x4a6, 0x4a8, 0x4aa, 0x4ac, 0x4ae, 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba, 0x4bc, 0x4be, 0x4c1, 0x4c3, 0x4c5, 0x4c7, 0x4c9, 0x4cb, 0x4cd, 0x4c0, 0x4d0, 0x4d2, 0x4d4, 0x4d6, 0x4d8, 0x4da, 0x4dc, 0x4de, 0x4e0, 0x4e2, 0x4e4, 0x4e6, 0x4e8, 0x4ea, 0x4ec, 0x4ee, 0x4f0, 0x4f2, 0x4f4, 0x4f6, 0x4f8, 0x4fa, 0x4fc, 0x4fe, 0x500, 0x502, 0x504, 0x506, 0x508, 0x50a, 0x50c, 0x50e, 0x510, 0x512, 0x514, 0x516, 0x518, 0x51a, 0x51c, 0x51e, 0x520, 0x522, 0x524, 0x526, 0x531, 0x532, 0x533, 0x534, 0x535, 0x536, 0x537, 0x538, 0x539, 0x53a, 0x53b, 0x53c, 0x53d, 0x53e, 0x53f, 0x540, 0x541, 0x542, 0x543, 0x544, 0x545, 0x546, 0x547, 0x548, 0x549, 0x54a, 0x54b, 0x54c, 0x54d, 0x54e, 0x54f, 0x550, 0x551, 0x552, 0x553, 0x554, 0x555, 0x556, 0xa77d, 0x2c63, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, 0x1e0c, 0x1e0e, 0x1e10, 0x1e12, 0x1e14, 0x1e16, 0x1e18, 0x1e1a, 0x1e1c, 0x1e1e, 0x1e20, 0x1e22, 0x1e24, 0x1e26, 0x1e28, 0x1e2a, 0x1e2c, 0x1e2e, 0x1e30, 0x1e32, 0x1e34, 0x1e36, 0x1e38, 0x1e3a, 0x1e3c, 0x1e3e, 0x1e40, 0x1e42, 0x1e44, 0x1e46, 0x1e48, 0x1e4a, 0x1e4c, 0x1e4e, 0x1e50, 0x1e52, 0x1e54, 0x1e56, 0x1e58, 0x1e5a, 0x1e5c, 0x1e5e, 0x1e60, 0x1e62, 0x1e64, 0x1e66, 0x1e68, 0x1e6a, 0x1e6c, 0x1e6e, 0x1e70, 0x1e72, 0x1e74, 0x1e76, 0x1e78, 0x1e7a, 0x1e7c, 0x1e7e, 0x1e80, 0x1e82, 0x1e84, 0x1e86, 0x1e88, 0x1e8a, 0x1e8c, 0x1e8e, 0x1e90, 0x1e92, 0x1e94, 0x1e60, 0x1ea0, 0x1ea2, 0x1ea4, 0x1ea6, 0x1ea8, 0x1eaa, 0x1eac, 0x1eae, 0x1eb0, 0x1eb2, 0x1eb4, 0x1eb6, 0x1eb8, 0x1eba, 0x1ebc, 0x1ebe, 0x1ec0, 0x1ec2, 0x1ec4, 0x1ec6, 0x1ec8, 0x1eca, 0x1ecc, 0x1ece, 0x1ed0, 0x1ed2, 0x1ed4, 0x1ed6, 0x1ed8, 0x1eda, 0x1edc, 0x1ede, 0x1ee0, 0x1ee2, 0x1ee4, 0x1ee6, 0x1ee8, 0x1eea, 0x1eec, 0x1eee, 0x1ef0, 0x1ef2, 0x1ef4, 0x1ef6, 0x1ef8, 0x1efa, 0x1efc, 0x1efe, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0x1f59, 0x1f5b, 0x1f5d, 0x1f5f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, 0x1ffa, 0x1ffb, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fb8, 0x1fb9, 0x1fbc, 0x399, 0x1fcc, 0x1fd8, 0x1fd9, 0x1fe8, 0x1fe9, 0x1fec, 0x1ffc, 0x2132, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, 0x216c, 0x216d, 0x216e, 0x216f, 0x2183, 0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, 0x24bb, 0x24bc, 0x24bd, 0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, 0x24c3, 0x24c4, 0x24c5, 0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, 0x24cb, 0x24cc, 0x24cd, 0x24ce, 0x24cf, 0x2c00, 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x2c08, 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x2c10, 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, 0x2c18, 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, 0x2c20, 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, 0x2c28, 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x2c60, 0x23a, 0x23e, 0x2c67, 0x2c69, 0x2c6b, 0x2c72, 0x2c75, 0x2c80, 0x2c82, 0x2c84, 0x2c86, 0x2c88, 0x2c8a, 0x2c8c, 0x2c8e, 0x2c90, 0x2c92, 0x2c94, 0x2c96, 0x2c98, 0x2c9a, 0x2c9c, 0x2c9e, 0x2ca0, 0x2ca2, 0x2ca4, 0x2ca6, 0x2ca8, 0x2caa, 0x2cac, 0x2cae, 0x2cb0, 0x2cb2, 0x2cb4, 0x2cb6, 0x2cb8, 0x2cba, 0x2cbc, 0x2cbe, 0x2cc0, 0x2cc2, 0x2cc4, 0x2cc6, 0x2cc8, 0x2cca, 0x2ccc, 0x2cce, 0x2cd0, 0x2cd2, 0x2cd4, 0x2cd6, 0x2cd8, 0x2cda, 0x2cdc, 0x2cde, 0x2ce0, 0x2ce2, 0x2ceb, 0x2ced, 0x2cf2, 0x10a0, 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0, 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8, 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0, 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0x10c7, 0x10cd, 0xa640, 0xa642, 0xa644, 0xa646, 0xa648, 0xa64a, 0xa64c, 0xa64e, 0xa650, 0xa652, 0xa654, 0xa656, 0xa658, 0xa65a, 0xa65c, 0xa65e, 0xa660, 0xa662, 0xa664, 0xa666, 0xa668, 0xa66a, 0xa66c, 0xa680, 0xa682, 0xa684, 0xa686, 0xa688, 0xa68a, 0xa68c, 0xa68e, 0xa690, 0xa692, 0xa694, 0xa696, 0xa722, 0xa724, 0xa726, 0xa728, 0xa72a, 0xa72c, 0xa72e, 0xa732, 0xa734, 0xa736, 0xa738, 0xa73a, 0xa73c, 0xa73e, 0xa740, 0xa742, 0xa744, 0xa746, 0xa748, 0xa74a, 0xa74c, 0xa74e, 0xa750, 0xa752, 0xa754, 0xa756, 0xa758, 0xa75a, 0xa75c, 0xa75e, 0xa760, 0xa762, 0xa764, 0xa766, 0xa768, 0xa76a, 0xa76c, 0xa76e, 0xa779, 0xa77b, 0xa77e, 0xa780, 0xa782, 0xa784, 0xa786, 0xa78b, 0xa790, 0xa792, 0xa7a0, 0xa7a2, 0xa7a4, 0xa7a6, 0xa7a8, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, 0xff3a, 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407, 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f, 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417, 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f, 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427, 0x2000053, 0x73, 0x130, 0x2000046, 0x66, 0x2000046, 0x69, 0x2000046, 0x6c, 0x3000046, 0x66, 0x69, 0x3000046, 0x66, 0x6c, 0x2000053, 0x74, 0x2000053, 0x74, 0x2000535, 0x582, 0x2000544, 0x576, 0x2000544, 0x565, 0x2000544, 0x56b, 0x200054e, 0x576, 0x2000544, 0x56d, 0x20002bc, 0x4e, 0x3000399, 0x308, 0x301, 0x30003a5, 0x308, 0x301, 0x200004a, 0x30c, 0x2000048, 0x331, 0x2000054, 0x308, 0x2000057, 0x30a, 0x2000059, 0x30a, 0x2000041, 0x2be, 0x20003a5, 0x313, 0x30003a5, 0x313, 0x300, 0x30003a5, 0x313, 0x301, 0x30003a5, 0x313, 0x342, 0x2000391, 0x342, 0x2000397, 0x342, 0x3000399, 0x308, 0x300, 0x3000399, 0x308, 0x301, 0x2000399, 0x342, 0x3000399, 0x308, 0x342, 0x30003a5, 0x308, 0x300, 0x30003a5, 0x308, 0x301, 0x20003a1, 0x313, 0x20003a5, 0x342, 0x30003a5, 0x308, 0x342, 0x20003a9, 0x342, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fbc, 0x1fbc, 0x1fcc, 0x1fcc, 0x1ffc, 0x1ffc, 0x2001fba, 0x345, 0x2000386, 0x345, 0x2001fca, 0x345, 0x2000389, 0x345, 0x2001ffa, 0x345, 0x200038f, 0x345, 0x3000391, 0x342, 0x345, 0x3000397, 0x342, 0x345, 0x30003a9, 0x342, 0x345]; return t; } } } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/windows/0000775000175000017500000000000012776215007021214 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/internal/windows/advapi32.d0000664000175000017500000000365312776215007023001 0ustar kaikai// Written in the D programming language. /** * The only purpose of this module is to do the static construction for * std.windows.registry, to eliminate cyclic construction errors. * * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Kenji Hara * Source: $(PHOBOSSRC std/internal/windows/_advapi32.d) */ module std.internal.windows.advapi32; version(Windows): private import core.sys.windows.windows; pragma(lib, "advapi32.lib"); immutable bool isWow64; shared static this() { // WOW64 is the x86 emulator that allows 32-bit Windows-based applications to run seamlessly on 64-bit Windows // IsWow64Process Function - Minimum supported client - Windows Vista, Windows XP with SP2 alias fptr_t = extern(Windows) BOOL function(HANDLE, PBOOL); auto hKernel = GetModuleHandleA("kernel32"); auto IsWow64Process = cast(fptr_t) GetProcAddress(hKernel, "IsWow64Process"); BOOL bIsWow64; isWow64 = IsWow64Process && IsWow64Process(GetCurrentProcess(), &bIsWow64) && bIsWow64; } HMODULE hAdvapi32 = null; extern (Windows) { LONG function(in HKEY hkey, in LPCWSTR lpSubKey, in REGSAM samDesired, in DWORD reserved) pRegDeleteKeyExW; } void loadAdvapi32() { if (!hAdvapi32) { hAdvapi32 = LoadLibraryA("Advapi32.dll"); if (!hAdvapi32) throw new Exception(`LoadLibraryA("Advapi32.dll")`); pRegDeleteKeyExW = cast(typeof(pRegDeleteKeyExW)) GetProcAddress(hAdvapi32 , "RegDeleteKeyExW"); if (!pRegDeleteKeyExW) throw new Exception(`GetProcAddress(hAdvapi32 , "RegDeleteKeyExW")`); } } // It will free Advapi32.dll, which may be loaded for RegDeleteKeyEx function private void freeAdvapi32() { if (hAdvapi32) { if (!FreeLibrary(hAdvapi32)) throw new Exception(`FreeLibrary("Advapi32.dll")`); hAdvapi32 = null; pRegDeleteKeyExW = null; } } static ~this() { freeAdvapi32(); } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/scopebuffer.d0000664000175000017500000002533212776215007022177 0ustar kaikai/* * Copyright: 2014 by Digital Mars * License: $(LINK2 http://boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright * Source: $(PHOBOSSRC std/internal/_scopebuffer.d) */ module std.internal.scopebuffer; //debug=ScopeBuffer; private import core.stdc.stdlib : realloc; private import std.traits; /************************************** * ScopeBuffer encapsulates using a local array as a temporary buffer. * It is initialized with the local array that should be large enough for * most uses. If the need exceeds the size, ScopeBuffer will resize it * using malloc() and friends. * * ScopeBuffer cannot contain more than (uint.max-16)/2 elements. * * ScopeBuffer is an OutputRange. * * Since ScopeBuffer potentially stores elements of type T in malloc'd memory, * those elements are not scanned when the GC collects. This can cause * memory corruption. Do not use ScopeBuffer when elements of type T point * to the GC heap. * * Example: --- import core.stdc.stdio; import std.internal.scopebuffer; void main() { char[2] buf = void; auto textbuf = ScopeBuffer!char(buf); scope(exit) textbuf.free(); // necessary for cleanup // Put characters and strings into textbuf, verify they got there textbuf.put('a'); textbuf.put('x'); textbuf.put("abc"); assert(textbuf.length == 5); assert(textbuf[1..3] == "xa"); assert(textbuf[3] == 'b'); // Can shrink it textbuf.length = 3; assert(textbuf[0..textbuf.length] == "axa"); assert(textbuf[textbuf.length - 1] == 'a'); assert(textbuf[1..3] == "xa"); textbuf.put('z'); assert(textbuf[] == "axaz"); // Can shrink it to 0 size, and reuse same memory textbuf.length = 0; } --- * It is invalid to access ScopeBuffer's contents when ScopeBuffer goes out of scope. * Hence, copying the contents are necessary to keep them around: --- import std.internal.scopebuffer; string cat(string s1, string s2) { char[10] tmpbuf = void; auto textbuf = ScopeBuffer!char(tmpbuf); scope(exit) textbuf.free(); textbuf.put(s1); textbuf.put(s2); textbuf.put("even more"); return textbuf[].idup; } --- * ScopeBuffer is intended for high performance usages in $(D @system) and $(D @trusted) code. * It is designed to fit into two 64 bit registers, again for high performance use. * If used incorrectly, memory leaks and corruption can result. Be sure to use * $(D scope(exit) textbuf.free();) for proper cleanup, and do not refer to a ScopeBuffer * instance's contents after $(D ScopeBuffer.free()) has been called. * * The realloc parameter defaults to C's realloc(). Another can be supplied to override it. * * ScopeBuffer instances may be copied, as in: --- textbuf = doSomething(textbuf, args); --- * which can be very efficent, but these must be regarded as a move rather than a copy. * Additionally, the code between passing and returning the instance must not throw * exceptions, otherwise when ScopeBuffer.free() is called, memory may get corrupted. */ @system struct ScopeBuffer(T, alias realloc = /*core.stdc.stdlib*/.realloc) if (isAssignable!T && !hasElaborateDestructor!T && !hasElaborateCopyConstructor!T && !hasElaborateAssign!T) { import core.stdc.string : memcpy; import core.exception : onOutOfMemoryError; /************************** * Initialize with buf to use as scratch buffer space. * Params: * buf = Scratch buffer space, must have length that is even * Example: * --- * ubyte[10] tmpbuf = void; * auto sbuf = ScopeBuffer!ubyte(tmpbuf); * --- * If buf was created by the same realloc passed as a parameter * to ScopeBuffer, then the contents of ScopeBuffer can be extracted without needing * to copy them, and ScopeBuffer.free() will not need to be called. */ this(T[] buf) in { assert(!(buf.length & wasResized)); // assure even length of scratch buffer space assert(buf.length <= uint.max); // because we cast to uint later } body { this.buf = buf.ptr; this.bufLen = cast(uint)buf.length; } unittest { ubyte[10] tmpbuf = void; auto sbuf = ScopeBuffer!ubyte(tmpbuf); } /************************** * Releases any memory used. * This will invalidate any references returned by the [] operator. * A destructor is not used, because that would make it not POD * (Plain Old Data) and it could not be placed in registers. */ void free() { debug(ScopeBuffer) buf[0 .. bufLen] = 0; if (bufLen & wasResized) realloc(buf, 0); buf = null; bufLen = 0; used = 0; } /**************************** * Copying of ScopeBuffer is not allowed. */ //@disable this(this); /************************ * Append element c to the buffer. * This member function makes ScopeBuffer an OutputRange. */ void put(T c) { /* j will get enregistered, while used will not because resize() may change used */ const j = used; if (j == bufLen) { assert(j <= (uint.max - 16) / 2); resize(j * 2 + 16); } buf[j] = c; used = j + 1; } /************************ * Append array s to the buffer. * * If $(D const(T)) can be converted to $(D T), then put will accept * $(D const(T)[]) as input. It will accept a $(D T[]) otherwise. */ private alias CT = Select!(is(const(T) : T), const(T), T); /// ditto void put(CT[] s) { const newlen = used + s.length; assert((cast(ulong)used + s.length) <= uint.max); const len = bufLen; if (newlen > len) { assert(len <= uint.max / 2); resize(newlen <= len * 2 ? len * 2 : newlen); } buf[used .. newlen] = s[]; used = cast(uint)newlen; } /****** * Retrieve a slice into the result. * Returns: * A slice into the temporary buffer that is only * valid until the next put() or ScopeBuffer goes out of scope. */ @system inout(T)[] opSlice(size_t lower, size_t upper) inout in { assert(lower <= bufLen); assert(upper <= bufLen); assert(lower <= upper); } body { return buf[lower .. upper]; } /// ditto @system inout(T)[] opSlice() inout { assert(used <= bufLen); return buf[0 .. used]; } /******* * Returns: * the element at index i. */ ref inout(T) opIndex(size_t i) inout { assert(i < bufLen); return buf[i]; } /*** * Returns: * the number of elements in the ScopeBuffer */ @property size_t length() const { return used; } /*** * Used to shrink the length of the buffer, * typically to 0 so the buffer can be reused. * Cannot be used to extend the length of the buffer. */ @property void length(size_t i) in { assert(i <= this.used); } body { this.used = cast(uint)i; } alias opDollar = length; private: T* buf; // Using uint instead of size_t so the struct fits in 2 registers in 64 bit code uint bufLen; enum wasResized = 1; // this bit is set in bufLen if we control the memory uint used; void resize(size_t newsize) in { assert(newsize <= uint.max); } body { //writefln("%s: oldsize %s newsize %s", id, buf.length, newsize); newsize |= wasResized; void *newBuf = realloc((bufLen & wasResized) ? buf : null, newsize * T.sizeof); if (!newBuf) onOutOfMemoryError(); if (!(bufLen & wasResized)) { memcpy(newBuf, buf, used * T.sizeof); debug(ScopeBuffer) buf[0 .. bufLen] = 0; } buf = cast(T*)newBuf; bufLen = cast(uint)newsize; /* This function is called only rarely, * inlining results in poorer register allocation. */ version (DigitalMars) /* With dmd, a fake loop will prevent inlining. * Using a hack until a language enhancement is implemented. */ while (1) { break; } } } unittest { import core.stdc.stdio; import std.range; char[2] tmpbuf = void; { // Exercise all the lines of code except for assert(0)'s auto textbuf = ScopeBuffer!char(tmpbuf); scope(exit) textbuf.free(); static assert(isOutputRange!(ScopeBuffer!char, char)); textbuf.put('a'); textbuf.put('x'); textbuf.put("abc"); // tickle put([])'s resize assert(textbuf.length == 5); assert(textbuf[1..3] == "xa"); assert(textbuf[3] == 'b'); textbuf.length = textbuf.length - 1; assert(textbuf[0..textbuf.length] == "axab"); textbuf.length = 3; assert(textbuf[0..textbuf.length] == "axa"); assert(textbuf[textbuf.length - 1] == 'a'); assert(textbuf[1..3] == "xa"); textbuf.put(cast(dchar)'z'); assert(textbuf[] == "axaz"); textbuf.length = 0; // reset for reuse assert(textbuf.length == 0); foreach (char c; "asdf;lasdlfaklsdjfalksdjfa;lksdjflkajsfdasdfkja;sdlfj") { textbuf.put(c); // tickle put(c)'s resize } assert(textbuf[] == "asdf;lasdlfaklsdjfalksdjfa;lksdjflkajsfdasdfkja;sdlfj"); } // run destructor on textbuf here } unittest { string cat(string s1, string s2) { char[10] tmpbuf = void; auto textbuf = ScopeBuffer!char(tmpbuf); scope(exit) textbuf.free(); textbuf.put(s1); textbuf.put(s2); textbuf.put("even more"); return textbuf[].idup; } auto s = cat("hello", "betty"); assert(s == "hellobettyeven more"); } // const unittest { char[10] tmpbuf = void; auto textbuf = ScopeBuffer!char(tmpbuf); scope(exit) textbuf.free(); foreach(i; 0..10) textbuf.put('w'); const csb = textbuf; const elem = csb[3]; const slice0 = csb[0..5]; const slice1 = csb[]; } /********************************* * This is a slightly simpler way to create a ScopeBuffer instance * that uses type deduction. * Params: * tmpbuf = the initial buffer to use * Returns: * an instance of ScopeBuffer * Example: --- ubyte[10] tmpbuf = void; auto sb = scopeBuffer(tmpbuf); scope(exit) sp.free(); --- */ auto scopeBuffer(T)(T[] tmpbuf) { return ScopeBuffer!T(tmpbuf); } unittest { ubyte[10] tmpbuf = void; auto sb = scopeBuffer(tmpbuf); scope(exit) sb.free(); } unittest { ScopeBuffer!(int*) b; int*[] s; b.put(s); ScopeBuffer!char c; string s1; char[] s2; c.put(s1); c.put(s2); } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/unicode_comp.d0000664000175000017500000057533012776215007022350 0ustar kaikaimodule std.internal.unicode_comp; import std.internal.unicode_tables; @safe pure nothrow @nogc: static if(size_t.sizeof == 8) { //6976 bytes enum combiningClassTrieEntries = TrieEntry!(ubyte, 8, 7, 6)([ 0x0, 0x20, 0x120], [ 0x100, 0x400, 0x1240], [ 0x402030202020100, 0x206020202020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x20001, 0x300000000, 0x5000400000000, 0x8000000070006, 0xb0000000a0009, 0xe0000000d000c, 0x11000f0010000f, 0x11000f0011000f, 0x1100000011000f, 0x11000f00120000, 0x13000000110000, 0x17001600150014, 0x1b001a00190018, 0x1d0000001c, 0x0, 0x0, 0x1e0000, 0x0, 0x0, 0x0, 0x2000000000001f, 0x2100000000, 0x22, 0x240023, 0x28002700260025, 0x2a000000000029, 0x2b000000000000, 0x0, 0x0, 0x2c000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d000000000000, 0x2f0000002e0000, 0x0, 0x0, 0x3100000030, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34003300320000, 0x0, 0x36000000000035, 0x3a003900380037, 0x3c003b00000000, 0x3d000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x40000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x41, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4200350000, 0x3a000000000043, 0x0, 0x0, 0x0, 0x0, 0x4400000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4600450000, 0x470000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6e6e6e6e6, 0xe6e6e6e6e6e6e6e6, 0xdcdce8e6e6e6e6e6, 0xdcdcdcdcd8e8dcdc, 0xcadcdcdcdccacadc, 0xdcdcdcdcdcdcdcca, 0x1010101dcdcdcdc, 0xe6e6e6dcdcdcdc01, 0xdce6f0e6e6e6e6e6, 0xdcdce6e6e6dcdc, 0xe6dcdcdcdce6e6e6, 0xe9eaeae9e6dcdce8, 0xe6e6e6e6e6e9eaea, 0xe6e6e6e6e6e6e6e6, 0x0, 0x0, 0xe6e6e6e6e6000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6dce6e6e6e6dc00, 0xe6e6e6e6dcdee6e6, 0xdcdcdcdcdcdce6e6, 0xe6e4dee6e6dce6e6, 0x11100f0e0d0c0b0a, 0x1700161514131312, 0x1200dce600191800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6e6e6e6e6, 0x201f1e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f1e1d1c1b000000, 0xe6dcdce6e6222120, 0xdce6e6dce6e6e6e6, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, 0xe6e6000000000000, 0xe60000e6e6e6e6e6, 0xe60000e6dce6e6e6, 0xdce6e6dc00e6, 0x0, 0x0, 0x0, 0x0, 0x2400, 0x0, 0x0, 0x0, 0xdce6e6dce6e6dce6, 0xe6dce6dcdce6dcdc, 0xe6dce6dce6dce6e6, 0xe6e6dc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6e6000000, 0xe6dce6e6, 0x0, 0x0, 0x0, 0xe6e6000000000000, 0xe6e6e6e6e600e6e6, 0xe6e6e600e6e6e6e6, 0xe6e6e6e6e600, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdcdcdc00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6dce6e600000000, 0xdcdcdce6e6e6dce6, 0xe6dce6e6e61d1c1b, 0xe6e6e6e6dcdce6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x700000000, 0x0, 0x90000000000, 0xe6e6dce600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90000000000, 0x5b540000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x96767, 0x0, 0x6b6b6b6b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7676, 0x0, 0x7a7a7a7a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdcdc, 0x0, 0x0, 0xdc00dc0000000000, 0xd800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8400828100, 0x828282820000, 0xe6e60009e6e60082, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdc000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x700000000000000, 0x90900, 0x0, 0xdc0000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e60000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x900000000, 0x0, 0x0, 0x0, 0x900000000, 0x0, 0x0, 0x0, 0x90000, 0xe60000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdce6de00, 0x0, 0x0, 0xe600000000000000, 0xdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0xe6e6e60000000000, 0xdc0000e6e6e6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x700000000, 0x0, 0x900000000, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6dce6000000, 0xe6e6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9090000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7000000000000, 0x0, 0x9090000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x700000000000000, 0x0, 0x0, 0x0, 0xdcdcdc0100e6e6e6, 0xdcdcdcdce6e6dcdc, 0x1010101010100e6, 0xdc0000000001, 0xe600000000, 0x0, 0xe6e6e6e6e6dce6e6, 0xdcd6eae6e6dce6e6, 0xe6e6e6e6e6e6e6ca, 0xe6e6e6e6e6e6e6e6, 0xe6e6e6e6e6e6e6, 0x0, 0x0, 0xdce6dce900000000, 0x0, 0x0, 0xe6e6e6e60101e6e6, 0xe6e6010101, 0xe60101000000e600, 0xdcdcdcdc0101e6dc, 0xe6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe600000000000000, 0xe6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x900000000000000, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6e6e6e6e6, 0xe6e6e6e6e6e6e6e6, 0xe6e6e6e6e6e6e6e6, 0xe6e6e6e6e6e6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0e0dee8e4da0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe600000000000000, 0xe6e6e6e600000000, 0xe6e6e6e6e6e6, 0x0, 0x0, 0x0, 0xe600000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6, 0x0, 0x9000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x900000000, 0x0, 0x0, 0x0, 0xe6e6e6e6e6e6e6e6, 0xe6e6e6e6e6e6e6e6, 0xe6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdcdcdc000000, 0x0, 0x0, 0x0, 0x0, 0x9000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7000000, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe60000dce6e600e6, 0xe6e60000000000e6, 0xe600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6e6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdc0000000000, 0x0, 0xe600dc0000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x900000000dc01e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x70900, 0xe6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x909000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x709000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d8d80000000000, 0xd8d8e20000000101, 0xd8d8d8, 0xdcdcdcdcdc000000, 0xe6e6e60000dcdcdc, 0xdcdce6e6, 0x0, 0x0, 0x0, 0xe6e6e6e60000, 0x0, 0x0, 0xe6e6e60000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); enum composeIdxMask = (1<<11)-1, composeCntShift = 11; enum compositionJumpTrieEntries = TrieEntry!(ushort, 12, 9)([ 0x0, 0x400], [ 0x1000, 0x2000], [ 0x3000200010000, 0x7000600050004, 0x7000700070008, 0xa000700090007, 0x70007000c000b, 0x7000700070007, 0x700070007000d, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x700070007000e, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0x7000700070007, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff080208010800, 0x281618138003ffff, 0x383308328821301b, 0x285108507841383a, 0x8068485f185c3056, 0x3882407affff1078, 0x30a510a398903889, 0xffff30b648ad10ab, 0xffffffffffffffff, 0x28cf18cc80bcffff, 0x38ec08eb88da30d4, 0x290b110970fb40f3, 0x8122491919163110, 0x393c4134ffff1132, 0x3960115e994b4143, 0xffff317351691167, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff1979, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff217cffffffff, 0x984118209810980, 0xffff2185ffffffff, 0x989ffffffffffff, 0xffffffffffffffff, 0xffff0991198e218a, 0xffffffffffff0992, 0xffffffffffff2193, 0xffff2197ffffffff, 0x99f119d099c099b, 0xffff21a0ffffffff, 0x9a4ffffffffffff, 0xffffffffffffffff, 0xffff09ac19a921a5, 0xffffffffffff09ad, 0xffffffffffff21ae, 0x21b621b2ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x11bc11baffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff11c011be, 0xffffffffffffffff, 0xffffffffffffffff, 0x9c309c2ffffffff, 0xffffffffffffffff, 0xffffffff09c509c4, 0xffffffffffffffff, 0x9c909c809c709c6, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x9caffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff29d029cb, 0xffffffffffffffff, 0xffffffffffffffff, 0x29d5ffffffffffff, 0xffffffffffff29da, 0x9dfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x9e109e0ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x9e309e2ffffffff, 0xffffffff09e509e4, 0x9e709e6ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff09e8ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff39e9ffff, 0x29f4ffff21f0ffff, 0xffffffff39f9ffff, 0x2200ffffffffffff, 0xffffffff0a04ffff, 0xffffffff3205ffff, 0xffffffff2a0bffff, 0xffff0a11ffff0a10, 0xffffffff4212ffff, 0x321effff221affff, 0xffffffff4224ffff, 0x222cffffffffffff, 0xffffffff1230ffff, 0xffffffff4232ffff, 0x1a431a40323affff, 0xffff0a46ffffffff, 0xffff1247ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0a49ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xa4cffffffff124a, 0xa5212501a4dffff, 0xffff0a57ffff2253, 0xffff0a58ffffffff, 0x2259ffffffffffff, 0xa5dffffffffffff, 0xa5effffffffffff, 0xffffffff0a5fffff, 0xa62ffffffff1260, 0xa6812661a63ffff, 0xffff0a6dffff2269, 0xffff0a6effffffff, 0x226fffffffffffff, 0xa73ffffffffffff, 0xa74ffffffffffff, 0xffffffff0a75ffff, 0xffffffffffffffff, 0xffff0a76ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0a780a77, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0a7a0a79, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0a7c0a7b, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1a7dffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0a81ffff0a80, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0a82ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0a83ffffffff, 0xffffffff0a84ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff0a85, 0xffffffffffffffff, 0xa87ffffffff0a86, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1288ffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x1a8affffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0a8dffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xa90128effffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0a91ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xa92ffffffffffff, 0xffffffffffffffff, 0xffff1a93ffffffff, 0xffff0a96ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xa991297ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff1a9affff, 0xffffffffffff0a9d, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0a9effff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xaa0ffff0a9fffff, 0xaa2ffff0aa1ffff, 0xffffffff0aa3ffff, 0xffffffff0aa4ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0aa5ffffffff, 0xaa80aa7ffff0aa6, 0xffff0aa9ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xaab0aaaffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xaad0aacffffffff, 0xffffffffffffffff, 0xaaf0aaeffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff12b212b0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0ab50ab4, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0ab70ab6, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xac10ac022bc22b8, 0xac50ac40ac30ac2, 0xacf0ace22ca22c6, 0xad30ad20ad10ad0, 0xffffffff12d612d4, 0xffffffffffffffff, 0xffffffff12da12d8, 0xffffffffffffffff, 0xae50ae422e022dc, 0xae90ae80ae70ae6, 0xaf30af222ee22ea, 0xaf70af60af50af4, 0xffffffff1afb1af8, 0xffffffffffffffff, 0xffffffff1b011afe, 0xffffffffffffffff, 0xffffffff13061304, 0xffffffffffffffff, 0xffffffff130a1308, 0xffffffffffffffff, 0xffffffff1b0f1b0c, 0xffffffffffffffff, 0xffffffff1b12ffff, 0xffffffffffffffff, 0xb1e0b1d23192315, 0xb220b210b200b1f, 0xb2c0b2b23272323, 0xb300b2f0b2e0b2d, 0xffffffffffff0b31, 0xffffffffffff0b32, 0xffffffffffffffff, 0xffffffffffff0b33, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0b34ffffffff, 0xffffffffffffffff, 0x1b35ffffffffffff, 0xffffffffffffffff, 0xffff0b38ffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0b39ffffffff, 0xffffffffffffffff, 0xffff1b3affffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0b3effff0b3d, 0xffffffffffff0b3f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0b41ffff0b40, 0xffffffffffff0b42, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xb43ffffffffffff, 0xffffffffffffffff, 0xb45ffffffff0b44, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xb46ffffffffffff, 0xffffffff0b47ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff0b48, 0xb49ffffffffffff, 0xffffffff0b4affff, 0xffffffffffff0b4b, 0xffffffff0b4cffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0b4dffff, 0xffffffff0b4f0b4e, 0xffffffffffffffff, 0xffffffffffffffff, 0xb510b50ffffffff, 0xb530b52ffffffff, 0xb550b54ffffffff, 0xffffffff0b570b56, 0xb590b58ffffffff, 0xb5b0b5affffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0b5d0b5cffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0b5effffffff, 0xffffffffffffffff, 0xb61ffff0b600b5f, 0xffffffffffffffff, 0xb630b62ffffffff, 0xffffffff0b650b64, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0b66ffffffff, 0xb67ffffffffffff, 0xb69ffff0b68ffff, 0xb6bffff0b6affff, 0xb6dffff0b6cffff, 0xb6fffff0b6effff, 0xb71ffff0b70ffff, 0xffffffff0b72ffff, 0xffff0b74ffff0b73, 0xffffffffffff0b75, 0x1376ffffffffffff, 0xffff1378ffffffff, 0xffffffff137affff, 0x137effffffff137c, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0b80ffff, 0xffffffffffffffff, 0xffff0b81ffffffff, 0xb82ffffffffffff, 0xb84ffff0b83ffff, 0xb86ffff0b85ffff, 0xb88ffff0b87ffff, 0xb8affff0b89ffff, 0xb8cffff0b8bffff, 0xffffffff0b8dffff, 0xffff0b8fffff0b8e, 0xffffffffffff0b90, 0x1391ffffffffffff, 0xffff1393ffffffff, 0xffffffff1395ffff, 0x1399ffffffff1397, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xb9bffffffffffff, 0xffff0b9e0b9d0b9c, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0b9fffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xba1ffff0ba0ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffff0ba2ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffff0ba40ba3ffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff]); @property immutable(CompEntry[]) compositionTable() { alias CE = CompEntry; static immutable CE[] t = [CE(0x00338, 0x0226e),CE(0x00338, 0x02260),CE(0x00338, 0x0226f),CE(0x00300, 0x000c0),CE(0x00301, 0x000c1),CE(0x00302, 0x000c2),CE(0x00303, 0x000c3),CE(0x00304, 0x00100),CE(0x00306, 0x00102),CE(0x00307, 0x00226),CE(0x00308, 0x000c4),CE(0x00309, 0x01ea2),CE(0x0030a, 0x000c5),CE(0x0030c, 0x001cd),CE(0x0030f, 0x00200),CE(0x00311, 0x00202),CE(0x00323, 0x01ea0),CE(0x00325, 0x01e00),CE(0x00328, 0x00104),CE(0x00307, 0x01e02),CE(0x00323, 0x01e04),CE(0x00331, 0x01e06),CE(0x00301, 0x00106),CE(0x00302, 0x00108),CE(0x00307, 0x0010a),CE(0x0030c, 0x0010c),CE(0x00327, 0x000c7),CE(0x00307, 0x01e0a),CE(0x0030c, 0x0010e),CE(0x00323, 0x01e0c),CE(0x00327, 0x01e10),CE(0x0032d, 0x01e12),CE(0x00331, 0x01e0e),CE(0x00300, 0x000c8),CE(0x00301, 0x000c9),CE(0x00302, 0x000ca),CE(0x00303, 0x01ebc),CE(0x00304, 0x00112),CE(0x00306, 0x00114),CE(0x00307, 0x00116),CE(0x00308, 0x000cb),CE(0x00309, 0x01eba),CE(0x0030c, 0x0011a),CE(0x0030f, 0x00204),CE(0x00311, 0x00206),CE(0x00323, 0x01eb8),CE(0x00327, 0x00228),CE(0x00328, 0x00118),CE(0x0032d, 0x01e18),CE(0x00330, 0x01e1a),CE(0x00307, 0x01e1e),CE(0x00301, 0x001f4),CE(0x00302, 0x0011c),CE(0x00304, 0x01e20),CE(0x00306, 0x0011e),CE(0x00307, 0x00120),CE(0x0030c, 0x001e6),CE(0x00327, 0x00122),CE(0x00302, 0x00124),CE(0x00307, 0x01e22),CE(0x00308, 0x01e26),CE(0x0030c, 0x0021e),CE(0x00323, 0x01e24),CE(0x00327, 0x01e28),CE(0x0032e, 0x01e2a),CE(0x00300, 0x000cc),CE(0x00301, 0x000cd),CE(0x00302, 0x000ce),CE(0x00303, 0x00128),CE(0x00304, 0x0012a),CE(0x00306, 0x0012c),CE(0x00307, 0x00130),CE(0x00308, 0x000cf),CE(0x00309, 0x01ec8),CE(0x0030c, 0x001cf),CE(0x0030f, 0x00208),CE(0x00311, 0x0020a),CE(0x00323, 0x01eca),CE(0x00328, 0x0012e),CE(0x00330, 0x01e2c),CE(0x00302, 0x00134),CE(0x00301, 0x01e30),CE(0x0030c, 0x001e8),CE(0x00323, 0x01e32),CE(0x00327, 0x00136),CE(0x00331, 0x01e34),CE(0x00301, 0x00139),CE(0x0030c, 0x0013d),CE(0x00323, 0x01e36),CE(0x00327, 0x0013b),CE(0x0032d, 0x01e3c),CE(0x00331, 0x01e3a),CE(0x00301, 0x01e3e),CE(0x00307, 0x01e40),CE(0x00323, 0x01e42),CE(0x00300, 0x001f8),CE(0x00301, 0x00143),CE(0x00303, 0x000d1),CE(0x00307, 0x01e44),CE(0x0030c, 0x00147),CE(0x00323, 0x01e46),CE(0x00327, 0x00145),CE(0x0032d, 0x01e4a),CE(0x00331, 0x01e48),CE(0x00300, 0x000d2),CE(0x00301, 0x000d3),CE(0x00302, 0x000d4),CE(0x00303, 0x000d5),CE(0x00304, 0x0014c),CE(0x00306, 0x0014e),CE(0x00307, 0x0022e),CE(0x00308, 0x000d6),CE(0x00309, 0x01ece),CE(0x0030b, 0x00150),CE(0x0030c, 0x001d1),CE(0x0030f, 0x0020c),CE(0x00311, 0x0020e),CE(0x0031b, 0x001a0),CE(0x00323, 0x01ecc),CE(0x00328, 0x001ea),CE(0x00301, 0x01e54),CE(0x00307, 0x01e56),CE(0x00301, 0x00154),CE(0x00307, 0x01e58),CE(0x0030c, 0x00158),CE(0x0030f, 0x00210),CE(0x00311, 0x00212),CE(0x00323, 0x01e5a),CE(0x00327, 0x00156),CE(0x00331, 0x01e5e),CE(0x00301, 0x0015a),CE(0x00302, 0x0015c),CE(0x00307, 0x01e60),CE(0x0030c, 0x00160),CE(0x00323, 0x01e62),CE(0x00326, 0x00218),CE(0x00327, 0x0015e),CE(0x00307, 0x01e6a),CE(0x0030c, 0x00164),CE(0x00323, 0x01e6c),CE(0x00326, 0x0021a),CE(0x00327, 0x00162),CE(0x0032d, 0x01e70),CE(0x00331, 0x01e6e),CE(0x00300, 0x000d9),CE(0x00301, 0x000da),CE(0x00302, 0x000db),CE(0x00303, 0x00168),CE(0x00304, 0x0016a),CE(0x00306, 0x0016c),CE(0x00308, 0x000dc),CE(0x00309, 0x01ee6),CE(0x0030a, 0x0016e),CE(0x0030b, 0x00170),CE(0x0030c, 0x001d3),CE(0x0030f, 0x00214),CE(0x00311, 0x00216),CE(0x0031b, 0x001af),CE(0x00323, 0x01ee4),CE(0x00324, 0x01e72),CE(0x00328, 0x00172),CE(0x0032d, 0x01e76),CE(0x00330, 0x01e74),CE(0x00303, 0x01e7c),CE(0x00323, 0x01e7e),CE(0x00300, 0x01e80),CE(0x00301, 0x01e82),CE(0x00302, 0x00174),CE(0x00307, 0x01e86),CE(0x00308, 0x01e84),CE(0x00323, 0x01e88),CE(0x00307, 0x01e8a),CE(0x00308, 0x01e8c),CE(0x00300, 0x01ef2),CE(0x00301, 0x000dd),CE(0x00302, 0x00176),CE(0x00303, 0x01ef8),CE(0x00304, 0x00232),CE(0x00307, 0x01e8e),CE(0x00308, 0x00178),CE(0x00309, 0x01ef6),CE(0x00323, 0x01ef4),CE(0x00301, 0x00179),CE(0x00302, 0x01e90),CE(0x00307, 0x0017b),CE(0x0030c, 0x0017d),CE(0x00323, 0x01e92),CE(0x00331, 0x01e94),CE(0x00300, 0x000e0),CE(0x00301, 0x000e1),CE(0x00302, 0x000e2),CE(0x00303, 0x000e3),CE(0x00304, 0x00101),CE(0x00306, 0x00103),CE(0x00307, 0x00227),CE(0x00308, 0x000e4),CE(0x00309, 0x01ea3),CE(0x0030a, 0x000e5),CE(0x0030c, 0x001ce),CE(0x0030f, 0x00201),CE(0x00311, 0x00203),CE(0x00323, 0x01ea1),CE(0x00325, 0x01e01),CE(0x00328, 0x00105),CE(0x00307, 0x01e03),CE(0x00323, 0x01e05),CE(0x00331, 0x01e07),CE(0x00301, 0x00107),CE(0x00302, 0x00109),CE(0x00307, 0x0010b),CE(0x0030c, 0x0010d),CE(0x00327, 0x000e7),CE(0x00307, 0x01e0b),CE(0x0030c, 0x0010f),CE(0x00323, 0x01e0d),CE(0x00327, 0x01e11),CE(0x0032d, 0x01e13),CE(0x00331, 0x01e0f),CE(0x00300, 0x000e8),CE(0x00301, 0x000e9),CE(0x00302, 0x000ea),CE(0x00303, 0x01ebd),CE(0x00304, 0x00113),CE(0x00306, 0x00115),CE(0x00307, 0x00117),CE(0x00308, 0x000eb),CE(0x00309, 0x01ebb),CE(0x0030c, 0x0011b),CE(0x0030f, 0x00205),CE(0x00311, 0x00207),CE(0x00323, 0x01eb9),CE(0x00327, 0x00229),CE(0x00328, 0x00119),CE(0x0032d, 0x01e19),CE(0x00330, 0x01e1b),CE(0x00307, 0x01e1f),CE(0x00301, 0x001f5),CE(0x00302, 0x0011d),CE(0x00304, 0x01e21),CE(0x00306, 0x0011f),CE(0x00307, 0x00121),CE(0x0030c, 0x001e7),CE(0x00327, 0x00123),CE(0x00302, 0x00125),CE(0x00307, 0x01e23),CE(0x00308, 0x01e27),CE(0x0030c, 0x0021f),CE(0x00323, 0x01e25),CE(0x00327, 0x01e29),CE(0x0032e, 0x01e2b),CE(0x00331, 0x01e96),CE(0x00300, 0x000ec),CE(0x00301, 0x000ed),CE(0x00302, 0x000ee),CE(0x00303, 0x00129),CE(0x00304, 0x0012b),CE(0x00306, 0x0012d),CE(0x00308, 0x000ef),CE(0x00309, 0x01ec9),CE(0x0030c, 0x001d0),CE(0x0030f, 0x00209),CE(0x00311, 0x0020b),CE(0x00323, 0x01ecb),CE(0x00328, 0x0012f),CE(0x00330, 0x01e2d),CE(0x00302, 0x00135),CE(0x0030c, 0x001f0),CE(0x00301, 0x01e31),CE(0x0030c, 0x001e9),CE(0x00323, 0x01e33),CE(0x00327, 0x00137),CE(0x00331, 0x01e35),CE(0x00301, 0x0013a),CE(0x0030c, 0x0013e),CE(0x00323, 0x01e37),CE(0x00327, 0x0013c),CE(0x0032d, 0x01e3d),CE(0x00331, 0x01e3b),CE(0x00301, 0x01e3f),CE(0x00307, 0x01e41),CE(0x00323, 0x01e43),CE(0x00300, 0x001f9),CE(0x00301, 0x00144),CE(0x00303, 0x000f1),CE(0x00307, 0x01e45),CE(0x0030c, 0x00148),CE(0x00323, 0x01e47),CE(0x00327, 0x00146),CE(0x0032d, 0x01e4b),CE(0x00331, 0x01e49),CE(0x00300, 0x000f2),CE(0x00301, 0x000f3),CE(0x00302, 0x000f4),CE(0x00303, 0x000f5),CE(0x00304, 0x0014d),CE(0x00306, 0x0014f),CE(0x00307, 0x0022f),CE(0x00308, 0x000f6),CE(0x00309, 0x01ecf),CE(0x0030b, 0x00151),CE(0x0030c, 0x001d2),CE(0x0030f, 0x0020d),CE(0x00311, 0x0020f),CE(0x0031b, 0x001a1),CE(0x00323, 0x01ecd),CE(0x00328, 0x001eb),CE(0x00301, 0x01e55),CE(0x00307, 0x01e57),CE(0x00301, 0x00155),CE(0x00307, 0x01e59),CE(0x0030c, 0x00159),CE(0x0030f, 0x00211),CE(0x00311, 0x00213),CE(0x00323, 0x01e5b),CE(0x00327, 0x00157),CE(0x00331, 0x01e5f),CE(0x00301, 0x0015b),CE(0x00302, 0x0015d),CE(0x00307, 0x01e61),CE(0x0030c, 0x00161),CE(0x00323, 0x01e63),CE(0x00326, 0x00219),CE(0x00327, 0x0015f),CE(0x00307, 0x01e6b),CE(0x00308, 0x01e97),CE(0x0030c, 0x00165),CE(0x00323, 0x01e6d),CE(0x00326, 0x0021b),CE(0x00327, 0x00163),CE(0x0032d, 0x01e71),CE(0x00331, 0x01e6f),CE(0x00300, 0x000f9),CE(0x00301, 0x000fa),CE(0x00302, 0x000fb),CE(0x00303, 0x00169),CE(0x00304, 0x0016b),CE(0x00306, 0x0016d),CE(0x00308, 0x000fc),CE(0x00309, 0x01ee7),CE(0x0030a, 0x0016f),CE(0x0030b, 0x00171),CE(0x0030c, 0x001d4),CE(0x0030f, 0x00215),CE(0x00311, 0x00217),CE(0x0031b, 0x001b0),CE(0x00323, 0x01ee5),CE(0x00324, 0x01e73),CE(0x00328, 0x00173),CE(0x0032d, 0x01e77),CE(0x00330, 0x01e75),CE(0x00303, 0x01e7d),CE(0x00323, 0x01e7f),CE(0x00300, 0x01e81),CE(0x00301, 0x01e83),CE(0x00302, 0x00175),CE(0x00307, 0x01e87),CE(0x00308, 0x01e85),CE(0x0030a, 0x01e98),CE(0x00323, 0x01e89),CE(0x00307, 0x01e8b),CE(0x00308, 0x01e8d),CE(0x00300, 0x01ef3),CE(0x00301, 0x000fd),CE(0x00302, 0x00177),CE(0x00303, 0x01ef9),CE(0x00304, 0x00233),CE(0x00307, 0x01e8f),CE(0x00308, 0x000ff),CE(0x00309, 0x01ef7),CE(0x0030a, 0x01e99),CE(0x00323, 0x01ef5),CE(0x00301, 0x0017a),CE(0x00302, 0x01e91),CE(0x00307, 0x0017c),CE(0x0030c, 0x0017e),CE(0x00323, 0x01e93),CE(0x00331, 0x01e95),CE(0x00300, 0x01fed),CE(0x00301, 0x00385),CE(0x00342, 0x01fc1),CE(0x00300, 0x01ea6),CE(0x00301, 0x01ea4),CE(0x00303, 0x01eaa),CE(0x00309, 0x01ea8),CE(0x00304, 0x001de),CE(0x00301, 0x001fa),CE(0x00301, 0x001fc),CE(0x00304, 0x001e2),CE(0x00301, 0x01e08),CE(0x00300, 0x01ec0),CE(0x00301, 0x01ebe),CE(0x00303, 0x01ec4),CE(0x00309, 0x01ec2),CE(0x00301, 0x01e2e),CE(0x00300, 0x01ed2),CE(0x00301, 0x01ed0),CE(0x00303, 0x01ed6),CE(0x00309, 0x01ed4),CE(0x00301, 0x01e4c),CE(0x00304, 0x0022c),CE(0x00308, 0x01e4e),CE(0x00304, 0x0022a),CE(0x00301, 0x001fe),CE(0x00300, 0x001db),CE(0x00301, 0x001d7),CE(0x00304, 0x001d5),CE(0x0030c, 0x001d9),CE(0x00300, 0x01ea7),CE(0x00301, 0x01ea5),CE(0x00303, 0x01eab),CE(0x00309, 0x01ea9),CE(0x00304, 0x001df),CE(0x00301, 0x001fb),CE(0x00301, 0x001fd),CE(0x00304, 0x001e3),CE(0x00301, 0x01e09),CE(0x00300, 0x01ec1),CE(0x00301, 0x01ebf),CE(0x00303, 0x01ec5),CE(0x00309, 0x01ec3),CE(0x00301, 0x01e2f),CE(0x00300, 0x01ed3),CE(0x00301, 0x01ed1),CE(0x00303, 0x01ed7),CE(0x00309, 0x01ed5),CE(0x00301, 0x01e4d),CE(0x00304, 0x0022d),CE(0x00308, 0x01e4f),CE(0x00304, 0x0022b),CE(0x00301, 0x001ff),CE(0x00300, 0x001dc),CE(0x00301, 0x001d8),CE(0x00304, 0x001d6),CE(0x0030c, 0x001da),CE(0x00300, 0x01eb0),CE(0x00301, 0x01eae),CE(0x00303, 0x01eb4),CE(0x00309, 0x01eb2),CE(0x00300, 0x01eb1),CE(0x00301, 0x01eaf),CE(0x00303, 0x01eb5),CE(0x00309, 0x01eb3),CE(0x00300, 0x01e14),CE(0x00301, 0x01e16),CE(0x00300, 0x01e15),CE(0x00301, 0x01e17),CE(0x00300, 0x01e50),CE(0x00301, 0x01e52),CE(0x00300, 0x01e51),CE(0x00301, 0x01e53),CE(0x00307, 0x01e64),CE(0x00307, 0x01e65),CE(0x00307, 0x01e66),CE(0x00307, 0x01e67),CE(0x00301, 0x01e78),CE(0x00301, 0x01e79),CE(0x00308, 0x01e7a),CE(0x00308, 0x01e7b),CE(0x00307, 0x01e9b),CE(0x00300, 0x01edc),CE(0x00301, 0x01eda),CE(0x00303, 0x01ee0),CE(0x00309, 0x01ede),CE(0x00323, 0x01ee2),CE(0x00300, 0x01edd),CE(0x00301, 0x01edb),CE(0x00303, 0x01ee1),CE(0x00309, 0x01edf),CE(0x00323, 0x01ee3),CE(0x00300, 0x01eea),CE(0x00301, 0x01ee8),CE(0x00303, 0x01eee),CE(0x00309, 0x01eec),CE(0x00323, 0x01ef0),CE(0x00300, 0x01eeb),CE(0x00301, 0x01ee9),CE(0x00303, 0x01eef),CE(0x00309, 0x01eed),CE(0x00323, 0x01ef1),CE(0x0030c, 0x001ee),CE(0x00304, 0x001ec),CE(0x00304, 0x001ed),CE(0x00304, 0x001e0),CE(0x00304, 0x001e1),CE(0x00306, 0x01e1c),CE(0x00306, 0x01e1d),CE(0x00304, 0x00230),CE(0x00304, 0x00231),CE(0x0030c, 0x001ef),CE(0x00300, 0x01fba),CE(0x00301, 0x00386),CE(0x00304, 0x01fb9),CE(0x00306, 0x01fb8),CE(0x00313, 0x01f08),CE(0x00314, 0x01f09),CE(0x00345, 0x01fbc),CE(0x00300, 0x01fc8),CE(0x00301, 0x00388),CE(0x00313, 0x01f18),CE(0x00314, 0x01f19),CE(0x00300, 0x01fca),CE(0x00301, 0x00389),CE(0x00313, 0x01f28),CE(0x00314, 0x01f29),CE(0x00345, 0x01fcc),CE(0x00300, 0x01fda),CE(0x00301, 0x0038a),CE(0x00304, 0x01fd9),CE(0x00306, 0x01fd8),CE(0x00308, 0x003aa),CE(0x00313, 0x01f38),CE(0x00314, 0x01f39),CE(0x00300, 0x01ff8),CE(0x00301, 0x0038c),CE(0x00313, 0x01f48),CE(0x00314, 0x01f49),CE(0x00314, 0x01fec),CE(0x00300, 0x01fea),CE(0x00301, 0x0038e),CE(0x00304, 0x01fe9),CE(0x00306, 0x01fe8),CE(0x00308, 0x003ab),CE(0x00314, 0x01f59),CE(0x00300, 0x01ffa),CE(0x00301, 0x0038f),CE(0x00313, 0x01f68),CE(0x00314, 0x01f69),CE(0x00345, 0x01ffc),CE(0x00345, 0x01fb4),CE(0x00345, 0x01fc4),CE(0x00300, 0x01f70),CE(0x00301, 0x003ac),CE(0x00304, 0x01fb1),CE(0x00306, 0x01fb0),CE(0x00313, 0x01f00),CE(0x00314, 0x01f01),CE(0x00342, 0x01fb6),CE(0x00345, 0x01fb3),CE(0x00300, 0x01f72),CE(0x00301, 0x003ad),CE(0x00313, 0x01f10),CE(0x00314, 0x01f11),CE(0x00300, 0x01f74),CE(0x00301, 0x003ae),CE(0x00313, 0x01f20),CE(0x00314, 0x01f21),CE(0x00342, 0x01fc6),CE(0x00345, 0x01fc3),CE(0x00300, 0x01f76),CE(0x00301, 0x003af),CE(0x00304, 0x01fd1),CE(0x00306, 0x01fd0),CE(0x00308, 0x003ca),CE(0x00313, 0x01f30),CE(0x00314, 0x01f31),CE(0x00342, 0x01fd6),CE(0x00300, 0x01f78),CE(0x00301, 0x003cc),CE(0x00313, 0x01f40),CE(0x00314, 0x01f41),CE(0x00313, 0x01fe4),CE(0x00314, 0x01fe5),CE(0x00300, 0x01f7a),CE(0x00301, 0x003cd),CE(0x00304, 0x01fe1),CE(0x00306, 0x01fe0),CE(0x00308, 0x003cb),CE(0x00313, 0x01f50),CE(0x00314, 0x01f51),CE(0x00342, 0x01fe6),CE(0x00300, 0x01f7c),CE(0x00301, 0x003ce),CE(0x00313, 0x01f60),CE(0x00314, 0x01f61),CE(0x00342, 0x01ff6),CE(0x00345, 0x01ff3),CE(0x00300, 0x01fd2),CE(0x00301, 0x00390),CE(0x00342, 0x01fd7),CE(0x00300, 0x01fe2),CE(0x00301, 0x003b0),CE(0x00342, 0x01fe7),CE(0x00345, 0x01ff4),CE(0x00301, 0x003d3),CE(0x00308, 0x003d4),CE(0x00308, 0x00407),CE(0x00306, 0x004d0),CE(0x00308, 0x004d2),CE(0x00301, 0x00403),CE(0x00300, 0x00400),CE(0x00306, 0x004d6),CE(0x00308, 0x00401),CE(0x00306, 0x004c1),CE(0x00308, 0x004dc),CE(0x00308, 0x004de),CE(0x00300, 0x0040d),CE(0x00304, 0x004e2),CE(0x00306, 0x00419),CE(0x00308, 0x004e4),CE(0x00301, 0x0040c),CE(0x00308, 0x004e6),CE(0x00304, 0x004ee),CE(0x00306, 0x0040e),CE(0x00308, 0x004f0),CE(0x0030b, 0x004f2),CE(0x00308, 0x004f4),CE(0x00308, 0x004f8),CE(0x00308, 0x004ec),CE(0x00306, 0x004d1),CE(0x00308, 0x004d3),CE(0x00301, 0x00453),CE(0x00300, 0x00450),CE(0x00306, 0x004d7),CE(0x00308, 0x00451),CE(0x00306, 0x004c2),CE(0x00308, 0x004dd),CE(0x00308, 0x004df),CE(0x00300, 0x0045d),CE(0x00304, 0x004e3),CE(0x00306, 0x00439),CE(0x00308, 0x004e5),CE(0x00301, 0x0045c),CE(0x00308, 0x004e7),CE(0x00304, 0x004ef),CE(0x00306, 0x0045e),CE(0x00308, 0x004f1),CE(0x0030b, 0x004f3),CE(0x00308, 0x004f5),CE(0x00308, 0x004f9),CE(0x00308, 0x004ed),CE(0x00308, 0x00457),CE(0x0030f, 0x00476),CE(0x0030f, 0x00477),CE(0x00308, 0x004da),CE(0x00308, 0x004db),CE(0x00308, 0x004ea),CE(0x00308, 0x004eb),CE(0x00653, 0x00622),CE(0x00654, 0x00623),CE(0x00655, 0x00625),CE(0x00654, 0x00624),CE(0x00654, 0x00626),CE(0x00654, 0x006c2),CE(0x00654, 0x006d3),CE(0x00654, 0x006c0),CE(0x0093c, 0x00929),CE(0x0093c, 0x00931),CE(0x0093c, 0x00934),CE(0x009be, 0x009cb),CE(0x009d7, 0x009cc),CE(0x00b3e, 0x00b4b),CE(0x00b56, 0x00b48),CE(0x00b57, 0x00b4c),CE(0x00bd7, 0x00b94),CE(0x00bbe, 0x00bca),CE(0x00bd7, 0x00bcc),CE(0x00bbe, 0x00bcb),CE(0x00c56, 0x00c48),CE(0x00cd5, 0x00cc0),CE(0x00cc2, 0x00cca),CE(0x00cd5, 0x00cc7),CE(0x00cd6, 0x00cc8),CE(0x00cd5, 0x00ccb),CE(0x00d3e, 0x00d4a),CE(0x00d57, 0x00d4c),CE(0x00d3e, 0x00d4b),CE(0x00dca, 0x00dda),CE(0x00dcf, 0x00ddc),CE(0x00ddf, 0x00dde),CE(0x00dca, 0x00ddd),CE(0x0102e, 0x01026),CE(0x01b35, 0x01b06),CE(0x01b35, 0x01b08),CE(0x01b35, 0x01b0a),CE(0x01b35, 0x01b0c),CE(0x01b35, 0x01b0e),CE(0x01b35, 0x01b12),CE(0x01b35, 0x01b3b),CE(0x01b35, 0x01b3d),CE(0x01b35, 0x01b40),CE(0x01b35, 0x01b41),CE(0x01b35, 0x01b43),CE(0x00304, 0x01e38),CE(0x00304, 0x01e39),CE(0x00304, 0x01e5c),CE(0x00304, 0x01e5d),CE(0x00307, 0x01e68),CE(0x00307, 0x01e69),CE(0x00302, 0x01eac),CE(0x00306, 0x01eb6),CE(0x00302, 0x01ead),CE(0x00306, 0x01eb7),CE(0x00302, 0x01ec6),CE(0x00302, 0x01ec7),CE(0x00302, 0x01ed8),CE(0x00302, 0x01ed9),CE(0x00300, 0x01f02),CE(0x00301, 0x01f04),CE(0x00342, 0x01f06),CE(0x00345, 0x01f80),CE(0x00300, 0x01f03),CE(0x00301, 0x01f05),CE(0x00342, 0x01f07),CE(0x00345, 0x01f81),CE(0x00345, 0x01f82),CE(0x00345, 0x01f83),CE(0x00345, 0x01f84),CE(0x00345, 0x01f85),CE(0x00345, 0x01f86),CE(0x00345, 0x01f87),CE(0x00300, 0x01f0a),CE(0x00301, 0x01f0c),CE(0x00342, 0x01f0e),CE(0x00345, 0x01f88),CE(0x00300, 0x01f0b),CE(0x00301, 0x01f0d),CE(0x00342, 0x01f0f),CE(0x00345, 0x01f89),CE(0x00345, 0x01f8a),CE(0x00345, 0x01f8b),CE(0x00345, 0x01f8c),CE(0x00345, 0x01f8d),CE(0x00345, 0x01f8e),CE(0x00345, 0x01f8f),CE(0x00300, 0x01f12),CE(0x00301, 0x01f14),CE(0x00300, 0x01f13),CE(0x00301, 0x01f15),CE(0x00300, 0x01f1a),CE(0x00301, 0x01f1c),CE(0x00300, 0x01f1b),CE(0x00301, 0x01f1d),CE(0x00300, 0x01f22),CE(0x00301, 0x01f24),CE(0x00342, 0x01f26),CE(0x00345, 0x01f90),CE(0x00300, 0x01f23),CE(0x00301, 0x01f25),CE(0x00342, 0x01f27),CE(0x00345, 0x01f91),CE(0x00345, 0x01f92),CE(0x00345, 0x01f93),CE(0x00345, 0x01f94),CE(0x00345, 0x01f95),CE(0x00345, 0x01f96),CE(0x00345, 0x01f97),CE(0x00300, 0x01f2a),CE(0x00301, 0x01f2c),CE(0x00342, 0x01f2e),CE(0x00345, 0x01f98),CE(0x00300, 0x01f2b),CE(0x00301, 0x01f2d),CE(0x00342, 0x01f2f),CE(0x00345, 0x01f99),CE(0x00345, 0x01f9a),CE(0x00345, 0x01f9b),CE(0x00345, 0x01f9c),CE(0x00345, 0x01f9d),CE(0x00345, 0x01f9e),CE(0x00345, 0x01f9f),CE(0x00300, 0x01f32),CE(0x00301, 0x01f34),CE(0x00342, 0x01f36),CE(0x00300, 0x01f33),CE(0x00301, 0x01f35),CE(0x00342, 0x01f37),CE(0x00300, 0x01f3a),CE(0x00301, 0x01f3c),CE(0x00342, 0x01f3e),CE(0x00300, 0x01f3b),CE(0x00301, 0x01f3d),CE(0x00342, 0x01f3f),CE(0x00300, 0x01f42),CE(0x00301, 0x01f44),CE(0x00300, 0x01f43),CE(0x00301, 0x01f45),CE(0x00300, 0x01f4a),CE(0x00301, 0x01f4c),CE(0x00300, 0x01f4b),CE(0x00301, 0x01f4d),CE(0x00300, 0x01f52),CE(0x00301, 0x01f54),CE(0x00342, 0x01f56),CE(0x00300, 0x01f53),CE(0x00301, 0x01f55),CE(0x00342, 0x01f57),CE(0x00300, 0x01f5b),CE(0x00301, 0x01f5d),CE(0x00342, 0x01f5f),CE(0x00300, 0x01f62),CE(0x00301, 0x01f64),CE(0x00342, 0x01f66),CE(0x00345, 0x01fa0),CE(0x00300, 0x01f63),CE(0x00301, 0x01f65),CE(0x00342, 0x01f67),CE(0x00345, 0x01fa1),CE(0x00345, 0x01fa2),CE(0x00345, 0x01fa3),CE(0x00345, 0x01fa4),CE(0x00345, 0x01fa5),CE(0x00345, 0x01fa6),CE(0x00345, 0x01fa7),CE(0x00300, 0x01f6a),CE(0x00301, 0x01f6c),CE(0x00342, 0x01f6e),CE(0x00345, 0x01fa8),CE(0x00300, 0x01f6b),CE(0x00301, 0x01f6d),CE(0x00342, 0x01f6f),CE(0x00345, 0x01fa9),CE(0x00345, 0x01faa),CE(0x00345, 0x01fab),CE(0x00345, 0x01fac),CE(0x00345, 0x01fad),CE(0x00345, 0x01fae),CE(0x00345, 0x01faf),CE(0x00345, 0x01fb2),CE(0x00345, 0x01fc2),CE(0x00345, 0x01ff2),CE(0x00345, 0x01fb7),CE(0x00300, 0x01fcd),CE(0x00301, 0x01fce),CE(0x00342, 0x01fcf),CE(0x00345, 0x01fc7),CE(0x00345, 0x01ff7),CE(0x00300, 0x01fdd),CE(0x00301, 0x01fde),CE(0x00342, 0x01fdf),CE(0x00338, 0x0219a),CE(0x00338, 0x0219b),CE(0x00338, 0x021ae),CE(0x00338, 0x021cd),CE(0x00338, 0x021cf),CE(0x00338, 0x021ce),CE(0x00338, 0x02204),CE(0x00338, 0x02209),CE(0x00338, 0x0220c),CE(0x00338, 0x02224),CE(0x00338, 0x02226),CE(0x00338, 0x02241),CE(0x00338, 0x02244),CE(0x00338, 0x02247),CE(0x00338, 0x02249),CE(0x00338, 0x0226d),CE(0x00338, 0x02262),CE(0x00338, 0x02270),CE(0x00338, 0x02271),CE(0x00338, 0x02274),CE(0x00338, 0x02275),CE(0x00338, 0x02278),CE(0x00338, 0x02279),CE(0x00338, 0x02280),CE(0x00338, 0x02281),CE(0x00338, 0x022e0),CE(0x00338, 0x022e1),CE(0x00338, 0x02284),CE(0x00338, 0x02285),CE(0x00338, 0x02288),CE(0x00338, 0x02289),CE(0x00338, 0x022e2),CE(0x00338, 0x022e3),CE(0x00338, 0x022ac),CE(0x00338, 0x022ad),CE(0x00338, 0x022ae),CE(0x00338, 0x022af),CE(0x00338, 0x022ea),CE(0x00338, 0x022eb),CE(0x00338, 0x022ec),CE(0x00338, 0x022ed),CE(0x03099, 0x03094),CE(0x03099, 0x0304c),CE(0x03099, 0x0304e),CE(0x03099, 0x03050),CE(0x03099, 0x03052),CE(0x03099, 0x03054),CE(0x03099, 0x03056),CE(0x03099, 0x03058),CE(0x03099, 0x0305a),CE(0x03099, 0x0305c),CE(0x03099, 0x0305e),CE(0x03099, 0x03060),CE(0x03099, 0x03062),CE(0x03099, 0x03065),CE(0x03099, 0x03067),CE(0x03099, 0x03069),CE(0x03099, 0x03070),CE(0x0309a, 0x03071),CE(0x03099, 0x03073),CE(0x0309a, 0x03074),CE(0x03099, 0x03076),CE(0x0309a, 0x03077),CE(0x03099, 0x03079),CE(0x0309a, 0x0307a),CE(0x03099, 0x0307c),CE(0x0309a, 0x0307d),CE(0x03099, 0x0309e),CE(0x03099, 0x030f4),CE(0x03099, 0x030ac),CE(0x03099, 0x030ae),CE(0x03099, 0x030b0),CE(0x03099, 0x030b2),CE(0x03099, 0x030b4),CE(0x03099, 0x030b6),CE(0x03099, 0x030b8),CE(0x03099, 0x030ba),CE(0x03099, 0x030bc),CE(0x03099, 0x030be),CE(0x03099, 0x030c0),CE(0x03099, 0x030c2),CE(0x03099, 0x030c5),CE(0x03099, 0x030c7),CE(0x03099, 0x030c9),CE(0x03099, 0x030d0),CE(0x0309a, 0x030d1),CE(0x03099, 0x030d3),CE(0x0309a, 0x030d4),CE(0x03099, 0x030d6),CE(0x0309a, 0x030d7),CE(0x03099, 0x030d9),CE(0x0309a, 0x030da),CE(0x03099, 0x030dc),CE(0x0309a, 0x030dd),CE(0x03099, 0x030f7),CE(0x03099, 0x030f8),CE(0x03099, 0x030f9),CE(0x03099, 0x030fa),CE(0x03099, 0x030fe),CE(0x110ba, 0x1109a),CE(0x110ba, 0x1109c),CE(0x110ba, 0x110ab),CE(0x11127, 0x1112e),CE(0x11127, 0x1112f),]; return t; } } static if(size_t.sizeof == 4) { //6976 bytes enum combiningClassTrieEntries = TrieEntry!(ubyte, 8, 7, 6)([ 0x0, 0x40, 0x240], [ 0x100, 0x400, 0x1240], [ 0x2020100, 0x4020302, 0x2020205, 0x2060202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20001, 0x0, 0x0, 0x3, 0x0, 0x50004, 0x70006, 0x80000, 0xa0009, 0xb0000, 0xd000c, 0xe0000, 0x10000f, 0x11000f, 0x11000f, 0x11000f, 0x11000f, 0x110000, 0x120000, 0x11000f, 0x110000, 0x130000, 0x150014, 0x170016, 0x190018, 0x1b001a, 0x1c, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x1e0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x200000, 0x0, 0x21, 0x22, 0x0, 0x240023, 0x0, 0x260025, 0x280027, 0x29, 0x2a0000, 0x0, 0x2b0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d0000, 0x2e0000, 0x2f0000, 0x0, 0x0, 0x0, 0x0, 0x30, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x320000, 0x340033, 0x0, 0x0, 0x35, 0x360000, 0x380037, 0x3a0039, 0x0, 0x3c003b, 0x0, 0x3d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x41, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x350000, 0x42, 0x43, 0x3a0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x450000, 0x46, 0x470000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xdcdce8e6, 0xd8e8dcdc, 0xdcdcdcdc, 0xdccacadc, 0xcadcdcdc, 0xdcdcdcca, 0xdcdcdcdc, 0xdcdcdcdc, 0x1010101, 0xdcdcdc01, 0xe6e6e6dc, 0xe6e6e6e6, 0xdce6f0e6, 0xe6e6dcdc, 0xdcdce6, 0xdce6e6e6, 0xe6dcdcdc, 0xe6dcdce8, 0xe9eaeae9, 0xe6e9eaea, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0x0, 0x0, 0x0, 0x0, 0xe6000000, 0xe6e6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6dc00, 0xe6dce6e6, 0xdcdee6e6, 0xe6e6e6e6, 0xdcdce6e6, 0xdcdcdcdc, 0xe6dce6e6, 0xe6e4dee6, 0xd0c0b0a, 0x11100f0e, 0x14131312, 0x17001615, 0x191800, 0x1200dce6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6, 0xe6e6e6e6, 0x201f1e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b000000, 0x1f1e1d1c, 0xe6222120, 0xe6dcdce6, 0xe6e6e6e6, 0xdce6e6dc, 0x0, 0x0, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e60000, 0xe6e6e6e6, 0xe60000e6, 0xdce6e6e6, 0xe60000e6, 0xe6dc00e6, 0xdce6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6dce6, 0xdce6e6dc, 0xdce6dcdc, 0xe6dce6dc, 0xe6dce6e6, 0xe6dce6dc, 0xe6e6dc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6000000, 0xe6e6e6e6, 0xe6dce6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e60000, 0xe600e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e600, 0xe6e6e600, 0xe6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdcdcdc00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6dce6e6, 0xe6e6dce6, 0xdcdcdce6, 0xe61d1c1b, 0xe6dce6e6, 0xe6dcdce6, 0xe6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x900, 0xe6dce600, 0xe6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x900, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x900, 0x0, 0x5b5400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x96767, 0x0, 0x0, 0x0, 0x6b6b6b6b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7676, 0x0, 0x0, 0x0, 0x7a7a7a7a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdcdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdc00dc00, 0xd800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x828100, 0x84, 0x82820000, 0x8282, 0xe6e60082, 0xe6e60009, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdc0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7000000, 0x90900, 0x0, 0x0, 0x0, 0x0, 0xdc00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90000, 0x0, 0x0, 0xe600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdce6de00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6000000, 0xdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0xe6e6e600, 0xe6e6e6e6, 0xdc0000e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6000000, 0xe6e6e6dc, 0xe6e6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9090000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x70000, 0x0, 0x0, 0x9090000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6, 0xdcdcdc01, 0xe6e6dcdc, 0xdcdcdcdc, 0x10100e6, 0x1010101, 0x1, 0xdc00, 0x0, 0xe6, 0x0, 0x0, 0xe6dce6e6, 0xe6e6e6e6, 0xe6dce6e6, 0xdcd6eae6, 0xe6e6e6ca, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdce6dce9, 0x0, 0x0, 0x0, 0x0, 0x101e6e6, 0xe6e6e6e6, 0xe6010101, 0xe6, 0xe600, 0xe6010100, 0x101e6dc, 0xdcdcdcdc, 0xe6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6000000, 0xe6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe4da0000, 0xe0e0dee8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6000000, 0x0, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6, 0x0, 0x0, 0x0, 0x0, 0x90000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6e6e6, 0xe6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdc000000, 0xdcdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7000000, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e600e6, 0xe60000dc, 0xe6, 0xe6e60000, 0xe600, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x900, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e6e6e6, 0xe6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdc00, 0x0, 0x0, 0x0, 0xe600dc00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdc01e6, 0x9000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x70900, 0x0, 0xe6e6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9000000, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7090000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d8d800, 0x101, 0xd8d8e200, 0xd8d8d8, 0x0, 0xdc000000, 0xdcdcdcdc, 0xdcdcdc, 0xe6e6e600, 0xdcdce6e6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe6e60000, 0xe6e6, 0x0, 0x0, 0x0, 0x0, 0xe6e60000, 0xe6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); enum composeIdxMask = (1<<11)-1, composeCntShift = 11; enum compositionJumpTrieEntries = TrieEntry!(ushort, 12, 9)([ 0x0, 0x800], [ 0x1000, 0x2000], [ 0x10000, 0x30002, 0x50004, 0x70006, 0x70008, 0x70007, 0x90007, 0xa0007, 0xc000b, 0x70007, 0x70007, 0x70007, 0x7000d, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x7000e, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0x70007, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x8010800, 0xffff0802, 0x8003ffff, 0x28161813, 0x8821301b, 0x38330832, 0x7841383a, 0x28510850, 0x185c3056, 0x8068485f, 0xffff1078, 0x3882407a, 0x98903889, 0x30a510a3, 0x48ad10ab, 0xffff30b6, 0xffffffff, 0xffffffff, 0x80bcffff, 0x28cf18cc, 0x88da30d4, 0x38ec08eb, 0x70fb40f3, 0x290b1109, 0x19163110, 0x81224919, 0xffff1132, 0x393c4134, 0x994b4143, 0x3960115e, 0x51691167, 0xffff3173, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff1979, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff217c, 0x9810980, 0x9841182, 0xffffffff, 0xffff2185, 0xffffffff, 0x989ffff, 0xffffffff, 0xffffffff, 0x198e218a, 0xffff0991, 0xffff0992, 0xffffffff, 0xffff2193, 0xffffffff, 0xffffffff, 0xffff2197, 0x99c099b, 0x99f119d, 0xffffffff, 0xffff21a0, 0xffffffff, 0x9a4ffff, 0xffffffff, 0xffffffff, 0x19a921a5, 0xffff09ac, 0xffff09ad, 0xffffffff, 0xffff21ae, 0xffffffff, 0xffffffff, 0x21b621b2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x11bc11ba, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x11c011be, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x9c309c2, 0xffffffff, 0xffffffff, 0x9c509c4, 0xffffffff, 0xffffffff, 0xffffffff, 0x9c709c6, 0x9c909c8, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x9caffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x29d029cb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x29d5ffff, 0xffff29da, 0xffffffff, 0xffffffff, 0x9dfffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x9e109e0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x9e309e2, 0x9e509e4, 0xffffffff, 0xffffffff, 0x9e709e6, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff09e8, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x39e9ffff, 0xffffffff, 0x21f0ffff, 0x29f4ffff, 0x39f9ffff, 0xffffffff, 0xffffffff, 0x2200ffff, 0xa04ffff, 0xffffffff, 0x3205ffff, 0xffffffff, 0x2a0bffff, 0xffffffff, 0xffff0a10, 0xffff0a11, 0x4212ffff, 0xffffffff, 0x221affff, 0x321effff, 0x4224ffff, 0xffffffff, 0xffffffff, 0x222cffff, 0x1230ffff, 0xffffffff, 0x4232ffff, 0xffffffff, 0x323affff, 0x1a431a40, 0xffffffff, 0xffff0a46, 0xffffffff, 0xffff1247, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0a49, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff124a, 0xa4cffff, 0x1a4dffff, 0xa521250, 0xffff2253, 0xffff0a57, 0xffffffff, 0xffff0a58, 0xffffffff, 0x2259ffff, 0xffffffff, 0xa5dffff, 0xffffffff, 0xa5effff, 0xa5fffff, 0xffffffff, 0xffff1260, 0xa62ffff, 0x1a63ffff, 0xa681266, 0xffff2269, 0xffff0a6d, 0xffffffff, 0xffff0a6e, 0xffffffff, 0x226fffff, 0xffffffff, 0xa73ffff, 0xffffffff, 0xa74ffff, 0xa75ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0a76, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa780a77, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa7a0a79, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa7c0a7b, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1a7dffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0a80, 0xffff0a81, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa82ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0a83, 0xa84ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0a85, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0a86, 0xa87ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1288ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1a8affff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0a8d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa90128e, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0a91, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa92ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff1a93, 0xffffffff, 0xffff0a96, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa991297, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x1a9affff, 0xffffffff, 0xffff0a9d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa9effff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xa9fffff, 0xaa0ffff, 0xaa1ffff, 0xaa2ffff, 0xaa3ffff, 0xffffffff, 0xaa4ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0aa5, 0xffff0aa6, 0xaa80aa7, 0xffffffff, 0xffff0aa9, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xaab0aaa, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xaad0aac, 0xffffffff, 0xffffffff, 0xffffffff, 0xaaf0aae, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x12b212b0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xab50ab4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xab70ab6, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x22bc22b8, 0xac10ac0, 0xac30ac2, 0xac50ac4, 0x22ca22c6, 0xacf0ace, 0xad10ad0, 0xad30ad2, 0x12d612d4, 0xffffffff, 0xffffffff, 0xffffffff, 0x12da12d8, 0xffffffff, 0xffffffff, 0xffffffff, 0x22e022dc, 0xae50ae4, 0xae70ae6, 0xae90ae8, 0x22ee22ea, 0xaf30af2, 0xaf50af4, 0xaf70af6, 0x1afb1af8, 0xffffffff, 0xffffffff, 0xffffffff, 0x1b011afe, 0xffffffff, 0xffffffff, 0xffffffff, 0x13061304, 0xffffffff, 0xffffffff, 0xffffffff, 0x130a1308, 0xffffffff, 0xffffffff, 0xffffffff, 0x1b0f1b0c, 0xffffffff, 0xffffffff, 0xffffffff, 0x1b12ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x23192315, 0xb1e0b1d, 0xb200b1f, 0xb220b21, 0x23272323, 0xb2c0b2b, 0xb2e0b2d, 0xb300b2f, 0xffff0b31, 0xffffffff, 0xffff0b32, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b33, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b34, 0xffffffff, 0xffffffff, 0xffffffff, 0x1b35ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b38, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b39, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff1b3a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b3d, 0xffff0b3e, 0xffff0b3f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b40, 0xffff0b41, 0xffff0b42, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb43ffff, 0xffffffff, 0xffffffff, 0xffff0b44, 0xb45ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb46ffff, 0xb47ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b48, 0xffffffff, 0xffffffff, 0xb49ffff, 0xb4affff, 0xffffffff, 0xffff0b4b, 0xffffffff, 0xb4cffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb4dffff, 0xffffffff, 0xb4f0b4e, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb510b50, 0xffffffff, 0xb530b52, 0xffffffff, 0xb550b54, 0xb570b56, 0xffffffff, 0xffffffff, 0xb590b58, 0xffffffff, 0xb5b0b5a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb5cffff, 0xffff0b5d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b5e, 0xffffffff, 0xffffffff, 0xb600b5f, 0xb61ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb630b62, 0xb650b64, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b66, 0xffffffff, 0xb67ffff, 0xb68ffff, 0xb69ffff, 0xb6affff, 0xb6bffff, 0xb6cffff, 0xb6dffff, 0xb6effff, 0xb6fffff, 0xb70ffff, 0xb71ffff, 0xb72ffff, 0xffffffff, 0xffff0b73, 0xffff0b74, 0xffff0b75, 0xffffffff, 0xffffffff, 0x1376ffff, 0xffffffff, 0xffff1378, 0x137affff, 0xffffffff, 0xffff137c, 0x137effff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb80ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0b81, 0xffffffff, 0xb82ffff, 0xb83ffff, 0xb84ffff, 0xb85ffff, 0xb86ffff, 0xb87ffff, 0xb88ffff, 0xb89ffff, 0xb8affff, 0xb8bffff, 0xb8cffff, 0xb8dffff, 0xffffffff, 0xffff0b8e, 0xffff0b8f, 0xffff0b90, 0xffffffff, 0xffffffff, 0x1391ffff, 0xffffffff, 0xffff1393, 0x1395ffff, 0xffffffff, 0xffff1397, 0x1399ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb9bffff, 0xb9d0b9c, 0xffff0b9e, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xb9fffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xba0ffff, 0xba1ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xba2ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xba3ffff, 0xffff0ba4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]); @property immutable(CompEntry[]) compositionTable() { alias CE = CompEntry; static immutable CE[] t = [CE(0x00338, 0x0226e),CE(0x00338, 0x02260),CE(0x00338, 0x0226f),CE(0x00300, 0x000c0),CE(0x00301, 0x000c1),CE(0x00302, 0x000c2),CE(0x00303, 0x000c3),CE(0x00304, 0x00100),CE(0x00306, 0x00102),CE(0x00307, 0x00226),CE(0x00308, 0x000c4),CE(0x00309, 0x01ea2),CE(0x0030a, 0x000c5),CE(0x0030c, 0x001cd),CE(0x0030f, 0x00200),CE(0x00311, 0x00202),CE(0x00323, 0x01ea0),CE(0x00325, 0x01e00),CE(0x00328, 0x00104),CE(0x00307, 0x01e02),CE(0x00323, 0x01e04),CE(0x00331, 0x01e06),CE(0x00301, 0x00106),CE(0x00302, 0x00108),CE(0x00307, 0x0010a),CE(0x0030c, 0x0010c),CE(0x00327, 0x000c7),CE(0x00307, 0x01e0a),CE(0x0030c, 0x0010e),CE(0x00323, 0x01e0c),CE(0x00327, 0x01e10),CE(0x0032d, 0x01e12),CE(0x00331, 0x01e0e),CE(0x00300, 0x000c8),CE(0x00301, 0x000c9),CE(0x00302, 0x000ca),CE(0x00303, 0x01ebc),CE(0x00304, 0x00112),CE(0x00306, 0x00114),CE(0x00307, 0x00116),CE(0x00308, 0x000cb),CE(0x00309, 0x01eba),CE(0x0030c, 0x0011a),CE(0x0030f, 0x00204),CE(0x00311, 0x00206),CE(0x00323, 0x01eb8),CE(0x00327, 0x00228),CE(0x00328, 0x00118),CE(0x0032d, 0x01e18),CE(0x00330, 0x01e1a),CE(0x00307, 0x01e1e),CE(0x00301, 0x001f4),CE(0x00302, 0x0011c),CE(0x00304, 0x01e20),CE(0x00306, 0x0011e),CE(0x00307, 0x00120),CE(0x0030c, 0x001e6),CE(0x00327, 0x00122),CE(0x00302, 0x00124),CE(0x00307, 0x01e22),CE(0x00308, 0x01e26),CE(0x0030c, 0x0021e),CE(0x00323, 0x01e24),CE(0x00327, 0x01e28),CE(0x0032e, 0x01e2a),CE(0x00300, 0x000cc),CE(0x00301, 0x000cd),CE(0x00302, 0x000ce),CE(0x00303, 0x00128),CE(0x00304, 0x0012a),CE(0x00306, 0x0012c),CE(0x00307, 0x00130),CE(0x00308, 0x000cf),CE(0x00309, 0x01ec8),CE(0x0030c, 0x001cf),CE(0x0030f, 0x00208),CE(0x00311, 0x0020a),CE(0x00323, 0x01eca),CE(0x00328, 0x0012e),CE(0x00330, 0x01e2c),CE(0x00302, 0x00134),CE(0x00301, 0x01e30),CE(0x0030c, 0x001e8),CE(0x00323, 0x01e32),CE(0x00327, 0x00136),CE(0x00331, 0x01e34),CE(0x00301, 0x00139),CE(0x0030c, 0x0013d),CE(0x00323, 0x01e36),CE(0x00327, 0x0013b),CE(0x0032d, 0x01e3c),CE(0x00331, 0x01e3a),CE(0x00301, 0x01e3e),CE(0x00307, 0x01e40),CE(0x00323, 0x01e42),CE(0x00300, 0x001f8),CE(0x00301, 0x00143),CE(0x00303, 0x000d1),CE(0x00307, 0x01e44),CE(0x0030c, 0x00147),CE(0x00323, 0x01e46),CE(0x00327, 0x00145),CE(0x0032d, 0x01e4a),CE(0x00331, 0x01e48),CE(0x00300, 0x000d2),CE(0x00301, 0x000d3),CE(0x00302, 0x000d4),CE(0x00303, 0x000d5),CE(0x00304, 0x0014c),CE(0x00306, 0x0014e),CE(0x00307, 0x0022e),CE(0x00308, 0x000d6),CE(0x00309, 0x01ece),CE(0x0030b, 0x00150),CE(0x0030c, 0x001d1),CE(0x0030f, 0x0020c),CE(0x00311, 0x0020e),CE(0x0031b, 0x001a0),CE(0x00323, 0x01ecc),CE(0x00328, 0x001ea),CE(0x00301, 0x01e54),CE(0x00307, 0x01e56),CE(0x00301, 0x00154),CE(0x00307, 0x01e58),CE(0x0030c, 0x00158),CE(0x0030f, 0x00210),CE(0x00311, 0x00212),CE(0x00323, 0x01e5a),CE(0x00327, 0x00156),CE(0x00331, 0x01e5e),CE(0x00301, 0x0015a),CE(0x00302, 0x0015c),CE(0x00307, 0x01e60),CE(0x0030c, 0x00160),CE(0x00323, 0x01e62),CE(0x00326, 0x00218),CE(0x00327, 0x0015e),CE(0x00307, 0x01e6a),CE(0x0030c, 0x00164),CE(0x00323, 0x01e6c),CE(0x00326, 0x0021a),CE(0x00327, 0x00162),CE(0x0032d, 0x01e70),CE(0x00331, 0x01e6e),CE(0x00300, 0x000d9),CE(0x00301, 0x000da),CE(0x00302, 0x000db),CE(0x00303, 0x00168),CE(0x00304, 0x0016a),CE(0x00306, 0x0016c),CE(0x00308, 0x000dc),CE(0x00309, 0x01ee6),CE(0x0030a, 0x0016e),CE(0x0030b, 0x00170),CE(0x0030c, 0x001d3),CE(0x0030f, 0x00214),CE(0x00311, 0x00216),CE(0x0031b, 0x001af),CE(0x00323, 0x01ee4),CE(0x00324, 0x01e72),CE(0x00328, 0x00172),CE(0x0032d, 0x01e76),CE(0x00330, 0x01e74),CE(0x00303, 0x01e7c),CE(0x00323, 0x01e7e),CE(0x00300, 0x01e80),CE(0x00301, 0x01e82),CE(0x00302, 0x00174),CE(0x00307, 0x01e86),CE(0x00308, 0x01e84),CE(0x00323, 0x01e88),CE(0x00307, 0x01e8a),CE(0x00308, 0x01e8c),CE(0x00300, 0x01ef2),CE(0x00301, 0x000dd),CE(0x00302, 0x00176),CE(0x00303, 0x01ef8),CE(0x00304, 0x00232),CE(0x00307, 0x01e8e),CE(0x00308, 0x00178),CE(0x00309, 0x01ef6),CE(0x00323, 0x01ef4),CE(0x00301, 0x00179),CE(0x00302, 0x01e90),CE(0x00307, 0x0017b),CE(0x0030c, 0x0017d),CE(0x00323, 0x01e92),CE(0x00331, 0x01e94),CE(0x00300, 0x000e0),CE(0x00301, 0x000e1),CE(0x00302, 0x000e2),CE(0x00303, 0x000e3),CE(0x00304, 0x00101),CE(0x00306, 0x00103),CE(0x00307, 0x00227),CE(0x00308, 0x000e4),CE(0x00309, 0x01ea3),CE(0x0030a, 0x000e5),CE(0x0030c, 0x001ce),CE(0x0030f, 0x00201),CE(0x00311, 0x00203),CE(0x00323, 0x01ea1),CE(0x00325, 0x01e01),CE(0x00328, 0x00105),CE(0x00307, 0x01e03),CE(0x00323, 0x01e05),CE(0x00331, 0x01e07),CE(0x00301, 0x00107),CE(0x00302, 0x00109),CE(0x00307, 0x0010b),CE(0x0030c, 0x0010d),CE(0x00327, 0x000e7),CE(0x00307, 0x01e0b),CE(0x0030c, 0x0010f),CE(0x00323, 0x01e0d),CE(0x00327, 0x01e11),CE(0x0032d, 0x01e13),CE(0x00331, 0x01e0f),CE(0x00300, 0x000e8),CE(0x00301, 0x000e9),CE(0x00302, 0x000ea),CE(0x00303, 0x01ebd),CE(0x00304, 0x00113),CE(0x00306, 0x00115),CE(0x00307, 0x00117),CE(0x00308, 0x000eb),CE(0x00309, 0x01ebb),CE(0x0030c, 0x0011b),CE(0x0030f, 0x00205),CE(0x00311, 0x00207),CE(0x00323, 0x01eb9),CE(0x00327, 0x00229),CE(0x00328, 0x00119),CE(0x0032d, 0x01e19),CE(0x00330, 0x01e1b),CE(0x00307, 0x01e1f),CE(0x00301, 0x001f5),CE(0x00302, 0x0011d),CE(0x00304, 0x01e21),CE(0x00306, 0x0011f),CE(0x00307, 0x00121),CE(0x0030c, 0x001e7),CE(0x00327, 0x00123),CE(0x00302, 0x00125),CE(0x00307, 0x01e23),CE(0x00308, 0x01e27),CE(0x0030c, 0x0021f),CE(0x00323, 0x01e25),CE(0x00327, 0x01e29),CE(0x0032e, 0x01e2b),CE(0x00331, 0x01e96),CE(0x00300, 0x000ec),CE(0x00301, 0x000ed),CE(0x00302, 0x000ee),CE(0x00303, 0x00129),CE(0x00304, 0x0012b),CE(0x00306, 0x0012d),CE(0x00308, 0x000ef),CE(0x00309, 0x01ec9),CE(0x0030c, 0x001d0),CE(0x0030f, 0x00209),CE(0x00311, 0x0020b),CE(0x00323, 0x01ecb),CE(0x00328, 0x0012f),CE(0x00330, 0x01e2d),CE(0x00302, 0x00135),CE(0x0030c, 0x001f0),CE(0x00301, 0x01e31),CE(0x0030c, 0x001e9),CE(0x00323, 0x01e33),CE(0x00327, 0x00137),CE(0x00331, 0x01e35),CE(0x00301, 0x0013a),CE(0x0030c, 0x0013e),CE(0x00323, 0x01e37),CE(0x00327, 0x0013c),CE(0x0032d, 0x01e3d),CE(0x00331, 0x01e3b),CE(0x00301, 0x01e3f),CE(0x00307, 0x01e41),CE(0x00323, 0x01e43),CE(0x00300, 0x001f9),CE(0x00301, 0x00144),CE(0x00303, 0x000f1),CE(0x00307, 0x01e45),CE(0x0030c, 0x00148),CE(0x00323, 0x01e47),CE(0x00327, 0x00146),CE(0x0032d, 0x01e4b),CE(0x00331, 0x01e49),CE(0x00300, 0x000f2),CE(0x00301, 0x000f3),CE(0x00302, 0x000f4),CE(0x00303, 0x000f5),CE(0x00304, 0x0014d),CE(0x00306, 0x0014f),CE(0x00307, 0x0022f),CE(0x00308, 0x000f6),CE(0x00309, 0x01ecf),CE(0x0030b, 0x00151),CE(0x0030c, 0x001d2),CE(0x0030f, 0x0020d),CE(0x00311, 0x0020f),CE(0x0031b, 0x001a1),CE(0x00323, 0x01ecd),CE(0x00328, 0x001eb),CE(0x00301, 0x01e55),CE(0x00307, 0x01e57),CE(0x00301, 0x00155),CE(0x00307, 0x01e59),CE(0x0030c, 0x00159),CE(0x0030f, 0x00211),CE(0x00311, 0x00213),CE(0x00323, 0x01e5b),CE(0x00327, 0x00157),CE(0x00331, 0x01e5f),CE(0x00301, 0x0015b),CE(0x00302, 0x0015d),CE(0x00307, 0x01e61),CE(0x0030c, 0x00161),CE(0x00323, 0x01e63),CE(0x00326, 0x00219),CE(0x00327, 0x0015f),CE(0x00307, 0x01e6b),CE(0x00308, 0x01e97),CE(0x0030c, 0x00165),CE(0x00323, 0x01e6d),CE(0x00326, 0x0021b),CE(0x00327, 0x00163),CE(0x0032d, 0x01e71),CE(0x00331, 0x01e6f),CE(0x00300, 0x000f9),CE(0x00301, 0x000fa),CE(0x00302, 0x000fb),CE(0x00303, 0x00169),CE(0x00304, 0x0016b),CE(0x00306, 0x0016d),CE(0x00308, 0x000fc),CE(0x00309, 0x01ee7),CE(0x0030a, 0x0016f),CE(0x0030b, 0x00171),CE(0x0030c, 0x001d4),CE(0x0030f, 0x00215),CE(0x00311, 0x00217),CE(0x0031b, 0x001b0),CE(0x00323, 0x01ee5),CE(0x00324, 0x01e73),CE(0x00328, 0x00173),CE(0x0032d, 0x01e77),CE(0x00330, 0x01e75),CE(0x00303, 0x01e7d),CE(0x00323, 0x01e7f),CE(0x00300, 0x01e81),CE(0x00301, 0x01e83),CE(0x00302, 0x00175),CE(0x00307, 0x01e87),CE(0x00308, 0x01e85),CE(0x0030a, 0x01e98),CE(0x00323, 0x01e89),CE(0x00307, 0x01e8b),CE(0x00308, 0x01e8d),CE(0x00300, 0x01ef3),CE(0x00301, 0x000fd),CE(0x00302, 0x00177),CE(0x00303, 0x01ef9),CE(0x00304, 0x00233),CE(0x00307, 0x01e8f),CE(0x00308, 0x000ff),CE(0x00309, 0x01ef7),CE(0x0030a, 0x01e99),CE(0x00323, 0x01ef5),CE(0x00301, 0x0017a),CE(0x00302, 0x01e91),CE(0x00307, 0x0017c),CE(0x0030c, 0x0017e),CE(0x00323, 0x01e93),CE(0x00331, 0x01e95),CE(0x00300, 0x01fed),CE(0x00301, 0x00385),CE(0x00342, 0x01fc1),CE(0x00300, 0x01ea6),CE(0x00301, 0x01ea4),CE(0x00303, 0x01eaa),CE(0x00309, 0x01ea8),CE(0x00304, 0x001de),CE(0x00301, 0x001fa),CE(0x00301, 0x001fc),CE(0x00304, 0x001e2),CE(0x00301, 0x01e08),CE(0x00300, 0x01ec0),CE(0x00301, 0x01ebe),CE(0x00303, 0x01ec4),CE(0x00309, 0x01ec2),CE(0x00301, 0x01e2e),CE(0x00300, 0x01ed2),CE(0x00301, 0x01ed0),CE(0x00303, 0x01ed6),CE(0x00309, 0x01ed4),CE(0x00301, 0x01e4c),CE(0x00304, 0x0022c),CE(0x00308, 0x01e4e),CE(0x00304, 0x0022a),CE(0x00301, 0x001fe),CE(0x00300, 0x001db),CE(0x00301, 0x001d7),CE(0x00304, 0x001d5),CE(0x0030c, 0x001d9),CE(0x00300, 0x01ea7),CE(0x00301, 0x01ea5),CE(0x00303, 0x01eab),CE(0x00309, 0x01ea9),CE(0x00304, 0x001df),CE(0x00301, 0x001fb),CE(0x00301, 0x001fd),CE(0x00304, 0x001e3),CE(0x00301, 0x01e09),CE(0x00300, 0x01ec1),CE(0x00301, 0x01ebf),CE(0x00303, 0x01ec5),CE(0x00309, 0x01ec3),CE(0x00301, 0x01e2f),CE(0x00300, 0x01ed3),CE(0x00301, 0x01ed1),CE(0x00303, 0x01ed7),CE(0x00309, 0x01ed5),CE(0x00301, 0x01e4d),CE(0x00304, 0x0022d),CE(0x00308, 0x01e4f),CE(0x00304, 0x0022b),CE(0x00301, 0x001ff),CE(0x00300, 0x001dc),CE(0x00301, 0x001d8),CE(0x00304, 0x001d6),CE(0x0030c, 0x001da),CE(0x00300, 0x01eb0),CE(0x00301, 0x01eae),CE(0x00303, 0x01eb4),CE(0x00309, 0x01eb2),CE(0x00300, 0x01eb1),CE(0x00301, 0x01eaf),CE(0x00303, 0x01eb5),CE(0x00309, 0x01eb3),CE(0x00300, 0x01e14),CE(0x00301, 0x01e16),CE(0x00300, 0x01e15),CE(0x00301, 0x01e17),CE(0x00300, 0x01e50),CE(0x00301, 0x01e52),CE(0x00300, 0x01e51),CE(0x00301, 0x01e53),CE(0x00307, 0x01e64),CE(0x00307, 0x01e65),CE(0x00307, 0x01e66),CE(0x00307, 0x01e67),CE(0x00301, 0x01e78),CE(0x00301, 0x01e79),CE(0x00308, 0x01e7a),CE(0x00308, 0x01e7b),CE(0x00307, 0x01e9b),CE(0x00300, 0x01edc),CE(0x00301, 0x01eda),CE(0x00303, 0x01ee0),CE(0x00309, 0x01ede),CE(0x00323, 0x01ee2),CE(0x00300, 0x01edd),CE(0x00301, 0x01edb),CE(0x00303, 0x01ee1),CE(0x00309, 0x01edf),CE(0x00323, 0x01ee3),CE(0x00300, 0x01eea),CE(0x00301, 0x01ee8),CE(0x00303, 0x01eee),CE(0x00309, 0x01eec),CE(0x00323, 0x01ef0),CE(0x00300, 0x01eeb),CE(0x00301, 0x01ee9),CE(0x00303, 0x01eef),CE(0x00309, 0x01eed),CE(0x00323, 0x01ef1),CE(0x0030c, 0x001ee),CE(0x00304, 0x001ec),CE(0x00304, 0x001ed),CE(0x00304, 0x001e0),CE(0x00304, 0x001e1),CE(0x00306, 0x01e1c),CE(0x00306, 0x01e1d),CE(0x00304, 0x00230),CE(0x00304, 0x00231),CE(0x0030c, 0x001ef),CE(0x00300, 0x01fba),CE(0x00301, 0x00386),CE(0x00304, 0x01fb9),CE(0x00306, 0x01fb8),CE(0x00313, 0x01f08),CE(0x00314, 0x01f09),CE(0x00345, 0x01fbc),CE(0x00300, 0x01fc8),CE(0x00301, 0x00388),CE(0x00313, 0x01f18),CE(0x00314, 0x01f19),CE(0x00300, 0x01fca),CE(0x00301, 0x00389),CE(0x00313, 0x01f28),CE(0x00314, 0x01f29),CE(0x00345, 0x01fcc),CE(0x00300, 0x01fda),CE(0x00301, 0x0038a),CE(0x00304, 0x01fd9),CE(0x00306, 0x01fd8),CE(0x00308, 0x003aa),CE(0x00313, 0x01f38),CE(0x00314, 0x01f39),CE(0x00300, 0x01ff8),CE(0x00301, 0x0038c),CE(0x00313, 0x01f48),CE(0x00314, 0x01f49),CE(0x00314, 0x01fec),CE(0x00300, 0x01fea),CE(0x00301, 0x0038e),CE(0x00304, 0x01fe9),CE(0x00306, 0x01fe8),CE(0x00308, 0x003ab),CE(0x00314, 0x01f59),CE(0x00300, 0x01ffa),CE(0x00301, 0x0038f),CE(0x00313, 0x01f68),CE(0x00314, 0x01f69),CE(0x00345, 0x01ffc),CE(0x00345, 0x01fb4),CE(0x00345, 0x01fc4),CE(0x00300, 0x01f70),CE(0x00301, 0x003ac),CE(0x00304, 0x01fb1),CE(0x00306, 0x01fb0),CE(0x00313, 0x01f00),CE(0x00314, 0x01f01),CE(0x00342, 0x01fb6),CE(0x00345, 0x01fb3),CE(0x00300, 0x01f72),CE(0x00301, 0x003ad),CE(0x00313, 0x01f10),CE(0x00314, 0x01f11),CE(0x00300, 0x01f74),CE(0x00301, 0x003ae),CE(0x00313, 0x01f20),CE(0x00314, 0x01f21),CE(0x00342, 0x01fc6),CE(0x00345, 0x01fc3),CE(0x00300, 0x01f76),CE(0x00301, 0x003af),CE(0x00304, 0x01fd1),CE(0x00306, 0x01fd0),CE(0x00308, 0x003ca),CE(0x00313, 0x01f30),CE(0x00314, 0x01f31),CE(0x00342, 0x01fd6),CE(0x00300, 0x01f78),CE(0x00301, 0x003cc),CE(0x00313, 0x01f40),CE(0x00314, 0x01f41),CE(0x00313, 0x01fe4),CE(0x00314, 0x01fe5),CE(0x00300, 0x01f7a),CE(0x00301, 0x003cd),CE(0x00304, 0x01fe1),CE(0x00306, 0x01fe0),CE(0x00308, 0x003cb),CE(0x00313, 0x01f50),CE(0x00314, 0x01f51),CE(0x00342, 0x01fe6),CE(0x00300, 0x01f7c),CE(0x00301, 0x003ce),CE(0x00313, 0x01f60),CE(0x00314, 0x01f61),CE(0x00342, 0x01ff6),CE(0x00345, 0x01ff3),CE(0x00300, 0x01fd2),CE(0x00301, 0x00390),CE(0x00342, 0x01fd7),CE(0x00300, 0x01fe2),CE(0x00301, 0x003b0),CE(0x00342, 0x01fe7),CE(0x00345, 0x01ff4),CE(0x00301, 0x003d3),CE(0x00308, 0x003d4),CE(0x00308, 0x00407),CE(0x00306, 0x004d0),CE(0x00308, 0x004d2),CE(0x00301, 0x00403),CE(0x00300, 0x00400),CE(0x00306, 0x004d6),CE(0x00308, 0x00401),CE(0x00306, 0x004c1),CE(0x00308, 0x004dc),CE(0x00308, 0x004de),CE(0x00300, 0x0040d),CE(0x00304, 0x004e2),CE(0x00306, 0x00419),CE(0x00308, 0x004e4),CE(0x00301, 0x0040c),CE(0x00308, 0x004e6),CE(0x00304, 0x004ee),CE(0x00306, 0x0040e),CE(0x00308, 0x004f0),CE(0x0030b, 0x004f2),CE(0x00308, 0x004f4),CE(0x00308, 0x004f8),CE(0x00308, 0x004ec),CE(0x00306, 0x004d1),CE(0x00308, 0x004d3),CE(0x00301, 0x00453),CE(0x00300, 0x00450),CE(0x00306, 0x004d7),CE(0x00308, 0x00451),CE(0x00306, 0x004c2),CE(0x00308, 0x004dd),CE(0x00308, 0x004df),CE(0x00300, 0x0045d),CE(0x00304, 0x004e3),CE(0x00306, 0x00439),CE(0x00308, 0x004e5),CE(0x00301, 0x0045c),CE(0x00308, 0x004e7),CE(0x00304, 0x004ef),CE(0x00306, 0x0045e),CE(0x00308, 0x004f1),CE(0x0030b, 0x004f3),CE(0x00308, 0x004f5),CE(0x00308, 0x004f9),CE(0x00308, 0x004ed),CE(0x00308, 0x00457),CE(0x0030f, 0x00476),CE(0x0030f, 0x00477),CE(0x00308, 0x004da),CE(0x00308, 0x004db),CE(0x00308, 0x004ea),CE(0x00308, 0x004eb),CE(0x00653, 0x00622),CE(0x00654, 0x00623),CE(0x00655, 0x00625),CE(0x00654, 0x00624),CE(0x00654, 0x00626),CE(0x00654, 0x006c2),CE(0x00654, 0x006d3),CE(0x00654, 0x006c0),CE(0x0093c, 0x00929),CE(0x0093c, 0x00931),CE(0x0093c, 0x00934),CE(0x009be, 0x009cb),CE(0x009d7, 0x009cc),CE(0x00b3e, 0x00b4b),CE(0x00b56, 0x00b48),CE(0x00b57, 0x00b4c),CE(0x00bd7, 0x00b94),CE(0x00bbe, 0x00bca),CE(0x00bd7, 0x00bcc),CE(0x00bbe, 0x00bcb),CE(0x00c56, 0x00c48),CE(0x00cd5, 0x00cc0),CE(0x00cc2, 0x00cca),CE(0x00cd5, 0x00cc7),CE(0x00cd6, 0x00cc8),CE(0x00cd5, 0x00ccb),CE(0x00d3e, 0x00d4a),CE(0x00d57, 0x00d4c),CE(0x00d3e, 0x00d4b),CE(0x00dca, 0x00dda),CE(0x00dcf, 0x00ddc),CE(0x00ddf, 0x00dde),CE(0x00dca, 0x00ddd),CE(0x0102e, 0x01026),CE(0x01b35, 0x01b06),CE(0x01b35, 0x01b08),CE(0x01b35, 0x01b0a),CE(0x01b35, 0x01b0c),CE(0x01b35, 0x01b0e),CE(0x01b35, 0x01b12),CE(0x01b35, 0x01b3b),CE(0x01b35, 0x01b3d),CE(0x01b35, 0x01b40),CE(0x01b35, 0x01b41),CE(0x01b35, 0x01b43),CE(0x00304, 0x01e38),CE(0x00304, 0x01e39),CE(0x00304, 0x01e5c),CE(0x00304, 0x01e5d),CE(0x00307, 0x01e68),CE(0x00307, 0x01e69),CE(0x00302, 0x01eac),CE(0x00306, 0x01eb6),CE(0x00302, 0x01ead),CE(0x00306, 0x01eb7),CE(0x00302, 0x01ec6),CE(0x00302, 0x01ec7),CE(0x00302, 0x01ed8),CE(0x00302, 0x01ed9),CE(0x00300, 0x01f02),CE(0x00301, 0x01f04),CE(0x00342, 0x01f06),CE(0x00345, 0x01f80),CE(0x00300, 0x01f03),CE(0x00301, 0x01f05),CE(0x00342, 0x01f07),CE(0x00345, 0x01f81),CE(0x00345, 0x01f82),CE(0x00345, 0x01f83),CE(0x00345, 0x01f84),CE(0x00345, 0x01f85),CE(0x00345, 0x01f86),CE(0x00345, 0x01f87),CE(0x00300, 0x01f0a),CE(0x00301, 0x01f0c),CE(0x00342, 0x01f0e),CE(0x00345, 0x01f88),CE(0x00300, 0x01f0b),CE(0x00301, 0x01f0d),CE(0x00342, 0x01f0f),CE(0x00345, 0x01f89),CE(0x00345, 0x01f8a),CE(0x00345, 0x01f8b),CE(0x00345, 0x01f8c),CE(0x00345, 0x01f8d),CE(0x00345, 0x01f8e),CE(0x00345, 0x01f8f),CE(0x00300, 0x01f12),CE(0x00301, 0x01f14),CE(0x00300, 0x01f13),CE(0x00301, 0x01f15),CE(0x00300, 0x01f1a),CE(0x00301, 0x01f1c),CE(0x00300, 0x01f1b),CE(0x00301, 0x01f1d),CE(0x00300, 0x01f22),CE(0x00301, 0x01f24),CE(0x00342, 0x01f26),CE(0x00345, 0x01f90),CE(0x00300, 0x01f23),CE(0x00301, 0x01f25),CE(0x00342, 0x01f27),CE(0x00345, 0x01f91),CE(0x00345, 0x01f92),CE(0x00345, 0x01f93),CE(0x00345, 0x01f94),CE(0x00345, 0x01f95),CE(0x00345, 0x01f96),CE(0x00345, 0x01f97),CE(0x00300, 0x01f2a),CE(0x00301, 0x01f2c),CE(0x00342, 0x01f2e),CE(0x00345, 0x01f98),CE(0x00300, 0x01f2b),CE(0x00301, 0x01f2d),CE(0x00342, 0x01f2f),CE(0x00345, 0x01f99),CE(0x00345, 0x01f9a),CE(0x00345, 0x01f9b),CE(0x00345, 0x01f9c),CE(0x00345, 0x01f9d),CE(0x00345, 0x01f9e),CE(0x00345, 0x01f9f),CE(0x00300, 0x01f32),CE(0x00301, 0x01f34),CE(0x00342, 0x01f36),CE(0x00300, 0x01f33),CE(0x00301, 0x01f35),CE(0x00342, 0x01f37),CE(0x00300, 0x01f3a),CE(0x00301, 0x01f3c),CE(0x00342, 0x01f3e),CE(0x00300, 0x01f3b),CE(0x00301, 0x01f3d),CE(0x00342, 0x01f3f),CE(0x00300, 0x01f42),CE(0x00301, 0x01f44),CE(0x00300, 0x01f43),CE(0x00301, 0x01f45),CE(0x00300, 0x01f4a),CE(0x00301, 0x01f4c),CE(0x00300, 0x01f4b),CE(0x00301, 0x01f4d),CE(0x00300, 0x01f52),CE(0x00301, 0x01f54),CE(0x00342, 0x01f56),CE(0x00300, 0x01f53),CE(0x00301, 0x01f55),CE(0x00342, 0x01f57),CE(0x00300, 0x01f5b),CE(0x00301, 0x01f5d),CE(0x00342, 0x01f5f),CE(0x00300, 0x01f62),CE(0x00301, 0x01f64),CE(0x00342, 0x01f66),CE(0x00345, 0x01fa0),CE(0x00300, 0x01f63),CE(0x00301, 0x01f65),CE(0x00342, 0x01f67),CE(0x00345, 0x01fa1),CE(0x00345, 0x01fa2),CE(0x00345, 0x01fa3),CE(0x00345, 0x01fa4),CE(0x00345, 0x01fa5),CE(0x00345, 0x01fa6),CE(0x00345, 0x01fa7),CE(0x00300, 0x01f6a),CE(0x00301, 0x01f6c),CE(0x00342, 0x01f6e),CE(0x00345, 0x01fa8),CE(0x00300, 0x01f6b),CE(0x00301, 0x01f6d),CE(0x00342, 0x01f6f),CE(0x00345, 0x01fa9),CE(0x00345, 0x01faa),CE(0x00345, 0x01fab),CE(0x00345, 0x01fac),CE(0x00345, 0x01fad),CE(0x00345, 0x01fae),CE(0x00345, 0x01faf),CE(0x00345, 0x01fb2),CE(0x00345, 0x01fc2),CE(0x00345, 0x01ff2),CE(0x00345, 0x01fb7),CE(0x00300, 0x01fcd),CE(0x00301, 0x01fce),CE(0x00342, 0x01fcf),CE(0x00345, 0x01fc7),CE(0x00345, 0x01ff7),CE(0x00300, 0x01fdd),CE(0x00301, 0x01fde),CE(0x00342, 0x01fdf),CE(0x00338, 0x0219a),CE(0x00338, 0x0219b),CE(0x00338, 0x021ae),CE(0x00338, 0x021cd),CE(0x00338, 0x021cf),CE(0x00338, 0x021ce),CE(0x00338, 0x02204),CE(0x00338, 0x02209),CE(0x00338, 0x0220c),CE(0x00338, 0x02224),CE(0x00338, 0x02226),CE(0x00338, 0x02241),CE(0x00338, 0x02244),CE(0x00338, 0x02247),CE(0x00338, 0x02249),CE(0x00338, 0x0226d),CE(0x00338, 0x02262),CE(0x00338, 0x02270),CE(0x00338, 0x02271),CE(0x00338, 0x02274),CE(0x00338, 0x02275),CE(0x00338, 0x02278),CE(0x00338, 0x02279),CE(0x00338, 0x02280),CE(0x00338, 0x02281),CE(0x00338, 0x022e0),CE(0x00338, 0x022e1),CE(0x00338, 0x02284),CE(0x00338, 0x02285),CE(0x00338, 0x02288),CE(0x00338, 0x02289),CE(0x00338, 0x022e2),CE(0x00338, 0x022e3),CE(0x00338, 0x022ac),CE(0x00338, 0x022ad),CE(0x00338, 0x022ae),CE(0x00338, 0x022af),CE(0x00338, 0x022ea),CE(0x00338, 0x022eb),CE(0x00338, 0x022ec),CE(0x00338, 0x022ed),CE(0x03099, 0x03094),CE(0x03099, 0x0304c),CE(0x03099, 0x0304e),CE(0x03099, 0x03050),CE(0x03099, 0x03052),CE(0x03099, 0x03054),CE(0x03099, 0x03056),CE(0x03099, 0x03058),CE(0x03099, 0x0305a),CE(0x03099, 0x0305c),CE(0x03099, 0x0305e),CE(0x03099, 0x03060),CE(0x03099, 0x03062),CE(0x03099, 0x03065),CE(0x03099, 0x03067),CE(0x03099, 0x03069),CE(0x03099, 0x03070),CE(0x0309a, 0x03071),CE(0x03099, 0x03073),CE(0x0309a, 0x03074),CE(0x03099, 0x03076),CE(0x0309a, 0x03077),CE(0x03099, 0x03079),CE(0x0309a, 0x0307a),CE(0x03099, 0x0307c),CE(0x0309a, 0x0307d),CE(0x03099, 0x0309e),CE(0x03099, 0x030f4),CE(0x03099, 0x030ac),CE(0x03099, 0x030ae),CE(0x03099, 0x030b0),CE(0x03099, 0x030b2),CE(0x03099, 0x030b4),CE(0x03099, 0x030b6),CE(0x03099, 0x030b8),CE(0x03099, 0x030ba),CE(0x03099, 0x030bc),CE(0x03099, 0x030be),CE(0x03099, 0x030c0),CE(0x03099, 0x030c2),CE(0x03099, 0x030c5),CE(0x03099, 0x030c7),CE(0x03099, 0x030c9),CE(0x03099, 0x030d0),CE(0x0309a, 0x030d1),CE(0x03099, 0x030d3),CE(0x0309a, 0x030d4),CE(0x03099, 0x030d6),CE(0x0309a, 0x030d7),CE(0x03099, 0x030d9),CE(0x0309a, 0x030da),CE(0x03099, 0x030dc),CE(0x0309a, 0x030dd),CE(0x03099, 0x030f7),CE(0x03099, 0x030f8),CE(0x03099, 0x030f9),CE(0x03099, 0x030fa),CE(0x03099, 0x030fe),CE(0x110ba, 0x1109a),CE(0x110ba, 0x1109c),CE(0x110ba, 0x110ab),CE(0x11127, 0x1112e),CE(0x11127, 0x1112f),]; return t; } } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/math/0000775000175000017500000000000012776215007020453 5ustar kaikaildc-1.1.0-beta3-src/runtime/phobos/std/internal/math/biguintx86.d0000664000175000017500000012067112776215007022636 0ustar kaikai/** Optimised asm arbitrary precision arithmetic ('bignum') * routines for X86 processors. * * All functions operate on arrays of uints, stored LSB first. * If there is a destination array, it will be the first parameter. * Currently, all of these functions are subject to change, and are * intended for internal use only. * The symbol [#] indicates an array of machine words which is to be * interpreted as a multi-byte number. */ /* Copyright Don Clugston 2008 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ /** * In simple terms, there are 3 modern x86 microarchitectures: * (a) the P6 family (Pentium Pro, PII, PIII, PM, Core), produced by Intel; * (b) the K6, Athlon, and AMD64 families, produced by AMD; and * (c) the Pentium 4, produced by Marketing. * * This code has been optimised for the Intel P6 family. * Generally the code remains near-optimal for Intel Core2/Corei7, after * translating EAX-> RAX, etc, since all these CPUs use essentially the same * pipeline, and are typically limited by memory access. * The code uses techniques described in Agner Fog's superb Pentium manuals * available at www.agner.org. * Not optimised for AMD, which can do two memory loads per cycle (Intel * CPUs can only do one). Despite this, performance is superior on AMD. * Performance is dreadful on P4. * * Timing results (cycles per int) * --Intel Pentium-- --AMD-- * PM P4 Core2 K7 * +,- 2.25 15.6 2.25 1.5 * <<,>> 2.0 6.6 2.0 5.0 * (<< MMX) 1.7 5.3 1.5 1.2 * * 5.0 15.0 4.0 4.3 * mulAdd 5.7 19.0 4.9 4.0 * div 30.0 32.0 32.0 22.4 * mulAcc(32) 6.5 20.0 5.4 4.9 * * mulAcc(32) is multiplyAccumulate() for a 32*32 multiply. Thus it includes * function call overhead. * The timing for Div is quite unpredictable, but it's probably too slow * to be useful. On 64-bit processors, these times should * halve if run in 64-bit mode, except for the MMX functions. */ module std.internal.math.biguintx86; @system: pure: nothrow: /* Naked asm is used throughout, because: (a) it frees up the EBP register (b) compiler bugs prevent the use of .ptr when a frame pointer is used. */ version(D_InlineAsm_X86) { private: /* Duplicate string s, with n times, substituting index for '@'. * * Each instance of '@' in s is replaced by 0,1,...n-1. This is a helper * function for some of the asm routines. */ string indexedLoopUnroll(int n, string s) pure @safe { string u; for (int i = 0; i9 ? ""~ cast(char)('0'+i/10) : "") ~ cast(char)('0' + i%10); int last = 0; for (int j = 0; j> numbits * numbits must be in the range 1..31 * This version uses MMX. */ uint multibyteShl(uint [] dest, const uint [] src, uint numbits) pure { // Timing: // K7 1.2/int. PM 1.7/int P4 5.3/int enum { LASTPARAM = 4*4 } // 3* pushes + return address. asm pure nothrow { naked; push ESI; push EDI; push EBX; mov EDI, [ESP + LASTPARAM + 4*3]; //dest.ptr; mov EBX, [ESP + LASTPARAM + 4*2]; //dest.length; mov ESI, [ESP + LASTPARAM + 4*1]; //src.ptr; movd MM3, EAX; // numbits = bits to shift left xor EAX, 63; align 16; inc EAX; movd MM4, EAX ; // 64-numbits = bits to shift right // Get the return value into EAX and EAX, 31; // EAX = 32-numbits movd MM2, EAX; // 32-numbits movd MM1, [ESI+4*EBX-4]; psrlq MM1, MM2; movd EAX, MM1; // EAX = return value test EBX, 1; jz L_even; L_odd: cmp EBX, 1; jz L_length1; // deal with odd lengths movq MM1, [ESI+4*EBX-8]; psrlq MM1, MM2; movd [EDI +4*EBX-4], MM1; sub EBX, 1; L_even: // It's either singly or doubly even movq MM2, [ESI + 4*EBX - 8]; psllq MM2, MM3; sub EBX, 2; jle L_last; movq MM1, MM2; add EBX, 2; test EBX, 2; jz L_onceeven; sub EBX, 2; // MAIN LOOP -- 128 bytes per iteration L_twiceeven: // here MM2 is the carry movq MM0, [ESI + 4*EBX-8]; psrlq MM0, MM4; movq MM1, [ESI + 4*EBX-8]; psllq MM1, MM3; por MM2, MM0; movq [EDI +4*EBX], MM2; L_onceeven: // here MM1 is the carry movq MM0, [ESI + 4*EBX-16]; psrlq MM0, MM4; movq MM2, [ESI + 4*EBX-16]; por MM1, MM0; movq [EDI +4*EBX-8], MM1; psllq MM2, MM3; sub EBX, 4; jg L_twiceeven; L_last: movq [EDI +4*EBX], MM2; L_alldone: emms; // NOTE: costs 6 cycles on Intel CPUs pop EBX; pop EDI; pop ESI; ret 4*4; L_length1: // length 1 is a special case movd MM1, [ESI]; psllq MM1, MM3; movd [EDI], MM1; jmp L_alldone; } } void multibyteShr(uint [] dest, const uint [] src, uint numbits) pure { enum { LASTPARAM = 4*4 } // 3* pushes + return address. asm pure nothrow { naked; push ESI; push EDI; push EBX; mov EDI, [ESP + LASTPARAM + 4*3]; //dest.ptr; mov EBX, [ESP + LASTPARAM + 4*2]; //dest.length; align 16; mov ESI, [ESP + LASTPARAM + 4*1]; //src.ptr; lea EDI, [EDI + 4*EBX]; // EDI = end of dest lea ESI, [ESI + 4*EBX]; // ESI = end of src neg EBX; // count UP to zero. movd MM3, EAX; // numbits = bits to shift right xor EAX, 63; inc EAX; movd MM4, EAX ; // 64-numbits = bits to shift left test EBX, 1; jz L_even; L_odd: // deal with odd lengths and EAX, 31; // EAX = 32-numbits movd MM2, EAX; // 32-numbits cmp EBX, -1; jz L_length1; movq MM0, [ESI+4*EBX]; psrlq MM0, MM3; movd [EDI +4*EBX], MM0; add EBX, 1; L_even: movq MM2, [ESI + 4*EBX]; psrlq MM2, MM3; movq MM1, MM2; add EBX, 4; cmp EBX, -2+4; jz L_last; // It's either singly or doubly even sub EBX, 2; test EBX, 2; jnz L_onceeven; add EBX, 2; // MAIN LOOP -- 128 bytes per iteration L_twiceeven: // here MM2 is the carry movq MM0, [ESI + 4*EBX-8]; psllq MM0, MM4; movq MM1, [ESI + 4*EBX-8]; psrlq MM1, MM3; por MM2, MM0; movq [EDI +4*EBX-16], MM2; L_onceeven: // here MM1 is the carry movq MM0, [ESI + 4*EBX]; psllq MM0, MM4; movq MM2, [ESI + 4*EBX]; por MM1, MM0; movq [EDI +4*EBX-8], MM1; psrlq MM2, MM3; add EBX, 4; jl L_twiceeven; L_last: movq [EDI +4*EBX-16], MM2; L_alldone: emms; // NOTE: costs 6 cycles on Intel CPUs pop EBX; pop EDI; pop ESI; ret 4*4; L_length1: // length 1 is a special case movd MM1, [ESI+4*EBX]; psrlq MM1, MM3; movd [EDI +4*EBX], MM1; jmp L_alldone; } } /** dest[#] = src[#] >> numbits * numbits must be in the range 1..31 */ void multibyteShrNoMMX(uint [] dest, const uint [] src, uint numbits) pure { // Timing: Optimal for P6 family. // 2.0 cycles/int on PPro..PM (limited by execution port p0) // Terrible performance on AMD64, which has 7 cycles for SHRD!! enum { LASTPARAM = 4*4 } // 3* pushes + return address. asm pure nothrow { naked; push ESI; push EDI; push EBX; mov EDI, [ESP + LASTPARAM + 4*3]; //dest.ptr; mov EBX, [ESP + LASTPARAM + 4*2]; //dest.length; mov ESI, [ESP + LASTPARAM + 4*1]; //src.ptr; mov ECX, EAX; // numbits; lea EDI, [EDI + 4*EBX]; // EDI = end of dest lea ESI, [ESI + 4*EBX]; // ESI = end of src neg EBX; // count UP to zero. mov EAX, [ESI + 4*EBX]; cmp EBX, -1; jz L_last; mov EDX, [ESI + 4*EBX]; test EBX, 1; jz L_odd; add EBX, 1; L_even: mov EDX, [ ESI + 4*EBX]; shrd EAX, EDX, CL; mov [-4 + EDI+4*EBX], EAX; L_odd: mov EAX, [4 + ESI + 4*EBX]; shrd EDX, EAX, CL; mov [EDI + 4*EBX], EDX; add EBX, 2; jl L_even; L_last: shr EAX, CL; mov [-4 + EDI], EAX; pop EBX; pop EDI; pop ESI; ret 4*4; } } unittest { uint [] aa = [0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteShr(aa[0..$-1], aa, 4); assert(aa[0] == 0x6122_2222 && aa[1]==0xA455_5555 && aa[2]==0xD899_9999 && aa[3]==0x0BCC_CCCC); aa = [0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteShr(aa[2..$-1], aa[2..$-1], 4); assert(aa[0] == 0x1222_2223 && aa[1]==0x4555_5556 && aa[2]==0xD899_9999 && aa[3]==0x0BCC_CCCC); aa = [0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteShr(aa[0..$-2], aa, 4); assert(aa[1]==0xA455_5555 && aa[2]==0x0899_9999); assert(aa[0]==0x6122_2222); assert(aa[3]==0xBCCC_CCCD); aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; uint r = multibyteShl(aa[2..4], aa[2..4], 4); assert(aa[0] == 0xF0FF_FFFF && aa[1]==0x1222_2223 && aa[2]==0x5555_5560 && aa[3]==0x9999_99A4 && aa[4]==0xBCCC_CCCD); assert(r==8); aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; r = multibyteShl(aa[1..4], aa[1..4], 4); assert(aa[0] == 0xF0FF_FFFF && aa[2]==0x5555_5561); assert(aa[3]==0x9999_99A4 && aa[4]==0xBCCC_CCCD); assert(r==8); assert(aa[1]==0x2222_2230); aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; r = multibyteShl(aa[0..4], aa[1..5], 31); } /** dest[#] = src[#] * multiplier + carry. * Returns carry. */ uint multibyteMul(uint[] dest, const uint[] src, uint multiplier, uint carry) pure { // Timing: definitely not optimal. // Pentium M: 5.0 cycles/operation, has 3 resource stalls/iteration // Fastest implementation found was 4.6 cycles/op, but not worth the complexity. enum { LASTPARAM = 4*4 } // 4* pushes + return address. // We'll use p2 (load unit) instead of the overworked p0 or p1 (ALU units) // when initializing variables to zero. version(D_PIC) { enum { zero = 0 } } else version(LDC) { // Cannot define statics in naked functions with LDC. enum { zero = 0 } } else { __gshared int zero = 0; } asm pure nothrow { naked; push ESI; push EDI; push EBX; mov EDI, [ESP + LASTPARAM + 4*4]; // dest.ptr mov EBX, [ESP + LASTPARAM + 4*3]; // dest.length mov ESI, [ESP + LASTPARAM + 4*2]; // src.ptr align 16; lea EDI, [EDI + 4*EBX]; // EDI = end of dest lea ESI, [ESI + 4*EBX]; // ESI = end of src mov ECX, EAX; // [carry]; -- last param is in EAX. neg EBX; // count UP to zero. test EBX, 1; jnz L_odd; add EBX, 1; L1: mov EAX, [-4 + ESI + 4*EBX]; mul int ptr [ESP+LASTPARAM]; //[multiplier]; add EAX, ECX; mov ECX, zero; mov [-4+EDI + 4*EBX], EAX; adc ECX, EDX; L_odd: mov EAX, [ESI + 4*EBX]; // p2 mul int ptr [ESP+LASTPARAM]; //[multiplier]; // p0*3, add EAX, ECX; mov ECX, zero; adc ECX, EDX; mov [EDI + 4*EBX], EAX; add EBX, 2; jl L1; mov EAX, ECX; // get final carry pop EBX; pop EDI; pop ESI; ret 5*4; } } unittest { uint [] aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteMul(aa[1..4], aa[1..4], 16, 0); assert(aa[0] == 0xF0FF_FFFF && aa[1] == 0x2222_2230 && aa[2]==0x5555_5561 && aa[3]==0x9999_99A4 && aa[4]==0x0BCCC_CCCD); } // The inner multiply-and-add loop, together with the Even entry point. // Multiples by M_ADDRESS which should be "ESP+LASTPARAM" or "ESP". OP must be "add" or "sub" // This is the most time-critical code in the BigInt library. // It is used by both MulAdd, multiplyAccumulate, and triangleAccumulate string asmMulAdd_innerloop(string OP, string M_ADDRESS) pure { // The bottlenecks in this code are extremely complicated. The MUL, ADD, and ADC // need 4 cycles on each of the ALUs units p0 and p1. So we use memory load // (unit p2) for initializing registers to zero. // There are also dependencies between the instructions, and we run up against the // ROB-read limit (can only read 2 registers per cycle). // We also need the number of uops in the loop to be a multiple of 3. // The only available execution unit for this is p3 (memory write). Unfortunately we can't do that // if Position-Independent Code is required. // Register usage // ESI = end of src // EDI = end of dest // EBX = index. Counts up to zero (in steps of 2). // EDX:EAX = scratch, used in multiply. // ECX = carry1. // EBP = carry2. // ESP = points to the multiplier. // The first member of 'dest' which will be modified is [EDI+4*EBX]. // EAX must already contain the first member of 'src', [ESI+4*EBX]. version(D_PIC) { bool using_PIC = true; } else version(LDC) { bool using_PIC = true; } else { bool using_PIC=false; } return " // Entry point for even length add EBX, 1; mov EBP, ECX; // carry mul int ptr [" ~ M_ADDRESS ~ "]; // M mov ECX, 0; add EBP, EAX; mov EAX, [ESI+4*EBX]; adc ECX, EDX; mul int ptr [" ~ M_ADDRESS ~ "]; // M " ~ OP ~ " [-4+EDI+4*EBX], EBP; mov EBP, zero; adc ECX, EAX; mov EAX, [4+ESI+4*EBX]; adc EBP, EDX; add EBX, 2; jnl L_done; L1: mul int ptr [" ~ M_ADDRESS ~ "]; " ~ OP ~ " [-8+EDI+4*EBX], ECX; adc EBP, EAX; mov ECX, zero; mov EAX, [ESI+4*EBX]; adc ECX, EDX; " ~ (using_PIC ? "" : " mov storagenop, EDX; ") // make #uops in loop a multiple of 3, can't do this in PIC mode. ~ " mul int ptr [" ~ M_ADDRESS ~ "]; " ~ OP ~ " [-4+EDI+4*EBX], EBP; mov EBP, zero; adc ECX, EAX; mov EAX, [4+ESI+4*EBX]; adc EBP, EDX; add EBX, 2; jl L1; L_done: " ~ OP ~ " [-8+EDI+4*EBX], ECX; adc EBP, 0; "; // final carry is now in EBP } string asmMulAdd_enter_odd(string OP, string M_ADDRESS) pure { return " mul int ptr [" ~M_ADDRESS ~"]; mov EBP, zero; add ECX, EAX; mov EAX, [4+ESI+4*EBX]; adc EBP, EDX; add EBX, 2; jl L1; jmp L_done; "; } /** * dest[#] += src[#] * multiplier OP carry(0..FFFF_FFFF). * where op == '+' or '-' * Returns carry out of MSB (0..FFFF_FFFF). */ uint multibyteMulAdd(char op)(uint [] dest, const uint [] src, uint multiplier, uint carry) pure { // Timing: This is the most time-critical bignum function. // Pentium M: 5.4 cycles/operation, still has 2 resource stalls + 1load block/iteration // The main loop is pipelined and unrolled by 2, // so entry to the loop is also complicated. // Register usage // EDX:EAX = multiply // EBX = counter // ECX = carry1 // EBP = carry2 // EDI = dest // ESI = src enum string OP = (op=='+')? "add" : "sub"; version(D_PIC) { enum { zero = 0 } } else version(LDC) { // Cannot define statics in naked functions with LDC. enum { zero = 0 } } else { // use p2 (load unit) instead of the overworked p0 or p1 (ALU units) // when initializing registers to zero. __gshared int zero = 0; // use p3/p4 units __gshared int storagenop; // write-only } enum { LASTPARAM = 5*4 } // 4* pushes + return address. asm pure nothrow { naked; push ESI; push EDI; push EBX; push EBP; mov EDI, [ESP + LASTPARAM + 4*4]; // dest.ptr mov EBX, [ESP + LASTPARAM + 4*3]; // dest.length align 16; nop; mov ESI, [ESP + LASTPARAM + 4*2]; // src.ptr lea EDI, [EDI + 4*EBX]; // EDI = end of dest lea ESI, [ESI + 4*EBX]; // ESI = end of src mov EBP, 0; mov ECX, EAX; // ECX = input carry. neg EBX; // count UP to zero. mov EAX, [ESI+4*EBX]; test EBX, 1; jnz L_enter_odd; } // Main loop, with entry point for even length mixin("asm pure nothrow {" ~ asmMulAdd_innerloop(OP, "ESP+LASTPARAM") ~ "}"); asm pure nothrow { mov EAX, EBP; // get final carry pop EBP; pop EBX; pop EDI; pop ESI; ret 5*4; } L_enter_odd: mixin("asm pure nothrow {" ~ asmMulAdd_enter_odd(OP, "ESP+LASTPARAM") ~ "}"); } unittest { uint [] aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; uint [] bb = [0x1234_1234, 0xF0F0_F0F0, 0x00C0_C0C0, 0xF0F0_F0F0, 0xC0C0_C0C0]; multibyteMulAdd!('+')(bb[1..$-1], aa[1..$-2], 16, 5); assert(bb[0] == 0x1234_1234 && bb[4] == 0xC0C0_C0C0); assert(bb[1] == 0x2222_2230 + 0xF0F0_F0F0+5 && bb[2] == 0x5555_5561+0x00C0_C0C0+1 && bb[3] == 0x9999_99A4+0xF0F0_F0F0 ); } /** Sets result[#] = result[0..left.length] + left[#] * right[#] It is defined in this way to allow cache-efficient multiplication. This function is equivalent to: ---- for (int i = 0; i< right.length; ++i) { dest[left.length + i] = multibyteMulAdd(dest[i..left.length+i], left, right[i], 0); } ---- */ void multibyteMultiplyAccumulate(uint [] dest, const uint[] left, const uint [] right) pure { // Register usage // EDX:EAX = used in multiply // EBX = index // ECX = carry1 // EBP = carry2 // EDI = end of dest for this pass through the loop. Index for outer loop. // ESI = end of left. never changes // [ESP] = M = right[i] = multiplier for this pass through the loop. // right.length is changed into dest.ptr+dest.length version(D_PIC) { enum { zero = 0 } } else version(LDC) { // Cannot define statics in naked functions with LDC. enum { zero = 0 } } else { // use p2 (load unit) instead of the overworked p0 or p1 (ALU units) // when initializing registers to zero. __gshared int zero = 0; // use p3/p4 units __gshared int storagenop; // write-only } enum { LASTPARAM = 6*4 } // 4* pushes + local + return address. asm pure nothrow { naked; push ESI; push EDI; align 16; push EBX; push EBP; push EAX; // local variable M mov EDI, [ESP + LASTPARAM + 4*5]; // dest.ptr mov EBX, [ESP + LASTPARAM + 4*2]; // left.length mov ESI, [ESP + LASTPARAM + 4*3]; // left.ptr lea EDI, [EDI + 4*EBX]; // EDI = end of dest for first pass mov EAX, [ESP + LASTPARAM + 4*0]; // right.length lea EAX, [EDI + 4*EAX]; mov [ESP + LASTPARAM + 4*0], EAX; // last value for EDI lea ESI, [ESI + 4*EBX]; // ESI = end of left mov EAX, [ESP + LASTPARAM + 4*1]; // right.ptr mov EAX, [EAX]; mov [ESP], EAX; // M outer_loop: mov EBP, 0; mov ECX, 0; // ECX = input carry. neg EBX; // count UP to zero. mov EAX, [ESI+4*EBX]; test EBX, 1; jnz L_enter_odd; } // -- Inner loop, with even entry point mixin("asm pure nothrow { " ~ asmMulAdd_innerloop("add", "ESP") ~ "}"); asm pure nothrow { mov [-4+EDI+4*EBX], EBP; add EDI, 4; cmp EDI, [ESP + LASTPARAM + 4*0]; // is EDI = &dest[$]? jz outer_done; mov EAX, [ESP + LASTPARAM + 4*1]; // right.ptr mov EAX, [EAX+4]; // get new M mov [ESP], EAX; // save new M add int ptr [ESP + LASTPARAM + 4*1], 4; // right.ptr mov EBX, [ESP + LASTPARAM + 4*2]; // left.length jmp outer_loop; outer_done: pop EAX; pop EBP; pop EBX; pop EDI; pop ESI; ret 6*4; } L_enter_odd: mixin("asm pure nothrow {" ~ asmMulAdd_enter_odd("add", "ESP") ~ "}"); } /** dest[#] /= divisor. * overflow is the initial remainder, and must be in the range 0..divisor-1. * divisor must not be a power of 2 (use right shift for that case; * A division by zero will occur if divisor is a power of 2). * Returns the final remainder * * Based on public domain code by Eric Bainville. * (http://www.bealto.com/) Used with permission. */ uint multibyteDivAssign(uint [] dest, uint divisor, uint overflow) pure { // Timing: limited by a horrible dependency chain. // Pentium M: 18 cycles/op, 8 resource stalls/op. // EAX, EDX = scratch, used by MUL // EDI = dest // CL = shift // ESI = quotient // EBX = remainderhi // EBP = remainderlo // [ESP-4] = mask // [ESP] = kinv (2^64 /divisor) enum { LASTPARAM = 5*4 } // 4* pushes + return address. enum { LOCALS = 2*4} // MASK, KINV asm pure nothrow { naked; push ESI; push EDI; push EBX; push EBP; mov EDI, [ESP + LASTPARAM + 4*2]; // dest.ptr mov EBX, [ESP + LASTPARAM + 4*1]; // dest.length // Loop from msb to lsb lea EDI, [EDI + 4*EBX]; mov EBP, EAX; // rem is the input remainder, in 0..divisor-1 // Build the pseudo-inverse of divisor k: 2^64/k // First determine the shift in ecx to get the max number of bits in kinv xor ECX, ECX; mov EAX, [ESP + LASTPARAM]; //divisor; mov EDX, 1; kinv1: inc ECX; ror EDX, 1; shl EAX, 1; jnc kinv1; dec ECX; // Here, ecx is a left shift moving the msb of k to bit 32 mov EAX, 1; shl EAX, CL; dec EAX; ror EAX, CL ; //ecx bits at msb push EAX; // MASK // Then divide 2^(32+cx) by divisor (edx already ok) xor EAX, EAX; div int ptr [ESP + LASTPARAM + LOCALS-4*1]; //divisor; push EAX; // kinv align 16; L2: // Get 32 bits of quotient approx, multiplying // most significant word of (rem*2^32+input) mov EAX, [ESP+4]; //MASK; and EAX, [EDI - 4]; or EAX, EBP; rol EAX, CL; mov EBX, EBP; mov EBP, [EDI - 4]; mul int ptr [ESP]; //KINV; shl EAX, 1; rcl EDX, 1; // Multiply by k and subtract to get remainder // Subtraction must be done on two words mov EAX, EDX; mov ESI, EDX; // quot = high word mul int ptr [ESP + LASTPARAM+LOCALS]; //divisor; sub EBP, EAX; sbb EBX, EDX; jz Lb; // high word is 0, goto adjust on single word // Adjust quotient and remainder on two words Ld: inc ESI; sub EBP, [ESP + LASTPARAM+LOCALS]; //divisor; sbb EBX, 0; jnz Ld; // Adjust quotient and remainder on single word Lb: cmp EBP, [ESP + LASTPARAM+LOCALS]; //divisor; jc Lc; // rem in 0..divisor-1, OK sub EBP, [ESP + LASTPARAM+LOCALS]; //divisor; inc ESI; jmp Lb; // Store result Lc: mov [EDI - 4], ESI; lea EDI, [EDI - 4]; dec int ptr [ESP + LASTPARAM + 4*1+LOCALS]; // len jnz L2; pop EAX; // discard kinv pop EAX; // discard mask mov EAX, EBP; // return final remainder pop EBP; pop EBX; pop EDI; pop ESI; ret 3*4; } } unittest { uint [] aa = new uint[101]; for (int i=0; i>= 32; c += cast(ulong)(x[$-3]) * x[$-1] + dest[$-4]; dest[$-4] = cast(uint)c; c >>= 32; length2: c += cast(ulong)(x[$-2]) * x[$-1]; dest[$-3] = cast(uint)c; c >>= 32; dest[$-2] = cast(uint)c; } //dest += src[0]*src[1...$] + src[1]*src[2..$] + ... + src[$-3]*src[$-2..$]+ src[$-2]*src[$-1] // assert(dest.length = src.length*2); // assert(src.length >= 3); void multibyteTriangleAccumulateAsm(uint[] dest, const uint[] src) pure { // Register usage // EDX:EAX = used in multiply // EBX = index // ECX = carry1 // EBP = carry2 // EDI = end of dest for this pass through the loop. Index for outer loop. // ESI = end of src. never changes // [ESP] = M = src[i] = multiplier for this pass through the loop. // dest.length is changed into dest.ptr+dest.length version(D_PIC) { enum { zero = 0 } } else version(LDC) { // Cannot define statics in naked functions with LDC. enum { zero = 0 } } else { // use p2 (load unit) instead of the overworked p0 or p1 (ALU units) // when initializing registers to zero. __gshared int zero = 0; // use p3/p4 units __gshared int storagenop; // write-only } enum { LASTPARAM = 6*4 } // 4* pushes + local + return address. asm pure nothrow { naked; push ESI; push EDI; align 16; push EBX; push EBP; push EAX; // local variable M= src[i] mov EDI, [ESP + LASTPARAM + 4*3]; // dest.ptr mov EBX, [ESP + LASTPARAM + 4*0]; // src.length mov ESI, [ESP + LASTPARAM + 4*1]; // src.ptr lea ESI, [ESI + 4*EBX]; // ESI = end of left add int ptr [ESP + LASTPARAM + 4*1], 4; // src.ptr, used for getting M // local variable [ESP + LASTPARAM + 4*2] = last value for EDI lea EDI, [EDI + 4*EBX]; // EDI = end of dest for first pass lea EAX, [EDI + 4*EBX-3*4]; // up to src.length - 3 mov [ESP + LASTPARAM + 4*2], EAX; // last value for EDI = &dest[src.length*2 -3] cmp EBX, 3; jz length_is_3; // We start at src[1], not src[0]. dec EBX; mov [ESP + LASTPARAM + 4*0], EBX; outer_loop: mov EBX, [ESP + LASTPARAM + 4*0]; // src.length mov EBP, 0; mov ECX, 0; // ECX = input carry. dec [ESP + LASTPARAM + 4*0]; // Next time, the length will be shorter by 1. neg EBX; // count UP to zero. mov EAX, [ESI + 4*EBX - 4*1]; // get new M mov [ESP], EAX; // save new M mov EAX, [ESI+4*EBX]; test EBX, 1; jnz L_enter_odd; } // -- Inner loop, with even entry point mixin("asm pure nothrow { " ~ asmMulAdd_innerloop("add", "ESP") ~ "}"); asm pure nothrow { mov [-4+EDI+4*EBX], EBP; add EDI, 4; cmp EDI, [ESP + LASTPARAM + 4*2]; // is EDI = &dest[$-3]? jnz outer_loop; length_is_3: mov EAX, [ESI - 4*3]; mul EAX, [ESI - 4*2]; mov ECX, 0; add [EDI-2*4], EAX; // ECX:dest[$-5] += x[$-3] * x[$-2] adc ECX, EDX; mov EAX, [ESI - 4*3]; mul EAX, [ESI - 4*1]; // x[$-3] * x[$-1] add EAX, ECX; mov ECX, 0; adc EDX, 0; // now EDX: EAX = c + x[$-3] * x[$-1] add [EDI-1*4], EAX; // ECX:dest[$-4] += (EDX:EAX) adc ECX, EDX; // ECX holds dest[$-3], it acts as carry for the last row // do length==2 mov EAX, [ESI - 4*2]; mul EAX, [ESI - 4*1]; add ECX, EAX; adc EDX, 0; mov [EDI - 0*4], ECX; // dest[$-2:$-3] = c + x[$-2] * x[$-1]; mov [EDI + 1*4], EDX; pop EAX; pop EBP; pop EBX; pop EDI; pop ESI; ret 4*4; } L_enter_odd: mixin("asm pure nothrow {" ~ asmMulAdd_enter_odd("add", "ESP") ~ "}"); } unittest { uint [] aa = new uint[200]; uint [] a = aa[0..100]; uint [] b = new uint [100]; aa[] = 761; a[] = 0; b[] = 0; a[3] = 6; b[0]=1; b[1] = 17; b[50..100]=78; multibyteTriangleAccumulateAsm(a, b[0..50]); uint [] c = new uint[100]; c[] = 0; c[1] = 17; c[3] = 6; assert(a[]==c[]); assert(a[0]==0); aa[] = 0xFFFF_FFFF; a[] = 0; b[] = 0; b[0]= 0xbf6a1f01; b[1]= 0x6e38ed64; b[2]= 0xdaa797ed; b[3] = 0; multibyteTriangleAccumulateAsm(a[0..8], b[0..4]); assert(a[1]==0x3a600964); assert(a[2]==0x339974f6); assert(a[3]==0x46736fce); assert(a[4]==0x5e24a2b4); b[3] = 0xe93ff9f4; b[4] = 0x184f03; a[]=0; multibyteTriangleAccumulateAsm(a[0..14], b[0..7]); assert(a[3]==0x79fff5c2); assert(a[4]==0xcf384241); assert(a[5]== 0x4a17fc8); assert(a[6]==0x4d549025); } void multibyteSquare(BigDigit[] result, const BigDigit [] x) pure { if (x.length < 4) { // Special cases, not worth doing triangular. result[x.length] = multibyteMul(result[0..x.length], x, x[0], 0); multibyteMultiplyAccumulate(result[1..$], x, x[1..$]); return; } // Do half a square multiply. // dest += src[0]*src[1...$] + src[1]*src[2..$] + ... + src[$-3]*src[$-2..$]+ src[$-2]*src[$-1] result[x.length] = multibyteMul(result[1 .. x.length], x[1..$], x[0], 0); multibyteTriangleAccumulateAsm(result[2..$], x[1..$]); // Multiply by 2 result[$-1] = multibyteShlNoMMX(result[1..$-1], result[1..$-1], 1); // And add the diagonal elements result[0] = 0; multibyteAddDiagonalSquares(result, x); } version(BignumPerformanceTest) { import core.stdc.stdio; int clock() { asm { push EBX; xor EAX, EAX; cpuid; pop EBX; rdtsc; } } __gshared uint [2200] X1; __gshared uint [2200] Y1; __gshared uint [4000] Z1; void testPerformance() pure { // The performance results at the top of this file were obtained using // a Windows device driver to access the CPU performance counters. // The code below is less accurate but more widely usable. // The value for division is quite inconsistent. for (int i=0; i 0xFFFF_FFFF); } return cast(uint)c; } unittest { uint [] a = new uint[40]; uint [] b = new uint[40]; uint [] c = new uint[40]; for (size_t i = 0; i < a.length; ++i) { if (i&1) a[i]=cast(uint)(0x8000_0000 + i); else a[i]=cast(uint)i; b[i]= 0x8000_0003; } c[19]=0x3333_3333; uint carry = multibyteAddSub!('+')(c[0..18], b[0..18], a[0..18], 0); assert(c[0]==0x8000_0003); assert(c[1]==4); assert(c[19]==0x3333_3333); // check for overrun assert(carry==1); for (size_t i = 0; i < a.length; ++i) { a[i] = b[i] = c[i] = 0; } a[8]=0x048D159E; b[8]=0x048D159E; a[10]=0x1D950C84; b[10]=0x1D950C84; a[5] =0x44444444; carry = multibyteAddSub!('-')(a[0..12], a[0..12], b[0..12], 0); assert(a[11] == 0); for (size_t i = 0; i < 10; ++i) if (i != 5) assert(a[i] == 0); for (size_t q = 3; q < 36; ++q) { for (size_t i = 0; i< a.length; ++i) { a[i] = b[i] = c[i] = 0; } a[q-2]=0x040000; b[q-2]=0x040000; carry = multibyteAddSub!('-')(a[0..q], a[0..q], b[0..q], 0); assert(a[q-2]==0); } } /** dest[] += carry, or dest[] -= carry. * op must be '+' or '-' * Returns final carry or borrow (0 or 1) */ uint multibyteIncrementAssign(char op)(uint[] dest, uint carry) pure @nogc @safe { static if (op=='+') { ulong c = carry; c += dest[0]; dest[0] = cast(uint)c; if (c<=0xFFFF_FFFF) return 0; for (size_t i = 1; i < dest.length; ++i) { ++dest[i]; if (dest[i] != 0) return 0; } return 1; } else { ulong c = carry; c = dest[0] - c; dest[0] = cast(uint)c; if (c<=0xFFFF_FFFF) return 0; for (size_t i = 1; i < dest.length; ++i) { --dest[i]; if (dest[i] != 0xFFFF_FFFF) return 0; } return 1; } } /** dest[] = src[] << numbits * numbits must be in the range 1..31 */ uint multibyteShl(uint [] dest, const(uint) [] src, uint numbits) pure @nogc @safe { ulong c = 0; for (size_t i = 0; i < dest.length; ++i) { c += (cast(ulong)(src[i]) << numbits); dest[i] = cast(uint)c; c >>>= 32; } return cast(uint)c; } /** dest[] = src[] >> numbits * numbits must be in the range 1..31 */ void multibyteShr(uint [] dest, const(uint) [] src, uint numbits) pure @nogc @safe { ulong c = 0; for(ptrdiff_t i = dest.length; i!=0; --i) { c += (src[i-1] >>numbits) + (cast(ulong)(src[i-1]) << (64 - numbits)); dest[i-1] = cast(uint)c; c >>>= 32; } } unittest { uint [] aa = [0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteShr(aa[0..$-2], aa, 4); assert(aa[0] == 0x6122_2222 && aa[1] == 0xA455_5555 && aa[2] == 0x0899_9999); assert(aa[3] == 0xBCCC_CCCD); aa = [0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteShr(aa[0..$-1], aa, 4); assert(aa[0] == 0x6122_2222 && aa[1] == 0xA455_5555 && aa[2] == 0xD899_9999 && aa[3] == 0x0BCC_CCCC); aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteShl(aa[1..4], aa[1..$], 4); assert(aa[0] == 0xF0FF_FFFF && aa[1] == 0x2222_2230 && aa[2]==0x5555_5561 && aa[3]==0x9999_99A4 && aa[4]==0x0BCCC_CCCD); } /** dest[] = src[] * multiplier + carry. * Returns carry. */ uint multibyteMul(uint[] dest, const(uint)[] src, uint multiplier, uint carry) pure @nogc @safe { assert(dest.length == src.length); ulong c = carry; for(size_t i = 0; i < src.length; ++i) { c += cast(ulong)(src[i]) * multiplier; dest[i] = cast(uint)c; c>>=32; } return cast(uint)c; } unittest { uint [] aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteMul(aa[1..4], aa[1..4], 16, 0); assert(aa[0] == 0xF0FF_FFFF && aa[1] == 0x2222_2230 && aa[2]==0x5555_5561 && aa[3]==0x9999_99A4 && aa[4]==0x0BCCC_CCCD); } /** * dest[] += src[] * multiplier + carry(0..FFFF_FFFF). * Returns carry out of MSB (0..FFFF_FFFF). */ uint multibyteMulAdd(char op)(uint [] dest, const(uint)[] src, uint multiplier, uint carry) pure @nogc @safe { assert(dest.length == src.length); ulong c = carry; for(size_t i = 0; i < src.length; ++i) { static if(op=='+') { c += cast(ulong)(multiplier) * src[i] + dest[i]; dest[i] = cast(uint)c; c >>= 32; } else { c += cast(ulong)multiplier * src[i]; ulong t = cast(ulong)dest[i] - cast(uint)c; dest[i] = cast(uint)t; c = cast(uint)((c>>32) - (t>>32)); } } return cast(uint)c; } unittest { uint [] aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; uint [] bb = [0x1234_1234, 0xF0F0_F0F0, 0x00C0_C0C0, 0xF0F0_F0F0, 0xC0C0_C0C0]; multibyteMulAdd!('+')(bb[1..$-1], aa[1..$-2], 16, 5); assert(bb[0] == 0x1234_1234 && bb[4] == 0xC0C0_C0C0); assert(bb[1] == 0x2222_2230 + 0xF0F0_F0F0 + 5 && bb[2] == 0x5555_5561 + 0x00C0_C0C0 + 1 && bb[3] == 0x9999_99A4 + 0xF0F0_F0F0 ); } /** Sets result = result[0..left.length] + left * right It is defined in this way to allow cache-efficient multiplication. This function is equivalent to: ---- for (size_t i = 0; i< right.length; ++i) { dest[left.length + i] = multibyteMulAdd(dest[i..left.length+i], left, right[i], 0); } ---- */ void multibyteMultiplyAccumulate(uint [] dest, const(uint)[] left, const(uint) [] right) pure @nogc @safe { for (size_t i = 0; i < right.length; ++i) { dest[left.length + i] = multibyteMulAdd!('+')(dest[i..left.length+i], left, right[i], 0); } } /** dest[] /= divisor. * overflow is the initial remainder, and must be in the range 0..divisor-1. */ uint multibyteDivAssign(uint [] dest, uint divisor, uint overflow) pure @nogc @safe { ulong c = cast(ulong)overflow; for(ptrdiff_t i = dest.length-1; i>= 0; --i) { c = (c<<32) + cast(ulong)(dest[i]); uint q = cast(uint)(c/divisor); c -= divisor * q; dest[i] = q; } return cast(uint)c; } unittest { uint [] aa = new uint[101]; for (uint i = 0; i < aa.length; ++i) aa[i] = 0x8765_4321 * (i+3); uint overflow = multibyteMul(aa, aa, 0x8EFD_FCFB, 0x33FF_7461); uint r = multibyteDivAssign(aa, 0x8EFD_FCFB, overflow); for (uint i=0; i>=32) + dest[2*i+1]; dest[2*i+1] = cast(uint)c; c >>= 32; } } // Does half a square multiply. (square = diagonal + 2*triangle) void multibyteTriangleAccumulate(uint[] dest, const(uint)[] x) pure @nogc @safe { // x[0]*x[1...$] + x[1]*x[2..$] + ... + x[$-2]x[$-1..$] dest[x.length] = multibyteMul(dest[1 .. x.length], x[1..$], x[0], 0); if (x.length < 4) { if (x.length == 3) { ulong c = cast(ulong)(x[$-1]) * x[$-2] + dest[2*x.length-3]; dest[2*x.length - 3] = cast(uint)c; c >>= 32; dest[2*x.length - 2] = cast(uint)c; } return; } for (size_t i = 2; i < x.length - 2; ++i) { dest[i-1+ x.length] = multibyteMulAdd!('+')( dest[i+i-1 .. i+x.length-1], x[i..$], x[i-1], 0); } // Unroll the last two entries, to reduce loop overhead: ulong c = cast(ulong)(x[$-3]) * x[$-2] + dest[2*x.length-5]; dest[2*x.length-5] = cast(uint)c; c >>= 32; c += cast(ulong)(x[$-3]) * x[$-1] + dest[2*x.length-4]; dest[2*x.length-4] = cast(uint)c; c >>= 32; c += cast(ulong)(x[$-1]) * x[$-2]; dest[2*x.length-3] = cast(uint)c; c >>= 32; dest[2*x.length-2] = cast(uint)c; } void multibyteSquare(BigDigit[] result, const(BigDigit) [] x) pure @nogc @safe { multibyteTriangleAccumulate(result, x); result[$-1] = multibyteShl(result[1..$-1], result[1..$-1], 1); // mul by 2 result[0] = 0; multibyteAddDiagonalSquares(result, x); } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/math/gammafunction.d0000664000175000017500000014461412776215007023462 0ustar kaikai/** * Implementation of the gamma and beta functions, and their integrals. * * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). * Copyright: Based on the CEPHES math library, which is * Copyright (C) 1994 Stephen L. Moshier (moshier@world.std.com). * Authors: Stephen L. Moshier (original C code). Conversion to D by Don Clugston * * Macros: * TABLE_SV = * * $0
Special Values
* SVH = $(TR $(TH $1) $(TH $2)) * SV = $(TR $(TD $1) $(TD $2)) * GAMMA = Γ * INTEGRATE = $(BIG ∫$(SMALL $1)$2) * POWER = $1$2 * NAN = $(RED NAN) */ module std.internal.math.gammafunction; import std.internal.math.errorfunction; import std.math; pure: nothrow: @safe: @nogc: private { enum real SQRT2PI = 2.50662827463100050242E0L; // sqrt(2pi) immutable real EULERGAMMA = 0.57721_56649_01532_86060_65120_90082_40243_10421_59335_93992L; /** Euler-Mascheroni constant 0.57721566.. */ // Polynomial approximations for gamma and loggamma. immutable real[8] GammaNumeratorCoeffs = [ 1.0, 0x1.acf42d903366539ep-1, 0x1.73a991c8475f1aeap-2, 0x1.c7e918751d6b2a92p-4, 0x1.86d162cca32cfe86p-6, 0x1.0c378e2e6eaf7cd8p-8, 0x1.dc5c66b7d05feb54p-12, 0x1.616457b47e448694p-15 ]; immutable real[9] GammaDenominatorCoeffs = [ 1.0, 0x1.a8f9faae5d8fc8bp-2, -0x1.cb7895a6756eebdep-3, -0x1.7b9bab006d30652ap-5, 0x1.c671af78f312082ep-6, -0x1.a11ebbfaf96252dcp-11, -0x1.447b4d2230a77ddap-10, 0x1.ec1d45bb85e06696p-13,-0x1.d4ce24d05bd0a8e6p-17 ]; immutable real[9] GammaSmallCoeffs = [ 1.0, 0x1.2788cfc6fb618f52p-1, -0x1.4fcf4026afa2f7ecp-1, -0x1.5815e8fa24d7e306p-5, 0x1.5512320aea2ad71ap-3, -0x1.59af0fb9d82e216p-5, -0x1.3b4b61d3bfdf244ap-7, 0x1.d9358e9d9d69fd34p-8, -0x1.38fc4bcbada775d6p-10 ]; immutable real[9] GammaSmallNegCoeffs = [ -1.0, 0x1.2788cfc6fb618f54p-1, 0x1.4fcf4026afa2bc4cp-1, -0x1.5815e8fa2468fec8p-5, -0x1.5512320baedaf4b6p-3, -0x1.59af0fa283baf07ep-5, 0x1.3b4a70de31e05942p-7, 0x1.d9398be3bad13136p-8, 0x1.291b73ee05bcbba2p-10 ]; immutable real[7] logGammaStirlingCoeffs = [ 0x1.5555555555553f98p-4, -0x1.6c16c16c07509b1p-9, 0x1.a01a012461cbf1e4p-11, -0x1.3813089d3f9d164p-11, 0x1.b911a92555a277b8p-11, -0x1.ed0a7b4206087b22p-10, 0x1.402523859811b308p-8 ]; immutable real[7] logGammaNumerator = [ -0x1.0edd25913aaa40a2p+23, -0x1.31c6ce2e58842d1ep+24, -0x1.f015814039477c3p+23, -0x1.74ffe40c4b184b34p+22, -0x1.0d9c6d08f9eab55p+20, -0x1.54c6b71935f1fc88p+16, -0x1.0e761b42932b2aaep+11 ]; immutable real[8] logGammaDenominator = [ -0x1.4055572d75d08c56p+24, -0x1.deeb6013998e4d76p+24, -0x1.106f7cded5dcc79ep+24, -0x1.25e17184848c66d2p+22, -0x1.301303b99a614a0ap+19, -0x1.09e76ab41ae965p+15, -0x1.00f95ced9e5f54eep+9, 1.0 ]; /* * Helper function: Gamma function computed by Stirling's formula. * * Stirling's formula for the gamma function is: * * $(GAMMA)(x) = sqrt(2 π) xx-0.5 exp(-x) (1 + 1/x P(1/x)) * */ real gammaStirling(real x) { // CEPHES code Copyright 1994 by Stephen L. Moshier static immutable real[9] SmallStirlingCoeffs = [ 0x1.55555555555543aap-4, 0x1.c71c71c720dd8792p-9, -0x1.5f7268f0b5907438p-9, -0x1.e13cd410e0477de6p-13, 0x1.9b0f31643442616ep-11, 0x1.2527623a3472ae08p-14, -0x1.37f6bc8ef8b374dep-11,-0x1.8c968886052b872ap-16, 0x1.76baa9c6d3eeddbcp-11 ]; static immutable real[7] LargeStirlingCoeffs = [ 1.0L, 8.33333333333333333333E-2L, 3.47222222222222222222E-3L, -2.68132716049382716049E-3L, -2.29472093621399176955E-4L, 7.84039221720066627474E-4L, 6.97281375836585777429E-5L ]; real w = 1.0L/x; real y = exp(x); if ( x > 1024.0L ) { // For large x, use rational coefficients from the analytical expansion. w = poly(w, LargeStirlingCoeffs); // Avoid overflow in pow() real v = pow( x, 0.5L * x - 0.25L ); y = v * (v / y); } else { w = 1.0L + w * poly( w, SmallStirlingCoeffs); static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) { // Avoid overflow in pow() for 64-bit reals if (x > 143.0) { real v = pow( x, 0.5 * x - 0.25 ); y = v * (v / y); } else { y = pow( x, x - 0.5 ) / y; } } else { y = pow( x, x - 0.5L ) / y; } } y = SQRT2PI * y * w; return y; } /* * Helper function: Incomplete gamma function computed by Temme's expansion. * * This is a port of igamma_temme_large from Boost. * */ real igammaTemmeLarge(real a, real x) { static immutable real[][13] coef = [ [ -0.333333333333333333333, 0.0833333333333333333333, -0.0148148148148148148148, 0.00115740740740740740741, 0.000352733686067019400353, -0.0001787551440329218107, 0.39192631785224377817e-4, -0.218544851067999216147e-5, -0.18540622107151599607e-5, 0.829671134095308600502e-6, -0.176659527368260793044e-6, 0.670785354340149858037e-8, 0.102618097842403080426e-7, -0.438203601845335318655e-8, 0.914769958223679023418e-9, -0.255141939949462497669e-10, -0.583077213255042506746e-10, 0.243619480206674162437e-10, -0.502766928011417558909e-11 ], [ -0.00185185185185185185185, -0.00347222222222222222222, 0.00264550264550264550265, -0.000990226337448559670782, 0.000205761316872427983539, -0.40187757201646090535e-6, -0.18098550334489977837e-4, 0.764916091608111008464e-5, -0.161209008945634460038e-5, 0.464712780280743434226e-8, 0.137863344691572095931e-6, -0.575254560351770496402e-7, 0.119516285997781473243e-7, -0.175432417197476476238e-10, -0.100915437106004126275e-8, 0.416279299184258263623e-9, -0.856390702649298063807e-10 ], [ 0.00413359788359788359788, -0.00268132716049382716049, 0.000771604938271604938272, 0.200938786008230452675e-5, -0.000107366532263651605215, 0.529234488291201254164e-4, -0.127606351886187277134e-4, 0.342357873409613807419e-7, 0.137219573090629332056e-5, -0.629899213838005502291e-6, 0.142806142060642417916e-6, -0.204770984219908660149e-9, -0.140925299108675210533e-7, 0.622897408492202203356e-8, -0.136704883966171134993e-8 ], [ 0.000649434156378600823045, 0.000229472093621399176955, -0.000469189494395255712128, 0.000267720632062838852962, -0.756180167188397641073e-4, -0.239650511386729665193e-6, 0.110826541153473023615e-4, -0.56749528269915965675e-5, 0.142309007324358839146e-5, -0.278610802915281422406e-10, -0.169584040919302772899e-6, 0.809946490538808236335e-7, -0.191111684859736540607e-7 ], [ -0.000861888290916711698605, 0.000784039221720066627474, -0.000299072480303190179733, -0.146384525788434181781e-5, 0.664149821546512218666e-4, -0.396836504717943466443e-4, 0.113757269706784190981e-4, 0.250749722623753280165e-9, -0.169541495365583060147e-5, 0.890750753220530968883e-6, -0.229293483400080487057e-6], [ -0.000336798553366358150309, -0.697281375836585777429e-4, 0.000277275324495939207873, -0.000199325705161888477003, 0.679778047793720783882e-4, 0.141906292064396701483e-6, -0.135940481897686932785e-4, 0.801847025633420153972e-5, -0.229148117650809517038e-5 ], [ 0.000531307936463992223166, -0.000592166437353693882865, 0.000270878209671804482771, 0.790235323266032787212e-6, -0.815396936756196875093e-4, 0.561168275310624965004e-4, -0.183291165828433755673e-4, -0.307961345060330478256e-8, 0.346515536880360908674e-5, -0.20291327396058603727e-5, 0.57887928631490037089e-6 ], [ 0.000344367606892377671254, 0.517179090826059219337e-4, -0.000334931610811422363117, 0.000281269515476323702274, -0.000109765822446847310235, -0.127410090954844853795e-6, 0.277444515115636441571e-4, -0.182634888057113326614e-4, 0.578769494973505239894e-5 ], [ -0.000652623918595309418922, 0.000839498720672087279993, -0.000438297098541721005061, -0.696909145842055197137e-6, 0.000166448466420675478374, -0.000127835176797692185853, 0.462995326369130429061e-4 ], [ -0.000596761290192746250124, -0.720489541602001055909e-4, 0.000678230883766732836162, -0.0006401475260262758451, 0.000277501076343287044992 ], [ 0.00133244544948006563713, -0.0019144384985654775265, 0.00110893691345966373396 ], [ 0.00157972766073083495909, 0.000162516262783915816899, -0.00206334210355432762645, 0.00213896861856890981541, -0.00101085593912630031708 ], [ -0.00407251211951401664727, 0.00640336283380806979482, -0.00404101610816766177474 ] ]; // avoid nans when one of the arguments is inf: if(x == real.infinity && a != real.infinity) return 0; if(x != real.infinity && a == real.infinity) return 1; real sigma = (x - a) / a; real phi = sigma - log(sigma + 1); real y = a * phi; real z = sqrt(2 * phi); if(x < a) z = -z; real[13] workspace; foreach(i; 0 .. coef.length) workspace[i] = poly(z, coef[i]); real result = poly(1 / a, workspace); result *= exp(-y) / sqrt(2 * PI * a); if(x < a) result = -result; result += erfc(sqrt(y)) / 2; return result; } } // private public: /// The maximum value of x for which gamma(x) < real.infinity. static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) enum real MAXGAMMA = 1755.5483429L; else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) enum real MAXGAMMA = 171.6243769L; else static assert(0, "missing MAXGAMMA for other real types"); /***************************************************** * The Gamma function, $(GAMMA)(x) * * $(GAMMA)(x) is a generalisation of the factorial function * to real and complex numbers. * Like x!, $(GAMMA)(x+1) = x*$(GAMMA)(x). * * Mathematically, if z.re > 0 then * $(GAMMA)(z) = $(INTEGRATE 0, ∞) $(POWER t, z-1)$(POWER e, -t) dt * * $(TABLE_SV * $(SVH x, $(GAMMA)(x) ) * $(SV $(NAN), $(NAN) ) * $(SV ±0.0, ±∞) * $(SV integer > 0, (x-1)! ) * $(SV integer < 0, $(NAN) ) * $(SV +∞, +∞ ) * $(SV -∞, $(NAN) ) * ) */ real gamma(real x) { /* Based on code from the CEPHES library. * CEPHES code Copyright 1994 by Stephen L. Moshier * * Arguments |x| <= 13 are reduced by recurrence and the function * approximated by a rational function of degree 7/8 in the * interval (2,3). Large arguments are handled by Stirling's * formula. Large negative arguments are made positive using * a reflection formula. */ real q, z; if (isNaN(x)) return x; if (x == -x.infinity) return real.nan; if ( fabs(x) > MAXGAMMA ) return real.infinity; if (x==0) return 1.0 / x; // +- infinity depending on sign of x, create an exception. q = fabs(x); if ( q > 13.0L ) { // Large arguments are handled by Stirling's // formula. Large negative arguments are made positive using // the reflection formula. if ( x < 0.0L ) { if (x < -1/real.epsilon) { // Large negatives lose all precision return real.nan; } int sgngam = 1; // sign of gamma. long intpart = cast(long)(q); if (q == intpart) return real.nan; // poles for all integers <0. real p = intpart; if ( (intpart & 1) == 0 ) sgngam = -1; z = q - p; if ( z > 0.5L ) { p += 1.0L; z = q - p; } z = q * sin( PI * z ); z = fabs(z) * gammaStirling(q); if ( z <= PI/real.max ) return sgngam * real.infinity; return sgngam * PI/z; } else { return gammaStirling(x); } } // Arguments |x| <= 13 are reduced by recurrence and the function // approximated by a rational function of degree 7/8 in the // interval (2,3). z = 1.0L; while ( x >= 3.0L ) { x -= 1.0L; z *= x; } while ( x < -0.03125L ) { z /= x; x += 1.0L; } if ( x <= 0.03125L ) { if ( x == 0.0L ) return real.nan; else { if ( x < 0.0L ) { x = -x; return z / (x * poly( x, GammaSmallNegCoeffs )); } else { return z / (x * poly( x, GammaSmallCoeffs )); } } } while ( x < 2.0L ) { z /= x; x += 1.0L; } if ( x == 2.0L ) return z; x -= 2.0L; return z * poly( x, GammaNumeratorCoeffs ) / poly( x, GammaDenominatorCoeffs ); } unittest { // gamma(n) = factorial(n-1) if n is an integer. real fact = 1.0L; for (int i=1; fact= real.mant_dig-15); fact *= (i*1.0L); } assert(gamma(0.0) == real.infinity); assert(gamma(-0.0) == -real.infinity); assert(isNaN(gamma(-1.0))); assert(isNaN(gamma(-15.0))); assert(isIdentical(gamma(NaN(0xABC)), NaN(0xABC))); assert(gamma(real.infinity) == real.infinity); assert(gamma(real.max) == real.infinity); assert(isNaN(gamma(-real.infinity))); assert(gamma(real.min_normal*real.epsilon) == real.infinity); assert(gamma(MAXGAMMA)< real.infinity); assert(gamma(MAXGAMMA*2) == real.infinity); // Test some high-precision values (50 decimal digits) real SQRT_PI = 1.77245385090551602729816748334114518279754945612238L; assert(feqrel(gamma(0.5L), SQRT_PI) >= real.mant_dig-1); assert(feqrel(gamma(17.25L), 4.224986665692703551570937158682064589938e13L) >= real.mant_dig-4); assert(feqrel(gamma(1.0 / 3.0L), 2.67893853470774763365569294097467764412868937795730L) >= real.mant_dig-2); assert(feqrel(gamma(0.25L), 3.62560990822190831193068515586767200299516768288006L) >= real.mant_dig-1); assert(feqrel(gamma(1.0 / 5.0L), 4.59084371199880305320475827592915200343410999829340L) >= real.mant_dig-1); } /***************************************************** * Natural logarithm of gamma function. * * Returns the base e (2.718...) logarithm of the absolute * value of the gamma function of the argument. * * For reals, logGamma is equivalent to log(fabs(gamma(x))). * * $(TABLE_SV * $(SVH x, logGamma(x) ) * $(SV $(NAN), $(NAN) ) * $(SV integer <= 0, +∞ ) * $(SV ±∞, +∞ ) * ) */ real logGamma(real x) { /* Based on code from the CEPHES library. * CEPHES code Copyright 1994 by Stephen L. Moshier * * For arguments greater than 33, the logarithm of the gamma * function is approximated by the logarithmic version of * Stirling's formula using a polynomial approximation of * degree 4. Arguments between -33 and +33 are reduced by * recurrence to the interval [2,3] of a rational approximation. * The cosecant reflection formula is employed for arguments * less than -33. */ real q, w, z, f, nx; if (isNaN(x)) return x; if (fabs(x) == x.infinity) return x.infinity; if( x < -34.0L ) { q = -x; w = logGamma(q); real p = floor(q); if ( p == q ) return real.infinity; int intpart = cast(int)(p); real sgngam = 1; if ( (intpart & 1) == 0 ) sgngam = -1; z = q - p; if ( z > 0.5L ) { p += 1.0L; z = p - q; } z = q * sin( PI * z ); if ( z == 0.0L ) return sgngam * real.infinity; /* z = LOGPI - logl( z ) - w; */ z = log( PI/z ) - w; return z; } if( x < 13.0L ) { z = 1.0L; nx = floor( x + 0.5L ); f = x - nx; while ( x >= 3.0L ) { nx -= 1.0L; x = nx + f; z *= x; } while ( x < 2.0L ) { if( fabs(x) <= 0.03125 ) { if ( x == 0.0L ) return real.infinity; if ( x < 0.0L ) { x = -x; q = z / (x * poly( x, GammaSmallNegCoeffs)); } else q = z / (x * poly( x, GammaSmallCoeffs)); return log( fabs(q) ); } z /= nx + f; nx += 1.0L; x = nx + f; } z = fabs(z); if ( x == 2.0L ) return log(z); x = (nx - 2.0L) + f; real p = x * rationalPoly( x, logGammaNumerator, logGammaDenominator); return log(z) + p; } // const real MAXLGM = 1.04848146839019521116e+4928L; // if( x > MAXLGM ) return sgngaml * real.infinity; const real LOGSQRT2PI = 0.91893853320467274178L; // log( sqrt( 2*pi ) ) q = ( x - 0.5L ) * log(x) - x + LOGSQRT2PI; if (x > 1.0e10L) return q; real p = 1.0L / (x*x); q += poly( p, logGammaStirlingCoeffs ) / x; return q ; } unittest { assert(isIdentical(logGamma(NaN(0xDEF)), NaN(0xDEF))); assert(logGamma(real.infinity) == real.infinity); assert(logGamma(-1.0) == real.infinity); assert(logGamma(0.0) == real.infinity); assert(logGamma(-50.0) == real.infinity); assert(isIdentical(0.0L, logGamma(1.0L))); assert(isIdentical(0.0L, logGamma(2.0L))); assert(logGamma(real.min_normal*real.epsilon) == real.infinity); assert(logGamma(-real.min_normal*real.epsilon) == real.infinity); // x, correct loggamma(x), correct d/dx loggamma(x). immutable static real[] testpoints = [ 8.0L, 8.525146484375L + 1.48766904143001655310E-5, 2.01564147795560999654E0L, 8.99993896484375e-1L, 6.6375732421875e-2L + 5.11505711292524166220E-6L, -7.54938684259372234258E-1, 7.31597900390625e-1L, 2.2369384765625e-1 + 5.21506341809849792422E-6L, -1.13355566660398608343E0L, 2.31639862060546875e-1L, 1.3686676025390625L + 1.12609441752996145670E-5L, -4.56670961813812679012E0, 1.73162841796875L, -8.88214111328125e-2L + 3.36207740803753034508E-6L, 2.33339034686200586920E-1L, 1.23162841796875L, -9.3902587890625e-2L + 1.28765089229009648104E-5L, -2.49677345775751390414E-1L, 7.3786976294838206464e19L, 3.301798506038663053312e21L - 1.656137564136932662487046269677E5L, 4.57477139169563904215E1L, 1.08420217248550443401E-19L, 4.36682586669921875e1L + 1.37082843669932230418E-5L, -9.22337203685477580858E18L, 1.0L, 0.0L, -5.77215664901532860607E-1L, 2.0L, 0.0L, 4.22784335098467139393E-1L, -0.5L, 1.2655029296875L + 9.19379714539648894580E-6L, 3.64899739785765205590E-2L, -1.5L, 8.6004638671875e-1L + 6.28657731014510932682E-7L, 7.03156640645243187226E-1L, -2.5L, -5.6243896484375E-2L + 1.79986700949327405470E-7, 1.10315664064524318723E0L, -3.5L, -1.30902099609375L + 1.43111007079536392848E-5L, 1.38887092635952890151E0L ]; // TODO: test derivatives as well. for (int i=0; i real.mant_dig-5); if (testpoints[i] real.mant_dig-5); } } assert(logGamma(-50.2) == log(fabs(gamma(-50.2)))); assert(logGamma(-0.008) == log(fabs(gamma(-0.008)))); assert(feqrel(logGamma(-38.8),log(fabs(gamma(-38.8)))) > real.mant_dig-4); static if (real.mant_dig >= 64) // incl. 80-bit reals assert(feqrel(logGamma(1500.0L),log(gamma(1500.0L))) > real.mant_dig-2); else static if (real.mant_dig >= 53) // incl. 64-bit reals assert(feqrel(logGamma(150.0L),log(gamma(150.0L))) > real.mant_dig-2); } private { static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) { enum real MAXLOG = 0x1.62e42fefa39ef358p+13L; // log(real.max) enum real MINLOG = -0x1.6436716d5406e6d8p+13L; // log(real.min_normal*real.epsilon) = log(smallest denormal) } else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) { enum real MAXLOG = 0x1.62e42fefa39efp+9L; // log(real.max) enum real MINLOG = -0x1.74385446d71c3p+9L; // log(real.min_normal*real.epsilon) = log(smallest denormal) } else static assert(0, "missing MAXLOG and MINLOG for other real types"); enum real BETA_BIG = 9.223372036854775808e18L; enum real BETA_BIGINV = 1.084202172485504434007e-19L; } /** Incomplete beta integral * * Returns incomplete beta integral of the arguments, evaluated * from zero to x. The regularized incomplete beta function is defined as * * betaIncomplete(a, b, x) = Γ(a+b)/(Γ(a) Γ(b)) * * $(INTEGRATE 0, x) $(POWER t, a-1)$(POWER (1-t),b-1) dt * * and is the same as the the cumulative distribution function. * * The domain of definition is 0 <= x <= 1. In this * implementation a and b are restricted to positive values. * The integral from x to 1 may be obtained by the symmetry * relation * * betaIncompleteCompl(a, b, x ) = betaIncomplete( b, a, 1-x ) * * The integral is evaluated by a continued fraction expansion * or, when b*x is small, by a power series. */ real betaIncomplete(real aa, real bb, real xx ) { if ( !(aa>0 && bb>0) ) { if ( isNaN(aa) ) return aa; if ( isNaN(bb) ) return bb; return real.nan; // domain error } if (!(xx>0 && xx<1.0)) { if (isNaN(xx)) return xx; if ( xx == 0.0L ) return 0.0; if ( xx == 1.0L ) return 1.0; return real.nan; // domain error } if ( (bb * xx) <= 1.0L && xx <= 0.95L) { return betaDistPowerSeries(aa, bb, xx); } real x; real xc; // = 1 - x real a, b; int flag = 0; /* Reverse a and b if x is greater than the mean. */ if( xx > (aa/(aa+bb)) ) { // here x > aa/(aa+bb) and (bb*x>1 or x>0.95) flag = 1; a = bb; b = aa; xc = xx; x = 1.0L - xx; } else { a = aa; b = bb; xc = 1.0L - xx; x = xx; } if( flag == 1 && (b * x) <= 1.0L && x <= 0.95L) { // here xx > aa/(aa+bb) and ((bb*xx>1) or xx>0.95) and (aa*(1-xx)<=1) and xx > 0.05 return 1.0 - betaDistPowerSeries(a, b, x); // note loss of precision } real w; // Choose expansion for optimal convergence // One is for x * (a+b+2) < (a+1), // the other is for x * (a+b+2) > (a+1). real y = x * (a+b-2.0L) - (a-1.0L); if( y < 0.0L ) { w = betaDistExpansion1( a, b, x ); } else { w = betaDistExpansion2( a, b, x ) / xc; } /* Multiply w by the factor a b x (1-x) Gamma(a+b) / ( a Gamma(a) Gamma(b) ) . */ y = a * log(x); real t = b * log(xc); if ( (a+b) < MAXGAMMA && fabs(y) < MAXLOG && fabs(t) < MAXLOG ) { t = pow(xc,b); t *= pow(x,a); t /= a; t *= w; t *= gamma(a+b) / (gamma(a) * gamma(b)); } else { /* Resort to logarithms. */ y += t + logGamma(a+b) - logGamma(a) - logGamma(b); y += log(w/a); t = exp(y); /+ // There seems to be a bug in Cephes at this point. // Problems occur for y > MAXLOG, not y < MINLOG. if( y < MINLOG ) { t = 0.0L; } else { t = exp(y); } +/ } if( flag == 1 ) { /+ // CEPHES includes this code, but I think it is erroneous. if( t <= real.epsilon ) { t = 1.0L - real.epsilon; } else +/ t = 1.0L - t; } return t; } /** Inverse of incomplete beta integral * * Given y, the function finds x such that * * betaIncomplete(a, b, x) == y * * Newton iterations or interval halving is used. */ real betaIncompleteInv(real aa, real bb, real yy0 ) { real a, b, y0, d, y, x, x0, x1, lgm, yp, di, dithresh, yl, yh, xt; int i, rflg, dir, nflg; if (isNaN(yy0)) return yy0; if (isNaN(aa)) return aa; if (isNaN(bb)) return bb; if( yy0 <= 0.0L ) return 0.0L; if( yy0 >= 1.0L ) return 1.0L; x0 = 0.0L; yl = 0.0L; x1 = 1.0L; yh = 1.0L; if( aa <= 1.0L || bb <= 1.0L ) { dithresh = 1.0e-7L; rflg = 0; a = aa; b = bb; y0 = yy0; x = a/(a+b); y = betaIncomplete( a, b, x ); nflg = 0; goto ihalve; } else { nflg = 0; dithresh = 1.0e-4L; } // approximation to inverse function yp = -normalDistributionInvImpl( yy0 ); if( yy0 > 0.5L ) { rflg = 1; a = bb; b = aa; y0 = 1.0L - yy0; yp = -yp; } else { rflg = 0; a = aa; b = bb; y0 = yy0; } lgm = (yp * yp - 3.0L)/6.0L; x = 2.0L/( 1.0L/(2.0L * a-1.0L) + 1.0L/(2.0L * b - 1.0L) ); d = yp * sqrt( x + lgm ) / x - ( 1.0L/(2.0L * b - 1.0L) - 1.0L/(2.0L * a - 1.0L) ) * (lgm + (5.0L/6.0L) - 2.0L/(3.0L * x)); d = 2.0L * d; if( d < MINLOG ) { x = 1.0L; goto under; } x = a/( a + b * exp(d) ); y = betaIncomplete( a, b, x ); yp = (y - y0)/y0; if( fabs(yp) < 0.2 ) goto newt; /* Resort to interval halving if not close enough. */ ihalve: dir = 0; di = 0.5L; for( i=0; i<400; i++ ) { if( i != 0 ) { x = x0 + di * (x1 - x0); if( x == 1.0L ) { x = 1.0L - real.epsilon; } if( x == 0.0L ) { di = 0.5; x = x0 + di * (x1 - x0); if( x == 0.0 ) goto under; } y = betaIncomplete( a, b, x ); yp = (x1 - x0)/(x1 + x0); if( fabs(yp) < dithresh ) goto newt; yp = (y-y0)/y0; if( fabs(yp) < dithresh ) goto newt; } if( y < y0 ) { x0 = x; yl = y; if( dir < 0 ) { dir = 0; di = 0.5L; } else if( dir > 3 ) di = 1.0L - (1.0L - di) * (1.0L - di); else if( dir > 1 ) di = 0.5L * di + 0.5L; else di = (y0 - y)/(yh - yl); dir += 1; if( x0 > 0.95L ) { if( rflg == 1 ) { rflg = 0; a = aa; b = bb; y0 = yy0; } else { rflg = 1; a = bb; b = aa; y0 = 1.0 - yy0; } x = 1.0L - x; y = betaIncomplete( a, b, x ); x0 = 0.0; yl = 0.0; x1 = 1.0; yh = 1.0; goto ihalve; } } else { x1 = x; if( rflg == 1 && x1 < real.epsilon ) { x = 0.0L; goto done; } yh = y; if( dir > 0 ) { dir = 0; di = 0.5L; } else if( dir < -3 ) di = di * di; else if( dir < -1 ) di = 0.5L * di; else di = (y - y0)/(yh - yl); dir -= 1; } } if( x0 >= 1.0L ) { // partial loss of precision x = 1.0L - real.epsilon; goto done; } if( x <= 0.0L ) { under: // underflow has occurred x = real.min_normal * real.min_normal; goto done; } newt: if ( nflg ) { goto done; } nflg = 1; lgm = logGamma(a+b) - logGamma(a) - logGamma(b); for( i=0; i<15; i++ ) { /* Compute the function at this point. */ if ( i != 0 ) y = betaIncomplete(a,b,x); if ( y < yl ) { x = x0; y = yl; } else if( y > yh ) { x = x1; y = yh; } else if( y < y0 ) { x0 = x; yl = y; } else { x1 = x; yh = y; } if( x == 1.0L || x == 0.0L ) break; /* Compute the derivative of the function at this point. */ d = (a - 1.0L) * log(x) + (b - 1.0L) * log(1.0L - x) + lgm; if ( d < MINLOG ) { goto done; } if ( d > MAXLOG ) { break; } d = exp(d); /* Compute the step to the next approximation of x. */ d = (y - y0)/d; xt = x - d; if ( xt <= x0 ) { y = (x - x0) / (x1 - x0); xt = x0 + 0.5L * y * (x - x0); if( xt <= 0.0L ) break; } if ( xt >= x1 ) { y = (x1 - x) / (x1 - x0); xt = x1 - 0.5L * y * (x1 - x); if ( xt >= 1.0L ) break; } x = xt; if ( fabs(d/x) < (128.0L * real.epsilon) ) goto done; } /* Did not converge. */ dithresh = 256.0L * real.epsilon; goto ihalve; done: if ( rflg ) { if( x <= real.epsilon ) x = 1.0L - real.epsilon; else x = 1.0L - x; } return x; } unittest { // also tested by the normal distribution // check NaN propagation assert(isIdentical(betaIncomplete(NaN(0xABC),2,3), NaN(0xABC))); assert(isIdentical(betaIncomplete(7,NaN(0xABC),3), NaN(0xABC))); assert(isIdentical(betaIncomplete(7,15,NaN(0xABC)), NaN(0xABC))); assert(isIdentical(betaIncompleteInv(NaN(0xABC),1,17), NaN(0xABC))); assert(isIdentical(betaIncompleteInv(2,NaN(0xABC),8), NaN(0xABC))); assert(isIdentical(betaIncompleteInv(2,3, NaN(0xABC)), NaN(0xABC))); assert(isNaN(betaIncomplete(-1, 2, 3))); assert(betaIncomplete(1, 2, 0)==0); assert(betaIncomplete(1, 2, 1)==1); assert(isNaN(betaIncomplete(1, 2, 3))); assert(betaIncompleteInv(1, 1, 0)==0); assert(betaIncompleteInv(1, 1, 1)==1); // Test against Mathematica betaRegularized[z,a,b] // These arbitrary points are chosen to give good code coverage. assert(feqrel(betaIncomplete(8, 10, 0.2), 0.010_934_315_234_099_2L) >= real.mant_dig - 5); assert(feqrel(betaIncomplete(2, 2.5, 0.9), 0.989_722_597_604_452_767_171_003_59L) >= real.mant_dig - 1); static if (real.mant_dig >= 64) // incl. 80-bit reals assert(feqrel(betaIncomplete(1000, 800, 0.5), 1.179140859734704555102808541457164E-06L) >= real.mant_dig - 13); else assert(feqrel(betaIncomplete(1000, 800, 0.5), 1.179140859734704555102808541457164E-06L) >= real.mant_dig - 14); assert(feqrel(betaIncomplete(0.0001, 10000, 0.0001), 0.999978059362107134278786L) >= real.mant_dig - 18); assert(betaIncomplete(0.01, 327726.7, 0.545113) == 1.0); assert(feqrel(betaIncompleteInv(8, 10, 0.010_934_315_234_099_2L), 0.2L) >= real.mant_dig - 2); assert(feqrel(betaIncomplete(0.01, 498.437, 0.0121433), 0.99999664562033077636065L) >= real.mant_dig - 1); assert(feqrel(betaIncompleteInv(5, 10, 0.2000002972865658842), 0.229121208190918L) >= real.mant_dig - 3); assert(feqrel(betaIncompleteInv(4, 7, 0.8000002209179505L), 0.483657360076904L) >= real.mant_dig - 3); // Coverage tests. I don't have correct values for these tests, but // these values cover most of the code, so they are useful for // regression testing. // Extensive testing failed to increase the coverage. It seems likely that about // half the code in this function is unnecessary; there is potential for // significant improvement over the original CEPHES code. static if (real.mant_dig == 64) // 80-bit reals { assert(betaIncompleteInv(0.01, 8e-48, 5.45464e-20) == 1-real.epsilon); assert(betaIncompleteInv(0.01, 8e-48, 9e-26) == 1-real.epsilon); // Beware: a one-bit change in pow() changes almost all digits in the result! assert(feqrel(betaIncompleteInv(0x1.b3d151fbba0eb18p+1, 1.2265e-19, 2.44859e-18), 0x1.c0110c8531d0952cp-1L) > 10); // This next case uncovered a one-bit difference in the FYL2X instruction // between Intel and AMD processors. This difference gets magnified by 2^^38. // WolframAlpha crashes attempting to calculate this. assert(feqrel(betaIncompleteInv(0x1.ff1275ae5b939bcap-41, 4.6713e18, 0.0813601), 0x1.f97749d90c7adba8p-63L) >= real.mant_dig - 39); real a1 = 3.40483; assert(betaIncompleteInv(a1, 4.0640301659679627772e19L, 0.545113) == 0x1.ba8c08108aaf5d14p-109); real b1 = 2.82847e-25; assert(feqrel(betaIncompleteInv(0.01, b1, 9e-26), 0x1.549696104490aa9p-830L) >= real.mant_dig-10); // --- Problematic cases --- // This is a situation where the series expansion fails to converge assert( isNaN(betaIncompleteInv(0.12167, 4.0640301659679627772e19L, 0.0813601))); // This next result is almost certainly erroneous. // Mathematica states: "(cannot be determined by current methods)" assert(betaIncomplete(1.16251e20, 2.18e39, 5.45e-20) == -real.infinity); // WolframAlpha gives no result for this, though indicates that it approximately 1.0 - 1.3e-9 assert(1 - betaIncomplete(0.01, 328222, 4.0375e-5) == 0x1.5f62926b4p-30); } } private { // Implementation functions // Continued fraction expansion #1 for incomplete beta integral // Use when x < (a+1)/(a+b+2) real betaDistExpansion1(real a, real b, real x ) { real xk, pk, pkm1, pkm2, qk, qkm1, qkm2; real k1, k2, k3, k4, k5, k6, k7, k8; real r, t, ans; int n; k1 = a; k2 = a + b; k3 = a; k4 = a + 1.0L; k5 = 1.0L; k6 = b - 1.0L; k7 = k4; k8 = a + 2.0L; pkm2 = 0.0L; qkm2 = 1.0L; pkm1 = 1.0L; qkm1 = 1.0L; ans = 1.0L; r = 1.0L; n = 0; const real thresh = 3.0L * real.epsilon; do { xk = -( x * k1 * k2 )/( k3 * k4 ); pk = pkm1 + pkm2 * xk; qk = qkm1 + qkm2 * xk; pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; xk = ( x * k5 * k6 )/( k7 * k8 ); pk = pkm1 + pkm2 * xk; qk = qkm1 + qkm2 * xk; pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; if( qk != 0.0L ) r = pk/qk; if( r != 0.0L ) { t = fabs( (ans - r)/r ); ans = r; } else { t = 1.0L; } if( t < thresh ) return ans; k1 += 1.0L; k2 += 1.0L; k3 += 2.0L; k4 += 2.0L; k5 += 1.0L; k6 -= 1.0L; k7 += 2.0L; k8 += 2.0L; if( (fabs(qk) + fabs(pk)) > BETA_BIG ) { pkm2 *= BETA_BIGINV; pkm1 *= BETA_BIGINV; qkm2 *= BETA_BIGINV; qkm1 *= BETA_BIGINV; } if( (fabs(qk) < BETA_BIGINV) || (fabs(pk) < BETA_BIGINV) ) { pkm2 *= BETA_BIG; pkm1 *= BETA_BIG; qkm2 *= BETA_BIG; qkm1 *= BETA_BIG; } } while( ++n < 400 ); // loss of precision has occurred // mtherr( "incbetl", PLOSS ); return ans; } // Continued fraction expansion #2 for incomplete beta integral // Use when x > (a+1)/(a+b+2) real betaDistExpansion2(real a, real b, real x ) { real xk, pk, pkm1, pkm2, qk, qkm1, qkm2; real k1, k2, k3, k4, k5, k6, k7, k8; real r, t, ans, z; k1 = a; k2 = b - 1.0L; k3 = a; k4 = a + 1.0L; k5 = 1.0L; k6 = a + b; k7 = a + 1.0L; k8 = a + 2.0L; pkm2 = 0.0L; qkm2 = 1.0L; pkm1 = 1.0L; qkm1 = 1.0L; z = x / (1.0L-x); ans = 1.0L; r = 1.0L; int n = 0; const real thresh = 3.0L * real.epsilon; do { xk = -( z * k1 * k2 )/( k3 * k4 ); pk = pkm1 + pkm2 * xk; qk = qkm1 + qkm2 * xk; pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; xk = ( z * k5 * k6 )/( k7 * k8 ); pk = pkm1 + pkm2 * xk; qk = qkm1 + qkm2 * xk; pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; if( qk != 0.0L ) r = pk/qk; if( r != 0.0L ) { t = fabs( (ans - r)/r ); ans = r; } else t = 1.0L; if( t < thresh ) return ans; k1 += 1.0L; k2 -= 1.0L; k3 += 2.0L; k4 += 2.0L; k5 += 1.0L; k6 += 1.0L; k7 += 2.0L; k8 += 2.0L; if( (fabs(qk) + fabs(pk)) > BETA_BIG ) { pkm2 *= BETA_BIGINV; pkm1 *= BETA_BIGINV; qkm2 *= BETA_BIGINV; qkm1 *= BETA_BIGINV; } if( (fabs(qk) < BETA_BIGINV) || (fabs(pk) < BETA_BIGINV) ) { pkm2 *= BETA_BIG; pkm1 *= BETA_BIG; qkm2 *= BETA_BIG; qkm1 *= BETA_BIG; } } while( ++n < 400 ); // loss of precision has occurred //mtherr( "incbetl", PLOSS ); return ans; } /* Power series for incomplete gamma integral. Use when b*x is small. */ real betaDistPowerSeries(real a, real b, real x ) { real ai = 1.0L / a; real u = (1.0L - b) * x; real v = u / (a + 1.0L); real t1 = v; real t = u; real n = 2.0L; real s = 0.0L; real z = real.epsilon * ai; while( fabs(v) > z ) { u = (n - b) * x / n; t *= u; v = t / (a + n); s += v; n += 1.0L; } s += t1; s += ai; u = a * log(x); if ( (a+b) < MAXGAMMA && fabs(u) < MAXLOG ) { t = gamma(a+b)/(gamma(a)*gamma(b)); s = s * t * pow(x,a); } else { t = logGamma(a+b) - logGamma(a) - logGamma(b) + u + log(s); if( t < MINLOG ) { s = 0.0L; } else s = exp(t); } return s; } } /*************************************** * Incomplete gamma integral and its complement * * These functions are defined by * * gammaIncomplete = ( $(INTEGRATE 0, x) $(POWER e, -t) $(POWER t, a-1) dt )/ $(GAMMA)(a) * * gammaIncompleteCompl(a,x) = 1 - gammaIncomplete(a,x) * = ($(INTEGRATE x, ∞) $(POWER e, -t) $(POWER t, a-1) dt )/ $(GAMMA)(a) * * In this implementation both arguments must be positive. * The integral is evaluated by either a power series or * continued fraction expansion, depending on the relative * values of a and x. */ real gammaIncomplete(real a, real x ) in { assert(x >= 0); assert(a > 0); } body { /* left tail of incomplete gamma function: * * inf. k * a -x - x * x e > ---------- * - - * k=0 | (a+k+1) * */ if (x==0) return 0.0L; if ( (x > 1.0L) && (x > a ) ) return 1.0L - gammaIncompleteCompl(a,x); real ax = a * log(x) - x - logGamma(a); /+ if( ax < MINLOGL ) return 0; // underflow // { mtherr( "igaml", UNDERFLOW ); return( 0.0L ); } +/ ax = exp(ax); /* power series */ real r = a; real c = 1.0L; real ans = 1.0L; do { r += 1.0L; c *= x/r; ans += c; } while( c/ans > real.epsilon ); return ans * ax/a; } /** ditto */ real gammaIncompleteCompl(real a, real x ) in { assert(x >= 0); assert(a > 0); } body { if (x==0) return 1.0L; if ( (x < 1.0L) || (x < a) ) return 1.0L - gammaIncomplete(a,x); // DAC (Cephes bug fix): This is necessary to avoid // spurious nans, eg // log(x)-x = NaN when x = real.infinity const real MAXLOGL = 1.1356523406294143949492E4L; if (x > MAXLOGL) return igammaTemmeLarge(a, x); real ax = a * log(x) - x - logGamma(a); //const real MINLOGL = -1.1355137111933024058873E4L; // if ( ax < MINLOGL ) return 0; // underflow; ax = exp(ax); /* continued fraction */ real y = 1.0L - a; real z = x + y + 1.0L; real c = 0.0L; real pk, qk, t; real pkm2 = 1.0L; real qkm2 = x; real pkm1 = x + 1.0L; real qkm1 = z * x; real ans = pkm1/qkm1; do { c += 1.0L; y += 1.0L; z += 2.0L; real yc = y * c; pk = pkm1 * z - pkm2 * yc; qk = qkm1 * z - qkm2 * yc; if( qk != 0.0L ) { real r = pk/qk; t = fabs( (ans - r)/r ); ans = r; } else { t = 1.0L; } pkm2 = pkm1; pkm1 = pk; qkm2 = qkm1; qkm1 = qk; const real BIG = 9.223372036854775808e18L; if ( fabs(pk) > BIG ) { pkm2 /= BIG; pkm1 /= BIG; qkm2 /= BIG; qkm1 /= BIG; } } while ( t > real.epsilon ); return ans * ax; } /** Inverse of complemented incomplete gamma integral * * Given a and p, the function finds x such that * * gammaIncompleteCompl( a, x ) = p. * * Starting with the approximate value x = a $(POWER t, 3), where * t = 1 - d - normalDistributionInv(p) sqrt(d), * and d = 1/9a, * the routine performs up to 10 Newton iterations to find the * root of incompleteGammaCompl(a,x) - p = 0. */ real gammaIncompleteComplInv(real a, real p) in { assert(p>=0 && p<= 1); assert(a>0); } body { if (p==0) return real.infinity; real y0 = p; const real MAXLOGL = 1.1356523406294143949492E4L; real x0, x1, x, yl, yh, y, d, lgm, dithresh; int i, dir; /* bound the solution */ x0 = real.max; yl = 0.0L; x1 = 0.0L; yh = 1.0L; dithresh = 4.0 * real.epsilon; /* approximation to inverse function */ d = 1.0L/(9.0L*a); y = 1.0L - d - normalDistributionInvImpl(y0) * sqrt(d); x = a * y * y * y; lgm = logGamma(a); for( i=0; i<10; i++ ) { if( x > x0 || x < x1 ) goto ihalve; y = gammaIncompleteCompl(a,x); if ( y < yl || y > yh ) goto ihalve; if ( y < y0 ) { x0 = x; yl = y; } else { x1 = x; yh = y; } /* compute the derivative of the function at this point */ d = (a - 1.0L) * log(x0) - x0 - lgm; if ( d < -MAXLOGL ) goto ihalve; d = -exp(d); /* compute the step to the next approximation of x */ d = (y - y0)/d; x = x - d; if ( i < 3 ) continue; if ( fabs(d/x) < dithresh ) return x; } /* Resort to interval halving if Newton iteration did not converge. */ ihalve: d = 0.0625L; if ( x0 == real.max ) { if( x <= 0.0L ) x = 1.0L; while( x0 == real.max ) { x = (1.0L + d) * x; y = gammaIncompleteCompl( a, x ); if ( y < y0 ) { x0 = x; yl = y; break; } d = d + d; } } d = 0.5L; dir = 0; for( i=0; i<400; i++ ) { x = x1 + d * (x0 - x1); y = gammaIncompleteCompl( a, x ); lgm = (x0 - x1)/(x1 + x0); if ( fabs(lgm) < dithresh ) break; lgm = (y - y0)/y0; if ( fabs(lgm) < dithresh ) break; if ( x <= 0.0L ) break; if ( y > y0 ) { x1 = x; yh = y; if ( dir < 0 ) { dir = 0; d = 0.5L; } else if ( dir > 1 ) d = 0.5L * d + 0.5L; else d = (y0 - yl)/(yh - yl); dir += 1; } else { x0 = x; yl = y; if ( dir > 0 ) { dir = 0; d = 0.5L; } else if ( dir < -1 ) d = 0.5L * d; else d = (y0 - yl)/(yh - yl); dir -= 1; } } /+ if( x == 0.0L ) mtherr( "igamil", UNDERFLOW ); +/ return x; } unittest { //Values from Excel's GammaInv(1-p, x, 1) assert(fabs(gammaIncompleteComplInv(1, 0.5) - 0.693147188044814) < 0.00000005); assert(fabs(gammaIncompleteComplInv(12, 0.99) - 5.42818075054289) < 0.00000005); assert(fabs(gammaIncompleteComplInv(100, 0.8) - 91.5013985848288L) < 0.000005); assert(gammaIncomplete(1, 0)==0); assert(gammaIncompleteCompl(1, 0)==1); assert(gammaIncomplete(4545, real.infinity)==1); // Values from Excel's (1-GammaDist(x, alpha, 1, TRUE)) assert(fabs(1.0L-gammaIncompleteCompl(0.5, 2) - 0.954499729507309L) < 0.00000005); assert(fabs(gammaIncomplete(0.5, 2) - 0.954499729507309L) < 0.00000005); // Fixed Cephes bug: assert(gammaIncompleteCompl(384, real.infinity)==0); assert(gammaIncompleteComplInv(3, 0)==real.infinity); // Fixed a bug that caused gammaIncompleteCompl to return a wrong value when // x was larger than a, but not by much, and both were large: // The value is from WolframAlpha (Gamma[100000, 100001, inf] / Gamma[100000]) static if (real.mant_dig >= 64) // incl. 80-bit reals assert(fabs(gammaIncompleteCompl(100000, 100001) - 0.49831792109) < 0.000000000005); else assert(fabs(gammaIncompleteCompl(100000, 100001) - 0.49831792109) < 0.00000005); } // DAC: These values are Bn / n for n=2,4,6,8,10,12,14. immutable real [7] Bn_n = [ 1.0L/(6*2), -1.0L/(30*4), 1.0L/(42*6), -1.0L/(30*8), 5.0L/(66*10), -691.0L/(2730*12), 7.0L/(6*14) ]; /** Digamma function * * The digamma function is the logarithmic derivative of the gamma function. * * digamma(x) = d/dx logGamma(x) * * References: * 1. Abramowitz, M., and Stegun, I. A. (1970). * Handbook of mathematical functions. Dover, New York, * pages 258-259, equations 6.3.6 and 6.3.18. */ real digamma(real x) { // Based on CEPHES, Stephen L. Moshier. real p, q, nz, s, w, y, z; long i, n; int negative; negative = 0; nz = 0.0; if ( x <= 0.0 ) { negative = 1; q = x; p = floor(q); if( p == q ) { return real.nan; // singularity. } /* Remove the zeros of tan(PI x) * by subtracting the nearest integer from x */ nz = q - p; if ( nz != 0.5 ) { if ( nz > 0.5 ) { p += 1.0; nz = q - p; } nz = PI/tan(PI*nz); } else { nz = 0.0; } x = 1.0 - x; } // check for small positive integer if ((x <= 13.0) && (x == floor(x)) ) { y = 0.0; n = lrint(x); // DAC: CEPHES bugfix. Cephes did this in reverse order, which // created a larger roundoff error. for (i=n-1; i>0; --i) { y+=1.0L/i; } y -= EULERGAMMA; goto done; } s = x; w = 0.0; while ( s < 10.0 ) { w += 1.0/s; s += 1.0; } if ( s < 1.0e17 ) { z = 1.0/(s * s); y = z * poly(z, Bn_n); } else y = 0.0; y = log(s) - 0.5L/s - y - w; done: if ( negative ) { y -= nz; } return y; } unittest { // Exact values assert(digamma(1.0)== -EULERGAMMA); assert(feqrel(digamma(0.25), -PI/2 - 3* LN2 - EULERGAMMA) >= real.mant_dig-7); assert(feqrel(digamma(1.0L/6), -PI/2 *sqrt(3.0L) - 2* LN2 -1.5*log(3.0L) - EULERGAMMA) >= real.mant_dig-7); assert(digamma(-5.0).isNaN()); assert(feqrel(digamma(2.5), -EULERGAMMA - 2*LN2 + 2.0 + 2.0L/3) >= real.mant_dig-9); assert(isIdentical(digamma(NaN(0xABC)), NaN(0xABC))); for (int k=1; k<40; ++k) { real y=0; for (int u=k; u>=1; --u) { y += 1.0L/u; } assert(feqrel(digamma(k+1.0), -EULERGAMMA + y) >= real.mant_dig-2); } } /** Log Minus Digamma function * * logmdigamma(x) = log(x) - digamma(x) * * References: * 1. Abramowitz, M., and Stegun, I. A. (1970). * Handbook of mathematical functions. Dover, New York, * pages 258-259, equations 6.3.6 and 6.3.18. */ real logmdigamma(real x) { if (x <= 0.0) { if (x == 0.0) { return real.infinity; } return real.nan; } real s = x; real w = 0.0; while ( s < 10.0 ) { w += 1.0/s; s += 1.0; } real y; if ( s < 1.0e17 ) { immutable real z = 1.0/(s * s); y = z * poly(z, Bn_n); } else y = 0.0; return x == s ? y + 0.5L/s : (log(x/s) + 0.5L/s + y + w); } unittest { assert(logmdigamma(-5.0).isNaN()); assert(isIdentical(logmdigamma(NaN(0xABC)), NaN(0xABC))); assert(logmdigamma(0.0) == real.infinity); for(auto x = 0.01; x < 1.0; x += 0.1) assert(approxEqual(digamma(x), log(x) - logmdigamma(x))); for(auto x = 1.0; x < 15.0; x += 1.0) assert(approxEqual(digamma(x), log(x) - logmdigamma(x))); } /** Inverse of the Log Minus Digamma function * * Returns x such $(D log(x) - digamma(x) == y). * * References: * 1. Abramowitz, M., and Stegun, I. A. (1970). * Handbook of mathematical functions. Dover, New York, * pages 258-259, equation 6.3.18. * * Authors: Ilya Yaroshenko */ real logmdigammaInverse(real y) { import std.numeric: findRoot; // FIXME: should be returned back to enum. // Fix requires CTFEable `log` on non-x86 targets (check both LDC and GDC). immutable maxY = logmdigamma(real.min_normal); assert(maxY > 0 && maxY <= real.max); if (y >= maxY) { //lim x->0 (log(x)-digamma(x))*x == 1 return 1 / y; } if (y < 0) { return real.nan; } if (y < real.min_normal) { //6.3.18 return 0.5 / y; } if (y > 0) { // x/2 <= logmdigamma(1 / x) <= x, x > 0 // calls logmdigamma ~6 times return 1 / findRoot((real x) => logmdigamma(1 / x) - y, y, 2*y); } return y; //NaN } unittest { import std.typecons; //WolframAlpha, 22.02.2015 immutable Tuple!(real, real)[5] testData = [ tuple(1.0L, 0.615556766479594378978099158335549201923L), tuple(1.0L/8, 4.15937801516894947161054974029150730555L), tuple(1.0L/1024, 512.166612384991507850643277924243523243L), tuple(0.000500083333325000003968249801594877323784632117L, 1000.0L), tuple(1017.644138623741168814449776695062817947092468536L, 1.0L/1024), ]; foreach (test; testData) assert(approxEqual(logmdigammaInverse(test[0]), test[1], 2e-15, 0)); assert(approxEqual(logmdigamma(logmdigammaInverse(1)), 1, 1e-15, 0)); assert(approxEqual(logmdigamma(logmdigammaInverse(real.min_normal)), real.min_normal, 1e-15, 0)); assert(approxEqual(logmdigamma(logmdigammaInverse(real.max/2)), real.max/2, 1e-15, 0)); assert(approxEqual(logmdigammaInverse(logmdigamma(1)), 1, 1e-15, 0)); assert(approxEqual(logmdigammaInverse(logmdigamma(real.min_normal)), real.min_normal, 1e-15, 0)); assert(approxEqual(logmdigammaInverse(logmdigamma(real.max/2)), real.max/2, 1e-15, 0)); } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/math/biguintarm.d0000664000175000017500000010320312776215007022760 0ustar kaikai/** Optimised asm arbitrary precision arithmetic ('bignum') * routines for ARM processors. * * All functions operate on arrays of uints, stored LSB first. * If there is a destination array, it will be the first parameter. * Currently, all of these functions are subject to change, and are * intended for internal use only. */ /* Copyright Kai Nacke 2016. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ /** * Like the generic module biguintnoasm, some functions assume * non-empty arrays. */ module std.internal.math.biguintarm; version(LDC): version(ARM): import ldc.llvmasm; static import stdnoasm = std.internal.math.biguintnoasm; @system: public: alias BigDigit = stdnoasm.BigDigit; // A Bignum is an array of BigDigits. // Limits for when to switch between multiplication algorithms. enum : int { KARATSUBALIMIT = 10 }; // Minimum value for which Karatsuba is worthwhile. enum : int { KARATSUBASQUARELIMIT=12 }; // Minimum value for which square Karatsuba is worthwhile /** Multi-byte addition or subtraction * dest[] = src1[] + src2[] + carry (0 or 1). * or dest[] = src1[] - src2[] - carry (0 or 1). * Returns carry or borrow (0 or 1). * Set op == '+' for addition, '-' for subtraction. */ uint multibyteAddSub(char op)(uint[] dest, const(uint) [] src1, const (uint) [] src2, uint carry) pure @nogc nothrow { assert(carry == 0 || carry == 1); assert(src1.length >= dest.length && src2.length >= dest.length); static if (op == '+') { enum opcs = "adcs"; // Use "addition with carry" enum foc = "@"; // Use comment } else { enum opcs = "sbcs"; // Use "subtraction with carry" enum foc = "eor"; // Use "exclusive or" } return __asm!uint(` cmp $2,#0 @ Check dest.length beq 1f `~foc~` $0,$0,#1 @ Flip carry or comment mov r5,#0 @ Initialize index 2: ldr r6,[${3:m},r5,LSL #2] @ Load *(src1.ptr + index) ldr r7,[${4:m},r5,LSL #2] @ Load *(src2.ptr + index) lsrs $0,$0,#1 @ Set carry `~opcs~` r6,r6,r7 @ Add/Sub with carry str r6,[${1:m},r5,LSL #2] @ Store *(dest.ptr + index) adc $0,$0,#0 @ Store carry add r5,r5,#1 @ Increment index cmp $2,r5 bhi 2b `~foc~` $0,$0,#1 @ Flip carry or comment 1:`, "=&r,=*m,r,*m,*m,0,~{r5},~{r6},~{r7},~{cpsr}", dest.ptr, dest.length, src1.ptr, src2.ptr, carry); } unittest { // Some simple checks to validate the interface uint carry; uint [] a = new uint[40]; uint [] b = new uint[40]; uint [] c = new uint[40]; // Add a[0] = 0xFFFFFFFE; b[0] = 0x00000001; c[1] = 0xDEADBEEF; carry = multibyteAddSub!('+')(c[0..1], a[0..1], b[0..1], 0); assert(c[0] == 0xFFFFFFFF); assert(carry == 0); a[0] = 0xFFFFFFFE; b[0] = 0x00000000; carry = multibyteAddSub!('+')(c[0..1], a[0..1], b[0..1], 1); assert(c[0] == 0xFFFFFFFF); assert(carry == 0); a[0] = 0xFFFFFFFF; b[0] = 0x00000001; carry = multibyteAddSub!('+')(c[0..1], a[0..1], b[0..1], 0); assert(c[0] == 0x00000000); assert(carry == 1); a[0] = 0xFFFFFFFF; b[0] = 0x00000000; carry = multibyteAddSub!('+')(c[0..1], a[0..1], b[0..1], 1); assert(c[0] == 0x00000000); assert(carry == 1); a[0] = 0xFFFFFFFF; a[1] = 0x00000000; b[0] = 0x00000001; b[1] = 0x00000000; c[0] = 0xDEADBEEF; c[1] = 0xDEADBEEF; c[2] = 0xDEADBEEF; carry = multibyteAddSub!('+')(c[0..2], a[0..2], b[0..2], 0); assert(c[0] == 0x00000000); assert(c[1] == 0x00000001); assert(c[2] == 0xDEADBEEF); assert(carry == 0); a[0] = 0xFFFF0000; b[0] = 0x0001FFFF; for (size_t i = 1; i < 9; i++) { a[i] = 0x0000FFFF; b[i] = 0xFFFF0000; c[i] = 0xDEADBEEF; } a[9] = 0x00000000; b[9] = 0x00000000; c[9] = 0xDEADBEEF; c[10] = 0xDEADBEEF; carry = multibyteAddSub!('+')(c[0..10], a[0..10], b[0..10], 0); assert(c[0] == 0x0000FFFF); for (size_t i = 1; i < 9; i++) assert(c[i] == 0x00000000); assert(c[9] == 0x00000001); assert(c[10] == 0xDEADBEEF); assert(carry == 0); // Sub a[0] = 0xFFFFFFFF; b[0] = 0x00000000; c[1] = 0xDEADBEEF; carry = multibyteAddSub!('-')(c[0..1], a[0..1], b[0..1], 1); assert(c[0] == 0xFFFFFFFE); assert(c[1] == 0xDEADBEEF); assert(carry == 0); a[0] = 0xFFFFFFFF; b[0] = 0x00000001; c[1] = 0xDEADBEEF; carry = multibyteAddSub!('-')(c[0..1], a[0..1], b[0..1], 1); assert(c[0] == 0xFFFFFFFD); assert(c[1] == 0xDEADBEEF); assert(carry == 0); a[0] = 0xC0000000; a[1] = 0x7000BEEF; b[0] = 0x80000000; b[1] = 0x3000BABE; c[0] = 0x40000000; c[1] = 0x40000431; carry = multibyteAddSub!('-')(c[0..2], a[0..2], b[0..2], 0); assert(c[0] == 0x40000000); assert(c[1] == 0x40000431); assert(carry == 0); } unittest { uint [] a = new uint[40]; uint [] b = new uint[40]; uint [] c = new uint[40]; for (size_t i = 0; i < a.length; ++i) { if (i&1) a[i]=cast(uint)(0x8000_0000 + i); else a[i]=cast(uint)i; b[i]= 0x8000_0003; } c[19]=0x3333_3333; uint carry = multibyteAddSub!('+')(c[0..18], b[0..18], a[0..18], 0); assert(c[0]==0x8000_0003); assert(c[1]==4); assert(c[19]==0x3333_3333); // check for overrun assert(carry==1); for (size_t i = 0; i < a.length; ++i) { a[i] = b[i] = c[i] = 0; } a[8]=0x048D159E; b[8]=0x048D159E; a[10]=0x1D950C84; b[10]=0x1D950C84; a[5] =0x44444444; carry = multibyteAddSub!('-')(a[0..12], a[0..12], b[0..12], 0); assert(a[11] == 0); for (size_t i = 0; i < 10; ++i) if (i != 5) assert(a[i] == 0); for (size_t q = 3; q < 36; ++q) { for (size_t i = 0; i< a.length; ++i) { a[i] = b[i] = c[i] = 0; } a[q-2]=0x040000; b[q-2]=0x040000; carry = multibyteAddSub!('-')(a[0..q], a[0..q], b[0..q], 0); assert(a[q-2]==0); } } /** dest[] += carry, or dest[] -= carry. * op must be '+' or '-' * Returns final carry or borrow (0 or 1) */ uint multibyteIncrementAssign(char op)(uint[] dest, uint carry) pure @nogc nothrow { static if (op == '+') { enum ops = "adds"; enum bcc = "bcc"; } else { enum ops = "subs"; enum bcc = "bcs"; } return __asm!uint(` cmp $2,0 @ Check dest.length beq 1f ldr r6,$1 @ Load *(dest) `~ops~` r6,r6,$0 @ Add/Sub str r6,$1 @ Store *(dest + index) mov $0,#0 @ Assume result "carry 0" `~bcc~` 1f cmp $2,#1 beq 2f mov r5,#1 @ Initialize index 3: ldr r6,[${1:m},r5,LSL #2] @ Load *(dest + index) `~ops~` r6,r6,#1 @ Add/Sub str r6,[${1:m},r5,LSL #2] @ Store *(dest + index) `~bcc~` 1f add r5,r5,#1 @ Increment index cmp $2,r5 bhi 3b 2: mov $0,#1 @ Result "carry 1" 1:`, "=&r,=*m,r,0,~{r5},~{r6},~{cpsr}", dest.ptr, dest.length, carry); } unittest { // Some simple checks to validate the interface uint carry; uint [] a = new uint[40]; // Add a[0] = 0xFFFFFFFE; a[1] = 0xDEADBEEF; carry = multibyteIncrementAssign!('+')(a[0..1], 1); assert(a[0] == 0xFFFFFFFF); assert(a[1] == 0xDEADBEEF); assert(carry == 0); a[0] = 0xFFFFFFFF; a[1] = 0xDEADBEEF; carry = multibyteIncrementAssign!('+')(a[0..1], 0); assert(a[0] == 0xFFFFFFFF); assert(a[1] == 0xDEADBEEF); assert(carry == 0); a[0] = 0xFFFFFFFF; a[1] = 0xDEADBEEF; carry = multibyteIncrementAssign!('+')(a[0..1], 1); assert(a[0] == 0x00000000); assert(a[1] == 0xDEADBEEF); assert(carry == 1); a[0] = 0xFFFFFFFF; a[1] = 0x0000FFFF; a[2] = 0xDEADBEEF; carry = multibyteIncrementAssign!('+')(a[0..2], 1); assert(a[0] == 0x00000000); assert(a[1] == 0x00010000); assert(a[2] == 0xDEADBEEF); assert(carry == 0); a[0] = 0xFFFFFFFF; a[1] = 0xFFFFFFFF; a[2] = 0x0000FFFF; a[3] = 0xDEADBEEF; carry = multibyteIncrementAssign!('+')(a[0..3], 1); assert(a[0] == 0x00000000); assert(a[1] == 0x00000000); assert(a[2] == 0x00010000); assert(a[3] == 0xDEADBEEF); assert(carry == 0); a[0] = 0xFFFFFFFF; a[1] = 0xFFFFFFFF; a[2] = 0xFFFFFFFF; a[3] = 0xDEADBEEF; carry = multibyteIncrementAssign!('+')(a[0..3], 1); assert(a[0] == 0x00000000); assert(a[1] == 0x00000000); assert(a[2] == 0x00000000); assert(a[3] == 0xDEADBEEF); assert(carry == 1); // Sub a[0] = 0xFFFFFFFF; a[1] = 0xDEADBEEF; carry = multibyteIncrementAssign!('-')(a[0..1], 1); assert(a[0] == 0xFFFFFFFE); assert(a[1] == 0xDEADBEEF); assert(carry == 0); a[0] = 0xFFFFFFFF; a[1] = 0xDEADBEEF; carry = multibyteIncrementAssign!('-')(a[0..1], 0); assert(a[0] == 0xFFFFFFFF); assert(a[1] == 0xDEADBEEF); assert(carry == 0); a[0] = 0x00000000; a[1] = 0xDEADBEEF; carry = multibyteIncrementAssign!('-')(a[0..1], 1); assert(a[0] == 0xFFFFFFFF); assert(a[1] == 0xDEADBEEF); assert(carry == 1); a[0] = 0x00000000; a[1] = 0x00000000; a[2] = 0xDEADBEEF; carry = multibyteIncrementAssign!('-')(a[0..2], 1); assert(a[0] == 0xFFFFFFFF); assert(a[1] == 0xFFFFFFFF); assert(a[2] == 0xDEADBEEF); assert(carry == 1); a[0] = 0x00000000; a[1] = 0x00000000; a[2] = 0x00000000; a[3] = 0xDEADBEEF; carry = multibyteIncrementAssign!('-')(a[0..3], 1); assert(a[0] == 0xFFFFFFFF); assert(a[1] == 0xFFFFFFFF); assert(a[2] == 0xFFFFFFFF); assert(a[3] == 0xDEADBEEF); assert(carry == 1); a[0] = 0x00000000; a[1] = 0x00000000; a[2] = 0x00000010; a[3] = 0xDEADBEEF; carry = multibyteIncrementAssign!('-')(a[0..3], 1); assert(a[0] == 0xFFFFFFFF); assert(a[1] == 0xFFFFFFFF); assert(a[2] == 0x0000000F); assert(a[3] == 0xDEADBEEF); assert(carry == 0); } /** dest[] = src[] << numbits * numbits must be in the range 1..31 */ uint multibyteShl(uint [] dest, const(uint) [] src, uint numbits) pure @nogc nothrow { assert(dest.length > 0 && src.length >= dest.length); assert(numbits >= 1 && numbits <= 31); return __asm!uint(` mov $0,#0 @ result = 0 mov r5,#0 @ Initialize index 1: ldr r6,[${3:m},r5,LSL #2] @ Load *(src + index) lsl r7,r6,$4 add r7,r7,$0 str r7,[${1:m},r5,LSL #2] @ Store *(dest + index) lsr $0,r6,$5 add r5,r5,#1 cmp $2,r5 bhi 1b`, "=&r,=*m,r,*m,r,r,~{r5},~{r6},~{r7},~{cpsr}", dest.ptr, dest.length, src.ptr, numbits, 32-numbits); } /** dest[] = src[] >> numbits * numbits must be in the range 1..31 */ void multibyteShr(uint [] dest, const(uint) [] src, uint numbits) pure @nogc nothrow { assert(dest.length > 0 && src.length >= dest.length); assert(numbits >= 1 && numbits <= 31); __asm(` mov r0,#0 @ result = 0 mov r5,$1 @ Initialize index 1: sub r5,#1 ldr r6,[${2:m},r5,LSL #2] @ Load *(src + index) lsr r7,r6,$3 add r7,r7,r0 str r7,[${0:m},r5,LSL #2] @ Store *(dest + index) lsl r0,r6,$4 cmp $1,r5 bhi 1b`, "=*m,r,*m,r,r,~{r0},~{r5},~{r6},~{r7},~{cpsr}", dest.ptr, dest.length, src.ptr, numbits, 32-numbits); } unittest { uint [] aa = [0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteShr(aa[0..$-2], aa, 4); assert(aa[0] == 0x6122_2222 && aa[1] == 0xA455_5555 && aa[2] == 0x0899_9999); assert(aa[3] == 0xBCCC_CCCD); aa = [0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteShr(aa[0..$-1], aa, 4); assert(aa[0] == 0x6122_2222 && aa[1] == 0xA455_5555 && aa[2] == 0xD899_9999 && aa[3] == 0x0BCC_CCCC); aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteShl(aa[1..4], aa[1..$], 4); assert(aa[0] == 0xF0FF_FFFF && aa[1] == 0x2222_2230 && aa[2]==0x5555_5561 && aa[3]==0x9999_99A4 && aa[4]==0x0BCCC_CCCD); } /** dest[] = src[] * multiplier + carry. * Returns carry. */ uint multibyteMul(uint[] dest, const(uint)[] src, uint multiplier, uint carry) pure @nogc nothrow { assert(src.length >= dest.length); return __asm!uint(` cmp $2,#0 @ Check dest.length beq 1f mov r5,#0 @ Initialize index movs r8,$2,LSR #1 @ Loop unrolled 2 times beq 2f lsl r8,#1 3: mov r7,#0 @ Clear high word ldr r6,[${3:m},r5,LSL #2] @ Load *(src + index) umlal $0,r7,r6,$4 @ r6 * $4 + r7:$0 str $0,[${1:m},r5,LSL #2] @ Store *(dest + index) add r5,r5,#1 mov $0,#0 @ Clear high word ldr r6,[${3:m},r5,LSL #2] @ Load *(src + index) umlal r7,$0,r6,$4 @ r6 * $4 + $0:r7 str r7,[${1:m},r5,LSL #2] @ Store *(dest + index) add r5,r5,#1 cmp r8,r5 bhi 3b cmp $2,r5 beq 1f 2: mov r7,#0 @ Clear high word ldr r6,[${3:m},r5,LSL #2] @ Load *(src + index) umlal $0,r7,r6,$4 @ r6 * $4 + r7:$0 str $0,[${1:m},r5,LSL #2] @ Store *(dest + index) mov $0,r7 @ Move high word to low word @add r5,r5,#1 @cmp $2,r5 @bhi 2b 1:`, "=&r,=*m,r,*m,r,0,~{r5},~{r6},~{r7},~{r8},~{cpsr}", dest.ptr, dest.length, src.ptr, multiplier, carry); } unittest { uint [] aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; multibyteMul(aa[1..4], aa[1..4], 16, 0); assert(aa[0] == 0xF0FF_FFFF && aa[1] == 0x2222_2230 && aa[2]==0x5555_5561 && aa[3]==0x9999_99A4 && aa[4]==0x0BCCC_CCCD); } /** * dest[] += src[] * multiplier + carry(0..FFFF_FFFF). * Returns carry out of MSB (0..FFFF_FFFF). */ uint multibyteMulAdd(char op)(uint [] dest, const(uint)[] src, uint multiplier, uint carry) pure @nogc nothrow { assert(dest.length > 0 && dest.length == src.length); static if (op == '+') { enum adds = "adds"; enum adc = "adc"; enum com = "@"; } else { enum adds = "rsbs"; enum adc = "rsc"; enum com = ""; } return __asm!uint(` mov r5,#0 @ Initialize index 1: mov r8,#0 @ High word of carry r8:$0 ldr r6,[${3:m},r5,LSL #2] @ Load *(src + index) ldr r7,[${1:m},r5,LSL #2] @ Load *(dest + index) umlal $0,r8,r6,$4 @ r6 * $4 + r8:$0 `~adds~` $0,$0,r7 str $0,[${1:m},r5,LSL #2] @ Store *(dest + index) `~adc~` $0,r8,#0 `~com~` rsb $0,$0,#0 @ FIXME: Fold negate into rsc add r5,r5,#1 cmp $2,r5 bhi 1b`, "=r,=*m,r,*m,r,0,~{r5},~{r6},~{r7},~{r8},~{cpsr}", dest.ptr, dest.length, src.ptr, multiplier, carry); } unittest { uint [] aa = [0xF0FF_FFFF, 0x1222_2223, 0x4555_5556, 0x8999_999A, 0xBCCC_CCCD, 0xEEEE_EEEE]; uint [] bb = [0x1234_1234, 0xF0F0_F0F0, 0x00C0_C0C0, 0xF0F0_F0F0, 0xC0C0_C0C0]; multibyteMulAdd!('+')(bb[1..$-1], aa[1..$-2], 16, 5); assert(bb[0] == 0x1234_1234 && bb[4] == 0xC0C0_C0C0); assert(bb[1] == 0x2222_2230 + 0xF0F0_F0F0 + 5 && bb[2] == 0x5555_5561 + 0x00C0_C0C0 + 1 && bb[3] == 0x9999_99A4 + 0xF0F0_F0F0 ); multibyteMulAdd!('-')(bb[1..$-1], aa[1..$-2], 16, 5); assert(bb[0] == 0x1234_1234 && bb[1] == 0xF0F0_F0F0); assert(bb[2] == 0x00C0_C0C0 && bb[3] == 0xF0F0_F0F0); assert(bb[4] == 0xC0C0_C0C0); } /** Sets result = result[0..left.length] + left * right It is defined in this way to allow cache-efficient multiplication. This function is equivalent to: ---- for (size_t i = 0; i< right.length; ++i) { dest[left.length + i] = multibyteMulAdd(dest[i..left.length+i], left, right[i], 0); } ---- */ void multibyteMultiplyAccumulate(uint [] dest, const(uint)[] left, const(uint) [] right) pure @nogc nothrow { for (size_t i = 0; i < right.length; ++i) { dest[left.length + i] = multibyteMulAdd!('+')(dest[i..left.length+i], left, right[i], 0); } } /** dest[] /= divisor. * overflow is the initial remainder, and must be in the range 0..divisor-1. */ uint multibyteDivAssign(uint [] dest, uint divisor, uint overflow) pure @nogc nothrow { ulong c = cast(ulong)overflow; for(ptrdiff_t i = dest.length-1; i>= 0; --i) { c = (c<<32) + cast(ulong)(dest[i]); uint q = cast(uint)(c/divisor); c -= divisor * q; dest[i] = q; } return cast(uint)c; } unittest { uint [] aa = new uint[101]; for (uint i = 0; i < aa.length; ++i) aa[i] = 0x8765_4321 * (i+3); uint overflow = multibyteMul(aa, aa, 0x8EFD_FCFB, 0x33FF_7461); uint r = multibyteDivAssign(aa, 0x8EFD_FCFB, overflow); for (uint i=0; i= 2*src.length); __asm(` cmp $2,0 @ Check src.length beq 1f mov r5,#0 @ Initialize index 1 mov r6,${0:m} @ Initialize dest mov r3,#0 @ Initialize carry lo mov r4,#0 @ Initialize carry hi 2: ldr r7,[${1:m},r5,LSL #2] @ Load *(src + index) ldr r8,[r6] @ Load *(dest + 2*index) umlal r3,r4,r7,r7 @ r7 * r7 + r4:r3 adds r3,r8 str r3,[r6],#4 @ Store *(dest + 2*index) ldr r8,[r6] @ Load *(dest + 2*index +1) adcs r3,r4,r8 str r3,[r6],#4 @ Store *(dest + 2*index + 1) mov r4,#0 @ Initialize carry hi adc r3,r4,#0 @ Initialize carry lo add r5,r5,#1 cmp $2,r5 bhi 2b 1:`, "=*m,*m,r,~{r3},~{r4},~{r5},~{r6},~{r7},~{r8},~{cpsr}", dest.ptr, src.ptr, src.length); } // Does half a square multiply. (square = diagonal + 2*triangle) void multibyteTriangleAccumulate(uint[] dest, const(uint)[] x) pure @nogc nothrow { assert(dest.length >= 2*x.length && x.length > 0); // x[0]*x[1...$] + x[1]*x[2..$] + ... + x[$-2]x[$-1..$] dest[x.length] = multibyteMul(dest[1 .. x.length], x[1..$], x[0], 0); if (x.length < 4) { if (x.length == 3) { ulong c = cast(ulong)(x[$-1]) * x[$-2] + dest[2*x.length-3]; dest[2*x.length - 3] = cast(uint)c; c >>= 32; dest[2*x.length - 2] = cast(uint)c; } return; } for (size_t i = 2; i < x.length - 2; ++i) { dest[i-1+ x.length] = multibyteMulAdd!('+')( dest[i+i-1 .. i+x.length-1], x[i..$], x[i-1], 0); } // Unroll the last two entries, to reduce loop overhead: ulong c = cast(ulong)(x[$-3]) * x[$-2] + dest[2*x.length-5]; dest[2*x.length-5] = cast(uint)c; c >>= 32; c += cast(ulong)(x[$-3]) * x[$-1] + dest[2*x.length-4]; dest[2*x.length-4] = cast(uint)c; c >>= 32; c += cast(ulong)(x[$-1]) * x[$-2]; dest[2*x.length-3] = cast(uint)c; c >>= 32; dest[2*x.length-2] = cast(uint)c; } void multibyteSquare(BigDigit[] result, const(BigDigit) [] x) pure @nogc nothrow { multibyteTriangleAccumulate(result, x); result[$-1] = multibyteShl(result[1..$-1], result[1..$-1], 1); // mul by 2 result[0] = 0; multibyteAddDiagonalSquares(result, x); } version(unittest) { static import std.internal.math.biguintnoasm; import core.stdc.stdio : printf; import std.random; size_t rndArraySz(size_t sz = maxArraySz) { return uniform(1, sz); } immutable tombstone = 0xDEADBEEF; void rndNum(uint[] a, size_t sz) { for (int i = 0; i < sz; i++) a[i] = uniform!uint(); for (int i = sz; i < a.length; i++) a[i] = tombstone; } void initNum(uint[] a) { for (int i = 0; i < a.length; i++) a[i] = tombstone; } void println(string str, uint[] a) { printf("%.*s: ", str.length, str.ptr); for (size_t i = 0; i < a.length; i++) printf("%08X ", a[i]); printf("\n"); } void println(string str, uint[] a, size_t sz) { printf("%.*s: ", str.length, str.ptr); for (size_t i = 0; i < sz; i++) printf("%08X ", a[i]); printf("\n"); } immutable loopMax = 100_000; immutable size_t maxArraySz = 273; uint[] a = new uint[maxArraySz+1]; uint[] b = new uint[maxArraySz+1]; uint[] r1 = new uint[maxArraySz+1]; uint[] r2 = new uint[maxArraySz+1]; void testMultibyteAddSub() { for (int j = 0; j < loopMax; j++) { auto arraySz = rndArraySz(); rndNum(a, arraySz); rndNum(b, arraySz); initNum(r1); initNum(r2); immutable uint carry = uniform(0, 2); // Add auto c1 = multibyteAddSub!('+')(r1[0..arraySz], a[0..arraySz], b[0..arraySz], carry); auto c2 = std.internal.math.biguintnoasm.multibyteAddSub!('+')(r2[0..arraySz], a[0..arraySz], b[0..arraySz], carry); assert(r1[0..arraySz] == r2[0..arraySz]); assert(c1 == c2); assert(c1 == 0 || c1 == 1); assert(a[arraySz] == tombstone); assert(b[arraySz] == tombstone); assert(r1[arraySz] == tombstone); assert(r2[arraySz] == tombstone); // Sub c1 = multibyteAddSub!('-')(r1[0..arraySz], a[0..arraySz], b[0..arraySz], carry); c2 = std.internal.math.biguintnoasm.multibyteAddSub!('-')(r2[0..arraySz], a[0..arraySz], b[0..arraySz], carry); assert(r1[0..arraySz] == r2[0..arraySz]); assert(c1 == c2); assert(c1 == 0 || c1 == 1); assert(a[arraySz] == tombstone); assert(b[arraySz] == tombstone); assert(r1[arraySz] == tombstone); assert(r2[arraySz] == tombstone); } } void testMultibyteIncrementAssign() { auto arraySz = rndArraySz(); rndNum(r1, arraySz); a[] = r1[]; b[] = r1[]; immutable uint carry = uniform!uint(); // Add auto c1 = multibyteIncrementAssign!('+')(a[0..arraySz], carry); auto c2 = std.internal.math.biguintnoasm.multibyteIncrementAssign!('+')(b[0..arraySz], carry); assert(a[0..arraySz] == b[0..arraySz]); assert(c1 == c2); assert(c1 == 0 || c1 == 1); assert(a[arraySz] == tombstone); assert(b[arraySz] == tombstone); // Sub a[] = r1[]; b[] = r1[]; c1 = multibyteIncrementAssign!('-')(a[0..arraySz], carry); c2 = std.internal.math.biguintnoasm.multibyteIncrementAssign!('-')(b[0..arraySz], carry); assert(a[0..arraySz] == b[0..arraySz]); assert(c1 == c2); assert(c1 == 0 || c1 == 1); assert(a[arraySz] == tombstone); assert(b[arraySz] == tombstone); } void testMultibyteShl() { for (int i = 0; i < loopMax; i++) { auto arraySz = rndArraySz(); rndNum(a, arraySz); initNum(r1); initNum(r2); immutable uint shift = uniform(1, 32); auto sh1 = multibyteShl(r1[0..arraySz], a[0..arraySz], shift); auto sh2 = std.internal.math.biguintnoasm.multibyteShl(r2[0..arraySz], a[0..arraySz], shift); assert(r1[0..arraySz] == r2[0..arraySz]); assert(sh1 == sh2); assert(a[arraySz] == tombstone); assert(r1[arraySz] == tombstone); assert(r2[arraySz] == tombstone); } } void testMultibyteShr() { for (int i = 0; i < loopMax; i++) { auto arraySz = rndArraySz(); rndNum(a, arraySz); initNum(r1); initNum(r2); immutable uint shift = uniform(1, 32); multibyteShr(r1[0..arraySz], a[0..arraySz], shift); std.internal.math.biguintnoasm.multibyteShr(r2[0..arraySz], a[0..arraySz], shift); assert(r1[0..arraySz] == r2[0..arraySz]); assert(a[arraySz] == tombstone); assert(r1[arraySz] == tombstone); assert(r2[arraySz] == tombstone); } } void testMultibyteMul() { for (int i = 0; i < loopMax; i++) { auto arraySz = rndArraySz(); rndNum(a, arraySz); initNum(r1); initNum(r2); immutable uint mult = uniform!uint(); immutable uint carry = uniform(0, 2); auto c1 = multibyteMul(r1[0..arraySz], a[0..arraySz], mult, carry); auto c2 = std.internal.math.biguintnoasm.multibyteMul(r2[0..arraySz], a[0..arraySz], mult, carry); assert(r1[0..arraySz] == r2[0..arraySz]); assert(c1 == c2); assert(a[arraySz] == tombstone); assert(r1[arraySz] == tombstone); assert(r2[arraySz] == tombstone); } } void testMultibyteMulAdd() { for (int i = 0; i < loopMax; i++) { auto arraySz = rndArraySz(); rndNum(a, arraySz); initNum(r1); initNum(r2); immutable uint mult = uniform!uint(); immutable uint carry = uniform(0, 2); // Add auto c1 = multibyteMulAdd!('+')(r1[0..arraySz], a[0..arraySz], mult, carry); auto c2 = std.internal.math.biguintnoasm.multibyteMulAdd!('+')(r2[0..arraySz], a[0..arraySz], mult, carry); assert(r1[0..arraySz] == r2[0..arraySz]); assert(c1 == c2); assert(a[arraySz] == tombstone); assert(r1[arraySz] == tombstone); assert(r2[arraySz] == tombstone); // Sub c1 = multibyteMulAdd!('-')(r1[0..arraySz], a[0..arraySz], mult, carry); c2 = std.internal.math.biguintnoasm.multibyteMulAdd!('-')(r2[0..arraySz], a[0..arraySz], mult, carry); assert(r1[0..arraySz] == r2[0..arraySz]); assert(c1 == c2); assert(a[arraySz] == tombstone); assert(r1[arraySz] == tombstone); assert(r2[arraySz] == tombstone); } } void testMultibyteAddDiagonalSquares() { for (int i = 0; i < loopMax; i++) { auto arraySz = rndArraySz(maxArraySz/2); rndNum(a, arraySz); initNum(r1); initNum(r2); multibyteAddDiagonalSquares(r1, a[0..arraySz]); std.internal.math.biguintnoasm.multibyteAddDiagonalSquares(r2, a[0..arraySz]); assert(r1[0..2*arraySz] == r2[0..2*arraySz]); assert(a[arraySz] == tombstone); assert(r1[2*arraySz+1] == tombstone); assert(r2[2*arraySz+1] == tombstone); } } unittest { testMultibyteAddSub(); testMultibyteIncrementAssign(); testMultibyteShl(); testMultibyteShr(); testMultibyteMul(); testMultibyteMulAdd(); testMultibyteAddDiagonalSquares(); } } //version = timings; version(timings) { static import std.internal.math.biguintnoasm; import core.stdc.stdio : printf; import core.time : TickDuration; import std.datetime : StopWatch; import std.random; void report(string name, TickDuration time1, TickDuration time2) { printf("Result for %.*s: Speedup = %.4f\n", name.length, name.ptr, cast(float)time2.hnsecs / cast(float)time1.hnsecs); printf("Opt: %lld usec %lld nsec\n", cast(ulong)time1.usecs, cast(ulong)time1.hnsecs); printf("Base: %lld usec %lld nsec\n", cast(ulong)time2.usecs, cast(ulong)time2.hnsecs); } void main() { StopWatch sw; immutable size_t loopCount = 10_000; immutable size_t arraySz = 380; immutable size_t dataSz = 1000; uint[][] data = new uint[][dataSz]; foreach (ref d; data) { d = new uint[arraySz]; foreach (ref i; d) i = uniform!uint(); } uint[] r = new uint[arraySz]; // Warm-up for (size_t i = 0; i < dataSz; i +=2) { auto c1 = multibyteAddSub!('+')(r, data[i], data[i+1], 0); } // Time sw.start(); for (size_t j = 0; j < loopCount; j++) { for (size_t i = 0; i < dataSz; i +=2) { auto c1 = multibyteAddSub!('+')(r, data[i], data[i+1], 0); } } sw.stop(); auto time1 = sw.peek(); // Warm-up for (size_t i = 0; i < dataSz; i +=2) { auto c1 = std.internal.math.biguintnoasm.multibyteAddSub!('+')(r, data[i], data[i+1], 0); } // Time sw.start(); for (size_t j = 0; j < loopCount; j++) { for (size_t i = 0; i < dataSz; i +=2) { auto c1 = std.internal.math.biguintnoasm.multibyteAddSub!('+')(r, data[i], data[i+1], 0); } } sw.stop(); auto time2 = sw.peek(); // Print result report("multibyteAddSub!('+')", time1, time2); // Warm-up for (size_t i = 0; i < dataSz; i +=2) { auto c1 = multibyteMul(r, data[i], 17, 0); } // Time sw.start(); for (size_t j = 0; j < loopCount; j++) { for (size_t i = 0; i < dataSz; i +=2) { auto c1 = multibyteMul(r, data[i], 17, 0); } } sw.stop(); auto time3 = sw.peek(); // Warm-up for (size_t i = 0; i < dataSz; i +=2) { auto c1 = std.internal.math.biguintnoasm.multibyteMul(r, data[i], 17, 0); } // Time sw.start(); for (size_t j = 0; j < loopCount; j++) { for (size_t i = 0; i < dataSz; i +=2) { auto c1 = std.internal.math.biguintnoasm.multibyteMul(r, data[i], 17, 0); } } sw.stop(); auto time4 = sw.peek(); // Print result report("multibyteMul", time3, time4); // Warm-up for (size_t i = 0; i < dataSz; i +=2) { auto c1 = multibyteMulAdd!('+')(r, data[i], 17, 0); } // Time sw.start(); for (size_t j = 0; j < loopCount; j++) { r[] = 0; for (size_t i = 0; i < dataSz; i +=2) { auto c1 = multibyteMulAdd!('+')(r, data[i], 17, 0); } } sw.stop(); auto time5 = sw.peek(); // Warm-up for (size_t i = 0; i < dataSz; i +=2) { auto c1 = std.internal.math.biguintnoasm.multibyteMulAdd!('+')(r, data[i], 17, 0); } // Time sw.start(); for (size_t j = 0; j < loopCount; j++) { r[] = 0; for (size_t i = 0; i < dataSz; i +=2) { auto c1 = std.internal.math.biguintnoasm.multibyteMulAdd!('+')(r, data[i], 17, 0); } } sw.stop(); auto time6 = sw.peek(); // Print result report("multibyteMulAdd!('+')", time5, time6); } } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/math/biguintcore.d0000664000175000017500000023175212776215007023144 0ustar kaikai/** Fundamental operations for arbitrary-precision arithmetic * * These functions are for internal use only. */ /* Copyright Don Clugston 2008 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ /* References: "Modern Computer Arithmetic" (MCA) is the primary reference for all algorithms used in this library. - R.P. Brent and P. Zimmermann, "Modern Computer Arithmetic", Version 0.5.9, (Oct 2010). - C. Burkinel and J. Ziegler, "Fast Recursive Division", MPI-I-98-1-022, Max-Planck Institute fuer Informatik, (Oct 1998). - G. Hanrot, M. Quercia, and P. Zimmermann, "The Middle Product Algorithm, I.", INRIA 4664, (Dec 2002). - M. Bodrato and A. Zanoni, "What about Toom-Cook Matrices Optimality?", http://bodrato.it/papers (2006). - A. Fog, "Optimizing subroutines in assembly language", www.agner.org/optimize (2008). - A. Fog, "The microarchitecture of Intel and AMD CPU's", www.agner.org/optimize (2008). - A. Fog, "Instruction tables: Lists of instruction latencies, throughputs and micro-operation breakdowns for Intel and AMD CPU's.", www.agner.org/optimize (2008). Idioms: Many functions in this module use 'func(Tulong)(Tulong x) if (is(Tulong == ulong))' rather than 'func(ulong x)' in order to disable implicit conversion. */ module std.internal.math.biguintcore; version(D_InlineAsm_X86) { import std.internal.math.biguintx86; } else version(LDC) { version(ARM_Thumb) import std.internal.math.biguintnoasm; else version(ARM) import std.internal.math.biguintarm; else import std.internal.math.biguintnoasm; } else { import std.internal.math.biguintnoasm; } alias multibyteAdd = multibyteAddSub!('+'); alias multibyteSub = multibyteAddSub!('-'); private import core.cpuid; private import std.traits : Unqual; public import std.ascii : LetterCase; shared static this() { CACHELIMIT = core.cpuid.datacache[0].size*1024/2; } private: // Limits for when to switch between algorithms. immutable size_t CACHELIMIT; // Half the size of the data cache. enum size_t FASTDIVLIMIT = 100; // crossover to recursive division // These constants are used by shift operations static if (BigDigit.sizeof == int.sizeof) { enum { LG2BIGDIGITBITS = 5, BIGDIGITSHIFTMASK = 31 }; alias BIGHALFDIGIT = ushort; } else static if (BigDigit.sizeof == long.sizeof) { alias BIGHALFDIGIT = uint; enum { LG2BIGDIGITBITS = 6, BIGDIGITSHIFTMASK = 63 }; } else static assert(0, "Unsupported BigDigit size"); private import std.exception : assumeUnique; private import std.traits:isIntegral; enum BigDigitBits = BigDigit.sizeof*8; template maxBigDigits(T) if (isIntegral!T) { enum maxBigDigits = (T.sizeof+BigDigit.sizeof-1)/BigDigit.sizeof; } static immutable BigDigit[] ZERO = [0]; static immutable BigDigit[] ONE = [1]; static immutable BigDigit[] TWO = [2]; static immutable BigDigit[] TEN = [10]; public: /// BigUint performs memory management and wraps the low-level calls. struct BigUint { private: pure invariant() { assert( data.length >= 1 && (data.length == 1 || data[$-1] != 0 )); } immutable(BigDigit) [] data = ZERO; this(immutable(BigDigit) [] x) pure nothrow @nogc @safe { data = x; } package(std) // used from: std.bigint this(T)(T x) pure nothrow @safe if (isIntegral!T) { opAssign(x); } enum trustedAssumeUnique = function(BigDigit[] input) pure @trusted @nogc { return assumeUnique(input); }; public: // Length in uints @property size_t uintLength() pure nothrow const @safe @nogc { static if (BigDigit.sizeof == uint.sizeof) { return data.length; } else static if (BigDigit.sizeof == ulong.sizeof) { return data.length * 2 - ((data[$-1] & 0xFFFF_FFFF_0000_0000L) ? 1 : 0); } } @property size_t ulongLength() pure nothrow const @safe @nogc { static if (BigDigit.sizeof == uint.sizeof) { return (data.length + 1) >> 1; } else static if (BigDigit.sizeof == ulong.sizeof) { return data.length; } } // The value at (cast(ulong[])data)[n] ulong peekUlong(int n) pure nothrow const @safe @nogc { static if (BigDigit.sizeof == int.sizeof) { if (data.length == n*2 + 1) return data[n*2]; return data[n*2] + ((cast(ulong)data[n*2 + 1]) << 32 ); } else static if (BigDigit.sizeof == long.sizeof) { return data[n]; } } uint peekUint(int n) pure nothrow const @safe @nogc { static if (BigDigit.sizeof == int.sizeof) { return data[n]; } else { ulong x = data[n >> 1]; return (n & 1) ? cast(uint)(x >> 32) : cast(uint)x; } } public: /// void opAssign(Tulong)(Tulong u) pure nothrow @safe if (is (Tulong == ulong)) { if (u == 0) data = ZERO; else if (u == 1) data = ONE; else if (u == 2) data = TWO; else if (u == 10) data = TEN; else { static if (BigDigit.sizeof == int.sizeof) { uint ulo = cast(uint)(u & 0xFFFF_FFFF); uint uhi = cast(uint)(u >> 32); if (uhi == 0) { data = [ulo]; } else { data = [ulo, uhi]; } } else static if (BigDigit.sizeof == long.sizeof) { data = [u]; } } } void opAssign(Tdummy = void)(BigUint y) pure nothrow @nogc @safe { this.data = y.data; } /// int opCmp(Tdummy = void)(const BigUint y) pure nothrow @nogc const @safe { if (data.length != y.data.length) return (data.length > y.data.length) ? 1 : -1; size_t k = highestDifferentDigit(data, y.data); if (data[k] == y.data[k]) return 0; return data[k] > y.data[k] ? 1 : -1; } /// int opCmp(Tulong)(Tulong y) pure nothrow @nogc const @safe if(is (Tulong == ulong)) { if (data.length > maxBigDigits!Tulong) return 1; foreach_reverse (i; 0 .. maxBigDigits!Tulong) { BigDigit tmp = cast(BigDigit)(y>>(i*BigDigitBits)); if (tmp == 0) if (data.length >= i+1) { // Since ZERO is [0], so we cannot simply return 1 here, as // data[i] would be 0 for i==0 in that case. return (data[i] > 0) ? 1 : 0; } else continue; else if (i+1 > data.length) return -1; else if (tmp != data[i]) return data[i] > tmp ? 1 : -1; } return 0; } bool opEquals(Tdummy = void)(ref const BigUint y) pure nothrow @nogc const @safe { return y.data[] == data[]; } bool opEquals(Tdummy = void)(ulong y) pure nothrow @nogc const @safe { if (data.length > 2) return false; uint ylo = cast(uint)(y & 0xFFFF_FFFF); uint yhi = cast(uint)(y >> 32); if (data.length==2 && data[1]!=yhi) return false; if (data.length==1 && yhi!=0) return false; return (data[0] == ylo); } bool isZero() pure const nothrow @safe @nogc { return data.length == 1 && data[0] == 0; } size_t numBytes() pure nothrow const @safe @nogc { return data.length * BigDigit.sizeof; } // the extra bytes are added to the start of the string char [] toDecimalString(int frontExtraBytes) const pure nothrow { auto predictlength = 20+20*(data.length/2); // just over 19 char [] buff = new char[frontExtraBytes + predictlength]; ptrdiff_t sofar = biguintToDecimal(buff, data.dup); return buff[sofar-frontExtraBytes..$]; } /** Convert to a hex string, printing a minimum number of digits 'minPadding', * allocating an additional 'frontExtraBytes' at the start of the string. * Padding is done with padChar, which may be '0' or ' '. * 'separator' is a digit separation character. If non-zero, it is inserted * between every 8 digits. * Separator characters do not contribute to the minPadding. */ char [] toHexString(int frontExtraBytes, char separator = 0, int minPadding=0, char padChar = '0', LetterCase letterCase = LetterCase.upper) const pure nothrow @safe { // Calculate number of extra padding bytes size_t extraPad = (minPadding > data.length * 2 * BigDigit.sizeof) ? minPadding - data.length * 2 * BigDigit.sizeof : 0; // Length not including separator bytes size_t lenBytes = data.length * 2 * BigDigit.sizeof; // Calculate number of separator bytes size_t mainSeparatorBytes = separator ? (lenBytes / 8) - 1 : 0; size_t totalSeparatorBytes = separator ? ((extraPad + lenBytes + 7) / 8) - 1: 0; char [] buff = new char[lenBytes + extraPad + totalSeparatorBytes + frontExtraBytes]; biguintToHex(buff[$ - lenBytes - mainSeparatorBytes .. $], data, separator, letterCase); if (extraPad > 0) { if (separator) { size_t start = frontExtraBytes; // first index to pad if (extraPad &7) { // Do 1 to 7 extra zeros. buff[frontExtraBytes .. frontExtraBytes + (extraPad & 7)] = padChar; buff[frontExtraBytes + (extraPad & 7)] = (padChar == ' ' ? ' ' : separator); start += (extraPad & 7) + 1; } for (int i=0; i< (extraPad >> 3); ++i) { buff[start .. start + 8] = padChar; buff[start + 8] = (padChar == ' ' ? ' ' : separator); start += 9; } } else { buff[frontExtraBytes .. frontExtraBytes + extraPad]=padChar; } } int z = frontExtraBytes; if (lenBytes > minPadding) { // Strip leading zeros. ptrdiff_t maxStrip = lenBytes - minPadding; while (z< buff.length-1 && (buff[z]=='0' || buff[z]==padChar) && maxStrip>0) { ++z; --maxStrip; } } if (padChar!='0') { // Convert leading zeros into padChars. for (size_t k= z; k< buff.length-1 && (buff[k]=='0' || buff[k]==padChar); ++k) { if (buff[k]=='0') buff[k]=padChar; } } return buff[z-frontExtraBytes..$]; } // return false if invalid character found bool fromHexString(const(char)[] s) pure nothrow @safe { //Strip leading zeros int firstNonZero = 0; while ((firstNonZero < s.length - 1) && (s[firstNonZero]=='0' || s[firstNonZero]=='_')) { ++firstNonZero; } auto len = (s.length - firstNonZero + 15)/4; auto tmp = new BigDigit[len+1]; uint part = 0; uint sofar = 0; uint partcount = 0; assert(s.length>0); for (ptrdiff_t i = s.length - 1; i>=firstNonZero; --i) { assert(i>=0); char c = s[i]; if (s[i]=='_') continue; uint x = (c>='0' && c<='9') ? c - '0' : (c>='A' && c<='F') ? c - 'A' + 10 : (c>='a' && c<='f') ? c - 'a' + 10 : 100; if (x==100) return false; part >>= 4; part |= (x<<(32-4)); ++partcount; if (partcount==8) { tmp[sofar] = part; ++sofar; partcount = 0; part = 0; } } if (part) { for ( ; partcount != 8; ++partcount) part >>= 4; tmp[sofar] = part; ++sofar; } if (sofar == 0) data = ZERO; else data = trustedAssumeUnique(tmp[0 .. sofar]); return true; } // return true if OK; false if erroneous characters found // FIXME: actually throws `ConvException` on error. bool fromDecimalString(const(char)[] s) pure @trusted { //Strip leading zeros int firstNonZero = 0; while ((firstNonZero < s.length) && (s[firstNonZero]=='0' || s[firstNonZero]=='_')) { ++firstNonZero; } if (firstNonZero == s.length && s.length >= 1) { data = ZERO; return true; } auto predictlength = (18*2 + 2*(s.length-firstNonZero)) / 19; auto tmp = new BigDigit[predictlength]; uint hi = biguintFromDecimal(tmp, s[firstNonZero..$]); tmp.length = hi; data = trustedAssumeUnique(tmp); return true; } //////////////////////// // // All of these member functions create a new BigUint. // return x >> y BigUint opShr(Tulong)(Tulong y) pure nothrow const if (is (Tulong == ulong)) { assert(y>0); uint bits = cast(uint)y & BIGDIGITSHIFTMASK; if ((y>>LG2BIGDIGITBITS) >= data.length) return BigUint(ZERO); uint words = cast(uint)(y >> LG2BIGDIGITBITS); if (bits==0) { return BigUint(data[words..$]); } else { uint [] result = new BigDigit[data.length - words]; multibyteShr(result, data[words..$], bits); if (result.length > 1 && result[$-1] == 0) return BigUint(trustedAssumeUnique(result[0 .. $-1])); else return BigUint(trustedAssumeUnique(result)); } } // return x << y BigUint opShl(Tulong)(Tulong y) pure nothrow const if (is (Tulong == ulong)) { assert(y>0); if (isZero()) return this; uint bits = cast(uint)y & BIGDIGITSHIFTMASK; assert ((y>>LG2BIGDIGITBITS) < cast(ulong)(uint.max)); uint words = cast(uint)(y >> LG2BIGDIGITBITS); BigDigit [] result = new BigDigit[data.length + words+1]; result[0..words] = 0; if (bits==0) { result[words..words+data.length] = data[]; return BigUint(trustedAssumeUnique(result[0..words+data.length])); } else { uint c = multibyteShl(result[words..words+data.length], data, bits); if (c==0) return BigUint(trustedAssumeUnique(result[0..words+data.length])); result[$-1] = c; return BigUint(trustedAssumeUnique(result)); } } // If wantSub is false, return x + y, leaving sign unchanged // If wantSub is true, return abs(x - y), negating sign if x < y static BigUint addOrSubInt(Tulong)(const BigUint x, Tulong y, bool wantSub, ref bool sign) pure nothrow if (is(Tulong == ulong)) { BigUint r; if (wantSub) { // perform a subtraction if (x.data.length > 2) { r.data = subInt(x.data, y); } else { // could change sign! ulong xx = x.data[0]; if (x.data.length > 1) xx += (cast(ulong)x.data[1]) << 32; ulong d; if (xx <= y) { d = y - xx; sign = !sign; } else { d = xx - y; } if (d == 0) { r = 0UL; sign = false; return r; } if (d > uint.max) { r.data = [cast(uint)(d & 0xFFFF_FFFF), cast(uint)(d>>32)]; } else { r.data = [cast(uint)(d & 0xFFFF_FFFF)]; } } } else { r.data = addInt(x.data, y); } return r; } // If wantSub is false, return x + y, leaving sign unchanged. // If wantSub is true, return abs(x - y), negating sign if x>> 32); uint lo = cast(uint)(y & 0xFFFF_FFFF); uint [] result = new BigDigit[x.data.length+1+(hi!=0)]; result[x.data.length] = multibyteMul(result[0..x.data.length], x.data, lo, 0); if (hi!=0) { result[x.data.length+1] = multibyteMulAdd!('+')(result[1..x.data.length+1], x.data, hi, 0); } return BigUint(removeLeadingZeros(trustedAssumeUnique(result))); } /* return x * y. */ static BigUint mul(BigUint x, BigUint y) pure nothrow { if (y==0 || x == 0) return BigUint(ZERO); auto len = x.data.length + y.data.length; BigDigit [] result = new BigDigit[len]; if (y.data.length > x.data.length) { mulInternal(result, y.data, x.data); } else { if (x.data[]==y.data[]) squareInternal(result, x.data); else mulInternal(result, x.data, y.data); } // the highest element could be zero, // in which case we need to reduce the length return BigUint(removeLeadingZeros(trustedAssumeUnique(result))); } // return x / y static BigUint divInt(T)(BigUint x, T y_) pure nothrow if ( is(Unqual!T == uint) ) { uint y = y_; if (y == 1) return x; uint [] result = new BigDigit[x.data.length]; if ((y&(-y))==y) { assert(y!=0, "BigUint division by zero"); // perfect power of 2 uint b = 0; for (;y!=1; y>>=1) { ++b; } multibyteShr(result, x.data, b); } else { result[] = x.data[]; uint rem = multibyteDivAssign(result, y, 0); } return BigUint(removeLeadingZeros(trustedAssumeUnique(result))); } static BigUint divInt(T)(BigUint x, T y) pure nothrow if ( is(Unqual!T == ulong) ) { if (y <= uint.max) return divInt!uint(x, cast(uint)y); if (x.data.length < 2) return BigUint(ZERO); uint hi = cast(uint)(y >>> 32); uint lo = cast(uint)(y & 0xFFFF_FFFF); immutable uint[2] z = [lo, hi]; BigDigit[] result = new BigDigit[x.data.length - z.length + 1]; divModInternal(result, null, x.data, z[]); return BigUint(removeLeadingZeros(trustedAssumeUnique(result))); } // return x % y static uint modInt(T)(BigUint x, T y_) pure if ( is(Unqual!T == uint) ) { uint y = y_; assert(y!=0); if ((y&(-y)) == y) { // perfect power of 2 return x.data[0] & (y-1); } else { // horribly inefficient - malloc, copy, & store are unnecessary. uint [] wasteful = new BigDigit[x.data.length]; wasteful[] = x.data[]; uint rem = multibyteDivAssign(wasteful, y, 0); delete wasteful; return rem; } } // return x / y static BigUint div(BigUint x, BigUint y) pure nothrow { if (y.data.length > x.data.length) return BigUint(ZERO); if (y.data.length == 1) return divInt(x, y.data[0]); BigDigit [] result = new BigDigit[x.data.length - y.data.length + 1]; divModInternal(result, null, x.data, y.data); return BigUint(removeLeadingZeros(trustedAssumeUnique(result))); } // return x % y static BigUint mod(BigUint x, BigUint y) pure nothrow { if (y.data.length > x.data.length) return x; if (y.data.length == 1) { return BigUint([modInt(x, y.data[0])]); } BigDigit [] result = new BigDigit[x.data.length - y.data.length + 1]; BigDigit [] rem = new BigDigit[y.data.length]; divModInternal(result, rem, x.data, y.data); return BigUint(removeLeadingZeros(trustedAssumeUnique(rem))); } // return x op y static BigUint bitwiseOp(string op)(BigUint x, BigUint y, bool xSign, bool ySign, ref bool resultSign) pure nothrow @safe if (op == "|" || op == "^" || op == "&") { auto d1 = includeSign(x.data, y.uintLength, xSign); auto d2 = includeSign(y.data, x.uintLength, ySign); foreach (i; 0..d1.length) { mixin("d1[i] " ~ op ~ "= d2[i];"); } mixin("resultSign = xSign " ~ op ~ " ySign;"); if (resultSign) { twosComplement(d1, d1); } return BigUint(removeLeadingZeros(trustedAssumeUnique(d1))); } /** * Return a BigUint which is x raised to the power of y. * Method: Powers of 2 are removed from x, then left-to-right binary * exponentiation is used. * Memory allocation is minimized: at most one temporary BigUint is used. */ static BigUint pow(BigUint x, ulong y) pure nothrow { // Deal with the degenerate cases first. if (y==0) return BigUint(ONE); if (y==1) return x; if (x==0 || x==1) return x; BigUint result; // Simplify, step 1: Remove all powers of 2. uint firstnonzero = firstNonZeroDigit(x.data); // Now we know x = x[firstnonzero..$] * (2^^(firstnonzero*BigDigitBits)) // where BigDigitBits = BigDigit.sizeof * 8 // See if x[firstnonzero..$] can now fit into a single digit. bool singledigit = ((x.data.length - firstnonzero) == 1); // If true, then x0 is that digit // and the result will be (x0 ^^ y) * (2^^(firstnonzero*y*BigDigitBits)) BigDigit x0 = x.data[firstnonzero]; assert(x0 !=0); // Length of the non-zero portion size_t nonzerolength = x.data.length - firstnonzero; ulong y0; uint evenbits = 0; // number of even bits in the bottom of x while (!(x0 & 1)) { x0 >>= 1; ++evenbits; } if ((x.data.length- firstnonzero == 2)) { // Check for a single digit straddling a digit boundary BigDigit x1 = x.data[firstnonzero+1]; if ((x1 >> evenbits) == 0) { x0 |= (x1 << (BigDigit.sizeof * 8 - evenbits)); singledigit = true; } } // Now if (singledigit), x^^y = (x0 ^^ y) * 2^^(evenbits * y) * 2^^(firstnonzero*y*BigDigitBits)) uint evenshiftbits = 0; // Total powers of 2 to shift by, at the end // Simplify, step 2: For singledigits, see if we can trivially reduce y BigDigit finalMultiplier = 1UL; if (singledigit) { // x fits into a single digit. Raise it to the highest power we can // that still fits into a single digit, then reduce the exponent accordingly. // We're quite likely to have a residual multiply at the end. // For example, 10^^100 = (((5^^13)^^7) * 5^^9) * 2^^100. // and 5^^13 still fits into a uint. evenshiftbits = cast(uint)( (evenbits * y) & BIGDIGITSHIFTMASK); if (x0 == 1) { // Perfect power of 2 result = 1UL; return result << (evenbits + firstnonzero * 8 * BigDigit.sizeof) * y; } int p = highestPowerBelowUintMax(x0); if (y <= p) { // Just do it with pow result = cast(ulong)intpow(x0, y); if (evenbits + firstnonzero == 0) return result; return result << (evenbits + firstnonzero * 8 * BigDigit.sizeof) * y; } y0 = y / p; finalMultiplier = intpow(x0, y - y0*p); x0 = intpow(x0, p); // Result is x0 nonzerolength = 1; } // Now if (singledigit), x^^y = finalMultiplier * (x0 ^^ y0) * 2^^(evenbits * y) * 2^^(firstnonzero*y*BigDigitBits)) // Perform a crude check for overflow and allocate result buffer. // The length required is y * lg2(x) bits. // which will always fit into y*x.length digits. But this is // a gross overestimate if x is small (length 1 or 2) and the highest // digit is nearly empty. // A better estimate is: // y * lg2(x[$-1]/BigDigit.max) + y * (x.length - 1) digits, // and the first term is always between // y * (bsr(x.data[$-1]) + 1) / BIGDIGITBITS and // y * (bsr(x.data[$-1]) + 2) / BIGDIGITBITS // For single digit payloads, we already have // x^^y = finalMultiplier * (x0 ^^ y0) * 2^^(evenbits * y) * 2^^(firstnonzero*y*BigDigitBits)) // and x0 is almost a full digit, so it's a tight estimate. // Number of digits is therefore 1 + x0.length*y0 + (evenbits*y)/BIGDIGIT + firstnonzero*y // Note that the divisions must be rounded up. // Estimated length in BigDigits ulong estimatelength = singledigit ? 1 + y0 + ((evenbits*y + BigDigit.sizeof * 8 - 1) / (BigDigit.sizeof *8)) + firstnonzero*y : x.data.length * y; // Imprecise check for overflow. Makes the extreme cases easier to debug // (less extreme overflow will result in an out of memory error). if (estimatelength > uint.max/(4*BigDigit.sizeof)) assert(0, "Overflow in BigInt.pow"); // The result buffer includes space for all the trailing zeros BigDigit [] resultBuffer = new BigDigit[cast(size_t)estimatelength]; // Do all the powers of 2! size_t result_start = cast(size_t)( firstnonzero * y + (singledigit ? ((evenbits * y) >> LG2BIGDIGITBITS) : 0)); resultBuffer[0..result_start] = 0; BigDigit [] t1 = resultBuffer[result_start..$]; BigDigit [] r1; if (singledigit) { r1 = t1[0..1]; r1[0] = x0; y = y0; } else { // It's not worth right shifting by evenbits unless we also shrink the length after each // multiply or squaring operation. That might still be worthwhile for large y. r1 = t1[0..x.data.length - firstnonzero]; r1[0..$] = x.data[firstnonzero..$]; } if (y>1) { // Set r1 = r1 ^^ y. // The secondary buffer only needs space for the multiplication results BigDigit [] secondaryBuffer = new BigDigit[resultBuffer.length - result_start]; BigDigit [] t2 = secondaryBuffer; BigDigit [] r2; int shifts = 63; // num bits in a long while(!(y & 0x8000_0000_0000_0000L)) { y <<= 1; --shifts; } y <<=1; while(y!=0) { // For each bit of y: Set r1 = r1 * r1 // If the bit is 1, set r1 = r1 * x // Eg, if y is 0b101, result = ((x^^2)^^2)*x == x^^5. // Optimization opportunity: if more than 2 bits in y are set, // it's usually possible to reduce the number of multiplies // by caching odd powers of x. eg for y = 54, // (0b110110), set u = x^^3, and result is ((u^^8)*u)^^2 r2 = t2[0 .. r1.length*2]; squareInternal(r2, r1); if (y & 0x8000_0000_0000_0000L) { r1 = t1[0 .. r2.length + nonzerolength]; if (singledigit) { r1[$-1] = multibyteMul(r1[0 .. $-1], r2, x0, 0); } else { mulInternal(r1, r2, x.data[firstnonzero..$]); } } else { r1 = t1[0 .. r2.length]; r1[] = r2[]; } y <<=1; shifts--; } while (shifts>0) { r2 = t2[0 .. r1.length * 2]; squareInternal(r2, r1); r1 = t1[0 .. r2.length]; r1[] = r2[]; --shifts; } } if (finalMultiplier!=1) { BigDigit carry = multibyteMul(r1, r1, finalMultiplier, 0); if (carry) { r1 = t1[0 .. r1.length + 1]; r1[$-1] = carry; } } if (evenshiftbits) { BigDigit carry = multibyteShl(r1, r1, evenshiftbits); if (carry!=0) { r1 = t1[0 .. r1.length + 1]; r1[$ - 1] = carry; } } while(r1[$ - 1]==0) { r1=r1[0 .. $ - 1]; } return BigUint(trustedAssumeUnique(resultBuffer[0 .. result_start + r1.length])); } // Implement toHash so that BigUint works properly as an AA key. size_t toHash() const @trusted nothrow { return typeid(data).getHash(&data); } } // end BigUint @safe pure nothrow unittest { // ulong comparison test BigUint a = [1]; assert(a == 1); assert(a < 0x8000_0000_0000_0000UL); // bug 9548 // bug 12234 BigUint z = [0]; assert(z == 0UL); assert(!(z > 0UL)); assert(!(z < 0UL)); } // Remove leading zeros from x, to restore the BigUint invariant inout(BigDigit) [] removeLeadingZeros(inout(BigDigit) [] x) pure nothrow @safe { size_t k = x.length; while(k>1 && x[k - 1]==0) --k; return x[0 .. k]; } pure unittest { BigUint r = BigUint([5]); BigUint t = BigUint([7]); BigUint s = BigUint.mod(r, t); assert(s==5); } @safe pure unittest { BigUint r; r = 5UL; assert(r.peekUlong(0) == 5UL); assert(r.peekUint(0) == 5U); r = 0x1234_5678_9ABC_DEF0UL; assert(r.peekUlong(0) == 0x1234_5678_9ABC_DEF0UL); assert(r.peekUint(0) == 0x9ABC_DEF0U); } // Pow tests pure unittest { BigUint r, s; r.fromHexString("80000000_00000001"); s = BigUint.pow(r, 5); r.fromHexString("08000000_00000000_50000000_00000001_40000000_00000002_80000000" ~ "_00000002_80000000_00000001"); assert(s == r); s = 10UL; s = BigUint.pow(s, 39); r.fromDecimalString("1000000000000000000000000000000000000000"); assert(s == r); r.fromHexString("1_E1178E81_00000000"); s = BigUint.pow(r, 15); // Regression test: this used to overflow array bounds r.fromDecimalString("000_000_00"); assert(r == 0); r.fromDecimalString("0007"); assert(r == 7); r.fromDecimalString("0"); assert(r == 0); } // Radix conversion tests @safe pure unittest { BigUint r; r.fromHexString("1_E1178E81_00000000"); assert(r.toHexString(0, '_', 0) == "1_E1178E81_00000000"); assert(r.toHexString(0, '_', 20) == "0001_E1178E81_00000000"); assert(r.toHexString(0, '_', 16+8) == "00000001_E1178E81_00000000"); assert(r.toHexString(0, '_', 16+9) == "0_00000001_E1178E81_00000000"); assert(r.toHexString(0, '_', 16+8+8) == "00000000_00000001_E1178E81_00000000"); assert(r.toHexString(0, '_', 16+8+8+1) == "0_00000000_00000001_E1178E81_00000000"); assert(r.toHexString(0, '_', 16+8+8+1, ' ') == " 1_E1178E81_00000000"); assert(r.toHexString(0, 0, 16+8+8+1) == "00000000000000001E1178E8100000000"); r = 0UL; assert(r.toHexString(0, '_', 0) == "0"); assert(r.toHexString(0, '_', 7) == "0000000"); assert(r.toHexString(0, '_', 7, ' ') == " 0"); assert(r.toHexString(0, '#', 9) == "0#00000000"); assert(r.toHexString(0, 0, 9) == "000000000"); } // @safe pure unittest { BigUint r; r.fromHexString("1_E1178E81_00000000"); assert(r.toHexString(0, '_', 0, '0', LetterCase.lower) == "1_e1178e81_00000000"); assert(r.toHexString(0, '_', 20, '0', LetterCase.lower) == "0001_e1178e81_00000000"); assert(r.toHexString(0, '_', 16+8, '0', LetterCase.lower) == "00000001_e1178e81_00000000"); assert(r.toHexString(0, '_', 16+9, '0', LetterCase.lower) == "0_00000001_e1178e81_00000000"); assert(r.toHexString(0, '_', 16+8+8, '0', LetterCase.lower) == "00000000_00000001_e1178e81_00000000"); assert(r.toHexString(0, '_', 16+8+8+1, '0', LetterCase.lower) == "0_00000000_00000001_e1178e81_00000000"); assert(r.toHexString(0, '_', 16+8+8+1, ' ', LetterCase.lower) == " 1_e1178e81_00000000"); assert(r.toHexString(0, 0, 16+8+8+1, '0', LetterCase.lower) == "00000000000000001e1178e8100000000"); r = 0UL; assert(r.toHexString(0, '_', 0, '0', LetterCase.lower) == "0"); assert(r.toHexString(0, '_', 7, '0', LetterCase.lower) == "0000000"); assert(r.toHexString(0, '_', 7, ' ', LetterCase.lower) == " 0"); assert(r.toHexString(0, '#', 9, '0', LetterCase.lower) == "0#00000000"); assert(r.toHexString(0, 'Z', 9, '0', LetterCase.lower) == "0Z00000000"); assert(r.toHexString(0, 0, 9, '0', LetterCase.lower) == "000000000"); } private: void twosComplement(const(BigDigit) [] x, BigDigit[] result) pure nothrow @safe { foreach (i; 0..x.length) { result[i] = ~x[i]; } result[x.length..$] = BigDigit.max; bool sgn = false; foreach (i; 0..result.length) { if (result[i] == BigDigit.max) { result[i] = 0; } else { result[i] += 1; break; } } } // Encode BigInt as BigDigit array (sign and 2's complement) BigDigit[] includeSign(const(BigDigit) [] x, size_t minSize, bool sign) pure nothrow @safe { size_t length = (x.length > minSize) ? x.length : minSize; BigDigit [] result = new BigDigit[length]; if (sign) { twosComplement(x, result); } else { result[0..x.length] = x; } return result; } // works for any type T intpow(T)(T x, ulong n) pure nothrow @safe { T p; switch (n) { case 0: p = 1; break; case 1: p = x; break; case 2: p = x * x; break; default: p = 1; while (1){ if (n & 1) p *= x; n >>= 1; if (!n) break; x *= x; } break; } return p; } // returns the maximum power of x that will fit in a uint. int highestPowerBelowUintMax(uint x) pure nothrow @safe { assert(x>1); static immutable ubyte [22] maxpwr = [ 31, 20, 15, 13, 12, 11, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7]; if (x<24) return maxpwr[x-2]; if (x<41) return 6; if (x<85) return 5; if (x<256) return 4; if (x<1626) return 3; if (x<65536) return 2; return 1; } // returns the maximum power of x that will fit in a ulong. int highestPowerBelowUlongMax(uint x) pure nothrow @safe { assert(x>1); static immutable ubyte [39] maxpwr = [ 63, 40, 31, 27, 24, 22, 21, 20, 19, 18, 17, 17, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12]; if (x<41) return maxpwr[x-2]; if (x<57) return 11; if (x<85) return 10; if (x<139) return 9; if (x<256) return 8; if (x<566) return 7; if (x<1626) return 6; if (x<7132) return 5; if (x<65536) return 4; if (x<2642246) return 3; return 2; } version(unittest) { int slowHighestPowerBelowUintMax(uint x) pure nothrow @safe { int pwr = 1; for (ulong q = x;x*q < cast(ulong)uint.max; ) { q*=x; ++pwr; } return pwr; } @safe pure unittest { assert(highestPowerBelowUintMax(10)==9); for (int k=82; k<88; ++k) { assert(highestPowerBelowUintMax(k)== slowHighestPowerBelowUintMax(k)); } } } /* General unsigned subtraction routine for bigints. * Sets result = x - y. If the result is negative, negative will be true. */ BigDigit [] sub(const BigDigit [] x, const BigDigit [] y, bool *negative) pure nothrow { if (x.length == y.length) { // There's a possibility of cancellation, if x and y are almost equal. ptrdiff_t last = highestDifferentDigit(x, y); BigDigit [] result = new BigDigit[last+1]; if (x[last] < y[last]) { // we know result is negative multibyteSub(result[0..last+1], y[0..last+1], x[0..last+1], 0); *negative = true; } else { // positive or zero result multibyteSub(result[0..last+1], x[0..last+1], y[0..last+1], 0); *negative = false; } while (result.length > 1 && result[$-1] == 0) { result = result[0..$-1]; } // if (result.length >1 && result[$-1]==0) return result[0..$-1]; return result; } // Lengths are different const(BigDigit) [] large, small; if (x.length < y.length) { *negative = true; large = y; small = x; } else { *negative = false; large = x; small = y; } // result.length will be equal to larger length, or could decrease by 1. BigDigit [] result = new BigDigit[large.length]; BigDigit carry = multibyteSub(result[0..small.length], large[0..small.length], small, 0); result[small.length..$] = large[small.length..$]; if (carry) { multibyteIncrementAssign!('-')(result[small.length..$], carry); } while (result.length > 1 && result[$-1] == 0) { result = result[0..$-1]; } return result; } // return a + b BigDigit [] add(const BigDigit [] a, const BigDigit [] b) pure nothrow { const(BigDigit) [] x, y; if (a.length < b.length) { x = b; y = a; } else { x = a; y = b; } // now we know x.length > y.length // create result. add 1 in case it overflows BigDigit [] result = new BigDigit[x.length + 1]; BigDigit carry = multibyteAdd(result[0..y.length], x[0..y.length], y, 0); if (x.length != y.length) { result[y.length..$-1]= x[y.length..$]; carry = multibyteIncrementAssign!('+')(result[y.length..$-1], carry); } if (carry) { result[$-1] = carry; return result; } else return result[0..$-1]; } /** return x + y */ BigDigit [] addInt(const BigDigit[] x, ulong y) pure nothrow { uint hi = cast(uint)(y >>> 32); uint lo = cast(uint)(y& 0xFFFF_FFFF); auto len = x.length; if (x.length < 2 && hi!=0) ++len; BigDigit [] result = new BigDigit[len+1]; result[0..x.length] = x[]; if (x.length < 2 && hi!=0) { result[1]=hi; hi=0; } uint carry = multibyteIncrementAssign!('+')(result[0..$-1], lo); if (hi!=0) carry += multibyteIncrementAssign!('+')(result[1..$-1], hi); if (carry) { result[$-1] = carry; return result; } else return result[0..$-1]; } /** Return x - y. * x must be greater than y. */ BigDigit [] subInt(const BigDigit[] x, ulong y) pure nothrow { uint hi = cast(uint)(y >>> 32); uint lo = cast(uint)(y & 0xFFFF_FFFF); BigDigit [] result = new BigDigit[x.length]; result[] = x[]; multibyteIncrementAssign!('-')(result[], lo); if (hi) multibyteIncrementAssign!('-')(result[1..$], hi); if (result[$-1] == 0) return result[0..$-1]; else return result; } /** General unsigned multiply routine for bigints. * Sets result = x * y. * * The length of y must not be larger than the length of x. * Different algorithms are used, depending on the lengths of x and y. * TODO: "Modern Computer Arithmetic" suggests the OddEvenKaratsuba algorithm for the * unbalanced case. (But I doubt it would be faster in practice). * */ void mulInternal(BigDigit[] result, const(BigDigit)[] x, const(BigDigit)[] y) pure nothrow { assert( result.length == x.length + y.length ); assert( y.length > 0 ); assert( x.length >= y.length); if (y.length <= KARATSUBALIMIT) { // Small multiplier, we'll just use the asm classic multiply. if (y.length == 1) { // Trivial case, no cache effects to worry about result[x.length] = multibyteMul(result[0..x.length], x, y[0], 0); return; } if (x.length + y.length < CACHELIMIT) return mulSimple(result, x, y); // If x is so big that it won't fit into the cache, we divide it into chunks // Every chunk must be greater than y.length. // We make the first chunk shorter, if necessary, to ensure this. auto chunksize = CACHELIMIT / y.length; auto residual = x.length % chunksize; if (residual < y.length) { chunksize -= y.length; } // Use schoolbook multiply. mulSimple(result[0 .. chunksize + y.length], x[0..chunksize], y); auto done = chunksize; while (done < x.length) { // result[done .. done+ylength] already has a value. chunksize = (done + (CACHELIMIT / y.length) < x.length) ? (CACHELIMIT / y.length) : x.length - done; BigDigit [KARATSUBALIMIT] partial; partial[0..y.length] = result[done..done+y.length]; mulSimple(result[done..done+chunksize+y.length], x[done..done+chunksize], y); addAssignSimple(result[done..done+chunksize + y.length], partial[0..y.length]); done += chunksize; } return; } auto half = (x.length >> 1) + (x.length & 1); if (2*y.length*y.length <= x.length*x.length) { // UNBALANCED MULTIPLY // Use school multiply to cut into quasi-squares of Karatsuba-size // or larger. The ratio of the two sides of the 'square' must be // between 1.414:1 and 1:1. Use Karatsuba on each chunk. // // For maximum performance, we want the ratio to be as close to // 1:1 as possible. To achieve this, we can either pad x or y. // The best choice depends on the modulus x%y. auto numchunks = x.length / y.length; auto chunksize = y.length; auto extra = x.length % y.length; auto maxchunk = chunksize + extra; bool paddingY; // true = we're padding Y, false = we're padding X. if (extra * extra * 2 < y.length*y.length) { // The leftover bit is small enough that it should be incorporated // in the existing chunks. // Make all the chunks a tiny bit bigger // (We're padding y with zeros) chunksize += extra / numchunks; extra = x.length - chunksize*numchunks; // there will probably be a few left over. // Every chunk will either have size chunksize, or chunksize+1. maxchunk = chunksize + 1; paddingY = true; assert(chunksize + extra + chunksize *(numchunks-1) == x.length ); } else { // the extra bit is large enough that it's worth making a new chunk. // (This means we're padding x with zeros, when doing the first one). maxchunk = chunksize; ++numchunks; paddingY = false; assert(extra + chunksize *(numchunks-1) == x.length ); } // We make the buffer a bit bigger so we have space for the partial sums. BigDigit [] scratchbuff = new BigDigit[karatsubaRequiredBuffSize(maxchunk) + y.length]; BigDigit [] partial = scratchbuff[$ - y.length .. $]; size_t done; // how much of X have we done so far? double residual = 0; if (paddingY) { // If the first chunk is bigger, do it first. We're padding y. mulKaratsuba(result[0 .. y.length + chunksize + (extra > 0 ? 1 : 0 )], x[0 .. chunksize + (extra>0?1:0)], y, scratchbuff); done = chunksize + (extra > 0 ? 1 : 0); if (extra) --extra; } else { // We're padding X. Begin with the extra bit. mulKaratsuba(result[0 .. y.length + extra], y, x[0..extra], scratchbuff); done = extra; extra = 0; } auto basechunksize = chunksize; while (done < x.length) { chunksize = basechunksize + (extra > 0 ? 1 : 0); if (extra) --extra; partial[] = result[done .. done+y.length]; mulKaratsuba(result[done .. done + y.length + chunksize], x[done .. done+chunksize], y, scratchbuff); addAssignSimple(result[done .. done + y.length + chunksize], partial); done += chunksize; } delete scratchbuff; } else { // Balanced. Use Karatsuba directly. BigDigit [] scratchbuff = new BigDigit[karatsubaRequiredBuffSize(x.length)]; mulKaratsuba(result, x, y, scratchbuff); delete scratchbuff; } } /** General unsigned squaring routine for BigInts. * Sets result = x*x. * NOTE: If the highest half-digit of x is zero, the highest digit of result will * also be zero. */ void squareInternal(BigDigit[] result, const BigDigit[] x) pure nothrow { // Squaring is potentially half a multiply, plus add the squares of // the diagonal elements. assert(result.length == 2*x.length); if (x.length <= KARATSUBASQUARELIMIT) { if (x.length==1) { result[1] = multibyteMul(result[0..1], x, x[0], 0); return; } return squareSimple(result, x); } // The nice thing about squaring is that it always stays balanced BigDigit [] scratchbuff = new BigDigit[karatsubaRequiredBuffSize(x.length)]; squareKaratsuba(result, x, scratchbuff); delete scratchbuff; } import core.bitop : bsr; /// if remainder is null, only calculate quotient. void divModInternal(BigDigit [] quotient, BigDigit[] remainder, const BigDigit [] u, const BigDigit [] v) pure nothrow { assert(quotient.length == u.length - v.length + 1); assert(remainder == null || remainder.length == v.length); assert(v.length > 1); assert(u.length >= v.length); // Normalize by shifting v left just enough so that // its high-order bit is on, and shift u left the // same amount. The highest bit of u will never be set. BigDigit [] vn = new BigDigit[v.length]; BigDigit [] un = new BigDigit[u.length + 1]; // How much to left shift v, so that its MSB is set. uint s = BIGDIGITSHIFTMASK - bsr(v[$-1]); if (s!=0) { multibyteShl(vn, v, s); un[$-1] = multibyteShl(un[0..$-1], u, s); } else { vn[] = v[]; un[0..$-1] = u[]; un[$-1] = 0; } if (quotient.length=0; --i) { toHexZeroPadded(buff[x..x+8], data[i], letterCase); x+=8; if (separator) { if (i>0) buff[x] = separator; ++x; } } return buff; } /** Convert a big uint into a decimal string. * * Params: * data The biguint to be converted. Will be destroyed. * buff The destination buffer for the decimal string. Must be * large enough to store the result, including leading zeros. * Will be filled backwards, starting from buff[$-1]. * * buff.length must be >= (data.length*32)/log2(10) = 9.63296 * data.length. * Returns: * the lowest index of buff which was used. */ size_t biguintToDecimal(char [] buff, BigDigit [] data) pure nothrow { ptrdiff_t sofar = buff.length; // Might be better to divide by (10^38/2^32) since that gives 38 digits for // the price of 3 divisions and a shr; this version only gives 27 digits // for 3 divisions. while(data.length>1) { uint rem = multibyteDivAssign(data, 10_0000_0000, 0); itoaZeroPadded(buff[sofar-9 .. sofar], rem); sofar -= 9; if (data[$-1] == 0 && data.length > 1) { data.length = data.length - 1; } } itoaZeroPadded(buff[sofar-10 .. sofar], data[0]); sofar -= 10; // and strip off the leading zeros while(sofar!= buff.length-1 && buff[sofar] == '0') sofar++; return sofar; } /** Convert a decimal string into a big uint. * * Params: * data The biguint to be receive the result. Must be large enough to * store the result. * s The decimal string. May contain _ or 0..9 * * The required length for the destination buffer is slightly less than * 1 + s.length/log2(10) = 1 + s.length/3.3219. * * Returns: * the highest index of data which was used. */ int biguintFromDecimal(BigDigit [] data, const(char)[] s) pure in { assert((data.length >= 2) || (data.length == 1 && s.length == 1)); } body { import std.conv : ConvException; // Convert to base 1e19 = 10_000_000_000_000_000_000. // (this is the largest power of 10 that will fit into a long). // The length will be less than 1 + s.length/log2(10) = 1 + s.length/3.3219. // 485 bits will only just fit into 146 decimal digits. // As we convert the string, we record the number of digits we've seen in base 19: // hi is the number of digits/19, lo is the extra digits (0 to 18). // TODO: This is inefficient for very large strings (it is O(n^^2)). // We should take advantage of fast multiplication once the numbers exceed // Karatsuba size. uint lo = 0; // number of powers of digits, 0..18 uint x = 0; ulong y = 0; uint hi = 0; // number of base 1e19 digits data[0] = 0; // initially number is 0. if (data.length > 1) data[1] = 0; for (int i= (s[0]=='-' || s[0]=='+')? 1 : 0; i '9') throw new ConvException("invalid digit"); x *= 10; x += s[i] - '0'; ++lo; if (lo == 9) { y = x; x = 0; } if (lo == 18) { y *= 10_0000_0000; y += x; x = 0; } if (lo == 19) { y *= 10; y += x; x = 0; // Multiply existing number by 10^19, then add y1. if (hi>0) { data[hi] = multibyteMul(data[0..hi], data[0..hi], 1220703125*2u, 0); // 5^13*2 = 0x9184_E72A ++hi; data[hi] = multibyteMul(data[0..hi], data[0..hi], 15625*262144u, 0); // 5^6*2^18 = 0xF424_0000 ++hi; } else hi = 2; uint c = multibyteIncrementAssign!('+')(data[0..hi], cast(uint)(y&0xFFFF_FFFF)); c += multibyteIncrementAssign!('+')(data[1..hi], cast(uint)(y>>32)); if (c!=0) { data[hi]=c; ++hi; } y = 0; lo = 0; } } // Now set y = all remaining digits. if (lo>=18) { } else if (lo>=9) { for (int k=9; k>> 32); hi=2; } } else { while (lo>0) { uint c = multibyteMul(data[0..hi], data[0..hi], 10, 0); if (c!=0) { data[hi]=c; ++hi; } --lo; } uint c = multibyteIncrementAssign!('+')(data[0..hi], cast(uint)(y&0xFFFF_FFFF)); if (y > 0xFFFF_FFFFL) { c += multibyteIncrementAssign!('+')(data[1..hi], cast(uint)(y>>32)); } if (c!=0) { data[hi]=c; ++hi; } } } while (hi>1 && data[hi-1]==0) --hi; return hi; } private: // ------------------------ // These in-place functions are only for internal use; they are incompatible // with COW. // Classic 'schoolbook' multiplication. void mulSimple(BigDigit[] result, const(BigDigit) [] left, const(BigDigit)[] right) pure nothrow in { assert(result.length == left.length + right.length); assert(right.length>1); } body { result[left.length] = multibyteMul(result[0..left.length], left, right[0], 0); multibyteMultiplyAccumulate(result[1..$], left, right[1..$]); } // Classic 'schoolbook' squaring void squareSimple(BigDigit[] result, const(BigDigit) [] x) pure nothrow in { assert(result.length == 2*x.length); assert(x.length>1); } body { multibyteSquare(result, x); } // add two uints of possibly different lengths. Result must be as long // as the larger length. // Returns carry (0 or 1). uint addSimple(BigDigit[] result, const BigDigit [] left, const BigDigit [] right) pure nothrow in { assert(result.length == left.length); assert(left.length >= right.length); assert(right.length>0); } body { uint carry = multibyteAdd(result[0..right.length], left[0..right.length], right, 0); if (right.length < left.length) { result[right.length..left.length] = left[right.length .. $]; carry = multibyteIncrementAssign!('+')(result[right.length..$], carry); } return carry; } // result = left - right // returns carry (0 or 1) BigDigit subSimple(BigDigit [] result,const(BigDigit) [] left, const(BigDigit) [] right) pure nothrow in { assert(result.length == left.length); assert(left.length >= right.length); assert(right.length>0); } body { BigDigit carry = multibyteSub(result[0..right.length], left[0..right.length], right, 0); if (right.length < left.length) { result[right.length..left.length] = left[right.length .. $]; carry = multibyteIncrementAssign!('-')(result[right.length..$], carry); } //else if (result.length==left.length+1) { result[$-1] = carry; carry=0; } return carry; } /* result = result - right * Returns carry = 1 if result was less than right. */ BigDigit subAssignSimple(BigDigit [] result, const(BigDigit) [] right) pure nothrow { assert(result.length >= right.length); uint c = multibyteSub(result[0..right.length], result[0..right.length], right, 0); if (c && result.length > right.length) c = multibyteIncrementAssign!('-')(result[right.length .. $], c); return c; } /* result = result + right */ BigDigit addAssignSimple(BigDigit [] result, const(BigDigit) [] right) pure nothrow { assert(result.length >= right.length); uint c = multibyteAdd(result[0..right.length], result[0..right.length], right, 0); if (c && result.length > right.length) c = multibyteIncrementAssign!('+')(result[right.length .. $], c); return c; } /* performs result += wantSub? - right : right; */ BigDigit addOrSubAssignSimple(BigDigit [] result, const(BigDigit) [] right, bool wantSub) pure nothrow { if (wantSub) return subAssignSimple(result, right); else return addAssignSimple(result, right); } // return true if x= y.length); auto k = x.length-1; while(x[k]==0 && k>=y.length) --k; if (k>=y.length) return false; while (k>0 && x[k]==y[k]) --k; return x[k] < y[k]; } // Set result = abs(x-y), return true if result is negative(x= y.length) ? x.length : y.length); size_t minlen; bool negative; if (x.length >= y.length) { minlen = y.length; negative = less(x, y); } else { minlen = x.length; negative = !less(y, x); } const (BigDigit)[] large, small; if (negative) { large = y; small = x; } else { large = x; small = y; } BigDigit carry = multibyteSub(result[0..minlen], large[0..minlen], small[0..minlen], 0); if (x.length != y.length) { result[minlen..large.length]= large[minlen..$]; result[large.length..$] = 0; if (carry) multibyteIncrementAssign!('-')(result[minlen..$], carry); } return negative; } /* Determine how much space is required for the temporaries * when performing a Karatsuba multiplication. */ size_t karatsubaRequiredBuffSize(size_t xlen) pure nothrow @safe { return xlen <= KARATSUBALIMIT ? 0 : 2*xlen; // - KARATSUBALIMIT+2; } /* Sets result = x*y, using Karatsuba multiplication. * x must be longer or equal to y. * Valid only for balanced multiplies, where x is not shorter than y. * It is superior to schoolbook multiplication if and only if * sqrt(2)*y.length > x.length > y.length. * Karatsuba multiplication is O(n^1.59), whereas schoolbook is O(n^2) * The maximum allowable length of x and y is uint.max; but better algorithms * should be used far before that length is reached. * Params: * scratchbuff An array long enough to store all the temporaries. Will be destroyed. */ void mulKaratsuba(BigDigit [] result, const(BigDigit) [] x, const(BigDigit)[] y, BigDigit [] scratchbuff) pure nothrow { assert(x.length >= y.length); assert(result.length < uint.max, "Operands too large"); assert(result.length == x.length + y.length); if (x.length <= KARATSUBALIMIT) { return mulSimple(result, x, y); } // Must be almost square (otherwise, a schoolbook iteration is better) assert(2L * y.length * y.length > (x.length-1) * (x.length-1), "Bigint Internal Error: Asymmetric Karatsuba"); // The subtractive version of Karatsuba multiply uses the following result: // (Nx1 + x0)*(Ny1 + y0) = (N*N)*x1y1 + x0y0 + N * (x0y0 + x1y1 - mid) // where mid = (x0-x1)*(y0-y1) // requiring 3 multiplies of length N, instead of 4. // The advantage of the subtractive over the additive version is that // the mid multiply cannot exceed length N. But there are subtleties: // (x0-x1),(y0-y1) may be negative or zero. To keep it simple, we // retain all of the leading zeros in the subtractions // half length, round up. auto half = (x.length >> 1) + (x.length & 1); const(BigDigit) [] x0 = x[0 .. half]; const(BigDigit) [] x1 = x[half .. $]; const(BigDigit) [] y0 = y[0 .. half]; const(BigDigit) [] y1 = y[half .. $]; BigDigit [] mid = scratchbuff[0 .. half*2]; BigDigit [] newscratchbuff = scratchbuff[half*2 .. $]; BigDigit [] resultLow = result[0 .. 2*half]; BigDigit [] resultHigh = result[2*half .. $]; // initially use result to store temporaries BigDigit [] xdiff= result[0 .. half]; BigDigit [] ydiff = result[half .. half*2]; // First, we calculate mid, and sign of mid bool midNegative = inplaceSub(xdiff, x0, x1) ^ inplaceSub(ydiff, y0, y1); mulKaratsuba(mid, xdiff, ydiff, newscratchbuff); // Low half of result gets x0 * y0. High half gets x1 * y1 mulKaratsuba(resultLow, x0, y0, newscratchbuff); if (2L * y1.length * y1.length < x1.length * x1.length) { // an asymmetric situation has been created. // Worst case is if x:y = 1.414 : 1, then x1:y1 = 2.41 : 1. // Applying one schoolbook multiply gives us two pieces each 1.2:1 if (y1.length <= KARATSUBALIMIT) mulSimple(resultHigh, x1, y1); else { // divide x1 in two, then use schoolbook multiply on the two pieces. auto quarter = (x1.length >> 1) + (x1.length & 1); bool ysmaller = (quarter >= y1.length); mulKaratsuba(resultHigh[0..quarter+y1.length], ysmaller ? x1[0..quarter] : y1, ysmaller ? y1 : x1[0..quarter], newscratchbuff); // Save the part which will be overwritten. bool ysmaller2 = ((x1.length - quarter) >= y1.length); newscratchbuff[0..y1.length] = resultHigh[quarter..quarter + y1.length]; mulKaratsuba(resultHigh[quarter..$], ysmaller2 ? x1[quarter..$] : y1, ysmaller2 ? y1 : x1[quarter..$], newscratchbuff[y1.length..$]); resultHigh[quarter..$].addAssignSimple(newscratchbuff[0..y1.length]); } } else mulKaratsuba(resultHigh, x1, y1, newscratchbuff); /* We now have result = x0y0 + (N*N)*x1y1 Before adding or subtracting mid, we must calculate result += N * (x0y0 + x1y1) We can do this with three half-length additions. With a = x0y0, b = x1y1: aHI aLO + aHI aLO + bHI bLO + bHI bLO = R3 R2 R1 R0 R1 = aHI + bLO + aLO R2 = aHI + bLO + aHI + carry_from_R1 R3 = bHi + carry_from_R2 It might actually be quicker to do it in two full-length additions: newscratchbuff[2*half] = addSimple(newscratchbuff[0..2*half], result[0..2*half], result[2*half..$]); addAssignSimple(result[half..$], newscratchbuff[0..2*half+1]); */ BigDigit[] R1 = result[half..half*2]; BigDigit[] R2 = result[half*2..half*3]; BigDigit[] R3 = result[half*3..$]; BigDigit c1 = multibyteAdd(R2, R2, R1, 0); // c1:R2 = R2 + R1 BigDigit c2 = multibyteAdd(R1, R2, result[0..half], 0); // c2:R1 = R2 + R1 + R0 BigDigit c3 = addAssignSimple(R2, R3); // R2 = R2 + R1 + R3 if (c1+c2) multibyteIncrementAssign!('+')(result[half*2..$], c1+c2); if (c1+c3) multibyteIncrementAssign!('+')(R3, c1+c3); // And finally we subtract mid addOrSubAssignSimple(result[half..$], mid, !midNegative); } void squareKaratsuba(BigDigit [] result, const BigDigit [] x, BigDigit [] scratchbuff) pure nothrow { // See mulKaratsuba for implementation comments. // Squaring is simpler, since it never gets asymmetric. assert(result.length < uint.max, "Operands too large"); assert(result.length == 2*x.length); if (x.length <= KARATSUBASQUARELIMIT) { return squareSimple(result, x); } // half length, round up. auto half = (x.length >> 1) + (x.length & 1); const(BigDigit)[] x0 = x[0 .. half]; const(BigDigit)[] x1 = x[half .. $]; BigDigit [] mid = scratchbuff[0 .. half*2]; BigDigit [] newscratchbuff = scratchbuff[half*2 .. $]; // initially use result to store temporaries BigDigit [] xdiff= result[0 .. half]; BigDigit [] ydiff = result[half .. half*2]; // First, we calculate mid. We don't need its sign inplaceSub(xdiff, x0, x1); squareKaratsuba(mid, xdiff, newscratchbuff); // Set result = x0x0 + (N*N)*x1x1 squareKaratsuba(result[0 .. 2*half], x0, newscratchbuff); squareKaratsuba(result[2*half .. $], x1, newscratchbuff); /* result += N * (x0x0 + x1x1) Do this with three half-length additions. With a = x0x0, b = x1x1: R1 = aHI + bLO + aLO R2 = aHI + bLO + aHI + carry_from_R1 R3 = bHi + carry_from_R2 */ BigDigit[] R1 = result[half..half*2]; BigDigit[] R2 = result[half*2..half*3]; BigDigit[] R3 = result[half*3..$]; BigDigit c1 = multibyteAdd(R2, R2, R1, 0); // c1:R2 = R2 + R1 BigDigit c2 = multibyteAdd(R1, R2, result[0..half], 0); // c2:R1 = R2 + R1 + R0 BigDigit c3 = addAssignSimple(R2, R3); // R2 = R2 + R1 + R3 if (c1+c2) multibyteIncrementAssign!('+')(result[half*2..$], c1+c2); if (c1+c3) multibyteIncrementAssign!('+')(R3, c1+c3); // And finally we subtract mid, which is always positive subAssignSimple(result[half..$], mid); } /* Knuth's Algorithm D, as presented in * H.S. Warren, "Hacker's Delight", Addison-Wesley Professional (2002). * Also described in "Modern Computer Arithmetic" 0.2, Exercise 1.8.18. * Given u and v, calculates quotient = u / v, u = u % v. * v must be normalized (ie, the MSB of v must be 1). * The most significant words of quotient and u may be zero. * u[0..v.length] holds the remainder. */ void schoolbookDivMod(BigDigit [] quotient, BigDigit [] u, in BigDigit [] v) pure nothrow { assert(quotient.length == u.length - v.length); assert(v.length > 1); assert(u.length >= v.length); assert((v[$-1]&0x8000_0000)!=0); assert(u[$-1] < v[$-1]); // BUG: This code only works if BigDigit is uint. uint vhi = v[$-1]; uint vlo = v[$-2]; for (ptrdiff_t j = u.length - v.length - 1; j >= 0; j--) { // Compute estimate of quotient[j], // qhat = (three most significant words of u)/(two most sig words of v). uint qhat; if (u[j + v.length] == vhi) { // uu/vhi could exceed uint.max (it will be 0x8000_0000 or 0x8000_0001) qhat = uint.max; } else { uint ulo = u[j + v.length - 2]; version(D_InlineAsm_X86) { // Note: On DMD, this is only ~10% faster than the non-asm code. uint *p = &u[j + v.length - 1]; asm pure nothrow { mov EAX, p; mov EDX, [EAX+4]; mov EAX, [EAX]; div dword ptr [vhi]; mov qhat, EAX; mov ECX, EDX; div3by2correction: mul dword ptr [vlo]; // EDX:EAX = qhat * vlo sub EAX, ulo; sbb EDX, ECX; jbe div3by2done; mov EAX, qhat; dec EAX; mov qhat, EAX; add ECX, dword ptr [vhi]; jnc div3by2correction; div3by2done: ; } } else { // version(InlineAsm) ulong uu = (cast(ulong)(u[j + v.length]) << 32) | u[j + v.length - 1]; ulong bigqhat = uu / vhi; ulong rhat = uu - bigqhat * vhi; qhat = cast(uint)bigqhat; again: if (cast(ulong)qhat * vlo > ((rhat << 32) + ulo)) { --qhat; rhat += vhi; if (!(rhat & 0xFFFF_FFFF_0000_0000L)) goto again; } } // version(InlineAsm) } // Multiply and subtract. uint carry = multibyteMulAdd!('-')(u[j..j + v.length], v, qhat, 0); if (u[j+v.length] < carry) { // If we subtracted too much, add back --qhat; carry -= multibyteAdd(u[j..j + v.length],u[j..j + v.length], v, 0); } quotient[j] = qhat; u[j + v.length] = u[j + v.length] - carry; } } private: // TODO: Replace with a library call void itoaZeroPadded(char[] output, uint value) pure nothrow @safe @nogc { for (auto i = output.length; i--;) { if (value < 10) { output[i] = cast(char)(value + '0'); value = 0; } else { output[i] = cast(char)(value % 10 + '0'); value /= 10; } } } void toHexZeroPadded(char[] output, uint value, LetterCase letterCase = LetterCase.upper) pure nothrow @safe { ptrdiff_t x = output.length - 1; static immutable string upperHexDigits = "0123456789ABCDEF"; static immutable string lowerHexDigits = "0123456789abcdef"; for( ; x>=0; --x) { if (letterCase == LetterCase.upper) { output[x] = upperHexDigits[value & 0xF]; } else { output[x] = lowerHexDigits[value & 0xF]; } value >>= 4; } } private: // Returns the highest value of i for which left[i]!=right[i], // or 0 if left[] == right[] size_t highestDifferentDigit(const BigDigit [] left, const BigDigit [] right) pure nothrow @nogc @safe { assert(left.length == right.length); for (ptrdiff_t i = left.length - 1; i>0; --i) { if (left[i] != right[i]) return i; } return 0; } // Returns the lowest value of i for which x[i]!=0. int firstNonZeroDigit(const BigDigit [] x) pure nothrow @nogc @safe { int k = 0; while (x[k]==0) { ++k; assert(k= quotient + 1. Returns: u[0..v.length] is the remainder. u[v.length..$] is corrupted. Implements algorithm 1.8 from MCA. This algorithm has an annoying special case. After the first recursion, the highest bit of the quotient may be set. This means that in the second recursive call, the 'in' contract would be violated. (This happens only when the top quarter of u is equal to the top half of v. A base 10 equivalent example of this situation is 5517/56; the first step gives 55/5 = 11). To maintain the in contract, we pad a zero to the top of both u and the quotient. 'mayOverflow' indicates that that the special case has occurred. (In MCA, a different strategy is used: the in contract is weakened, and schoolbookDivMod is more general: it allows the high bit of u to be set). See also: - C. Burkinel and J. Ziegler, "Fast Recursive Division", MPI-I-98-1-022, Max-Planck Institute fuer Informatik, (Oct 1998). */ void recursiveDivMod(BigDigit[] quotient, BigDigit[] u, const(BigDigit)[] v, BigDigit[] scratch, bool mayOverflow = false) pure nothrow in { // v must be normalized assert(v.length > 1); assert((v[$ - 1] & 0x8000_0000) != 0); assert(!(u[$ - 1] & 0x8000_0000)); assert(quotient.length == u.length - v.length); if (mayOverflow) { assert(u[$-1] == 0); assert(u[$-2] & 0x8000_0000); } // Must be symmetric. Use block schoolbook division if not. assert((mayOverflow ? u.length-1 : u.length) <= 2 * v.length); assert((mayOverflow ? u.length-1 : u.length) >= v.length); assert(scratch.length >= quotient.length + (mayOverflow ? 0 : 1)); } body { if (quotient.length < FASTDIVLIMIT) { return schoolbookDivMod(quotient, u, v); } // Split quotient into two halves, but keep padding in the top half auto k = (mayOverflow ? quotient.length - 1 : quotient.length) >> 1; // RECURSION 1: Calculate the high half of the quotient // Note that if u and quotient were padded, they remain padded during // this call, so in contract is satisfied. recursiveDivMod(quotient[k .. $], u[2 * k .. $], v[k .. $], scratch, mayOverflow); // quotient[k..$] is our guess at the high quotient. // u[2*k.. 2.*k + v.length - k = k + v.length] is the high part of the // first remainder. u[0..2*k] is the low part. // Calculate the full first remainder to be // remainder - highQuotient * lowDivisor // reducing highQuotient until the remainder is positive. // The low part of the remainder, u[0..k], cannot be altered by this. adjustRemainder(quotient[k .. $], u[k .. k + v.length], v, k, scratch[0 .. quotient.length], mayOverflow); // RECURSION 2: Calculate the low half of the quotient // The full first remainder is now in u[0..k + v.length]. if (u[k + v.length - 1] & 0x8000_0000) { // Special case. The high quotient is 0x1_00...000 or 0x1_00...001. // This means we need an extra quotient word for the next recursion. // We need to restore the invariant for the recursive calls. // We do this by padding both u and quotient. Extending u is trivial, // because the higher words will not be used again. But for the // quotient, we're clobbering the low word of the high quotient, // so we need save it, and add it back in after the recursive call. auto clobberedQuotient = quotient[k]; u[k+v.length] = 0; recursiveDivMod(quotient[0 .. k+1], u[k .. k + v.length+1], v[k .. $], scratch, true); adjustRemainder(quotient[0 .. k+1], u[0 .. v.length], v, k, scratch[0 .. 2 * k+1], true); // Now add the quotient word that got clobbered earlier. multibyteIncrementAssign!('+')(quotient[k..$], clobberedQuotient); } else { // The special case has NOT happened. recursiveDivMod(quotient[0 .. k], u[k .. k + v.length], v[k .. $], scratch, false); // high remainder is in u[k..k+(v.length-k)] == u[k .. v.length] adjustRemainder(quotient[0 .. k], u[0 .. v.length], v, k, scratch[0 .. 2 * k]); } } // rem -= quot * v[0..k]. // If would make rem negative, decrease quot until rem is >=0. // Needs (quot.length * k) scratch space to store the result of the multiply. void adjustRemainder(BigDigit[] quot, BigDigit[] rem, const(BigDigit)[] v, ptrdiff_t k, BigDigit[] scratch, bool mayOverflow = false) pure nothrow { assert(rem.length == v.length); mulInternal(scratch, quot, v[0 .. k]); uint carry = 0; if (mayOverflow) carry = scratch[$-1] + subAssignSimple(rem, scratch[0..$-1]); else carry = subAssignSimple(rem, scratch); while(carry) { multibyteIncrementAssign!('-')(quot, 1); // quot-- carry -= multibyteAdd(rem, rem, v, 0); } } // Cope with unbalanced division by performing block schoolbook division. void blockDivMod(BigDigit [] quotient, BigDigit [] u, in BigDigit [] v) pure nothrow { assert(quotient.length == u.length - v.length); assert(v.length > 1); assert(u.length >= v.length); assert((v[$-1] & 0x8000_0000)!=0); assert((u[$-1] & 0x8000_0000)==0); BigDigit [] scratch = new BigDigit[v.length + 1]; // Perform block schoolbook division, with 'v.length' blocks. auto m = u.length - v.length; while (m > v.length) { bool mayOverflow = (u[m + v.length -1 ] & 0x8000_0000)!=0; BigDigit saveq; if (mayOverflow) { u[m + v.length] = 0; saveq = quotient[m]; } recursiveDivMod(quotient[m-v.length..m + (mayOverflow? 1: 0)], u[m - v.length..m + v.length + (mayOverflow? 1: 0)], v, scratch, mayOverflow); if (mayOverflow) { assert(quotient[m] == 0); quotient[m] = saveq; } m -= v.length; } recursiveDivMod(quotient[0..m], u[0..m + v.length], v, scratch); delete scratch; } unittest { import core.stdc.stdio; void printBiguint(const uint [] data) { char [] buff = biguintToHex(new char[data.length*9], data, '_'); printf("%.*s\n", buff.length, buff.ptr); } void printDecimalBigUint(BigUint data) { auto str = data.toDecimalString(0); printf("%.*s\n", str.length, str.ptr); } uint [] a, b; a = new uint[43]; b = new uint[179]; for (int i=0; i$0 * GAMMA = Γ * INTEGRAL = ∫ * INTEGRATE = $(BIG ∫$(SMALL $1)$2) * POWER = $1$2 * BIGSUM = $(BIG Σ $2$(SMALL $1)) * CHOOSE = $(BIG () $(SMALL $1)$(SMALL $2) $(BIG )) * TABLE_SV = * * $0
Special Values
* SVH = $(TR $(TH $1) $(TH $2)) * SV = $(TR $(TD $1) $(TD $2)) */ module std.internal.math.errorfunction; import std.math; pure: nothrow: @safe: @nogc: private { immutable real EXP_2 = 0.13533528323661269189L; /* exp(-2) */ enum real SQRT2PI = 2.50662827463100050242E0L; // sqrt(2pi) enum real MAXLOG = 0x1.62e42fefa39ef358p+13L; // log(real.max) enum real MINLOG = -0x1.6436716d5406e6d8p+13L; // log(real.min*real.epsilon) = log(smallest denormal) } T rationalPoly(T)(T x, const(T) [] numerator, const(T) [] denominator) pure nothrow { return poly(x, numerator)/poly(x, denominator); } private { /* erfc(x) = exp(-x^2) P(1/x)/Q(1/x) 1/8 <= 1/x <= 1 Peak relative error 5.8e-21 */ immutable real [10] P = [ -0x1.30dfa809b3cc6676p-17, 0x1.38637cd0913c0288p+18, 0x1.2f015e047b4476bp+22, 0x1.24726f46aa9ab08p+25, 0x1.64b13c6395dc9c26p+27, 0x1.294c93046ad55b5p+29, 0x1.5962a82f92576dap+30, 0x1.11a709299faba04ap+31, 0x1.11028065b087be46p+31, 0x1.0d8ef40735b097ep+30 ]; immutable real [11] Q = [ 0x1.14d8e2a72dec49f4p+19, 0x1.0c880ff467626e1p+23, 0x1.04417ef060b58996p+26, 0x1.404e61ba86df4ebap+28, 0x1.0f81887bc82b873ap+30, 0x1.4552a5e39fb49322p+31, 0x1.11779a0ceb2a01cep+32, 0x1.3544dd691b5b1d5cp+32, 0x1.a91781f12251f02ep+31, 0x1.0d8ef3da605a1c86p+30, 1.0 ]; /* erfc(x) = exp(-x^2) 1/x R(1/x^2) / S(1/x^2) 1/128 <= 1/x < 1/8 Peak relative error 1.9e-21 */ immutable real [5] R = [ 0x1.b9f6d8b78e22459ep-6, 0x1.1b84686b0a4ea43ap-1, 0x1.b8f6aebe96000c2ap+1, 0x1.cb1dbedac27c8ec2p+2, 0x1.cf885f8f572a4c14p+1 ]; immutable real [6] S = [ 0x1.87ae3cae5f65eb5ep-5, 0x1.01616f266f306d08p+0, 0x1.a4abe0411eed6c22p+2, 0x1.eac9ce3da600abaap+3, 0x1.5752a9ac2faebbccp+3, 1.0 ]; /* erf(x) = x P(x^2)/Q(x^2) 0 <= x <= 1 Peak relative error 7.6e-23 */ immutable real [7] T = [ 0x1.0da01654d757888cp+20, 0x1.2eb7497bc8b4f4acp+17, 0x1.79078c19530f72a8p+15, 0x1.4eaf2126c0b2c23p+11, 0x1.1f2ea81c9d272a2ep+8, 0x1.59ca6e2d866e625p+2, 0x1.c188e0b67435faf4p-4 ]; immutable real [7] U = [ 0x1.dde6025c395ae34ep+19, 0x1.c4bc8b6235df35aap+18, 0x1.8465900e88b6903ap+16, 0x1.855877093959ffdp+13, 0x1.e5c44395625ee358p+9, 0x1.6a0fed103f1c68a6p+5, 1.0 ]; } /** * Complementary error function * * erfc(x) = 1 - erf(x), and has high relative accuracy for * values of x far from zero. (For values near zero, use erf(x)). * * 1 - erf(x) = 2/ $(SQRT)(π) * $(INTEGRAL x, $(INFINITY)) exp( - $(POWER t, 2)) dt * * * For small x, erfc(x) = 1 - erf(x); otherwise rational * approximations are computed. * * A special function expx2(x) is used to suppress error amplification * in computing exp(-x^2). */ real erfc(real a) { if (a == real.infinity) return 0.0; if (a == -real.infinity) return 2.0; real x; if (a < 0.0L ) x = -a; else x = a; if (x < 1.0) return 1.0 - erf(a); real z = -a * a; if (z < -MAXLOG){ // mtherr( "erfcl", UNDERFLOW ); if (a < 0) return 2.0; else return 0.0; } /* Compute z = exp(z). */ z = expx2(a, -1); real y = 1.0/x; if( x < 8.0 ) y = z * rationalPoly(y, P, Q); else y = z * y * rationalPoly(y * y, R, S); if (a < 0.0L) y = 2.0L - y; if (y == 0.0) { // mtherr( "erfcl", UNDERFLOW ); if (a < 0) return 2.0; else return 0.0; } return y; } private { /* Exponentially scaled erfc function exp(x^2) erfc(x) valid for x > 1. Use with normalDistribution and expx2. */ real erfce(real x) { real y = 1.0/x; if (x < 8.0) { return rationalPoly( y, P, Q); } else { return y * rationalPoly(y*y, R, S); } } } /** * Error function * * The integral is * * erf(x) = 2/ $(SQRT)(π) * $(INTEGRAL 0, x) exp( - $(POWER t, 2)) dt * * The magnitude of x is limited to about 106.56 for IEEE 80-bit * arithmetic; 1 or -1 is returned outside this range. * * For 0 <= |x| < 1, a rational polynomials are used; otherwise * erf(x) = 1 - erfc(x). * * ACCURACY: * Relative error: * arithmetic domain # trials peak rms * IEEE 0,1 50000 2.0e-19 5.7e-20 */ real erf(real x) { if (x == 0.0) return x; // deal with negative zero if (x == -real.infinity) return -1.0; if (x == real.infinity) return 1.0; if (abs(x) > 1.0L) return 1.0L - erfc(x); real z = x * x; return x * rationalPoly(z, T, U); } unittest { // High resolution test points. enum real erfc0_250 = 0.723663330078125 + 1.0279753638067014931732235184287934646022E-5; enum real erfc0_375 = 0.5958709716796875 + 1.2118885490201676174914080878232469565953E-5; enum real erfc0_500 = 0.4794921875 + 7.9346869534623172533461080354712635484242E-6; enum real erfc0_625 = 0.3767547607421875 + 4.3570693945275513594941232097252997287766E-6; enum real erfc0_750 = 0.2888336181640625 + 1.0748182422368401062165408589222625794046E-5; enum real erfc0_875 = 0.215911865234375 + 1.3073705765341685464282101150637224028267E-5; enum real erfc1_000 = 0.15728759765625 + 1.1609394035130658779364917390740703933002E-5; enum real erfc1_125 = 0.111602783203125 + 8.9850951672359304215530728365232161564636E-6; enum real erf0_875 = (1-0.215911865234375) - 1.3073705765341685464282101150637224028267E-5; static bool isNaNWithPayload(real x, ulong payload) @safe pure nothrow @nogc { return isNaN(x) && getNaNPayload(x) == payload; } assert(feqrel(erfc(0.250L), erfc0_250 )>=real.mant_dig-1); assert(feqrel(erfc(0.375L), erfc0_375 )>=real.mant_dig-0); assert(feqrel(erfc(0.500L), erfc0_500 )>=real.mant_dig-2); assert(feqrel(erfc(0.625L), erfc0_625 )>=real.mant_dig-1); assert(feqrel(erfc(0.750L), erfc0_750 )>=real.mant_dig-1); assert(feqrel(erfc(0.875L), erfc0_875 )>=real.mant_dig-4); assert(feqrel(erfc(1.000L), erfc1_000 )>=real.mant_dig-2); assert(feqrel(erfc(1.125L), erfc1_125 )>=real.mant_dig-2); assert(feqrel(erf(0.875L), erf0_875 )>=real.mant_dig-1); // The DMC implementation of erfc() fails this next test (just) assert(feqrel(erfc(4.1L),0.67000276540848983727e-8L)>=real.mant_dig-5); assert(isIdentical(erf(0.0),0.0)); assert(isIdentical(erf(-0.0),-0.0)); assert(erf(real.infinity) == 1.0); assert(erf(-real.infinity) == -1.0); assert(isNaNWithPayload(erf(NaN(0xDEF)), 0xDEF)); assert(isNaNWithPayload(erfc(NaN(0xDEF)), 0xDEF)); assert(isIdentical(erfc(real.infinity),0.0)); assert(erfc(-real.infinity) == 2.0); assert(erfc(0) == 1.0); } /* * Exponential of squared argument * * Computes y = exp(x*x) while suppressing error amplification * that would ordinarily arise from the inexactness of the * exponential argument x*x. * * If sign < 0, the result is inverted; i.e., y = exp(-x*x) . * * ACCURACY: * Relative error: * arithmetic domain # trials peak rms * IEEE -106.566, 106.566 10^5 1.6e-19 4.4e-20 */ real expx2(real x, int sign) { /* Cephes Math Library Release 2.9: June, 2000 Copyright 2000 by Stephen L. Moshier */ const real M = 32768.0; const real MINV = 3.0517578125e-5L; x = abs(x); if (sign < 0) x = -x; /* Represent x as an exact multiple of M plus a residual. M is a power of 2 chosen so that exp(m * m) does not overflow or underflow and so that |x - m| is small. */ real m = MINV * floor(M * x + 0.5L); real f = x - m; /* x^2 = m^2 + 2mf + f^2 */ real u = m * m; real u1 = 2 * m * f + f * f; if (sign < 0) { u = -u; u1 = -u1; } if ((u+u1) > MAXLOG) return real.infinity; /* u is exact, u1 is small. */ return exp(u) * exp(u1); } /* Computes the normal distribution function. The normal (or Gaussian, or bell-shaped) distribution is defined as: normalDist(x) = 1/$(SQRT) π $(INTEGRAL -$(INFINITY), x) exp( - $(POWER t, 2)/2) dt = 0.5 + 0.5 * erf(x/sqrt(2)) = 0.5 * erfc(- x/sqrt(2)) To maintain accuracy at high values of x, use normalDistribution(x) = 1 - normalDistribution(-x). Accuracy: Within a few bits of machine resolution over the entire range. References: $(LINK http://www.netlib.org/cephes/ldoubdoc.html), G. Marsaglia, "Evaluating the Normal Distribution", Journal of Statistical Software 11, (July 2004). */ real normalDistributionImpl(real a) { real x = a * SQRT1_2; real z = abs(x); if( z < 1.0 ) return 0.5L + 0.5L * erf(x); else { real y = 0.5L * erfce(z); /* Multiply by exp(-x^2 / 2) */ z = expx2(a, -1); y = y * sqrt(z); if( x > 0.0L ) y = 1.0L - y; return y; } } unittest { assert(fabs(normalDistributionImpl(1L) - (0.841344746068543))< 0.0000000000000005); assert(isIdentical(normalDistributionImpl(NaN(0x325)), NaN(0x325))); } /* * Inverse of Normal distribution function * * Returns the argument, x, for which the area under the * Normal probability density function (integrated from * minus infinity to x) is equal to p. * * For small arguments 0 < p < exp(-2), the program computes * z = sqrt( -2 log(p) ); then the approximation is * x = z - log(z)/z - (1/z) P(1/z) / Q(1/z) . * For larger arguments, x/sqrt(2 pi) = w + w^3 R(w^2)/S(w^2)) , * where w = p - 0.5 . */ real normalDistributionInvImpl(real p) in { assert(p>=0.0L && p<=1.0L, "Domain error"); } body { static immutable real[8] P0 = [ -0x1.758f4d969484bfdcp-7, 0x1.53cee17a59259dd2p-3, -0x1.ea01e4400a9427a2p-1, 0x1.61f7504a0105341ap+1, -0x1.09475a594d0399f6p+2, 0x1.7c59e7a0df99e3e2p+1, -0x1.87a81da52edcdf14p-1, 0x1.1fb149fd3f83600cp-7 ]; static immutable real[8] Q0 = [ -0x1.64b92ae791e64bb2p-7, 0x1.7585c7d597298286p-3, -0x1.40011be4f7591ce6p+0, 0x1.1fc067d8430a425ep+2, -0x1.21008ffb1e7ccdf2p+3, 0x1.3d1581cf9bc12fccp+3, -0x1.53723a89fd8f083cp+2, 1.0 ]; static immutable real[10] P1 = [ 0x1.20ceea49ea142f12p-13, 0x1.cbe8a7267aea80bp-7, 0x1.79fea765aa787c48p-2, 0x1.d1f59faa1f4c4864p+1, 0x1.1c22e426a013bb96p+4, 0x1.a8675a0c51ef3202p+5, 0x1.75782c4f83614164p+6, 0x1.7a2f3d90948f1666p+6, 0x1.5cd116ee4c088c3ap+5, 0x1.1361e3eb6e3cc20ap+2 ]; static immutable real[10] Q1 = [ 0x1.3a4ce1406cea98fap-13, 0x1.f45332623335cda2p-7, 0x1.98f28bbd4b98db1p-2, 0x1.ec3b24f9c698091cp+1, 0x1.1cc56ecda7cf58e4p+4, 0x1.92c6f7376bf8c058p+5, 0x1.4154c25aa47519b4p+6, 0x1.1b321d3b927849eap+6, 0x1.403a5f5a4ce7b202p+4, 1.0 ]; static immutable real[8] P2 = [ 0x1.8c124a850116a6d8p-21, 0x1.534abda3c2fb90bap-13, 0x1.29a055ec93a4718cp-7, 0x1.6468e98aad6dd474p-3, 0x1.3dab2ef4c67a601cp+0, 0x1.e1fb3a1e70c67464p+1, 0x1.b6cce8035ff57b02p+2, 0x1.9f4c9e749ff35f62p+1 ]; static immutable real[8] Q2 = [ 0x1.af03f4fc0655e006p-21, 0x1.713192048d11fb2p-13, 0x1.4357e5bbf5fef536p-7, 0x1.7fdac8749985d43cp-3, 0x1.4a080c813a2d8e84p+0, 0x1.c3a4b423cdb41bdap+1, 0x1.8160694e24b5557ap+2, 1.0 ]; static immutable real[8] P3 = [ -0x1.55da447ae3806168p-34, -0x1.145635641f8778a6p-24, -0x1.abf46d6b48040128p-17, -0x1.7da550945da790fcp-11, -0x1.aa0b2a31157775fap-8, 0x1.b11d97522eed26bcp-3, 0x1.1106d22f9ae89238p+1, 0x1.029a358e1e630f64p+1 ]; static immutable real[8] Q3 = [ -0x1.74022dd5523e6f84p-34, -0x1.2cb60d61e29ee836p-24, -0x1.d19e6ec03a85e556p-17, -0x1.9ea2a7b4422f6502p-11, -0x1.c54b1e852f107162p-8, 0x1.e05268dd3c07989ep-3, 0x1.239c6aff14afbf82p+1, 1.0 ]; if(p<=0.0L || p>=1.0L) { if (p == 0.0L) return -real.infinity; if( p == 1.0L ) return real.infinity; return real.nan; // domain error } int code = 1; real y = p; if( y > (1.0L - EXP_2) ) { y = 1.0L - y; code = 0; } real x, z, y2, x0, x1; if ( y > EXP_2 ) { y = y - 0.5L; y2 = y * y; x = y + y * (y2 * rationalPoly( y2, P0, Q0)); return x * SQRT2PI; } x = sqrt( -2.0L * log(y) ); x0 = x - log(x)/x; z = 1.0L/x; if ( x < 8.0L ) { x1 = z * rationalPoly( z, P1, Q1); } else if( x < 32.0L ) { x1 = z * rationalPoly( z, P2, Q2); } else { x1 = z * rationalPoly( z, P3, Q3); } x = x0 - x1; if ( code != 0 ) { x = -x; } return x; } unittest { // TODO: Use verified test points. // The values below are from Excel 2003. assert(fabs(normalDistributionInvImpl(0.001) - (-3.09023230616779))< 0.00000000000005); assert(fabs(normalDistributionInvImpl(1e-50) - (-14.9333375347885))< 0.00000000000005); assert(feqrel(normalDistributionInvImpl(0.999), -normalDistributionInvImpl(0.001)) > real.mant_dig-6); // Excel 2003 gets all the following values wrong! assert(normalDistributionInvImpl(0.0) == -real.infinity); assert(normalDistributionInvImpl(1.0) == real.infinity); assert(normalDistributionInvImpl(0.5) == 0); // (Excel 2003 returns norminv(p) = -30 for all p < 1e-200). // The value tested here is the one the function returned in Jan 2006. real unknown1 = normalDistributionInvImpl(1e-250L); assert( fabs(unknown1 -(-33.79958617269L) ) < 0.00000005); } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/processinit.d0000664000175000017500000000111112776215007022223 0ustar kaikai// Written in the D programming language. /++ The only purpose of this module is to do the static construction for std.process in order to eliminate cyclic construction errors. Copyright: Copyright 2011 - License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jonathan M Davis and Kato Shoichi Source: $(PHOBOSSRC std/internal/_processinit.d) +/ module std.internal.processinit; version(OSX) { extern(C) void std_process_shared_static_this(); shared static this() { std_process_shared_static_this(); } } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/unicode_decomp.d0000664000175000017500000131075512776215007022660 0ustar kaikaimodule std.internal.unicode_decomp; import std.internal.unicode_tables; @safe pure nothrow @nogc: static if(size_t.sizeof == 8) { //22656 bytes enum compatMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)([ 0x0, 0x20, 0x2a0], [ 0x100, 0xa00, 0x21c0], [ 0x402030202020100, 0x706020202020205, 0x802020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x3000200010000, 0x7000600050004, 0xa000900080000, 0xc000b, 0xf000e000d0000, 0x11001000000000, 0x15001400130012, 0x19001800170016, 0x1b001a00000000, 0x0, 0x1c, 0x1e0000001d0000, 0x1f00000000, 0x0, 0x0, 0x0, 0x0, 0x2100200000, 0x2200000000, 0x2400230000, 0x0, 0x2500000000, 0x2700000026, 0x2800000000, 0x2900000000, 0x2a00000000, 0x2b00000000, 0x2c0000, 0x2e002d0000, 0x3100300000002f, 0x330032, 0x340000, 0x35000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3800370036, 0x0, 0x0, 0x0, 0x3b003a00390000, 0x3d003c, 0x410040003f003e, 0x45004400430042, 0x49004800470046, 0x4d004c004b004a, 0x510050004f004e, 0x530052, 0x57005600550054, 0x5a00590058, 0x5e005d005c005b, 0x6100000060005f, 0x620000, 0x0, 0x63000000000000, 0x67006600650064, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x69000000000068, 0x6a00000000, 0x0, 0x0, 0x6b000000000000, 0x0, 0x6c000000000000, 0x0, 0x0, 0x6e00000000006d, 0x7200710070006f, 0x7500740073, 0x79007800770076, 0x7d007c007b007a, 0x80007f007e0000, 0x81, 0x85008400830082, 0x89008800870086, 0x8d008c008b008a, 0x910090008f008e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92000000000000, 0x93000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x97009600950094, 0x9b009a00990098, 0x9f009e009d009c, 0xa200a100a0, 0xa600a500a400a3, 0xaa00a900a800a7, 0xae00ad00ac00ab, 0xb200b100b000af, 0xb600b500b400b3, 0xba00b900b800b7, 0xbe00bd00bc00bb, 0xc200c100c000bf, 0xc600c500c400c3, 0xca00c900c800c7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcc00cb, 0xcd0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf00ce00000000, 0xd100d00000, 0x0, 0x0, 0x0, 0x0, 0xd500d400d300d2, 0xd900d800d700d6, 0xdd00dc00db00da, 0xdf00d300d200de, 0xe200e100e000d5, 0xe500e400e300d9, 0xe900e800e700e6, 0xed00ec00eb00ea, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf100f000ef00ee, 0xf300f2, 0x0, 0x0, 0x0, 0x0, 0xf700f600f500f4, 0xf8, 0xfb00fa00f9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff00fe00fd00fc, 0x103010201010100, 0x107010601050104, 0x10b010a01090108, 0x10c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x69200000015, 0x9000000000000, 0x30f034300000000, 0x11b20003, 0x78703140048, 0x49403c603ce, 0x58605730570056d, 0x5f8000005b005a6, 0x6580631062e062b, 0x6f906ea06e706e4, 0x7a907a6078f0000, 0x7e307bf07ac, 0x8b708b408b10000, 0x95f08cb, 0x9c209af09ac09a9, 0xa47000009ec09e2, 0xab30a8c0a890a86, 0xb550b490b460b43, 0xc5e0c5b0c410000, 0xc980c740c61, 0xd6e0d6b0d680000, 0xe1b00000e0c0d82, 0x9c8058c09c50589, 0xa3b05ec0a0a05ce, 0xa4105f20a3e05ef, 0xa6e061a0a4405f5, 0xaa2064700000000, 0xab006550aad0652, 0xab9065e0ad00675, 0xb0106a00afb069a, 0xb0a06a90b0406a3, 0xb1606ba, 0xb4f06f00b4c06ed, 0xb6b070f0b5206f3, 0xb3706d8000006f6, 0xbae072e0b730717, 0x7500bcc07430000, 0x7400bcf07460bd9, 0x78c000000000bc9, 0x7950c4d079b0c3e, 0xed70c47, 0xc8e07d90c8307ce, 0xca207ed, 0xd1d08580d070842, 0xd2b086c0d0d0848, 0xd49088a0d320873, 0xd5d08a60d380879, 0xd54089d, 0xd7808c10d7108ba, 0xd9808e10d7f08c8, 0xdc4090d0d9b08e4, 0xe0f09620de9093f, 0x97f0e290979096e, 0x8400614060d0e2f, 0xcae07f9, 0x0, 0x0, 0x8f0000000000000, 0xda7, 0x0, 0x0, 0x0, 0x0, 0x7360a670613060c, 0x78307800bb9073d, 0x70309f305b70c32, 0x8e70ca507f00b5f, 0x8d20d8d08d60d9e, 0x8ce0d9108da0d89, 0x9e505a900000d85, 0xe630e5a09de05a2, 0xb0706a600000000, 0xccc08170ba80728, 0xecc0e7b0ccf081a, 0xa64061006090b76, 0xaf80697, 0x9ef05b30c3b0789, 0xe680e5d0e600e57, 0x9f905bd09f605ba, 0xabf06640abc0661, 0xb6507090b620706, 0xcab07f60ca807f3, 0xd13084e0d10084b, 0xda408ed0da108ea, 0xd5a08a30d460887, 0xb1f06c300000000, 0x0, 0x9db059f00000000, 0xc9b07e60ac9066e, 0xc9107dc0c7b07c6, 0xe1509680c9407df, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa11073e0e9a0b0d, 0xde10eb80eb60eb4, 0x695, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4b00240012000f, 0x270006, 0xb4108400a280e96, 0xecf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b00000004001a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xed5, 0x5400000000, 0x54600000000, 0x0, 0x7410ee8001c0003, 0xfb40f630f43, 0x103c101600000fed, 0x1185, 0x0, 0x0, 0x0, 0x0, 0x0, 0x101f0fbd00000000, 0x1175111910f5108f, 0x1213, 0x0, 0x0, 0x0, 0x0, 0x0, 0x120c117e00000000, 0x124b120311d5, 0x10161011116e10ea, 0x11ee123c101f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11f811f011ae, 0x10f00fad, 0x100d0000, 0x0, 0x12ad000012b612b0, 0x12a4000000000000, 0x0, 0x12d712c212ce, 0x0, 0x0, 0x12c80000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x130a0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12ef000012f812f2, 0x132d000000000000, 0x0, 0x131b13041310, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1333133000000000, 0x0, 0x0, 0x12fb12b90000, 0x0, 0x0, 0x0, 0x12ec12aa12e912a7, 0x12f512b300000000, 0x1339133600000000, 0x130112bf12fe12bc, 0x130712c500000000, 0x131512d1130d12cb, 0x133f133c00000000, 0x131812d4132a12e6, 0x132112dd131e12da, 0x132412e0, 0x132712e3, 0x0, 0x0, 0x1342000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13e913e600000000, 0x17ca13ec178f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x185b179213ef0000, 0x1811, 0x0, 0x18520000186d, 0x0, 0x0, 0x0, 0x186a000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18820000, 0x0, 0x188b0000, 0x188e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1879187618731870, 0x18881885187f187c, 0x0, 0x0, 0x189a000000000000, 0x189d, 0x0, 0x0, 0x0, 0x1897000018941891, 0x0, 0x0, 0x0, 0x0, 0x18ac000000000000, 0x18af00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18a618a318a00000, 0x18a900000000, 0x0, 0x0, 0x18b80000000018bb, 0x18be, 0x0, 0x0, 0x0, 0x18b518b2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18c1, 0x0, 0x0, 0x0, 0x0, 0x18ca18c400000000, 0x18c7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18cd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18d0, 0x18da000000000000, 0x18d618d3000018dd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18e618e000000000, 0x18e3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18e900000000, 0x18f318ef18ec, 0x0, 0x0, 0x0, 0x0, 0x18f6000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18ff000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18fc18f9, 0x0, 0x0, 0x0, 0x1902, 0x0, 0x0, 0x0, 0x0, 0x1907000000000000, 0x0, 0x0, 0x190a0000, 0x190d00000000, 0x1910000000000000, 0x0, 0x1913, 0x0, 0x0, 0x19040000, 0x0, 0x1916000000000000, 0x1931193519190000, 0x1938193c, 0x0, 0x191c0000, 0x0, 0x0, 0x0, 0x1922000000000000, 0x0, 0x0, 0x19250000, 0x192800000000, 0x192b000000000000, 0x0, 0x192e, 0x0, 0x0, 0x191f0000, 0x0, 0x0, 0x193f00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1942, 0x0, 0x1a3800000000, 0x1a3e00001a3b, 0x1a4400001a41, 0x1a4700000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a4a000000000000, 0x1a4d0000, 0x1a5600001a531a50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5d50e550568, 0x6870e75062905e6, 0x71a060706cf06ac, 0x77e07230734, 0x82c06af0e7e07a4, 0x6920770056b088d, 0x9371a590e840e82, 0xe8e0e8c0a7d0a2e, 0xb79000006020e90, 0xe8807870e7105d3, 0xba30cd31a5d1a5b, 0x86a0ea41a610a24, 0x10ee10ec10ea1a63, 0xa110ae0123e123c, 0x10ec10ea086a0a24, 0x123e123c11f0, 0x0, 0x0, 0x0, 0x1313, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe86000000000000, 0xe900e660e8a09a0, 0xe980e940e920ad9, 0x1a650ea00e9e0e9c, 0xed31a670ea20ed1, 0xeac0eaa0ea60ea8, 0xeba0eb20eb00eae, 0xec00ebe0e790ebc, 0x6110ec40ec21a5f, 0x116e0eca0ec80ec6, 0xa1305da0a0705cb, 0xa1905e00a1605dd, 0xa6b06170a4a05fb, 0xa7a06260a71061d, 0xa7706230a740620, 0xaa9064e0aa5064a, 0xad6067b0ad30678, 0xaef06840acc0671, 0xb1906bd0afe069d, 0xb1c06c00b2206c6, 0xb2806cc0b2506c9, 0xb5806fc0b6e0712, 0xbab072b0ba50725, 0xbd207490bb10731, 0xbdf07560bd5074c, 0xc1207720bdc0753, 0xc1807780c150775, 0xc4a07980c440792, 0xc50079e0c5307a1, 0xc7f07ca0c7707c2, 0xc8a07d50c8607d1, 0xcef08380cec0835, 0xd1608510d0a0845, 0xd20085b0d190854, 0xd3f08800d350876, 0xd3b087c0d2e086f, 0xd4e089a0d420883, 0xd6308ac0d5708a0, 0xdc1090a0d6008a9, 0xdc709100dca0913, 0xd7b08c40d7408bd, 0xdde09270ddb0924, 0xde6093c0de30939, 0xdec09420def0945, 0xe0109540df50948, 0xe18096b0e040957, 0xe3509850e2c097c, 0xd510b2b0e380988, 0xd3509a60e210df2, 0x0, 0x9e905ad09fc05c0, 0x9b2057609b6057a, 0x9ba057e09be0582, 0x9cf059309ff05c3, 0x9d7059b09cb058f, 0xa0305c709d30597, 0xab6065b0ac20667, 0xa9306380a9f0644, 0xa9b06400a8f0634, 0xac5066a0a97063c, 0xb68070c0b5c0700, 0xc9f07ea0cc50810, 0xc6407af0c6807b3, 0xc6c07b70c7007bb, 0xcb508000cc80813, 0xcbd08080cb107fc, 0xcc1080c0cb90804, 0xd9508de0dbe0907, 0xdaa08f30dae08f7, 0xdb208fb0db608ff, 0xe09095c0dba0903, 0xe1e09710e240974, 0xe120965, 0x0, 0x10c1109f10be109c, 0x10d310b110ca10a8, 0xf160ef40f130ef1, 0xf280f060f1f0efd, 0x110610fb110310f8, 0x110a10ff, 0xf540f490f510f46, 0xf580f4d, 0x1145112311421120, 0x11571135114e112c, 0xf8b0f690f880f66, 0xf9d0f7b0f940f72, 0x119f1190119c118d, 0x11a7119811a31194, 0xfd20fc30fcf0fc0, 0xfda0fcb0fd60fc7, 0x11e611db11e311d8, 0x11ea11df, 0xffe0ff30ffb0ff0, 0x10020ff7, 0x122d121e122a121b, 0x1235122612311222, 0x1025000010220000, 0x102d000010290000, 0x1277125512741252, 0x128912671280125e, 0x106410421061103f, 0x10761054106d104b, 0x10f510f2108f1088, 0x1175117211191112, 0x1203120011d511d2, 0x124b1244, 0x10c510a310dc10ba, 0x10d710b510ce10ac, 0xf1a0ef80f310f0f, 0xf2c0f0a0f230f01, 0x114911271160113e, 0x115b113911521130, 0xf8f0f6d0fa60f84, 0xfa10f7f0f980f76, 0x127b125912921270, 0x128d126b12841262, 0x10681046107f105d, 0x107a10581071104f, 0x10e7108b10961099, 0x10e310e000001092, 0xee80ee50eeb0eee, 0x2a1170002a0f35, 0x116b111500200051, 0x116711640000111c, 0xf630f600f430f40, 0x350031002d0faa, 0x118511811178117b, 0x118911ab00000000, 0xfb40fb10fb70fba, 0x440040003c0000, 0x1213120f12061209, 0x1217123911f511f2, 0x101610131019101c, 0x995001c0018100a, 0x129d124700000000, 0x129912960000124e, 0x103c10390fed0fea, 0x3900031083, 0x1000100010001, 0x1000100010001, 0x100010001, 0x0, 0x1a690000, 0x4e000000000000, 0x0, 0x0, 0x0, 0x2ff02fc02fa, 0x0, 0x1000000000000, 0x1a6f000000000000, 0x1a7e1a7b00001a72, 0x0, 0xc0000008f, 0x0, 0x563000000000000, 0x920560, 0x0, 0x0, 0x1a76000000000000, 0x0, 0x1000000000000, 0x0, 0x0, 0x0, 0x0, 0xae00305, 0x392038303740365, 0x1aad02f403b003a1, 0xb3b00a500a10544, 0x30f034303140305, 0x392038303740365, 0x1aad02f403b003a1, 0xa500a10544, 0xb4107870a7d0692, 0xa280b790b0d0e8c, 0x8400cd30b3b05d3, 0xba3, 0x0, 0x0, 0x83f, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe4d05e309a2099e, 0xe770a220a1e0000, 0x6ac06020e500000, 0xe6d0b0d06ac06ac, 0xa28073406cf06cf, 0x786077e0000, 0x82c083b06af0000, 0x82c082c, 0x897088f0863, 0x77c0000060a, 0x5b0071a0000060a, 0xa7d000005e305d5, 0x7230000067e0629, 0x136a136213540787, 0x68000000ae0136f, 0x10060f3a10ec11ee, 0x1aab, 0xa7d0a2e05e60000, 0x73e0ae0, 0x0, 0x3ca03c103e203da, 0x498045903d20455, 0x3de04e703d604cf, 0x3be051104eb049c, 0x6de06d406d106cf, 0x91f091b091806b2, 0x950094d068206e1, 0x72305e605e30734, 0xb3d0b330b300ae0, 0xdd60dd20dcf086a, 0xdfd0dfa0b410b40, 0x5d30a2e09a00a28, 0x0, 0x0, 0x30d0000, 0x0, 0x0, 0x0, 0x1a8d1a8600000000, 0x0, 0x0, 0x0, 0x0, 0x1a9200000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a981a9b1a950000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1aa0, 0x1aa50000, 0x1aa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1ab200001aaf, 0x0, 0x1ac100001ab81ab5, 0x1ac4, 0x0, 0x0, 0x0, 0x1ac80000, 0x1ace000000001acb, 0x1ad10000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1ad700000556, 0x0, 0x0, 0x55b054a1ad40000, 0x1add1ada, 0x1ae31ae0, 0x1ae91ae6, 0x0, 0x1aef1aec, 0x1afb1af8, 0x1b011afe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b131b101b0d1b0a, 0x0, 0x0, 0x0, 0x0, 0x1b071b041af51af2, 0x0, 0x1b191b1600000000, 0x1b1f1b1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b371b350000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x365030f03430314, 0x3a1039203830374, 0x342032f031c03b0, 0x382037303640355, 0x3f703af03a00391, 0xe600e200d900a3, 0xf600f200ee00ea, 0xb100ac00a700fa, 0xc500c000bb00b6, 0xdd00d400cf00ca, 0x368035903460319, 0x3a4039503860377, 0x3450332031f03b3, 0x385037603670358, 0x3fa03b203a30394, 0x172016e016a0166, 0x182017e017a0176, 0x192018e018a0186, 0x1a2019e019a0196, 0x1b201ae01aa01a6, 0x1c201be01ba01b6, 0x5d5056801ca01c6, 0x67e062905e605e3, 0x60706cf06ac0687, 0x77e07230734071a, 0x82c083b06af07a4, 0x6b2056b088d085e, 0x60a095a06820770, 0xa2e09a009370692, 0xb0d06020ad90a7d, 0xa280b79073e0ae0, 0xcd307870b3b05d3, 0xba308400a1105d8, 0xb410de1086a0a24, 0x30506110695, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1abc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x552054f0542, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b2c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6b2073e, 0x0, 0x0, 0x0, 0x1b2f000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x227c000000000000, 0x0, 0x0, 0x0, 0x0, 0x26b0000000000000, 0x0, 0x0, 0x0, 0x1f091f011efb1ee9, 0x1f1b1f171f131f0d, 0x1f5f1f571f4b1f21, 0x1f871f771f6f1f67, 0x1fb91fa51f8b1f89, 0x1fcd1fc71fc51fc1, 0x1feb1fe91fdd1fdb, 0x204f20451ff71fef, 0x207f207d2079206f, 0x20b420ae20982087, 0x20ce20cc20ca20c4, 0x20f820f220dc20da, 0x210f2108210020fc, 0x212f212b21292113, 0x2141213921352131, 0x21972195218b214f, 0x21e521e321d921d7, 0x32521f121ed21e9, 0x2260222303292211, 0x227a2274226e2266, 0x228422822280227e, 0x230c230622e22286, 0x231623122310230e, 0x2334233023222318, 0x235c235a23562354, 0x2376237423622360, 0x238a238823862384, 0x23aa23a823a62394, 0x23ee23de23dc23bc, 0x241c240a23fa23f6, 0x2452244c2442243e, 0x245e245c245a2456, 0x247e247a246c246a, 0x248e248a24842482, 0x2498249624922490, 0x250e250c24f224e8, 0x2530252c25282512, 0x2558255425522534, 0x25742572255c255a, 0x2592258425822578, 0x25ba25aa25982596, 0x25de25c825c425c2, 0x260025fa25e825e0, 0x261a261826142608, 0x26262624261e261c, 0x263c263a2638262a, 0x2658264e264a2648, 0x26622660265c265a, 0x2670266826662664, 0x26862684267e267c, 0x2690268e268a2688, 0x26a0269c26982692, 0x26aa26a826a626a2, 0x26b226ae, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b4900000000, 0x1fd11fcf1fcd, 0x0, 0x0, 0x0, 0x0, 0x1b8100001b7e, 0x1b8700001b84, 0x1b8d00001b8a, 0x1b9300001b90, 0x1b9900001b96, 0x1b9f00001b9c, 0x1ba500001ba20000, 0x1ba80000, 0x0, 0x1bb100001bae1bab, 0x1bba1bb700001bb4, 0x1bc01bbd0000, 0x1bc91bc6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b7b, 0x87000000000000, 0x1bcc1bd30000008a, 0x0, 0x0, 0x0, 0x1c4300001c26, 0x1c9200001bf6, 0x1caf00001c9b, 0x1cca00001cbf, 0x1cdc00001ccf, 0x1ceb00001ce1, 0x1cf700001cf20000, 0x1c100000, 0x0, 0x1d3b00001d261d1d, 0x1d611d5700001d42, 0x1d7e1d760000, 0x1caa1da1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e44000000001c01, 0x1e571e521e4d, 0x1ca11e6000000000, 0x0, 0x0, 0x0, 0x0, 0x1a10194919440000, 0x19501a141a12194b, 0x1a181a1619571955, 0x1a201a1e1a1c1a1a, 0x19661961195c19a6, 0x196f196d196819b0, 0x198e198319811977, 0x1947199d19981993, 0x19de19dc19da19d8, 0x198c19e419e219e0, 0x19ee19ec19ea19e8, 0x19f619f419f21975, 0x19fe197f19fa19f8, 0x1a2219a419a219d4, 0x1a2a1a281a261a24, 0x1a3019a81a2e1a2c, 0x19ae19ac19aa1a32, 0x19b819b619b419b2, 0x19c019be19bc19ba, 0x19c819c619c419c2, 0x1a361a3419cc19ca, 0x1a0019d219d019ce, 0x1a081a061a041a02, 0x1a0e1a0c1a0a, 0x1f171ee900000000, 0x1efd1ef120471eef, 0x1ef71f0d23641ef3, 0x1f212051208c1eeb, 0x1e901e001d701ce, 0x20d020401fb01f2, 0x245023c02330225, 0x1db01d20257024e, 0x1ff01f601ed01e4, 0x237022902110208, 0x25b025202490240, 0x21e0216022e, 0x2a0026802700260, 0x284026402880274, 0x2c402b00290026c, 0x2a402ec02b802c0, 0x2d002b402bc02ac, 0x2d402e402c80298, 0x2a8029c0278028c, 0x29402e8027c02cc, 0x2e002dc028002d8, 0x23fe21e321112021, 0x0, 0x0, 0x41c04110406082e, 0x440043904320427, 0x475046e044e0447, 0x4850482047f047c, 0x19571950194b1944, 0x196f19681961195c, 0x1993198e19831977, 0x194d1946199d1998, 0x1963195e19591952, 0x198519791971196a, 0x199f199a19951990, 0x1974197c1988, 0x20471eef1f171ee9, 0x1f5f1eed1f611f19, 0x22e203291fcd1f0f, 0x204f25c822232286, 0x2240221b223b0325, 0x23ca255e231c2007, 0x2098236823e21fab, 0x22961fdf1f4925a2, 0x208a1f731f2b262c, 0x20fa1ef31efd1ef1, 0x20b220b81fc92001, 0x1fd725681f292390, 0x48e048b04882083, 0x4b704b404b10491, 0x4c304c004bd04ba, 0x4e404cc04c904c6, 0x4d604a3034e033b, 0x5290518050304f2, 0x34d033a0327053a, 0x7390a7f0a8206b4, 0x1c0a1bff1bf11bd8, 0x1c731c411c241c1a, 0x1cbd1cad1c991c90, 0x1cdf1cda1ccd1c1e, 0x1bde1cf51cf01bfb, 0x1c8e1d111d0f1ca6, 0x1d551d391d1b1d0d, 0x1ddc1c311d9f1d74, 0x1e041e001def1c22, 0x1c351e1b1e191e11, 0x1e421c5d1e341bed, 0x1e551e501e4b, 0x1beb1be51be01bda, 0x1c0c1c041bf91bf3, 0x1c331c201c1c1c13, 0x1c2e1c291c3c1c37, 0x1c501c571c4b1c46, 0x1c6d1c661c5f1c5c, 0x1c8b1c841c7d1c61, 0x1cb21ca81ca41c95, 0x1cd61cd21cc21cb7, 0x1c811d031cfa1ce4, 0x1d291d351d171d0c, 0x1d4c1d451d201d30, 0x1d6b1d641d3e1d51, 0x1d811d951d701d5a, 0x1d8f1d8a1d9b1d85, 0x1db81da41dac1d79, 0x1dc51dbf1dbb1db2, 0x1dd61dd21dce1dca, 0x1df11de61de31dde, 0x1e0b1e061c681df5, 0x1e291e241e1f1e13, 0x1c6f1e391e361e2e, 0x3610352033f0311, 0x39d038e037f0370, 0x33e032b03bb03ac, 0x37e036f03600351, 0x3ba03ab039c038d, 0x4230418040d0402, 0x56a0a530b0f042e, 0xa590ce60c580a0f, 0x210a06db0a600a5c, 0x223d21f920892200, 0xbea11b40c260cda, 0x689075b071c0b7b, 0xc290cdd0b8c0a26, 0x6010bf611c011b7, 0x68c07640b7e068d, 0xa560bfd11c30893, 0x11c60c350aec0b94, 0xc030b970a300c00, 0xc070b9a0a340a33, 0xc1b0b9e0a380a37, 0x7680b8206910c1f, 0xd000cfa0cf60690, 0xc0f11c90c380ce9, 0xbed11ba0c2c0ce0, 0xc2f0ce3076c0b86, 0x76f0b890bf011bd, 0x5d70999077b0bb4, 0x5e805ff0a2d0a2a, 0x6ae0b1306940a50, 0xba20722071f0b3a, 0xbc60bc20bbf0bbc, 0x8200c0b0bf90bf3, 0xd25082b08230cd5, 0x5d1092a09360869, 0x36c035d034a0337, 0x3a80399038a037b, 0x3490336032303b7, 0x389037a036b035c, 0x3fe03b603a70398, 0x42a041f04140409, 0x44a0443043c0435, 0xaf4047804710451, 0x0, 0x0, 0x0, 0x0, 0x26b4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe730e6b, 0x0, 0x256a258422132556, 0x26ae1ff91eff22c6, 0x202b25c8209226ae, 0x244a238221872090, 0x25a8251e250424e6, 0x233c22f0229a2254, 0x1f11265225bc24ca, 0x24e42302225e1fe3, 0x24dc22d620e6267a, 0x250a247821a12526, 0x232822a6221d211f, 0x1fb31f7d1f3125ae, 0x23922300225a21d5, 0x257e24ec24e02456, 0x23b02678266a2610, 0x25d624bc242c23d0, 0x212d206d2540267e, 0x23b4231a24682408, 0x20d4206b260c2566, 0x242422ca22b02256, 0x246e1fb125ec2438, 0x242e23e61f811f83, 0x21a3254e25f024c8, 0x20be1f0525462254, 0x1fc3237223322159, 0x1ef5214b1f3923b8, 0x1fed242221e12290, 0x253824cc23982063, 0x21ab228c25962276, 0x1f1f237021bb24a8, 0x241822441f7f1f5d, 0x1fb725c6253e2494, 0x21ef212720982011, 0x265625e423ba22d8, 0x220f1fa5268c2680, 0x217b210d2590226c, 0x22f622d021d12189, 0x2464243223e0234e, 0x25d8259c24d02588, 0x22ee201b1fa71f91, 0x2155211d25382514, 0x232c2406227221b7, 0x20f020be20491f27, 0x24502348233a215b, 0x2612260a25ca2460, 0x25c023da1f332630, 0x1f451f15216725fe, 0x225421e720d020c0, 0x25a624d6238022fc, 0x1fa325ea220726aa, 0x22be22a22233222d, 0x242023ae236e2340, 0x25f221911f612636, 0x258a22b220e21f3d, 0x23322237216b2143, 0x20d820091f9525f6, 0x2294224a222521fc, 0x251624462378233e, 0x1fcb260425c4251c, 0x235022fe200b22c0, 0x2682266e25f824de, 0x23f6247c22ae2231, 0x22ea2326240e23fc, 0x1f9724b01f23254c, 0x241421a521151f8f, 0x258e220d229c20b6, 0x2123252c25ee250e, 0x20371f4d, 0x220500002061, 0x238c232a1f850000, 0x23d823ce23cc23be, 0x245224102616, 0x2544000024e2, 0x25b4259e0000, 0x2642264000000000, 0x25fc25b026762644, 0x1faf1f511f471f35, 0x203d202f1fd51fb5, 0x20d62065205f2041, 0x21792175216120da, 0x220921f321db2185, 0x22ce22b622a82246, 0x23b22342230822f8, 0x23c623c223c42240, 0x23d623d423ca23c8, 0x2432240023f223e8, 0x24582444243a2436, 0x24ce249a249a2480, 0x254a2548252e2522, 0x259e259a256e256c, 0x215d263426282606, 0x248c274b, 0x1f2f1f5b1f7b1ef9, 0x1fbb1fad1f651f4f, 0x203b202d2025202f, 0x2094208e20692061, 0x2125212120aa20a2, 0x21712165214d213d, 0x2185217321792169, 0x21c921c521bf2193, 0x221f221d220521dd, 0x22a22276226e2229, 0x22dc22ce22c422c8, 0x2324230a23a422f8, 0x236a2358234a232a, 0x238e238c237e237c, 0x23b6239e23a02396, 0x2428240c240023f4, 0x24b2245824402432, 0x252a2524250024c6, 0x253c2544253a252e, 0x254a254225462548, 0x25a4258c256e2550, 0x260625f425ce25be, 0x262e262826202616, 0x272126ae265e2634, 0x1ea11e8d2733271f, 0x27a9277927671ea3, 0x26ac26a4, 0x0, 0xade0ae30adf0adb, 0xd280d280ae2, 0x0, 0x0, 0x134e000000000000, 0x134b135113481345, 0x0, 0x13d2000013850000, 0x1374136f135413a6, 0x13b7139b1360138e, 0x13ca13c702f413cd, 0x1359135613c313bf, 0x1371136c1364135c, 0x137f137c1376, 0x1390138b13881382, 0x139d00001398, 0x13a8000013a313a0, 0x13b413b1000013ab, 0x137913cf13bc13b9, 0x135f13ae13931367, 0x181e181e18181818, 0x18201820181e181e, 0x1824182418201820, 0x181c181c18241824, 0x18221822181c181c, 0x181a181a18221822, 0x183c183c181a181a, 0x183e183e183c183c, 0x18281828183e183e, 0x1826182618281828, 0x182a182a18261826, 0x182c182c182a182a, 0x18321832182c182c, 0x1834183418301830, 0x18381838182e182e, 0x1840184018361836, 0x1844184418401840, 0x1848184818441844, 0x1846184618481848, 0x184a184a18461846, 0x184c184c184c184c, 0x18501850186d186d, 0x184e184e18501850, 0x15911591184e184e, 0x186a186a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1842000000000000, 0x1803184218421842, 0x180717ff17ff1803, 0x18621862185b1807, 0x1860186018551855, 0x180b180b180b180b, 0x17cd17cd14151415, 0x17f117f1180d180d, 0x17fd17fd18011801, 0x1809180918051805, 0x17f517f517f51809, 0x1864186418641864, 0x17f517e517d517d1, 0x13fe13f713f417f9, 0x141e14171414140b, 0x146a144d1438142d, 0x1484147b1472146d, 0x14311422148c1487, 0x143c14d414d11435, 0x151a150c150514fa, 0x15a515a215931562, 0x15c815c515ba15b0, 0x1607157515e415df, 0x16451642163f160a, 0x165b16561653164c, 0x1679167416711662, 0x16851682167f167c, 0x16aa169616931688, 0x1579158c16c816b9, 0x14591455145116e0, 0x172d1461145d1526, 0x17691758174f1740, 0x177f17741771176c, 0x17aa17a3179c1782, 0x14e417c717c417b3, 0x64005d179714ee, 0x8000790072006b, 0x17e917e517e117dd, 0x140813db17f917f5, 0x14171414140e140b, 0x1464144d144a1447, 0x14781475146d146a, 0x14871484147e147b, 0x1674167116561653, 0x1693168816851679, 0x16e01579158c1696, 0x17551752152616e5, 0x176c176917631758, 0x17b317b017ad1797, 0x17d117c717c417be, 0x17ed17e517d917d5, 0x140b13fe13f713f4, 0x1438142d141e1411, 0x148c147b1467144d, 0x14d1143514311422, 0x150c150514fa143c, 0x1593156d1562151a, 0x15ba15b015a515a2, 0x157515e415df15c5, 0x1642163f160a1607, 0x1662165b164c1645, 0x16851682167f167c, 0x16c816b916aa1688, 0x1455145113e0158c, 0x1740172d15261459, 0x177117661758174f, 0x17a3179c17851774, 0x17e515ed17b317aa, 0x144d1411140b17ed, 0x151a1481147b1467, 0x16851557154c1529, 0x17661758158c1688, 0x162c162515ed17b3, 0x15ff15da15d71633, 0x152c161c16191602, 0x1490155d155a152f, 0x1440142a142613fb, 0x15bd159d159a1402, 0x1546153b153415c0, 0x157015171549154c, 0x15ff15da15d715b7, 0x152c161c16191602, 0x1490155d155a152f, 0x1440142a142613fb, 0x15bd159d159a1402, 0x1546153b153415c0, 0x157015171549154c, 0x1546153b153415b7, 0x15c815571529154c, 0x1534150c150514fa, 0x15df15c81546153b, 0x13e313e3, 0x0, 0x0, 0x0, 0x0, 0x1434143014301421, 0x145814541450143b, 0x14c114c514a314a3, 0x1521150114fd1508, 0x15251525151d1521, 0x153e159615651565, 0x154f154f1537153e, 0x15b315a815531553, 0x15cf15cb15cb15b3, 0x15f315f315e715d3, 0x16111615160d15f7, 0x1669166516481648, 0x16ad16c016c416bc, 0x16d216cb16cb16ad, 0x170b170216fe16d2, 0x1716171216f316eb, 0x177716ef00000000, 0x173417471743177b, 0x175b175f17381734, 0x1429140117b617b6, 0x1460143f14431425, 0x14a7148f14ab145c, 0x15ac15421569150f, 0x179f17a616d616b5, 0x174b166d172117ba, 0x168f15fb16bc1665, 0x168b16b1171a1730, 0x14ba1493173016b1, 0x168b13fa164f16f7, 0x173c1513159615e7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13d913de165e158f, 0x15eb14e915731706, 0x1497157c1578158a, 0x14f1, 0x0, 0x0, 0x0, 0x0, 0x5401b331b3102f6, 0x1b770093008d0546, 0x2ff1b79, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9931a6b1a6d02fc, 0xe3b00a500a10993, 0x1b451b4f1b4b0e3f, 0x1b351b3b1b391b47, 0x1b411b3f1b3d1b37, 0x98b000000001b43, 0xc000c000c098f, 0x99309930993000c, 0x2fa1b3102f6, 0x8d009305400546, 0xe3b00a500a11a6d, 0x971b4f1b4b0e3f, 0x2f802f402f2009d, 0x54405590548, 0x566009b0099098d, 0x0, 0x5a161f0057, 0x1622006800000061, 0x163000761629006f, 0x163a00841637007d, 0x13e913e613e613d5, 0x13ec178f178f13e9, 0x17ca17ca17ca13ec, 0x13f213d713d717ca, 0x141a13f213f213f2, 0x141c141c141c141a, 0x147014701470141c, 0x13f513f513f51470, 0x13f813f813f813f5, 0x13ff13ff13ff13f8, 0x14e214e014e013ff, 0x140913dc13dc14e2, 0x14f814f814f81409, 0x15321532153214f8, 0x1560156015601532, 0x15a015a015a01560, 0x15c315c315c315a0, 0x15dd15dd15dd15c3, 0x15e215e215e215dd, 0x16051605160515e2, 0x163d163d163d1605, 0x165916591659163d, 0x1677167716771659, 0x14ec14ec14ec1677, 0x140c140c140c14ec, 0x140f140f140f140c, 0x13e113e113e1140f, 0x14151788178813e1, 0x13fc13fc13fc1415, 0x16a2169e169e13fc, 0x169b16a616a616a2, 0x169b, 0x970095008d0000, 0x9f009d009b0099, 0x2f402f200a500a1, 0x30302fa02f802f6, 0x30f034303140305, 0x392038303740365, 0x546054003b003a1, 0x93055905440548, 0x5e305d505680566, 0x687067e062905e6, 0x71a060706cf06ac, 0x7a4077e07230734, 0x85e082c083b06af, 0x77006b2056b088d, 0x98b060a095a0682, 0x9930991098f098d, 0x9a0093706920995, 0x6020ad90a7d0a2e, 0xb79073e0ae00b0d, 0x7870b3b05d30a28, 0x8400a1105d80cd3, 0xde1086a0a240ba3, 0xe3b061106950b41, 0x1b280e410e3f0e3d, 0x1b3f1b3d1b331b2a, 0x1bd61e551e5c1b31, 0x1c181c081bfd1bef, 0x1cee1e171e0f1e02, 0x1bff1bf11bd81c16, 0x1c411c241c1a1c0a, 0x1cad1c991c901c73, 0x1cda1ccd1c1e1cbd, 0x1cf51cf01bfb1cdf, 0x1d111d0f1ca61bde, 0x1d391d1b1d0d1c8e, 0x1c311d9f1d741d55, 0x1e001def1c221ddc, 0x1e1b1e191e111e04, 0x1c5d1e341bed1c35, 0x8b00881c061e42, 0x1a101949194419d4, 0x19501a141a12194b, 0x1a181a1619571955, 0x1a201a1e1a1c1a1a, 0x19661961195c19a6, 0x196f196d196819b0, 0x198e198319811977, 0x199d19981993, 0x19d8194700000000, 0x19e019de19dc19da, 0x19e419e200000000, 0x19ec19ea19e8198c, 0x197519ee00000000, 0x19f819f619f419f2, 0x197f19fa00000000, 0x19fe, 0x90e4b0e450e43, 0x1a820e470e49, 0x1a8b1a891a841b22, 0x1b261b241a90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26b600000000, 0x26b9, 0x0, 0x0, 0x26bc000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26c226bf00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26c826c500000000, 0x26d726d326cf26cb, 0x26db, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26df000000000000, 0x26e626ed26e226ea, 0x26f1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5e605e305d50568, 0x6ac0687067e0629, 0x734071a060706cf, 0x6af07a4077e0723, 0x88d085e082c083b, 0x682077006b2056b, 0x9370692060a095a, 0xad90a7d0a2e09a0, 0x73e0ae00b0d0602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x86a0a240ba30840, 0x61106950b410de1, 0x5e605e305d50568, 0x6ac0687067e0629, 0x734071a060706cf, 0x6af07a4077e0723, 0x88d085e082c083b, 0x682077006b2056b, 0x9370692060a095a, 0xad90a7d0a2e09a0, 0x73e0ae000000602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x86a0a240ba30840, 0x61106950b410de1, 0x5e605e305d50568, 0x6ac0687067e0629, 0x734071a060706cf, 0x6af07a4077e0723, 0x88d085e082c083b, 0x682077006b2056b, 0x9370692060a095a, 0xad90a7d0a2e09a0, 0x73e0ae00b0d0602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x86a0a240ba30840, 0x61106950b410de1, 0x5e605e300000568, 0x68700000000, 0x71a06070000, 0x6af07a4077e0000, 0x88d085e0000083b, 0x682077006b2056b, 0x9370692060a095a, 0xad900000a2e09a0, 0x73e0ae00b0d0000, 0xb3b05d30a280b79, 0xa1105d80cd30000, 0x86a0a240ba30840, 0x61106950b410de1, 0x5e605e305d50568, 0x6ac0687067e0629, 0x734071a060706cf, 0x6af07a4077e0723, 0x88d085e082c083b, 0x682077006b2056b, 0x9370692060a095a, 0xad90a7d0a2e09a0, 0x73e0ae00b0d0602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x86a0a240ba30840, 0x61106950b410de1, 0x5e6000005d50568, 0x687067e0629, 0x734071a06070000, 0x6af07a4077e0723, 0x88d085e0000083b, 0x682077006b2056b, 0x93706920000095a, 0xad90a7d0a2e09a0, 0x73e0ae00b0d0602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x86a0a240ba30840, 0x61106950b410de1, 0x5e6000005d50568, 0x687067e0629, 0x734071a060706cf, 0x7a400000723, 0x88d085e00000000, 0x682077006b2056b, 0x93706920000095a, 0xad90a7d0a2e09a0, 0x73e0ae00b0d0602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x86a0a240ba30840, 0x61106950b410de1, 0x5e605e305d50568, 0x6ac0687067e0629, 0x734071a060706cf, 0x6af07a4077e0723, 0x88d085e082c083b, 0x682077006b2056b, 0x9370692060a095a, 0xad90a7d0a2e09a0, 0x73e0ae00b0d0602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x86a0a240ba30840, 0x61106950b410de1, 0x6af07a4077e0723, 0x88d085e082c083b, 0x682077006b2056b, 0x9370692060a095a, 0xad90a7d0a2e09a0, 0x73e0ae00b0d0602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x9370692060a095a, 0xad90a7d0a2e09a0, 0x73e0ae00b0d0602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x86a0a240ba30840, 0x61106950b410de1, 0x5e605e305d50568, 0x6ac0687067e0629, 0x734071a060706cf, 0x6af07a4077e0723, 0x88d085e082c083b, 0x682077006b2056b, 0x9370692060a095a, 0xad90a7d0a2e09a0, 0x73e0ae00b0d0602, 0xb3b05d30a280b79, 0xa1105d80cd30787, 0x86a0a240ba30840, 0x61106950b410de1, 0x5e605e305d50568, 0x6ac0687067e0629, 0x734071a060706cf, 0x6af07a4077e0723, 0x61106950b410de1, 0xe800e6f, 0xf3c0f3a0f380ee3, 0xfad0f5e0f5c0f3e, 0xfe20fe00fde0faf, 0x10060fe80fe60fe4, 0x100f100d0fad1008, 0x1035103310311011, 0x10ea10861aa3077c, 0x110e10f010ee10ec, 0x11ae1170116e1110, 0x11ce11cc11b211b0, 0x11f811f011ee11d0, 0x123c11fe11fc11fa, 0x1a9e12421240123e, 0x123c11ae116e10f0, 0xf380ee311ee11f0, 0xf5c0f3e0f3c0f3a, 0xfde0faf0fad0f5e, 0xfe60fe40fe20fe0, 0xfad100810060fe8, 0x10311011100f100d, 0x1aa3077c10351033, 0x10ee10ec10ea1086, 0x116e1110110e10f0, 0x11b211b011ae1170, 0x11ee11d011ce11cc, 0x11fc11fa11f811f0, 0x1240123e123c11fe, 0x116e10f01a9e1242, 0x11ee11f0123c11ae, 0xf3c0f3a0f380ee3, 0xfad0f5e0f5c0f3e, 0xfe20fe00fde0faf, 0x10060fe80fe60fe4, 0x100f100d0fad1008, 0x1035103310311011, 0x10ea10861aa3077c, 0x110e10f010ee10ec, 0x11ae1170116e1110, 0x11ce11cc11b211b0, 0x11f811f011ee11d0, 0x123c11fe11fc11fa, 0x1a9e12421240123e, 0x123c11ae116e10f0, 0xf380ee311ee11f0, 0xf5c0f3e0f3c0f3a, 0xfde0faf0fad0f5e, 0xfe60fe40fe20fe0, 0xfad100810060fe8, 0x10311011100f100d, 0x1aa3077c10351033, 0x10ee10ec10ea1086, 0x116e1110110e10f0, 0x11b211b011ae1170, 0x11ee11d011ce11cc, 0x11fc11fa11f811f0, 0x1240123e123c11fe, 0x116e10f01a9e1242, 0x11ee11f0123c11ae, 0xf3c0f3a0f380ee3, 0xfad0f5e0f5c0f3e, 0xfe20fe00fde0faf, 0x10060fe80fe60fe4, 0x100f100d0fad1008, 0x1035103310311011, 0x10ea10861aa3077c, 0x110e10f010ee10ec, 0x11ae1170116e1110, 0x11ce11cc11b211b0, 0x11f811f011ee11d0, 0x123c11fe11fc11fa, 0x1a9e12421240123e, 0x123c11ae116e10f0, 0x12a212a011ee11f0, 0x314030500000000, 0x3740365030f0343, 0x3b003a103920383, 0x30f034303140305, 0x392038303740365, 0x314030503b003a1, 0x3740365030f0343, 0x3b003a103920383, 0x30f034303140305, 0x392038303740365, 0x314030503b003a1, 0x3740365030f0343, 0x3b003a103920383, 0x14e013f513f213d7, 0x13f8140917880000, 0x14ec167713fc15c3, 0x15e214f8140f140c, 0x13dc16591560163d, 0x13ff1470141c1532, 0x160515dd15a014e2, 0x1816183a184a1814, 0x13f513f20000, 0x13f80000000013e1, 0x14ec167713fc0000, 0x15e214f8140f140c, 0x16591560163d, 0x13ff1470141c1532, 0x1605000015a00000, 0x0, 0x13f500000000, 0x13f8000000000000, 0x14ec000013fc0000, 0x15e214f8140f0000, 0x165915600000, 0x13ff000000001532, 0x1605000015a00000, 0x18160000184a0000, 0x13f513f20000, 0x13f80000000013e1, 0x167713fc15c3, 0x15e214f8140f140c, 0x16591560163d, 0x13ff1470141c1532, 0x160515dd15a00000, 0x183a00001814, 0x14e013f513f213d7, 0x13f81409178813e1, 0x14ec000013fc15c3, 0x15e214f8140f140c, 0x13dc16591560163d, 0x13ff1470141c1532, 0x160515dd15a014e2, 0x0, 0x14e013f513f20000, 0x13f8140917880000, 0x14ec000013fc15c3, 0x15e214f8140f140c, 0x13dc16591560163d, 0x13ff1470141c1532, 0x160515dd15a014e2, 0x0, 0x3f103160307030a, 0x4fa04de04ab0468, 0x5310520050b, 0x0, 0x10a0106010200fe, 0x11a01160112010e, 0x12a01260122011e, 0x13a01360132012e, 0x14a01460142013e, 0x15a01560152014e, 0x5e31b4d0162015e, 0x93305e5082c, 0x5e605e305d50568, 0x6ac0687067e0629, 0x734071a060706cf, 0x6af07a4077e0723, 0x88d085e082c083b, 0x682077006b2056b, 0x76c06b1060a095a, 0x930082708660860, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x761075e00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x606, 0x0, 0x0, 0x0, 0x1cad1c9e1bc3, 0x0, 0x0, 0x0, 0x1cf71ff320b02197, 0x208c253220811f17, 0x21e722f221fe1f1d, 0x21eb1f6921451f9d, 0x2560235c24261f93, 0x219d22cc200f2073, 0x25a01eef1ee921b3, 0x21ad20011efd20fa, 0x23f023d221992574, 0x329221b22bc2005, 0x20351f9f2366, 0x0, 0x1b5d1b551b511b69, 0x1b591b711b611b6d, 0x1b65, 0x0, 0x1ffd2147, 0x0, 0x0, 0x0, 0x26f51f0b1f031f07, 0x1f3b1f371f351f2d, 0x1f431f471f411f3f, 0x1f531f5126fd1e63, 0x1e6526f71f631f55, 0x1f7126fb1f691f59, 0x1f7b1f791f251f75, 0x1e691f8d1f8927b9, 0x1fa11f9f1f9b1f99, 0x1fb51faf1fad1e6b, 0x1fc31fbf1fbd1fbb, 0x1fe11fd91fd51fd3, 0x1fe71fe71fe71fe5, 0x1ff51ff122e42703, 0x20031fff1ffb2705, 0x20152013200d2017, 0x2023201f201d2019, 0x202d202920292027, 0x204b203920332031, 0x2043203f204d203d, 0x2057205520711f8f, 0x205b205d20532059, 0x2077207527072067, 0x209620852081207b, 0x209e209c270b2709, 0x1e6d20a4209a20a0, 0x20ac20ac20a81e6f, 0x20be20bc20ba270d, 0x20c820c6270f20c2, 0x20d21e7120cc2137, 0x271320de20e020da, 0x20e820ea271520e4, 0x1e7320f620f420ec, 0x21062104210220fe, 0x21171e7727171e75, 0x27cd211f211b2119, 0x2486271b271b212b, 0x27291e7921332133, 0x1e7b213f213b277d, 0x2157215321512149, 0x21611e7d1e7f215f, 0x216f216d2163271d, 0x21792177216f2171, 0x2183217f217d2181, 0x218f210b21872185, 0x21b121a7219f219b, 0x21b521a921af2723, 0x21c7272521c321b9, 0x21cb1e8121bd21c1, 0x1e8321cd21d321cf, 0x21f5272721df21db, 0x22091e8922032215, 0x1f6d1f6b1e851e87, 0x1ebb2470220b2217, 0x222b2221221f221d, 0x22351e8b27312227, 0x273522462242222f, 0x1e8d224c22392248, 0x225822522250224e, 0x22621e8f225c2737, 0x226a1e9122642739, 0x273b227822762270, 0x273f2288273d2711, 0x2298228a2292228e, 0x22a422a222a822a0, 0x229e274122ac22aa, 0x22c41e9322ba22b8, 0x22d222b4274322c2, 0x22de22d427472745, 0x22e01e9522da22dc, 0x26f922ec22e622e8, 0x274d22fa274922f4, 0x274f2314230a2304, 0x275327512320231e, 0x23381e972336232e, 0x234623441e991e99, 0x1e9b2352234c234a, 0x2757236c2755235e, 0x2759237a27192372, 0x1e9f1e9d275d275b, 0x2763275f27612396, 0x239c239c239a2765, 0x1ea523a21ea323a0, 0x23b023ac27691ea7, 0x23c8276b1ea923b6, 0x23e423d8276f276d, 0x23ec23ea23e81eab, 0x23f8277327732771, 0x2404240227751ead, 0x1eb1241227771eaf, 0x277b241e2416241a, 0x243424301eb3242a, 0x2781277f1eb5243c, 0x2785244827831eb7, 0x278724582454244e, 0x2466278b24622789, 0x247424721eb9272b, 0x278d20a624761ebd, 0x2486272f272d278f, 0x249e1ebf25942488, 0x24a21fa924a0249c, 0x279124aa24a624a4, 0x24b824b624ac24a8, 0x24ce24c424ba24ae, 0x24c224c024be24b4, 0x1ec1279527972793, 0x279f24d824d424d2, 0x1ec51ec3279924da, 0x24ea1ec7279d279b, 0x24f624f024ee24ec, 0x250024f824fa24f4, 0x1ec9250224fe24fc, 0x25101ecb25082506, 0x251a251827a12512, 0x27a31e6725201ecd, 0x25361ed11ecf27a5, 0x27a7255825502542, 0x2576257025642562, 0x257a257c26ff27ab, 0x258c258627012580, 0x25b225ac27af27ad, 0x25cc25b827b125b6, 0x25da25d025d425d2, 0x1ed325e227b325dc, 0x26021ed527b525e6, 0x27bb27b7260e20ee, 0x27bd26221ed91ed7, 0x262e262e27bf1edb, 0x1edd263e27c12632, 0x26542650264c2646, 0x266c265e27c31edf, 0x26741ee31ee12672, 0x27c927c71ee527c5, 0x26901ee7268627cb, 0x269e269a26962694, 0x27cf26a2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //12288 bytes enum canonMappingTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x20, 0x120], [ 0x100, 0x400, 0x1380], [ 0x302020202020100, 0x205020202020204, 0x602020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x1000000000000, 0x5000400030002, 0x6, 0x9000800070000, 0xc0000000b000a, 0x0, 0xe00000000000d, 0x0, 0x0, 0x1100000010000f, 0x130012, 0x16001500140000, 0x18000000170000, 0x1a000000190000, 0x0, 0x1c001b0000, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f001e, 0x0, 0x0, 0x23002200210020, 0x27002600250024, 0x28, 0x2b002a00000029, 0x2f002e002d002c, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34003300320000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38003700360035, 0x3c003b003a0039, 0x3e003d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f00000000, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x43004200410000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x47004600450044, 0x4b004a00490048, 0x4c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x250012000f000c, 0x850000004f0045, 0xcb00a400a1009e, 0x13301240121011e, 0x1a0019d01880000, 0x1da01b601a3, 0x2730270026d0000, 0x2f30287, 0x33803250322031f, 0x398000003620358, 0x3de03b703b403b1, 0x446043a04370434, 0x4b404b1049c0000, 0x4ee04ca04b7, 0x58a058705840000, 0x61c0000060d059e, 0x33e002b033b0028, 0x38c00790380006d, 0x392007f038f007c, 0x3a2008f03950082, 0x3cd00ba00000000, 0x3db00c803d800c5, 0x3e400d103fb00e8, 0x41000fd040a00f7, 0x419010604130100, 0x41c0109, 0x440012a043d0127, 0x45c01490443012d, 0x130, 0x471015d0462014f, 0x170047701630000, 0x47a01660484, 0x185000000000000, 0x18e04a801940499, 0x4a2, 0x4e401d004d901c5, 0x4f801e4, 0x5450231052f021b, 0x54b023705350221, 0x56902550552023e, 0x57b026405580244, 0x572025b, 0x594027d058d0276, 0x5b4029d059b0284, 0x5e002c905b702a0, 0x61002f605f502de, 0x3110628030b0302, 0x6310314062e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x50401f0, 0x0, 0x0, 0x2ac000000000000, 0x5c3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13d036900560000, 0x2a304fb01e70450, 0x28e05a9029205ba, 0x28a05ad029605a5, 0x35b0048000005a1, 0x653064a03540041, 0x416010300000000, 0x522020e046b0157, 0x65f065c05250211, 0x465, 0x40700f4, 0x365005204960182, 0x656064d06500647, 0x36f005c036c0059, 0x3ea00d703e700d4, 0x456014304530140, 0x50101ed04fe01ea, 0x53b022705380224, 0x5c002a905bd02a6, 0x578026105660252, 0x425011200000000, 0x0, 0x351003e00000000, 0x4f101dd03f400e1, 0x4e701d304d101bd, 0x61602fc04ea01d6, 0x0, 0x0, 0x0, 0x66b00000010000d, 0x137, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x662, 0x0, 0x100000000, 0x0, 0x6450670063d0000, 0x72c06df06c3, 0x798077800000759, 0x8d1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x781073500000000, 0x8c10867084707e9, 0x92f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92808ca00000000, 0x95f091f08fd, 0x9b4000000000000, 0x9b7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9c3000009cc09c6, 0x9ba000000000000, 0x0, 0x9ed09d809e4, 0x0, 0x0, 0x9de0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa200000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa0500000a0e0a08, 0xa41000000000000, 0x0, 0xa2f0a1a0a26, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa470a4400000000, 0x0, 0x0, 0xa1109cf0000, 0x0, 0x0, 0x0, 0xa0209c009ff09bd, 0xa0b09c900000000, 0xa4d0a4a00000000, 0xa1709d50a1409d2, 0xa1d09db00000000, 0xa2909e70a2309e1, 0xa530a5000000000, 0xa2c09ea0a3e09fc, 0xa3509f30a3209f0, 0xa3809f6, 0xa3b09f9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xac10abe00000000, 0xaca0ac40ac7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xacd00000ad3, 0x0, 0x0, 0x0, 0xad0000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae80000, 0x0, 0xaf10000, 0xaf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xadf0adc0ad90ad6, 0xaee0aeb0ae50ae2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb00000000000000, 0xb03, 0x0, 0x0, 0x0, 0xafd00000afa0af7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb12000000000000, 0xb1500000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb0c0b090b060000, 0xb0f00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb1e000000000b21, 0xb24, 0x0, 0x0, 0x0, 0xb1b0b18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb300b2a00000000, 0xb2d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb36, 0xb40000000000000, 0xb3c0b3900000b43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb4c0b4600000000, 0xb49, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb4f00000000, 0xb590b550b52, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb5f000000000000, 0x0, 0x0, 0xb620000, 0xb6500000000, 0xb68000000000000, 0x0, 0xb6b, 0x0, 0x0, 0xb5c0000, 0x0, 0xb6e000000000000, 0xb890b710000, 0xb8c, 0x0, 0xb740000, 0x0, 0x0, 0x0, 0xb7a000000000000, 0x0, 0x0, 0xb7d0000, 0xb8000000000, 0xb83000000000000, 0x0, 0xb86, 0x0, 0x0, 0xb770000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb8f00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb9200000000, 0xb9800000b95, 0xb9e00000b9b, 0xba100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xba4000000000000, 0xba70000, 0xbb000000bad0baa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3830070037d006a, 0x389007603860073, 0x39f008c039b0088, 0x3ae009b03a50092, 0x3ab009803a80095, 0x3d400c103d000bd, 0x40100ee03fe00eb, 0x40400f103f700e4, 0x41f010c040d00fa, 0x422010f04280115, 0x42e011b042b0118, 0x4490136045f014c, 0x46e015a04680154, 0x47d016904740160, 0x48a01760480016c, 0x48d017904870173, 0x493017f0490017c, 0x4a50191049f018b, 0x4ab019704ae019a, 0x4d501c104cd01b9, 0x4e001cc04dc01c8, 0x52c021805290215, 0x53e022a0532021e, 0x54802340541022d, 0x55f024b05550241, 0x55b0247054e023a, 0x56c02580562024e, 0x581026a0575025e, 0x5dd02c6057e0267, 0x5e302cc05e602cf, 0x597028005900279, 0x5ec02d505e902d2, 0x5f202db05ef02d8, 0x5f802e105fb02e4, 0x60402ea060102e7, 0x61902ff060702ed, 0x6340317062b030e, 0x56f04310637031a, 0x6590000062205fe, 0x0, 0x35f004c0372005f, 0x3280015032c0019, 0x330001d03340021, 0x345003203750062, 0x34d003a0341002e, 0x379006603490036, 0x3e100ce03ed00da, 0x3be00ab03ca00b7, 0x3c600b303ba00a7, 0x3f000dd03c200af, 0x4590146044d013a, 0x4f501e1051b0207, 0x4ba01a604be01aa, 0x4c201ae04c601b2, 0x50b01f7051e020a, 0x51301ff050701f3, 0x5170203050f01fb, 0x5b1029a05da02c3, 0x5c602af05ca02b3, 0x5ce02b705d202bb, 0x60a02f005d602bf, 0x61f030506250308, 0x61302f9, 0x0, 0x81b07f9081807f6, 0x82d080b08240802, 0x69e067c069b0679, 0x6b0068e06a70685, 0x858084d0855084a, 0x85c0851, 0x6d406c906d106c6, 0x6d806cd, 0x89308710890086e, 0x8a50883089c087a, 0x70706e5070406e2, 0x71906f7071006ee, 0x8eb08dc08e808d9, 0x8f308e408ef08e0, 0x74a073b07470738, 0x7520743074e073f, 0x90e0903090b0900, 0x9120907, 0x76a075f0767075c, 0x76e0763, 0x949093a09460937, 0x9510942094d093e, 0x787000007840000, 0x78f0000078b0000, 0x98b096909880966, 0x99d097b09940972, 0x7c0079e07bd079b, 0x7d207b007c907a7, 0x847084407e907e2, 0x8c108be08670860, 0x91f091c08fd08fa, 0x95f0958, 0x81f07fd08360814, 0x831080f08280806, 0x6a2068006b90697, 0x6b4069206ab0689, 0x897087508ae088c, 0x8a9088708a0087e, 0x70b06e907220700, 0x71d06fb071406f2, 0x98f096d09a60984, 0x9a1097f09980976, 0x7c407a207db07b9, 0x7d607b407cd07ab, 0x84107e507f007f3, 0x83d083a000007ec, 0x670066d06730676, 0x8bc000006bd, 0x8b9086306400000, 0x8b508b20000086a, 0x6df06dc06c306c0, 0xbb90bb60bb30726, 0x8d108cd08c408c7, 0x8d508f700000000, 0x72c0729072f0732, 0xbc20bbf0bbc0000, 0x92f092b09220925, 0x933095509190916, 0x7780775077b077e, 0x31d063d063a0772, 0x9b1095b00000000, 0x9ad09aa00000962, 0x798079507590756, 0x64307df, 0xbc70bc5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x79300000000, 0x4f015200000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbcc0bc900000000, 0x0, 0x0, 0x0, 0x0, 0xbcf00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbd50bd80bd20000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbdb, 0xbde0000, 0xbe1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbe700000be4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbea0000, 0xbf0000000000bed, 0xbf30000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf900000006, 0x0, 0x0, 0x900030bf60000, 0xbff0bfc, 0xc050c02, 0xc0b0c08, 0x0, 0xc110c0e, 0xc1d0c1a, 0xc230c20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc350c320c2f0c2c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc290c260c170c14, 0x0, 0xc3b0c3800000000, 0xc410c3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc490c470000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc5100000c4e, 0xc5700000c54, 0xc5d00000c5a, 0xc6300000c60, 0xc6900000c66, 0xc6f00000c6c, 0xc7500000c720000, 0xc780000, 0x0, 0xc8100000c7e0c7b, 0xc8a0c8700000c84, 0xc900c8d0000, 0xc960c93, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc4b, 0x0, 0xc9900000000, 0x0, 0x0, 0x0, 0xca200000c9f, 0xca800000ca5, 0xcae00000cab, 0xcb400000cb1, 0xcba00000cb7, 0xcc000000cbd, 0xcc600000cc30000, 0xcc90000, 0x0, 0xcd200000ccf0ccc, 0xcdb0cd800000cd5, 0xce10cde0000, 0xce70ce4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcea000000000c9c, 0xcf30cf00ced, 0xcf600000000, 0x124b125d0fb71241, 0x13270e290d831043, 0xe4f12930e991327, 0x116710cd0f550e97, 0x1279121511fd11e3, 0x109d106910190feb, 0xd8d12f3128911c7, 0x11e110790ff50e1d, 0x11d910510edb1309, 0x120311890f65121d, 0x108d10250fbd0eff, 0xe050dd90d9d127d, 0x10d310770ff10f95, 0x125911e711dd1171, 0x10e9130712fb12cf, 0x12a111b9114d1107, 0xf0b0e87122f130b, 0x10ed1083117d112f, 0xecb0e8512cb1249, 0x11471047102f0fed, 0x117f0e0312b11159, 0x114f11150ddd0ddf, 0xf67123d12b511c5, 0xebb0d8712350feb, 0xe1110c110950f27, 0xd7f0f1b0da510f1, 0xe2311450f9d1011, 0x122711c910d70e7d, 0xf6f100d126d1005, 0xd9110bf0f7b11a5, 0x113d0fdb0ddb0dc3, 0xe091291122d1195, 0xfa10f070e9f0e37, 0x12f712ab10f31053, 0xfb50df91313130d, 0xf490ef312690ffd, 0x106d104b0f910f57, 0x11791153111110af, 0x12a3127111cd1261, 0x10670e410dfb0de9, 0xf230efd1227120b, 0x1091112d10030f77, 0xee50ebb0e670d97, 0x116b10a9109b0f29, 0x12d112c912951175, 0x128d110f0d9f12dd, 0xdb10d8f0f3512c1, 0xfeb0f9f0ec70ebd, 0x127711d310cb1073, 0xdf712af0fad1323, 0x103b10210fd10fcb, 0x114310e710bd10a1, 0x12b70f5d0dc512e3, 0x126310310ed70da9, 0x10950fd50f390f17, 0xecf0e310deb12bb, 0x10150fe10fc30fa7, 0x120d116310c3109f, 0xe1312c5128f1213, 0x10b110750e33103d, 0x130f12ff12bd11db, 0x1121118b102d0fcf, 0x1063108b11331125, 0xded11ad0d93123b, 0x11390f690ef50de7, 0x12670fb3101b0eb5, 0xf03122112b31205, 0xe590db5, 0xfab00000e7b, 0x10cf108f0de10000, 0x110d1105110310f5, 0x116d113512d3, 0x1233000011df, 0x128312730000, 0x12e912e700000000, 0x12bf127f130512eb, 0xe010db90db30da1, 0xe5f0e530e170e07, 0xecd0e7f0e790e63, 0xf470f430f2f0ed1, 0xfaf0fa30f970f53, 0x1049103510270fdd, 0x10eb10a3107d106f, 0x10fd10f910fb10f7, 0x110b1109110110ff, 0x11531127111d1117, 0x11731161115b1157, 0x11cb11971197118d, 0x1239123712231219, 0x1273126f124f124d, 0xf2b12e112d912c7, 0x119313be, 0xd9b0dc10dd70d81, 0xe0b0dff0dc90db7, 0xe5d0e510e490e53, 0xe9b0e950e830e7b, 0xf050f010eb10ea9, 0xf3f0f330f1d0f13, 0xf530f410f470f37, 0xf890f850f7f0f5f, 0xfbf0fbd0fab0f99, 0x102110050fff0fc7, 0x1057104910411045, 0x1089107f10e3106f, 0x10b910b510ab108f, 0x10d110cf10c910c7, 0x10ef10dd10df10d5, 0x114911311127111f, 0x11af1173115f1153, 0x121f121b11f911c3, 0x122b123312291223, 0x1239123112351237, 0x12751265124f123f, 0x12c712b91299128b, 0x12db12d912d512d3, 0x1394132712f912e1, 0xd370d2313a61392, 0x141c13ec13da0d39, 0x13251321, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xabb00000a7a0000, 0x0, 0x0, 0xab50ab200000000, 0xa590a560aae0aaa, 0xa680a650a5f0a5c, 0xa740a710a6b, 0xa830a800a7d0a77, 0xa8c00000a89, 0xa9500000a920a8f, 0xaa10a9e00000a98, 0xa6e0ab80aa70aa4, 0xa9b0a860a62, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x132900000000, 0x132c, 0x0, 0x0, 0x132f000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1335133200000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x133b133800000000, 0x134a13461342133e, 0x134e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1352000000000000, 0x135913601355135d, 0x1364, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13680d8b0d850d89, 0xda70da30da10d99, 0xdaf0db30dad0dab, 0xdbb0db913700cf9, 0xcfb136a0dc70dbd, 0xdd1136e0dcb0dbf, 0xdd70dd50d950dd3, 0xcff0de50de3142c, 0xdf50df30df10def, 0xe070e010dff0d01, 0xe110e0f0e0d0e0b, 0xe1b0e190e170e15, 0xe210e210e210e1f, 0xe270e25105d1376, 0xe2f0e2d0e2b1378, 0xe3b0e390e350e3d, 0xe470e450e430e3f, 0xe510e4d0e4d0e4b, 0xe690e5b0e570e55, 0xe650e610e6b0e5f, 0xe710e6f0e890de7, 0xe750e770e6d0e73, 0xe8d0e8b137a0e81, 0xe9d0e930e910e8f, 0xea50ea3137e137c, 0xd030eab0ea10ea7, 0xeb30eb30eaf0d05, 0xebb0eb90eb71380, 0xec30ec113820ebf, 0xec90d070ec50f0f, 0x13860ed30ed50ed1, 0xedd0edf13880ed9, 0xd090ee90ee70ee1, 0xef10eef0eed0eeb, 0xef70d0d138a0d0b, 0x14400eff0efb0ef9, 0x118f138e138e0f09, 0x139c0d0f0f0d0f0d, 0xd110f150f1113f0, 0xf250f210f1f0f19, 0xf2f0d130d150f2d, 0xf3d0f3b0f311390, 0xf470f450f3d0f3f, 0xf510f4d0f4b0f4f, 0xf5b0f590f550f53, 0xf730f6b0f630f61, 0xf750f6d0f711396, 0xf8713980f830f79, 0xf8b0d170f7d0f81, 0xd190f8d0f930f8f, 0xfa5139a0f9b0f97, 0xfaf0d1f0fa90fb9, 0xdcf0dcd0d1b0d1d, 0xd5111810fb10fbb, 0xfc90fc10fbf0fbd, 0xfd30d2113a40fc5, 0x13a80fdd0fd90fcd, 0xd230fe30fd70fdf, 0xfef0fe90fe70fe5, 0xff70d250ff313aa, 0xffb0d270ff913ac, 0x13ae100710051001, 0x13b2100913b01384, 0x1017100b1013100f, 0x102310211027101f, 0x101d13b4102b1029, 0x10410d2910391037, 0x104d103313b6103f, 0x1059104f13ba13b8, 0x105b0d2b10551057, 0x136c1065105f1061, 0x13c0107113bc106b, 0x13c21081107f107b, 0x13c613c410871085, 0x10990d2d10971093, 0x10a710a50d2f0d2f, 0xd3110b310ad10ab, 0x13ca10bb13c810b7, 0x13cc10c5138c10c1, 0xd350d3313d013ce, 0x13d613d213d410d5, 0x10db10db10d913d8, 0xd3b10e10d3910df, 0x10e910e513dc0d3d, 0x10ff13de0d3f10ef, 0x1113110d13e213e0, 0x111b111911170d41, 0x112313e613e613e4, 0x112b112913e80d43, 0xd47113713ea0d45, 0x13ee1141113b113f, 0x115511510d49114b, 0x13f413f20d4b115d, 0x13f8116513f60d4d, 0x13fa1173116f1169, 0x117b13fe117713fc, 0x118511830d4f139e, 0x14000ead11870d53, 0x118f13a213a01402, 0x119b0d55126b1191, 0x119f0dfd119d1199, 0x140411a711a311a1, 0x11b511b311a911a5, 0x11cb11c111b711ab, 0x11bf11bd11bb11b1, 0xd571408140a1406, 0x141211d511d111cf, 0xd5b0d59140c11d7, 0x11e50d5d1410140e, 0x11ef11eb11e911e7, 0x11f911f111f311ed, 0xd5f11fb11f711f5, 0x12070d61120111ff, 0x1211120f14141209, 0x14160cfd12170d63, 0x12250d670d651418, 0x141a1243123f1231, 0x1253125112471245, 0x125512571372141e, 0x1265125f1374125b, 0x1281127b14221420, 0x1297128714241285, 0x12a5129b129f129d, 0xd6912a9142612a7, 0x12c30d6b142812ad, 0x142e142a12cd0ee3, 0x143012d70d6f0d6d, 0x12db12db14320d71, 0xd7312e5143412df, 0x12f512f112ef12ed, 0x12fd12f914360d75, 0x13030d790d771301, 0x143c143a0d7b1438, 0x13150d7d1311143e, 0x131d131b13191317, 0x1442131f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); @property { private alias _IDCA = immutable(dchar[]); _IDCA decompCanonTable() { static _IDCA t = [ 0x0, 0x3b, 0x0, 0x3c, 0x338, 0x0, 0x3d, 0x338, 0x0, 0x3e, 0x338, 0x0, 0x41, 0x300, 0x0, 0x41, 0x301, 0x0, 0x41, 0x302, 0x0, 0x41, 0x302, 0x300, 0x0, 0x41, 0x302, 0x301, 0x0, 0x41, 0x302, 0x303, 0x0, 0x41, 0x302, 0x309, 0x0, 0x41, 0x303, 0x0, 0x41, 0x304, 0x0, 0x41, 0x306, 0x0, 0x41, 0x306, 0x300, 0x0, 0x41, 0x306, 0x301, 0x0, 0x41, 0x306, 0x303, 0x0, 0x41, 0x306, 0x309, 0x0, 0x41, 0x307, 0x0, 0x41, 0x307, 0x304, 0x0, 0x41, 0x308, 0x0, 0x41, 0x308, 0x304, 0x0, 0x41, 0x309, 0x0, 0x41, 0x30a, 0x0, 0x41, 0x30a, 0x301, 0x0, 0x41, 0x30c, 0x0, 0x41, 0x30f, 0x0, 0x41, 0x311, 0x0, 0x41, 0x323, 0x0, 0x41, 0x323, 0x302, 0x0, 0x41, 0x323, 0x306, 0x0, 0x41, 0x325, 0x0, 0x41, 0x328, 0x0, 0x42, 0x307, 0x0, 0x42, 0x323, 0x0, 0x42, 0x331, 0x0, 0x43, 0x301, 0x0, 0x43, 0x302, 0x0, 0x43, 0x307, 0x0, 0x43, 0x30c, 0x0, 0x43, 0x327, 0x0, 0x43, 0x327, 0x301, 0x0, 0x44, 0x307, 0x0, 0x44, 0x30c, 0x0, 0x44, 0x323, 0x0, 0x44, 0x327, 0x0, 0x44, 0x32d, 0x0, 0x44, 0x331, 0x0, 0x45, 0x300, 0x0, 0x45, 0x301, 0x0, 0x45, 0x302, 0x0, 0x45, 0x302, 0x300, 0x0, 0x45, 0x302, 0x301, 0x0, 0x45, 0x302, 0x303, 0x0, 0x45, 0x302, 0x309, 0x0, 0x45, 0x303, 0x0, 0x45, 0x304, 0x0, 0x45, 0x304, 0x300, 0x0, 0x45, 0x304, 0x301, 0x0, 0x45, 0x306, 0x0, 0x45, 0x307, 0x0, 0x45, 0x308, 0x0, 0x45, 0x309, 0x0, 0x45, 0x30c, 0x0, 0x45, 0x30f, 0x0, 0x45, 0x311, 0x0, 0x45, 0x323, 0x0, 0x45, 0x323, 0x302, 0x0, 0x45, 0x327, 0x0, 0x45, 0x327, 0x306, 0x0, 0x45, 0x328, 0x0, 0x45, 0x32d, 0x0, 0x45, 0x330, 0x0, 0x46, 0x307, 0x0, 0x47, 0x301, 0x0, 0x47, 0x302, 0x0, 0x47, 0x304, 0x0, 0x47, 0x306, 0x0, 0x47, 0x307, 0x0, 0x47, 0x30c, 0x0, 0x47, 0x327, 0x0, 0x48, 0x302, 0x0, 0x48, 0x307, 0x0, 0x48, 0x308, 0x0, 0x48, 0x30c, 0x0, 0x48, 0x323, 0x0, 0x48, 0x327, 0x0, 0x48, 0x32e, 0x0, 0x49, 0x300, 0x0, 0x49, 0x301, 0x0, 0x49, 0x302, 0x0, 0x49, 0x303, 0x0, 0x49, 0x304, 0x0, 0x49, 0x306, 0x0, 0x49, 0x307, 0x0, 0x49, 0x308, 0x0, 0x49, 0x308, 0x301, 0x0, 0x49, 0x309, 0x0, 0x49, 0x30c, 0x0, 0x49, 0x30f, 0x0, 0x49, 0x311, 0x0, 0x49, 0x323, 0x0, 0x49, 0x328, 0x0, 0x49, 0x330, 0x0, 0x4a, 0x302, 0x0, 0x4b, 0x0, 0x4b, 0x301, 0x0, 0x4b, 0x30c, 0x0, 0x4b, 0x323, 0x0, 0x4b, 0x327, 0x0, 0x4b, 0x331, 0x0, 0x4c, 0x301, 0x0, 0x4c, 0x30c, 0x0, 0x4c, 0x323, 0x0, 0x4c, 0x323, 0x304, 0x0, 0x4c, 0x327, 0x0, 0x4c, 0x32d, 0x0, 0x4c, 0x331, 0x0, 0x4d, 0x301, 0x0, 0x4d, 0x307, 0x0, 0x4d, 0x323, 0x0, 0x4e, 0x300, 0x0, 0x4e, 0x301, 0x0, 0x4e, 0x303, 0x0, 0x4e, 0x307, 0x0, 0x4e, 0x30c, 0x0, 0x4e, 0x323, 0x0, 0x4e, 0x327, 0x0, 0x4e, 0x32d, 0x0, 0x4e, 0x331, 0x0, 0x4f, 0x300, 0x0, 0x4f, 0x301, 0x0, 0x4f, 0x302, 0x0, 0x4f, 0x302, 0x300, 0x0, 0x4f, 0x302, 0x301, 0x0, 0x4f, 0x302, 0x303, 0x0, 0x4f, 0x302, 0x309, 0x0, 0x4f, 0x303, 0x0, 0x4f, 0x303, 0x301, 0x0, 0x4f, 0x303, 0x304, 0x0, 0x4f, 0x303, 0x308, 0x0, 0x4f, 0x304, 0x0, 0x4f, 0x304, 0x300, 0x0, 0x4f, 0x304, 0x301, 0x0, 0x4f, 0x306, 0x0, 0x4f, 0x307, 0x0, 0x4f, 0x307, 0x304, 0x0, 0x4f, 0x308, 0x0, 0x4f, 0x308, 0x304, 0x0, 0x4f, 0x309, 0x0, 0x4f, 0x30b, 0x0, 0x4f, 0x30c, 0x0, 0x4f, 0x30f, 0x0, 0x4f, 0x311, 0x0, 0x4f, 0x31b, 0x0, 0x4f, 0x31b, 0x300, 0x0, 0x4f, 0x31b, 0x301, 0x0, 0x4f, 0x31b, 0x303, 0x0, 0x4f, 0x31b, 0x309, 0x0, 0x4f, 0x31b, 0x323, 0x0, 0x4f, 0x323, 0x0, 0x4f, 0x323, 0x302, 0x0, 0x4f, 0x328, 0x0, 0x4f, 0x328, 0x304, 0x0, 0x50, 0x301, 0x0, 0x50, 0x307, 0x0, 0x52, 0x301, 0x0, 0x52, 0x307, 0x0, 0x52, 0x30c, 0x0, 0x52, 0x30f, 0x0, 0x52, 0x311, 0x0, 0x52, 0x323, 0x0, 0x52, 0x323, 0x304, 0x0, 0x52, 0x327, 0x0, 0x52, 0x331, 0x0, 0x53, 0x301, 0x0, 0x53, 0x301, 0x307, 0x0, 0x53, 0x302, 0x0, 0x53, 0x307, 0x0, 0x53, 0x30c, 0x0, 0x53, 0x30c, 0x307, 0x0, 0x53, 0x323, 0x0, 0x53, 0x323, 0x307, 0x0, 0x53, 0x326, 0x0, 0x53, 0x327, 0x0, 0x54, 0x307, 0x0, 0x54, 0x30c, 0x0, 0x54, 0x323, 0x0, 0x54, 0x326, 0x0, 0x54, 0x327, 0x0, 0x54, 0x32d, 0x0, 0x54, 0x331, 0x0, 0x55, 0x300, 0x0, 0x55, 0x301, 0x0, 0x55, 0x302, 0x0, 0x55, 0x303, 0x0, 0x55, 0x303, 0x301, 0x0, 0x55, 0x304, 0x0, 0x55, 0x304, 0x308, 0x0, 0x55, 0x306, 0x0, 0x55, 0x308, 0x0, 0x55, 0x308, 0x300, 0x0, 0x55, 0x308, 0x301, 0x0, 0x55, 0x308, 0x304, 0x0, 0x55, 0x308, 0x30c, 0x0, 0x55, 0x309, 0x0, 0x55, 0x30a, 0x0, 0x55, 0x30b, 0x0, 0x55, 0x30c, 0x0, 0x55, 0x30f, 0x0, 0x55, 0x311, 0x0, 0x55, 0x31b, 0x0, 0x55, 0x31b, 0x300, 0x0, 0x55, 0x31b, 0x301, 0x0, 0x55, 0x31b, 0x303, 0x0, 0x55, 0x31b, 0x309, 0x0, 0x55, 0x31b, 0x323, 0x0, 0x55, 0x323, 0x0, 0x55, 0x324, 0x0, 0x55, 0x328, 0x0, 0x55, 0x32d, 0x0, 0x55, 0x330, 0x0, 0x56, 0x303, 0x0, 0x56, 0x323, 0x0, 0x57, 0x300, 0x0, 0x57, 0x301, 0x0, 0x57, 0x302, 0x0, 0x57, 0x307, 0x0, 0x57, 0x308, 0x0, 0x57, 0x323, 0x0, 0x58, 0x307, 0x0, 0x58, 0x308, 0x0, 0x59, 0x300, 0x0, 0x59, 0x301, 0x0, 0x59, 0x302, 0x0, 0x59, 0x303, 0x0, 0x59, 0x304, 0x0, 0x59, 0x307, 0x0, 0x59, 0x308, 0x0, 0x59, 0x309, 0x0, 0x59, 0x323, 0x0, 0x5a, 0x301, 0x0, 0x5a, 0x302, 0x0, 0x5a, 0x307, 0x0, 0x5a, 0x30c, 0x0, 0x5a, 0x323, 0x0, 0x5a, 0x331, 0x0, 0x60, 0x0, 0x61, 0x300, 0x0, 0x61, 0x301, 0x0, 0x61, 0x302, 0x0, 0x61, 0x302, 0x300, 0x0, 0x61, 0x302, 0x301, 0x0, 0x61, 0x302, 0x303, 0x0, 0x61, 0x302, 0x309, 0x0, 0x61, 0x303, 0x0, 0x61, 0x304, 0x0, 0x61, 0x306, 0x0, 0x61, 0x306, 0x300, 0x0, 0x61, 0x306, 0x301, 0x0, 0x61, 0x306, 0x303, 0x0, 0x61, 0x306, 0x309, 0x0, 0x61, 0x307, 0x0, 0x61, 0x307, 0x304, 0x0, 0x61, 0x308, 0x0, 0x61, 0x308, 0x304, 0x0, 0x61, 0x309, 0x0, 0x61, 0x30a, 0x0, 0x61, 0x30a, 0x301, 0x0, 0x61, 0x30c, 0x0, 0x61, 0x30f, 0x0, 0x61, 0x311, 0x0, 0x61, 0x323, 0x0, 0x61, 0x323, 0x302, 0x0, 0x61, 0x323, 0x306, 0x0, 0x61, 0x325, 0x0, 0x61, 0x328, 0x0, 0x62, 0x307, 0x0, 0x62, 0x323, 0x0, 0x62, 0x331, 0x0, 0x63, 0x301, 0x0, 0x63, 0x302, 0x0, 0x63, 0x307, 0x0, 0x63, 0x30c, 0x0, 0x63, 0x327, 0x0, 0x63, 0x327, 0x301, 0x0, 0x64, 0x307, 0x0, 0x64, 0x30c, 0x0, 0x64, 0x323, 0x0, 0x64, 0x327, 0x0, 0x64, 0x32d, 0x0, 0x64, 0x331, 0x0, 0x65, 0x300, 0x0, 0x65, 0x301, 0x0, 0x65, 0x302, 0x0, 0x65, 0x302, 0x300, 0x0, 0x65, 0x302, 0x301, 0x0, 0x65, 0x302, 0x303, 0x0, 0x65, 0x302, 0x309, 0x0, 0x65, 0x303, 0x0, 0x65, 0x304, 0x0, 0x65, 0x304, 0x300, 0x0, 0x65, 0x304, 0x301, 0x0, 0x65, 0x306, 0x0, 0x65, 0x307, 0x0, 0x65, 0x308, 0x0, 0x65, 0x309, 0x0, 0x65, 0x30c, 0x0, 0x65, 0x30f, 0x0, 0x65, 0x311, 0x0, 0x65, 0x323, 0x0, 0x65, 0x323, 0x302, 0x0, 0x65, 0x327, 0x0, 0x65, 0x327, 0x306, 0x0, 0x65, 0x328, 0x0, 0x65, 0x32d, 0x0, 0x65, 0x330, 0x0, 0x66, 0x307, 0x0, 0x67, 0x301, 0x0, 0x67, 0x302, 0x0, 0x67, 0x304, 0x0, 0x67, 0x306, 0x0, 0x67, 0x307, 0x0, 0x67, 0x30c, 0x0, 0x67, 0x327, 0x0, 0x68, 0x302, 0x0, 0x68, 0x307, 0x0, 0x68, 0x308, 0x0, 0x68, 0x30c, 0x0, 0x68, 0x323, 0x0, 0x68, 0x327, 0x0, 0x68, 0x32e, 0x0, 0x68, 0x331, 0x0, 0x69, 0x300, 0x0, 0x69, 0x301, 0x0, 0x69, 0x302, 0x0, 0x69, 0x303, 0x0, 0x69, 0x304, 0x0, 0x69, 0x306, 0x0, 0x69, 0x308, 0x0, 0x69, 0x308, 0x301, 0x0, 0x69, 0x309, 0x0, 0x69, 0x30c, 0x0, 0x69, 0x30f, 0x0, 0x69, 0x311, 0x0, 0x69, 0x323, 0x0, 0x69, 0x328, 0x0, 0x69, 0x330, 0x0, 0x6a, 0x302, 0x0, 0x6a, 0x30c, 0x0, 0x6b, 0x301, 0x0, 0x6b, 0x30c, 0x0, 0x6b, 0x323, 0x0, 0x6b, 0x327, 0x0, 0x6b, 0x331, 0x0, 0x6c, 0x301, 0x0, 0x6c, 0x30c, 0x0, 0x6c, 0x323, 0x0, 0x6c, 0x323, 0x304, 0x0, 0x6c, 0x327, 0x0, 0x6c, 0x32d, 0x0, 0x6c, 0x331, 0x0, 0x6d, 0x301, 0x0, 0x6d, 0x307, 0x0, 0x6d, 0x323, 0x0, 0x6e, 0x300, 0x0, 0x6e, 0x301, 0x0, 0x6e, 0x303, 0x0, 0x6e, 0x307, 0x0, 0x6e, 0x30c, 0x0, 0x6e, 0x323, 0x0, 0x6e, 0x327, 0x0, 0x6e, 0x32d, 0x0, 0x6e, 0x331, 0x0, 0x6f, 0x300, 0x0, 0x6f, 0x301, 0x0, 0x6f, 0x302, 0x0, 0x6f, 0x302, 0x300, 0x0, 0x6f, 0x302, 0x301, 0x0, 0x6f, 0x302, 0x303, 0x0, 0x6f, 0x302, 0x309, 0x0, 0x6f, 0x303, 0x0, 0x6f, 0x303, 0x301, 0x0, 0x6f, 0x303, 0x304, 0x0, 0x6f, 0x303, 0x308, 0x0, 0x6f, 0x304, 0x0, 0x6f, 0x304, 0x300, 0x0, 0x6f, 0x304, 0x301, 0x0, 0x6f, 0x306, 0x0, 0x6f, 0x307, 0x0, 0x6f, 0x307, 0x304, 0x0, 0x6f, 0x308, 0x0, 0x6f, 0x308, 0x304, 0x0, 0x6f, 0x309, 0x0, 0x6f, 0x30b, 0x0, 0x6f, 0x30c, 0x0, 0x6f, 0x30f, 0x0, 0x6f, 0x311, 0x0, 0x6f, 0x31b, 0x0, 0x6f, 0x31b, 0x300, 0x0, 0x6f, 0x31b, 0x301, 0x0, 0x6f, 0x31b, 0x303, 0x0, 0x6f, 0x31b, 0x309, 0x0, 0x6f, 0x31b, 0x323, 0x0, 0x6f, 0x323, 0x0, 0x6f, 0x323, 0x302, 0x0, 0x6f, 0x328, 0x0, 0x6f, 0x328, 0x304, 0x0, 0x70, 0x301, 0x0, 0x70, 0x307, 0x0, 0x72, 0x301, 0x0, 0x72, 0x307, 0x0, 0x72, 0x30c, 0x0, 0x72, 0x30f, 0x0, 0x72, 0x311, 0x0, 0x72, 0x323, 0x0, 0x72, 0x323, 0x304, 0x0, 0x72, 0x327, 0x0, 0x72, 0x331, 0x0, 0x73, 0x301, 0x0, 0x73, 0x301, 0x307, 0x0, 0x73, 0x302, 0x0, 0x73, 0x307, 0x0, 0x73, 0x30c, 0x0, 0x73, 0x30c, 0x307, 0x0, 0x73, 0x323, 0x0, 0x73, 0x323, 0x307, 0x0, 0x73, 0x326, 0x0, 0x73, 0x327, 0x0, 0x74, 0x307, 0x0, 0x74, 0x308, 0x0, 0x74, 0x30c, 0x0, 0x74, 0x323, 0x0, 0x74, 0x326, 0x0, 0x74, 0x327, 0x0, 0x74, 0x32d, 0x0, 0x74, 0x331, 0x0, 0x75, 0x300, 0x0, 0x75, 0x301, 0x0, 0x75, 0x302, 0x0, 0x75, 0x303, 0x0, 0x75, 0x303, 0x301, 0x0, 0x75, 0x304, 0x0, 0x75, 0x304, 0x308, 0x0, 0x75, 0x306, 0x0, 0x75, 0x308, 0x0, 0x75, 0x308, 0x300, 0x0, 0x75, 0x308, 0x301, 0x0, 0x75, 0x308, 0x304, 0x0, 0x75, 0x308, 0x30c, 0x0, 0x75, 0x309, 0x0, 0x75, 0x30a, 0x0, 0x75, 0x30b, 0x0, 0x75, 0x30c, 0x0, 0x75, 0x30f, 0x0, 0x75, 0x311, 0x0, 0x75, 0x31b, 0x0, 0x75, 0x31b, 0x300, 0x0, 0x75, 0x31b, 0x301, 0x0, 0x75, 0x31b, 0x303, 0x0, 0x75, 0x31b, 0x309, 0x0, 0x75, 0x31b, 0x323, 0x0, 0x75, 0x323, 0x0, 0x75, 0x324, 0x0, 0x75, 0x328, 0x0, 0x75, 0x32d, 0x0, 0x75, 0x330, 0x0, 0x76, 0x303, 0x0, 0x76, 0x323, 0x0, 0x77, 0x300, 0x0, 0x77, 0x301, 0x0, 0x77, 0x302, 0x0, 0x77, 0x307, 0x0, 0x77, 0x308, 0x0, 0x77, 0x30a, 0x0, 0x77, 0x323, 0x0, 0x78, 0x307, 0x0, 0x78, 0x308, 0x0, 0x79, 0x300, 0x0, 0x79, 0x301, 0x0, 0x79, 0x302, 0x0, 0x79, 0x303, 0x0, 0x79, 0x304, 0x0, 0x79, 0x307, 0x0, 0x79, 0x308, 0x0, 0x79, 0x309, 0x0, 0x79, 0x30a, 0x0, 0x79, 0x323, 0x0, 0x7a, 0x301, 0x0, 0x7a, 0x302, 0x0, 0x7a, 0x307, 0x0, 0x7a, 0x30c, 0x0, 0x7a, 0x323, 0x0, 0x7a, 0x331, 0x0, 0xa8, 0x300, 0x0, 0xa8, 0x301, 0x0, 0xa8, 0x342, 0x0, 0xb4, 0x0, 0xb7, 0x0, 0xc6, 0x301, 0x0, 0xc6, 0x304, 0x0, 0xd8, 0x301, 0x0, 0xe6, 0x301, 0x0, 0xe6, 0x304, 0x0, 0xf8, 0x301, 0x0, 0x17f, 0x307, 0x0, 0x1b7, 0x30c, 0x0, 0x292, 0x30c, 0x0, 0x2b9, 0x0, 0x300, 0x0, 0x301, 0x0, 0x308, 0x301, 0x0, 0x313, 0x0, 0x391, 0x300, 0x0, 0x391, 0x301, 0x0, 0x391, 0x304, 0x0, 0x391, 0x306, 0x0, 0x391, 0x313, 0x0, 0x391, 0x313, 0x300, 0x0, 0x391, 0x313, 0x300, 0x345, 0x0, 0x391, 0x313, 0x301, 0x0, 0x391, 0x313, 0x301, 0x345, 0x0, 0x391, 0x313, 0x342, 0x0, 0x391, 0x313, 0x342, 0x345, 0x0, 0x391, 0x313, 0x345, 0x0, 0x391, 0x314, 0x0, 0x391, 0x314, 0x300, 0x0, 0x391, 0x314, 0x300, 0x345, 0x0, 0x391, 0x314, 0x301, 0x0, 0x391, 0x314, 0x301, 0x345, 0x0, 0x391, 0x314, 0x342, 0x0, 0x391, 0x314, 0x342, 0x345, 0x0, 0x391, 0x314, 0x345, 0x0, 0x391, 0x345, 0x0, 0x395, 0x300, 0x0, 0x395, 0x301, 0x0, 0x395, 0x313, 0x0, 0x395, 0x313, 0x300, 0x0, 0x395, 0x313, 0x301, 0x0, 0x395, 0x314, 0x0, 0x395, 0x314, 0x300, 0x0, 0x395, 0x314, 0x301, 0x0, 0x397, 0x300, 0x0, 0x397, 0x301, 0x0, 0x397, 0x313, 0x0, 0x397, 0x313, 0x300, 0x0, 0x397, 0x313, 0x300, 0x345, 0x0, 0x397, 0x313, 0x301, 0x0, 0x397, 0x313, 0x301, 0x345, 0x0, 0x397, 0x313, 0x342, 0x0, 0x397, 0x313, 0x342, 0x345, 0x0, 0x397, 0x313, 0x345, 0x0, 0x397, 0x314, 0x0, 0x397, 0x314, 0x300, 0x0, 0x397, 0x314, 0x300, 0x345, 0x0, 0x397, 0x314, 0x301, 0x0, 0x397, 0x314, 0x301, 0x345, 0x0, 0x397, 0x314, 0x342, 0x0, 0x397, 0x314, 0x342, 0x345, 0x0, 0x397, 0x314, 0x345, 0x0, 0x397, 0x345, 0x0, 0x399, 0x300, 0x0, 0x399, 0x301, 0x0, 0x399, 0x304, 0x0, 0x399, 0x306, 0x0, 0x399, 0x308, 0x0, 0x399, 0x313, 0x0, 0x399, 0x313, 0x300, 0x0, 0x399, 0x313, 0x301, 0x0, 0x399, 0x313, 0x342, 0x0, 0x399, 0x314, 0x0, 0x399, 0x314, 0x300, 0x0, 0x399, 0x314, 0x301, 0x0, 0x399, 0x314, 0x342, 0x0, 0x39f, 0x300, 0x0, 0x39f, 0x301, 0x0, 0x39f, 0x313, 0x0, 0x39f, 0x313, 0x300, 0x0, 0x39f, 0x313, 0x301, 0x0, 0x39f, 0x314, 0x0, 0x39f, 0x314, 0x300, 0x0, 0x39f, 0x314, 0x301, 0x0, 0x3a1, 0x314, 0x0, 0x3a5, 0x300, 0x0, 0x3a5, 0x301, 0x0, 0x3a5, 0x304, 0x0, 0x3a5, 0x306, 0x0, 0x3a5, 0x308, 0x0, 0x3a5, 0x314, 0x0, 0x3a5, 0x314, 0x300, 0x0, 0x3a5, 0x314, 0x301, 0x0, 0x3a5, 0x314, 0x342, 0x0, 0x3a9, 0x0, 0x3a9, 0x300, 0x0, 0x3a9, 0x301, 0x0, 0x3a9, 0x313, 0x0, 0x3a9, 0x313, 0x300, 0x0, 0x3a9, 0x313, 0x300, 0x345, 0x0, 0x3a9, 0x313, 0x301, 0x0, 0x3a9, 0x313, 0x301, 0x345, 0x0, 0x3a9, 0x313, 0x342, 0x0, 0x3a9, 0x313, 0x342, 0x345, 0x0, 0x3a9, 0x313, 0x345, 0x0, 0x3a9, 0x314, 0x0, 0x3a9, 0x314, 0x300, 0x0, 0x3a9, 0x314, 0x300, 0x345, 0x0, 0x3a9, 0x314, 0x301, 0x0, 0x3a9, 0x314, 0x301, 0x345, 0x0, 0x3a9, 0x314, 0x342, 0x0, 0x3a9, 0x314, 0x342, 0x345, 0x0, 0x3a9, 0x314, 0x345, 0x0, 0x3a9, 0x345, 0x0, 0x3b1, 0x300, 0x0, 0x3b1, 0x300, 0x345, 0x0, 0x3b1, 0x301, 0x0, 0x3b1, 0x301, 0x345, 0x0, 0x3b1, 0x304, 0x0, 0x3b1, 0x306, 0x0, 0x3b1, 0x313, 0x0, 0x3b1, 0x313, 0x300, 0x0, 0x3b1, 0x313, 0x300, 0x345, 0x0, 0x3b1, 0x313, 0x301, 0x0, 0x3b1, 0x313, 0x301, 0x345, 0x0, 0x3b1, 0x313, 0x342, 0x0, 0x3b1, 0x313, 0x342, 0x345, 0x0, 0x3b1, 0x313, 0x345, 0x0, 0x3b1, 0x314, 0x0, 0x3b1, 0x314, 0x300, 0x0, 0x3b1, 0x314, 0x300, 0x345, 0x0, 0x3b1, 0x314, 0x301, 0x0, 0x3b1, 0x314, 0x301, 0x345, 0x0, 0x3b1, 0x314, 0x342, 0x0, 0x3b1, 0x314, 0x342, 0x345, 0x0, 0x3b1, 0x314, 0x345, 0x0, 0x3b1, 0x342, 0x0, 0x3b1, 0x342, 0x345, 0x0, 0x3b1, 0x345, 0x0, 0x3b5, 0x300, 0x0, 0x3b5, 0x301, 0x0, 0x3b5, 0x313, 0x0, 0x3b5, 0x313, 0x300, 0x0, 0x3b5, 0x313, 0x301, 0x0, 0x3b5, 0x314, 0x0, 0x3b5, 0x314, 0x300, 0x0, 0x3b5, 0x314, 0x301, 0x0, 0x3b7, 0x300, 0x0, 0x3b7, 0x300, 0x345, 0x0, 0x3b7, 0x301, 0x0, 0x3b7, 0x301, 0x345, 0x0, 0x3b7, 0x313, 0x0, 0x3b7, 0x313, 0x300, 0x0, 0x3b7, 0x313, 0x300, 0x345, 0x0, 0x3b7, 0x313, 0x301, 0x0, 0x3b7, 0x313, 0x301, 0x345, 0x0, 0x3b7, 0x313, 0x342, 0x0, 0x3b7, 0x313, 0x342, 0x345, 0x0, 0x3b7, 0x313, 0x345, 0x0, 0x3b7, 0x314, 0x0, 0x3b7, 0x314, 0x300, 0x0, 0x3b7, 0x314, 0x300, 0x345, 0x0, 0x3b7, 0x314, 0x301, 0x0, 0x3b7, 0x314, 0x301, 0x345, 0x0, 0x3b7, 0x314, 0x342, 0x0, 0x3b7, 0x314, 0x342, 0x345, 0x0, 0x3b7, 0x314, 0x345, 0x0, 0x3b7, 0x342, 0x0, 0x3b7, 0x342, 0x345, 0x0, 0x3b7, 0x345, 0x0, 0x3b9, 0x0, 0x3b9, 0x300, 0x0, 0x3b9, 0x301, 0x0, 0x3b9, 0x304, 0x0, 0x3b9, 0x306, 0x0, 0x3b9, 0x308, 0x0, 0x3b9, 0x308, 0x300, 0x0, 0x3b9, 0x308, 0x301, 0x0, 0x3b9, 0x308, 0x342, 0x0, 0x3b9, 0x313, 0x0, 0x3b9, 0x313, 0x300, 0x0, 0x3b9, 0x313, 0x301, 0x0, 0x3b9, 0x313, 0x342, 0x0, 0x3b9, 0x314, 0x0, 0x3b9, 0x314, 0x300, 0x0, 0x3b9, 0x314, 0x301, 0x0, 0x3b9, 0x314, 0x342, 0x0, 0x3b9, 0x342, 0x0, 0x3bf, 0x300, 0x0, 0x3bf, 0x301, 0x0, 0x3bf, 0x313, 0x0, 0x3bf, 0x313, 0x300, 0x0, 0x3bf, 0x313, 0x301, 0x0, 0x3bf, 0x314, 0x0, 0x3bf, 0x314, 0x300, 0x0, 0x3bf, 0x314, 0x301, 0x0, 0x3c1, 0x313, 0x0, 0x3c1, 0x314, 0x0, 0x3c5, 0x300, 0x0, 0x3c5, 0x301, 0x0, 0x3c5, 0x304, 0x0, 0x3c5, 0x306, 0x0, 0x3c5, 0x308, 0x0, 0x3c5, 0x308, 0x300, 0x0, 0x3c5, 0x308, 0x301, 0x0, 0x3c5, 0x308, 0x342, 0x0, 0x3c5, 0x313, 0x0, 0x3c5, 0x313, 0x300, 0x0, 0x3c5, 0x313, 0x301, 0x0, 0x3c5, 0x313, 0x342, 0x0, 0x3c5, 0x314, 0x0, 0x3c5, 0x314, 0x300, 0x0, 0x3c5, 0x314, 0x301, 0x0, 0x3c5, 0x314, 0x342, 0x0, 0x3c5, 0x342, 0x0, 0x3c9, 0x300, 0x0, 0x3c9, 0x300, 0x345, 0x0, 0x3c9, 0x301, 0x0, 0x3c9, 0x301, 0x345, 0x0, 0x3c9, 0x313, 0x0, 0x3c9, 0x313, 0x300, 0x0, 0x3c9, 0x313, 0x300, 0x345, 0x0, 0x3c9, 0x313, 0x301, 0x0, 0x3c9, 0x313, 0x301, 0x345, 0x0, 0x3c9, 0x313, 0x342, 0x0, 0x3c9, 0x313, 0x342, 0x345, 0x0, 0x3c9, 0x313, 0x345, 0x0, 0x3c9, 0x314, 0x0, 0x3c9, 0x314, 0x300, 0x0, 0x3c9, 0x314, 0x300, 0x345, 0x0, 0x3c9, 0x314, 0x301, 0x0, 0x3c9, 0x314, 0x301, 0x345, 0x0, 0x3c9, 0x314, 0x342, 0x0, 0x3c9, 0x314, 0x342, 0x345, 0x0, 0x3c9, 0x314, 0x345, 0x0, 0x3c9, 0x342, 0x0, 0x3c9, 0x342, 0x345, 0x0, 0x3c9, 0x345, 0x0, 0x3d2, 0x301, 0x0, 0x3d2, 0x308, 0x0, 0x406, 0x308, 0x0, 0x410, 0x306, 0x0, 0x410, 0x308, 0x0, 0x413, 0x301, 0x0, 0x415, 0x300, 0x0, 0x415, 0x306, 0x0, 0x415, 0x308, 0x0, 0x416, 0x306, 0x0, 0x416, 0x308, 0x0, 0x417, 0x308, 0x0, 0x418, 0x300, 0x0, 0x418, 0x304, 0x0, 0x418, 0x306, 0x0, 0x418, 0x308, 0x0, 0x41a, 0x301, 0x0, 0x41e, 0x308, 0x0, 0x423, 0x304, 0x0, 0x423, 0x306, 0x0, 0x423, 0x308, 0x0, 0x423, 0x30b, 0x0, 0x427, 0x308, 0x0, 0x42b, 0x308, 0x0, 0x42d, 0x308, 0x0, 0x430, 0x306, 0x0, 0x430, 0x308, 0x0, 0x433, 0x301, 0x0, 0x435, 0x300, 0x0, 0x435, 0x306, 0x0, 0x435, 0x308, 0x0, 0x436, 0x306, 0x0, 0x436, 0x308, 0x0, 0x437, 0x308, 0x0, 0x438, 0x300, 0x0, 0x438, 0x304, 0x0, 0x438, 0x306, 0x0, 0x438, 0x308, 0x0, 0x43a, 0x301, 0x0, 0x43e, 0x308, 0x0, 0x443, 0x304, 0x0, 0x443, 0x306, 0x0, 0x443, 0x308, 0x0, 0x443, 0x30b, 0x0, 0x447, 0x308, 0x0, 0x44b, 0x308, 0x0, 0x44d, 0x308, 0x0, 0x456, 0x308, 0x0, 0x474, 0x30f, 0x0, 0x475, 0x30f, 0x0, 0x4d8, 0x308, 0x0, 0x4d9, 0x308, 0x0, 0x4e8, 0x308, 0x0, 0x4e9, 0x308, 0x0, 0x5d0, 0x5b7, 0x0, 0x5d0, 0x5b8, 0x0, 0x5d0, 0x5bc, 0x0, 0x5d1, 0x5bc, 0x0, 0x5d1, 0x5bf, 0x0, 0x5d2, 0x5bc, 0x0, 0x5d3, 0x5bc, 0x0, 0x5d4, 0x5bc, 0x0, 0x5d5, 0x5b9, 0x0, 0x5d5, 0x5bc, 0x0, 0x5d6, 0x5bc, 0x0, 0x5d8, 0x5bc, 0x0, 0x5d9, 0x5b4, 0x0, 0x5d9, 0x5bc, 0x0, 0x5da, 0x5bc, 0x0, 0x5db, 0x5bc, 0x0, 0x5db, 0x5bf, 0x0, 0x5dc, 0x5bc, 0x0, 0x5de, 0x5bc, 0x0, 0x5e0, 0x5bc, 0x0, 0x5e1, 0x5bc, 0x0, 0x5e3, 0x5bc, 0x0, 0x5e4, 0x5bc, 0x0, 0x5e4, 0x5bf, 0x0, 0x5e6, 0x5bc, 0x0, 0x5e7, 0x5bc, 0x0, 0x5e8, 0x5bc, 0x0, 0x5e9, 0x5bc, 0x0, 0x5e9, 0x5bc, 0x5c1, 0x0, 0x5e9, 0x5bc, 0x5c2, 0x0, 0x5e9, 0x5c1, 0x0, 0x5e9, 0x5c2, 0x0, 0x5ea, 0x5bc, 0x0, 0x5f2, 0x5b7, 0x0, 0x627, 0x653, 0x0, 0x627, 0x654, 0x0, 0x627, 0x655, 0x0, 0x648, 0x654, 0x0, 0x64a, 0x654, 0x0, 0x6c1, 0x654, 0x0, 0x6d2, 0x654, 0x0, 0x6d5, 0x654, 0x0, 0x915, 0x93c, 0x0, 0x916, 0x93c, 0x0, 0x917, 0x93c, 0x0, 0x91c, 0x93c, 0x0, 0x921, 0x93c, 0x0, 0x922, 0x93c, 0x0, 0x928, 0x93c, 0x0, 0x92b, 0x93c, 0x0, 0x92f, 0x93c, 0x0, 0x930, 0x93c, 0x0, 0x933, 0x93c, 0x0, 0x9a1, 0x9bc, 0x0, 0x9a2, 0x9bc, 0x0, 0x9af, 0x9bc, 0x0, 0x9c7, 0x9be, 0x0, 0x9c7, 0x9d7, 0x0, 0xa16, 0xa3c, 0x0, 0xa17, 0xa3c, 0x0, 0xa1c, 0xa3c, 0x0, 0xa2b, 0xa3c, 0x0, 0xa32, 0xa3c, 0x0, 0xa38, 0xa3c, 0x0, 0xb21, 0xb3c, 0x0, 0xb22, 0xb3c, 0x0, 0xb47, 0xb3e, 0x0, 0xb47, 0xb56, 0x0, 0xb47, 0xb57, 0x0, 0xb92, 0xbd7, 0x0, 0xbc6, 0xbbe, 0x0, 0xbc6, 0xbd7, 0x0, 0xbc7, 0xbbe, 0x0, 0xc46, 0xc56, 0x0, 0xcbf, 0xcd5, 0x0, 0xcc6, 0xcc2, 0x0, 0xcc6, 0xcc2, 0xcd5, 0x0, 0xcc6, 0xcd5, 0x0, 0xcc6, 0xcd6, 0x0, 0xd46, 0xd3e, 0x0, 0xd46, 0xd57, 0x0, 0xd47, 0xd3e, 0x0, 0xdd9, 0xdca, 0x0, 0xdd9, 0xdcf, 0x0, 0xdd9, 0xdcf, 0xdca, 0x0, 0xdd9, 0xddf, 0x0, 0xf40, 0xfb5, 0x0, 0xf42, 0xfb7, 0x0, 0xf4c, 0xfb7, 0x0, 0xf51, 0xfb7, 0x0, 0xf56, 0xfb7, 0x0, 0xf5b, 0xfb7, 0x0, 0xf71, 0xf72, 0x0, 0xf71, 0xf74, 0x0, 0xf71, 0xf80, 0x0, 0xf90, 0xfb5, 0x0, 0xf92, 0xfb7, 0x0, 0xf9c, 0xfb7, 0x0, 0xfa1, 0xfb7, 0x0, 0xfa6, 0xfb7, 0x0, 0xfab, 0xfb7, 0x0, 0xfb2, 0xf80, 0x0, 0xfb3, 0xf80, 0x0, 0x1025, 0x102e, 0x0, 0x1b05, 0x1b35, 0x0, 0x1b07, 0x1b35, 0x0, 0x1b09, 0x1b35, 0x0, 0x1b0b, 0x1b35, 0x0, 0x1b0d, 0x1b35, 0x0, 0x1b11, 0x1b35, 0x0, 0x1b3a, 0x1b35, 0x0, 0x1b3c, 0x1b35, 0x0, 0x1b3e, 0x1b35, 0x0, 0x1b3f, 0x1b35, 0x0, 0x1b42, 0x1b35, 0x0, 0x1fbf, 0x300, 0x0, 0x1fbf, 0x301, 0x0, 0x1fbf, 0x342, 0x0, 0x1ffe, 0x300, 0x0, 0x1ffe, 0x301, 0x0, 0x1ffe, 0x342, 0x0, 0x2002, 0x0, 0x2003, 0x0, 0x2190, 0x338, 0x0, 0x2192, 0x338, 0x0, 0x2194, 0x338, 0x0, 0x21d0, 0x338, 0x0, 0x21d2, 0x338, 0x0, 0x21d4, 0x338, 0x0, 0x2203, 0x338, 0x0, 0x2208, 0x338, 0x0, 0x220b, 0x338, 0x0, 0x2223, 0x338, 0x0, 0x2225, 0x338, 0x0, 0x223c, 0x338, 0x0, 0x2243, 0x338, 0x0, 0x2245, 0x338, 0x0, 0x2248, 0x338, 0x0, 0x224d, 0x338, 0x0, 0x2261, 0x338, 0x0, 0x2264, 0x338, 0x0, 0x2265, 0x338, 0x0, 0x2272, 0x338, 0x0, 0x2273, 0x338, 0x0, 0x2276, 0x338, 0x0, 0x2277, 0x338, 0x0, 0x227a, 0x338, 0x0, 0x227b, 0x338, 0x0, 0x227c, 0x338, 0x0, 0x227d, 0x338, 0x0, 0x2282, 0x338, 0x0, 0x2283, 0x338, 0x0, 0x2286, 0x338, 0x0, 0x2287, 0x338, 0x0, 0x2291, 0x338, 0x0, 0x2292, 0x338, 0x0, 0x22a2, 0x338, 0x0, 0x22a8, 0x338, 0x0, 0x22a9, 0x338, 0x0, 0x22ab, 0x338, 0x0, 0x22b2, 0x338, 0x0, 0x22b3, 0x338, 0x0, 0x22b4, 0x338, 0x0, 0x22b5, 0x338, 0x0, 0x2add, 0x338, 0x0, 0x3008, 0x0, 0x3009, 0x0, 0x3046, 0x3099, 0x0, 0x304b, 0x3099, 0x0, 0x304d, 0x3099, 0x0, 0x304f, 0x3099, 0x0, 0x3051, 0x3099, 0x0, 0x3053, 0x3099, 0x0, 0x3055, 0x3099, 0x0, 0x3057, 0x3099, 0x0, 0x3059, 0x3099, 0x0, 0x305b, 0x3099, 0x0, 0x305d, 0x3099, 0x0, 0x305f, 0x3099, 0x0, 0x3061, 0x3099, 0x0, 0x3064, 0x3099, 0x0, 0x3066, 0x3099, 0x0, 0x3068, 0x3099, 0x0, 0x306f, 0x3099, 0x0, 0x306f, 0x309a, 0x0, 0x3072, 0x3099, 0x0, 0x3072, 0x309a, 0x0, 0x3075, 0x3099, 0x0, 0x3075, 0x309a, 0x0, 0x3078, 0x3099, 0x0, 0x3078, 0x309a, 0x0, 0x307b, 0x3099, 0x0, 0x307b, 0x309a, 0x0, 0x309d, 0x3099, 0x0, 0x30a6, 0x3099, 0x0, 0x30ab, 0x3099, 0x0, 0x30ad, 0x3099, 0x0, 0x30af, 0x3099, 0x0, 0x30b1, 0x3099, 0x0, 0x30b3, 0x3099, 0x0, 0x30b5, 0x3099, 0x0, 0x30b7, 0x3099, 0x0, 0x30b9, 0x3099, 0x0, 0x30bb, 0x3099, 0x0, 0x30bd, 0x3099, 0x0, 0x30bf, 0x3099, 0x0, 0x30c1, 0x3099, 0x0, 0x30c4, 0x3099, 0x0, 0x30c6, 0x3099, 0x0, 0x30c8, 0x3099, 0x0, 0x30cf, 0x3099, 0x0, 0x30cf, 0x309a, 0x0, 0x30d2, 0x3099, 0x0, 0x30d2, 0x309a, 0x0, 0x30d5, 0x3099, 0x0, 0x30d5, 0x309a, 0x0, 0x30d8, 0x3099, 0x0, 0x30d8, 0x309a, 0x0, 0x30db, 0x3099, 0x0, 0x30db, 0x309a, 0x0, 0x30ef, 0x3099, 0x0, 0x30f0, 0x3099, 0x0, 0x30f1, 0x3099, 0x0, 0x30f2, 0x3099, 0x0, 0x30fd, 0x3099, 0x0, 0x349e, 0x0, 0x34b9, 0x0, 0x34bb, 0x0, 0x34df, 0x0, 0x3515, 0x0, 0x36ee, 0x0, 0x36fc, 0x0, 0x3781, 0x0, 0x382f, 0x0, 0x3862, 0x0, 0x387c, 0x0, 0x38c7, 0x0, 0x38e3, 0x0, 0x391c, 0x0, 0x393a, 0x0, 0x3a2e, 0x0, 0x3a6c, 0x0, 0x3ae4, 0x0, 0x3b08, 0x0, 0x3b19, 0x0, 0x3b49, 0x0, 0x3b9d, 0x0, 0x3c18, 0x0, 0x3c4e, 0x0, 0x3d33, 0x0, 0x3d96, 0x0, 0x3eac, 0x0, 0x3eb8, 0x0, 0x3f1b, 0x0, 0x3ffc, 0x0, 0x4008, 0x0, 0x4018, 0x0, 0x4039, 0x0, 0x4046, 0x0, 0x4096, 0x0, 0x40e3, 0x0, 0x412f, 0x0, 0x4202, 0x0, 0x4227, 0x0, 0x42a0, 0x0, 0x4301, 0x0, 0x4334, 0x0, 0x4359, 0x0, 0x43d5, 0x0, 0x43d9, 0x0, 0x440b, 0x0, 0x446b, 0x0, 0x452b, 0x0, 0x455d, 0x0, 0x4561, 0x0, 0x456b, 0x0, 0x45d7, 0x0, 0x45f9, 0x0, 0x4635, 0x0, 0x46be, 0x0, 0x46c7, 0x0, 0x4995, 0x0, 0x49e6, 0x0, 0x4a6e, 0x0, 0x4a76, 0x0, 0x4ab2, 0x0, 0x4b33, 0x0, 0x4bce, 0x0, 0x4cce, 0x0, 0x4ced, 0x0, 0x4cf8, 0x0, 0x4d56, 0x0, 0x4e0d, 0x0, 0x4e26, 0x0, 0x4e32, 0x0, 0x4e38, 0x0, 0x4e39, 0x0, 0x4e3d, 0x0, 0x4e41, 0x0, 0x4e82, 0x0, 0x4e86, 0x0, 0x4eae, 0x0, 0x4ec0, 0x0, 0x4ecc, 0x0, 0x4ee4, 0x0, 0x4f60, 0x0, 0x4f80, 0x0, 0x4f86, 0x0, 0x4f8b, 0x0, 0x4fae, 0x0, 0x4fbb, 0x0, 0x4fbf, 0x0, 0x5002, 0x0, 0x502b, 0x0, 0x507a, 0x0, 0x5099, 0x0, 0x50cf, 0x0, 0x50da, 0x0, 0x50e7, 0x0, 0x5140, 0x0, 0x5145, 0x0, 0x514d, 0x0, 0x5154, 0x0, 0x5164, 0x0, 0x5167, 0x0, 0x5168, 0x0, 0x5169, 0x0, 0x516d, 0x0, 0x5177, 0x0, 0x5180, 0x0, 0x518d, 0x0, 0x5192, 0x0, 0x5195, 0x0, 0x5197, 0x0, 0x51a4, 0x0, 0x51ac, 0x0, 0x51b5, 0x0, 0x51b7, 0x0, 0x51c9, 0x0, 0x51cc, 0x0, 0x51dc, 0x0, 0x51de, 0x0, 0x51f5, 0x0, 0x5203, 0x0, 0x5207, 0x0, 0x5217, 0x0, 0x5229, 0x0, 0x523a, 0x0, 0x523b, 0x0, 0x5246, 0x0, 0x5272, 0x0, 0x5277, 0x0, 0x5289, 0x0, 0x529b, 0x0, 0x52a3, 0x0, 0x52b3, 0x0, 0x52c7, 0x0, 0x52c9, 0x0, 0x52d2, 0x0, 0x52de, 0x0, 0x52e4, 0x0, 0x52f5, 0x0, 0x52fa, 0x0, 0x5305, 0x0, 0x5306, 0x0, 0x5317, 0x0, 0x533f, 0x0, 0x5349, 0x0, 0x5351, 0x0, 0x535a, 0x0, 0x5373, 0x0, 0x5375, 0x0, 0x537d, 0x0, 0x537f, 0x0, 0x53c3, 0x0, 0x53ca, 0x0, 0x53df, 0x0, 0x53e5, 0x0, 0x53eb, 0x0, 0x53f1, 0x0, 0x5406, 0x0, 0x540f, 0x0, 0x541d, 0x0, 0x5438, 0x0, 0x5442, 0x0, 0x5448, 0x0, 0x5468, 0x0, 0x549e, 0x0, 0x54a2, 0x0, 0x54bd, 0x0, 0x54f6, 0x0, 0x5510, 0x0, 0x5553, 0x0, 0x5555, 0x0, 0x5563, 0x0, 0x5584, 0x0, 0x5587, 0x0, 0x5599, 0x0, 0x559d, 0x0, 0x55ab, 0x0, 0x55b3, 0x0, 0x55c0, 0x0, 0x55c2, 0x0, 0x55e2, 0x0, 0x5606, 0x0, 0x5651, 0x0, 0x5668, 0x0, 0x5674, 0x0, 0x56f9, 0x0, 0x5716, 0x0, 0x5717, 0x0, 0x578b, 0x0, 0x57ce, 0x0, 0x57f4, 0x0, 0x580d, 0x0, 0x5831, 0x0, 0x5832, 0x0, 0x5840, 0x0, 0x585a, 0x0, 0x585e, 0x0, 0x58a8, 0x0, 0x58ac, 0x0, 0x58b3, 0x0, 0x58d8, 0x0, 0x58df, 0x0, 0x58ee, 0x0, 0x58f2, 0x0, 0x58f7, 0x0, 0x5906, 0x0, 0x591a, 0x0, 0x5922, 0x0, 0x5944, 0x0, 0x5948, 0x0, 0x5951, 0x0, 0x5954, 0x0, 0x5962, 0x0, 0x5973, 0x0, 0x59d8, 0x0, 0x59ec, 0x0, 0x5a1b, 0x0, 0x5a27, 0x0, 0x5a62, 0x0, 0x5a66, 0x0, 0x5ab5, 0x0, 0x5b08, 0x0, 0x5b28, 0x0, 0x5b3e, 0x0, 0x5b85, 0x0, 0x5bc3, 0x0, 0x5bd8, 0x0, 0x5be7, 0x0, 0x5bee, 0x0, 0x5bf3, 0x0, 0x5bff, 0x0, 0x5c06, 0x0, 0x5c22, 0x0, 0x5c3f, 0x0, 0x5c60, 0x0, 0x5c62, 0x0, 0x5c64, 0x0, 0x5c65, 0x0, 0x5c6e, 0x0, 0x5c8d, 0x0, 0x5cc0, 0x0, 0x5d19, 0x0, 0x5d43, 0x0, 0x5d50, 0x0, 0x5d6b, 0x0, 0x5d6e, 0x0, 0x5d7c, 0x0, 0x5db2, 0x0, 0x5dba, 0x0, 0x5de1, 0x0, 0x5de2, 0x0, 0x5dfd, 0x0, 0x5e28, 0x0, 0x5e3d, 0x0, 0x5e69, 0x0, 0x5e74, 0x0, 0x5ea6, 0x0, 0x5eb0, 0x0, 0x5eb3, 0x0, 0x5eb6, 0x0, 0x5ec9, 0x0, 0x5eca, 0x0, 0x5ed2, 0x0, 0x5ed3, 0x0, 0x5ed9, 0x0, 0x5eec, 0x0, 0x5efe, 0x0, 0x5f04, 0x0, 0x5f22, 0x0, 0x5f53, 0x0, 0x5f62, 0x0, 0x5f69, 0x0, 0x5f6b, 0x0, 0x5f8b, 0x0, 0x5f9a, 0x0, 0x5fa9, 0x0, 0x5fad, 0x0, 0x5fcd, 0x0, 0x5fd7, 0x0, 0x5ff5, 0x0, 0x5ff9, 0x0, 0x6012, 0x0, 0x601c, 0x0, 0x6075, 0x0, 0x6081, 0x0, 0x6094, 0x0, 0x60c7, 0x0, 0x60d8, 0x0, 0x60e1, 0x0, 0x6108, 0x0, 0x6144, 0x0, 0x6148, 0x0, 0x614c, 0x0, 0x614e, 0x0, 0x6160, 0x0, 0x6168, 0x0, 0x617a, 0x0, 0x618e, 0x0, 0x6190, 0x0, 0x61a4, 0x0, 0x61af, 0x0, 0x61b2, 0x0, 0x61de, 0x0, 0x61f2, 0x0, 0x61f6, 0x0, 0x6200, 0x0, 0x6210, 0x0, 0x621b, 0x0, 0x622e, 0x0, 0x6234, 0x0, 0x625d, 0x0, 0x62b1, 0x0, 0x62c9, 0x0, 0x62cf, 0x0, 0x62d3, 0x0, 0x62d4, 0x0, 0x62fc, 0x0, 0x62fe, 0x0, 0x633d, 0x0, 0x6350, 0x0, 0x6368, 0x0, 0x637b, 0x0, 0x6383, 0x0, 0x63a0, 0x0, 0x63a9, 0x0, 0x63c4, 0x0, 0x63c5, 0x0, 0x63e4, 0x0, 0x641c, 0x0, 0x6422, 0x0, 0x6452, 0x0, 0x6469, 0x0, 0x6477, 0x0, 0x647e, 0x0, 0x649a, 0x0, 0x649d, 0x0, 0x64c4, 0x0, 0x654f, 0x0, 0x6556, 0x0, 0x656c, 0x0, 0x6578, 0x0, 0x6599, 0x0, 0x65c5, 0x0, 0x65e2, 0x0, 0x65e3, 0x0, 0x6613, 0x0, 0x6649, 0x0, 0x6674, 0x0, 0x6688, 0x0, 0x6691, 0x0, 0x669c, 0x0, 0x66b4, 0x0, 0x66c6, 0x0, 0x66f4, 0x0, 0x66f8, 0x0, 0x6700, 0x0, 0x6717, 0x0, 0x671b, 0x0, 0x6721, 0x0, 0x674e, 0x0, 0x6753, 0x0, 0x6756, 0x0, 0x675e, 0x0, 0x677b, 0x0, 0x6785, 0x0, 0x6797, 0x0, 0x67f3, 0x0, 0x67fa, 0x0, 0x6817, 0x0, 0x681f, 0x0, 0x6852, 0x0, 0x6881, 0x0, 0x6885, 0x0, 0x688e, 0x0, 0x68a8, 0x0, 0x6914, 0x0, 0x6942, 0x0, 0x69a3, 0x0, 0x69ea, 0x0, 0x6a02, 0x0, 0x6a13, 0x0, 0x6aa8, 0x0, 0x6ad3, 0x0, 0x6adb, 0x0, 0x6b04, 0x0, 0x6b21, 0x0, 0x6b54, 0x0, 0x6b72, 0x0, 0x6b77, 0x0, 0x6b79, 0x0, 0x6b9f, 0x0, 0x6bae, 0x0, 0x6bba, 0x0, 0x6bbb, 0x0, 0x6c4e, 0x0, 0x6c67, 0x0, 0x6c88, 0x0, 0x6cbf, 0x0, 0x6ccc, 0x0, 0x6ccd, 0x0, 0x6ce5, 0x0, 0x6d16, 0x0, 0x6d1b, 0x0, 0x6d1e, 0x0, 0x6d34, 0x0, 0x6d3e, 0x0, 0x6d41, 0x0, 0x6d69, 0x0, 0x6d6a, 0x0, 0x6d77, 0x0, 0x6d78, 0x0, 0x6d85, 0x0, 0x6dcb, 0x0, 0x6dda, 0x0, 0x6dea, 0x0, 0x6df9, 0x0, 0x6e1a, 0x0, 0x6e2f, 0x0, 0x6e6e, 0x0, 0x6e9c, 0x0, 0x6eba, 0x0, 0x6ec7, 0x0, 0x6ecb, 0x0, 0x6ed1, 0x0, 0x6edb, 0x0, 0x6f0f, 0x0, 0x6f22, 0x0, 0x6f23, 0x0, 0x6f6e, 0x0, 0x6fc6, 0x0, 0x6feb, 0x0, 0x6ffe, 0x0, 0x701b, 0x0, 0x701e, 0x0, 0x7039, 0x0, 0x704a, 0x0, 0x7070, 0x0, 0x7077, 0x0, 0x707d, 0x0, 0x7099, 0x0, 0x70ad, 0x0, 0x70c8, 0x0, 0x70d9, 0x0, 0x7145, 0x0, 0x7149, 0x0, 0x716e, 0x0, 0x719c, 0x0, 0x71ce, 0x0, 0x71d0, 0x0, 0x7210, 0x0, 0x721b, 0x0, 0x7228, 0x0, 0x722b, 0x0, 0x7235, 0x0, 0x7250, 0x0, 0x7262, 0x0, 0x7280, 0x0, 0x7295, 0x0, 0x72af, 0x0, 0x72c0, 0x0, 0x72fc, 0x0, 0x732a, 0x0, 0x7375, 0x0, 0x737a, 0x0, 0x7387, 0x0, 0x738b, 0x0, 0x73a5, 0x0, 0x73b2, 0x0, 0x73de, 0x0, 0x7406, 0x0, 0x7409, 0x0, 0x7422, 0x0, 0x7447, 0x0, 0x745c, 0x0, 0x7469, 0x0, 0x7471, 0x0, 0x7485, 0x0, 0x7489, 0x0, 0x7498, 0x0, 0x74ca, 0x0, 0x7506, 0x0, 0x7524, 0x0, 0x753b, 0x0, 0x753e, 0x0, 0x7559, 0x0, 0x7565, 0x0, 0x7570, 0x0, 0x75e2, 0x0, 0x7610, 0x0, 0x761d, 0x0, 0x761f, 0x0, 0x7642, 0x0, 0x7669, 0x0, 0x76ca, 0x0, 0x76db, 0x0, 0x76e7, 0x0, 0x76f4, 0x0, 0x7701, 0x0, 0x771e, 0x0, 0x771f, 0x0, 0x7740, 0x0, 0x774a, 0x0, 0x778b, 0x0, 0x77a7, 0x0, 0x784e, 0x0, 0x786b, 0x0, 0x788c, 0x0, 0x7891, 0x0, 0x78ca, 0x0, 0x78cc, 0x0, 0x78fb, 0x0, 0x792a, 0x0, 0x793c, 0x0, 0x793e, 0x0, 0x7948, 0x0, 0x7949, 0x0, 0x7950, 0x0, 0x7956, 0x0, 0x795d, 0x0, 0x795e, 0x0, 0x7965, 0x0, 0x797f, 0x0, 0x798d, 0x0, 0x798e, 0x0, 0x798f, 0x0, 0x79ae, 0x0, 0x79ca, 0x0, 0x79eb, 0x0, 0x7a1c, 0x0, 0x7a40, 0x0, 0x7a4a, 0x0, 0x7a4f, 0x0, 0x7a81, 0x0, 0x7ab1, 0x0, 0x7acb, 0x0, 0x7aee, 0x0, 0x7b20, 0x0, 0x7bc0, 0x0, 0x7bc6, 0x0, 0x7bc9, 0x0, 0x7c3e, 0x0, 0x7c60, 0x0, 0x7c7b, 0x0, 0x7c92, 0x0, 0x7cbe, 0x0, 0x7cd2, 0x0, 0x7cd6, 0x0, 0x7ce3, 0x0, 0x7ce7, 0x0, 0x7ce8, 0x0, 0x7d00, 0x0, 0x7d10, 0x0, 0x7d22, 0x0, 0x7d2f, 0x0, 0x7d5b, 0x0, 0x7d63, 0x0, 0x7da0, 0x0, 0x7dbe, 0x0, 0x7dc7, 0x0, 0x7df4, 0x0, 0x7e02, 0x0, 0x7e09, 0x0, 0x7e37, 0x0, 0x7e41, 0x0, 0x7e45, 0x0, 0x7f3e, 0x0, 0x7f72, 0x0, 0x7f79, 0x0, 0x7f7a, 0x0, 0x7f85, 0x0, 0x7f95, 0x0, 0x7f9a, 0x0, 0x7fbd, 0x0, 0x7ffa, 0x0, 0x8001, 0x0, 0x8005, 0x0, 0x8046, 0x0, 0x8060, 0x0, 0x806f, 0x0, 0x8070, 0x0, 0x807e, 0x0, 0x808b, 0x0, 0x80ad, 0x0, 0x80b2, 0x0, 0x8103, 0x0, 0x813e, 0x0, 0x81d8, 0x0, 0x81e8, 0x0, 0x81ed, 0x0, 0x8201, 0x0, 0x8204, 0x0, 0x8218, 0x0, 0x826f, 0x0, 0x8279, 0x0, 0x828b, 0x0, 0x8291, 0x0, 0x829d, 0x0, 0x82b1, 0x0, 0x82b3, 0x0, 0x82bd, 0x0, 0x82e5, 0x0, 0x82e6, 0x0, 0x831d, 0x0, 0x8323, 0x0, 0x8336, 0x0, 0x8352, 0x0, 0x8353, 0x0, 0x8363, 0x0, 0x83ad, 0x0, 0x83bd, 0x0, 0x83c9, 0x0, 0x83ca, 0x0, 0x83cc, 0x0, 0x83dc, 0x0, 0x83e7, 0x0, 0x83ef, 0x0, 0x83f1, 0x0, 0x843d, 0x0, 0x8449, 0x0, 0x8457, 0x0, 0x84ee, 0x0, 0x84f1, 0x0, 0x84f3, 0x0, 0x84fc, 0x0, 0x8516, 0x0, 0x8564, 0x0, 0x85cd, 0x0, 0x85fa, 0x0, 0x8606, 0x0, 0x8612, 0x0, 0x862d, 0x0, 0x863f, 0x0, 0x8650, 0x0, 0x865c, 0x0, 0x8667, 0x0, 0x8669, 0x0, 0x8688, 0x0, 0x86a9, 0x0, 0x86e2, 0x0, 0x870e, 0x0, 0x8728, 0x0, 0x876b, 0x0, 0x8779, 0x0, 0x8786, 0x0, 0x87ba, 0x0, 0x87e1, 0x0, 0x8801, 0x0, 0x881f, 0x0, 0x884c, 0x0, 0x8860, 0x0, 0x8863, 0x0, 0x88c2, 0x0, 0x88cf, 0x0, 0x88d7, 0x0, 0x88de, 0x0, 0x88e1, 0x0, 0x88f8, 0x0, 0x88fa, 0x0, 0x8910, 0x0, 0x8941, 0x0, 0x8964, 0x0, 0x8986, 0x0, 0x898b, 0x0, 0x8996, 0x0, 0x8aa0, 0x0, 0x8aaa, 0x0, 0x8abf, 0x0, 0x8acb, 0x0, 0x8ad2, 0x0, 0x8ad6, 0x0, 0x8aed, 0x0, 0x8af8, 0x0, 0x8afe, 0x0, 0x8b01, 0x0, 0x8b39, 0x0, 0x8b58, 0x0, 0x8b80, 0x0, 0x8b8a, 0x0, 0x8c48, 0x0, 0x8c55, 0x0, 0x8cab, 0x0, 0x8cc1, 0x0, 0x8cc2, 0x0, 0x8cc8, 0x0, 0x8cd3, 0x0, 0x8d08, 0x0, 0x8d1b, 0x0, 0x8d77, 0x0, 0x8dbc, 0x0, 0x8dcb, 0x0, 0x8def, 0x0, 0x8df0, 0x0, 0x8eca, 0x0, 0x8ed4, 0x0, 0x8f26, 0x0, 0x8f2a, 0x0, 0x8f38, 0x0, 0x8f3b, 0x0, 0x8f62, 0x0, 0x8f9e, 0x0, 0x8fb0, 0x0, 0x8fb6, 0x0, 0x9023, 0x0, 0x9038, 0x0, 0x9072, 0x0, 0x907c, 0x0, 0x908f, 0x0, 0x9094, 0x0, 0x90ce, 0x0, 0x90de, 0x0, 0x90f1, 0x0, 0x90fd, 0x0, 0x9111, 0x0, 0x911b, 0x0, 0x916a, 0x0, 0x9199, 0x0, 0x91b4, 0x0, 0x91cc, 0x0, 0x91cf, 0x0, 0x91d1, 0x0, 0x9234, 0x0, 0x9238, 0x0, 0x9276, 0x0, 0x927c, 0x0, 0x92d7, 0x0, 0x92d8, 0x0, 0x9304, 0x0, 0x934a, 0x0, 0x93f9, 0x0, 0x9415, 0x0, 0x958b, 0x0, 0x95ad, 0x0, 0x95b7, 0x0, 0x962e, 0x0, 0x964b, 0x0, 0x964d, 0x0, 0x9675, 0x0, 0x9678, 0x0, 0x967c, 0x0, 0x9686, 0x0, 0x96a3, 0x0, 0x96b7, 0x0, 0x96b8, 0x0, 0x96c3, 0x0, 0x96e2, 0x0, 0x96e3, 0x0, 0x96f6, 0x0, 0x96f7, 0x0, 0x9723, 0x0, 0x9732, 0x0, 0x9748, 0x0, 0x9756, 0x0, 0x97db, 0x0, 0x97e0, 0x0, 0x97ff, 0x0, 0x980b, 0x0, 0x9818, 0x0, 0x9829, 0x0, 0x983b, 0x0, 0x985e, 0x0, 0x98e2, 0x0, 0x98ef, 0x0, 0x98fc, 0x0, 0x9928, 0x0, 0x9929, 0x0, 0x99a7, 0x0, 0x99c2, 0x0, 0x99f1, 0x0, 0x99fe, 0x0, 0x9a6a, 0x0, 0x9b12, 0x0, 0x9b6f, 0x0, 0x9c40, 0x0, 0x9c57, 0x0, 0x9cfd, 0x0, 0x9d67, 0x0, 0x9db4, 0x0, 0x9dfa, 0x0, 0x9e1e, 0x0, 0x9e7f, 0x0, 0x9e97, 0x0, 0x9e9f, 0x0, 0x9ebb, 0x0, 0x9ece, 0x0, 0x9ef9, 0x0, 0x9efe, 0x0, 0x9f05, 0x0, 0x9f0f, 0x0, 0x9f16, 0x0, 0x9f3b, 0x0, 0x9f43, 0x0, 0x9f8d, 0x0, 0x9f8e, 0x0, 0x9f9c, 0x0, 0x11099, 0x110ba, 0x0, 0x1109b, 0x110ba, 0x0, 0x110a5, 0x110ba, 0x0, 0x11131, 0x11127, 0x0, 0x11132, 0x11127, 0x0, 0x1d157, 0x1d165, 0x0, 0x1d158, 0x1d165, 0x0, 0x1d158, 0x1d165, 0x1d16e, 0x0, 0x1d158, 0x1d165, 0x1d16f, 0x0, 0x1d158, 0x1d165, 0x1d170, 0x0, 0x1d158, 0x1d165, 0x1d171, 0x0, 0x1d158, 0x1d165, 0x1d172, 0x0, 0x1d1b9, 0x1d165, 0x0, 0x1d1b9, 0x1d165, 0x1d16e, 0x0, 0x1d1b9, 0x1d165, 0x1d16f, 0x0, 0x1d1ba, 0x1d165, 0x0, 0x1d1ba, 0x1d165, 0x1d16e, 0x0, 0x1d1ba, 0x1d165, 0x1d16f, 0x0, 0x20122, 0x0, 0x2051c, 0x0, 0x20525, 0x0, 0x2054b, 0x0, 0x2063a, 0x0, 0x20804, 0x0, 0x208de, 0x0, 0x20a2c, 0x0, 0x20b63, 0x0, 0x214e4, 0x0, 0x216a8, 0x0, 0x216ea, 0x0, 0x219c8, 0x0, 0x21b18, 0x0, 0x21d0b, 0x0, 0x21de4, 0x0, 0x21de6, 0x0, 0x22183, 0x0, 0x2219f, 0x0, 0x22331, 0x0, 0x226d4, 0x0, 0x22844, 0x0, 0x2284a, 0x0, 0x22b0c, 0x0, 0x22bf1, 0x0, 0x2300a, 0x0, 0x232b8, 0x0, 0x2335f, 0x0, 0x23393, 0x0, 0x2339c, 0x0, 0x233c3, 0x0, 0x233d5, 0x0, 0x2346d, 0x0, 0x236a3, 0x0, 0x238a7, 0x0, 0x23a8d, 0x0, 0x23afa, 0x0, 0x23cbc, 0x0, 0x23d1e, 0x0, 0x23ed1, 0x0, 0x23f5e, 0x0, 0x23f8e, 0x0, 0x24263, 0x0, 0x242ee, 0x0, 0x243ab, 0x0, 0x24608, 0x0, 0x24735, 0x0, 0x24814, 0x0, 0x24c36, 0x0, 0x24c92, 0x0, 0x24fa1, 0x0, 0x24fb8, 0x0, 0x25044, 0x0, 0x250f2, 0x0, 0x250f3, 0x0, 0x25119, 0x0, 0x25133, 0x0, 0x25249, 0x0, 0x2541d, 0x0, 0x25626, 0x0, 0x2569a, 0x0, 0x256c5, 0x0, 0x2597c, 0x0, 0x25aa7, 0x0, 0x25bab, 0x0, 0x25c80, 0x0, 0x25cd0, 0x0, 0x25f86, 0x0, 0x261da, 0x0, 0x26228, 0x0, 0x26247, 0x0, 0x262d9, 0x0, 0x2633e, 0x0, 0x264da, 0x0, 0x26523, 0x0, 0x265a8, 0x0, 0x267a7, 0x0, 0x267b5, 0x0, 0x26b3c, 0x0, 0x26c36, 0x0, 0x26cd5, 0x0, 0x26d6b, 0x0, 0x26f2c, 0x0, 0x26fb1, 0x0, 0x270d2, 0x0, 0x273ca, 0x0, 0x27667, 0x0, 0x278ae, 0x0, 0x27966, 0x0, 0x27ca8, 0x0, 0x27ed3, 0x0, 0x27f2f, 0x0, 0x285d2, 0x0, 0x285ed, 0x0, 0x2872e, 0x0, 0x28bfa, 0x0, 0x28d77, 0x0, 0x29145, 0x0, 0x291df, 0x0, 0x2921a, 0x0, 0x2940a, 0x0, 0x29496, 0x0, 0x295b6, 0x0, 0x29b30, 0x0, 0x2a0ce, 0x0, 0x2a105, 0x0, 0x2a20e, 0x0, 0x2a291, 0x0, 0x2a392, 0x0, 0x2a600, 0x0]; return t; } _IDCA decompCompatTable() { static _IDCA t = [ 0x0, 0x20, 0x0, 0x20, 0x301, 0x0, 0x20, 0x303, 0x0, 0x20, 0x304, 0x0, 0x20, 0x305, 0x0, 0x20, 0x306, 0x0, 0x20, 0x307, 0x0, 0x20, 0x308, 0x0, 0x20, 0x308, 0x300, 0x0, 0x20, 0x308, 0x301, 0x0, 0x20, 0x308, 0x342, 0x0, 0x20, 0x30a, 0x0, 0x20, 0x30b, 0x0, 0x20, 0x313, 0x0, 0x20, 0x313, 0x300, 0x0, 0x20, 0x313, 0x301, 0x0, 0x20, 0x313, 0x342, 0x0, 0x20, 0x314, 0x0, 0x20, 0x314, 0x300, 0x0, 0x20, 0x314, 0x301, 0x0, 0x20, 0x314, 0x342, 0x0, 0x20, 0x327, 0x0, 0x20, 0x328, 0x0, 0x20, 0x333, 0x0, 0x20, 0x342, 0x0, 0x20, 0x345, 0x0, 0x20, 0x64b, 0x0, 0x20, 0x64c, 0x0, 0x20, 0x64c, 0x651, 0x0, 0x20, 0x64d, 0x0, 0x20, 0x64d, 0x651, 0x0, 0x20, 0x64e, 0x0, 0x20, 0x64e, 0x651, 0x0, 0x20, 0x64f, 0x0, 0x20, 0x64f, 0x651, 0x0, 0x20, 0x650, 0x0, 0x20, 0x650, 0x651, 0x0, 0x20, 0x651, 0x0, 0x20, 0x651, 0x670, 0x0, 0x20, 0x652, 0x0, 0x20, 0x3099, 0x0, 0x20, 0x309a, 0x0, 0x21, 0x0, 0x21, 0x21, 0x0, 0x21, 0x3f, 0x0, 0x22, 0x0, 0x23, 0x0, 0x24, 0x0, 0x25, 0x0, 0x26, 0x0, 0x27, 0x0, 0x28, 0x0, 0x28, 0x31, 0x29, 0x0, 0x28, 0x31, 0x30, 0x29, 0x0, 0x28, 0x31, 0x31, 0x29, 0x0, 0x28, 0x31, 0x32, 0x29, 0x0, 0x28, 0x31, 0x33, 0x29, 0x0, 0x28, 0x31, 0x34, 0x29, 0x0, 0x28, 0x31, 0x35, 0x29, 0x0, 0x28, 0x31, 0x36, 0x29, 0x0, 0x28, 0x31, 0x37, 0x29, 0x0, 0x28, 0x31, 0x38, 0x29, 0x0, 0x28, 0x31, 0x39, 0x29, 0x0, 0x28, 0x32, 0x29, 0x0, 0x28, 0x32, 0x30, 0x29, 0x0, 0x28, 0x33, 0x29, 0x0, 0x28, 0x34, 0x29, 0x0, 0x28, 0x35, 0x29, 0x0, 0x28, 0x36, 0x29, 0x0, 0x28, 0x37, 0x29, 0x0, 0x28, 0x38, 0x29, 0x0, 0x28, 0x39, 0x29, 0x0, 0x28, 0x41, 0x29, 0x0, 0x28, 0x42, 0x29, 0x0, 0x28, 0x43, 0x29, 0x0, 0x28, 0x44, 0x29, 0x0, 0x28, 0x45, 0x29, 0x0, 0x28, 0x46, 0x29, 0x0, 0x28, 0x47, 0x29, 0x0, 0x28, 0x48, 0x29, 0x0, 0x28, 0x49, 0x29, 0x0, 0x28, 0x4a, 0x29, 0x0, 0x28, 0x4b, 0x29, 0x0, 0x28, 0x4c, 0x29, 0x0, 0x28, 0x4d, 0x29, 0x0, 0x28, 0x4e, 0x29, 0x0, 0x28, 0x4f, 0x29, 0x0, 0x28, 0x50, 0x29, 0x0, 0x28, 0x51, 0x29, 0x0, 0x28, 0x52, 0x29, 0x0, 0x28, 0x53, 0x29, 0x0, 0x28, 0x54, 0x29, 0x0, 0x28, 0x55, 0x29, 0x0, 0x28, 0x56, 0x29, 0x0, 0x28, 0x57, 0x29, 0x0, 0x28, 0x58, 0x29, 0x0, 0x28, 0x59, 0x29, 0x0, 0x28, 0x5a, 0x29, 0x0, 0x28, 0x61, 0x29, 0x0, 0x28, 0x62, 0x29, 0x0, 0x28, 0x63, 0x29, 0x0, 0x28, 0x64, 0x29, 0x0, 0x28, 0x65, 0x29, 0x0, 0x28, 0x66, 0x29, 0x0, 0x28, 0x67, 0x29, 0x0, 0x28, 0x68, 0x29, 0x0, 0x28, 0x69, 0x29, 0x0, 0x28, 0x6a, 0x29, 0x0, 0x28, 0x6b, 0x29, 0x0, 0x28, 0x6c, 0x29, 0x0, 0x28, 0x6d, 0x29, 0x0, 0x28, 0x6e, 0x29, 0x0, 0x28, 0x6f, 0x29, 0x0, 0x28, 0x70, 0x29, 0x0, 0x28, 0x71, 0x29, 0x0, 0x28, 0x72, 0x29, 0x0, 0x28, 0x73, 0x29, 0x0, 0x28, 0x74, 0x29, 0x0, 0x28, 0x75, 0x29, 0x0, 0x28, 0x76, 0x29, 0x0, 0x28, 0x77, 0x29, 0x0, 0x28, 0x78, 0x29, 0x0, 0x28, 0x79, 0x29, 0x0, 0x28, 0x7a, 0x29, 0x0, 0x28, 0x1100, 0x29, 0x0, 0x28, 0x1100, 0x1161, 0x29, 0x0, 0x28, 0x1102, 0x29, 0x0, 0x28, 0x1102, 0x1161, 0x29, 0x0, 0x28, 0x1103, 0x29, 0x0, 0x28, 0x1103, 0x1161, 0x29, 0x0, 0x28, 0x1105, 0x29, 0x0, 0x28, 0x1105, 0x1161, 0x29, 0x0, 0x28, 0x1106, 0x29, 0x0, 0x28, 0x1106, 0x1161, 0x29, 0x0, 0x28, 0x1107, 0x29, 0x0, 0x28, 0x1107, 0x1161, 0x29, 0x0, 0x28, 0x1109, 0x29, 0x0, 0x28, 0x1109, 0x1161, 0x29, 0x0, 0x28, 0x110b, 0x29, 0x0, 0x28, 0x110b, 0x1161, 0x29, 0x0, 0x28, 0x110b, 0x1169, 0x110c, 0x1165, 0x11ab, 0x29, 0x0, 0x28, 0x110b, 0x1169, 0x1112, 0x116e, 0x29, 0x0, 0x28, 0x110c, 0x29, 0x0, 0x28, 0x110c, 0x1161, 0x29, 0x0, 0x28, 0x110c, 0x116e, 0x29, 0x0, 0x28, 0x110e, 0x29, 0x0, 0x28, 0x110e, 0x1161, 0x29, 0x0, 0x28, 0x110f, 0x29, 0x0, 0x28, 0x110f, 0x1161, 0x29, 0x0, 0x28, 0x1110, 0x29, 0x0, 0x28, 0x1110, 0x1161, 0x29, 0x0, 0x28, 0x1111, 0x29, 0x0, 0x28, 0x1111, 0x1161, 0x29, 0x0, 0x28, 0x1112, 0x29, 0x0, 0x28, 0x1112, 0x1161, 0x29, 0x0, 0x28, 0x4e00, 0x29, 0x0, 0x28, 0x4e03, 0x29, 0x0, 0x28, 0x4e09, 0x29, 0x0, 0x28, 0x4e5d, 0x29, 0x0, 0x28, 0x4e8c, 0x29, 0x0, 0x28, 0x4e94, 0x29, 0x0, 0x28, 0x4ee3, 0x29, 0x0, 0x28, 0x4f01, 0x29, 0x0, 0x28, 0x4f11, 0x29, 0x0, 0x28, 0x516b, 0x29, 0x0, 0x28, 0x516d, 0x29, 0x0, 0x28, 0x52b4, 0x29, 0x0, 0x28, 0x5341, 0x29, 0x0, 0x28, 0x5354, 0x29, 0x0, 0x28, 0x540d, 0x29, 0x0, 0x28, 0x547c, 0x29, 0x0, 0x28, 0x56db, 0x29, 0x0, 0x28, 0x571f, 0x29, 0x0, 0x28, 0x5b66, 0x29, 0x0, 0x28, 0x65e5, 0x29, 0x0, 0x28, 0x6708, 0x29, 0x0, 0x28, 0x6709, 0x29, 0x0, 0x28, 0x6728, 0x29, 0x0, 0x28, 0x682a, 0x29, 0x0, 0x28, 0x6c34, 0x29, 0x0, 0x28, 0x706b, 0x29, 0x0, 0x28, 0x7279, 0x29, 0x0, 0x28, 0x76e3, 0x29, 0x0, 0x28, 0x793e, 0x29, 0x0, 0x28, 0x795d, 0x29, 0x0, 0x28, 0x796d, 0x29, 0x0, 0x28, 0x81ea, 0x29, 0x0, 0x28, 0x81f3, 0x29, 0x0, 0x28, 0x8ca1, 0x29, 0x0, 0x28, 0x8cc7, 0x29, 0x0, 0x28, 0x91d1, 0x29, 0x0, 0x29, 0x0, 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, 0x2e, 0x0, 0x2e, 0x2e, 0x0, 0x2e, 0x2e, 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x30, 0x2c, 0x0, 0x30, 0x2e, 0x0, 0x30, 0x2044, 0x33, 0x0, 0x30, 0x70b9, 0x0, 0x31, 0x0, 0x31, 0x2c, 0x0, 0x31, 0x2e, 0x0, 0x31, 0x30, 0x0, 0x31, 0x30, 0x2e, 0x0, 0x31, 0x30, 0x65e5, 0x0, 0x31, 0x30, 0x6708, 0x0, 0x31, 0x30, 0x70b9, 0x0, 0x31, 0x31, 0x0, 0x31, 0x31, 0x2e, 0x0, 0x31, 0x31, 0x65e5, 0x0, 0x31, 0x31, 0x6708, 0x0, 0x31, 0x31, 0x70b9, 0x0, 0x31, 0x32, 0x0, 0x31, 0x32, 0x2e, 0x0, 0x31, 0x32, 0x65e5, 0x0, 0x31, 0x32, 0x6708, 0x0, 0x31, 0x32, 0x70b9, 0x0, 0x31, 0x33, 0x0, 0x31, 0x33, 0x2e, 0x0, 0x31, 0x33, 0x65e5, 0x0, 0x31, 0x33, 0x70b9, 0x0, 0x31, 0x34, 0x0, 0x31, 0x34, 0x2e, 0x0, 0x31, 0x34, 0x65e5, 0x0, 0x31, 0x34, 0x70b9, 0x0, 0x31, 0x35, 0x0, 0x31, 0x35, 0x2e, 0x0, 0x31, 0x35, 0x65e5, 0x0, 0x31, 0x35, 0x70b9, 0x0, 0x31, 0x36, 0x0, 0x31, 0x36, 0x2e, 0x0, 0x31, 0x36, 0x65e5, 0x0, 0x31, 0x36, 0x70b9, 0x0, 0x31, 0x37, 0x0, 0x31, 0x37, 0x2e, 0x0, 0x31, 0x37, 0x65e5, 0x0, 0x31, 0x37, 0x70b9, 0x0, 0x31, 0x38, 0x0, 0x31, 0x38, 0x2e, 0x0, 0x31, 0x38, 0x65e5, 0x0, 0x31, 0x38, 0x70b9, 0x0, 0x31, 0x39, 0x0, 0x31, 0x39, 0x2e, 0x0, 0x31, 0x39, 0x65e5, 0x0, 0x31, 0x39, 0x70b9, 0x0, 0x31, 0x2044, 0x0, 0x31, 0x2044, 0x31, 0x30, 0x0, 0x31, 0x2044, 0x32, 0x0, 0x31, 0x2044, 0x33, 0x0, 0x31, 0x2044, 0x34, 0x0, 0x31, 0x2044, 0x35, 0x0, 0x31, 0x2044, 0x36, 0x0, 0x31, 0x2044, 0x37, 0x0, 0x31, 0x2044, 0x38, 0x0, 0x31, 0x2044, 0x39, 0x0, 0x31, 0x65e5, 0x0, 0x31, 0x6708, 0x0, 0x31, 0x70b9, 0x0, 0x32, 0x0, 0x32, 0x2c, 0x0, 0x32, 0x2e, 0x0, 0x32, 0x30, 0x0, 0x32, 0x30, 0x2e, 0x0, 0x32, 0x30, 0x65e5, 0x0, 0x32, 0x30, 0x70b9, 0x0, 0x32, 0x31, 0x0, 0x32, 0x31, 0x65e5, 0x0, 0x32, 0x31, 0x70b9, 0x0, 0x32, 0x32, 0x0, 0x32, 0x32, 0x65e5, 0x0, 0x32, 0x32, 0x70b9, 0x0, 0x32, 0x33, 0x0, 0x32, 0x33, 0x65e5, 0x0, 0x32, 0x33, 0x70b9, 0x0, 0x32, 0x34, 0x0, 0x32, 0x34, 0x65e5, 0x0, 0x32, 0x34, 0x70b9, 0x0, 0x32, 0x35, 0x0, 0x32, 0x35, 0x65e5, 0x0, 0x32, 0x36, 0x0, 0x32, 0x36, 0x65e5, 0x0, 0x32, 0x37, 0x0, 0x32, 0x37, 0x65e5, 0x0, 0x32, 0x38, 0x0, 0x32, 0x38, 0x65e5, 0x0, 0x32, 0x39, 0x0, 0x32, 0x39, 0x65e5, 0x0, 0x32, 0x2044, 0x33, 0x0, 0x32, 0x2044, 0x35, 0x0, 0x32, 0x65e5, 0x0, 0x32, 0x6708, 0x0, 0x32, 0x70b9, 0x0, 0x33, 0x0, 0x33, 0x2c, 0x0, 0x33, 0x2e, 0x0, 0x33, 0x30, 0x0, 0x33, 0x30, 0x65e5, 0x0, 0x33, 0x31, 0x0, 0x33, 0x31, 0x65e5, 0x0, 0x33, 0x32, 0x0, 0x33, 0x33, 0x0, 0x33, 0x34, 0x0, 0x33, 0x35, 0x0, 0x33, 0x36, 0x0, 0x33, 0x37, 0x0, 0x33, 0x38, 0x0, 0x33, 0x39, 0x0, 0x33, 0x2044, 0x34, 0x0, 0x33, 0x2044, 0x35, 0x0, 0x33, 0x2044, 0x38, 0x0, 0x33, 0x65e5, 0x0, 0x33, 0x6708, 0x0, 0x33, 0x70b9, 0x0, 0x34, 0x0, 0x34, 0x2c, 0x0, 0x34, 0x2e, 0x0, 0x34, 0x30, 0x0, 0x34, 0x31, 0x0, 0x34, 0x32, 0x0, 0x34, 0x33, 0x0, 0x34, 0x34, 0x0, 0x34, 0x35, 0x0, 0x34, 0x36, 0x0, 0x34, 0x37, 0x0, 0x34, 0x38, 0x0, 0x34, 0x39, 0x0, 0x34, 0x2044, 0x35, 0x0, 0x34, 0x65e5, 0x0, 0x34, 0x6708, 0x0, 0x34, 0x70b9, 0x0, 0x35, 0x0, 0x35, 0x2c, 0x0, 0x35, 0x2e, 0x0, 0x35, 0x30, 0x0, 0x35, 0x2044, 0x36, 0x0, 0x35, 0x2044, 0x38, 0x0, 0x35, 0x65e5, 0x0, 0x35, 0x6708, 0x0, 0x35, 0x70b9, 0x0, 0x36, 0x0, 0x36, 0x2c, 0x0, 0x36, 0x2e, 0x0, 0x36, 0x65e5, 0x0, 0x36, 0x6708, 0x0, 0x36, 0x70b9, 0x0, 0x37, 0x0, 0x37, 0x2c, 0x0, 0x37, 0x2e, 0x0, 0x37, 0x2044, 0x38, 0x0, 0x37, 0x65e5, 0x0, 0x37, 0x6708, 0x0, 0x37, 0x70b9, 0x0, 0x38, 0x0, 0x38, 0x2c, 0x0, 0x38, 0x2e, 0x0, 0x38, 0x65e5, 0x0, 0x38, 0x6708, 0x0, 0x38, 0x70b9, 0x0, 0x39, 0x0, 0x39, 0x2c, 0x0, 0x39, 0x2e, 0x0, 0x39, 0x65e5, 0x0, 0x39, 0x6708, 0x0, 0x39, 0x70b9, 0x0, 0x3a, 0x0, 0x3a, 0x3a, 0x3d, 0x0, 0x3b, 0x0, 0x3c, 0x0, 0x3c, 0x338, 0x0, 0x3d, 0x0, 0x3d, 0x3d, 0x0, 0x3d, 0x3d, 0x3d, 0x0, 0x3d, 0x338, 0x0, 0x3e, 0x0, 0x3e, 0x338, 0x0, 0x3f, 0x0, 0x3f, 0x21, 0x0, 0x3f, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, 0x41, 0x55, 0x0, 0x41, 0x300, 0x0, 0x41, 0x301, 0x0, 0x41, 0x302, 0x0, 0x41, 0x302, 0x300, 0x0, 0x41, 0x302, 0x301, 0x0, 0x41, 0x302, 0x303, 0x0, 0x41, 0x302, 0x309, 0x0, 0x41, 0x303, 0x0, 0x41, 0x304, 0x0, 0x41, 0x306, 0x0, 0x41, 0x306, 0x300, 0x0, 0x41, 0x306, 0x301, 0x0, 0x41, 0x306, 0x303, 0x0, 0x41, 0x306, 0x309, 0x0, 0x41, 0x307, 0x0, 0x41, 0x307, 0x304, 0x0, 0x41, 0x308, 0x0, 0x41, 0x308, 0x304, 0x0, 0x41, 0x309, 0x0, 0x41, 0x30a, 0x0, 0x41, 0x30a, 0x301, 0x0, 0x41, 0x30c, 0x0, 0x41, 0x30f, 0x0, 0x41, 0x311, 0x0, 0x41, 0x323, 0x0, 0x41, 0x323, 0x302, 0x0, 0x41, 0x323, 0x306, 0x0, 0x41, 0x325, 0x0, 0x41, 0x328, 0x0, 0x41, 0x2215, 0x6d, 0x0, 0x42, 0x0, 0x42, 0x71, 0x0, 0x42, 0x307, 0x0, 0x42, 0x323, 0x0, 0x42, 0x331, 0x0, 0x43, 0x0, 0x43, 0x44, 0x0, 0x43, 0x6f, 0x2e, 0x0, 0x43, 0x301, 0x0, 0x43, 0x302, 0x0, 0x43, 0x307, 0x0, 0x43, 0x30c, 0x0, 0x43, 0x327, 0x0, 0x43, 0x327, 0x301, 0x0, 0x43, 0x2215, 0x6b, 0x67, 0x0, 0x44, 0x0, 0x44, 0x4a, 0x0, 0x44, 0x5a, 0x0, 0x44, 0x5a, 0x30c, 0x0, 0x44, 0x7a, 0x0, 0x44, 0x7a, 0x30c, 0x0, 0x44, 0x307, 0x0, 0x44, 0x30c, 0x0, 0x44, 0x323, 0x0, 0x44, 0x327, 0x0, 0x44, 0x32d, 0x0, 0x44, 0x331, 0x0, 0x45, 0x0, 0x45, 0x300, 0x0, 0x45, 0x301, 0x0, 0x45, 0x302, 0x0, 0x45, 0x302, 0x300, 0x0, 0x45, 0x302, 0x301, 0x0, 0x45, 0x302, 0x303, 0x0, 0x45, 0x302, 0x309, 0x0, 0x45, 0x303, 0x0, 0x45, 0x304, 0x0, 0x45, 0x304, 0x300, 0x0, 0x45, 0x304, 0x301, 0x0, 0x45, 0x306, 0x0, 0x45, 0x307, 0x0, 0x45, 0x308, 0x0, 0x45, 0x309, 0x0, 0x45, 0x30c, 0x0, 0x45, 0x30f, 0x0, 0x45, 0x311, 0x0, 0x45, 0x323, 0x0, 0x45, 0x323, 0x302, 0x0, 0x45, 0x327, 0x0, 0x45, 0x327, 0x306, 0x0, 0x45, 0x328, 0x0, 0x45, 0x32d, 0x0, 0x45, 0x330, 0x0, 0x46, 0x0, 0x46, 0x41, 0x58, 0x0, 0x46, 0x307, 0x0, 0x47, 0x0, 0x47, 0x42, 0x0, 0x47, 0x48, 0x7a, 0x0, 0x47, 0x50, 0x61, 0x0, 0x47, 0x79, 0x0, 0x47, 0x301, 0x0, 0x47, 0x302, 0x0, 0x47, 0x304, 0x0, 0x47, 0x306, 0x0, 0x47, 0x307, 0x0, 0x47, 0x30c, 0x0, 0x47, 0x327, 0x0, 0x48, 0x0, 0x48, 0x50, 0x0, 0x48, 0x56, 0x0, 0x48, 0x67, 0x0, 0x48, 0x7a, 0x0, 0x48, 0x302, 0x0, 0x48, 0x307, 0x0, 0x48, 0x308, 0x0, 0x48, 0x30c, 0x0, 0x48, 0x323, 0x0, 0x48, 0x327, 0x0, 0x48, 0x32e, 0x0, 0x49, 0x0, 0x49, 0x49, 0x0, 0x49, 0x49, 0x49, 0x0, 0x49, 0x4a, 0x0, 0x49, 0x55, 0x0, 0x49, 0x56, 0x0, 0x49, 0x58, 0x0, 0x49, 0x300, 0x0, 0x49, 0x301, 0x0, 0x49, 0x302, 0x0, 0x49, 0x303, 0x0, 0x49, 0x304, 0x0, 0x49, 0x306, 0x0, 0x49, 0x307, 0x0, 0x49, 0x308, 0x0, 0x49, 0x308, 0x301, 0x0, 0x49, 0x309, 0x0, 0x49, 0x30c, 0x0, 0x49, 0x30f, 0x0, 0x49, 0x311, 0x0, 0x49, 0x323, 0x0, 0x49, 0x328, 0x0, 0x49, 0x330, 0x0, 0x4a, 0x0, 0x4a, 0x302, 0x0, 0x4b, 0x0, 0x4b, 0x42, 0x0, 0x4b, 0x4b, 0x0, 0x4b, 0x4d, 0x0, 0x4b, 0x301, 0x0, 0x4b, 0x30c, 0x0, 0x4b, 0x323, 0x0, 0x4b, 0x327, 0x0, 0x4b, 0x331, 0x0, 0x4c, 0x0, 0x4c, 0x4a, 0x0, 0x4c, 0x54, 0x44, 0x0, 0x4c, 0x6a, 0x0, 0x4c, 0xb7, 0x0, 0x4c, 0x301, 0x0, 0x4c, 0x30c, 0x0, 0x4c, 0x323, 0x0, 0x4c, 0x323, 0x304, 0x0, 0x4c, 0x327, 0x0, 0x4c, 0x32d, 0x0, 0x4c, 0x331, 0x0, 0x4d, 0x0, 0x4d, 0x42, 0x0, 0x4d, 0x43, 0x0, 0x4d, 0x44, 0x0, 0x4d, 0x48, 0x7a, 0x0, 0x4d, 0x50, 0x61, 0x0, 0x4d, 0x56, 0x0, 0x4d, 0x57, 0x0, 0x4d, 0x301, 0x0, 0x4d, 0x307, 0x0, 0x4d, 0x323, 0x0, 0x4d, 0x3a9, 0x0, 0x4e, 0x0, 0x4e, 0x4a, 0x0, 0x4e, 0x6a, 0x0, 0x4e, 0x6f, 0x0, 0x4e, 0x300, 0x0, 0x4e, 0x301, 0x0, 0x4e, 0x303, 0x0, 0x4e, 0x307, 0x0, 0x4e, 0x30c, 0x0, 0x4e, 0x323, 0x0, 0x4e, 0x327, 0x0, 0x4e, 0x32d, 0x0, 0x4e, 0x331, 0x0, 0x4f, 0x0, 0x4f, 0x300, 0x0, 0x4f, 0x301, 0x0, 0x4f, 0x302, 0x0, 0x4f, 0x302, 0x300, 0x0, 0x4f, 0x302, 0x301, 0x0, 0x4f, 0x302, 0x303, 0x0, 0x4f, 0x302, 0x309, 0x0, 0x4f, 0x303, 0x0, 0x4f, 0x303, 0x301, 0x0, 0x4f, 0x303, 0x304, 0x0, 0x4f, 0x303, 0x308, 0x0, 0x4f, 0x304, 0x0, 0x4f, 0x304, 0x300, 0x0, 0x4f, 0x304, 0x301, 0x0, 0x4f, 0x306, 0x0, 0x4f, 0x307, 0x0, 0x4f, 0x307, 0x304, 0x0, 0x4f, 0x308, 0x0, 0x4f, 0x308, 0x304, 0x0, 0x4f, 0x309, 0x0, 0x4f, 0x30b, 0x0, 0x4f, 0x30c, 0x0, 0x4f, 0x30f, 0x0, 0x4f, 0x311, 0x0, 0x4f, 0x31b, 0x0, 0x4f, 0x31b, 0x300, 0x0, 0x4f, 0x31b, 0x301, 0x0, 0x4f, 0x31b, 0x303, 0x0, 0x4f, 0x31b, 0x309, 0x0, 0x4f, 0x31b, 0x323, 0x0, 0x4f, 0x323, 0x0, 0x4f, 0x323, 0x302, 0x0, 0x4f, 0x328, 0x0, 0x4f, 0x328, 0x304, 0x0, 0x50, 0x0, 0x50, 0x48, 0x0, 0x50, 0x50, 0x4d, 0x0, 0x50, 0x50, 0x56, 0x0, 0x50, 0x52, 0x0, 0x50, 0x54, 0x45, 0x0, 0x50, 0x61, 0x0, 0x50, 0x301, 0x0, 0x50, 0x307, 0x0, 0x51, 0x0, 0x52, 0x0, 0x52, 0x73, 0x0, 0x52, 0x301, 0x0, 0x52, 0x307, 0x0, 0x52, 0x30c, 0x0, 0x52, 0x30f, 0x0, 0x52, 0x311, 0x0, 0x52, 0x323, 0x0, 0x52, 0x323, 0x304, 0x0, 0x52, 0x327, 0x0, 0x52, 0x331, 0x0, 0x53, 0x0, 0x53, 0x44, 0x0, 0x53, 0x4d, 0x0, 0x53, 0x53, 0x0, 0x53, 0x76, 0x0, 0x53, 0x301, 0x0, 0x53, 0x301, 0x307, 0x0, 0x53, 0x302, 0x0, 0x53, 0x307, 0x0, 0x53, 0x30c, 0x0, 0x53, 0x30c, 0x307, 0x0, 0x53, 0x323, 0x0, 0x53, 0x323, 0x307, 0x0, 0x53, 0x326, 0x0, 0x53, 0x327, 0x0, 0x54, 0x0, 0x54, 0x45, 0x4c, 0x0, 0x54, 0x48, 0x7a, 0x0, 0x54, 0x4d, 0x0, 0x54, 0x307, 0x0, 0x54, 0x30c, 0x0, 0x54, 0x323, 0x0, 0x54, 0x326, 0x0, 0x54, 0x327, 0x0, 0x54, 0x32d, 0x0, 0x54, 0x331, 0x0, 0x55, 0x0, 0x55, 0x300, 0x0, 0x55, 0x301, 0x0, 0x55, 0x302, 0x0, 0x55, 0x303, 0x0, 0x55, 0x303, 0x301, 0x0, 0x55, 0x304, 0x0, 0x55, 0x304, 0x308, 0x0, 0x55, 0x306, 0x0, 0x55, 0x308, 0x0, 0x55, 0x308, 0x300, 0x0, 0x55, 0x308, 0x301, 0x0, 0x55, 0x308, 0x304, 0x0, 0x55, 0x308, 0x30c, 0x0, 0x55, 0x309, 0x0, 0x55, 0x30a, 0x0, 0x55, 0x30b, 0x0, 0x55, 0x30c, 0x0, 0x55, 0x30f, 0x0, 0x55, 0x311, 0x0, 0x55, 0x31b, 0x0, 0x55, 0x31b, 0x300, 0x0, 0x55, 0x31b, 0x301, 0x0, 0x55, 0x31b, 0x303, 0x0, 0x55, 0x31b, 0x309, 0x0, 0x55, 0x31b, 0x323, 0x0, 0x55, 0x323, 0x0, 0x55, 0x324, 0x0, 0x55, 0x328, 0x0, 0x55, 0x32d, 0x0, 0x55, 0x330, 0x0, 0x56, 0x0, 0x56, 0x49, 0x0, 0x56, 0x49, 0x49, 0x0, 0x56, 0x49, 0x49, 0x49, 0x0, 0x56, 0x303, 0x0, 0x56, 0x323, 0x0, 0x56, 0x2215, 0x6d, 0x0, 0x57, 0x0, 0x57, 0x43, 0x0, 0x57, 0x5a, 0x0, 0x57, 0x62, 0x0, 0x57, 0x300, 0x0, 0x57, 0x301, 0x0, 0x57, 0x302, 0x0, 0x57, 0x307, 0x0, 0x57, 0x308, 0x0, 0x57, 0x323, 0x0, 0x58, 0x0, 0x58, 0x49, 0x0, 0x58, 0x49, 0x49, 0x0, 0x58, 0x307, 0x0, 0x58, 0x308, 0x0, 0x59, 0x0, 0x59, 0x300, 0x0, 0x59, 0x301, 0x0, 0x59, 0x302, 0x0, 0x59, 0x303, 0x0, 0x59, 0x304, 0x0, 0x59, 0x307, 0x0, 0x59, 0x308, 0x0, 0x59, 0x309, 0x0, 0x59, 0x323, 0x0, 0x5a, 0x0, 0x5a, 0x301, 0x0, 0x5a, 0x302, 0x0, 0x5a, 0x307, 0x0, 0x5a, 0x30c, 0x0, 0x5a, 0x323, 0x0, 0x5a, 0x331, 0x0, 0x5b, 0x0, 0x5c, 0x0, 0x5d, 0x0, 0x5e, 0x0, 0x5f, 0x0, 0x60, 0x0, 0x61, 0x0, 0x61, 0x2e, 0x6d, 0x2e, 0x0, 0x61, 0x2f, 0x63, 0x0, 0x61, 0x2f, 0x73, 0x0, 0x61, 0x2be, 0x0, 0x61, 0x300, 0x0, 0x61, 0x301, 0x0, 0x61, 0x302, 0x0, 0x61, 0x302, 0x300, 0x0, 0x61, 0x302, 0x301, 0x0, 0x61, 0x302, 0x303, 0x0, 0x61, 0x302, 0x309, 0x0, 0x61, 0x303, 0x0, 0x61, 0x304, 0x0, 0x61, 0x306, 0x0, 0x61, 0x306, 0x300, 0x0, 0x61, 0x306, 0x301, 0x0, 0x61, 0x306, 0x303, 0x0, 0x61, 0x306, 0x309, 0x0, 0x61, 0x307, 0x0, 0x61, 0x307, 0x304, 0x0, 0x61, 0x308, 0x0, 0x61, 0x308, 0x304, 0x0, 0x61, 0x309, 0x0, 0x61, 0x30a, 0x0, 0x61, 0x30a, 0x301, 0x0, 0x61, 0x30c, 0x0, 0x61, 0x30f, 0x0, 0x61, 0x311, 0x0, 0x61, 0x323, 0x0, 0x61, 0x323, 0x302, 0x0, 0x61, 0x323, 0x306, 0x0, 0x61, 0x325, 0x0, 0x61, 0x328, 0x0, 0x62, 0x0, 0x62, 0x61, 0x72, 0x0, 0x62, 0x307, 0x0, 0x62, 0x323, 0x0, 0x62, 0x331, 0x0, 0x63, 0x0, 0x63, 0x2f, 0x6f, 0x0, 0x63, 0x2f, 0x75, 0x0, 0x63, 0x61, 0x6c, 0x0, 0x63, 0x63, 0x0, 0x63, 0x64, 0x0, 0x63, 0x6d, 0x0, 0x63, 0x6d, 0x32, 0x0, 0x63, 0x6d, 0x33, 0x0, 0x63, 0x301, 0x0, 0x63, 0x302, 0x0, 0x63, 0x307, 0x0, 0x63, 0x30c, 0x0, 0x63, 0x327, 0x0, 0x63, 0x327, 0x301, 0x0, 0x64, 0x0, 0x64, 0x42, 0x0, 0x64, 0x61, 0x0, 0x64, 0x6c, 0x0, 0x64, 0x6d, 0x0, 0x64, 0x6d, 0x32, 0x0, 0x64, 0x6d, 0x33, 0x0, 0x64, 0x7a, 0x0, 0x64, 0x7a, 0x30c, 0x0, 0x64, 0x307, 0x0, 0x64, 0x30c, 0x0, 0x64, 0x323, 0x0, 0x64, 0x327, 0x0, 0x64, 0x32d, 0x0, 0x64, 0x331, 0x0, 0x65, 0x0, 0x65, 0x56, 0x0, 0x65, 0x72, 0x67, 0x0, 0x65, 0x300, 0x0, 0x65, 0x301, 0x0, 0x65, 0x302, 0x0, 0x65, 0x302, 0x300, 0x0, 0x65, 0x302, 0x301, 0x0, 0x65, 0x302, 0x303, 0x0, 0x65, 0x302, 0x309, 0x0, 0x65, 0x303, 0x0, 0x65, 0x304, 0x0, 0x65, 0x304, 0x300, 0x0, 0x65, 0x304, 0x301, 0x0, 0x65, 0x306, 0x0, 0x65, 0x307, 0x0, 0x65, 0x308, 0x0, 0x65, 0x309, 0x0, 0x65, 0x30c, 0x0, 0x65, 0x30f, 0x0, 0x65, 0x311, 0x0, 0x65, 0x323, 0x0, 0x65, 0x323, 0x302, 0x0, 0x65, 0x327, 0x0, 0x65, 0x327, 0x306, 0x0, 0x65, 0x328, 0x0, 0x65, 0x32d, 0x0, 0x65, 0x330, 0x0, 0x66, 0x0, 0x66, 0x66, 0x0, 0x66, 0x66, 0x69, 0x0, 0x66, 0x66, 0x6c, 0x0, 0x66, 0x69, 0x0, 0x66, 0x6c, 0x0, 0x66, 0x6d, 0x0, 0x66, 0x307, 0x0, 0x67, 0x0, 0x67, 0x61, 0x6c, 0x0, 0x67, 0x301, 0x0, 0x67, 0x302, 0x0, 0x67, 0x304, 0x0, 0x67, 0x306, 0x0, 0x67, 0x307, 0x0, 0x67, 0x30c, 0x0, 0x67, 0x327, 0x0, 0x68, 0x0, 0x68, 0x50, 0x61, 0x0, 0x68, 0x61, 0x0, 0x68, 0x302, 0x0, 0x68, 0x307, 0x0, 0x68, 0x308, 0x0, 0x68, 0x30c, 0x0, 0x68, 0x323, 0x0, 0x68, 0x327, 0x0, 0x68, 0x32e, 0x0, 0x68, 0x331, 0x0, 0x69, 0x0, 0x69, 0x69, 0x0, 0x69, 0x69, 0x69, 0x0, 0x69, 0x6a, 0x0, 0x69, 0x6e, 0x0, 0x69, 0x76, 0x0, 0x69, 0x78, 0x0, 0x69, 0x300, 0x0, 0x69, 0x301, 0x0, 0x69, 0x302, 0x0, 0x69, 0x303, 0x0, 0x69, 0x304, 0x0, 0x69, 0x306, 0x0, 0x69, 0x308, 0x0, 0x69, 0x308, 0x301, 0x0, 0x69, 0x309, 0x0, 0x69, 0x30c, 0x0, 0x69, 0x30f, 0x0, 0x69, 0x311, 0x0, 0x69, 0x323, 0x0, 0x69, 0x328, 0x0, 0x69, 0x330, 0x0, 0x6a, 0x0, 0x6a, 0x302, 0x0, 0x6a, 0x30c, 0x0, 0x6b, 0x0, 0x6b, 0x41, 0x0, 0x6b, 0x48, 0x7a, 0x0, 0x6b, 0x50, 0x61, 0x0, 0x6b, 0x56, 0x0, 0x6b, 0x57, 0x0, 0x6b, 0x63, 0x61, 0x6c, 0x0, 0x6b, 0x67, 0x0, 0x6b, 0x6c, 0x0, 0x6b, 0x6d, 0x0, 0x6b, 0x6d, 0x32, 0x0, 0x6b, 0x6d, 0x33, 0x0, 0x6b, 0x74, 0x0, 0x6b, 0x301, 0x0, 0x6b, 0x30c, 0x0, 0x6b, 0x323, 0x0, 0x6b, 0x327, 0x0, 0x6b, 0x331, 0x0, 0x6b, 0x3a9, 0x0, 0x6c, 0x0, 0x6c, 0x6a, 0x0, 0x6c, 0x6d, 0x0, 0x6c, 0x6e, 0x0, 0x6c, 0x6f, 0x67, 0x0, 0x6c, 0x78, 0x0, 0x6c, 0xb7, 0x0, 0x6c, 0x301, 0x0, 0x6c, 0x30c, 0x0, 0x6c, 0x323, 0x0, 0x6c, 0x323, 0x304, 0x0, 0x6c, 0x327, 0x0, 0x6c, 0x32d, 0x0, 0x6c, 0x331, 0x0, 0x6d, 0x0, 0x6d, 0x32, 0x0, 0x6d, 0x33, 0x0, 0x6d, 0x41, 0x0, 0x6d, 0x56, 0x0, 0x6d, 0x57, 0x0, 0x6d, 0x62, 0x0, 0x6d, 0x67, 0x0, 0x6d, 0x69, 0x6c, 0x0, 0x6d, 0x6c, 0x0, 0x6d, 0x6d, 0x0, 0x6d, 0x6d, 0x32, 0x0, 0x6d, 0x6d, 0x33, 0x0, 0x6d, 0x6f, 0x6c, 0x0, 0x6d, 0x73, 0x0, 0x6d, 0x301, 0x0, 0x6d, 0x307, 0x0, 0x6d, 0x323, 0x0, 0x6d, 0x2215, 0x73, 0x0, 0x6d, 0x2215, 0x73, 0x32, 0x0, 0x6e, 0x0, 0x6e, 0x41, 0x0, 0x6e, 0x46, 0x0, 0x6e, 0x56, 0x0, 0x6e, 0x57, 0x0, 0x6e, 0x6a, 0x0, 0x6e, 0x6d, 0x0, 0x6e, 0x73, 0x0, 0x6e, 0x300, 0x0, 0x6e, 0x301, 0x0, 0x6e, 0x303, 0x0, 0x6e, 0x307, 0x0, 0x6e, 0x30c, 0x0, 0x6e, 0x323, 0x0, 0x6e, 0x327, 0x0, 0x6e, 0x32d, 0x0, 0x6e, 0x331, 0x0, 0x6f, 0x0, 0x6f, 0x56, 0x0, 0x6f, 0x300, 0x0, 0x6f, 0x301, 0x0, 0x6f, 0x302, 0x0, 0x6f, 0x302, 0x300, 0x0, 0x6f, 0x302, 0x301, 0x0, 0x6f, 0x302, 0x303, 0x0, 0x6f, 0x302, 0x309, 0x0, 0x6f, 0x303, 0x0, 0x6f, 0x303, 0x301, 0x0, 0x6f, 0x303, 0x304, 0x0, 0x6f, 0x303, 0x308, 0x0, 0x6f, 0x304, 0x0, 0x6f, 0x304, 0x300, 0x0, 0x6f, 0x304, 0x301, 0x0, 0x6f, 0x306, 0x0, 0x6f, 0x307, 0x0, 0x6f, 0x307, 0x304, 0x0, 0x6f, 0x308, 0x0, 0x6f, 0x308, 0x304, 0x0, 0x6f, 0x309, 0x0, 0x6f, 0x30b, 0x0, 0x6f, 0x30c, 0x0, 0x6f, 0x30f, 0x0, 0x6f, 0x311, 0x0, 0x6f, 0x31b, 0x0, 0x6f, 0x31b, 0x300, 0x0, 0x6f, 0x31b, 0x301, 0x0, 0x6f, 0x31b, 0x303, 0x0, 0x6f, 0x31b, 0x309, 0x0, 0x6f, 0x31b, 0x323, 0x0, 0x6f, 0x323, 0x0, 0x6f, 0x323, 0x302, 0x0, 0x6f, 0x328, 0x0, 0x6f, 0x328, 0x304, 0x0, 0x70, 0x0, 0x70, 0x2e, 0x6d, 0x2e, 0x0, 0x70, 0x41, 0x0, 0x70, 0x46, 0x0, 0x70, 0x56, 0x0, 0x70, 0x57, 0x0, 0x70, 0x63, 0x0, 0x70, 0x73, 0x0, 0x70, 0x301, 0x0, 0x70, 0x307, 0x0, 0x71, 0x0, 0x72, 0x0, 0x72, 0x61, 0x64, 0x0, 0x72, 0x61, 0x64, 0x2215, 0x73, 0x0, 0x72, 0x61, 0x64, 0x2215, 0x73, 0x32, 0x0, 0x72, 0x301, 0x0, 0x72, 0x307, 0x0, 0x72, 0x30c, 0x0, 0x72, 0x30f, 0x0, 0x72, 0x311, 0x0, 0x72, 0x323, 0x0, 0x72, 0x323, 0x304, 0x0, 0x72, 0x327, 0x0, 0x72, 0x331, 0x0, 0x73, 0x0, 0x73, 0x72, 0x0, 0x73, 0x74, 0x0, 0x73, 0x301, 0x0, 0x73, 0x301, 0x307, 0x0, 0x73, 0x302, 0x0, 0x73, 0x307, 0x0, 0x73, 0x30c, 0x0, 0x73, 0x30c, 0x307, 0x0, 0x73, 0x323, 0x0, 0x73, 0x323, 0x307, 0x0, 0x73, 0x326, 0x0, 0x73, 0x327, 0x0, 0x74, 0x0, 0x74, 0x307, 0x0, 0x74, 0x308, 0x0, 0x74, 0x30c, 0x0, 0x74, 0x323, 0x0, 0x74, 0x326, 0x0, 0x74, 0x327, 0x0, 0x74, 0x32d, 0x0, 0x74, 0x331, 0x0, 0x75, 0x0, 0x75, 0x300, 0x0, 0x75, 0x301, 0x0, 0x75, 0x302, 0x0, 0x75, 0x303, 0x0, 0x75, 0x303, 0x301, 0x0, 0x75, 0x304, 0x0, 0x75, 0x304, 0x308, 0x0, 0x75, 0x306, 0x0, 0x75, 0x308, 0x0, 0x75, 0x308, 0x300, 0x0, 0x75, 0x308, 0x301, 0x0, 0x75, 0x308, 0x304, 0x0, 0x75, 0x308, 0x30c, 0x0, 0x75, 0x309, 0x0, 0x75, 0x30a, 0x0, 0x75, 0x30b, 0x0, 0x75, 0x30c, 0x0, 0x75, 0x30f, 0x0, 0x75, 0x311, 0x0, 0x75, 0x31b, 0x0, 0x75, 0x31b, 0x300, 0x0, 0x75, 0x31b, 0x301, 0x0, 0x75, 0x31b, 0x303, 0x0, 0x75, 0x31b, 0x309, 0x0, 0x75, 0x31b, 0x323, 0x0, 0x75, 0x323, 0x0, 0x75, 0x324, 0x0, 0x75, 0x328, 0x0, 0x75, 0x32d, 0x0, 0x75, 0x330, 0x0, 0x76, 0x0, 0x76, 0x69, 0x0, 0x76, 0x69, 0x69, 0x0, 0x76, 0x69, 0x69, 0x69, 0x0, 0x76, 0x303, 0x0, 0x76, 0x323, 0x0, 0x77, 0x0, 0x77, 0x300, 0x0, 0x77, 0x301, 0x0, 0x77, 0x302, 0x0, 0x77, 0x307, 0x0, 0x77, 0x308, 0x0, 0x77, 0x30a, 0x0, 0x77, 0x323, 0x0, 0x78, 0x0, 0x78, 0x69, 0x0, 0x78, 0x69, 0x69, 0x0, 0x78, 0x307, 0x0, 0x78, 0x308, 0x0, 0x79, 0x0, 0x79, 0x300, 0x0, 0x79, 0x301, 0x0, 0x79, 0x302, 0x0, 0x79, 0x303, 0x0, 0x79, 0x304, 0x0, 0x79, 0x307, 0x0, 0x79, 0x308, 0x0, 0x79, 0x309, 0x0, 0x79, 0x30a, 0x0, 0x79, 0x323, 0x0, 0x7a, 0x0, 0x7a, 0x301, 0x0, 0x7a, 0x302, 0x0, 0x7a, 0x307, 0x0, 0x7a, 0x30c, 0x0, 0x7a, 0x323, 0x0, 0x7a, 0x331, 0x0, 0x7b, 0x0, 0x7c, 0x0, 0x7d, 0x0, 0x7e, 0x0, 0xa2, 0x0, 0xa3, 0x0, 0xa5, 0x0, 0xa6, 0x0, 0xac, 0x0, 0xb0, 0x43, 0x0, 0xb0, 0x46, 0x0, 0xb7, 0x0, 0xc6, 0x0, 0xc6, 0x301, 0x0, 0xc6, 0x304, 0x0, 0xd8, 0x301, 0x0, 0xe6, 0x301, 0x0, 0xe6, 0x304, 0x0, 0xf0, 0x0, 0xf8, 0x301, 0x0, 0x126, 0x0, 0x127, 0x0, 0x131, 0x0, 0x14b, 0x0, 0x153, 0x0, 0x18e, 0x0, 0x190, 0x0, 0x1ab, 0x0, 0x1b7, 0x30c, 0x0, 0x222, 0x0, 0x237, 0x0, 0x250, 0x0, 0x251, 0x0, 0x252, 0x0, 0x254, 0x0, 0x255, 0x0, 0x259, 0x0, 0x25b, 0x0, 0x25c, 0x0, 0x25f, 0x0, 0x261, 0x0, 0x263, 0x0, 0x265, 0x0, 0x266, 0x0, 0x268, 0x0, 0x269, 0x0, 0x26a, 0x0, 0x26d, 0x0, 0x26f, 0x0, 0x270, 0x0, 0x271, 0x0, 0x272, 0x0, 0x273, 0x0, 0x274, 0x0, 0x275, 0x0, 0x278, 0x0, 0x279, 0x0, 0x27b, 0x0, 0x281, 0x0, 0x282, 0x0, 0x283, 0x0, 0x289, 0x0, 0x28a, 0x0, 0x28b, 0x0, 0x28c, 0x0, 0x290, 0x0, 0x291, 0x0, 0x292, 0x0, 0x292, 0x30c, 0x0, 0x295, 0x0, 0x29d, 0x0, 0x29f, 0x0, 0x2b9, 0x0, 0x2bc, 0x6e, 0x0, 0x300, 0x0, 0x301, 0x0, 0x308, 0x301, 0x0, 0x313, 0x0, 0x391, 0x0, 0x391, 0x300, 0x0, 0x391, 0x301, 0x0, 0x391, 0x304, 0x0, 0x391, 0x306, 0x0, 0x391, 0x313, 0x0, 0x391, 0x313, 0x300, 0x0, 0x391, 0x313, 0x300, 0x345, 0x0, 0x391, 0x313, 0x301, 0x0, 0x391, 0x313, 0x301, 0x345, 0x0, 0x391, 0x313, 0x342, 0x0, 0x391, 0x313, 0x342, 0x345, 0x0, 0x391, 0x313, 0x345, 0x0, 0x391, 0x314, 0x0, 0x391, 0x314, 0x300, 0x0, 0x391, 0x314, 0x300, 0x345, 0x0, 0x391, 0x314, 0x301, 0x0, 0x391, 0x314, 0x301, 0x345, 0x0, 0x391, 0x314, 0x342, 0x0, 0x391, 0x314, 0x342, 0x345, 0x0, 0x391, 0x314, 0x345, 0x0, 0x391, 0x345, 0x0, 0x392, 0x0, 0x393, 0x0, 0x394, 0x0, 0x395, 0x0, 0x395, 0x300, 0x0, 0x395, 0x301, 0x0, 0x395, 0x313, 0x0, 0x395, 0x313, 0x300, 0x0, 0x395, 0x313, 0x301, 0x0, 0x395, 0x314, 0x0, 0x395, 0x314, 0x300, 0x0, 0x395, 0x314, 0x301, 0x0, 0x396, 0x0, 0x397, 0x0, 0x397, 0x300, 0x0, 0x397, 0x301, 0x0, 0x397, 0x313, 0x0, 0x397, 0x313, 0x300, 0x0, 0x397, 0x313, 0x300, 0x345, 0x0, 0x397, 0x313, 0x301, 0x0, 0x397, 0x313, 0x301, 0x345, 0x0, 0x397, 0x313, 0x342, 0x0, 0x397, 0x313, 0x342, 0x345, 0x0, 0x397, 0x313, 0x345, 0x0, 0x397, 0x314, 0x0, 0x397, 0x314, 0x300, 0x0, 0x397, 0x314, 0x300, 0x345, 0x0, 0x397, 0x314, 0x301, 0x0, 0x397, 0x314, 0x301, 0x345, 0x0, 0x397, 0x314, 0x342, 0x0, 0x397, 0x314, 0x342, 0x345, 0x0, 0x397, 0x314, 0x345, 0x0, 0x397, 0x345, 0x0, 0x398, 0x0, 0x399, 0x0, 0x399, 0x300, 0x0, 0x399, 0x301, 0x0, 0x399, 0x304, 0x0, 0x399, 0x306, 0x0, 0x399, 0x308, 0x0, 0x399, 0x313, 0x0, 0x399, 0x313, 0x300, 0x0, 0x399, 0x313, 0x301, 0x0, 0x399, 0x313, 0x342, 0x0, 0x399, 0x314, 0x0, 0x399, 0x314, 0x300, 0x0, 0x399, 0x314, 0x301, 0x0, 0x399, 0x314, 0x342, 0x0, 0x39a, 0x0, 0x39b, 0x0, 0x39c, 0x0, 0x39d, 0x0, 0x39e, 0x0, 0x39f, 0x0, 0x39f, 0x300, 0x0, 0x39f, 0x301, 0x0, 0x39f, 0x313, 0x0, 0x39f, 0x313, 0x300, 0x0, 0x39f, 0x313, 0x301, 0x0, 0x39f, 0x314, 0x0, 0x39f, 0x314, 0x300, 0x0, 0x39f, 0x314, 0x301, 0x0, 0x3a0, 0x0, 0x3a1, 0x0, 0x3a1, 0x314, 0x0, 0x3a3, 0x0, 0x3a4, 0x0, 0x3a5, 0x0, 0x3a5, 0x300, 0x0, 0x3a5, 0x301, 0x0, 0x3a5, 0x304, 0x0, 0x3a5, 0x306, 0x0, 0x3a5, 0x308, 0x0, 0x3a5, 0x314, 0x0, 0x3a5, 0x314, 0x300, 0x0, 0x3a5, 0x314, 0x301, 0x0, 0x3a5, 0x314, 0x342, 0x0, 0x3a6, 0x0, 0x3a7, 0x0, 0x3a8, 0x0, 0x3a9, 0x0, 0x3a9, 0x300, 0x0, 0x3a9, 0x301, 0x0, 0x3a9, 0x313, 0x0, 0x3a9, 0x313, 0x300, 0x0, 0x3a9, 0x313, 0x300, 0x345, 0x0, 0x3a9, 0x313, 0x301, 0x0, 0x3a9, 0x313, 0x301, 0x345, 0x0, 0x3a9, 0x313, 0x342, 0x0, 0x3a9, 0x313, 0x342, 0x345, 0x0, 0x3a9, 0x313, 0x345, 0x0, 0x3a9, 0x314, 0x0, 0x3a9, 0x314, 0x300, 0x0, 0x3a9, 0x314, 0x300, 0x345, 0x0, 0x3a9, 0x314, 0x301, 0x0, 0x3a9, 0x314, 0x301, 0x345, 0x0, 0x3a9, 0x314, 0x342, 0x0, 0x3a9, 0x314, 0x342, 0x345, 0x0, 0x3a9, 0x314, 0x345, 0x0, 0x3a9, 0x345, 0x0, 0x3b1, 0x0, 0x3b1, 0x300, 0x0, 0x3b1, 0x300, 0x345, 0x0, 0x3b1, 0x301, 0x0, 0x3b1, 0x301, 0x345, 0x0, 0x3b1, 0x304, 0x0, 0x3b1, 0x306, 0x0, 0x3b1, 0x313, 0x0, 0x3b1, 0x313, 0x300, 0x0, 0x3b1, 0x313, 0x300, 0x345, 0x0, 0x3b1, 0x313, 0x301, 0x0, 0x3b1, 0x313, 0x301, 0x345, 0x0, 0x3b1, 0x313, 0x342, 0x0, 0x3b1, 0x313, 0x342, 0x345, 0x0, 0x3b1, 0x313, 0x345, 0x0, 0x3b1, 0x314, 0x0, 0x3b1, 0x314, 0x300, 0x0, 0x3b1, 0x314, 0x300, 0x345, 0x0, 0x3b1, 0x314, 0x301, 0x0, 0x3b1, 0x314, 0x301, 0x345, 0x0, 0x3b1, 0x314, 0x342, 0x0, 0x3b1, 0x314, 0x342, 0x345, 0x0, 0x3b1, 0x314, 0x345, 0x0, 0x3b1, 0x342, 0x0, 0x3b1, 0x342, 0x345, 0x0, 0x3b1, 0x345, 0x0, 0x3b2, 0x0, 0x3b3, 0x0, 0x3b4, 0x0, 0x3b5, 0x0, 0x3b5, 0x300, 0x0, 0x3b5, 0x301, 0x0, 0x3b5, 0x313, 0x0, 0x3b5, 0x313, 0x300, 0x0, 0x3b5, 0x313, 0x301, 0x0, 0x3b5, 0x314, 0x0, 0x3b5, 0x314, 0x300, 0x0, 0x3b5, 0x314, 0x301, 0x0, 0x3b6, 0x0, 0x3b7, 0x0, 0x3b7, 0x300, 0x0, 0x3b7, 0x300, 0x345, 0x0, 0x3b7, 0x301, 0x0, 0x3b7, 0x301, 0x345, 0x0, 0x3b7, 0x313, 0x0, 0x3b7, 0x313, 0x300, 0x0, 0x3b7, 0x313, 0x300, 0x345, 0x0, 0x3b7, 0x313, 0x301, 0x0, 0x3b7, 0x313, 0x301, 0x345, 0x0, 0x3b7, 0x313, 0x342, 0x0, 0x3b7, 0x313, 0x342, 0x345, 0x0, 0x3b7, 0x313, 0x345, 0x0, 0x3b7, 0x314, 0x0, 0x3b7, 0x314, 0x300, 0x0, 0x3b7, 0x314, 0x300, 0x345, 0x0, 0x3b7, 0x314, 0x301, 0x0, 0x3b7, 0x314, 0x301, 0x345, 0x0, 0x3b7, 0x314, 0x342, 0x0, 0x3b7, 0x314, 0x342, 0x345, 0x0, 0x3b7, 0x314, 0x345, 0x0, 0x3b7, 0x342, 0x0, 0x3b7, 0x342, 0x345, 0x0, 0x3b7, 0x345, 0x0, 0x3b8, 0x0, 0x3b9, 0x0, 0x3b9, 0x300, 0x0, 0x3b9, 0x301, 0x0, 0x3b9, 0x304, 0x0, 0x3b9, 0x306, 0x0, 0x3b9, 0x308, 0x0, 0x3b9, 0x308, 0x300, 0x0, 0x3b9, 0x308, 0x301, 0x0, 0x3b9, 0x308, 0x342, 0x0, 0x3b9, 0x313, 0x0, 0x3b9, 0x313, 0x300, 0x0, 0x3b9, 0x313, 0x301, 0x0, 0x3b9, 0x313, 0x342, 0x0, 0x3b9, 0x314, 0x0, 0x3b9, 0x314, 0x300, 0x0, 0x3b9, 0x314, 0x301, 0x0, 0x3b9, 0x314, 0x342, 0x0, 0x3b9, 0x342, 0x0, 0x3ba, 0x0, 0x3bb, 0x0, 0x3bc, 0x0, 0x3bc, 0x41, 0x0, 0x3bc, 0x46, 0x0, 0x3bc, 0x56, 0x0, 0x3bc, 0x57, 0x0, 0x3bc, 0x67, 0x0, 0x3bc, 0x6c, 0x0, 0x3bc, 0x6d, 0x0, 0x3bc, 0x73, 0x0, 0x3bd, 0x0, 0x3be, 0x0, 0x3bf, 0x0, 0x3bf, 0x300, 0x0, 0x3bf, 0x301, 0x0, 0x3bf, 0x313, 0x0, 0x3bf, 0x313, 0x300, 0x0, 0x3bf, 0x313, 0x301, 0x0, 0x3bf, 0x314, 0x0, 0x3bf, 0x314, 0x300, 0x0, 0x3bf, 0x314, 0x301, 0x0, 0x3c0, 0x0, 0x3c1, 0x0, 0x3c1, 0x313, 0x0, 0x3c1, 0x314, 0x0, 0x3c2, 0x0, 0x3c3, 0x0, 0x3c4, 0x0, 0x3c5, 0x0, 0x3c5, 0x300, 0x0, 0x3c5, 0x301, 0x0, 0x3c5, 0x304, 0x0, 0x3c5, 0x306, 0x0, 0x3c5, 0x308, 0x0, 0x3c5, 0x308, 0x300, 0x0, 0x3c5, 0x308, 0x301, 0x0, 0x3c5, 0x308, 0x342, 0x0, 0x3c5, 0x313, 0x0, 0x3c5, 0x313, 0x300, 0x0, 0x3c5, 0x313, 0x301, 0x0, 0x3c5, 0x313, 0x342, 0x0, 0x3c5, 0x314, 0x0, 0x3c5, 0x314, 0x300, 0x0, 0x3c5, 0x314, 0x301, 0x0, 0x3c5, 0x314, 0x342, 0x0, 0x3c5, 0x342, 0x0, 0x3c6, 0x0, 0x3c7, 0x0, 0x3c8, 0x0, 0x3c9, 0x0, 0x3c9, 0x300, 0x0, 0x3c9, 0x300, 0x345, 0x0, 0x3c9, 0x301, 0x0, 0x3c9, 0x301, 0x345, 0x0, 0x3c9, 0x313, 0x0, 0x3c9, 0x313, 0x300, 0x0, 0x3c9, 0x313, 0x300, 0x345, 0x0, 0x3c9, 0x313, 0x301, 0x0, 0x3c9, 0x313, 0x301, 0x345, 0x0, 0x3c9, 0x313, 0x342, 0x0, 0x3c9, 0x313, 0x342, 0x345, 0x0, 0x3c9, 0x313, 0x345, 0x0, 0x3c9, 0x314, 0x0, 0x3c9, 0x314, 0x300, 0x0, 0x3c9, 0x314, 0x300, 0x345, 0x0, 0x3c9, 0x314, 0x301, 0x0, 0x3c9, 0x314, 0x301, 0x345, 0x0, 0x3c9, 0x314, 0x342, 0x0, 0x3c9, 0x314, 0x342, 0x345, 0x0, 0x3c9, 0x314, 0x345, 0x0, 0x3c9, 0x342, 0x0, 0x3c9, 0x342, 0x345, 0x0, 0x3c9, 0x345, 0x0, 0x3dc, 0x0, 0x3dd, 0x0, 0x406, 0x308, 0x0, 0x410, 0x306, 0x0, 0x410, 0x308, 0x0, 0x413, 0x301, 0x0, 0x415, 0x300, 0x0, 0x415, 0x306, 0x0, 0x415, 0x308, 0x0, 0x416, 0x306, 0x0, 0x416, 0x308, 0x0, 0x417, 0x308, 0x0, 0x418, 0x300, 0x0, 0x418, 0x304, 0x0, 0x418, 0x306, 0x0, 0x418, 0x308, 0x0, 0x41a, 0x301, 0x0, 0x41e, 0x308, 0x0, 0x423, 0x304, 0x0, 0x423, 0x306, 0x0, 0x423, 0x308, 0x0, 0x423, 0x30b, 0x0, 0x427, 0x308, 0x0, 0x42b, 0x308, 0x0, 0x42d, 0x308, 0x0, 0x430, 0x306, 0x0, 0x430, 0x308, 0x0, 0x433, 0x301, 0x0, 0x435, 0x300, 0x0, 0x435, 0x306, 0x0, 0x435, 0x308, 0x0, 0x436, 0x306, 0x0, 0x436, 0x308, 0x0, 0x437, 0x308, 0x0, 0x438, 0x300, 0x0, 0x438, 0x304, 0x0, 0x438, 0x306, 0x0, 0x438, 0x308, 0x0, 0x43a, 0x301, 0x0, 0x43d, 0x0, 0x43e, 0x308, 0x0, 0x443, 0x304, 0x0, 0x443, 0x306, 0x0, 0x443, 0x308, 0x0, 0x443, 0x30b, 0x0, 0x447, 0x308, 0x0, 0x44b, 0x308, 0x0, 0x44d, 0x308, 0x0, 0x456, 0x308, 0x0, 0x474, 0x30f, 0x0, 0x475, 0x30f, 0x0, 0x4d8, 0x308, 0x0, 0x4d9, 0x308, 0x0, 0x4e8, 0x308, 0x0, 0x4e9, 0x308, 0x0, 0x565, 0x582, 0x0, 0x574, 0x565, 0x0, 0x574, 0x56b, 0x0, 0x574, 0x56d, 0x0, 0x574, 0x576, 0x0, 0x57e, 0x576, 0x0, 0x5d0, 0x0, 0x5d0, 0x5b7, 0x0, 0x5d0, 0x5b8, 0x0, 0x5d0, 0x5bc, 0x0, 0x5d0, 0x5dc, 0x0, 0x5d1, 0x0, 0x5d1, 0x5bc, 0x0, 0x5d1, 0x5bf, 0x0, 0x5d2, 0x0, 0x5d2, 0x5bc, 0x0, 0x5d3, 0x0, 0x5d3, 0x5bc, 0x0, 0x5d4, 0x0, 0x5d4, 0x5bc, 0x0, 0x5d5, 0x5b9, 0x0, 0x5d5, 0x5bc, 0x0, 0x5d6, 0x5bc, 0x0, 0x5d8, 0x5bc, 0x0, 0x5d9, 0x5b4, 0x0, 0x5d9, 0x5bc, 0x0, 0x5da, 0x5bc, 0x0, 0x5db, 0x0, 0x5db, 0x5bc, 0x0, 0x5db, 0x5bf, 0x0, 0x5dc, 0x0, 0x5dc, 0x5bc, 0x0, 0x5dd, 0x0, 0x5de, 0x5bc, 0x0, 0x5e0, 0x5bc, 0x0, 0x5e1, 0x5bc, 0x0, 0x5e2, 0x0, 0x5e3, 0x5bc, 0x0, 0x5e4, 0x5bc, 0x0, 0x5e4, 0x5bf, 0x0, 0x5e6, 0x5bc, 0x0, 0x5e7, 0x5bc, 0x0, 0x5e8, 0x0, 0x5e8, 0x5bc, 0x0, 0x5e9, 0x5bc, 0x0, 0x5e9, 0x5bc, 0x5c1, 0x0, 0x5e9, 0x5bc, 0x5c2, 0x0, 0x5e9, 0x5c1, 0x0, 0x5e9, 0x5c2, 0x0, 0x5ea, 0x0, 0x5ea, 0x5bc, 0x0, 0x5f2, 0x5b7, 0x0, 0x621, 0x0, 0x627, 0x0, 0x627, 0x643, 0x628, 0x631, 0x0, 0x627, 0x644, 0x644, 0x647, 0x0, 0x627, 0x64b, 0x0, 0x627, 0x653, 0x0, 0x627, 0x654, 0x0, 0x627, 0x655, 0x0, 0x627, 0x674, 0x0, 0x628, 0x0, 0x628, 0x62c, 0x0, 0x628, 0x62d, 0x0, 0x628, 0x62d, 0x64a, 0x0, 0x628, 0x62e, 0x0, 0x628, 0x62e, 0x64a, 0x0, 0x628, 0x631, 0x0, 0x628, 0x632, 0x0, 0x628, 0x645, 0x0, 0x628, 0x646, 0x0, 0x628, 0x647, 0x0, 0x628, 0x649, 0x0, 0x628, 0x64a, 0x0, 0x629, 0x0, 0x62a, 0x0, 0x62a, 0x62c, 0x0, 0x62a, 0x62c, 0x645, 0x0, 0x62a, 0x62c, 0x649, 0x0, 0x62a, 0x62c, 0x64a, 0x0, 0x62a, 0x62d, 0x0, 0x62a, 0x62d, 0x62c, 0x0, 0x62a, 0x62d, 0x645, 0x0, 0x62a, 0x62e, 0x0, 0x62a, 0x62e, 0x645, 0x0, 0x62a, 0x62e, 0x649, 0x0, 0x62a, 0x62e, 0x64a, 0x0, 0x62a, 0x631, 0x0, 0x62a, 0x632, 0x0, 0x62a, 0x645, 0x0, 0x62a, 0x645, 0x62c, 0x0, 0x62a, 0x645, 0x62d, 0x0, 0x62a, 0x645, 0x62e, 0x0, 0x62a, 0x645, 0x649, 0x0, 0x62a, 0x645, 0x64a, 0x0, 0x62a, 0x646, 0x0, 0x62a, 0x647, 0x0, 0x62a, 0x649, 0x0, 0x62a, 0x64a, 0x0, 0x62b, 0x0, 0x62b, 0x62c, 0x0, 0x62b, 0x631, 0x0, 0x62b, 0x632, 0x0, 0x62b, 0x645, 0x0, 0x62b, 0x646, 0x0, 0x62b, 0x647, 0x0, 0x62b, 0x649, 0x0, 0x62b, 0x64a, 0x0, 0x62c, 0x0, 0x62c, 0x62d, 0x0, 0x62c, 0x62d, 0x649, 0x0, 0x62c, 0x62d, 0x64a, 0x0, 0x62c, 0x644, 0x20, 0x62c, 0x644, 0x627, 0x644, 0x647, 0x0, 0x62c, 0x645, 0x0, 0x62c, 0x645, 0x62d, 0x0, 0x62c, 0x645, 0x649, 0x0, 0x62c, 0x645, 0x64a, 0x0, 0x62c, 0x649, 0x0, 0x62c, 0x64a, 0x0, 0x62d, 0x0, 0x62d, 0x62c, 0x0, 0x62d, 0x62c, 0x64a, 0x0, 0x62d, 0x645, 0x0, 0x62d, 0x645, 0x649, 0x0, 0x62d, 0x645, 0x64a, 0x0, 0x62d, 0x649, 0x0, 0x62d, 0x64a, 0x0, 0x62e, 0x0, 0x62e, 0x62c, 0x0, 0x62e, 0x62d, 0x0, 0x62e, 0x645, 0x0, 0x62e, 0x649, 0x0, 0x62e, 0x64a, 0x0, 0x62f, 0x0, 0x630, 0x0, 0x630, 0x670, 0x0, 0x631, 0x0, 0x631, 0x633, 0x648, 0x644, 0x0, 0x631, 0x670, 0x0, 0x631, 0x6cc, 0x627, 0x644, 0x0, 0x632, 0x0, 0x633, 0x0, 0x633, 0x62c, 0x0, 0x633, 0x62c, 0x62d, 0x0, 0x633, 0x62c, 0x649, 0x0, 0x633, 0x62d, 0x0, 0x633, 0x62d, 0x62c, 0x0, 0x633, 0x62e, 0x0, 0x633, 0x62e, 0x649, 0x0, 0x633, 0x62e, 0x64a, 0x0, 0x633, 0x631, 0x0, 0x633, 0x645, 0x0, 0x633, 0x645, 0x62c, 0x0, 0x633, 0x645, 0x62d, 0x0, 0x633, 0x645, 0x645, 0x0, 0x633, 0x647, 0x0, 0x633, 0x649, 0x0, 0x633, 0x64a, 0x0, 0x634, 0x0, 0x634, 0x62c, 0x0, 0x634, 0x62c, 0x64a, 0x0, 0x634, 0x62d, 0x0, 0x634, 0x62d, 0x645, 0x0, 0x634, 0x62d, 0x64a, 0x0, 0x634, 0x62e, 0x0, 0x634, 0x631, 0x0, 0x634, 0x645, 0x0, 0x634, 0x645, 0x62e, 0x0, 0x634, 0x645, 0x645, 0x0, 0x634, 0x647, 0x0, 0x634, 0x649, 0x0, 0x634, 0x64a, 0x0, 0x635, 0x0, 0x635, 0x62d, 0x0, 0x635, 0x62d, 0x62d, 0x0, 0x635, 0x62d, 0x64a, 0x0, 0x635, 0x62e, 0x0, 0x635, 0x631, 0x0, 0x635, 0x644, 0x639, 0x645, 0x0, 0x635, 0x644, 0x649, 0x0, 0x635, 0x644, 0x649, 0x20, 0x627, 0x644, 0x644, 0x647, 0x20, 0x639, 0x644, 0x64a, 0x647, 0x20, 0x648, 0x633, 0x644, 0x645, 0x0, 0x635, 0x644, 0x6d2, 0x0, 0x635, 0x645, 0x0, 0x635, 0x645, 0x645, 0x0, 0x635, 0x649, 0x0, 0x635, 0x64a, 0x0, 0x636, 0x0, 0x636, 0x62c, 0x0, 0x636, 0x62d, 0x0, 0x636, 0x62d, 0x649, 0x0, 0x636, 0x62d, 0x64a, 0x0, 0x636, 0x62e, 0x0, 0x636, 0x62e, 0x645, 0x0, 0x636, 0x631, 0x0, 0x636, 0x645, 0x0, 0x636, 0x649, 0x0, 0x636, 0x64a, 0x0, 0x637, 0x0, 0x637, 0x62d, 0x0, 0x637, 0x645, 0x0, 0x637, 0x645, 0x62d, 0x0, 0x637, 0x645, 0x645, 0x0, 0x637, 0x645, 0x64a, 0x0, 0x637, 0x649, 0x0, 0x637, 0x64a, 0x0, 0x638, 0x0, 0x638, 0x645, 0x0, 0x639, 0x0, 0x639, 0x62c, 0x0, 0x639, 0x62c, 0x645, 0x0, 0x639, 0x644, 0x64a, 0x647, 0x0, 0x639, 0x645, 0x0, 0x639, 0x645, 0x645, 0x0, 0x639, 0x645, 0x649, 0x0, 0x639, 0x645, 0x64a, 0x0, 0x639, 0x649, 0x0, 0x639, 0x64a, 0x0, 0x63a, 0x0, 0x63a, 0x62c, 0x0, 0x63a, 0x645, 0x0, 0x63a, 0x645, 0x645, 0x0, 0x63a, 0x645, 0x649, 0x0, 0x63a, 0x645, 0x64a, 0x0, 0x63a, 0x649, 0x0, 0x63a, 0x64a, 0x0, 0x640, 0x64b, 0x0, 0x640, 0x64e, 0x0, 0x640, 0x64e, 0x651, 0x0, 0x640, 0x64f, 0x0, 0x640, 0x64f, 0x651, 0x0, 0x640, 0x650, 0x0, 0x640, 0x650, 0x651, 0x0, 0x640, 0x651, 0x0, 0x640, 0x652, 0x0, 0x641, 0x0, 0x641, 0x62c, 0x0, 0x641, 0x62d, 0x0, 0x641, 0x62e, 0x0, 0x641, 0x62e, 0x645, 0x0, 0x641, 0x645, 0x0, 0x641, 0x645, 0x64a, 0x0, 0x641, 0x649, 0x0, 0x641, 0x64a, 0x0, 0x642, 0x0, 0x642, 0x62d, 0x0, 0x642, 0x644, 0x6d2, 0x0, 0x642, 0x645, 0x0, 0x642, 0x645, 0x62d, 0x0, 0x642, 0x645, 0x645, 0x0, 0x642, 0x645, 0x64a, 0x0, 0x642, 0x649, 0x0, 0x642, 0x64a, 0x0, 0x643, 0x0, 0x643, 0x627, 0x0, 0x643, 0x62c, 0x0, 0x643, 0x62d, 0x0, 0x643, 0x62e, 0x0, 0x643, 0x644, 0x0, 0x643, 0x645, 0x0, 0x643, 0x645, 0x645, 0x0, 0x643, 0x645, 0x64a, 0x0, 0x643, 0x649, 0x0, 0x643, 0x64a, 0x0, 0x644, 0x0, 0x644, 0x627, 0x0, 0x644, 0x627, 0x653, 0x0, 0x644, 0x627, 0x654, 0x0, 0x644, 0x627, 0x655, 0x0, 0x644, 0x62c, 0x0, 0x644, 0x62c, 0x62c, 0x0, 0x644, 0x62c, 0x645, 0x0, 0x644, 0x62c, 0x64a, 0x0, 0x644, 0x62d, 0x0, 0x644, 0x62d, 0x645, 0x0, 0x644, 0x62d, 0x649, 0x0, 0x644, 0x62d, 0x64a, 0x0, 0x644, 0x62e, 0x0, 0x644, 0x62e, 0x645, 0x0, 0x644, 0x645, 0x0, 0x644, 0x645, 0x62d, 0x0, 0x644, 0x645, 0x64a, 0x0, 0x644, 0x647, 0x0, 0x644, 0x649, 0x0, 0x644, 0x64a, 0x0, 0x645, 0x0, 0x645, 0x627, 0x0, 0x645, 0x62c, 0x0, 0x645, 0x62c, 0x62d, 0x0, 0x645, 0x62c, 0x62e, 0x0, 0x645, 0x62c, 0x645, 0x0, 0x645, 0x62c, 0x64a, 0x0, 0x645, 0x62d, 0x0, 0x645, 0x62d, 0x62c, 0x0, 0x645, 0x62d, 0x645, 0x0, 0x645, 0x62d, 0x645, 0x62f, 0x0, 0x645, 0x62d, 0x64a, 0x0, 0x645, 0x62e, 0x0, 0x645, 0x62e, 0x62c, 0x0, 0x645, 0x62e, 0x645, 0x0, 0x645, 0x62e, 0x64a, 0x0, 0x645, 0x645, 0x0, 0x645, 0x645, 0x64a, 0x0, 0x645, 0x649, 0x0, 0x645, 0x64a, 0x0, 0x646, 0x0, 0x646, 0x62c, 0x0, 0x646, 0x62c, 0x62d, 0x0, 0x646, 0x62c, 0x645, 0x0, 0x646, 0x62c, 0x649, 0x0, 0x646, 0x62c, 0x64a, 0x0, 0x646, 0x62d, 0x0, 0x646, 0x62d, 0x645, 0x0, 0x646, 0x62d, 0x649, 0x0, 0x646, 0x62d, 0x64a, 0x0, 0x646, 0x62e, 0x0, 0x646, 0x631, 0x0, 0x646, 0x632, 0x0, 0x646, 0x645, 0x0, 0x646, 0x645, 0x649, 0x0, 0x646, 0x645, 0x64a, 0x0, 0x646, 0x646, 0x0, 0x646, 0x647, 0x0, 0x646, 0x649, 0x0, 0x646, 0x64a, 0x0, 0x647, 0x0, 0x647, 0x62c, 0x0, 0x647, 0x645, 0x0, 0x647, 0x645, 0x62c, 0x0, 0x647, 0x645, 0x645, 0x0, 0x647, 0x649, 0x0, 0x647, 0x64a, 0x0, 0x647, 0x670, 0x0, 0x648, 0x0, 0x648, 0x633, 0x644, 0x645, 0x0, 0x648, 0x654, 0x0, 0x648, 0x674, 0x0, 0x649, 0x0, 0x649, 0x670, 0x0, 0x64a, 0x0, 0x64a, 0x62c, 0x0, 0x64a, 0x62c, 0x64a, 0x0, 0x64a, 0x62d, 0x0, 0x64a, 0x62d, 0x64a, 0x0, 0x64a, 0x62e, 0x0, 0x64a, 0x631, 0x0, 0x64a, 0x632, 0x0, 0x64a, 0x645, 0x0, 0x64a, 0x645, 0x645, 0x0, 0x64a, 0x645, 0x64a, 0x0, 0x64a, 0x646, 0x0, 0x64a, 0x647, 0x0, 0x64a, 0x649, 0x0, 0x64a, 0x64a, 0x0, 0x64a, 0x654, 0x0, 0x64a, 0x654, 0x627, 0x0, 0x64a, 0x654, 0x62c, 0x0, 0x64a, 0x654, 0x62d, 0x0, 0x64a, 0x654, 0x62e, 0x0, 0x64a, 0x654, 0x631, 0x0, 0x64a, 0x654, 0x632, 0x0, 0x64a, 0x654, 0x645, 0x0, 0x64a, 0x654, 0x646, 0x0, 0x64a, 0x654, 0x647, 0x0, 0x64a, 0x654, 0x648, 0x0, 0x64a, 0x654, 0x649, 0x0, 0x64a, 0x654, 0x64a, 0x0, 0x64a, 0x654, 0x6c6, 0x0, 0x64a, 0x654, 0x6c7, 0x0, 0x64a, 0x654, 0x6c8, 0x0, 0x64a, 0x654, 0x6d0, 0x0, 0x64a, 0x654, 0x6d5, 0x0, 0x64a, 0x674, 0x0, 0x66e, 0x0, 0x66f, 0x0, 0x671, 0x0, 0x679, 0x0, 0x67a, 0x0, 0x67b, 0x0, 0x67e, 0x0, 0x67f, 0x0, 0x680, 0x0, 0x683, 0x0, 0x684, 0x0, 0x686, 0x0, 0x687, 0x0, 0x688, 0x0, 0x68c, 0x0, 0x68d, 0x0, 0x68e, 0x0, 0x691, 0x0, 0x698, 0x0, 0x6a1, 0x0, 0x6a4, 0x0, 0x6a6, 0x0, 0x6a9, 0x0, 0x6ad, 0x0, 0x6af, 0x0, 0x6b1, 0x0, 0x6b3, 0x0, 0x6ba, 0x0, 0x6bb, 0x0, 0x6be, 0x0, 0x6c1, 0x0, 0x6c1, 0x654, 0x0, 0x6c5, 0x0, 0x6c6, 0x0, 0x6c7, 0x0, 0x6c7, 0x674, 0x0, 0x6c8, 0x0, 0x6c9, 0x0, 0x6cb, 0x0, 0x6cc, 0x0, 0x6d0, 0x0, 0x6d2, 0x0, 0x6d2, 0x654, 0x0, 0x6d5, 0x654, 0x0, 0x915, 0x93c, 0x0, 0x916, 0x93c, 0x0, 0x917, 0x93c, 0x0, 0x91c, 0x93c, 0x0, 0x921, 0x93c, 0x0, 0x922, 0x93c, 0x0, 0x928, 0x93c, 0x0, 0x92b, 0x93c, 0x0, 0x92f, 0x93c, 0x0, 0x930, 0x93c, 0x0, 0x933, 0x93c, 0x0, 0x9a1, 0x9bc, 0x0, 0x9a2, 0x9bc, 0x0, 0x9af, 0x9bc, 0x0, 0x9c7, 0x9be, 0x0, 0x9c7, 0x9d7, 0x0, 0xa16, 0xa3c, 0x0, 0xa17, 0xa3c, 0x0, 0xa1c, 0xa3c, 0x0, 0xa2b, 0xa3c, 0x0, 0xa32, 0xa3c, 0x0, 0xa38, 0xa3c, 0x0, 0xb21, 0xb3c, 0x0, 0xb22, 0xb3c, 0x0, 0xb47, 0xb3e, 0x0, 0xb47, 0xb56, 0x0, 0xb47, 0xb57, 0x0, 0xb92, 0xbd7, 0x0, 0xbc6, 0xbbe, 0x0, 0xbc6, 0xbd7, 0x0, 0xbc7, 0xbbe, 0x0, 0xc46, 0xc56, 0x0, 0xcbf, 0xcd5, 0x0, 0xcc6, 0xcc2, 0x0, 0xcc6, 0xcc2, 0xcd5, 0x0, 0xcc6, 0xcd5, 0x0, 0xcc6, 0xcd6, 0x0, 0xd46, 0xd3e, 0x0, 0xd46, 0xd57, 0x0, 0xd47, 0xd3e, 0x0, 0xdd9, 0xdca, 0x0, 0xdd9, 0xdcf, 0x0, 0xdd9, 0xdcf, 0xdca, 0x0, 0xdd9, 0xddf, 0x0, 0xe4d, 0xe32, 0x0, 0xeab, 0xe99, 0x0, 0xeab, 0xea1, 0x0, 0xecd, 0xeb2, 0x0, 0xf0b, 0x0, 0xf40, 0xfb5, 0x0, 0xf42, 0xfb7, 0x0, 0xf4c, 0xfb7, 0x0, 0xf51, 0xfb7, 0x0, 0xf56, 0xfb7, 0x0, 0xf5b, 0xfb7, 0x0, 0xf71, 0xf72, 0x0, 0xf71, 0xf74, 0x0, 0xf71, 0xf80, 0x0, 0xf90, 0xfb5, 0x0, 0xf92, 0xfb7, 0x0, 0xf9c, 0xfb7, 0x0, 0xfa1, 0xfb7, 0x0, 0xfa6, 0xfb7, 0x0, 0xfab, 0xfb7, 0x0, 0xfb2, 0xf71, 0xf80, 0x0, 0xfb2, 0xf80, 0x0, 0xfb3, 0xf71, 0xf80, 0x0, 0xfb3, 0xf80, 0x0, 0x1025, 0x102e, 0x0, 0x10dc, 0x0, 0x1100, 0x0, 0x1100, 0x1161, 0x0, 0x1101, 0x0, 0x1102, 0x0, 0x1102, 0x1161, 0x0, 0x1103, 0x0, 0x1103, 0x1161, 0x0, 0x1104, 0x0, 0x1105, 0x0, 0x1105, 0x1161, 0x0, 0x1106, 0x0, 0x1106, 0x1161, 0x0, 0x1107, 0x0, 0x1107, 0x1161, 0x0, 0x1108, 0x0, 0x1109, 0x0, 0x1109, 0x1161, 0x0, 0x110a, 0x0, 0x110b, 0x0, 0x110b, 0x1161, 0x0, 0x110b, 0x116e, 0x0, 0x110c, 0x0, 0x110c, 0x1161, 0x0, 0x110c, 0x116e, 0x110b, 0x1174, 0x0, 0x110d, 0x0, 0x110e, 0x0, 0x110e, 0x1161, 0x0, 0x110e, 0x1161, 0x11b7, 0x1100, 0x1169, 0x0, 0x110f, 0x0, 0x110f, 0x1161, 0x0, 0x1110, 0x0, 0x1110, 0x1161, 0x0, 0x1111, 0x0, 0x1111, 0x1161, 0x0, 0x1112, 0x0, 0x1112, 0x1161, 0x0, 0x1114, 0x0, 0x1115, 0x0, 0x111a, 0x0, 0x111c, 0x0, 0x111d, 0x0, 0x111e, 0x0, 0x1120, 0x0, 0x1121, 0x0, 0x1122, 0x0, 0x1123, 0x0, 0x1127, 0x0, 0x1129, 0x0, 0x112b, 0x0, 0x112c, 0x0, 0x112d, 0x0, 0x112e, 0x0, 0x112f, 0x0, 0x1132, 0x0, 0x1136, 0x0, 0x1140, 0x0, 0x1147, 0x0, 0x114c, 0x0, 0x1157, 0x0, 0x1158, 0x0, 0x1159, 0x0, 0x1160, 0x0, 0x1161, 0x0, 0x1162, 0x0, 0x1163, 0x0, 0x1164, 0x0, 0x1165, 0x0, 0x1166, 0x0, 0x1167, 0x0, 0x1168, 0x0, 0x1169, 0x0, 0x116a, 0x0, 0x116b, 0x0, 0x116c, 0x0, 0x116d, 0x0, 0x116e, 0x0, 0x116f, 0x0, 0x1170, 0x0, 0x1171, 0x0, 0x1172, 0x0, 0x1173, 0x0, 0x1174, 0x0, 0x1175, 0x0, 0x1184, 0x0, 0x1185, 0x0, 0x1188, 0x0, 0x1191, 0x0, 0x1192, 0x0, 0x1194, 0x0, 0x119e, 0x0, 0x11a1, 0x0, 0x11aa, 0x0, 0x11ac, 0x0, 0x11ad, 0x0, 0x11b0, 0x0, 0x11b1, 0x0, 0x11b2, 0x0, 0x11b3, 0x0, 0x11b4, 0x0, 0x11b5, 0x0, 0x11c7, 0x0, 0x11c8, 0x0, 0x11cc, 0x0, 0x11ce, 0x0, 0x11d3, 0x0, 0x11d7, 0x0, 0x11d9, 0x0, 0x11dd, 0x0, 0x11df, 0x0, 0x11f1, 0x0, 0x11f2, 0x0, 0x1b05, 0x1b35, 0x0, 0x1b07, 0x1b35, 0x0, 0x1b09, 0x1b35, 0x0, 0x1b0b, 0x1b35, 0x0, 0x1b0d, 0x1b35, 0x0, 0x1b11, 0x1b35, 0x0, 0x1b3a, 0x1b35, 0x0, 0x1b3c, 0x1b35, 0x0, 0x1b3e, 0x1b35, 0x0, 0x1b3f, 0x1b35, 0x0, 0x1b42, 0x1b35, 0x0, 0x1d02, 0x0, 0x1d16, 0x0, 0x1d17, 0x0, 0x1d1c, 0x0, 0x1d1d, 0x0, 0x1d25, 0x0, 0x1d7b, 0x0, 0x1d85, 0x0, 0x2010, 0x0, 0x2013, 0x0, 0x2014, 0x0, 0x2032, 0x2032, 0x0, 0x2032, 0x2032, 0x2032, 0x0, 0x2032, 0x2032, 0x2032, 0x2032, 0x0, 0x2035, 0x2035, 0x0, 0x2035, 0x2035, 0x2035, 0x0, 0x20a9, 0x0, 0x2190, 0x0, 0x2190, 0x338, 0x0, 0x2191, 0x0, 0x2192, 0x0, 0x2192, 0x338, 0x0, 0x2193, 0x0, 0x2194, 0x338, 0x0, 0x21d0, 0x338, 0x0, 0x21d2, 0x338, 0x0, 0x21d4, 0x338, 0x0, 0x2202, 0x0, 0x2203, 0x338, 0x0, 0x2207, 0x0, 0x2208, 0x338, 0x0, 0x220b, 0x338, 0x0, 0x2211, 0x0, 0x2212, 0x0, 0x2223, 0x338, 0x0, 0x2225, 0x338, 0x0, 0x222b, 0x222b, 0x0, 0x222b, 0x222b, 0x222b, 0x0, 0x222b, 0x222b, 0x222b, 0x222b, 0x0, 0x222e, 0x222e, 0x0, 0x222e, 0x222e, 0x222e, 0x0, 0x223c, 0x338, 0x0, 0x2243, 0x338, 0x0, 0x2245, 0x338, 0x0, 0x2248, 0x338, 0x0, 0x224d, 0x338, 0x0, 0x2261, 0x338, 0x0, 0x2264, 0x338, 0x0, 0x2265, 0x338, 0x0, 0x2272, 0x338, 0x0, 0x2273, 0x338, 0x0, 0x2276, 0x338, 0x0, 0x2277, 0x338, 0x0, 0x227a, 0x338, 0x0, 0x227b, 0x338, 0x0, 0x227c, 0x338, 0x0, 0x227d, 0x338, 0x0, 0x2282, 0x338, 0x0, 0x2283, 0x338, 0x0, 0x2286, 0x338, 0x0, 0x2287, 0x338, 0x0, 0x2291, 0x338, 0x0, 0x2292, 0x338, 0x0, 0x22a2, 0x338, 0x0, 0x22a8, 0x338, 0x0, 0x22a9, 0x338, 0x0, 0x22ab, 0x338, 0x0, 0x22b2, 0x338, 0x0, 0x22b3, 0x338, 0x0, 0x22b4, 0x338, 0x0, 0x22b5, 0x338, 0x0, 0x2502, 0x0, 0x25a0, 0x0, 0x25cb, 0x0, 0x2985, 0x0, 0x2986, 0x0, 0x2add, 0x338, 0x0, 0x2d61, 0x0, 0x3001, 0x0, 0x3002, 0x0, 0x3008, 0x0, 0x3009, 0x0, 0x300a, 0x0, 0x300b, 0x0, 0x300c, 0x0, 0x300d, 0x0, 0x300e, 0x0, 0x300f, 0x0, 0x3010, 0x0, 0x3011, 0x0, 0x3012, 0x0, 0x3014, 0x0, 0x3014, 0x53, 0x3015, 0x0, 0x3014, 0x4e09, 0x3015, 0x0, 0x3014, 0x4e8c, 0x3015, 0x0, 0x3014, 0x52dd, 0x3015, 0x0, 0x3014, 0x5b89, 0x3015, 0x0, 0x3014, 0x6253, 0x3015, 0x0, 0x3014, 0x6557, 0x3015, 0x0, 0x3014, 0x672c, 0x3015, 0x0, 0x3014, 0x70b9, 0x3015, 0x0, 0x3014, 0x76d7, 0x3015, 0x0, 0x3015, 0x0, 0x3016, 0x0, 0x3017, 0x0, 0x3046, 0x3099, 0x0, 0x304b, 0x3099, 0x0, 0x304d, 0x3099, 0x0, 0x304f, 0x3099, 0x0, 0x3051, 0x3099, 0x0, 0x3053, 0x3099, 0x0, 0x3055, 0x3099, 0x0, 0x3057, 0x3099, 0x0, 0x3059, 0x3099, 0x0, 0x305b, 0x3099, 0x0, 0x305d, 0x3099, 0x0, 0x305f, 0x3099, 0x0, 0x3061, 0x3099, 0x0, 0x3064, 0x3099, 0x0, 0x3066, 0x3099, 0x0, 0x3068, 0x3099, 0x0, 0x306f, 0x3099, 0x0, 0x306f, 0x309a, 0x0, 0x3072, 0x3099, 0x0, 0x3072, 0x309a, 0x0, 0x3075, 0x3099, 0x0, 0x3075, 0x309a, 0x0, 0x3078, 0x3099, 0x0, 0x3078, 0x309a, 0x0, 0x307b, 0x304b, 0x0, 0x307b, 0x3099, 0x0, 0x307b, 0x309a, 0x0, 0x3088, 0x308a, 0x0, 0x3099, 0x0, 0x309a, 0x0, 0x309d, 0x3099, 0x0, 0x30a1, 0x0, 0x30a2, 0x0, 0x30a2, 0x30cf, 0x309a, 0x30fc, 0x30c8, 0x0, 0x30a2, 0x30eb, 0x30d5, 0x30a1, 0x0, 0x30a2, 0x30f3, 0x30d8, 0x309a, 0x30a2, 0x0, 0x30a2, 0x30fc, 0x30eb, 0x0, 0x30a3, 0x0, 0x30a4, 0x0, 0x30a4, 0x30cb, 0x30f3, 0x30af, 0x3099, 0x0, 0x30a4, 0x30f3, 0x30c1, 0x0, 0x30a5, 0x0, 0x30a6, 0x0, 0x30a6, 0x3099, 0x0, 0x30a6, 0x30a9, 0x30f3, 0x0, 0x30a7, 0x0, 0x30a8, 0x0, 0x30a8, 0x30b9, 0x30af, 0x30fc, 0x30c8, 0x3099, 0x0, 0x30a8, 0x30fc, 0x30ab, 0x30fc, 0x0, 0x30a9, 0x0, 0x30aa, 0x0, 0x30aa, 0x30f3, 0x30b9, 0x0, 0x30aa, 0x30fc, 0x30e0, 0x0, 0x30ab, 0x0, 0x30ab, 0x3099, 0x0, 0x30ab, 0x3099, 0x30ed, 0x30f3, 0x0, 0x30ab, 0x3099, 0x30f3, 0x30de, 0x0, 0x30ab, 0x30a4, 0x30ea, 0x0, 0x30ab, 0x30e9, 0x30c3, 0x30c8, 0x0, 0x30ab, 0x30ed, 0x30ea, 0x30fc, 0x0, 0x30ad, 0x0, 0x30ad, 0x3099, 0x0, 0x30ad, 0x3099, 0x30ab, 0x3099, 0x0, 0x30ad, 0x3099, 0x30cb, 0x30fc, 0x0, 0x30ad, 0x3099, 0x30eb, 0x30bf, 0x3099, 0x30fc, 0x0, 0x30ad, 0x30e5, 0x30ea, 0x30fc, 0x0, 0x30ad, 0x30ed, 0x0, 0x30ad, 0x30ed, 0x30af, 0x3099, 0x30e9, 0x30e0, 0x0, 0x30ad, 0x30ed, 0x30e1, 0x30fc, 0x30c8, 0x30eb, 0x0, 0x30ad, 0x30ed, 0x30ef, 0x30c3, 0x30c8, 0x0, 0x30af, 0x0, 0x30af, 0x3099, 0x0, 0x30af, 0x3099, 0x30e9, 0x30e0, 0x0, 0x30af, 0x3099, 0x30e9, 0x30e0, 0x30c8, 0x30f3, 0x0, 0x30af, 0x30eb, 0x30bb, 0x3099, 0x30a4, 0x30ed, 0x0, 0x30af, 0x30ed, 0x30fc, 0x30cd, 0x0, 0x30b1, 0x0, 0x30b1, 0x3099, 0x0, 0x30b1, 0x30fc, 0x30b9, 0x0, 0x30b3, 0x0, 0x30b3, 0x3099, 0x0, 0x30b3, 0x30b3, 0x0, 0x30b3, 0x30c8, 0x0, 0x30b3, 0x30eb, 0x30ca, 0x0, 0x30b3, 0x30fc, 0x30db, 0x309a, 0x0, 0x30b5, 0x0, 0x30b5, 0x3099, 0x0, 0x30b5, 0x30a4, 0x30af, 0x30eb, 0x0, 0x30b5, 0x30f3, 0x30c1, 0x30fc, 0x30e0, 0x0, 0x30b7, 0x0, 0x30b7, 0x3099, 0x0, 0x30b7, 0x30ea, 0x30f3, 0x30af, 0x3099, 0x0, 0x30b9, 0x0, 0x30b9, 0x3099, 0x0, 0x30bb, 0x0, 0x30bb, 0x3099, 0x0, 0x30bb, 0x30f3, 0x30c1, 0x0, 0x30bb, 0x30f3, 0x30c8, 0x0, 0x30bd, 0x0, 0x30bd, 0x3099, 0x0, 0x30bf, 0x0, 0x30bf, 0x3099, 0x0, 0x30bf, 0x3099, 0x30fc, 0x30b9, 0x0, 0x30c1, 0x0, 0x30c1, 0x3099, 0x0, 0x30c3, 0x0, 0x30c4, 0x0, 0x30c4, 0x3099, 0x0, 0x30c6, 0x0, 0x30c6, 0x3099, 0x0, 0x30c6, 0x3099, 0x30b7, 0x0, 0x30c8, 0x0, 0x30c8, 0x3099, 0x0, 0x30c8, 0x3099, 0x30eb, 0x0, 0x30c8, 0x30f3, 0x0, 0x30ca, 0x0, 0x30ca, 0x30ce, 0x0, 0x30cb, 0x0, 0x30cc, 0x0, 0x30cd, 0x0, 0x30ce, 0x0, 0x30ce, 0x30c3, 0x30c8, 0x0, 0x30cf, 0x0, 0x30cf, 0x3099, 0x0, 0x30cf, 0x3099, 0x30fc, 0x30ec, 0x30eb, 0x0, 0x30cf, 0x309a, 0x0, 0x30cf, 0x309a, 0x30fc, 0x30bb, 0x30f3, 0x30c8, 0x0, 0x30cf, 0x309a, 0x30fc, 0x30c4, 0x0, 0x30cf, 0x30a4, 0x30c4, 0x0, 0x30d2, 0x0, 0x30d2, 0x3099, 0x0, 0x30d2, 0x3099, 0x30eb, 0x0, 0x30d2, 0x309a, 0x0, 0x30d2, 0x309a, 0x30a2, 0x30b9, 0x30c8, 0x30eb, 0x0, 0x30d2, 0x309a, 0x30af, 0x30eb, 0x0, 0x30d2, 0x309a, 0x30b3, 0x0, 0x30d5, 0x0, 0x30d5, 0x3099, 0x0, 0x30d5, 0x3099, 0x30c3, 0x30b7, 0x30a7, 0x30eb, 0x0, 0x30d5, 0x309a, 0x0, 0x30d5, 0x30a1, 0x30e9, 0x30c3, 0x30c8, 0x3099, 0x0, 0x30d5, 0x30a3, 0x30fc, 0x30c8, 0x0, 0x30d5, 0x30e9, 0x30f3, 0x0, 0x30d8, 0x0, 0x30d8, 0x3099, 0x0, 0x30d8, 0x3099, 0x30fc, 0x30bf, 0x0, 0x30d8, 0x309a, 0x0, 0x30d8, 0x309a, 0x30bd, 0x0, 0x30d8, 0x309a, 0x30cb, 0x30d2, 0x0, 0x30d8, 0x309a, 0x30f3, 0x30b9, 0x0, 0x30d8, 0x309a, 0x30fc, 0x30b7, 0x3099, 0x0, 0x30d8, 0x30af, 0x30bf, 0x30fc, 0x30eb, 0x0, 0x30d8, 0x30eb, 0x30c4, 0x0, 0x30db, 0x0, 0x30db, 0x3099, 0x0, 0x30db, 0x3099, 0x30eb, 0x30c8, 0x0, 0x30db, 0x309a, 0x0, 0x30db, 0x309a, 0x30a4, 0x30f3, 0x30c8, 0x0, 0x30db, 0x309a, 0x30f3, 0x30c8, 0x3099, 0x0, 0x30db, 0x30f3, 0x0, 0x30db, 0x30fc, 0x30eb, 0x0, 0x30db, 0x30fc, 0x30f3, 0x0, 0x30de, 0x0, 0x30de, 0x30a4, 0x30af, 0x30ed, 0x0, 0x30de, 0x30a4, 0x30eb, 0x0, 0x30de, 0x30c3, 0x30cf, 0x0, 0x30de, 0x30eb, 0x30af, 0x0, 0x30de, 0x30f3, 0x30b7, 0x30e7, 0x30f3, 0x0, 0x30df, 0x0, 0x30df, 0x30af, 0x30ed, 0x30f3, 0x0, 0x30df, 0x30ea, 0x0, 0x30df, 0x30ea, 0x30cf, 0x3099, 0x30fc, 0x30eb, 0x0, 0x30e0, 0x0, 0x30e1, 0x0, 0x30e1, 0x30ab, 0x3099, 0x0, 0x30e1, 0x30ab, 0x3099, 0x30c8, 0x30f3, 0x0, 0x30e1, 0x30fc, 0x30c8, 0x30eb, 0x0, 0x30e2, 0x0, 0x30e3, 0x0, 0x30e4, 0x0, 0x30e4, 0x30fc, 0x30c8, 0x3099, 0x0, 0x30e4, 0x30fc, 0x30eb, 0x0, 0x30e5, 0x0, 0x30e6, 0x0, 0x30e6, 0x30a2, 0x30f3, 0x0, 0x30e7, 0x0, 0x30e8, 0x0, 0x30e9, 0x0, 0x30ea, 0x0, 0x30ea, 0x30c3, 0x30c8, 0x30eb, 0x0, 0x30ea, 0x30e9, 0x0, 0x30eb, 0x0, 0x30eb, 0x30d2, 0x309a, 0x30fc, 0x0, 0x30eb, 0x30fc, 0x30d5, 0x3099, 0x30eb, 0x0, 0x30ec, 0x0, 0x30ec, 0x30e0, 0x0, 0x30ec, 0x30f3, 0x30c8, 0x30b1, 0x3099, 0x30f3, 0x0, 0x30ed, 0x0, 0x30ef, 0x0, 0x30ef, 0x3099, 0x0, 0x30ef, 0x30c3, 0x30c8, 0x0, 0x30f0, 0x0, 0x30f0, 0x3099, 0x0, 0x30f1, 0x0, 0x30f1, 0x3099, 0x0, 0x30f2, 0x0, 0x30f2, 0x3099, 0x0, 0x30f3, 0x0, 0x30fb, 0x0, 0x30fc, 0x0, 0x30fd, 0x3099, 0x0, 0x349e, 0x0, 0x34b9, 0x0, 0x34bb, 0x0, 0x34df, 0x0, 0x3515, 0x0, 0x36ee, 0x0, 0x36fc, 0x0, 0x3781, 0x0, 0x382f, 0x0, 0x3862, 0x0, 0x387c, 0x0, 0x38c7, 0x0, 0x38e3, 0x0, 0x391c, 0x0, 0x393a, 0x0, 0x3a2e, 0x0, 0x3a6c, 0x0, 0x3ae4, 0x0, 0x3b08, 0x0, 0x3b19, 0x0, 0x3b49, 0x0, 0x3b9d, 0x0, 0x3c18, 0x0, 0x3c4e, 0x0, 0x3d33, 0x0, 0x3d96, 0x0, 0x3eac, 0x0, 0x3eb8, 0x0, 0x3f1b, 0x0, 0x3ffc, 0x0, 0x4008, 0x0, 0x4018, 0x0, 0x4039, 0x0, 0x4046, 0x0, 0x4096, 0x0, 0x40e3, 0x0, 0x412f, 0x0, 0x4202, 0x0, 0x4227, 0x0, 0x42a0, 0x0, 0x4301, 0x0, 0x4334, 0x0, 0x4359, 0x0, 0x43d5, 0x0, 0x43d9, 0x0, 0x440b, 0x0, 0x446b, 0x0, 0x452b, 0x0, 0x455d, 0x0, 0x4561, 0x0, 0x456b, 0x0, 0x45d7, 0x0, 0x45f9, 0x0, 0x4635, 0x0, 0x46be, 0x0, 0x46c7, 0x0, 0x4995, 0x0, 0x49e6, 0x0, 0x4a6e, 0x0, 0x4a76, 0x0, 0x4ab2, 0x0, 0x4b33, 0x0, 0x4bce, 0x0, 0x4cce, 0x0, 0x4ced, 0x0, 0x4cf8, 0x0, 0x4d56, 0x0, 0x4e00, 0x0, 0x4e01, 0x0, 0x4e03, 0x0, 0x4e09, 0x0, 0x4e0a, 0x0, 0x4e0b, 0x0, 0x4e0d, 0x0, 0x4e19, 0x0, 0x4e26, 0x0, 0x4e28, 0x0, 0x4e2d, 0x0, 0x4e32, 0x0, 0x4e36, 0x0, 0x4e38, 0x0, 0x4e39, 0x0, 0x4e3d, 0x0, 0x4e3f, 0x0, 0x4e41, 0x0, 0x4e59, 0x0, 0x4e5d, 0x0, 0x4e82, 0x0, 0x4e85, 0x0, 0x4e86, 0x0, 0x4e8c, 0x0, 0x4e94, 0x0, 0x4ea0, 0x0, 0x4ea4, 0x0, 0x4eae, 0x0, 0x4eba, 0x0, 0x4ec0, 0x0, 0x4ecc, 0x0, 0x4ee4, 0x0, 0x4f01, 0x0, 0x4f11, 0x0, 0x4f60, 0x0, 0x4f80, 0x0, 0x4f86, 0x0, 0x4f8b, 0x0, 0x4fae, 0x0, 0x4fbb, 0x0, 0x4fbf, 0x0, 0x5002, 0x0, 0x502b, 0x0, 0x507a, 0x0, 0x5099, 0x0, 0x50cf, 0x0, 0x50da, 0x0, 0x50e7, 0x0, 0x512a, 0x0, 0x513f, 0x0, 0x5140, 0x0, 0x5145, 0x0, 0x514d, 0x0, 0x5154, 0x0, 0x5164, 0x0, 0x5165, 0x0, 0x5167, 0x0, 0x5168, 0x0, 0x5169, 0x0, 0x516b, 0x0, 0x516d, 0x0, 0x5177, 0x0, 0x5180, 0x0, 0x5182, 0x0, 0x518d, 0x0, 0x5192, 0x0, 0x5195, 0x0, 0x5196, 0x0, 0x5197, 0x0, 0x5199, 0x0, 0x51a4, 0x0, 0x51ab, 0x0, 0x51ac, 0x0, 0x51b5, 0x0, 0x51b7, 0x0, 0x51c9, 0x0, 0x51cc, 0x0, 0x51dc, 0x0, 0x51de, 0x0, 0x51e0, 0x0, 0x51f5, 0x0, 0x5200, 0x0, 0x5203, 0x0, 0x5207, 0x0, 0x5217, 0x0, 0x521d, 0x0, 0x5229, 0x0, 0x523a, 0x0, 0x523b, 0x0, 0x5246, 0x0, 0x524d, 0x0, 0x5272, 0x0, 0x5277, 0x0, 0x5289, 0x0, 0x529b, 0x0, 0x52a3, 0x0, 0x52b3, 0x0, 0x52b4, 0x0, 0x52c7, 0x0, 0x52c9, 0x0, 0x52d2, 0x0, 0x52de, 0x0, 0x52e4, 0x0, 0x52f5, 0x0, 0x52f9, 0x0, 0x52fa, 0x0, 0x5305, 0x0, 0x5306, 0x0, 0x5315, 0x0, 0x5317, 0x0, 0x531a, 0x0, 0x5338, 0x0, 0x533b, 0x0, 0x533f, 0x0, 0x5341, 0x0, 0x5344, 0x0, 0x5345, 0x0, 0x5349, 0x0, 0x5351, 0x0, 0x5354, 0x0, 0x535a, 0x0, 0x535c, 0x0, 0x5369, 0x0, 0x5370, 0x0, 0x5373, 0x0, 0x5375, 0x0, 0x537d, 0x0, 0x537f, 0x0, 0x5382, 0x0, 0x53b6, 0x0, 0x53c3, 0x0, 0x53c8, 0x0, 0x53ca, 0x0, 0x53cc, 0x0, 0x53df, 0x0, 0x53e3, 0x0, 0x53e5, 0x0, 0x53eb, 0x0, 0x53ef, 0x0, 0x53f1, 0x0, 0x53f3, 0x0, 0x5406, 0x0, 0x5408, 0x0, 0x540d, 0x0, 0x540f, 0x0, 0x541d, 0x0, 0x5438, 0x0, 0x5439, 0x0, 0x5442, 0x0, 0x5448, 0x0, 0x5468, 0x0, 0x549e, 0x0, 0x54a2, 0x0, 0x54bd, 0x0, 0x54f6, 0x0, 0x5510, 0x0, 0x554f, 0x0, 0x5553, 0x0, 0x5555, 0x0, 0x5563, 0x0, 0x5584, 0x0, 0x5587, 0x0, 0x5599, 0x0, 0x559d, 0x0, 0x55ab, 0x0, 0x55b3, 0x0, 0x55b6, 0x0, 0x55c0, 0x0, 0x55c2, 0x0, 0x55e2, 0x0, 0x5606, 0x0, 0x5651, 0x0, 0x5668, 0x0, 0x5674, 0x0, 0x56d7, 0x0, 0x56db, 0x0, 0x56f9, 0x0, 0x5716, 0x0, 0x5717, 0x0, 0x571f, 0x0, 0x5730, 0x0, 0x578b, 0x0, 0x57ce, 0x0, 0x57f4, 0x0, 0x580d, 0x0, 0x5831, 0x0, 0x5832, 0x0, 0x5840, 0x0, 0x585a, 0x0, 0x585e, 0x0, 0x58a8, 0x0, 0x58ac, 0x0, 0x58b3, 0x0, 0x58d8, 0x0, 0x58df, 0x0, 0x58eb, 0x0, 0x58ee, 0x0, 0x58f0, 0x0, 0x58f2, 0x0, 0x58f7, 0x0, 0x5902, 0x0, 0x5906, 0x0, 0x590a, 0x0, 0x5915, 0x0, 0x591a, 0x0, 0x591c, 0x0, 0x5922, 0x0, 0x5927, 0x0, 0x5927, 0x6b63, 0x0, 0x5929, 0x0, 0x5944, 0x0, 0x5948, 0x0, 0x5951, 0x0, 0x5954, 0x0, 0x5962, 0x0, 0x5973, 0x0, 0x59d8, 0x0, 0x59ec, 0x0, 0x5a1b, 0x0, 0x5a27, 0x0, 0x5a62, 0x0, 0x5a66, 0x0, 0x5ab5, 0x0, 0x5b08, 0x0, 0x5b28, 0x0, 0x5b3e, 0x0, 0x5b50, 0x0, 0x5b57, 0x0, 0x5b66, 0x0, 0x5b80, 0x0, 0x5b85, 0x0, 0x5b97, 0x0, 0x5bc3, 0x0, 0x5bd8, 0x0, 0x5be7, 0x0, 0x5bee, 0x0, 0x5bf3, 0x0, 0x5bf8, 0x0, 0x5bff, 0x0, 0x5c06, 0x0, 0x5c0f, 0x0, 0x5c22, 0x0, 0x5c38, 0x0, 0x5c3f, 0x0, 0x5c60, 0x0, 0x5c62, 0x0, 0x5c64, 0x0, 0x5c65, 0x0, 0x5c6e, 0x0, 0x5c71, 0x0, 0x5c8d, 0x0, 0x5cc0, 0x0, 0x5d19, 0x0, 0x5d43, 0x0, 0x5d50, 0x0, 0x5d6b, 0x0, 0x5d6e, 0x0, 0x5d7c, 0x0, 0x5db2, 0x0, 0x5dba, 0x0, 0x5ddb, 0x0, 0x5de1, 0x0, 0x5de2, 0x0, 0x5de5, 0x0, 0x5de6, 0x0, 0x5df1, 0x0, 0x5dfd, 0x0, 0x5dfe, 0x0, 0x5e28, 0x0, 0x5e3d, 0x0, 0x5e69, 0x0, 0x5e72, 0x0, 0x5e73, 0x6210, 0x0, 0x5e74, 0x0, 0x5e7a, 0x0, 0x5e7c, 0x0, 0x5e7f, 0x0, 0x5ea6, 0x0, 0x5eb0, 0x0, 0x5eb3, 0x0, 0x5eb6, 0x0, 0x5ec9, 0x0, 0x5eca, 0x0, 0x5ed2, 0x0, 0x5ed3, 0x0, 0x5ed9, 0x0, 0x5eec, 0x0, 0x5ef4, 0x0, 0x5efe, 0x0, 0x5f04, 0x0, 0x5f0b, 0x0, 0x5f13, 0x0, 0x5f22, 0x0, 0x5f50, 0x0, 0x5f53, 0x0, 0x5f61, 0x0, 0x5f62, 0x0, 0x5f69, 0x0, 0x5f6b, 0x0, 0x5f73, 0x0, 0x5f8b, 0x0, 0x5f8c, 0x0, 0x5f97, 0x0, 0x5f9a, 0x0, 0x5fa9, 0x0, 0x5fad, 0x0, 0x5fc3, 0x0, 0x5fcd, 0x0, 0x5fd7, 0x0, 0x5ff5, 0x0, 0x5ff9, 0x0, 0x6012, 0x0, 0x601c, 0x0, 0x6075, 0x0, 0x6081, 0x0, 0x6094, 0x0, 0x60c7, 0x0, 0x60d8, 0x0, 0x60e1, 0x0, 0x6108, 0x0, 0x6144, 0x0, 0x6148, 0x0, 0x614c, 0x0, 0x614e, 0x0, 0x6160, 0x0, 0x6168, 0x0, 0x617a, 0x0, 0x618e, 0x0, 0x6190, 0x0, 0x61a4, 0x0, 0x61af, 0x0, 0x61b2, 0x0, 0x61de, 0x0, 0x61f2, 0x0, 0x61f6, 0x0, 0x6200, 0x0, 0x6208, 0x0, 0x6210, 0x0, 0x621b, 0x0, 0x622e, 0x0, 0x6234, 0x0, 0x6236, 0x0, 0x624b, 0x0, 0x6253, 0x0, 0x625d, 0x0, 0x6295, 0x0, 0x62b1, 0x0, 0x62c9, 0x0, 0x62cf, 0x0, 0x62d3, 0x0, 0x62d4, 0x0, 0x62fc, 0x0, 0x62fe, 0x0, 0x6307, 0x0, 0x633d, 0x0, 0x6350, 0x0, 0x6355, 0x0, 0x6368, 0x0, 0x637b, 0x0, 0x6383, 0x0, 0x63a0, 0x0, 0x63a9, 0x0, 0x63c4, 0x0, 0x63c5, 0x0, 0x63e4, 0x0, 0x641c, 0x0, 0x6422, 0x0, 0x6452, 0x0, 0x6469, 0x0, 0x6477, 0x0, 0x647e, 0x0, 0x649a, 0x0, 0x649d, 0x0, 0x64c4, 0x0, 0x652f, 0x0, 0x6534, 0x0, 0x654f, 0x0, 0x6556, 0x0, 0x656c, 0x0, 0x6578, 0x0, 0x6587, 0x0, 0x6597, 0x0, 0x6599, 0x0, 0x65a4, 0x0, 0x65b0, 0x0, 0x65b9, 0x0, 0x65c5, 0x0, 0x65e0, 0x0, 0x65e2, 0x0, 0x65e3, 0x0, 0x65e5, 0x0, 0x660e, 0x6cbb, 0x0, 0x6613, 0x0, 0x6620, 0x0, 0x662d, 0x548c, 0x0, 0x6649, 0x0, 0x6674, 0x0, 0x6688, 0x0, 0x6691, 0x0, 0x669c, 0x0, 0x66b4, 0x0, 0x66c6, 0x0, 0x66f0, 0x0, 0x66f4, 0x0, 0x66f8, 0x0, 0x6700, 0x0, 0x6708, 0x0, 0x6709, 0x0, 0x6717, 0x0, 0x671b, 0x0, 0x6721, 0x0, 0x6728, 0x0, 0x674e, 0x0, 0x6753, 0x0, 0x6756, 0x0, 0x675e, 0x0, 0x677b, 0x0, 0x6785, 0x0, 0x6797, 0x0, 0x67f3, 0x0, 0x67fa, 0x0, 0x6817, 0x0, 0x681f, 0x0, 0x682a, 0x0, 0x682a, 0x5f0f, 0x4f1a, 0x793e, 0x0, 0x6852, 0x0, 0x6881, 0x0, 0x6885, 0x0, 0x688e, 0x0, 0x68a8, 0x0, 0x6914, 0x0, 0x6942, 0x0, 0x69a3, 0x0, 0x69ea, 0x0, 0x6a02, 0x0, 0x6a13, 0x0, 0x6aa8, 0x0, 0x6ad3, 0x0, 0x6adb, 0x0, 0x6b04, 0x0, 0x6b20, 0x0, 0x6b21, 0x0, 0x6b54, 0x0, 0x6b62, 0x0, 0x6b63, 0x0, 0x6b72, 0x0, 0x6b77, 0x0, 0x6b79, 0x0, 0x6b9f, 0x0, 0x6bae, 0x0, 0x6bb3, 0x0, 0x6bba, 0x0, 0x6bbb, 0x0, 0x6bcb, 0x0, 0x6bcd, 0x0, 0x6bd4, 0x0, 0x6bdb, 0x0, 0x6c0f, 0x0, 0x6c14, 0x0, 0x6c34, 0x0, 0x6c4e, 0x0, 0x6c67, 0x0, 0x6c88, 0x0, 0x6cbf, 0x0, 0x6ccc, 0x0, 0x6ccd, 0x0, 0x6ce5, 0x0, 0x6ce8, 0x0, 0x6d16, 0x0, 0x6d1b, 0x0, 0x6d1e, 0x0, 0x6d34, 0x0, 0x6d3e, 0x0, 0x6d41, 0x0, 0x6d69, 0x0, 0x6d6a, 0x0, 0x6d77, 0x0, 0x6d78, 0x0, 0x6d85, 0x0, 0x6dcb, 0x0, 0x6dda, 0x0, 0x6dea, 0x0, 0x6df9, 0x0, 0x6e1a, 0x0, 0x6e2f, 0x0, 0x6e6e, 0x0, 0x6e80, 0x0, 0x6e9c, 0x0, 0x6eba, 0x0, 0x6ec7, 0x0, 0x6ecb, 0x0, 0x6ed1, 0x0, 0x6edb, 0x0, 0x6f0f, 0x0, 0x6f14, 0x0, 0x6f22, 0x0, 0x6f23, 0x0, 0x6f6e, 0x0, 0x6fc6, 0x0, 0x6feb, 0x0, 0x6ffe, 0x0, 0x701b, 0x0, 0x701e, 0x0, 0x7039, 0x0, 0x704a, 0x0, 0x706b, 0x0, 0x7070, 0x0, 0x7077, 0x0, 0x707d, 0x0, 0x7099, 0x0, 0x70ad, 0x0, 0x70c8, 0x0, 0x70d9, 0x0, 0x7121, 0x0, 0x7145, 0x0, 0x7149, 0x0, 0x716e, 0x0, 0x719c, 0x0, 0x71ce, 0x0, 0x71d0, 0x0, 0x7210, 0x0, 0x721b, 0x0, 0x7228, 0x0, 0x722a, 0x0, 0x722b, 0x0, 0x7235, 0x0, 0x7236, 0x0, 0x723b, 0x0, 0x723f, 0x0, 0x7247, 0x0, 0x7250, 0x0, 0x7259, 0x0, 0x725b, 0x0, 0x7262, 0x0, 0x7279, 0x0, 0x7280, 0x0, 0x7295, 0x0, 0x72ac, 0x0, 0x72af, 0x0, 0x72c0, 0x0, 0x72fc, 0x0, 0x732a, 0x0, 0x7375, 0x0, 0x737a, 0x0, 0x7384, 0x0, 0x7387, 0x0, 0x7389, 0x0, 0x738b, 0x0, 0x73a5, 0x0, 0x73b2, 0x0, 0x73de, 0x0, 0x7406, 0x0, 0x7409, 0x0, 0x7422, 0x0, 0x7447, 0x0, 0x745c, 0x0, 0x7469, 0x0, 0x7471, 0x0, 0x7485, 0x0, 0x7489, 0x0, 0x7498, 0x0, 0x74ca, 0x0, 0x74dc, 0x0, 0x74e6, 0x0, 0x7506, 0x0, 0x7518, 0x0, 0x751f, 0x0, 0x7524, 0x0, 0x7528, 0x0, 0x7530, 0x0, 0x7532, 0x0, 0x7533, 0x0, 0x7537, 0x0, 0x753b, 0x0, 0x753e, 0x0, 0x7559, 0x0, 0x7565, 0x0, 0x7570, 0x0, 0x758b, 0x0, 0x7592, 0x0, 0x75e2, 0x0, 0x7610, 0x0, 0x761d, 0x0, 0x761f, 0x0, 0x7642, 0x0, 0x7669, 0x0, 0x7676, 0x0, 0x767d, 0x0, 0x76ae, 0x0, 0x76bf, 0x0, 0x76ca, 0x0, 0x76db, 0x0, 0x76e3, 0x0, 0x76e7, 0x0, 0x76ee, 0x0, 0x76f4, 0x0, 0x7701, 0x0, 0x771e, 0x0, 0x771f, 0x0, 0x7740, 0x0, 0x774a, 0x0, 0x778b, 0x0, 0x77a7, 0x0, 0x77db, 0x0, 0x77e2, 0x0, 0x77f3, 0x0, 0x784e, 0x0, 0x786b, 0x0, 0x788c, 0x0, 0x7891, 0x0, 0x78ca, 0x0, 0x78cc, 0x0, 0x78fb, 0x0, 0x792a, 0x0, 0x793a, 0x0, 0x793c, 0x0, 0x793e, 0x0, 0x7948, 0x0, 0x7949, 0x0, 0x7950, 0x0, 0x7956, 0x0, 0x795d, 0x0, 0x795e, 0x0, 0x7965, 0x0, 0x797f, 0x0, 0x7981, 0x0, 0x798d, 0x0, 0x798e, 0x0, 0x798f, 0x0, 0x79ae, 0x0, 0x79b8, 0x0, 0x79be, 0x0, 0x79ca, 0x0, 0x79d8, 0x0, 0x79eb, 0x0, 0x7a1c, 0x0, 0x7a40, 0x0, 0x7a4a, 0x0, 0x7a4f, 0x0, 0x7a74, 0x0, 0x7a7a, 0x0, 0x7a81, 0x0, 0x7ab1, 0x0, 0x7acb, 0x0, 0x7aee, 0x0, 0x7af9, 0x0, 0x7b20, 0x0, 0x7b8f, 0x0, 0x7bc0, 0x0, 0x7bc6, 0x0, 0x7bc9, 0x0, 0x7c3e, 0x0, 0x7c60, 0x0, 0x7c73, 0x0, 0x7c7b, 0x0, 0x7c92, 0x0, 0x7cbe, 0x0, 0x7cd2, 0x0, 0x7cd6, 0x0, 0x7ce3, 0x0, 0x7ce7, 0x0, 0x7ce8, 0x0, 0x7cf8, 0x0, 0x7d00, 0x0, 0x7d10, 0x0, 0x7d22, 0x0, 0x7d2f, 0x0, 0x7d42, 0x0, 0x7d5b, 0x0, 0x7d63, 0x0, 0x7da0, 0x0, 0x7dbe, 0x0, 0x7dc7, 0x0, 0x7df4, 0x0, 0x7e02, 0x0, 0x7e09, 0x0, 0x7e37, 0x0, 0x7e41, 0x0, 0x7e45, 0x0, 0x7f36, 0x0, 0x7f3e, 0x0, 0x7f51, 0x0, 0x7f72, 0x0, 0x7f79, 0x0, 0x7f7a, 0x0, 0x7f85, 0x0, 0x7f8a, 0x0, 0x7f95, 0x0, 0x7f9a, 0x0, 0x7fbd, 0x0, 0x7ffa, 0x0, 0x8001, 0x0, 0x8005, 0x0, 0x800c, 0x0, 0x8012, 0x0, 0x8033, 0x0, 0x8046, 0x0, 0x8060, 0x0, 0x806f, 0x0, 0x8070, 0x0, 0x807e, 0x0, 0x807f, 0x0, 0x8089, 0x0, 0x808b, 0x0, 0x80ad, 0x0, 0x80b2, 0x0, 0x8103, 0x0, 0x813e, 0x0, 0x81d8, 0x0, 0x81e3, 0x0, 0x81e8, 0x0, 0x81ea, 0x0, 0x81ed, 0x0, 0x81f3, 0x0, 0x81fc, 0x0, 0x8201, 0x0, 0x8204, 0x0, 0x820c, 0x0, 0x8218, 0x0, 0x821b, 0x0, 0x821f, 0x0, 0x826e, 0x0, 0x826f, 0x0, 0x8272, 0x0, 0x8278, 0x0, 0x8279, 0x0, 0x828b, 0x0, 0x8291, 0x0, 0x829d, 0x0, 0x82b1, 0x0, 0x82b3, 0x0, 0x82bd, 0x0, 0x82e5, 0x0, 0x82e6, 0x0, 0x831d, 0x0, 0x8323, 0x0, 0x8336, 0x0, 0x8352, 0x0, 0x8353, 0x0, 0x8363, 0x0, 0x83ad, 0x0, 0x83bd, 0x0, 0x83c9, 0x0, 0x83ca, 0x0, 0x83cc, 0x0, 0x83dc, 0x0, 0x83e7, 0x0, 0x83ef, 0x0, 0x83f1, 0x0, 0x843d, 0x0, 0x8449, 0x0, 0x8457, 0x0, 0x84ee, 0x0, 0x84f1, 0x0, 0x84f3, 0x0, 0x84fc, 0x0, 0x8516, 0x0, 0x8564, 0x0, 0x85cd, 0x0, 0x85fa, 0x0, 0x8606, 0x0, 0x8612, 0x0, 0x862d, 0x0, 0x863f, 0x0, 0x864d, 0x0, 0x8650, 0x0, 0x865c, 0x0, 0x8667, 0x0, 0x8669, 0x0, 0x866b, 0x0, 0x8688, 0x0, 0x86a9, 0x0, 0x86e2, 0x0, 0x870e, 0x0, 0x8728, 0x0, 0x876b, 0x0, 0x8779, 0x0, 0x8786, 0x0, 0x87ba, 0x0, 0x87e1, 0x0, 0x8801, 0x0, 0x881f, 0x0, 0x8840, 0x0, 0x884c, 0x0, 0x8860, 0x0, 0x8863, 0x0, 0x88c2, 0x0, 0x88cf, 0x0, 0x88d7, 0x0, 0x88de, 0x0, 0x88e1, 0x0, 0x88f8, 0x0, 0x88fa, 0x0, 0x8910, 0x0, 0x8941, 0x0, 0x8964, 0x0, 0x897e, 0x0, 0x8986, 0x0, 0x898b, 0x0, 0x8996, 0x0, 0x89d2, 0x0, 0x89e3, 0x0, 0x8a00, 0x0, 0x8aa0, 0x0, 0x8aaa, 0x0, 0x8abf, 0x0, 0x8acb, 0x0, 0x8ad2, 0x0, 0x8ad6, 0x0, 0x8aed, 0x0, 0x8af8, 0x0, 0x8afe, 0x0, 0x8b01, 0x0, 0x8b39, 0x0, 0x8b58, 0x0, 0x8b80, 0x0, 0x8b8a, 0x0, 0x8c37, 0x0, 0x8c46, 0x0, 0x8c48, 0x0, 0x8c55, 0x0, 0x8c78, 0x0, 0x8c9d, 0x0, 0x8ca1, 0x0, 0x8ca9, 0x0, 0x8cab, 0x0, 0x8cc1, 0x0, 0x8cc2, 0x0, 0x8cc7, 0x0, 0x8cc8, 0x0, 0x8cd3, 0x0, 0x8d08, 0x0, 0x8d1b, 0x0, 0x8d64, 0x0, 0x8d70, 0x0, 0x8d77, 0x0, 0x8db3, 0x0, 0x8dbc, 0x0, 0x8dcb, 0x0, 0x8def, 0x0, 0x8df0, 0x0, 0x8eab, 0x0, 0x8eca, 0x0, 0x8ed4, 0x0, 0x8f26, 0x0, 0x8f2a, 0x0, 0x8f38, 0x0, 0x8f3b, 0x0, 0x8f62, 0x0, 0x8f9b, 0x0, 0x8f9e, 0x0, 0x8fb0, 0x0, 0x8fb5, 0x0, 0x8fb6, 0x0, 0x9023, 0x0, 0x9038, 0x0, 0x904a, 0x0, 0x9069, 0x0, 0x9072, 0x0, 0x907c, 0x0, 0x908f, 0x0, 0x9091, 0x0, 0x9094, 0x0, 0x90ce, 0x0, 0x90de, 0x0, 0x90f1, 0x0, 0x90fd, 0x0, 0x9111, 0x0, 0x911b, 0x0, 0x9149, 0x0, 0x916a, 0x0, 0x9199, 0x0, 0x91b4, 0x0, 0x91c6, 0x0, 0x91cc, 0x0, 0x91cf, 0x0, 0x91d1, 0x0, 0x9234, 0x0, 0x9238, 0x0, 0x9276, 0x0, 0x927c, 0x0, 0x92d7, 0x0, 0x92d8, 0x0, 0x9304, 0x0, 0x934a, 0x0, 0x93f9, 0x0, 0x9415, 0x0, 0x9577, 0x0, 0x9580, 0x0, 0x958b, 0x0, 0x95ad, 0x0, 0x95b7, 0x0, 0x961c, 0x0, 0x962e, 0x0, 0x964b, 0x0, 0x964d, 0x0, 0x9675, 0x0, 0x9678, 0x0, 0x967c, 0x0, 0x9686, 0x0, 0x96a3, 0x0, 0x96b6, 0x0, 0x96b7, 0x0, 0x96b8, 0x0, 0x96b9, 0x0, 0x96c3, 0x0, 0x96e2, 0x0, 0x96e3, 0x0, 0x96e8, 0x0, 0x96f6, 0x0, 0x96f7, 0x0, 0x9723, 0x0, 0x9732, 0x0, 0x9748, 0x0, 0x9751, 0x0, 0x9756, 0x0, 0x975e, 0x0, 0x9762, 0x0, 0x9769, 0x0, 0x97cb, 0x0, 0x97db, 0x0, 0x97e0, 0x0, 0x97ed, 0x0, 0x97f3, 0x0, 0x97ff, 0x0, 0x9801, 0x0, 0x9805, 0x0, 0x980b, 0x0, 0x9818, 0x0, 0x9829, 0x0, 0x983b, 0x0, 0x985e, 0x0, 0x98a8, 0x0, 0x98db, 0x0, 0x98df, 0x0, 0x98e2, 0x0, 0x98ef, 0x0, 0x98fc, 0x0, 0x9928, 0x0, 0x9929, 0x0, 0x9996, 0x0, 0x9999, 0x0, 0x99a7, 0x0, 0x99ac, 0x0, 0x99c2, 0x0, 0x99f1, 0x0, 0x99fe, 0x0, 0x9a6a, 0x0, 0x9aa8, 0x0, 0x9ad8, 0x0, 0x9adf, 0x0, 0x9b12, 0x0, 0x9b25, 0x0, 0x9b2f, 0x0, 0x9b32, 0x0, 0x9b3c, 0x0, 0x9b5a, 0x0, 0x9b6f, 0x0, 0x9c40, 0x0, 0x9c57, 0x0, 0x9ce5, 0x0, 0x9cfd, 0x0, 0x9d67, 0x0, 0x9db4, 0x0, 0x9dfa, 0x0, 0x9e1e, 0x0, 0x9e75, 0x0, 0x9e7f, 0x0, 0x9e97, 0x0, 0x9e9f, 0x0, 0x9ea5, 0x0, 0x9ebb, 0x0, 0x9ec3, 0x0, 0x9ecd, 0x0, 0x9ece, 0x0, 0x9ed1, 0x0, 0x9ef9, 0x0, 0x9efd, 0x0, 0x9efe, 0x0, 0x9f05, 0x0, 0x9f0e, 0x0, 0x9f0f, 0x0, 0x9f13, 0x0, 0x9f16, 0x0, 0x9f20, 0x0, 0x9f3b, 0x0, 0x9f43, 0x0, 0x9f4a, 0x0, 0x9f52, 0x0, 0x9f8d, 0x0, 0x9f8e, 0x0, 0x9f9c, 0x0, 0x9f9f, 0x0, 0x9fa0, 0x0, 0xa76f, 0x0, 0x11099, 0x110ba, 0x0, 0x1109b, 0x110ba, 0x0, 0x110a5, 0x110ba, 0x0, 0x11131, 0x11127, 0x0, 0x11132, 0x11127, 0x0, 0x1d157, 0x1d165, 0x0, 0x1d158, 0x1d165, 0x0, 0x1d158, 0x1d165, 0x1d16e, 0x0, 0x1d158, 0x1d165, 0x1d16f, 0x0, 0x1d158, 0x1d165, 0x1d170, 0x0, 0x1d158, 0x1d165, 0x1d171, 0x0, 0x1d158, 0x1d165, 0x1d172, 0x0, 0x1d1b9, 0x1d165, 0x0, 0x1d1b9, 0x1d165, 0x1d16e, 0x0, 0x1d1b9, 0x1d165, 0x1d16f, 0x0, 0x1d1ba, 0x1d165, 0x0, 0x1d1ba, 0x1d165, 0x1d16e, 0x0, 0x1d1ba, 0x1d165, 0x1d16f, 0x0, 0x20122, 0x0, 0x2051c, 0x0, 0x20525, 0x0, 0x2054b, 0x0, 0x2063a, 0x0, 0x20804, 0x0, 0x208de, 0x0, 0x20a2c, 0x0, 0x20b63, 0x0, 0x214e4, 0x0, 0x216a8, 0x0, 0x216ea, 0x0, 0x219c8, 0x0, 0x21b18, 0x0, 0x21d0b, 0x0, 0x21de4, 0x0, 0x21de6, 0x0, 0x22183, 0x0, 0x2219f, 0x0, 0x22331, 0x0, 0x226d4, 0x0, 0x22844, 0x0, 0x2284a, 0x0, 0x22b0c, 0x0, 0x22bf1, 0x0, 0x2300a, 0x0, 0x232b8, 0x0, 0x2335f, 0x0, 0x23393, 0x0, 0x2339c, 0x0, 0x233c3, 0x0, 0x233d5, 0x0, 0x2346d, 0x0, 0x236a3, 0x0, 0x238a7, 0x0, 0x23a8d, 0x0, 0x23afa, 0x0, 0x23cbc, 0x0, 0x23d1e, 0x0, 0x23ed1, 0x0, 0x23f5e, 0x0, 0x23f8e, 0x0, 0x24263, 0x0, 0x242ee, 0x0, 0x243ab, 0x0, 0x24608, 0x0, 0x24735, 0x0, 0x24814, 0x0, 0x24c36, 0x0, 0x24c92, 0x0, 0x24fa1, 0x0, 0x24fb8, 0x0, 0x25044, 0x0, 0x250f2, 0x0, 0x250f3, 0x0, 0x25119, 0x0, 0x25133, 0x0, 0x25249, 0x0, 0x2541d, 0x0, 0x25626, 0x0, 0x2569a, 0x0, 0x256c5, 0x0, 0x2597c, 0x0, 0x25aa7, 0x0, 0x25bab, 0x0, 0x25c80, 0x0, 0x25cd0, 0x0, 0x25f86, 0x0, 0x261da, 0x0, 0x26228, 0x0, 0x26247, 0x0, 0x262d9, 0x0, 0x2633e, 0x0, 0x264da, 0x0, 0x26523, 0x0, 0x265a8, 0x0, 0x267a7, 0x0, 0x267b5, 0x0, 0x26b3c, 0x0, 0x26c36, 0x0, 0x26cd5, 0x0, 0x26d6b, 0x0, 0x26f2c, 0x0, 0x26fb1, 0x0, 0x270d2, 0x0, 0x273ca, 0x0, 0x27667, 0x0, 0x278ae, 0x0, 0x27966, 0x0, 0x27ca8, 0x0, 0x27ed3, 0x0, 0x27f2f, 0x0, 0x285d2, 0x0, 0x285ed, 0x0, 0x2872e, 0x0, 0x28bfa, 0x0, 0x28d77, 0x0, 0x29145, 0x0, 0x291df, 0x0, 0x2921a, 0x0, 0x2940a, 0x0, 0x29496, 0x0, 0x295b6, 0x0, 0x29b30, 0x0, 0x2a0ce, 0x0, 0x2a105, 0x0, 0x2a20e, 0x0, 0x2a291, 0x0, 0x2a392, 0x0, 0x2a600, 0x0]; return t; } } } static if(size_t.sizeof == 4) { //22656 bytes enum compatMappingTrieEntries = TrieEntry!(ushort, 8, 8, 5)([ 0x0, 0x40, 0x540], [ 0x100, 0xa00, 0x21c0], [ 0x2020100, 0x4020302, 0x2020205, 0x7060202, 0x2020202, 0x8020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x80000, 0xa0009, 0xc000b, 0x0, 0xd0000, 0xf000e, 0x0, 0x110010, 0x130012, 0x150014, 0x170016, 0x190018, 0x0, 0x1b001a, 0x0, 0x0, 0x1c, 0x0, 0x1d0000, 0x1e0000, 0x0, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000, 0x21, 0x0, 0x22, 0x230000, 0x24, 0x0, 0x0, 0x0, 0x25, 0x26, 0x27, 0x0, 0x28, 0x0, 0x29, 0x0, 0x2a, 0x0, 0x2b, 0x2c0000, 0x0, 0x2d0000, 0x2e, 0x2f, 0x310030, 0x330032, 0x0, 0x340000, 0x0, 0x0, 0x350000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x370036, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x390000, 0x3b003a, 0x3d003c, 0x0, 0x3f003e, 0x410040, 0x430042, 0x450044, 0x470046, 0x490048, 0x4b004a, 0x4d004c, 0x4f004e, 0x510050, 0x530052, 0x0, 0x550054, 0x570056, 0x590058, 0x5a, 0x5c005b, 0x5e005d, 0x60005f, 0x610000, 0x620000, 0x0, 0x0, 0x0, 0x0, 0x630000, 0x650064, 0x670066, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x690000, 0x0, 0x6a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6b0000, 0x0, 0x0, 0x0, 0x6c0000, 0x0, 0x0, 0x0, 0x0, 0x6d, 0x6e0000, 0x70006f, 0x720071, 0x740073, 0x75, 0x770076, 0x790078, 0x7b007a, 0x7d007c, 0x7e0000, 0x80007f, 0x81, 0x0, 0x830082, 0x850084, 0x870086, 0x890088, 0x8b008a, 0x8d008c, 0x8f008e, 0x910090, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x920000, 0x0, 0x930000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x950094, 0x970096, 0x990098, 0x9b009a, 0x9d009c, 0x9f009e, 0xa100a0, 0xa2, 0xa400a3, 0xa600a5, 0xa800a7, 0xaa00a9, 0xac00ab, 0xae00ad, 0xb000af, 0xb200b1, 0xb400b3, 0xb600b5, 0xb800b7, 0xba00b9, 0xbc00bb, 0xbe00bd, 0xc000bf, 0xc200c1, 0xc400c3, 0xc600c5, 0xc800c7, 0xca00c9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcc00cb, 0x0, 0xcd0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf00ce, 0xd00000, 0xd1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd300d2, 0xd500d4, 0xd700d6, 0xd900d8, 0xdb00da, 0xdd00dc, 0xd200de, 0xdf00d3, 0xe000d5, 0xe200e1, 0xe300d9, 0xe500e4, 0xe700e6, 0xe900e8, 0xeb00ea, 0xed00ec, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef00ee, 0xf100f0, 0xf300f2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf500f4, 0xf700f6, 0xf8, 0x0, 0xfa00f9, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd00fc, 0xff00fe, 0x1010100, 0x1030102, 0x1050104, 0x1070106, 0x1090108, 0x10b010a, 0x10c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x15, 0x692, 0x0, 0x90000, 0x0, 0x30f0343, 0x11b20003, 0x0, 0x3140048, 0x787, 0x3c603ce, 0x494, 0x570056d, 0x5860573, 0x5b005a6, 0x5f80000, 0x62e062b, 0x6580631, 0x6e706e4, 0x6f906ea, 0x78f0000, 0x7a907a6, 0x7bf07ac, 0x7e3, 0x8b10000, 0x8b708b4, 0x95f08cb, 0x0, 0x9ac09a9, 0x9c209af, 0x9ec09e2, 0xa470000, 0xa890a86, 0xab30a8c, 0xb460b43, 0xb550b49, 0xc410000, 0xc5e0c5b, 0xc740c61, 0xc98, 0xd680000, 0xd6e0d6b, 0xe0c0d82, 0xe1b0000, 0x9c50589, 0x9c8058c, 0xa0a05ce, 0xa3b05ec, 0xa3e05ef, 0xa4105f2, 0xa4405f5, 0xa6e061a, 0x0, 0xaa20647, 0xaad0652, 0xab00655, 0xad00675, 0xab9065e, 0xafb069a, 0xb0106a0, 0xb0406a3, 0xb0a06a9, 0xb1606ba, 0x0, 0xb4c06ed, 0xb4f06f0, 0xb5206f3, 0xb6b070f, 0x6f6, 0xb3706d8, 0xb730717, 0xbae072e, 0x7430000, 0x7500bcc, 0x7460bd9, 0x7400bcf, 0xbc9, 0x78c0000, 0x79b0c3e, 0x7950c4d, 0xed70c47, 0x0, 0xc8307ce, 0xc8e07d9, 0xca207ed, 0x0, 0xd070842, 0xd1d0858, 0xd0d0848, 0xd2b086c, 0xd320873, 0xd49088a, 0xd380879, 0xd5d08a6, 0xd54089d, 0x0, 0xd7108ba, 0xd7808c1, 0xd7f08c8, 0xd9808e1, 0xd9b08e4, 0xdc4090d, 0xde9093f, 0xe0f0962, 0x979096e, 0x97f0e29, 0x60d0e2f, 0x8400614, 0xcae07f9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f00000, 0xda7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x613060c, 0x7360a67, 0xbb9073d, 0x7830780, 0x5b70c32, 0x70309f3, 0x7f00b5f, 0x8e70ca5, 0x8d60d9e, 0x8d20d8d, 0x8da0d89, 0x8ce0d91, 0xd85, 0x9e505a9, 0x9de05a2, 0xe630e5a, 0x0, 0xb0706a6, 0xba80728, 0xccc0817, 0xccf081a, 0xecc0e7b, 0x6090b76, 0xa640610, 0xaf80697, 0x0, 0xc3b0789, 0x9ef05b3, 0xe600e57, 0xe680e5d, 0x9f605ba, 0x9f905bd, 0xabc0661, 0xabf0664, 0xb620706, 0xb650709, 0xca807f3, 0xcab07f6, 0xd10084b, 0xd13084e, 0xda108ea, 0xda408ed, 0xd460887, 0xd5a08a3, 0x0, 0xb1f06c3, 0x0, 0x0, 0x0, 0x9db059f, 0xac9066e, 0xc9b07e6, 0xc7b07c6, 0xc9107dc, 0xc9407df, 0xe150968, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe9a0b0d, 0xa11073e, 0xeb60eb4, 0xde10eb8, 0x695, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12000f, 0x4b0024, 0x270006, 0x0, 0xa280e96, 0xb410840, 0xecf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4001a, 0x2b0000, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xed5, 0x0, 0x0, 0x54, 0x0, 0x546, 0x0, 0x0, 0x1c0003, 0x7410ee8, 0xf630f43, 0xfb4, 0xfed, 0x103c1016, 0x1185, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x101f0fbd, 0x10f5108f, 0x11751119, 0x1213, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x120c117e, 0x120311d5, 0x124b, 0x116e10ea, 0x10161011, 0x123c101f, 0x11ee, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11f011ae, 0x11f8, 0x10f00fad, 0x0, 0x100d0000, 0x0, 0x0, 0x0, 0x12b612b0, 0x12ad0000, 0x0, 0x12a40000, 0x0, 0x0, 0x12c212ce, 0x12d7, 0x0, 0x0, 0x0, 0x0, 0x12c80000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x130a0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12f812f2, 0x12ef0000, 0x0, 0x132d0000, 0x0, 0x0, 0x13041310, 0x131b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13331330, 0x0, 0x0, 0x0, 0x0, 0x12b90000, 0x12fb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12e912a7, 0x12ec12aa, 0x0, 0x12f512b3, 0x0, 0x13391336, 0x12fe12bc, 0x130112bf, 0x0, 0x130712c5, 0x130d12cb, 0x131512d1, 0x0, 0x133f133c, 0x132a12e6, 0x131812d4, 0x131e12da, 0x132112dd, 0x132412e0, 0x0, 0x132712e3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13420000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13e913e6, 0x13ec178f, 0x17ca, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13ef0000, 0x185b1792, 0x1811, 0x0, 0x0, 0x0, 0x186d, 0x1852, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x186a0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18820000, 0x0, 0x0, 0x0, 0x188b0000, 0x0, 0x188e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18731870, 0x18791876, 0x187f187c, 0x18881885, 0x0, 0x0, 0x0, 0x0, 0x0, 0x189a0000, 0x189d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18941891, 0x18970000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18ac0000, 0x0, 0x18af, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18a00000, 0x18a618a3, 0x0, 0x18a9, 0x0, 0x0, 0x0, 0x0, 0x18bb, 0x18b80000, 0x18be, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18b518b2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18c1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18ca18c4, 0x18c7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18cd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18d0, 0x0, 0x0, 0x18da0000, 0x18dd, 0x18d618d3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18e618e0, 0x18e3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18e9, 0x18ef18ec, 0x18f3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18f60000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18ff0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18fc18f9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1902, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19070000, 0x0, 0x0, 0x0, 0x0, 0x190a0000, 0x0, 0x0, 0x190d, 0x0, 0x19100000, 0x0, 0x0, 0x1913, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19040000, 0x0, 0x0, 0x0, 0x0, 0x19160000, 0x19190000, 0x19311935, 0x1938193c, 0x0, 0x0, 0x0, 0x191c0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19220000, 0x0, 0x0, 0x0, 0x0, 0x19250000, 0x0, 0x0, 0x1928, 0x0, 0x192b0000, 0x0, 0x0, 0x192e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x191f0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x193f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1942, 0x0, 0x0, 0x0, 0x0, 0x1a38, 0x1a3b, 0x1a3e, 0x1a41, 0x1a44, 0x0, 0x1a47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a4a0000, 0x1a4d0000, 0x0, 0x1a531a50, 0x1a560000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe550568, 0x5d5, 0x62905e6, 0x6870e75, 0x6cf06ac, 0x71a0607, 0x7230734, 0x77e, 0xe7e07a4, 0x82c06af, 0x56b088d, 0x6920770, 0xe840e82, 0x9371a59, 0xa7d0a2e, 0xe8e0e8c, 0x6020e90, 0xb790000, 0xe7105d3, 0xe880787, 0x1a5d1a5b, 0xba30cd3, 0x1a610a24, 0x86a0ea4, 0x10ea1a63, 0x10ee10ec, 0x123e123c, 0xa110ae0, 0x86a0a24, 0x10ec10ea, 0x123c11f0, 0x123e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1313, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe860000, 0xe8a09a0, 0xe900e66, 0xe920ad9, 0xe980e94, 0xe9e0e9c, 0x1a650ea0, 0xea20ed1, 0xed31a67, 0xea60ea8, 0xeac0eaa, 0xeb00eae, 0xeba0eb2, 0xe790ebc, 0xec00ebe, 0xec21a5f, 0x6110ec4, 0xec80ec6, 0x116e0eca, 0xa0705cb, 0xa1305da, 0xa1605dd, 0xa1905e0, 0xa4a05fb, 0xa6b0617, 0xa71061d, 0xa7a0626, 0xa740620, 0xa770623, 0xaa5064a, 0xaa9064e, 0xad30678, 0xad6067b, 0xacc0671, 0xaef0684, 0xafe069d, 0xb1906bd, 0xb2206c6, 0xb1c06c0, 0xb2506c9, 0xb2806cc, 0xb6e0712, 0xb5806fc, 0xba50725, 0xbab072b, 0xbb10731, 0xbd20749, 0xbd5074c, 0xbdf0756, 0xbdc0753, 0xc120772, 0xc150775, 0xc180778, 0xc440792, 0xc4a0798, 0xc5307a1, 0xc50079e, 0xc7707c2, 0xc7f07ca, 0xc8607d1, 0xc8a07d5, 0xcec0835, 0xcef0838, 0xd0a0845, 0xd160851, 0xd190854, 0xd20085b, 0xd350876, 0xd3f0880, 0xd2e086f, 0xd3b087c, 0xd420883, 0xd4e089a, 0xd5708a0, 0xd6308ac, 0xd6008a9, 0xdc1090a, 0xdca0913, 0xdc70910, 0xd7408bd, 0xd7b08c4, 0xddb0924, 0xdde0927, 0xde30939, 0xde6093c, 0xdef0945, 0xdec0942, 0xdf50948, 0xe010954, 0xe040957, 0xe18096b, 0xe2c097c, 0xe350985, 0xe380988, 0xd510b2b, 0xe210df2, 0xd3509a6, 0x0, 0x0, 0x9fc05c0, 0x9e905ad, 0x9b6057a, 0x9b20576, 0x9be0582, 0x9ba057e, 0x9ff05c3, 0x9cf0593, 0x9cb058f, 0x9d7059b, 0x9d30597, 0xa0305c7, 0xac20667, 0xab6065b, 0xa9f0644, 0xa930638, 0xa8f0634, 0xa9b0640, 0xa97063c, 0xac5066a, 0xb5c0700, 0xb68070c, 0xcc50810, 0xc9f07ea, 0xc6807b3, 0xc6407af, 0xc7007bb, 0xc6c07b7, 0xcc80813, 0xcb50800, 0xcb107fc, 0xcbd0808, 0xcb90804, 0xcc1080c, 0xdbe0907, 0xd9508de, 0xdae08f7, 0xdaa08f3, 0xdb608ff, 0xdb208fb, 0xdba0903, 0xe09095c, 0xe240974, 0xe1e0971, 0xe120965, 0x0, 0x0, 0x0, 0x10be109c, 0x10c1109f, 0x10ca10a8, 0x10d310b1, 0xf130ef1, 0xf160ef4, 0xf1f0efd, 0xf280f06, 0x110310f8, 0x110610fb, 0x110a10ff, 0x0, 0xf510f46, 0xf540f49, 0xf580f4d, 0x0, 0x11421120, 0x11451123, 0x114e112c, 0x11571135, 0xf880f66, 0xf8b0f69, 0xf940f72, 0xf9d0f7b, 0x119c118d, 0x119f1190, 0x11a31194, 0x11a71198, 0xfcf0fc0, 0xfd20fc3, 0xfd60fc7, 0xfda0fcb, 0x11e311d8, 0x11e611db, 0x11ea11df, 0x0, 0xffb0ff0, 0xffe0ff3, 0x10020ff7, 0x0, 0x122a121b, 0x122d121e, 0x12311222, 0x12351226, 0x10220000, 0x10250000, 0x10290000, 0x102d0000, 0x12741252, 0x12771255, 0x1280125e, 0x12891267, 0x1061103f, 0x10641042, 0x106d104b, 0x10761054, 0x108f1088, 0x10f510f2, 0x11191112, 0x11751172, 0x11d511d2, 0x12031200, 0x124b1244, 0x0, 0x10dc10ba, 0x10c510a3, 0x10ce10ac, 0x10d710b5, 0xf310f0f, 0xf1a0ef8, 0xf230f01, 0xf2c0f0a, 0x1160113e, 0x11491127, 0x11521130, 0x115b1139, 0xfa60f84, 0xf8f0f6d, 0xf980f76, 0xfa10f7f, 0x12921270, 0x127b1259, 0x12841262, 0x128d126b, 0x107f105d, 0x10681046, 0x1071104f, 0x107a1058, 0x10961099, 0x10e7108b, 0x1092, 0x10e310e0, 0xeeb0eee, 0xee80ee5, 0x2a0f35, 0x2a1170, 0x200051, 0x116b1115, 0x111c, 0x11671164, 0xf430f40, 0xf630f60, 0x2d0faa, 0x350031, 0x1178117b, 0x11851181, 0x0, 0x118911ab, 0xfb70fba, 0xfb40fb1, 0x3c0000, 0x440040, 0x12061209, 0x1213120f, 0x11f511f2, 0x12171239, 0x1019101c, 0x10161013, 0x18100a, 0x995001c, 0x0, 0x129d1247, 0x124e, 0x12991296, 0xfed0fea, 0x103c1039, 0x31083, 0x39, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x1, 0x0, 0x0, 0x1a690000, 0x0, 0x0, 0x4e0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2fc02fa, 0x2ff, 0x0, 0x0, 0x0, 0x10000, 0x0, 0x1a6f0000, 0x1a72, 0x1a7e1a7b, 0x0, 0x0, 0x8f, 0xc, 0x0, 0x0, 0x0, 0x5630000, 0x920560, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a760000, 0x0, 0x0, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae00305, 0x0, 0x3740365, 0x3920383, 0x3b003a1, 0x1aad02f4, 0xa10544, 0xb3b00a5, 0x3140305, 0x30f0343, 0x3740365, 0x3920383, 0x3b003a1, 0x1aad02f4, 0xa10544, 0xa5, 0xa7d0692, 0xb410787, 0xb0d0e8c, 0xa280b79, 0xb3b05d3, 0x8400cd3, 0xba3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x83f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9a2099e, 0xe4d05e3, 0xa1e0000, 0xe770a22, 0xe500000, 0x6ac0602, 0x6ac06ac, 0xe6d0b0d, 0x6cf06cf, 0xa280734, 0x77e0000, 0x786, 0x6af0000, 0x82c083b, 0x82c082c, 0x0, 0x88f0863, 0x897, 0x60a, 0x77c, 0x60a, 0x5b0071a, 0x5e305d5, 0xa7d0000, 0x67e0629, 0x7230000, 0x13540787, 0x136a1362, 0xae0136f, 0x6800000, 0x10ec11ee, 0x10060f3a, 0x1aab, 0x0, 0x5e60000, 0xa7d0a2e, 0x73e0ae0, 0x0, 0x0, 0x0, 0x3e203da, 0x3ca03c1, 0x3d20455, 0x4980459, 0x3d604cf, 0x3de04e7, 0x4eb049c, 0x3be0511, 0x6d106cf, 0x6de06d4, 0x91806b2, 0x91f091b, 0x68206e1, 0x950094d, 0x5e30734, 0x72305e6, 0xb300ae0, 0xb3d0b33, 0xdcf086a, 0xdd60dd2, 0xb410b40, 0xdfd0dfa, 0x9a00a28, 0x5d30a2e, 0x0, 0x0, 0x0, 0x0, 0x30d0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a8d1a86, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a92, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a950000, 0x1a981a9b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1aa0, 0x0, 0x1aa50000, 0x0, 0x1aa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1aaf, 0x1ab2, 0x0, 0x0, 0x1ab81ab5, 0x1ac10000, 0x1ac4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1ac80000, 0x0, 0x1acb, 0x1ace0000, 0x1ad10000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x556, 0x1ad7, 0x0, 0x0, 0x0, 0x0, 0x1ad40000, 0x55b054a, 0x1add1ada, 0x0, 0x1ae31ae0, 0x0, 0x1ae91ae6, 0x0, 0x0, 0x0, 0x1aef1aec, 0x0, 0x1afb1af8, 0x0, 0x1b011afe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b0d1b0a, 0x1b131b10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1af51af2, 0x1b071b04, 0x0, 0x0, 0x0, 0x1b191b16, 0x1b1f1b1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b350000, 0x1b37, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3430314, 0x365030f, 0x3830374, 0x3a10392, 0x31c03b0, 0x342032f, 0x3640355, 0x3820373, 0x3a00391, 0x3f703af, 0xd900a3, 0xe600e2, 0xee00ea, 0xf600f2, 0xa700fa, 0xb100ac, 0xbb00b6, 0xc500c0, 0xcf00ca, 0xdd00d4, 0x3460319, 0x3680359, 0x3860377, 0x3a40395, 0x31f03b3, 0x3450332, 0x3670358, 0x3850376, 0x3a30394, 0x3fa03b2, 0x16a0166, 0x172016e, 0x17a0176, 0x182017e, 0x18a0186, 0x192018e, 0x19a0196, 0x1a2019e, 0x1aa01a6, 0x1b201ae, 0x1ba01b6, 0x1c201be, 0x1ca01c6, 0x5d50568, 0x5e605e3, 0x67e0629, 0x6ac0687, 0x60706cf, 0x734071a, 0x77e0723, 0x6af07a4, 0x82c083b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x305, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1abc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x54f0542, 0x552, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b2c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6b2073e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b2f0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x227c0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26b00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1efb1ee9, 0x1f091f01, 0x1f131f0d, 0x1f1b1f17, 0x1f4b1f21, 0x1f5f1f57, 0x1f6f1f67, 0x1f871f77, 0x1f8b1f89, 0x1fb91fa5, 0x1fc51fc1, 0x1fcd1fc7, 0x1fdd1fdb, 0x1feb1fe9, 0x1ff71fef, 0x204f2045, 0x2079206f, 0x207f207d, 0x20982087, 0x20b420ae, 0x20ca20c4, 0x20ce20cc, 0x20dc20da, 0x20f820f2, 0x210020fc, 0x210f2108, 0x21292113, 0x212f212b, 0x21352131, 0x21412139, 0x218b214f, 0x21972195, 0x21d921d7, 0x21e521e3, 0x21ed21e9, 0x32521f1, 0x3292211, 0x22602223, 0x226e2266, 0x227a2274, 0x2280227e, 0x22842282, 0x22e22286, 0x230c2306, 0x2310230e, 0x23162312, 0x23222318, 0x23342330, 0x23562354, 0x235c235a, 0x23622360, 0x23762374, 0x23862384, 0x238a2388, 0x23a62394, 0x23aa23a8, 0x23dc23bc, 0x23ee23de, 0x23fa23f6, 0x241c240a, 0x2442243e, 0x2452244c, 0x245a2456, 0x245e245c, 0x246c246a, 0x247e247a, 0x24842482, 0x248e248a, 0x24922490, 0x24982496, 0x24f224e8, 0x250e250c, 0x25282512, 0x2530252c, 0x25522534, 0x25582554, 0x255c255a, 0x25742572, 0x25822578, 0x25922584, 0x25982596, 0x25ba25aa, 0x25c425c2, 0x25de25c8, 0x25e825e0, 0x260025fa, 0x26142608, 0x261a2618, 0x261e261c, 0x26262624, 0x2638262a, 0x263c263a, 0x264a2648, 0x2658264e, 0x265c265a, 0x26622660, 0x26662664, 0x26702668, 0x267e267c, 0x26862684, 0x268a2688, 0x2690268e, 0x26982692, 0x26a0269c, 0x26a626a2, 0x26aa26a8, 0x26b226ae, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b49, 0x1fcf1fcd, 0x1fd1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b7e, 0x1b81, 0x1b84, 0x1b87, 0x1b8a, 0x1b8d, 0x1b90, 0x1b93, 0x1b96, 0x1b99, 0x1b9c, 0x1b9f, 0x1ba20000, 0x1ba50000, 0x1ba80000, 0x0, 0x0, 0x0, 0x1bae1bab, 0x1bb10000, 0x1bb4, 0x1bba1bb7, 0x1bbd0000, 0x1bc0, 0x1bc91bc6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b7b, 0x0, 0x0, 0x870000, 0x8a, 0x1bcc1bd3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c26, 0x1c43, 0x1bf6, 0x1c92, 0x1c9b, 0x1caf, 0x1cbf, 0x1cca, 0x1ccf, 0x1cdc, 0x1ce1, 0x1ceb, 0x1cf20000, 0x1cf70000, 0x1c100000, 0x0, 0x0, 0x0, 0x1d261d1d, 0x1d3b0000, 0x1d42, 0x1d611d57, 0x1d760000, 0x1d7e, 0x1caa1da1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c01, 0x1e440000, 0x1e521e4d, 0x1e57, 0x0, 0x1ca11e60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19440000, 0x1a101949, 0x1a12194b, 0x19501a14, 0x19571955, 0x1a181a16, 0x1a1c1a1a, 0x1a201a1e, 0x195c19a6, 0x19661961, 0x196819b0, 0x196f196d, 0x19811977, 0x198e1983, 0x19981993, 0x1947199d, 0x19da19d8, 0x19de19dc, 0x19e219e0, 0x198c19e4, 0x19ea19e8, 0x19ee19ec, 0x19f21975, 0x19f619f4, 0x19fa19f8, 0x19fe197f, 0x19a219d4, 0x1a2219a4, 0x1a261a24, 0x1a2a1a28, 0x1a2e1a2c, 0x1a3019a8, 0x19aa1a32, 0x19ae19ac, 0x19b419b2, 0x19b819b6, 0x19bc19ba, 0x19c019be, 0x19c419c2, 0x19c819c6, 0x19cc19ca, 0x1a361a34, 0x19d019ce, 0x1a0019d2, 0x1a041a02, 0x1a081a06, 0x1a0c1a0a, 0x1a0e, 0x0, 0x1f171ee9, 0x20471eef, 0x1efd1ef1, 0x23641ef3, 0x1ef71f0d, 0x208c1eeb, 0x1f212051, 0x1d701ce, 0x1e901e0, 0x1fb01f2, 0x20d0204, 0x2330225, 0x245023c, 0x257024e, 0x1db01d2, 0x1ed01e4, 0x1ff01f6, 0x2110208, 0x2370229, 0x2490240, 0x25b0252, 0x216022e, 0x21e, 0x2700260, 0x2a00268, 0x2880274, 0x2840264, 0x290026c, 0x2c402b0, 0x2b802c0, 0x2a402ec, 0x2bc02ac, 0x2d002b4, 0x2c80298, 0x2d402e4, 0x278028c, 0x2a8029c, 0x27c02cc, 0x29402e8, 0x28002d8, 0x2e002dc, 0x21112021, 0x23fe21e3, 0x0, 0x0, 0x0, 0x0, 0x406082e, 0x41c0411, 0x4320427, 0x4400439, 0x44e0447, 0x475046e, 0x47f047c, 0x4850482, 0x194b1944, 0x19571950, 0x1961195c, 0x196f1968, 0x19831977, 0x1993198e, 0x199d1998, 0x194d1946, 0x19591952, 0x1963195e, 0x1971196a, 0x19851979, 0x19951990, 0x199f199a, 0x197c1988, 0x1974, 0x1f171ee9, 0x20471eef, 0x1f611f19, 0x1f5f1eed, 0x1fcd1f0f, 0x22e20329, 0x22232286, 0x204f25c8, 0x223b0325, 0x2240221b, 0x231c2007, 0x23ca255e, 0x23e21fab, 0x20982368, 0x1f4925a2, 0x22961fdf, 0x1f2b262c, 0x208a1f73, 0x1efd1ef1, 0x20fa1ef3, 0x1fc92001, 0x20b220b8, 0x1f292390, 0x1fd72568, 0x4882083, 0x48e048b, 0x4b10491, 0x4b704b4, 0x4bd04ba, 0x4c304c0, 0x4c904c6, 0x4e404cc, 0x34e033b, 0x4d604a3, 0x50304f2, 0x5290518, 0x327053a, 0x34d033a, 0xa8206b4, 0x7390a7f, 0x1bf11bd8, 0x1c0a1bff, 0x1c241c1a, 0x1c731c41, 0x1c991c90, 0x1cbd1cad, 0x1ccd1c1e, 0x1cdf1cda, 0x1cf01bfb, 0x1bde1cf5, 0x1d0f1ca6, 0x1c8e1d11, 0x1d1b1d0d, 0x1d551d39, 0x1d9f1d74, 0x1ddc1c31, 0x1def1c22, 0x1e041e00, 0x1e191e11, 0x1c351e1b, 0x1e341bed, 0x1e421c5d, 0x1e501e4b, 0x1e55, 0x1be01bda, 0x1beb1be5, 0x1bf91bf3, 0x1c0c1c04, 0x1c1c1c13, 0x1c331c20, 0x1c3c1c37, 0x1c2e1c29, 0x1c4b1c46, 0x1c501c57, 0x1c5f1c5c, 0x1c6d1c66, 0x1c7d1c61, 0x1c8b1c84, 0x1ca41c95, 0x1cb21ca8, 0x1cc21cb7, 0x1cd61cd2, 0x1cfa1ce4, 0x1c811d03, 0x1d171d0c, 0x1d291d35, 0x1d201d30, 0x1d4c1d45, 0x1d3e1d51, 0x1d6b1d64, 0x1d701d5a, 0x1d811d95, 0x1d9b1d85, 0x1d8f1d8a, 0x1dac1d79, 0x1db81da4, 0x1dbb1db2, 0x1dc51dbf, 0x1dce1dca, 0x1dd61dd2, 0x1de31dde, 0x1df11de6, 0x1c681df5, 0x1e0b1e06, 0x1e1f1e13, 0x1e291e24, 0x1e361e2e, 0x1c6f1e39, 0x33f0311, 0x3610352, 0x37f0370, 0x39d038e, 0x3bb03ac, 0x33e032b, 0x3600351, 0x37e036f, 0x39c038d, 0x3ba03ab, 0x40d0402, 0x4230418, 0xb0f042e, 0x56a0a53, 0xc580a0f, 0xa590ce6, 0xa600a5c, 0x210a06db, 0x20892200, 0x223d21f9, 0xc260cda, 0xbea11b4, 0x71c0b7b, 0x689075b, 0xb8c0a26, 0xc290cdd, 0x11c011b7, 0x6010bf6, 0xb7e068d, 0x68c0764, 0x11c30893, 0xa560bfd, 0xaec0b94, 0x11c60c35, 0xa300c00, 0xc030b97, 0xa340a33, 0xc070b9a, 0xa380a37, 0xc1b0b9e, 0x6910c1f, 0x7680b82, 0xcf60690, 0xd000cfa, 0xc380ce9, 0xc0f11c9, 0xc2c0ce0, 0xbed11ba, 0x76c0b86, 0xc2f0ce3, 0xbf011bd, 0x76f0b89, 0x77b0bb4, 0x5d70999, 0xa2d0a2a, 0x5e805ff, 0x6940a50, 0x6ae0b13, 0x71f0b3a, 0xba20722, 0xbbf0bbc, 0xbc60bc2, 0xbf90bf3, 0x8200c0b, 0x8230cd5, 0xd25082b, 0x9360869, 0x5d1092a, 0x34a0337, 0x36c035d, 0x38a037b, 0x3a80399, 0x32303b7, 0x3490336, 0x36b035c, 0x389037a, 0x3a70398, 0x3fe03b6, 0x4140409, 0x42a041f, 0x43c0435, 0x44a0443, 0x4710451, 0xaf40478, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26b4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe730e6b, 0x0, 0x0, 0x0, 0x22132556, 0x256a2584, 0x1eff22c6, 0x26ae1ff9, 0x209226ae, 0x202b25c8, 0x21872090, 0x244a2382, 0x250424e6, 0x25a8251e, 0x229a2254, 0x233c22f0, 0x25bc24ca, 0x1f112652, 0x225e1fe3, 0x24e42302, 0x20e6267a, 0x24dc22d6, 0x21a12526, 0x250a2478, 0x221d211f, 0x232822a6, 0x1f3125ae, 0x1fb31f7d, 0x225a21d5, 0x23922300, 0x24e02456, 0x257e24ec, 0x266a2610, 0x23b02678, 0x242c23d0, 0x25d624bc, 0x2540267e, 0x212d206d, 0x24682408, 0x23b4231a, 0x260c2566, 0x20d4206b, 0x22b02256, 0x242422ca, 0x25ec2438, 0x246e1fb1, 0x1f811f83, 0x242e23e6, 0x25f024c8, 0x21a3254e, 0x25462254, 0x20be1f05, 0x23322159, 0x1fc32372, 0x1f3923b8, 0x1ef5214b, 0x21e12290, 0x1fed2422, 0x23982063, 0x253824cc, 0x25962276, 0x21ab228c, 0x21bb24a8, 0x1f1f2370, 0x1f7f1f5d, 0x24182244, 0x253e2494, 0x1fb725c6, 0x20982011, 0x21ef2127, 0x23ba22d8, 0x265625e4, 0x268c2680, 0x220f1fa5, 0x2590226c, 0x217b210d, 0x21d12189, 0x22f622d0, 0x23e0234e, 0x24642432, 0x24d02588, 0x25d8259c, 0x1fa71f91, 0x22ee201b, 0x25382514, 0x2155211d, 0x227221b7, 0x232c2406, 0x20491f27, 0x20f020be, 0x233a215b, 0x24502348, 0x25ca2460, 0x2612260a, 0x1f332630, 0x25c023da, 0x216725fe, 0x1f451f15, 0x20d020c0, 0x225421e7, 0x238022fc, 0x25a624d6, 0x220726aa, 0x1fa325ea, 0x2233222d, 0x22be22a2, 0x236e2340, 0x242023ae, 0x1f612636, 0x25f22191, 0x20e21f3d, 0x258a22b2, 0x216b2143, 0x23322237, 0x1f9525f6, 0x20d82009, 0x222521fc, 0x2294224a, 0x2378233e, 0x25162446, 0x25c4251c, 0x1fcb2604, 0x200b22c0, 0x235022fe, 0x25f824de, 0x2682266e, 0x22ae2231, 0x23f6247c, 0x240e23fc, 0x22ea2326, 0x1f23254c, 0x1f9724b0, 0x21151f8f, 0x241421a5, 0x229c20b6, 0x258e220d, 0x25ee250e, 0x2123252c, 0x20371f4d, 0x0, 0x2061, 0x2205, 0x1f850000, 0x238c232a, 0x23cc23be, 0x23d823ce, 0x24102616, 0x2452, 0x24e2, 0x2544, 0x259e0000, 0x25b4, 0x0, 0x26422640, 0x26762644, 0x25fc25b0, 0x1f471f35, 0x1faf1f51, 0x1fd51fb5, 0x203d202f, 0x205f2041, 0x20d62065, 0x216120da, 0x21792175, 0x21db2185, 0x220921f3, 0x22a82246, 0x22ce22b6, 0x230822f8, 0x23b22342, 0x23c42240, 0x23c623c2, 0x23ca23c8, 0x23d623d4, 0x23f223e8, 0x24322400, 0x243a2436, 0x24582444, 0x249a2480, 0x24ce249a, 0x252e2522, 0x254a2548, 0x256e256c, 0x259e259a, 0x26282606, 0x215d2634, 0x248c274b, 0x0, 0x1f7b1ef9, 0x1f2f1f5b, 0x1f651f4f, 0x1fbb1fad, 0x2025202f, 0x203b202d, 0x20692061, 0x2094208e, 0x20aa20a2, 0x21252121, 0x214d213d, 0x21712165, 0x21792169, 0x21852173, 0x21bf2193, 0x21c921c5, 0x220521dd, 0x221f221d, 0x226e2229, 0x22a22276, 0x22c422c8, 0x22dc22ce, 0x23a422f8, 0x2324230a, 0x234a232a, 0x236a2358, 0x237e237c, 0x238e238c, 0x23a02396, 0x23b6239e, 0x240023f4, 0x2428240c, 0x24402432, 0x24b22458, 0x250024c6, 0x252a2524, 0x253a252e, 0x253c2544, 0x25462548, 0x254a2542, 0x256e2550, 0x25a4258c, 0x25ce25be, 0x260625f4, 0x26202616, 0x262e2628, 0x265e2634, 0x272126ae, 0x2733271f, 0x1ea11e8d, 0x27671ea3, 0x27a92779, 0x26ac26a4, 0x0, 0x0, 0x0, 0xadf0adb, 0xade0ae3, 0xd280ae2, 0xd28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x134e0000, 0x13481345, 0x134b1351, 0x0, 0x0, 0x13850000, 0x13d20000, 0x135413a6, 0x1374136f, 0x1360138e, 0x13b7139b, 0x2f413cd, 0x13ca13c7, 0x13c313bf, 0x13591356, 0x1364135c, 0x1371136c, 0x137c1376, 0x137f, 0x13881382, 0x1390138b, 0x1398, 0x139d, 0x13a313a0, 0x13a80000, 0x13ab, 0x13b413b1, 0x13bc13b9, 0x137913cf, 0x13931367, 0x135f13ae, 0x18181818, 0x181e181e, 0x181e181e, 0x18201820, 0x18201820, 0x18241824, 0x18241824, 0x181c181c, 0x181c181c, 0x18221822, 0x18221822, 0x181a181a, 0x181a181a, 0x183c183c, 0x183c183c, 0x183e183e, 0x183e183e, 0x18281828, 0x18281828, 0x18261826, 0x18261826, 0x182a182a, 0x182a182a, 0x182c182c, 0x182c182c, 0x18321832, 0x18301830, 0x18341834, 0x182e182e, 0x18381838, 0x18361836, 0x18401840, 0x18401840, 0x18441844, 0x18441844, 0x18481848, 0x18481848, 0x18461846, 0x18461846, 0x184a184a, 0x184c184c, 0x184c184c, 0x186d186d, 0x18501850, 0x18501850, 0x184e184e, 0x184e184e, 0x15911591, 0x186a186a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18420000, 0x18421842, 0x18031842, 0x17ff1803, 0x180717ff, 0x185b1807, 0x18621862, 0x18551855, 0x18601860, 0x180b180b, 0x180b180b, 0x14151415, 0x17cd17cd, 0x180d180d, 0x17f117f1, 0x18011801, 0x17fd17fd, 0x18051805, 0x18091809, 0x17f51809, 0x17f517f5, 0x18641864, 0x18641864, 0x17d517d1, 0x17f517e5, 0x13f417f9, 0x13fe13f7, 0x1414140b, 0x141e1417, 0x1438142d, 0x146a144d, 0x1472146d, 0x1484147b, 0x148c1487, 0x14311422, 0x14d11435, 0x143c14d4, 0x150514fa, 0x151a150c, 0x15931562, 0x15a515a2, 0x15ba15b0, 0x15c815c5, 0x15e415df, 0x16071575, 0x163f160a, 0x16451642, 0x1653164c, 0x165b1656, 0x16711662, 0x16791674, 0x167f167c, 0x16851682, 0x16931688, 0x16aa1696, 0x16c816b9, 0x1579158c, 0x145116e0, 0x14591455, 0x145d1526, 0x172d1461, 0x174f1740, 0x17691758, 0x1771176c, 0x177f1774, 0x179c1782, 0x17aa17a3, 0x17c417b3, 0x14e417c7, 0x179714ee, 0x64005d, 0x72006b, 0x800079, 0x17e117dd, 0x17e917e5, 0x17f917f5, 0x140813db, 0x140e140b, 0x14171414, 0x144a1447, 0x1464144d, 0x146d146a, 0x14781475, 0x147e147b, 0x14871484, 0x16561653, 0x16741671, 0x16851679, 0x16931688, 0x158c1696, 0x16e01579, 0x152616e5, 0x17551752, 0x17631758, 0x176c1769, 0x17ad1797, 0x17b317b0, 0x17c417be, 0x17d117c7, 0x17d917d5, 0x17ed17e5, 0x13f713f4, 0x140b13fe, 0x141e1411, 0x1438142d, 0x1467144d, 0x148c147b, 0x14311422, 0x14d11435, 0x14fa143c, 0x150c1505, 0x1562151a, 0x1593156d, 0x15a515a2, 0x15ba15b0, 0x15df15c5, 0x157515e4, 0x160a1607, 0x1642163f, 0x164c1645, 0x1662165b, 0x167f167c, 0x16851682, 0x16aa1688, 0x16c816b9, 0x13e0158c, 0x14551451, 0x15261459, 0x1740172d, 0x1758174f, 0x17711766, 0x17851774, 0x17a3179c, 0x17b317aa, 0x17e515ed, 0x140b17ed, 0x144d1411, 0x147b1467, 0x151a1481, 0x154c1529, 0x16851557, 0x158c1688, 0x17661758, 0x15ed17b3, 0x162c1625, 0x15d71633, 0x15ff15da, 0x16191602, 0x152c161c, 0x155a152f, 0x1490155d, 0x142613fb, 0x1440142a, 0x159a1402, 0x15bd159d, 0x153415c0, 0x1546153b, 0x1549154c, 0x15701517, 0x15d715b7, 0x15ff15da, 0x16191602, 0x152c161c, 0x155a152f, 0x1490155d, 0x142613fb, 0x1440142a, 0x159a1402, 0x15bd159d, 0x153415c0, 0x1546153b, 0x1549154c, 0x15701517, 0x153415b7, 0x1546153b, 0x1529154c, 0x15c81557, 0x150514fa, 0x1534150c, 0x1546153b, 0x15df15c8, 0x13e313e3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14301421, 0x14341430, 0x1450143b, 0x14581454, 0x14a314a3, 0x14c114c5, 0x14fd1508, 0x15211501, 0x151d1521, 0x15251525, 0x15651565, 0x153e1596, 0x1537153e, 0x154f154f, 0x15531553, 0x15b315a8, 0x15cb15b3, 0x15cf15cb, 0x15e715d3, 0x15f315f3, 0x160d15f7, 0x16111615, 0x16481648, 0x16691665, 0x16c416bc, 0x16ad16c0, 0x16cb16ad, 0x16d216cb, 0x16fe16d2, 0x170b1702, 0x16f316eb, 0x17161712, 0x0, 0x177716ef, 0x1743177b, 0x17341747, 0x17381734, 0x175b175f, 0x17b617b6, 0x14291401, 0x14431425, 0x1460143f, 0x14ab145c, 0x14a7148f, 0x1569150f, 0x15ac1542, 0x16d616b5, 0x179f17a6, 0x172117ba, 0x174b166d, 0x16bc1665, 0x168f15fb, 0x171a1730, 0x168b16b1, 0x173016b1, 0x14ba1493, 0x164f16f7, 0x168b13fa, 0x159615e7, 0x173c1513, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x165e158f, 0x13d913de, 0x15731706, 0x15eb14e9, 0x1578158a, 0x1497157c, 0x14f1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b3102f6, 0x5401b33, 0x8d0546, 0x1b770093, 0x2ff1b79, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a6d02fc, 0x9931a6b, 0xa10993, 0xe3b00a5, 0x1b4b0e3f, 0x1b451b4f, 0x1b391b47, 0x1b351b3b, 0x1b3d1b37, 0x1b411b3f, 0x1b43, 0x98b0000, 0xc098f, 0xc000c, 0x993000c, 0x9930993, 0x1b3102f6, 0x2fa, 0x5400546, 0x8d0093, 0xa11a6d, 0xe3b00a5, 0x1b4b0e3f, 0x971b4f, 0x2f2009d, 0x2f802f4, 0x5590548, 0x544, 0x99098d, 0x566009b, 0x0, 0x0, 0x161f0057, 0x5a, 0x61, 0x16220068, 0x1629006f, 0x16300076, 0x1637007d, 0x163a0084, 0x13e613d5, 0x13e913e6, 0x178f13e9, 0x13ec178f, 0x17ca13ec, 0x17ca17ca, 0x13d717ca, 0x13f213d7, 0x13f213f2, 0x141a13f2, 0x141c141a, 0x141c141c, 0x1470141c, 0x14701470, 0x13f51470, 0x13f513f5, 0x13f813f5, 0x13f813f8, 0x13ff13f8, 0x13ff13ff, 0x14e013ff, 0x14e214e0, 0x13dc14e2, 0x140913dc, 0x14f81409, 0x14f814f8, 0x153214f8, 0x15321532, 0x15601532, 0x15601560, 0x15a01560, 0x15a015a0, 0x15c315a0, 0x15c315c3, 0x15dd15c3, 0x15dd15dd, 0x15e215dd, 0x15e215e2, 0x160515e2, 0x16051605, 0x163d1605, 0x163d163d, 0x1659163d, 0x16591659, 0x16771659, 0x16771677, 0x14ec1677, 0x14ec14ec, 0x140c14ec, 0x140c140c, 0x140f140c, 0x140f140f, 0x13e1140f, 0x13e113e1, 0x178813e1, 0x14151788, 0x13fc1415, 0x13fc13fc, 0x169e13fc, 0x16a2169e, 0x16a616a2, 0x169b16a6, 0x169b, 0x0, 0x8d0000, 0x970095, 0x9b0099, 0x9f009d, 0xa500a1, 0x2f402f2, 0x2f802f6, 0x30302fa, 0x3140305, 0x30f0343, 0x3740365, 0x3920383, 0x3b003a1, 0x5460540, 0x5440548, 0x930559, 0x5680566, 0x5e305d5, 0x62905e6, 0x687067e, 0x6cf06ac, 0x71a0607, 0x7230734, 0x7a4077e, 0x83b06af, 0x85e082c, 0x56b088d, 0x77006b2, 0x95a0682, 0x98b060a, 0x98f098d, 0x9930991, 0x6920995, 0x9a00937, 0xa7d0a2e, 0x6020ad9, 0xae00b0d, 0xb79073e, 0x5d30a28, 0x7870b3b, 0x5d80cd3, 0x8400a11, 0xa240ba3, 0xde1086a, 0x6950b41, 0xe3b0611, 0xe3f0e3d, 0x1b280e41, 0x1b331b2a, 0x1b3f1b3d, 0x1e5c1b31, 0x1bd61e55, 0x1bfd1bef, 0x1c181c08, 0x1e0f1e02, 0x1cee1e17, 0x1bd81c16, 0x1bff1bf1, 0x1c1a1c0a, 0x1c411c24, 0x1c901c73, 0x1cad1c99, 0x1c1e1cbd, 0x1cda1ccd, 0x1bfb1cdf, 0x1cf51cf0, 0x1ca61bde, 0x1d111d0f, 0x1d0d1c8e, 0x1d391d1b, 0x1d741d55, 0x1c311d9f, 0x1c221ddc, 0x1e001def, 0x1e111e04, 0x1e1b1e19, 0x1bed1c35, 0x1c5d1e34, 0x1c061e42, 0x8b0088, 0x194419d4, 0x1a101949, 0x1a12194b, 0x19501a14, 0x19571955, 0x1a181a16, 0x1a1c1a1a, 0x1a201a1e, 0x195c19a6, 0x19661961, 0x196819b0, 0x196f196d, 0x19811977, 0x198e1983, 0x19981993, 0x199d, 0x0, 0x19d81947, 0x19dc19da, 0x19e019de, 0x0, 0x19e419e2, 0x19e8198c, 0x19ec19ea, 0x0, 0x197519ee, 0x19f419f2, 0x19f819f6, 0x0, 0x197f19fa, 0x19fe, 0x0, 0xe450e43, 0x90e4b, 0xe470e49, 0x1a82, 0x1a841b22, 0x1a8b1a89, 0x1b241a90, 0x1b26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26b6, 0x26b9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26bc0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26c226bf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26c826c5, 0x26cf26cb, 0x26d726d3, 0x26db, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26df0000, 0x26e226ea, 0x26e626ed, 0x26f1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5d50568, 0x5e605e3, 0x67e0629, 0x6ac0687, 0x60706cf, 0x734071a, 0x77e0723, 0x6af07a4, 0x82c083b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x5d50568, 0x5e605e3, 0x67e0629, 0x6ac0687, 0x60706cf, 0x734071a, 0x77e0723, 0x6af07a4, 0x82c083b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0x602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x5d50568, 0x5e605e3, 0x67e0629, 0x6ac0687, 0x60706cf, 0x734071a, 0x77e0723, 0x6af07a4, 0x82c083b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x568, 0x5e605e3, 0x0, 0x687, 0x6070000, 0x71a, 0x77e0000, 0x6af07a4, 0x83b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90000, 0xb0d0000, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30000, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x5d50568, 0x5e605e3, 0x67e0629, 0x6ac0687, 0x60706cf, 0x734071a, 0x77e0723, 0x6af07a4, 0x82c083b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x5d50568, 0x5e60000, 0x67e0629, 0x687, 0x6070000, 0x734071a, 0x77e0723, 0x6af07a4, 0x83b, 0x88d085e, 0x6b2056b, 0x6820770, 0x95a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x5d50568, 0x5e60000, 0x67e0629, 0x687, 0x60706cf, 0x734071a, 0x723, 0x7a4, 0x0, 0x88d085e, 0x6b2056b, 0x6820770, 0x95a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x5d50568, 0x5e605e3, 0x67e0629, 0x6ac0687, 0x60706cf, 0x734071a, 0x77e0723, 0x6af07a4, 0x82c083b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x77e0723, 0x6af07a4, 0x82c083b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x5d50568, 0x5e605e3, 0x67e0629, 0x6ac0687, 0x60706cf, 0x734071a, 0x77e0723, 0x6af07a4, 0x82c083b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x9370692, 0xa2e09a0, 0xad90a7d, 0xb0d0602, 0x73e0ae0, 0xa280b79, 0xb3b05d3, 0xcd30787, 0xa1105d8, 0xba30840, 0x86a0a24, 0xb410de1, 0x6110695, 0x5d50568, 0x5e605e3, 0x67e0629, 0x6ac0687, 0x60706cf, 0x734071a, 0x77e0723, 0x6af07a4, 0xb410de1, 0x6110695, 0xe800e6f, 0x0, 0xf380ee3, 0xf3c0f3a, 0xf5c0f3e, 0xfad0f5e, 0xfde0faf, 0xfe20fe0, 0xfe60fe4, 0x10060fe8, 0xfad1008, 0x100f100d, 0x10311011, 0x10351033, 0x1aa3077c, 0x10ea1086, 0x10ee10ec, 0x110e10f0, 0x116e1110, 0x11ae1170, 0x11b211b0, 0x11ce11cc, 0x11ee11d0, 0x11f811f0, 0x11fc11fa, 0x123c11fe, 0x1240123e, 0x1a9e1242, 0x116e10f0, 0x123c11ae, 0x11ee11f0, 0xf380ee3, 0xf3c0f3a, 0xf5c0f3e, 0xfad0f5e, 0xfde0faf, 0xfe20fe0, 0xfe60fe4, 0x10060fe8, 0xfad1008, 0x100f100d, 0x10311011, 0x10351033, 0x1aa3077c, 0x10ea1086, 0x10ee10ec, 0x110e10f0, 0x116e1110, 0x11ae1170, 0x11b211b0, 0x11ce11cc, 0x11ee11d0, 0x11f811f0, 0x11fc11fa, 0x123c11fe, 0x1240123e, 0x1a9e1242, 0x116e10f0, 0x123c11ae, 0x11ee11f0, 0xf380ee3, 0xf3c0f3a, 0xf5c0f3e, 0xfad0f5e, 0xfde0faf, 0xfe20fe0, 0xfe60fe4, 0x10060fe8, 0xfad1008, 0x100f100d, 0x10311011, 0x10351033, 0x1aa3077c, 0x10ea1086, 0x10ee10ec, 0x110e10f0, 0x116e1110, 0x11ae1170, 0x11b211b0, 0x11ce11cc, 0x11ee11d0, 0x11f811f0, 0x11fc11fa, 0x123c11fe, 0x1240123e, 0x1a9e1242, 0x116e10f0, 0x123c11ae, 0x11ee11f0, 0xf380ee3, 0xf3c0f3a, 0xf5c0f3e, 0xfad0f5e, 0xfde0faf, 0xfe20fe0, 0xfe60fe4, 0x10060fe8, 0xfad1008, 0x100f100d, 0x10311011, 0x10351033, 0x1aa3077c, 0x10ea1086, 0x10ee10ec, 0x110e10f0, 0x116e1110, 0x11ae1170, 0x11b211b0, 0x11ce11cc, 0x11ee11d0, 0x11f811f0, 0x11fc11fa, 0x123c11fe, 0x1240123e, 0x1a9e1242, 0x116e10f0, 0x123c11ae, 0x11ee11f0, 0xf380ee3, 0xf3c0f3a, 0xf5c0f3e, 0xfad0f5e, 0xfde0faf, 0xfe20fe0, 0xfe60fe4, 0x10060fe8, 0xfad1008, 0x100f100d, 0x10311011, 0x10351033, 0x1aa3077c, 0x10ea1086, 0x10ee10ec, 0x110e10f0, 0x116e1110, 0x11ae1170, 0x11b211b0, 0x11ce11cc, 0x11ee11d0, 0x11f811f0, 0x11fc11fa, 0x123c11fe, 0x1240123e, 0x1a9e1242, 0x116e10f0, 0x123c11ae, 0x11ee11f0, 0x12a212a0, 0x0, 0x3140305, 0x30f0343, 0x3740365, 0x3920383, 0x3b003a1, 0x3140305, 0x30f0343, 0x3740365, 0x3920383, 0x3b003a1, 0x3140305, 0x30f0343, 0x3740365, 0x3920383, 0x3b003a1, 0x3140305, 0x30f0343, 0x3740365, 0x3920383, 0x3b003a1, 0x3140305, 0x30f0343, 0x3740365, 0x3920383, 0x3b003a1, 0x13f213d7, 0x14e013f5, 0x17880000, 0x13f81409, 0x13fc15c3, 0x14ec1677, 0x140f140c, 0x15e214f8, 0x1560163d, 0x13dc1659, 0x141c1532, 0x13ff1470, 0x15a014e2, 0x160515dd, 0x184a1814, 0x1816183a, 0x13f20000, 0x13f5, 0x13e1, 0x13f80000, 0x13fc0000, 0x14ec1677, 0x140f140c, 0x15e214f8, 0x1560163d, 0x1659, 0x141c1532, 0x13ff1470, 0x15a00000, 0x16050000, 0x0, 0x0, 0x0, 0x13f5, 0x0, 0x13f80000, 0x13fc0000, 0x14ec0000, 0x140f0000, 0x15e214f8, 0x15600000, 0x1659, 0x1532, 0x13ff0000, 0x15a00000, 0x16050000, 0x184a0000, 0x18160000, 0x13f20000, 0x13f5, 0x13e1, 0x13f80000, 0x13fc15c3, 0x1677, 0x140f140c, 0x15e214f8, 0x1560163d, 0x1659, 0x141c1532, 0x13ff1470, 0x15a00000, 0x160515dd, 0x1814, 0x183a, 0x13f213d7, 0x14e013f5, 0x178813e1, 0x13f81409, 0x13fc15c3, 0x14ec0000, 0x140f140c, 0x15e214f8, 0x1560163d, 0x13dc1659, 0x141c1532, 0x13ff1470, 0x15a014e2, 0x160515dd, 0x0, 0x0, 0x13f20000, 0x14e013f5, 0x17880000, 0x13f81409, 0x13fc15c3, 0x14ec0000, 0x140f140c, 0x15e214f8, 0x1560163d, 0x13dc1659, 0x141c1532, 0x13ff1470, 0x15a014e2, 0x160515dd, 0x0, 0x0, 0x307030a, 0x3f10316, 0x4ab0468, 0x4fa04de, 0x520050b, 0x531, 0x0, 0x0, 0x10200fe, 0x10a0106, 0x112010e, 0x11a0116, 0x122011e, 0x12a0126, 0x132012e, 0x13a0136, 0x142013e, 0x14a0146, 0x152014e, 0x15a0156, 0x162015e, 0x5e31b4d, 0x5e5082c, 0x933, 0x5d50568, 0x5e605e3, 0x67e0629, 0x6ac0687, 0x60706cf, 0x734071a, 0x77e0723, 0x6af07a4, 0x82c083b, 0x88d085e, 0x6b2056b, 0x6820770, 0x60a095a, 0x76c06b1, 0x8660860, 0x9300827, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x761075e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x606, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c9e1bc3, 0x1cad, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20b02197, 0x1cf71ff3, 0x20811f17, 0x208c2532, 0x21fe1f1d, 0x21e722f2, 0x21451f9d, 0x21eb1f69, 0x24261f93, 0x2560235c, 0x200f2073, 0x219d22cc, 0x1ee921b3, 0x25a01eef, 0x1efd20fa, 0x21ad2001, 0x21992574, 0x23f023d2, 0x22bc2005, 0x329221b, 0x1f9f2366, 0x2035, 0x0, 0x0, 0x1b511b69, 0x1b5d1b55, 0x1b611b6d, 0x1b591b71, 0x1b65, 0x0, 0x0, 0x0, 0x1ffd2147, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f031f07, 0x26f51f0b, 0x1f351f2d, 0x1f3b1f37, 0x1f411f3f, 0x1f431f47, 0x26fd1e63, 0x1f531f51, 0x1f631f55, 0x1e6526f7, 0x1f691f59, 0x1f7126fb, 0x1f251f75, 0x1f7b1f79, 0x1f8927b9, 0x1e691f8d, 0x1f9b1f99, 0x1fa11f9f, 0x1fad1e6b, 0x1fb51faf, 0x1fbd1fbb, 0x1fc31fbf, 0x1fd51fd3, 0x1fe11fd9, 0x1fe71fe5, 0x1fe71fe7, 0x22e42703, 0x1ff51ff1, 0x1ffb2705, 0x20031fff, 0x200d2017, 0x20152013, 0x201d2019, 0x2023201f, 0x20292027, 0x202d2029, 0x20332031, 0x204b2039, 0x204d203d, 0x2043203f, 0x20711f8f, 0x20572055, 0x20532059, 0x205b205d, 0x27072067, 0x20772075, 0x2081207b, 0x20962085, 0x270b2709, 0x209e209c, 0x209a20a0, 0x1e6d20a4, 0x20a81e6f, 0x20ac20ac, 0x20ba270d, 0x20be20bc, 0x270f20c2, 0x20c820c6, 0x20cc2137, 0x20d21e71, 0x20e020da, 0x271320de, 0x271520e4, 0x20e820ea, 0x20f420ec, 0x1e7320f6, 0x210220fe, 0x21062104, 0x27171e75, 0x21171e77, 0x211b2119, 0x27cd211f, 0x271b212b, 0x2486271b, 0x21332133, 0x27291e79, 0x213b277d, 0x1e7b213f, 0x21512149, 0x21572153, 0x1e7f215f, 0x21611e7d, 0x2163271d, 0x216f216d, 0x216f2171, 0x21792177, 0x217d2181, 0x2183217f, 0x21872185, 0x218f210b, 0x219f219b, 0x21b121a7, 0x21af2723, 0x21b521a9, 0x21c321b9, 0x21c72725, 0x21bd21c1, 0x21cb1e81, 0x21d321cf, 0x1e8321cd, 0x21df21db, 0x21f52727, 0x22032215, 0x22091e89, 0x1e851e87, 0x1f6d1f6b, 0x220b2217, 0x1ebb2470, 0x221f221d, 0x222b2221, 0x27312227, 0x22351e8b, 0x2242222f, 0x27352246, 0x22392248, 0x1e8d224c, 0x2250224e, 0x22582252, 0x225c2737, 0x22621e8f, 0x22642739, 0x226a1e91, 0x22762270, 0x273b2278, 0x273d2711, 0x273f2288, 0x2292228e, 0x2298228a, 0x22a822a0, 0x22a422a2, 0x22ac22aa, 0x229e2741, 0x22ba22b8, 0x22c41e93, 0x274322c2, 0x22d222b4, 0x27472745, 0x22de22d4, 0x22da22dc, 0x22e01e95, 0x22e622e8, 0x26f922ec, 0x274922f4, 0x274d22fa, 0x230a2304, 0x274f2314, 0x2320231e, 0x27532751, 0x2336232e, 0x23381e97, 0x1e991e99, 0x23462344, 0x234c234a, 0x1e9b2352, 0x2755235e, 0x2757236c, 0x27192372, 0x2759237a, 0x275d275b, 0x1e9f1e9d, 0x27612396, 0x2763275f, 0x239a2765, 0x239c239c, 0x1ea323a0, 0x1ea523a2, 0x27691ea7, 0x23b023ac, 0x1ea923b6, 0x23c8276b, 0x276f276d, 0x23e423d8, 0x23e81eab, 0x23ec23ea, 0x27732771, 0x23f82773, 0x27751ead, 0x24042402, 0x27771eaf, 0x1eb12412, 0x2416241a, 0x277b241e, 0x1eb3242a, 0x24342430, 0x1eb5243c, 0x2781277f, 0x27831eb7, 0x27852448, 0x2454244e, 0x27872458, 0x24622789, 0x2466278b, 0x1eb9272b, 0x24742472, 0x24761ebd, 0x278d20a6, 0x272d278f, 0x2486272f, 0x25942488, 0x249e1ebf, 0x24a0249c, 0x24a21fa9, 0x24a624a4, 0x279124aa, 0x24ac24a8, 0x24b824b6, 0x24ba24ae, 0x24ce24c4, 0x24be24b4, 0x24c224c0, 0x27972793, 0x1ec12795, 0x24d424d2, 0x279f24d8, 0x279924da, 0x1ec51ec3, 0x279d279b, 0x24ea1ec7, 0x24ee24ec, 0x24f624f0, 0x24fa24f4, 0x250024f8, 0x24fe24fc, 0x1ec92502, 0x25082506, 0x25101ecb, 0x27a12512, 0x251a2518, 0x25201ecd, 0x27a31e67, 0x1ecf27a5, 0x25361ed1, 0x25502542, 0x27a72558, 0x25642562, 0x25762570, 0x26ff27ab, 0x257a257c, 0x27012580, 0x258c2586, 0x27af27ad, 0x25b225ac, 0x27b125b6, 0x25cc25b8, 0x25d425d2, 0x25da25d0, 0x27b325dc, 0x1ed325e2, 0x27b525e6, 0x26021ed5, 0x260e20ee, 0x27bb27b7, 0x1ed91ed7, 0x27bd2622, 0x27bf1edb, 0x262e262e, 0x27c12632, 0x1edd263e, 0x264c2646, 0x26542650, 0x27c31edf, 0x266c265e, 0x1ee12672, 0x26741ee3, 0x1ee527c5, 0x27c927c7, 0x268627cb, 0x26901ee7, 0x26962694, 0x269e269a, 0x27cf26a2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //12288 bytes enum canonMappingTrieEntries = TrieEntry!(ushort, 8, 7, 6)([ 0x0, 0x40, 0x240], [ 0x100, 0x400, 0x1380], [ 0x2020100, 0x3020202, 0x2020204, 0x2050202, 0x2020202, 0x6020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x10000, 0x30002, 0x50004, 0x6, 0x0, 0x70000, 0x90008, 0xb000a, 0xc0000, 0x0, 0x0, 0xd, 0xe0000, 0x0, 0x0, 0x0, 0x0, 0x10000f, 0x110000, 0x130012, 0x0, 0x140000, 0x160015, 0x170000, 0x180000, 0x190000, 0x1a0000, 0x0, 0x0, 0x1b0000, 0x1c, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f001e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x210020, 0x230022, 0x250024, 0x270026, 0x28, 0x0, 0x29, 0x2b002a, 0x2d002c, 0x2f002e, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x310000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x320000, 0x340033, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x360035, 0x380037, 0x3a0039, 0x3c003b, 0x3e003d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x410000, 0x430042, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x450044, 0x470046, 0x490048, 0x4b004a, 0x4c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf000c, 0x250012, 0x4f0045, 0x850000, 0xa1009e, 0xcb00a4, 0x121011e, 0x1330124, 0x1880000, 0x1a0019d, 0x1b601a3, 0x1da, 0x26d0000, 0x2730270, 0x2f30287, 0x0, 0x322031f, 0x3380325, 0x3620358, 0x3980000, 0x3b403b1, 0x3de03b7, 0x4370434, 0x446043a, 0x49c0000, 0x4b404b1, 0x4ca04b7, 0x4ee, 0x5840000, 0x58a0587, 0x60d059e, 0x61c0000, 0x33b0028, 0x33e002b, 0x380006d, 0x38c0079, 0x38f007c, 0x392007f, 0x3950082, 0x3a2008f, 0x0, 0x3cd00ba, 0x3d800c5, 0x3db00c8, 0x3fb00e8, 0x3e400d1, 0x40a00f7, 0x41000fd, 0x4130100, 0x4190106, 0x41c0109, 0x0, 0x43d0127, 0x440012a, 0x443012d, 0x45c0149, 0x130, 0x0, 0x462014f, 0x471015d, 0x1630000, 0x1700477, 0x1660484, 0x47a, 0x0, 0x1850000, 0x1940499, 0x18e04a8, 0x4a2, 0x0, 0x4d901c5, 0x4e401d0, 0x4f801e4, 0x0, 0x52f021b, 0x5450231, 0x5350221, 0x54b0237, 0x552023e, 0x5690255, 0x5580244, 0x57b0264, 0x572025b, 0x0, 0x58d0276, 0x594027d, 0x59b0284, 0x5b4029d, 0x5b702a0, 0x5e002c9, 0x5f502de, 0x61002f6, 0x30b0302, 0x3110628, 0x314062e, 0x631, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x50401f0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2ac0000, 0x5c3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x560000, 0x13d0369, 0x1e70450, 0x2a304fb, 0x29205ba, 0x28e05a9, 0x29605a5, 0x28a05ad, 0x5a1, 0x35b0048, 0x3540041, 0x653064a, 0x0, 0x4160103, 0x46b0157, 0x522020e, 0x5250211, 0x65f065c, 0x465, 0x0, 0x40700f4, 0x0, 0x4960182, 0x3650052, 0x6500647, 0x656064d, 0x36c0059, 0x36f005c, 0x3e700d4, 0x3ea00d7, 0x4530140, 0x4560143, 0x4fe01ea, 0x50101ed, 0x5380224, 0x53b0227, 0x5bd02a6, 0x5c002a9, 0x5660252, 0x5780261, 0x0, 0x4250112, 0x0, 0x0, 0x0, 0x351003e, 0x3f400e1, 0x4f101dd, 0x4d101bd, 0x4e701d3, 0x4ea01d6, 0x61602fc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000d, 0x66b0000, 0x137, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x662, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x63d0000, 0x6450670, 0x6df06c3, 0x72c, 0x759, 0x7980778, 0x8d1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7810735, 0x84707e9, 0x8c10867, 0x92f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92808ca, 0x91f08fd, 0x95f, 0x0, 0x9b40000, 0x9b7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9cc09c6, 0x9c30000, 0x0, 0x9ba0000, 0x0, 0x0, 0x9d809e4, 0x9ed, 0x0, 0x0, 0x0, 0x0, 0x9de0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa200000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa0e0a08, 0xa050000, 0x0, 0xa410000, 0x0, 0x0, 0xa1a0a26, 0xa2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa470a44, 0x0, 0x0, 0x0, 0x0, 0x9cf0000, 0xa11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9ff09bd, 0xa0209c0, 0x0, 0xa0b09c9, 0x0, 0xa4d0a4a, 0xa1409d2, 0xa1709d5, 0x0, 0xa1d09db, 0xa2309e1, 0xa2909e7, 0x0, 0xa530a50, 0xa3e09fc, 0xa2c09ea, 0xa3209f0, 0xa3509f3, 0xa3809f6, 0x0, 0xa3b09f9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xac10abe, 0xac40ac7, 0xaca, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad3, 0xacd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae80000, 0x0, 0x0, 0x0, 0xaf10000, 0x0, 0xaf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xad90ad6, 0xadf0adc, 0xae50ae2, 0xaee0aeb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb000000, 0xb03, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xafa0af7, 0xafd0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb120000, 0x0, 0xb15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb060000, 0xb0c0b09, 0x0, 0xb0f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb21, 0xb1e0000, 0xb24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb1b0b18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb300b2a, 0xb2d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb36, 0x0, 0x0, 0xb400000, 0xb43, 0xb3c0b39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb4c0b46, 0xb49, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb4f, 0xb550b52, 0xb59, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb5f0000, 0x0, 0x0, 0x0, 0x0, 0xb620000, 0x0, 0x0, 0xb65, 0x0, 0xb680000, 0x0, 0x0, 0xb6b, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb5c0000, 0x0, 0x0, 0x0, 0x0, 0xb6e0000, 0xb710000, 0xb89, 0xb8c, 0x0, 0x0, 0x0, 0xb740000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb7a0000, 0x0, 0x0, 0x0, 0x0, 0xb7d0000, 0x0, 0x0, 0xb80, 0x0, 0xb830000, 0x0, 0x0, 0xb86, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb770000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb8f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb92, 0xb95, 0xb98, 0xb9b, 0xb9e, 0x0, 0xba1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xba40000, 0xba70000, 0x0, 0xbad0baa, 0xbb00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x37d006a, 0x3830070, 0x3860073, 0x3890076, 0x39b0088, 0x39f008c, 0x3a50092, 0x3ae009b, 0x3a80095, 0x3ab0098, 0x3d000bd, 0x3d400c1, 0x3fe00eb, 0x40100ee, 0x3f700e4, 0x40400f1, 0x40d00fa, 0x41f010c, 0x4280115, 0x422010f, 0x42b0118, 0x42e011b, 0x45f014c, 0x4490136, 0x4680154, 0x46e015a, 0x4740160, 0x47d0169, 0x480016c, 0x48a0176, 0x4870173, 0x48d0179, 0x490017c, 0x493017f, 0x49f018b, 0x4a50191, 0x4ae019a, 0x4ab0197, 0x4cd01b9, 0x4d501c1, 0x4dc01c8, 0x4e001cc, 0x5290215, 0x52c0218, 0x532021e, 0x53e022a, 0x541022d, 0x5480234, 0x5550241, 0x55f024b, 0x54e023a, 0x55b0247, 0x562024e, 0x56c0258, 0x575025e, 0x581026a, 0x57e0267, 0x5dd02c6, 0x5e602cf, 0x5e302cc, 0x5900279, 0x5970280, 0x5e902d2, 0x5ec02d5, 0x5ef02d8, 0x5f202db, 0x5fb02e4, 0x5f802e1, 0x60102e7, 0x60402ea, 0x60702ed, 0x61902ff, 0x62b030e, 0x6340317, 0x637031a, 0x56f0431, 0x62205fe, 0x6590000, 0x0, 0x0, 0x372005f, 0x35f004c, 0x32c0019, 0x3280015, 0x3340021, 0x330001d, 0x3750062, 0x3450032, 0x341002e, 0x34d003a, 0x3490036, 0x3790066, 0x3ed00da, 0x3e100ce, 0x3ca00b7, 0x3be00ab, 0x3ba00a7, 0x3c600b3, 0x3c200af, 0x3f000dd, 0x44d013a, 0x4590146, 0x51b0207, 0x4f501e1, 0x4be01aa, 0x4ba01a6, 0x4c601b2, 0x4c201ae, 0x51e020a, 0x50b01f7, 0x50701f3, 0x51301ff, 0x50f01fb, 0x5170203, 0x5da02c3, 0x5b1029a, 0x5ca02b3, 0x5c602af, 0x5d202bb, 0x5ce02b7, 0x5d602bf, 0x60a02f0, 0x6250308, 0x61f0305, 0x61302f9, 0x0, 0x0, 0x0, 0x81807f6, 0x81b07f9, 0x8240802, 0x82d080b, 0x69b0679, 0x69e067c, 0x6a70685, 0x6b0068e, 0x855084a, 0x858084d, 0x85c0851, 0x0, 0x6d106c6, 0x6d406c9, 0x6d806cd, 0x0, 0x890086e, 0x8930871, 0x89c087a, 0x8a50883, 0x70406e2, 0x70706e5, 0x71006ee, 0x71906f7, 0x8e808d9, 0x8eb08dc, 0x8ef08e0, 0x8f308e4, 0x7470738, 0x74a073b, 0x74e073f, 0x7520743, 0x90b0900, 0x90e0903, 0x9120907, 0x0, 0x767075c, 0x76a075f, 0x76e0763, 0x0, 0x9460937, 0x949093a, 0x94d093e, 0x9510942, 0x7840000, 0x7870000, 0x78b0000, 0x78f0000, 0x9880966, 0x98b0969, 0x9940972, 0x99d097b, 0x7bd079b, 0x7c0079e, 0x7c907a7, 0x7d207b0, 0x7e907e2, 0x8470844, 0x8670860, 0x8c108be, 0x8fd08fa, 0x91f091c, 0x95f0958, 0x0, 0x8360814, 0x81f07fd, 0x8280806, 0x831080f, 0x6b90697, 0x6a20680, 0x6ab0689, 0x6b40692, 0x8ae088c, 0x8970875, 0x8a0087e, 0x8a90887, 0x7220700, 0x70b06e9, 0x71406f2, 0x71d06fb, 0x9a60984, 0x98f096d, 0x9980976, 0x9a1097f, 0x7db07b9, 0x7c407a2, 0x7cd07ab, 0x7d607b4, 0x7f007f3, 0x84107e5, 0x7ec, 0x83d083a, 0x6730676, 0x670066d, 0x6bd, 0x8bc, 0x6400000, 0x8b90863, 0x86a, 0x8b508b2, 0x6c306c0, 0x6df06dc, 0xbb30726, 0xbb90bb6, 0x8c408c7, 0x8d108cd, 0x0, 0x8d508f7, 0x72f0732, 0x72c0729, 0xbbc0000, 0xbc20bbf, 0x9220925, 0x92f092b, 0x9190916, 0x9330955, 0x77b077e, 0x7780775, 0x63a0772, 0x31d063d, 0x0, 0x9b1095b, 0x962, 0x9ad09aa, 0x7590756, 0x7980795, 0x64307df, 0x0, 0xbc70bc5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x793, 0x0, 0x4f0152, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbcc0bc9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbcf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbd20000, 0xbd50bd8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbdb, 0x0, 0xbde0000, 0x0, 0xbe1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbe4, 0xbe7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbea0000, 0x0, 0xbed, 0xbf00000, 0xbf30000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xbf9, 0x0, 0x0, 0x0, 0x0, 0xbf60000, 0x90003, 0xbff0bfc, 0x0, 0xc050c02, 0x0, 0xc0b0c08, 0x0, 0x0, 0x0, 0xc110c0e, 0x0, 0xc1d0c1a, 0x0, 0xc230c20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc2f0c2c, 0xc350c32, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc170c14, 0xc290c26, 0x0, 0x0, 0x0, 0xc3b0c38, 0xc410c3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc470000, 0xc49, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc4e, 0xc51, 0xc54, 0xc57, 0xc5a, 0xc5d, 0xc60, 0xc63, 0xc66, 0xc69, 0xc6c, 0xc6f, 0xc720000, 0xc750000, 0xc780000, 0x0, 0x0, 0x0, 0xc7e0c7b, 0xc810000, 0xc84, 0xc8a0c87, 0xc8d0000, 0xc90, 0xc960c93, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc4b, 0x0, 0x0, 0x0, 0x0, 0xc99, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc9f, 0xca2, 0xca5, 0xca8, 0xcab, 0xcae, 0xcb1, 0xcb4, 0xcb7, 0xcba, 0xcbd, 0xcc0, 0xcc30000, 0xcc60000, 0xcc90000, 0x0, 0x0, 0x0, 0xccf0ccc, 0xcd20000, 0xcd5, 0xcdb0cd8, 0xcde0000, 0xce1, 0xce70ce4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc9c, 0xcea0000, 0xcf00ced, 0xcf3, 0x0, 0xcf6, 0xfb71241, 0x124b125d, 0xd831043, 0x13270e29, 0xe991327, 0xe4f1293, 0xf550e97, 0x116710cd, 0x11fd11e3, 0x12791215, 0x10190feb, 0x109d1069, 0x128911c7, 0xd8d12f3, 0xff50e1d, 0x11e11079, 0xedb1309, 0x11d91051, 0xf65121d, 0x12031189, 0xfbd0eff, 0x108d1025, 0xd9d127d, 0xe050dd9, 0xff10f95, 0x10d31077, 0x11dd1171, 0x125911e7, 0x12fb12cf, 0x10e91307, 0x114d1107, 0x12a111b9, 0x122f130b, 0xf0b0e87, 0x117d112f, 0x10ed1083, 0x12cb1249, 0xecb0e85, 0x102f0fed, 0x11471047, 0x12b11159, 0x117f0e03, 0xddd0ddf, 0x114f1115, 0x12b511c5, 0xf67123d, 0x12350feb, 0xebb0d87, 0x10950f27, 0xe1110c1, 0xda510f1, 0xd7f0f1b, 0xf9d1011, 0xe231145, 0x10d70e7d, 0x122711c9, 0x126d1005, 0xf6f100d, 0xf7b11a5, 0xd9110bf, 0xddb0dc3, 0x113d0fdb, 0x122d1195, 0xe091291, 0xe9f0e37, 0xfa10f07, 0x10f31053, 0x12f712ab, 0x1313130d, 0xfb50df9, 0x12690ffd, 0xf490ef3, 0xf910f57, 0x106d104b, 0x111110af, 0x11791153, 0x11cd1261, 0x12a31271, 0xdfb0de9, 0x10670e41, 0x1227120b, 0xf230efd, 0x10030f77, 0x1091112d, 0xe670d97, 0xee50ebb, 0x109b0f29, 0x116b10a9, 0x12951175, 0x12d112c9, 0xd9f12dd, 0x128d110f, 0xf3512c1, 0xdb10d8f, 0xec70ebd, 0xfeb0f9f, 0x10cb1073, 0x127711d3, 0xfad1323, 0xdf712af, 0xfd10fcb, 0x103b1021, 0x10bd10a1, 0x114310e7, 0xdc512e3, 0x12b70f5d, 0xed70da9, 0x12631031, 0xf390f17, 0x10950fd5, 0xdeb12bb, 0xecf0e31, 0xfc30fa7, 0x10150fe1, 0x10c3109f, 0x120d1163, 0x128f1213, 0xe1312c5, 0xe33103d, 0x10b11075, 0x12bd11db, 0x130f12ff, 0x102d0fcf, 0x1121118b, 0x11331125, 0x1063108b, 0xd93123b, 0xded11ad, 0xef50de7, 0x11390f69, 0x101b0eb5, 0x12670fb3, 0x12b31205, 0xf031221, 0xe590db5, 0x0, 0xe7b, 0xfab, 0xde10000, 0x10cf108f, 0x110310f5, 0x110d1105, 0x113512d3, 0x116d, 0x11df, 0x1233, 0x12730000, 0x1283, 0x0, 0x12e912e7, 0x130512eb, 0x12bf127f, 0xdb30da1, 0xe010db9, 0xe170e07, 0xe5f0e53, 0xe790e63, 0xecd0e7f, 0xf2f0ed1, 0xf470f43, 0xf970f53, 0xfaf0fa3, 0x10270fdd, 0x10491035, 0x107d106f, 0x10eb10a3, 0x10fb10f7, 0x10fd10f9, 0x110110ff, 0x110b1109, 0x111d1117, 0x11531127, 0x115b1157, 0x11731161, 0x1197118d, 0x11cb1197, 0x12231219, 0x12391237, 0x124f124d, 0x1273126f, 0x12d912c7, 0xf2b12e1, 0x119313be, 0x0, 0xdd70d81, 0xd9b0dc1, 0xdc90db7, 0xe0b0dff, 0xe490e53, 0xe5d0e51, 0xe830e7b, 0xe9b0e95, 0xeb10ea9, 0xf050f01, 0xf1d0f13, 0xf3f0f33, 0xf470f37, 0xf530f41, 0xf7f0f5f, 0xf890f85, 0xfab0f99, 0xfbf0fbd, 0xfff0fc7, 0x10211005, 0x10411045, 0x10571049, 0x10e3106f, 0x1089107f, 0x10ab108f, 0x10b910b5, 0x10c910c7, 0x10d110cf, 0x10df10d5, 0x10ef10dd, 0x1127111f, 0x11491131, 0x115f1153, 0x11af1173, 0x11f911c3, 0x121f121b, 0x12291223, 0x122b1233, 0x12351237, 0x12391231, 0x124f123f, 0x12751265, 0x1299128b, 0x12c712b9, 0x12d512d3, 0x12db12d9, 0x12f912e1, 0x13941327, 0x13a61392, 0xd370d23, 0x13da0d39, 0x141c13ec, 0x13251321, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa7a0000, 0xabb0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xab50ab2, 0xaae0aaa, 0xa590a56, 0xa5f0a5c, 0xa680a65, 0xa710a6b, 0xa74, 0xa7d0a77, 0xa830a80, 0xa89, 0xa8c, 0xa920a8f, 0xa950000, 0xa98, 0xaa10a9e, 0xaa70aa4, 0xa6e0ab8, 0xa860a62, 0xa9b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1329, 0x132c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x132f0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13351332, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x133b1338, 0x1342133e, 0x134a1346, 0x134e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13520000, 0x1355135d, 0x13591360, 0x1364, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd850d89, 0x13680d8b, 0xda10d99, 0xda70da3, 0xdad0dab, 0xdaf0db3, 0x13700cf9, 0xdbb0db9, 0xdc70dbd, 0xcfb136a, 0xdcb0dbf, 0xdd1136e, 0xd950dd3, 0xdd70dd5, 0xde3142c, 0xcff0de5, 0xdf10def, 0xdf50df3, 0xdff0d01, 0xe070e01, 0xe0d0e0b, 0xe110e0f, 0xe170e15, 0xe1b0e19, 0xe210e1f, 0xe210e21, 0x105d1376, 0xe270e25, 0xe2b1378, 0xe2f0e2d, 0xe350e3d, 0xe3b0e39, 0xe430e3f, 0xe470e45, 0xe4d0e4b, 0xe510e4d, 0xe570e55, 0xe690e5b, 0xe6b0e5f, 0xe650e61, 0xe890de7, 0xe710e6f, 0xe6d0e73, 0xe750e77, 0x137a0e81, 0xe8d0e8b, 0xe910e8f, 0xe9d0e93, 0x137e137c, 0xea50ea3, 0xea10ea7, 0xd030eab, 0xeaf0d05, 0xeb30eb3, 0xeb71380, 0xebb0eb9, 0x13820ebf, 0xec30ec1, 0xec50f0f, 0xec90d07, 0xed50ed1, 0x13860ed3, 0x13880ed9, 0xedd0edf, 0xee70ee1, 0xd090ee9, 0xeed0eeb, 0xef10eef, 0x138a0d0b, 0xef70d0d, 0xefb0ef9, 0x14400eff, 0x138e0f09, 0x118f138e, 0xf0d0f0d, 0x139c0d0f, 0xf1113f0, 0xd110f15, 0xf1f0f19, 0xf250f21, 0xd150f2d, 0xf2f0d13, 0xf311390, 0xf3d0f3b, 0xf3d0f3f, 0xf470f45, 0xf4b0f4f, 0xf510f4d, 0xf550f53, 0xf5b0f59, 0xf630f61, 0xf730f6b, 0xf711396, 0xf750f6d, 0xf830f79, 0xf871398, 0xf7d0f81, 0xf8b0d17, 0xf930f8f, 0xd190f8d, 0xf9b0f97, 0xfa5139a, 0xfa90fb9, 0xfaf0d1f, 0xd1b0d1d, 0xdcf0dcd, 0xfb10fbb, 0xd511181, 0xfbf0fbd, 0xfc90fc1, 0x13a40fc5, 0xfd30d21, 0xfd90fcd, 0x13a80fdd, 0xfd70fdf, 0xd230fe3, 0xfe70fe5, 0xfef0fe9, 0xff313aa, 0xff70d25, 0xff913ac, 0xffb0d27, 0x10051001, 0x13ae1007, 0x13b01384, 0x13b21009, 0x1013100f, 0x1017100b, 0x1027101f, 0x10231021, 0x102b1029, 0x101d13b4, 0x10391037, 0x10410d29, 0x13b6103f, 0x104d1033, 0x13ba13b8, 0x1059104f, 0x10551057, 0x105b0d2b, 0x105f1061, 0x136c1065, 0x13bc106b, 0x13c01071, 0x107f107b, 0x13c21081, 0x10871085, 0x13c613c4, 0x10971093, 0x10990d2d, 0xd2f0d2f, 0x10a710a5, 0x10ad10ab, 0xd3110b3, 0x13c810b7, 0x13ca10bb, 0x138c10c1, 0x13cc10c5, 0x13d013ce, 0xd350d33, 0x13d410d5, 0x13d613d2, 0x10d913d8, 0x10db10db, 0xd3910df, 0xd3b10e1, 0x13dc0d3d, 0x10e910e5, 0xd3f10ef, 0x10ff13de, 0x13e213e0, 0x1113110d, 0x11170d41, 0x111b1119, 0x13e613e4, 0x112313e6, 0x13e80d43, 0x112b1129, 0x13ea0d45, 0xd471137, 0x113b113f, 0x13ee1141, 0xd49114b, 0x11551151, 0xd4b115d, 0x13f413f2, 0x13f60d4d, 0x13f81165, 0x116f1169, 0x13fa1173, 0x117713fc, 0x117b13fe, 0xd4f139e, 0x11851183, 0x11870d53, 0x14000ead, 0x13a01402, 0x118f13a2, 0x126b1191, 0x119b0d55, 0x119d1199, 0x119f0dfd, 0x11a311a1, 0x140411a7, 0x11a911a5, 0x11b511b3, 0x11b711ab, 0x11cb11c1, 0x11bb11b1, 0x11bf11bd, 0x140a1406, 0xd571408, 0x11d111cf, 0x141211d5, 0x140c11d7, 0xd5b0d59, 0x1410140e, 0x11e50d5d, 0x11e911e7, 0x11ef11eb, 0x11f311ed, 0x11f911f1, 0x11f711f5, 0xd5f11fb, 0x120111ff, 0x12070d61, 0x14141209, 0x1211120f, 0x12170d63, 0x14160cfd, 0xd651418, 0x12250d67, 0x123f1231, 0x141a1243, 0x12471245, 0x12531251, 0x1372141e, 0x12551257, 0x1374125b, 0x1265125f, 0x14221420, 0x1281127b, 0x14241285, 0x12971287, 0x129f129d, 0x12a5129b, 0x142612a7, 0xd6912a9, 0x142812ad, 0x12c30d6b, 0x12cd0ee3, 0x142e142a, 0xd6f0d6d, 0x143012d7, 0x14320d71, 0x12db12db, 0x143412df, 0xd7312e5, 0x12ef12ed, 0x12f512f1, 0x14360d75, 0x12fd12f9, 0xd771301, 0x13030d79, 0xd7b1438, 0x143c143a, 0x1311143e, 0x13150d7d, 0x13191317, 0x131d131b, 0x1442131f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); @property { private alias _IDCA = immutable(dchar[]); _IDCA decompCanonTable() { static _IDCA t = [ 0x0, 0x3b, 0x0, 0x3c, 0x338, 0x0, 0x3d, 0x338, 0x0, 0x3e, 0x338, 0x0, 0x41, 0x300, 0x0, 0x41, 0x301, 0x0, 0x41, 0x302, 0x0, 0x41, 0x302, 0x300, 0x0, 0x41, 0x302, 0x301, 0x0, 0x41, 0x302, 0x303, 0x0, 0x41, 0x302, 0x309, 0x0, 0x41, 0x303, 0x0, 0x41, 0x304, 0x0, 0x41, 0x306, 0x0, 0x41, 0x306, 0x300, 0x0, 0x41, 0x306, 0x301, 0x0, 0x41, 0x306, 0x303, 0x0, 0x41, 0x306, 0x309, 0x0, 0x41, 0x307, 0x0, 0x41, 0x307, 0x304, 0x0, 0x41, 0x308, 0x0, 0x41, 0x308, 0x304, 0x0, 0x41, 0x309, 0x0, 0x41, 0x30a, 0x0, 0x41, 0x30a, 0x301, 0x0, 0x41, 0x30c, 0x0, 0x41, 0x30f, 0x0, 0x41, 0x311, 0x0, 0x41, 0x323, 0x0, 0x41, 0x323, 0x302, 0x0, 0x41, 0x323, 0x306, 0x0, 0x41, 0x325, 0x0, 0x41, 0x328, 0x0, 0x42, 0x307, 0x0, 0x42, 0x323, 0x0, 0x42, 0x331, 0x0, 0x43, 0x301, 0x0, 0x43, 0x302, 0x0, 0x43, 0x307, 0x0, 0x43, 0x30c, 0x0, 0x43, 0x327, 0x0, 0x43, 0x327, 0x301, 0x0, 0x44, 0x307, 0x0, 0x44, 0x30c, 0x0, 0x44, 0x323, 0x0, 0x44, 0x327, 0x0, 0x44, 0x32d, 0x0, 0x44, 0x331, 0x0, 0x45, 0x300, 0x0, 0x45, 0x301, 0x0, 0x45, 0x302, 0x0, 0x45, 0x302, 0x300, 0x0, 0x45, 0x302, 0x301, 0x0, 0x45, 0x302, 0x303, 0x0, 0x45, 0x302, 0x309, 0x0, 0x45, 0x303, 0x0, 0x45, 0x304, 0x0, 0x45, 0x304, 0x300, 0x0, 0x45, 0x304, 0x301, 0x0, 0x45, 0x306, 0x0, 0x45, 0x307, 0x0, 0x45, 0x308, 0x0, 0x45, 0x309, 0x0, 0x45, 0x30c, 0x0, 0x45, 0x30f, 0x0, 0x45, 0x311, 0x0, 0x45, 0x323, 0x0, 0x45, 0x323, 0x302, 0x0, 0x45, 0x327, 0x0, 0x45, 0x327, 0x306, 0x0, 0x45, 0x328, 0x0, 0x45, 0x32d, 0x0, 0x45, 0x330, 0x0, 0x46, 0x307, 0x0, 0x47, 0x301, 0x0, 0x47, 0x302, 0x0, 0x47, 0x304, 0x0, 0x47, 0x306, 0x0, 0x47, 0x307, 0x0, 0x47, 0x30c, 0x0, 0x47, 0x327, 0x0, 0x48, 0x302, 0x0, 0x48, 0x307, 0x0, 0x48, 0x308, 0x0, 0x48, 0x30c, 0x0, 0x48, 0x323, 0x0, 0x48, 0x327, 0x0, 0x48, 0x32e, 0x0, 0x49, 0x300, 0x0, 0x49, 0x301, 0x0, 0x49, 0x302, 0x0, 0x49, 0x303, 0x0, 0x49, 0x304, 0x0, 0x49, 0x306, 0x0, 0x49, 0x307, 0x0, 0x49, 0x308, 0x0, 0x49, 0x308, 0x301, 0x0, 0x49, 0x309, 0x0, 0x49, 0x30c, 0x0, 0x49, 0x30f, 0x0, 0x49, 0x311, 0x0, 0x49, 0x323, 0x0, 0x49, 0x328, 0x0, 0x49, 0x330, 0x0, 0x4a, 0x302, 0x0, 0x4b, 0x0, 0x4b, 0x301, 0x0, 0x4b, 0x30c, 0x0, 0x4b, 0x323, 0x0, 0x4b, 0x327, 0x0, 0x4b, 0x331, 0x0, 0x4c, 0x301, 0x0, 0x4c, 0x30c, 0x0, 0x4c, 0x323, 0x0, 0x4c, 0x323, 0x304, 0x0, 0x4c, 0x327, 0x0, 0x4c, 0x32d, 0x0, 0x4c, 0x331, 0x0, 0x4d, 0x301, 0x0, 0x4d, 0x307, 0x0, 0x4d, 0x323, 0x0, 0x4e, 0x300, 0x0, 0x4e, 0x301, 0x0, 0x4e, 0x303, 0x0, 0x4e, 0x307, 0x0, 0x4e, 0x30c, 0x0, 0x4e, 0x323, 0x0, 0x4e, 0x327, 0x0, 0x4e, 0x32d, 0x0, 0x4e, 0x331, 0x0, 0x4f, 0x300, 0x0, 0x4f, 0x301, 0x0, 0x4f, 0x302, 0x0, 0x4f, 0x302, 0x300, 0x0, 0x4f, 0x302, 0x301, 0x0, 0x4f, 0x302, 0x303, 0x0, 0x4f, 0x302, 0x309, 0x0, 0x4f, 0x303, 0x0, 0x4f, 0x303, 0x301, 0x0, 0x4f, 0x303, 0x304, 0x0, 0x4f, 0x303, 0x308, 0x0, 0x4f, 0x304, 0x0, 0x4f, 0x304, 0x300, 0x0, 0x4f, 0x304, 0x301, 0x0, 0x4f, 0x306, 0x0, 0x4f, 0x307, 0x0, 0x4f, 0x307, 0x304, 0x0, 0x4f, 0x308, 0x0, 0x4f, 0x308, 0x304, 0x0, 0x4f, 0x309, 0x0, 0x4f, 0x30b, 0x0, 0x4f, 0x30c, 0x0, 0x4f, 0x30f, 0x0, 0x4f, 0x311, 0x0, 0x4f, 0x31b, 0x0, 0x4f, 0x31b, 0x300, 0x0, 0x4f, 0x31b, 0x301, 0x0, 0x4f, 0x31b, 0x303, 0x0, 0x4f, 0x31b, 0x309, 0x0, 0x4f, 0x31b, 0x323, 0x0, 0x4f, 0x323, 0x0, 0x4f, 0x323, 0x302, 0x0, 0x4f, 0x328, 0x0, 0x4f, 0x328, 0x304, 0x0, 0x50, 0x301, 0x0, 0x50, 0x307, 0x0, 0x52, 0x301, 0x0, 0x52, 0x307, 0x0, 0x52, 0x30c, 0x0, 0x52, 0x30f, 0x0, 0x52, 0x311, 0x0, 0x52, 0x323, 0x0, 0x52, 0x323, 0x304, 0x0, 0x52, 0x327, 0x0, 0x52, 0x331, 0x0, 0x53, 0x301, 0x0, 0x53, 0x301, 0x307, 0x0, 0x53, 0x302, 0x0, 0x53, 0x307, 0x0, 0x53, 0x30c, 0x0, 0x53, 0x30c, 0x307, 0x0, 0x53, 0x323, 0x0, 0x53, 0x323, 0x307, 0x0, 0x53, 0x326, 0x0, 0x53, 0x327, 0x0, 0x54, 0x307, 0x0, 0x54, 0x30c, 0x0, 0x54, 0x323, 0x0, 0x54, 0x326, 0x0, 0x54, 0x327, 0x0, 0x54, 0x32d, 0x0, 0x54, 0x331, 0x0, 0x55, 0x300, 0x0, 0x55, 0x301, 0x0, 0x55, 0x302, 0x0, 0x55, 0x303, 0x0, 0x55, 0x303, 0x301, 0x0, 0x55, 0x304, 0x0, 0x55, 0x304, 0x308, 0x0, 0x55, 0x306, 0x0, 0x55, 0x308, 0x0, 0x55, 0x308, 0x300, 0x0, 0x55, 0x308, 0x301, 0x0, 0x55, 0x308, 0x304, 0x0, 0x55, 0x308, 0x30c, 0x0, 0x55, 0x309, 0x0, 0x55, 0x30a, 0x0, 0x55, 0x30b, 0x0, 0x55, 0x30c, 0x0, 0x55, 0x30f, 0x0, 0x55, 0x311, 0x0, 0x55, 0x31b, 0x0, 0x55, 0x31b, 0x300, 0x0, 0x55, 0x31b, 0x301, 0x0, 0x55, 0x31b, 0x303, 0x0, 0x55, 0x31b, 0x309, 0x0, 0x55, 0x31b, 0x323, 0x0, 0x55, 0x323, 0x0, 0x55, 0x324, 0x0, 0x55, 0x328, 0x0, 0x55, 0x32d, 0x0, 0x55, 0x330, 0x0, 0x56, 0x303, 0x0, 0x56, 0x323, 0x0, 0x57, 0x300, 0x0, 0x57, 0x301, 0x0, 0x57, 0x302, 0x0, 0x57, 0x307, 0x0, 0x57, 0x308, 0x0, 0x57, 0x323, 0x0, 0x58, 0x307, 0x0, 0x58, 0x308, 0x0, 0x59, 0x300, 0x0, 0x59, 0x301, 0x0, 0x59, 0x302, 0x0, 0x59, 0x303, 0x0, 0x59, 0x304, 0x0, 0x59, 0x307, 0x0, 0x59, 0x308, 0x0, 0x59, 0x309, 0x0, 0x59, 0x323, 0x0, 0x5a, 0x301, 0x0, 0x5a, 0x302, 0x0, 0x5a, 0x307, 0x0, 0x5a, 0x30c, 0x0, 0x5a, 0x323, 0x0, 0x5a, 0x331, 0x0, 0x60, 0x0, 0x61, 0x300, 0x0, 0x61, 0x301, 0x0, 0x61, 0x302, 0x0, 0x61, 0x302, 0x300, 0x0, 0x61, 0x302, 0x301, 0x0, 0x61, 0x302, 0x303, 0x0, 0x61, 0x302, 0x309, 0x0, 0x61, 0x303, 0x0, 0x61, 0x304, 0x0, 0x61, 0x306, 0x0, 0x61, 0x306, 0x300, 0x0, 0x61, 0x306, 0x301, 0x0, 0x61, 0x306, 0x303, 0x0, 0x61, 0x306, 0x309, 0x0, 0x61, 0x307, 0x0, 0x61, 0x307, 0x304, 0x0, 0x61, 0x308, 0x0, 0x61, 0x308, 0x304, 0x0, 0x61, 0x309, 0x0, 0x61, 0x30a, 0x0, 0x61, 0x30a, 0x301, 0x0, 0x61, 0x30c, 0x0, 0x61, 0x30f, 0x0, 0x61, 0x311, 0x0, 0x61, 0x323, 0x0, 0x61, 0x323, 0x302, 0x0, 0x61, 0x323, 0x306, 0x0, 0x61, 0x325, 0x0, 0x61, 0x328, 0x0, 0x62, 0x307, 0x0, 0x62, 0x323, 0x0, 0x62, 0x331, 0x0, 0x63, 0x301, 0x0, 0x63, 0x302, 0x0, 0x63, 0x307, 0x0, 0x63, 0x30c, 0x0, 0x63, 0x327, 0x0, 0x63, 0x327, 0x301, 0x0, 0x64, 0x307, 0x0, 0x64, 0x30c, 0x0, 0x64, 0x323, 0x0, 0x64, 0x327, 0x0, 0x64, 0x32d, 0x0, 0x64, 0x331, 0x0, 0x65, 0x300, 0x0, 0x65, 0x301, 0x0, 0x65, 0x302, 0x0, 0x65, 0x302, 0x300, 0x0, 0x65, 0x302, 0x301, 0x0, 0x65, 0x302, 0x303, 0x0, 0x65, 0x302, 0x309, 0x0, 0x65, 0x303, 0x0, 0x65, 0x304, 0x0, 0x65, 0x304, 0x300, 0x0, 0x65, 0x304, 0x301, 0x0, 0x65, 0x306, 0x0, 0x65, 0x307, 0x0, 0x65, 0x308, 0x0, 0x65, 0x309, 0x0, 0x65, 0x30c, 0x0, 0x65, 0x30f, 0x0, 0x65, 0x311, 0x0, 0x65, 0x323, 0x0, 0x65, 0x323, 0x302, 0x0, 0x65, 0x327, 0x0, 0x65, 0x327, 0x306, 0x0, 0x65, 0x328, 0x0, 0x65, 0x32d, 0x0, 0x65, 0x330, 0x0, 0x66, 0x307, 0x0, 0x67, 0x301, 0x0, 0x67, 0x302, 0x0, 0x67, 0x304, 0x0, 0x67, 0x306, 0x0, 0x67, 0x307, 0x0, 0x67, 0x30c, 0x0, 0x67, 0x327, 0x0, 0x68, 0x302, 0x0, 0x68, 0x307, 0x0, 0x68, 0x308, 0x0, 0x68, 0x30c, 0x0, 0x68, 0x323, 0x0, 0x68, 0x327, 0x0, 0x68, 0x32e, 0x0, 0x68, 0x331, 0x0, 0x69, 0x300, 0x0, 0x69, 0x301, 0x0, 0x69, 0x302, 0x0, 0x69, 0x303, 0x0, 0x69, 0x304, 0x0, 0x69, 0x306, 0x0, 0x69, 0x308, 0x0, 0x69, 0x308, 0x301, 0x0, 0x69, 0x309, 0x0, 0x69, 0x30c, 0x0, 0x69, 0x30f, 0x0, 0x69, 0x311, 0x0, 0x69, 0x323, 0x0, 0x69, 0x328, 0x0, 0x69, 0x330, 0x0, 0x6a, 0x302, 0x0, 0x6a, 0x30c, 0x0, 0x6b, 0x301, 0x0, 0x6b, 0x30c, 0x0, 0x6b, 0x323, 0x0, 0x6b, 0x327, 0x0, 0x6b, 0x331, 0x0, 0x6c, 0x301, 0x0, 0x6c, 0x30c, 0x0, 0x6c, 0x323, 0x0, 0x6c, 0x323, 0x304, 0x0, 0x6c, 0x327, 0x0, 0x6c, 0x32d, 0x0, 0x6c, 0x331, 0x0, 0x6d, 0x301, 0x0, 0x6d, 0x307, 0x0, 0x6d, 0x323, 0x0, 0x6e, 0x300, 0x0, 0x6e, 0x301, 0x0, 0x6e, 0x303, 0x0, 0x6e, 0x307, 0x0, 0x6e, 0x30c, 0x0, 0x6e, 0x323, 0x0, 0x6e, 0x327, 0x0, 0x6e, 0x32d, 0x0, 0x6e, 0x331, 0x0, 0x6f, 0x300, 0x0, 0x6f, 0x301, 0x0, 0x6f, 0x302, 0x0, 0x6f, 0x302, 0x300, 0x0, 0x6f, 0x302, 0x301, 0x0, 0x6f, 0x302, 0x303, 0x0, 0x6f, 0x302, 0x309, 0x0, 0x6f, 0x303, 0x0, 0x6f, 0x303, 0x301, 0x0, 0x6f, 0x303, 0x304, 0x0, 0x6f, 0x303, 0x308, 0x0, 0x6f, 0x304, 0x0, 0x6f, 0x304, 0x300, 0x0, 0x6f, 0x304, 0x301, 0x0, 0x6f, 0x306, 0x0, 0x6f, 0x307, 0x0, 0x6f, 0x307, 0x304, 0x0, 0x6f, 0x308, 0x0, 0x6f, 0x308, 0x304, 0x0, 0x6f, 0x309, 0x0, 0x6f, 0x30b, 0x0, 0x6f, 0x30c, 0x0, 0x6f, 0x30f, 0x0, 0x6f, 0x311, 0x0, 0x6f, 0x31b, 0x0, 0x6f, 0x31b, 0x300, 0x0, 0x6f, 0x31b, 0x301, 0x0, 0x6f, 0x31b, 0x303, 0x0, 0x6f, 0x31b, 0x309, 0x0, 0x6f, 0x31b, 0x323, 0x0, 0x6f, 0x323, 0x0, 0x6f, 0x323, 0x302, 0x0, 0x6f, 0x328, 0x0, 0x6f, 0x328, 0x304, 0x0, 0x70, 0x301, 0x0, 0x70, 0x307, 0x0, 0x72, 0x301, 0x0, 0x72, 0x307, 0x0, 0x72, 0x30c, 0x0, 0x72, 0x30f, 0x0, 0x72, 0x311, 0x0, 0x72, 0x323, 0x0, 0x72, 0x323, 0x304, 0x0, 0x72, 0x327, 0x0, 0x72, 0x331, 0x0, 0x73, 0x301, 0x0, 0x73, 0x301, 0x307, 0x0, 0x73, 0x302, 0x0, 0x73, 0x307, 0x0, 0x73, 0x30c, 0x0, 0x73, 0x30c, 0x307, 0x0, 0x73, 0x323, 0x0, 0x73, 0x323, 0x307, 0x0, 0x73, 0x326, 0x0, 0x73, 0x327, 0x0, 0x74, 0x307, 0x0, 0x74, 0x308, 0x0, 0x74, 0x30c, 0x0, 0x74, 0x323, 0x0, 0x74, 0x326, 0x0, 0x74, 0x327, 0x0, 0x74, 0x32d, 0x0, 0x74, 0x331, 0x0, 0x75, 0x300, 0x0, 0x75, 0x301, 0x0, 0x75, 0x302, 0x0, 0x75, 0x303, 0x0, 0x75, 0x303, 0x301, 0x0, 0x75, 0x304, 0x0, 0x75, 0x304, 0x308, 0x0, 0x75, 0x306, 0x0, 0x75, 0x308, 0x0, 0x75, 0x308, 0x300, 0x0, 0x75, 0x308, 0x301, 0x0, 0x75, 0x308, 0x304, 0x0, 0x75, 0x308, 0x30c, 0x0, 0x75, 0x309, 0x0, 0x75, 0x30a, 0x0, 0x75, 0x30b, 0x0, 0x75, 0x30c, 0x0, 0x75, 0x30f, 0x0, 0x75, 0x311, 0x0, 0x75, 0x31b, 0x0, 0x75, 0x31b, 0x300, 0x0, 0x75, 0x31b, 0x301, 0x0, 0x75, 0x31b, 0x303, 0x0, 0x75, 0x31b, 0x309, 0x0, 0x75, 0x31b, 0x323, 0x0, 0x75, 0x323, 0x0, 0x75, 0x324, 0x0, 0x75, 0x328, 0x0, 0x75, 0x32d, 0x0, 0x75, 0x330, 0x0, 0x76, 0x303, 0x0, 0x76, 0x323, 0x0, 0x77, 0x300, 0x0, 0x77, 0x301, 0x0, 0x77, 0x302, 0x0, 0x77, 0x307, 0x0, 0x77, 0x308, 0x0, 0x77, 0x30a, 0x0, 0x77, 0x323, 0x0, 0x78, 0x307, 0x0, 0x78, 0x308, 0x0, 0x79, 0x300, 0x0, 0x79, 0x301, 0x0, 0x79, 0x302, 0x0, 0x79, 0x303, 0x0, 0x79, 0x304, 0x0, 0x79, 0x307, 0x0, 0x79, 0x308, 0x0, 0x79, 0x309, 0x0, 0x79, 0x30a, 0x0, 0x79, 0x323, 0x0, 0x7a, 0x301, 0x0, 0x7a, 0x302, 0x0, 0x7a, 0x307, 0x0, 0x7a, 0x30c, 0x0, 0x7a, 0x323, 0x0, 0x7a, 0x331, 0x0, 0xa8, 0x300, 0x0, 0xa8, 0x301, 0x0, 0xa8, 0x342, 0x0, 0xb4, 0x0, 0xb7, 0x0, 0xc6, 0x301, 0x0, 0xc6, 0x304, 0x0, 0xd8, 0x301, 0x0, 0xe6, 0x301, 0x0, 0xe6, 0x304, 0x0, 0xf8, 0x301, 0x0, 0x17f, 0x307, 0x0, 0x1b7, 0x30c, 0x0, 0x292, 0x30c, 0x0, 0x2b9, 0x0, 0x300, 0x0, 0x301, 0x0, 0x308, 0x301, 0x0, 0x313, 0x0, 0x391, 0x300, 0x0, 0x391, 0x301, 0x0, 0x391, 0x304, 0x0, 0x391, 0x306, 0x0, 0x391, 0x313, 0x0, 0x391, 0x313, 0x300, 0x0, 0x391, 0x313, 0x300, 0x345, 0x0, 0x391, 0x313, 0x301, 0x0, 0x391, 0x313, 0x301, 0x345, 0x0, 0x391, 0x313, 0x342, 0x0, 0x391, 0x313, 0x342, 0x345, 0x0, 0x391, 0x313, 0x345, 0x0, 0x391, 0x314, 0x0, 0x391, 0x314, 0x300, 0x0, 0x391, 0x314, 0x300, 0x345, 0x0, 0x391, 0x314, 0x301, 0x0, 0x391, 0x314, 0x301, 0x345, 0x0, 0x391, 0x314, 0x342, 0x0, 0x391, 0x314, 0x342, 0x345, 0x0, 0x391, 0x314, 0x345, 0x0, 0x391, 0x345, 0x0, 0x395, 0x300, 0x0, 0x395, 0x301, 0x0, 0x395, 0x313, 0x0, 0x395, 0x313, 0x300, 0x0, 0x395, 0x313, 0x301, 0x0, 0x395, 0x314, 0x0, 0x395, 0x314, 0x300, 0x0, 0x395, 0x314, 0x301, 0x0, 0x397, 0x300, 0x0, 0x397, 0x301, 0x0, 0x397, 0x313, 0x0, 0x397, 0x313, 0x300, 0x0, 0x397, 0x313, 0x300, 0x345, 0x0, 0x397, 0x313, 0x301, 0x0, 0x397, 0x313, 0x301, 0x345, 0x0, 0x397, 0x313, 0x342, 0x0, 0x397, 0x313, 0x342, 0x345, 0x0, 0x397, 0x313, 0x345, 0x0, 0x397, 0x314, 0x0, 0x397, 0x314, 0x300, 0x0, 0x397, 0x314, 0x300, 0x345, 0x0, 0x397, 0x314, 0x301, 0x0, 0x397, 0x314, 0x301, 0x345, 0x0, 0x397, 0x314, 0x342, 0x0, 0x397, 0x314, 0x342, 0x345, 0x0, 0x397, 0x314, 0x345, 0x0, 0x397, 0x345, 0x0, 0x399, 0x300, 0x0, 0x399, 0x301, 0x0, 0x399, 0x304, 0x0, 0x399, 0x306, 0x0, 0x399, 0x308, 0x0, 0x399, 0x313, 0x0, 0x399, 0x313, 0x300, 0x0, 0x399, 0x313, 0x301, 0x0, 0x399, 0x313, 0x342, 0x0, 0x399, 0x314, 0x0, 0x399, 0x314, 0x300, 0x0, 0x399, 0x314, 0x301, 0x0, 0x399, 0x314, 0x342, 0x0, 0x39f, 0x300, 0x0, 0x39f, 0x301, 0x0, 0x39f, 0x313, 0x0, 0x39f, 0x313, 0x300, 0x0, 0x39f, 0x313, 0x301, 0x0, 0x39f, 0x314, 0x0, 0x39f, 0x314, 0x300, 0x0, 0x39f, 0x314, 0x301, 0x0, 0x3a1, 0x314, 0x0, 0x3a5, 0x300, 0x0, 0x3a5, 0x301, 0x0, 0x3a5, 0x304, 0x0, 0x3a5, 0x306, 0x0, 0x3a5, 0x308, 0x0, 0x3a5, 0x314, 0x0, 0x3a5, 0x314, 0x300, 0x0, 0x3a5, 0x314, 0x301, 0x0, 0x3a5, 0x314, 0x342, 0x0, 0x3a9, 0x0, 0x3a9, 0x300, 0x0, 0x3a9, 0x301, 0x0, 0x3a9, 0x313, 0x0, 0x3a9, 0x313, 0x300, 0x0, 0x3a9, 0x313, 0x300, 0x345, 0x0, 0x3a9, 0x313, 0x301, 0x0, 0x3a9, 0x313, 0x301, 0x345, 0x0, 0x3a9, 0x313, 0x342, 0x0, 0x3a9, 0x313, 0x342, 0x345, 0x0, 0x3a9, 0x313, 0x345, 0x0, 0x3a9, 0x314, 0x0, 0x3a9, 0x314, 0x300, 0x0, 0x3a9, 0x314, 0x300, 0x345, 0x0, 0x3a9, 0x314, 0x301, 0x0, 0x3a9, 0x314, 0x301, 0x345, 0x0, 0x3a9, 0x314, 0x342, 0x0, 0x3a9, 0x314, 0x342, 0x345, 0x0, 0x3a9, 0x314, 0x345, 0x0, 0x3a9, 0x345, 0x0, 0x3b1, 0x300, 0x0, 0x3b1, 0x300, 0x345, 0x0, 0x3b1, 0x301, 0x0, 0x3b1, 0x301, 0x345, 0x0, 0x3b1, 0x304, 0x0, 0x3b1, 0x306, 0x0, 0x3b1, 0x313, 0x0, 0x3b1, 0x313, 0x300, 0x0, 0x3b1, 0x313, 0x300, 0x345, 0x0, 0x3b1, 0x313, 0x301, 0x0, 0x3b1, 0x313, 0x301, 0x345, 0x0, 0x3b1, 0x313, 0x342, 0x0, 0x3b1, 0x313, 0x342, 0x345, 0x0, 0x3b1, 0x313, 0x345, 0x0, 0x3b1, 0x314, 0x0, 0x3b1, 0x314, 0x300, 0x0, 0x3b1, 0x314, 0x300, 0x345, 0x0, 0x3b1, 0x314, 0x301, 0x0, 0x3b1, 0x314, 0x301, 0x345, 0x0, 0x3b1, 0x314, 0x342, 0x0, 0x3b1, 0x314, 0x342, 0x345, 0x0, 0x3b1, 0x314, 0x345, 0x0, 0x3b1, 0x342, 0x0, 0x3b1, 0x342, 0x345, 0x0, 0x3b1, 0x345, 0x0, 0x3b5, 0x300, 0x0, 0x3b5, 0x301, 0x0, 0x3b5, 0x313, 0x0, 0x3b5, 0x313, 0x300, 0x0, 0x3b5, 0x313, 0x301, 0x0, 0x3b5, 0x314, 0x0, 0x3b5, 0x314, 0x300, 0x0, 0x3b5, 0x314, 0x301, 0x0, 0x3b7, 0x300, 0x0, 0x3b7, 0x300, 0x345, 0x0, 0x3b7, 0x301, 0x0, 0x3b7, 0x301, 0x345, 0x0, 0x3b7, 0x313, 0x0, 0x3b7, 0x313, 0x300, 0x0, 0x3b7, 0x313, 0x300, 0x345, 0x0, 0x3b7, 0x313, 0x301, 0x0, 0x3b7, 0x313, 0x301, 0x345, 0x0, 0x3b7, 0x313, 0x342, 0x0, 0x3b7, 0x313, 0x342, 0x345, 0x0, 0x3b7, 0x313, 0x345, 0x0, 0x3b7, 0x314, 0x0, 0x3b7, 0x314, 0x300, 0x0, 0x3b7, 0x314, 0x300, 0x345, 0x0, 0x3b7, 0x314, 0x301, 0x0, 0x3b7, 0x314, 0x301, 0x345, 0x0, 0x3b7, 0x314, 0x342, 0x0, 0x3b7, 0x314, 0x342, 0x345, 0x0, 0x3b7, 0x314, 0x345, 0x0, 0x3b7, 0x342, 0x0, 0x3b7, 0x342, 0x345, 0x0, 0x3b7, 0x345, 0x0, 0x3b9, 0x0, 0x3b9, 0x300, 0x0, 0x3b9, 0x301, 0x0, 0x3b9, 0x304, 0x0, 0x3b9, 0x306, 0x0, 0x3b9, 0x308, 0x0, 0x3b9, 0x308, 0x300, 0x0, 0x3b9, 0x308, 0x301, 0x0, 0x3b9, 0x308, 0x342, 0x0, 0x3b9, 0x313, 0x0, 0x3b9, 0x313, 0x300, 0x0, 0x3b9, 0x313, 0x301, 0x0, 0x3b9, 0x313, 0x342, 0x0, 0x3b9, 0x314, 0x0, 0x3b9, 0x314, 0x300, 0x0, 0x3b9, 0x314, 0x301, 0x0, 0x3b9, 0x314, 0x342, 0x0, 0x3b9, 0x342, 0x0, 0x3bf, 0x300, 0x0, 0x3bf, 0x301, 0x0, 0x3bf, 0x313, 0x0, 0x3bf, 0x313, 0x300, 0x0, 0x3bf, 0x313, 0x301, 0x0, 0x3bf, 0x314, 0x0, 0x3bf, 0x314, 0x300, 0x0, 0x3bf, 0x314, 0x301, 0x0, 0x3c1, 0x313, 0x0, 0x3c1, 0x314, 0x0, 0x3c5, 0x300, 0x0, 0x3c5, 0x301, 0x0, 0x3c5, 0x304, 0x0, 0x3c5, 0x306, 0x0, 0x3c5, 0x308, 0x0, 0x3c5, 0x308, 0x300, 0x0, 0x3c5, 0x308, 0x301, 0x0, 0x3c5, 0x308, 0x342, 0x0, 0x3c5, 0x313, 0x0, 0x3c5, 0x313, 0x300, 0x0, 0x3c5, 0x313, 0x301, 0x0, 0x3c5, 0x313, 0x342, 0x0, 0x3c5, 0x314, 0x0, 0x3c5, 0x314, 0x300, 0x0, 0x3c5, 0x314, 0x301, 0x0, 0x3c5, 0x314, 0x342, 0x0, 0x3c5, 0x342, 0x0, 0x3c9, 0x300, 0x0, 0x3c9, 0x300, 0x345, 0x0, 0x3c9, 0x301, 0x0, 0x3c9, 0x301, 0x345, 0x0, 0x3c9, 0x313, 0x0, 0x3c9, 0x313, 0x300, 0x0, 0x3c9, 0x313, 0x300, 0x345, 0x0, 0x3c9, 0x313, 0x301, 0x0, 0x3c9, 0x313, 0x301, 0x345, 0x0, 0x3c9, 0x313, 0x342, 0x0, 0x3c9, 0x313, 0x342, 0x345, 0x0, 0x3c9, 0x313, 0x345, 0x0, 0x3c9, 0x314, 0x0, 0x3c9, 0x314, 0x300, 0x0, 0x3c9, 0x314, 0x300, 0x345, 0x0, 0x3c9, 0x314, 0x301, 0x0, 0x3c9, 0x314, 0x301, 0x345, 0x0, 0x3c9, 0x314, 0x342, 0x0, 0x3c9, 0x314, 0x342, 0x345, 0x0, 0x3c9, 0x314, 0x345, 0x0, 0x3c9, 0x342, 0x0, 0x3c9, 0x342, 0x345, 0x0, 0x3c9, 0x345, 0x0, 0x3d2, 0x301, 0x0, 0x3d2, 0x308, 0x0, 0x406, 0x308, 0x0, 0x410, 0x306, 0x0, 0x410, 0x308, 0x0, 0x413, 0x301, 0x0, 0x415, 0x300, 0x0, 0x415, 0x306, 0x0, 0x415, 0x308, 0x0, 0x416, 0x306, 0x0, 0x416, 0x308, 0x0, 0x417, 0x308, 0x0, 0x418, 0x300, 0x0, 0x418, 0x304, 0x0, 0x418, 0x306, 0x0, 0x418, 0x308, 0x0, 0x41a, 0x301, 0x0, 0x41e, 0x308, 0x0, 0x423, 0x304, 0x0, 0x423, 0x306, 0x0, 0x423, 0x308, 0x0, 0x423, 0x30b, 0x0, 0x427, 0x308, 0x0, 0x42b, 0x308, 0x0, 0x42d, 0x308, 0x0, 0x430, 0x306, 0x0, 0x430, 0x308, 0x0, 0x433, 0x301, 0x0, 0x435, 0x300, 0x0, 0x435, 0x306, 0x0, 0x435, 0x308, 0x0, 0x436, 0x306, 0x0, 0x436, 0x308, 0x0, 0x437, 0x308, 0x0, 0x438, 0x300, 0x0, 0x438, 0x304, 0x0, 0x438, 0x306, 0x0, 0x438, 0x308, 0x0, 0x43a, 0x301, 0x0, 0x43e, 0x308, 0x0, 0x443, 0x304, 0x0, 0x443, 0x306, 0x0, 0x443, 0x308, 0x0, 0x443, 0x30b, 0x0, 0x447, 0x308, 0x0, 0x44b, 0x308, 0x0, 0x44d, 0x308, 0x0, 0x456, 0x308, 0x0, 0x474, 0x30f, 0x0, 0x475, 0x30f, 0x0, 0x4d8, 0x308, 0x0, 0x4d9, 0x308, 0x0, 0x4e8, 0x308, 0x0, 0x4e9, 0x308, 0x0, 0x5d0, 0x5b7, 0x0, 0x5d0, 0x5b8, 0x0, 0x5d0, 0x5bc, 0x0, 0x5d1, 0x5bc, 0x0, 0x5d1, 0x5bf, 0x0, 0x5d2, 0x5bc, 0x0, 0x5d3, 0x5bc, 0x0, 0x5d4, 0x5bc, 0x0, 0x5d5, 0x5b9, 0x0, 0x5d5, 0x5bc, 0x0, 0x5d6, 0x5bc, 0x0, 0x5d8, 0x5bc, 0x0, 0x5d9, 0x5b4, 0x0, 0x5d9, 0x5bc, 0x0, 0x5da, 0x5bc, 0x0, 0x5db, 0x5bc, 0x0, 0x5db, 0x5bf, 0x0, 0x5dc, 0x5bc, 0x0, 0x5de, 0x5bc, 0x0, 0x5e0, 0x5bc, 0x0, 0x5e1, 0x5bc, 0x0, 0x5e3, 0x5bc, 0x0, 0x5e4, 0x5bc, 0x0, 0x5e4, 0x5bf, 0x0, 0x5e6, 0x5bc, 0x0, 0x5e7, 0x5bc, 0x0, 0x5e8, 0x5bc, 0x0, 0x5e9, 0x5bc, 0x0, 0x5e9, 0x5bc, 0x5c1, 0x0, 0x5e9, 0x5bc, 0x5c2, 0x0, 0x5e9, 0x5c1, 0x0, 0x5e9, 0x5c2, 0x0, 0x5ea, 0x5bc, 0x0, 0x5f2, 0x5b7, 0x0, 0x627, 0x653, 0x0, 0x627, 0x654, 0x0, 0x627, 0x655, 0x0, 0x648, 0x654, 0x0, 0x64a, 0x654, 0x0, 0x6c1, 0x654, 0x0, 0x6d2, 0x654, 0x0, 0x6d5, 0x654, 0x0, 0x915, 0x93c, 0x0, 0x916, 0x93c, 0x0, 0x917, 0x93c, 0x0, 0x91c, 0x93c, 0x0, 0x921, 0x93c, 0x0, 0x922, 0x93c, 0x0, 0x928, 0x93c, 0x0, 0x92b, 0x93c, 0x0, 0x92f, 0x93c, 0x0, 0x930, 0x93c, 0x0, 0x933, 0x93c, 0x0, 0x9a1, 0x9bc, 0x0, 0x9a2, 0x9bc, 0x0, 0x9af, 0x9bc, 0x0, 0x9c7, 0x9be, 0x0, 0x9c7, 0x9d7, 0x0, 0xa16, 0xa3c, 0x0, 0xa17, 0xa3c, 0x0, 0xa1c, 0xa3c, 0x0, 0xa2b, 0xa3c, 0x0, 0xa32, 0xa3c, 0x0, 0xa38, 0xa3c, 0x0, 0xb21, 0xb3c, 0x0, 0xb22, 0xb3c, 0x0, 0xb47, 0xb3e, 0x0, 0xb47, 0xb56, 0x0, 0xb47, 0xb57, 0x0, 0xb92, 0xbd7, 0x0, 0xbc6, 0xbbe, 0x0, 0xbc6, 0xbd7, 0x0, 0xbc7, 0xbbe, 0x0, 0xc46, 0xc56, 0x0, 0xcbf, 0xcd5, 0x0, 0xcc6, 0xcc2, 0x0, 0xcc6, 0xcc2, 0xcd5, 0x0, 0xcc6, 0xcd5, 0x0, 0xcc6, 0xcd6, 0x0, 0xd46, 0xd3e, 0x0, 0xd46, 0xd57, 0x0, 0xd47, 0xd3e, 0x0, 0xdd9, 0xdca, 0x0, 0xdd9, 0xdcf, 0x0, 0xdd9, 0xdcf, 0xdca, 0x0, 0xdd9, 0xddf, 0x0, 0xf40, 0xfb5, 0x0, 0xf42, 0xfb7, 0x0, 0xf4c, 0xfb7, 0x0, 0xf51, 0xfb7, 0x0, 0xf56, 0xfb7, 0x0, 0xf5b, 0xfb7, 0x0, 0xf71, 0xf72, 0x0, 0xf71, 0xf74, 0x0, 0xf71, 0xf80, 0x0, 0xf90, 0xfb5, 0x0, 0xf92, 0xfb7, 0x0, 0xf9c, 0xfb7, 0x0, 0xfa1, 0xfb7, 0x0, 0xfa6, 0xfb7, 0x0, 0xfab, 0xfb7, 0x0, 0xfb2, 0xf80, 0x0, 0xfb3, 0xf80, 0x0, 0x1025, 0x102e, 0x0, 0x1b05, 0x1b35, 0x0, 0x1b07, 0x1b35, 0x0, 0x1b09, 0x1b35, 0x0, 0x1b0b, 0x1b35, 0x0, 0x1b0d, 0x1b35, 0x0, 0x1b11, 0x1b35, 0x0, 0x1b3a, 0x1b35, 0x0, 0x1b3c, 0x1b35, 0x0, 0x1b3e, 0x1b35, 0x0, 0x1b3f, 0x1b35, 0x0, 0x1b42, 0x1b35, 0x0, 0x1fbf, 0x300, 0x0, 0x1fbf, 0x301, 0x0, 0x1fbf, 0x342, 0x0, 0x1ffe, 0x300, 0x0, 0x1ffe, 0x301, 0x0, 0x1ffe, 0x342, 0x0, 0x2002, 0x0, 0x2003, 0x0, 0x2190, 0x338, 0x0, 0x2192, 0x338, 0x0, 0x2194, 0x338, 0x0, 0x21d0, 0x338, 0x0, 0x21d2, 0x338, 0x0, 0x21d4, 0x338, 0x0, 0x2203, 0x338, 0x0, 0x2208, 0x338, 0x0, 0x220b, 0x338, 0x0, 0x2223, 0x338, 0x0, 0x2225, 0x338, 0x0, 0x223c, 0x338, 0x0, 0x2243, 0x338, 0x0, 0x2245, 0x338, 0x0, 0x2248, 0x338, 0x0, 0x224d, 0x338, 0x0, 0x2261, 0x338, 0x0, 0x2264, 0x338, 0x0, 0x2265, 0x338, 0x0, 0x2272, 0x338, 0x0, 0x2273, 0x338, 0x0, 0x2276, 0x338, 0x0, 0x2277, 0x338, 0x0, 0x227a, 0x338, 0x0, 0x227b, 0x338, 0x0, 0x227c, 0x338, 0x0, 0x227d, 0x338, 0x0, 0x2282, 0x338, 0x0, 0x2283, 0x338, 0x0, 0x2286, 0x338, 0x0, 0x2287, 0x338, 0x0, 0x2291, 0x338, 0x0, 0x2292, 0x338, 0x0, 0x22a2, 0x338, 0x0, 0x22a8, 0x338, 0x0, 0x22a9, 0x338, 0x0, 0x22ab, 0x338, 0x0, 0x22b2, 0x338, 0x0, 0x22b3, 0x338, 0x0, 0x22b4, 0x338, 0x0, 0x22b5, 0x338, 0x0, 0x2add, 0x338, 0x0, 0x3008, 0x0, 0x3009, 0x0, 0x3046, 0x3099, 0x0, 0x304b, 0x3099, 0x0, 0x304d, 0x3099, 0x0, 0x304f, 0x3099, 0x0, 0x3051, 0x3099, 0x0, 0x3053, 0x3099, 0x0, 0x3055, 0x3099, 0x0, 0x3057, 0x3099, 0x0, 0x3059, 0x3099, 0x0, 0x305b, 0x3099, 0x0, 0x305d, 0x3099, 0x0, 0x305f, 0x3099, 0x0, 0x3061, 0x3099, 0x0, 0x3064, 0x3099, 0x0, 0x3066, 0x3099, 0x0, 0x3068, 0x3099, 0x0, 0x306f, 0x3099, 0x0, 0x306f, 0x309a, 0x0, 0x3072, 0x3099, 0x0, 0x3072, 0x309a, 0x0, 0x3075, 0x3099, 0x0, 0x3075, 0x309a, 0x0, 0x3078, 0x3099, 0x0, 0x3078, 0x309a, 0x0, 0x307b, 0x3099, 0x0, 0x307b, 0x309a, 0x0, 0x309d, 0x3099, 0x0, 0x30a6, 0x3099, 0x0, 0x30ab, 0x3099, 0x0, 0x30ad, 0x3099, 0x0, 0x30af, 0x3099, 0x0, 0x30b1, 0x3099, 0x0, 0x30b3, 0x3099, 0x0, 0x30b5, 0x3099, 0x0, 0x30b7, 0x3099, 0x0, 0x30b9, 0x3099, 0x0, 0x30bb, 0x3099, 0x0, 0x30bd, 0x3099, 0x0, 0x30bf, 0x3099, 0x0, 0x30c1, 0x3099, 0x0, 0x30c4, 0x3099, 0x0, 0x30c6, 0x3099, 0x0, 0x30c8, 0x3099, 0x0, 0x30cf, 0x3099, 0x0, 0x30cf, 0x309a, 0x0, 0x30d2, 0x3099, 0x0, 0x30d2, 0x309a, 0x0, 0x30d5, 0x3099, 0x0, 0x30d5, 0x309a, 0x0, 0x30d8, 0x3099, 0x0, 0x30d8, 0x309a, 0x0, 0x30db, 0x3099, 0x0, 0x30db, 0x309a, 0x0, 0x30ef, 0x3099, 0x0, 0x30f0, 0x3099, 0x0, 0x30f1, 0x3099, 0x0, 0x30f2, 0x3099, 0x0, 0x30fd, 0x3099, 0x0, 0x349e, 0x0, 0x34b9, 0x0, 0x34bb, 0x0, 0x34df, 0x0, 0x3515, 0x0, 0x36ee, 0x0, 0x36fc, 0x0, 0x3781, 0x0, 0x382f, 0x0, 0x3862, 0x0, 0x387c, 0x0, 0x38c7, 0x0, 0x38e3, 0x0, 0x391c, 0x0, 0x393a, 0x0, 0x3a2e, 0x0, 0x3a6c, 0x0, 0x3ae4, 0x0, 0x3b08, 0x0, 0x3b19, 0x0, 0x3b49, 0x0, 0x3b9d, 0x0, 0x3c18, 0x0, 0x3c4e, 0x0, 0x3d33, 0x0, 0x3d96, 0x0, 0x3eac, 0x0, 0x3eb8, 0x0, 0x3f1b, 0x0, 0x3ffc, 0x0, 0x4008, 0x0, 0x4018, 0x0, 0x4039, 0x0, 0x4046, 0x0, 0x4096, 0x0, 0x40e3, 0x0, 0x412f, 0x0, 0x4202, 0x0, 0x4227, 0x0, 0x42a0, 0x0, 0x4301, 0x0, 0x4334, 0x0, 0x4359, 0x0, 0x43d5, 0x0, 0x43d9, 0x0, 0x440b, 0x0, 0x446b, 0x0, 0x452b, 0x0, 0x455d, 0x0, 0x4561, 0x0, 0x456b, 0x0, 0x45d7, 0x0, 0x45f9, 0x0, 0x4635, 0x0, 0x46be, 0x0, 0x46c7, 0x0, 0x4995, 0x0, 0x49e6, 0x0, 0x4a6e, 0x0, 0x4a76, 0x0, 0x4ab2, 0x0, 0x4b33, 0x0, 0x4bce, 0x0, 0x4cce, 0x0, 0x4ced, 0x0, 0x4cf8, 0x0, 0x4d56, 0x0, 0x4e0d, 0x0, 0x4e26, 0x0, 0x4e32, 0x0, 0x4e38, 0x0, 0x4e39, 0x0, 0x4e3d, 0x0, 0x4e41, 0x0, 0x4e82, 0x0, 0x4e86, 0x0, 0x4eae, 0x0, 0x4ec0, 0x0, 0x4ecc, 0x0, 0x4ee4, 0x0, 0x4f60, 0x0, 0x4f80, 0x0, 0x4f86, 0x0, 0x4f8b, 0x0, 0x4fae, 0x0, 0x4fbb, 0x0, 0x4fbf, 0x0, 0x5002, 0x0, 0x502b, 0x0, 0x507a, 0x0, 0x5099, 0x0, 0x50cf, 0x0, 0x50da, 0x0, 0x50e7, 0x0, 0x5140, 0x0, 0x5145, 0x0, 0x514d, 0x0, 0x5154, 0x0, 0x5164, 0x0, 0x5167, 0x0, 0x5168, 0x0, 0x5169, 0x0, 0x516d, 0x0, 0x5177, 0x0, 0x5180, 0x0, 0x518d, 0x0, 0x5192, 0x0, 0x5195, 0x0, 0x5197, 0x0, 0x51a4, 0x0, 0x51ac, 0x0, 0x51b5, 0x0, 0x51b7, 0x0, 0x51c9, 0x0, 0x51cc, 0x0, 0x51dc, 0x0, 0x51de, 0x0, 0x51f5, 0x0, 0x5203, 0x0, 0x5207, 0x0, 0x5217, 0x0, 0x5229, 0x0, 0x523a, 0x0, 0x523b, 0x0, 0x5246, 0x0, 0x5272, 0x0, 0x5277, 0x0, 0x5289, 0x0, 0x529b, 0x0, 0x52a3, 0x0, 0x52b3, 0x0, 0x52c7, 0x0, 0x52c9, 0x0, 0x52d2, 0x0, 0x52de, 0x0, 0x52e4, 0x0, 0x52f5, 0x0, 0x52fa, 0x0, 0x5305, 0x0, 0x5306, 0x0, 0x5317, 0x0, 0x533f, 0x0, 0x5349, 0x0, 0x5351, 0x0, 0x535a, 0x0, 0x5373, 0x0, 0x5375, 0x0, 0x537d, 0x0, 0x537f, 0x0, 0x53c3, 0x0, 0x53ca, 0x0, 0x53df, 0x0, 0x53e5, 0x0, 0x53eb, 0x0, 0x53f1, 0x0, 0x5406, 0x0, 0x540f, 0x0, 0x541d, 0x0, 0x5438, 0x0, 0x5442, 0x0, 0x5448, 0x0, 0x5468, 0x0, 0x549e, 0x0, 0x54a2, 0x0, 0x54bd, 0x0, 0x54f6, 0x0, 0x5510, 0x0, 0x5553, 0x0, 0x5555, 0x0, 0x5563, 0x0, 0x5584, 0x0, 0x5587, 0x0, 0x5599, 0x0, 0x559d, 0x0, 0x55ab, 0x0, 0x55b3, 0x0, 0x55c0, 0x0, 0x55c2, 0x0, 0x55e2, 0x0, 0x5606, 0x0, 0x5651, 0x0, 0x5668, 0x0, 0x5674, 0x0, 0x56f9, 0x0, 0x5716, 0x0, 0x5717, 0x0, 0x578b, 0x0, 0x57ce, 0x0, 0x57f4, 0x0, 0x580d, 0x0, 0x5831, 0x0, 0x5832, 0x0, 0x5840, 0x0, 0x585a, 0x0, 0x585e, 0x0, 0x58a8, 0x0, 0x58ac, 0x0, 0x58b3, 0x0, 0x58d8, 0x0, 0x58df, 0x0, 0x58ee, 0x0, 0x58f2, 0x0, 0x58f7, 0x0, 0x5906, 0x0, 0x591a, 0x0, 0x5922, 0x0, 0x5944, 0x0, 0x5948, 0x0, 0x5951, 0x0, 0x5954, 0x0, 0x5962, 0x0, 0x5973, 0x0, 0x59d8, 0x0, 0x59ec, 0x0, 0x5a1b, 0x0, 0x5a27, 0x0, 0x5a62, 0x0, 0x5a66, 0x0, 0x5ab5, 0x0, 0x5b08, 0x0, 0x5b28, 0x0, 0x5b3e, 0x0, 0x5b85, 0x0, 0x5bc3, 0x0, 0x5bd8, 0x0, 0x5be7, 0x0, 0x5bee, 0x0, 0x5bf3, 0x0, 0x5bff, 0x0, 0x5c06, 0x0, 0x5c22, 0x0, 0x5c3f, 0x0, 0x5c60, 0x0, 0x5c62, 0x0, 0x5c64, 0x0, 0x5c65, 0x0, 0x5c6e, 0x0, 0x5c8d, 0x0, 0x5cc0, 0x0, 0x5d19, 0x0, 0x5d43, 0x0, 0x5d50, 0x0, 0x5d6b, 0x0, 0x5d6e, 0x0, 0x5d7c, 0x0, 0x5db2, 0x0, 0x5dba, 0x0, 0x5de1, 0x0, 0x5de2, 0x0, 0x5dfd, 0x0, 0x5e28, 0x0, 0x5e3d, 0x0, 0x5e69, 0x0, 0x5e74, 0x0, 0x5ea6, 0x0, 0x5eb0, 0x0, 0x5eb3, 0x0, 0x5eb6, 0x0, 0x5ec9, 0x0, 0x5eca, 0x0, 0x5ed2, 0x0, 0x5ed3, 0x0, 0x5ed9, 0x0, 0x5eec, 0x0, 0x5efe, 0x0, 0x5f04, 0x0, 0x5f22, 0x0, 0x5f53, 0x0, 0x5f62, 0x0, 0x5f69, 0x0, 0x5f6b, 0x0, 0x5f8b, 0x0, 0x5f9a, 0x0, 0x5fa9, 0x0, 0x5fad, 0x0, 0x5fcd, 0x0, 0x5fd7, 0x0, 0x5ff5, 0x0, 0x5ff9, 0x0, 0x6012, 0x0, 0x601c, 0x0, 0x6075, 0x0, 0x6081, 0x0, 0x6094, 0x0, 0x60c7, 0x0, 0x60d8, 0x0, 0x60e1, 0x0, 0x6108, 0x0, 0x6144, 0x0, 0x6148, 0x0, 0x614c, 0x0, 0x614e, 0x0, 0x6160, 0x0, 0x6168, 0x0, 0x617a, 0x0, 0x618e, 0x0, 0x6190, 0x0, 0x61a4, 0x0, 0x61af, 0x0, 0x61b2, 0x0, 0x61de, 0x0, 0x61f2, 0x0, 0x61f6, 0x0, 0x6200, 0x0, 0x6210, 0x0, 0x621b, 0x0, 0x622e, 0x0, 0x6234, 0x0, 0x625d, 0x0, 0x62b1, 0x0, 0x62c9, 0x0, 0x62cf, 0x0, 0x62d3, 0x0, 0x62d4, 0x0, 0x62fc, 0x0, 0x62fe, 0x0, 0x633d, 0x0, 0x6350, 0x0, 0x6368, 0x0, 0x637b, 0x0, 0x6383, 0x0, 0x63a0, 0x0, 0x63a9, 0x0, 0x63c4, 0x0, 0x63c5, 0x0, 0x63e4, 0x0, 0x641c, 0x0, 0x6422, 0x0, 0x6452, 0x0, 0x6469, 0x0, 0x6477, 0x0, 0x647e, 0x0, 0x649a, 0x0, 0x649d, 0x0, 0x64c4, 0x0, 0x654f, 0x0, 0x6556, 0x0, 0x656c, 0x0, 0x6578, 0x0, 0x6599, 0x0, 0x65c5, 0x0, 0x65e2, 0x0, 0x65e3, 0x0, 0x6613, 0x0, 0x6649, 0x0, 0x6674, 0x0, 0x6688, 0x0, 0x6691, 0x0, 0x669c, 0x0, 0x66b4, 0x0, 0x66c6, 0x0, 0x66f4, 0x0, 0x66f8, 0x0, 0x6700, 0x0, 0x6717, 0x0, 0x671b, 0x0, 0x6721, 0x0, 0x674e, 0x0, 0x6753, 0x0, 0x6756, 0x0, 0x675e, 0x0, 0x677b, 0x0, 0x6785, 0x0, 0x6797, 0x0, 0x67f3, 0x0, 0x67fa, 0x0, 0x6817, 0x0, 0x681f, 0x0, 0x6852, 0x0, 0x6881, 0x0, 0x6885, 0x0, 0x688e, 0x0, 0x68a8, 0x0, 0x6914, 0x0, 0x6942, 0x0, 0x69a3, 0x0, 0x69ea, 0x0, 0x6a02, 0x0, 0x6a13, 0x0, 0x6aa8, 0x0, 0x6ad3, 0x0, 0x6adb, 0x0, 0x6b04, 0x0, 0x6b21, 0x0, 0x6b54, 0x0, 0x6b72, 0x0, 0x6b77, 0x0, 0x6b79, 0x0, 0x6b9f, 0x0, 0x6bae, 0x0, 0x6bba, 0x0, 0x6bbb, 0x0, 0x6c4e, 0x0, 0x6c67, 0x0, 0x6c88, 0x0, 0x6cbf, 0x0, 0x6ccc, 0x0, 0x6ccd, 0x0, 0x6ce5, 0x0, 0x6d16, 0x0, 0x6d1b, 0x0, 0x6d1e, 0x0, 0x6d34, 0x0, 0x6d3e, 0x0, 0x6d41, 0x0, 0x6d69, 0x0, 0x6d6a, 0x0, 0x6d77, 0x0, 0x6d78, 0x0, 0x6d85, 0x0, 0x6dcb, 0x0, 0x6dda, 0x0, 0x6dea, 0x0, 0x6df9, 0x0, 0x6e1a, 0x0, 0x6e2f, 0x0, 0x6e6e, 0x0, 0x6e9c, 0x0, 0x6eba, 0x0, 0x6ec7, 0x0, 0x6ecb, 0x0, 0x6ed1, 0x0, 0x6edb, 0x0, 0x6f0f, 0x0, 0x6f22, 0x0, 0x6f23, 0x0, 0x6f6e, 0x0, 0x6fc6, 0x0, 0x6feb, 0x0, 0x6ffe, 0x0, 0x701b, 0x0, 0x701e, 0x0, 0x7039, 0x0, 0x704a, 0x0, 0x7070, 0x0, 0x7077, 0x0, 0x707d, 0x0, 0x7099, 0x0, 0x70ad, 0x0, 0x70c8, 0x0, 0x70d9, 0x0, 0x7145, 0x0, 0x7149, 0x0, 0x716e, 0x0, 0x719c, 0x0, 0x71ce, 0x0, 0x71d0, 0x0, 0x7210, 0x0, 0x721b, 0x0, 0x7228, 0x0, 0x722b, 0x0, 0x7235, 0x0, 0x7250, 0x0, 0x7262, 0x0, 0x7280, 0x0, 0x7295, 0x0, 0x72af, 0x0, 0x72c0, 0x0, 0x72fc, 0x0, 0x732a, 0x0, 0x7375, 0x0, 0x737a, 0x0, 0x7387, 0x0, 0x738b, 0x0, 0x73a5, 0x0, 0x73b2, 0x0, 0x73de, 0x0, 0x7406, 0x0, 0x7409, 0x0, 0x7422, 0x0, 0x7447, 0x0, 0x745c, 0x0, 0x7469, 0x0, 0x7471, 0x0, 0x7485, 0x0, 0x7489, 0x0, 0x7498, 0x0, 0x74ca, 0x0, 0x7506, 0x0, 0x7524, 0x0, 0x753b, 0x0, 0x753e, 0x0, 0x7559, 0x0, 0x7565, 0x0, 0x7570, 0x0, 0x75e2, 0x0, 0x7610, 0x0, 0x761d, 0x0, 0x761f, 0x0, 0x7642, 0x0, 0x7669, 0x0, 0x76ca, 0x0, 0x76db, 0x0, 0x76e7, 0x0, 0x76f4, 0x0, 0x7701, 0x0, 0x771e, 0x0, 0x771f, 0x0, 0x7740, 0x0, 0x774a, 0x0, 0x778b, 0x0, 0x77a7, 0x0, 0x784e, 0x0, 0x786b, 0x0, 0x788c, 0x0, 0x7891, 0x0, 0x78ca, 0x0, 0x78cc, 0x0, 0x78fb, 0x0, 0x792a, 0x0, 0x793c, 0x0, 0x793e, 0x0, 0x7948, 0x0, 0x7949, 0x0, 0x7950, 0x0, 0x7956, 0x0, 0x795d, 0x0, 0x795e, 0x0, 0x7965, 0x0, 0x797f, 0x0, 0x798d, 0x0, 0x798e, 0x0, 0x798f, 0x0, 0x79ae, 0x0, 0x79ca, 0x0, 0x79eb, 0x0, 0x7a1c, 0x0, 0x7a40, 0x0, 0x7a4a, 0x0, 0x7a4f, 0x0, 0x7a81, 0x0, 0x7ab1, 0x0, 0x7acb, 0x0, 0x7aee, 0x0, 0x7b20, 0x0, 0x7bc0, 0x0, 0x7bc6, 0x0, 0x7bc9, 0x0, 0x7c3e, 0x0, 0x7c60, 0x0, 0x7c7b, 0x0, 0x7c92, 0x0, 0x7cbe, 0x0, 0x7cd2, 0x0, 0x7cd6, 0x0, 0x7ce3, 0x0, 0x7ce7, 0x0, 0x7ce8, 0x0, 0x7d00, 0x0, 0x7d10, 0x0, 0x7d22, 0x0, 0x7d2f, 0x0, 0x7d5b, 0x0, 0x7d63, 0x0, 0x7da0, 0x0, 0x7dbe, 0x0, 0x7dc7, 0x0, 0x7df4, 0x0, 0x7e02, 0x0, 0x7e09, 0x0, 0x7e37, 0x0, 0x7e41, 0x0, 0x7e45, 0x0, 0x7f3e, 0x0, 0x7f72, 0x0, 0x7f79, 0x0, 0x7f7a, 0x0, 0x7f85, 0x0, 0x7f95, 0x0, 0x7f9a, 0x0, 0x7fbd, 0x0, 0x7ffa, 0x0, 0x8001, 0x0, 0x8005, 0x0, 0x8046, 0x0, 0x8060, 0x0, 0x806f, 0x0, 0x8070, 0x0, 0x807e, 0x0, 0x808b, 0x0, 0x80ad, 0x0, 0x80b2, 0x0, 0x8103, 0x0, 0x813e, 0x0, 0x81d8, 0x0, 0x81e8, 0x0, 0x81ed, 0x0, 0x8201, 0x0, 0x8204, 0x0, 0x8218, 0x0, 0x826f, 0x0, 0x8279, 0x0, 0x828b, 0x0, 0x8291, 0x0, 0x829d, 0x0, 0x82b1, 0x0, 0x82b3, 0x0, 0x82bd, 0x0, 0x82e5, 0x0, 0x82e6, 0x0, 0x831d, 0x0, 0x8323, 0x0, 0x8336, 0x0, 0x8352, 0x0, 0x8353, 0x0, 0x8363, 0x0, 0x83ad, 0x0, 0x83bd, 0x0, 0x83c9, 0x0, 0x83ca, 0x0, 0x83cc, 0x0, 0x83dc, 0x0, 0x83e7, 0x0, 0x83ef, 0x0, 0x83f1, 0x0, 0x843d, 0x0, 0x8449, 0x0, 0x8457, 0x0, 0x84ee, 0x0, 0x84f1, 0x0, 0x84f3, 0x0, 0x84fc, 0x0, 0x8516, 0x0, 0x8564, 0x0, 0x85cd, 0x0, 0x85fa, 0x0, 0x8606, 0x0, 0x8612, 0x0, 0x862d, 0x0, 0x863f, 0x0, 0x8650, 0x0, 0x865c, 0x0, 0x8667, 0x0, 0x8669, 0x0, 0x8688, 0x0, 0x86a9, 0x0, 0x86e2, 0x0, 0x870e, 0x0, 0x8728, 0x0, 0x876b, 0x0, 0x8779, 0x0, 0x8786, 0x0, 0x87ba, 0x0, 0x87e1, 0x0, 0x8801, 0x0, 0x881f, 0x0, 0x884c, 0x0, 0x8860, 0x0, 0x8863, 0x0, 0x88c2, 0x0, 0x88cf, 0x0, 0x88d7, 0x0, 0x88de, 0x0, 0x88e1, 0x0, 0x88f8, 0x0, 0x88fa, 0x0, 0x8910, 0x0, 0x8941, 0x0, 0x8964, 0x0, 0x8986, 0x0, 0x898b, 0x0, 0x8996, 0x0, 0x8aa0, 0x0, 0x8aaa, 0x0, 0x8abf, 0x0, 0x8acb, 0x0, 0x8ad2, 0x0, 0x8ad6, 0x0, 0x8aed, 0x0, 0x8af8, 0x0, 0x8afe, 0x0, 0x8b01, 0x0, 0x8b39, 0x0, 0x8b58, 0x0, 0x8b80, 0x0, 0x8b8a, 0x0, 0x8c48, 0x0, 0x8c55, 0x0, 0x8cab, 0x0, 0x8cc1, 0x0, 0x8cc2, 0x0, 0x8cc8, 0x0, 0x8cd3, 0x0, 0x8d08, 0x0, 0x8d1b, 0x0, 0x8d77, 0x0, 0x8dbc, 0x0, 0x8dcb, 0x0, 0x8def, 0x0, 0x8df0, 0x0, 0x8eca, 0x0, 0x8ed4, 0x0, 0x8f26, 0x0, 0x8f2a, 0x0, 0x8f38, 0x0, 0x8f3b, 0x0, 0x8f62, 0x0, 0x8f9e, 0x0, 0x8fb0, 0x0, 0x8fb6, 0x0, 0x9023, 0x0, 0x9038, 0x0, 0x9072, 0x0, 0x907c, 0x0, 0x908f, 0x0, 0x9094, 0x0, 0x90ce, 0x0, 0x90de, 0x0, 0x90f1, 0x0, 0x90fd, 0x0, 0x9111, 0x0, 0x911b, 0x0, 0x916a, 0x0, 0x9199, 0x0, 0x91b4, 0x0, 0x91cc, 0x0, 0x91cf, 0x0, 0x91d1, 0x0, 0x9234, 0x0, 0x9238, 0x0, 0x9276, 0x0, 0x927c, 0x0, 0x92d7, 0x0, 0x92d8, 0x0, 0x9304, 0x0, 0x934a, 0x0, 0x93f9, 0x0, 0x9415, 0x0, 0x958b, 0x0, 0x95ad, 0x0, 0x95b7, 0x0, 0x962e, 0x0, 0x964b, 0x0, 0x964d, 0x0, 0x9675, 0x0, 0x9678, 0x0, 0x967c, 0x0, 0x9686, 0x0, 0x96a3, 0x0, 0x96b7, 0x0, 0x96b8, 0x0, 0x96c3, 0x0, 0x96e2, 0x0, 0x96e3, 0x0, 0x96f6, 0x0, 0x96f7, 0x0, 0x9723, 0x0, 0x9732, 0x0, 0x9748, 0x0, 0x9756, 0x0, 0x97db, 0x0, 0x97e0, 0x0, 0x97ff, 0x0, 0x980b, 0x0, 0x9818, 0x0, 0x9829, 0x0, 0x983b, 0x0, 0x985e, 0x0, 0x98e2, 0x0, 0x98ef, 0x0, 0x98fc, 0x0, 0x9928, 0x0, 0x9929, 0x0, 0x99a7, 0x0, 0x99c2, 0x0, 0x99f1, 0x0, 0x99fe, 0x0, 0x9a6a, 0x0, 0x9b12, 0x0, 0x9b6f, 0x0, 0x9c40, 0x0, 0x9c57, 0x0, 0x9cfd, 0x0, 0x9d67, 0x0, 0x9db4, 0x0, 0x9dfa, 0x0, 0x9e1e, 0x0, 0x9e7f, 0x0, 0x9e97, 0x0, 0x9e9f, 0x0, 0x9ebb, 0x0, 0x9ece, 0x0, 0x9ef9, 0x0, 0x9efe, 0x0, 0x9f05, 0x0, 0x9f0f, 0x0, 0x9f16, 0x0, 0x9f3b, 0x0, 0x9f43, 0x0, 0x9f8d, 0x0, 0x9f8e, 0x0, 0x9f9c, 0x0, 0x11099, 0x110ba, 0x0, 0x1109b, 0x110ba, 0x0, 0x110a5, 0x110ba, 0x0, 0x11131, 0x11127, 0x0, 0x11132, 0x11127, 0x0, 0x1d157, 0x1d165, 0x0, 0x1d158, 0x1d165, 0x0, 0x1d158, 0x1d165, 0x1d16e, 0x0, 0x1d158, 0x1d165, 0x1d16f, 0x0, 0x1d158, 0x1d165, 0x1d170, 0x0, 0x1d158, 0x1d165, 0x1d171, 0x0, 0x1d158, 0x1d165, 0x1d172, 0x0, 0x1d1b9, 0x1d165, 0x0, 0x1d1b9, 0x1d165, 0x1d16e, 0x0, 0x1d1b9, 0x1d165, 0x1d16f, 0x0, 0x1d1ba, 0x1d165, 0x0, 0x1d1ba, 0x1d165, 0x1d16e, 0x0, 0x1d1ba, 0x1d165, 0x1d16f, 0x0, 0x20122, 0x0, 0x2051c, 0x0, 0x20525, 0x0, 0x2054b, 0x0, 0x2063a, 0x0, 0x20804, 0x0, 0x208de, 0x0, 0x20a2c, 0x0, 0x20b63, 0x0, 0x214e4, 0x0, 0x216a8, 0x0, 0x216ea, 0x0, 0x219c8, 0x0, 0x21b18, 0x0, 0x21d0b, 0x0, 0x21de4, 0x0, 0x21de6, 0x0, 0x22183, 0x0, 0x2219f, 0x0, 0x22331, 0x0, 0x226d4, 0x0, 0x22844, 0x0, 0x2284a, 0x0, 0x22b0c, 0x0, 0x22bf1, 0x0, 0x2300a, 0x0, 0x232b8, 0x0, 0x2335f, 0x0, 0x23393, 0x0, 0x2339c, 0x0, 0x233c3, 0x0, 0x233d5, 0x0, 0x2346d, 0x0, 0x236a3, 0x0, 0x238a7, 0x0, 0x23a8d, 0x0, 0x23afa, 0x0, 0x23cbc, 0x0, 0x23d1e, 0x0, 0x23ed1, 0x0, 0x23f5e, 0x0, 0x23f8e, 0x0, 0x24263, 0x0, 0x242ee, 0x0, 0x243ab, 0x0, 0x24608, 0x0, 0x24735, 0x0, 0x24814, 0x0, 0x24c36, 0x0, 0x24c92, 0x0, 0x24fa1, 0x0, 0x24fb8, 0x0, 0x25044, 0x0, 0x250f2, 0x0, 0x250f3, 0x0, 0x25119, 0x0, 0x25133, 0x0, 0x25249, 0x0, 0x2541d, 0x0, 0x25626, 0x0, 0x2569a, 0x0, 0x256c5, 0x0, 0x2597c, 0x0, 0x25aa7, 0x0, 0x25bab, 0x0, 0x25c80, 0x0, 0x25cd0, 0x0, 0x25f86, 0x0, 0x261da, 0x0, 0x26228, 0x0, 0x26247, 0x0, 0x262d9, 0x0, 0x2633e, 0x0, 0x264da, 0x0, 0x26523, 0x0, 0x265a8, 0x0, 0x267a7, 0x0, 0x267b5, 0x0, 0x26b3c, 0x0, 0x26c36, 0x0, 0x26cd5, 0x0, 0x26d6b, 0x0, 0x26f2c, 0x0, 0x26fb1, 0x0, 0x270d2, 0x0, 0x273ca, 0x0, 0x27667, 0x0, 0x278ae, 0x0, 0x27966, 0x0, 0x27ca8, 0x0, 0x27ed3, 0x0, 0x27f2f, 0x0, 0x285d2, 0x0, 0x285ed, 0x0, 0x2872e, 0x0, 0x28bfa, 0x0, 0x28d77, 0x0, 0x29145, 0x0, 0x291df, 0x0, 0x2921a, 0x0, 0x2940a, 0x0, 0x29496, 0x0, 0x295b6, 0x0, 0x29b30, 0x0, 0x2a0ce, 0x0, 0x2a105, 0x0, 0x2a20e, 0x0, 0x2a291, 0x0, 0x2a392, 0x0, 0x2a600, 0x0]; return t; } _IDCA decompCompatTable() { static _IDCA t = [ 0x0, 0x20, 0x0, 0x20, 0x301, 0x0, 0x20, 0x303, 0x0, 0x20, 0x304, 0x0, 0x20, 0x305, 0x0, 0x20, 0x306, 0x0, 0x20, 0x307, 0x0, 0x20, 0x308, 0x0, 0x20, 0x308, 0x300, 0x0, 0x20, 0x308, 0x301, 0x0, 0x20, 0x308, 0x342, 0x0, 0x20, 0x30a, 0x0, 0x20, 0x30b, 0x0, 0x20, 0x313, 0x0, 0x20, 0x313, 0x300, 0x0, 0x20, 0x313, 0x301, 0x0, 0x20, 0x313, 0x342, 0x0, 0x20, 0x314, 0x0, 0x20, 0x314, 0x300, 0x0, 0x20, 0x314, 0x301, 0x0, 0x20, 0x314, 0x342, 0x0, 0x20, 0x327, 0x0, 0x20, 0x328, 0x0, 0x20, 0x333, 0x0, 0x20, 0x342, 0x0, 0x20, 0x345, 0x0, 0x20, 0x64b, 0x0, 0x20, 0x64c, 0x0, 0x20, 0x64c, 0x651, 0x0, 0x20, 0x64d, 0x0, 0x20, 0x64d, 0x651, 0x0, 0x20, 0x64e, 0x0, 0x20, 0x64e, 0x651, 0x0, 0x20, 0x64f, 0x0, 0x20, 0x64f, 0x651, 0x0, 0x20, 0x650, 0x0, 0x20, 0x650, 0x651, 0x0, 0x20, 0x651, 0x0, 0x20, 0x651, 0x670, 0x0, 0x20, 0x652, 0x0, 0x20, 0x3099, 0x0, 0x20, 0x309a, 0x0, 0x21, 0x0, 0x21, 0x21, 0x0, 0x21, 0x3f, 0x0, 0x22, 0x0, 0x23, 0x0, 0x24, 0x0, 0x25, 0x0, 0x26, 0x0, 0x27, 0x0, 0x28, 0x0, 0x28, 0x31, 0x29, 0x0, 0x28, 0x31, 0x30, 0x29, 0x0, 0x28, 0x31, 0x31, 0x29, 0x0, 0x28, 0x31, 0x32, 0x29, 0x0, 0x28, 0x31, 0x33, 0x29, 0x0, 0x28, 0x31, 0x34, 0x29, 0x0, 0x28, 0x31, 0x35, 0x29, 0x0, 0x28, 0x31, 0x36, 0x29, 0x0, 0x28, 0x31, 0x37, 0x29, 0x0, 0x28, 0x31, 0x38, 0x29, 0x0, 0x28, 0x31, 0x39, 0x29, 0x0, 0x28, 0x32, 0x29, 0x0, 0x28, 0x32, 0x30, 0x29, 0x0, 0x28, 0x33, 0x29, 0x0, 0x28, 0x34, 0x29, 0x0, 0x28, 0x35, 0x29, 0x0, 0x28, 0x36, 0x29, 0x0, 0x28, 0x37, 0x29, 0x0, 0x28, 0x38, 0x29, 0x0, 0x28, 0x39, 0x29, 0x0, 0x28, 0x41, 0x29, 0x0, 0x28, 0x42, 0x29, 0x0, 0x28, 0x43, 0x29, 0x0, 0x28, 0x44, 0x29, 0x0, 0x28, 0x45, 0x29, 0x0, 0x28, 0x46, 0x29, 0x0, 0x28, 0x47, 0x29, 0x0, 0x28, 0x48, 0x29, 0x0, 0x28, 0x49, 0x29, 0x0, 0x28, 0x4a, 0x29, 0x0, 0x28, 0x4b, 0x29, 0x0, 0x28, 0x4c, 0x29, 0x0, 0x28, 0x4d, 0x29, 0x0, 0x28, 0x4e, 0x29, 0x0, 0x28, 0x4f, 0x29, 0x0, 0x28, 0x50, 0x29, 0x0, 0x28, 0x51, 0x29, 0x0, 0x28, 0x52, 0x29, 0x0, 0x28, 0x53, 0x29, 0x0, 0x28, 0x54, 0x29, 0x0, 0x28, 0x55, 0x29, 0x0, 0x28, 0x56, 0x29, 0x0, 0x28, 0x57, 0x29, 0x0, 0x28, 0x58, 0x29, 0x0, 0x28, 0x59, 0x29, 0x0, 0x28, 0x5a, 0x29, 0x0, 0x28, 0x61, 0x29, 0x0, 0x28, 0x62, 0x29, 0x0, 0x28, 0x63, 0x29, 0x0, 0x28, 0x64, 0x29, 0x0, 0x28, 0x65, 0x29, 0x0, 0x28, 0x66, 0x29, 0x0, 0x28, 0x67, 0x29, 0x0, 0x28, 0x68, 0x29, 0x0, 0x28, 0x69, 0x29, 0x0, 0x28, 0x6a, 0x29, 0x0, 0x28, 0x6b, 0x29, 0x0, 0x28, 0x6c, 0x29, 0x0, 0x28, 0x6d, 0x29, 0x0, 0x28, 0x6e, 0x29, 0x0, 0x28, 0x6f, 0x29, 0x0, 0x28, 0x70, 0x29, 0x0, 0x28, 0x71, 0x29, 0x0, 0x28, 0x72, 0x29, 0x0, 0x28, 0x73, 0x29, 0x0, 0x28, 0x74, 0x29, 0x0, 0x28, 0x75, 0x29, 0x0, 0x28, 0x76, 0x29, 0x0, 0x28, 0x77, 0x29, 0x0, 0x28, 0x78, 0x29, 0x0, 0x28, 0x79, 0x29, 0x0, 0x28, 0x7a, 0x29, 0x0, 0x28, 0x1100, 0x29, 0x0, 0x28, 0x1100, 0x1161, 0x29, 0x0, 0x28, 0x1102, 0x29, 0x0, 0x28, 0x1102, 0x1161, 0x29, 0x0, 0x28, 0x1103, 0x29, 0x0, 0x28, 0x1103, 0x1161, 0x29, 0x0, 0x28, 0x1105, 0x29, 0x0, 0x28, 0x1105, 0x1161, 0x29, 0x0, 0x28, 0x1106, 0x29, 0x0, 0x28, 0x1106, 0x1161, 0x29, 0x0, 0x28, 0x1107, 0x29, 0x0, 0x28, 0x1107, 0x1161, 0x29, 0x0, 0x28, 0x1109, 0x29, 0x0, 0x28, 0x1109, 0x1161, 0x29, 0x0, 0x28, 0x110b, 0x29, 0x0, 0x28, 0x110b, 0x1161, 0x29, 0x0, 0x28, 0x110b, 0x1169, 0x110c, 0x1165, 0x11ab, 0x29, 0x0, 0x28, 0x110b, 0x1169, 0x1112, 0x116e, 0x29, 0x0, 0x28, 0x110c, 0x29, 0x0, 0x28, 0x110c, 0x1161, 0x29, 0x0, 0x28, 0x110c, 0x116e, 0x29, 0x0, 0x28, 0x110e, 0x29, 0x0, 0x28, 0x110e, 0x1161, 0x29, 0x0, 0x28, 0x110f, 0x29, 0x0, 0x28, 0x110f, 0x1161, 0x29, 0x0, 0x28, 0x1110, 0x29, 0x0, 0x28, 0x1110, 0x1161, 0x29, 0x0, 0x28, 0x1111, 0x29, 0x0, 0x28, 0x1111, 0x1161, 0x29, 0x0, 0x28, 0x1112, 0x29, 0x0, 0x28, 0x1112, 0x1161, 0x29, 0x0, 0x28, 0x4e00, 0x29, 0x0, 0x28, 0x4e03, 0x29, 0x0, 0x28, 0x4e09, 0x29, 0x0, 0x28, 0x4e5d, 0x29, 0x0, 0x28, 0x4e8c, 0x29, 0x0, 0x28, 0x4e94, 0x29, 0x0, 0x28, 0x4ee3, 0x29, 0x0, 0x28, 0x4f01, 0x29, 0x0, 0x28, 0x4f11, 0x29, 0x0, 0x28, 0x516b, 0x29, 0x0, 0x28, 0x516d, 0x29, 0x0, 0x28, 0x52b4, 0x29, 0x0, 0x28, 0x5341, 0x29, 0x0, 0x28, 0x5354, 0x29, 0x0, 0x28, 0x540d, 0x29, 0x0, 0x28, 0x547c, 0x29, 0x0, 0x28, 0x56db, 0x29, 0x0, 0x28, 0x571f, 0x29, 0x0, 0x28, 0x5b66, 0x29, 0x0, 0x28, 0x65e5, 0x29, 0x0, 0x28, 0x6708, 0x29, 0x0, 0x28, 0x6709, 0x29, 0x0, 0x28, 0x6728, 0x29, 0x0, 0x28, 0x682a, 0x29, 0x0, 0x28, 0x6c34, 0x29, 0x0, 0x28, 0x706b, 0x29, 0x0, 0x28, 0x7279, 0x29, 0x0, 0x28, 0x76e3, 0x29, 0x0, 0x28, 0x793e, 0x29, 0x0, 0x28, 0x795d, 0x29, 0x0, 0x28, 0x796d, 0x29, 0x0, 0x28, 0x81ea, 0x29, 0x0, 0x28, 0x81f3, 0x29, 0x0, 0x28, 0x8ca1, 0x29, 0x0, 0x28, 0x8cc7, 0x29, 0x0, 0x28, 0x91d1, 0x29, 0x0, 0x29, 0x0, 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, 0x2e, 0x0, 0x2e, 0x2e, 0x0, 0x2e, 0x2e, 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x30, 0x2c, 0x0, 0x30, 0x2e, 0x0, 0x30, 0x2044, 0x33, 0x0, 0x30, 0x70b9, 0x0, 0x31, 0x0, 0x31, 0x2c, 0x0, 0x31, 0x2e, 0x0, 0x31, 0x30, 0x0, 0x31, 0x30, 0x2e, 0x0, 0x31, 0x30, 0x65e5, 0x0, 0x31, 0x30, 0x6708, 0x0, 0x31, 0x30, 0x70b9, 0x0, 0x31, 0x31, 0x0, 0x31, 0x31, 0x2e, 0x0, 0x31, 0x31, 0x65e5, 0x0, 0x31, 0x31, 0x6708, 0x0, 0x31, 0x31, 0x70b9, 0x0, 0x31, 0x32, 0x0, 0x31, 0x32, 0x2e, 0x0, 0x31, 0x32, 0x65e5, 0x0, 0x31, 0x32, 0x6708, 0x0, 0x31, 0x32, 0x70b9, 0x0, 0x31, 0x33, 0x0, 0x31, 0x33, 0x2e, 0x0, 0x31, 0x33, 0x65e5, 0x0, 0x31, 0x33, 0x70b9, 0x0, 0x31, 0x34, 0x0, 0x31, 0x34, 0x2e, 0x0, 0x31, 0x34, 0x65e5, 0x0, 0x31, 0x34, 0x70b9, 0x0, 0x31, 0x35, 0x0, 0x31, 0x35, 0x2e, 0x0, 0x31, 0x35, 0x65e5, 0x0, 0x31, 0x35, 0x70b9, 0x0, 0x31, 0x36, 0x0, 0x31, 0x36, 0x2e, 0x0, 0x31, 0x36, 0x65e5, 0x0, 0x31, 0x36, 0x70b9, 0x0, 0x31, 0x37, 0x0, 0x31, 0x37, 0x2e, 0x0, 0x31, 0x37, 0x65e5, 0x0, 0x31, 0x37, 0x70b9, 0x0, 0x31, 0x38, 0x0, 0x31, 0x38, 0x2e, 0x0, 0x31, 0x38, 0x65e5, 0x0, 0x31, 0x38, 0x70b9, 0x0, 0x31, 0x39, 0x0, 0x31, 0x39, 0x2e, 0x0, 0x31, 0x39, 0x65e5, 0x0, 0x31, 0x39, 0x70b9, 0x0, 0x31, 0x2044, 0x0, 0x31, 0x2044, 0x31, 0x30, 0x0, 0x31, 0x2044, 0x32, 0x0, 0x31, 0x2044, 0x33, 0x0, 0x31, 0x2044, 0x34, 0x0, 0x31, 0x2044, 0x35, 0x0, 0x31, 0x2044, 0x36, 0x0, 0x31, 0x2044, 0x37, 0x0, 0x31, 0x2044, 0x38, 0x0, 0x31, 0x2044, 0x39, 0x0, 0x31, 0x65e5, 0x0, 0x31, 0x6708, 0x0, 0x31, 0x70b9, 0x0, 0x32, 0x0, 0x32, 0x2c, 0x0, 0x32, 0x2e, 0x0, 0x32, 0x30, 0x0, 0x32, 0x30, 0x2e, 0x0, 0x32, 0x30, 0x65e5, 0x0, 0x32, 0x30, 0x70b9, 0x0, 0x32, 0x31, 0x0, 0x32, 0x31, 0x65e5, 0x0, 0x32, 0x31, 0x70b9, 0x0, 0x32, 0x32, 0x0, 0x32, 0x32, 0x65e5, 0x0, 0x32, 0x32, 0x70b9, 0x0, 0x32, 0x33, 0x0, 0x32, 0x33, 0x65e5, 0x0, 0x32, 0x33, 0x70b9, 0x0, 0x32, 0x34, 0x0, 0x32, 0x34, 0x65e5, 0x0, 0x32, 0x34, 0x70b9, 0x0, 0x32, 0x35, 0x0, 0x32, 0x35, 0x65e5, 0x0, 0x32, 0x36, 0x0, 0x32, 0x36, 0x65e5, 0x0, 0x32, 0x37, 0x0, 0x32, 0x37, 0x65e5, 0x0, 0x32, 0x38, 0x0, 0x32, 0x38, 0x65e5, 0x0, 0x32, 0x39, 0x0, 0x32, 0x39, 0x65e5, 0x0, 0x32, 0x2044, 0x33, 0x0, 0x32, 0x2044, 0x35, 0x0, 0x32, 0x65e5, 0x0, 0x32, 0x6708, 0x0, 0x32, 0x70b9, 0x0, 0x33, 0x0, 0x33, 0x2c, 0x0, 0x33, 0x2e, 0x0, 0x33, 0x30, 0x0, 0x33, 0x30, 0x65e5, 0x0, 0x33, 0x31, 0x0, 0x33, 0x31, 0x65e5, 0x0, 0x33, 0x32, 0x0, 0x33, 0x33, 0x0, 0x33, 0x34, 0x0, 0x33, 0x35, 0x0, 0x33, 0x36, 0x0, 0x33, 0x37, 0x0, 0x33, 0x38, 0x0, 0x33, 0x39, 0x0, 0x33, 0x2044, 0x34, 0x0, 0x33, 0x2044, 0x35, 0x0, 0x33, 0x2044, 0x38, 0x0, 0x33, 0x65e5, 0x0, 0x33, 0x6708, 0x0, 0x33, 0x70b9, 0x0, 0x34, 0x0, 0x34, 0x2c, 0x0, 0x34, 0x2e, 0x0, 0x34, 0x30, 0x0, 0x34, 0x31, 0x0, 0x34, 0x32, 0x0, 0x34, 0x33, 0x0, 0x34, 0x34, 0x0, 0x34, 0x35, 0x0, 0x34, 0x36, 0x0, 0x34, 0x37, 0x0, 0x34, 0x38, 0x0, 0x34, 0x39, 0x0, 0x34, 0x2044, 0x35, 0x0, 0x34, 0x65e5, 0x0, 0x34, 0x6708, 0x0, 0x34, 0x70b9, 0x0, 0x35, 0x0, 0x35, 0x2c, 0x0, 0x35, 0x2e, 0x0, 0x35, 0x30, 0x0, 0x35, 0x2044, 0x36, 0x0, 0x35, 0x2044, 0x38, 0x0, 0x35, 0x65e5, 0x0, 0x35, 0x6708, 0x0, 0x35, 0x70b9, 0x0, 0x36, 0x0, 0x36, 0x2c, 0x0, 0x36, 0x2e, 0x0, 0x36, 0x65e5, 0x0, 0x36, 0x6708, 0x0, 0x36, 0x70b9, 0x0, 0x37, 0x0, 0x37, 0x2c, 0x0, 0x37, 0x2e, 0x0, 0x37, 0x2044, 0x38, 0x0, 0x37, 0x65e5, 0x0, 0x37, 0x6708, 0x0, 0x37, 0x70b9, 0x0, 0x38, 0x0, 0x38, 0x2c, 0x0, 0x38, 0x2e, 0x0, 0x38, 0x65e5, 0x0, 0x38, 0x6708, 0x0, 0x38, 0x70b9, 0x0, 0x39, 0x0, 0x39, 0x2c, 0x0, 0x39, 0x2e, 0x0, 0x39, 0x65e5, 0x0, 0x39, 0x6708, 0x0, 0x39, 0x70b9, 0x0, 0x3a, 0x0, 0x3a, 0x3a, 0x3d, 0x0, 0x3b, 0x0, 0x3c, 0x0, 0x3c, 0x338, 0x0, 0x3d, 0x0, 0x3d, 0x3d, 0x0, 0x3d, 0x3d, 0x3d, 0x0, 0x3d, 0x338, 0x0, 0x3e, 0x0, 0x3e, 0x338, 0x0, 0x3f, 0x0, 0x3f, 0x21, 0x0, 0x3f, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, 0x41, 0x55, 0x0, 0x41, 0x300, 0x0, 0x41, 0x301, 0x0, 0x41, 0x302, 0x0, 0x41, 0x302, 0x300, 0x0, 0x41, 0x302, 0x301, 0x0, 0x41, 0x302, 0x303, 0x0, 0x41, 0x302, 0x309, 0x0, 0x41, 0x303, 0x0, 0x41, 0x304, 0x0, 0x41, 0x306, 0x0, 0x41, 0x306, 0x300, 0x0, 0x41, 0x306, 0x301, 0x0, 0x41, 0x306, 0x303, 0x0, 0x41, 0x306, 0x309, 0x0, 0x41, 0x307, 0x0, 0x41, 0x307, 0x304, 0x0, 0x41, 0x308, 0x0, 0x41, 0x308, 0x304, 0x0, 0x41, 0x309, 0x0, 0x41, 0x30a, 0x0, 0x41, 0x30a, 0x301, 0x0, 0x41, 0x30c, 0x0, 0x41, 0x30f, 0x0, 0x41, 0x311, 0x0, 0x41, 0x323, 0x0, 0x41, 0x323, 0x302, 0x0, 0x41, 0x323, 0x306, 0x0, 0x41, 0x325, 0x0, 0x41, 0x328, 0x0, 0x41, 0x2215, 0x6d, 0x0, 0x42, 0x0, 0x42, 0x71, 0x0, 0x42, 0x307, 0x0, 0x42, 0x323, 0x0, 0x42, 0x331, 0x0, 0x43, 0x0, 0x43, 0x44, 0x0, 0x43, 0x6f, 0x2e, 0x0, 0x43, 0x301, 0x0, 0x43, 0x302, 0x0, 0x43, 0x307, 0x0, 0x43, 0x30c, 0x0, 0x43, 0x327, 0x0, 0x43, 0x327, 0x301, 0x0, 0x43, 0x2215, 0x6b, 0x67, 0x0, 0x44, 0x0, 0x44, 0x4a, 0x0, 0x44, 0x5a, 0x0, 0x44, 0x5a, 0x30c, 0x0, 0x44, 0x7a, 0x0, 0x44, 0x7a, 0x30c, 0x0, 0x44, 0x307, 0x0, 0x44, 0x30c, 0x0, 0x44, 0x323, 0x0, 0x44, 0x327, 0x0, 0x44, 0x32d, 0x0, 0x44, 0x331, 0x0, 0x45, 0x0, 0x45, 0x300, 0x0, 0x45, 0x301, 0x0, 0x45, 0x302, 0x0, 0x45, 0x302, 0x300, 0x0, 0x45, 0x302, 0x301, 0x0, 0x45, 0x302, 0x303, 0x0, 0x45, 0x302, 0x309, 0x0, 0x45, 0x303, 0x0, 0x45, 0x304, 0x0, 0x45, 0x304, 0x300, 0x0, 0x45, 0x304, 0x301, 0x0, 0x45, 0x306, 0x0, 0x45, 0x307, 0x0, 0x45, 0x308, 0x0, 0x45, 0x309, 0x0, 0x45, 0x30c, 0x0, 0x45, 0x30f, 0x0, 0x45, 0x311, 0x0, 0x45, 0x323, 0x0, 0x45, 0x323, 0x302, 0x0, 0x45, 0x327, 0x0, 0x45, 0x327, 0x306, 0x0, 0x45, 0x328, 0x0, 0x45, 0x32d, 0x0, 0x45, 0x330, 0x0, 0x46, 0x0, 0x46, 0x41, 0x58, 0x0, 0x46, 0x307, 0x0, 0x47, 0x0, 0x47, 0x42, 0x0, 0x47, 0x48, 0x7a, 0x0, 0x47, 0x50, 0x61, 0x0, 0x47, 0x79, 0x0, 0x47, 0x301, 0x0, 0x47, 0x302, 0x0, 0x47, 0x304, 0x0, 0x47, 0x306, 0x0, 0x47, 0x307, 0x0, 0x47, 0x30c, 0x0, 0x47, 0x327, 0x0, 0x48, 0x0, 0x48, 0x50, 0x0, 0x48, 0x56, 0x0, 0x48, 0x67, 0x0, 0x48, 0x7a, 0x0, 0x48, 0x302, 0x0, 0x48, 0x307, 0x0, 0x48, 0x308, 0x0, 0x48, 0x30c, 0x0, 0x48, 0x323, 0x0, 0x48, 0x327, 0x0, 0x48, 0x32e, 0x0, 0x49, 0x0, 0x49, 0x49, 0x0, 0x49, 0x49, 0x49, 0x0, 0x49, 0x4a, 0x0, 0x49, 0x55, 0x0, 0x49, 0x56, 0x0, 0x49, 0x58, 0x0, 0x49, 0x300, 0x0, 0x49, 0x301, 0x0, 0x49, 0x302, 0x0, 0x49, 0x303, 0x0, 0x49, 0x304, 0x0, 0x49, 0x306, 0x0, 0x49, 0x307, 0x0, 0x49, 0x308, 0x0, 0x49, 0x308, 0x301, 0x0, 0x49, 0x309, 0x0, 0x49, 0x30c, 0x0, 0x49, 0x30f, 0x0, 0x49, 0x311, 0x0, 0x49, 0x323, 0x0, 0x49, 0x328, 0x0, 0x49, 0x330, 0x0, 0x4a, 0x0, 0x4a, 0x302, 0x0, 0x4b, 0x0, 0x4b, 0x42, 0x0, 0x4b, 0x4b, 0x0, 0x4b, 0x4d, 0x0, 0x4b, 0x301, 0x0, 0x4b, 0x30c, 0x0, 0x4b, 0x323, 0x0, 0x4b, 0x327, 0x0, 0x4b, 0x331, 0x0, 0x4c, 0x0, 0x4c, 0x4a, 0x0, 0x4c, 0x54, 0x44, 0x0, 0x4c, 0x6a, 0x0, 0x4c, 0xb7, 0x0, 0x4c, 0x301, 0x0, 0x4c, 0x30c, 0x0, 0x4c, 0x323, 0x0, 0x4c, 0x323, 0x304, 0x0, 0x4c, 0x327, 0x0, 0x4c, 0x32d, 0x0, 0x4c, 0x331, 0x0, 0x4d, 0x0, 0x4d, 0x42, 0x0, 0x4d, 0x43, 0x0, 0x4d, 0x44, 0x0, 0x4d, 0x48, 0x7a, 0x0, 0x4d, 0x50, 0x61, 0x0, 0x4d, 0x56, 0x0, 0x4d, 0x57, 0x0, 0x4d, 0x301, 0x0, 0x4d, 0x307, 0x0, 0x4d, 0x323, 0x0, 0x4d, 0x3a9, 0x0, 0x4e, 0x0, 0x4e, 0x4a, 0x0, 0x4e, 0x6a, 0x0, 0x4e, 0x6f, 0x0, 0x4e, 0x300, 0x0, 0x4e, 0x301, 0x0, 0x4e, 0x303, 0x0, 0x4e, 0x307, 0x0, 0x4e, 0x30c, 0x0, 0x4e, 0x323, 0x0, 0x4e, 0x327, 0x0, 0x4e, 0x32d, 0x0, 0x4e, 0x331, 0x0, 0x4f, 0x0, 0x4f, 0x300, 0x0, 0x4f, 0x301, 0x0, 0x4f, 0x302, 0x0, 0x4f, 0x302, 0x300, 0x0, 0x4f, 0x302, 0x301, 0x0, 0x4f, 0x302, 0x303, 0x0, 0x4f, 0x302, 0x309, 0x0, 0x4f, 0x303, 0x0, 0x4f, 0x303, 0x301, 0x0, 0x4f, 0x303, 0x304, 0x0, 0x4f, 0x303, 0x308, 0x0, 0x4f, 0x304, 0x0, 0x4f, 0x304, 0x300, 0x0, 0x4f, 0x304, 0x301, 0x0, 0x4f, 0x306, 0x0, 0x4f, 0x307, 0x0, 0x4f, 0x307, 0x304, 0x0, 0x4f, 0x308, 0x0, 0x4f, 0x308, 0x304, 0x0, 0x4f, 0x309, 0x0, 0x4f, 0x30b, 0x0, 0x4f, 0x30c, 0x0, 0x4f, 0x30f, 0x0, 0x4f, 0x311, 0x0, 0x4f, 0x31b, 0x0, 0x4f, 0x31b, 0x300, 0x0, 0x4f, 0x31b, 0x301, 0x0, 0x4f, 0x31b, 0x303, 0x0, 0x4f, 0x31b, 0x309, 0x0, 0x4f, 0x31b, 0x323, 0x0, 0x4f, 0x323, 0x0, 0x4f, 0x323, 0x302, 0x0, 0x4f, 0x328, 0x0, 0x4f, 0x328, 0x304, 0x0, 0x50, 0x0, 0x50, 0x48, 0x0, 0x50, 0x50, 0x4d, 0x0, 0x50, 0x50, 0x56, 0x0, 0x50, 0x52, 0x0, 0x50, 0x54, 0x45, 0x0, 0x50, 0x61, 0x0, 0x50, 0x301, 0x0, 0x50, 0x307, 0x0, 0x51, 0x0, 0x52, 0x0, 0x52, 0x73, 0x0, 0x52, 0x301, 0x0, 0x52, 0x307, 0x0, 0x52, 0x30c, 0x0, 0x52, 0x30f, 0x0, 0x52, 0x311, 0x0, 0x52, 0x323, 0x0, 0x52, 0x323, 0x304, 0x0, 0x52, 0x327, 0x0, 0x52, 0x331, 0x0, 0x53, 0x0, 0x53, 0x44, 0x0, 0x53, 0x4d, 0x0, 0x53, 0x53, 0x0, 0x53, 0x76, 0x0, 0x53, 0x301, 0x0, 0x53, 0x301, 0x307, 0x0, 0x53, 0x302, 0x0, 0x53, 0x307, 0x0, 0x53, 0x30c, 0x0, 0x53, 0x30c, 0x307, 0x0, 0x53, 0x323, 0x0, 0x53, 0x323, 0x307, 0x0, 0x53, 0x326, 0x0, 0x53, 0x327, 0x0, 0x54, 0x0, 0x54, 0x45, 0x4c, 0x0, 0x54, 0x48, 0x7a, 0x0, 0x54, 0x4d, 0x0, 0x54, 0x307, 0x0, 0x54, 0x30c, 0x0, 0x54, 0x323, 0x0, 0x54, 0x326, 0x0, 0x54, 0x327, 0x0, 0x54, 0x32d, 0x0, 0x54, 0x331, 0x0, 0x55, 0x0, 0x55, 0x300, 0x0, 0x55, 0x301, 0x0, 0x55, 0x302, 0x0, 0x55, 0x303, 0x0, 0x55, 0x303, 0x301, 0x0, 0x55, 0x304, 0x0, 0x55, 0x304, 0x308, 0x0, 0x55, 0x306, 0x0, 0x55, 0x308, 0x0, 0x55, 0x308, 0x300, 0x0, 0x55, 0x308, 0x301, 0x0, 0x55, 0x308, 0x304, 0x0, 0x55, 0x308, 0x30c, 0x0, 0x55, 0x309, 0x0, 0x55, 0x30a, 0x0, 0x55, 0x30b, 0x0, 0x55, 0x30c, 0x0, 0x55, 0x30f, 0x0, 0x55, 0x311, 0x0, 0x55, 0x31b, 0x0, 0x55, 0x31b, 0x300, 0x0, 0x55, 0x31b, 0x301, 0x0, 0x55, 0x31b, 0x303, 0x0, 0x55, 0x31b, 0x309, 0x0, 0x55, 0x31b, 0x323, 0x0, 0x55, 0x323, 0x0, 0x55, 0x324, 0x0, 0x55, 0x328, 0x0, 0x55, 0x32d, 0x0, 0x55, 0x330, 0x0, 0x56, 0x0, 0x56, 0x49, 0x0, 0x56, 0x49, 0x49, 0x0, 0x56, 0x49, 0x49, 0x49, 0x0, 0x56, 0x303, 0x0, 0x56, 0x323, 0x0, 0x56, 0x2215, 0x6d, 0x0, 0x57, 0x0, 0x57, 0x43, 0x0, 0x57, 0x5a, 0x0, 0x57, 0x62, 0x0, 0x57, 0x300, 0x0, 0x57, 0x301, 0x0, 0x57, 0x302, 0x0, 0x57, 0x307, 0x0, 0x57, 0x308, 0x0, 0x57, 0x323, 0x0, 0x58, 0x0, 0x58, 0x49, 0x0, 0x58, 0x49, 0x49, 0x0, 0x58, 0x307, 0x0, 0x58, 0x308, 0x0, 0x59, 0x0, 0x59, 0x300, 0x0, 0x59, 0x301, 0x0, 0x59, 0x302, 0x0, 0x59, 0x303, 0x0, 0x59, 0x304, 0x0, 0x59, 0x307, 0x0, 0x59, 0x308, 0x0, 0x59, 0x309, 0x0, 0x59, 0x323, 0x0, 0x5a, 0x0, 0x5a, 0x301, 0x0, 0x5a, 0x302, 0x0, 0x5a, 0x307, 0x0, 0x5a, 0x30c, 0x0, 0x5a, 0x323, 0x0, 0x5a, 0x331, 0x0, 0x5b, 0x0, 0x5c, 0x0, 0x5d, 0x0, 0x5e, 0x0, 0x5f, 0x0, 0x60, 0x0, 0x61, 0x0, 0x61, 0x2e, 0x6d, 0x2e, 0x0, 0x61, 0x2f, 0x63, 0x0, 0x61, 0x2f, 0x73, 0x0, 0x61, 0x2be, 0x0, 0x61, 0x300, 0x0, 0x61, 0x301, 0x0, 0x61, 0x302, 0x0, 0x61, 0x302, 0x300, 0x0, 0x61, 0x302, 0x301, 0x0, 0x61, 0x302, 0x303, 0x0, 0x61, 0x302, 0x309, 0x0, 0x61, 0x303, 0x0, 0x61, 0x304, 0x0, 0x61, 0x306, 0x0, 0x61, 0x306, 0x300, 0x0, 0x61, 0x306, 0x301, 0x0, 0x61, 0x306, 0x303, 0x0, 0x61, 0x306, 0x309, 0x0, 0x61, 0x307, 0x0, 0x61, 0x307, 0x304, 0x0, 0x61, 0x308, 0x0, 0x61, 0x308, 0x304, 0x0, 0x61, 0x309, 0x0, 0x61, 0x30a, 0x0, 0x61, 0x30a, 0x301, 0x0, 0x61, 0x30c, 0x0, 0x61, 0x30f, 0x0, 0x61, 0x311, 0x0, 0x61, 0x323, 0x0, 0x61, 0x323, 0x302, 0x0, 0x61, 0x323, 0x306, 0x0, 0x61, 0x325, 0x0, 0x61, 0x328, 0x0, 0x62, 0x0, 0x62, 0x61, 0x72, 0x0, 0x62, 0x307, 0x0, 0x62, 0x323, 0x0, 0x62, 0x331, 0x0, 0x63, 0x0, 0x63, 0x2f, 0x6f, 0x0, 0x63, 0x2f, 0x75, 0x0, 0x63, 0x61, 0x6c, 0x0, 0x63, 0x63, 0x0, 0x63, 0x64, 0x0, 0x63, 0x6d, 0x0, 0x63, 0x6d, 0x32, 0x0, 0x63, 0x6d, 0x33, 0x0, 0x63, 0x301, 0x0, 0x63, 0x302, 0x0, 0x63, 0x307, 0x0, 0x63, 0x30c, 0x0, 0x63, 0x327, 0x0, 0x63, 0x327, 0x301, 0x0, 0x64, 0x0, 0x64, 0x42, 0x0, 0x64, 0x61, 0x0, 0x64, 0x6c, 0x0, 0x64, 0x6d, 0x0, 0x64, 0x6d, 0x32, 0x0, 0x64, 0x6d, 0x33, 0x0, 0x64, 0x7a, 0x0, 0x64, 0x7a, 0x30c, 0x0, 0x64, 0x307, 0x0, 0x64, 0x30c, 0x0, 0x64, 0x323, 0x0, 0x64, 0x327, 0x0, 0x64, 0x32d, 0x0, 0x64, 0x331, 0x0, 0x65, 0x0, 0x65, 0x56, 0x0, 0x65, 0x72, 0x67, 0x0, 0x65, 0x300, 0x0, 0x65, 0x301, 0x0, 0x65, 0x302, 0x0, 0x65, 0x302, 0x300, 0x0, 0x65, 0x302, 0x301, 0x0, 0x65, 0x302, 0x303, 0x0, 0x65, 0x302, 0x309, 0x0, 0x65, 0x303, 0x0, 0x65, 0x304, 0x0, 0x65, 0x304, 0x300, 0x0, 0x65, 0x304, 0x301, 0x0, 0x65, 0x306, 0x0, 0x65, 0x307, 0x0, 0x65, 0x308, 0x0, 0x65, 0x309, 0x0, 0x65, 0x30c, 0x0, 0x65, 0x30f, 0x0, 0x65, 0x311, 0x0, 0x65, 0x323, 0x0, 0x65, 0x323, 0x302, 0x0, 0x65, 0x327, 0x0, 0x65, 0x327, 0x306, 0x0, 0x65, 0x328, 0x0, 0x65, 0x32d, 0x0, 0x65, 0x330, 0x0, 0x66, 0x0, 0x66, 0x66, 0x0, 0x66, 0x66, 0x69, 0x0, 0x66, 0x66, 0x6c, 0x0, 0x66, 0x69, 0x0, 0x66, 0x6c, 0x0, 0x66, 0x6d, 0x0, 0x66, 0x307, 0x0, 0x67, 0x0, 0x67, 0x61, 0x6c, 0x0, 0x67, 0x301, 0x0, 0x67, 0x302, 0x0, 0x67, 0x304, 0x0, 0x67, 0x306, 0x0, 0x67, 0x307, 0x0, 0x67, 0x30c, 0x0, 0x67, 0x327, 0x0, 0x68, 0x0, 0x68, 0x50, 0x61, 0x0, 0x68, 0x61, 0x0, 0x68, 0x302, 0x0, 0x68, 0x307, 0x0, 0x68, 0x308, 0x0, 0x68, 0x30c, 0x0, 0x68, 0x323, 0x0, 0x68, 0x327, 0x0, 0x68, 0x32e, 0x0, 0x68, 0x331, 0x0, 0x69, 0x0, 0x69, 0x69, 0x0, 0x69, 0x69, 0x69, 0x0, 0x69, 0x6a, 0x0, 0x69, 0x6e, 0x0, 0x69, 0x76, 0x0, 0x69, 0x78, 0x0, 0x69, 0x300, 0x0, 0x69, 0x301, 0x0, 0x69, 0x302, 0x0, 0x69, 0x303, 0x0, 0x69, 0x304, 0x0, 0x69, 0x306, 0x0, 0x69, 0x308, 0x0, 0x69, 0x308, 0x301, 0x0, 0x69, 0x309, 0x0, 0x69, 0x30c, 0x0, 0x69, 0x30f, 0x0, 0x69, 0x311, 0x0, 0x69, 0x323, 0x0, 0x69, 0x328, 0x0, 0x69, 0x330, 0x0, 0x6a, 0x0, 0x6a, 0x302, 0x0, 0x6a, 0x30c, 0x0, 0x6b, 0x0, 0x6b, 0x41, 0x0, 0x6b, 0x48, 0x7a, 0x0, 0x6b, 0x50, 0x61, 0x0, 0x6b, 0x56, 0x0, 0x6b, 0x57, 0x0, 0x6b, 0x63, 0x61, 0x6c, 0x0, 0x6b, 0x67, 0x0, 0x6b, 0x6c, 0x0, 0x6b, 0x6d, 0x0, 0x6b, 0x6d, 0x32, 0x0, 0x6b, 0x6d, 0x33, 0x0, 0x6b, 0x74, 0x0, 0x6b, 0x301, 0x0, 0x6b, 0x30c, 0x0, 0x6b, 0x323, 0x0, 0x6b, 0x327, 0x0, 0x6b, 0x331, 0x0, 0x6b, 0x3a9, 0x0, 0x6c, 0x0, 0x6c, 0x6a, 0x0, 0x6c, 0x6d, 0x0, 0x6c, 0x6e, 0x0, 0x6c, 0x6f, 0x67, 0x0, 0x6c, 0x78, 0x0, 0x6c, 0xb7, 0x0, 0x6c, 0x301, 0x0, 0x6c, 0x30c, 0x0, 0x6c, 0x323, 0x0, 0x6c, 0x323, 0x304, 0x0, 0x6c, 0x327, 0x0, 0x6c, 0x32d, 0x0, 0x6c, 0x331, 0x0, 0x6d, 0x0, 0x6d, 0x32, 0x0, 0x6d, 0x33, 0x0, 0x6d, 0x41, 0x0, 0x6d, 0x56, 0x0, 0x6d, 0x57, 0x0, 0x6d, 0x62, 0x0, 0x6d, 0x67, 0x0, 0x6d, 0x69, 0x6c, 0x0, 0x6d, 0x6c, 0x0, 0x6d, 0x6d, 0x0, 0x6d, 0x6d, 0x32, 0x0, 0x6d, 0x6d, 0x33, 0x0, 0x6d, 0x6f, 0x6c, 0x0, 0x6d, 0x73, 0x0, 0x6d, 0x301, 0x0, 0x6d, 0x307, 0x0, 0x6d, 0x323, 0x0, 0x6d, 0x2215, 0x73, 0x0, 0x6d, 0x2215, 0x73, 0x32, 0x0, 0x6e, 0x0, 0x6e, 0x41, 0x0, 0x6e, 0x46, 0x0, 0x6e, 0x56, 0x0, 0x6e, 0x57, 0x0, 0x6e, 0x6a, 0x0, 0x6e, 0x6d, 0x0, 0x6e, 0x73, 0x0, 0x6e, 0x300, 0x0, 0x6e, 0x301, 0x0, 0x6e, 0x303, 0x0, 0x6e, 0x307, 0x0, 0x6e, 0x30c, 0x0, 0x6e, 0x323, 0x0, 0x6e, 0x327, 0x0, 0x6e, 0x32d, 0x0, 0x6e, 0x331, 0x0, 0x6f, 0x0, 0x6f, 0x56, 0x0, 0x6f, 0x300, 0x0, 0x6f, 0x301, 0x0, 0x6f, 0x302, 0x0, 0x6f, 0x302, 0x300, 0x0, 0x6f, 0x302, 0x301, 0x0, 0x6f, 0x302, 0x303, 0x0, 0x6f, 0x302, 0x309, 0x0, 0x6f, 0x303, 0x0, 0x6f, 0x303, 0x301, 0x0, 0x6f, 0x303, 0x304, 0x0, 0x6f, 0x303, 0x308, 0x0, 0x6f, 0x304, 0x0, 0x6f, 0x304, 0x300, 0x0, 0x6f, 0x304, 0x301, 0x0, 0x6f, 0x306, 0x0, 0x6f, 0x307, 0x0, 0x6f, 0x307, 0x304, 0x0, 0x6f, 0x308, 0x0, 0x6f, 0x308, 0x304, 0x0, 0x6f, 0x309, 0x0, 0x6f, 0x30b, 0x0, 0x6f, 0x30c, 0x0, 0x6f, 0x30f, 0x0, 0x6f, 0x311, 0x0, 0x6f, 0x31b, 0x0, 0x6f, 0x31b, 0x300, 0x0, 0x6f, 0x31b, 0x301, 0x0, 0x6f, 0x31b, 0x303, 0x0, 0x6f, 0x31b, 0x309, 0x0, 0x6f, 0x31b, 0x323, 0x0, 0x6f, 0x323, 0x0, 0x6f, 0x323, 0x302, 0x0, 0x6f, 0x328, 0x0, 0x6f, 0x328, 0x304, 0x0, 0x70, 0x0, 0x70, 0x2e, 0x6d, 0x2e, 0x0, 0x70, 0x41, 0x0, 0x70, 0x46, 0x0, 0x70, 0x56, 0x0, 0x70, 0x57, 0x0, 0x70, 0x63, 0x0, 0x70, 0x73, 0x0, 0x70, 0x301, 0x0, 0x70, 0x307, 0x0, 0x71, 0x0, 0x72, 0x0, 0x72, 0x61, 0x64, 0x0, 0x72, 0x61, 0x64, 0x2215, 0x73, 0x0, 0x72, 0x61, 0x64, 0x2215, 0x73, 0x32, 0x0, 0x72, 0x301, 0x0, 0x72, 0x307, 0x0, 0x72, 0x30c, 0x0, 0x72, 0x30f, 0x0, 0x72, 0x311, 0x0, 0x72, 0x323, 0x0, 0x72, 0x323, 0x304, 0x0, 0x72, 0x327, 0x0, 0x72, 0x331, 0x0, 0x73, 0x0, 0x73, 0x72, 0x0, 0x73, 0x74, 0x0, 0x73, 0x301, 0x0, 0x73, 0x301, 0x307, 0x0, 0x73, 0x302, 0x0, 0x73, 0x307, 0x0, 0x73, 0x30c, 0x0, 0x73, 0x30c, 0x307, 0x0, 0x73, 0x323, 0x0, 0x73, 0x323, 0x307, 0x0, 0x73, 0x326, 0x0, 0x73, 0x327, 0x0, 0x74, 0x0, 0x74, 0x307, 0x0, 0x74, 0x308, 0x0, 0x74, 0x30c, 0x0, 0x74, 0x323, 0x0, 0x74, 0x326, 0x0, 0x74, 0x327, 0x0, 0x74, 0x32d, 0x0, 0x74, 0x331, 0x0, 0x75, 0x0, 0x75, 0x300, 0x0, 0x75, 0x301, 0x0, 0x75, 0x302, 0x0, 0x75, 0x303, 0x0, 0x75, 0x303, 0x301, 0x0, 0x75, 0x304, 0x0, 0x75, 0x304, 0x308, 0x0, 0x75, 0x306, 0x0, 0x75, 0x308, 0x0, 0x75, 0x308, 0x300, 0x0, 0x75, 0x308, 0x301, 0x0, 0x75, 0x308, 0x304, 0x0, 0x75, 0x308, 0x30c, 0x0, 0x75, 0x309, 0x0, 0x75, 0x30a, 0x0, 0x75, 0x30b, 0x0, 0x75, 0x30c, 0x0, 0x75, 0x30f, 0x0, 0x75, 0x311, 0x0, 0x75, 0x31b, 0x0, 0x75, 0x31b, 0x300, 0x0, 0x75, 0x31b, 0x301, 0x0, 0x75, 0x31b, 0x303, 0x0, 0x75, 0x31b, 0x309, 0x0, 0x75, 0x31b, 0x323, 0x0, 0x75, 0x323, 0x0, 0x75, 0x324, 0x0, 0x75, 0x328, 0x0, 0x75, 0x32d, 0x0, 0x75, 0x330, 0x0, 0x76, 0x0, 0x76, 0x69, 0x0, 0x76, 0x69, 0x69, 0x0, 0x76, 0x69, 0x69, 0x69, 0x0, 0x76, 0x303, 0x0, 0x76, 0x323, 0x0, 0x77, 0x0, 0x77, 0x300, 0x0, 0x77, 0x301, 0x0, 0x77, 0x302, 0x0, 0x77, 0x307, 0x0, 0x77, 0x308, 0x0, 0x77, 0x30a, 0x0, 0x77, 0x323, 0x0, 0x78, 0x0, 0x78, 0x69, 0x0, 0x78, 0x69, 0x69, 0x0, 0x78, 0x307, 0x0, 0x78, 0x308, 0x0, 0x79, 0x0, 0x79, 0x300, 0x0, 0x79, 0x301, 0x0, 0x79, 0x302, 0x0, 0x79, 0x303, 0x0, 0x79, 0x304, 0x0, 0x79, 0x307, 0x0, 0x79, 0x308, 0x0, 0x79, 0x309, 0x0, 0x79, 0x30a, 0x0, 0x79, 0x323, 0x0, 0x7a, 0x0, 0x7a, 0x301, 0x0, 0x7a, 0x302, 0x0, 0x7a, 0x307, 0x0, 0x7a, 0x30c, 0x0, 0x7a, 0x323, 0x0, 0x7a, 0x331, 0x0, 0x7b, 0x0, 0x7c, 0x0, 0x7d, 0x0, 0x7e, 0x0, 0xa2, 0x0, 0xa3, 0x0, 0xa5, 0x0, 0xa6, 0x0, 0xac, 0x0, 0xb0, 0x43, 0x0, 0xb0, 0x46, 0x0, 0xb7, 0x0, 0xc6, 0x0, 0xc6, 0x301, 0x0, 0xc6, 0x304, 0x0, 0xd8, 0x301, 0x0, 0xe6, 0x301, 0x0, 0xe6, 0x304, 0x0, 0xf0, 0x0, 0xf8, 0x301, 0x0, 0x126, 0x0, 0x127, 0x0, 0x131, 0x0, 0x14b, 0x0, 0x153, 0x0, 0x18e, 0x0, 0x190, 0x0, 0x1ab, 0x0, 0x1b7, 0x30c, 0x0, 0x222, 0x0, 0x237, 0x0, 0x250, 0x0, 0x251, 0x0, 0x252, 0x0, 0x254, 0x0, 0x255, 0x0, 0x259, 0x0, 0x25b, 0x0, 0x25c, 0x0, 0x25f, 0x0, 0x261, 0x0, 0x263, 0x0, 0x265, 0x0, 0x266, 0x0, 0x268, 0x0, 0x269, 0x0, 0x26a, 0x0, 0x26d, 0x0, 0x26f, 0x0, 0x270, 0x0, 0x271, 0x0, 0x272, 0x0, 0x273, 0x0, 0x274, 0x0, 0x275, 0x0, 0x278, 0x0, 0x279, 0x0, 0x27b, 0x0, 0x281, 0x0, 0x282, 0x0, 0x283, 0x0, 0x289, 0x0, 0x28a, 0x0, 0x28b, 0x0, 0x28c, 0x0, 0x290, 0x0, 0x291, 0x0, 0x292, 0x0, 0x292, 0x30c, 0x0, 0x295, 0x0, 0x29d, 0x0, 0x29f, 0x0, 0x2b9, 0x0, 0x2bc, 0x6e, 0x0, 0x300, 0x0, 0x301, 0x0, 0x308, 0x301, 0x0, 0x313, 0x0, 0x391, 0x0, 0x391, 0x300, 0x0, 0x391, 0x301, 0x0, 0x391, 0x304, 0x0, 0x391, 0x306, 0x0, 0x391, 0x313, 0x0, 0x391, 0x313, 0x300, 0x0, 0x391, 0x313, 0x300, 0x345, 0x0, 0x391, 0x313, 0x301, 0x0, 0x391, 0x313, 0x301, 0x345, 0x0, 0x391, 0x313, 0x342, 0x0, 0x391, 0x313, 0x342, 0x345, 0x0, 0x391, 0x313, 0x345, 0x0, 0x391, 0x314, 0x0, 0x391, 0x314, 0x300, 0x0, 0x391, 0x314, 0x300, 0x345, 0x0, 0x391, 0x314, 0x301, 0x0, 0x391, 0x314, 0x301, 0x345, 0x0, 0x391, 0x314, 0x342, 0x0, 0x391, 0x314, 0x342, 0x345, 0x0, 0x391, 0x314, 0x345, 0x0, 0x391, 0x345, 0x0, 0x392, 0x0, 0x393, 0x0, 0x394, 0x0, 0x395, 0x0, 0x395, 0x300, 0x0, 0x395, 0x301, 0x0, 0x395, 0x313, 0x0, 0x395, 0x313, 0x300, 0x0, 0x395, 0x313, 0x301, 0x0, 0x395, 0x314, 0x0, 0x395, 0x314, 0x300, 0x0, 0x395, 0x314, 0x301, 0x0, 0x396, 0x0, 0x397, 0x0, 0x397, 0x300, 0x0, 0x397, 0x301, 0x0, 0x397, 0x313, 0x0, 0x397, 0x313, 0x300, 0x0, 0x397, 0x313, 0x300, 0x345, 0x0, 0x397, 0x313, 0x301, 0x0, 0x397, 0x313, 0x301, 0x345, 0x0, 0x397, 0x313, 0x342, 0x0, 0x397, 0x313, 0x342, 0x345, 0x0, 0x397, 0x313, 0x345, 0x0, 0x397, 0x314, 0x0, 0x397, 0x314, 0x300, 0x0, 0x397, 0x314, 0x300, 0x345, 0x0, 0x397, 0x314, 0x301, 0x0, 0x397, 0x314, 0x301, 0x345, 0x0, 0x397, 0x314, 0x342, 0x0, 0x397, 0x314, 0x342, 0x345, 0x0, 0x397, 0x314, 0x345, 0x0, 0x397, 0x345, 0x0, 0x398, 0x0, 0x399, 0x0, 0x399, 0x300, 0x0, 0x399, 0x301, 0x0, 0x399, 0x304, 0x0, 0x399, 0x306, 0x0, 0x399, 0x308, 0x0, 0x399, 0x313, 0x0, 0x399, 0x313, 0x300, 0x0, 0x399, 0x313, 0x301, 0x0, 0x399, 0x313, 0x342, 0x0, 0x399, 0x314, 0x0, 0x399, 0x314, 0x300, 0x0, 0x399, 0x314, 0x301, 0x0, 0x399, 0x314, 0x342, 0x0, 0x39a, 0x0, 0x39b, 0x0, 0x39c, 0x0, 0x39d, 0x0, 0x39e, 0x0, 0x39f, 0x0, 0x39f, 0x300, 0x0, 0x39f, 0x301, 0x0, 0x39f, 0x313, 0x0, 0x39f, 0x313, 0x300, 0x0, 0x39f, 0x313, 0x301, 0x0, 0x39f, 0x314, 0x0, 0x39f, 0x314, 0x300, 0x0, 0x39f, 0x314, 0x301, 0x0, 0x3a0, 0x0, 0x3a1, 0x0, 0x3a1, 0x314, 0x0, 0x3a3, 0x0, 0x3a4, 0x0, 0x3a5, 0x0, 0x3a5, 0x300, 0x0, 0x3a5, 0x301, 0x0, 0x3a5, 0x304, 0x0, 0x3a5, 0x306, 0x0, 0x3a5, 0x308, 0x0, 0x3a5, 0x314, 0x0, 0x3a5, 0x314, 0x300, 0x0, 0x3a5, 0x314, 0x301, 0x0, 0x3a5, 0x314, 0x342, 0x0, 0x3a6, 0x0, 0x3a7, 0x0, 0x3a8, 0x0, 0x3a9, 0x0, 0x3a9, 0x300, 0x0, 0x3a9, 0x301, 0x0, 0x3a9, 0x313, 0x0, 0x3a9, 0x313, 0x300, 0x0, 0x3a9, 0x313, 0x300, 0x345, 0x0, 0x3a9, 0x313, 0x301, 0x0, 0x3a9, 0x313, 0x301, 0x345, 0x0, 0x3a9, 0x313, 0x342, 0x0, 0x3a9, 0x313, 0x342, 0x345, 0x0, 0x3a9, 0x313, 0x345, 0x0, 0x3a9, 0x314, 0x0, 0x3a9, 0x314, 0x300, 0x0, 0x3a9, 0x314, 0x300, 0x345, 0x0, 0x3a9, 0x314, 0x301, 0x0, 0x3a9, 0x314, 0x301, 0x345, 0x0, 0x3a9, 0x314, 0x342, 0x0, 0x3a9, 0x314, 0x342, 0x345, 0x0, 0x3a9, 0x314, 0x345, 0x0, 0x3a9, 0x345, 0x0, 0x3b1, 0x0, 0x3b1, 0x300, 0x0, 0x3b1, 0x300, 0x345, 0x0, 0x3b1, 0x301, 0x0, 0x3b1, 0x301, 0x345, 0x0, 0x3b1, 0x304, 0x0, 0x3b1, 0x306, 0x0, 0x3b1, 0x313, 0x0, 0x3b1, 0x313, 0x300, 0x0, 0x3b1, 0x313, 0x300, 0x345, 0x0, 0x3b1, 0x313, 0x301, 0x0, 0x3b1, 0x313, 0x301, 0x345, 0x0, 0x3b1, 0x313, 0x342, 0x0, 0x3b1, 0x313, 0x342, 0x345, 0x0, 0x3b1, 0x313, 0x345, 0x0, 0x3b1, 0x314, 0x0, 0x3b1, 0x314, 0x300, 0x0, 0x3b1, 0x314, 0x300, 0x345, 0x0, 0x3b1, 0x314, 0x301, 0x0, 0x3b1, 0x314, 0x301, 0x345, 0x0, 0x3b1, 0x314, 0x342, 0x0, 0x3b1, 0x314, 0x342, 0x345, 0x0, 0x3b1, 0x314, 0x345, 0x0, 0x3b1, 0x342, 0x0, 0x3b1, 0x342, 0x345, 0x0, 0x3b1, 0x345, 0x0, 0x3b2, 0x0, 0x3b3, 0x0, 0x3b4, 0x0, 0x3b5, 0x0, 0x3b5, 0x300, 0x0, 0x3b5, 0x301, 0x0, 0x3b5, 0x313, 0x0, 0x3b5, 0x313, 0x300, 0x0, 0x3b5, 0x313, 0x301, 0x0, 0x3b5, 0x314, 0x0, 0x3b5, 0x314, 0x300, 0x0, 0x3b5, 0x314, 0x301, 0x0, 0x3b6, 0x0, 0x3b7, 0x0, 0x3b7, 0x300, 0x0, 0x3b7, 0x300, 0x345, 0x0, 0x3b7, 0x301, 0x0, 0x3b7, 0x301, 0x345, 0x0, 0x3b7, 0x313, 0x0, 0x3b7, 0x313, 0x300, 0x0, 0x3b7, 0x313, 0x300, 0x345, 0x0, 0x3b7, 0x313, 0x301, 0x0, 0x3b7, 0x313, 0x301, 0x345, 0x0, 0x3b7, 0x313, 0x342, 0x0, 0x3b7, 0x313, 0x342, 0x345, 0x0, 0x3b7, 0x313, 0x345, 0x0, 0x3b7, 0x314, 0x0, 0x3b7, 0x314, 0x300, 0x0, 0x3b7, 0x314, 0x300, 0x345, 0x0, 0x3b7, 0x314, 0x301, 0x0, 0x3b7, 0x314, 0x301, 0x345, 0x0, 0x3b7, 0x314, 0x342, 0x0, 0x3b7, 0x314, 0x342, 0x345, 0x0, 0x3b7, 0x314, 0x345, 0x0, 0x3b7, 0x342, 0x0, 0x3b7, 0x342, 0x345, 0x0, 0x3b7, 0x345, 0x0, 0x3b8, 0x0, 0x3b9, 0x0, 0x3b9, 0x300, 0x0, 0x3b9, 0x301, 0x0, 0x3b9, 0x304, 0x0, 0x3b9, 0x306, 0x0, 0x3b9, 0x308, 0x0, 0x3b9, 0x308, 0x300, 0x0, 0x3b9, 0x308, 0x301, 0x0, 0x3b9, 0x308, 0x342, 0x0, 0x3b9, 0x313, 0x0, 0x3b9, 0x313, 0x300, 0x0, 0x3b9, 0x313, 0x301, 0x0, 0x3b9, 0x313, 0x342, 0x0, 0x3b9, 0x314, 0x0, 0x3b9, 0x314, 0x300, 0x0, 0x3b9, 0x314, 0x301, 0x0, 0x3b9, 0x314, 0x342, 0x0, 0x3b9, 0x342, 0x0, 0x3ba, 0x0, 0x3bb, 0x0, 0x3bc, 0x0, 0x3bc, 0x41, 0x0, 0x3bc, 0x46, 0x0, 0x3bc, 0x56, 0x0, 0x3bc, 0x57, 0x0, 0x3bc, 0x67, 0x0, 0x3bc, 0x6c, 0x0, 0x3bc, 0x6d, 0x0, 0x3bc, 0x73, 0x0, 0x3bd, 0x0, 0x3be, 0x0, 0x3bf, 0x0, 0x3bf, 0x300, 0x0, 0x3bf, 0x301, 0x0, 0x3bf, 0x313, 0x0, 0x3bf, 0x313, 0x300, 0x0, 0x3bf, 0x313, 0x301, 0x0, 0x3bf, 0x314, 0x0, 0x3bf, 0x314, 0x300, 0x0, 0x3bf, 0x314, 0x301, 0x0, 0x3c0, 0x0, 0x3c1, 0x0, 0x3c1, 0x313, 0x0, 0x3c1, 0x314, 0x0, 0x3c2, 0x0, 0x3c3, 0x0, 0x3c4, 0x0, 0x3c5, 0x0, 0x3c5, 0x300, 0x0, 0x3c5, 0x301, 0x0, 0x3c5, 0x304, 0x0, 0x3c5, 0x306, 0x0, 0x3c5, 0x308, 0x0, 0x3c5, 0x308, 0x300, 0x0, 0x3c5, 0x308, 0x301, 0x0, 0x3c5, 0x308, 0x342, 0x0, 0x3c5, 0x313, 0x0, 0x3c5, 0x313, 0x300, 0x0, 0x3c5, 0x313, 0x301, 0x0, 0x3c5, 0x313, 0x342, 0x0, 0x3c5, 0x314, 0x0, 0x3c5, 0x314, 0x300, 0x0, 0x3c5, 0x314, 0x301, 0x0, 0x3c5, 0x314, 0x342, 0x0, 0x3c5, 0x342, 0x0, 0x3c6, 0x0, 0x3c7, 0x0, 0x3c8, 0x0, 0x3c9, 0x0, 0x3c9, 0x300, 0x0, 0x3c9, 0x300, 0x345, 0x0, 0x3c9, 0x301, 0x0, 0x3c9, 0x301, 0x345, 0x0, 0x3c9, 0x313, 0x0, 0x3c9, 0x313, 0x300, 0x0, 0x3c9, 0x313, 0x300, 0x345, 0x0, 0x3c9, 0x313, 0x301, 0x0, 0x3c9, 0x313, 0x301, 0x345, 0x0, 0x3c9, 0x313, 0x342, 0x0, 0x3c9, 0x313, 0x342, 0x345, 0x0, 0x3c9, 0x313, 0x345, 0x0, 0x3c9, 0x314, 0x0, 0x3c9, 0x314, 0x300, 0x0, 0x3c9, 0x314, 0x300, 0x345, 0x0, 0x3c9, 0x314, 0x301, 0x0, 0x3c9, 0x314, 0x301, 0x345, 0x0, 0x3c9, 0x314, 0x342, 0x0, 0x3c9, 0x314, 0x342, 0x345, 0x0, 0x3c9, 0x314, 0x345, 0x0, 0x3c9, 0x342, 0x0, 0x3c9, 0x342, 0x345, 0x0, 0x3c9, 0x345, 0x0, 0x3dc, 0x0, 0x3dd, 0x0, 0x406, 0x308, 0x0, 0x410, 0x306, 0x0, 0x410, 0x308, 0x0, 0x413, 0x301, 0x0, 0x415, 0x300, 0x0, 0x415, 0x306, 0x0, 0x415, 0x308, 0x0, 0x416, 0x306, 0x0, 0x416, 0x308, 0x0, 0x417, 0x308, 0x0, 0x418, 0x300, 0x0, 0x418, 0x304, 0x0, 0x418, 0x306, 0x0, 0x418, 0x308, 0x0, 0x41a, 0x301, 0x0, 0x41e, 0x308, 0x0, 0x423, 0x304, 0x0, 0x423, 0x306, 0x0, 0x423, 0x308, 0x0, 0x423, 0x30b, 0x0, 0x427, 0x308, 0x0, 0x42b, 0x308, 0x0, 0x42d, 0x308, 0x0, 0x430, 0x306, 0x0, 0x430, 0x308, 0x0, 0x433, 0x301, 0x0, 0x435, 0x300, 0x0, 0x435, 0x306, 0x0, 0x435, 0x308, 0x0, 0x436, 0x306, 0x0, 0x436, 0x308, 0x0, 0x437, 0x308, 0x0, 0x438, 0x300, 0x0, 0x438, 0x304, 0x0, 0x438, 0x306, 0x0, 0x438, 0x308, 0x0, 0x43a, 0x301, 0x0, 0x43d, 0x0, 0x43e, 0x308, 0x0, 0x443, 0x304, 0x0, 0x443, 0x306, 0x0, 0x443, 0x308, 0x0, 0x443, 0x30b, 0x0, 0x447, 0x308, 0x0, 0x44b, 0x308, 0x0, 0x44d, 0x308, 0x0, 0x456, 0x308, 0x0, 0x474, 0x30f, 0x0, 0x475, 0x30f, 0x0, 0x4d8, 0x308, 0x0, 0x4d9, 0x308, 0x0, 0x4e8, 0x308, 0x0, 0x4e9, 0x308, 0x0, 0x565, 0x582, 0x0, 0x574, 0x565, 0x0, 0x574, 0x56b, 0x0, 0x574, 0x56d, 0x0, 0x574, 0x576, 0x0, 0x57e, 0x576, 0x0, 0x5d0, 0x0, 0x5d0, 0x5b7, 0x0, 0x5d0, 0x5b8, 0x0, 0x5d0, 0x5bc, 0x0, 0x5d0, 0x5dc, 0x0, 0x5d1, 0x0, 0x5d1, 0x5bc, 0x0, 0x5d1, 0x5bf, 0x0, 0x5d2, 0x0, 0x5d2, 0x5bc, 0x0, 0x5d3, 0x0, 0x5d3, 0x5bc, 0x0, 0x5d4, 0x0, 0x5d4, 0x5bc, 0x0, 0x5d5, 0x5b9, 0x0, 0x5d5, 0x5bc, 0x0, 0x5d6, 0x5bc, 0x0, 0x5d8, 0x5bc, 0x0, 0x5d9, 0x5b4, 0x0, 0x5d9, 0x5bc, 0x0, 0x5da, 0x5bc, 0x0, 0x5db, 0x0, 0x5db, 0x5bc, 0x0, 0x5db, 0x5bf, 0x0, 0x5dc, 0x0, 0x5dc, 0x5bc, 0x0, 0x5dd, 0x0, 0x5de, 0x5bc, 0x0, 0x5e0, 0x5bc, 0x0, 0x5e1, 0x5bc, 0x0, 0x5e2, 0x0, 0x5e3, 0x5bc, 0x0, 0x5e4, 0x5bc, 0x0, 0x5e4, 0x5bf, 0x0, 0x5e6, 0x5bc, 0x0, 0x5e7, 0x5bc, 0x0, 0x5e8, 0x0, 0x5e8, 0x5bc, 0x0, 0x5e9, 0x5bc, 0x0, 0x5e9, 0x5bc, 0x5c1, 0x0, 0x5e9, 0x5bc, 0x5c2, 0x0, 0x5e9, 0x5c1, 0x0, 0x5e9, 0x5c2, 0x0, 0x5ea, 0x0, 0x5ea, 0x5bc, 0x0, 0x5f2, 0x5b7, 0x0, 0x621, 0x0, 0x627, 0x0, 0x627, 0x643, 0x628, 0x631, 0x0, 0x627, 0x644, 0x644, 0x647, 0x0, 0x627, 0x64b, 0x0, 0x627, 0x653, 0x0, 0x627, 0x654, 0x0, 0x627, 0x655, 0x0, 0x627, 0x674, 0x0, 0x628, 0x0, 0x628, 0x62c, 0x0, 0x628, 0x62d, 0x0, 0x628, 0x62d, 0x64a, 0x0, 0x628, 0x62e, 0x0, 0x628, 0x62e, 0x64a, 0x0, 0x628, 0x631, 0x0, 0x628, 0x632, 0x0, 0x628, 0x645, 0x0, 0x628, 0x646, 0x0, 0x628, 0x647, 0x0, 0x628, 0x649, 0x0, 0x628, 0x64a, 0x0, 0x629, 0x0, 0x62a, 0x0, 0x62a, 0x62c, 0x0, 0x62a, 0x62c, 0x645, 0x0, 0x62a, 0x62c, 0x649, 0x0, 0x62a, 0x62c, 0x64a, 0x0, 0x62a, 0x62d, 0x0, 0x62a, 0x62d, 0x62c, 0x0, 0x62a, 0x62d, 0x645, 0x0, 0x62a, 0x62e, 0x0, 0x62a, 0x62e, 0x645, 0x0, 0x62a, 0x62e, 0x649, 0x0, 0x62a, 0x62e, 0x64a, 0x0, 0x62a, 0x631, 0x0, 0x62a, 0x632, 0x0, 0x62a, 0x645, 0x0, 0x62a, 0x645, 0x62c, 0x0, 0x62a, 0x645, 0x62d, 0x0, 0x62a, 0x645, 0x62e, 0x0, 0x62a, 0x645, 0x649, 0x0, 0x62a, 0x645, 0x64a, 0x0, 0x62a, 0x646, 0x0, 0x62a, 0x647, 0x0, 0x62a, 0x649, 0x0, 0x62a, 0x64a, 0x0, 0x62b, 0x0, 0x62b, 0x62c, 0x0, 0x62b, 0x631, 0x0, 0x62b, 0x632, 0x0, 0x62b, 0x645, 0x0, 0x62b, 0x646, 0x0, 0x62b, 0x647, 0x0, 0x62b, 0x649, 0x0, 0x62b, 0x64a, 0x0, 0x62c, 0x0, 0x62c, 0x62d, 0x0, 0x62c, 0x62d, 0x649, 0x0, 0x62c, 0x62d, 0x64a, 0x0, 0x62c, 0x644, 0x20, 0x62c, 0x644, 0x627, 0x644, 0x647, 0x0, 0x62c, 0x645, 0x0, 0x62c, 0x645, 0x62d, 0x0, 0x62c, 0x645, 0x649, 0x0, 0x62c, 0x645, 0x64a, 0x0, 0x62c, 0x649, 0x0, 0x62c, 0x64a, 0x0, 0x62d, 0x0, 0x62d, 0x62c, 0x0, 0x62d, 0x62c, 0x64a, 0x0, 0x62d, 0x645, 0x0, 0x62d, 0x645, 0x649, 0x0, 0x62d, 0x645, 0x64a, 0x0, 0x62d, 0x649, 0x0, 0x62d, 0x64a, 0x0, 0x62e, 0x0, 0x62e, 0x62c, 0x0, 0x62e, 0x62d, 0x0, 0x62e, 0x645, 0x0, 0x62e, 0x649, 0x0, 0x62e, 0x64a, 0x0, 0x62f, 0x0, 0x630, 0x0, 0x630, 0x670, 0x0, 0x631, 0x0, 0x631, 0x633, 0x648, 0x644, 0x0, 0x631, 0x670, 0x0, 0x631, 0x6cc, 0x627, 0x644, 0x0, 0x632, 0x0, 0x633, 0x0, 0x633, 0x62c, 0x0, 0x633, 0x62c, 0x62d, 0x0, 0x633, 0x62c, 0x649, 0x0, 0x633, 0x62d, 0x0, 0x633, 0x62d, 0x62c, 0x0, 0x633, 0x62e, 0x0, 0x633, 0x62e, 0x649, 0x0, 0x633, 0x62e, 0x64a, 0x0, 0x633, 0x631, 0x0, 0x633, 0x645, 0x0, 0x633, 0x645, 0x62c, 0x0, 0x633, 0x645, 0x62d, 0x0, 0x633, 0x645, 0x645, 0x0, 0x633, 0x647, 0x0, 0x633, 0x649, 0x0, 0x633, 0x64a, 0x0, 0x634, 0x0, 0x634, 0x62c, 0x0, 0x634, 0x62c, 0x64a, 0x0, 0x634, 0x62d, 0x0, 0x634, 0x62d, 0x645, 0x0, 0x634, 0x62d, 0x64a, 0x0, 0x634, 0x62e, 0x0, 0x634, 0x631, 0x0, 0x634, 0x645, 0x0, 0x634, 0x645, 0x62e, 0x0, 0x634, 0x645, 0x645, 0x0, 0x634, 0x647, 0x0, 0x634, 0x649, 0x0, 0x634, 0x64a, 0x0, 0x635, 0x0, 0x635, 0x62d, 0x0, 0x635, 0x62d, 0x62d, 0x0, 0x635, 0x62d, 0x64a, 0x0, 0x635, 0x62e, 0x0, 0x635, 0x631, 0x0, 0x635, 0x644, 0x639, 0x645, 0x0, 0x635, 0x644, 0x649, 0x0, 0x635, 0x644, 0x649, 0x20, 0x627, 0x644, 0x644, 0x647, 0x20, 0x639, 0x644, 0x64a, 0x647, 0x20, 0x648, 0x633, 0x644, 0x645, 0x0, 0x635, 0x644, 0x6d2, 0x0, 0x635, 0x645, 0x0, 0x635, 0x645, 0x645, 0x0, 0x635, 0x649, 0x0, 0x635, 0x64a, 0x0, 0x636, 0x0, 0x636, 0x62c, 0x0, 0x636, 0x62d, 0x0, 0x636, 0x62d, 0x649, 0x0, 0x636, 0x62d, 0x64a, 0x0, 0x636, 0x62e, 0x0, 0x636, 0x62e, 0x645, 0x0, 0x636, 0x631, 0x0, 0x636, 0x645, 0x0, 0x636, 0x649, 0x0, 0x636, 0x64a, 0x0, 0x637, 0x0, 0x637, 0x62d, 0x0, 0x637, 0x645, 0x0, 0x637, 0x645, 0x62d, 0x0, 0x637, 0x645, 0x645, 0x0, 0x637, 0x645, 0x64a, 0x0, 0x637, 0x649, 0x0, 0x637, 0x64a, 0x0, 0x638, 0x0, 0x638, 0x645, 0x0, 0x639, 0x0, 0x639, 0x62c, 0x0, 0x639, 0x62c, 0x645, 0x0, 0x639, 0x644, 0x64a, 0x647, 0x0, 0x639, 0x645, 0x0, 0x639, 0x645, 0x645, 0x0, 0x639, 0x645, 0x649, 0x0, 0x639, 0x645, 0x64a, 0x0, 0x639, 0x649, 0x0, 0x639, 0x64a, 0x0, 0x63a, 0x0, 0x63a, 0x62c, 0x0, 0x63a, 0x645, 0x0, 0x63a, 0x645, 0x645, 0x0, 0x63a, 0x645, 0x649, 0x0, 0x63a, 0x645, 0x64a, 0x0, 0x63a, 0x649, 0x0, 0x63a, 0x64a, 0x0, 0x640, 0x64b, 0x0, 0x640, 0x64e, 0x0, 0x640, 0x64e, 0x651, 0x0, 0x640, 0x64f, 0x0, 0x640, 0x64f, 0x651, 0x0, 0x640, 0x650, 0x0, 0x640, 0x650, 0x651, 0x0, 0x640, 0x651, 0x0, 0x640, 0x652, 0x0, 0x641, 0x0, 0x641, 0x62c, 0x0, 0x641, 0x62d, 0x0, 0x641, 0x62e, 0x0, 0x641, 0x62e, 0x645, 0x0, 0x641, 0x645, 0x0, 0x641, 0x645, 0x64a, 0x0, 0x641, 0x649, 0x0, 0x641, 0x64a, 0x0, 0x642, 0x0, 0x642, 0x62d, 0x0, 0x642, 0x644, 0x6d2, 0x0, 0x642, 0x645, 0x0, 0x642, 0x645, 0x62d, 0x0, 0x642, 0x645, 0x645, 0x0, 0x642, 0x645, 0x64a, 0x0, 0x642, 0x649, 0x0, 0x642, 0x64a, 0x0, 0x643, 0x0, 0x643, 0x627, 0x0, 0x643, 0x62c, 0x0, 0x643, 0x62d, 0x0, 0x643, 0x62e, 0x0, 0x643, 0x644, 0x0, 0x643, 0x645, 0x0, 0x643, 0x645, 0x645, 0x0, 0x643, 0x645, 0x64a, 0x0, 0x643, 0x649, 0x0, 0x643, 0x64a, 0x0, 0x644, 0x0, 0x644, 0x627, 0x0, 0x644, 0x627, 0x653, 0x0, 0x644, 0x627, 0x654, 0x0, 0x644, 0x627, 0x655, 0x0, 0x644, 0x62c, 0x0, 0x644, 0x62c, 0x62c, 0x0, 0x644, 0x62c, 0x645, 0x0, 0x644, 0x62c, 0x64a, 0x0, 0x644, 0x62d, 0x0, 0x644, 0x62d, 0x645, 0x0, 0x644, 0x62d, 0x649, 0x0, 0x644, 0x62d, 0x64a, 0x0, 0x644, 0x62e, 0x0, 0x644, 0x62e, 0x645, 0x0, 0x644, 0x645, 0x0, 0x644, 0x645, 0x62d, 0x0, 0x644, 0x645, 0x64a, 0x0, 0x644, 0x647, 0x0, 0x644, 0x649, 0x0, 0x644, 0x64a, 0x0, 0x645, 0x0, 0x645, 0x627, 0x0, 0x645, 0x62c, 0x0, 0x645, 0x62c, 0x62d, 0x0, 0x645, 0x62c, 0x62e, 0x0, 0x645, 0x62c, 0x645, 0x0, 0x645, 0x62c, 0x64a, 0x0, 0x645, 0x62d, 0x0, 0x645, 0x62d, 0x62c, 0x0, 0x645, 0x62d, 0x645, 0x0, 0x645, 0x62d, 0x645, 0x62f, 0x0, 0x645, 0x62d, 0x64a, 0x0, 0x645, 0x62e, 0x0, 0x645, 0x62e, 0x62c, 0x0, 0x645, 0x62e, 0x645, 0x0, 0x645, 0x62e, 0x64a, 0x0, 0x645, 0x645, 0x0, 0x645, 0x645, 0x64a, 0x0, 0x645, 0x649, 0x0, 0x645, 0x64a, 0x0, 0x646, 0x0, 0x646, 0x62c, 0x0, 0x646, 0x62c, 0x62d, 0x0, 0x646, 0x62c, 0x645, 0x0, 0x646, 0x62c, 0x649, 0x0, 0x646, 0x62c, 0x64a, 0x0, 0x646, 0x62d, 0x0, 0x646, 0x62d, 0x645, 0x0, 0x646, 0x62d, 0x649, 0x0, 0x646, 0x62d, 0x64a, 0x0, 0x646, 0x62e, 0x0, 0x646, 0x631, 0x0, 0x646, 0x632, 0x0, 0x646, 0x645, 0x0, 0x646, 0x645, 0x649, 0x0, 0x646, 0x645, 0x64a, 0x0, 0x646, 0x646, 0x0, 0x646, 0x647, 0x0, 0x646, 0x649, 0x0, 0x646, 0x64a, 0x0, 0x647, 0x0, 0x647, 0x62c, 0x0, 0x647, 0x645, 0x0, 0x647, 0x645, 0x62c, 0x0, 0x647, 0x645, 0x645, 0x0, 0x647, 0x649, 0x0, 0x647, 0x64a, 0x0, 0x647, 0x670, 0x0, 0x648, 0x0, 0x648, 0x633, 0x644, 0x645, 0x0, 0x648, 0x654, 0x0, 0x648, 0x674, 0x0, 0x649, 0x0, 0x649, 0x670, 0x0, 0x64a, 0x0, 0x64a, 0x62c, 0x0, 0x64a, 0x62c, 0x64a, 0x0, 0x64a, 0x62d, 0x0, 0x64a, 0x62d, 0x64a, 0x0, 0x64a, 0x62e, 0x0, 0x64a, 0x631, 0x0, 0x64a, 0x632, 0x0, 0x64a, 0x645, 0x0, 0x64a, 0x645, 0x645, 0x0, 0x64a, 0x645, 0x64a, 0x0, 0x64a, 0x646, 0x0, 0x64a, 0x647, 0x0, 0x64a, 0x649, 0x0, 0x64a, 0x64a, 0x0, 0x64a, 0x654, 0x0, 0x64a, 0x654, 0x627, 0x0, 0x64a, 0x654, 0x62c, 0x0, 0x64a, 0x654, 0x62d, 0x0, 0x64a, 0x654, 0x62e, 0x0, 0x64a, 0x654, 0x631, 0x0, 0x64a, 0x654, 0x632, 0x0, 0x64a, 0x654, 0x645, 0x0, 0x64a, 0x654, 0x646, 0x0, 0x64a, 0x654, 0x647, 0x0, 0x64a, 0x654, 0x648, 0x0, 0x64a, 0x654, 0x649, 0x0, 0x64a, 0x654, 0x64a, 0x0, 0x64a, 0x654, 0x6c6, 0x0, 0x64a, 0x654, 0x6c7, 0x0, 0x64a, 0x654, 0x6c8, 0x0, 0x64a, 0x654, 0x6d0, 0x0, 0x64a, 0x654, 0x6d5, 0x0, 0x64a, 0x674, 0x0, 0x66e, 0x0, 0x66f, 0x0, 0x671, 0x0, 0x679, 0x0, 0x67a, 0x0, 0x67b, 0x0, 0x67e, 0x0, 0x67f, 0x0, 0x680, 0x0, 0x683, 0x0, 0x684, 0x0, 0x686, 0x0, 0x687, 0x0, 0x688, 0x0, 0x68c, 0x0, 0x68d, 0x0, 0x68e, 0x0, 0x691, 0x0, 0x698, 0x0, 0x6a1, 0x0, 0x6a4, 0x0, 0x6a6, 0x0, 0x6a9, 0x0, 0x6ad, 0x0, 0x6af, 0x0, 0x6b1, 0x0, 0x6b3, 0x0, 0x6ba, 0x0, 0x6bb, 0x0, 0x6be, 0x0, 0x6c1, 0x0, 0x6c1, 0x654, 0x0, 0x6c5, 0x0, 0x6c6, 0x0, 0x6c7, 0x0, 0x6c7, 0x674, 0x0, 0x6c8, 0x0, 0x6c9, 0x0, 0x6cb, 0x0, 0x6cc, 0x0, 0x6d0, 0x0, 0x6d2, 0x0, 0x6d2, 0x654, 0x0, 0x6d5, 0x654, 0x0, 0x915, 0x93c, 0x0, 0x916, 0x93c, 0x0, 0x917, 0x93c, 0x0, 0x91c, 0x93c, 0x0, 0x921, 0x93c, 0x0, 0x922, 0x93c, 0x0, 0x928, 0x93c, 0x0, 0x92b, 0x93c, 0x0, 0x92f, 0x93c, 0x0, 0x930, 0x93c, 0x0, 0x933, 0x93c, 0x0, 0x9a1, 0x9bc, 0x0, 0x9a2, 0x9bc, 0x0, 0x9af, 0x9bc, 0x0, 0x9c7, 0x9be, 0x0, 0x9c7, 0x9d7, 0x0, 0xa16, 0xa3c, 0x0, 0xa17, 0xa3c, 0x0, 0xa1c, 0xa3c, 0x0, 0xa2b, 0xa3c, 0x0, 0xa32, 0xa3c, 0x0, 0xa38, 0xa3c, 0x0, 0xb21, 0xb3c, 0x0, 0xb22, 0xb3c, 0x0, 0xb47, 0xb3e, 0x0, 0xb47, 0xb56, 0x0, 0xb47, 0xb57, 0x0, 0xb92, 0xbd7, 0x0, 0xbc6, 0xbbe, 0x0, 0xbc6, 0xbd7, 0x0, 0xbc7, 0xbbe, 0x0, 0xc46, 0xc56, 0x0, 0xcbf, 0xcd5, 0x0, 0xcc6, 0xcc2, 0x0, 0xcc6, 0xcc2, 0xcd5, 0x0, 0xcc6, 0xcd5, 0x0, 0xcc6, 0xcd6, 0x0, 0xd46, 0xd3e, 0x0, 0xd46, 0xd57, 0x0, 0xd47, 0xd3e, 0x0, 0xdd9, 0xdca, 0x0, 0xdd9, 0xdcf, 0x0, 0xdd9, 0xdcf, 0xdca, 0x0, 0xdd9, 0xddf, 0x0, 0xe4d, 0xe32, 0x0, 0xeab, 0xe99, 0x0, 0xeab, 0xea1, 0x0, 0xecd, 0xeb2, 0x0, 0xf0b, 0x0, 0xf40, 0xfb5, 0x0, 0xf42, 0xfb7, 0x0, 0xf4c, 0xfb7, 0x0, 0xf51, 0xfb7, 0x0, 0xf56, 0xfb7, 0x0, 0xf5b, 0xfb7, 0x0, 0xf71, 0xf72, 0x0, 0xf71, 0xf74, 0x0, 0xf71, 0xf80, 0x0, 0xf90, 0xfb5, 0x0, 0xf92, 0xfb7, 0x0, 0xf9c, 0xfb7, 0x0, 0xfa1, 0xfb7, 0x0, 0xfa6, 0xfb7, 0x0, 0xfab, 0xfb7, 0x0, 0xfb2, 0xf71, 0xf80, 0x0, 0xfb2, 0xf80, 0x0, 0xfb3, 0xf71, 0xf80, 0x0, 0xfb3, 0xf80, 0x0, 0x1025, 0x102e, 0x0, 0x10dc, 0x0, 0x1100, 0x0, 0x1100, 0x1161, 0x0, 0x1101, 0x0, 0x1102, 0x0, 0x1102, 0x1161, 0x0, 0x1103, 0x0, 0x1103, 0x1161, 0x0, 0x1104, 0x0, 0x1105, 0x0, 0x1105, 0x1161, 0x0, 0x1106, 0x0, 0x1106, 0x1161, 0x0, 0x1107, 0x0, 0x1107, 0x1161, 0x0, 0x1108, 0x0, 0x1109, 0x0, 0x1109, 0x1161, 0x0, 0x110a, 0x0, 0x110b, 0x0, 0x110b, 0x1161, 0x0, 0x110b, 0x116e, 0x0, 0x110c, 0x0, 0x110c, 0x1161, 0x0, 0x110c, 0x116e, 0x110b, 0x1174, 0x0, 0x110d, 0x0, 0x110e, 0x0, 0x110e, 0x1161, 0x0, 0x110e, 0x1161, 0x11b7, 0x1100, 0x1169, 0x0, 0x110f, 0x0, 0x110f, 0x1161, 0x0, 0x1110, 0x0, 0x1110, 0x1161, 0x0, 0x1111, 0x0, 0x1111, 0x1161, 0x0, 0x1112, 0x0, 0x1112, 0x1161, 0x0, 0x1114, 0x0, 0x1115, 0x0, 0x111a, 0x0, 0x111c, 0x0, 0x111d, 0x0, 0x111e, 0x0, 0x1120, 0x0, 0x1121, 0x0, 0x1122, 0x0, 0x1123, 0x0, 0x1127, 0x0, 0x1129, 0x0, 0x112b, 0x0, 0x112c, 0x0, 0x112d, 0x0, 0x112e, 0x0, 0x112f, 0x0, 0x1132, 0x0, 0x1136, 0x0, 0x1140, 0x0, 0x1147, 0x0, 0x114c, 0x0, 0x1157, 0x0, 0x1158, 0x0, 0x1159, 0x0, 0x1160, 0x0, 0x1161, 0x0, 0x1162, 0x0, 0x1163, 0x0, 0x1164, 0x0, 0x1165, 0x0, 0x1166, 0x0, 0x1167, 0x0, 0x1168, 0x0, 0x1169, 0x0, 0x116a, 0x0, 0x116b, 0x0, 0x116c, 0x0, 0x116d, 0x0, 0x116e, 0x0, 0x116f, 0x0, 0x1170, 0x0, 0x1171, 0x0, 0x1172, 0x0, 0x1173, 0x0, 0x1174, 0x0, 0x1175, 0x0, 0x1184, 0x0, 0x1185, 0x0, 0x1188, 0x0, 0x1191, 0x0, 0x1192, 0x0, 0x1194, 0x0, 0x119e, 0x0, 0x11a1, 0x0, 0x11aa, 0x0, 0x11ac, 0x0, 0x11ad, 0x0, 0x11b0, 0x0, 0x11b1, 0x0, 0x11b2, 0x0, 0x11b3, 0x0, 0x11b4, 0x0, 0x11b5, 0x0, 0x11c7, 0x0, 0x11c8, 0x0, 0x11cc, 0x0, 0x11ce, 0x0, 0x11d3, 0x0, 0x11d7, 0x0, 0x11d9, 0x0, 0x11dd, 0x0, 0x11df, 0x0, 0x11f1, 0x0, 0x11f2, 0x0, 0x1b05, 0x1b35, 0x0, 0x1b07, 0x1b35, 0x0, 0x1b09, 0x1b35, 0x0, 0x1b0b, 0x1b35, 0x0, 0x1b0d, 0x1b35, 0x0, 0x1b11, 0x1b35, 0x0, 0x1b3a, 0x1b35, 0x0, 0x1b3c, 0x1b35, 0x0, 0x1b3e, 0x1b35, 0x0, 0x1b3f, 0x1b35, 0x0, 0x1b42, 0x1b35, 0x0, 0x1d02, 0x0, 0x1d16, 0x0, 0x1d17, 0x0, 0x1d1c, 0x0, 0x1d1d, 0x0, 0x1d25, 0x0, 0x1d7b, 0x0, 0x1d85, 0x0, 0x2010, 0x0, 0x2013, 0x0, 0x2014, 0x0, 0x2032, 0x2032, 0x0, 0x2032, 0x2032, 0x2032, 0x0, 0x2032, 0x2032, 0x2032, 0x2032, 0x0, 0x2035, 0x2035, 0x0, 0x2035, 0x2035, 0x2035, 0x0, 0x20a9, 0x0, 0x2190, 0x0, 0x2190, 0x338, 0x0, 0x2191, 0x0, 0x2192, 0x0, 0x2192, 0x338, 0x0, 0x2193, 0x0, 0x2194, 0x338, 0x0, 0x21d0, 0x338, 0x0, 0x21d2, 0x338, 0x0, 0x21d4, 0x338, 0x0, 0x2202, 0x0, 0x2203, 0x338, 0x0, 0x2207, 0x0, 0x2208, 0x338, 0x0, 0x220b, 0x338, 0x0, 0x2211, 0x0, 0x2212, 0x0, 0x2223, 0x338, 0x0, 0x2225, 0x338, 0x0, 0x222b, 0x222b, 0x0, 0x222b, 0x222b, 0x222b, 0x0, 0x222b, 0x222b, 0x222b, 0x222b, 0x0, 0x222e, 0x222e, 0x0, 0x222e, 0x222e, 0x222e, 0x0, 0x223c, 0x338, 0x0, 0x2243, 0x338, 0x0, 0x2245, 0x338, 0x0, 0x2248, 0x338, 0x0, 0x224d, 0x338, 0x0, 0x2261, 0x338, 0x0, 0x2264, 0x338, 0x0, 0x2265, 0x338, 0x0, 0x2272, 0x338, 0x0, 0x2273, 0x338, 0x0, 0x2276, 0x338, 0x0, 0x2277, 0x338, 0x0, 0x227a, 0x338, 0x0, 0x227b, 0x338, 0x0, 0x227c, 0x338, 0x0, 0x227d, 0x338, 0x0, 0x2282, 0x338, 0x0, 0x2283, 0x338, 0x0, 0x2286, 0x338, 0x0, 0x2287, 0x338, 0x0, 0x2291, 0x338, 0x0, 0x2292, 0x338, 0x0, 0x22a2, 0x338, 0x0, 0x22a8, 0x338, 0x0, 0x22a9, 0x338, 0x0, 0x22ab, 0x338, 0x0, 0x22b2, 0x338, 0x0, 0x22b3, 0x338, 0x0, 0x22b4, 0x338, 0x0, 0x22b5, 0x338, 0x0, 0x2502, 0x0, 0x25a0, 0x0, 0x25cb, 0x0, 0x2985, 0x0, 0x2986, 0x0, 0x2add, 0x338, 0x0, 0x2d61, 0x0, 0x3001, 0x0, 0x3002, 0x0, 0x3008, 0x0, 0x3009, 0x0, 0x300a, 0x0, 0x300b, 0x0, 0x300c, 0x0, 0x300d, 0x0, 0x300e, 0x0, 0x300f, 0x0, 0x3010, 0x0, 0x3011, 0x0, 0x3012, 0x0, 0x3014, 0x0, 0x3014, 0x53, 0x3015, 0x0, 0x3014, 0x4e09, 0x3015, 0x0, 0x3014, 0x4e8c, 0x3015, 0x0, 0x3014, 0x52dd, 0x3015, 0x0, 0x3014, 0x5b89, 0x3015, 0x0, 0x3014, 0x6253, 0x3015, 0x0, 0x3014, 0x6557, 0x3015, 0x0, 0x3014, 0x672c, 0x3015, 0x0, 0x3014, 0x70b9, 0x3015, 0x0, 0x3014, 0x76d7, 0x3015, 0x0, 0x3015, 0x0, 0x3016, 0x0, 0x3017, 0x0, 0x3046, 0x3099, 0x0, 0x304b, 0x3099, 0x0, 0x304d, 0x3099, 0x0, 0x304f, 0x3099, 0x0, 0x3051, 0x3099, 0x0, 0x3053, 0x3099, 0x0, 0x3055, 0x3099, 0x0, 0x3057, 0x3099, 0x0, 0x3059, 0x3099, 0x0, 0x305b, 0x3099, 0x0, 0x305d, 0x3099, 0x0, 0x305f, 0x3099, 0x0, 0x3061, 0x3099, 0x0, 0x3064, 0x3099, 0x0, 0x3066, 0x3099, 0x0, 0x3068, 0x3099, 0x0, 0x306f, 0x3099, 0x0, 0x306f, 0x309a, 0x0, 0x3072, 0x3099, 0x0, 0x3072, 0x309a, 0x0, 0x3075, 0x3099, 0x0, 0x3075, 0x309a, 0x0, 0x3078, 0x3099, 0x0, 0x3078, 0x309a, 0x0, 0x307b, 0x304b, 0x0, 0x307b, 0x3099, 0x0, 0x307b, 0x309a, 0x0, 0x3088, 0x308a, 0x0, 0x3099, 0x0, 0x309a, 0x0, 0x309d, 0x3099, 0x0, 0x30a1, 0x0, 0x30a2, 0x0, 0x30a2, 0x30cf, 0x309a, 0x30fc, 0x30c8, 0x0, 0x30a2, 0x30eb, 0x30d5, 0x30a1, 0x0, 0x30a2, 0x30f3, 0x30d8, 0x309a, 0x30a2, 0x0, 0x30a2, 0x30fc, 0x30eb, 0x0, 0x30a3, 0x0, 0x30a4, 0x0, 0x30a4, 0x30cb, 0x30f3, 0x30af, 0x3099, 0x0, 0x30a4, 0x30f3, 0x30c1, 0x0, 0x30a5, 0x0, 0x30a6, 0x0, 0x30a6, 0x3099, 0x0, 0x30a6, 0x30a9, 0x30f3, 0x0, 0x30a7, 0x0, 0x30a8, 0x0, 0x30a8, 0x30b9, 0x30af, 0x30fc, 0x30c8, 0x3099, 0x0, 0x30a8, 0x30fc, 0x30ab, 0x30fc, 0x0, 0x30a9, 0x0, 0x30aa, 0x0, 0x30aa, 0x30f3, 0x30b9, 0x0, 0x30aa, 0x30fc, 0x30e0, 0x0, 0x30ab, 0x0, 0x30ab, 0x3099, 0x0, 0x30ab, 0x3099, 0x30ed, 0x30f3, 0x0, 0x30ab, 0x3099, 0x30f3, 0x30de, 0x0, 0x30ab, 0x30a4, 0x30ea, 0x0, 0x30ab, 0x30e9, 0x30c3, 0x30c8, 0x0, 0x30ab, 0x30ed, 0x30ea, 0x30fc, 0x0, 0x30ad, 0x0, 0x30ad, 0x3099, 0x0, 0x30ad, 0x3099, 0x30ab, 0x3099, 0x0, 0x30ad, 0x3099, 0x30cb, 0x30fc, 0x0, 0x30ad, 0x3099, 0x30eb, 0x30bf, 0x3099, 0x30fc, 0x0, 0x30ad, 0x30e5, 0x30ea, 0x30fc, 0x0, 0x30ad, 0x30ed, 0x0, 0x30ad, 0x30ed, 0x30af, 0x3099, 0x30e9, 0x30e0, 0x0, 0x30ad, 0x30ed, 0x30e1, 0x30fc, 0x30c8, 0x30eb, 0x0, 0x30ad, 0x30ed, 0x30ef, 0x30c3, 0x30c8, 0x0, 0x30af, 0x0, 0x30af, 0x3099, 0x0, 0x30af, 0x3099, 0x30e9, 0x30e0, 0x0, 0x30af, 0x3099, 0x30e9, 0x30e0, 0x30c8, 0x30f3, 0x0, 0x30af, 0x30eb, 0x30bb, 0x3099, 0x30a4, 0x30ed, 0x0, 0x30af, 0x30ed, 0x30fc, 0x30cd, 0x0, 0x30b1, 0x0, 0x30b1, 0x3099, 0x0, 0x30b1, 0x30fc, 0x30b9, 0x0, 0x30b3, 0x0, 0x30b3, 0x3099, 0x0, 0x30b3, 0x30b3, 0x0, 0x30b3, 0x30c8, 0x0, 0x30b3, 0x30eb, 0x30ca, 0x0, 0x30b3, 0x30fc, 0x30db, 0x309a, 0x0, 0x30b5, 0x0, 0x30b5, 0x3099, 0x0, 0x30b5, 0x30a4, 0x30af, 0x30eb, 0x0, 0x30b5, 0x30f3, 0x30c1, 0x30fc, 0x30e0, 0x0, 0x30b7, 0x0, 0x30b7, 0x3099, 0x0, 0x30b7, 0x30ea, 0x30f3, 0x30af, 0x3099, 0x0, 0x30b9, 0x0, 0x30b9, 0x3099, 0x0, 0x30bb, 0x0, 0x30bb, 0x3099, 0x0, 0x30bb, 0x30f3, 0x30c1, 0x0, 0x30bb, 0x30f3, 0x30c8, 0x0, 0x30bd, 0x0, 0x30bd, 0x3099, 0x0, 0x30bf, 0x0, 0x30bf, 0x3099, 0x0, 0x30bf, 0x3099, 0x30fc, 0x30b9, 0x0, 0x30c1, 0x0, 0x30c1, 0x3099, 0x0, 0x30c3, 0x0, 0x30c4, 0x0, 0x30c4, 0x3099, 0x0, 0x30c6, 0x0, 0x30c6, 0x3099, 0x0, 0x30c6, 0x3099, 0x30b7, 0x0, 0x30c8, 0x0, 0x30c8, 0x3099, 0x0, 0x30c8, 0x3099, 0x30eb, 0x0, 0x30c8, 0x30f3, 0x0, 0x30ca, 0x0, 0x30ca, 0x30ce, 0x0, 0x30cb, 0x0, 0x30cc, 0x0, 0x30cd, 0x0, 0x30ce, 0x0, 0x30ce, 0x30c3, 0x30c8, 0x0, 0x30cf, 0x0, 0x30cf, 0x3099, 0x0, 0x30cf, 0x3099, 0x30fc, 0x30ec, 0x30eb, 0x0, 0x30cf, 0x309a, 0x0, 0x30cf, 0x309a, 0x30fc, 0x30bb, 0x30f3, 0x30c8, 0x0, 0x30cf, 0x309a, 0x30fc, 0x30c4, 0x0, 0x30cf, 0x30a4, 0x30c4, 0x0, 0x30d2, 0x0, 0x30d2, 0x3099, 0x0, 0x30d2, 0x3099, 0x30eb, 0x0, 0x30d2, 0x309a, 0x0, 0x30d2, 0x309a, 0x30a2, 0x30b9, 0x30c8, 0x30eb, 0x0, 0x30d2, 0x309a, 0x30af, 0x30eb, 0x0, 0x30d2, 0x309a, 0x30b3, 0x0, 0x30d5, 0x0, 0x30d5, 0x3099, 0x0, 0x30d5, 0x3099, 0x30c3, 0x30b7, 0x30a7, 0x30eb, 0x0, 0x30d5, 0x309a, 0x0, 0x30d5, 0x30a1, 0x30e9, 0x30c3, 0x30c8, 0x3099, 0x0, 0x30d5, 0x30a3, 0x30fc, 0x30c8, 0x0, 0x30d5, 0x30e9, 0x30f3, 0x0, 0x30d8, 0x0, 0x30d8, 0x3099, 0x0, 0x30d8, 0x3099, 0x30fc, 0x30bf, 0x0, 0x30d8, 0x309a, 0x0, 0x30d8, 0x309a, 0x30bd, 0x0, 0x30d8, 0x309a, 0x30cb, 0x30d2, 0x0, 0x30d8, 0x309a, 0x30f3, 0x30b9, 0x0, 0x30d8, 0x309a, 0x30fc, 0x30b7, 0x3099, 0x0, 0x30d8, 0x30af, 0x30bf, 0x30fc, 0x30eb, 0x0, 0x30d8, 0x30eb, 0x30c4, 0x0, 0x30db, 0x0, 0x30db, 0x3099, 0x0, 0x30db, 0x3099, 0x30eb, 0x30c8, 0x0, 0x30db, 0x309a, 0x0, 0x30db, 0x309a, 0x30a4, 0x30f3, 0x30c8, 0x0, 0x30db, 0x309a, 0x30f3, 0x30c8, 0x3099, 0x0, 0x30db, 0x30f3, 0x0, 0x30db, 0x30fc, 0x30eb, 0x0, 0x30db, 0x30fc, 0x30f3, 0x0, 0x30de, 0x0, 0x30de, 0x30a4, 0x30af, 0x30ed, 0x0, 0x30de, 0x30a4, 0x30eb, 0x0, 0x30de, 0x30c3, 0x30cf, 0x0, 0x30de, 0x30eb, 0x30af, 0x0, 0x30de, 0x30f3, 0x30b7, 0x30e7, 0x30f3, 0x0, 0x30df, 0x0, 0x30df, 0x30af, 0x30ed, 0x30f3, 0x0, 0x30df, 0x30ea, 0x0, 0x30df, 0x30ea, 0x30cf, 0x3099, 0x30fc, 0x30eb, 0x0, 0x30e0, 0x0, 0x30e1, 0x0, 0x30e1, 0x30ab, 0x3099, 0x0, 0x30e1, 0x30ab, 0x3099, 0x30c8, 0x30f3, 0x0, 0x30e1, 0x30fc, 0x30c8, 0x30eb, 0x0, 0x30e2, 0x0, 0x30e3, 0x0, 0x30e4, 0x0, 0x30e4, 0x30fc, 0x30c8, 0x3099, 0x0, 0x30e4, 0x30fc, 0x30eb, 0x0, 0x30e5, 0x0, 0x30e6, 0x0, 0x30e6, 0x30a2, 0x30f3, 0x0, 0x30e7, 0x0, 0x30e8, 0x0, 0x30e9, 0x0, 0x30ea, 0x0, 0x30ea, 0x30c3, 0x30c8, 0x30eb, 0x0, 0x30ea, 0x30e9, 0x0, 0x30eb, 0x0, 0x30eb, 0x30d2, 0x309a, 0x30fc, 0x0, 0x30eb, 0x30fc, 0x30d5, 0x3099, 0x30eb, 0x0, 0x30ec, 0x0, 0x30ec, 0x30e0, 0x0, 0x30ec, 0x30f3, 0x30c8, 0x30b1, 0x3099, 0x30f3, 0x0, 0x30ed, 0x0, 0x30ef, 0x0, 0x30ef, 0x3099, 0x0, 0x30ef, 0x30c3, 0x30c8, 0x0, 0x30f0, 0x0, 0x30f0, 0x3099, 0x0, 0x30f1, 0x0, 0x30f1, 0x3099, 0x0, 0x30f2, 0x0, 0x30f2, 0x3099, 0x0, 0x30f3, 0x0, 0x30fb, 0x0, 0x30fc, 0x0, 0x30fd, 0x3099, 0x0, 0x349e, 0x0, 0x34b9, 0x0, 0x34bb, 0x0, 0x34df, 0x0, 0x3515, 0x0, 0x36ee, 0x0, 0x36fc, 0x0, 0x3781, 0x0, 0x382f, 0x0, 0x3862, 0x0, 0x387c, 0x0, 0x38c7, 0x0, 0x38e3, 0x0, 0x391c, 0x0, 0x393a, 0x0, 0x3a2e, 0x0, 0x3a6c, 0x0, 0x3ae4, 0x0, 0x3b08, 0x0, 0x3b19, 0x0, 0x3b49, 0x0, 0x3b9d, 0x0, 0x3c18, 0x0, 0x3c4e, 0x0, 0x3d33, 0x0, 0x3d96, 0x0, 0x3eac, 0x0, 0x3eb8, 0x0, 0x3f1b, 0x0, 0x3ffc, 0x0, 0x4008, 0x0, 0x4018, 0x0, 0x4039, 0x0, 0x4046, 0x0, 0x4096, 0x0, 0x40e3, 0x0, 0x412f, 0x0, 0x4202, 0x0, 0x4227, 0x0, 0x42a0, 0x0, 0x4301, 0x0, 0x4334, 0x0, 0x4359, 0x0, 0x43d5, 0x0, 0x43d9, 0x0, 0x440b, 0x0, 0x446b, 0x0, 0x452b, 0x0, 0x455d, 0x0, 0x4561, 0x0, 0x456b, 0x0, 0x45d7, 0x0, 0x45f9, 0x0, 0x4635, 0x0, 0x46be, 0x0, 0x46c7, 0x0, 0x4995, 0x0, 0x49e6, 0x0, 0x4a6e, 0x0, 0x4a76, 0x0, 0x4ab2, 0x0, 0x4b33, 0x0, 0x4bce, 0x0, 0x4cce, 0x0, 0x4ced, 0x0, 0x4cf8, 0x0, 0x4d56, 0x0, 0x4e00, 0x0, 0x4e01, 0x0, 0x4e03, 0x0, 0x4e09, 0x0, 0x4e0a, 0x0, 0x4e0b, 0x0, 0x4e0d, 0x0, 0x4e19, 0x0, 0x4e26, 0x0, 0x4e28, 0x0, 0x4e2d, 0x0, 0x4e32, 0x0, 0x4e36, 0x0, 0x4e38, 0x0, 0x4e39, 0x0, 0x4e3d, 0x0, 0x4e3f, 0x0, 0x4e41, 0x0, 0x4e59, 0x0, 0x4e5d, 0x0, 0x4e82, 0x0, 0x4e85, 0x0, 0x4e86, 0x0, 0x4e8c, 0x0, 0x4e94, 0x0, 0x4ea0, 0x0, 0x4ea4, 0x0, 0x4eae, 0x0, 0x4eba, 0x0, 0x4ec0, 0x0, 0x4ecc, 0x0, 0x4ee4, 0x0, 0x4f01, 0x0, 0x4f11, 0x0, 0x4f60, 0x0, 0x4f80, 0x0, 0x4f86, 0x0, 0x4f8b, 0x0, 0x4fae, 0x0, 0x4fbb, 0x0, 0x4fbf, 0x0, 0x5002, 0x0, 0x502b, 0x0, 0x507a, 0x0, 0x5099, 0x0, 0x50cf, 0x0, 0x50da, 0x0, 0x50e7, 0x0, 0x512a, 0x0, 0x513f, 0x0, 0x5140, 0x0, 0x5145, 0x0, 0x514d, 0x0, 0x5154, 0x0, 0x5164, 0x0, 0x5165, 0x0, 0x5167, 0x0, 0x5168, 0x0, 0x5169, 0x0, 0x516b, 0x0, 0x516d, 0x0, 0x5177, 0x0, 0x5180, 0x0, 0x5182, 0x0, 0x518d, 0x0, 0x5192, 0x0, 0x5195, 0x0, 0x5196, 0x0, 0x5197, 0x0, 0x5199, 0x0, 0x51a4, 0x0, 0x51ab, 0x0, 0x51ac, 0x0, 0x51b5, 0x0, 0x51b7, 0x0, 0x51c9, 0x0, 0x51cc, 0x0, 0x51dc, 0x0, 0x51de, 0x0, 0x51e0, 0x0, 0x51f5, 0x0, 0x5200, 0x0, 0x5203, 0x0, 0x5207, 0x0, 0x5217, 0x0, 0x521d, 0x0, 0x5229, 0x0, 0x523a, 0x0, 0x523b, 0x0, 0x5246, 0x0, 0x524d, 0x0, 0x5272, 0x0, 0x5277, 0x0, 0x5289, 0x0, 0x529b, 0x0, 0x52a3, 0x0, 0x52b3, 0x0, 0x52b4, 0x0, 0x52c7, 0x0, 0x52c9, 0x0, 0x52d2, 0x0, 0x52de, 0x0, 0x52e4, 0x0, 0x52f5, 0x0, 0x52f9, 0x0, 0x52fa, 0x0, 0x5305, 0x0, 0x5306, 0x0, 0x5315, 0x0, 0x5317, 0x0, 0x531a, 0x0, 0x5338, 0x0, 0x533b, 0x0, 0x533f, 0x0, 0x5341, 0x0, 0x5344, 0x0, 0x5345, 0x0, 0x5349, 0x0, 0x5351, 0x0, 0x5354, 0x0, 0x535a, 0x0, 0x535c, 0x0, 0x5369, 0x0, 0x5370, 0x0, 0x5373, 0x0, 0x5375, 0x0, 0x537d, 0x0, 0x537f, 0x0, 0x5382, 0x0, 0x53b6, 0x0, 0x53c3, 0x0, 0x53c8, 0x0, 0x53ca, 0x0, 0x53cc, 0x0, 0x53df, 0x0, 0x53e3, 0x0, 0x53e5, 0x0, 0x53eb, 0x0, 0x53ef, 0x0, 0x53f1, 0x0, 0x53f3, 0x0, 0x5406, 0x0, 0x5408, 0x0, 0x540d, 0x0, 0x540f, 0x0, 0x541d, 0x0, 0x5438, 0x0, 0x5439, 0x0, 0x5442, 0x0, 0x5448, 0x0, 0x5468, 0x0, 0x549e, 0x0, 0x54a2, 0x0, 0x54bd, 0x0, 0x54f6, 0x0, 0x5510, 0x0, 0x554f, 0x0, 0x5553, 0x0, 0x5555, 0x0, 0x5563, 0x0, 0x5584, 0x0, 0x5587, 0x0, 0x5599, 0x0, 0x559d, 0x0, 0x55ab, 0x0, 0x55b3, 0x0, 0x55b6, 0x0, 0x55c0, 0x0, 0x55c2, 0x0, 0x55e2, 0x0, 0x5606, 0x0, 0x5651, 0x0, 0x5668, 0x0, 0x5674, 0x0, 0x56d7, 0x0, 0x56db, 0x0, 0x56f9, 0x0, 0x5716, 0x0, 0x5717, 0x0, 0x571f, 0x0, 0x5730, 0x0, 0x578b, 0x0, 0x57ce, 0x0, 0x57f4, 0x0, 0x580d, 0x0, 0x5831, 0x0, 0x5832, 0x0, 0x5840, 0x0, 0x585a, 0x0, 0x585e, 0x0, 0x58a8, 0x0, 0x58ac, 0x0, 0x58b3, 0x0, 0x58d8, 0x0, 0x58df, 0x0, 0x58eb, 0x0, 0x58ee, 0x0, 0x58f0, 0x0, 0x58f2, 0x0, 0x58f7, 0x0, 0x5902, 0x0, 0x5906, 0x0, 0x590a, 0x0, 0x5915, 0x0, 0x591a, 0x0, 0x591c, 0x0, 0x5922, 0x0, 0x5927, 0x0, 0x5927, 0x6b63, 0x0, 0x5929, 0x0, 0x5944, 0x0, 0x5948, 0x0, 0x5951, 0x0, 0x5954, 0x0, 0x5962, 0x0, 0x5973, 0x0, 0x59d8, 0x0, 0x59ec, 0x0, 0x5a1b, 0x0, 0x5a27, 0x0, 0x5a62, 0x0, 0x5a66, 0x0, 0x5ab5, 0x0, 0x5b08, 0x0, 0x5b28, 0x0, 0x5b3e, 0x0, 0x5b50, 0x0, 0x5b57, 0x0, 0x5b66, 0x0, 0x5b80, 0x0, 0x5b85, 0x0, 0x5b97, 0x0, 0x5bc3, 0x0, 0x5bd8, 0x0, 0x5be7, 0x0, 0x5bee, 0x0, 0x5bf3, 0x0, 0x5bf8, 0x0, 0x5bff, 0x0, 0x5c06, 0x0, 0x5c0f, 0x0, 0x5c22, 0x0, 0x5c38, 0x0, 0x5c3f, 0x0, 0x5c60, 0x0, 0x5c62, 0x0, 0x5c64, 0x0, 0x5c65, 0x0, 0x5c6e, 0x0, 0x5c71, 0x0, 0x5c8d, 0x0, 0x5cc0, 0x0, 0x5d19, 0x0, 0x5d43, 0x0, 0x5d50, 0x0, 0x5d6b, 0x0, 0x5d6e, 0x0, 0x5d7c, 0x0, 0x5db2, 0x0, 0x5dba, 0x0, 0x5ddb, 0x0, 0x5de1, 0x0, 0x5de2, 0x0, 0x5de5, 0x0, 0x5de6, 0x0, 0x5df1, 0x0, 0x5dfd, 0x0, 0x5dfe, 0x0, 0x5e28, 0x0, 0x5e3d, 0x0, 0x5e69, 0x0, 0x5e72, 0x0, 0x5e73, 0x6210, 0x0, 0x5e74, 0x0, 0x5e7a, 0x0, 0x5e7c, 0x0, 0x5e7f, 0x0, 0x5ea6, 0x0, 0x5eb0, 0x0, 0x5eb3, 0x0, 0x5eb6, 0x0, 0x5ec9, 0x0, 0x5eca, 0x0, 0x5ed2, 0x0, 0x5ed3, 0x0, 0x5ed9, 0x0, 0x5eec, 0x0, 0x5ef4, 0x0, 0x5efe, 0x0, 0x5f04, 0x0, 0x5f0b, 0x0, 0x5f13, 0x0, 0x5f22, 0x0, 0x5f50, 0x0, 0x5f53, 0x0, 0x5f61, 0x0, 0x5f62, 0x0, 0x5f69, 0x0, 0x5f6b, 0x0, 0x5f73, 0x0, 0x5f8b, 0x0, 0x5f8c, 0x0, 0x5f97, 0x0, 0x5f9a, 0x0, 0x5fa9, 0x0, 0x5fad, 0x0, 0x5fc3, 0x0, 0x5fcd, 0x0, 0x5fd7, 0x0, 0x5ff5, 0x0, 0x5ff9, 0x0, 0x6012, 0x0, 0x601c, 0x0, 0x6075, 0x0, 0x6081, 0x0, 0x6094, 0x0, 0x60c7, 0x0, 0x60d8, 0x0, 0x60e1, 0x0, 0x6108, 0x0, 0x6144, 0x0, 0x6148, 0x0, 0x614c, 0x0, 0x614e, 0x0, 0x6160, 0x0, 0x6168, 0x0, 0x617a, 0x0, 0x618e, 0x0, 0x6190, 0x0, 0x61a4, 0x0, 0x61af, 0x0, 0x61b2, 0x0, 0x61de, 0x0, 0x61f2, 0x0, 0x61f6, 0x0, 0x6200, 0x0, 0x6208, 0x0, 0x6210, 0x0, 0x621b, 0x0, 0x622e, 0x0, 0x6234, 0x0, 0x6236, 0x0, 0x624b, 0x0, 0x6253, 0x0, 0x625d, 0x0, 0x6295, 0x0, 0x62b1, 0x0, 0x62c9, 0x0, 0x62cf, 0x0, 0x62d3, 0x0, 0x62d4, 0x0, 0x62fc, 0x0, 0x62fe, 0x0, 0x6307, 0x0, 0x633d, 0x0, 0x6350, 0x0, 0x6355, 0x0, 0x6368, 0x0, 0x637b, 0x0, 0x6383, 0x0, 0x63a0, 0x0, 0x63a9, 0x0, 0x63c4, 0x0, 0x63c5, 0x0, 0x63e4, 0x0, 0x641c, 0x0, 0x6422, 0x0, 0x6452, 0x0, 0x6469, 0x0, 0x6477, 0x0, 0x647e, 0x0, 0x649a, 0x0, 0x649d, 0x0, 0x64c4, 0x0, 0x652f, 0x0, 0x6534, 0x0, 0x654f, 0x0, 0x6556, 0x0, 0x656c, 0x0, 0x6578, 0x0, 0x6587, 0x0, 0x6597, 0x0, 0x6599, 0x0, 0x65a4, 0x0, 0x65b0, 0x0, 0x65b9, 0x0, 0x65c5, 0x0, 0x65e0, 0x0, 0x65e2, 0x0, 0x65e3, 0x0, 0x65e5, 0x0, 0x660e, 0x6cbb, 0x0, 0x6613, 0x0, 0x6620, 0x0, 0x662d, 0x548c, 0x0, 0x6649, 0x0, 0x6674, 0x0, 0x6688, 0x0, 0x6691, 0x0, 0x669c, 0x0, 0x66b4, 0x0, 0x66c6, 0x0, 0x66f0, 0x0, 0x66f4, 0x0, 0x66f8, 0x0, 0x6700, 0x0, 0x6708, 0x0, 0x6709, 0x0, 0x6717, 0x0, 0x671b, 0x0, 0x6721, 0x0, 0x6728, 0x0, 0x674e, 0x0, 0x6753, 0x0, 0x6756, 0x0, 0x675e, 0x0, 0x677b, 0x0, 0x6785, 0x0, 0x6797, 0x0, 0x67f3, 0x0, 0x67fa, 0x0, 0x6817, 0x0, 0x681f, 0x0, 0x682a, 0x0, 0x682a, 0x5f0f, 0x4f1a, 0x793e, 0x0, 0x6852, 0x0, 0x6881, 0x0, 0x6885, 0x0, 0x688e, 0x0, 0x68a8, 0x0, 0x6914, 0x0, 0x6942, 0x0, 0x69a3, 0x0, 0x69ea, 0x0, 0x6a02, 0x0, 0x6a13, 0x0, 0x6aa8, 0x0, 0x6ad3, 0x0, 0x6adb, 0x0, 0x6b04, 0x0, 0x6b20, 0x0, 0x6b21, 0x0, 0x6b54, 0x0, 0x6b62, 0x0, 0x6b63, 0x0, 0x6b72, 0x0, 0x6b77, 0x0, 0x6b79, 0x0, 0x6b9f, 0x0, 0x6bae, 0x0, 0x6bb3, 0x0, 0x6bba, 0x0, 0x6bbb, 0x0, 0x6bcb, 0x0, 0x6bcd, 0x0, 0x6bd4, 0x0, 0x6bdb, 0x0, 0x6c0f, 0x0, 0x6c14, 0x0, 0x6c34, 0x0, 0x6c4e, 0x0, 0x6c67, 0x0, 0x6c88, 0x0, 0x6cbf, 0x0, 0x6ccc, 0x0, 0x6ccd, 0x0, 0x6ce5, 0x0, 0x6ce8, 0x0, 0x6d16, 0x0, 0x6d1b, 0x0, 0x6d1e, 0x0, 0x6d34, 0x0, 0x6d3e, 0x0, 0x6d41, 0x0, 0x6d69, 0x0, 0x6d6a, 0x0, 0x6d77, 0x0, 0x6d78, 0x0, 0x6d85, 0x0, 0x6dcb, 0x0, 0x6dda, 0x0, 0x6dea, 0x0, 0x6df9, 0x0, 0x6e1a, 0x0, 0x6e2f, 0x0, 0x6e6e, 0x0, 0x6e80, 0x0, 0x6e9c, 0x0, 0x6eba, 0x0, 0x6ec7, 0x0, 0x6ecb, 0x0, 0x6ed1, 0x0, 0x6edb, 0x0, 0x6f0f, 0x0, 0x6f14, 0x0, 0x6f22, 0x0, 0x6f23, 0x0, 0x6f6e, 0x0, 0x6fc6, 0x0, 0x6feb, 0x0, 0x6ffe, 0x0, 0x701b, 0x0, 0x701e, 0x0, 0x7039, 0x0, 0x704a, 0x0, 0x706b, 0x0, 0x7070, 0x0, 0x7077, 0x0, 0x707d, 0x0, 0x7099, 0x0, 0x70ad, 0x0, 0x70c8, 0x0, 0x70d9, 0x0, 0x7121, 0x0, 0x7145, 0x0, 0x7149, 0x0, 0x716e, 0x0, 0x719c, 0x0, 0x71ce, 0x0, 0x71d0, 0x0, 0x7210, 0x0, 0x721b, 0x0, 0x7228, 0x0, 0x722a, 0x0, 0x722b, 0x0, 0x7235, 0x0, 0x7236, 0x0, 0x723b, 0x0, 0x723f, 0x0, 0x7247, 0x0, 0x7250, 0x0, 0x7259, 0x0, 0x725b, 0x0, 0x7262, 0x0, 0x7279, 0x0, 0x7280, 0x0, 0x7295, 0x0, 0x72ac, 0x0, 0x72af, 0x0, 0x72c0, 0x0, 0x72fc, 0x0, 0x732a, 0x0, 0x7375, 0x0, 0x737a, 0x0, 0x7384, 0x0, 0x7387, 0x0, 0x7389, 0x0, 0x738b, 0x0, 0x73a5, 0x0, 0x73b2, 0x0, 0x73de, 0x0, 0x7406, 0x0, 0x7409, 0x0, 0x7422, 0x0, 0x7447, 0x0, 0x745c, 0x0, 0x7469, 0x0, 0x7471, 0x0, 0x7485, 0x0, 0x7489, 0x0, 0x7498, 0x0, 0x74ca, 0x0, 0x74dc, 0x0, 0x74e6, 0x0, 0x7506, 0x0, 0x7518, 0x0, 0x751f, 0x0, 0x7524, 0x0, 0x7528, 0x0, 0x7530, 0x0, 0x7532, 0x0, 0x7533, 0x0, 0x7537, 0x0, 0x753b, 0x0, 0x753e, 0x0, 0x7559, 0x0, 0x7565, 0x0, 0x7570, 0x0, 0x758b, 0x0, 0x7592, 0x0, 0x75e2, 0x0, 0x7610, 0x0, 0x761d, 0x0, 0x761f, 0x0, 0x7642, 0x0, 0x7669, 0x0, 0x7676, 0x0, 0x767d, 0x0, 0x76ae, 0x0, 0x76bf, 0x0, 0x76ca, 0x0, 0x76db, 0x0, 0x76e3, 0x0, 0x76e7, 0x0, 0x76ee, 0x0, 0x76f4, 0x0, 0x7701, 0x0, 0x771e, 0x0, 0x771f, 0x0, 0x7740, 0x0, 0x774a, 0x0, 0x778b, 0x0, 0x77a7, 0x0, 0x77db, 0x0, 0x77e2, 0x0, 0x77f3, 0x0, 0x784e, 0x0, 0x786b, 0x0, 0x788c, 0x0, 0x7891, 0x0, 0x78ca, 0x0, 0x78cc, 0x0, 0x78fb, 0x0, 0x792a, 0x0, 0x793a, 0x0, 0x793c, 0x0, 0x793e, 0x0, 0x7948, 0x0, 0x7949, 0x0, 0x7950, 0x0, 0x7956, 0x0, 0x795d, 0x0, 0x795e, 0x0, 0x7965, 0x0, 0x797f, 0x0, 0x7981, 0x0, 0x798d, 0x0, 0x798e, 0x0, 0x798f, 0x0, 0x79ae, 0x0, 0x79b8, 0x0, 0x79be, 0x0, 0x79ca, 0x0, 0x79d8, 0x0, 0x79eb, 0x0, 0x7a1c, 0x0, 0x7a40, 0x0, 0x7a4a, 0x0, 0x7a4f, 0x0, 0x7a74, 0x0, 0x7a7a, 0x0, 0x7a81, 0x0, 0x7ab1, 0x0, 0x7acb, 0x0, 0x7aee, 0x0, 0x7af9, 0x0, 0x7b20, 0x0, 0x7b8f, 0x0, 0x7bc0, 0x0, 0x7bc6, 0x0, 0x7bc9, 0x0, 0x7c3e, 0x0, 0x7c60, 0x0, 0x7c73, 0x0, 0x7c7b, 0x0, 0x7c92, 0x0, 0x7cbe, 0x0, 0x7cd2, 0x0, 0x7cd6, 0x0, 0x7ce3, 0x0, 0x7ce7, 0x0, 0x7ce8, 0x0, 0x7cf8, 0x0, 0x7d00, 0x0, 0x7d10, 0x0, 0x7d22, 0x0, 0x7d2f, 0x0, 0x7d42, 0x0, 0x7d5b, 0x0, 0x7d63, 0x0, 0x7da0, 0x0, 0x7dbe, 0x0, 0x7dc7, 0x0, 0x7df4, 0x0, 0x7e02, 0x0, 0x7e09, 0x0, 0x7e37, 0x0, 0x7e41, 0x0, 0x7e45, 0x0, 0x7f36, 0x0, 0x7f3e, 0x0, 0x7f51, 0x0, 0x7f72, 0x0, 0x7f79, 0x0, 0x7f7a, 0x0, 0x7f85, 0x0, 0x7f8a, 0x0, 0x7f95, 0x0, 0x7f9a, 0x0, 0x7fbd, 0x0, 0x7ffa, 0x0, 0x8001, 0x0, 0x8005, 0x0, 0x800c, 0x0, 0x8012, 0x0, 0x8033, 0x0, 0x8046, 0x0, 0x8060, 0x0, 0x806f, 0x0, 0x8070, 0x0, 0x807e, 0x0, 0x807f, 0x0, 0x8089, 0x0, 0x808b, 0x0, 0x80ad, 0x0, 0x80b2, 0x0, 0x8103, 0x0, 0x813e, 0x0, 0x81d8, 0x0, 0x81e3, 0x0, 0x81e8, 0x0, 0x81ea, 0x0, 0x81ed, 0x0, 0x81f3, 0x0, 0x81fc, 0x0, 0x8201, 0x0, 0x8204, 0x0, 0x820c, 0x0, 0x8218, 0x0, 0x821b, 0x0, 0x821f, 0x0, 0x826e, 0x0, 0x826f, 0x0, 0x8272, 0x0, 0x8278, 0x0, 0x8279, 0x0, 0x828b, 0x0, 0x8291, 0x0, 0x829d, 0x0, 0x82b1, 0x0, 0x82b3, 0x0, 0x82bd, 0x0, 0x82e5, 0x0, 0x82e6, 0x0, 0x831d, 0x0, 0x8323, 0x0, 0x8336, 0x0, 0x8352, 0x0, 0x8353, 0x0, 0x8363, 0x0, 0x83ad, 0x0, 0x83bd, 0x0, 0x83c9, 0x0, 0x83ca, 0x0, 0x83cc, 0x0, 0x83dc, 0x0, 0x83e7, 0x0, 0x83ef, 0x0, 0x83f1, 0x0, 0x843d, 0x0, 0x8449, 0x0, 0x8457, 0x0, 0x84ee, 0x0, 0x84f1, 0x0, 0x84f3, 0x0, 0x84fc, 0x0, 0x8516, 0x0, 0x8564, 0x0, 0x85cd, 0x0, 0x85fa, 0x0, 0x8606, 0x0, 0x8612, 0x0, 0x862d, 0x0, 0x863f, 0x0, 0x864d, 0x0, 0x8650, 0x0, 0x865c, 0x0, 0x8667, 0x0, 0x8669, 0x0, 0x866b, 0x0, 0x8688, 0x0, 0x86a9, 0x0, 0x86e2, 0x0, 0x870e, 0x0, 0x8728, 0x0, 0x876b, 0x0, 0x8779, 0x0, 0x8786, 0x0, 0x87ba, 0x0, 0x87e1, 0x0, 0x8801, 0x0, 0x881f, 0x0, 0x8840, 0x0, 0x884c, 0x0, 0x8860, 0x0, 0x8863, 0x0, 0x88c2, 0x0, 0x88cf, 0x0, 0x88d7, 0x0, 0x88de, 0x0, 0x88e1, 0x0, 0x88f8, 0x0, 0x88fa, 0x0, 0x8910, 0x0, 0x8941, 0x0, 0x8964, 0x0, 0x897e, 0x0, 0x8986, 0x0, 0x898b, 0x0, 0x8996, 0x0, 0x89d2, 0x0, 0x89e3, 0x0, 0x8a00, 0x0, 0x8aa0, 0x0, 0x8aaa, 0x0, 0x8abf, 0x0, 0x8acb, 0x0, 0x8ad2, 0x0, 0x8ad6, 0x0, 0x8aed, 0x0, 0x8af8, 0x0, 0x8afe, 0x0, 0x8b01, 0x0, 0x8b39, 0x0, 0x8b58, 0x0, 0x8b80, 0x0, 0x8b8a, 0x0, 0x8c37, 0x0, 0x8c46, 0x0, 0x8c48, 0x0, 0x8c55, 0x0, 0x8c78, 0x0, 0x8c9d, 0x0, 0x8ca1, 0x0, 0x8ca9, 0x0, 0x8cab, 0x0, 0x8cc1, 0x0, 0x8cc2, 0x0, 0x8cc7, 0x0, 0x8cc8, 0x0, 0x8cd3, 0x0, 0x8d08, 0x0, 0x8d1b, 0x0, 0x8d64, 0x0, 0x8d70, 0x0, 0x8d77, 0x0, 0x8db3, 0x0, 0x8dbc, 0x0, 0x8dcb, 0x0, 0x8def, 0x0, 0x8df0, 0x0, 0x8eab, 0x0, 0x8eca, 0x0, 0x8ed4, 0x0, 0x8f26, 0x0, 0x8f2a, 0x0, 0x8f38, 0x0, 0x8f3b, 0x0, 0x8f62, 0x0, 0x8f9b, 0x0, 0x8f9e, 0x0, 0x8fb0, 0x0, 0x8fb5, 0x0, 0x8fb6, 0x0, 0x9023, 0x0, 0x9038, 0x0, 0x904a, 0x0, 0x9069, 0x0, 0x9072, 0x0, 0x907c, 0x0, 0x908f, 0x0, 0x9091, 0x0, 0x9094, 0x0, 0x90ce, 0x0, 0x90de, 0x0, 0x90f1, 0x0, 0x90fd, 0x0, 0x9111, 0x0, 0x911b, 0x0, 0x9149, 0x0, 0x916a, 0x0, 0x9199, 0x0, 0x91b4, 0x0, 0x91c6, 0x0, 0x91cc, 0x0, 0x91cf, 0x0, 0x91d1, 0x0, 0x9234, 0x0, 0x9238, 0x0, 0x9276, 0x0, 0x927c, 0x0, 0x92d7, 0x0, 0x92d8, 0x0, 0x9304, 0x0, 0x934a, 0x0, 0x93f9, 0x0, 0x9415, 0x0, 0x9577, 0x0, 0x9580, 0x0, 0x958b, 0x0, 0x95ad, 0x0, 0x95b7, 0x0, 0x961c, 0x0, 0x962e, 0x0, 0x964b, 0x0, 0x964d, 0x0, 0x9675, 0x0, 0x9678, 0x0, 0x967c, 0x0, 0x9686, 0x0, 0x96a3, 0x0, 0x96b6, 0x0, 0x96b7, 0x0, 0x96b8, 0x0, 0x96b9, 0x0, 0x96c3, 0x0, 0x96e2, 0x0, 0x96e3, 0x0, 0x96e8, 0x0, 0x96f6, 0x0, 0x96f7, 0x0, 0x9723, 0x0, 0x9732, 0x0, 0x9748, 0x0, 0x9751, 0x0, 0x9756, 0x0, 0x975e, 0x0, 0x9762, 0x0, 0x9769, 0x0, 0x97cb, 0x0, 0x97db, 0x0, 0x97e0, 0x0, 0x97ed, 0x0, 0x97f3, 0x0, 0x97ff, 0x0, 0x9801, 0x0, 0x9805, 0x0, 0x980b, 0x0, 0x9818, 0x0, 0x9829, 0x0, 0x983b, 0x0, 0x985e, 0x0, 0x98a8, 0x0, 0x98db, 0x0, 0x98df, 0x0, 0x98e2, 0x0, 0x98ef, 0x0, 0x98fc, 0x0, 0x9928, 0x0, 0x9929, 0x0, 0x9996, 0x0, 0x9999, 0x0, 0x99a7, 0x0, 0x99ac, 0x0, 0x99c2, 0x0, 0x99f1, 0x0, 0x99fe, 0x0, 0x9a6a, 0x0, 0x9aa8, 0x0, 0x9ad8, 0x0, 0x9adf, 0x0, 0x9b12, 0x0, 0x9b25, 0x0, 0x9b2f, 0x0, 0x9b32, 0x0, 0x9b3c, 0x0, 0x9b5a, 0x0, 0x9b6f, 0x0, 0x9c40, 0x0, 0x9c57, 0x0, 0x9ce5, 0x0, 0x9cfd, 0x0, 0x9d67, 0x0, 0x9db4, 0x0, 0x9dfa, 0x0, 0x9e1e, 0x0, 0x9e75, 0x0, 0x9e7f, 0x0, 0x9e97, 0x0, 0x9e9f, 0x0, 0x9ea5, 0x0, 0x9ebb, 0x0, 0x9ec3, 0x0, 0x9ecd, 0x0, 0x9ece, 0x0, 0x9ed1, 0x0, 0x9ef9, 0x0, 0x9efd, 0x0, 0x9efe, 0x0, 0x9f05, 0x0, 0x9f0e, 0x0, 0x9f0f, 0x0, 0x9f13, 0x0, 0x9f16, 0x0, 0x9f20, 0x0, 0x9f3b, 0x0, 0x9f43, 0x0, 0x9f4a, 0x0, 0x9f52, 0x0, 0x9f8d, 0x0, 0x9f8e, 0x0, 0x9f9c, 0x0, 0x9f9f, 0x0, 0x9fa0, 0x0, 0xa76f, 0x0, 0x11099, 0x110ba, 0x0, 0x1109b, 0x110ba, 0x0, 0x110a5, 0x110ba, 0x0, 0x11131, 0x11127, 0x0, 0x11132, 0x11127, 0x0, 0x1d157, 0x1d165, 0x0, 0x1d158, 0x1d165, 0x0, 0x1d158, 0x1d165, 0x1d16e, 0x0, 0x1d158, 0x1d165, 0x1d16f, 0x0, 0x1d158, 0x1d165, 0x1d170, 0x0, 0x1d158, 0x1d165, 0x1d171, 0x0, 0x1d158, 0x1d165, 0x1d172, 0x0, 0x1d1b9, 0x1d165, 0x0, 0x1d1b9, 0x1d165, 0x1d16e, 0x0, 0x1d1b9, 0x1d165, 0x1d16f, 0x0, 0x1d1ba, 0x1d165, 0x0, 0x1d1ba, 0x1d165, 0x1d16e, 0x0, 0x1d1ba, 0x1d165, 0x1d16f, 0x0, 0x20122, 0x0, 0x2051c, 0x0, 0x20525, 0x0, 0x2054b, 0x0, 0x2063a, 0x0, 0x20804, 0x0, 0x208de, 0x0, 0x20a2c, 0x0, 0x20b63, 0x0, 0x214e4, 0x0, 0x216a8, 0x0, 0x216ea, 0x0, 0x219c8, 0x0, 0x21b18, 0x0, 0x21d0b, 0x0, 0x21de4, 0x0, 0x21de6, 0x0, 0x22183, 0x0, 0x2219f, 0x0, 0x22331, 0x0, 0x226d4, 0x0, 0x22844, 0x0, 0x2284a, 0x0, 0x22b0c, 0x0, 0x22bf1, 0x0, 0x2300a, 0x0, 0x232b8, 0x0, 0x2335f, 0x0, 0x23393, 0x0, 0x2339c, 0x0, 0x233c3, 0x0, 0x233d5, 0x0, 0x2346d, 0x0, 0x236a3, 0x0, 0x238a7, 0x0, 0x23a8d, 0x0, 0x23afa, 0x0, 0x23cbc, 0x0, 0x23d1e, 0x0, 0x23ed1, 0x0, 0x23f5e, 0x0, 0x23f8e, 0x0, 0x24263, 0x0, 0x242ee, 0x0, 0x243ab, 0x0, 0x24608, 0x0, 0x24735, 0x0, 0x24814, 0x0, 0x24c36, 0x0, 0x24c92, 0x0, 0x24fa1, 0x0, 0x24fb8, 0x0, 0x25044, 0x0, 0x250f2, 0x0, 0x250f3, 0x0, 0x25119, 0x0, 0x25133, 0x0, 0x25249, 0x0, 0x2541d, 0x0, 0x25626, 0x0, 0x2569a, 0x0, 0x256c5, 0x0, 0x2597c, 0x0, 0x25aa7, 0x0, 0x25bab, 0x0, 0x25c80, 0x0, 0x25cd0, 0x0, 0x25f86, 0x0, 0x261da, 0x0, 0x26228, 0x0, 0x26247, 0x0, 0x262d9, 0x0, 0x2633e, 0x0, 0x264da, 0x0, 0x26523, 0x0, 0x265a8, 0x0, 0x267a7, 0x0, 0x267b5, 0x0, 0x26b3c, 0x0, 0x26c36, 0x0, 0x26cd5, 0x0, 0x26d6b, 0x0, 0x26f2c, 0x0, 0x26fb1, 0x0, 0x270d2, 0x0, 0x273ca, 0x0, 0x27667, 0x0, 0x278ae, 0x0, 0x27966, 0x0, 0x27ca8, 0x0, 0x27ed3, 0x0, 0x27f2f, 0x0, 0x285d2, 0x0, 0x285ed, 0x0, 0x2872e, 0x0, 0x28bfa, 0x0, 0x28d77, 0x0, 0x29145, 0x0, 0x291df, 0x0, 0x2921a, 0x0, 0x2940a, 0x0, 0x29496, 0x0, 0x295b6, 0x0, 0x29b30, 0x0, 0x2a0ce, 0x0, 0x2a105, 0x0, 0x2a20e, 0x0, 0x2a291, 0x0, 0x2a392, 0x0, 0x2a600, 0x0]; return t; } } } ldc-1.1.0-beta3-src/runtime/phobos/std/internal/unicode_grapheme.d0000664000175000017500000004573712776215007023205 0ustar kaikaimodule std.internal.unicode_grapheme; import std.internal.unicode_tables; static if(size_t.sizeof == 8) { //832 bytes enum hangulLVTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x40], [ 0x100, 0x80, 0xa00], [ 0x2010000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000300020001, 0x1000700060005, 0x5000400030002, 0x2000100070006, 0x6000500040003, 0x3000200010007, 0x7000600050004, 0x4000300020001, 0x1000700060005, 0x5000400030002, 0x8000100070006, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000010000001, 0x1000000100000, 0x10000001000, 0x1000000100000010, 0x10000001000000, 0x100000010000, 0x1000000100, 0x100000010000001, 0x1000000100000, 0x10000001000, 0x1000000100000010, 0x10000001000000, 0x100000010000, 0x1000000100, 0x100000010000001, 0x1000000100000, 0x10000001000, 0x1000000100000010, 0x10000001000000, 0x100000010000, 0x1000000100, 0x100000010000001, 0x1000000100000, 0x10000001000, 0x1000000100000010, 0x10000001000000, 0x100000010000, 0x1000000100, 0x10000001000000, 0x100000010000, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0]); //832 bytes enum hangulLVTTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x40], [ 0x100, 0x80, 0xa00], [ 0x2010000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000300020001, 0x1000700060005, 0x5000400030002, 0x2000100070006, 0x6000500040003, 0x3000200010007, 0x7000600050004, 0x4000300020001, 0x1000700060005, 0x5000400030002, 0x8000100070006, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfeffffffeffffffe, 0xfffeffffffefffff, 0xfffffeffffffefff, 0xeffffffeffffffef, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeffffffeff, 0xfeffffffeffffffe, 0xfffeffffffefffff, 0xfffffeffffffefff, 0xeffffffeffffffef, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeffffffeff, 0xfeffffffeffffffe, 0xfffeffffffefffff, 0xfffffeffffffefff, 0xeffffffeffffffef, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeffffffeff, 0xfeffffffeffffffe, 0xfffeffffffefffff, 0xfffffeffffffefff, 0xeffffffeffffffef, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeffffffeff, 0xffeffffffeffffff, 0xffffeffffffeffff, 0xffffffeff, 0x0, 0x0, 0x0, 0x0, 0x0]); //1536 bytes enum mcTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x60], [ 0x100, 0x100, 0x1800], [ 0x202030202020100, 0x206020205020204, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3000200010000, 0x6000000050004, 0x7, 0x8000000000000, 0xb000a00090000, 0xc, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x110010000f000e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x130012, 0x1400000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x160000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc800000000000008, 0xde01, 0xc00000000000000c, 0x801981, 0xc000000000000008, 0x1, 0xc000000000000008, 0x1a01, 0x400000000000000c, 0x801981, 0xc000000000000000, 0x801dc6, 0xe, 0x1e, 0x400000000000000c, 0x600d9f, 0xc00000000000000c, 0x801dc1, 0xc, 0xc0000ff038000, 0xc000000000000000, 0x8000000000000000, 0x0, 0x0, 0x1902180000000000, 0x3f9c00c00000, 0x1c009f98, 0x0, 0x0, 0x0, 0xc040000000000000, 0x1bf, 0x1fb0e7800000000, 0x0, 0xffff000000000000, 0x301, 0x6000000, 0x7e01a00a00000, 0x0, 0x0, 0xe820000000000010, 0x1b, 0x34c200000004, 0xc5c8000000000, 0x300ff000000000, 0x0, 0x0, 0xc000200000000, 0xc00000000000, 0x0, 0x0, 0x0, 0x9800000000, 0x0, 0xfff0000000000003, 0xf, 0x0, 0xc0000, 0xec30000000000008, 0x1, 0x19800000000000, 0x800000000002000, 0x0, 0x20c80000000000, 0x0, 0x0, 0x0, 0x16d800000000, 0x5, 0x0, 0x187000000000004, 0x0, 0x100000000000, 0x0, 0x8038000000000004, 0x1, 0x0, 0x0, 0x40d00000000000, 0x0, 0x0, 0x7ffffffffffe0000, 0x0, 0x0, 0x0, 0x7e06000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2336 bytes enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x20, 0x70], [ 0x100, 0x140, 0x2d00], [ 0x402030202020100, 0x207020206020205, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020202, 0x202020202020208, 0x202020202020202, 0x202020202020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000, 0x5000400030002, 0x9000800070006, 0xd000c000b000a, 0xf00000000000e, 0x10000000000000, 0x14001300120011, 0x160015, 0x17, 0x0, 0x0, 0x190018, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b00000000, 0x1f001e001d001c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000000, 0x22002100000000, 0x230000, 0x0, 0x2400000000, 0x0, 0x260025, 0x2700000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x28000000000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a00290000, 0x0, 0x0, 0x0, 0x2b0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffff, 0x0, 0x0, 0x0, 0x0, 0x3f8, 0x0, 0x0, 0x0, 0xbffffffffffe0000, 0xb6, 0x7ff0000, 0x10000fffff800, 0x0, 0x3d9f9fc00000, 0xffff000000020000, 0x7ff, 0x1ffc000000000, 0xff80000000000, 0x3eeffbc00000, 0xe000000, 0x0, 0x7ffffff000000000, 0x1400000000000007, 0xc00fe21fe, 0x5000000000000002, 0xc0080201e, 0x1000000000000006, 0x23000000023986, 0x1000000000000006, 0xc000021be, 0xd000000000000002, 0xc00c0201e, 0x4000000000000004, 0x802001, 0xc000000000000000, 0xc00603dc1, 0x9000000000000000, 0xc00603044, 0x4000000000000000, 0xc0080201e, 0x0, 0x805c8400, 0x7f2000000000000, 0x7f80, 0x1bf2000000000000, 0x3f00, 0x2a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x40, 0x66fde00000000000, 0x1e0001c3000000, 0x20002064, 0x0, 0x0, 0xe0000000, 0x0, 0x0, 0x1c0000001c0000, 0xc0000000c0000, 0x3fb0000000000000, 0x200ffe40, 0x3800, 0x0, 0x20000000000, 0x0, 0xe04018700000000, 0x0, 0x0, 0x0, 0x9800000, 0x9ff81fe57f400000, 0x0, 0x0, 0x17d000000000000f, 0xff80000000004, 0xb3c00000003, 0x3a34000000000, 0xcff00000000000, 0x0, 0x0, 0x1021fdfff70000, 0x0, 0x0, 0x0, 0xf000007fffffffff, 0x3000, 0x0, 0x0, 0x1ffffffff0000, 0x0, 0x0, 0x0, 0x3800000000000, 0x0, 0x8000000000000000, 0x0, 0xffffffff00000000, 0xfc0000000000, 0x0, 0x6000000, 0x0, 0x0, 0x3ff7800000000000, 0x80000000, 0x3000000000000, 0x6000000844, 0x0, 0x0, 0x3ffff00000010, 0x3fc000000000, 0x3ff80, 0x13c8000000000007, 0x0, 0x667e0000000000, 0x1008, 0xc19d000000000000, 0x40300000000002, 0x0, 0x0, 0x0, 0x212000000000, 0x40000000, 0x0, 0x0, 0x0, 0x7f0000ffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x0, 0x2000000000000000, 0x870000000000f06e, 0x0, 0x0, 0x0, 0xff00000000000002, 0x7f, 0x678000000000003, 0x0, 0x1fef8000000007, 0x0, 0x7fc0000000000003, 0x0, 0x0, 0x0, 0xbf280000000000, 0x0, 0x0, 0x0, 0x78000, 0x0, 0x0, 0xf807c3a000000000, 0x3c0000000fe7, 0x0, 0x0, 0x1c, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffff, 0x0, 0x0, 0x0, 0x0]); } static if(size_t.sizeof == 4) { //832 bytes enum hangulLVTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x80], [ 0x100, 0x80, 0xa00], [ 0x0, 0x20100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x80001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x10000001, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //832 bytes enum hangulLVTTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0x80], [ 0x100, 0x80, 0xa00], [ 0x0, 0x20100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x20001, 0x40003, 0x60005, 0x10007, 0x30002, 0x50004, 0x70006, 0x80001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xeffffffe, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xffffffef, 0xfeffffff, 0xffefffff, 0xfffeffff, 0xffffefff, 0xfffffeff, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //1536 bytes enum mcTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xc0], [ 0x100, 0x100, 0x1800], [ 0x2020100, 0x2020302, 0x5020204, 0x2060202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x60000, 0x7, 0x0, 0x0, 0x80000, 0x90000, 0xb000a, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf000e, 0x110010, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x130012, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x150000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x160000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xc8000000, 0xde01, 0x0, 0xc, 0xc0000000, 0x801981, 0x0, 0x8, 0xc0000000, 0x1, 0x0, 0x8, 0xc0000000, 0x1a01, 0x0, 0xc, 0x40000000, 0x801981, 0x0, 0x0, 0xc0000000, 0x801dc6, 0x0, 0xe, 0x0, 0x1e, 0x0, 0xc, 0x40000000, 0x600d9f, 0x0, 0xc, 0xc0000000, 0x801dc1, 0x0, 0xc, 0x0, 0xff038000, 0xc0000, 0x0, 0xc0000000, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19021800, 0xc00000, 0x3f9c, 0x1c009f98, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400000, 0x1bf, 0x0, 0x0, 0x1fb0e78, 0x0, 0x0, 0x0, 0xffff0000, 0x301, 0x0, 0x6000000, 0x0, 0xa00000, 0x7e01a, 0x0, 0x0, 0x0, 0x0, 0x10, 0xe8200000, 0x1b, 0x0, 0x4, 0x34c2, 0x0, 0xc5c80, 0x0, 0x300ff0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0002, 0x0, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x98, 0x0, 0x0, 0x3, 0xfff00000, 0xf, 0x0, 0x0, 0x0, 0xc0000, 0x0, 0x8, 0xec300000, 0x1, 0x0, 0x0, 0x198000, 0x2000, 0x8000000, 0x0, 0x0, 0x0, 0x20c800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16d8, 0x5, 0x0, 0x0, 0x0, 0x4, 0x1870000, 0x0, 0x0, 0x0, 0x1000, 0x0, 0x0, 0x4, 0x80380000, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40d000, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, 0x7fffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e060, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); //2336 bytes enum graphemeExtendTrieEntries = TrieEntry!(bool, 8, 5, 8)([ 0x0, 0x40, 0xe0], [ 0x100, 0x140, 0x2d00], [ 0x2020100, 0x4020302, 0x6020205, 0x2070202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020208, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x2020202, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000, 0x30002, 0x50004, 0x70006, 0x90008, 0xb000a, 0xd000c, 0xe, 0xf0000, 0x0, 0x100000, 0x120011, 0x140013, 0x160015, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x190018, 0x0, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x1d001c, 0x1f001e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x220021, 0x230000, 0x0, 0x0, 0x0, 0x0, 0x24, 0x0, 0x0, 0x260025, 0x0, 0x0, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x280000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x290000, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2b0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, 0xbfffffff, 0xb6, 0x0, 0x7ff0000, 0x0, 0xfffff800, 0x10000, 0x0, 0x0, 0x9fc00000, 0x3d9f, 0x20000, 0xffff0000, 0x7ff, 0x0, 0x0, 0x1ffc0, 0x0, 0xff800, 0xfbc00000, 0x3eef, 0xe000000, 0x0, 0x0, 0x0, 0x0, 0x7ffffff0, 0x7, 0x14000000, 0xfe21fe, 0xc, 0x2, 0x50000000, 0x80201e, 0xc, 0x6, 0x10000000, 0x23986, 0x230000, 0x6, 0x10000000, 0x21be, 0xc, 0x2, 0xd0000000, 0xc0201e, 0xc, 0x4, 0x40000000, 0x802001, 0x0, 0x0, 0xc0000000, 0x603dc1, 0xc, 0x0, 0x90000000, 0x603044, 0xc, 0x0, 0x40000000, 0x80201e, 0xc, 0x0, 0x0, 0x805c8400, 0x0, 0x0, 0x7f20000, 0x7f80, 0x0, 0x0, 0x1bf20000, 0x3f00, 0x0, 0x3000000, 0x2a00000, 0x0, 0x7ffe0000, 0xfeffe0df, 0x1fffffff, 0x40, 0x0, 0x0, 0x66fde000, 0xc3000000, 0x1e0001, 0x20002064, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c0000, 0x1c0000, 0xc0000, 0xc0000, 0x0, 0x3fb00000, 0x200ffe40, 0x0, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x200, 0x0, 0x0, 0x0, 0xe040187, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9800000, 0x0, 0x7f400000, 0x9ff81fe5, 0x0, 0x0, 0x0, 0x0, 0xf, 0x17d00000, 0x4, 0xff800, 0x3, 0xb3c, 0x0, 0x3a340, 0x0, 0xcff000, 0x0, 0x0, 0x0, 0x0, 0xfff70000, 0x1021fd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xf000007f, 0x3000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff0000, 0x1ffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38000, 0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0x0, 0xffffffff, 0x0, 0xfc00, 0x0, 0x0, 0x6000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff78000, 0x80000000, 0x0, 0x0, 0x30000, 0x844, 0x60, 0x0, 0x0, 0x0, 0x0, 0x10, 0x3ffff, 0x0, 0x3fc0, 0x3ff80, 0x0, 0x7, 0x13c80000, 0x0, 0x0, 0x0, 0x667e00, 0x1008, 0x0, 0x0, 0xc19d0000, 0x2, 0x403000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2120, 0x40000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000, 0xf06e, 0x87000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff000000, 0x7f, 0x0, 0x3, 0x6780000, 0x0, 0x0, 0x7, 0x1fef80, 0x0, 0x0, 0x3, 0x7fc00000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf2800, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf807c3a0, 0xfe7, 0x3c00, 0x0, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); } ldc-1.1.0-beta3-src/runtime/phobos/std/getopt.d0000664000175000017500000014212212776215007017357 0ustar kaikai// Written in the D programming language. /** Processing of command line options. The getopt module implements a $(D getopt) function, which adheres to the POSIX syntax for command line options. GNU extensions are supported in the form of long options introduced by a double dash ("--"). Support for bundling of command line options, as was the case with the more traditional single-letter approach, is provided but not enabled by default. Macros: WIKI = Phobos/StdGetopt Copyright: Copyright Andrei Alexandrescu 2008 - 2015. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB erdani.org, Andrei Alexandrescu) Credits: This module and its documentation are inspired by Perl's $(WEB perldoc.perl.org/Getopt/Long.html, Getopt::Long) module. The syntax of D's $(D getopt) is simpler than its Perl counterpart because $(D getopt) infers the expected parameter types from the static types of the passed-in pointers. Source: $(PHOBOSSRC std/_getopt.d) */ /* Copyright Andrei Alexandrescu 2008 - 2015. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.getopt; import std.traits; import std.exception; // basicExceptionCtors /** Thrown on one of the following conditions: $(UL $(LI An unrecognized command-line argument is passed, and $(D std.getopt.config.passThrough) was not present.) $(LI A command-line option was not found, and $(D std.getopt.config.required) was present.) ) */ class GetOptException : Exception { mixin basicExceptionCtors; } static assert(is(typeof(new GetOptException("message")))); static assert(is(typeof(new GetOptException("message", Exception.init)))); /** Parse and remove command line options from a string array. Synopsis: --------- import std.getopt; string data = "file.dat"; int length = 24; bool verbose; enum Color { no, yes }; Color color; void main(string[] args) { auto helpInformation = getopt( args, "length", &length, // numeric "file", &data, // string "verbose", &verbose, // flag "color", "Information about this color", &color); // enum ... if (helpInformation.helpWanted) { defaultGetoptPrinter("Some information about the program.", helpInformation.options); } } --------- The $(D getopt) function takes a reference to the command line (as received by $(D main)) as its first argument, and an unbounded number of pairs of strings and pointers. Each string is an option meant to "fill" the value referenced by the pointer to its right (the "bound" pointer). The option string in the call to $(D getopt) should not start with a dash. In all cases, the command-line options that were parsed and used by $(D getopt) are removed from $(D args). Whatever in the arguments did not look like an option is left in $(D args) for further processing by the program. Values that were unaffected by the options are not touched, so a common idiom is to initialize options to their defaults and then invoke $(D getopt). If a command-line argument is recognized as an option with a parameter and the parameter cannot be parsed properly (e.g., a number is expected but not present), a $(D ConvException) exception is thrown. If $(D std.getopt.config.passThrough) was not passed to $(D getopt) and an unrecognized command-line argument is found, a $(D GetOptException) is thrown. Depending on the type of the pointer being bound, $(D getopt) recognizes the following kinds of options: $(OL $(LI $(I Boolean options). A lone argument sets the option to $(D true). Additionally $(B true) or $(B false) can be set within the option separated with an "=" sign: --------- bool verbose = false, debugging = true; getopt(args, "verbose", &verbose, "debug", &debugging); --------- To set $(D verbose) to $(D true), invoke the program with either $(D --verbose) or $(D --verbose=true). To set $(D debugging) to $(D false), invoke the program with $(D --debugging=false). ) $(LI $(I Numeric options.) If an option is bound to a numeric type, a number is expected as the next option, or right within the option separated with an "=" sign: --------- uint timeout; getopt(args, "timeout", &timeout); --------- To set $(D timeout) to $(D 5), invoke the program with either $(D --timeout=5) or $(D --timeout 5). ) $(LI $(I Incremental options.) If an option name has a "+" suffix and is bound to a numeric type, then the option's value tracks the number of times the option occurred on the command line: --------- uint paranoid; getopt(args, "paranoid+", ¶noid); --------- Invoking the program with "--paranoid --paranoid --paranoid" will set $(D paranoid) to 3. Note that an incremental option never expects a parameter, e.g., in the command line "--paranoid 42 --paranoid", the "42" does not set $(D paranoid) to 42; instead, $(D paranoid) is set to 2 and "42" is not considered as part of the normal program arguments. ) $(LI $(I Enum options.) If an option is bound to an enum, an enum symbol as a string is expected as the next option, or right within the option separated with an "=" sign: --------- enum Color { no, yes }; Color color; // default initialized to Color.no getopt(args, "color", &color); --------- To set $(D color) to $(D Color.yes), invoke the program with either $(D --color=yes) or $(D --color yes). ) $(LI $(I String options.) If an option is bound to a string, a string is expected as the next option, or right within the option separated with an "=" sign: --------- string outputFile; getopt(args, "output", &outputFile); --------- Invoking the program with "--output=myfile.txt" or "--output myfile.txt" will set $(D outputFile) to "myfile.txt". If you want to pass a string containing spaces, you need to use the quoting that is appropriate to your shell, e.g. --output='my file.txt'. ) $(LI $(I Array options.) If an option is bound to an array, a new element is appended to the array each time the option occurs: --------- string[] outputFiles; getopt(args, "output", &outputFiles); --------- Invoking the program with "--output=myfile.txt --output=yourfile.txt" or "--output myfile.txt --output yourfile.txt" will set $(D outputFiles) to $(D [ "myfile.txt", "yourfile.txt" ]). Alternatively you can set $(LREF arraySep) as the element separator: --------- string[] outputFiles; arraySep = ","; // defaults to "", separation by whitespace getopt(args, "output", &outputFiles); --------- With the above code you can invoke the program with "--output=myfile.txt,yourfile.txt", or "--output myfile.txt,yourfile.txt".) $(LI $(I Hash options.) If an option is bound to an associative array, a string of the form "name=value" is expected as the next option, or right within the option separated with an "=" sign: --------- double[string] tuningParms; getopt(args, "tune", &tuningParms); --------- Invoking the program with e.g. "--tune=alpha=0.5 --tune beta=0.6" will set $(D tuningParms) to [ "alpha" : 0.5, "beta" : 0.6 ]. Alternatively you can set $(LREF arraySep) as the element separator: --------- double[string] tuningParms; arraySep = ","; // defaults to "", separation by whitespace getopt(args, "tune", &tuningParms); --------- With the above code you can invoke the program with "--tune=alpha=0.5,beta=0.6", or "--tune alpha=0.5,beta=0.6". In general, the keys and values can be of any parsable types. ) $(LI $(I Callback options.) An option can be bound to a function or delegate with the signature $(D void function()), $(D void function(string option)), $(D void function(string option, string value)), or their delegate equivalents. $(UL $(LI If the callback doesn't take any arguments, the callback is invoked whenever the option is seen. ) $(LI If the callback takes one string argument, the option string (without the leading dash(es)) is passed to the callback. After that, the option string is considered handled and removed from the options array. --------- void main(string[] args) { uint verbosityLevel = 1; void myHandler(string option) { if (option == "quiet") { verbosityLevel = 0; } else { assert(option == "verbose"); verbosityLevel = 2; } } getopt(args, "verbose", &myHandler, "quiet", &myHandler); } --------- ) $(LI If the callback takes two string arguments, the option string is handled as an option with one argument, and parsed accordingly. The option and its value are passed to the callback. After that, whatever was passed to the callback is considered handled and removed from the list. --------- int main(string[] args) { uint verbosityLevel = 1; bool handlerFailed = false; void myHandler(string option, string value) { switch (value) { case "quiet": verbosityLevel = 0; break; case "verbose": verbosityLevel = 2; break; case "shouting": verbosityLevel = verbosityLevel.max; break; default : stderr.writeln("Dunno how verbose you want me to be by saying ", value); handlerFailed = true; break; } } getopt(args, "verbosity", &myHandler); return handlerFailed ? 1 : 0; } --------- ) )) ) Options_with_multiple_names: Sometimes option synonyms are desirable, e.g. "--verbose", "--loquacious", and "--garrulous" should have the same effect. Such alternate option names can be included in the option specification, using "|" as a separator: --------- bool verbose; getopt(args, "verbose|loquacious|garrulous", &verbose); --------- Case: By default options are case-insensitive. You can change that behavior by passing $(D getopt) the $(D caseSensitive) directive like this: --------- bool foo, bar; getopt(args, std.getopt.config.caseSensitive, "foo", &foo, "bar", &bar); --------- In the example above, "--foo", "--bar", "--FOo", "--bAr" etc. are recognized. The directive is active til the end of $(D getopt), or until the converse directive $(D caseInsensitive) is encountered: --------- bool foo, bar; getopt(args, std.getopt.config.caseSensitive, "foo", &foo, std.getopt.config.caseInsensitive, "bar", &bar); --------- The option "--Foo" is rejected due to $(D std.getopt.config.caseSensitive), but not "--Bar", "--bAr" etc. because the directive $(D std.getopt.config.caseInsensitive) turned sensitivity off before option "bar" was parsed. Short_versus_long_options: Traditionally, programs accepted single-letter options preceded by only one dash (e.g. $(D -t)). $(D getopt) accepts such parameters seamlessly. When used with a double-dash (e.g. $(D --t)), a single-letter option behaves the same as a multi-letter option. When used with a single dash, a single-letter option is accepted. If the option has a parameter, that must be "stuck" to the option without any intervening space or "=": --------- uint timeout; getopt(args, "timeout|t", &timeout); --------- To set $(D timeout) to $(D 5), use either of the following: $(D --timeout=5), $(D --timeout 5), $(D --t=5), $(D --t 5), or $(D -t5). Forms such as $(D -t 5) and $(D -timeout=5) will be not accepted. For more details about short options, refer also to the next section. Bundling: Single-letter options can be bundled together, i.e. "-abc" is the same as $(D "-a -b -c"). By default, this option is turned off. You can turn it on with the $(D std.getopt.config.bundling) directive: --------- bool foo, bar; getopt(args, std.getopt.config.bundling, "foo|f", &foo, "bar|b", &bar); --------- In case you want to only enable bundling for some of the parameters, bundling can be turned off with $(D std.getopt.config.noBundling). Required: An option can be marked as required. If that option is not present in the arguments an exception will be thrown. --------- bool foo, bar; getopt(args, std.getopt.config.required, "foo|f", &foo, "bar|b", &bar); --------- Only the option directly following $(D std.getopt.config.required) is required. Passing_unrecognized_options_through: If an application needs to do its own processing of whichever arguments $(D getopt) did not understand, it can pass the $(D std.getopt.config.passThrough) directive to $(D getopt): --------- bool foo, bar; getopt(args, std.getopt.config.passThrough, "foo", &foo, "bar", &bar); --------- An unrecognized option such as "--baz" will be found untouched in $(D args) after $(D getopt) returns. Help_Information_Generation: If an option string is followed by another string, this string serves as a description for this option. The $(D getopt) function returns a struct of type $(D GetoptResult). This return value contains information about all passed options as well a $(D bool GetoptResult.helpWanted) flag indicating whether information about these options was requested. The $(getopt) function always adds an option for --help|-h` to set the flag if the option is seen on the command line. Options_Terminator: A lone double-dash terminates $(D getopt) gathering. It is used to separate program options from other parameters (e.g., options to be passed to another program). Invoking the example above with $(D "--foo -- --bar") parses foo but leaves "--bar" in $(D args). The double-dash itself is removed from the argument array unless the $(D std.getopt.config.keepEndOfOptions) directive is given. */ GetoptResult getopt(T...)(ref string[] args, T opts) { import std.exception : enforce; enforce(args.length, "Invalid arguments string passed: program name missing"); configuration cfg; GetoptResult rslt; GetOptException excep; getoptImpl(args, cfg, rslt, excep, opts); if (!rslt.helpWanted && excep !is null) { throw excep; } return rslt; } /// unittest { auto args = ["prog", "--foo", "-b"]; bool foo; bool bar; auto rslt = getopt(args, "foo|f", "Some information about foo.", &foo, "bar|b", "Some help message about bar.", &bar); if (rslt.helpWanted) { defaultGetoptPrinter("Some information about the program.", rslt.options); } } /** Configuration options for $(D getopt). You can pass them to $(D getopt) in any position, except in between an option string and its bound pointer. */ enum config { /// Turn case sensitivity on caseSensitive, /// Turn case sensitivity off caseInsensitive, /// Turn bundling on bundling, /// Turn bundling off noBundling, /// Pass unrecognized arguments through passThrough, /// Signal unrecognized arguments as errors noPassThrough, /// Stop at first argument that does not look like an option stopOnFirstNonOption, /// Do not erase the endOfOptions separator from args keepEndOfOptions, /// Make the next option a required option required } /** The result of the $(D getopt) function. $(D helpWanted) is set if the option `--help` or `-h` was passed to the option parser. */ struct GetoptResult { bool helpWanted; /// Flag indicating if help was requested Option[] options; /// All possible options } /** Information about an option. */ struct Option { string optShort; /// The short symbol for this option string optLong; /// The long symbol for this option string help; /// The description of this option bool required; /// If a option is required, not passing it will result in an error } private pure Option splitAndGet(string opt) @trusted nothrow { import std.array : split; auto sp = split(opt, "|"); Option ret; if (sp.length > 1) { ret.optShort = "-" ~ (sp[0].length < sp[1].length ? sp[0] : sp[1]); ret.optLong = "--" ~ (sp[0].length > sp[1].length ? sp[0] : sp[1]); } else { ret.optLong = "--" ~ sp[0]; } return ret; } /* This function verifies that the variadic parameters passed in getOpt follow this pattern: [config override], option, [description], receiver, - config override: a config value, optional - option: a string or a char - description: a string, optional - receiver: a pointer or a callable */ private template optionValidator(A...) { import std.typecons: staticIota; import std.format: format; enum fmt = "getopt validator: %s (at position %d)"; enum isReceiver(T) = isPointer!T || (is(T==function)) || (is(T==delegate)); enum isOptionStr(T) = isSomeString!T || isSomeChar!T; auto validator() { string msg; static if (A.length > 0) { static if (isReceiver!(A[0])) { msg = format(fmt, "first argument must be a string or a config", 0); } else static if (!isOptionStr!(A[0]) && !is(A[0] == config)) { msg = format(fmt, "invalid argument type: " ~ A[0].stringof, 0); } else foreach(i; staticIota!(1, A.length)) { static if (!isReceiver!(A[i]) && !isOptionStr!(A[i]) && !(is(A[i] == config))) { msg = format(fmt, "invalid argument type: " ~ A[i].stringof, i); break; } else static if (isReceiver!(A[i]) && !isOptionStr!(A[i-1])) { msg = format(fmt, "a receiver can not be preceeded by a receiver", i); break; } else static if (i > 1 && isOptionStr!(A[i]) && isOptionStr!(A[i-1]) && isSomeString!(A[i-2])) { msg = format(fmt, "a string can not be preceeded by two strings", i); break; } } static if (!isReceiver!(A[$-1]) && !is(A[$-1] == config)) { msg = format(fmt, "last argument must be a receiver or a config", A.length -1); } } return msg; } enum message = validator; alias optionValidator = message; } @safe pure unittest { alias P = void*; alias S = string; alias A = char; alias C = config; alias F = void function(); static assert(optionValidator!(S,P) == ""); static assert(optionValidator!(S,F) == ""); static assert(optionValidator!(A,P) == ""); static assert(optionValidator!(A,F) == ""); static assert(optionValidator!(C,S,P) == ""); static assert(optionValidator!(C,S,F) == ""); static assert(optionValidator!(C,A,P) == ""); static assert(optionValidator!(C,A,F) == ""); static assert(optionValidator!(C,S,S,P) == ""); static assert(optionValidator!(C,S,S,F) == ""); static assert(optionValidator!(C,A,S,P) == ""); static assert(optionValidator!(C,A,S,F) == ""); static assert(optionValidator!(C,S,S,P) == ""); static assert(optionValidator!(C,S,S,P,C,S,F) == ""); static assert(optionValidator!(C,S,P,C,S,S,F) == ""); static assert(optionValidator!(C,A,P,A,S,F) == ""); static assert(optionValidator!(C,A,P,C,A,S,F) == ""); static assert(optionValidator!(P,S,S) != ""); static assert(optionValidator!(P,P,S) != ""); static assert(optionValidator!(P,F,S,P) != ""); static assert(optionValidator!(C,C,S) != ""); static assert(optionValidator!(S,S,P,S,S,P,S) != ""); static assert(optionValidator!(S,S,P,P) != ""); static assert(optionValidator!(S,S,S,P) != ""); static assert(optionValidator!(C,A,S,P,C,A,F) == ""); static assert(optionValidator!(C,A,P,C,A,S,F) == ""); } unittest // bugzilla 15914 { bool opt; string[] args = ["program", "-a"]; getopt(args, config.passThrough, 'a', &opt); assert(opt); opt = false; args = ["program", "-a"]; getopt(args, 'a', &opt); assert(opt); opt = false; args = ["program", "-a"]; getopt(args, 'a', "help string", &opt); assert(opt); opt = false; args = ["program", "-a"]; getopt(args, config.caseSensitive, 'a', "help string", &opt); assert(opt); } private void getoptImpl(T...)(ref string[] args, ref configuration cfg, ref GetoptResult rslt, ref GetOptException excep, T opts) { enum validationMessage = optionValidator!T; static assert(validationMessage == "", validationMessage); import std.algorithm : remove; import std.conv : to; static if (opts.length) { static if (is(typeof(opts[0]) : config)) { // it's a configuration flag, act on it setConfig(cfg, opts[0]); return getoptImpl(args, cfg, rslt, excep, opts[1 .. $]); } else { // it's an option string auto option = to!string(opts[0]); Option optionHelp = splitAndGet(option); optionHelp.required = cfg.required; static if (is(typeof(opts[1]) : string)) { auto receiver = opts[2]; optionHelp.help = opts[1]; immutable lowSliceIdx = 3; } else { auto receiver = opts[1]; immutable lowSliceIdx = 2; } rslt.options ~= optionHelp; bool incremental; // Handle options of the form --blah+ if (option.length && option[$ - 1] == autoIncrementChar) { option = option[0 .. $ - 1]; incremental = true; } bool optWasHandled = handleOption(option, receiver, args, cfg, incremental); if (cfg.required && !optWasHandled) { excep = new GetOptException("Required option " ~ option ~ " was not supplied", excep); } cfg.required = false; getoptImpl(args, cfg, rslt, excep, opts[lowSliceIdx .. $]); } } else { // no more options to look for, potentially some arguments left for (size_t i = 1; i < args.length;) { auto a = args[i]; if (endOfOptions.length && a == endOfOptions) { // Consume the "--" if keepEndOfOptions is not specified if (!cfg.keepEndOfOptions) args = args.remove(i); break; } if (!a.length || a[0] != optionChar) { // not an option if (cfg.stopOnFirstNonOption) break; ++i; continue; } if (a == "--help" || a == "-h") { rslt.helpWanted = true; args = args.remove(i); continue; } if (!cfg.passThrough) { throw new GetOptException("Unrecognized option "~a, excep); } ++i; } Option helpOpt; helpOpt.optShort = "-h"; helpOpt.optLong = "--help"; helpOpt.help = "This help information."; rslt.options ~= helpOpt; } } private bool handleOption(R)(string option, R receiver, ref string[] args, ref configuration cfg, bool incremental) { import std.algorithm : map, splitter; import std.ascii : isAlpha; import std.conv : text, to; // Scan arguments looking for a match for this option bool ret = false; for (size_t i = 1; i < args.length; ) { auto a = args[i]; if (endOfOptions.length && a == endOfOptions) break; if (cfg.stopOnFirstNonOption && (!a.length || a[0] != optionChar)) { // first non-option is end of options break; } // Unbundle bundled arguments if necessary if (cfg.bundling && a.length > 2 && a[0] == optionChar && a[1] != optionChar) { string[] expanded; foreach (j, dchar c; a[1 .. $]) { // If the character is not alpha, stop right there. This allows // e.g. -j100 to work as "pass argument 100 to option -j". if (!isAlpha(c)) { if (c == '=') j++; expanded ~= a[j + 1 .. $]; break; } expanded ~= text(optionChar, c); } args = args[0 .. i] ~ expanded ~ args[i + 1 .. $]; continue; } string val; if (!optMatch(a, option, val, cfg)) { ++i; continue; } ret = true; // found it // from here on, commit to eat args[i] // (and potentially args[i + 1] too, but that comes later) args = args[0 .. i] ~ args[i + 1 .. $]; static if (is(typeof(*receiver) == bool)) { // parse '--b=true/false' if (val.length) { *receiver = to!(typeof(*receiver))(val); break; } // no argument means set it to true *receiver = true; break; } else { import std.exception : enforce; // non-boolean option, which might include an argument //enum isCallbackWithOneParameter = is(typeof(receiver("")) : void); enum isCallbackWithLessThanTwoParameters = (is(typeof(receiver) == delegate) || is(typeof(*receiver) == function)) && !is(typeof(receiver("", ""))); if (!isCallbackWithLessThanTwoParameters && !(val.length) && !incremental) { // Eat the next argument too. Check to make sure there's one // to be eaten first, though. enforce(i < args.length, "Missing value for argument " ~ a ~ "."); val = args[i]; args = args[0 .. i] ~ args[i + 1 .. $]; } static if (is(typeof(*receiver) == enum)) { *receiver = to!(typeof(*receiver))(val); } else static if (is(typeof(*receiver) : real)) { // numeric receiver if (incremental) ++*receiver; else *receiver = to!(typeof(*receiver))(val); } else static if (is(typeof(*receiver) == string)) { // string receiver *receiver = to!(typeof(*receiver))(val); } else static if (is(typeof(receiver) == delegate) || is(typeof(*receiver) == function)) { static if (is(typeof(receiver("", "")) : void)) { // option with argument receiver(option, val); } else static if (is(typeof(receiver("")) : void)) { static assert(is(typeof(receiver("")) : void)); // boolean-style receiver receiver(option); } else { static assert(is(typeof(receiver()) : void)); // boolean-style receiver without argument receiver(); } } else static if (isArray!(typeof(*receiver))) { // array receiver import std.range : ElementEncodingType; alias E = ElementEncodingType!(typeof(*receiver)); if (arraySep == "") { *receiver ~= to!E(val); } else { foreach (elem; val.splitter(arraySep).map!(a => to!E(a))()) *receiver ~= elem; } } else static if (isAssociativeArray!(typeof(*receiver))) { // hash receiver alias K = typeof(receiver.keys[0]); alias V = typeof(receiver.values[0]); import std.range : only; import std.typecons : Tuple, tuple; import std.string : indexOf; static Tuple!(K, V) getter(string input) { auto j = indexOf(input, assignChar); auto key = input[0 .. j]; auto value = input[j + 1 .. $]; return tuple(to!K(key), to!V(value)); } static void setHash(Range)(R receiver, Range range) { foreach (k, v; range.map!getter) (*receiver)[k] = v; } if (arraySep == "") setHash(receiver, val.only); else setHash(receiver, val.splitter(arraySep)); } else { static assert(false, "Dunno how to deal with type " ~ typeof(receiver).stringof); } } } return ret; } // 5316 - arrays with arraySep unittest { import std.conv; arraySep = ","; scope (exit) arraySep = ""; string[] names; auto args = ["program.name", "-nfoo,bar,baz"]; getopt(args, "name|n", &names); assert(names == ["foo", "bar", "baz"], to!string(names)); names = names.init; args = ["program.name", "-n", "foo,bar,baz"]; getopt(args, "name|n", &names); assert(names == ["foo", "bar", "baz"], to!string(names)); names = names.init; args = ["program.name", "--name=foo,bar,baz"]; getopt(args, "name|n", &names); assert(names == ["foo", "bar", "baz"], to!string(names)); names = names.init; args = ["program.name", "--name", "foo,bar,baz"]; getopt(args, "name|n", &names); assert(names == ["foo", "bar", "baz"], to!string(names)); } // 5316 - associative arrays with arraySep unittest { import std.conv; arraySep = ","; scope (exit) arraySep = ""; int[string] values; values = values.init; auto args = ["program.name", "-vfoo=0,bar=1,baz=2"]; getopt(args, "values|v", &values); assert(values == ["foo":0, "bar":1, "baz":2], to!string(values)); values = values.init; args = ["program.name", "-v", "foo=0,bar=1,baz=2"]; getopt(args, "values|v", &values); assert(values == ["foo":0, "bar":1, "baz":2], to!string(values)); values = values.init; args = ["program.name", "--values=foo=0,bar=1,baz=2"]; getopt(args, "values|t", &values); assert(values == ["foo":0, "bar":1, "baz":2], to!string(values)); values = values.init; args = ["program.name", "--values", "foo=0,bar=1,baz=2"]; getopt(args, "values|v", &values); assert(values == ["foo":0, "bar":1, "baz":2], to!string(values)); } /** The option character (default '-'). Defaults to '-' but it can be assigned to prior to calling $(D getopt). */ dchar optionChar = '-'; /** The string that conventionally marks the end of all options (default '--'). Defaults to "--" but can be assigned to prior to calling $(D getopt). Assigning an empty string to $(D endOfOptions) effectively disables it. */ string endOfOptions = "--"; /** The assignment character used in options with parameters (default '='). Defaults to '=' but can be assigned to prior to calling $(D getopt). */ dchar assignChar = '='; /** The string used to separate the elements of an array or associative array (default is "" which means the elements are separated by whitespace). Defaults to "" but can be assigned to prior to calling $(D getopt). */ string arraySep = ""; enum autoIncrementChar = '+'; private struct configuration { import std.bitmanip : bitfields; mixin(bitfields!( bool, "caseSensitive", 1, bool, "bundling", 1, bool, "passThrough", 1, bool, "stopOnFirstNonOption", 1, bool, "keepEndOfOptions", 1, bool, "required", 1, ubyte, "", 2)); } private bool optMatch(string arg, string optPattern, ref string value, configuration cfg) { import std.uni : toUpper; import std.string : indexOf; import std.array : split; //writeln("optMatch:\n ", arg, "\n ", optPattern, "\n ", value); //scope(success) writeln("optMatch result: ", value); if (!arg.length || arg[0] != optionChar) return false; // yank the leading '-' arg = arg[1 .. $]; immutable isLong = arg.length > 1 && arg[0] == optionChar; //writeln("isLong: ", isLong); // yank the second '-' if present if (isLong) arg = arg[1 .. $]; immutable eqPos = indexOf(arg, assignChar); if (isLong && eqPos >= 0) { // argument looks like --opt=value value = arg[eqPos + 1 .. $]; arg = arg[0 .. eqPos]; } else { if (!isLong && eqPos==1) { // argument looks like -o=value value = arg[2 .. $]; arg = arg[0 .. 1]; } else if (!isLong && !cfg.bundling) { // argument looks like -ovalue and there's no bundling value = arg[1 .. $]; arg = arg[0 .. 1]; } else { // argument looks like --opt, or -oxyz with bundling value = null; } } //writeln("Arg: ", arg, " pattern: ", optPattern, " value: ", value); // Split the option const variants = split(optPattern, "|"); foreach (v ; variants) { //writeln("Trying variant: ", v, " against ", arg); if (arg == v || !cfg.caseSensitive && toUpper(arg) == toUpper(v)) return true; if (cfg.bundling && !isLong && v.length == 1 && indexOf(arg, v) >= 0) { //writeln("success"); return true; } } return false; } private void setConfig(ref configuration cfg, config option) { switch (option) { case config.caseSensitive: cfg.caseSensitive = true; break; case config.caseInsensitive: cfg.caseSensitive = false; break; case config.bundling: cfg.bundling = true; break; case config.noBundling: cfg.bundling = false; break; case config.passThrough: cfg.passThrough = true; break; case config.noPassThrough: cfg.passThrough = false; break; case config.required: cfg.required = true; break; case config.stopOnFirstNonOption: cfg.stopOnFirstNonOption = true; break; case config.keepEndOfOptions: cfg.keepEndOfOptions = true; break; default: assert(false); } } unittest { import std.conv; import std.math; uint paranoid = 2; string[] args = ["program.name", "--paranoid", "--paranoid", "--paranoid"]; getopt(args, "paranoid+", ¶noid); assert(paranoid == 5, to!(string)(paranoid)); enum Color { no, yes } Color color; args = ["program.name", "--color=yes",]; getopt(args, "color", &color); assert(color, to!(string)(color)); color = Color.no; args = ["program.name", "--color", "yes",]; getopt(args, "color", &color); assert(color, to!(string)(color)); string data = "file.dat"; int length = 24; bool verbose = false; args = ["program.name", "--length=5", "--file", "dat.file", "--verbose"]; getopt( args, "length", &length, "file", &data, "verbose", &verbose); assert(args.length == 1); assert(data == "dat.file"); assert(length == 5); assert(verbose); // string[] outputFiles; args = ["program.name", "--output=myfile.txt", "--output", "yourfile.txt"]; getopt(args, "output", &outputFiles); assert(outputFiles.length == 2 && outputFiles[0] == "myfile.txt" && outputFiles[1] == "yourfile.txt"); outputFiles = []; arraySep = ","; args = ["program.name", "--output", "myfile.txt,yourfile.txt"]; getopt(args, "output", &outputFiles); assert(outputFiles.length == 2 && outputFiles[0] == "myfile.txt" && outputFiles[1] == "yourfile.txt"); arraySep = ""; foreach (testArgs; [["program.name", "--tune=alpha=0.5", "--tune", "beta=0.6"], ["program.name", "--tune=alpha=0.5,beta=0.6"], ["program.name", "--tune", "alpha=0.5,beta=0.6"]]) { arraySep = ","; double[string] tuningParms; getopt(testArgs, "tune", &tuningParms); assert(testArgs.length == 1); assert(tuningParms.length == 2); assert(approxEqual(tuningParms["alpha"], 0.5)); assert(approxEqual(tuningParms["beta"], 0.6)); arraySep = ""; } uint verbosityLevel = 1; void myHandler(string option) { if (option == "quiet") { verbosityLevel = 0; } else { assert(option == "verbose"); verbosityLevel = 2; } } args = ["program.name", "--quiet"]; getopt(args, "verbose", &myHandler, "quiet", &myHandler); assert(verbosityLevel == 0); args = ["program.name", "--verbose"]; getopt(args, "verbose", &myHandler, "quiet", &myHandler); assert(verbosityLevel == 2); verbosityLevel = 1; void myHandler2(string option, string value) { assert(option == "verbose"); verbosityLevel = 2; } args = ["program.name", "--verbose", "2"]; getopt(args, "verbose", &myHandler2); assert(verbosityLevel == 2); verbosityLevel = 1; void myHandler3() { verbosityLevel = 2; } args = ["program.name", "--verbose"]; getopt(args, "verbose", &myHandler3); assert(verbosityLevel == 2); bool foo, bar; args = ["program.name", "--foo", "--bAr"]; getopt(args, std.getopt.config.caseSensitive, std.getopt.config.passThrough, "foo", &foo, "bar", &bar); assert(args[1] == "--bAr"); // test stopOnFirstNonOption args = ["program.name", "--foo", "nonoption", "--bar"]; foo = bar = false; getopt(args, std.getopt.config.stopOnFirstNonOption, "foo", &foo, "bar", &bar); assert(foo && !bar && args[1] == "nonoption" && args[2] == "--bar"); args = ["program.name", "--foo", "nonoption", "--zab"]; foo = bar = false; getopt(args, std.getopt.config.stopOnFirstNonOption, "foo", &foo, "bar", &bar); assert(foo && !bar && args[1] == "nonoption" && args[2] == "--zab"); args = ["program.name", "--fb1", "--fb2=true", "--tb1=false"]; bool fb1, fb2; bool tb1 = true; getopt(args, "fb1", &fb1, "fb2", &fb2, "tb1", &tb1); assert(fb1 && fb2 && !tb1); // test keepEndOfOptions args = ["program.name", "--foo", "nonoption", "--bar", "--", "--baz"]; getopt(args, std.getopt.config.keepEndOfOptions, "foo", &foo, "bar", &bar); assert(args == ["program.name", "nonoption", "--", "--baz"]); // Ensure old behavior without the keepEndOfOptions args = ["program.name", "--foo", "nonoption", "--bar", "--", "--baz"]; getopt(args, "foo", &foo, "bar", &bar); assert(args == ["program.name", "nonoption", "--baz"]); // test function callbacks static class MyEx : Exception { this() { super(""); } this(string option) { this(); this.option = option; } this(string option, string value) { this(option); this.value = value; } string option; string value; } static void myStaticHandler1() { throw new MyEx(); } args = ["program.name", "--verbose"]; try { getopt(args, "verbose", &myStaticHandler1); assert(0); } catch (MyEx ex) { assert(ex.option is null && ex.value is null); } static void myStaticHandler2(string option) { throw new MyEx(option); } args = ["program.name", "--verbose"]; try { getopt(args, "verbose", &myStaticHandler2); assert(0); } catch (MyEx ex) { assert(ex.option == "verbose" && ex.value is null); } static void myStaticHandler3(string option, string value) { throw new MyEx(option, value); } args = ["program.name", "--verbose", "2"]; try { getopt(args, "verbose", &myStaticHandler3); assert(0); } catch (MyEx ex) { assert(ex.option == "verbose" && ex.value == "2"); } } unittest { // From bugzilla 2142 bool f_linenum, f_filename; string[] args = [ "", "-nl" ]; getopt ( args, std.getopt.config.bundling, //std.getopt.config.caseSensitive, "linenum|l", &f_linenum, "filename|n", &f_filename ); assert(f_linenum); assert(f_filename); } unittest { // From bugzilla 6887 string[] p; string[] args = ["", "-pa"]; getopt(args, "p", &p); assert(p.length == 1); assert(p[0] == "a"); } unittest { // From bugzilla 6888 int[string] foo; auto args = ["", "-t", "a=1"]; getopt(args, "t", &foo); assert(foo == ["a":1]); } unittest { // From bugzilla 9583 int opt; auto args = ["prog", "--opt=123", "--", "--a", "--b", "--c"]; getopt(args, "opt", &opt); assert(args == ["prog", "--a", "--b", "--c"]); } unittest { string foo, bar; auto args = ["prog", "-thello", "-dbar=baz"]; getopt(args, "t", &foo, "d", &bar); assert(foo == "hello"); assert(bar == "bar=baz"); // From bugzilla 5762 string a; args = ["prog", "-a-0x12"]; getopt(args, config.bundling, "a|addr", &a); assert(a == "-0x12", a); args = ["prog", "--addr=-0x12"]; getopt(args, config.bundling, "a|addr", &a); assert(a == "-0x12"); // From https://d.puremagic.com/issues/show_bug.cgi?id=11764 args = ["main", "-test"]; bool opt; args.getopt(config.passThrough, "opt", &opt); assert(args == ["main", "-test"]); // From https://issues.dlang.org/show_bug.cgi?id=15220 args = ["main", "-o=str"]; string o; args.getopt("o", &o); assert(o == "str"); args = ["main", "-o=str"]; o = null; args.getopt(config.bundling, "o", &o); assert(o == "str"); } unittest // 5228 { import std.exception; import std.conv; auto args = ["prog", "--foo=bar"]; int abc; assertThrown!GetOptException(getopt(args, "abc", &abc)); args = ["prog", "--abc=string"]; assertThrown!ConvException(getopt(args, "abc", &abc)); } unittest // From bugzilla 7693 { import std.exception; enum Foo { bar, baz } auto args = ["prog", "--foo=barZZZ"]; Foo foo; assertThrown(getopt(args, "foo", &foo)); args = ["prog", "--foo=bar"]; assertNotThrown(getopt(args, "foo", &foo)); args = ["prog", "--foo", "barZZZ"]; assertThrown(getopt(args, "foo", &foo)); args = ["prog", "--foo", "baz"]; assertNotThrown(getopt(args, "foo", &foo)); } unittest // same bug as 7693 only for bool { import std.exception; auto args = ["prog", "--foo=truefoobar"]; bool foo; assertThrown(getopt(args, "foo", &foo)); args = ["prog", "--foo"]; getopt(args, "foo", &foo); assert(foo); } unittest { bool foo; auto args = ["prog", "--foo"]; getopt(args, "foo", &foo); assert(foo); } unittest { bool foo; bool bar; auto args = ["prog", "--foo", "-b"]; getopt(args, config.caseInsensitive,"foo|f", "Some foo", &foo, config.caseSensitive, "bar|b", "Some bar", &bar); assert(foo); assert(bar); } unittest { bool foo; bool bar; auto args = ["prog", "-b", "--foo", "-z"]; getopt(args, config.caseInsensitive, config.required, "foo|f", "Some foo", &foo, config.caseSensitive, "bar|b", "Some bar", &bar, config.passThrough); assert(foo); assert(bar); } unittest { import std.exception; bool foo; bool bar; auto args = ["prog", "-b", "-z"]; assertThrown(getopt(args, config.caseInsensitive, config.required, "foo|f", "Some foo", &foo, config.caseSensitive, "bar|b", "Some bar", &bar, config.passThrough)); } unittest { import std.exception; bool foo; bool bar; auto args = ["prog", "--foo", "-z"]; assertNotThrown(getopt(args, config.caseInsensitive, config.required, "foo|f", "Some foo", &foo, config.caseSensitive, "bar|b", "Some bar", &bar, config.passThrough)); assert(foo); assert(!bar); } unittest { bool foo; auto args = ["prog", "-f"]; auto r = getopt(args, config.caseInsensitive, "help|f", "Some foo", &foo); assert(foo); assert(!r.helpWanted); } unittest // implicit help option without config.passThrough { string[] args = ["program", "--help"]; auto r = getopt(args); assert(r.helpWanted); } // Issue 13316 - std.getopt: implicit help option breaks the next argument unittest { string[] args = ["program", "--help", "--", "something"]; getopt(args); assert(args == ["program", "something"]); args = ["program", "--help", "--"]; getopt(args); assert(args == ["program"]); bool b; args = ["program", "--help", "nonoption", "--option"]; getopt(args, config.stopOnFirstNonOption, "option", &b); assert(args == ["program", "nonoption", "--option"]); } // Issue 13317 - std.getopt: endOfOptions broken when it doesn't look like an option unittest { auto endOfOptionsBackup = endOfOptions; scope(exit) endOfOptions = endOfOptionsBackup; endOfOptions = "endofoptions"; string[] args = ["program", "endofoptions", "--option"]; bool b = false; getopt(args, "option", &b); assert(!b); assert(args == ["program", "--option"]); } /** This function prints the passed $(D Option)s and text in an aligned manner on $(D stdout). The passed text will be printed first, followed by a newline, then the short and long version of every option will be printed. The short and long version will be aligned to the longest option of every $(D Option) passed. If the option is required, then "Required:" will be printed after the long version of the $(D Option). If a help message is present it will be printed next. The format is illustrated by this code: ------------ foreach(it; opt) { writefln("%*s %*s%s%s", lengthOfLongestShortOption, it.optShort, lengthOfLongestLongOption, it.optLong, it.required ? " Required: " : " ", it.help); } ------------ Params: text = The text to printed at the beginning of the help output. opt = The $(D Option) extracted from the $(D getopt) parameter. */ void defaultGetoptPrinter(string text, Option[] opt) { import std.stdio : stdout; defaultGetoptFormatter(stdout.lockingTextWriter(), text, opt); } /** This function writes the passed text and $(D Option) into an output range in the manner described in the documentation of function $(D defaultGetoptPrinter). Params: output = The output range used to write the help information. text = The text to print at the beginning of the help output. opt = The $(D Option) extracted from the $(D getopt) parameter. */ void defaultGetoptFormatter(Output)(Output output, string text, Option[] opt) { import std.format : formattedWrite; import std.algorithm : min, max; output.formattedWrite("%s\n", text); size_t ls, ll; bool hasRequired = false; foreach (it; opt) { ls = max(ls, it.optShort.length); ll = max(ll, it.optLong.length); hasRequired = hasRequired || it.required; } size_t argLength = ls + ll + 2; string re = " Required: "; foreach (it; opt) { output.formattedWrite("%*s %*s%*s%s\n", ls, it.optShort, ll, it.optLong, hasRequired ? re.length : 1, it.required ? re : " ", it.help); } } unittest { import std.conv; import std.array; import std.string; bool a; auto args = ["prog", "--foo"]; auto t = getopt(args, "foo|f", "Help", &a); string s; auto app = appender!string(); defaultGetoptFormatter(app, "Some Text", t.options); string helpMsg = app.data; //writeln(helpMsg); assert(helpMsg.length); assert(helpMsg.count("\n") == 3, to!string(helpMsg.count("\n")) ~ " " ~ helpMsg); assert(helpMsg.indexOf("--foo") != -1); assert(helpMsg.indexOf("-f") != -1); assert(helpMsg.indexOf("-h") != -1); assert(helpMsg.indexOf("--help") != -1); assert(helpMsg.indexOf("Help") != -1); string wanted = "Some Text\n-f --foo Help\n-h --help This help " ~ "information.\n"; assert(wanted == helpMsg); } unittest { import std.conv; import std.string; import std.array ; bool a; auto args = ["prog", "--foo"]; auto t = getopt(args, config.required, "foo|f", "Help", &a); string s; auto app = appender!string(); defaultGetoptFormatter(app, "Some Text", t.options); string helpMsg = app.data; //writeln(helpMsg); assert(helpMsg.length); assert(helpMsg.count("\n") == 3, to!string(helpMsg.count("\n")) ~ " " ~ helpMsg); assert(helpMsg.indexOf("Required:") != -1); assert(helpMsg.indexOf("--foo") != -1); assert(helpMsg.indexOf("-f") != -1); assert(helpMsg.indexOf("-h") != -1); assert(helpMsg.indexOf("--help") != -1); assert(helpMsg.indexOf("Help") != -1); string wanted = "Some Text\n-f --foo Required: Help\n-h --help " ~ " This help information.\n"; assert(wanted == helpMsg, helpMsg ~ wanted); } unittest // Issue 14724 { bool a; auto args = ["prog", "--help"]; GetoptResult rslt; try { rslt = getopt(args, config.required, "foo|f", "bool a", &a); } catch(Exception e) { assert(false, "If the request for help was passed required options" "must not be set."); } assert(rslt.helpWanted); } ldc-1.1.0-beta3-src/runtime/phobos/std/bitmanip.d0000664000175000017500000031540712776215007017670 0ustar kaikai// Written in the D programming language. /** Bit-level manipulation facilities. Macros: WIKI = StdBitarray Copyright: Copyright Digital Mars 2007 - 2011. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei Alexandrescu), Jonathan M Davis, Alex Rønne Petersen, Damian Ziemba Amaury SECHET Source: $(PHOBOSSRC std/_bitmanip.d) */ /* Copyright Digital Mars 2007 - 2012. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.bitmanip; //debug = bitarray; // uncomment to turn on debugging printf's import std.range.primitives; public import std.system : Endian; import std.traits; version(unittest) { import std.stdio; } private string myToString(ulong n) { import core.internal.string; UnsignedStringBuf buf; auto s = unsignedToTempString(n, buf); return cast(string)s ~ (n > uint.max ? "UL" : "U"); } private template createAccessors( string store, T, string name, size_t len, size_t offset) { static if (!name.length) { // No need to create any accessor enum result = ""; } else static if (len == 0) { // Fields of length 0 are always zero enum result = "enum "~T.stringof~" "~name~" = 0;\n"; } else { enum ulong maskAllElse = ((~0uL) >> (64 - len)) << offset, signBitCheck = 1uL << (len - 1); static if (T.min < 0) { enum long minVal = -(1uL << (len - 1)); enum ulong maxVal = (1uL << (len - 1)) - 1; alias UT = Unsigned!(T); enum UT extendSign = cast(UT)~((~0uL) >> (64 - len)); } else { enum ulong minVal = 0; enum ulong maxVal = (~0uL) >> (64 - len); enum extendSign = 0; } static if (is(T == bool)) { static assert(len == 1); enum result = // getter "@property bool " ~ name ~ "() @safe pure nothrow @nogc const { return " ~"("~store~" & "~myToString(maskAllElse)~") != 0;}\n" // setter ~"@property void " ~ name ~ "(bool v) @safe pure nothrow @nogc { " ~"if (v) "~store~" |= "~myToString(maskAllElse)~";" ~"else "~store~" &= ~cast(typeof("~store~"))"~myToString(maskAllElse)~";}\n"; } else { // getter enum result = "@property "~T.stringof~" "~name~"() @safe pure nothrow @nogc const { auto result = " ~"("~store~" & " ~ myToString(maskAllElse) ~ ") >>" ~ myToString(offset) ~ ";" ~ (T.min < 0 ? "if (result >= " ~ myToString(signBitCheck) ~ ") result |= " ~ myToString(extendSign) ~ ";" : "") ~ " return cast("~T.stringof~") result;}\n" // setter ~"@property void "~name~"("~T.stringof~" v) @safe pure nothrow @nogc { " ~"assert(v >= "~name~`_min, "Value is smaller than the minimum value of bitfield '`~name~`'"); ` ~"assert(v <= "~name~`_max, "Value is greater than the maximum value of bitfield '`~name~`'"); ` ~store~" = cast(typeof("~store~"))" ~" (("~store~" & ~cast(typeof("~store~"))"~myToString(maskAllElse)~")" ~" | ((cast(typeof("~store~")) v << "~myToString(offset)~")" ~" & "~myToString(maskAllElse)~"));}\n" // constants ~"enum "~T.stringof~" "~name~"_min = cast("~T.stringof~")" ~myToString(minVal)~"; " ~" enum "~T.stringof~" "~name~"_max = cast("~T.stringof~")" ~myToString(maxVal)~"; "; } } } private template createStoreName(Ts...) { static if (Ts.length < 2) enum createStoreName = ""; else enum createStoreName = "_" ~ Ts[1] ~ createStoreName!(Ts[3 .. $]); } private template createFields(string store, size_t offset, Ts...) { static if (!Ts.length) { static if (offset == ubyte.sizeof * 8) alias StoreType = ubyte; else static if (offset == ushort.sizeof * 8) alias StoreType = ushort; else static if (offset == uint.sizeof * 8) alias StoreType = uint; else static if (offset == ulong.sizeof * 8) alias StoreType = ulong; else { static assert(false, "Field widths must sum to 8, 16, 32, or 64"); alias StoreType = ulong; // just to avoid another error msg } enum result = "private " ~ StoreType.stringof ~ " " ~ store ~ ";"; } else { enum result = createAccessors!(store, Ts[0], Ts[1], Ts[2], offset).result ~ createFields!(store, offset + Ts[2], Ts[3 .. $]).result; } } private ulong getBitsForAlign(ulong a) { ulong bits = 0; while ((a & 0x01) == 0) { bits++; a >>= 1; } assert(a == 1, "alignment is not a power of 2"); return bits; } private template createReferenceAccessor(string store, T, ulong bits, string name) { enum mask = (1UL << bits) - 1; // getter enum result = "@property "~T.stringof~" "~name~"() @trusted pure nothrow @nogc const { auto result = " ~ "("~store~" & "~myToString(~mask)~");" ~ " return cast("~T.stringof~") cast(void*) result;}\n" // setter ~"@property void "~name~"("~T.stringof~" v) @trusted pure nothrow @nogc { " ~"assert(((cast(typeof("~store~")) cast(void*) v) & "~myToString(mask)~`) == 0, "Value not properly aligned for '`~name~`'"); ` ~store~" = cast(typeof("~store~"))" ~" (("~store~" & (cast(typeof("~store~")) "~myToString(mask)~"))" ~" | ((cast(typeof("~store~")) cast(void*) v) & (cast(typeof("~store~")) "~myToString(~mask)~")));}\n"; } private template sizeOfBitField(T...) { static if(T.length < 2) enum sizeOfBitField = 0; else enum sizeOfBitField = T[2] + sizeOfBitField!(T[3 .. $]); } private template createTaggedReference(string store, T, ulong a, string name, Ts...) { static assert(sizeOfBitField!Ts <= getBitsForAlign(a), "Fields must fit in the bits know to be zero because of alignment."); enum result = createReferenceAccessor!(store, T, sizeOfBitField!Ts, name).result ~ createFields!(store, 0, Ts, size_t, "", T.sizeof * 8 - sizeOfBitField!Ts).result; } /** Allows creating bit fields inside $(D_PARAM struct)s and $(D_PARAM class)es. Example: ---- struct A { int a; mixin(bitfields!( uint, "x", 2, int, "y", 3, uint, "z", 2, bool, "flag", 1)); } A obj; obj.x = 2; obj.z = obj.x; ---- The example above creates a bitfield pack of eight bits, which fit in one $(D_PARAM ubyte). The bitfields are allocated starting from the least significant bit, i.e. x occupies the two least significant bits of the bitfields storage. The sum of all bit lengths in one $(D_PARAM bitfield) instantiation must be exactly 8, 16, 32, or 64. If padding is needed, just allocate one bitfield with an empty name. Example: ---- struct A { mixin(bitfields!( bool, "flag1", 1, bool, "flag2", 1, uint, "", 6)); } ---- The type of a bit field can be any integral type or enumerated type. The most efficient type to store in bitfields is $(D_PARAM bool), followed by unsigned types, followed by signed types. */ template bitfields(T...) { enum { bitfields = createFields!(createStoreName!(T), 0, T).result } } /** This string mixin generator allows one to create tagged pointers inside $(D_PARAM struct)s and $(D_PARAM class)es. A tagged pointer uses the bits known to be zero in a normal pointer or class reference to store extra information. For example, a pointer to an integer must be 4-byte aligned, so there are 2 bits that are always known to be zero. One can store a 2-bit integer there. The example above creates a tagged pointer in the struct A. The pointer is of type $(D uint*) as specified by the first argument, and is named x, as specified by the second argument. Following arguments works the same way as $(D bitfield)'s. The bitfield must fit into the bits known to be zero because of the pointer alignment. $(RED Warning: Don't use $(D taggedPointer) with pointers to garbage collected objects, as it will result in undefined behaviour. See $(DDLINK spec/garbage, Garbage Collection, Garbage Collection) for details.) */ template taggedPointer(T : T*, string name, Ts...) { enum taggedPointer = createTaggedReference!(createStoreName!(T, name, 0, Ts), T*, T.alignof, name, Ts).result; } /// unittest { struct A { int a; mixin(taggedPointer!( uint*, "x", bool, "b1", 1, bool, "b2", 1)); } A obj; obj.x = new uint; obj.b1 = true; obj.b2 = false; } /** This string mixin generator allows one to create tagged class reference inside $(D_PARAM struct)s and $(D_PARAM class)es. A tagged class reference uses the bits known to be zero in a normal class reference to store extra information. For example, a pointer to an integer must be 4-byte aligned, so there are 2 bits that are always known to be zero. One can store a 2-bit integer there. The example above creates a tagged reference to an Object in the struct A. This expects the same parameters as $(D taggedPointer), except the first argument which must be a class type instead of a pointer type. $(RED Warning: Don't use $(D taggedClassRef) with references to garbage collected objects, as it will result in undefined behaviour. See $(DDLINK spec/garbage, Garbage Collection, Garbage Collection) for details.) */ template taggedClassRef(T, string name, Ts...) if(is(T == class)) { enum taggedClassRef = createTaggedReference!(createStoreName!(T, name, 0, Ts), T, 8, name, Ts).result; } /// unittest { struct A { int a; mixin(taggedClassRef!( Object, "o", uint, "i", 2)); } A obj; obj.o = new Object(); obj.i = 3; } @safe pure nothrow @nogc unittest { // Degenerate bitfields (#8474 / #11160) tests mixed with range tests struct Test1 { mixin(bitfields!(uint, "a", 32, uint, "b", 4, uint, "c", 4, uint, "d", 8, uint, "e", 16,)); static assert(Test1.b_min == 0); static assert(Test1.b_max == 15); } struct Test2 { mixin(bitfields!(bool, "a", 0, ulong, "b", 64)); static assert(Test2.b_min == ulong.min); static assert(Test2.b_max == ulong.max); } struct Test1b { mixin(bitfields!(bool, "a", 0, int, "b", 8)); } struct Test2b { mixin(bitfields!(int, "a", 32, int, "b", 4, int, "c", 4, int, "d", 8, int, "e", 16,)); static assert(Test2b.b_min == -8); static assert(Test2b.b_max == 7); } struct Test3b { mixin(bitfields!(bool, "a", 0, long, "b", 64)); static assert(Test3b.b_min == long.min); static assert(Test3b.b_max == long.max); } struct Test4b { mixin(bitfields!(long, "a", 32, int, "b", 32)); } // Sign extension tests Test2b t2b; Test4b t4b; t2b.b = -5; assert(t2b.b == -5); t2b.d = -5; assert(t2b.d == -5); t2b.e = -5; assert(t2b.e == -5); t4b.a = -5; assert(t4b.a == -5L); } unittest { struct Test5 { mixin(taggedPointer!( int*, "a", uint, "b", 2)); } Test5 t5; t5.a = null; t5.b = 3; assert(t5.a is null); assert(t5.b == 3); int myint = 42; t5.a = &myint; assert(t5.a is &myint); assert(t5.b == 3); struct Test6 { mixin(taggedClassRef!( Object, "o", bool, "b", 1)); } Test6 t6; t6.o = null; t6.b = false; assert(t6.o is null); assert(t6.b == false); auto o = new Object(); t6.o = o; t6.b = true; assert(t6.o is o); assert(t6.b == true); } unittest { static assert(!__traits(compiles, taggedPointer!( int*, "a", uint, "b", 3))); static assert(!__traits(compiles, taggedClassRef!( Object, "a", uint, "b", 4))); } unittest { // Bug #6686 union S { ulong bits = ulong.max; mixin (bitfields!( ulong, "back", 31, ulong, "front", 33) ); } S num; num.bits = ulong.max; num.back = 1; assert(num.bits == 0xFFFF_FFFF_8000_0001uL); } unittest { // Bug #5942 struct S { mixin(bitfields!( int, "a" , 32, int, "b" , 32 )); } S data; data.b = 42; data.a = 1; assert(data.b == 42); } unittest { struct Test { mixin(bitfields!(bool, "a", 1, uint, "b", 3, short, "c", 4)); } @safe void test() pure nothrow { Test t; t.a = true; t.b = 5; t.c = 2; assert(t.a); assert(t.b == 5); assert(t.c == 2); } test(); } unittest { { static struct Integrals { bool checkExpectations(bool eb, int ei, short es) { return b == eb && i == ei && s == es; } mixin(bitfields!( bool, "b", 1, uint, "i", 3, short, "s", 4)); } Integrals i; assert(i.checkExpectations(false, 0, 0)); i.b = true; assert(i.checkExpectations(true, 0, 0)); i.i = 7; assert(i.checkExpectations(true, 7, 0)); i.s = -8; assert(i.checkExpectations(true, 7, -8)); i.s = 7; assert(i.checkExpectations(true, 7, 7)); } //Bug# 8876 { struct MoreIntegrals { bool checkExpectations(uint eu, ushort es, uint ei) { return u == eu && s == es && i == ei; } mixin(bitfields!( uint, "u", 24, short, "s", 16, int, "i", 24)); } MoreIntegrals i; assert(i.checkExpectations(0, 0, 0)); i.s = 20; assert(i.checkExpectations(0, 20, 0)); i.i = 72; assert(i.checkExpectations(0, 20, 72)); i.u = 8; assert(i.checkExpectations(8, 20, 72)); i.s = 7; assert(i.checkExpectations(8, 7, 72)); } enum A { True, False } enum B { One, Two, Three, Four } static struct Enums { bool checkExpectations(A ea, B eb) { return a == ea && b == eb; } mixin(bitfields!( A, "a", 1, B, "b", 2, uint, "", 5)); } Enums e; assert(e.checkExpectations(A.True, B.One)); e.a = A.False; assert(e.checkExpectations(A.False, B.One)); e.b = B.Three; assert(e.checkExpectations(A.False, B.Three)); static struct SingleMember { bool checkExpectations(bool eb) { return b == eb; } mixin(bitfields!( bool, "b", 1, uint, "", 7)); } SingleMember f; assert(f.checkExpectations(false)); f.b = true; assert(f.checkExpectations(true)); } // Issue 12477 unittest { import std.algorithm : canFind; import std.bitmanip : bitfields; import core.exception : AssertError; static struct S { mixin(bitfields!( uint, "a", 6, int, "b", 2)); } S s; try { s.a = uint.max; assert(0); } catch (AssertError ae) { assert(ae.msg.canFind("Value is greater than the maximum value of bitfield 'a'"), ae.msg); } try { s.b = int.min; assert(0); } catch (AssertError ae) { assert(ae.msg.canFind("Value is smaller than the minimum value of bitfield 'b'"), ae.msg); } } /** Allows manipulating the fraction, exponent, and sign parts of a $(D_PARAM float) separately. The definition is: ---- struct FloatRep { union { float value; mixin(bitfields!( uint, "fraction", 23, ubyte, "exponent", 8, bool, "sign", 1)); } enum uint bias = 127, fractionBits = 23, exponentBits = 8, signBits = 1; } ---- */ struct FloatRep { union { float value; mixin(bitfields!( uint, "fraction", 23, ubyte, "exponent", 8, bool, "sign", 1)); } enum uint bias = 127, fractionBits = 23, exponentBits = 8, signBits = 1; } /** Allows manipulating the fraction, exponent, and sign parts of a $(D_PARAM double) separately. The definition is: ---- struct DoubleRep { union { double value; mixin(bitfields!( ulong, "fraction", 52, ushort, "exponent", 11, bool, "sign", 1)); } enum uint bias = 1023, signBits = 1, fractionBits = 52, exponentBits = 11; } ---- */ struct DoubleRep { union { double value; mixin(bitfields!( ulong, "fraction", 52, ushort, "exponent", 11, bool, "sign", 1)); } enum uint bias = 1023, signBits = 1, fractionBits = 52, exponentBits = 11; } unittest { // test reading DoubleRep x; x.value = 1.0; assert(x.fraction == 0 && x.exponent == 1023 && !x.sign); x.value = -0.5; assert(x.fraction == 0 && x.exponent == 1022 && x.sign); x.value = 0.5; assert(x.fraction == 0 && x.exponent == 1022 && !x.sign); // test writing x.fraction = 1125899906842624; x.exponent = 1025; x.sign = true; assert(x.value == -5.0); // test enums enum ABC { A, B, C } struct EnumTest { mixin(bitfields!( ABC, "x", 2, bool, "y", 1, ubyte, "z", 5)); } } unittest { // Issue #15305 struct S { mixin(bitfields!( bool, "alice", 1, ulong, "bob", 63, )); } S s; s.bob = long.max - 1; s.alice = false; assert(s.bob == long.max - 1); } /** * An array of bits. */ struct BitArray { // Explicitly undocumented. They will be removed in April 2016. @@@DEPRECATED_2016-04@@@ deprecated("Use the constructor instead.") @property void ptr(size_t* p) pure nothrow @nogc { _ptr = p; } deprecated("Use .opIndex instead.") @property inout(size_t)* ptr() inout pure nothrow @nogc { return _ptr; } deprecated("Use .length instead.") @property void len(size_t v) pure nothrow @nogc { _len = v; } deprecated("Use .length instead.") @property size_t len() const pure nothrow @nogc { return _len; } private: import std.format : FormatSpec; import core.bitop: bts, btr, bsf, bt; size_t _len; size_t* _ptr; enum bitsPerSizeT = size_t.sizeof * 8; @property size_t fullWords() const @nogc pure nothrow { return _len / bitsPerSizeT; } // Number of bits after the last full word @property size_t endBits() const @nogc pure nothrow { return _len % bitsPerSizeT; } // Bit mask to extract the bits after the last full word @property size_t endMask() const @nogc pure nothrow { return (size_t(1) << endBits) - 1; } static size_t lenToDim(size_t len) @nogc pure nothrow { return (len + (bitsPerSizeT-1)) / bitsPerSizeT; } public: /********************************************** * Gets the amount of native words backing this $(D BitArray). */ @property size_t dim() const @nogc pure nothrow { return lenToDim(_len); } /********************************************** * Gets the amount of bits in the $(D BitArray). */ @property size_t length() const @nogc pure nothrow { return _len; } /********************************************** * Sets the amount of bits in the $(D BitArray). * $(RED Warning: increasing length may overwrite bits in * final word up to the next word boundary. i.e. D dynamic * array extension semantics are not followed.) */ @property size_t length(size_t newlen) pure nothrow { if (newlen != _len) { size_t olddim = dim; size_t newdim = lenToDim(newlen); if (newdim != olddim) { // Create a fake array so we can use D's realloc machinery auto b = _ptr[0 .. olddim]; b.length = newdim; // realloc _ptr = b.ptr; } _len = newlen; } return _len; } /********************************************** * Gets the $(D i)'th bit in the $(D BitArray). */ bool opIndex(size_t i) const @nogc pure nothrow in { assert(i < _len); } body { return cast(bool) bt(_ptr, i); } unittest { debug(bitarray) printf("BitArray.opIndex.unittest\n"); void Fun(const BitArray arr) { auto x = arr[0]; assert(x == 1); } BitArray a; a.length = 3; a[0] = 1; Fun(a); } /********************************************** * Sets the $(D i)'th bit in the $(D BitArray). */ bool opIndexAssign(bool b, size_t i) @nogc pure nothrow in { assert(i < _len); } body { if (b) bts(_ptr, i); else btr(_ptr, i); return b; } /********************************************** * Duplicates the $(D BitArray) and its contents. */ @property BitArray dup() const pure nothrow { BitArray ba; auto b = _ptr[0 .. dim].dup; ba._len = _len; ba._ptr = b.ptr; return ba; } unittest { BitArray a; BitArray b; int i; debug(bitarray) printf("BitArray.dup.unittest\n"); a.length = 3; a[0] = 1; a[1] = 0; a[2] = 1; b = a.dup; assert(b.length == 3); for (i = 0; i < 3; i++) { debug(bitarray) printf("b[%d] = %d\n", i, b[i]); assert(b[i] == (((i ^ 1) & 1) ? true : false)); } } /********************************************** * Support for $(D foreach) loops for $(D BitArray). */ int opApply(scope int delegate(ref bool) dg) { int result; foreach (i; 0 .. _len) { bool b = opIndex(i); result = dg(b); this[i] = b; if (result) break; } return result; } /** ditto */ int opApply(scope int delegate(bool) dg) const { int result; foreach (i; 0 .. _len) { bool b = opIndex(i); result = dg(b); if (result) break; } return result; } /** ditto */ int opApply(scope int delegate(size_t, ref bool) dg) { int result; foreach (i; 0 .. _len) { bool b = opIndex(i); result = dg(i, b); this[i] = b; if (result) break; } return result; } /** ditto */ int opApply(scope int delegate(size_t, bool) dg) const { int result; foreach (i; 0 .. _len) { bool b = opIndex(i); result = dg(i, b); if (result) break; } return result; } unittest { debug(bitarray) printf("BitArray.opApply unittest\n"); static bool[] ba = [1,0,1]; auto a = BitArray(ba); int i; foreach (b;a) { switch (i) { case 0: assert(b == true); break; case 1: assert(b == false); break; case 2: assert(b == true); break; default: assert(0); } i++; } foreach (j,b;a) { switch (j) { case 0: assert(b == true); break; case 1: assert(b == false); break; case 2: assert(b == true); break; default: assert(0); } } } /********************************************** * Reverses the bits of the $(D BitArray). */ @property BitArray reverse() @nogc pure nothrow out (result) { assert(result == this); } body { if (_len >= 2) { bool t; size_t lo, hi; lo = 0; hi = _len - 1; for (; lo < hi; lo++, hi--) { t = this[lo]; this[lo] = this[hi]; this[hi] = t; } } return this; } unittest { debug(bitarray) printf("BitArray.reverse.unittest\n"); BitArray b; static bool[5] data = [1,0,1,1,0]; int i; b = BitArray(data); b.reverse; for (i = 0; i < data.length; i++) { assert(b[i] == data[4 - i]); } } /********************************************** * Sorts the $(D BitArray)'s elements. */ @property BitArray sort() @nogc pure nothrow out (result) { assert(result == this); } body { if (_len >= 2) { size_t lo, hi; lo = 0; hi = _len - 1; while (1) { while (1) { if (lo >= hi) goto Ldone; if (this[lo] == true) break; lo++; } while (1) { if (lo >= hi) goto Ldone; if (this[hi] == false) break; hi--; } this[lo] = false; this[hi] = true; lo++; hi--; } } Ldone: return this; } unittest { debug(bitarray) printf("BitArray.sort.unittest\n"); __gshared size_t x = 0b1100011000; __gshared ba = BitArray(10, &x); ba.sort; for (size_t i = 0; i < 6; i++) assert(ba[i] == false); for (size_t i = 6; i < 10; i++) assert(ba[i] == true); } /*************************************** * Support for operators == and != for $(D BitArray). */ bool opEquals(const ref BitArray a2) const @nogc pure nothrow { if (this.length != a2.length) return false; auto p1 = this._ptr; auto p2 = a2._ptr; if (p1[0..fullWords] != p2[0..fullWords]) return false; if (!endBits) return true; auto i = fullWords; return (p1[i] & endMask) == (p2[i] & endMask); } unittest { debug(bitarray) printf("BitArray.opEquals unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1]; static bool[] bc = [1,0,1,0,1,0,1]; static bool[] bd = [1,0,1,1,1]; static bool[] be = [1,0,1,0,1]; static bool[] bf = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; static bool[] bg = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]; auto a = BitArray(ba); auto b = BitArray(bb); auto c = BitArray(bc); auto d = BitArray(bd); auto e = BitArray(be); auto f = BitArray(bf); auto g = BitArray(bg); assert(a != b); assert(a != c); assert(a != d); assert(a == e); assert(f != g); } /*************************************** * Supports comparison operators for $(D BitArray). */ int opCmp(BitArray a2) const @nogc pure nothrow { auto lesser = this.length < a2.length ? &this : &a2; size_t fullWords = lesser.fullWords; size_t endBits = lesser.endBits; auto p1 = this._ptr; auto p2 = a2._ptr; foreach (i; 0 .. fullWords) { if (p1[i] != p2[i]) { return p1[i] & (size_t(1) << bsf(p1[i] ^ p2[i])) ? 1 : -1; } } if (endBits) { immutable i = fullWords; immutable diff = p1[i] ^ p2[i]; if (diff) { immutable index = bsf(diff); if (index < endBits) { return p1[i] & (size_t(1) << index) ? 1 : -1; } } } // Standard: // A bool value can be implicitly converted to any integral type, // with false becoming 0 and true becoming 1 return (this.length > a2.length) - (this.length < a2.length); } unittest { debug(bitarray) printf("BitArray.opCmp unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1]; static bool[] bc = [1,0,1,0,1,0,1]; static bool[] bd = [1,0,1,1,1]; static bool[] be = [1,0,1,0,1]; static bool[] bf = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]; static bool[] bg = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); auto c = BitArray(bc); auto d = BitArray(bd); auto e = BitArray(be); auto f = BitArray(bf); auto g = BitArray(bg); assert(a > b); assert(a >= b); assert(a < c); assert(a <= c); assert(a < d); assert(a <= d); assert(a == e); assert(a <= e); assert(a >= e); assert(f < g); assert(g <= g); bool[] v; foreach (i; 1 .. 256) { v.length = i; v[] = false; auto x = BitArray(v); v[i-1] = true; auto y = BitArray(v); assert(x < y); assert(x <= y); } BitArray a1, a2; for (size_t len = 4; len <= 256; len <<= 1) { a1.length = a2.length = len; a1[len-2] = a2[len-1] = true; assert(a1 > a2); a1[len-2] = a2[len-1] = false; } foreach (j; 1 .. a1.length) { a1[j-1] = a2[j] = true; assert(a1 > a2); a1[j-1] = a2[j] = false; } } /*************************************** * Support for hashing for $(D BitArray). */ size_t toHash() const @nogc pure nothrow { size_t hash = 3557; auto fullBytes = _len / 8; foreach (i; 0 .. fullBytes) { hash *= 3559; hash += (cast(byte*)this._ptr)[i]; } foreach (i; 8*fullBytes .. _len) { hash *= 3571; hash += this[i]; } return hash; } // Explicitly undocumented. It will be removed in January 2017. @@@DEPRECATED_2017-01@@@ deprecated("Use the constructor instead.") void init(bool[] ba) pure nothrow { this = BitArray(ba); } // Explicitly undocumented. It will be removed in January 2017. @@@DEPRECATED_2017-01@@@ deprecated("Use the constructor instead.") void init(void[] v, size_t numbits) pure nothrow { this = BitArray(v, numbits); } /*************************************** * Set this $(D BitArray) to the contents of $(D ba). */ this(bool[] ba) pure nothrow { length = ba.length; foreach (i, b; ba) { this[i] = b; } } // Deliberately undocumented: raw initialization of bit array. this(size_t len, size_t* ptr) { _len = len; _ptr = ptr; } /*************************************** * Map the $(D BitArray) onto $(D v), with $(D numbits) being the number of bits * in the array. Does not copy the data. $(D v.length) must be a multiple of * $(D size_t.sizeof). If there are unmapped bits in the final mapped word then * these will be set to 0. * * This is the inverse of $(D opCast). */ this(void[] v, size_t numbits) pure nothrow in { assert(numbits <= v.length * 8); assert(v.length % size_t.sizeof == 0); } body { _ptr = cast(size_t*)v.ptr; _len = numbits; if (endBits) { // Need to mask away extraneous bits from v. _ptr[dim - 1] &= endMask; } } unittest { debug(bitarray) printf("BitArray.init unittest\n"); static bool[] ba = [1,0,1,0,1]; auto a = BitArray(ba); void[] v; v = cast(void[])a; auto b = BitArray(v, a.length); assert(b[0] == 1); assert(b[1] == 0); assert(b[2] == 1); assert(b[3] == 0); assert(b[4] == 1); a[0] = 0; assert(b[0] == 0); assert(a == b); } /*************************************** * Convert to $(D void[]). */ void[] opCast(T : void[])() @nogc pure nothrow { return cast(void[])_ptr[0 .. dim]; } /*************************************** * Convert to $(D size_t[]). */ size_t[] opCast(T : size_t[])() @nogc pure nothrow { return _ptr[0 .. dim]; } unittest { debug(bitarray) printf("BitArray.opCast unittest\n"); static bool[] ba = [1,0,1,0,1]; auto a = BitArray(ba); void[] v = cast(void[])a; assert(v.length == a.dim * size_t.sizeof); } /*************************************** * Support for unary operator ~ for $(D BitArray). */ BitArray opCom() const pure nothrow { auto dim = this.dim; BitArray result; result.length = _len; result._ptr[0..dim] = ~this._ptr[0..dim]; // Avoid putting garbage in extra bits // Remove once we zero on length extension if (endBits) result._ptr[dim - 1] &= endMask; return result; } unittest { debug(bitarray) printf("BitArray.opCom unittest\n"); static bool[] ba = [1,0,1,0,1]; auto a = BitArray(ba); BitArray b = ~a; assert(b[0] == 0); assert(b[1] == 1); assert(b[2] == 0); assert(b[3] == 1); assert(b[4] == 0); } /*************************************** * Support for binary bitwise operators for $(D BitArray). */ BitArray opBinary(string op)(const BitArray e2) const pure nothrow if (op == "-" || op == "&" || op == "|" || op == "^") in { assert(_len == e2.length); } body { auto dim = this.dim; BitArray result; result.length = _len; static if (op == "-") result._ptr[0..dim] = this._ptr[0..dim] & ~e2._ptr[0..dim]; else mixin("result._ptr[0..dim] = this._ptr[0..dim]"~op~" e2._ptr[0..dim];"); // Avoid putting garbage in extra bits // Remove once we zero on length extension if (endBits) result._ptr[dim - 1] &= endMask; return result; } unittest { debug(bitarray) printf("BitArray.opAnd unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); BitArray c = a & b; assert(c[0] == 1); assert(c[1] == 0); assert(c[2] == 1); assert(c[3] == 0); assert(c[4] == 0); } unittest { debug(bitarray) printf("BitArray.opOr unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); BitArray c = a | b; assert(c[0] == 1); assert(c[1] == 0); assert(c[2] == 1); assert(c[3] == 1); assert(c[4] == 1); } unittest { debug(bitarray) printf("BitArray.opXor unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); BitArray c = a ^ b; assert(c[0] == 0); assert(c[1] == 0); assert(c[2] == 0); assert(c[3] == 1); assert(c[4] == 1); } unittest { debug(bitarray) printf("BitArray.opSub unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); BitArray c = a - b; assert(c[0] == 0); assert(c[1] == 0); assert(c[2] == 0); assert(c[3] == 0); assert(c[4] == 1); } /*************************************** * Support for operator op= for $(D BitArray). */ BitArray opOpAssign(string op)(const BitArray e2) @nogc pure nothrow if (op == "-" || op == "&" || op == "|" || op == "^") in { assert(_len == e2.length); } body { foreach (i; 0 .. fullWords) { static if (op == "-") _ptr[i] &= ~e2._ptr[i]; else mixin("_ptr[i] "~op~"= e2._ptr[i];"); } if (!endBits) return this; size_t i = fullWords; size_t endWord = _ptr[i]; static if (op == "-") endWord &= ~e2._ptr[i]; else mixin("endWord "~op~"= e2._ptr[i];"); _ptr[i] = (_ptr[i] & ~endMask) | (endWord & endMask); return this; } unittest { static bool[] ba = [1,0,1,0,1,1,0,1,0,1]; static bool[] bb = [1,0,1,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); BitArray c = a; c.length = 5; c &= b; assert(a[5] == 1); assert(a[6] == 0); assert(a[7] == 1); assert(a[8] == 0); assert(a[9] == 1); } unittest { debug(bitarray) printf("BitArray.opAndAssign unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); a &= b; assert(a[0] == 1); assert(a[1] == 0); assert(a[2] == 1); assert(a[3] == 0); assert(a[4] == 0); } unittest { debug(bitarray) printf("BitArray.opOrAssign unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); a |= b; assert(a[0] == 1); assert(a[1] == 0); assert(a[2] == 1); assert(a[3] == 1); assert(a[4] == 1); } unittest { debug(bitarray) printf("BitArray.opXorAssign unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); a ^= b; assert(a[0] == 0); assert(a[1] == 0); assert(a[2] == 0); assert(a[3] == 1); assert(a[4] == 1); } unittest { debug(bitarray) printf("BitArray.opSubAssign unittest\n"); static bool[] ba = [1,0,1,0,1]; static bool[] bb = [1,0,1,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); a -= b; assert(a[0] == 0); assert(a[1] == 0); assert(a[2] == 0); assert(a[3] == 0); assert(a[4] == 1); } /*************************************** * Support for operator ~= for $(D BitArray). * $(RED Warning: This will overwrite a bit in the final word * of the current underlying data regardless of whether it is * shared between BitArray objects. i.e. D dynamic array * concatenation semantics are not followed) */ BitArray opCatAssign(bool b) pure nothrow { length = _len + 1; this[_len - 1] = b; return this; } unittest { debug(bitarray) printf("BitArray.opCatAssign unittest\n"); static bool[] ba = [1,0,1,0,1]; auto a = BitArray(ba); BitArray b; b = (a ~= true); assert(a[0] == 1); assert(a[1] == 0); assert(a[2] == 1); assert(a[3] == 0); assert(a[4] == 1); assert(a[5] == 1); assert(b == a); } /*************************************** * ditto */ BitArray opCatAssign(BitArray b) pure nothrow { auto istart = _len; length = _len + b.length; for (auto i = istart; i < _len; i++) this[i] = b[i - istart]; return this; } unittest { debug(bitarray) printf("BitArray.opCatAssign unittest\n"); static bool[] ba = [1,0]; static bool[] bb = [0,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); BitArray c; c = (a ~= b); assert(a.length == 5); assert(a[0] == 1); assert(a[1] == 0); assert(a[2] == 0); assert(a[3] == 1); assert(a[4] == 0); assert(c == a); } /*************************************** * Support for binary operator ~ for $(D BitArray). */ BitArray opCat(bool b) const pure nothrow { BitArray r; r = this.dup; r.length = _len + 1; r[_len] = b; return r; } /** ditto */ BitArray opCat_r(bool b) const pure nothrow { BitArray r; r.length = _len + 1; r[0] = b; foreach (i; 0 .. _len) r[1 + i] = this[i]; return r; } /** ditto */ BitArray opCat(BitArray b) const pure nothrow { BitArray r; r = this.dup; r ~= b; return r; } unittest { debug(bitarray) printf("BitArray.opCat unittest\n"); static bool[] ba = [1,0]; static bool[] bb = [0,1,0]; auto a = BitArray(ba); auto b = BitArray(bb); BitArray c; c = (a ~ b); assert(c.length == 5); assert(c[0] == 1); assert(c[1] == 0); assert(c[2] == 0); assert(c[3] == 1); assert(c[4] == 0); c = (a ~ true); assert(c.length == 3); assert(c[0] == 1); assert(c[1] == 0); assert(c[2] == 1); c = (false ~ a); assert(c.length == 3); assert(c[0] == 0); assert(c[1] == 1); assert(c[2] == 0); } // Rolls double word (upper, lower) to the right by n bits and returns the // lower word of the result. private static size_t rollRight()(size_t upper, size_t lower, size_t nbits) pure @safe nothrow @nogc in { assert(nbits < bitsPerSizeT); } body { return (upper << (bitsPerSizeT - nbits)) | (lower >> nbits); } unittest { static if (size_t.sizeof == 8) { size_t x = 0x12345678_90ABCDEF; size_t y = 0xFEDBCA09_87654321; assert(rollRight(x, y, 32) == 0x90ABCDEF_FEDBCA09); assert(rollRight(y, x, 4) == 0x11234567_890ABCDE); } else static if (size_t.sizeof == 4) { size_t x = 0x12345678; size_t y = 0x90ABCDEF; assert(rollRight(x, y, 16) == 0x567890AB); assert(rollRight(y, x, 4) == 0xF1234567); } else static assert(0, "Unsupported size_t width"); } // Rolls double word (upper, lower) to the left by n bits and returns the // upper word of the result. private static size_t rollLeft()(size_t upper, size_t lower, size_t nbits) pure @safe nothrow @nogc in { assert(nbits < bitsPerSizeT); } body { return (upper << nbits) | (lower >> (bitsPerSizeT - nbits)); } unittest { static if (size_t.sizeof == 8) { size_t x = 0x12345678_90ABCDEF; size_t y = 0xFEDBCA09_87654321; assert(rollLeft(x, y, 32) == 0x90ABCDEF_FEDBCA09); assert(rollLeft(y, x, 4) == 0xEDBCA098_76543211); } else static if (size_t.sizeof == 4) { size_t x = 0x12345678; size_t y = 0x90ABCDEF; assert(rollLeft(x, y, 16) == 0x567890AB); assert(rollLeft(y, x, 4) == 0x0ABCDEF1); } } /** * Operator $(D <<=) support. * * Shifts all the bits in the array to the left by the given number of * bits. The leftmost bits are dropped, and 0's are appended to the end * to fill up the vacant bits. * * $(RED Warning: unused bits in the final word up to the next word * boundary may be overwritten by this operation. It does not attempt to * preserve bits past the end of the array.) */ void opOpAssign(string op)(size_t nbits) @nogc pure nothrow if (op == "<<") { size_t wordsToShift = nbits / bitsPerSizeT; size_t bitsToShift = nbits % bitsPerSizeT; if (wordsToShift < dim) { foreach_reverse (i; 1 .. dim - wordsToShift) { _ptr[i + wordsToShift] = rollLeft(_ptr[i], _ptr[i-1], bitsToShift); } _ptr[wordsToShift] = rollLeft(_ptr[0], 0, bitsToShift); } import std.algorithm : min; foreach (i; 0 .. min(wordsToShift, dim)) { _ptr[i] = 0; } } /** * Operator $(D >>=) support. * * Shifts all the bits in the array to the right by the given number of * bits. The rightmost bits are dropped, and 0's are inserted at the back * to fill up the vacant bits. * * $(RED Warning: unused bits in the final word up to the next word * boundary may be overwritten by this operation. It does not attempt to * preserve bits past the end of the array.) */ void opOpAssign(string op)(size_t nbits) @nogc pure nothrow if (op == ">>") { size_t wordsToShift = nbits / bitsPerSizeT; size_t bitsToShift = nbits % bitsPerSizeT; if (wordsToShift + 1 < dim) { foreach (i; 0 .. dim - wordsToShift - 1) { _ptr[i] = rollRight(_ptr[i + wordsToShift + 1], _ptr[i + wordsToShift], bitsToShift); } } // The last word needs some care, as it must shift in 0's from past the // end of the array. if (wordsToShift < dim) { _ptr[dim - wordsToShift - 1] = rollRight(0, _ptr[dim - 1] & endMask, bitsToShift); } import std.algorithm : min; foreach (i; 0 .. min(wordsToShift, dim)) { _ptr[dim - i - 1] = 0; } } unittest { import std.format : format; auto b = BitArray([1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1]); b <<= 1; assert(format("%b", b) == "01100_10101101"); b >>= 1; assert(format("%b", b) == "11001_01011010"); b <<= 4; assert(format("%b", b) == "00001_10010101"); b >>= 5; assert(format("%b", b) == "10010_10100000"); b <<= 13; assert(format("%b", b) == "00000_00000000"); b = BitArray([1, 0, 1, 1, 0, 1, 1, 1]); b >>= 8; assert(format("%b", b) == "00000000"); } // Test multi-word case unittest { import std.format : format; // This has to be long enough to occupy more than one size_t. On 64-bit // machines, this would be at least 64 bits. auto b = BitArray([ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, ]); b <<= 8; assert(format("%b", b) == "00000000_10000000_"~ "11000000_11100000_"~ "11110000_11111000_"~ "11111100_11111110_"~ "11111111_10101010"); // Test right shift of more than one size_t's worth of bits b <<= 68; assert(format("%b", b) == "00000000_00000000_"~ "00000000_00000000_"~ "00000000_00000000_"~ "00000000_00000000_"~ "00000000_00001000"); b = BitArray([ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, ]); b >>= 8; assert(format("%b", b) == "11000000_11100000_"~ "11110000_11111000_"~ "11111100_11111110_"~ "11111111_10101010_"~ "01010101_00000000"); // Test left shift of more than 1 size_t's worth of bits b >>= 68; assert(format("%b", b) == "01010000_00000000_"~ "00000000_00000000_"~ "00000000_00000000_"~ "00000000_00000000_"~ "00000000_00000000"); } /*************************************** * Return a string representation of this BitArray. * * Two format specifiers are supported: * $(LI $(B %s) which prints the bits as an array, and) * $(LI $(B %b) which prints the bits as 8-bit byte packets) * separated with an underscore. */ void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) const { switch(fmt.spec) { case 'b': return formatBitString(sink); case 's': return formatBitArray(sink); default: throw new Exception("Unknown format specifier: %" ~ fmt.spec); } } /// unittest { import std.format : format; debug(bitarray) printf("BitArray.toString unittest\n"); auto b = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); auto s1 = format("%s", b); assert(s1 == "[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]"); auto s2 = format("%b", b); assert(s2 == "00001111_00001111"); } /*************************************** * Return a lazy range of the indices of set bits. */ @property auto bitsSet() const nothrow { import std.algorithm : filter, map, joiner; import std.range : iota; return iota(dim). filter!(i => _ptr[i])(). map!(i => BitsSet!size_t(_ptr[i], i * bitsPerSizeT))(). joiner(); } /// unittest { import std.algorithm : equal; auto b1 = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); assert(b1.bitsSet.equal([4, 5, 6, 7, 12, 13, 14, 15])); BitArray b2; b2.length = 1000; b2[333] = true; b2[666] = true; b2[999] = true; assert(b2.bitsSet.equal([333, 666, 999])); } unittest { import std.algorithm : equal; import std.range : iota; debug(bitarray) printf("BitArray.bitsSet unittest\n"); BitArray b; enum wordBits = size_t.sizeof * 8; b = BitArray([size_t.max], 0); assert(b.bitsSet.empty); b = BitArray([size_t.max], 1); assert(b.bitsSet.equal([0])); b = BitArray([size_t.max], wordBits); assert(b.bitsSet.equal(iota(wordBits))); b = BitArray([size_t.max, size_t.max], wordBits); assert(b.bitsSet.equal(iota(wordBits))); b = BitArray([size_t.max, size_t.max], wordBits + 1); assert(b.bitsSet.equal(iota(wordBits + 1))); b = BitArray([size_t.max, size_t.max], wordBits * 2); assert(b.bitsSet.equal(iota(wordBits * 2))); } private void formatBitString(scope void delegate(const(char)[]) sink) const { if (!length) return; auto leftover = _len % 8; foreach (idx; 0 .. leftover) { char[1] res = cast(char)(this[idx] + '0'); sink.put(res[]); } if (leftover && _len > 8) sink.put("_"); size_t count; foreach (idx; leftover .. _len) { char[1] res = cast(char)(this[idx] + '0'); sink.put(res[]); if (++count == 8 && idx != _len - 1) { sink.put("_"); count = 0; } } } private void formatBitArray(scope void delegate(const(char)[]) sink) const { sink("["); foreach (idx; 0 .. _len) { char[1] res = cast(char)(this[idx] + '0'); sink(res[]); if (idx+1 < _len) sink(", "); } sink("]"); } } unittest { import std.format : format; BitArray b; b = BitArray([]); assert(format("%s", b) == "[]"); assert(format("%b", b) is null); b = BitArray([1]); assert(format("%s", b) == "[1]"); assert(format("%b", b) == "1"); b = BitArray([0, 0, 0, 0]); assert(format("%b", b) == "0000"); b = BitArray([0, 0, 0, 0, 1, 1, 1, 1]); assert(format("%s", b) == "[0, 0, 0, 0, 1, 1, 1, 1]"); assert(format("%b", b) == "00001111"); b = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); assert(format("%s", b) == "[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]"); assert(format("%b", b) == "00001111_00001111"); b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1]); assert(format("%b", b) == "1_00001111"); b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); assert(format("%b", b) == "1_00001111_00001111"); } /++ Swaps the endianness of the given integral value or character. +/ T swapEndian(T)(T val) @safe pure nothrow @nogc if(isIntegral!T || isSomeChar!T || isBoolean!T) { static if(val.sizeof == 1) return val; else static if(isUnsigned!T) return swapEndianImpl(val); else static if(isIntegral!T) return cast(T)swapEndianImpl(cast(Unsigned!T) val); else static if(is(Unqual!T == wchar)) return cast(T)swapEndian(cast(ushort)val); else static if(is(Unqual!T == dchar)) return cast(T)swapEndian(cast(uint)val); else static assert(0, T.stringof ~ " unsupported by swapEndian."); } private ushort swapEndianImpl(ushort val) @safe pure nothrow @nogc { return ((val & 0xff00U) >> 8) | ((val & 0x00ffU) << 8); } private uint swapEndianImpl(uint val) @trusted pure nothrow @nogc { import core.bitop: bswap; return bswap(val); } private ulong swapEndianImpl(ulong val) @trusted pure nothrow @nogc { import core.bitop: bswap; immutable ulong res = bswap(cast(uint)val); return res << 32 | bswap(cast(uint)(val >> 32)); } unittest { import std.meta; foreach(T; AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, char, wchar, dchar)) { scope(failure) writefln("Failed type: %s", T.stringof); T val; const T cval; immutable T ival; assert(swapEndian(swapEndian(val)) == val); assert(swapEndian(swapEndian(cval)) == cval); assert(swapEndian(swapEndian(ival)) == ival); assert(swapEndian(swapEndian(T.min)) == T.min); assert(swapEndian(swapEndian(T.max)) == T.max); foreach(i; 2 .. 10) { immutable T maxI = cast(T)(T.max / i); immutable T minI = cast(T)(T.min / i); assert(swapEndian(swapEndian(maxI)) == maxI); static if(isSigned!T) assert(swapEndian(swapEndian(minI)) == minI); } static if(isSigned!T) assert(swapEndian(swapEndian(cast(T)0)) == 0); // used to trigger BUG6354 static if(T.sizeof > 1 && isUnsigned!T) { T left = 0xffU; left <<= (T.sizeof - 1) * 8; T right = 0xffU; for(size_t i = 1; i < T.sizeof; ++i) { assert(swapEndian(left) == right); assert(swapEndian(right) == left); left >>= 8; right <<= 8; } } } } private union EndianSwapper(T) if(canSwapEndianness!T) { Unqual!T value; ubyte[T.sizeof] array; static if(is(FloatingPointTypeOf!T == float)) uint intValue; else static if(is(FloatingPointTypeOf!T == double)) ulong intValue; } /++ Converts the given value from the native endianness to big endian and returns it as a $(D ubyte[n]) where $(D n) is the size of the given type. Returning a $(D ubyte[n]) helps prevent accidentally using a swapped value as a regular one (and in the case of floating point values, it's necessary, because the FPU will mess up any swapped floating point values. So, you can't actually have swapped floating point values as floating point values). $(D real) is not supported, because its size is implementation-dependent and therefore could vary from machine to machine (which could make it unusable if you tried to transfer it to another machine). +/ auto nativeToBigEndian(T)(T val) @safe pure nothrow @nogc if(canSwapEndianness!T) { return nativeToBigEndianImpl(val); } /// unittest { int i = 12345; ubyte[4] swappedI = nativeToBigEndian(i); assert(i == bigEndianToNative!int(swappedI)); double d = 123.45; ubyte[8] swappedD = nativeToBigEndian(d); assert(d == bigEndianToNative!double(swappedD)); } private auto nativeToBigEndianImpl(T)(T val) @safe pure nothrow @nogc if(isIntegral!T || isSomeChar!T || isBoolean!T) { EndianSwapper!T es = void; version(LittleEndian) es.value = swapEndian(val); else es.value = val; return es.array; } private auto nativeToBigEndianImpl(T)(T val) @safe pure nothrow @nogc if(isFloatOrDouble!T) { version(LittleEndian) return floatEndianImpl!(T, true)(val); else return floatEndianImpl!(T, false)(val); } unittest { import std.meta; foreach(T; AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, char, wchar, dchar /* The trouble here is with floats and doubles being compared against nan * using a bit compare. There are two kinds of nans, quiet and signaling. * When a nan passes through the x87, it converts signaling to quiet. * When a nan passes through the XMM, it does not convert signaling to quiet. * float.init is a signaling nan. * The binary API sometimes passes the data through the XMM, sometimes through * the x87, meaning these will fail the 'is' bit compare under some circumstances. * I cannot think of a fix for this that makes consistent sense. */ /*,float, double*/)) { scope(failure) writefln("Failed type: %s", T.stringof); T val; const T cval; immutable T ival; //is instead of == because of NaN for floating point values. assert(bigEndianToNative!T(nativeToBigEndian(val)) is val); assert(bigEndianToNative!T(nativeToBigEndian(cval)) is cval); assert(bigEndianToNative!T(nativeToBigEndian(ival)) is ival); assert(bigEndianToNative!T(nativeToBigEndian(T.min)) == T.min); assert(bigEndianToNative!T(nativeToBigEndian(T.max)) == T.max); static if(isSigned!T) assert(bigEndianToNative!T(nativeToBigEndian(cast(T)0)) == 0); static if(!is(T == bool)) { foreach(i; [2, 4, 6, 7, 9, 11]) { immutable T maxI = cast(T)(T.max / i); immutable T minI = cast(T)(T.min / i); assert(bigEndianToNative!T(nativeToBigEndian(maxI)) == maxI); static if(T.sizeof > 1) assert(nativeToBigEndian(maxI) != nativeToLittleEndian(maxI)); else assert(nativeToBigEndian(maxI) == nativeToLittleEndian(maxI)); static if(isSigned!T) { assert(bigEndianToNative!T(nativeToBigEndian(minI)) == minI); static if(T.sizeof > 1) assert(nativeToBigEndian(minI) != nativeToLittleEndian(minI)); else assert(nativeToBigEndian(minI) == nativeToLittleEndian(minI)); } } } static if(isUnsigned!T || T.sizeof == 1 || is(T == wchar)) assert(nativeToBigEndian(T.max) == nativeToLittleEndian(T.max)); else assert(nativeToBigEndian(T.max) != nativeToLittleEndian(T.max)); static if(isUnsigned!T || T.sizeof == 1 || isSomeChar!T) assert(nativeToBigEndian(T.min) == nativeToLittleEndian(T.min)); else assert(nativeToBigEndian(T.min) != nativeToLittleEndian(T.min)); } } /++ Converts the given value from big endian to the native endianness and returns it. The value is given as a $(D ubyte[n]) where $(D n) is the size of the target type. You must give the target type as a template argument, because there are multiple types with the same size and so the type of the argument is not enough to determine the return type. Taking a $(D ubyte[n]) helps prevent accidentally using a swapped value as a regular one (and in the case of floating point values, it's necessary, because the FPU will mess up any swapped floating point values. So, you can't actually have swapped floating point values as floating point values). +/ T bigEndianToNative(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc if(canSwapEndianness!T && n == T.sizeof) { return bigEndianToNativeImpl!(T, n)(val); } /// unittest { ushort i = 12345; ubyte[2] swappedI = nativeToBigEndian(i); assert(i == bigEndianToNative!ushort(swappedI)); dchar c = 'D'; ubyte[4] swappedC = nativeToBigEndian(c); assert(c == bigEndianToNative!dchar(swappedC)); } private T bigEndianToNativeImpl(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc if((isIntegral!T || isSomeChar!T || isBoolean!T) && n == T.sizeof) { EndianSwapper!T es = void; es.array = val; version(LittleEndian) immutable retval = swapEndian(es.value); else immutable retval = es.value; return retval; } private T bigEndianToNativeImpl(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc if(isFloatOrDouble!T && n == T.sizeof) { version(LittleEndian) return cast(T) floatEndianImpl!(n, true)(val); else return cast(T) floatEndianImpl!(n, false)(val); } /++ Converts the given value from the native endianness to little endian and returns it as a $(D ubyte[n]) where $(D n) is the size of the given type. Returning a $(D ubyte[n]) helps prevent accidentally using a swapped value as a regular one (and in the case of floating point values, it's necessary, because the FPU will mess up any swapped floating point values. So, you can't actually have swapped floating point values as floating point values). +/ auto nativeToLittleEndian(T)(T val) @safe pure nothrow @nogc if(canSwapEndianness!T) { return nativeToLittleEndianImpl(val); } /// unittest { int i = 12345; ubyte[4] swappedI = nativeToLittleEndian(i); assert(i == littleEndianToNative!int(swappedI)); double d = 123.45; ubyte[8] swappedD = nativeToLittleEndian(d); assert(d == littleEndianToNative!double(swappedD)); } private auto nativeToLittleEndianImpl(T)(T val) @safe pure nothrow @nogc if(isIntegral!T || isSomeChar!T || isBoolean!T) { EndianSwapper!T es = void; version(BigEndian) es.value = swapEndian(val); else es.value = val; return es.array; } private auto nativeToLittleEndianImpl(T)(T val) @safe pure nothrow @nogc if(isFloatOrDouble!T) { version(BigEndian) return floatEndianImpl!(T, true)(val); else return floatEndianImpl!(T, false)(val); } unittest { import std.meta; foreach(T; AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, char, wchar, dchar/*, float, double*/)) { scope(failure) writefln("Failed type: %s", T.stringof); T val; const T cval; immutable T ival; //is instead of == because of NaN for floating point values. assert(littleEndianToNative!T(nativeToLittleEndian(val)) is val); assert(littleEndianToNative!T(nativeToLittleEndian(cval)) is cval); assert(littleEndianToNative!T(nativeToLittleEndian(ival)) is ival); assert(littleEndianToNative!T(nativeToLittleEndian(T.min)) == T.min); assert(littleEndianToNative!T(nativeToLittleEndian(T.max)) == T.max); static if(isSigned!T) assert(littleEndianToNative!T(nativeToLittleEndian(cast(T)0)) == 0); static if(!is(T == bool)) { foreach(i; 2 .. 10) { immutable T maxI = cast(T)(T.max / i); immutable T minI = cast(T)(T.min / i); assert(littleEndianToNative!T(nativeToLittleEndian(maxI)) == maxI); static if(isSigned!T) assert(littleEndianToNative!T(nativeToLittleEndian(minI)) == minI); } } } } /++ Converts the given value from little endian to the native endianness and returns it. The value is given as a $(D ubyte[n]) where $(D n) is the size of the target type. You must give the target type as a template argument, because there are multiple types with the same size and so the type of the argument is not enough to determine the return type. Taking a $(D ubyte[n]) helps prevent accidentally using a swapped value as a regular one (and in the case of floating point values, it's necessary, because the FPU will mess up any swapped floating point values. So, you can't actually have swapped floating point values as floating point values). $(D real) is not supported, because its size is implementation-dependent and therefore could vary from machine to machine (which could make it unusable if you tried to transfer it to another machine). +/ T littleEndianToNative(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc if(canSwapEndianness!T && n == T.sizeof) { return littleEndianToNativeImpl!T(val); } /// unittest { ushort i = 12345; ubyte[2] swappedI = nativeToLittleEndian(i); assert(i == littleEndianToNative!ushort(swappedI)); dchar c = 'D'; ubyte[4] swappedC = nativeToLittleEndian(c); assert(c == littleEndianToNative!dchar(swappedC)); } private T littleEndianToNativeImpl(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc if((isIntegral!T || isSomeChar!T || isBoolean!T) && n == T.sizeof) { EndianSwapper!T es = void; es.array = val; version(BigEndian) immutable retval = swapEndian(es.value); else immutable retval = es.value; return retval; } private T littleEndianToNativeImpl(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc if(((isFloatOrDouble!T) && n == T.sizeof)) { version(BigEndian) return floatEndianImpl!(n, true)(val); else return floatEndianImpl!(n, false)(val); } private auto floatEndianImpl(T, bool swap)(T val) @safe pure nothrow @nogc if(isFloatOrDouble!T) { EndianSwapper!T es = void; es.value = val; static if(swap) es.intValue = swapEndian(es.intValue); return es.array; } private auto floatEndianImpl(size_t n, bool swap)(ubyte[n] val) @safe pure nothrow @nogc if(n == 4 || n == 8) { static if(n == 4) EndianSwapper!float es = void; else static if(n == 8) EndianSwapper!double es = void; es.array = val; static if(swap) es.intValue = swapEndian(es.intValue); return es.value; } private template isFloatOrDouble(T) { enum isFloatOrDouble = isFloatingPoint!T && !is(Unqual!(FloatingPointTypeOf!T) == real); } unittest { import std.meta; foreach(T; AliasSeq!(float, double)) { static assert(isFloatOrDouble!(T)); static assert(isFloatOrDouble!(const T)); static assert(isFloatOrDouble!(immutable T)); static assert(isFloatOrDouble!(shared T)); static assert(isFloatOrDouble!(shared(const T))); static assert(isFloatOrDouble!(shared(immutable T))); } static assert(!isFloatOrDouble!(real)); static assert(!isFloatOrDouble!(const real)); static assert(!isFloatOrDouble!(immutable real)); static assert(!isFloatOrDouble!(shared real)); static assert(!isFloatOrDouble!(shared(const real))); static assert(!isFloatOrDouble!(shared(immutable real))); } private template canSwapEndianness(T) { enum canSwapEndianness = isIntegral!T || isSomeChar!T || isBoolean!T || isFloatOrDouble!T; } unittest { import std.meta; foreach(T; AliasSeq!(bool, ubyte, byte, ushort, short, uint, int, ulong, long, char, wchar, dchar, float, double)) { static assert(canSwapEndianness!(T)); static assert(canSwapEndianness!(const T)); static assert(canSwapEndianness!(immutable T)); static assert(canSwapEndianness!(shared(T))); static assert(canSwapEndianness!(shared(const T))); static assert(canSwapEndianness!(shared(immutable T))); } //! foreach(T; AliasSeq!(real, string, wstring, dstring)) { static assert(!canSwapEndianness!(T)); static assert(!canSwapEndianness!(const T)); static assert(!canSwapEndianness!(immutable T)); static assert(!canSwapEndianness!(shared(T))); static assert(!canSwapEndianness!(shared(const T))); static assert(!canSwapEndianness!(shared(immutable T))); } } /++ Takes a range of $(D ubyte)s and converts the first $(D T.sizeof) bytes to $(D T). The value returned is converted from the given endianness to the native endianness. The range is not consumed. Params: T = The integral type to convert the first $(D T.sizeof) bytes to. endianness = The endianness that the bytes are assumed to be in. range = The range to read from. index = The index to start reading from (instead of starting at the front). If index is a pointer, then it is updated to the index after the bytes read. The overloads with index are only available if $(D hasSlicing!R) is $(D true). +/ T peek(T, Endian endianness = Endian.bigEndian, R)(R range) if (canSwapEndianness!T && isForwardRange!R && is(ElementType!R : const ubyte)) { static if(hasSlicing!R) const ubyte[T.sizeof] bytes = range[0 .. T.sizeof]; else { ubyte[T.sizeof] bytes; //Make sure that range is not consumed, even if it's a class. range = range.save; foreach(ref e; bytes) { e = range.front; range.popFront(); } } static if(endianness == Endian.bigEndian) return bigEndianToNative!T(bytes); else return littleEndianToNative!T(bytes); } /++ Ditto +/ T peek(T, Endian endianness = Endian.bigEndian, R)(R range, size_t index) if(canSwapEndianness!T && isForwardRange!R && hasSlicing!R && is(ElementType!R : const ubyte)) { return peek!(T, endianness)(range, &index); } /++ Ditto +/ T peek(T, Endian endianness = Endian.bigEndian, R)(R range, size_t* index) if(canSwapEndianness!T && isForwardRange!R && hasSlicing!R && is(ElementType!R : const ubyte)) { assert(index); immutable begin = *index; immutable end = begin + T.sizeof; const ubyte[T.sizeof] bytes = range[begin .. end]; *index = end; static if(endianness == Endian.bigEndian) return bigEndianToNative!T(bytes); else return littleEndianToNative!T(bytes); } /// unittest { ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; assert(buffer.peek!uint() == 17110537); assert(buffer.peek!ushort() == 261); assert(buffer.peek!ubyte() == 1); assert(buffer.peek!uint(2) == 369700095); assert(buffer.peek!ushort(2) == 5641); assert(buffer.peek!ubyte(2) == 22); size_t index = 0; assert(buffer.peek!ushort(&index) == 261); assert(index == 2); assert(buffer.peek!uint(&index) == 369700095); assert(index == 6); assert(buffer.peek!ubyte(&index) == 8); assert(index == 7); } unittest { { //bool ubyte[] buffer = [0, 1]; assert(buffer.peek!bool() == false); assert(buffer.peek!bool(1) == true); size_t index = 0; assert(buffer.peek!bool(&index) == false); assert(index == 1); assert(buffer.peek!bool(&index) == true); assert(index == 2); } { //char (8bit) ubyte[] buffer = [97, 98, 99, 100]; assert(buffer.peek!char() == 'a'); assert(buffer.peek!char(1) == 'b'); size_t index = 0; assert(buffer.peek!char(&index) == 'a'); assert(index == 1); assert(buffer.peek!char(&index) == 'b'); assert(index == 2); } { //wchar (16bit - 2x ubyte) ubyte[] buffer = [1, 5, 32, 29, 1, 7]; assert(buffer.peek!wchar() == 'ą'); assert(buffer.peek!wchar(2) == '”'); assert(buffer.peek!wchar(4) == 'ć'); size_t index = 0; assert(buffer.peek!wchar(&index) == 'ą'); assert(index == 2); assert(buffer.peek!wchar(&index) == '”'); assert(index == 4); assert(buffer.peek!wchar(&index) == 'ć'); assert(index == 6); } { //dchar (32bit - 4x ubyte) ubyte[] buffer = [0, 0, 1, 5, 0, 0, 32, 29, 0, 0, 1, 7]; assert(buffer.peek!dchar() == 'ą'); assert(buffer.peek!dchar(4) == '”'); assert(buffer.peek!dchar(8) == 'ć'); size_t index = 0; assert(buffer.peek!dchar(&index) == 'ą'); assert(index == 4); assert(buffer.peek!dchar(&index) == '”'); assert(index == 8); assert(buffer.peek!dchar(&index) == 'ć'); assert(index == 12); } { //float (32bit - 4x ubyte) ubyte[] buffer = [66, 0, 0, 0, 65, 200, 0, 0]; assert(buffer.peek!float()== 32.0); assert(buffer.peek!float(4) == 25.0f); size_t index = 0; assert(buffer.peek!float(&index) == 32.0f); assert(index == 4); assert(buffer.peek!float(&index) == 25.0f); assert(index == 8); } { //double (64bit - 8x ubyte) ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; assert(buffer.peek!double() == 32.0); assert(buffer.peek!double(8) == 25.0); size_t index = 0; assert(buffer.peek!double(&index) == 32.0); assert(index == 8); assert(buffer.peek!double(&index) == 25.0); assert(index == 16); } { //enum ubyte[] buffer = [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]; enum Foo { one = 10, two = 20, three = 30 } assert(buffer.peek!Foo() == Foo.one); assert(buffer.peek!Foo(0) == Foo.one); assert(buffer.peek!Foo(4) == Foo.two); assert(buffer.peek!Foo(8) == Foo.three); size_t index = 0; assert(buffer.peek!Foo(&index) == Foo.one); assert(index == 4); assert(buffer.peek!Foo(&index) == Foo.two); assert(index == 8); assert(buffer.peek!Foo(&index) == Foo.three); assert(index == 12); } { //enum - bool ubyte[] buffer = [0, 1]; enum Bool: bool { bfalse = false, btrue = true, } assert(buffer.peek!Bool() == Bool.bfalse); assert(buffer.peek!Bool(0) == Bool.bfalse); assert(buffer.peek!Bool(1) == Bool.btrue); size_t index = 0; assert(buffer.peek!Bool(&index) == Bool.bfalse); assert(index == 1); assert(buffer.peek!Bool(&index) == Bool.btrue); assert(index == 2); } { //enum - float ubyte[] buffer = [66, 0, 0, 0, 65, 200, 0, 0]; enum Float: float { one = 32.0f, two = 25.0f } assert(buffer.peek!Float() == Float.one); assert(buffer.peek!Float(0) == Float.one); assert(buffer.peek!Float(4) == Float.two); size_t index = 0; assert(buffer.peek!Float(&index) == Float.one); assert(index == 4); assert(buffer.peek!Float(&index) == Float.two); assert(index == 8); } { //enum - double ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; enum Double: double { one = 32.0, two = 25.0 } assert(buffer.peek!Double() == Double.one); assert(buffer.peek!Double(0) == Double.one); assert(buffer.peek!Double(8) == Double.two); size_t index = 0; assert(buffer.peek!Double(&index) == Double.one); assert(index == 8); assert(buffer.peek!Double(&index) == Double.two); assert(index == 16); } { //enum - real ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; enum Real: real { one = 32.0, two = 25.0 } static assert(!__traits(compiles, buffer.peek!Real())); } } unittest { import std.algorithm; ubyte[] buffer = [1, 5, 22, 9, 44, 255, 7]; auto range = filter!"true"(buffer); assert(range.peek!uint() == 17110537); assert(range.peek!ushort() == 261); assert(range.peek!ubyte() == 1); } /++ Takes a range of $(D ubyte)s and converts the first $(D T.sizeof) bytes to $(D T). The value returned is converted from the given endianness to the native endianness. The $(D T.sizeof) bytes which are read are consumed from the range. Params: T = The integral type to convert the first $(D T.sizeof) bytes to. endianness = The endianness that the bytes are assumed to be in. range = The range to read from. +/ T read(T, Endian endianness = Endian.bigEndian, R)(ref R range) if(canSwapEndianness!T && isInputRange!R && is(ElementType!R : const ubyte)) { static if(hasSlicing!R) { const ubyte[T.sizeof] bytes = range[0 .. T.sizeof]; range.popFrontN(T.sizeof); } else { ubyte[T.sizeof] bytes; foreach(ref e; bytes) { e = range.front; range.popFront(); } } static if(endianness == Endian.bigEndian) return bigEndianToNative!T(bytes); else return littleEndianToNative!T(bytes); } /// unittest { ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; assert(buffer.length == 7); assert(buffer.read!ushort() == 261); assert(buffer.length == 5); assert(buffer.read!uint() == 369700095); assert(buffer.length == 1); assert(buffer.read!ubyte() == 8); assert(buffer.empty); } unittest { { //bool ubyte[] buffer = [0, 1]; assert(buffer.length == 2); assert(buffer.read!bool() == false); assert(buffer.length == 1); assert(buffer.read!bool() == true); assert(buffer.empty); } { //char (8bit) ubyte[] buffer = [97, 98, 99]; assert(buffer.length == 3); assert(buffer.read!char() == 'a'); assert(buffer.length == 2); assert(buffer.read!char() == 'b'); assert(buffer.length == 1); assert(buffer.read!char() == 'c'); assert(buffer.empty); } { //wchar (16bit - 2x ubyte) ubyte[] buffer = [1, 5, 32, 29, 1, 7]; assert(buffer.length == 6); assert(buffer.read!wchar() == 'ą'); assert(buffer.length == 4); assert(buffer.read!wchar() == '”'); assert(buffer.length == 2); assert(buffer.read!wchar() == 'ć'); assert(buffer.empty); } { //dchar (32bit - 4x ubyte) ubyte[] buffer = [0, 0, 1, 5, 0, 0, 32, 29, 0, 0, 1, 7]; assert(buffer.length == 12); assert(buffer.read!dchar() == 'ą'); assert(buffer.length == 8); assert(buffer.read!dchar() == '”'); assert(buffer.length == 4); assert(buffer.read!dchar() == 'ć'); assert(buffer.empty); } { //float (32bit - 4x ubyte) ubyte[] buffer = [66, 0, 0, 0, 65, 200, 0, 0]; assert(buffer.length == 8); assert(buffer.read!float()== 32.0); assert(buffer.length == 4); assert(buffer.read!float() == 25.0f); assert(buffer.empty); } { //double (64bit - 8x ubyte) ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; assert(buffer.length == 16); assert(buffer.read!double() == 32.0); assert(buffer.length == 8); assert(buffer.read!double() == 25.0); assert(buffer.empty); } { //enum - uint ubyte[] buffer = [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]; assert(buffer.length == 12); enum Foo { one = 10, two = 20, three = 30 } assert(buffer.read!Foo() == Foo.one); assert(buffer.length == 8); assert(buffer.read!Foo() == Foo.two); assert(buffer.length == 4); assert(buffer.read!Foo() == Foo.three); assert(buffer.empty); } { //enum - bool ubyte[] buffer = [0, 1]; assert(buffer.length == 2); enum Bool: bool { bfalse = false, btrue = true, } assert(buffer.read!Bool() == Bool.bfalse); assert(buffer.length == 1); assert(buffer.read!Bool() == Bool.btrue); assert(buffer.empty); } { //enum - float ubyte[] buffer = [66, 0, 0, 0, 65, 200, 0, 0]; assert(buffer.length == 8); enum Float: float { one = 32.0f, two = 25.0f } assert(buffer.read!Float() == Float.one); assert(buffer.length == 4); assert(buffer.read!Float() == Float.two); assert(buffer.empty); } { //enum - double ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; assert(buffer.length == 16); enum Double: double { one = 32.0, two = 25.0 } assert(buffer.read!Double() == Double.one); assert(buffer.length == 8); assert(buffer.read!Double() == Double.two); assert(buffer.empty); } { //enum - real ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; enum Real: real { one = 32.0, two = 25.0 } static assert(!__traits(compiles, buffer.read!Real())); } } unittest { import std.algorithm; ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; auto range = filter!"true"(buffer); assert(walkLength(range) == 7); assert(range.read!ushort() == 261); assert(walkLength(range) == 5); assert(range.read!uint() == 369700095); assert(walkLength(range) == 1); assert(range.read!ubyte() == 8); assert(range.empty); } /++ Takes an integral value, converts it to the given endianness, and writes it to the given range of $(D ubyte)s as a sequence of $(D T.sizeof) $(D ubyte)s starting at index. $(D hasSlicing!R) must be $(D true). Params: T = The integral type to convert the first $(D T.sizeof) bytes to. endianness = The endianness to _write the bytes in. range = The range to _write to. value = The value to _write. index = The index to start writing to. If index is a pointer, then it is updated to the index after the bytes read. +/ void write(T, Endian endianness = Endian.bigEndian, R)(R range, T value, size_t index) if(canSwapEndianness!T && isForwardRange!R && hasSlicing!R && is(ElementType!R : ubyte)) { write!(T, endianness)(range, value, &index); } /++ Ditto +/ void write(T, Endian endianness = Endian.bigEndian, R)(R range, T value, size_t* index) if(canSwapEndianness!T && isForwardRange!R && hasSlicing!R && is(ElementType!R : ubyte)) { assert(index); static if(endianness == Endian.bigEndian) immutable bytes = nativeToBigEndian!T(value); else immutable bytes = nativeToLittleEndian!T(value); immutable begin = *index; immutable end = begin + T.sizeof; *index = end; range[begin .. end] = bytes[0 .. T.sizeof]; } /// unittest { { ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; buffer.write!uint(29110231u, 0); assert(buffer == [1, 188, 47, 215, 0, 0, 0, 0]); buffer.write!ushort(927, 0); assert(buffer == [3, 159, 47, 215, 0, 0, 0, 0]); buffer.write!ubyte(42, 0); assert(buffer == [42, 159, 47, 215, 0, 0, 0, 0]); } { ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0]; buffer.write!uint(142700095u, 2); assert(buffer == [0, 0, 8, 129, 110, 63, 0, 0, 0]); buffer.write!ushort(19839, 2); assert(buffer == [0, 0, 77, 127, 110, 63, 0, 0, 0]); buffer.write!ubyte(132, 2); assert(buffer == [0, 0, 132, 127, 110, 63, 0, 0, 0]); } { ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; size_t index = 0; buffer.write!ushort(261, &index); assert(buffer == [1, 5, 0, 0, 0, 0, 0, 0]); assert(index == 2); buffer.write!uint(369700095u, &index); assert(buffer == [1, 5, 22, 9, 44, 255, 0, 0]); assert(index == 6); buffer.write!ubyte(8, &index); assert(buffer == [1, 5, 22, 9, 44, 255, 8, 0]); assert(index == 7); } } unittest { { //bool ubyte[] buffer = [0, 0]; buffer.write!bool(false, 0); assert(buffer == [0, 0]); buffer.write!bool(true, 0); assert(buffer == [1, 0]); buffer.write!bool(true, 1); assert(buffer == [1, 1]); buffer.write!bool(false, 1); assert(buffer == [1, 0]); size_t index = 0; buffer.write!bool(false, &index); assert(buffer == [0, 0]); assert(index == 1); buffer.write!bool(true, &index); assert(buffer == [0, 1]); assert(index == 2); } { //char (8bit) ubyte[] buffer = [0, 0, 0]; buffer.write!char('a', 0); assert(buffer == [97, 0, 0]); buffer.write!char('b', 1); assert(buffer == [97, 98, 0]); size_t index = 0; buffer.write!char('a', &index); assert(buffer == [97, 98, 0]); assert(index == 1); buffer.write!char('b', &index); assert(buffer == [97, 98, 0]); assert(index == 2); buffer.write!char('c', &index); assert(buffer == [97, 98, 99]); assert(index == 3); } { //wchar (16bit - 2x ubyte) ubyte[] buffer = [0, 0, 0, 0]; buffer.write!wchar('ą', 0); assert(buffer == [1, 5, 0, 0]); buffer.write!wchar('”', 2); assert(buffer == [1, 5, 32, 29]); size_t index = 0; buffer.write!wchar('ć', &index); assert(buffer == [1, 7, 32, 29]); assert(index == 2); buffer.write!wchar('ą', &index); assert(buffer == [1, 7, 1, 5]); assert(index == 4); } { //dchar (32bit - 4x ubyte) ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; buffer.write!dchar('ą', 0); assert(buffer == [0, 0, 1, 5, 0, 0, 0, 0]); buffer.write!dchar('”', 4); assert(buffer == [0, 0, 1, 5, 0, 0, 32, 29]); size_t index = 0; buffer.write!dchar('ć', &index); assert(buffer == [0, 0, 1, 7, 0, 0, 32, 29]); assert(index == 4); buffer.write!dchar('ą', &index); assert(buffer == [0, 0, 1, 7, 0, 0, 1, 5]); assert(index == 8); } { //float (32bit - 4x ubyte) ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; buffer.write!float(32.0f, 0); assert(buffer == [66, 0, 0, 0, 0, 0, 0, 0]); buffer.write!float(25.0f, 4); assert(buffer == [66, 0, 0, 0, 65, 200, 0, 0]); size_t index = 0; buffer.write!float(25.0f, &index); assert(buffer == [65, 200, 0, 0, 65, 200, 0, 0]); assert(index == 4); buffer.write!float(32.0f, &index); assert(buffer == [65, 200, 0, 0, 66, 0, 0, 0]); assert(index == 8); } { //double (64bit - 8x ubyte) ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; buffer.write!double(32.0, 0); assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); buffer.write!double(25.0, 8); assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); size_t index = 0; buffer.write!double(25.0, &index); assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); assert(index == 8); buffer.write!double(32.0, &index); assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); assert(index == 16); } { //enum ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; enum Foo { one = 10, two = 20, three = 30 } buffer.write!Foo(Foo.one, 0); assert(buffer == [0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0]); buffer.write!Foo(Foo.two, 4); assert(buffer == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 0]); buffer.write!Foo(Foo.three, 8); assert(buffer == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]); size_t index = 0; buffer.write!Foo(Foo.three, &index); assert(buffer == [0, 0, 0, 30, 0, 0, 0, 20, 0, 0, 0, 30]); assert(index == 4); buffer.write!Foo(Foo.one, &index); assert(buffer == [0, 0, 0, 30, 0, 0, 0, 10, 0, 0, 0, 30]); assert(index == 8); buffer.write!Foo(Foo.two, &index); assert(buffer == [0, 0, 0, 30, 0, 0, 0, 10, 0, 0, 0, 20]); assert(index == 12); } { //enum - bool ubyte[] buffer = [0, 0]; enum Bool: bool { bfalse = false, btrue = true, } buffer.write!Bool(Bool.btrue, 0); assert(buffer == [1, 0]); buffer.write!Bool(Bool.btrue, 1); assert(buffer == [1, 1]); size_t index = 0; buffer.write!Bool(Bool.bfalse, &index); assert(buffer == [0, 1]); assert(index == 1); buffer.write!Bool(Bool.bfalse, &index); assert(buffer == [0, 0]); assert(index == 2); } { //enum - float ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; enum Float: float { one = 32.0f, two = 25.0f } buffer.write!Float(Float.one, 0); assert(buffer == [66, 0, 0, 0, 0, 0, 0, 0]); buffer.write!Float(Float.two, 4); assert(buffer == [66, 0, 0, 0, 65, 200, 0, 0]); size_t index = 0; buffer.write!Float(Float.two, &index); assert(buffer == [65, 200, 0, 0, 65, 200, 0, 0]); assert(index == 4); buffer.write!Float(Float.one, &index); assert(buffer == [65, 200, 0, 0, 66, 0, 0, 0]); assert(index == 8); } { //enum - double ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; enum Double: double { one = 32.0, two = 25.0 } buffer.write!Double(Double.one, 0); assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); buffer.write!Double(Double.two, 8); assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); size_t index = 0; buffer.write!Double(Double.two, &index); assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); assert(index == 8); buffer.write!Double(Double.one, &index); assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); assert(index == 16); } { //enum - real ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; enum Real: real { one = 32.0, two = 25.0 } static assert(!__traits(compiles, buffer.write!Real(Real.one))); } } /++ Takes an integral value, converts it to the given endianness, and appends it to the given range of $(D ubyte)s (using $(D put)) as a sequence of $(D T.sizeof) $(D ubyte)s starting at index. $(D hasSlicing!R) must be $(D true). Params: T = The integral type to convert the first $(D T.sizeof) bytes to. endianness = The endianness to write the bytes in. range = The range to _append to. value = The value to _append. +/ void append(T, Endian endianness = Endian.bigEndian, R)(R range, T value) if(canSwapEndianness!T && isOutputRange!(R, ubyte)) { static if(endianness == Endian.bigEndian) immutable bytes = nativeToBigEndian!T(value); else immutable bytes = nativeToLittleEndian!T(value); put(range, bytes[]); } /// unittest { import std.array; auto buffer = appender!(const ubyte[])(); buffer.append!ushort(261); assert(buffer.data == [1, 5]); buffer.append!uint(369700095u); assert(buffer.data == [1, 5, 22, 9, 44, 255]); buffer.append!ubyte(8); assert(buffer.data == [1, 5, 22, 9, 44, 255, 8]); } unittest { import std.array; { //bool auto buffer = appender!(const ubyte[])(); buffer.append!bool(true); assert(buffer.data == [1]); buffer.append!bool(false); assert(buffer.data == [1, 0]); } { //char wchar dchar auto buffer = appender!(const ubyte[])(); buffer.append!char('a'); assert(buffer.data == [97]); buffer.append!char('b'); assert(buffer.data == [97, 98]); buffer.append!wchar('ą'); assert(buffer.data == [97, 98, 1, 5]); buffer.append!dchar('ą'); assert(buffer.data == [97, 98, 1, 5, 0, 0, 1, 5]); } { //float double auto buffer = appender!(const ubyte[])(); buffer.append!float(32.0f); assert(buffer.data == [66, 0, 0, 0]); buffer.append!double(32.0); assert(buffer.data == [66, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); } { //enum auto buffer = appender!(const ubyte[])(); enum Foo { one = 10, two = 20, three = 30 } buffer.append!Foo(Foo.one); assert(buffer.data == [0, 0, 0, 10]); buffer.append!Foo(Foo.two); assert(buffer.data == [0, 0, 0, 10, 0, 0, 0, 20]); buffer.append!Foo(Foo.three); assert(buffer.data == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]); } { //enum - bool auto buffer = appender!(const ubyte[])(); enum Bool: bool { bfalse = false, btrue = true, } buffer.append!Bool(Bool.btrue); assert(buffer.data == [1]); buffer.append!Bool(Bool.bfalse); assert(buffer.data == [1, 0]); buffer.append!Bool(Bool.btrue); assert(buffer.data == [1, 0, 1]); } { //enum - float auto buffer = appender!(const ubyte[])(); enum Float: float { one = 32.0f, two = 25.0f } buffer.append!Float(Float.one); assert(buffer.data == [66, 0, 0, 0]); buffer.append!Float(Float.two); assert(buffer.data == [66, 0, 0, 0, 65, 200, 0, 0]); } { //enum - double auto buffer = appender!(const ubyte[])(); enum Double: double { one = 32.0, two = 25.0 } buffer.append!Double(Double.one); assert(buffer.data == [64, 64, 0, 0, 0, 0, 0, 0]); buffer.append!Double(Double.two); assert(buffer.data == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); } { //enum - real auto buffer = appender!(const ubyte[])(); enum Real: real { one = 32.0, two = 25.0 } static assert(!__traits(compiles, buffer.append!Real(Real.one))); } } unittest { import std.format : format; import std.array; import std.meta; foreach(endianness; AliasSeq!(Endian.bigEndian, Endian.littleEndian)) { auto toWrite = appender!(ubyte[])(); alias Types = AliasSeq!(uint, int, long, ulong, short, ubyte, ushort, byte, uint); ulong[] values = [42, -11, long.max, 1098911981329L, 16, 255, 19012, 2, 17]; assert(Types.length == values.length); size_t index = 0; size_t length = 0; foreach(T; Types) { toWrite.append!(T, endianness)(cast(T)values[index++]); length += T.sizeof; } auto toRead = toWrite.data; assert(toRead.length == length); index = 0; foreach(T; Types) { assert(toRead.peek!(T, endianness)() == values[index], format("Failed Index: %s", index)); assert(toRead.peek!(T, endianness)(0) == values[index], format("Failed Index: %s", index)); assert(toRead.length == length, format("Failed Index [%s], Actual Length: %s", index, toRead.length)); assert(toRead.read!(T, endianness)() == values[index], format("Failed Index: %s", index)); length -= T.sizeof; assert(toRead.length == length, format("Failed Index [%s], Actual Length: %s", index, toRead.length)); ++index; } assert(toRead.empty); } } /** Counts the number of set bits in the binary representation of $(D value). For signed integers, the sign bit is included in the count. */ private uint countBitsSet(T)(T value) @nogc pure nothrow if (isIntegral!T) { // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel static if (T.sizeof == 8) { T c = value - ((value >> 1) & 0x55555555_55555555); c = ((c >> 2) & 0x33333333_33333333) + (c & 0x33333333_33333333); c = ((c >> 4) + c) & 0x0F0F0F0F_0F0F0F0F; c = ((c >> 8) + c) & 0x00FF00FF_00FF00FF; c = ((c >> 16) + c) & 0x0000FFFF_0000FFFF; c = ((c >> 32) + c) & 0x00000000_FFFFFFFF; } else static if (T.sizeof == 4) { T c = value - ((value >> 1) & 0x55555555); c = ((c >> 2) & 0x33333333) + (c & 0x33333333); c = ((c >> 4) + c) & 0x0F0F0F0F; c = ((c >> 8) + c) & 0x00FF00FF; c = ((c >> 16) + c) & 0x0000FFFF; } else static if (T.sizeof == 2) { uint c = value - ((value >> 1) & 0x5555); c = ((c >> 2) & 0x3333) + (c & 0X3333); c = ((c >> 4) + c) & 0x0F0F; c = ((c >> 8) + c) & 0x00FF; } else static if (T.sizeof == 1) { uint c = value - ((value >> 1) & 0x55); c = ((c >> 2) & 0x33) + (c & 0X33); c = ((c >> 4) + c) & 0x0F; } else { static assert("countBitsSet only supports 1, 2, 4, or 8 byte sized integers."); } return cast(uint)c; } /// unittest { assert(countBitsSet(1) == 1); assert(countBitsSet(0) == 0); assert(countBitsSet(int.min) == 1); assert(countBitsSet(uint.max) == 32); } unittest { import std.meta; foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) { assert(countBitsSet(cast(T)0) == 0); assert(countBitsSet(cast(T)1) == 1); assert(countBitsSet(cast(T)2) == 1); assert(countBitsSet(cast(T)3) == 2); assert(countBitsSet(cast(T)4) == 1); assert(countBitsSet(cast(T)5) == 2); assert(countBitsSet(cast(T)127) == 7); static if (isSigned!T) { assert(countBitsSet(cast(T)-1) == 8 * T.sizeof); assert(countBitsSet(T.min) == 1); } else { assert(countBitsSet(T.max) == 8 * T.sizeof); } } assert(countBitsSet(1_000_000) == 7); foreach (i; 0..63) assert(countBitsSet(1UL << i) == 1); } private struct BitsSet(T) { static assert(T.sizeof <= 8, "bitsSet assumes T is no more than 64-bit."); @nogc pure nothrow: this(T value, size_t startIndex = 0) { _value = value; // Further calculation is only valid and needed when the range is non-empty. if (!_value) return; import core.bitop : bsf; uint trailingZerosCount = bsf(value); _value >>>= trailingZerosCount; _index = startIndex + trailingZerosCount; } @property size_t front() { return _index; } @property bool empty() const { return !_value; } void popFront() { assert(_value, "Cannot call popFront on empty range."); _value >>>= 1; // Further calculation is only valid and needed when the range is non-empty. if (!_value) return; import core.bitop : bsf; uint trailingZerosCount = bsf(_value); _value >>>= trailingZerosCount; _index += trailingZerosCount + 1; } @property auto save() { return this; } @property size_t length() { return countBitsSet(_value); } private T _value; private size_t _index; } /** Range that iterates the indices of the set bits in $(D value). Index 0 corresponds to the least significant bit. For signed integers, the highest index corresponds to the sign bit. */ auto bitsSet(T)(T value) @nogc pure nothrow if (isIntegral!T) { return BitsSet!T(value); } /// unittest { import std.algorithm : equal; import std.range : iota; assert(bitsSet(1).equal([0])); assert(bitsSet(5).equal([0, 2])); assert(bitsSet(-1).equal(iota(32))); assert(bitsSet(int.min).equal([31])); } unittest { import std.algorithm : equal; import std.range: iota; import std.meta; foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) { assert(bitsSet(cast(T)0).empty); assert(bitsSet(cast(T)1).equal([0])); assert(bitsSet(cast(T)2).equal([1])); assert(bitsSet(cast(T)3).equal([0, 1])); assert(bitsSet(cast(T)4).equal([2])); assert(bitsSet(cast(T)5).equal([0, 2])); assert(bitsSet(cast(T)127).equal(iota(7))); static if (isSigned!T) { assert(bitsSet(cast(T)-1).equal(iota(8 * T.sizeof))); assert(bitsSet(T.min).equal([8 * T.sizeof - 1])); } else { assert(bitsSet(T.max).equal(iota(8 * T.sizeof))); } } assert(bitsSet(1_000_000).equal([6, 9, 14, 16, 17, 18, 19])); foreach (i; 0..63) assert(bitsSet(1UL << i).equal([i])); } ldc-1.1.0-beta3-src/runtime/phobos/std/string.d0000664000175000017500000062313012776215007017366 0ustar kaikai// Written in the D programming language. /** String handling functions. $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE , $(TR $(TH Category) $(TH Functions) ) $(TR $(TDNW Searching) $(TD $(MYREF column) $(MYREF inPattern) $(MYREF indexOf) $(MYREF indexOfAny) $(MYREF indexOfNeither) $(MYREF lastIndexOf) $(MYREF lastIndexOfAny) $(MYREF lastIndexOfNeither) ) ) $(TR $(TDNW Comparison) $(TD $(MYREF countchars) $(MYREF isNumeric) ) ) $(TR $(TDNW Mutation) $(TD $(MYREF capitalize) $(MYREF munch) $(MYREF removechars) $(MYREF squeeze) ) ) $(TR $(TDNW Pruning and Filling) $(TD $(MYREF center) $(MYREF chomp) $(MYREF chompPrefix) $(MYREF chop) $(MYREF detabber) $(MYREF detab) $(MYREF entab) $(MYREF entabber) $(MYREF leftJustify) $(MYREF outdent) $(MYREF rightJustify) $(MYREF strip) $(MYREF stripLeft) $(MYREF stripRight) $(MYREF wrap) ) ) $(TR $(TDNW Substitution) $(TD $(MYREF abbrev) $(MYREF soundex) $(MYREF soundexer) $(MYREF succ) $(MYREF tr) $(MYREF translate) ) ) $(TR $(TDNW Miscellaneous) $(TD $(MYREF assumeUTF) $(MYREF fromStringz) $(MYREF lineSplitter) $(MYREF representation) $(MYREF splitLines) $(MYREF toStringz) ) ))) Objects of types $(D _string), $(D wstring), and $(D dstring) are value types and cannot be mutated element-by-element. For using mutation during building strings, use $(D char[]), $(D wchar[]), or $(D dchar[]). The $(D xxxstring) types are preferable because they don't exhibit undesired aliasing, thus making code more robust. The following functions are publicly imported: $(BOOKTABLE , $(TR $(TH Module) $(TH Functions) ) $(LEADINGROW Publicly imported functions) $(TR $(TD std.algorithm) $(TD $(SHORTXREF_PACK algorithm,comparison,cmp) $(SHORTXREF_PACK algorithm,searching,count) $(SHORTXREF_PACK algorithm,searching,endsWith) $(SHORTXREF_PACK algorithm,searching,startsWith) )) $(TR $(TD std.array) $(TD $(SHORTXREF array, join) $(SHORTXREF array, replace) $(SHORTXREF array, replaceInPlace) $(SHORTXREF array, split) $(SHORTXREF array, empty) )) $(TR $(TD std.format) $(TD $(SHORTXREF format, format) $(SHORTXREF format, sformat) )) $(TR $(TD std.uni) $(TD $(SHORTXREF uni, icmp) $(SHORTXREF uni, toLower) $(SHORTXREF uni, toLowerInPlace) $(SHORTXREF uni, toUpper) $(SHORTXREF uni, toUpperInPlace) )) ) There is a rich set of functions for _string handling defined in other modules. Functions related to Unicode and ASCII are found in $(LINK2 std_uni.html, std.uni) and $(LINK2 std_ascii.html, std.ascii), respectively. Other functions that have a wider generality than just strings can be found in $(LINK2 std_algorithm.html, std.algorithm) and $(LINK2 std_range.html, std.range). See_Also: $(LIST $(LINK2 std_algorithm.html, std.algorithm) and $(LINK2 std_range.html, std.range) for generic range algorithms , $(LINK2 std_ascii.html, std.ascii) for functions that work with ASCII strings , $(LINK2 std_uni.html, std.uni) for functions that work with unicode strings ) Macros: WIKI = Phobos/StdString SHORTXREF=$(XREF2 $1, $2, $(TT $2)) SHORTXREF_PACK=$(XREF_PACK_NAMED $1,$2,$3, $(TT $3)) Copyright: Copyright Digital Mars 2007-. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei Alexandrescu), Jonathan M Davis, and David L. 'SpottedTiger' Davis Source: $(PHOBOSSRC std/_string.d) */ module std.string; //debug=string; // uncomment to turn on debugging trustedPrintf's debug(string) private void trustedPrintf(in char* str) @trusted nothrow @nogc { import core.stdc.stdio : printf; printf("%s", str); } version (unittest) { private: struct TestAliasedString { string get() @safe @nogc pure nothrow { return _s; } alias get this; @disable this(this); string _s; } bool testAliasedString(alias func, Args...)(string s, Args args) { import std.algorithm.comparison : equal; auto a = func(TestAliasedString(s), args); auto b = func(s, args); static if (is(typeof(equal(a, b)))) { // For ranges, compare contents instead of object identity. return equal(a, b); } else { return a == b; } } } public import std.uni : icmp, toLower, toLowerInPlace, toUpper, toUpperInPlace; public import std.format : format, sformat; import std.typecons : Flag; import std.meta; import std.range.primitives; import std.traits; //public imports for backward compatibility public import std.algorithm : startsWith, endsWith, cmp, count; public import std.array : join, replace, replaceInPlace, split, empty; /* ************* Exceptions *************** */ /++ Exception thrown on errors in std.string functions. +/ class StringException : Exception { /++ Params: msg = The message for the exception. file = The file where the exception occurred. line = The line number where the exception occurred. next = The previous exception in the chain of exceptions, if any. +/ this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @safe pure nothrow { super(msg, file, line, next); } } /++ Params: cString = A null-terminated c-style string. Returns: A D-style array of $(D char) referencing the same string. The returned array will retain the same type qualifiers as the input. $(RED Important Note:) The returned array is a slice of the original buffer. The original data is not changed and not copied. +/ inout(char)[] fromStringz(inout(char)* cString) @nogc @system pure nothrow { import core.stdc.string : strlen; return cString ? cString[0 .. strlen(cString)] : null; } /// @system pure unittest { assert(fromStringz(null) == null); assert(fromStringz("foo") == "foo"); } /++ Params: s = A D-style string. Returns: A C-style null-terminated string equivalent to $(D s). $(D s) must not contain embedded $(D '\0')'s as any C function will treat the first $(D '\0') that it sees as the end of the string. If $(D s.empty) is $(D true), then a string containing only $(D '\0') is returned. $(RED Important Note:) When passing a $(D char*) to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it. +/ immutable(char)* toStringz(const(char)[] s) @trusted pure nothrow in { // The assert below contradicts the unittests! //assert(memchr(s.ptr, 0, s.length) == null, //text(s.length, ": `", s, "'")); } out (result) { import core.stdc.string : strlen, memcmp; if (result) { auto slen = s.length; while (slen > 0 && s[slen-1] == 0) --slen; assert(strlen(result) == slen); assert(memcmp(result, s.ptr, slen) == 0); } } body { import std.exception : assumeUnique; /+ Unfortunately, this isn't reliable. We could make this work if string literals are put in read-only memory and we test if s[] is pointing into that. /* Peek past end of s[], if it's 0, no conversion necessary. * Note that the compiler will put a 0 past the end of static * strings, and the storage allocator will put a 0 past the end * of newly allocated char[]'s. */ char* p = &s[0] + s.length; if (*p == 0) return s; +/ // Need to make a copy auto copy = new char[s.length + 1]; copy[0..s.length] = s[]; copy[s.length] = 0; return assumeUnique(copy).ptr; } /++ Ditto +/ immutable(char)* toStringz(in string s) @trusted pure nothrow { if (s.empty) return "".ptr; /* Peek past end of s[], if it's 0, no conversion necessary. * Note that the compiler will put a 0 past the end of static * strings, and the storage allocator will put a 0 past the end * of newly allocated char[]'s. */ immutable p = s.ptr + s.length; // Is p dereferenceable? A simple test: if the p points to an // address multiple of 4, then conservatively assume the pointer // might be pointing to a new block of memory, which might be // unreadable. Otherwise, it's definitely pointing to valid // memory. if ((cast(size_t) p & 3) && *p == 0) return s.ptr; return toStringz(cast(const char[]) s); } pure nothrow unittest { import core.stdc.string : strlen; import std.conv : to; debug(string) trustedPrintf("string.toStringz.unittest\n"); // TODO: CTFEable toStringz is really necessary? //assertCTFEable!( //{ auto p = toStringz("foo"); assert(strlen(p) == 3); const(char)[] foo = "abbzxyzzy"; p = toStringz(foo[3..5]); assert(strlen(p) == 2); string test = ""; p = toStringz(test); assert(*p == 0); test = "\0"; p = toStringz(test); assert(*p == 0); test = "foo\0"; p = toStringz(test); assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0); const string test2 = ""; p = toStringz(test2); assert(*p == 0); //}); } /** Flag indicating whether a search is case-sensitive. */ alias CaseSensitive = Flag!"caseSensitive"; /++ Searches for character in range. Params: s = string or InputRange of characters to search in correct UTF format c = character to search for startIdx = starting index to a well-formed code point cs = CaseSensitive.yes or CaseSensitive.no Returns: the index of the first occurrence of $(D c) in $(D s) with respect to the start index $(D startIdx). If $(D c) is not found, then $(D -1) is returned. If $(D c) is found the value of the returned index is at least $(D startIdx). If the parameters are not valid UTF, the result will still be in the range [-1 .. s.length], but will not be reliable otherwise. Throws: If the sequence starting at $(D startIdx) does not represent a well formed codepoint, then a $(XREF utf,UTFException) may be thrown. +/ ptrdiff_t indexOf(Range)(Range s, in dchar c, in CaseSensitive cs = CaseSensitive.yes) if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { static import std.ascii; static import std.uni; import std.utf : byDchar, byCodeUnit, UTFException, codeLength; alias Char = Unqual!(ElementEncodingType!Range); if (cs == CaseSensitive.yes) { static if (Char.sizeof == 1 && isSomeString!Range) { import core.stdc.string : memchr; if (std.ascii.isASCII(c) && !__ctfe) { // Plain old ASCII auto trustedmemchr() @trusted { return cast(Char*)memchr(s.ptr, c, s.length); } const p = trustedmemchr(); if (p) return p - s.ptr; else return -1; } } static if (Char.sizeof == 1) { if (c <= 0x7F) { ptrdiff_t i; foreach (const c2; s) { if (c == c2) return i; ++i; } } else { ptrdiff_t i; foreach (const c2; s.byDchar()) { if (c == c2) return i; i += codeLength!Char(c2); } } } else static if (Char.sizeof == 2) { if (c <= 0xFFFF) { ptrdiff_t i; foreach (const c2; s) { if (c == c2) return i; ++i; } } else if (c <= 0x10FFFF) { // Encode UTF-16 surrogate pair const wchar c1 = cast(wchar)((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); const wchar c2 = cast(wchar)(((c - 0x10000) & 0x3FF) + 0xDC00); ptrdiff_t i; for (auto r = s.byCodeUnit(); !r.empty; r.popFront()) { if (c1 == r.front) { r.popFront(); if (r.empty) // invalid UTF - missing second of pair break; if (c2 == r.front) return i; ++i; } ++i; } } } else static if (Char.sizeof == 4) { ptrdiff_t i; foreach (const c2; s) { if (c == c2) return i; ++i; } } else static assert(0); return -1; } else { if (std.ascii.isASCII(c)) { // Plain old ASCII auto c1 = cast(char) std.ascii.toLower(c); ptrdiff_t i; foreach (const c2; s.byCodeUnit()) { if (c1 == std.ascii.toLower(c2)) return i; ++i; } } else { // c is a universal character auto c1 = std.uni.toLower(c); ptrdiff_t i; foreach (const c2; s.byDchar()) { if (c1 == std.uni.toLower(c2)) return i; i += codeLength!Char(c2); } } } return -1; } /// Ditto ptrdiff_t indexOf(Range)(Range s, in dchar c, in size_t startIdx, in CaseSensitive cs = CaseSensitive.yes) if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { static if (isSomeString!(typeof(s)) || (hasSlicing!(typeof(s)) && hasLength!(typeof(s)))) { if (startIdx < s.length) { ptrdiff_t foundIdx = indexOf(s[startIdx .. $], c, cs); if (foundIdx != -1) { return foundIdx + cast(ptrdiff_t)startIdx; } } } else { foreach (i; 0 .. startIdx) { if (s.empty) return -1; s.popFront(); } ptrdiff_t foundIdx = indexOf(s, c, cs); if (foundIdx != -1) { return foundIdx + cast(ptrdiff_t)startIdx; } } return -1; } /// @safe pure unittest { string s = "Hello World"; assert(indexOf(s, 'W') == 6); assert(indexOf(s, 'Z') == -1); assert(indexOf(s, 'w', CaseSensitive.no) == 6); } /// @safe pure unittest { string s = "Hello World"; assert(indexOf(s, 'W', 4) == 6); assert(indexOf(s, 'Z', 100) == -1); assert(indexOf(s, 'w', 3, CaseSensitive.no) == 6); } ptrdiff_t indexOf(Range)(auto ref Range s, in dchar c, in CaseSensitive cs = CaseSensitive.yes) if (isConvertibleToString!Range) { return indexOf!(StringTypeOf!Range)(s, c, cs); } ptrdiff_t indexOf(Range)(auto ref Range s, in dchar c, in size_t startIdx, in CaseSensitive cs = CaseSensitive.yes) if (isConvertibleToString!Range) { return indexOf!(StringTypeOf!Range)(s, c, startIdx, cs); } unittest { assert(testAliasedString!indexOf("std/string.d", '/')); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.indexOf.unittest\n"); import std.exception; import std.utf : byChar, byWchar, byDchar; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { assert(indexOf(cast(S)null, cast(dchar)'a') == -1); assert(indexOf(to!S("def"), cast(dchar)'a') == -1); assert(indexOf(to!S("abba"), cast(dchar)'a') == 0); assert(indexOf(to!S("def"), cast(dchar)'f') == 2); assert(indexOf(to!S("def"), cast(dchar)'a', CaseSensitive.no) == -1); assert(indexOf(to!S("def"), cast(dchar)'a', CaseSensitive.no) == -1); assert(indexOf(to!S("Abba"), cast(dchar)'a', CaseSensitive.no) == 0); assert(indexOf(to!S("def"), cast(dchar)'F', CaseSensitive.no) == 2); assert(indexOf(to!S("ödef"), 'ö', CaseSensitive.no) == 0); S sPlts = "Mars: the fourth Rock (Planet) from the Sun."; assert(indexOf("def", cast(char)'f', CaseSensitive.no) == 2); assert(indexOf(sPlts, cast(char)'P', CaseSensitive.no) == 23); assert(indexOf(sPlts, cast(char)'R', CaseSensitive.no) == 2); } foreach (cs; EnumMembers!CaseSensitive) { assert(indexOf("hello\U00010143\u0100\U00010143", '\u0100', cs) == 9); assert(indexOf("hello\U00010143\u0100\U00010143"w, '\u0100', cs) == 7); assert(indexOf("hello\U00010143\u0100\U00010143"d, '\u0100', cs) == 6); assert(indexOf("hello\U00010143\u0100\U00010143".byChar, '\u0100', cs) == 9); assert(indexOf("hello\U00010143\u0100\U00010143".byWchar, '\u0100', cs) == 7); assert(indexOf("hello\U00010143\u0100\U00010143".byDchar, '\u0100', cs) == 6); assert(indexOf("hello\U000007FF\u0100\U00010143".byChar, 'l', cs) == 2); assert(indexOf("hello\U000007FF\u0100\U00010143".byChar, '\u0100', cs) == 7); assert(indexOf("hello\U0000EFFF\u0100\U00010143".byChar, '\u0100', cs) == 8); assert(indexOf("hello\U00010100".byWchar, '\U00010100', cs) == 5); assert(indexOf("hello\U00010100".byWchar, '\U00010101', cs) == -1); } char[10] fixedSizeArray = "0123456789"; assert(indexOf(fixedSizeArray, '2') == 2); }); } unittest { assert(testAliasedString!indexOf("std/string.d", '/', 3)); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.indexOf(startIdx).unittest\n"); import std.utf : byCodeUnit, byChar, byWchar; assert("hello".byCodeUnit.indexOf(cast(dchar)'l', 1) == 2); assert("hello".byWchar.indexOf(cast(dchar)'l', 1) == 2); assert("hello".byWchar.indexOf(cast(dchar)'l', 6) == -1); foreach (S; AliasSeq!(string, wstring, dstring)) { assert(indexOf(cast(S)null, cast(dchar)'a', 1) == -1); assert(indexOf(to!S("def"), cast(dchar)'a', 1) == -1); assert(indexOf(to!S("abba"), cast(dchar)'a', 1) == 3); assert(indexOf(to!S("def"), cast(dchar)'f', 1) == 2); assert((to!S("def")).indexOf(cast(dchar)'a', 1, CaseSensitive.no) == -1); assert(indexOf(to!S("def"), cast(dchar)'a', 1, CaseSensitive.no) == -1); assert(indexOf(to!S("def"), cast(dchar)'a', 12, CaseSensitive.no) == -1); assert(indexOf(to!S("AbbA"), cast(dchar)'a', 2, CaseSensitive.no) == 3); assert(indexOf(to!S("def"), cast(dchar)'F', 2, CaseSensitive.no) == 2); S sPlts = "Mars: the fourth Rock (Planet) from the Sun."; assert(indexOf("def", cast(char)'f', cast(uint)2, CaseSensitive.no) == 2); assert(indexOf(sPlts, cast(char)'P', 12, CaseSensitive.no) == 23); assert(indexOf(sPlts, cast(char)'R', cast(ulong)1, CaseSensitive.no) == 2); } foreach (cs; EnumMembers!CaseSensitive) { assert(indexOf("hello\U00010143\u0100\U00010143", '\u0100', 2, cs) == 9); assert(indexOf("hello\U00010143\u0100\U00010143"w, '\u0100', 3, cs) == 7); assert(indexOf("hello\U00010143\u0100\U00010143"d, '\u0100', 6, cs) == 6); } } /++ Searches for substring in $(D s). Params: s = string or ForwardRange of characters to search in correct UTF format sub = substring to search for startIdx = the index into s to start searching from cs = CaseSensitive.yes or CaseSensitive.no Returns: the index of the first occurrence of $(D sub) in $(D s) with respect to the start index $(D startIdx). If $(D sub) is not found, then $(D -1) is returned. If the arguments are not valid UTF, the result will still be in the range [-1 .. s.length], but will not be reliable otherwise. If $(D sub) is found the value of the returned index is at least $(D startIdx). Throws: If the sequence starting at $(D startIdx) does not represent a well formed codepoint, then a $(XREF utf,UTFException) may be thrown. Bugs: Does not work with case insensitive strings where the mapping of tolower and toupper is not 1:1. +/ ptrdiff_t indexOf(Range, Char)(Range s, const(Char)[] sub, in CaseSensitive cs = CaseSensitive.yes) if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && isSomeChar!Char) { import std.uni : toLower; alias Char1 = Unqual!(ElementEncodingType!Range); static if (isSomeString!Range) { import std.algorithm : find; const(Char1)[] balance; if (cs == CaseSensitive.yes) { balance = find(s, sub); } else { balance = find! ((a, b) => toLower(a) == toLower(b)) (s, sub); } return balance.empty ? -1 : balance.ptr - s.ptr; } else { if (s.empty) return -1; if (sub.empty) return 0; // degenerate case import std.utf : byDchar, codeLength; auto subr = sub.byDchar; // decode sub[] by dchar's dchar sub0 = subr.front; // cache first character of sub[] subr.popFront(); // Special case for single character search if (subr.empty) return indexOf(s, sub0, cs); if (cs == CaseSensitive.no) sub0 = toLower(sub0); /* Classic double nested loop search algorithm */ ptrdiff_t index = 0; // count code unit index into s for (auto sbydchar = s.byDchar(); !sbydchar.empty; sbydchar.popFront()) { dchar c2 = sbydchar.front; if (cs == CaseSensitive.no) c2 = toLower(c2); if (c2 == sub0) { auto s2 = sbydchar.save; // why s must be a forward range foreach (c; subr.save) { s2.popFront(); if (s2.empty) return -1; if (cs == CaseSensitive.yes ? c != s2.front : toLower(c) != toLower(s2.front) ) goto Lnext; } return index; } Lnext: index += codeLength!Char1(c2); } return -1; } } /// Ditto ptrdiff_t indexOf(Char1, Char2)(const(Char1)[] s, const(Char2)[] sub, in size_t startIdx, in CaseSensitive cs = CaseSensitive.yes) @safe if (isSomeChar!Char1 && isSomeChar!Char2) { if (startIdx < s.length) { ptrdiff_t foundIdx = indexOf(s[startIdx .. $], sub, cs); if (foundIdx != -1) { return foundIdx + cast(ptrdiff_t)startIdx; } } return -1; } /// @safe pure unittest { string s = "Hello World"; assert(indexOf(s, "Wo", 4) == 6); assert(indexOf(s, "Zo", 100) == -1); assert(indexOf(s, "wo", 3, CaseSensitive.no) == 6); } /// @safe pure unittest { string s = "Hello World"; assert(indexOf(s, "Wo") == 6); assert(indexOf(s, "Zo") == -1); assert(indexOf(s, "wO", CaseSensitive.no) == 6); } ptrdiff_t indexOf(Range, Char)(auto ref Range s, const(Char)[] sub, in CaseSensitive cs = CaseSensitive.yes) if (!(isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && isSomeChar!Char) && is(StringTypeOf!Range)) { return indexOf!(StringTypeOf!Range)(s, sub, cs); } unittest { assert(testAliasedString!indexOf("std/string.d", "string")); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.indexOf.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(indexOf(cast(S)null, to!T("a")) == -1); assert(indexOf(to!S("def"), to!T("a")) == -1); assert(indexOf(to!S("abba"), to!T("a")) == 0); assert(indexOf(to!S("def"), to!T("f")) == 2); assert(indexOf(to!S("dfefffg"), to!T("fff")) == 3); assert(indexOf(to!S("dfeffgfff"), to!T("fff")) == 6); assert(indexOf(to!S("dfeffgfff"), to!T("a"), CaseSensitive.no) == -1); assert(indexOf(to!S("def"), to!T("a"), CaseSensitive.no) == -1); assert(indexOf(to!S("abba"), to!T("a"), CaseSensitive.no) == 0); assert(indexOf(to!S("def"), to!T("f"), CaseSensitive.no) == 2); assert(indexOf(to!S("dfefffg"), to!T("fff"), CaseSensitive.no) == 3); assert(indexOf(to!S("dfeffgfff"), to!T("fff"), CaseSensitive.no) == 6); S sPlts = "Mars: the fourth Rock (Planet) from the Sun."; S sMars = "Who\'s \'My Favorite Maritian?\'"; assert(indexOf(sMars, to!T("MY fAVe"), CaseSensitive.no) == -1); assert(indexOf(sMars, to!T("mY fAVOriTe"), CaseSensitive.no) == 7); assert(indexOf(sPlts, to!T("mArS:"), CaseSensitive.no) == 0); assert(indexOf(sPlts, to!T("rOcK"), CaseSensitive.no) == 17); assert(indexOf(sPlts, to!T("Un."), CaseSensitive.no) == 41); assert(indexOf(sPlts, to!T(sPlts), CaseSensitive.no) == 0); assert(indexOf("\u0100", to!T("\u0100"), CaseSensitive.no) == 0); // Thanks to Carlos Santander B. and zwang assert(indexOf("sus mejores cortesanos. Se embarcaron en el puerto de Dubai y", to!T("page-break-before"), CaseSensitive.no) == -1); }(); foreach (cs; EnumMembers!CaseSensitive) { assert(indexOf("hello\U00010143\u0100\U00010143", to!S("\u0100"), cs) == 9); assert(indexOf("hello\U00010143\u0100\U00010143"w, to!S("\u0100"), cs) == 7); assert(indexOf("hello\U00010143\u0100\U00010143"d, to!S("\u0100"), cs) == 6); } } }); } @safe pure @nogc nothrow unittest { import std.utf : byWchar; foreach (cs; EnumMembers!CaseSensitive) { assert(indexOf("".byWchar, "", cs) == -1); assert(indexOf("hello".byWchar, "", cs) == 0); assert(indexOf("hello".byWchar, "l", cs) == 2); assert(indexOf("heLLo".byWchar, "LL", cs) == 2); assert(indexOf("hello".byWchar, "lox", cs) == -1); assert(indexOf("hello".byWchar, "betty", cs) == -1); assert(indexOf("hello\U00010143\u0100*\U00010143".byWchar, "\u0100*", cs) == 7); } } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.indexOf(startIdx).unittest\n"); foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(indexOf(cast(S)null, to!T("a"), 1337) == -1); assert(indexOf(to!S("def"), to!T("a"), 0) == -1); assert(indexOf(to!S("abba"), to!T("a"), 2) == 3); assert(indexOf(to!S("def"), to!T("f"), 1) == 2); assert(indexOf(to!S("dfefffg"), to!T("fff"), 1) == 3); assert(indexOf(to!S("dfeffgfff"), to!T("fff"), 5) == 6); assert(indexOf(to!S("dfeffgfff"), to!T("a"), 1, CaseSensitive.no) == -1); assert(indexOf(to!S("def"), to!T("a"), 2, CaseSensitive.no) == -1); assert(indexOf(to!S("abba"), to!T("a"), 3, CaseSensitive.no) == 3); assert(indexOf(to!S("def"), to!T("f"), 1, CaseSensitive.no) == 2); assert(indexOf(to!S("dfefffg"), to!T("fff"), 2, CaseSensitive.no) == 3); assert(indexOf(to!S("dfeffgfff"), to!T("fff"), 4, CaseSensitive.no) == 6); assert(indexOf(to!S("dfeffgffföä"), to!T("öä"), 9, CaseSensitive.no) == 9, to!string(indexOf(to!S("dfeffgffföä"), to!T("öä"), 9, CaseSensitive.no)) ~ " " ~ S.stringof ~ " " ~ T.stringof); S sPlts = "Mars: the fourth Rock (Planet) from the Sun."; S sMars = "Who\'s \'My Favorite Maritian?\'"; assert(indexOf(sMars, to!T("MY fAVe"), 10, CaseSensitive.no) == -1); assert(indexOf(sMars, to!T("mY fAVOriTe"), 4, CaseSensitive.no) == 7); assert(indexOf(sPlts, to!T("mArS:"), 0, CaseSensitive.no) == 0); assert(indexOf(sPlts, to!T("rOcK"), 12, CaseSensitive.no) == 17); assert(indexOf(sPlts, to!T("Un."), 32, CaseSensitive.no) == 41); assert(indexOf(sPlts, to!T(sPlts), 0, CaseSensitive.no) == 0); assert(indexOf("\u0100", to!T("\u0100"), 0, CaseSensitive.no) == 0); // Thanks to Carlos Santander B. and zwang assert(indexOf("sus mejores cortesanos. Se embarcaron en el puerto de Dubai y", to!T("page-break-before"), 10, CaseSensitive.no) == -1); // In order for indexOf with and without index to be consistent assert(indexOf(to!S(""), to!T("")) == indexOf(to!S(""), to!T(""), 0)); }(); foreach (cs; EnumMembers!CaseSensitive) { assert(indexOf("hello\U00010143\u0100\U00010143", to!S("\u0100"), 3, cs) == 9); assert(indexOf("hello\U00010143\u0100\U00010143"w, to!S("\u0100"), 3, cs) == 7); assert(indexOf("hello\U00010143\u0100\U00010143"d, to!S("\u0100"), 3, cs) == 6); } } } /++ Params: s = string to search c = character to search for startIdx = the index into s to start searching from cs = CaseSensitive.yes or CaseSensitive.no Returns: The index of the last occurrence of $(D c) in $(D s). If $(D c) is not found, then $(D -1) is returned. The $(D startIdx) slices $(D s) in the following way $(D s[0 .. startIdx]). $(D startIdx) represents a codeunit index in $(D s). Throws: If the sequence ending at $(D startIdx) does not represent a well formed codepoint, then a $(XREF utf,UTFException) may be thrown. $(D cs) indicates whether the comparisons are case sensitive. +/ ptrdiff_t lastIndexOf(Char)(const(Char)[] s, in dchar c, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char) { static import std.ascii, std.uni; import std.utf : canSearchInCodeUnits; if (cs == CaseSensitive.yes) { if (canSearchInCodeUnits!Char(c)) { foreach_reverse (i, it; s) { if (it == c) { return i; } } } else { foreach_reverse (i, dchar it; s) { if (it == c) { return i; } } } } else { if (std.ascii.isASCII(c)) { immutable c1 = std.ascii.toLower(c); foreach_reverse (i, it; s) { immutable c2 = std.ascii.toLower(it); if (c1 == c2) { return i; } } } else { immutable c1 = std.uni.toLower(c); foreach_reverse (i, dchar it; s) { immutable c2 = std.uni.toLower(it); if (c1 == c2) { return i; } } } } return -1; } /// Ditto ptrdiff_t lastIndexOf(Char)(const(Char)[] s, in dchar c, in size_t startIdx, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char) { if (startIdx <= s.length) { return lastIndexOf(s[0u .. startIdx], c, cs); } return -1; } /// @safe pure unittest { string s = "Hello World"; assert(lastIndexOf(s, 'l') == 9); assert(lastIndexOf(s, 'Z') == -1); assert(lastIndexOf(s, 'L', CaseSensitive.no) == 9); } /// @safe pure unittest { string s = "Hello World"; assert(lastIndexOf(s, 'l', 4) == 3); assert(lastIndexOf(s, 'Z', 1337) == -1); assert(lastIndexOf(s, 'L', 7, CaseSensitive.no) == 3); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.lastIndexOf.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { assert(lastIndexOf(cast(S) null, 'a') == -1); assert(lastIndexOf(to!S("def"), 'a') == -1); assert(lastIndexOf(to!S("abba"), 'a') == 3); assert(lastIndexOf(to!S("def"), 'f') == 2); assert(lastIndexOf(to!S("ödef"), 'ö') == 0); assert(lastIndexOf(cast(S) null, 'a', CaseSensitive.no) == -1); assert(lastIndexOf(to!S("def"), 'a', CaseSensitive.no) == -1); assert(lastIndexOf(to!S("AbbA"), 'a', CaseSensitive.no) == 3); assert(lastIndexOf(to!S("def"), 'F', CaseSensitive.no) == 2); assert(lastIndexOf(to!S("ödef"), 'ö', CaseSensitive.no) == 0); assert(lastIndexOf(to!S("i\u0100def"), to!dchar("\u0100"), CaseSensitive.no) == 1); S sPlts = "Mars: the fourth Rock (Planet) from the Sun."; assert(lastIndexOf(to!S("def"), 'f', CaseSensitive.no) == 2); assert(lastIndexOf(sPlts, 'M', CaseSensitive.no) == 34); assert(lastIndexOf(sPlts, 'S', CaseSensitive.no) == 40); } foreach (cs; EnumMembers!CaseSensitive) { assert(lastIndexOf("\U00010143\u0100\U00010143hello", '\u0100', cs) == 4); assert(lastIndexOf("\U00010143\u0100\U00010143hello"w, '\u0100', cs) == 2); assert(lastIndexOf("\U00010143\u0100\U00010143hello"d, '\u0100', cs) == 1); } }); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.lastIndexOf.unittest\n"); foreach (S; AliasSeq!(string, wstring, dstring)) { assert(lastIndexOf(cast(S) null, 'a') == -1); assert(lastIndexOf(to!S("def"), 'a') == -1); assert(lastIndexOf(to!S("abba"), 'a', 3) == 0); assert(lastIndexOf(to!S("deff"), 'f', 3) == 2); assert(lastIndexOf(cast(S) null, 'a', CaseSensitive.no) == -1); assert(lastIndexOf(to!S("def"), 'a', CaseSensitive.no) == -1); assert(lastIndexOf(to!S("AbbAa"), 'a', to!ushort(4), CaseSensitive.no) == 3, to!string(lastIndexOf(to!S("AbbAa"), 'a', 4, CaseSensitive.no))); assert(lastIndexOf(to!S("def"), 'F', 3, CaseSensitive.no) == 2); S sPlts = "Mars: the fourth Rock (Planet) from the Sun."; assert(lastIndexOf(to!S("def"), 'f', 4, CaseSensitive.no) == -1); assert(lastIndexOf(sPlts, 'M', sPlts.length -2, CaseSensitive.no) == 34); assert(lastIndexOf(sPlts, 'S', sPlts.length -2, CaseSensitive.no) == 40); } foreach (cs; EnumMembers!CaseSensitive) { assert(lastIndexOf("\U00010143\u0100\U00010143hello", '\u0100', cs) == 4); assert(lastIndexOf("\U00010143\u0100\U00010143hello"w, '\u0100', cs) == 2); assert(lastIndexOf("\U00010143\u0100\U00010143hello"d, '\u0100', cs) == 1); } } /++ Params: s = string to search sub = substring to search for startIdx = the index into s to start searching from cs = CaseSensitive.yes or CaseSensitive.no Returns: the index of the last occurrence of $(D sub) in $(D s). If $(D sub) is not found, then $(D -1) is returned. The $(D startIdx) slices $(D s) in the following way $(D s[0 .. startIdx]). $(D startIdx) represents a codeunit index in $(D s). Throws: If the sequence ending at $(D startIdx) does not represent a well formed codepoint, then a $(XREF utf,UTFException) may be thrown. $(D cs) indicates whether the comparisons are case sensitive. +/ ptrdiff_t lastIndexOf(Char1, Char2)(const(Char1)[] s, const(Char2)[] sub, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char1 && isSomeChar!Char2) { import std.utf : strideBack; import std.conv : to; import std.algorithm : endsWith; if (sub.empty) return -1; if (walkLength(sub) == 1) return lastIndexOf(s, sub.front, cs); if (cs == CaseSensitive.yes) { static if (is(Unqual!Char1 == Unqual!Char2)) { import core.stdc.string : memcmp; immutable c = sub[0]; for (ptrdiff_t i = s.length - sub.length; i >= 0; --i) { if (s[i] == c) { if (__ctfe) { foreach (j; 1 .. sub.length) { if (s[i + j] != sub[j]) continue; } return i; } else { auto trustedMemcmp(in void* s1, in void* s2, size_t n) @trusted { return memcmp(s1, s2, n); } if (trustedMemcmp(&s[i + 1], &sub[1], (sub.length - 1) * Char1.sizeof) == 0) return i; } } } } else { for (size_t i = s.length; !s.empty;) { if (s.endsWith(sub)) return cast(ptrdiff_t)i - to!(const(Char1)[])(sub).length; i -= strideBack(s, i); s = s[0 .. i]; } } } else { for (size_t i = s.length; !s.empty;) { if (endsWith!((a, b) => std.uni.toLower(a) == std.uni.toLower(b)) (s, sub)) { return cast(ptrdiff_t)i - to!(const(Char1)[])(sub).length; } i -= strideBack(s, i); s = s[0 .. i]; } } return -1; } /// Ditto ptrdiff_t lastIndexOf(Char1, Char2)(const(Char1)[] s, const(Char2)[] sub, in size_t startIdx, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char1 && isSomeChar!Char2) { if (startIdx <= s.length) { return lastIndexOf(s[0u .. startIdx], sub, cs); } return -1; } /// @safe pure unittest { string s = "Hello World"; assert(lastIndexOf(s, "ll") == 2); assert(lastIndexOf(s, "Zo") == -1); assert(lastIndexOf(s, "lL", CaseSensitive.no) == 2); } /// @safe pure unittest { string s = "Hello World"; assert(lastIndexOf(s, "ll", 4) == 2); assert(lastIndexOf(s, "Zo", 128) == -1); assert(lastIndexOf(s, "lL", 3, CaseSensitive.no) == -1); } @safe pure unittest { import std.conv : to; foreach (S; AliasSeq!(string, wstring, dstring)) { auto r = to!S("").lastIndexOf("hello"); assert(r == -1, to!string(r)); r = to!S("hello").lastIndexOf(""); assert(r == -1, to!string(r)); r = to!S("").lastIndexOf(""); assert(r == -1, to!string(r)); } } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.lastIndexOf.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 enum typeStr = S.stringof ~ " " ~ T.stringof; assert(lastIndexOf(cast(S)null, to!T("a")) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("c")) == 6, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("cd")) == 6, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("ef")) == 8, typeStr); assert(lastIndexOf(to!S("abcdefCdef"), to!T("c")) == 2, typeStr); assert(lastIndexOf(to!S("abcdefCdef"), to!T("cd")) == 2, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("x")) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("xy")) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("")) == -1, typeStr); assert(lastIndexOf(to!S("öabcdefcdef"), to!T("ö")) == 0, typeStr); assert(lastIndexOf(cast(S)null, to!T("a"), CaseSensitive.no) == -1, typeStr); assert(lastIndexOf(to!S("abcdefCdef"), to!T("c"), CaseSensitive.no) == 6, typeStr); assert(lastIndexOf(to!S("abcdefCdef"), to!T("cD"), CaseSensitive.no) == 6, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("x"), CaseSensitive.no) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("xy"), CaseSensitive.no) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T(""), CaseSensitive.no) == -1, typeStr); assert(lastIndexOf(to!S("öabcdefcdef"), to!T("ö"), CaseSensitive.no) == 0, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("c"), CaseSensitive.no) == 6, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("cd"), CaseSensitive.no) == 6, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("def"), CaseSensitive.no) == 7, typeStr); assert(lastIndexOf(to!S("ödfeffgfff"), to!T("ö"), CaseSensitive.yes) == 0); S sPlts = "Mars: the fourth Rock (Planet) from the Sun."; S sMars = "Who\'s \'My Favorite Maritian?\'"; assert(lastIndexOf(sMars, to!T("RiTE maR"), CaseSensitive.no) == 14, typeStr); assert(lastIndexOf(sPlts, to!T("FOuRTh"), CaseSensitive.no) == 10, typeStr); assert(lastIndexOf(sMars, to!T("whO\'s \'MY"), CaseSensitive.no) == 0, typeStr); assert(lastIndexOf(sMars, to!T(sMars), CaseSensitive.no) == 0, typeStr); }(); foreach (cs; EnumMembers!CaseSensitive) { enum csString = to!string(cs); assert(lastIndexOf("\U00010143\u0100\U00010143hello", to!S("\u0100"), cs) == 4, csString); assert(lastIndexOf("\U00010143\u0100\U00010143hello"w, to!S("\u0100"), cs) == 2, csString); assert(lastIndexOf("\U00010143\u0100\U00010143hello"d, to!S("\u0100"), cs) == 1, csString); } } }); } @safe pure unittest // issue13529 { import std.conv : to; foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) { enum typeStr = S.stringof ~ " " ~ T.stringof; auto idx = lastIndexOf(to!T("Hällö Wörldö ö"),to!S("ö ö")); assert(idx != -1, to!string(idx) ~ " " ~ typeStr); idx = lastIndexOf(to!T("Hällö Wörldö ö"),to!S("ö öd")); assert(idx == -1, to!string(idx) ~ " " ~ typeStr); } } } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.lastIndexOf.unittest\n"); foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 enum typeStr = S.stringof ~ " " ~ T.stringof; assert(lastIndexOf(cast(S)null, to!T("a")) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("c"), 5) == 2, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("cd"), 3) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("ef"), 6) == 4, typeStr ~ format(" %u", lastIndexOf(to!S("abcdefcdef"), to!T("ef"), 6))); assert(lastIndexOf(to!S("abcdefCdef"), to!T("c"), 5) == 2, typeStr); assert(lastIndexOf(to!S("abcdefCdef"), to!T("cd"), 3) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdefx"), to!T("x"), 1) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdefxy"), to!T("xy"), 6) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T(""), 8) == -1, typeStr); assert(lastIndexOf(to!S("öafö"), to!T("ö"), 3) == 0, typeStr ~ to!string(lastIndexOf(to!S("öafö"), to!T("ö"), 3))); //BUG 10472 assert(lastIndexOf(cast(S)null, to!T("a"), 1, CaseSensitive.no) == -1, typeStr); assert(lastIndexOf(to!S("abcdefCdef"), to!T("c"), 5, CaseSensitive.no) == 2, typeStr); assert(lastIndexOf(to!S("abcdefCdef"), to!T("cD"), 4, CaseSensitive.no) == 2, typeStr ~ " " ~ to!string(lastIndexOf(to!S("abcdefCdef"), to!T("cD"), 3, CaseSensitive.no))); assert(lastIndexOf(to!S("abcdefcdef"), to!T("x"),3 , CaseSensitive.no) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdefXY"), to!T("xy"), 4, CaseSensitive.no) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T(""), 7, CaseSensitive.no) == -1, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("c"), 4, CaseSensitive.no) == 2, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("cd"), 4, CaseSensitive.no) == 2, typeStr); assert(lastIndexOf(to!S("abcdefcdef"), to!T("def"), 6, CaseSensitive.no) == 3, typeStr); assert(lastIndexOf(to!S(""), to!T(""), 0) == lastIndexOf(to!S(""), to!T("")), typeStr); }(); foreach (cs; EnumMembers!CaseSensitive) { enum csString = to!string(cs); assert(lastIndexOf("\U00010143\u0100\U00010143hello", to!S("\u0100"), 6, cs) == 4, csString); assert(lastIndexOf("\U00010143\u0100\U00010143hello"w, to!S("\u0100"), 6, cs) == 2, csString); assert(lastIndexOf("\U00010143\u0100\U00010143hello"d, to!S("\u0100"), 3, cs) == 1, csString); } } } private ptrdiff_t indexOfAnyNeitherImpl(bool forward, bool any, Char, Char2)( const(Char)[] haystack, const(Char2)[] needles, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char && isSomeChar!Char2) { import std.algorithm : canFind; if (cs == CaseSensitive.yes) { static if (forward) { static if (any) { import std.algorithm : findAmong; size_t n = haystack.findAmong(needles).length; return n ? haystack.length - n : -1; } else { foreach (idx, dchar hay; haystack) { if (!canFind(needles, hay)) { return idx; } } } } else { static if (any) { import std.utf : strideBack; import std.algorithm : findAmong; import std.range : retro; size_t n = haystack.retro.findAmong(needles).source.length; if (n) { return n - haystack.strideBack(n); } } else { foreach_reverse (idx, dchar hay; haystack) { if(!canFind(needles, hay)) { return idx; } } } } } else { import std.uni: toLower; if (needles.length <= 16 && needles.walkLength(17)) { size_t si = 0; dchar[16] scratch = void; foreach ( dchar c; needles) { scratch[si++] = toLower(c); } static if (forward) { foreach (i, dchar c; haystack) { if (canFind(scratch[0 .. si], toLower(c)) == any) { return i; } } } else { foreach_reverse (i, dchar c; haystack) { if (canFind(scratch[0 .. si], toLower(c)) == any) { return i; } } } } else { static bool f(dchar a, dchar b) { return toLower(a) == b; } static if (forward) { foreach (i, dchar c; haystack) { if (canFind!f(needles, toLower(c)) == any) { return i; } } } else { foreach_reverse (i, dchar c; haystack) { if (canFind!f(needles, toLower(c)) == any) { return i; } } } } } return -1; } /** Returns the index of the first occurence of any of the elements in $(D needles) in $(D haystack). If no element of $(D needles) is found, then $(D -1) is returned. The $(D startIdx) slices $(D haystack) in the following way $(D haystack[startIdx .. $]). $(D startIdx) represents a codeunit index in $(D haystack). If the sequence ending at $(D startIdx) does not represent a well formed codepoint, then a $(XREF utf,UTFException) may be thrown. Params: haystack = String to search for needles in. needles = Strings to search for in haystack. startIdx = slices haystack like this $(D haystack[startIdx .. $]). If the startIdx is greater equal the length of haystack the functions returns $(D -1). cs = Indicates whether the comparisons are case sensitive. */ ptrdiff_t indexOfAny(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char && isSomeChar!Char2) { return indexOfAnyNeitherImpl!(true, true)(haystack, needles, cs); } /// Ditto ptrdiff_t indexOfAny(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles, in size_t startIdx, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char && isSomeChar!Char2) { if (startIdx < haystack.length) { ptrdiff_t foundIdx = indexOfAny(haystack[startIdx .. $], needles, cs); if (foundIdx != -1) { return foundIdx + cast(ptrdiff_t)startIdx; } } return -1; } /// @safe pure unittest { import std.conv : to; ptrdiff_t i = "helloWorld".indexOfAny("Wr"); assert(i == 5); i = "öällo world".indexOfAny("lo "); assert(i == 4, to!string(i)); } /// @safe pure unittest { import std.conv : to; ptrdiff_t i = "helloWorld".indexOfAny("Wr", 4); assert(i == 5); i = "Foo öällo world".indexOfAny("lh", 3); assert(i == 8, to!string(i)); } @safe pure unittest { import std.conv : to; foreach (S; AliasSeq!(string, wstring, dstring)) { auto r = to!S("").indexOfAny("hello"); assert(r == -1, to!string(r)); r = to!S("hello").indexOfAny(""); assert(r == -1, to!string(r)); r = to!S("").indexOfAny(""); assert(r == -1, to!string(r)); } } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.indexOfAny.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(indexOfAny(cast(S)null, to!T("a")) == -1); assert(indexOfAny(to!S("def"), to!T("rsa")) == -1); assert(indexOfAny(to!S("abba"), to!T("a")) == 0); assert(indexOfAny(to!S("def"), to!T("f")) == 2); assert(indexOfAny(to!S("dfefffg"), to!T("fgh")) == 1); assert(indexOfAny(to!S("dfeffgfff"), to!T("feg")) == 1); assert(indexOfAny(to!S("zfeffgfff"), to!T("ACDC"), CaseSensitive.no) == -1); assert(indexOfAny(to!S("def"), to!T("MI6"), CaseSensitive.no) == -1); assert(indexOfAny(to!S("abba"), to!T("DEA"), CaseSensitive.no) == 0); assert(indexOfAny(to!S("def"), to!T("FBI"), CaseSensitive.no) == 2); assert(indexOfAny(to!S("dfefffg"), to!T("NSA"), CaseSensitive.no) == -1); assert(indexOfAny(to!S("dfeffgfff"), to!T("BND"), CaseSensitive.no) == 0); assert(indexOfAny(to!S("dfeffgfff"), to!T("BNDabCHIJKQEPÖÖSYXÄ??ß"), CaseSensitive.no) == 0); assert(indexOfAny("\u0100", to!T("\u0100"), CaseSensitive.no) == 0); }(); } } ); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.indexOfAny(startIdx).unittest\n"); foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(indexOfAny(cast(S)null, to!T("a"), 1337) == -1); assert(indexOfAny(to!S("def"), to!T("AaF"), 0) == -1); assert(indexOfAny(to!S("abba"), to!T("NSa"), 2) == 3); assert(indexOfAny(to!S("def"), to!T("fbi"), 1) == 2); assert(indexOfAny(to!S("dfefffg"), to!T("foo"), 2) == 3); assert(indexOfAny(to!S("dfeffgfff"), to!T("fsb"), 5) == 6); assert(indexOfAny(to!S("dfeffgfff"), to!T("NDS"), 1, CaseSensitive.no) == -1); assert(indexOfAny(to!S("def"), to!T("DRS"), 2, CaseSensitive.no) == -1); assert(indexOfAny(to!S("abba"), to!T("SI"), 3, CaseSensitive.no) == -1); assert(indexOfAny(to!S("deO"), to!T("ASIO"), 1, CaseSensitive.no) == 2); assert(indexOfAny(to!S("dfefffg"), to!T("fbh"), 2, CaseSensitive.no) == 3); assert(indexOfAny(to!S("dfeffgfff"), to!T("fEe"), 4, CaseSensitive.no) == 4); assert(indexOfAny(to!S("dfeffgffföä"), to!T("föä"), 9, CaseSensitive.no) == 9); assert(indexOfAny("\u0100", to!T("\u0100"), 0, CaseSensitive.no) == 0); }(); foreach (cs; EnumMembers!CaseSensitive) { assert(indexOfAny("hello\U00010143\u0100\U00010143", to!S("e\u0100"), 3, cs) == 9); assert(indexOfAny("hello\U00010143\u0100\U00010143"w, to!S("h\u0100"), 3, cs) == 7); assert(indexOfAny("hello\U00010143\u0100\U00010143"d, to!S("l\u0100"), 5, cs) == 6); } } } /** Returns the index of the last occurence of any of the elements in $(D needles) in $(D haystack). If no element of $(D needles) is found, then $(D -1) is returned. The $(D stopIdx) slices $(D haystack) in the following way $(D s[0 .. stopIdx]). $(D stopIdx) represents a codeunit index in $(D haystack). If the sequence ending at $(D startIdx) does not represent a well formed codepoint, then a $(XREF utf,UTFException) may be thrown. Params: haystack = String to search for needles in. needles = Strings to search for in haystack. stopIdx = slices haystack like this $(D haystack[0 .. stopIdx]). If the stopIdx is greater equal the length of haystack the functions returns $(D -1). cs = Indicates whether the comparisons are case sensitive. */ ptrdiff_t lastIndexOfAny(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char && isSomeChar!Char2) { return indexOfAnyNeitherImpl!(false, true)(haystack, needles, cs); } /// Ditto ptrdiff_t lastIndexOfAny(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles, in size_t stopIdx, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char && isSomeChar!Char2) { if (stopIdx <= haystack.length) { return lastIndexOfAny(haystack[0u .. stopIdx], needles, cs); } return -1; } /// @safe pure unittest { ptrdiff_t i = "helloWorld".lastIndexOfAny("Wlo"); assert(i == 8); i = "Foo öäöllo world".lastIndexOfAny("öF"); assert(i == 8); } /// @safe pure unittest { import std.conv : to; ptrdiff_t i = "helloWorld".lastIndexOfAny("Wlo", 4); assert(i == 3); i = "Foo öäöllo world".lastIndexOfAny("öF", 3); assert(i == 0); } @safe pure unittest { import std.conv : to; foreach (S; AliasSeq!(string, wstring, dstring)) { auto r = to!S("").lastIndexOfAny("hello"); assert(r == -1, to!string(r)); r = to!S("hello").lastIndexOfAny(""); assert(r == -1, to!string(r)); r = to!S("").lastIndexOfAny(""); assert(r == -1, to!string(r)); } } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.lastIndexOfAny.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(lastIndexOfAny(cast(S)null, to!T("a")) == -1); assert(lastIndexOfAny(to!S("def"), to!T("rsa")) == -1); assert(lastIndexOfAny(to!S("abba"), to!T("a")) == 3); assert(lastIndexOfAny(to!S("def"), to!T("f")) == 2); assert(lastIndexOfAny(to!S("dfefffg"), to!T("fgh")) == 6); ptrdiff_t oeIdx = 9; if (is(S == wstring) || is(S == dstring)) { oeIdx = 8; } auto foundOeIdx = lastIndexOfAny(to!S("dfeffgföf"), to!T("feg")); assert(foundOeIdx == oeIdx, to!string(foundOeIdx)); assert(lastIndexOfAny(to!S("zfeffgfff"), to!T("ACDC"), CaseSensitive.no) == -1); assert(lastIndexOfAny(to!S("def"), to!T("MI6"), CaseSensitive.no) == -1); assert(lastIndexOfAny(to!S("abba"), to!T("DEA"), CaseSensitive.no) == 3); assert(lastIndexOfAny(to!S("def"), to!T("FBI"), CaseSensitive.no) == 2); assert(lastIndexOfAny(to!S("dfefffg"), to!T("NSA"), CaseSensitive.no) == -1); oeIdx = 2; if (is(S == wstring) || is(S == dstring)) { oeIdx = 1; } assert(lastIndexOfAny(to!S("ödfeffgfff"), to!T("BND"), CaseSensitive.no) == oeIdx); assert(lastIndexOfAny("\u0100", to!T("\u0100"), CaseSensitive.no) == 0); }(); } } ); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.lastIndexOfAny(index).unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 enum typeStr = S.stringof ~ " " ~ T.stringof; assert(lastIndexOfAny(cast(S)null, to!T("a"), 1337) == -1, typeStr); assert(lastIndexOfAny(to!S("abcdefcdef"), to!T("c"), 7) == 6, typeStr); assert(lastIndexOfAny(to!S("abcdefcdef"), to!T("cd"), 5) == 3, typeStr); assert(lastIndexOfAny(to!S("abcdefcdef"), to!T("ef"), 6) == 5, typeStr); assert(lastIndexOfAny(to!S("abcdefCdef"), to!T("c"), 8) == 2, typeStr); assert(lastIndexOfAny(to!S("abcdefcdef"), to!T("x"), 7) == -1, typeStr); assert(lastIndexOfAny(to!S("abcdefcdef"), to!T("xy"), 4) == -1, typeStr); assert(lastIndexOfAny(to!S("öabcdefcdef"), to!T("ö"), 2) == 0, typeStr); assert(lastIndexOfAny(cast(S)null, to!T("a"), 1337, CaseSensitive.no) == -1, typeStr); assert(lastIndexOfAny(to!S("abcdefcdef"), to!T("C"), 7, CaseSensitive.no) == 6, typeStr); assert(lastIndexOfAny(to!S("ABCDEFCDEF"), to!T("cd"), 5, CaseSensitive.no) == 3, typeStr); assert(lastIndexOfAny(to!S("abcdefcdef"), to!T("EF"), 6, CaseSensitive.no) == 5, typeStr); assert(lastIndexOfAny(to!S("ABCDEFcDEF"), to!T("C"), 8, CaseSensitive.no) == 6, typeStr); assert(lastIndexOfAny(to!S("ABCDEFCDEF"), to!T("x"), 7, CaseSensitive.no) == -1, typeStr); assert(lastIndexOfAny(to!S("abCdefcdef"), to!T("XY"), 4, CaseSensitive.no) == -1, typeStr); assert(lastIndexOfAny(to!S("ÖABCDEFCDEF"), to!T("ö"), 2, CaseSensitive.no) == 0, typeStr); }(); } } ); } /** Returns the index of the first occurence of any character not an elements in $(D needles) in $(D haystack). If all element of $(D haystack) are element of $(D needles) $(D -1) is returned. Params: haystack = String to search for needles in. needles = Strings to search for in haystack. startIdx = slices haystack like this $(D haystack[startIdx .. $]). If the startIdx is greater equal the length of haystack the functions returns $(D -1). cs = Indicates whether the comparisons are case sensitive. */ ptrdiff_t indexOfNeither(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char && isSomeChar!Char2) { return indexOfAnyNeitherImpl!(true, false)(haystack, needles, cs); } /// Ditto ptrdiff_t indexOfNeither(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles, in size_t startIdx, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char && isSomeChar!Char2) { if (startIdx < haystack.length) { ptrdiff_t foundIdx = indexOfAnyNeitherImpl!(true, false)( haystack[startIdx .. $], needles, cs); if (foundIdx != -1) { return foundIdx + cast(ptrdiff_t)startIdx; } } return -1; } /// @safe pure unittest { assert(indexOfNeither("abba", "a", 2) == 2); assert(indexOfNeither("def", "de", 1) == 2); assert(indexOfNeither("dfefffg", "dfe", 4) == 6); } /// @safe pure unittest { assert(indexOfNeither("def", "a") == 0); assert(indexOfNeither("def", "de") == 2); assert(indexOfNeither("dfefffg", "dfe") == 6); } @safe pure unittest { import std.conv : to; foreach (S; AliasSeq!(string, wstring, dstring)) { auto r = to!S("").indexOfNeither("hello"); assert(r == -1, to!string(r)); r = to!S("hello").indexOfNeither(""); assert(r == 0, to!string(r)); r = to!S("").indexOfNeither(""); assert(r == -1, to!string(r)); } } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.indexOf.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(indexOfNeither(cast(S)null, to!T("a")) == -1); assert(indexOfNeither("abba", "a") == 1); assert(indexOfNeither(to!S("dfeffgfff"), to!T("a"), CaseSensitive.no) == 0); assert(indexOfNeither(to!S("def"), to!T("D"), CaseSensitive.no) == 1); assert(indexOfNeither(to!S("ABca"), to!T("a"), CaseSensitive.no) == 1); assert(indexOfNeither(to!S("def"), to!T("f"), CaseSensitive.no) == 0); assert(indexOfNeither(to!S("DfEfffg"), to!T("dFe"), CaseSensitive.no) == 6); if (is(S == string)) { assert(indexOfNeither(to!S("äDfEfffg"), to!T("ädFe"), CaseSensitive.no) == 8, to!string(indexOfNeither(to!S("äDfEfffg"), to!T("ädFe"), CaseSensitive.no))); } else { assert(indexOfNeither(to!S("äDfEfffg"), to!T("ädFe"), CaseSensitive.no) == 7, to!string(indexOfNeither(to!S("äDfEfffg"), to!T("ädFe"), CaseSensitive.no))); } }(); } } ); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.indexOfNeither(index).unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(indexOfNeither(cast(S)null, to!T("a"), 1) == -1); assert(indexOfNeither(to!S("def"), to!T("a"), 1) == 1, to!string(indexOfNeither(to!S("def"), to!T("a"), 1))); assert(indexOfNeither(to!S("dfeffgfff"), to!T("a"), 4, CaseSensitive.no) == 4); assert(indexOfNeither(to!S("def"), to!T("D"), 2, CaseSensitive.no) == 2); assert(indexOfNeither(to!S("ABca"), to!T("a"), 3, CaseSensitive.no) == -1); assert(indexOfNeither(to!S("def"), to!T("tzf"), 2, CaseSensitive.no) == -1); assert(indexOfNeither(to!S("DfEfffg"), to!T("dFe"), 5, CaseSensitive.no) == 6); if (is(S == string)) { assert(indexOfNeither(to!S("öDfEfffg"), to!T("äDi"), 2, CaseSensitive.no) == 3, to!string(indexOfNeither( to!S("öDfEfffg"), to!T("äDi"), 2, CaseSensitive.no))); } else { assert(indexOfNeither(to!S("öDfEfffg"), to!T("äDi"), 2, CaseSensitive.no) == 2, to!string(indexOfNeither( to!S("öDfEfffg"), to!T("äDi"), 2, CaseSensitive.no))); } }(); } } ); } /** Returns the last index of the first occurence of any character that is not an elements in $(D needles) in $(D haystack). If all element of $(D haystack) are element of $(D needles) $(D -1) is returned. Params: haystack = String to search for needles in. needles = Strings to search for in haystack. stopIdx = slices haystack like this $(D haystack[0 .. stopIdx]) If the stopIdx is greater equal the length of haystack the functions returns $(D -1). cs = Indicates whether the comparisons are case sensitive. */ ptrdiff_t lastIndexOfNeither(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char && isSomeChar!Char2) { return indexOfAnyNeitherImpl!(false, false)(haystack, needles, cs); } /// Ditto ptrdiff_t lastIndexOfNeither(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles, in size_t stopIdx, in CaseSensitive cs = CaseSensitive.yes) @safe pure if (isSomeChar!Char && isSomeChar!Char2) { if (stopIdx < haystack.length) { return indexOfAnyNeitherImpl!(false, false)(haystack[0 .. stopIdx], needles, cs); } return -1; } /// @safe pure unittest { assert(lastIndexOfNeither("abba", "a") == 2); assert(lastIndexOfNeither("def", "f") == 1); } /// @safe pure unittest { assert(lastIndexOfNeither("def", "rsa", 3) == -1); assert(lastIndexOfNeither("abba", "a", 2) == 1); } @safe pure unittest { import std.conv : to; foreach (S; AliasSeq!(string, wstring, dstring)) { auto r = to!S("").lastIndexOfNeither("hello"); assert(r == -1, to!string(r)); r = to!S("hello").lastIndexOfNeither(""); assert(r == 4, to!string(r)); r = to!S("").lastIndexOfNeither(""); assert(r == -1, to!string(r)); } } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.lastIndexOfNeither.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(lastIndexOfNeither(cast(S)null, to!T("a")) == -1); assert(lastIndexOfNeither(to!S("def"), to!T("rsa")) == 2); assert(lastIndexOfNeither(to!S("dfefffg"), to!T("fgh")) == 2); ptrdiff_t oeIdx = 8; if (is(S == string)) { oeIdx = 9; } auto foundOeIdx = lastIndexOfNeither(to!S("ödfefegff"), to!T("zeg")); assert(foundOeIdx == oeIdx, to!string(foundOeIdx)); assert(lastIndexOfNeither(to!S("zfeffgfsb"), to!T("FSB"), CaseSensitive.no) == 5); assert(lastIndexOfNeither(to!S("def"), to!T("MI6"), CaseSensitive.no) == 2, to!string(lastIndexOfNeither(to!S("def"), to!T("MI6"), CaseSensitive.no))); assert(lastIndexOfNeither(to!S("abbadeafsb"), to!T("fSb"), CaseSensitive.no) == 6, to!string(lastIndexOfNeither( to!S("abbadeafsb"), to!T("fSb"), CaseSensitive.no))); assert(lastIndexOfNeither(to!S("defbi"), to!T("FBI"), CaseSensitive.no) == 1); assert(lastIndexOfNeither(to!S("dfefffg"), to!T("NSA"), CaseSensitive.no) == 6); assert(lastIndexOfNeither(to!S("dfeffgfffö"), to!T("BNDabCHIJKQEPÖÖSYXÄ??ß"), CaseSensitive.no) == 8, to!string(lastIndexOfNeither(to!S("dfeffgfffö"), to!T("BNDabCHIJKQEPÖÖSYXÄ??ß"), CaseSensitive.no))); }(); } } ); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.lastIndexOfNeither(index).unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { foreach (T; AliasSeq!(string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(lastIndexOfNeither(cast(S)null, to!T("a"), 1337) == -1); assert(lastIndexOfNeither(to!S("def"), to!T("f")) == 1); assert(lastIndexOfNeither(to!S("dfefffg"), to!T("fgh")) == 2); ptrdiff_t oeIdx = 4; if (is(S == string)) { oeIdx = 5; } auto foundOeIdx = lastIndexOfNeither(to!S("ödfefegff"), to!T("zeg"), 7); assert(foundOeIdx == oeIdx, to!string(foundOeIdx)); assert(lastIndexOfNeither(to!S("zfeffgfsb"), to!T("FSB"), 6, CaseSensitive.no) == 5); assert(lastIndexOfNeither(to!S("def"), to!T("MI6"), 2, CaseSensitive.no) == 1, to!string(lastIndexOfNeither(to!S("def"), to!T("MI6"), 2, CaseSensitive.no))); assert(lastIndexOfNeither(to!S("abbadeafsb"), to!T("fSb"), 6, CaseSensitive.no) == 5, to!string(lastIndexOfNeither( to!S("abbadeafsb"), to!T("fSb"), 6, CaseSensitive.no))); assert(lastIndexOfNeither(to!S("defbi"), to!T("FBI"), 3, CaseSensitive.no) == 1); assert(lastIndexOfNeither(to!S("dfefffg"), to!T("NSA"), 2, CaseSensitive.no) == 1, to!string(lastIndexOfNeither( to!S("dfefffg"), to!T("NSA"), 2, CaseSensitive.no))); }(); } } ); } /** * Returns the _representation of a string, which has the same type * as the string except the character type is replaced by $(D ubyte), * $(D ushort), or $(D uint) depending on the character width. * * Params: * s = The string to return the _representation of. * * Returns: * The _representation of the passed string. */ auto representation(Char)(Char[] s) @safe pure nothrow @nogc if (isSomeChar!Char) { alias ToRepType(T) = AliasSeq!(ubyte, ushort, uint)[T.sizeof / 2]; return cast(ModifyTypePreservingTQ!(ToRepType, Char)[])s; } /// @safe pure unittest { string s = "hello"; static assert(is(typeof(representation(s)) == immutable(ubyte)[])); assert(representation(s) is cast(immutable(ubyte)[]) s); assert(representation(s) == [0x68, 0x65, 0x6c, 0x6c, 0x6f]); } @trusted pure unittest { import std.exception; import std.typecons; assertCTFEable!( { void test(Char, T)(Char[] str) { static assert(is(typeof(representation(str)) == T[])); assert(representation(str) is cast(T[]) str); } foreach (Type; AliasSeq!(Tuple!(char , ubyte ), Tuple!(wchar, ushort), Tuple!(dchar, uint ))) { alias Char = Fields!Type[0]; alias Int = Fields!Type[1]; enum immutable(Char)[] hello = "hello"; test!( immutable Char, immutable Int)(hello); test!( const Char, const Int)(hello); test!( Char, Int)(hello.dup); test!( shared Char, shared Int)(cast(shared) hello.dup); test!(const shared Char, const shared Int)(hello); } }); } /** * Capitalize the first character of $(D s) and convert the rest of $(D s) to * lowercase. * * Params: * input = The string to _capitalize. * * Returns: * The capitalized string. * * See_Also: * $(XREF uni, asCapitalized) for a lazy range version that doesn't allocate memory */ S capitalize(S)(S input) @trusted pure if (isSomeString!S) { import std.uni : asCapitalized; import std.conv: to; import std.array; return input.asCapitalized.array.to!S; } /// pure @safe unittest { assert(capitalize("hello") == "Hello"); assert(capitalize("World") == "World"); } auto capitalize(S)(auto ref S s) if (!isSomeString!S && is(StringTypeOf!S)) { return capitalize!(StringTypeOf!S)(s); } @safe pure unittest { assert(testAliasedString!capitalize("hello")); } @safe pure unittest { import std.conv : to; import std.algorithm : cmp; import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[])) { S s1 = to!S("FoL"); S s2; s2 = capitalize(s1); assert(cmp(s2, "Fol") == 0); assert(s2 !is s1); s2 = capitalize(s1[0 .. 2]); assert(cmp(s2, "Fo") == 0); s1 = to!S("fOl"); s2 = capitalize(s1); assert(cmp(s2, "Fol") == 0); assert(s2 !is s1); s1 = to!S("\u0131 \u0130"); s2 = capitalize(s1); assert(cmp(s2, "\u0049 i\u0307") == 0); assert(s2 !is s1); s1 = to!S("\u017F \u0049"); s2 = capitalize(s1); assert(cmp(s2, "\u0053 \u0069") == 0); assert(s2 !is s1); } }); } /++ Split $(D s) into an array of lines according to the unicode standard using $(D '\r'), $(D '\n'), $(D "\r\n"), $(XREF uni, lineSep), $(XREF uni, paraSep), $(D U+0085) (NEL), $(D '\v') and $(D '\f') as delimiters. If $(D keepTerm) is set to $(D KeepTerminator.yes), then the delimiter is included in the strings returned. Does not throw on invalid UTF; such is simply passed unchanged to the output. Allocates memory; use $(LREF lineSplitter) for an alternative that does not. Adheres to $(WEB http://www.unicode.org/versions/Unicode7.0.0/ch05.pdf, Unicode 7.0). Params: s = a string of $(D chars), $(D wchars), or $(D dchars), or any custom type that casts to a $(D string) type keepTerm = whether delimiter is included or not in the results Returns: array of strings, each element is a line that is a slice of $(D s) See_Also: $(LREF lineSplitter) $(XREF algorithm, splitter) $(XREF regex, splitter) +/ alias KeepTerminator = Flag!"keepTerminator"; /// ditto S[] splitLines(S)(S s, in KeepTerminator keepTerm = KeepTerminator.no) @safe pure if (isSomeString!S) { import std.uni : lineSep, paraSep; import std.array : appender; size_t iStart = 0; auto retval = appender!(S[])(); for (size_t i; i < s.length; ++i) { switch (s[i]) { case '\v', '\f', '\n': retval.put(s[iStart .. i + (keepTerm == KeepTerminator.yes)]); iStart = i + 1; break; case '\r': if (i + 1 < s.length && s[i + 1] == '\n') { retval.put(s[iStart .. i + (keepTerm == KeepTerminator.yes) * 2]); iStart = i + 2; ++i; } else { goto case '\n'; } break; static if (s[i].sizeof == 1) { /* Manually decode: * lineSep is E2 80 A8 * paraSep is E2 80 A9 */ case 0xE2: if (i + 2 < s.length && s[i + 1] == 0x80 && (s[i + 2] == 0xA8 || s[i + 2] == 0xA9) ) { retval.put(s[iStart .. i + (keepTerm == KeepTerminator.yes) * 3]); iStart = i + 3; i += 2; } else goto default; break; /* Manually decode: * NEL is C2 85 */ case 0xC2: if(i + 1 < s.length && s[i + 1] == 0x85) { retval.put(s[iStart .. i + (keepTerm == KeepTerminator.yes) * 2]); iStart = i + 2; i += 1; } else goto default; break; } else { case lineSep: case paraSep: case '\u0085': goto case '\n'; } default: break; } } if (iStart != s.length) retval.put(s[iStart .. $]); return retval.data; } /// unittest { string s = "Hello\nmy\rname\nis"; assert(splitLines(s) == ["Hello", "my", "name", "is"]); } auto splitLines(S)(auto ref S s, in KeepTerminator keepTerm = KeepTerminator.no) if (!isSomeString!S && is(StringTypeOf!S)) { return splitLines!(StringTypeOf!S)(s, keepTerm); } unittest { assert(testAliasedString!splitLines("hello\nworld")); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.splitLines.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { auto s = to!S( "\rpeter\n\rpaul\r\njerry\u2028ice\u2029cream\n\nsunday\n" ~ "mon\u2030day\nschadenfreude\vkindergarten\f\vcookies\u0085" ); auto lines = splitLines(s); assert(lines.length == 14); assert(lines[0] == ""); assert(lines[1] == "peter"); assert(lines[2] == ""); assert(lines[3] == "paul"); assert(lines[4] == "jerry"); assert(lines[5] == "ice"); assert(lines[6] == "cream"); assert(lines[7] == ""); assert(lines[8] == "sunday"); assert(lines[9] == "mon\u2030day"); assert(lines[10] == "schadenfreude"); assert(lines[11] == "kindergarten"); assert(lines[12] == ""); assert(lines[13] == "cookies"); ubyte[] u = ['a', 0xFF, 0x12, 'b']; // invalid UTF auto ulines = splitLines(cast(char[])u); assert(cast(ubyte[])(ulines[0]) == u); lines = splitLines(s, KeepTerminator.yes); assert(lines.length == 14); assert(lines[0] == "\r"); assert(lines[1] == "peter\n"); assert(lines[2] == "\r"); assert(lines[3] == "paul\r\n"); assert(lines[4] == "jerry\u2028"); assert(lines[5] == "ice\u2029"); assert(lines[6] == "cream\n"); assert(lines[7] == "\n"); assert(lines[8] == "sunday\n"); assert(lines[9] == "mon\u2030day\n"); assert(lines[10] == "schadenfreude\v"); assert(lines[11] == "kindergarten\f"); assert(lines[12] == "\v"); assert(lines[13] == "cookies\u0085"); s.popBack(); // Lop-off trailing \n lines = splitLines(s); assert(lines.length == 14); assert(lines[9] == "mon\u2030day"); lines = splitLines(s, KeepTerminator.yes); assert(lines.length == 14); assert(lines[13] == "cookies"); } }); } private struct LineSplitter(KeepTerminator keepTerm = KeepTerminator.no, Range) { import std.uni : lineSep, paraSep; import std.conv : unsigned; private: Range _input; alias IndexType = typeof(unsigned(_input.length)); enum IndexType _unComputed = IndexType.max; IndexType iStart = _unComputed; IndexType iEnd = 0; IndexType iNext = 0; public: this(Range input) { _input = input; } static if (isInfinite!Range) { enum bool empty = false; } else { @property bool empty() { return iStart == _unComputed && iNext == _input.length; } } @property typeof(_input) front() { if (iStart == _unComputed) { iStart = iNext; Loop: for (IndexType i = iNext; ; ++i) { if (i == _input.length) { iEnd = i; iNext = i; break Loop; } switch (_input[i]) { case '\v', '\f', '\n': iEnd = i + (keepTerm == KeepTerminator.yes); iNext = i + 1; break Loop; case '\r': if (i + 1 < _input.length && _input[i + 1] == '\n') { iEnd = i + (keepTerm == KeepTerminator.yes) * 2; iNext = i + 2; break Loop; } else { goto case '\n'; } static if (_input[i].sizeof == 1) { /* Manually decode: * lineSep is E2 80 A8 * paraSep is E2 80 A9 */ case 0xE2: if (i + 2 < _input.length && _input[i + 1] == 0x80 && (_input[i + 2] == 0xA8 || _input[i + 2] == 0xA9) ) { iEnd = i + (keepTerm == KeepTerminator.yes) * 3; iNext = i + 3; break Loop; } else goto default; /* Manually decode: * NEL is C2 85 */ case 0xC2: if(i + 1 < _input.length && _input[i + 1] == 0x85) { iEnd = i + (keepTerm == KeepTerminator.yes) * 2; iNext = i + 2; break Loop; } else goto default; } else { case '\u0085': case lineSep: case paraSep: goto case '\n'; } default: break; } } } return _input[iStart .. iEnd]; } void popFront() { if (iStart == _unComputed) { assert(!empty); front; } iStart = _unComputed; } static if (isForwardRange!Range) { @property typeof(this) save() { auto ret = this; ret._input = _input.save; return ret; } } } /*********************************** * Split an array or slicable range of characters into a range of lines using $(D '\r'), $(D '\n'), $(D '\v'), $(D '\f'), $(D "\r\n"), $(XREF uni, lineSep), $(XREF uni, paraSep) and $(D '\u0085') (NEL) as delimiters. If $(D keepTerm) is set to $(D KeepTerminator.yes), then the delimiter is included in the slices returned. Does not throw on invalid UTF; such is simply passed unchanged to the output. Adheres to $(WEB http://www.unicode.org/versions/Unicode7.0.0/ch05.pdf, Unicode 7.0). Does not allocate memory. Params: r = array of $(D chars), $(D wchars), or $(D dchars) or a slicable range keepTerm = whether delimiter is included or not in the results Returns: range of slices of the input range $(D r) See_Also: $(LREF splitLines) $(XREF algorithm, splitter) $(XREF regex, splitter) */ auto lineSplitter(KeepTerminator keepTerm = KeepTerminator.no, Range)(Range r) if ((hasSlicing!Range && hasLength!Range && isSomeChar!(ElementType!Range) || isSomeString!Range) && !isConvertibleToString!Range) { return LineSplitter!(keepTerm, Range)(r); } /// @safe pure unittest { import std.array : array; string s = "Hello\nmy\rname\nis"; /* notice the call to $(D array) to turn the lazy range created by lineSplitter comparable to the $(D string[]) created by splitLines. */ assert(lineSplitter(s).array == splitLines(s)); } auto lineSplitter(KeepTerminator keepTerm = KeepTerminator.no, Range)(auto ref Range r) if (isConvertibleToString!Range) { return LineSplitter!(keepTerm, StringTypeOf!Range)(r); } @safe pure unittest { import std.conv : to; import std.array : array; debug(string) trustedPrintf("string.lineSplitter.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { auto s = to!S( "\rpeter\n\rpaul\r\njerry\u2028ice\u2029cream\n\n" ~ "sunday\nmon\u2030day\nschadenfreude\vkindergarten\f\vcookies\u0085" ); auto lines = lineSplitter(s).array; assert(lines.length == 14); assert(lines[0] == ""); assert(lines[1] == "peter"); assert(lines[2] == ""); assert(lines[3] == "paul"); assert(lines[4] == "jerry"); assert(lines[5] == "ice"); assert(lines[6] == "cream"); assert(lines[7] == ""); assert(lines[8] == "sunday"); assert(lines[9] == "mon\u2030day"); assert(lines[10] == "schadenfreude"); assert(lines[11] == "kindergarten"); assert(lines[12] == ""); assert(lines[13] == "cookies"); ubyte[] u = ['a', 0xFF, 0x12, 'b']; // invalid UTF auto ulines = lineSplitter(cast(char[])u).array; assert(cast(ubyte[])(ulines[0]) == u); lines = lineSplitter!(KeepTerminator.yes)(s).array; assert(lines.length == 14); assert(lines[0] == "\r"); assert(lines[1] == "peter\n"); assert(lines[2] == "\r"); assert(lines[3] == "paul\r\n"); assert(lines[4] == "jerry\u2028"); assert(lines[5] == "ice\u2029"); assert(lines[6] == "cream\n"); assert(lines[7] == "\n"); assert(lines[8] == "sunday\n"); assert(lines[9] == "mon\u2030day\n"); assert(lines[10] == "schadenfreude\v"); assert(lines[11] == "kindergarten\f"); assert(lines[12] == "\v"); assert(lines[13] == "cookies\u0085"); s.popBack(); // Lop-off trailing \n lines = lineSplitter(s).array; assert(lines.length == 14); assert(lines[9] == "mon\u2030day"); lines = lineSplitter!(KeepTerminator.yes)(s).array; assert(lines.length == 14); assert(lines[13] == "cookies"); } }); } /// @nogc @safe pure unittest { auto s = "\rpeter\n\rpaul\r\njerry\u2028ice\u2029cream\n\nsunday\nmon\u2030day\n"; auto lines = s.lineSplitter(); static immutable witness = ["", "peter", "", "paul", "jerry", "ice", "cream", "", "sunday", "mon\u2030day"]; uint i; foreach (line; lines) { assert(line == witness[i++]); } assert(i == witness.length); } unittest { import std.algorithm.comparison : equal; auto s = "std/string.d"; auto as = TestAliasedString(s); assert(equal(s.lineSplitter(), as.lineSplitter())); } /++ Strips leading whitespace (as defined by $(XREF uni, isWhite)). Params: input = string or ForwardRange of characters Returns: $(D input) stripped of leading whitespace. Postconditions: $(D input) and the returned value will share the same tail (see $(XREF array, sameTail)). See_Also: Generic stripping on ranges: $(REF _stripLeft, std, algorithm, mutation) +/ auto stripLeft(Range)(Range input) if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { static import std.ascii; static import std.uni; import std.utf : decodeFront; while (!input.empty) { auto c = input.front; if (std.ascii.isASCII(c)) { if (!std.ascii.isWhite(c)) break; input.popFront(); } else { auto save = input.save; auto dc = decodeFront(input); if (!std.uni.isWhite(dc)) return save; } } return input; } /// @safe pure unittest { import std.uni : lineSep, paraSep; assert(stripLeft(" hello world ") == "hello world "); assert(stripLeft("\n\t\v\rhello world\n\t\v\r") == "hello world\n\t\v\r"); assert(stripLeft("hello world") == "hello world"); assert(stripLeft([lineSep] ~ "hello world" ~ lineSep) == "hello world" ~ [lineSep]); assert(stripLeft([paraSep] ~ "hello world" ~ paraSep) == "hello world" ~ [paraSep]); import std.utf : byChar; import std.array; assert(stripLeft(" hello world "w.byChar).array == "hello world "); } auto stripLeft(Range)(auto ref Range str) if (isConvertibleToString!Range) { return stripLeft!(StringTypeOf!Range)(str); } unittest { assert(testAliasedString!stripLeft(" hello")); } /++ Strips trailing whitespace (as defined by $(XREF uni, isWhite)). Params: str = string or random access range of characters Returns: slice of $(D str) stripped of trailing whitespace. See_Also: Generic stripping on ranges: $(REF _stripRight, std, algorithm, mutation) +/ auto stripRight(Range)(Range str) if (isSomeString!Range || isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && !isConvertibleToString!Range && isSomeChar!(ElementEncodingType!Range)) { import std.uni : isWhite; alias C = Unqual!(ElementEncodingType!(typeof(str))); static if (isSomeString!(typeof(str))) { import std.utf : codeLength; foreach_reverse (i, dchar c; str) { if (!isWhite(c)) return str[0 .. i + codeLength!C(c)]; } return str[0 .. 0]; } else { size_t i = str.length; while (i--) { static if (C.sizeof == 4) { if (isWhite(str[i])) continue; break; } else static if (C.sizeof == 2) { auto c2 = str[i]; if (c2 < 0xD800 || c2 >= 0xE000) { if (isWhite(c2)) continue; } else if (c2 >= 0xDC00) { if (i) { auto c1 = str[i - 1]; if (c1 >= 0xD800 && c1 < 0xDC00) { dchar c = ((c1 - 0xD7C0) << 10) + (c2 - 0xDC00); if (isWhite(c)) { --i; continue; } } } } break; } else static if (C.sizeof == 1) { import std.utf : byDchar; char cx = str[i]; if (cx <= 0x7F) { if (isWhite(cx)) continue; break; } else { size_t stride = 0; while (1) { ++stride; if (!i || (cx & 0xC0) == 0xC0 || stride == 4) break; cx = str[i - 1]; if (!(cx & 0x80)) break; --i; } if (!str[i .. i + stride].byDchar.front.isWhite) return str[0 .. i + stride]; } } else static assert(0); } return str[0 .. i + 1]; } } /// @safe pure unittest { import std.uni : lineSep, paraSep; assert(stripRight(" hello world ") == " hello world"); assert(stripRight("\n\t\v\rhello world\n\t\v\r") == "\n\t\v\rhello world"); assert(stripRight("hello world") == "hello world"); assert(stripRight([lineSep] ~ "hello world" ~ lineSep) == [lineSep] ~ "hello world"); assert(stripRight([paraSep] ~ "hello world" ~ paraSep) == [paraSep] ~ "hello world"); } auto stripRight(Range)(auto ref Range str) if (isConvertibleToString!Range) { return stripRight!(StringTypeOf!Range)(str); } unittest { assert(testAliasedString!stripRight("hello ")); } unittest { import std.utf; import std.array; import std.uni : lineSep, paraSep; assert(stripRight(" hello world ".byChar).array == " hello world"); assert(stripRight("\n\t\v\rhello world\n\t\v\r"w.byWchar).array == "\n\t\v\rhello world"w); assert(stripRight("hello world"d.byDchar).array == "hello world"d); assert(stripRight("\u2028hello world\u2020\u2028".byChar).array == "\u2028hello world\u2020"); assert(stripRight("hello world\U00010001"w.byWchar).array == "hello world\U00010001"w); foreach (C; AliasSeq!(char, wchar, dchar)) { foreach (s; invalidUTFstrings!C()) { cast(void)stripRight(s.byUTF!C).array; } } cast(void)stripRight("a\x80".byUTF!char).array; wstring ws = ['a', cast(wchar)0xDC00]; cast(void)stripRight(ws.byUTF!wchar).array; } /++ Strips both leading and trailing whitespace (as defined by $(XREF uni, isWhite)). Params: str = string or random access range of characters Returns: slice of $(D str) stripped of leading and trailing whitespace. See_Also: Generic stripping on ranges: $(REF _strip, std, algorithm, mutation) +/ auto strip(Range)(Range str) if (isSomeString!Range || isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && !isConvertibleToString!Range && isSomeChar!(ElementEncodingType!Range)) { return stripRight(stripLeft(str)); } /// @safe pure unittest { import std.uni : lineSep, paraSep; assert(strip(" hello world ") == "hello world"); assert(strip("\n\t\v\rhello world\n\t\v\r") == "hello world"); assert(strip("hello world") == "hello world"); assert(strip([lineSep] ~ "hello world" ~ [lineSep]) == "hello world"); assert(strip([paraSep] ~ "hello world" ~ [paraSep]) == "hello world"); } auto strip(Range)(auto ref Range str) if (isConvertibleToString!Range) { return strip!(StringTypeOf!Range)(str); } @safe pure unittest { assert(testAliasedString!strip(" hello world ")); } @safe pure unittest { import std.conv : to; import std.algorithm : equal; debug(string) trustedPrintf("string.strip.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!( char[], const char[], string, wchar[], const wchar[], wstring, dchar[], const dchar[], dstring)) { assert(equal(stripLeft(to!S(" foo\t ")), "foo\t ")); assert(equal(stripLeft(to!S("\u2008 foo\t \u2007")), "foo\t \u2007")); assert(equal(stripLeft(to!S("\u0085 μ \u0085 \u00BB \r")), "μ \u0085 \u00BB \r")); assert(equal(stripLeft(to!S("1")), "1")); assert(equal(stripLeft(to!S("\U0010FFFE")), "\U0010FFFE")); assert(equal(stripLeft(to!S("")), "")); assert(equal(stripRight(to!S(" foo\t ")), " foo")); assert(equal(stripRight(to!S("\u2008 foo\t \u2007")), "\u2008 foo")); assert(equal(stripRight(to!S("\u0085 μ \u0085 \u00BB \r")), "\u0085 μ \u0085 \u00BB")); assert(equal(stripRight(to!S("1")), "1")); assert(equal(stripRight(to!S("\U0010FFFE")), "\U0010FFFE")); assert(equal(stripRight(to!S("")), "")); assert(equal(strip(to!S(" foo\t ")), "foo")); assert(equal(strip(to!S("\u2008 foo\t \u2007")), "foo")); assert(equal(strip(to!S("\u0085 μ \u0085 \u00BB \r")), "μ \u0085 \u00BB")); assert(equal(strip(to!S("\U0010FFFE")), "\U0010FFFE")); assert(equal(strip(to!S("")), "")); } }); } @safe pure unittest { import std.exception; import std.range; assertCTFEable!( { wstring s = " "; assert(s.sameTail(s.stripLeft())); assert(s.sameHead(s.stripRight())); }); } /++ If $(D str) ends with $(D delimiter), then $(D str) is returned without $(D delimiter) on its end. If it $(D str) does $(I not) end with $(D delimiter), then it is returned unchanged. If no $(D delimiter) is given, then one trailing $(D '\r'), $(D '\n'), $(D "\r\n"), $(D '\f'), $(D '\v'), $(XREF uni, lineSep), $(XREF uni, paraSep), or $(XREF uni, nelSep) is removed from the end of $(D str). If $(D str) does not end with any of those characters, then it is returned unchanged. Params: str = string or indexable range of characters delimiter = string of characters to be sliced off end of str[] Returns: slice of str +/ Range chomp(Range)(Range str) if ((isRandomAccessRange!Range && isSomeChar!(ElementEncodingType!Range) || isNarrowString!Range) && !isConvertibleToString!Range) { import std.uni : lineSep, paraSep, nelSep; if (str.empty) return str; alias C = ElementEncodingType!Range; switch (str[$ - 1]) { case '\n': { if (str.length > 1 && str[$ - 2] == '\r') return str[0 .. $ - 2]; goto case; } case '\r', '\v', '\f': return str[0 .. $ - 1]; // Pop off the last character if lineSep, paraSep, or nelSep static if (is(C : const char)) { /* Manually decode: * lineSep is E2 80 A8 * paraSep is E2 80 A9 */ case 0xA8: // Last byte of lineSep case 0xA9: // Last byte of paraSep if (str.length > 2 && str[$ - 2] == 0x80 && str[$ - 3] == 0xE2) return str [0 .. $ - 3]; goto default; /* Manually decode: * NEL is C2 85 */ case 0x85: if (str.length > 1 && str[$ - 2] == 0xC2) return str [0 .. $ - 2]; goto default; } else { case lineSep: case paraSep: case nelSep: return str[0 .. $ - 1]; } default: return str; } } /// Ditto Range chomp(Range, C2)(Range str, const(C2)[] delimiter) if ((isBidirectionalRange!Range && isSomeChar!(ElementEncodingType!Range) || isNarrowString!Range) && !isConvertibleToString!Range && isSomeChar!C2) { if (delimiter.empty) return chomp(str); alias C1 = ElementEncodingType!Range; static if (is(Unqual!C1 == Unqual!C2) && (isSomeString!Range || (hasSlicing!Range && C2.sizeof == 4))) { import std.algorithm : endsWith; if (str.endsWith(delimiter)) return str[0 .. $ - delimiter.length]; return str; } else { auto orig = str.save; static if (isSomeString!Range) alias C = dchar; // because strings auto-decode else alias C = C1; // and ranges do not foreach_reverse (C c; delimiter) { if (str.empty || str.back != c) return orig; str.popBack(); } return str; } } /// @safe pure unittest { import std.utf : decode; import std.uni : lineSep, paraSep, nelSep; assert(chomp(" hello world \n\r") == " hello world \n"); assert(chomp(" hello world \r\n") == " hello world "); assert(chomp(" hello world \f") == " hello world "); assert(chomp(" hello world \v") == " hello world "); assert(chomp(" hello world \n\n") == " hello world \n"); assert(chomp(" hello world \n\n ") == " hello world \n\n "); assert(chomp(" hello world \n\n" ~ [lineSep]) == " hello world \n\n"); assert(chomp(" hello world \n\n" ~ [paraSep]) == " hello world \n\n"); assert(chomp(" hello world \n\n" ~ [ nelSep]) == " hello world \n\n"); assert(chomp(" hello world") == " hello world"); assert(chomp("") == ""); assert(chomp(" hello world", "orld") == " hello w"); assert(chomp(" hello world", " he") == " hello world"); assert(chomp("", "hello") == ""); // Don't decode pointlessly assert(chomp("hello\xFE", "\r") == "hello\xFE"); } StringTypeOf!Range chomp(Range)(auto ref Range str) if (isConvertibleToString!Range) { return chomp!(StringTypeOf!Range)(str); } StringTypeOf!Range chomp(Range, C2)(auto ref Range str, const(C2)[] delimiter) if (isConvertibleToString!Range) { return chomp!(StringTypeOf!Range, C2)(str, delimiter); } unittest { assert(testAliasedString!chomp(" hello world \n\r")); assert(testAliasedString!chomp(" hello world", "orld")); } unittest { import std.conv : to; debug(string) trustedPrintf("string.chomp.unittest\n"); string s; import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { // @@@ BUG IN COMPILER, MUST INSERT CAST assert(chomp(cast(S)null) is null); assert(chomp(to!S("hello")) == "hello"); assert(chomp(to!S("hello\n")) == "hello"); assert(chomp(to!S("hello\r")) == "hello"); assert(chomp(to!S("hello\r\n")) == "hello"); assert(chomp(to!S("hello\n\r")) == "hello\n"); assert(chomp(to!S("hello\n\n")) == "hello\n"); assert(chomp(to!S("hello\r\r")) == "hello\r"); assert(chomp(to!S("hello\nxxx\n")) == "hello\nxxx"); assert(chomp(to!S("hello\u2028")) == "hello"); assert(chomp(to!S("hello\u2029")) == "hello"); assert(chomp(to!S("hello\u0085")) == "hello"); assert(chomp(to!S("hello\u2028\u2028")) == "hello\u2028"); assert(chomp(to!S("hello\u2029\u2029")) == "hello\u2029"); assert(chomp(to!S("hello\u2029\u2129")) == "hello\u2029\u2129"); assert(chomp(to!S("hello\u2029\u0185")) == "hello\u2029\u0185"); foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 // @@@ BUG IN COMPILER, MUST INSERT CAST assert(chomp(cast(S)null, cast(T)null) is null); assert(chomp(to!S("hello\n"), cast(T)null) == "hello"); assert(chomp(to!S("hello"), to!T("o")) == "hell"); assert(chomp(to!S("hello"), to!T("p")) == "hello"); // @@@ BUG IN COMPILER, MUST INSERT CAST assert(chomp(to!S("hello"), cast(T) null) == "hello"); assert(chomp(to!S("hello"), to!T("llo")) == "he"); assert(chomp(to!S("\uFF28ello"), to!T("llo")) == "\uFF28e"); assert(chomp(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co")) == "\uFF28e"); }(); } }); // Ranges import std.utf : byChar, byWchar, byDchar; import std.array; assert(chomp("hello world\r\n" .byChar ).array == "hello world"); assert(chomp("hello world\r\n"w.byWchar).array == "hello world"w); assert(chomp("hello world\r\n"d.byDchar).array == "hello world"d); assert(chomp("hello world"d.byDchar, "ld").array == "hello wor"d); assert(chomp("hello\u2020" .byChar , "\u2020").array == "hello"); assert(chomp("hello\u2020"d.byDchar, "\u2020"d).array == "hello"d); } /++ If $(D str) starts with $(D delimiter), then the part of $(D str) following $(D delimiter) is returned. If $(D str) does $(I not) start with $(D delimiter), then it is returned unchanged. Params: str = string or forward range of characters delimiter = string of characters to be sliced off front of str[] Returns: slice of str +/ Range chompPrefix(Range, C2)(Range str, const(C2)[] delimiter) if ((isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) || isNarrowString!Range) && !isConvertibleToString!Range && isSomeChar!C2) { alias C1 = ElementEncodingType!Range; static if (is(Unqual!C1 == Unqual!C2) && (isSomeString!Range || (hasSlicing!Range && C2.sizeof == 4))) { import std.algorithm : startsWith; if (str.startsWith(delimiter)) return str[delimiter.length .. $]; return str; } else { auto orig = str.save; static if (isSomeString!Range) alias C = dchar; // because strings auto-decode else alias C = C1; // and ranges do not foreach (C c; delimiter) { if (str.empty || str.front != c) return orig; str.popFront(); } return str; } } /// @safe pure unittest { assert(chompPrefix("hello world", "he") == "llo world"); assert(chompPrefix("hello world", "hello w") == "orld"); assert(chompPrefix("hello world", " world") == "hello world"); assert(chompPrefix("", "hello") == ""); } StringTypeOf!Range chompPrefix(Range, C2)(auto ref Range str, const(C2)[] delimiter) if (isConvertibleToString!Range) { return chompPrefix!(StringTypeOf!Range, C2)(str, delimiter); } @safe pure unittest { import std.conv : to; import std.algorithm : equal; import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(equal(chompPrefix(to!S("abcdefgh"), to!T("abcde")), "fgh")); assert(equal(chompPrefix(to!S("abcde"), to!T("abcdefgh")), "abcde")); assert(equal(chompPrefix(to!S("\uFF28el\uFF4co"), to!T("\uFF28el\uFF4co")), "")); assert(equal(chompPrefix(to!S("\uFF28el\uFF4co"), to!T("\uFF28el")), "\uFF4co")); assert(equal(chompPrefix(to!S("\uFF28el"), to!T("\uFF28el\uFF4co")), "\uFF28el")); }(); } }); // Ranges import std.utf : byChar, byWchar, byDchar; import std.array; assert(chompPrefix("hello world" .byChar , "hello"d).array == " world"); assert(chompPrefix("hello world"w.byWchar, "hello" ).array == " world"w); assert(chompPrefix("hello world"d.byDchar, "hello"w).array == " world"d); assert(chompPrefix("hello world"c.byDchar, "hello"w).array == " world"d); assert(chompPrefix("hello world"d.byDchar, "lx").array == "hello world"d); assert(chompPrefix("hello world"d.byDchar, "hello world xx").array == "hello world"d); assert(chompPrefix("\u2020world" .byChar , "\u2020").array == "world"); assert(chompPrefix("\u2020world"d.byDchar, "\u2020"d).array == "world"d); } unittest { assert(testAliasedString!chompPrefix("hello world", "hello")); } /++ Returns $(D str) without its last character, if there is one. If $(D str) ends with $(D "\r\n"), then both are removed. If $(D str) is empty, then then it is returned unchanged. Params: str = string (must be valid UTF) Returns: slice of str +/ Range chop(Range)(Range str) if ((isBidirectionalRange!Range && isSomeChar!(ElementEncodingType!Range) || isNarrowString!Range) && !isConvertibleToString!Range) { if (str.empty) return str; static if (isSomeString!Range) { if (str.length >= 2 && str[$ - 1] == '\n' && str[$ - 2] == '\r') return str[0 .. $ - 2]; str.popBack(); return str; } else { alias C = Unqual!(ElementEncodingType!Range); C c = str.back; str.popBack(); if (c == '\n') { if (!str.empty && str.back == '\r') str.popBack(); return str; } // Pop back a dchar, not just a code unit static if (C.sizeof == 1) { int cnt = 1; while ((c & 0xC0) == 0x80) { if (str.empty) break; c = str.back; str.popBack(); if (++cnt > 4) break; } } else static if (C.sizeof == 2) { if (c >= 0xD800 && c <= 0xDBFF) { if (!str.empty) str.popBack(); } } else static if (C.sizeof == 4) { } else static assert(0); return str; } } /// @safe pure unittest { assert(chop("hello world") == "hello worl"); assert(chop("hello world\n") == "hello world"); assert(chop("hello world\r") == "hello world"); assert(chop("hello world\n\r") == "hello world\n"); assert(chop("hello world\r\n") == "hello world"); assert(chop("Walter Bright") == "Walter Brigh"); assert(chop("") == ""); } StringTypeOf!Range chop(Range)(auto ref Range str) if (isConvertibleToString!Range) { return chop!(StringTypeOf!Range)(str); } unittest { assert(testAliasedString!chop("hello world")); } @safe pure unittest { import std.utf : byChar, byWchar, byDchar, byCodeUnit, invalidUTFstrings; import std.array; assert(chop("hello world".byChar).array == "hello worl"); assert(chop("hello world\n"w.byWchar).array == "hello world"w); assert(chop("hello world\r"d.byDchar).array == "hello world"d); assert(chop("hello world\n\r".byChar).array == "hello world\n"); assert(chop("hello world\r\n"w.byWchar).array == "hello world"w); assert(chop("Walter Bright"d.byDchar).array == "Walter Brigh"d); assert(chop("".byChar).array == ""); assert(chop(`ミツバチと科学者` .byCodeUnit).array == "ミツバチと科学"); assert(chop(`ミツバチと科学者`w.byCodeUnit).array == "ミツバチと科学"w); assert(chop(`ミツバチと科学者`d.byCodeUnit).array == "ミツバチと科学"d); auto ca = invalidUTFstrings!char(); foreach (s; ca) { foreach (c; chop(s.byCodeUnit)) { } } auto wa = invalidUTFstrings!wchar(); foreach (s; wa) { foreach (c; chop(s.byCodeUnit)) { } } } unittest { import std.conv : to; import std.algorithm : equal; debug(string) trustedPrintf("string.chop.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { assert(chop(cast(S) null) is null); assert(equal(chop(to!S("hello")), "hell")); assert(equal(chop(to!S("hello\r\n")), "hello")); assert(equal(chop(to!S("hello\n\r")), "hello\n")); assert(equal(chop(to!S("Verité")), "Verit")); assert(equal(chop(to!S(`さいごの果実`)), "さいごの果")); assert(equal(chop(to!S(`ミツバチと科学者`)), "ミツバチと科学")); } }); } /++ Left justify $(D s) in a field $(D width) characters wide. $(D fillChar) is the character that will be used to fill up the space in the field that $(D s) doesn't fill. Params: s = string width = minimum field width fillChar = used to pad end up to $(D width) characters Returns: GC allocated string See_Also: $(LREF leftJustifier), which does not allocate +/ S leftJustify(S)(S s, size_t width, dchar fillChar = ' ') if (isSomeString!S) { import std.array; return leftJustifier(s, width, fillChar).array; } /// @safe pure unittest { assert(leftJustify("hello", 7, 'X') == "helloXX"); assert(leftJustify("hello", 2, 'X') == "hello"); assert(leftJustify("hello", 9, 'X') == "helloXXXX"); } /++ Left justify $(D s) in a field $(D width) characters wide. $(D fillChar) is the character that will be used to fill up the space in the field that $(D s) doesn't fill. Params: r = string or range of characters width = minimum field width fillChar = used to pad end up to $(D width) characters Returns: a lazy range of the left justified result See_Also: $(LREF rightJustifier) +/ auto leftJustifier(Range)(Range r, size_t width, dchar fillChar = ' ') if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { alias C = Unqual!(ElementEncodingType!Range); static if (C.sizeof == 1) { import std.utf : byDchar, byChar; return leftJustifier(r.byDchar, width, fillChar).byChar; } else static if (C.sizeof == 2) { import std.utf : byDchar, byWchar; return leftJustifier(r.byDchar, width, fillChar).byWchar; } else static if (C.sizeof == 4) { static struct Result { private: Range _input; size_t _width; dchar _fillChar; size_t len; public: this(Range input, size_t width, dchar fillChar) { _input = input; _width = width; _fillChar = fillChar; } @property bool empty() { return len >= _width && _input.empty; } @property C front() { return _input.empty ? _fillChar : _input.front; } void popFront() { ++len; if (!_input.empty) _input.popFront(); } static if (isForwardRange!Range) { @property typeof(this) save() { auto ret = this; ret._input = _input.save; return ret; } } } return Result(r, width, fillChar); } else static assert(0); } /// @safe pure @nogc nothrow unittest { import std.algorithm : equal; import std.utf : byChar; assert(leftJustifier("hello", 2).equal("hello".byChar)); assert(leftJustifier("hello", 7).equal("hello ".byChar)); assert(leftJustifier("hello", 7, 'x').equal("helloxx".byChar)); } auto leftJustifier(Range)(auto ref Range r, size_t width, dchar fillChar = ' ') if (isConvertibleToString!Range) { return leftJustifier!(StringTypeOf!Range)(r, width, fillChar); } unittest { auto r = "hello".leftJustifier(8); r.popFront(); auto save = r.save; r.popFront(); assert(r.front == 'l'); assert(save.front == 'e'); } unittest { assert(testAliasedString!leftJustifier("hello", 2)); } /++ Right justify $(D s) in a field $(D width) characters wide. $(D fillChar) is the character that will be used to fill up the space in the field that $(D s) doesn't fill. Params: s = string width = minimum field width fillChar = used to pad end up to $(D width) characters Returns: GC allocated string See_Also: $(LREF rightJustifier), which does not allocate +/ S rightJustify(S)(S s, size_t width, dchar fillChar = ' ') if (isSomeString!S) { import std.array; return rightJustifier(s, width, fillChar).array; } /// @safe pure unittest { assert(rightJustify("hello", 7, 'X') == "XXhello"); assert(rightJustify("hello", 2, 'X') == "hello"); assert(rightJustify("hello", 9, 'X') == "XXXXhello"); } /++ Right justify $(D s) in a field $(D width) characters wide. $(D fillChar) is the character that will be used to fill up the space in the field that $(D s) doesn't fill. Params: r = string or forward range of characters width = minimum field width fillChar = used to pad end up to $(D width) characters Returns: a lazy range of the right justified result See_Also: $(LREF leftJustifier) +/ auto rightJustifier(Range)(Range r, size_t width, dchar fillChar = ' ') if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { alias C = Unqual!(ElementEncodingType!Range); static if (C.sizeof == 1) { import std.utf : byDchar, byChar; return rightJustifier(r.byDchar, width, fillChar).byChar; } else static if (C.sizeof == 2) { import std.utf : byDchar, byWchar; return rightJustifier(r.byDchar, width, fillChar).byWchar; } else static if (C.sizeof == 4) { static struct Result { private: Range _input; size_t _width; alias nfill = _width; // number of fill characters to prepend dchar _fillChar; bool inited; // Lazy initialization so constructor is trivial and cannot fail void initialize() { // Replace _width with nfill // (use alias instead of union because CTFE cannot deal with unions) assert(_width); static if (hasLength!Range) { auto len = _input.length; nfill = (_width > len) ? _width - len : 0; } else { // Lookahead to see now many fill characters are needed import std.range : walkLength, take; nfill = _width - walkLength(_input.save.take(_width), _width); } inited = true; } public: this(Range input, size_t width, dchar fillChar) pure nothrow { _input = input; _fillChar = fillChar; _width = width; } @property bool empty() { return !nfill && _input.empty; } @property C front() { if (!nfill) return _input.front; // fast path if (!inited) initialize(); return nfill ? _fillChar : _input.front; } void popFront() { if (!nfill) _input.popFront(); // fast path else { if (!inited) initialize(); if (nfill) --nfill; else _input.popFront(); } } @property typeof(this) save() { auto ret = this; ret._input = _input.save; return ret; } } return Result(r, width, fillChar); } else static assert(0); } /// @safe pure @nogc nothrow unittest { import std.algorithm : equal; import std.utf : byChar; assert(rightJustifier("hello", 2).equal("hello".byChar)); assert(rightJustifier("hello", 7).equal(" hello".byChar)); assert(rightJustifier("hello", 7, 'x').equal("xxhello".byChar)); } auto rightJustifier(Range)(auto ref Range r, size_t width, dchar fillChar = ' ') if (isConvertibleToString!Range) { return rightJustifier!(StringTypeOf!Range)(r, width, fillChar); } unittest { assert(testAliasedString!rightJustifier("hello", 2)); } unittest { auto r = "hello"d.rightJustifier(6); r.popFront(); auto save = r.save; r.popFront(); assert(r.front == 'e'); assert(save.front == 'h'); auto t = "hello".rightJustifier(7); t.popFront(); assert(t.front == ' '); t.popFront(); assert(t.front == 'h'); auto u = "hello"d.rightJustifier(5); u.popFront(); u.popFront(); u.popFront(); } /++ Center $(D s) in a field $(D width) characters wide. $(D fillChar) is the character that will be used to fill up the space in the field that $(D s) doesn't fill. Params: s = The string to center width = Width of the field to center `s` in fillChar = The character to use for filling excess space in the field Returns: The resulting _center-justified string. The returned string is GC-allocated. To avoid GC allocation, use $(LREF centerJustifier) instead. +/ S center(S)(S s, size_t width, dchar fillChar = ' ') if (isSomeString!S) { import std.array; return centerJustifier(s, width, fillChar).array; } /// @safe pure unittest { assert(center("hello", 7, 'X') == "XhelloX"); assert(center("hello", 2, 'X') == "hello"); assert(center("hello", 9, 'X') == "XXhelloXX"); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.justify.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { S s = to!S("hello"); assert(leftJustify(s, 2) == "hello"); assert(rightJustify(s, 2) == "hello"); assert(center(s, 2) == "hello"); assert(leftJustify(s, 7) == "hello "); assert(rightJustify(s, 7) == " hello"); assert(center(s, 7) == " hello "); assert(leftJustify(s, 8) == "hello "); assert(rightJustify(s, 8) == " hello"); assert(center(s, 8) == " hello "); assert(leftJustify(s, 8, '\u0100') == "hello\u0100\u0100\u0100"); assert(rightJustify(s, 8, '\u0100') == "\u0100\u0100\u0100hello"); assert(center(s, 8, '\u0100') == "\u0100hello\u0100\u0100"); assert(leftJustify(s, 8, 'ö') == "helloööö"); assert(rightJustify(s, 8, 'ö') == "öööhello"); assert(center(s, 8, 'ö') == "öhelloöö"); } }); } /++ Center justify $(D r) in a field $(D width) characters wide. $(D fillChar) is the character that will be used to fill up the space in the field that $(D r) doesn't fill. Params: r = string or forward range of characters width = minimum field width fillChar = used to pad end up to $(D width) characters Returns: a lazy range of the center justified result See_Also: $(LREF leftJustifier) $(LREF rightJustifier) +/ auto centerJustifier(Range)(Range r, size_t width, dchar fillChar = ' ') if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { alias C = Unqual!(ElementEncodingType!Range); static if (C.sizeof == 1) { import std.utf : byDchar, byChar; return centerJustifier(r.byDchar, width, fillChar).byChar; } else static if (C.sizeof == 2) { import std.utf : byDchar, byWchar; return centerJustifier(r.byDchar, width, fillChar).byWchar; } else static if (C.sizeof == 4) { import std.range : chain, repeat, walkLength; auto len = walkLength(r.save, width); if (len > width) len = width; const nleft = (width - len) / 2; const nright = width - len - nleft; return chain(repeat(fillChar, nleft), r, repeat(fillChar, nright)); } else static assert(0); } /// @safe pure @nogc nothrow unittest { import std.algorithm : equal; import std.utf : byChar; assert(centerJustifier("hello", 2).equal("hello".byChar)); assert(centerJustifier("hello", 8).equal(" hello ".byChar)); assert(centerJustifier("hello", 7, 'x').equal("xhellox".byChar)); } auto centerJustifier(Range)(auto ref Range r, size_t width, dchar fillChar = ' ') if (isConvertibleToString!Range) { return centerJustifier!(StringTypeOf!Range)(r, width, fillChar); } unittest { assert(testAliasedString!centerJustifier("hello", 8)); } unittest { static auto byFwdRange(dstring s) { static struct FRange { dstring str; this(dstring s) { str = s; } @property bool empty() { return str.length == 0; } @property dchar front() { return str[0]; } void popFront() { str = str[1 .. $]; } @property FRange save() { return this; } } return FRange(s); } auto r = centerJustifier(byFwdRange("hello"d), 6); r.popFront(); auto save = r.save; r.popFront(); assert(r.front == 'l'); assert(save.front == 'e'); auto t = "hello".centerJustifier(7); t.popFront(); assert(t.front == 'h'); t.popFront(); assert(t.front == 'e'); auto u = byFwdRange("hello"d).centerJustifier(6); u.popFront(); u.popFront(); u.popFront(); u.popFront(); u.popFront(); u.popFront(); } /++ Replace each tab character in $(D s) with the number of spaces necessary to align the following character at the next tab stop. Params: s = string tabSize = distance between tab stops Returns: GC allocated string with tabs replaced with spaces +/ auto detab(Range)(auto ref Range s, size_t tabSize = 8) pure if ((isForwardRange!Range && isSomeChar!(ElementEncodingType!Range)) || __traits(compiles, StringTypeOf!Range)) { import std.array; return detabber(s, tabSize).array; } /// @trusted pure unittest { import std.array; assert(detab(" \n\tx", 9) == " \n x"); } unittest { static struct TestStruct { string s; alias s this; } static struct TestStruct2 { string s; alias s this; @disable this(this); } string s = " \n\tx"; string cmp = " \n x"; auto t = TestStruct(s); assert(detab(t, 9) == cmp); assert(detab(TestStruct(s), 9) == cmp); assert(detab(TestStruct(s), 9) == detab(TestStruct(s), 9)); assert(detab(TestStruct2(s), 9) == detab(TestStruct2(s), 9)); assert(detab(TestStruct2(s), 9) == cmp); } /++ Replace each tab character in $(D r) with the number of spaces necessary to align the following character at the next tab stop. Params: r = string or forward range tabSize = distance between tab stops Returns: lazy forward range with tabs replaced with spaces +/ auto detabber(Range)(Range r, size_t tabSize = 8) if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { import std.uni : lineSep, paraSep, nelSep; import std.utf : codeUnitLimit, decodeFront; assert(tabSize > 0); alias C = Unqual!(ElementEncodingType!(Range)); static struct Result { private: Range _input; size_t _tabSize; size_t nspaces; int column; size_t index; public: this(Range input, size_t tabSize) { _input = input; _tabSize = tabSize; } static if (isInfinite!(Range)) { enum bool empty = false; } else { @property bool empty() { return _input.empty && nspaces == 0; } } @property C front() { if (nspaces) return ' '; static if (isSomeString!(Range)) C c = _input[0]; else C c = _input.front; if (index) return c; dchar dc; if (c < codeUnitLimit!(immutable(C)[])) { dc = c; index = 1; } else { auto r = _input.save; dc = decodeFront(r, index); // lookahead to decode } switch (dc) { case '\r': case '\n': case paraSep: case lineSep: case nelSep: column = 0; break; case '\t': nspaces = _tabSize - (column % _tabSize); column += nspaces; c = ' '; break; default: ++column; break; } return c; } void popFront() { if (!index) front; if (nspaces) --nspaces; if (!nspaces) { static if (isSomeString!(Range)) _input = _input[1 .. $]; else _input.popFront(); --index; } } @property typeof(this) save() { auto ret = this; ret._input = _input.save; return ret; } } return Result(r, tabSize); } /// @trusted pure unittest { import std.array; assert(detabber(" \n\tx", 9).array == " \n x"); } auto detabber(Range)(auto ref Range r, size_t tabSize = 8) if (isConvertibleToString!Range) { return detabber!(StringTypeOf!Range)(r, tabSize); } unittest { assert(testAliasedString!detabber( " ab\t asdf ", 8)); } @trusted pure unittest { import std.conv : to; import std.algorithm : cmp; debug(string) trustedPrintf("string.detab.unittest\n"); import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring)) { S s = to!S("This \tis\t a fofof\tof list"); assert(cmp(detab(s), "This is a fofof of list") == 0); assert(detab(cast(S)null) is null); assert(detab("").empty); assert(detab("a") == "a"); assert(detab("\t") == " "); assert(detab("\t", 3) == " "); assert(detab("\t", 9) == " "); assert(detab( " ab\t asdf ") == " ab asdf "); assert(detab( " \U00010000b\tasdf ") == " \U00010000b asdf "); assert(detab("\r\t", 9) == "\r "); assert(detab("\n\t", 9) == "\n "); assert(detab("\u0085\t", 9) == "\u0085 "); assert(detab("\u2028\t", 9) == "\u2028 "); assert(detab(" \u2029\t", 9) == " \u2029 "); } }); } /// @trusted pure unittest { import std.utf; import std.array; assert(detabber(" \u2029\t".byChar, 9).array == " \u2029 "); auto r = "hel\tx".byWchar.detabber(); assert(r.front == 'h' && r.front == 'h'); auto s = r.save; r.popFront(); r.popFront(); assert(r.front == 'l'); assert(s.front == 'h'); } /++ Replaces spaces in $(D s) with the optimal number of tabs. All spaces and tabs at the end of a line are removed. Params: s = String to convert. tabSize = Tab columns are $(D tabSize) spaces apart. Returns: GC allocated string with spaces replaced with tabs; use $(LREF entabber) to not allocate. See_Also: $(LREF entabber) +/ auto entab(Range)(Range s, size_t tabSize = 8) if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range)) { import std.array : array; return entabber(s, tabSize).array; } /// unittest { assert(entab(" x \n") == "\tx\n"); } auto entab(Range)(auto ref Range s, size_t tabSize = 8) if (!(isForwardRange!Range && isSomeChar!(ElementEncodingType!Range)) && is(StringTypeOf!Range)) { return entab!(StringTypeOf!Range)(s, tabSize); } unittest { assert(testAliasedString!entab(" x \n")); } /++ Replaces spaces in range $(D r) with the optimal number of tabs. All spaces and tabs at the end of a line are removed. Params: r = string or forward range tabSize = distance between tab stops Returns: lazy forward range with spaces replaced with tabs See_Also: $(LREF entab) +/ auto entabber(Range)(Range r, size_t tabSize = 8) if (isForwardRange!Range && !isConvertibleToString!Range) { import std.uni : lineSep, paraSep, nelSep; import std.utf : codeUnitLimit, decodeFront; assert(tabSize > 0); alias C = Unqual!(ElementEncodingType!Range); static struct Result { private: Range _input; size_t _tabSize; size_t nspaces; size_t ntabs; int column; size_t index; @property C getFront() { static if (isSomeString!Range) return _input[0]; // avoid autodecode else return _input.front; } public: this(Range input, size_t tabSize) { _input = input; _tabSize = tabSize; } @property bool empty() { if (ntabs || nspaces) return false; /* Since trailing spaces are removed, * look ahead for anything that is not a trailing space */ static if (isSomeString!Range) { foreach (c; _input) { if (c != ' ' && c != '\t') return false; } return true; } else { if (_input.empty) return true; C c = _input.front; if (c != ' ' && c != '\t') return false; auto t = _input.save; t.popFront(); foreach (c2; t) { if (c2 != ' ' && c2 != '\t') return false; } return true; } } @property C front() { //writefln(" front(): ntabs = %s nspaces = %s index = %s front = '%s'", ntabs, nspaces, index, getFront); if (ntabs) return '\t'; if (nspaces) return ' '; C c = getFront; if (index) return c; dchar dc; if (c < codeUnitLimit!(immutable(C)[])) { index = 1; dc = c; if (c == ' ' || c == '\t') { // Consume input until a non-blank is encountered size_t startcol = column; C cx; static if (isSomeString!Range) { while (1) { assert(_input.length); cx = _input[0]; if (cx == ' ') ++column; else if (cx == '\t') column += _tabSize - (column % _tabSize); else break; _input = _input[1 .. $]; } } else { while (1) { assert(!_input.empty); cx = _input.front; if (cx == ' ') ++column; else if (cx == '\t') column += _tabSize - (column % _tabSize); else break; _input.popFront(); } } // Compute ntabs+nspaces to get from startcol to column auto n = column - startcol; if (n == 1) { nspaces = 1; } else { ntabs = column / _tabSize - startcol / _tabSize; if (ntabs == 0) nspaces = column - startcol; else nspaces = column % _tabSize; } //writefln("\tstartcol = %s, column = %s, _tabSize = %s", startcol, column, _tabSize); //writefln("\tntabs = %s, nspaces = %s", ntabs, nspaces); if (cx < codeUnitLimit!(immutable(C)[])) { dc = cx; index = 1; } else { auto r = _input.save; dc = decodeFront(r, index); // lookahead to decode } switch (dc) { case '\r': case '\n': case paraSep: case lineSep: case nelSep: column = 0; // Spaces followed by newline are ignored ntabs = 0; nspaces = 0; return cx; default: ++column; break; } return ntabs ? '\t' : ' '; } } else { auto r = _input.save; dc = decodeFront(r, index); // lookahead to decode } //writefln("dc = x%x", dc); switch (dc) { case '\r': case '\n': case paraSep: case lineSep: case nelSep: column = 0; break; default: ++column; break; } return c; } void popFront() { //writefln("popFront(): ntabs = %s nspaces = %s index = %s front = '%s'", ntabs, nspaces, index, getFront); if (!index) front; if (ntabs) --ntabs; else if (nspaces) --nspaces; else if (!ntabs && !nspaces) { static if (isSomeString!Range) _input = _input[1 .. $]; else _input.popFront(); --index; } } @property typeof(this) save() { auto ret = this; ret._input = _input.save; return ret; } } return Result(r, tabSize); } /// unittest { import std.array; assert(entabber(" x \n").array == "\tx\n"); } auto entabber(Range)(auto ref Range r, size_t tabSize = 8) if (isConvertibleToString!Range) { return entabber!(StringTypeOf!Range)(r, tabSize); } unittest { assert(testAliasedString!entabber(" ab asdf ", 8)); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.entab.unittest\n"); import std.exception; assertCTFEable!( { assert(entab(cast(string) null) is null); assert(entab("").empty); assert(entab("a") == "a"); assert(entab(" ") == ""); assert(entab(" x") == "\tx"); assert(entab(" ab asdf ") == " ab\tasdf"); assert(entab(" ab asdf ") == " ab\t asdf"); assert(entab(" ab \t asdf ") == " ab\t asdf"); assert(entab("1234567 \ta") == "1234567\t\ta"); assert(entab("1234567 \ta") == "1234567\t\ta"); assert(entab("1234567 \ta") == "1234567\t\ta"); assert(entab("1234567 \ta") == "1234567\t\ta"); assert(entab("1234567 \ta") == "1234567\t\ta"); assert(entab("1234567 \ta") == "1234567\t\ta"); assert(entab("1234567 \ta") == "1234567\t\ta"); assert(entab("1234567 \ta") == "1234567\t\ta"); assert(entab("1234567 \ta") == "1234567\t\t\ta"); assert(entab("a ") == "a"); assert(entab("a\v") == "a\v"); assert(entab("a\f") == "a\f"); assert(entab("a\n") == "a\n"); assert(entab("a\n\r") == "a\n\r"); assert(entab("a\r\n") == "a\r\n"); assert(entab("a\u2028") == "a\u2028"); assert(entab("a\u2029") == "a\u2029"); assert(entab("a\u0085") == "a\u0085"); assert(entab("a ") == "a"); assert(entab("a\t") == "a"); assert(entab("\uFF28\uFF45\uFF4C\uFF4C567 \t\uFF4F \t") == "\uFF28\uFF45\uFF4C\uFF4C567\t\t\uFF4F"); assert(entab(" \naa") == "\naa"); assert(entab(" \r aa") == "\r aa"); assert(entab(" \u2028 aa") == "\u2028 aa"); assert(entab(" \u2029 aa") == "\u2029 aa"); assert(entab(" \u0085 aa") == "\u0085 aa"); }); } @safe pure unittest { import std.utf : byChar; import std.array; assert(entabber(" \u0085 aa".byChar).array == "\u0085 aa"); assert(entabber(" \u2028\t aa \t".byChar).array == "\u2028\t aa"); auto r = entabber("1234", 4); r.popFront(); auto rsave = r.save; r.popFront(); assert(r.front == '3'); assert(rsave.front == '2'); } /++ Replaces the characters in $(D str) which are keys in $(D transTable) with their corresponding values in $(D transTable). $(D transTable) is an AA where its keys are $(D dchar) and its values are either $(D dchar) or some type of string. Also, if $(D toRemove) is given, the characters in it are removed from $(D str) prior to translation. $(D str) itself is unaltered. A copy with the changes is returned. See_Also: $(LREF tr) $(XREF array, replace) Params: str = The original string. transTable = The AA indicating which characters to replace and what to replace them with. toRemove = The characters to remove from the string. +/ C1[] translate(C1, C2 = immutable char)(C1[] str, in dchar[dchar] transTable, const(C2)[] toRemove = null) @safe pure if (isSomeChar!C1 && isSomeChar!C2) { import std.array : appender; auto buffer = appender!(C1[])(); translateImpl(str, transTable, toRemove, buffer); return buffer.data; } /// @safe pure unittest { dchar[dchar] transTable1 = ['e' : '5', 'o' : '7', '5': 'q']; assert(translate("hello world", transTable1) == "h5ll7 w7rld"); assert(translate("hello world", transTable1, "low") == "h5 rd"); string[dchar] transTable2 = ['e' : "5", 'o' : "orange"]; assert(translate("hello world", transTable2) == "h5llorange worangerld"); } @safe pure unittest // issue 13018 { immutable dchar[dchar] transTable1 = ['e' : '5', 'o' : '7', '5': 'q']; assert(translate("hello world", transTable1) == "h5ll7 w7rld"); assert(translate("hello world", transTable1, "low") == "h5 rd"); immutable string[dchar] transTable2 = ['e' : "5", 'o' : "orange"]; assert(translate("hello world", transTable2) == "h5llorange worangerld"); } @trusted pure unittest { import std.conv : to; import std.exception; assertCTFEable!( { foreach (S; AliasSeq!( char[], const( char)[], immutable( char)[], wchar[], const(wchar)[], immutable(wchar)[], dchar[], const(dchar)[], immutable(dchar)[])) { assert(translate(to!S("hello world"), cast(dchar[dchar])['h' : 'q', 'l' : '5']) == to!S("qe55o wor5d")); assert(translate(to!S("hello world"), cast(dchar[dchar])['o' : 'l', 'l' : '\U00010143']) == to!S("he\U00010143\U00010143l wlr\U00010143d")); assert(translate(to!S("hello \U00010143 world"), cast(dchar[dchar])['h' : 'q', 'l': '5']) == to!S("qe55o \U00010143 wor5d")); assert(translate(to!S("hello \U00010143 world"), cast(dchar[dchar])['o' : '0', '\U00010143' : 'o']) == to!S("hell0 o w0rld")); assert(translate(to!S("hello world"), cast(dchar[dchar])null) == to!S("hello world")); foreach (T; AliasSeq!( char[], const( char)[], immutable( char)[], wchar[], const(wchar)[], immutable(wchar)[], dchar[], const(dchar)[], immutable(dchar)[])) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 foreach(R; AliasSeq!(dchar[dchar], const dchar[dchar], immutable dchar[dchar])) { R tt = ['h' : 'q', 'l' : '5']; assert(translate(to!S("hello world"), tt, to!T("r")) == to!S("qe55o wo5d")); assert(translate(to!S("hello world"), tt, to!T("helo")) == to!S(" wrd")); assert(translate(to!S("hello world"), tt, to!T("q5")) == to!S("qe55o wor5d")); } }(); auto s = to!S("hello world"); dchar[dchar] transTable = ['h' : 'q', 'l' : '5']; static assert(is(typeof(s) == typeof(translate(s, transTable)))); } }); } /++ Ditto +/ C1[] translate(C1, S, C2 = immutable char)(C1[] str, in S[dchar] transTable, const(C2)[] toRemove = null) @safe pure if (isSomeChar!C1 && isSomeString!S && isSomeChar!C2) { import std.array : appender; auto buffer = appender!(C1[])(); translateImpl(str, transTable, toRemove, buffer); return buffer.data; } @trusted pure unittest { import std.conv : to; import std.exception; assertCTFEable!( { foreach (S; AliasSeq!( char[], const( char)[], immutable( char)[], wchar[], const(wchar)[], immutable(wchar)[], dchar[], const(dchar)[], immutable(dchar)[])) { assert(translate(to!S("hello world"), ['h' : "yellow", 'l' : "42"]) == to!S("yellowe4242o wor42d")); assert(translate(to!S("hello world"), ['o' : "owl", 'l' : "\U00010143\U00010143"]) == to!S("he\U00010143\U00010143\U00010143\U00010143owl wowlr\U00010143\U00010143d")); assert(translate(to!S("hello \U00010143 world"), ['h' : "yellow", 'l' : "42"]) == to!S("yellowe4242o \U00010143 wor42d")); assert(translate(to!S("hello \U00010143 world"), ['o' : "owl", 'l' : "\U00010143\U00010143"]) == to!S("he\U00010143\U00010143\U00010143\U00010143owl \U00010143 wowlr\U00010143\U00010143d")); assert(translate(to!S("hello \U00010143 world"), ['h' : ""]) == to!S("ello \U00010143 world")); assert(translate(to!S("hello \U00010143 world"), ['\U00010143' : ""]) == to!S("hello world")); assert(translate(to!S("hello world"), cast(string[dchar])null) == to!S("hello world")); foreach (T; AliasSeq!( char[], const( char)[], immutable( char)[], wchar[], const(wchar)[], immutable(wchar)[], dchar[], const(dchar)[], immutable(dchar)[])) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 foreach(R; AliasSeq!(string[dchar], const string[dchar], immutable string[dchar])) { R tt = ['h' : "yellow", 'l' : "42"]; assert(translate(to!S("hello world"), tt, to!T("r")) == to!S("yellowe4242o wo42d")); assert(translate(to!S("hello world"), tt, to!T("helo")) == to!S(" wrd")); assert(translate(to!S("hello world"), tt, to!T("y42")) == to!S("yellowe4242o wor42d")); assert(translate(to!S("hello world"), tt, to!T("hello world")) == to!S("")); assert(translate(to!S("hello world"), tt, to!T("42")) == to!S("yellowe4242o wor42d")); } }(); auto s = to!S("hello world"); string[dchar] transTable = ['h' : "silly", 'l' : "putty"]; static assert(is(typeof(s) == typeof(translate(s, transTable)))); } }); } /++ This is an overload of $(D translate) which takes an existing buffer to write the contents to. Params: str = The original string. transTable = The AA indicating which characters to replace and what to replace them with. toRemove = The characters to remove from the string. buffer = An output range to write the contents to. +/ void translate(C1, C2 = immutable char, Buffer)(C1[] str, in dchar[dchar] transTable, const(C2)[] toRemove, Buffer buffer) if (isSomeChar!C1 && isSomeChar!C2 && isOutputRange!(Buffer, C1)) { translateImpl(str, transTable, toRemove, buffer); } /// @safe pure unittest { import std.array : appender; dchar[dchar] transTable1 = ['e' : '5', 'o' : '7', '5': 'q']; auto buffer = appender!(dchar[])(); translate("hello world", transTable1, null, buffer); assert(buffer.data == "h5ll7 w7rld"); buffer.clear(); translate("hello world", transTable1, "low", buffer); assert(buffer.data == "h5 rd"); buffer.clear(); string[dchar] transTable2 = ['e' : "5", 'o' : "orange"]; translate("hello world", transTable2, null, buffer); assert(buffer.data == "h5llorange worangerld"); } @safe pure unittest // issue 13018 { import std.array : appender; immutable dchar[dchar] transTable1 = ['e' : '5', 'o' : '7', '5': 'q']; auto buffer = appender!(dchar[])(); translate("hello world", transTable1, null, buffer); assert(buffer.data == "h5ll7 w7rld"); buffer.clear(); translate("hello world", transTable1, "low", buffer); assert(buffer.data == "h5 rd"); buffer.clear(); immutable string[dchar] transTable2 = ['e' : "5", 'o' : "orange"]; translate("hello world", transTable2, null, buffer); assert(buffer.data == "h5llorange worangerld"); } /++ Ditto +/ void translate(C1, S, C2 = immutable char, Buffer)(C1[] str, in S[dchar] transTable, const(C2)[] toRemove, Buffer buffer) if (isSomeChar!C1 && isSomeString!S && isSomeChar!C2 && isOutputRange!(Buffer, S)) { translateImpl(str, transTable, toRemove, buffer); } private void translateImpl(C1, T, C2, Buffer)(C1[] str, T transTable, const(C2)[] toRemove, Buffer buffer) { bool[dchar] removeTable; foreach (dchar c; toRemove) removeTable[c] = true; foreach (dchar c; str) { if (c in removeTable) continue; auto newC = c in transTable; if (newC) put(buffer, *newC); else put(buffer, c); } } /++ This is an $(I $(RED ASCII-only)) overload of $(LREF _translate). It will $(I not) work with Unicode. It exists as an optimization for the cases where Unicode processing is not necessary. Unlike the other overloads of $(LREF _translate), this one does not take an AA. Rather, it takes a $(D string) generated by $(LREF makeTransTable). The array generated by $(D makeTransTable) is $(D 256) elements long such that the index is equal to the ASCII character being replaced and the value is equal to the character that it's being replaced with. Note that translate does not decode any of the characters, so you can actually pass it Extended ASCII characters if you want to (ASCII only actually uses $(D 128) characters), but be warned that Extended ASCII characters are not valid Unicode and therefore will result in a $(D UTFException) being thrown from most other Phobos functions. Also, because no decoding occurs, it is possible to use this overload to translate ASCII characters within a proper UTF-8 string without altering the other, non-ASCII characters. It's replacing any code unit greater than $(D 127) with another code unit or replacing any code unit with another code unit greater than $(D 127) which will cause UTF validation issues. See_Also: $(LREF tr) $(XREF array, replace) Params: str = The original string. transTable = The string indicating which characters to replace and what to replace them with. It is generated by $(LREF makeTransTable). toRemove = The characters to remove from the string. +/ C[] translate(C = immutable char)(in char[] str, in char[] transTable, in char[] toRemove = null) @trusted pure nothrow if (is(Unqual!C == char)) in { assert(transTable.length == 256); } body { bool[256] remTable = false; foreach (char c; toRemove) remTable[c] = true; size_t count = 0; foreach (char c; str) { if (!remTable[c]) ++count; } auto buffer = new char[count]; size_t i = 0; foreach (char c; str) { if (!remTable[c]) buffer[i++] = transTable[c]; } return cast(C[])(buffer); } /** * Do same thing as $(LREF makeTransTable) but allocate the translation table * on the GC heap. * * Use $(LREF makeTransTable) instead. */ string makeTrans(in char[] from, in char[] to) @trusted pure nothrow { return makeTransTable(from, to)[].idup; } /// @safe pure nothrow unittest { auto transTable1 = makeTrans("eo5", "57q"); assert(translate("hello world", transTable1) == "h5ll7 w7rld"); assert(translate("hello world", transTable1, "low") == "h5 rd"); } /******* * Construct 256 character translation table, where characters in from[] are replaced * by corresponding characters in to[]. * * Params: * from = array of chars, less than or equal to 256 in length * to = corresponding array of chars to translate to * Returns: * translation array */ char[256] makeTransTable(in char[] from, in char[] to) @safe pure nothrow @nogc in { import std.ascii : isASCII; assert(from.length == to.length); assert(from.length <= 256); foreach (char c; from) assert(isASCII(c)); foreach (char c; to) assert(isASCII(c)); } body { char[256] result = void; foreach (i; 0 .. result.length) result[i] = cast(char)i; foreach (i, c; from) result[c] = to[i]; return result; } @safe pure unittest { import std.conv : to; import std.exception; assertCTFEable!( { foreach (C; AliasSeq!(char, const char, immutable char)) { assert(translate!C("hello world", makeTransTable("hl", "q5")) == to!(C[])("qe55o wor5d")); auto s = to!(C[])("hello world"); auto transTable = makeTransTable("hl", "q5"); static assert(is(typeof(s) == typeof(translate!C(s, transTable)))); } foreach (S; AliasSeq!(char[], const(char)[], immutable(char)[])) { assert(translate(to!S("hello world"), makeTransTable("hl", "q5")) == to!S("qe55o wor5d")); assert(translate(to!S("hello \U00010143 world"), makeTransTable("hl", "q5")) == to!S("qe55o \U00010143 wor5d")); assert(translate(to!S("hello world"), makeTransTable("ol", "1o")) == to!S("heoo1 w1rod")); assert(translate(to!S("hello world"), makeTransTable("", "")) == to!S("hello world")); assert(translate(to!S("hello world"), makeTransTable("12345", "67890")) == to!S("hello world")); assert(translate(to!S("hello \U00010143 world"), makeTransTable("12345", "67890")) == to!S("hello \U00010143 world")); foreach (T; AliasSeq!(char[], const(char)[], immutable(char)[])) (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396 assert(translate(to!S("hello world"), makeTransTable("hl", "q5"), to!T("r")) == to!S("qe55o wo5d")); assert(translate(to!S("hello \U00010143 world"), makeTransTable("hl", "q5"), to!T("r")) == to!S("qe55o \U00010143 wo5d")); assert(translate(to!S("hello world"), makeTransTable("hl", "q5"), to!T("helo")) == to!S(" wrd")); assert(translate(to!S("hello world"), makeTransTable("hl", "q5"), to!T("q5")) == to!S("qe55o wor5d")); }(); } }); } /++ This is an $(I $(RED ASCII-only)) overload of $(D translate) which takes an existing buffer to write the contents to. Params: str = The original string. transTable = The string indicating which characters to replace and what to replace them with. It is generated by $(LREF makeTransTable). toRemove = The characters to remove from the string. buffer = An output range to write the contents to. +/ void translate(C = immutable char, Buffer)(in char[] str, in char[] transTable, in char[] toRemove, Buffer buffer) @trusted pure if (is(Unqual!C == char) && isOutputRange!(Buffer, char)) in { assert(transTable.length == 256); } body { bool[256] remTable = false; foreach (char c; toRemove) remTable[c] = true; foreach (char c; str) { if (!remTable[c]) put(buffer, transTable[c]); } } /// @safe pure unittest { import std.array : appender; auto buffer = appender!(char[])(); auto transTable1 = makeTransTable("eo5", "57q"); translate("hello world", transTable1, null, buffer); assert(buffer.data == "h5ll7 w7rld"); buffer.clear(); translate("hello world", transTable1, "low", buffer); assert(buffer.data == "h5 rd"); } /*********************************************** * See if character c is in the pattern. * Patterns: * * A pattern is an array of characters much like a character * class in regular expressions. A sequence of characters * can be given, such as "abcde". The '-' can represent a range * of characters, as "a-e" represents the same pattern as "abcde". * "a-fA-F0-9" represents all the hex characters. * If the first character of a pattern is '^', then the pattern * is negated, i.e. "^0-9" means any character except a digit. * The functions inPattern, countchars, removeschars, * and squeeze * use patterns. * * Note: In the future, the pattern syntax may be improved * to be more like regular expression character classes. */ bool inPattern(S)(dchar c, in S pattern) @safe pure @nogc if (isSomeString!S) { bool result = false; int range = 0; dchar lastc; foreach (size_t i, dchar p; pattern) { if (p == '^' && i == 0) { result = true; if (i + 1 == pattern.length) return (c == p); // or should this be an error? } else if (range) { range = 0; if (lastc <= c && c <= p || c == p) return !result; } else if (p == '-' && i > result && i + 1 < pattern.length) { range = 1; continue; } else if (c == p) return !result; lastc = p; } return result; } @safe pure @nogc unittest { import std.conv : to; debug(string) trustedPrintf("std.string.inPattern.unittest\n"); import std.exception; assertCTFEable!( { assert(inPattern('x', "x") == 1); assert(inPattern('x', "y") == 0); assert(inPattern('x', string.init) == 0); assert(inPattern('x', "^y") == 1); assert(inPattern('x', "yxxy") == 1); assert(inPattern('x', "^yxxy") == 0); assert(inPattern('x', "^abcd") == 1); assert(inPattern('^', "^^") == 0); assert(inPattern('^', "^") == 1); assert(inPattern('^', "a^") == 1); assert(inPattern('x', "a-z") == 1); assert(inPattern('x', "A-Z") == 0); assert(inPattern('x', "^a-z") == 0); assert(inPattern('x', "^A-Z") == 1); assert(inPattern('-', "a-") == 1); assert(inPattern('-', "^A-") == 0); assert(inPattern('a', "z-a") == 1); assert(inPattern('z', "z-a") == 1); assert(inPattern('x', "z-a") == 0); }); } /*********************************************** * See if character c is in the intersection of the patterns. */ bool inPattern(S)(dchar c, S[] patterns) @safe pure @nogc if (isSomeString!S) { foreach (string pattern; patterns) { if (!inPattern(c, pattern)) { return false; } } return true; } /******************************************** * Count characters in s that match pattern. */ size_t countchars(S, S1)(S s, in S1 pattern) @safe pure @nogc if (isSomeString!S && isSomeString!S1) { size_t count; foreach (dchar c; s) { count += inPattern(c, pattern); } return count; } @safe pure @nogc unittest { import std.conv : to; debug(string) trustedPrintf("std.string.count.unittest\n"); import std.exception; assertCTFEable!( { assert(countchars("abc", "a-c") == 3); assert(countchars("hello world", "or") == 3); }); } /******************************************** * Return string that is s with all characters removed that match pattern. */ S removechars(S)(S s, in S pattern) @safe pure if (isSomeString!S) { import std.utf : encode; Unqual!(typeof(s[0]))[] r; bool changed = false; foreach (size_t i, dchar c; s) { if (inPattern(c, pattern)) { if (!changed) { changed = true; r = s[0 .. i].dup; } continue; } if (changed) { encode(r, c); } } if (changed) return r; else return s; } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("std.string.removechars.unittest\n"); import std.exception; assertCTFEable!( { assert(removechars("abc", "a-c").length == 0); assert(removechars("hello world", "or") == "hell wld"); assert(removechars("hello world", "d") == "hello worl"); assert(removechars("hah", "h") == "a"); }); } /*************************************************** * Return string where sequences of a character in s[] from pattern[] * are replaced with a single instance of that character. * If pattern is null, it defaults to all characters. */ S squeeze(S)(S s, in S pattern = null) { import std.utf : encode, stride; Unqual!(typeof(s[0]))[] r; dchar lastc; size_t lasti; int run; bool changed; foreach (size_t i, dchar c; s) { if (run && lastc == c) { changed = true; } else if (pattern is null || inPattern(c, pattern)) { run = 1; if (changed) { if (r is null) r = s[0 .. lasti].dup; encode(r, c); } else lasti = i + stride(s, i); lastc = c; } else { run = 0; if (changed) { if (r is null) r = s[0 .. lasti].dup; encode(r, c); } } } return changed ? ((r is null) ? s[0 .. lasti] : cast(S) r) : s; } @trusted pure unittest { import std.conv : to; debug(string) trustedPrintf("std.string.squeeze.unittest\n"); import std.exception; assertCTFEable!( { string s; assert(squeeze("hello") == "helo"); s = "abcd"; assert(squeeze(s) is s); s = "xyzz"; assert(squeeze(s).ptr == s.ptr); // should just be a slice assert(squeeze("hello goodbyee", "oe") == "hello godbye"); }); } /*************************************************************** Finds the position $(D_PARAM pos) of the first character in $(D_PARAM s) that does not match $(D_PARAM pattern) (in the terminology used by $(LINK2 std_string.html,inPattern)). Updates $(D_PARAM s = s[pos..$]). Returns the slice from the beginning of the original (before update) string up to, and excluding, $(D_PARAM pos). The $(D_PARAM munch) function is mostly convenient for skipping certain category of characters (e.g. whitespace) when parsing strings. (In such cases, the return value is not used.) */ S1 munch(S1, S2)(ref S1 s, S2 pattern) @safe pure @nogc { size_t j = s.length; foreach (i, dchar c; s) { if (!inPattern(c, pattern)) { j = i; break; } } scope(exit) s = s[j .. $]; return s[0 .. j]; } /// @safe pure @nogc unittest { string s = "123abc"; string t = munch(s, "0123456789"); assert(t == "123" && s == "abc"); t = munch(s, "0123456789"); assert(t == "" && s == "abc"); } @safe pure @nogc unittest { string s = "123€abc"; string t = munch(s, "0123456789"); assert(t == "123" && s == "€abc"); t = munch(s, "0123456789"); assert(t == "" && s == "€abc"); t = munch(s, "£$€¥"); assert(t == "€" && s == "abc"); } /********************************************** * Return string that is the 'successor' to s[]. * If the rightmost character is a-zA-Z0-9, it is incremented within * its case or digits. If it generates a carry, the process is * repeated with the one to its immediate left. */ S succ(S)(S s) @safe pure if (isSomeString!S) { import std.ascii : isAlphaNum; if (s.length && isAlphaNum(s[$ - 1])) { auto r = s.dup; size_t i = r.length - 1; while (1) { dchar c = s[i]; dchar carry; switch (c) { case '9': c = '0'; carry = '1'; goto Lcarry; case 'z': case 'Z': c -= 'Z' - 'A'; carry = c; Lcarry: r[i] = cast(char)c; if (i == 0) { auto t = new typeof(r[0])[r.length + 1]; t[0] = cast(char) carry; t[1 .. $] = r[]; return t; } i--; break; default: if (isAlphaNum(c)) r[i]++; return r; } } } return s; } /// @safe pure unittest { assert(succ("1") == "2"); assert(succ("9") == "10"); assert(succ("999") == "1000"); assert(succ("zz99") == "aaa00"); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("std.string.succ.unittest\n"); import std.exception; assertCTFEable!( { assert(succ(string.init) is null); assert(succ("!@#$%") == "!@#$%"); assert(succ("1") == "2"); assert(succ("9") == "10"); assert(succ("999") == "1000"); assert(succ("zz99") == "aaa00"); }); } /++ Replaces the characters in $(D str) which are in $(D from) with the the corresponding characters in $(D to) and returns the resulting string. $(D tr) is based on $(WEB pubs.opengroup.org/onlinepubs/9699919799/utilities/_tr.html, Posix's tr), though it doesn't do everything that the Posix utility does. Params: str = The original string. from = The characters to replace. to = The characters to replace with. modifiers = String containing modifiers. Modifiers: $(BOOKTABLE, $(TR $(TD Modifier) $(TD Description)) $(TR $(TD $(D 'c')) $(TD Complement the list of characters in $(D from))) $(TR $(TD $(D 'd')) $(TD Removes matching characters with no corresponding replacement in $(D to))) $(TR $(TD $(D 's')) $(TD Removes adjacent duplicates in the replaced characters)) ) If the modifier $(D 'd') is present, then the number of characters in $(D to) may be only $(D 0) or $(D 1). If the modifier $(D 'd') is $(I not) present, and $(D to) is empty, then $(D to) is taken to be the same as $(D from). If the modifier $(D 'd') is $(I not) present, and $(D to) is shorter than $(D from), then $(D to) is extended by replicating the last character in $(D to). Both $(D from) and $(D to) may contain ranges using the $(D '-') character (e.g. $(D "a-d") is synonymous with $(D "abcd").) Neither accept a leading $(D '^') as meaning the complement of the string (use the $(D 'c') modifier for that). +/ C1[] tr(C1, C2, C3, C4 = immutable char) (C1[] str, const(C2)[] from, const(C3)[] to, const(C4)[] modifiers = null) { import std.conv : conv_to = to; import std.utf : decode; import std.array : appender; bool mod_c; bool mod_d; bool mod_s; foreach (char c; modifiers) { switch (c) { case 'c': mod_c = 1; break; // complement case 'd': mod_d = 1; break; // delete unreplaced chars case 's': mod_s = 1; break; // squeeze duplicated replaced chars default: assert(0); } } if (to.empty && !mod_d) to = conv_to!(typeof(to))(from); auto result = appender!(C1[])(); bool modified; dchar lastc; foreach (dchar c; str) { dchar lastf; dchar lastt; dchar newc; int n = 0; for (size_t i = 0; i < from.length; ) { dchar f = decode(from, i); if (f == '-' && lastf != dchar.init && i < from.length) { dchar nextf = decode(from, i); if (lastf <= c && c <= nextf) { n += c - lastf - 1; if (mod_c) goto Lnotfound; goto Lfound; } n += nextf - lastf; lastf = lastf.init; continue; } if (c == f) { if (mod_c) goto Lnotfound; goto Lfound; } lastf = f; n++; } if (!mod_c) goto Lnotfound; n = 0; // consider it 'found' at position 0 Lfound: // Find the nth character in to[] dchar nextt; for (size_t i = 0; i < to.length; ) { dchar t = decode(to, i); if (t == '-' && lastt != dchar.init && i < to.length) { nextt = decode(to, i); n -= nextt - lastt; if (n < 0) { newc = nextt + n + 1; goto Lnewc; } lastt = dchar.init; continue; } if (n == 0) { newc = t; goto Lnewc; } lastt = t; nextt = t; n--; } if (mod_d) continue; newc = nextt; Lnewc: if (mod_s && modified && newc == lastc) continue; result.put(newc); assert(newc != dchar.init); modified = true; lastc = newc; continue; Lnotfound: result.put(c); lastc = c; modified = false; } return result.data; } unittest { import std.conv : to; debug(string) trustedPrintf("std.string.tr.unittest\n"); import std.algorithm : equal; // Complete list of test types; too slow to test'em all // alias TestTypes = AliasSeq!( // char[], const( char)[], immutable( char)[], // wchar[], const(wchar)[], immutable(wchar)[], // dchar[], const(dchar)[], immutable(dchar)[]); // Reduced list of test types alias TestTypes = AliasSeq!(char[], const(wchar)[], immutable(dchar)[]); import std.exception; assertCTFEable!( { foreach (S; TestTypes) { foreach (T; TestTypes) { foreach (U; TestTypes) { assert(equal(tr(to!S("abcdef"), to!T("cd"), to!U("CD")), "abCDef")); assert(equal(tr(to!S("abcdef"), to!T("b-d"), to!U("B-D")), "aBCDef")); assert(equal(tr(to!S("abcdefgh"), to!T("b-dh"), to!U("B-Dx")), "aBCDefgx")); assert(equal(tr(to!S("abcdefgh"), to!T("b-dh"), to!U("B-CDx")), "aBCDefgx")); assert(equal(tr(to!S("abcdefgh"), to!T("b-dh"), to!U("B-BCDx")), "aBCDefgx")); assert(equal(tr(to!S("abcdef"), to!T("ef"), to!U("*"), to!S("c")), "****ef")); assert(equal(tr(to!S("abcdef"), to!T("ef"), to!U(""), to!T("d")), "abcd")); assert(equal(tr(to!S("hello goodbye"), to!T("lo"), to!U(""), to!U("s")), "helo godbye")); assert(equal(tr(to!S("hello goodbye"), to!T("lo"), to!U("x"), "s"), "hex gxdbye")); assert(equal(tr(to!S("14-Jul-87"), to!T("a-zA-Z"), to!U(" "), "cs"), " Jul ")); assert(equal(tr(to!S("Abc"), to!T("AAA"), to!U("XYZ")), "Xbc")); } } auto s = to!S("hello world"); static assert(is(typeof(s) == typeof(tr(s, "he", "if")))); } }); } /** * Takes a string $(D s) and determines if it represents a number. This function * also takes an optional parameter, $(D bAllowSep), which will accept the * separator characters $(D ',') and $(D '__') within the string. But these * characters should be stripped from the string before using any * of the conversion functions like $(D to!int()), $(D to!float()), and etc * else an error will occur. * * Also please note, that no spaces are allowed within the string * anywhere whether it's a leading, trailing, or embedded space(s), * thus they too must be stripped from the string before using this * function, or any of the conversion functions. * * Params: * s = the string to check * bAllowSep = accept separator characters or not * * Returns: * $(D bool) */ bool isNumeric(const(char)[] s, in bool bAllowSep = false) @safe pure { import std.algorithm : among; immutable iLen = s.length; if (iLen == 0) return false; // Check for NaN (Not a Number) and for Infinity if (s.among!((a, b) => icmp(a, b) == 0) ("nan", "nani", "nan+nani", "inf", "-inf")) return true; immutable j = s[0].among!('-', '+')() != 0; bool bDecimalPoint, bExponent, bComplex, sawDigits; for (size_t i = j; i < iLen; i++) { immutable c = s[i]; // Digits are good, continue checking // with the popFront character... ;) if (c >= '0' && c <= '9') { sawDigits = true; continue; } // Check for the complex type, and if found // reset the flags for checking the 2nd number. if (c == '+') { if (!i) return false; bDecimalPoint = false; bExponent = false; bComplex = true; sawDigits = false; continue; } // Allow only one exponent per number if (c.among!('e', 'E')()) { // A 2nd exponent found, return not a number if (bExponent || i + 1 >= iLen) return false; // Look forward for the sign, and if // missing then this is not a number. if (!s[i + 1].among!('-', '+')()) return false; bExponent = true; i++; continue; } // Allow only one decimal point per number to be used if (c == '.' ) { // A 2nd decimal point found, return not a number if (bDecimalPoint) return false; bDecimalPoint = true; continue; } // Check for ending literal characters: "f,u,l,i,ul,fi,li", // and whether they're being used with the correct datatype. if (i == iLen - 2) { if (!sawDigits) return false; // Integer Whole Number if (icmp(s[i..iLen], "ul") == 0 && (!bDecimalPoint && !bExponent && !bComplex)) return true; // Floating-Point Number if (s[i..iLen].among!((a, b) => icmp(a, b) == 0)("fi", "li") && (bDecimalPoint || bExponent || bComplex)) return true; if (icmp(s[i..iLen], "ul") == 0 && (bDecimalPoint || bExponent || bComplex)) return false; // Could be a Integer or a Float, thus // all these suffixes are valid for both return s[i..iLen].among!((a, b) => icmp(a, b) == 0) ("ul", "fi", "li") != 0; } if (i == iLen - 1) { if (!sawDigits) return false; // Integer Whole Number if (c.among!('u', 'l', 'U', 'L')() && (!bDecimalPoint && !bExponent && !bComplex)) return true; // Check to see if the last character in the string // is the required 'i' character if (bComplex) return c.among!('i', 'I')() != 0; // Floating-Point Number return c.among!('l', 'L', 'f', 'F', 'i', 'I')() != 0; } // Check if separators are allowed to be in the numeric string if (!bAllowSep || !c.among!('_', ',')()) return false; } return sawDigits; } /** * Integer Whole Number: (byte, ubyte, short, ushort, int, uint, long, and ulong) * ['+'|'-']digit(s)[U|L|UL] */ @safe pure unittest { assert(isNumeric("123")); assert(isNumeric("123UL")); assert(isNumeric("123L")); assert(isNumeric("+123U")); assert(isNumeric("-123L")); } /** * Floating-Point Number: (float, double, real, ifloat, idouble, and ireal) * ['+'|'-']digit(s)[.][digit(s)][[e-|e+]digit(s)][i|f|L|Li|fi]] * or [nan|nani|inf|-inf] */ @safe pure unittest { assert(isNumeric("+123")); assert(isNumeric("-123.01")); assert(isNumeric("123.3e-10f")); assert(isNumeric("123.3e-10fi")); assert(isNumeric("123.3e-10L")); assert(isNumeric("nan")); assert(isNumeric("nani")); assert(isNumeric("-inf")); } /** * Floating-Point Number: (cfloat, cdouble, and creal) * ['+'|'-']digit(s)[.][digit(s)][[e-|e+]digit(s)][+] * [digit(s)[.][digit(s)][[e-|e+]digit(s)][i|f|L|Li|fi]] * or [nan|nani|nan+nani|inf|-inf] */ @safe pure unittest { assert(isNumeric("-123e-1+456.9e-10Li")); assert(isNumeric("+123e+10+456i")); assert(isNumeric("123+456")); } @safe pure unittest { assert(!isNumeric("F")); assert(!isNumeric("L")); assert(!isNumeric("U")); assert(!isNumeric("i")); assert(!isNumeric("fi")); assert(!isNumeric("ul")); assert(!isNumeric("li")); assert(!isNumeric(".")); assert(!isNumeric("-")); assert(!isNumeric("+")); assert(!isNumeric("e-")); assert(!isNumeric("e+")); assert(!isNumeric(".f")); assert(!isNumeric("e+f")); } @trusted unittest { import std.conv : to; debug(string) trustedPrintf("isNumeric(in string, bool = false).unittest\n"); import std.exception; assertCTFEable!( { // Test the isNumeric(in string) function assert(isNumeric("1") == true ); assert(isNumeric("1.0") == true ); assert(isNumeric("1e-1") == true ); assert(isNumeric("12345xxxx890") == false ); assert(isNumeric("567L") == true ); assert(isNumeric("23UL") == true ); assert(isNumeric("-123..56f") == false ); assert(isNumeric("12.3.5.6") == false ); assert(isNumeric(" 12.356") == false ); assert(isNumeric("123 5.6") == false ); assert(isNumeric("1233E-1+1.0e-1i") == true ); assert(isNumeric("123.00E-5+1234.45E-12Li") == true); assert(isNumeric("123.00e-5+1234.45E-12iL") == false); assert(isNumeric("123.00e-5+1234.45e-12uL") == false); assert(isNumeric("123.00E-5+1234.45e-12lu") == false); assert(isNumeric("123fi") == true); assert(isNumeric("123li") == true); assert(isNumeric("--123L") == false); assert(isNumeric("+123.5UL") == false); assert(isNumeric("123f") == true); assert(isNumeric("123.u") == false); // @@@BUG@@ to!string(float) is not CTFEable. // Related: formatValue(T) if (is(FloatingPointTypeOf!T)) if (!__ctfe) { assert(isNumeric(to!string(real.nan)) == true); assert(isNumeric(to!string(-real.infinity)) == true); assert(isNumeric(to!string(123e+2+1234.78Li)) == true); } string s = "$250.99-"; assert(isNumeric(s[1..s.length - 2]) == true); assert(isNumeric(s) == false); assert(isNumeric(s[0..s.length - 1]) == false); }); assert(!isNumeric("-")); assert(!isNumeric("+")); } /***************************** * Soundex algorithm. * * The Soundex algorithm converts a word into 4 characters * based on how the word sounds phonetically. The idea is that * two spellings that sound alike will have the same Soundex * value, which means that Soundex can be used for fuzzy matching * of names. * * Params: * str = String or InputRange to convert to Soundex representation. * * Returns: * The four character array with the Soundex result in it. * The array has zero's in it if there is no Soundex representation for the string. * * See_Also: * $(LINK2 http://en.wikipedia.org/wiki/Soundex, Wikipedia), * $(LUCKY The Soundex Indexing System) * $(LREF soundex) * * Bugs: * Only works well with English names. * There are other arguably better Soundex algorithms, * but this one is the standard one. */ char[4] soundexer(Range)(Range str) if (isInputRange!Range && isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range) { alias C = Unqual!(ElementEncodingType!Range); static immutable dex = // ABCDEFGHIJKLMNOPQRSTUVWXYZ "01230120022455012623010202"; char[4] result = void; size_t b = 0; C lastc; foreach (C c; str) { if (c >= 'a' && c <= 'z') c -= 'a' - 'A'; else if (c >= 'A' && c <= 'Z') { } else { lastc = lastc.init; continue; } if (b == 0) { result[0] = cast(char)c; b++; lastc = dex[c - 'A']; } else { if (c == 'H' || c == 'W') continue; if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U') lastc = lastc.init; c = dex[c - 'A']; if (c != '0' && c != lastc) { result[b] = cast(char)c; b++; lastc = c; } if (b == 4) goto Lret; } } if (b == 0) result[] = 0; else result[b .. 4] = '0'; Lret: return result; } char[4] soundexer(Range)(auto ref Range str) if (isConvertibleToString!Range) { return soundexer!(StringTypeOf!Range)(str); } /***************************** * Like $(LREF soundexer), but with different parameters * and return value. * * Params: * str = String to convert to Soundex representation. * buffer = Optional 4 char array to put the resulting Soundex * characters into. If null, the return value * buffer will be allocated on the heap. * Returns: * The four character array with the Soundex result in it. * Returns null if there is no Soundex representation for the string. * See_Also: * $(LREF soundexer) */ char[] soundex(const(char)[] str, char[] buffer = null) @safe pure nothrow in { assert(!buffer.ptr || buffer.length >= 4); } out (result) { if (result.ptr) { assert(result.length == 4); assert(result[0] >= 'A' && result[0] <= 'Z'); foreach (char c; result[1 .. 4]) assert(c >= '0' && c <= '6'); } } body { char[4] result = soundexer(str); if (result[0] == 0) return null; if (!buffer.ptr) buffer = new char[4]; buffer[] = result[]; return buffer; } @safe pure nothrow unittest { import std.exception; assertCTFEable!( { char[4] buffer; assert(soundex(null) == null); assert(soundex("") == null); assert(soundex("0123^&^^**&^") == null); assert(soundex("Euler") == "E460"); assert(soundex(" Ellery ") == "E460"); assert(soundex("Gauss") == "G200"); assert(soundex("Ghosh") == "G200"); assert(soundex("Hilbert") == "H416"); assert(soundex("Heilbronn") == "H416"); assert(soundex("Knuth") == "K530"); assert(soundex("Kant", buffer) == "K530"); assert(soundex("Lloyd") == "L300"); assert(soundex("Ladd") == "L300"); assert(soundex("Lukasiewicz", buffer) == "L222"); assert(soundex("Lissajous") == "L222"); assert(soundex("Robert") == "R163"); assert(soundex("Rupert") == "R163"); assert(soundex("Rubin") == "R150"); assert(soundex("Washington") == "W252"); assert(soundex("Lee") == "L000"); assert(soundex("Gutierrez") == "G362"); assert(soundex("Pfister") == "P236"); assert(soundex("Jackson") == "J250"); assert(soundex("Tymczak") == "T522"); assert(soundex("Ashcraft") == "A261"); assert(soundex("Woo") == "W000"); assert(soundex("Pilgrim") == "P426"); assert(soundex("Flingjingwaller") == "F452"); assert(soundex("PEARSE") == "P620"); assert(soundex("PIERCE") == "P620"); assert(soundex("Price") == "P620"); assert(soundex("CATHY") == "C300"); assert(soundex("KATHY") == "K300"); assert(soundex("Jones") == "J520"); assert(soundex("johnsons") == "J525"); assert(soundex("Hardin") == "H635"); assert(soundex("Martinez") == "M635"); import std.utf; assert(soundexer("Martinez".byChar ) == "M635"); assert(soundexer("Martinez".byWchar) == "M635"); assert(soundexer("Martinez".byDchar) == "M635"); }); } unittest { assert(testAliasedString!soundexer("Martinez")); } /*************************************************** * Construct an associative array consisting of all * abbreviations that uniquely map to the strings in values. * * This is useful in cases where the user is expected to type * in one of a known set of strings, and the program will helpfully * autocomplete the string once sufficient characters have been * entered that uniquely identify it. */ string[string] abbrev(string[] values) @safe pure { import std.algorithm : sort; string[string] result; // Make a copy when sorting so we follow COW principles. values = values.dup; sort(values); size_t values_length = values.length; size_t lasti = values_length; size_t nexti; string nv; string lv; for (size_t i = 0; i < values_length; i = nexti) { string value = values[i]; // Skip dups for (nexti = i + 1; nexti < values_length; nexti++) { nv = values[nexti]; if (value != values[nexti]) break; } import std.utf : stride; for (size_t j = 0; j < value.length; j += stride(value, j)) { string v = value[0 .. j]; if ((nexti == values_length || j > nv.length || v != nv[0 .. j]) && (lasti == values_length || j > lv.length || v != lv[0 .. j])) { result[v] = value; } } result[value] = value; lasti = i; lv = value; } return result; } /// unittest { import std.string; static string[] list = [ "food", "foxy" ]; auto abbrevs = std.string.abbrev(list); assert(abbrevs == ["fox": "foxy", "food": "food", "foxy": "foxy", "foo": "food"]); } @trusted pure unittest { import std.conv : to; import std.algorithm : sort; debug(string) trustedPrintf("string.abbrev.unittest\n"); import std.exception; assertCTFEable!( { string[] values; values ~= "hello"; values ~= "hello"; values ~= "he"; string[string] r; r = abbrev(values); auto keys = r.keys.dup; sort(keys); assert(keys.length == 4); assert(keys[0] == "he"); assert(keys[1] == "hel"); assert(keys[2] == "hell"); assert(keys[3] == "hello"); assert(r[keys[0]] == "he"); assert(r[keys[1]] == "hello"); assert(r[keys[2]] == "hello"); assert(r[keys[3]] == "hello"); }); } /****************************************** * Compute _column number at the end of the printed form of the string, * assuming the string starts in the leftmost _column, which is numbered * starting from 0. * * Tab characters are expanded into enough spaces to bring the _column number * to the next multiple of tabsize. * If there are multiple lines in the string, the _column number of the last * line is returned. * * Params: * str = string or InputRange to be analyzed * tabsize = number of columns a tab character represents * * Returns: * column number */ size_t column(Range)(Range str, in size_t tabsize = 8) if ((isInputRange!Range && isSomeChar!(Unqual!(ElementEncodingType!Range)) || isNarrowString!Range) && !isConvertibleToString!Range) { static if (is(Unqual!(ElementEncodingType!Range) == char)) { // decoding needed for chars import std.utf: byDchar; return str.byDchar.column(tabsize); } else { // decoding not needed for wchars and dchars import std.uni : lineSep, paraSep, nelSep; size_t column; foreach (const c; str) { switch (c) { case '\t': column = (column + tabsize) / tabsize * tabsize; break; case '\r': case '\n': case paraSep: case lineSep: case nelSep: column = 0; break; default: column++; break; } } return column; } } /// unittest { import std.utf : byChar, byWchar, byDchar; assert(column("1234 ") == 5); assert(column("1234 "w) == 5); assert(column("1234 "d) == 5); assert(column("1234 ".byChar()) == 5); assert(column("1234 "w.byWchar()) == 5); assert(column("1234 "d.byDchar()) == 5); // Tab stops are set at 8 spaces by default; tab characters insert enough // spaces to bring the column position to the next multiple of 8. assert(column("\t") == 8); assert(column("1\t") == 8); assert(column("\t1") == 9); assert(column("123\t") == 8); // Other tab widths are possible by specifying it explicitly: assert(column("\t", 4) == 4); assert(column("1\t", 4) == 4); assert(column("\t1", 4) == 5); assert(column("123\t", 4) == 4); // New lines reset the column number. assert(column("abc\n") == 0); assert(column("abc\n1") == 1); assert(column("abcdefg\r1234") == 4); assert(column("abc\u20281") == 1); assert(column("abc\u20291") == 1); assert(column("abc\u00851") == 1); assert(column("abc\u00861") == 5); } size_t column(Range)(auto ref Range str, in size_t tabsize = 8) if (isConvertibleToString!Range) { return column!(StringTypeOf!Range)(str, tabsize); } unittest { assert(testAliasedString!column("abc\u00861")); } @safe @nogc unittest { import std.conv : to; debug(string) trustedPrintf("string.column.unittest\n"); import std.exception; assertCTFEable!( { assert(column(string.init) == 0); assert(column("") == 0); assert(column("\t") == 8); assert(column("abc\t") == 8); assert(column("12345678\t") == 16); }); } /****************************************** * Wrap text into a paragraph. * * The input text string s is formed into a paragraph * by breaking it up into a sequence of lines, delineated * by \n, such that the number of columns is not exceeded * on each line. * The last line is terminated with a \n. * Params: * s = text string to be wrapped * columns = maximum number of _columns in the paragraph * firstindent = string used to _indent first line of the paragraph * indent = string to use to _indent following lines of the paragraph * tabsize = column spacing of tabs in firstindent[] and indent[] * Returns: * resulting paragraph as an allocated string */ S wrap(S)(S s, in size_t columns = 80, S firstindent = null, S indent = null, in size_t tabsize = 8) if (isSomeString!S) { import std.uni: isWhite; typeof(s.dup) result; bool inword; bool first = true; size_t wordstart; const indentcol = column(indent, tabsize); result.length = firstindent.length + s.length; result.length = firstindent.length; result[] = firstindent[]; auto col = column(firstindent, tabsize); foreach (size_t i, dchar c; s) { if (isWhite(c)) { if (inword) { if (first) { } else if (col + 1 + (i - wordstart) > columns) { result ~= '\n'; result ~= indent; col = indentcol; } else { result ~= ' '; col += 1; } result ~= s[wordstart .. i]; col += i - wordstart; inword = false; first = false; } } else { if (!inword) { wordstart = i; inword = true; } } } if (inword) { if (col + 1 + (s.length - wordstart) >= columns) { result ~= '\n'; result ~= indent; } else if (result.length != firstindent.length) result ~= ' '; result ~= s[wordstart .. s.length]; } result ~= '\n'; return result; } /// @safe pure unittest { assert(wrap("a short string", 7) == "a short\nstring\n"); // wrap will not break inside of a word, but at the next space assert(wrap("a short string", 4) == "a\nshort\nstring\n"); assert(wrap("a short string", 7, "\t") == "\ta\nshort\nstring\n"); assert(wrap("a short string", 7, "\t", " ") == "\ta\n short\n string\n"); } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.wrap.unittest\n"); import std.exception; assertCTFEable!( { assert(wrap(string.init) == "\n"); assert(wrap(" a b df ") == "a b df\n"); assert(wrap(" a b df ", 3) == "a b\ndf\n"); assert(wrap(" a bc df ", 3) == "a\nbc\ndf\n"); assert(wrap(" abcd df ", 3) == "abcd\ndf\n"); assert(wrap("x") == "x\n"); assert(wrap("u u") == "u u\n"); assert(wrap("abcd", 3) == "\nabcd\n"); assert(wrap("a de", 10, "\t", " ", 8) == "\ta\n de\n"); }); } /****************************************** * Removes one level of indentation from a multi-line string. * * This uniformly outdents the text as much as possible. * Whitespace-only lines are always converted to blank lines. * * Does not allocate memory if it does not throw. * * Params: * str = multi-line string * * Returns: * outdented string * * Throws: * StringException if indentation is done with different sequences * of whitespace characters. */ S outdent(S)(S str) @safe pure if(isSomeString!S) { return str.splitLines(KeepTerminator.yes).outdent().join(); } /// @safe pure unittest { enum pretty = q{ import std.stdio; void main() { writeln("Hello"); } }.outdent(); enum ugly = q{ import std.stdio; void main() { writeln("Hello"); } }; assert(pretty == ugly); } /****************************************** * Removes one level of indentation from an array of single-line strings. * * This uniformly outdents the text as much as possible. * Whitespace-only lines are always converted to blank lines. * * Params: * lines = array of single-line strings * * Returns: * lines[] is rewritten in place with outdented lines * * Throws: * StringException if indentation is done with different sequences * of whitespace characters. */ S[] outdent(S)(S[] lines) @safe pure if(isSomeString!S) { import std.algorithm : startsWith; if (lines.empty) { return null; } static S leadingWhiteOf(S str) { return str[ 0 .. $ - stripLeft(str).length ]; } S shortestIndent; foreach (ref line; lines) { auto stripped = line.stripLeft(); if (stripped.empty) { line = line[line.chomp().length .. $]; } else { auto indent = leadingWhiteOf(line); // Comparing number of code units instead of code points is OK here // because this function throws upon inconsistent indentation. if (shortestIndent is null || indent.length < shortestIndent.length) { if (indent.empty) return lines; shortestIndent = indent; } } } foreach (ref line; lines) { auto stripped = line.stripLeft(); if (stripped.empty) { // Do nothing } else if (line.startsWith(shortestIndent)) { line = line[shortestIndent.length .. $]; } else { throw new StringException("outdent: Inconsistent indentation"); } } return lines; } @safe pure unittest { import std.conv : to; debug(string) trustedPrintf("string.outdent.unittest\n"); template outdent_testStr(S) { enum S outdent_testStr = " \t\tX \t\U00010143X \t\t \t\t\tX \t "; } template outdent_expected(S) { enum S outdent_expected = " \tX \U00010143X \t\tX "; } import std.exception; assertCTFEable!( { foreach (S; AliasSeq!(string, wstring, dstring)) { enum S blank = ""; assert(blank.outdent() == blank); static assert(blank.outdent() == blank); enum S testStr1 = " \n \t\n "; enum S expected1 = "\n\n"; assert(testStr1.outdent() == expected1); static assert(testStr1.outdent() == expected1); assert(testStr1[0..$-1].outdent() == expected1); static assert(testStr1[0..$-1].outdent() == expected1); enum S testStr2 = "a\n \t\nb"; assert(testStr2.outdent() == testStr2); static assert(testStr2.outdent() == testStr2); enum S testStr3 = " \t\tX \t\U00010143X \t\t \t\t\tX \t "; enum S expected3 = " \tX \U00010143X \t\tX "; assert(testStr3.outdent() == expected3); static assert(testStr3.outdent() == expected3); enum testStr4 = " X\r X\n X\r\n X\u2028 X\u2029 X"; enum expected4 = "X\rX\nX\r\nX\u2028X\u2029X"; assert(testStr4.outdent() == expected4); static assert(testStr4.outdent() == expected4); enum testStr5 = testStr4[0..$-1]; enum expected5 = expected4[0..$-1]; assert(testStr5.outdent() == expected5); static assert(testStr5.outdent() == expected5); enum testStr6 = " \r \n \r\n \u2028 \u2029"; enum expected6 = "\r\n\r\n\u2028\u2029"; assert(testStr6.outdent() == expected6); static assert(testStr6.outdent() == expected6); enum testStr7 = " a \n b "; enum expected7 = "a \nb "; assert(testStr7.outdent() == expected7); static assert(testStr7.outdent() == expected7); } }); } /** Assume the given array of integers $(D arr) is a well-formed UTF string and return it typed as a UTF string. $(D ubyte) becomes $(D char), $(D ushort) becomes $(D wchar) and $(D uint) becomes $(D dchar). Type qualifiers are preserved. Params: arr = array of bytes, ubytes, shorts, ushorts, ints, or uints Returns: arr retyped as an array of chars, wchars, or dchars See_Also: $(LREF representation) */ auto assumeUTF(T)(T[] arr) pure if(staticIndexOf!(Unqual!T, ubyte, ushort, uint) != -1) { import std.utf : validate; alias ToUTFType(U) = AliasSeq!(char, wchar, dchar)[U.sizeof / 2]; auto asUTF = cast(ModifyTypePreservingTQ!(ToUTFType, T)[])arr; debug validate(asUTF); return asUTF; } /// @safe pure unittest { string a = "Hölo World"; immutable(ubyte)[] b = a.representation; string c = b.assumeUTF; assert(a == c); } pure unittest { import std.algorithm : equal; foreach(T; AliasSeq!(char[], wchar[], dchar[])) { immutable T jti = "Hello World"; T jt = jti.dup; static if(is(T == char[])) { auto gt = cast(ubyte[])jt; auto gtc = cast(const(ubyte)[])jt; auto gti = cast(immutable(ubyte)[])jt; } else static if(is(T == wchar[])) { auto gt = cast(ushort[])jt; auto gtc = cast(const(ushort)[])jt; auto gti = cast(immutable(ushort)[])jt; } else static if(is(T == dchar[])) { auto gt = cast(uint[])jt; auto gtc = cast(const(uint)[])jt; auto gti = cast(immutable(uint)[])jt; } auto ht = assumeUTF(gt); auto htc = assumeUTF(gtc); auto hti = assumeUTF(gti); assert(equal(jt, ht)); assert(equal(jt, htc)); assert(equal(jt, hti)); } } ldc-1.1.0-beta3-src/runtime/phobos/std/system.d0000664000175000017500000000471512776215007017406 0ustar kaikai// Written in the D programming language. /** * Information about the target operating system, environment, and CPU. * * Macros: * WIKI = Phobos/StdSystem * * Copyright: Copyright Digital Mars 2000 - 2011 * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) and Jonathan M Davis * Source: $(PHOBOSSRC std/_system.d) */ module std.system; immutable { /++ Operating system. Note: This is for cases where you need a value representing the OS at runtime. If you're doing something which should compile differently on different OSes, then please use $(D version(Windows)), $(D version(linux)), etc. See_Also: $(DDSUBLINK spec/version,PredefinedVersions, Predefined Versions) +/ enum OS { win32 = 1, /// Microsoft 32 bit Windows systems win64, /// Microsoft 64 bit Windows systems linux, /// All Linux Systems osx, /// Mac OS X freeBSD, /// FreeBSD netBSD, /// NetBSD solaris, /// Solaris android, /// Android otherPosix /// Other Posix Systems } /// The OS that the program was compiled for. version(Win32) OS os = OS.win32; else version(Win64) OS os = OS.win64; else version(Android) OS os = OS.android; else version(linux) OS os = OS.linux; else version(OSX) OS os = OS.osx; else version(FreeBSD) OS os = OS.freeBSD; else version(NetBSD) OS os = OS.netBSD; else version(Posix) OS os = OS.otherPosix; else static assert(0, "Unknown OS."); /++ Byte order endianness. Note: This is intended for cases where you need to deal with endianness at runtime. If you're doing something which should compile differently depending on whether you're compiling on a big endian or little endian machine, then please use $(D version(BigEndian)) and $(D version(LittleEndian)). See_Also: $(DDSUBLINK spec/version,PredefinedVersions, Predefined Versions) +/ enum Endian { bigEndian, /// Big endian byte order littleEndian /// Little endian byte order } /// The endianness that the program was compiled for. version(LittleEndian) Endian endian = Endian.littleEndian; else Endian endian = Endian.bigEndian; } ldc-1.1.0-beta3-src/runtime/phobos/std/socketstream.d0000664000175000017500000001026612776215007020564 0ustar kaikai// Written in the D programming language /* Copyright (C) 2004 Christopher E. Miller This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. 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. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /************** * $(RED Deprecated: This module is considered out-dated and not up to Phobos' * current standards. It will be remove in October 2016.) * * $(D SocketStream) is a stream for a blocking, * connected $(D Socket). * * Example: * See $(SAMPLESRC htmlget.d) * Authors: Christopher E. Miller * References: * $(LINK2 std_stream.html, std.stream) * Source: $(PHOBOSSRC std/_socketstream.d) * Macros: WIKI=Phobos/StdSocketstream */ deprecated("It will be removed from Phobos in October 2016. If you still need it, go to https://github.com/DigitalMars/undeaD") module std.socketstream; // @@@DEPRECATED_2016-10@@@ private import std.stream; private import std.socket; /************** * $(D SocketStream) is a stream for a blocking, * connected $(D Socket). */ class SocketStream: Stream { private: Socket sock; public: /** * Constructs a SocketStream with the specified Socket and FileMode flags. */ this(Socket sock, FileMode mode) { if(mode & FileMode.In) readable = true; if(mode & FileMode.Out) writeable = true; this.sock = sock; } /** * Uses mode $(D FileMode.In | FileMode.Out). */ this(Socket sock) { writeable = readable = true; this.sock = sock; } /** * Property to get the $(D Socket) that is being streamed. */ Socket socket() { return sock; } /** * Attempts to read the entire block, waiting if necessary. */ override size_t readBlock(void* _buffer, size_t size) { ubyte* buffer = cast(ubyte*)_buffer; assertReadable(); if (size == 0) return size; auto len = sock.receive(buffer[0 .. size]); readEOF = cast(bool)(len == 0); if (len == sock.ERROR) len = 0; return len; } /** * Attempts to write the entire block, waiting if necessary. */ override size_t writeBlock(const void* _buffer, size_t size) { ubyte* buffer = cast(ubyte*)_buffer; assertWriteable(); if (size == 0) return size; auto len = sock.send(buffer[0 .. size]); readEOF = cast(bool)(len == 0); if (len == sock.ERROR) len = 0; return len; } /** * Socket streams do not support seeking. This disabled method throws * a $(D SeekException). */ @disable override ulong seek(long offset, SeekPos whence) { throw new SeekException("Cannot seek a socket."); } /** * Does not return the entire stream because that would * require the remote connection to be closed. */ override string toString() { return sock.toString(); } /** * Close the $(D Socket). */ override void close() { sock.close(); super.close(); } } ldc-1.1.0-beta3-src/runtime/phobos/std/process.d0000664000175000017500000035540312776215007017543 0ustar kaikai// Written in the D programming language. /** Functions for starting and interacting with other processes, and for working with the current _process' execution environment. Process_handling: $(UL $(LI $(LREF spawnProcess) spawns a new _process, optionally assigning it an arbitrary set of standard input, output, and error streams. The function returns immediately, leaving the child _process to execute in parallel with its parent. All other functions in this module that spawn processes are built around $(D spawnProcess).) $(LI $(LREF wait) makes the parent _process wait for a child _process to terminate. In general one should always do this, to avoid child processes becoming "zombies" when the parent _process exits. Scope guards are perfect for this – see the $(LREF spawnProcess) documentation for examples. $(LREF tryWait) is similar to $(D wait), but does not block if the _process has not yet terminated.) $(LI $(LREF pipeProcess) also spawns a child _process which runs in parallel with its parent. However, instead of taking arbitrary streams, it automatically creates a set of pipes that allow the parent to communicate with the child through the child's standard input, output, and/or error streams. This function corresponds roughly to C's $(D popen) function.) $(LI $(LREF execute) starts a new _process and waits for it to complete before returning. Additionally, it captures the _process' standard output and error streams and returns the output of these as a string.) $(LI $(LREF spawnShell), $(LREF pipeShell) and $(LREF executeShell) work like $(D spawnProcess), $(D pipeProcess) and $(D execute), respectively, except that they take a single command string and run it through the current user's default command interpreter. $(D executeShell) corresponds roughly to C's $(D system) function.) $(LI $(LREF kill) attempts to terminate a running _process.) ) The following table compactly summarises the different _process creation functions and how they relate to each other: $(BOOKTABLE, $(TR $(TH ) $(TH Runs program directly) $(TH Runs shell command)) $(TR $(TD Low-level _process creation) $(TD $(LREF spawnProcess)) $(TD $(LREF spawnShell))) $(TR $(TD Automatic input/output redirection using pipes) $(TD $(LREF pipeProcess)) $(TD $(LREF pipeShell))) $(TR $(TD Execute and wait for completion, collect output) $(TD $(LREF execute)) $(TD $(LREF executeShell))) ) Other_functionality: $(UL $(LI $(LREF pipe) is used to create unidirectional pipes.) $(LI $(LREF environment) is an interface through which the current _process' environment variables can be read and manipulated.) $(LI $(LREF escapeShellCommand) and $(LREF escapeShellFileName) are useful for constructing shell command lines in a portable way.) ) Authors: $(LINK2 https://github.com/kyllingstad, Lars Tandle Kyllingstad), $(LINK2 https://github.com/schveiguy, Steven Schveighoffer), $(WEB thecybershadow.net, Vladimir Panteleev) Copyright: Copyright (c) 2013, the authors. All rights reserved. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Source: $(PHOBOSSRC std/_process.d) Macros: WIKI=Phobos/StdProcess OBJECTREF=$(D $(LINK2 object.html#$0,$0)) LREF=$(D $(LINK2 #.$0,$0)) */ module std.process; version (Posix) { import core.stdc.errno; import core.stdc.string; import core.sys.posix.stdio; import core.sys.posix.unistd; import core.sys.posix.sys.wait; } version (Windows) { import core.stdc.stdio; import core.sys.windows.windows; import std.utf; import std.windows.syserror; } import std.range.primitives; import std.conv; import std.exception; import std.path; import std.stdio; import std.internal.processinit; import std.internal.cstring; // When the DMC runtime is used, we have to use some custom functions // to convert between Windows file handles and FILE*s. version (Win32) version (CRuntime_DigitalMars) version = DMC_RUNTIME; // Some of the following should be moved to druntime. private { // Microsoft Visual C Runtime (MSVCRT) declarations. version (Windows) { version (DMC_RUNTIME) { } else { import core.stdc.stdint; enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2, } } } // POSIX API declarations. version (Posix) { version (OSX) { extern(C) char*** _NSGetEnviron() nothrow; private __gshared const(char**)* environPtr; extern(C) void std_process_shared_static_this() { environPtr = _NSGetEnviron(); } const(char**) environ() @property @trusted nothrow { return *environPtr; } } else { // Made available by the C runtime: extern(C) extern __gshared const char** environ; } unittest { new Thread({assert(environ !is null);}).start(); } } } // private // ============================================================================= // Functions and classes for process management. // ============================================================================= /** Spawns a new _process, optionally assigning it an arbitrary set of standard input, output, and error streams. The function returns immediately, leaving the child _process to execute in parallel with its parent. It is recommended to always call $(LREF wait) on the returned $(LREF Pid), as detailed in the documentation for $(D wait). Command_line: There are four overloads of this function. The first two take an array of strings, $(D args), which should contain the program name as the zeroth element and any command-line arguments in subsequent elements. The third and fourth versions are included for convenience, and may be used when there are no command-line arguments. They take a single string, $(D program), which specifies the program name. Unless a directory is specified in $(D args[0]) or $(D program), $(D spawnProcess) will search for the program in a platform-dependent manner. On POSIX systems, it will look for the executable in the directories listed in the PATH environment variable, in the order they are listed. On Windows, it will search for the executable in the following sequence: $(OL $(LI The directory from which the application loaded.) $(LI The current directory for the parent process.) $(LI The 32-bit Windows system directory.) $(LI The 16-bit Windows system directory.) $(LI The Windows directory.) $(LI The directories listed in the PATH environment variable.) ) --- // Run an executable called "prog" located in the current working // directory: auto pid = spawnProcess("./prog"); scope(exit) wait(pid); // We can do something else while the program runs. The scope guard // ensures that the process is waited for at the end of the scope. ... // Run DMD on the file "myprog.d", specifying a few compiler switches: auto dmdPid = spawnProcess(["dmd", "-O", "-release", "-inline", "myprog.d" ]); if (wait(dmdPid) != 0) writeln("Compilation failed!"); --- Environment_variables: By default, the child process inherits the environment of the parent process, along with any additional variables specified in the $(D env) parameter. If the same variable exists in both the parent's environment and in $(D env), the latter takes precedence. If the $(LREF Config.newEnv) flag is set in $(D config), the child process will $(I not) inherit the parent's environment. Its entire environment will then be determined by $(D env). --- wait(spawnProcess("myapp", ["foo" : "bar"], Config.newEnv)); --- Standard_streams: The optional arguments $(D stdin), $(D stdout) and $(D stderr) may be used to assign arbitrary $(XREF stdio,File) objects as the standard input, output and error streams, respectively, of the child process. The former must be opened for reading, while the latter two must be opened for writing. The default is for the child process to inherit the standard streams of its parent. --- // Run DMD on the file myprog.d, logging any error messages to a // file named errors.log. auto logFile = File("errors.log", "w"); auto pid = spawnProcess(["dmd", "myprog.d"], std.stdio.stdin, std.stdio.stdout, logFile); if (wait(pid) != 0) writeln("Compilation failed. See errors.log for details."); --- Note that if you pass a $(D File) object that is $(I not) one of the standard input/output/error streams of the parent process, that stream will by default be $(I closed) in the parent process when this function returns. See the $(LREF Config) documentation below for information about how to disable this behaviour. Beware of buffering issues when passing $(D File) objects to $(D spawnProcess). The child process will inherit the low-level raw read/write offset associated with the underlying file descriptor, but it will not be aware of any buffered data. In cases where this matters (e.g. when a file should be aligned before being passed on to the child process), it may be a good idea to use unbuffered streams, or at least ensure all relevant buffers are flushed. Params: args = An array which contains the program name as the zeroth element and any command-line arguments in the following elements. stdin = The standard input stream of the child process. This can be any $(XREF stdio,File) that is opened for reading. By default the child process inherits the parent's input stream. stdout = The standard output stream of the child process. This can be any $(XREF stdio,File) that is opened for writing. By default the child process inherits the parent's output stream. stderr = The standard error stream of the child process. This can be any $(XREF stdio,File) that is opened for writing. By default the child process inherits the parent's error stream. env = Additional environment variables for the child process. config = Flags that control process creation. See $(LREF Config) for an overview of available flags. workDir = The working directory for the new process. By default the child process inherits the parent's working directory. Returns: A $(LREF Pid) object that corresponds to the spawned process. Throws: $(LREF ProcessException) on failure to start the process.$(BR) $(XREF stdio,StdioException) on failure to pass one of the streams to the child process (Windows only).$(BR) $(CXREF exception,RangeError) if $(D args) is empty. */ Pid spawnProcess(in char[][] args, File stdin = std.stdio.stdin, File stdout = std.stdio.stdout, File stderr = std.stdio.stderr, const string[string] env = null, Config config = Config.none, in char[] workDir = null) @trusted // TODO: Should be @safe { version (Windows) auto args2 = escapeShellArguments(args); else version (Posix) alias args2 = args; return spawnProcessImpl(args2, stdin, stdout, stderr, env, config, workDir); } /// ditto Pid spawnProcess(in char[][] args, const string[string] env, Config config = Config.none, in char[] workDir = null) @trusted // TODO: Should be @safe { return spawnProcess(args, std.stdio.stdin, std.stdio.stdout, std.stdio.stderr, env, config, workDir); } /// ditto Pid spawnProcess(in char[] program, File stdin = std.stdio.stdin, File stdout = std.stdio.stdout, File stderr = std.stdio.stderr, const string[string] env = null, Config config = Config.none, in char[] workDir = null) @trusted { return spawnProcess((&program)[0 .. 1], stdin, stdout, stderr, env, config, workDir); } /// ditto Pid spawnProcess(in char[] program, const string[string] env, Config config = Config.none, in char[] workDir = null) @trusted { return spawnProcess((&program)[0 .. 1], env, config, workDir); } /* Implementation of spawnProcess() for POSIX. envz should be a zero-terminated array of zero-terminated strings on the form "var=value". */ version (Posix) private Pid spawnProcessImpl(in char[][] args, File stdin, File stdout, File stderr, const string[string] env, Config config, in char[] workDir) @trusted // TODO: Should be @safe { import core.exception: RangeError; import std.path : isDirSeparator; import std.algorithm : any; import std.string : toStringz; if (args.empty) throw new RangeError(); const(char)[] name = args[0]; if (any!isDirSeparator(name)) { if (!isExecutable(name)) throw new ProcessException(text("Not an executable file: ", name)); } else { name = searchPathFor(name); if (name is null) throw new ProcessException(text("Executable file not found: ", args[0])); } // Convert program name and arguments to C-style strings. auto argz = new const(char)*[args.length+1]; argz[0] = toStringz(name); foreach (i; 1 .. args.length) argz[i] = toStringz(args[i]); argz[$-1] = null; // Prepare environment. auto envz = createEnv(env, !(config & Config.newEnv)); // Open the working directory. // We use open in the parent and fchdir in the child // so that most errors (directory doesn't exist, not a directory) // can be propagated as exceptions before forking. int workDirFD = -1; scope(exit) if (workDirFD >= 0) close(workDirFD); if (workDir.length) { import core.sys.posix.fcntl; workDirFD = open(workDir.tempCString(), O_RDONLY); if (workDirFD < 0) throw ProcessException.newFromErrno("Failed to open working directory"); stat_t s; if (fstat(workDirFD, &s) < 0) throw ProcessException.newFromErrno("Failed to stat working directory"); if (!S_ISDIR(s.st_mode)) throw new ProcessException("Not a directory: " ~ cast(string)workDir); } int getFD(ref File f) { return core.stdc.stdio.fileno(f.getFP()); } // Get the file descriptors of the streams. // These could potentially be invalid, but that is OK. If so, later calls // to dup2() and close() will just silently fail without causing any harm. auto stdinFD = getFD(stdin); auto stdoutFD = getFD(stdout); auto stderrFD = getFD(stderr); auto id = fork(); if (id < 0) throw ProcessException.newFromErrno("Failed to spawn new process"); if (id == 0) { // Child process // Set the working directory. if (workDirFD >= 0) { if (fchdir(workDirFD) < 0) { // Fail. It is dangerous to run a program // in an unexpected working directory. core.sys.posix.stdio.perror("spawnProcess(): " ~ "Failed to set working directory"); core.sys.posix.unistd._exit(1); assert(0); } close(workDirFD); } // Redirect streams and close the old file descriptors. // In the case that stderr is redirected to stdout, we need // to backup the file descriptor since stdout may be redirected // as well. if (stderrFD == STDOUT_FILENO) stderrFD = dup(stderrFD); dup2(stdinFD, STDIN_FILENO); dup2(stdoutFD, STDOUT_FILENO); dup2(stderrFD, STDERR_FILENO); // Ensure that the standard streams aren't closed on execute, and // optionally close all other file descriptors. setCLOEXEC(STDIN_FILENO, false); setCLOEXEC(STDOUT_FILENO, false); setCLOEXEC(STDERR_FILENO, false); if (!(config & Config.inheritFDs)) { import core.sys.posix.sys.resource; rlimit r; getrlimit(RLIMIT_NOFILE, &r); foreach (i; 3 .. cast(int) r.rlim_cur) close(i); } // Close the old file descriptors, unless they are // either of the standard streams. if (stdinFD > STDERR_FILENO) close(stdinFD); if (stdoutFD > STDERR_FILENO) close(stdoutFD); if (stderrFD > STDERR_FILENO) close(stderrFD); // Execute program. core.sys.posix.unistd.execve(argz[0], argz.ptr, envz); // If execution fails, exit as quickly as possible. core.sys.posix.stdio.perror("spawnProcess(): Failed to execute program"); core.sys.posix.unistd._exit(1); assert (0); } else { // Parent process: Close streams and return. if (!(config & Config.retainStdin ) && stdinFD > STDERR_FILENO && stdinFD != getFD(std.stdio.stdin )) stdin.close(); if (!(config & Config.retainStdout) && stdoutFD > STDERR_FILENO && stdoutFD != getFD(std.stdio.stdout)) stdout.close(); if (!(config & Config.retainStderr) && stderrFD > STDERR_FILENO && stderrFD != getFD(std.stdio.stderr)) stderr.close(); return new Pid(id); } } /* Implementation of spawnProcess() for Windows. commandLine must contain the entire command line, properly quoted/escaped as required by CreateProcessW(). envz must be a pointer to a block of UTF-16 characters on the form "var1=value1\0var2=value2\0...varN=valueN\0\0". */ version (Windows) private Pid spawnProcessImpl(in char[] commandLine, File stdin, File stdout, File stderr, const string[string] env, Config config, in char[] workDir) @trusted { import core.exception: RangeError; if (commandLine.empty) throw new RangeError("Command line is empty"); // Prepare environment. auto envz = createEnv(env, !(config & Config.newEnv)); // Startup info for CreateProcessW(). STARTUPINFO_W startinfo; startinfo.cb = startinfo.sizeof; static int getFD(ref File f) { return f.isOpen ? f.fileno : -1; } // Extract file descriptors and HANDLEs from the streams and make the // handles inheritable. static void prepareStream(ref File file, DWORD stdHandle, string which, out int fileDescriptor, out HANDLE handle) { fileDescriptor = getFD(file); handle = null; if (fileDescriptor >= 0) handle = file.windowsHandle; // Windows GUI applications have a fd but not a valid Windows HANDLE. if (handle is null || handle == INVALID_HANDLE_VALUE) handle = GetStdHandle(stdHandle); DWORD dwFlags; if (GetHandleInformation(handle, &dwFlags)) { if (!(dwFlags & HANDLE_FLAG_INHERIT)) { if (!SetHandleInformation(handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { throw new StdioException( "Failed to make "~which~" stream inheritable by child process (" ~sysErrorString(GetLastError()) ~ ')', 0); } } } } int stdinFD = -1, stdoutFD = -1, stderrFD = -1; prepareStream(stdin, STD_INPUT_HANDLE, "stdin" , stdinFD, startinfo.hStdInput ); prepareStream(stdout, STD_OUTPUT_HANDLE, "stdout", stdoutFD, startinfo.hStdOutput); prepareStream(stderr, STD_ERROR_HANDLE, "stderr", stderrFD, startinfo.hStdError ); if ((startinfo.hStdInput != null && startinfo.hStdInput != INVALID_HANDLE_VALUE) || (startinfo.hStdOutput != null && startinfo.hStdOutput != INVALID_HANDLE_VALUE) || (startinfo.hStdError != null && startinfo.hStdError != INVALID_HANDLE_VALUE)) startinfo.dwFlags = STARTF_USESTDHANDLES; // Create process. PROCESS_INFORMATION pi; DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | ((config & Config.suppressConsole) ? CREATE_NO_WINDOW : 0); auto pworkDir = workDir.tempCStringW(); // workaround until Bugzilla 14696 is fixed if (!CreateProcessW(null, commandLine.tempCStringW().buffPtr, null, null, true, dwCreationFlags, envz, workDir.length ? pworkDir : null, &startinfo, &pi)) throw ProcessException.newFromLastError("Failed to spawn new process"); // figure out if we should close any of the streams if (!(config & Config.retainStdin ) && stdinFD > STDERR_FILENO && stdinFD != getFD(std.stdio.stdin )) stdin.close(); if (!(config & Config.retainStdout) && stdoutFD > STDERR_FILENO && stdoutFD != getFD(std.stdio.stdout)) stdout.close(); if (!(config & Config.retainStderr) && stderrFD > STDERR_FILENO && stderrFD != getFD(std.stdio.stderr)) stderr.close(); // close the thread handle in the process info structure CloseHandle(pi.hThread); return new Pid(pi.dwProcessId, pi.hProcess); } // Converts childEnv to a zero-terminated array of zero-terminated strings // on the form "name=value", optionally adding those of the current process' // environment strings that are not present in childEnv. If the parent's // environment should be inherited without modification, this function // returns environ directly. version (Posix) private const(char*)* createEnv(const string[string] childEnv, bool mergeWithParentEnv) { // Determine the number of strings in the parent's environment. int parentEnvLength = 0; if (mergeWithParentEnv) { if (childEnv.length == 0) return environ; while (environ[parentEnvLength] != null) ++parentEnvLength; } // Convert the "new" variables to C-style strings. auto envz = new const(char)*[parentEnvLength + childEnv.length + 1]; int pos = 0; foreach (var, val; childEnv) envz[pos++] = (var~'='~val~'\0').ptr; // Add the parent's environment. foreach (environStr; environ[0 .. parentEnvLength]) { int eqPos = 0; while (environStr[eqPos] != '=' && environStr[eqPos] != '\0') ++eqPos; if (environStr[eqPos] != '=') continue; auto var = environStr[0 .. eqPos]; if (var in childEnv) continue; envz[pos++] = environStr; } envz[pos] = null; return envz.ptr; } version (Posix) unittest { auto e1 = createEnv(null, false); assert (e1 != null && *e1 == null); auto e2 = createEnv(null, true); assert (e2 != null); int i = 0; for (; environ[i] != null; ++i) { assert (e2[i] != null); import core.stdc.string; assert (strcmp(e2[i], environ[i]) == 0); } assert (e2[i] == null); auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false); assert (e3 != null && e3[0] != null && e3[1] != null && e3[2] == null); assert ((e3[0][0 .. 8] == "foo=bar\0" && e3[1][0 .. 12] == "hello=world\0") || (e3[0][0 .. 12] == "hello=world\0" && e3[1][0 .. 8] == "foo=bar\0")); } // Converts childEnv to a Windows environment block, which is on the form // "name1=value1\0name2=value2\0...nameN=valueN\0\0", optionally adding // those of the current process' environment strings that are not present // in childEnv. Returns null if the parent's environment should be // inherited without modification, as this is what is expected by // CreateProcess(). version (Windows) private LPVOID createEnv(const string[string] childEnv, bool mergeWithParentEnv) { if (mergeWithParentEnv && childEnv.length == 0) return null; import std.array : appender; import std.uni : toUpper; auto envz = appender!(wchar[])(); void put(string var, string val) { envz.put(var); envz.put('='); envz.put(val); envz.put(cast(wchar) '\0'); } // Add the variables in childEnv, removing them from parentEnv // if they exist there too. auto parentEnv = mergeWithParentEnv ? environment.toAA() : null; foreach (k, v; childEnv) { auto uk = toUpper(k); put(uk, v); if (uk in parentEnv) parentEnv.remove(uk); } // Add remaining parent environment variables. foreach (k, v; parentEnv) put(k, v); // Two final zeros are needed in case there aren't any environment vars, // and the last one does no harm when there are. envz.put("\0\0"w); return envz.data.ptr; } version (Windows) unittest { assert (createEnv(null, true) == null); assert ((cast(wchar*) createEnv(null, false))[0 .. 2] == "\0\0"w); auto e1 = (cast(wchar*) createEnv(["foo":"bar", "ab":"c"], false))[0 .. 14]; assert (e1 == "FOO=bar\0AB=c\0\0"w || e1 == "AB=c\0FOO=bar\0\0"w); } // Searches the PATH variable for the given executable file, // (checking that it is in fact executable). version (Posix) private string searchPathFor(in char[] executable) @trusted //TODO: @safe nothrow { import std.algorithm : splitter; auto pathz = core.stdc.stdlib.getenv("PATH"); if (pathz == null) return null; foreach (dir; splitter(to!string(pathz), ':')) { auto execPath = buildPath(dir, executable); if (isExecutable(execPath)) return execPath; } return null; } // Checks whether the file exists and can be executed by the // current user. version (Posix) private bool isExecutable(in char[] path) @trusted nothrow @nogc //TODO: @safe { return (access(path.tempCString(), X_OK) == 0); } version (Posix) unittest { import std.algorithm; auto lsPath = searchPathFor("ls"); assert (!lsPath.empty); assert (lsPath[0] == '/'); assert (lsPath.endsWith("ls")); auto unlikely = searchPathFor("lkmqwpoialhggyaofijadsohufoiqezm"); assert (unlikely is null, "Are you kidding me?"); } // Sets or unsets the FD_CLOEXEC flag on the given file descriptor. version (Posix) private void setCLOEXEC(int fd, bool on) { import core.sys.posix.fcntl; auto flags = fcntl(fd, F_GETFD); if (flags >= 0) { if (on) flags |= FD_CLOEXEC; else flags &= ~(cast(typeof(flags)) FD_CLOEXEC); flags = fcntl(fd, F_SETFD, flags); } assert (flags != -1 || .errno == EBADF); } unittest // Command line arguments in spawnProcess(). { version (Windows) TestScript prog = "if not [%~1]==[foo] ( exit 1 ) if not [%~2]==[bar] ( exit 2 ) exit 0"; else version (Posix) TestScript prog = `if test "$1" != "foo"; then exit 1; fi if test "$2" != "bar"; then exit 2; fi exit 0`; assert (wait(spawnProcess(prog.path)) == 1); assert (wait(spawnProcess([prog.path])) == 1); assert (wait(spawnProcess([prog.path, "foo"])) == 2); assert (wait(spawnProcess([prog.path, "foo", "baz"])) == 2); assert (wait(spawnProcess([prog.path, "foo", "bar"])) == 0); } unittest // Environment variables in spawnProcess(). { // We really should use set /a on Windows, but Wine doesn't support it. version (Windows) TestScript envProg = `if [%STD_PROCESS_UNITTEST1%] == [1] ( if [%STD_PROCESS_UNITTEST2%] == [2] (exit 3) exit 1 ) if [%STD_PROCESS_UNITTEST1%] == [4] ( if [%STD_PROCESS_UNITTEST2%] == [2] (exit 6) exit 4 ) if [%STD_PROCESS_UNITTEST2%] == [2] (exit 2) exit 0`; version (Posix) TestScript envProg = `if test "$std_process_unittest1" = ""; then std_process_unittest1=0 fi if test "$std_process_unittest2" = ""; then std_process_unittest2=0 fi exit $(($std_process_unittest1+$std_process_unittest2))`; environment.remove("std_process_unittest1"); // Just in case. environment.remove("std_process_unittest2"); assert (wait(spawnProcess(envProg.path)) == 0); assert (wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0); environment["std_process_unittest1"] = "1"; assert (wait(spawnProcess(envProg.path)) == 1); assert (wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0); auto env = ["std_process_unittest2" : "2"]; assert (wait(spawnProcess(envProg.path, env)) == 3); assert (wait(spawnProcess(envProg.path, env, Config.newEnv)) == 2); env["std_process_unittest1"] = "4"; assert (wait(spawnProcess(envProg.path, env)) == 6); assert (wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6); environment.remove("std_process_unittest1"); assert (wait(spawnProcess(envProg.path, env)) == 6); assert (wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6); } unittest // Stream redirection in spawnProcess(). { import std.string; version (Windows) TestScript prog = "set /p INPUT= echo %INPUT% output %~1 echo %INPUT% error %~2 1>&2"; else version (Posix) TestScript prog = "read INPUT echo $INPUT output $1 echo $INPUT error $2 >&2"; // Pipes auto pipei = pipe(); auto pipeo = pipe(); auto pipee = pipe(); auto pid = spawnProcess([prog.path, "foo", "bar"], pipei.readEnd, pipeo.writeEnd, pipee.writeEnd); pipei.writeEnd.writeln("input"); pipei.writeEnd.flush(); assert (pipeo.readEnd.readln().chomp() == "input output foo"); assert (pipee.readEnd.readln().chomp().stripRight() == "input error bar"); wait(pid); // Files import std.ascii, std.file, std.uuid; auto pathi = buildPath(tempDir(), randomUUID().toString()); auto patho = buildPath(tempDir(), randomUUID().toString()); auto pathe = buildPath(tempDir(), randomUUID().toString()); std.file.write(pathi, "INPUT"~std.ascii.newline); auto filei = File(pathi, "r"); auto fileo = File(patho, "w"); auto filee = File(pathe, "w"); pid = spawnProcess([prog.path, "bar", "baz" ], filei, fileo, filee); wait(pid); assert (readText(patho).chomp() == "INPUT output bar"); assert (readText(pathe).chomp().stripRight() == "INPUT error baz"); remove(pathi); remove(patho); remove(pathe); } unittest // Error handling in spawnProcess() { assertThrown!ProcessException(spawnProcess("ewrgiuhrifuheiohnmnvqweoijwf")); assertThrown!ProcessException(spawnProcess("./rgiuhrifuheiohnmnvqweoijwf")); } unittest // Specifying a working directory. { TestScript prog = "echo foo>bar"; auto directory = uniqueTempPath(); mkdir(directory); scope(exit) rmdirRecurse(directory); auto pid = spawnProcess([prog.path], null, Config.none, directory); wait(pid); assert(exists(buildPath(directory, "bar"))); } unittest // Specifying a bad working directory. { TestScript prog = "echo"; auto directory = uniqueTempPath(); assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory)); std.file.write(directory, "foo"); scope(exit) remove(directory); assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory)); } unittest // Specifying empty working directory. { TestScript prog = ""; string directory = ""; assert(directory.ptr && !directory.length); spawnProcess([prog.path], null, Config.none, directory).wait(); } unittest // Reopening the standard streams (issue 13258) { import std.string; void fun() { spawnShell("echo foo").wait(); spawnShell("echo bar").wait(); } auto tmpFile = uniqueTempPath(); scope(exit) if (exists(tmpFile)) remove(tmpFile); { auto oldOut = std.stdio.stdout; scope(exit) std.stdio.stdout = oldOut; std.stdio.stdout = File(tmpFile, "w"); fun(); std.stdio.stdout.close(); } auto lines = readText(tmpFile).splitLines(); assert(lines == ["foo", "bar"]); } version (Windows) unittest // MSVCRT workaround (issue 14422) { auto fn = uniqueTempPath(); std.file.write(fn, "AAAAAAAAAA"); auto f = File(fn, "a"); spawnProcess(["cmd", "/c", "echo BBBBB"], std.stdio.stdin, f).wait(); auto data = readText(fn); assert(data == "AAAAAAAAAABBBBB\r\n", data); } /** A variation on $(LREF spawnProcess) that runs the given _command through the current user's preferred _command interpreter (aka. shell). The string $(D command) is passed verbatim to the shell, and is therefore subject to its rules about _command structure, argument/filename quoting and escaping of special characters. The path to the shell executable defaults to $(LREF nativeShell). In all other respects this function works just like $(D spawnProcess). Please refer to the $(LREF spawnProcess) documentation for descriptions of the other function parameters, the return value and any exceptions that may be thrown. --- // Run the command/program "foo" on the file named "my file.txt", and // redirect its output into foo.log. auto pid = spawnShell(`foo "my file.txt" > foo.log`); wait(pid); --- See_also: $(LREF escapeShellCommand), which may be helpful in constructing a properly quoted and escaped shell _command line for the current platform. */ Pid spawnShell(in char[] command, File stdin = std.stdio.stdin, File stdout = std.stdio.stdout, File stderr = std.stdio.stderr, const string[string] env = null, Config config = Config.none, in char[] workDir = null, string shellPath = nativeShell) @trusted // TODO: Should be @safe { version (Windows) { // CMD does not parse its arguments like other programs. // It does not use CommandLineToArgvW. // Instead, it treats the first and last quote specially. // See CMD.EXE /? for details. auto args = escapeShellFileName(shellPath) ~ ` ` ~ shellSwitch ~ ` "` ~ command ~ `"`; } else version (Posix) { const(char)[][3] args; args[0] = shellPath; args[1] = shellSwitch; args[2] = command; } return spawnProcessImpl(args, stdin, stdout, stderr, env, config, workDir); } /// ditto Pid spawnShell(in char[] command, const string[string] env, Config config = Config.none, in char[] workDir = null, string shellPath = nativeShell) @trusted // TODO: Should be @safe { return spawnShell(command, std.stdio.stdin, std.stdio.stdout, std.stdio.stderr, env, config, workDir, shellPath); } unittest { version (Windows) auto cmd = "echo %FOO%"; else version (Posix) auto cmd = "echo $foo"; import std.file; auto tmpFile = uniqueTempPath(); scope(exit) if (exists(tmpFile)) remove(tmpFile); auto redir = "> \""~tmpFile~'"'; auto env = ["foo" : "bar"]; assert (wait(spawnShell(cmd~redir, env)) == 0); auto f = File(tmpFile, "a"); version(CRuntime_Microsoft) f.seek(0, SEEK_END); // MSVCRT probably seeks to the end when writing, not before assert (wait(spawnShell(cmd, std.stdio.stdin, f, std.stdio.stderr, env)) == 0); f.close(); auto output = std.file.readText(tmpFile); assert (output == "bar\nbar\n" || output == "bar\r\nbar\r\n"); } version (Windows) unittest { import std.string; TestScript prog = "echo %0 %*"; auto outputFn = uniqueTempPath(); scope(exit) if (exists(outputFn)) remove(outputFn); auto args = [`a b c`, `a\b\c\`, `a"b"c"`]; auto result = executeShell( escapeShellCommand([prog.path] ~ args) ~ " > " ~ escapeShellFileName(outputFn)); assert(result.status == 0); auto args2 = outputFn.readText().strip().parseCommandLine()[1..$]; assert(args == args2, text(args2)); } /** Flags that control the behaviour of $(LREF spawnProcess) and $(LREF spawnShell). Use bitwise OR to combine flags. Example: --- auto logFile = File("myapp_error.log", "w"); // Start program, suppressing the console window (Windows only), // redirect its error stream to logFile, and leave logFile open // in the parent process as well. auto pid = spawnProcess("myapp", stdin, stdout, logFile, Config.retainStderr | Config.suppressConsole); scope(exit) { auto exitCode = wait(pid); logFile.writeln("myapp exited with code ", exitCode); logFile.close(); } --- */ enum Config { none = 0, /** By default, the child process inherits the parent's environment, and any environment variables passed to $(LREF spawnProcess) will be added to it. If this flag is set, the only variables in the child process' environment will be those given to spawnProcess. */ newEnv = 1, /** Unless the child process inherits the standard input/output/error streams of its parent, one almost always wants the streams closed in the parent when $(LREF spawnProcess) returns. Therefore, by default, this is done. If this is not desirable, pass any of these options to spawnProcess. */ retainStdin = 2, retainStdout = 4, /// ditto retainStderr = 8, /// ditto /** On Windows, if the child process is a console application, this flag will prevent the creation of a console window. Otherwise, it will be ignored. On POSIX, $(D suppressConsole) has no effect. */ suppressConsole = 16, /** On POSIX, open $(LINK2 http://en.wikipedia.org/wiki/File_descriptor,file descriptors) are by default inherited by the child process. As this may lead to subtle bugs when pipes or multiple threads are involved, $(LREF spawnProcess) ensures that all file descriptors except the ones that correspond to standard input/output/error are closed in the child process when it starts. Use $(D inheritFDs) to prevent this. On Windows, this option has no effect, and any handles which have been explicitly marked as inheritable will always be inherited by the child process. */ inheritFDs = 32, } /// A handle that corresponds to a spawned process. final class Pid { /** The process ID number. This is a number that uniquely identifies the process on the operating system, for at least as long as the process is running. Once $(LREF wait) has been called on the $(LREF Pid), this method will return an invalid (negative) process ID. */ @property int processID() const @safe pure nothrow { return _processID; } /** An operating system handle to the process. This handle is used to specify the process in OS-specific APIs. On POSIX, this function returns a $(D core.sys.posix.sys.types.pid_t) with the same value as $(LREF Pid.processID), while on Windows it returns a $(D core.sys.windows.windows.HANDLE). Once $(LREF wait) has been called on the $(LREF Pid), this method will return an invalid handle. */ // Note: Since HANDLE is a reference, this function cannot be const. version (Windows) @property HANDLE osHandle() @safe pure nothrow { return _handle; } else version (Posix) @property pid_t osHandle() @safe pure nothrow { return _processID; } private: /* Pid.performWait() does the dirty work for wait() and nonBlockingWait(). If block == true, this function blocks until the process terminates, sets _processID to terminated, and returns the exit code or terminating signal as described in the wait() documentation. If block == false, this function returns immediately, regardless of the status of the process. If the process has terminated, the function has the exact same effect as the blocking version. If not, it returns 0 and does not modify _processID. */ version (Posix) int performWait(bool block) @trusted { if (_processID == terminated) return _exitCode; int exitCode; while(true) { int status; auto check = waitpid(_processID, &status, block ? 0 : WNOHANG); if (check == -1) { if (errno == ECHILD) { throw new ProcessException( "Process does not exist or is not a child process."); } else { // waitpid() was interrupted by a signal. We simply // restart it. assert (errno == EINTR); continue; } } if (!block && check == 0) return 0; if (WIFEXITED(status)) { exitCode = WEXITSTATUS(status); break; } else if (WIFSIGNALED(status)) { exitCode = -WTERMSIG(status); break; } // We check again whether the call should be blocking, // since we don't care about other status changes besides // "exited" and "terminated by signal". if (!block) return 0; // Process has stopped, but not terminated, so we continue waiting. } // Mark Pid as terminated, and cache and return exit code. _processID = terminated; _exitCode = exitCode; return exitCode; } else version (Windows) { int performWait(bool block) @trusted { if (_processID == terminated) return _exitCode; assert (_handle != INVALID_HANDLE_VALUE); if (block) { auto result = WaitForSingleObject(_handle, INFINITE); if (result != WAIT_OBJECT_0) throw ProcessException.newFromLastError("Wait failed."); } if (!GetExitCodeProcess(_handle, cast(LPDWORD)&_exitCode)) throw ProcessException.newFromLastError(); if (!block && _exitCode == STILL_ACTIVE) return 0; CloseHandle(_handle); _handle = INVALID_HANDLE_VALUE; _processID = terminated; return _exitCode; } ~this() { if(_handle != INVALID_HANDLE_VALUE) { CloseHandle(_handle); _handle = INVALID_HANDLE_VALUE; } } } // Special values for _processID. enum invalid = -1, terminated = -2; // OS process ID number. Only nonnegative IDs correspond to // running processes. int _processID = invalid; // Exit code cached by wait(). This is only expected to hold a // sensible value if _processID == terminated. int _exitCode; // Pids are only meant to be constructed inside this module, so // we make the constructor private. version (Windows) { HANDLE _handle = INVALID_HANDLE_VALUE; this(int pid, HANDLE handle) @safe pure nothrow { _processID = pid; _handle = handle; } } else { this(int id) @safe pure nothrow { _processID = id; } } } /** Waits for the process associated with $(D pid) to terminate, and returns its exit status. In general one should always _wait for child processes to terminate before exiting the parent process. Otherwise, they may become "$(WEB en.wikipedia.org/wiki/Zombie_process,zombies)" – processes that are defunct, yet still occupy a slot in the OS process table. If the process has already terminated, this function returns directly. The exit code is cached, so that if wait() is called multiple times on the same $(LREF Pid) it will always return the same value. POSIX_specific: If the process is terminated by a signal, this function returns a negative number whose absolute value is the signal number. Since POSIX restricts normal exit codes to the range 0-255, a negative return value will always indicate termination by signal. Signal codes are defined in the $(D core.sys.posix.signal) module (which corresponds to the $(D signal.h) POSIX header). Throws: $(LREF ProcessException) on failure. Example: See the $(LREF spawnProcess) documentation. See_also: $(LREF tryWait), for a non-blocking function. */ int wait(Pid pid) @safe { assert(pid !is null, "Called wait on a null Pid."); return pid.performWait(true); } unittest // Pid and wait() { version (Windows) TestScript prog = "exit %~1"; else version (Posix) TestScript prog = "exit $1"; assert (wait(spawnProcess([prog.path, "0"])) == 0); assert (wait(spawnProcess([prog.path, "123"])) == 123); auto pid = spawnProcess([prog.path, "10"]); assert (pid.processID > 0); version (Windows) assert (pid.osHandle != INVALID_HANDLE_VALUE); else version (Posix) assert (pid.osHandle == pid.processID); assert (wait(pid) == 10); assert (wait(pid) == 10); // cached exit code assert (pid.processID < 0); version (Windows) assert (pid.osHandle == INVALID_HANDLE_VALUE); else version (Posix) assert (pid.osHandle < 0); } /** A non-blocking version of $(LREF wait). If the process associated with $(D pid) has already terminated, $(D tryWait) has the exact same effect as $(D wait). In this case, it returns a tuple where the $(D terminated) field is set to $(D true) and the $(D status) field has the same interpretation as the return value of $(D wait). If the process has $(I not) yet terminated, this function differs from $(D wait) in that does not wait for this to happen, but instead returns immediately. The $(D terminated) field of the returned tuple will then be set to $(D false), while the $(D status) field will always be 0 (zero). $(D wait) or $(D tryWait) should then be called again on the same $(D Pid) at some later time; not only to get the exit code, but also to avoid the process becoming a "zombie" when it finally terminates. (See $(LREF wait) for details). Returns: An $(D std.typecons.Tuple!(bool, "terminated", int, "status")). Throws: $(LREF ProcessException) on failure. Example: --- auto pid = spawnProcess("dmd myapp.d"); scope(exit) wait(pid); ... auto dmd = tryWait(pid); if (dmd.terminated) { if (dmd.status == 0) writeln("Compilation succeeded!"); else writeln("Compilation failed"); } else writeln("Still compiling..."); ... --- Note that in this example, the first $(D wait) call will have no effect if the process has already terminated by the time $(D tryWait) is called. In the opposite case, however, the $(D scope) statement ensures that we always wait for the process if it hasn't terminated by the time we reach the end of the scope. */ auto tryWait(Pid pid) @safe { import std.typecons : Tuple; assert(pid !is null, "Called tryWait on a null Pid."); auto code = pid.performWait(false); return Tuple!(bool, "terminated", int, "status")(pid._processID == Pid.terminated, code); } // unittest: This function is tested together with kill() below. /** Attempts to terminate the process associated with $(D pid). The effect of this function, as well as the meaning of $(D codeOrSignal), is highly platform dependent. Details are given below. Common to all platforms is that this function only $(I initiates) termination of the process, and returns immediately. It does not wait for the process to end, nor does it guarantee that the process does in fact get terminated. Always call $(LREF wait) to wait for a process to complete, even if $(D kill) has been called on it. Windows_specific: The process will be $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.100%29.aspx, forcefully and abruptly terminated). If $(D codeOrSignal) is specified, it must be a nonnegative number which will be used as the exit code of the process. If not, the process wil exit with code 1. Do not use $(D codeOrSignal = 259), as this is a special value (aka. $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189.aspx,STILL_ACTIVE)) used by Windows to signal that a process has in fact $(I not) terminated yet. --- auto pid = spawnProcess("some_app"); kill(pid, 10); assert (wait(pid) == 10); --- POSIX_specific: A $(LINK2 http://en.wikipedia.org/wiki/Unix_signal,signal) will be sent to the process, whose value is given by $(D codeOrSignal). Depending on the signal sent, this may or may not terminate the process. Symbolic constants for various $(LINK2 http://en.wikipedia.org/wiki/Unix_signal#POSIX_signals, POSIX signals) are defined in $(D core.sys.posix.signal), which corresponds to the $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html, $(D signal.h) POSIX header). If $(D codeOrSignal) is omitted, the $(D SIGTERM) signal will be sent. (This matches the behaviour of the $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/kill.html, $(D _kill)) shell command.) --- import core.sys.posix.signal: SIGKILL; auto pid = spawnProcess("some_app"); kill(pid, SIGKILL); assert (wait(pid) == -SIGKILL); // Negative return value on POSIX! --- Throws: $(LREF ProcessException) on error (e.g. if codeOrSignal is invalid). Note that failure to terminate the process is considered a "normal" outcome, not an error.$(BR) */ void kill(Pid pid) { version (Windows) kill(pid, 1); else version (Posix) { import core.sys.posix.signal: SIGTERM; kill(pid, SIGTERM); } } /// ditto void kill(Pid pid, int codeOrSignal) { version (Windows) { if (codeOrSignal < 0) throw new ProcessException("Invalid exit code"); // On Windows, TerminateProcess() appears to terminate the // *current* process if it is passed an invalid handle... if (pid.osHandle == INVALID_HANDLE_VALUE) throw new ProcessException("Invalid process handle"); if (!TerminateProcess(pid.osHandle, codeOrSignal)) throw ProcessException.newFromLastError(); } else version (Posix) { import core.sys.posix.signal : kill; if (kill(pid.osHandle, codeOrSignal) == -1) throw ProcessException.newFromErrno(); } } unittest // tryWait() and kill() { import core.thread; // The test script goes into an infinite loop. version (Windows) { TestScript prog = ":loop goto loop"; } else version (Posix) { import core.sys.posix.signal: SIGTERM, SIGKILL; TestScript prog = "while true; do sleep 1; done"; } auto pid = spawnProcess(prog.path); // Android appears to automatically kill sleeping processes very quickly, // so shorten the wait before killing here. version (Android) Thread.sleep(dur!"msecs"(5)); else Thread.sleep(dur!"seconds"(1)); kill(pid); version (Windows) assert (wait(pid) == 1); else version (Posix) assert (wait(pid) == -SIGTERM); pid = spawnProcess(prog.path); Thread.sleep(dur!"seconds"(1)); auto s = tryWait(pid); assert (!s.terminated && s.status == 0); assertThrown!ProcessException(kill(pid, -123)); // Negative code not allowed. version (Windows) kill(pid, 123); else version (Posix) kill(pid, SIGKILL); do { s = tryWait(pid); } while (!s.terminated); version (Windows) assert (s.status == 123); else version (Posix) assert (s.status == -SIGKILL); assertThrown!ProcessException(kill(pid)); } /** Creates a unidirectional _pipe. Data is written to one end of the _pipe and read from the other. --- auto p = pipe(); p.writeEnd.writeln("Hello World"); p.writeEnd.flush(); assert (p.readEnd.readln().chomp() == "Hello World"); --- Pipes can, for example, be used for interprocess communication by spawning a new process and passing one end of the _pipe to the child, while the parent uses the other end. (See also $(LREF pipeProcess) and $(LREF pipeShell) for an easier way of doing this.) --- // Use cURL to download the dlang.org front page, pipe its // output to grep to extract a list of links to ZIP files, // and write the list to the file "D downloads.txt": auto p = pipe(); auto outFile = File("D downloads.txt", "w"); auto cpid = spawnProcess(["curl", "http://dlang.org/download.html"], std.stdio.stdin, p.writeEnd); scope(exit) wait(cpid); auto gpid = spawnProcess(["grep", "-o", `http://\S*\.zip`], p.readEnd, outFile); scope(exit) wait(gpid); --- Returns: A $(LREF Pipe) object that corresponds to the created _pipe. Throws: $(XREF stdio,StdioException) on failure. */ version (Posix) Pipe pipe() @trusted //TODO: @safe { int[2] fds; if (core.sys.posix.unistd.pipe(fds) != 0) throw new StdioException("Unable to create pipe"); Pipe p; auto readFP = fdopen(fds[0], "r"); if (readFP == null) throw new StdioException("Cannot open read end of pipe"); p._read = File(readFP, null); auto writeFP = fdopen(fds[1], "w"); if (writeFP == null) throw new StdioException("Cannot open write end of pipe"); p._write = File(writeFP, null); return p; } else version (Windows) Pipe pipe() @trusted //TODO: @safe { // use CreatePipe to create an anonymous pipe HANDLE readHandle; HANDLE writeHandle; if (!CreatePipe(&readHandle, &writeHandle, null, 0)) { throw new StdioException( "Error creating pipe (" ~ sysErrorString(GetLastError()) ~ ')', 0); } scope(failure) { CloseHandle(readHandle); CloseHandle(writeHandle); } try { Pipe p; p._read .windowsHandleOpen(readHandle , "r"); p._write.windowsHandleOpen(writeHandle, "a"); return p; } catch (Exception e) { throw new StdioException("Error attaching pipe (" ~ e.msg ~ ")", 0); } } /// An interface to a pipe created by the $(LREF pipe) function. struct Pipe { /// The read end of the pipe. @property File readEnd() @safe nothrow { return _read; } /// The write end of the pipe. @property File writeEnd() @safe nothrow { return _write; } /** Closes both ends of the pipe. Normally it is not necessary to do this manually, as $(XREF stdio,File) objects are automatically closed when there are no more references to them. Note that if either end of the pipe has been passed to a child process, it will only be closed in the parent process. (What happens in the child process is platform dependent.) Throws: $(XREF exception,ErrnoException) if an error occurs. */ void close() @safe { _read.close(); _write.close(); } private: File _read, _write; } unittest { import std.string; auto p = pipe(); p.writeEnd.writeln("Hello World"); p.writeEnd.flush(); assert (p.readEnd.readln().chomp() == "Hello World"); p.close(); assert (!p.readEnd.isOpen); assert (!p.writeEnd.isOpen); } /** Starts a new process, creating pipes to redirect its standard input, output and/or error streams. $(D pipeProcess) and $(D pipeShell) are convenient wrappers around $(LREF spawnProcess) and $(LREF spawnShell), respectively, and automate the task of redirecting one or more of the child process' standard streams through pipes. Like the functions they wrap, these functions return immediately, leaving the child process to execute in parallel with the invoking process. It is recommended to always call $(LREF wait) on the returned $(LREF ProcessPipes.pid), as detailed in the documentation for $(D wait). The $(D args)/$(D program)/$(D command), $(D env) and $(D config) parameters are forwarded straight to the underlying spawn functions, and we refer to their documentation for details. Params: args = An array which contains the program name as the zeroth element and any command-line arguments in the following elements. (See $(LREF spawnProcess) for details.) program = The program name, $(I without) command-line arguments. (See $(LREF spawnProcess) for details.) command = A shell command which is passed verbatim to the command interpreter. (See $(LREF spawnShell) for details.) redirect = Flags that determine which streams are redirected, and how. See $(LREF Redirect) for an overview of available flags. env = Additional environment variables for the child process. (See $(LREF spawnProcess) for details.) config = Flags that control process creation. See $(LREF Config) for an overview of available flags, and note that the $(D retainStd...) flags have no effect in this function. workDir = The working directory for the new process. By default the child process inherits the parent's working directory. shellPath = The path to the shell to use to run the specified program. By default this is $(LREF nativeShell). Returns: A $(LREF ProcessPipes) object which contains $(XREF stdio,File) handles that communicate with the redirected streams of the child process, along with a $(LREF Pid) object that corresponds to the spawned process. Throws: $(LREF ProcessException) on failure to start the process.$(BR) $(XREF stdio,StdioException) on failure to redirect any of the streams.$(BR) Example: --- // my_application writes to stdout and might write to stderr auto pipes = pipeProcess("my_application", Redirect.stdout | Redirect.stderr); scope(exit) wait(pipes.pid); // Store lines of output. string[] output; foreach (line; pipes.stdout.byLine) output ~= line.idup; // Store lines of errors. string[] errors; foreach (line; pipes.stderr.byLine) errors ~= line.idup; // sendmail expects to read from stdin pipes = pipeProcess(["/usr/bin/sendmail", "-t"], Redirect.stdin); pipes.stdin.writeln("To: you"); pipes.stdin.writeln("From: me"); pipes.stdin.writeln("Subject: dlang"); pipes.stdin.writeln(""); pipes.stdin.writeln(message); // a single period tells sendmail we are finished pipes.stdin.writeln("."); // but at this point sendmail might not see it, we need to flush pipes.stdin.flush(); // sendmail happens to exit on ".", but some you have to close the file: pipes.stdin.close(); // otherwise this wait will wait forever wait(pipes.pid); --- */ ProcessPipes pipeProcess(in char[][] args, Redirect redirect = Redirect.all, const string[string] env = null, Config config = Config.none, in char[] workDir = null) @safe { return pipeProcessImpl!spawnProcess(args, redirect, env, config, workDir); } /// ditto ProcessPipes pipeProcess(in char[] program, Redirect redirect = Redirect.all, const string[string] env = null, Config config = Config.none, in char[] workDir = null) @safe { return pipeProcessImpl!spawnProcess(program, redirect, env, config, workDir); } /// ditto ProcessPipes pipeShell(in char[] command, Redirect redirect = Redirect.all, const string[string] env = null, Config config = Config.none, in char[] workDir = null, string shellPath = nativeShell) @safe { return pipeProcessImpl!spawnShell(command, redirect, env, config, workDir, shellPath); } // Implementation of the pipeProcess() family of functions. private ProcessPipes pipeProcessImpl(alias spawnFunc, Cmd, ExtraSpawnFuncArgs...) (Cmd command, Redirect redirectFlags, const string[string] env = null, Config config = Config.none, in char[] workDir = null, ExtraSpawnFuncArgs extraArgs = ExtraSpawnFuncArgs.init) @trusted //TODO: @safe { File childStdin, childStdout, childStderr; ProcessPipes pipes; pipes._redirectFlags = redirectFlags; if (redirectFlags & Redirect.stdin) { auto p = pipe(); childStdin = p.readEnd; pipes._stdin = p.writeEnd; } else { childStdin = std.stdio.stdin; } if (redirectFlags & Redirect.stdout) { if ((redirectFlags & Redirect.stdoutToStderr) != 0) throw new StdioException("Cannot create pipe for stdout AND " ~"redirect it to stderr", 0); auto p = pipe(); childStdout = p.writeEnd; pipes._stdout = p.readEnd; } else { childStdout = std.stdio.stdout; } if (redirectFlags & Redirect.stderr) { if ((redirectFlags & Redirect.stderrToStdout) != 0) throw new StdioException("Cannot create pipe for stderr AND " ~"redirect it to stdout", 0); auto p = pipe(); childStderr = p.writeEnd; pipes._stderr = p.readEnd; } else { childStderr = std.stdio.stderr; } if (redirectFlags & Redirect.stdoutToStderr) { if (redirectFlags & Redirect.stderrToStdout) { // We know that neither of the other options have been // set, so we assign the std.stdio.std* streams directly. childStdout = std.stdio.stderr; childStderr = std.stdio.stdout; } else { childStdout = childStderr; } } else if (redirectFlags & Redirect.stderrToStdout) { childStderr = childStdout; } config &= ~(Config.retainStdin | Config.retainStdout | Config.retainStderr); pipes._pid = spawnFunc(command, childStdin, childStdout, childStderr, env, config, workDir, extraArgs); return pipes; } /** Flags that can be passed to $(LREF pipeProcess) and $(LREF pipeShell) to specify which of the child process' standard streams are redirected. Use bitwise OR to combine flags. */ enum Redirect { /// Redirect the standard input, output or error streams, respectively. stdin = 1, stdout = 2, /// ditto stderr = 4, /// ditto /** Redirect _all three streams. This is equivalent to $(D Redirect.stdin | Redirect.stdout | Redirect.stderr). */ all = stdin | stdout | stderr, /** Redirect the standard error stream into the standard output stream. This can not be combined with $(D Redirect.stderr). */ stderrToStdout = 8, /** Redirect the standard output stream into the standard error stream. This can not be combined with $(D Redirect.stdout). */ stdoutToStderr = 16, } unittest { import std.string; version (Windows) TestScript prog = "call :sub %~1 %~2 0 call :sub %~1 %~2 1 call :sub %~1 %~2 2 call :sub %~1 %~2 3 exit 3 :sub set /p INPUT= if -%INPUT%-==-stop- ( exit %~3 ) echo %INPUT% %~1 echo %INPUT% %~2 1>&2"; else version (Posix) TestScript prog = `for EXITCODE in 0 1 2 3; do read INPUT if test "$INPUT" = stop; then break; fi echo "$INPUT $1" echo "$INPUT $2" >&2 done exit $EXITCODE`; auto pp = pipeProcess([prog.path, "bar", "baz"]); pp.stdin.writeln("foo"); pp.stdin.flush(); assert (pp.stdout.readln().chomp() == "foo bar"); assert (pp.stderr.readln().chomp().stripRight() == "foo baz"); pp.stdin.writeln("1234567890"); pp.stdin.flush(); assert (pp.stdout.readln().chomp() == "1234567890 bar"); assert (pp.stderr.readln().chomp().stripRight() == "1234567890 baz"); pp.stdin.writeln("stop"); pp.stdin.flush(); assert (wait(pp.pid) == 2); pp = pipeProcess([prog.path, "12345", "67890"], Redirect.stdin | Redirect.stdout | Redirect.stderrToStdout); pp.stdin.writeln("xyz"); pp.stdin.flush(); assert (pp.stdout.readln().chomp() == "xyz 12345"); assert (pp.stdout.readln().chomp().stripRight() == "xyz 67890"); pp.stdin.writeln("stop"); pp.stdin.flush(); assert (wait(pp.pid) == 1); pp = pipeShell(escapeShellCommand(prog.path, "AAAAA", "BBB"), Redirect.stdin | Redirect.stdoutToStderr | Redirect.stderr); pp.stdin.writeln("ab"); pp.stdin.flush(); assert (pp.stderr.readln().chomp() == "ab AAAAA"); assert (pp.stderr.readln().chomp().stripRight() == "ab BBB"); pp.stdin.writeln("stop"); pp.stdin.flush(); assert (wait(pp.pid) == 1); } unittest { TestScript prog = "exit 0"; assertThrown!StdioException(pipeProcess( prog.path, Redirect.stdout | Redirect.stdoutToStderr)); assertThrown!StdioException(pipeProcess( prog.path, Redirect.stderr | Redirect.stderrToStdout)); auto p = pipeProcess(prog.path, Redirect.stdin); assertThrown!Error(p.stdout); assertThrown!Error(p.stderr); wait(p.pid); p = pipeProcess(prog.path, Redirect.stderr); assertThrown!Error(p.stdin); assertThrown!Error(p.stdout); wait(p.pid); } /** Object which contains $(XREF stdio,File) handles that allow communication with a child process through its standard streams. */ struct ProcessPipes { /// The $(LREF Pid) of the child process. @property Pid pid() @safe nothrow { assert(_pid !is null); return _pid; } /** An $(XREF stdio,File) that allows writing to the child process' standard input stream. Throws: $(OBJECTREF Error) if the child process' standard input stream hasn't been redirected. */ @property File stdin() @safe nothrow { if ((_redirectFlags & Redirect.stdin) == 0) throw new Error("Child process' standard input stream hasn't " ~"been redirected."); return _stdin; } /** An $(XREF stdio,File) that allows reading from the child process' standard output stream. Throws: $(OBJECTREF Error) if the child process' standard output stream hasn't been redirected. */ @property File stdout() @safe nothrow { if ((_redirectFlags & Redirect.stdout) == 0) throw new Error("Child process' standard output stream hasn't " ~"been redirected."); return _stdout; } /** An $(XREF stdio,File) that allows reading from the child process' standard error stream. Throws: $(OBJECTREF Error) if the child process' standard error stream hasn't been redirected. */ @property File stderr() @safe nothrow { if ((_redirectFlags & Redirect.stderr) == 0) throw new Error("Child process' standard error stream hasn't " ~"been redirected."); return _stderr; } private: Redirect _redirectFlags; Pid _pid; File _stdin, _stdout, _stderr; } /** Executes the given program or shell command and returns its exit code and output. $(D execute) and $(D executeShell) start a new process using $(LREF spawnProcess) and $(LREF spawnShell), respectively, and wait for the process to complete before returning. The functions capture what the child process prints to both its standard output and standard error streams, and return this together with its exit code. --- auto dmd = execute(["dmd", "myapp.d"]); if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output); auto ls = executeShell("ls -l"); if (ls.status != 0) writeln("Failed to retrieve file listing"); else writeln(ls.output); --- The $(D args)/$(D program)/$(D command), $(D env) and $(D config) parameters are forwarded straight to the underlying spawn functions, and we refer to their documentation for details. Params: args = An array which contains the program name as the zeroth element and any command-line arguments in the following elements. (See $(LREF spawnProcess) for details.) program = The program name, $(I without) command-line arguments. (See $(LREF spawnProcess) for details.) command = A shell command which is passed verbatim to the command interpreter. (See $(LREF spawnShell) for details.) env = Additional environment variables for the child process. (See $(LREF spawnProcess) for details.) config = Flags that control process creation. See $(LREF Config) for an overview of available flags, and note that the $(D retainStd...) flags have no effect in this function. maxOutput = The maximum number of bytes of output that should be captured. workDir = The working directory for the new process. By default the child process inherits the parent's working directory. shellPath = The path to the shell to use to run the specified program. By default this is $(LREF nativeShell). Returns: An $(D std.typecons.Tuple!(int, "status", string, "output")). POSIX_specific: If the process is terminated by a signal, the $(D status) field of the return value will contain a negative number whose absolute value is the signal number. (See $(LREF wait) for details.) Throws: $(LREF ProcessException) on failure to start the process.$(BR) $(XREF stdio,StdioException) on failure to capture output. */ auto execute(in char[][] args, const string[string] env = null, Config config = Config.none, size_t maxOutput = size_t.max, in char[] workDir = null) @trusted //TODO: @safe { return executeImpl!pipeProcess(args, env, config, maxOutput, workDir); } /// ditto auto execute(in char[] program, const string[string] env = null, Config config = Config.none, size_t maxOutput = size_t.max, in char[] workDir = null) @trusted //TODO: @safe { return executeImpl!pipeProcess(program, env, config, maxOutput, workDir); } /// ditto auto executeShell(in char[] command, const string[string] env = null, Config config = Config.none, size_t maxOutput = size_t.max, in char[] workDir = null, string shellPath = nativeShell) @trusted //TODO: @safe { return executeImpl!pipeShell(command, env, config, maxOutput, workDir, shellPath); } // Does the actual work for execute() and executeShell(). private auto executeImpl(alias pipeFunc, Cmd, ExtraPipeFuncArgs...)( Cmd commandLine, const string[string] env = null, Config config = Config.none, size_t maxOutput = size_t.max, in char[] workDir = null, ExtraPipeFuncArgs extraArgs = ExtraPipeFuncArgs.init) { import std.string; import std.typecons : Tuple; import std.array : appender; import std.algorithm : min; auto p = pipeFunc(commandLine, Redirect.stdout | Redirect.stderrToStdout, env, config, workDir, extraArgs); auto a = appender!(ubyte[])(); enum size_t defaultChunkSize = 4096; immutable chunkSize = min(maxOutput, defaultChunkSize); // Store up to maxOutput bytes in a. foreach (ubyte[] chunk; p.stdout.byChunk(chunkSize)) { immutable size_t remain = maxOutput - a.data.length; if (chunk.length < remain) a.put(chunk); else { a.put(chunk[0 .. remain]); break; } } // Exhaust the stream, if necessary. foreach (ubyte[] chunk; p.stdout.byChunk(defaultChunkSize)) { } return Tuple!(int, "status", string, "output")(wait(p.pid), cast(string) a.data); } unittest { import std.string; // To avoid printing the newline characters, we use the echo|set trick on // Windows, and printf on POSIX (neither echo -n nor echo \c are portable). version (Windows) TestScript prog = "echo|set /p=%~1 echo|set /p=%~2 1>&2 exit 123"; else version (Android) TestScript prog = `echo -n $1 echo -n $2 >&2 exit 123`; else version (Posix) TestScript prog = `printf '%s' $1 printf '%s' $2 >&2 exit 123`; auto r = execute([prog.path, "foo", "bar"]); assert (r.status == 123); assert (r.output.stripRight() == "foobar"); auto s = execute([prog.path, "Hello", "World"]); assert (s.status == 123); assert (s.output.stripRight() == "HelloWorld"); } unittest { import std.string; auto r1 = executeShell("echo foo"); assert (r1.status == 0); assert (r1.output.chomp() == "foo"); auto r2 = executeShell("echo bar 1>&2"); assert (r2.status == 0); assert (r2.output.chomp().stripRight() == "bar"); auto r3 = executeShell("exit 123"); assert (r3.status == 123); assert (r3.output.empty); } unittest { import std.typecons : Tuple; void foo() //Just test the compilation { auto ret1 = execute(["dummy", "arg"]); auto ret2 = executeShell("dummy arg"); static assert(is(typeof(ret1) == typeof(ret2))); Tuple!(int, string) ret3 = execute(["dummy", "arg"]); } } /// An exception that signals a problem with starting or waiting for a process. class ProcessException : Exception { mixin basicExceptionCtors; // Creates a new ProcessException based on errno. static ProcessException newFromErrno(string customMsg = null, string file = __FILE__, size_t line = __LINE__) { import core.stdc.errno; import core.stdc.string; version (CRuntime_Glibc) { char[1024] buf; auto errnoMsg = to!string( core.stdc.string.strerror_r(errno, buf.ptr, buf.length)); } else { auto errnoMsg = to!string(core.stdc.string.strerror(errno)); } auto msg = customMsg.empty ? errnoMsg : customMsg ~ " (" ~ errnoMsg ~ ')'; return new ProcessException(msg, file, line); } // Creates a new ProcessException based on GetLastError() (Windows only). version (Windows) static ProcessException newFromLastError(string customMsg = null, string file = __FILE__, size_t line = __LINE__) { auto lastMsg = sysErrorString(GetLastError()); auto msg = customMsg.empty ? lastMsg : customMsg ~ " (" ~ lastMsg ~ ')'; return new ProcessException(msg, file, line); } } /** Determines the path to the current user's preferred command interpreter. On Windows, this function returns the contents of the COMSPEC environment variable, if it exists. Otherwise, it returns the result of $(LREF nativeShell). On POSIX, $(D userShell) returns the contents of the SHELL environment variable, if it exists and is non-empty. Otherwise, it returns the result of $(LREF nativeShell). */ @property string userShell() @safe { version (Windows) return environment.get("COMSPEC", nativeShell); else version (Posix) return environment.get("SHELL", nativeShell); } /** The platform-specific native shell path. This function returns $(D "cmd.exe") on Windows, $(D "/bin/sh") on POSIX, and $(D "/system/bin/sh") on Android. */ @property string nativeShell() @safe @nogc pure nothrow { version (Windows) return "cmd.exe"; else version (Android) return "/system/bin/sh"; else version (Posix) return "/bin/sh"; } // A command-line switch that indicates to the shell that it should // interpret the following argument as a command to be executed. version (Posix) private immutable string shellSwitch = "-c"; version (Windows) private immutable string shellSwitch = "/C"; /** * Returns the process ID of the current process, * which is guaranteed to be unique on the system. * * Example: * --- * writefln("Current process ID: %d", thisProcessID); * --- */ @property int thisProcessID() @trusted nothrow //TODO: @safe { version (Windows) return GetCurrentProcessId(); else version (Posix) return core.sys.posix.unistd.getpid(); } /** * Returns the process ID of the current thread, * which is guaranteed to be unique within the current process. * * Returns: * A $(CXREF thread, ThreadID) value for the calling thread. * * Example: * --- * writefln("Current thread ID: %s", thisThreadID); * --- */ @property ThreadID thisThreadID() @trusted nothrow //TODO: @safe { version (Windows) return GetCurrentThreadId(); else version (Posix) { import core.sys.posix.pthread; return pthread_self(); } } unittest { int pidA, pidB; ThreadID tidA, tidB; pidA = thisProcessID; tidA = thisThreadID; import core.thread; auto t = new Thread({ pidB = thisProcessID; tidB = thisThreadID; }); t.start(); t.join(); assert(pidA == pidB); assert(tidA != tidB); } // Unittest support code: TestScript takes a string that contains a // shell script for the current platform, and writes it to a temporary // file. On Windows the file name gets a .cmd extension, while on // POSIX its executable permission bit is set. The file is // automatically deleted when the object goes out of scope. version (unittest) private struct TestScript { this(string code) { import std.ascii, std.file; version (Windows) { auto ext = ".cmd"; auto firstLine = "@echo off"; } else version (Posix) { auto ext = ""; auto firstLine = "#!" ~ nativeShell; } path = uniqueTempPath()~ext; std.file.write(path, firstLine~std.ascii.newline~code~std.ascii.newline); version (Posix) { import core.sys.posix.sys.stat; chmod(path.tempCString(), octal!777); } } ~this() { import std.file; if (!path.empty && exists(path)) { try { remove(path); } catch (Exception e) { debug std.stdio.stderr.writeln(e.msg); } } } string path; } version (unittest) private string uniqueTempPath() { import std.file, std.uuid; // Path should contain spaces to test escaping whitespace return buildPath(tempDir(), "std.process temporary file " ~ randomUUID().toString()); } // ============================================================================= // Functions for shell command quoting/escaping. // ============================================================================= /* Command line arguments exist in three forms: 1) string or char* array, as received by main. Also used internally on POSIX systems. 2) Command line string, as used in Windows' CreateProcess and CommandLineToArgvW functions. A specific quoting and escaping algorithm is used to distinguish individual arguments. 3) Shell command string, as written at a shell prompt or passed to cmd /C - this one may contain shell control characters, e.g. > or | for redirection / piping - thus, yet another layer of escaping is used to distinguish them from program arguments. Except for escapeWindowsArgument, the intermediary format (2) is hidden away from the user in this module. */ /** Escapes an argv-style argument array to be used with $(LREF spawnShell), $(LREF pipeShell) or $(LREF executeShell). --- string url = "http://dlang.org/"; executeShell(escapeShellCommand("wget", url, "-O", "dlang-index.html")); --- Concatenate multiple $(D escapeShellCommand) and $(LREF escapeShellFileName) results to use shell redirection or piping operators. --- executeShell( escapeShellCommand("curl", "http://dlang.org/download.html") ~ "|" ~ escapeShellCommand("grep", "-o", `http://\S*\.zip`) ~ ">" ~ escapeShellFileName("D download links.txt")); --- Throws: $(OBJECTREF Exception) if any part of the command line contains unescapable characters (NUL on all platforms, as well as CR and LF on Windows). */ string escapeShellCommand(in char[][] args...) @safe pure { if (args.empty) return null; version (Windows) { // Do not ^-escape the first argument (the program path), // as the shell parses it differently from parameters. // ^-escaping a program path that contains spaces will fail. string result = escapeShellFileName(args[0]); if (args.length > 1) { result ~= " " ~ escapeShellCommandString( escapeShellArguments(args[1..$])); } return result; } version (Posix) { return escapeShellCommandString(escapeShellArguments(args)); } } unittest { // This is a simple unit test without any special requirements, // in addition to the unittest_burnin one below which requires // special preparation. struct TestVector { string[] args; string windows, posix; } TestVector[] tests = [ { args : ["foo bar"], windows : `"foo bar"`, posix : `'foo bar'` }, { args : ["foo bar", "hello"], windows : `"foo bar" hello`, posix : `'foo bar' 'hello'` }, { args : ["foo bar", "hello world"], windows : `"foo bar" ^"hello world^"`, posix : `'foo bar' 'hello world'` }, { args : ["foo bar", "hello", "world"], windows : `"foo bar" hello world`, posix : `'foo bar' 'hello' 'world'` }, { args : ["foo bar", `'"^\`], windows : `"foo bar" ^"'\^"^^\\^"`, posix : `'foo bar' ''\''"^\'` }, ]; foreach (test; tests) version (Windows) assert(escapeShellCommand(test.args) == test.windows); else assert(escapeShellCommand(test.args) == test.posix ); } private string escapeShellCommandString(string command) @safe pure { version (Windows) return escapeWindowsShellCommand(command); else return command; } private string escapeWindowsShellCommand(in char[] command) @safe pure { import std.array : appender; auto result = appender!string(); result.reserve(command.length); foreach (c; command) switch (c) { case '\0': throw new Exception("Cannot put NUL in command line"); case '\r': case '\n': throw new Exception("CR/LF are not escapable"); case '\x01': .. case '\x09': case '\x0B': .. case '\x0C': case '\x0E': .. case '\x1F': case '"': case '^': case '&': case '<': case '>': case '|': result.put('^'); goto default; default: result.put(c); } return result.data; } private string escapeShellArguments(in char[][] args...) @trusted pure nothrow { char[] buf; @safe nothrow char[] allocator(size_t size) { if (buf.length == 0) return buf = new char[size]; else { auto p = buf.length; buf.length = buf.length + 1 + size; buf[p++] = ' '; return buf[p..p+size]; } } foreach (arg; args) escapeShellArgument!allocator(arg); return assumeUnique(buf); } private auto escapeShellArgument(alias allocator)(in char[] arg) @safe nothrow { // The unittest for this function requires special // preparation - see below. version (Windows) return escapeWindowsArgumentImpl!allocator(arg); else return escapePosixArgumentImpl!allocator(arg); } /** Quotes a command-line argument in a manner conforming to the behavior of $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx, CommandLineToArgvW). */ string escapeWindowsArgument(in char[] arg) @trusted pure nothrow { // Rationale for leaving this function as public: // this algorithm of escaping paths is also used in other software, // e.g. DMD's response files. auto buf = escapeWindowsArgumentImpl!charAllocator(arg); return assumeUnique(buf); } private char[] charAllocator(size_t size) @safe pure nothrow { return new char[size]; } private char[] escapeWindowsArgumentImpl(alias allocator)(in char[] arg) @safe nothrow if (is(typeof(allocator(size_t.init)[0] = char.init))) { // References: // * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx // * http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx // Check if the string needs to be escaped, // and calculate the total string size. // Trailing backslashes must be escaped bool escaping = true; bool needEscape = false; // Result size = input size + 2 for surrounding quotes + 1 for the // backslash for each escaped character. size_t size = 1 + arg.length + 1; foreach_reverse (char c; arg) { if (c == '"') { needEscape = true; escaping = true; size++; } else if (c == '\\') { if (escaping) size++; } else { if (c == ' ' || c == '\t') needEscape = true; escaping = false; } } import std.ascii : isDigit; // Empty arguments need to be specified as "" if (!arg.length) needEscape = true; else // Arguments ending with digits need to be escaped, // to disambiguate with 1>file redirection syntax if (isDigit(arg[$-1])) needEscape = true; if (!needEscape) return allocator(arg.length)[] = arg; // Construct result string. auto buf = allocator(size); size_t p = size; buf[--p] = '"'; escaping = true; foreach_reverse (char c; arg) { if (c == '"') escaping = true; else if (c != '\\') escaping = false; buf[--p] = c; if (escaping) buf[--p] = '\\'; } buf[--p] = '"'; assert(p == 0); return buf; } version(Windows) version(unittest) { import core.sys.windows.shellapi : CommandLineToArgvW; import core.sys.windows.windows; import core.stdc.stddef; import core.stdc.wchar_ : wcslen; import std.array; string[] parseCommandLine(string line) { import std.algorithm : map; import std.array : array; LPWSTR lpCommandLine = (to!(wchar[])(line) ~ "\0"w).ptr; int numArgs; LPWSTR* args = CommandLineToArgvW(lpCommandLine, &numArgs); scope(exit) LocalFree(args); return args[0..numArgs] .map!(arg => to!string(arg[0..wcslen(arg)])) .array(); } unittest { string[] testStrings = [ `Hello`, `Hello, world`, `Hello, "world"`, `C:\`, `C:\dmd`, `C:\Program Files\`, ]; enum CHARS = `_x\" *&^` ~ "\t"; // _ is placeholder for nothing foreach (c1; CHARS) foreach (c2; CHARS) foreach (c3; CHARS) foreach (c4; CHARS) testStrings ~= [c1, c2, c3, c4].replace("_", ""); foreach (s; testStrings) { auto q = escapeWindowsArgument(s); auto args = parseCommandLine("Dummy.exe " ~ q); assert(args.length==2, s ~ " => " ~ q ~ " #" ~ text(args.length-1)); assert(args[1] == s, s ~ " => " ~ q ~ " => " ~ args[1]); } } } private string escapePosixArgument(in char[] arg) @trusted pure nothrow { auto buf = escapePosixArgumentImpl!charAllocator(arg); return assumeUnique(buf); } private char[] escapePosixArgumentImpl(alias allocator)(in char[] arg) @safe nothrow if (is(typeof(allocator(size_t.init)[0] = char.init))) { // '\'' means: close quoted part of argument, append an escaped // single quote, and reopen quotes // Below code is equivalent to: // return `'` ~ std.array.replace(arg, `'`, `'\''`) ~ `'`; size_t size = 1 + arg.length + 1; foreach (char c; arg) if (c == '\'') size += 3; auto buf = allocator(size); size_t p = 0; buf[p++] = '\''; foreach (char c; arg) if (c == '\'') { buf[p..p+4] = `'\''`; p += 4; } else buf[p++] = c; buf[p++] = '\''; assert(p == size); return buf; } /** Escapes a filename to be used for shell redirection with $(LREF spawnShell), $(LREF pipeShell) or $(LREF executeShell). */ string escapeShellFileName(in char[] fileName) @trusted pure nothrow { // The unittest for this function requires special // preparation - see below. version (Windows) { // If a file starts with &, it can cause cmd.exe to misinterpret // the file name as the stream redirection syntax: // command > "&foo.txt" // gets interpreted as // command >&foo.txt // Prepend .\ to disambiguate. if (fileName.length && fileName[0] == '&') return cast(string)(`".\` ~ fileName ~ '"'); return cast(string)('"' ~ fileName ~ '"'); } else return escapePosixArgument(fileName); } // Loop generating strings with random characters //version = unittest_burnin; version(unittest_burnin) unittest { // There are no readily-available commands on all platforms suitable // for properly testing command escaping. The behavior of CMD's "echo" // built-in differs from the POSIX program, and Windows ports of POSIX // environments (Cygwin, msys, gnuwin32) may interfere with their own // "echo" ports. // To run this unit test, create std_process_unittest_helper.d with the // following content and compile it: // import std.stdio, std.array; void main(string[] args) { write(args.join("\0")); } // Then, test this module with: // rdmd --main -unittest -version=unittest_burnin process.d auto helper = absolutePath("std_process_unittest_helper"); assert(executeShell(helper ~ " hello").output.split("\0")[1..$] == ["hello"], "Helper malfunction"); void test(string[] s, string fn) { string e; string[] g; e = escapeShellCommand(helper ~ s); { scope(failure) writefln("executeShell() failed.\nExpected:\t%s\nEncoded:\t%s", s, [e]); auto result = executeShell(e); assert(result.status == 0, "std_process_unittest_helper failed"); g = result.output.split("\0")[1..$]; } assert(s == g, format("executeShell() test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e])); e = escapeShellCommand(helper ~ s) ~ ">" ~ escapeShellFileName(fn); { scope(failure) writefln("executeShell() with redirect failed.\nExpected:\t%s\nFilename:\t%s\nEncoded:\t%s", s, [fn], [e]); auto result = executeShell(e); assert(result.status == 0, "std_process_unittest_helper failed"); assert(!result.output.length, "No output expected, got:\n" ~ result.output); g = readText(fn).split("\0")[1..$]; } remove(fn); assert(s == g, format("executeShell() with redirect test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e])); } while (true) { string[] args; foreach (n; 0..uniform(1, 4)) { string arg; foreach (l; 0..uniform(0, 10)) { dchar c; while (true) { version (Windows) { // As long as DMD's system() uses CreateProcessA, // we can't reliably pass Unicode c = uniform(0, 128); } else c = uniform!ubyte(); if (c == 0) continue; // argv-strings are zero-terminated version (Windows) if (c == '\r' || c == '\n') continue; // newlines are unescapable on Windows break; } arg ~= c; } args ~= arg; } // generate filename string fn; foreach (l; 0..uniform(1, 10)) { dchar c; while (true) { version (Windows) c = uniform(0, 128); // as above else c = uniform!ubyte(); if (c == 0 || c == '/') continue; // NUL and / are the only characters // forbidden in POSIX filenames version (Windows) if (c < '\x20' || c == '<' || c == '>' || c == ':' || c == '"' || c == '\\' || c == '|' || c == '?' || c == '*') continue; // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx break; } fn ~= c; } fn = fn[0..$/2] ~ "_testfile_" ~ fn[$/2..$]; test(args, fn); } } // ============================================================================= // Environment variable manipulation. // ============================================================================= /** Manipulates _environment variables using an associative-array-like interface. This class contains only static methods, and cannot be instantiated. See below for examples of use. */ abstract final class environment { static: /** Retrieves the value of the environment variable with the given $(D name). --- auto path = environment["PATH"]; --- Throws: $(OBJECTREF Exception) if the environment variable does not exist, or $(XREF utf,UTFException) if the variable contains invalid UTF-16 characters (Windows only). See_also: $(LREF environment.get), which doesn't throw on failure. */ string opIndex(in char[] name) @safe { string value; enforce(getImpl(name, value), "Environment variable not found: "~name); return value; } /** Retrieves the value of the environment variable with the given $(D name), or a default value if the variable doesn't exist. Unlike $(LREF environment.opIndex), this function never throws. --- auto sh = environment.get("SHELL", "/bin/sh"); --- This function is also useful in checking for the existence of an environment variable. --- auto myVar = environment.get("MYVAR"); if (myVar is null) { // Environment variable doesn't exist. // Note that we have to use 'is' for the comparison, since // myVar == null is also true if the variable exists but is // empty. } --- Throws: $(XREF utf,UTFException) if the variable contains invalid UTF-16 characters (Windows only). */ string get(in char[] name, string defaultValue = null) @safe { string value; auto found = getImpl(name, value); return found ? value : defaultValue; } /** Assigns the given $(D value) to the environment variable with the given $(D name). If the variable does not exist, it will be created. If it already exists, it will be overwritten. --- environment["foo"] = "bar"; --- Throws: $(OBJECTREF Exception) if the environment variable could not be added (e.g. if the name is invalid). */ inout(char)[] opIndexAssign(inout char[] value, in char[] name) @trusted { version (Posix) { if (core.sys.posix.stdlib.setenv(name.tempCString(), value.tempCString(), 1) != -1) { return value; } // The default errno error message is very uninformative // in the most common case, so we handle it manually. enforce(errno != EINVAL, "Invalid environment variable name: '"~name~"'"); errnoEnforce(false, "Failed to add environment variable"); assert(0); } else version (Windows) { enforce( SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()), sysErrorString(GetLastError()) ); return value; } else static assert(0); } /** Removes the environment variable with the given $(D name). If the variable isn't in the environment, this function returns successfully without doing anything. */ void remove(in char[] name) @trusted nothrow @nogc // TODO: @safe { version (Windows) SetEnvironmentVariableW(name.tempCStringW(), null); else version (Posix) core.sys.posix.stdlib.unsetenv(name.tempCString()); else static assert(0); } /** Copies all environment variables into an associative array. Windows_specific: While Windows environment variable names are case insensitive, D's built-in associative arrays are not. This function will store all variable names in uppercase (e.g. $(D PATH)). Throws: $(OBJECTREF Exception) if the environment variables could not be retrieved (Windows only). */ string[string] toAA() @trusted { string[string] aa; version (Posix) { for (int i=0; environ[i] != null; ++i) { import std.string : indexOf; immutable varDef = to!string(environ[i]); immutable eq = indexOf(varDef, '='); assert (eq >= 0); immutable name = varDef[0 .. eq]; immutable value = varDef[eq+1 .. $]; // In POSIX, environment variables may be defined more // than once. This is a security issue, which we avoid // by checking whether the key already exists in the array. // For more info: // http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html if (name !in aa) aa[name] = value; } } else version (Windows) { import std.uni : toUpper; auto envBlock = GetEnvironmentStringsW(); enforce(envBlock, "Failed to retrieve environment variables."); scope(exit) FreeEnvironmentStringsW(envBlock); for (int i=0; envBlock[i] != '\0'; ++i) { auto start = i; while (envBlock[i] != '=') ++i; immutable name = toUTF8(toUpper(envBlock[start .. i])); start = i+1; while (envBlock[i] != '\0') ++i; // Ignore variables with empty names. These are used internally // by Windows to keep track of each drive's individual current // directory. if (!name.length) continue; // Just like in POSIX systems, environment variables may be // defined more than once in an environment block on Windows, // and it is just as much of a security issue there. Moreso, // in fact, due to the case insensensitivity of variable names, // which is not handled correctly by all programs. if (name !in aa) aa[name] = toUTF8(envBlock[start .. i]); } } else static assert(0); return aa; } private: // Returns the length of an environment variable (in number of // wchars, including the null terminator), or 0 if it doesn't exist. version (Windows) int varLength(LPCWSTR namez) @trusted nothrow { return GetEnvironmentVariableW(namez, null, 0); } // Retrieves the environment variable, returns false on failure. bool getImpl(in char[] name, out string value) @trusted { version (Windows) { const namezTmp = name.tempCStringW(); immutable len = varLength(namezTmp); if (len == 0) return false; if (len == 1) { value = ""; return true; } auto buf = new WCHAR[len]; GetEnvironmentVariableW(namezTmp, buf.ptr, to!DWORD(buf.length)); value = toUTF8(buf[0 .. $-1]); return true; } else version (Posix) { const vz = core.sys.posix.stdlib.getenv(name.tempCString()); if (vz == null) return false; auto v = vz[0 .. strlen(vz)]; // Cache the last call's result. static string lastResult; if (v != lastResult) lastResult = v.idup; value = lastResult; return true; } else static assert(0); } } unittest { // New variable environment["std_process"] = "foo"; assert (environment["std_process"] == "foo"); // Set variable again environment["std_process"] = "bar"; assert (environment["std_process"] == "bar"); // Remove variable environment.remove("std_process"); // Remove again, should succeed environment.remove("std_process"); // Throw on not found. assertThrown(environment["std_process"]); // get() without default value assert (environment.get("std_process") == null); // get() with default value assert (environment.get("std_process", "baz") == "baz"); // Convert to associative array auto aa = environment.toAA(); assert (aa.length > 0); foreach (n, v; aa) { // Wine has some bugs related to environment variables: // - Wine allows the existence of an env. variable with the name // "\0", but GetEnvironmentVariable refuses to retrieve it. // As of 2.067 we filter these out anyway (see comment in toAA). // - If an env. variable has zero length, i.e. is "\0", // GetEnvironmentVariable should return 1. Instead it returns // 0, indicating the variable doesn't exist. version (Windows) if (v.length == 0) continue; assert (v == environment[n]); } // ... and back again. foreach (n, v; aa) environment[n] = v; // Complete the roundtrip auto aa2 = environment.toAA(); assert(aa == aa2); } // ============================================================================= // Everything below this line was part of the old std.process, and most of // it will be deprecated and removed. // ============================================================================= /* Macros: WIKI=Phobos/StdProcess Copyright: Copyright Digital Mars 2007 - 2009. License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org, Andrei Alexandrescu), $(WEB thecybershadow.net, Vladimir Panteleev) Source: $(PHOBOSSRC std/_process.d) */ /* Copyright Digital Mars 2007 - 2009. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ import core.stdc.stdlib; import core.stdc.errno; import core.thread; import core.stdc.string; version (Windows) { import std.format, std.random, std.file; } version (Posix) { import core.sys.posix.stdlib; } version (unittest) { import std.file, std.conv, std.random; } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Please use wait(spawnShell(command)) or executeShell(command) instead") int system(string command) { if (!command.ptr) return core.stdc.stdlib.system(null); immutable status = core.stdc.stdlib.system(command.tempCString()); if (status == -1) return status; version (Posix) { if (exited(status)) return exitstatus(status); // Abnormal termination, return -1. return -1; } else version (Windows) return status; else static assert(0, "system not implemented for this OS."); } private void toAStringz(in string[] a, const(char)**az) { import std.string : toStringz; foreach(string s; a) { *az++ = toStringz(s); } *az = null; } /* ========================================================== */ //version (Windows) //{ // int spawnvp(int mode, string pathname, string[] argv) // { // char** argv_ = cast(char**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length)); // scope(exit) core.stdc.stdlib.free(argv_); // // toAStringz(argv, argv_); // // return spawnvp(mode, pathname.tempCString(), argv_); // } //} // Incorporating idea (for spawnvp() on Posix) from Dave Fladebo enum { _P_WAIT, _P_NOWAIT, _P_OVERLAY }; version(Windows) extern(C) int spawnvp(int, in char *, in char **); alias P_WAIT = _P_WAIT; alias P_NOWAIT = _P_NOWAIT; // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Please use spawnProcess instead") int spawnvp(int mode, string pathname, string[] argv) { auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length)); scope(exit) core.stdc.stdlib.free(argv_); toAStringz(argv, argv_); version (Posix) { return _spawnvp(mode, pathname.tempCString(), argv_); } else version (Windows) { return spawnvp(mode, pathname.tempCString(), argv_); } else static assert(0, "spawnvp not implemented for this OS."); } version (Posix) { private import core.sys.posix.unistd; private import core.sys.posix.sys.wait; // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Please use spawnProcess instead") int _spawnvp(int mode, in char *pathname, in char **argv) { int retval = 0; pid_t pid = fork(); if(!pid) { // child core.sys.posix.unistd.execvp(pathname, argv); goto Lerror; } else if(pid > 0) { // parent if(mode == _P_NOWAIT) { retval = pid; // caller waits } else { while(1) { int status; pid_t wpid = waitpid(pid, &status, 0); if(exited(status)) { retval = exitstatus(status); break; } else if(signaled(status)) { retval = -termsig(status); break; } else if(stopped(status)) // ptrace support continue; else goto Lerror; } } return retval; } Lerror: retval = errno; char[80] buf = void; throw new Exception( "Cannot spawn " ~ to!string(pathname) ~ "; " ~ to!string(strerror_r(retval, buf.ptr, buf.length)) ~ " [errno " ~ to!string(retval) ~ "]"); } // _spawnvp private { alias stopped = WIFSTOPPED; alias signaled = WIFSIGNALED; alias termsig = WTERMSIG; alias exited = WIFEXITED; alias exitstatus = WEXITSTATUS; } // private } // version (Posix) /* ========================================================== */ version (StdDdoc) { /** Replaces the current process by executing a command, $(D pathname), with the arguments in $(D argv). $(BLUE This functions is Posix-Only.) Typically, the first element of $(D argv) is the command being executed, i.e. $(D argv[0] == pathname). The 'p' versions of $(D exec) search the PATH environment variable for $(D pathname). The 'e' versions additionally take the new process' environment variables as an array of strings of the form key=value. Does not return on success (the current process will have been replaced). Returns -1 on failure with no indication of the underlying error. Windows_specific: These functions are only supported on POSIX platforms, as the Windows operating systems do not provide the ability to overwrite the current process image with another. In single-threaded programs it is possible to approximate the effect of $(D execv*) by using $(LREF spawnProcess) and terminating the current process once the child process has returned. For example: --- auto commandLine = [ "program", "arg1", "arg2" ]; version (Posix) { execv(commandLine[0], commandLine); throw new Exception("Failed to execute program"); } else version (Windows) { import core.stdc.stdlib: _exit; _exit(wait(spawnProcess(commandLine))); } --- This is, however, NOT equivalent to POSIX' $(D execv*). For one thing, the executed program is started as a separate process, with all this entails. Secondly, in a multithreaded program, other threads will continue to do work while the current thread is waiting for the child process to complete. A better option may sometimes be to terminate the current program immediately after spawning the child process. This is the behaviour exhibited by the $(LINK2 http://msdn.microsoft.com/en-us/library/431x4c1w.aspx,$(D __exec)) functions in Microsoft's C runtime library, and it is how D's now-deprecated Windows $(D execv*) functions work. Example: --- auto commandLine = [ "program", "arg1", "arg2" ]; version (Posix) { execv(commandLine[0], commandLine); throw new Exception("Failed to execute program"); } else version (Windows) { spawnProcess(commandLine); import core.stdc.stdlib: _exit; _exit(0); } --- */ int execv(in string pathname, in string[] argv); ///ditto int execve(in string pathname, in string[] argv, in string[] envp); /// ditto int execvp(in string pathname, in string[] argv); /// ditto int execvpe(in string pathname, in string[] argv, in string[] envp); } else { private enum execvForwarderDefs = q{ int execv(in string pathname, in string[] argv) { return execv_(pathname, argv); } int execve(in string pathname, in string[] argv, in string[] envp) { return execve_(pathname, argv, envp); } int execvp(in string pathname, in string[] argv) { return execvp_(pathname, argv); } int execvpe(in string pathname, in string[] argv, in string[] envp) { return execvpe_(pathname, argv, envp); } }; version (Posix) { mixin (execvForwarderDefs); } else version (Windows) { // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ private enum execvDeprecationMsg = "Please consult the API documentation for more information: " ~"http://dlang.org/phobos/std_process.html#.execv"; mixin (`deprecated ("`~execvDeprecationMsg~`") {` ~ execvForwarderDefs ~ `}`); } else static assert (false, "Unsupported platform"); } // Move these C declarations to druntime if we decide to keep the D wrappers extern(C) { int execv(in char *, in char **); int execve(in char *, in char **, in char **); int execvp(in char *, in char **); version(Windows) int execvpe(in char *, in char **, in char **); } private int execv_(in string pathname, in string[] argv) { auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length)); scope(exit) core.stdc.stdlib.free(argv_); toAStringz(argv, argv_); return execv(pathname.tempCString(), argv_); } private int execve_(in string pathname, in string[] argv, in string[] envp) { auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length)); scope(exit) core.stdc.stdlib.free(argv_); auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length)); scope(exit) core.stdc.stdlib.free(envp_); toAStringz(argv, argv_); toAStringz(envp, envp_); return execve(pathname.tempCString(), argv_, envp_); } private int execvp_(in string pathname, in string[] argv) { auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length)); scope(exit) core.stdc.stdlib.free(argv_); toAStringz(argv, argv_); return execvp(pathname.tempCString(), argv_); } private int execvpe_(in string pathname, in string[] argv, in string[] envp) { version(Posix) { import std.array : split; // Is pathname rooted? if(pathname[0] == '/') { // Yes, so just call execve() return execve(pathname, argv, envp); } else { // No, so must traverse PATHs, looking for first match string[] envPaths = split( to!string(core.stdc.stdlib.getenv("PATH")), ":"); int iRet = 0; // Note: if any call to execve() succeeds, this process will cease // execution, so there's no need to check the execve() result through // the loop. foreach(string pathDir; envPaths) { string composite = cast(string) (pathDir ~ "/" ~ pathname); iRet = execve(composite, argv, envp); } if(0 != iRet) { iRet = execve(pathname, argv, envp); } return iRet; } } else version(Windows) { auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length)); scope(exit) core.stdc.stdlib.free(argv_); auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length)); scope(exit) core.stdc.stdlib.free(envp_); toAStringz(argv, argv_); toAStringz(envp, envp_); return execvpe(pathname.tempCString(), argv_, envp_); } else { static assert(0); } // version } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Please use thisProcessID instead") alias getpid = core.thread.getpid; // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Please use executeShell instead") string shell(string cmd) { version(Windows) { import std.array : appender; // Generate a random filename auto a = appender!string(); foreach (ref e; 0 .. 8) { formattedWrite(a, "%x", rndGen.front); rndGen.popFront(); } auto filename = a.data; scope(exit) if (exists(filename)) remove(filename); // We can't use escapeShellCommands here because we don't know // if cmd is escaped (wrapped in quotes) or not, without relying // on shady heuristics. The current code shouldn't cause much // trouble unless filename contained spaces (it won't). errnoEnforce(system(cmd ~ "> " ~ filename) == 0); return readText(filename); } else version(Posix) { File f; f.popen(cmd, "r"); char[] line; string result; while (f.readln(line)) { result ~= line; } f.close(); return result; } else static assert(0, "shell not implemented for this OS."); } deprecated unittest { auto x = shell("echo wyda"); // @@@ This fails on wine //assert(x == "wyda" ~ newline, text(x.length)); import std.exception; // Issue 9444 version(windows) string cmd = "98c10ec7e253a11cdff45f807b984a81 2>NUL"; else string cmd = "98c10ec7e253a11cdff45f807b984a81 2>/dev/null"; assertThrown!ErrnoException(shell(cmd)); } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Please use environment.opIndex or environment.get instead") string getenv(in char[] name) nothrow { // Cache the last call's result static string lastResult; auto p = core.stdc.stdlib.getenv(name.tempCString()); if (!p) return null; auto value = p[0 .. strlen(p)]; if (value == lastResult) return lastResult; return lastResult = value.idup; } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ version(StdDdoc) deprecated void setenv(in char[] name, in char[] value, bool overwrite); else version(Posix) deprecated("Please use environment.opIndexAssign instead.") void setenv(in char[] name, in char[] value, bool overwrite) { errnoEnforce( core.sys.posix.stdlib.setenv(name.tempCString(), value.tempCString(), overwrite) == 0); } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ version(StdDdoc) deprecated void unsetenv(in char[] name); else version(Posix) deprecated("Please use environment.remove instead") void unsetenv(in char[] name) { errnoEnforce(core.sys.posix.stdlib.unsetenv(name.tempCString()) == 0); } version (Posix) deprecated unittest { setenv("wyda", "geeba", true); assert(getenv("wyda") == "geeba"); // Get again to make sure caching works assert(getenv("wyda") == "geeba"); unsetenv("wyda"); assert(getenv("wyda") is null); } version(StdDdoc) { /**************************************** * Start up the browser and set it to viewing the page at url. */ void browse(string url); } else version (Windows) { import core.sys.windows.windows; pragma(lib,"shell32.lib"); void browse(string url) { ShellExecuteW(null, "open", url.tempCStringW(), null, null, SW_SHOWNORMAL); } } else version (OSX) { import core.stdc.stdio; import core.stdc.string; import core.sys.posix.unistd; void browse(string url) { const(char)*[5] args; auto curl = url.tempCString(); const(char)* browser = core.stdc.stdlib.getenv("BROWSER"); if (browser) { browser = strdup(browser); args[0] = browser; args[1] = curl; args[2] = null; } else { args[0] = "open".ptr; args[1] = curl; args[2] = null; } auto childpid = fork(); if (childpid == 0) { core.sys.posix.unistd.execvp(args[0], cast(char**)args.ptr); perror(args[0]); // failed to execute return; } if (browser) free(cast(void*)browser); } } else version (Posix) { import core.stdc.stdio; import core.stdc.string; import core.sys.posix.unistd; void browse(string url) { const(char)*[3] args; const(char)* browser = core.stdc.stdlib.getenv("BROWSER"); if (browser) { browser = strdup(browser); args[0] = browser; } else //args[0] = "x-www-browser".ptr; // doesn't work on some systems args[0] = "xdg-open".ptr; args[1] = url.tempCString(); args[2] = null; auto childpid = fork(); if (childpid == 0) { core.sys.posix.unistd.execvp(args[0], cast(char**)args.ptr); perror(args[0]); // failed to execute return; } if (browser) free(cast(void*)browser); } } else static assert(0, "os not supported"); ldc-1.1.0-beta3-src/runtime/phobos/std/meta.d0000664000175000017500000010605412776215007017007 0ustar kaikai// Written in the D programming language. /** * Templates to manipulate template argument lists (also known as type lists). * * Some operations on alias sequences are built in to the language, * such as TL[$(I n)] which gets the $(I n)th type from the * alias sequence. TL[$(I lwr) .. $(I upr)] returns a new type * list that is a slice of the old one. * * Several templates in this module use or operate on eponymous templates that * take a single argument and evaluate to a boolean constant. Such templates * are referred to as $(I template predicates). * * References: * Based on ideas in Table 3.1 from * $(LINK2 http://amazon.com/exec/obidos/ASIN/0201704315/ref=ase_classicempire/102-2957199-2585768, * Modern C++ Design), * Andrei Alexandrescu (Addison-Wesley Professional, 2001) * Macros: * WIKI = Phobos/StdMeta * * Copyright: Copyright Digital Mars 2005 - 2015. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: * $(WEB digitalmars.com, Walter Bright), * $(WEB klickverbot.at, David Nadlinger) * Source: $(PHOBOSSRC std/_meta.d) */ module std.meta; /** * Creates a sequence of zero or more aliases. This is most commonly * used as template parameters or arguments. */ template AliasSeq(TList...) { alias AliasSeq = TList; } /// unittest { import std.meta; alias TL = AliasSeq!(int, double); int foo(TL td) // same as int foo(int, double); { return td[0] + cast(int)td[1]; } } /// unittest { alias TL = AliasSeq!(int, double); alias Types = AliasSeq!(TL, char); static assert(is(Types == AliasSeq!(int, double, char))); } /** * Allows `alias`ing of any single symbol, type or compile-time expression. * * Not everything can be directly aliased. An alias cannot be declared * of - for example - a literal: * * `alias a = 4; //Error` * * With this template any single entity can be aliased: * * `alias b = Alias!4; //OK` * * See_Also: * To alias more than one thing at once, use $(LREF AliasSeq) */ template Alias(alias a) { static if (__traits(compiles, { alias x = a; })) alias Alias = a; else static if (__traits(compiles, { enum x = a; })) enum Alias = a; else static assert(0, "Cannot alias " ~ a.stringof); } /// Ditto template Alias(T) { alias Alias = T; } /// unittest { // Without Alias this would fail if Args[0] was e.g. a value and // some logic would be needed to detect when to use enum instead alias Head(Args ...) = Alias!(Args[0]); alias Tail(Args ...) = Args[1 .. $]; alias Blah = AliasSeq!(3, int, "hello"); static assert(Head!Blah == 3); static assert(is(Head!(Tail!Blah) == int)); static assert((Tail!Blah)[1] == "hello"); } /// unittest { alias a = Alias!(123); static assert(a == 123); enum abc = 1; alias b = Alias!(abc); static assert(b == 1); alias c = Alias!(3 + 4); static assert(c == 7); alias concat = (s0, s1) => s0 ~ s1; alias d = Alias!(concat("Hello", " World!")); static assert(d == "Hello World!"); alias e = Alias!(int); static assert(is(e == int)); alias f = Alias!(AliasSeq!(int)); static assert(!is(typeof(f[0]))); //not an AliasSeq static assert(is(f == int)); auto g = 6; alias h = Alias!g; ++h; assert(g == 7); } package template OldAlias(alias a) { static if (__traits(compiles, { alias x = a; })) alias OldAlias = a; else static if (__traits(compiles, { enum x = a; })) enum OldAlias = a; else static assert(0, "Cannot alias " ~ a.stringof); } import std.traits : isAggregateType, Unqual; package template OldAlias(T) if (!isAggregateType!T || is(Unqual!T == T)) { alias OldAlias = T; } deprecated("Alias will stop to unqualify user defined types.") package template OldAlias(T) if (isAggregateType!T && !is(Unqual!T == T)) { alias OldAlias = Unqual!T; } unittest { static struct Foo {} static assert(is(OldAlias!(const(Foo)) == Foo)); static assert(is(OldAlias!(const(int)) == const(int))); static assert(OldAlias!123 == 123); enum abc = 123; static assert(OldAlias!abc == 123); } /** * Returns the index of the first occurrence of type T in the * sequence of zero or more types TList. * If not found, -1 is returned. */ template staticIndexOf(T, TList...) { enum staticIndexOf = genericIndexOf!(T, TList).index; } /// Ditto template staticIndexOf(alias T, TList...) { enum staticIndexOf = genericIndexOf!(T, TList).index; } /// unittest { import std.stdio; void foo() { writefln("The index of long is %s", staticIndexOf!(long, AliasSeq!(int, long, double))); // prints: The index of long is 1 } } // [internal] private template genericIndexOf(args...) if (args.length >= 1) { alias e = OldAlias!(args[0]); alias tuple = args[1 .. $]; static if (tuple.length) { alias head = OldAlias!(tuple[0]); alias tail = tuple[1 .. $]; static if (isSame!(e, head)) { enum index = 0; } else { enum next = genericIndexOf!(e, tail).index; enum index = (next == -1) ? -1 : 1 + next; } } else { enum index = -1; } } unittest { static assert(staticIndexOf!( byte, byte, short, int, long) == 0); static assert(staticIndexOf!(short, byte, short, int, long) == 1); static assert(staticIndexOf!( int, byte, short, int, long) == 2); static assert(staticIndexOf!( long, byte, short, int, long) == 3); static assert(staticIndexOf!( char, byte, short, int, long) == -1); static assert(staticIndexOf!( -1, byte, short, int, long) == -1); static assert(staticIndexOf!(void) == -1); static assert(staticIndexOf!("abc", "abc", "def", "ghi", "jkl") == 0); static assert(staticIndexOf!("def", "abc", "def", "ghi", "jkl") == 1); static assert(staticIndexOf!("ghi", "abc", "def", "ghi", "jkl") == 2); static assert(staticIndexOf!("jkl", "abc", "def", "ghi", "jkl") == 3); static assert(staticIndexOf!("mno", "abc", "def", "ghi", "jkl") == -1); static assert(staticIndexOf!( void, "abc", "def", "ghi", "jkl") == -1); static assert(staticIndexOf!(42) == -1); static assert(staticIndexOf!(void, 0, "void", void) == 2); static assert(staticIndexOf!("void", 0, void, "void") == 2); } /// Kept for backwards compatibility alias IndexOf = staticIndexOf; /** * Returns a typetuple created from TList with the first occurrence, * if any, of T removed. */ template Erase(T, TList...) { alias Erase = GenericErase!(T, TList).result; } /// Ditto template Erase(alias T, TList...) { alias Erase = GenericErase!(T, TList).result; } /// unittest { alias Types = AliasSeq!(int, long, double, char); alias TL = Erase!(long, Types); static assert(is(TL == AliasSeq!(int, double, char))); } // [internal] private template GenericErase(args...) if (args.length >= 1) { alias e = OldAlias!(args[0]); alias tuple = args[1 .. $] ; static if (tuple.length) { alias head = OldAlias!(tuple[0]); alias tail = tuple[1 .. $]; static if (isSame!(e, head)) alias result = tail; else alias result = AliasSeq!(head, GenericErase!(e, tail).result); } else { alias result = AliasSeq!(); } } unittest { static assert(Pack!(Erase!(int, short, int, int, 4)). equals!(short, int, 4)); static assert(Pack!(Erase!(1, real, 3, 1, 4, 1, 5, 9)). equals!(real, 3, 4, 1, 5, 9)); } /** * Returns a typetuple created from TList with the all occurrences, * if any, of T removed. */ template EraseAll(T, TList...) { alias EraseAll = GenericEraseAll!(T, TList).result; } /// Ditto template EraseAll(alias T, TList...) { alias EraseAll = GenericEraseAll!(T, TList).result; } /// unittest { alias Types = AliasSeq!(int, long, long, int); alias TL = EraseAll!(long, Types); static assert(is(TL == AliasSeq!(int, int))); } // [internal] private template GenericEraseAll(args...) if (args.length >= 1) { alias e = OldAlias!(args[0]); alias tuple = args[1 .. $]; static if (tuple.length) { alias head = OldAlias!(tuple[0]); alias tail = tuple[1 .. $]; alias next = GenericEraseAll!(e, tail).result; static if (isSame!(e, head)) alias result = next; else alias result = AliasSeq!(head, next); } else { alias result = AliasSeq!(); } } unittest { static assert(Pack!(EraseAll!(int, short, int, int, 4)). equals!(short, 4)); static assert(Pack!(EraseAll!(1, real, 3, 1, 4, 1, 5, 9)). equals!(real, 3, 4, 5, 9)); } /** * Returns a typetuple created from TList with the all duplicate * types removed. */ template NoDuplicates(TList...) { static if (TList.length == 0) alias NoDuplicates = TList; else alias NoDuplicates = AliasSeq!(TList[0], NoDuplicates!(EraseAll!(TList[0], TList[1 .. $]))); } /// unittest { alias Types = AliasSeq!(int, long, long, int, float); alias TL = NoDuplicates!(Types); static assert(is(TL == AliasSeq!(int, long, float))); } unittest { static assert( Pack!( NoDuplicates!(1, int, 1, NoDuplicates, int, NoDuplicates, real)) .equals!(1, int, NoDuplicates, real)); } /** * Returns a typetuple created from TList with the first occurrence * of type T, if found, replaced with type U. */ template Replace(T, U, TList...) { alias Replace = GenericReplace!(T, U, TList).result; } /// Ditto template Replace(alias T, U, TList...) { alias Replace = GenericReplace!(T, U, TList).result; } /// Ditto template Replace(T, alias U, TList...) { alias Replace = GenericReplace!(T, U, TList).result; } /// Ditto template Replace(alias T, alias U, TList...) { alias Replace = GenericReplace!(T, U, TList).result; } /// unittest { alias Types = AliasSeq!(int, long, long, int, float); alias TL = Replace!(long, char, Types); static assert(is(TL == AliasSeq!(int, char, long, int, float))); } // [internal] private template GenericReplace(args...) if (args.length >= 2) { alias from = OldAlias!(args[0]); alias to = OldAlias!(args[1]); alias tuple = args[2 .. $]; static if (tuple.length) { alias head = OldAlias!(tuple[0]); alias tail = tuple[1 .. $]; static if (isSame!(from, head)) alias result = AliasSeq!(to, tail); else alias result = AliasSeq!(head, GenericReplace!(from, to, tail).result); } else { alias result = AliasSeq!(); } } unittest { static assert(Pack!(Replace!(byte, ubyte, short, byte, byte, byte)). equals!(short, ubyte, byte, byte)); static assert(Pack!(Replace!(1111, byte, 2222, 1111, 1111, 1111)). equals!(2222, byte, 1111, 1111)); static assert(Pack!(Replace!(byte, 1111, short, byte, byte, byte)). equals!(short, 1111, byte, byte)); static assert(Pack!(Replace!(1111, "11", 2222, 1111, 1111, 1111)). equals!(2222, "11", 1111, 1111)); } /** * Returns a typetuple created from TList with all occurrences * of type T, if found, replaced with type U. */ template ReplaceAll(T, U, TList...) { alias ReplaceAll = GenericReplaceAll!(T, U, TList).result; } /// Ditto template ReplaceAll(alias T, U, TList...) { alias ReplaceAll = GenericReplaceAll!(T, U, TList).result; } /// Ditto template ReplaceAll(T, alias U, TList...) { alias ReplaceAll = GenericReplaceAll!(T, U, TList).result; } /// Ditto template ReplaceAll(alias T, alias U, TList...) { alias ReplaceAll = GenericReplaceAll!(T, U, TList).result; } /// unittest { alias Types = AliasSeq!(int, long, long, int, float); alias TL = ReplaceAll!(long, char, Types); static assert(is(TL == AliasSeq!(int, char, char, int, float))); } // [internal] private template GenericReplaceAll(args...) if (args.length >= 2) { alias from = OldAlias!(args[0]); alias to = OldAlias!(args[1]); alias tuple = args[2 .. $]; static if (tuple.length) { alias head = OldAlias!(tuple[0]); alias tail = tuple[1 .. $]; alias next = GenericReplaceAll!(from, to, tail).result; static if (isSame!(from, head)) alias result = AliasSeq!(to, next); else alias result = AliasSeq!(head, next); } else { alias result = AliasSeq!(); } } unittest { static assert(Pack!(ReplaceAll!(byte, ubyte, byte, short, byte, byte)). equals!(ubyte, short, ubyte, ubyte)); static assert(Pack!(ReplaceAll!(1111, byte, 1111, 2222, 1111, 1111)). equals!(byte, 2222, byte, byte)); static assert(Pack!(ReplaceAll!(byte, 1111, byte, short, byte, byte)). equals!(1111, short, 1111, 1111)); static assert(Pack!(ReplaceAll!(1111, "11", 1111, 2222, 1111, 1111)). equals!("11", 2222, "11", "11")); } /** * Returns a typetuple created from TList with the order reversed. */ template Reverse(TList...) { static if (TList.length <= 1) { alias Reverse = TList; } else { alias Reverse = AliasSeq!( Reverse!(TList[$/2 .. $ ]), Reverse!(TList[ 0 .. $/2])); } } /// unittest { alias Types = AliasSeq!(int, long, long, int, float); alias TL = Reverse!(Types); static assert(is(TL == AliasSeq!(float, int, long, long, int))); } /** * Returns the type from TList that is the most derived from type T. * If none are found, T is returned. */ template MostDerived(T, TList...) { static if (TList.length == 0) alias MostDerived = T; else static if (is(TList[0] : T)) alias MostDerived = MostDerived!(TList[0], TList[1 .. $]); else alias MostDerived = MostDerived!(T, TList[1 .. $]); } /// unittest { class A { } class B : A { } class C : B { } alias Types = AliasSeq!(A, C, B); MostDerived!(Object, Types) x; // x is declared as type C static assert(is(typeof(x) == C)); } /** * Returns the typetuple TList with the types sorted so that the most * derived types come first. */ template DerivedToFront(TList...) { static if (TList.length == 0) alias DerivedToFront = TList; else alias DerivedToFront = AliasSeq!(MostDerived!(TList[0], TList[1 .. $]), DerivedToFront!(ReplaceAll!(MostDerived!(TList[0], TList[1 .. $]), TList[0], TList[1 .. $]))); } /// unittest { class A { } class B : A { } class C : B { } alias Types = AliasSeq!(A, C, B); alias TL = DerivedToFront!(Types); static assert(is(TL == AliasSeq!(C, B, A))); } /** Evaluates to $(D AliasSeq!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1]))). */ template staticMap(alias F, T...) { static if (T.length == 0) { alias staticMap = AliasSeq!(); } else static if (T.length == 1) { alias staticMap = AliasSeq!(F!(T[0])); } else { alias staticMap = AliasSeq!( staticMap!(F, T[ 0 .. $/2]), staticMap!(F, T[$/2 .. $ ])); } } /// unittest { import std.traits : Unqual; alias TL = staticMap!(Unqual, int, const int, immutable int); static assert(is(TL == AliasSeq!(int, int, int))); } unittest { import std.traits : Unqual; // empty alias Empty = staticMap!(Unqual); static assert(Empty.length == 0); // single alias Single = staticMap!(Unqual, const int); static assert(is(Single == AliasSeq!int)); alias T = staticMap!(Unqual, int, const int, immutable int); static assert(is(T == AliasSeq!(int, int, int))); } /** Tests whether all given items satisfy a template predicate, i.e. evaluates to $(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])). Evaluation is $(I not) short-circuited if a false result is encountered; the template predicate must be instantiable with all the given items. */ template allSatisfy(alias F, T...) { static if (T.length == 0) { enum allSatisfy = true; } else static if (T.length == 1) { enum allSatisfy = F!(T[0]); } else { enum allSatisfy = allSatisfy!(F, T[ 0 .. $/2]) && allSatisfy!(F, T[$/2 .. $ ]); } } /// unittest { import std.traits : isIntegral; static assert(!allSatisfy!(isIntegral, int, double)); static assert( allSatisfy!(isIntegral, int, long)); } /** Tests whether any given items satisfy a template predicate, i.e. evaluates to $(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])). Evaluation is $(I not) short-circuited if a true result is encountered; the template predicate must be instantiable with all the given items. */ template anySatisfy(alias F, T...) { static if(T.length == 0) { enum anySatisfy = false; } else static if (T.length == 1) { enum anySatisfy = F!(T[0]); } else { enum anySatisfy = anySatisfy!(F, T[ 0 .. $/2]) || anySatisfy!(F, T[$/2 .. $ ]); } } /// unittest { import std.traits : isIntegral; static assert(!anySatisfy!(isIntegral, string, double)); static assert( anySatisfy!(isIntegral, int, double)); } /** * Filters an $(D AliasSeq) using a template predicate. Returns a * $(D AliasSeq) of the elements which satisfy the predicate. */ template Filter(alias pred, TList...) { static if (TList.length == 0) { alias Filter = AliasSeq!(); } else static if (TList.length == 1) { static if (pred!(TList[0])) alias Filter = AliasSeq!(TList[0]); else alias Filter = AliasSeq!(); } else { alias Filter = AliasSeq!( Filter!(pred, TList[ 0 .. $/2]), Filter!(pred, TList[$/2 .. $ ])); } } /// unittest { import std.traits : isNarrowString, isUnsigned; alias Types1 = AliasSeq!(string, wstring, dchar[], char[], dstring, int); alias TL1 = Filter!(isNarrowString, Types1); static assert(is(TL1 == AliasSeq!(string, wstring, char[]))); alias Types2 = AliasSeq!(int, byte, ubyte, dstring, dchar, uint, ulong); alias TL2 = Filter!(isUnsigned, Types2); static assert(is(TL2 == AliasSeq!(ubyte, uint, ulong))); } unittest { import std.traits : isPointer; static assert(is(Filter!(isPointer, int, void*, char[], int*) == AliasSeq!(void*, int*))); static assert(is(Filter!isPointer == AliasSeq!())); } // Used in template predicate unit tests below. private version (unittest) { template testAlways(T...) { enum testAlways = true; } template testNever(T...) { enum testNever = false; } template testError(T...) { static assert(false, "Should never be instantiated."); } } /** * Negates the passed template predicate. */ template templateNot(alias pred) { enum templateNot(T...) = !pred!T; } /// unittest { import std.traits : isPointer; alias isNoPointer = templateNot!isPointer; static assert(!isNoPointer!(int*)); static assert(allSatisfy!(isNoPointer, string, char, float)); } unittest { foreach (T; AliasSeq!(int, staticMap, 42)) { static assert(!Instantiate!(templateNot!testAlways, T)); static assert(Instantiate!(templateNot!testNever, T)); } } /** * Combines several template predicates using logical AND, i.e. constructs a new * predicate which evaluates to true for a given input T if and only if all of * the passed predicates are true for T. * * The predicates are evaluated from left to right, aborting evaluation in a * short-cut manner if a false result is encountered, in which case the latter * instantiations do not need to compile. */ template templateAnd(Preds...) { template templateAnd(T...) { static if (Preds.length == 0) { enum templateAnd = true; } else { static if (Instantiate!(Preds[0], T)) alias templateAnd = Instantiate!(.templateAnd!(Preds[1 .. $]), T); else enum templateAnd = false; } } } /// unittest { import std.traits : isNumeric, isUnsigned; alias storesNegativeNumbers = templateAnd!(isNumeric, templateNot!isUnsigned); static assert(storesNegativeNumbers!int); static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint); // An empty list of predicates always yields true. alias alwaysTrue = templateAnd!(); static assert(alwaysTrue!int); } unittest { foreach (T; AliasSeq!(int, staticMap, 42)) { static assert( Instantiate!(templateAnd!(), T)); static assert( Instantiate!(templateAnd!(testAlways), T)); static assert( Instantiate!(templateAnd!(testAlways, testAlways), T)); static assert(!Instantiate!(templateAnd!(testNever), T)); static assert(!Instantiate!(templateAnd!(testAlways, testNever), T)); static assert(!Instantiate!(templateAnd!(testNever, testAlways), T)); static assert(!Instantiate!(templateAnd!(testNever, testError), T)); static assert(!is(typeof(Instantiate!(templateAnd!(testAlways, testError), T)))); } } /** * Combines several template predicates using logical OR, i.e. constructs a new * predicate which evaluates to true for a given input T if and only at least * one of the passed predicates is true for T. * * The predicates are evaluated from left to right, aborting evaluation in a * short-cut manner if a true result is encountered, in which case the latter * instantiations do not need to compile. */ template templateOr(Preds...) { template templateOr(T...) { static if (Preds.length == 0) { enum templateOr = false; } else { static if (Instantiate!(Preds[0], T)) enum templateOr = true; else alias templateOr = Instantiate!(.templateOr!(Preds[1 .. $]), T); } } } /// unittest { import std.traits : isPointer, isUnsigned; alias isPtrOrUnsigned = templateOr!(isPointer, isUnsigned); static assert( isPtrOrUnsigned!uint && isPtrOrUnsigned!(short*)); static assert(!isPtrOrUnsigned!int && !isPtrOrUnsigned!(string)); // An empty list of predicates never yields true. alias alwaysFalse = templateOr!(); static assert(!alwaysFalse!int); } unittest { foreach (T; AliasSeq!(int, staticMap, 42)) { static assert( Instantiate!(templateOr!(testAlways), T)); static assert( Instantiate!(templateOr!(testAlways, testAlways), T)); static assert( Instantiate!(templateOr!(testAlways, testNever), T)); static assert( Instantiate!(templateOr!(testNever, testAlways), T)); static assert(!Instantiate!(templateOr!(), T)); static assert(!Instantiate!(templateOr!(testNever), T)); static assert( Instantiate!(templateOr!(testAlways, testError), T)); static assert( Instantiate!(templateOr!(testNever, testAlways, testError), T)); // DMD @@BUG@@: Assertion fails for int, seems like a error gagging // problem. The bug goes away when removing some of the other template // instantiations in the module. // static assert(!is(typeof(Instantiate!(templateOr!(testNever, testError), T)))); } } /** * Converts an input range $(D range) to an alias sequence. */ template aliasSeqOf(alias range) { import std.range : isInputRange; import std.traits : isArray, isNarrowString; alias ArrT = typeof(range); static if (isArray!ArrT && !isNarrowString!ArrT) { static if (range.length == 0) { alias aliasSeqOf = AliasSeq!(); } else static if (range.length == 1) { alias aliasSeqOf = AliasSeq!(range[0]); } else { alias aliasSeqOf = AliasSeq!(aliasSeqOf!(range[0 .. $/2]), aliasSeqOf!(range[$/2 .. $])); } } else static if (isInputRange!ArrT) { import std.array : array; alias aliasSeqOf = aliasSeqOf!(array(range)); } else { import std.string : format; static assert(false, format("Cannot transform %s of type %s into a AliasSeq.", range, ArrT.stringof)); } } /// unittest { import std.algorithm : map, sort; import std.string : capitalize; struct S { int a; int c; int b; } alias capMembers = aliasSeqOf!([__traits(allMembers, S)].sort().map!capitalize()); static assert(capMembers[0] == "A"); static assert(capMembers[1] == "B"); static assert(capMembers[2] == "C"); } /// unittest { enum REF = [0, 1, 2, 3]; foreach(I, V; aliasSeqOf!([0, 1, 2, 3])) { static assert(V == I); static assert(V == REF[I]); } } unittest { import std.range : iota; import std.conv : to, octal; //Testing compile time octal foreach (I2; aliasSeqOf!(iota(0, 8))) foreach (I1; aliasSeqOf!(iota(0, 8))) { enum oct = I2 * 8 + I1; enum dec = I2 * 10 + I1; enum str = to!string(dec); static assert(octal!dec == oct); static assert(octal!str == oct); } } unittest { enum REF = "日本語"d; foreach(I, V; aliasSeqOf!"日本語"c) { static assert(V == REF[I]); } } /** * $(LINK2 http://en.wikipedia.org/wiki/Partial_application, Partially applies) * $(D_PARAM Template) by binding its first (left) or last (right) arguments * to $(D_PARAM args). * * Behaves like the identity function when $(D_PARAM args) is empty. * Params: * Template = template to partially apply * args = arguments to bind * Returns: * _Template with arity smaller than or equal to $(D_PARAM Template) */ template ApplyLeft(alias Template, args...) { static if (args.length) { template ApplyLeft(right...) { static if (is(typeof(Template!(args, right)))) enum ApplyLeft = Template!(args, right); // values else alias ApplyLeft = Template!(args, right); // symbols } } else alias ApplyLeft = Template; } /// Ditto template ApplyRight(alias Template, args...) { static if (args.length) { template ApplyRight(left...) { static if (is(typeof(Template!(left, args)))) enum ApplyRight = Template!(left, args); // values else alias ApplyRight = Template!(left, args); // symbols } } else alias ApplyRight = Template; } /// unittest { import std.traits : isImplicitlyConvertible; static assert(allSatisfy!( ApplyLeft!(isImplicitlyConvertible, ubyte), short, ushort, int, uint, long, ulong)); static assert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short), ubyte, string, short, float, int) == AliasSeq!(ubyte, short))); } /// unittest { import std.traits : hasMember, ifTestable; struct T1 { bool foo; } struct T2 { struct Test { bool opCast(T : bool)() { return true; } } Test foo; } static assert(allSatisfy!(ApplyRight!(hasMember, "foo"), T1, T2)); static assert(allSatisfy!(ApplyRight!(ifTestable, a => a.foo), T1, T2)); } /// unittest { import std.traits : Largest; alias Types = AliasSeq!(byte, short, int, long); static assert(is(staticMap!(ApplyLeft!(Largest, short), Types) == AliasSeq!(short, short, int, long))); static assert(is(staticMap!(ApplyLeft!(Largest, int), Types) == AliasSeq!(int, int, int, long))); } /// unittest { import std.traits : FunctionAttribute, SetFunctionAttributes; static void foo() @system; static int bar(int) @system; alias SafeFunctions = AliasSeq!( void function() @safe, int function(int) @safe); static assert(is(staticMap!(ApplyRight!( SetFunctionAttributes, "D", FunctionAttribute.safe), typeof(&foo), typeof(&bar)) == SafeFunctions)); } /** * Creates an `AliasSeq` which repeats a type or an `AliasSeq` exactly `n` times. */ template Repeat(size_t n, TList...) if (n > 0) { static if (n == 1) { alias Repeat = AliasSeq!TList; } else static if (n == 2) { alias Repeat = AliasSeq!(TList, TList); } else { alias R = Repeat!((n - 1) / 2, TList); static if ((n - 1) % 2 == 0) { alias Repeat = AliasSeq!(TList, R, R); } else { alias Repeat = AliasSeq!(TList, TList, R, R); } } } /// unittest { alias ImInt1 = Repeat!(1, immutable(int)); static assert(is(ImInt1 == AliasSeq!(immutable(int)))); alias Real3 = Repeat!(3, real); static assert(is(Real3 == AliasSeq!(real, real, real))); alias Real12 = Repeat!(4, Real3); static assert(is(Real12 == AliasSeq!(real, real, real, real, real, real, real, real, real, real, real, real))); alias Composite = AliasSeq!(uint, int); alias Composite2 = Repeat!(2, Composite); static assert(is(Composite2 == AliasSeq!(uint, int, uint, int))); } /// unittest { auto staticArray(T, size_t n)(Repeat!(n, T) elems) { T[n] a = [elems]; return a; } auto a = staticArray!(long, 3)(3, 1, 4); assert(is(typeof(a) == long[3])); assert(a == [3, 1, 4]); } /** * Sorts a $(LREF AliasSeq) using $(D cmp). * * Parameters: * cmp = A template that returns a $(D bool) (if its first argument is less than the second one) * or an $(D int) (-1 means less than, 0 means equal, 1 means greater than) * * Seq = The $(LREF AliasSeq) to sort * * Returns: The sorted alias sequence */ template staticSort(alias cmp, Seq...) { static if (Seq.length < 2) { alias staticSort = Seq; } else { private alias bottom = staticSort!(cmp, Seq[0 .. $ / 2]); private alias top = staticSort!(cmp, Seq[$ / 2 .. $]); alias staticSort = staticMerge!(cmp, Seq.length / 2, bottom, top); } } /// unittest { alias Nums = AliasSeq!(7, 2, 3, 23); enum Comp(int N1, int N2) = N1 < N2; static assert(AliasSeq!(2, 3, 7, 23) == staticSort!(Comp, Nums)); } /// unittest { alias Types = AliasSeq!(uint, short, ubyte, long, ulong); enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1); static assert(is(AliasSeq!(uint, ubyte, ulong, short, long) == staticSort!(Comp, Types))); } private template staticMerge(alias cmp, int half, Seq...) { static if (half == 0 || half == Seq.length) { alias staticMerge = Seq; } else { private enum Result = cmp!(Seq[0], Seq[half]); static if (is(typeof(Result) == bool)) { private enum Check = Result; } else static if (is(typeof(Result) : int)) { private enum Check = Result <= 0; } else { static assert(0, typeof(Result).stringof ~ " is not a value comparison type"); } static if (Check) { alias staticMerge = AliasSeq!(Seq[0], staticMerge!(cmp, half - 1, Seq[1 .. $])); } else { alias staticMerge = AliasSeq!(Seq[half], staticMerge!(cmp, half, Seq[0 .. half], Seq[half + 1 .. $])); } } } // : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : // private: /* * [internal] Returns true if a and b are the same thing, or false if * not. Both a and b can be types, literals, or symbols. * * How: When: * is(a == b) - both are types * a == b - both are literals (true literals, enums) * __traits(isSame, a, b) - other cases (variables, functions, * templates, etc.) */ private template isSame(ab...) if (ab.length == 2) { static if (__traits(compiles, expectType!(ab[0]), expectType!(ab[1]))) { enum isSame = is(ab[0] == ab[1]); } else static if (!__traits(compiles, expectType!(ab[0])) && !__traits(compiles, expectType!(ab[1])) && __traits(compiles, expectBool!(ab[0] == ab[1]))) { static if (!__traits(compiles, &ab[0]) || !__traits(compiles, &ab[1])) enum isSame = (ab[0] == ab[1]); else enum isSame = __traits(isSame, ab[0], ab[1]); } else { enum isSame = __traits(isSame, ab[0], ab[1]); } } private template expectType(T) {} private template expectBool(bool b) {} unittest { static assert( isSame!(int, int)); static assert(!isSame!(int, short)); enum a = 1, b = 1, c = 2, s = "a", t = "a"; static assert( isSame!(1, 1)); static assert( isSame!(a, 1)); static assert( isSame!(a, b)); static assert(!isSame!(b, c)); static assert( isSame!("a", "a")); static assert( isSame!(s, "a")); static assert( isSame!(s, t)); static assert(!isSame!(1, "1")); static assert(!isSame!(a, "a")); static assert( isSame!(isSame, isSame)); static assert(!isSame!(isSame, a)); static assert(!isSame!(byte, a)); static assert(!isSame!(short, isSame)); static assert(!isSame!(a, int)); static assert(!isSame!(long, isSame)); static immutable X = 1, Y = 1, Z = 2; static assert( isSame!(X, X)); static assert(!isSame!(X, Y)); static assert(!isSame!(Y, Z)); int foo(); int bar(); real baz(int); static assert( isSame!(foo, foo)); static assert(!isSame!(foo, bar)); static assert(!isSame!(bar, baz)); static assert( isSame!(baz, baz)); static assert(!isSame!(foo, 0)); int x, y; real z; static assert( isSame!(x, x)); static assert(!isSame!(x, y)); static assert(!isSame!(y, z)); static assert( isSame!(z, z)); static assert(!isSame!(x, 0)); } /* * [internal] Confines a tuple within a template. */ private template Pack(T...) { alias tuple = T; // For convenience template equals(U...) { static if (T.length == U.length) { static if (T.length == 0) enum equals = true; else enum equals = isSame!(T[0], U[0]) && Pack!(T[1 .. $]).equals!(U[1 .. $]); } else { enum equals = false; } } } unittest { static assert( Pack!(1, int, "abc").equals!(1, int, "abc")); static assert(!Pack!(1, int, "abc").equals!(1, int, "cba")); } /* * Instantiates the given template with the given list of parameters. * * Used to work around syntactic limitations of D with regard to instantiating * a template from an alias sequence (e.g. T[0]!(...) is not valid) or a template * returning another template (e.g. Foo!(Bar)!(Baz) is not allowed). */ // TODO: Consider publicly exposing this, maybe even if only for better // understandability of error messages. alias Instantiate(alias Template, Params...) = Template!Params; ldc-1.1.0-beta3-src/runtime/phobos/win64.mak0000664000175000017500000012573012776215007016565 0ustar kaikai# Makefile to build D runtime library phobos64.lib for Win64 # Prerequisites: # Microsoft Visual Studio # Targets: # make # Same as make unittest # make phobos64.lib # Build phobos64.lib # make clean # Delete unneeded files created by build process # make unittest # Build phobos64.lib, build and run unit tests # make phobos32mscoff # Build phobos32mscoff.lib # make unittest32mscoff # Build phobos32mscoff.lib, build and run unit tests # make cov # Build for coverage tests, run coverage tests # make html # Build documentation ## Memory model (32 or 64) MODEL=64 ## Copy command CP=cp ## Directory where dmd has been installed DIR=\dmd2 ## Visual C directories VCDIR=\Program Files (x86)\Microsoft Visual Studio 10.0\VC SDKDIR=\Program Files (x86)\Microsoft SDKs\Windows\v7.0A ## Flags for VC compiler #CFLAGS=/Zi /nologo /I"$(VCDIR)\INCLUDE" /I"$(SDKDIR)\Include" CFLAGS=/O2 /nologo /I"$(VCDIR)\INCLUDE" /I"$(SDKDIR)\Include" ## Location of druntime tree DRUNTIME=..\druntime DRUNTIMELIB=$(DRUNTIME)\lib\druntime$(MODEL).lib ## Flags for dmd D compiler DFLAGS=-conf= -m$(MODEL) -O -release -w -dip25 -I$(DRUNTIME)\import #DFLAGS=-m$(MODEL) -unittest -g #DFLAGS=-m$(MODEL) -unittest -cov -g ## Flags for compiling unittests UDFLAGS=-conf= -g -m$(MODEL) -O -w -dip25 -I$(DRUNTIME)\import ## C compiler, linker, librarian CC="$(VCDIR)\bin\amd64\cl" LD="$(VCDIR)\bin\amd64\link" AR="$(VCDIR)\bin\amd64\lib" MAKE=make ## D compiler DMD=$(DIR)\bin\dmd #DMD=..\dmd DMD=dmd ## Location of where to write the html documentation files DOCSRC = ../dlang.org STDDOC = $(DOCSRC)/html.ddoc $(DOCSRC)/dlang.org.ddoc $(DOCSRC)/std.ddoc $(DOCSRC)/macros.ddoc $(DOCSRC)/std_navbar-prerelease.ddoc project.ddoc DOC=..\..\html\d\phobos #DOC=..\doc\phobos ## Zlib library ZLIB=etc\c\zlib\zlib$(MODEL).lib .c.obj: $(CC) -c $(CFLAGS) $*.c .cpp.obj: $(CC) -c $(CFLAGS) $*.cpp .d.obj: $(DMD) -c $(DFLAGS) $* .asm.obj: $(CC) -c $* LIB=phobos$(MODEL).lib targets : $(LIB) test : test.exe test.obj : test.d $(DMD) -conf= -c -m$(MODEL) test -g -unittest test.exe : test.obj $(LIB) $(DMD) -conf= test.obj -m$(MODEL) -g -L/map # ti_bit.obj ti_Abit.obj # The separation is a workaround for bug 4904 (optlink bug 3372). # SRCS_1 is the heavyweight modules which are most likely to trigger the bug. # Do not add any more modules to SRCS_1. SRC_STD_1_HEAVY= std\stdio.d std\stdiobase.d \ std\string.d std\format.d \ std\file.d SRC_STD_2a_HEAVY= std\array.d std\functional.d std\path.d std\outbuffer.d std\utf.d SRC_STD_math=std\math.d SRC_STD_3= std\csv.d std\complex.d std\numeric.d std\bigint.d SRC_STD_3c= std\datetime.d std\bitmanip.d std\typecons.d SRC_STD_3a= std\uni.d std\base64.d std\ascii.d \ std\demangle.d std\uri.d std\mmfile.d std\getopt.d SRC_STD_3b= std\signals.d std\meta.d std\typetuple.d std\traits.d \ std\encoding.d std\xml.d \ std\random.d \ std\exception.d \ std\compiler.d \ std\system.d std\concurrency.d std\concurrencybase.d #can't place SRC_STD_DIGEST in SRC_STD_REST because of out-of-memory issues SRC_STD_DIGEST= std\digest\crc.d std\digest\sha.d std\digest\md.d \ std\digest\ripemd.d std\digest\digest.d std\digest\hmac.d SRC_STD_CONTAINER= std\container\array.d std\container\binaryheap.d \ std\container\dlist.d std\container\rbtree.d std\container\slist.d \ std\container\util.d std\container\package.d SRC_STD_4= std\uuid.d $(SRC_STD_DIGEST) SRC_STD_ALGO_1=std\algorithm\package.d std\algorithm\comparison.d \ std\algorithm\iteration.d std\algorithm\mutation.d SRC_STD_ALGO_2=std\algorithm\searching.d std\algorithm\setops.d \ std\algorithm\sorting.d std\algorithm\internal.d SRC_STD_ALGO=$(SRC_STD_ALGO_1) $(SRC_STD_ALGO_2) SRC_STD_LOGGER= std\experimental\logger\core.d std\experimental\logger\filelogger.d \ std\experimental\logger\multilogger.d std\experimental\logger\nulllogger.d \ std\experimental\logger\package.d SRC_STD_ALLOC_BB= std\experimental\allocator\building_blocks\affix_allocator.d \ std\experimental\allocator\building_blocks\allocator_list.d \ std\experimental\allocator\building_blocks\bitmapped_block.d \ std\experimental\allocator\building_blocks\bucketizer.d \ std\experimental\allocator\building_blocks\fallback_allocator.d \ std\experimental\allocator\building_blocks\free_list.d \ std\experimental\allocator\building_blocks\free_tree.d \ std\experimental\allocator\building_blocks\kernighan_ritchie.d \ std\experimental\allocator\building_blocks\null_allocator.d \ std\experimental\allocator\building_blocks\quantizer.d \ std\experimental\allocator\building_blocks\region.d \ std\experimental\allocator\building_blocks\scoped_allocator.d \ std\experimental\allocator\building_blocks\segregator.d \ std\experimental\allocator\building_blocks\stats_collector.d \ std\experimental\allocator\building_blocks\package.d SRC_STD_ALLOC= std\experimental\allocator\common.d std\experimental\allocator\gc_allocator.d \ std\experimental\allocator\mallocator.d std\experimental\allocator\mmap_allocator.d \ std\experimental\allocator\showcase.d std\experimental\allocator\typed.d \ std\experimental\allocator\package.d \ $(SRC_STD_ALLOC_BB) SRC_STD_5a=$(SRC_STD_ALGO_1) SRC_STD_5b=$(SRC_STD_ALGO_2) SRC_STD_6a=std\variant.d SRC_STD_6c=std\zlib.d SRC_STD_6d=std\stream.d SRC_STD_6e=std\socket.d SRC_STD_6f=std\socketstream.d SRC_STD_6h=std\conv.d SRC_STD_6i=std\zip.d SRC_STD_6j=std\cstream.d SRC_STD_7= \ std\stdint.d \ std\json.d \ std\parallelism.d \ std\mathspecial.d \ std\process.d SRC_STD_9= $(SRC_STD_ALLOC) SRC_STD_ALL= $(SRC_STD_1_HEAVY) $(SRC_STD_2a_HEAVY) \ $(SRC_STD_math) \ $(SRC_STD_3) $(SRC_STD_3a) $(SRC_STD_3b) $(SRC_STD_3c) $(SRC_STD_4) \ $(SRC_STD_6a) \ $(SRC_STD_6c) \ $(SRC_STD_6d) \ $(SRC_STD_6e) \ $(SRC_STD_6f) \ $(SRC_STD_CONTAINER) \ $(SRC_STD_6h) \ $(SRC_STD_6i) \ $(SRC_STD_6j) \ $(SRC_STD_7) \ $(SRC_STD_LOGGER) \ $(SRC_STD_9) SRC= unittest.d index.d SRC_STD= std\zlib.d std\zip.d std\stdint.d std\conv.d std\utf.d std\uri.d \ std\math.d std\string.d std\path.d std\datetime.d \ std\csv.d std\file.d std\compiler.d std\system.d \ std\outbuffer.d std\base64.d \ std\meta.d std\mmfile.d \ std\random.d std\stream.d std\process.d \ std\socket.d std\socketstream.d std\format.d \ std\stdio.d std\uni.d std\uuid.d \ std\cstream.d std\demangle.d \ std\signals.d std\typetuple.d std\traits.d \ std\getopt.d \ std\variant.d std\numeric.d std\bitmanip.d std\complex.d std\mathspecial.d \ std\functional.d std\array.d std\typecons.d \ std\json.d std\xml.d std\encoding.d std\bigint.d std\concurrency.d \ std\concurrencybase.d std\stdiobase.d std\parallelism.d \ std\exception.d std\ascii.d SRC_STD_REGEX= std\regex\internal\ir.d std\regex\package.d std\regex\internal\parser.d \ std\regex\internal\tests.d std\regex\internal\backtracking.d \ std\regex\internal\thompson.d std\regex\internal\kickstart.d \ std\regex\internal\generator.d SRC_STD_RANGE= std\range\package.d std\range\primitives.d \ std\range\interfaces.d SRC_STD_NDSLICE= std\experimental\ndslice\package.d \ std\experimental\ndslice\iteration.d \ std\experimental\ndslice\selection.d \ std\experimental\ndslice\slice.d \ std\experimental\ndslice\internal.d SRC_STD_NET= std\net\isemail.d std\net\curl.d SRC_STD_C= std\c\process.d std\c\stdlib.d std\c\time.d std\c\stdio.d \ std\c\math.d std\c\stdarg.d std\c\stddef.d std\c\fenv.d std\c\string.d \ std\c\locale.d std\c\wcharh.d SRC_STD_WIN= std\windows\registry.d \ std\windows\iunknown.d std\windows\syserror.d std\windows\charset.d SRC_STD_C_WIN= std\c\windows\windows.d std\c\windows\com.d \ std\c\windows\winsock.d std\c\windows\stat.d SRC_STD_C_LINUX= std\c\linux\linux.d \ std\c\linux\socket.d std\c\linux\pthread.d std\c\linux\termios.d \ std\c\linux\tipc.d SRC_STD_C_OSX= std\c\osx\socket.d SRC_STD_C_FREEBSD= std\c\freebsd\socket.d SRC_STD_INTERNAL= std\internal\cstring.d std\internal\processinit.d \ std\internal\unicode_tables.d std\internal\unicode_comp.d std\internal\unicode_decomp.d \ std\internal\unicode_grapheme.d std\internal\unicode_norm.d std\internal\scopebuffer.d \ std\internal\test\dummyrange.d SRC_STD_INTERNAL_DIGEST= std\internal\digest\sha_SSSE3.d SRC_STD_INTERNAL_MATH= std\internal\math\biguintcore.d \ std\internal\math\biguintnoasm.d std\internal\math\biguintx86.d \ std\internal\math\gammafunction.d std\internal\math\errorfunction.d SRC_STD_INTERNAL_WINDOWS= std\internal\windows\advapi32.d SRC_ETC= SRC_ETC_C= etc\c\zlib.d etc\c\curl.d etc\c\sqlite3.d \ etc\c\odbc\sql.d etc\c\odbc\sqlext.d etc\c\odbc\sqltypes.d etc\c\odbc\sqlucode.d SRC_TO_COMPILE_NOT_STD= \ $(SRC_STD_REGEX) \ $(SRC_STD_NET) \ $(SRC_STD_C) \ $(SRC_STD_WIN) \ $(SRC_STD_C_WIN) \ $(SRC_STD_INTERNAL) \ $(SRC_STD_INTERNAL_DIGEST) \ $(SRC_STD_INTERNAL_MATH) \ $(SRC_STD_INTERNAL_WINDOWS) \ $(SRC_ETC) \ $(SRC_ETC_C) SRC_TO_COMPILE= $(SRC_STD_ALL) \ $(SRC_STD_ALGO) \ $(SRC_STD_RANGE) \ $(SRC_STD_NDSLICE) \ $(SRC_TO_COMPILE_NOT_STD) SRC_ZLIB= \ etc\c\zlib\crc32.h \ etc\c\zlib\deflate.h \ etc\c\zlib\gzguts.h \ etc\c\zlib\inffixed.h \ etc\c\zlib\inffast.h \ etc\c\zlib\inftrees.h \ etc\c\zlib\inflate.h \ etc\c\zlib\trees.h \ etc\c\zlib\zconf.h \ etc\c\zlib\zlib.h \ etc\c\zlib\zutil.h \ etc\c\zlib\adler32.c \ etc\c\zlib\compress.c \ etc\c\zlib\crc32.c \ etc\c\zlib\deflate.c \ etc\c\zlib\example.c \ etc\c\zlib\gzclose.c \ etc\c\zlib\gzlib.c \ etc\c\zlib\gzread.c \ etc\c\zlib\gzwrite.c \ etc\c\zlib\infback.c \ etc\c\zlib\inffast.c \ etc\c\zlib\inflate.c \ etc\c\zlib\inftrees.c \ etc\c\zlib\minigzip.c \ etc\c\zlib\trees.c \ etc\c\zlib\uncompr.c \ etc\c\zlib\zutil.c \ etc\c\zlib\algorithm.txt \ etc\c\zlib\zlib.3 \ etc\c\zlib\ChangeLog \ etc\c\zlib\README \ etc\c\zlib\win32.mak \ etc\c\zlib\win64.mak \ etc\c\zlib\linux.mak \ etc\c\zlib\osx.mak DOCS= $(DOC)\object.html \ $(DOC)\core_atomic.html \ $(DOC)\core_bitop.html \ $(DOC)\core_exception.html \ $(DOC)\core_memory.html \ $(DOC)\core_runtime.html \ $(DOC)\core_simd.html \ $(DOC)\core_time.html \ $(DOC)\core_thread.html \ $(DOC)\core_vararg.html \ $(DOC)\core_sync_barrier.html \ $(DOC)\core_sync_condition.html \ $(DOC)\core_sync_config.html \ $(DOC)\core_sync_exception.html \ $(DOC)\core_sync_mutex.html \ $(DOC)\core_sync_rwmutex.html \ $(DOC)\core_sync_semaphore.html \ $(DOC)\std_algorithm.html \ $(DOC)\std_algorithm_comparison.html \ $(DOC)\std_algorithm_iteration.html \ $(DOC)\std_algorithm_mutation.html \ $(DOC)\std_algorithm_searching.html \ $(DOC)\std_algorithm_setops.html \ $(DOC)\std_algorithm_sorting.html \ $(DOC)\std_array.html \ $(DOC)\std_ascii.html \ $(DOC)\std_base64.html \ $(DOC)\std_bigint.html \ $(DOC)\std_bitmanip.html \ $(DOC)\std_concurrency.html \ $(DOC)\std_compiler.html \ $(DOC)\std_complex.html \ $(DOC)\std_container_array.html \ $(DOC)\std_container_binaryheap.html \ $(DOC)\std_container_dlist.html \ $(DOC)\std_container_rbtree.html \ $(DOC)\std_container_slist.html \ $(DOC)\std_container.html \ $(DOC)\std_container_util.html \ $(DOC)\std_conv.html \ $(DOC)\std_digest_crc.html \ $(DOC)\std_digest_sha.html \ $(DOC)\std_digest_md.html \ $(DOC)\std_digest_ripemd.html \ $(DOC)\std_digest_hmac.html \ $(DOC)\std_digest_digest.html \ $(DOC)\std_digest_hmac.html \ $(DOC)\std_cstream.html \ $(DOC)\std_csv.html \ $(DOC)\std_datetime.html \ $(DOC)\std_demangle.html \ $(DOC)\std_encoding.html \ $(DOC)\std_exception.html \ $(DOC)\std_file.html \ $(DOC)\std_format.html \ $(DOC)\std_functional.html \ $(DOC)\std_getopt.html \ $(DOC)\std_json.html \ $(DOC)\std_math.html \ $(DOC)\std_mathspecial.html \ $(DOC)\std_meta.html \ $(DOC)\std_mmfile.html \ $(DOC)\std_numeric.html \ $(DOC)\std_outbuffer.html \ $(DOC)\std_parallelism.html \ $(DOC)\std_path.html \ $(DOC)\std_process.html \ $(DOC)\std_random.html \ $(DOC)\std_range.html \ $(DOC)\std_range_primitives.html \ $(DOC)\std_range_interfaces.html \ $(DOC)\std_regex.html \ $(DOC)\std_signals.html \ $(DOC)\std_socket.html \ $(DOC)\std_socketstream.html \ $(DOC)\std_stdint.html \ $(DOC)\std_stdio.html \ $(DOC)\std_stream.html \ $(DOC)\std_string.html \ $(DOC)\std_system.html \ $(DOC)\std_traits.html \ $(DOC)\std_typecons.html \ $(DOC)\std_typetuple.html \ $(DOC)\std_uni.html \ $(DOC)\std_uri.html \ $(DOC)\std_utf.html \ $(DOC)\std_uuid.html \ $(DOC)\std_variant.html \ $(DOC)\std_xml.html \ $(DOC)\std_zip.html \ $(DOC)\std_zlib.html \ $(DOC)\std_net_isemail.html \ $(DOC)\std_net_curl.html \ $(DOC)\std_experimental_logger_core.html \ $(DOC)\std_experimental_logger_filelogger.html \ $(DOC)\std_experimental_logger_multilogger.html \ $(DOC)\std_experimental_logger_nulllogger.html \ $(DOC)\std_experimental_logger.html \ $(DOC)\std_experimental_allocator_building_blocks_affix_allocator.html \ $(DOC)\std_experimental_allocator_building_blocks_allocator_list.html \ $(DOC)\std_experimental_allocator_building_blocks_bitmapped_block.html \ $(DOC)\std_experimental_allocator_building_blocks_bucketizer.html \ $(DOC)\std_experimental_allocator_building_blocks_fallback_allocator.html \ $(DOC)\std_experimental_allocator_building_blocks_free_list.html \ $(DOC)\std_experimental_allocator_building_blocks_free_tree.html \ $(DOC)\std_experimental_allocator_building_blocks_kernighan_ritchie.html \ $(DOC)\std_experimental_allocator_building_blocks_null_allocator.html \ $(DOC)\std_experimental_allocator_building_blocks_quantizer.html \ $(DOC)\std_experimental_allocator_building_blocks_region.html \ $(DOC)\std_experimental_allocator_building_blocks_scoped_allocator.html \ $(DOC)\std_experimental_allocator_building_blocks_segregator.html \ $(DOC)\std_experimental_allocator_building_blocks_stats_collector.html \ $(DOC)\std_experimental_allocator_building_blocks.html \ $(DOC)\std_experimental_allocator_common.html \ $(DOC)\std_experimental_allocator_gc_allocator.html \ $(DOC)\std_experimental_allocator_mmap_allocator.html \ $(DOC)\std_experimental_allocator_showcase.html \ $(DOC)\std_experimental_allocator_typed.html \ $(DOC)\std_experimental_allocator.html \ $(DOC)\std_experimental_ndslice_iteration.html \ $(DOC)\std_experimental_ndslice_selection.html \ $(DOC)\std_experimental_ndslice_slice.html \ $(DOC)\std_experimental_ndslice.html \ $(DOC)\std_windows_charset.html \ $(DOC)\std_windows_registry.html \ $(DOC)\std_c_fenv.html \ $(DOC)\std_c_locale.html \ $(DOC)\std_c_math.html \ $(DOC)\std_c_process.html \ $(DOC)\std_c_stdarg.html \ $(DOC)\std_c_stddef.html \ $(DOC)\std_c_stdio.html \ $(DOC)\std_c_stdlib.html \ $(DOC)\std_c_string.html \ $(DOC)\std_c_time.html \ $(DOC)\std_c_wcharh.html \ $(DOC)\etc_c_curl.html \ $(DOC)\etc_c_sqlite3.html \ $(DOC)\etc_c_zlib.html \ $(DOC)\etc_c_odbc_sql.html \ $(DOC)\etc_c_odbc_sqlext.html \ $(DOC)\etc_c_odbc_sqltypes.html \ $(DOC)\etc_c_odbc_sqlucode.html \ $(DOC)\index.html $(LIB) : $(SRC_TO_COMPILE) \ $(ZLIB) $(DRUNTIMELIB) win32.mak win64.mak $(DMD) -lib -of$(LIB) -Xfphobos.json $(DFLAGS) $(SRC_TO_COMPILE) \ $(ZLIB) $(DRUNTIMELIB) UNITTEST_OBJS= \ unittest1.obj \ unittest2.obj \ unittest2a.obj \ unittestM.obj \ unittest3.obj \ unittest3a.obj \ unittest3b.obj \ unittest3c.obj \ unittest4.obj \ unittest5a.obj \ unittest5b.obj \ unittest6a.obj \ unittest6c.obj \ unittest6d.obj \ unittest6e.obj \ unittest6f.obj \ unittest6g.obj \ unittest6h.obj \ unittest6i.obj \ unittest6j.obj \ unittest7.obj \ unittest8.obj \ unittest9.obj unittest : $(LIB) $(DMD) $(UDFLAGS) -c -unittest -ofunittest1.obj $(SRC_STD_1_HEAVY) $(DMD) $(UDFLAGS) -c -unittest -ofunittest2.obj $(SRC_STD_RANGE) $(DMD) $(UDFLAGS) -c -unittest -ofunittest2.obj $(SRC_STD_NDSLICE) $(DMD) $(UDFLAGS) -c -unittest -ofunittest2a.obj $(SRC_STD_2a_HEAVY) $(DMD) $(UDFLAGS) -c -unittest -ofunittestM.obj $(SRC_STD_math) $(DMD) $(UDFLAGS) -c -unittest -ofunittest3.obj $(SRC_STD_3) $(DMD) $(UDFLAGS) -c -unittest -ofunittest3a.obj $(SRC_STD_3a) $(DMD) $(UDFLAGS) -c -unittest -ofunittest3b.obj $(SRC_STD_3b) $(DMD) $(UDFLAGS) -c -unittest -ofunittest3c.obj $(SRC_STD_3c) $(DMD) $(UDFLAGS) -c -unittest -ofunittest4.obj $(SRC_STD_4) $(DMD) $(UDFLAGS) -c -unittest -ofunittest5a.obj $(SRC_STD_5a) $(DMD) $(UDFLAGS) -c -unittest -ofunittest5b.obj $(SRC_STD_5b) $(DMD) $(UDFLAGS) -c -unittest -ofunittest6a.obj $(SRC_STD_6a) $(DMD) $(UDFLAGS) -c -unittest -ofunittest6c.obj $(SRC_STD_6c) $(DMD) $(UDFLAGS) -c -unittest -ofunittest6d.obj $(SRC_STD_6d) $(DMD) $(UDFLAGS) -c -unittest -ofunittest6e.obj $(SRC_STD_6e) $(DMD) $(UDFLAGS) -c -unittest -ofunittest6f.obj $(SRC_STD_6f) $(DMD) $(UDFLAGS) -c -unittest -ofunittest6g.obj $(SRC_STD_CONTAINER) $(DMD) $(UDFLAGS) -c -unittest -ofunittest6h.obj $(SRC_STD_6h) $(DMD) $(UDFLAGS) -c -unittest -ofunittest6i.obj $(SRC_STD_6i) $(DMD) $(UDFLAGS) -c -unittest -ofunittest6j.obj $(SRC_STD_6j) $(DMD) $(UDFLAGS) -c -unittest -ofunittest7.obj $(SRC_STD_7) $(SRC_STD_LOGGER) $(DMD) $(UDFLAGS) -c -unittest -ofunittest8.obj $(SRC_TO_COMPILE_NOT_STD) $(DMD) $(UDFLAGS) -c -unittest -ofunittest9.obj $(SRC_STD_9) $(DMD) $(UDFLAGS) -L/OPT:NOICF -unittest unittest.d $(UNITTEST_OBJS) \ $(ZLIB) $(DRUNTIMELIB) .\unittest.exe #unittest : unittest.exe # unittest # #unittest.exe : unittest.d $(LIB) # $(DMD) -conf= unittest -g # dmc unittest.obj -g cov : $(SRC_TO_COMPILE) $(LIB) $(DMD) -conf= -m$(MODEL) -cov -unittest -ofcov.exe unittest.d $(SRC_TO_COMPILE) $(LIB) cov html : $(DOCS) changelog.html: changelog.dd $(DMD) -Dfchangelog.html changelog.dd ################### Win32 COFF support ######################### # default to 32-bit compiler relative to the location of the 64-bit compiler, # link and lib are architecture agnostic CC32=$(CC)\..\..\cl # build phobos32mscoff.lib phobos32mscoff: $(MAKE) -f win64.mak "DMD=$(DMD)" "MAKE=$(MAKE)" MODEL=32mscoff "CC=\$(CC32)"\"" "AR=\$(AR)"\"" "VCDIR=$(VCDIR)" "SDKDIR=$(SDKDIR)" # run unittests for 32-bit COFF version unittest32mscoff: $(MAKE) -f win64.mak "DMD=$(DMD)" "MAKE=$(MAKE)" MODEL=32mscoff "CC=\$(CC32)"\"" "AR=\$(AR)"\"" "VCDIR=$(VCDIR)" "SDKDIR=$(SDKDIR)" unittest ###################################################### $(ZLIB): $(SRC_ZLIB) cd etc\c\zlib $(MAKE) -f win64.mak MODEL=$(MODEL) zlib$(MODEL).lib "CC=\$(CC)"\"" "LIB=\$(AR)"\"" "VCDIR=$(VCDIR)" cd ..\..\.. ################## DOCS #################################### DDOCFLAGS=$(DFLAGS) -version=StdDdoc $(DOC)\object.html : $(STDDOC) $(DRUNTIME)\src\object.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\object.html $(STDDOC) $(DRUNTIME)\src\object.d -I$(DRUNTIME)\src\ $(DOC)\index.html : $(STDDOC) index.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\index.html $(STDDOC) index.d $(DOC)\core_atomic.html : $(STDDOC) $(DRUNTIME)\src\core\atomic.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_atomic.html $(STDDOC) $(DRUNTIME)\src\core\atomic.d -I$(DRUNTIME)\src\ $(DOC)\core_bitop.html : $(STDDOC) $(DRUNTIME)\src\core\bitop.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_bitop.html $(STDDOC) $(DRUNTIME)\src\core\bitop.d -I$(DRUNTIME)\src\ $(DOC)\core_exception.html : $(STDDOC) $(DRUNTIME)\src\core\exception.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_exception.html $(STDDOC) $(DRUNTIME)\src\core\exception.d -I$(DRUNTIME)\src\ $(DOC)\core_memory.html : $(STDDOC) $(DRUNTIME)\src\core\memory.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_memory.html $(STDDOC) $(DRUNTIME)\src\core\memory.d -I$(DRUNTIME)\src\ $(DOC)\core_runtime.html : $(STDDOC) $(DRUNTIME)\src\core\runtime.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_runtime.html $(STDDOC) $(DRUNTIME)\src\core\runtime.d -I$(DRUNTIME)\src\ $(DOC)\core_simd.html : $(STDDOC) $(DRUNTIME)\src\core\simd.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_simd.html $(STDDOC) $(DRUNTIME)\src\core\simd.d -I$(DRUNTIME)\src\ $(DOC)\core_time.html : $(STDDOC) $(DRUNTIME)\src\core\time.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_time.html $(STDDOC) $(DRUNTIME)\src\core\time.d -I$(DRUNTIME)\src\ $(DOC)\core_thread.html : $(STDDOC) $(DRUNTIME)\src\core\thread.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_thread.html $(STDDOC) $(DRUNTIME)\src\core\thread.d -I$(DRUNTIME)\src\ $(DOC)\core_vararg.html : $(STDDOC) $(DRUNTIME)\src\core\vararg.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_vararg.html $(STDDOC) $(DRUNTIME)\src\core\vararg.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_barrier.html : $(STDDOC) $(DRUNTIME)\src\core\sync\barrier.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_barrier.html $(STDDOC) $(DRUNTIME)\src\core\sync\barrier.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_condition.html : $(STDDOC) $(DRUNTIME)\src\core\sync\condition.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_condition.html $(STDDOC) $(DRUNTIME)\src\core\sync\condition.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_config.html : $(STDDOC) $(DRUNTIME)\src\core\sync\config.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_config.html $(STDDOC) $(DRUNTIME)\src\core\sync\config.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_exception.html : $(STDDOC) $(DRUNTIME)\src\core\sync\exception.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_exception.html $(STDDOC) $(DRUNTIME)\src\core\sync\exception.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_mutex.html : $(STDDOC) $(DRUNTIME)\src\core\sync\mutex.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_mutex.html $(STDDOC) $(DRUNTIME)\src\core\sync\mutex.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_rwmutex.html : $(STDDOC) $(DRUNTIME)\src\core\sync\rwmutex.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_rwmutex.html $(STDDOC) $(DRUNTIME)\src\core\sync\rwmutex.d -I$(DRUNTIME)\src\ $(DOC)\core_sync_semaphore.html : $(STDDOC) $(DRUNTIME)\src\core\sync\semaphore.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\core_sync_semaphore.html $(STDDOC) $(DRUNTIME)\src\core\sync\semaphore.d -I$(DRUNTIME)\src\ $(DOC)\std_algorithm.html : $(STDDOC) std\algorithm\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm.html $(STDDOC) std\algorithm\package.d $(DOC)\std_algorithm_comparison.html : $(STDDOC) std\algorithm\comparison.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_comparison.html $(STDDOC) std\algorithm\comparison.d $(DOC)\std_algorithm_iteration.html : $(STDDOC) std\algorithm\iteration.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_iteration.html $(STDDOC) std\algorithm\iteration.d $(DOC)\std_algorithm_mutation.html : $(STDDOC) std\algorithm\mutation.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_mutation.html $(STDDOC) std\algorithm\mutation.d $(DOC)\std_algorithm_searching.html : $(STDDOC) std\algorithm\searching.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_searching.html $(STDDOC) std\algorithm\searching.d $(DOC)\std_algorithm_setops.html : $(STDDOC) std\algorithm\setops.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_setops.html $(STDDOC) std\algorithm\setops.d $(DOC)\std_algorithm_sorting.html : $(STDDOC) std\algorithm\sorting.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_algorithm_sorting.html $(STDDOC) std\algorithm\sorting.d $(DOC)\std_array.html : $(STDDOC) std\array.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_array.html $(STDDOC) std\array.d $(DOC)\std_ascii.html : $(STDDOC) std\ascii.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_ascii.html $(STDDOC) std\ascii.d $(DOC)\std_base64.html : $(STDDOC) std\base64.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_base64.html $(STDDOC) std\base64.d $(DOC)\std_bigint.html : $(STDDOC) std\bigint.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_bigint.html $(STDDOC) std\bigint.d $(DOC)\std_bitmanip.html : $(STDDOC) std\bitmanip.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_bitmanip.html $(STDDOC) std\bitmanip.d $(DOC)\std_concurrency.html : $(STDDOC) std\concurrency.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_concurrency.html $(STDDOC) std\concurrency.d $(DOC)\std_compiler.html : $(STDDOC) std\compiler.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_compiler.html $(STDDOC) std\compiler.d $(DOC)\std_complex.html : $(STDDOC) std\complex.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_complex.html $(STDDOC) std\complex.d $(DOC)\std_conv.html : $(STDDOC) std\conv.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_conv.html $(STDDOC) std\conv.d $(DOC)\std_container_array.html : $(STDDOC) std\container\array.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_array.html $(STDDOC) std\container\array.d $(DOC)\std_container_binaryheap.html : $(STDDOC) std\container\binaryheap.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_binaryheap.html $(STDDOC) std\container\binaryheap.d $(DOC)\std_container_dlist.html : $(STDDOC) std\container\dlist.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_dlist.html $(STDDOC) std\container\dlist.d $(DOC)\std_container_rbtree.html : $(STDDOC) std\container\rbtree.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_rbtree.html $(STDDOC) std\container\rbtree.d $(DOC)\std_container_slist.html : $(STDDOC) std\container\slist.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_slist.html $(STDDOC) std\container\slist.d $(DOC)\std_container_util.html : $(STDDOC) std\container\util.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container_util.html $(STDDOC) std\container\util.d $(DOC)\std_container.html : $(STDDOC) std\container\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_container.html $(STDDOC) std\container\package.d $(DOC)\std_range.html : $(STDDOC) std\range\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_range.html $(STDDOC) std\range\package.d $(DOC)\std_range_primitives.html : $(STDDOC) std\range\primitives.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_range_primitives.html $(STDDOC) std\range\primitives.d $(DOC)\std_range_interfaces.html : $(STDDOC) std\range\interfaces.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_range_interfaces.html $(STDDOC) std\range\interfaces.d $(DOC)\std_cstream.html : $(STDDOC) std\cstream.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_cstream.html $(STDDOC) std\cstream.d $(DOC)\std_csv.html : $(STDDOC) std\csv.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_csv.html $(STDDOC) std\csv.d $(DOC)\std_datetime.html : $(STDDOC) std\datetime.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_datetime.html $(STDDOC) std\datetime.d $(DOC)\std_demangle.html : $(STDDOC) std\demangle.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_demangle.html $(STDDOC) std\demangle.d $(DOC)\std_exception.html : $(STDDOC) std\exception.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_exception.html $(STDDOC) std\exception.d $(DOC)\std_file.html : $(STDDOC) std\file.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_file.html $(STDDOC) std\file.d $(DOC)\std_format.html : $(STDDOC) std\format.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_format.html $(STDDOC) std\format.d $(DOC)\std_functional.html : $(STDDOC) std\functional.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_functional.html $(STDDOC) std\functional.d $(DOC)\std_getopt.html : $(STDDOC) std\getopt.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_getopt.html $(STDDOC) std\getopt.d $(DOC)\std_json.html : $(STDDOC) std\json.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_json.html $(STDDOC) std\json.d $(DOC)\std_math.html : $(STDDOC) std\math.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_math.html $(STDDOC) std\math.d $(DOC)\std_meta.html : $(STDDOC) std\meta.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_meta.html $(STDDOC) std\meta.d $(DOC)\std_mathspecial.html : $(STDDOC) std\mathspecial.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_mathspecial.html $(STDDOC) std\mathspecial.d $(DOC)\std_mmfile.html : $(STDDOC) std\mmfile.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_mmfile.html $(STDDOC) std\mmfile.d $(DOC)\std_numeric.html : $(STDDOC) std\numeric.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_numeric.html $(STDDOC) std\numeric.d $(DOC)\std_outbuffer.html : $(STDDOC) std\outbuffer.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_outbuffer.html $(STDDOC) std\outbuffer.d $(DOC)\std_parallelism.html : $(STDDOC) std\parallelism.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_parallelism.html $(STDDOC) std\parallelism.d $(DOC)\std_path.html : $(STDDOC) std\path.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_path.html $(STDDOC) std\path.d $(DOC)\std_process.html : $(STDDOC) std\process.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_process.html $(STDDOC) std\process.d $(DOC)\std_random.html : $(STDDOC) std\random.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_random.html $(STDDOC) std\random.d $(DOC)\std_range.html : $(STDDOC) std\range\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_range.html $(STDDOC) std\range\package.d $(DOC)\std_regex.html : $(STDDOC) std\regex\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_regex.html $(STDDOC) std\regex\package.d $(DOC)\std_signals.html : $(STDDOC) std\signals.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_signals.html $(STDDOC) std\signals.d $(DOC)\std_socket.html : $(STDDOC) std\socket.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_socket.html $(STDDOC) std\socket.d $(DOC)\std_socketstream.html : $(STDDOC) std\socketstream.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_socketstream.html $(STDDOC) std\socketstream.d $(DOC)\std_stdint.html : $(STDDOC) std\stdint.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_stdint.html $(STDDOC) std\stdint.d $(DOC)\std_stdio.html : $(STDDOC) std\stdio.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_stdio.html $(STDDOC) std\stdio.d $(DOC)\std_stream.html : $(STDDOC) std\stream.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_stream.html $(STDDOC) std\stream.d $(DOC)\std_string.html : $(STDDOC) std\string.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_string.html $(STDDOC) std\string.d $(DOC)\std_system.html : $(STDDOC) std\system.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_system.html $(STDDOC) std\system.d $(DOC)\std_traits.html : $(STDDOC) std\traits.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_traits.html $(STDDOC) std\traits.d $(DOC)\std_typecons.html : $(STDDOC) std\typecons.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_typecons.html $(STDDOC) std\typecons.d $(DOC)\std_typetuple.html : $(STDDOC) std\typetuple.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_typetuple.html $(STDDOC) std\typetuple.d $(DOC)\std_uni.html : $(STDDOC) std\uni.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_uni.html $(STDDOC) std\uni.d $(DOC)\std_uri.html : $(STDDOC) std\uri.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_uri.html $(STDDOC) std\uri.d $(DOC)\std_utf.html : $(STDDOC) std\utf.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_utf.html $(STDDOC) std\utf.d $(DOC)\std_uuid.html : $(STDDOC) std\uuid.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_uuid.html $(STDDOC) std\uuid.d $(DOC)\std_variant.html : $(STDDOC) std\variant.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_variant.html $(STDDOC) std\variant.d $(DOC)\std_xml.html : $(STDDOC) std\xml.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_xml.html $(STDDOC) std\xml.d $(DOC)\std_encoding.html : $(STDDOC) std\encoding.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_encoding.html $(STDDOC) std\encoding.d $(DOC)\std_zip.html : $(STDDOC) std\zip.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_zip.html $(STDDOC) std\zip.d $(DOC)\std_zlib.html : $(STDDOC) std\zlib.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_zlib.html $(STDDOC) std\zlib.d $(DOC)\std_net_isemail.html : $(STDDOC) std\net\isemail.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_net_isemail.html $(STDDOC) std\net\isemail.d $(DOC)\std_net_curl.html : $(STDDOC) std\net\curl.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_net_curl.html $(STDDOC) std\net\curl.d $(DOC)\std_experimental_logger_core.html : $(STDDOC) std\experimental\logger\core.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger_core.html $(STDDOC) std\experimental\logger\core.d $(DOC)\std_experimental_logger_multilogger.html : $(STDDOC) std\experimental\logger\multilogger.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger_multilogger.html $(STDDOC) std\experimental\logger\multilogger.d $(DOC)\std_experimental_logger_filelogger.html : $(STDDOC) std\experimental\logger\filelogger.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger_filelogger.html $(STDDOC) std\experimental\logger\filelogger.d $(DOC)\std_experimental_logger_nulllogger.html : $(STDDOC) std\experimental\logger\nulllogger.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger_nulllogger.html $(STDDOC) std\experimental\logger\nulllogger.d $(DOC)\std_experimental_logger.html : $(STDDOC) std\experimental\logger\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_logger.html $(STDDOC) std\experimental\logger\package.d $(DOC)\std_experimental_allocator_building_blocks_affix_allocator.html : $(STDDOC) std\experimental\allocator\building_blocks\affix_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_affix_allocator.html \ $(STDDOC) std\experimental\allocator\building_blocks\affix_allocator.d $(DOC)\std_experimental_allocator_building_blocks_allocator_list.html : $(STDDOC) std\experimental\allocator\building_blocks\allocator_list.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_allocator_list.html \ $(STDDOC) std\experimental\allocator\building_blocks\allocator_list.d $(DOC)\std_experimental_allocator_building_blocks_bitmapped_block.html : $(STDDOC) std\experimental\allocator\building_blocks\bitmapped_block.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_bitmapped_block.html \ $(STDDOC) std\experimental\allocator\building_blocks\bitmapped_block.d $(DOC)\std_experimental_allocator_building_blocks_bucketizer.html : $(STDDOC) std\experimental\allocator\building_blocks\bucketizer.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_bucketizer.html \ $(STDDOC) std\experimental\allocator\building_blocks\bucketizer.d $(DOC)\std_experimental_allocator_building_blocks_fallback_allocator.html : $(STDDOC) std\experimental\allocator\building_blocks\fallback_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_fallback_allocator.html \ $(STDDOC) std\experimental\allocator\building_blocks\fallback_allocator.d $(DOC)\std_experimental_allocator_building_blocks_free_list.html : $(STDDOC) std\experimental\allocator\building_blocks\free_list.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_free_list.html \ $(STDDOC) std\experimental\allocator\building_blocks\free_list.d $(DOC)\std_experimental_allocator_building_blocks_free_tree.html : $(STDDOC) std\experimental\allocator\building_blocks\free_tree.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_free_tree.html \ $(STDDOC) std\experimental\allocator\building_blocks\free_tree.d $(DOC)\std_experimental_allocator_building_blocks_kernighan_ritchie.html : $(STDDOC) std\experimental\allocator\building_blocks\kernighan_ritchie.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_kernighan_ritchie.html \ $(STDDOC) std\experimental\allocator\building_blocks\kernighan_ritchie.d $(DOC)\std_experimental_allocator_building_blocks_null_allocator.html : $(STDDOC) std\experimental\allocator\building_blocks\null_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_null_allocator.html \ $(STDDOC) std\experimental\allocator\building_blocks\null_allocator.d $(DOC)\std_experimental_allocator_building_blocks_quantizer.html : $(STDDOC) std\experimental\allocator\building_blocks\quantizer.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_quantizer.html \ $(STDDOC) std\experimental\allocator\building_blocks\quantizer.d $(DOC)\std_experimental_allocator_building_blocks_region.html : $(STDDOC) std\experimental\allocator\building_blocks\region.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_region.html \ $(STDDOC) std\experimental\allocator\building_blocks\region.d $(DOC)\std_experimental_allocator_building_blocks_scoped_allocator.html : $(STDDOC) std\experimental\allocator\building_blocks\scoped_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_scoped_allocator.html \ $(STDDOC) std\experimental\allocator\building_blocks\scoped_allocator.d $(DOC)\std_experimental_allocator_building_blocks_segregator.html : $(STDDOC) std\experimental\allocator\building_blocks\segregator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_segregator.html \ $(STDDOC) std\experimental\allocator\building_blocks\segregator.d $(DOC)\std_experimental_allocator_building_blocks_stats_collector.html : $(STDDOC) std\experimental\allocator\building_blocks\stats_collector.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks_stats_collector.html \ $(STDDOC) std\experimental\allocator\building_blocks\stats_collector.d $(DOC)\std_experimental_allocator_building_blocks.html : $(STDDOC) std\experimental\allocator\building_blocks\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_building_blocks.html \ $(STDDOC) std\experimental\allocator\building_blocks\package.d $(DOC)\std_experimental_allocator_common.html : $(STDDOC) std\experimental\allocator\common.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_common.html $(STDDOC) std\experimental\allocator\common.d $(DOC)\std_experimental_allocator_gc_allocator.html : $(STDDOC) std\experimental\allocator\gc_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_gc_allocator.html $(STDDOC) std\experimental\allocator\gc_allocator.d $(DOC)\std_experimental_allocator_mallocator.html : $(STDDOC) std\experimental\allocator\mallocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_mallocator.html $(STDDOC) std\experimental\allocator\mallocator.d $(DOC)\std_experimental_allocator_mmap_allocator.html : $(STDDOC) std\experimental\allocator\mmap_allocator.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_mmap_allocator.html $(STDDOC) std\experimental\allocator\mmap_allocator.d $(DOC)\std_experimental_allocator_showcase.html : $(STDDOC) std\experimental\allocator\showcase.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_showcase.html $(STDDOC) std\experimental\allocator\showcase.d $(DOC)\std_experimental_allocator_typed.html : $(STDDOC) std\experimental\allocator\typed.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator_typed.html $(STDDOC) std\experimental\allocator\typed.d $(DOC)\std_experimental_allocator.html : $(STDDOC) std\experimental\allocator\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_allocator.html $(STDDOC) std\experimental\allocator\package.d $(DOC)\std_experimental_ndslice_iteration.html : $(STDDOC) std\experimental\ndslice\iteration.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_ndslice_iteration.html $(STDDOC) std\experimental\ndslice\iteration.d $(DOC)\std_experimental_ndslice_selection.html : $(STDDOC) std\experimental\ndslice\selection.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_ndslice_selection.html $(STDDOC) std\experimental\ndslice\selection.d $(DOC)\std_experimental_ndslice_slice.html : $(STDDOC) std\experimental\ndslice\slice.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_ndslice_slice.html $(STDDOC) std\experimental\ndslice\slice.d $(DOC)\std_experimental_ndslice.html : $(STDDOC) std\experimental\ndslice\package.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_experimental_ndslice.html $(STDDOC) std\experimental\ndslice\package.d $(DOC)\std_digest_crc.html : $(STDDOC) std\digest\crc.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_crc.html $(STDDOC) std\digest\crc.d $(DOC)\std_digest_sha.html : $(STDDOC) std\digest\sha.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_sha.html $(STDDOC) std\digest\sha.d $(DOC)\std_digest_md.html : $(STDDOC) std\digest\md.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_md.html $(STDDOC) std\digest\md.d $(DOC)\std_digest_ripemd.html : $(STDDOC) std\digest\ripemd.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_ripemd.html $(STDDOC) std\digest\ripemd.d $(DOC)\std_digest_digest.html : $(STDDOC) std\digest\digest.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_digest.html $(STDDOC) std\digest\digest.d $(DOC)\std_digest_hmac.html : $(STDDOC) std\digest\hmac.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_digest_hmac.html $(STDDOC) std\digest\hmac.d $(DOC)\std_windows_charset.html : $(STDDOC) std\windows\charset.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_windows_charset.html $(STDDOC) std\windows\charset.d $(DOC)\std_windows_registry.html : $(STDDOC) std\windows\registry.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_windows_registry.html $(STDDOC) std\windows\registry.d $(DOC)\std_c_fenv.html : $(STDDOC) std\c\fenv.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_fenv.html $(STDDOC) std\c\fenv.d $(DOC)\std_c_locale.html : $(STDDOC) std\c\locale.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_locale.html $(STDDOC) std\c\locale.d $(DOC)\std_c_math.html : $(STDDOC) std\c\math.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_math.html $(STDDOC) std\c\math.d $(DOC)\std_c_process.html : $(STDDOC) std\c\process.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_process.html $(STDDOC) std\c\process.d $(DOC)\std_c_stdarg.html : $(STDDOC) std\c\stdarg.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_stdarg.html $(STDDOC) std\c\stdarg.d $(DOC)\std_c_stddef.html : $(STDDOC) std\c\stddef.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_stddef.html $(STDDOC) std\c\stddef.d $(DOC)\std_c_stdio.html : $(STDDOC) std\c\stdio.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_stdio.html $(STDDOC) std\c\stdio.d $(DOC)\std_c_stdlib.html : $(STDDOC) std\c\stdlib.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_stdlib.html $(STDDOC) std\c\stdlib.d $(DOC)\std_c_string.html : $(STDDOC) std\c\string.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_string.html $(STDDOC) std\c\string.d $(DOC)\std_c_time.html : $(STDDOC) std\c\time.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_time.html $(STDDOC) std\c\time.d $(DOC)\std_c_wcharh.html : $(STDDOC) std\c\wcharh.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\std_c_wcharh.html $(STDDOC) std\c\wcharh.d $(DOC)\etc_c_curl.html : $(STDDOC) etc\c\curl.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_curl.html $(STDDOC) etc\c\curl.d $(DOC)\etc_c_sqlite3.html : $(STDDOC) etc\c\sqlite3.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_sqlite3.html $(STDDOC) etc\c\sqlite3.d $(DOC)\etc_c_zlib.html : $(STDDOC) etc\c\zlib.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_zlib.html $(STDDOC) etc\c\zlib.d $(DOC)\etc_c_odbc_sql.html : $(STDDOC) etc\c\odbc\sql.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sql.html $(STDDOC) etc\c\odbc\sql.d $(DOC)\etc_c_odbc_sqlext.html : $(STDDOC) etc\c\odbc\sqlext.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sqlext.html $(STDDOC) etc\c\odbc\sqlext.d $(DOC)\etc_c_odbc_sqltypes.html : $(STDDOC) etc\c\odbc\sqltypes.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sqltypes.html $(STDDOC) etc\c\odbc\sqltypes.d $(DOC)\etc_c_odbc_sqlucode.html : $(STDDOC) etc\c\odbc\sqlucode.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sqlucode.html $(STDDOC) etc\c\odbc\sqlucode.d $(DOC)\etc_c_odbc_sql.html : $(STDDOC) etc\c\odbc\sql.d $(DMD) -c -o- $(DDOCFLAGS) -Df$(DOC)\etc_c_odbc_sql.html $(STDDOC) etc\c\odbc\sql.d ###################################################### zip: del phobos.zip zip32 -r phobos.zip . -x .git\* -x \*.lib -x \*.obj phobos.zip : zip clean: cd etc\c\zlib $(MAKE) -f win64.mak MODEL=$(MODEL) clean cd ..\..\.. del $(DOCS) del $(UNITTEST_OBJS) unittest.obj unittest.exe del $(LIB) del phobos.json cleanhtml: del $(DOCS) install: phobos.zip $(CP) phobos.lib phobos64.lib $(DIR)\windows\lib $(CP) $(DRUNTIME)\lib\gcstub.obj $(DRUNTIME)\lib\gcstub64.obj $(DIR)\windows\lib +rd/s/q $(DIR)\src\phobos unzip -o phobos.zip -d $(DIR)\src\phobos auto-tester-build: targets auto-tester-test: unittest ldc-1.1.0-beta3-src/runtime/phobos/index.d0000664000175000017500000004421312776215007016374 0ustar kaikaiDdoc $(P Phobos is the standard runtime library that comes with the D language compiler.) $(P Generally, the $(D std) namespace is used for the main modules in the Phobos standard library. The $(D etc) namespace is used for external C/C++ library bindings. The $(D core) namespace is used for low-level D runtime functions.) $(P The following table is a quick reference guide for which Phobos modules to use for a given category of functionality. Note that some modules may appear in more than one category, as some Phobos modules are quite generic and can be applied in a variety of situations.) $(BOOKTABLE , $(TR $(TH Modules) $(TH Description) ) $(LEADINGROW Algorithms & ranges) $(TR $(TDNW $(LINK2 std_algorithm.html, std.algorithm)$(BR) $(LINK2 std_range.html, std.range)$(BR) $(LINK2 std_range_primitives.html, std.range.primitives)$(BR) $(LINK2 std_range_interfaces.html, std.range.interfaces)$(BR) ) $(TD Generic algorithms that work with $(LINK2 std_range.html, ranges) of any type, including strings, arrays, and other kinds of sequentially-accessed data. Algorithms include searching, comparison, iteration, sorting, set operations, and mutation. ) ) $(LEADINGROW Array manipulation) $(TR $(TDNW $(LINK2 std_array.html, std.array)$(BR) $(LINK2 std_algorithm.html, std.algorithm)$(BR) ) $(TD Convenient operations commonly used with built-in arrays. Note that many common array operations are subsets of more generic algorithms that work with arbitrary ranges, so they are found in $(D std.algorithm). ) ) $(LEADINGROW Containers) $(TR $(TDNW $(LINK2 std_container_array.html, std.container.array)$(BR) $(LINK2 std_container_binaryheap.html, std.container.binaryheap)$(BR) $(LINK2 std_container_dlist.html, std.container.dlist)$(BR) $(LINK2 std_container_rbtree.html, std.container.rbtree)$(BR) $(LINK2 std_container_slist.html, std.container.slist)$(BR) ) $(TD See $(LINK2 std_container.html, std.container.*) for an overview. ) ) $(LEADINGROW Data formats) $(TR $(TDNW $(LINK2 std_base64.html, std.base64)) $(TD Encoding / decoding Base64 format.) ) $(TR $(TDNW $(LINK2 std_csv.html, std.csv)) $(TD Read Comma Separated Values and its variants from an input range of $(CODE dchar).) ) $(TR $(TDNW $(LINK2 std_json.html, std.json)) $(TD Read/write data in JSON format.) ) $(TR $(TDNW $(LINK2 std_xml.html, std.xml)) $(TD Read/write data in XML format.) ) $(TR $(TDNW $(LINK2 std_zip.html, std.zip)) $(TD Read/write data in the ZIP archive format.) ) $(TR $(TDNW $(LINK2 std_zlib.html, std.zlib)) $(TD Compress/decompress data using the zlib library.) ) $(LEADINGROW Data integrity) $(TR $(TDNW $(LINK2 std_digest_crc.html, std.digest.crc)) $(TD Cyclic Redundancy Check (32-bit) implementation.) ) $(TR $(TDNW $(LINK2 std_digest_digest.html, std.digest.digest)) $(TD Compute digests such as md5, sha1 and crc32.) ) $(TR $(TDNW $(LINK2 std_digest_hmac.html, std.digest.hmac)) $(TD Compute HMAC digests of arbitrary data.) ) $(TR $(TDNW $(LINK2 std_digest_md.html, std.digest.md)) $(TD Compute MD5 hash of arbitrary data.) ) $(TR $(TDNW $(LINK2 std_digest_ripemd.html, std.digest.ripemd)) $(TD Compute RIPEMD-160 hash of arbitrary data.) ) $(TR $(TDNW $(LINK2 std_digest_sha.html, std.digest.sha)) $(TD Compute SHA1 and SHA2 hashes of arbitrary data.) ) $(LEADINGROW Date & time) $(TR $(TDNW $(LINK2 std_datetime.html, std.datetime)) $(TD Provides convenient access to date and time representations.) ) $(TR $(TDNW $(LINK2 core_time.html, core.time)) $(TD Implements low-level time primitives.) ) $(LEADINGROW Exception handling) $(TR $(TDNW $(LINK2 std_exception.html, std.exception)) $(TD Implements routines related to exceptions.) ) $(TR $(TDNW $(LINK2 core_exception.html, core.exception)) $(TD Defines built-in exception types and low-level language hooks required by the compiler.) ) $(LEADINGROW External library bindings) $(TR $(TDNW $(LINK2 etc_c_curl.html, etc.c.curl)) $(TD Interface to libcurl C library.) ) $(TR $(TDNW $(LINK2 etc_c_odbc_sql.html, etc.c.odbc.sql)) $(TD Interface to ODBC C library.) ) $(TR $(TDNW $(LINK2 etc_c_odbc_sqlext.html, etc.c.odbc.sqlext)) ) $(TR $(TDNW $(LINK2 etc_c_odbc_sqltypes.html, etc.c.odbc.sqltypes)) ) $(TR $(TDNW $(LINK2 etc_c_odbc_sqlucode.html, etc.c.odbc.sqlucode)) ) $(TR $(TDNW $(LINK2 etc_c_sqlite3.html, etc.c.sqlite3)) $(TD Interface to SQLite C library.) ) $(TR $(TDNW $(LINK2 etc_c_zlib.html, etc.c.zlib)) $(TD Interface to zlib C library.) ) $(LEADINGROW I/O & File system) $(TR $(TDNW $(LINK2 std_file.html, std.file)) $(TD Manipulate files and directories.) ) $(TR $(TDNW $(LINK2 std_path.html, std.path)) $(TD Manipulate strings that represent filesystem paths.) ) $(TR $(TDNW $(LINK2 std_stdio.html, std.stdio)) $(TD Perform buffered I/O.) ) $(LEADINGROW Interoperability) $(TR $(TDNW $(LINK2 core_stdc_complex.html, core.stdc.complex)$(BR) $(LINK2 core_stdc_ctype.html, core.stdc.ctype)$(BR) $(LINK2 core_stdc_errno.html, core.stdc.errno)$(BR) $(LINK2 core_stdc_fenv.html, core.stdc.fenv)$(BR) $(LINK2 core_stdc_float_.html, core.stdc.float_)$(BR) $(LINK2 core_stdc_inttypes.html, core.stdc.inttypes)$(BR) $(LINK2 core_stdc_limits.html, core.stdc.limits)$(BR) $(LINK2 core_stdc_locale.html, core.stdc.locale)$(BR) $(LINK2 core_stdc_math.html, core.stdc.math)$(BR) $(LINK2 core_stdc_signal.html, core.stdc.signal)$(BR) $(LINK2 core_stdc_stdarg.html, core.stdc.stdarg)$(BR) $(LINK2 core_stdc_stddef.html, core.stdc.stddef)$(BR) $(LINK2 core_stdc_stdint.html, core.stdc.stdint)$(BR) $(LINK2 core_stdc_stdio.html, core.stdc.stdio)$(BR) $(LINK2 core_stdc_stdlib.html, core.stdc.stdlib)$(BR) $(LINK2 core_stdc_string.html, core.stdc.string)$(BR) $(LINK2 core_stdc_tgmath.html, core.stdc.tgmath)$(BR) $(LINK2 core_stdc_time.html, core.stdc.time)$(BR) $(LINK2 core_stdc_wchar_.html, core.stdc.wchar_)$(BR) $(LINK2 core_stdc_wctype.html, core.stdc.wctype)$(BR) ) $(TD D bindings for standard C headers.$(BR)$(BR) These are mostly undocumented, as documentation for the functions these declarations provide bindings to can be found on external resources. ) ) $(LEADINGROW Memory management) $(TR $(TDNW $(LINK2 core_memory.html, core.memory)) $(TD Control the built-in garbage collector.) ) $(TR $(TDNW $(LINK2 std_typecons.html, std.typecons)) $(TD Build scoped variables and reference-counted types.) ) $(LEADINGROW Metaprogramming) $(TR $(TDNW $(LINK2 core_attribute.html, core.attribute)) $(TD Definitions of special attributes recognized by the compiler.) ) $(TR $(TDNW $(LINK2 core_demangle.html, core.demangle)) $(TD Convert $(I mangled) D symbol identifiers to source representation.) ) $(TR $(TDNW $(LINK2 std_demangle.html, std.demangle)) $(TD A simple wrapper around core.demangle.) ) $(TR $(TDNW $(LINK2 std_meta.html, std.meta)) $(TD Construct and manipulate template argument lists (aka type lists).) ) $(TR $(TDNW $(LINK2 std_traits.html, std.traits)) $(TD Extract information about types and symbols at compile time.) ) $(TR $(TDNW $(LINK2 std_typecons.html, std.typecons)) $(TD Construct new, useful general purpose types.) ) $(LEADINGROW Multitasking) $(TR $(TDNW $(LINK2 std_concurrency.html, std.concurrency)) $(TD Low level messaging API for threads.) ) $(TR $(TDNW $(LINK2 std_parallelism.html, std.parallelism)) $(TD High level primitives for SMP parallelism.) ) $(TR $(TDNW $(LINK2 std_process.html, std.process)) $(TD Starting and manipulating processes.) ) $(TR $(TDNW $(LINK2 core_atomic.html, core.atomic)) $(TD Basic support for lock-free concurrent programming.) ) $(TR $(TDNW $(LINK2 core_sync_barrier.html, core.sync.barrier)) $(TD Synchronize the progress of a group of threads.) ) $(TR $(TDNW $(LINK2 core_sync_condition.html, core.sync.condition)) $(TD Synchronized condition checking.) ) $(TR $(TDNW $(LINK2 core_sync_exception.html, core.sync.exception)) $(TD Base class for synchronization exceptions.) ) $(TR $(TDNW $(LINK2 core_sync_mutex.html, core.sync.mutex)) $(TD Mutex for mutually exclusive access.) ) $(TR $(TDNW $(LINK2 core_sync_rwmutex.html, core.sync.rwmutex)) $(TD Shared read access and mutually exclusive write access.) ) $(TR $(TDNW $(LINK2 core_sync_semaphore.html, core.sync.semaphore)) $(TD General use synchronization semaphore.) ) $(TR $(TDNW $(LINK2 core_thread.html, core.thread)) $(TD Thread creation and management.) ) $(LEADINGROW Networking) $(TR $(TDNW $(LINK2 std_socket.html, std.socket)) $(TD Socket primitives.) ) $(TR $(TDNW $(LINK2 std_net_curl.html, std.net.curl)) $(TD Networking client functionality as provided by libcurl.) ) $(TR $(TDNW $(LINK2 std_net_isemail.html, std.net.isemail)) $(TD Validates an email address according to RFCs 5321, 5322 and others.) ) $(TR $(TDNW $(LINK2 std_uri.html, std.uri)) $(TD Encode and decode Uniform Resource Identifiers (URIs).) ) $(TR $(TDNW $(LINK2 std_uuid.html, std.uuid)) $(TD Universally-unique identifiers for resources in distributed systems.) ) $(LEADINGROW Numeric) $(TR $(TDNW $(LINK2 std_bigint.html, std.bigint)) $(TD An arbitrary-precision integer type.) ) $(TR $(TDNW $(LINK2 std_complex.html, std.complex)) $(TD A complex number type.) ) $(TR $(TDNW $(LINK2 std_math.html, std.math)) $(TD Elementary mathematical functions (powers, roots, trigonometry).) ) $(TR $(TDNW $(LINK2 std_mathspecial.html, std.mathspecial)) $(TD Families of transcendental functions.) ) $(TR $(TDNW $(LINK2 std_numeric.html, std.numeric)) $(TD Floating point numerics functions.) ) $(TR $(TDNW $(LINK2 std_random.html, std.random)) $(TD Pseudo-random number generators.) ) $(TR $(TDNW $(LINK2 core_checkedint.html, core.checkedint)) $(TD Range-checking integral arithmetic primitives.) ) $(TR $(TDNW $(LINK2 core_math.html, core.math)) $(TD Built-in mathematical intrinsics.) ) $(LEADINGROW Paradigms) $(TR $(TDNW $(LINK2 std_functional.html, std.functional)) $(TD Functions that manipulate other functions.) ) $(TR $(TDNW $(LINK2 std_algorithm.html, std.algorithm)) $(TD Generic algorithms for processing sequences.) ) $(TR $(TDNW $(LINK2 std_signals.html, std.signals)) $(TD Signal-and-slots framework for event-driven programming.) ) $(LEADINGROW Runtime utilities) $(TR $(TDNW $(LINK2 object.html, object)) $(TD Core language definitions. Automatically imported.) ) $(TR $(TDNW $(LINK2 std_getopt.html, std.getopt)) $(TD Parsing of command-line arguments.) ) $(TR $(TDNW $(LINK2 std_compiler.html, std.compiler)) $(TD Host compiler vendor string and language version.) ) $(TR $(TDNW $(LINK2 std_system.html, std.system)) $(TD Runtime environment, such as OS type and endianness.) ) $(TR $(TDNW $(LINK2 core_cpuid.html, core.cpuid)) $(TD Capabilities of the CPU the program is running on.) ) $(TR $(TDNW $(LINK2 core_memory.html, core.memory)) $(TD Control the built-in garbage collector.) ) $(TR $(TDNW $(LINK2 core_runtime.html, core.runtime)) $(TD Control and configure the D runtime.) ) $(LEADINGROW String manipulation) $(TR $(TDNW $(LINK2 std_string.html, std.string)) $(TD Algorithms that work specifically with strings.) ) $(TR $(TDNW $(LINK2 std_array.html, std.array)) $(TD Manipulate builtin arrays.) ) $(TR $(TDNW $(LINK2 std_algorithm.html, std.algorithm)) $(TD Generic algorithms for processing sequences.) ) $(TR $(TDNW $(LINK2 std_uni.html, std.uni)) $(TD Fundamental Unicode algorithms and data structures.) ) $(TR $(TDNW $(LINK2 std_utf.html, std.utf)) $(TD Encode and decode UTF-8, UTF-16 and UTF-32 strings.) ) $(TR $(TDNW $(LINK2 std_format.html, std.format)) $(TD Format data into strings.) ) $(TR $(TDNW $(LINK2 std_path.html, std.path)) $(TD Manipulate strings that represent filesystem paths.) ) $(TR $(TDNW $(LINK2 std_regex.html, std.regex)) $(TD Regular expressions.) ) $(TR $(TDNW $(LINK2 std_ascii.html, std.ascii)) $(TD Routines specific to the ASCII subset of Unicode.) ) $(TR $(TDNW $(LINK2 std_encoding.html, std.encoding)) $(TD Handle and transcode between various text encodings.) ) $(TR $(TDNW $(LINK2 std_windows_charset.html, std.windows.charset)) $(TD Windows specific character set support.) ) $(TR $(TDNW $(LINK2 std_outbuffer.html, std.outbuffer)) $(TD Serialize data to $(CODE ubyte) arrays.) ) $(LEADINGROW Type manipulations) $(TR $(TDNW $(LINK2 std_conv.html, std.conv)) $(TD Convert types from one type to another.) ) $(TR $(TDNW $(LINK2 std_typecons.html, std.typecons)) $(TD Type constructors for scoped variables, ref counted types, etc.) ) $(TR $(TDNW $(LINK2 std_bitmanip.html, std.bitmanip)) $(TD High level bit level manipulation, bit arrays, bit fields.) ) $(TR $(TDNW $(LINK2 std_variant.html, std.variant)) $(TD Discriminated unions and algebraic types.) ) $(TR $(TDNW $(LINK2 core_bitop.html, core.bitop)) $(TD Low level bit manipulation.) ) $(LEADINGROW Vector programming) $(TR $(TDNW $(LINK2 core_simd.html, core.simd)) $(TD SIMD intrinsics) ) $(COMMENT $(LEADINGROW Undocumented modules (intentionally omitted).) $(TR $(TDNW $(LINK2 core_sync_config.html, core.sync.config)$(BR) $(LINK2 std_concurrencybase.html, std.concurrencybase)$(BR) $(LINK2 std_container_util.html, std.container.util)$(BR) $(LINK2 std_regex_internal_backtracking.html, std.regex.internal.backtracking)$(BR) $(LINK2 std_regex_internal_generator.html, std.regex.internal.generator)$(BR) $(LINK2 std_regex_internal_ir.html, std.regex.internal.ir)$(BR) $(LINK2 std_regex_internal_kickstart.html, std.regex.internal.kickstart)$(BR) $(LINK2 std_regex_internal_parser.html, std.regex.internal.parser)$(BR) $(LINK2 std_regex_internal_tests.html, std.regex.internal.tests)$(BR) $(LINK2 std_regex_internal_thompson.html, std.regex.internal.thompson)$(BR) $(LINK2 std_stdiobase.html, std.stdiobase)$(BR) ) $(TD Internal modules. ) ) $(TR $(TDNW $(LINK2 core_vararg.html, core.vararg)$(BR) $(LINK2 std_c_fenv.html, std.c.fenv)$(BR) $(LINK2 std_c_linux_linux.html, std.c.linux_linux)$(BR) $(LINK2 std_c_linux_socket.html, std.c.linux_socket)$(BR) $(LINK2 std_c_locale.html, std.c.locale)$(BR) $(LINK2 std_c_math.html, std.c.math)$(BR) $(LINK2 std_c_process.html, std.c.process)$(BR) $(LINK2 std_c_stdarg.html, std.c.stdarg)$(BR) $(LINK2 std_c_stddef.html, std.c.stddef)$(BR) $(LINK2 std_c_stdio.html, std.c.stdio)$(BR) $(LINK2 std_c_stdlib.html, std.c.stdlib)$(BR) $(LINK2 std_c_string.html, std.c.string)$(BR) $(LINK2 std_c_time.html, std.c.time)$(BR) $(LINK2 std_c_wcharh.html, std.c.wcharh)$(BR) $(LINK2 std_stdint.html, std.stdint)$(BR) ) $(TDN Redirect modules. ) ) $(TR $(TDNW $(LINK2 std_cstream.html, std.cstream)$(BR) $(LINK2 std_mmfile.html, std.mmfile)$(BR) $(LINK2 std_socketstream.html, std.socketstream)$(BR) $(LINK2 std_stream.html, std.stream)$(BR) $(LINK2 std_typetuple.html, std.typetuple)$(BR) ) $(TD Deprecated modules. ) ) $(TR $(TDNW $(LINK2 std_experimental_logger.html, std.experimental.logger)$(BR) $(LINK2 std_experimental_logger_core.html, std.experimental.logger.core)$(BR) $(LINK2 std_experimental_logger_filelogger.html, std.experimental.logger.filelogger)$(BR) $(LINK2 std_experimental_logger_multilogger.html, std.experimental.logger.multilogger)$(BR) $(LINK2 std_experimental_logger_nulllogger.html, std.experimental.logger.nulllogger)$(BR) ) $(TD Experimental modules. ) ) ) ) Macros: TITLE=Phobos Runtime Library WIKI=Phobos ldc-1.1.0-beta3-src/runtime/CMakeLists.txt0000664000175000017500000007732212776214734016403 0ustar kaikaiproject(runtime) cmake_minimum_required(VERSION 2.6) # # Main configuration. # set(DMDFE_VERSION ${D_VERSION}.${DMDFE_MINOR_VERSION}.${DMDFE_PATCH_VERSION}) set(MULTILIB OFF CACHE BOOL "Build both 32/64 bit runtime libraries") set(BUILD_BC_LIBS OFF CACHE BOOL "Build the runtime as LLVM bitcode libraries") set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/d CACHE PATH "Path to install D modules to") set(BUILD_SHARED_LIBS OFF CACHE BOOL "Whether to build the runtime as a shared library") set(D_FLAGS -w CACHE STRING "Runtime build flags, separated by ;") set(D_FLAGS_DEBUG -g;-link-debuglib CACHE STRING "Runtime build flags (debug libraries), separated by ;") set(D_FLAGS_RELEASE -O3;-release CACHE STRING "Runtime build flags (release libraries), separated by ;") if(MSVC) set(LINK_WITH_MSVCRT OFF CACHE BOOL "Link with MSVCRT.lib (DLL) instead of LIBCMT.lib (static)") endif() # Note: In the below building helpers, this is more fittingly called # ${path_suffix}. ${lib_suffix} refers to the library file suffix there # (e.g. -debug). set(LIB_SUFFIX "" CACHE STRING "'64' to install libraries into ${PREFIX}/lib64") set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) include(CheckTypeSize) check_type_size(void* ptr_size) if(${ptr_size} MATCHES "^8$") ## if it's 64-bit OS set(HOST_BITNESS 64) set(MULTILIB_SUFFIX 32) else() set(HOST_BITNESS 32) set(MULTILIB_SUFFIX 64) endif() if(BUILD_SHARED_LIBS) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") message(FATAL_ERROR "Shared libraries (BUILD_SHARED_LIBS) are only supported on Linux and FreeBSD for the time being.") endif() list(APPEND D_FLAGS -relocation-model=pic) set(D_LIBRARY_TYPE SHARED) else() set(D_LIBRARY_TYPE STATIC) endif() get_directory_property(PROJECT_PARENT_DIR DIRECTORY ${PROJECT_SOURCE_DIR} PARENT_DIRECTORY) set(RUNTIME_DIR ${PROJECT_SOURCE_DIR}/druntime CACHE PATH "druntime root directory") set(PHOBOS2_DIR ${PROJECT_SOURCE_DIR}/phobos CACHE PATH "Phobos root directory") set(PROFILERT_DIR ${PROJECT_SOURCE_DIR}/profile-rt CACHE PATH "profile-rt root directory") # # Gather source files. # file(GLOB CORE_D ${RUNTIME_DIR}/src/core/*.d) file(GLOB_RECURSE CORE_D_INTERNAL ${RUNTIME_DIR}/src/core/internal/*.d) file(GLOB CORE_D_SYNC ${RUNTIME_DIR}/src/core/sync/*.d) file(GLOB CORE_D_STDC ${RUNTIME_DIR}/src/core/stdc/*.d) file(GLOB_RECURSE GC_D ${RUNTIME_DIR}/src/gc/*.d) file(GLOB_RECURSE DCRT_D ${RUNTIME_DIR}/src/rt/*.d) file(GLOB_RECURSE LDC_D ${RUNTIME_DIR}/src/ldc/*.d) list(REMOVE_ITEM DCRT_D ${RUNTIME_DIR}/src/rt/alloca.d ${RUNTIME_DIR}/src/rt/deh.d ${RUNTIME_DIR}/src/rt/deh_win32.d ${RUNTIME_DIR}/src/rt/deh_win64_posix.d ${RUNTIME_DIR}/src/rt/dwarfeh.d ${RUNTIME_DIR}/src/rt/llmath.d ${RUNTIME_DIR}/src/rt/trace.d ) file(GLOB DCRT_C ${RUNTIME_DIR}/src/rt/*.c) list(REMOVE_ITEM DCRT_C ${RUNTIME_DIR}/src/rt/deh.c ${RUNTIME_DIR}/src/rt/dylib_fixes.c) if(APPLE) list(APPEND DCRT_C ${RUNTIME_DIR}/src/ldc/osx_tls.c) endif() if(MSVC) list(APPEND DCRT_C ${RUNTIME_DIR}/src/ldc/msvc.c) else() list(REMOVE_ITEM DCRT_C ${RUNTIME_DIR}/src/rt/msvc.c) list(REMOVE_ITEM DCRT_C ${RUNTIME_DIR}/src/rt/msvc_math.c) list(REMOVE_ITEM DCRT_C ${RUNTIME_DIR}/src/rt/stdio_msvc.c) endif() file(GLOB_RECURSE CORE_D_UNIX ${RUNTIME_DIR}/src/core/sys/posix/*.d) file(GLOB_RECURSE CORE_D_FREEBSD ${RUNTIME_DIR}/src/core/sys/freebsd/*.d) file(GLOB_RECURSE CORE_D_NETBSD ${RUNTIME_DIR}/src/core/sys/netbsd/*.d) file(GLOB_RECURSE CORE_D_LINUX ${RUNTIME_DIR}/src/core/sys/linux/*.d) file(GLOB_RECURSE CORE_D_OSX ${RUNTIME_DIR}/src/core/sys/osx/*.d) file(GLOB_RECURSE CORE_D_SOLARIS ${RUNTIME_DIR}/src/core/sys/solaris/*.d) file(GLOB_RECURSE CORE_D_WIN ${RUNTIME_DIR}/src/core/sys/windows/*.d) set(CORE_D_SYS) set(DCRT_ASM) if(UNIX) list(APPEND CORE_D_SYS ${CORE_D_UNIX}) if(${CMAKE_SYSTEM} MATCHES "FreeBSD") list(APPEND CORE_D_SYS ${CORE_D_FREEBSD}) endif() if(${CMAKE_SYSTEM} MATCHES "NetBSD") list(APPEND CORE_D_SYS ${CORE_D_NETBSD}) endif() if(${CMAKE_SYSTEM} MATCHES "Linux") list(APPEND CORE_D_SYS ${CORE_D_LINUX}) endif() if(${CMAKE_SYSTEM} MATCHES "SunOS") list(APPEND CORE_D_SYS ${CORE_D_SOLARIS}) endif() # Assembler support was rewritten in CMake 2.8.5. # The assembler file must be passed to gcc but prior to this # version it is passed to as. This results in a bunch of # error message. This is only critical for non-x86 platforms. # On x86/x86-64 the file can safely be ignored. if("${CMAKE_VERSION}" MATCHES "^2\\.8\\.[01234]($|\\..*)") message(WARNING "Excluding core/threadasm.S from build because of missing CMake support.") message(WARNING "This file is required for certain non-x86 platforms.") message(WARNING "Please consider updating CMake to at least 2.8.5.") else() list(APPEND DCRT_ASM ${RUNTIME_DIR}/src/core/threadasm.S) list(APPEND DCRT_ASM ${RUNTIME_DIR}/src/ldc/eh_asm.S) endif() if(APPLE) list(APPEND CORE_D_SYS ${CORE_D_OSX}) endif() # Using CMAKE_SYSTEM_PROCESSOR might be inacurrate when somebody is # cross-compiling by just setting the tool executbles to a cross toolchain, # so just always include the file. list(APPEND DCRT_C ${RUNTIME_DIR}/src/ldc/arm_unwind.c) elseif(WIN32) list(APPEND CORE_D_SYS ${CORE_D_WIN}) list(REMOVE_ITEM DCRT_C ${RUNTIME_DIR}/src/rt/monitor.c) list(REMOVE_ITEM DCRT_C ${RUNTIME_DIR}/src/rt/bss_section.c) endif() list(APPEND CORE_D ${CORE_D_INTERNAL} ${CORE_D_SYNC} ${CORE_D_SYS} ${CORE_D_STDC}) list(APPEND CORE_D ${LDC_D} ${RUNTIME_DIR}/src/object.d) file(GLOB CORE_C ${RUNTIME_DIR}/src/core/stdc/*.c) if(PHOBOS2_DIR) file(GLOB PHOBOS2_D ${PHOBOS2_DIR}/std/*.d) file(GLOB PHOBOS2_D_ALGORITHM ${PHOBOS2_DIR}/std/algorithm/*.d) file(GLOB PHOBOS2_D_CONTAINER ${PHOBOS2_DIR}/std/container/*.d) file(GLOB PHOBOS2_D_DIGEST ${PHOBOS2_DIR}/std/digest/*.d) file(GLOB_RECURSE PHOBOS2_D_EXPERIMENTAL ${PHOBOS2_DIR}/std/experimental/*.d) file(GLOB PHOBOS2_D_NET ${PHOBOS2_DIR}/std/net/*.d) file(GLOB PHOBOS2_D_RANGE ${PHOBOS2_DIR}/std/range/*.d) file(GLOB_RECURSE PHOBOS2_D_REGEX ${PHOBOS2_DIR}/std/regex/*.d) file(GLOB_RECURSE PHOBOS2_D_INTERNAL ${PHOBOS2_DIR}/std/internal/*.d) file(GLOB PHOBOS2_D_C ${PHOBOS2_DIR}/std/c/*.d) file(GLOB PHOBOS2_ETC ${PHOBOS2_DIR}/etc/c/*.d) if(APPLE) file(GLOB PHOBOS2_D_C_SYS ${PHOBOS2_DIR}/std/c/osx/*.d) elseif(FreeBSD) file(GLOB PHOBOS2_D_C_SYS ${PHOBOS2_DIR}/std/c/freebsd/*.d) elseif(UNIX) # Install Linux headers on all non-Apple *nixes - not correct, but # shouldn't cause any harm either. file(GLOB PHOBOS2_D_C_SYS ${PHOBOS2_DIR}/std/c/linux/*.d) elseif(WIN32) file(GLOB PHOBOS2_D_C_SYS ${PHOBOS2_DIR}/std/c/windows/*.d) endif() file(GLOB ZLIB_C ${PHOBOS2_DIR}/etc/c/zlib/*.c) list(REMOVE_ITEM ZLIB_C ${PHOBOS2_DIR}/etc/c/zlib/minigzip.c ${PHOBOS2_DIR}/etc/c/zlib/example.c ${PHOBOS2_DIR}/etc/c/zlib/gzio.c ) if(WIN32) file(GLOB PHOBOS2_D_WIN ${PHOBOS2_DIR}/std/windows/*.d) endif() list(APPEND PHOBOS2_D ${PHOBOS2_D_ALGORITHM} ${PHOBOS2_D_CONTAINER} ${PHOBOS2_D_DIGEST} ${PHOBOS2_D_EXPERIMENTAL} ${PHOBOS2_D_NET} ${PHOBOS2_D_RANGE} ${PHOBOS2_D_REGEX} ${PHOBOS2_D_INTERNAL} ${PHOBOS2_D_WIN} ${PHOBOS2_D_C} ${PHOBOS2_D_C_SYS} ${PHOBOS2_ETC} ) list(REMOVE_ITEM PHOBOS2_D ${PHOBOS2_DIR}/std/intrinsic.d ) set(CONFIG_NAME ${LDC_EXE}_phobos) else() set(CONFIG_NAME ${LDC_EXE}) endif() # should only be necessary if run independently from ldc cmake project if(NOT LDC_EXE) find_program(LDC_EXE ldc2 ${PROJECT_BINARY_DIR}/../bin DOC "path to ldc binary") if(NOT LDC_EXE) message(SEND_ERROR "ldc not found") endif() endif() # # Create configuration files. # # Add extra paths on Linux and disable linker arch mismatch warnings (like # DMD and GDC do). OS X doesn't need extra configuration due to the use of # fat binaries. Other Posixen might need to be added here. if((${CMAKE_SYSTEM_NAME} MATCHES "Linux") OR (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")) if(MULTILIB) set(MULTILIB_ADDITIONAL_PATH "\n \"-L-L${CMAKE_BINARY_DIR}/lib${MULTILIB_SUFFIX}\",\n \"-L--no-warn-search-mismatch\",") set(MULTILIB_ADDITIONAL_INSTALL_PATH "\n \"-L-L${CMAKE_INSTALL_PREFIX}/lib${MULTILIB_SUFFIX}\",\n \"-L--no-warn-search-mismatch\",") endif() if(BUILD_SHARED_LIBS) set(SHARED_LIBS_RPATH "\n \"-L-rpath=${CMAKE_BINARY_DIR}/lib\",") endif() endif() configure_file(${PROJECT_PARENT_DIR}/${CONFIG_NAME}.conf.in ${PROJECT_BINARY_DIR}/../bin/${LDC_EXE}.conf) # Prepare the config files we are going to install later in bin. configure_file(${PROJECT_PARENT_DIR}/${LDC_EXE}_install.conf.in ${PROJECT_BINARY_DIR}/../bin/${LDC_EXE}_install.conf) # # druntime/Phobos compilation helpers. # set(GCCBUILTINS "") function(gen_gccbuiltins name) set(module "${PROJECT_BINARY_DIR}/gccbuiltins_${name}.di") if (GCCBUILTINS STREQUAL "") set(GCCBUILTINS "${module}" PARENT_SCOPE) else() set(GCCBUILTINS "${GCCBUILTINS};${module}" PARENT_SCOPE) endif() add_custom_command( OUTPUT ${module} COMMAND gen_gccbuiltins ${module} "${name}" ) endfunction() set(target_arch "AArch64;ARM;Mips;PowerPC;SystemZ;X86") set(target_name "aarch64;arm;mips;ppc;s390;x86") foreach(target ${LLVM_TARGETS_TO_BUILD}) list(FIND target_arch ${target} idx) if(idx GREATER -1) list(GET target_name ${idx} name) gen_gccbuiltins(${name}) endif() endforeach() # Always build zlib and other C parts of the runtime in release mode, regardless # of what the user chose for LDC itself. # 1) Set up CMAKE_C_FLAGS_RELEASE if(MSVC) if(NOT LINK_WITH_MSVCRT) string(REGEX REPLACE "(^| )[/-]MD( |$)" "\\2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") if(NOT CMAKE_C_FLAGS_RELEASE MATCHES "(^| )[/-]MT( |$)") append("/MT" CMAKE_C_FLAGS_RELEASE) endif() else() string(REGEX REPLACE "(^| )[/-]MT( |$)" "\\2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") if(NOT CMAKE_C_FLAGS_RELEASE MATCHES "(^| )[/-]MD( |$)") append("/MD" CMAKE_C_FLAGS_RELEASE) endif() endif() # warning C4996: zlib uses 'deprecated' POSIX names append("/wd4996" CMAKE_C_FLAGS_RELEASE) endif() # 2) Set all other CMAKE_C_FLAGS variants to CMAKE_C_FLAGS_RELEASE set(variables CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO ) foreach(variable ${variables}) set(${variable} "${CMAKE_C_FLAGS_RELEASE}") endforeach() # Compiles the given D module into an object file, and if enabled, a bitcode # file. The output is written to a path based on output_dir. The paths of the # output files are appended to outlist_o and outlist_bc, respectively. macro(dc input_d d_flags output_dir output_suffix outlist_o outlist_bc) file(RELATIVE_PATH output ${output_dir} ${input_d}) get_filename_component(name ${output} NAME_WE) get_filename_component(path ${output} PATH) if("${path}" STREQUAL "") set(output_root ${name}) else() set(output_root ${path}/${name}) endif() set(output_o ${PROJECT_BINARY_DIR}/${output_root}${output_suffix}${CMAKE_C_OUTPUT_EXTENSION}) set(output_bc ${PROJECT_BINARY_DIR}/${output_root}${output_suffix}.bc) list(APPEND ${outlist_o} ${output_o}) if(BUILD_BC_LIBS) list(APPEND ${outlist_bc} ${output_bc}) endif() # Compile if(BUILD_BC_LIBS) set(outfiles ${output_o} ${output_bc}) set(dc_flags --output-o --output-bc) else() set(outfiles ${output_o}) set(dc_flags --output-o) endif() add_custom_command( OUTPUT ${outfiles} COMMAND ${LDC_EXE_FULL} ${dc_flags} -c -I${RUNTIME_DIR}/src -I${RUNTIME_DIR}/src/gc ${input_d} -of${output_o} ${d_flags} WORKING_DIRECTORY ${PROJECT_PARENT_DIR} DEPENDS ${input_d} ${LDC_EXE} ${LDC_EXE_FULL} ${GCCBUILTINS} ${PROJECT_BINARY_DIR}/../bin/${LDC_EXE}.conf ) endmacro() # Sets target_suffix to a purely cosmetical suffix for the CMake target names # from the given suffixes on the library name and the target path. We could use # any string that resolves the ambiguities between the different variants. macro(get_target_suffix lib_suffix path_suffix target_suffix) set(${target_suffix} "") if(NOT "${lib_suffix}" STREQUAL "") set(${target_suffix} "${lib_suffix}") endif() # If LIB_SUFFIX is set there is always a suffix; leave it off for simplicity. if(NOT "${path_suffix}" STREQUAL "" AND NOT "${path_suffix}" STREQUAL "${LIB_SUFFIX}") set(${target_suffix} "${${target_suffix}}_${path_suffix}") endif() endmacro() # Sets up the targets for building the individual druntime object files, # appending the names of the (bitcode) files to link into the library to # outlist_o (outlist_bc). macro(compile_druntime d_flags lib_suffix path_suffix outlist_o outlist_bc) get_target_suffix("${lib_suffix}" "${path_suffix}" target_suffix) # Always disable invariants for debug builds of core.* and gc.* (there # are/were some broken invariants around; druntime is always built in # release mode in upstream builds). set(rt_flags "${d_flags};-disable-invariants") if(BUILD_SHARED_LIBS) set(shared ";-d-version=Shared") else() set(shared) endif() foreach(f ${CORE_D} ${GC_D}) dc( ${f} "${rt_flags}${shared}" "${RUNTIME_DIR}" "${target_suffix}" ${outlist_o} ${outlist_bc} ) endforeach() foreach(f ${DCRT_D}) dc( ${f} "${d_flags}${shared}" "${RUNTIME_DIR}" "${target_suffix}" ${outlist_o} ${outlist_bc} ) endforeach() endmacro() # Sets up the targets for building the individual Phobos object files, # appending the names of the (bitcode) files to link into the library to # outlist_o (outlist_bc). macro(compile_phobos2 d_flags lib_suffix path_suffix outlist_o outlist_bc) get_target_suffix("${lib_suffix}" "${path_suffix}" target_suffix) foreach(f ${PHOBOS2_D}) dc( ${f} "${d_flags};-I${PHOBOS2_DIR}" ${PHOBOS2_DIR} "${target_suffix}" ${outlist_o} ${outlist_bc} ) endforeach() endmacro() # Builds a copy of druntime/Phobos from the source files gathered above. The # names of the added library targets are appended to outlist_targets. macro(build_runtime d_flags c_flags ld_flags lib_suffix path_suffix outlist_targets) set(output_path ${CMAKE_BINARY_DIR}/lib${path_suffix}) set(druntime_o "") set(druntime_bc "") compile_druntime("${d_flags}" "${lib_suffix}" "${path_suffix}" druntime_o druntime_bc) add_library(druntime-ldc${target_suffix} ${D_LIBRARY_TYPE} ${druntime_o} ${CORE_C} ${DCRT_C} ${DCRT_ASM}) set_target_properties( druntime-ldc${target_suffix} PROPERTIES OUTPUT_NAME druntime-ldc${lib_suffix} VERSION ${DMDFE_VERSION} SOVERSION ${DMDFE_PATCH_VERSION} LINKER_LANGUAGE C ARCHIVE_OUTPUT_DIRECTORY ${output_path} LIBRARY_OUTPUT_DIRECTORY ${output_path} RUNTIME_OUTPUT_DIRECTORY ${output_path} COMPILE_FLAGS "${c_flags}" LINK_FLAGS "${ld_flags}" ) # When building a shared library, we need to link in all the default # libraries otherwise implicitly added by LDC to make it loadable from # C executables. if(BUILD_SHARED_LIBS) if(${CMAKE_SYSTEM} MATCHES "FreeBSD") set(dso_system_libs "m" "pthread") else() set(dso_system_libs "m" "pthread" "rt" "dl") endif() target_link_libraries(druntime-ldc${target_suffix} ${dso_system_libs}) endif() list(APPEND ${outlist_targets} druntime-ldc${target_suffix}) if(PHOBOS2_DIR) set(phobos2_o "") set(phobos2_bc "") compile_phobos2("${d_flags}" "${lib_suffix}" "${path_suffix}" phobos2_o phobos2_bc) add_library(phobos2-ldc${target_suffix} ${D_LIBRARY_TYPE} ${ZLIB_C} ${phobos2_o}) set_target_properties( phobos2-ldc${target_suffix} PROPERTIES OUTPUT_NAME phobos2-ldc${lib_suffix} VERSION ${DMDFE_VERSION} SOVERSION ${DMDFE_PATCH_VERSION} LINKER_LANGUAGE C ARCHIVE_OUTPUT_DIRECTORY ${output_path} LIBRARY_OUTPUT_DIRECTORY ${output_path} RUNTIME_OUTPUT_DIRECTORY ${output_path} COMPILE_FLAGS "${c_flags}" LINK_FLAGS "${ld_flags}" ) if(BUILD_SHARED_LIBS) # TODO: As for druntime, adapt once shared libraries are supported # on more operating systems. target_link_libraries(phobos2-ldc${target_suffix} druntime-ldc${target_suffix} ${dso_system_libs}) endif() list(APPEND ${outlist_targets} "phobos2-ldc${target_suffix}") endif() if(BUILD_BC_LIBS) find_program(LLVM_AR_EXE llvm-ar HINTS ${LLVM_ROOT_DIR}/bin DOC "path to llvm-ar tool" ) if(NOT LLVM_AR_EXE) message(SEND_ERROR "llvm-ar not found") endif() set(bclibs ${output_path}/libdruntime-ldc${lib_suffix}-bc.a ${output_path}/libphobos2-ldc${lib_suffix}-bc.a ) add_custom_command( OUTPUT ${bclibs} COMMAND ${LLVM_AR_EXE} rs libdruntime-ldc${lib_suffix}-bc.a ${druntime_bc} COMMAND ${LLVM_AR_EXE} rs libphobos2-ldc${lib_suffix}-bc.a ${phobos2_bc} WORKING_DIRECTORY ${output_path} DEPENDS ${druntime_bc} ${phobos2_bc} VERBATIM ) add_custom_target(bitcode-libraries${target_suffix} ALL DEPENDS ${bclibs}) endif() endmacro() # Builds both a debug and a release copy of druntime/Phobos. macro(build_runtime_variants d_flags c_flags ld_flags path_suffix outlist_targets) build_runtime( "${d_flags};${D_FLAGS};${D_FLAGS_RELEASE}" "${c_flags}" "${ld_flags}" "" "${path_suffix}" ${outlist_targets} ) build_runtime( "${d_flags};${D_FLAGS};${D_FLAGS_DEBUG}" "${c_flags}" "${ld_flags}" "-debug" "${path_suffix}" ${outlist_targets} ) build_profile_runtime ("${d_flags}" "${c_flags}" "${ld_flags}" "${path_suffix}" ${outlist_targets}) endmacro() # Setup the build of profile-rt include(profile-rt/DefineBuildProfileRT.cmake) # # Set up build targets. # set(RT_CFLAGS "") # This is a bit of a mess as we need to join the two libraries together on # OS X before installing them. After this has run, LIBS_TO_INSTALL contains # a list of library "base names" to install (i.e. without the multilib suffix, # if any). set(LIBS_TO_INSTALL) if(BUILD_SHARED_LIBS) set(OSX_LIBEXT "dylib") else() set(OSX_LIBEXT "a") endif() if(MULTILIB) if(APPLE) # On OS X, build a "fat" library. # Some suffix for the target/file names of the host-native arch so # that they don't collide with the final combined ones. set(hostsuffix "${LIB_SUFFIX}${HOST_BITNESS}") set(hosttargets) build_runtime_variants("" "${RT_CFLAGS}" "${LD_FLAGS}" "${hostsuffix}" hosttargets) #build_profile_runtime ("" "${RT_CFLAGS}" "${LD_FLAGS}" "${hostsuffix}" hosttargets) set(multitargets) build_runtime_variants("-m${MULTILIB_SUFFIX}" "-m${MULTILIB_SUFFIX} ${RT_CFLAGS}" "-m${MULTILIB_SUFFIX} ${LD_FLAGS}" "${MULTILIB_SUFFIX}" multitargets) #build_profile_runtime ("-m${MULTILIB_SUFFIX}" "-m${MULTILIB_SUFFIX} ${RT_CFLAGS}" "-m${MULTILIB_SUFFIX} ${LD_FLAGS}" "${MULTILIB_SUFFIX}" multitargets) foreach(targetname ${hosttargets}) string(REPLACE "_${hostsuffix}" "" t ${targetname}) add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/lib${LIB_SUFFIX}/lib${t}.${OSX_LIBEXT} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/lib${LIB_SUFFIX} COMMAND "lipo" ARGS ${CMAKE_BINARY_DIR}/lib${MULTILIB_SUFFIX}/lib${t}.${OSX_LIBEXT} ${CMAKE_BINARY_DIR}/lib${hostsuffix}/lib${t}.${OSX_LIBEXT} -create -output ${CMAKE_BINARY_DIR}/lib${LIB_SUFFIX}/lib${t}.${OSX_LIBEXT} DEPENDS ${hosttargets} ${multitargets} ) add_custom_target(${t} ALL DEPENDS ${CMAKE_BINARY_DIR}/lib${LIB_SUFFIX}/lib${t}.${OSX_LIBEXT}) list(APPEND LIBS_TO_INSTALL ${t}) endforeach() else() build_runtime_variants("" "${RT_CFLAGS}" "${LD_FLAGS}" "${LIB_SUFFIX}" LIBS_TO_INSTALL) #build_profile_runtime ("" "${RT_CFLAGS}" "${LD_FLAGS}" "${LIB_SUFFIX}" LIBS_TO_INSTALL) build_runtime_variants("-m${MULTILIB_SUFFIX}" "-m${MULTILIB_SUFFIX} ${RT_CFLAGS}" "-m${MULTILIB_SUFFIX} ${LD_FLAGS}" "${MULTILIB_SUFFIX}" dummy) #build_profile_runtime ("-m${MULTILIB_SUFFIX}" "-m${MULTILIB_SUFFIX} ${RT_CFLAGS}" "-m${MULTILIB_SUFFIX} ${LD_FLAGS}" "${MULTILIB_SUFFIX}" dummy) endif() else() build_runtime_variants("" "${RT_CFLAGS}" "${LD_FLAGS}" "${LIB_SUFFIX}" LIBS_TO_INSTALL) #build_profile_runtime ("" "${RT_CFLAGS}" "${LD_FLAGS}" "${LIB_SUFFIX}" LIBS_TO_INSTALL) endif() # # Install target. # set(DRUNTIME_PACKAGES core etc ldc) install(FILES ${RUNTIME_DIR}/src/object.d DESTINATION ${INCLUDE_INSTALL_DIR}/ldc) foreach(p ${DRUNTIME_PACKAGES}) install(DIRECTORY ${RUNTIME_DIR}/src/${p} DESTINATION ${INCLUDE_INSTALL_DIR}) endforeach() if(PHOBOS2_DIR) install(DIRECTORY ${PHOBOS2_DIR}/std DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.d") install(DIRECTORY ${PHOBOS2_DIR}/etc DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.d") endif() install(FILES ${GCCBUILTINS} DESTINATION ${INCLUDE_INSTALL_DIR}/ldc) foreach(libname ${LIBS_TO_INSTALL}) if(APPLE) install( FILES ${CMAKE_BINARY_DIR}/lib${LIB_SUFFIX}/lib${libname}.${OSX_LIBEXT} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} ) else() install( TARGETS ${libname} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} ) if(MULTILIB) install( TARGETS ${libname}_${MULTILIB_SUFFIX} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${MULTILIB_SUFFIX} ) endif() endif() endforeach() # # Test targets. # # Build the "test runner" executables containing the druntime and Phobos unit # tests. They are invoked with the modules to test later. When using a shared # runtime, we just build another copy of the two libraries with -unittest # enabled. When linking statically, we have to directly pass the object files # to the linking command instead so that all tests are pulled in. macro(build_test_runner name_suffix d_flags c_flags) set(flags "${D_FLAGS};${d_flags};-unittest") if(BUILD_SHARED_LIBS) set(unittest_libs "") build_runtime( "${flags}" "${RT_CFLAGS} ${c_flags}" "${LD_FLAGS} ${c_flags}" "-unittest${name_suffix}" "" unittest_libs ) # Only build the unittest libraries when running the tests. Unfortunately, # I couldn't find an easier way to make a test depend on a CMake target than # just invoking the build command through the CMake executable. set_target_properties(${unittest_libs} PROPERTIES EXCLUDE_FROM_ALL ON EXCLUDE_FROM_DEFAULT_BUILD ON) foreach(l ${unittest_libs}) add_test(build-${l} "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target ${l}) endforeach() set(libarg "druntime-ldc-unittest${name_suffix}") add_test(NAME build-druntime-test-runner${name_suffix} COMMAND ${LDC_EXE_FULL} -of${PROJECT_BINARY_DIR}/druntime-test-runner${name_suffix}${CMAKE_EXECUTABLE_SUFFIX} -defaultlib=${libarg} -debuglib=${libarg} -singleobj ${flags} ${RUNTIME_DIR}/src/test_runner.d ) set_tests_properties(build-druntime-test-runner${name_suffix} PROPERTIES DEPENDS build-druntime-ldc-unittest${name_suffix}) if(PHOBOS2_DIR) set(libarg "phobos2-ldc-unittest${name_suffix},druntime-ldc-unittest${name_suffix}") add_test(NAME build-phobos2-test-runner${name_suffix} COMMAND ${LDC_EXE_FULL} -of${PROJECT_BINARY_DIR}/phobos2-test-runner${name_suffix}${CMAKE_EXECUTABLE_SUFFIX} -L--no-as-needed -defaultlib=${libarg} -debuglib=${libarg} -singleobj ${flags} ${RUNTIME_DIR}/src/test_runner.d ) set_tests_properties(build-phobos2-test-runner${name_suffix} PROPERTIES DEPENDS build-phobos2-ldc-unittest${name_suffix}) endif() else() set(druntime_o "") set(druntime_bc "") set(casm_lib_path "${CMAKE_BINARY_DIR}/lib") compile_druntime("${flags}" "-unittest${name_suffix}" "" druntime_o druntime_bc) # We need to compile a small static library with the C/ASM files, as # there is no easy way of getting the object file names used when # compiling the main libraries. If we could require CMake 2.8.8, we # would be able to just build the files once (resp. twice for multilib) # for both the runtime debug/release builds and the tests. Oh well. set(druntime-casm druntime-ldc-casm${name_suffix}) add_library(${druntime-casm} STATIC ${CORE_C} ${DCRT_C} ${DCRT_ASM}) set_target_properties( ${druntime-casm} PROPERTIES LINKER_LANGUAGE C COMPILE_FLAGS "${RT_CFLAGS} ${c_flags}" LINK_FLAGS "${LD_FLAGS} ${ld_flags}" ARCHIVE_OUTPUT_DIRECTORY ${casm_lib_path} ) # See shared library case for explanation. set_target_properties(${druntime-casm} PROPERTIES EXCLUDE_FROM_ALL ON EXCLUDE_FROM_DEFAULT_BUILD ON) add_custom_target(druntime-ldc-unittest${name_suffix} DEPENDS ${druntime_o} ${druntime-casm}) add_test(build-druntime-ldc-unittest${name_suffix} "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target druntime-ldc-unittest${name_suffix}) add_test(NAME build-druntime-test-runner${name_suffix} COMMAND ${LDC_EXE_FULL} -of${PROJECT_BINARY_DIR}/druntime-test-runner${name_suffix}${CMAKE_EXECUTABLE_SUFFIX} -defaultlib=${druntime-casm} -debuglib=${druntime-casm} -singleobj ${flags} ${druntime_o} ${RUNTIME_DIR}/src/test_runner.d ) set_tests_properties(build-druntime-test-runner${name_suffix} PROPERTIES DEPENDS build-druntime-ldc-unittest${name_suffix} ) # And the same for Phobos. if(PHOBOS2_DIR) set(phobos2_o "") set(phobos2_bc "") compile_phobos2("${flags}" "-unittest${name_suffix}" "" phobos2_o phobos2_bc) set(phobos2-casm phobos2-ldc-casm${name_suffix}) add_library(${phobos2-casm} STATIC ${ZLIB_C}) set_target_properties( ${phobos2-casm} PROPERTIES LINKER_LANGUAGE C COMPILE_FLAGS "${RT_CFLAGS} ${c_flags}" LINK_FLAGS "${LD_FLAGS} ${ld_flags}" ARCHIVE_OUTPUT_DIRECTORY ${casm_lib_path} ) set_target_properties(${phobos2-casm} PROPERTIES EXCLUDE_FROM_ALL ON EXCLUDE_FROM_DEFAULT_BUILD ON) add_custom_target(phobos2-ldc-unittest${name_suffix} DEPENDS ${phobos2_o} ${phobos2-casm}) add_test(build-phobos2-ldc-unittest${name_suffix} "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target phobos2-ldc-unittest${name_suffix}) add_test(NAME build-phobos2-test-runner${name_suffix} COMMAND ${LDC_EXE_FULL} -of${PROJECT_BINARY_DIR}/phobos2-test-runner${name_suffix}${CMAKE_EXECUTABLE_SUFFIX} -defaultlib=druntime-ldc,${phobos2-casm} -debuglib=druntime-ldc,${phobos2-casm} -singleobj ${flags} ${phobos2_o} ${RUNTIME_DIR}/src/test_runner.d ) set_tests_properties(build-phobos2-test-runner${name_suffix} PROPERTIES DEPENDS build-phobos2-ldc-unittest${name_suffix} ) endif() endif() endmacro() build_test_runner("" "${D_FLAGS_RELEASE}" "") build_test_runner("-debug" "${D_FLAGS_DEBUG}" "") if(MULTILIB AND ${HOST_BITNESS} EQUAL 64) build_test_runner("-32" "${D_FLAGS_RELEASE};-m32" "-m32") build_test_runner("-debug-32" "${D_FLAGS_DEBUG};-m32" "-m32") endif() # Add the druntime/Phobos test runner invocations for all the different modules. macro(file_to_module_name file_name out_module_name) string(REPLACE ${PROJECT_SOURCE_DIR}/ "" stripped ${file_name}) string(REPLACE "druntime/src/" "" stripped ${stripped}) string(REPLACE "phobos/" "" stripped ${stripped}) string(REPLACE ".d" "" stripped ${stripped}) string(REPLACE "/" "." module ${stripped}) # The logical module name for package.d files doesn't include the # trailing .package part. string(REPLACE ".package" "" module ${module}) # rt.invariant doesn't have a module declaration, presumably because # invariant is a keyword. string(REPLACE "rt.invariant" "invariant" ${out_module_name} ${module}) endmacro() function(add_tests d_files runner name_suffix) foreach(file ${d_files}) file_to_module_name(${file} module) add_test(NAME "${module}${name_suffix}" WORKING_DIRECTORY "${PROJECT_BINARY_DIR}" COMMAND ${runner}-test-runner${name_suffix} ${module} ) set_tests_properties("${module}${name_suffix}" PROPERTIES DEPENDS build-${runner}-test-runner${name_suffix} ) endforeach() endfunction() function(add_runtime_tests name_suffix) add_tests("${CORE_D};${DCRT_D};${GC_D}" "druntime" "${name_suffix}") if(PHOBOS2_DIR) add_tests("${PHOBOS2_D}" "phobos2" "${name_suffix}") endif() endfunction() add_runtime_tests("") add_runtime_tests("-debug") if(MULTILIB AND ${HOST_BITNESS} EQUAL 64) add_runtime_tests("-32") add_runtime_tests("-debug-32") endif() # Add the standalone druntime tests. # TODO: Add test/excetions and test/init_fini. if(BUILD_SHARED_LIBS) set(druntime_path "$") set(outdir ${PROJECT_BINARY_DIR}/druntime-test-shared) add_test(NAME clean-druntime-test-shared COMMAND ${CMAKE_COMMAND} -E remove_directory ${outdir}) if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") set(linkflags "") else() set(linkflags "LINKDL=-L-ldl") endif() add_test(NAME druntime-test-shared COMMAND make -C ${PROJECT_SOURCE_DIR}/druntime/test/shared ROOT=${outdir} DMD=${LDMD_EXE_FULL} MODEL=default DRUNTIMESO=${druntime_path} CFLAGS=-Wall\ -Wl,-rpath,${CMAKE_BINARY_DIR}/lib ${linkflags} ) set_tests_properties(druntime-test-shared PROPERTIES DEPENDS clean-druntime-test-shared) endif() ldc-1.1.0-beta3-src/runtime/README0000664000175000017500000000135312776214734014512 0ustar kaikaiBuilding druntime/Phobos for D2 --- LDC currently needs custom forks of druntime and Phobos. They are integrated with the main repository using Git submodules. To build them, make sure you have up-to-date copies of the submodules in your local repository: $ git submodule update -i The libraries should then be built and installed automatically along with the compiler itself. If, for some reason, you want to build them separately, the targets are: $ make runtime $ make phobos2 Building Tango for D1 --- This directory used to contain scripts for building Tango for LDC/D1, which became obsolete after LDC support was added to its build system, and were consequently removed. Please use the official Tango build system (bob) from now on. ldc-1.1.0-beta3-src/runtime/druntime/0000775000175000017500000000000012776214756015463 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/win32.mak0000664000175000017500000010070512776214756017122 0ustar kaikai# Makefile to build D runtime library druntime.lib for Win32 MODEL=32 DMD=dmd CC=dmc DOCDIR=doc IMPDIR=import DFLAGS=-m$(MODEL) -conf= -O -release -dip25 -inline -w -Isrc -Iimport UDFLAGS=-m$(MODEL) -conf= -O -release -dip25 -w -Isrc -Iimport DDOCFLAGS=-conf= -c -w -o- -Isrc -Iimport -version=CoreDdoc CFLAGS= DRUNTIME_BASE=druntime DRUNTIME=lib\$(DRUNTIME_BASE).lib GCSTUB=lib\gcstub.obj DOCFMT= target : import copydir copy $(DRUNTIME) $(GCSTUB) $(mak\COPY) $(mak\DOCS) $(mak\IMPORTS) $(mak\SRCS) # NOTE: trace.d and cover.d are not necessary for a successful build # as both are used for debugging features (profiling and coverage) # NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and # minit.asm is not used by dmd for Linux OBJS= errno_c_$(MODEL).obj src\rt\minit.obj OBJS_TO_DELETE= errno_c_$(MODEL).obj ######################## Doc .html file generation ############################## doc: $(DOCS) $(DOCDIR)\object.html : src\object.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_atomic.html : src\core\atomic.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_attribute.html : src\core\attribute.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_bitop.html : src\core\bitop.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_checkedint.html : src\core\checkedint.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_cpuid.html : src\core\cpuid.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_demangle.html : src\core\demangle.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_exception.html : src\core\exception.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_math.html : src\core\math.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_memory.html : src\core\memory.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_runtime.html : src\core\runtime.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_simd.html : src\core\simd.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_thread.html : src\core\thread.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_time.html : src\core\time.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_vararg.html : src\core\vararg.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_complex.html : src\core\stdc\complex.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_ctype.html : src\core\stdc\ctype.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_errno.html : src\core\stdc\errno.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_fenv.html : src\core\stdc\fenv.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_float_.html : src\core\stdc\float_.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_inttypes.html : src\core\stdc\inttypes.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_limits.html : src\core\stdc\limits.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_locale.html : src\core\stdc\locale.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_math.html : src\core\stdc\math.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_signal.html : src\core\stdc\signal.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stdarg.html : src\core\stdc\stdarg.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stddef.html : src\core\stdc\stddef.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stdint.html : src\core\stdc\stdint.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stdio.html : src\core\stdc\stdio.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stdlib.html : src\core\stdc\stdlib.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_string.html : src\core\stdc\string.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_tgmath.html : src\core\stdc\tgmath.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_time.html : src\core\stdc\time.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_wchar_.html : src\core\stdc\wchar_.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_wctype.html : src\core\stdc\wctype.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_barrier.html : src\core\sync\barrier.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_condition.html : src\core\sync\condition.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_config.html : src\core\sync\config.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_exception.html : src\core\sync\exception.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_mutex.html : src\core\sync\mutex.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_rwmutex.html : src\core\sync\rwmutex.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_semaphore.html : src\core\sync\semaphore.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** changelog.html: changelog.dd $(DMD) -Dfchangelog.html changelog.dd ######################## Header .di file generation ############################## import: $(IMPORTS) $(IMPDIR)\core\sync\barrier.di : src\core\sync\barrier.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\condition.di : src\core\sync\condition.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\config.di : src\core\sync\config.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\exception.di : src\core\sync\exception.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\mutex.di : src\core\sync\mutex.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\rwmutex.di : src\core\sync\rwmutex.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\semaphore.di : src\core\sync\semaphore.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** ######################## Header .di file copy ############################## copydir: $(IMPDIR) mkdir $(IMPDIR)\core\stdc mkdir $(IMPDIR)\core\stdcpp mkdir $(IMPDIR)\core\internal mkdir $(IMPDIR)\core\sys\freebsd\sys mkdir $(IMPDIR)\core\sys\linux\sys mkdir $(IMPDIR)\core\sys\osx\mach mkdir $(IMPDIR)\core\sys\posix\arpa mkdir $(IMPDIR)\core\sys\posix\net mkdir $(IMPDIR)\core\sys\posix\netinet mkdir $(IMPDIR)\core\sys\posix\sys mkdir $(IMPDIR)\core\sys\solaris\sys mkdir $(IMPDIR)\core\sys\windows mkdir $(IMPDIR)\etc\linux copy: $(COPY) $(IMPDIR)\object.d : src\object.d copy $** $@ if exist $(IMPDIR)\object.di del $(IMPDIR)\object.di $(IMPDIR)\core\atomic.d : src\core\atomic.d copy $** $@ $(IMPDIR)\core\attribute.d : src\core\attribute.d copy $** $@ $(IMPDIR)\core\bitop.d : src\core\bitop.d copy $** $@ $(IMPDIR)\core\checkedint.d : src\core\checkedint.d copy $** $@ $(IMPDIR)\core\cpuid.d : src\core\cpuid.d copy $** $@ $(IMPDIR)\core\demangle.d : src\core\demangle.d copy $** $@ $(IMPDIR)\core\exception.d : src\core\exception.d copy $** $@ $(IMPDIR)\core\math.d : src\core\math.d copy $** $@ $(IMPDIR)\core\memory.d : src\core\memory.d copy $** $@ $(IMPDIR)\core\runtime.d : src\core\runtime.d copy $** $@ $(IMPDIR)\core\simd.d : src\core\simd.d copy $** $@ $(IMPDIR)\core\thread.d : src\core\thread.d copy $** $@ $(IMPDIR)\core\time.d : src\core\time.d copy $** $@ $(IMPDIR)\core\vararg.d : src\core\vararg.d copy $** $@ $(IMPDIR)\core\internal\abort.d : src\core\internal\abort.d copy $** $@ $(IMPDIR)\core\internal\convert.d : src\core\internal\convert.d copy $** $@ $(IMPDIR)\core\internal\hash.d : src\core\internal\hash.d copy $** $@ $(IMPDIR)\core\internal\spinlock.d : src\core\internal\spinlock.d copy $** $@ $(IMPDIR)\core\internal\string.d : src\core\internal\string.d copy $** $@ $(IMPDIR)\core\internal\traits.d : src\core\internal\traits.d copy $** $@ $(IMPDIR)\core\stdc\complex.d : src\core\stdc\complex.d copy $** $@ $(IMPDIR)\core\stdc\config.d : src\core\stdc\config.d copy $** $@ $(IMPDIR)\core\stdc\ctype.d : src\core\stdc\ctype.d copy $** $@ $(IMPDIR)\core\stdc\errno.d : src\core\stdc\errno.d copy $** $@ $(IMPDIR)\core\stdc\fenv.d : src\core\stdc\fenv.d copy $** $@ $(IMPDIR)\core\stdc\float_.d : src\core\stdc\float_.d copy $** $@ $(IMPDIR)\core\stdc\inttypes.d : src\core\stdc\inttypes.d copy $** $@ $(IMPDIR)\core\stdc\limits.d : src\core\stdc\limits.d copy $** $@ $(IMPDIR)\core\stdc\locale.d : src\core\stdc\locale.d copy $** $@ $(IMPDIR)\core\stdc\math.d : src\core\stdc\math.d copy $** $@ $(IMPDIR)\core\stdc\signal.d : src\core\stdc\signal.d copy $** $@ $(IMPDIR)\core\stdc\stdarg.d : src\core\stdc\stdarg.d copy $** $@ $(IMPDIR)\core\stdc\stddef.d : src\core\stdc\stddef.d copy $** $@ $(IMPDIR)\core\stdc\stdint.d : src\core\stdc\stdint.d copy $** $@ $(IMPDIR)\core\stdc\stdio.d : src\core\stdc\stdio.d copy $** $@ $(IMPDIR)\core\stdc\stdlib.d : src\core\stdc\stdlib.d copy $** $@ $(IMPDIR)\core\stdc\string.d : src\core\stdc\string.d copy $** $@ $(IMPDIR)\core\stdc\tgmath.d : src\core\stdc\tgmath.d copy $** $@ $(IMPDIR)\core\stdc\time.d : src\core\stdc\time.d copy $** $@ $(IMPDIR)\core\stdc\wchar_.d : src\core\stdc\wchar_.d copy $** $@ $(IMPDIR)\core\stdc\wctype.d : src\core\stdc\wctype.d copy $** $@ $(IMPDIR)\core\stdcpp\exception.d : src\core\stdcpp\exception.d copy $** $@ $(IMPDIR)\core\stdcpp\typeinfo.d : src\core\stdcpp\typeinfo.d copy $** $@ $(IMPDIR)\core\sys\freebsd\dlfcn.d : src\core\sys\freebsd\dlfcn.d copy $** $@ $(IMPDIR)\core\sys\freebsd\execinfo.d : src\core\sys\freebsd\execinfo.d copy $** $@ $(IMPDIR)\core\sys\freebsd\time.d : src\core\sys\freebsd\time.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\cdefs.d : src\core\sys\freebsd\sys\cdefs.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\elf.d : src\core\sys\freebsd\sys\elf.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\elf_common.d : src\core\sys\freebsd\sys\elf_common.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\elf32.d : src\core\sys\freebsd\sys\elf32.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\elf64.d : src\core\sys\freebsd\sys\elf64.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\event.d : src\core\sys\freebsd\sys\event.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\link_elf.d : src\core\sys\freebsd\sys\link_elf.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\mman.d : src\core\sys\freebsd\sys\mman.d copy $** $@ $(IMPDIR)\core\sys\linux\config.d : src\core\sys\linux\config.d copy $** $@ $(IMPDIR)\core\sys\linux\dlfcn.d : src\core\sys\linux\dlfcn.d copy $** $@ $(IMPDIR)\core\sys\linux\elf.d : src\core\sys\linux\elf.d copy $** $@ $(IMPDIR)\core\sys\linux\epoll.d : src\core\sys\linux\epoll.d copy $** $@ $(IMPDIR)\core\sys\linux\errno.d : src\core\sys\linux\errno.d copy $** $@ $(IMPDIR)\core\sys\linux\execinfo.d : src\core\sys\linux\execinfo.d copy $** $@ $(IMPDIR)\core\sys\linux\fcntl.d : src\core\sys\linux\fcntl.d copy $** $@ $(IMPDIR)\core\sys\linux\link.d : src\core\sys\linux\link.d copy $** $@ $(IMPDIR)\core\sys\linux\termios.d : src\core\sys\linux\termios.d copy $** $@ $(IMPDIR)\core\sys\linux\time.d : src\core\sys\linux\time.d copy $** $@ $(IMPDIR)\core\sys\linux\timerfd.d : src\core\sys\linux\timerfd.d copy $** $@ $(IMPDIR)\core\sys\linux\tipc.d : src\core\sys\linux\tipc.d copy $** $@ $(IMPDIR)\core\sys\linux\unistd.d : src\core\sys\linux\unistd.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\auxv.d : src\core\sys\linux\sys\auxv.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\inotify.d : src\core\sys\linux\sys\inotify.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\mman.d : src\core\sys\linux\sys\mman.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\signalfd.d : src\core\sys\linux\sys\signalfd.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\socket.d : src\core\sys\linux\sys\socket.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\sysinfo.d : src\core\sys\linux\sys\sysinfo.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\xattr.d : src\core\sys\linux\sys\xattr.d copy $** $@ $(IMPDIR)\core\sys\osx\execinfo.d : src\core\sys\osx\execinfo.d copy $** $@ $(IMPDIR)\core\sys\osx\pthread.d : src\core\sys\osx\pthread.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\dyld.d : src\core\sys\osx\mach\dyld.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\getsect.d : src\core\sys\osx\mach\getsect.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\kern_return.d : src\core\sys\osx\mach\kern_return.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\loader.d : src\core\sys\osx\mach\loader.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\port.d : src\core\sys\osx\mach\port.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\semaphore.d : src\core\sys\osx\mach\semaphore.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\thread_act.d : src\core\sys\osx\mach\thread_act.d copy $** $@ $(IMPDIR)\core\sys\osx\sys\cdefs.d : src\core\sys\osx\sys\cdefs.d copy $** $@ $(IMPDIR)\core\sys\osx\sys\mman.d : src\core\sys\osx\sys\mman.d copy $** $@ $(IMPDIR)\core\sys\posix\arpa\inet.d : src\core\sys\posix\arpa\inet.d copy $** $@ $(IMPDIR)\core\sys\posix\config.d : src\core\sys\posix\config.d copy $** $@ $(IMPDIR)\core\sys\posix\dirent.d : src\core\sys\posix\dirent.d copy $** $@ $(IMPDIR)\core\sys\posix\dlfcn.d : src\core\sys\posix\dlfcn.d copy $** $@ $(IMPDIR)\core\sys\posix\fcntl.d : src\core\sys\posix\fcntl.d copy $** $@ $(IMPDIR)\core\sys\posix\grp.d : src\core\sys\posix\grp.d copy $** $@ $(IMPDIR)\core\sys\posix\inttypes.d : src\core\sys\posix\inttypes.d copy $** $@ $(IMPDIR)\core\sys\posix\netdb.d : src\core\sys\posix\netdb.d copy $** $@ $(IMPDIR)\core\sys\posix\net\if_.d : src\core\sys\posix\net\if_.d copy $** $@ $(IMPDIR)\core\sys\posix\netinet\in_.d : src\core\sys\posix\netinet\in_.d copy $** $@ $(IMPDIR)\core\sys\posix\netinet\tcp.d : src\core\sys\posix\netinet\tcp.d copy $** $@ $(IMPDIR)\core\sys\posix\poll.d : src\core\sys\posix\poll.d copy $** $@ $(IMPDIR)\core\sys\posix\pthread.d : src\core\sys\posix\pthread.d copy $** $@ $(IMPDIR)\core\sys\posix\pwd.d : src\core\sys\posix\pwd.d copy $** $@ $(IMPDIR)\core\sys\posix\sched.d : src\core\sys\posix\sched.d copy $** $@ $(IMPDIR)\core\sys\posix\semaphore.d : src\core\sys\posix\semaphore.d copy $** $@ $(IMPDIR)\core\sys\posix\setjmp.d : src\core\sys\posix\setjmp.d copy $** $@ $(IMPDIR)\core\sys\posix\signal.d : src\core\sys\posix\signal.d copy $** $@ $(IMPDIR)\core\sys\posix\stdio.d : src\core\sys\posix\stdio.d copy $** $@ $(IMPDIR)\core\sys\posix\stdlib.d : src\core\sys\posix\stdlib.d copy $** $@ $(IMPDIR)\core\sys\posix\syslog.d : src\core\sys\posix\syslog.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\ioctl.d : src\core\sys\posix\sys\ioctl.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\ipc.d : src\core\sys\posix\sys\ipc.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\mman.d : src\core\sys\posix\sys\mman.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\resource.d : src\core\sys\posix\sys\resource.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\select.d : src\core\sys\posix\sys\select.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\shm.d : src\core\sys\posix\sys\shm.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\socket.d : src\core\sys\posix\sys\socket.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\stat.d : src\core\sys\posix\sys\stat.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\statvfs.d : src\core\sys\posix\sys\statvfs.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\time.d : src\core\sys\posix\sys\time.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\types.d : src\core\sys\posix\sys\types.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\uio.d : src\core\sys\posix\sys\uio.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\un.d : src\core\sys\posix\sys\un.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\wait.d : src\core\sys\posix\sys\wait.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\utsname.d : src\core\sys\posix\sys\utsname.d copy $** $@ $(IMPDIR)\core\sys\posix\termios.d : src\core\sys\posix\termios.d copy $** $@ $(IMPDIR)\core\sys\posix\time.d : src\core\sys\posix\time.d copy $** $@ $(IMPDIR)\core\sys\posix\ucontext.d : src\core\sys\posix\ucontext.d copy $** $@ $(IMPDIR)\core\sys\posix\unistd.d : src\core\sys\posix\unistd.d copy $** $@ $(IMPDIR)\core\sys\posix\utime.d : src\core\sys\posix\utime.d copy $** $@ $(IMPDIR)\core\sys\solaris\dlfcn.d : src\core\sys\solaris\dlfcn.d copy $** $@ $(IMPDIR)\core\sys\solaris\elf.d : src\core\sys\solaris\elf.d copy $** $@ $(IMPDIR)\core\sys\solaris\execinfo.d : src\core\sys\solaris\execinfo.d copy $** $@ $(IMPDIR)\core\sys\solaris\libelf.d : src\core\sys\solaris\libelf.d copy $** $@ $(IMPDIR)\core\sys\solaris\link.d : src\core\sys\solaris\link.d copy $** $@ $(IMPDIR)\core\sys\solaris\time.d : src\core\sys\solaris\time.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf.d : src\core\sys\solaris\sys\elf.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf_386.d : src\core\sys\solaris\sys\elf_386.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf_amd64.d : src\core\sys\solaris\sys\elf_amd64.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf_notes.d : src\core\sys\solaris\sys\elf_notes.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf_SPARC.d : src\core\sys\solaris\sys\elf_SPARC.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elftypes.d : src\core\sys\solaris\sys\elftypes.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\link.d : src\core\sys\solaris\sys\link.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\procset.d : src\core\sys\solaris\sys\procset.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\types.d : src\core\sys\solaris\sys\types.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\priocntl.d : src\core\sys\solaris\sys\priocntl.d copy $** $@ $(IMPDIR)\core\sys\windows\accctrl.d : src\core\sys\windows\accctrl.d copy $** $@ $(IMPDIR)\core\sys\windows\aclapi.d : src\core\sys\windows\aclapi.d copy $** $@ $(IMPDIR)\core\sys\windows\aclui.d : src\core\sys\windows\aclui.d copy $** $@ $(IMPDIR)\core\sys\windows\basetsd.d : src\core\sys\windows\basetsd.d copy $** $@ $(IMPDIR)\core\sys\windows\basetyps.d : src\core\sys\windows\basetyps.d copy $** $@ $(IMPDIR)\core\sys\windows\cderr.d : src\core\sys\windows\cderr.d copy $** $@ $(IMPDIR)\core\sys\windows\cguid.d : src\core\sys\windows\cguid.d copy $** $@ $(IMPDIR)\core\sys\windows\com.d : src\core\sys\windows\com.d copy $** $@ $(IMPDIR)\core\sys\windows\comcat.d : src\core\sys\windows\comcat.d copy $** $@ $(IMPDIR)\core\sys\windows\commctrl.d : src\core\sys\windows\commctrl.d copy $** $@ $(IMPDIR)\core\sys\windows\commdlg.d : src\core\sys\windows\commdlg.d copy $** $@ $(IMPDIR)\core\sys\windows\core.d : src\core\sys\windows\core.d copy $** $@ $(IMPDIR)\core\sys\windows\cpl.d : src\core\sys\windows\cpl.d copy $** $@ $(IMPDIR)\core\sys\windows\cplext.d : src\core\sys\windows\cplext.d copy $** $@ $(IMPDIR)\core\sys\windows\custcntl.d : src\core\sys\windows\custcntl.d copy $** $@ $(IMPDIR)\core\sys\windows\dbghelp.d : src\core\sys\windows\dbghelp.d copy $** $@ $(IMPDIR)\core\sys\windows\dbghelp_types.d : src\core\sys\windows\dbghelp_types.d copy $** $@ $(IMPDIR)\core\sys\windows\dbt.d : src\core\sys\windows\dbt.d copy $** $@ $(IMPDIR)\core\sys\windows\dde.d : src\core\sys\windows\dde.d copy $** $@ $(IMPDIR)\core\sys\windows\ddeml.d : src\core\sys\windows\ddeml.d copy $** $@ $(IMPDIR)\core\sys\windows\dhcpcsdk.d : src\core\sys\windows\dhcpcsdk.d copy $** $@ $(IMPDIR)\core\sys\windows\dlgs.d : src\core\sys\windows\dlgs.d copy $** $@ $(IMPDIR)\core\sys\windows\dll.d : src\core\sys\windows\dll.d copy $** $@ $(IMPDIR)\core\sys\windows\docobj.d : src\core\sys\windows\docobj.d copy $** $@ $(IMPDIR)\core\sys\windows\errorrep.d : src\core\sys\windows\errorrep.d copy $** $@ $(IMPDIR)\core\sys\windows\exdisp.d : src\core\sys\windows\exdisp.d copy $** $@ $(IMPDIR)\core\sys\windows\exdispid.d : src\core\sys\windows\exdispid.d copy $** $@ $(IMPDIR)\core\sys\windows\httpext.d : src\core\sys\windows\httpext.d copy $** $@ $(IMPDIR)\core\sys\windows\idispids.d : src\core\sys\windows\idispids.d copy $** $@ $(IMPDIR)\core\sys\windows\imagehlp.d : src\core\sys\windows\imagehlp.d copy $** $@ $(IMPDIR)\core\sys\windows\imm.d : src\core\sys\windows\imm.d copy $** $@ $(IMPDIR)\core\sys\windows\intshcut.d : src\core\sys\windows\intshcut.d copy $** $@ $(IMPDIR)\core\sys\windows\ipexport.d : src\core\sys\windows\ipexport.d copy $** $@ $(IMPDIR)\core\sys\windows\iphlpapi.d : src\core\sys\windows\iphlpapi.d copy $** $@ $(IMPDIR)\core\sys\windows\ipifcons.d : src\core\sys\windows\ipifcons.d copy $** $@ $(IMPDIR)\core\sys\windows\iprtrmib.d : src\core\sys\windows\iprtrmib.d copy $** $@ $(IMPDIR)\core\sys\windows\iptypes.d : src\core\sys\windows\iptypes.d copy $** $@ $(IMPDIR)\core\sys\windows\isguids.d : src\core\sys\windows\isguids.d copy $** $@ $(IMPDIR)\core\sys\windows\lm.d : src\core\sys\windows\lm.d copy $** $@ $(IMPDIR)\core\sys\windows\lmaccess.d : src\core\sys\windows\lmaccess.d copy $** $@ $(IMPDIR)\core\sys\windows\lmalert.d : src\core\sys\windows\lmalert.d copy $** $@ $(IMPDIR)\core\sys\windows\lmapibuf.d : src\core\sys\windows\lmapibuf.d copy $** $@ $(IMPDIR)\core\sys\windows\lmat.d : src\core\sys\windows\lmat.d copy $** $@ $(IMPDIR)\core\sys\windows\lmaudit.d : src\core\sys\windows\lmaudit.d copy $** $@ $(IMPDIR)\core\sys\windows\lmbrowsr.d : src\core\sys\windows\lmbrowsr.d copy $** $@ $(IMPDIR)\core\sys\windows\lmchdev.d : src\core\sys\windows\lmchdev.d copy $** $@ $(IMPDIR)\core\sys\windows\lmconfig.d : src\core\sys\windows\lmconfig.d copy $** $@ $(IMPDIR)\core\sys\windows\lmcons.d : src\core\sys\windows\lmcons.d copy $** $@ $(IMPDIR)\core\sys\windows\lmerr.d : src\core\sys\windows\lmerr.d copy $** $@ $(IMPDIR)\core\sys\windows\lmerrlog.d : src\core\sys\windows\lmerrlog.d copy $** $@ $(IMPDIR)\core\sys\windows\lmmsg.d : src\core\sys\windows\lmmsg.d copy $** $@ $(IMPDIR)\core\sys\windows\lmremutl.d : src\core\sys\windows\lmremutl.d copy $** $@ $(IMPDIR)\core\sys\windows\lmrepl.d : src\core\sys\windows\lmrepl.d copy $** $@ $(IMPDIR)\core\sys\windows\lmserver.d : src\core\sys\windows\lmserver.d copy $** $@ $(IMPDIR)\core\sys\windows\lmshare.d : src\core\sys\windows\lmshare.d copy $** $@ $(IMPDIR)\core\sys\windows\lmsname.d : src\core\sys\windows\lmsname.d copy $** $@ $(IMPDIR)\core\sys\windows\lmstats.d : src\core\sys\windows\lmstats.d copy $** $@ $(IMPDIR)\core\sys\windows\lmsvc.d : src\core\sys\windows\lmsvc.d copy $** $@ $(IMPDIR)\core\sys\windows\lmuse.d : src\core\sys\windows\lmuse.d copy $** $@ $(IMPDIR)\core\sys\windows\lmuseflg.d : src\core\sys\windows\lmuseflg.d copy $** $@ $(IMPDIR)\core\sys\windows\lmwksta.d : src\core\sys\windows\lmwksta.d copy $** $@ $(IMPDIR)\core\sys\windows\lzexpand.d : src\core\sys\windows\lzexpand.d copy $** $@ $(IMPDIR)\core\sys\windows\mapi.d : src\core\sys\windows\mapi.d copy $** $@ $(IMPDIR)\core\sys\windows\mciavi.d : src\core\sys\windows\mciavi.d copy $** $@ $(IMPDIR)\core\sys\windows\mcx.d : src\core\sys\windows\mcx.d copy $** $@ $(IMPDIR)\core\sys\windows\mgmtapi.d : src\core\sys\windows\mgmtapi.d copy $** $@ $(IMPDIR)\core\sys\windows\mmsystem.d : src\core\sys\windows\mmsystem.d copy $** $@ $(IMPDIR)\core\sys\windows\msacm.d : src\core\sys\windows\msacm.d copy $** $@ $(IMPDIR)\core\sys\windows\mshtml.d : src\core\sys\windows\mshtml.d copy $** $@ $(IMPDIR)\core\sys\windows\mswsock.d : src\core\sys\windows\mswsock.d copy $** $@ $(IMPDIR)\core\sys\windows\nb30.d : src\core\sys\windows\nb30.d copy $** $@ $(IMPDIR)\core\sys\windows\nddeapi.d : src\core\sys\windows\nddeapi.d copy $** $@ $(IMPDIR)\core\sys\windows\nspapi.d : src\core\sys\windows\nspapi.d copy $** $@ $(IMPDIR)\core\sys\windows\ntdef.d : src\core\sys\windows\ntdef.d copy $** $@ $(IMPDIR)\core\sys\windows\ntdll.d : src\core\sys\windows\ntdll.d copy $** $@ $(IMPDIR)\core\sys\windows\ntldap.d : src\core\sys\windows\ntldap.d copy $** $@ $(IMPDIR)\core\sys\windows\ntsecapi.d : src\core\sys\windows\ntsecapi.d copy $** $@ $(IMPDIR)\core\sys\windows\ntsecpkg.d : src\core\sys\windows\ntsecpkg.d copy $** $@ $(IMPDIR)\core\sys\windows\oaidl.d : src\core\sys\windows\oaidl.d copy $** $@ $(IMPDIR)\core\sys\windows\objbase.d : src\core\sys\windows\objbase.d copy $** $@ $(IMPDIR)\core\sys\windows\objfwd.d : src\core\sys\windows\objfwd.d copy $** $@ $(IMPDIR)\core\sys\windows\objidl.d : src\core\sys\windows\objidl.d copy $** $@ $(IMPDIR)\core\sys\windows\objsafe.d : src\core\sys\windows\objsafe.d copy $** $@ $(IMPDIR)\core\sys\windows\ocidl.d : src\core\sys\windows\ocidl.d copy $** $@ $(IMPDIR)\core\sys\windows\odbcinst.d : src\core\sys\windows\odbcinst.d copy $** $@ $(IMPDIR)\core\sys\windows\ole.d : src\core\sys\windows\ole.d copy $** $@ $(IMPDIR)\core\sys\windows\ole2.d : src\core\sys\windows\ole2.d copy $** $@ $(IMPDIR)\core\sys\windows\ole2ver.d : src\core\sys\windows\ole2ver.d copy $** $@ $(IMPDIR)\core\sys\windows\oleacc.d : src\core\sys\windows\oleacc.d copy $** $@ $(IMPDIR)\core\sys\windows\oleauto.d : src\core\sys\windows\oleauto.d copy $** $@ $(IMPDIR)\core\sys\windows\olectl.d : src\core\sys\windows\olectl.d copy $** $@ $(IMPDIR)\core\sys\windows\olectlid.d : src\core\sys\windows\olectlid.d copy $** $@ $(IMPDIR)\core\sys\windows\oledlg.d : src\core\sys\windows\oledlg.d copy $** $@ $(IMPDIR)\core\sys\windows\oleidl.d : src\core\sys\windows\oleidl.d copy $** $@ $(IMPDIR)\core\sys\windows\pbt.d : src\core\sys\windows\pbt.d copy $** $@ $(IMPDIR)\core\sys\windows\powrprof.d : src\core\sys\windows\powrprof.d copy $** $@ $(IMPDIR)\core\sys\windows\prsht.d : src\core\sys\windows\prsht.d copy $** $@ $(IMPDIR)\core\sys\windows\psapi.d : src\core\sys\windows\psapi.d copy $** $@ $(IMPDIR)\core\sys\windows\rapi.d : src\core\sys\windows\rapi.d copy $** $@ $(IMPDIR)\core\sys\windows\ras.d : src\core\sys\windows\ras.d copy $** $@ $(IMPDIR)\core\sys\windows\rasdlg.d : src\core\sys\windows\rasdlg.d copy $** $@ $(IMPDIR)\core\sys\windows\raserror.d : src\core\sys\windows\raserror.d copy $** $@ $(IMPDIR)\core\sys\windows\rassapi.d : src\core\sys\windows\rassapi.d copy $** $@ $(IMPDIR)\core\sys\windows\reason.d : src\core\sys\windows\reason.d copy $** $@ $(IMPDIR)\core\sys\windows\regstr.d : src\core\sys\windows\regstr.d copy $** $@ $(IMPDIR)\core\sys\windows\richedit.d : src\core\sys\windows\richedit.d copy $** $@ $(IMPDIR)\core\sys\windows\richole.d : src\core\sys\windows\richole.d copy $** $@ $(IMPDIR)\core\sys\windows\rpc.d : src\core\sys\windows\rpc.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcdce.d : src\core\sys\windows\rpcdce.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcdce2.d : src\core\sys\windows\rpcdce2.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcdcep.d : src\core\sys\windows\rpcdcep.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcndr.d : src\core\sys\windows\rpcndr.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcnsi.d : src\core\sys\windows\rpcnsi.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcnsip.d : src\core\sys\windows\rpcnsip.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcnterr.d : src\core\sys\windows\rpcnterr.d copy $** $@ $(IMPDIR)\core\sys\windows\schannel.d : src\core\sys\windows\schannel.d copy $** $@ $(IMPDIR)\core\sys\windows\secext.d : src\core\sys\windows\secext.d copy $** $@ $(IMPDIR)\core\sys\windows\security.d : src\core\sys\windows\security.d copy $** $@ $(IMPDIR)\core\sys\windows\servprov.d : src\core\sys\windows\servprov.d copy $** $@ $(IMPDIR)\core\sys\windows\setupapi.d : src\core\sys\windows\setupapi.d copy $** $@ $(IMPDIR)\core\sys\windows\shellapi.d : src\core\sys\windows\shellapi.d copy $** $@ $(IMPDIR)\core\sys\windows\shldisp.d : src\core\sys\windows\shldisp.d copy $** $@ $(IMPDIR)\core\sys\windows\shlguid.d : src\core\sys\windows\shlguid.d copy $** $@ $(IMPDIR)\core\sys\windows\shlobj.d : src\core\sys\windows\shlobj.d copy $** $@ $(IMPDIR)\core\sys\windows\shlwapi.d : src\core\sys\windows\shlwapi.d copy $** $@ $(IMPDIR)\core\sys\windows\snmp.d : src\core\sys\windows\snmp.d copy $** $@ $(IMPDIR)\core\sys\windows\sql.d : src\core\sys\windows\sql.d copy $** $@ $(IMPDIR)\core\sys\windows\sqlext.d : src\core\sys\windows\sqlext.d copy $** $@ $(IMPDIR)\core\sys\windows\sqltypes.d : src\core\sys\windows\sqltypes.d copy $** $@ $(IMPDIR)\core\sys\windows\sqlucode.d : src\core\sys\windows\sqlucode.d copy $** $@ $(IMPDIR)\core\sys\windows\sspi.d : src\core\sys\windows\sspi.d copy $** $@ $(IMPDIR)\core\sys\windows\stacktrace.d : src\core\sys\windows\stacktrace.d copy $** $@ $(IMPDIR)\core\sys\windows\stat.d : src\core\sys\windows\stat.d copy $** $@ $(IMPDIR)\core\sys\windows\subauth.d : src\core\sys\windows\subauth.d copy $** $@ $(IMPDIR)\core\sys\windows\threadaux.d : src\core\sys\windows\threadaux.d copy $** $@ $(IMPDIR)\core\sys\windows\tlhelp32.d : src\core\sys\windows\tlhelp32.d copy $** $@ $(IMPDIR)\core\sys\windows\tmschema.d : src\core\sys\windows\tmschema.d copy $** $@ $(IMPDIR)\core\sys\windows\unknwn.d : src\core\sys\windows\unknwn.d copy $** $@ $(IMPDIR)\core\sys\windows\uuid.d : src\core\sys\windows\uuid.d copy $** $@ $(IMPDIR)\core\sys\windows\vfw.d : src\core\sys\windows\vfw.d copy $** $@ $(IMPDIR)\core\sys\windows\w32api.d : src\core\sys\windows\w32api.d copy $** $@ $(IMPDIR)\core\sys\windows\winbase.d : src\core\sys\windows\winbase.d copy $** $@ $(IMPDIR)\core\sys\windows\winber.d : src\core\sys\windows\winber.d copy $** $@ $(IMPDIR)\core\sys\windows\wincon.d : src\core\sys\windows\wincon.d copy $** $@ $(IMPDIR)\core\sys\windows\wincrypt.d : src\core\sys\windows\wincrypt.d copy $** $@ $(IMPDIR)\core\sys\windows\windef.d : src\core\sys\windows\windef.d copy $** $@ $(IMPDIR)\core\sys\windows\windows.d : src\core\sys\windows\windows.d copy $** $@ $(IMPDIR)\core\sys\windows\winerror.d : src\core\sys\windows\winerror.d copy $** $@ $(IMPDIR)\core\sys\windows\wingdi.d : src\core\sys\windows\wingdi.d copy $** $@ $(IMPDIR)\core\sys\windows\winhttp.d : src\core\sys\windows\winhttp.d copy $** $@ $(IMPDIR)\core\sys\windows\wininet.d : src\core\sys\windows\wininet.d copy $** $@ $(IMPDIR)\core\sys\windows\winioctl.d : src\core\sys\windows\winioctl.d copy $** $@ $(IMPDIR)\core\sys\windows\winldap.d : src\core\sys\windows\winldap.d copy $** $@ $(IMPDIR)\core\sys\windows\winnetwk.d : src\core\sys\windows\winnetwk.d copy $** $@ $(IMPDIR)\core\sys\windows\winnls.d : src\core\sys\windows\winnls.d copy $** $@ $(IMPDIR)\core\sys\windows\winnt.d : src\core\sys\windows\winnt.d copy $** $@ $(IMPDIR)\core\sys\windows\winperf.d : src\core\sys\windows\winperf.d copy $** $@ $(IMPDIR)\core\sys\windows\winreg.d : src\core\sys\windows\winreg.d copy $** $@ $(IMPDIR)\core\sys\windows\winsock2.d : src\core\sys\windows\winsock2.d copy $** $@ $(IMPDIR)\core\sys\windows\winspool.d : src\core\sys\windows\winspool.d copy $** $@ $(IMPDIR)\core\sys\windows\winsvc.d : src\core\sys\windows\winsvc.d copy $** $@ $(IMPDIR)\core\sys\windows\winuser.d : src\core\sys\windows\winuser.d copy $** $@ $(IMPDIR)\core\sys\windows\winver.d : src\core\sys\windows\winver.d copy $** $@ $(IMPDIR)\core\sys\windows\wtsapi32.d : src\core\sys\windows\wtsapi32.d copy $** $@ $(IMPDIR)\core\sys\windows\wtypes.d : src\core\sys\windows\wtypes.d copy $** $@ $(IMPDIR)\etc\linux\memoryerror.d : src\etc\linux\memoryerror.d copy $** $@ ################### Win32 Import Libraries ################### IMPLIBS= \ lib\win32\glu32.lib \ lib\win32\odbc32.lib \ lib\win32\opengl32.lib \ lib\win32\rpcrt4.lib \ lib\win32\shell32.lib \ lib\win32\version.lib \ lib\win32\wininet.lib \ lib\win32\winspool.lib implibsdir : if not exist lib\win32 mkdir lib\win32 implibs : implibsdir $(IMPLIBS) lib\win32\glu32.lib : def\glu32.def implib $@ $** lib\win32\odbc32.lib : def\odbc32.def implib $@ $** lib\win32\opengl32.lib : def\opengl32.def implib $@ $** lib\win32\rpcrt4.lib : def\rpcrt4.def implib $@ $** lib\win32\shell32.lib : def\shell32.def implib $@ $** lib\win32\version.lib : def\version.def implib $@ $** lib\win32\wininet.lib : def\wininet.def implib $@ $** lib\win32\winspool.lib : def\winspool.def implib $@ $** ################### C\ASM Targets ############################ errno_c_$(MODEL).obj : src\core\stdc\errno.c $(CC) -c -o$@ $(CFLAGS) src\core\stdc\errno.c # only rebuild explicitly rebuild_minit_obj : src\rt\minit.asm $(CC) -c $(CFLAGS) src\rt\minit.asm ################### gcstub generation ######################### $(GCSTUB) : src\gcstub\gc.d win$(MODEL).mak $(DMD) -c -of$(GCSTUB) src\gcstub\gc.d $(DFLAGS) ################### Library generation ######################### $(DRUNTIME): $(OBJS) $(SRCS) win$(MODEL).mak $(DMD) -lib -of$(DRUNTIME) -Xfdruntime.json $(DFLAGS) $(SRCS) $(OBJS) unittest : $(SRCS) $(DRUNTIME) $(DMD) $(UDFLAGS) -L/co -unittest -ofunittest.exe -main $(SRCS) $(DRUNTIME) -debuglib=$(DRUNTIME) -defaultlib=$(DRUNTIME) unittest zip: druntime.zip druntime.zip: del druntime.zip git ls-tree --name-only -r HEAD >MANIFEST.tmp zip32 -T -ur druntime @MANIFEST.tmp del MANIFEST.tmp install: druntime.zip unzip -o druntime.zip -d \dmd2\src\druntime clean: del $(DRUNTIME) $(OBJS_TO_DELETE) $(GCSTUB) rmdir /S /Q $(DOCDIR) $(IMPDIR) auto-tester-build: target auto-tester-test: unittest ldc-1.1.0-beta3-src/runtime/druntime/test/0000775000175000017500000000000012776214756016442 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/init_fini/0000775000175000017500000000000012776214756020412 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/init_fini/Makefile0000664000175000017500000000046712776214756022061 0ustar kaikaiinclude ../common.mak TESTS:=thread_join runtime_args .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) $(ROOT)/%.done: $(ROOT)/% @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ $(ROOT)/%: $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: rm -rf $(ROOT) ldc-1.1.0-beta3-src/runtime/druntime/test/init_fini/src/0000775000175000017500000000000012776214756021201 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/init_fini/src/thread_join.d0000664000175000017500000000070212776214756023633 0ustar kaikai// Bugzilla 11309 - std.concurrency: OwnerTerminated message doesn't work // We need to assure that the thread dtors of parent threads run before the thread dtors of the child threads. import core.thread, core.sync.semaphore; import core.stdc.stdio; __gshared Semaphore sem; static ~this() { if (sem !is null) sem.notify(); } void main() { sem = new Semaphore; auto thr = new Thread({assert(sem.wait(1.seconds));}); thr.start(); } ldc-1.1.0-beta3-src/runtime/druntime/test/init_fini/src/runtime_args.d0000664000175000017500000000037612776214756024053 0ustar kaikai// Bugzilla 11149 - Runtime.args no longer available in static constructors import core.runtime; shared static this() { assert(Runtime.cArgs.argc > 0); assert(Runtime.cArgs.argv !is null); assert(Runtime.args.length > 0); } void main() { } ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/0000775000175000017500000000000012776214756020235 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/coverage/src-no_code_imp.lst.exp0000664000175000017500000000007412776214756024615 0ustar kaikai |enum NO_CODE_IMP = 0; src/no_code_imp.d has no code ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/src-merge_true.lst.exp0000664000175000017500000000031112776214756024472 0ustar kaikai |import core.runtime; | |void main(string[] args) |{ 2| dmd_coverDestPath(args[1]); 2| dmd_coverSetMerge(true); |} src/merge_true.d is 100% covered ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/src-no_code.lst.exp0000664000175000017500000000024112776214756023744 0ustar kaikai |import core.runtime; | |void main(string[] args) |{ 1| dmd_coverDestPath(args[1]); |} src/no_code.d is 100% covered ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/Makefile0000664000175000017500000000211312776214756021672 0ustar kaikaiinclude ../common.mak DFLAGS+=-cov NORMAL_TESTS:=$(addprefix $(ROOT)/,$(addsuffix .done,basic no_code)) MERGE_TESTS:=$(addprefix $(ROOT)/,$(addsuffix .done,merge merge_true)) DIFF:=diff .PHONY: all clean all: $(NORMAL_TESTS) $(MERGE_TESTS) $(NORMAL_TESTS): $(ROOT)/%.done: $(ROOT)/% @echo Testing $* @rm -f $(ROOT)/src-$*.lst $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) $(QUIET)$(DIFF) src-$*.lst.exp $(ROOT)/src-$*.lst @touch $@ $(MERGE_TESTS): $(ROOT)/%.done: $(ROOT)/% @echo Testing $* @rm -f $(ROOT)/src-$*.lst $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) $(QUIET)$(DIFF) src-$*.lst.exp $(ROOT)/src-$*.lst @touch $@ $(ROOT)/no_code.done: $(ROOT)/%.done: $(ROOT)/% @echo Testing $* @rm -f $(ROOT)/src-$*.lst $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) $(QUIET)$(DIFF) src-$*.lst.exp $(ROOT)/src-$*.lst $(QUIET)$(DIFF) src-$*_imp.lst.exp $(ROOT)/src-$*_imp.lst @touch $@ $(ROOT)/no_code: $(SRC)/no_code_imp.d $(ROOT)/%: $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$(ROOT)/$* $^ clean: rm -rf $(GENERATED) *.lst ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/src-merge.lst.exp0000664000175000017500000000026412776214756023442 0ustar kaikai |import core.runtime; | |int main(string[] args) |{ 1| dmd_coverDestPath(args[1]); 1| return 0; |} src/merge.d is 100% covered ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/src-basic.lst.exp0000664000175000017500000000023712776214756023424 0ustar kaikai |import core.runtime; | |void main(string[] args) |{ 1| dmd_coverDestPath(args[1]); |} src/basic.d is 100% covered ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/src/0000775000175000017500000000000012776214756021024 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/coverage/src/no_code_imp.d0000664000175000017500000000002612776214756023442 0ustar kaikaienum NO_CODE_IMP = 0; ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/src/no_code.d0000664000175000017500000000012312776214756022573 0ustar kaikaiimport core.runtime; void main(string[] args) { dmd_coverDestPath(args[1]); } ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/src/merge.d0000664000175000017500000000014012776214756022263 0ustar kaikaiimport core.runtime; int main(string[] args) { dmd_coverDestPath(args[1]); return 0; } ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/src/merge_true.d0000664000175000017500000000016012776214756023324 0ustar kaikaiimport core.runtime; void main(string[] args) { dmd_coverDestPath(args[1]); dmd_coverSetMerge(true); } ldc-1.1.0-beta3-src/runtime/druntime/test/coverage/src/basic.d0000664000175000017500000000012312776214756022246 0ustar kaikaiimport core.runtime; void main(string[] args) { dmd_coverDestPath(args[1]); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/0000775000175000017500000000000012776214756017710 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/shared/Makefile0000664000175000017500000000547012776214756021356 0ustar kaikaiLINK_SHARED:=1 include ../common.mak TESTS:=link load linkD linkDR loadDR host finalize TESTS+=link_linkdep load_linkdep link_loaddep load_loaddep load_13414 TESTS+=link_mod_collision load_mod_collision .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) $(ROOT)/loadDR.done $(ROOT)/host.done: RUN_ARGS:=$(DRUNTIMESO) $(ROOT)/%_mod_collision.done: $(ROOT)/%_mod_collision @echo Testing $*_mod_collision $(QUIET)($(TIMELIMIT)$< $(RUN_ARGS) 2>&1 || true) | grep -qF 'already defined' @touch $@ $(ROOT)/%.done: $(ROOT)/% @echo Testing $* $(QUIET)$(TIMELIMIT)$< $(RUN_ARGS) @touch $@ $(ROOT)/link: $(SRC)/link.d $(ROOT)/lib.so $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< -L$(ROOT)/lib.so $(ROOT)/link_linkdep: $(SRC)/link_linkdep.d $(ROOT)/lib.so $(ROOT)/liblinkdep.so $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) -L$(ROOT)/liblinkdep.so -L$(ROOT)/lib.so $(ROOT)/load_linkdep: $(SRC)/load_linkdep.d $(ROOT)/lib.so $(ROOT)/liblinkdep.so $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) $(LINKDL) $(ROOT)/link_loaddep: $(SRC)/link_loaddep.d $(ROOT)/lib.so $(ROOT)/libloaddep.so $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) -L$(ROOT)/libloaddep.so $(ROOT)/load_loaddep: $(SRC)/load_loaddep.d $(ROOT)/lib.so $(ROOT)/libloaddep.so $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) $(LINKDL) $(ROOT)/load $(ROOT)/finalize: $(ROOT)/%: $(SRC)/%.d $(ROOT)/lib.so $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKDL) $(ROOT)/load_13414: $(ROOT)/%: $(SRC)/%.d $(ROOT)/lib_13414.so $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKDL) $(ROOT)/linkD: $(SRC)/linkD.c $(ROOT)/lib.so $(DRUNTIMESO) $(QUIET)$(CC) $(CFLAGS) -o $@ $< $(ROOT)/lib.so $(LDL) -pthread $(ROOT)/linkDR: $(SRC)/linkDR.c $(ROOT)/lib.so $(DRUNTIMESO) $(QUIET)$(CC) $(CFLAGS) -o $@ $< $(DRUNTIMESO) $(LDL) -pthread $(ROOT)/loadDR: $(SRC)/loadDR.c $(ROOT)/lib.so $(DRUNTIMESO) $(QUIET)$(CC) $(CFLAGS) -o $@ $< $(LDL) -pthread $(ROOT)/host: $(SRC)/host.c $(ROOT)/plugin1.so $(ROOT)/plugin2.so $(QUIET)$(CC) $(CFLAGS) -o $@ $< $(LDL) -pthread $(ROOT)/link_mod_collision: $(ROOT)/%: $(SRC)/%.d $(ROOT)/lib.so $(DRUNTIMESO) # use no-as-needed to enforce linking of unused lib.so $(QUIET)$(DMD) $(DFLAGS) -of$@ $< -L--no-as-needed -L$(ROOT)/lib.so $(ROOT)/load_mod_collision: $(ROOT)/%: $(SRC)/%.d $(ROOT)/lib.so $(DRUNTIMESO) # use export dynamic so that Module in exe can interposes Module in lib.so $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKDL) -L--export-dynamic $(ROOT)/liblinkdep.so: $(ROOT)/lib.so $(ROOT)/liblinkdep.so: DFLAGS+=-L$(ROOT)/lib.so $(ROOT)/plugin1.so $(ROOT)/plugin2.so: $(SRC)/plugin.d $(DRUNTIMESO) $(QUIET)$(DMD) -fPIC -shared $(DFLAGS) -of$@ $< $(ROOT)/%.so: $(SRC)/%.d $(DRUNTIMESO) $(QUIET)$(DMD) -fPIC -shared $(DFLAGS) -of$@ $< $(LINKDL) clean: rm -rf $(GENERATED) ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/0000775000175000017500000000000012776214756020477 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/shared/src/load.d0000664000175000017500000000645012776214756021570 0ustar kaikaiimport core.runtime, core.stdc.stdio, core.thread; version (linux) import core.sys.linux.dlfcn; else version (FreeBSD) import core.sys.freebsd.dlfcn; else static assert(0, "unimplemented"); void loadSym(T)(void* handle, ref T val, const char* mangle) { val = cast(T).dlsym(handle, mangle); } void* openLib(string s) { auto h = Runtime.loadLibrary(s); assert(h !is null); loadSym(h, libThrowException, "_D3lib14throwExceptionFZv"); loadSym(h, libCollectException, "_D3lib16collectExceptionFDFZvZC9Exception"); loadSym(h, libAlloc, "_D3lib5allocFZv"); loadSym(h, libTlsAlloc, "_D3lib9tls_allocFZv"); loadSym(h, libAccess, "_D3lib6accessFZv"); loadSym(h, libTlsAccess, "_D3lib10tls_accessFZv"); loadSym(h, libFree, "_D3lib4freeFZv"); loadSym(h, libTlsFree, "_D3lib8tls_freeFZv"); loadSym(h, libSharedStaticCtor, "_D3lib18shared_static_ctorOk"); loadSym(h, libSharedStaticDtor, "_D3lib18shared_static_dtorOk"); loadSym(h, libStaticCtor, "_D3lib11static_ctorOk"); loadSym(h, libStaticDtor, "_D3lib11static_dtorOk"); return h; } void closeLib(void* h) { Runtime.unloadLibrary(h); } __gshared { void function() libThrowException; Exception function(void delegate()) libCollectException; void function() libAlloc; void function() libTlsAlloc; void function() libAccess; void function() libTlsAccess; void function() libFree; void function() libTlsFree; shared uint* libSharedStaticCtor; shared uint* libSharedStaticDtor; shared uint* libStaticCtor; shared uint* libStaticDtor; } void testEH() { bool passed; try libThrowException(); catch (Exception e) passed = true; assert(passed); passed = false; assert(libCollectException({throw new Exception(null);}) !is null); assert(libCollectException({libThrowException();}) !is null); } void testGC() { import core.memory; libAlloc(); libTlsAlloc(); libAccess(); libTlsAccess(); GC.collect(); libTlsAccess(); libAccess(); libTlsFree(); libFree(); } void testInit() { assert(*libStaticCtor == 1); assert(*libStaticDtor == 0); static void run() { assert(*libSharedStaticCtor == 1); assert(*libSharedStaticDtor == 0); assert(*libStaticCtor == 2); assert(*libStaticDtor == 0); } auto thr = new Thread(&run); thr.start(); thr.join(); assert(*libSharedStaticCtor == 1); assert(*libSharedStaticDtor == 0); assert(*libStaticCtor == 2); assert(*libStaticDtor == 1); } const(ModuleInfo)* findModuleInfo(string name) { foreach (m; ModuleInfo) if (m.name == name) return m; return null; } void runTests(string libName) { assert(findModuleInfo("lib") is null); auto handle = openLib(libName); assert(findModuleInfo("lib") !is null); testEH(); testGC(); testInit(); closeLib(handle); assert(findModuleInfo("lib") is null); } void main(string[] args) { auto name = args[0]; assert(name[$-5 .. $] == "/load"); name = name[0 .. $-4] ~ "lib.so"; runTests(name); // lib is no longer resident name ~= '\0'; assert(.dlopen(name.ptr, RTLD_LAZY | RTLD_NOLOAD) is null); name = name[0 .. $-1]; auto thr = new Thread({runTests(name);}); thr.start(); thr.join(); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/finalize.d0000664000175000017500000000250212776214756022444 0ustar kaikaiimport core.runtime, core.stdc.stdio, core.thread, core.sys.posix.dlfcn; void runTest() { Object obj; obj = Object.factory("lib.MyFinalizer"); assert(obj.toString() == "lib.MyFinalizer"); obj = Object.factory("lib.MyFinalizerBig"); assert(obj.toString() == "lib.MyFinalizerBig"); } class NoFinalize { size_t _finalizeCounter; ~this() { ++_finalizeCounter; } } class NoFinalizeBig : NoFinalize { ubyte[4096] _big = void; } extern (C) alias SetFinalizeCounter = void function(shared(size_t*)); void main(string[] args) { printf("STARTING finalize\n"); auto name = args[0]; assert(name[$-9 .. $] == "/finalize"); name = name[0 .. $-8] ~ "lib.so"; auto h = Runtime.loadLibrary(name); assert(h !is null); auto nf1 = new NoFinalize; auto nf2 = new NoFinalizeBig; shared size_t finalizeCounter; auto setFinalizeCounter = cast(SetFinalizeCounter)dlsym(h, "setFinalizeCounter"); setFinalizeCounter(&finalizeCounter); runTest(); auto thr = new Thread(&runTest); thr.start(); thr.join(); auto r = Runtime.unloadLibrary(h); if (!r) assert(0); if (finalizeCounter != 4) assert(0); if (nf1._finalizeCounter) assert(0); if (nf2._finalizeCounter) assert(0); printf("PASS finalize\n"); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/load_loaddep.d0000664000175000017500000000065512776214756023261 0ustar kaikaiimport core.runtime, core.sys.posix.dlfcn; extern(C) alias RunDepTests = int function(const char*); void main(string[] args) { auto root = args[0][0..$-"load_loaddep".length]; auto libloaddep = root ~ "libloaddep.so"; auto h = Runtime.loadLibrary(libloaddep); auto runDepTests = cast(RunDepTests)dlsym(h, "runDepTests"); assert(runDepTests((root ~ "lib.so\0").ptr)); assert(Runtime.unloadLibrary(h)); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/load_mod_collision.d0000664000175000017500000000044612776214756024501 0ustar kaikaimodule lib; // module collides with lib.so import core.runtime, core.stdc.stdio, core.sys.posix.dlfcn; void main(string[] args) { auto name = args[0]; assert(name[$-19 .. $] == "/load_mod_collision"); name = name[0 .. $-18] ~ "lib.so"; auto lib = Runtime.loadLibrary(name); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/link_linkdep.d0000664000175000017500000000006712776214756023312 0ustar kaikaiimport liblinkdep; void main() { runDepTests(); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/link_mod_collision.d0000664000175000017500000000007412776214756024514 0ustar kaikaimodule lib; // module collides with lib.so void main() { } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/linkDR.c0000664000175000017500000000135612776214756022033 0ustar kaikai#include #include #include #include extern void* rt_loadLibrary(const char*); extern int rt_unloadLibrary(void*); extern int rt_init(void); extern int rt_term(void); int main(int argc, char* argv[]) { if (!rt_init()) return EXIT_FAILURE; const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1; char *name = malloc(pathlen + sizeof("lib.so")); memcpy(name, argv[0], pathlen); memcpy(name+pathlen, "lib.so", sizeof("lib.so")); void *dlib = rt_loadLibrary(name); free(name); assert(dlib); int (*runTests)(void) = dlsym(dlib, "runTests"); assert(runTests()); assert(rt_unloadLibrary(dlib)); if (!rt_term()) return EXIT_FAILURE; return EXIT_SUCCESS; } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/link_loaddep.d0000664000175000017500000000022412776214756023267 0ustar kaikaiimport libloaddep; void main(string[] args) { auto libname = args[0][0..$-"link_loaddep".length] ~ "lib.so\0"; runDepTests(libname.ptr); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/host.c0000664000175000017500000000331412776214756021621 0ustar kaikai#include #include #include #include int main(int argc, char* argv[]) { #if defined(__FreeBSD__) // workaround for Bugzilla 14824 void *druntime = dlopen(argv[1], RTLD_LAZY); // load druntime assert(druntime); #endif const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1; char *name = malloc(pathlen + sizeof("plugin1.so")); memcpy(name, argv[0], pathlen); memcpy(name+pathlen, "plugin1.so", sizeof("plugin1.so")); void* plugin1 = dlopen(name, RTLD_LAZY); name[pathlen + sizeof("plugin1.so") - 5] = '2'; void* plugin2 = dlopen(name, RTLD_LAZY); int (*plugin1_init)() = dlsym(plugin1, "plugin_init"); int (*plugin1_term)() = dlsym(plugin1, "plugin_term"); int (*runTests1)() = dlsym(plugin1, "runTests"); int (*plugin2_init)() = dlsym(plugin2, "plugin_init"); int (*plugin2_term)() = dlsym(plugin2, "plugin_term"); int (*runTests2)() = dlsym(plugin2, "runTests"); assert(plugin1_init()); assert(runTests1()); assert(plugin2_init()); assert(runTests2()); assert(plugin1_term()); assert(dlclose(plugin1) == 0); assert(runTests2()); name[pathlen + sizeof("plugin1.so") - 5] = '1'; plugin1 = dlopen(name, RTLD_LAZY); plugin1_init = dlsym(plugin1, "plugin_init"); plugin1_term = dlsym(plugin1, "plugin_term"); runTests1 = dlsym(plugin1, "runTests"); assert(plugin1_init()); assert(runTests1()); assert(runTests2()); assert(plugin2_term()); assert(dlclose(plugin2) == 0); assert(runTests1()); assert(plugin1_term()); assert(dlclose(plugin1) == 0); free(name); #if defined(__FreeBSD__) dlclose(druntime); #endif return EXIT_SUCCESS; } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/plugin.d0000664000175000017500000000211412776214756022140 0ustar kaikaiimport core.thread, core.memory, core.atomic; shared uint gctor, gdtor, tctor, tdtor; shared static this() { if (atomicOp!"+="(gctor, 1) != 1) assert(0); } shared static ~this() { if (atomicOp!"+="(gdtor, 1) != 1) assert(0); } static this() { atomicOp!"+="(tctor, 1); } static ~this() { atomicOp!"+="(tdtor, 1); } Thread t; void launchThread() { (t = new Thread({})).start(); } void joinThread() { t.join(); } extern(C) int runTests() { try { assert(atomicLoad!(MemoryOrder.acq)(gctor) == 1); assert(atomicLoad!(MemoryOrder.acq)(gdtor) == 0); assert(atomicLoad!(MemoryOrder.acq)(tctor) >= 1); assert(atomicLoad!(MemoryOrder.acq)(tdtor) >= 0); // test some runtime functionality launchThread(); GC.collect(); joinThread(); } catch (Throwable) { return false; } return true; } // Provide a way to initialize D from C programs that are D agnostic. import core.runtime : rt_init, rt_term; extern(C) int plugin_init() { return rt_init(); } extern(C) int plugin_term() { return rt_term(); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/lib.d0000664000175000017500000000453412776214756021420 0ustar kaikaimodule lib; // test EH void throwException() { throw new Exception(null); } Exception collectException(void delegate() dg) { try dg(); catch (Exception e) return e; return null; } // test GC __gshared Object root; void alloc() { root = new Object(); } void access() { assert(root.toString() !is null); } // vtbl call will fail if finalized void free() { root = null; } Object tls_root; void tls_alloc() { tls_root = new Object(); } void tls_access() { assert(tls_root.toString() !is null); } // vtbl call will fail if finalized void tls_free() { tls_root = null; } // test Init import core.atomic : atomicOp; shared uint shared_static_ctor, shared_static_dtor, static_ctor, static_dtor; shared static this() { if (atomicOp!"+="(shared_static_ctor, 1) != 1) assert(0); } shared static ~this() { if (atomicOp!"+="(shared_static_dtor, 1) != 1) assert(0); } static this() { atomicOp!"+="(static_ctor, 1); } static ~this() { atomicOp!"+="(static_dtor, 1); } extern(C) int runTests() { try runTestsImpl(); catch (Throwable) return 0; return 1; } void runTestsImpl() { import core.memory, core.thread; bool passed; try throwException(); catch (Exception e) passed = true; assert(passed); assert(collectException({throwException();}) !is null); alloc(); tls_alloc(); access(); tls_access(); GC.collect(); tls_access(); access(); tls_free(); free(); assert(shared_static_ctor == 1); assert(static_ctor == 1); static void run() { assert(static_ctor == 2); assert(shared_static_ctor == 1); } auto thr = new Thread(&run); thr.start(); thr.join(); assert(static_dtor == 1); passed = false; foreach (m; ModuleInfo) if (m.name == "lib") passed = true; assert(passed); } // Provide a way to initialize D from C programs that are D agnostic. import core.runtime : rt_init, rt_term; extern(C) int lib_init() { return rt_init(); } extern(C) int lib_term() { return rt_term(); } shared size_t* _finalizeCounter; class MyFinalizer { ~this() { import core.atomic; atomicOp!"+="(*_finalizeCounter, 1); } } class MyFinalizerBig : MyFinalizer { ubyte[4096] _big = void; } extern(C) void setFinalizeCounter(shared(size_t)* p) { _finalizeCounter = p; } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/liblinkdep.d0000664000175000017500000000010412776214756022754 0ustar kaikaiimport lib; extern(C) int runDepTests() { return runTests(); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/load_13414.d0000664000175000017500000000140112776214756022313 0ustar kaikaiimport core.runtime, core.atomic, core.sys.posix.dlfcn; shared uint tlsDtor, dtor; void staticDtorHook() { atomicOp!"+="(tlsDtor, 1); } void sharedStaticDtorHook() { atomicOp!"+="(dtor, 1); } void runTest(string name) { auto h = Runtime.loadLibrary(name); assert(h !is null); *cast(void function()*).dlsym(h, "_D9lib_1341414staticDtorHookOPFZv") = &staticDtorHook; *cast(void function()*).dlsym(h, "_D9lib_1341420sharedStaticDtorHookOPFZv") = &sharedStaticDtorHook; Runtime.unloadLibrary(h); assert(tlsDtor == 1); assert(dtor == 1); } void main(string[] args) { auto name = args[0]; assert(name[$-"load_13414".length-1 .. $] == "/load_13414"); name = name[0 .. $-"load_13414".length] ~ "lib_13414.so"; runTest(name); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/load_linkdep.d0000664000175000017500000000065112776214756023273 0ustar kaikaiimport core.runtime, core.sys.posix.dlfcn; extern(C) alias RunDepTests = int function(); void main(string[] args) { auto name = args[0]; assert(name[$-13 .. $] == "/load_linkdep"); name = name[0 .. $-12] ~ "liblinkdep.so"; auto h = Runtime.loadLibrary(name); assert(h); auto runDepTests = cast(RunDepTests)dlsym(h, "runDepTests"); assert(runDepTests()); assert(Runtime.unloadLibrary(h)); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/libloaddep.d0000664000175000017500000000054712776214756022751 0ustar kaikaiimport core.runtime, core.sys.posix.dlfcn; extern(C) alias RunTests = int function(); extern(C) int runDepTests(const char* name) { auto h = rt_loadLibrary(name); if (h is null) return false; auto runTests = cast(RunTests).dlsym(h, "runTests"); assert(runTests !is null); if (!runTests()) return false; return rt_unloadLibrary(h); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/link.d0000664000175000017500000000271512776214756021606 0ustar kaikaiimport lib; void testEH() { bool passed; try lib.throwException(); catch (Exception e) passed = true; assert(passed); passed = false; assert(lib.collectException({throw new Exception(null);}) !is null); assert(lib.collectException({lib.throwException();}) !is null); } void testGC() { import core.memory; lib.alloc(); lib.tls_alloc(); lib.access(); lib.tls_access(); GC.collect(); lib.tls_access(); lib.access(); lib.tls_free(); lib.free(); } import core.atomic : atomicOp; shared static this() { assert(lib.shared_static_ctor == 1); } shared static ~this() { assert(lib.shared_static_dtor == 0); } shared uint static_ctor, static_dtor; static this() { assert(lib.static_ctor == atomicOp!"+="(static_ctor, 1)); } static ~this() { assert(lib.static_dtor + 1 == atomicOp!"+="(static_dtor, 1)); } void testInit() { import core.thread; assert(lib.static_ctor == 1); assert(lib.static_dtor == 0); static void foo() { assert(lib.shared_static_ctor == 1); assert(lib.shared_static_dtor == 0); assert(lib.static_ctor == 2); assert(lib.static_dtor == 0); } auto thr = new Thread(&foo); thr.start(); assert(thr.join() is null); assert(lib.shared_static_ctor == 1); assert(lib.shared_static_dtor == 0); assert(lib.static_ctor == 2); assert(lib.static_dtor == 1); } void main() { testEH(); testGC(); testInit(); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/loadDR.c0000664000175000017500000000201012776214756022001 0ustar kaikai#include #include #include #include int main(int argc, char* argv[]) { if (argc != 2) return EXIT_FAILURE; void *h = dlopen(argv[1], RTLD_LAZY); // load druntime assert(h != NULL); int (*rt_init)(void) = dlsym(h, "rt_init"); int (*rt_term)(void) = dlsym(h, "rt_term"); void* (*rt_loadLibrary)(const char*) = dlsym(h, "rt_loadLibrary"); int (*rt_unloadLibrary)(void*) = dlsym(h, "rt_unloadLibrary"); int res = EXIT_FAILURE; if (!rt_init()) goto Lexit; const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1; char *name = malloc(pathlen + sizeof("lib.so")); memcpy(name, argv[0], pathlen); memcpy(name+pathlen, "lib.so", sizeof("lib.so")); void *dlib = rt_loadLibrary(name); free(name); assert(dlib); int (*runTests)(void) = dlsym(dlib, "runTests"); assert(runTests()); assert(rt_unloadLibrary(dlib)); if (rt_term()) res = EXIT_SUCCESS; Lexit: assert(dlclose(h) == 0); return res; } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/lib_13414.d0000664000175000017500000000025312776214756022146 0ustar kaikaishared void function() sharedStaticDtorHook; shared void function() staticDtorHook; shared static ~this() { sharedStaticDtorHook(); } static ~this() { staticDtorHook(); } ldc-1.1.0-beta3-src/runtime/druntime/test/shared/src/linkD.c0000664000175000017500000000050212776214756021701 0ustar kaikai#include #include extern int runTests(void); extern int lib_init(void); extern int lib_term(void); int main(int argc, char* argv[]) { if (!lib_init()) return EXIT_SUCCESS; const int res = runTests() ? EXIT_SUCCESS : EXIT_FAILURE; if (!lib_term()) return EXIT_FAILURE; return res; } ldc-1.1.0-beta3-src/runtime/druntime/test/profile/0000775000175000017500000000000012776214756020102 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/profile/bothgc.log.exp0000664000175000017500000000017012776214756022644 0ustar kaikaibytes allocated, allocations, type, function, file:line 4000 1000 both.Num both.foo src/both.d:15 ldc-1.1.0-beta3-src/runtime/druntime/test/profile/myprofilegc.log.exp0000664000175000017500000000016612776214756023723 0ustar kaikaibytes allocated, allocations, type, function, file:line 4 1 uint D main src/profilegc.d:6 ldc-1.1.0-beta3-src/runtime/druntime/test/profile/Makefile0000664000175000017500000000263212776214756021545 0ustar kaikaiinclude ../common.mak TESTS:=profile profilegc both DIFF:=diff GREP:=grep .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) $(ROOT)/profile.done: DFLAGS+=-profile $(ROOT)/profile.done: $(ROOT)/%.done: $(ROOT)/% @echo Testing $* @rm -f $(ROOT)/mytrace.log $(ROOT)/mytrace.def $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(ROOT)/mytrace.log $(ROOT)/mytrace.def $(QUIET)$(GREP) -q '1 .*_Dmain' $(ROOT)/mytrace.log $(QUIET)$(GREP) -q '1000 .*uint profile.foo(uint)' $(ROOT)/mytrace.log $(QUIET)$(DIFF) mytrace.def.exp $(ROOT)/mytrace.def @touch $@ $(ROOT)/profilegc.done: DFLAGS+=-profile=gc $(ROOT)/profilegc.done: $(ROOT)/%.done: $(ROOT)/% @echo Testing $* @rm -f $(ROOT)/myprofilegc.log $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(ROOT)/myprofilegc.log $(QUIET)$(DIFF) myprofilegc.log.exp $(ROOT)/myprofilegc.log @touch $@ $(ROOT)/both.done: DFLAGS+=-profile -profile=gc $(ROOT)/both.done: $(ROOT)/%.done: $(ROOT)/% @echo Testing $* @rm -f $(ROOT)/both.log $(ROOT)/both.def $(ROOT)/bothgc.log $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(ROOT)/both.log $(ROOT)/both.def $(ROOT)/bothgc.log $(QUIET)$(GREP) -q '1 .*_Dmain' $(ROOT)/both.log $(QUIET)$(GREP) -q '1000 .*both.Num\* both.foo(uint)' $(ROOT)/both.log $(QUIET)$(DIFF) both.def.exp $(ROOT)/both.def $(QUIET)$(DIFF) bothgc.log.exp $(ROOT)/bothgc.log @touch $@ $(ROOT)/%: $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$(ROOT)/$* $< clean: rm -rf $(GENERATED) *.log *.def ldc-1.1.0-beta3-src/runtime/druntime/test/profile/src/0000775000175000017500000000000012776214756020671 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/profile/src/both.d0000664000175000017500000000064412776214756021776 0ustar kaikaiimport core.runtime; struct Num { pragma(inline, false) this(uint val) { this.val = val; } uint val; } pragma(inline, false) Num* foo(uint val) { return new Num(val); } __gshared uint sum; void main(string[] args) { trace_setlogfilename(args[1]); trace_setdeffilename(args[2]); profilegc_setlogfilename(args[3]); foreach (uint i; 0 .. 1_000) sum += foo(i).val; } ldc-1.1.0-beta3-src/runtime/druntime/test/profile/src/profile.d0000664000175000017500000000041012776214756022471 0ustar kaikaiimport core.runtime; pragma(inline, false) uint foo(uint val) { return val * 2; } __gshared uint sum; void main(string[] args) { trace_setlogfilename(args[1]); trace_setdeffilename(args[2]); foreach (uint i; 0 .. 1_000) sum += foo(i); } ldc-1.1.0-beta3-src/runtime/druntime/test/profile/src/profilegc.d0000664000175000017500000000016112776214756023006 0ustar kaikaiimport core.runtime; void main(string[] args) { profilegc_setlogfilename(args[1]); auto p = new uint; } ldc-1.1.0-beta3-src/runtime/druntime/test/profile/mytrace.def.exp0000664000175000017500000000004712776214756023022 0ustar kaikai FUNCTIONS _Dmain _D7profile3fooFkZk ldc-1.1.0-beta3-src/runtime/druntime/test/profile/both.def.exp0000664000175000017500000000012212776214756022304 0ustar kaikai FUNCTIONS _Dmain _D4both3fooFkZPS4both3Num _D4both3Num6__ctorMFNckZS4both3Num ldc-1.1.0-beta3-src/runtime/druntime/test/common.mak0000664000175000017500000000112412776214756020422 0ustar kaikai# set from top makefile OS:= MODEL:= BUILD:= DMD:= DRUNTIME:= DRUNTIMESO:= LINKDL:= QUIET:= TIMELIMIT:= LDL:=$(subst -L,,$(LINKDL)) # -ldl SRC:=src GENERATED:=./generated ROOT:=$(GENERATED)/$(OS)/$(BUILD)/$(MODEL) ifneq (default,$(MODEL)) MODEL_FLAG:=-m$(MODEL) endif CFLAGS:=$(MODEL_FLAG) -Wall DFLAGS:=$(MODEL_FLAG) -w -I../../src -I../../import -I$(SRC) -defaultlib= -debuglib= # LINK_SHARED may be set by importing makefile DFLAGS+=$(if $(LINK_SHARED),-L$(DRUNTIMESO),-L$(DRUNTIME)) ifeq ($(BUILD),debug) DFLAGS += -g -debug CFLAGS += -g else DFLAGS += -O -release CFLAGS += -O3 endif ldc-1.1.0-beta3-src/runtime/druntime/test/exceptions/0000775000175000017500000000000012776214756020623 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/exceptions/line_trace.exp0000664000175000017500000000122012776214756023441 0ustar kaikaiobject.Exception@src/line_trace.d(17): exception ---------------- src/line_trace.d:17 void line_trace.f1() [ADDR] src/line_trace.d:5 _Dmain [ADDR] src/rt/dmain2.d:472 _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv [ADDR] src/rt/dmain2.d:447 void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [ADDR] src/rt/dmain2.d:472 void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll() [ADDR] src/rt/dmain2.d:447 void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [ADDR] src/rt/dmain2.d:480 _d_run_main [ADDR] ldc-1.1.0-beta3-src/runtime/druntime/test/exceptions/Makefile0000664000175000017500000000214612776214756022266 0ustar kaikaiinclude ../common.mak TESTS:=stderr_msg unittest_assert invalid_memory_operation ifeq ($(OS)-$(BUILD),linux-debug) TESTS:=$(TESTS) line_trace endif ifeq ($(OS)-$(BUILD),freebsd-debug) TESTS:=$(TESTS) line_trace endif DIFF:=diff SED:=sed .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) $(ROOT)/line_trace.done: $(ROOT)/line_trace @echo Testing line_trace $(QUIET)$(TIMELIMIT)$(ROOT)/line_trace $(RUN_ARGS) > $(ROOT)/line_trace.output $(QUIET)$(SED) "s/\[0x[0-9a-f]*\]/\[ADDR\]/g" $(ROOT)/line_trace.output | $(DIFF) line_trace.exp - @rm -f $(ROOT)/line_trace.output @touch $@ $(ROOT)/stderr_msg.done: STDERR_EXP="stderr_msg msg" $(ROOT)/unittest_assert.done: STDERR_EXP="unittest_assert msg" $(ROOT)/invalid_memory_operation.done: STDERR_EXP="InvalidMemoryOperationError" $(ROOT)/%.done: $(ROOT)/% @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) 2>&1 1>/dev/null | grep -qF $(STDERR_EXP) @touch $@ $(ROOT)/unittest_assert: DFLAGS+=-unittest $(ROOT)/line_trace: DFLAGS+=-L--export-dynamic $(ROOT)/%: $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: rm -rf $(GENERATED) ldc-1.1.0-beta3-src/runtime/druntime/test/exceptions/src/0000775000175000017500000000000012776214756021412 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/test/exceptions/src/stderr_msg.d0000664000175000017500000000007312776214756023730 0ustar kaikaivoid main() { throw new Exception("stderr_msg msg"); } ldc-1.1.0-beta3-src/runtime/druntime/test/exceptions/src/unittest_assert.d0000664000175000017500000000010412776214756025012 0ustar kaikaiunittest { assert(0, "unittest_assert msg"); } void main() { } ldc-1.1.0-beta3-src/runtime/druntime/test/exceptions/src/invalid_memory_operation.d0000664000175000017500000000012212776214756026650 0ustar kaikaistruct S { ~this() { new int; } } void main() { new S; } ldc-1.1.0-beta3-src/runtime/druntime/test/exceptions/src/line_trace.d0000664000175000017500000000037312776214756023667 0ustar kaikaivoid main() { try { f1(); } catch (Exception e) { import core.stdc.stdio; auto str = e.toString(); printf("%.*s\n", str.length, str.ptr); } } void f1() { throw new Exception("exception"); } ldc-1.1.0-beta3-src/runtime/druntime/def/0000775000175000017500000000000012776214756016221 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/def/winspool.def0000664000175000017500000001655612776214756020570 0ustar kaikaiLIBRARY winspool EXETYPE NT SUBSYSTEM WINDOWS EXPORTS _AbortPrinter@4 = AbortPrinter _AddFormA@12 = AddFormA _AddFormW@12 = AddFormW _AddJobA@20 = AddJobA _AddJobW@20 = AddJobW _AddMonitorA@12 = AddMonitorA _AddMonitorW@12 = AddMonitorW _AddPerMachineConnectionA@16 = AddPerMachineConnectionA _AddPerMachineConnectionW@16 = AddPerMachineConnectionW _AddPortA@12 = AddPortA _AddPortExA@16 = AddPortExA _AddPortExW@16 = AddPortExW _AddPortW@12 = AddPortW _AddPrintProcessorA@16 = AddPrintProcessorA _AddPrintProcessorW@16 = AddPrintProcessorW _AddPrintProvidorA@12 = AddPrintProvidorA _AddPrintProvidorW@12 = AddPrintProvidorW _AddPrinterA@12 = AddPrinterA _AddPrinterConnectionA@4 = AddPrinterConnectionA _AddPrinterConnectionUI@12 = AddPrinterConnectionUI _AddPrinterConnectionW@4 = AddPrinterConnectionW _AddPrinterDriverA@12 = AddPrinterDriverA _AddPrinterDriverExA@16 = AddPrinterDriverExA _AddPrinterDriverExW@16 = AddPrinterDriverExW _AddPrinterDriverW@12 = AddPrinterDriverW _AddPrinterW@12 = AddPrinterW _AdvancedDocumentPropertiesA@20 = AdvancedDocumentPropertiesA _AdvancedDocumentPropertiesW@20 = AdvancedDocumentPropertiesW _AdvancedSetupDialog@16 = AdvancedSetupDialog _ClosePrinter@4 = ClosePrinter _CloseSpoolFileHandle@8 = CloseSpoolFileHandle _ClusterSplClose@4 = ClusterSplClose _ClusterSplIsAlive@4 = ClusterSplIsAlive _ClusterSplOpen@20 = ClusterSplOpen _CommitSpoolData@12 = CommitSpoolData _ConfigurePortA@12 = ConfigurePortA _ConfigurePortW@12 = ConfigurePortW _ConnectToPrinterDlg@8 = ConnectToPrinterDlg _ConvertAnsiDevModeToUnicodeDevmode@16 = ConvertAnsiDevModeToUnicodeDevmode _ConvertUnicodeDevModeToAnsiDevmode@16 = ConvertUnicodeDevModeToAnsiDevmode _CreatePrinterIC@8 = CreatePrinterIC _DeleteFormA@8 = DeleteFormA _DeleteFormW@8 = DeleteFormW _DeleteMonitorA@12 = DeleteMonitorA _DeleteMonitorW@12 = DeleteMonitorW _DeletePerMachineConnectionA@8 = DeletePerMachineConnectionA _DeletePerMachineConnectionW@8 = DeletePerMachineConnectionW _DeletePortA@12 = DeletePortA _DeletePortW@12 = DeletePortW _DeletePrintProcessorA@12 = DeletePrintProcessorA _DeletePrintProcessorW@12 = DeletePrintProcessorW _DeletePrintProvidorA@12 = DeletePrintProvidorA _DeletePrintProvidorW@12 = DeletePrintProvidorW _DeletePrinter@4 = DeletePrinter _DeletePrinterConnectionA@4 = DeletePrinterConnectionA _DeletePrinterConnectionW@4 = DeletePrinterConnectionW _DeletePrinterDataA@8 = DeletePrinterDataA _DeletePrinterDataExA@12 = DeletePrinterDataExA _DeletePrinterDataExW@12 = DeletePrinterDataExW _DeletePrinterDataW@8 = DeletePrinterDataW _DeletePrinterDriverA@12 = DeletePrinterDriverA _DeletePrinterDriverExA@20 = DeletePrinterDriverExA _DeletePrinterDriverExW@20 = DeletePrinterDriverExW _DeletePrinterDriverW@12 = DeletePrinterDriverW _DeletePrinterIC@4 = DeletePrinterIC _DeletePrinterKeyA@8 = DeletePrinterKeyA _DeletePrinterKeyW@8 = DeletePrinterKeyW _DevQueryPrint@12 = DevQueryPrint _DevQueryPrintEx@4 = DevQueryPrintEx _DeviceCapabilities@20 = DeviceCapabilities _DeviceCapabilitiesA@20 = DeviceCapabilitiesA _DeviceCapabilitiesW@20 = DeviceCapabilitiesW _DeviceMode@16 = DeviceMode _DevicePropertySheets@8 = DevicePropertySheets _DocumentEvent@28 = DocumentEvent _DocumentPropertiesA@24 = DocumentPropertiesA _DocumentPropertiesW@24 = DocumentPropertiesW _DocumentPropertySheets@8 = DocumentPropertySheets _EndDocPrinter@4 = EndDocPrinter _EndPagePrinter@4 = EndPagePrinter _EnumFormsA@24 = EnumFormsA _EnumFormsW@24 = EnumFormsW _EnumJobsA@32 = EnumJobsA _EnumJobsW@32 = EnumJobsW _EnumMonitorsA@24 = EnumMonitorsA _EnumMonitorsW@24 = EnumMonitorsW _EnumPerMachineConnectionsA@20 = EnumPerMachineConnectionsA _EnumPerMachineConnectionsW@20 = EnumPerMachineConnectionsW _EnumPortsA@24 = EnumPortsA _EnumPortsW@24 = EnumPortsW _EnumPrintProcessorDatatypesA@28 = EnumPrintProcessorDatatypesA _EnumPrintProcessorDatatypesW@28 = EnumPrintProcessorDatatypesW _EnumPrintProcessorsA@28 = EnumPrintProcessorsA _EnumPrintProcessorsW@28 = EnumPrintProcessorsW _EnumPrinterDataA@36 = EnumPrinterDataA _EnumPrinterDataExA@24 = EnumPrinterDataExA _EnumPrinterDataExW@24 = EnumPrinterDataExW _EnumPrinterDataW@36 = EnumPrinterDataW _EnumPrinterDriversA@28 = EnumPrinterDriversA _EnumPrinterDriversW@28 = EnumPrinterDriversW _EnumPrinterKeyA@20 = EnumPrinterKeyA _EnumPrinterKeyW@20 = EnumPrinterKeyW _EnumPrinterPropertySheets@16 = EnumPrinterPropertySheets _EnumPrintersA@28 = EnumPrintersA _EnumPrintersW@28 = EnumPrintersW _ExtDeviceMode@32 = ExtDeviceMode _FindClosePrinterChangeNotification@4 = FindClosePrinterChangeNotification _FindFirstPrinterChangeNotification@16 = FindFirstPrinterChangeNotification _FindNextPrinterChangeNotification@16 = FindNextPrinterChangeNotification _ForceUnloadDriver@4 = ForceUnloadDriver _FreePrinterNotifyInfo@4 = FreePrinterNotifyInfo _GetDefaultPrinterA@8 = GetDefaultPrinterA _GetDefaultPrinterW@8 = GetDefaultPrinterW _GetFormA@24 = GetFormA _GetFormW@24 = GetFormW _GetJobA@24 = GetJobA _GetJobW@24 = GetJobW _GetPrintProcessorDirectoryA@24 = GetPrintProcessorDirectoryA _GetPrintProcessorDirectoryW@24 = GetPrintProcessorDirectoryW _GetPrinterA@20 = GetPrinterA _GetPrinterDataA@24 = GetPrinterDataA _GetPrinterDataExA@28 = GetPrinterDataExA _GetPrinterDataExW@28 = GetPrinterDataExW _GetPrinterDataW@24 = GetPrinterDataW _GetPrinterDriverA@24 = GetPrinterDriverA _GetPrinterDriverDirectoryA@24 = GetPrinterDriverDirectoryA _GetPrinterDriverDirectoryW@24 = GetPrinterDriverDirectoryW _GetPrinterDriverW@24 = GetPrinterDriverW _GetPrinterHTMLViewA@20 = GetPrinterHTMLViewA _GetPrinterHTMLViewW@20 = GetPrinterHTMLViewW _GetPrinterW@20 = GetPrinterW _GetPrinterWebInformation@16 = GetPrinterWebInformation _GetSpoolFileHandle@4 = GetSpoolFileHandle _InitializeDll@12 = InitializeDll _LoadPrinterDriver@4 = LoadPrinterDriver _OpenPrinterA@12 = OpenPrinterA _OpenPrinterW@12 = OpenPrinterW _PlayGdiScriptOnPrinterIC@24 = PlayGdiScriptOnPrinterIC _PrinterMessageBoxA@24 = PrinterMessageBoxA _PrinterMessageBoxW@24 = PrinterMessageBoxW _PrinterProperties@8 = PrinterProperties _PublishPrinterA@24 = PublishPrinterA _PublishPrinterW@24 = PublishPrinterW _QueryColorProfile@24 = QueryColorProfile _QueryRemoteFonts@12 = QueryRemoteFonts _QuerySpoolMode@12 = QuerySpoolMode _ReadPrinter@16 = ReadPrinter _RefCntLoadDriver@16 = RefCntLoadDriver _RefCntUnloadDriver@8 = RefCntUnloadDriver _ResetPrinterA@8 = ResetPrinterA _ResetPrinterW@8 = ResetPrinterW _ScheduleJob@8 = ScheduleJob _SeekPrinter@24 = SeekPrinter _SetAllocFailCount@20 = SetAllocFailCount _SetDefaultPrinterA@4 = SetDefaultPrinterA _SetDefaultPrinterW@4 = SetDefaultPrinterW _SetFormA@16 = SetFormA _SetFormW@16 = SetFormW _SetJobA@20 = SetJobA _SetJobW@20 = SetJobW _SetPortA@16 = SetPortA _SetPortW@16 = SetPortW _SetPrinterA@16 = SetPrinterA _SetPrinterDataA@20 = SetPrinterDataA _SetPrinterDataExA@24 = SetPrinterDataExA _SetPrinterDataExW@24 = SetPrinterDataExW _SetPrinterDataW@20 = SetPrinterDataW _SetPrinterHTMLViewA@12 = SetPrinterHTMLViewA _SetPrinterHTMLViewW@12 = SetPrinterHTMLViewW _SetPrinterW@16 = SetPrinterW _SplDriverUnloadComplete@4 = SplDriverUnloadComplete _SplReadPrinter@12 = SplReadPrinter _SpoolerDevQueryPrintW@20 = SpoolerDevQueryPrintW _SpoolerInit@0 = SpoolerInit _SpoolerPrinterEvent@16 = SpoolerPrinterEvent _StartDocDlgA@8 = StartDocDlgA _StartDocDlgW@8 = StartDocDlgW _StartDocPrinterA@12 = StartDocPrinterA _StartDocPrinterW@12 = StartDocPrinterW _StartPagePrinter@4 = StartPagePrinter _WaitForPrinterChange@8 = WaitForPrinterChange _WritePrinter@16 = WritePrinter _XcvDataW@32 = XcvDataW ldc-1.1.0-beta3-src/runtime/druntime/def/opengl32.def0000664000175000017500000010043312776214756020333 0ustar kaikaiLIBRARY OPENGL32 EXETYPE NT SUBSYSTEM WINDOWS EXPORTS ; _GlmfBeginGlsBlock@4 = GlmfBeginGlsBlock GlmfBeginGlsBlock ; _GlmfCloseMetaFile@4 = GlmfCloseMetaFile GlmfCloseMetaFile ; _GlmfEndGlsBlock@4 = GlmfEndGlsBlock GlmfEndGlsBlock ; _GlmfEndPlayback@4 = GlmfEndPlayback GlmfEndPlayback ; _GlmfInitPlayback@12 = GlmfInitPlayback GlmfInitPlayback ; _GlmfPlayGlsRecord@16 = GlmfPlayGlsRecord GlmfPlayGlsRecord _glAccum@8 = glAccum ; glAccum _glAlphaFunc@8 = glAlphaFunc ; glAlphaFunc _glAreTexturesResident@12 = glAreTexturesResident ; glAreTexturesResident _glArrayElement@4 = glArrayElement ; glArrayElement _glBegin@4 = glBegin ; glBegin _glBindTexture@8 = glBindTexture ; glBindTexture _glBitmap@28 = glBitmap ; glBitmap _glBlendFunc@8 = glBlendFunc ; glBlendFunc _glCallList@4 = glCallList ; glCallList _glCallLists@12 = glCallLists ; glCallLists _glClear@4 = glClear ; glClear _glClearAccum@16 = glClearAccum ; glClearAccum _glClearColor@16 = glClearColor ; glClearColor _glClearDepth@8 = glClearDepth ; glClearDepth _glClearIndex@4 = glClearIndex ; glClearIndex _glClearStencil@4 = glClearStencil ; glClearStencil _glClipPlane@8 = glClipPlane ; glClipPlane _glColor3b@12 = glColor3b ; glColor3b _glColor3bv@4 = glColor3bv ; glColor3bv _glColor3d@24 = glColor3d ; glColor3d _glColor3dv@4 = glColor3dv ; glColor3dv _glColor3f@12 = glColor3f ; glColor3f _glColor3fv@4 = glColor3fv ; glColor3fv _glColor3i@12 = glColor3i ; glColor3i _glColor3iv@4 = glColor3iv ; glColor3iv _glColor3s@12 = glColor3s ; glColor3s _glColor3sv@4 = glColor3sv ; glColor3sv _glColor3ub@12 = glColor3ub ; glColor3ub _glColor3ubv@4 = glColor3ubv ; glColor3ubv _glColor3ui@12 = glColor3ui ; glColor3ui _glColor3uiv@4 = glColor3uiv ; glColor3uiv _glColor3us@12 = glColor3us ; glColor3us _glColor3usv@4 = glColor3usv ; glColor3usv _glColor4b@16 = glColor4b ; glColor4b _glColor4bv@4 = glColor4bv ; glColor4bv _glColor4d@32 = glColor4d ; glColor4d _glColor4dv@4 = glColor4dv ; glColor4dv _glColor4f@16 = glColor4f ; glColor4f _glColor4fv@4 = glColor4fv ; glColor4fv _glColor4i@16 = glColor4i ; glColor4i _glColor4iv@4 = glColor4iv ; glColor4iv _glColor4s@16 = glColor4s ; glColor4s _glColor4sv@4 = glColor4sv ; glColor4sv _glColor4ub@16 = glColor4ub ; glColor4ub _glColor4ubv@4 = glColor4ubv ; glColor4ubv _glColor4ui@16 = glColor4ui ; glColor4ui _glColor4uiv@4 = glColor4uiv ; glColor4uiv _glColor4us@16 = glColor4us ; glColor4us _glColor4usv@4 = glColor4usv ; glColor4usv _glColorMask@16 = glColorMask ; glColorMask _glColorMaterial@8 = glColorMaterial ; glColorMaterial _glColorPointer@16 = glColorPointer ; glColorPointer _glCopyPixels@20 = glCopyPixels ; glCopyPixels _glCopyTexImage1D@28 = glCopyTexImage1D ; glCopyTexImage1D _glCopyTexImage2D@32 = glCopyTexImage2D ; glCopyTexImage2D _glCopyTexSubImage1D@24 = glCopyTexSubImage1D ; glCopyTexSubImage1D _glCopyTexSubImage2D@32 = glCopyTexSubImage2D ; glCopyTexSubImage2D _glCullFace@4 = glCullFace ; glCullFace _glDebugEntry@8 = glDebugEntry ; glDebugEntry _glDeleteLists@8 = glDeleteLists ; glDeleteLists _glDeleteTextures@8 = glDeleteTextures ; glDeleteTextures _glDepthFunc@4 = glDepthFunc ; glDepthFunc _glDepthMask@4 = glDepthMask ; glDepthMask _glDepthRange@16 = glDepthRange ; glDepthRange _glDisable@4 = glDisable ; glDisable _glDisableClientState@4 = glDisableClientState ; glDisableClientState _glDrawArrays@12 = glDrawArrays ; glDrawArrays _glDrawBuffer@4 = glDrawBuffer ; glDrawBuffer _glDrawElements@16 = glDrawElements ; glDrawElements _glDrawPixels@20 = glDrawPixels ; glDrawPixels _glEdgeFlag@4 = glEdgeFlag ; glEdgeFlag _glEdgeFlagPointer@8 = glEdgeFlagPointer ; glEdgeFlagPointer _glEdgeFlagv@4 = glEdgeFlagv ; glEdgeFlagv _glEnable@4 = glEnable ; glEnable _glEnableClientState@4 = glEnableClientState ; glEnableClientState _glEnd@0 = glEnd ; glEnd _glEndList@0 = glEndList ; glEndList _glEvalCoord1d@8 = glEvalCoord1d ; glEvalCoord1d _glEvalCoord1dv@4 = glEvalCoord1dv ; glEvalCoord1dv _glEvalCoord1f@4 = glEvalCoord1f ; glEvalCoord1f _glEvalCoord1fv@4 = glEvalCoord1fv ; glEvalCoord1fv _glEvalCoord2d@16 = glEvalCoord2d ; glEvalCoord2d _glEvalCoord2dv@4 = glEvalCoord2dv ; glEvalCoord2dv _glEvalCoord2f@8 = glEvalCoord2f ; glEvalCoord2f _glEvalCoord2fv@4 = glEvalCoord2fv ; glEvalCoord2fv _glEvalMesh1@12 = glEvalMesh1 ; glEvalMesh1 _glEvalMesh2@20 = glEvalMesh2 ; glEvalMesh2 _glEvalPoint1@4 = glEvalPoint1 ; glEvalPoint1 _glEvalPoint2@8 = glEvalPoint2 ; glEvalPoint2 _glFeedbackBuffer@12 = glFeedbackBuffer ; glFeedbackBuffer _glFinish@0 = glFinish ; glFinish _glFlush@0 = glFlush ; glFlush _glFogf@8 = glFogf ; glFogf _glFogfv@8 = glFogfv ; glFogfv _glFogi@8 = glFogi ; glFogi _glFogiv@8 = glFogiv ; glFogiv _glFrontFace@4 = glFrontFace ; glFrontFace _glFrustum@48 = glFrustum ; glFrustum _glGenLists@4 = glGenLists ; glGenLists _glGenTextures@8 = glGenTextures ; glGenTextures _glGetBooleanv@8 = glGetBooleanv ; glGetBooleanv _glGetClipPlane@8 = glGetClipPlane ; glGetClipPlane _glGetDoublev@8 = glGetDoublev ; glGetDoublev _glGetError@0 = glGetError ; glGetError _glGetFloatv@8 = glGetFloatv ; glGetFloatv _glGetIntegerv@8 = glGetIntegerv ; glGetIntegerv _glGetLightfv@12 = glGetLightfv ; glGetLightfv _glGetLightiv@12 = glGetLightiv ; glGetLightiv _glGetMapdv@12 = glGetMapdv ; glGetMapdv _glGetMapfv@12 = glGetMapfv ; glGetMapfv _glGetMapiv@12 = glGetMapiv ; glGetMapiv _glGetMaterialfv@12 = glGetMaterialfv ; glGetMaterialfv _glGetMaterialiv@12 = glGetMaterialiv ; glGetMaterialiv _glGetPixelMapfv@8 = glGetPixelMapfv ; glGetPixelMapfv _glGetPixelMapuiv@8 = glGetPixelMapuiv ; glGetPixelMapuiv _glGetPixelMapusv@8 = glGetPixelMapusv ; glGetPixelMapusv _glGetPointerv@8 = glGetPointerv ; glGetPointerv _glGetPolygonStipple@4 = glGetPolygonStipple ; glGetPolygonStipple _glGetString@4 = glGetString ; glGetString _glGetTexEnvfv@12 = glGetTexEnvfv ; glGetTexEnvfv _glGetTexEnviv@12 = glGetTexEnviv ; glGetTexEnviv _glGetTexGendv@12 = glGetTexGendv ; glGetTexGendv _glGetTexGenfv@12 = glGetTexGenfv ; glGetTexGenfv _glGetTexGeniv@12 = glGetTexGeniv ; glGetTexGeniv _glGetTexImage@20 = glGetTexImage ; glGetTexImage _glGetTexLevelParameterfv@16 = glGetTexLevelParameterfv ; glGetTexLevelParameterfv _glGetTexLevelParameteriv@16 = glGetTexLevelParameteriv ; glGetTexLevelParameteriv _glGetTexParameterfv@12 = glGetTexParameterfv ; glGetTexParameterfv _glGetTexParameteriv@12 = glGetTexParameteriv ; glGetTexParameteriv _glHint@8 = glHint ; glHint _glIndexMask@4 = glIndexMask ; glIndexMask _glIndexPointer@12 = glIndexPointer ; glIndexPointer _glIndexd@8 = glIndexd ; glIndexd _glIndexdv@4 = glIndexdv ; glIndexdv _glIndexf@4 = glIndexf ; glIndexf _glIndexfv@4 = glIndexfv ; glIndexfv _glIndexi@4 = glIndexi ; glIndexi _glIndexiv@4 = glIndexiv ; glIndexiv _glIndexs@4 = glIndexs ; glIndexs _glIndexsv@4 = glIndexsv ; glIndexsv _glIndexub@4 = glIndexub ; glIndexub _glIndexubv@4 = glIndexubv ; glIndexubv _glInitNames@0 = glInitNames ; glInitNames _glInterleavedArrays@12 = glInterleavedArrays ; glInterleavedArrays _glIsEnabled@4 = glIsEnabled ; glIsEnabled _glIsList@4 = glIsList ; glIsList _glIsTexture@4 = glIsTexture ; glIsTexture _glLightModelf@8 = glLightModelf ; glLightModelf _glLightModelfv@8 = glLightModelfv ; glLightModelfv _glLightModeli@8 = glLightModeli ; glLightModeli _glLightModeliv@8 = glLightModeliv ; glLightModeliv _glLightf@12 = glLightf ; glLightf _glLightfv@12 = glLightfv ; glLightfv _glLighti@12 = glLighti ; glLighti _glLightiv@12 = glLightiv ; glLightiv _glLineStipple@8 = glLineStipple ; glLineStipple _glLineWidth@4 = glLineWidth ; glLineWidth _glListBase@4 = glListBase ; glListBase _glLoadIdentity@0 = glLoadIdentity ; glLoadIdentity _glLoadMatrixd@4 = glLoadMatrixd ; glLoadMatrixd _glLoadMatrixf@4 = glLoadMatrixf ; glLoadMatrixf _glLoadName@4 = glLoadName ; glLoadName _glLogicOp@4 = glLogicOp ; glLogicOp _glMap1d@32 = glMap1d ; glMap1d _glMap1f@24 = glMap1f ; glMap1f _glMap2d@56 = glMap2d ; glMap2d _glMap2f@40 = glMap2f ; glMap2f _glMapGrid1d@20 = glMapGrid1d ; glMapGrid1d _glMapGrid1f@12 = glMapGrid1f ; glMapGrid1f _glMapGrid2d@40 = glMapGrid2d ; glMapGrid2d _glMapGrid2f@24 = glMapGrid2f ; glMapGrid2f _glMaterialf@12 = glMaterialf ; glMaterialf _glMaterialfv@12 = glMaterialfv ; glMaterialfv _glMateriali@12 = glMateriali ; glMateriali _glMaterialiv@12 = glMaterialiv ; glMaterialiv _glMatrixMode@4 = glMatrixMode ; glMatrixMode _glMultMatrixd@4 = glMultMatrixd ; glMultMatrixd _glMultMatrixf@4 = glMultMatrixf ; glMultMatrixf _glNewList@8 = glNewList ; glNewList _glNormal3b@12 = glNormal3b ; glNormal3b _glNormal3bv@4 = glNormal3bv ; glNormal3bv _glNormal3d@24 = glNormal3d ; glNormal3d _glNormal3dv@4 = glNormal3dv ; glNormal3dv _glNormal3f@12 = glNormal3f ; glNormal3f _glNormal3fv@4 = glNormal3fv ; glNormal3fv _glNormal3i@12 = glNormal3i ; glNormal3i _glNormal3iv@4 = glNormal3iv ; glNormal3iv _glNormal3s@12 = glNormal3s ; glNormal3s _glNormal3sv@4 = glNormal3sv ; glNormal3sv _glNormalPointer@12 = glNormalPointer ; glNormalPointer _glOrtho@48 = glOrtho ; glOrtho _glPassThrough@4 = glPassThrough ; glPassThrough _glPixelMapfv@12 = glPixelMapfv ; glPixelMapfv _glPixelMapuiv@12 = glPixelMapuiv ; glPixelMapuiv _glPixelMapusv@12 = glPixelMapusv ; glPixelMapusv _glPixelStoref@8 = glPixelStoref ; glPixelStoref _glPixelStorei@8 = glPixelStorei ; glPixelStorei _glPixelTransferf@8 = glPixelTransferf ; glPixelTransferf _glPixelTransferi@8 = glPixelTransferi ; glPixelTransferi _glPixelZoom@8 = glPixelZoom ; glPixelZoom _glPointSize@4 = glPointSize ; glPointSize _glPolygonMode@8 = glPolygonMode ; glPolygonMode _glPolygonOffset@8 = glPolygonOffset ; glPolygonOffset _glPolygonStipple@4 = glPolygonStipple ; glPolygonStipple _glPopAttrib@0 = glPopAttrib ; glPopAttrib _glPopClientAttrib@0 = glPopClientAttrib ; glPopClientAttrib _glPopMatrix@0 = glPopMatrix ; glPopMatrix _glPopName@0 = glPopName ; glPopName _glPrioritizeTextures@12 = glPrioritizeTextures ; glPrioritizeTextures _glPushAttrib@4 = glPushAttrib ; glPushAttrib _glPushClientAttrib@4 = glPushClientAttrib ; glPushClientAttrib _glPushMatrix@0 = glPushMatrix ; glPushMatrix _glPushName@4 = glPushName ; glPushName _glRasterPos2d@16 = glRasterPos2d ; glRasterPos2d _glRasterPos2dv@4 = glRasterPos2dv ; glRasterPos2dv _glRasterPos2f@8 = glRasterPos2f ; glRasterPos2f _glRasterPos2fv@4 = glRasterPos2fv ; glRasterPos2fv _glRasterPos2i@8 = glRasterPos2i ; glRasterPos2i _glRasterPos2iv@4 = glRasterPos2iv ; glRasterPos2iv _glRasterPos2s@8 = glRasterPos2s ; glRasterPos2s _glRasterPos2sv@4 = glRasterPos2sv ; glRasterPos2sv _glRasterPos3d@24 = glRasterPos3d ; glRasterPos3d _glRasterPos3dv@4 = glRasterPos3dv ; glRasterPos3dv _glRasterPos3f@12 = glRasterPos3f ; glRasterPos3f _glRasterPos3fv@4 = glRasterPos3fv ; glRasterPos3fv _glRasterPos3i@12 = glRasterPos3i ; glRasterPos3i _glRasterPos3iv@4 = glRasterPos3iv ; glRasterPos3iv _glRasterPos3s@12 = glRasterPos3s ; glRasterPos3s _glRasterPos3sv@4 = glRasterPos3sv ; glRasterPos3sv _glRasterPos4d@32 = glRasterPos4d ; glRasterPos4d _glRasterPos4dv@4 = glRasterPos4dv ; glRasterPos4dv _glRasterPos4f@16 = glRasterPos4f ; glRasterPos4f _glRasterPos4fv@4 = glRasterPos4fv ; glRasterPos4fv _glRasterPos4i@16 = glRasterPos4i ; glRasterPos4i _glRasterPos4iv@4 = glRasterPos4iv ; glRasterPos4iv _glRasterPos4s@16 = glRasterPos4s ; glRasterPos4s _glRasterPos4sv@4 = glRasterPos4sv ; glRasterPos4sv _glReadBuffer@4 = glReadBuffer ; glReadBuffer _glReadPixels@28 = glReadPixels ; glReadPixels _glRectd@32 = glRectd ; glRectd _glRectdv@8 = glRectdv ; glRectdv _glRectf@16 = glRectf ; glRectf _glRectfv@8 = glRectfv ; glRectfv _glRecti@16 = glRecti ; glRecti _glRectiv@8 = glRectiv ; glRectiv _glRects@16 = glRects ; glRects _glRectsv@8 = glRectsv ; glRectsv _glRenderMode@4 = glRenderMode ; glRenderMode _glRotated@32 = glRotated ; glRotated _glRotatef@16 = glRotatef ; glRotatef _glScaled@24 = glScaled ; glScaled _glScalef@12 = glScalef ; glScalef _glScissor@16 = glScissor ; glScissor _glSelectBuffer@8 = glSelectBuffer ; glSelectBuffer _glShadeModel@4 = glShadeModel ; glShadeModel _glStencilFunc@12 = glStencilFunc ; glStencilFunc _glStencilMask@4 = glStencilMask ; glStencilMask _glStencilOp@12 = glStencilOp ; glStencilOp _glTexCoord1d@8 = glTexCoord1d ; glTexCoord1d _glTexCoord1dv@4 = glTexCoord1dv ; glTexCoord1dv _glTexCoord1f@4 = glTexCoord1f ; glTexCoord1f _glTexCoord1fv@4 = glTexCoord1fv ; glTexCoord1fv _glTexCoord1i@4 = glTexCoord1i ; glTexCoord1i _glTexCoord1iv@4 = glTexCoord1iv ; glTexCoord1iv _glTexCoord1s@4 = glTexCoord1s ; glTexCoord1s _glTexCoord1sv@4 = glTexCoord1sv ; glTexCoord1sv _glTexCoord2d@16 = glTexCoord2d ; glTexCoord2d _glTexCoord2dv@4 = glTexCoord2dv ; glTexCoord2dv _glTexCoord2f@8 = glTexCoord2f ; glTexCoord2f _glTexCoord2fv@4 = glTexCoord2fv ; glTexCoord2fv _glTexCoord2i@8 = glTexCoord2i ; glTexCoord2i _glTexCoord2iv@4 = glTexCoord2iv ; glTexCoord2iv _glTexCoord2s@8 = glTexCoord2s ; glTexCoord2s _glTexCoord2sv@4 = glTexCoord2sv ; glTexCoord2sv _glTexCoord3d@24 = glTexCoord3d ; glTexCoord3d _glTexCoord3dv@4 = glTexCoord3dv ; glTexCoord3dv _glTexCoord3f@12 = glTexCoord3f ; glTexCoord3f _glTexCoord3fv@4 = glTexCoord3fv ; glTexCoord3fv _glTexCoord3i@12 = glTexCoord3i ; glTexCoord3i _glTexCoord3iv@4 = glTexCoord3iv ; glTexCoord3iv _glTexCoord3s@12 = glTexCoord3s ; glTexCoord3s _glTexCoord3sv@4 = glTexCoord3sv ; glTexCoord3sv _glTexCoord4d@32 = glTexCoord4d ; glTexCoord4d _glTexCoord4dv@4 = glTexCoord4dv ; glTexCoord4dv _glTexCoord4f@16 = glTexCoord4f ; glTexCoord4f _glTexCoord4fv@4 = glTexCoord4fv ; glTexCoord4fv _glTexCoord4i@16 = glTexCoord4i ; glTexCoord4i _glTexCoord4iv@4 = glTexCoord4iv ; glTexCoord4iv _glTexCoord4s@16 = glTexCoord4s ; glTexCoord4s _glTexCoord4sv@4 = glTexCoord4sv ; glTexCoord4sv _glTexCoordPointer@16 = glTexCoordPointer ; glTexCoordPointer _glTexEnvf@12 = glTexEnvf ; glTexEnvf _glTexEnvfv@12 = glTexEnvfv ; glTexEnvfv _glTexEnvi@12 = glTexEnvi ; glTexEnvi _glTexEnviv@12 = glTexEnviv ; glTexEnviv _glTexGend@16 = glTexGend ; glTexGend _glTexGendv@12 = glTexGendv ; glTexGendv _glTexGenf@12 = glTexGenf ; glTexGenf _glTexGenfv@12 = glTexGenfv ; glTexGenfv _glTexGeni@12 = glTexGeni ; glTexGeni _glTexGeniv@12 = glTexGeniv ; glTexGeniv _glTexImage1D@32 = glTexImage1D ; glTexImage1D _glTexImage2D@36 = glTexImage2D ; glTexImage2D _glTexParameterf@12 = glTexParameterf ; glTexParameterf _glTexParameterfv@12 = glTexParameterfv ; glTexParameterfv _glTexParameteri@12 = glTexParameteri ; glTexParameteri _glTexParameteriv@12 = glTexParameteriv ; glTexParameteriv _glTexSubImage1D@28 = glTexSubImage1D ; glTexSubImage1D _glTexSubImage2D@36 = glTexSubImage2D ; glTexSubImage2D _glTranslated@24 = glTranslated ; glTranslated _glTranslatef@12 = glTranslatef ; glTranslatef _glVertex2d@16 = glVertex2d ; glVertex2d _glVertex2dv@4 = glVertex2dv ; glVertex2dv _glVertex2f@8 = glVertex2f ; glVertex2f _glVertex2fv@4 = glVertex2fv ; glVertex2fv _glVertex2i@8 = glVertex2i ; glVertex2i _glVertex2iv@4 = glVertex2iv ; glVertex2iv _glVertex2s@8 = glVertex2s ; glVertex2s _glVertex2sv@4 = glVertex2sv ; glVertex2sv _glVertex3d@24 = glVertex3d ; glVertex3d _glVertex3dv@4 = glVertex3dv ; glVertex3dv _glVertex3f@12 = glVertex3f ; glVertex3f _glVertex3fv@4 = glVertex3fv ; glVertex3fv _glVertex3i@12 = glVertex3i ; glVertex3i _glVertex3iv@4 = glVertex3iv ; glVertex3iv _glVertex3s@12 = glVertex3s ; glVertex3s _glVertex3sv@4 = glVertex3sv ; glVertex3sv _glVertex4d@32 = glVertex4d ; glVertex4d _glVertex4dv@4 = glVertex4dv ; glVertex4dv _glVertex4f@16 = glVertex4f ; glVertex4f _glVertex4fv@4 = glVertex4fv ; glVertex4fv _glVertex4i@16 = glVertex4i ; glVertex4i _glVertex4iv@4 = glVertex4iv ; glVertex4iv _glVertex4s@16 = glVertex4s ; glVertex4s _glVertex4sv@4 = glVertex4sv ; glVertex4sv _glVertexPointer@16 = glVertexPointer ; glVertexPointer _glViewport@16 = glViewport ; glViewport _wglChoosePixelFormat@8 = wglChoosePixelFormat ; wglChoosePixelFormat _wglCopyContext@12 = wglCopyContext ; wglCopyContext _wglCreateContext@4 = wglCreateContext ; wglCreateContext _wglCreateLayerContext@8 = wglCreateLayerContext ; wglCreateLayerContext _wglDeleteContext@4 = wglDeleteContext ; wglDeleteContext _wglDescribeLayerPlane@20 = wglDescribeLayerPlane ; wglDescribeLayerPlane _wglDescribePixelFormat@16 = wglDescribePixelFormat ; wglDescribePixelFormat _wglGetCurrentContext@0 = wglGetCurrentContext ; wglGetCurrentContext _wglGetCurrentDC@0 = wglGetCurrentDC ; wglGetCurrentDC _wglGetDefaultProcAddress@4 = wglGetDefaultProcAddress ; wglGetDefaultProcAddress _wglGetLayerPaletteEntries@20 = wglGetLayerPaletteEntries ; wglGetLayerPaletteEntries _wglGetPixelFormat@4 = wglGetPixelFormat ; wglGetPixelFormat _wglGetProcAddress@4 = wglGetProcAddress ; wglGetProcAddress _wglMakeCurrent@8 = wglMakeCurrent ; wglMakeCurrent _wglRealizeLayerPalette@12 = wglRealizeLayerPalette ; wglRealizeLayerPalette _wglSetLayerPaletteEntries@20 = wglSetLayerPaletteEntries ; wglSetLayerPaletteEntries _wglSetPixelFormat@12 = wglSetPixelFormat ; wglSetPixelFormat _wglShareLists@8 = wglShareLists ; wglShareLists _wglSwapBuffers@4 = wglSwapBuffers ; wglSwapBuffers _wglSwapLayerBuffers@8 = wglSwapLayerBuffers ; wglSwapLayerBuffers _wglSwapMultipleBuffers@8 = wglSwapMultipleBuffers ; wglSwapMultipleBuffers _wglUseFontBitmapsA@16 = wglUseFontBitmapsA ; wglUseFontBitmapsA _wglUseFontBitmapsW@16 = wglUseFontBitmapsW ; wglUseFontBitmapsW _wglUseFontOutlinesA@32 = wglUseFontOutlinesA ; wglUseFontOutlinesA _wglUseFontOutlinesW@32 = wglUseFontOutlinesW ; wglUseFontOutlinesW ldc-1.1.0-beta3-src/runtime/druntime/def/version.def0000664000175000017500000000103712776214756020367 0ustar kaikaiLIBRARY version EXETYPE NT SUBSYSTEM WINDOWS EXPORTS _GetFileVersionInfoA@16 = GetFileVersionInfoA _GetFileVersionInfoSizeA@8 = GetFileVersionInfoSizeA _GetFileVersionInfoSizeW@8 = GetFileVersionInfoSizeW _GetFileVersionInfoW@16 = GetFileVersionInfoW _VerFindFileA@32 = VerFindFileA _VerFindFileW@32 = VerFindFileW _VerInstallFileA@32 = VerInstallFileA _VerInstallFileW@32 = VerInstallFileW _VerLanguageNameA@12 = VerLanguageNameA _VerLanguageNameW@12 = VerLanguageNameW _VerQueryValueA@16 = VerQueryValueA _VerQueryValueW@16 = VerQueryValueW ldc-1.1.0-beta3-src/runtime/druntime/def/odbc32.def0000664000175000017500000001315312776214756017760 0ustar kaikaiLIBRARY odbc32 EXETYPE NT SUBSYSTEM WINDOWS EXPORTS _ConnectDlg@16 = ConnectDlg _PostError@20 = PostError _PostODBCError@16 = PostODBCError _SQLAllocConnect@8 = SQLAllocConnect _SQLAllocEnv@4 = SQLAllocEnv _SQLAllocHandle@12 = SQLAllocHandle _SQLAllocHandleStd@12 = SQLAllocHandleStd _SQLAllocStmt@8 = SQLAllocStmt _SQLBindCol@24 = SQLBindCol _SQLBindParam@32 = SQLBindParam _SQLBindParameter@40 = SQLBindParameter _SQLBrowseConnect@24 = SQLBrowseConnect _SQLBrowseConnectA@24 = SQLBrowseConnectA _SQLBrowseConnectW@24 = SQLBrowseConnectW _SQLBulkOperations@8 = SQLBulkOperations _SQLCancel@4 = SQLCancel _SQLCancelHandle@8 = SQLCancelHandle _SQLCloseCursor@4 = SQLCloseCursor _SQLColAttribute@28 = SQLColAttribute _SQLColAttributeA@28 = SQLColAttributeA _SQLColAttributeW@28 = SQLColAttributeW _SQLColAttributes@28 = SQLColAttributes _SQLColAttributesA@28 = SQLColAttributesA _SQLColAttributesW@28 = SQLColAttributesW _SQLColumnPrivileges@36 = SQLColumnPrivileges _SQLColumnPrivilegesA@36 = SQLColumnPrivilegesA _SQLColumnPrivilegesW@36 = SQLColumnPrivilegesW _SQLColumns@36 = SQLColumns _SQLColumnsA@36 = SQLColumnsA _SQLColumnsW@36 = SQLColumnsW _SQLConnect@28 = SQLConnect _SQLConnectA@28 = SQLConnectA _SQLConnectW@28 = SQLConnectW _SQLCopyDesc@8 = SQLCopyDesc _SQLDataSources@32 = SQLDataSources _SQLDataSourcesA@32 = SQLDataSourcesA _SQLDataSourcesW@32 = SQLDataSourcesW _SQLDescribeCol@36 = SQLDescribeCol _SQLDescribeColA@36 = SQLDescribeColA _SQLDescribeColW@36 = SQLDescribeColW _SQLDescribeParam@24 = SQLDescribeParam _SQLDisconnect@4 = SQLDisconnect _SQLDriverConnect@32 = SQLDriverConnect _SQLDriverConnectA@32 = SQLDriverConnectA _SQLDriverConnectW@32 = SQLDriverConnectW _SQLDrivers@32 = SQLDrivers _SQLDriversA@32 = SQLDriversA _SQLDriversW@32 = SQLDriversW _SQLEndTran@12 = SQLEndTran _SQLError@32 = SQLError _SQLErrorA@32 = SQLErrorA _SQLErrorW@32 = SQLErrorW _SQLExecDirect@12 = SQLExecDirect _SQLExecDirectA@12 = SQLExecDirectA _SQLExecDirectW@12 = SQLExecDirectW _SQLExecute@4 = SQLExecute _SQLExtendedFetch@20 = SQLExtendedFetch _SQLFetch@4 = SQLFetch _SQLFetchScroll@12 = SQLFetchScroll _SQLForeignKeys@52 = SQLForeignKeys _SQLForeignKeysA@52 = SQLForeignKeysA _SQLForeignKeysW@52 = SQLForeignKeysW _SQLFreeConnect@4 = SQLFreeConnect _SQLFreeEnv@4 = SQLFreeEnv _SQLFreeHandle@8 = SQLFreeHandle _SQLFreeStmt@8 = SQLFreeStmt _SQLGetConnectAttr@20 = SQLGetConnectAttr _SQLGetConnectAttrA@20 = SQLGetConnectAttrA _SQLGetConnectAttrW@20 = SQLGetConnectAttrW _SQLGetConnectOption@12 = SQLGetConnectOption _SQLGetConnectOptionA@12 = SQLGetConnectOptionA _SQLGetConnectOptionW@12 = SQLGetConnectOptionW _SQLGetCursorName@16 = SQLGetCursorName _SQLGetCursorNameA@16 = SQLGetCursorNameA _SQLGetCursorNameW@16 = SQLGetCursorNameW _SQLGetData@24 = SQLGetData _SQLGetDescField@24 = SQLGetDescField _SQLGetDescFieldA@24 = SQLGetDescFieldA _SQLGetDescFieldW@24 = SQLGetDescFieldW _SQLGetDescRec@44 = SQLGetDescRec _SQLGetDescRecA@44 = SQLGetDescRecA _SQLGetDescRecW@44 = SQLGetDescRecW _SQLGetDiagField@28 = SQLGetDiagField _SQLGetDiagFieldA@28 = SQLGetDiagFieldA _SQLGetDiagFieldW@28 = SQLGetDiagFieldW _SQLGetDiagRec@32 = SQLGetDiagRec _SQLGetDiagRecA@32 = SQLGetDiagRecA _SQLGetDiagRecW@32 = SQLGetDiagRecW _SQLGetEnvAttr@20 = SQLGetEnvAttr _SQLGetFunctions@12 = SQLGetFunctions _SQLGetInfo@20 = SQLGetInfo _SQLGetInfoA@20 = SQLGetInfoA _SQLGetInfoW@20 = SQLGetInfoW _SQLGetStmtAttr@20 = SQLGetStmtAttr _SQLGetStmtAttrA@20 = SQLGetStmtAttrA _SQLGetStmtAttrW@20 = SQLGetStmtAttrW _SQLGetStmtOption@12 = SQLGetStmtOption _SQLGetTypeInfo@8 = SQLGetTypeInfo _SQLGetTypeInfoA@8 = SQLGetTypeInfoA _SQLGetTypeInfoW@8 = SQLGetTypeInfoW _SQLMoreResults@4 = SQLMoreResults _SQLNativeSql@24 = SQLNativeSql _SQLNativeSqlA@24 = SQLNativeSqlA _SQLNativeSqlW@24 = SQLNativeSqlW _SQLNumParams@8 = SQLNumParams _SQLNumResultCols@8 = SQLNumResultCols _SQLParamData@8 = SQLParamData _SQLParamOptions@12 = SQLParamOptions _SQLPrepare@12 = SQLPrepare _SQLPrepareA@12 = SQLPrepareA _SQLPrepareW@12 = SQLPrepareW _SQLPrimaryKeys@28 = SQLPrimaryKeys _SQLPrimaryKeysA@28 = SQLPrimaryKeysA _SQLPrimaryKeysW@28 = SQLPrimaryKeysW _SQLProcedureColumns@36 = SQLProcedureColumns _SQLProcedureColumnsA@36 = SQLProcedureColumnsA _SQLProcedureColumnsW@36 = SQLProcedureColumnsW _SQLProcedures@28 = SQLProcedures _SQLProceduresA@28 = SQLProceduresA _SQLProceduresW@28 = SQLProceduresW _SQLPutData@12 = SQLPutData _SQLRowCount@8 = SQLRowCount _SQLSetConnectAttr@16 = SQLSetConnectAttr _SQLSetConnectAttrA@16 = SQLSetConnectAttrA _SQLSetConnectAttrW@16 = SQLSetConnectAttrW _SQLSetConnectOption@12 = SQLSetConnectOption _SQLSetConnectOptionA@12 = SQLSetConnectOptionA _SQLSetConnectOptionW@12 = SQLSetConnectOptionW _SQLSetCursorName@12 = SQLSetCursorName _SQLSetCursorNameA@12 = SQLSetCursorNameA _SQLSetCursorNameW@12 = SQLSetCursorNameW _SQLSetDescField@20 = SQLSetDescField _SQLSetDescFieldA@20 = SQLSetDescFieldA _SQLSetDescFieldW@20 = SQLSetDescFieldW _SQLSetDescRec@40 = SQLSetDescRec _SQLSetEnvAttr@16 = SQLSetEnvAttr _SQLSetParam@32 = SQLSetParam _SQLSetPos@16 = SQLSetPos _SQLSetScrollOptions@16 = SQLSetScrollOptions _SQLSetStmtAttr@16 = SQLSetStmtAttr _SQLSetStmtAttrA@16 = SQLSetStmtAttrA _SQLSetStmtAttrW@16 = SQLSetStmtAttrW _SQLSetStmtOption@12 = SQLSetStmtOption _SQLSpecialColumns@40 = SQLSpecialColumns _SQLSpecialColumnsA@40 = SQLSpecialColumnsA _SQLSpecialColumnsW@40 = SQLSpecialColumnsW _SQLStatistics@36 = SQLStatistics _SQLStatisticsA@36 = SQLStatisticsA _SQLStatisticsW@36 = SQLStatisticsW _SQLTablePrivileges@28 = SQLTablePrivileges _SQLTablePrivilegesA@28 = SQLTablePrivilegesA _SQLTablePrivilegesW@28 = SQLTablePrivilegesW _SQLTables@36 = SQLTables _SQLTablesA@36 = SQLTablesA _SQLTablesW@36 = SQLTablesW _SQLTransact@12 = SQLTransact ldc-1.1.0-beta3-src/runtime/druntime/def/wininet.def0000664000175000017500000002437012776214756020364 0ustar kaikaiLIBRARY wininet EXETYPE NT SUBSYSTEM WINDOWS EXPORTS _CommitUrlCacheEntryA@44 = CommitUrlCacheEntryA _CommitUrlCacheEntryW@44 = CommitUrlCacheEntryW _CreateUrlCacheContainerA@32 = CreateUrlCacheContainerA _CreateUrlCacheContainerW@32 = CreateUrlCacheContainerW _CreateUrlCacheEntryA@20 = CreateUrlCacheEntryA _CreateUrlCacheEntryW@20 = CreateUrlCacheEntryW _CreateUrlCacheGroup@8 = CreateUrlCacheGroup _DeleteIE3Cache@16 = DeleteIE3Cache _DeleteUrlCacheContainerA@8 = DeleteUrlCacheContainerA _DeleteUrlCacheContainerW@8 = DeleteUrlCacheContainerW _DeleteUrlCacheEntry@4 = DeleteUrlCacheEntry _DeleteUrlCacheEntryA@4 = DeleteUrlCacheEntryA _DeleteUrlCacheEntryW@4 = DeleteUrlCacheEntryW _DeleteUrlCacheGroup@16 = DeleteUrlCacheGroup _DoConnectoidsExist@0 = DoConnectoidsExist _ExportCookieFileA@8 = ExportCookieFileA _ExportCookieFileW@8 = ExportCookieFileW _FindCloseUrlCache@4 = FindCloseUrlCache _FindFirstUrlCacheContainerA@16 = FindFirstUrlCacheContainerA _FindFirstUrlCacheContainerW@16 = FindFirstUrlCacheContainerW _FindFirstUrlCacheEntryA@12 = FindFirstUrlCacheEntryA _FindFirstUrlCacheEntryExA@40 = FindFirstUrlCacheEntryExA _FindFirstUrlCacheEntryExW@40 = FindFirstUrlCacheEntryExW _FindFirstUrlCacheEntryW@12 = FindFirstUrlCacheEntryW _FindFirstUrlCacheGroup@24 = FindFirstUrlCacheGroup _FindNextUrlCacheContainerA@12 = FindNextUrlCacheContainerA _FindNextUrlCacheContainerW@12 = FindNextUrlCacheContainerW _FindNextUrlCacheEntryA@12 = FindNextUrlCacheEntryA _FindNextUrlCacheEntryExA@24 = FindNextUrlCacheEntryExA _FindNextUrlCacheEntryExW@24 = FindNextUrlCacheEntryExW _FindNextUrlCacheEntryW@12 = FindNextUrlCacheEntryW _FindNextUrlCacheGroup@12 = FindNextUrlCacheGroup _FreeUrlCacheSpaceA@12 = FreeUrlCacheSpaceA _FreeUrlCacheSpaceW@12 = FreeUrlCacheSpaceW _FtpCommandA@24 = FtpCommandA _FtpCommandW@24 = FtpCommandW _FtpCreateDirectoryA@8 = FtpCreateDirectoryA _FtpCreateDirectoryW@8 = FtpCreateDirectoryW _FtpDeleteFileA@8 = FtpDeleteFileA _FtpDeleteFileW@8 = FtpDeleteFileW _FtpFindFirstFileA@20 = FtpFindFirstFileA _FtpFindFirstFileW@20 = FtpFindFirstFileW _FtpGetCurrentDirectoryA@12 = FtpGetCurrentDirectoryA _FtpGetCurrentDirectoryW@12 = FtpGetCurrentDirectoryW _FtpGetFileA@28 = FtpGetFileA _FtpGetFileEx@28 = FtpGetFileEx _FtpGetFileSize@8 = FtpGetFileSize _FtpGetFileW@28 = FtpGetFileW _FtpOpenFileA@20 = FtpOpenFileA _FtpOpenFileW@20 = FtpOpenFileW _FtpPutFileA@20 = FtpPutFileA _FtpPutFileEx@20 = FtpPutFileEx _FtpPutFileW@20 = FtpPutFileW _FtpRemoveDirectoryA@8 = FtpRemoveDirectoryA _FtpRemoveDirectoryW@8 = FtpRemoveDirectoryW _FtpRenameFileA@12 = FtpRenameFileA _FtpRenameFileW@12 = FtpRenameFileW _FtpSetCurrentDirectoryA@8 = FtpSetCurrentDirectoryA _FtpSetCurrentDirectoryW@8 = FtpSetCurrentDirectoryW _GetDiskInfoA@16 = GetDiskInfoA _GetUrlCacheConfigInfoA@12 = GetUrlCacheConfigInfoA _GetUrlCacheConfigInfoW@12 = GetUrlCacheConfigInfoW _GetUrlCacheEntryInfoA@12 = GetUrlCacheEntryInfoA _GetUrlCacheEntryInfoExA@28 = GetUrlCacheEntryInfoExA _GetUrlCacheEntryInfoExW@28 = GetUrlCacheEntryInfoExW _GetUrlCacheEntryInfoW@12 = GetUrlCacheEntryInfoW _GetUrlCacheGroupAttributeA@28 = GetUrlCacheGroupAttributeA _GetUrlCacheGroupAttributeW@28 = GetUrlCacheGroupAttributeW _GetUrlCacheHeaderData@8 = GetUrlCacheHeaderData _GopherCreateLocatorA@28 = GopherCreateLocatorA _GopherCreateLocatorW@28 = GopherCreateLocatorW _GopherFindFirstFileA@24 = GopherFindFirstFileA _GopherFindFirstFileW@24 = GopherFindFirstFileW _GopherGetAttributeA@32 = GopherGetAttributeA _GopherGetAttributeW@32 = GopherGetAttributeW _GopherGetLocatorTypeA@8 = GopherGetLocatorTypeA _GopherGetLocatorTypeW@8 = GopherGetLocatorTypeW _GopherOpenFileA@20 = GopherOpenFileA _GopherOpenFileW@20 = GopherOpenFileW _HttpAddRequestHeadersA@16 = HttpAddRequestHeadersA _HttpAddRequestHeadersW@16 = HttpAddRequestHeadersW _HttpCheckDavCompliance@20 = HttpCheckDavCompliance _HttpCheckDavComplianceA@20 = HttpCheckDavComplianceA _HttpCheckDavComplianceW@20 = HttpCheckDavComplianceW _HttpEndRequestA@16 = HttpEndRequestA _HttpEndRequestW@16 = HttpEndRequestW _HttpOpenRequestA@32 = HttpOpenRequestA _HttpOpenRequestW@32 = HttpOpenRequestW _HttpQueryInfoA@20 = HttpQueryInfoA _HttpQueryInfoW@20 = HttpQueryInfoW _HttpSendRequestA@20 = HttpSendRequestA _HttpSendRequestExA@20 = HttpSendRequestExA _HttpSendRequestExW@20 = HttpSendRequestExW _HttpSendRequestW@20 = HttpSendRequestW _ImportCookieFileA@4 = ImportCookieFileA _ImportCookieFileW@4 = ImportCookieFileW _IncrementUrlCacheHeaderData@8 = IncrementUrlCacheHeaderData _InternetAlgIdToStringA@16 = InternetAlgIdToStringA _InternetAlgIdToStringW@16 = InternetAlgIdToStringW _InternetAttemptConnect@4 = InternetAttemptConnect _InternetAutodial@8 = InternetAutodial _InternetAutodialCallback@8 = InternetAutodialCallback _InternetAutodialHangup@4 = InternetAutodialHangup _InternetCanonicalizeUrlA@16 = InternetCanonicalizeUrlA _InternetCanonicalizeUrlW@16 = InternetCanonicalizeUrlW _InternetCheckConnectionA@12 = InternetCheckConnectionA _InternetCheckConnectionW@12 = InternetCheckConnectionW _InternetCloseHandle@4 = InternetCloseHandle _InternetCombineUrlA@20 = InternetCombineUrlA _InternetCombineUrlW@20 = InternetCombineUrlW _InternetConfirmZoneCrossing@16 = InternetConfirmZoneCrossing _InternetConfirmZoneCrossingA@16 = InternetConfirmZoneCrossingA _InternetConfirmZoneCrossingW@16 = InternetConfirmZoneCrossingW _InternetConnectA@32 = InternetConnectA _InternetConnectW@32 = InternetConnectW _InternetCrackUrlA@16 = InternetCrackUrlA _InternetCrackUrlW@16 = InternetCrackUrlW _InternetCreateUrlA@16 = InternetCreateUrlA _InternetCreateUrlW@16 = InternetCreateUrlW _InternetDial@20 = InternetDial _InternetDialA@20 = InternetDialA _InternetDialW@20 = InternetDialW _InternetErrorDlg@20 = InternetErrorDlg _InternetFindNextFileA@8 = InternetFindNextFileA _InternetFindNextFileW@8 = InternetFindNextFileW _InternetFortezzaCommand@12 = InternetFortezzaCommand _InternetGetCertByURL@12 = InternetGetCertByURL _InternetGetCertByURLA@12 = InternetGetCertByURLA _InternetGetConnectedState@8 = InternetGetConnectedState _InternetGetConnectedStateEx@16 = InternetGetConnectedStateEx _InternetGetConnectedStateExA@16 = InternetGetConnectedStateExA _InternetGetConnectedStateExW@16 = InternetGetConnectedStateExW _InternetGetCookieA@16 = InternetGetCookieA _InternetGetCookieW@16 = InternetGetCookieW _InternetGetLastResponseInfoA@12 = InternetGetLastResponseInfoA _InternetGetLastResponseInfoW@12 = InternetGetLastResponseInfoW _InternetGoOnline@12 = InternetGoOnline _InternetGoOnlineA@12 = InternetGoOnlineA _InternetGoOnlineW@12 = InternetGoOnlineW _InternetHangUp@8 = InternetHangUp _InternetLockRequestFile@8 = InternetLockRequestFile _InternetOpenA@20 = InternetOpenA _InternetOpenUrlA@24 = InternetOpenUrlA _InternetOpenUrlW@24 = InternetOpenUrlW _InternetOpenW@20 = InternetOpenW _InternetQueryDataAvailable@16 = InternetQueryDataAvailable _InternetQueryFortezzaStatus@8 = InternetQueryFortezzaStatus _InternetQueryOptionA@16 = InternetQueryOptionA _InternetQueryOptionW@16 = InternetQueryOptionW _InternetReadFile@16 = InternetReadFile _InternetReadFileExA@16 = InternetReadFileExA _InternetReadFileExW@16 = InternetReadFileExW _InternetSecurityProtocolToStringA@16 = InternetSecurityProtocolToStringA _InternetSecurityProtocolToStringW@16 = InternetSecurityProtocolToStringW _InternetSetCookieA@12 = InternetSetCookieA _InternetSetCookieW@12 = InternetSetCookieW _InternetSetDialState@12 = InternetSetDialState _InternetSetDialStateA@12 = InternetSetDialStateA _InternetSetDialStateW@12 = InternetSetDialStateW _InternetSetFilePointer@20 = InternetSetFilePointer _InternetSetOptionA@16 = InternetSetOptionA _InternetSetOptionExA@20 = InternetSetOptionExA _InternetSetOptionExW@20 = InternetSetOptionExW _InternetSetOptionW@16 = InternetSetOptionW _InternetSetStatusCallback@8 = InternetSetStatusCallback _InternetSetStatusCallbackA@8 = InternetSetStatusCallbackA _InternetSetStatusCallbackW@8 = InternetSetStatusCallbackW _InternetShowSecurityInfoByURL@8 = InternetShowSecurityInfoByURL _InternetShowSecurityInfoByURLA@8 = InternetShowSecurityInfoByURLA _InternetShowSecurityInfoByURLW@8 = InternetShowSecurityInfoByURLW _InternetTimeFromSystemTime@16 = InternetTimeFromSystemTime _InternetTimeFromSystemTimeA@16 = InternetTimeFromSystemTimeA _InternetTimeFromSystemTimeW@16 = InternetTimeFromSystemTimeW _InternetTimeToSystemTime@12 = InternetTimeToSystemTime _InternetTimeToSystemTimeA@12 = InternetTimeToSystemTimeA _InternetTimeToSystemTimeW@12 = InternetTimeToSystemTimeW _InternetUnlockRequestFile@4 = InternetUnlockRequestFile _InternetWriteFile@16 = InternetWriteFile _InternetWriteFileExA@16 = InternetWriteFileExA _InternetWriteFileExW@16 = InternetWriteFileExW _IsHostInProxyBypassList@12 = IsHostInProxyBypassList _IsUrlCacheEntryExpiredA@12 = IsUrlCacheEntryExpiredA _IsUrlCacheEntryExpiredW@12 = IsUrlCacheEntryExpiredW _LoadUrlCacheContent@0 = LoadUrlCacheContent _ParseX509EncodedCertificateForListBoxEntry@16 = ParseX509EncodedCertificateForListBoxEntry _PerformOperationOverUrlCacheA@40 = PerformOperationOverUrlCacheA _ReadUrlCacheEntryStream@20 = ReadUrlCacheEntryStream _RegisterUrlCacheNotification@24 = RegisterUrlCacheNotification _ResumeSuspendedDownload@8 = ResumeSuspendedDownload _RetrieveUrlCacheEntryFileA@16 = RetrieveUrlCacheEntryFileA _RetrieveUrlCacheEntryFileW@16 = RetrieveUrlCacheEntryFileW _RetrieveUrlCacheEntryStreamA@20 = RetrieveUrlCacheEntryStreamA _RetrieveUrlCacheEntryStreamW@20 = RetrieveUrlCacheEntryStreamW _RunOnceUrlCache@16 = RunOnceUrlCache _SetUrlCacheConfigInfoA@8 = SetUrlCacheConfigInfoA _SetUrlCacheConfigInfoW@8 = SetUrlCacheConfigInfoW _SetUrlCacheEntryGroup@28 = SetUrlCacheEntryGroup _SetUrlCacheEntryGroupA@28 = SetUrlCacheEntryGroupA _SetUrlCacheEntryGroupW@28 = SetUrlCacheEntryGroupW _SetUrlCacheEntryInfoA@12 = SetUrlCacheEntryInfoA _SetUrlCacheEntryInfoW@12 = SetUrlCacheEntryInfoW _SetUrlCacheGroupAttributeA@24 = SetUrlCacheGroupAttributeA _SetUrlCacheGroupAttributeW@24 = SetUrlCacheGroupAttributeW _SetUrlCacheHeaderData@8 = SetUrlCacheHeaderData _ShowClientAuthCerts@4 = ShowClientAuthCerts _ShowSecurityInfo@8 = ShowSecurityInfo _ShowX509EncodedCertificate@12 = ShowX509EncodedCertificate _UnlockUrlCacheEntryFile@8 = UnlockUrlCacheEntryFile _UnlockUrlCacheEntryFileA@8 = UnlockUrlCacheEntryFileA _UnlockUrlCacheEntryFileW@8 = UnlockUrlCacheEntryFileW _UnlockUrlCacheEntryStream@8 = UnlockUrlCacheEntryStream _UpdateUrlCacheContentPath@4 = UpdateUrlCacheContentPath ldc-1.1.0-beta3-src/runtime/druntime/def/glu32.def0000664000175000017500000001135612776214756017643 0ustar kaikaiLIBRARY GLU32 EXETYPE NT SUBSYSTEM WINDOWS EXPORTS _gluBeginCurve@4 = gluBeginCurve ; gluBeginCurve _gluBeginPolygon@4 = gluBeginPolygon ; gluBeginPolygon _gluBeginSurface@4 = gluBeginSurface ; gluBeginSurface _gluBeginTrim@4 = gluBeginTrim ; gluBeginTrim _gluBuild1DMipmaps@24 = gluBuild1DMipmaps ; gluBuild1DMipmaps _gluBuild2DMipmaps@28 = gluBuild2DMipmaps ; gluBuild2DMipmaps _gluCylinder@36 = gluCylinder ; gluCylinder _gluDeleteNurbsRenderer@4 = gluDeleteNurbsRenderer ; gluDeleteNurbsRenderer _gluDeleteQuadric@4 = gluDeleteQuadric ; gluDeleteQuadric _gluDeleteTess@4 = gluDeleteTess ; gluDeleteTess _gluDisk@28 = gluDisk ; gluDisk _gluEndCurve@4 = gluEndCurve ; gluEndCurve _gluEndPolygon@4 = gluEndPolygon ; gluEndPolygon _gluEndSurface@4 = gluEndSurface ; gluEndSurface _gluEndTrim@4 = gluEndTrim ; gluEndTrim _gluErrorString@4 = gluErrorString ; gluErrorString _gluErrorUnicodeStringEXT@4 = gluErrorUnicodeStringEXT ; gluErrorUnicodeStringEXT _gluGetNurbsProperty@12 = gluGetNurbsProperty ; gluGetNurbsProperty _gluGetString@4 = gluGetString ; gluGetString _gluGetTessProperty@12 = gluGetTessProperty ; gluGetTessProperty _gluLoadSamplingMatrices@16 = gluLoadSamplingMatrices ; gluLoadSamplingMatrices _gluLookAt@72 = gluLookAt ; gluLookAt _gluNewNurbsRenderer@0 = gluNewNurbsRenderer ; gluNewNurbsRenderer _gluNewQuadric@0 = gluNewQuadric ; gluNewQuadric _gluNewTess@0 = gluNewTess ; gluNewTess _gluNextContour@8 = gluNextContour ; gluNextContour _gluNurbsCallback@12 = gluNurbsCallback ; gluNurbsCallback _gluNurbsCurve@28 = gluNurbsCurve ; gluNurbsCurve _gluNurbsProperty@12 = gluNurbsProperty ; gluNurbsProperty _gluNurbsSurface@44 = gluNurbsSurface ; gluNurbsSurface _gluOrtho2D@32 = gluOrtho2D ; gluOrtho2D _gluPartialDisk@44 = gluPartialDisk ; gluPartialDisk _gluPerspective@32 = gluPerspective ; gluPerspective _gluPickMatrix@36 = gluPickMatrix ; gluPickMatrix _gluProject@48 = gluProject ; gluProject _gluPwlCurve@20 = gluPwlCurve ; gluPwlCurve _gluQuadricCallback@12 = gluQuadricCallback ; gluQuadricCallback _gluQuadricDrawStyle@8 = gluQuadricDrawStyle ; gluQuadricDrawStyle _gluQuadricNormals@8 = gluQuadricNormals ; gluQuadricNormals _gluQuadricOrientation@8 = gluQuadricOrientation ; gluQuadricOrientation _gluQuadricTexture@8 = gluQuadricTexture ; gluQuadricTexture _gluScaleImage@36 = gluScaleImage ; gluScaleImage _gluSphere@20 = gluSphere ; gluSphere _gluTessBeginContour@4 = gluTessBeginContour ; gluTessBeginContour _gluTessBeginPolygon@8 = gluTessBeginPolygon ; gluTessBeginPolygon _gluTessCallback@12 = gluTessCallback ; gluTessCallback _gluTessEndContour@4 = gluTessEndContour ; gluTessEndContour _gluTessEndPolygon@4 = gluTessEndPolygon ; gluTessEndPolygon _gluTessNormal@28 = gluTessNormal ; gluTessNormal _gluTessProperty@16 = gluTessProperty ; gluTessProperty _gluTessVertex@12 = gluTessVertex ; gluTessVertex _gluUnProject@48 = gluUnProject ; gluUnProject ldc-1.1.0-beta3-src/runtime/druntime/def/shell32.def0000664000175000017500000002550712776214756020166 0ustar kaikaiLIBRARY shell32 EXETYPE NT SUBSYSTEM WINDOWS EXPORTS _CDefFolderMenu_Create2@36 = CDefFolderMenu_Create2 _CDefFolderMenu_Create@36 = CDefFolderMenu_Create _CallCPLEntry16@24 = CallCPLEntry16 _CheckEscapesA@8 = CheckEscapesA _CheckEscapesW@8 = CheckEscapesW _CommandLineToArgvW@8 = CommandLineToArgvW _DAD_AutoScroll@12 = DAD_AutoScroll _DAD_DragEnterEx2@16 = DAD_DragEnterEx2 _DAD_DragEnterEx@12 = DAD_DragEnterEx _DAD_DragLeave@0 = DAD_DragLeave _DAD_DragMove@8 = DAD_DragMove _DAD_SetDragImage@8 = DAD_SetDragImage _DAD_ShowDragImage@4 = DAD_ShowDragImage _DoEnvironmentSubstA@8 = DoEnvironmentSubstA _DoEnvironmentSubstW@8 = DoEnvironmentSubstW _DragAcceptFiles@8 = DragAcceptFiles _DragFinish@4 = DragFinish _DragQueryFile@16 = DragQueryFile _DragQueryFileA@16 = DragQueryFileA _DragQueryFileAorW@24 = DragQueryFileAorW _DragQueryFileW@16 = DragQueryFileW _DragQueryPoint@8 = DragQueryPoint _DriveType@4 = DriveType _DuplicateIcon@8 = DuplicateIcon _ExtractAssociatedIconA@12 = ExtractAssociatedIconA _ExtractAssociatedIconExA@16 = ExtractAssociatedIconExA _ExtractAssociatedIconExW@16 = ExtractAssociatedIconExW _ExtractAssociatedIconW@12 = ExtractAssociatedIconW _ExtractIconA@12 = ExtractIconA _ExtractIconEx@20 = ExtractIconEx _ExtractIconExA@20 = ExtractIconExA _ExtractIconExW@20 = ExtractIconExW _ExtractIconResInfoA@20 = ExtractIconResInfoA _ExtractIconResInfoW@20 = ExtractIconResInfoW _ExtractIconW@12 = ExtractIconW _ExtractVersionResource16W@8 = ExtractVersionResource16W _FindExeDlgProc@16 = FindExeDlgProc _FindExecutableA@12 = FindExecutableA _FindExecutableW@12 = FindExecutableW _FreeIconList@8 = FreeIconList _GetFileNameFromBrowse@28 = GetFileNameFromBrowse _ILAppendID@12 = ILAppendID _ILClone@4 = ILClone _ILCloneFirst@4 = ILCloneFirst _ILCombine@8 = ILCombine _ILCreateFromPath@4 = ILCreateFromPath _ILCreateFromPathA@4 = ILCreateFromPathA _ILCreateFromPathW@4 = ILCreateFromPathW _ILFindChild@8 = ILFindChild _ILFindLastID@4 = ILFindLastID _ILFree@4 = ILFree _ILGetNext@4 = ILGetNext _ILGetSize@4 = ILGetSize _ILIsEqual@8 = ILIsEqual _ILIsParent@12 = ILIsParent _ILLoadFromStream@8 = ILLoadFromStream _ILRemoveLastID@4 = ILRemoveLastID _ILSaveToStream@8 = ILSaveToStream _InternalExtractIconListA@12 = InternalExtractIconListA _InternalExtractIconListW@12 = InternalExtractIconListW _IsLFNDrive@4 = IsLFNDrive _IsLFNDriveA@4 = IsLFNDriveA _IsLFNDriveW@4 = IsLFNDriveW _IsNetDrive@4 = IsNetDrive _IsUserAnAdmin@0 = IsUserAnAdmin _OpenRegStream@16 = OpenRegStream _PathCleanupSpec@8 = PathCleanupSpec _PathGetShortPath@4 = PathGetShortPath _PathIsExe@4 = PathIsExe _PathIsSlowA@8 = PathIsSlowA _PathIsSlowW@8 = PathIsSlowW _PathMakeUniqueName@20 = PathMakeUniqueName _PathProcessCommand@16 = PathProcessCommand _PathQualify@4 = PathQualify _PathResolve@12 = PathResolve _PathYetAnotherMakeUniqueName@16 = PathYetAnotherMakeUniqueName _PickIconDlg@16 = PickIconDlg _PifMgr_CloseProperties@8 = PifMgr_CloseProperties _PifMgr_GetProperties@20 = PifMgr_GetProperties _PifMgr_OpenProperties@16 = PifMgr_OpenProperties _PifMgr_SetProperties@20 = PifMgr_SetProperties _ReadCabinetState@8 = ReadCabinetState _RealDriveType@8 = RealDriveType _RealShellExecuteA@40 = RealShellExecuteA _RealShellExecuteExA@44 = RealShellExecuteExA _RealShellExecuteExW@44 = RealShellExecuteExW _RealShellExecuteW@40 = RealShellExecuteW _RegenerateUserEnvironment@8 = RegenerateUserEnvironment _RestartDialog@12 = RestartDialog _RestartDialogEx@16 = RestartDialogEx _SHAddFromPropSheetExtArray@12 = SHAddFromPropSheetExtArray _SHAddToRecentDocs@8 = SHAddToRecentDocs _SHAlloc@4 = SHAlloc _SHAllocShared@12 = SHAllocShared _SHAppBarMessage@8 = SHAppBarMessage _SHBindToParent@16 = SHBindToParent _SHBrowseForFolder@4 = SHBrowseForFolder _SHBrowseForFolderA@4 = SHBrowseForFolderA _SHBrowseForFolderW@4 = SHBrowseForFolderW _SHCLSIDFromString@8 = SHCLSIDFromString _SHChangeNotification_Lock@16 = SHChangeNotification_Lock _SHChangeNotification_Unlock@4 = SHChangeNotification_Unlock _SHChangeNotify@16 = SHChangeNotify _SHChangeNotifyDeregister@4 = SHChangeNotifyDeregister _SHChangeNotifyRegister@24 = SHChangeNotifyRegister _SHCloneSpecialIDList@12 = SHCloneSpecialIDList _SHCoCreateInstance@20 = SHCoCreateInstance _SHCreateDirectory@8 = SHCreateDirectory _SHCreateDirectoryExA@12 = SHCreateDirectoryExA _SHCreateDirectoryExW@12 = SHCreateDirectoryExW _SHCreateFileExtractIconW@16 = SHCreateFileExtractIconW _SHCreateProcessAsUserW@4 = SHCreateProcessAsUserW _SHCreatePropSheetExtArray@12 = SHCreatePropSheetExtArray _SHCreateQueryCancelAutoPlayMoniker@4 = SHCreateQueryCancelAutoPlayMoniker _SHCreateShellFolderView@8 = SHCreateShellFolderView _SHCreateShellFolderViewEx@8 = SHCreateShellFolderViewEx _SHCreateShellItem@16 = SHCreateShellItem _SHCreateStdEnumFmtEtc@12 = SHCreateStdEnumFmtEtc _SHDefExtractIconA@24 = SHDefExtractIconA _SHDefExtractIconW@24 = SHDefExtractIconW _SHDestroyPropSheetExtArray@4 = SHDestroyPropSheetExtArray _SHDoDragDrop@20 = SHDoDragDrop _SHEmptyRecycleBinA@12 = SHEmptyRecycleBinA _SHEmptyRecycleBinW@12 = SHEmptyRecycleBinW _SHEnumerateUnreadMailAccountsW@16 = SHEnumerateUnreadMailAccountsW _SHExtractIconsW@32 = SHExtractIconsW _SHFileOperation@4 = SHFileOperation _SHFileOperationA@4 = SHFileOperationA _SHFileOperationW@4 = SHFileOperationW _SHFindFiles@8 = SHFindFiles _SHFind_InitMenuPopup@16 = SHFind_InitMenuPopup _SHFlushClipboard@0 = SHFlushClipboard _SHFlushSFCache@0 = SHFlushSFCache _SHFormatDrive@16 = SHFormatDrive _SHFree@4 = SHFree _SHFreeNameMappings@4 = SHFreeNameMappings _SHFreeShared@8 = SHFreeShared _SHGetAttributesFromDataObject@16 = SHGetAttributesFromDataObject _SHGetDataFromIDListA@20 = SHGetDataFromIDListA _SHGetDataFromIDListW@20 = SHGetDataFromIDListW _SHGetDesktopFolder@4 = SHGetDesktopFolder _SHGetDiskFreeSpaceA@16 = SHGetDiskFreeSpaceA _SHGetDiskFreeSpaceExA@16 = SHGetDiskFreeSpaceExA _SHGetDiskFreeSpaceExW@16 = SHGetDiskFreeSpaceExW _SHGetFileInfo@20 = SHGetFileInfo _SHGetFileInfoA@20 = SHGetFileInfoA _SHGetFileInfoW@20 = SHGetFileInfoW _SHGetFolderLocation@20 = SHGetFolderLocation _SHGetFolderPathA@20 = SHGetFolderPathA _SHGetFolderPathAndSubDirA@24 = SHGetFolderPathAndSubDirA _SHGetFolderPathAndSubDirW@24 = SHGetFolderPathAndSubDirW _SHGetFolderPathW@20 = SHGetFolderPathW _SHGetIconOverlayIndexA@8 = SHGetIconOverlayIndexA _SHGetIconOverlayIndexW@8 = SHGetIconOverlayIndexW _SHGetInstanceExplorer@4 = SHGetInstanceExplorer _SHGetMalloc@4 = SHGetMalloc _SHGetNewLinkInfo@20 = SHGetNewLinkInfo _SHGetNewLinkInfoA@20 = SHGetNewLinkInfoA _SHGetNewLinkInfoW@20 = SHGetNewLinkInfoW _SHGetPathFromIDList@8 = SHGetPathFromIDList _SHGetPathFromIDListA@8 = SHGetPathFromIDListA _SHGetPathFromIDListW@8 = SHGetPathFromIDListW _SHGetRealIDL@12 = SHGetRealIDL _SHGetSetFolderCustomSettingsW@12 = SHGetSetFolderCustomSettingsW _SHGetSetSettings@12 = SHGetSetSettings _SHGetSettings@8 = SHGetSettings _SHGetShellStyleHInstance@0 = SHGetShellStyleHInstance _SHGetSpecialFolderLocation@12 = SHGetSpecialFolderLocation _SHGetSpecialFolderPath@16 = SHGetSpecialFolderPath _SHGetSpecialFolderPathA@16 = SHGetSpecialFolderPathA _SHGetSpecialFolderPathW@16 = SHGetSpecialFolderPathW _SHGetUnreadMailCountW@24 = SHGetUnreadMailCountW _SHHandleUpdateImage@4 = SHHandleUpdateImage _SHILCreateFromPath@12 = SHILCreateFromPath _SHInvokePrinterCommandA@20 = SHInvokePrinterCommandA _SHInvokePrinterCommandW@20 = SHInvokePrinterCommandW _SHIsFileAvailableOffline@8 = SHIsFileAvailableOffline _SHLimitInputEdit@8 = SHLimitInputEdit _SHLoadInProc@4 = SHLoadInProc _SHLoadNonloadedIconOverlayIdentifiers@0 = SHLoadNonloadedIconOverlayIdentifiers _SHLoadOLE@4 = SHLoadOLE _SHLockShared@8 = SHLockShared _SHMapIDListToImageListIndexAsync@36 = SHMapIDListToImageListIndexAsync _SHMapPIDLToSystemImageListIndex@12 = SHMapPIDLToSystemImageListIndex _SHMultiFileProperties@8 = SHMultiFileProperties _SHObjectProperties@16 = SHObjectProperties _SHOpenFolderAndSelectItems@16 = SHOpenFolderAndSelectItems _SHOpenPropSheetW@28 = SHOpenPropSheetW _SHParseDisplayName@20 = SHParseDisplayName _SHPathPrepareForWriteA@16 = SHPathPrepareForWriteA _SHPathPrepareForWriteW@16 = SHPathPrepareForWriteW _SHPropStgCreate@32 = SHPropStgCreate _SHPropStgReadMultiple@20 = SHPropStgReadMultiple _SHPropStgWriteMultiple@24 = SHPropStgWriteMultiple _SHQueryRecycleBinA@8 = SHQueryRecycleBinA _SHQueryRecycleBinW@8 = SHQueryRecycleBinW _SHReplaceFromPropSheetExtArray@16 = SHReplaceFromPropSheetExtArray _SHRestricted@4 = SHRestricted _SHRunControlPanel@8 = SHRunControlPanel _SHSetInstanceExplorer@4 = SHSetInstanceExplorer _SHSetLocalizedName@12 = SHSetLocalizedName _SHSetUnreadMailCountW@12 = SHSetUnreadMailCountW _SHShellFolderView_Message@12 = SHShellFolderView_Message _SHSimpleIDListFromPath@4 = SHSimpleIDListFromPath _SHStartNetConnectionDialogW@12 = SHStartNetConnectionDialogW _SHTestTokenMembership@8 = SHTestTokenMembership _SHUnlockShared@4 = SHUnlockShared _SHUpdateImageA@16 = SHUpdateImageA _SHUpdateImageW@16 = SHUpdateImageW _SHUpdateRecycleBinIcon@0 = SHUpdateRecycleBinIcon _SHValidateUNC@12 = SHValidateUNC _SheChangeDirA@4 = SheChangeDirA _SheChangeDirExA@4 = SheChangeDirExA _SheChangeDirExW@4 = SheChangeDirExW _SheChangeDirW@4 = SheChangeDirW _SheConvertPathW@12 = SheConvertPathW _SheFullPathA@12 = SheFullPathA _SheFullPathW@12 = SheFullPathW _SheGetCurDrive@0 = SheGetCurDrive _SheGetDirA@8 = SheGetDirA _SheGetDirExW@12 = SheGetDirExW _SheGetDirW@8 = SheGetDirW _SheGetPathOffsetW@4 = SheGetPathOffsetW _SheRemoveQuotesA@4 = SheRemoveQuotesA _SheRemoveQuotesW@4 = SheRemoveQuotesW _SheSetCurDrive@4 = SheSetCurDrive _SheShortenPathA@8 = SheShortenPathA _SheShortenPathW@8 = SheShortenPathW _ShellAboutA@16 = ShellAboutA _ShellAboutW@16 = ShellAboutW _ShellExecuteA@24 = ShellExecuteA _ShellExecuteEx@4 = ShellExecuteEx _ShellExecuteExA@4 = ShellExecuteExA _ShellExecuteExW@4 = ShellExecuteExW _ShellExecuteW@24 = ShellExecuteW _ShellHookProc@12 = ShellHookProc _ShellMessageBoxA = ShellMessageBoxA _ShellMessageBoxW = ShellMessageBoxW _Shell_GetCachedImageIndex@12 = Shell_GetCachedImageIndex _Shell_GetImageLists@8 = Shell_GetImageLists _Shell_MergeMenus@24 = Shell_MergeMenus _Shell_NotifyIcon@8 = Shell_NotifyIcon _Shell_NotifyIconA@8 = Shell_NotifyIconA _Shell_NotifyIconW@8 = Shell_NotifyIconW _SignalFileOpen@4 = SignalFileOpen _StrChrA@8 = StrChrA _StrChrIA@8 = StrChrIA _StrChrIW@8 = StrChrIW _StrChrW@8 = StrChrW _StrCmpNA@12 = StrCmpNA _StrCmpNIA@12 = StrCmpNIA _StrCmpNIW@12 = StrCmpNIW _StrCmpNW@12 = StrCmpNW _StrCpyNA@12 = StrCpyNA _StrCpyNW@12 = StrCpyNW _StrNCmpA@12 = StrNCmpA _StrNCmpIA@12 = StrNCmpIA _StrNCmpIW@12 = StrNCmpIW _StrNCmpW@12 = StrNCmpW _StrNCpyA@12 = StrNCpyA _StrNCpyW@12 = StrNCpyW _StrRChrA@12 = StrRChrA _StrRChrIA@12 = StrRChrIA _StrRChrIW@12 = StrRChrIW _StrRChrW@12 = StrRChrW _StrRStrA@12 = StrRStrA _StrRStrIA@12 = StrRStrIA _StrRStrIW@12 = StrRStrIW _StrRStrW@12 = StrRStrW _StrStrA@8 = StrStrA _StrStrIA@8 = StrStrIA _StrStrIW@8 = StrStrIW _StrStrW@8 = StrStrW _WOWShellExecute@28 = WOWShellExecute _Win32DeleteFile@4 = Win32DeleteFile _WriteCabinetState@4 = WriteCabinetState ldc-1.1.0-beta3-src/runtime/druntime/def/rpcrt4.def0000664000175000017500000005741312776214756020131 0ustar kaikaiLIBRARY rpcrt4 EXETYPE NT SUBSYSTEM WINDOWS EXPORTS _CStdStubBuffer_AddRef@4 = CStdStubBuffer_AddRef _CStdStubBuffer_Connect@8 = CStdStubBuffer_Connect _CStdStubBuffer_CountRefs@4 = CStdStubBuffer_CountRefs _CStdStubBuffer_DebugServerQueryInterface@8 = CStdStubBuffer_DebugServerQueryInterface _CStdStubBuffer_DebugServerRelease@8 = CStdStubBuffer_DebugServerRelease _CStdStubBuffer_Disconnect@4 = CStdStubBuffer_Disconnect _CStdStubBuffer_Invoke@12 = CStdStubBuffer_Invoke _CStdStubBuffer_IsIIDSupported@8 = CStdStubBuffer_IsIIDSupported _CStdStubBuffer_QueryInterface@12 = CStdStubBuffer_QueryInterface _DceErrorInqTextA@8 = DceErrorInqTextA _DceErrorInqTextW@8 = DceErrorInqTextW _GlobalMutexClear@0 = GlobalMutexClear _GlobalMutexClearExternal@0 = GlobalMutexClearExternal _GlobalMutexRequest@0 = GlobalMutexRequest _GlobalMutexRequestExternal@0 = GlobalMutexRequestExternal _IUnknown_AddRef_Proxy@4 = IUnknown_AddRef_Proxy _IUnknown_QueryInterface_Proxy@12 = IUnknown_QueryInterface_Proxy _IUnknown_Release_Proxy@4 = IUnknown_Release_Proxy _I_RpcAbortAsyncCall@8 = I_RpcAbortAsyncCall _I_RpcAllocate@4 = I_RpcAllocate _I_RpcAsyncAbortCall@8 = I_RpcAsyncAbortCall _I_RpcAsyncSetHandle@8 = I_RpcAsyncSetHandle _I_RpcBCacheAllocate@4 = I_RpcBCacheAllocate _I_RpcBCacheFree@4 = I_RpcBCacheFree _I_RpcBindingCopy@8 = I_RpcBindingCopy _I_RpcBindingInqConnId@12 = I_RpcBindingInqConnId _I_RpcBindingInqDynamicEndpoint@8 = I_RpcBindingInqDynamicEndpoint _I_RpcBindingInqDynamicEndpointA@8 = I_RpcBindingInqDynamicEndpointA _I_RpcBindingInqDynamicEndpointW@8 = I_RpcBindingInqDynamicEndpointW _I_RpcBindingInqSecurityContext@8 = I_RpcBindingInqSecurityContext _I_RpcBindingInqTransportType@8 = I_RpcBindingInqTransportType _I_RpcBindingInqWireIdForSnego@8 = I_RpcBindingInqWireIdForSnego _I_RpcBindingIsClientLocal@8 = I_RpcBindingIsClientLocal _I_RpcBindingToStaticStringBindingW@8 = I_RpcBindingToStaticStringBindingW _I_RpcClearMutex@4 = I_RpcClearMutex _I_RpcConnectionInqSockBuffSize@8 = I_RpcConnectionInqSockBuffSize _I_RpcConnectionSetSockBuffSize@8 = I_RpcConnectionSetSockBuffSize _I_RpcDeleteMutex@4 = I_RpcDeleteMutex _I_RpcFree@4 = I_RpcFree _I_RpcFreeBuffer@4 = I_RpcFreeBuffer _I_RpcFreePipeBuffer@4 = I_RpcFreePipeBuffer _I_RpcGetAssociationContext@8 = I_RpcGetAssociationContext _I_RpcGetBuffer@4 = I_RpcGetBuffer _I_RpcGetBufferWithObject@8 = I_RpcGetBufferWithObject _I_RpcGetCurrentCallHandle@0 = I_RpcGetCurrentCallHandle _I_RpcGetExtendedError@0 = I_RpcGetExtendedError _I_RpcGetServerContextList@4 = I_RpcGetServerContextList _I_RpcIfInqTransferSyntaxes@16 = I_RpcIfInqTransferSyntaxes _I_RpcLogEvent@28 = I_RpcLogEvent _I_RpcMapWin32Status@4 = I_RpcMapWin32Status _I_RpcMonitorAssociation@12 = I_RpcMonitorAssociation _I_RpcNsBindingSetEntryName@12 = I_RpcNsBindingSetEntryName _I_RpcNsBindingSetEntryNameA@12 = I_RpcNsBindingSetEntryNameA _I_RpcNsBindingSetEntryNameW@12 = I_RpcNsBindingSetEntryNameW _I_RpcNsInterfaceExported@12 = I_RpcNsInterfaceExported _I_RpcNsInterfaceUnexported@12 = I_RpcNsInterfaceUnexported _I_RpcParseSecurity@8 = I_RpcParseSecurity _I_RpcPauseExecution@4 = I_RpcPauseExecution _I_RpcReallocPipeBuffer@8 = I_RpcReallocPipeBuffer _I_RpcReceive@8 = I_RpcReceive _I_RpcRequestMutex@4 = I_RpcRequestMutex _I_RpcSend@4 = I_RpcSend _I_RpcSendReceive@4 = I_RpcSendReceive _I_RpcServerAllocateIpPort@8 = I_RpcServerAllocateIpPort _I_RpcServerInqAddressChangeFn@0 = I_RpcServerInqAddressChangeFn _I_RpcServerInqTransportType@4 = I_RpcServerInqTransportType _I_RpcServerRegisterForwardFunction@4 = I_RpcServerRegisterForwardFunction _I_RpcServerSetAddressChangeFn@4 = I_RpcServerSetAddressChangeFn _I_RpcServerUseProtseq2A@20 = I_RpcServerUseProtseq2A _I_RpcServerUseProtseq2W@20 = I_RpcServerUseProtseq2W _I_RpcServerUseProtseqEp2A@24 = I_RpcServerUseProtseqEp2A _I_RpcServerUseProtseqEp2W@24 = I_RpcServerUseProtseqEp2W _I_RpcSetAsyncHandle@8 = I_RpcSetAsyncHandle _I_RpcSetServerContextList@8 = I_RpcSetServerContextList _I_RpcSsDontSerializeContext@0 = I_RpcSsDontSerializeContext _I_RpcStopMonitorAssociation@4 = I_RpcStopMonitorAssociation _I_RpcTransConnectionAllocatePacket@8 = I_RpcTransConnectionAllocatePacket _I_RpcTransConnectionFreePacket@8 = I_RpcTransConnectionFreePacket _I_RpcTransConnectionReallocPacket@16 = I_RpcTransConnectionReallocPacket _I_RpcTransDatagramAllocate2@16 = I_RpcTransDatagramAllocate2 _I_RpcTransDatagramAllocate@16 = I_RpcTransDatagramAllocate _I_RpcTransDatagramFree@12 = I_RpcTransDatagramFree _I_RpcTransGetAddressList@8 = I_RpcTransGetAddressList _I_RpcTransGetThreadEvent@0 = I_RpcTransGetThreadEvent _I_RpcTransIoCancelled@8 = I_RpcTransIoCancelled _I_RpcTransProtectThread@0 = I_RpcTransProtectThread _I_RpcTransServerNewConnection@4 = I_RpcTransServerNewConnection _I_RpcTransUnprotectThread@4 = I_RpcTransUnprotectThread _I_UuidCreate@4 = I_UuidCreate _MIDL_wchar_strcpy@8 = MIDL_wchar_strcpy _MIDL_wchar_strlen@4 = MIDL_wchar_strlen _MesBufferHandleReset@24 = MesBufferHandleReset _MesDecodeBufferHandleCreate@12 = MesDecodeBufferHandleCreate _MesDecodeIncrementalHandleCreate@12 = MesDecodeIncrementalHandleCreate _MesEncodeDynBufferHandleCreate@12 = MesEncodeDynBufferHandleCreate _MesEncodeFixedBufferHandleCreate@16 = MesEncodeFixedBufferHandleCreate _MesEncodeIncrementalHandleCreate@16 = MesEncodeIncrementalHandleCreate _MesHandleFree@4 = MesHandleFree _MesIncrementalHandleReset@24 = MesIncrementalHandleReset _MesInqProcEncodingId@12 = MesInqProcEncodingId _NDRCContextBinding@4 = NDRCContextBinding _NDRCContextMarshall@8 = NDRCContextMarshall _NDRCContextUnmarshall@16 = NDRCContextUnmarshall _NDRSContextMarshall2@24 = NDRSContextMarshall2 _NDRSContextMarshall@12 = NDRSContextMarshall _NDRSContextMarshallEx@16 = NDRSContextMarshallEx _NDRSContextUnmarshall2@20 = NDRSContextUnmarshall2 _NDRSContextUnmarshall@8 = NDRSContextUnmarshall _NDRSContextUnmarshallEx@12 = NDRSContextUnmarshallEx _NDRcopy@12 = NDRcopy _NdrAllocate@8 = NdrAllocate _NdrAsyncClientCall = NdrAsyncClientCall _NdrAsyncServerCall@4 = NdrAsyncServerCall _NdrAsyncStubCall@16 = NdrAsyncStubCall _NdrByteCountPointerBufferSize@12 = NdrByteCountPointerBufferSize _NdrByteCountPointerFree@12 = NdrByteCountPointerFree _NdrByteCountPointerMarshall@12 = NdrByteCountPointerMarshall _NdrByteCountPointerUnmarshall@16 = NdrByteCountPointerUnmarshall _NdrCStdStubBuffer2_Release@8 = NdrCStdStubBuffer2_Release _NdrCStdStubBuffer_Release@8 = NdrCStdStubBuffer_Release _NdrClearOutParameters@12 = NdrClearOutParameters _NdrClientCall = NdrClientCall _NdrClientCall2 = NdrClientCall2 _NdrClientContextMarshall@12 = NdrClientContextMarshall _NdrClientContextUnmarshall@12 = NdrClientContextUnmarshall _NdrClientInitialize@16 = NdrClientInitialize _NdrClientInitializeNew@16 = NdrClientInitializeNew _NdrComplexArrayBufferSize@12 = NdrComplexArrayBufferSize _NdrComplexArrayFree@12 = NdrComplexArrayFree _NdrComplexArrayMarshall@12 = NdrComplexArrayMarshall _NdrComplexArrayMemorySize@8 = NdrComplexArrayMemorySize _NdrComplexArrayUnmarshall@16 = NdrComplexArrayUnmarshall _NdrComplexStructBufferSize@12 = NdrComplexStructBufferSize _NdrComplexStructFree@12 = NdrComplexStructFree _NdrComplexStructMarshall@12 = NdrComplexStructMarshall _NdrComplexStructMemorySize@8 = NdrComplexStructMemorySize _NdrComplexStructUnmarshall@16 = NdrComplexStructUnmarshall _NdrConformantArrayBufferSize@12 = NdrConformantArrayBufferSize _NdrConformantArrayFree@12 = NdrConformantArrayFree _NdrConformantArrayMarshall@12 = NdrConformantArrayMarshall _NdrConformantArrayMemorySize@8 = NdrConformantArrayMemorySize _NdrConformantArrayUnmarshall@16 = NdrConformantArrayUnmarshall _NdrConformantStringBufferSize@12 = NdrConformantStringBufferSize _NdrConformantStringMarshall@12 = NdrConformantStringMarshall _NdrConformantStringMemorySize@8 = NdrConformantStringMemorySize _NdrConformantStringUnmarshall@16 = NdrConformantStringUnmarshall _NdrConformantStructBufferSize@12 = NdrConformantStructBufferSize _NdrConformantStructFree@12 = NdrConformantStructFree _NdrConformantStructMarshall@12 = NdrConformantStructMarshall _NdrConformantStructMemorySize@8 = NdrConformantStructMemorySize _NdrConformantStructUnmarshall@16 = NdrConformantStructUnmarshall _NdrConformantVaryingArrayBufferSize@12 = NdrConformantVaryingArrayBufferSize _NdrConformantVaryingArrayFree@12 = NdrConformantVaryingArrayFree _NdrConformantVaryingArrayMarshall@12 = NdrConformantVaryingArrayMarshall _NdrConformantVaryingArrayMemorySize@8 = NdrConformantVaryingArrayMemorySize _NdrConformantVaryingArrayUnmarshall@16 = NdrConformantVaryingArrayUnmarshall _NdrConformantVaryingStructBufferSize@12 = NdrConformantVaryingStructBufferSize _NdrConformantVaryingStructFree@12 = NdrConformantVaryingStructFree _NdrConformantVaryingStructMarshall@12 = NdrConformantVaryingStructMarshall _NdrConformantVaryingStructMemorySize@8 = NdrConformantVaryingStructMemorySize _NdrConformantVaryingStructUnmarshall@16 = NdrConformantVaryingStructUnmarshall _NdrContextHandleInitialize@8 = NdrContextHandleInitialize _NdrContextHandleSize@12 = NdrContextHandleSize _NdrConvert2@12 = NdrConvert2 _NdrConvert@8 = NdrConvert _NdrCorrelationFree@4 = NdrCorrelationFree _NdrCorrelationInitialize@16 = NdrCorrelationInitialize _NdrCorrelationPass@4 = NdrCorrelationPass _NdrDcomAsyncClientCall = NdrDcomAsyncClientCall _NdrDcomAsyncStubCall@16 = NdrDcomAsyncStubCall _NdrDllCanUnloadNow@4 = NdrDllCanUnloadNow _NdrDllGetClassObject@24 = NdrDllGetClassObject _NdrDllRegisterProxy@12 = NdrDllRegisterProxy _NdrDllUnregisterProxy@12 = NdrDllUnregisterProxy _NdrEncapsulatedUnionBufferSize@12 = NdrEncapsulatedUnionBufferSize _NdrEncapsulatedUnionFree@12 = NdrEncapsulatedUnionFree _NdrEncapsulatedUnionMarshall@12 = NdrEncapsulatedUnionMarshall _NdrEncapsulatedUnionMemorySize@8 = NdrEncapsulatedUnionMemorySize _NdrEncapsulatedUnionUnmarshall@16 = NdrEncapsulatedUnionUnmarshall _NdrFixedArrayBufferSize@12 = NdrFixedArrayBufferSize _NdrFixedArrayFree@12 = NdrFixedArrayFree _NdrFixedArrayMarshall@12 = NdrFixedArrayMarshall _NdrFixedArrayMemorySize@8 = NdrFixedArrayMemorySize _NdrFixedArrayUnmarshall@16 = NdrFixedArrayUnmarshall _NdrFreeBuffer@4 = NdrFreeBuffer _NdrFullPointerFree@8 = NdrFullPointerFree _NdrFullPointerInsertRefId@12 = NdrFullPointerInsertRefId _NdrFullPointerQueryPointer@16 = NdrFullPointerQueryPointer _NdrFullPointerQueryRefId@16 = NdrFullPointerQueryRefId _NdrFullPointerXlatFree@4 = NdrFullPointerXlatFree _NdrFullPointerXlatInit@8 = NdrFullPointerXlatInit _NdrGetBuffer@12 = NdrGetBuffer _NdrGetDcomProtocolVersion@8 = NdrGetDcomProtocolVersion _NdrGetPartialBuffer@4 = NdrGetPartialBuffer _NdrGetPipeBuffer@12 = NdrGetPipeBuffer _NdrGetUserMarshalInfo@12 = NdrGetUserMarshalInfo _NdrHardStructBufferSize@12 = NdrHardStructBufferSize _NdrHardStructFree@12 = NdrHardStructFree _NdrHardStructMarshall@12 = NdrHardStructMarshall _NdrHardStructMemorySize@8 = NdrHardStructMemorySize _NdrHardStructUnmarshall@16 = NdrHardStructUnmarshall _NdrInterfacePointerBufferSize@12 = NdrInterfacePointerBufferSize _NdrInterfacePointerFree@12 = NdrInterfacePointerFree _NdrInterfacePointerMarshall@12 = NdrInterfacePointerMarshall _NdrInterfacePointerMemorySize@8 = NdrInterfacePointerMemorySize _NdrInterfacePointerUnmarshall@16 = NdrInterfacePointerUnmarshall _NdrIsAppDoneWithPipes@4 = NdrIsAppDoneWithPipes _NdrMapCommAndFaultStatus@16 = NdrMapCommAndFaultStatus _NdrMarkNextActivePipe@4 = NdrMarkNextActivePipe _NdrMesProcEncodeDecode = NdrMesProcEncodeDecode _NdrMesProcEncodeDecode2 = NdrMesProcEncodeDecode2 _NdrMesSimpleTypeAlignSize@4 = NdrMesSimpleTypeAlignSize _NdrMesSimpleTypeDecode@12 = NdrMesSimpleTypeDecode _NdrMesSimpleTypeEncode@16 = NdrMesSimpleTypeEncode _NdrMesTypeAlignSize2@20 = NdrMesTypeAlignSize2 _NdrMesTypeAlignSize@16 = NdrMesTypeAlignSize _NdrMesTypeDecode2@20 = NdrMesTypeDecode2 _NdrMesTypeDecode@16 = NdrMesTypeDecode _NdrMesTypeEncode2@20 = NdrMesTypeEncode2 _NdrMesTypeEncode@16 = NdrMesTypeEncode _NdrMesTypeFree2@20 = NdrMesTypeFree2 _NdrNonConformantStringBufferSize@12 = NdrNonConformantStringBufferSize _NdrNonConformantStringMarshall@12 = NdrNonConformantStringMarshall _NdrNonConformantStringMemorySize@8 = NdrNonConformantStringMemorySize _NdrNonConformantStringUnmarshall@16 = NdrNonConformantStringUnmarshall _NdrNonEncapsulatedUnionBufferSize@12 = NdrNonEncapsulatedUnionBufferSize _NdrNonEncapsulatedUnionFree@12 = NdrNonEncapsulatedUnionFree _NdrNonEncapsulatedUnionMarshall@12 = NdrNonEncapsulatedUnionMarshall _NdrNonEncapsulatedUnionMemorySize@8 = NdrNonEncapsulatedUnionMemorySize _NdrNonEncapsulatedUnionUnmarshall@16 = NdrNonEncapsulatedUnionUnmarshall _NdrNsGetBuffer@12 = NdrNsGetBuffer _NdrNsSendReceive@12 = NdrNsSendReceive _NdrOleAllocate@4 = NdrOleAllocate _NdrOleFree@4 = NdrOleFree _NdrPipePull@16 = NdrPipePull _NdrPipePush@12 = NdrPipePush _NdrPipeSendReceive@8 = NdrPipeSendReceive _NdrPipesDone@4 = NdrPipesDone _NdrPipesInitialize@24 = NdrPipesInitialize _NdrPointerBufferSize@12 = NdrPointerBufferSize _NdrPointerFree@12 = NdrPointerFree _NdrPointerMarshall@12 = NdrPointerMarshall _NdrPointerMemorySize@8 = NdrPointerMemorySize _NdrPointerUnmarshall@16 = NdrPointerUnmarshall _NdrProxyErrorHandler@4 = NdrProxyErrorHandler _NdrProxyFreeBuffer@8 = NdrProxyFreeBuffer _NdrProxyGetBuffer@8 = NdrProxyGetBuffer _NdrProxyInitialize@20 = NdrProxyInitialize _NdrProxySendReceive@8 = NdrProxySendReceive _NdrRangeUnmarshall@16 = NdrRangeUnmarshall _NdrRpcSmClientAllocate@4 = NdrRpcSmClientAllocate _NdrRpcSmClientFree@4 = NdrRpcSmClientFree _NdrRpcSmSetClientToOsf@4 = NdrRpcSmSetClientToOsf _NdrRpcSsDefaultAllocate@4 = NdrRpcSsDefaultAllocate _NdrRpcSsDefaultFree@4 = NdrRpcSsDefaultFree _NdrRpcSsDisableAllocate@4 = NdrRpcSsDisableAllocate _NdrRpcSsEnableAllocate@4 = NdrRpcSsEnableAllocate _NdrSendReceive@8 = NdrSendReceive _NdrServerCall2@4 = NdrServerCall2 _NdrServerCall@4 = NdrServerCall _NdrServerContextMarshall@12 = NdrServerContextMarshall _NdrServerContextNewMarshall@16 = NdrServerContextNewMarshall _NdrServerContextNewUnmarshall@8 = NdrServerContextNewUnmarshall _NdrServerContextUnmarshall@4 = NdrServerContextUnmarshall _NdrServerInitialize@12 = NdrServerInitialize _NdrServerInitializeMarshall@8 = NdrServerInitializeMarshall _NdrServerInitializeNew@12 = NdrServerInitializeNew _NdrServerInitializePartial@16 = NdrServerInitializePartial _NdrServerInitializeUnmarshall@12 = NdrServerInitializeUnmarshall _NdrServerMarshall@16 = NdrServerMarshall _NdrServerUnmarshall@24 = NdrServerUnmarshall _NdrSimpleStructBufferSize@12 = NdrSimpleStructBufferSize _NdrSimpleStructFree@12 = NdrSimpleStructFree _NdrSimpleStructMarshall@12 = NdrSimpleStructMarshall _NdrSimpleStructMemorySize@8 = NdrSimpleStructMemorySize _NdrSimpleStructUnmarshall@16 = NdrSimpleStructUnmarshall _NdrSimpleTypeMarshall@12 = NdrSimpleTypeMarshall _NdrSimpleTypeUnmarshall@12 = NdrSimpleTypeUnmarshall _NdrStubCall2@16 = NdrStubCall2 _NdrStubCall@16 = NdrStubCall _NdrStubForwardingFunction@16 = NdrStubForwardingFunction _NdrStubGetBuffer@12 = NdrStubGetBuffer _NdrStubInitialize@16 = NdrStubInitialize _NdrStubInitializeMarshall@12 = NdrStubInitializeMarshall _NdrUserMarshalBufferSize@12 = NdrUserMarshalBufferSize _NdrUserMarshalFree@12 = NdrUserMarshalFree _NdrUserMarshalMarshall@12 = NdrUserMarshalMarshall _NdrUserMarshalMemorySize@8 = NdrUserMarshalMemorySize _NdrUserMarshalSimpleTypeConvert@12 = NdrUserMarshalSimpleTypeConvert _NdrUserMarshalUnmarshall@16 = NdrUserMarshalUnmarshall _NdrVaryingArrayBufferSize@12 = NdrVaryingArrayBufferSize _NdrVaryingArrayFree@12 = NdrVaryingArrayFree _NdrVaryingArrayMarshall@12 = NdrVaryingArrayMarshall _NdrVaryingArrayMemorySize@8 = NdrVaryingArrayMemorySize _NdrVaryingArrayUnmarshall@16 = NdrVaryingArrayUnmarshall _NdrXmitOrRepAsBufferSize@12 = NdrXmitOrRepAsBufferSize _NdrXmitOrRepAsFree@12 = NdrXmitOrRepAsFree _NdrXmitOrRepAsMarshall@12 = NdrXmitOrRepAsMarshall _NdrXmitOrRepAsMemorySize@8 = NdrXmitOrRepAsMemorySize _NdrXmitOrRepAsUnmarshall@16 = NdrXmitOrRepAsUnmarshall _NdrpSetRpcSsDefaults@8 = NdrpSetRpcSsDefaults _RpcAbortAsyncCall@8 = RpcAbortAsyncCall _RpcAsyncAbortCall@8 = RpcAsyncAbortCall _RpcAsyncCancelCall@8 = RpcAsyncCancelCall _RpcAsyncCompleteCall@8 = RpcAsyncCompleteCall _RpcAsyncGetCallStatus@4 = RpcAsyncGetCallStatus _RpcAsyncInitializeHandle@8 = RpcAsyncInitializeHandle _RpcAsyncRegisterInfo@4 = RpcAsyncRegisterInfo _RpcBindingCopy@8 = RpcBindingCopy _RpcBindingFree@4 = RpcBindingFree _RpcBindingFromStringBindingA@8 = RpcBindingFromStringBindingA _RpcBindingFromStringBindingW@8 = RpcBindingFromStringBindingW _RpcBindingInqAuthClientA@24 = RpcBindingInqAuthClientA _RpcBindingInqAuthClientExA@28 = RpcBindingInqAuthClientExA _RpcBindingInqAuthClientExW@28 = RpcBindingInqAuthClientExW _RpcBindingInqAuthClientW@24 = RpcBindingInqAuthClientW _RpcBindingInqAuthInfoA@24 = RpcBindingInqAuthInfoA _RpcBindingInqAuthInfoExA@32 = RpcBindingInqAuthInfoExA _RpcBindingInqAuthInfoExW@32 = RpcBindingInqAuthInfoExW _RpcBindingInqAuthInfoW@24 = RpcBindingInqAuthInfoW _RpcBindingInqObject@8 = RpcBindingInqObject _RpcBindingInqOption@12 = RpcBindingInqOption _RpcBindingReset@4 = RpcBindingReset _RpcBindingServerFromClient@8 = RpcBindingServerFromClient _RpcBindingSetAuthInfoA@24 = RpcBindingSetAuthInfoA _RpcBindingSetAuthInfoExA@28 = RpcBindingSetAuthInfoExA _RpcBindingSetAuthInfoExW@28 = RpcBindingSetAuthInfoExW _RpcBindingSetAuthInfoW@24 = RpcBindingSetAuthInfoW _RpcBindingSetObject@8 = RpcBindingSetObject _RpcBindingSetOption@12 = RpcBindingSetOption _RpcBindingToStringBindingA@8 = RpcBindingToStringBindingA _RpcBindingToStringBindingW@8 = RpcBindingToStringBindingW _RpcBindingVectorFree@4 = RpcBindingVectorFree _RpcCancelAsyncCall@8 = RpcCancelAsyncCall _RpcCancelThread@4 = RpcCancelThread _RpcCancelThreadEx@8 = RpcCancelThreadEx _RpcCertGeneratePrincipalNameA@12 = RpcCertGeneratePrincipalNameA _RpcCertGeneratePrincipalNameW@12 = RpcCertGeneratePrincipalNameW _RpcCompleteAsyncCall@8 = RpcCompleteAsyncCall _RpcEpRegisterA@16 = RpcEpRegisterA _RpcEpRegisterNoReplaceA@16 = RpcEpRegisterNoReplaceA _RpcEpRegisterNoReplaceW@16 = RpcEpRegisterNoReplaceW _RpcEpRegisterW@16 = RpcEpRegisterW _RpcEpResolveBinding@8 = RpcEpResolveBinding _RpcEpUnregister@12 = RpcEpUnregister _RpcGetAsyncCallStatus@4 = RpcGetAsyncCallStatus _RpcIfIdVectorFree@4 = RpcIfIdVectorFree _RpcIfInqId@8 = RpcIfInqId _RpcImpersonateClient@4 = RpcImpersonateClient _RpcInitializeAsyncHandle@8 = RpcInitializeAsyncHandle _RpcMgmtBindingInqParameter@12 = RpcMgmtBindingInqParameter _RpcMgmtBindingSetParameter@12 = RpcMgmtBindingSetParameter _RpcMgmtEnableIdleCleanup@0 = RpcMgmtEnableIdleCleanup _RpcMgmtEpEltInqBegin@24 = RpcMgmtEpEltInqBegin _RpcMgmtEpEltInqDone@4 = RpcMgmtEpEltInqDone _RpcMgmtEpEltInqNextA@20 = RpcMgmtEpEltInqNextA _RpcMgmtEpEltInqNextW@20 = RpcMgmtEpEltInqNextW _RpcMgmtEpUnregister@16 = RpcMgmtEpUnregister _RpcMgmtInqComTimeout@8 = RpcMgmtInqComTimeout _RpcMgmtInqDefaultProtectLevel@8 = RpcMgmtInqDefaultProtectLevel _RpcMgmtInqIfIds@8 = RpcMgmtInqIfIds _RpcMgmtInqParameter@8 = RpcMgmtInqParameter _RpcMgmtInqServerPrincNameA@12 = RpcMgmtInqServerPrincNameA _RpcMgmtInqServerPrincNameW@12 = RpcMgmtInqServerPrincNameW _RpcMgmtInqStats@8 = RpcMgmtInqStats _RpcMgmtIsServerListening@4 = RpcMgmtIsServerListening _RpcMgmtSetAuthorizationFn@4 = RpcMgmtSetAuthorizationFn _RpcMgmtSetCancelTimeout@4 = RpcMgmtSetCancelTimeout _RpcMgmtSetComTimeout@8 = RpcMgmtSetComTimeout _RpcMgmtSetParameter@8 = RpcMgmtSetParameter _RpcMgmtSetServerStackSize@4 = RpcMgmtSetServerStackSize _RpcMgmtStatsVectorFree@4 = RpcMgmtStatsVectorFree _RpcMgmtStopServerListening@4 = RpcMgmtStopServerListening _RpcMgmtWaitServerListen@0 = RpcMgmtWaitServerListen _RpcNetworkInqProtseqsA@4 = RpcNetworkInqProtseqsA _RpcNetworkInqProtseqsW@4 = RpcNetworkInqProtseqsW _RpcNetworkIsProtseqValidA@4 = RpcNetworkIsProtseqValidA _RpcNetworkIsProtseqValidW@4 = RpcNetworkIsProtseqValidW _RpcNsBindingInqEntryNameA@12 = RpcNsBindingInqEntryNameA _RpcNsBindingInqEntryNameW@12 = RpcNsBindingInqEntryNameW _RpcObjectInqType@8 = RpcObjectInqType _RpcObjectSetInqFn@4 = RpcObjectSetInqFn _RpcObjectSetType@8 = RpcObjectSetType _RpcProtseqVectorFreeA@4 = RpcProtseqVectorFreeA _RpcProtseqVectorFreeW@4 = RpcProtseqVectorFreeW _RpcRaiseException@4 = RpcRaiseException _RpcRegisterAsyncInfo@4 = RpcRegisterAsyncInfo _RpcRevertToSelf@0 = RpcRevertToSelf _RpcRevertToSelfEx@4 = RpcRevertToSelfEx _RpcServerInqBindings@4 = RpcServerInqBindings _RpcServerInqDefaultPrincNameA@8 = RpcServerInqDefaultPrincNameA _RpcServerInqDefaultPrincNameW@8 = RpcServerInqDefaultPrincNameW _RpcServerInqIf@12 = RpcServerInqIf _RpcServerListen@12 = RpcServerListen _RpcServerRegisterAuthInfoA@16 = RpcServerRegisterAuthInfoA _RpcServerRegisterAuthInfoW@16 = RpcServerRegisterAuthInfoW _RpcServerRegisterIf2@28 = RpcServerRegisterIf2 _RpcServerRegisterIf@12 = RpcServerRegisterIf _RpcServerRegisterIfEx@24 = RpcServerRegisterIfEx _RpcServerTestCancel@4 = RpcServerTestCancel _RpcServerUnregisterIf@12 = RpcServerUnregisterIf _RpcServerUseAllProtseqs@8 = RpcServerUseAllProtseqs _RpcServerUseAllProtseqsEx@12 = RpcServerUseAllProtseqsEx _RpcServerUseAllProtseqsIf@12 = RpcServerUseAllProtseqsIf _RpcServerUseAllProtseqsIfEx@16 = RpcServerUseAllProtseqsIfEx _RpcServerUseProtseqA@12 = RpcServerUseProtseqA _RpcServerUseProtseqEpA@16 = RpcServerUseProtseqEpA _RpcServerUseProtseqEpExA@20 = RpcServerUseProtseqEpExA _RpcServerUseProtseqEpExW@20 = RpcServerUseProtseqEpExW _RpcServerUseProtseqEpW@16 = RpcServerUseProtseqEpW _RpcServerUseProtseqExA@16 = RpcServerUseProtseqExA _RpcServerUseProtseqExW@16 = RpcServerUseProtseqExW _RpcServerUseProtseqIfA@16 = RpcServerUseProtseqIfA _RpcServerUseProtseqIfExA@20 = RpcServerUseProtseqIfExA _RpcServerUseProtseqIfExW@20 = RpcServerUseProtseqIfExW _RpcServerUseProtseqIfW@16 = RpcServerUseProtseqIfW _RpcServerUseProtseqW@12 = RpcServerUseProtseqW _RpcServerYield@0 = RpcServerYield _RpcSmAllocate@8 = RpcSmAllocate _RpcSmClientFree@4 = RpcSmClientFree _RpcSmDestroyClientContext@4 = RpcSmDestroyClientContext _RpcSmDisableAllocate@0 = RpcSmDisableAllocate _RpcSmEnableAllocate@0 = RpcSmEnableAllocate _RpcSmFree@4 = RpcSmFree _RpcSmGetThreadHandle@4 = RpcSmGetThreadHandle _RpcSmSetClientAllocFree@8 = RpcSmSetClientAllocFree _RpcSmSetThreadHandle@4 = RpcSmSetThreadHandle _RpcSmSwapClientAllocFree@16 = RpcSmSwapClientAllocFree _RpcSsAllocate@4 = RpcSsAllocate _RpcSsDestroyClientContext@4 = RpcSsDestroyClientContext _RpcSsDisableAllocate@0 = RpcSsDisableAllocate _RpcSsDontSerializeContext@0 = RpcSsDontSerializeContext _RpcSsEnableAllocate@0 = RpcSsEnableAllocate _RpcSsFree@4 = RpcSsFree _RpcSsGetContextBinding@8 = RpcSsGetContextBinding _RpcSsGetThreadHandle@0 = RpcSsGetThreadHandle _RpcSsSetClientAllocFree@8 = RpcSsSetClientAllocFree _RpcSsSetThreadHandle@4 = RpcSsSetThreadHandle _RpcSsSwapClientAllocFree@16 = RpcSsSwapClientAllocFree _RpcStringBindingComposeA@24 = RpcStringBindingComposeA _RpcStringBindingComposeW@24 = RpcStringBindingComposeW _RpcStringBindingParseA@24 = RpcStringBindingParseA _RpcStringBindingParseW@24 = RpcStringBindingParseW _RpcStringFreeA@4 = RpcStringFreeA _RpcStringFreeW@4 = RpcStringFreeW _RpcTestCancel@0 = RpcTestCancel _TowerConstruct@24 = TowerConstruct _TowerExplode@24 = TowerExplode _UuidCompare@12 = UuidCompare _UuidCreate@4 = UuidCreate _UuidCreateNil@4 = UuidCreateNil _UuidCreateSequential@4 = UuidCreateSequential _UuidEqual@12 = UuidEqual _UuidFromStringA@8 = UuidFromStringA _UuidFromStringW@8 = UuidFromStringW _UuidHash@8 = UuidHash _UuidIsNil@8 = UuidIsNil _UuidToStringA@8 = UuidToStringA _UuidToStringW@8 = UuidToStringW _char_array_from_ndr@16 = char_array_from_ndr _char_from_ndr@8 = char_from_ndr _data_from_ndr@16 = data_from_ndr _data_into_ndr@16 = data_into_ndr _data_size_ndr@16 = data_size_ndr _double_array_from_ndr@16 = double_array_from_ndr _double_from_ndr@8 = double_from_ndr _enum_from_ndr@8 = enum_from_ndr _float_array_from_ndr@16 = float_array_from_ndr _float_from_ndr@8 = float_from_ndr _long_array_from_ndr@16 = long_array_from_ndr _long_from_ndr@8 = long_from_ndr _long_from_ndr_temp@12 = long_from_ndr_temp _short_array_from_ndr@16 = short_array_from_ndr _short_from_ndr@8 = short_from_ndr _short_from_ndr_temp@12 = short_from_ndr_temp _tree_into_ndr@16 = tree_into_ndr _tree_peek_ndr@16 = tree_peek_ndr _tree_size_ndr@16 = tree_size_ndr ldc-1.1.0-beta3-src/runtime/druntime/benchmark/0000775000175000017500000000000012776214756017415 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/0000775000175000017500000000000012776214756020776 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/ptr.d0000664000175000017500000000104112776214756021744 0ustar kaikai/** * Benchmark ptr hashing. * * Copyright: Copyright Martin Nowak 2011 - 2015. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ import std.random; void main(string[] args) { auto rnd = Xorshift32(33); int[int* ] aa; auto keys = new int*[](32768); foreach (ref k; keys) k = new int; foreach (_; 0 .. 10) foreach (__; 0 .. 100_000) ++aa[keys[uniform(0, keys.length, rnd)]]; if (aa.length != keys.length) assert(0); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/stomper.d0000664000175000017500000000245312776214756022640 0ustar kaikai/** * Benchmark hash with cache stomping. * * Copyright: Copyright Martin Nowak 2015 - . * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ import std.file, std.algorithm, std.random, std.math; // exponential distribution around mean struct ExpRandom { double mean; Xorshift32 gen; this(double mean) { this.mean = mean; gen = Xorshift32(unpredictableSeed); } size_t front() { return cast(size_t)(mean * -log(uniform!"()"(0.0, 1.0, gen)) + 0.5); } alias gen this; } struct CacheStomper { ExpRandom rnd; size_t i; ubyte[] mem; this(size_t avgBytesPerCall) { rnd = ExpRandom(avgBytesPerCall / 64.0); mem = new ubyte[](32 * 1024 * 1024); } void stomp() { immutable n = rnd.front(); rnd.popFront(); foreach (_; 0 .. n) ++mem[(i += 64) & ($ - 1)]; } } void main(string[] args) { auto path = args.length > 1 ? args[1] : "extra-files/dante.txt"; auto words = splitter(cast(string) read(path), ' '); size_t[string] aa; auto stomper = CacheStomper(1000); foreach (_; 0 .. 10) { foreach (word; words) { ++aa[word]; stomper.stomp(); } } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/l3cache.d0000664000175000017500000000057012776214756022447 0ustar kaikai/** * Benchmark with big bucket array (> L3 cache). * * Copyright: Copyright Martin Nowak 2011 - 2015. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ void main(string[] args) { int[int] aa; foreach (_; 0 .. 5) { foreach (i; 0 .. 1_000_000) { ++aa[i]; } } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/int.d0000664000175000017500000000067412776214756021744 0ustar kaikai/** * Benchmark int hashing. * * Copyright: Copyright Martin Nowak 2011 - 2015. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ import std.random; void main(string[] args) { auto rnd = Xorshift32(33); int[int] aa; foreach (_; 0 .. 10) foreach (__; 0 .. 100_000) ++aa[uniform(0, 100_000, rnd)]; if (aa.length != 99998) assert(0); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/obj.d0000664000175000017500000000123612776214756021717 0ustar kaikai/** * Benchmark class hashing. * * Copyright: Copyright Martin Nowak 2011 - 2015. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ import std.random; void main(string[] args) { auto rnd = Xorshift32(33); Object[Object] aa; auto objs = new Object[](32768); foreach (ref o; objs) o = new Object; foreach (_; 0 .. 10) { foreach (__; 0 .. 100_000) { auto k = objs[uniform(0, objs.length, rnd)]; auto v = objs[uniform(0, objs.length, rnd)]; aa[k] = v; } } if (aa.length != objs.length) assert(0); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/bulk.d0000664000175000017500000000373712776214756022112 0ustar kaikai/** * Benchmark bulk filling of AA. * * Copyright: Copyright Martin Nowak 2011 - 2011. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ import std.random, std.typetuple, std.conv; version (VERBOSE) import std.datetime, std.stdio; alias ValueTuple = TypeTuple!(void[0], uint, void*, Object, ubyte[16], ubyte[64]); size_t Size = 2 ^^ 16; size_t trot; void runTest(V)(ref V v) { version (VERBOSE) { StopWatch sw; writef("%15-s %8u", V.stringof, Size / V.sizeof); void start() { sw.reset; sw.start; } void stop() { sw.stop; writef(" %5u.%03u", sw.peek.seconds, sw.peek.msecs % 1000); } } else { static void start() {} static void stop() {} } V[size_t] aa; start(); foreach(k; 0 .. Size) { aa[k] = v; } stop(); aa.destroy(); start(); foreach_reverse(k; 0 .. Size) { aa[k] = v; } stop(); aa.destroy(); start(); foreach(ref k; 0 .. trot * Size) { aa[k] = v; k += trot - 1; } stop(); aa.destroy(); start(); foreach_reverse(ref k; 0 .. trot * Size) { k -= trot - 1; aa[k] = v; } stop(); aa.destroy(); version (VERBOSE) writeln(); } void main(string[] args) { trot = 7; version (VERBOSE) { writefln("==================== Bulk Test ===================="); writefln("Filling %s KiB, times in s.", Size/1024); writefln("Key step %27d | %7d | %7d | %7d", 1, -1, cast(int)trot, -cast(int)trot); writefln("%15-s | %8s | %7s | %7s | %7s | %7s", "Type", "num", "step", "revstep", "trot", "revtrot"); }; ValueTuple valTuple; foreach(v; valTuple) runTest(v); version (VERBOSE) { writefln("==================== Test Done ===================="); } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/resize.d0000664000175000017500000000210712776214756022444 0ustar kaikai/** * Benchmark increasing/decreasing AA size. * * Copyright: Copyright Martin Nowak 2011 - 2011. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ import std.random; enum Count = 256; enum MinSize = 512; enum MaxSize = 16_384; void runTest(RNG)(RNG gen) { bool[uint] aa; sizediff_t diff = MinSize; size_t cnt = Count; do { while (diff > 0) { auto key = uniform(0, MaxSize, gen); if (!(key in aa)) { aa[key] = true; --diff; } } while (diff < 0) { auto key = uniform(0, MaxSize, gen); if (!!(key in aa)) { aa.remove(key); ++diff; } } auto nsize = uniform(MinSize, MaxSize, gen); diff = nsize - aa.length; } while (--cnt); } void main() { version (RANDOMIZE) auto gen = Xorshift32(unpredictableSeed); else auto gen = Xorshift32(33); runTest(gen); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/bigval.d0000664000175000017500000000057212776214756022413 0ustar kaikai/** * Benchmark AA with big values. * * Copyright: Copyright Martin Nowak 2011 - 2015. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ void main(string[] args) { static struct V { ubyte[1024] data; } V[int] aa; V v; foreach (_; 0 .. 10) foreach (i; 0 .. 100_000) aa[i] = v; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/aabench/string.d0000664000175000017500000000111212776214756022444 0ustar kaikai/** * Benchmark string hashing. * * Copyright: Copyright Martin Nowak 2011 - 2015. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ import std.algorithm, std.file; void runTest(R)(R words) { size_t[string] aa; foreach (_; 0 .. 10) foreach (word; words) ++aa[word]; if (aa.length != 24900) assert(0); } void main(string[] args) { auto path = args.length > 1 ? args[1] : "extra-files/dante.txt"; auto words = splitter(cast(string) read(path), ' '); runTest(words); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/0000775000175000017500000000000012776214756021006 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/slist.d0000664000175000017500000000222112776214756022306 0ustar kaikai/** * Copyright: Copyright Rainer Schuetze 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Rainer Schuetze * * This test reads a text file, then splits the result into white space delimited words. * The result is a single linked list of strings referencing the full text. * Regarding GC activity, this test probes collection of linked lists. */ import std.stdio; import std.conv; import std.file; import std.string; import std.exception; struct Node { string token; Node* next; } void main(string[] args) { string txt = cast(string) std.file.read(args.length > 1 ? args[1] : "extra-files/dante.txt"); uint cnt = args.length > 2 ? to!uint(args[2]) : 100; uint allwords = 0; for(uint i = 0; i < cnt; i++) { Node* firstNode; auto words = txt.split(); foreach(w; words) { Node* n = new Node; n.token = w; n.next = firstNode; firstNode = n; } for(Node* p = firstNode; p; p = p.next) allwords++; } enforce(allwords == (args.length > 3 ? to!size_t(args[3]) : 9767600)); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/rand_large.d0000664000175000017500000000173012776214756023252 0ustar kaikai/** * Benchmark on uniformly distributed, random large allocations. * * Copyright: Copyright David Simcha 2011 - 2011. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: David Simcha */ /* Copyright David Simcha 2011 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ import std.random, core.memory, std.stdio; enum nIter = 1000; void main() { version (RANDOMIZE) auto rnd = Random(unpredictableSeed); else auto rnd = Random(1202387523); auto ptrs = new void*[1024]; // Allocate 1024 large blocks with size uniformly distributed between 1 // and 128 kilobytes. foreach(i; 0..nIter) { foreach(ref ptr; ptrs) { immutable sz = uniform(1024, 128 * 1024 + 1, rnd); ptr = GC.malloc(sz, GC.BlkAttr.NO_SCAN); } } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.d0000664000175000017500000000137512776214756023007 0ustar kaikaiimport vdc.semantic; import std.random, std.conv, std.file, std.path; struct FalsePointers { string s; ubyte[40960] data; } FalsePointers* ptrs; void main(string[] argv) { size_t nIter = 20; if(argv.length > 2) nIter = to!size_t(argv[2]); // create some random data as false pointer simulation version (RANDOMIZE) auto rnd = Random(unpredictableSeed); else auto rnd = Random(2929088778); ptrs = new FalsePointers; foreach(ref b; ptrs.data) b = cast(ubyte) uniform(0, 255, rnd); Project prj = new Project; foreach(i; 0..nIter) { foreach(string name; dirEntries(buildPath("gcbench", "vdparser.extra"), "*.d", SpanMode.depth)) prj.addAndParseFile(name); } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/tree2.d0000664000175000017500000000144612776214756022201 0ustar kaikai/** * Another tree building benchmark. Thanks again to Bearophile. * * Copyright: Copyright David Simcha 2011 - 2011. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: David Simcha */ /* Copyright David Simcha 2011 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ import std.stdio, std.container, std.range, std.conv, std.exception; void main(string[] args) { int n = args.length > 1 ? to!int(args[1]) : 7000000; int range = args.length > 2 ? to!int(args[2]) : 100; auto t = redBlackTree!int(); for (int i = 0; i < n; i++) { if (i > range) t.removeFront(); t.insert(i); } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/conmsg.d0000664000175000017500000000373312776214756022447 0ustar kaikai/** * This benchmarks GC in a producer-consumer program. * * Copyright: Copyright Martin Nowak 2014 -. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ import std.algorithm, std.concurrency, std.conv, std.file, std.json, std.range; JSONValue buildVal(in dchar[] word) { JSONValue[string] res; res["word"] = word.to!string; res["length"] = word.length; auto pos = new size_t[word.length]; foreach (i; 0 .. pos.length) pos[i] = i; res["array"] = pos; return JSONValue(res); } void producer(Tid consumer) { auto text = cast(string)read("extra-files/dante.txt"); foreach (word; text.splitter.map!(to!(dchar[]))) { foreach (_; 0 .. 3) { immutable val = buildVal(word); consumer.send(val); if (!nextPermutation(word)) break; } } } void serialize(in JSONValue val, ref ubyte[] buf) { with (JSON_TYPE) switch (val.type) { case OBJECT: foreach (k, v; val.object) { buf ~= cast(ubyte[])k; serialize(v, buf); } break; case ARRAY: foreach (v; val.array) serialize(v, buf); break; case UINTEGER: ulong v = val.uinteger; buf ~= (cast(ubyte*)&v)[0 .. v.sizeof]; break; case STRING: buf ~= cast(ubyte[])val.str; break; default: assert(0); } } struct Socket { static void send(ubyte[] buf) { _buf = buf; } static ubyte[] _buf; // keep a reference } void log(string s) { __gshared size_t dummy; dummy = s.length; } void consumer() { scope (failure) assert(0); while (true) { auto msg = receiveOnly!(Variant); if (msg.peek!OwnerTerminated) return; auto val = msg.get!(immutable JSONValue); ubyte[] buf; serialize(val, buf); Socket.send(buf); } } void main(string[] args) { producer(spawn(&consumer)); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/dlist.d0000664000175000017500000000271012776214756022272 0ustar kaikai/** * Copyright: Copyright Rainer Schuetze 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Rainer Schuetze * * This test reads a text file, then splits the result into white space delimited words. * The result is a double linked list of strings referencing the full text. * Regarding GC activity, this test probes collection of linked lists. */ import std.stdio; import std.conv; import std.file; import std.string; import std.exception; // double-linked list with circular next/prev pointers struct Node { string token; Node* next; // first in root Node* prev; // last in root } void main(string[] args) { string txt = cast(string) std.file.read(args.length > 1 ? args[1] : "extra-files/dante.txt"); uint cnt = args.length > 2 ? to!uint(args[2]) : 100; uint allwords = 0; for(uint i = 0; i < cnt; i++) { Node* rootNode = new Node; rootNode.next = rootNode; rootNode.prev = rootNode; auto words = txt.split(); foreach(w; words) { Node* n = new Node; n.token = w; // insert at end of list n.next = rootNode; n.prev = rootNode.prev; rootNode.prev.next = n; rootNode.prev = n; } for(Node* p = rootNode.next; p != rootNode; p = p.next) allwords++; } enforce(allwords == (args.length > 3 ? to!size_t(args[3]) : 9767600)); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/rand_small.d0000664000175000017500000000203412776214756023266 0ustar kaikai/** * Benchmark on uniformly distributed, random small allocations. * * Copyright: Copyright David Simcha 2011 - 2011. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: David Simcha */ /* Copyright David Simcha 2011 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ import std.random, core.memory, std.stdio, std.conv; void main(string[] args) { size_t nIter = 1000; if(args.length > 1) nIter = to!size_t(args[1]); version (RANDOMIZE) auto rnd = Random(unpredictableSeed); else auto rnd = Random(2929088778); auto ptrs = new void*[4096]; // Allocate large blocks with size uniformly distributed between 8 // and 2048 bytes. foreach(i; 0..nIter) { foreach(ref ptr; ptrs) { immutable sz = uniform(8, 2048, rnd); ptr = GC.malloc(sz, GC.BlkAttr.NO_SCAN); } } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/words.d0000664000175000017500000000177112776214756022317 0ustar kaikai/** * Copyright: Copyright Rainer Schuetze 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Rainer Schuetze * * This test reads a text file, duplicates it in memory the given number of times, * then splits the result into white space delimited words. The result is an array * of strings referencing the full text. * Regarding GC activity, this test probes concatenation of long strings and appending * to a large array of strings. */ import std.stdio; import std.conv; import std.file; import std.string; import std.exception; void main(string[] args) { string txt = cast(string)std.file.read(args.length > 1 ? args[1] : "extra-files/dante.txt"); uint cnt = args.length > 2 ? to!uint(args[2]) : 100; string data; for(int b = 31; b >= 0; b--) { data ~= data; if(cnt & (1 << b)) data ~= txt; } auto words = data.split().length; enforce(words == (args.length > 3 ? to!size_t(args[3]) : 9767600)); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/tree1.d0000664000175000017500000000366612776214756022206 0ustar kaikai/** * Benchmark the GC on tree building. Thanks to Bearophile. * * Copyright: Copyright David Simcha 2011 - 2011. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: David Simcha */ /* Copyright David Simcha 2011 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ import std.stdio, std.conv, std.exception; class TreeNode { private TreeNode left, right; private int item; this(int item) { this.item = item; } this(TreeNode left, TreeNode right, int item){ this.left = left; this.right = right; this.item = item; } private static TreeNode bottomUpTree(int item, int depth) { if (depth > 0) { return new TreeNode(bottomUpTree(2 * item - 1, depth - 1), bottomUpTree(2 * item, depth - 1), item); } else { return new TreeNode(item); } } private int itemCheck() { if (left is null) return item; else return item + left.itemCheck() - right.itemCheck(); } } void main(string[] args) { int n = args.length > 1 ? to!int(args[1]) : 14; int minDepth = args.length > 2 ? to!int(args[2]) : 4; int maxDepth = (minDepth + 2 > n) ? minDepth + 2 : n; int stretchDepth = maxDepth + 1; int check = (TreeNode.bottomUpTree(0,stretchDepth)).itemCheck(); TreeNode longLivedTree = TreeNode.bottomUpTree(0, maxDepth); for (int depth = minDepth; depth <= maxDepth; depth += 2) { int iterations = 1 << (maxDepth - depth + minDepth); check = 0; foreach (int i; 1 .. iterations+1) { check += (TreeNode.bottomUpTree(i, depth)).itemCheck(); check += (TreeNode.bottomUpTree(-i, depth)).itemCheck(); } } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/conalloc.d0000664000175000017500000000237212776214756022751 0ustar kaikai/** * The goal of this program is to do very CPU intensive work with allocations in threads * * Copyright: Copyright Leandro Lucarella 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Leandro Lucarella */ import core.thread; import core.atomic; import std.conv; import std.file; import std.digest.sha; auto N = 50; auto NT = 4; __gshared ubyte[] BYTES; shared(int) running; // Atomic void main(string[] args) { auto fname = "extra-files/dante.txt"; if (args.length > 3) fname = args[3]; if (args.length > 2) NT = to!int(args[2]); if (args.length > 1) N = to!int(args[1]); N /= NT; atomicStore(running, NT); BYTES = cast(ubyte[]) std.file.read(fname); auto threads = new Thread[NT]; foreach(ref thread; threads) { thread = new Thread(&doSha); thread.start(); } while (atomicLoad(running)) { auto a = new ubyte[](BYTES.length); a[] = cast(ubyte[]) BYTES[]; Thread.yield(); } foreach(thread; threads) thread.join(); } void doSha() { for (size_t i = 0; i < N; i++) { auto sha = new SHA1; // undefined identifier SHA512? sha.put(BYTES); } running += -1; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/conappend.d0000664000175000017500000000254412776214756023127 0ustar kaikai/** * The goal of this program is to do concurrent allocations in threads * * Copyright: Copyright Leandro Lucarella 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Leandro Lucarella */ import core.thread; import core.atomic; import std.conv; import std.file; import std.exception; auto N = 50; auto NT = 4; __gshared ubyte[] BYTES; shared(int) running; // Atomic void main(string[] args) { auto fname = "extra-files/dante.txt"; if (args.length > 3) fname = args[3]; if (args.length > 2) NT = to!(int)(args[2]); if (args.length > 1) N = to!(int)(args[1]); N /= NT; atomicStore(running, NT); BYTES = cast(ubyte[]) std.file.read(fname); auto threads = new Thread[NT]; foreach(ref thread; threads) { thread = new Thread(&doAppend); thread.start(); } while (atomicLoad(running)) { auto a = new ubyte[](BYTES.length); a[] = cast(ubyte[]) BYTES[]; Thread.yield(); } foreach(thread; threads) thread.join(); } void doAppend() { for (size_t i = 0; i < N; i++) { int[] arr; for (int j = 0; j < 1000; j++) arr ~= j; int sum = 0; foreach (a; arr) sum += a; enforce(sum == 1000 * 999 / 2, "bad sum"); } running += -1; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/testgc3.d0000664000175000017500000000202612776214756022527 0ustar kaikai/** * taken from the dmd test suite, added options to run multiple times * * This test creates 10000 associative arrays uint[uint] multiple times * collecting arrays created in previous iterations. * A 32-bit process can be sensitive to false pointers as hash values * in the AAs can reference arbitrary addresses. */ import std.c.stdio; import std.conv; import std.exception; int main(string[] args) { int cnt = 4; int num = 200; if (args.length > 1) cnt = to!int(args[1]); if (args.length > 2) num = to!int(args[2]); ulong sum; for(int n = 0; n < cnt; n++) { uint[uint][] aa; aa.length = 10000; int aacnt = num * 10000; for(int i = 0; i < aacnt; i++) { size_t j = i % aa.length; uint k = i; uint l = i; aa[j][k] = l; } sum = 0; foreach(s; aa[4711]) sum += s; enforce(sum == 4711 * num + 10000 * num * (num - 1) / 2); aa[] = null; } return 0; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/huge_single.d0000664000175000017500000000110512776214756023441 0ustar kaikai/** * Benchmark on one huge allocation. * * Copyright: Copyright David Simcha 2011 - 2011. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: David Simcha */ /* Copyright David Simcha 2011 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ import std.stdio, core.memory; void main(string[] args) { enum mul = 1000; auto ptr = GC.malloc(mul * 1_048_576, GC.BlkAttr.NO_SCAN); GC.collect(); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/0000775000175000017500000000000012776214756023756 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/0000775000175000017500000000000012776214756024532 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/versions.d0000664000175000017500000000636612776214756026562 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.versions; __gshared int[string] predefinedVersions; alias AssociativeArray!(string, int) _wa1; // fully instantiate type info static @property int[string] sPredefinedVersions() { if(!predefinedVersions) { // see http://dlang.org/version.html // 1: always defined // -1: always undefined // 0: to be determined by compiler option predefinedVersions = [ "DigitalMars" : 0, "GNU" : 0, "LDC" : 0, "SDC" : -1, "D_NET" : -1, "Windows" : 1, "Win32" : 0, "Win64" : 0, "linux" : -1, "OSX" : -1, "FreeBSD" : -1, "OpenBSD" : -1, "NetBSD" : -1, "DragonFlyBSD" : -1, "BSD" : -1, "Solaris" : -1, "Posix" : -1, "AIX" : -1, "Haiku" : -1, "SkyOS" : -1, "SysV3" : -1, "SysV4" : -1, "Hurd" : -1, "Android" : -1, "Cygwin" : -1, "MinGW" : -1, "X86" : 0, "X86_64" : 0, "ARM" : -1, "ARM_Thumb" : -1, "ARM_SoftFloat" : -1, "ARM_SoftFP" : -1, "ARM_HardFloat" : -1, "AArch64" : -1, "Epiphany" : -1, "PPC" : -1, "PPC_SoftFloat" : -1, "PPC_HardFloat" : -1, "PPC64" : -1, "IA64" : -1, "MIPS32" : -1, "MIPS64" : -1, "MIPS_O32" : -1, "MIPS_N32" : -1, "MIPS_O64" : -1, "MIPS_N64" : -1, "MIPS_EABI" : -1, "MIPS_SoftFloat" : -1, "MIPS_HardFloat" : -1, "NVPTX" : -1, "NVPTX64" : -1, "SPARC" : -1, "SPARC_V8Plus" : -1, "SPARC_SoftFloat" : -1, "SPARC_HardFloat" : -1, "SPARC64" : -1, "S390" : -1, "SystemZ" : -1, "HPPA" : -1, "HPPA64" : -1, "SH" : -1, "SH64" : -1, "Alpha" : -1, "Alpha_SoftFloat" : -1, "Alpha_HardFloat" : -1, "LittleEndian" : 1, "BigEndian" : -1, "ELFv1" : -1, "ELFv2" : -1, "CRuntime_DigitalMars" : 0, "CRuntime_Microsoft" : 0, "CRuntime_Glibc" : -1, "D_Coverage" : 0, "D_Ddoc" : 0, "D_InlineAsm_X86" : 0, "D_InlineAsm_X86_64" : 0, "D_LP64" : 0, "D_X32" : -1, "D_HardFloat" : 1, "D_SoftFloat" : -1, "D_PIC" : -1, "D_SIMD" : 1, "D_Version2" : 1, "D_NoBoundsChecks" : 0, "unittest" : 0, "assert" : 0, "none" : -1, "all" : 1, ]; } return predefinedVersions; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/lexer.d0000664000175000017500000011317312776214756026024 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.lexer; import std.ascii; import std.uni : isAlpha; import std.utf; import std.conv; enum supportUnorderedCompareOps = false; // current limitations: // - nested comments must not nest more than 255 times // - braces must not nest more than 4095 times inside token string // - number of different delimiters must not exceed 256 enum TokenCat : int { // assumed to match beginning of visuald.colorizer.TokenColor Text, Keyword, Comment, Identifier, String, Literal, Text2, Operator, } struct TokenInfo { TokenCat type; int tokid; int StartIndex; int EndIndex; } /////////////////////////////////////////////////////////////////////////////// struct Lexer { enum State { kWhite, kBlockComment, kNestedComment, kStringCStyle, kStringWysiwyg, kStringAltWysiwyg, kStringDelimited, kStringDelimitedNestedBracket, kStringDelimitedNestedParen, kStringDelimitedNestedBrace, kStringDelimitedNestedAngle, kStringTokenFirst, // after 'q', but before '{' to pass '{' as single operator kStringToken, // encoded by tokenStringLevel > 0 kStringHex, // for now, treated as State.kStringWysiwyg kStringEscape, // removed in D2.026, not supported } // lexer scan state is: ___TTNNS // TT: token string nesting level // NN: comment nesting level/string delimiter id // S: State static State scanState(int state) { return cast(State) (state & 0xf); } static int nestingLevel(int state) { return (state >> 4) & 0xff; } // used for state kNestedComment and kStringDelimited static int tokenStringLevel(int state) { return (state >> 12) & 0xff; } static int getOtherState(int state) { return (state & 0xfff00000); } bool mTokenizeTokenString = true; bool mSplitNestedComments = true; bool mAllowDollarInIdentifiers = false; static int toState(State s, int nesting, int tokLevel, int otherState) { static assert(State.kStringToken <= 15); assert(s >= State.kWhite && s <= State.kStringToken); assert(nesting < 32); assert(tokLevel < 32); return s | ((nesting & 0xff) << 4) | ((tokLevel & 0xff) << 12) | otherState; } static bool isStringState(State state) { return state >= State.kStringCStyle; } static bool isCommentState(State state) { return state == State.kBlockComment || state == State.kNestedComment; } static string[256] s_delimiters; static int s_nextDelimiter; static int getDelimiterIndex(string delim) { int idx = (s_nextDelimiter - 1) & 0xff; for( ; idx != s_nextDelimiter; idx = (idx - 1) & 0xff) if(delim == s_delimiters[idx]) return idx; s_nextDelimiter = (s_nextDelimiter + 1) & 0xff; s_delimiters[idx] = delim; return idx; } int scanIdentifier(S)(S text, size_t startpos, ref size_t pos) { int pid; return scanIdentifier(text, startpos, pos, pid); } int scanIdentifier(S)(S text, size_t startpos, ref size_t pos, ref int pid) { while(pos < text.length) { auto nextpos = pos; dchar ch = decode(text, nextpos); if(!isIdentifierCharOrDigit(ch)) break; pos = nextpos; } string ident = toUTF8(text[startpos .. pos]); if(findKeyword(ident, pid)) return pid == TOK_is ? TokenCat.Operator : TokenCat.Keyword; if(findSpecial(ident, pid)) return TokenCat.String; pid = TOK_Identifier; return TokenCat.Identifier; } static int scanOperator(S)(S text, size_t startpos, ref size_t pos, ref int pid) { size_t len; int id = parseOperator(text, startpos, len); if(id == TOK_error) return TokenCat.Text; pid = id; pos = startpos + len; return TokenCat.Operator; } static dchar trydecode(S)(S text, ref size_t pos) { if(pos >= text.length) return 0; dchar ch = decode(text, pos); return ch; } static void skipDigits(S)(S text, ref size_t pos, int base) { while(pos < text.length) { auto nextpos = pos; dchar ch = decode(text, nextpos); if(ch != '_') { if(base < 16 && (ch < '0' || ch >= '0' + base)) break; else if(base == 16 && !isHexDigit(ch)) break; } pos = nextpos; } } static int scanNumber(S)(S text, dchar ch, ref size_t pos) { int pid; return scanNumber(text, ch, pos, pid); } static int scanNumber(S)(S text, dchar ch, ref size_t pos, ref int pid) { // pos after first digit int base = 10; size_t nextpos = pos; if(ch == '.') goto L_float; if(ch == '0') { size_t prevpos = pos; ch = trydecode(text, pos); ch = toLower(ch); if(ch == 'b') base = 2; else if (ch == 'x') base = 16; else { base = 8; pos = prevpos; } } // pos now after prefix or first digit skipDigits(text, pos, base); // pos now after last digit of integer part nextpos = pos; ch = trydecode(text, nextpos); if((base == 10 && toLower(ch) == 'e') || (base == 16 && toLower(ch) == 'p')) goto L_exponent; if(base >= 8 && ch == '.') // ".." is the slice token { { // mute errors about goto skipping declaration size_t trypos = nextpos; dchar trych = trydecode(text, trypos); if (trych == '.') goto L_integer; //if (isAlpha(trych) || trych == '_' || (p[1] & 0x80)) // goto done; } // float if(base < 10) base = 10; L_float: pos = nextpos; skipDigits(text, pos, base); nextpos = pos; ch = trydecode(text, nextpos); if((base == 10 && toLower(ch) == 'e') || (base == 16 && toLower(ch) == 'p')) { L_exponent: // exponent pos = nextpos; ch = trydecode(text, nextpos); if(ch == '-' || ch == '+') pos = nextpos; skipDigits(text, pos, 10); } // suffix nextpos = pos; ch = trydecode(text, nextpos); if(ch == 'L' || toUpper(ch) == 'F') { L_floatLiteral: pos = nextpos; ch = trydecode(text, nextpos); } if(ch == 'i') L_complexLiteral: pos = nextpos; pid = TOK_FloatLiteral; } else { // check integer suffix if(ch == 'i') goto L_complexLiteral; if(toUpper(ch) == 'F') goto L_floatLiteral; if(toUpper(ch) == 'U') { pos = nextpos; ch = trydecode(text, nextpos); if(ch == 'L') pos = nextpos; } else if (ch == 'L') { pos = nextpos; ch = trydecode(text, nextpos); if(ch == 'i') goto L_complexLiteral; if(toUpper(ch) == 'U') pos = nextpos; } L_integer: pid = TOK_IntegerLiteral; } return TokenCat.Literal; } version(unspecified) unittest { int pid; size_t pos = 1; auto cat = scanNumber("0.0i", '0', pos, pid); assert(pid == TOK_FloatLiteral); pos = 1; cat = scanNumber("0.i", '0', pos, pid); assert(pid == TOK_IntegerLiteral); } static State scanBlockComment(S)(S text, ref size_t pos) { while(pos < text.length) { dchar ch = decode(text, pos); while(ch == '*') { if (pos >= text.length) return State.kBlockComment; ch = decode(text, pos); if(ch == '/') return State.kWhite; } } return State.kBlockComment; } State scanNestedComment(S)(S text, size_t startpos, ref size_t pos, ref int nesting) { while(pos < text.length) { dchar ch = decode(text, pos); while(ch == '/') { if (pos >= text.length) return State.kNestedComment; ch = decode(text, pos); if(ch == '+') { if(mSplitNestedComments && pos > startpos + 2) { pos -= 2; return State.kNestedComment; } nesting++; goto nextChar; } } while(ch == '+') { if (pos >= text.length) return State.kNestedComment; ch = decode(text, pos); if(ch == '/') { nesting--; if(nesting == 0) return State.kWhite; if(mSplitNestedComments) return State.kNestedComment; break; } } nextChar:; } return State.kNestedComment; } static State scanStringPostFix(S)(S text, ref size_t pos) { size_t nextpos = pos; dchar ch = trydecode(text, nextpos); if(ch == 'c' || ch == 'w' || ch == 'd') pos = nextpos; return State.kWhite; } static State scanStringWysiwyg(S)(S text, ref size_t pos) { while(pos < text.length) { dchar ch = decode(text, pos); if(ch == '"') return scanStringPostFix(text, pos); } return State.kStringWysiwyg; } static State scanStringAltWysiwyg(S)(S text, ref size_t pos) { while(pos < text.length) { dchar ch = decode(text, pos); if(ch == '`') return scanStringPostFix(text, pos); } return State.kStringAltWysiwyg; } static State scanStringCStyle(S)(S text, ref size_t pos, dchar term) { while(pos < text.length) { dchar ch = decode(text, pos); if(ch == '\\') { if (pos >= text.length) break; ch = decode(text, pos); } else if(ch == term) return scanStringPostFix(text, pos); } return State.kStringCStyle; } State startDelimiterString(S)(S text, ref size_t pos, ref int nesting) { nesting = 1; auto startpos = pos; dchar ch = trydecode(text, pos); State s = State.kStringDelimited; if(ch == '[') s = State.kStringDelimitedNestedBracket; else if(ch == '(') s = State.kStringDelimitedNestedParen; else if(ch == '{') s = State.kStringDelimitedNestedBrace; else if(ch == '<') s = State.kStringDelimitedNestedAngle; else if(ch == 0 || std.uni.isWhite(ch)) // bad delimiter, fallback to wysiwyg string s = State.kStringWysiwyg; else { if(isIdentifierChar(ch)) scanIdentifier(text, startpos, pos); string delim = toUTF8(text[startpos .. pos]); nesting = getDelimiterIndex(delim); } return s; } State scanTokenString(S)(S text, ref size_t pos, ref int tokLevel) { int state = toState(State.kWhite, 0, 0, 0); int id = -1; while(pos < text.length && tokLevel > 0) { int type = scan(state, text, pos, id); if(id == TOK_lcurly) tokLevel++; else if(id == TOK_rcurly) tokLevel--; } return (tokLevel > 0 ? State.kStringToken : State.kWhite); } static bool isStartingComment(S)(S txt, ref size_t idx) { if(idx >= 0 && idx < txt.length-1 && txt[idx] == '/' && (txt[idx+1] == '*' || txt[idx+1] == '+')) return true; if((txt[idx] == '*' || txt[idx] == '+') && idx > 0 && txt[idx-1] == '/') { idx--; return true; } return false; } static bool isEndingComment(S)(S txt, ref size_t pos) { if(pos < txt.length && pos > 0 && txt[pos] == '/' && (txt[pos-1] == '*' || txt[pos-1] == '+')) { pos--; return true; } if(pos < txt.length-1 && pos >= 0 && (txt[pos] == '*' || txt[pos] == '+') && txt[pos+1] == '/') return true; return false; } bool isIdentifierChar(dchar ch) { if(mAllowDollarInIdentifiers && ch == '$') return true; return isAlpha(ch) || ch == '_' || ch == '@'; } bool isIdentifierCharOrDigit(dchar ch) { return isIdentifierChar(ch) || isDigit(ch); } bool isIdentifier(S)(S text) { if(text.length == 0) return false; size_t pos; dchar ch = decode(text, pos); if(!isIdentifierChar(ch)) return false; while(pos < text.length) { ch = decode(text, pos); if(!isIdentifierCharOrDigit(ch)) return false; } return true; } static bool isInteger(S)(S text) { if(text.length == 0) return false; size_t pos; while(pos < text.length) { dchar ch = decode(text, pos); if(!isDigit(ch)) return false; } return true; } static bool isBracketPair(dchar ch1, dchar ch2) { switch(ch1) { case '{': return ch2 == '}'; case '}': return ch2 == '{'; case '(': return ch2 == ')'; case ')': return ch2 == '('; case '[': return ch2 == ']'; case ']': return ch2 == '['; default: return false; } } static bool isOpeningBracket(dchar ch) { return ch == '[' || ch == '(' || ch == '{'; } static bool isClosingBracket(dchar ch) { return ch == ']' || ch == ')' || ch == '}'; } static dchar openingBracket(State s) { switch(s) { case State.kStringDelimitedNestedBracket: return '['; case State.kStringDelimitedNestedParen: return '('; case State.kStringDelimitedNestedBrace: return '{'; case State.kStringDelimitedNestedAngle: return '<'; default: break; } assert(0); } static dchar closingBracket(State s) { switch(s) { case State.kStringDelimitedNestedBracket: return ']'; case State.kStringDelimitedNestedParen: return ')'; case State.kStringDelimitedNestedBrace: return '}'; case State.kStringDelimitedNestedAngle: return '>'; default: break; } assert(0); } static bool isCommentOrSpace(S)(int type, S text) { return (type == TokenCat.Comment || (type == TokenCat.Text && isWhite(text[0]))); } static State scanNestedDelimiterString(S)(S text, ref size_t pos, State s, ref int nesting) { dchar open = openingBracket(s); dchar close = closingBracket(s); while(pos < text.length) { dchar ch = decode(text, pos); if(ch == open) nesting++; else if(ch == close && nesting > 0) nesting--; else if(ch == '"' && nesting == 0) return scanStringPostFix(text, pos); } return s; } State scanDelimitedString(S)(S text, ref size_t pos, ref int delim) { string delimiter = s_delimiters[delim]; while(pos < text.length) { auto startpos = pos; dchar ch = decode(text, pos); if(isIdentifierChar(ch)) scanIdentifier(text, startpos, pos); string ident = toUTF8(text[startpos .. pos]); if(ident == delimiter) { ch = trydecode(text, pos); if(ch == '"') { delim = 0; // reset delimiter id, it shadows nesting return scanStringPostFix(text, pos); } } } return State.kStringDelimited; } int scan(S)(ref int state, in S text, ref size_t pos, ref int id) { State s = scanState(state); int nesting = nestingLevel(state); int tokLevel = tokenStringLevel(state); int otherState = getOtherState(state); int type = TokenCat.Text; size_t startpos = pos; dchar ch; id = TOK_Space; switch(s) { case State.kWhite: ch = decode(text, pos); if(ch == 'r' || ch == 'x' || ch == 'q') { size_t prevpos = pos; dchar nch = trydecode(text, pos); if(nch == '"' && ch == 'q') { s = startDelimiterString(text, pos, nesting); if(s == State.kStringDelimited) goto case State.kStringDelimited; else if(s == State.kStringWysiwyg) goto case State.kStringWysiwyg; else goto case State.kStringDelimitedNestedBracket; } else if(tokLevel == 0 && ch == 'q' && nch == '{') { type = TokenCat.String; id = TOK_StringLiteral; if(mTokenizeTokenString) { pos = prevpos; s = State.kStringTokenFirst; } else { tokLevel = 1; s = scanTokenString(text, pos, tokLevel); } break; } else if(nch == '"') { goto case State.kStringWysiwyg; } else { pos = prevpos; type = scanIdentifier(text, startpos, pos, id); } } else if(isIdentifierChar(ch)) type = scanIdentifier(text, startpos, pos, id); else if(isDigit(ch)) type = scanNumber(text, ch, pos, id); else if (ch == '.') { size_t nextpos = pos; ch = trydecode(text, nextpos); if(isDigit(ch)) type = scanNumber(text, '.', pos, id); else type = scanOperator(text, startpos, pos, id); } else if (ch == '/') { size_t prevpos = pos; ch = trydecode(text, pos); if (ch == '/') { // line comment type = TokenCat.Comment; id = TOK_Comment; while(pos < text.length && decode(text, pos) != '\n') {} } else if (ch == '*') { s = scanBlockComment(text, pos); type = TokenCat.Comment; id = TOK_Comment; } else if (ch == '+') { nesting = 1; s = scanNestedComment(text, startpos, pos, nesting); type = TokenCat.Comment; id = TOK_Comment; } else { // step back to position after '/' pos = prevpos; type = scanOperator(text, startpos, pos, id); } } else if (ch == '"') goto case State.kStringCStyle; else if (ch == '`') goto case State.kStringAltWysiwyg; else if (ch == '\'') { s = scanStringCStyle(text, pos, '\''); id = TOK_CharacterLiteral; type = TokenCat.String; } else if (ch == '#') { // display #! or #line as line comment type = TokenCat.Comment; id = TOK_Comment; while(pos < text.length && decode(text, pos) != '\n') {} } else { if (tokLevel > 0) { if(ch == '{') tokLevel++; else if (ch == '}') tokLevel--; if(!isWhite(ch)) type = scanOperator(text, startpos, pos, id); id = TOK_StringLiteral; } else if(!isWhite(ch)) type = scanOperator(text, startpos, pos, id); } break; case State.kStringTokenFirst: ch = decode(text, pos); assert(ch == '{'); tokLevel = 1; type = TokenCat.Operator; id = TOK_StringLiteral; s = State.kWhite; break; case State.kStringToken: type = TokenCat.String; id = TOK_StringLiteral; s = scanTokenString(text, pos, tokLevel); break; case State.kBlockComment: s = scanBlockComment(text, pos); type = TokenCat.Comment; id = TOK_Comment; break; case State.kNestedComment: s = scanNestedComment(text, pos, pos, nesting); type = TokenCat.Comment; id = TOK_Comment; break; case State.kStringCStyle: s = scanStringCStyle(text, pos, '"'); type = TokenCat.String; id = TOK_StringLiteral; break; case State.kStringWysiwyg: s = scanStringWysiwyg(text, pos); type = TokenCat.String; id = TOK_StringLiteral; break; case State.kStringAltWysiwyg: s = scanStringAltWysiwyg(text, pos); type = TokenCat.String; id = TOK_StringLiteral; break; case State.kStringDelimited: s = scanDelimitedString(text, pos, nesting); type = TokenCat.String; id = TOK_StringLiteral; break; case State.kStringDelimitedNestedBracket: case State.kStringDelimitedNestedParen: case State.kStringDelimitedNestedBrace: case State.kStringDelimitedNestedAngle: s = scanNestedDelimiterString(text, pos, s, nesting); type = TokenCat.String; id = TOK_StringLiteral; break; default: break; } state = toState(s, nesting, tokLevel, otherState); if(tokLevel > 0) id = TOK_StringLiteral; return type; } int scan(S)(ref int state, in S text, ref size_t pos) { int id; return scan(state, text, pos, id); } /////////////////////////////////////////////////////////////// TokenInfo[] ScanLine(S)(int iState, S text) { TokenInfo[] lineInfo; for(size_t pos = 0; pos < text.length; ) { TokenInfo info; info.StartIndex = pos; info.type = cast(TokenCat) scan(iState, text, pos, info.tokid); info.EndIndex = pos; lineInfo ~= info; } return lineInfo; } } /////////////////////////////////////////////////////////////// // converted int[string] to short[string] due to bug #2500 __gshared short[string] keywords_map; // maps to TOK enumerator __gshared short[string] specials_map; // maps to TOK enumerator alias AssociativeArray!(string, short) _wa1; // fully instantiate type info alias AssociativeArray!(int, const(int)) _wa2; // fully instantiate type info shared static this() { foreach(i, s; keywords) keywords_map[s] = cast(short) (TOK_begin_Keywords + i); foreach(i, s; specials) specials_map[s] = cast(short) i; } bool findKeyword(string ident, ref int id) { if(__ctfe) { // slow, but compiles foreach(i, k; keywords) if(k == ident) { id = cast(int) (TOK_begin_Keywords + i); return true; } } else if(auto pident = ident in keywords_map) { id = *pident; return true; } return false; } bool isKeyword(string ident) { int id; return findKeyword(ident, id); } bool findSpecial(string ident, ref int id) { if(__ctfe) { // slow, but compiles foreach(i, k; specials) if(k == ident) { id = TOK_StringLiteral; return true; } } else if(auto pident = ident in specials_map) { id = TOK_StringLiteral; return true; } return false; } const string[] keywords = [ "this", "super", "assert", "null", "true", "false", "cast", "new", "delete", "throw", "module", "pragma", "typeof", "typeid", "template", "void", "byte", "ubyte", "short", "ushort", "int", "uint", "long", "ulong", "cent", "ucent", "float", "double", "real", "bool", "char", "wchar", "dchar", "ifloat", "idouble", "ireal", "cfloat", "cdouble", "creal", "delegate", "function", "is", "if", "else", "while", "for", "do", "switch", "case", "default", "break", "continue", "synchronized", "return", "goto", "try", "catch", "finally", "with", "asm", "foreach", "foreach_reverse", "scope", "struct", "class", "interface", "union", "enum", "import", "mixin", "static", "final", "const", "typedef", "alias", "override", "abstract", "volatile", "debug", "deprecated", "in", "out", "inout", "lazy", "auto", "align", "extern", "private", "package", "protected", "public", "export", "body", "invariant", "unittest", "version", //{ "manifest", TOKmanifest }, // Added after 1.0 "ref", "macro", "pure", "nothrow", "__gshared", "__thread", "__traits", "__overloadset", "__parameters", "__argTypes", "__vector", "__FILE__", "__LINE__", "__FUNCTION__", "__PRETTY_FUNCTION__", "__MODULE__", "shared", "immutable", "@disable", "@property", "@nogc", "@safe", "@system", "@trusted", ]; // not listed as keywords, but "special tokens" const string[] specials = [ "__DATE__", "__EOF__", "__TIME__", "__TIMESTAMP__", "__VENDOR__", "__VERSION__", ]; //////////////////////////////////////////////////////////////////////// enum { TOK_begin_Generic, TOK_Space = TOK_begin_Generic, TOK_Comment, TOK_Identifier, TOK_IntegerLiteral, TOK_FloatLiteral, TOK_StringLiteral, TOK_CharacterLiteral, TOK_EOF, TOK_RECOVER, TOK_end_Generic } string genKeywordEnum(string kw) { if(kw[0] == '@') kw = kw[1..$]; return "TOK_" ~ kw; } string genKeywordsEnum(T)(const string[] kwords, T begin) { string enums = "enum { TOK_begin_Keywords = " ~ to!string(begin) ~ ", "; bool first = true; foreach(kw; kwords) { enums ~= genKeywordEnum(kw); if(first) { first = false; enums ~= " = TOK_begin_Keywords"; } enums ~= ","; } enums ~= "TOK_end_Keywords }"; return enums; } mixin(genKeywordsEnum(keywords, "TOK_end_Generic")); const string[2][] operators = [ [ "lcurly", "{" ], [ "rcurly", "}" ], [ "lparen", "(" ], [ "rparen", ")" ], [ "lbracket", "[" ], [ "rbracket", "]" ], [ "semicolon", ";" ], [ "colon", ":" ], [ "comma", "," ], [ "dot", "." ], // binary operators [ "xor", "^" ], [ "lt", "<" ], [ "gt", ">" ], [ "le", "<=" ], [ "ge", ">=" ], [ "equal", "==" ], [ "notequal", "!=" ], [ "lambda", "=>" ], [ "unord", "!<>=" ], [ "ue", "!<>" ], [ "lg", "<>" ], [ "leg", "<>=" ], [ "ule", "!>" ], [ "ul", "!>=" ], [ "uge", "!<" ], [ "ug", "!<=" ], [ "notcontains", "!in" ], [ "notidentity", "!is" ], [ "shl", "<<" ], [ "shr", ">>" ], [ "ushr", ">>>" ], [ "add", "+" ], [ "min", "-" ], [ "mul", "*" ], [ "div", "/" ], [ "mod", "%" ], [ "pow", "^^" ], [ "and", "&" ], [ "andand", "&&" ], [ "or", "|" ], [ "oror", "||" ], [ "tilde", "~" ], [ "assign", "=" ], [ "xorass", "^=" ], [ "addass", "+=" ], [ "minass", "-=" ], [ "mulass", "*=" ], [ "divass", "/=" ], [ "modass", "%=" ], [ "powass", "^^=" ], [ "shlass", "<<=" ], [ "shrass", ">>=" ], [ "ushrass", ">>>=" ], [ "andass", "&=" ], [ "orass", "|=" ], [ "catass", "~=" ], // end of binary operators [ "not", "!" ], [ "dollar", "$" ], [ "slice", ".." ], [ "dotdotdot", "..." ], [ "plusplus", "++" ], [ "minusminus", "--" ], [ "question", "?" ], /+ [ "array", "[]" ], // symbols with duplicate meaning [ "address", "&" ], [ "star", "*" ], [ "preplusplus", "++" ], [ "preminusminus", "--" ], [ "neg", "-" ], [ "uadd", "+" ], [ "cat", "~" ], [ "identity", "is" ], [ "plus", "++" ], [ "minus", "--" ], +/ ]; string genOperatorEnum(T)(const string[2][] ops, T begin) { string enums = "enum { TOK_begin_Operators = " ~ to!string(begin) ~ ", "; bool first = true; for(int o = 0; o < ops.length; o++) { enums ~= "TOK_" ~ ops[o][0]; if(first) { first = false; enums ~= " = TOK_begin_Operators"; } enums ~= ","; } enums ~= "TOK_end_Operators }"; return enums; } mixin(genOperatorEnum(operators, "TOK_end_Keywords")); enum TOK_binaryOperatorFirst = TOK_xor; enum TOK_binaryOperatorLast = TOK_catass; enum TOK_assignOperatorFirst = TOK_assign; enum TOK_assignOperatorLast = TOK_catass; enum TOK_unorderedOperatorFirst = TOK_unord; enum TOK_unorderedOperatorLast = TOK_ug; enum TOK_error = -1; bool _stringEqual(string s1, string s2, int length) { if(s1.length < length || s2.length < length) return false; for(int i = 0; i < length; i++) if(s1[i] != s2[i]) return false; return true; } int[] sortedOperatorIndexArray() { // create sorted list of operators int[] opIndex; for(int o = 0; o < operators.length; o++) { string op = operators[o][1]; int p = 0; while(p < opIndex.length) { assert(op != operators[opIndex[p]][1], "duplicate operator " ~ op); if(op < operators[opIndex[p]][1]) break; p++; } // array slicing does not work in CTFE? // opIndex ~= opIndex[0..p] ~ o ~ opIndex[p..$]; int[] nIndex; for(int i = 0; i < p; i++) nIndex ~= opIndex[i]; nIndex ~= o; for(int i = p; i < opIndex.length; i++) nIndex ~= opIndex[i]; opIndex = nIndex; } return opIndex; } string[] sortedOperatorArray() { string[] array; foreach(o; sortedOperatorIndexArray()) array ~= operators[o][1]; return array; } string genOperatorParser(string getch) { int[] opIndex = sortedOperatorIndexArray(); int matchlen = 0; string indent = ""; string[] defaults = [ "error" ]; string txt = indent ~ "dchar ch;\n"; for(int o = 0; o < opIndex.length; o++) { string op = operators[opIndex[o]][1]; string nextop; if(o + 1 < opIndex.length) nextop = operators[opIndex[o+1]][1]; while(op.length > matchlen) { if(matchlen > 0) txt ~= indent ~ "case '" ~ op[matchlen-1] ~ "':\n"; indent ~= " "; txt ~= indent ~ "ch = " ~ getch ~ ";\n"; txt ~= indent ~ "switch(ch)\n"; txt ~= indent ~ "{\n"; indent ~= " "; int len = (matchlen > 0 ? matchlen - 1 : 0); while(len > 0 && defaults[len] == defaults[len+1]) len--; txt ~= indent ~ "default: len = " ~ to!string(len) ~ "; return TOK_" ~ defaults[$-1] ~ ";\n"; //txt ~= indent ~ "case '" ~ op[matchlen] ~ "':\n"; defaults ~= defaults[$-1]; matchlen++; } if(nextop.length > matchlen && nextop[0..matchlen] == op) { if(matchlen > 0) txt ~= indent ~ "case '" ~ op[matchlen-1] ~ "':\n"; indent ~= " "; txt ~= indent ~ "ch = " ~ getch ~ ";\n"; txt ~= indent ~ "switch(ch)\n"; txt ~= indent ~ "{\n"; indent ~= " "; txt ~= indent ~ "default: len = " ~ to!string(matchlen) ~ "; return TOK_" ~ operators[opIndex[o]][0] ~ "; // " ~ op ~ "\n"; defaults ~= operators[opIndex[o]][0]; matchlen++; } else { string case_txt = "case '" ~ op[matchlen-1] ~ "':"; if(isAlphaNum(op[matchlen-1])) case_txt ~= " ch = getch(); if(isAlphaNum(ch) || ch == '_') goto default;\n" ~ indent ~ " "; txt ~= indent ~ case_txt ~ " len = " ~ to!string(matchlen) ~ "; return TOK_" ~ operators[opIndex[o]][0] ~ "; // " ~ op ~ "\n"; while(nextop.length < matchlen || (matchlen > 0 && !_stringEqual(op, nextop, matchlen-1))) { matchlen--; indent = indent[0..$-2]; txt ~= indent ~ "}\n"; indent = indent[0..$-2]; defaults = defaults[0..$-1]; } } } return txt; } int parseOperator(S)(S txt, size_t pos, ref size_t len) { dchar getch() { if(pos >= txt.length) return 0; return decode(txt, pos); } mixin(genOperatorParser("getch()")); } //////////////////////////////////////////////////////////////////////// version(none) { pragma(msg, genKeywordsEnum(keywords, "TOK_end_Generic")); pragma(msg, genOperatorEnum(operators, "TOK_end_Keywords")); pragma(msg, sortedOperatorArray()); pragma(msg, genOperatorParser("getch()")); } string tokenString(int id) { switch(id) { case TOK_Space: return " "; case TOK_Comment: return "/**/"; case TOK_Identifier: return "Identifier"; case TOK_IntegerLiteral: return "IntegerLiteral"; case TOK_FloatLiteral: return "FloatLiteral"; case TOK_StringLiteral: return "StringtLiteral"; case TOK_CharacterLiteral: return "CharacterLiteral"; case TOK_EOF: return "__EOF__"; case TOK_RECOVER: return "__RECOVER__"; case TOK_begin_Keywords: .. case TOK_end_Keywords - 1: return keywords[id - TOK_begin_Keywords]; case TOK_begin_Operators: .. case TOK_end_Operators - 1: return operators[id - TOK_begin_Operators][1]; default: assert(false); } } string operatorName(int id) { switch(id) { case TOK_begin_Operators: .. case TOK_end_Operators - 1: return operators[id - TOK_begin_Operators][0]; default: assert(false); } } enum case_TOKs_BasicTypeX = q{ case TOK_bool: case TOK_byte: case TOK_ubyte: case TOK_short: case TOK_ushort: case TOK_int: case TOK_uint: case TOK_long: case TOK_ulong: case TOK_char: case TOK_wchar: case TOK_dchar: case TOK_float: case TOK_double: case TOK_real: case TOK_ifloat: case TOK_idouble: case TOK_ireal: case TOK_cfloat: case TOK_cdouble: case TOK_creal: case TOK_void: }; enum case_TOKs_TemplateSingleArgument = q{ case TOK_Identifier: case TOK_CharacterLiteral: case TOK_StringLiteral: case TOK_IntegerLiteral: case TOK_FloatLiteral: case TOK_true: case TOK_false: case TOK_null: case TOK___FILE__: case TOK___LINE__: }; // + case_TOKs_BasicTypeX; ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/0000775000175000017500000000000012776214756026026 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/mod.d0000664000175000017500000006033412776214756026760 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.parser.mod; import vdc.util; import vdc.lexer; import vdc.parser.engine; import vdc.parser.decl; import vdc.parser.expr; import vdc.parser.misc; import vdc.parser.aggr; import vdc.parser.tmpl; import vdc.parser.stmt; import ast = vdc.ast.mod; import std.conv; //////////////////////////////////////////////////////////////// //-- GRAMMAR_BEGIN -- //Module: // ModuleDeclaration DeclDefs_opt // DeclDefs_opt // class Module { static Action enter(Parser p) { p.pushNode(new ast.Module(p.tok)); if(p.tok.id == TOK_module) { p.pushRecoverState(&recoverModuleDeclaration); p.pushState(&shiftModuleDeclaration); return ModuleDeclaration.enter(p); } if(p.tok.id == TOK_EOF) return Accept; p.pushState(&shiftModuleDeclDefs); return DeclDefs.enter(p); } static Action shiftModuleDeclaration(Parser p) { p.popAppendTopNode!(ast.Module)(); if(p.tok.id == TOK_EOF) return Accept; p.pushState(&shiftModuleDeclDefs); return DeclDefs.enter(p); } static Action shiftModuleDeclDefs(Parser p) { if(p.tok.id != TOK_EOF) { // recover by assuming the mismatched braces, trying to add more declarations to the module p.pushRecoverState(&recoverModuleDeclaration); return p.parseError("EOF expected"); } return Accept; } static Action recoverModuleDeclaration(Parser p) { p.pushState(&afterRecover); return Parser.recoverSemiCurly(p); } static Action recoverDeclDef(Parser p) { p.pushState(&afterRecover); return Parser.recoverSemiCurly(p); } static Action afterRecover(Parser p) { if(p.tok.id == TOK_EOF) return Accept; if(p.tok.id == TOK_rcurly) { // eat pending '}' p.pushState(&afterRecover); return Accept; } p.pushState(&shiftModuleDeclDefs); return DeclDefs.enter(p); } } //-- GRAMMAR_BEGIN -- //ModuleDeclaration: // module ModuleFullyQualifiedName ; class ModuleDeclaration { static Action enter(Parser p) { if(p.tok.id != TOK_module) return p.parseError("module expected"); p.pushNode(new ast.ModuleDeclaration(p.tok)); p.pushState(&shiftName); p.pushState(&ModuleFullyQualifiedName.enter); return Accept; } static Action shiftName(Parser p) { if(p.tok.id != TOK_semicolon) return p.parseError("semicolon expected"); p.popAppendTopNode!(ast.ModuleDeclaration)(); return Accept; } } //-- GRAMMAR_BEGIN -- //ModuleFullyQualifiedName: // ModuleName // Packages . ModuleName // //ModuleName: // Identifier // //Packages: // PackageName // Packages . PackageName // //PackageName: // Identifier class ModuleFullyQualifiedName { mixin ListNode!(ast.ModuleFullyQualifiedName, Identifier, TOK_dot); } /* might also be empty, but the grammar reflects this by the _opt suffix where used */ //-- GRAMMAR_BEGIN -- //DeclDefs: // DeclDef // DeclDef DeclDefs class DeclDefs { enum doNotPopNode = true; // does not create new Node, but inserts DeclDef into module or block static Action enter(Parser p) { if(p.tok.id == TOK_rcurly || p.tok.id == TOK_EOF) return Forward; p.pushRecoverState(&recover); p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover p.pushState(&shiftDeclDef); return DeclDef.enter(p); } static Action next(Parser p) { if(p.tok.id == TOK_rcurly || p.tok.id == TOK_EOF || p.tok.id == TOK_RECOVER) return Forward; p.pushState(&shiftDeclDef); return DeclDef.enter(p); } static Action shiftDeclDef(Parser p) { p.popAppendTopNode(); return next(p); } static Action recover(Parser p) { auto node = new ast.ParseRecoverNode(p.tok); if(p.nodeStack.depth) node.fulspan.start = p.topNode().fulspan.end; // record span of removed text p.pushNode(node); p.pushState(&afterRecover); return Parser.recoverSemiCurly(p); } static Action afterRecover(Parser p) { p.popAppendTopNode!(ast.Node, ast.ParseRecoverNode)(); p.pushRecoverState(&recover); p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover return next(p); } } //-- GRAMMAR_BEGIN -- //DeclDef: // AttributeSpecifier // PragmaSpecifier // ImportDeclaration // EnumDeclaration // ClassDeclaration // InterfaceDeclaration // AggregateDeclaration // Declaration // Constructor // Destructor // Invariant // UnitTest // StaticConstructor // StaticDestructor // SharedStaticConstructor // SharedStaticDestructor // DebugSpecification // VersionSpecification // ConditionalDeclaration // StaticAssert // TemplateDeclaration // TemplateMixinDeclaration // TemplateMixin // MixinDeclaration // ClassAllocator // ClassDeallocator // ; class DeclDef { // does not create new Node, but inserts DeclDef into module or block static Action enter(Parser p) { switch(p.tok.id) { case TOK_pragma: return Pragma.enter(p); case TOK_mixin: p.pushState(&shiftMixin); return Accept; case TOK_import: return ImportDeclaration.enter(p); case TOK_enum: return EnumDeclaration.enter(p); case TOK_struct: case TOK_union: case TOK_class: case TOK_interface: return AggregateDeclaration.enter(p); case TOK_this: return Constructor.enter(p); case TOK_tilde: return Destructor.enter(p); case TOK_invariant: return Invariant.enter(p); case TOK_unittest: return Unittest.enter(p); case TOK_debug: return DebugCondOrSpec.enter(p); case TOK_version: return VersionCondOrSpec.enter(p); case TOK_template: return TemplateDeclaration.enter(p); case TOK_new: return ClassAllocator.enter(p); case TOK_delete: return ClassDeallocator.enter(p); case TOK_semicolon: p.pushNode(new ast.EmptyDeclDef(p.tok)); return Accept; case TOK_static: p.pushToken(p.tok); p.pushState(&shiftStatic); return Accept; default: if(AttributeSpecifier.tryenter(p) == Accept) return Accept; return Declaration.enter(p); } } static Action shiftStatic(Parser p) { switch(p.tok.id) { case TOK_if: // only after static p.popToken(); return ConditionalDeclaration.enterAfterStatic(p); case TOK_assert: // only after static p.popToken(); return StaticAssert.enterAfterStatic(p); default: return AttributeSpecifier.enterAfterStatic(p); } } static Action shiftMixin(Parser p) { switch(p.tok.id) { case TOK_template: return TemplateMixinDeclaration.enterAfterMixin(p); case TOK_lparen: return MixinDeclaration.enterAfterMixin(p); default: return TemplateMixin.enterAfterMixin(p); } } } //-- GRAMMAR_BEGIN -- //AttributeSpecifier: // Attribute : // Attribute DeclarationBlock // //Attribute: // LinkageAttribute // AlignAttribute // AttributeOrStorageClass // ProtectionAttribute // @disable // @property // @safe // @system // @trusted class AttributeSpecifier { // no members means "Attribute:" static Action enter(Parser p) { if(tryenter(p) != Accept) return p.parseError("attribute specifier expected"); return Accept; } static Action tryenter(Parser p) { switch(p.tok.id) { case TOK_align: p.pushState(&shiftAttribute); return AlignAttribute.enter(p); case TOK_extern: p.pushState(&shiftAttribute); return LinkageAttribute.enter(p); case TOK_Identifier: if(p.tok.txt[0] != '@') return Forward; return UserAttributeSpecifier.enter(p); case TOK_deprecated: return UserAttributeSpecifier.enter(p); default: if(tokenToAnnotation(p.tok.id) == 0 && tokenToProtection(p.tok.id) == 0 && tokenToAttribute(p.tok.id) == 0) return Forward; p.pushToken(p.tok); p.pushState(&shiftColonOrLcurly); return Accept; } } // assumes attribute on the token stack static Action enterAfterStatic(Parser p) { return shiftColonOrLcurly(p); } static ast.AttributeSpecifier createFromToken(Token tok) { TokenId id = tok.id; ast.AttributeSpecifier n; Annotation annot = tokenToAnnotation(id); if(annot == 0) annot = tokenToProtection(id); if(annot != 0) { n = new ast.AttributeSpecifier(tok); n.annotation = annot; } else { Attribute attr = tokenToAttribute(id); if(attr != 0) { n = new ast.AttributeSpecifier(tok); n.attr = attr; } } assert(n); return n; } static Action shiftColonOrLcurly(Parser p) { switch(p.tok.id) { case TOK_lparen: if(isTypeModifier(p.topToken().id)) // running into a type instead of an attribute, so switch to Declaration return Decl!true.enterAttributeSpecifier(p); goto default; default: Token tok = p.popToken(); auto attr = createFromToken(tok); p.pushNode(attr); return shiftAttribute(p); } } static Action shiftAttribute(Parser p) { auto attr = p.topNode!(ast.AttributeSpecifier); switch(p.tok.id) { case TOK_colon: attr.id = TOK_colon; return Accept; case TOK_lcurly: attr.id = TOK_lcurly; p.pushState(&shiftRcurly); p.pushState(&DeclDefs.enter); p.pushNode(new ast.DeclarationBlock(p.tok)); return Accept; case TOK_Identifier: // identifier can be basic type or identifier of an AutoDeclaration p.pushToken(p.tok); p.pushState(&shiftIdentifier); return Accept; case TOK_alias: case TOK_typedef: p.pushState(&shiftDeclDef); return Declaration.enter(p); case TOK_align: p.pushState(&shiftDeclDef); p.pushState(&shiftAttribute); return AlignAttribute.enter(p); case TOK_extern: p.pushState(&shiftDeclDef); p.pushState(&shiftAttribute); return LinkageAttribute.enter(p); case TOK_pragma: case TOK_mixin: case TOK_import: case TOK_enum: case TOK_struct: case TOK_union: case TOK_class: case TOK_interface: case TOK_this: case TOK_tilde: case TOK_invariant: case TOK_unittest: case TOK_debug: case TOK_version: case TOK_template: case TOK_semicolon: case TOK_static: p.pushState(&shiftDeclDef); return DeclDef.enter(p); default: if(isTypeModifier(p.tok.id)) { p.pushState(&shiftDeclDef); p.pushToken(p.tok); p.pushState(&shiftColonOrLcurly); return Accept; } int annot = tokenToAnnotation(p.tok.id) | tokenToProtection(p.tok.id); int attrib = tokenToAttribute(p.tok.id); if(annot || attrib) { p.combineAnnotations(attr.annotation, annot); p.combineAttributes(attr.attr, attrib); p.pushState(&shiftAttribute); return Accept; } p.pushState(&shiftDeclDef); return Decl!true.enter(p); } } static Action shiftRcurly(Parser p) { if(p.tok.id != TOK_rcurly) return p.parseError("closing brace expected for declaration block"); p.popAppendTopNode!(ast.AttributeSpecifier)(); return Accept; } static Action shiftDeclDef(Parser p) { p.popAppendTopNode!(ast.AttributeSpecifier)(); return Forward; } static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_assign: p.pushState(&shiftDeclDef); return Decl!true.enterIdentifier(p); case TOK_lparen: p.pushState(&shiftDeclDef); return Decl!true.enterAutoReturn(p); default: p.pushState(&shiftDeclDef); return Decl!true.enterTypeIdentifier(p); } } } //-- GRAMMAR_BEGIN -- //UserAttributeSpecifier: // deprectated // @identifier // deprecated ( ArgumentList ) // @identifier ( ArgumentList ) class UserAttributeSpecifier { static Action enter(Parser p) { switch(p.tok.id) { case TOK_deprecated: case TOK_Identifier: auto attr = new ast.UserAttributeSpecifier(p.tok); attr.ident = p.tok.txt; p.pushNode(attr); p.pushState(&shiftIdentifier); return Accept; default: return p.parseError("@identifier expected in user attribute"); } } static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushState(&shiftArgumentList); return Arguments.enter(p); default: return Forward; } } static Action shiftArgumentList(Parser p) { p.popAppendTopNode!(ast.UserAttributeSpecifier, ast.ArgumentList)(); return Forward; } } //-- GRAMMAR_BEGIN -- //DeclarationBlock: // DeclDef // { DeclDefs_opt } class DeclarationBlock { static Action enter(Parser p) { switch(p.tok.id) { case TOK_lcurly: auto decl = new ast.DeclarationBlock(p.tok); p.pushNode(decl); p.pushState(&shiftLcurly); return Accept; default: return DeclDef.enter(p); } } static Action shiftLcurly(Parser p) { switch(p.tok.id) { case TOK_rcurly: return Accept; default: p.pushState(&shiftDeclDefs); return DeclDefs.enter(p); } } static Action shiftDeclDefs(Parser p) { switch(p.tok.id) { case TOK_rcurly: return Accept; default: return p.parseError("'}' expected"); } } } //-- GRAMMAR_BEGIN -- //LinkageAttribute: // extern ( LinkageType ) // //LinkageType: // "C" // "C" ++ // "D" // "Windows" // "Pascal" // "System" class LinkageAttribute { static Action enter(Parser p) { if(p.tok.id != TOK_extern) return p.parseError("extern expected"); p.pushState(&shiftLparen); return Accept; } static Action shiftLparen(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushNode(new ast.LinkageAttribute(p.tok)); p.pushState(&shiftLinkageType); return Accept; default: auto attr = new ast.AttributeSpecifier(p.tok); attr.attr = Attr_Extern; p.pushNode(attr); return Forward; } } static Action shiftLinkageType(Parser p) { Attribute attr = tokenToLinkageType(p.tok); if(attr == 0) return p.parseError("linkage type expected in extern"); p.topNode!(ast.LinkageAttribute)().attr = attr; p.pushState(&shiftRParen); return Accept; } static Action shiftRParen(Parser p) { assert(cast(ast.LinkageAttribute)p.topNode()); if(p.tok.id == TOK_rparen) return Accept; if(p.topNode().attr != Attr_ExternC || p.tok.id != TOK_plusplus) return p.parseError("closing parenthesis expected after linkage type"); p.topNode().attr = Attr_ExternCPP; p.pushState(&shiftRParen); return Accept; } } Attribute tokenToLinkageType(Token tok) { if(tok.id != TOK_Identifier) return 0; switch(tok.txt) { case "C": return Attr_ExternC; case "D": return Attr_ExternD; case "Windows": return Attr_ExternWindows; case "Pascal": return Attr_ExternPascal; case "System": return Attr_ExternSystem; default: return 0; } } //-- GRAMMAR_BEGIN -- //AlignAttribute: // align // align ( Integer ) class AlignAttribute { static Action enter(Parser p) { if(p.tok.id != TOK_align) return p.parseError("align expected"); p.pushNode(new ast.AlignAttribute(p.tok)); p.pushState(&shiftLparen); return Accept; } static Action shiftLparen(Parser p) { if(p.tok.id != TOK_lparen) return Forward; p.pushState(&shiftInteger); return Accept; } static Action shiftInteger(Parser p) { if(p.tok.id != TOK_IntegerLiteral) return p.parseError("integer expected in align"); int algn = parse!int(p.tok.txt); Attribute attr = alignmentToAttribute(algn); if(attr == 0) return p.parseError("alignment not supported: " ~ p.tok.txt); p.topNode!(ast.AlignAttribute)().attr = attr; p.pushState(&shiftRParen); return Accept; } static Action shiftRParen(Parser p) { assert(cast(ast.AlignAttribute)p.topNode()); if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected after align"); return Accept; } } Attribute alignmentToAttribute(int algn) { switch(algn) { case 1: return Attr_Align1; case 2: return Attr_Align2; case 4: return Attr_Align4; case 8: return Attr_Align8; case 16: return Attr_Align16; default: return 0; } } //-- GRAMMAR_BEGIN -- //ProtectionAttribute: // private // package // protected // public // export //PragmaSpecifier: // Pragma DeclDef //Pragma: // pragma ( Identifier ) // pragma ( Identifier , TemplateArgumentList ) class Pragma { static Action enter(Parser p) { if(p.tok.id != TOK_pragma) return p.parseError("pragma expected"); p.pushNode(new ast.Pragma(p.tok)); p.pushState(&shiftLparen); return Accept; } static Action shiftLparen(Parser p) { if(p.tok.id != TOK_lparen) return Forward; p.pushState(&shiftIdentifier); return Accept; } static Action shiftIdentifier(Parser p) { if(p.tok.id != TOK_Identifier) return p.parseError("integer expected in align"); p.topNode!(ast.Pragma)().ident = p.tok.txt; p.pushState(&shiftCommaOrRParen); return Accept; } static Action shiftCommaOrRParen(Parser p) { if(p.tok.id == TOK_comma) { p.pushState(&shiftArgumentList); p.pushState(&TemplateArgumentList.enter); return Accept; } return shiftRParen(p); } static Action shiftRParen(Parser p) { assert(cast(ast.Pragma)p.topNode()); if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected for pragma"); return Accept; } static Action shiftArgumentList(Parser p) { p.popAppendTopNode!(ast.Pragma)(); return shiftRParen(p); } } //-- GRAMMAR_BEGIN -- //ImportDeclaration: // import ImportList ; class ImportDeclaration { mixin SequenceNode!(ast.ImportDeclaration, TOK_import, ImportList, TOK_semicolon); } //-- GRAMMAR_BEGIN -- //ImportList: // Import // ImportBindings // Import , ImportList // //ImportBindings: // Import : ImportBindList class ImportList { static Action enter(Parser p) { p.pushNode(new ast.ImportList(p.tok)); p.pushState(&shiftImport); return Import.enter(p); } static Action shiftImport(Parser p) { if(p.tok.id == TOK_colon) { p.pushState(&shiftImportBindList); p.pushState(&ImportBindList.enter); return Accept; } p.popAppendTopNode!(ast.ImportList)(); if(p.tok.id == TOK_comma) { p.pushState(&shiftImport); p.pushState(&Import.enter); return Accept; } return Forward; } static Action shiftImportBindList(Parser p) { p.popAppendTopNode!(ast.Import)(); p.popAppendTopNode!(ast.ImportList)(); return Forward; } } //-- GRAMMAR_BEGIN -- //Import: // ModuleFullyQualifiedName // ModuleAliasIdentifier = ModuleFullyQualifiedName // //ModuleAliasIdentifier: // Identifier class Import { static Action enter(Parser p) { if(p.tok.id != TOK_Identifier) return p.parseError("identifier expected in import"); p.pushToken(p.tok); p.pushNode(new ast.Import(p.tok)); p.pushState(&shiftIdentifier); return Accept; } static Action shiftIdentifier(Parser p) { p.pushState(&shiftFullyQualifiedName); if(p.tok.id == TOK_assign) { p.topNode!(ast.Import)().aliasIdent = p.popToken().txt; p.pushState(&ModuleFullyQualifiedName.enter); return Accept; } // delegate into ModuleFullyQualifiedName p.pushNode(new ast.ModuleFullyQualifiedName(p.tok)); auto id = new ast.Identifier(p.popToken()); p.pushNode(id); return ModuleFullyQualifiedName.shift(p); } static Action shiftFullyQualifiedName(Parser p) { p.popAppendTopNode!(ast.Import)(); return Forward; } } //-- GRAMMAR_BEGIN -- //ImportBindList: // ImportBind // ImportBind , ImportBindList class ImportBindList { mixin ListNode!(ast.ImportBindList, ImportBind, TOK_comma); } //-- GRAMMAR_BEGIN -- //ImportBind: // Identifier // Identifier = Identifier class ImportBind { mixin OptionalNode!(ast.ImportBind, Identifier, TOK_assign, Identifier); } //-- GRAMMAR_BEGIN -- //MixinDeclaration: // mixin ( AssignExpression ) ; class MixinDeclaration { mixin SequenceNode!(ast.MixinDeclaration, TOK_mixin, TOK_lparen, AssignExpression, TOK_rparen, TOK_semicolon); static Action enterAfterMixin(Parser p) { p.pushNode(new ast.MixinDeclaration(p.tok)); return shift1.shift(p); } } //-- GRAMMAR_BEGIN -- //Unittest: // unittest BlockStatement class Unittest { mixin SequenceNode!(ast.Unittest, TOK_unittest, BlockStatement); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/stmt.d0000664000175000017500000010102112776214756027155 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.parser.stmt; import vdc.util; import vdc.lexer; import vdc.parser.engine; import vdc.parser.expr; import vdc.parser.decl; import vdc.parser.iasm; import vdc.parser.mod; import vdc.parser.misc; import vdc.parser.tmpl; import vdc.parser.aggr; import ast = vdc.ast.all; import stdext.util; //-- GRAMMAR_BEGIN -- //Statement: // ScopeStatement class Statement { static Action enter(Parser p) { return ScopeStatement.enter(p); } } //-- GRAMMAR_BEGIN -- //ScopeStatement: // ; // NonEmptyStatement // ScopeBlockStatement // //ScopeBlockStatement: // BlockStatement class ScopeStatement : Statement { static Action enter(Parser p) { switch(p.tok.id) { case TOK_semicolon: p.pushNode(new ast.EmptyStatement(p.tok)); return Accept; case TOK_lcurly: return BlockStatement.enter(p); default: return NonEmptyStatement.enter(p); } } } //-- GRAMMAR_BEGIN -- //ScopeNonEmptyStatement: // NonEmptyStatement // BlockStatement class ScopeNonEmptyStatement : Statement { static Action enter(Parser p) { switch(p.tok.id) { case TOK_lcurly: return BlockStatement.enter(p); default: return NonEmptyStatement.enter(p); } } } //-- GRAMMAR_BEGIN -- //NoScopeNonEmptyStatement: // NonEmptyStatement // BlockStatement alias ScopeNonEmptyStatement NoScopeNonEmptyStatement; //-- GRAMMAR_BEGIN -- //NoScopeStatement: // ; // NonEmptyStatement // BlockStatement alias ScopeStatement NoScopeStatement; //-- GRAMMAR_BEGIN -- //NonEmptyStatement: // LabeledStatement // ExpressionStatement // DeclarationStatement // IfStatement // WhileStatement // DoStatement // ForStatement // ForeachStatement // SwitchStatement // FinalSwitchStatement // CaseStatement // CaseRangeStatement // DefaultStatement // ContinueStatement // BreakStatement // ReturnStatement // GotoStatement // WithStatement // SynchronizedStatement // VolatileStatement // TryStatement // ScopeGuardStatement // ThrowStatement // AsmStatement // PragmaStatement // MixinStatement // ForeachRangeStatement // ConditionalStatement // StaticAssert // TemplateMixin // EnumDeclaration // ClassDeclaration // InterfaceDeclaration // AggregateDeclaration // TemplateDeclaration // //LabeledStatement: // Identifier : NoScopeStatement class NonEmptyStatement : Statement { static Action enter(Parser p) { switch(p.tok.id) { case TOK_if: return IfStatement.enter(p); case TOK_while: return WhileStatement.enter(p); case TOK_do: return DoStatement.enter(p); case TOK_for: return ForStatement.enter(p); case TOK_foreach: case TOK_foreach_reverse: return ForeachStatement.enter(p); // includes ForeachRangeStatement case TOK_switch: return SwitchStatement.enter(p); case TOK_final: // could also be a declaration? return FinalSwitchStatement.enter(p); case TOK_case: return CaseStatement.enter(p); // includes CaseRangeStatement case TOK_default: return DefaultStatement.enter(p); case TOK_continue: return ContinueStatement.enter(p); case TOK_break: return BreakStatement.enter(p); case TOK_return: return ReturnStatement.enter(p); case TOK_goto: return GotoStatement.enter(p); case TOK_with: return WithStatement.enter(p); case TOK_synchronized: // could also be a declaration? return SynchronizedStatement.enter(p); case TOK_volatile: // could also be a declaration? return VolatileStatement.enter(p); case TOK_try: return TryStatement.enter(p); case TOK_scope: p.pushState(&shiftScope); return Accept; case TOK_throw: return ThrowStatement.enter(p); case TOK_asm: return AsmStatement.enter(p); case TOK_pragma: return PragmaStatement.enter(p); case TOK_mixin: p.pushRollback(&rollbackDeclFailure); p.pushState(&shiftMixin); return Accept; case TOK_debug: case TOK_version: return ConditionalStatement.enter(p); case TOK_static: // can also be static assert or declaration p.pushToken(p.tok); p.pushState(&shiftStatic); return Accept; case TOK_Identifier: // label, declaration or expression p.pushRollback(&rollbackDeclFailure); p.pushToken(p.tok); p.pushState(&shiftIdentifier); return Accept; case TOK_enum: p.pushState(&shiftDeclaration); return EnumDeclaration.enter(p); case TOK_struct: case TOK_union: case TOK_class: case TOK_interface: p.pushState(&shiftDeclaration); return AggregateDeclaration.enter(p); case TOK_template: p.pushState(&shiftDeclaration); return TemplateDeclaration.enter(p); case TOK_align: case TOK_extern: p.pushState(&shiftDeclaration); return AttributeSpecifier.enter(p); mixin(case_TOKs_BasicTypeX); goto case; case TOK_deprecated: // case TOK_static: // case TOK_final: case TOK_override: case TOK_abstract: case TOK_const: case TOK_auto: // case TOK_scope: case TOK___gshared: case TOK___thread: case TOK___vector: case TOK_shared: case TOK_immutable: case TOK_inout: mixin(case_TOKs_FunctionAttribute); p.pushState(&shiftDeclaration); return Declaration.enter(p); case TOK_import: p.pushRollback(&rollbackDeclFailure); p.pushState(&shiftImport); return ImportDeclaration.enter(p); default: p.pushRollback(&rollbackDeclFailure); p.pushState(&shiftDecl); return Declaration.enter(p); } } // assumes identifier token pushed on token stack static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_colon: p.popRollback(); Token tok = p.popToken(); p.pushNode(new ast.LabeledStatement(tok)); p.pushState(&shiftLabeledStatement); p.pushState(&NoScopeStatement.enter); return Accept; default: p.pushState(&shiftDecl); return Decl!true.enterTypeIdentifier(p); } } static Action shiftLabeledStatement(Parser p) { p.popAppendTopNode!(ast.LabeledStatement); return Forward; } static Action shiftDecl(Parser p) { p.popRollback(); return shiftDeclaration(p); } static rollbackDeclFailure(Parser p) { return ExpressionStatement.enter(p); } static Action shiftStatic(Parser p) { switch(p.tok.id) { case TOK_if: p.popToken(); return ConditionalStatement.enterAfterStatic(p); case TOK_assert: p.popToken(); return StaticAssert.enterAfterStatic(p); default: p.pushState(&shiftDeclaration); return AttributeSpecifier.enterAfterStatic(p); } } static Action shiftMixin(Parser p) { switch(p.tok.id) { case TOK_template: p.pushState(&shiftDeclaration); return TemplateMixinDeclaration.enterAfterMixin(p); case TOK_lparen: p.pushState(&shiftMixInStatement); return MixinStatement.enterAfterMixin(p); default: return TemplateMixin.enterAfterMixin(p); } } static Action shiftScope(Parser p) { switch(p.tok.id) { case TOK_lparen: return ScopeGuardStatement.enterAfterScope(p); default: return Decl!true.enterAfterStorageClass(p, TOK_scope); } } static Action shiftDeclaration(Parser p) { p.appendReplaceTopNode(new ast.DeclarationStatement(p.topNode().span)); return Forward; } static Action shiftMixInStatement(Parser p) { switch(p.tok.id) { case TOK_semicolon: p.popRollback(); return Accept; default: // roll back for mixin expression return p.parseError("';' expected after mixin statement"); } } static Action shiftImport(Parser p) { p.popRollback(); p.appendReplaceTopNode(new ast.ImportStatement(p.topNode().span)); return Forward; } } //-- GRAMMAR_BEGIN -- //BlockStatement: // { } // { StatementList } // //StatementList: // Statement // Statement StatementList class BlockStatement : Statement { static Action enter(Parser p) { switch(p.tok.id) { case TOK_lcurly: p.pushNode(new ast.BlockStatement(p.tok)); p.pushRecoverState(&recover); p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover p.pushState(&shiftLcurly); return Accept; default: return p.parseError("opening curly brace expected"); } } static Action shiftLcurly(Parser p) { switch(p.tok.id) { case TOK_rcurly: return Accept; case TOK_EOF: return Forward; default: p.pushState(&shiftStatement); return Statement.enter(p); } } static Action shiftStatement(Parser p) { p.popAppendTopNode!(ast.BlockStatement)(); return shiftLcurly(p); } static Action recover(Parser p) { auto node = new ast.ParseRecoverNode(p.tok); if(p.nodeStack.depth) node.fulspan.start = p.topNode().fulspan.end; // record span of removed text p.pushNode(node); p.pushState(&afterRecover); return Parser.recoverSemiCurly(p); } static Action afterRecover(Parser p) { p.popAppendTopNode!(ast.BlockStatement, ast.ParseRecoverNode)(); p.pushRecoverState(&recover); p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover return shiftLcurly(p); } } //-- GRAMMAR_BEGIN -- //ExpressionStatement: // Expression ; class ExpressionStatement : Statement { mixin SequenceNode!(ast.ExpressionStatement, Expression, TOK_semicolon); } //-- GRAMMAR_BEGIN -- //DeclarationStatement: // Declaration // //IfStatement: // if ( IfCondition ) ThenStatement // if ( IfCondition ) ThenStatement else ElseStatement // //ThenStatement: // ScopeNonEmptyStatement // //ElseStatement: // ScopeNonEmptyStatement class IfStatement : Statement { // if ( IfCondition ) $ ThenStatement else ElseStatement mixin stateAppendClass!(ScopeNonEmptyStatement, shiftElse) stateThenStatement; // if ( IfCondition $ ) ThenStatement else ElseStatement mixin stateShiftToken!(TOK_rparen, stateThenStatement.shift) stateRparen; // if ( $ IfCondition ) ThenStatement else ElseStatement mixin stateAppendClass!(IfCondition, stateRparen.shift) stateCondition; // if $ ( IfCondition ) ThenStatement else ElseStatement mixin stateShiftToken!(TOK_lparen, stateCondition.shift) stateLparen; // $ if ( IfCondition ) ThenStatement else ElseStatement mixin stateEnterToken!(TOK_if, ast.IfStatement, stateLparen.shift); // if ( IfCondition ) ThenStatement $ else ElseStatement static Action shiftElse(Parser p) { switch(p.tok.id) { case TOK_else: p.pushState(&shiftElseStatement); p.pushState(&ScopeNonEmptyStatement.enter); return Accept; default: return Forward; } } // if ( IfCondition ) ThenStatement else ElseStatement $ static Action shiftElseStatement(Parser p) { p.popAppendTopNode!(ast.IfStatement, ast.Statement)(); return Forward; } } //-- GRAMMAR_BEGIN -- //IfCondition: // Expression // auto Identifier = Expression // BasicType BasicTypes2_opt Declarator = Expression // class IfCondition { static Action enter(Parser p) { p.pushRollback(&rollbackTypeFailure); p.pushState(&shiftDecl); return Decl!false.enter(p); } static Action shiftDecl(Parser p) { if(p.tok.id != TOK_rparen) return p.parseError("')' expected after declaration"); p.popRollback(); return Forward; } static Action rollbackTypeFailure(Parser p) { return Expression.enter(p); } } //-- GRAMMAR_BEGIN -- //WhileStatement: // while ( Expression ) ScopeNonEmptyStatement class WhileStatement : Statement { mixin SequenceNode!(ast.WhileStatement, TOK_while, TOK_lparen, Expression, TOK_rparen, ScopeNonEmptyStatement); } //-- GRAMMAR_BEGIN -- //DoStatement: // do ScopeNonEmptyStatement while ( Expression ) // trailing ';' currently not part of grammar ;-( class DoStatement : Statement { mixin SequenceNode!(ast.DoStatement, TOK_do, ScopeNonEmptyStatement, TOK_while, TOK_lparen, Expression, TOK_rparen); //, TOK_semicolon); } //-- GRAMMAR_BEGIN -- //ForStatement: // for ( Initialize Test ; Increment ) ScopeNonEmptyStatement //Initialize: // ; // NoScopeNonEmptyStatement // //Test: // Expression_opt // //Increment: // Expression_opt // class ForStatement : Statement { mixin SequenceNode!(ast.ForStatement, TOK_for, TOK_lparen, Initialize, Expression_opt, TOK_semicolon, Expression_opt, TOK_rparen, ScopeNonEmptyStatement); } class Initialize { static Action enter(Parser p) { switch(p.tok.id) { case TOK_semicolon: p.pushNode(new ast.EmptyStatement(p.tok)); return Accept; default: return NoScopeNonEmptyStatement.enter(p); } } } class Expression_opt { // cerates "void" if no expression static Action enter(Parser p) { switch(p.tok.id) { case TOK_semicolon: case TOK_rcurly: case TOK_rbracket: case TOK_rparen: p.pushNode(new ast.EmptyExpression(p.tok)); return Forward; default: return Expression.enter(p); } } } //-- GRAMMAR_BEGIN -- //ForeachStatement: // Foreach ( ForeachTypeList ; Aggregate ) NoScopeNonEmptyStatement // //Foreach: // foreach // foreach_reverse // //Aggregate: // Expression // Type // //ForeachRangeStatement: // Foreach ( ForeachType ; LwrExpression .. UprExpression ) ScopeNonEmptyStatement // //LwrExpression: // Expression // //UprExpression: // Expression class ForeachStatement : Statement { static Action enter(Parser p) { switch(p.tok.id) { case TOK_foreach: case TOK_foreach_reverse: p.pushNode(new ast.ForeachStatement(p.tok)); p.pushState(&stateLparen.shift); return Accept; default: return p.parseError("foreach or foreach_reverse expected"); } } // Foreach ( ForeachTypeList ; Aggregate ) $ NoScopeNonEmptyStatement mixin stateAppendClass!(NoScopeNonEmptyStatement, Parser.forward) stateStatement; // Foreach ( ForeachTypeList ; LwrExpression .. UprExpression $ ) NoScopeNonEmptyStatement mixin stateShiftToken!(TOK_rparen, stateStatement.shift) stateRparen; // Foreach ( ForeachType ; LwrExpression .. $ UprExpression ) ScopeNonEmptyStatement mixin stateAppendClass!(Expression, stateRparen.shift) stateUprExpression; // Foreach ( ForeachTypeList ; Aggregate $ ) NoScopeNonEmptyStatement // Foreach ( ForeachType ; LwrExpression $ .. UprExpression ) ScopeNonEmptyStatement static Action shiftExpression(Parser p) { switch(p.tok.id) { case TOK_slice: p.popAppendTopNode!(); p.popRollback(); p.pushState(&stateUprExpression.shift); return Accept; case TOK_rparen: p.popAppendTopNode!(); p.popRollback(); p.pushState(&stateStatement.shift); return Accept; default: return p.parseError("closing parenthesis expected"); } } static Action shiftType(Parser p) { // static foreach with type tuple switch(p.tok.id) { case TOK_rparen: p.popAppendTopNode!(); p.pushState(&stateStatement.shift); return Accept; default: return p.parseError("closing parenthesis expected"); } } // Foreach ( ForeachTypeList ; $ Aggregate ) NoScopeNonEmptyStatement static Action stateExpression(Parser p) { p.pushRollback(&rollbackExpression); p.pushState(&shiftExpression); return Expression.enter(p); } static Action rollbackExpression(Parser p) { p.pushState(&shiftType); return Type.enter(p); } // Foreach ( ForeachTypeList $ ; Aggregate ) NoScopeNonEmptyStatement mixin stateShiftToken!(TOK_semicolon, stateExpression) stateSemicolon; // Foreach ( $ ForeachTypeList ; Aggregate ) NoScopeNonEmptyStatement mixin stateAppendClass!(ForeachTypeList, stateSemicolon.shift) stateForeachTypeList; // Foreach $ ( ForeachTypeList ; Aggregate ) NoScopeNonEmptyStatement mixin stateShiftToken!(TOK_lparen, stateForeachTypeList.shift) stateLparen; } //-- GRAMMAR_BEGIN -- //ForeachTypeList: // ForeachType // ForeachType , ForeachTypeList class ForeachTypeList { mixin ListNode!(ast.ForeachTypeList, ForeachType, TOK_comma); } //-- GRAMMAR_BEGIN -- //ForeachType: // ref_opt Type_opt Identifier // class ForeachType { static Action enter(Parser p) { auto n = new ast.ForeachType(p.tok); p.pushNode(n); return shiftRef(p); } static Action shiftRef(Parser p) { switch(p.tok.id) { case TOK_ref: auto n = p.topNode!(ast.ForeachType)(); n.isRef = true; p.pushState(&shiftRef); return Accept; case TOK_Identifier: p.pushToken(p.tok); p.pushState(&shiftIdentifier); return Accept; case TOK_const: case TOK_immutable: case TOK_shared: case TOK_inout: p.pushToken(p.tok); p.pushState(&shiftTypeModifier); return Accept; default: p.pushState(&shiftType); return Type.enter(p); } } static Action shiftTypeModifier(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushState(&shiftType); return Type.enterTypeModifier(p); default: auto tok = p.popToken(); auto n = p.topNode!(ast.ForeachType)(); combineAttributes(n.attr, tokenToAttribute(tok.id)); return shiftRef(p); } } static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_semicolon: case TOK_comma: auto tok = p.popToken(); auto n = p.topNode!(ast.ForeachType)(); // add auto type here? n.addMember(new ast.Identifier(tok)); return Forward; default: p.pushState(&shiftType); return Type.enterIdentifier(p); } } static Action shiftType(Parser p) { p.popAppendTopNode!(ast.ForeachType, ast.Type)(); switch(p.tok.id) { case TOK_Identifier: p.topNode!(ast.ForeachType).addMember(new ast.Identifier(p.tok)); return Accept; default: return p.parseError("identifier expected"); } } } //-- GRAMMAR_BEGIN -- //SwitchStatement: // switch ( Expression ) ScopeNonEmptyStatement class SwitchStatement : Statement { mixin SequenceNode!(ast.SwitchStatement, TOK_switch, TOK_lparen, Expression, TOK_rparen, ScopeNonEmptyStatement); } //-- GRAMMAR_BEGIN -- //FinalSwitchStatement: // final switch ( Expression ) ScopeNonEmptyStatement // class FinalSwitchStatement : Statement { static Action enter(Parser p) { if(p.tok.id != TOK_final) return p.parseError("final expected"); p.pushState(&shiftFinal); return Accept; } static Action shiftFinal(Parser p) { if(p.tok.id != TOK_switch) return p.parseError("switch expected"); p.pushState(&shiftSwitch); return SwitchStatement.enter(p); } static Action shiftSwitch(Parser p) { p.topNode!(ast.SwitchStatement)().isFinal = true; return Forward; } } //-- GRAMMAR_BEGIN -- //CaseStatement: // case ArgumentList : Statement_opt // //CaseRangeStatement: // case FirstExp : .. case LastExp : Statement_opt // //FirstExp: // AssignExpression // //LastExp: // AssignExpression class CaseStatement : Statement { // also used by DefaultStatement static Action stateStatement(Parser p) { return Forward; /+ switch(p.tok.id) { case TOK_case: case TOK_default: case TOK_rcurly: return Forward; default: p.pushState(&Parser.popForward); return Statement.enter(p); } +/ } // argument list mixin stateShiftToken!(TOK_comma, stateArgumentList_shift, TOK_colon, stateStatement) stateAfterArg; // mixin expanded due to unresolvable forward references // mixin stateAppendClass!(AssignExpression, stateAfterArg.shift) stateArgumentList; static Action stateArgumentList_shift(Parser p) { p.pushState(&stateArgumentList_reduce); return AssignExpression.enter(p); } static Action stateArgumentList_reduce(Parser p) { p.popAppendTopNode!(); return stateAfterArg.shift(p); } // range mixin stateShiftToken!(TOK_colon, stateStatement) stateAfterLast; mixin stateAppendClass!(AssignExpression, stateAfterLast.shift) stateCaseLast; mixin stateShiftToken!(TOK_case, stateCaseLast.shift) stateRange; static Action stateRememberRange(Parser p) { p.topNode!(ast.CaseStatement).id = TOK_slice; return stateRange.shift(p); } // disambiguation mixin stateShiftToken!(TOK_slice, stateRememberRange, -1, stateStatement) stateFirstArgument; mixin stateShiftToken!(TOK_comma, stateArgumentList_shift, TOK_colon, stateFirstArgument.shift) stateAfterFirstArg; mixin stateAppendClass!(AssignExpression, stateAfterFirstArg.shift) stateArgument; // $ case ArgumentList : Statement // $ case AssignExpression : Statement // $ case FirstExp : .. case LastExp : Statement mixin stateEnterToken!(TOK_case, ast.CaseStatement, stateArgument.shift); } //-- GRAMMAR_BEGIN -- //DefaultStatement: // default : Statement_opt class DefaultStatement : Statement { mixin SequenceNode!(ast.DefaultStatement, TOK_default, TOK_colon, CaseStatement.stateStatement); } //-- GRAMMAR_BEGIN -- //ContinueStatement: // continue ; // continue Identifier ; class ContinueStatement : Statement { mixin SequenceNode!(ast.ContinueStatement, TOK_continue, Identifier_opt!(ast.ContinueStatement), TOK_semicolon); } class Identifier_opt(T) : Statement { enum doNotPopNode = true; static Action enter(Parser p) { if(p.tok.id == TOK_Identifier) { p.topNode!T().ident = p.tok.txt; return Accept; } return Forward; } } //-- GRAMMAR_BEGIN -- //BreakStatement: // break ; // break Identifier ; class BreakStatement : Statement { mixin SequenceNode!(ast.BreakStatement, TOK_break, Identifier_opt!(ast.BreakStatement), TOK_semicolon); } //-- GRAMMAR_BEGIN -- //ReturnStatement: // return ; // return Expression ; class ReturnStatement : Statement { mixin SequenceNode!(ast.ReturnStatement, TOK_return, Expression_opt, TOK_semicolon); } //-- GRAMMAR_BEGIN -- //GotoStatement: // goto Identifier ; // goto default ; // goto case ; // goto case Expression ; class GotoStatement : Statement { mixin stateShiftToken!(TOK_semicolon, Parser.forward) stateSemicolon; mixin stateAppendClass!(Expression, stateSemicolon.shift) stateExpression; mixin stateShiftToken!(TOK_semicolon, Parser.forward, -1, stateExpression.shift) stateCase; static Action rememberArgument(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.topNode!(ast.GotoStatement).ident = p.tok.txt; p.topNode!(ast.GotoStatement).id = TOK_Identifier; p.pushState(&stateSemicolon.shift); return Accept; case TOK_default: p.topNode!(ast.GotoStatement).id = TOK_default; p.pushState(&stateSemicolon.shift); return Accept; case TOK_case: p.topNode!(ast.GotoStatement).id = TOK_case; p.pushState(&stateCase.shift); return Accept; default: return p.parseError("identifier, case or default expected in goto statement"); } } mixin stateEnterToken!(TOK_goto, ast.GotoStatement, rememberArgument); } //-- GRAMMAR_BEGIN -- //WithStatement: // with ( Expression ) ScopeNonEmptyStatement // with ( Symbol ) ScopeNonEmptyStatement // with ( TemplateInstance ) ScopeNonEmptyStatement class WithStatement : Statement { // Symbol, TemplateInstance also syntactically included by Expression mixin SequenceNode!(ast.WithStatement, TOK_with, TOK_lparen, Expression, TOK_rparen, ScopeNonEmptyStatement); } //-- GRAMMAR_BEGIN -- //SynchronizedStatement: // synchronized ScopeNonEmptyStatement // synchronized ( Expression ) ScopeNonEmptyStatement class SynchronizedStatement : Statement { mixin stateAppendClass!(ScopeNonEmptyStatement, Parser.forward) stateStatement; mixin stateShiftToken!(TOK_rparen, stateStatement.shift) stateRparen; mixin stateAppendClass!(Expression, stateRparen.shift) stateExpression; mixin stateShiftToken!(TOK_lparen, stateExpression.shift, -1, stateStatement.shift) stateLparen; mixin stateEnterToken!(TOK_synchronized, ast.SynchronizedStatement, stateLparen.shift); } //-- GRAMMAR_BEGIN -- //VolatileStatement: // volatile ScopeNonEmptyStatement class VolatileStatement : Statement { mixin SequenceNode!(ast.VolatileStatement, TOK_volatile, ScopeNonEmptyStatement); } //-- GRAMMAR_BEGIN -- //TryStatement: // try ScopeNonEmptyStatement Catches // try ScopeNonEmptyStatement Catches FinallyStatement // try ScopeNonEmptyStatement FinallyStatement // //Catches: // LastCatch // Catch // Catch Catches // //LastCatch: // catch NoScopeNonEmptyStatement // //FinallyStatement: // finally NoScopeNonEmptyStatement class TryStatement : Statement { mixin stateAppendClass!(FinallyStatement, Parser.forward) stateFinally; static Action reduceLastCatch(Parser p) { p.popAppendTopNode!(ast.Catch, ast.Statement)(); p.popAppendTopNode!(ast.TryStatement, ast.Catch)(); switch(p.tok.id) { case TOK_finally: return stateFinally.shift(p); default: return Forward; } } static Action reduceCatch(Parser p) { p.popAppendTopNode!(ast.TryStatement, ast.Catch)(); return stateCatches_shift(p); } static Action shiftCatch(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushState(&reduceCatch); return Catch.enterAfterCatch(p); default: p.pushState(&reduceLastCatch); p.pushNode(new ast.Catch(p.tok)); return NoScopeNonEmptyStatement.enter(p); } } static Action stateCatches_shift(Parser p) { switch(p.tok.id) { case TOK_catch: p.pushState(&shiftCatch); return Accept; case TOK_finally: return stateFinally.shift(p); default: if(p.topNode!(ast.TryStatement).members.length < 2) return p.parseError("catch or finally expected"); return Forward; } } mixin stateAppendClass!(ScopeNonEmptyStatement, stateCatches_shift) stateTryStatement; mixin stateEnterToken!(TOK_try, ast.TryStatement, stateTryStatement.shift); } //-- GRAMMAR_BEGIN -- //Catch: // catch ( CatchParameter ) NoScopeNonEmptyStatement // //CatchParameter: // BasicType Identifier class Catch { mixin SequenceNode!(ast.Catch, TOK_catch, TOK_lparen, BasicType, Opt!(Identifier, TOK_Identifier), TOK_rparen, NoScopeNonEmptyStatement); static Action enterAfterCatch(Parser p) { p.pushNode(new ast.Catch(p.tok)); return shift1.shift(p); } } class FinallyStatement { mixin SequenceNode!(ast.FinallyStatement, TOK_finally, NoScopeNonEmptyStatement); } //-- GRAMMAR_BEGIN -- //ThrowStatement: // throw Expression ; class ThrowStatement : Statement { mixin SequenceNode!(ast.ThrowStatement, TOK_throw, Expression, TOK_semicolon); } //-- GRAMMAR_BEGIN -- //ScopeGuardStatement: // scope ( "exit" ) ScopeNonEmptyStatement // scope ( "success" ) ScopeNonEmptyStatement // scope ( "failure" ) ScopeNonEmptyStatement class ScopeGuardStatement : Statement { mixin SequenceNode!(ast.ScopeGuardStatement, TOK_scope, TOK_lparen, ScopeGuardIdentifier, TOK_rparen, ScopeNonEmptyStatement); static Action enterAfterScope(Parser p) { p.pushNode(new ast.ScopeGuardStatement(p.tok)); return shift1.shift(p); } } class ScopeGuardIdentifier { static Action enter(Parser p) { if(p.tok.id != TOK_Identifier) return p.parseError("identifier expected"); if(!isIn(p.tok.txt, "exit", "success", "failure")) return p.parseError("one of exit, success and failure expected in scope guard statement"); p.pushNode(new ast.Identifier(p.tok)); return Accept; } } //-- GRAMMAR_BEGIN -- //AsmStatement: // asm { } // asm { AsmInstructionList } // //AsmInstructionList: // AsmInstruction ; // AsmInstruction ; AsmInstructionList class AsmStatement : Statement { mixin SequenceNode!(ast.AsmStatement, TOK_asm, TOK_lcurly, AsmInstructionList, TOK_rcurly); } class AsmInstructionList { mixin ListNode!(ast.AsmInstructionList, AsmInstruction, TOK_semicolon, true); } //-- GRAMMAR_BEGIN -- //PragmaStatement: // Pragma NoScopeStatement class PragmaStatement : Statement { mixin SequenceNode!(ast.PragmaStatement, Pragma, NoScopeStatement); } //-- GRAMMAR_BEGIN -- //MixinStatement: // mixin ( AssignExpression ) ; class MixinStatement : Statement { mixin SequenceNode!(ast.MixinStatement, TOK_mixin, TOK_lparen, AssignExpression, TOK_rparen); static Action enterAfterMixin(Parser p) { p.pushNode(new ast.MixinStatement(p.tok)); return shift1.shift(p); } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/expr.d0000664000175000017500000013126612776214756027162 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.parser.expr; import vdc.util; import vdc.lexer; import vdc.parser.engine; import vdc.parser.decl; import vdc.parser.tmpl; import vdc.parser.misc; import vdc.parser.aggr; import ast = vdc.ast.all; alias ast.PREC PREC; //////////////////////////////////////////////////////////////// //-- GRAMMAR_BEGIN -- //Expression: // CommaExpression class Expression { static Action enter(Parser p) { return CommaExpression.enter(p); } } class BinaryExpression : Expression { } mixin template BinaryExpr(ASTNodeType, PREC prec, string recursion, SubType, ops...) { shared static this() { foreach(o; ops) { ast.precedence[o] = prec; ast.recursion[o] = recursion[0]; } } mixin BinaryNode!(ASTNodeType, recursion, SubType, ops); } //-- GRAMMAR_BEGIN -- //CommaExpression: // AssignExpression // AssignExpression , CommaExpression class CommaExpression : BinaryExpression { mixin BinaryExpr!(ast.CommaExpression, PREC.expr, "R", AssignExpression, TOK_comma); } //-- GRAMMAR_BEGIN -- //AssignExpression: // ConditionalExpression // ConditionalExpression = AssignExpression // ConditionalExpression += AssignExpression // ConditionalExpression -= AssignExpression // ConditionalExpression *= AssignExpression // ConditionalExpression /= AssignExpression // ConditionalExpression %= AssignExpression // ConditionalExpression &= AssignExpression // ConditionalExpression |= AssignExpression // ConditionalExpression ^= AssignExpression // ConditionalExpression ~= AssignExpression // ConditionalExpression <<= AssignExpression // ConditionalExpression >>= AssignExpression // ConditionalExpression >>>= AssignExpression // ConditionalExpression ^^= AssignExpression class AssignExpression : BinaryExpression { mixin BinaryExpr!(ast.AssignExpression, PREC.assign, "R", ConditionalExpression, TOK_assign, TOK_addass, TOK_minass, TOK_mulass, TOK_divass, TOK_modass, TOK_andass, TOK_orass, TOK_xorass, TOK_catass, TOK_shlass, TOK_shrass, TOK_ushrass, TOK_powass); } //-- GRAMMAR_BEGIN -- //ConditionalExpression: // OrOrExpression // OrOrExpression ? Expression : ConditionalExpression class ConditionalExpression : Expression { mixin TernaryNode!(ast.ConditionalExpression, OrOrExpression, TOK_question, Expression, TOK_colon); } //-- GRAMMAR_BEGIN -- //OrOrExpression: // AndAndExpression // OrOrExpression || AndAndExpression class OrOrExpression : BinaryExpression { mixin BinaryExpr!(ast.OrOrExpression, PREC.oror, "L", AndAndExpression, TOK_oror); } //-- GRAMMAR_BEGIN -- //AndAndExpression: // OrExpression // AndAndExpression && OrExpression class AndAndExpression : BinaryExpression { mixin BinaryExpr!(ast.AndAndExpression, PREC.andand, "L", OrExpression, TOK_andand); } //-- GRAMMAR_BEGIN -- //OrExpression: // XorExpression // OrExpression | XorExpression class OrExpression : BinaryExpression { mixin BinaryExpr!(ast.OrExpression, PREC.or, "L", XorExpression, TOK_or); } //-- GRAMMAR_BEGIN -- //XorExpression: // AndExpression // XorExpression ^ AndExpression class XorExpression : BinaryExpression { mixin BinaryExpr!(ast.XorExpression, PREC.xor, "L", AndExpression, TOK_xor); } //-- GRAMMAR_BEGIN -- //AndExpression: // CmpExpression // AndExpression & CmpExpression class AndExpression : BinaryExpression { mixin BinaryExpr!(ast.AndExpression, PREC.and, "L", CmpExpression, TOK_and); } //-- GRAMMAR_BEGIN -- //CmpExpression: // ShiftExpression // EqualExpression // IdentityExpression // RelExpression // InExpression // //EqualExpression: // ShiftExpression == ShiftExpression // ShiftExpression != ShiftExpression // //IdentityExpression: // ShiftExpression is ShiftExpression // ShiftExpression !is ShiftExpression // //RelExpression: // ShiftExpression < ShiftExpression // ShiftExpression <= ShiftExpression // ShiftExpression > ShiftExpression // ShiftExpression >= ShiftExpression // ShiftExpression !<>= ShiftExpression // ShiftExpression !<> ShiftExpression // ShiftExpression <> ShiftExpression // ShiftExpression <>= ShiftExpression // ShiftExpression !> ShiftExpression // ShiftExpression !>= ShiftExpression // ShiftExpression !< ShiftExpression // ShiftExpression !<= ShiftExpression // //InExpression: // ShiftExpression in ShiftExpression // ShiftExpression !in ShiftExpression class CmpExpression : BinaryExpression { static if(!supportUnorderedCompareOps) mixin BinaryExpr!(ast.CmpExpression, PREC.rel, "N", ShiftExpression, TOK_equal, TOK_notequal, TOK_is, TOK_notidentity, TOK_lt, TOK_le, TOK_gt, TOK_ge, // TOK_unord, TOK_ue, TOK_lg, TOK_leg, TOK_ule, TOK_ul, TOK_uge, TOK_ug, TOK_in, TOK_notcontains); else mixin BinaryExpr!(ast.CmpExpression, PREC.rel, "N", ShiftExpression, TOK_equal, TOK_notequal, TOK_is, TOK_notidentity, TOK_lt, TOK_le, TOK_gt, TOK_ge, // TOK_unord, TOK_ue, TOK_lg, TOK_leg, TOK_ule, TOK_ul, TOK_uge, TOK_ug, TOK_in, TOK_notcontains); } //-- GRAMMAR_BEGIN -- //ShiftExpression: // AddExpression // ShiftExpression << AddExpression // ShiftExpression >> AddExpression // ShiftExpression >>> AddExpression class ShiftExpression : BinaryExpression { mixin BinaryExpr!(ast.ShiftExpression, PREC.shift, "L", AddExpression, TOK_shl, TOK_shr, TOK_ushr); } //-- GRAMMAR_BEGIN -- //AddExpression: // MulExpression // AddExpression + MulExpression // AddExpression - MulExpression // CatExpression: //CatExpression: // AddExpression ~ MulExpression class AddExpression : BinaryExpression { mixin BinaryExpr!(ast.AddExpression, PREC.add, "L", MulExpression, TOK_add, TOK_min, TOK_tilde); } //-- GRAMMAR_BEGIN -- //MulExpression: // SignExpression // MulExpression * SignExpression // MulExpression / SignExpression // MulExpression % SignExpression class MulExpression : BinaryExpression { mixin BinaryExpr!(ast.MulExpression, PREC.mul, "L", SignExpression, TOK_mul, TOK_div, TOK_mod); } //-- GRAMMAR_BEGIN -- //SignExpression: // PowExpression // + SignExpression // - SignExpression class SignExpression : Expression { static Action enter(Parser p) { switch(p.tok.id) { case TOK_min: case TOK_add: auto expr = new ast.UnaryExpression(p.tok); p.pushNode(expr); p.pushState(&shift); p.pushState(&enter); return Accept; default: return PowExpression.enter(p); } } static Action shift(Parser p) { p.popAppendTopNode!(ast.UnaryExpression)(); return Forward; } } //-- GRAMMAR_BEGIN -- //PowExpression: // UnaryExpression // UnaryExpression ^^ SignExpression class PowExpression : BinaryExpression { static Action shiftExponent(Parser p) { p.popAppendTopNode!(ast.PowExpression)(); return Forward; } static Action shiftPow(Parser p) { switch(p.tok.id) { case TOK_pow: auto pe = new ast.PowExpression(p.tok); p.appendReplaceTopNode(pe); p.pushState(&shiftExponent); p.pushState(&SignExpression.enter); return Accept; default: return Forward; } } mixin stateEnterClass!(UnaryExpression, NoASTNode, shiftPow); } //-- GRAMMAR_BEGIN -- //UnaryExpression: // PostfixExpression // & UnaryExpression // ++ UnaryExpression // -- UnaryExpression // * UnaryExpression // - UnaryExpression // + UnaryExpression // ! UnaryExpression // ~ UnaryExpression // NewExpression // DeleteExpression // CastExpression // /*NewAnonClassExpression*/ // // DeleteExpression: // delete UnaryExpression class UnaryExpression : Expression { static Action enter(Parser p) { switch(p.tok.id) { case TOK_and: case TOK_plusplus: case TOK_minusminus: case TOK_mul: case TOK_min: case TOK_add: case TOK_not: case TOK_tilde: case TOK_delete: auto expr = new ast.UnaryExpression(p.tok); p.pushNode(expr); p.pushState(&shift); p.pushState(&enter); return Accept; case TOK_new: return NewExpression.enter(p); case TOK_cast: return CastExpression.enter(p); default: return PostfixExpression.enter(p); } } static Action shift(Parser p) { p.popAppendTopNode!(ast.UnaryExpression)(); return Forward; } } //-- GRAMMAR_BEGIN -- //NewExpression: // NewArguments Type [ AssignExpression ] // NewArguments Type ( ArgumentList ) // NewArguments Type // NewArguments ClassArguments BaseClassList_opt { DeclDefs_opt } // //NewArguments: // new ( ArgumentList ) // new ( ) // new // //ClassArguments: // class ( ArgumentList ) // class ( ) // class class NewExpression : UnaryExpression { static Action enter(Parser p) { p.pushNode(new ast.NewExpression(p.tok)); switch(p.tok.id) { case TOK_new: p.pushState(&shiftNew); return Accept; default: return p.parseError("new expected"); } } static Action shiftNew(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushState(&shiftNewLparen); return Accept; case TOK_class: p.pushState(&shiftClass); return AnonymousClass.enter(p); default: p.pushState(&shiftType); return Type.enter(p); } } static Action shiftType(Parser p) { p.popAppendTopNode!(ast.NewExpression); switch(p.tok.id) { // [] are parsed as part of the type case TOK_lparen: p.pushState(&shiftTypeLparen); return Accept; default: return Forward; } } static Action shiftTypeLparen(Parser p) { switch(p.tok.id) { case TOK_rparen: return Accept; // empty argument list as good as none default: p.pushState(&shiftArgumentList); return ArgumentList.enter(p); } } static Action shiftArgumentList(Parser p) { switch(p.tok.id) { // [] are parsed as part of the type case TOK_rparen: p.popAppendTopNode!(ast.NewExpression); return Accept; default: return p.parseError("')' expected"); } } static Action shiftNewLparen(Parser p) { p.pushState(&shiftNewArgumentList); return ArgumentList.enter(p); } static Action shiftNewArgumentList(Parser p) { p.popAppendTopNode!(ast.NewExpression); p.topNode!(ast.NewExpression).hasNewArgs = true; switch(p.tok.id) { case TOK_rparen: p.pushState(&shiftRparen); return Accept; default: return p.parseError("')' expected for new argument list"); } } static Action shiftRparen(Parser p) { switch(p.tok.id) { case TOK_class: p.pushState(&shiftClass); return AnonymousClass.enter(p); default: p.pushState(&shiftType); return Type.enter(p); } } static Action shiftClass(Parser p) { p.popAppendTopNode!(ast.NewExpression); return Forward; } } //-- GRAMMAR_BEGIN -- // AnonymousClass: // ClassArguments BaseClassList_opt { DeclDefs_opt } class AnonymousClass { static Action enter(Parser p) { switch(p.tok.id) { case TOK_class: p.pushNode(new ast.AnonymousClassType(p.tok)); p.pushState(&shiftClass); return Accept; default: return p.parseError("class expected"); } } static Action shiftClass(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushState(&shiftLparen); return Accept; default: p.pushState(&shiftClassDeclaration); return AggregateDeclaration.enterAnonymousClass(p); } } static Action shiftLparen(Parser p) { switch(p.tok.id) { case TOK_rparen: p.topNode!(ast.AnonymousClassType).addMember(new ast.ArgumentList(p.tok)); p.pushState(&shiftClassDeclaration); p.pushState(&AggregateDeclaration.enterAnonymousClass); return Accept; default: p.pushState(&shiftArgumentList); return ArgumentList.enter(p); } } static Action shiftClassDeclaration(Parser p) { p.popAppendTopNode!(ast.AnonymousClassType); return Forward; } static Action shiftArgumentList(Parser p) { switch(p.tok.id) { case TOK_rparen: p.popAppendTopNode!(ast.AnonymousClassType); p.pushState(&shiftClassDeclaration); p.pushState(&AggregateDeclaration.enterAnonymousClass); return Accept; default: return p.parseError("')' expected"); } } } //-- GRAMMAR_BEGIN -- //CastExpression: // cast ( Type ) UnaryExpression // cast ( ) UnaryExpression // cast ( const ) UnaryExpression // cast ( const shared ) UnaryExpression // cast ( immutable ) UnaryExpression // cast ( inout ) UnaryExpression // cast ( inout shared ) UnaryExpression // cast ( shared ) UnaryExpression // cast ( shared const ) UnaryExpression // cast ( shared inout ) UnaryExpression class CastExpression : UnaryExpression { mixin stateAppendClass!(UnaryExpression, Parser.forward) stateExpression; static Action shiftType(Parser p) { p.popAppendTopNode!(ast.CastExpression)(); switch(p.tok.id) { case TOK_rparen: p.pushState(&stateExpression.shift); return Accept; default: return p.parseError("')' expected"); } } mixin stateShiftToken!(TOK_rparen, stateExpression.shift) stateRparen; static Action shiftModifier(Parser p) { Token tok; switch(p.tok.id) { case TOK_rparen: tok = p.popToken(); p.topNode!(ast.CastExpression)().attr = tokenToAttribute(tok.id); p.pushState(&stateExpression.shift); return Accept; case TOK_const: case TOK_inout: tok = p.topToken(); if(tok.id != TOK_shared) goto default; L_combineAttr: tok = p.popToken(); auto attr = tokenToAttribute(tok.id); p.combineAttributes(attr, tokenToAttribute(p.tok.id)); p.topNode!(ast.CastExpression)().attr = attr; p.pushState(&stateRparen.shift); return Accept; case TOK_shared: tok = p.topToken(); if(tok.id != TOK_inout && tok.id != TOK_const) goto default; goto L_combineAttr; default: p.pushState(&shiftType); return Type.enterTypeModifier(p); } } static Action stateType(Parser p) { switch(p.tok.id) { case TOK_rparen: p.pushState(&stateExpression.shift); return Accept; case TOK_const: case TOK_immutable: case TOK_inout: case TOK_shared: p.pushToken(p.tok); p.pushState(&shiftModifier); return Accept; default: p.pushState(&shiftType); return Type.enter(p); } } mixin stateShiftToken!(TOK_lparen, stateType) stateLparen; mixin stateEnterToken!(TOK_cast, ast.CastExpression, stateLparen.shift); } //-- GRAMMAR_BEGIN -- //PostfixExpression: // PrimaryExpression // PostfixExpression . IdentifierOrTemplateInstance // PostfixExpression . NewExpression // PostfixExpression ++ // PostfixExpression -- // PostfixExpression ( ) // PostfixExpression ( ArgumentList ) // IndexExpression // SliceExpression // //IndexExpression: // PostfixExpression [ ArgumentList ] // //SliceExpression: // PostfixExpression [ ] // PostfixExpression [ AssignExpression .. AssignExpression ] class PostfixExpression : Expression { static Action enter(Parser p) { p.pushState(&shift); return PrimaryExpression.enter(p); } static Action shift(Parser p) { switch(p.tok.id) { case TOK_plusplus: case TOK_minusminus: p.appendReplaceTopNode(new ast.PostfixExpression(p.tok)); return Accept; case TOK_dot: p.pushState(&shiftDot); p.appendReplaceTopNode(new ast.DotExpression(p.tok)); return Accept; case TOK_lparen: p.pushState(&shiftLParen); p.appendReplaceTopNode(new ast.PostfixExpression(p.tok)); return Accept; case TOK_lbracket: p.pushState(&shiftLBracket); p.appendReplaceTopNode(new ast.PostfixExpression(p.tok)); return Accept; default: return Forward; } } static Action shiftDot(Parser p) { switch(p.tok.id) { case TOK_Identifier: auto expr = p.topNode!(ast.DotExpression)(); expr.id = TOK_dot; p.pushState(&shiftIdentifierOrTemplateInstance); return IdentifierOrTemplateInstance.enter(p); case TOK_RECOVER: auto expr = p.topNode!(ast.DotExpression)(); expr.id = TOK_dot; auto id = new ast.Identifier(p.tok); expr.addMember(id); return Forward; case TOK_new: p.pushState(&shiftNewExpression); return NewExpression.enter(p); default: return p.parseError("identifier or new expected after '.'"); } } static Action shiftIdentifierOrTemplateInstance(Parser p) { p.popAppendTopNode!(ast.PostfixExpression, ast.Identifier)(); return shift(p); } static Action shiftLParen(Parser p) { if(p.tok.id == TOK_rparen) { p.pushState(&shift); return Accept; } p.pushState(&shiftRParen); return ArgumentList.enter(p); // ArgumentList also starts with AssignExpression } static Action shiftRParen(Parser p) { if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected"); p.popAppendTopNode!(ast.PostfixExpression)(); p.pushState(&shift); return Accept; } static Action shiftLBracket(Parser p) { if(p.tok.id == TOK_rbracket) { p.pushState(&shift); return Accept; } p.pushState(&shiftRBracket); return ArgumentList.enter(p); } static Action shiftRBracket(Parser p) { if(p.tok.id == TOK_slice) { // throw away the argument list, just use the expression ast.Node arglist = p.popNode(); if (arglist.members.length != 1) return p.parseError("a single expression is expected before .."); p.topNode().addMember(arglist.removeMember(0)); p.pushState(&shiftSlice); p.pushState(&AssignExpression.enter); return Accept; } else if(p.tok.id != TOK_rbracket) return p.parseError("closing bracket or .. expected"); p.popAppendTopNode!(ast.PostfixExpression)(); p.pushState(&shift); return Accept; } static Action shiftSlice(Parser p) { if(p.tok.id != TOK_rbracket) return p.parseError("closing bracket expected"); p.popAppendTopNode!(ast.PostfixExpression)(); p.pushState(&shift); return Accept; } static Action shiftNewExpression(Parser p) { p.popAppendTopNode!(ast.PostfixExpression)(); auto expr = p.topNode!(ast.PostfixExpression)(); expr.id = TOK_new; return Forward; } } //-- GRAMMAR_BEGIN -- //ArgumentList: // AssignExpression // AssignExpression , // AssignExpression , ArgumentList class ArgumentList { mixin ListNode!(ast.ArgumentList, AssignExpression, TOK_comma, true); } //-- GRAMMAR_BEGIN -- //Arguments: // ( ) // ( ArgumentList ) class Arguments { mixin SequenceNode!(NoASTNode, TOK_lparen, EmptyArgumentList, TOK_rparen); } class EmptyArgumentList { mixin ListNode!(ast.ArgumentList, AssignExpression, TOK_comma, false, true); } //-- GRAMMAR_BEGIN -- //PrimaryExpression: // IdentifierOrTemplateInstance // . IdentifierOrTemplateInstance // this // super // null // true // false // $ // __FILE__ // __LINE__ // IntegerLiteral // FloatLiteral // CharacterLiteral // StringLiteral // ArrayLiteral // AssocArrayLiteral // Lambda // FunctionLiteral // StructLiteral // deprecated // AssertExpression // MixinExpression // ImportExpression // TypeidExpression // IsExpression // ( Expression ) // BasicType . IdentifierOrTemplateInstance // Typeof . IdentifierOrTemplateInstance // ( Type ) . IdentifierOrTemplateInstance // BasicType Arguments // Typeof Arguments // ( Type ) Arguments // TraitsExpression class PrimaryExpression : Expression { static Action enter(Parser p) { switch(p.tok.id) { case TOK_typeid: return TypeIdExpression.enter(p); case TOK_is: return IsExpression.enter(p); case TOK_notidentity: return IsExpression.enterNotIs(p); case TOK_import: return ImportExpression.enter(p); case TOK_mixin: return MixinExpression.enter(p); case TOK_assert: return AssertExpression.enter(p); case TOK___traits: return TraitsExpression.enter(p); case TOK_this: case TOK_super: case TOK_null: case TOK_true: case TOK_false: case TOK_dollar: case TOK___FILE__: case TOK___LINE__: case TOK___FUNCTION__: case TOK___PRETTY_FUNCTION__: case TOK___MODULE__: auto expr = new ast.PrimaryExpression(p.tok); p.pushNode(expr); return Accept; case TOK_typeof: // cannot make this part of Type, because it will also eat the property p.pushState(&shiftType); return Typeof.enter(p); case TOK___vector: mixin(case_TOKs_TypeModifier); mixin(case_TOKs_BasicTypeX); p.pushState(&shiftType); return Type.enter(p); case TOK_dot: p.pushState(&shiftDot); return Accept; case TOK_Identifier: p.pushToken(p.tok); p.pushState(&shiftIdentifier); return Accept; case TOK_IntegerLiteral: p.pushNode(new ast.IntegerLiteralExpression(p.tok)); return Accept; case TOK_FloatLiteral: p.pushNode(new ast.FloatLiteralExpression(p.tok)); return Accept; case TOK_CharacterLiteral: p.pushNode(new ast.CharacterLiteralExpression(p.tok)); return Accept; case TOK_StringLiteral: p.pushNode(new ast.StringLiteralExpression(p.tok)); p.pushState(&shiftStringLiteral); return Accept; case TOK_lbracket: return ArrayLiteral.enter(p); case TOK_delegate: case TOK_function: return FunctionLiteral!true.enter(p); // SPEC: allowing lambda not in the language spec case TOK_lcurly: p.pushRollback(&rollbackFunctionLiteralFailure); p.pushState(&shiftFunctionLiteral); return FunctionLiteral!false.enter(p); case TOK_lparen: p.pushRollback(&rollbackExpressionFailure); p.pushState(&shiftLparenExpr); p.pushState(&Expression.enter); return Accept; default: return p.parseError("primary expression expected"); } } static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_lambda: // id => expr auto tok = p.popToken(); auto lambda = new ast.Lambda(p.tok); auto pdecl = new ast.ParameterDeclarator; auto type = new ast.AutoType; auto id = new ast.Declarator(tok); pdecl.addMember(type); pdecl.addMember(id); auto pl = new ast.ParameterList; pl.addMember(pdecl); lambda.addMember(pl); p.pushNode(lambda); p.pushState(&shiftLambda); p.pushState(&AssignExpression.enter); return Accept; default: auto tok = p.topToken(); p.pushNode(new ast.IdentifierExpression(tok)); p.pushState(&shiftIdentifierOrTemplateInstance); return IdentifierOrTemplateInstance.enterIdentifier(p); } } static Action shiftLambda(Parser p) { p.popAppendTopNode!(ast.Lambda)(); return Forward; } // ( Expression ) // ( Type ) . Identifier // FunctionLiteral: ParameterAttributes FunctionBody static Action shiftLparenExpr(Parser p) { if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected"); p.pushState(&shiftRparenExpr); return Accept; } static Action shiftRparenExpr(Parser p) { if(p.tok.id == TOK_lcurly || p.tok.id == TOK_lambda) return Reject; p.popRollback(); return Forward; } static Action rollbackExpressionFailure(Parser p) { assert(p.tok.id == TOK_lparen); p.pushRollback(&rollbackTypeFailure); p.pushState(&shiftLparenType); p.pushState(&Type.enter); return Accept; } static Action rollbackFunctionLiteralFailure(Parser p) { assert(p.tok.id == TOK_lcurly || p.tok.id == TOK_lambda); return StructLiteral.enter(p); } static Action shiftFunctionLiteral(Parser p) { p.popRollback(); return Forward; } static Action shiftLparenType(Parser p) { if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected"); p.pushState(&shiftLparenTypeDot); return Accept; } static Action shiftLparenTypeDot(Parser p) { switch(p.tok.id) { case TOK_dot: p.popRollback(); p.appendReplaceTopNode(new ast.TypeProperty(p.tok)); p.pushState(&shiftTypeDot); p.pushState(&IdentifierOrTemplateInstance.enter); return Accept; case TOK_lparen: p.popRollback(); p.appendReplaceTopNode(new ast.StructConstructor(p.tok)); p.pushState(&shiftStructArguments); return Arguments.enter(p); default: return p.parseError("'.' expected for type property"); } } static Action rollbackTypeFailure(Parser p) { assert(p.tok.id == TOK_lparen); return FunctionLiteral!true.enter(p); } static Action shiftDot(Parser p) { if(p.tok.id != TOK_Identifier) return p.parseError("identifier expected"); auto id = new ast.IdentifierExpression(p.tok); id.global = true; p.pushNode(id); p.pushState(&shiftIdentifierOrTemplateInstance); return IdentifierOrTemplateInstance.enter(p); } static Action shiftIdentifierOrTemplateInstance(Parser p) { p.popAppendTopNode!(ast.IdentifierExpression, ast.Identifier)(); return Forward; } // BasicType . Identifier static Action shiftType(Parser p) { switch(p.tok.id) { case TOK_dot: p.appendReplaceTopNode(new ast.TypeProperty(p.tok)); p.pushState(&shiftTypeDot); p.pushState(&IdentifierOrTemplateInstance.enter); return Accept; case TOK_lparen: p.appendReplaceTopNode(new ast.StructConstructor(p.tok)); p.pushState(&shiftStructArguments); return Arguments.enter(p); default: return p.parseError("'.' expected for type property"); } } static Action shiftTypeDot(Parser p) { p.popAppendTopNode!(ast.TypeProperty)(); return Forward; } static Action shiftStructArguments(Parser p) { p.popAppendTopNode!(ast.StructConstructor)(); return Forward; } static Action shiftStringLiteral(Parser p) { switch(p.tok.id) { case TOK_StringLiteral: p.topNode!(ast.StringLiteralExpression).addText(p.tok); p.pushState(&shiftStringLiteral); return Accept; default: return Forward; } } } //-- GRAMMAR_BEGIN -- //VoidInitializer: // void // //ArrayLiteral: // [ ArgumentList ] // //AssocArrayLiteral: // [ KeyValuePairs ] class ArrayLiteral : Expression { // combines all array literals, has to be disambiguated when assigned mixin SequenceNode!(ast.ArrayLiteral, TOK_lbracket, ArrayValueList, TOK_rbracket); } //-- GRAMMAR_BEGIN -- //ArrayValueList: // ArrayValue // ArrayValue , ArrayValue class ArrayValueList { mixin ListNode!(ast.ArgumentList, ArrayValue, TOK_comma, true, true); } //-- GRAMMAR_BEGIN -- //ArrayValue: // AssignExpression // AssignExpression : AssignExpression class ArrayValue : BinaryExpression { mixin stateAppendClass!(AssignExpression, Parser.forward) stateValue; static Action statePrepareValue(Parser p) { auto kp = new ast.KeyValuePair(p.tok); p.appendReplaceTopNode(kp); return stateValue.shift(p); } mixin stateShiftToken!(TOK_colon, statePrepareValue, -1) stateColon; mixin stateEnterClass!(AssignExpression, NoASTNode, stateColon.shift); } //-- GRAMMAR_BEGIN -- //FunctionLiteral: // function Type_opt ParameterAttributes_opt FunctionBody // delegate Type_opt ParameterAttributes_opt FunctionBody // ParameterAttributes FunctionBody // FunctionBody // //ParameterAttributes: // Parameters // Parameters FunctionAttributes class FunctionLiteral(bool allowLambda) : Expression { static Action enter(Parser p) { auto lit = new ast.FunctionLiteral(0, p.tok.span); p.pushNode(lit); switch(p.tok.id) { case TOK_function: case TOK_delegate: lit.id = p.tok.id; p.pushState(&shiftFunctionDelegate); return Accept; case TOK_lcurly: lit.addMember(new ast.ParameterList(p.tok)); p.pushState(&shiftFunctionBody); return FunctionBody.enter(p); case TOK_lparen: p.pushState(&shiftParameters); return Parameters.enter(p); default: return p.parseError("unexpected token for function/delegate literal"); } } static Action shiftFunctionDelegate(Parser p) { switch(p.tok.id) { case TOK_lcurly: auto lit = p.topNode!(ast.FunctionLiteral)(); lit.addMember(new ast.ParameterList(p.tok)); p.pushState(&shiftFunctionBody); return FunctionBody.enter(p); case TOK_lparen: p.pushState(&shiftParameters); return Parameters.enter(p); default: p.pushState(&shiftType); return Type.enter(p); } } static Action shiftType(Parser p) { p.popAppendTopNode!(ast.FunctionLiteral); switch(p.tok.id) { case TOK_lcurly: auto lit = p.topNode!(ast.FunctionLiteral)(); lit.addMember(new ast.ParameterList(p.tok)); p.pushState(&shiftFunctionBody); return FunctionBody.enter(p); case TOK_lparen: p.pushState(&shiftParameters); return Parameters.enter(p); default: return p.parseError("'(' or '{' expected in function literal"); } } static Action shiftParameters(Parser p) { p.popAppendTopNode!(ast.FunctionLiteral)(); return shiftFunctionAttribute(p); } static Action shiftFunctionAttribute(Parser p) { switch(p.tok.id) { case TOK_lcurly: p.pushState(&shiftFunctionBody); return FunctionBody.enter(p); static if(allowLambda) { case TOK_lambda: p.pushState(&shiftLambda); p.pushState(&AssignExpression.enter); return Accept; } mixin(case_TOKs_FunctionAttribute); auto lit = p.topNode!(ast.FunctionLiteral)(); p.combineAttributes(lit.attr, tokenToAttribute(p.tok.id)); p.combineAnnotations(lit.annotation, tokenToAnnotation(p.tok.id)); p.pushState(&shiftFunctionAttribute); return Accept; default: return p.parseError("'{' expected in function literal"); } } static Action shiftFunctionBody(Parser p) { p.popAppendTopNode!(ast.FunctionLiteral); return Forward; } static Action shiftLambda(Parser p) { auto expr = p.popNode!(ast.Expression)(); auto ret = new ast.ReturnStatement; ret.addMember(expr); auto blk = new ast.BlockStatement; blk.addMember(ret); auto bdy = new ast.FunctionBody; bdy.addMember(blk); bdy.bodyStatement = blk; auto lit = p.topNode!(ast.FunctionLiteral)(); lit.addMember(bdy); return Forward; } } //-- GRAMMAR_BEGIN -- //StructLiteral: // { ArrayValueList } class StructLiteral : Expression { mixin SequenceNode!(ast.StructLiteral, TOK_lcurly, ArrayValueList, TOK_rcurly); } //-- GRAMMAR_BEGIN -- //AssertExpression: // assert ( AssignExpression ) // assert ( AssignExpression , AssignExpression ) class AssertExpression : Expression { // assert ( AssignExpression , AssignExpression $ ) mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen; // assert ( AssignExpression , $ AssignExpression ) mixin stateAppendClass!(AssignExpression, stateRparen.shift) stateMessage; // assert ( AssignExpression $ ) // assert ( AssignExpression $ , AssignExpression ) mixin stateShiftToken!(TOK_rparen, Parser.forward, TOK_comma, stateMessage.shift) stateRparenComma; // assert ( $ AssignExpression , AssignExpression ) mixin stateAppendClass!(AssignExpression, stateRparenComma.shift) stateExpression; // assert $ ( AssignExpression , AssignExpression ) mixin stateShiftToken!(TOK_lparen, stateExpression.shift) stateLparen; // $ assert ( AssignExpression , AssignExpression ) mixin stateEnterToken!(TOK_assert, ast.AssertExpression, stateLparen.shift); } //-- GRAMMAR_BEGIN -- //MixinExpression: // mixin ( AssignExpression ) class MixinExpression : Expression { mixin SequenceNode!(ast.MixinExpression, TOK_mixin, TOK_lparen, AssignExpression, TOK_rparen); } //-- GRAMMAR_BEGIN -- //ImportExpression: // import ( AssignExpression ) class ImportExpression : Expression { mixin SequenceNode!(ast.ImportExpression, TOK_import, TOK_lparen, AssignExpression, TOK_rparen); } //-- GRAMMAR_BEGIN -- //TypeidExpression: // typeid ( Type ) // typeid ( Expression ) class TypeIdExpression : Expression { mixin SequenceNode!(ast.TypeIdExpression, TOK_typeid, TOK_lparen, TypeOrExpression!TOK_rparen, TOK_rparen); } class TypeOrExpression(ops...) { static Action enter(Parser p) { p.pushRollback(&rollbackTypeFailure); p.pushState(&shiftType); return Type.enter(p); } static Action shiftType(Parser p) { if(!isInOps!(ops)(p.tok.id)) return p.parseError("not a type!"); p.popRollback(); return Forward; } static Action rollbackTypeFailure(Parser p) { return AssignExpression.enter(p); } } //-- GRAMMAR_BEGIN -- //IsExpression: // is ( Type ) // is ( Type : TypeSpecialization ) // is ( Type == TypeSpecialization ) // is ( Type Identifier ) // is ( Type Identifier : TypeSpecialization ) // is ( Type Identifier == TypeSpecialization ) // is ( Type Identifier : TypeSpecialization , TemplateParameterList ) // is ( Type Identifier == TypeSpecialization , TemplateParameterList ) // //TypeSpecialization: // TypeWithModifier // struct // union // class // interface // enum // function // delegate // super // const // immutable // inout // shared // return // __parameters // __argTypes // // !is specially treated, because it's a token to the lexer class IsExpression : Expression { // is ( Type Identifier == TypeSpecialization , TemplateParameterList $ ) mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen; // is ( Type Identifier == TypeSpecialization , $ TemplateParameterList ) mixin stateAppendClass!(TemplateParameterList, stateRparen.shift) stateTemplateParameterList; // is ( Type : TypeSpecialization $ ) // ... // is ( Type Identifier == TypeSpecialization $ , TemplateParameterList ) mixin stateShiftToken!(TOK_rparen, Parser.forward, TOK_comma, stateTemplateParameterList.shift) stateRparenComma; // is ( Type : $ TypeSpecialization ) // is ( Type == $ TypeSpecialization ) mixin stateAppendClass!(TypeSpecialization, stateRparenComma.shift) stateTypeSpecialization; static Action rememberColon(Parser p) { p.topNode!(ast.IsExpression).kind = TOK_colon; return stateTypeSpecialization.shift(p); } static Action rememberAssign(Parser p) { p.topNode!(ast.IsExpression).kind = TOK_equal; return stateTypeSpecialization.shift(p); } mixin stateShiftToken!(TOK_rparen, Parser.forward, TOK_colon, rememberColon, TOK_equal, rememberAssign) stateAfterIdentifier; static Action rememberIdentifier(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.topNode!(ast.IsExpression).ident = p.tok.txt; p.pushState(&stateAfterIdentifier.shift); return Accept; default: return p.parseError("')', ':', '==' or identifier expected"); } } // is ( Type $ ) // is ( Type $ : TypeSpecialization ) // is ( Type $ == TypeSpecialization ) // is ( Type $ Identifier == TypeSpecialization , TemplateParameterList ) mixin stateShiftToken!(TOK_rparen, Parser.forward, TOK_colon, rememberColon, TOK_equal, rememberAssign, -1, rememberIdentifier) stateIdentifier; // is ( $ Type Identifier == TypeSpecialization , TemplateParameterList ) mixin stateAppendClass!(Type, stateIdentifier.shift) stateType; // is $ ( Type Identifier == TypeSpecialization , TemplateParameterList ) mixin stateShiftToken!(TOK_lparen, stateType.shift) stateLparen; // $ is ( Type Identifier == TypeSpecialization , TemplateParameterList ) mixin stateEnterToken!(TOK_is, ast.IsExpression, stateLparen.shift); static Action enterNotIs(Parser p) { p.pushNode(new ast.UnaryExpression(TOK_not, p.tok.span)); p.pushNode(new ast.IsExpression(p.tok)); p.pushState(&shiftNotIsExpression); p.pushState(&stateLparen.shift); return Accept; } static Action shiftNotIsExpression(Parser p) { p.popAppendTopNode!(ast.UnaryExpression)(); return Forward; } } class TypeSpecialization { static Action enter(Parser p) { switch(p.tok.id) { case TOK_struct: case TOK_union: case TOK_class: case TOK_interface: case TOK_enum: case TOK_function: case TOK_delegate: case TOK_super: case TOK_return: case TOK_typedef: case TOK___parameters: case TOK___argTypes: p.pushNode(new ast.TypeSpecialization(p.tok)); return Accept; case TOK_const: case TOK_immutable: case TOK_inout: case TOK_shared: p.pushToken(p.tok); p.pushState(&shiftModifier); return Accept; default: p.pushNode(new ast.TypeSpecialization(0, p.tok.span)); p.pushState(&shiftType); return Type.enter(p); } } static Action shiftModifier(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushNode(new ast.TypeSpecialization(0, p.tok.span)); p.pushState(&shiftType); return Type.enterTypeModifier(p); case TOK_rparen: case TOK_comma: auto tok = p.popToken(); p.pushNode(new ast.TypeSpecialization(tok)); return Forward; default: p.pushNode(new ast.TypeSpecialization(0, p.tok.span)); p.pushState(&shiftType); return TypeWithModifier.shiftModifier(p); } } static Action shiftType(Parser p) { p.popAppendTopNode!(ast.TypeSpecialization)(); return Forward; } } //-- GRAMMAR_BEGIN -- //TraitsExpression: // __traits ( TraitsKeyword , TraitsArguments ) // //TraitsKeyword: // "isAbstractClass" // "isArithmetic" // "isAssociativeArray" // "isFinalClass" // "isFloating" // "isIntegral" // "isScalar" // "isStaticArray" // "isUnsigned" // "isVirtualFunction" // "isAbstractFunction" // "isFinalFunction" // "isStaticFunction" // "isRef" // "isOut" // "isLazy" // "hasMember" // "identifier" // "getMember" // "getOverloads" // "getVirtualFunctions" // "classInstanceSize" // "allMembers" // "derivedMembers" // "isSame" // "compiles" class TraitsExpression : Expression { mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen; mixin stateAppendClass!(TraitsArguments, stateRparen.shift) stateArguments; mixin stateShiftToken!(TOK_comma, stateArguments.shift, TOK_rparen, Parser.forward) stateComma; mixin stateAppendClass!(Identifier, stateComma.shift) stateIdentifier; mixin stateShiftToken!(TOK_lparen, stateIdentifier.shift) stateLparen; mixin stateEnterToken!(TOK___traits, ast.TraitsExpression, stateLparen.shift); } //-- GRAMMAR_BEGIN -- //TraitsArguments: // TraitsArgument // TraitsArgument , TraitsArguments // //TraitsArgument: // AssignExpression // Type class TraitsArguments { mixin ListNode!(ast.TraitsArguments, TypeOrExpression!(TOK_comma, TOK_rparen), TOK_comma, false, false); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/aggr.d0000664000175000017500000003433612776214756027124 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.parser.aggr; import vdc.util; import vdc.lexer; import vdc.parser.engine; import vdc.parser.mod; import vdc.parser.tmpl; import vdc.parser.decl; import vdc.parser.misc; import vdc.parser.stmt; import ast = vdc.ast.all; import stdext.util; //-- GRAMMAR_BEGIN -- //AggregateDeclaration: // struct Identifier StructBody // union Identifier StructBody // struct Identifier ; // union Identifier ; // StructTemplateDeclaration // UnionTemplateDeclaration // ClassDeclaration // InterfaceDeclaration // //StructTemplateDeclaration: // struct Identifier ( TemplateParameterList ) Constraint_opt StructBody // //UnionTemplateDeclaration: // union Identifier ( TemplateParameterList ) Constraint_opt StructBody // //ClassDeclaration: // class Identifier BaseClassList_opt ClassBody // ClassTemplateDeclaration // //BaseClassList: // : SuperClass // : SuperClass , InterfaceClasses // : InterfaceClass // //SuperClass: // GlobalIdentifierList // Protection GlobalIdentifierList // //InterfaceClasses: // InterfaceClass // InterfaceClass , InterfaceClasses // //InterfaceClass: // GlobalIdentifierList // Protection GlobalIdentifierList // //InterfaceDeclaration: // interface Identifier BaseInterfaceList_opt InterfaceBody // InterfaceTemplateDeclaration // //BaseInterfaceList: // : InterfaceClasses // //StructBody: // { DeclDefs_opt } // //ClassBody: // { DeclDefs_opt } // //InterfaceBody: // { DeclDefs_opt } // //Protection: // private // package // public // export class AggregateDeclaration { static Action enter(Parser p) { switch(p.tok.id) { case TOK_union: p.pushState(&shiftUnion); return Accept; case TOK_struct: p.pushState(&shiftStruct); return Accept; case TOK_class: p.pushState(&shiftClass); return Accept; case TOK_interface: p.pushState(&shiftInterface); return Accept; default: return p.parseError("class, struct or union expected"); } } static Action shiftStruct(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.pushNode(new ast.Struct(p.tok)); p.pushState(&shiftIdentifier); return Accept; case TOK_lcurly: case TOK_lparen: p.pushNode(new ast.Struct(p.tok.span)); return shiftIdentifier(p); default: return p.parseError("struct identifier expected"); } } static Action shiftUnion(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.pushNode(new ast.Union(p.tok)); p.pushState(&shiftIdentifier); return Accept; case TOK_lcurly: case TOK_lparen: p.pushNode(new ast.Union(p.tok.span)); return shiftIdentifier(p); default: return p.parseError("union identifier expected"); } } static Action shiftClass(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.pushNode(new ast.Class(p.tok)); p.pushState(&shiftIdentifier); return Accept; default: return p.parseError("class identifier expected"); } } static Action shiftInterface(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.pushNode(new ast.Intrface(p.tok)); p.pushState(&shiftIdentifier); return Accept; default: return p.parseError("interface identifier expected"); } } static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_semicolon: p.topNode!(ast.Aggregate).hasBody = false; return Accept; case TOK_lcurly: return shiftLcurly(p); case TOK_lparen: p.pushState(&shiftLparen); return Accept; case TOK_colon: if(!cast(ast.Class) p.topNode() && !cast(ast.Intrface) p.topNode()) return p.parseError("only classes and interfaces support inheritance"); p.pushState(&shiftColon); return Accept; default: return p.parseError("';', '(' or '{' expected after struct or union identifier"); } } // NewArguments ClassArguments $ BaseClassList_opt ClassBody static Action enterAnonymousClass(Parser p) { p.pushNode(new ast.AnonymousClass(p.tok)); switch(p.tok.id) { case TOK_lparen: p.pushState(&shiftLparen); return Accept; case TOK_lcurly: return shiftLcurly(p); default: return shiftColon(p); } } static Action shiftColon(Parser p) { switch(p.tok.id) { case TOK_dot: case TOK_Identifier: p.pushNode(new ast.BaseClass(TOK_public, p.tok.span)); p.pushState(&shiftBaseClass); return GlobalIdentifierList.enter(p); case TOK_private: case TOK_package: case TOK_public: case TOK_export: p.pushToken(p.tok); p.pushState(&shiftProtection); return Accept; default: return p.parseError("identifier or protection attribute expected"); } } static Action shiftProtection(Parser p) { Token tok = p.popToken(); switch(p.tok.id) { case TOK_dot: case TOK_Identifier: p.pushNode(new ast.BaseClass(tok.id, tok.span)); p.pushState(&shiftBaseClass); return GlobalIdentifierList.enter(p); default: return p.parseError("identifier expected after protection attribute"); } } static Action shiftBaseClass(Parser p) { p.popAppendTopNode(); auto bc = p.popNode!(ast.BaseClass)(); p.topNode!(ast.InheritingAggregate).addBaseClass(bc); switch(p.tok.id) { case TOK_comma: p.pushState(&shiftColon); return Accept; case TOK_lcurly: return shiftLcurly(p); default: return p.parseError("'{' expected after base class list"); } } static Action shiftLparen(Parser p) { p.pushState(&shiftTemplateParameterList); return TemplateParameterList.enter(p); } static Action shiftTemplateParameterList(Parser p) { switch(p.tok.id) { case TOK_rparen: p.popAppendTopNode!(ast.Aggregate)(); p.topNode!(ast.Aggregate).hasTemplArgs = true; p.pushState(&shiftRparen); return Accept; default: return p.parseError("')' expected after template parameter list"); } } static Action shiftRparen(Parser p) { switch(p.tok.id) { case TOK_semicolon: p.topNode!(ast.Aggregate).hasBody = false; return Accept; case TOK_colon: if(!cast(ast.Class) p.topNode() && !cast(ast.Intrface) p.topNode()) return p.parseError("only classes and interfaces support inheritance"); p.pushState(&shiftColon); return Accept; case TOK_if: p.pushState(&shiftConstraint); return Constraint.enter(p); case TOK_lcurly: return shiftLcurly(p); default: return p.parseError("'{' expected after template parameter list"); } } static Action shiftConstraint(Parser p) { p.popAppendTopNode!(ast.Aggregate)(); p.topNode!(ast.Aggregate).hasConstraint = true; switch(p.tok.id) { case TOK_semicolon: p.topNode!(ast.Aggregate).hasBody = false; return Accept; case TOK_lcurly: return shiftLcurly(p); case TOK_colon: if(!cast(ast.Class) p.topNode() && !cast(ast.Intrface) p.topNode()) return p.parseError("only classes and interfaces support inheritance"); p.pushState(&shiftColon); return Accept; default: return p.parseError("'{' expected after constraint"); } } static Action shiftLcurly(Parser p) { assert(p.tok.id == TOK_lcurly); p.pushNode(new ast.StructBody(p.tok)); p.pushState(&shiftDeclDefs); p.pushState(&DeclDefs.enter); return Accept; } static Action shiftDeclDefs(Parser p) { switch(p.tok.id) { case TOK_rcurly: p.popAppendTopNode!(ast.Aggregate)(); return Accept; default: return p.parseError("closing curly brace expected to terminate aggregate body"); } } } //-- GRAMMAR_BEGIN -- //Constructor: // this TemplateParameters_opt Parameters MemberFunctionAttributes_opt Constraint_opt FunctionBody // this ( this ) Constraint_opt FunctionBody class Constructor { mixin stateAppendClass!(FunctionBody, Parser.forward) stateFunctionBody; ////////////////////////////////////////////////////////////// mixin stateAppendClass!(Constraint, stateFunctionBody.shift) stateConstraint; static Action stateMemberFunctionAttributes(Parser p) { switch(p.tok.id) { mixin(case_TOKs_MemberFunctionAttribute); auto ctor = p.topNode!(ast.Constructor); auto list = static_cast!(ast.ParameterList)(ctor.members[$-1]); if(auto attr = tokenToAttribute(p.tok.id)) p.combineAttributes(list.attr, attr); if(auto annot = tokenToAnnotation(p.tok.id)) p.combineAnnotations(list.annotation, annot); p.pushState(&stateMemberFunctionAttributes); return Accept; case TOK_if: return stateConstraint.shift(p); default: return stateFunctionBody.shift(p); } } mixin stateAppendClass!(Parameters, stateMemberFunctionAttributes) stateParametersTemplate; mixin stateAppendClass!(TemplateParameters, stateParametersTemplate.shift) stateTemplateParameterList; ////////////////////////////////////////////////////////////// static Action shiftRparen(Parser p) { switch(p.tok.id) { case TOK_lparen: return Reject; // retry with template arguments default: p.popRollback(); return stateMemberFunctionAttributes(p); } } static Action shiftParameters(Parser p) { p.popAppendTopNode!(ast.Constructor)(); switch(p.tok.id) { case TOK_rparen: p.pushState(&shiftRparen); return Accept; default: return p.parseError("')' expected"); } } static Action gotoParameters(Parser p) { switch(p.tok.id) { case TOK_rparen: p.topNode!(ast.Constructor)().addMember(new ast.ParameterList(p.tok)); p.pushState(&shiftRparen); return Accept; default: p.pushState(&shiftParameters); return ParameterList.enter(p); } } mixin stateShiftToken!(TOK_rparen, stateFunctionBody.shift) stateThis; static Action gotoThis(Parser p) { p.popRollback(); return stateThis.shift(p); } mixin stateShiftToken!(TOK_this, gotoThis, -1, gotoParameters) stateParameters; static Action rollbackParameters(Parser p) { p.topNode!(ast.Constructor)().reinit(); assert(p.tok.id == TOK_lparen); return stateTemplateParameterList.shift(p); } static Action stateLparen(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushRollback(&rollbackParameters); p.pushState(&stateParameters.shift); return Accept; default: return p.parseError("'(' expected in constructor"); } } mixin stateEnterToken!(TOK_this, ast.Constructor, stateLparen); } //-- GRAMMAR_BEGIN -- //Destructor: // ~ this ( ) FunctionBody class Destructor { mixin SequenceNode!(ast.Destructor, TOK_tilde, TOK_this, TOK_lparen, TOK_rparen, FunctionBody); } //-- GRAMMAR_BEGIN -- //StaticConstructor: // static this ( ) FunctionBody // //StaticDestructor: // static ~ this ( ) FunctionBody // //SharedStaticConstructor: // shared static this ( ) FunctionBody // //SharedStaticDestructor: // shared static ~ this ( ) FunctionBody // // //StructAllocator: // ClassAllocator // //StructDeallocator: // ClassDeallocator // //StructConstructor: // this ( ParameterList ) FunctionBody // //StructPostblit: // this ( this ) FunctionBody // //StructDestructor: // ~ this ( ) FunctionBody // // //Invariant: // invariant ( ) BlockStatement class Invariant { mixin SequenceNode!(ast.Unittest, TOK_invariant, TOK_lparen, TOK_rparen, BlockStatement); } //-- GRAMMAR_BEGIN -- //ClassAllocator: // new Parameters FunctionBody class ClassAllocator { mixin SequenceNode!(ast.ClassAllocator, TOK_new, Parameters, FunctionBody); } //-- GRAMMAR_BEGIN -- //ClassDeallocator: // delete Parameters FunctionBody class ClassDeallocator { mixin SequenceNode!(ast.ClassDeallocator, TOK_delete, Parameters, FunctionBody); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/tmpl.d0000664000175000017500000003331312776214756027152 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.parser.tmpl; import vdc.util; import vdc.lexer; import vdc.parser.engine; import vdc.parser.decl; import vdc.parser.expr; import vdc.parser.mod; import ast = vdc.ast.all; //-- GRAMMAR_BEGIN -- //TemplateDeclaration: // template TemplateIdentifier ( TemplateParameterList ) Constraint_opt { DeclDefs } class TemplateDeclaration { mixin SequenceNode!(ast.TemplateDeclaration, TOK_template, Identifier, TOK_lparen, TemplateParameterList, TOK_rparen, Opt!(Constraint, TOK_if), DeclDefsBlock); } class DeclDefsBlock { mixin SequenceNode!(ast.DeclarationBlock, TOK_lcurly, DeclDefs, TOK_rcurly); } //-- GRAMMAR_BEGIN -- //TemplateIdentifier: // Identifier // //TemplateParameters: // ( TemplateParameterList ) class TemplateParameters { mixin SequenceNode!(NoASTNode, TOK_lparen, TemplateParameterList, TOK_rparen); } //-- GRAMMAR_BEGIN -- //TemplateParameterList: // TemplateParameter // TemplateParameter , // TemplateParameter , TemplateParameterList class TemplateParameterList { mixin ListNode!(ast.TemplateParameterList, TemplateParameter, TOK_comma, true, true); } //-- GRAMMAR_BEGIN -- //TemplateParameter: // TemplateTypeParameter // TemplateValueParameter // TemplateAliasParameter // TemplateTupleParameter // TemplateThisParameter // //TemplateTupleParameter: // Identifier ... class TemplateParameter { static Action enter(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.pushToken(p.tok); p.pushState(&shiftIdentifier); return Accept; case TOK_this: return TemplateThisParameter.enter(p); case TOK_alias: return TemplateAliasParameter.enter(p); default: return TemplateValueParameter.enter(p); } } static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_comma: case TOK_rparen: Token tok = p.popToken(); p.pushNode(new ast.TemplateTypeParameter(tok)); return Forward; case TOK_colon: case TOK_assign: return TemplateTypeParameter!false.enterIdentifier(p); case TOK_dotdotdot: Token tok = p.popToken(); p.pushNode(new ast.TemplateTupleParameter(tok)); return Accept; default: return TemplateValueParameter.enterIdentifier(p); } } } //-- GRAMMAR_BEGIN -- //IdentifierOrTemplateInstance: // Identifier // TemplateInstance // //TemplateInstance: // TemplateIdentifier ! ( TemplateArgumentList ) // TemplateIdentifier ! TemplateSingleArgument class IdentifierOrTemplateInstance { static Action enter(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.pushToken(p.tok); p.pushState(&shiftIdentifier); return Accept; default: return p.parseError("identifier expected"); } } // assumes identifier token on the info stack static Action enterIdentifier(Parser p) { return shiftIdentifier(p); } static Action shiftIdentifier(Parser p) { auto tok = p.popToken(); switch(p.tok.id) { case TOK_not: p.pushNode(new ast.TemplateInstance(tok)); p.pushState(&shiftNot); return Accept; default: p.pushNode(new ast.Identifier(tok)); return Forward; } } static Action shiftNot(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushState(&shiftArgumentList); p.pushState(&TemplateArgumentList.enter); return Accept; mixin(case_TOKs_TemplateSingleArgument); p.pushNode(new ast.TemplateArgumentList(p.tok)); p.pushState(&shiftSingleArgument); return PrimaryExpression.enter(p); case TOK___vector: mixin(case_TOKs_BasicTypeX); auto n = new ast.TemplateArgumentList(p.tok); n.addMember(new ast.BasicType(p.tok)); p.topNode!(ast.TemplateInstance).addMember(n); return Accept; default: return p.parseError("'(' or single argument template expected after '!'"); } } static Action shiftArgumentList(Parser p) { p.popAppendTopNode!(ast.TemplateInstance); switch(p.tok.id) { case TOK_rparen: return Accept; default: return p.parseError("closing parenthesis expected"); } } static Action shiftSingleArgument(Parser p) { p.popAppendTopNode!(ast.TemplateArgumentList); p.popAppendTopNode!(ast.TemplateInstance); return Forward; } } //-- GRAMMAR_BEGIN -- //TemplateArgumentList: // TemplateArgument // TemplateArgument , // TemplateArgument , TemplateArgumentList // //TemplateArgument: // Type // AssignExpression // Symbol /* same as IdentifierList, so already in Type and AssignExpression */ //Symbol: // SymbolTail // . SymbolTail // //// identical to IdentifierList //SymbolTail: // Identifier // Identifier . SymbolTail // TemplateInstance // TemplateInstance . SymbolTail class TemplateArgumentList { mixin ListNode!(ast.TemplateArgumentList, TypeOrExpression!(TOK_comma, TOK_rparen), TOK_comma, true, true); } //-- GRAMMAR_BEGIN -- //TemplateSingleArgument: // Identifier // BasicTypeX // CharacterLiteral // StringLiteral // IntegerLiteral // FloatLiteral // true // false // null // __FILE__ // __LINE__ //-- GRAMMAR_BEGIN -- //TemplateTypeParameter: // Identifier // Identifier TemplateTypeParameterSpecialization // Identifier TemplateTypeParameterDefault // Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault // //TemplateTypeParameterSpecialization: // : Type // //TemplateTypeParameterDefault: // = Type class TemplateTypeParameter(bool exprDefault = false) { static Action enter(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.pushNode(new ast.TemplateTypeParameter(p.tok)); p.pushState(&shiftIdentifier); return Accept; default: return p.parseError("identifier expected"); } } static Action enterIdentifier(Parser p) { Token tok = p.popToken(); p.pushNode(new ast.TemplateTypeParameter(tok)); return shiftIdentifier(p); } static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_colon: p.pushState(&shiftSpecialization); p.pushState(&Type.enter); return Accept; case TOK_assign: p.pushState(&shiftDefault); static if(exprDefault) p.pushState(&TypeOrExpression!(TOK_rparen, TOK_comma).enter); else p.pushState(&Type.enter); return Accept; default: return Forward; } } static Action shiftSpecialization(Parser p) { auto special = p.popNode!(ast.Type)(); auto param = p.topNode!(ast.TemplateTypeParameter); param.specialization = special; param.addMember(special); switch(p.tok.id) { case TOK_assign: p.pushState(&shiftDefault); static if(exprDefault) p.pushState(&TypeOrExpression!(TOK_rparen, TOK_comma).enter); else p.pushState(&Type.enter); return Accept; default: return Forward; } } static Action shiftDefault(Parser p) { auto def = p.popNode(); auto param = p.topNode!(ast.TemplateTypeParameter); param.def = def; param.addMember(def); return Forward; } } //TemplateThisParameter: // this TemplateTypeParameter class TemplateThisParameter { mixin SequenceNode!(ast.TemplateThisParameter, TOK_this, TemplateTypeParameter!false); } //-- GRAMMAR_BEGIN -- //TemplateValueParameter: // TemplateValueDeclaration // TemplateValueDeclaration TemplateValueParameterSpecialization // TemplateValueDeclaration TemplateValueParameterDefault // TemplateValueDeclaration TemplateValueParameterSpecialization TemplateValueParameterDefault // //TemplateValueDeclaration: // ParameterDeclarator /* without storage classes */ // //TemplateValueParameterSpecialization: // : ConditionalExpression // //TemplateValueParameterDefault: // = __FILE__ /* already part of ConditionalExpression */ // = __LINE__ /* already part of ConditionalExpression */ // = ConditionalExpression class TemplateValueParameter { static Action enter(Parser p) { p.pushNode(new ast.TemplateValueParameter(p.tok)); p.pushState(&shiftDecl); return ParameterDeclarator.enter(p); } static Action enterIdentifier(Parser p) { p.pushNode(new ast.TemplateValueParameter(p.tok)); p.pushState(&shiftDecl); return ParameterDeclarator.enterTypeIdentifier(p); } static Action shiftDecl(Parser p) { p.popAppendTopNode!(ast.TemplateValueParameter)(); switch(p.tok.id) { case TOK_colon: p.pushState(&shiftSpecialization); p.pushState(&ConditionalExpression.enter); return Accept; case TOK_assign: p.pushState(&shiftDefault); p.pushState(&ConditionalExpression.enter); return Accept; default: return Forward; } } static Action shiftSpecialization(Parser p) { auto special = p.popNode!(ast.Expression)(); auto param = p.topNode!(ast.TemplateValueParameter); param.specialization = special; param.addMember(special); switch(p.tok.id) { case TOK_assign: p.pushState(&shiftDefault); p.pushState(&ConditionalExpression.enter); return Accept; default: return Forward; } } static Action shiftDefault(Parser p) { auto def = p.popNode!(ast.Expression)(); auto param = p.topNode!(ast.TemplateValueParameter); param.def = def; param.addMember(def); return Forward; } } //-- GRAMMAR_BEGIN -- //TemplateAliasParameter: // alias Type_opt Identifier TemplateAliasParameterSpecialization_opt TemplateAliasParameterDefault_opt // //TemplateAliasParameterSpecialization: // : Type // //TemplateAliasParameterDefault: // = TypeOrExpression class TemplateAliasParameter { mixin SequenceNode!(ast.TemplateAliasParameter, TOK_alias, TemplateTypeParameter!true); } //-- GRAMMAR_BEGIN -- //ClassTemplateDeclaration: // class Identifier ( TemplateParameterList ) Constraint_opt BaseClassList_opt ClassBody // //InterfaceTemplateDeclaration: // interface Identifier ( TemplateParameterList ) Constraint_opt BaseInterfaceList_opt InterfaceBody // //TemplateMixinDeclaration: // mixin template TemplateIdentifier ( TemplateParameterList ) Constraint_opt { DeclDefs } class TemplateMixinDeclaration { static Action enter(Parser p) { switch(p.tok.id) { case TOK_mixin: p.pushState(&shiftTemplateDeclaration); p.pushState(&TemplateDeclaration.enter); return Accept; default: return p.parseError("mixin expected in mixin template declaration"); } } static Action enterAfterMixin(Parser p) { p.pushState(&shiftTemplateDeclaration); return TemplateDeclaration.enter(p); } static Action shiftTemplateDeclaration(Parser p) { p.topNode!(ast.TemplateDeclaration).id = TOK_mixin; return Forward; } } //TemplateMixin: // mixin TemplateIdentifier ; // mixin TemplateIdentifier MixinIdentifier ; // mixin TemplateIdentifier ! ( TemplateArgumentList ) ; // mixin TemplateIdentifier ! ( TemplateArgumentList ) MixinIdentifier ; // //MixinIdentifier: // Identifier // // translated to //-- GRAMMAR_BEGIN -- //TemplateMixin: // mixin GlobalIdentifierList MixinIdentifier_opt ; // mixin Typeof . IdentifierList MixinIdentifier_opt ; class TemplateMixin { mixin SequenceNode!(ast.TemplateMixin, TOK_mixin, GlobalIdentifierList, Opt!(Identifier, TOK_Identifier), TOK_semicolon); static Action enterAfterMixin(Parser p) { p.pushNode(new ast.TemplateMixin(p.tok)); switch(p.tok.id) { case TOK_typeof: p.pushState(&shiftTypeof); return PostfixExpression.enter(p); default: return shift1.shift(p); } } static Action shiftTypeof(Parser p) { // already in shift2.shift(): p.popAppendTopNode!(ast.TemplateMixin)(); return shift2.shift(p); } } //-- GRAMMAR_BEGIN -- //Constraint: // if ( ConstraintExpression ) // //ConstraintExpression: // Expression class Constraint { mixin SequenceNode!(ast.Constraint, TOK_if, TOK_lparen, Expression, TOK_rparen); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/decl.d0000664000175000017500000012174212776214756027111 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.parser.decl; import vdc.util; import vdc.lexer; import vdc.parser.engine; import vdc.parser.expr; import vdc.parser.misc; import vdc.parser.tmpl; import vdc.parser.mod; import ast = vdc.ast.all; import stdext.util; //-- GRAMMAR_BEGIN -- //Declaration: // alias LinkageAttribute_opt Decl // typedef Decl /* for legacy code */ // Decl // alias Identifier this // alias this = Identifier class Declaration { static Action enter(Parser p) { switch(p.tok.id) { case TOK_alias: p.pushState(&shiftAlias); return Accept; case TOK_typedef: p.pushState(&shiftTypedef); p.pushState(&Decl!true.enter); return Accept; default: return Decl!true.enter(p); } } static Action shiftAlias(Parser p) { switch(p.tok.id) { case TOK_extern: p.pushState(&shiftAliasLinkage); p.pushState(&Decl!true.enter); return LinkageAttribute.enter(p); case TOK_Identifier: p.pushToken(p.tok); p.pushState(&shiftAliasIdentifier); return Accept; case TOK_this: p.pushState(&shiftThis); return Accept; default: p.pushState(&shiftTypedef); return Decl!true.enter(p); } } static Action shiftAliasLinkage(Parser p) { auto decl = p.popNode!(ast.Decl)(); auto link = p.popNode!(ast.AttributeSpecifier)(); p.combineAttributes(decl.attr, link.attr); p.pushNode(decl); return Forward; } // assumes identifier token on the info stack static Action shiftAliasIdentifier(Parser p) { switch(p.tok.id) { case TOK_this: auto tok = p.popToken(); p.pushNode(new ast.AliasThis(tok)); p.pushState(&shiftAliasThis); return Accept; case TOK_assign: p.pushState(&shiftAliasAssign); p.pushState(&Type.enter); return Accept; default: p.pushState(&shiftTypedef); return Decl!true.enterTypeIdentifier(p); } } static Action shiftThis(Parser p) { switch(p.tok.id) { case TOK_assign: p.pushState(&shiftThisAssign); return Accept; default: return p.parseError("'=' expected after alias this"); } } static Action shiftThisAssign(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.pushNode(new ast.AliasThis(p.tok)); p.pushState(&shiftAliasThis); return Accept; default: return p.parseError("identifier expected after alias this ="); } } static Action shiftAliasThis(Parser p) { switch(p.tok.id) { case TOK_semicolon: return Accept; default: return p.parseError("semicolon expected after alias this;"); } } // assumes identifier token on the info stack static Action shiftAliasAssign(Parser p) { auto type = static_cast!(ast.Type)(p.popNode()); auto tok = p.popToken(); auto decl = new ast.Decl(type.id, type.span); auto decls = new ast.Declarators(tok); decls.addMember(new ast.Declarator(tok)); // insert type before declarator identifier decl.addMember(type); decl.addMember(decls); decl.isAlias = true; decl.hasSemi = true; p.pushNode(decl); switch(p.tok.id) { case TOK_semicolon: return Accept; case TOK_comma: default: return p.parseError("semicolon expected after alias identifier = type"); } } static Action shiftTypedef(Parser p) { //p.appendReplaceTopNode(new ast.AliasDeclaration(p.tok)); p.topNode!(ast.Decl)().isAlias = true; return Forward; } } //-- GRAMMAR_BEGIN -- //Decl: // StorageClasses Decl // BasicType BasicTypes2_opt Declarators ; // BasicType BasicTypes2_opt Declarator FunctionBody // AutoDeclaration // //AutoDeclaration: // StorageClasses Identifier = AssignExpression ; class Decl(bool checkSemi = true) { // storage class stored in Decl.attr, first child is Type (TOK_auto if not present) static Action enter(Parser p) { auto decl = new ast.Decl(p.tok); decl.hasSemi = checkSemi; p.pushNode(decl); if(isTypeModifier(p.tok.id)) { // could be storage class or BasicType p.pushToken(p.tok); p.pushState(&shiftTypeModifier); return Accept; } if(isStorageClass(p.tok.id)) { p.combineAttributes(decl.attr, tokenToAttribute(p.tok.id)); p.combineAnnotations(decl.annotation, tokenToAnnotation(p.tok.id)); p.pushState(&shiftStorageClass); return Accept; } p.pushState(&shiftBasicType); return BasicType.enter(p); } // switch here from AttributeSpecifier when detecting a '(' after const,etc // assumes modifier token on the info stack static Action enterAttributeSpecifier(Parser p) { assert(p.tok.id == TOK_lparen); auto decl = new ast.Decl(p.tok); decl.hasSemi = checkSemi; p.pushNode(decl); p.pushState(&shiftBasicType); return BasicType.shiftTypeModifier(p); } // disambiguate "const x" and "const(int) x" // assumes modifier token on the info stack static Action shiftTypeModifier(Parser p) { if(p.tok.id == TOK_lparen) { p.pushState(&shiftBasicType); return BasicType.shiftTypeModifier(p); } auto decl = p.topNode!(ast.Decl)(); Token tok = p.popToken(); p.combineAttributes(decl.attr, tokenToAttribute(tok.id)); return shiftStorageClass(p); } static Action enterAfterStorageClass(Parser p, TokenId storage) { auto decl = new ast.Decl(p.tok); decl.hasSemi = checkSemi; p.pushNode(decl); decl.attr = tokenToAttribute(storage); return shiftStorageClass(p); } static Action shiftStorageClass(Parser p) { if(p.tok.id == TOK_Identifier) { p.pushToken(p.tok); p.pushState(&shiftIdentifier); return Accept; } if(isTypeModifier(p.tok.id)) { // could be storage class or BasicType p.pushToken(p.tok); p.pushState(&shiftTypeModifier); return Accept; } if(isStorageClass(p.tok.id)) { auto decl = p.topNode!(ast.Decl)(); p.combineAttributes(decl.attr, tokenToAttribute(p.tok.id)); p.combineAnnotations(decl.annotation, tokenToAnnotation(p.tok.id)); p.pushState(&shiftStorageClass); return Accept; } p.pushState(&shiftBasicType); return BasicType.enter(p); } // switch here from Statement when detecting a declaration after an identifier // assumes identifier token on the info stack static Action enterTypeIdentifier(Parser p) { auto decl = new ast.Decl(p.tok); decl.hasSemi = checkSemi; p.pushNode(decl); p.pushState(&shiftBasicType); return BasicType.enterIdentifier(p); } // assumes identifier token on the info stack static Action enterIdentifier(Parser p) { auto decl = new ast.Decl(p.tok); decl.hasSemi = checkSemi; p.pushNode(decl); return shiftIdentifier(p); } // assumes identifier token on the info stack static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_assign: auto bt = new ast.AutoType(TOK_auto, p.topToken().span); p.topNode!(ast.Decl)().addMember(bt); p.pushState(&shiftDeclarators); return Declarators.enterAfterIdentifier(p); case TOK_lparen: // storageclass identifier(... must be function with auto return auto bt = new ast.AutoType(TOK_auto, p.topToken().span); p.topNode!(ast.Decl).addMember(bt); p.pushState(&shiftDeclarators); return Declarators.enterAfterIdentifier(p); default: p.pushState(&shiftBasicType); return BasicType.enterIdentifier(p); } } // assumes identifier token on the info stack static Action enterAutoReturn(Parser p) { assert(p.tok.id == TOK_lparen); auto decl = new ast.Decl(p.topToken()); decl.hasSemi = checkSemi; p.pushNode(decl); auto bt = new ast.AutoType(TOK_auto, p.topToken().span); decl.addMember(bt); p.pushState(&shiftDeclarators); return Declarators.enterAfterIdentifier(p); } static Action shiftBasicType(Parser p) { switch(p.tok.id) { mixin(BasicType2.case_TOKs); p.pushState(&shiftBasicTypes2); return BasicTypes2.enter(p); default: return shiftBasicTypes2(p); } } static Action shiftBasicTypes2(Parser p) { p.popAppendTopNode!(ast.Decl, ast.Type)(); p.pushState(&shiftDeclarators); return Declarators.enter(p); } static Action shiftDeclarators(Parser p) { p.popAppendTopNode!(ast.Decl)(); static if(checkSemi) { if(p.tok.id == TOK_RECOVER) return Forward; auto decl = p.topNode!(ast.Decl)(); if(decl.members.length == 2 && // BasicType and Declarators decl.members[1].members.length == 1 && // only one declarator FunctionBody.isInitTerminal(p.tok)) { decl.hasSemi = false; p.pushState(&shiftFunctionBody); return FunctionBody.enter(p); } if(p.tok.id != TOK_semicolon) return p.parseError("semicolon expected after declaration"); return Accept; } else { return Forward; } } static Action shiftFunctionBody(Parser p) { p.popAppendTopNode!(ast.Decl)(); return Forward; } } //-- GRAMMAR_BEGIN -- //Declarators: // DeclaratorInitializer // DeclaratorInitializer , DeclaratorIdentifierList class Declarators { mixin ListNode!(ast.Declarators, DeclaratorInitializer, TOK_comma); // assumes identifier token on the info stack static Action enterAfterIdentifier(Parser p) { p.pushNode(new ast.Declarators(p.tok)); p.pushState(&shift); return DeclaratorInitializer.enterAfterIdentifier(p); } } //-- GRAMMAR_BEGIN -- //DeclaratorInitializer: // Declarator // Declarator = Initializer class DeclaratorInitializer { mixin OptionalNode!(ast.DeclaratorInitializer, Declarator, TOK_assign, Initializer); // assumes identifier token on the info stack static Action enterAfterIdentifier(Parser p) { switch(p.tok.id) { case TOK_assign: auto tok = p.popToken(); p.pushNode(new ast.Declarator(tok)); return shiftSubType1(p); default: p.pushState(&shiftSubType1); return Declarator.enterAfterIdentifier(p); } } } //-- GRAMMAR_BEGIN -- //DeclaratorIdentifierList: // DeclaratorIdentifier // DeclaratorIdentifier , DeclaratorIdentifierList class DeclaratorIdentifierList { mixin ListNode!(ast.DeclaratorIdentifierList, DeclaratorIdentifier, TOK_comma); } //-- GRAMMAR_BEGIN -- //DeclaratorIdentifier: // Identifier // Identifier = Initializer class DeclaratorIdentifier { mixin OptionalNode!(ast.DeclaratorIdentifier, Identifier, TOK_assign, Initializer); } //-- GRAMMAR_BEGIN -- //Initializer: // VoidInitializer // NonVoidInitializer // //NonVoidInitializer: // AssignExpression // ArrayInitializer /* same as ArrayLiteral? */ // StructInitializer class Initializer { static Action enter(Parser p) { if(p.tok.id == TOK_void) { p.pushRollback(&rollbackVoid); p.pushState(&shiftVoid); return Accept; } // StructInitializer not implemented return AssignExpression.enter(p); } static Action shiftVoid(Parser p) { switch(p.tok.id) { case TOK_dot: return p.parseError("unexpected '.' in void initializer"); default: p.popRollback(); p.pushNode(new ast.VoidInitializer(p.tok)); return Forward; } } static Action rollbackVoid(Parser p) { return AssignExpression.enter(p); } } //-- GRAMMAR_BEGIN -- //BasicType: // BasicTypeX // . IdentifierList // IdentifierList // Typeof // Typeof . IdentifierList // ModifiedType // VectorType // //ModifiedType: // const ( Type ) // immutable ( Type ) // shared ( Type ) // inout ( Type ) class BasicType { static Action enter(Parser p) { switch(p.tok.id) { case TOK_dot: case TOK_Identifier: p.pushNode(new ast.IdentifierType(p.tok)); p.pushState(&shiftIdentifierList); return GlobalIdentifierList.enter(p); case TOK_typeof: p.pushState(&shiftTypeof); return Typeof.enter(p); mixin(case_TOKs_BasicTypeX); p.pushNode(new ast.BasicType(p.tok)); return Accept; mixin(case_TOKs_TypeModifier); p.pushToken(p.tok); p.pushState(&shiftTypeModifier); return Accept; case TOK___vector: return VectorType.enter(p); default: return p.parseError("unexpected token in BasicType"); } } // assumes modifier token on the info stack static Action shiftTypeModifier(Parser p) { Token tok = p.popToken(); p.pushNode(new ast.ModifiedType(tok)); switch(p.tok.id) { case TOK_lparen: p.pushState(&shiftParenType); p.pushState(&Type.enter); return Accept; default: p.pushState(&shiftType); return Type.enter(p); } } static Action shiftParenType(Parser p) { if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected"); p.popAppendTopNode(); return Accept; } static Action shiftType(Parser p) { p.popAppendTopNode(); return Forward; } // entry point on token after identifier // assumes identifier token on the info stack static Action enterIdentifier(Parser p) { p.pushNode(new ast.IdentifierType(p.topToken())); p.pushState(&shiftIdentifierList); return IdentifierList.enterAfterIdentifier(p); } static Action shiftIdentifierList(Parser p) { p.popAppendTopNode!(ast.IdentifierType)(); return Forward; } static Action shiftTypeof(Parser p) { if(p.tok.id != TOK_dot) return Forward; p.pushState(&shiftTypeofIdentifierList); p.pushState(&IdentifierList.enter); return Accept; } static Action shiftTypeofIdentifierList(Parser p) { p.popAppendTopNode!(ast.Typeof, ast.IdentifierList)(); return Forward; } } enum case_TOKs_TypeModifier = q{ case TOK_const: case TOK_shared: case TOK_immutable: case TOK_inout: }; bool isTypeModifier(TokenId tok) { switch(tok) { mixin(case_TOKs_TypeModifier); return true; default: return false; } } //-- GRAMMAR_BEGIN -- //BasicTypeX: // bool // byte // ubyte // short // ushort // int // uint // long // ulong // char // wchar // dchar // float // double // real // ifloat // idouble // ireal // cfloat // cdouble // creal // void bool isBasicTypeX(TokenId tok) { switch(tok) { mixin(case_TOKs_BasicTypeX); return true; default: return false; } } //-- GRAMMAR_BEGIN -- //VectorType: // __vector ( Type ) class VectorType { mixin SequenceNode!(ast.VectorType, TOK___vector, TOK_lparen, Type, TOK_rparen); } //-- GRAMMAR_BEGIN -- //Typeof: // typeof ( Expression ) // typeof ( return ) class Typeof { static Action enter(Parser p) { if(p.tok.id != TOK_typeof) return p.parseError("typeof expected"); p.pushNode(new ast.Typeof(p.tok)); p.pushState(&shiftLparen); return Accept; } static Action shiftLparen(Parser p) { if(p.tok.id != TOK_lparen) return p.parseError("opening parenthesis expected"); p.pushState(&shiftArgument); return Accept; } static Action shiftArgument(Parser p) { if(p.tok.id == TOK_return) { p.topNode!(ast.Typeof).id = TOK_return; p.pushState(&shiftRparen); return Accept; } p.pushState(&shiftExpression); return Expression.enter(p); } static Action shiftExpression(Parser p) { if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected"); p.popAppendTopNode!(ast.Typeof)(); return Accept; } static Action shiftRparen(Parser p) { if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected"); return Accept; } } //-- GRAMMAR_BEGIN -- //Declarator: // Identifier DeclaratorSuffixes_opt class Declarator { static Action enter(Parser p) { switch(p.tok.id) { case TOK_Identifier: p.pushNode(new ast.Declarator(p.tok)); p.pushState(&shiftIdentifier); return Accept; default: return p.parseError("unexpected token in Declarator"); } } static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_lparen: case TOK_lbracket: return DeclaratorSuffixes.enter(p); // appends to Declarator default: return Forward; } } // assumes identifier token on the info stack static Action enterAfterIdentifier(Parser p) { auto tok = p.popToken(); p.pushNode(new ast.Declarator(tok)); return shiftIdentifier(p); } } //-- GRAMMAR_BEGIN -- // always optional //BasicType2: // * // [ ] // [ AssignExpression ] // [ AssignExpression .. AssignExpression ] // [ Type ] // delegate Parameters FunctionAttributes_opt // function Parameters FunctionAttributes_opt class BasicType2 { enum case_TOKs = q{ case TOK_mul: case TOK_lbracket: case TOK_delegate: case TOK_function: }; static Action enter(Parser p) { assert(p.topNode!(ast.Type)); switch(p.tok.id) { case TOK_mul: p.appendReplaceTopNode(new ast.TypePointer(p.tok)); return Accept; case TOK_lbracket: p.pushState(&shiftLbracket); return Accept; case TOK_delegate: p.appendReplaceTopNode(new ast.TypeDelegate(p.tok)); p.pushState(&shiftParameters); p.pushState(&Parameters.enter); return Accept; case TOK_function: p.appendReplaceTopNode(new ast.TypeFunction(p.tok)); p.pushState(&shiftParameters); p.pushState(&Parameters.enter); return Accept; default: return p.parseError("unexpected token in BasicType2"); } } static Action shiftLbracket(Parser p) { switch(p.tok.id) { case TOK_rbracket: p.appendReplaceTopNode(new ast.TypeDynamicArray(p.tok)); return Accept; default: p.pushState(&shiftTypeOrExpression); return TypeOrExpression!TOK_rbracket.enter(p); } } static Action shiftTypeOrExpression(Parser p) { if(cast(ast.Type) p.topNode()) { auto keyType = p.popNode!(ast.Type); p.appendReplaceTopNode(new ast.TypeAssocArray(p.tok)); p.topNode().addMember(keyType); if(p.tok.id != TOK_rbracket) return p.parseError("']' expected"); return Accept; } switch(p.tok.id) { case TOK_rbracket: auto dim = p.popNode!(ast.Expression); p.appendReplaceTopNode(new ast.TypeStaticArray(p.tok)); p.topNode().addMember(dim); return Accept; case TOK_slice: auto low = p.popNode!(ast.Expression); p.appendReplaceTopNode(new ast.TypeArraySlice(p.tok)); p.topNode().addMember(low); p.pushState(&shiftSliceUpper); p.pushState(&AssignExpression.enter); return Accept; default: return p.parseError("']' expected"); } } static Action shiftSliceUpper(Parser p) { p.popAppendTopNode!(ast.TypeArraySlice)(); switch(p.tok.id) { case TOK_rbracket: return Accept; default: return p.parseError("']' expected"); } } static Action shiftParameters(Parser p) { p.popAppendTopNode(); return shiftAttributes(p); } static Action shiftAttributes(Parser p) { switch(p.tok.id) { mixin(case_TOKs_MemberFunctionAttribute); // no member attributes? auto type = p.topNode!(ast.Type); p.combineAttributes(type.attr, tokenToAttribute(p.tok.id)); p.pushState(&shiftAttributes); return Accept; default: return Forward; } } } //-- GRAMMAR_BEGIN -- //BasicTypes2: // BasicType2 // BasicType2 BasicTypes2 class BasicTypes2 { static Action enter(Parser p) { assert(p.topNode!(ast.Type)); switch(p.tok.id) { mixin(BasicType2.case_TOKs); p.pushState(&shiftBasicType); return BasicType2.enter(p); default: return p.parseError("unexpected token in BasicType2"); } } static Action shiftBasicType(Parser p) { switch(p.tok.id) { mixin(BasicType2.case_TOKs); p.pushState(&shiftBasicType); return BasicType2.enter(p); default: return Forward; } } } //-- GRAMMAR_BEGIN -- //DeclaratorSuffixes: // DeclaratorSuffix // DeclaratorSuffix DeclaratorSuffixes // // obsolete C-style? //DeclaratorSuffix: // TemplateParameterList_opt Parameters MemberFunctionAttributes_opt Constraint_opt // [ ] // [ AssignExpression ] // [ Type ] class DeclaratorSuffixes { static Action enter(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushRollback(&rollbackParametersFailure); p.pushState(&shiftParameters); return Parameters.enter(p); case TOK_lbracket: p.pushState(&shiftLbracket); return Accept; default: return p.parseError("opening parenthesis or bracket expected"); } } static Action nextSuffix(Parser p) { switch(p.tok.id) { case TOK_lbracket: p.pushState(&shiftLbracket); return Accept; default: return Forward; } } static Action shiftLbracket(Parser p) { switch(p.tok.id) { case TOK_rbracket: p.topNode().addMember(new ast.SuffixDynamicArray(p.tok)); p.pushState(&nextSuffix); return Accept; default: p.pushState(&shiftTypeOrExpression); return TypeOrExpression!(TOK_rbracket).enter(p); } // return p.notImplementedError("C style declarators"); } static Action shiftTypeOrExpression(Parser p) { switch(p.tok.id) { case TOK_rbracket: auto node = p.popNode(); ast.Node n = new ast.SuffixArray(p.tok); n.addMember(node); p.topNode().addMember(n); p.pushState(&nextSuffix); return Accept; default: return p.parseError("']' expected in C style declarator"); } } static Action shiftParameters(Parser p) { switch(p.tok.id) { case TOK_lparen: // somehow made it through the parameters, but another parameters list follow... return Reject; // so rollback to retry with template parameter list mixin(case_TOKs_MemberFunctionAttribute); p.popRollback(); auto param = p.topNode!(ast.ParameterList); p.combineAttributes(param.attr, tokenToAttribute(p.tok.id)); p.pushState(&shiftMemberFunctionAttribute); return Accept; case TOK_if: p.popRollback(); p.popAppendTopNode!(ast.Declarator, ast.ParameterList)(); p.pushState(&shiftConstraint); return Constraint.enter(p); default: p.popRollback(); p.popAppendTopNode!(ast.Declarator, ast.ParameterList)(); return Forward; } } static Action shiftMemberFunctionAttribute(Parser p) { switch(p.tok.id) { mixin(case_TOKs_MemberFunctionAttribute); auto param = p.topNode!(ast.ParameterList); p.combineAttributes(param.attr, tokenToAttribute(p.tok.id)); p.pushState(&shiftMemberFunctionAttribute); return Accept; case TOK_if: p.popAppendTopNode!(ast.Declarator, ast.ParameterList)(); p.pushState(&shiftConstraint); return Constraint.enter(p); default: p.popAppendTopNode!(ast.Declarator, ast.ParameterList)(); return Forward; } } static Action shiftConstraint(Parser p) { p.popAppendTopNode!(ast.Declarator, ast.Constraint)(); return Forward; } static Action rollbackParametersFailure(Parser p) { p.pushState(&shiftTemplateParameterList); return TemplateParameters.enter(p); } static Action shiftTemplateParameterList(Parser p) { p.popAppendTopNode(); // append to declarator switch(p.tok.id) { case TOK_lparen: p.pushState(&shiftParametersAfterTempl); return Parameters.enter(p); default: return p.parseError("parameter list expected after template arguments"); } } static Action shiftParametersAfterTempl(Parser p) { return shiftMemberFunctionAttribute(p); } } //-- GRAMMAR_BEGIN -- //GlobalIdentifierList: // IdentifierList // . IdentifierList class GlobalIdentifierList { static Action enter(Parser p) { switch(p.tok.id) { case TOK_dot: return IdentifierList.enterGlobal(p); default: return IdentifierList.enter(p); } } } //-- GRAMMAR_BEGIN -- //IdentifierList: // Identifier // Identifier . IdentifierList // TemplateInstance // TemplateInstance . IdentifierList // // using IdentifierOrTemplateInstance class IdentifierList { mixin ListNode!(ast.IdentifierList, IdentifierOrTemplateInstance, TOK_dot); // if preceded by '.', enter here fore global scope static Action enterGlobal(Parser p) { assert(p.tok.id == TOK_dot); auto list = new ast.IdentifierList(p.tok); list.global = true; p.pushNode(list); p.pushState(&shift); p.pushState(&IdentifierOrTemplateInstance.enter); return Accept; } // assumes identifier token on the info stack static Action enterAfterIdentifier(Parser p) { auto list = new ast.IdentifierList(p.topToken()); p.pushNode(list); p.pushState(&shift); return IdentifierOrTemplateInstance.enterIdentifier(p); } } class Identifier { static Action enter(Parser p) { if(p.tok.id != TOK_Identifier) return p.parseError("identifier expected"); p.pushNode(new ast.Identifier(p.tok)); return Accept; } } //-- GRAMMAR_BEGIN -- //StorageClasses: // StorageClass // StorageClass StorageClasses // //StorageClass: // AttributeOrStorageClass // extern // nothrow // pure // synchronized bool isStorageClass(TokenId tok) { switch(tok) { case TOK_extern: case TOK_synchronized: mixin(case_TOKs_FunctionAttribute); mixin(case_TOKs_AttributeOrStorageClass); return true; default: return false; } } //-- GRAMMAR_BEGIN -- //AttributeOrStorageClass: // deprecated // static // final // override // abstract // const // auto // scope // __gshared // __thread // shared // immutable // inout // ref enum case_TOKs_AttributeOrStorageClass = q{ case TOK_deprecated: case TOK_static: case TOK_final: case TOK_override: case TOK_abstract: case TOK_const: case TOK_auto: case TOK_scope: case TOK_volatile: case TOK___gshared: case TOK___thread: case TOK_shared: case TOK_immutable: case TOK_inout: case TOK_ref: }; bool isAttributeOrStorageClass(TokenId tok) { switch(tok) { mixin(case_TOKs_AttributeOrStorageClass); return true; default: return false; } } //-- GRAMMAR_BEGIN -- //Type: // BasicType // BasicType Declarator2 // //Declarator2: // BasicType2 Declarator2 // ( Declarator2 ) // ( Declarator2 ) DeclaratorSuffixes // class Type { static Action enter(Parser p) { p.pushState(&shiftBasicType); return BasicType.enter(p); } static Action shiftBasicType(Parser p) { switch(p.tok.id) { mixin(BasicType2.case_TOKs); p.pushState(&shiftBasicType); return BasicType2.enter(p); case TOK_lparen: // not implemented, better forward, it might also be constructor arguments // p.pushState(&shiftDeclarator2); // return Accept; default: return Forward; } } // entry point from EnumMember: Type Identifier = AssignExpression // and ForeachType: ref_opt Type_opt Identifier // assumes identifier pushed onto token stack static Action enterIdentifier(Parser p) { p.pushState(&shiftBasicType); return BasicType.enterIdentifier(p); } // assumes modifier token on the info stack static Action enterTypeModifier(Parser p) { p.pushState(&shiftBasicType); return BasicType.shiftTypeModifier(p); } static Action shiftDeclarator2(Parser p) { return p.notImplementedError(); } } //-- GRAMMAR_BEGIN -- //TypeWithModifier: // Type // const TypeWithModifier // immutable TypeWithModifier // inout TypeWithModifier // shared TypeWithModifier class TypeWithModifier { static Action enter(Parser p) { switch(p.tok.id) { case TOK_const: case TOK_immutable: case TOK_inout: case TOK_shared: p.pushToken(p.tok); p.pushState(&shiftModifier); return Accept; default: return Type.enter(p); } } static Action shiftModifier(Parser p) { switch(p.tok.id) { case TOK_lparen: return Type.enterTypeModifier(p); default: auto tok = p.popToken(); p.pushNode(new ast.ModifiedType(tok)); p.pushState(&shiftModifiedType); return enter(p); } } static Action shiftModifiedType(Parser p) { p.popAppendTopNode!(ast.ModifiedType)(); return Forward; } } //-- GRAMMAR_BEGIN -- //Parameters: // ( ParameterList ) // ( ) class Parameters { static Action enter(Parser p) { switch(p.tok.id) { case TOK_lparen: p.pushState(&shiftLparen); return Accept; default: return p.parseError("opening parenthesis expected in parameter list"); } } static Action shiftLparen(Parser p) { if(p.tok.id == TOK_rparen) { p.pushNode(new ast.ParameterList(p.tok)); return Accept; } p.pushState(&shiftParameterList); return ParameterList.enter(p); } static Action shiftParameterList(Parser p) { if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected for parameter list"); return Accept; } } //-- GRAMMAR_BEGIN -- //ParameterList: // Parameter // Parameter , ParameterList // Parameter ... // ... class ParameterList { static Action enter(Parser p) { p.pushNode(new ast.ParameterList(p.tok)); return shift(p); } static Action shift(Parser p) { switch(p.tok.id) { case TOK_dotdotdot: p.topNode!(ast.ParameterList)().anonymous_varargs = true; return Accept; default: p.pushState(&shiftParameter); return Parameter.enter(p); } } static Action shiftParameter(Parser p) { p.popAppendTopNode!(ast.ParameterList)(); switch(p.tok.id) { case TOK_dotdotdot: p.topNode!(ast.ParameterList)().varargs = true; return Accept; case TOK_comma: p.pushState(&shift); return Accept; default: return Forward; } } } //-- GRAMMAR_BEGIN -- ///* Declarator replaced with ParameterDeclarator */ //Parameter: // InOut_opt ParameterDeclarator DefaultInitializerExpression_opt // //DefaultInitializerExpression: // = AssignExpression // = __FILE__ // already in primary expression // = __LINE__ // already in primary expression class Parameter { static Action enter(Parser p) { p.pushNode(new ast.Parameter(p.tok)); p.pushState(&shiftParameterDeclarator); if(isInOut(p.tok.id)) { p.topNode!(ast.Parameter)().io = p.tok.id; p.pushState(&ParameterDeclarator.enter); return Accept; } return ParameterDeclarator.enter(p); } static Action shiftParameterDeclarator(Parser p) { p.popAppendTopNode!(ast.Parameter)(); if(p.tok.id != TOK_assign) return Forward; p.pushState(&shiftInitializer); p.pushState(&AssignExpression.enter); return Accept; } static Action shiftInitializer(Parser p) { p.popAppendTopNode!(ast.Parameter)(); return Forward; } } //-- GRAMMAR_BEGIN -- //ParameterDeclarator: // StorageClasses_opt BasicType BasicTypes2_opt Declarator_opt // /*Identifier DeclaratorSuffixes_opt*/ class ParameterDeclarator { // very similar to Decl, combine? // differences: no auto, single Declarator only static Action enter(Parser p) { auto decl = new ast.ParameterDeclarator(p.tok); p.pushNode(decl); return shift(p); } static Action shift(Parser p) { if(isTypeModifier(p.tok.id)) { // could be storage class or BasicType p.pushToken(p.tok); p.pushState(&shiftTypeModifier); return Accept; } if(isStorageClass(p.tok.id)) { auto decl = p.topNode!(ast.ParameterDeclarator)(); p.combineAttributes(decl.attr, tokenToAttribute(p.tok.id)); p.combineAnnotations(decl.annotation, tokenToAnnotation(p.tok.id)); p.pushState(&shiftStorageClass); return Accept; } p.pushState(&shiftBasicType); return BasicType.enter(p); } // disambiguate "const x" and "const(int) x" // assumes modifier token on the info stack static Action shiftTypeModifier(Parser p) { if(p.tok.id == TOK_lparen) { p.pushState(&shiftBasicType); return BasicType.shiftTypeModifier(p); } auto decl = p.topNode!(ast.ParameterDeclarator)(); Token tok = p.popToken(); p.combineAttributes(decl.attr, tokenToAttribute(tok.id)); return shift(p); } static Action shiftStorageClass(Parser p) { if(isTypeModifier(p.tok.id)) { // could be storage class or BasicType p.pushToken(p.tok); p.pushState(&shiftTypeModifier); return Accept; } if(isStorageClass(p.tok.id)) { auto decl = p.topNode!(ast.ParameterDeclarator)(); p.combineAttributes(decl.attr, tokenToAttribute(p.tok.id)); p.combineAnnotations(decl.annotation, tokenToAnnotation(p.tok.id)); p.pushState(&shiftStorageClass); return Accept; } p.pushState(&shiftBasicType); return BasicType.enter(p); } // switch here from TemplateValueParameter when detecting a declaration after an identifier // assumes identifier token on the info stack static Action enterTypeIdentifier(Parser p) { auto decl = new ast.ParameterDeclarator(p.tok); p.pushNode(decl); p.pushState(&shiftBasicType); return BasicType.enterIdentifier(p); } static Action shiftBasicType(Parser p) { switch(p.tok.id) { mixin(BasicType2.case_TOKs); p.pushState(&shiftBasicTypes2); return BasicTypes2.enter(p); default: return shiftBasicTypes2(p); } } static Action shiftBasicTypes2(Parser p) { p.popAppendTopNode!(ast.ParameterDeclarator, ast.Type)(); if(p.tok.id != TOK_Identifier) return Forward; p.pushState(&shiftDeclarator); return Declarator.enter(p); } static Action shiftDeclarator(Parser p) { p.popAppendTopNode!(ast.ParameterDeclarator)(); return Forward; } } //-- GRAMMAR_BEGIN -- //InOut: // in // out // ref // lazy // scope /* ? */ enum case_TOKs_InOut = q{ case TOK_in: case TOK_out: case TOK_ref: case TOK_lazy: case TOK_scope: }; bool isInOut(TokenId tok) { switch(tok) { mixin(case_TOKs_InOut); return true; default: return false; } } //-- GRAMMAR_BEGIN -- //FunctionAttributes: // FunctionAttribute // FunctionAttribute FunctionAttributes // //FunctionAttribute: // nothrow // pure enum case_TOKs_FunctionAttribute = q{ case TOK_nothrow: case TOK_pure: case TOK_safe: case TOK_system: case TOK_trusted: case TOK_property: case TOK_disable: case TOK_nogc: }; bool isFunctionAttribute(TokenId tok) { switch(tok) { mixin(case_TOKs_FunctionAttribute); return true; default: return false; } } //-- GRAMMAR_BEGIN -- //MemberFunctionAttributes: // MemberFunctionAttribute // MemberFunctionAttribute MemberFunctionAttributes // //MemberFunctionAttribute: // const // immutable // inout // shared // FunctionAttribute // enum case_TOKs_MemberFunctionAttribute = q{ case TOK_const: case TOK_immutable: case TOK_inout: case TOK_shared: } ~ case_TOKs_FunctionAttribute; bool isMemberFunctionAttribute(TokenId tok) { switch(tok) { mixin(case_TOKs_MemberFunctionAttribute); return true; default: return false; } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/engine.d0000664000175000017500000010412412776214756027442 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.parser.engine; import std.exception; import std.stdio; import std.string; import std.conv; import std.utf; import stdext.util; import core.bitop; import vdc.util; import vdc.lexer; import vdc.parser.expr; import vdc.parser.mod; import vdc.parser.stmt; import vdc.ast.node; import vdc.ast.writer; // debug version = TraceParser; // version = recoverError; class ParseException : Exception { this(TextSpan _span, string msg) { super(msg); span = _span; } this() { super("syntax error"); } TextSpan span; } alias Action function (Parser p) State; enum { Forward, Accept, Reject } alias int Action; alias TokenId Info; struct Stack(T) { int depth; T[] stack; // use Appender instead? ref T top() { assert(depth > 0); return stack[depth-1]; } void push(T t) { static if(is(T == Token)) { if(depth >= stack.length) { stack ~= new T; } stack[depth].copy(t); } else { if(depth >= stack.length) stack ~= t; else stack[depth] = t; } depth++; } T pop() { assert(depth > 0); auto s = stack[--depth]; return s; } void copyTo(ref Stack!T other) { other.depth = depth; other.stack.length = depth; other.stack[] = stack[0..depth]; } bool compare(ref Stack!T other, int maxdepth) { if(maxdepth > depth) maxdepth = depth; if(other.depth < maxdepth) return false; for(int i = 0; i < maxdepth; i++) if(stack[i] !is other.stack[i]) return false; return true; } } struct Snapshot { int stateStackDepth; int nodeStackDepth; int tokenStackDepth; int tokenPos; State rollbackState; } struct ParseError { TextSpan span; string msg; } class Parser { Stack!State stateStack; Stack!Node nodeStack; Stack!Token tokenStack; Stack!Snapshot rollbackStack; // for backtracking parsing Stack!Snapshot recoverStack; // to continue after errors Stack!Token tokenHistory; int tokenHistoryStart; Stack!Token redoTokens; string filename; int lineno; int tokenPos; Token lookaheadToken; Token tok; Token lexerTok; string partialString; TextSpan partialStringSpan; int countErrors; int lastErrorTokenPos; string lastError; TextSpan lastErrorSpan; version(recoverError) { Stack!State errStateStack; Stack!Node errNodeStack; Stack!Token errTokenStack; } version(TraceParser) State[] traceState; version(TraceParser) string[] traceToken; bool recovering; bool abort; bool saveErrors; ParseError[] errors; State lastState; this() { lexerTok = new Token; } // node stack ////////////////// @property T topNode(T = Node)() { Node n = nodeStack.top(); return static_cast!T(n); } void pushNode(Node n) { nodeStack.push(n); } T popNode(T = Node)() { Node n = nodeStack.pop(); nodeStack.stack[nodeStack.depth] = null; return static_cast!T(n); } // replace item on the node stack, appending old top as child void appendReplaceTopNode(Node n) { auto node = popNode(); n.addMember(node); pushNode(n); } // pop top item from the node stack and add it to the members of the new top item void popAppendTopNode(T = Node, P = Node)() { auto node = popNode(); if(!__ctfe) assert(cast(P) node); if(!__ctfe) assert(cast(T) topNode()); topNode().addMember(node); } // extend the full psan of the node on top of the node stack void extendTopNode(Token tok) { if(nodeStack.depth > 0) topNode().extendSpan(tok.span); } // state stack ////////////////// void pushState(State fn) { stateStack.push(fn); } State popState() { State s = stateStack.pop(); stateStack.stack[stateStack.depth] = null; return s; } // token stack ////////////////// Token topToken() { return tokenStack.top(); } void pushToken(Token token) { tokenStack.push(token); } Token popToken() { return tokenStack.pop(); } // error handling ////////////////// string createError(string msg) { string where; if(filename.length) where = filename ~ "(" ~ text(lineno) ~ "): '" ~ tok.txt ~ "' - "; else where = "line " ~ text(lineno) ~ " '" ~ tok.txt ~ "': "; return where ~ msg; } Action parseError(string msg) { if(tokenPos < lastErrorTokenPos || recovering) return Reject; lastErrorTokenPos = tokenPos; lastError = createError(msg); lastErrorSpan = tok.span; version(recoverError) { stateStack.copyTo(errStateStack); nodeStack.copyTo(errNodeStack); tokenStack.copyTo(errTokenStack); errStateStack.push(lastState); } return Reject; } void writeError(ref const(TextSpan) errorSpan, string msg) { if(saveErrors) errors ~= ParseError(errorSpan, msg); else writeln(msg); countErrors++; } void writeError(string msg) { writeError(tok.span, msg); } Action notImplementedError(string what = "") { return parseError("not implemented: " ~ what); } // backtrace parsing void pushRollback(State rollbackState) { Snapshot ss; ss.stateStackDepth = stateStack.depth; ss.nodeStackDepth = nodeStack.depth; ss.tokenStackDepth = tokenStack.depth; ss.tokenPos = tokenHistory.depth; ss.rollbackState = rollbackState; rollbackStack.push(ss); } void popRollback() { rollbackStack.pop(); if(rollbackStack.depth == 0) tokenHistory.depth = 0; } void rollback() { Snapshot ss = rollbackStack.pop(); assert(stateStack.depth >= ss.stateStackDepth); assert(nodeStack.depth >= ss.nodeStackDepth); assert(tokenStack.depth >= ss.tokenStackDepth); assert(ss.tokenPos < tokenHistory.depth); stateStack.depth = ss.stateStackDepth; nodeStack.depth = ss.nodeStackDepth; tokenStack.depth = ss.tokenStackDepth; while(ss.tokenPos < tokenHistory.depth) { Token token = tokenHistory.pop(); redoTokens.push(token); tokenPos--; } pushState(ss.rollbackState); } version(recoverError) void recoverNode(ref Snapshot ss) { assert(stateStack.compare(errStateStack, ss.stateStackDepth)); assert(nodeStack.compare(errNodeStack, ss.nodeStackDepth)); assert(tokenStack.compare(errTokenStack, ss.tokenStackDepth)); Token _tok = new Token; _tok.copy(lexerTok); _tok.id = TOK_RECOVER; _tok.txt = "__recover" ~ to!string(countErrors); _tok.span.end = tok.span.start; tok = _tok; recovering = true; scope(exit) recovering = false; errStateStack.copyTo(stateStack); errNodeStack.copyTo(nodeStack); errTokenStack.copyTo(tokenStack); Action act = Forward; while(stateStack.depth > ss.stateStackDepth && nodeStack.depth >= ss.nodeStackDepth && tokenStack.depth >= ss.tokenStackDepth && act == Forward) { State fn = popState(); act = fn(this); } } // recover from error void pushRecoverState(State recoverState) { Snapshot ss; ss.stateStackDepth = stateStack.depth; ss.nodeStackDepth = nodeStack.depth; ss.tokenStackDepth = tokenStack.depth; ss.rollbackState = recoverState; recoverStack.push(ss); } void popRecoverState() { recoverStack.pop(); } void recover() { Snapshot ss = recoverStack.top(); assert(stateStack.depth >= ss.stateStackDepth); assert(nodeStack.depth >= ss.nodeStackDepth); assert(tokenStack.depth >= ss.tokenStackDepth); version(recoverError) recoverNode(ss); stateStack.depth = ss.stateStackDepth; nodeStack.depth = ss.nodeStackDepth; tokenStack.depth = ss.tokenStackDepth; pushState(ss.rollbackState); } static Action keepRecover(Parser p) { // can be inserted into the state stack to avoid implicitely removing an entry of the recover stack return Forward; } static Action recoverSemiCurly(Parser p) { switch(p.tok.id) { case TOK_semicolon: return Accept; case TOK_EOF: case TOK_rcurly: return Forward; case TOK_lcurly: // stop after closing curly (if not nested in some other braces p.pushState(&recoverBlock!TOK_rcurly); return Accept; case TOK_lparen: p.pushState(&recoverSemiCurly); p.pushState(&recoverBlock!TOK_rparen); return Accept; case TOK_lbracket: p.pushState(&recoverSemiCurly); p.pushState(&recoverBlock!TOK_rbracket); return Accept; default: p.pushState(&recoverSemiCurly); return Accept; } } // skip over nested brace blocks static Action recoverBlock(TokenId id)(Parser p) { switch(p.tok.id) { case TOK_EOF: return Forward; case TOK_rcurly: case TOK_rparen: case TOK_rbracket: return p.tok.id == id ? Accept : Forward; case TOK_lparen: p.pushState(&recoverBlock!id); p.pushState(&recoverBlock!TOK_rparen); return Accept; case TOK_lbracket: p.pushState(&recoverBlock!id); p.pushState(&recoverBlock!TOK_rbracket); return Accept; case TOK_lcurly: p.pushState(&recoverBlock!id); p.pushState(&recoverBlock!TOK_rcurly); return Accept; default: p.pushState(&recoverBlock!id); return Accept; } } /////////////////////////////////////////////////////////// void verifyAttributes(Attribute attr, ref Attribute newAttr, Attribute mask) { if((newAttr & mask) && (attr & mask) && (newAttr & mask) != (attr & mask)) { string txt; writeError(createError("conflicting attributes " ~ attrToString(attr & mask) ~ " and " ~ attrToString(newAttr & mask))); newAttr &= ~mask; } } void combineAttributes(ref Attribute attr, Attribute newAttr) { if(newAttr & attr) { string txt; DCodeWriter writer = new DCodeWriter(getStringSink(txt)); writer.writeAttributes(newAttr & attr); writeError(createError("multiple specification of " ~ txt)); } verifyAttributes(attr, newAttr, Attr_AlignMask); verifyAttributes(attr, newAttr, Attr_CallMask); verifyAttributes(attr, newAttr, Attr_ShareMask); attr = attr | newAttr; } void verifyAnnotations(Annotation annot, ref Annotation newAnnot, Annotation mask) { if((newAnnot & mask) && (annot & mask) && (newAnnot & mask) != (annot & mask)) { string txt; writeError(createError("conflicting attributes " ~ annotationToString(annot & mask) ~ " and " ~ annotationToString(newAnnot & mask))); newAnnot &= ~mask; } } void combineAnnotations(ref Annotation annot, Annotation newAnnot) { if(newAnnot & annot) { string txt; DCodeWriter writer = new DCodeWriter(getStringSink(txt)); writer.writeAnnotations(newAnnot & annot); writeError(createError("multiple specification of " ~ txt)); } verifyAttributes(annot, newAnnot, Annotation_ProtectionMask); verifyAttributes(annot, newAnnot, Annotation_SafeMask); annot = annot | newAnnot; } /////////////////////////////////////////////////////////// // skip over nested parenthesis blocks static Action lookaheadParen(Parser p) { switch(p.tok.id) { case TOK_EOF: return Forward; case TOK_rparen: return Accept; case TOK_lparen: p.pushState(&lookaheadParen); p.pushState(&lookaheadParen); return Accept; default: p.pushState(&lookaheadParen); return Accept; } } static Action finishLookaheadParen(Parser p) { p.lookaheadToken = p.tok; return Reject; } static Action rollbackPeekAfterParen(Parser p) { assert(p.tok.id == TOK_lparen); return Forward; } // look ahead after closing paren and return token after ')' on token stack Action peekAfterParen(Parser p, State fn) { assert(tok.id == TOK_lparen); p.pushState(fn); p.pushRollback(&rollbackPeekAfterParen); p.pushState(&finishLookaheadParen); return lookaheadParen(p); } // parsing ////////////////// static Action forward(Parser p) { return Forward; } static Action popForward(Parser p) { p.popAppendTopNode!()(); return Forward; } static Action accept(Parser p) { return Accept; } Action shiftOne(Token _tok) { tok = _tok; Action act; do { assert(stateStack.depth > 0); State fn = popState(); lastState = fn; while(recoverStack.depth > 0 && stateStack.depth <= recoverStack.top().stateStackDepth) popRecoverState(); version(TraceParser) { traceState ~= fn; traceToken ~= tok.txt; if(traceState.length > 200) { traceState = traceState[$-100 .. $]; traceToken = traceToken[$-100 .. $]; } } act = fn(this); if(act == Accept) extendTopNode(tok); } while(act == Forward); return act; } bool shift(Token _tok) { Action act; redoTokens.push(_tok); while(redoTokens.depth > 0) { Token t = redoTokens.pop(); tokenPos++; retryToken: act = shiftOne(t); if(rollbackStack.depth > 0) tokenHistory.push(tok); if(act == Reject) { if(rollbackStack.depth > 0) { rollback(); continue; } if(recoverStack.depth > 0) { writeError(lastErrorSpan, lastError); recover(); goto retryToken; } throw new ParseException(lastErrorSpan, lastError); } } return act == Accept; } bool shiftEOF() { lexerTok.id = TOK_EOF; lexerTok.txt = ""; if(!shift(lexerTok)) return false; if (nodeStack.depth > 1) return parseError("parsing unfinished before end of file") == Accept; if (nodeStack.depth == 0) return false; return true; } void parseLine(S)(ref int state, S line, int lno) { version(log) writeln(line); if(partialString.length) partialString ~= "\n"; lineno = lno; for(uint pos = 0; pos < line.length && !abort; ) { int tokid; uint prevpos = pos; TokenCat type = cast(TokenCat) Lexer.scan(state, line, pos, tokid); if(tokid != TOK_Space && tokid != TOK_Comment) { string txt = line[prevpos .. pos]; lexerTok.span.start.line = lexerTok.span.end.line = lineno; lexerTok.span.start.index = prevpos; lexerTok.span.end.index = pos; if(tokid == TOK_StringLiteral) { if(Lexer.scanState(state) != Lexer.State.kWhite || Lexer.tokenStringLevel(state) > 0) { if(partialString.length == 0) partialStringSpan = lexerTok.span; partialString ~= txt; continue; } else { if(partialString.length) { lexerTok.span.start.line = partialStringSpan.start.line; lexerTok.span.start.index = partialStringSpan.start.index; txt = partialString ~ txt; partialString = partialString.init; } } } lexerTok.txt = txt; lexerTok.id = tokid; shift(lexerTok); } } } void parseText(S)(S text) { int state = 0; version(all) { Lexer lex; lex.mTokenizeTokenString = false; lineno = 1; size_t linepos = 0; // position after last line break int tokid; for(size_t pos = 0; pos < text.length && !abort; ) { int prevlineno = lineno; size_t prevlinepos = linepos; size_t prevpos = pos; TokenCat type = cast(TokenCat) lex.scan(state, text, pos, tokid); if(tokid == TOK_Space || tokid == TOK_Comment || tokid == TOK_StringLiteral || tokid == TOK_CharacterLiteral) { for(size_t lpos = prevpos; lpos < pos; lpos++) if(text[lpos] == '\n') { lineno++; linepos = lpos + 1; } } if(tokid != TOK_Space && tokid != TOK_Comment) { lexerTok.txt = text[prevpos .. pos]; lexerTok.id = tokid; lexerTok.span.start.line = prevlineno; lexerTok.span.end.line = lineno; lexerTok.span.start.index = cast(int) (prevpos - prevlinepos); lexerTok.span.end.index = cast(int) (pos - linepos); shift(lexerTok); } } } else { S[] lines = splitLines(text); foreach(lno, line; lines) parseLine(state, line, lno + 1); } } Node parseModule(S)(S text) { reinit(); pushState(&Module.enter); parseText(text); if(abort || !shiftEOF()) return null; return popNode(); } Node[] parseCurlyBlock(S)(S text, TextSpan mixinSpan) { lexerTok.txt = "{"; lexerTok.id = TOK_lcurly; lexerTok.span = mixinSpan; lexerTok.span.end.index = mixinSpan.end.index + 1; if(!shift(lexerTok)) return null; parseText(text); lexerTok.txt = "}"; lexerTok.id = TOK_rcurly; if(abort || !shift(lexerTok)) return null; if (nodeStack.depth > 1) return parseError("parsing unfinished before end of mixin"), null; return popNode().members; } Node[] parseDeclarations(S)(S text, TextSpan mixinSpan) { reinit(); pushState(&DeclarationBlock.enter); return parseCurlyBlock(text, mixinSpan); } Node[] parseStatements(S)(S text, TextSpan mixinSpan) { reinit(); pushState(&BlockStatement.enter); return parseCurlyBlock(text, mixinSpan); } Node parseExpression(S)(S text, TextSpan mixinSpan) { reinit(); pushState(&Expression.enter); lexerTok.txt = "("; lexerTok.id = TOK_lparen; lexerTok.span = mixinSpan; lexerTok.span.end.index = mixinSpan.end.index + 1; if(!shift(lexerTok)) return null; parseText(text); lexerTok.txt = ")"; lexerTok.id = TOK_rparen; if(abort || !shift(lexerTok)) return null; if (nodeStack.depth > 1) return parseError("parsing unfinished before end of mixin"), null; return popNode(); } void reinit() { stateStack = stateStack.init; nodeStack = nodeStack.init; tokenStack = tokenStack.init; version(recoverError) { errStateStack = errStateStack.init; errNodeStack = errNodeStack.init; errTokenStack = errTokenStack.init; } lastErrorTokenPos = 0; lastError = ""; errors = errors.init; countErrors = 0; abort = false; recovering = false; lastState = null; } } string readUtf8(string fname) { /* Convert all non-UTF-8 formats to UTF-8. * BOM : http://www.unicode.org/faq/utf_bom.html * 00 00 FE FF UTF-32BE, big-endian * FF FE 00 00 UTF-32LE, little-endian * FE FF UTF-16BE, big-endian * FF FE UTF-16LE, little-endian * EF BB BF UTF-8 */ static const ubyte[4] bomUTF32BE = [ 0x00, 0x00, 0xFE, 0xFF ]; // UTF-32, big-endian static const ubyte[4] bomUTF32LE = [ 0xFF, 0xFE, 0x00, 0x00 ]; // UTF-32, little-endian static const ubyte[2] bomUTF16BE = [ 0xFE, 0xFF ]; // UTF-16, big-endian static const ubyte[2] bomUTF16LE = [ 0xFF, 0xFE ]; // UTF-16, little-endian static const ubyte[3] bomUTF8 = [ 0xEF, 0xBB, 0xBF ]; // UTF-8 ubyte[] data = cast(ubyte[]) std.file.read(fname); if(data.length >= 4 && data[0..4] == bomUTF32BE[]) foreach(ref d; cast(uint[]) data) d = bswap(d); if(data.length >= 2 && data[0..2] == bomUTF16BE[]) foreach(ref d; cast(ushort[]) data) d = bswap(d) >> 16; if(data.length >= 4 && data[0..4] == bomUTF32LE[]) return toUTF8(cast(dchar[]) data[4..$]); if(data.length >= 2 && data[0..2] == bomUTF16LE[]) return toUTF8(cast(wchar[]) data[2..$]); if(data.length >= 3 && data[0..3] == bomUTF8[]) return toUTF8(cast(string) data[3..$]); return cast(string)data; } //////////////////////////////////////////////////////////////// bool isInOps(ops...)(TokenId tok) { foreach(o; ops) if(tok == o) return true; return false; } class NoASTNode {} // always adds a node with an array of ASTNodeType nodes, even if empty // if trailingSeparator, sep at the end is allowed, but closing bracket is expected afterwards mixin template ListNode(ASTNodeType, SubType, TokenId sep, bool trailingSeparator = false, bool allowEmpty = false) { static Action enter(Parser p) { static if(!is(ASTNodeType == NoASTNode)) p.pushNode(new ASTNodeType(p.tok)); static if(allowEmpty) switch(p.tok.id) { case TOK_rparen: case TOK_rbracket: case TOK_rcurly: return Forward; default: } p.pushState(&shift); return SubType.enter(p); } static Action shift(Parser p) { p.popAppendTopNode!ASTNodeType(); if(p.tok.id != sep) return Forward; static if(trailingSeparator) { p.pushState(&shiftSeparator); } else { p.pushState(&shift); p.pushState(&SubType.enter); } return Accept; } static if(trailingSeparator) static Action shiftSeparator(Parser p) { switch(p.tok.id) { case TOK_rparen: case TOK_rbracket: case TOK_rcurly: return Forward; default: p.pushState(&shift); return SubType.enter(p); } } } // binary operator, left/right/no recursion // //BinaryNode: // SubType // R: SubType op BinaryNode // L: BinaryNode op SubType // N: SubType op SubType mixin template BinaryNode(ASTNodeType, string recursion, SubType, ops...) { static assert(recursion == "L" || recursion == "R" || recursion == "N"); static Action enter(Parser p) { p.pushState(&shift); return SubType.enter(p); } static Action shift(Parser p) { if(!isInOps!(ops)(p.tok.id)) return Forward; p.appendReplaceTopNode(new ASTNodeType(p.tok)); p.pushState(&shiftNext); static if(recursion == "L" || recursion == "N") p.pushState(&SubType.enter); else p.pushState(&enter); return Accept; } static Action shiftNext(Parser p) { p.popAppendTopNode!ASTNodeType(); static if(recursion == "L") return shift(p); else return Forward; } } // ternary operator, right recursion // //TernaryNode: // SubType1 // SubType1 op1 SubType2 op2 TernaryNode mixin template TernaryNode(ASTNodeType, SubType1, TokenId op1, SubType2, TokenId op2) { static Action enter(Parser p) { p.pushState(&shift); return SubType1.enter(p); } static Action shift(Parser p) { if(p.tok.id != op1) return Forward; p.appendReplaceTopNode(new ASTNodeType(p.tok)); p.pushState(&shiftNext); p.pushState(&SubType2.enter); return Accept; } static Action shiftNext(Parser p) { if(p.tok.id != op2) return p.parseError("second operator '" ~ tokenString(op2) ~ "'in ternary expression expected"); p.popAppendTopNode!ASTNodeType(); p.pushState(&shiftLast); p.pushState(&enter); return Accept; } static Action shiftLast(Parser p) { p.popAppendTopNode!ASTNodeType(); return Forward; } } //OptionalNode: // SubType1 // SubType1 op SubType2 mixin template OptionalNode(ASTNodeType, SubType1, TokenId op, SubType2) { static Action enter(Parser p) { p.pushState(&shiftSubType1); return SubType1.enter(p); } static Action shiftSubType1(Parser p) { if(p.tok.id != op) return Forward; p.appendReplaceTopNode(new ASTNodeType(p.tok)); p.pushState(&shiftSubType2); p.pushState(&SubType2.enter); return Accept; } static Action shiftSubType2(Parser p) { p.popAppendTopNode!ASTNodeType(); return Forward; } } //SequenceNode: // SubType1/Token1 SubType2/Token2 SubType3/Token3 SubType4/Token4 mixin template SequenceNode(ASTNodeType, T...) { static Action enter(Parser p) { static if(!is(ASTNodeType == NoASTNode)) p.pushNode(new ASTNodeType(p.tok)); return shift0.next(p); } mixin template ShiftState(int n, alias shiftFn, alias nextFn) { static if(n < T.length) { static Action shift(Parser p) { static if(is(T[n-1] == class)) { static if(!__traits(compiles,T[n-1].doNotPopNode)) static if(!is(ASTNodeType == NoASTNode)) p.popAppendTopNode!ASTNodeType(); } return next(p); } static Action next(Parser p) { static if (is(typeof(& T[n]) U : U*) && is(U == function)) { return T[n](p); } else { static if(__traits(compiles,T[n].startsWithOp(p.tok.id))) if(!T[n].startsWithOp(p.tok.id)) return nextFn(p); static if(n < T.length-1) p.pushState(&shiftFn); static if(is(T[n] == class)) { static if(n == T.length-1) p.pushState(&reduce); return T[n].enter(p); } else { if(p.tok.id != T[n]) return p.parseError("'" ~ tokenString(T[n]) ~ "' expected"); return Accept; } } } } else { static Action shift(Parser p) { return Forward; } static Action next(Parser p) { return Forward; } } } mixin ShiftState!(9, reduce, reduce) shift9; mixin ShiftState!(8, shift9.shift, shift9.next) shift8; mixin ShiftState!(7, shift8.shift, shift8.next) shift7; mixin ShiftState!(6, shift7.shift, shift7.next) shift6; mixin ShiftState!(5, shift6.shift, shift6.next) shift5; mixin ShiftState!(4, shift5.shift, shift5.next) shift4; mixin ShiftState!(3, shift4.shift, shift4.next) shift3; mixin ShiftState!(2, shift3.shift, shift3.next) shift2; mixin ShiftState!(1, shift2.shift, shift2.next) shift1; mixin ShiftState!(0, shift1.shift, shift1.next) shift0; static Action reduce(Parser p) { static if(!is(ASTNodeType == NoASTNode)) p.popAppendTopNode!ASTNodeType(); return Forward; } } class Opt(NT, ops...) { static bool startsWithOp(TokenId tok) { foreach(o; ops) if(tok == o) return true; return false; } static Action enter(Parser p) { return NT.enter(p); } } //////////////////////////////////////////////////////////////// // unfortunately, states have to be in reverse order because of unresolved forward references mixin template stateEnterToken(TokenId id, ASTType, alias newstate) { static Action enter(Parser p) { switch(p.tok.id) { case id: static if(!is(ASTType : NoASTNode)) p.pushNode(new ASTType(p.tok)); p.pushState(&newstate); return Accept; default: return p.parseError(tokenString(id) ~ " expected"); } } } mixin template stateEnterClass(SubType, ASTType, alias newstate) { static Action enter(Parser p) { static if(!is(ASTType : NoASTNode)) p.pushNode(new ASTType(p.tok)); p.pushState(&enterReduce); return SubType.enter(p); } static Action enterReduce(Parser p) { static if(!is(ASTType : NoASTNode)) p.popAppendTopNode!(); return newstate(p); } } mixin template stateShiftToken(TokenId id1, alias newstate1, TokenId id2 = 0, alias newstate2 = Parser.forward, TokenId id3 = 0, alias newstate3 = Parser.forward, TokenId id4 = 0, alias newstate4 = Parser.forward) { static Action shift(Parser p) { switch(p.tok.id) { static if(id1 > 0) { case id1: static if(&newstate1 !is &Parser.forward) p.pushState(&newstate1); return Accept; } static if(id2 > 0) { case id2: static if(&newstate2 !is &Parser.forward) p.pushState(&newstate2); return Accept; } static if(id3 > 0) { case id3: static if(&newstate3 !is &Parser.forward) p.pushState(&newstate3); return Accept; } static if(id4 > 0) { case id4: static if(&newstate4 !is &Parser.forward) p.pushState(&newstate4); return Accept; } default: static if(id1 == -1) static if(&newstate1 is &Parser.forward) return Forward; else return newstate1(p); else static if(id2 == -1) static if(&newstate2 is &Parser.forward) return Forward; else return newstate2(p); else static if(id3 == -1) static if(&newstate3 is &Parser.forward) return Forward; else return newstate3(p); else static if(id4 == -1) static if(&newstate4 is &Parser.forward) return Forward; else return newstate4(p); else { string msg = tokenString(id1); static if(id2 != 0) msg ~= " or " ~ tokenString(id2); static if(id3 != 0) msg ~= " or " ~ tokenString(id3); static if(id4 != 0) msg ~= " or " ~ tokenString(id4); return p.parseError(tokenString(id1) ~ " expected"); } } } } mixin template stateAppendClass(C, alias newstate) { static Action shift(Parser p) { p.pushState(&reduce); return C.enter(p); } static Action reduce(Parser p) { p.popAppendTopNode!(); return newstate(p); } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/misc.d0000664000175000017500000005421712776214756027137 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.parser.misc; import vdc.util; import vdc.lexer; import vdc.parser.engine; import vdc.parser.expr; import vdc.parser.decl; import vdc.parser.stmt; import vdc.parser.mod; import ast = vdc.ast.all; import stdext.util; //-- GRAMMAR_BEGIN -- //EnumDeclaration: // enum EnumTag EnumBody // enum EnumBody // enum EnumTag : EnumBaseType EnumBody // enum : EnumBaseType EnumBody // enum EnumTag ; // enum EnumInitializers ; // enum Type EnumInitializers ; // //EnumTag: // Identifier // //EnumBaseType: // Type // //EnumInitializers: // EnumInitializer // EnumInitializers , EnumInitializer // //EnumInitializer: // Identifier = AssignExpression class EnumDeclaration { static Action enter(Parser p) { if(p.tok.id != TOK_enum) return p.parseError("enum expected"); p.pushNode(new ast.EnumDeclaration(p.tok)); p.pushState(&shiftEnum); return Accept; } static Action shiftEnum(Parser p) { switch(p.tok.id) { case TOK_lcurly: p.pushState(&shiftEnumBody); return EnumBody.enter(p); case TOK_colon: p.pushState(&shiftColon); return Accept; case TOK_Identifier: p.pushToken(p.tok); p.pushState(&shiftIdentifier); return Accept; default: p.pushState(&shiftType); return Type.enter(p); } } static Action shiftColon(Parser p) { p.pushState(&shiftBaseType); return Type.enter(p); } static Action shiftType(Parser p) { p.popAppendTopNode!(ast.EnumDeclaration)(); switch(p.tok.id) { case TOK_Identifier: p.topNode!(ast.EnumDeclaration)().ident = p.tok.txt; p.pushState(&shiftAssignAfterType); return Accept; default: return p.parseError("identifier expected after enum type"); } } // assumes token on stack static Action shiftIdentifier(Parser p) { switch(p.tok.id) { case TOK_colon: p.topNode!(ast.EnumDeclaration)().ident = p.popToken().txt; p.pushState(&shiftColon); return Accept; case TOK_semicolon: p.topNode!(ast.EnumDeclaration)().ident = p.popToken().txt; return Accept; case TOK_assign: p.topNode!(ast.EnumDeclaration)().ident = p.popToken().txt; p.pushState(&shiftAssign); return Accept; case TOK_lcurly: p.topNode!(ast.EnumDeclaration)().ident = p.popToken().txt; p.pushState(&shiftEnumBody); return EnumBody.enter(p); default: p.pushState(&shiftType); return Type.enterIdentifier(p); } } static Action shiftBaseType(Parser p) { p.popAppendTopNode!(ast.EnumDeclaration)(); p.pushState(&shiftEnumBody); return EnumBody.enter(p); } static Action shiftEnumBody(Parser p) { p.popAppendTopNode!(ast.EnumDeclaration)(); return Forward; } static Action shiftAssignAfterType(Parser p) { switch(p.tok.id) { case TOK_assign: p.pushState(&shiftAssign); return Accept; default: return p.parseError("'=' expected to initialize enum"); } } static Action shiftAssign(Parser p) { p.pushState(&shiftExpression); return AssignExpression.enter(p); } static Action shiftExpression(Parser p) { auto expr = p.popNode(); auto ed = p.topNode!(ast.EnumDeclaration)(); // rebuild as anonymous enum with single member auto b = new ast.EnumBody(TOK_lcurly, ed.span); auto m = new ast.EnumMembers(TOK_Identifier, ed.span); auto e = new ast.EnumMember(TOK_Identifier, ed.span); e.addMember(expr); e.ident = ed.ident; m.addMember(e); b.addMember(m); ed.ident = null; ed.isDecl = true; ed.addMember(b); switch(p.tok.id) { case TOK_semicolon: return Accept; case TOK_comma: p.pushState(&shiftNextIdentifier); return Accept; default: return p.parseError("';' expected after single line enum"); } } static Action shiftNextIdentifier(Parser p) { switch(p.tok.id) { case TOK_Identifier: auto e = new ast.EnumMember(p.tok); e.ident = p.tok.txt; p.pushNode(e); p.pushState(&shiftAssignAfterNextIdentifier); return Accept; default: return p.parseError("identifier expected after enum type"); } } static Action shiftAssignAfterNextIdentifier(Parser p) { switch(p.tok.id) { case TOK_assign: p.pushState(&shiftNextAssign); return Accept; default: return p.parseError("'=' expected to initialize enum"); } } static Action shiftNextAssign(Parser p) { p.pushState(&shiftNextExpression); return AssignExpression.enter(p); } static Action shiftNextExpression(Parser p) { p.popAppendTopNode!(ast.EnumMember)(); auto m = p.popNode!(ast.EnumMember)(); auto ed = p.topNode!(ast.EnumDeclaration)(); auto eb = ed.getBody(); auto em = static_cast!(ast.EnumMembers)(eb.getMember(0)); em.addMember(m); switch(p.tok.id) { case TOK_semicolon: return Accept; case TOK_comma: p.pushState(&shiftNextIdentifier); return Accept; default: return p.parseError("';' expected after single line enum"); } } } //-- GRAMMAR_BEGIN -- // forward declaration not needed with proper handling //EnumBody: // ; // { EnumMembers } class EnumBody { mixin SequenceNode!(ast.EnumBody, TOK_lcurly, EnumMembersRecover, TOK_rcurly); } class EnumMembersRecover { static Action enter(Parser p) { p.pushNode(new ast.EnumMembers(p.tok)); // recover code inserted into EnumMembers.enter p.pushRecoverState(&recover); p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover p.pushState(&verifyCurly); p.pushState(&EnumMembers.shift); return EnumMember.enter(p); } static Action verifyCurly(Parser p) { if(p.tok.id != TOK_rcurly) return p.parseError("'}' expected after enum"); return Forward; } static Action recover(Parser p) { return Parser.recoverSemiCurly(p); } } //-- GRAMMAR_BEGIN -- //EnumMembers: // EnumMember // EnumMember , // EnumMember , EnumMembers class EnumMembers { mixin ListNode!(ast.EnumMembers, EnumMember, TOK_comma, true); } //-- GRAMMAR_BEGIN -- //EnumMember: // Identifier // Identifier = AssignExpression // Type Identifier = AssignExpression class EnumMember { static Action enter(Parser p) { p.pushNode(new ast.EnumMember(p.tok)); if(p.tok.id != TOK_Identifier) { p.pushState(&shiftType); return Type.enter(p); } p.pushState(&shiftIdentifierOrType); p.pushToken(p.tok); return Accept; } static Action shiftIdentifierOrType(Parser p) { if(p.tok.id != TOK_assign && p.tok.id != TOK_comma && p.tok.id != TOK_rcurly) { p.pushState(&shiftType); return Type.enterIdentifier(p); } Token tok = p.popToken(); ast.EnumMember em = p.topNode!(ast.EnumMember)(); em.ident = tok.txt; return shiftIdentifier(p); } static Action shiftAssign(Parser p) { p.pushState(&shiftExpression); return AssignExpression.enter(p); } static Action shiftExpression(Parser p) { p.popAppendTopNode!(ast.EnumMember, ast.Expression)(); return Forward; } static Action shiftType(Parser p) { if(p.tok.id != TOK_Identifier) return p.parseError("identifier expected after type in enum"); p.popAppendTopNode!(ast.EnumMember, ast.Type)(); auto em = p.topNode!(ast.EnumMember)(); em.ident = p.tok.txt; p.pushState(&shiftIdentifier); return Accept; } static Action shiftIdentifier(Parser p) { if(p.tok.id != TOK_assign) return Forward; p.pushState(&shiftAssign); return Accept; } } //////////////////////////////////////////////////////////////// //-- GRAMMAR_BEGIN -- //FunctionBody: // BlockStatement // BodyStatement // InStatement BodyStatement // OutStatement BodyStatement // InStatement OutStatement BodyStatement // OutStatement InStatement BodyStatement // //InStatement: // in BlockStatement // //OutStatement: // out BlockStatement // out ( Identifier ) BlockStatement // //BodyStatement: // body BlockStatement // // body statement might be missing in interface contracts // class FunctionBody { static bool isInitTerminal(Token tok) { switch(tok.id) { case TOK_lcurly: case TOK_body: case TOK_in: case TOK_out: return true; default: return false; } } static Action enter(Parser p) { ast.FunctionBody fb = new ast.FunctionBody(p.tok); p.pushNode(fb); if(p.tok.id == TOK_lcurly) { p.pushState(&shiftBodyStatement); return BlockStatement.enter(p); } return shiftStatement(p); } static Action shiftBodyStatement(Parser p) { auto bodyStmt = p.topNode!(ast.BlockStatement)(); p.popAppendTopNode(); p.topNode!(ast.FunctionBody)().bodyStatement = bodyStmt; return Forward; } static Action shiftInStatement(Parser p) { auto inStmt = p.topNode!(ast.BlockStatement)(); p.popAppendTopNode(); p.topNode!(ast.FunctionBody)().inStatement = inStmt; return shiftStatement(p); } static Action shiftOutStatement(Parser p) { auto outStmt = p.topNode!(ast.BlockStatement)(); p.popAppendTopNode(); p.topNode!(ast.FunctionBody)().outStatement = outStmt; return shiftStatement(p); } static Action shiftStatement(Parser p) { switch(p.tok.id) { case TOK_body: p.pushState(&shiftBodyStatement); p.pushState(&BlockStatement.enter); return Accept; case TOK_in: if(p.topNode!(ast.FunctionBody)().inStatement) return p.parseError("duplicate in block"); p.pushState(&shiftInStatement); p.pushState(&BlockStatement.enter); return Accept; case TOK_out: if(p.topNode!(ast.FunctionBody)().outStatement) return p.parseError("duplicate out block"); p.pushState(&shiftOut); return Accept; default: return Forward; // p.parseError("expected body or in or out block"); } } static Action shiftOut(Parser p) { if(p.tok.id == TOK_lparen) { p.pushState(&shiftLparen); return Accept; } p.pushState(&shiftOutStatement); return BlockStatement.enter(p); } static Action shiftLparen(Parser p) { if(p.tok.id != TOK_Identifier) return p.parseError("identifier expected for return value in out contract"); auto outid = new ast.OutIdentifier(p.tok); p.topNode!(ast.FunctionBody)().addMember(outid); p.topNode!(ast.FunctionBody)().outIdentifier = outid; p.pushState(&shiftOutIdentifier); return Accept; } static Action shiftOutIdentifier(Parser p) { if(p.tok.id != TOK_rparen) return p.parseError("closing parenthesis expected in out contract"); p.pushState(&shiftOutStatement); p.pushState(&BlockStatement.enter); return Accept; } } //////////////////////////////////////////////////////////////// // disambiguate between VersionCondition and VersionSpecification class VersionCondOrSpec { static Action enter(Parser p) { assert(p.tok.id == TOK_version); p.pushState(&shiftVersion); return Accept; } static Action shiftVersion(Parser p) { switch(p.tok.id) { case TOK_assign: return VersionSpecification.enterAfterVersion(p); case TOK_lparen: return ConditionalDeclaration.enterAfterVersion(p); default: return p.parseError("'=' or '(' expected after version"); } } } //-- GRAMMAR_BEGIN -- //ConditionalDeclaration: // Condition DeclarationBlock // Condition DeclarationBlock else DeclarationBlock // Condition: DeclDefs_opt class ConditionalDeclaration { // Condition DeclarationBlock else $ DeclarationBlock mixin stateAppendClass!(DeclarationBlock, Parser.forward) stateElseDecl; // Condition DeclarationBlock $ else DeclarationBlock mixin stateShiftToken!(TOK_else, stateElseDecl.shift, -1, Parser.forward) stateElse; // Condition $ DeclarationBlock else DeclarationBlock mixin stateAppendClass!(DeclarationBlock, stateElse.shift) stateThenDecl; static Action shiftCondition(Parser p) { switch(p.tok.id) { case TOK_colon: auto declblk = new ast.DeclarationBlock(p.tok); p.topNode!(ast.ConditionalDeclaration).id = TOK_colon; p.pushNode(declblk); p.pushState(&enterDeclarationBlock); return Accept; default: return stateThenDecl.shift(p); } } static Action enterDeclarationBlock(Parser p) { switch(p.tok.id) { case TOK_rcurly: case TOK_EOF: return shiftDeclarationBlock(p); default: p.pushState(&shiftDeclarationBlock); return DeclDefs.enter(p); } } static Action shiftDeclarationBlock(Parser p) { p.popAppendTopNode!(ast.ConditionalDeclaration,ast.DeclarationBlock)(); return Forward; } // $ Condition DeclarationBlock else DeclarationBlock mixin stateEnterClass!(Condition, ast.ConditionalDeclaration, shiftCondition); static Action enterAfterVersion(Parser p) { p.pushNode(new ast.ConditionalDeclaration(p.tok)); p.pushState(&enterReduce); return VersionCondition.enterAfterVersion(p); } static Action enterAfterDebug(Parser p) { p.pushNode(new ast.ConditionalDeclaration(p.tok)); p.pushState(&enterReduce); return DebugCondition.enterAfterDebug(p); } static Action enterAfterStatic(Parser p) { p.pushNode(new ast.ConditionalDeclaration(p.tok)); p.pushState(&enterReduce); return StaticIfCondition.enterAfterStatic(p); } } //-- GRAMMAR_BEGIN -- //ConditionalStatement: // Condition NoScopeNonEmptyStatement // Condition NoScopeNonEmptyStatement else NoScopeNonEmptyStatement class ConditionalStatement { // Condition $ NoScopeNonEmptyStatement else NoScopeNonEmptyStatement mixin stateAppendClass!(NoScopeNonEmptyStatement, Parser.forward) stateElseStmt; mixin stateShiftToken!(TOK_else, stateElseStmt.shift, -1, Parser.forward) stateElse; // Condition $ NoScopeNonEmptyStatement else NoScopeNonEmptyStatement mixin stateAppendClass!(NoScopeNonEmptyStatement, stateElse.shift) stateThenStmt; // $ Condition NoScopeNonEmptyStatement else NoScopeNonEmptyStatement mixin stateEnterClass!(Condition, ast.ConditionalStatement, stateThenStmt.shift); static Action enterAfterStatic(Parser p) { p.pushNode(new ast.ConditionalStatement(p.tok)); p.pushState(&enterReduce); return StaticIfCondition.enterAfterStatic(p); } } //-- GRAMMAR_BEGIN -- //Condition: // VersionCondition // DebugCondition // StaticIfCondition class Condition { static Action enter(Parser p) { switch(p.tok.id) { case TOK_version: return VersionCondition.enter(p); case TOK_debug: return DebugCondition.enter(p); case TOK_static: return StaticIfCondition.enter(p); default: return p.parseError("version, debug or static if expected"); } } } //-- GRAMMAR_BEGIN -- //VersionCondition: // version ( Integer ) // version ( Identifier ) // version ( unittest ) // version ( assert ) class VersionCondition { // version ( Integer $ ) mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen; // version ( $ Integer ) mixin stateAppendClass!(IdentifierOrInteger, stateRparen.shift) stateArgument2; static Action shiftUnittest(Parser p) { p.topNode!(ast.VersionCondition).id = TOK_unittest; return stateRparen.shift(p); } static Action shiftAssert(Parser p) { p.topNode!(ast.VersionCondition).id = TOK_assert; return stateRparen.shift(p); } mixin stateShiftToken!(TOK_unittest, shiftUnittest, TOK_assert, shiftAssert, -1, stateArgument2.shift) stateArgument; // version $ ( Integer ) mixin stateShiftToken!(TOK_lparen, stateArgument.shift) stateLparen; // $ version ( Integer ) mixin stateEnterToken!(TOK_version, ast.VersionCondition, stateLparen.shift); static Action enterAfterVersion(Parser p) { p.pushNode(new ast.VersionCondition(p.tok)); return stateLparen.shift(p); } } //-- GRAMMAR_BEGIN -- //VersionSpecification: // version = Identifier ; // version = Integer ; class VersionSpecification { mixin stateShiftToken!(TOK_semicolon, Parser.forward) stateSemi; mixin stateAppendClass!(IdentifierOrInteger, stateSemi.shift) stateArgument; mixin stateShiftToken!(TOK_assign, stateArgument.shift) stateAssign; mixin stateEnterToken!(TOK_version, ast.VersionSpecification, stateAssign.shift); static Action enterAfterVersion(Parser p) { p.pushNode(new ast.VersionSpecification(p.tok)); return stateAssign.shift(p); } } // disambiguate between DebugCondition and DebugSpecification class DebugCondOrSpec { static Action enter(Parser p) { assert(p.tok.id == TOK_debug); p.pushState(&shiftDebug); return Accept; } static Action shiftDebug(Parser p) { switch(p.tok.id) { case TOK_assign: return DebugSpecification.enterAfterDebug(p); default: return ConditionalDeclaration.enterAfterDebug(p); } } } //-- GRAMMAR_BEGIN -- //DebugCondition: // debug // debug ( Integer ) // debug ( Identifier ) class DebugCondition { // debug ( Integer $ ) mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen; // debug ( $ Integer ) mixin stateAppendClass!(IdentifierOrInteger, stateRparen.shift) stateArgument; // debug $ ( Integer ) mixin stateShiftToken!(TOK_lparen, stateArgument.shift, -1, Parser.forward) stateLparen; // $ debug ( Integer ) mixin stateEnterToken!(TOK_debug, ast.DebugCondition, stateLparen.shift); static Action enterAfterDebug(Parser p) { p.pushNode(new ast.DebugCondition(p.tok)); return stateLparen.shift(p); } } //-- GRAMMAR_BEGIN -- //DebugSpecification: // debug = Identifier ; // debug = Integer ; class DebugSpecification { // debug = Integer $ ; mixin stateShiftToken!(TOK_semicolon, Parser.forward) stateSemi; // debug = $ Integer ; mixin stateAppendClass!(IdentifierOrInteger, stateSemi.shift) stateArgument; // debug $ = Integer ; mixin stateShiftToken!(TOK_assign, stateArgument.shift) stateAssign; // $ debug = Integer ; mixin stateEnterToken!(TOK_debug, ast.DebugSpecification, stateAssign.shift); static Action enterAfterDebug(Parser p) { p.pushNode(new ast.DebugSpecification(p.tok)); return stateAssign.shift(p); } } class IdentifierOrInteger { static Action enter(Parser p) { switch(p.tok.id) { case TOK_IntegerLiteral: p.pushNode(new ast.IntegerLiteralExpression(p.tok)); return Accept; case TOK_Identifier: p.pushNode(new ast.Identifier(p.tok)); return Accept; default: return p.parseError("integer or identifier expected"); } } } //-- GRAMMAR_BEGIN -- //StaticIfCondition: // static if ( AssignExpression ) class StaticIfCondition { mixin SequenceNode!(ast.StaticIfCondition, TOK_static, TOK_if, TOK_lparen, AssignExpression, TOK_rparen); static Action enterAfterStatic(Parser p) { p.pushNode(new ast.StaticIfCondition(p.tok)); return shift1.shift(p); // jump into sequence before TOK_if } } //-- GRAMMAR_BEGIN -- //StaticAssert: // static assert ( AssignExpression ) ; // static assert ( AssignExpression , AssignExpression ) ; class StaticAssert { mixin SequenceNode!(ast.StaticAssert, TOK_static, TOK_assert, TOK_lparen, ArgumentList, TOK_rparen, TOK_semicolon); static Action enterAfterStatic(Parser p) { p.pushNode(new ast.StaticAssert(p.tok)); return shift1.shift(p); // jump into sequence before TOK_assert } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/parser/iasm.d0000664000175000017500000000745012776214756027132 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.parser.iasm; import vdc.util; import vdc.lexer; import vdc.parser.engine; import ast = vdc.ast.all; class AsmInstruction { static Action enter(Parser p) { p.pushNode(new ast.AsmInstruction(p.tok)); return shift(p); } static Action shift(Parser p) { switch(p.tok.id) { case TOK_EOF: return p.parseError("end of file in asm block"); case TOK_semicolon: case TOK_rcurly: return Forward; default: p.topNode!(ast.AsmInstruction).addToken(p.tok); p.pushState(&shift); return Accept; } } } //-- GRAMMAR_BEGIN -- //AsmInstruction: // Identifier : AsmInstruction // "align" IntegerExpression // "even" // "naked" // "db" Operands // "ds" Operands // "di" Operands // "dl" Operands // "df" Operands // "dd" Operands // "de" Operands // Opcode // Opcode Operands // //Operands: // Operand // Operand , Operands // //IntegerExpression: // IntegerLiteral // Identifier // //Operand: // AsmExp // //AsmExp: // AsmLogOrExp // AsmLogOrExp ? AsmExp : AsmExp // //AsmLogOrExp: // AsmLogAndExp // AsmLogAndExp || AsmLogAndExp // //AsmLogAndExp: // AsmOrExp // AsmOrExp && AsmOrExp // //AsmOrExp: // AsmXorExp // AsmXorExp | AsmXorExp // //AsmXorExp: // AsmAndExp // AsmAndExp ^ AsmAndExp // //AsmAndExp: // AsmEqualExp // AsmEqualExp & AsmEqualExp // //AsmEqualExp: // AsmRelExp // AsmRelExp == AsmRelExp // AsmRelExp != AsmRelExp // //AsmRelExp: // AsmShiftExp // AsmShiftExp < AsmShiftExp // AsmShiftExp <= AsmShiftExp // AsmShiftExp > AsmShiftExp // AsmShiftExp >= AsmShiftExp // //AsmShiftExp: // AsmAddExp // AsmAddExp << AsmAddExp // AsmAddExp >> AsmAddExp // AsmAddExp >>> AsmAddExp // //AsmAddExp: // AsmMulExp // AsmMulExp + AsmMulExp // AsmMulExp - AsmMulExp // //AsmMulExp: // AsmBrExp // AsmBrExp * AsmBrExp // AsmBrExp / AsmBrExp // AsmBrExp % AsmBrExp // //AsmBrExp: // AsmUnaExp // AsmBrExp [ AsmExp ] // //AsmUnaExp: // AsmTypePrefix AsmExp // "offsetof" AsmExp // "seg" AsmExp // + AsmUnaExp // - AsmUnaExp // ! AsmUnaExp // ~ AsmUnaExp // AsmPrimaryExp // //AsmPrimaryExp: // IntegerLiteral // FloatLiteral // "__LOCAL_SIZE" // $ // Register // DotIdentifier // //DotIdentifier: // Identifier // Identifier . DotIdentifier // //AsmTypePrefix: // "near" "ptr" // "far" "ptr" // byte "ptr" // short "ptr" // int "ptr" // "word" "ptr" // "dword" "ptr" // "qword" "ptr" // float "ptr" // double "ptr" // real "ptr" // //Register: // TOK_register // //Opcode: // TOK_opcode // //Identifier: // TOK_Identifier // //Integer: // IntegerLiteral // //IntegerLiteral: // TOK_IntegerLiteral // //FloatLiteral: // TOK_FloatLiteral // //StringLiteral: // TOK_StringLiteral // //CharacterLiteral: // TOK_CharacterLiteral // //// removed from grammar: //// ////Register: //// AL AH AX EAX //// BL BH BX EBX //// CL CH CX ECX //// DL DH DX EDX //// BP EBP //// SP ESP //// DI EDI //// SI ESI //// ES CS SS DS GS FS //// CR0 CR2 CR3 CR4 //// DR0 DR1 DR2 DR3 DR6 DR7 //// TR3 TR4 TR5 TR6 TR7 //// ST //// ST(0) ST(1) ST(2) ST(3) ST(4) ST(5) ST(6) ST(7) //// MM0 MM1 MM2 MM3 MM4 MM5 MM6 MM7 //// XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 //// ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/util.d0000664000175000017500000003023212776214756025654 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.util; import vdc.lexer; import std.conv; import std.string; import std.array; //////////////////////////////////////////////////////////////// // use instead of assert() to be nicely breakable and avoid the bad // semantics of assert(false) void _assert(bool cond) { if(!cond) assert(false); } //////////////////////////////////////////////////////////////// alias int TokenId; enum NumTokens = TOK_end_Operators; struct TextPos { int index; int line; int opCmp(ref const(TextPos) tp) const { if(line != tp.line) return line - tp.line; return index - tp.index; } } struct TextSpan { TextPos start; TextPos end; } // returns < 0 if adr1 < adr2 int compareTextSpanAddress(int line1, int index1, int line2, int index2) { int difflines = line1 - line2; if(difflines != 0) return difflines; return index1 - index2; } bool textSpanContains(ref const(TextSpan) span, int line, int index) { return compareTextSpanAddress(span.start.line, span.start.index, line, index) <= 0 && compareTextSpanAddress(span.end.line, span.end.index, line, index) > 0; } class Token { TokenId id; // terminals and non-terminals string txt; TextSpan span; void copy(const(Token) tok) { id = tok.id; txt = tok.txt; span = tok.span; } } //////////////////////////////////////////////////////////////// string genFlagsEnum(string name, string prefix, string[] allMembers) { string s = "enum " ~ name ~ " { "; foreach(i, c; allMembers) s ~= prefix ~ c ~ " = 1 << " ~ to!string(i) ~ ", "; s ~= "}"; return s; } // Attribute also used for storage class enum AttrBits { Extern, Synchronized, Static, Final, Abstract, Const, Auto, Scope, Ref, Volatile, Gshared, Thread, Shared, Immutable, Pure, Nothrow, Inout, ExternC, ExternCPP, ExternD, ExternWindows, ExternPascal, ExternSystem, Export, Align, Align1, Align2, Align4, Align8, Align16, } mixin(genFlagsEnum("", "Attr_", [__traits(allMembers,AttrBits)])); enum Attr_AlignMask = Attr_Align | Attr_Align1 | Attr_Align2 | Attr_Align4 | Attr_Align8 | Attr_Align16; enum Attr_CallMask = Attr_ExternC | Attr_ExternCPP | Attr_ExternD | Attr_ExternWindows | Attr_ExternPascal | Attr_ExternSystem; enum Attr_ShareMask = Attr_Shared | Attr_Gshared | Attr_Thread; alias uint Attribute; Attribute tokenToAttribute(TokenId tok) { switch(tok) { case TOK_extern: return Attr_Extern; case TOK_synchronized: return Attr_Synchronized; case TOK_static: return Attr_Static; case TOK_final: return Attr_Final; case TOK_abstract: return Attr_Abstract; case TOK_const: return Attr_Const; case TOK_auto: return Attr_Auto; case TOK_scope: return Attr_Scope; case TOK_ref: return Attr_Ref; case TOK_volatile: return Attr_Volatile; case TOK___gshared: return Attr_Gshared; case TOK___thread: return Attr_Thread; case TOK_shared: return Attr_Shared; case TOK_immutable: return Attr_Immutable; case TOK_pure: return Attr_Pure; case TOK_nothrow: return Attr_Nothrow; case TOK_inout: return Attr_Inout; case TOK_export: return Attr_Export; case TOK_align: return Attr_Align; default: return 0; } } TokenId attributeToToken(Attribute attr) { switch(attr) { case Attr_Extern: return TOK_extern; case Attr_Synchronized: return TOK_synchronized; case Attr_Static: return TOK_static; case Attr_Final: return TOK_final; case Attr_Abstract: return TOK_abstract; case Attr_Const: return TOK_const; case Attr_Auto: return TOK_auto; case Attr_Scope: return TOK_scope; case Attr_Ref: return TOK_ref; case Attr_Volatile: return TOK_volatile; case Attr_Gshared: return TOK___gshared; case Attr_Thread: return TOK___thread; case Attr_Shared: return TOK_shared; case Attr_Immutable: return TOK_immutable; case Attr_Pure: return TOK_pure; case Attr_Nothrow: return TOK_nothrow; case Attr_Inout: return TOK_inout; case Attr_Export: return TOK_export; case Attr_Align: return TOK_align; default: return -1; } } Attribute combineAttributes(Attribute attr, Attribute newAttr) { if(newAttr & Attr_AlignMask) attr &= ~Attr_AlignMask; if(newAttr & Attr_CallMask) attr &= ~Attr_CallMask; if(newAttr & Attr_ShareMask) attr &= ~Attr_ShareMask; return attr | newAttr; } string attrToString(Attribute attr) { switch(attr) { case Attr_Extern: return "extern"; case Attr_Synchronized: return "synchronized"; case Attr_Static: return "static"; case Attr_Final: return "final"; case Attr_Abstract: return "abstract"; case Attr_Const: return "const"; case Attr_Auto: return "auto"; case Attr_Scope: return "scope"; case Attr_Ref: return "ref"; case Attr_Volatile: return "volatile"; case Attr_Gshared: return "__gshared"; case Attr_Thread: return "__thread"; case Attr_Shared: return "shared"; case Attr_Immutable: return "immutable"; case Attr_Pure: return "pure"; case Attr_Nothrow: return "nothrow"; case Attr_Inout: return "inout"; case Attr_ExternC: return "extern(C)"; case Attr_ExternCPP: return "extern(C++)"; case Attr_ExternD: return "extern(D)"; case Attr_ExternWindows: return "extern(Windows)"; case Attr_ExternPascal: return "extern(Pascal)"; case Attr_ExternSystem: return "extern(System)"; case Attr_Export: return "export"; case Attr_Align: return "align"; case Attr_Align1: return "align(1)"; case Attr_Align2: return "align(2)"; case Attr_Align4: return "align(4)"; case Attr_Align8: return "align(8)"; case Attr_Align16: return "align(16)"; default: assert(false); } } string attrToStringC(Attribute attr) { // Compiler-Specific switch(attr) { case Attr_Extern: return "extern"; case Attr_Synchronized: return ""; case Attr_Static: return "static"; case Attr_Final: return ""; case Attr_Abstract: return ""; case Attr_Const: return "const"; case Attr_Auto: return "auto"; case Attr_Scope: return "scope"; case Attr_Ref: return "ref"; case Attr_Volatile: return "volatile"; case Attr_Gshared: return ""; case Attr_Thread: return "__declspec(thread)"; case Attr_Shared: return "shared"; case Attr_Immutable: return "const"; case Attr_Pure: return ""; case Attr_Nothrow: return ""; case Attr_Inout: return ""; case Attr_ExternC: return "extern \"C\""; case Attr_ExternCPP: return ""; case Attr_ExternD: return ""; case Attr_ExternWindows: return "__stdcall"; case Attr_ExternPascal: return "__pascal"; case Attr_ExternSystem: return "__stdcall"; case Attr_Export: return "__declspec(dllexport)"; case Attr_Align: return "__declspec(align(4))"; case Attr_Align1: return "__declspec(align(1))"; case Attr_Align2: return "__declspec(align(2))"; case Attr_Align4: return "__declspec(align(4))"; case Attr_Align8: return "__declspec(align(8))"; case Attr_Align16: return "__declspec(align(16))"; default: assert(false); } } //////////////////////////////////////////////////////////////// enum AnnotationBits { Deprecated, Override, Private, Package, Protected, Nogc, Public, Export, Disable, Property, Safe, System, Trusted, } mixin(genFlagsEnum("", "Annotation_", [__traits(allMembers,AnnotationBits)])); alias uint Annotation; enum Annotation_ProtectionMask = Annotation_Private | Annotation_Protected | Annotation_Public | Annotation_Package; enum Annotation_SafeMask = Annotation_Safe | Annotation_System | Annotation_Trusted; Annotation tokenToAnnotation(TokenId tok) { switch(tok) { case TOK_deprecated: return Annotation_Deprecated; case TOK_override: return Annotation_Override; case TOK_disable: return Annotation_Disable; case TOK_property: return Annotation_Property; case TOK_nogc: return Annotation_Nogc; case TOK_safe: return Annotation_Safe; case TOK_system: return Annotation_System; case TOK_trusted: return Annotation_Trusted; default: return 0; } } Annotation tokenToProtection(TokenId tok) { switch(tok) { case TOK_private: return Annotation_Private; case TOK_package: return Annotation_Package; case TOK_protected: return Annotation_Protected; case TOK_public: return Annotation_Public; case TOK_export: return Annotation_Export; default: return 0; } } Annotation combineAnnotations(Annotation annot, Annotation newAnnot) { if(newAnnot & Annotation_ProtectionMask) annot &= ~Annotation_ProtectionMask; if(newAnnot & Annotation_SafeMask) annot &= ~Annotation_SafeMask; return annot | newAnnot; } string annotationToString(Annotation annot) { switch(annot) { case Annotation_Deprecated:return "deprecated"; case Annotation_Override: return "override"; case Annotation_Disable: return "@disable"; case Annotation_Property: return "@property"; case Annotation_Nogc: return "@nogc"; case Annotation_Safe: return "@safe"; case Annotation_System: return "@system"; case Annotation_Trusted: return "@trusted"; case Annotation_Private: return "private"; case Annotation_Package: return "package"; case Annotation_Protected: return "protected"; case Annotation_Public: return "public"; case Annotation_Export: return "export"; default: assert(false); } } //////////////////////////////////////////////////////////////// string _mixinGetClasses(allMembers...)() { string s; foreach(c; allMembers) s ~= "if(is(" ~ c ~ " == class)) classes ~= `" ~ c ~ "`;"; return s; } string[] getClasses(allMembers...)() { string[] classes; mixin(_mixinGetClasses!(allMembers)); return classes; } string genClassEnum(allMembers...)(string name, string prefix, int off) { string[] classes = getClasses!allMembers(); string s = "enum " ~ name ~ " { "; bool first = true; foreach(c; classes) { if(first) s ~= prefix ~ c ~ " = " ~ to!string(off) ~ ", "; else s ~= prefix ~ c ~ ", "; first = false; } if(prefix.length > 0) s ~= prefix ~ "end"; s ~= " }"; return s; } version(none) mixin(genClassEnum!(__traits(allMembers,vdc.parser.expr), __traits(allMembers,vdc.parser.decl), __traits(allMembers,vdc.parser.stmt), __traits(allMembers,vdc.parser.mod), __traits(allMembers,vdc.parser.aggr), __traits(allMembers,vdc.parser.misc))("", "NT_", TOK_end_Operators)); ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/interpret.d0000664000175000017500000016332112776214756026721 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt // // Interpretation passes around a context, holding the current variable stack // class Context { Scope sc; Value[Node] vars; Context parent; } // // static shared values are not looked up in the context // thread local static values are looked up in a global thread context // non-static values are looked up in the current context // // member/field lookup in aggregates uses an instance specific Context // // when entering a scope, a new Context is created with the current // Context as parent // when leaving a scope, the context is destroyed together with scoped values // created within the lifetime of the context // a delegate value saves the current context to be used when calling the delegate // // local functions are called with the context of the enclosing function // member functions are called with the context of the instance // static or global functions are called with the thread context // module vdc.interpret; import vdc.util; import vdc.semantic; import vdc.lexer; import vdc.logger; import vdc.ast.decl; import vdc.ast.type; import vdc.ast.aggr; import vdc.ast.expr; import vdc.ast.node; import vdc.ast.writer; import stdext.util; import stdext.string; import std.variant; import std.conv; import std.typetuple; import std.string; import std.utf; import std.traits; template Singleton(T, ARGS...) { T get() { static T instance; if(!instance) instance = new T(ARGS); return instance; } } class Value { bool mutable = true; bool literal = false; debug string sval; debug string ident; static T _create(T, V)(V val) { T v = new T; *v.pval = val; debug v.sval = v.toStr(); return v; } static Value create(bool v) { return _create!BoolValue (v); } static Value create(byte v) { return _create!ByteValue (v); } static Value create(ubyte v) { return _create!UByteValue (v); } static Value create(short v) { return _create!ShortValue (v); } static Value create(ushort v) { return _create!UShortValue (v); } static Value create(int v) { return _create!IntValue (v); } static Value create(uint v) { return _create!UIntValue (v); } static Value create(long v) { return _create!LongValue (v); } static Value create(ulong v) { return _create!ULongValue (v); } static Value create(char v) { return _create!CharValue (v); } static Value create(wchar v) { return _create!WCharValue (v); } static Value create(dchar v) { return _create!DCharValue (v); } static Value create(float v) { return _create!FloatValue (v); } static Value create(double v) { return _create!DoubleValue (v); } static Value create(real v) { return _create!RealValue (v); } static Value create(ifloat v) { return _create!IFloatValue (v); } static Value create(idouble v) { return _create!IDoubleValue(v); } static Value create(ireal v) { return _create!IRealValue (v); } static Value create(cfloat v) { return _create!CFloatValue (v); } static Value create(cdouble v) { return _create!CDoubleValue(v); } static Value create(creal v) { return _create!CRealValue (v); } static Value create(string v) { return createStringValue (v); } Type getType() { semanticError("cannot get type of ", this); return Singleton!(ErrorType).get(); } bool toBool() { semanticError("cannot convert ", this, " to bool"); return false; } int toInt() { long lng = toLong(); return cast(int) lng; } long toLong() { semanticError("cannot convert ", this, " to integer"); return 0; } void setLong(long lng) { semanticError("cannot convert long to ", this); } string toStr() { semanticError("cannot convert ", this, " to string"); return ""; } string toMixin() { semanticError("cannot convert ", this, " to mixin"); return ""; } Value getElement(size_t idx) { return semanticErrorValue("cannot get ", idx, ". element of array of ", this); } void setElements(size_t oldcnt, size_t newcnt) { semanticError("cannot set no of elements of array of ", this); } PointerValue toPointer(TypePointer to) { return null; } final void validate() { debug sval = toStr(); } //override string toString() //{ // return text(getType(), ":", toStr()); //} version(all) Value opBin(Context ctx, int tokid, Value v) { return semanticErrorValue("cannot calculate ", this, " ", tokenString(tokid), " ", v); //return semanticErrorValue("binary operator ", tokenString(tokid), " on ", this, " not implemented"); } Value opBin_r(Context ctx, int tokid, Value v) { return semanticErrorValue("cannot calculate ", v, " ", tokenString(tokid), " ", this); //return semanticErrorValue("binary operator ", tokenString(tokid), " on ", this, " not implemented"); } Value opUn(Context ctx, int tokid) { switch(tokid) { case TOK_and: return opRefPointer(); case TOK_mul: return opDerefPointer(); default: break; } return semanticErrorValue("unary operator ", tokenString(tokid), " on ", this, " not implemented"); } Value opRefPointer() { auto tp = new TypePointer(); tp.setNextType(getType()); //addMember(getType().clone()); return PointerValue._create(tp, this); } Value opDerefPointer() { return semanticErrorValue("cannot dereference a ", this); } @disable final Value interpretProperty(Context ctx, string prop) { if(Value v = _interpretProperty(ctx, prop)) return v; return semanticErrorValue("cannot calculate property ", prop, " of value ", toStr()); } @disable Value _interpretProperty(Context ctx, string prop) { return getType()._interpretProperty(ctx, prop); } Value doCast(Value v) { return semanticErrorValue("cannot cast a ", v, " to ", this); } Value opIndex(Value v) { return semanticErrorValue("cannot index a ", this); } Value opSlice(Value b, Value e) { return semanticErrorValue("cannot slice a ", this); } Value opCall(Context sc, Value args) { return semanticErrorValue("cannot call a ", this); } //mixin template operators() version(none) Value opassign(string op)(Value v) { TypeInfo ti1 = this.classinfo; TypeInfo ti2 = v.classinfo; foreach(iv1; BasicTypeValues) { if(ti1 is typeid(iv1)) { foreach(iv2; BasicTypeValues) { if(ti2 is typeid(iv2)) static if (__traits(compiles, { iv1.ValType x; iv2.ValType y; mixin("x " ~ op ~ "y;"); })) { iv2.ValType v2 = (cast(iv2) v).val; static if(op == "/=" || op == "%=") if(v2 == 0) return semanticErrorValue("division by zero"); mixin("(cast(iv1) this).val " ~ op ~ "v2;"); return this; } } } } return semanticErrorValue("cannot execute ", op, " on a ", v, " with a ", this); } version(none) Value opBinOp(string op)(Value v) { TypeInfo ti1 = this.classinfo; TypeInfo ti2 = v.classinfo; foreach(iv1; BasicTypeValues) { if(ti1 is typeid(iv1)) { foreach(iv2; BasicTypeValues) { if(ti2 is typeid(iv2)) { static if (__traits(compiles, { iv1.ValType x; iv2.ValType y; mixin("auto z = x " ~ op ~ "y;"); })) { iv1.ValType v1 = (cast(iv1) this).val; iv2.ValType v2 = (cast(iv2) v).val; static if(op == "/" || op == "%") if(v2 == 0) return semanticErrorValue("division by zero"); mixin("auto z = v1 " ~ op ~ "v2;"); return create(z); } else { return semanticErrorValue("cannot calculate ", op, " on a ", this, " and a ", v); } } } } } return semanticErrorValue("cannot calculate ", op, " on a ", this, " and a ", v); } version(none) Value opUnOp(string op)() { TypeInfo ti1 = this.classinfo; foreach(iv1; BasicTypeValues) { if(ti1 is typeid(iv1)) { static if (__traits(compiles, { iv1.ValType x; mixin("auto z = " ~ op ~ "x;"); })) { mixin("auto z = " ~ op ~ "(cast(iv1) this).val;"); return create(z); } } } return semanticErrorValue("cannot calculate ", op, " on a ", this); } //////////////////////////////////////////////////////////// mixin template mixinBinaryOp1(string op, iv2) { Value binOp1(Value v) { if(auto vv = cast(iv2) v) { iv2.ValType v2 = *vv.pval; static if(op == "/" || op == "%") if(v2 == 0) return semanticErrorValue("division by zero"); mixin("auto z = *pval " ~ op ~ "v2;"); return create(z); } return semanticErrorValue("cannot calculate ", op, " on ", this, " and ", v); } } mixin template mixinBinaryOp(string op, Types...) { Value binOp(Value v) { TypeInfo ti = v.classinfo; foreach(iv2; Types) { if(ti is typeid(iv2)) { static if (__traits(compiles, { iv2.ValType y; mixin("auto z = (*pval) " ~ op ~ " y;"); })) { iv2.ValType v2 = *(cast(iv2) v).pval; static if(op == "/" || op == "%") if(v2 == 0) return semanticErrorValue("division by zero"); static if(op == "^^" && isIntegral!(ValType) && isIntegral!(iv2.ValType)) if(v2 < 0) return semanticErrorValue("integer pow with negative exponent"); mixin("auto z = (*pval) " ~ op ~ " v2;"); return create(z); } else break; } } return semanticErrorValue("cannot calculate ", op, " on a ", this, " and a ", v); } } mixin template mixinAssignOp(string op, Types...) { Value assOp(Value v) { if(!mutable) return semanticErrorValue(this, " value is not mutable"); TypeInfo ti = v.classinfo; foreach(iv2; Types) { if(ti is typeid(iv2)) { static if (__traits(compiles, { iv2.ValType y; mixin("*pval " ~ op ~ " y;"); })) { iv2.ValType v2 = *(cast(iv2) v).pval; static if(op == "/=" || op == "%=") if(v2 == 0) return semanticErrorValue("division by zero"); static if(op == "%=" && (is(T == float) || is(T == double) || is(T == real))) // compiler bug mixin("*pval = *pval % v2;"); else mixin("*pval " ~ op ~ " v2;"); debug logInfo("value %s changed by %s to %s", ident, op, toStr()); debug sval = toStr(); return this; } else break; } } return semanticErrorValue("cannot assign ", op, " a ", v, " to a ", this); } } } T createInitValue(T)(Context ctx, Value initValue) { T v = new T; if(initValue) v.opBin(ctx, TOK_assign, initValue); return v; } alias TypeTuple!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, char, wchar, dchar, float, double, real, ifloat, idouble, ireal, cfloat, cdouble, creal) BasicTypes; alias TypeTuple!(BoolValue, ByteValue, UByteValue, ShortValue, UShortValue, IntValue, UIntValue, LongValue, ULongValue, CharValue, WCharValue, DCharValue, FloatValue, DoubleValue, RealValue, IFloatValue, IDoubleValue, IRealValue, CFloatValue, CDoubleValue, CRealValue) BasicTypeValues; alias TypeTuple!(BasicTypeValues, SetLengthValue) RHS_BasicTypeValues; alias TypeTuple!(TOK_bool, TOK_byte, TOK_ubyte, TOK_short, TOK_ushort, TOK_int, TOK_uint, TOK_long, TOK_ulong, TOK_char, TOK_wchar, TOK_dchar, TOK_float, TOK_double, TOK_real, TOK_ifloat, TOK_idouble, TOK_ireal, TOK_cfloat, TOK_cdouble, TOK_creal) BasicTypeTokens; int BasicType2Token(T)() { return BasicTypeTokens[staticIndexOf!(T, BasicTypes)]; } template BasicType2ValueType(T) { alias BasicTypeValues[staticIndexOf!(T, BasicTypes)] BasicType2ValueType; } template Token2BasicType(int tok) { alias BasicTypes[staticIndexOf!(tok, BasicTypeTokens)] Token2BasicType; } template Token2ValueType(int tok) { alias BasicTypeValues[staticIndexOf!(tok, BasicTypeTokens)] Token2ValueType; } class ValueT(T) : Value { alias T ValType; ValType* pval; this() { pval = (new ValType[1]).ptr; debug sval = toStr(); } static int getTypeIndex() { return staticIndexOf!(ValType, BasicTypes); } override Type getType() { static Type instance; if(!instance) instance = createBasicType(BasicTypeTokens[getTypeIndex()]); return instance; } override string toStr() { return to!string(*pval); } override Value getElement(size_t idx) { alias BasicTypeValues[getTypeIndex()] ValueType; auto v = new ValueType; v.pval = pval + idx; debug v.sval = v.toStr(); return v; } override void setElements(size_t oldcnt, size_t newcnt) { ValType[] arr = pval[0 .. oldcnt]; arr.length = newcnt; pval = arr.ptr; debug sval = toStr(); } // pragma(msg, ValType); // pragma(msg, text(" compiles?", __traits(compiles, val ? true : false ))); // pragma(msg, "toBool " ~ ValType.stringof ~ (__traits(compiles, *pval ? true : false) ? " compiles" : " fails")); static if(__traits(compiles, *pval ? true : false)) override bool toBool() { return *pval ? true : false; } // pragma(msg, "toLong " ~ ValType.stringof ~ (__traits(compiles, function long () { ValType v; return v; }) ? " compiles" : " fails")); static if(__traits(compiles, function long () { ValType v; return v; } )) override long toLong() { return *pval; } //////////////////////////////////////////////////////////// static string genMixinBinOpAll() { string s; for(int i = TOK_binaryOperatorFirst; i <= TOK_binaryOperatorLast; i++) { static if(!supportUnorderedCompareOps) if(i >= TOK_unorderedOperatorFirst && i <= TOK_unorderedOperatorLast) continue; if(i >= TOK_assignOperatorFirst && i <= TOK_assignOperatorLast) s ~= text("mixin mixinAssignOp!(\"", tokenString(i), "\", RHS_BasicTypeValues) ass_", operatorName(i), ";\n"); else s ~= text("mixin mixinBinaryOp!(\"", tokenString(i), "\", RHS_BasicTypeValues) bin_", operatorName(i), ";\n"); } return s; } mixin(genMixinBinOpAll()); mixin mixinBinaryOp!("is", RHS_BasicTypeValues) bin_is; static string genBinOpCases() { string s; for(int i = TOK_binaryOperatorFirst; i <= TOK_binaryOperatorLast; i++) { static if(!supportUnorderedCompareOps) if(i >= TOK_unorderedOperatorFirst && i <= TOK_unorderedOperatorLast) continue; if(i >= TOK_assignOperatorFirst && i <= TOK_assignOperatorLast) s ~= text("case ", i, ": return ass_", operatorName(i), ".assOp(v);\n"); else s ~= text("case ", i, ": return bin_", operatorName(i), ".binOp(v);\n"); } return s; } override Value opBin(Context ctx, int tokid, Value v) { switch(tokid) { mixin(genBinOpCases()); case TOK_is: return bin_is.binOp(v); default: break; } return semanticErrorValue("cannot calculate '", tokenString(tokid), "' on a ", this, " and a ", v); } //////////////////////////////////////////////////////////// mixin template mixinUnaryOp(string op) { Value unOp() { static if (__traits(compiles, { mixin("auto z = " ~ op ~ "(*pval);"); })) { mixin("auto z = " ~ op ~ "(*pval);"); return create(z); } else { return semanticErrorValue("cannot calculate '", op, "' on a ", this); } } } enum int[] unOps = [ TOK_plusplus, TOK_minusminus, TOK_min, TOK_add, TOK_not, TOK_tilde ]; static string genMixinUnOpAll() { string s; foreach(id; unOps) s ~= text("mixin mixinUnaryOp!(\"", tokenString(id), "\") un_", operatorName(id), ";\n"); return s; } mixin(genMixinUnOpAll()); static string genUnOpCases() { string s; foreach(id; unOps) s ~= text("case ", id, ": return un_", operatorName(id), ".unOp();\n"); return s; } override Value opUn(Context ctx, int tokid) { switch(tokid) { case TOK_and: return opRefPointer(); case TOK_mul: return opDerefPointer(); mixin(genUnOpCases()); default: break; } return semanticErrorValue("cannot calculate '", tokenString(tokid), "' on a ", this); } override Value doCast(Value v) { if(!mutable) // doCast changes this value return semanticErrorValue(this, " value is not mutable"); TypeInfo ti = v.classinfo; foreach(iv2; RHS_BasicTypeValues) { if(ti is typeid(iv2)) { static if (__traits(compiles, { iv2.ValType y; *pval = cast(ValType)(y); })) { iv2.ValType v2 = *(cast(iv2) v).pval; *pval = cast(ValType)(v2); debug logInfo("value %s changed by cast(" ~ ValType.stringof ~ ") to %s", ident, toStr()); debug sval = toStr(); return this; } else break; } } return super.doCast(v); } } class VoidValue : Value { override string toStr() { return "void"; } } VoidValue _theVoidValue; @property VoidValue theVoidValue() { if(!_theVoidValue) { _theVoidValue = new VoidValue; _theVoidValue.mutable = false; } return _theVoidValue; } class ErrorValue : Value { override string toStr() { return "_error_"; } override Type getType() { return Singleton!ErrorType.get(); } } class NullValue : Value { override string toStr() { return "null"; } override Type getType() { return Singleton!NullType.get(); } } class BoolValue : ValueT!bool { } class ByteValue : ValueT!byte { } class UByteValue : ValueT!ubyte { } class ShortValue : ValueT!short { } class UShortValue : ValueT!ushort { } class IntValue : ValueT!int { } class UIntValue : ValueT!uint { } class LongValue : ValueT!long { } class ULongValue : ValueT!ulong { } class CharValue : ValueT!char { override string toStr() { return "'" ~ toUTF8Safe(pval[0..1]) ~ "'"; } } class WCharValue : ValueT!wchar { override string toStr() { return "'" ~ toUTF8Safe(pval[0..1]) ~ "'w"; } } class DCharValue : ValueT!dchar { override string toStr() { return "'" ~ toUTF8Safe(pval[0..1]) ~ "'d"; } } class FloatValue : ValueT!float { } class DoubleValue : ValueT!double { } class RealValue : ValueT!real { } class IFloatValue : ValueT!ifloat { } class IDoubleValue : ValueT!idouble { } class IRealValue : ValueT!ireal { } class CFloatValue : ValueT!cfloat { } class CDoubleValue : ValueT!cdouble { } class CRealValue : ValueT!creal { } class ArrayValueBase : Value { Value first; size_t len; override string toStr() { string s = "["; for(size_t i = 0; i < len; i++) { if(i > 0) s ~= ","; Value v = first.getElement(i); s ~= v.toStr(); } s ~= "]"; return s; } override Value opIndex(Value v) { int idx = v.toInt(); if(idx < 0 || idx >= len) return semanticErrorValue("index ", idx, " out of bounds on value tuple"); return first.getElement(idx); } void setItem(Context ctx, size_t idx, Value v) { if(idx < 0 || idx >= len) return semanticError("index ", idx, " out of bounds on dynamic array"); first.getElement(idx).opBin(ctx, TOK_assign, v); } ArrayValueBase createResultArray(Context ctx, Value fv, size_t nlen) { auto dim = new IntegerLiteralExpression(); dim.txt = to!string(nlen); dim.value = nlen; auto ntype = new TypeStaticArray; ntype.addMember(fv.getType().clone()); ntype.addMember(dim); auto narr = static_cast!ArrayValueBase(ntype.createValue(ctx, null)); narr.first.getElement(0).opBin(ctx, TOK_assign, fv); return narr; } private Value getItem(size_t idx) { return first.getElement(idx); } static Value _opBin(Context ctx, int tokid, Value v1, Value v2, bool reverse) { if(reverse) return v2.opBin(ctx, tokid, v1); return v1.opBin(ctx, tokid, v2); } Value _opBin(Context ctx, int tokid, Value v, bool reverse) { switch(tokid) { case TOK_equal: case TOK_lt: case TOK_le: case TOK_gt: case TOK_ge: static if(supportUnorderedCompareOps) { case TOK_unord: case TOK_ue: case TOK_lg: case TOK_leg: case TOK_ule: case TOK_ul: case TOK_uge: case TOK_ug: } //case TOK_notcontains: //case TOK_notidentity: //case TOK_is: //case TOK_in: if(auto tv = cast(ArrayValueBase) v) { if(tv.len != len) return Value.create(false); for(int i = 0; i < len; i++) if(!_opBin(ctx, tokid, first.getElement(i), tv.first.getElement(i), reverse).toBool()) return Value.create(false); return Value.create(true); } for(int i = 0; i < len; i++) if(!_opBin(ctx, tokid, first.getElement(i), v, reverse).toBool()) return Value.create(false); return Value.create(true); case TOK_notequal: return Value.create(!opBin(ctx, TOK_equal, v).toBool()); case TOK_add: case TOK_min: case TOK_mul: case TOK_div: case TOK_mod: case TOK_pow: case TOK_shl: case TOK_shr: case TOK_ushr: case TOK_xor: case TOK_or: case TOK_and: //case TOK_cat: if(auto tv = cast(ArrayValueBase) v) { if(tv.len != len) return semanticErrorValue(tokenString(tokid), " on arrays of different length ", len, " and ", tv.len); if(len == 0) return getType().createValue(ctx, null); Value fv = _opBin(ctx, tokid, first.getElement(0), tv.first.getElement(0), reverse); auto narr = createResultArray(ctx, fv, len); for(int i = 1; i < len; i++) { fv = _opBin(ctx, tokid, first.getElement(i), tv.first.getElement(i), reverse); narr.first.getElement(i).opBin(ctx, TOK_assign, fv); } debug narr.sval = narr.toStr(); return narr; } if(len == 0) return getType().createValue(ctx, null); Value fv = _opBin(ctx, tokid, first.getElement(0), v, reverse); auto narr = createResultArray(ctx, fv, len); for(int i = 1; i < len; i++) { fv = _opBin(ctx, tokid, first.getElement(i), v, reverse); narr.first.getElement(i).opBin(ctx, TOK_assign, fv); } debug narr.sval = narr.toStr(); return narr; default: if(reverse) return super.opBin_r(ctx, tokid, v); return super.opBin(ctx, tokid, v); } } override Value opBin(Context ctx, int tokid, Value v) { switch(tokid) { case TOK_addass: case TOK_minass: case TOK_mulass: case TOK_divass: case TOK_modass: case TOK_powass: case TOK_shlass: case TOK_shrass: case TOK_ushrass: case TOK_xorass: case TOK_orass: case TOK_andass: //case TOK_catass: if(auto tv = cast(ArrayValueBase) v) { if(tv.len != len) return semanticErrorValue(tokenString(tokid), " on arrays of different length ", len, " and ", tv.len); for(int i = 0; i < len; i++) first.getElement(i).opBin(ctx, tokid, tv.first.getElement(i)); } else { for(int i = 0; i < len; i++) first.getElement(i).opBin(ctx, tokid, v); } debug sval = toStr(); return this; default: return _opBin(ctx, tokid, v, false); } } override Value opBin_r(Context ctx, int tokid, Value v) { return _opBin(ctx, tokid, v, true); } override Value opUn(Context ctx, int tokid) { switch(tokid) { case TOK_add: case TOK_min: case TOK_not: case TOK_tilde: if(len == 0) return getType().createValue(ctx, null); Value fv = first.getElement(0).opUn(ctx, tokid); auto narr = createResultArray(ctx, fv, len); for(int i = 1; i < len; i++) { fv = first.getElement(i).opUn(ctx, tokid); narr.first.getElement(i).opBin(ctx, TOK_assign, fv); } return narr; default: return super.opUn(ctx, tokid); } } } class ArrayValue(T) : ArrayValueBase { T type; void setLength(Context ctx, size_t newlen) { if(newlen > len) { if(len == 0) { first = type.getNextType().createValue(ctx, null); first.setElements(1, newlen); } else first.setElements(len, newlen); } len = newlen; // intermediate state, cannot set sval yet } override Value opSlice(Value b, Value e) { int idxb = b.toInt(); int idxe = e.toInt(); if(idxb < 0 || idxb > len || idxe < idxb || idxe > len) return semanticErrorValue("slice [", idxb, "..", idxe, "] out of bounds on value ", toStr()); auto nv = type.opSlice(idxb, idxe).createValue(nullContext, null); if(auto arr = cast(ArrayValueBase) nv) { if(idxb == 0) arr.first = first; else arr.first = first.getElement(idxb); arr.len = idxe - idxb; } debug nv.sval = nv.toStr(); return nv; } } class DynArrayValue : ArrayValue!TypeDynamicArray { this(TypeDynamicArray t) { type = t; debug sval = toStr(); } override string toStr() { if(isString()) return "\"" ~ toMixin() ~ "\""; return super.toStr(); } override Type getType() { return type; } override Value opBin(Context ctx, int tokid, Value v) { switch(tokid) { case TOK_assign: if(auto tv = cast(ArrayValueBase) v) { if(tv.len == 0) first = null; else first = tv.first.getElement(0); // create copy of "ptr" value len = tv.len; } else if(cast(NullValue) v) { first = null; len = 0; } else return semanticErrorValue("cannot assign ", v, " to ", this); debug sval = toStr(); return this; case TOK_tilde: if(auto ev = cast(ErrorValue) v) return v; auto nv = new DynArrayValue(type); if(auto tv = cast(DynArrayValue) v) { nv.setLength(ctx, len + tv.len); for(size_t i = 0; i < len; i++) nv.setItem(ctx, i, getItem(i)); for(size_t i = 0; i < tv.len; i++) nv.setItem(ctx, len + i, tv.getItem(i)); } else { nv.setLength(ctx, len + 1); for(size_t i = 0; i < len; i++) nv.setItem(ctx, i, getItem(i)); nv.setItem(ctx, len, v); } debug nv.sval = nv.toStr(); return nv; case TOK_catass: size_t oldlen = len; if(auto ev = cast(ErrorValue) v) return v; if(auto tv = cast(DynArrayValue) v) { setLength(ctx, len + tv.len); for(size_t i = 0; i < tv.len; i++) setItem(ctx, oldlen + i, tv.getItem(i)); } else { setLength(ctx, len + 1); setItem(ctx, oldlen, v); } debug sval = toStr(); return this; default: return super.opBin(ctx, tokid, v); } } bool isString() { auto t = type.getNextType().unqualified(); if(auto bt = cast(BasicType) t) if(bt.id == TOK_char || bt.id == TOK_wchar || bt.id == TOK_dchar) return true; return false; } override PointerValue toPointer(TypePointer to) { // TODO: implementation here just to satisfy string -> C const char* conversion if(isString()) { Value nfirst = first; auto nt = type.getNextType(); auto nto = to.getNextType(); if(literal) { // automatic conversion between string,wstring,dstring auto uto = nto.unqualified(); auto ut = nt.unqualified(); if(auto bt = cast(BasicType) ut) if(auto bto = cast(BasicType) uto) { if(bt.id != bto.id) { semanticErrorValue("literal string conversion not implemented!"); DynArrayValue nv; switch(bto.id) { case TOK_char: string s; switch(bt.id) { case TOK_wchar: case TOK_dchar: default: break; } nv = createStringValue(s); break; case TOK_wchar: wstring s; switch(bt.id) { case TOK_char: case TOK_dchar: default: break; } nv = createStringValue(s); break; case TOK_dchar: dstring s; switch(bt.id) { case TOK_char: case TOK_wchar: default: break; } nv = createStringValue(s); break; default: assert(0); } nfirst = nv.first; } } } PointerValue pv = new PointerValue; auto tp = new TypePointer; tp.setNextType(nto); pv.type = tp; pv.pval = nfirst; debug pv.sval = pv.toStr(); return pv; } return super.toPointer(to); } override string toMixin() { if(isString()) { if(len == 0) return ""; if(auto cv = cast(CharValue)first) return toUTF8Safe(cv.pval[0..len]); if(auto wv = cast(WCharValue)first) return toUTF8Safe(wv.pval[0..len]); if(auto dv = cast(DCharValue)first) return toUTF8Safe(dv.pval[0..len]); } return super.toMixin(); } @disable override Value _interpretProperty(Context ctx, string prop) { switch(prop) { case "length": return new SetLengthValue(this); default: return super._interpretProperty(ctx, prop); } } } class SetLengthValue : UIntValue { DynArrayValue array; this(DynArrayValue a) { array = a; super(); debug sval = toStr(); } override string toStr() { return array.toStr() ~ ".length"; } override Value opBin(Context ctx, int tokid, Value v) { switch(tokid) { case TOK_assign: int len = v.toInt(); array.setLength(ctx, len); debug array.sval = array.toStr(); return this; default: return super.opBin(ctx, tokid, v); } } } DynArrayValue createStringValue(C)(immutable(C)[] s) { DynArrayValue dav = new DynArrayValue(getTypeString!C()); auto cv = new BasicType2ValueType!C; cv.mutable = false; cv.pval = cast(C*) s.ptr; debug cv.sval = cv.toStr(); dav.first = cv; dav.len = s.length; dav.literal = true; debug dav.sval = dav.toStr(); return dav; } class StaticArrayValue : ArrayValue!TypeStaticArray { this(TypeStaticArray t) { type = t; debug sval = toStr(); } override Type getType() { return type; } override Value opBin(Context ctx, int tokid, Value v) { switch(tokid) { case TOK_assign: if(auto tv = cast(ArrayValueBase) v) { if(tv.len != len) return semanticErrorValue("different length in assignment from ", v, " to ", this); IntValue idxval = new IntValue; for(int i = 0; i < len; i++) { *(idxval.pval) = i; Value vidx = v.opIndex(idxval); auto idx = opIndex(idxval); idx.opBin(ctx, TOK_assign, vidx); } } else return semanticErrorValue("cannot assign ", v, " to ", this); debug sval = toStr(); return this; default: return super.opBin(ctx, tokid, v); } } } alias TypeTuple!(CharValue, WCharValue, DCharValue, StringValue) StringTypeValues; class StringValue : Value { alias string ValType; ValType* pval; this() { pval = (new string[1]).ptr; debug sval = toStr(); } this(string s) { pval = (new string[1]).ptr; *pval = s; debug sval = toStr(); } static StringValue _create(string s) { StringValue sv = new StringValue(s); return sv; } override Type getType() { return getTypeString!char(); } override string toStr() { return '"' ~ *pval ~ '"'; } override string toMixin() { return *pval; } override PointerValue toPointer(TypePointer to) { // TODO: implementation here just to satisfy string -> C const char* conversion PointerValue pv = new PointerValue; pv.type = new TypePointer; pv.type.addMember(createBasicType(TOK_char)); pv.pval = this; debug pv.sval = pv.toStr(); return pv; } override bool toBool() { return *pval !is null; } mixin mixinAssignOp!("=", StringTypeValues) ass_assign; mixin mixinAssignOp!("~=", StringTypeValues) ass_catass; mixin mixinBinaryOp!("~", StringTypeValues) bin_tilde; mixin mixinBinaryOp1!("<", StringValue) bin_lt; mixin mixinBinaryOp1!(">", StringValue) bin_gt; mixin mixinBinaryOp1!("<=", StringValue) bin_le; mixin mixinBinaryOp1!(">=", StringValue) bin_ge; mixin mixinBinaryOp1!("==", StringValue) bin_equal; mixin mixinBinaryOp1!("!=", StringValue) bin_notequal; override Value opBin(Context ctx, int tokid, Value v) { switch(tokid) { case TOK_assign: auto rv = ass_assign.assOp(v); debug sval = toStr(); return rv; case TOK_catass: auto rv = ass_catass.assOp(v); debug sval = toStr(); return rv; case TOK_tilde: return bin_tilde.binOp(v); case TOK_lt: return bin_lt.binOp1(v); case TOK_gt: return bin_gt.binOp1(v); case TOK_le: return bin_le.binOp1(v); case TOK_ge: return bin_ge.binOp1(v); case TOK_equal: return bin_equal.binOp1(v); case TOK_notequal: return bin_notequal.binOp1(v); default: return super.opBin(ctx, tokid, v); } } override Value opIndex(Value v) { int idx = v.toInt(); if(idx < 0 || idx >= (*pval).length) return semanticErrorValue("index ", idx, " out of bounds on ", *pval); return create((*pval)[idx]); } } class PointerValue : Value { TypePointer type; // type of pointer Value pval; // Value is a class type, so its a reference, i.e. a pointer to the value override string toStr() { return pval ? "&" ~ pval.toStr() : "null"; } static PointerValue _create(TypePointer type, Value v) { PointerValue pv = new PointerValue; pv.type = type; pv.pval = v; debug pv.sval = pv.toStr(); return pv; } override Type getType() { return type; } override bool toBool() { return pval !is null; } override PointerValue toPointer(TypePointer to) { return this; } override Value opDerefPointer() { if(!pval) return semanticErrorValue("dereferencing a null pointer"); return pval; } override Value opBin(Context ctx, int tokid, Value v) { switch(tokid) { case TOK_assign: auto pv = v.toPointer(type); if(!v) pval = null; else if(!pv) return semanticErrorValue("cannot convert value ", v, " to pointer of type ", type); else if(type.convertableFromImplicite(pv.type)) pval = pv.pval; else return semanticErrorValue("cannot convert pointer type ", pv.type, " to ", type); debug sval = toStr(); return this; case TOK_equal: case TOK_notequal: auto pv = cast(PointerValue)v; if(!pv || (!pv.type.convertableFromImplicite(type) && !type.convertableFromImplicite(pv.type))) return semanticErrorValue("cannot compare types ", v.getType(), " and ", type); if(tokid == TOK_equal) return Value.create(pv.pval is pval); else return Value.create(pv.pval !is pval); default: return super.opBin(ctx, tokid, v); } } @disable override Value _interpretProperty(Context ctx, string prop) { switch(prop) { case "init": return _create(type, null); default: if(!pval) return semanticErrorValue("dereferencing null pointer"); return pval._interpretProperty(ctx, prop); } } } class TypeValue : Value { Type type; this(Type t) { type = t; debug sval = toStr(); } override Type getType() { return type; } override string toStr() { return writeD(type); } override Value opCall(Context sc, Value vargs) { return type.createValue(sc, vargs); } } class AliasValue : Value { IdentifierList id; this(IdentifierList _id) { id = _id; debug sval = toStr(); } Node resolve() { return id.resolve(); } override Type getType() { return id.calcType(); } override string toStr() { return writeD(id); } } class TupleValue : Value { private: Value[] _values; public: this() { debug sval = toStr(); } @property Value[] values() { return _values; } @property void values(Value[] v) { _values = v; debug sval = toStr(); } void addValue(Value v) { _values ~= v; debug sval = toStr(); } void setValuesLength(size_t len) { _values.length = len; } override string toStr() { return _toStr("(", ")"); } string _toStr(string open, string close) { string s = open; foreach(i, v; values) { if(i > 0) s ~= ","; s ~= v.toStr(); } s ~= close; return s; } override Value opIndex(Value v) { int idx = v.toInt(); if(idx < 0 || idx >= values.length) return semanticErrorValue("index ", idx, " out of bounds on value tuple"); return values[idx]; } override Value opSlice(Value b, Value e) { int idxb = b.toInt(); int idxe = e.toInt(); if(idxb < 0 || idxb > values.length || idxe < idxb || idxe > values.length) return semanticErrorValue("slice [", idxb, "..", idxe, "] out of bounds on value tuple"); auto nv = new TupleValue; nv._values = _values[idxb..idxe]; return nv; } override Value opBin(Context ctx, int tokid, Value v) { switch(tokid) { case TOK_equal: if(auto tv = cast(TupleValue) v) { if(tv.values.length != values.length) return Value.create(false); for(int i = 0; i < values.length; i++) if(!values[i].opBin(ctx, TOK_equal, tv.values[i]).toBool()) return Value.create(false); return Value.create(true); } return semanticErrorValue("cannot compare ", v, " to ", this); case TOK_notequal: return Value.create(!opBin(ctx, TOK_equal, v).toBool()); case TOK_assign: if(auto tv = cast(TupleValue) v) values = tv.values; else return semanticErrorValue("cannot assign ", v, " to ", this); debug sval = toStr(); return this; case TOK_tilde: auto nv = new TupleValue; if(auto tv = cast(TupleValue) v) nv._values = _values ~ tv._values; else nv._values = _values ~ v; return nv; case TOK_catass: if(auto tv = cast(TupleValue) v) _values ~= tv._values; else _values ~= v; return this; default: return super.opBin(ctx, tokid, v); } } @disable override Value _interpretProperty(Context ctx, string prop) { switch(prop) { case "length": return create(values.length); default: return super._interpretProperty(ctx, prop); } } } Value doCall(CallableNode funcNode, Context sc, ParameterList params, Value vargs) { if(!funcNode) return semanticErrorValue("calling null reference"); auto ctx = new Context(sc); auto args = static_cast!TupleValue(vargs); auto numparams = params.members.length; auto numargs = args ? args.values.length : 0; if(params.anonymous_varargs) { if(numargs < numparams) return semanticErrorValue("too few arguments"); // TODO: add _arguments and _argptr variables } else if(params.varargs) { if(numargs < numparams - 1) return semanticErrorValue("too few arguments"); numparams--; } else if(numargs != numparams) return semanticErrorValue("incorrect number of arguments"); for(size_t p = 0; p < numparams; p++) { if(auto decl = params.getParameter(p).getParameterDeclarator().getDeclarator()) { Value v = args.values[p]; Type t = v.getType(); if(!decl.isRef) v = decl.calcType().createValue(sc, v); // if not ref, always create copy else if(!t.compare(decl.calcType())) return semanticErrorValue("cannot create reference of incompatible type", v.getType()); ctx.setValue(decl, v); } } if(params.varargs) { // TODO: pack remaining arguments into array auto decl = params.getParameter(numparams).getParameterDeclarator(); auto vdecl = decl.getDeclarator(); if(!vdecl) return semanticErrorValue("cannot pack remaining arguments into parameter", decl); Value arr = vdecl.calcType().createValue(ctx, null); if(auto darr = cast(DynArrayValue) arr) { darr.setLength(ctx, args.values.length - numparams); for(size_t n = numparams; n < args.values.length; n++) { Value v = args.values[n]; Type t = v.getType(); v = t.createValue(sc, v); // if not ref, always create copy darr.setItem(ctx, n - numparams, v); } debug darr.sval = darr.toStr(); ctx.setValue(vdecl, darr); } else return semanticErrorValue("array type expected for variable argument parameter"); } Value retVal = funcNode.interpretCall(ctx); return retVal ? retVal : theVoidValue; } class FunctionValue : Value { TypeFunction functype; bool adr; override string toStr() { if(!functype.funcDecl) return "null"; if(!functype.funcDecl.ident) return "_funcliteral_"; return "&" ~ functype.funcDecl.ident; } override Value opCall(Context sc, Value vargs) { return doCall(functype.funcDecl, threadContext, functype.getParameters(), vargs); } override Value opBin(Context ctx, int tokid, Value v) { FunctionValue dg = cast(FunctionValue) v; if(!dg) return semanticErrorValue("cannot assign ", v, " to function"); //! TODO: verify compatibility of types switch(tokid) { case TOK_assign: functype = dg.functype; debug sval = toStr(); return this; case TOK_equal: return Value.create(functype.compare(dg.functype)); case TOK_notequal: return Value.create(!functype.compare(dg.functype)); default: return super.opBin(ctx, tokid, v); } } override Type getType() { return functype; } override Value opRefPointer() { adr = true; return this; } } class DelegateValue : FunctionValue { Context context; override Value opCall(Context sc, Value vargs) { return doCall(functype.funcDecl, context, functype.getParameters(), vargs); } override Value opBin(Context ctx, int tokid, Value v) { DelegateValue dg = cast(DelegateValue) v; if(!dg) return semanticErrorValue("cannot assign ", v, " to delegate"); //! TODO: verify compatibility of types switch(tokid) { case TOK_assign: context = dg.context; functype = dg.functype; debug sval = toStr(); return this; case TOK_equal: return Value.create((context is dg.context) && functype.compare(dg.functype)); case TOK_notequal: return Value.create((context !is dg.context) || !functype.compare(dg.functype)); default: return super.opBin(ctx, tokid, v); } } } class AggrValue : TupleValue { Context outer; AggrContext context; abstract override Aggregate getType(); override string toStr() { if(auto t = getType()) return t.ident ~ _toStr("{", "}"); return "" ~ _toStr("{", "}"); } @disable override Value _interpretProperty(Context ctx, string prop) { auto type = getType(); if(Value v = type.getProperty(this, prop, true)) return v; if(Value v = type.getStaticProperty(prop)) return v; if(!context) context = new AggrContext(outer, this); if(Value v = super._interpretProperty(context, prop)) return v; //if(outer) // TODO: outer checked after super? // if(Value v = outer._interpretProperty(ctx, prop)) // return v; // return null; } override Value opBin(Context ctx, int tokid, Value v) { switch(tokid) { case TOK_equal: if(Value fv = getType().getProperty(this, "opEquals", true)) { auto tctx = new AggrContext(ctx, this); auto tv = new TupleValue; tv.addValue(v); return fv.opCall(tctx, tv); } return super.opBin(ctx, tokid, v); case TOK_is: return Value.create(v is this); case TOK_notidentity: return Value.create(v !is this); default: return super.opBin(ctx, tokid, v); } } } class AggrValueT(T) : AggrValue { T type; this(T t) { type = t; debug sval = toStr(); } override Aggregate getType() { return type; } } class StructValue : AggrValueT!Struct { this(Struct t) { super(t); } } class UnionValue : AggrValueT!Union { this(Union t) { super(t); } } class ClassInstanceValue : AggrValueT!Class { this(Class t) { super(t); } } class ReferenceValue : Value { ClassInstanceValue instance; bool insideToStr; override string toStr() { if(!instance) return "null"; if(insideToStr) return "recursive-toStr"; insideToStr = true; scope(exit) insideToStr = false; return instance.toStr(); } override Value opBin(Context ctx, int tokid, Value v) { ClassInstanceValue other; if(auto cv = cast(ReferenceValue) v) other = cv.instance; else if(!cast(NullValue) v) return super.opBin(ctx, tokid, v); switch(tokid) { case TOK_assign: instance = other; debug sval = toStr(); return this; case TOK_equal: if(instance is other) return Value.create(true); if(!instance || !other) return Value.create(false); return instance.opBin(ctx, TOK_equal, other); case TOK_is: return Value.create(instance is other); case TOK_notidentity: return Value.create(instance !is other); default: return super.opBin(ctx, tokid, v); } } } class ReferenceValueT(T) : ReferenceValue { T type; this(T t) { type = t; } override T getType() { return type; } @disable override Value _interpretProperty(Context ctx, string prop) { if(instance) if(Value v = instance._interpretProperty(ctx, prop)) return v; if(Value v = type.getStaticProperty(prop)) return v; return super._interpretProperty(ctx, prop); } override Value doCast(Value v) { if(cast(NullValue) v) { instance = null; return this; } if(auto cv = cast(ReferenceValue) v) { if(type.convertableFrom(cv.getType(), Type.ConversionFlags.kImpliciteConversion)) instance = cv.instance; else instance = null; return this; } return super.doCast(v); } } class ClassValue : ReferenceValueT!Class { this(Class t, ClassInstanceValue inst = null) { super(t); instance = inst; validate(); } } class InterfaceValue : ReferenceValueT!Intrface { this(Intrface t) { super(t); validate(); } } class AnonymousClassInstanceValue : AggrValueT!AnonymousClass { this(AnonymousClass t) { super(t); validate(); } } class AnonymousClassValue : ReferenceValueT!AnonymousClass { this(AnonymousClass t) { super(t); validate(); } } //////////////////////////////////////////////////////////////////////// // program control class ProgramControlValue : Value { string label; } class BreakValue : ProgramControlValue { this(string s) { label = s; } } class ContinueValue : ProgramControlValue { this(string s) { label = s; } } class GotoValue : ProgramControlValue { this(string s) { label = s; } } class GotoCaseValue : ProgramControlValue { this(string s) { label = s; } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/semantic.d0000664000175000017500000006250412776214756026511 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.semantic; import vdc.util; import vdc.ast.mod; import vdc.ast.node; import vdc.ast.type; import vdc.ast.aggr; import vdc.ast.decl; import vdc.ast.expr; import vdc.ast.tmpl; import vdc.ast.writer; import vdc.parser.engine; import vdc.logger; import vdc.interpret; import vdc.versions; import stdext.util; import stdext.array; import stdext.path; import std.exception; import std.stdio; import std.string; import std.array; import std.conv; import std.datetime; int semanticErrors; alias object.AssociativeArray!(Node, const(bool)) _wa1; // fully instantiate type info for bool[Node] alias object.AssociativeArray!(string, const(VersionInfo)) _wa2; // fully instantiate type info for VersionInfo[string] alias object.AssociativeArray!(string, const(bool)) _wa3; // fully instantiate type info for bool[string] class SemanticException : Exception { this(string msg) { super(msg); } } class InterpretException : Exception { this() { super("cannot interpret"); } } enum MessageType { Warning, Error, Message } void delegate(MessageType,string) fnSemanticWriteError = null; string semanticErrorWriteLoc(string filename, ref const(TextPos) pos) { string txt = filename; if(pos.line > 0) txt ~= text("(", pos.line, ")"); txt ~= ": "; semanticErrors++; return txt; } void semanticErrorLoc(T...)(string filename, ref const(TextPos) pos, T args) { foreach(a; args) if(typeid(a) == typeid(ErrorType) || typeid(a) == typeid(ErrorValue)) return; string msg = semanticErrorWriteLoc(filename, pos); msg ~= text(args); if(fnSemanticWriteError) fnSemanticWriteError(MessageType.Error, msg); logInfo("%s", msg); // avoid interpreting % in message } void semanticErrorPos(T...)(ref const(TextPos) pos, T args) { string filename; if(Scope.current && Scope.current.mod) filename = Scope.current.mod.filename; else filename = "at global scope"; semanticErrorLoc(filename, pos, args); } void semanticError(T...)(T args) { TextPos pos; semanticErrorPos(pos, args); } void semanticErrorFile(T...)(string fname, T args) { TextPos pos; semanticErrorLoc(fname, pos, args); } void semanticMessage(string msg) { if(fnSemanticWriteError) fnSemanticWriteError(MessageType.Message, msg); } ErrorValue semanticErrorValue(T...)(T args) { TextPos pos; semanticErrorPos(pos, args); //throw new InterpretException; return Singleton!(ErrorValue).get(); } ErrorType semanticErrorType(T...)(T args) { semanticErrorPos(TextPos(), args); return Singleton!(ErrorType).get(); } alias Node Symbol; class Context { Scope scop; Value[Node] vars; Context parent; this(Context p) { parent = p; } Value getThis() { if(parent) return parent.getThis(); return null; } void setThis(Value v) { setValue(null, v); } Value getValue(Node n) { if(auto pn = n in vars) return *pn; if(parent) return parent.getValue(n); return null; } void setValue(Node n, Value v) { vars[n] = v; } } class AggrContext : Context { Value instance; bool virtualCall; this(Context p, Value inst) { super(p); instance = inst; virtualCall = true; } override Value getThis() { if(auto t = cast(Class)instance.getType()) return new ClassValue(t, static_cast!ClassInstanceValue (instance)); return instance; } override Value getValue(Node n) { if(auto pn = n in vars) return *pn; if(auto decl = cast(Declarator) n) //if(Value v = instance._interpretProperty(this, decl.ident)) if(Value v = instance.getType().getProperty(instance, decl, virtualCall)) return v; if(parent) return parent.getValue(n); return null; } } class AssertContext : Context { Value[Node] identVal; this(Context p) { super(p); } } Context nullContext; AggrContext noThisContext; Context globalContext; Context threadContext; Context errorContext; class Scope { Scope parent; Annotation annotations; Attribute attributes; Module mod; Node node; Set!Symbol[string] symbols; Import[] imports; // Context ctx; // compile time only static Scope current; this() { logInfo("Scope(%s) created, current=%s", cast(void*)this, cast(void*)current); } enum { SearchParentScope = 1, SearchPrivateImport = 2, } Scope pushClone() { Scope sc = new Scope; sc.annotations = annotations; sc.attributes = attributes; sc.mod = mod; sc.parent = this; return current = sc; } Scope push(Scope sc) { if(!sc) return pushClone(); assert(this !is sc); sc.parent = this; return current = sc; } Scope pop() { return current = parent; } Type getThisType() { if(!parent) return null; return parent.getThisType(); } void addSymbol(string ident, Symbol s) { logInfo("Scope(%s).addSymbol(%s, sym %s=%s)", cast(void*)this, ident, s, cast(void*)s); if(auto sym = ident in symbols) addunique(*sym, s); else symbols[ident] = Set!Symbol([s : true]); } void addImport(Import imp) { imports ~= imp; } struct SearchData { string ident; Scope sc; } static Stack!SearchData searchStack; alias Set!Symbol SearchSet; void searchCollect(string ident, ref SearchSet syms) { string iden = ident[0..$-1]; foreach(id, sym; symbols) if(id.startsWith(iden)) addunique(syms, sym); } void searchParents(string ident, bool inParents, bool privateImports, bool publicImports, ref SearchSet syms) { if(inParents && parent) { if(syms.length == 0) syms = parent.search(ident, true, privateImports, publicImports); else if(collectSymbols(ident)) addunique(syms, parent.search(ident, true, privateImports, publicImports)); } } static bool collectSymbols(string ident) { return ident.endsWith("*"); } SearchSet search(string ident, bool inParents, bool privateImports, bool publicImports) { // check recursive search SearchData sd = SearchData(ident, this); for(int d = 0; d < searchStack.depth; d++) if(searchStack.stack[d] == sd) // memcmp return Scope.SearchSet(); SearchSet syms; if(collectSymbols(ident)) searchCollect(ident, syms); else if(auto pn = ident in symbols) return *pn; searchStack.push(sd); if(publicImports) foreach(imp; imports) { if(privateImports || (imp.getProtection() & Annotation_Public)) addunique(syms, imp.search(this, ident)); } searchParents(ident, inParents, privateImports, publicImports, syms); searchStack.pop(); return syms; } Scope.SearchSet matchFunctionArguments(Node id, Scope.SearchSet n) { Scope.SearchSet matches; ArgumentList fnargs = id.getFunctionArguments(); int cntFunc = 0; foreach(s, b; n) if(s.getParameterList()) cntFunc++; if(cntFunc != n.length) return matches; Node[] args; if(fnargs) args = fnargs.members; foreach(s, b; n) { auto pl = s.getParameterList(); if(args.length > pl.members.length) continue; if(args.length < pl.members.length) // parameterlist must have default if(auto param = pl.getParameter(args.length)) if(!param.getInitializer()) continue; int a; for(a = 0; a < args.length; a++) { auto atype = args[a].calcType(); auto ptype = pl.members[a].calcType(); if(!ptype.convertableFrom(atype, Type.ConversionFlags.kImpliciteConversion)) break; } if(a < args.length) continue; matches[s] = true; } return matches; } Node resolveOverload(string ident, Node id, Scope.SearchSet n) { if(n.length == 0) { id.semanticError("unknown identifier " ~ ident); return null; } foreach(s, b; n) s.semanticSearches++; if(n.length > 1) { auto matches = matchFunctionArguments(id, n); if(matches.length == 1) return matches.first(); else if(matches.length > 0) n = matches; // report only matching funcs id.semanticError("ambiguous identifier " ~ ident); foreach(s, b; n) s.semanticError("possible candidate"); if(!collectSymbols(ident)) return null; } return n.first(); } Node resolve(string ident, Node id, bool inParents = true) { auto n = search(ident, inParents, true, true); logInfo("Scope(%s).search(%s) found %s %s", cast(void*)this, ident, n.keys(), n.length > 0 ? cast(void*)n.first() : null); return resolveOverload(ident, id, n); } Node resolveWithTemplate(string ident, Scope sc, Node id, bool inParents = true) { auto n = search(ident, inParents, true, true); logInfo("Scope(%s).search(%s) found %s %s", cast(void*)this, ident, n.keys(), n.length > 0 ? cast(void*)n.first() : null); auto resolved = resolveOverload(ident, id, n); if(resolved && resolved.isTemplate()) { TemplateArgumentList args; if(auto tmplid = cast(TemplateInstance)id) { args = tmplid.getTemplateArgumentList(); } else { args = new TemplateArgumentList; // no args } resolved = resolved.expandTemplate(sc, args); } return resolved; } Project getProject() { return mod ? mod.getProject() : null; } } struct ArgMatch { Value value; string name; string toString() { return "{" ~ value.toStr() ~ "," ~ name ~ "}"; } } class SourceModule { // filename already in Module SysTime lastModified; Options options; string txt; Module parsed; Module analyzed; Parser parser; ParseError[] parseErrors; bool parsing() { return parser !is null; } } version = no_syntaxcopy; version = no_disconnect; //version = free_ast; class Project : Node { Options options; int countErrors; bool saveErrors; Module mObjectModule; // object.d SourceModule[string] mSourcesByModName; SourceModule[string] mSourcesByFileName; this() { TextSpan initspan; super(initspan); options = new Options; version(none) { options.importDirs ~= r"c:\l\dmd-2.055\src\druntime\import\"; options.importDirs ~= r"c:\l\dmd-2.055\src\phobos\"; options.importDirs ~= r"c:\tmp\d\runnable\"; options.importDirs ~= r"c:\tmp\d\runnable\imports\"; options.importDirs ~= r"m:\s\d\rainers\dmd\test\"; options.importDirs ~= r"m:\s\d\rainers\dmd\test\imports\"; } globalContext = new Context(null); threadContext = new Context(null); errorContext = new Context(null); } Module addSource(string fname, Module mod, ParseError[] errors, Node importFrom = null) { mod.filename = fname; mod.imported = importFrom !is null; SourceModule src; string modname = mod.getModuleName(); if(auto pm = modname in mSourcesByModName) { if(pm.parsed && pm.parsed.filename != fname) { semanticErrorFile(fname, "module name " ~ modname ~ " already used by " ~ pm.parsed.filename); countErrors++; //return null; } src = *pm; } else if(auto pm = fname in mSourcesByFileName) src = *pm; else src = new SourceModule; if(src.parsed) { version(no_disconnect) {} else src.parsed.disconnect(); version(free_ast) src.parsed.free(); } src.parsed = mod; src.parseErrors = errors; if(std.file.exists(fname)) // could be pseudo name src.lastModified = std.file.timeLastModified(fname); if(src.analyzed) { removeMember(src.analyzed); version(disconnect) {} else src.analyzed.disconnect(); version(free_ast) src.analyzed.free(); } version(no_syntaxcopy) {} else { src.analyzed = mod.clone(); addMember(src.analyzed); } src.options = options; if(importFrom) if(auto m = importFrom.getModule()) src.options = m.getOptions(); mSourcesByModName[modname] = src; mSourcesByFileName[fname] = src; version(no_syntaxcopy) return src.parsed; else return src.analyzed; } //////////////////////////////////////////////////////////// Module addText(string fname, string txt, Node importFrom = null) { SourceModule src; if(auto pm = fname in mSourcesByFileName) src = *pm; else src = new SourceModule; logInfo("parsing " ~ fname); Parser p = new Parser; p.saveErrors = saveErrors; src.parser = p; scope(exit) src.parser = null; p.filename = fname; Node n; try { semanticMessage(fname ~ ": parsing..."); n = p.parseModule(txt); } catch(Exception e) { if(fnSemanticWriteError) fnSemanticWriteError(MessageType.Error, e.msg); countErrors += p.countErrors + 1; return null; } countErrors += p.countErrors; if(!n) return null; auto mod = static_cast!(Module)(n); return addSource(fname, mod, p.errors, importFrom); } Module addAndParseFile(string fname, Node importFrom = null) { //debug writeln(fname, ":"); string txt = readUtf8(fname); return addText(fname, txt, importFrom); } bool addFile(string fname) { auto src = new SourceModule; if(std.file.exists(fname)) // could be pseudo name src.lastModified = std.file.timeLastModified(fname); src.txt = readUtf8(fname); mSourcesByFileName[fname] = src; return true; } Module getModule(string modname) { if(auto pm = modname in mSourcesByModName) return pm.analyzed; return null; } SourceModule getModuleByFilename(string filename) { if(auto pm = filename in mSourcesByFileName) return *pm; return null; } Module importModule(string modname, Node importFrom) { if(auto mod = getModule(modname)) return mod; string dfile = replace(modname, ".", "/") ~ ".di"; string srcfile = searchImportFile(dfile, importFrom); if(srcfile.length == 0) { dfile = replace(modname, ".", "/") ~ ".d"; srcfile = searchImportFile(dfile, importFrom); } if(srcfile.length == 0) { if (importFrom) importFrom.semanticError("cannot find imported module " ~ modname); else .semanticError("cannot find imported module " ~ modname); return null; } srcfile = normalizePath(srcfile); return addAndParseFile(srcfile, importFrom); } string searchImportFile(string dfile, Node importFrom) { if(std.file.exists(dfile)) return dfile; Options opt = options; if(importFrom) if(auto mod = importFrom.getModule()) opt = mod.getOptions(); foreach(dir; opt.importDirs) if(std.file.exists(dir ~ dfile)) return dir ~ dfile; return null; } void initScope() { getObjectModule(null); scop = new Scope; } Module getObjectModule(Module importFrom) { if(!mObjectModule) mObjectModule = importModule("object", importFrom); return mObjectModule; } // for error messages override string getModuleFilename() { return ""; } void semantic() { try { size_t cnt = members.length; // do not fully analyze imported modules initScope(); for(size_t m = 0; m < cnt; m++) members[m].semantic(scop); } catch(InterpretException) { semanticError("unhandled interpret exception, semantic analysis aborted"); } } //////////////////////////////////////////////////////////// void update() { } void disconnectAll() { foreach(s; mSourcesByFileName) { if(s.parsed) s.parsed.disconnect(); if(s.analyzed) s.analyzed.disconnect(); } } //////////////////////////////////////////////////////////// void writeCpp(string fname) { string src; CCodeWriter writer = new CCodeWriter(getStringSink(src)); writer.writeDeclarations = true; writer.writeImplementations = false; for(int m = 0; m < members.length; m++) { writer.writeReferencedOnly = getMember!Module(m).imported; writer(members[m]); writer.nl; } writer.writeDeclarations = false; writer.writeImplementations = true; for(int m = 0; m < members.length; m++) { writer.writeReferencedOnly = getMember!Module(m).imported; writer(members[m]); writer.nl; } Node mainNode; for(int m = 0; m < members.length; m++) if(members[m].scop) { if(auto pn = "main" in members[m].scop.symbols) { if(pn.length > 1 || mainNode) semanticError("multiple candidates for main function"); else mainNode = (*pn).first(); } } if(mainNode) { writer("int main(int argc, char**argv)"); writer.nl; writer("{"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); Module mod = mainNode.getModule(); mod.writeNamespace(writer); writer("main();"); writer.nl; writer("return 0;"); writer.nl; } writer("}"); writer.nl; } std.file.write(fname, src); } override void toD(CodeWriter writer) { throw new SemanticException("Project.toD not implemeted"); } int run() { Scope.SearchSet funcs; foreach(m; mSourcesByModName) addunique(funcs, m.analyzed.search("main")); if(funcs.length == 0) { semanticError("no function main"); return -1; } if(funcs.length > 1) { semanticError("multiple functions main"); return -2; } TupleValue args = new TupleValue; if(auto cn = cast(CallableNode)funcs.first()) if(auto pl = cn.getParameterList()) if(pl.members.length > 0) { auto tda = new TypeDynamicArray; tda.setNextType(getTypeString!char()); auto dav = new DynArrayValue(tda); args.addValue(dav); } try { Value v = funcs.first().interpret(nullContext).opCall(nullContext, args); if(v is theVoidValue) return 0; return v.toInt(); } catch(InterpretException) { semanticError("cannot run main, interpretation aborted"); return -1; } } } struct VersionInfo { TextPos defined; // line -1 if not defined yet TextPos firstUsage; // line int.max if not used yet } struct VersionDebug { int level; VersionInfo[string] identifiers; bool reset(int lev, string[] ids) { if(lev == level && ids.length == identifiers.length) { bool different = false; foreach(id; ids) if(id !in identifiers) different = true; if(!different) return false; } level = lev; identifiers = identifiers.init; foreach(id; ids) identifiers[id] = VersionInfo(); return true; } bool preDefined(string ident) const { if(auto vi = ident in identifiers) return vi.defined.line >= 0; return false; } bool defined(string ident, TextPos pos) { if(auto vi = ident in identifiers) { if(pos < vi.defined) semanticErrorPos(pos, "identifier " ~ ident ~ " used before defined"); if(pos < vi.firstUsage) vi.firstUsage = pos; return vi.defined.line >= 0; } VersionInfo vi; vi.defined.line = -1; vi.firstUsage = pos; identifiers[ident] = vi; return false; } void define(string ident, TextPos pos) { if(auto vi = ident in identifiers) { if(pos > vi.firstUsage) semanticErrorPos(pos, "identifier " ~ ident ~ " defined after usage"); if(pos < vi.defined) vi.defined = pos; } VersionInfo vi; vi.firstUsage.line = int.max; vi.defined = pos; identifiers[ident] = vi; } } class Options { string[] importDirs; string[] stringImportDirs; public /* debug & version handling */ { bool unittestOn; bool x64; bool debugOn; bool coverage; bool doDoc; bool noBoundsCheck; bool gdcCompiler; bool noDeprecated; bool mixinAnalysis; bool UFCSExpansions; VersionDebug debugIds; VersionDebug versionIds; int changeCount; bool setImportDirs(string[] dirs) { if(dirs == importDirs) return false; importDirs = dirs.dup; changeCount++; return true; } bool setStringImportDirs(string[] dirs) { if(dirs == stringImportDirs) return false; stringImportDirs = dirs.dup; changeCount++; return true; } bool setVersionIds(int level, string[] versionids) { if(!versionIds.reset(level, versionids)) return false; changeCount++; return true; } bool setDebugIds(int level, string[] debugids) { if(!debugIds.reset(level, debugids)) return false; changeCount++; return true; } bool versionEnabled(string ident) { int pre = versionPredefined(ident); if(pre == 0) return versionIds.defined(ident, TextPos()); return pre > 0; } bool versionEnabled(int level) { return level <= versionIds.level; } bool debugEnabled(string ident) { return debugIds.defined(ident, TextPos()); } bool debugEnabled(int level) { return level <= debugIds.level; } int versionPredefined(string ident) { int* p = ident in sPredefinedVersions; if(!p) return 0; if(*p) return *p; switch(ident) { case "unittest": return unittestOn ? 1 : -1; case "assert": return unittestOn || debugOn ? 1 : -1; case "D_Coverage": return coverage ? 1 : -1; case "D_Ddoc": return doDoc ? 1 : -1; case "D_NoBoundsChecks": return noBoundsCheck ? 1 : -1; case "CRuntime_DigitalMars": case "Win32": case "X86": case "D_InlineAsm_X86": return x64 ? -1 : 1; case "CRuntime_Microsoft": case "Win64": case "X86_64": case "D_InlineAsm_X86_64": case "D_LP64": return x64 ? 1 : -1; case "GNU": return gdcCompiler ? 1 : -1; case "DigitalMars": return gdcCompiler ? -1 : 1; default: assert(false, "inconsistent predefined versions"); } } } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/logger.d0000664000175000017500000000453312776214756026163 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.logger; import std.stdio; import std.datetime; import std.conv; import std.string; import std.array; extern(Windows) void OutputDebugStringA(const char* lpOutputString); extern(Windows) uint GetCurrentThreadId(); import core.sys.windows.windows; __gshared int gLogIndent = 0; __gshared bool gLogFirst = true; __gshared const string gLogFile = "c:/tmp/parser.log"; //debug version = enableLog; version(enableLog) { struct LogIndent { this(int n) { indent = n; gLogIndent += indent; } ~this() { gLogIndent -= indent; } int indent; } mixin template logIndent(int n = 1) { LogIndent indent = LogIndent(n); } class logSync {} void logInfo(...) { auto buffer = new char[17 + 1]; SysTime now = Clock.currTime(); uint tid = GetCurrentThreadId(); auto len = sprintf(buffer.ptr, "%02d:%02d:%02d - %04x - ", now.hour, now.minute, now.second, tid); string s = to!string(buffer[0..len]); s ~= replicate(" ", gLogIndent); void putc(dchar c) { s ~= c; } try { std.format.doFormat(&putc, _arguments, _argptr); } catch(Exception e) { string msg = e.toString(); s ~= " EXCEPTION"; } log_string(s); } void log_string(string s) { s ~= "\n"; if(gLogFile.length == 0) OutputDebugStringA(toStringz(s)); else synchronized(logSync.classinfo) { if(gLogFirst) { gLogFirst = false; s = "\n" ~ replicate("=", 80) ~ "\n" ~ s; } std.file.append(gLogFile, s); } } } else { import core.vararg; struct LogIndent { this(int n) { } } void logInfo(...) { } void log_string(string s) { } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/0000775000175000017500000000000012776214756025321 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/writer.d0000664000175000017500000001460312776214756027006 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.writer; import vdc.lexer; import vdc.util; import vdc.parser.expr; import vdc.parser.decl; import vdc.parser.stmt; import vdc.parser.aggr; import vdc.parser.misc; import vdc.parser.mod; import ast = vdc.ast.all; import std.stdio; import std.array; //////////////////////////////////////////////////////////////// void delegate(string s) getStringSink(ref string s) { void stringSink(string txt) { s ~= txt; } return &stringSink; } void delegate(string s) getConsoleSink() { void consoleSink(string txt) { write(txt); } return &consoleSink; } class CodeWriter { alias void delegate(string s) Sink; Sink sink; bool writeDeclarations = true; bool writeImplementations = true; bool writeClassImplementations = true; bool writeReferencedOnly = false; bool newline; bool lastLineEmpty; string indentation; this(Sink snk) { sink = snk; } abstract void writeNode(ast.Node node); void write(T...)(T args) { if(newline) { sink(indentation); newline = false; } foreach(t; args) static if(is(typeof(t) : ast.Node)) writeNode(t); else static if(is(typeof(t) : int)) writeKeyword(t); else sink(t); } void opCall(T...)(T args) { write(args); } void indent(int n) { if(n > 0) indentation ~= replicate(" ", n); else indentation = indentation[0..$+n*2]; } void writeArray(T)(T[] members, string sep = ", ", bool beforeFirst = false, bool afterLast = false) { bool writeSep = beforeFirst; foreach(m; members) { if(writeSep) write(sep); writeSep = true; write(m); } if(afterLast) write(sep); } @property void nl(bool force = true) { if(!lastLineEmpty) force = true; if(force) { sink("\n"); lastLineEmpty = newline; newline = true; } } void writeKeyword(int id) { write(tokenString(id)); } void writeIdentifier(string ident) { write(ident); } bool writeAttributes(Attribute attr, bool spaceBefore = false) { if(!attr) return false; while(attr) { Attribute a = attr & -attr; if(spaceBefore) write(" "); write(attrToString(a)); if(!spaceBefore) write(" "); attr -= a; } return true; } bool writeAnnotations(Annotation annot, bool spaceBefore = false) { if(!annot) return false; while(annot) { Annotation a = annot & -annot; if(spaceBefore) write(" "); write(annotationToString(a)); if(!spaceBefore) write(" "); annot -= a; } return true; } void writeAttributesAndAnnotations(Attribute attr, Annotation annot, bool spaceBefore = false) { writeAttributes(attr, spaceBefore); writeAnnotations(annot, spaceBefore); } } class DCodeWriter : CodeWriter { this(Sink snk) { super(snk); } override void writeNode(ast.Node node) { node.toD(this); } } class CCodeWriter : CodeWriter { this(Sink snk) { super(snk); } override void writeNode(ast.Node node) { node.toC(this); } override void writeKeyword(int id) { // Compiler-specific switch(id) { case TOK_long: write("__int64"); break; case TOK_alias: write("typedef"); break; case TOK_in: write("const"); break; default: write(tokenString(id)); } } override void writeIdentifier(string ident) { // check whether it conflicts with a C++ keyword // Compiler-specific switch(ident) { case "__int64": case "__int32": case "__int16": case "__int8": case "unsigned": case "signed": write(ident, "__D"); break; default: write(ident); break; } } override bool writeAttributes(Annotation attr, bool spaceBefore = false) { if(!attr) return false; while(attr) { Attribute a = attr & -attr; string cs = attrToStringC(a); if(cs.length > 0) { if(spaceBefore) write(" "); write(cs); if(!spaceBefore) write(" "); } attr -= a; } return true; } override bool writeAnnotations(Annotation annot, bool spaceBefore = false) { return true; } } struct CodeIndenter { CodeWriter writer; int indent; this(CodeWriter _writer, int n = 1) { writer = _writer; indent = n; writer.indent(n); } ~this() { writer.indent(-indent); } } string writeD(ast.Node n) { string txt; DCodeWriter writer = new DCodeWriter(getStringSink(txt)); writer.writeImplementations = false; writer.writeClassImplementations = false; writer(n); return txt; } //////////////////////////////////////////////////////////////// version(all) { import vdc.parser.engine; void verifyParseWrite(string filename = __FILE__, int lno = __LINE__)(string txt) { Parser p = new Parser; p.filename = filename; ast.Node n = p.parseModule(txt); string ntxt; DCodeWriter writer = new DCodeWriter(getStringSink(ntxt)); writer(n); ast.Node m = p.parseModule(ntxt); bool eq = n.compare(m); assert(eq); } //////////////////////////////////////////////////////////////// } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/mod.d0000664000175000017500000004321612776214756026253 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.mod; import vdc.util; import vdc.semantic; import vdc.lexer; import vdc.ast.node; import vdc.ast.decl; import vdc.ast.expr; import vdc.ast.misc; import vdc.ast.aggr; import vdc.ast.tmpl; import vdc.ast.writer; import vdc.parser.engine; import vdc.interpret; import stdext.util; import std.conv; import std.path; import std.array; import std.algorithm; //////////////////////////////////////////////////////////////// //Module: // [ModuleDeclaration_opt DeclDef...] class Module : Node { mixin ForwardCtor!(); string filename; bool imported; Options options; override Module clone() { Module n = static_cast!Module(super.clone()); n.filename = filename; n.imported = imported; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.filename == filename && tn.imported == imported; } Project getProject() { return static_cast!Project(parent); } override void toD(CodeWriter writer) { foreach(m; members) writer(m); } override void toC(CodeWriter writer) { if(members.length > 0 && cast(ModuleDeclaration) getMember(0)) { auto fqn = getMember(0).getMember!ModuleFullyQualifiedName(0); foreach(m; fqn.members) { writer("namespace ", m, " {"); writer.nl; } writer.nl; foreach(m; members[1..$]) writer(m); writer.nl(false); foreach_reverse(m; fqn.members) { writer("} // namespace ", m); writer.nl; } } else { writer("namespace ", baseName(filename), " {"); writer.nl; foreach(m; members) writer(m); writer.nl(false); writer("} // namespace ", baseName(filename)); writer.nl; } } void writeNamespace(CodeWriter writer) { if(members.length > 0 && cast(ModuleDeclaration) getMember(0)) { auto fqn = getMember(0).getMember!ModuleFullyQualifiedName(0); foreach(m; fqn.members) writer("::", m); } else writer("::", baseName(filename)); writer("::"); } string getModuleName() { if(auto md = cast(ModuleDeclaration) getMember(0)) { auto mfqn = md.getMember!ModuleFullyQualifiedName(0); string name = mfqn.getName(); return name; } return stripExtension(baseName(filename)); } override bool createsScope() const { return true; } override Scope enterScope(Scope sc) { initScope(); return super.enterScope(sc); } override Scope getScope() { initScope(); return scop; } void initScope() { if(!scop) { scop = new Scope; scop.mod = this; scop.node = this; // add implicite import of module object if(auto prj = getProject()) if(auto objmod = prj.getObjectModule(this)) if(objmod !is this) { auto imp = Import.create(objmod); // only needs module name scop.addImport(imp); } super.addMemberSymbols(scop); } } override void addMemberSymbols(Scope sc) { initScope(); } Scope.SearchSet search(string ident) { initScope(); return scop.search(ident, false, false, true); } override void _semantic(Scope sc) { if(imported) // no full semantic on imports return; // the order in which lazy semantic analysis takes place: // - evaluate/expand version/debug // - evaluate mixins and static if conditionals in lexical order // - analyze declarations: // - instantiate templates // - evaluate compile time expression // to resolve identifiers: // look in current scope, module // if not found, search all imports initScope(); sc = sc.push(scop); scope(exit) sc.pop(); foreach(m; members) { m.semantic(scop); } } public /* debug & version handling */ { VersionDebug debugIds; VersionDebug versionIds; Options getOptions() { if(options) return options; if(auto prj = getProject()) return prj.options; return null; } void specifyVersion(string ident, TextPos pos) { if(Options opt = getOptions()) if(opt.versionPredefined(ident) != 0) semanticError("cannot define predefined version identifier " ~ ident); versionIds.define(ident, pos); } void specifyVersion(int level) { versionIds.level = max(level, versionIds.level); } bool versionEnabled(string ident, TextPos pos) { if(Options opt = getOptions()) if(opt.versionEnabled(ident)) return true; if(versionIds.defined(ident, pos)) return true; return false; } bool versionEnabled(int level) { if(Options opt = getOptions()) if(opt.versionEnabled(level)) return true; return level <= versionIds.level; } void specifyDebug(string ident, TextPos pos) { debugIds.define(ident, pos); } void specifyDebug(int level) { debugIds.level = max(level, debugIds.level); } bool debugEnabled(string ident, TextPos pos) { if(Options opt = getOptions()) { if(!opt.debugOn) return false; if(opt.debugEnabled(ident)) return true; } if(debugIds.defined(ident, pos)) return true; return false; } bool debugEnabled(int level) { if(Options opt = getOptions()) { if(!opt.debugOn) return false; if(opt.debugEnabled(level)) return true; } return level <= debugIds.level; } bool debugEnabled() { if(Options opt = getOptions()) return opt.debugOn; return false; } } } //ModuleDeclaration: // [ModuleFullyQualifiedName] class ModuleDeclaration : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("module ", getMember(0), ";"); writer.nl; } } class PackageIdentifier : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { assert(false); } } //ModuleFullyQualifiedName: // [Identifier...] class ModuleFullyQualifiedName : Node { PackageIdentifier[] pkgs; mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer.writeArray(members, "."); } override bool createsScope() const { return true; } override void addSymbols(Scope sc) { for(int m = 0; m < members.length; m++) { auto id = getMember!Identifier(m); string name = id.ident; Scope.SearchSet syms = sc.search(name, false, false, false); if(syms.length > 1) { semanticError("ambiguous use of package/module name ", name); break; } else if(syms.length == 1) { Node n = syms.first(); if(auto pkg = cast(PackageIdentifier)n) { sc = pkg.enterScope(sc); pkgs ~= pkg; } else { semanticError("package/module name ", name, " also used as ", n); break; } } else { auto pkg = new PackageIdentifier(id.span); sc.addSymbol(name, pkg); sc = pkg.enterScope(sc); pkgs ~= pkg; } } } string getName() { string name = getMember!Identifier(0).ident; foreach(m; 1..members.length) name ~= "." ~ getMember!Identifier(m).ident; return name; } } //EmptyDeclDef: // [] class EmptyDeclDef : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer(";"); writer.nl; } } //AttributeSpecifier: // attributes annotations [DeclarationBlock_opt] class AttributeSpecifier : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer.writeAttributesAndAnnotations(attr, annotation); switch(id) { case TOK_colon: assert(members.length == 0); writer(":"); writer.nl; break; case TOK_lcurly: writer.nl; //writer("{"); //writer.nl; //{ // CodeIndenter indent = CodeIndenter(writer); writer(getMember(0)); //} //writer("}"); //writer.nl; break; default: writer(getMember(0)); break; } } void applyAttributes(Node m) { m.attr = combineAttributes(attr, m.attr); m.annotation = combineAnnotations(annotation, m.annotation); } override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { switch(id) { case TOK_colon: combineAttributes(sc.attributes, attr); combineAnnotations(sc.attributes, annotation); return []; case TOK_lcurly: auto db = getMember!DeclarationBlock(0); foreach(m; db.members) applyAttributes(m); return db.removeAll(); default: applyAttributes(getMember(0)); return removeAll(); } } } //UserAttributeSpecifier: // ident [ArgumentList_opt] class UserAttributeSpecifier : Node { mixin ForwardCtor!(); string ident; ArgumentList getArgumentList() { return getMember!ArgumentList(0); } override void toD(CodeWriter writer) { writer(ident); if(members.length) { writer("("); writer.writeArray(members); writer(")"); } } override void addSymbols(Scope sc) { addMemberSymbols(sc); } override void _semantic(Scope sc) { } } //DeclarationBlock: // [DeclDef...] class DeclarationBlock : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { if(id == TOK_lcurly) { writer("{"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); foreach(m; members) writer(m); } writer("}"); writer.nl; } else foreach(m; members) writer(m); } override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { return removeAll(); } } //LinkageAttribute: // attribute class LinkageAttribute : AttributeSpecifier { mixin ForwardCtor!(); override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { return super.expandNonScopeBlock(sc, athis); } } //AlignAttribute: // attribute class AlignAttribute : AttributeSpecifier { mixin ForwardCtor!(); } //Pragma: // ident [TemplateArgumentList] class Pragma : Node { mixin ForwardCtor!(); string ident; TemplateArgumentList getTemplateArgumentList() { return getMember!TemplateArgumentList(0); } override Pragma clone() { Pragma n = static_cast!Pragma(super.clone()); n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } override void toD(CodeWriter writer) { writer("pragma(", ident, ", ", getMember(0), ")"); } override void _semantic(Scope sc) { if(ident == "msg") { string msg; auto alst = getTemplateArgumentList(); alst.semantic(sc); foreach(m; alst.members) { Value val = m.interpretCatch(nullContext); msg ~= val.toMixin(); } semanticMessage(msg); } } } //ImportDeclaration: // [ImportList] class ImportDeclaration : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("import ", getMember(0), ";"); writer.nl(); } override void toC(CodeWriter writer) { } override void _semantic(Scope sc) { getMember(0).annotation = annotation; // copy protection attributes getMember(0).semantic(sc); } override void addSymbols(Scope sc) { getMember(0).addSymbols(sc); } } //ImportList: // [Import...] class ImportList : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer.writeArray(members); } override void _semantic(Scope sc) { foreach(m; members) { m.annotation = annotation; // copy protection attributes m.semantic(sc); } } override void addSymbols(Scope sc) { foreach(m; members) m.addSymbols(sc); } } //Import: // aliasIdent_opt [ModuleFullyQualifiedName ImportBindList_opt] class Import : Node { mixin ForwardCtor!(); string aliasIdent; ImportBindList getImportBindList() { return members.length > 1 ? getMember!ImportBindList(1) : null; } Annotation getProtection() { if(parent && parent.parent) return parent.parent.annotation & Annotation_ProtectionMask; return Annotation_Private; } // semantic data Module mod; int countLookups; int countFound; override Import clone() { Import n = static_cast!Import(super.clone()); n.aliasIdent = aliasIdent; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.aliasIdent == aliasIdent; } override void toD(CodeWriter writer) { if(aliasIdent.length) writer(aliasIdent, " = "); writer(getMember(0)); if(auto bindList = getImportBindList()) writer(" : ", bindList); } override void addSymbols(Scope sc) { sc.addImport(this); if(aliasIdent.length > 0) sc.addSymbol(aliasIdent, this); auto mfqn = getMember!ModuleFullyQualifiedName(0); mfqn.addSymbols(sc); } Scope.SearchSet search(Scope sc, string ident) { if(!mod) if(auto prj = sc.mod.getProject()) mod = prj.importModule(getModuleName(), this); if(!mod) return Scope.SearchSet(); return mod.search(ident); } string getModuleName() { auto mfqn = getMember!ModuleFullyQualifiedName(0); return mfqn.getName(); } static Import create(Module mod) { // TODO: no location info auto id = new Identifier; id.ident = mod.getModuleName(); // TODO: incorrect for modules in packages auto mfqm = new ModuleFullyQualifiedName; mfqm.addMember(id); auto imp = new Import; imp.addMember(mfqm); return imp; } } unittest { verifyParseWrite(q{ import test; }); verifyParseWrite(q{ import ntest = pkg.test; }); verifyParseWrite(q{ import io = std.stdio : writeln, write; }); } //ImportBindList: // ImportBind // ImportBind , ImportBindList class ImportBindList : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer.writeArray(members); } } //ImportBind: // Identifier // Identifier = Identifier class ImportBind : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer(getMember(0)); if(members.length > 1) writer(" = ", getMember(1)); } } //MixinDeclaration: // mixin ( AssignExpression ) ; class MixinDeclaration : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("mixin(", getMember(0), ");"); writer.nl; } override Node[] expandNonScopeInterpret(Scope sc, Node[] athis) { Context ctx = new Context(nullContext); ctx.scop = sc; Value v = getMember(0).interpret(ctx); string s = v.toMixin(); Parser parser = new Parser; if(auto prj = sc.getProject()) parser.saveErrors = prj.saveErrors; return parser.parseDeclarations(s, span); } } //Unittest: // unittest BlockStatement class Unittest : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("unittest"); writer.nl; writer(getMember(0)); } override void toC(CodeWriter writer) { } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/stmt.d0000664000175000017500000006633212776214756026467 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt // // interpret: return null to indicate that execution should continue // return special values for program flow control // return normal values for returning values // module vdc.ast.stmt; import vdc.util; import vdc.lexer; import vdc.ast.node; import vdc.ast.expr; import vdc.ast.decl; import vdc.ast.type; import vdc.ast.writer; import vdc.semantic; import vdc.interpret; import vdc.parser.engine; import stdext.util; import std.conv; //Statement: // [Statement...] class Statement : Node { mixin ForwardCtor!(); override Value interpret(Context sc) { foreach(m; members) { Value v = m.interpret(sc); if(v) return v; } return null; } } class EmptyStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer(";"); writer.nl; } } version(obsolete) { //ScopeStatement: // ; // NonEmptyStatement // ScopeBlockStatement // //ScopeBlockStatement: // BlockStatement class ScopeStatement : Statement { mixin ForwardCtor!(); } //ScopeNonEmptyStatement: // NonEmptyStatement // BlockStatement class ScopeNonEmptyStatement : Statement { mixin ForwardCtor!(); } //NoScopeNonEmptyStatement: // NonEmptyStatement // BlockStatement class NoScopeNonEmptyStatement : ScopeNonEmptyStatement { mixin ForwardCtor!(); } //NoScopeStatement: // ; // NonEmptyStatement // BlockStatement class NoScopeStatement : ScopeStatement { mixin ForwardCtor!(); } //NonEmptyStatement: // LabeledStatement // ExpressionStatement // DeclarationStatement // IfStatement // WhileStatement // DoStatement // ForStatement // ForeachStatement // SwitchStatement // FinalSwitchStatement // CaseStatement // CaseRangeStatement // DefaultStatement // ContinueStatement // BreakStatement // ReturnStatement // GotoStatement // WithStatement // SynchronizedStatement // VolatileStatement // TryStatement // ScopeGuardStatement // ThrowStatement // AsmStatement // PragmaStatement // MixinStatement // ForeachRangeStatement // ConditionalStatement // StaticAssert // TemplateMixin class NonEmptyStatement : Statement { mixin ForwardCtor!(); } } // version(obsolete) //LabeledStatement: // Identifier : NoScopeStatement class LabeledStatement : Statement { string ident; Statement getStatement() { return getMember!Statement(0); } this() {} // default constructor needed for clone() this(Token tok) { super(tok); ident = tok.txt; } override LabeledStatement clone() { LabeledStatement n = static_cast!LabeledStatement(super.clone()); n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } override void toD(CodeWriter writer) { { CodeIndenter indent = CodeIndenter(writer, -1); writer.writeIdentifier(ident); writer(":"); writer.nl; } writer(getStatement()); } } //BlockStatement: // { } // { StatementList } // //StatementList: // Statement // Statement StatementList class BlockStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("{"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); foreach(m; members) writer(m); } writer("}"); writer.nl; } override bool createsScope() const { return true; } override void _semantic(Scope sc) { // TODO: TemplateParameterList, Constraint if(members.length > 0) { sc = enterScope(sc); super._semantic(sc); sc = sc.pop(); } } } //ExpressionStatement: // [Expression] class ExpressionStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer(getMember(0), ";"); writer.nl; } override Value interpret(Context sc) { getMember(0).interpret(sc); return null; } } //DeclarationStatement: // [Decl] class DeclarationStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer(getMember(0)); } override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { Node n = getMember(0); Node[1] nthis = [ n ]; Node[] nm = n.expandNonScopeBlock(sc, nthis); if(nm.length == 1 && nm[0] == n) return athis; Node[] decls; foreach(m; nm) { auto decl = new DeclarationStatement(id, span); decl.addMember(m); decls ~= decl; } return decls; } override void addSymbols(Scope sc) { addMemberSymbols(sc); } override void _semantic(Scope sc) { auto decl = getMember(0); decl.addSymbols(sc); // symbols might already be referenced in an initializer super._semantic(sc); if(decl.attr & Attr_Static) { Context ctx = new Context(nullContext); ctx.scop = sc; initValues(ctx, false); } } override Value interpret(Context sc) { auto decl = getMember(0); if(!(decl.attr & Attr_Static)) initValues(sc, true); return null; } void initValues(Context sc, bool reinit) { auto decl = cast(Decl)getMember(0); if(!decl) return; // classes, enums, etc //if(decl.getFunctionBody()) // return; // nothing to do for local functions auto decls = decl.getDeclarators(); for(int n = 0; n < decls.members.length; n++) { auto d = decls.getDeclarator(n); if(reinit) { d.value = null; d.interpretReinit(sc); } else d.interpret(sc); } } } //ImportStatement: // [ImportDeclaration] class ImportStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { getMember(0).toD(writer); } override Value interpret(Context sc) { return null; } } //IfStatement: // if ( IfCondition ) ThenStatement // if ( IfCondition ) ThenStatement else ElseStatement // //IfCondition: // Expression // auto Identifier = Expression // Declarator = Expression // //ThenStatement: // ScopeNonEmptyStatement // //ElseStatement: // ScopeNonEmptyStatement class IfStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("if(", getMember(0), ")"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(1)); } if(members.length > 2) { writer("else"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(2)); } } } override bool createsScope() const { return true; } override Value interpret(Context sc) { Value cond = getMember(0).interpret(sc); if(cond.toBool()) { if(Value v = getMember(1).interpret(sc)) return v; } else if(members.length > 2) { if(Value v = getMember(2).interpret(sc)) return v; } return null; } } //WhileStatement: // while ( Expression ) ScopeNonEmptyStatement class WhileStatement : Statement { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { writer("while(", getMember(0), ")"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(1)); } } override Value interpret(Context sc) { while(getMember(0).interpret(sc).toBool()) { if(Value v = getMember(1).interpret(sc)) { if(auto bv = cast(BreakValue)v) { if(!bv.label) break; if(auto ls = cast(LabeledStatement)parent) if(ls.ident == bv.label) break; } else if(auto cv = cast(ContinueValue)v) { if(!cv.label) continue; if(auto ls = cast(LabeledStatement)parent) if(ls.ident == cv.label) continue; } return v; } } return null; } } //DoStatement: // do ScopeNonEmptyStatement while ( Expression ) class DoStatement : Statement { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { writer("do"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(0)); } writer("while(", getMember(1), ")"); writer.nl; } override Value interpret(Context sc) { do { if(Value v = getMember(0).interpret(sc)) { if(auto bv = cast(BreakValue)v) { if(!bv.label) break; if(auto ls = cast(LabeledStatement)parent) if(ls.ident == bv.label) break; } else if(auto cv = cast(ContinueValue)v) { if(!cv.label) continue; if(auto ls = cast(LabeledStatement)parent) if(ls.ident == cv.label) continue; } return v; } } while(getMember(1).interpret(sc).toBool()); return null; } } //ForStatement: // for ( Initialize Test ; Increment ) ScopeNonEmptyStatement //Initialize: // ; // NoScopeNonEmptyStatement // //Test: // Expression_opt // //Increment: // Expression_opt // class ForStatement : Statement { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { writer("for(", getMember(0), getMember(1), "; ", getMember(2), ")"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(3)); } } override Value interpret(Context sc) { for(getMember(0).interpret(sc); getMember(1).interpret(sc).toBool(); getMember(2).interpret(sc)) { if(Value v = getMember(3).interpret(sc)) { if(auto bv = cast(BreakValue)v) { if(!bv.label) break; if(auto ls = cast(LabeledStatement)parent) if(ls.ident == bv.label) break; } else if(auto cv = cast(ContinueValue)v) { if(!cv.label) continue; if(auto ls = cast(LabeledStatement)parent) if(ls.ident == cv.label) continue; } return v; } } return null; } } //ForeachStatement: // Foreach ( ForeachTypeList ; Aggregate ) NoScopeNonEmptyStatement // //Foreach: // foreach // foreach_reverse // //ForeachTypeList: // ForeachType // ForeachType , ForeachTypeList // //ForeachType: // ref Type Identifier // Type Identifier // ref Identifier // Identifier // //Aggregate: // Expression // //ForeachRangeStatement: // Foreach ( ForeachType ; LwrExpression .. UprExpression ) ScopeNonEmptyStatement // //LwrExpression: // Expression // //UprExpression: // Expression class ForeachStatement : Statement { mixin ForwardCtor!(); override bool createsScope() const { return true; } Expression getAggregate() { return getMember!Expression(1); } Expression getLwrExpression() { return getMember!Expression(1); } Expression getUprExpression() { return getMember!Expression(2); } final bool isRangeForeach() const { return members.length > 3; } override void toD(CodeWriter writer) { writer(id, "(", getMember(0), "; "); if(members.length == 3) writer(getMember(1)); else writer(getMember(1), " .. ", getMember(2)); writer(")"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(members.length - 1)); } } override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } class ForeachTypeList : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer.writeArray(members); } override void addSymbols(Scope sc) { addMemberSymbols(sc); } } class ForeachType : Node { mixin ForwardCtor!(); bool isRef; Type type; Type getType() { return members.length == 2 ? getMember!Type(0) : null; } Identifier getIdentifier() { return getMember!Identifier(members.length - 1); } override ForeachType clone() { ForeachType n = static_cast!ForeachType(super.clone()); n.isRef = isRef; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.isRef == isRef; } override void toD(CodeWriter writer) { if(isRef) writer("ref "); writer.writeArray(members, " "); } override void addSymbols(Scope sc) { string ident = getIdentifier().ident; sc.addSymbol(ident, this); } override Type calcType() { if(type) return type; if(auto t = getType()) type = t.calcType(); else if(ForeachStatement stmt = parent ? cast(ForeachStatement) parent.parent : null) { if(stmt.isRangeForeach()) type = stmt.getLwrExpression().calcType(); else { Expression expr = stmt.getAggregate(); Type et = expr.calcType(); if(auto ti = cast(TypeIndirection) et) { type = ti.getNextType(); } } } if(!type) type = semanticErrorType("cannot infer type of foreach variable ", getIdentifier().ident); return type; } } //SwitchStatement: // switch ( Expression ) ScopeNonEmptyStatement class SwitchStatement : Statement { mixin ForwardCtor!(); bool isFinal; override bool createsScope() const { return true; } override SwitchStatement clone() { SwitchStatement n = static_cast!SwitchStatement(super.clone()); n.isFinal = isFinal; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.isFinal == isFinal; } override void toD(CodeWriter writer) { if(isFinal) writer("final "); writer("switch(", getMember(0), ")"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(1)); } } override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } //FinalSwitchStatement: // final switch ( Expression ) ScopeNonEmptyStatement // class FinalSwitchStatement : Statement { mixin ForwardCtor!(); override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } //CaseStatement: // case ArgumentList : Statement // //CaseRangeStatement: // case FirstExp : .. case LastExp : Statement // //FirstExp: // AssignExpression // //LastExp: // AssignExpression class CaseStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { { CodeIndenter indent = CodeIndenter(writer, -1); writer("case ", getMember(0)); if(id == TOK_slice) { writer(": .. case ", getMember(1)); } else { writer.writeArray(members[1..$], ", ", true); } writer(":"); } writer.nl(); } override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } //DefaultStatement: // default : Statement class DefaultStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { { CodeIndenter indent = CodeIndenter(writer, -1); writer("default:"); } writer.nl(); } override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } //ContinueStatement: // continue ; // continue Identifier ; class ContinueStatement : Statement { mixin ForwardCtor!(); string ident; override ContinueStatement clone() { ContinueStatement n = static_cast!ContinueStatement(super.clone()); n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } override void toD(CodeWriter writer) { writer("continue"); if(ident.length) { writer(" "); writer.writeIdentifier(ident); } writer(";"); writer.nl; } override Value interpret(Context sc) { return new ContinueValue(ident); } } //BreakStatement: // break ; // break Identifier ; class BreakStatement : Statement { mixin ForwardCtor!(); string ident; override BreakStatement clone() { BreakStatement n = static_cast!BreakStatement(super.clone()); n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } override void toD(CodeWriter writer) { writer("break"); if(ident.length) { writer(" "); writer.writeIdentifier(ident); } writer(";"); writer.nl; } override Value interpret(Context sc) { return new BreakValue(ident); } } //ReturnStatement: // return ; // return Expression ; class ReturnStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("return ", getMember(0), ";"); writer.nl; } override Value interpret(Context sc) { return getMember(0).interpret(sc); } } //GotoStatement: // goto Identifier ; // goto default ; // goto case ; // goto case Expression ; class GotoStatement : Statement { mixin ForwardCtor!(); string ident; override GotoStatement clone() { GotoStatement n = static_cast!GotoStatement(super.clone()); n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } override void toD(CodeWriter writer) { if(id == TOK_Identifier) { writer("goto "); writer.writeIdentifier(ident); writer(";"); } else if(id == TOK_default) writer("goto default;"); else { if(members.length > 0) writer("goto case ", getMember(0), ";"); else writer("goto case;"); } writer.nl; } override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } //WithStatement: // with ( Expression ) ScopeNonEmptyStatement // with ( Symbol ) ScopeNonEmptyStatement // with ( TemplateInstance ) ScopeNonEmptyStatement class WithStatement : Statement { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { writer("with(", getMember(0), ")"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(1)); } } override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } //SynchronizedStatement: // [Expression_opt ScopeNonEmptyStatement] class SynchronizedStatement : Statement { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { if(members.length > 1) writer("synchronized(", getMember(0), ") "); else writer("synchronized "); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(members.length - 1)); } } override Value interpret(Context sc) { // no need to synhronize, interpreter is single-threaded return getMember(members.length - 1).interpret(sc); } } //VolatileStatement: // [ScopeNonEmptyStatement] class VolatileStatement : Statement { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { writer("volatile "); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(members.length - 1)); } } override Value interpret(Context sc) { // no need to synhronize, interpreter is single-threaded return super.interpret(sc); } } //TryStatement: // try ScopeNonEmptyStatement Catches // try ScopeNonEmptyStatement Catches FinallyStatement // try ScopeNonEmptyStatement FinallyStatement // //Catches: // LastCatch // Catch // Catch Catches // //LastCatch: // catch NoScopeNonEmptyStatement // //Catch: // catch ( CatchParameter ) NoScopeNonEmptyStatement // //CatchParameter: // BasicType Identifier // //FinallyStatement: // finally NoScopeNonEmptyStatement class TryStatement : Statement { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { writer("try"); writer.nl(); { CodeIndenter indent = CodeIndenter(writer); writer(getMember(0)); } foreach(m; members[1..$]) writer(m); } override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } class Catch : Node { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { if(members.length > 2) writer("catch(", getMember(0), " ", getMember(1), ")"); else if(members.length > 1) writer("catch(", getMember(0), ")"); else writer("catch"); writer.nl(); { CodeIndenter indent = CodeIndenter(writer); writer(getMember(members.length - 1)); } } } class FinallyStatement : Catch { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { writer("finally"); writer.nl(); { CodeIndenter indent = CodeIndenter(writer); writer(getMember(0)); } } } //ThrowStatement: // throw Expression ; class ThrowStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("throw ", getMember(0), ";"); writer.nl; } override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } //ScopeGuardStatement: // scope ( "exit" ) ScopeNonEmptyStatement // scope ( "success" ) ScopeNonEmptyStatement // scope ( "failure" ) ScopeNonEmptyStatement class ScopeGuardStatement : Statement { mixin ForwardCtor!(); override bool createsScope() const { return true; } override void toD(CodeWriter writer) { writer("scope(", getMember(0), ")"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(1)); } } override Value interpret(Context sc) { return semanticErrorValue(this, " not implemented."); } } //AsmStatement: // asm { } // asm { AsmInstructionList } // //AsmInstructionList: // AsmInstruction ; // AsmInstruction ; AsmInstructionList class AsmStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("asm {"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(0)); } writer("}"); writer.nl; } override Value interpret(Context sc) { return semanticErrorValue(this, " cannot be interpreted."); } } class AsmInstructionList : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { foreach(m; members) { writer(m, ";"); writer.nl(); } } } //PragmaStatement: // Pragma NoScopeStatement class PragmaStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer(getMember(0), " ", getMember(1)); } override Value interpret(Context sc) { getMember(0).interpret(sc); return getMember(1).interpret(sc); } } //MixinStatement: // [ AssignExpression ] class MixinStatement : Statement { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("mixin(", getMember(0), ");"); writer.nl; } override void _semantic(Scope sc) { Context ctx = new Context(nullContext); ctx.scop = sc; Value v = getMember(0).interpretCatch(ctx); string s = v.toMixin(); Parser parser = new Parser; if(auto prj = sc.getProject()) parser.saveErrors = prj.saveErrors; Node[] n = parser.parseStatements(s, span); parent.replaceMember(this, n); } override Value interpret(Context sc) { return semanticErrorValue(this, " semantic not run"); } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/expr.d0000664000175000017500000016321012776214756026447 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.expr; import vdc.util; import vdc.lexer; import vdc.semantic; import vdc.interpret; import vdc.ast.node; import vdc.ast.decl; import vdc.ast.misc; import vdc.ast.tmpl; import vdc.ast.aggr; import vdc.ast.mod; import vdc.ast.type; import vdc.ast.writer; import vdc.parser.engine; import stdext.util; import std.conv; import std.string; //////////////////////////////////////////////////////////////// // Operator precedence - greater values are higher precedence enum PREC { zero, expr, assign, cond, oror, andand, or, xor, and, equal, rel, shift, add, mul, pow, unary, primary, } shared static PREC precedence[NumTokens]; shared static char recursion[NumTokens]; //////////////////////////////////////////////////////////////// void writeExpr(CodeWriter writer, Expression expr, bool paren) { if(paren) writer("("); writer(expr); if(paren) writer(")"); } enum Spaces { None = 0, Left = 1, Right = 2, LeftRight = Left | Right } void writeOperator(CodeWriter writer, TokenId op, int spaces) { if(spaces & Spaces.Left) writer(" "); writer(op); if(spaces & Spaces.Right) writer(" "); } //////////////////////////////////////////////////////////////// //Expression: class Expression : Node { // semantic data Type type; mixin ForwardCtor!(); abstract PREC getPrecedence(); override Type calcType() { if(!type) return semanticErrorType(this, ".calcType not implemented"); return type; } } //BinaryExpression: // [Expression Expression] class BinaryExpression : Expression { mixin ForwardCtor!(); TokenId getOperator() { return id; } Expression getLeftExpr() { return getMember!Expression(0); } Expression getRightExpr() { return getMember!Expression(1); } override PREC getPrecedence() { return precedence[id]; } bool isAssign() { return false; } override void _semantic(Scope sc) { getLeftExpr().semantic(sc); getRightExpr().semantic(sc); } override void toD(CodeWriter writer) { Expression exprL = getLeftExpr(); Expression exprR = getRightExpr(); bool parenL = (exprL.getPrecedence() < getPrecedence() + (recursion[id] == 'L' ? 0 : 1)); bool parenR = (exprR.getPrecedence() < getPrecedence() + (recursion[id] == 'R' ? 0 : 1)); writeExpr(writer, exprL, parenL); writeOperator(writer, id, Spaces.LeftRight); writeExpr(writer, exprR, parenR); } override Type calcType() { if(!type) { Type typeL = getLeftExpr().calcType(); Type typeR = getRightExpr().calcType(); type = typeL.commonType(typeR); } return type; } override Value interpret(Context sc) { Value vL, vR; if(isAssign()) { // right side evaluated first in assignments vR = getRightExpr().interpret(sc); vL = getLeftExpr().interpret(sc); } else { vL = getLeftExpr().interpret(sc); vR = getRightExpr().interpret(sc); } version(all) { auto btL = cast(BasicType) vL.getType(); auto avR = cast(ArrayValueBase) vR; if(btL && avR) return vR.opBin_r(sc, id, vL); return vL.opBin(sc, id, vR); } else switch(id) { case TOK_equal: return vL.opBinOp!"=="(vR); case TOK_notequal: return vL.opBinOp!"!="(vR); case TOK_lt: return vL.opBinOp!"<"(vR); case TOK_gt: return vL.opBinOp!">"(vR); case TOK_le: return vL.opBinOp!"<="(vR); case TOK_ge: return vL.opBinOp!">="(vR); case TOK_unord: return vL.opBinOp!"!<>="(vR); case TOK_ue: return vL.opBinOp!"!<>"(vR); case TOK_lg: return vL.opBinOp!"<>"(vR); case TOK_leg: return vL.opBinOp!"<>="(vR); case TOK_ule: return vL.opBinOp!"!>"(vR); case TOK_ul: return vL.opBinOp!"!>="(vR); case TOK_uge: return vL.opBinOp!"!<"(vR); case TOK_ug: return vL.opBinOp!"!<="(vR); case TOK_is: return vL.opBinOp!"is"(vR); case TOK_notcontains:return vL.opBinOp!"!in"(vR); case TOK_notidentity:return vL.opBinOp!"!is"(vR); case TOK_shl: return vL.opBinOp!"<<"(vR); case TOK_shr: return vL.opBinOp!">>"(vR); case TOK_ushr: return vL.opBinOp!">>>"(vR); case TOK_add: return vL.opBinOp!"+"(vR); case TOK_min: return vL.opBinOp!"-"(vR); case TOK_mul: return vL.opBinOp!"*"(vR); case TOK_pow: return vL.opBinOp!"^^"(vR); case TOK_div: return vL.opBinOp!"/"(vR); case TOK_mod: return vL.opBinOp!"%"(vR); //[ "slice", ".." ], //[ "dotdotdot", "..." ], case TOK_xor: return vL.opBinOp!"^"(vR); case TOK_and: return vL.opBinOp!"&"(vR); case TOK_or: return vL.opBinOp!"|"(vR); case TOK_tilde: return vL.opBinOp!"~"(vR); //[ "plusplus", "++" ], //[ "minusminus", "--" ], //[ "question", "?" ], case TOK_assign: return vL.opassign!"="(vR); case TOK_addass: return vL.opassign!"+="(vR); case TOK_minass: return vL.opassign!"-="(vR); case TOK_mulass: return vL.opassign!"*="(vR); case TOK_powass: return vL.opassign!"^^="(vR); case TOK_shlass: return vL.opassign!"<<="(vR); case TOK_shrass: return vL.opassign!">>="(vR); case TOK_ushrass: return vL.opassign!">>>="(vR); case TOK_xorass: return vL.opassign!"^="(vR); case TOK_andass: return vL.opassign!"&="(vR); case TOK_orass: return vL.opassign!"|="(vR); case TOK_catass: return vL.opassign!"~="(vR); case TOK_divass: return vL.opassign!"/="(vR); case TOK_modass: return vL.opassign!"%="(vR); default: return semanticErrorType("interpretation of binary operator ", tokenString(id), " not implemented"); } } }; mixin template BinaryExpr() { this() {} // default constructor needed for clone() this(Token tok) { super(tok); } } class CommaExpression : BinaryExpression { mixin BinaryExpr!(); override Type calcType() { return getRightExpr().calcType(); } } class AssignExpression : BinaryExpression { override bool isAssign() { return true; } mixin BinaryExpr!(); override Type calcType() { return getLeftExpr().calcType(); } } //ConditionalExpression: // [Expression Expression Expression] class ConditionalExpression : Expression { this() {} // default constructor needed for clone() this(Token tok) { super(tok); } Expression getCondition() { return getMember!Expression(0); } Expression getThenExpr() { return getMember!Expression(1); } Expression getElseExpr() { return getMember!Expression(2); } override PREC getPrecedence() { return PREC.cond; } override void _semantic(Scope sc) { getCondition().semantic(sc); getThenExpr().semantic(sc); getElseExpr().semantic(sc); } override void toD(CodeWriter writer) { Expression condExpr = getCondition(); Expression thenExpr = getThenExpr(); Expression elseExpr = getElseExpr(); bool condParen = (condExpr.getPrecedence() <= getPrecedence()); bool thenParen = (thenExpr.getPrecedence() < PREC.expr); bool elseParen = (elseExpr.getPrecedence() < getPrecedence()); writeExpr(writer, condExpr, condParen); writeOperator(writer, TOK_question, Spaces.LeftRight); writeExpr(writer, thenExpr, thenParen); writeOperator(writer, TOK_colon, Spaces.LeftRight); writeExpr(writer, elseExpr, elseParen); } override Type calcType() { if(!type) { Type typeL = getThenExpr().calcType(); Type typeR = getElseExpr().calcType(); type = typeL.commonType(typeR); } return type; } override Value interpret(Context sc) { Value cond = getCondition().interpret(sc); Expression e = (cond.toBool() ? getThenExpr() : getElseExpr()); return e.interpret(sc); // TODO: cast to common type } } class OrOrExpression : BinaryExpression { mixin BinaryExpr!(); override Type calcType() { if(!type) type = createBasicType(TOK_bool); return type; } override Value interpret(Context sc) { Value vL = getLeftExpr().interpret(sc); if(vL.toBool()) return Value.create(true); Value vR = getRightExpr().interpret(sc); return Value.create(vR.toBool()); } } class AndAndExpression : BinaryExpression { mixin BinaryExpr!(); override Type calcType() { if(!type) type = createBasicType(TOK_bool); return type; } override Value interpret(Context sc) { Value vL = getLeftExpr().interpret(sc); if(!vL.toBool()) return Value.create(false); Value vR = getRightExpr().interpret(sc); return Value.create(vR.toBool()); } } class OrExpression : BinaryExpression { mixin BinaryExpr!(); } class XorExpression : BinaryExpression { mixin BinaryExpr!(); } class AndExpression : BinaryExpression { mixin BinaryExpr!(); } class CmpExpression : BinaryExpression { mixin BinaryExpr!(); void _checkIdentityLiterals() { if(id == TOK_is || id == TOK_notidentity) { if(auto litL = cast(IntegerLiteralExpression) getLeftExpr()) litL.forceLargerType(getRightExpr().calcType()); if(auto litR = cast(IntegerLiteralExpression) getRightExpr()) litR.forceLargerType(getLeftExpr().calcType()); } } override Type calcType() { if(!type) { _checkIdentityLiterals(); if(id == TOK_in) { auto t = getRightExpr().calcType(); if(auto ti = cast(TypeIndirection)t) { auto tp = new TypePointer(); tp.setNextType(ti.getNextType()); type = tp; } else type = semanticErrorType("cannot calculate type of operator in on ", t); } else type = createBasicType(TOK_bool); } return type; } override void _semantic(Scope sc) { _checkIdentityLiterals(); getLeftExpr().semantic(sc); getRightExpr().semantic(sc); } } class ShiftExpression : BinaryExpression { mixin BinaryExpr!(); } class AddExpression : BinaryExpression { mixin BinaryExpr!(); } class MulExpression : BinaryExpression { mixin BinaryExpr!(); } class PowExpression : BinaryExpression { mixin BinaryExpr!(); } //UnaryExpression: // id [Expression] class UnaryExpression : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.unary; } Expression getExpression() { return getMember!Expression(0); } override void _semantic(Scope sc) { getExpression().semantic(sc); } override Type calcType() { if(!type) { Type exprtype = getExpression().calcType(); switch(id) { default: type = exprtype; break; case TOK_delete: type = createBasicType(TOK_void); break; case TOK_not: type = createBasicType(TOK_bool); break; } } return type; } override Value interpret(Context sc) { Value v = getExpression().interpret(sc); version(all) switch(id) { case TOK_plusplus: return v.opBin(sc, TOK_addass, Value.create(cast(byte)1)); case TOK_minusminus: return v.opBin(sc, TOK_minass, Value.create(cast(byte)1)); case TOK_delete: // TODO: call destructor? v.opBin(sc, TOK_assign, v.getType().createValue(sc, null)); return theVoidValue; default: return v.opUn(sc, id); } else switch(id) { case TOK_and: return v.opRefPointer(); case TOK_mul: return v.opDerefPointer(); case TOK_plusplus: return v.opUnOp!"++"(); case TOK_minusminus: return v.opUnOp!"--"(); case TOK_min: return v.opUnOp!"-"(); case TOK_add: return v.opUnOp!"+"(); case TOK_not: return v.opUnOp!"!"(); case TOK_tilde: return v.opUnOp!"~"(); default: return semanticErrorValue("interpretation of unary operator ", tokenString(id), " not implemented"); } } override void toD(CodeWriter writer) { Expression expr = getExpression(); bool paren = (expr.getPrecedence() < getPrecedence()); writeOperator(writer, id, Spaces.Right); writeExpr(writer, expr, paren); } } //NewExpression: // NewArguments Type [ AssignExpression ] // NewArguments Type ( ArgumentList ) // NewArguments Type // NewArguments ClassArguments BaseClassList_opt { DeclDefs } class NewExpression : Expression { bool hasNewArgs; this() {} // default constructor needed for clone() this(Token tok) { super(TOK_new, tok.span); } override NewExpression clone() { NewExpression n = static_cast!NewExpression(super.clone()); n.hasNewArgs = hasNewArgs; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.hasNewArgs == hasNewArgs; } override PREC getPrecedence() { return PREC.unary; } ArgumentList getNewArguments() { return hasNewArgs ? getMember!ArgumentList(0) : null; } Type getType() { return getMember!Type(hasNewArgs ? 1 : 0); } ArgumentList getCtorArguments() { return members.length > (hasNewArgs ? 2 : 1) ? getMember!ArgumentList(members.length - 1) : null; } override void _semantic(Scope sc) { if(auto args = getNewArguments()) args.semantic(sc); getType().semantic(sc); if(auto args = getCtorArguments()) args.semantic(sc); } override Type calcType() { return getType().calcType(); } override Value interpret(Context sc) { Value initVal; if(auto args = getCtorArguments()) initVal = args.interpret(sc); else initVal = new TupleValue; // empty args force new instance return calcType().createValue(sc, initVal); } override void toD(CodeWriter writer) { if(ArgumentList nargs = getNewArguments()) writer("new(", nargs, ") "); else writer("new "); writer(getType()); if(ArgumentList cargs = getCtorArguments()) writer("(", cargs, ")"); } } class AnonymousClassType : Type { mixin ForwardCtor!(); ArgumentList getArguments() { return members.length > 1 ? getMember!ArgumentList(0) : null; } AnonymousClass getClass() { return getMember!AnonymousClass(members.length - 1); } override bool propertyNeedsParens() const { return true; } override void toD(CodeWriter writer) { if(ArgumentList args = getArguments()) writer("class(", args, ") "); else writer("class "); writer(getClass()); } override Type calcType() { return getClass().calcType(); } } //CastExpression: // attr [Type_opt Expression] class CastExpression : Expression { this() {} // default constructor needed for clone() this(Token tok) { super(TOK_cast, tok.span); } override PREC getPrecedence() { return PREC.unary; } Type getType() { return members.length > 1 ? getMember!Type(0) : null; } Expression getExpression() { return getMember!Expression(members.length - 1); } override void toD(CodeWriter writer) { writer("cast("); writer.writeAttributesAndAnnotations(attr, annotation); if(Type type = getType()) writer(getType()); writer(")"); if(getExpression().getPrecedence() < getPrecedence()) writer("(", getExpression(), ")"); else writer(getExpression()); } override void _semantic(Scope sc) { if(auto type = getType()) type.semantic(sc); getExpression().semantic(sc); } override Type calcType() { if(type) return type; if(auto t = getType()) type = getType().calcType(); else { // extract basic type and attributes from expression Type t = getExpression().calcType(); Attribute mattr = 0; while(t) { auto mf = cast(ModifiedType) t; if(!mf) break; mattr |= tokenToAttribute(mf.id); t = mf.getType(); } assert(t); if(mattr != attr) { // rebuild modified type for(Attribute a = attr, ta; a; a -= ta) { ta = a & -a; TokenId aid = attributeToToken(attr); auto mt = new ModifiedType(aid, span); mt.addMember(t); t = mt; } } type = t; } return type; } override Value interpret(Context sc) { Value val = getExpression().interpret(sc); Type t = calcType(); Type vt = val.getType(); if(t.compare(vt)) return val; Value v = t.createValue(sc, null); return v.doCast(val); } } //PostfixExpression: // PrimaryExpression // PostfixExpression . Identifier // PostfixExpression . NewExpression // PostfixExpression ++ // PostfixExpression -- // PostfixExpression ( ) // PostfixExpression ( ArgumentList ) // IndexExpression // SliceExpression // //IndexExpression: // PostfixExpression [ ArgumentList ] // //SliceExpression: // PostfixExpression [ ] // PostfixExpression [ AssignExpression .. AssignExpression ] class PostfixExpression : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } Expression getExpression() { return getMember!Expression(0); } override Type calcType() { if(type) return type; auto expr = getExpression(); auto etype = expr.calcType(); switch(id) { // TOK_dot handled by DotExpression case TOK_lbracket: if(members.length == 2) // if slice, same type as expression { auto args = getMember!ArgumentList(1); auto vidx = args.interpret(nullContext); Value idx; if(vidx.values.length != 1) return semanticErrorType("exactly one value expected as array index"); idx = vidx.values[0]; type = etype.opIndex(idx.toInt()); } else if(members.length == 3) { Scope sc = getScope(); Value beg = getMember(1).interpret(nullContext); Value end = getMember(2).interpret(nullContext); type = etype.opSlice(beg.toInt(), end.toInt()); } else { assert(members.length == 1); // full slice type = etype; } break; case TOK_lparen: Type args; if(members.length == 2) args = getMember!ArgumentList(1).calcType(); else args = new TypeArraySlice; type = etype.opCall(args); break; default: type = semanticErrorType("cannot determine type of ", this); break; } return type; } override ArgumentList getFunctionArguments() { switch(id) { case TOK_lparen: if(members.length == 2) return getMember!ArgumentList(1); return new ArgumentList; default: return null; } } override Value interpret(Context sc) { Expression expr = getExpression(); Value val = expr.interpret(sc); switch(id) { // TOK_dot handled by DotExpression case TOK_lbracket: if(members.length == 2) { auto args = getMember!ArgumentList(1); auto vidx = args.interpret(sc); Value idx; if(vidx.values.length != 1) return semanticErrorValue("exactly one value expected as array index"); idx = vidx.values[0]; return val.opIndex(idx); } else if(members.length == 3) { Value beg = getMember(1).interpret(sc); Value end = getMember(2).interpret(sc); return val.opSlice(beg, end); } assert(members.length == 1); // full slice Node nodelen = val.getType().getScope().resolve("length", val.getType(), false); if(nodelen) return val.opSlice(Value.create(0), nodelen.interpret(sc)); return val; case TOK_lparen: TupleValue args; if(members.length == 2) args = getMember!ArgumentList(1).interpret(sc); else args = new TupleValue; return val.opCall(sc, args); case TOK_plusplus: Value v2 = val.getType().createValue(sc, val); val.opBin(sc, TOK_addass, Value.create(cast(byte)1)); return v2; case TOK_minusminus: Value v2 = val.getType().createValue(sc, val); val.opBin(sc, TOK_minass, Value.create(cast(byte)1)); return v2; case TOK_new: default: return super.interpret(sc); } } override void toD(CodeWriter writer) { Expression expr = getExpression(); bool paren = (expr.getPrecedence() < getPrecedence()); writeExpr(writer, expr, paren); switch(id) { case TOK_lbracket: writer("["); if(members.length == 2) writer(getMember!ArgumentList(1)); else if(members.length == 3) { writer(getMember!Expression(1)); writer(" .. "); writer(getMember!Expression(2)); } writer("]"); break; case TOK_lparen: writer("("); if(members.length > 1) writer(getMember!ArgumentList(1)); writer(")"); break; case TOK_dot: case TOK_new: writer(".", getMember(1)); break; default: writeOperator(writer, id, Spaces.Right); break; } } } class DotExpression : PostfixExpression { mixin ForwardCtor!(); Identifier getIdentifier() { return id == TOK_new ? null : getMember!Identifier(1); } Node resolved; override Node resolve() { if(resolved) return resolved; auto expr = getExpression(); auto etype = expr.calcType(); switch(id) { case TOK_new: auto nexpr = getMember!NewExpression(1); resolved = nexpr.calcType(); break; default: auto id = getMember!Identifier(1); if(auto pt = cast(TypePointer)etype) etype = pt.getNextType(); Scope s = etype.getScope(); resolved = s ? s.resolve(id.ident, id, false) : null; break; } return resolved; } override Type calcType() { if(type) return type; if(auto n = resolve()) type = n.calcType(); else if(id == TOK_new) type = semanticErrorType("cannot resolve type of new expression ", getMember(1)); else type = semanticErrorType("cannot resolve type of property ", getMember!Identifier(1).ident); return type; } override Value interpret(Context sc) { Expression expr = getExpression(); Value val = expr.interpret(sc); if(!type) calcType(); if(!resolved) return Singleton!ErrorValue.get(); // calcType already produced an error //auto id = getMember!Identifier(1); auto ctx = new AggrContext(sc, val); if(expr.id == TOK_super) ctx.virtualCall = false; return resolved.interpret(ctx); } } //ArgumentList: // [Expression...] class ArgumentList : Node { mixin ForwardCtor!(); override void _semantic(Scope sc) { foreach(m; members) m.semantic(sc); } override TupleValue interpret(Context sc) { TupleValue args = new TupleValue; foreach(m; members) args.addValue(m.interpret(sc)); return args; } override void toD(CodeWriter writer) { bool writeSep = false; foreach(m; members) { if(writeSep) writer(", "); writeSep = true; bool paren = false; if(auto expr = cast(Expression) m) paren = (expr.getPrecedence() <= PREC.expr); if(paren) writer("(", m, ")"); else writer(m); } } } //PrimaryExpression: // Identifier // . Identifier // TemplateInstance // this // super // null // true // false // $ // __FILE__ // __LINE__ // IntegerLiteral // FloatLiteral // CharacterLiteral // StringLiterals // ArrayLiteral // AssocArrayLiteral // Lambda // FunctionLiteral // AssertExpression // MixinExpression // ImportExpression // TypeProperty // Typeof // TypeidExpression // IsExpression // ( Expression ) // ( Type ) . Identifier // TraitsExpression class PrimaryExpression : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } override Value interpret(Context sc) { switch(id) { case TOK_super: case TOK_this: Value v = sc ? sc.getThis() : null; if(!v) return semanticErrorValue("this needs context"); return v; case TOK_true: return Value.create(true); case TOK_false: return Value.create(false); case TOK_null: return new NullValue; case TOK___LINE__: return Value.create(span.start.line); case TOK___FILE__: return createStringValue(getModuleFilename()); case TOK_dollar: default: return super.interpret(sc); } } override Type calcType() { if(type) return type; switch(id) { case TOK_this: case TOK_super: auto sc = getScope(); type = sc ? sc.getThisType() : null; if(id == TOK_super) if(auto clss = cast(Class)type) if(auto bc = clss.getBaseClass()) type = bc.calcType(); if(!type) type = semanticErrorType("this needs context"); break; case TOK_true: case TOK_false: type = createBasicType(TOK_bool); break; case TOK_null: type = Singleton!NullType.get(); break; case TOK_dollar: case TOK___LINE__: type = createBasicType(TOK_uint); break; case TOK___FILE__: type = getTypeString!char(); break; default: return super.calcType(); } return type; } override void toD(CodeWriter writer) { writer(id); } } //ArrayLiteral: // [ ArgumentList ] class ArrayLiteral : Expression { bool isAssoc; mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } ArgumentList getArgumentList() { return getMember!ArgumentList(0); } override void toD(CodeWriter writer) { writer("["); writer.writeArray(members); writer("]"); } override void _semantic(Scope sc) { super._semantic(sc); auto argl = getArgumentList(); int cntPairs = 0; int cntIndex = 0; foreach(m; argl.members) { m.semantic(sc); if(auto kv = cast(KeyValuePair) m) { Type kt = kv.getKey().calcType(); Type st = BasicType.getSizeType(); if(st.convertableFrom(kt, Type.ConversionFlags.kImpliciteConversion)) cntIndex++; cntPairs++; } else break; } if(cntPairs == argl.members.length && cntIndex < argl.members.length) isAssoc = true; if(!isAssoc) { type = new TypeDynamicArray; if(argl.members.length) { Type vt = argl.members[0].calcType(); foreach(m; argl.members[1..$]) vt = vt.commonType(m.calcType()); type.addMember(vt.clone()); } else type.addMember(new AutoType(TOK_auto, span)); } } override Type calcType() { if(type) return type; semantic(getScope()); return type; } override Value interpret(Context sc) { TupleValue val; if(auto args = getArgumentList()) val = args.interpret(sc); else val = new TupleValue; if(auto tda = cast(TypeDynamicArray) calcType()) { auto telem = tda.getNextType(); auto vda = new DynArrayValue(tda); vda.setLength(sc, val.values.length); for(size_t i = 0; i < val.values.length; i++) vda.setItem(sc, i, val.values[i]); debug vda.sval = vda.toStr(); return vda; } return val; } } //VoidInitializer: // void class VoidInitializer : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } override Type calcType() { if(!type) type = createBasicType(TOK_void); return type; } override void toD(CodeWriter writer) { writer("void"); } override Value interpret(Context sc) { return theVoidValue(); } } // used for Expression_opt in for and return statements class EmptyExpression : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.expr; } override void toD(CodeWriter writer) { } } //KeyValuePair: // [Expression Expression] class KeyValuePair : BinaryExpression { mixin ForwardCtor!(); static this() { precedence[TOK_colon] = PREC.assign; } this() {} // default constructor needed for clone() this(Token tok) { super(TOK_colon, tok.span); } Expression getKey() { return getMember!Expression(0); } Expression getValue() { return getMember!Expression(1); } } //FunctionLiteral: // id [ Type_opt ParameterList_opt FunctionBody ] attr class FunctionLiteral : Expression { mixin ForwardCtor!(); Type getType() { return members.length > 2 ? getMember!Type(0) : null; } override ParameterList getParameterList() { return getMember!ParameterList(members.length - 2); } FunctionBody getFunctionBody() { return getMember!FunctionBody(members.length - 1); } override PREC getPrecedence() { return PREC.primary; } override void toD(CodeWriter writer) { if(id != 0) writer(id, " "); if(Type type = getType()) writer(type, " "); writer(getParameterList(), " "); writer.writeAttributesAndAnnotations(attr, annotation, false); writer(getFunctionBody()); } override bool createsScope() const { return true; } override void _semantic(Scope sc) { if(auto t = getType()) t.semantic(sc); sc = enterScope(sc); getFunctionBody().semantic(sc); sc = sc.pop(); } TypeFunction func; override Type calcType() { if(!func) { auto pl = getParameterList(); if(!pl) pl = new ParameterList(); if(id == TOK_function) { auto funclit = new TypeFunctionLiteral; funclit.paramList = pl; func = funclit; } else { auto funclit = new TypeDelegateLiteral; funclit.paramList = pl; func = funclit; } /+ auto rt = getType(); if(!rt) rt = new AutoType(TOK_auto, span); else rt = rt.clone(); func.addMember(rt); auto pl = getParameterList(); if(!pl) pl = new ParameterList(); else pl = pl.clone(); func.addMember(pl); +/ auto decl = new FuncLiteralDeclarator; decl.type = func; decl.funcbody = getFunctionBody(); func.funcDecl = decl; } return func; } override Value interpret(Context sc) { if(!func) calcType(); if(id == TOK_function) { auto fn = new FunctionValue; fn.functype = func; return fn; } else { auto dg = new DelegateValue; dg.context = sc; dg.functype = func; return dg; } } } //Lambda: // [ ParameterList Expression ] class Lambda : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } override void toD(CodeWriter writer) { writer(getMember(0), " => ", getMember(1)); } } class TypeFunctionLiteral : TypeFunction { override Type getReturnType() { if (returnType) return returnType; if(members.length) returnType = getMember!Type(0); // TODO: infer return type from code if (!returnType) returnType = new AutoType; return returnType; } } class TypeDelegateLiteral : TypeDelegate { override Type getReturnType() { if (returnType) return returnType; if(members.length) returnType = getMember!Type(0); // TODO: infer return type from code if (!returnType) returnType = new AutoType; return returnType; } } class FuncLiteralDeclarator : Declarator { FunctionBody funcbody; override Value interpretCall(Context sc) { return funcbody.interpret(sc); } } //StructLiteral: // [ArrayValueList] class StructLiteral : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } override void toD(CodeWriter writer) { writer("{ ", getMember(0), " }"); } override Value interpret(Context sc) { return getMember(0).interpret(sc); } } //AssertExpression: // assert ( AssignExpression ) // assert ( AssignExpression , AssignExpression ) class AssertExpression : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } Expression getExpression() { return getMember!Expression(0); } Expression getMessage() { return getMember!Expression(1); } override void toD(CodeWriter writer) { writer("assert("); writer(getExpression()); if(Expression msg = getMessage()) writer(", ", msg); writer(")"); } override Value interpret(Context sc) { auto actx = new AssertContext(sc); auto cond = getExpression().interpret(actx); if(!cond.toBool()) { string msg; if(auto m = getMessage()) msg = m.interpret(sc).toMixin(); else msg = "assertion " ~ writeD(getExpression()) ~ " failed"; foreach(id, val; actx.identVal) msg ~= "\n\t" ~ writeD(id) ~ " = " ~ val.toStr(); return semanticErrorValue(msg); } return theVoidValue; } } //MixinExpression: // mixin ( AssignExpression ) class MixinExpression : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } Expression getExpression() { return getMember!Expression(0); } Expression resolved; override void toD(CodeWriter writer) { if(resolved) resolved.toD(writer); else writer("mixin(", getMember!Expression(0), ")"); } override void _semantic(Scope sc) { if(resolved) return; Value v = getMember(0).interpretCatch(nullContext); string s = v.toMixin(); Parser parser = new Parser; if(auto prj = sc.getProject()) parser.saveErrors = prj.saveErrors; Node n = parser.parseExpression(s, span); resolved = cast(Expression) n; if(resolved) { addMember(resolved); resolved.semantic(sc); } } override Type calcType() { if(!resolved) semantic(getScope()); if(resolved) return resolved.calcType(); return new ErrorType; } override Value interpret(Context sc) { if(!resolved) semantic(getScope()); if(resolved) return resolved.interpret(sc); return semanticErrorValue("cannot interpret mixin"); } } //ImportExpression: // import ( AssignExpression ) class ImportExpression : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } Expression getExpression() { return getMember!Expression(0); } override Type calcType() { if(!type) type = getTypeString!char(); return type; } override void toD(CodeWriter writer) { writer("import(", getMember!Expression(0), ")"); } } //TypeidExpression: // typeid ( Type ) // typeid ( Expression ) class TypeIdExpression : Expression { mixin ForwardCtor!(); override PREC getPrecedence() { return PREC.primary; } override void toD(CodeWriter writer) { writer("typeid(", getMember(0), ")"); } } //IsExpression: // is ( Type ) // is ( Type : TypeSpecialization ) // is ( Type == TypeSpecialization ) // is ( Type Identifier ) // is ( Type Identifier : TypeSpecialization ) // is ( Type Identifier == TypeSpecialization ) // is ( Type Identifier : TypeSpecialization , TemplateParameterList ) // is ( Type Identifier == TypeSpecialization , TemplateParameterList ) // //TypeSpecialization: // Type // struct // union // class // interface // enum // function // delegate // super // const // immutable // inout // shared // return // class IsExpression : PrimaryExpression { int kind; string ident; this() {} // default constructor needed for clone() this(Token tok) { super(TOK_is, tok.span); } override IsExpression clone() { IsExpression n = static_cast!IsExpression(super.clone()); n.kind = kind; n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.kind == kind && tn.ident == ident; } Type getType() { return getMember!Type(0); } TypeSpecialization getTypeSpecialization() { return members.length > 1 ? getMember!TypeSpecialization(1) : null; } override void toD(CodeWriter writer) { writer("is(", getType()); if(ident.length) { writer(" "); writer.writeIdentifier(ident); } if(kind != 0) writer(" ", kind, " "); if(auto ts = getTypeSpecialization()) writer(ts); writer(")"); } override Type calcType() { if(!type) type = createBasicType(TOK_bool); return type; } } class TypeSpecialization : Node { mixin ForwardCtor!(); Type getType() { return getMember!Type(0); } override void toD(CodeWriter writer) { if(id != 0) writer(id); else writer(getMember(0)); } } class IdentifierExpression : PrimaryExpression { bool global; // semantic data Node resolved; this() {} // default constructor needed for clone() this(Token tok) { super(TOK_Identifier, tok.span); } override IdentifierExpression clone() { IdentifierExpression n = static_cast!IdentifierExpression(super.clone()); n.global = global; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.global == global; } Identifier getIdentifier() { return getMember!Identifier(0); } override void toD(CodeWriter writer) { if(global) writer("."); writer(getIdentifier()); } override void toC(CodeWriter writer) { //resolve(); if(resolved) { Module thisMod = getModule(); Module thatMod = resolved.getModule(); if(global || thisMod is thatMod) { thatMod.writeNamespace(writer); } } writer(getIdentifier()); } override Node resolve() { if(resolved) return resolved; if(!scop) semantic(getScope()); auto id = getIdentifier(); resolved = scop.resolveWithTemplate(id.ident, scop, id); return resolved; } override void _semantic(Scope sc) { if(global) scop = getModule().scop; else scop = sc; resolve(); } override Type calcType() { if(type) return type; if(!scop) semantic(getScope()); if(resolved) type = resolved.calcType(); if(!type) return semanticErrorType("cannot determine type"); return type; } override ArgumentList getFunctionArguments() { if(parent) return parent.getFunctionArguments(); return null; } override Value interpret(Context sc) { if(!resolved) semantic(getScope()); if(!resolved) return semanticErrorValue("unresolved identifier ", writeD(this)); Value v = resolved.interpret(sc); if(auto actx = cast(AssertContext)sc) actx.identVal[this] = v; return v; } } class IntegerLiteralExpression : PrimaryExpression { string txt; ulong value; // literals are never negative by themselves bool unsigned; bool lng; bool forceInt; // set in semantic pass bool forceShort; this() {} // default constructor needed for clone() this(Token tok) { super(tok); txt = tok.txt; initValue(); } void initValue() { string val = txt; while(val.length > 1) { if(val[$-1] == 'L') lng = true; else if(val[$-1] == 'U' || val[$-1] == 'u') unsigned = true; else break; val = val[0..$-1]; } int radix = 10; if(val[0] == '0' && val.length > 1) { if(val[1] == 'x' || val[1] == 'X') { radix = 16; val = val[2..$]; } else if(val[1] == 'b' || val[1] == 'B') { radix = 2; val = val[2..$]; } else { radix = 8; } unsigned = true; } val = removechars(val, "_"); value = parse!ulong(val, radix); } override IntegerLiteralExpression clone() { IntegerLiteralExpression n = static_cast!IntegerLiteralExpression(super.clone()); n.txt = txt; n.value = value; n.unsigned = unsigned; n.lng = lng; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.txt == txt && tn.value == value && tn.unsigned == unsigned && tn.lng == lng; } override void toD(CodeWriter writer) { writer(txt); } void forceLargerType(Type t) { if(t.id == TOK_int || t.id == TOK_uint) forceInt = true; if(t.id == TOK_short || t.id == TOK_ushort) forceShort = true; } override Type calcType() { if(type) return type; long lim = unsigned ? 0x1_0000_0000 : 0x8000_0000; if(lng || value >= lim) if(unsigned) type = new BasicType(TOK_ulong, span); else type = new BasicType(TOK_long, span); else if(true || forceInt || value >= (lim >> 16)) if(unsigned) type = new BasicType(TOK_uint, span); else type = new BasicType(TOK_int, span); else if(forceShort || value >= (lim >= 24)) if(unsigned) type = new BasicType(TOK_ushort, span); else type = new BasicType(TOK_short, span); else if(unsigned) type = new BasicType(TOK_ubyte, span); else type = new BasicType(TOK_byte, span); return type; } override void _semantic(Scope sc) { calcType().semantic(sc); } Value _interpret(Context sc) { if(lng || value >= 0x80000000) if(unsigned) return Value.create(cast(ulong)value); else return Value.create(cast(long)value); else if(true || forceInt || value >= 0x8000) if(unsigned) return Value.create(cast(uint)value); else return Value.create(cast(int)value); else if(forceShort || value >= 0x80) if(unsigned) return Value.create(cast(ushort)value); else return Value.create(cast(short)value); else if(unsigned) return Value.create(cast(ubyte)value); else return Value.create(cast(byte)value); } override Value interpret(Context sc) { Value v = _interpret(sc); v.literal = true; return v; } int getInt() { if(value > int.max) semanticErrorPos(span.start, text(value, " too large to fit an integer")); return cast(int) value; } uint getUInt() { if(value > uint.max) semanticErrorPos(span.start, text(value, " too large to fit an unsigned integer")); return cast(uint) value; } } class FloatLiteralExpression : PrimaryExpression { string txt; real value; bool complex; bool lng; bool flt; this() {} // default constructor needed for clone() this(Token tok) { super(tok); txt = tok.txt; initValue(); } void initValue() { string val = txt; while(val.length > 1) { if(val[$-1] == 'L') lng = true; else if(val[$-1] == 'f' || val[$-1] == 'F') flt = true; else if(val[$-1] == 'i') complex = true; else if(val[$-1] == '.') { val = val[0..$-1]; break; } else break; val = val[0..$-1]; } val = removechars(val, "_"); value = parse!real(val); } override FloatLiteralExpression clone() { FloatLiteralExpression n = static_cast!FloatLiteralExpression(super.clone()); n.txt = txt; n.value = value; n.complex = complex; n.lng = lng; n.flt = flt; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.txt == txt && tn.value == value && tn.complex == complex && tn.flt == flt && tn.lng == lng; } override Type calcType() { if(type) return type; if(complex) if(lng) type = new BasicType(TOK_ireal, span); else if(flt) type = new BasicType(TOK_ifloat, span); else type = new BasicType(TOK_idouble, span); else if(lng) type = new BasicType(TOK_real, span); else if(flt) type = new BasicType(TOK_float, span); else type = new BasicType(TOK_double, span); return type; } override void _semantic(Scope sc) { calcType().semantic(sc); } Value _interpret(Context sc) { if(complex) if(lng) return Value.create(cast(ireal) (1i * value)); else if(flt) return Value.create(cast(ifloat) (1i * value)); else return Value.create(cast(idouble) (1i * value)); else if(lng) return Value.create(cast(real)value); else if(flt) return Value.create(cast(float)value); else return Value.create(cast(double)value); } override Value interpret(Context sc) { Value v = _interpret(sc); v.literal = true; return v; } override void toD(CodeWriter writer) { writer(txt); } } class StringLiteralExpression : PrimaryExpression { string txt; string rawtxt; this() {} // default constructor needed for clone() static string raw(string s) { if(s.length == 0) return s; if(s.length > 2 && s[0] == 'q' && s[1] == '{' && s[$-1] == '}') return s[2..$-1]; // TODO: missing hex/escape translation and delimiter string handling size_t p = 0; while(p < s.length && s[p] != '"' && s[p] != '`') p++; if(p >= s.length) return s; size_t q = s.length - 1; while(q > p && s[q] != s[p]) q--; if(q <= p) return s; return s[p+1..q]; } unittest { assert(raw(`r"abc"`) == "abc"); assert(raw(`q{abc}`) == "abc"); assert(raw(`"abc"c`) == "abc"); } this(Token tok) { super(tok); txt = tok.txt; rawtxt = raw(txt); } void addText(Token tok) { txt ~= " " ~ tok.txt; rawtxt ~= raw(tok.txt); } override StringLiteralExpression clone() { StringLiteralExpression n = static_cast!StringLiteralExpression(super.clone()); n.txt = txt; n.rawtxt = rawtxt; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.txt == txt; } override Type calcType() { if(!type) { switch(txt[$-1]) { default: case 'c': type = getTypeString!char(); break; case 'w': type = getTypeString!wchar(); break; case 'd': type = getTypeString!dchar(); break; } } return type; } override void _semantic(Scope sc) { calcType(); } override Value interpret(Context sc) { Value v = Value.create(rawtxt); v.literal = true; return v; } override void toD(CodeWriter writer) { writer(txt); } } class CharacterLiteralExpression : PrimaryExpression { string txt; this() {} // default constructor needed for clone() this(Token tok) { super(tok); txt = tok.txt; } override CharacterLiteralExpression clone() { CharacterLiteralExpression n = static_cast!CharacterLiteralExpression(super.clone()); n.txt = txt; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.txt == txt; } override Type calcType() { if(type) return type; if(txt.length >= 3) { if(txt[$-1] == 'd') type = new BasicType(TOK_dchar, span); else if(txt[$-1] == 'w') type = new BasicType(TOK_wchar, span); } if(!type) type = new BasicType(TOK_char, span); return type; } Value _interpret(Context sc) { if(txt.length < 3) return Value.create(char.init); // TODO: missing escape decoding dchar ch = txt[1]; if(txt[$-1] == 'd') return Value.create(ch); if(txt[$-1] == 'w') return Value.create(cast(wchar)ch); return Value.create(cast(char)ch); } override Value interpret(Context sc) { Value v = _interpret(sc); v.literal = true; return v; } override void _semantic(Scope sc) { calcType().semantic(sc); } override void toD(CodeWriter writer) { writer(txt); } } //TypeProperty: // [Type Identifier] class TypeProperty : PrimaryExpression { Node resolved; this() {} // default constructor needed for clone() this(Token tok) { super(0, tok.span); } Type getType() { return getMember!Type(0); } Identifier getProperty() { return getMember!Identifier(1); } override void toD(CodeWriter writer) { Type type = getType(); if(type.propertyNeedsParens()) writer("(", getType(), ").", getProperty()); else writer(getType(), ".", getProperty()); } override Node resolve() { if(resolved) return resolved; auto id = getProperty(); resolved = getType().getScope().resolve(id.ident, id); return resolved; } override Type calcType() { if(type) return type; if(auto n = resolve()) type = n.calcType(); else type = semanticErrorType("cannot determine type of property ", getProperty().ident); return type; } override Value interpret(Context sc) { if(!type) calcType(); if(!resolved) return Singleton!ErrorValue.get(); // calcType already produced an error return resolved.interpret(nullContext); } } class StructConstructor : PrimaryExpression { this() {} // default constructor needed for clone() this(Token tok) { super(0, tok.span); } Type getType() { return getMember!Type(0); } ArgumentList getArguments() { return getMember!ArgumentList(1); } override void toD(CodeWriter writer) { Type type = getType(); if(type.propertyNeedsParens()) writer("(", getType(), ")(", getArguments(), ")"); else writer(getType(), "(", getArguments(), ")"); } } class TraitsExpression : PrimaryExpression { this() {} // default constructor needed for clone() this(Token tok) { super(TOK___traits, tok.span); } override void toD(CodeWriter writer) { writer("__traits(", getMember(0)); if(members.length > 1) writer(", ", getMember(1)); writer(")"); } } class TraitsArguments : TemplateArgumentList { mixin ForwardCtorNoId!(); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/aggr.d0000664000175000017500000006421512776214756026416 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.aggr; import vdc.util; import vdc.lexer; import vdc.logger; import vdc.semantic; import vdc.interpret; import vdc.ast.node; import vdc.ast.mod; import vdc.ast.tmpl; import vdc.ast.decl; import vdc.ast.expr; import vdc.ast.misc; import vdc.ast.type; import vdc.ast.writer; import stdext.array; import stdext.util; import std.algorithm; import std.conv; //Aggregate: // [TemplateParameterList_opt Constraint_opt BaseClass... StructBody] class Aggregate : Type { mixin ForwardCtor!(); override bool propertyNeedsParens() const { return true; } abstract bool isReferenceType() const; bool hasBody = true; bool hasTemplArgs; bool hasConstraint; string ident; TemplateParameterList getTemplateParameterList() { return hasTemplArgs ? getMember!TemplateParameterList(0) : null; } Constraint getConstraint() { return hasConstraint ? getMember!Constraint(1) : null; } StructBody getBody() { return hasBody ? getMember!StructBody(members.length - 1) : null; } override Aggregate clone() { Aggregate n = static_cast!Aggregate(super.clone()); n.hasBody = hasBody; n.hasTemplArgs = hasTemplArgs; n.hasConstraint = hasConstraint; n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.hasBody == hasBody && tn.hasTemplArgs == hasTemplArgs && tn.hasConstraint == hasConstraint && tn.ident == ident; } void bodyToD(CodeWriter writer) { if(auto bdy = getBody()) { writer.nl; writer(getBody()); writer.nl; } else { writer(";"); writer.nl; } } void tmplToD(CodeWriter writer) { if(TemplateParameterList tpl = getTemplateParameterList()) writer(tpl); if(auto constraint = getConstraint()) writer(constraint); } override bool createsScope() const { return true; } override Scope enterScope(ref Scope nscope, Scope sc) { if(!nscope) { nscope = new AggregateScope; nscope.annotations = sc.annotations; nscope.attributes = sc.attributes; nscope.mod = sc.mod; nscope.parent = sc; nscope.node = this; addMemberSymbols(nscope); return nscope; } return sc.push(nscope); } override void _semantic(Scope sc) { // TODO: TemplateParameterList, Constraint if(auto bdy = getBody()) { sc = super.enterScope(sc); bdy.semantic(sc); sc = sc.pop(); } if(!initVal) { if(mapName2Value.length == 0) _initFields(0); if(mapName2Method.length == 0 && constructors.length == 0) _initMethods(); } } override void addSymbols(Scope sc) { if(ident.length) sc.addSymbol(ident, this); } // always tree internal references size_t mapDeclOffset; size_t[Declarator] mapDecl2Value; size_t[string] mapName2Value; Declarator[string] mapName2Method; bool[Declarator] isMethod; Constructor[] constructors; TupleValue initVal; TypeValue typeVal; abstract TupleValue _initValue(); void _setupInitValue(AggrValue sv) { auto bdy = getBody(); if(!bdy) return; auto ctx = new AggrContext(nullContext, sv); ctx.scop = scop; bdy.iterateDeclarators(false, false, (Declarator decl) { Type type = decl.calcType(); Value value; if(auto expr = decl.getInitializer()) value = type.createValue(ctx, expr.interpret(ctx)); else value = type.createValue(ctx, null); debug value.ident = decl.ident; sv.addValue(value); }); } void _initValues(AggrContext thisctx, Value[] initValues) { if(!initVal) { initVal = _initValue(); _initMethods(); } auto inst = static_cast!AggrValue(thisctx.instance); mapDeclOffset = inst.values.length; inst.setValuesLength(mapDeclOffset + mapDecl2Value.length); foreach(decl, idx; mapDecl2Value) { Value v = mapDeclOffset + idx < initValues.length ? initValues[mapDeclOffset + idx] : initVal.values[idx]; Type t = decl.calcType(); v = t.createValue(thisctx, v); debug v.ident = decl.ident; inst.values[mapDeclOffset + idx] = v; } } ValueType _createValue(ValueType, Args...)(Context ctx, Value initValue, Args a) { //! TODO: check type of initValue ValueType sv = new ValueType(a); auto bdy = getBody(); if(!bdy) { semanticErrorValue("cannot create value of incomplete type ", ident); return sv; } Value[] initValues; if(initValue) { auto tv = cast(TupleValue) initValue; if(!tv) { semanticErrorValue("cannot initialize a ", sv, " from ", initValue); return sv; } initValues = tv.values; } auto aggr = cast(AggrValue) initValue; if(aggr) sv.outer = aggr.outer; else if(!(attr & Attr_Static) && ctx) sv.outer = ctx; if(initValue) logInfo("creating new instance of %s with args ", ident, initValue.toStr()); else logInfo("creating new instance of %s", ident); auto thisctx = new AggrContext(ctx, sv); thisctx.scop = scop; _initValues(thisctx, initValues); // appends to sv.values if(constructors.length > 0) { doCall(constructors[0], thisctx, constructors[0].getParameterList(), initValue); } return sv; } int _initFields(int off) { if(auto bdy = getBody()) bdy.iterateDeclarators(false, false, (Declarator decl) { mapDecl2Value[decl] = off; mapName2Value[decl.ident] = off++; }); return off; } void _initMethods() { if(auto bdy = getBody()) { bdy.iterateDeclarators(false, true, (Declarator decl) { isMethod[decl] = true; mapName2Method[decl.ident] = decl; }); bdy.iterateConstructors(false, (Constructor ctor) { if(!ctor.isPostBlit()) constructors ~= ctor; }); } } override Value getProperty(Value sv, string prop, bool virtualCall) { if(auto pidx = prop in mapName2Value) { if(AggrValue av = cast(AggrValue)sv) return av.values[*pidx]; } else if(auto pdecl = prop in mapName2Method) { return getProperty(sv, *pdecl, virtualCall); } return null; } override Value getProperty(Value sv, Declarator decl, bool virtualCall) { if(auto tv = cast(TypeValue) sv) { if(decl.needsContext) return new TypeValue(decl.calcType()); return decl.interpret(nullContext); } if(auto rv = cast(ReferenceValue) sv) sv = rv.instance; AggrValue av = static_cast!AggrValue(sv); if(Value v = _getProperty(av, decl, virtualCall)) return v; if(av && av.outer) return av.outer.getValue(decl); return null; } Value _getProperty(AggrValue av, Declarator decl, bool virtualCall) { if(auto pidx = decl in mapDecl2Value) { if(!av) return semanticErrorValue("member access needs non-null instance pointer"); return av.values[*pidx + mapDeclOffset]; } if(decl in isMethod) { if(!av) return semanticErrorValue("method access needs non-null instance pointer"); if(virtualCall) decl = findOverride(av, decl); auto func = decl.calcType(); auto cv = new AggrContext(nullContext, av); cv.scop = scop; Value dgv = func.createValue(cv, null); return dgv; } return null; } @disable override Value _interpretProperty(Context ctx, string prop) { if(Value v = getStaticProperty(prop)) return v; Value vt = ctx.getThis(); auto av = cast(AggrValue) vt; if(!av) if(auto rv = cast(ReferenceValue) vt) av = rv.instance; if(av) if(Value v = getProperty(av, prop, true)) return v; return super._interpretProperty(ctx, prop); } Value getStaticProperty(string prop) { if(!scop && parent) semantic(parent.getScope()); if(!scop) return semanticErrorValue(this, ": no scope set in lookup of ", prop); Scope.SearchSet res = scop.search(prop, false, true, true); if(res.length == 0) return null; if(res.length > 1) semanticError("ambiguous identifier " ~ prop); foreach(n, b; res) { if(n.attr & Attr_Static) return n.interpret(nullContext); } return null; // delay into getProperty } override Type opCall(Type args) { // must be a constructor return this; } override Value interpret(Context sc) { if(!typeVal) typeVal = new TypeValue(this); return typeVal; } final Declarator findOverride(AggrValue av, Declarator decl) { Aggregate clss = av.getType(); return clss._findOverride(av, decl); } Declarator _findOverride(AggrValue av, Declarator decl) { return decl; } } class AggregateScope : Scope { override Type getThisType() { return static_cast!Aggregate(node); } } class Struct : Aggregate { this() {} // default constructor needed for clone() override bool isReferenceType() const { return false; } this(ref const(TextSpan) _span) { super(_span); } this(Token tok) { super(tok); ident = tok.txt; } override void toD(CodeWriter writer) { if(writer.writeReferencedOnly && semanticSearches == 0) return; writer("struct "); writer.writeIdentifier(ident); tmplToD(writer); if(writer.writeClassImplementations) bodyToD(writer); } override TupleValue _initValue() { StructValue sv = new StructValue(this); _setupInitValue(sv); return sv; } override Value createValue(Context ctx, Value initValue) { return _createValue!StructValue(ctx, initValue, this); } } class Union : Aggregate { this() {} // default constructor needed for clone() override bool isReferenceType() const { return false; } this(ref const(TextSpan) _span) { super(_span); } this(Token tok) { super(tok); ident = tok.txt; } override void toD(CodeWriter writer) { if(writer.writeReferencedOnly && semanticSearches == 0) return; writer("union "); writer.writeIdentifier(ident); tmplToD(writer); if(writer.writeClassImplementations) bodyToD(writer); } override TupleValue _initValue() { UnionValue sv = new UnionValue(this); _setupInitValue(sv); return sv; } override Value createValue(Context ctx, Value initValue) { return _createValue!UnionValue(ctx, initValue, this); } } class InheritingAggregate : Aggregate { mixin ForwardCtor!(); override bool isReferenceType() const { return true; } BaseClass[] baseClasses; void addBaseClass(BaseClass bc) { addMember(bc); baseClasses ~= bc; } override Scope enterScope(ref Scope nscope, Scope sc) { if(!nscope) { nscope = new InheritingScope; nscope.annotations = sc.annotations; nscope.attributes = sc.attributes; nscope.mod = sc.mod; nscope.parent = sc; nscope.node = this; addMemberSymbols(nscope); return nscope; } return sc.push(nscope); } override InheritingAggregate clone() { InheritingAggregate n = static_cast!InheritingAggregate(super.clone()); for(int m = 0; m < members.length; m++) if(arrIndex(cast(Node[]) baseClasses, members[m]) >= 0) n.baseClasses ~= static_cast!BaseClass(n.members[m]); return n; } override bool convertableFrom(Type from, ConversionFlags flags) { if(super.convertableFrom(from, flags)) return true; if(flags & ConversionFlags.kAllowBaseClass) if(auto inh = cast(InheritingAggregate) from) { foreach(bc; inh.baseClasses) if(auto inhbc = bc.getClass()) if(convertableFrom(inhbc, flags)) return true; } return false; } @disable override Value _interpretProperty(Context ctx, string prop) { foreach(bc; baseClasses) if(Value v = bc._interpretProperty(ctx, prop)) return v; return super._interpretProperty(ctx, prop); } override void toD(CodeWriter writer) { // class/interface written by derived class writer.writeIdentifier(ident); tmplToD(writer); if(writer.writeClassImplementations) { if(baseClasses.length) { if(ident.length > 0) writer(" : "); writer(baseClasses[0]); foreach(bc; baseClasses[1..$]) writer(", ", bc); } bodyToD(writer); } } override void _initValues(AggrContext thisctx, Value[] initValues) { if(baseClasses.length > 0) if(auto bc = cast(Class)baseClasses[0].getClass()) bc._initValues(thisctx, initValues); super._initValues(thisctx, initValues); } override Value _getProperty(AggrValue av, Declarator decl, bool virtualCall) { if(Value v = super._getProperty(av, decl, virtualCall)) return v; if(baseClasses.length > 0) if(auto bc = baseClasses[0].getClass()) if(Value v = bc._getProperty(av, decl, virtualCall)) return v; return null; } override Declarator _findOverride(AggrValue av, Declarator decl) { if(auto pdecl = decl.ident in mapName2Method) return *pdecl; if(baseClasses.length > 0) if(auto bc = baseClasses[0].getClass()) return bc._findOverride(av, decl); return decl; } } class InheritingScope : AggregateScope { override void searchParents(string ident, bool inParents, bool privateImports, bool publicImports, ref SearchSet syms) { auto ia = static_cast!InheritingAggregate(node); foreach(bc; ia.baseClasses) if(auto sc = bc.calcType().getScope()) addunique(syms, sc.search(ident, false, false, true)); super.searchParents(ident, inParents, privateImports, publicImports, syms); } } class Class : InheritingAggregate { this() {} // default constructor needed for clone() this(ref const(TextSpan) _span) { super(_span); } this(Token tok) { super(tok); ident = tok.txt; } override void toD(CodeWriter writer) { if(writer.writeReferencedOnly && semanticSearches == 0) return; writer("class "); super.toD(writer); } Class getBaseClass() { if(baseClasses.length > 0) if(auto bc = cast(Class)baseClasses[0].getClass()) return bc; return null; } override TupleValue _initValue() { ClassInstanceValue sv = new ClassInstanceValue(this); _setupInitValue(sv); return sv; } override Value createValue(Context ctx, Value initValue) { if(!scop && parent) semantic(parent.getScope()); auto v = new ClassValue(this); if(!initValue) return v; if(auto rv = cast(ReferenceValue)initValue) return v.opBin(ctx, TOK_assign, rv); v.instance = _createValue!ClassInstanceValue(ctx, initValue, this); v.validate(); return v; } } class AnonymousClass : Class { mixin ForwardCtorNoId!(); override void toD(CodeWriter writer) { // "class(args) " written by AnonymousClassType, so skip Class.toD InheritingAggregate.toD(writer); } override TupleValue _initValue() { ClassInstanceValue sv = new ClassInstanceValue(this); _setupInitValue(sv); return sv; } override Value createValue(Context ctx, Value initValue) { auto v = new ClassValue(this); if(!initValue) return v; if(auto rv = cast(ReferenceValue)initValue) return v.opBin(ctx, TOK_assign, rv); v.instance = _createValue!ClassInstanceValue(ctx, initValue, this); v.validate(); return v; } } // Interface conflicts with object.Interface class Intrface : InheritingAggregate { this() {} // default constructor needed for clone() this(ref const(TextSpan) _span) { super(_span); } this(Token tok) { super(tok); ident = tok.txt; } override void toD(CodeWriter writer) { if(writer.writeReferencedOnly && semanticSearches == 0) return; writer(TOK_interface, " "); super.toD(writer); } override TupleValue _initValue() { semanticError("Intrface::_initValue should not be called!"); return new TupleValue; } override Value createValue(Context ctx, Value initValue) { Value v = new InterfaceValue(this); if(!initValue) return v; return v.opBin(ctx, TOK_assign, initValue); } } // BaseClass: // [IdentifierList] class BaseClass : Node { mixin ForwardCtor!(); Type type; this() {} // default constructor needed for clone() this(TokenId prot, ref const(TextSpan) _span) { super(prot, _span); } TokenId getProtection() { return id; } IdentifierList getIdentifierList() { return getMember!IdentifierList(0); } InheritingAggregate getClass() { auto res = getIdentifierList().resolve(); if(auto inh = cast(InheritingAggregate) res) return inh; if (res) // if null, resolve already issued an error semanticError("class or interface expected instead of ", res); return null; } override Type calcType() { if(type) return type; type = getClass(); if(!type) type = semanticErrorType("cannot resolve base class ", this); return type; } override void toD(CodeWriter writer) { // do not output protection in anonymous classes, and public is the default anyway if(id != TOK_public) writer(id, " "); writer(getMember(0)); } override void toC(CodeWriter writer) { writer("public ", getMember(0)); // protection diffent from C } @disable Value _interpretProperty(Context ctx, string prop) { if(auto clss = getClass()) return clss._interpretProperty(ctx, prop); return null; } } // StructBody: // [DeclDef...] class StructBody : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("{"); writer.nl(); { auto indent = CodeIndenter(writer); foreach(n; members) writer(n); } writer("}"); writer.nl(); } void initStatics(Scope sc) { foreach(m; members) { Decl decl = cast(Decl) m; if(!decl) continue; if(!(decl.attr & Attr_Static)) continue; if(decl.isAlias || decl.getFunctionBody()) continue; // nothing to do for local functions auto decls = decl.getDeclarators(); for(int n = 0; n < decls.members.length; n++) { auto d = decls.getDeclarator(n); d.interpretCatch(nullContext); } } } void iterateDeclarators(bool wantStatics, bool wantFuncs, void delegate(Declarator d) dg) { foreach(m; members) { Decl decl = cast(Decl) m; if(!decl) continue; if(decl.isAlias) continue; // nothing to do for aliases bool isStatic = (decl.attr & Attr_Static) != 0; if(isStatic != wantStatics) continue; auto decls = decl.getDeclarators(); for(int n = 0; n < decls.members.length; n++) { auto d = decls.getDeclarator(n); bool isFunc = d.getParameterList() !is null; if(isFunc != wantFuncs) continue; // nothing to do for aliases and local functions dg(d); } } } void iterateConstructors(bool wantStatics, void delegate(Constructor ctor) dg) { foreach(m; members) { Constructor ctor = cast(Constructor) m; if(!ctor) continue; bool isStatic = (ctor.attr & Attr_Static) != 0; if(isStatic != wantStatics) continue; dg(ctor); } } override void _semantic(Scope sc) { super._semantic(sc); initStatics(sc); } override void addSymbols(Scope sc) { addMemberSymbols(sc); } } //Constructor: // [TemplateParameters_opt Parameters_opt Constraint_opt FunctionBody] // if no parameters: this ( this ) class Constructor : Node, CallableNode { mixin ForwardCtor!(); override bool isTemplate() const { return members.length > 2; } TemplateParameterList getTemplateParameters() { return isTemplate() ? getMember!TemplateParameterList(0) : null; } Constraint getConstraint() { return isTemplate() && members.length > 3 ? getMember!Constraint(2) : null; } override ParameterList getParameterList() { return members.length > 1 ? getMember!ParameterList(isTemplate() ? 1 : 0) : null; } override FunctionBody getFunctionBody() { return getMember!FunctionBody(members.length - 1); } bool isPostBlit() { return members.length <= 1; } override void toD(CodeWriter writer) { writer("this"); if(auto tpl = getTemplateParameters()) writer(tpl); if(auto pl = getParameterList()) writer(pl); else writer("(this)"); if(auto c = getConstraint()) writer(c); if(writer.writeImplementations) { writer.nl; writer(getFunctionBody()); } else { writer(";"); writer.nl; } } override bool createsScope() const { return true; } override void _semantic(Scope sc) { if(auto fbody = getFunctionBody()) { sc = enterScope(sc); fbody.semantic(sc); sc = sc.pop(); } } override Value interpretCall(Context sc) { logInfo("calling ctor"); if(auto fbody = getFunctionBody()) return fbody.interpret(sc); return semanticErrorValue("ctor is not a interpretable function"); } } //Destructor: // [FunctionBody] class Destructor : Node { mixin ForwardCtor!(); FunctionBody getBody() { return getMember!FunctionBody(0); } override void toD(CodeWriter writer) { writer("~this()"); if(writer.writeImplementations) { writer.nl; writer(getBody()); } else { writer(";"); writer.nl; } } } //Invariant: // [BlockStatement] class Invariant : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("invariant()"); if(writer.writeImplementations) { writer.nl; writer(getMember(0)); } else { writer(";"); writer.nl; } } } //ClassAllocator: // [Parameters FunctionBody] class ClassAllocator : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("new", getMember(0)); writer.nl; writer(getMember(1)); } } //ClassDeallocator: // [Parameters FunctionBody] class ClassDeallocator : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("delete", getMember(0)); writer.nl; writer(getMember(1)); } } //AliasThis: class AliasThis : Node { string ident; mixin ForwardCtor!(); this() {} // default constructor needed for clone() this(Token tok) { super(tok); ident = tok.txt; } override AliasThis clone() { AliasThis n = static_cast!AliasThis(super.clone()); n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } override void toD(CodeWriter writer) { writer("alias "); writer.writeIdentifier(ident); writer(" this;"); writer.nl; } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/type.d0000664000175000017500000010435112776214756026453 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.type; import vdc.util; import vdc.lexer; import vdc.semantic; import vdc.interpret; import vdc.ast.node; import vdc.ast.expr; import vdc.ast.misc; import vdc.ast.aggr; import vdc.ast.tmpl; import vdc.ast.stmt; import vdc.ast.decl; import vdc.ast.writer; import stdext.util; import std.conv; class BuiltinPropertyBase : Symbol { string ident; } class BuiltinProperty(T) : BuiltinPropertyBase { Value value; this(string id, T val) { ident = id; value = Value.create(val); } override void toD(CodeWriter writer) { _assert(false); } override Type calcType() { return value.getType(); } override Value interpret(Context sc) { return value; } } Symbol newBuiltinProperty(T)(Scope sc, string id, T val) { auto bp = new BuiltinProperty!T(id, val); sc.addSymbol(id, bp); return bp; } class BuiltinType(T) : Node { } Scope[int] builtInScopes; alias AssociativeArray!(int, Scope) _wa1; // fully instantiate type info Scope getBuiltinBasicTypeScope(int tokid) { if(auto ps = tokid in builtInScopes) return *ps; Scope sc = new Scope; foreach(tok; BasicTypeTokens) { if (tokid == tok) { alias Token2BasicType!(tok) BT; newBuiltinProperty(sc, "init", BT.init); newBuiltinProperty(sc, "sizeof", BT.sizeof); newBuiltinProperty(sc, "mangleof", BT.mangleof); newBuiltinProperty(sc, "alignof", BT.alignof); newBuiltinProperty(sc, "stringof", BT.stringof); static if(__traits(compiles, BT.min)) newBuiltinProperty(sc, "min", BT.min); static if(__traits(compiles, BT.max)) newBuiltinProperty(sc, "max", BT.max); static if(__traits(compiles, BT.nan)) newBuiltinProperty(sc, "nan", BT.nan); } } builtInScopes[tokid] = sc; return sc; } class Type : Node { // semantic data TypeInfo typeinfo; mixin ForwardCtor!(); abstract bool propertyNeedsParens() const; override Type clone() { Type n = static_cast!Type(super.clone()); return n; } enum ConversionFlags { kAllowBaseClass = 1 << 0, kAllowConstConversion = 1 << 1, kAllowBaseTypeConversion = 1 << 2, // flags to clear on indirection kIndirectionClear = kAllowBaseClass | kAllowBaseTypeConversion, kImpliciteConversion = kAllowBaseClass | kAllowConstConversion | kAllowBaseTypeConversion, } bool convertableFrom(Type from, ConversionFlags flags) { if(from == this) return true; return false; } final bool convertableFromImplicite(Type from) { return convertableFrom(from, ConversionFlags.kImpliciteConversion); } Type commonType(Type other) { if(convertableFromImplicite(other)) return this; if(other.convertableFromImplicite(this)) return other; return semanticErrorType(this, " has no common type with ", other); } override void _semantic(Scope sc) { if(!typeinfo) typeSemantic(sc); } void typeSemantic(Scope sc) { super._semantic(sc); } override Type calcType() { return this; } override Value interpret(Context sc) { return new TypeValue(this); } Value getProperty(Value sv, string ident, bool virtualCall) { return null; } Value getProperty(Value sv, Declarator decl, bool virtualCall) { return null; } @disable final Value interpretProperty(Context ctx, string prop) { if(Value v = _interpretProperty(ctx, prop)) return v; return semanticErrorValue("cannot calculate property ", prop, " of type ", this); } @disable Value _interpretProperty(Context ctx, string prop) { return null; } Value createValue(Context ctx, Value initValue) { return semanticErrorValue("cannot create value of type ", this); } Type opIndex(int v) { return semanticErrorType("cannot index a ", this); } Type opSlice(int b, int e) { return semanticErrorType("cannot slice a ", this); } Type opCall(Type args) { return semanticErrorType("cannot call a ", this); } ////////////////////////////////////////////////////////////// Type unqualified() { return this; } } class ErrorType : Type { mixin ForwardCtor!(); override bool propertyNeedsParens() const { return false; } override void toD(CodeWriter writer) { writer("_errortype_"); } override Scope getScope() { if(!scop) scop = new Scope(); return scop; } } // moved out of BasicType due to BUG9672 Type createBasicType(int tokid) { BasicType type = new BasicType; type.id = tokid; return type; } //BasicType only created for standard types associated with tokens class BasicType : Type { mixin ForwardCtor!(); override bool propertyNeedsParens() const { return false; } static Type getSizeType() { return getType(TOK_uint); // TOK_ulong if compiling for 64-bit } static Type getType(int tokid) { static Type[] cachedTypes; if(tokid >= cachedTypes.length) cachedTypes.length = tokid + 1; if(!cachedTypes[tokid]) cachedTypes[tokid] = createBasicType(tokid); return cachedTypes[tokid]; } static TypeInfo getTypeInfo(int id) { // TODO: convert foreach to table access for faster lookup foreach(tok; BasicTypeTokens) { if (id == tok) return typeid(Token2BasicType!(tok)); } return null; } static size_t getSizeof(int id) { // TODO: convert foreach to table access for faster lookup foreach(tok; BasicTypeTokens) { if (id == tok) return Token2BasicType!(tok).sizeof; } _assert(false); return int.sizeof; } static string getMangleof(int id) { // TODO: convert foreach to table access for faster lookup foreach(tok; BasicTypeTokens) { if (id == tok) return Token2BasicType!(tok).mangleof; } _assert(false); return null; } static size_t getAlignof(int id) { // TODO: convert foreach to table access for faster lookup foreach(tok; BasicTypeTokens) { if (id == tok) return Token2BasicType!(tok).alignof; } _assert(false); return int.alignof; } static string getStringof(int id) { // TODO: convert foreach to table access for faster lookup foreach(tok; BasicTypeTokens) { if (id == tok) return Token2BasicType!(tok).stringof; } _assert(false); return null; } static Value getMin(int id) { // TODO: convert foreach to table access for faster lookup foreach(tok; BasicTypeTokens) { static if(__traits(compiles, Token2BasicType!(tok).min)) if (id == tok) return Value.create(Token2BasicType!(tok).min); } return .semanticErrorValue(tokenString(id), " has no min property"); } static Value getMax(int id) { // TODO: convert foreach to table access for faster lookup foreach(tok; BasicTypeTokens) { static if(__traits(compiles, Token2BasicType!(tok).max)) if (id == tok) return Value.create(Token2BasicType!(tok).max); } return .semanticErrorValue(tokenString(id), " has no max property"); } override Value createValue(Context ctx, Value initValue) { // TODO: convert foreach to table access for faster lookup foreach(tok; BasicTypeTokens) { if (id == tok) { if(initValue) return createInitValue!(Token2ValueType!(tok))(ctx, initValue); return Value.create(Token2BasicType!(tok).init); } } return semanticErrorValue("cannot create value of type ", this); } override void typeSemantic(Scope sc) { _assert(id != TOK_auto); typeinfo = getTypeInfo(id); } override Scope getScope() { if(!scop) scop = getBuiltinBasicTypeScope(id); return scop; } enum Category { kInteger, kFloat, kComplex, kVoid } static int categoryLevel(int id) { switch(id) { case TOK_bool: return 0; case TOK_byte: return 1; case TOK_ubyte: return 1; case TOK_short: return 2; case TOK_ushort: return 2; case TOK_int: return 4; case TOK_uint: return 4; case TOK_long: return 8; case TOK_ulong: return 8; case TOK_char: return 1; case TOK_wchar: return 2; case TOK_dchar: return 4; case TOK_float: return 10; // assume al floats convertable, ignore lost accuracy case TOK_double: return 10; case TOK_real: return 10; case TOK_ifloat: return 10; case TOK_idouble: return 10; case TOK_ireal: return 10; case TOK_cfloat: return 16; case TOK_cdouble: return 16; case TOK_creal: return 16; default: assert(false); } } static Category category(int id) { switch(id) { case TOK_bool: return Category.kInteger; case TOK_byte: return Category.kInteger; case TOK_ubyte: return Category.kInteger; case TOK_short: return Category.kInteger; case TOK_ushort: return Category.kInteger; case TOK_int: return Category.kInteger; case TOK_uint: return Category.kInteger; case TOK_long: return Category.kInteger; case TOK_ulong: return Category.kInteger; case TOK_char: return Category.kInteger; case TOK_wchar: return Category.kInteger; case TOK_dchar: return Category.kInteger; case TOK_float: return Category.kFloat; case TOK_double: return Category.kFloat; case TOK_real: return Category.kFloat; case TOK_ifloat: return Category.kFloat; case TOK_idouble: return Category.kFloat; case TOK_ireal: return Category.kFloat; case TOK_cfloat: return Category.kComplex; case TOK_cdouble: return Category.kComplex; case TOK_creal: return Category.kComplex; case TOK_void: return Category.kVoid; default: break; } _assert(false); return Category.kVoid; } @disable override Value _interpretProperty(Context ctx, string prop) { switch(prop) { // all types case "init": return createValue(nullContext, null); case "sizeof": return Value.create(getSizeof(id)); case "alignof": return Value.create(getAlignof(id)); case "mangleof": return Value.create(getMangleof(id)); case "stringof": return Value.create(getStringof(id)); // integer types case "min": return getMin(id); case "max": return getMax(id); // floating point types case "infinity": case "nan": case "dig": case "epsilon": case "mant_dig": case "max_10_exp": case "max_exp": case "min_10_exp": case "min_exp": case "min_normal": case "re": case "im": default: return super._interpretProperty(ctx, prop); } } override bool convertableFrom(Type from, ConversionFlags flags) { if(super.convertableFrom(from, flags)) return true; auto bt = cast(BasicType) from; if(!bt) return false; if(id == bt.id) return true; Category cat = category(id); Category fcat = category(bt.id); if(flags & ConversionFlags.kAllowBaseTypeConversion) return cat == fcat; if(flags & ConversionFlags.kImpliciteConversion) { if(cat == Category.kVoid || fcat != Category.kVoid) return cat == fcat; return (categoryLevel(id) >= categoryLevel(bt.id)); } return false; } override void toD(CodeWriter writer) { _assert(id != TOK_auto); writer(id); } } class NullType : Type { override bool propertyNeedsParens() const { return false; } override void toD(CodeWriter writer) { writer("Null"); } } //AutoType: // auto added implicitely if there is no other type specified class AutoType : Type { mixin ForwardCtor!(); override bool propertyNeedsParens() const { return false; } override void toD(CodeWriter writer) { if(id != TOK_auto) // only implicitely added? writer(id); } override Value createValue(Context ctx, Value initValue) { if(!initValue) return semanticErrorValue("no initializer in auto declaration"); return initValue; } override Type calcType() { Expression expr; if(auto decl = cast(Decl) parent) { Declarators decls = decl.getDeclarators(); if(auto declinit = cast(DeclaratorInitializer) decls.getMember(0)) expr = declinit.getInitializer(); } if(expr) return expr.calcType(); return semanticErrorType("no initializer in auto declaration"); } override bool convertableFrom(Type from, ConversionFlags flags) { return calcType().convertableFrom(from, flags); } } class VectorType : Type { mixin ForwardCtor!(); override bool propertyNeedsParens() const { return true; } override void toD(CodeWriter writer) { writer("__vector(", getMember(0), ")"); } } //ModifiedType: // [Type] class ModifiedType : Type { mixin ForwardCtor!(); override bool propertyNeedsParens() const { return true; } Type getType() { return getMember!Type(0); } // ignoring modifiers override Type unqualified() { return getType(); } override void typeSemantic(Scope sc) { TypeInfo_Const ti; switch(id) { case TOK_const: ti = new TypeInfo_Const; break; case TOK_immutable: ti = new TypeInfo_Invariant; break; case TOK_inout: ti = new TypeInfo_Inout; break; case TOK_shared: ti = new TypeInfo_Shared; break; default: _assert(false); } auto type = getType(); type.semantic(sc); ti.base = type.typeinfo; typeinfo = ti; } override bool convertableFrom(Type from, ConversionFlags flags) { if(super.convertableFrom(from, flags)) return true; Type nextThis = getType(); auto modfrom = cast(ModifiedType) from; if(modfrom) { Type nextFrom = modfrom.getType(); if(id == modfrom.id) if(nextThis.convertableFrom(nextFrom, flags)) return true; if(flags & ConversionFlags.kAllowConstConversion) if(id == TOK_const && modfrom.id == TOK_immutable) if(nextThis.convertableFrom(nextFrom, flags)) return true; } if(flags & ConversionFlags.kAllowConstConversion) if(id == TOK_const) if(nextThis.convertableFrom(from, flags)) return true; return false; } override Value createValue(Context ctx, Value initValue) { return getType().createValue(ctx, initValue); // TODO: ignores modifier } override void toD(CodeWriter writer) { writer(id, "(", getMember(0), ")"); } } //IdentifierType: // [IdentifierList] class IdentifierType : Type { mixin ForwardCtor!(); override bool propertyNeedsParens() const { return false; } //Node resolved; Type type; IdentifierList getIdentifierList() { return getMember!IdentifierList(0); } override void toD(CodeWriter writer) { writer(getMember(0)); } override bool convertableFrom(Type from, ConversionFlags flags) { return calcType().convertableFrom(from, flags); } override Type calcType() { if(type) return type; auto idlist = getIdentifierList(); type = idlist.calcType(); return type; } override Value interpret(Context sc) { // might also be called inside an alias, actually resolving to a value return new TypeValue(this); } } //Typeof: // [Expression/Type_opt IdentifierList_opt] class Typeof : Type { mixin ForwardCtor!(); override bool propertyNeedsParens() const { return false; } bool isReturn() { return id == TOK_return; } IdentifierList getIdentifierList() { return getMember!IdentifierList(1); } override void toD(CodeWriter writer) { if(isReturn()) writer("typeof(return)"); else writer("typeof(", getMember(0), ")"); if(auto identifierList = getIdentifierList()) writer(".", identifierList); } override Value interpret(Context sc) { if(isReturn()) { return semanticErrorValue("typeof(return) not implemented"); } Node n = getMember(0); Type t = n.calcType(); return new TypeValue(t); } } // base class for types that have an indirection, i.e. pointer and arrays class TypeIndirection : Type { mixin ForwardCtor!(); override TypeIndirection clone() { auto n = static_cast!TypeIndirection(super.clone()); if(members.length == 0) n.setNextType(_next); return n; } Type _next; override bool propertyNeedsParens() const { return true; } //Type getType() { return getMember!Type(0); } void setNextType(Type t) { _next = t.calcType(); } Type getNextType() { if(_next) return _next; _next = getMember!Type(0).calcType(); return _next; } override bool convertableFrom(Type from, ConversionFlags flags) { if(super.convertableFrom(from, flags)) return true; Type nextThis = getNextType(); if(this.classinfo != from.classinfo) return false; auto ifrom = static_cast!TypeIndirection(from); _assert(ifrom !is null); // could allow A* -> const(B*) if class A derives from B // even better -> head_const(B*) return nextThis.convertableFrom(ifrom.getNextType(), flags & ~ConversionFlags.kIndirectionClear); } override Type opIndex(int v) { //_assert(false); return getNextType(); } override Type opSlice(int b, int e) { _assert(false); return this; } } //TypePointer: // [Type] class TypePointer : TypeIndirection { mixin ForwardCtor!(); override void typeSemantic(Scope sc) { auto type = getNextType(); //type.semantic(sc); auto typeinfo_ptr = new TypeInfo_Pointer; typeinfo_ptr.m_next = type.typeinfo; typeinfo = typeinfo_ptr; } override Value createValue(Context ctx, Value initValue) { auto v = PointerValue._create(this, null); if(initValue) v.opBin(ctx, TOK_assign, initValue); return v; } bool convertableTo(TypePointer t) { auto type = getNextType(); auto otype = t.getNextType(); return otype.compare(type); } override void toD(CodeWriter writer) { if(auto m = getMember(0)) writer(m, "*"); else if(_next) writer(_next, "*"); else writer("_missingtype_*"); } } class LengthProperty : Symbol { Type type; override Type calcType() { if(!type) type = createBasicType(TOK_uint); return type; } override Value interpret(Context sc) { if(auto ac = cast(AggrContext)sc) { if(auto dav = cast(DynArrayValue) ac.instance) return new SetLengthValue(dav); return semanticErrorValue("cannot calulate length of ", ac.instance); } return semanticErrorValue("no context to length of ", sc); } override void toD(CodeWriter writer) { writer("length"); } } class PtrProperty : Symbol { Type type; this(Type t) { auto tp = new TypePointer(TOK_mul, t.span); tp.setNextType(t); type = tp; } override Type calcType() { return type; } override Value interpret(Context sc) { if(auto ac = cast(AggrContext)sc) { if(auto dav = cast(DynArrayValue) ac.instance) { if(dav.first) return dav.first.opRefPointer(); else return type.createValue(sc, null); } return semanticErrorValue("cannot calculate ptr of ", ac.instance); } return semanticErrorValue("no context to ptr of ", sc); } override void toD(CodeWriter writer) { writer("ptr"); } } //TypeDynamicArray: // [Type] class TypeDynamicArray : TypeIndirection { mixin ForwardCtor!(); static Scope cachedScope; override void typeSemantic(Scope sc) { auto type = getNextType(); //type.semantic(sc); auto typeinfo_arr = new TypeInfo_Array; typeinfo_arr.value = type.typeinfo; typeinfo = typeinfo_arr; } override bool convertableFrom(Type from, ConversionFlags flags) { if(super.convertableFrom(from, flags)) return true; if(from.classinfo == typeid(TypeStaticArray)) { Type nextThis = getNextType(); auto arrfrom = static_cast!TypeStaticArray(from); assert(arrfrom); // should allow A[] -> const(B[]) if class A derives from B // even better -> head_const(B[]) if(nextThis.convertableFrom(arrfrom.getNextType(), flags & ~ConversionFlags.kIndirectionClear)) return true; } return false; } override void toD(CodeWriter writer) { writer(getMember(0), "[]"); } override Scope getScope() { if(!scop) { Scope sc = parent ? parent.getScope() : null; scop = sc ? sc.pushClone() : new Scope; scop.addSymbol("length", new LengthProperty); scop.addSymbol("ptr", new PtrProperty(getNextType())); } return scop; } override Value createValue(Context ctx, Value initValue) { version(none) if(auto mtype = cast(ModifiedType) getType()) if(mtype.id == TOK_immutable) if(auto btype = cast(BasicType) mtype.getType()) if(btype.id == TOK_char) return createInitValue!StringValue(ctx, initValue); auto val = new DynArrayValue(this); if(initValue) val.opBin(ctx, TOK_assign, initValue); return val; } override Type opSlice(int b, int e) { return this; /+ auto da = new TypeStaticArray; da.setNextType(getNextType()); //addMember(nextType().clone()); return da; +/ } /+ Value deepCopy(Context sc, Value initValue) { auto val = new DynArrayValue(this); if(int dim = initValue ? initValue.interpretProperty(sc, "length").toInt() : 0) { auto type = getType(); Value[] values; values.length = dim; IntValue idxval = new IntValue; for(int i = 0; i < dim; i++) { *(idxval.pval) = i; Value v = initValue ? initValue.opIndex(idxval) : null; values[i] = type.createValue(sc, v); } val.values = values; } return val; } +/ } //SuffixDynamicArray: // [] class SuffixDynamicArray : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("[]"); } } // can be both static or assoc, which one is correct cannot be decided by the parser in general //SuffixArray: // [Expression|Type] class SuffixArray : Node { mixin ForwardCtor!(); Expression getDimension() { return getMember!Expression(0); } Type getKeyType() { return getMember!Type(0); } override void toD(CodeWriter writer) { writer("[", getMember(0), "]"); } } //TypeStaticArray: // [Type Expression] class TypeStaticArray : TypeIndirection { mixin ForwardCtor!(); override TypeStaticArray clone() { auto n = static_cast!TypeStaticArray(super.clone()); n.dimExpr = dimExpr; return n; } Expression getDimension() { return dimExpr ? dimExpr : getMember!Expression(1); } Expression dimExpr; override void typeSemantic(Scope sc) { auto type = getNextType(); //type.semantic(sc); auto typeinfo_arr = new TypeInfo_StaticArray; typeinfo_arr.value = type.typeinfo; Context ctx = new Context(nullContext); ctx.scop = sc; typeinfo_arr.len = getDimension().interpret(ctx).toInt(); typeinfo = typeinfo_arr; } override Scope getScope() { if(!scop) { enterScope(parent.getScope()); Context ctx = new Context(nullContext); ctx.scop = scop; size_t len = getDimension().interpret(ctx).toInt(); newBuiltinProperty(scop, "length", len); } return scop; } /+ override Scope getScope() { if(!scop) { scop = createTypeScope(); //scop.addSymbol("length", new BuiltinProperty!uint(BasicType.getType(TOK_uint), 0)); scop.parent = super.getScope(); } return scop; } +/ override void toD(CodeWriter writer) { writer(getMember(0), "[", getMember(1), "]"); } override Value createValue(Context ctx, Value initValue) { int dim = getDimension().interpret(ctx).toInt(); auto val = new StaticArrayValue(this); val.setLength(ctx, dim); if(initValue) val.opBin(ctx, TOK_assign, initValue); return val; } override Type opSlice(int b, int e) { auto da = new TypeDynamicArray; da.setNextType(getNextType()); //addMember(nextType().clone()); return da; //return this; } } //TypeAssocArray: // [Type Type] class TypeAssocArray : TypeIndirection { mixin ForwardCtor!(); override TypeAssocArray clone() { auto n = static_cast!TypeAssocArray(super.clone()); n.keyType = keyType; return n; } Type getKeyType() { return keyType ? keyType : getMember!Type(1); } Type keyType; override void typeSemantic(Scope sc) { auto vtype = getNextType(); //vtype.semantic(sc); auto ktype = getKeyType(); //ktype.semantic(sc); auto typeinfo_arr = new TypeInfo_AssociativeArray; typeinfo_arr.value = vtype.typeinfo; typeinfo_arr.key = ktype.typeinfo; typeinfo = typeinfo_arr; } override bool convertableFrom(Type from, ConversionFlags flags) { if(super.convertableFrom(from, flags)) { auto aafrom = static_cast!TypeAssocArray(from); // verified in super.convertableFrom if(getKeyType().convertableFrom(aafrom.getKeyType(), flags & ~ConversionFlags.kIndirectionClear)) return true; } return false; } override void toD(CodeWriter writer) { writer(getMember(0), "[", getMember(1), "]"); } } //TypeArraySlice: // [Type Expression Expression] class TypeArraySlice : Type { mixin ForwardCtor!(); override bool propertyNeedsParens() const { return true; } Type getType() { return getMember!Type(0); } Expression getLower() { return getMember!Expression(1); } Expression getUpper() { return getMember!Expression(2); } override void typeSemantic(Scope sc) { auto rtype = getType(); if(auto tpl = cast(TypeInfo_Tuple) rtype.typeinfo) { Context ctx = new Context(nullContext); ctx.scop = sc; int lo = getLower().interpret(ctx).toInt(); int up = getUpper().interpret(ctx).toInt(); if(lo > up || lo < 0 || up > tpl.elements.length) { semanticError("tuple slice out of bounds"); typeinfo = tpl; } else { auto ntpl = new TypeInfo_Tuple; ntpl.elements = tpl.elements[lo..up]; typeinfo = ntpl; } } else { semanticError("type is not a tuple"); typeinfo = rtype.typeinfo; } } override void toD(CodeWriter writer) { writer(getMember(0), "[", getLower(), " .. ", getUpper(), "]"); } } //TypeFunction: // [Type ParameterList] class TypeFunction : Type { mixin ForwardCtor!(); override TypeFunction clone() { auto n = static_cast!TypeFunction(super.clone()); n.paramList = paramList; n.returnType = returnType; n.funcDecl = funcDecl; return n; } override bool propertyNeedsParens() const { return true; } Type getReturnType() { return returnType ? returnType : getMember!Type(0); } // overwritten in TypeFunctionLiteral/TypeDelegateLiteral ParameterList getParameters() { return paramList ? paramList : getMember!ParameterList(1); } ParameterList paramList; Type returnType; Declarator funcDecl; // the actual function pointer override void typeSemantic(Scope sc) { auto ti_fn = new TypeInfo_FunctionX; auto rtype = getReturnType(); rtype.semantic(sc); auto params = getParameters(); params.semantic(sc); ti_fn.next = rtype.typeinfo; ti_fn.parameters = new TypeInfo_Tuple; for(size_t p = 0; p < params.members.length; p++) ti_fn.parameters.elements ~= params.getParameter(p).getParameterDeclarator().getType().typeinfo; ti_fn.attributes = combineAttributes(attr, params.attr); typeinfo = ti_fn; } override Value createValue(Context ctx, Value initValue) { auto fv = new FunctionValue; if(FunctionValue ifv = cast(FunctionValue) initValue) { // TODO: verfy types fv.functype = ifv.functype; } else if(initValue) return semanticErrorValue("cannot assign ", initValue, " to ", this); else fv.functype = this; return fv; } override Type opCall(Type args) { return getReturnType().calcType(); } override void toD(CodeWriter writer) { writer(getReturnType(), " function", getParameters()); writer.writeAttributesAndAnnotations(attr, annotation, true); } } //TypeDelegate: // [Type ParameterList] class TypeDelegate : TypeFunction { mixin ForwardCtor!(); override void typeSemantic(Scope sc) { auto ti_dg = new TypeInfo_DelegateX; auto rtype = getReturnType(); rtype.semantic(sc); auto params = getParameters(); params.semantic(sc); ti_dg.next = rtype.typeinfo; ti_dg.parameters = new TypeInfo_Tuple; for(size_t p = 0; p < params.members.length; p++) ti_dg.parameters.elements ~= params.getParameter(p).getParameterDeclarator().getType().typeinfo; ti_dg.attributes = combineAttributes(attr, params.attr); // no context information when defining the type, only with an instance typeinfo = ti_dg; } override Value createValue(Context ctx, Value initValue) { auto fv = new DelegateValue; if(DelegateValue ifv = cast(DelegateValue) initValue) { // TODO: verfy types fv.functype = ifv.functype; fv.context = ifv.context; } else if(initValue) return semanticErrorValue("cannot assign ", initValue, " to ", this); else { fv.functype = this; fv.context = ctx; } return fv; } override void toD(CodeWriter writer) { writer(getReturnType(), " delegate", getParameters()); writer.writeAttributesAndAnnotations(attr, annotation, true); } } class TypeInfo_FunctionX : TypeInfo_Function { TypeInfo_Tuple parameters; int attributes; } class TypeInfo_DelegateX : TypeInfo_Delegate { TypeInfo_Tuple parameters; int attributes; TypeInfo context; } class TypeString : TypeDynamicArray { mixin ForwardCtor!(); version(none) override Value createValue(Context ctx, Value initValue) { return createInitValue!StringValue(ctx, initValue); } } TypeDynamicArray createTypeString(C)() { TextSpan span; return createTypeString!C(span); } TypeDynamicArray createTypeString(C)(ref const(TextSpan) span) { auto arr = new TypeString(span); BasicType ct = new BasicType(BasicType2Token!C(), span); ModifiedType mt = new ModifiedType(TOK_immutable, span); mt.addMember(ct); arr.addMember(mt); return arr; } TypeDynamicArray getTypeString(C)() { static TypeDynamicArray cachedTypedString; if(!cachedTypedString) { TextSpan span; cachedTypedString = createTypeString!C(span); } return cachedTypedString; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/tmpl.d0000664000175000017500000003552512776214756026454 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.tmpl; import vdc.util; import vdc.lexer; import vdc.ast.node; import vdc.ast.decl; import vdc.ast.expr; import vdc.ast.type; import vdc.ast.writer; import vdc.interpret; import vdc.semantic; import stdext.util; //TemplateDeclaration: // [Identifier TemplateParameterList Constraint_opt DeclarationBlock] class TemplateDeclaration : Node { mixin ForwardCtor!(); Identifier getIdentifier() { return getMember!Identifier(0); } TemplateParameterList getTemplateParameterList() { return getMember!TemplateParameterList(1); } Constraint getConstraint() { return members.length > 3 ? getMember!Constraint(2) : null; } Node getBody() { return getMember(members.length - 1); } bool isMixin() { return id == TOK_mixin; } override TemplateDeclaration clone() { TemplateDeclaration n = static_cast!TemplateDeclaration(super.clone()); return n; } override void toD(CodeWriter writer) { if(isMixin()) writer("mixin "); writer("template ", getIdentifier(), getTemplateParameterList()); writer.nl(); if(getConstraint()) { writer(getConstraint()); writer.nl(); } // writer("{"); // writer.nl(); // { // CodeIndenter indent = CodeIndenter(writer); writer(getBody()); // } // writer("}"); // writer.nl(); writer.nl(); } override void toC(CodeWriter writer) { // we never write the template, only instantiations } override void addSymbols(Scope sc) { string ident = getIdentifier().ident; sc.addSymbol(ident, this); } override void _semantic(Scope sc) { // do not recurse into declaration, it only makes sense for an instance } override bool isTemplate() const { return true; } override Node expandTemplate(Scope sc, TemplateArgumentList args) { TemplateParameterList tpl = getTemplateParameterList(); string ident = getIdentifier().ident; ArgMatch[] vargs = matchTemplateArgs(ident, sc, args, tpl); ParameterList pl = createTemplateParameterList(vargs); auto bdy = getBody().clone(); auto inst = new TemplateMixinInstance; inst.addMember(pl); inst.addMember(bdy); return inst; } } //TemplateMixinInstance: // name [ParameterList DeclarationBlock] class TemplateMixinInstance : Type { mixin ForwardCtor!(); // semantic data string instanceName; // set when named instance created by cloning TypeValue typeVal; ParameterList getTemplateParameterList() { return getMember!ParameterList(0); } Node getBody() { return getMember(1); } override bool propertyNeedsParens() const { return false; } override void toD(CodeWriter writer) { writer("mixin ", getBody(), " ", instanceName); } override void _semantic(Scope sc) { // TODO: TemplateParameterList, Constraint sc = enterScope(sc); super._semantic(sc); sc = sc.pop(); } override void addSymbols(Scope sc) { if(instanceName.length) sc.addSymbol(instanceName, this); else { sc = enterScope(sc).pop(); // put symbols into parent scope aswell foreach(id, sym; scop.symbols) foreach(s, b; sym) sc.addSymbol(id, s); } } override Type calcType() { return this; } override Value interpret(Context sc) { if(!typeVal) typeVal = new TypeValue(calcType()); return typeVal; } } //TemplateParameterList: // [ TemplateParameter... ] class TemplateParameterList : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("("); writer.writeArray(members); writer(")"); } } //TemplateParameter: // TemplateTypeParameter // TemplateValueParameter // TemplateAliasParameter // TemplateTupleParameter // TemplateThisParameter class TemplateParameter : Node { mixin ForwardCtor!(); } //TemplateInstance: // ident [ TemplateArgumentList ] class TemplateInstance : Identifier { mixin ForwardCtorTok!(); TemplateArgumentList getTemplateArgumentList() { return getMember!TemplateArgumentList(0); } override void toD(CodeWriter writer) { writer.writeIdentifier(ident); writer("!(", getMember(0), ")"); } override Value interpret(Context sc) { return super.interpret(sc); } } // // //TemplateArgumentList: // [ TemplateArgument... ] class TemplateArgumentList : Node { mixin ForwardCtorNoId!(); override void toD(CodeWriter writer) { bool writeSep = false; foreach(m; members) { if(writeSep) writer(", "); writeSep = true; bool paren = false; if(auto expr = cast(Expression) m) paren = (expr.getPrecedence() <= PREC.expr); if(paren) writer("(", m, ")"); else writer(m); } } } // //TemplateArgument: // Type // AssignExpression // Symbol // //// identical to IdentifierList //Symbol: // SymbolTail // . SymbolTail // //SymbolTail: // Identifier // Identifier . SymbolTail // TemplateInstance // TemplateInstance . SymbolTail // //TemplateSingleArgument: // Identifier // BasicTypeX // CharacterLiteral // StringLiteral // IntegerLiteral // FloatLiteral // true // false // null // __FILE__ // __LINE__ //TemplateTypeParameter: // Identifier // Identifier TemplateTypeParameterSpecialization // Identifier TemplateTypeParameterDefault // Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault class TemplateTypeParameter : TemplateParameter { string ident; Type specialization; Node def; this() {} // default constructor needed for clone() this(Token tok) { super(tok); ident = tok.txt; } override TemplateTypeParameter clone() { TemplateTypeParameter n = static_cast!TemplateTypeParameter(super.clone()); n.ident = ident; for(int m = 0; m < members.length; m++) { if(members[m] is specialization) n.specialization = static_cast!Type(n.members[m]); if(members[m] is def) n.def = n.members[m]; } return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } override void toD(CodeWriter writer) { writer.writeIdentifier(ident); if(specialization) writer(" : ", specialization); if(def) writer(" = ", def); } } //TemplateTypeParameterSpecialization: // : Type // //TemplateTypeParameterDefault: // = Type //TemplateThisParameter: // [ TemplateTypeParameter ] class TemplateThisParameter : TemplateParameter { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("this ", getMember(0)); } } // //TemplateValueParameter: // Declaration // Declaration TemplateValueParameterSpecialization // Declaration TemplateValueParameterDefault // Declaration TemplateValueParameterSpecialization TemplateValueParameterDefault class TemplateValueParameter : TemplateParameter { mixin ForwardCtor!(); Expression specialization; Expression def; ParameterDeclarator getParameterDeclarator() { return getMember!ParameterDeclarator(0); } override TemplateValueParameter clone() { TemplateValueParameter n = static_cast!TemplateValueParameter(super.clone()); for(int m = 0; m < members.length; m++) { if(members[m] is specialization) n.specialization = static_cast!Expression(n.members[m]); if(members[m] is def) n.def = static_cast!Expression(n.members[m]); } return n; } override void toD(CodeWriter writer) { writer(getMember(0)); if(specialization) writer(" : ", specialization); if(def) writer(" = ", def); } } // //TemplateValueParameterSpecialization: // : ConditionalExpression // //TemplateValueParameterDefault: // = __FILE__ // = __LINE__ // = ConditionalExpression // //TemplateAliasParameter: // alias Identifier TemplateAliasParameterSpecialization_opt TemplateAliasParameterDefault_opt // //TemplateAliasParameterSpecialization: // : Type // //TemplateAliasParameterDefault: // = Type class TemplateAliasParameter : TemplateParameter { mixin ForwardCtor!(); string getIdent() { return getMember!TemplateTypeParameter(0).ident; } override void toD(CodeWriter writer) { writer("alias ", getMember(0)); } } // //TemplateTupleParameter: // Identifier ... class TemplateTupleParameter : TemplateParameter { string ident; override TemplateTupleParameter clone() { TemplateTupleParameter n = static_cast!TemplateTupleParameter(super.clone()); n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } this() {} // default constructor needed for clone() this(Token tok) { super(tok); ident = tok.txt; } override void toD(CodeWriter writer) { writer.writeIdentifier(ident); writer("..."); } } // //ClassTemplateDeclaration: // class Identifier ( TemplateParameterList ) BaseClassList_opt ClassBody // //InterfaceTemplateDeclaration: // interface Identifier ( TemplateParameterList ) Constraint_opt BaseInterfaceList_opt InterfaceBody // //TemplateMixinDeclaration: // mixin template TemplateIdentifier ( TemplateParameterList ) Constraint_opt { DeclDefs } //TemplateMixin: // mixin TemplateIdentifier ; // mixin TemplateIdentifier MixinIdentifier ; // mixin TemplateIdentifier ! ( TemplateArgumentList ) ; // mixin TemplateIdentifier ! ( TemplateArgumentList ) MixinIdentifier ; // // translated to //TemplateMixin: // [IdentifierList MixinIdentifier_opt] // [Typeof MixinIdentifier] class TemplateMixin : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer("mixin ", getMember(0)); if(members.length > 1) writer(" ", getMember(1)); writer(";"); writer.nl(); } override Node[] expandNonScopeInterpret(Scope sc, Node[] athis) { Node tmpl = getMember(0); Node n; if(auto prop = cast(TypeProperty) tmpl) n = prop.resolve(); else if(auto idlist = cast(IdentifierList) tmpl) n = idlist.doResolve(true); if(!n) semanticError("cannot resolve ", tmpl); else if(auto tmi = cast(TemplateMixinInstance) n) { // TODO: match constraints, replace parameters if(members.length > 1) { // named instance string name = getMember!Identifier(1).ident; tmi.instanceName = name; } return [ tmi ]; } else semanticError(n, " is not a TemplateMixinInstance"); return athis; } } // //Constraint: // if ( ConstraintExpression ) class Constraint : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { writer(" if(", getMember(0), ")"); } } // //ConstraintExpression: // Expression // //MixinIdentifier: // Identifier // ArgMatch[] matchTemplateArgs(string ident, Scope sc, TemplateArgumentList args, TemplateParameterList tpl) { if(args.members.length != tpl.members.length) { semanticError("incorrect number of arguments for template expansion of ", ident); return null; } ArgMatch[] vargs; Context ctx = new Context(nullContext); ctx.scop = sc; int m; for(m = 0; m < args.members.length; m++) { Value v; string name; auto am = args.members[m]; auto pm = tpl.members[m]; if(auto typeparam = cast(TemplateTypeParameter) pm) { v = am.interpret(ctx); name = typeparam.ident; if(!cast(TypeValue) v) { semanticError(ident, ": ", m+1, ". argument must evaluate to a type, not ", v.toStr()); v = null; } } else if(auto thisparam = cast(TemplateThisParameter) pm) { semanticError("cannot infer this parameter for ", ident); } else if(auto valueparam = cast(TemplateValueParameter) pm) { v = am.interpret(ctx); auto decl = valueparam.getParameterDeclarator().getDeclarator(); v = decl.calcType().createValue(ctx, v); name = decl.ident; } else if(auto aliasparam = cast(TemplateAliasParameter) pm) { if(auto idtype = cast(IdentifierType) am) v = new AliasValue(idtype.getIdentifierList()); else if(auto type = cast(Type) am) v = new TypeValue(type); else if(auto id = cast(IdentifierExpression) am) { auto idlist = new IdentifierList; idlist.addMember(id.getIdentifier().clone()); v = new AliasValue(idlist); } else semanticError(ident, ": ", m+1, ". argument must evaluate to an identifier, not ", am); name = aliasparam.getIdent(); } else if(auto tupleparam = cast(TemplateTupleParameter) pm) { semanticError("cannot infer template tuple parameter for ", ident); } if(!v) return null; vargs ~= ArgMatch(v, name); } return vargs; } ParameterList createTemplateParameterList(ArgMatch[] vargs) { ParameterList pl = new ParameterList; for(int m = 0; m < vargs.length; m++) { auto pd = new ParameterDeclarator; pd.addMember(vargs[m].value.getType().clone()); auto d = new Declarator; d.ident = vargs[m].name; if(auto av = cast(AliasValue) vargs[m].value) { d.isAlias = true; d.aliasTo = av.resolve(); } else { d.value = vargs[m].value; } pd.addMember(d); pl.addMember(pd); } return pl; }ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/decl.d0000664000175000017500000006014412776214756026402 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.decl; import vdc.util; import vdc.lexer; import vdc.semantic; import vdc.logger; import vdc.interpret; import vdc.ast.node; import vdc.ast.expr; import vdc.ast.misc; import vdc.ast.aggr; import vdc.ast.tmpl; import vdc.ast.stmt; import vdc.ast.type; import vdc.ast.mod; import vdc.ast.writer; import std.conv; import stdext.util; version(obsolete) { //Declaration: // alias Decl // Decl class Declaration : Node { mixin ForwardCtor!(); } } // AliasDeclaration: // [Decl] class AliasDeclaration : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { if(writer.writeDeclarations) writer("alias ", getMember(0)); } override void addSymbols(Scope sc) { getMember(0).addSymbols(sc); } } //Decl: // attributes annotations [Type Declarators FunctionBody_opt] class Decl : Node { mixin ForwardCtor!(); bool hasSemi; bool isAlias; Type getType() { return getMember!Type(0); } Declarators getDeclarators() { return getMember!Declarators(1); } FunctionBody getFunctionBody() { return getMember!FunctionBody(2); } override Decl clone() { Decl n = static_cast!Decl(super.clone()); n.hasSemi = hasSemi; n.isAlias = isAlias; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.hasSemi == hasSemi && tn.isAlias == isAlias; } override void toD(CodeWriter writer) { if(isAlias) writer(TOK_alias, " "); writer.writeAttributesAndAnnotations(attr, annotation); writer(getType(), " ", getDeclarators()); bool semi = true; if(auto fn = getFunctionBody()) { if(writer.writeImplementations) { writer.nl; writer(fn); semi = hasSemi; } } if(semi) { writer(";"); writer.nl(); } } override void toC(CodeWriter writer) { bool addExtern = false; if(!isAlias && writer.writeDeclarations && !(attr & Attr_ExternC)) { Node p = parent; while(p && !cast(Aggregate) p && !cast(TemplateDeclaration) p && !cast(Statement) p) p = p.parent; if(!p) addExtern = true; } if(auto fn = getFunctionBody()) { if(writer.writeReferencedOnly && getDeclarators().getDeclarator(0).semanticSearches == 0) return; writer.nl; if(isAlias) writer(TOK_alias, " "); writer.writeAttributesAndAnnotations(attr | (addExtern ? Attr_Extern : 0), annotation); bool semi = true; writer(getType(), " ", getDeclarators()); if(writer.writeImplementations) { writer.nl; writer(fn); semi = hasSemi; } if(semi) { writer(";"); writer.nl(); } } else { foreach(i, d; getDeclarators().members) { if(writer.writeReferencedOnly && getDeclarators().getDeclarator(i).semanticSearches == 0) continue; if(isAlias) writer(TOK_alias, " "); writer.writeAttributesAndAnnotations(attr | (addExtern ? Attr_Extern : 0), annotation); writer(getType(), " ", d, ";"); writer.nl(); } } } override Type calcType() { return getType().calcType(); } override void addSymbols(Scope sc) { getDeclarators().addSymbols(sc); } override void _semantic(Scope sc) { bool isTemplate = false; if(auto fn = getFunctionBody()) { // if it is a function declaration, create a new scope including function parameters scop = sc.push(scop); scop.node = this; if(auto decls = getDeclarators()) if(auto decl = decls.getDeclarator(0)) { foreach(m; decl.members) // template parameters and function parameters and constraint { if(cast(TemplateParameterList) m) { // it does not make sense to add symbols for unexpanded templates isTemplate = decl._isTemplate = true; break; } m.addSymbols(scop); } } if(!isTemplate) super._semantic(scop); //fn.semantic(scop); sc = scop.pop(); } else super._semantic(sc); } } //Declarators: // [DeclaratorInitializer|Declarator...] class Declarators : Node { mixin ForwardCtor!(); Declarator getDeclarator(size_t n) { if(auto decl = cast(Declarator) getMember(n)) return decl; return getMember!DeclaratorInitializer(n).getDeclarator(); } override void toD(CodeWriter writer) { writer(getMember(0)); foreach(decl; members[1..$]) writer(", ", decl); } override void addSymbols(Scope sc) { foreach(decl; members) decl.addSymbols(sc); } } //DeclaratorInitializer: // [Declarator Initializer_opt] class DeclaratorInitializer : Node { mixin ForwardCtor!(); Declarator getDeclarator() { return getMember!Declarator(0); } Expression getInitializer() { return getMember!Expression(1); } override void toD(CodeWriter writer) { writer(getMember(0)); if(Expression expr = getInitializer()) { if(expr.getPrecedence() <= PREC.assign) writer(" = (", expr, ")"); else writer(" = ", getMember(1)); } } override Type calcType() { return getInitializer().calcType(); } override void addSymbols(Scope sc) { getDeclarator().addSymbols(sc); } } // unused class DeclaratorIdentifierList : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { assert(false); } } // unused class DeclaratorIdentifier : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { assert(false); } } class Initializer : Expression { mixin ForwardCtor!(); } //Declarator: // Identifier [DeclaratorSuffixes...] class Declarator : Identifier, CallableNode { mixin ForwardCtorTok!(); Type type; Value value; Node aliasTo; ParameterList parameterList; bool isAlias; bool isRef; bool needsContext; bool _isTemplate; bool _inReinit; TemplateInstantiation[] tmpl; override Declarator clone() { Declarator n = static_cast!Declarator(super.clone()); n.type = type; return n; } final Declarator cloneDeclaratorShallow() { auto decl = static_cast!Declarator(_cloneShallow()); decl.ident = ident; if(parameterList) decl.addMember(parameterList.clone()); // copy info from applySuffixes return decl; } Expression getInitializer() { if(auto di = cast(DeclaratorInitializer) parent) return di.getInitializer(); return null; } override void toD(CodeWriter writer) { super.toD(writer); foreach(m; members) // template parameters and function parameters and constraint writer(m); } bool _isAlias() { for(Node p = parent; p; p = p.parent) if(auto decl = cast(Decl) p) return decl.isAlias; else if(auto pdecl = cast(ParameterDeclarator) p) break; return false; } // returns 0 for never, 1 for non-static statement declaration, 2 for yes bool _needsContext() { for(Node p = parent; p; p = p.parent) if(auto decl = cast(Decl) p) { if(!decl.parent || cast(Module)decl.parent) return false; if (decl.attr & (Attr_Static | Attr_Shared | Attr_Gshared)) return false; return true; } else if(auto pdecl = cast(ParameterDeclarator) p) return true; return false; } override bool isTemplate() { return _isTemplate; } override Node expandTemplate(Scope sc, TemplateArgumentList args) { assert(_isTemplate); calcType(); // ensure suffixes applied TemplateParameterList tpl = getTemplateParameterList(); ArgMatch[] vargs = matchTemplateArgs(ident, sc, args, tpl); if(vargs is null) return this; if(auto impl = getTemplateInstantiation(vargs)) return impl.getDeclarator(); // new instantiation has template parameters as parameterlist and contains // a copy of the function declaration without template arguments auto tmpl = new TemplateInstantiation(this, vargs); addMember(tmpl); // add as suffix tmpl.semantic(getScope()); return tmpl.getDeclarator(); } TemplateInstantiation getTemplateInstantiation(ArgMatch[] args) { return null; } TemplateParameterList getTemplateParameterList() { for(int m = 0; m < members.length; m++) { auto member = members[0]; if(auto tpl = cast(TemplateParameterList) member) return tpl; } return null; } override void addSymbols(Scope sc) { sc.addSymbol(ident, this); } Type applySuffixes(Type t) { // assumed to be only called once by calcType isAlias = _isAlias(); needsContext = _needsContext(); // template parameters and function parameters and constraint size_t mlen = members.length; for(int m = 0; m < members.length; m++) { auto member = members[m]; if(auto pl = cast(ParameterList) member) { auto tf = needsContext ? new TypeDelegate(pl.id, pl.span) : new TypeFunction(pl.id, pl.span); tf.funcDecl = this; tf.returnType = t; // need clones? tf.paramList = pl; tf.scop = getScope(); // not fully added to node tree t = tf; parameterList = pl; } else if(auto sa = cast(SuffixArray) member) { auto idx = sa.getMember(0); if(auto tidx = cast(Type) idx) // TODO: need to resolve identifiers? { auto taa = new TypeAssocArray(sa.id, sa.span); taa.setNextType(t); // need clones? taa.keyType = tidx; t = taa; } else { auto tsa = new TypeStaticArray(sa.id, sa.span); tsa.setNextType(t); // need clones? tsa.dimExpr = static_cast!Expression(idx); t = tsa; } t.scop = getScope(); // not fully added to node tree } else if(auto sda = cast(SuffixDynamicArray) member) { auto tda = new TypeDynamicArray(sda.id, sda.span); tda.addMember(t.clone()); t = tda; tda.scop = getScope(); // not fully added to node tree } // TODO: slice suffix? template parameters, constraint } //// after removal, limit span to remaining members //if(mlen > members.length) //{ // fulspan = span; // foreach(m; members) // extendSpan(m.fulspan); //} return t; } override Node resolve() { return this; } override Type calcType() { if(type) return type; if(aliasTo) return aliasTo.calcType(); for(Node p = parent; p; p = p.parent) { if(auto decl = cast(Decl) p) { type = decl.getType(); if(cast(AutoType)type) { if(auto expr = getInitializer()) type = expr.calcType(); } if(type) { type = applySuffixes(type); type = type.calcType(); } return type; } else if(auto pdecl = cast(ParameterDeclarator) p) { type = pdecl.getType(); if(type) { type = applySuffixes(type); type = type.calcType(); } return type; } } type = semanticErrorType("cannot find Declarator type"); return type; } override Value interpret(Context sc) { if(value) return value; if(aliasTo) return aliasTo.interpret(sc); // TODO: alias not restricted to types Type type = calcType(); if(isAlias) return type.interpret(sc); // TODO: alias not restricted to types else if(needsContext) { if(!sc) return semanticErrorValue("evaluating ", ident, " needs context pointer"); if(auto v = sc.getValue(this)) return v; } return interpretReinit(sc); } Value interpretReinit(Context sc) { if(_inReinit) return semanticErrorValue("initializing ", ident, " refers to itself"); _inReinit = true; scope(exit) _inReinit = false; if(aliasTo) return aliasTo.interpret(sc); // TODO: alias not restricted to types Type type = calcType(); if(isAlias) return type.interpret(sc); // TODO: alias not restricted to types else if(needsContext) { if(!sc) return semanticErrorValue("evaluating ", ident, " needs context pointer"); Value v; if(auto expr = getInitializer()) { v = expr.interpret(sc); if(!v.getType().compare(type)) type.createValue(sc, v); } else v = type.createValue(sc, null); debug v.ident = ident; sc.setValue(this, v); return v; } else if(auto expr = getInitializer()) value = type.createValue(sc, expr.interpret(sc)); else value = type.createValue(sc, null); debug value.ident = ident; return value; } override ParameterList getParameterList() { calcType(); return parameterList; } override FunctionBody getFunctionBody() { for(Node p = parent; p; p = p.parent) if(auto decl = cast(Decl) p) if(auto fbody = decl.getFunctionBody()) return fbody; return null; } override Value interpretCall(Context sc) { logInfo("calling %s", ident); if(auto fbody = getFunctionBody()) return fbody.interpret(sc); return semanticErrorValue(ident, " is not an interpretable function"); } } //TemplateInstantiation: // [ParameterList Decl] class TemplateInstantiation : Node { ArgMatch[] args; Declarator dec; override ParameterList getParameterList() { return getMember!ParameterList(0); } Declarator getDeclarator() { return dec; } this(Declarator ddec, ArgMatch[] vargs) { Decl decl = new Decl; dec = ddec.cloneDeclaratorShallow(); args = vargs; for(Node p = ddec.parent; p; p = p.parent) if(auto ddecl = cast(Decl) p) { if(auto type = ddecl.getType()) decl.addMember(type.clone()); Declarators decs = new Declarators; decs.addMember(dec); decl.addMember(decs); if(auto fbody = ddecl.getFunctionBody()) decl.addMember(fbody.clone()); break; } assert(decl.members.length > 0); if(auto tpl = ddec.getTemplateParameterList()) addMember(createTemplateParameterList(vargs)); else addMember(new ParameterList); addMember(decl); logInfo("created template instance of ", dec.ident, " with args ", vargs); } override void toD(CodeWriter writer) { // suppress output (add a flag to the writer to enable output of expanded template?) } override void addSymbols(Scope sc) { getParameterList().addSymbols(sc); } override bool createsScope() const { return true; } override void _semantic(Scope sc) { sc = enterScope(sc); super._semantic(sc); sc = scop.pop(); } } //IdentifierList: // [IdentifierOrTemplateInstance...] class IdentifierList : Node { mixin ForwardCtor!(); bool global; // semantic data Node resolved; override IdentifierList clone() { IdentifierList n = static_cast!IdentifierList(super.clone()); n.global = global; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.global == global; } Node doResolve(bool isMixin) { // TODO: does not work for package qualified symbols Scope sc; if(global) sc = getModule().scop; else if(auto bc = cast(BaseClass) parent) if(auto clss = bc.parent) if(auto p = clss.parent) sc = p.getScope(); if(!sc) sc = getScope(); Node res; for(int m = 0; sc && m < members.length; m++) { auto id = getMember!Identifier(m); res = sc.resolveWithTemplate(id.ident, sc, id); sc = (res ? res.getScope() : null); } if(!sc && !isMixin) res = semanticErrorType("cannot resolve ", writeD(this)); return res; } override Node resolve() { if(resolved) return resolved; resolved = doResolve(false); return resolved; } override Type calcType() { if(Node n = resolve()) return n.calcType(); return semanticErrorType("cannot resolve type of ", writeD(this)); } override Value interpret(Context sc) { if(Node n = resolve()) return n.interpret(sc); return semanticErrorValue("cannot resolve ", writeD(this)); } override void _semantic(Scope sc) { resolve(); } override void toD(CodeWriter writer) { if(global) writer("."); writer.writeArray(members, "."); } } class Identifier : Node { string ident; this() {} // default constructor needed for clone() this(Token tok) { super(tok); ident = tok.txt; } override Identifier clone() { Identifier n = static_cast!Identifier(super.clone()); n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } override void toD(CodeWriter writer) { writer.writeIdentifier(ident); } override ArgumentList getFunctionArguments() { if(parent) return parent.getFunctionArguments(); return null; } override Node resolve() { if(parent) return parent.resolve(); return super.resolve(); } override Type calcType() { if(auto p = cast(IdentifierList) parent) return p.calcType(); if(auto p = cast(IdentifierExpression) parent) return p.calcType(); if(auto p = cast(DotExpression) parent) return p.calcType(); if(auto p = cast(ModuleFullyQualifiedName) parent) { } if(auto p = cast(ForeachType) parent) return parent.calcType(); return super.calcType(); } override Value interpret(Context ctx) { if(auto p = cast(IdentifierList) parent) return p.interpret(ctx); if(auto p = cast(IdentifierExpression) parent) return p.interpret(ctx); if(auto p = cast(DotExpression) parent) return p.interpret(ctx); if(auto p = cast(ModuleFullyQualifiedName) parent) { } if(auto p = cast(ForeachType) parent) return parent.interpret(ctx); return super.interpret(ctx); } } //ParameterList: // [Parameter...] attributes class ParameterList : Node { mixin ForwardCtor!(); Parameter getParameter(size_t i) { return getMember!Parameter(i); } bool varargs; bool anonymous_varargs; override ParameterList clone() { ParameterList n = static_cast!ParameterList(super.clone()); n.varargs = varargs; n.anonymous_varargs = anonymous_varargs; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.varargs == varargs && tn.anonymous_varargs == anonymous_varargs; } override void toD(CodeWriter writer) { writer("("); writer.writeArray(members); if(anonymous_varargs) writer(", ..."); else if(varargs) writer("..."); writer(")"); if(attr) { writer.writeAttributesAndAnnotations(attr, annotation, true); } } override void addSymbols(Scope sc) { foreach(m; members) m.addSymbols(sc); } } //Parameter: // io [ParameterDeclarator Expression_opt] class Parameter : Node { mixin ForwardCtor!(); TokenId io; ParameterDeclarator getParameterDeclarator() { return getMember!ParameterDeclarator(0); } Expression getInitializer() { return getMember!Expression(1); } override Parameter clone() { Parameter n = static_cast!Parameter(super.clone()); n.io = io; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.io == io; } override void toD(CodeWriter writer) { if(io) writer(io, " "); writer(getMember(0)); if(members.length > 1) writer(" = ", getMember(1)); } override void addSymbols(Scope sc) { getParameterDeclarator().addSymbols(sc); } override Type calcType() { return getParameterDeclarator().calcType(); } } //ParameterDeclarator: // attributes [Type Declarator] class ParameterDeclarator : Node { mixin ForwardCtor!(); Type getType() { return getMember!Type(0); } Declarator getDeclarator() { return members.length > 1 ? getMember!Declarator(1) : null; } override void toD(CodeWriter writer) { writer.writeAttributesAndAnnotations(attr, annotation); writer(getType()); if(auto decl = getDeclarator()) writer(" ", decl); } override void addSymbols(Scope sc) { if (auto decl = getDeclarator()) decl.addSymbols(sc); } override Type calcType() { if (auto decl = getDeclarator()) return decl.calcType(); return getType().calcType(); } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/all.d0000664000175000017500000000122112776214756026232 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.all; public import vdc.ast.aggr; public import vdc.ast.decl; public import vdc.ast.expr; public import vdc.ast.iasm; public import vdc.ast.misc; public import vdc.ast.mod; public import vdc.ast.node; public import vdc.ast.stmt; public import vdc.ast.tmpl; public import vdc.ast.type; public import vdc.ast.writer; ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/node.d0000664000175000017500000004507012776214756026421 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.node; import vdc.util; import vdc.semantic; import vdc.lexer; import vdc.ast.expr; import vdc.ast.type; import vdc.ast.mod; import vdc.ast.tmpl; import vdc.ast.decl; import vdc.ast.misc; import vdc.ast.writer; import vdc.logger; import vdc.interpret; import std.exception; import std.stdio; import std.string; import std.conv; import std.algorithm; import stdext.util; //version = COUNT; //version = NODE_ALLOC; version(COUNT) import visuald.windows; version(NODE_ALLOC) class NodeAllocData { enum kSize = 0x4000; byte* pos; private byte** data; private int numdata; byte* base() { return data[numdata-1]; } void moreData() { byte* arr = cast(byte*) gc_calloc(kSize, 0); // when appending to the array, ensure that no old reference is dangling byte** ndata = cast(byte**) gc_malloc((numdata + 1) * data[0].sizeof, 0); ndata[0..numdata] = data[0..numdata]; data[0..numdata] = null; ndata[numdata] = arr; gc_free(data); data = ndata; numdata++; pos = arr; } ~this() { destroy(false); // must not call back into GC } void destroy(bool free) { while(numdata > 0) { size_t sz; byte* beg = data[--numdata]; byte* end = beg + kSize; for(byte* p = beg; p < end && *cast(size_t*)p != 0; p += sz) { Node n = cast(Node) p; sz = n.classinfo.init.length; sz = (sz + 15) & ~15; assert(sz > 0); clear(n); // calls rt_finalize } if(free) gc_free(beg); data[numdata] = null; } if(data && free) gc_free(data); data = null; pos = null; } static NodeAllocData current; static NodeAllocData detachCurrent() { auto cur = current; current = null; return cur; } static void checkAlloc(size_t sz) { if(!current) current = new NodeAllocData; if(!current.pos) current.moreData(); if(current.pos + sz > current.base() + kSize) current.moreData(); } static void* alloc(size_t sz) { sz = (sz + 15) & ~15; checkAlloc(sz); void* p = current.pos; current.pos += sz; //if(current.pos < current.base() + kSize) // *cast(size_t*)current.pos = 0; return p; } } // moved out of Node due to regression http://d.puremagic.com/issues/show_bug.cgi?id=9101 mixin template ForwardCtor() { this() { // default constructor needed for clone() } this(ref const(TextSpan) _span) { super(_span); } this(Token tok) { super(tok); } this(TokenId _id, ref const(TextSpan) _span) { super(_id, _span); } } mixin template ForwardCtorTok() { this() {} // default constructor needed for clone() this(Token tok) { super(tok); } } mixin template ForwardCtorNoId() { this() {} // default constructor needed for clone() this(ref const(TextSpan) _span) { super(_span); } this(Token tok) { super(tok.span); } } class Node { TokenId id; Attribute attr; Annotation annotation; TextSpan span; // file extracted from parent module TextSpan fulspan; Node parent; Node[] members; // semantic data int semanticSearches; Scope scop; version(COUNT) static __gshared int countNodes; version(NODE_ALLOC) new(size_t sz) { assert(sz < NodeAllocData.kSize / 2); //return gc_malloc(sz, 1); // BlkAttr.FINALIZE void* p = NodeAllocData.alloc(sz); return p; } this() { version(COUNT) InterlockedIncrement(&countNodes); // default constructor needed for clone() } this(ref const(TextSpan) _span) { version(COUNT) InterlockedIncrement(&countNodes); fulspan = span = _span; } this(Token tok) { version(COUNT) InterlockedIncrement(&countNodes); id = tok.id; span = tok.span; fulspan = tok.span; } this(TokenId _id, ref const(TextSpan) _span) { version(COUNT) InterlockedIncrement(&countNodes); id = _id; fulspan = span = _span; } version(COUNT) ~this() { version(COUNT) InterlockedDecrement(&countNodes); } void reinit() { id = 0; attr = 0; annotation = 0; members.length = 0; clearSpan(); } final Node _cloneShallow() { Node n = static_cast!Node(this.classinfo.create()); n.id = id; n.attr = attr; n.annotation = annotation; n.span = span; n.fulspan = fulspan; return n; } Node clone() { Node n = _cloneShallow(); foreach(m; members) n.addMember(m.clone()); return n; } bool compare(const(Node) n) const { if(this.classinfo !is n.classinfo) return false; if(n.id != id || n.attr != attr || n.annotation != annotation) return false; // ignore span if(members.length != n.members.length) return false; for(int m = 0; m < members.length; m++) if(!members[m].compare(n.members[m])) return false; return true; } //////////////////////////////////////////////////////////// Node visit(DG)(DG dg) { if(!dg(this)) return this; for(int m = 0; m < members.length; m++) if(auto n = members[m].visit(dg)) return n; return null; } bool detachFromModule(Module mod) { return true; } void disconnect() { for(int m = 0; m < members.length; m++) members[m].disconnect(); for(int m = 0; m < members.length; m++) members[m].parent = null; members = members.init; } void free() { for(int m = 0; m < members.length; m++) members[m].free(); for(int m = 0; m < members.length; m++) members[m].parent = null; import core.memory; for(int m = 0; m < members.length; m++) GC.free(cast(void*) (members[m])); GC.free(cast(void*) (members.ptr)); members = members.init; } //////////////////////////////////////////////////////////// abstract void toD(CodeWriter writer) { writer(this.classinfo.name); writer.nl(); auto indent = CodeIndenter(writer); foreach(c; members) writer(c); } void toC(CodeWriter writer) { toD(writer); } //////////////////////////////////////////////////////////// static string genCheckState(string state) { return " if(" ~ state ~ "!= 0) return; " ~ state ~ " = 1; scope(exit) " ~ state ~ " = 2; "; } enum SemanticState { None, ExpandingNonScopeMembers, ExpandedNonScopeMembers, AddingSymbols, AddedSymbols, ResolvingSymbols, ResolvedSymbols, SemanticDone, } int semanticState; void expandNonScopeSimple(Scope sc, size_t i, size_t j) { Node[1] narray; for(size_t m = i; m < j; ) { Node n = members[m]; narray[0] = n; size_t mlen = members.length; Node[] nm = n.expandNonScopeBlock(sc, narray); assert(members.length == mlen); if(nm.length == 1 && nm[0] == n) { n.addSymbols(sc); assert(members.length == mlen); m++; } else { replaceMember(m, nm); assert(members.length == mlen + nm.length - 1); j += nm.length - 1; } } } void expandNonScopeBlocks(Scope sc) { if(semanticState >= SemanticState.ExpandingNonScopeMembers) return; // simple expansions semanticState = SemanticState.ExpandingNonScopeMembers; expandNonScopeSimple(sc, 0, members.length); // expansions with interpretation Node[1] narray; for(int m = 0; m < members.length; ) { Node n = members[m]; narray[0] = n; Node[] nm = n.expandNonScopeInterpret(sc, narray); if(nm.length == 1 && nm[0] == n) m++; else { replaceMember(m, nm); expandNonScopeSimple(sc, m, m + nm.length); } } semanticState = SemanticState.ExpandedNonScopeMembers; } Node[] expandNonScopeBlock(Scope sc, Node[] athis) { return athis; } Node[] expandNonScopeInterpret(Scope sc, Node[] athis) { return athis; } void addMemberSymbols(Scope sc) { if(semanticState >= SemanticState.AddingSymbols) return; scop = sc; expandNonScopeBlocks(scop); semanticState = SemanticState.AddedSymbols; } void addSymbols(Scope sc) { } bool createsScope() const { return false; } Scope enterScope(ref Scope nscope, Scope sc) { if(!nscope) { nscope = sc.pushClone(); nscope.node = this; addMemberSymbols(nscope); return nscope; } return sc.push(nscope); } Scope enterScope(Scope sc) { return enterScope(scop, sc); } final void semantic(Scope sc) { assert(sc); if(semanticState < SemanticState.SemanticDone) { logInfo("Scope(%s):semantic(%s=%s)", cast(void*)sc, this, cast(void*)this); LogIndent indent = LogIndent(1); _semantic(sc); semanticState = SemanticState.SemanticDone; } } void _semantic(Scope sc) { // throw new SemanticException(text(this, ".semantic not implemented")); foreach(m; members) m.semantic(sc); } Scope getScope() { if(scop) return scop; if(parent) { Scope sc = parent.getScope(); assert(sc); if(sc && createsScope()) sc = enterScope(sc); return sc; } return null; } Node resolve() { return null; } Type calcType() { return semanticErrorType(this, ".calcType not implemented"); } Value interpret(Context sc) { return semanticErrorValue(this, ".interpret not implemented"); } Value interpretCatch(Context sc) { try { return interpret(sc); } catch(InterpretException) { } return semanticErrorValue(this, ": interpretation stopped"); } ParameterList getParameterList() { return null; } ArgumentList getFunctionArguments() { return null; } bool isTemplate() { return false; } Node expandTemplate(Scope sc, TemplateArgumentList args) { return this; } //////////////////////////////////////////////////////////// version(COUNT) {} else // invariant does not work with destructor invariant() { if(!__ctfe) foreach(m; members) assert(m.parent is this); } void addMember(Node m) { assert(m.parent is null); members ~= m; m.parent = this; extendSpan(m.fulspan); } Node removeMember(Node m) { auto n = std.algorithm.countUntil(members, m); assert(n >= 0); return removeMember(n); } Node removeMember(size_t m) { Node n = members[m]; removeMember(m, 1); return n; } void removeMember(size_t m, size_t cnt) { assert(m >= 0 && m + cnt <= members.length); for (size_t i = 0; i < cnt; i++) members[m + i].parent = null; for (size_t n = m + cnt; n < members.length; n++) members[n - cnt] = members[n]; members.length = members.length - cnt; } Node[] removeAll() { for (size_t m = 0; m < members.length; m++) members[m].parent = null; Node[] nm = members; members = members.init; return nm; } void replaceMember(Node m, Node[] nm) { auto n = std.algorithm.countUntil(members, m); assert(n >= 0); replaceMember(n, nm); } void replaceMember(size_t m, Node[] nm) { if(m < members.length) members[m].parent = null; if(nm.length == 1 && m < members.length) members[m] = nm[0]; else members = members[0..m] ~ nm ~ members[m+1..$]; foreach(n; nm) n.parent = this; } T getMember(T = Node)(size_t idx) { if (idx < 0 || idx >= members.length) return null; return static_cast!T(members[idx]); } Module getModule() { Node n = this; while(n) { if(n.scop) return n.scop.mod; n = n.parent; } return null; } string getModuleFilename() { Module mod = getModule(); if(!mod) return null; return mod.filename; } void semanticError(T...)(T args) { semanticErrorLoc(getModuleFilename(), span.start, args); } ErrorValue semanticErrorValue(T...)(T args) { semanticErrorLoc(getModuleFilename(), span.start, args); return Singleton!(ErrorValue).get(); } ErrorType semanticErrorType(T...)(T args) { semanticErrorLoc(getModuleFilename(), span.start, args); return Singleton!(ErrorType).get(); } //////////////////////////////////////////////////////////// void extendSpan(ref const(TextSpan) _span) { if(_span.start < fulspan.start) fulspan.start = _span.start; if(_span.end > fulspan.end) fulspan.end = _span.end; } void limitSpan(ref const(TextSpan) _span) { if(_span.start > fulspan.start) fulspan.start = _span.start; if(_span.end < fulspan.end) fulspan.end = _span.end; } void clearSpan() { span.end.line = span.start.line; span.end.index = span.start.index; fulspan = span; } } class ParseRecoverNode : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { string start = to!string(fulspan.start.line) ~ "," ~ to!string(fulspan.start.index); string end = to!string(fulspan.end.line) ~ "," ~ to!string(fulspan.end.index); writer("/+ syntax error: span = ", start, " - ", end, " +/"); writer.nl(); } override void _semantic(Scope sc) { } } interface CallableNode { Value interpretCall(Context sc); ParameterList getParameterList(); FunctionBody getFunctionBody(); } TextPos minimumTextPos(Node node) { version(all) return node.fulspan.start; else { TextPos start = node.span.start; while(node.members.length > 0) { if(compareTextSpanAddress(node.members[0].span.start.line, node.members[0].span.start.index, start.line, start.index) < 0) start = node.members[0].span.start; node = node.members[0]; } return start; } } TextPos maximumTextPos(Node node) { version(all) return node.fulspan.end; else { TextPos end = node.span.end; while(node.members.length > 0) { if(compareTextSpanAddress(node.members[$-1].span.end.line, node.members[$-1].span.start.index, end.line, end.index) > 0) end = node.members[$-1].span.end; node = node.members[$-1]; } return end; } } // prefer start bool nodeContains(Node node, in TextPos pos) { TextPos start = minimumTextPos(node); if(start > pos) return false; TextPos end = maximumTextPos(node); if(end <= pos) return false; return true; } bool nodeContains(Node node, in TextSpan* span) { TextPos start = minimumTextPos(node); if(start > span.start) return false; TextPos end = maximumTextPos(node); if(end < span.end) return false; return true; } // prefer end bool nodeContainsEnd(Node node, in TextPos* pos) { TextPos start = minimumTextPos(node); if(start >= *pos) return false; TextPos end = maximumTextPos(node); if(end < *pos) return false; return true; } // figure out whether the given range is between the children of a binary expression bool isBinaryOperator(Node root, int startLine, int startIndex, int endLine, int endIndex) { TextPos pos = TextPos(startIndex, startLine); if(!nodeContains(root, pos)) return false; L_loop: if(root.members.length == 2) { if(cast(BinaryExpression) root) if(maximumTextPos(root.members[0]) <= pos && minimumTextPos(root.members[1]) > pos) return true; } foreach(m; root.members) if(nodeContains(m, pos)) { root = m; goto L_loop; } return false; } Node getTextPosNode(Node root, in TextSpan* span, bool *inDotExpr) { if(!nodeContains(root, span)) return null; L_loop: foreach(m; root.members) if(nodeContains(m, span)) { root = m; goto L_loop; } if(inDotExpr) *inDotExpr = false; if(auto dotexpr = cast(DotExpression)root) { if(inDotExpr) { root = dotexpr.getExpression(); *inDotExpr = true; } } else if(auto id = cast(Identifier)root) { if(auto dotexpr = cast(DotExpression)id.parent) { if(dotexpr.getIdentifier() == id) { if(inDotExpr) { root = dotexpr.getExpression(); *inDotExpr = true; } else root = dotexpr; } } } return root; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/misc.d0000664000175000017500000004274512776214756026435 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.misc; import vdc.lexer; import vdc.semantic; import vdc.interpret; import vdc.util; import vdc.ast.node; import vdc.ast.expr; import vdc.ast.decl; import vdc.ast.stmt; import vdc.ast.type; import vdc.ast.writer; import stdext.util; import std.algorithm; //EnumDeclaration: // enum EnumTag EnumBody // enum EnumBody // enum EnumTag : EnumBaseType EnumBody // enum : EnumBaseType EnumBody // enum Identifier = AssignExpression ; // //EnumTag: // Identifier // //EnumBaseType: // Type class EnumDeclaration : Type { mixin ForwardCtor!(); string ident; bool isDecl; // does not have body syntax override bool propertyNeedsParens() const { return false; } override EnumDeclaration clone() { EnumDeclaration n = static_cast!EnumDeclaration(super.clone()); n.ident = ident; n.isDecl = isDecl; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.isDecl == isDecl && tn.ident == ident; } Type getBaseType() { return members.length > 1 ? getMember!Type(0) : null; } EnumBody getBody() { return members.length > 0 ? getMember!EnumBody(members.length - 1) : null; } override void toD(CodeWriter writer) { if(!writer.writeDeclarations) return; if(writer.writeReferencedOnly) { if(ident.length) { if(semanticSearches == 0) return; } else if(auto bdy = getBody()) if(!bdy.hasSemanticSearches()) return; } if(isDecl) { writer("enum "); if (auto type = getBaseType()) writer(type, " "); writer.writeArray(getBody().getEnumMembers().members); writer(";"); writer.nl; } else { writer("enum "); writer.writeIdentifier(ident); if(writer.writeClassImplementations) { if(Type type = getBaseType()) writer(" : ", type); if (members.length > 0) { writer.nl(); writer(getBody()); } else { writer(";"); writer.nl; } } } } override bool createsScope() const { return ident.length > 0; } override void addSymbols(Scope sc) { if(ident.length) sc.addSymbol(ident, this); else if(auto bdy = getBody()) bdy.addSymbols(sc); } override Value createValue(Context ctx, Value initValue) { if(auto bt = getBaseType()) return getBaseType().createValue(ctx, initValue); if(initValue) return initValue.getType().createValue(ctx, initValue); return Value.create(0); } } // forward declaration not needed with proper handling //EnumBody: // ; // { EnumMembers } class EnumBody : Node { mixin ForwardCtor!(); EnumMembers getEnumMembers() { return getMember!EnumMembers(0); } override void toD(CodeWriter writer) { writer("{"); writer.nl(); { CodeIndenter indent = CodeIndenter(writer); writer(getMember(0)); } writer("}"); writer.nl(); } bool hasSemanticSearches() { return getEnumMembers().hasSemanticSearches(); } override void addSymbols(Scope sc) { getMember(0).addSymbols(sc); } } //EnumMembers: // EnumMember // EnumMember , // EnumMember , EnumMembers class EnumMembers : Node { mixin ForwardCtor!(); override void toD(CodeWriter writer) { foreach(m; members) { writer(m, ","); writer.nl(); } } bool hasSemanticSearches() { foreach(m; members) if(m.semanticSearches > 0) return true; return false; } override void addSymbols(Scope sc) { addMemberSymbols(sc); } } //EnumMember: // Identifier // Identifier = AssignExpression // Type Identifier = AssignExpression class EnumMember : Node { mixin ForwardCtor!(); string ident; Type type; Value value; override EnumMember clone() { EnumMember n = static_cast!EnumMember(super.clone()); n.ident = ident; return n; } override bool compare(const(Node) n) const { if(!super.compare(n)) return false; auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } string getIdentifier() { return ident; } Expression getInitializer() { return members.length > 0 ? getMember!Expression(members.length - 1) : null; } Type getType() { return members.length > 1 ? getMember!Type(0) : null; } override Type calcType() { if(type) return type; if(auto dtype = getType()) type = dtype.calcType(); else if(parent && parent.parent && parent.parent) if(auto ed = cast(EnumDeclaration)parent.parent.parent) type = ed.calcType(); if(!type) type = semanticErrorType("cannot determine type of enum member ", ident); return type; } override void toD(CodeWriter writer) { if(Type type = getType()) writer(type, " "); writer.writeIdentifier(ident); if(auto expr = getInitializer()) writer(" = ", expr); } override void addSymbols(Scope sc) { sc.addSymbol(ident, this); } override Value interpret(Context sc) { if(value) return value; Value ival; if(Expression expr = getInitializer()) ival = expr.interpret(sc); else if(auto em = cast(EnumMembers)parent) { auto n = countUntil(parent.members, this); if(n > 0) { ival = parent.members[n - 1].interpret(sc); ival = ival.opBin(sc, TOK_add, Value.create(cast(byte)1)); } } value = calcType().createValue(sc, ival); return value; } } //////////////////////////////////////////////////////////////// //FunctionBody: // [InStatement_opt OutStatement_opt BodyStatement] outIdentifier class FunctionBody : Node { mixin ForwardCtor!(); Statement inStatement; Statement outStatement; Statement bodyStatement; OutIdentifier outIdentifier; Scope inScop; Scope outScop; override FunctionBody clone() { FunctionBody n = static_cast!FunctionBody(super.clone()); for(int m = 0; m < members.length; m++) { if(members[m] is inStatement) n.inStatement = static_cast!Statement(n.members[m]); if(members[m] is outStatement) n.outStatement = static_cast!Statement(n.members[m]); if(members[m] is bodyStatement) n.bodyStatement = static_cast!Statement(n.members[m]); if(members[m] is outIdentifier) n.outIdentifier = static_cast!OutIdentifier(n.members[m]); } return n; } override void toD(CodeWriter writer) { if(inStatement) { writer("in"); writer.nl(); writer(inStatement); } if(outStatement) { if(outIdentifier) writer("out(", outIdentifier, ")"); else writer("out"); writer.nl(); writer(outStatement); } if(bodyStatement) { if(inStatement || outStatement) { writer("body"); writer.nl(); } writer(bodyStatement); } writer.nl; // should not be written for function literals } override bool createsScope() const { return true; } override Scope enterScope(ref Scope nscope, Scope sc) { if(!nscope) { nscope = new Scope; nscope.annotations = sc.annotations; nscope.attributes = sc.attributes; nscope.mod = sc.mod; nscope.parent = sc; nscope.node = this; ParameterList pl; if(auto callable = cast(CallableNode) parent) pl = callable.getParameterList(); if(auto decl = cast(Decl) parent) if(auto decls = decl.getDeclarators()) if(auto callable = cast(CallableNode) decls.getDeclarator(0)) pl = callable.getParameterList(); if(pl) pl.addSymbols(nscope); return nscope; } return sc.push(nscope); } override void _semantic(Scope sc) { if(inStatement) { sc = enterScope(inScop, sc); inStatement.semantic(sc); sc = sc.pop(); } if(bodyStatement) { sc = super.enterScope(sc); bodyStatement.semantic(sc); sc = sc.pop(); } if(outStatement) { // TODO: put into scope of inStatement? sc = enterScope(outScop, sc); if(outIdentifier) sc.addSymbol(outIdentifier.ident, outIdentifier); // TODO: create Symbol for outIdentifier outStatement.semantic(sc); sc = sc.pop(); } } override Value interpret(Context sc) { Value value; if(inStatement) { inStatement.interpret(sc); } if(bodyStatement) { value = bodyStatement.interpret(sc); } if(outStatement) { // TODO: put into scope of inStatement? outStatement.interpret(sc); } if(!value) return theVoidValue; return value; } } class OutIdentifier : Identifier { mixin ForwardCtorTok!(); override Type calcType() { auto fb = cast(FunctionBody)parent; if(fb) { auto type = fb.parent.calcType(); if(auto tf = cast(TypeFunction) type) return tf.getReturnType(); } return semanticErrorType("cannot calculate type of out identifier ", ident); } } //////////////////////////////////////////////////////////////// class ConditionalDeclaration : Node { mixin ForwardCtor!(); Condition getCondition() { return getMember!Condition(0); } Node getThenDeclarations() { return getMember(1); } Node getElseDeclarations() { return getMember(2); } override void toD(CodeWriter writer) { writer(getMember(0)); if(id == TOK_colon) writer(":"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(1)); } if(members.length > 2) { writer("else"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(2)); } } } override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { Node n; if(getCondition().evalCondition(sc)) n = getThenDeclarations(); else n = getElseDeclarations(); if(!n) return null; athis[0] = removeMember(n); return athis; } } class ConditionalStatement : Statement { mixin ForwardCtor!(); Condition getCondition() { return getMember!Condition(0); } Statement getThenStatement() { return getMember!Statement(1); } Statement getElseStatement() { return getMember!Statement(2); } override void toD(CodeWriter writer) { writer(getMember(0)); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(1)); } if(members.length > 2) { writer("else"); writer.nl; { CodeIndenter indent = CodeIndenter(writer); writer(getMember(2)); } } } override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { if(cast(StaticIfCondition) getCondition()) return athis; Node n; if(getCondition().evalCondition(sc)) n = getThenStatement(); else n = getElseStatement(); if(!n) return null; athis[0] = removeMember(n); return athis; } override Node[] expandNonScopeInterpret(Scope sc, Node[] athis) { if(!cast(StaticIfCondition) getCondition()) return athis; Node n; if(getCondition().evalCondition(sc)) n = getThenStatement(); else n = getElseStatement(); if(!n) return null; athis[0] = n; return athis; } } mixin template GetIdentifierOrInteger(int pos = 0) { bool isIdentifier() { return getMember(pos).id == TOK_Identifier; } string getIdentifier() { return getMember!Identifier(pos).ident; } int getInteger() { return getMember!IntegerLiteralExpression(pos).getInt(); } } class VersionSpecification : Node { mixin ForwardCtor!(); mixin GetIdentifierOrInteger!(); override void toD(CodeWriter writer) { writer("version = ", getMember(0), ";"); writer.nl; } override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { auto mod = sc.mod; if(isIdentifier()) mod.specifyVersion(getIdentifier(), span.start); else mod.specifyVersion(getInteger()); return []; } } class DebugSpecification : Node { mixin ForwardCtor!(); mixin GetIdentifierOrInteger!(); override void toD(CodeWriter writer) { writer("debug = ", getMember(0), ";"); writer.nl; } override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { auto mod = sc.mod; if(isIdentifier()) mod.specifyDebug(getIdentifier(), span.start); else mod.specifyDebug(getInteger()); return []; } } class Condition : Node { mixin ForwardCtor!(); abstract bool evalCondition(Scope sc); } class VersionCondition : Condition { mixin ForwardCtor!(); mixin GetIdentifierOrInteger!(); override bool evalCondition(Scope sc) { if(members.length == 0) { assert(id == TOK_unittest || id == TOK_assert); if(auto mod = getModule()) if(auto prj = mod.getProject()) return prj.options.unittestOn || (id == TOK_assert && prj.options.debugOn); return false; } auto mod = getModule(); if(isIdentifier()) return mod.versionEnabled(getIdentifier(), span.start); return mod.versionEnabled(getInteger()); } override void toD(CodeWriter writer) { if(members.length > 0) writer("version(", getMember(0), ") "); else { assert(id == TOK_unittest); writer("version(", id, ")"); } } } class DebugCondition : Condition { mixin ForwardCtor!(); mixin GetIdentifierOrInteger!(); override bool evalCondition(Scope sc) { auto mod = getModule(); if(members.length == 0) return mod.debugEnabled(); if(isIdentifier()) return mod.debugEnabled(getIdentifier(), span.start); return mod.debugEnabled(getInteger()); } override void toD(CodeWriter writer) { if(members.length > 0) writer("debug(", getMember(0), ") "); else writer("debug "); } } class StaticIfCondition : Condition { mixin ForwardCtor!(); override bool evalCondition(Scope sc) { Context ctx = new Context(nullContext); ctx.scop = sc; return getMember!Expression(0).interpret(ctx).toBool(); } override void toD(CodeWriter writer) { writer("static if(", getMember(0), ")"); } } //Aggregate: // [ArgumentList] class StaticAssert : Statement { mixin ForwardCtor!(); ArgumentList getArgumentList() { return getMember!ArgumentList(0); } override void toD(CodeWriter writer) { if(writer.writeImplementations) { writer("static assert(", getMember(0), ");"); writer.nl(); } } override void toC(CodeWriter writer) { } override void _semantic(Scope sc) { auto args = getArgumentList(); auto expr = args.getMember!Expression(0); if(!expr.interpretCatch(globalContext).toBool()) { string txt; for(int a = 1; a < args.members.length; a++) { auto arg = args.getMember!Expression(a); txt ~= arg.interpret(globalContext).toMixin(); } if(txt.length == 0) txt = "static assertion " ~ writeD(expr) ~ " failed"; semanticErrorPos(span.start, txt); } } override Value interpret(Context sc) { return null; // "execution" done in _sementic } } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/vdc/ast/iasm.d0000664000175000017500000000702512776214756026423 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module vdc.ast.iasm; import vdc.util; import vdc.lexer; import vdc.ast.node; import vdc.ast.writer; class AsmInstruction : Node { mixin ForwardCtor!(); Token[] tokens; void addToken(Token tok) { Token ntok = new Token; ntok.copy(tok); tokens ~= ntok; } override void toD(CodeWriter writer) { foreach(t; tokens) { writer(t.txt, " "); } } } //AsmInstruction: // Identifier : AsmInstruction // "align" IntegerExpression // "even" // "naked" // "db" Operands // "ds" Operands // "di" Operands // "dl" Operands // "df" Operands // "dd" Operands // "de" Operands // Opcode // Opcode Operands // //Operands: // Operand // Operand , Operands // //IntegerExpression: // IntegerLiteral // Identifier // //Operand: // AsmExp // //AsmExp: // AsmLogOrExp // AsmLogOrExp ? AsmExp : AsmExp // //AsmLogOrExp: // AsmLogAndExp // AsmLogAndExp || AsmLogAndExp // //AsmLogAndExp: // AsmOrExp // AsmOrExp && AsmOrExp // //AsmOrExp: // AsmXorExp // AsmXorExp | AsmXorExp // //AsmXorExp: // AsmAndExp // AsmAndExp ^ AsmAndExp // //AsmAndExp: // AsmEqualExp // AsmEqualExp & AsmEqualExp // //AsmEqualExp: // AsmRelExp // AsmRelExp == AsmRelExp // AsmRelExp != AsmRelExp // //AsmRelExp: // AsmShiftExp // AsmShiftExp < AsmShiftExp // AsmShiftExp <= AsmShiftExp // AsmShiftExp > AsmShiftExp // AsmShiftExp >= AsmShiftExp // //AsmShiftExp: // AsmAddExp // AsmAddExp << AsmAddExp // AsmAddExp >> AsmAddExp // AsmAddExp >>> AsmAddExp // //AsmAddExp: // AsmMulExp // AsmMulExp + AsmMulExp // AsmMulExp - AsmMulExp // //AsmMulExp: // AsmBrExp // AsmBrExp * AsmBrExp // AsmBrExp / AsmBrExp // AsmBrExp % AsmBrExp // //AsmBrExp: // AsmUnaExp // AsmBrExp [ AsmExp ] // //AsmUnaExp: // AsmTypePrefix AsmExp // "offsetof" AsmExp // "seg" AsmExp // + AsmUnaExp // - AsmUnaExp // ! AsmUnaExp // ~ AsmUnaExp // AsmPrimaryExp // //AsmPrimaryExp: // IntegerLiteral // FloatLiteral // "__LOCAL_SIZE" // $ // Register // DotIdentifier // //DotIdentifier: // Identifier // Identifier . DotIdentifier // //AsmTypePrefix: // "near" "ptr" // "far" "ptr" // byte "ptr" // short "ptr" // int "ptr" // "word" "ptr" // "dword" "ptr" // "qword" "ptr" // float "ptr" // double "ptr" // real "ptr" // //Register: // TOK_register // //Opcode: // TOK_opcode // //Identifier: // TOK_Identifier // //Integer: // IntegerLiteral // //IntegerLiteral: // TOK_IntegerLiteral // //FloatLiteral: // TOK_FloatLiteral // //StringLiteral: // TOK_StringLiteral // //CharacterLiteral: // TOK_CharacterLiteral // //// removed from grammar: //// ////Register: //// AL AH AX EAX //// BL BH BX EBX //// CL CH CX ECX //// DL DH DX EDX //// BP EBP //// SP ESP //// DI EDI //// SI ESI //// ES CS SS DS GS FS //// CR0 CR2 CR3 CR4 //// DR0 DR1 DR2 DR3 DR6 DR7 //// TR3 TR4 TR5 TR6 TR7 //// ST //// ST(0) ST(1) ST(2) ST(3) ST(4) ST(5) ST(6) ST(7) //// MM0 MM1 MM2 MM3 MM4 MM5 MM6 MM7 //// XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 //// ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/stdext/0000775000175000017500000000000012776214756025271 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/stdext/array.d0000664000175000017500000000467612776214756026571 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module stdext.array; T* contains(T)(T[] arr, bool delegate(ref T t) dg) { foreach(ref T t; arr) if (dg(t)) return &t; return null; } T* contains(T)(T[] arr, T val) { foreach(ref T t; arr) if (t == val) return &t; return null; } int arrIndex(T)(in T[] arr, T val) { for(int i = 0; i < arr.length; i++) if (arr[i] == val) return i; return -1; } int arrIndexPtr(T)(in T[] arr, T val) { for(int i = 0; i < arr.length; i++) if (arr[i] is val) return i; return -1; } void addunique(T)(ref T[] arr, T val) { if (!contains(arr, val)) arr ~= val; } void addunique(T)(ref T[] arr, T[] vals) { foreach(val; vals) if (!contains(arr, val)) arr ~= val; } void remove(T)(ref T[] arr, T val) { int idx = arrIndex(arr, val); if(idx >= 0) arr = arr[0..idx] ~ arr[idx+1..$]; } void adduniqueLRU(T)(ref T[] arr, T val, size_t maxEntries) { for(size_t i = 0; i < arr.length; i++) if(val == arr[i]) { // move to front if(i > 0) arr = [val] ~ arr[0..i] ~ arr[i+1 .. $]; return; } if(arr.length >= maxEntries) arr.length = maxEntries - 1; arr = [val] ~ arr; } /////////////////////////////////////////////////////////////////////// struct Set(T) { bool[T] _payload; alias _payload this; T first() { foreach(n, b; _payload) return n; return null; } } bool contains(T)(ref bool[T] arr, T val) { return (val in arr); } void addunique(T)(ref bool[T] arr, T val) { arr[val] = true; } void addunique(T)(ref bool[T] arr, T[] vals) { foreach(val; vals) arr[val] = true; } void addunique(T)(ref bool[T] arr, bool[T] vals) { foreach(val, b; vals) arr[val] = true; } // needed in dmd 2.058beta //version(none): void addunique(T)(ref Set!T arr, T val) { arr[val] = true; } void addunique(T)(ref Set!T arr, bool[T] vals) { foreach(val, b; vals) arr[val] = true; } void remove(T)(ref bool[T] arr, T val) { arr.remove(val); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/stdext/util.d0000664000175000017500000000152712776214756026420 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module stdext.util; //////////////////////////////////////////////////////////////// inout(T) static_cast(T, S = Object)(inout(S) p) { if(!p) return null; if(__ctfe) return cast(inout(T)) p; assert(cast(inout(T)) p); void* vp = cast(void*)p; return cast(inout(T)) vp; } //////////////////////////////////////////////////////////////// bool isIn(T...)(T values) { T[0] needle = values[0]; foreach(v; values[1..$]) if(v == needle) return true; return false; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/stdext/path.d0000664000175000017500000001234312776214756026375 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module stdext.path; import std.path; import std.array; import std.string; import std.conv; string normalizeDir(string dir) { if(dir.length == 0) return ".\\"; dir = replace(dir, "/", "\\"); if(dir[$-1] == '\\') return dir; return dir ~ "\\"; } string normalizePath(string path) { return replace(path, "/", "\\"); } string canonicalPath(string path) { return toLower(replace(path, "/", "\\")); } string makeFilenameAbsolute(string file, string workdir) { if(!isAbsolute(file) && workdir.length) { if(file == ".") file = workdir; else file = normalizeDir(workdir) ~ file; } return file; } void makeFilenamesAbsolute(string[] files, string workdir) { foreach(ref file; files) { if(!isAbsolute(file) && workdir.length) file = makeFilenameAbsolute(file, workdir); } } string removeDotDotPath(string file) { // assumes \\ used as path separator for( ; ; ) { // remove duplicate back slashes auto pos = indexOf(file[1..$], "\\\\"); if(pos < 0) break; file = file[0..pos+1] ~ file[pos + 2 .. $]; } for( ; ; ) { auto pos = indexOf(file, "\\..\\"); if(pos < 0) break; auto lpos = lastIndexOf(file[0..pos], '\\'); if(lpos < 0) break; file = file[0..lpos] ~ file[pos + 3 .. $]; } for( ; ; ) { auto pos = indexOf(file, "\\.\\"); if(pos < 0) break; file = file[0..pos] ~ file[pos + 2 .. $]; } return file; } string makeFilenameCanonical(string file, string workdir) { file = makeFilenameAbsolute(file, workdir); file = normalizePath(file); file = removeDotDotPath(file); return file; } string makeDirnameCanonical(string dir, string workdir) { dir = makeFilenameAbsolute(dir, workdir); dir = normalizeDir(dir); dir = removeDotDotPath(dir); return dir; } void makeFilenamesCanonical(string[] files, string workdir) { foreach(ref file; files) file = makeFilenameCanonical(file, workdir); } void makeDirnamesCanonical(string[] dirs, string workdir) { foreach(ref dir; dirs) dir = makeDirnameCanonical(dir, workdir); } string quoteFilename(string fname) { if(fname.length >= 2 && fname[0] == '\"' && fname[$-1] == '\"') return fname; if(fname.indexOf('$') >= 0 || indexOf(fname, ' ') >= 0) fname = "\"" ~ fname ~ "\""; return fname; } void quoteFilenames(string[] files) { foreach(ref file; files) { file = quoteFilename(file); } } string quoteNormalizeFilename(string fname) { return quoteFilename(normalizePath(fname)); } string getNameWithoutExt(string fname) { string bname = baseName(fname); string name = stripExtension(bname); if(name.length == 0) name = bname; return name; } string safeFilename(string fname, string rep = "-") // - instead of _ to not possibly be part of a module name { string safefile = fname; foreach(char ch; ":\\/") safefile = replace(safefile, to!string(ch), rep); return safefile; } string makeRelative(string file, string path) { if(!isAbsolute(file)) return file; if(!isAbsolute(path)) return file; file = replace(file, "/", "\\"); path = replace(path, "/", "\\"); if(path[$-1] != '\\') path ~= "\\"; string lfile = toLower(file); string lpath = toLower(path); int posfile = 0; for( ; ; ) { auto idxfile = indexOf(lfile, '\\'); auto idxpath = indexOf(lpath, '\\'); assert(idxpath >= 0); if(idxfile < 0 || idxfile != idxpath || lfile[0..idxfile] != lpath[0 .. idxpath]) { if(posfile == 0) return file; // path longer than file path or different subdirs string res; while(idxpath >= 0) { res ~= "..\\"; lpath = lpath[idxpath + 1 .. $]; idxpath = indexOf(lpath, '\\'); } return res ~ file[posfile .. $]; } lfile = lfile[idxfile + 1 .. $]; lpath = lpath[idxpath + 1 .. $]; posfile += idxfile + 1; if(lpath.length == 0) { // file longer than path return file[posfile .. $]; } } } unittest { string file = "c:\\a\\bc\\def\\ghi.d"; string path = "c:\\a\\bc\\x"; string res = makeRelative(file, path); assert(res == "..\\def\\ghi.d"); file = "c:\\a\\bc\\def\\ghi.d"; path = "c:\\a\\bc\\def"; res = makeRelative(file, path); assert(res == "ghi.d"); file = "c:\\a\\bc\\def\\Ghi.d"; path = "c:\\a\\bc\\Def\\ggg\\hhh\\iii"; res = makeRelative(file, path); assert(res == "..\\..\\..\\Ghi.d"); file = "d:\\a\\bc\\Def\\ghi.d"; path = "c:\\a\\bc\\def\\ggg\\hhh\\iii"; res = makeRelative(file, path); assert(res == file); } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/vdparser.extra/stdext/string.d0000664000175000017500000002027112776214756026746 0ustar kaikai// This file is part of Visual D // // Visual D integrates the D programming language into Visual Studio // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved // // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt module stdext.string; import std.utf; import std.string; import std.ascii; import std.conv; import std.array; size_t endofStringCStyle(string text, size_t pos, dchar term = '\"', dchar esc = '\\') { while(pos < text.length) { dchar ch = decode(text, pos); if(ch == esc) { if (pos >= text.length) break; ch = decode(text, pos); } else if(ch == term) return pos; } return pos; } string[] tokenizeArgs(string text, bool semi_is_seperator = true, bool space_is_seperator = true) { string[] args; size_t pos = 0; while(pos < text.length) { size_t startpos = pos; dchar ch = decode(text, pos); if(isWhite(ch)) continue; size_t endpos = pos; while(pos < text.length) { if(ch == '\"') { pos = endofStringCStyle(text, pos, '\"', 0); ch = 0; } else { ch = decode(text, pos); } if(isWhite(ch) && (space_is_seperator || ch != ' ')) break; if(semi_is_seperator && ch == ';') break; endpos = pos; } args ~= text[startpos .. endpos]; } return args; } string unquoteArgument(string arg) { if(arg.length <= 0 || arg[0] != '\"') return arg; if (endofStringCStyle(arg, 1, '\"', 0) != arg.length) return arg; return arg[1..$-1]; } string replaceCrLfSemi(string s) { return replace(replace(s, "\n", ";"), "\r", ""); } string replaceSemiCrLf(string s) { return replace(s, ";", "\r\n"); } string insertCr(string s) { string ns; while(s.length > 0) { auto p = s.indexOf('\n'); if(p < 0) break; if(p > 0 && s[p-1] == '\r') ns ~= s[0 .. p+1]; else ns ~= s[0 .. p] ~ "\r\n"; s = s[p+1 .. $]; } return ns ~ s; } version(unittest) unittest { string t = insertCr("a\nb\r\ncd\n\ne\n\r\nf"); assert(t == "a\r\nb\r\ncd\r\n\r\ne\r\n\r\nf"); } S escapeString(S)(S s) { s = replace(s, "\\"w, "\\\\"w); s = replace(s, "\t"w, "\\t"w); s = replace(s, "\r"w, "\\r"w); s = replace(s, "\n"w, "\\n"w); return s; } int countVisualSpaces(S)(S txt, int tabSize, int* txtpos = null) { int p = 0; int n = 0; while(n < txt.length && isWhite(txt[n])) { if(txt[n] == '\t') p = p + tabSize - (p % tabSize); else p++; n++; } if(txtpos) *txtpos = n; return p; } int visiblePosition(S)(S txt, int tabSize, int idx) { if(idx > txt.length) idx = txt.length; int p = 0; for(int n = 0; n < idx; n++) if(txt[n] == '\t') p = p + tabSize - (p % tabSize); else p++; return p; } S createVisualSpaces(S)(int n, int tabSize, int tabOff = 0) { S s; if(tabSize < 2) { for(int i = 0; i < n; i++) s ~= " "; } else { while (n > 0 && tabOff > 0 && tabOff < tabSize) { s ~= " "; tabOff++; n--; } while(n >= tabSize) { s ~= "\t"; n -= tabSize; } while(n > 0) { s ~= " "; n--; } } return s; } // extract value from a series of #define values string extractDefine(string s, string def) { for(int p = 0; p < s.length; p++) { while(p < s.length && (s[p] == ' ' || s[p] == '\t')) p++; int q = p; while(q < s.length && s[q] != '\n' && s[q] != '\r') q++; if(_startsWith(s[p .. $], "#define") && (s[p+7] == ' ' || s[p+7] == '\t')) { p += 7; while(p < s.length && (s[p] == ' ' || s[p] == '\t')) p++; if(_startsWith(s[p .. $], def) && (s[p+def.length] == ' ' || s[p+def.length] == '\t')) { p += def.length; while(p < s.length && (s[p] == ' ' || s[p] == '\t')) p++; return s[p .. q]; } } p = q; } return ""; } string extractDefines(string s) { string m; for(int p = 0; p < s.length; p++) { while(p < s.length && (s[p] == ' ' || s[p] == '\t')) p++; int q = p; while(q < s.length && s[q] != '\n' && s[q] != '\r') q++; if(_startsWith(s[p .. $], "#define") && (s[p+7] == ' ' || s[p+7] == '\t')) { p += 7; int b = p; while(p < q && (s[p] == ' ' || s[p] == '\t')) p++; int r = p; while(r < q && !isWhite(s[r])) r++; if(r < q) { m ~= "const " ~ s[p..r] ~ " = " ~ s[r..q] ~ ";\n"; } } p = q; } return m; } // endsWith does not work reliable and crashes on page end bool _endsWith(string s, string e) { return (s.length >= e.length && s[$-e.length .. $] == e); } // startsWith causes compile error when used in ctfe bool _startsWith(string s, string w) { return (s.length >= w.length && s[0 .. w.length] == w); } //alias startsWith _startsWith; bool parseLong(ref char[] txt, out long res) { munch(txt, " \t\n\r"); int n = 0; while(n < txt.length && isDigit(txt[n])) n++; if(n <= 0) return false; res = to!long(txt[0..n]); txt = txt[n..$]; return true; } char[] parseNonSpace(ref char[] txt) { munch(txt, " \t\n\r"); int n = 0; while(n < txt.length && !isWhite(txt[n])) n++; char[] res = txt[0..n]; txt = txt[n..$]; return res; } T[] firstLine(T)(T[] s) { for(size_t i = 0; i < s.length; i++) if(s[i] == '\n' || s[i] == '\r') return s[0..i]; return s; } char kInvalidUTF8Replacement = '?'; string toUTF8Safe(const(char)[] text) { char[] modtext; for(size_t p = 0; p < text.length; p++) { ubyte ch = text[p]; if((ch & 0xc0) == 0xc0) { auto q = p; for(int s = 0; s < 5 && ((ch << s) & 0xc0) == 0xc0; s++, q++) if(q >= text.length || (text[q] & 0xc0) != 0x80) goto L_invalid; p = q; } else if(ch & 0x80) { L_invalid: if(modtext.length == 0) modtext = text.dup; modtext[p] = kInvalidUTF8Replacement; } } if(modtext.length) return cast(string) modtext; return cast(string) text; } string toUTF8Safe(const(wchar)[] text) { wchar[] modtext; void invalidChar(size_t pos) { if(modtext.length == 0) modtext = text.dup; modtext[pos] = kInvalidUTF8Replacement; } for(size_t p = 0; p < text.length; p++) { ushort ch = text[p]; if(ch >= 0xD800 && ch <= 0xDFFF) { if(p + 1 >= text.length) invalidChar(p); else { if (text[p+1] < 0xD800 || text[p+1] > 0xDFFF) { invalidChar(p); // invalid surragate pair invalidChar(p+1); } p++; } } } return toUTF8(modtext.length ? modtext : text); } string toUTF8Safe(const(dchar)[] text) { dchar[] modtext; for(size_t p = 0; p < text.length; p++) if(!isValidDchar(text[p])) { if(modtext.length == 0) modtext = text.dup; modtext[p] = kInvalidUTF8Replacement; } return toUTF8(modtext.length ? modtext : text); } dchar decodeBwd(Char)(const(Char) txt, ref size_t pos) { assert(pos > 0); uint len = strideBack(txt, pos); pos -= len; size_t p = pos; dchar ch = decode(txt, p); assert(pos + len == p); return ch; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/gcbench/concpu.d0000664000175000017500000000234712776214756022450 0ustar kaikai/** * The goal of this program is to do very CPU intensive work in threads * * Copyright: Copyright Leandro Lucarella 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Leandro Lucarella */ import core.thread; import core.atomic; import std.conv; import std.file; import std.digest.sha; auto N = 50; auto NT = 4; __gshared ubyte[] BYTES; shared(int) running; // Atomic void main(string[] args) { auto fname = "extra-files/dante.txt"; if (args.length > 3) fname = args[3]; if (args.length > 2) NT = to!(int)(args[2]); if (args.length > 1) N = to!(int)(args[1]); N /= NT; atomicStore(running, NT); BYTES = cast(ubyte[]) std.file.read(fname); auto threads = new Thread[NT]; foreach(ref thread; threads) { thread = new Thread(&doSha); thread.start(); } while (atomicLoad(running)) { auto a = new void[](BYTES.length); a[] = cast(void[]) BYTES[]; Thread.yield(); } foreach(thread; threads) thread.join(); } void doSha() { auto sha = new SHA1; // undefined identifier SHA512? for (size_t i = 0; i < N; i++) { sha.put(BYTES); } running += -1; } ldc-1.1.0-beta3-src/runtime/druntime/benchmark/extra-files/0000775000175000017500000000000012776214756021640 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/benchmark/extra-files/dante.txt0000664000175000017500000207776212776214756023521 0ustar kaikaiLA DIVINA COMMEDIA di Dante Alighieri INFERNO Inferno · Canto I Nel mezzo del cammin di nostra vita mi ritrovai per una selva oscura, ché la diritta via era smarrita. Ahi quanto a dir qual era è cosa dura esta selva selvaggia e aspra e forte che nel pensier rinova la paura! Tant’ è amara che poco è più morte; ma per trattar del ben ch’i’ vi trovai, dirò de l’altre cose ch’i’ v’ho scorte. Io non so ben ridir com’ i’ v’intrai, tant’ era pien di sonno a quel punto che la verace via abbandonai. Ma poi ch’i’ fui al piè d’un colle giunto, là dove terminava quella valle che m’avea di paura il cor compunto, guardai in alto e vidi le sue spalle vestite già de’ raggi del pianeta che mena dritto altrui per ogne calle. Allor fu la paura un poco queta, che nel lago del cor m’era durata la notte ch’i’ passai con tanta pieta. E come quei che con lena affannata, uscito fuor del pelago a la riva, si volge a l’acqua perigliosa e guata, così l’animo mio, ch’ancor fuggiva, si volse a retro a rimirar lo passo che non lasciò già mai persona viva. Poi ch’èi posato un poco il corpo lasso, ripresi via per la piaggia diserta, sì che ’l piè fermo sempre era ’l più basso. Ed ecco, quasi al cominciar de l’erta, una lonza leggera e presta molto, che di pel macolato era coverta; e non mi si partia dinanzi al volto, anzi ’mpediva tanto il mio cammino, ch’i’ fui per ritornar più volte vòlto. Temp’ era dal principio del mattino, e ’l sol montava ’n sù con quelle stelle ch’eran con lui quando l’amor divino mosse di prima quelle cose belle; sì ch’a bene sperar m’era cagione di quella fiera a la gaetta pelle l’ora del tempo e la dolce stagione; ma non sì che paura non mi desse la vista che m’apparve d’un leone. Questi parea che contra me venisse con la test’ alta e con rabbiosa fame, sì che parea che l’aere ne tremesse. Ed una lupa, che di tutte brame sembiava carca ne la sua magrezza, e molte genti fé già viver grame, questa mi porse tanto di gravezza con la paura ch’uscia di sua vista, ch’io perdei la speranza de l’altezza. E qual è quei che volontieri acquista, e giugne ’l tempo che perder lo face, che ’n tutti suoi pensier piange e s’attrista; tal mi fece la bestia sanza pace, che, venendomi ’ncontro, a poco a poco mi ripigneva là dove ’l sol tace. Mentre ch’i’ rovinava in basso loco, dinanzi a li occhi mi si fu offerto chi per lungo silenzio parea fioco. Quando vidi costui nel gran diserto, «Miserere di me», gridai a lui, «qual che tu sii, od ombra od omo certo!». Rispuosemi: «Non omo, omo già fui, e li parenti miei furon lombardi, mantoani per patrïa ambedui. Nacqui sub Iulio, ancor che fosse tardi, e vissi a Roma sotto ’l buono Augusto nel tempo de li dèi falsi e bugiardi. Poeta fui, e cantai di quel giusto figliuol d’Anchise che venne di Troia, poi che ’l superbo Ilïón fu combusto. Ma tu perché ritorni a tanta noia? perché non sali il dilettoso monte ch’è principio e cagion di tutta gioia?». «Or se’ tu quel Virgilio e quella fonte che spandi di parlar sì largo fiume?», rispuos’ io lui con vergognosa fronte. «O de li altri poeti onore e lume, vagliami ’l lungo studio e ’l grande amore che m’ha fatto cercar lo tuo volume. Tu se’ lo mio maestro e ’l mio autore, tu se’ solo colui da cu’ io tolsi lo bello stilo che m’ha fatto onore. Vedi la bestia per cu’ io mi volsi; aiutami da lei, famoso saggio, ch’ella mi fa tremar le vene e i polsi». «A te convien tenere altro vïaggio», rispuose, poi che lagrimar mi vide, «se vuo’ campar d’esto loco selvaggio; ché questa bestia, per la qual tu gride, non lascia altrui passar per la sua via, ma tanto lo ’mpedisce che l’uccide; e ha natura sì malvagia e ria, che mai non empie la bramosa voglia, e dopo ’l pasto ha più fame che pria. Molti son li animali a cui s’ammoglia, e più saranno ancora, infin che ’l veltro verrà, che la farà morir con doglia. Questi non ciberà terra né peltro, ma sapïenza, amore e virtute, e sua nazion sarà tra feltro e feltro. Di quella umile Italia fia salute per cui morì la vergine Cammilla, Eurialo e Turno e Niso di ferute. Questi la caccerà per ogne villa, fin che l’avrà rimessa ne lo ’nferno, là onde ’nvidia prima dipartilla. Ond’ io per lo tuo me’ penso e discerno che tu mi segui, e io sarò tua guida, e trarrotti di qui per loco etterno; ove udirai le disperate strida, vedrai li antichi spiriti dolenti, ch’a la seconda morte ciascun grida; e vederai color che son contenti nel foco, perché speran di venire quando che sia a le beate genti. A le quai poi se tu vorrai salire, anima fia a ciò più di me degna: con lei ti lascerò nel mio partire; ché quello imperador che là sù regna, perch’ i’ fu’ ribellante a la sua legge, non vuol che ’n sua città per me si vegna. In tutte parti impera e quivi regge; quivi è la sua città e l’alto seggio: oh felice colui cu’ ivi elegge!». E io a lui: «Poeta, io ti richeggio per quello Dio che tu non conoscesti, acciò ch’io fugga questo male e peggio, che tu mi meni là dov’ or dicesti, sì ch’io veggia la porta di san Pietro e color cui tu fai cotanto mesti». Allor si mosse, e io li tenni dietro. Inferno · Canto II Lo giorno se n’andava, e l’aere bruno toglieva li animai che sono in terra da le fatiche loro; e io sol uno m’apparecchiava a sostener la guerra sì del cammino e sì de la pietate, che ritrarrà la mente che non erra. O muse, o alto ingegno, or m’aiutate; o mente che scrivesti ciò ch’io vidi, qui si parrà la tua nobilitate. Io cominciai: «Poeta che mi guidi, guarda la mia virtù s’ell’ è possente, prima ch’a l’alto passo tu mi fidi. Tu dici che di Silvïo il parente, corruttibile ancora, ad immortale secolo andò, e fu sensibilmente. Però, se l’avversario d’ogne male cortese i fu, pensando l’alto effetto ch’uscir dovea di lui, e ’l chi e ’l quale non pare indegno ad omo d’intelletto; ch’e’ fu de l’alma Roma e di suo impero ne l’empireo ciel per padre eletto: la quale e ’l quale, a voler dir lo vero, fu stabilita per lo loco santo u’ siede il successor del maggior Piero. Per quest’ andata onde li dai tu vanto, intese cose che furon cagione di sua vittoria e del papale ammanto. Andovvi poi lo Vas d’elezïone, per recarne conforto a quella fede ch’è principio a la via di salvazione. Ma io, perché venirvi? o chi ’l concede? Io non Enëa, io non Paulo sono; me degno a ciò né io né altri ’l crede. Per che, se del venire io m’abbandono, temo che la venuta non sia folle. Se’ savio; intendi me’ ch’i’ non ragiono». E qual è quei che disvuol ciò che volle e per novi pensier cangia proposta, sì che dal cominciar tutto si tolle, tal mi fec’ ïo ’n quella oscura costa, perché, pensando, consumai la ’mpresa che fu nel cominciar cotanto tosta. «S’i’ ho ben la parola tua intesa», rispuose del magnanimo quell’ ombra, «l’anima tua è da viltade offesa; la qual molte fïate l’omo ingombra sì che d’onrata impresa lo rivolve, come falso veder bestia quand’ ombra. Da questa tema acciò che tu ti solve, dirotti perch’ io venni e quel ch’io ’ntesi nel primo punto che di te mi dolve. Io era tra color che son sospesi, e donna mi chiamò beata e bella, tal che di comandare io la richiesi. Lucevan li occhi suoi più che la stella; e cominciommi a dir soave e piana, con angelica voce, in sua favella: “O anima cortese mantoana, di cui la fama ancor nel mondo dura, e durerà quanto ’l mondo lontana, l’amico mio, e non de la ventura, ne la diserta piaggia è impedito sì nel cammin, che vòlt’ è per paura; e temo che non sia già sì smarrito, ch’io mi sia tardi al soccorso levata, per quel ch’i’ ho di lui nel cielo udito. Or movi, e con la tua parola ornata e con ciò c’ha mestieri al suo campare, l’aiuta sì ch’i’ ne sia consolata. I’ son Beatrice che ti faccio andare; vegno del loco ove tornar disio; amor mi mosse, che mi fa parlare. Quando sarò dinanzi al segnor mio, di te mi loderò sovente a lui”. Tacette allora, e poi comincia’ io: “O donna di virtù sola per cui l’umana spezie eccede ogne contento di quel ciel c’ha minor li cerchi sui, tanto m’aggrada il tuo comandamento, che l’ubidir, se già fosse, m’è tardi; più non t’è uo’ ch’aprirmi il tuo talento. Ma dimmi la cagion che non ti guardi de lo scender qua giuso in questo centro de l’ampio loco ove tornar tu ardi”. “Da che tu vuo’ saver cotanto a dentro, dirotti brievemente”, mi rispuose, “perch’ i’ non temo di venir qua entro. Temer si dee di sole quelle cose c’hanno potenza di fare altrui male; de l’altre no, ché non son paurose. I’ son fatta da Dio, sua mercé, tale, che la vostra miseria non mi tange, né fiamma d’esto ’ncendio non m’assale. Donna è gentil nel ciel che si compiange di questo ’mpedimento ov’ io ti mando, sì che duro giudicio là sù frange. Questa chiese Lucia in suo dimando e disse:—Or ha bisogno il tuo fedele di te, e io a te lo raccomando—. Lucia, nimica di ciascun crudele, si mosse, e venne al loco dov’ i’ era, che mi sedea con l’antica Rachele. Disse:—Beatrice, loda di Dio vera, ché non soccorri quei che t’amò tanto, ch’uscì per te de la volgare schiera? Non odi tu la pieta del suo pianto, non vedi tu la morte che ’l combatte su la fiumana ove ’l mar non ha vanto?—. Al mondo non fur mai persone ratte a far lor pro o a fuggir lor danno, com’ io, dopo cotai parole fatte, venni qua giù del mio beato scanno, fidandomi del tuo parlare onesto, ch’onora te e quei ch’udito l’hanno”. Poscia che m’ebbe ragionato questo, li occhi lucenti lagrimando volse, per che mi fece del venir più presto. E venni a te così com’ ella volse: d’inanzi a quella fiera ti levai che del bel monte il corto andar ti tolse. Dunque: che è? perché, perché restai, perché tanta viltà nel core allette, perché ardire e franchezza non hai, poscia che tai tre donne benedette curan di te ne la corte del cielo, e ’l mio parlar tanto ben ti promette?». Quali fioretti dal notturno gelo chinati e chiusi, poi che ’l sol li ’mbianca, si drizzan tutti aperti in loro stelo, tal mi fec’ io di mia virtude stanca, e tanto buono ardire al cor mi corse, ch’i’ cominciai come persona franca: «Oh pietosa colei che mi soccorse! e te cortese ch’ubidisti tosto a le vere parole che ti porse! Tu m’hai con disiderio il cor disposto sì al venir con le parole tue, ch’i’ son tornato nel primo proposto. Or va, ch’un sol volere è d’ambedue: tu duca, tu segnore e tu maestro». Così li dissi; e poi che mosso fue, intrai per lo cammino alto e silvestro. Inferno · Canto III ‘Per me si va ne la città dolente, per me si va ne l’etterno dolore, per me si va tra la perduta gente. Giustizia mosse il mio alto fattore; fecemi la divina podestate, la somma sapïenza e ’l primo amore. Dinanzi a me non fuor cose create se non etterne, e io etterno duro. Lasciate ogne speranza, voi ch’intrate’. Queste parole di colore oscuro vid’ ïo scritte al sommo d’una porta; per ch’io: «Maestro, il senso lor m’è duro». Ed elli a me, come persona accorta: «Qui si convien lasciare ogne sospetto; ogne viltà convien che qui sia morta. Noi siam venuti al loco ov’ i’ t’ho detto che tu vedrai le genti dolorose c’hanno perduto il ben de l’intelletto». E poi che la sua mano a la mia puose con lieto volto, ond’ io mi confortai, mi mise dentro a le segrete cose. Quivi sospiri, pianti e alti guai risonavan per l’aere sanza stelle, per ch’io al cominciar ne lagrimai. Diverse lingue, orribili favelle, parole di dolore, accenti d’ira, voci alte e fioche, e suon di man con elle facevano un tumulto, il qual s’aggira sempre in quell’ aura sanza tempo tinta, come la rena quando turbo spira. E io ch’avea d’error la testa cinta, dissi: «Maestro, che è quel ch’i’ odo? e che gent’ è che par nel duol sì vinta?». Ed elli a me: «Questo misero modo tegnon l’anime triste di coloro che visser sanza ’nfamia e sanza lodo. Mischiate sono a quel cattivo coro de li angeli che non furon ribelli né fur fedeli a Dio, ma per sé fuoro. Caccianli i ciel per non esser men belli, né lo profondo inferno li riceve, ch’alcuna gloria i rei avrebber d’elli». E io: «Maestro, che è tanto greve a lor che lamentar li fa sì forte?». Rispuose: «Dicerolti molto breve. Questi non hanno speranza di morte, e la lor cieca vita è tanto bassa, che ’nvidïosi son d’ogne altra sorte. Fama di loro il mondo esser non lassa; misericordia e giustizia li sdegna: non ragioniam di lor, ma guarda e passa». E io, che riguardai, vidi una ’nsegna che girando correva tanto ratta, che d’ogne posa mi parea indegna; e dietro le venìa sì lunga tratta di gente, ch’i’ non averei creduto che morte tanta n’avesse disfatta. Poscia ch’io v’ebbi alcun riconosciuto, vidi e conobbi l’ombra di colui che fece per viltade il gran rifiuto. Incontanente intesi e certo fui che questa era la setta d’i cattivi, a Dio spiacenti e a’ nemici sui. Questi sciaurati, che mai non fur vivi, erano ignudi e stimolati molto da mosconi e da vespe ch’eran ivi. Elle rigavan lor di sangue il volto, che, mischiato di lagrime, a’ lor piedi da fastidiosi vermi era ricolto. E poi ch’a riguardar oltre mi diedi, vidi genti a la riva d’un gran fiume; per ch’io dissi: «Maestro, or mi concedi ch’i’ sappia quali sono, e qual costume le fa di trapassar parer sì pronte, com’ i’ discerno per lo fioco lume». Ed elli a me: «Le cose ti fier conte quando noi fermerem li nostri passi su la trista riviera d’Acheronte». Allor con li occhi vergognosi e bassi, temendo no ’l mio dir li fosse grave, infino al fiume del parlar mi trassi. Ed ecco verso noi venir per nave un vecchio, bianco per antico pelo, gridando: «Guai a voi, anime prave! Non isperate mai veder lo cielo: i’ vegno per menarvi a l’altra riva ne le tenebre etterne, in caldo e ’n gelo. E tu che se’ costì, anima viva, pàrtiti da cotesti che son morti». Ma poi che vide ch’io non mi partiva, disse: «Per altra via, per altri porti verrai a piaggia, non qui, per passare: più lieve legno convien che ti porti». E ’l duca lui: «Caron, non ti crucciare: vuolsi così colà dove si puote ciò che si vuole, e più non dimandare». Quinci fuor quete le lanose gote al nocchier de la livida palude, che ’ntorno a li occhi avea di fiamme rote. Ma quell’ anime, ch’eran lasse e nude, cangiar colore e dibattero i denti, ratto che ’nteser le parole crude. Bestemmiavano Dio e lor parenti, l’umana spezie e ’l loco e ’l tempo e ’l seme di lor semenza e di lor nascimenti. Poi si ritrasser tutte quante insieme, forte piangendo, a la riva malvagia ch’attende ciascun uom che Dio non teme. Caron dimonio, con occhi di bragia loro accennando, tutte le raccoglie; batte col remo qualunque s’adagia. Come d’autunno si levan le foglie l’una appresso de l’altra, fin che ’l ramo vede a la terra tutte le sue spoglie, similemente il mal seme d’Adamo gittansi di quel lito ad una ad una, per cenni come augel per suo richiamo. Così sen vanno su per l’onda bruna, e avanti che sien di là discese, anche di qua nuova schiera s’auna. «Figliuol mio», disse ’l maestro cortese, «quelli che muoion ne l’ira di Dio tutti convegnon qui d’ogne paese; e pronti sono a trapassar lo rio, ché la divina giustizia li sprona, sì che la tema si volve in disio. Quinci non passa mai anima buona; e però, se Caron di te si lagna, ben puoi sapere omai che ’l suo dir suona». Finito questo, la buia campagna tremò sì forte, che de lo spavento la mente di sudore ancor mi bagna. La terra lagrimosa diede vento, che balenò una luce vermiglia la qual mi vinse ciascun sentimento; e caddi come l’uom cui sonno piglia. Inferno · Canto IV Ruppemi l’alto sonno ne la testa un greve truono, sì ch’io mi riscossi come persona ch’è per forza desta; e l’occhio riposato intorno mossi, dritto levato, e fiso riguardai per conoscer lo loco dov’ io fossi. Vero è che ’n su la proda mi trovai de la valle d’abisso dolorosa che ’ntrono accoglie d’infiniti guai. Oscura e profonda era e nebulosa tanto che, per ficcar lo viso a fondo, io non vi discernea alcuna cosa. «Or discendiam qua giù nel cieco mondo», cominciò il poeta tutto smorto. «Io sarò primo, e tu sarai secondo». E io, che del color mi fui accorto, dissi: «Come verrò, se tu paventi che suoli al mio dubbiare esser conforto?». Ed elli a me: «L’angoscia de le genti che son qua giù, nel viso mi dipigne quella pietà che tu per tema senti. Andiam, ché la via lunga ne sospigne». Così si mise e così mi fé intrare nel primo cerchio che l’abisso cigne. Quivi, secondo che per ascoltare, non avea pianto mai che di sospiri che l’aura etterna facevan tremare; ciò avvenia di duol sanza martìri, ch’avean le turbe, ch’eran molte e grandi, d’infanti e di femmine e di viri. Lo buon maestro a me: «Tu non dimandi che spiriti son questi che tu vedi? Or vo’ che sappi, innanzi che più andi, ch’ei non peccaro; e s’elli hanno mercedi, non basta, perché non ebber battesmo, ch’è porta de la fede che tu credi; e s’e’ furon dinanzi al cristianesmo, non adorar debitamente a Dio: e di questi cotai son io medesmo. Per tai difetti, non per altro rio, semo perduti, e sol di tanto offesi che sanza speme vivemo in disio». Gran duol mi prese al cor quando lo ’ntesi, però che gente di molto valore conobbi che ’n quel limbo eran sospesi. «Dimmi, maestro mio, dimmi, segnore», comincia’ io per voler esser certo di quella fede che vince ogne errore: «uscicci mai alcuno, o per suo merto o per altrui, che poi fosse beato?». E quei che ’ntese il mio parlar coverto, rispuose: «Io era nuovo in questo stato, quando ci vidi venire un possente, con segno di vittoria coronato. Trasseci l’ombra del primo parente, d’Abèl suo figlio e quella di Noè, di Moïsè legista e ubidente; Abraàm patrïarca e Davìd re, Israèl con lo padre e co’ suoi nati e con Rachele, per cui tanto fé, e altri molti, e feceli beati. E vo’ che sappi che, dinanzi ad essi, spiriti umani non eran salvati». Non lasciavam l’andar perch’ ei dicessi, ma passavam la selva tuttavia, la selva, dico, di spiriti spessi. Non era lunga ancor la nostra via di qua dal sonno, quand’ io vidi un foco ch’emisperio di tenebre vincia. Di lungi n’eravamo ancora un poco, ma non sì ch’io non discernessi in parte ch’orrevol gente possedea quel loco. «O tu ch’onori scïenzïa e arte, questi chi son c’hanno cotanta onranza, che dal modo de li altri li diparte?». E quelli a me: «L’onrata nominanza che di lor suona sù ne la tua vita, grazïa acquista in ciel che sì li avanza». Intanto voce fu per me udita: «Onorate l’altissimo poeta; l’ombra sua torna, ch’era dipartita». Poi che la voce fu restata e queta, vidi quattro grand’ ombre a noi venire: sembianz’ avevan né trista né lieta. Lo buon maestro cominciò a dire: «Mira colui con quella spada in mano, che vien dinanzi ai tre sì come sire: quelli è Omero poeta sovrano; l’altro è Orazio satiro che vene; Ovidio è ’l terzo, e l’ultimo Lucano. Però che ciascun meco si convene nel nome che sonò la voce sola, fannomi onore, e di ciò fanno bene». Così vid’ i’ adunar la bella scola di quel segnor de l’altissimo canto che sovra li altri com’ aquila vola. Da ch’ebber ragionato insieme alquanto, volsersi a me con salutevol cenno, e ’l mio maestro sorrise di tanto; e più d’onore ancora assai mi fenno, ch’e’ sì mi fecer de la loro schiera, sì ch’io fui sesto tra cotanto senno. Così andammo infino a la lumera, parlando cose che ’l tacere è bello, sì com’ era ’l parlar colà dov’ era. Venimmo al piè d’un nobile castello, sette volte cerchiato d’alte mura, difeso intorno d’un bel fiumicello. Questo passammo come terra dura; per sette porte intrai con questi savi: giugnemmo in prato di fresca verdura. Genti v’eran con occhi tardi e gravi, di grande autorità ne’ lor sembianti: parlavan rado, con voci soavi. Traemmoci così da l’un de’ canti, in loco aperto, luminoso e alto, sì che veder si potien tutti quanti. Colà diritto, sovra ’l verde smalto, mi fuor mostrati li spiriti magni, che del vedere in me stesso m’essalto. I’ vidi Eletra con molti compagni, tra ’ quai conobbi Ettòr ed Enea, Cesare armato con li occhi grifagni. Vidi Cammilla e la Pantasilea; da l’altra parte vidi ’l re Latino che con Lavina sua figlia sedea. Vidi quel Bruto che cacciò Tarquino, Lucrezia, Iulia, Marzïa e Corniglia; e solo, in parte, vidi ’l Saladino. Poi ch’innalzai un poco più le ciglia, vidi ’l maestro di color che sanno seder tra filosofica famiglia. Tutti lo miran, tutti onor li fanno: quivi vid’ ïo Socrate e Platone, che ’nnanzi a li altri più presso li stanno; Democrito che ’l mondo a caso pone, Dïogenès, Anassagora e Tale, Empedoclès, Eraclito e Zenone; e vidi il buono accoglitor del quale, Dïascoride dico; e vidi Orfeo, Tulïo e Lino e Seneca morale; Euclide geomètra e Tolomeo, Ipocràte, Avicenna e Galïeno, Averoìs, che ’l gran comento feo. Io non posso ritrar di tutti a pieno, però che sì mi caccia il lungo tema, che molte volte al fatto il dir vien meno. La sesta compagnia in due si scema: per altra via mi mena il savio duca, fuor de la queta, ne l’aura che trema. E vegno in parte ove non è che luca. Inferno · Canto V Così discesi del cerchio primaio giù nel secondo, che men loco cinghia e tanto più dolor, che punge a guaio. Stavvi Minòs orribilmente, e ringhia: essamina le colpe ne l’intrata; giudica e manda secondo ch’avvinghia. Dico che quando l’anima mal nata li vien dinanzi, tutta si confessa; e quel conoscitor de le peccata vede qual loco d’inferno è da essa; cignesi con la coda tante volte quantunque gradi vuol che giù sia messa. Sempre dinanzi a lui ne stanno molte: vanno a vicenda ciascuna al giudizio, dicono e odono e poi son giù volte. «O tu che vieni al doloroso ospizio», disse Minòs a me quando mi vide, lasciando l’atto di cotanto offizio, «guarda com’ entri e di cui tu ti fide; non t’inganni l’ampiezza de l’intrare!». E ’l duca mio a lui: «Perché pur gride? Non impedir lo suo fatale andare: vuolsi così colà dove si puote ciò che si vuole, e più non dimandare». Or incomincian le dolenti note a farmisi sentire; or son venuto là dove molto pianto mi percuote. Io venni in loco d’ogne luce muto, che mugghia come fa mar per tempesta, se da contrari venti è combattuto. La bufera infernal, che mai non resta, mena li spirti con la sua rapina; voltando e percotendo li molesta. Quando giungon davanti a la ruina, quivi le strida, il compianto, il lamento; bestemmian quivi la virtù divina. Intesi ch’a così fatto tormento enno dannati i peccator carnali, che la ragion sommettono al talento. E come li stornei ne portan l’ali nel freddo tempo, a schiera larga e piena, così quel fiato li spiriti mali di qua, di là, di giù, di sù li mena; nulla speranza li conforta mai, non che di posa, ma di minor pena. E come i gru van cantando lor lai, faccendo in aere di sé lunga riga, così vid’ io venir, traendo guai, ombre portate da la detta briga; per ch’i’ dissi: «Maestro, chi son quelle genti che l’aura nera sì gastiga?». «La prima di color di cui novelle tu vuo’ saper», mi disse quelli allotta, «fu imperadrice di molte favelle. A vizio di lussuria fu sì rotta, che libito fé licito in sua legge, per tòrre il biasmo in che era condotta. Ell’ è Semiramìs, di cui si legge che succedette a Nino e fu sua sposa: tenne la terra che ’l Soldan corregge. L’altra è colei che s’ancise amorosa, e ruppe fede al cener di Sicheo; poi è Cleopatràs lussurïosa. Elena vedi, per cui tanto reo tempo si volse, e vedi ’l grande Achille, che con amore al fine combatteo. Vedi Parìs, Tristano»; e più di mille ombre mostrommi e nominommi a dito, ch’amor di nostra vita dipartille. Poscia ch’io ebbi ’l mio dottore udito nomar le donne antiche e ’ cavalieri, pietà mi giunse, e fui quasi smarrito. I’ cominciai: «Poeta, volontieri parlerei a quei due che ’nsieme vanno, e paion sì al vento esser leggeri». Ed elli a me: «Vedrai quando saranno più presso a noi; e tu allor li priega per quello amor che i mena, ed ei verranno». Sì tosto come il vento a noi li piega, mossi la voce: «O anime affannate, venite a noi parlar, s’altri nol niega!». Quali colombe dal disio chiamate con l’ali alzate e ferme al dolce nido vegnon per l’aere, dal voler portate; cotali uscir de la schiera ov’ è Dido, a noi venendo per l’aere maligno, sì forte fu l’affettüoso grido. «O animal grazïoso e benigno che visitando vai per l’aere perso noi che tignemmo il mondo di sanguigno, se fosse amico il re de l’universo, noi pregheremmo lui de la tua pace, poi c’hai pietà del nostro mal perverso. Di quel che udire e che parlar vi piace, noi udiremo e parleremo a voi, mentre che ’l vento, come fa, ci tace. Siede la terra dove nata fui su la marina dove ’l Po discende per aver pace co’ seguaci sui. Amor, ch’al cor gentil ratto s’apprende, prese costui de la bella persona che mi fu tolta; e ’l modo ancor m’offende. Amor, ch’a nullo amato amar perdona, mi prese del costui piacer sì forte, che, come vedi, ancor non m’abbandona. Amor condusse noi ad una morte. Caina attende chi a vita ci spense». Queste parole da lor ci fuor porte. Quand’ io intesi quell’ anime offense, china’ il viso, e tanto il tenni basso, fin che ’l poeta mi disse: «Che pense?». Quando rispuosi, cominciai: «Oh lasso, quanti dolci pensier, quanto disio menò costoro al doloroso passo!». Poi mi rivolsi a loro e parla’ io, e cominciai: «Francesca, i tuoi martìri a lagrimar mi fanno tristo e pio. Ma dimmi: al tempo d’i dolci sospiri, a che e come concedette amore che conosceste i dubbiosi disiri?». E quella a me: «Nessun maggior dolore che ricordarsi del tempo felice ne la miseria; e ciò sa ’l tuo dottore. Ma s’a conoscer la prima radice del nostro amor tu hai cotanto affetto, dirò come colui che piange e dice. Noi leggiavamo un giorno per diletto di Lancialotto come amor lo strinse; soli eravamo e sanza alcun sospetto. Per più fïate li occhi ci sospinse quella lettura, e scolorocci il viso; ma solo un punto fu quel che ci vinse. Quando leggemmo il disïato riso esser basciato da cotanto amante, questi, che mai da me non fia diviso, la bocca mi basciò tutto tremante. Galeotto fu ’l libro e chi lo scrisse: quel giorno più non vi leggemmo avante». Mentre che l’uno spirto questo disse, l’altro piangëa; sì che di pietade io venni men così com’ io morisse. E caddi come corpo morto cade. Inferno · Canto VI Al tornar de la mente, che si chiuse dinanzi a la pietà d’i due cognati, che di trestizia tutto mi confuse, novi tormenti e novi tormentati mi veggio intorno, come ch’io mi mova e ch’io mi volga, e come che io guati. Io sono al terzo cerchio, de la piova etterna, maladetta, fredda e greve; regola e qualità mai non l’è nova. Grandine grossa, acqua tinta e neve per l’aere tenebroso si riversa; pute la terra che questo riceve. Cerbero, fiera crudele e diversa, con tre gole caninamente latra sovra la gente che quivi è sommersa. Li occhi ha vermigli, la barba unta e atra, e ’l ventre largo, e unghiate le mani; graffia li spirti ed iscoia ed isquatra. Urlar li fa la pioggia come cani; de l’un de’ lati fanno a l’altro schermo; volgonsi spesso i miseri profani. Quando ci scorse Cerbero, il gran vermo, le bocche aperse e mostrocci le sanne; non avea membro che tenesse fermo. E ’l duca mio distese le sue spanne, prese la terra, e con piene le pugna la gittò dentro a le bramose canne. Qual è quel cane ch’abbaiando agogna, e si racqueta poi che ’l pasto morde, ché solo a divorarlo intende e pugna, cotai si fecer quelle facce lorde de lo demonio Cerbero, che ’ntrona l’anime sì, ch’esser vorrebber sorde. Noi passavam su per l’ombre che adona la greve pioggia, e ponavam le piante sovra lor vanità che par persona. Elle giacean per terra tutte quante, fuor d’una ch’a seder si levò, ratto ch’ella ci vide passarsi davante. «O tu che se’ per questo ’nferno tratto», mi disse, «riconoscimi, se sai: tu fosti, prima ch’io disfatto, fatto». E io a lui: «L’angoscia che tu hai forse ti tira fuor de la mia mente, sì che non par ch’i’ ti vedessi mai. Ma dimmi chi tu se’ che ’n sì dolente loco se’ messo, e hai sì fatta pena, che, s’altra è maggio, nulla è sì spiacente». Ed elli a me: «La tua città, ch’è piena d’invidia sì che già trabocca il sacco, seco mi tenne in la vita serena. Voi cittadini mi chiamaste Ciacco: per la dannosa colpa de la gola, come tu vedi, a la pioggia mi fiacco. E io anima trista non son sola, ché tutte queste a simil pena stanno per simil colpa». E più non fé parola. Io li rispuosi: «Ciacco, il tuo affanno mi pesa sì, ch’a lagrimar mi ’nvita; ma dimmi, se tu sai, a che verranno li cittadin de la città partita; s’alcun v’è giusto; e dimmi la cagione per che l’ha tanta discordia assalita». E quelli a me: «Dopo lunga tencione verranno al sangue, e la parte selvaggia caccerà l’altra con molta offensione. Poi appresso convien che questa caggia infra tre soli, e che l’altra sormonti con la forza di tal che testé piaggia. Alte terrà lungo tempo le fronti, tenendo l’altra sotto gravi pesi, come che di ciò pianga o che n’aonti. Giusti son due, e non vi sono intesi; superbia, invidia e avarizia sono le tre faville c’hanno i cuori accesi». Qui puose fine al lagrimabil suono. E io a lui: «Ancor vo’ che mi ’nsegni e che di più parlar mi facci dono. Farinata e ’l Tegghiaio, che fuor sì degni, Iacopo Rusticucci, Arrigo e ’l Mosca e li altri ch’a ben far puoser li ’ngegni, dimmi ove sono e fa ch’io li conosca; ché gran disio mi stringe di savere se ’l ciel li addolcia o lo ’nferno li attosca». E quelli: «Ei son tra l’anime più nere; diverse colpe giù li grava al fondo: se tanto scendi, là i potrai vedere. Ma quando tu sarai nel dolce mondo, priegoti ch’a la mente altrui mi rechi: più non ti dico e più non ti rispondo». Li diritti occhi torse allora in biechi; guardommi un poco e poi chinò la testa: cadde con essa a par de li altri ciechi. E ’l duca disse a me: «Più non si desta di qua dal suon de l’angelica tromba, quando verrà la nimica podesta: ciascun rivederà la trista tomba, ripiglierà sua carne e sua figura, udirà quel ch’in etterno rimbomba». Sì trapassammo per sozza mistura de l’ombre e de la pioggia, a passi lenti, toccando un poco la vita futura; per ch’io dissi: «Maestro, esti tormenti crescerann’ ei dopo la gran sentenza, o fier minori, o saran sì cocenti?». Ed elli a me: «Ritorna a tua scïenza, che vuol, quanto la cosa è più perfetta, più senta il bene, e così la doglienza. Tutto che questa gente maladetta in vera perfezion già mai non vada, di là più che di qua essere aspetta». Noi aggirammo a tondo quella strada, parlando più assai ch’i’ non ridico; venimmo al punto dove si digrada: quivi trovammo Pluto, il gran nemico. Inferno · Canto VII «Pape Satàn, pape Satàn aleppe!», cominciò Pluto con la voce chioccia; e quel savio gentil, che tutto seppe, disse per confortarmi: «Non ti noccia la tua paura; ché, poder ch’elli abbia, non ci torrà lo scender questa roccia». Poi si rivolse a quella ’nfiata labbia, e disse: «Taci, maladetto lupo! consuma dentro te con la tua rabbia. Non è sanza cagion l’andare al cupo: vuolsi ne l’alto, là dove Michele fé la vendetta del superbo strupo». Quali dal vento le gonfiate vele caggiono avvolte, poi che l’alber fiacca, tal cadde a terra la fiera crudele. Così scendemmo ne la quarta lacca, pigliando più de la dolente ripa che ’l mal de l’universo tutto insacca. Ahi giustizia di Dio! tante chi stipa nove travaglie e pene quant’ io viddi? e perché nostra colpa sì ne scipa? Come fa l’onda là sovra Cariddi, che si frange con quella in cui s’intoppa, così convien che qui la gente riddi. Qui vid’ i’ gente più ch’altrove troppa, e d’una parte e d’altra, con grand’ urli, voltando pesi per forza di poppa. Percotëansi ’ncontro; e poscia pur lì si rivolgea ciascun, voltando a retro, gridando: «Perché tieni?» e «Perché burli?». Così tornavan per lo cerchio tetro da ogne mano a l’opposito punto, gridandosi anche loro ontoso metro; poi si volgea ciascun, quand’ era giunto, per lo suo mezzo cerchio a l’altra giostra. E io, ch’avea lo cor quasi compunto, dissi: «Maestro mio, or mi dimostra che gente è questa, e se tutti fuor cherci questi chercuti a la sinistra nostra». Ed elli a me: «Tutti quanti fuor guerci sì de la mente in la vita primaia, che con misura nullo spendio ferci. Assai la voce lor chiaro l’abbaia, quando vegnono a’ due punti del cerchio dove colpa contraria li dispaia. Questi fuor cherci, che non han coperchio piloso al capo, e papi e cardinali, in cui usa avarizia il suo soperchio». E io: «Maestro, tra questi cotali dovre’ io ben riconoscere alcuni che furo immondi di cotesti mali». Ed elli a me: «Vano pensiero aduni: la sconoscente vita che i fé sozzi, ad ogne conoscenza or li fa bruni. In etterno verranno a li due cozzi: questi resurgeranno del sepulcro col pugno chiuso, e questi coi crin mozzi. Mal dare e mal tener lo mondo pulcro ha tolto loro, e posti a questa zuffa: qual ella sia, parole non ci appulcro. Or puoi, figliuol, veder la corta buffa d’i ben che son commessi a la fortuna, per che l’umana gente si rabbuffa; ché tutto l’oro ch’è sotto la luna e che già fu, di quest’ anime stanche non poterebbe farne posare una». «Maestro mio», diss’ io, «or mi dì anche: questa fortuna di che tu mi tocche, che è, che i ben del mondo ha sì tra branche?». E quelli a me: «Oh creature sciocche, quanta ignoranza è quella che v’offende! Or vo’ che tu mia sentenza ne ’mbocche. Colui lo cui saver tutto trascende, fece li cieli e diè lor chi conduce sì, ch’ogne parte ad ogne parte splende, distribuendo igualmente la luce. Similemente a li splendor mondani ordinò general ministra e duce che permutasse a tempo li ben vani di gente in gente e d’uno in altro sangue, oltre la difension d’i senni umani; per ch’una gente impera e l’altra langue, seguendo lo giudicio di costei, che è occulto come in erba l’angue. Vostro saver non ha contasto a lei: questa provede, giudica, e persegue suo regno come il loro li altri dèi. Le sue permutazion non hanno triegue: necessità la fa esser veloce; sì spesso vien chi vicenda consegue. Quest’ è colei ch’è tanto posta in croce pur da color che le dovrien dar lode, dandole biasmo a torto e mala voce; ma ella s’è beata e ciò non ode: con l’altre prime creature lieta volve sua spera e beata si gode. Or discendiamo omai a maggior pieta; già ogne stella cade che saliva quand’ io mi mossi, e ’l troppo star si vieta». Noi ricidemmo il cerchio a l’altra riva sovr’ una fonte che bolle e riversa per un fossato che da lei deriva. L’acqua era buia assai più che persa; e noi, in compagnia de l’onde bige, intrammo giù per una via diversa. In la palude va c’ha nome Stige questo tristo ruscel, quand’ è disceso al piè de le maligne piagge grige. E io, che di mirare stava inteso, vidi genti fangose in quel pantano, ignude tutte, con sembiante offeso. Queste si percotean non pur con mano, ma con la testa e col petto e coi piedi, troncandosi co’ denti a brano a brano. Lo buon maestro disse: «Figlio, or vedi l’anime di color cui vinse l’ira; e anche vo’ che tu per certo credi che sotto l’acqua è gente che sospira, e fanno pullular quest’ acqua al summo, come l’occhio ti dice, u’ che s’aggira. Fitti nel limo dicon: “Tristi fummo ne l’aere dolce che dal sol s’allegra, portando dentro accidïoso fummo: or ci attristiam ne la belletta negra”. Quest’ inno si gorgoglian ne la strozza, ché dir nol posson con parola integra». Così girammo de la lorda pozza grand’ arco tra la ripa secca e ’l mézzo, con li occhi vòlti a chi del fango ingozza. Venimmo al piè d’una torre al da sezzo. Inferno · Canto VIII Io dico, seguitando, ch’assai prima che noi fossimo al piè de l’alta torre, li occhi nostri n’andar suso a la cima per due fiammette che i vedemmo porre, e un’altra da lungi render cenno, tanto ch’a pena il potea l’occhio tòrre. E io mi volsi al mar di tutto ’l senno; dissi: «Questo che dice? e che risponde quell’ altro foco? e chi son quei che ’l fenno?». Ed elli a me: «Su per le sucide onde già scorgere puoi quello che s’aspetta, se ’l fummo del pantan nol ti nasconde». Corda non pinse mai da sé saetta che sì corresse via per l’aere snella, com’ io vidi una nave piccioletta venir per l’acqua verso noi in quella, sotto ’l governo d’un sol galeoto, che gridava: «Or se’ giunta, anima fella!». «Flegïàs, Flegïàs, tu gridi a vòto», disse lo mio segnore, «a questa volta: più non ci avrai che sol passando il loto». Qual è colui che grande inganno ascolta che li sia fatto, e poi se ne rammarca, fecesi Flegïàs ne l’ira accolta. Lo duca mio discese ne la barca, e poi mi fece intrare appresso lui; e sol quand’ io fui dentro parve carca. Tosto che ’l duca e io nel legno fui, segando se ne va l’antica prora de l’acqua più che non suol con altrui. Mentre noi corravam la morta gora, dinanzi mi si fece un pien di fango, e disse: «Chi se’ tu che vieni anzi ora?». E io a lui: «S’i’ vegno, non rimango; ma tu chi se’, che sì se’ fatto brutto?». Rispuose: «Vedi che son un che piango». E io a lui: «Con piangere e con lutto, spirito maladetto, ti rimani; ch’i’ ti conosco, ancor sie lordo tutto». Allor distese al legno ambo le mani; per che ’l maestro accorto lo sospinse, dicendo: «Via costà con li altri cani!». Lo collo poi con le braccia mi cinse; basciommi ’l volto e disse: «Alma sdegnosa, benedetta colei che ’n te s’incinse! Quei fu al mondo persona orgogliosa; bontà non è che sua memoria fregi: così s’è l’ombra sua qui furïosa. Quanti si tegnon or là sù gran regi che qui staranno come porci in brago, di sé lasciando orribili dispregi!». E io: «Maestro, molto sarei vago di vederlo attuffare in questa broda prima che noi uscissimo del lago». Ed elli a me: «Avante che la proda ti si lasci veder, tu sarai sazio: di tal disïo convien che tu goda». Dopo ciò poco vid’ io quello strazio far di costui a le fangose genti, che Dio ancor ne lodo e ne ringrazio. Tutti gridavano: «A Filippo Argenti!»; e ’l fiorentino spirito bizzarro in sé medesmo si volvea co’ denti. Quivi il lasciammo, che più non ne narro; ma ne l’orecchie mi percosse un duolo, per ch’io avante l’occhio intento sbarro. Lo buon maestro disse: «Omai, figliuolo, s’appressa la città c’ha nome Dite, coi gravi cittadin, col grande stuolo». E io: «Maestro, già le sue meschite là entro certe ne la valle cerno, vermiglie come se di foco uscite fossero». Ed ei mi disse: «Il foco etterno ch’entro l’affoca le dimostra rosse, come tu vedi in questo basso inferno». Noi pur giugnemmo dentro a l’alte fosse che vallan quella terra sconsolata: le mura mi parean che ferro fosse. Non sanza prima far grande aggirata, venimmo in parte dove il nocchier forte «Usciteci», gridò: «qui è l’intrata». Io vidi più di mille in su le porte da ciel piovuti, che stizzosamente dicean: «Chi è costui che sanza morte va per lo regno de la morta gente?». E ’l savio mio maestro fece segno di voler lor parlar segretamente. Allor chiusero un poco il gran disdegno e disser: «Vien tu solo, e quei sen vada che sì ardito intrò per questo regno. Sol si ritorni per la folle strada: pruovi, se sa; ché tu qui rimarrai, che li ha’ iscorta sì buia contrada». Pensa, lettor, se io mi sconfortai nel suon de le parole maladette, ché non credetti ritornarci mai. «O caro duca mio, che più di sette volte m’hai sicurtà renduta e tratto d’alto periglio che ’ncontra mi stette, non mi lasciar», diss’ io, «così disfatto; e se ’l passar più oltre ci è negato, ritroviam l’orme nostre insieme ratto». E quel segnor che lì m’avea menato, mi disse: «Non temer; ché ’l nostro passo non ci può tòrre alcun: da tal n’è dato. Ma qui m’attendi, e lo spirito lasso conforta e ciba di speranza buona, ch’i’ non ti lascerò nel mondo basso». Così sen va, e quivi m’abbandona lo dolce padre, e io rimagno in forse, che sì e no nel capo mi tenciona. Udir non potti quello ch’a lor porse; ma ei non stette là con essi guari, che ciascun dentro a pruova si ricorse. Chiuser le porte que’ nostri avversari nel petto al mio segnor, che fuor rimase e rivolsesi a me con passi rari. Li occhi a la terra e le ciglia avea rase d’ogne baldanza, e dicea ne’ sospiri: «Chi m’ha negate le dolenti case!». E a me disse: «Tu, perch’ io m’adiri, non sbigottir, ch’io vincerò la prova, qual ch’a la difension dentro s’aggiri. Questa lor tracotanza non è nova; ché già l’usaro a men segreta porta, la qual sanza serrame ancor si trova. Sovr’ essa vedestù la scritta morta: e già di qua da lei discende l’erta, passando per li cerchi sanza scorta, tal che per lui ne fia la terra aperta». Inferno · Canto IX Quel color che viltà di fuor mi pinse veggendo il duca mio tornare in volta, più tosto dentro il suo novo ristrinse. Attento si fermò com’ uom ch’ascolta; ché l’occhio nol potea menare a lunga per l’aere nero e per la nebbia folta. «Pur a noi converrà vincer la punga», cominciò el, «se non . . . Tal ne s’offerse. Oh quanto tarda a me ch’altri qui giunga!». I’ vidi ben sì com’ ei ricoperse lo cominciar con l’altro che poi venne, che fur parole a le prime diverse; ma nondimen paura il suo dir dienne, perch’ io traeva la parola tronca forse a peggior sentenzia che non tenne. «In questo fondo de la trista conca discende mai alcun del primo grado, che sol per pena ha la speranza cionca?». Questa question fec’ io; e quei «Di rado incontra», mi rispuose, «che di noi faccia il cammino alcun per qual io vado. Ver è ch’altra fïata qua giù fui, congiurato da quella Eritón cruda che richiamava l’ombre a’ corpi sui. Di poco era di me la carne nuda, ch’ella mi fece intrar dentr’ a quel muro, per trarne un spirto del cerchio di Giuda. Quell’ è ’l più basso loco e ’l più oscuro, e ’l più lontan dal ciel che tutto gira: ben so ’l cammin; però ti fa sicuro. Questa palude che ’l gran puzzo spira cigne dintorno la città dolente, u’ non potemo intrare omai sanz’ ira». E altro disse, ma non l’ho a mente; però che l’occhio m’avea tutto tratto ver’ l’alta torre a la cima rovente, dove in un punto furon dritte ratto tre furïe infernal di sangue tinte, che membra feminine avieno e atto, e con idre verdissime eran cinte; serpentelli e ceraste avien per crine, onde le fiere tempie erano avvinte. E quei, che ben conobbe le meschine de la regina de l’etterno pianto, «Guarda», mi disse, «le feroci Erine. Quest’ è Megera dal sinistro canto; quella che piange dal destro è Aletto; Tesifón è nel mezzo»; e tacque a tanto. Con l’unghie si fendea ciascuna il petto; battiensi a palme e gridavan sì alto, ch’i’ mi strinsi al poeta per sospetto. «Vegna Medusa: sì ’l farem di smalto», dicevan tutte riguardando in giuso; «mal non vengiammo in Tesëo l’assalto». «Volgiti ’n dietro e tien lo viso chiuso; ché se ’l Gorgón si mostra e tu ’l vedessi, nulla sarebbe di tornar mai suso». Così disse ’l maestro; ed elli stessi mi volse, e non si tenne a le mie mani, che con le sue ancor non mi chiudessi. O voi ch’avete li ’ntelletti sani, mirate la dottrina che s’asconde sotto ’l velame de li versi strani. E già venìa su per le torbide onde un fracasso d’un suon, pien di spavento, per cui tremavano amendue le sponde, non altrimenti fatto che d’un vento impetüoso per li avversi ardori, che fier la selva e sanz’ alcun rattento li rami schianta, abbatte e porta fori; dinanzi polveroso va superbo, e fa fuggir le fiere e li pastori. Li occhi mi sciolse e disse: «Or drizza il nerbo del viso su per quella schiuma antica per indi ove quel fummo è più acerbo». Come le rane innanzi a la nimica biscia per l’acqua si dileguan tutte, fin ch’a la terra ciascuna s’abbica, vid’ io più di mille anime distrutte fuggir così dinanzi ad un ch’al passo passava Stige con le piante asciutte. Dal volto rimovea quell’ aere grasso, menando la sinistra innanzi spesso; e sol di quell’ angoscia parea lasso. Ben m’accorsi ch’elli era da ciel messo, e volsimi al maestro; e quei fé segno ch’i’ stessi queto ed inchinassi ad esso. Ahi quanto mi parea pien di disdegno! Venne a la porta e con una verghetta l’aperse, che non v’ebbe alcun ritegno. «O cacciati del ciel, gente dispetta», cominciò elli in su l’orribil soglia, «ond’ esta oltracotanza in voi s’alletta? Perché recalcitrate a quella voglia a cui non puote il fin mai esser mozzo, e che più volte v’ha cresciuta doglia? Che giova ne le fata dar di cozzo? Cerbero vostro, se ben vi ricorda, ne porta ancor pelato il mento e ’l gozzo». Poi si rivolse per la strada lorda, e non fé motto a noi, ma fé sembiante d’omo cui altra cura stringa e morda che quella di colui che li è davante; e noi movemmo i piedi inver’ la terra, sicuri appresso le parole sante. Dentro li ’ntrammo sanz’ alcuna guerra; e io, ch’avea di riguardar disio la condizion che tal fortezza serra, com’ io fui dentro, l’occhio intorno invio: e veggio ad ogne man grande campagna, piena di duolo e di tormento rio. Sì come ad Arli, ove Rodano stagna, sì com’ a Pola, presso del Carnaro ch’Italia chiude e suoi termini bagna, fanno i sepulcri tutt’ il loco varo, così facevan quivi d’ogne parte, salvo che ’l modo v’era più amaro; ché tra li avelli fiamme erano sparte, per le quali eran sì del tutto accesi, che ferro più non chiede verun’ arte. Tutti li lor coperchi eran sospesi, e fuor n’uscivan sì duri lamenti, che ben parean di miseri e d’offesi. E io: «Maestro, quai son quelle genti che, seppellite dentro da quell’ arche, si fan sentir coi sospiri dolenti?». E quelli a me: «Qui son li eresïarche con lor seguaci, d’ogne setta, e molto più che non credi son le tombe carche. Simile qui con simile è sepolto, e i monimenti son più e men caldi». E poi ch’a la man destra si fu vòlto, passammo tra i martìri e li alti spaldi. Inferno · Canto X Ora sen va per un secreto calle, tra ’l muro de la terra e li martìri, lo mio maestro, e io dopo le spalle. «O virtù somma, che per li empi giri mi volvi», cominciai, «com’ a te piace, parlami, e sodisfammi a’ miei disiri. La gente che per li sepolcri giace potrebbesi veder? già son levati tutt’ i coperchi, e nessun guardia face». E quelli a me: «Tutti saran serrati quando di Iosafàt qui torneranno coi corpi che là sù hanno lasciati. Suo cimitero da questa parte hanno con Epicuro tutti suoi seguaci, che l’anima col corpo morta fanno. Però a la dimanda che mi faci quinc’ entro satisfatto sarà tosto, e al disio ancor che tu mi taci». E io: «Buon duca, non tegno riposto a te mio cuor se non per dicer poco, e tu m’hai non pur mo a ciò disposto». «O Tosco che per la città del foco vivo ten vai così parlando onesto, piacciati di restare in questo loco. La tua loquela ti fa manifesto di quella nobil patrïa natio, a la qual forse fui troppo molesto». Subitamente questo suono uscìo d’una de l’arche; però m’accostai, temendo, un poco più al duca mio. Ed el mi disse: «Volgiti! Che fai? Vedi là Farinata che s’è dritto: da la cintola in sù tutto ’l vedrai». Io avea già il mio viso nel suo fitto; ed el s’ergea col petto e con la fronte com’ avesse l’inferno a gran dispitto. E l’animose man del duca e pronte mi pinser tra le sepulture a lui, dicendo: «Le parole tue sien conte». Com’ io al piè de la sua tomba fui, guardommi un poco, e poi, quasi sdegnoso, mi dimandò: «Chi fuor li maggior tui?». Io ch’era d’ubidir disideroso, non gliel celai, ma tutto gliel’ apersi; ond’ ei levò le ciglia un poco in suso; poi disse: «Fieramente furo avversi a me e a miei primi e a mia parte, sì che per due fïate li dispersi». «S’ei fur cacciati, ei tornar d’ogne parte», rispuos’ io lui, «l’una e l’altra fïata; ma i vostri non appreser ben quell’ arte». Allor surse a la vista scoperchiata un’ombra, lungo questa, infino al mento: credo che s’era in ginocchie levata. Dintorno mi guardò, come talento avesse di veder s’altri era meco; e poi che ’l sospecciar fu tutto spento, piangendo disse: «Se per questo cieco carcere vai per altezza d’ingegno, mio figlio ov’ è? e perché non è teco?». E io a lui: «Da me stesso non vegno: colui ch’attende là, per qui mi mena forse cui Guido vostro ebbe a disdegno». Le sue parole e ’l modo de la pena m’avean di costui già letto il nome; però fu la risposta così piena. Di sùbito drizzato gridò: «Come? dicesti “elli ebbe”? non viv’ elli ancora? non fiere li occhi suoi lo dolce lume?». Quando s’accorse d’alcuna dimora ch’io facëa dinanzi a la risposta, supin ricadde e più non parve fora. Ma quell’ altro magnanimo, a cui posta restato m’era, non mutò aspetto, né mosse collo, né piegò sua costa; e sé continüando al primo detto, «S’elli han quell’ arte», disse, «male appresa, ciò mi tormenta più che questo letto. Ma non cinquanta volte fia raccesa la faccia de la donna che qui regge, che tu saprai quanto quell’ arte pesa. E se tu mai nel dolce mondo regge, dimmi: perché quel popolo è sì empio incontr’ a’ miei in ciascuna sua legge?». Ond’ io a lui: «Lo strazio e ’l grande scempio che fece l’Arbia colorata in rosso, tal orazion fa far nel nostro tempio». Poi ch’ebbe sospirando il capo mosso, «A ciò non fu’ io sol», disse, «né certo sanza cagion con li altri sarei mosso. Ma fu’ io solo, là dove sofferto fu per ciascun di tòrre via Fiorenza, colui che la difesi a viso aperto». «Deh, se riposi mai vostra semenza», prega’ io lui, «solvetemi quel nodo che qui ha ’nviluppata mia sentenza. El par che voi veggiate, se ben odo, dinanzi quel che ’l tempo seco adduce, e nel presente tenete altro modo». «Noi veggiam, come quei c’ha mala luce, le cose», disse, «che ne son lontano; cotanto ancor ne splende il sommo duce. Quando s’appressano o son, tutto è vano nostro intelletto; e s’altri non ci apporta, nulla sapem di vostro stato umano. Però comprender puoi che tutta morta fia nostra conoscenza da quel punto che del futuro fia chiusa la porta». Allor, come di mia colpa compunto, dissi: «Or direte dunque a quel caduto che ’l suo nato è co’ vivi ancor congiunto; e s’i’ fui, dianzi, a la risposta muto, fate i saper che ’l fei perché pensava già ne l’error che m’avete soluto». E già ’l maestro mio mi richiamava; per ch’i’ pregai lo spirto più avaccio che mi dicesse chi con lu’ istava. Dissemi: «Qui con più di mille giaccio: qua dentro è ’l secondo Federico e ’l Cardinale; e de li altri mi taccio». Indi s’ascose; e io inver’ l’antico poeta volsi i passi, ripensando a quel parlar che mi parea nemico. Elli si mosse; e poi, così andando, mi disse: «Perché se’ tu sì smarrito?». E io li sodisfeci al suo dimando. «La mente tua conservi quel ch’udito hai contra te», mi comandò quel saggio; «e ora attendi qui», e drizzò ’l dito: «quando sarai dinanzi al dolce raggio di quella il cui bell’ occhio tutto vede, da lei saprai di tua vita il vïaggio». Appresso mosse a man sinistra il piede: lasciammo il muro e gimmo inver’ lo mezzo per un sentier ch’a una valle fiede, che ’nfin là sù facea spiacer suo lezzo. Inferno · Canto XI In su l’estremità d’un’alta ripa che facevan gran pietre rotte in cerchio, venimmo sopra più crudele stipa; e quivi, per l’orribile soperchio del puzzo che ’l profondo abisso gitta, ci raccostammo, in dietro, ad un coperchio d’un grand’ avello, ov’ io vidi una scritta che dicea: ‘Anastasio papa guardo, lo qual trasse Fotin de la via dritta’. «Lo nostro scender conviene esser tardo, sì che s’ausi un poco in prima il senso al tristo fiato; e poi no i fia riguardo». Così ’l maestro; e io «Alcun compenso», dissi lui, «trova che ’l tempo non passi perduto». Ed elli: «Vedi ch’a ciò penso». «Figliuol mio, dentro da cotesti sassi», cominciò poi a dir, «son tre cerchietti di grado in grado, come que’ che lassi. Tutti son pien di spirti maladetti; ma perché poi ti basti pur la vista, intendi come e perché son costretti. D’ogne malizia, ch’odio in cielo acquista, ingiuria è ’l fine, ed ogne fin cotale o con forza o con frode altrui contrista. Ma perché frode è de l’uom proprio male, più spiace a Dio; e però stan di sotto li frodolenti, e più dolor li assale. Di vïolenti il primo cerchio è tutto; ma perché si fa forza a tre persone, in tre gironi è distinto e costrutto. A Dio, a sé, al prossimo si pòne far forza, dico in loro e in lor cose, come udirai con aperta ragione. Morte per forza e ferute dogliose nel prossimo si danno, e nel suo avere ruine, incendi e tollette dannose; onde omicide e ciascun che mal fiere, guastatori e predon, tutti tormenta lo giron primo per diverse schiere. Puote omo avere in sé man vïolenta e ne’ suoi beni; e però nel secondo giron convien che sanza pro si penta qualunque priva sé del vostro mondo, biscazza e fonde la sua facultade, e piange là dov’ esser de’ giocondo. Puossi far forza ne la deïtade, col cor negando e bestemmiando quella, e spregiando natura e sua bontade; e però lo minor giron suggella del segno suo e Soddoma e Caorsa e chi, spregiando Dio col cor, favella. La frode, ond’ ogne coscïenza è morsa, può l’omo usare in colui che ’n lui fida e in quel che fidanza non imborsa. Questo modo di retro par ch’incida pur lo vinco d’amor che fa natura; onde nel cerchio secondo s’annida ipocresia, lusinghe e chi affattura, falsità, ladroneccio e simonia, ruffian, baratti e simile lordura. Per l’altro modo quell’ amor s’oblia che fa natura, e quel ch’è poi aggiunto, di che la fede spezïal si cria; onde nel cerchio minore, ov’ è ’l punto de l’universo in su che Dite siede, qualunque trade in etterno è consunto». E io: «Maestro, assai chiara procede la tua ragione, e assai ben distingue questo baràtro e ’l popol ch’e’ possiede. Ma dimmi: quei de la palude pingue, che mena il vento, e che batte la pioggia, e che s’incontran con sì aspre lingue, perché non dentro da la città roggia sono ei puniti, se Dio li ha in ira? e se non li ha, perché sono a tal foggia?». Ed elli a me «Perché tanto delira», disse, «lo ’ngegno tuo da quel che sòle? o ver la mente dove altrove mira? Non ti rimembra di quelle parole con le quai la tua Etica pertratta le tre disposizion che ’l ciel non vole, incontenenza, malizia e la matta bestialitade? e come incontenenza men Dio offende e men biasimo accatta? Se tu riguardi ben questa sentenza, e rechiti a la mente chi son quelli che sù di fuor sostegnon penitenza, tu vedrai ben perché da questi felli sien dipartiti, e perché men crucciata la divina vendetta li martelli». «O sol che sani ogne vista turbata, tu mi contenti sì quando tu solvi, che, non men che saver, dubbiar m’aggrata. Ancora in dietro un poco ti rivolvi», diss’ io, «là dove di’ ch’usura offende la divina bontade, e ’l groppo solvi». «Filosofia», mi disse, «a chi la ’ntende, nota, non pure in una sola parte, come natura lo suo corso prende dal divino ’ntelletto e da sua arte; e se tu ben la tua Fisica note, tu troverai, non dopo molte carte, che l’arte vostra quella, quanto pote, segue, come ’l maestro fa ’l discente; sì che vostr’ arte a Dio quasi è nepote. Da queste due, se tu ti rechi a mente lo Genesì dal principio, convene prender sua vita e avanzar la gente; e perché l’usuriere altra via tene, per sé natura e per la sua seguace dispregia, poi ch’in altro pon la spene. Ma seguimi oramai che ’l gir mi piace; ché i Pesci guizzan su per l’orizzonta, e ’l Carro tutto sovra ’l Coro giace, e ’l balzo via là oltra si dismonta». Inferno · Canto XII Era lo loco ov’ a scender la riva venimmo, alpestro e, per quel che v’er’ anco, tal, ch’ogne vista ne sarebbe schiva. Qual è quella ruina che nel fianco di qua da Trento l’Adice percosse, o per tremoto o per sostegno manco, che da cima del monte, onde si mosse, al piano è sì la roccia discoscesa, ch’alcuna via darebbe a chi sù fosse: cotal di quel burrato era la scesa; e ’n su la punta de la rotta lacca l’infamïa di Creti era distesa che fu concetta ne la falsa vacca; e quando vide noi, sé stesso morse, sì come quei cui l’ira dentro fiacca. Lo savio mio inver’ lui gridò: «Forse tu credi che qui sia ’l duca d’Atene, che sù nel mondo la morte ti porse? Pàrtiti, bestia, ché questi non vene ammaestrato da la tua sorella, ma vassi per veder le vostre pene». Qual è quel toro che si slaccia in quella c’ha ricevuto già ’l colpo mortale, che gir non sa, ma qua e là saltella, vid’ io lo Minotauro far cotale; e quello accorto gridò: «Corri al varco; mentre ch’e’ ’nfuria, è buon che tu ti cale». Così prendemmo via giù per lo scarco di quelle pietre, che spesso moviensi sotto i miei piedi per lo novo carco. Io gia pensando; e quei disse: «Tu pensi forse a questa ruina, ch’è guardata da quell’ ira bestial ch’i’ ora spensi. Or vo’ che sappi che l’altra fïata ch’i’ discesi qua giù nel basso inferno, questa roccia non era ancor cascata. Ma certo poco pria, se ben discerno, che venisse colui che la gran preda levò a Dite del cerchio superno, da tutte parti l’alta valle feda tremò sì, ch’i’ pensai che l’universo sentisse amor, per lo qual è chi creda più volte il mondo in caòsso converso; e in quel punto questa vecchia roccia, qui e altrove, tal fece riverso. Ma ficca li occhi a valle, ché s’approccia la riviera del sangue in la qual bolle qual che per vïolenza in altrui noccia». Oh cieca cupidigia e ira folle, che sì ci sproni ne la vita corta, e ne l’etterna poi sì mal c’immolle! Io vidi un’ampia fossa in arco torta, come quella che tutto ’l piano abbraccia, secondo ch’avea detto la mia scorta; e tra ’l piè de la ripa ed essa, in traccia corrien centauri, armati di saette, come solien nel mondo andare a caccia. Veggendoci calar, ciascun ristette, e de la schiera tre si dipartiro con archi e asticciuole prima elette; e l’un gridò da lungi: «A qual martiro venite voi che scendete la costa? Ditel costinci; se non, l’arco tiro». Lo mio maestro disse: «La risposta farem noi a Chirón costà di presso: mal fu la voglia tua sempre sì tosta». Poi mi tentò, e disse: «Quelli è Nesso, che morì per la bella Deianira, e fé di sé la vendetta elli stesso. E quel di mezzo, ch’al petto si mira, è il gran Chirón, il qual nodrì Achille; quell’ altro è Folo, che fu sì pien d’ira. Dintorno al fosso vanno a mille a mille, saettando qual anima si svelle del sangue più che sua colpa sortille». Noi ci appressammo a quelle fiere isnelle: Chirón prese uno strale, e con la cocca fece la barba in dietro a le mascelle. Quando s’ebbe scoperta la gran bocca, disse a’ compagni: «Siete voi accorti che quel di retro move ciò ch’el tocca? Così non soglion far li piè d’i morti». E ’l mio buon duca, che già li er’ al petto, dove le due nature son consorti, rispuose: «Ben è vivo, e sì soletto mostrar li mi convien la valle buia; necessità ’l ci ’nduce, e non diletto. Tal si partì da cantare alleluia che mi commise quest’ officio novo: non è ladron, né io anima fuia. Ma per quella virtù per cu’ io movo li passi miei per sì selvaggia strada, danne un de’ tuoi, a cui noi siamo a provo, e che ne mostri là dove si guada, e che porti costui in su la groppa, ché non è spirto che per l’aere vada». Chirón si volse in su la destra poppa, e disse a Nesso: «Torna, e sì li guida, e fa cansar s’altra schiera v’intoppa». Or ci movemmo con la scorta fida lungo la proda del bollor vermiglio, dove i bolliti facieno alte strida. Io vidi gente sotto infino al ciglio; e ’l gran centauro disse: «E’ son tiranni che dier nel sangue e ne l’aver di piglio. Quivi si piangon li spietati danni; quivi è Alessandro, e Dïonisio fero che fé Cicilia aver dolorosi anni. E quella fronte c’ha ’l pel così nero, è Azzolino; e quell’ altro ch’è biondo, è Opizzo da Esti, il qual per vero fu spento dal figliastro sù nel mondo». Allor mi volsi al poeta, e quei disse: «Questi ti sia or primo, e io secondo». Poco più oltre il centauro s’affisse sovr’ una gente che ’nfino a la gola parea che di quel bulicame uscisse. Mostrocci un’ombra da l’un canto sola, dicendo: «Colui fesse in grembo a Dio lo cor che ’n su Tamisi ancor si cola». Poi vidi gente che di fuor del rio tenean la testa e ancor tutto ’l casso; e di costoro assai riconobb’ io. Così a più a più si facea basso quel sangue, sì che cocea pur li piedi; e quindi fu del fosso il nostro passo. «Sì come tu da questa parte vedi lo bulicame che sempre si scema», disse ’l centauro, «voglio che tu credi che da quest’ altra a più a più giù prema lo fondo suo, infin ch’el si raggiunge ove la tirannia convien che gema. La divina giustizia di qua punge quell’ Attila che fu flagello in terra, e Pirro e Sesto; e in etterno munge le lagrime, che col bollor diserra, a Rinier da Corneto, a Rinier Pazzo, che fecero a le strade tanta guerra». Poi si rivolse e ripassossi ’l guazzo. Inferno · Canto XIII Non era ancor di là Nesso arrivato, quando noi ci mettemmo per un bosco che da neun sentiero era segnato. Non fronda verde, ma di color fosco; non rami schietti, ma nodosi e ’nvolti; non pomi v’eran, ma stecchi con tòsco. Non han sì aspri sterpi né sì folti quelle fiere selvagge che ’n odio hanno tra Cecina e Corneto i luoghi cólti. Quivi le brutte Arpie lor nidi fanno, che cacciar de le Strofade i Troiani con tristo annunzio di futuro danno. Ali hanno late, e colli e visi umani, piè con artigli, e pennuto ’l gran ventre; fanno lamenti in su li alberi strani. E ’l buon maestro «Prima che più entre, sappi che se’ nel secondo girone», mi cominciò a dire, «e sarai mentre che tu verrai ne l’orribil sabbione. Però riguarda ben; sì vederai cose che torrien fede al mio sermone». Io sentia d’ogne parte trarre guai e non vedea persona che ’l facesse; per ch’io tutto smarrito m’arrestai. Cred’ ïo ch’ei credette ch’io credesse che tante voci uscisser, tra quei bronchi, da gente che per noi si nascondesse. Però disse ’l maestro: «Se tu tronchi qualche fraschetta d’una d’este piante, li pensier c’hai si faran tutti monchi». Allor porsi la mano un poco avante e colsi un ramicel da un gran pruno; e ’l tronco suo gridò: «Perché mi schiante?». Da che fatto fu poi di sangue bruno, ricominciò a dir: «Perché mi scerpi? non hai tu spirto di pietade alcuno? Uomini fummo, e or siam fatti sterpi: ben dovrebb’ esser la tua man più pia, se state fossimo anime di serpi». Come d’un stizzo verde ch’arso sia da l’un de’ capi, che da l’altro geme e cigola per vento che va via, sì de la scheggia rotta usciva insieme parole e sangue; ond’ io lasciai la cima cadere, e stetti come l’uom che teme. «S’elli avesse potuto creder prima», rispuose ’l savio mio, «anima lesa, ciò c’ha veduto pur con la mia rima, non averebbe in te la man distesa; ma la cosa incredibile mi fece indurlo ad ovra ch’a me stesso pesa. Ma dilli chi tu fosti, sì che ’n vece d’alcun’ ammenda tua fama rinfreschi nel mondo sù, dove tornar li lece». E ’l tronco: «Sì col dolce dir m’adeschi, ch’i’ non posso tacere; e voi non gravi perch’ ïo un poco a ragionar m’inveschi. Io son colui che tenni ambo le chiavi del cor di Federigo, e che le volsi, serrando e diserrando, sì soavi, che dal secreto suo quasi ogn’ uom tolsi; fede portai al glorïoso offizio, tanto ch’i’ ne perde’ li sonni e ’ polsi. La meretrice che mai da l’ospizio di Cesare non torse li occhi putti, morte comune e de le corti vizio, infiammò contra me li animi tutti; e li ’nfiammati infiammar sì Augusto, che ’ lieti onor tornaro in tristi lutti. L’animo mio, per disdegnoso gusto, credendo col morir fuggir disdegno, ingiusto fece me contra me giusto. Per le nove radici d’esto legno vi giuro che già mai non ruppi fede al mio segnor, che fu d’onor sì degno. E se di voi alcun nel mondo riede, conforti la memoria mia, che giace ancor del colpo che ’nvidia le diede». Un poco attese, e poi «Da ch’el si tace», disse ’l poeta a me, «non perder l’ora; ma parla, e chiedi a lui, se più ti piace». Ond’ ïo a lui: «Domandal tu ancora di quel che credi ch’a me satisfaccia; ch’i’ non potrei, tanta pietà m’accora». Perciò ricominciò: «Se l’om ti faccia liberamente ciò che ’l tuo dir priega, spirito incarcerato, ancor ti piaccia di dirne come l’anima si lega in questi nocchi; e dinne, se tu puoi, s’alcuna mai di tai membra si spiega». Allor soffiò il tronco forte, e poi si convertì quel vento in cotal voce: «Brievemente sarà risposto a voi. Quando si parte l’anima feroce dal corpo ond’ ella stessa s’è disvelta, Minòs la manda a la settima foce. Cade in la selva, e non l’è parte scelta; ma là dove fortuna la balestra, quivi germoglia come gran di spelta. Surge in vermena e in pianta silvestra: l’Arpie, pascendo poi de le sue foglie, fanno dolore, e al dolor fenestra. Come l’altre verrem per nostre spoglie, ma non però ch’alcuna sen rivesta, ché non è giusto aver ciò ch’om si toglie. Qui le strascineremo, e per la mesta selva saranno i nostri corpi appesi, ciascuno al prun de l’ombra sua molesta». Noi eravamo ancora al tronco attesi, credendo ch’altro ne volesse dire, quando noi fummo d’un romor sorpresi, similemente a colui che venire sente ’l porco e la caccia a la sua posta, ch’ode le bestie, e le frasche stormire. Ed ecco due da la sinistra costa, nudi e graffiati, fuggendo sì forte, che de la selva rompieno ogne rosta. Quel dinanzi: «Or accorri, accorri, morte!». E l’altro, cui pareva tardar troppo, gridava: «Lano, sì non furo accorte le gambe tue a le giostre dal Toppo!». E poi che forse li fallia la lena, di sé e d’un cespuglio fece un groppo. Di rietro a loro era la selva piena di nere cagne, bramose e correnti come veltri ch’uscisser di catena. In quel che s’appiattò miser li denti, e quel dilaceraro a brano a brano; poi sen portar quelle membra dolenti. Presemi allor la mia scorta per mano, e menommi al cespuglio che piangea per le rotture sanguinenti in vano. «O Iacopo», dicea, «da Santo Andrea, che t’è giovato di me fare schermo? che colpa ho io de la tua vita rea?». Quando ’l maestro fu sovr’ esso fermo, disse: «Chi fosti, che per tante punte soffi con sangue doloroso sermo?». Ed elli a noi: «O anime che giunte siete a veder lo strazio disonesto c’ha le mie fronde sì da me disgiunte, raccoglietele al piè del tristo cesto. I’ fui de la città che nel Batista mutò ’l primo padrone; ond’ ei per questo sempre con l’arte sua la farà trista; e se non fosse che ’n sul passo d’Arno rimane ancor di lui alcuna vista, que’ cittadin che poi la rifondarno sovra ’l cener che d’Attila rimase, avrebber fatto lavorare indarno. Io fei gibetto a me de le mie case». Inferno · Canto XIV Poi che la carità del natio loco mi strinse, raunai le fronde sparte e rende’le a colui, ch’era già fioco. Indi venimmo al fine ove si parte lo secondo giron dal terzo, e dove si vede di giustizia orribil arte. A ben manifestar le cose nove, dico che arrivammo ad una landa che dal suo letto ogne pianta rimove. La dolorosa selva l’è ghirlanda intorno, come ’l fosso tristo ad essa; quivi fermammo i passi a randa a randa. Lo spazzo era una rena arida e spessa, non d’altra foggia fatta che colei che fu da’ piè di Caton già soppressa. O vendetta di Dio, quanto tu dei esser temuta da ciascun che legge ciò che fu manifesto a li occhi mei! D’anime nude vidi molte gregge che piangean tutte assai miseramente, e parea posta lor diversa legge. Supin giacea in terra alcuna gente, alcuna si sedea tutta raccolta, e altra andava continüamente. Quella che giva ’ntorno era più molta, e quella men che giacëa al tormento, ma più al duolo avea la lingua sciolta. Sovra tutto ’l sabbion, d’un cader lento, piovean di foco dilatate falde, come di neve in alpe sanza vento. Quali Alessandro in quelle parti calde d’Indïa vide sopra ’l süo stuolo fiamme cadere infino a terra salde, per ch’ei provide a scalpitar lo suolo con le sue schiere, acciò che lo vapore mei si stingueva mentre ch’era solo: tale scendeva l’etternale ardore; onde la rena s’accendea, com’ esca sotto focile, a doppiar lo dolore. Sanza riposo mai era la tresca de le misere mani, or quindi or quinci escotendo da sé l’arsura fresca. I’ cominciai: «Maestro, tu che vinci tutte le cose, fuor che ’ demon duri ch’a l’intrar de la porta incontra uscinci, chi è quel grande che non par che curi lo ’ncendio e giace dispettoso e torto, sì che la pioggia non par che ’l marturi?». E quel medesmo, che si fu accorto ch’io domandava il mio duca di lui, gridò: «Qual io fui vivo, tal son morto. Se Giove stanchi ’l suo fabbro da cui crucciato prese la folgore aguta onde l’ultimo dì percosso fui; o s’elli stanchi li altri a muta a muta in Mongibello a la focina negra, chiamando “Buon Vulcano, aiuta, aiuta!”, sì com’ el fece a la pugna di Flegra, e me saetti con tutta sua forza: non ne potrebbe aver vendetta allegra». Allora il duca mio parlò di forza tanto, ch’i’ non l’avea sì forte udito: «O Capaneo, in ciò che non s’ammorza la tua superbia, se’ tu più punito; nullo martiro, fuor che la tua rabbia, sarebbe al tuo furor dolor compito». Poi si rivolse a me con miglior labbia, dicendo: «Quei fu l’un d’i sette regi ch’assiser Tebe; ed ebbe e par ch’elli abbia Dio in disdegno, e poco par che ’l pregi; ma, com’ io dissi lui, li suoi dispetti sono al suo petto assai debiti fregi. Or mi vien dietro, e guarda che non metti, ancor, li piedi ne la rena arsiccia; ma sempre al bosco tien li piedi stretti». Tacendo divenimmo là ’ve spiccia fuor de la selva un picciol fiumicello, lo cui rossore ancor mi raccapriccia. Quale del Bulicame esce ruscello che parton poi tra lor le peccatrici, tal per la rena giù sen giva quello. Lo fondo suo e ambo le pendici fatt’ era ’n pietra, e ’ margini dallato; per ch’io m’accorsi che ’l passo era lici. «Tra tutto l’altro ch’i’ t’ho dimostrato, poscia che noi intrammo per la porta lo cui sogliare a nessuno è negato, cosa non fu da li tuoi occhi scorta notabile com’ è ’l presente rio, che sovra sé tutte fiammelle ammorta». Queste parole fuor del duca mio; per ch’io ’l pregai che mi largisse ’l pasto di cui largito m’avëa il disio. «In mezzo mar siede un paese guasto», diss’ elli allora, «che s’appella Creta, sotto ’l cui rege fu già ’l mondo casto. Una montagna v’è che già fu lieta d’acqua e di fronde, che si chiamò Ida; or è diserta come cosa vieta. Rëa la scelse già per cuna fida del suo figliuolo, e per celarlo meglio, quando piangea, vi facea far le grida. Dentro dal monte sta dritto un gran veglio, che tien volte le spalle inver’ Dammiata e Roma guarda come süo speglio. La sua testa è di fin oro formata, e puro argento son le braccia e ’l petto, poi è di rame infino a la forcata; da indi in giuso è tutto ferro eletto, salvo che ’l destro piede è terra cotta; e sta ’n su quel, più che ’n su l’altro, eretto. Ciascuna parte, fuor che l’oro, è rotta d’una fessura che lagrime goccia, le quali, accolte, fóran quella grotta. Lor corso in questa valle si diroccia; fanno Acheronte, Stige e Flegetonta; poi sen van giù per questa stretta doccia, infin, là ove più non si dismonta, fanno Cocito; e qual sia quello stagno tu lo vedrai, però qui non si conta». E io a lui: «Se ’l presente rigagno si diriva così dal nostro mondo, perché ci appar pur a questo vivagno?». Ed elli a me: «Tu sai che ’l loco è tondo; e tutto che tu sie venuto molto, pur a sinistra, giù calando al fondo, non se’ ancor per tutto ’l cerchio vòlto; per che, se cosa n’apparisce nova, non de’ addur maraviglia al tuo volto». E io ancor: «Maestro, ove si trova Flegetonta e Letè? ché de l’un taci, e l’altro di’ che si fa d’esta piova». «In tutte tue question certo mi piaci», rispuose, «ma ’l bollor de l’acqua rossa dovea ben solver l’una che tu faci. Letè vedrai, ma fuor di questa fossa, là dove vanno l’anime a lavarsi quando la colpa pentuta è rimossa». Poi disse: «Omai è tempo da scostarsi dal bosco; fa che di retro a me vegne: li margini fan via, che non son arsi, e sopra loro ogne vapor si spegne». Inferno · Canto XV Ora cen porta l’un de’ duri margini; e ’l fummo del ruscel di sopra aduggia, sì che dal foco salva l’acqua e li argini. Quali Fiamminghi tra Guizzante e Bruggia, temendo ’l fiotto che ’nver’ lor s’avventa, fanno lo schermo perché ’l mar si fuggia; e quali Padoan lungo la Brenta, per difender lor ville e lor castelli, anzi che Carentana il caldo senta: a tale imagine eran fatti quelli, tutto che né sì alti né sì grossi, qual che si fosse, lo maestro félli. Già eravam da la selva rimossi tanto, ch’i’ non avrei visto dov’ era, perch’ io in dietro rivolto mi fossi, quando incontrammo d’anime una schiera che venian lungo l’argine, e ciascuna ci riguardava come suol da sera guardare uno altro sotto nuova luna; e sì ver’ noi aguzzavan le ciglia come ’l vecchio sartor fa ne la cruna. Così adocchiato da cotal famiglia, fui conosciuto da un, che mi prese per lo lembo e gridò: «Qual maraviglia!». E io, quando ’l suo braccio a me distese, ficcaï li occhi per lo cotto aspetto, sì che ’l viso abbrusciato non difese la conoscenza süa al mio ’ntelletto; e chinando la mano a la sua faccia, rispuosi: «Siete voi qui, ser Brunetto?». E quelli: «O figliuol mio, non ti dispiaccia se Brunetto Latino un poco teco ritorna ’n dietro e lascia andar la traccia». I’ dissi lui: «Quanto posso, ven preco; e se volete che con voi m’asseggia, faròl, se piace a costui che vo seco». «O figliuol», disse, «qual di questa greggia s’arresta punto, giace poi cent’ anni sanz’ arrostarsi quando ’l foco il feggia. Però va oltre: i’ ti verrò a’ panni; e poi rigiugnerò la mia masnada, che va piangendo i suoi etterni danni». Io non osava scender de la strada per andar par di lui; ma ’l capo chino tenea com’ uom che reverente vada. El cominciò: «Qual fortuna o destino anzi l’ultimo dì qua giù ti mena? e chi è questi che mostra ’l cammino?». «Là sù di sopra, in la vita serena», rispuos’ io lui, «mi smarri’ in una valle, avanti che l’età mia fosse piena. Pur ier mattina le volsi le spalle: questi m’apparve, tornand’ ïo in quella, e reducemi a ca per questo calle». Ed elli a me: «Se tu segui tua stella, non puoi fallire a glorïoso porto, se ben m’accorsi ne la vita bella; e s’io non fossi sì per tempo morto, veggendo il cielo a te così benigno, dato t’avrei a l’opera conforto. Ma quello ingrato popolo maligno che discese di Fiesole ab antico, e tiene ancor del monte e del macigno, ti si farà, per tuo ben far, nimico; ed è ragion, ché tra li lazzi sorbi si disconvien fruttare al dolce fico. Vecchia fama nel mondo li chiama orbi; gent’ è avara, invidiosa e superba: dai lor costumi fa che tu ti forbi. La tua fortuna tanto onor ti serba, che l’una parte e l’altra avranno fame di te; ma lungi fia dal becco l’erba. Faccian le bestie fiesolane strame di lor medesme, e non tocchin la pianta, s’alcuna surge ancora in lor letame, in cui riviva la sementa santa di que’ Roman che vi rimaser quando fu fatto il nido di malizia tanta». «Se fosse tutto pieno il mio dimando», rispuos’ io lui, «voi non sareste ancora de l’umana natura posto in bando; ché ’n la mente m’è fitta, e or m’accora, la cara e buona imagine paterna di voi quando nel mondo ad ora ad ora m’insegnavate come l’uom s’etterna: e quant’ io l’abbia in grado, mentr’ io vivo convien che ne la mia lingua si scerna. Ciò che narrate di mio corso scrivo, e serbolo a chiosar con altro testo a donna che saprà, s’a lei arrivo. Tanto vogl’ io che vi sia manifesto, pur che mia coscïenza non mi garra, ch’a la Fortuna, come vuol, son presto. Non è nuova a li orecchi miei tal arra: però giri Fortuna la sua rota come le piace, e ’l villan la sua marra». Lo mio maestro allora in su la gota destra si volse in dietro e riguardommi; poi disse: «Bene ascolta chi la nota». Né per tanto di men parlando vommi con ser Brunetto, e dimando chi sono li suoi compagni più noti e più sommi. Ed elli a me: «Saper d’alcuno è buono; de li altri fia laudabile tacerci, ché ’l tempo saria corto a tanto suono. In somma sappi che tutti fur cherci e litterati grandi e di gran fama, d’un peccato medesmo al mondo lerci. Priscian sen va con quella turba grama, e Francesco d’Accorso anche; e vedervi, s’avessi avuto di tal tigna brama, colui potei che dal servo de’ servi fu trasmutato d’Arno in Bacchiglione, dove lasciò li mal protesi nervi. Di più direi; ma ’l venire e ’l sermone più lungo esser non può, però ch’i’ veggio là surger nuovo fummo del sabbione. Gente vien con la quale esser non deggio. Sieti raccomandato il mio Tesoro, nel qual io vivo ancora, e più non cheggio». Poi si rivolse, e parve di coloro che corrono a Verona il drappo verde per la campagna; e parve di costoro quelli che vince, non colui che perde. Inferno · Canto XVI Già era in loco onde s’udia ’l rimbombo de l’acqua che cadea ne l’altro giro, simile a quel che l’arnie fanno rombo, quando tre ombre insieme si partiro, correndo, d’una torma che passava sotto la pioggia de l’aspro martiro. Venian ver’ noi, e ciascuna gridava: «Sòstati tu ch’a l’abito ne sembri esser alcun di nostra terra prava». Ahimè, che piaghe vidi ne’ lor membri, ricenti e vecchie, da le fiamme incese! Ancor men duol pur ch’i’ me ne rimembri. A le lor grida il mio dottor s’attese; volse ’l viso ver’ me, e «Or aspetta», disse, «a costor si vuole esser cortese. E se non fosse il foco che saetta la natura del loco, i’ dicerei che meglio stesse a te che a lor la fretta». Ricominciar, come noi restammo, ei l’antico verso; e quando a noi fuor giunti, fenno una rota di sé tutti e trei. Qual sogliono i campion far nudi e unti, avvisando lor presa e lor vantaggio, prima che sien tra lor battuti e punti, così rotando, ciascuno il visaggio drizzava a me, sì che ’n contraro il collo faceva ai piè continüo vïaggio. E «Se miseria d’esto loco sollo rende in dispetto noi e nostri prieghi», cominciò l’uno, «e ’l tinto aspetto e brollo, la fama nostra il tuo animo pieghi a dirne chi tu se’, che i vivi piedi così sicuro per lo ’nferno freghi. Questi, l’orme di cui pestar mi vedi, tutto che nudo e dipelato vada, fu di grado maggior che tu non credi: nepote fu de la buona Gualdrada; Guido Guerra ebbe nome, e in sua vita fece col senno assai e con la spada. L’altro, ch’appresso me la rena trita, è Tegghiaio Aldobrandi, la cui voce nel mondo sù dovria esser gradita. E io, che posto son con loro in croce, Iacopo Rusticucci fui, e certo la fiera moglie più ch’altro mi nuoce». S’i’ fossi stato dal foco coperto, gittato mi sarei tra lor di sotto, e credo che ’l dottor l’avria sofferto; ma perch’ io mi sarei brusciato e cotto, vinse paura la mia buona voglia che di loro abbracciar mi facea ghiotto. Poi cominciai: «Non dispetto, ma doglia la vostra condizion dentro mi fisse, tanta che tardi tutta si dispoglia, tosto che questo mio segnor mi disse parole per le quali i’ mi pensai che qual voi siete, tal gente venisse. Di vostra terra sono, e sempre mai l’ovra di voi e li onorati nomi con affezion ritrassi e ascoltai. Lascio lo fele e vo per dolci pomi promessi a me per lo verace duca; ma ’nfino al centro pria convien ch’i’ tomi». «Se lungamente l’anima conduca le membra tue», rispuose quelli ancora, «e se la fama tua dopo te luca, cortesia e valor dì se dimora ne la nostra città sì come suole, o se del tutto se n’è gita fora; ché Guiglielmo Borsiere, il qual si duole con noi per poco e va là coi compagni, assai ne cruccia con le sue parole». «La gente nuova e i sùbiti guadagni orgoglio e dismisura han generata, Fiorenza, in te, sì che tu già ten piagni». Così gridai con la faccia levata; e i tre, che ciò inteser per risposta, guardar l’un l’altro com’ al ver si guata. «Se l’altre volte sì poco ti costa», rispuoser tutti, «il satisfare altrui, felice te se sì parli a tua posta! Però, se campi d’esti luoghi bui e torni a riveder le belle stelle, quando ti gioverà dicere “I’ fui”, fa che di noi a la gente favelle». Indi rupper la rota, e a fuggirsi ali sembiar le gambe loro isnelle. Un amen non saria possuto dirsi tosto così com’ e’ fuoro spariti; per ch’al maestro parve di partirsi. Io lo seguiva, e poco eravam iti, che ’l suon de l’acqua n’era sì vicino, che per parlar saremmo a pena uditi. Come quel fiume c’ha proprio cammino prima dal Monte Viso ’nver’ levante, da la sinistra costa d’Apennino, che si chiama Acquacheta suso, avante che si divalli giù nel basso letto, e a Forlì di quel nome è vacante, rimbomba là sovra San Benedetto de l’Alpe per cadere ad una scesa ove dovea per mille esser recetto; così, giù d’una ripa discoscesa, trovammo risonar quell’ acqua tinta, sì che ’n poc’ ora avria l’orecchia offesa. Io avea una corda intorno cinta, e con essa pensai alcuna volta prender la lonza a la pelle dipinta. Poscia ch’io l’ebbi tutta da me sciolta, sì come ’l duca m’avea comandato, porsila a lui aggroppata e ravvolta. Ond’ ei si volse inver’ lo destro lato, e alquanto di lunge da la sponda la gittò giuso in quell’ alto burrato. ‘E’ pur convien che novità risponda’, dicea fra me medesmo, ‘al novo cenno che ’l maestro con l’occhio sì seconda’. Ahi quanto cauti li uomini esser dienno presso a color che non veggion pur l’ovra, ma per entro i pensier miran col senno! El disse a me: «Tosto verrà di sovra ciò ch’io attendo e che il tuo pensier sogna; tosto convien ch’al tuo viso si scovra». Sempre a quel ver c’ha faccia di menzogna de’ l’uom chiuder le labbra fin ch’el puote, però che sanza colpa fa vergogna; ma qui tacer nol posso; e per le note di questa comedìa, lettor, ti giuro, s’elle non sien di lunga grazia vòte, ch’i’ vidi per quell’ aere grosso e scuro venir notando una figura in suso, maravigliosa ad ogne cor sicuro, sì come torna colui che va giuso talora a solver l’àncora ch’aggrappa o scoglio o altro che nel mare è chiuso, che ’n sù si stende e da piè si rattrappa. Inferno · Canto XVII «Ecco la fiera con la coda aguzza, che passa i monti e rompe i muri e l’armi! Ecco colei che tutto ’l mondo appuzza!». Sì cominciò lo mio duca a parlarmi; e accennolle che venisse a proda, vicino al fin d’i passeggiati marmi. E quella sozza imagine di froda sen venne, e arrivò la testa e ’l busto, ma ’n su la riva non trasse la coda. La faccia sua era faccia d’uom giusto, tanto benigna avea di fuor la pelle, e d’un serpente tutto l’altro fusto; due branche avea pilose insin l’ascelle; lo dosso e ’l petto e ambedue le coste dipinti avea di nodi e di rotelle. Con più color, sommesse e sovraposte non fer mai drappi Tartari né Turchi, né fuor tai tele per Aragne imposte. Come talvolta stanno a riva i burchi, che parte sono in acqua e parte in terra, e come là tra li Tedeschi lurchi lo bivero s’assetta a far sua guerra, così la fiera pessima si stava su l’orlo ch’è di pietra e ’l sabbion serra. Nel vano tutta sua coda guizzava, torcendo in sù la venenosa forca ch’a guisa di scorpion la punta armava. Lo duca disse: «Or convien che si torca la nostra via un poco insino a quella bestia malvagia che colà si corca». Però scendemmo a la destra mammella, e diece passi femmo in su lo stremo, per ben cessar la rena e la fiammella. E quando noi a lei venuti semo, poco più oltre veggio in su la rena gente seder propinqua al loco scemo. Quivi ’l maestro «Acciò che tutta piena esperïenza d’esto giron porti», mi disse, «va, e vedi la lor mena. Li tuoi ragionamenti sian là corti; mentre che torni, parlerò con questa, che ne conceda i suoi omeri forti». Così ancor su per la strema testa di quel settimo cerchio tutto solo andai, dove sedea la gente mesta. Per li occhi fora scoppiava lor duolo; di qua, di là soccorrien con le mani quando a’ vapori, e quando al caldo suolo: non altrimenti fan di state i cani or col ceffo or col piè, quando son morsi o da pulci o da mosche o da tafani. Poi che nel viso a certi li occhi porsi, ne’ quali ’l doloroso foco casca, non ne conobbi alcun; ma io m’accorsi che dal collo a ciascun pendea una tasca ch’avea certo colore e certo segno, e quindi par che ’l loro occhio si pasca. E com’ io riguardando tra lor vegno, in una borsa gialla vidi azzurro che d’un leone avea faccia e contegno. Poi, procedendo di mio sguardo il curro, vidine un’altra come sangue rossa, mostrando un’oca bianca più che burro. E un che d’una scrofa azzurra e grossa segnato avea lo suo sacchetto bianco, mi disse: «Che fai tu in questa fossa? Or te ne va; e perché se’ vivo anco, sappi che ’l mio vicin Vitalïano sederà qui dal mio sinistro fianco. Con questi Fiorentin son padoano: spesse fïate mi ’ntronan li orecchi gridando: “Vegna ’l cavalier sovrano, che recherà la tasca con tre becchi!”». Qui distorse la bocca e di fuor trasse la lingua, come bue che ’l naso lecchi. E io, temendo no ’l più star crucciasse lui che di poco star m’avea ’mmonito, torna’mi in dietro da l’anime lasse. Trova’ il duca mio ch’era salito già su la groppa del fiero animale, e disse a me: «Or sie forte e ardito. Omai si scende per sì fatte scale; monta dinanzi, ch’i’ voglio esser mezzo, sì che la coda non possa far male». Qual è colui che sì presso ha ’l riprezzo de la quartana, c’ha già l’unghie smorte, e triema tutto pur guardando ’l rezzo, tal divenn’ io a le parole porte; ma vergogna mi fé le sue minacce, che innanzi a buon segnor fa servo forte. I’ m’assettai in su quelle spallacce; sì volli dir, ma la voce non venne com’ io credetti: ‘Fa che tu m’abbracce’. Ma esso, ch’altra volta mi sovvenne ad altro forse, tosto ch’i’ montai con le braccia m’avvinse e mi sostenne; e disse: «Gerïon, moviti omai: le rote larghe, e lo scender sia poco; pensa la nova soma che tu hai». Come la navicella esce di loco in dietro in dietro, sì quindi si tolse; e poi ch’al tutto si sentì a gioco, là ’v’ era ’l petto, la coda rivolse, e quella tesa, come anguilla, mosse, e con le branche l’aere a sé raccolse. Maggior paura non credo che fosse quando Fetonte abbandonò li freni, per che ’l ciel, come pare ancor, si cosse; né quando Icaro misero le reni sentì spennar per la scaldata cera, gridando il padre a lui «Mala via tieni!», che fu la mia, quando vidi ch’i’ era ne l’aere d’ogne parte, e vidi spenta ogne veduta fuor che de la fera. Ella sen va notando lenta lenta; rota e discende, ma non me n’accorgo se non che al viso e di sotto mi venta. Io sentia già da la man destra il gorgo far sotto noi un orribile scroscio, per che con li occhi ’n giù la testa sporgo. Allor fu’ io più timido a lo stoscio, però ch’i’ vidi fuochi e senti’ pianti; ond’ io tremando tutto mi raccoscio. E vidi poi, ché nol vedea davanti, lo scendere e ’l girar per li gran mali che s’appressavan da diversi canti. Come ’l falcon ch’è stato assai su l’ali, che sanza veder logoro o uccello fa dire al falconiere «Omè, tu cali!», discende lasso onde si move isnello, per cento rote, e da lunge si pone dal suo maestro, disdegnoso e fello; così ne puose al fondo Gerïone al piè al piè de la stagliata rocca, e, discarcate le nostre persone, si dileguò come da corda cocca. Inferno · Canto XVIII Luogo è in inferno detto Malebolge, tutto di pietra di color ferrigno, come la cerchia che dintorno il volge. Nel dritto mezzo del campo maligno vaneggia un pozzo assai largo e profondo, di cui suo loco dicerò l’ordigno. Quel cinghio che rimane adunque è tondo tra ’l pozzo e ’l piè de l’alta ripa dura, e ha distinto in dieci valli il fondo. Quale, dove per guardia de le mura più e più fossi cingon li castelli, la parte dove son rende figura, tale imagine quivi facean quelli; e come a tai fortezze da’ lor sogli a la ripa di fuor son ponticelli, così da imo de la roccia scogli movien che ricidien li argini e ’ fossi infino al pozzo che i tronca e raccogli. In questo luogo, de la schiena scossi di Gerïon, trovammoci; e ’l poeta tenne a sinistra, e io dietro mi mossi. A la man destra vidi nova pieta, novo tormento e novi frustatori, di che la prima bolgia era repleta. Nel fondo erano ignudi i peccatori; dal mezzo in qua ci venien verso ’l volto, di là con noi, ma con passi maggiori, come i Roman per l’essercito molto, l’anno del giubileo, su per lo ponte hanno a passar la gente modo colto, che da l’un lato tutti hanno la fronte verso ’l castello e vanno a Santo Pietro, da l’altra sponda vanno verso ’l monte. Di qua, di là, su per lo sasso tetro vidi demon cornuti con gran ferze, che li battien crudelmente di retro. Ahi come facean lor levar le berze a le prime percosse! già nessuno le seconde aspettava né le terze. Mentr’ io andava, li occhi miei in uno furo scontrati; e io sì tosto dissi: «Già di veder costui non son digiuno». Per ch’ïo a figurarlo i piedi affissi; e ’l dolce duca meco si ristette, e assentio ch’alquanto in dietro gissi. E quel frustato celar si credette bassando ’l viso; ma poco li valse, ch’io dissi: «O tu che l’occhio a terra gette, se le fazion che porti non son false, Venedico se’ tu Caccianemico. Ma che ti mena a sì pungenti salse?». Ed elli a me: «Mal volontier lo dico; ma sforzami la tua chiara favella, che mi fa sovvenir del mondo antico. I’ fui colui che la Ghisolabella condussi a far la voglia del marchese, come che suoni la sconcia novella. E non pur io qui piango bolognese; anzi n’è questo loco tanto pieno, che tante lingue non son ora apprese a dicer ‘sipa’ tra Sàvena e Reno; e se di ciò vuoi fede o testimonio, rècati a mente il nostro avaro seno». Così parlando il percosse un demonio de la sua scurïada, e disse: «Via, ruffian! qui non son femmine da conio». I’ mi raggiunsi con la scorta mia; poscia con pochi passi divenimmo là ’v’ uno scoglio de la ripa uscia. Assai leggeramente quel salimmo; e vòlti a destra su per la sua scheggia, da quelle cerchie etterne ci partimmo. Quando noi fummo là dov’ el vaneggia di sotto per dar passo a li sferzati, lo duca disse: «Attienti, e fa che feggia lo viso in te di quest’ altri mal nati, ai quali ancor non vedesti la faccia però che son con noi insieme andati». Del vecchio ponte guardavam la traccia che venìa verso noi da l’altra banda, e che la ferza similmente scaccia. E ’l buon maestro, sanza mia dimanda, mi disse: «Guarda quel grande che vene, e per dolor non par lagrime spanda: quanto aspetto reale ancor ritene! Quelli è Iasón, che per cuore e per senno li Colchi del monton privati féne. Ello passò per l’isola di Lenno poi che l’ardite femmine spietate tutti li maschi loro a morte dienno. Ivi con segni e con parole ornate Isifile ingannò, la giovinetta che prima avea tutte l’altre ingannate. Lasciolla quivi, gravida, soletta; tal colpa a tal martiro lui condanna; e anche di Medea si fa vendetta. Con lui sen va chi da tal parte inganna; e questo basti de la prima valle sapere e di color che ’n sé assanna». Già eravam là ’ve lo stretto calle con l’argine secondo s’incrocicchia, e fa di quello ad un altr’ arco spalle. Quindi sentimmo gente che si nicchia ne l’altra bolgia e che col muso scuffa, e sé medesma con le palme picchia. Le ripe eran grommate d’una muffa, per l’alito di giù che vi s’appasta, che con li occhi e col naso facea zuffa. Lo fondo è cupo sì, che non ci basta loco a veder sanza montare al dosso de l’arco, ove lo scoglio più sovrasta. Quivi venimmo; e quindi giù nel fosso vidi gente attuffata in uno sterco che da li uman privadi parea mosso. E mentre ch’io là giù con l’occhio cerco, vidi un col capo sì di merda lordo, che non parëa s’era laico o cherco. Quei mi sgridò: «Perché se’ tu sì gordo di riguardar più me che li altri brutti?». E io a lui: «Perché, se ben ricordo, già t’ho veduto coi capelli asciutti, e se’ Alessio Interminei da Lucca: però t’adocchio più che li altri tutti». Ed elli allor, battendosi la zucca: «Qua giù m’hanno sommerso le lusinghe ond’ io non ebbi mai la lingua stucca». Appresso ciò lo duca «Fa che pinghe», mi disse, «il viso un poco più avante, sì che la faccia ben con l’occhio attinghe di quella sozza e scapigliata fante che là si graffia con l’unghie merdose, e or s’accoscia e ora è in piedi stante. Taïde è, la puttana che rispuose al drudo suo quando disse “Ho io grazie grandi apo te?”: “Anzi maravigliose!”. E quinci sian le nostre viste sazie». Inferno · Canto XIX O Simon mago, o miseri seguaci che le cose di Dio, che di bontate deon essere spose, e voi rapaci per oro e per argento avolterate, or convien che per voi suoni la tromba, però che ne la terza bolgia state. Già eravamo, a la seguente tomba, montati de lo scoglio in quella parte ch’a punto sovra mezzo ’l fosso piomba. O somma sapïenza, quanta è l’arte che mostri in cielo, in terra e nel mal mondo, e quanto giusto tua virtù comparte! Io vidi per le coste e per lo fondo piena la pietra livida di fóri, d’un largo tutti e ciascun era tondo. Non mi parean men ampi né maggiori che que’ che son nel mio bel San Giovanni, fatti per loco d’i battezzatori; l’un de li quali, ancor non è molt’ anni, rupp’ io per un che dentro v’annegava: e questo sia suggel ch’ogn’ omo sganni. Fuor de la bocca a ciascun soperchiava d’un peccator li piedi e de le gambe infino al grosso, e l’altro dentro stava. Le piante erano a tutti accese intrambe; per che sì forte guizzavan le giunte, che spezzate averien ritorte e strambe. Qual suole il fiammeggiar de le cose unte muoversi pur su per la strema buccia, tal era lì dai calcagni a le punte. «Chi è colui, maestro, che si cruccia guizzando più che li altri suoi consorti», diss’ io, «e cui più roggia fiamma succia?». Ed elli a me: «Se tu vuo’ ch’i’ ti porti là giù per quella ripa che più giace, da lui saprai di sé e de’ suoi torti». E io: «Tanto m’è bel, quanto a te piace: tu se’ segnore, e sai ch’i’ non mi parto dal tuo volere, e sai quel che si tace». Allor venimmo in su l’argine quarto; volgemmo e discendemmo a mano stanca là giù nel fondo foracchiato e arto. Lo buon maestro ancor de la sua anca non mi dipuose, sì mi giunse al rotto di quel che si piangeva con la zanca. «O qual che se’ che ’l di sù tien di sotto, anima trista come pal commessa», comincia’ io a dir, «se puoi, fa motto». Io stava come ’l frate che confessa lo perfido assessin, che, poi ch’è fitto, richiama lui per che la morte cessa. Ed el gridò: «Se’ tu già costì ritto, se’ tu già costì ritto, Bonifazio? Di parecchi anni mi mentì lo scritto. Se’ tu sì tosto di quell’ aver sazio per lo qual non temesti tòrre a ’nganno la bella donna, e poi di farne strazio?». Tal mi fec’ io, quai son color che stanno, per non intender ciò ch’è lor risposto, quasi scornati, e risponder non sanno. Allor Virgilio disse: «Dilli tosto: “Non son colui, non son colui che credi”»; e io rispuosi come a me fu imposto. Per che lo spirto tutti storse i piedi; poi, sospirando e con voce di pianto, mi disse: «Dunque che a me richiedi? Se di saper ch’i’ sia ti cal cotanto, che tu abbi però la ripa corsa, sappi ch’i’ fui vestito del gran manto; e veramente fui figliuol de l’orsa, cupido sì per avanzar li orsatti, che sù l’avere e qui me misi in borsa. Di sotto al capo mio son li altri tratti che precedetter me simoneggiando, per le fessure de la pietra piatti. Là giù cascherò io altresì quando verrà colui ch’i’ credea che tu fossi, allor ch’i’ feci ’l sùbito dimando. Ma più è ’l tempo già che i piè mi cossi e ch’i’ son stato così sottosopra, ch’el non starà piantato coi piè rossi: ché dopo lui verrà di più laida opra, di ver’ ponente, un pastor sanza legge, tal che convien che lui e me ricuopra. Nuovo Iasón sarà, di cui si legge ne’ Maccabei; e come a quel fu molle suo re, così fia lui chi Francia regge». Io non so s’i’ mi fui qui troppo folle, ch’i’ pur rispuosi lui a questo metro: «Deh, or mi dì: quanto tesoro volle Nostro Segnore in prima da san Pietro ch’ei ponesse le chiavi in sua balìa? Certo non chiese se non “Viemmi retro”. Né Pier né li altri tolsero a Matia oro od argento, quando fu sortito al loco che perdé l’anima ria. Però ti sta, ché tu se’ ben punito; e guarda ben la mal tolta moneta ch’esser ti fece contra Carlo ardito. E se non fosse ch’ancor lo mi vieta la reverenza de le somme chiavi che tu tenesti ne la vita lieta, io userei parole ancor più gravi; ché la vostra avarizia il mondo attrista, calcando i buoni e sollevando i pravi. Di voi pastor s’accorse il Vangelista, quando colei che siede sopra l’acque puttaneggiar coi regi a lui fu vista; quella che con le sette teste nacque, e da le diece corna ebbe argomento, fin che virtute al suo marito piacque. Fatto v’avete dio d’oro e d’argento; e che altro è da voi a l’idolatre, se non ch’elli uno, e voi ne orate cento? Ahi, Costantin, di quanto mal fu matre, non la tua conversion, ma quella dote che da te prese il primo ricco patre!». E mentr’ io li cantava cotai note, o ira o coscïenza che ’l mordesse, forte spingava con ambo le piote. I’ credo ben ch’al mio duca piacesse, con sì contenta labbia sempre attese lo suon de le parole vere espresse. Però con ambo le braccia mi prese; e poi che tutto su mi s’ebbe al petto, rimontò per la via onde discese. Né si stancò d’avermi a sé distretto, sì men portò sovra ’l colmo de l’arco che dal quarto al quinto argine è tragetto. Quivi soavemente spuose il carco, soave per lo scoglio sconcio ed erto che sarebbe a le capre duro varco. Indi un altro vallon mi fu scoperto. Inferno · Canto XX Di nova pena mi conven far versi e dar matera al ventesimo canto de la prima canzon, ch’è d’i sommersi. Io era già disposto tutto quanto a riguardar ne lo scoperto fondo, che si bagnava d’angoscioso pianto; e vidi gente per lo vallon tondo venir, tacendo e lagrimando, al passo che fanno le letane in questo mondo. Come ’l viso mi scese in lor più basso, mirabilmente apparve esser travolto ciascun tra ’l mento e ’l principio del casso, ché da le reni era tornato ’l volto, e in dietro venir li convenia, perché ’l veder dinanzi era lor tolto. Forse per forza già di parlasia si travolse così alcun del tutto; ma io nol vidi, né credo che sia. Se Dio ti lasci, lettor, prender frutto di tua lezione, or pensa per te stesso com’ io potea tener lo viso asciutto, quando la nostra imagine di presso vidi sì torta, che ’l pianto de li occhi le natiche bagnava per lo fesso. Certo io piangea, poggiato a un de’ rocchi del duro scoglio, sì che la mia scorta mi disse: «Ancor se’ tu de li altri sciocchi? Qui vive la pietà quand’ è ben morta; chi è più scellerato che colui che al giudicio divin passion comporta? Drizza la testa, drizza, e vedi a cui s’aperse a li occhi d’i Teban la terra; per ch’ei gridavan tutti: “Dove rui, Anfïarao? perché lasci la guerra?”. E non restò di ruinare a valle fino a Minòs che ciascheduno afferra. Mira c’ha fatto petto de le spalle; perché volle veder troppo davante, di retro guarda e fa retroso calle. Vedi Tiresia, che mutò sembiante quando di maschio femmina divenne, cangiandosi le membra tutte quante; e prima, poi, ribatter li convenne li duo serpenti avvolti, con la verga, che rïavesse le maschili penne. Aronta è quel ch’al ventre li s’atterga, che ne’ monti di Luni, dove ronca lo Carrarese che di sotto alberga, ebbe tra ’ bianchi marmi la spelonca per sua dimora; onde a guardar le stelle e ’l mar non li era la veduta tronca. E quella che ricuopre le mammelle, che tu non vedi, con le trecce sciolte, e ha di là ogne pilosa pelle, Manto fu, che cercò per terre molte; poscia si puose là dove nacqu’ io; onde un poco mi piace che m’ascolte. Poscia che ’l padre suo di vita uscìo e venne serva la città di Baco, questa gran tempo per lo mondo gio. Suso in Italia bella giace un laco, a piè de l’Alpe che serra Lamagna sovra Tiralli, c’ha nome Benaco. Per mille fonti, credo, e più si bagna tra Garda e Val Camonica e Pennino de l’acqua che nel detto laco stagna. Loco è nel mezzo là dove ’l trentino pastore e quel di Brescia e ’l veronese segnar poria, s’e’ fesse quel cammino. Siede Peschiera, bello e forte arnese da fronteggiar Bresciani e Bergamaschi, ove la riva ’ntorno più discese. Ivi convien che tutto quanto caschi ciò che ’n grembo a Benaco star non può, e fassi fiume giù per verdi paschi. Tosto che l’acqua a correr mette co, non più Benaco, ma Mencio si chiama fino a Governol, dove cade in Po. Non molto ha corso, ch’el trova una lama, ne la qual si distende e la ’mpaluda; e suol di state talor essere grama. Quindi passando la vergine cruda vide terra, nel mezzo del pantano, sanza coltura e d’abitanti nuda. Lì, per fuggire ogne consorzio umano, ristette con suoi servi a far sue arti, e visse, e vi lasciò suo corpo vano. Li uomini poi che ’ntorno erano sparti s’accolsero a quel loco, ch’era forte per lo pantan ch’avea da tutte parti. Fer la città sovra quell’ ossa morte; e per colei che ’l loco prima elesse, Mantüa l’appellar sanz’ altra sorte. Già fuor le genti sue dentro più spesse, prima che la mattia da Casalodi da Pinamonte inganno ricevesse. Però t’assenno che, se tu mai odi originar la mia terra altrimenti, la verità nulla menzogna frodi». E io: «Maestro, i tuoi ragionamenti mi son sì certi e prendon sì mia fede, che li altri mi sarien carboni spenti. Ma dimmi, de la gente che procede, se tu ne vedi alcun degno di nota; ché solo a ciò la mia mente rifiede». Allor mi disse: «Quel che da la gota porge la barba in su le spalle brune, fu—quando Grecia fu di maschi vòta, sì ch’a pena rimaser per le cune— augure, e diede ’l punto con Calcanta in Aulide a tagliar la prima fune. Euripilo ebbe nome, e così ’l canta l’alta mia tragedìa in alcun loco: ben lo sai tu che la sai tutta quanta. Quell’ altro che ne’ fianchi è così poco, Michele Scotto fu, che veramente de le magiche frode seppe ’l gioco. Vedi Guido Bonatti; vedi Asdente, ch’avere inteso al cuoio e a lo spago ora vorrebbe, ma tardi si pente. Vedi le triste che lasciaron l’ago, la spuola e ’l fuso, e fecersi ’ndivine; fecer malie con erbe e con imago. Ma vienne omai, ché già tiene ’l confine d’amendue li emisperi e tocca l’onda sotto Sobilia Caino e le spine; e già iernotte fu la luna tonda: ben ten de’ ricordar, ché non ti nocque alcuna volta per la selva fonda». Sì mi parlava, e andavamo introcque. Inferno · Canto XXI Così di ponte in ponte, altro parlando che la mia comedìa cantar non cura, venimmo; e tenavamo ’l colmo, quando restammo per veder l’altra fessura di Malebolge e li altri pianti vani; e vidila mirabilmente oscura. Quale ne l’arzanà de’ Viniziani bolle l’inverno la tenace pece a rimpalmare i legni lor non sani, ché navicar non ponno—in quella vece chi fa suo legno novo e chi ristoppa le coste a quel che più vïaggi fece; chi ribatte da proda e chi da poppa; altri fa remi e altri volge sarte; chi terzeruolo e artimon rintoppa—: tal, non per foco ma per divin’ arte, bollia là giuso una pegola spessa, che ’nviscava la ripa d’ogne parte. I’ vedea lei, ma non vedëa in essa mai che le bolle che ’l bollor levava, e gonfiar tutta, e riseder compressa. Mentr’ io là giù fisamente mirava, lo duca mio, dicendo «Guarda, guarda!», mi trasse a sé del loco dov’ io stava. Allor mi volsi come l’uom cui tarda di veder quel che li convien fuggire e cui paura sùbita sgagliarda, che, per veder, non indugia ’l partire: e vidi dietro a noi un diavol nero correndo su per lo scoglio venire. Ahi quant’ elli era ne l’aspetto fero! e quanto mi parea ne l’atto acerbo, con l’ali aperte e sovra i piè leggero! L’omero suo, ch’era aguto e superbo, carcava un peccator con ambo l’anche, e quei tenea de’ piè ghermito ’l nerbo. Del nostro ponte disse: «O Malebranche, ecco un de li anzïan di Santa Zita! Mettetel sotto, ch’i’ torno per anche a quella terra, che n’è ben fornita: ogn’ uom v’è barattier, fuor che Bonturo; del no, per li denar, vi si fa ita». Là giù ’l buttò, e per lo scoglio duro si volse; e mai non fu mastino sciolto con tanta fretta a seguitar lo furo. Quel s’attuffò, e tornò sù convolto; ma i demon che del ponte avean coperchio, gridar: «Qui non ha loco il Santo Volto! qui si nuota altrimenti che nel Serchio! Però, se tu non vuo’ di nostri graffi, non far sopra la pegola soverchio». Poi l’addentar con più di cento raffi, disser: «Coverto convien che qui balli, sì che, se puoi, nascosamente accaffi». Non altrimenti i cuoci a’ lor vassalli fanno attuffare in mezzo la caldaia la carne con li uncin, perché non galli. Lo buon maestro «Acciò che non si paia che tu ci sia», mi disse, «giù t’acquatta dopo uno scheggio, ch’alcun schermo t’aia; e per nulla offension che mi sia fatta, non temer tu, ch’i’ ho le cose conte, perch’ altra volta fui a tal baratta». Poscia passò di là dal co del ponte; e com’ el giunse in su la ripa sesta, mestier li fu d’aver sicura fronte. Con quel furore e con quella tempesta ch’escono i cani a dosso al poverello che di sùbito chiede ove s’arresta, usciron quei di sotto al ponticello, e volser contra lui tutt’ i runcigli; ma el gridò: «Nessun di voi sia fello! Innanzi che l’uncin vostro mi pigli, traggasi avante l’un di voi che m’oda, e poi d’arruncigliarmi si consigli». Tutti gridaron: «Vada Malacoda!»; per ch’un si mosse—e li altri stetter fermi— e venne a lui dicendo: «Che li approda?». «Credi tu, Malacoda, qui vedermi esser venuto», disse ’l mio maestro, «sicuro già da tutti vostri schermi, sanza voler divino e fato destro? Lascian’ andar, ché nel cielo è voluto ch’i’ mostri altrui questo cammin silvestro». Allor li fu l’orgoglio sì caduto, ch’e’ si lasciò cascar l’uncino a’ piedi, e disse a li altri: «Omai non sia feruto». E ’l duca mio a me: «O tu che siedi tra li scheggion del ponte quatto quatto, sicuramente omai a me ti riedi». Per ch’io mi mossi e a lui venni ratto; e i diavoli si fecer tutti avanti, sì ch’io temetti ch’ei tenesser patto; così vid’ ïo già temer li fanti ch’uscivan patteggiati di Caprona, veggendo sé tra nemici cotanti. I’ m’accostai con tutta la persona lungo ’l mio duca, e non torceva li occhi da la sembianza lor ch’era non buona. Ei chinavan li raffi e «Vuo’ che ’l tocchi», diceva l’un con l’altro, «in sul groppone?». E rispondien: «Sì, fa che gliel’ accocchi». Ma quel demonio che tenea sermone col duca mio, si volse tutto presto e disse: «Posa, posa, Scarmiglione!». Poi disse a noi: «Più oltre andar per questo iscoglio non si può, però che giace tutto spezzato al fondo l’arco sesto. E se l’andare avante pur vi piace, andatevene su per questa grotta; presso è un altro scoglio che via face. Ier, più oltre cinqu’ ore che quest’ otta, mille dugento con sessanta sei anni compié che qui la via fu rotta. Io mando verso là di questi miei a riguardar s’alcun se ne sciorina; gite con lor, che non saranno rei». «Tra’ti avante, Alichino, e Calcabrina», cominciò elli a dire, «e tu, Cagnazzo; e Barbariccia guidi la decina. Libicocco vegn’ oltre e Draghignazzo, Cirïatto sannuto e Graffiacane e Farfarello e Rubicante pazzo. Cercate ’ntorno le boglienti pane; costor sian salvi infino a l’altro scheggio che tutto intero va sovra le tane». «Omè, maestro, che è quel ch’i’ veggio?», diss’ io, «deh, sanza scorta andianci soli, se tu sa’ ir; ch’i’ per me non la cheggio. Se tu se’ sì accorto come suoli, non vedi tu ch’e’ digrignan li denti e con le ciglia ne minaccian duoli?». Ed elli a me: «Non vo’ che tu paventi; lasciali digrignar pur a lor senno, ch’e’ fanno ciò per li lessi dolenti». Per l’argine sinistro volta dienno; ma prima avea ciascun la lingua stretta coi denti, verso lor duca, per cenno; ed elli avea del cul fatto trombetta. Inferno · Canto XXII Io vidi già cavalier muover campo, e cominciare stormo e far lor mostra, e talvolta partir per loro scampo; corridor vidi per la terra vostra, o Aretini, e vidi gir gualdane, fedir torneamenti e correr giostra; quando con trombe, e quando con campane, con tamburi e con cenni di castella, e con cose nostrali e con istrane; né già con sì diversa cennamella cavalier vidi muover né pedoni, né nave a segno di terra o di stella. Noi andavam con li diece demoni. Ahi fiera compagnia! ma ne la chiesa coi santi, e in taverna coi ghiottoni. Pur a la pegola era la mia ’ntesa, per veder de la bolgia ogne contegno e de la gente ch’entro v’era incesa. Come i dalfini, quando fanno segno a’ marinar con l’arco de la schiena che s’argomentin di campar lor legno, talor così, ad alleggiar la pena, mostrav’ alcun de’ peccatori ’l dosso e nascondea in men che non balena. E come a l’orlo de l’acqua d’un fosso stanno i ranocchi pur col muso fuori, sì che celano i piedi e l’altro grosso, sì stavan d’ogne parte i peccatori; ma come s’appressava Barbariccia, così si ritraén sotto i bollori. I’ vidi, e anco il cor me n’accapriccia, uno aspettar così, com’ elli ’ncontra ch’una rana rimane e l’altra spiccia; e Graffiacan, che li era più di contra, li arruncigliò le ’mpegolate chiome e trassel sù, che mi parve una lontra. I’ sapea già di tutti quanti ’l nome, sì li notai quando fuorono eletti, e poi ch’e’ si chiamaro, attesi come. «O Rubicante, fa che tu li metti li unghioni a dosso, sì che tu lo scuoi!», gridavan tutti insieme i maladetti. E io: «Maestro mio, fa, se tu puoi, che tu sappi chi è lo sciagurato venuto a man de li avversari suoi». Lo duca mio li s’accostò allato; domandollo ond’ ei fosse, e quei rispuose: «I’ fui del regno di Navarra nato. Mia madre a servo d’un segnor mi puose, che m’avea generato d’un ribaldo, distruggitor di sé e di sue cose. Poi fui famiglia del buon re Tebaldo; quivi mi misi a far baratteria, di ch’io rendo ragione in questo caldo». E Cirïatto, a cui di bocca uscia d’ogne parte una sanna come a porco, li fé sentir come l’una sdruscia. Tra male gatte era venuto ’l sorco; ma Barbariccia il chiuse con le braccia e disse: «State in là, mentr’ io lo ’nforco». E al maestro mio volse la faccia; «Domanda», disse, «ancor, se più disii saper da lui, prima ch’altri ’l disfaccia». Lo duca dunque: «Or dì: de li altri rii conosci tu alcun che sia latino sotto la pece?». E quelli: «I’ mi partii, poco è, da un che fu di là vicino. Così foss’ io ancor con lui coperto, ch’i’ non temerei unghia né uncino!». E Libicocco «Troppo avem sofferto», disse; e preseli ’l braccio col runciglio, sì che, stracciando, ne portò un lacerto. Draghignazzo anco i volle dar di piglio giuso a le gambe; onde ’l decurio loro si volse intorno intorno con mal piglio. Quand’ elli un poco rappaciati fuoro, a lui, ch’ancor mirava sua ferita, domandò ’l duca mio sanza dimoro: «Chi fu colui da cui mala partita di’ che facesti per venire a proda?». Ed ei rispuose: «Fu frate Gomita, quel di Gallura, vasel d’ogne froda, ch’ebbe i nemici di suo donno in mano, e fé sì lor, che ciascun se ne loda. Danar si tolse e lasciolli di piano, sì com’ e’ dice; e ne li altri offici anche barattier fu non picciol, ma sovrano. Usa con esso donno Michel Zanche di Logodoro; e a dir di Sardigna le lingue lor non si sentono stanche. Omè, vedete l’altro che digrigna; i’ direi anche, ma i’ temo ch’ello non s’apparecchi a grattarmi la tigna». E ’l gran proposto, vòlto a Farfarello che stralunava li occhi per fedire, disse: «Fatti ’n costà, malvagio uccello!». «Se voi volete vedere o udire», ricominciò lo spaürato appresso, «Toschi o Lombardi, io ne farò venire; ma stieno i Malebranche un poco in cesso, sì ch’ei non teman de le lor vendette; e io, seggendo in questo loco stesso, per un ch’io son, ne farò venir sette quand’ io suffolerò, com’ è nostro uso di fare allor che fori alcun si mette». Cagnazzo a cotal motto levò ’l muso, crollando ’l capo, e disse: «Odi malizia ch’elli ha pensata per gittarsi giuso!». Ond’ ei, ch’avea lacciuoli a gran divizia, rispuose: «Malizioso son io troppo, quand’ io procuro a’ mia maggior trestizia». Alichin non si tenne e, di rintoppo a li altri, disse a lui: «Se tu ti cali, io non ti verrò dietro di gualoppo, ma batterò sovra la pece l’ali. Lascisi ’l collo, e sia la ripa scudo, a veder se tu sol più di noi vali». O tu che leggi, udirai nuovo ludo: ciascun da l’altra costa li occhi volse, quel prima, ch’a ciò fare era più crudo. Lo Navarrese ben suo tempo colse; fermò le piante a terra, e in un punto saltò e dal proposto lor si sciolse. Di che ciascun di colpa fu compunto, ma quei più che cagion fu del difetto; però si mosse e gridò: «Tu se’ giunto!». Ma poco i valse: ché l’ali al sospetto non potero avanzar; quelli andò sotto, e quei drizzò volando suso il petto: non altrimenti l’anitra di botto, quando ’l falcon s’appressa, giù s’attuffa, ed ei ritorna sù crucciato e rotto. Irato Calcabrina de la buffa, volando dietro li tenne, invaghito che quei campasse per aver la zuffa; e come ’l barattier fu disparito, così volse li artigli al suo compagno, e fu con lui sopra ’l fosso ghermito. Ma l’altro fu bene sparvier grifagno ad artigliar ben lui, e amendue cadder nel mezzo del bogliente stagno. Lo caldo sghermitor sùbito fue; ma però di levarsi era neente, sì avieno inviscate l’ali sue. Barbariccia, con li altri suoi dolente, quattro ne fé volar da l’altra costa con tutt’ i raffi, e assai prestamente di qua, di là discesero a la posta; porser li uncini verso li ’mpaniati, ch’eran già cotti dentro da la crosta. E noi lasciammo lor così ’mpacciati. Inferno · Canto XXIII Taciti, soli, sanza compagnia n’andavam l’un dinanzi e l’altro dopo, come frati minor vanno per via. Vòlt’ era in su la favola d’Isopo lo mio pensier per la presente rissa, dov’ el parlò de la rana e del topo; ché più non si pareggia ‘mo’ e ‘issa’ che l’un con l’altro fa, se ben s’accoppia principio e fine con la mente fissa. E come l’un pensier de l’altro scoppia, così nacque di quello un altro poi, che la prima paura mi fé doppia. Io pensava così: ‘Questi per noi sono scherniti con danno e con beffa sì fatta, ch’assai credo che lor nòi. Se l’ira sovra ’l mal voler s’aggueffa, ei ne verranno dietro più crudeli che ’l cane a quella lievre ch’elli acceffa’. Già mi sentia tutti arricciar li peli de la paura e stava in dietro intento, quand’ io dissi: «Maestro, se non celi te e me tostamente, i’ ho pavento d’i Malebranche. Noi li avem già dietro; io li ’magino sì, che già li sento». E quei: «S’i’ fossi di piombato vetro, l’imagine di fuor tua non trarrei più tosto a me, che quella dentro ’mpetro. Pur mo venieno i tuo’ pensier tra ’ miei, con simile atto e con simile faccia, sì che d’intrambi un sol consiglio fei. S’elli è che sì la destra costa giaccia, che noi possiam ne l’altra bolgia scendere, noi fuggirem l’imaginata caccia». Già non compié di tal consiglio rendere, ch’io li vidi venir con l’ali tese non molto lungi, per volerne prendere. Lo duca mio di sùbito mi prese, come la madre ch’al romore è desta e vede presso a sé le fiamme accese, che prende il figlio e fugge e non s’arresta, avendo più di lui che di sé cura, tanto che solo una camiscia vesta; e giù dal collo de la ripa dura supin si diede a la pendente roccia, che l’un de’ lati a l’altra bolgia tura. Non corse mai sì tosto acqua per doccia a volger ruota di molin terragno, quand’ ella più verso le pale approccia, come ’l maestro mio per quel vivagno, portandosene me sovra ’l suo petto, come suo figlio, non come compagno. A pena fuoro i piè suoi giunti al letto del fondo giù, ch’e’ furon in sul colle sovresso noi; ma non lì era sospetto: ché l’alta provedenza che lor volle porre ministri de la fossa quinta, poder di partirs’ indi a tutti tolle. Là giù trovammo una gente dipinta che giva intorno assai con lenti passi, piangendo e nel sembiante stanca e vinta. Elli avean cappe con cappucci bassi dinanzi a li occhi, fatte de la taglia che in Clugnì per li monaci fassi. Di fuor dorate son, sì ch’elli abbaglia; ma dentro tutte piombo, e gravi tanto, che Federigo le mettea di paglia. Oh in etterno faticoso manto! Noi ci volgemmo ancor pur a man manca con loro insieme, intenti al tristo pianto; ma per lo peso quella gente stanca venìa sì pian, che noi eravam nuovi di compagnia ad ogne mover d’anca. Per ch’io al duca mio: «Fa che tu trovi alcun ch’al fatto o al nome si conosca, e li occhi, sì andando, intorno movi». E un che ’ntese la parola tosca, di retro a noi gridò: «Tenete i piedi, voi che correte sì per l’aura fosca! Forse ch’avrai da me quel che tu chiedi». Onde ’l duca si volse e disse: «Aspetta, e poi secondo il suo passo procedi». Ristetti, e vidi due mostrar gran fretta de l’animo, col viso, d’esser meco; ma tardavali ’l carco e la via stretta. Quando fuor giunti, assai con l’occhio bieco mi rimiraron sanza far parola; poi si volsero in sé, e dicean seco: «Costui par vivo a l’atto de la gola; e s’e’ son morti, per qual privilegio vanno scoperti de la grave stola?». Poi disser me: «O Tosco, ch’al collegio de l’ipocriti tristi se’ venuto, dir chi tu se’ non avere in dispregio». E io a loro: «I’ fui nato e cresciuto sovra ’l bel fiume d’Arno a la gran villa, e son col corpo ch’i’ ho sempre avuto. Ma voi chi siete, a cui tanto distilla quant’ i’ veggio dolor giù per le guance? e che pena è in voi che sì sfavilla?». E l’un rispuose a me: «Le cappe rance son di piombo sì grosse, che li pesi fan così cigolar le lor bilance. Frati godenti fummo, e bolognesi; io Catalano e questi Loderingo nomati, e da tua terra insieme presi come suole esser tolto un uom solingo, per conservar sua pace; e fummo tali, ch’ancor si pare intorno dal Gardingo». Io cominciai: «O frati, i vostri mali . . . »; ma più non dissi, ch’a l’occhio mi corse un, crucifisso in terra con tre pali. Quando mi vide, tutto si distorse, soffiando ne la barba con sospiri; e ’l frate Catalan, ch’a ciò s’accorse, mi disse: «Quel confitto che tu miri, consigliò i Farisei che convenia porre un uom per lo popolo a’ martìri. Attraversato è, nudo, ne la via, come tu vedi, ed è mestier ch’el senta qualunque passa, come pesa, pria. E a tal modo il socero si stenta in questa fossa, e li altri dal concilio che fu per li Giudei mala sementa». Allor vid’ io maravigliar Virgilio sovra colui ch’era disteso in croce tanto vilmente ne l’etterno essilio. Poscia drizzò al frate cotal voce: «Non vi dispiaccia, se vi lece, dirci s’a la man destra giace alcuna foce onde noi amendue possiamo uscirci, sanza costrigner de li angeli neri che vegnan d’esto fondo a dipartirci». Rispuose adunque: «Più che tu non speri s’appressa un sasso che da la gran cerchia si move e varca tutt’ i vallon feri, salvo che ’n questo è rotto e nol coperchia; montar potrete su per la ruina, che giace in costa e nel fondo soperchia». Lo duca stette un poco a testa china; poi disse: «Mal contava la bisogna colui che i peccator di qua uncina». E ’l frate: «Io udi’ già dire a Bologna del diavol vizi assai, tra ’ quali udi’ ch’elli è bugiardo, e padre di menzogna». Appresso il duca a gran passi sen gì, turbato un poco d’ira nel sembiante; ond’ io da li ’ncarcati mi parti’ dietro a le poste de le care piante. Inferno · Canto XXIV In quella parte del giovanetto anno che ’l sole i crin sotto l’Aquario tempra e già le notti al mezzo dì sen vanno, quando la brina in su la terra assempra l’imagine di sua sorella bianca, ma poco dura a la sua penna tempra, lo villanello a cui la roba manca, si leva, e guarda, e vede la campagna biancheggiar tutta; ond’ ei si batte l’anca, ritorna in casa, e qua e là si lagna, come ’l tapin che non sa che si faccia; poi riede, e la speranza ringavagna, veggendo ’l mondo aver cangiata faccia in poco d’ora, e prende suo vincastro e fuor le pecorelle a pascer caccia. Così mi fece sbigottir lo mastro quand’ io li vidi sì turbar la fronte, e così tosto al mal giunse lo ’mpiastro; ché, come noi venimmo al guasto ponte, lo duca a me si volse con quel piglio dolce ch’io vidi prima a piè del monte. Le braccia aperse, dopo alcun consiglio eletto seco riguardando prima ben la ruina, e diedemi di piglio. E come quei ch’adopera ed estima, che sempre par che ’nnanzi si proveggia, così, levando me sù ver’ la cima d’un ronchione, avvisava un’altra scheggia dicendo: «Sovra quella poi t’aggrappa; ma tenta pria s’è tal ch’ella ti reggia». Non era via da vestito di cappa, ché noi a pena, ei lieve e io sospinto, potavam sù montar di chiappa in chiappa. E se non fosse che da quel precinto più che da l’altro era la costa corta, non so di lui, ma io sarei ben vinto. Ma perché Malebolge inver’ la porta del bassissimo pozzo tutta pende, lo sito di ciascuna valle porta che l’una costa surge e l’altra scende; noi pur venimmo al fine in su la punta onde l’ultima pietra si scoscende. La lena m’era del polmon sì munta quand’ io fui sù, ch’i’ non potea più oltre, anzi m’assisi ne la prima giunta. «Omai convien che tu così ti spoltre», disse ’l maestro; «ché, seggendo in piuma, in fama non si vien, né sotto coltre; sanza la qual chi sua vita consuma, cotal vestigio in terra di sé lascia, qual fummo in aere e in acqua la schiuma. E però leva sù; vinci l’ambascia con l’animo che vince ogne battaglia, se col suo grave corpo non s’accascia. Più lunga scala convien che si saglia; non basta da costoro esser partito. Se tu mi ’ntendi, or fa sì che ti vaglia». Leva’mi allor, mostrandomi fornito meglio di lena ch’i’ non mi sentia, e dissi: «Va, ch’i’ son forte e ardito». Su per lo scoglio prendemmo la via, ch’era ronchioso, stretto e malagevole, ed erto più assai che quel di pria. Parlando andava per non parer fievole; onde una voce uscì de l’altro fosso, a parole formar disconvenevole. Non so che disse, ancor che sovra ’l dosso fossi de l’arco già che varca quivi; ma chi parlava ad ire parea mosso. Io era vòlto in giù, ma li occhi vivi non poteano ire al fondo per lo scuro; per ch’io: «Maestro, fa che tu arrivi da l’altro cinghio e dismontiam lo muro; ché, com’ i’ odo quinci e non intendo, così giù veggio e neente affiguro». «Altra risposta», disse, «non ti rendo se non lo far; ché la dimanda onesta si de’ seguir con l’opera tacendo». Noi discendemmo il ponte da la testa dove s’aggiugne con l’ottava ripa, e poi mi fu la bolgia manifesta: e vidivi entro terribile stipa di serpenti, e di sì diversa mena che la memoria il sangue ancor mi scipa. Più non si vanti Libia con sua rena; ché se chelidri, iaculi e faree produce, e cencri con anfisibena, né tante pestilenzie né sì ree mostrò già mai con tutta l’Etïopia né con ciò che di sopra al Mar Rosso èe. Tra questa cruda e tristissima copia corrëan genti nude e spaventate, sanza sperar pertugio o elitropia: con serpi le man dietro avean legate; quelle ficcavan per le ren la coda e ’l capo, ed eran dinanzi aggroppate. Ed ecco a un ch’era da nostra proda, s’avventò un serpente che ’l trafisse là dove ’l collo a le spalle s’annoda. Né O sì tosto mai né I si scrisse, com’ el s’accese e arse, e cener tutto convenne che cascando divenisse; e poi che fu a terra sì distrutto, la polver si raccolse per sé stessa e ’n quel medesmo ritornò di butto. Così per li gran savi si confessa che la fenice more e poi rinasce, quando al cinquecentesimo anno appressa; erba né biado in sua vita non pasce, ma sol d’incenso lagrime e d’amomo, e nardo e mirra son l’ultime fasce. E qual è quel che cade, e non sa como, per forza di demon ch’a terra il tira, o d’altra oppilazion che lega l’omo, quando si leva, che ’ntorno si mira tutto smarrito de la grande angoscia ch’elli ha sofferta, e guardando sospira: tal era ’l peccator levato poscia. Oh potenza di Dio, quant’ è severa, che cotai colpi per vendetta croscia! Lo duca il domandò poi chi ello era; per ch’ei rispuose: «Io piovvi di Toscana, poco tempo è, in questa gola fiera. Vita bestial mi piacque e non umana, sì come a mul ch’i’ fui; son Vanni Fucci bestia, e Pistoia mi fu degna tana». E ïo al duca: «Dilli che non mucci, e domanda che colpa qua giù ’l pinse; ch’io ’l vidi uomo di sangue e di crucci». E ’l peccator, che ’ntese, non s’infinse, ma drizzò verso me l’animo e ’l volto, e di trista vergogna si dipinse; poi disse: «Più mi duol che tu m’hai colto ne la miseria dove tu mi vedi, che quando fui de l’altra vita tolto. Io non posso negar quel che tu chiedi; in giù son messo tanto perch’ io fui ladro a la sagrestia d’i belli arredi, e falsamente già fu apposto altrui. Ma perché di tal vista tu non godi, se mai sarai di fuor da’ luoghi bui, apri li orecchi al mio annunzio, e odi. Pistoia in pria d’i Neri si dimagra; poi Fiorenza rinova gente e modi. Tragge Marte vapor di Val di Magra ch’è di torbidi nuvoli involuto; e con tempesta impetüosa e agra sovra Campo Picen fia combattuto; ond’ ei repente spezzerà la nebbia, sì ch’ogne Bianco ne sarà feruto. E detto l’ho perché doler ti debbia!». Inferno · Canto XXV Al fine de le sue parole il ladro le mani alzò con amendue le fiche, gridando: «Togli, Dio, ch’a te le squadro!». Da indi in qua mi fuor le serpi amiche, perch’ una li s’avvolse allora al collo, come dicesse ‘Non vo’ che più diche’; e un’altra a le braccia, e rilegollo, ribadendo sé stessa sì dinanzi, che non potea con esse dare un crollo. Ahi Pistoia, Pistoia, ché non stanzi d’incenerarti sì che più non duri, poi che ’n mal fare il seme tuo avanzi? Per tutt’ i cerchi de lo ’nferno scuri non vidi spirto in Dio tanto superbo, non quel che cadde a Tebe giù da’ muri. El si fuggì che non parlò più verbo; e io vidi un centauro pien di rabbia venir chiamando: «Ov’ è, ov’ è l’acerbo?». Maremma non cred’ io che tante n’abbia, quante bisce elli avea su per la groppa infin ove comincia nostra labbia. Sovra le spalle, dietro da la coppa, con l’ali aperte li giacea un draco; e quello affuoca qualunque s’intoppa. Lo mio maestro disse: «Questi è Caco, che, sotto ’l sasso di monte Aventino, di sangue fece spesse volte laco. Non va co’ suoi fratei per un cammino, per lo furto che frodolente fece del grande armento ch’elli ebbe a vicino; onde cessar le sue opere biece sotto la mazza d’Ercule, che forse gliene diè cento, e non sentì le diece». Mentre che sì parlava, ed el trascorse, e tre spiriti venner sotto noi, de’ quai né io né ’l duca mio s’accorse, se non quando gridar: «Chi siete voi?»; per che nostra novella si ristette, e intendemmo pur ad essi poi. Io non li conoscea; ma ei seguette, come suol seguitar per alcun caso, che l’un nomar un altro convenette, dicendo: «Cianfa dove fia rimaso?»; per ch’io, acciò che ’l duca stesse attento, mi puosi ’l dito su dal mento al naso. Se tu se’ or, lettore, a creder lento ciò ch’io dirò, non sarà maraviglia, ché io che ’l vidi, a pena il mi consento. Com’ io tenea levate in lor le ciglia, e un serpente con sei piè si lancia dinanzi a l’uno, e tutto a lui s’appiglia. Co’ piè di mezzo li avvinse la pancia e con li anterïor le braccia prese; poi li addentò e l’una e l’altra guancia; li diretani a le cosce distese, e miseli la coda tra ’mbedue e dietro per le ren sù la ritese. Ellera abbarbicata mai non fue ad alber sì, come l’orribil fiera per l’altrui membra avviticchiò le sue. Poi s’appiccar, come di calda cera fossero stati, e mischiar lor colore, né l’un né l’altro già parea quel ch’era: come procede innanzi da l’ardore, per lo papiro suso, un color bruno che non è nero ancora e ’l bianco more. Li altri due ’l riguardavano, e ciascuno gridava: «Omè, Agnel, come ti muti! Vedi che già non se’ né due né uno». Già eran li due capi un divenuti, quando n’apparver due figure miste in una faccia, ov’ eran due perduti. Fersi le braccia due di quattro liste; le cosce con le gambe e ’l ventre e ’l casso divenner membra che non fuor mai viste. Ogne primaio aspetto ivi era casso: due e nessun l’imagine perversa parea; e tal sen gio con lento passo. Come ’l ramarro sotto la gran fersa dei dì canicular, cangiando sepe, folgore par se la via attraversa, sì pareva, venendo verso l’epe de li altri due, un serpentello acceso, livido e nero come gran di pepe; e quella parte onde prima è preso nostro alimento, a l’un di lor trafisse; poi cadde giuso innanzi lui disteso. Lo trafitto ’l mirò, ma nulla disse; anzi, co’ piè fermati, sbadigliava pur come sonno o febbre l’assalisse. Elli ’l serpente e quei lui riguardava; l’un per la piaga e l’altro per la bocca fummavan forte, e ’l fummo si scontrava. Taccia Lucano ormai là dov’ e’ tocca del misero Sabello e di Nasidio, e attenda a udir quel ch’or si scocca. Taccia di Cadmo e d’Aretusa Ovidio, ché se quello in serpente e quella in fonte converte poetando, io non lo ’nvidio; ché due nature mai a fronte a fronte non trasmutò sì ch’amendue le forme a cambiar lor matera fosser pronte. Insieme si rispuosero a tai norme, che ’l serpente la coda in forca fesse, e ’l feruto ristrinse insieme l’orme. Le gambe con le cosce seco stesse s’appiccar sì, che ’n poco la giuntura non facea segno alcun che si paresse. Togliea la coda fessa la figura che si perdeva là, e la sua pelle si facea molle, e quella di là dura. Io vidi intrar le braccia per l’ascelle, e i due piè de la fiera, ch’eran corti, tanto allungar quanto accorciavan quelle. Poscia li piè di rietro, insieme attorti, diventaron lo membro che l’uom cela, e ’l misero del suo n’avea due porti. Mentre che ’l fummo l’uno e l’altro vela di color novo, e genera ’l pel suso per l’una parte e da l’altra il dipela, l’un si levò e l’altro cadde giuso, non torcendo però le lucerne empie, sotto le quai ciascun cambiava muso. Quel ch’era dritto, il trasse ver’ le tempie, e di troppa matera ch’in là venne uscir li orecchi de le gote scempie; ciò che non corse in dietro e si ritenne di quel soverchio, fé naso a la faccia e le labbra ingrossò quanto convenne. Quel che giacëa, il muso innanzi caccia, e li orecchi ritira per la testa come face le corna la lumaccia; e la lingua, ch’avëa unita e presta prima a parlar, si fende, e la forcuta ne l’altro si richiude; e ’l fummo resta. L’anima ch’era fiera divenuta, suffolando si fugge per la valle, e l’altro dietro a lui parlando sputa. Poscia li volse le novelle spalle, e disse a l’altro: «I’ vo’ che Buoso corra, com’ ho fatt’ io, carpon per questo calle». Così vid’ io la settima zavorra mutare e trasmutare; e qui mi scusi la novità se fior la penna abborra. E avvegna che li occhi miei confusi fossero alquanto e l’animo smagato, non poter quei fuggirsi tanto chiusi, ch’i’ non scorgessi ben Puccio Sciancato; ed era quel che sol, di tre compagni che venner prima, non era mutato; l’altr’ era quel che tu, Gaville, piagni. Inferno · Canto XXVI Godi, Fiorenza, poi che se’ sì grande che per mare e per terra batti l’ali, e per lo ’nferno tuo nome si spande! Tra li ladron trovai cinque cotali tuoi cittadini onde mi ven vergogna, e tu in grande orranza non ne sali. Ma se presso al mattin del ver si sogna, tu sentirai, di qua da picciol tempo, di quel che Prato, non ch’altri, t’agogna. E se già fosse, non saria per tempo. Così foss’ ei, da che pur esser dee! ché più mi graverà, com’ più m’attempo. Noi ci partimmo, e su per le scalee che n’avea fatto iborni a scender pria, rimontò ’l duca mio e trasse mee; e proseguendo la solinga via, tra le schegge e tra ’ rocchi de lo scoglio lo piè sanza la man non si spedia. Allor mi dolsi, e ora mi ridoglio quando drizzo la mente a ciò ch’io vidi, e più lo ’ngegno affreno ch’i’ non soglio, perché non corra che virtù nol guidi; sì che, se stella bona o miglior cosa m’ha dato ’l ben, ch’io stessi nol m’invidi. Quante ’l villan ch’al poggio si riposa, nel tempo che colui che ’l mondo schiara la faccia sua a noi tien meno ascosa, come la mosca cede a la zanzara, vede lucciole giù per la vallea, forse colà dov’ e’ vendemmia e ara: di tante fiamme tutta risplendea l’ottava bolgia, sì com’ io m’accorsi tosto che fui là ’ve ’l fondo parea. E qual colui che si vengiò con li orsi vide ’l carro d’Elia al dipartire, quando i cavalli al cielo erti levorsi, che nol potea sì con li occhi seguire, ch’el vedesse altro che la fiamma sola, sì come nuvoletta, in sù salire: tal si move ciascuna per la gola del fosso, ché nessuna mostra ’l furto, e ogne fiamma un peccatore invola. Io stava sovra ’l ponte a veder surto, sì che s’io non avessi un ronchion preso, caduto sarei giù sanz’ esser urto. E ’l duca che mi vide tanto atteso, disse: «Dentro dai fuochi son li spirti; catun si fascia di quel ch’elli è inceso». «Maestro mio», rispuos’ io, «per udirti son io più certo; ma già m’era avviso che così fosse, e già voleva dirti: chi è ’n quel foco che vien sì diviso di sopra, che par surger de la pira dov’ Eteòcle col fratel fu miso?». Rispuose a me: «Là dentro si martira Ulisse e Dïomede, e così insieme a la vendetta vanno come a l’ira; e dentro da la lor fiamma si geme l’agguato del caval che fé la porta onde uscì de’ Romani il gentil seme. Piangevisi entro l’arte per che, morta, Deïdamìa ancor si duol d’Achille, e del Palladio pena vi si porta». «S’ei posson dentro da quelle faville parlar», diss’ io, «maestro, assai ten priego e ripriego, che ’l priego vaglia mille, che non mi facci de l’attender niego fin che la fiamma cornuta qua vegna; vedi che del disio ver’ lei mi piego!». Ed elli a me: «La tua preghiera è degna di molta loda, e io però l’accetto; ma fa che la tua lingua si sostegna. Lascia parlare a me, ch’i’ ho concetto ciò che tu vuoi; ch’ei sarebbero schivi, perch’ e’ fuor greci, forse del tuo detto». Poi che la fiamma fu venuta quivi dove parve al mio duca tempo e loco, in questa forma lui parlare audivi: «O voi che siete due dentro ad un foco, s’io meritai di voi mentre ch’io vissi, s’io meritai di voi assai o poco quando nel mondo li alti versi scrissi, non vi movete; ma l’un di voi dica dove, per lui, perduto a morir gissi». Lo maggior corno de la fiamma antica cominciò a crollarsi mormorando, pur come quella cui vento affatica; indi la cima qua e là menando, come fosse la lingua che parlasse, gittò voce di fuori e disse: «Quando mi diparti’ da Circe, che sottrasse me più d’un anno là presso a Gaeta, prima che sì Enëa la nomasse, né dolcezza di figlio, né la pieta del vecchio padre, né ’l debito amore lo qual dovea Penelopè far lieta, vincer potero dentro a me l’ardore ch’i’ ebbi a divenir del mondo esperto e de li vizi umani e del valore; ma misi me per l’alto mare aperto sol con un legno e con quella compagna picciola da la qual non fui diserto. L’un lito e l’altro vidi infin la Spagna, fin nel Morrocco, e l’isola d’i Sardi, e l’altre che quel mare intorno bagna. Io e ’ compagni eravam vecchi e tardi quando venimmo a quella foce stretta dov’ Ercule segnò li suoi riguardi acciò che l’uom più oltre non si metta; da la man destra mi lasciai Sibilia, da l’altra già m’avea lasciata Setta. “O frati”, dissi “che per cento milia perigli siete giunti a l’occidente, a questa tanto picciola vigilia d’i nostri sensi ch’è del rimanente non vogliate negar l’esperïenza, di retro al sol, del mondo sanza gente. Considerate la vostra semenza: fatti non foste a viver come bruti, ma per seguir virtute e canoscenza”. Li miei compagni fec’ io sì aguti, con questa orazion picciola, al cammino, che a pena poscia li avrei ritenuti; e volta nostra poppa nel mattino, de’ remi facemmo ali al folle volo, sempre acquistando dal lato mancino. Tutte le stelle già de l’altro polo vedea la notte, e ’l nostro tanto basso, che non surgëa fuor del marin suolo. Cinque volte racceso e tante casso lo lume era di sotto da la luna, poi che ’ntrati eravam ne l’alto passo, quando n’apparve una montagna, bruna per la distanza, e parvemi alta tanto quanto veduta non avëa alcuna. Noi ci allegrammo, e tosto tornò in pianto; ché de la nova terra un turbo nacque e percosse del legno il primo canto. Tre volte il fé girar con tutte l’acque; a la quarta levar la poppa in suso e la prora ire in giù, com’ altrui piacque, infin che ’l mar fu sovra noi richiuso». Inferno · Canto XXVII Già era dritta in sù la fiamma e queta per non dir più, e già da noi sen gia con la licenza del dolce poeta, quand’ un’altra, che dietro a lei venìa, ne fece volger li occhi a la sua cima per un confuso suon che fuor n’uscia. Come ’l bue cicilian che mugghiò prima col pianto di colui, e ciò fu dritto, che l’avea temperato con sua lima, mugghiava con la voce de l’afflitto, sì che, con tutto che fosse di rame, pur el pareva dal dolor trafitto; così, per non aver via né forame dal principio nel foco, in suo linguaggio si convertïan le parole grame. Ma poscia ch’ebber colto lor vïaggio su per la punta, dandole quel guizzo che dato avea la lingua in lor passaggio, udimmo dire: «O tu a cu’ io drizzo la voce e che parlavi mo lombardo, dicendo “Istra ten va, più non t’adizzo”, perch’ io sia giunto forse alquanto tardo, non t’incresca restare a parlar meco; vedi che non incresce a me, e ardo! Se tu pur mo in questo mondo cieco caduto se’ di quella dolce terra latina ond’ io mia colpa tutta reco, dimmi se Romagnuoli han pace o guerra; ch’io fui d’i monti là intra Orbino e ’l giogo di che Tever si diserra». Io era in giuso ancora attento e chino, quando il mio duca mi tentò di costa, dicendo: «Parla tu; questi è latino». E io, ch’avea già pronta la risposta, sanza indugio a parlare incominciai: «O anima che se’ là giù nascosta, Romagna tua non è, e non fu mai, sanza guerra ne’ cuor de’ suoi tiranni; ma ’n palese nessuna or vi lasciai. Ravenna sta come stata è molt’ anni: l’aguglia da Polenta la si cova, sì che Cervia ricuopre co’ suoi vanni. La terra che fé già la lunga prova e di Franceschi sanguinoso mucchio, sotto le branche verdi si ritrova. E ’l mastin vecchio e ’l nuovo da Verrucchio, che fecer di Montagna il mal governo, là dove soglion fan d’i denti succhio. Le città di Lamone e di Santerno conduce il lïoncel dal nido bianco, che muta parte da la state al verno. E quella cu’ il Savio bagna il fianco, così com’ ella sie’ tra ’l piano e ’l monte, tra tirannia si vive e stato franco. Ora chi se’, ti priego che ne conte; non esser duro più ch’altri sia stato, se ’l nome tuo nel mondo tegna fronte». Poscia che ’l foco alquanto ebbe rugghiato al modo suo, l’aguta punta mosse di qua, di là, e poi diè cotal fiato: «S’i’ credesse che mia risposta fosse a persona che mai tornasse al mondo, questa fiamma staria sanza più scosse; ma però che già mai di questo fondo non tornò vivo alcun, s’i’ odo il vero, sanza tema d’infamia ti rispondo. Io fui uom d’arme, e poi fui cordigliero, credendomi, sì cinto, fare ammenda; e certo il creder mio venìa intero, se non fosse il gran prete, a cui mal prenda!, che mi rimise ne le prime colpe; e come e quare, voglio che m’intenda. Mentre ch’io forma fui d’ossa e di polpe che la madre mi diè, l’opere mie non furon leonine, ma di volpe. Li accorgimenti e le coperte vie io seppi tutte, e sì menai lor arte, ch’al fine de la terra il suono uscie. Quando mi vidi giunto in quella parte di mia etade ove ciascun dovrebbe calar le vele e raccoglier le sarte, ciò che pria mi piacëa, allor m’increbbe, e pentuto e confesso mi rendei; ahi miser lasso! e giovato sarebbe. Lo principe d’i novi Farisei, avendo guerra presso a Laterano, e non con Saracin né con Giudei, ché ciascun suo nimico era cristiano, e nessun era stato a vincer Acri né mercatante in terra di Soldano, né sommo officio né ordini sacri guardò in sé, né in me quel capestro che solea fare i suoi cinti più macri. Ma come Costantin chiese Silvestro d’entro Siratti a guerir de la lebbre, così mi chiese questi per maestro a guerir de la sua superba febbre; domandommi consiglio, e io tacetti perché le sue parole parver ebbre. E’ poi ridisse: “Tuo cuor non sospetti; finor t’assolvo, e tu m’insegna fare sì come Penestrino in terra getti. Lo ciel poss’ io serrare e diserrare, come tu sai; però son due le chiavi che ’l mio antecessor non ebbe care”. Allor mi pinser li argomenti gravi là ’ve ’l tacer mi fu avviso ’l peggio, e dissi: “Padre, da che tu mi lavi di quel peccato ov’ io mo cader deggio, lunga promessa con l’attender corto ti farà trïunfar ne l’alto seggio”. Francesco venne poi, com’ io fu’ morto, per me; ma un d’i neri cherubini li disse: “Non portar: non mi far torto. Venir se ne dee giù tra ’ miei meschini perché diede ’l consiglio frodolente, dal quale in qua stato li sono a’ crini; ch’assolver non si può chi non si pente, né pentere e volere insieme puossi per la contradizion che nol consente”. Oh me dolente! come mi riscossi quando mi prese dicendomi: “Forse tu non pensavi ch’io löico fossi!”. A Minòs mi portò; e quelli attorse otto volte la coda al dosso duro; e poi che per gran rabbia la si morse, disse: “Questi è d’i rei del foco furo”; per ch’io là dove vedi son perduto, e sì vestito, andando, mi rancuro». Quand’ elli ebbe ’l suo dir così compiuto, la fiamma dolorando si partio, torcendo e dibattendo ’l corno aguto. Noi passamm’ oltre, e io e ’l duca mio, su per lo scoglio infino in su l’altr’ arco che cuopre ’l fosso in che si paga il fio a quei che scommettendo acquistan carco. Inferno · Canto XXVIII Chi poria mai pur con parole sciolte dicer del sangue e de le piaghe a pieno ch’i’ ora vidi, per narrar più volte? Ogne lingua per certo verria meno per lo nostro sermone e per la mente c’hanno a tanto comprender poco seno. S’el s’aunasse ancor tutta la gente che già, in su la fortunata terra di Puglia, fu del suo sangue dolente per li Troiani e per la lunga guerra che de l’anella fé sì alte spoglie, come Livïo scrive, che non erra, con quella che sentio di colpi doglie per contastare a Ruberto Guiscardo; e l’altra il cui ossame ancor s’accoglie a Ceperan, là dove fu bugiardo ciascun Pugliese, e là da Tagliacozzo, dove sanz’ arme vinse il vecchio Alardo; e qual forato suo membro e qual mozzo mostrasse, d’aequar sarebbe nulla il modo de la nona bolgia sozzo. Già veggia, per mezzul perdere o lulla, com’ io vidi un, così non si pertugia, rotto dal mento infin dove si trulla. Tra le gambe pendevan le minugia; la corata pareva e ’l tristo sacco che merda fa di quel che si trangugia. Mentre che tutto in lui veder m’attacco, guardommi e con le man s’aperse il petto, dicendo: «Or vedi com’ io mi dilacco! vedi come storpiato è Mäometto! Dinanzi a me sen va piangendo Alì, fesso nel volto dal mento al ciuffetto. E tutti li altri che tu vedi qui, seminator di scandalo e di scisma fuor vivi, e però son fessi così. Un diavolo è qua dietro che n’accisma sì crudelmente, al taglio de la spada rimettendo ciascun di questa risma, quand’ avem volta la dolente strada; però che le ferite son richiuse prima ch’altri dinanzi li rivada. Ma tu chi se’ che ’n su lo scoglio muse, forse per indugiar d’ire a la pena ch’è giudicata in su le tue accuse?». «Né morte ’l giunse ancor, né colpa ’l mena», rispuose ’l mio maestro, «a tormentarlo; ma per dar lui esperïenza piena, a me, che morto son, convien menarlo per lo ’nferno qua giù di giro in giro; e quest’ è ver così com’ io ti parlo». Più fuor di cento che, quando l’udiro, s’arrestaron nel fosso a riguardarmi per maraviglia, oblïando il martiro. «Or dì a fra Dolcin dunque che s’armi, tu che forse vedra’ il sole in breve, s’ello non vuol qui tosto seguitarmi, sì di vivanda, che stretta di neve non rechi la vittoria al Noarese, ch’altrimenti acquistar non saria leve». Poi che l’un piè per girsene sospese, Mäometto mi disse esta parola; indi a partirsi in terra lo distese. Un altro, che forata avea la gola e tronco ’l naso infin sotto le ciglia, e non avea mai ch’una orecchia sola, ristato a riguardar per maraviglia con li altri, innanzi a li altri aprì la canna, ch’era di fuor d’ogne parte vermiglia, e disse: «O tu cui colpa non condanna e cu’ io vidi su in terra latina, se troppa simiglianza non m’inganna, rimembriti di Pier da Medicina, se mai torni a veder lo dolce piano che da Vercelli a Marcabò dichina. E fa saper a’ due miglior da Fano, a messer Guido e anco ad Angiolello, che, se l’antiveder qui non è vano, gittati saran fuor di lor vasello e mazzerati presso a la Cattolica per tradimento d’un tiranno fello. Tra l’isola di Cipri e di Maiolica non vide mai sì gran fallo Nettuno, non da pirate, non da gente argolica. Quel traditor che vede pur con l’uno, e tien la terra che tale qui meco vorrebbe di vedere esser digiuno, farà venirli a parlamento seco; poi farà sì, ch’al vento di Focara non sarà lor mestier voto né preco». E io a lui: «Dimostrami e dichiara, se vuo’ ch’i’ porti sù di te novella, chi è colui da la veduta amara». Allor puose la mano a la mascella d’un suo compagno e la bocca li aperse, gridando: «Questi è desso, e non favella. Questi, scacciato, il dubitar sommerse in Cesare, affermando che ’l fornito sempre con danno l’attender sofferse». Oh quanto mi pareva sbigottito con la lingua tagliata ne la strozza Curïo, ch’a dir fu così ardito! E un ch’avea l’una e l’altra man mozza, levando i moncherin per l’aura fosca, sì che ’l sangue facea la faccia sozza, gridò: «Ricordera’ti anche del Mosca, che disse, lasso!, “Capo ha cosa fatta”, che fu mal seme per la gente tosca». E io li aggiunsi: «E morte di tua schiatta»; per ch’elli, accumulando duol con duolo, sen gio come persona trista e matta. Ma io rimasi a riguardar lo stuolo, e vidi cosa ch’io avrei paura, sanza più prova, di contarla solo; se non che coscïenza m’assicura, la buona compagnia che l’uom francheggia sotto l’asbergo del sentirsi pura. Io vidi certo, e ancor par ch’io ’l veggia, un busto sanza capo andar sì come andavan li altri de la trista greggia; e ’l capo tronco tenea per le chiome, pesol con mano a guisa di lanterna: e quel mirava noi e dicea: «Oh me!». Di sé facea a sé stesso lucerna, ed eran due in uno e uno in due; com’ esser può, quei sa che sì governa. Quando diritto al piè del ponte fue, levò ’l braccio alto con tutta la testa per appressarne le parole sue, che fuoro: «Or vedi la pena molesta, tu che, spirando, vai veggendo i morti: vedi s’alcuna è grande come questa. E perché tu di me novella porti, sappi ch’i’ son Bertram dal Bornio, quelli che diedi al re giovane i ma’ conforti. Io feci il padre e ’l figlio in sé ribelli; Achitofèl non fé più d’Absalone e di Davìd coi malvagi punzelli. Perch’ io parti’ così giunte persone, partito porto il mio cerebro, lasso!, dal suo principio ch’è in questo troncone. Così s’osserva in me lo contrapasso». Inferno · Canto XXIX La molta gente e le diverse piaghe avean le luci mie sì inebrïate, che de lo stare a piangere eran vaghe. Ma Virgilio mi disse: «Che pur guate? perché la vista tua pur si soffolge là giù tra l’ombre triste smozzicate? Tu non hai fatto sì a l’altre bolge; pensa, se tu annoverar le credi, che miglia ventidue la valle volge. E già la luna è sotto i nostri piedi; lo tempo è poco omai che n’è concesso, e altro è da veder che tu non vedi». «Se tu avessi», rispuos’ io appresso, «atteso a la cagion per ch’io guardava, forse m’avresti ancor lo star dimesso». Parte sen giva, e io retro li andava, lo duca, già faccendo la risposta, e soggiugnendo: «Dentro a quella cava dov’ io tenea or li occhi sì a posta, credo ch’un spirto del mio sangue pianga la colpa che là giù cotanto costa». Allor disse ’l maestro: «Non si franga lo tuo pensier da qui innanzi sovr’ ello. Attendi ad altro, ed ei là si rimanga; ch’io vidi lui a piè del ponticello mostrarti e minacciar forte col dito, e udi’ ’l nominar Geri del Bello. Tu eri allor sì del tutto impedito sovra colui che già tenne Altaforte, che non guardasti in là, sì fu partito». «O duca mio, la vïolenta morte che non li è vendicata ancor», diss’ io, «per alcun che de l’onta sia consorte, fece lui disdegnoso; ond’ el sen gio sanza parlarmi, sì com’ ïo estimo: e in ciò m’ha el fatto a sé più pio». Così parlammo infino al loco primo che de lo scoglio l’altra valle mostra, se più lume vi fosse, tutto ad imo. Quando noi fummo sor l’ultima chiostra di Malebolge, sì che i suoi conversi potean parere a la veduta nostra, lamenti saettaron me diversi, che di pietà ferrati avean li strali; ond’ io li orecchi con le man copersi. Qual dolor fora, se de li spedali di Valdichiana tra ’l luglio e ’l settembre e di Maremma e di Sardigna i mali fossero in una fossa tutti ’nsembre, tal era quivi, e tal puzzo n’usciva qual suol venir de le marcite membre. Noi discendemmo in su l’ultima riva del lungo scoglio, pur da man sinistra; e allor fu la mia vista più viva giù ver’ lo fondo, la ’ve la ministra de l’alto Sire infallibil giustizia punisce i falsador che qui registra. Non credo ch’a veder maggior tristizia fosse in Egina il popol tutto infermo, quando fu l’aere sì pien di malizia, che li animali, infino al picciol vermo, cascaron tutti, e poi le genti antiche, secondo che i poeti hanno per fermo, si ristorar di seme di formiche; ch’era a veder per quella oscura valle languir li spirti per diverse biche. Qual sovra ’l ventre e qual sovra le spalle l’un de l’altro giacea, e qual carpone si trasmutava per lo tristo calle. Passo passo andavam sanza sermone, guardando e ascoltando li ammalati, che non potean levar le lor persone. Io vidi due sedere a sé poggiati, com’ a scaldar si poggia tegghia a tegghia, dal capo al piè di schianze macolati; e non vidi già mai menare stregghia a ragazzo aspettato dal segnorso, né a colui che mal volontier vegghia, come ciascun menava spesso il morso de l’unghie sopra sé per la gran rabbia del pizzicor, che non ha più soccorso; e sì traevan giù l’unghie la scabbia, come coltel di scardova le scaglie o d’altro pesce che più larghe l’abbia. «O tu che con le dita ti dismaglie», cominciò ’l duca mio a l’un di loro, «e che fai d’esse talvolta tanaglie, dinne s’alcun Latino è tra costoro che son quinc’ entro, se l’unghia ti basti etternalmente a cotesto lavoro». «Latin siam noi, che tu vedi sì guasti qui ambedue», rispuose l’un piangendo; «ma tu chi se’ che di noi dimandasti?». E ’l duca disse: «I’ son un che discendo con questo vivo giù di balzo in balzo, e di mostrar lo ’nferno a lui intendo». Allor si ruppe lo comun rincalzo; e tremando ciascuno a me si volse con altri che l’udiron di rimbalzo. Lo buon maestro a me tutto s’accolse, dicendo: «Dì a lor ciò che tu vuoli»; e io incominciai, poscia ch’ei volse: «Se la vostra memoria non s’imboli nel primo mondo da l’umane menti, ma s’ella viva sotto molti soli, ditemi chi voi siete e di che genti; la vostra sconcia e fastidiosa pena di palesarvi a me non vi spaventi». «Io fui d’Arezzo, e Albero da Siena», rispuose l’un, «mi fé mettere al foco; ma quel per ch’io mori’ qui non mi mena. Vero è ch’i’ dissi lui, parlando a gioco: “I’ mi saprei levar per l’aere a volo”; e quei, ch’avea vaghezza e senno poco, volle ch’i’ li mostrassi l’arte; e solo perch’ io nol feci Dedalo, mi fece ardere a tal che l’avea per figliuolo. Ma ne l’ultima bolgia de le diece me per l’alchìmia che nel mondo usai dannò Minòs, a cui fallar non lece». E io dissi al poeta: «Or fu già mai gente sì vana come la sanese? Certo non la francesca sì d’assai!». Onde l’altro lebbroso, che m’intese, rispuose al detto mio: «Tra’mene Stricca che seppe far le temperate spese, e Niccolò che la costuma ricca del garofano prima discoverse ne l’orto dove tal seme s’appicca; e tra’ne la brigata in che disperse Caccia d’Ascian la vigna e la gran fonda, e l’Abbagliato suo senno proferse. Ma perché sappi chi sì ti seconda contra i Sanesi, aguzza ver’ me l’occhio, sì che la faccia mia ben ti risponda: sì vedrai ch’io son l’ombra di Capocchio, che falsai li metalli con l’alchìmia; e te dee ricordar, se ben t’adocchio, com’ io fui di natura buona scimia». Inferno · Canto XXX Nel tempo che Iunone era crucciata per Semelè contra ’l sangue tebano, come mostrò una e altra fïata, Atamante divenne tanto insano, che veggendo la moglie con due figli andar carcata da ciascuna mano, gridò: «Tendiam le reti, sì ch’io pigli la leonessa e ’ leoncini al varco»; e poi distese i dispietati artigli, prendendo l’un ch’avea nome Learco, e rotollo e percosselo ad un sasso; e quella s’annegò con l’altro carco. E quando la fortuna volse in basso l’altezza de’ Troian che tutto ardiva, sì che ’nsieme col regno il re fu casso, Ecuba trista, misera e cattiva, poscia che vide Polissena morta, e del suo Polidoro in su la riva del mar si fu la dolorosa accorta, forsennata latrò sì come cane; tanto il dolor le fé la mente torta. Ma né di Tebe furie né troiane si vider mäi in alcun tanto crude, non punger bestie, nonché membra umane, quant’ io vidi in due ombre smorte e nude, che mordendo correvan di quel modo che ’l porco quando del porcil si schiude. L’una giunse a Capocchio, e in sul nodo del collo l’assannò, sì che, tirando, grattar li fece il ventre al fondo sodo. E l’Aretin che rimase, tremando mi disse: «Quel folletto è Gianni Schicchi, e va rabbioso altrui così conciando». «Oh», diss’ io lui, «se l’altro non ti ficchi li denti a dosso, non ti sia fatica a dir chi è, pria che di qui si spicchi». Ed elli a me: «Quell’ è l’anima antica di Mirra scellerata, che divenne al padre, fuor del dritto amore, amica. Questa a peccar con esso così venne, falsificando sé in altrui forma, come l’altro che là sen va, sostenne, per guadagnar la donna de la torma, falsificare in sé Buoso Donati, testando e dando al testamento norma». E poi che i due rabbiosi fuor passati sovra cu’ io avea l’occhio tenuto, rivolsilo a guardar li altri mal nati. Io vidi un, fatto a guisa di lëuto, pur ch’elli avesse avuta l’anguinaia tronca da l’altro che l’uomo ha forcuto. La grave idropesì, che sì dispaia le membra con l’omor che mal converte, che ’l viso non risponde a la ventraia, faceva lui tener le labbra aperte come l’etico fa, che per la sete l’un verso ’l mento e l’altro in sù rinverte. «O voi che sanz’ alcuna pena siete, e non so io perché, nel mondo gramo», diss’ elli a noi, «guardate e attendete a la miseria del maestro Adamo; io ebbi, vivo, assai di quel ch’i’ volli, e ora, lasso!, un gocciol d’acqua bramo. Li ruscelletti che d’i verdi colli del Casentin discendon giuso in Arno, faccendo i lor canali freddi e molli, sempre mi stanno innanzi, e non indarno, ché l’imagine lor vie più m’asciuga che ’l male ond’ io nel volto mi discarno. La rigida giustizia che mi fruga tragge cagion del loco ov’ io peccai a metter più li miei sospiri in fuga. Ivi è Romena, là dov’ io falsai la lega suggellata del Batista; per ch’io il corpo sù arso lasciai. Ma s’io vedessi qui l’anima trista di Guido o d’Alessandro o di lor frate, per Fonte Branda non darei la vista. Dentro c’è l’una già, se l’arrabbiate ombre che vanno intorno dicon vero; ma che mi val, c’ho le membra legate? S’io fossi pur di tanto ancor leggero ch’i’ potessi in cent’ anni andare un’oncia, io sarei messo già per lo sentiero, cercando lui tra questa gente sconcia, con tutto ch’ella volge undici miglia, e men d’un mezzo di traverso non ci ha. Io son per lor tra sì fatta famiglia; e’ m’indussero a batter li fiorini ch’avevan tre carati di mondiglia». E io a lui: «Chi son li due tapini che fumman come man bagnate ’l verno, giacendo stretti a’ tuoi destri confini?». «Qui li trovai—e poi volta non dierno—», rispuose, «quando piovvi in questo greppo, e non credo che dieno in sempiterno. L’una è la falsa ch’accusò Gioseppo; l’altr’ è ’l falso Sinon greco di Troia: per febbre aguta gittan tanto leppo». E l’un di lor, che si recò a noia forse d’esser nomato sì oscuro, col pugno li percosse l’epa croia. Quella sonò come fosse un tamburo; e mastro Adamo li percosse il volto col braccio suo, che non parve men duro, dicendo a lui: «Ancor che mi sia tolto lo muover per le membra che son gravi, ho io il braccio a tal mestiere sciolto». Ond’ ei rispuose: «Quando tu andavi al fuoco, non l’avei tu così presto; ma sì e più l’avei quando coniavi». E l’idropico: «Tu di’ ver di questo: ma tu non fosti sì ver testimonio là ’ve del ver fosti a Troia richesto». «S’io dissi falso, e tu falsasti il conio», disse Sinon; «e son qui per un fallo, e tu per più ch’alcun altro demonio!». «Ricorditi, spergiuro, del cavallo», rispuose quel ch’avëa infiata l’epa; «e sieti reo che tutto il mondo sallo!». «E te sia rea la sete onde ti crepa», disse ’l Greco, «la lingua, e l’acqua marcia che ’l ventre innanzi a li occhi sì t’assiepa!». Allora il monetier: «Così si squarcia la bocca tua per tuo mal come suole; ché, s’i’ ho sete e omor mi rinfarcia, tu hai l’arsura e ’l capo che ti duole, e per leccar lo specchio di Narcisso, non vorresti a ’nvitar molte parole». Ad ascoltarli er’ io del tutto fisso, quando ’l maestro mi disse: «Or pur mira, che per poco che teco non mi risso!». Quand’ io ’l senti’ a me parlar con ira, volsimi verso lui con tal vergogna, ch’ancor per la memoria mi si gira. Qual è colui che suo dannaggio sogna, che sognando desidera sognare, sì che quel ch’è, come non fosse, agogna, tal mi fec’ io, non possendo parlare, che disïava scusarmi, e scusava me tuttavia, e nol mi credea fare. «Maggior difetto men vergogna lava», disse ’l maestro, «che ’l tuo non è stato; però d’ogne trestizia ti disgrava. E fa ragion ch’io ti sia sempre allato, se più avvien che fortuna t’accoglia dove sien genti in simigliante piato: ché voler ciò udire è bassa voglia». Inferno · Canto XXXI Una medesma lingua pria mi morse, sì che mi tinse l’una e l’altra guancia, e poi la medicina mi riporse; così od’ io che solea far la lancia d’Achille e del suo padre esser cagione prima di trista e poi di buona mancia. Noi demmo il dosso al misero vallone su per la ripa che ’l cinge dintorno, attraversando sanza alcun sermone. Quiv’ era men che notte e men che giorno, sì che ’l viso m’andava innanzi poco; ma io senti’ sonare un alto corno, tanto ch’avrebbe ogne tuon fatto fioco, che, contra sé la sua via seguitando, dirizzò li occhi miei tutti ad un loco. Dopo la dolorosa rotta, quando Carlo Magno perdé la santa gesta, non sonò sì terribilmente Orlando. Poco portäi in là volta la testa, che me parve veder molte alte torri; ond’ io: «Maestro, dì, che terra è questa?». Ed elli a me: «Però che tu trascorri per le tenebre troppo da la lungi, avvien che poi nel maginare abborri. Tu vedrai ben, se tu là ti congiungi, quanto ’l senso s’inganna di lontano; però alquanto più te stesso pungi». Poi caramente mi prese per mano e disse: «Pria che noi siam più avanti, acciò che ’l fatto men ti paia strano, sappi che non son torri, ma giganti, e son nel pozzo intorno da la ripa da l’umbilico in giuso tutti quanti». Come quando la nebbia si dissipa, lo sguardo a poco a poco raffigura ciò che cela ’l vapor che l’aere stipa, così forando l’aura grossa e scura, più e più appressando ver’ la sponda, fuggiemi errore e cresciemi paura; però che, come su la cerchia tonda Montereggion di torri si corona, così la proda che ’l pozzo circonda torreggiavan di mezza la persona li orribili giganti, cui minaccia Giove del cielo ancora quando tuona. E io scorgeva già d’alcun la faccia, le spalle e ’l petto e del ventre gran parte, e per le coste giù ambo le braccia. Natura certo, quando lasciò l’arte di sì fatti animali, assai fé bene per tòrre tali essecutori a Marte. E s’ella d’elefanti e di balene non si pente, chi guarda sottilmente, più giusta e più discreta la ne tene; ché dove l’argomento de la mente s’aggiugne al mal volere e a la possa, nessun riparo vi può far la gente. La faccia sua mi parea lunga e grossa come la pina di San Pietro a Roma, e a sua proporzione eran l’altre ossa; sì che la ripa, ch’era perizoma dal mezzo in giù, ne mostrava ben tanto di sovra, che di giugnere a la chioma tre Frison s’averien dato mal vanto; però ch’i’ ne vedea trenta gran palmi dal loco in giù dov’ omo affibbia ’l manto. «Raphèl maì amècche zabì almi», cominciò a gridar la fiera bocca, cui non si convenia più dolci salmi. E ’l duca mio ver’ lui: «Anima sciocca, tienti col corno, e con quel ti disfoga quand’ ira o altra passïon ti tocca! Cércati al collo, e troverai la soga che ’l tien legato, o anima confusa, e vedi lui che ’l gran petto ti doga». Poi disse a me: «Elli stessi s’accusa; questi è Nembrotto per lo cui mal coto pur un linguaggio nel mondo non s’usa. Lasciànlo stare e non parliamo a vòto; ché così è a lui ciascun linguaggio come ’l suo ad altrui, ch’a nullo è noto». Facemmo adunque più lungo vïaggio, vòlti a sinistra; e al trar d’un balestro trovammo l’altro assai più fero e maggio. A cigner lui qual che fosse ’l maestro, non so io dir, ma el tenea soccinto dinanzi l’altro e dietro il braccio destro d’una catena che ’l tenea avvinto dal collo in giù, sì che ’n su lo scoperto si ravvolgëa infino al giro quinto. «Questo superbo volle esser esperto di sua potenza contra ’l sommo Giove», disse ’l mio duca, «ond’ elli ha cotal merto. Fïalte ha nome, e fece le gran prove quando i giganti fer paura a’ dèi; le braccia ch’el menò, già mai non move». E io a lui: «S’esser puote, io vorrei che de lo smisurato Brïareo esperïenza avesser li occhi mei». Ond’ ei rispuose: «Tu vedrai Anteo presso di qui che parla ed è disciolto, che ne porrà nel fondo d’ogne reo. Quel che tu vuo’ veder, più là è molto ed è legato e fatto come questo, salvo che più feroce par nel volto». Non fu tremoto già tanto rubesto, che scotesse una torre così forte, come Fïalte a scuotersi fu presto. Allor temett’ io più che mai la morte, e non v’era mestier più che la dotta, s’io non avessi viste le ritorte. Noi procedemmo più avante allotta, e venimmo ad Anteo, che ben cinque alle, sanza la testa, uscia fuor de la grotta. «O tu che ne la fortunata valle che fece Scipïon di gloria reda, quand’ Anibàl co’ suoi diede le spalle, recasti già mille leon per preda, e che, se fossi stato a l’alta guerra de’ tuoi fratelli, ancor par che si creda ch’avrebber vinto i figli de la terra: mettine giù, e non ten vegna schifo, dove Cocito la freddura serra. Non ci fare ire a Tizio né a Tifo: questi può dar di quel che qui si brama; però ti china e non torcer lo grifo. Ancor ti può nel mondo render fama, ch’el vive, e lunga vita ancor aspetta se ’nnanzi tempo grazia a sé nol chiama». Così disse ’l maestro; e quelli in fretta le man distese, e prese ’l duca mio, ond’ Ercule sentì già grande stretta. Virgilio, quando prender si sentio, disse a me: «Fatti qua, sì ch’io ti prenda»; poi fece sì ch’un fascio era elli e io. Qual pare a riguardar la Carisenda sotto ’l chinato, quando un nuvol vada sovr’ essa sì, ched ella incontro penda: tal parve Antëo a me che stava a bada di vederlo chinare, e fu tal ora ch’i’ avrei voluto ir per altra strada. Ma lievemente al fondo che divora Lucifero con Giuda, ci sposò; né, sì chinato, lì fece dimora, e come albero in nave si levò. Inferno · Canto XXXII S’ïo avessi le rime aspre e chiocce, come si converrebbe al tristo buco sovra ’l qual pontan tutte l’altre rocce, io premerei di mio concetto il suco più pienamente; ma perch’ io non l’abbo, non sanza tema a dicer mi conduco; ché non è impresa da pigliare a gabbo discriver fondo a tutto l’universo, né da lingua che chiami mamma o babbo. Ma quelle donne aiutino il mio verso ch’aiutaro Anfïone a chiuder Tebe, sì che dal fatto il dir non sia diverso. Oh sovra tutte mal creata plebe che stai nel loco onde parlare è duro, mei foste state qui pecore o zebe! Come noi fummo giù nel pozzo scuro sotto i piè del gigante assai più bassi, e io mirava ancora a l’alto muro, dicere udi’mi: «Guarda come passi: va sì, che tu non calchi con le piante le teste de’ fratei miseri lassi». Per ch’io mi volsi, e vidimi davante e sotto i piedi un lago che per gelo avea di vetro e non d’acqua sembiante. Non fece al corso suo sì grosso velo di verno la Danoia in Osterlicchi, né Tanaï là sotto ’l freddo cielo, com’ era quivi; che se Tambernicchi vi fosse sù caduto, o Pietrapana, non avria pur da l’orlo fatto cricchi. E come a gracidar si sta la rana col muso fuor de l’acqua, quando sogna di spigolar sovente la villana, livide, insin là dove appar vergogna eran l’ombre dolenti ne la ghiaccia, mettendo i denti in nota di cicogna. Ognuna in giù tenea volta la faccia; da bocca il freddo, e da li occhi il cor tristo tra lor testimonianza si procaccia. Quand’ io m’ebbi dintorno alquanto visto, volsimi a’ piedi, e vidi due sì stretti, che ’l pel del capo avieno insieme misto. «Ditemi, voi che sì strignete i petti», diss’ io, «chi siete?». E quei piegaro i colli; e poi ch’ebber li visi a me eretti, li occhi lor, ch’eran pria pur dentro molli, gocciar su per le labbra, e ’l gelo strinse le lagrime tra essi e riserrolli. Con legno legno spranga mai non cinse forte così; ond’ ei come due becchi cozzaro insieme, tanta ira li vinse. E un ch’avea perduti ambo li orecchi per la freddura, pur col viso in giùe, disse: «Perché cotanto in noi ti specchi? Se vuoi saper chi son cotesti due, la valle onde Bisenzo si dichina del padre loro Alberto e di lor fue. D’un corpo usciro; e tutta la Caina potrai cercare, e non troverai ombra degna più d’esser fitta in gelatina: non quelli a cui fu rotto il petto e l’ombra con esso un colpo per la man d’Artù; non Focaccia; non questi che m’ingombra col capo sì, ch’i’ non veggio oltre più, e fu nomato Sassol Mascheroni; se tosco se’, ben sai omai chi fu. E perché non mi metti in più sermoni, sappi ch’i’ fu’ il Camiscion de’ Pazzi; e aspetto Carlin che mi scagioni». Poscia vid’ io mille visi cagnazzi fatti per freddo; onde mi vien riprezzo, e verrà sempre, de’ gelati guazzi. E mentre ch’andavamo inver’ lo mezzo al quale ogne gravezza si rauna, e io tremava ne l’etterno rezzo; se voler fu o destino o fortuna, non so; ma, passeggiando tra le teste, forte percossi ’l piè nel viso ad una. Piangendo mi sgridò: «Perché mi peste? se tu non vieni a crescer la vendetta di Montaperti, perché mi moleste?». E io: «Maestro mio, or qui m’aspetta, sì ch’io esca d’un dubbio per costui; poi mi farai, quantunque vorrai, fretta». Lo duca stette, e io dissi a colui che bestemmiava duramente ancora: «Qual se’ tu che così rampogni altrui?». «Or tu chi se’ che vai per l’Antenora, percotendo», rispuose, «altrui le gote, sì che, se fossi vivo, troppo fora?». «Vivo son io, e caro esser ti puote», fu mia risposta, «se dimandi fama, ch’io metta il nome tuo tra l’altre note». Ed elli a me: «Del contrario ho io brama. Lèvati quinci e non mi dar più lagna, ché mal sai lusingar per questa lama!». Allor lo presi per la cuticagna e dissi: «El converrà che tu ti nomi, o che capel qui sù non ti rimagna». Ond’ elli a me: «Perché tu mi dischiomi, né ti dirò ch’io sia, né mosterrolti, se mille fiate in sul capo mi tomi». Io avea già i capelli in mano avvolti, e tratti glien’ avea più d’una ciocca, latrando lui con li occhi in giù raccolti, quando un altro gridò: «Che hai tu, Bocca? non ti basta sonar con le mascelle, se tu non latri? qual diavol ti tocca?». «Omai», diss’ io, «non vo’ che più favelle, malvagio traditor; ch’a la tua onta io porterò di te vere novelle». «Va via», rispuose, «e ciò che tu vuoi conta; ma non tacer, se tu di qua entro eschi, di quel ch’ebbe or così la lingua pronta. El piange qui l’argento de’ Franceschi: “Io vidi”, potrai dir, “quel da Duera là dove i peccatori stanno freschi”. Se fossi domandato “Altri chi v’era?”, tu hai dallato quel di Beccheria di cui segò Fiorenza la gorgiera. Gianni de’ Soldanier credo che sia più là con Ganellone e Tebaldello, ch’aprì Faenza quando si dormia». Noi eravam partiti già da ello, ch’io vidi due ghiacciati in una buca, sì che l’un capo a l’altro era cappello; e come ’l pan per fame si manduca, così ’l sovran li denti a l’altro pose là ’ve ’l cervel s’aggiugne con la nuca: non altrimenti Tidëo si rose le tempie a Menalippo per disdegno, che quei faceva il teschio e l’altre cose. «O tu che mostri per sì bestial segno odio sovra colui che tu ti mangi, dimmi ’l perché», diss’ io, «per tal convegno, che se tu a ragion di lui ti piangi, sappiendo chi voi siete e la sua pecca, nel mondo suso ancora io te ne cangi, se quella con ch’io parlo non si secca». Inferno · Canto XXXIII La bocca sollevò dal fiero pasto quel peccator, forbendola a’ capelli del capo ch’elli avea di retro guasto. Poi cominciò: «Tu vuo’ ch’io rinovelli disperato dolor che ’l cor mi preme già pur pensando, pria ch’io ne favelli. Ma se le mie parole esser dien seme che frutti infamia al traditor ch’i’ rodo, parlar e lagrimar vedrai insieme. Io non so chi tu se’ né per che modo venuto se’ qua giù; ma fiorentino mi sembri veramente quand’ io t’odo. Tu dei saper ch’i’ fui conte Ugolino, e questi è l’arcivescovo Ruggieri: or ti dirò perché i son tal vicino. Che per l’effetto de’ suo’ mai pensieri, fidandomi di lui, io fossi preso e poscia morto, dir non è mestieri; però quel che non puoi avere inteso, cioè come la morte mia fu cruda, udirai, e saprai s’e’ m’ha offeso. Breve pertugio dentro da la Muda, la qual per me ha ’l titol de la fame, e che conviene ancor ch’altrui si chiuda, m’avea mostrato per lo suo forame più lune già, quand’ io feci ’l mal sonno che del futuro mi squarciò ’l velame. Questi pareva a me maestro e donno, cacciando il lupo e ’ lupicini al monte per che i Pisan veder Lucca non ponno. Con cagne magre, studïose e conte Gualandi con Sismondi e con Lanfranchi s’avea messi dinanzi da la fronte. In picciol corso mi parieno stanchi lo padre e ’ figli, e con l’agute scane mi parea lor veder fender li fianchi. Quando fui desto innanzi la dimane, pianger senti’ fra ’l sonno i miei figliuoli ch’eran con meco, e dimandar del pane. Ben se’ crudel, se tu già non ti duoli pensando ciò che ’l mio cor s’annunziava; e se non piangi, di che pianger suoli? Già eran desti, e l’ora s’appressava che ’l cibo ne solëa essere addotto, e per suo sogno ciascun dubitava; e io senti’ chiavar l’uscio di sotto a l’orribile torre; ond’ io guardai nel viso a’ mie’ figliuoi sanza far motto. Io non piangëa, sì dentro impetrai: piangevan elli; e Anselmuccio mio disse: “Tu guardi sì, padre! che hai?”. Perciò non lagrimai né rispuos’ io tutto quel giorno né la notte appresso, infin che l’altro sol nel mondo uscìo. Come un poco di raggio si fu messo nel doloroso carcere, e io scorsi per quattro visi il mio aspetto stesso, ambo le man per lo dolor mi morsi; ed ei, pensando ch’io ’l fessi per voglia di manicar, di sùbito levorsi e disser: “Padre, assai ci fia men doglia se tu mangi di noi: tu ne vestisti queste misere carni, e tu le spoglia”. Queta’mi allor per non farli più tristi; lo dì e l’altro stemmo tutti muti; ahi dura terra, perché non t’apristi? Poscia che fummo al quarto dì venuti, Gaddo mi si gittò disteso a’ piedi, dicendo: “Padre mio, ché non m’aiuti?”. Quivi morì; e come tu mi vedi, vid’ io cascar li tre ad uno ad uno tra ’l quinto dì e ’l sesto; ond’ io mi diedi, già cieco, a brancolar sovra ciascuno, e due dì li chiamai, poi che fur morti. Poscia, più che ’l dolor, poté ’l digiuno». Quand’ ebbe detto ciò, con li occhi torti riprese ’l teschio misero co’ denti, che furo a l’osso, come d’un can, forti. Ahi Pisa, vituperio de le genti del bel paese là dove ’l sì suona, poi che i vicini a te punir son lenti, muovasi la Capraia e la Gorgona, e faccian siepe ad Arno in su la foce, sì ch’elli annieghi in te ogne persona! Che se ’l conte Ugolino aveva voce d’aver tradita te de le castella, non dovei tu i figliuoi porre a tal croce. Innocenti facea l’età novella, novella Tebe, Uguiccione e ’l Brigata e li altri due che ’l canto suso appella. Noi passammo oltre, là ’ve la gelata ruvidamente un’altra gente fascia, non volta in giù, ma tutta riversata. Lo pianto stesso lì pianger non lascia, e ’l duol che truova in su li occhi rintoppo, si volge in entro a far crescer l’ambascia; ché le lagrime prime fanno groppo, e sì come visiere di cristallo, rïempion sotto ’l ciglio tutto il coppo. E avvegna che, sì come d’un callo, per la freddura ciascun sentimento cessato avesse del mio viso stallo, già mi parea sentire alquanto vento; per ch’io: «Maestro mio, questo chi move? non è qua giù ogne vapore spento?». Ond’ elli a me: «Avaccio sarai dove di ciò ti farà l’occhio la risposta, veggendo la cagion che ’l fiato piove». E un de’ tristi de la fredda crosta gridò a noi: «O anime crudeli tanto che data v’è l’ultima posta, levatemi dal viso i duri veli, sì ch’ïo sfoghi ’l duol che ’l cor m’impregna, un poco, pria che ’l pianto si raggeli». Per ch’io a lui: «Se vuo’ ch’i’ ti sovvegna, dimmi chi se’, e s’io non ti disbrigo, al fondo de la ghiaccia ir mi convegna». Rispuose adunque: «I’ son frate Alberigo; i’ son quel da le frutta del mal orto, che qui riprendo dattero per figo». «Oh», diss’ io lui, «or se’ tu ancor morto?». Ed elli a me: «Come ’l mio corpo stea nel mondo sù, nulla scïenza porto. Cotal vantaggio ha questa Tolomea, che spesse volte l’anima ci cade innanzi ch’Atropòs mossa le dea. E perché tu più volentier mi rade le ’nvetrïate lagrime dal volto, sappie che, tosto che l’anima trade come fec’ ïo, il corpo suo l’è tolto da un demonio, che poscia il governa mentre che ’l tempo suo tutto sia vòlto. Ella ruina in sì fatta cisterna; e forse pare ancor lo corpo suso de l’ombra che di qua dietro mi verna. Tu ’l dei saper, se tu vien pur mo giuso: elli è ser Branca Doria, e son più anni poscia passati ch’el fu sì racchiuso». «Io credo», diss’ io lui, «che tu m’inganni; ché Branca Doria non morì unquanche, e mangia e bee e dorme e veste panni». «Nel fosso sù», diss’ el, «de’ Malebranche, là dove bolle la tenace pece, non era ancora giunto Michel Zanche, che questi lasciò il diavolo in sua vece nel corpo suo, ed un suo prossimano che ’l tradimento insieme con lui fece. Ma distendi oggimai in qua la mano; aprimi li occhi». E io non gliel’ apersi; e cortesia fu lui esser villano. Ahi Genovesi, uomini diversi d’ogne costume e pien d’ogne magagna, perché non siete voi del mondo spersi? Ché col peggiore spirto di Romagna trovai di voi un tal, che per sua opra in anima in Cocito già si bagna, e in corpo par vivo ancor di sopra. Inferno · Canto XXXIV «Vexilla regis prodeunt inferni verso di noi; però dinanzi mira», disse ’l maestro mio, «se tu ’l discerni». Come quando una grossa nebbia spira, o quando l’emisperio nostro annotta, par di lungi un molin che ’l vento gira, veder mi parve un tal dificio allotta; poi per lo vento mi ristrinsi retro al duca mio, ché non lì era altra grotta. Già era, e con paura il metto in metro, là dove l’ombre tutte eran coperte, e trasparien come festuca in vetro. Altre sono a giacere; altre stanno erte, quella col capo e quella con le piante; altra, com’ arco, il volto a’ piè rinverte. Quando noi fummo fatti tanto avante, ch’al mio maestro piacque di mostrarmi la creatura ch’ebbe il bel sembiante, d’innanzi mi si tolse e fé restarmi, «Ecco Dite», dicendo, «ed ecco il loco ove convien che di fortezza t’armi». Com’ io divenni allor gelato e fioco, nol dimandar, lettor, ch’i’ non lo scrivo, però ch’ogne parlar sarebbe poco. Io non mori’ e non rimasi vivo; pensa oggimai per te, s’hai fior d’ingegno, qual io divenni, d’uno e d’altro privo. Lo ’mperador del doloroso regno da mezzo ’l petto uscia fuor de la ghiaccia; e più con un gigante io mi convegno, che i giganti non fan con le sue braccia: vedi oggimai quant’ esser dee quel tutto ch’a così fatta parte si confaccia. S’el fu sì bel com’ elli è ora brutto, e contra ’l suo fattore alzò le ciglia, ben dee da lui procedere ogne lutto. Oh quanto parve a me gran maraviglia quand’ io vidi tre facce a la sua testa! L’una dinanzi, e quella era vermiglia; l’altr’ eran due, che s’aggiugnieno a questa sovresso ’l mezzo di ciascuna spalla, e sé giugnieno al loco de la cresta: e la destra parea tra bianca e gialla; la sinistra a vedere era tal, quali vegnon di là onde ’l Nilo s’avvalla. Sotto ciascuna uscivan due grand’ ali, quanto si convenia a tanto uccello: vele di mar non vid’ io mai cotali. Non avean penne, ma di vispistrello era lor modo; e quelle svolazzava, sì che tre venti si movean da ello: quindi Cocito tutto s’aggelava. Con sei occhi piangëa, e per tre menti gocciava ’l pianto e sanguinosa bava. Da ogne bocca dirompea co’ denti un peccatore, a guisa di maciulla, sì che tre ne facea così dolenti. A quel dinanzi il mordere era nulla verso ’l graffiar, che talvolta la schiena rimanea de la pelle tutta brulla. «Quell’ anima là sù c’ha maggior pena», disse ’l maestro, «è Giuda Scarïotto, che ’l capo ha dentro e fuor le gambe mena. De li altri due c’hanno il capo di sotto, quel che pende dal nero ceffo è Bruto: vedi come si storce, e non fa motto!; e l’altro è Cassio, che par sì membruto. Ma la notte risurge, e oramai è da partir, ché tutto avem veduto». Com’ a lui piacque, il collo li avvinghiai; ed el prese di tempo e loco poste, e quando l’ali fuoro aperte assai, appigliò sé a le vellute coste; di vello in vello giù discese poscia tra ’l folto pelo e le gelate croste. Quando noi fummo là dove la coscia si volge, a punto in sul grosso de l’anche, lo duca, con fatica e con angoscia, volse la testa ov’ elli avea le zanche, e aggrappossi al pel com’ om che sale, sì che ’n inferno i’ credea tornar anche. «Attienti ben, ché per cotali scale», disse ’l maestro, ansando com’ uom lasso, «conviensi dipartir da tanto male». Poi uscì fuor per lo fóro d’un sasso e puose me in su l’orlo a sedere; appresso porse a me l’accorto passo. Io levai li occhi e credetti vedere Lucifero com’ io l’avea lasciato, e vidili le gambe in sù tenere; e s’io divenni allora travagliato, la gente grossa il pensi, che non vede qual è quel punto ch’io avea passato. «Lèvati sù», disse ’l maestro, «in piede: la via è lunga e ’l cammino è malvagio, e già il sole a mezza terza riede». Non era camminata di palagio là ’v’ eravam, ma natural burella ch’avea mal suolo e di lume disagio. «Prima ch’io de l’abisso mi divella, maestro mio», diss’ io quando fui dritto, «a trarmi d’erro un poco mi favella: ov’ è la ghiaccia? e questi com’ è fitto sì sottosopra? e come, in sì poc’ ora, da sera a mane ha fatto il sol tragitto?». Ed elli a me: «Tu imagini ancora d’esser di là dal centro, ov’ io mi presi al pel del vermo reo che ’l mondo fóra. Di là fosti cotanto quant’ io scesi; quand’ io mi volsi, tu passasti ’l punto al qual si traggon d’ogne parte i pesi. E se’ or sotto l’emisperio giunto ch’è contraposto a quel che la gran secca coverchia, e sotto ’l cui colmo consunto fu l’uom che nacque e visse sanza pecca; tu haï i piedi in su picciola spera che l’altra faccia fa de la Giudecca. Qui è da man, quando di là è sera; e questi, che ne fé scala col pelo, fitto è ancora sì come prim’ era. Da questa parte cadde giù dal cielo; e la terra, che pria di qua si sporse, per paura di lui fé del mar velo, e venne a l’emisperio nostro; e forse per fuggir lui lasciò qui loco vòto quella ch’appar di qua, e sù ricorse». Luogo è là giù da Belzebù remoto tanto quanto la tomba si distende, che non per vista, ma per suono è noto d’un ruscelletto che quivi discende per la buca d’un sasso, ch’elli ha roso, col corso ch’elli avvolge, e poco pende. Lo duca e io per quel cammino ascoso intrammo a ritornar nel chiaro mondo; e sanza cura aver d’alcun riposo, salimmo sù, el primo e io secondo, tanto ch’i’ vidi de le cose belle che porta ’l ciel, per un pertugio tondo. E quindi uscimmo a riveder le stelle. PURGATORIO Purgatorio · Canto I Per correr miglior acque alza le vele omai la navicella del mio ingegno, che lascia dietro a sé mar sì crudele; e canterò di quel secondo regno dove l’umano spirito si purga e di salire al ciel diventa degno. Ma qui la morta poesì resurga, o sante Muse, poi che vostro sono; e qui Calïopè alquanto surga, seguitando il mio canto con quel suono di cui le Piche misere sentiro lo colpo tal, che disperar perdono. Dolce color d’orïental zaffiro, che s’accoglieva nel sereno aspetto del mezzo, puro infino al primo giro, a li occhi miei ricominciò diletto, tosto ch’io usci’ fuor de l’aura morta che m’avea contristati li occhi e ’l petto. Lo bel pianeto che d’amar conforta faceva tutto rider l’orïente, velando i Pesci ch’erano in sua scorta. I’ mi volsi a man destra, e puosi mente a l’altro polo, e vidi quattro stelle non viste mai fuor ch’a la prima gente. Goder pareva ’l ciel di lor fiammelle: oh settentrïonal vedovo sito, poi che privato se’ di mirar quelle! Com’ io da loro sguardo fui partito, un poco me volgendo a l ’altro polo, là onde ’l Carro già era sparito, vidi presso di me un veglio solo, degno di tanta reverenza in vista, che più non dee a padre alcun figliuolo. Lunga la barba e di pel bianco mista portava, a’ suoi capelli simigliante, de’ quai cadeva al petto doppia lista. Li raggi de le quattro luci sante fregiavan sì la sua faccia di lume, ch’i’ ’l vedea come ’l sol fosse davante. «Chi siete voi che contro al cieco fiume fuggita avete la pregione etterna?», diss’ el, movendo quelle oneste piume. «Chi v’ha guidati, o che vi fu lucerna, uscendo fuor de la profonda notte che sempre nera fa la valle inferna? Son le leggi d’abisso così rotte? o è mutato in ciel novo consiglio, che, dannati, venite a le mie grotte?». Lo duca mio allor mi diè di piglio, e con parole e con mani e con cenni reverenti mi fé le gambe e ’l ciglio. Poscia rispuose lui: «Da me non venni: donna scese del ciel, per li cui prieghi de la mia compagnia costui sovvenni. Ma da ch’è tuo voler che più si spieghi di nostra condizion com’ ell’ è vera, esser non puote il mio che a te si nieghi. Questi non vide mai l’ultima sera; ma per la sua follia le fu sì presso, che molto poco tempo a volger era. Sì com’ io dissi, fui mandato ad esso per lui campare; e non lì era altra via che questa per la quale i’ mi son messo. Mostrata ho lui tutta la gente ria; e ora intendo mostrar quelli spirti che purgan sé sotto la tua balìa. Com’ io l’ho tratto, saria lungo a dirti; de l’alto scende virtù che m’aiuta conducerlo a vederti e a udirti. Or ti piaccia gradir la sua venuta: libertà va cercando, ch’è sì cara, come sa chi per lei vita rifiuta. Tu ’l sai, ché non ti fu per lei amara in Utica la morte, ove lasciasti la vesta ch’al gran dì sarà sì chiara. Non son li editti etterni per noi guasti, ché questi vive e Minòs me non lega; ma son del cerchio ove son li occhi casti di Marzia tua, che ’n vista ancor ti priega, o santo petto, che per tua la tegni: per lo suo amore adunque a noi ti piega. Lasciane andar per li tuoi sette regni; grazie riporterò di te a lei, se d’esser mentovato là giù degni». «Marzïa piacque tanto a li occhi miei mentre ch’i’ fu’ di là», diss’ elli allora, «che quante grazie volse da me, fei. Or che di là dal mal fiume dimora, più muover non mi può, per quella legge che fatta fu quando me n’usci’ fora. Ma se donna del ciel ti move e regge, come tu di’, non c’è mestier lusinghe: bastisi ben che per lei mi richegge. Va dunque, e fa che tu costui ricinghe d’un giunco schietto e che li lavi ’l viso, sì ch’ogne sucidume quindi stinghe; ché non si converria, l’occhio sorpriso d’alcuna nebbia, andar dinanzi al primo ministro, ch’è di quei di paradiso. Questa isoletta intorno ad imo ad imo, là giù colà dove la batte l’onda, porta di giunchi sovra ’l molle limo: null’ altra pianta che facesse fronda o indurasse, vi puote aver vita, però ch’a le percosse non seconda. Poscia non sia di qua vostra reddita; lo sol vi mosterrà, che surge omai, prendere il monte a più lieve salita». Così sparì; e io sù mi levai sanza parlare, e tutto mi ritrassi al duca mio, e li occhi a lui drizzai. El cominciò: «Figliuol, segui i miei passi: volgianci in dietro, ché di qua dichina questa pianura a’ suoi termini bassi». L’alba vinceva l’ora mattutina che fuggia innanzi, sì che di lontano conobbi il tremolar de la marina. Noi andavam per lo solingo piano com’ om che torna a la perduta strada, che ’nfino ad essa li pare ire in vano. Quando noi fummo là ’ve la rugiada pugna col sole, per essere in parte dove, ad orezza, poco si dirada, ambo le mani in su l’erbetta sparte soavemente ’l mio maestro pose: ond’ io, che fui accorto di sua arte, porsi ver’ lui le guance lagrimose; ivi mi fece tutto discoverto quel color che l’inferno mi nascose. Venimmo poi in sul lito diserto, che mai non vide navicar sue acque omo, che di tornar sia poscia esperto. Quivi mi cinse sì com’ altrui piacque: oh maraviglia! ché qual elli scelse l’umile pianta, cotal si rinacque subitamente là onde l’avelse. Purgatorio · Canto II Già era ’l sole a l’orizzonte giunto lo cui meridïan cerchio coverchia Ierusalèm col suo più alto punto; e la notte, che opposita a lui cerchia, uscia di Gange fuor con le Bilance, che le caggion di man quando soverchia; sì che le bianche e le vermiglie guance, là dov’ i’ era, de la bella Aurora per troppa etate divenivan rance. Noi eravam lunghesso mare ancora, come gente che pensa a suo cammino, che va col cuore e col corpo dimora. Ed ecco, qual, sorpreso dal mattino, per li grossi vapor Marte rosseggia giù nel ponente sovra ’l suol marino, cotal m’apparve, s’io ancor lo veggia, un lume per lo mar venir sì ratto, che ’l muover suo nessun volar pareggia. Dal qual com’ io un poco ebbi ritratto l’occhio per domandar lo duca mio, rividil più lucente e maggior fatto. Poi d’ogne lato ad esso m’appario un non sapeva che bianco, e di sotto a poco a poco un altro a lui uscìo. Lo mio maestro ancor non facea motto, mentre che i primi bianchi apparver ali; allor che ben conobbe il galeotto, gridò: «Fa, fa che le ginocchia cali. Ecco l’angel di Dio: piega le mani; omai vedrai di sì fatti officiali. Vedi che sdegna li argomenti umani, sì che remo non vuol, né altro velo che l’ali sue, tra liti sì lontani. Vedi come l’ha dritte verso ’l cielo, trattando l’aere con l’etterne penne, che non si mutan come mortal pelo». Poi, come più e più verso noi venne l’uccel divino, più chiaro appariva: per che l’occhio da presso nol sostenne, ma chinail giuso; e quei sen venne a riva con un vasello snelletto e leggero, tanto che l’acqua nulla ne ’nghiottiva. Da poppa stava il celestial nocchiero, tal che faria beato pur descripto; e più di cento spirti entro sediero. ‘In exitu Isräel de Aegypto’ cantavan tutti insieme ad una voce con quanto di quel salmo è poscia scripto. Poi fece il segno lor di santa croce; ond’ ei si gittar tutti in su la piaggia: ed el sen gì, come venne, veloce. La turba che rimase lì, selvaggia parea del loco, rimirando intorno come colui che nove cose assaggia. Da tutte parti saettava il giorno lo sol, ch’avea con le saette conte di mezzo ’l ciel cacciato Capricorno, quando la nova gente alzò la fronte ver’ noi, dicendo a noi: «Se voi sapete, mostratene la via di gire al monte». E Virgilio rispuose: «Voi credete forse che siamo esperti d’esto loco; ma noi siam peregrin come voi siete. Dianzi venimmo, innanzi a voi un poco, per altra via, che fu sì aspra e forte, che lo salire omai ne parrà gioco». L’anime, che si fuor di me accorte, per lo spirare, ch’i’ era ancor vivo, maravigliando diventaro smorte. E come a messagger che porta ulivo tragge la gente per udir novelle, e di calcar nessun si mostra schivo, così al viso mio s’affisar quelle anime fortunate tutte quante, quasi oblïando d’ire a farsi belle. Io vidi una di lor trarresi avante per abbracciarmi con sì grande affetto, che mosse me a far lo somigliante. Ohi ombre vane, fuor che ne l’aspetto! tre volte dietro a lei le mani avvinsi, e tante mi tornai con esse al petto. Di maraviglia, credo, mi dipinsi; per che l’ombra sorrise e si ritrasse, e io, seguendo lei, oltre mi pinsi. Soavemente disse ch’io posasse; allor conobbi chi era, e pregai che, per parlarmi, un poco s’arrestasse. Rispuosemi: «Così com’ io t’amai nel mortal corpo, così t’amo sciolta: però m’arresto; ma tu perché vai?». «Casella mio, per tornar altra volta là dov’ io son, fo io questo vïaggio», diss’ io; «ma a te com’ è tanta ora tolta?». Ed elli a me: «Nessun m’è fatto oltraggio, se quei che leva quando e cui li piace, più volte m’ha negato esto passaggio; ché di giusto voler lo suo si face: veramente da tre mesi elli ha tolto chi ha voluto intrar, con tutta pace. Ond’ io, ch’era ora a la marina vòlto dove l’acqua di Tevero s’insala, benignamente fu’ da lui ricolto. A quella foce ha elli or dritta l’ala, però che sempre quivi si ricoglie qual verso Acheronte non si cala». E io: «Se nuova legge non ti toglie memoria o uso a l’amoroso canto che mi solea quetar tutte mie doglie, di ciò ti piaccia consolare alquanto l’anima mia, che, con la sua persona venendo qui, è affannata tanto!». ‘Amor che ne la mente mi ragiona’ cominciò elli allor sì dolcemente, che la dolcezza ancor dentro mi suona. Lo mio maestro e io e quella gente ch’eran con lui parevan sì contenti, come a nessun toccasse altro la mente. Noi eravam tutti fissi e attenti a le sue note; ed ecco il veglio onesto gridando: «Che è ciò, spiriti lenti? qual negligenza, quale stare è questo? Correte al monte a spogliarvi lo scoglio ch’esser non lascia a voi Dio manifesto». Come quando, cogliendo biado o loglio, li colombi adunati a la pastura, queti, sanza mostrar l’usato orgoglio, se cosa appare ond’ elli abbian paura, subitamente lasciano star l’esca, perch’ assaliti son da maggior cura; così vid’ io quella masnada fresca lasciar lo canto, e fuggir ver’ la costa, com’ om che va, né sa dove rïesca; né la nostra partita fu men tosta. Purgatorio · Canto III Avvegna che la subitana fuga dispergesse color per la campagna, rivolti al monte ove ragion ne fruga, i’ mi ristrinsi a la fida compagna: e come sare’ io sanza lui corso? chi m’avria tratto su per la montagna? El mi parea da sé stesso rimorso: o dignitosa coscïenza e netta, come t’è picciol fallo amaro morso! Quando li piedi suoi lasciar la fretta, che l’onestade ad ogn’ atto dismaga, la mente mia, che prima era ristretta, lo ’ntento rallargò, sì come vaga, e diedi ’l viso mio incontr’ al poggio che ’nverso ’l ciel più alto si dislaga. Lo sol, che dietro fiammeggiava roggio, rotto m’era dinanzi a la figura, ch’avëa in me de’ suoi raggi l’appoggio. Io mi volsi dallato con paura d’essere abbandonato, quand’ io vidi solo dinanzi a me la terra oscura; e ’l mio conforto: «Perché pur diffidi?», a dir mi cominciò tutto rivolto; «non credi tu me teco e ch’io ti guidi? Vespero è già colà dov’ è sepolto lo corpo dentro al quale io facea ombra; Napoli l’ha, e da Brandizio è tolto. Ora, se innanzi a me nulla s’aombra, non ti maravigliar più che d’i cieli che l’uno a l’altro raggio non ingombra. A sofferir tormenti, caldi e geli simili corpi la Virtù dispone che, come fa, non vuol ch’a noi si sveli. Matto è chi spera che nostra ragione possa trascorrer la infinita via che tiene una sustanza in tre persone. State contenti, umana gente, al quia; ché, se potuto aveste veder tutto, mestier non era parturir Maria; e disïar vedeste sanza frutto tai che sarebbe lor disio quetato, ch’etternalmente è dato lor per lutto: io dico d’Aristotile e di Plato e di molt’ altri»; e qui chinò la fronte, e più non disse, e rimase turbato. Noi divenimmo intanto a piè del monte; quivi trovammo la roccia sì erta, che ’ndarno vi sarien le gambe pronte. Tra Lerice e Turbìa la più diserta, la più rotta ruina è una scala, verso di quella, agevole e aperta. «Or chi sa da qual man la costa cala», disse ’l maestro mio fermando ’l passo, «sì che possa salir chi va sanz’ ala?». E mentre ch’e’ tenendo ’l viso basso essaminava del cammin la mente, e io mirava suso intorno al sasso, da man sinistra m’apparì una gente d’anime, che movieno i piè ver’ noi, e non pareva, sì venïan lente. «Leva», diss’ io, «maestro, li occhi tuoi: ecco di qua chi ne darà consiglio, se tu da te medesmo aver nol puoi». Guardò allora, e con libero piglio rispuose: «Andiamo in là, ch’ei vegnon piano; e tu ferma la spene, dolce figlio». Ancora era quel popol di lontano, i’ dico dopo i nostri mille passi, quanto un buon gittator trarria con mano, quando si strinser tutti ai duri massi de l’alta ripa, e stetter fermi e stretti com’ a guardar, chi va dubbiando, stassi. «O ben finiti, o già spiriti eletti», Virgilio incominciò, «per quella pace ch’i’ credo che per voi tutti s’aspetti, ditene dove la montagna giace, sì che possibil sia l’andare in suso; ché perder tempo a chi più sa più spiace». Come le pecorelle escon del chiuso a una, a due, a tre, e l’altre stanno timidette atterrando l’occhio e ’l muso; e ciò che fa la prima, e l’altre fanno, addossandosi a lei, s’ella s’arresta, semplici e quete, e lo ’mperché non sanno; sì vid’ io muovere a venir la testa di quella mandra fortunata allotta, pudica in faccia e ne l’andare onesta. Come color dinanzi vider rotta la luce in terra dal mio destro canto, sì che l’ombra era da me a la grotta, restaro, e trasser sé in dietro alquanto, e tutti li altri che venieno appresso, non sappiendo ’l perché, fenno altrettanto. «Sanza vostra domanda io vi confesso che questo è corpo uman che voi vedete; per che ’l lume del sole in terra è fesso. Non vi maravigliate, ma credete che non sanza virtù che da ciel vegna cerchi di soverchiar questa parete». Così ’l maestro; e quella gente degna «Tornate», disse, «intrate innanzi dunque», coi dossi de le man faccendo insegna. E un di loro incominciò: «Chiunque tu se’, così andando, volgi ’l viso: pon mente se di là mi vedesti unque». Io mi volsi ver’ lui e guardail fiso: biondo era e bello e di gentile aspetto, ma l’un de’ cigli un colpo avea diviso. Quand’ io mi fui umilmente disdetto d’averlo visto mai, el disse: «Or vedi»; e mostrommi una piaga a sommo ’l petto. Poi sorridendo disse: «Io son Manfredi, nepote di Costanza imperadrice; ond’ io ti priego che, quando tu riedi, vadi a mia bella figlia, genitrice de l’onor di Cicilia e d’Aragona, e dichi ’l vero a lei, s’altro si dice. Poscia ch’io ebbi rotta la persona di due punte mortali, io mi rendei, piangendo, a quei che volontier perdona. Orribil furon li peccati miei; ma la bontà infinita ha sì gran braccia, che prende ciò che si rivolge a lei. Se ’l pastor di Cosenza, che a la caccia di me fu messo per Clemente allora, avesse in Dio ben letta questa faccia, l’ossa del corpo mio sarieno ancora in co del ponte presso a Benevento, sotto la guardia de la grave mora. Or le bagna la pioggia e move il vento di fuor dal regno, quasi lungo ’l Verde, dov’ e’ le trasmutò a lume spento. Per lor maladizion sì non si perde, che non possa tornar, l’etterno amore, mentre che la speranza ha fior del verde. Vero è che quale in contumacia more di Santa Chiesa, ancor ch’al fin si penta, star li convien da questa ripa in fore, per ognun tempo ch’elli è stato, trenta, in sua presunzïon, se tal decreto più corto per buon prieghi non diventa. Vedi oggimai se tu mi puoi far lieto, revelando a la mia buona Costanza come m’hai visto, e anco esto divieto; ché qui per quei di là molto s’avanza». Purgatorio · Canto IV Quando per dilettanze o ver per doglie, che alcuna virtù nostra comprenda, l’anima bene ad essa si raccoglie, par ch’a nulla potenza più intenda; e questo è contra quello error che crede ch’un’anima sovr’ altra in noi s’accenda. E però, quando s’ode cosa o vede che tegna forte a sé l’anima volta, vassene ’l tempo e l’uom non se n’avvede; ch’altra potenza è quella che l’ascolta, e altra è quella c’ha l’anima intera: questa è quasi legata e quella è sciolta. Di ciò ebb’ io esperïenza vera, udendo quello spirto e ammirando; ché ben cinquanta gradi salito era lo sole, e io non m’era accorto, quando venimmo ove quell’ anime ad una gridaro a noi: «Qui è vostro dimando». Maggiore aperta molte volte impruna con una forcatella di sue spine l’uom de la villa quando l’uva imbruna, che non era la calla onde salìne lo duca mio, e io appresso, soli, come da noi la schiera si partìne. Vassi in Sanleo e discendesi in Noli, montasi su in Bismantova e ’n Cacume con esso i piè; ma qui convien ch’om voli; dico con l’ale snelle e con le piume del gran disio, di retro a quel condotto che speranza mi dava e facea lume. Noi salavam per entro ’l sasso rotto, e d’ogne lato ne stringea lo stremo, e piedi e man volea il suol di sotto. Poi che noi fummo in su l’orlo suppremo de l’alta ripa, a la scoperta piaggia, «Maestro mio», diss’ io, «che via faremo?». Ed elli a me: «Nessun tuo passo caggia; pur su al monte dietro a me acquista, fin che n’appaia alcuna scorta saggia». Lo sommo er’ alto che vincea la vista, e la costa superba più assai che da mezzo quadrante a centro lista. Io era lasso, quando cominciai: «O dolce padre, volgiti, e rimira com’ io rimango sol, se non restai». «Figliuol mio», disse, «infin quivi ti tira», additandomi un balzo poco in sùe che da quel lato il poggio tutto gira. Sì mi spronaron le parole sue, ch’i’ mi sforzai carpando appresso lui, tanto che ’l cinghio sotto i piè mi fue. A seder ci ponemmo ivi ambedui vòlti a levante ond’ eravam saliti, che suole a riguardar giovare altrui. Li occhi prima drizzai ai bassi liti; poscia li alzai al sole, e ammirava che da sinistra n’eravam feriti. Ben s’avvide il poeta ch’ïo stava stupido tutto al carro de la luce, ove tra noi e Aquilone intrava. Ond’ elli a me: «Se Castore e Poluce fossero in compagnia di quello specchio che sù e giù del suo lume conduce, tu vedresti il Zodïaco rubecchio ancora a l’Orse più stretto rotare, se non uscisse fuor del cammin vecchio. Come ciò sia, se ’l vuoi poter pensare, dentro raccolto, imagina Sïòn con questo monte in su la terra stare sì, ch’amendue hanno un solo orizzòn e diversi emisperi; onde la strada che mal non seppe carreggiar Fetòn, vedrai come a costui convien che vada da l’un, quando a colui da l’altro fianco, se lo ’ntelletto tuo ben chiaro bada». «Certo, maestro mio,» diss’ io, «unquanco non vid’ io chiaro sì com’ io discerno là dove mio ingegno parea manco, che ’l mezzo cerchio del moto superno, che si chiama Equatore in alcun’ arte, e che sempre riman tra ’l sole e ’l verno, per la ragion che di’, quinci si parte verso settentrïon, quanto li Ebrei vedevan lui verso la calda parte. Ma se a te piace, volontier saprei quanto avemo ad andar; ché ’l poggio sale più che salir non posson li occhi miei». Ed elli a me: «Questa montagna è tale, che sempre al cominciar di sotto è grave; e quant’ om più va sù, e men fa male. Però, quand’ ella ti parrà soave tanto, che sù andar ti fia leggero com’ a seconda giù andar per nave, allor sarai al fin d’esto sentiero; quivi di riposar l’affanno aspetta. Più non rispondo, e questo so per vero». E com’ elli ebbe sua parola detta, una voce di presso sonò: «Forse che di sedere in pria avrai distretta!». Al suon di lei ciascun di noi si torse, e vedemmo a mancina un gran petrone, del qual né io né ei prima s’accorse. Là ci traemmo; e ivi eran persone che si stavano a l’ombra dietro al sasso come l’uom per negghienza a star si pone. E un di lor, che mi sembiava lasso, sedeva e abbracciava le ginocchia, tenendo ’l viso giù tra esse basso. «O dolce segnor mio», diss’ io, «adocchia colui che mostra sé più negligente che se pigrizia fosse sua serocchia». Allor si volse a noi e puose mente, movendo ’l viso pur su per la coscia, e disse: «Or va tu sù, che se’ valente!». Conobbi allor chi era, e quella angoscia che m’avacciava un poco ancor la lena, non m’impedì l’andare a lui; e poscia ch’a lui fu’ giunto, alzò la testa a pena, dicendo: «Hai ben veduto come ’l sole da l’omero sinistro il carro mena?». Li atti suoi pigri e le corte parole mosser le labbra mie un poco a riso; poi cominciai: «Belacqua, a me non dole di te omai; ma dimmi: perché assiso quiritto se’? attendi tu iscorta, o pur lo modo usato t’ha’ ripriso?». Ed elli: «O frate, andar in sù che porta? ché non mi lascerebbe ire a’ martìri l’angel di Dio che siede in su la porta. Prima convien che tanto il ciel m’aggiri di fuor da essa, quanto fece in vita, per ch’io ’ndugiai al fine i buon sospiri, se orazïone in prima non m’aita che surga sù di cuor che in grazia viva; l’altra che val, che ’n ciel non è udita?». E già il poeta innanzi mi saliva, e dicea: «Vienne omai; vedi ch’è tocco meridïan dal sole e a la riva cuopre la notte già col piè Morrocco». Purgatorio · Canto V Io era già da quell’ ombre partito, e seguitava l’orme del mio duca, quando di retro a me, drizzando ’l dito, una gridò: «Ve’ che non par che luca lo raggio da sinistra a quel di sotto, e come vivo par che si conduca!». Li occhi rivolsi al suon di questo motto, e vidile guardar per maraviglia pur me, pur me, e ’l lume ch’era rotto. «Perché l’animo tuo tanto s’impiglia», disse ’l maestro, «che l’andare allenti? che ti fa ciò che quivi si pispiglia? Vien dietro a me, e lascia dir le genti: sta come torre ferma, che non crolla già mai la cima per soffiar di venti; ché sempre l’omo in cui pensier rampolla sovra pensier, da sé dilunga il segno, perché la foga l’un de l’altro insolla». Che potea io ridir, se non «Io vegno»? Dissilo, alquanto del color consperso che fa l’uom di perdon talvolta degno. E ’ntanto per la costa di traverso venivan genti innanzi a noi un poco, cantando ‘Miserere’ a verso a verso. Quando s’accorser ch’i’ non dava loco per lo mio corpo al trapassar d’i raggi, mutar lor canto in un «oh!» lungo e roco; e due di loro, in forma di messaggi, corsero incontr’ a noi e dimandarne: «Di vostra condizion fatene saggi». E ’l mio maestro: «Voi potete andarne e ritrarre a color che vi mandaro che ’l corpo di costui è vera carne. Se per veder la sua ombra restaro, com’ io avviso, assai è lor risposto: fàccianli onore, ed esser può lor caro». Vapori accesi non vid’ io sì tosto di prima notte mai fender sereno, né, sol calando, nuvole d’agosto, che color non tornasser suso in meno; e, giunti là, con li altri a noi dier volta, come schiera che scorre sanza freno. «Questa gente che preme a noi è molta, e vegnonti a pregar», disse ’l poeta: «però pur va, e in andando ascolta». «O anima che vai per esser lieta con quelle membra con le quai nascesti», venian gridando, «un poco il passo queta. Guarda s’alcun di noi unqua vedesti, sì che di lui di là novella porti: deh, perché vai? deh, perché non t’arresti? Noi fummo tutti già per forza morti, e peccatori infino a l’ultima ora; quivi lume del ciel ne fece accorti, sì che, pentendo e perdonando, fora di vita uscimmo a Dio pacificati, che del disio di sé veder n’accora». E io: «Perché ne’ vostri visi guati, non riconosco alcun; ma s’a voi piace cosa ch’io possa, spiriti ben nati, voi dite, e io farò per quella pace che, dietro a’ piedi di sì fatta guida, di mondo in mondo cercar mi si face». E uno incominciò: «Ciascun si fida del beneficio tuo sanza giurarlo, pur che ’l voler nonpossa non ricida. Ond’ io, che solo innanzi a li altri parlo, ti priego, se mai vedi quel paese che siede tra Romagna e quel di Carlo, che tu mi sie di tuoi prieghi cortese in Fano, sì che ben per me s’adori pur ch’i’ possa purgar le gravi offese. Quindi fu’ io; ma li profondi fóri ond’ uscì ’l sangue in sul quale io sedea, fatti mi fuoro in grembo a li Antenori, là dov’ io più sicuro esser credea: quel da Esti il fé far, che m’avea in ira assai più là che dritto non volea. Ma s’io fosse fuggito inver’ la Mira, quando fu’ sovragiunto ad Orïaco, ancor sarei di là dove si spira. Corsi al palude, e le cannucce e ’l braco m’impigliar sì ch’i’ caddi; e lì vid’ io de le mie vene farsi in terra laco». Poi disse un altro: «Deh, se quel disio si compia che ti tragge a l’alto monte, con buona pïetate aiuta il mio! Io fui di Montefeltro, io son Bonconte; Giovanna o altri non ha di me cura; per ch’io vo tra costor con bassa fronte». E io a lui: «Qual forza o qual ventura ti travïò sì fuor di Campaldino, che non si seppe mai tua sepultura?». «Oh!», rispuos’ elli, «a piè del Casentino traversa un’acqua c’ha nome l’Archiano, che sovra l’Ermo nasce in Apennino. Là ’ve ’l vocabol suo diventa vano, arriva’ io forato ne la gola, fuggendo a piede e sanguinando il piano. Quivi perdei la vista e la parola; nel nome di Maria fini’, e quivi caddi, e rimase la mia carne sola. Io dirò vero, e tu ’l ridì tra ’ vivi: l’angel di Dio mi prese, e quel d’inferno gridava: “O tu del ciel, perché mi privi? Tu te ne porti di costui l’etterno per una lagrimetta che ’l mi toglie; ma io farò de l’altro altro governo!”. Ben sai come ne l’aere si raccoglie quell’ umido vapor che in acqua riede, tosto che sale dove ’l freddo il coglie. Giunse quel mal voler che pur mal chiede con lo ’ntelletto, e mosse il fummo e ’l vento per la virtù che sua natura diede. Indi la valle, come ’l dì fu spento, da Pratomagno al gran giogo coperse di nebbia; e ’l ciel di sopra fece intento, sì che ’l pregno aere in acqua si converse; la pioggia cadde, e a’ fossati venne di lei ciò che la terra non sofferse; e come ai rivi grandi si convenne, ver’ lo fiume real tanto veloce si ruinò, che nulla la ritenne. Lo corpo mio gelato in su la foce trovò l’Archian rubesto; e quel sospinse ne l’Arno, e sciolse al mio petto la croce ch’i’ fe’ di me quando ’l dolor mi vinse; voltòmmi per le ripe e per lo fondo, poi di sua preda mi coperse e cinse». «Deh, quando tu sarai tornato al mondo e riposato de la lunga via», seguitò ’l terzo spirito al secondo, «ricorditi di me, che son la Pia; Siena mi fé, disfecemi Maremma: salsi colui che ’nnanellata pria disposando m’avea con la sua gemma». Purgatorio · Canto VI Quando si parte il gioco de la zara, colui che perde si riman dolente, repetendo le volte, e tristo impara; con l’altro se ne va tutta la gente; qual va dinanzi, e qual di dietro il prende, e qual dallato li si reca a mente; el non s’arresta, e questo e quello intende; a cui porge la man, più non fa pressa; e così da la calca si difende. Tal era io in quella turba spessa, volgendo a loro, e qua e là, la faccia, e promettendo mi sciogliea da essa. Quiv’ era l’Aretin che da le braccia fiere di Ghin di Tacco ebbe la morte, e l’altro ch’annegò correndo in caccia. Quivi pregava con le mani sporte Federigo Novello, e quel da Pisa che fé parer lo buon Marzucco forte. Vidi conte Orso e l’anima divisa dal corpo suo per astio e per inveggia, com’ e’ dicea, non per colpa commisa; Pier da la Broccia dico; e qui proveggia, mentr’ è di qua, la donna di Brabante, sì che però non sia di peggior greggia. Come libero fui da tutte quante quell’ ombre che pregar pur ch’altri prieghi, sì che s’avacci lor divenir sante, io cominciai: «El par che tu mi nieghi, o luce mia, espresso in alcun testo che decreto del cielo orazion pieghi; e questa gente prega pur di questo: sarebbe dunque loro speme vana, o non m’è ’l detto tuo ben manifesto?». Ed elli a me: «La mia scrittura è piana; e la speranza di costor non falla, se ben si guarda con la mente sana; ché cima di giudicio non s’avvalla perché foco d’amor compia in un punto ciò che de’ sodisfar chi qui s’astalla; e là dov’ io fermai cotesto punto, non s’ammendava, per pregar, difetto, perché ’l priego da Dio era disgiunto. Veramente a così alto sospetto non ti fermar, se quella nol ti dice che lume fia tra ’l vero e lo ’ntelletto. Non so se ’ntendi: io dico di Beatrice; tu la vedrai di sopra, in su la vetta di questo monte, ridere e felice». E io: «Segnore, andiamo a maggior fretta, ché già non m’affatico come dianzi, e vedi omai che ’l poggio l’ombra getta». «Noi anderem con questo giorno innanzi», rispuose, «quanto più potremo omai; ma ’l fatto è d’altra forma che non stanzi. Prima che sie là sù, tornar vedrai colui che già si cuopre de la costa, sì che ’ suoi raggi tu romper non fai. Ma vedi là un’anima che, posta sola soletta, inverso noi riguarda: quella ne ’nsegnerà la via più tosta». Venimmo a lei: o anima lombarda, come ti stavi altera e disdegnosa e nel mover de li occhi onesta e tarda! Ella non ci dicëa alcuna cosa, ma lasciavane gir, solo sguardando a guisa di leon quando si posa. Pur Virgilio si trasse a lei, pregando che ne mostrasse la miglior salita; e quella non rispuose al suo dimando, ma di nostro paese e de la vita ci ’nchiese; e ’l dolce duca incominciava «Mantüa . . . », e l’ombra, tutta in sé romita, surse ver’ lui del loco ove pria stava, dicendo: «O Mantoano, io son Sordello de la tua terra!»; e l’un l’altro abbracciava. Ahi serva Italia, di dolore ostello, nave sanza nocchiere in gran tempesta, non donna di province, ma bordello! Quell’ anima gentil fu così presta, sol per lo dolce suon de la sua terra, di fare al cittadin suo quivi festa; e ora in te non stanno sanza guerra li vivi tuoi, e l’un l’altro si rode di quei ch’un muro e una fossa serra. Cerca, misera, intorno da le prode le tue marine, e poi ti guarda in seno, s’alcuna parte in te di pace gode. Che val perché ti racconciasse il freno Iustinïano, se la sella è vòta? Sanz’ esso fora la vergogna meno. Ahi gente che dovresti esser devota, e lasciar seder Cesare in la sella, se bene intendi ciò che Dio ti nota, guarda come esta fiera è fatta fella per non esser corretta da li sproni, poi che ponesti mano a la predella. O Alberto tedesco ch’abbandoni costei ch’è fatta indomita e selvaggia, e dovresti inforcar li suoi arcioni, giusto giudicio da le stelle caggia sovra ’l tuo sangue, e sia novo e aperto, tal che ’l tuo successor temenza n’aggia! Ch’avete tu e ’l tuo padre sofferto, per cupidigia di costà distretti, che ’l giardin de lo ’mperio sia diserto. Vieni a veder Montecchi e Cappelletti, Monaldi e Filippeschi, uom sanza cura: color già tristi, e questi con sospetti! Vien, crudel, vieni, e vedi la pressura d’i tuoi gentili, e cura lor magagne; e vedrai Santafior com’ è oscura! Vieni a veder la tua Roma che piagne vedova e sola, e dì e notte chiama: «Cesare mio, perché non m’accompagne?». Vieni a veder la gente quanto s’ama! e se nulla di noi pietà ti move, a vergognar ti vien de la tua fama. E se licito m’è, o sommo Giove che fosti in terra per noi crucifisso, son li giusti occhi tuoi rivolti altrove? O è preparazion che ne l’abisso del tuo consiglio fai per alcun bene in tutto de l’accorger nostro scisso? Ché le città d’Italia tutte piene son di tiranni, e un Marcel diventa ogne villan che parteggiando viene. Fiorenza mia, ben puoi esser contenta di questa digression che non ti tocca, mercé del popol tuo che si argomenta. Molti han giustizia in cuore, e tardi scocca per non venir sanza consiglio a l’arco; ma il popol tuo l’ha in sommo de la bocca. Molti rifiutan lo comune incarco; ma il popol tuo solicito risponde sanza chiamare, e grida: «I’ mi sobbarco!». Or ti fa lieta, ché tu hai ben onde: tu ricca, tu con pace e tu con senno! S’io dico ’l ver, l’effetto nol nasconde. Atene e Lacedemona, che fenno l’antiche leggi e furon sì civili, fecero al viver bene un picciol cenno verso di te, che fai tanto sottili provedimenti, ch’a mezzo novembre non giugne quel che tu d’ottobre fili. Quante volte, del tempo che rimembre, legge, moneta, officio e costume hai tu mutato, e rinovate membre! E se ben ti ricordi e vedi lume, vedrai te somigliante a quella inferma che non può trovar posa in su le piume, ma con dar volta suo dolore scherma. Purgatorio · Canto VII Poscia che l’accoglienze oneste e liete furo iterate tre e quattro volte, Sordel si trasse, e disse: «Voi, chi siete?». «Anzi che a questo monte fosser volte l’anime degne di salire a Dio, fur l’ossa mie per Ottavian sepolte. Io son Virgilio; e per null’ altro rio lo ciel perdei che per non aver fé». Così rispuose allora il duca mio. Qual è colui che cosa innanzi sé sùbita vede ond’ e’ si maraviglia, che crede e non, dicendo «Ella è . . . non è . . . », tal parve quelli; e poi chinò le ciglia, e umilmente ritornò ver’ lui, e abbracciòl là ’ve ’l minor s’appiglia. «O gloria di Latin», disse, «per cui mostrò ciò che potea la lingua nostra, o pregio etterno del loco ond’ io fui, qual merito o qual grazia mi ti mostra? S’io son d’udir le tue parole degno, dimmi se vien d’inferno, e di qual chiostra». «Per tutt’ i cerchi del dolente regno», rispuose lui, «son io di qua venuto; virtù del ciel mi mosse, e con lei vegno. Non per far, ma per non fare ho perduto a veder l’alto Sol che tu disiri e che fu tardi per me conosciuto. Luogo è là giù non tristo di martìri, ma di tenebre solo, ove i lamenti non suonan come guai, ma son sospiri. Quivi sto io coi pargoli innocenti dai denti morsi de la morte avante che fosser da l’umana colpa essenti; quivi sto io con quei che le tre sante virtù non si vestiro, e sanza vizio conobber l’altre e seguir tutte quante. Ma se tu sai e puoi, alcuno indizio dà noi per che venir possiam più tosto là dove purgatorio ha dritto inizio». Rispuose: «Loco certo non c’è posto; licito m’è andar suso e intorno; per quanto ir posso, a guida mi t’accosto. Ma vedi già come dichina il giorno, e andar sù di notte non si puote; però è buon pensar di bel soggiorno. Anime sono a destra qua remote; se mi consenti, io ti merrò ad esse, e non sanza diletto ti fier note». «Com’ è ciò?», fu risposto. «Chi volesse salir di notte, fora elli impedito d’altrui, o non sarria ché non potesse?». E ’l buon Sordello in terra fregò ’l dito, dicendo: «Vedi? sola questa riga non varcheresti dopo ’l sol partito: non però ch’altra cosa desse briga, che la notturna tenebra, ad ir suso; quella col nonpoder la voglia intriga. Ben si poria con lei tornare in giuso e passeggiar la costa intorno errando, mentre che l’orizzonte il dì tien chiuso». Allora il mio segnor, quasi ammirando, «Menane», disse, «dunque là ’ve dici ch’aver si può diletto dimorando». Poco allungati c’eravam di lici, quand’ io m’accorsi che ’l monte era scemo, a guisa che i vallon li sceman quici. «Colà», disse quell’ ombra, «n’anderemo dove la costa face di sé grembo; e là il novo giorno attenderemo». Tra erto e piano era un sentiero schembo, che ne condusse in fianco de la lacca, là dove più ch’a mezzo muore il lembo. Oro e argento fine, cocco e biacca, indaco, legno lucido e sereno, fresco smeraldo in l’ora che si fiacca, da l’erba e da li fior, dentr’ a quel seno posti, ciascun saria di color vinto, come dal suo maggiore è vinto il meno. Non avea pur natura ivi dipinto, ma di soavità di mille odori vi facea uno incognito e indistinto. ‘Salve, Regina’ in sul verde e ’n su’ fiori quindi seder cantando anime vidi, che per la valle non parean di fuori. «Prima che ’l poco sole omai s’annidi», cominciò ’l Mantoan che ci avea vòlti, «tra color non vogliate ch’io vi guidi. Di questo balzo meglio li atti e ’ volti conoscerete voi di tutti quanti, che ne la lama giù tra essi accolti. Colui che più siede alto e fa sembianti d’aver negletto ciò che far dovea, e che non move bocca a li altrui canti, Rodolfo imperador fu, che potea sanar le piaghe c’hanno Italia morta, sì che tardi per altri si ricrea. L’altro che ne la vista lui conforta, resse la terra dove l’acqua nasce che Molta in Albia, e Albia in mar ne porta: Ottacchero ebbe nome, e ne le fasce fu meglio assai che Vincislao suo figlio barbuto, cui lussuria e ozio pasce. E quel nasetto che stretto a consiglio par con colui c’ha sì benigno aspetto, morì fuggendo e disfiorando il giglio: guardate là come si batte il petto! L’altro vedete c’ha fatto a la guancia de la sua palma, sospirando, letto. Padre e suocero son del mal di Francia: sanno la vita sua viziata e lorda, e quindi viene il duol che sì li lancia. Quel che par sì membruto e che s’accorda, cantando, con colui dal maschio naso, d’ogne valor portò cinta la corda; e se re dopo lui fosse rimaso lo giovanetto che retro a lui siede, ben andava il valor di vaso in vaso, che non si puote dir de l’altre rede; Iacomo e Federigo hanno i reami; del retaggio miglior nessun possiede. Rade volte risurge per li rami l’umana probitate; e questo vole quei che la dà, perché da lui si chiami. Anche al nasuto vanno mie parole non men ch’a l’altro, Pier, che con lui canta, onde Puglia e Proenza già si dole. Tant’ è del seme suo minor la pianta, quanto, più che Beatrice e Margherita, Costanza di marito ancor si vanta. Vedete il re de la semplice vita seder là solo, Arrigo d’Inghilterra: questi ha ne’ rami suoi migliore uscita. Quel che più basso tra costor s’atterra, guardando in suso, è Guiglielmo marchese, per cui e Alessandria e la sua guerra fa pianger Monferrato e Canavese». Purgatorio · Canto VIII Era già l’ora che volge il disio ai navicanti e ’ntenerisce il core lo dì c’han detto ai dolci amici addio; e che lo novo peregrin d’amore punge, se ode squilla di lontano che paia il giorno pianger che si more; quand’ io incominciai a render vano l’udire e a mirare una de l’alme surta, che l’ascoltar chiedea con mano. Ella giunse e levò ambo le palme, ficcando li occhi verso l’orïente, come dicesse a Dio: ‘D’altro non calme’. ‘Te lucis ante’ sì devotamente le uscìo di bocca e con sì dolci note, che fece me a me uscir di mente; e l’altre poi dolcemente e devote seguitar lei per tutto l’inno intero, avendo li occhi a le superne rote. Aguzza qui, lettor, ben li occhi al vero, ché ’l velo è ora ben tanto sottile, certo che ’l trapassar dentro è leggero. Io vidi quello essercito gentile tacito poscia riguardare in sùe, quasi aspettando, palido e umìle; e vidi uscir de l’alto e scender giùe due angeli con due spade affocate, tronche e private de le punte sue. Verdi come fogliette pur mo nate erano in veste, che da verdi penne percosse traean dietro e ventilate. L’un poco sovra noi a star si venne, e l’altro scese in l’opposita sponda, sì che la gente in mezzo si contenne. Ben discernëa in lor la testa bionda; ma ne la faccia l’occhio si smarria, come virtù ch’a troppo si confonda. «Ambo vegnon del grembo di Maria», disse Sordello, «a guardia de la valle, per lo serpente che verrà vie via». Ond’ io, che non sapeva per qual calle, mi volsi intorno, e stretto m’accostai, tutto gelato, a le fidate spalle. E Sordello anco: «Or avvalliamo omai tra le grandi ombre, e parleremo ad esse; grazïoso fia lor vedervi assai». Solo tre passi credo ch’i’ scendesse, e fui di sotto, e vidi un che mirava pur me, come conoscer mi volesse. Temp’ era già che l’aere s’annerava, ma non sì che tra li occhi suoi e ’ miei non dichiarisse ciò che pria serrava. Ver’ me si fece, e io ver’ lui mi fei: giudice Nin gentil, quanto mi piacque quando ti vidi non esser tra ’ rei! Nullo bel salutar tra noi si tacque; poi dimandò: «Quant’ è che tu venisti a piè del monte per le lontane acque?». «Oh!», diss’ io lui, «per entro i luoghi tristi venni stamane, e sono in prima vita, ancor che l’altra, sì andando, acquisti». E come fu la mia risposta udita, Sordello ed elli in dietro si raccolse come gente di sùbito smarrita. L’uno a Virgilio e l’altro a un si volse che sedea lì, gridando: «Sù, Currado! vieni a veder che Dio per grazia volse». Poi, vòlto a me: «Per quel singular grado che tu dei a colui che sì nasconde lo suo primo perché, che non lì è guado, quando sarai di là da le larghe onde, dì a Giovanna mia che per me chiami là dove a li ’nnocenti si risponde. Non credo che la sua madre più m’ami, poscia che trasmutò le bianche bende, le quai convien che, misera!, ancor brami. Per lei assai di lieve si comprende quanto in femmina foco d’amor dura, se l’occhio o ’l tatto spesso non l’accende. Non le farà sì bella sepultura la vipera che Melanesi accampa, com’ avria fatto il gallo di Gallura». Così dicea, segnato de la stampa, nel suo aspetto, di quel dritto zelo che misuratamente in core avvampa. Li occhi miei ghiotti andavan pur al cielo, pur là dove le stelle son più tarde, sì come rota più presso a lo stelo. E ’l duca mio: «Figliuol, che là sù guarde?». E io a lui: «A quelle tre facelle di che ’l polo di qua tutto quanto arde». Ond’ elli a me: «Le quattro chiare stelle che vedevi staman, son di là basse, e queste son salite ov’ eran quelle». Com’ ei parlava, e Sordello a sé il trasse dicendo: «Vedi là ’l nostro avversaro»; e drizzò il dito perché ’n là guardasse. Da quella parte onde non ha riparo la picciola vallea, era una biscia, forse qual diede ad Eva il cibo amaro. Tra l’erba e ’ fior venìa la mala striscia, volgendo ad ora ad or la testa, e ’l dosso leccando come bestia che si liscia. Io non vidi, e però dicer non posso, come mosser li astor celestïali; ma vidi bene e l’uno e l’altro mosso. Sentendo fender l’aere a le verdi ali, fuggì ’l serpente, e li angeli dier volta, suso a le poste rivolando iguali. L’ombra che s’era al giudice raccolta quando chiamò, per tutto quello assalto punto non fu da me guardare sciolta. «Se la lucerna che ti mena in alto truovi nel tuo arbitrio tanta cera quant’ è mestiere infino al sommo smalto», cominciò ella, «se novella vera di Val di Magra o di parte vicina sai, dillo a me, che già grande là era. Fui chiamato Currado Malaspina; non son l’antico, ma di lui discesi; a’ miei portai l’amor che qui raffina». «Oh!», diss’ io lui, «per li vostri paesi già mai non fui; ma dove si dimora per tutta Europa ch’ei non sien palesi? La fama che la vostra casa onora, grida i segnori e grida la contrada, sì che ne sa chi non vi fu ancora; e io vi giuro, s’io di sopra vada, che vostra gente onrata non si sfregia del pregio de la borsa e de la spada. Uso e natura sì la privilegia, che, perché il capo reo il mondo torca, sola va dritta e ’l mal cammin dispregia». Ed elli: «Or va; che ’l sol non si ricorca sette volte nel letto che ’l Montone con tutti e quattro i piè cuopre e inforca, che cotesta cortese oppinïone ti fia chiavata in mezzo de la testa con maggior chiovi che d’altrui sermone, se corso di giudicio non s’arresta». Purgatorio · Canto IX La concubina di Titone antico già s’imbiancava al balco d’orïente, fuor de le braccia del suo dolce amico; di gemme la sua fronte era lucente, poste in figura del freddo animale che con la coda percuote la gente; e la notte, de’ passi con che sale, fatti avea due nel loco ov’ eravamo, e ’l terzo già chinava in giuso l’ale; quand’ io, che meco avea di quel d’Adamo, vinto dal sonno, in su l’erba inchinai là ’ve già tutti e cinque sedavamo. Ne l’ora che comincia i tristi lai la rondinella presso a la mattina, forse a memoria de’ suo’ primi guai, e che la mente nostra, peregrina più da la carne e men da’ pensier presa, a le sue visïon quasi è divina, in sogno mi parea veder sospesa un’aguglia nel ciel con penne d’oro, con l’ali aperte e a calare intesa; ed esser mi parea là dove fuoro abbandonati i suoi da Ganimede, quando fu ratto al sommo consistoro. Fra me pensava: ‘Forse questa fiede pur qui per uso, e forse d’altro loco disdegna di portarne suso in piede’. Poi mi parea che, poi rotata un poco, terribil come folgor discendesse, e me rapisse suso infino al foco. Ivi parea che ella e io ardesse; e sì lo ’ncendio imaginato cosse, che convenne che ’l sonno si rompesse. Non altrimenti Achille si riscosse, li occhi svegliati rivolgendo in giro e non sappiendo là dove si fosse, quando la madre da Chirón a Schiro trafuggò lui dormendo in le sue braccia, là onde poi li Greci il dipartiro; che mi scoss’ io, sì come da la faccia mi fuggì ’l sonno, e diventa’ ismorto, come fa l’uom che, spaventato, agghiaccia. Dallato m’era solo il mio conforto, e ’l sole er’ alto già più che due ore, e ’l viso m’era a la marina torto. «Non aver tema», disse il mio segnore; «fatti sicur, ché noi semo a buon punto; non stringer, ma rallarga ogne vigore. Tu se’ omai al purgatorio giunto: vedi là il balzo che ’l chiude dintorno; vedi l’entrata là ’ve par digiunto. Dianzi, ne l’alba che procede al giorno, quando l’anima tua dentro dormia, sovra li fiori ond’ è là giù addorno venne una donna, e disse: “I’ son Lucia; lasciatemi pigliar costui che dorme; sì l’agevolerò per la sua via”. Sordel rimase e l’altre genti forme; ella ti tolse, e come ’l dì fu chiaro, sen venne suso; e io per le sue orme. Qui ti posò, ma pria mi dimostraro li occhi suoi belli quella intrata aperta; poi ella e ’l sonno ad una se n’andaro». A guisa d’uom che ’n dubbio si raccerta e che muta in conforto sua paura, poi che la verità li è discoperta, mi cambia’ io; e come sanza cura vide me ’l duca mio, su per lo balzo si mosse, e io di rietro inver’ l’altura. Lettor, tu vedi ben com’ io innalzo la mia matera, e però con più arte non ti maravigliar s’io la rincalzo. Noi ci appressammo, ed eravamo in parte che là dove pareami prima rotto, pur come un fesso che muro diparte, vidi una porta, e tre gradi di sotto per gire ad essa, di color diversi, e un portier ch’ancor non facea motto. E come l’occhio più e più v’apersi, vidil seder sovra ’l grado sovrano, tal ne la faccia ch’io non lo soffersi; e una spada nuda avëa in mano, che reflettëa i raggi sì ver’ noi, ch’io drizzava spesso il viso in vano. «Dite costinci: che volete voi?», cominciò elli a dire, «ov’ è la scorta? Guardate che ’l venir sù non vi nòi». «Donna del ciel, di queste cose accorta», rispuose ’l mio maestro a lui, «pur dianzi ne disse: “Andate là: quivi è la porta”». «Ed ella i passi vostri in bene avanzi», ricominciò il cortese portinaio: «Venite dunque a’ nostri gradi innanzi». Là ne venimmo; e lo scaglion primaio bianco marmo era sì pulito e terso, ch’io mi specchiai in esso qual io paio. Era il secondo tinto più che perso, d’una petrina ruvida e arsiccia, crepata per lo lungo e per traverso. Lo terzo, che di sopra s’ammassiccia, porfido mi parea, sì fiammeggiante come sangue che fuor di vena spiccia. Sovra questo tenëa ambo le piante l’angel di Dio sedendo in su la soglia che mi sembiava pietra di diamante. Per li tre gradi sù di buona voglia mi trasse il duca mio, dicendo: «Chiedi umilemente che ’l serrame scioglia». Divoto mi gittai a’ santi piedi; misericordia chiesi e ch’el m’aprisse, ma tre volte nel petto pria mi diedi. Sette P ne la fronte mi descrisse col punton de la spada, e «Fa che lavi, quando se’ dentro, queste piaghe» disse. Cenere, o terra che secca si cavi, d’un color fora col suo vestimento; e di sotto da quel trasse due chiavi. L’una era d’oro e l’altra era d’argento; pria con la bianca e poscia con la gialla fece a la porta sì, ch’i’ fu’ contento. «Quandunque l’una d’este chiavi falla, che non si volga dritta per la toppa», diss’ elli a noi, «non s’apre questa calla. Più cara è l’una; ma l’altra vuol troppa d’arte e d’ingegno avanti che diserri, perch’ ella è quella che ’l nodo digroppa. Da Pier le tegno; e dissemi ch’i’ erri anzi ad aprir ch’a tenerla serrata, pur che la gente a’ piedi mi s’atterri». Poi pinse l’uscio a la porta sacrata, dicendo: «Intrate; ma facciovi accorti che di fuor torna chi ’n dietro si guata». E quando fuor ne’ cardini distorti li spigoli di quella regge sacra, che di metallo son sonanti e forti, non rugghiò sì né si mostrò sì acra Tarpëa, come tolto le fu il buono Metello, per che poi rimase macra. Io mi rivolsi attento al primo tuono, e ‘Te Deum laudamus’ mi parea udire in voce mista al dolce suono. Tale imagine a punto mi rendea ciò ch’io udiva, qual prender si suole quando a cantar con organi si stea; ch’or sì or no s’intendon le parole. Purgatorio · Canto X Poi fummo dentro al soglio de la porta che ’l mal amor de l’anime disusa, perché fa parer dritta la via torta, sonando la senti’ esser richiusa; e s’io avesse li occhi vòlti ad essa, qual fora stata al fallo degna scusa? Noi salavam per una pietra fessa, che si moveva e d’una e d’altra parte, sì come l’onda che fugge e s’appressa. «Qui si conviene usare un poco d’arte», cominciò ’l duca mio, «in accostarsi or quinci, or quindi al lato che si parte». E questo fece i nostri passi scarsi, tanto che pria lo scemo de la luna rigiunse al letto suo per ricorcarsi, che noi fossimo fuor di quella cruna; ma quando fummo liberi e aperti sù dove il monte in dietro si rauna, ïo stancato e amendue incerti di nostra via, restammo in su un piano solingo più che strade per diserti. Da la sua sponda, ove confina il vano, al piè de l’alta ripa che pur sale, misurrebbe in tre volte un corpo umano; e quanto l’occhio mio potea trar d’ale, or dal sinistro e or dal destro fianco, questa cornice mi parea cotale. Là sù non eran mossi i piè nostri anco, quand’ io conobbi quella ripa intorno che dritto di salita aveva manco, esser di marmo candido e addorno d’intagli sì, che non pur Policleto, ma la natura lì avrebbe scorno. L’angel che venne in terra col decreto de la molt’ anni lagrimata pace, ch’aperse il ciel del suo lungo divieto, dinanzi a noi pareva sì verace quivi intagliato in un atto soave, che non sembiava imagine che tace. Giurato si saria ch’el dicesse ‘Ave!’; perché iv’ era imaginata quella ch’ad aprir l’alto amor volse la chiave; e avea in atto impressa esta favella ‘Ecce ancilla Deï’, propriamente come figura in cera si suggella. «Non tener pur ad un loco la mente», disse ’l dolce maestro, che m’avea da quella parte onde ’l cuore ha la gente. Per ch’i’ mi mossi col viso, e vedea di retro da Maria, da quella costa onde m’era colui che mi movea, un’altra storia ne la roccia imposta; per ch’io varcai Virgilio, e fe’mi presso, acciò che fosse a li occhi miei disposta. Era intagliato lì nel marmo stesso lo carro e ’ buoi, traendo l’arca santa, per che si teme officio non commesso. Dinanzi parea gente; e tutta quanta, partita in sette cori, a’ due mie’ sensi faceva dir l’un ‘No’, l’altro ‘Sì, canta’. Similemente al fummo de li ’ncensi che v’era imaginato, li occhi e ’l naso e al sì e al no discordi fensi. Lì precedeva al benedetto vaso, trescando alzato, l’umile salmista, e più e men che re era in quel caso. Di contra, effigïata ad una vista d’un gran palazzo, Micòl ammirava sì come donna dispettosa e trista. I’ mossi i piè del loco dov’ io stava, per avvisar da presso un’altra istoria, che di dietro a Micòl mi biancheggiava. Quiv’ era storïata l’alta gloria del roman principato, il cui valore mosse Gregorio a la sua gran vittoria; i’ dico di Traiano imperadore; e una vedovella li era al freno, di lagrime atteggiata e di dolore. Intorno a lui parea calcato e pieno di cavalieri, e l’aguglie ne l’oro sovr’ essi in vista al vento si movieno. La miserella intra tutti costoro pareva dir: «Segnor, fammi vendetta di mio figliuol ch’è morto, ond’ io m’accoro»; ed elli a lei rispondere: «Or aspetta tanto ch’i’ torni»; e quella: «Segnor mio», come persona in cui dolor s’affretta, «se tu non torni?»; ed ei: «Chi fia dov’ io, la ti farà»; ed ella: «L’altrui bene a te che fia, se ’l tuo metti in oblio?»; ond’ elli: «Or ti conforta; ch’ei convene ch’i’ solva il mio dovere anzi ch’i’ mova: giustizia vuole e pietà mi ritene». Colui che mai non vide cosa nova produsse esto visibile parlare, novello a noi perché qui non si trova. Mentr’ io mi dilettava di guardare l’imagini di tante umilitadi, e per lo fabbro loro a veder care, «Ecco di qua, ma fanno i passi radi», mormorava il poeta, «molte genti: questi ne ’nvïeranno a li alti gradi». Li occhi miei, ch’a mirare eran contenti per veder novitadi ond’ e’ son vaghi, volgendosi ver’ lui non furon lenti. Non vo’ però, lettor, che tu ti smaghi di buon proponimento per udire come Dio vuol che ’l debito si paghi. Non attender la forma del martìre: pensa la succession; pensa ch’al peggio oltre la gran sentenza non può ire. Io cominciai: «Maestro, quel ch’io veggio muovere a noi, non mi sembian persone, e non so che, sì nel veder vaneggio». Ed elli a me: «La grave condizione di lor tormento a terra li rannicchia, sì che ’ miei occhi pria n’ebber tencione. Ma guarda fiso là, e disviticchia col viso quel che vien sotto a quei sassi: già scorger puoi come ciascun si picchia». O superbi cristian, miseri lassi, che, de la vista de la mente infermi, fidanza avete ne’ retrosi passi, non v’accorgete voi che noi siam vermi nati a formar l’angelica farfalla, che vola a la giustizia sanza schermi? Di che l’animo vostro in alto galla, poi siete quasi antomata in difetto, sì come vermo in cui formazion falla? Come per sostentar solaio o tetto, per mensola talvolta una figura si vede giugner le ginocchia al petto, la qual fa del non ver vera rancura nascere ’n chi la vede; così fatti vid’ io color, quando puosi ben cura. Vero è che più e meno eran contratti secondo ch’avien più e meno a dosso; e qual più pazïenza avea ne li atti, piangendo parea dicer: ‘Più non posso’. Purgatorio · Canto XI «O Padre nostro, che ne’ cieli stai, non circunscritto, ma per più amore ch’ai primi effetti di là sù tu hai, laudato sia ’l tuo nome e ’l tuo valore da ogne creatura, com’ è degno di render grazie al tuo dolce vapore. Vegna ver’ noi la pace del tuo regno, ché noi ad essa non potem da noi, s’ella non vien, con tutto nostro ingegno. Come del suo voler li angeli tuoi fan sacrificio a te, cantando osanna, così facciano li uomini de’ suoi. Dà oggi a noi la cotidiana manna, sanza la qual per questo aspro diserto a retro va chi più di gir s’affanna. E come noi lo mal ch’avem sofferto perdoniamo a ciascuno, e tu perdona benigno, e non guardar lo nostro merto. Nostra virtù che di legger s’adona, non spermentar con l’antico avversaro, ma libera da lui che sì la sprona. Quest’ ultima preghiera, segnor caro, già non si fa per noi, ché non bisogna, ma per color che dietro a noi restaro». Così a sé e noi buona ramogna quell’ ombre orando, andavan sotto ’l pondo, simile a quel che talvolta si sogna, disparmente angosciate tutte a tondo e lasse su per la prima cornice, purgando la caligine del mondo. Se di là sempre ben per noi si dice, di qua che dire e far per lor si puote da quei c’hanno al voler buona radice? Ben si de’ loro atar lavar le note che portar quinci, sì che, mondi e lievi, possano uscire a le stellate ruote. «Deh, se giustizia e pietà vi disgrievi tosto, sì che possiate muover l’ala, che secondo il disio vostro vi lievi, mostrate da qual mano inver’ la scala si va più corto; e se c’è più d’un varco, quel ne ’nsegnate che men erto cala; ché questi che vien meco, per lo ’ncarco de la carne d’Adamo onde si veste, al montar sù, contra sua voglia, è parco». Le lor parole, che rendero a queste che dette avea colui cu’ io seguiva, non fur da cui venisser manifeste; ma fu detto: «A man destra per la riva con noi venite, e troverete il passo possibile a salir persona viva. E s’io non fossi impedito dal sasso che la cervice mia superba doma, onde portar convienmi il viso basso, cotesti, ch’ancor vive e non si noma, guardere’ io, per veder s’i’ ’l conosco, e per farlo pietoso a questa soma. Io fui latino e nato d’un gran Tosco: Guiglielmo Aldobrandesco fu mio padre; non so se ’l nome suo già mai fu vosco. L’antico sangue e l’opere leggiadre d’i miei maggior mi fer sì arrogante, che, non pensando a la comune madre, ogn’ uomo ebbi in despetto tanto avante, ch’io ne mori’, come i Sanesi sanno, e sallo in Campagnatico ogne fante. Io sono Omberto; e non pur a me danno superbia fa, ché tutti miei consorti ha ella tratti seco nel malanno. E qui convien ch’io questo peso porti per lei, tanto che a Dio si sodisfaccia, poi ch’io nol fe’ tra ’ vivi, qui tra ’ morti». Ascoltando chinai in giù la faccia; e un di lor, non questi che parlava, si torse sotto il peso che li ’mpaccia, e videmi e conobbemi e chiamava, tenendo li occhi con fatica fisi a me che tutto chin con loro andava. «Oh!», diss’ io lui, «non se’ tu Oderisi, l’onor d’Agobbio e l’onor di quell’ arte ch’alluminar chiamata è in Parisi?». «Frate», diss’ elli, «più ridon le carte che pennelleggia Franco Bolognese; l’onore è tutto or suo, e mio in parte. Ben non sare’ io stato sì cortese mentre ch’io vissi, per lo gran disio de l’eccellenza ove mio core intese. Di tal superbia qui si paga il fio; e ancor non sarei qui, se non fosse che, possendo peccar, mi volsi a Dio. Oh vana gloria de l’umane posse! com’ poco verde in su la cima dura, se non è giunta da l’etati grosse! Credette Cimabue ne la pittura tener lo campo, e ora ha Giotto il grido, sì che la fama di colui è scura. Così ha tolto l’uno a l’altro Guido la gloria de la lingua; e forse è nato chi l’uno e l’altro caccerà del nido. Non è il mondan romore altro ch’un fiato di vento, ch’or vien quinci e or vien quindi, e muta nome perché muta lato. Che voce avrai tu più, se vecchia scindi da te la carne, che se fossi morto anzi che tu lasciassi il ‘pappo’ e ’l ‘dindi’, pria che passin mill’ anni? ch’è più corto spazio a l’etterno, ch’un muover di ciglia al cerchio che più tardi in cielo è torto. Colui che del cammin sì poco piglia dinanzi a me, Toscana sonò tutta; e ora a pena in Siena sen pispiglia, ond’ era sire quando fu distrutta la rabbia fiorentina, che superba fu a quel tempo sì com’ ora è putta. La vostra nominanza è color d’erba, che viene e va, e quei la discolora per cui ella esce de la terra acerba». E io a lui: «Tuo vero dir m’incora bona umiltà, e gran tumor m’appiani; ma chi è quei di cui tu parlavi ora?». «Quelli è», rispuose, «Provenzan Salvani; ed è qui perché fu presuntüoso a recar Siena tutta a le sue mani. Ito è così e va, sanza riposo, poi che morì; cotal moneta rende a sodisfar chi è di là troppo oso». E io: «Se quello spirito ch’attende, pria che si penta, l’orlo de la vita, qua giù dimora e qua sù non ascende, se buona orazïon lui non aita, prima che passi tempo quanto visse, come fu la venuta lui largita?». «Quando vivea più glorïoso», disse, «liberamente nel Campo di Siena, ogne vergogna diposta, s’affisse; e lì, per trar l’amico suo di pena, ch’e’ sostenea ne la prigion di Carlo, si condusse a tremar per ogne vena. Più non dirò, e scuro so che parlo; ma poco tempo andrà, che ’ tuoi vicini faranno sì che tu potrai chiosarlo. Quest’ opera li tolse quei confini». Purgatorio · Canto XII Di pari, come buoi che vanno a giogo, m’andava io con quell’ anima carca, fin che ’l sofferse il dolce pedagogo. Ma quando disse: «Lascia lui e varca; ché qui è buono con l’ali e coi remi, quantunque può, ciascun pinger sua barca»; dritto sì come andar vuolsi rife’mi con la persona, avvegna che i pensieri mi rimanessero e chinati e scemi. Io m’era mosso, e seguia volontieri del mio maestro i passi, e amendue già mostravam com’ eravam leggeri; ed el mi disse: «Volgi li occhi in giùe: buon ti sarà, per tranquillar la via, veder lo letto de le piante tue». Come, perché di lor memoria sia, sovra i sepolti le tombe terragne portan segnato quel ch’elli eran pria, onde lì molte volte si ripiagne per la puntura de la rimembranza, che solo a’ pïi dà de le calcagne; sì vid’ io lì, ma di miglior sembianza secondo l’artificio, figurato quanto per via di fuor del monte avanza. Vedea colui che fu nobil creato più ch’altra creatura, giù dal cielo folgoreggiando scender, da l’un lato. Vedëa Brïareo fitto dal telo celestïal giacer, da l’altra parte, grave a la terra per lo mortal gelo. Vedea Timbreo, vedea Pallade e Marte, armati ancora, intorno al padre loro, mirar le membra d’i Giganti sparte. Vedea Nembròt a piè del gran lavoro quasi smarrito, e riguardar le genti che ’n Sennaàr con lui superbi fuoro. O Nïobè, con che occhi dolenti vedea io te segnata in su la strada, tra sette e sette tuoi figliuoli spenti! O Saùl, come in su la propria spada quivi parevi morto in Gelboè, che poi non sentì pioggia né rugiada! O folle Aragne, sì vedea io te già mezza ragna, trista in su li stracci de l’opera che mal per te si fé. O Roboàm, già non par che minacci quivi ’l tuo segno; ma pien di spavento nel porta un carro, sanza ch’altri il cacci. Mostrava ancor lo duro pavimento come Almeon a sua madre fé caro parer lo sventurato addornamento. Mostrava come i figli si gittaro sovra Sennacherìb dentro dal tempio, e come, morto lui, quivi il lasciaro. Mostrava la ruina e ’l crudo scempio che fé Tamiri, quando disse a Ciro: «Sangue sitisti, e io di sangue t’empio». Mostrava come in rotta si fuggiro li Assiri, poi che fu morto Oloferne, e anche le reliquie del martiro. Vedeva Troia in cenere e in caverne; o Ilïón, come te basso e vile mostrava il segno che lì si discerne! Qual di pennel fu maestro o di stile che ritraesse l’ombre e ’ tratti ch’ivi mirar farieno uno ingegno sottile? Morti li morti e i vivi parean vivi: non vide mei di me chi vide il vero, quant’ io calcai, fin che chinato givi. Or superbite, e via col viso altero, figliuoli d’Eva, e non chinate il volto sì che veggiate il vostro mal sentero! Più era già per noi del monte vòlto e del cammin del sole assai più speso che non stimava l’animo non sciolto, quando colui che sempre innanzi atteso andava, cominciò: «Drizza la testa; non è più tempo di gir sì sospeso. Vedi colà un angel che s’appresta per venir verso noi; vedi che torna dal servigio del dì l’ancella sesta. Di reverenza il viso e li atti addorna, sì che i diletti lo ’nvïarci in suso; pensa che questo dì mai non raggiorna!». Io era ben del suo ammonir uso pur di non perder tempo, sì che ’n quella materia non potea parlarmi chiuso. A noi venìa la creatura bella, biancovestito e ne la faccia quale par tremolando mattutina stella. Le braccia aperse, e indi aperse l’ale; disse: «Venite: qui son presso i gradi, e agevolemente omai si sale. A questo invito vegnon molto radi: o gente umana, per volar sù nata, perché a poco vento così cadi?». Menocci ove la roccia era tagliata; quivi mi batté l’ali per la fronte; poi mi promise sicura l’andata. Come a man destra, per salire al monte dove siede la chiesa che soggioga la ben guidata sopra Rubaconte, si rompe del montar l’ardita foga per le scalee che si fero ad etade ch’era sicuro il quaderno e la doga; così s’allenta la ripa che cade quivi ben ratta da l’altro girone; ma quinci e quindi l’alta pietra rade. Noi volgendo ivi le nostre persone, ‘Beati pauperes spiritu!’ voci cantaron sì, che nol diria sermone. Ahi quanto son diverse quelle foci da l’infernali! ché quivi per canti s’entra, e là giù per lamenti feroci. Già montavam su per li scaglion santi, ed esser mi parea troppo più lieve che per lo pian non mi parea davanti. Ond’ io: «Maestro, dì, qual cosa greve levata s’è da me, che nulla quasi per me fatica, andando, si riceve?». Rispuose: «Quando i P che son rimasi ancor nel volto tuo presso che stinti, saranno, com’ è l’un, del tutto rasi, fier li tuoi piè dal buon voler sì vinti, che non pur non fatica sentiranno, ma fia diletto loro esser sù pinti». Allor fec’ io come color che vanno con cosa in capo non da lor saputa, se non che ’ cenni altrui sospecciar fanno; per che la mano ad accertar s’aiuta, e cerca e truova e quello officio adempie che non si può fornir per la veduta; e con le dita de la destra scempie trovai pur sei le lettere che ’ncise quel da le chiavi a me sovra le tempie: a che guardando, il mio duca sorrise. Purgatorio · Canto XIII Noi eravamo al sommo de la scala, dove secondamente si risega lo monte che salendo altrui dismala. Ivi così una cornice lega dintorno il poggio, come la primaia; se non che l’arco suo più tosto piega. Ombra non lì è né segno che si paia: parsi la ripa e parsi la via schietta col livido color de la petraia. «Se qui per dimandar gente s’aspetta», ragionava il poeta, «io temo forse che troppo avrà d’indugio nostra eletta». Poi fisamente al sole li occhi porse; fece del destro lato a muover centro, e la sinistra parte di sé torse. «O dolce lume a cui fidanza i’ entro per lo novo cammin, tu ne conduci», dicea, «come condur si vuol quinc’ entro. Tu scaldi il mondo, tu sovr’ esso luci; s’altra ragione in contrario non ponta, esser dien sempre li tuoi raggi duci». Quanto di qua per un migliaio si conta, tanto di là eravam noi già iti, con poco tempo, per la voglia pronta; e verso noi volar furon sentiti, non però visti, spiriti parlando a la mensa d’amor cortesi inviti. La prima voce che passò volando ‘Vinum non habent’ altamente disse, e dietro a noi l’andò reïterando. E prima che del tutto non si udisse per allungarsi, un’altra ‘I’ sono Oreste’ passò gridando, e anco non s’affisse. «Oh!», diss’ io, «padre, che voci son queste?». E com’ io domandai, ecco la terza dicendo: ‘Amate da cui male aveste’. E ’l buon maestro: «Questo cinghio sferza la colpa de la invidia, e però sono tratte d’amor le corde de la ferza. Lo fren vuol esser del contrario suono; credo che l’udirai, per mio avviso, prima che giunghi al passo del perdono. Ma ficca li occhi per l’aere ben fiso, e vedrai gente innanzi a noi sedersi, e ciascun è lungo la grotta assiso». Allora più che prima li occhi apersi; guarda’mi innanzi, e vidi ombre con manti al color de la pietra non diversi. E poi che fummo un poco più avanti, udia gridar: ‘Maria, òra per noi’: gridar ‘Michele’ e ‘Pietro’ e ‘Tutti santi’. Non credo che per terra vada ancoi omo sì duro, che non fosse punto per compassion di quel ch’i’ vidi poi; ché, quando fui sì presso di lor giunto, che li atti loro a me venivan certi, per li occhi fui di grave dolor munto. Di vil ciliccio mi parean coperti, e l’un sofferia l’altro con la spalla, e tutti da la ripa eran sofferti. Così li ciechi a cui la roba falla, stanno a’ perdoni a chieder lor bisogna, e l’uno il capo sopra l’altro avvalla, perché ’n altrui pietà tosto si pogna, non pur per lo sonar de le parole, ma per la vista che non meno agogna. E come a li orbi non approda il sole, così a l’ombre quivi, ond’ io parlo ora, luce del ciel di sé largir non vole; ché a tutti un fil di ferro i cigli fóra e cusce sì, come a sparvier selvaggio si fa però che queto non dimora. A me pareva, andando, fare oltraggio, veggendo altrui, non essendo veduto: per ch’io mi volsi al mio consiglio saggio. Ben sapev’ ei che volea dir lo muto; e però non attese mia dimanda, ma disse: «Parla, e sie breve e arguto». Virgilio mi venìa da quella banda de la cornice onde cader si puote, perché da nulla sponda s’inghirlanda; da l’altra parte m’eran le divote ombre, che per l’orribile costura premevan sì, che bagnavan le gote. Volsimi a loro e: «O gente sicura», incominciai, «di veder l’alto lume che ’l disio vostro solo ha in sua cura, se tosto grazia resolva le schiume di vostra coscïenza sì che chiaro per essa scenda de la mente il fiume, ditemi, ché mi fia grazioso e caro, s’anima è qui tra voi che sia latina; e forse lei sarà buon s’i’ l’apparo». «O frate mio, ciascuna è cittadina d’una vera città; ma tu vuo’ dire che vivesse in Italia peregrina». Questo mi parve per risposta udire più innanzi alquanto che là dov’ io stava, ond’ io mi feci ancor più là sentire. Tra l’altre vidi un’ombra ch’aspettava in vista; e se volesse alcun dir ‘Come?’, lo mento a guisa d’orbo in sù levava. «Spirto», diss’ io, «che per salir ti dome, se tu se’ quelli che mi rispondesti, fammiti conto o per luogo o per nome». «Io fui sanese», rispuose, «e con questi altri rimendo qui la vita ria, lagrimando a colui che sé ne presti. Savia non fui, avvegna che Sapìa fossi chiamata, e fui de li altrui danni più lieta assai che di ventura mia. E perché tu non creda ch’io t’inganni, odi s’i’ fui, com’ io ti dico, folle, già discendendo l’arco d’i miei anni. Eran li cittadin miei presso a Colle in campo giunti co’ loro avversari, e io pregava Iddio di quel ch’e’ volle. Rotti fuor quivi e vòlti ne li amari passi di fuga; e veggendo la caccia, letizia presi a tutte altre dispari, tanto ch’io volsi in sù l’ardita faccia, gridando a Dio: “Omai più non ti temo!”, come fé ’l merlo per poca bonaccia. Pace volli con Dio in su lo stremo de la mia vita; e ancor non sarebbe lo mio dover per penitenza scemo, se ciò non fosse, ch’a memoria m’ebbe Pier Pettinaio in sue sante orazioni, a cui di me per caritate increbbe. Ma tu chi se’, che nostre condizioni vai dimandando, e porti li occhi sciolti, sì com’ io credo, e spirando ragioni?». «Li occhi», diss’ io, «mi fieno ancor qui tolti, ma picciol tempo, ché poca è l’offesa fatta per esser con invidia vòlti. Troppa è più la paura ond’ è sospesa l’anima mia del tormento di sotto, che già lo ’ncarco di là giù mi pesa». Ed ella a me: «Chi t’ha dunque condotto qua sù tra noi, se giù ritornar credi?». E io: «Costui ch’è meco e non fa motto. E vivo sono; e però mi richiedi, spirito eletto, se tu vuo’ ch’i’ mova di là per te ancor li mortai piedi». «Oh, questa è a udir sì cosa nuova», rispuose, «che gran segno è che Dio t’ami; però col priego tuo talor mi giova. E cheggioti, per quel che tu più brami, se mai calchi la terra di Toscana, che a’ miei propinqui tu ben mi rinfami. Tu li vedrai tra quella gente vana che spera in Talamone, e perderagli più di speranza ch’a trovar la Diana; ma più vi perderanno li ammiragli». Purgatorio · Canto XIV «Chi è costui che ’l nostro monte cerchia prima che morte li abbia dato il volo, e apre li occhi a sua voglia e coverchia?». «Non so chi sia, ma so ch’e’ non è solo; domandal tu che più li t’avvicini, e dolcemente, sì che parli, acco’lo». Così due spirti, l’uno a l’altro chini, ragionavan di me ivi a man dritta; poi fer li visi, per dirmi, supini; e disse l’uno: «O anima che fitta nel corpo ancora inver’ lo ciel ten vai, per carità ne consola e ne ditta onde vieni e chi se’; ché tu ne fai tanto maravigliar de la tua grazia, quanto vuol cosa che non fu più mai». E io: «Per mezza Toscana si spazia un fiumicel che nasce in Falterona, e cento miglia di corso nol sazia. Di sovr’ esso rech’ io questa persona: dirvi ch’i’ sia, saria parlare indarno, ché ’l nome mio ancor molto non suona». «Se ben lo ’ntendimento tuo accarno con lo ’ntelletto», allora mi rispuose quei che diceva pria, «tu parli d’Arno». E l’altro disse lui: «Perché nascose questi il vocabol di quella riviera, pur com’ om fa de l’orribili cose?». E l’ombra che di ciò domandata era, si sdebitò così: «Non so; ma degno ben è che ’l nome di tal valle pèra; ché dal principio suo, ov’ è sì pregno l’alpestro monte ond’ è tronco Peloro, che ’n pochi luoghi passa oltra quel segno, infin là ’ve si rende per ristoro di quel che ’l ciel de la marina asciuga, ond’ hanno i fiumi ciò che va con loro, vertù così per nimica si fuga da tutti come biscia, o per sventura del luogo, o per mal uso che li fruga: ond’ hanno sì mutata lor natura li abitator de la misera valle, che par che Circe li avesse in pastura. Tra brutti porci, più degni di galle che d’altro cibo fatto in uman uso, dirizza prima il suo povero calle. Botoli trova poi, venendo giuso, ringhiosi più che non chiede lor possa, e da lor disdegnosa torce il muso. Vassi caggendo; e quant’ ella più ’ngrossa, tanto più trova di can farsi lupi la maladetta e sventurata fossa. Discesa poi per più pelaghi cupi, trova le volpi sì piene di froda, che non temono ingegno che le occùpi. Né lascerò di dir perch’ altri m’oda; e buon sarà costui, s’ancor s’ammenta di ciò che vero spirto mi disnoda. Io veggio tuo nepote che diventa cacciator di quei lupi in su la riva del fiero fiume, e tutti li sgomenta. Vende la carne loro essendo viva; poscia li ancide come antica belva; molti di vita e sé di pregio priva. Sanguinoso esce de la trista selva; lasciala tal, che di qui a mille anni ne lo stato primaio non si rinselva». Com’ a l’annunzio di dogliosi danni si turba il viso di colui ch’ascolta, da qual che parte il periglio l’assanni, così vid’ io l’altr’ anima, che volta stava a udir, turbarsi e farsi trista, poi ch’ebbe la parola a sé raccolta. Lo dir de l’una e de l’altra la vista mi fer voglioso di saper lor nomi, e dimanda ne fei con prieghi mista; per che lo spirto che di pria parlòmi ricominciò: «Tu vuo’ ch’io mi deduca nel fare a te ciò che tu far non vuo’mi. Ma da che Dio in te vuol che traluca tanto sua grazia, non ti sarò scarso; però sappi ch’io fui Guido del Duca. Fu il sangue mio d’invidia sì rïarso, che se veduto avesse uom farsi lieto, visto m’avresti di livore sparso. Di mia semente cotal paglia mieto; o gente umana, perché poni ’l core là ’v’ è mestier di consorte divieto? Questi è Rinier; questi è ’l pregio e l’onore de la casa da Calboli, ove nullo fatto s’è reda poi del suo valore. E non pur lo suo sangue è fatto brullo, tra ’l Po e ’l monte e la marina e ’l Reno, del ben richesto al vero e al trastullo; ché dentro a questi termini è ripieno di venenosi sterpi, sì che tardi per coltivare omai verrebber meno. Ov’ è ’l buon Lizio e Arrigo Mainardi? Pier Traversaro e Guido di Carpigna? Oh Romagnuoli tornati in bastardi! Quando in Bologna un Fabbro si ralligna? quando in Faenza un Bernardin di Fosco, verga gentil di picciola gramigna? Non ti maravigliar s’io piango, Tosco, quando rimembro, con Guido da Prata, Ugolin d’Azzo che vivette nosco, Federigo Tignoso e sua brigata, la casa Traversara e li Anastagi (e l’una gente e l’altra è diretata), le donne e ’ cavalier, li affanni e li agi che ne ’nvogliava amore e cortesia là dove i cuor son fatti sì malvagi. O Bretinoro, ché non fuggi via, poi che gita se n’è la tua famiglia e molta gente per non esser ria? Ben fa Bagnacaval, che non rifiglia; e mal fa Castrocaro, e peggio Conio, che di figliar tai conti più s’impiglia. Ben faranno i Pagan, da che ’l demonio lor sen girà; ma non però che puro già mai rimagna d’essi testimonio. O Ugolin de’ Fantolin, sicuro è ’l nome tuo, da che più non s’aspetta chi far lo possa, tralignando, scuro. Ma va via, Tosco, omai; ch’or mi diletta troppo di pianger più che di parlare, sì m’ha nostra ragion la mente stretta». Noi sapavam che quell’ anime care ci sentivano andar; però, tacendo, facëan noi del cammin confidare. Poi fummo fatti soli procedendo, folgore parve quando l’aere fende, voce che giunse di contra dicendo: ‘Anciderammi qualunque m’apprende’; e fuggì come tuon che si dilegua, se sùbito la nuvola scoscende. Come da lei l’udir nostro ebbe triegua, ed ecco l’altra con sì gran fracasso, che somigliò tonar che tosto segua: «Io sono Aglauro che divenni sasso»; e allor, per ristrignermi al poeta, in destro feci, e non innanzi, il passo. Già era l’aura d’ogne parte queta; ed el mi disse: «Quel fu ’l duro camo che dovria l’uom tener dentro a sua meta. Ma voi prendete l’esca, sì che l’amo de l’antico avversaro a sé vi tira; e però poco val freno o richiamo. Chiamavi ’l cielo e ’ntorno vi si gira, mostrandovi le sue bellezze etterne, e l’occhio vostro pur a terra mira; onde vi batte chi tutto discerne». Purgatorio · Canto XV Quanto tra l’ultimar de l’ora terza e ’l principio del dì par de la spera che sempre a guisa di fanciullo scherza, tanto pareva già inver’ la sera essere al sol del suo corso rimaso; vespero là, e qui mezza notte era. E i raggi ne ferien per mezzo ’l naso, perché per noi girato era sì ’l monte, che già dritti andavamo inver’ l’occaso, quand’ io senti’ a me gravar la fronte a lo splendore assai più che di prima, e stupor m’eran le cose non conte; ond’ io levai le mani inver’ la cima de le mie ciglia, e fecimi ’l solecchio, che del soverchio visibile lima. Come quando da l’acqua o da lo specchio salta lo raggio a l’opposita parte, salendo su per lo modo parecchio a quel che scende, e tanto si diparte dal cader de la pietra in igual tratta, sì come mostra esperïenza e arte; così mi parve da luce rifratta quivi dinanzi a me esser percosso; per che a fuggir la mia vista fu ratta. «Che è quel, dolce padre, a che non posso schermar lo viso tanto che mi vaglia», diss’ io, «e pare inver’ noi esser mosso?». «Non ti maravigliar s’ancor t’abbaglia la famiglia del cielo», a me rispuose: «messo è che viene ad invitar ch’om saglia. Tosto sarà ch’a veder queste cose non ti fia grave, ma fieti diletto quanto natura a sentir ti dispuose». Poi giunti fummo a l’angel benedetto, con lieta voce disse: «Intrate quinci ad un scaleo vie men che li altri eretto». Noi montavam, già partiti di linci, e ‘Beati misericordes!’ fue cantato retro, e ‘Godi tu che vinci!’. Lo mio maestro e io soli amendue suso andavamo; e io pensai, andando, prode acquistar ne le parole sue; e dirizza’mi a lui sì dimandando: «Che volse dir lo spirto di Romagna, e ‘divieto’ e ‘consorte’ menzionando?». Per ch’elli a me: «Di sua maggior magagna conosce il danno; e però non s’ammiri se ne riprende perché men si piagna. Perché s’appuntano i vostri disiri dove per compagnia parte si scema, invidia move il mantaco a’ sospiri. Ma se l’amor de la spera supprema torcesse in suso il disiderio vostro, non vi sarebbe al petto quella tema; ché, per quanti si dice più lì ‘nostro’, tanto possiede più di ben ciascuno, e più di caritate arde in quel chiostro». «Io son d’esser contento più digiuno», diss’ io, «che se mi fosse pria taciuto, e più di dubbio ne la mente aduno. Com’ esser puote ch’un ben, distributo in più posseditor, faccia più ricchi di sé che se da pochi è posseduto?». Ed elli a me: «Però che tu rificchi la mente pur a le cose terrene, di vera luce tenebre dispicchi. Quello infinito e ineffabil bene che là sù è, così corre ad amore com’ a lucido corpo raggio vene. Tanto si dà quanto trova d’ardore; sì che, quantunque carità si stende, cresce sovr’ essa l’etterno valore. E quanta gente più là sù s’intende, più v’è da bene amare, e più vi s’ama, e come specchio l’uno a l’altro rende. E se la mia ragion non ti disfama, vedrai Beatrice, ed ella pienamente ti torrà questa e ciascun’ altra brama. Procaccia pur che tosto sieno spente, come son già le due, le cinque piaghe, che si richiudon per esser dolente». Com’ io voleva dicer ‘Tu m’appaghe’, vidimi giunto in su l’altro girone, sì che tacer mi fer le luci vaghe. Ivi mi parve in una visïone estatica di sùbito esser tratto, e vedere in un tempio più persone; e una donna, in su l’entrar, con atto dolce di madre dicer: «Figliuol mio, perché hai tu così verso noi fatto? Ecco, dolenti, lo tuo padre e io ti cercavamo». E come qui si tacque, ciò che pareva prima, dispario. Indi m’apparve un’altra con quell’ acque giù per le gote che ’l dolor distilla quando di gran dispetto in altrui nacque, e dir: «Se tu se’ sire de la villa del cui nome ne’ dèi fu tanta lite, e onde ogne scïenza disfavilla, vendica te di quelle braccia ardite ch’abbracciar nostra figlia, o Pisistràto». E ’l segnor mi parea, benigno e mite, risponder lei con viso temperato: «Che farem noi a chi mal ne disira, se quei che ci ama è per noi condannato?», Poi vidi genti accese in foco d’ira con pietre un giovinetto ancider, forte gridando a sé pur: «Martira, martira!». E lui vedea chinarsi, per la morte che l’aggravava già, inver’ la terra, ma de li occhi facea sempre al ciel porte, orando a l’alto Sire, in tanta guerra, che perdonasse a’ suoi persecutori, con quello aspetto che pietà diserra. Quando l’anima mia tornò di fori a le cose che son fuor di lei vere, io riconobbi i miei non falsi errori. Lo duca mio, che mi potea vedere far sì com’ om che dal sonno si slega, disse: «Che hai che non ti puoi tenere, ma se’ venuto più che mezza lega velando li occhi e con le gambe avvolte, a guisa di cui vino o sonno piega?». «O dolce padre mio, se tu m’ascolte, io ti dirò», diss’ io, «ciò che m’apparve quando le gambe mi furon sì tolte». Ed ei: «Se tu avessi cento larve sovra la faccia, non mi sarian chiuse le tue cogitazion, quantunque parve. Ciò che vedesti fu perché non scuse d’aprir lo core a l’acque de la pace che da l’etterno fonte son diffuse. Non dimandai “Che hai?” per quel che face chi guarda pur con l’occhio che non vede, quando disanimato il corpo giace; ma dimandai per darti forza al piede: così frugar conviensi i pigri, lenti ad usar lor vigilia quando riede». Noi andavam per lo vespero, attenti oltre quanto potean li occhi allungarsi contra i raggi serotini e lucenti. Ed ecco a poco a poco un fummo farsi verso di noi come la notte oscuro; né da quello era loco da cansarsi. Questo ne tolse li occhi e l’aere puro. Purgatorio · Canto XVI Buio d’inferno e di notte privata d’ogne pianeto, sotto pover cielo, quant’ esser può di nuvol tenebrata, non fece al viso mio sì grosso velo come quel fummo ch’ivi ci coperse, né a sentir di così aspro pelo, che l’occhio stare aperto non sofferse; onde la scorta mia saputa e fida mi s’accostò e l’omero m’offerse. Sì come cieco va dietro a sua guida per non smarrirsi e per non dar di cozzo in cosa che ’l molesti, o forse ancida, m’andava io per l’aere amaro e sozzo, ascoltando il mio duca che diceva pur: «Guarda che da me tu non sia mozzo». Io sentia voci, e ciascuna pareva pregar per pace e per misericordia l’Agnel di Dio che le peccata leva. Pur ‘Agnus Dei’ eran le loro essordia; una parola in tutte era e un modo, sì che parea tra esse ogne concordia. «Quei sono spirti, maestro, ch’i’ odo?», diss’ io. Ed elli a me: «Tu vero apprendi, e d’iracundia van solvendo il nodo». «Or tu chi se’ che ’l nostro fummo fendi, e di noi parli pur come se tue partissi ancor lo tempo per calendi?». Così per una voce detto fue; onde ’l maestro mio disse: «Rispondi, e domanda se quinci si va sùe». E io: «O creatura che ti mondi per tornar bella a colui che ti fece, maraviglia udirai, se mi secondi». «Io ti seguiterò quanto mi lece», rispuose; «e se veder fummo non lascia, l’udir ci terrà giunti in quella vece». Allora incominciai: «Con quella fascia che la morte dissolve men vo suso, e venni qui per l’infernale ambascia. E se Dio m’ha in sua grazia rinchiuso, tanto che vuol ch’i’ veggia la sua corte per modo tutto fuor del moderno uso, non mi celar chi fosti anzi la morte, ma dilmi, e dimmi s’i’ vo bene al varco; e tue parole fier le nostre scorte». «Lombardo fui, e fu’ chiamato Marco; del mondo seppi, e quel valore amai al quale ha or ciascun disteso l’arco. Per montar sù dirittamente vai». Così rispuose, e soggiunse: «I’ ti prego che per me prieghi quando sù sarai». E io a lui: «Per fede mi ti lego di far ciò che mi chiedi; ma io scoppio dentro ad un dubbio, s’io non me ne spiego. Prima era scempio, e ora è fatto doppio ne la sentenza tua, che mi fa certo qui, e altrove, quello ov’ io l’accoppio. Lo mondo è ben così tutto diserto d’ogne virtute, come tu mi sone, e di malizia gravido e coverto; ma priego che m’addite la cagione, sì ch’i’ la veggia e ch’i’ la mostri altrui; ché nel cielo uno, e un qua giù la pone». Alto sospir, che duolo strinse in «uhi!», mise fuor prima; e poi cominciò: «Frate, lo mondo è cieco, e tu vien ben da lui. Voi che vivete ogne cagion recate pur suso al cielo, pur come se tutto movesse seco di necessitate. Se così fosse, in voi fora distrutto libero arbitrio, e non fora giustizia per ben letizia, e per male aver lutto. Lo cielo i vostri movimenti inizia; non dico tutti, ma, posto ch’i’ ’l dica, lume v’è dato a bene e a malizia, e libero voler; che, se fatica ne le prime battaglie col ciel dura, poi vince tutto, se ben si notrica. A maggior forza e a miglior natura liberi soggiacete; e quella cria la mente in voi, che ’l ciel non ha in sua cura. Però, se ’l mondo presente disvia, in voi è la cagione, in voi si cheggia; e io te ne sarò or vera spia. Esce di mano a lui che la vagheggia prima che sia, a guisa di fanciulla che piangendo e ridendo pargoleggia, l’anima semplicetta che sa nulla, salvo che, mossa da lieto fattore, volontier torna a ciò che la trastulla. Di picciol bene in pria sente sapore; quivi s’inganna, e dietro ad esso corre, se guida o fren non torce suo amore. Onde convenne legge per fren porre; convenne rege aver, che discernesse de la vera cittade almen la torre. Le leggi son, ma chi pon mano ad esse? Nullo, però che ’l pastor che procede, rugumar può, ma non ha l’unghie fesse; per che la gente, che sua guida vede pur a quel ben fedire ond’ ella è ghiotta, di quel si pasce, e più oltre non chiede. Ben puoi veder che la mala condotta è la cagion che ’l mondo ha fatto reo, e non natura che ’n voi sia corrotta. Soleva Roma, che ’l buon mondo feo, due soli aver, che l’una e l’altra strada facean vedere, e del mondo e di Deo. L’un l’altro ha spento; ed è giunta la spada col pasturale, e l’un con l’altro insieme per viva forza mal convien che vada; però che, giunti, l’un l’altro non teme: se non mi credi, pon mente a la spiga, ch’ogn’ erba si conosce per lo seme. In sul paese ch’Adice e Po riga, solea valore e cortesia trovarsi, prima che Federigo avesse briga; or può sicuramente indi passarsi per qualunque lasciasse, per vergogna di ragionar coi buoni o d’appressarsi. Ben v’èn tre vecchi ancora in cui rampogna l’antica età la nova, e par lor tardo che Dio a miglior vita li ripogna: Currado da Palazzo e ’l buon Gherardo e Guido da Castel, che mei si noma, francescamente, il semplice Lombardo. Dì oggimai che la Chiesa di Roma, per confondere in sé due reggimenti, cade nel fango, e sé brutta e la soma». «O Marco mio», diss’ io, «bene argomenti; e or discerno perché dal retaggio li figli di Levì furono essenti. Ma qual Gherardo è quel che tu per saggio di’ ch’è rimaso de la gente spenta, in rimprovèro del secol selvaggio?». «O tuo parlar m’inganna, o el mi tenta», rispuose a me; «ché, parlandomi tosco, par che del buon Gherardo nulla senta. Per altro sopranome io nol conosco, s’io nol togliessi da sua figlia Gaia. Dio sia con voi, ché più non vegno vosco. Vedi l’albor che per lo fummo raia già biancheggiare, e me convien partirmi (l’angelo è ivi) prima ch’io li paia». Così tornò, e più non volle udirmi. Purgatorio · Canto XVII Ricorditi, lettor, se mai ne l’alpe ti colse nebbia per la qual vedessi non altrimenti che per pelle talpe, come, quando i vapori umidi e spessi a diradar cominciansi, la spera del sol debilemente entra per essi; e fia la tua imagine leggera in giugnere a veder com’ io rividi lo sole in pria, che già nel corcar era. Sì, pareggiando i miei co’ passi fidi del mio maestro, usci’ fuor di tal nube ai raggi morti già ne’ bassi lidi. O imaginativa che ne rube talvolta sì di fuor, ch’om non s’accorge perché dintorno suonin mille tube, chi move te, se ’l senso non ti porge? Moveti lume che nel ciel s’informa, per sé o per voler che giù lo scorge. De l’empiezza di lei che mutò forma ne l’uccel ch’a cantar più si diletta, ne l’imagine mia apparve l’orma; e qui fu la mia mente sì ristretta dentro da sé, che di fuor non venìa cosa che fosse allor da lei ricetta. Poi piovve dentro a l’alta fantasia un crucifisso, dispettoso e fero ne la sua vista, e cotal si moria; intorno ad esso era il grande Assüero, Estèr sua sposa e ’l giusto Mardoceo, che fu al dire e al far così intero. E come questa imagine rompeo sé per sé stessa, a guisa d’una bulla cui manca l’acqua sotto qual si feo, surse in mia visïone una fanciulla piangendo forte, e dicea: «O regina, perché per ira hai voluto esser nulla? Ancisa t’hai per non perder Lavina; or m’hai perduta! Io son essa che lutto, madre, a la tua pria ch’a l’altrui ruina». Come si frange il sonno ove di butto nova luce percuote il viso chiuso, che fratto guizza pria che muoia tutto; così l’imaginar mio cadde giuso tosto che lume il volto mi percosse, maggior assai che quel ch’è in nostro uso. I’ mi volgea per veder ov’ io fosse, quando una voce disse «Qui si monta», che da ogne altro intento mi rimosse; e fece la mia voglia tanto pronta di riguardar chi era che parlava, che mai non posa, se non si raffronta. Ma come al sol che nostra vista grava e per soverchio sua figura vela, così la mia virtù quivi mancava. «Questo è divino spirito, che ne la via da ir sù ne drizza sanza prego, e col suo lume sé medesmo cela. Sì fa con noi, come l’uom si fa sego; ché quale aspetta prego e l’uopo vede, malignamente già si mette al nego. Or accordiamo a tanto invito il piede; procacciam di salir pria che s’abbui, ché poi non si poria, se ’l dì non riede». Così disse il mio duca, e io con lui volgemmo i nostri passi ad una scala; e tosto ch’io al primo grado fui, senti’mi presso quasi un muover d’ala e ventarmi nel viso e dir: ‘Beati pacifici, che son sanz’ ira mala!’. Già eran sovra noi tanto levati li ultimi raggi che la notte segue, che le stelle apparivan da più lati. ‘O virtù mia, perché sì ti dilegue?’, fra me stesso dicea, ché mi sentiva la possa de le gambe posta in triegue. Noi eravam dove più non saliva la scala sù, ed eravamo affissi, pur come nave ch’a la piaggia arriva. E io attesi un poco, s’io udissi alcuna cosa nel novo girone; poi mi volsi al maestro mio, e dissi: «Dolce mio padre, dì, quale offensione si purga qui nel giro dove semo? Se i piè si stanno, non stea tuo sermone». Ed elli a me: «L’amor del bene, scemo del suo dover, quiritta si ristora; qui si ribatte il mal tardato remo. Ma perché più aperto intendi ancora, volgi la mente a me, e prenderai alcun buon frutto di nostra dimora». «Né creator né creatura mai», cominciò el, «figliuol, fu sanza amore, o naturale o d’animo; e tu ’l sai. Lo naturale è sempre sanza errore, ma l’altro puote errar per malo obietto o per troppo o per poco di vigore. Mentre ch’elli è nel primo ben diretto, e ne’ secondi sé stesso misura, esser non può cagion di mal diletto; ma quando al mal si torce, o con più cura o con men che non dee corre nel bene, contra ’l fattore adovra sua fattura. Quinci comprender puoi ch’esser convene amor sementa in voi d’ogne virtute e d’ogne operazion che merta pene. Or, perché mai non può da la salute amor del suo subietto volger viso, da l’odio proprio son le cose tute; e perché intender non si può diviso, e per sé stante, alcuno esser dal primo, da quello odiare ogne effetto è deciso. Resta, se dividendo bene stimo, che ’l mal che s’ama è del prossimo; ed esso amor nasce in tre modi in vostro limo. È chi, per esser suo vicin soppresso, spera eccellenza, e sol per questo brama ch’el sia di sua grandezza in basso messo; è chi podere, grazia, onore e fama teme di perder perch’ altri sormonti, onde s’attrista sì che ’l contrario ama; ed è chi per ingiuria par ch’aonti, sì che si fa de la vendetta ghiotto, e tal convien che ’l male altrui impronti. Questo triforme amor qua giù di sotto si piange: or vo’ che tu de l’altro intende, che corre al ben con ordine corrotto. Ciascun confusamente un bene apprende nel qual si queti l’animo, e disira; per che di giugner lui ciascun contende. Se lento amore a lui veder vi tira o a lui acquistar, questa cornice, dopo giusto penter, ve ne martira. Altro ben è che non fa l’uom felice; non è felicità, non è la buona essenza, d’ogne ben frutto e radice. L’amor ch’ad esso troppo s’abbandona, di sovr’ a noi si piange per tre cerchi; ma come tripartito si ragiona, tacciolo, acciò che tu per te ne cerchi». Purgatorio · Canto XVIII Posto avea fine al suo ragionamento l’alto dottore, e attento guardava ne la mia vista s’io parea contento; e io, cui nova sete ancor frugava, di fuor tacea, e dentro dicea: ‘Forse lo troppo dimandar ch’io fo li grava’. Ma quel padre verace, che s’accorse del timido voler che non s’apriva, parlando, di parlare ardir mi porse. Ond’ io: «Maestro, il mio veder s’avviva sì nel tuo lume, ch’io discerno chiaro quanto la tua ragion parta o descriva. Però ti prego, dolce padre caro, che mi dimostri amore, a cui reduci ogne buono operare e ’l suo contraro». «Drizza», disse, «ver’ me l’agute luci de lo ’ntelletto, e fieti manifesto l’error de’ ciechi che si fanno duci. L’animo, ch’è creato ad amar presto, ad ogne cosa è mobile che piace, tosto che dal piacere in atto è desto. Vostra apprensiva da esser verace tragge intenzione, e dentro a voi la spiega, sì che l’animo ad essa volger face; e se, rivolto, inver’ di lei si piega, quel piegare è amor, quell’ è natura che per piacer di novo in voi si lega. Poi, come ’l foco movesi in altura per la sua forma ch’è nata a salire là dove più in sua matera dura, così l’animo preso entra in disire, ch’è moto spiritale, e mai non posa fin che la cosa amata il fa gioire. Or ti puote apparer quant’ è nascosa la veritate a la gente ch’avvera ciascun amore in sé laudabil cosa; però che forse appar la sua matera sempre esser buona, ma non ciascun segno è buono, ancor che buona sia la cera». «Le tue parole e ’l mio seguace ingegno», rispuos’ io lui, «m’hanno amor discoverto, ma ciò m’ha fatto di dubbiar più pregno; ché, s’amore è di fuori a noi offerto e l’anima non va con altro piede, se dritta o torta va, non è suo merto». Ed elli a me: «Quanto ragion qui vede, dir ti poss’ io; da indi in là t’aspetta pur a Beatrice, ch’è opra di fede. Ogne forma sustanzïal, che setta è da matera ed è con lei unita, specifica vertute ha in sé colletta, la qual sanza operar non è sentita, né si dimostra mai che per effetto, come per verdi fronde in pianta vita. Però, là onde vegna lo ’ntelletto de le prime notizie, omo non sape, e de’ primi appetibili l’affetto, che sono in voi sì come studio in ape di far lo mele; e questa prima voglia merto di lode o di biasmo non cape. Or perché a questa ogn’ altra si raccoglia, innata v’è la virtù che consiglia, e de l’assenso de’ tener la soglia. Quest’ è ’l principio là onde si piglia ragion di meritare in voi, secondo che buoni e rei amori accoglie e viglia. Color che ragionando andaro al fondo, s’accorser d’esta innata libertate; però moralità lasciaro al mondo. Onde, poniam che di necessitate surga ogne amor che dentro a voi s’accende, di ritenerlo è in voi la podestate. La nobile virtù Beatrice intende per lo libero arbitrio, e però guarda che l’abbi a mente, s’a parlar ten prende». La luna, quasi a mezza notte tarda, facea le stelle a noi parer più rade, fatta com’ un secchion che tuttor arda; e correa contro ’l ciel per quelle strade che ’l sole infiamma allor che quel da Roma tra ’ Sardi e ’ Corsi il vede quando cade. E quell’ ombra gentil per cui si noma Pietola più che villa mantoana, del mio carcar diposta avea la soma; per ch’io, che la ragione aperta e piana sovra le mie quistioni avea ricolta, stava com’ om che sonnolento vana. Ma questa sonnolenza mi fu tolta subitamente da gente che dopo le nostre spalle a noi era già volta. E quale Ismeno già vide e Asopo lungo di sè di notte furia e calca, pur che i Teban di Bacco avesser uopo, cotal per quel giron suo passo falca, per quel ch’io vidi di color, venendo, cui buon volere e giusto amor cavalca. Tosto fur sovr’ a noi, perché correndo si movea tutta quella turba magna; e due dinanzi gridavan piangendo: «Maria corse con fretta a la montagna; e Cesare, per soggiogare Ilerda, punse Marsilia e poi corse in Ispagna». «Ratto, ratto, che ’l tempo non si perda per poco amor», gridavan li altri appresso, «che studio di ben far grazia rinverda». «O gente in cui fervore aguto adesso ricompie forse negligenza e indugio da voi per tepidezza in ben far messo, questi che vive, e certo i’ non vi bugio, vuole andar sù, pur che ’l sol ne riluca; però ne dite ond’ è presso il pertugio». Parole furon queste del mio duca; e un di quelli spirti disse: «Vieni di retro a noi, e troverai la buca. Noi siam di voglia a muoverci sì pieni, che restar non potem; però perdona, se villania nostra giustizia tieni. Io fui abate in San Zeno a Verona sotto lo ’mperio del buon Barbarossa, di cui dolente ancor Milan ragiona. E tale ha già l’un piè dentro la fossa, che tosto piangerà quel monastero, e tristo fia d’avere avuta possa; perché suo figlio, mal del corpo intero, e de la mente peggio, e che mal nacque, ha posto in loco di suo pastor vero». Io non so se più disse o s’ei si tacque, tant’ era già di là da noi trascorso; ma questo intesi, e ritener mi piacque. E quei che m’era ad ogne uopo soccorso disse: «Volgiti qua: vedine due venir dando a l’accidïa di morso». Di retro a tutti dicean: «Prima fue morta la gente a cui il mar s’aperse, che vedesse Iordan le rede sue. E quella che l’affanno non sofferse fino a la fine col figlio d’Anchise, sé stessa a vita sanza gloria offerse». Poi quando fuor da noi tanto divise quell’ ombre, che veder più non potiersi, novo pensiero dentro a me si mise, del qual più altri nacquero e diversi; e tanto d’uno in altro vaneggiai, che li occhi per vaghezza ricopersi, e ’l pensamento in sogno trasmutai. Purgatorio · Canto XIX Ne l’ora che non può ’l calor dïurno intepidar più ’l freddo de la luna, vinto da terra, e talor da Saturno —quando i geomanti lor Maggior Fortuna veggiono in orïente, innanzi a l’alba, surger per via che poco le sta bruna—, mi venne in sogno una femmina balba, ne li occhi guercia, e sovra i piè distorta, con le man monche, e di colore scialba. Io la mirava; e come ’l sol conforta le fredde membra che la notte aggrava, così lo sguardo mio le facea scorta la lingua, e poscia tutta la drizzava in poco d’ora, e lo smarrito volto, com’ amor vuol, così le colorava. Poi ch’ell’ avea ’l parlar così disciolto, cominciava a cantar sì, che con pena da lei avrei mio intento rivolto. «Io son», cantava, «io son dolce serena, che ’ marinari in mezzo mar dismago; tanto son di piacere a sentir piena! Io volsi Ulisse del suo cammin vago al canto mio; e qual meco s’ausa, rado sen parte; sì tutto l’appago!». Ancor non era sua bocca richiusa, quand’ una donna apparve santa e presta lunghesso me per far colei confusa. «O Virgilio, Virgilio, chi è questa?», fieramente dicea; ed el venìa con li occhi fitti pur in quella onesta. L’altra prendea, e dinanzi l’apria fendendo i drappi, e mostravami ’l ventre; quel mi svegliò col puzzo che n’uscia. Io mossi li occhi, e ’l buon maestro: «Almen tre voci t’ho messe!», dicea, «Surgi e vieni; troviam l’aperta per la qual tu entre». Sù mi levai, e tutti eran già pieni de l’alto dì i giron del sacro monte, e andavam col sol novo a le reni. Seguendo lui, portava la mia fronte come colui che l’ha di pensier carca, che fa di sé un mezzo arco di ponte; quand’ io udi’ «Venite; qui si varca» parlare in modo soave e benigno, qual non si sente in questa mortal marca. Con l’ali aperte, che parean di cigno, volseci in sù colui che sì parlonne tra due pareti del duro macigno. Mosse le penne poi e ventilonne, ‘Qui lugent’ affermando esser beati, ch’avran di consolar l’anime donne. «Che hai che pur inver’ la terra guati?», la guida mia incominciò a dirmi, poco amendue da l’angel sormontati. E io: «Con tanta sospeccion fa irmi novella visïon ch’a sé mi piega, sì ch’io non posso dal pensar partirmi». «Vedesti», disse, «quell’antica strega che sola sovr’ a noi omai si piagne; vedesti come l’uom da lei si slega. Bastiti, e batti a terra le calcagne; li occhi rivolgi al logoro che gira lo rege etterno con le rote magne». Quale ’l falcon, che prima a’ pié si mira, indi si volge al grido e si protende per lo disio del pasto che là il tira, tal mi fec’ io; e tal, quanto si fende la roccia per dar via a chi va suso, n’andai infin dove ’l cerchiar si prende. Com’ io nel quinto giro fui dischiuso, vidi gente per esso che piangea, giacendo a terra tutta volta in giuso. ‘Adhaesit pavimento anima mea’ sentia dir lor con sì alti sospiri, che la parola a pena s’intendea. «O eletti di Dio, li cui soffriri e giustizia e speranza fa men duri, drizzate noi verso li alti saliri». «Se voi venite dal giacer sicuri, e volete trovar la via più tosto, le vostre destre sien sempre di fori». Così pregò ’l poeta, e sì risposto poco dinanzi a noi ne fu; per ch’io nel parlare avvisai l’altro nascosto, e volsi li occhi a li occhi al segnor mio: ond’ elli m’assentì con lieto cenno ciò che chiedea la vista del disio. Poi ch’io potei di me fare a mio senno, trassimi sovra quella creatura le cui parole pria notar mi fenno, dicendo: «Spirto in cui pianger matura quel sanza ’l quale a Dio tornar non pòssi, sosta un poco per me tua maggior cura. Chi fosti e perché vòlti avete i dossi al sù, mi dì, e se vuo’ ch’io t’impetri cosa di là ond’ io vivendo mossi». Ed elli a me: «Perché i nostri diretri rivolga il cielo a sé, saprai; ma prima scias quod ego fui successor Petri. Intra Sïestri e Chiaveri s’adima una fiumana bella, e del suo nome lo titol del mio sangue fa sua cima. Un mese e poco più prova’ io come pesa il gran manto a chi dal fango il guarda, che piuma sembran tutte l’altre some. La mia conversïone, omè!, fu tarda; ma, come fatto fui roman pastore, così scopersi la vita bugiarda. Vidi che lì non s’acquetava il core, né più salir potiesi in quella vita; per che di questa in me s’accese amore. Fino a quel punto misera e partita da Dio anima fui, del tutto avara; or, come vedi, qui ne son punita. Quel ch’avarizia fa, qui si dichiara in purgazion de l’anime converse; e nulla pena il monte ha più amara. Sì come l’occhio nostro non s’aderse in alto, fisso a le cose terrene, così giustizia qui a terra il merse. Come avarizia spense a ciascun bene lo nostro amore, onde operar perdési, così giustizia qui stretti ne tene, ne’ piedi e ne le man legati e presi; e quanto fia piacer del giusto Sire, tanto staremo immobili e distesi». Io m’era inginocchiato e volea dire; ma com’ io cominciai ed el s’accorse, solo ascoltando, del mio reverire, «Qual cagion», disse, «in giù così ti torse?». E io a lui: «Per vostra dignitate mia coscïenza dritto mi rimorse». «Drizza le gambe, lèvati sù, frate!», rispuose; «non errar: conservo sono teco e con li altri ad una podestate. Se mai quel santo evangelico suono che dice ‘Neque nubent’ intendesti, ben puoi veder perch’ io così ragiono. Vattene omai: non vo’ che più t’arresti; ché la tua stanza mio pianger disagia, col qual maturo ciò che tu dicesti. Nepote ho io di là c’ha nome Alagia, buona da sé, pur che la nostra casa non faccia lei per essempro malvagia; e questa sola di là m’è rimasa». Purgatorio · Canto XX Contra miglior voler voler mal pugna; onde contra ’l piacer mio, per piacerli, trassi de l’acqua non sazia la spugna. Mossimi; e ’l duca mio si mosse per li luoghi spediti pur lungo la roccia, come si va per muro stretto a’ merli; ché la gente che fonde a goccia a goccia per li occhi il mal che tutto ’l mondo occupa, da l’altra parte in fuor troppo s’approccia. Maladetta sie tu, antica lupa, che più che tutte l’altre bestie hai preda per la tua fame sanza fine cupa! O ciel, nel cui girar par che si creda le condizion di qua giù trasmutarsi, quando verrà per cui questa disceda? Noi andavam con passi lenti e scarsi, e io attento a l’ombre, ch’i’ sentia pietosamente piangere e lagnarsi; e per ventura udi’ «Dolce Maria!» dinanzi a noi chiamar così nel pianto come fa donna che in parturir sia; e seguitar: «Povera fosti tanto, quanto veder si può per quello ospizio dove sponesti il tuo portato santo». Seguentemente intesi: «O buon Fabrizio, con povertà volesti anzi virtute che gran ricchezza posseder con vizio». Queste parole m’eran sì piaciute, ch’io mi trassi oltre per aver contezza di quello spirto onde parean venute. Esso parlava ancor de la larghezza che fece Niccolò a le pulcelle, per condurre ad onor lor giovinezza. «O anima che tanto ben favelle, dimmi chi fosti», dissi, «e perché sola tu queste degne lode rinovelle. Non fia sanza mercé la tua parola, s’io ritorno a compiér lo cammin corto di quella vita ch’al termine vola». Ed elli: «Io ti dirò, non per conforto ch’io attenda di là, ma perché tanta grazia in te luce prima che sie morto. Io fui radice de la mala pianta che la terra cristiana tutta aduggia, sì che buon frutto rado se ne schianta. Ma se Doagio, Lilla, Guanto e Bruggia potesser, tosto ne saria vendetta; e io la cheggio a lui che tutto giuggia. Chiamato fui di là Ugo Ciappetta; di me son nati i Filippi e i Luigi per cui novellamente è Francia retta. Figliuol fu’ io d’un beccaio di Parigi: quando li regi antichi venner meno tutti, fuor ch’un renduto in panni bigi, trova’mi stretto ne le mani il freno del governo del regno, e tanta possa di nuovo acquisto, e sì d’amici pieno, ch’a la corona vedova promossa la testa di mio figlio fu, dal quale cominciar di costor le sacrate ossa. Mentre che la gran dota provenzale al sangue mio non tolse la vergogna, poco valea, ma pur non facea male. Lì cominciò con forza e con menzogna la sua rapina; e poscia, per ammenda, Pontì e Normandia prese e Guascogna. Carlo venne in Italia e, per ammenda, vittima fé di Curradino; e poi ripinse al ciel Tommaso, per ammenda. Tempo vegg’ io, non molto dopo ancoi, che tragge un altro Carlo fuor di Francia, per far conoscer meglio e sé e ’ suoi. Sanz’ arme n’esce e solo con la lancia con la qual giostrò Giuda, e quella ponta sì, ch’a Fiorenza fa scoppiar la pancia. Quindi non terra, ma peccato e onta guadagnerà, per sé tanto più grave, quanto più lieve simil danno conta. L’altro, che già uscì preso di nave, veggio vender sua figlia e patteggiarne come fanno i corsar de l’altre schiave. O avarizia, che puoi tu più farne, poscia c’ha’ il mio sangue a te sì tratto, che non si cura de la propria carne? Perché men paia il mal futuro e ’l fatto, veggio in Alagna intrar lo fiordaliso, e nel vicario suo Cristo esser catto. Veggiolo un’altra volta esser deriso; veggio rinovellar l’aceto e ’l fiele, e tra vivi ladroni esser anciso. Veggio il novo Pilato sì crudele, che ciò nol sazia, ma sanza decreto portar nel Tempio le cupide vele. O Segnor mio, quando sarò io lieto a veder la vendetta che, nascosa, fa dolce l’ira tua nel tuo secreto? Ciò ch’io dicea di quell’ unica sposa de lo Spirito Santo e che ti fece verso me volger per alcuna chiosa, tanto è risposto a tutte nostre prece quanto ’l dì dura; ma com’ el s’annotta, contrario suon prendemo in quella vece. Noi repetiam Pigmalïon allotta, cui traditore e ladro e paricida fece la voglia sua de l’oro ghiotta; e la miseria de l’avaro Mida, che seguì a la sua dimanda gorda, per la qual sempre convien che si rida. Del folle Acàn ciascun poi si ricorda, come furò le spoglie, sì che l’ira di Iosüè qui par ch’ancor lo morda. Indi accusiam col marito Saffira; lodiam i calci ch’ebbe Elïodoro; e in infamia tutto ’l monte gira Polinestòr ch’ancise Polidoro; ultimamente ci si grida: “Crasso, dilci, che ’l sai: di che sapore è l’oro?”. Talor parla l’uno alto e l’altro basso, secondo l’affezion ch’ad ir ci sprona ora a maggiore e ora a minor passo: però al ben che ’l dì ci si ragiona, dianzi non era io sol; ma qui da presso non alzava la voce altra persona». Noi eravam partiti già da esso, e brigavam di soverchiar la strada tanto quanto al poder n’era permesso, quand’ io senti’, come cosa che cada, tremar lo monte; onde mi prese un gelo qual prender suol colui ch’a morte vada. Certo non si scoteo sì forte Delo, pria che Latona in lei facesse ’l nido a parturir li due occhi del cielo. Poi cominciò da tutte parti un grido tal, che ’l maestro inverso me si feo, dicendo: «Non dubbiar, mentr’ io ti guido». ‘Glorïa in excelsis’ tutti ‘Deo’ dicean, per quel ch’io da’ vicin compresi, onde intender lo grido si poteo. No’ istavamo immobili e sospesi come i pastor che prima udir quel canto, fin che ’l tremar cessò ed el compiési. Poi ripigliammo nostro cammin santo, guardando l’ombre che giacean per terra, tornate già in su l’usato pianto. Nulla ignoranza mai con tanta guerra mi fé desideroso di sapere, se la memoria mia in ciò non erra, quanta pareami allor, pensando, avere; né per la fretta dimandare er’ oso, né per me lì potea cosa vedere: così m’andava timido e pensoso. Purgatorio · Canto XXI La sete natural che mai non sazia se non con l’acqua onde la femminetta samaritana domandò la grazia, mi travagliava, e pungeami la fretta per la ’mpacciata via dietro al mio duca, e condoleami a la giusta vendetta. Ed ecco, sì come ne scrive Luca che Cristo apparve a’ due ch’erano in via, già surto fuor de la sepulcral buca, ci apparve un’ombra, e dietro a noi venìa, dal piè guardando la turba che giace; né ci addemmo di lei, sì parlò pria, dicendo: «O frati miei, Dio vi dea pace». Noi ci volgemmo sùbiti, e Virgilio rendéli ’l cenno ch’a ciò si conface. Poi cominciò: «Nel beato concilio ti ponga in pace la verace corte che me rilega ne l’etterno essilio». «Come!», diss’ elli, e parte andavam forte: «se voi siete ombre che Dio sù non degni, chi v’ha per la sua scala tanto scorte?». E ’l dottor mio: «Se tu riguardi a’ segni che questi porta e che l’angel profila, ben vedrai che coi buon convien ch’e’ regni. Ma perché lei che dì e notte fila non li avea tratta ancora la conocchia che Cloto impone a ciascuno e compila, l’anima sua, ch’è tua e mia serocchia, venendo sù, non potea venir sola, però ch’al nostro modo non adocchia. Ond’ io fui tratto fuor de l’ampia gola d’inferno per mostrarli, e mosterrolli oltre, quanto ’l potrà menar mia scola. Ma dimmi, se tu sai, perché tai crolli diè dianzi ’l monte, e perché tutto ad una parve gridare infino a’ suoi piè molli». Sì mi diè, dimandando, per la cruna del mio disio, che pur con la speranza si fece la mia sete men digiuna. Quei cominciò: «Cosa non è che sanza ordine senta la religïone de la montagna, o che sia fuor d’usanza. Libero è qui da ogne alterazione: di quel che ’l ciel da sé in sé riceve esser ci puote, e non d’altro, cagione. Per che non pioggia, non grando, non neve, non rugiada, non brina più sù cade che la scaletta di tre gradi breve; nuvole spesse non paion né rade, né coruscar, né figlia di Taumante, che di là cangia sovente contrade; secco vapor non surge più avante ch’al sommo d’i tre gradi ch’io parlai, dov’ ha ’l vicario di Pietro le piante. Trema forse più giù poco o assai; ma per vento che ’n terra si nasconda, non so come, qua sù non tremò mai. Tremaci quando alcuna anima monda sentesi, sì che surga o che si mova per salir sù; e tal grido seconda. De la mondizia sol voler fa prova, che, tutto libero a mutar convento, l’alma sorprende, e di voler le giova. Prima vuol ben, ma non lascia il talento che divina giustizia, contra voglia, come fu al peccar, pone al tormento. E io, che son giaciuto a questa doglia cinquecent’ anni e più, pur mo sentii libera volontà di miglior soglia: però sentisti il tremoto e li pii spiriti per lo monte render lode a quel Segnor, che tosto sù li ’nvii». Così ne disse; e però ch’el si gode tanto del ber quant’ è grande la sete, non saprei dir quant’ el mi fece prode. E ’l savio duca: «Omai veggio la rete che qui vi ’mpiglia e come si scalappia, perché ci trema e di che congaudete. Ora chi fosti, piacciati ch’io sappia, e perché tanti secoli giaciuto qui se’, ne le parole tue mi cappia». «Nel tempo che ’l buon Tito, con l’aiuto del sommo rege, vendicò le fóra ond’ uscì ’l sangue per Giuda venduto, col nome che più dura e più onora era io di là», rispuose quello spirto, «famoso assai, ma non con fede ancora. Tanto fu dolce mio vocale spirto, che, tolosano, a sé mi trasse Roma, dove mertai le tempie ornar di mirto. Stazio la gente ancor di là mi noma: cantai di Tebe, e poi del grande Achille; ma caddi in via con la seconda soma. Al mio ardor fuor seme le faville, che mi scaldar, de la divina fiamma onde sono allumati più di mille; de l’Eneïda dico, la qual mamma fummi, e fummi nutrice, poetando: sanz’ essa non fermai peso di dramma. E per esser vivuto di là quando visse Virgilio, assentirei un sole più che non deggio al mio uscir di bando». Volser Virgilio a me queste parole con viso che, tacendo, disse ‘Taci’; ma non può tutto la virtù che vuole; ché riso e pianto son tanto seguaci a la passion di che ciascun si spicca, che men seguon voler ne’ più veraci. Io pur sorrisi come l’uom ch’ammicca; per che l’ombra si tacque, e riguardommi ne li occhi ove ’l sembiante più si ficca; e «Se tanto labore in bene assommi», disse, «perché la tua faccia testeso un lampeggiar di riso dimostrommi?». Or son io d’una parte e d’altra preso: l’una mi fa tacer, l’altra scongiura ch’io dica; ond’ io sospiro, e sono inteso dal mio maestro, e «Non aver paura», mi dice, «di parlar; ma parla e digli quel ch’e’ dimanda con cotanta cura». Ond’ io: «Forse che tu ti maravigli, antico spirto, del rider ch’io fei; ma più d’ammirazion vo’ che ti pigli. Questi che guida in alto li occhi miei, è quel Virgilio dal qual tu togliesti forte a cantar de li uomini e d’i dèi. Se cagion altra al mio rider credesti, lasciala per non vera, ed esser credi quelle parole che di lui dicesti». Già s’inchinava ad abbracciar li piedi al mio dottor, ma el li disse: «Frate, non far, ché tu se’ ombra e ombra vedi». Ed ei surgendo: «Or puoi la quantitate comprender de l’amor ch’a te mi scalda, quand’ io dismento nostra vanitate, trattando l’ombre come cosa salda». Purgatorio · Canto XXII Già era l’angel dietro a noi rimaso, l’angel che n’avea vòlti al sesto giro, avendomi dal viso un colpo raso; e quei c’hanno a giustizia lor disiro detto n’avea beati, e le sue voci con ‘sitiunt’, sanz’ altro, ciò forniro. E io più lieve che per l’altre foci m’andava, sì che sanz’ alcun labore seguiva in sù li spiriti veloci; quando Virgilio incominciò: «Amore, acceso di virtù, sempre altro accese, pur che la fiamma sua paresse fore; onde da l’ora che tra noi discese nel limbo de lo ’nferno Giovenale, che la tua affezion mi fé palese, mia benvoglienza inverso te fu quale più strinse mai di non vista persona, sì ch’or mi parran corte queste scale. Ma dimmi, e come amico mi perdona se troppa sicurtà m’allarga il freno, e come amico omai meco ragiona: come poté trovar dentro al tuo seno loco avarizia, tra cotanto senno di quanto per tua cura fosti pieno?». Queste parole Stazio mover fenno un poco a riso pria; poscia rispuose: «Ogne tuo dir d’amor m’è caro cenno. Veramente più volte appaion cose che danno a dubitar falsa matera per le vere ragion che son nascose. La tua dimanda tuo creder m’avvera esser ch’i’ fossi avaro in l’altra vita, forse per quella cerchia dov’ io era. Or sappi ch’avarizia fu partita troppo da me, e questa dismisura migliaia di lunari hanno punita. E se non fosse ch’io drizzai mia cura, quand’ io intesi là dove tu chiame, crucciato quasi a l’umana natura: ‘Per che non reggi tu, o sacra fame de l’oro, l’appetito de’ mortali?’, voltando sentirei le giostre grame. Allor m’accorsi che troppo aprir l’ali potean le mani a spendere, e pente’mi così di quel come de li altri mali. Quanti risurgeran coi crini scemi per ignoranza, che di questa pecca toglie ’l penter vivendo e ne li stremi! E sappie che la colpa che rimbecca per dritta opposizione alcun peccato, con esso insieme qui suo verde secca; però, s’io son tra quella gente stato che piange l’avarizia, per purgarmi, per lo contrario suo m’è incontrato». «Or quando tu cantasti le crude armi de la doppia trestizia di Giocasta», disse ’l cantor de’ buccolici carmi, «per quello che Clïò teco lì tasta, non par che ti facesse ancor fedele la fede, sanza qual ben far non basta. Se così è, qual sole o quai candele ti stenebraron sì, che tu drizzasti poscia di retro al pescator le vele?». Ed elli a lui: «Tu prima m’invïasti verso Parnaso a ber ne le sue grotte, e prima appresso Dio m’alluminasti. Facesti come quei che va di notte, che porta il lume dietro e sé non giova, ma dopo sé fa le persone dotte, quando dicesti: ‘Secol si rinova; torna giustizia e primo tempo umano, e progenïe scende da ciel nova’. Per te poeta fui, per te cristiano: ma perché veggi mei ciò ch’io disegno, a colorare stenderò la mano. Già era ’l mondo tutto quanto pregno de la vera credenza, seminata per li messaggi de l’etterno regno; e la parola tua sopra toccata si consonava a’ nuovi predicanti; ond’ io a visitarli presi usata. Vennermi poi parendo tanto santi, che, quando Domizian li perseguette, sanza mio lagrimar non fur lor pianti; e mentre che di là per me si stette, io li sovvenni, e i lor dritti costumi fer dispregiare a me tutte altre sette. E pria ch’io conducessi i Greci a’ fiumi di Tebe poetando, ebb’ io battesmo; ma per paura chiuso cristian fu’mi, lungamente mostrando paganesmo; e questa tepidezza il quarto cerchio cerchiar mi fé più che ’l quarto centesmo. Tu dunque, che levato hai il coperchio che m’ascondeva quanto bene io dico, mentre che del salire avem soverchio, dimmi dov’ è Terrenzio nostro antico, Cecilio e Plauto e Varro, se lo sai: dimmi se son dannati, e in qual vico». «Costoro e Persio e io e altri assai», rispuose il duca mio, «siam con quel Greco che le Muse lattar più ch’altri mai, nel primo cinghio del carcere cieco; spesse fïate ragioniam del monte che sempre ha le nutrice nostre seco. Euripide v’è nosco e Antifonte, Simonide, Agatone e altri piùe Greci che già di lauro ornar la fronte. Quivi si veggion de le genti tue Antigone, Deïfile e Argia, e Ismene sì trista come fue. Védeisi quella che mostrò Langia; èvvi la figlia di Tiresia, e Teti, e con le suore sue Deïdamia». Tacevansi ambedue già li poeti, di novo attenti a riguardar dintorno, liberi da saliri e da pareti; e già le quattro ancelle eran del giorno rimase a dietro, e la quinta era al temo, drizzando pur in sù l’ardente corno, quando il mio duca: «Io credo ch’a lo stremo le destre spalle volger ne convegna, girando il monte come far solemo». Così l’usanza fu lì nostra insegna, e prendemmo la via con men sospetto per l’assentir di quell’ anima degna. Elli givan dinanzi, e io soletto di retro, e ascoltava i lor sermoni, ch’a poetar mi davano intelletto. Ma tosto ruppe le dolci ragioni un alber che trovammo in mezza strada, con pomi a odorar soavi e buoni; e come abete in alto si digrada di ramo in ramo, così quello in giuso, cred’ io, perché persona sù non vada. Dal lato onde ’l cammin nostro era chiuso, cadea de l’alta roccia un liquor chiaro e si spandeva per le foglie suso. Li due poeti a l’alber s’appressaro; e una voce per entro le fronde gridò: «Di questo cibo avrete caro». Poi disse: «Più pensava Maria onde fosser le nozze orrevoli e intere, ch’a la sua bocca, ch’or per voi risponde. E le Romane antiche, per lor bere, contente furon d’acqua; e Danïello dispregiò cibo e acquistò savere. Lo secol primo, quant’ oro fu bello, fé savorose con fame le ghiande, e nettare con sete ogne ruscello. Mele e locuste furon le vivande che nodriro il Batista nel diserto; per ch’elli è glorïoso e tanto grande quanto per lo Vangelio v’è aperto». Purgatorio · Canto XXIII Mentre che li occhi per la fronda verde ficcava ïo sì come far suole chi dietro a li uccellin sua vita perde, lo più che padre mi dicea: «Figliuole, vienne oramai, ché ’l tempo che n’è imposto più utilmente compartir si vuole». Io volsi ’l viso, e ’l passo non men tosto, appresso i savi, che parlavan sìe, che l’andar mi facean di nullo costo. Ed ecco piangere e cantar s’udìe ‘Labïa mëa, Domine’ per modo tal, che diletto e doglia parturìe. «O dolce padre, che è quel ch’i’ odo?», comincia’ io; ed elli: «Ombre che vanno forse di lor dover solvendo il nodo». Sì come i peregrin pensosi fanno, giugnendo per cammin gente non nota, che si volgono ad essa e non restanno, così di retro a noi, più tosto mota, venendo e trapassando ci ammirava d’anime turba tacita e devota. Ne li occhi era ciascuna oscura e cava, palida ne la faccia, e tanto scema che da l’ossa la pelle s’informava. Non credo che così a buccia strema Erisittone fosse fatto secco, per digiunar, quando più n’ebbe tema. Io dicea fra me stesso pensando: ‘Ecco la gente che perdé Ierusalemme, quando Maria nel figlio diè di becco!’ Parean l’occhiaie anella sanza gemme: chi nel viso de li uomini legge ‘omo’ ben avria quivi conosciuta l’emme. Chi crederebbe che l’odor d’un pomo sì governasse, generando brama, e quel d’un’acqua, non sappiendo como? Già era in ammirar che sì li affama, per la cagione ancor non manifesta di lor magrezza e di lor trista squama, ed ecco del profondo de la testa volse a me li occhi un’ombra e guardò fiso; poi gridò forte: «Qual grazia m’è questa?». Mai non l’avrei riconosciuto al viso; ma ne la voce sua mi fu palese ciò che l’aspetto in sé avea conquiso. Questa favilla tutta mi raccese mia conoscenza a la cangiata labbia, e ravvisai la faccia di Forese. «Deh, non contendere a l’asciutta scabbia che mi scolora», pregava, «la pelle, né a difetto di carne ch’io abbia; ma dimmi il ver di te, dì chi son quelle due anime che là ti fanno scorta; non rimaner che tu non mi favelle!». «La faccia tua, ch’io lagrimai già morta, mi dà di pianger mo non minor doglia», rispuos’ io lui, «veggendola sì torta. Però mi dì, per Dio, che sì vi sfoglia; non mi far dir mentr’ io mi maraviglio, ché mal può dir chi è pien d’altra voglia». Ed elli a me: «De l’etterno consiglio cade vertù ne l’acqua e ne la pianta rimasa dietro ond’ io sì m’assottiglio. Tutta esta gente che piangendo canta per seguitar la gola oltra misura, in fame e ’n sete qui si rifà santa. Di bere e di mangiar n’accende cura l’odor ch’esce del pomo e de lo sprazzo che si distende su per sua verdura. E non pur una volta, questo spazzo girando, si rinfresca nostra pena: io dico pena, e dovria dir sollazzo, ché quella voglia a li alberi ci mena che menò Cristo lieto a dire ‘Elì’, quando ne liberò con la sua vena». E io a lui: «Forese, da quel dì nel qual mutasti mondo a miglior vita, cinqu’ anni non son vòlti infino a qui. Se prima fu la possa in te finita di peccar più, che sovvenisse l’ora del buon dolor ch’a Dio ne rimarita, come se’ tu qua sù venuto ancora? Io ti credea trovar là giù di sotto, dove tempo per tempo si ristora». Ond’ elli a me: «Sì tosto m’ha condotto a ber lo dolce assenzo d’i martìri la Nella mia con suo pianger dirotto. Con suoi prieghi devoti e con sospiri tratto m’ha de la costa ove s’aspetta, e liberato m’ha de li altri giri. Tanto è a Dio più cara e più diletta la vedovella mia, che molto amai, quanto in bene operare è più soletta; ché la Barbagia di Sardigna assai ne le femmine sue più è pudica che la Barbagia dov’ io la lasciai. O dolce frate, che vuo’ tu ch’io dica? Tempo futuro m’è già nel cospetto, cui non sarà quest’ ora molto antica, nel qual sarà in pergamo interdetto a le sfacciate donne fiorentine l’andar mostrando con le poppe il petto. Quai barbare fuor mai, quai saracine, cui bisognasse, per farle ir coperte, o spiritali o altre discipline? Ma se le svergognate fosser certe di quel che ’l ciel veloce loro ammanna, già per urlare avrian le bocche aperte; ché, se l’antiveder qui non m’inganna, prima fien triste che le guance impeli colui che mo si consola con nanna. Deh, frate, or fa che più non mi ti celi! vedi che non pur io, ma questa gente tutta rimira là dove ’l sol veli». Per ch’io a lui: «Se tu riduci a mente qual fosti meco, e qual io teco fui, ancor fia grave il memorar presente. Di quella vita mi volse costui che mi va innanzi, l’altr’ ier, quando tonda vi si mostrò la suora di colui», e ’l sol mostrai; «costui per la profonda notte menato m’ha d’i veri morti con questa vera carne che ’l seconda. Indi m’han tratto sù li suoi conforti, salendo e rigirando la montagna che drizza voi che ’l mondo fece torti. Tanto dice di farmi sua compagna che io sarò là dove fia Beatrice; quivi convien che sanza lui rimagna. Virgilio è questi che così mi dice», e addita’lo; «e quest’ altro è quell’ ombra per cuï scosse dianzi ogne pendice lo vostro regno, che da sé lo sgombra». Purgatorio · Canto XXIV Né ’l dir l’andar, né l’andar lui più lento facea, ma ragionando andavam forte, sì come nave pinta da buon vento; e l’ombre, che parean cose rimorte, per le fosse de li occhi ammirazione traean di me, di mio vivere accorte. E io, continüando al mio sermone, dissi: «Ella sen va sù forse più tarda che non farebbe, per altrui cagione. Ma dimmi, se tu sai, dov’ è Piccarda; dimmi s’io veggio da notar persona tra questa gente che sì mi riguarda». «La mia sorella, che tra bella e buona non so qual fosse più, trïunfa lieta ne l’alto Olimpo già di sua corona». Sì disse prima; e poi: «Qui non si vieta di nominar ciascun, da ch’è sì munta nostra sembianza via per la dïeta. Questi», e mostrò col dito, «è Bonagiunta, Bonagiunta da Lucca; e quella faccia di là da lui più che l’altre trapunta ebbe la Santa Chiesa in le sue braccia: dal Torso fu, e purga per digiuno l’anguille di Bolsena e la vernaccia». Molti altri mi nomò ad uno ad uno; e del nomar parean tutti contenti, sì ch’io però non vidi un atto bruno. Vidi per fame a vòto usar li denti Ubaldin da la Pila e Bonifazio che pasturò col rocco molte genti. Vidi messer Marchese, ch’ebbe spazio già di bere a Forlì con men secchezza, e sì fu tal, che non si sentì sazio. Ma come fa chi guarda e poi s’apprezza più d’un che d’altro, fei a quel da Lucca, che più parea di me aver contezza. El mormorava; e non so che «Gentucca» sentiv’ io là, ov’ el sentia la piaga de la giustizia che sì li pilucca. «O anima», diss’ io, «che par sì vaga di parlar meco, fa sì ch’io t’intenda, e te e me col tuo parlare appaga». «Femmina è nata, e non porta ancor benda», cominciò el, «che ti farà piacere la mia città, come ch’om la riprenda. Tu te n’andrai con questo antivedere: se nel mio mormorar prendesti errore, dichiareranti ancor le cose vere. Ma dì s’i’ veggio qui colui che fore trasse le nove rime, cominciando ‘Donne ch’avete intelletto d’amore’». E io a lui: «I’ mi son un che, quando Amor mi spira, noto, e a quel modo ch’e’ ditta dentro vo significando». «O frate, issa vegg’ io», diss’ elli, «il nodo che ’l Notaro e Guittone e me ritenne di qua dal dolce stil novo ch’i’ odo! Io veggio ben come le vostre penne di retro al dittator sen vanno strette, che de le nostre certo non avvenne; e qual più a gradire oltre si mette, non vede più da l’uno a l’altro stilo»; e, quasi contentato, si tacette. Come li augei che vernan lungo ’l Nilo, alcuna volta in aere fanno schiera, poi volan più a fretta e vanno in filo, così tutta la gente che lì era, volgendo ’l viso, raffrettò suo passo, e per magrezza e per voler leggera. E come l’uom che di trottare è lasso, lascia andar li compagni, e sì passeggia fin che si sfoghi l’affollar del casso, sì lasciò trapassar la santa greggia Forese, e dietro meco sen veniva, dicendo: «Quando fia ch’io ti riveggia?». «Non so», rispuos’ io lui, «quant’ io mi viva; ma già non fïa il tornar mio tantosto, ch’io non sia col voler prima a la riva; però che ’l loco u’ fui a viver posto, di giorno in giorno più di ben si spolpa, e a trista ruina par disposto». «Or va», diss’ el; «che quei che più n’ha colpa, vegg’ ïo a coda d’una bestia tratto inver’ la valle ove mai non si scolpa. La bestia ad ogne passo va più ratto, crescendo sempre, fin ch’ella il percuote, e lascia il corpo vilmente disfatto. Non hanno molto a volger quelle ruote», e drizzò li occhi al ciel, «che ti fia chiaro ciò che ’l mio dir più dichiarar non puote. Tu ti rimani omai; ché ’l tempo è caro in questo regno, sì ch’io perdo troppo venendo teco sì a paro a paro». Qual esce alcuna volta di gualoppo lo cavalier di schiera che cavalchi, e va per farsi onor del primo intoppo, tal si partì da noi con maggior valchi; e io rimasi in via con esso i due che fuor del mondo sì gran marescalchi. E quando innanzi a noi intrato fue, che li occhi miei si fero a lui seguaci, come la mente a le parole sue, parvermi i rami gravidi e vivaci d’un altro pomo, e non molto lontani per esser pur allora vòlto in laci. Vidi gente sott’ esso alzar le mani e gridar non so che verso le fronde, quasi bramosi fantolini e vani che pregano, e ’l pregato non risponde, ma, per fare esser ben la voglia acuta, tien alto lor disio e nol nasconde. Poi si partì sì come ricreduta; e noi venimmo al grande arbore adesso, che tanti prieghi e lagrime rifiuta. «Trapassate oltre sanza farvi presso: legno è più sù che fu morso da Eva, e questa pianta si levò da esso». Sì tra le frasche non so chi diceva; per che Virgilio e Stazio e io, ristretti, oltre andavam dal lato che si leva. «Ricordivi», dicea, «d’i maladetti nei nuvoli formati, che, satolli, Tesëo combatter co’ doppi petti; e de li Ebrei ch’al ber si mostrar molli, per che no i volle Gedeon compagni, quando inver’ Madïan discese i colli». Sì accostati a l’un d’i due vivagni passammo, udendo colpe de la gola seguite già da miseri guadagni. Poi, rallargati per la strada sola, ben mille passi e più ci portar oltre, contemplando ciascun sanza parola. «Che andate pensando sì voi sol tre?». sùbita voce disse; ond’ io mi scossi come fan bestie spaventate e poltre. Drizzai la testa per veder chi fossi; e già mai non si videro in fornace vetri o metalli sì lucenti e rossi, com’ io vidi un che dicea: «S’a voi piace montare in sù, qui si convien dar volta; quinci si va chi vuole andar per pace». L’aspetto suo m’avea la vista tolta; per ch’io mi volsi dietro a’ miei dottori, com’ om che va secondo ch’elli ascolta. E quale, annunziatrice de li albori, l’aura di maggio movesi e olezza, tutta impregnata da l’erba e da’ fiori; tal mi senti’ un vento dar per mezza la fronte, e ben senti’ mover la piuma, che fé sentir d’ambrosïa l’orezza. E senti’ dir: «Beati cui alluma tanto di grazia, che l’amor del gusto nel petto lor troppo disir non fuma, esurïendo sempre quanto è giusto!». Purgatorio · Canto XXV Ora era onde ’l salir non volea storpio; ché ’l sole avëa il cerchio di merigge lasciato al Tauro e la notte a lo Scorpio: per che, come fa l’uom che non s’affigge ma vassi a la via sua, che che li appaia, se di bisogno stimolo il trafigge, così intrammo noi per la callaia, uno innanzi altro prendendo la scala che per artezza i salitor dispaia. E quale il cicognin che leva l’ala per voglia di volare, e non s’attenta d’abbandonar lo nido, e giù la cala; tal era io con voglia accesa e spenta di dimandar, venendo infino a l’atto che fa colui ch’a dicer s’argomenta. Non lasciò, per l’andar che fosse ratto, lo dolce padre mio, ma disse: «Scocca l’arco del dir, che ’nfino al ferro hai tratto». Allor sicuramente apri’ la bocca e cominciai: «Come si può far magro là dove l’uopo di nodrir non tocca?». «Se t’ammentassi come Meleagro si consumò al consumar d’un stizzo, non fora», disse, «a te questo sì agro; e se pensassi come, al vostro guizzo, guizza dentro a lo specchio vostra image, ciò che par duro ti parrebbe vizzo. Ma perché dentro a tuo voler t’adage, ecco qui Stazio; e io lui chiamo e prego che sia or sanator de le tue piage». «Se la veduta etterna li dislego», rispuose Stazio, «là dove tu sie, discolpi me non potert’ io far nego». Poi cominciò: «Se le parole mie, figlio, la mente tua guarda e riceve, lume ti fiero al come che tu die. Sangue perfetto, che poi non si beve da l’assetate vene, e si rimane quasi alimento che di mensa leve, prende nel core a tutte membra umane virtute informativa, come quello ch’a farsi quelle per le vene vane. Ancor digesto, scende ov’ è più bello tacer che dire; e quindi poscia geme sovr’ altrui sangue in natural vasello. Ivi s’accoglie l’uno e l’altro insieme, l’un disposto a patire, e l’altro a fare per lo perfetto loco onde si preme; e, giunto lui, comincia ad operare coagulando prima, e poi avviva ciò che per sua matera fé constare. Anima fatta la virtute attiva qual d’una pianta, in tanto differente, che questa è in via e quella è già a riva, tanto ovra poi, che già si move e sente, come spungo marino; e indi imprende ad organar le posse ond’ è semente. Or si spiega, figliuolo, or si distende la virtù ch’è dal cor del generante, dove natura a tutte membra intende. Ma come d’animal divegna fante, non vedi tu ancor: quest’ è tal punto, che più savio di te fé già errante, sì che per sua dottrina fé disgiunto da l’anima il possibile intelletto, perché da lui non vide organo assunto. Apri a la verità che viene il petto; e sappi che, sì tosto come al feto l’articular del cerebro è perfetto, lo motor primo a lui si volge lieto sovra tant’ arte di natura, e spira spirito novo, di vertù repleto, che ciò che trova attivo quivi, tira in sua sustanzia, e fassi un’alma sola, che vive e sente e sé in sé rigira. E perché meno ammiri la parola, guarda il calor del sole che si fa vino, giunto a l’omor che de la vite cola. Quando Làchesis non ha più del lino, solvesi da la carne, e in virtute ne porta seco e l’umano e ’l divino: l’altre potenze tutte quante mute; memoria, intelligenza e volontade in atto molto più che prima agute. Sanza restarsi, per sé stessa cade mirabilmente a l’una de le rive; quivi conosce prima le sue strade. Tosto che loco lì la circunscrive, la virtù formativa raggia intorno così e quanto ne le membra vive. E come l’aere, quand’ è ben pïorno, per l’altrui raggio che ’n sé si reflette, di diversi color diventa addorno; così l’aere vicin quivi si mette e in quella forma ch’è in lui suggella virtüalmente l’alma che ristette; e simigliante poi a la fiammella che segue il foco là ’vunque si muta, segue lo spirto sua forma novella. Però che quindi ha poscia sua paruta, è chiamata ombra; e quindi organa poi ciascun sentire infino a la veduta. Quindi parliamo e quindi ridiam noi; quindi facciam le lagrime e ’ sospiri che per lo monte aver sentiti puoi. Secondo che ci affliggono i disiri e li altri affetti, l’ombra si figura; e quest’ è la cagion di che tu miri». E già venuto a l’ultima tortura s’era per noi, e vòlto a la man destra, ed eravamo attenti ad altra cura. Quivi la ripa fiamma in fuor balestra, e la cornice spira fiato in suso che la reflette e via da lei sequestra; ond’ ir ne convenia dal lato schiuso ad uno ad uno; e io temëa ’l foco quinci, e quindi temeva cader giuso. Lo duca mio dicea: «Per questo loco si vuol tenere a li occhi stretto il freno, però ch’errar potrebbesi per poco». ‘Summae Deus clementïae’ nel seno al grande ardore allora udi’ cantando, che di volger mi fé caler non meno; e vidi spirti per la fiamma andando; per ch’io guardava a loro e a’ miei passi compartendo la vista a quando a quando. Appresso il fine ch’a quell’ inno fassi, gridavano alto: ‘Virum non cognosco’; indi ricominciavan l’inno bassi. Finitolo, anco gridavano: «Al bosco si tenne Diana, ed Elice caccionne che di Venere avea sentito il tòsco». Indi al cantar tornavano; indi donne gridavano e mariti che fuor casti come virtute e matrimonio imponne. E questo modo credo che lor basti per tutto il tempo che ’l foco li abbruscia: con tal cura conviene e con tai pasti che la piaga da sezzo si ricuscia. Purgatorio · Canto XXVI Mentre che sì per l’orlo, uno innanzi altro, ce n’andavamo, e spesso il buon maestro diceami: «Guarda: giovi ch’io ti scaltro»; feriami il sole in su l’omero destro, che già, raggiando, tutto l’occidente mutava in bianco aspetto di cilestro; e io facea con l’ombra più rovente parer la fiamma; e pur a tanto indizio vidi molt’ ombre, andando, poner mente. Questa fu la cagion che diede inizio loro a parlar di me; e cominciarsi a dir: «Colui non par corpo fittizio»; poi verso me, quanto potëan farsi, certi si fero, sempre con riguardo di non uscir dove non fosser arsi. «O tu che vai, non per esser più tardo, ma forse reverente, a li altri dopo, rispondi a me che ’n sete e ’n foco ardo. Né solo a me la tua risposta è uopo; ché tutti questi n’hanno maggior sete che d’acqua fredda Indo o Etïopo. Dinne com’ è che fai di te parete al sol, pur come tu non fossi ancora di morte intrato dentro da la rete». Sì mi parlava un d’essi; e io mi fora già manifesto, s’io non fossi atteso ad altra novità ch’apparve allora; ché per lo mezzo del cammino acceso venne gente col viso incontro a questa, la qual mi fece a rimirar sospeso. Lì veggio d’ogne parte farsi presta ciascun’ ombra e basciarsi una con una sanza restar, contente a brieve festa; così per entro loro schiera bruna s’ammusa l’una con l’altra formica, forse a spïar lor via e lor fortuna. Tosto che parton l’accoglienza amica, prima che ’l primo passo lì trascorra, sopragridar ciascuna s’affatica: la nova gente: «Soddoma e Gomorra»; e l’altra: «Ne la vacca entra Pasife, perché ’l torello a sua lussuria corra». Poi, come grue ch’a le montagne Rife volasser parte, e parte inver’ l’arene, queste del gel, quelle del sole schife, l’una gente sen va, l’altra sen vene; e tornan, lagrimando, a’ primi canti e al gridar che più lor si convene; e raccostansi a me, come davanti, essi medesmi che m’avean pregato, attenti ad ascoltar ne’ lor sembianti. Io, che due volte avea visto lor grato, incominciai: «O anime sicure d’aver, quando che sia, di pace stato, non son rimase acerbe né mature le membra mie di là, ma son qui meco col sangue suo e con le sue giunture. Quinci sù vo per non esser più cieco; donna è di sopra che m’acquista grazia, per che ’l mortal per vostro mondo reco. Ma se la vostra maggior voglia sazia tosto divegna, sì che ’l ciel v’alberghi ch’è pien d’amore e più ampio si spazia, ditemi, acciò ch’ancor carte ne verghi, chi siete voi, e chi è quella turba che se ne va di retro a’ vostri terghi». Non altrimenti stupido si turba lo montanaro, e rimirando ammuta, quando rozzo e salvatico s’inurba, che ciascun’ ombra fece in sua paruta; ma poi che furon di stupore scarche, lo qual ne li alti cuor tosto s’attuta, «Beato te, che de le nostre marche», ricominciò colei che pria m’inchiese, «per morir meglio, esperïenza imbarche! La gente che non vien con noi, offese di ciò per che già Cesar, trïunfando, “Regina” contra sé chiamar s’intese: però si parton “Soddoma” gridando, rimproverando a sé com’ hai udito, e aiutan l’arsura vergognando. Nostro peccato fu ermafrodito; ma perché non servammo umana legge, seguendo come bestie l’appetito, in obbrobrio di noi, per noi si legge, quando partinci, il nome di colei che s’imbestiò ne le ’mbestiate schegge. Or sai nostri atti e di che fummo rei: se forse a nome vuo’ saper chi semo, tempo non è di dire, e non saprei. Farotti ben di me volere scemo: son Guido Guinizzelli, e già mi purgo per ben dolermi prima ch’a lo stremo». Quali ne la tristizia di Ligurgo si fer due figli a riveder la madre, tal mi fec’ io, ma non a tanto insurgo, quand’ io odo nomar sé stesso il padre mio e de li altri miei miglior che mai rime d’amore usar dolci e leggiadre; e sanza udire e dir pensoso andai lunga fïata rimirando lui, né, per lo foco, in là più m’appressai. Poi che di riguardar pasciuto fui, tutto m’offersi pronto al suo servigio con l’affermar che fa credere altrui. Ed elli a me: «Tu lasci tal vestigio, per quel ch’i’ odo, in me, e tanto chiaro, che Letè nol può tòrre né far bigio. Ma se le tue parole or ver giuraro, dimmi che è cagion per che dimostri nel dire e nel guardar d’avermi caro». E io a lui: «Li dolci detti vostri, che, quanto durerà l’uso moderno, faranno cari ancora i loro incostri». «O frate», disse, «questi ch’io ti cerno col dito», e additò un spirto innanzi, «fu miglior fabbro del parlar materno. Versi d’amore e prose di romanzi soverchiò tutti; e lascia dir li stolti che quel di Lemosì credon ch’avanzi. A voce più ch’al ver drizzan li volti, e così ferman sua oppinïone prima ch’arte o ragion per lor s’ascolti. Così fer molti antichi di Guittone, di grido in grido pur lui dando pregio, fin che l’ha vinto il ver con più persone. Or se tu hai sì ampio privilegio, che licito ti sia l’andare al chiostro nel quale è Cristo abate del collegio, falli per me un dir d’un paternostro, quanto bisogna a noi di questo mondo, dove poter peccar non è più nostro». Poi, forse per dar luogo altrui secondo che presso avea, disparve per lo foco, come per l’acqua il pesce andando al fondo. Io mi fei al mostrato innanzi un poco, e dissi ch’al suo nome il mio disire apparecchiava grazïoso loco. El cominciò liberamente a dire: «Tan m’abellis vostre cortes deman, qu’ieu no me puesc ni voill a vos cobrire. Ieu sui Arnaut, que plor e vau cantan; consiros vei la passada folor, e vei jausen lo joi qu’esper, denan. Ara vos prec, per aquella valor que vos guida al som de l’escalina, sovenha vos a temps de ma dolor!». Poi s’ascose nel foco che li affina. Purgatorio · Canto XXVII Sì come quando i primi raggi vibra là dove il suo fattor lo sangue sparse, cadendo Ibero sotto l’alta Libra, e l’onde in Gange da nona rïarse, sì stava il sole; onde ’l giorno sen giva, come l’angel di Dio lieto ci apparse. Fuor de la fiamma stava in su la riva, e cantava ‘Beati mundo corde!’ in voce assai più che la nostra viva. Poscia «Più non si va, se pria non morde, anime sante, il foco: intrate in esso, e al cantar di là non siate sorde», ci disse come noi li fummo presso; per ch’io divenni tal, quando lo ’ntesi, qual è colui che ne la fossa è messo. In su le man commesse mi protesi, guardando il foco e imaginando forte umani corpi già veduti accesi. Volsersi verso me le buone scorte; e Virgilio mi disse: «Figliuol mio, qui può esser tormento, ma non morte. Ricorditi, ricorditi! E se io sovresso Gerïon ti guidai salvo, che farò ora presso più a Dio? Credi per certo che se dentro a l’alvo di questa fiamma stessi ben mille anni, non ti potrebbe far d’un capel calvo. E se tu forse credi ch’io t’inganni, fatti ver’ lei, e fatti far credenza con le tue mani al lembo d’i tuoi panni. Pon giù omai, pon giù ogne temenza; volgiti in qua e vieni: entra sicuro!». E io pur fermo e contra coscïenza. Quando mi vide star pur fermo e duro, turbato un poco disse: «Or vedi, figlio: tra Bëatrice e te è questo muro». Come al nome di Tisbe aperse il ciglio Piramo in su la morte, e riguardolla, allor che ’l gelso diventò vermiglio; così, la mia durezza fatta solla, mi volsi al savio duca, udendo il nome che ne la mente sempre mi rampolla. Ond’ ei crollò la fronte e disse: «Come! volenci star di qua?»; indi sorrise come al fanciul si fa ch’è vinto al pome. Poi dentro al foco innanzi mi si mise, pregando Stazio che venisse retro, che pria per lunga strada ci divise. Sì com’ fui dentro, in un bogliente vetro gittato mi sarei per rinfrescarmi, tant’ era ivi lo ’ncendio sanza metro. Lo dolce padre mio, per confortarmi, pur di Beatrice ragionando andava, dicendo: «Li occhi suoi già veder parmi». Guidavaci una voce che cantava di là; e noi, attenti pur a lei, venimmo fuor là ove si montava. ‘Venite, benedicti Patris mei’, sonò dentro a un lume che lì era, tal che mi vinse e guardar nol potei. «Lo sol sen va», soggiunse, «e vien la sera; non v’arrestate, ma studiate il passo, mentre che l’occidente non si annera». Dritta salia la via per entro ’l sasso verso tal parte ch’io toglieva i raggi dinanzi a me del sol ch’era già basso. E di pochi scaglion levammo i saggi, che ’l sol corcar, per l’ombra che si spense, sentimmo dietro e io e li miei saggi. E pria che ’n tutte le sue parti immense fosse orizzonte fatto d’uno aspetto, e notte avesse tutte sue dispense, ciascun di noi d’un grado fece letto; ché la natura del monte ci affranse la possa del salir più e ’l diletto. Quali si stanno ruminando manse le capre, state rapide e proterve sovra le cime avante che sien pranse, tacite a l’ombra, mentre che ’l sol ferve, guardate dal pastor, che ’n su la verga poggiato s’è e lor di posa serve; e quale il mandrïan che fori alberga, lungo il pecuglio suo queto pernotta, guardando perché fiera non lo sperga; tali eravamo tutti e tre allotta, io come capra, ed ei come pastori, fasciati quinci e quindi d’alta grotta. Poco parer potea lì del di fori; ma, per quel poco, vedea io le stelle di lor solere e più chiare e maggiori. Sì ruminando e sì mirando in quelle, mi prese il sonno; il sonno che sovente, anzi che ’l fatto sia, sa le novelle. Ne l’ora, credo, che de l’orïente prima raggiò nel monte Citerea, che di foco d’amor par sempre ardente, giovane e bella in sogno mi parea donna vedere andar per una landa cogliendo fiori; e cantando dicea: «Sappia qualunque il mio nome dimanda ch’i’ mi son Lia, e vo movendo intorno le belle mani a farmi una ghirlanda. Per piacermi a lo specchio, qui m’addorno; ma mia suora Rachel mai non si smaga dal suo miraglio, e siede tutto giorno. Ell’ è d’i suoi belli occhi veder vaga com’ io de l’addornarmi con le mani; lei lo vedere, e me l’ovrare appaga». E già per li splendori antelucani, che tanto a’ pellegrin surgon più grati, quanto, tornando, albergan men lontani, le tenebre fuggian da tutti lati, e ’l sonno mio con esse; ond’ io leva’mi, veggendo i gran maestri già levati. «Quel dolce pome che per tanti rami cercando va la cura de’ mortali, oggi porrà in pace le tue fami». Virgilio inverso me queste cotali parole usò; e mai non furo strenne che fosser di piacere a queste iguali. Tanto voler sopra voler mi venne de l’esser sù, ch’ad ogne passo poi al volo mi sentia crescer le penne. Come la scala tutta sotto noi fu corsa e fummo in su ’l grado superno, in me ficcò Virgilio li occhi suoi, e disse: «Il temporal foco e l’etterno veduto hai, figlio; e se’ venuto in parte dov’ io per me più oltre non discerno. Tratto t’ho qui con ingegno e con arte; lo tuo piacere omai prendi per duce; fuor se’ de l’erte vie, fuor se’ de l’arte. Vedi lo sol che ’n fronte ti riluce; vedi l’erbette, i fiori e li arbuscelli che qui la terra sol da sé produce. Mentre che vegnan lieti li occhi belli che, lagrimando, a te venir mi fenno, seder ti puoi e puoi andar tra elli. Non aspettar mio dir più né mio cenno; libero, dritto e sano è tuo arbitrio, e fallo fora non fare a suo senno: per ch’io te sovra te corono e mitrio». Purgatorio · Canto XXVIII Vago già di cercar dentro e dintorno la divina foresta spessa e viva, ch’a li occhi temperava il novo giorno, sanza più aspettar, lasciai la riva, prendendo la campagna lento lento su per lo suol che d’ogne parte auliva. Un’aura dolce, sanza mutamento avere in sé, mi feria per la fronte non di più colpo che soave vento; per cui le fronde, tremolando, pronte tutte quante piegavano a la parte u’ la prim’ ombra gitta il santo monte; non però dal loro esser dritto sparte tanto, che li augelletti per le cime lasciasser d’operare ogne lor arte; ma con piena letizia l’ore prime, cantando, ricevieno intra le foglie, che tenevan bordone a le sue rime, tal qual di ramo in ramo si raccoglie per la pineta in su ’l lito di Chiassi, quand’ Ëolo scilocco fuor discioglie. Già m’avean trasportato i lenti passi dentro a la selva antica tanto, ch’io non potea rivedere ond’ io mi ’ntrassi; ed ecco più andar mi tolse un rio, che ’nver’ sinistra con sue picciole onde piegava l’erba che ’n sua ripa uscìo. Tutte l’acque che son di qua più monde, parrieno avere in sé mistura alcuna verso di quella, che nulla nasconde, avvegna che si mova bruna bruna sotto l’ombra perpetüa, che mai raggiar non lascia sole ivi né luna. Coi piè ristetti e con li occhi passai di là dal fiumicello, per mirare la gran varïazion d’i freschi mai; e là m’apparve, sì com’ elli appare subitamente cosa che disvia per maraviglia tutto altro pensare, una donna soletta che si gia e cantando e scegliendo fior da fiore ond’ era pinta tutta la sua via. «Deh, bella donna, che a’ raggi d’amore ti scaldi, s’i’ vo’ credere a’ sembianti che soglion esser testimon del core, vegnati in voglia di trarreti avanti», diss’ io a lei, «verso questa rivera, tanto ch’io possa intender che tu canti. Tu mi fai rimembrar dove e qual era Proserpina nel tempo che perdette la madre lei, ed ella primavera». Come si volge, con le piante strette a terra e intra sé, donna che balli, e piede innanzi piede a pena mette, volsesi in su i vermigli e in su i gialli fioretti verso me, non altrimenti che vergine che li occhi onesti avvalli; e fece i prieghi miei esser contenti, sì appressando sé, che ’l dolce suono veniva a me co’ suoi intendimenti. Tosto che fu là dove l’erbe sono bagnate già da l’onde del bel fiume, di levar li occhi suoi mi fece dono. Non credo che splendesse tanto lume sotto le ciglia a Venere, trafitta dal figlio fuor di tutto suo costume. Ella ridea da l’altra riva dritta, trattando più color con le sue mani, che l’alta terra sanza seme gitta. Tre passi ci facea il fiume lontani; ma Elesponto, là ’ve passò Serse, ancora freno a tutti orgogli umani, più odio da Leandro non sofferse per mareggiare intra Sesto e Abido, che quel da me perch’ allor non s’aperse. «Voi siete nuovi, e forse perch’ io rido», cominciò ella, «in questo luogo eletto a l’umana natura per suo nido, maravigliando tienvi alcun sospetto; ma luce rende il salmo Delectasti, che puote disnebbiar vostro intelletto. E tu che se’ dinanzi e mi pregasti, dì s’altro vuoli udir; ch’i’ venni presta ad ogne tua question tanto che basti». «L’acqua», diss’ io, «e ’l suon de la foresta impugnan dentro a me novella fede di cosa ch’io udi’ contraria a questa». Ond’ ella: «Io dicerò come procede per sua cagion ciò ch’ammirar ti face, e purgherò la nebbia che ti fiede. Lo sommo Ben, che solo esso a sé piace, fé l’uom buono e a bene, e questo loco diede per arr’ a lui d’etterna pace. Per sua difalta qui dimorò poco; per sua difalta in pianto e in affanno cambiò onesto riso e dolce gioco. Perché ’l turbar che sotto da sé fanno l’essalazion de l’acqua e de la terra, che quanto posson dietro al calor vanno, a l’uomo non facesse alcuna guerra, questo monte salìo verso ’l ciel tanto, e libero n’è d’indi ove si serra. Or perché in circuito tutto quanto l’aere si volge con la prima volta, se non li è rotto il cerchio d’alcun canto, in questa altezza ch’è tutta disciolta ne l’aere vivo, tal moto percuote, e fa sonar la selva perch’ è folta; e la percossa pianta tanto puote, che de la sua virtute l’aura impregna e quella poi, girando, intorno scuote; e l’altra terra, secondo ch’è degna per sé e per suo ciel, concepe e figlia di diverse virtù diverse legna. Non parrebbe di là poi maraviglia, udito questo, quando alcuna pianta sanza seme palese vi s’appiglia. E saper dei che la campagna santa dove tu se’, d’ogne semenza è piena, e frutto ha in sé che di là non si schianta. L’acqua che vedi non surge di vena che ristori vapor che gel converta, come fiume ch’acquista e perde lena; ma esce di fontana salda e certa, che tanto dal voler di Dio riprende, quant’ ella versa da due parti aperta. Da questa parte con virtù discende che toglie altrui memoria del peccato; da l’altra d’ogne ben fatto la rende. Quinci Letè; così da l’altro lato Eünoè si chiama, e non adopra se quinci e quindi pria non è gustato: a tutti altri sapori esto è di sopra. E avvegna ch’assai possa esser sazia la sete tua perch’ io più non ti scuopra, darotti un corollario ancor per grazia; né credo che ’l mio dir ti sia men caro, se oltre promession teco si spazia. Quelli ch’anticamente poetaro l’età de l’oro e suo stato felice, forse in Parnaso esto loco sognaro. Qui fu innocente l’umana radice; qui primavera sempre e ogne frutto; nettare è questo di che ciascun dice». Io mi rivolsi ’n dietro allora tutto a’ miei poeti, e vidi che con riso udito avëan l’ultimo costrutto; poi a la bella donna torna’ il viso. Purgatorio · Canto XXIX Cantando come donna innamorata, continüò col fin di sue parole: ‘Beati quorum tecta sunt peccata!’. E come ninfe che si givan sole per le salvatiche ombre, disïando qual di veder, qual di fuggir lo sole, allor si mosse contra ’l fiume, andando su per la riva; e io pari di lei, picciol passo con picciol seguitando. Non eran cento tra ’ suoi passi e ’ miei, quando le ripe igualmente dier volta, per modo ch’a levante mi rendei. Né ancor fu così nostra via molta, quando la donna tutta a me si torse, dicendo: «Frate mio, guarda e ascolta». Ed ecco un lustro sùbito trascorse da tutte parti per la gran foresta, tal che di balenar mi mise in forse. Ma perché ’l balenar, come vien, resta, e quel, durando, più e più splendeva, nel mio pensier dicea: ‘Che cosa è questa?’. E una melodia dolce correva per l’aere luminoso; onde buon zelo mi fé riprender l’ardimento d’Eva, che là dove ubidia la terra e ’l cielo, femmina, sola e pur testé formata, non sofferse di star sotto alcun velo; sotto ’l qual se divota fosse stata, avrei quelle ineffabili delizie sentite prima e più lunga fïata. Mentr’ io m’andava tra tante primizie de l’etterno piacer tutto sospeso, e disïoso ancora a più letizie, dinanzi a noi, tal quale un foco acceso, ci si fé l’aere sotto i verdi rami; e ’l dolce suon per canti era già inteso. O sacrosante Vergini, se fami, freddi o vigilie mai per voi soffersi, cagion mi sprona ch’io mercé vi chiami. Or convien che Elicona per me versi, e Uranìe m’aiuti col suo coro forti cose a pensar mettere in versi. Poco più oltre, sette alberi d’oro falsava nel parere il lungo tratto del mezzo ch’era ancor tra noi e loro; ma quand’ i’ fui sì presso di lor fatto, che l’obietto comun, che ’l senso inganna, non perdea per distanza alcun suo atto, la virtù ch’a ragion discorso ammanna, sì com’ elli eran candelabri apprese, e ne le voci del cantare ‘Osanna’. Di sopra fiammeggiava il bello arnese più chiaro assai che luna per sereno di mezza notte nel suo mezzo mese. Io mi rivolsi d’ammirazion pieno al buon Virgilio, ed esso mi rispuose con vista carca di stupor non meno. Indi rendei l’aspetto a l’alte cose che si movieno incontr’ a noi sì tardi, che foran vinte da novelle spose. La donna mi sgridò: «Perché pur ardi sì ne l’affetto de le vive luci, e ciò che vien di retro a lor non guardi?». Genti vid’ io allor, come a lor duci, venire appresso, vestite di bianco; e tal candor di qua già mai non fuci. L’acqua imprendëa dal sinistro fianco, e rendea me la mia sinistra costa, s’io riguardava in lei, come specchio anco. Quand’ io da la mia riva ebbi tal posta, che solo il fiume mi facea distante, per veder meglio ai passi diedi sosta, e vidi le fiammelle andar davante, lasciando dietro a sé l’aere dipinto, e di tratti pennelli avean sembiante; sì che lì sopra rimanea distinto di sette liste, tutte in quei colori onde fa l’arco il Sole e Delia il cinto. Questi ostendali in dietro eran maggiori che la mia vista; e, quanto a mio avviso, diece passi distavan quei di fori. Sotto così bel ciel com’ io diviso, ventiquattro seniori, a due a due, coronati venien di fiordaliso. Tutti cantavan: «Benedicta tue ne le figlie d’Adamo, e benedette sieno in etterno le bellezze tue!». Poscia che i fiori e l’altre fresche erbette a rimpetto di me da l’altra sponda libere fuor da quelle genti elette, sì come luce luce in ciel seconda, vennero appresso lor quattro animali, coronati ciascun di verde fronda. Ognuno era pennuto di sei ali; le penne piene d’occhi; e li occhi d’Argo, se fosser vivi, sarebber cotali. A descriver lor forme più non spargo rime, lettor; ch’altra spesa mi strigne, tanto ch’a questa non posso esser largo; ma leggi Ezechïel, che li dipigne come li vide da la fredda parte venir con vento e con nube e con igne; e quali i troverai ne le sue carte, tali eran quivi, salvo ch’a le penne Giovanni è meco e da lui si diparte. Lo spazio dentro a lor quattro contenne un carro, in su due rote, trïunfale, ch’al collo d’un grifon tirato venne. Esso tendeva in sù l’una e l’altra ale tra la mezzana e le tre e tre liste, sì ch’a nulla, fendendo, facea male. Tanto salivan che non eran viste; le membra d’oro avea quant’ era uccello, e bianche l’altre, di vermiglio miste. Non che Roma di carro così bello rallegrasse Affricano, o vero Augusto, ma quel del Sol saria pover con ello; quel del Sol che, svïando, fu combusto per l’orazion de la Terra devota, quando fu Giove arcanamente giusto. Tre donne in giro da la destra rota venian danzando; l’una tanto rossa ch’a pena fora dentro al foco nota; l’altr’ era come se le carni e l’ossa fossero state di smeraldo fatte; la terza parea neve testé mossa; e or parëan da la bianca tratte, or da la rossa; e dal canto di questa l’altre toglien l’andare e tarde e ratte. Da la sinistra quattro facean festa, in porpore vestite, dietro al modo d’una di lor ch’avea tre occhi in testa. Appresso tutto il pertrattato nodo vidi due vecchi in abito dispari, ma pari in atto e onesto e sodo. L’un si mostrava alcun de’ famigliari di quel sommo Ipocràte che natura a li animali fé ch’ell’ ha più cari; mostrava l’altro la contraria cura con una spada lucida e aguta, tal che di qua dal rio mi fé paura. Poi vidi quattro in umile paruta; e di retro da tutti un vecchio solo venir, dormendo, con la faccia arguta. E questi sette col primaio stuolo erano abitüati, ma di gigli dintorno al capo non facëan brolo, anzi di rose e d’altri fior vermigli; giurato avria poco lontano aspetto che tutti ardesser di sopra da’ cigli. E quando il carro a me fu a rimpetto, un tuon s’udì, e quelle genti degne parvero aver l’andar più interdetto, fermandosi ivi con le prime insegne. Purgatorio · Canto XXX Quando il settentrïon del primo cielo, che né occaso mai seppe né orto né d’altra nebbia che di colpa velo, e che faceva lì ciascun accorto di suo dover, come ’l più basso face qual temon gira per venire a porto, fermo s’affisse: la gente verace, venuta prima tra ’l grifone ed esso, al carro volse sé come a sua pace; e un di loro, quasi da ciel messo, ‘Veni, sponsa, de Libano’ cantando gridò tre volte, e tutti li altri appresso. Quali i beati al novissimo bando surgeran presti ognun di sua caverna, la revestita voce alleluiando, cotali in su la divina basterna si levar cento, ad vocem tanti senis, ministri e messaggier di vita etterna. Tutti dicean: ‘Benedictus qui venis!’, e fior gittando e di sopra e dintorno, ‘Manibus, oh, date lilïa plenis!’. Io vidi già nel cominciar del giorno la parte orïental tutta rosata, e l’altro ciel di bel sereno addorno; e la faccia del sol nascere ombrata, sì che per temperanza di vapori l’occhio la sostenea lunga fïata: così dentro una nuvola di fiori che da le mani angeliche saliva e ricadeva in giù dentro e di fori, sovra candido vel cinta d’uliva donna m’apparve, sotto verde manto vestita di color di fiamma viva. E lo spirito mio, che già cotanto tempo era stato ch’a la sua presenza non era di stupor, tremando, affranto, sanza de li occhi aver più conoscenza, per occulta virtù che da lei mosse, d’antico amor sentì la gran potenza. Tosto che ne la vista mi percosse l’alta virtù che già m’avea trafitto prima ch’io fuor di püerizia fosse, volsimi a la sinistra col respitto col quale il fantolin corre a la mamma quando ha paura o quando elli è afflitto, per dicere a Virgilio: ‘Men che dramma di sangue m’è rimaso che non tremi: conosco i segni de l’antica fiamma’. Ma Virgilio n’avea lasciati scemi di sé, Virgilio dolcissimo patre, Virgilio a cui per mia salute die’mi; né quantunque perdeo l’antica matre, valse a le guance nette di rugiada, che, lagrimando, non tornasser atre. «Dante, perché Virgilio se ne vada, non pianger anco, non piangere ancora; ché pianger ti conven per altra spada». Quasi ammiraglio che in poppa e in prora viene a veder la gente che ministra per li altri legni, e a ben far l’incora; in su la sponda del carro sinistra, quando mi volsi al suon del nome mio, che di necessità qui si registra, vidi la donna che pria m’appario velata sotto l’angelica festa, drizzar li occhi ver’ me di qua dal rio. Tutto che ’l vel che le scendea di testa, cerchiato de le fronde di Minerva, non la lasciasse parer manifesta, regalmente ne l’atto ancor proterva continüò come colui che dice e ’l più caldo parlar dietro reserva: «Guardaci ben! Ben son, ben son Beatrice. Come degnasti d’accedere al monte? non sapei tu che qui è l’uom felice?». Li occhi mi cadder giù nel chiaro fonte; ma veggendomi in esso, i trassi a l’erba, tanta vergogna mi gravò la fronte. Così la madre al figlio par superba, com’ ella parve a me; perché d’amaro sente il sapor de la pietade acerba. Ella si tacque; e li angeli cantaro di sùbito ‘In te, Domine, speravi’; ma oltre ‘pedes meos’ non passaro. Sì come neve tra le vive travi per lo dosso d’Italia si congela, soffiata e stretta da li venti schiavi, poi, liquefatta, in sé stessa trapela, pur che la terra che perde ombra spiri, sì che par foco fonder la candela; così fui sanza lagrime e sospiri anzi ’l cantar di quei che notan sempre dietro a le note de li etterni giri; ma poi che ’ntesi ne le dolci tempre lor compatire a me, par che se detto avesser: ‘Donna, perché sì lo stempre?’, lo gel che m’era intorno al cor ristretto, spirito e acqua fessi, e con angoscia de la bocca e de li occhi uscì del petto. Ella, pur ferma in su la detta coscia del carro stando, a le sustanze pie volse le sue parole così poscia: «Voi vigilate ne l’etterno die, sì che notte né sonno a voi non fura passo che faccia il secol per sue vie; onde la mia risposta è con più cura che m’intenda colui che di là piagne, perché sia colpa e duol d’una misura. Non pur per ovra de le rote magne, che drizzan ciascun seme ad alcun fine secondo che le stelle son compagne, ma per larghezza di grazie divine, che sì alti vapori hanno a lor piova, che nostre viste là non van vicine, questi fu tal ne la sua vita nova virtüalmente, ch’ogne abito destro fatto averebbe in lui mirabil prova. Ma tanto più maligno e più silvestro si fa ’l terren col mal seme e non cólto, quant’ elli ha più di buon vigor terrestro. Alcun tempo il sostenni col mio volto: mostrando li occhi giovanetti a lui, meco il menava in dritta parte vòlto. Sì tosto come in su la soglia fui di mia seconda etade e mutai vita, questi si tolse a me, e diessi altrui. Quando di carne a spirto era salita, e bellezza e virtù cresciuta m’era, fu’ io a lui men cara e men gradita; e volse i passi suoi per via non vera, imagini di ben seguendo false, che nulla promession rendono intera. Né l’impetrare ispirazion mi valse, con le quali e in sogno e altrimenti lo rivocai: sì poco a lui ne calse! Tanto giù cadde, che tutti argomenti a la salute sua eran già corti, fuor che mostrarli le perdute genti. Per questo visitai l’uscio d’i morti, e a colui che l’ha qua sù condotto, li prieghi miei, piangendo, furon porti. Alto fato di Dio sarebbe rotto, se Letè si passasse e tal vivanda fosse gustata sanza alcuno scotto di pentimento che lagrime spanda». Purgatorio · Canto XXXI «O tu che se’ di là dal fiume sacro», volgendo suo parlare a me per punta, che pur per taglio m’era paruto acro, ricominciò, seguendo sanza cunta, «dì, dì se questo è vero: a tanta accusa tua confession conviene esser congiunta». Era la mia virtù tanto confusa, che la voce si mosse, e pria si spense che da li organi suoi fosse dischiusa. Poco sofferse; poi disse: «Che pense? Rispondi a me; ché le memorie triste in te non sono ancor da l’acqua offense». Confusione e paura insieme miste mi pinsero un tal «sì» fuor de la bocca, al quale intender fuor mestier le viste. Come balestro frange, quando scocca da troppa tesa, la sua corda e l’arco, e con men foga l’asta il segno tocca, sì scoppia’ io sottesso grave carco, fuori sgorgando lagrime e sospiri, e la voce allentò per lo suo varco. Ond’ ella a me: «Per entro i mie’ disiri, che ti menavano ad amar lo bene di là dal qual non è a che s’aspiri, quai fossi attraversati o quai catene trovasti, per che del passare innanzi dovessiti così spogliar la spene? E quali agevolezze o quali avanzi ne la fronte de li altri si mostraro, per che dovessi lor passeggiare anzi?». Dopo la tratta d’un sospiro amaro, a pena ebbi la voce che rispuose, e le labbra a fatica la formaro. Piangendo dissi: «Le presenti cose col falso lor piacer volser miei passi, tosto che ’l vostro viso si nascose». Ed ella: «Se tacessi o se negassi ciò che confessi, non fora men nota la colpa tua: da tal giudice sassi! Ma quando scoppia de la propria gota l’accusa del peccato, in nostra corte rivolge sé contra ’l taglio la rota. Tuttavia, perché mo vergogna porte del tuo errore, e perché altra volta, udendo le serene, sie più forte, pon giù il seme del piangere e ascolta: sì udirai come in contraria parte mover dovieti mia carne sepolta. Mai non t’appresentò natura o arte piacer, quanto le belle membra in ch’io rinchiusa fui, e che so’ ’n terra sparte; e se ’l sommo piacer sì ti fallio per la mia morte, qual cosa mortale dovea poi trarre te nel suo disio? Ben ti dovevi, per lo primo strale de le cose fallaci, levar suso di retro a me che non era più tale. Non ti dovea gravar le penne in giuso, ad aspettar più colpo, o pargoletta o altra novità con sì breve uso. Novo augelletto due o tre aspetta; ma dinanzi da li occhi d’i pennuti rete si spiega indarno o si saetta». Quali fanciulli, vergognando, muti con li occhi a terra stannosi, ascoltando e sé riconoscendo e ripentuti, tal mi stav’ io; ed ella disse: «Quando per udir se’ dolente, alza la barba, e prenderai più doglia riguardando». Con men di resistenza si dibarba robusto cerro, o vero al nostral vento o vero a quel de la terra di Iarba, ch’io non levai al suo comando il mento; e quando per la barba il viso chiese, ben conobbi il velen de l’argomento. E come la mia faccia si distese, posarsi quelle prime creature da loro aspersïon l’occhio comprese; e le mie luci, ancor poco sicure, vider Beatrice volta in su la fiera ch’è sola una persona in due nature. Sotto ’l suo velo e oltre la rivera vincer pariemi più sé stessa antica, vincer che l’altre qui, quand’ ella c’era. Di penter sì mi punse ivi l’ortica, che di tutte altre cose qual mi torse più nel suo amor, più mi si fé nemica. Tanta riconoscenza il cor mi morse, ch’io caddi vinto; e quale allora femmi, salsi colei che la cagion mi porse. Poi, quando il cor virtù di fuor rendemmi, la donna ch’io avea trovata sola sopra me vidi, e dicea: «Tiemmi, tiemmi!». Tratto m’avea nel fiume infin la gola, e tirandosi me dietro sen giva sovresso l’acqua lieve come scola. Quando fui presso a la beata riva, ‘Asperges me’ sì dolcemente udissi, che nol so rimembrar, non ch’io lo scriva. La bella donna ne le braccia aprissi; abbracciommi la testa e mi sommerse ove convenne ch’io l’acqua inghiottissi. Indi mi tolse, e bagnato m’offerse dentro a la danza de le quattro belle; e ciascuna del braccio mi coperse. «Noi siam qui ninfe e nel ciel siamo stelle; pria che Beatrice discendesse al mondo, fummo ordinate a lei per sue ancelle. Merrenti a li occhi suoi; ma nel giocondo lume ch’è dentro aguzzeranno i tuoi le tre di là, che miran più profondo». Così cantando cominciaro; e poi al petto del grifon seco menarmi, ove Beatrice stava volta a noi. Disser: «Fa che le viste non risparmi; posto t’avem dinanzi a li smeraldi ond’ Amor già ti trasse le sue armi». Mille disiri più che fiamma caldi strinsermi li occhi a li occhi rilucenti, che pur sopra ’l grifone stavan saldi. Come in lo specchio il sol, non altrimenti la doppia fiera dentro vi raggiava, or con altri, or con altri reggimenti. Pensa, lettor, s’io mi maravigliava, quando vedea la cosa in sé star queta, e ne l’idolo suo si trasmutava. Mentre che piena di stupore e lieta l’anima mia gustava di quel cibo che, saziando di sé, di sé asseta, sé dimostrando di più alto tribo ne li atti, l’altre tre si fero avanti, danzando al loro angelico caribo. «Volgi, Beatrice, volgi li occhi santi», era la sua canzone, «al tuo fedele che, per vederti, ha mossi passi tanti! Per grazia fa noi grazia che disvele a lui la bocca tua, sì che discerna la seconda bellezza che tu cele». O isplendor di viva luce etterna, chi palido si fece sotto l’ombra sì di Parnaso, o bevve in sua cisterna, che non paresse aver la mente ingombra, tentando a render te qual tu paresti là dove armonizzando il ciel t’adombra, quando ne l’aere aperto ti solvesti? Purgatorio · Canto XXXII Tant’ eran li occhi miei fissi e attenti a disbramarsi la decenne sete, che li altri sensi m’eran tutti spenti. Ed essi quinci e quindi avien parete di non caler—così lo santo riso a sé traéli con l’antica rete!—; quando per forza mi fu vòlto il viso ver’ la sinistra mia da quelle dee, perch’ io udi’ da loro un «Troppo fiso!»; e la disposizion ch’a veder èe ne li occhi pur testé dal sol percossi, sanza la vista alquanto esser mi fée. Ma poi ch’al poco il viso riformossi (e dico ‘al poco’ per rispetto al molto sensibile onde a forza mi rimossi), vidi ’n sul braccio destro esser rivolto lo glorïoso essercito, e tornarsi col sole e con le sette fiamme al volto. Come sotto li scudi per salvarsi volgesi schiera, e sé gira col segno, prima che possa tutta in sé mutarsi; quella milizia del celeste regno che procedeva, tutta trapassonne pria che piegasse il carro il primo legno. Indi a le rote si tornar le donne, e ’l grifon mosse il benedetto carco sì, che però nulla penna crollonne. La bella donna che mi trasse al varco e Stazio e io seguitavam la rota che fé l’orbita sua con minore arco. Sì passeggiando l’alta selva vòta, colpa di quella ch’al serpente crese, temprava i passi un’angelica nota. Forse in tre voli tanto spazio prese disfrenata saetta, quanto eramo rimossi, quando Bëatrice scese. Io senti’ mormorare a tutti «Adamo»; poi cerchiaro una pianta dispogliata di foglie e d’altra fronda in ciascun ramo. La coma sua, che tanto si dilata più quanto più è sù, fora da l’Indi ne’ boschi lor per altezza ammirata. «Beato se’, grifon, che non discindi col becco d’esto legno dolce al gusto, poscia che mal si torce il ventre quindi». Così dintorno a l’albero robusto gridaron li altri; e l’animal binato: «Sì si conserva il seme d’ogne giusto». E vòlto al temo ch’elli avea tirato, trasselo al piè de la vedova frasca, e quel di lei a lei lasciò legato. Come le nostre piante, quando casca giù la gran luce mischiata con quella che raggia dietro a la celeste lasca, turgide fansi, e poi si rinovella di suo color ciascuna, pria che ’l sole giunga li suoi corsier sotto altra stella; men che di rose e più che di vïole colore aprendo, s’innovò la pianta, che prima avea le ramora sì sole. Io non lo ’ntesi, né qui non si canta l’inno che quella gente allor cantaro, né la nota soffersi tutta quanta. S’io potessi ritrar come assonnaro li occhi spietati udendo di Siringa, li occhi a cui pur vegghiar costò sì caro; come pintor che con essempro pinga, disegnerei com’ io m’addormentai; ma qual vuol sia che l’assonnar ben finga. Però trascorro a quando mi svegliai, e dico ch’un splendor mi squarciò ’l velo del sonno, e un chiamar: «Surgi: che fai?». Quali a veder de’ fioretti del melo che del suo pome li angeli fa ghiotti e perpetüe nozze fa nel cielo, Pietro e Giovanni e Iacopo condotti e vinti, ritornaro a la parola da la qual furon maggior sonni rotti, e videro scemata loro scuola così di Moïsè come d’Elia, e al maestro suo cangiata stola; tal torna’ io, e vidi quella pia sovra me starsi che conducitrice fu de’ miei passi lungo ’l fiume pria. E tutto in dubbio dissi: «Ov’ è Beatrice?». Ond’ ella: «Vedi lei sotto la fronda nova sedere in su la sua radice. Vedi la compagnia che la circonda: li altri dopo ’l grifon sen vanno suso con più dolce canzone e più profonda». E se più fu lo suo parlar diffuso, non so, però che già ne li occhi m’era quella ch’ad altro intender m’avea chiuso. Sola sedeasi in su la terra vera, come guardia lasciata lì del plaustro che legar vidi a la biforme fera. In cerchio le facevan di sé claustro le sette ninfe, con quei lumi in mano che son sicuri d’Aquilone e d’Austro. «Qui sarai tu poco tempo silvano; e sarai meco sanza fine cive di quella Roma onde Cristo è romano. Però, in pro del mondo che mal vive, al carro tieni or li occhi, e quel che vedi, ritornato di là, fa che tu scrive». Così Beatrice; e io, che tutto ai piedi d’i suoi comandamenti era divoto, la mente e li occhi ov’ ella volle diedi. Non scese mai con sì veloce moto foco di spessa nube, quando piove da quel confine che più va remoto, com’ io vidi calar l’uccel di Giove per l’alber giù, rompendo de la scorza, non che d’i fiori e de le foglie nove; e ferì ’l carro di tutta sua forza; ond’ el piegò come nave in fortuna, vinta da l’onda, or da poggia, or da orza. Poscia vidi avventarsi ne la cuna del trïunfal veiculo una volpe che d’ogne pasto buon parea digiuna; ma, riprendendo lei di laide colpe, la donna mia la volse in tanta futa quanto sofferser l’ossa sanza polpe. Poscia per indi ond’ era pria venuta, l’aguglia vidi scender giù ne l’arca del carro e lasciar lei di sé pennuta; e qual esce di cuor che si rammarca, tal voce uscì del cielo e cotal disse: «O navicella mia, com’ mal se’ carca!». Poi parve a me che la terra s’aprisse tr’ambo le ruote, e vidi uscirne un drago che per lo carro sù la coda fisse; e come vespa che ritragge l’ago, a sé traendo la coda maligna, trasse del fondo, e gissen vago vago. Quel che rimase, come da gramigna vivace terra, da la piuma, offerta forse con intenzion sana e benigna, si ricoperse, e funne ricoperta e l’una e l’altra rota e ’l temo, in tanto che più tiene un sospir la bocca aperta. Trasformato così ’l dificio santo mise fuor teste per le parti sue, tre sovra ’l temo e una in ciascun canto. Le prime eran cornute come bue, ma le quattro un sol corno avean per fronte: simile mostro visto ancor non fue. Sicura, quasi rocca in alto monte, seder sovresso una puttana sciolta m’apparve con le ciglia intorno pronte; e come perché non li fosse tolta, vidi di costa a lei dritto un gigante; e basciavansi insieme alcuna volta. Ma perché l’occhio cupido e vagante a me rivolse, quel feroce drudo la flagellò dal capo infin le piante; poi, di sospetto pieno e d’ira crudo, disciolse il mostro, e trassel per la selva, tanto che sol di lei mi fece scudo a la puttana e a la nova belva. Purgatorio · Canto XXXIII ‘Deus, venerunt gentes’, alternando or tre or quattro dolce salmodia, le donne incominciaro, e lagrimando; e Bëatrice, sospirosa e pia, quelle ascoltava sì fatta, che poco più a la croce si cambiò Maria. Ma poi che l’altre vergini dier loco a lei di dir, levata dritta in pè, rispuose, colorata come foco: ‘Modicum, et non videbitis me; et iterum, sorelle mie dilette, modicum, et vos videbitis me’. Poi le si mise innanzi tutte e sette, e dopo sé, solo accennando, mosse me e la donna e ’l savio che ristette. Così sen giva; e non credo che fosse lo decimo suo passo in terra posto, quando con li occhi li occhi mi percosse; e con tranquillo aspetto «Vien più tosto», mi disse, «tanto che, s’io parlo teco, ad ascoltarmi tu sie ben disposto». Sì com’ io fui, com’ io dovëa, seco, dissemi: «Frate, perché non t’attenti a domandarmi omai venendo meco?». Come a color che troppo reverenti dinanzi a suo maggior parlando sono, che non traggon la voce viva ai denti, avvenne a me, che sanza intero suono incominciai: «Madonna, mia bisogna voi conoscete, e ciò ch’ad essa è buono». Ed ella a me: «Da tema e da vergogna voglio che tu omai ti disviluppe, sì che non parli più com’ om che sogna. Sappi che ’l vaso che ’l serpente ruppe, fu e non è; ma chi n’ha colpa, creda che vendetta di Dio non teme suppe. Non sarà tutto tempo sanza reda l’aguglia che lasciò le penne al carro, per che divenne mostro e poscia preda; ch’io veggio certamente, e però il narro, a darne tempo già stelle propinque, secure d’ogn’ intoppo e d’ogne sbarro, nel quale un cinquecento diece e cinque, messo di Dio, anciderà la fuia con quel gigante che con lei delinque. E forse che la mia narrazion buia, qual Temi e Sfinge, men ti persuade, perch’ a lor modo lo ’ntelletto attuia; ma tosto fier li fatti le Naiade, che solveranno questo enigma forte sanza danno di pecore o di biade. Tu nota; e sì come da me son porte, così queste parole segna a’ vivi del viver ch’è un correre a la morte. E aggi a mente, quando tu le scrivi, di non celar qual hai vista la pianta ch’è or due volte dirubata quivi. Qualunque ruba quella o quella schianta, con bestemmia di fatto offende a Dio, che solo a l’uso suo la creò santa. Per morder quella, in pena e in disio cinquemilia anni e più l’anima prima bramò colui che ’l morso in sé punio. Dorme lo ’ngegno tuo, se non estima per singular cagione esser eccelsa lei tanto e sì travolta ne la cima. E se stati non fossero acqua d’Elsa li pensier vani intorno a la tua mente, e ’l piacer loro un Piramo a la gelsa, per tante circostanze solamente la giustizia di Dio, ne l’interdetto, conosceresti a l’arbor moralmente. Ma perch’ io veggio te ne lo ’ntelletto fatto di pietra e, impetrato, tinto, sì che t’abbaglia il lume del mio detto, voglio anco, e se non scritto, almen dipinto, che ’l te ne porti dentro a te per quello che si reca il bordon di palma cinto». E io: «Sì come cera da suggello, che la figura impressa non trasmuta, segnato è or da voi lo mio cervello. Ma perché tanto sovra mia veduta vostra parola disïata vola, che più la perde quanto più s’aiuta?». «Perché conoschi», disse, «quella scuola c’hai seguitata, e veggi sua dottrina come può seguitar la mia parola; e veggi vostra via da la divina distar cotanto, quanto si discorda da terra il ciel che più alto festina». Ond’ io rispuosi lei: «Non mi ricorda ch’i’ stranïasse me già mai da voi, né honne coscïenza che rimorda». «E se tu ricordar non te ne puoi», sorridendo rispuose, «or ti rammenta come bevesti di Letè ancoi; e se dal fummo foco s’argomenta, cotesta oblivïon chiaro conchiude colpa ne la tua voglia altrove attenta. Veramente oramai saranno nude le mie parole, quanto converrassi quelle scovrire a la tua vista rude». E più corusco e con più lenti passi teneva il sole il cerchio di merigge, che qua e là, come li aspetti, fassi, quando s’affisser, sì come s’affigge chi va dinanzi a gente per iscorta se trova novitate o sue vestigge, le sette donne al fin d’un’ombra smorta, qual sotto foglie verdi e rami nigri sovra suoi freddi rivi l’alpe porta. Dinanzi ad esse Ëufratès e Tigri veder mi parve uscir d’una fontana, e, quasi amici, dipartirsi pigri. «O luce, o gloria de la gente umana, che acqua è questa che qui si dispiega da un principio e sé da sé lontana?». Per cotal priego detto mi fu: «Priega Matelda che ’l ti dica». E qui rispuose, come fa chi da colpa si dislega, la bella donna: «Questo e altre cose dette li son per me; e son sicura che l’acqua di Letè non gliel nascose». E Bëatrice: «Forse maggior cura, che spesse volte la memoria priva, fatt’ ha la mente sua ne li occhi oscura. Ma vedi Eünoè che là diriva: menalo ad esso, e come tu se’ usa, la tramortita sua virtù ravviva». Come anima gentil, che non fa scusa, ma fa sua voglia de la voglia altrui tosto che è per segno fuor dischiusa; così, poi che da essa preso fui, la bella donna mossesi, e a Stazio donnescamente disse: «Vien con lui». S’io avessi, lettor, più lungo spazio da scrivere, i’ pur cantere’ in parte lo dolce ber che mai non m’avria sazio; ma perché piene son tutte le carte ordite a questa cantica seconda, non mi lascia più ir lo fren de l’arte. Io ritornai da la santissima onda rifatto sì come piante novelle rinovellate di novella fronda, puro e disposto a salire a le stelle. PARADISO Paradiso · Canto I La gloria di colui che tutto move per l’universo penetra, e risplende in una parte più e meno altrove. Nel ciel che più de la sua luce prende fu’ io, e vidi cose che ridire né sa né può chi di là sù discende; perché appressando sé al suo disire, nostro intelletto si profonda tanto, che dietro la memoria non può ire. Veramente quant’ io del regno santo ne la mia mente potei far tesoro, sarà ora materia del mio canto. O buono Appollo, a l’ultimo lavoro fammi del tuo valor sì fatto vaso, come dimandi a dar l’amato alloro. Infino a qui l’un giogo di Parnaso assai mi fu; ma or con amendue m’è uopo intrar ne l’aringo rimaso. Entra nel petto mio, e spira tue sì come quando Marsïa traesti de la vagina de le membra sue. O divina virtù, se mi ti presti tanto che l’ombra del beato regno segnata nel mio capo io manifesti, vedra’mi al piè del tuo diletto legno venire, e coronarmi de le foglie che la materia e tu mi farai degno. Sì rade volte, padre, se ne coglie per trïunfare o cesare o poeta, colpa e vergogna de l’umane voglie, che parturir letizia in su la lieta delfica deïtà dovria la fronda peneia, quando alcun di sé asseta. Poca favilla gran fiamma seconda: forse di retro a me con miglior voci si pregherà perché Cirra risponda. Surge ai mortali per diverse foci la lucerna del mondo; ma da quella che quattro cerchi giugne con tre croci, con miglior corso e con migliore stella esce congiunta, e la mondana cera più a suo modo tempera e suggella. Fatto avea di là mane e di qua sera tal foce, e quasi tutto era là bianco quello emisperio, e l’altra parte nera, quando Beatrice in sul sinistro fianco vidi rivolta e riguardar nel sole: aguglia sì non li s’affisse unquanco. E sì come secondo raggio suole uscir del primo e risalire in suso, pur come pelegrin che tornar vuole, così de l’atto suo, per li occhi infuso ne l’imagine mia, il mio si fece, e fissi li occhi al sole oltre nostr’ uso. Molto è licito là, che qui non lece a le nostre virtù, mercé del loco fatto per proprio de l’umana spece. Io nol soffersi molto, né sì poco, ch’io nol vedessi sfavillar dintorno, com’ ferro che bogliente esce del foco; e di sùbito parve giorno a giorno essere aggiunto, come quei che puote avesse il ciel d’un altro sole addorno. Beatrice tutta ne l’etterne rote fissa con li occhi stava; e io in lei le luci fissi, di là sù rimote. Nel suo aspetto tal dentro mi fei, qual si fé Glauco nel gustar de l’erba che ’l fé consorto in mar de li altri dèi. Trasumanar significar per verba non si poria; però l’essemplo basti a cui esperïenza grazia serba. S’i’ era sol di me quel che creasti novellamente, amor che ’l ciel governi, tu ’l sai, che col tuo lume mi levasti. Quando la rota che tu sempiterni desiderato, a sé mi fece atteso con l’armonia che temperi e discerni, parvemi tanto allor del cielo acceso de la fiamma del sol, che pioggia o fiume lago non fece alcun tanto disteso. La novità del suono e ’l grande lume di lor cagion m’accesero un disio mai non sentito di cotanto acume. Ond’ ella, che vedea me sì com’ io, a quïetarmi l’animo commosso, pria ch’io a dimandar, la bocca aprio e cominciò: «Tu stesso ti fai grosso col falso imaginar, sì che non vedi ciò che vedresti se l’avessi scosso. Tu non se’ in terra, sì come tu credi; ma folgore, fuggendo il proprio sito, non corse come tu ch’ad esso riedi». S’io fui del primo dubbio disvestito per le sorrise parolette brevi, dentro ad un nuovo più fu’ inretito e dissi: «Già contento requïevi di grande ammirazion; ma ora ammiro com’ io trascenda questi corpi levi». Ond’ ella, appresso d’un pïo sospiro, li occhi drizzò ver’ me con quel sembiante che madre fa sovra figlio deliro, e cominciò: «Le cose tutte quante hanno ordine tra loro, e questo è forma che l’universo a Dio fa simigliante. Qui veggion l’alte creature l’orma de l’etterno valore, il qual è fine al quale è fatta la toccata norma. Ne l’ordine ch’io dico sono accline tutte nature, per diverse sorti, più al principio loro e men vicine; onde si muovono a diversi porti per lo gran mar de l’essere, e ciascuna con istinto a lei dato che la porti. Questi ne porta il foco inver’ la luna; questi ne’ cor mortali è permotore; questi la terra in sé stringe e aduna; né pur le creature che son fore d’intelligenza quest’ arco saetta, ma quelle c’hanno intelletto e amore. La provedenza, che cotanto assetta, del suo lume fa ’l ciel sempre quïeto nel qual si volge quel c’ha maggior fretta; e ora lì, come a sito decreto, cen porta la virtù di quella corda che ciò che scocca drizza in segno lieto. Vero è che, come forma non s’accorda molte fïate a l’intenzion de l’arte, perch’ a risponder la materia è sorda, così da questo corso si diparte talor la creatura, c’ha podere di piegar, così pinta, in altra parte; e sì come veder si può cadere foco di nube, sì l’impeto primo l’atterra torto da falso piacere. Non dei più ammirar, se bene stimo, lo tuo salir, se non come d’un rivo se d’alto monte scende giuso ad imo. Maraviglia sarebbe in te se, privo d’impedimento, giù ti fossi assiso, com’ a terra quïete in foco vivo». Quinci rivolse inver’ lo cielo il viso. Paradiso · Canto II O voi che siete in piccioletta barca, desiderosi d’ascoltar, seguiti dietro al mio legno che cantando varca, tornate a riveder li vostri liti: non vi mettete in pelago, ché forse, perdendo me, rimarreste smarriti. L’acqua ch’io prendo già mai non si corse; Minerva spira, e conducemi Appollo, e nove Muse mi dimostran l’Orse. Voialtri pochi che drizzaste il collo per tempo al pan de li angeli, del quale vivesi qui ma non sen vien satollo, metter potete ben per l’alto sale vostro navigio, servando mio solco dinanzi a l’acqua che ritorna equale. Que’ glorïosi che passaro al Colco non s’ammiraron come voi farete, quando Iasón vider fatto bifolco. La concreata e perpetüa sete del deïforme regno cen portava veloci quasi come ’l ciel vedete. Beatrice in suso, e io in lei guardava; e forse in tanto in quanto un quadrel posa e vola e da la noce si dischiava, giunto mi vidi ove mirabil cosa mi torse il viso a sé; e però quella cui non potea mia cura essere ascosa, volta ver’ me, sì lieta come bella, «Drizza la mente in Dio grata», mi disse, «che n’ha congiunti con la prima stella». Parev’ a me che nube ne coprisse lucida, spessa, solida e pulita, quasi adamante che lo sol ferisse. Per entro sé l’etterna margarita ne ricevette, com’ acqua recepe raggio di luce permanendo unita. S’io era corpo, e qui non si concepe com’ una dimensione altra patio, ch’esser convien se corpo in corpo repe, accender ne dovria più il disio di veder quella essenza in che si vede come nostra natura e Dio s’unio. Lì si vedrà ciò che tenem per fede, non dimostrato, ma fia per sé noto a guisa del ver primo che l’uom crede. Io rispuosi: «Madonna, sì devoto com’ esser posso più, ringrazio lui lo qual dal mortal mondo m’ha remoto. Ma ditemi: che son li segni bui di questo corpo, che là giuso in terra fan di Cain favoleggiare altrui?». Ella sorrise alquanto, e poi «S’elli erra l’oppinïon», mi disse, «d’i mortali dove chiave di senso non diserra, certo non ti dovrien punger li strali d’ammirazione omai, poi dietro ai sensi vedi che la ragione ha corte l’ali. Ma dimmi quel che tu da te ne pensi». E io: «Ciò che n’appar qua sù diverso credo che fanno i corpi rari e densi». Ed ella: «Certo assai vedrai sommerso nel falso il creder tuo, se bene ascolti l’argomentar ch’io li farò avverso. La spera ottava vi dimostra molti lumi, li quali e nel quale e nel quanto notar si posson di diversi volti. Se raro e denso ciò facesser tanto, una sola virtù sarebbe in tutti, più e men distributa e altrettanto. Virtù diverse esser convegnon frutti di princìpi formali, e quei, for ch’uno, seguiterieno a tua ragion distrutti. Ancor, se raro fosse di quel bruno cagion che tu dimandi, o d’oltre in parte fora di sua materia sì digiuno esto pianeto, o, sì come comparte lo grasso e ’l magro un corpo, così questo nel suo volume cangerebbe carte. Se ’l primo fosse, fora manifesto ne l’eclissi del sol, per trasparere lo lume come in altro raro ingesto. Questo non è: però è da vedere de l’altro; e s’elli avvien ch’io l’altro cassi, falsificato fia lo tuo parere. S’elli è che questo raro non trapassi, esser conviene un termine da onde lo suo contrario più passar non lassi; e indi l’altrui raggio si rifonde così come color torna per vetro lo qual di retro a sé piombo nasconde. Or dirai tu ch’el si dimostra tetro ivi lo raggio più che in altre parti, per esser lì refratto più a retro. Da questa instanza può deliberarti esperïenza, se già mai la provi, ch’esser suol fonte ai rivi di vostr’ arti. Tre specchi prenderai; e i due rimovi da te d’un modo, e l’altro, più rimosso, tr’ambo li primi li occhi tuoi ritrovi. Rivolto ad essi, fa che dopo il dosso ti stea un lume che i tre specchi accenda e torni a te da tutti ripercosso. Ben che nel quanto tanto non si stenda la vista più lontana, lì vedrai come convien ch’igualmente risplenda. Or, come ai colpi de li caldi rai de la neve riman nudo il suggetto e dal colore e dal freddo primai, così rimaso te ne l’intelletto voglio informar di luce sì vivace, che ti tremolerà nel suo aspetto. Dentro dal ciel de la divina pace si gira un corpo ne la cui virtute l’esser di tutto suo contento giace. Lo ciel seguente, c’ha tante vedute, quell’ esser parte per diverse essenze, da lui distratte e da lui contenute. Li altri giron per varie differenze le distinzion che dentro da sé hanno dispongono a lor fini e lor semenze. Questi organi del mondo così vanno, come tu vedi omai, di grado in grado, che di sù prendono e di sotto fanno. Riguarda bene omai sì com’ io vado per questo loco al vero che disiri, sì che poi sappi sol tener lo guado. Lo moto e la virtù d’i santi giri, come dal fabbro l’arte del martello, da’ beati motor convien che spiri; e ’l ciel cui tanti lumi fanno bello, de la mente profonda che lui volve prende l’image e fassene suggello. E come l’alma dentro a vostra polve per differenti membra e conformate a diverse potenze si risolve, così l’intelligenza sua bontate multiplicata per le stelle spiega, girando sé sovra sua unitate. Virtù diversa fa diversa lega col prezïoso corpo ch’ella avviva, nel qual, sì come vita in voi, si lega. Per la natura lieta onde deriva, la virtù mista per lo corpo luce come letizia per pupilla viva. Da essa vien ciò che da luce a luce par differente, non da denso e raro; essa è formal principio che produce, conforme a sua bontà, lo turbo e ’l chiaro». Paradiso · Canto III Quel sol che pria d’amor mi scaldò ’l petto, di bella verità m’avea scoverto, provando e riprovando, il dolce aspetto; e io, per confessar corretto e certo me stesso, tanto quanto si convenne leva’ il capo a proferer più erto; ma visïone apparve che ritenne a sé me tanto stretto, per vedersi, che di mia confession non mi sovvenne. Quali per vetri trasparenti e tersi, o ver per acque nitide e tranquille, non sì profonde che i fondi sien persi, tornan d’i nostri visi le postille debili sì, che perla in bianca fronte non vien men forte a le nostre pupille; tali vid’ io più facce a parlar pronte; per ch’io dentro a l’error contrario corsi a quel ch’accese amor tra l’omo e ’l fonte. Sùbito sì com’ io di lor m’accorsi, quelle stimando specchiati sembianti, per veder di cui fosser, li occhi torsi; e nulla vidi, e ritorsili avanti dritti nel lume de la dolce guida, che, sorridendo, ardea ne li occhi santi. «Non ti maravigliar perch’ io sorrida», mi disse, «appresso il tuo püeril coto, poi sopra ’l vero ancor lo piè non fida, ma te rivolve, come suole, a vòto: vere sustanze son ciò che tu vedi, qui rilegate per manco di voto. Però parla con esse e odi e credi; ché la verace luce che le appaga da sé non lascia lor torcer li piedi». E io a l’ombra che parea più vaga di ragionar, drizza’mi, e cominciai, quasi com’ uom cui troppa voglia smaga: «O ben creato spirito, che a’ rai di vita etterna la dolcezza senti che, non gustata, non s’intende mai, grazïoso mi fia se mi contenti del nome tuo e de la vostra sorte». Ond’ ella, pronta e con occhi ridenti: «La nostra carità non serra porte a giusta voglia, se non come quella che vuol simile a sé tutta sua corte. I’ fui nel mondo vergine sorella; e se la mente tua ben sé riguarda, non mi ti celerà l’esser più bella, ma riconoscerai ch’i’ son Piccarda, che, posta qui con questi altri beati, beata sono in la spera più tarda. Li nostri affetti, che solo infiammati son nel piacer de lo Spirito Santo, letizian del suo ordine formati. E questa sorte che par giù cotanto, però n’è data, perché fuor negletti li nostri voti, e vòti in alcun canto». Ond’ io a lei: «Ne’ mirabili aspetti vostri risplende non so che divino che vi trasmuta da’ primi concetti: però non fui a rimembrar festino; ma or m’aiuta ciò che tu mi dici, sì che raffigurar m’è più latino. Ma dimmi: voi che siete qui felici, disiderate voi più alto loco per più vedere e per più farvi amici?». Con quelle altr’ ombre pria sorrise un poco; da indi mi rispuose tanto lieta, ch’arder parea d’amor nel primo foco: «Frate, la nostra volontà quïeta virtù di carità, che fa volerne sol quel ch’avemo, e d’altro non ci asseta. Se disïassimo esser più superne, foran discordi li nostri disiri dal voler di colui che qui ne cerne; che vedrai non capere in questi giri, s’essere in carità è qui necesse, e se la sua natura ben rimiri. Anzi è formale ad esto beato esse tenersi dentro a la divina voglia, per ch’una fansi nostre voglie stesse; sì che, come noi sem di soglia in soglia per questo regno, a tutto il regno piace com’ a lo re che ’n suo voler ne ’nvoglia. E ’n la sua volontade è nostra pace: ell’ è quel mare al qual tutto si move ciò ch’ella crïa o che natura face». Chiaro mi fu allor come ogne dove in cielo è paradiso, etsi la grazia del sommo ben d’un modo non vi piove. Ma sì com’ elli avvien, s’un cibo sazia e d’un altro rimane ancor la gola, che quel si chere e di quel si ringrazia, così fec’ io con atto e con parola, per apprender da lei qual fu la tela onde non trasse infino a co la spuola. «Perfetta vita e alto merto inciela donna più sù», mi disse, «a la cui norma nel vostro mondo giù si veste e vela, perché fino al morir si vegghi e dorma con quello sposo ch’ogne voto accetta che caritate a suo piacer conforma. Dal mondo, per seguirla, giovinetta fuggi’mi, e nel suo abito mi chiusi e promisi la via de la sua setta. Uomini poi, a mal più ch’a bene usi, fuor mi rapiron de la dolce chiostra: Iddio si sa qual poi mia vita fusi. E quest’ altro splendor che ti si mostra da la mia destra parte e che s’accende di tutto il lume de la spera nostra, ciò ch’io dico di me, di sé intende; sorella fu, e così le fu tolta di capo l’ombra de le sacre bende. Ma poi che pur al mondo fu rivolta contra suo grado e contra buona usanza, non fu dal vel del cor già mai disciolta. Quest’ è la luce de la gran Costanza che del secondo vento di Soave generò ’l terzo e l’ultima possanza». Così parlommi, e poi cominciò ‘Ave, Maria’ cantando, e cantando vanio come per acqua cupa cosa grave. La vista mia, che tanto lei seguio quanto possibil fu, poi che la perse, volsesi al segno di maggior disio, e a Beatrice tutta si converse; ma quella folgorò nel mïo sguardo sì che da prima il viso non sofferse; e ciò mi fece a dimandar più tardo. Paradiso · Canto IV Intra due cibi, distanti e moventi d’un modo, prima si morria di fame, che liber’ omo l’un recasse ai denti; sì si starebbe un agno intra due brame di fieri lupi, igualmente temendo; sì si starebbe un cane intra due dame: per che, s’i’ mi tacea, me non riprendo, da li miei dubbi d’un modo sospinto, poi ch’era necessario, né commendo. Io mi tacea, ma ’l mio disir dipinto m’era nel viso, e ’l dimandar con ello, più caldo assai che per parlar distinto. Fé sì Beatrice qual fé Danïello, Nabuccodonosor levando d’ira, che l’avea fatto ingiustamente fello; e disse: «Io veggio ben come ti tira uno e altro disio, sì che tua cura sé stessa lega sì che fuor non spira. Tu argomenti: “Se ’l buon voler dura, la vïolenza altrui per qual ragione di meritar mi scema la misura?”. Ancor di dubitar ti dà cagione parer tornarsi l’anime a le stelle, secondo la sentenza di Platone. Queste son le question che nel tuo velle pontano igualmente; e però pria tratterò quella che più ha di felle. D’i Serafin colui che più s’india, Moïsè, Samuel, e quel Giovanni che prender vuoli, io dico, non Maria, non hanno in altro cielo i loro scanni che questi spirti che mo t’appariro, né hanno a l’esser lor più o meno anni; ma tutti fanno bello il primo giro, e differentemente han dolce vita per sentir più e men l’etterno spiro. Qui si mostraro, non perché sortita sia questa spera lor, ma per far segno de la celestïal c’ha men salita. Così parlar conviensi al vostro ingegno, però che solo da sensato apprende ciò che fa poscia d’intelletto degno. Per questo la Scrittura condescende a vostra facultate, e piedi e mano attribuisce a Dio e altro intende; e Santa Chiesa con aspetto umano Gabrïel e Michel vi rappresenta, e l’altro che Tobia rifece sano. Quel che Timeo de l’anime argomenta non è simile a ciò che qui si vede, però che, come dice, par che senta. Dice che l’alma a la sua stella riede, credendo quella quindi esser decisa quando natura per forma la diede; e forse sua sentenza è d’altra guisa che la voce non suona, ed esser puote con intenzion da non esser derisa. S’elli intende tornare a queste ruote l’onor de la influenza e ’l biasmo, forse in alcun vero suo arco percuote. Questo principio, male inteso, torse già tutto il mondo quasi, sì che Giove, Mercurio e Marte a nominar trascorse. L’altra dubitazion che ti commove ha men velen, però che sua malizia non ti poria menar da me altrove. Parere ingiusta la nostra giustizia ne li occhi d’i mortali, è argomento di fede e non d’eretica nequizia. Ma perché puote vostro accorgimento ben penetrare a questa veritate, come disiri, ti farò contento. Se vïolenza è quando quel che pate nïente conferisce a quel che sforza, non fuor quest’ alme per essa scusate: ché volontà, se non vuol, non s’ammorza, ma fa come natura face in foco, se mille volte vïolenza il torza. Per che, s’ella si piega assai o poco, segue la forza; e così queste fero possendo rifuggir nel santo loco. Se fosse stato lor volere intero, come tenne Lorenzo in su la grada, e fece Muzio a la sua man severo, così l’avria ripinte per la strada ond’ eran tratte, come fuoro sciolte; ma così salda voglia è troppo rada. E per queste parole, se ricolte l’hai come dei, è l’argomento casso che t’avria fatto noia ancor più volte. Ma or ti s’attraversa un altro passo dinanzi a li occhi, tal che per te stesso non usciresti: pria saresti lasso. Io t’ho per certo ne la mente messo ch’alma beata non poria mentire, però ch’è sempre al primo vero appresso; e poi potesti da Piccarda udire che l’affezion del vel Costanza tenne; sì ch’ella par qui meco contradire. Molte fïate già, frate, addivenne che, per fuggir periglio, contra grato si fé di quel che far non si convenne; come Almeone, che, di ciò pregato dal padre suo, la propria madre spense, per non perder pietà si fé spietato. A questo punto voglio che tu pense che la forza al voler si mischia, e fanno sì che scusar non si posson l’offense. Voglia assoluta non consente al danno; ma consentevi in tanto in quanto teme, se si ritrae, cadere in più affanno. Però, quando Piccarda quello spreme, de la voglia assoluta intende, e io de l’altra; sì che ver diciamo insieme». Cotal fu l’ondeggiar del santo rio ch’uscì del fonte ond’ ogne ver deriva; tal puose in pace uno e altro disio. «O amanza del primo amante, o diva», diss’ io appresso, «il cui parlar m’inonda e scalda sì, che più e più m’avviva, non è l’affezion mia tanto profonda, che basti a render voi grazia per grazia; ma quei che vede e puote a ciò risponda. Io veggio ben che già mai non si sazia nostro intelletto, se ’l ver non lo illustra di fuor dal qual nessun vero si spazia. Posasi in esso, come fera in lustra, tosto che giunto l’ha; e giugner puollo: se non, ciascun disio sarebbe frustra. Nasce per quello, a guisa di rampollo, a piè del vero il dubbio; ed è natura ch’al sommo pinge noi di collo in collo. Questo m’invita, questo m’assicura con reverenza, donna, a dimandarvi d’un’altra verità che m’è oscura. Io vo’ saper se l’uom può sodisfarvi ai voti manchi sì con altri beni, ch’a la vostra statera non sien parvi». Beatrice mi guardò con li occhi pieni di faville d’amor così divini, che, vinta, mia virtute diè le reni, e quasi mi perdei con li occhi chini. Paradiso · Canto V «S’io ti fiammeggio nel caldo d’amore di là dal modo che ’n terra si vede, sì che del viso tuo vinco il valore, non ti maravigliar, ché ciò procede da perfetto veder, che, come apprende, così nel bene appreso move il piede. Io veggio ben sì come già resplende ne l’intelletto tuo l’etterna luce, che, vista, sola e sempre amore accende; e s’altra cosa vostro amor seduce, non è se non di quella alcun vestigio, mal conosciuto, che quivi traluce. Tu vuo’ saper se con altro servigio, per manco voto, si può render tanto che l’anima sicuri di letigio». Sì cominciò Beatrice questo canto; e sì com’ uom che suo parlar non spezza, continüò così ’l processo santo: «Lo maggior don che Dio per sua larghezza fesse creando, e a la sua bontate più conformato, e quel ch’e’ più apprezza, fu de la volontà la libertate; di che le creature intelligenti, e tutte e sole, fuoro e son dotate. Or ti parrà, se tu quinci argomenti, l’alto valor del voto, s’è sì fatto che Dio consenta quando tu consenti; ché, nel fermar tra Dio e l’omo il patto, vittima fassi di questo tesoro, tal quale io dico; e fassi col suo atto. Dunque che render puossi per ristoro? Se credi bene usar quel c’hai offerto, di maltolletto vuo’ far buon lavoro. Tu se’ omai del maggior punto certo; ma perché Santa Chiesa in ciò dispensa, che par contra lo ver ch’i’ t’ho scoverto, convienti ancor sedere un poco a mensa, però che ’l cibo rigido c’hai preso, richiede ancora aiuto a tua dispensa. Apri la mente a quel ch’io ti paleso e fermalvi entro; ché non fa scïenza, sanza lo ritenere, avere inteso. Due cose si convegnono a l’essenza di questo sacrificio: l’una è quella di che si fa; l’altr’ è la convenenza. Quest’ ultima già mai non si cancella se non servata; e intorno di lei sì preciso di sopra si favella: però necessitato fu a li Ebrei pur l’offerere, ancor ch’alcuna offerta sì permutasse, come saver dei. L’altra, che per materia t’è aperta, puote ben esser tal, che non si falla se con altra materia si converta. Ma non trasmuti carco a la sua spalla per suo arbitrio alcun, sanza la volta e de la chiave bianca e de la gialla; e ogne permutanza credi stolta, se la cosa dimessa in la sorpresa come ’l quattro nel sei non è raccolta. Però qualunque cosa tanto pesa per suo valor che tragga ogne bilancia, sodisfar non si può con altra spesa. Non prendan li mortali il voto a ciancia; siate fedeli, e a ciò far non bieci, come Ieptè a la sua prima mancia; cui più si convenia dicer ‘Mal feci’, che, servando, far peggio; e così stolto ritrovar puoi il gran duca de’ Greci, onde pianse Efigènia il suo bel volto, e fé pianger di sé i folli e i savi ch’udir parlar di così fatto cólto. Siate, Cristiani, a muovervi più gravi: non siate come penna ad ogne vento, e non crediate ch’ogne acqua vi lavi. Avete il novo e ’l vecchio Testamento, e ’l pastor de la Chiesa che vi guida; questo vi basti a vostro salvamento. Se mala cupidigia altro vi grida, uomini siate, e non pecore matte, sì che ’l Giudeo di voi tra voi non rida! Non fate com’ agnel che lascia il latte de la sua madre, e semplice e lascivo seco medesmo a suo piacer combatte!». Così Beatrice a me com’ ïo scrivo; poi si rivolse tutta disïante a quella parte ove ’l mondo è più vivo. Lo suo tacere e ’l trasmutar sembiante puoser silenzio al mio cupido ingegno, che già nuove questioni avea davante; e sì come saetta che nel segno percuote pria che sia la corda queta, così corremmo nel secondo regno. Quivi la donna mia vid’ io sì lieta, come nel lume di quel ciel si mise, che più lucente se ne fé ’l pianeta. E se la stella si cambiò e rise, qual mi fec’ io che pur da mia natura trasmutabile son per tutte guise! Come ’n peschiera ch’è tranquilla e pura traggonsi i pesci a ciò che vien di fori per modo che lo stimin lor pastura, sì vid’ io ben più di mille splendori trarsi ver’ noi, e in ciascun s’udia: «Ecco chi crescerà li nostri amori». E sì come ciascuno a noi venìa, vedeasi l’ombra piena di letizia nel folgór chiaro che di lei uscia. Pensa, lettor, se quel che qui s’inizia non procedesse, come tu avresti di più savere angosciosa carizia; e per te vederai come da questi m’era in disio d’udir lor condizioni, sì come a li occhi mi fur manifesti. «O bene nato a cui veder li troni del trïunfo etternal concede grazia prima che la milizia s’abbandoni, del lume che per tutto il ciel si spazia noi semo accesi; e però, se disii di noi chiarirti, a tuo piacer ti sazia». Così da un di quelli spirti pii detto mi fu; e da Beatrice: «Dì, dì sicuramente, e credi come a dii». «Io veggio ben sì come tu t’annidi nel proprio lume, e che de li occhi il traggi, perch’ e’ corusca sì come tu ridi; ma non so chi tu se’, né perché aggi, anima degna, il grado de la spera che si vela a’ mortai con altrui raggi». Questo diss’ io diritto a la lumera che pria m’avea parlato; ond’ ella fessi lucente più assai di quel ch’ell’ era. Sì come il sol che si cela elli stessi per troppa luce, come ’l caldo ha róse le temperanze d’i vapori spessi, per più letizia sì mi si nascose dentro al suo raggio la figura santa; e così chiusa chiusa mi rispuose nel modo che ’l seguente canto canta. Paradiso · Canto VI «Poscia che Costantin l’aquila volse contr’ al corso del ciel, ch’ella seguio dietro a l’antico che Lavina tolse, cento e cent’ anni e più l’uccel di Dio ne lo stremo d’Europa si ritenne, vicino a’ monti de’ quai prima uscìo; e sotto l’ombra de le sacre penne governò ’l mondo lì di mano in mano, e, sì cangiando, in su la mia pervenne. Cesare fui e son Iustinïano, che, per voler del primo amor ch’i’ sento, d’entro le leggi trassi il troppo e ’l vano. E prima ch’io a l’ovra fossi attento, una natura in Cristo esser, non piùe, credea, e di tal fede era contento; ma ’l benedetto Agapito, che fue sommo pastore, a la fede sincera mi dirizzò con le parole sue. Io li credetti; e ciò che ’n sua fede era, vegg’ io or chiaro sì, come tu vedi ogni contradizione e falsa e vera. Tosto che con la Chiesa mossi i piedi, a Dio per grazia piacque di spirarmi l’alto lavoro, e tutto ’n lui mi diedi; e al mio Belisar commendai l’armi, cui la destra del ciel fu sì congiunta, che segno fu ch’i’ dovessi posarmi. Or qui a la question prima s’appunta la mia risposta; ma sua condizione mi stringe a seguitare alcuna giunta, perché tu veggi con quanta ragione si move contr’ al sacrosanto segno e chi ’l s’appropria e chi a lui s’oppone. Vedi quanta virtù l’ha fatto degno di reverenza; e cominciò da l’ora che Pallante morì per darli regno. Tu sai ch’el fece in Alba sua dimora per trecento anni e oltre, infino al fine che i tre a’ tre pugnar per lui ancora. E sai ch’el fé dal mal de le Sabine al dolor di Lucrezia in sette regi, vincendo intorno le genti vicine. Sai quel ch’el fé portato da li egregi Romani incontro a Brenno, incontro a Pirro, incontro a li altri principi e collegi; onde Torquato e Quinzio, che dal cirro negletto fu nomato, i Deci e ’ Fabi ebber la fama che volontier mirro. Esso atterrò l’orgoglio de li Aràbi che di retro ad Anibale passaro l’alpestre rocce, Po, di che tu labi. Sott’ esso giovanetti trïunfaro Scipïone e Pompeo; e a quel colle sotto ’l qual tu nascesti parve amaro. Poi, presso al tempo che tutto ’l ciel volle redur lo mondo a suo modo sereno, Cesare per voler di Roma il tolle. E quel che fé da Varo infino a Reno, Isara vide ed Era e vide Senna e ogne valle onde Rodano è pieno. Quel che fé poi ch’elli uscì di Ravenna e saltò Rubicon, fu di tal volo, che nol seguiteria lingua né penna. Inver’ la Spagna rivolse lo stuolo, poi ver’ Durazzo, e Farsalia percosse sì ch’al Nil caldo si sentì del duolo. Antandro e Simeonta, onde si mosse, rivide e là dov’ Ettore si cuba; e mal per Tolomeo poscia si scosse. Da indi scese folgorando a Iuba; onde si volse nel vostro occidente, ove sentia la pompeana tuba. Di quel che fé col baiulo seguente, Bruto con Cassio ne l’inferno latra, e Modena e Perugia fu dolente. Piangene ancor la trista Cleopatra, che, fuggendoli innanzi, dal colubro la morte prese subitana e atra. Con costui corse infino al lito rubro; con costui puose il mondo in tanta pace, che fu serrato a Giano il suo delubro. Ma ciò che ’l segno che parlar mi face fatto avea prima e poi era fatturo per lo regno mortal ch’a lui soggiace, diventa in apparenza poco e scuro, se in mano al terzo Cesare si mira con occhio chiaro e con affetto puro; ché la viva giustizia che mi spira, li concedette, in mano a quel ch’i’ dico, gloria di far vendetta a la sua ira. Or qui t’ammira in ciò ch’io ti replìco: poscia con Tito a far vendetta corse de la vendetta del peccato antico. E quando il dente longobardo morse la Santa Chiesa, sotto le sue ali Carlo Magno, vincendo, la soccorse. Omai puoi giudicar di quei cotali ch’io accusai di sopra e di lor falli, che son cagion di tutti vostri mali. L’uno al pubblico segno i gigli gialli oppone, e l’altro appropria quello a parte, sì ch’è forte a veder chi più si falli. Faccian li Ghibellin, faccian lor arte sott’ altro segno, ché mal segue quello sempre chi la giustizia e lui diparte; e non l’abbatta esto Carlo novello coi Guelfi suoi, ma tema de li artigli ch’a più alto leon trasser lo vello. Molte fïate già pianser li figli per la colpa del padre, e non si creda che Dio trasmuti l’armi per suoi gigli! Questa picciola stella si correda d’i buoni spirti che son stati attivi perché onore e fama li succeda: e quando li disiri poggian quivi, sì disvïando, pur convien che i raggi del vero amore in sù poggin men vivi. Ma nel commensurar d’i nostri gaggi col merto è parte di nostra letizia, perché non li vedem minor né maggi. Quindi addolcisce la viva giustizia in noi l’affetto sì, che non si puote torcer già mai ad alcuna nequizia. Diverse voci fanno dolci note; così diversi scanni in nostra vita rendon dolce armonia tra queste rote. E dentro a la presente margarita luce la luce di Romeo, di cui fu l’ovra grande e bella mal gradita. Ma i Provenzai che fecer contra lui non hanno riso; e però mal cammina qual si fa danno del ben fare altrui. Quattro figlie ebbe, e ciascuna reina, Ramondo Beringhiere, e ciò li fece Romeo, persona umìle e peregrina. E poi il mosser le parole biece a dimandar ragione a questo giusto, che li assegnò sette e cinque per diece, indi partissi povero e vetusto; e se ’l mondo sapesse il cor ch’elli ebbe mendicando sua vita a frusto a frusto, assai lo loda, e più lo loderebbe». Paradiso · Canto VII «Osanna, sanctus Deus sabaòth, superillustrans claritate tua felices ignes horum malacòth!». Così, volgendosi a la nota sua, fu viso a me cantare essa sustanza, sopra la qual doppio lume s’addua; ed essa e l’altre mossero a sua danza, e quasi velocissime faville mi si velar di sùbita distanza. Io dubitava e dicea ‘Dille, dille!’ fra me, ‘dille’ dicea, ‘a la mia donna che mi diseta con le dolci stille’. Ma quella reverenza che s’indonna di tutto me, pur per Be e per ice, mi richinava come l’uom ch’assonna. Poco sofferse me cotal Beatrice e cominciò, raggiandomi d’un riso tal, che nel foco faria l’uom felice: «Secondo mio infallibile avviso, come giusta vendetta giustamente punita fosse, t’ha in pensier miso; ma io ti solverò tosto la mente; e tu ascolta, ché le mie parole di gran sentenza ti faran presente. Per non soffrire a la virtù che vole freno a suo prode, quell’ uom che non nacque, dannando sé, dannò tutta sua prole; onde l’umana specie inferma giacque giù per secoli molti in grande errore, fin ch’al Verbo di Dio discender piacque u’ la natura, che dal suo fattore s’era allungata, unì a sé in persona con l’atto sol del suo etterno amore. Or drizza il viso a quel ch’or si ragiona: questa natura al suo fattore unita, qual fu creata, fu sincera e buona; ma per sé stessa pur fu ella sbandita di paradiso, però che si torse da via di verità e da sua vita. La pena dunque che la croce porse s’a la natura assunta si misura, nulla già mai sì giustamente morse; e così nulla fu di tanta ingiura, guardando a la persona che sofferse, in che era contratta tal natura. Però d’un atto uscir cose diverse: ch’a Dio e a’ Giudei piacque una morte; per lei tremò la terra e ’l ciel s’aperse. Non ti dee oramai parer più forte, quando si dice che giusta vendetta poscia vengiata fu da giusta corte. Ma io veggi’ or la tua mente ristretta di pensiero in pensier dentro ad un nodo, del qual con gran disio solver s’aspetta. Tu dici: “Ben discerno ciò ch’i’ odo; ma perché Dio volesse, m’è occulto, a nostra redenzion pur questo modo”. Questo decreto, frate, sta sepulto a li occhi di ciascuno il cui ingegno ne la fiamma d’amor non è adulto. Veramente, però ch’a questo segno molto si mira e poco si discerne, dirò perché tal modo fu più degno. La divina bontà, che da sé sperne ogne livore, ardendo in sé, sfavilla sì che dispiega le bellezze etterne. Ciò che da lei sanza mezzo distilla non ha poi fine, perché non si move la sua imprenta quand’ ella sigilla. Ciò che da essa sanza mezzo piove libero è tutto, perché non soggiace a la virtute de le cose nove. Più l’è conforme, e però più le piace; ché l’ardor santo ch’ogne cosa raggia, ne la più somigliante è più vivace. Di tutte queste dote s’avvantaggia l’umana creatura, e s’una manca, di sua nobilità convien che caggia. Solo il peccato è quel che la disfranca e falla dissimìle al sommo bene, per che del lume suo poco s’imbianca; e in sua dignità mai non rivene, se non rïempie, dove colpa vòta, contra mal dilettar con giuste pene. Vostra natura, quando peccò tota nel seme suo, da queste dignitadi, come di paradiso, fu remota; né ricovrar potiensi, se tu badi ben sottilmente, per alcuna via, sanza passar per un di questi guadi: o che Dio solo per sua cortesia dimesso avesse, o che l’uom per sé isso avesse sodisfatto a sua follia. Ficca mo l’occhio per entro l’abisso de l’etterno consiglio, quanto puoi al mio parlar distrettamente fisso. Non potea l’uomo ne’ termini suoi mai sodisfar, per non potere ir giuso con umiltate obedïendo poi, quanto disobediendo intese ir suso; e questa è la cagion per che l’uom fue da poter sodisfar per sé dischiuso. Dunque a Dio convenia con le vie sue riparar l’omo a sua intera vita, dico con l’una, o ver con amendue. Ma perché l’ovra tanto è più gradita da l’operante, quanto più appresenta de la bontà del core ond’ ell’ è uscita, la divina bontà che ’l mondo imprenta, di proceder per tutte le sue vie, a rilevarvi suso, fu contenta. Né tra l’ultima notte e ’l primo die sì alto o sì magnifico processo, o per l’una o per l’altra, fu o fie: ché più largo fu Dio a dar sé stesso per far l’uom sufficiente a rilevarsi, che s’elli avesse sol da sé dimesso; e tutti li altri modi erano scarsi a la giustizia, se ’l Figliuol di Dio non fosse umilïato ad incarnarsi. Or per empierti bene ogne disio, ritorno a dichiararti in alcun loco, perché tu veggi lì così com’ io. Tu dici: “Io veggio l’acqua, io veggio il foco, l’aere e la terra e tutte lor misture venire a corruzione, e durar poco; e queste cose pur furon creature; per che, se ciò ch’è detto è stato vero, esser dovrien da corruzion sicure”. Li angeli, frate, e ’l paese sincero nel qual tu se’, dir si posson creati, sì come sono, in loro essere intero; ma li alimenti che tu hai nomati e quelle cose che di lor si fanno da creata virtù sono informati. Creata fu la materia ch’elli hanno; creata fu la virtù informante in queste stelle che ’ntorno a lor vanno. L’anima d’ogne bruto e de le piante di complession potenzïata tira lo raggio e ’l moto de le luci sante; ma vostra vita sanza mezzo spira la somma beninanza, e la innamora di sé sì che poi sempre la disira. E quinci puoi argomentare ancora vostra resurrezion, se tu ripensi come l’umana carne fessi allora che li primi parenti intrambo fensi». Paradiso · Canto VIII Solea creder lo mondo in suo periclo che la bella Ciprigna il folle amore raggiasse, volta nel terzo epiciclo; per che non pur a lei faceano onore di sacrificio e di votivo grido le genti antiche ne l’antico errore; ma Dïone onoravano e Cupido, quella per madre sua, questo per figlio, e dicean ch’el sedette in grembo a Dido; e da costei ond’ io principio piglio pigliavano il vocabol de la stella che ’l sol vagheggia or da coppa or da ciglio. Io non m’accorsi del salire in ella; ma d’esservi entro mi fé assai fede la donna mia ch’i’ vidi far più bella. E come in fiamma favilla si vede, e come in voce voce si discerne, quand’ una è ferma e altra va e riede, vid’ io in essa luce altre lucerne muoversi in giro più e men correnti, al modo, credo, di lor viste interne. Di fredda nube non disceser venti, o visibili o no, tanto festini, che non paressero impediti e lenti a chi avesse quei lumi divini veduti a noi venir, lasciando il giro pria cominciato in li alti Serafini; e dentro a quei che più innanzi appariro sonava ‘Osanna’ sì, che unque poi di rïudir non fui sanza disiro. Indi si fece l’un più presso a noi e solo incominciò: «Tutti sem presti al tuo piacer, perché di noi ti gioi. Noi ci volgiam coi principi celesti d’un giro e d’un girare e d’una sete, ai quali tu del mondo già dicesti: ‘Voi che ’ntendendo il terzo ciel movete’; e sem sì pien d’amor, che, per piacerti, non fia men dolce un poco di quïete». Poscia che li occhi miei si fuoro offerti a la mia donna reverenti, ed essa fatti li avea di sé contenti e certi, rivolsersi a la luce che promessa tanto s’avea, e «Deh, chi siete?» fue la voce mia di grande affetto impressa. E quanta e quale vid’ io lei far piùe per allegrezza nova che s’accrebbe, quando parlai, a l’allegrezze sue! Così fatta, mi disse: «Il mondo m’ebbe giù poco tempo; e se più fosse stato, molto sarà di mal, che non sarebbe. La mia letizia mi ti tien celato che mi raggia dintorno e mi nasconde quasi animal di sua seta fasciato. Assai m’amasti, e avesti ben onde; che s’io fossi giù stato, io ti mostrava di mio amor più oltre che le fronde. Quella sinistra riva che si lava di Rodano poi ch’è misto con Sorga, per suo segnore a tempo m’aspettava, e quel corno d’Ausonia che s’imborga di Bari e di Gaeta e di Catona, da ove Tronto e Verde in mare sgorga. Fulgeami già in fronte la corona di quella terra che ’l Danubio riga poi che le ripe tedesche abbandona. E la bella Trinacria, che caliga tra Pachino e Peloro, sopra ’l golfo che riceve da Euro maggior briga, non per Tifeo ma per nascente solfo, attesi avrebbe li suoi regi ancora, nati per me di Carlo e di Ridolfo, se mala segnoria, che sempre accora li popoli suggetti, non avesse mosso Palermo a gridar: “Mora, mora!”. E se mio frate questo antivedesse, l’avara povertà di Catalogna già fuggeria, perché non li offendesse; ché veramente proveder bisogna per lui, o per altrui, sì ch’a sua barca carcata più d’incarco non si pogna. La sua natura, che di larga parca discese, avria mestier di tal milizia che non curasse di mettere in arca». «Però ch’i’ credo che l’alta letizia che ’l tuo parlar m’infonde, segnor mio, là ’ve ogne ben si termina e s’inizia, per te si veggia come la vegg’ io, grata m’è più; e anco quest’ ho caro perché ’l discerni rimirando in Dio. Fatto m’hai lieto, e così mi fa chiaro, poi che, parlando, a dubitar m’hai mosso com’ esser può, di dolce seme, amaro». Questo io a lui; ed elli a me: «S’io posso mostrarti un vero, a quel che tu dimandi terrai lo viso come tien lo dosso. Lo ben che tutto il regno che tu scandi volge e contenta, fa esser virtute sua provedenza in questi corpi grandi. E non pur le nature provedute sono in la mente ch’è da sé perfetta, ma esse insieme con la lor salute: per che quantunque quest’ arco saetta disposto cade a proveduto fine, sì come cosa in suo segno diretta. Se ciò non fosse, il ciel che tu cammine producerebbe sì li suoi effetti, che non sarebbero arti, ma ruine; e ciò esser non può, se li ’ntelletti che muovon queste stelle non son manchi, e manco il primo, che non li ha perfetti. Vuo’ tu che questo ver più ti s’imbianchi?». E io: «Non già; ché impossibil veggio che la natura, in quel ch’è uopo, stanchi». Ond’ elli ancora: «Or dì: sarebbe il peggio per l’omo in terra, se non fosse cive?». «Sì», rispuos’ io; «e qui ragion non cheggio». «E puot’ elli esser, se giù non si vive diversamente per diversi offici? Non, se ’l maestro vostro ben vi scrive». Sì venne deducendo infino a quici; poscia conchiuse: «Dunque esser diverse convien di vostri effetti le radici: per ch’un nasce Solone e altro Serse, altro Melchisedèch e altro quello che, volando per l’aere, il figlio perse. La circular natura, ch’è suggello a la cera mortal, fa ben sua arte, ma non distingue l’un da l’altro ostello. Quinci addivien ch’Esaù si diparte per seme da Iacòb; e vien Quirino da sì vil padre, che si rende a Marte. Natura generata il suo cammino simil farebbe sempre a’ generanti, se non vincesse il proveder divino. Or quel che t’era dietro t’è davanti: ma perché sappi che di te mi giova, un corollario voglio che t’ammanti. Sempre natura, se fortuna trova discorde a sé, com’ ogne altra semente fuor di sua regïon, fa mala prova. E se ’l mondo là giù ponesse mente al fondamento che natura pone, seguendo lui, avria buona la gente. Ma voi torcete a la religïone tal che fia nato a cignersi la spada, e fate re di tal ch’è da sermone; onde la traccia vostra è fuor di strada». Paradiso · Canto IX Da poi che Carlo tuo, bella Clemenza, m’ebbe chiarito, mi narrò li ’nganni che ricever dovea la sua semenza; ma disse: «Taci e lascia muover li anni»; sì ch’io non posso dir se non che pianto giusto verrà di retro ai vostri danni. E già la vita di quel lume santo rivolta s’era al Sol che la rïempie come quel ben ch’a ogne cosa è tanto. Ahi anime ingannate e fatture empie, che da sì fatto ben torcete i cuori, drizzando in vanità le vostre tempie! Ed ecco un altro di quelli splendori ver’ me si fece, e ’l suo voler piacermi significava nel chiarir di fori. Li occhi di Bëatrice, ch’eran fermi sovra me, come pria, di caro assenso al mio disio certificato fermi. «Deh, metti al mio voler tosto compenso, beato spirto», dissi, «e fammi prova ch’i’ possa in te refletter quel ch’io penso!». Onde la luce che m’era ancor nova, del suo profondo, ond’ ella pria cantava, seguette come a cui di ben far giova: «In quella parte de la terra prava italica che siede tra Rïalto e le fontane di Brenta e di Piava, si leva un colle, e non surge molt’ alto, là onde scese già una facella che fece a la contrada un grande assalto. D’una radice nacqui e io ed ella: Cunizza fui chiamata, e qui refulgo perché mi vinse il lume d’esta stella; ma lietamente a me medesma indulgo la cagion di mia sorte, e non mi noia; che parria forse forte al vostro vulgo. Di questa luculenta e cara gioia del nostro cielo che più m’è propinqua, grande fama rimase; e pria che moia, questo centesimo anno ancor s’incinqua: vedi se far si dee l’omo eccellente, sì ch’altra vita la prima relinqua. E ciò non pensa la turba presente che Tagliamento e Adice richiude, né per esser battuta ancor si pente; ma tosto fia che Padova al palude cangerà l’acqua che Vincenza bagna, per essere al dover le genti crude; e dove Sile e Cagnan s’accompagna, tal signoreggia e va con la testa alta, che già per lui carpir si fa la ragna. Piangerà Feltro ancora la difalta de l’empio suo pastor, che sarà sconcia sì, che per simil non s’entrò in malta. Troppo sarebbe larga la bigoncia che ricevesse il sangue ferrarese, e stanco chi ’l pesasse a oncia a oncia, che donerà questo prete cortese per mostrarsi di parte; e cotai doni conformi fieno al viver del paese. Sù sono specchi, voi dicete Troni, onde refulge a noi Dio giudicante; sì che questi parlar ne paion buoni». Qui si tacette; e fecemi sembiante che fosse ad altro volta, per la rota in che si mise com’ era davante. L’altra letizia, che m’era già nota per cara cosa, mi si fece in vista qual fin balasso in che lo sol percuota. Per letiziar là sù fulgor s’acquista, sì come riso qui; ma giù s’abbuia l’ombra di fuor, come la mente è trista. «Dio vede tutto, e tuo veder s’inluia», diss’ io, «beato spirto, sì che nulla voglia di sé a te puot’ esser fuia. Dunque la voce tua, che ’l ciel trastulla sempre col canto di quei fuochi pii che di sei ali facen la coculla, perché non satisface a’ miei disii? Già non attendere’ io tua dimanda, s’io m’intuassi, come tu t’inmii». «La maggior valle in che l’acqua si spanda», incominciaro allor le sue parole, «fuor di quel mar che la terra inghirlanda, tra ’ discordanti liti contra ’l sole tanto sen va, che fa meridïano là dove l’orizzonte pria far suole. Di quella valle fu’ io litorano tra Ebro e Macra, che per cammin corto parte lo Genovese dal Toscano. Ad un occaso quasi e ad un orto Buggea siede e la terra ond’ io fui, che fé del sangue suo già caldo il porto. Folco mi disse quella gente a cui fu noto il nome mio; e questo cielo di me s’imprenta, com’ io fe’ di lui; ché più non arse la figlia di Belo, noiando e a Sicheo e a Creusa, di me, infin che si convenne al pelo; né quella Rodopëa che delusa fu da Demofoonte, né Alcide quando Iole nel core ebbe rinchiusa. Non però qui si pente, ma si ride, non de la colpa, ch’a mente non torna, ma del valor ch’ordinò e provide. Qui si rimira ne l’arte ch’addorna cotanto affetto, e discernesi ’l bene per che ’l mondo di sù quel di giù torna. Ma perché tutte le tue voglie piene ten porti che son nate in questa spera, proceder ancor oltre mi convene. Tu vuo’ saper chi è in questa lumera che qui appresso me così scintilla come raggio di sole in acqua mera. Or sappi che là entro si tranquilla Raab; e a nostr’ ordine congiunta, di lei nel sommo grado si sigilla. Da questo cielo, in cui l’ombra s’appunta che ’l vostro mondo face, pria ch’altr’ alma del trïunfo di Cristo fu assunta. Ben si convenne lei lasciar per palma in alcun cielo de l’alta vittoria che s’acquistò con l’una e l’altra palma, perch’ ella favorò la prima gloria di Iosüè in su la Terra Santa, che poco tocca al papa la memoria. La tua città, che di colui è pianta che pria volse le spalle al suo fattore e di cui è la ’nvidia tanto pianta, produce e spande il maladetto fiore c’ha disvïate le pecore e li agni, però che fatto ha lupo del pastore. Per questo l’Evangelio e i dottor magni son derelitti, e solo ai Decretali si studia, sì che pare a’ lor vivagni. A questo intende il papa e ’ cardinali; non vanno i lor pensieri a Nazarette, là dove Gabrïello aperse l’ali. Ma Vaticano e l’altre parti elette di Roma che son state cimitero a la milizia che Pietro seguette, tosto libere fien de l’avoltero». Paradiso · Canto X Guardando nel suo Figlio con l’Amore che l’uno e l’altro etternalmente spira, lo primo e ineffabile Valore quanto per mente e per loco si gira con tant’ ordine fé, ch’esser non puote sanza gustar di lui chi ciò rimira. Leva dunque, lettore, a l’alte rote meco la vista, dritto a quella parte dove l’un moto e l’altro si percuote; e lì comincia a vagheggiar ne l’arte di quel maestro che dentro a sé l’ama, tanto che mai da lei l’occhio non parte. Vedi come da indi si dirama l’oblico cerchio che i pianeti porta, per sodisfare al mondo che li chiama. Che se la strada lor non fosse torta, molta virtù nel ciel sarebbe in vano, e quasi ogne potenza qua giù morta; e se dal dritto più o men lontano fosse ’l partire, assai sarebbe manco e giù e sù de l’ordine mondano. Or ti riman, lettor, sovra ’l tuo banco, dietro pensando a ciò che si preliba, s’esser vuoi lieto assai prima che stanco. Messo t’ho innanzi: omai per te ti ciba; ché a sé torce tutta la mia cura quella materia ond’ io son fatto scriba. Lo ministro maggior de la natura, che del valor del ciel lo mondo imprenta e col suo lume il tempo ne misura, con quella parte che sù si rammenta congiunto, si girava per le spire in che più tosto ognora s’appresenta; e io era con lui; ma del salire non m’accors’ io, se non com’ uom s’accorge, anzi ’l primo pensier, del suo venire. È Bëatrice quella che sì scorge di bene in meglio, sì subitamente che l’atto suo per tempo non si sporge. Quant’ esser convenia da sé lucente quel ch’era dentro al sol dov’ io entra’mi, non per color, ma per lume parvente! Perch’ io lo ’ngegno e l’arte e l’uso chiami, sì nol direi che mai s’imaginasse; ma creder puossi e di veder si brami. E se le fantasie nostre son basse a tanta altezza, non è maraviglia; ché sopra ’l sol non fu occhio ch’andasse. Tal era quivi la quarta famiglia de l’alto Padre, che sempre la sazia, mostrando come spira e come figlia. E Bëatrice cominciò: «Ringrazia, ringrazia il Sol de li angeli, ch’a questo sensibil t’ha levato per sua grazia». Cor di mortal non fu mai sì digesto a divozione e a rendersi a Dio con tutto ’l suo gradir cotanto presto, come a quelle parole mi fec’ io; e sì tutto ’l mio amore in lui si mise, che Bëatrice eclissò ne l’oblio. Non le dispiacque; ma sì se ne rise, che lo splendor de li occhi suoi ridenti mia mente unita in più cose divise. Io vidi più folgór vivi e vincenti far di noi centro e di sé far corona, più dolci in voce che in vista lucenti: così cinger la figlia di Latona vedem talvolta, quando l’aere è pregno, sì che ritenga il fil che fa la zona. Ne la corte del cielo, ond’ io rivegno, si trovan molte gioie care e belle tanto che non si posson trar del regno; e ’l canto di quei lumi era di quelle; chi non s’impenna sì che là sù voli, dal muto aspetti quindi le novelle. Poi, sì cantando, quelli ardenti soli si fuor girati intorno a noi tre volte, come stelle vicine a’ fermi poli, donne mi parver, non da ballo sciolte, ma che s’arrestin tacite, ascoltando fin che le nove note hanno ricolte. E dentro a l’un senti’ cominciar: «Quando lo raggio de la grazia, onde s’accende verace amore e che poi cresce amando, multiplicato in te tanto resplende, che ti conduce su per quella scala u’ sanza risalir nessun discende; qual ti negasse il vin de la sua fiala per la tua sete, in libertà non fora se non com’ acqua ch’al mar non si cala. Tu vuo’ saper di quai piante s’infiora questa ghirlanda che ’ntorno vagheggia la bella donna ch’al ciel t’avvalora. Io fui de li agni de la santa greggia che Domenico mena per cammino u’ ben s’impingua se non si vaneggia. Questi che m’è a destra più vicino, frate e maestro fummi, ed esso Alberto è di Cologna, e io Thomas d’Aquino. Se sì di tutti li altri esser vuo’ certo, di retro al mio parlar ten vien col viso girando su per lo beato serto. Quell’ altro fiammeggiare esce del riso di Grazïan, che l’uno e l’altro foro aiutò sì che piace in paradiso. L’altro ch’appresso addorna il nostro coro, quel Pietro fu che con la poverella offerse a Santa Chiesa suo tesoro. La quinta luce, ch’è tra noi più bella, spira di tale amor, che tutto ’l mondo là giù ne gola di saper novella: entro v’è l’alta mente u’ sì profondo saver fu messo, che, se ’l vero è vero, a veder tanto non surse il secondo. Appresso vedi il lume di quel cero che giù in carne più a dentro vide l’angelica natura e ’l ministero. Ne l’altra piccioletta luce ride quello avvocato de’ tempi cristiani del cui latino Augustin si provide. Or se tu l’occhio de la mente trani di luce in luce dietro a le mie lode, già de l’ottava con sete rimani. Per vedere ogne ben dentro vi gode l’anima santa che ’l mondo fallace fa manifesto a chi di lei ben ode. Lo corpo ond’ ella fu cacciata giace giuso in Cieldauro; ed essa da martiro e da essilio venne a questa pace. Vedi oltre fiammeggiar l’ardente spiro d’Isidoro, di Beda e di Riccardo, che a considerar fu più che viro. Questi onde a me ritorna il tuo riguardo, è ’l lume d’uno spirto che ’n pensieri gravi a morir li parve venir tardo: essa è la luce etterna di Sigieri, che, leggendo nel Vico de li Strami, silogizzò invidïosi veri». Indi, come orologio che ne chiami ne l’ora che la sposa di Dio surge a mattinar lo sposo perché l’ami, che l’una parte e l’altra tira e urge, tin tin sonando con sì dolce nota, che ’l ben disposto spirto d’amor turge; così vid’ ïo la gloriosa rota muoversi e render voce a voce in tempra e in dolcezza ch’esser non pò nota se non colà dove gioir s’insempra. Paradiso · Canto XI O insensata cura de’ mortali, quanto son difettivi silogismi quei che ti fanno in basso batter l’ali! Chi dietro a iura e chi ad amforismi sen giva, e chi seguendo sacerdozio, e chi regnar per forza o per sofismi, e chi rubare e chi civil negozio, chi nel diletto de la carne involto s’affaticava e chi si dava a l’ozio, quando, da tutte queste cose sciolto, con Bëatrice m’era suso in cielo cotanto glorïosamente accolto. Poi che ciascuno fu tornato ne lo punto del cerchio in che avanti s’era, fermossi, come a candellier candelo. E io senti’ dentro a quella lumera che pria m’avea parlato, sorridendo incominciar, faccendosi più mera: «Così com’ io del suo raggio resplendo, sì, riguardando ne la luce etterna, li tuoi pensieri onde cagioni apprendo. Tu dubbi, e hai voler che si ricerna in sì aperta e ’n sì distesa lingua lo dicer mio, ch’al tuo sentir si sterna, ove dinanzi dissi: “U’ ben s’impingua”, e là u’ dissi: “Non nacque il secondo”; e qui è uopo che ben si distingua. La provedenza, che governa il mondo con quel consiglio nel quale ogne aspetto creato è vinto pria che vada al fondo, però che andasse ver’ lo suo diletto la sposa di colui ch’ad alte grida disposò lei col sangue benedetto, in sé sicura e anche a lui più fida, due principi ordinò in suo favore, che quinci e quindi le fosser per guida. L’un fu tutto serafico in ardore; l’altro per sapïenza in terra fue di cherubica luce uno splendore. De l’un dirò, però che d’amendue si dice l’un pregiando, qual ch’om prende, perch’ ad un fine fur l’opere sue. Intra Tupino e l’acqua che discende del colle eletto dal beato Ubaldo, fertile costa d’alto monte pende, onde Perugia sente freddo e caldo da Porta Sole; e di rietro le piange per grave giogo Nocera con Gualdo. Di questa costa, là dov’ ella frange più sua rattezza, nacque al mondo un sole, come fa questo talvolta di Gange. Però chi d’esso loco fa parole, non dica Ascesi, ché direbbe corto, ma Orïente, se proprio dir vuole. Non era ancor molto lontan da l’orto, ch’el cominciò a far sentir la terra de la sua gran virtute alcun conforto; ché per tal donna, giovinetto, in guerra del padre corse, a cui, come a la morte, la porta del piacer nessun diserra; e dinanzi a la sua spirital corte et coram patre le si fece unito; poscia di dì in dì l’amò più forte. Questa, privata del primo marito, millecent’ anni e più dispetta e scura fino a costui si stette sanza invito; né valse udir che la trovò sicura con Amiclate, al suon de la sua voce, colui ch’a tutto ’l mondo fé paura; né valse esser costante né feroce, sì che, dove Maria rimase giuso, ella con Cristo pianse in su la croce. Ma perch’ io non proceda troppo chiuso, Francesco e Povertà per questi amanti prendi oramai nel mio parlar diffuso. La lor concordia e i lor lieti sembianti, amore e maraviglia e dolce sguardo facieno esser cagion di pensier santi; tanto che ’l venerabile Bernardo si scalzò prima, e dietro a tanta pace corse e, correndo, li parve esser tardo. Oh ignota ricchezza! oh ben ferace! Scalzasi Egidio, scalzasi Silvestro dietro a lo sposo, sì la sposa piace. Indi sen va quel padre e quel maestro con la sua donna e con quella famiglia che già legava l’umile capestro. Né li gravò viltà di cuor le ciglia per esser fi’ di Pietro Bernardone, né per parer dispetto a maraviglia; ma regalmente sua dura intenzione ad Innocenzio aperse, e da lui ebbe primo sigillo a sua religïone. Poi che la gente poverella crebbe dietro a costui, la cui mirabil vita meglio in gloria del ciel si canterebbe, di seconda corona redimita fu per Onorio da l’Etterno Spiro la santa voglia d’esto archimandrita. E poi che, per la sete del martiro, ne la presenza del Soldan superba predicò Cristo e li altri che ’l seguiro, e per trovare a conversione acerba troppo la gente e per non stare indarno, redissi al frutto de l’italica erba, nel crudo sasso intra Tevero e Arno da Cristo prese l’ultimo sigillo, che le sue membra due anni portarno. Quando a colui ch’a tanto ben sortillo piacque di trarlo suso a la mercede ch’el meritò nel suo farsi pusillo, a’ frati suoi, sì com’ a giuste rede, raccomandò la donna sua più cara, e comandò che l’amassero a fede; e del suo grembo l’anima preclara mover si volle, tornando al suo regno, e al suo corpo non volle altra bara. Pensa oramai qual fu colui che degno collega fu a mantener la barca di Pietro in alto mar per dritto segno; e questo fu il nostro patrïarca; per che qual segue lui, com’ el comanda, discerner puoi che buone merce carca. Ma ’l suo pecuglio di nova vivanda è fatto ghiotto, sì ch’esser non puote che per diversi salti non si spanda; e quanto le sue pecore remote e vagabunde più da esso vanno, più tornano a l’ovil di latte vòte. Ben son di quelle che temono ’l danno e stringonsi al pastor; ma son sì poche, che le cappe fornisce poco panno. Or, se le mie parole non son fioche, se la tua audïenza è stata attenta, se ciò ch’è detto a la mente revoche, in parte fia la tua voglia contenta, perché vedrai la pianta onde si scheggia, e vedra’ il corrègger che argomenta “U’ ben s’impingua, se non si vaneggia”». Paradiso · Canto XII Sì tosto come l’ultima parola la benedetta fiamma per dir tolse, a rotar cominciò la santa mola; e nel suo giro tutta non si volse prima ch’un’altra di cerchio la chiuse, e moto a moto e canto a canto colse; canto che tanto vince nostre muse, nostre serene in quelle dolci tube, quanto primo splendor quel ch’e’ refuse. Come si volgon per tenera nube due archi paralelli e concolori, quando Iunone a sua ancella iube, nascendo di quel d’entro quel di fori, a guisa del parlar di quella vaga ch’amor consunse come sol vapori, e fanno qui la gente esser presaga, per lo patto che Dio con Noè puose, del mondo che già mai più non s’allaga: così di quelle sempiterne rose volgiensi circa noi le due ghirlande, e sì l’estrema a l’intima rispuose. Poi che ’l tripudio e l’altra festa grande, sì del cantare e sì del fiammeggiarsi luce con luce gaudïose e blande, insieme a punto e a voler quetarsi, pur come li occhi ch’al piacer che i move conviene insieme chiudere e levarsi; del cor de l’una de le luci nove si mosse voce, che l’ago a la stella parer mi fece in volgermi al suo dove; e cominciò: «L’amor che mi fa bella mi tragge a ragionar de l’altro duca per cui del mio sì ben ci si favella. Degno è che, dov’ è l’un, l’altro s’induca: sì che, com’ elli ad una militaro, così la gloria loro insieme luca. L’essercito di Cristo, che sì caro costò a rïarmar, dietro a la ’nsegna si movea tardo, sospeccioso e raro, quando lo ’mperador che sempre regna provide a la milizia, ch’era in forse, per sola grazia, non per esser degna; e, come è detto, a sua sposa soccorse con due campioni, al cui fare, al cui dire lo popol disvïato si raccorse. In quella parte ove surge ad aprire Zefiro dolce le novelle fronde di che si vede Europa rivestire, non molto lungi al percuoter de l’onde dietro a le quali, per la lunga foga, lo sol talvolta ad ogne uom si nasconde, siede la fortunata Calaroga sotto la protezion del grande scudo in che soggiace il leone e soggioga: dentro vi nacque l’amoroso drudo de la fede cristiana, il santo atleta benigno a’ suoi e a’ nemici crudo; e come fu creata, fu repleta sì la sua mente di viva vertute che, ne la madre, lei fece profeta. Poi che le sponsalizie fuor compiute al sacro fonte intra lui e la Fede, u’ si dotar di mutüa salute, la donna che per lui l’assenso diede, vide nel sonno il mirabile frutto ch’uscir dovea di lui e de le rede; e perché fosse qual era in costrutto, quinci si mosse spirito a nomarlo del possessivo di cui era tutto. Domenico fu detto; e io ne parlo sì come de l’agricola che Cristo elesse a l’orto suo per aiutarlo. Ben parve messo e famigliar di Cristo: che ’l primo amor che ’n lui fu manifesto, fu al primo consiglio che diè Cristo. Spesse fïate fu tacito e desto trovato in terra da la sua nutrice, come dicesse: ‘Io son venuto a questo’. Oh padre suo veramente Felice! oh madre sua veramente Giovanna, se, interpretata, val come si dice! Non per lo mondo, per cui mo s’affanna di retro ad Ostïense e a Taddeo, ma per amor de la verace manna in picciol tempo gran dottor si feo; tal che si mise a circüir la vigna che tosto imbianca, se ’l vignaio è reo. E a la sedia che fu già benigna più a’ poveri giusti, non per lei, ma per colui che siede, che traligna, non dispensare o due o tre per sei, non la fortuna di prima vacante, non decimas, quae sunt pauperum Dei, addimandò, ma contro al mondo errante licenza di combatter per lo seme del qual ti fascian ventiquattro piante. Poi, con dottrina e con volere insieme, con l’officio appostolico si mosse quasi torrente ch’alta vena preme; e ne li sterpi eretici percosse l’impeto suo, più vivamente quivi dove le resistenze eran più grosse. Di lui si fecer poi diversi rivi onde l’orto catolico si riga, sì che i suoi arbuscelli stan più vivi. Se tal fu l’una rota de la biga in che la Santa Chiesa si difese e vinse in campo la sua civil briga, ben ti dovrebbe assai esser palese l’eccellenza de l’altra, di cui Tomma dinanzi al mio venir fu sì cortese. Ma l’orbita che fé la parte somma di sua circunferenza, è derelitta, sì ch’è la muffa dov’ era la gromma. La sua famiglia, che si mosse dritta coi piedi a le sue orme, è tanto volta, che quel dinanzi a quel di retro gitta; e tosto si vedrà de la ricolta de la mala coltura, quando il loglio si lagnerà che l’arca li sia tolta. Ben dico, chi cercasse a foglio a foglio nostro volume, ancor troveria carta u’ leggerebbe “I’ mi son quel ch’i’ soglio”; ma non fia da Casal né d’Acquasparta, là onde vegnon tali a la scrittura, ch’uno la fugge e altro la coarta. Io son la vita di Bonaventura da Bagnoregio, che ne’ grandi offici sempre pospuosi la sinistra cura. Illuminato e Augustin son quici, che fuor de’ primi scalzi poverelli che nel capestro a Dio si fero amici. Ugo da San Vittore è qui con elli, e Pietro Mangiadore e Pietro Spano, lo qual giù luce in dodici libelli; Natàn profeta e ’l metropolitano Crisostomo e Anselmo e quel Donato ch’a la prim’ arte degnò porre mano. Rabano è qui, e lucemi dallato il calavrese abate Giovacchino di spirito profetico dotato. Ad inveggiar cotanto paladino mi mosse l’infiammata cortesia di fra Tommaso e ’l discreto latino; e mosse meco questa compagnia». Paradiso · Canto XIII Imagini, chi bene intender cupe quel ch’i’ or vidi—e ritegna l’image, mentre ch’io dico, come ferma rupe—, quindici stelle che ’n diverse plage lo ciel avvivan di tanto sereno che soperchia de l’aere ogne compage; imagini quel carro a cu’ il seno basta del nostro cielo e notte e giorno, sì ch’al volger del temo non vien meno; imagini la bocca di quel corno che si comincia in punta de lo stelo a cui la prima rota va dintorno, aver fatto di sé due segni in cielo, qual fece la figliuola di Minoi allora che sentì di morte il gelo; e l’un ne l’altro aver li raggi suoi, e amendue girarsi per maniera che l’uno andasse al primo e l’altro al poi; e avrà quasi l’ombra de la vera costellazione e de la doppia danza che circulava il punto dov’ io era: poi ch’è tanto di là da nostra usanza, quanto di là dal mover de la Chiana si move il ciel che tutti li altri avanza. Lì si cantò non Bacco, non Peana, ma tre persone in divina natura, e in una persona essa e l’umana. Compié ’l cantare e ’l volger sua misura; e attesersi a noi quei santi lumi, felicitando sé di cura in cura. Ruppe il silenzio ne’ concordi numi poscia la luce in che mirabil vita del poverel di Dio narrata fumi, e disse: «Quando l’una paglia è trita, quando la sua semenza è già riposta, a batter l’altra dolce amor m’invita. Tu credi che nel petto onde la costa si trasse per formar la bella guancia il cui palato a tutto ’l mondo costa, e in quel che, forato da la lancia, e prima e poscia tanto sodisfece, che d’ogne colpa vince la bilancia, quantunque a la natura umana lece aver di lume, tutto fosse infuso da quel valor che l’uno e l’altro fece; e però miri a ciò ch’io dissi suso, quando narrai che non ebbe ’l secondo lo ben che ne la quinta luce è chiuso. Or apri li occhi a quel ch’io ti rispondo, e vedräi il tuo credere e ’l mio dire nel vero farsi come centro in tondo. Ciò che non more e ciò che può morire non è se non splendor di quella idea che partorisce, amando, il nostro Sire; ché quella viva luce che sì mea dal suo lucente, che non si disuna da lui né da l’amor ch’a lor s’intrea, per sua bontate il suo raggiare aduna, quasi specchiato, in nove sussistenze, etternalmente rimanendosi una. Quindi discende a l’ultime potenze giù d’atto in atto, tanto divenendo, che più non fa che brevi contingenze; e queste contingenze essere intendo le cose generate, che produce con seme e sanza seme il ciel movendo. La cera di costoro e chi la duce non sta d’un modo; e però sotto ’l segno idëale poi più e men traluce. Ond’ elli avvien ch’un medesimo legno, secondo specie, meglio e peggio frutta; e voi nascete con diverso ingegno. Se fosse a punto la cera dedutta e fosse il cielo in sua virtù supprema, la luce del suggel parrebbe tutta; ma la natura la dà sempre scema, similemente operando a l’artista ch’a l’abito de l’arte ha man che trema. Però se ’l caldo amor la chiara vista de la prima virtù dispone e segna, tutta la perfezion quivi s’acquista. Così fu fatta già la terra degna di tutta l’animal perfezïone; così fu fatta la Vergine pregna; sì ch’io commendo tua oppinïone, che l’umana natura mai non fue né fia qual fu in quelle due persone. Or s’i’ non procedesse avanti piùe, ‘Dunque, come costui fu sanza pare?’ comincerebber le parole tue. Ma perché paia ben ciò che non pare, pensa chi era, e la cagion che ’l mosse, quando fu detto “Chiedi”, a dimandare. Non ho parlato sì, che tu non posse ben veder ch’el fu re, che chiese senno acciò che re sufficïente fosse; non per sapere il numero in che enno li motor di qua sù, o se necesse con contingente mai necesse fenno; non si est dare primum motum esse, o se del mezzo cerchio far si puote trïangol sì ch’un retto non avesse. Onde, se ciò ch’io dissi e questo note, regal prudenza è quel vedere impari in che lo stral di mia intenzion percuote; e se al “surse” drizzi li occhi chiari, vedrai aver solamente respetto ai regi, che son molti, e ’ buon son rari. Con questa distinzion prendi ’l mio detto; e così puote star con quel che credi del primo padre e del nostro Diletto. E questo ti sia sempre piombo a’ piedi, per farti mover lento com’ uom lasso e al sì e al no che tu non vedi: ché quelli è tra li stolti bene a basso, che sanza distinzione afferma e nega ne l’un così come ne l’altro passo; perch’ elli ’ncontra che più volte piega l’oppinïon corrente in falsa parte, e poi l’affetto l’intelletto lega. Vie più che ’ndarno da riva si parte, perché non torna tal qual e’ si move, chi pesca per lo vero e non ha l’arte. E di ciò sono al mondo aperte prove Parmenide, Melisso e Brisso e molti, li quali andaro e non sapëan dove; sì fé Sabellio e Arrio e quelli stolti che furon come spade a le Scritture in render torti li diritti volti. Non sien le genti, ancor, troppo sicure a giudicar, sì come quei che stima le biade in campo pria che sien mature; ch’i’ ho veduto tutto ’l verno prima lo prun mostrarsi rigido e feroce, poscia portar la rosa in su la cima; e legno vidi già dritto e veloce correr lo mar per tutto suo cammino, perire al fine a l’intrar de la foce. Non creda donna Berta e ser Martino, per vedere un furare, altro offerere, vederli dentro al consiglio divino; ché quel può surgere, e quel può cadere». Paradiso · Canto XIV Dal centro al cerchio, e sì dal cerchio al centro movesi l’acqua in un ritondo vaso, secondo ch’è percosso fuori o dentro: ne la mia mente fé sùbito caso questo ch’io dico, sì come si tacque la glorïosa vita di Tommaso, per la similitudine che nacque del suo parlare e di quel di Beatrice, a cui sì cominciar, dopo lui, piacque: «A costui fa mestieri, e nol vi dice né con la voce né pensando ancora, d’un altro vero andare a la radice. Diteli se la luce onde s’infiora vostra sustanza, rimarrà con voi etternalmente sì com’ ell’ è ora; e se rimane, dite come, poi che sarete visibili rifatti, esser porà ch’al veder non vi nòi». Come, da più letizia pinti e tratti, a la fïata quei che vanno a rota levan la voce e rallegrano li atti, così, a l’orazion pronta e divota, li santi cerchi mostrar nova gioia nel torneare e ne la mira nota. Qual si lamenta perché qui si moia per viver colà sù, non vide quive lo refrigerio de l’etterna ploia. Quell’ uno e due e tre che sempre vive e regna sempre in tre e ’n due e ’n uno, non circunscritto, e tutto circunscrive, tre volte era cantato da ciascuno di quelli spirti con tal melodia, ch’ad ogne merto saria giusto muno. E io udi’ ne la luce più dia del minor cerchio una voce modesta, forse qual fu da l’angelo a Maria, risponder: «Quanto fia lunga la festa di paradiso, tanto il nostro amore si raggerà dintorno cotal vesta. La sua chiarezza séguita l’ardore; l’ardor la visïone, e quella è tanta, quant’ ha di grazia sovra suo valore. Come la carne glorïosa e santa fia rivestita, la nostra persona più grata fia per esser tutta quanta; per che s’accrescerà ciò che ne dona di gratüito lume il sommo bene, lume ch’a lui veder ne condiziona; onde la visïon crescer convene, crescer l’ardor che di quella s’accende, crescer lo raggio che da esso vene. Ma sì come carbon che fiamma rende, e per vivo candor quella soverchia, sì che la sua parvenza si difende; così questo folgór che già ne cerchia fia vinto in apparenza da la carne che tutto dì la terra ricoperchia; né potrà tanta luce affaticarne: ché li organi del corpo saran forti a tutto ciò che potrà dilettarne». Tanto mi parver sùbiti e accorti e l’uno e l’altro coro a dicer «Amme!», che ben mostrar disio d’i corpi morti: forse non pur per lor, ma per le mamme, per li padri e per li altri che fuor cari anzi che fosser sempiterne fiamme. Ed ecco intorno, di chiarezza pari, nascere un lustro sopra quel che v’era, per guisa d’orizzonte che rischiari. E sì come al salir di prima sera comincian per lo ciel nove parvenze, sì che la vista pare e non par vera, parvemi lì novelle sussistenze cominciare a vedere, e fare un giro di fuor da l’altre due circunferenze. Oh vero sfavillar del Santo Spiro! come si fece sùbito e candente a li occhi miei che, vinti, nol soffriro! Ma Bëatrice sì bella e ridente mi si mostrò, che tra quelle vedute si vuol lasciar che non seguir la mente. Quindi ripreser li occhi miei virtute a rilevarsi; e vidimi translato sol con mia donna in più alta salute. Ben m’accors’ io ch’io era più levato, per l’affocato riso de la stella, che mi parea più roggio che l’usato. Con tutto ’l core e con quella favella ch’è una in tutti, a Dio feci olocausto, qual conveniesi a la grazia novella. E non er’ anco del mio petto essausto l’ardor del sacrificio, ch’io conobbi esso litare stato accetto e fausto; ché con tanto lucore e tanto robbi m’apparvero splendor dentro a due raggi, ch’io dissi: «O Elïòs che sì li addobbi!». Come distinta da minori e maggi lumi biancheggia tra ’ poli del mondo Galassia sì, che fa dubbiar ben saggi; sì costellati facean nel profondo Marte quei raggi il venerabil segno che fan giunture di quadranti in tondo. Qui vince la memoria mia lo ’ngegno; ché quella croce lampeggiava Cristo, sì ch’io non so trovare essempro degno; ma chi prende sua croce e segue Cristo, ancor mi scuserà di quel ch’io lasso, vedendo in quell’ albor balenar Cristo. Di corno in corno e tra la cima e ’l basso si movien lumi, scintillando forte nel congiugnersi insieme e nel trapasso: così si veggion qui diritte e torte, veloci e tarde, rinovando vista, le minuzie d’i corpi, lunghe e corte, moversi per lo raggio onde si lista talvolta l’ombra che, per sua difesa, la gente con ingegno e arte acquista. E come giga e arpa, in tempra tesa di molte corde, fa dolce tintinno a tal da cui la nota non è intesa, così da’ lumi che lì m’apparinno s’accogliea per la croce una melode che mi rapiva, sanza intender l’inno. Ben m’accors’ io ch’elli era d’alte lode, però ch’a me venìa «Resurgi» e «Vinci» come a colui che non intende e ode. Ïo m’innamorava tanto quinci, che ’nfino a lì non fu alcuna cosa che mi legasse con sì dolci vinci. Forse la mia parola par troppo osa, posponendo il piacer de li occhi belli, ne’ quai mirando mio disio ha posa; ma chi s’avvede che i vivi suggelli d’ogne bellezza più fanno più suso, e ch’io non m’era lì rivolto a quelli, escusar puommi di quel ch’io m’accuso per escusarmi, e vedermi dir vero: ché ’l piacer santo non è qui dischiuso, perché si fa, montando, più sincero. Paradiso · Canto XV Benigna volontade in che si liqua sempre l’amor che drittamente spira, come cupidità fa ne la iniqua, silenzio puose a quella dolce lira, e fece quïetar le sante corde che la destra del cielo allenta e tira. Come saranno a’ giusti preghi sorde quelle sustanze che, per darmi voglia ch’io le pregassi, a tacer fur concorde? Bene è che sanza termine si doglia chi, per amor di cosa che non duri etternalmente, quello amor si spoglia. Quale per li seren tranquilli e puri discorre ad ora ad or sùbito foco, movendo li occhi che stavan sicuri, e pare stella che tramuti loco, se non che da la parte ond’ e’ s’accende nulla sen perde, ed esso dura poco: tale dal corno che ’n destro si stende a piè di quella croce corse un astro de la costellazion che lì resplende; né si partì la gemma dal suo nastro, ma per la lista radïal trascorse, che parve foco dietro ad alabastro. Sì pïa l’ombra d’Anchise si porse, se fede merta nostra maggior musa, quando in Eliso del figlio s’accorse. «O sanguis meus, o superinfusa gratïa Deï, sicut tibi cui bis unquam celi ianüa reclusa?». Così quel lume: ond’ io m’attesi a lui; poscia rivolsi a la mia donna il viso, e quinci e quindi stupefatto fui; ché dentro a li occhi suoi ardeva un riso tal, ch’io pensai co’ miei toccar lo fondo de la mia gloria e del mio paradiso. Indi, a udire e a veder giocondo, giunse lo spirto al suo principio cose, ch’io non lo ’ntesi, sì parlò profondo; né per elezïon mi si nascose, ma per necessità, ché ’l suo concetto al segno d’i mortal si soprapuose. E quando l’arco de l’ardente affetto fu sì sfogato, che ’l parlar discese inver’ lo segno del nostro intelletto, la prima cosa che per me s’intese, «Benedetto sia tu», fu, «trino e uno, che nel mio seme se’ tanto cortese!». E seguì: «Grato e lontano digiuno, tratto leggendo del magno volume du’ non si muta mai bianco né bruno, solvuto hai, figlio, dentro a questo lume in ch’io ti parlo, mercè di colei ch’a l’alto volo ti vestì le piume. Tu credi che a me tuo pensier mei da quel ch’è primo, così come raia da l’un, se si conosce, il cinque e ’l sei; e però ch’io mi sia e perch’ io paia più gaudïoso a te, non mi domandi, che alcun altro in questa turba gaia. Tu credi ’l vero; ché i minori e ’ grandi di questa vita miran ne lo speglio in che, prima che pensi, il pensier pandi; ma perché ’l sacro amore in che io veglio con perpetüa vista e che m’asseta di dolce disïar, s’adempia meglio, la voce tua sicura, balda e lieta suoni la volontà, suoni ’l disio, a che la mia risposta è già decreta!». Io mi volsi a Beatrice, e quella udio pria ch’io parlassi, e arrisemi un cenno che fece crescer l’ali al voler mio. Poi cominciai così: «L’affetto e ’l senno, come la prima equalità v’apparse, d’un peso per ciascun di voi si fenno, però che ’l sol che v’allumò e arse, col caldo e con la luce è sì iguali, che tutte simiglianze sono scarse. Ma voglia e argomento ne’ mortali, per la cagion ch’a voi è manifesta, diversamente son pennuti in ali; ond’ io, che son mortal, mi sento in questa disagguaglianza, e però non ringrazio se non col core a la paterna festa. Ben supplico io a te, vivo topazio che questa gioia prezïosa ingemmi, perché mi facci del tuo nome sazio». «O fronda mia in che io compiacemmi pur aspettando, io fui la tua radice»: cotal principio, rispondendo, femmi. Poscia mi disse: «Quel da cui si dice tua cognazione e che cent’ anni e piùe girato ha ’l monte in la prima cornice, mio figlio fu e tuo bisavol fue: ben si convien che la lunga fatica tu li raccorci con l’opere tue. Fiorenza dentro da la cerchia antica, ond’ ella toglie ancora e terza e nona, si stava in pace, sobria e pudica. Non avea catenella, non corona, non gonne contigiate, non cintura che fosse a veder più che la persona. Non faceva, nascendo, ancor paura la figlia al padre, che ’l tempo e la dote non fuggien quinci e quindi la misura. Non avea case di famiglia vòte; non v’era giunto ancor Sardanapalo a mostrar ciò che ’n camera si puote. Non era vinto ancora Montemalo dal vostro Uccellatoio, che, com’ è vinto nel montar sù, così sarà nel calo. Bellincion Berti vid’ io andar cinto di cuoio e d’osso, e venir da lo specchio la donna sua sanza ’l viso dipinto; e vidi quel d’i Nerli e quel del Vecchio esser contenti a la pelle scoperta, e le sue donne al fuso e al pennecchio. Oh fortunate! ciascuna era certa de la sua sepultura, e ancor nulla era per Francia nel letto diserta. L’una vegghiava a studio de la culla, e, consolando, usava l’idïoma che prima i padri e le madri trastulla; l’altra, traendo a la rocca la chioma, favoleggiava con la sua famiglia d’i Troiani, di Fiesole e di Roma. Saria tenuta allor tal maraviglia una Cianghella, un Lapo Salterello, qual or saria Cincinnato e Corniglia. A così riposato, a così bello viver di cittadini, a così fida cittadinanza, a così dolce ostello, Maria mi diè, chiamata in alte grida; e ne l’antico vostro Batisteo insieme fui cristiano e Cacciaguida. Moronto fu mio frate ed Eliseo; mia donna venne a me di val di Pado, e quindi il sopranome tuo si feo. Poi seguitai lo ’mperador Currado; ed el mi cinse de la sua milizia, tanto per bene ovrar li venni in grado. Dietro li andai incontro a la nequizia di quella legge il cui popolo usurpa, per colpa d’i pastor, vostra giustizia. Quivi fu’ io da quella gente turpa disviluppato dal mondo fallace, lo cui amor molt’ anime deturpa; e venni dal martiro a questa pace». Paradiso · Canto XVI O poca nostra nobiltà di sangue, se glorïar di te la gente fai qua giù dove l’affetto nostro langue, mirabil cosa non mi sarà mai: ché là dove appetito non si torce, dico nel cielo, io me ne gloriai. Ben se’ tu manto che tosto raccorce: sì che, se non s’appon di dì in die, lo tempo va dintorno con le force. Dal ‘voi’ che prima a Roma s’offerie, in che la sua famiglia men persevra, ricominciaron le parole mie; onde Beatrice, ch’era un poco scevra, ridendo, parve quella che tossio al primo fallo scritto di Ginevra. Io cominciai: «Voi siete il padre mio; voi mi date a parlar tutta baldezza; voi mi levate sì, ch’i’ son più ch’io. Per tanti rivi s’empie d’allegrezza la mente mia, che di sé fa letizia perché può sostener che non si spezza. Ditemi dunque, cara mia primizia, quai fuor li vostri antichi e quai fuor li anni che si segnaro in vostra püerizia; ditemi de l’ovil di San Giovanni quanto era allora, e chi eran le genti tra esso degne di più alti scanni». Come s’avviva a lo spirar d’i venti carbone in fiamma, così vid’ io quella luce risplendere a’ miei blandimenti; e come a li occhi miei si fé più bella, così con voce più dolce e soave, ma non con questa moderna favella, dissemi: «Da quel dì che fu detto ‘Ave’ al parto in che mia madre, ch’è or santa, s’allevïò di me ond’ era grave, al suo Leon cinquecento cinquanta e trenta fiate venne questo foco a rinfiammarsi sotto la sua pianta. Li antichi miei e io nacqui nel loco dove si truova pria l’ultimo sesto da quei che corre il vostro annüal gioco. Basti d’i miei maggiori udirne questo: chi ei si fosser e onde venner quivi, più è tacer che ragionare onesto. Tutti color ch’a quel tempo eran ivi da poter arme tra Marte e ’l Batista, eran il quinto di quei ch’or son vivi. Ma la cittadinanza, ch’è or mista di Campi, di Certaldo e di Fegghine, pura vediesi ne l’ultimo artista. Oh quanto fora meglio esser vicine quelle genti ch’io dico, e al Galluzzo e a Trespiano aver vostro confine, che averle dentro e sostener lo puzzo del villan d’Aguglion, di quel da Signa, che già per barattare ha l’occhio aguzzo! Se la gente ch’al mondo più traligna non fosse stata a Cesare noverca, ma come madre a suo figlio benigna, tal fatto è fiorentino e cambia e merca, che si sarebbe vòlto a Simifonti, là dove andava l’avolo a la cerca; sariesi Montemurlo ancor de’ Conti; sarieno i Cerchi nel piovier d’Acone, e forse in Valdigrieve i Buondelmonti. Sempre la confusion de le persone principio fu del mal de la cittade, come del vostro il cibo che s’appone; e cieco toro più avaccio cade che cieco agnello; e molte volte taglia più e meglio una che le cinque spade. Se tu riguardi Luni e Orbisaglia come sono ite, e come se ne vanno di retro ad esse Chiusi e Sinigaglia, udir come le schiatte si disfanno non ti parrà nova cosa né forte, poscia che le cittadi termine hanno. Le vostre cose tutte hanno lor morte, sì come voi; ma celasi in alcuna che dura molto, e le vite son corte. E come ’l volger del ciel de la luna cuopre e discuopre i liti sanza posa, così fa di Fiorenza la Fortuna: per che non dee parer mirabil cosa ciò ch’io dirò de li alti Fiorentini onde è la fama nel tempo nascosa. Io vidi li Ughi e vidi i Catellini, Filippi, Greci, Ormanni e Alberichi, già nel calare, illustri cittadini; e vidi così grandi come antichi, con quel de la Sannella, quel de l’Arca, e Soldanieri e Ardinghi e Bostichi. Sovra la porta ch’al presente è carca di nova fellonia di tanto peso che tosto fia iattura de la barca, erano i Ravignani, ond’ è disceso il conte Guido e qualunque del nome de l’alto Bellincione ha poscia preso. Quel de la Pressa sapeva già come regger si vuole, e avea Galigaio dorata in casa sua già l’elsa e ’l pome. Grand’ era già la colonna del Vaio, Sacchetti, Giuochi, Fifanti e Barucci e Galli e quei ch’arrossan per lo staio. Lo ceppo di che nacquero i Calfucci era già grande, e già eran tratti a le curule Sizii e Arrigucci. Oh quali io vidi quei che son disfatti per lor superbia! e le palle de l’oro fiorian Fiorenza in tutt’ i suoi gran fatti. Così facieno i padri di coloro che, sempre che la vostra chiesa vaca, si fanno grassi stando a consistoro. L’oltracotata schiatta che s’indraca dietro a chi fugge, e a chi mostra ’l dente o ver la borsa, com’ agnel si placa, già venìa sù, ma di picciola gente; sì che non piacque ad Ubertin Donato che poï il suocero il fé lor parente. Già era ’l Caponsacco nel mercato disceso giù da Fiesole, e già era buon cittadino Giuda e Infangato. Io dirò cosa incredibile e vera: nel picciol cerchio s’entrava per porta che si nomava da quei de la Pera. Ciascun che de la bella insegna porta del gran barone il cui nome e ’l cui pregio la festa di Tommaso riconforta, da esso ebbe milizia e privilegio; avvegna che con popol si rauni oggi colui che la fascia col fregio. Già eran Gualterotti e Importuni; e ancor saria Borgo più quïeto, se di novi vicin fosser digiuni. La casa di che nacque il vostro fleto, per lo giusto disdegno che v’ha morti e puose fine al vostro viver lieto, era onorata, essa e suoi consorti: o Buondelmonte, quanto mal fuggisti le nozze süe per li altrui conforti! Molti sarebber lieti, che son tristi, se Dio t’avesse conceduto ad Ema la prima volta ch’a città venisti. Ma conveniesi a quella pietra scema che guarda ’l ponte, che Fiorenza fesse vittima ne la sua pace postrema. Con queste genti, e con altre con esse, vid’ io Fiorenza in sì fatto riposo, che non avea cagione onde piangesse. Con queste genti vid’io glorïoso e giusto il popol suo, tanto che ’l giglio non era ad asta mai posto a ritroso, né per divisïon fatto vermiglio». Paradiso · Canto XVII Qual venne a Climenè, per accertarsi di ciò ch’avëa incontro a sé udito, quei ch’ancor fa li padri ai figli scarsi; tal era io, e tal era sentito e da Beatrice e da la santa lampa che pria per me avea mutato sito. Per che mia donna «Manda fuor la vampa del tuo disio», mi disse, «sì ch’ella esca segnata bene de la interna stampa: non perché nostra conoscenza cresca per tuo parlare, ma perché t’ausi a dir la sete, sì che l’uom ti mesca». «O cara piota mia che sì t’insusi, che, come veggion le terrene menti non capere in trïangol due ottusi, così vedi le cose contingenti anzi che sieno in sé, mirando il punto a cui tutti li tempi son presenti; mentre ch’io era a Virgilio congiunto su per lo monte che l’anime cura e discendendo nel mondo defunto, dette mi fuor di mia vita futura parole gravi, avvegna ch’io mi senta ben tetragono ai colpi di ventura; per che la voglia mia saria contenta d’intender qual fortuna mi s’appressa: ché saetta previsa vien più lenta». Così diss’ io a quella luce stessa che pria m’avea parlato; e come volle Beatrice, fu la mia voglia confessa. Né per ambage, in che la gente folle già s’inviscava pria che fosse anciso l’Agnel di Dio che le peccata tolle, ma per chiare parole e con preciso latin rispuose quello amor paterno, chiuso e parvente del suo proprio riso: «La contingenza, che fuor del quaderno de la vostra matera non si stende, tutta è dipinta nel cospetto etterno; necessità però quindi non prende se non come dal viso in che si specchia nave che per torrente giù discende. Da indi, sì come viene ad orecchia dolce armonia da organo, mi viene a vista il tempo che ti s’apparecchia. Qual si partio Ipolito d’Atene per la spietata e perfida noverca, tal di Fiorenza partir ti convene. Questo si vuole e questo già si cerca, e tosto verrà fatto a chi ciò pensa là dove Cristo tutto dì si merca. La colpa seguirà la parte offensa in grido, come suol; ma la vendetta fia testimonio al ver che la dispensa. Tu lascerai ogne cosa diletta più caramente; e questo è quello strale che l’arco de lo essilio pria saetta. Tu proverai sì come sa di sale lo pane altrui, e come è duro calle lo scendere e ’l salir per l’altrui scale. E quel che più ti graverà le spalle, sarà la compagnia malvagia e scempia con la qual tu cadrai in questa valle; che tutta ingrata, tutta matta ed empia si farà contr’ a te; ma, poco appresso, ella, non tu, n’avrà rossa la tempia. Di sua bestialitate il suo processo farà la prova; sì ch’a te fia bello averti fatta parte per te stesso. Lo primo tuo refugio e ’l primo ostello sarà la cortesia del gran Lombardo che ’n su la scala porta il santo uccello; ch’in te avrà sì benigno riguardo, che del fare e del chieder, tra voi due, fia primo quel che tra li altri è più tardo. Con lui vedrai colui che ’mpresso fue, nascendo, sì da questa stella forte, che notabili fier l’opere sue. Non se ne son le genti ancora accorte per la novella età, ché pur nove anni son queste rote intorno di lui torte; ma pria che ’l Guasco l’alto Arrigo inganni, parran faville de la sua virtute in non curar d’argento né d’affanni. Le sue magnificenze conosciute saranno ancora, sì che ’ suoi nemici non ne potran tener le lingue mute. A lui t’aspetta e a’ suoi benefici; per lui fia trasmutata molta gente, cambiando condizion ricchi e mendici; e portera’ne scritto ne la mente di lui, e nol dirai»; e disse cose incredibili a quei che fier presente. Poi giunse: «Figlio, queste son le chiose di quel che ti fu detto; ecco le ’nsidie che dietro a pochi giri son nascose. Non vo’ però ch’a’ tuoi vicini invidie, poscia che s’infutura la tua vita vie più là che ’l punir di lor perfidie». Poi che, tacendo, si mostrò spedita l’anima santa di metter la trama in quella tela ch’io le porsi ordita, io cominciai, come colui che brama, dubitando, consiglio da persona che vede e vuol dirittamente e ama: «Ben veggio, padre mio, sì come sprona lo tempo verso me, per colpo darmi tal, ch’è più grave a chi più s’abbandona; per che di provedenza è buon ch’io m’armi, sì che, se loco m’è tolto più caro, io non perdessi li altri per miei carmi. Giù per lo mondo sanza fine amaro, e per lo monte del cui bel cacume li occhi de la mia donna mi levaro, e poscia per lo ciel, di lume in lume, ho io appreso quel che s’io ridico, a molti fia sapor di forte agrume; e s’io al vero son timido amico, temo di perder viver tra coloro che questo tempo chiameranno antico». La luce in che rideva il mio tesoro ch’io trovai lì, si fé prima corusca, quale a raggio di sole specchio d’oro; indi rispuose: «Coscïenza fusca o de la propria o de l’altrui vergogna pur sentirà la tua parola brusca. Ma nondimen, rimossa ogne menzogna, tutta tua visïon fa manifesta; e lascia pur grattar dov’ è la rogna. Ché se la voce tua sarà molesta nel primo gusto, vital nodrimento lascerà poi, quando sarà digesta. Questo tuo grido farà come vento, che le più alte cime più percuote; e ciò non fa d’onor poco argomento. Però ti son mostrate in queste rote, nel monte e ne la valle dolorosa pur l’anime che son di fama note, che l’animo di quel ch’ode, non posa né ferma fede per essempro ch’aia la sua radice incognita e ascosa, né per altro argomento che non paia». Paradiso · Canto XVIII Già si godeva solo del suo verbo quello specchio beato, e io gustava lo mio, temprando col dolce l’acerbo; e quella donna ch’a Dio mi menava disse: «Muta pensier; pensa ch’i’ sono presso a colui ch’ogne torto disgrava». Io mi rivolsi a l’amoroso suono del mio conforto; e qual io allor vidi ne li occhi santi amor, qui l’abbandono: non perch’ io pur del mio parlar diffidi, ma per la mente che non può redire sovra sé tanto, s’altri non la guidi. Tanto poss’ io di quel punto ridire, che, rimirando lei, lo mio affetto libero fu da ogne altro disire, fin che ’l piacere etterno, che diretto raggiava in Bëatrice, dal bel viso mi contentava col secondo aspetto. Vincendo me col lume d’un sorriso, ella mi disse: «Volgiti e ascolta; ché non pur ne’ miei occhi è paradiso». Come si vede qui alcuna volta l’affetto ne la vista, s’elli è tanto, che da lui sia tutta l’anima tolta, così nel fiammeggiar del folgór santo, a ch’io mi volsi, conobbi la voglia in lui di ragionarmi ancora alquanto. El cominciò: «In questa quinta soglia de l’albero che vive de la cima e frutta sempre e mai non perde foglia, spiriti son beati, che giù, prima che venissero al ciel, fuor di gran voce, sì ch’ogne musa ne sarebbe opima. Però mira ne’ corni de la croce: quello ch’io nomerò, lì farà l’atto che fa in nube il suo foco veloce». Io vidi per la croce un lume tratto dal nomar Iosuè, com’ el si feo; né mi fu noto il dir prima che ’l fatto. E al nome de l’alto Macabeo vidi moversi un altro roteando, e letizia era ferza del paleo. Così per Carlo Magno e per Orlando due ne seguì lo mio attento sguardo, com’ occhio segue suo falcon volando. Poscia trasse Guiglielmo e Rinoardo e ’l duca Gottifredi la mia vista per quella croce, e Ruberto Guiscardo. Indi, tra l’altre luci mota e mista, mostrommi l’alma che m’avea parlato qual era tra i cantor del cielo artista. Io mi rivolsi dal mio destro lato per vedere in Beatrice il mio dovere, o per parlare o per atto, segnato; e vidi le sue luci tanto mere, tanto gioconde, che la sua sembianza vinceva li altri e l’ultimo solere. E come, per sentir più dilettanza bene operando, l’uom di giorno in giorno s’accorge che la sua virtute avanza, sì m’accors’ io che ’l mio girare intorno col cielo insieme avea cresciuto l’arco, veggendo quel miracol più addorno. E qual è ’l trasmutare in picciol varco di tempo in bianca donna, quando ’l volto suo si discarchi di vergogna il carco, tal fu ne li occhi miei, quando fui vòlto, per lo candor de la temprata stella sesta, che dentro a sé m’avea ricolto. Io vidi in quella giovïal facella lo sfavillar de l’amor che lì era segnare a li occhi miei nostra favella. E come augelli surti di rivera, quasi congratulando a lor pasture, fanno di sé or tonda or altra schiera, sì dentro ai lumi sante creature volitando cantavano, e faciensi or D, or I, or L in sue figure. Prima, cantando, a sua nota moviensi; poi, diventando l’un di questi segni, un poco s’arrestavano e taciensi. O diva Pegasëa che li ’ngegni fai glorïosi e rendili longevi, ed essi teco le cittadi e ’ regni, illustrami di te, sì ch’io rilevi le lor figure com’ io l’ho concette: paia tua possa in questi versi brevi! Mostrarsi dunque in cinque volte sette vocali e consonanti; e io notai le parti sì, come mi parver dette. ‘DILIGITE IUSTITIAM’, primai fur verbo e nome di tutto ’l dipinto; ‘QUI IUDICATIS TERRAM’, fur sezzai. Poscia ne l’emme del vocabol quinto rimasero ordinate; sì che Giove pareva argento lì d’oro distinto. E vidi scendere altre luci dove era il colmo de l’emme, e lì quetarsi cantando, credo, il ben ch’a sé le move. Poi, come nel percuoter d’i ciocchi arsi surgono innumerabili faville, onde li stolti sogliono agurarsi, resurger parver quindi più di mille luci e salir, qual assai e qual poco, sì come ’l sol che l’accende sortille; e quïetata ciascuna in suo loco, la testa e ’l collo d’un’aguglia vidi rappresentare a quel distinto foco. Quei che dipinge lì, non ha chi ’l guidi; ma esso guida, e da lui si rammenta quella virtù ch’è forma per li nidi. L’altra bëatitudo, che contenta pareva prima d’ingigliarsi a l’emme, con poco moto seguitò la ’mprenta. O dolce stella, quali e quante gemme mi dimostraro che nostra giustizia effetto sia del ciel che tu ingemme! Per ch’io prego la mente in che s’inizia tuo moto e tua virtute, che rimiri ond’ esce il fummo che ’l tuo raggio vizia; sì ch’un’altra fïata omai s’adiri del comperare e vender dentro al templo che si murò di segni e di martìri. O milizia del ciel cu’ io contemplo, adora per color che sono in terra tutti svïati dietro al malo essemplo! Già si solea con le spade far guerra; ma or si fa togliendo or qui or quivi lo pan che ’l pïo Padre a nessun serra. Ma tu che sol per cancellare scrivi, pensa che Pietro e Paulo, che moriro per la vigna che guasti, ancor son vivi. Ben puoi tu dire: «I’ ho fermo ’l disiro sì a colui che volle viver solo e che per salti fu tratto al martiro, ch’io non conosco il pescator né Polo». Paradiso · Canto XIX Parea dinanzi a me con l’ali aperte la bella image che nel dolce frui liete facevan l’anime conserte; parea ciascuna rubinetto in cui raggio di sole ardesse sì acceso, che ne’ miei occhi rifrangesse lui. E quel che mi convien ritrar testeso, non portò voce mai, né scrisse incostro, né fu per fantasia già mai compreso; ch’io vidi e anche udi’ parlar lo rostro, e sonar ne la voce e «io» e «mio», quand’ era nel concetto e ‘noi’ e ‘nostro’. E cominciò: «Per esser giusto e pio son io qui essaltato a quella gloria che non si lascia vincere a disio; e in terra lasciai la mia memoria sì fatta, che le genti lì malvage commendan lei, ma non seguon la storia». Così un sol calor di molte brage si fa sentir, come di molti amori usciva solo un suon di quella image. Ond’ io appresso: «O perpetüi fiori de l’etterna letizia, che pur uno parer mi fate tutti vostri odori, solvetemi, spirando, il gran digiuno che lungamente m’ha tenuto in fame, non trovandoli in terra cibo alcuno. Ben so io che, se ’n cielo altro reame la divina giustizia fa suo specchio, che ’l vostro non l’apprende con velame. Sapete come attento io m’apparecchio ad ascoltar; sapete qual è quello dubbio che m’è digiun cotanto vecchio». Quasi falcone ch’esce del cappello, move la testa e con l’ali si plaude, voglia mostrando e faccendosi bello, vid’ io farsi quel segno, che di laude de la divina grazia era contesto, con canti quai si sa chi là sù gaude. Poi cominciò: «Colui che volse il sesto a lo stremo del mondo, e dentro ad esso distinse tanto occulto e manifesto, non poté suo valor sì fare impresso in tutto l’universo, che ’l suo verbo non rimanesse in infinito eccesso. E ciò fa certo che ’l primo superbo, che fu la somma d’ogne creatura, per non aspettar lume, cadde acerbo; e quinci appar ch’ogne minor natura è corto recettacolo a quel bene che non ha fine e sé con sé misura. Dunque vostra veduta, che convene esser alcun de’ raggi de la mente di che tutte le cose son ripiene, non pò da sua natura esser possente tanto, che suo principio discerna molto di là da quel che l’è parvente. Però ne la giustizia sempiterna la vista che riceve il vostro mondo, com’ occhio per lo mare, entro s’interna; che, ben che da la proda veggia il fondo, in pelago nol vede; e nondimeno èli, ma cela lui l’esser profondo. Lume non è, se non vien dal sereno che non si turba mai; anzi è tenèbra od ombra de la carne o suo veleno. Assai t’è mo aperta la latebra che t’ascondeva la giustizia viva, di che facei question cotanto crebra; ché tu dicevi: “Un uom nasce a la riva de l’Indo, e quivi non è chi ragioni di Cristo né chi legga né chi scriva; e tutti suoi voleri e atti buoni sono, quanto ragione umana vede, sanza peccato in vita o in sermoni. Muore non battezzato e sanza fede: ov’ è questa giustizia che ’l condanna? ov’ è la colpa sua, se ei non crede?”. Or tu chi se’, che vuo’ sedere a scranna, per giudicar di lungi mille miglia con la veduta corta d’una spanna? Certo a colui che meco s’assottiglia, se la Scrittura sovra voi non fosse, da dubitar sarebbe a maraviglia. Oh terreni animali! oh menti grosse! La prima volontà, ch’è da sé buona, da sé, ch’è sommo ben, mai non si mosse. Cotanto è giusto quanto a lei consuona: nullo creato bene a sé la tira, ma essa, radïando, lui cagiona». Quale sovresso il nido si rigira poi c’ha pasciuti la cicogna i figli, e come quel ch’è pasto la rimira; cotal si fece, e sì leväi i cigli, la benedetta imagine, che l’ali movea sospinte da tanti consigli. Roteando cantava, e dicea: «Quali son le mie note a te, che non le ’ntendi, tal è il giudicio etterno a voi mortali». Poi si quetaro quei lucenti incendi de lo Spirito Santo ancor nel segno che fé i Romani al mondo reverendi, esso ricominciò: «A questo regno non salì mai chi non credette ’n Cristo, né pria né poi ch’el si chiavasse al legno. Ma vedi: molti gridan “Cristo, Cristo!”, che saranno in giudicio assai men prope a lui, che tal che non conosce Cristo; e tai Cristian dannerà l’Etïòpe, quando si partiranno i due collegi, l’uno in etterno ricco e l’altro inòpe. Che poran dir li Perse a’ vostri regi, come vedranno quel volume aperto nel qual si scrivon tutti suoi dispregi? Lì si vedrà, tra l’opere d’Alberto, quella che tosto moverà la penna, per che ’l regno di Praga fia diserto. Lì si vedrà il duol che sovra Senna induce, falseggiando la moneta, quel che morrà di colpo di cotenna. Lì si vedrà la superbia ch’asseta, che fa lo Scotto e l’Inghilese folle, sì che non può soffrir dentro a sua meta. Vedrassi la lussuria e ’l viver molle di quel di Spagna e di quel di Boemme, che mai valor non conobbe né volle. Vedrassi al Ciotto di Ierusalemme segnata con un i la sua bontate, quando ’l contrario segnerà un emme. Vedrassi l’avarizia e la viltate di quei che guarda l’isola del foco, ove Anchise finì la lunga etate; e a dare ad intender quanto è poco, la sua scrittura fian lettere mozze, che noteranno molto in parvo loco. E parranno a ciascun l’opere sozze del barba e del fratel, che tanto egregia nazione e due corone han fatte bozze. E quel di Portogallo e di Norvegia lì si conosceranno, e quel di Rascia che male ha visto il conio di Vinegia. Oh beata Ungheria, se non si lascia più malmenare! e beata Navarra, se s’armasse del monte che la fascia! E creder de’ ciascun che già, per arra di questo, Niccosïa e Famagosta per la lor bestia si lamenti e garra, che dal fianco de l’altre non si scosta». Paradiso · Canto XX Quando colui che tutto ’l mondo alluma de l’emisperio nostro sì discende, che ’l giorno d’ogne parte si consuma, lo ciel, che sol di lui prima s’accende, subitamente si rifà parvente per molte luci, in che una risplende; e questo atto del ciel mi venne a mente, come ’l segno del mondo e de’ suoi duci nel benedetto rostro fu tacente; però che tutte quelle vive luci, vie più lucendo, cominciaron canti da mia memoria labili e caduci. O dolce amor che di riso t’ammanti, quanto parevi ardente in que’ flailli, ch’avieno spirto sol di pensier santi! Poscia che i cari e lucidi lapilli ond’ io vidi ingemmato il sesto lume puoser silenzio a li angelici squilli, udir mi parve un mormorar di fiume che scende chiaro giù di pietra in pietra, mostrando l’ubertà del suo cacume. E come suono al collo de la cetra prende sua forma, e sì com’ al pertugio de la sampogna vento che penètra, così, rimosso d’aspettare indugio, quel mormorar de l’aguglia salissi su per lo collo, come fosse bugio. Fecesi voce quivi, e quindi uscissi per lo suo becco in forma di parole, quali aspettava il core ov’ io le scrissi. «La parte in me che vede e pate il sole ne l’aguglie mortali», incominciommi, «or fisamente riguardar si vole, perché d’i fuochi ond’ io figura fommi, quelli onde l’occhio in testa mi scintilla, e’ di tutti lor gradi son li sommi. Colui che luce in mezzo per pupilla, fu il cantor de lo Spirito Santo, che l’arca traslatò di villa in villa: ora conosce il merto del suo canto, in quanto effetto fu del suo consiglio, per lo remunerar ch’è altrettanto. Dei cinque che mi fan cerchio per ciglio, colui che più al becco mi s’accosta, la vedovella consolò del figlio: ora conosce quanto caro costa non seguir Cristo, per l’esperïenza di questa dolce vita e de l’opposta. E quel che segue in la circunferenza di che ragiono, per l’arco superno, morte indugiò per vera penitenza: ora conosce che ’l giudicio etterno non si trasmuta, quando degno preco fa crastino là giù de l’odïerno. L’altro che segue, con le leggi e meco, sotto buona intenzion che fé mal frutto, per cedere al pastor si fece greco: ora conosce come il mal dedutto dal suo bene operar non li è nocivo, avvegna che sia ’l mondo indi distrutto. E quel che vedi ne l’arco declivo, Guiglielmo fu, cui quella terra plora che piagne Carlo e Federigo vivo: ora conosce come s’innamora lo ciel del giusto rege, e al sembiante del suo fulgore il fa vedere ancora. Chi crederebbe giù nel mondo errante che Rifëo Troiano in questo tondo fosse la quinta de le luci sante? Ora conosce assai di quel che ’l mondo veder non può de la divina grazia, ben che sua vista non discerna il fondo». Quale allodetta che ’n aere si spazia prima cantando, e poi tace contenta de l’ultima dolcezza che la sazia, tal mi sembiò l’imago de la ’mprenta de l’etterno piacere, al cui disio ciascuna cosa qual ell’ è diventa. E avvegna ch’io fossi al dubbiar mio lì quasi vetro a lo color ch’el veste, tempo aspettar tacendo non patio, ma de la bocca, «Che cose son queste?», mi pinse con la forza del suo peso: per ch’io di coruscar vidi gran feste. Poi appresso, con l’occhio più acceso, lo benedetto segno mi rispuose per non tenermi in ammirar sospeso: «Io veggio che tu credi queste cose perch’ io le dico, ma non vedi come; sì che, se son credute, sono ascose. Fai come quei che la cosa per nome apprende ben, ma la sua quiditate veder non può se altri non la prome. Regnum celorum vïolenza pate da caldo amore e da viva speranza, che vince la divina volontate: non a guisa che l’omo a l’om sobranza, ma vince lei perché vuole esser vinta, e, vinta, vince con sua beninanza. La prima vita del ciglio e la quinta ti fa maravigliar, perché ne vedi la regïon de li angeli dipinta. D’i corpi suoi non uscir, come credi, Gentili, ma Cristiani, in ferma fede quel d’i passuri e quel d’i passi piedi. Ché l’una de lo ’nferno, u’ non si riede già mai a buon voler, tornò a l’ossa; e ciò di viva spene fu mercede: di viva spene, che mise la possa ne’ prieghi fatti a Dio per suscitarla, sì che potesse sua voglia esser mossa. L’anima glorïosa onde si parla, tornata ne la carne, in che fu poco, credette in lui che potëa aiutarla; e credendo s’accese in tanto foco di vero amor, ch’a la morte seconda fu degna di venire a questo gioco. L’altra, per grazia che da sì profonda fontana stilla, che mai creatura non pinse l’occhio infino a la prima onda, tutto suo amor là giù pose a drittura: per che, di grazia in grazia, Dio li aperse l’occhio a la nostra redenzion futura; ond’ ei credette in quella, e non sofferse da indi il puzzo più del paganesmo; e riprendiene le genti perverse. Quelle tre donne li fur per battesmo che tu vedesti da la destra rota, dinanzi al battezzar più d’un millesmo. O predestinazion, quanto remota è la radice tua da quelli aspetti che la prima cagion non veggion tota! E voi, mortali, tenetevi stretti a giudicar: ché noi, che Dio vedemo, non conosciamo ancor tutti li eletti; ed ènne dolce così fatto scemo, perché il ben nostro in questo ben s’affina, che quel che vole Iddio, e noi volemo». Così da quella imagine divina, per farmi chiara la mia corta vista, data mi fu soave medicina. E come a buon cantor buon citarista fa seguitar lo guizzo de la corda, in che più di piacer lo canto acquista, sì, mentre ch’e’ parlò, sì mi ricorda ch’io vidi le due luci benedette, pur come batter d’occhi si concorda, con le parole mover le fiammette. Paradiso · Canto XXI Già eran li occhi miei rifissi al volto de la mia donna, e l’animo con essi, e da ogne altro intento s’era tolto. E quella non ridea; ma «S’io ridessi», mi cominciò, «tu ti faresti quale fu Semelè quando di cener fessi: ché la bellezza mia, che per le scale de l’etterno palazzo più s’accende, com’ hai veduto, quanto più si sale, se non si temperasse, tanto splende, che ’l tuo mortal podere, al suo fulgore, sarebbe fronda che trono scoscende. Noi sem levati al settimo splendore, che sotto ’l petto del Leone ardente raggia mo misto giù del suo valore. Ficca di retro a li occhi tuoi la mente, e fa di quelli specchi a la figura che ’n questo specchio ti sarà parvente». Qual savesse qual era la pastura del viso mio ne l’aspetto beato quand’ io mi trasmutai ad altra cura, conoscerebbe quanto m’era a grato ubidire a la mia celeste scorta, contrapesando l’un con l’altro lato. Dentro al cristallo che ’l vocabol porta, cerchiando il mondo, del suo caro duce sotto cui giacque ogne malizia morta, di color d’oro in che raggio traluce vid’ io uno scaleo eretto in suso tanto, che nol seguiva la mia luce. Vidi anche per li gradi scender giuso tanti splendor, ch’io pensai ch’ogne lume che par nel ciel, quindi fosse diffuso. E come, per lo natural costume, le pole insieme, al cominciar del giorno, si movono a scaldar le fredde piume; poi altre vanno via sanza ritorno, altre rivolgon sé onde son mosse, e altre roteando fan soggiorno; tal modo parve me che quivi fosse in quello sfavillar che ’nsieme venne, sì come in certo grado si percosse. E quel che presso più ci si ritenne, si fé sì chiaro, ch’io dicea pensando: ‘Io veggio ben l’amor che tu m’accenne. Ma quella ond’ io aspetto il come e ’l quando del dire e del tacer, si sta; ond’ io, contra ’l disio, fo ben ch’io non dimando’. Per ch’ella, che vedëa il tacer mio nel veder di colui che tutto vede, mi disse: «Solvi il tuo caldo disio». E io incominciai: «La mia mercede non mi fa degno de la tua risposta; ma per colei che ’l chieder mi concede, vita beata che ti stai nascosta dentro a la tua letizia, fammi nota la cagion che sì presso mi t’ha posta; e dì perché si tace in questa rota la dolce sinfonia di paradiso, che giù per l’altre suona sì divota». «Tu hai l’udir mortal sì come il viso», rispuose a me; «onde qui non si canta per quel che Bëatrice non ha riso. Giù per li gradi de la scala santa discesi tanto sol per farti festa col dire e con la luce che mi ammanta; né più amor mi fece esser più presta, ché più e tanto amor quinci sù ferve, sì come il fiammeggiar ti manifesta. Ma l’alta carità, che ci fa serve pronte al consiglio che ’l mondo governa, sorteggia qui sì come tu osserve». «Io veggio ben», diss’ io, «sacra lucerna, come libero amore in questa corte basta a seguir la provedenza etterna; ma questo è quel ch’a cerner mi par forte, perché predestinata fosti sola a questo officio tra le tue consorte». Né venni prima a l’ultima parola, che del suo mezzo fece il lume centro, girando sé come veloce mola; poi rispuose l’amor che v’era dentro: «Luce divina sopra me s’appunta, penetrando per questa in ch’io m’inventro, la cui virtù, col mio veder congiunta, mi leva sopra me tanto, ch’i’ veggio la somma essenza de la quale è munta. Quinci vien l’allegrezza ond’ io fiammeggio; per ch’a la vista mia, quant’ ella è chiara, la chiarità de la fiamma pareggio. Ma quell’ alma nel ciel che più si schiara, quel serafin che ’n Dio più l’occhio ha fisso, a la dimanda tua non satisfara, però che sì s’innoltra ne lo abisso de l’etterno statuto quel che chiedi, che da ogne creata vista è scisso. E al mondo mortal, quando tu riedi, questo rapporta, sì che non presumma a tanto segno più mover li piedi. La mente, che qui luce, in terra fumma; onde riguarda come può là giùe quel che non pote perché ’l ciel l’assumma». Sì mi prescrisser le parole sue, ch’io lasciai la quistione e mi ritrassi a dimandarla umilmente chi fue. «Tra ’ due liti d’Italia surgon sassi, e non molto distanti a la tua patria, tanto che ’ troni assai suonan più bassi, e fanno un gibbo che si chiama Catria, di sotto al quale è consecrato un ermo, che suole esser disposto a sola latria». Così ricominciommi il terzo sermo; e poi, continüando, disse: «Quivi al servigio di Dio mi fe’ sì fermo, che pur con cibi di liquor d’ulivi lievemente passava caldi e geli, contento ne’ pensier contemplativi. Render solea quel chiostro a questi cieli fertilemente; e ora è fatto vano, sì che tosto convien che si riveli. In quel loco fu’ io Pietro Damiano, e Pietro Peccator fu’ ne la casa di Nostra Donna in sul lito adriano. Poca vita mortal m’era rimasa, quando fui chiesto e tratto a quel cappello, che pur di male in peggio si travasa. Venne Cefàs e venne il gran vasello de lo Spirito Santo, magri e scalzi, prendendo il cibo da qualunque ostello. Or voglion quinci e quindi chi rincalzi li moderni pastori e chi li meni, tanto son gravi, e chi di rietro li alzi. Cuopron d’i manti loro i palafreni, sì che due bestie van sott’ una pelle: oh pazïenza che tanto sostieni!». A questa voce vid’ io più fiammelle di grado in grado scendere e girarsi, e ogne giro le facea più belle. Dintorno a questa vennero e fermarsi, e fero un grido di sì alto suono, che non potrebbe qui assomigliarsi; né io lo ’ntesi, sì mi vinse il tuono. Paradiso · Canto XXII Oppresso di stupore, a la mia guida mi volsi, come parvol che ricorre sempre colà dove più si confida; e quella, come madre che soccorre sùbito al figlio palido e anelo con la sua voce, che ’l suol ben disporre, mi disse: «Non sai tu che tu se’ in cielo? e non sai tu che ’l cielo è tutto santo, e ciò che ci si fa vien da buon zelo? Come t’avrebbe trasmutato il canto, e io ridendo, mo pensar lo puoi, poscia che ’l grido t’ha mosso cotanto; nel qual, se ’nteso avessi i prieghi suoi, già ti sarebbe nota la vendetta che tu vedrai innanzi che tu muoi. La spada di qua sù non taglia in fretta né tardo, ma’ ch’al parer di colui che disïando o temendo l’aspetta. Ma rivolgiti omai inverso altrui; ch’assai illustri spiriti vedrai, se com’ io dico l’aspetto redui». Come a lei piacque, li occhi ritornai, e vidi cento sperule che ’nsieme più s’abbellivan con mutüi rai. Io stava come quei che ’n sé repreme la punta del disio, e non s’attenta di domandar, sì del troppo si teme; e la maggiore e la più luculenta di quelle margherite innanzi fessi, per far di sé la mia voglia contenta. Poi dentro a lei udi’: «Se tu vedessi com’ io la carità che tra noi arde, li tuoi concetti sarebbero espressi. Ma perché tu, aspettando, non tarde a l’alto fine, io ti farò risposta pur al pensier, da che sì ti riguarde. Quel monte a cui Cassino è ne la costa fu frequentato già in su la cima da la gente ingannata e mal disposta; e quel son io che sù vi portai prima lo nome di colui che ’n terra addusse la verità che tanto ci soblima; e tanta grazia sopra me relusse, ch’io ritrassi le ville circunstanti da l’empio cólto che ’l mondo sedusse. Questi altri fuochi tutti contemplanti uomini fuoro, accesi di quel caldo che fa nascere i fiori e ’ frutti santi. Qui è Maccario, qui è Romoaldo, qui son li frati miei che dentro ai chiostri fermar li piedi e tennero il cor saldo». E io a lui: «L’affetto che dimostri meco parlando, e la buona sembianza ch’io veggio e noto in tutti li ardor vostri, così m’ha dilatata mia fidanza, come ’l sol fa la rosa quando aperta tanto divien quant’ ell’ ha di possanza. Però ti priego, e tu, padre, m’accerta s’io posso prender tanta grazia, ch’io ti veggia con imagine scoverta». Ond’ elli: «Frate, il tuo alto disio s’adempierà in su l’ultima spera, ove s’adempion tutti li altri e ’l mio. Ivi è perfetta, matura e intera ciascuna disïanza; in quella sola è ogne parte là ove sempr’ era, perché non è in loco e non s’impola; e nostra scala infino ad essa varca, onde così dal viso ti s’invola. Infin là sù la vide il patriarca Iacobbe porger la superna parte, quando li apparve d’angeli sì carca. Ma, per salirla, mo nessun diparte da terra i piedi, e la regola mia rimasa è per danno de le carte. Le mura che solieno esser badia fatte sono spelonche, e le cocolle sacca son piene di farina ria. Ma grave usura tanto non si tolle contra ’l piacer di Dio, quanto quel frutto che fa il cor de’ monaci sì folle; ché quantunque la Chiesa guarda, tutto è de la gente che per Dio dimanda; non di parenti né d’altro più brutto. La carne d’i mortali è tanto blanda, che giù non basta buon cominciamento dal nascer de la quercia al far la ghianda. Pier cominciò sanz’ oro e sanz’ argento, e io con orazione e con digiuno, e Francesco umilmente il suo convento; e se guardi ’l principio di ciascuno, poscia riguardi là dov’ è trascorso, tu vederai del bianco fatto bruno. Veramente Iordan vòlto retrorso più fu, e ’l mar fuggir, quando Dio volse, mirabile a veder che qui ’l soccorso». Così mi disse, e indi si raccolse al suo collegio, e ’l collegio si strinse; poi, come turbo, in sù tutto s’avvolse. La dolce donna dietro a lor mi pinse con un sol cenno su per quella scala, sì sua virtù la mia natura vinse; né mai qua giù dove si monta e cala naturalmente, fu sì ratto moto ch’agguagliar si potesse a la mia ala. S’io torni mai, lettore, a quel divoto trïunfo per lo quale io piango spesso le mie peccata e ’l petto mi percuoto, tu non avresti in tanto tratto e messo nel foco il dito, in quant’ io vidi ’l segno che segue il Tauro e fui dentro da esso. O glorïose stelle, o lume pregno di gran virtù, dal quale io riconosco tutto, qual che si sia, il mio ingegno, con voi nasceva e s’ascondeva vosco quelli ch’è padre d’ogne mortal vita, quand’ io senti’ di prima l’aere tosco; e poi, quando mi fu grazia largita d’entrar ne l’alta rota che vi gira, la vostra regïon mi fu sortita. A voi divotamente ora sospira l’anima mia, per acquistar virtute al passo forte che a sé la tira. «Tu se’ sì presso a l’ultima salute», cominciò Bëatrice, «che tu dei aver le luci tue chiare e acute; e però, prima che tu più t’inlei, rimira in giù, e vedi quanto mondo sotto li piedi già esser ti fei; sì che ’l tuo cor, quantunque può, giocondo s’appresenti a la turba trïunfante che lieta vien per questo etera tondo». Col viso ritornai per tutte quante le sette spere, e vidi questo globo tal, ch’io sorrisi del suo vil sembiante; e quel consiglio per migliore approbo che l’ha per meno; e chi ad altro pensa chiamar si puote veramente probo. Vidi la figlia di Latona incensa sanza quell’ ombra che mi fu cagione per che già la credetti rara e densa. L’aspetto del tuo nato, Iperïone, quivi sostenni, e vidi com’ si move circa e vicino a lui Maia e Dïone. Quindi m’apparve il temperar di Giove tra ’l padre e ’l figlio; e quindi mi fu chiaro il varïar che fanno di lor dove; e tutti e sette mi si dimostraro quanto son grandi e quanto son veloci e come sono in distante riparo. L’aiuola che ci fa tanto feroci, volgendom’ io con li etterni Gemelli, tutta m’apparve da’ colli a le foci; poscia rivolsi li occhi a li occhi belli. Paradiso · Canto XXIII Come l’augello, intra l’amate fronde, posato al nido de’ suoi dolci nati la notte che le cose ci nasconde, che, per veder li aspetti disïati e per trovar lo cibo onde li pasca, in che gravi labor li sono aggrati, previene il tempo in su aperta frasca, e con ardente affetto il sole aspetta, fiso guardando pur che l’alba nasca; così la donna mïa stava eretta e attenta, rivolta inver’ la plaga sotto la quale il sol mostra men fretta: sì che, veggendola io sospesa e vaga, fecimi qual è quei che disïando altro vorria, e sperando s’appaga. Ma poco fu tra uno e altro quando, del mio attender, dico, e del vedere lo ciel venir più e più rischiarando; e Bëatrice disse: «Ecco le schiere del trïunfo di Cristo e tutto ’l frutto ricolto del girar di queste spere!». Pariemi che ’l suo viso ardesse tutto, e li occhi avea di letizia sì pieni, che passarmen convien sanza costrutto. Quale ne’ plenilunïi sereni Trivïa ride tra le ninfe etterne che dipingon lo ciel per tutti i seni, vid’ i’ sopra migliaia di lucerne un sol che tutte quante l’accendea, come fa ’l nostro le viste superne; e per la viva luce trasparea la lucente sustanza tanto chiara nel viso mio, che non la sostenea. Oh Bëatrice, dolce guida e cara! Ella mi disse: «Quel che ti sobranza è virtù da cui nulla si ripara. Quivi è la sapïenza e la possanza ch’aprì le strade tra ’l cielo e la terra, onde fu già sì lunga disïanza». Come foco di nube si diserra per dilatarsi sì che non vi cape, e fuor di sua natura in giù s’atterra, la mente mia così, tra quelle dape fatta più grande, di sé stessa uscìo, e che si fesse rimembrar non sape. «Apri li occhi e riguarda qual son io; tu hai vedute cose, che possente se’ fatto a sostener lo riso mio». Io era come quei che si risente di visïone oblita e che s’ingegna indarno di ridurlasi a la mente, quand’ io udi’ questa proferta, degna di tanto grato, che mai non si stingue del libro che ’l preterito rassegna. Se mo sonasser tutte quelle lingue che Polimnïa con le suore fero del latte lor dolcissimo più pingue, per aiutarmi, al millesmo del vero non si verria, cantando il santo riso e quanto il santo aspetto facea mero; e così, figurando il paradiso, convien saltar lo sacrato poema, come chi trova suo cammin riciso. Ma chi pensasse il ponderoso tema e l’omero mortal che se ne carca, nol biasmerebbe se sott’ esso trema: non è pareggio da picciola barca quel che fendendo va l’ardita prora, né da nocchier ch’a sé medesmo parca. «Perché la faccia mia sì t’innamora, che tu non ti rivolgi al bel giardino che sotto i raggi di Cristo s’infiora? Quivi è la rosa in che ’l verbo divino carne si fece; quivi son li gigli al cui odor si prese il buon cammino». Così Beatrice; e io, che a’ suoi consigli tutto era pronto, ancora mi rendei a la battaglia de’ debili cigli. Come a raggio di sol, che puro mei per fratta nube, già prato di fiori vider, coverti d’ombra, li occhi miei; vid’ io così più turbe di splendori, folgorate di sù da raggi ardenti, sanza veder principio di folgóri. O benigna vertù che sì li ’mprenti, sù t’essaltasti, per largirmi loco a li occhi lì che non t’eran possenti. Il nome del bel fior ch’io sempre invoco e mane e sera, tutto mi ristrinse l’animo ad avvisar lo maggior foco; e come ambo le luci mi dipinse il quale e il quanto de la viva stella che là sù vince come qua giù vinse, per entro il cielo scese una facella, formata in cerchio a guisa di corona, e cinsela e girossi intorno ad ella. Qualunque melodia più dolce suona qua giù e più a sé l’anima tira, parrebbe nube che squarciata tona, comparata al sonar di quella lira onde si coronava il bel zaffiro del quale il ciel più chiaro s’inzaffira. «Io sono amore angelico, che giro l’alta letizia che spira del ventre che fu albergo del nostro disiro; e girerommi, donna del ciel, mentre che seguirai tuo figlio, e farai dia più la spera suprema perché lì entre». Così la circulata melodia si sigillava, e tutti li altri lumi facean sonare il nome di Maria. Lo real manto di tutti i volumi del mondo, che più ferve e più s’avviva ne l’alito di Dio e nei costumi, avea sopra di noi l’interna riva tanto distante, che la sua parvenza, là dov’ io era, ancor non appariva: però non ebber li occhi miei potenza di seguitar la coronata fiamma che si levò appresso sua semenza. E come fantolin che ’nver’ la mamma tende le braccia, poi che ’l latte prese, per l’animo che ’nfin di fuor s’infiamma; ciascun di quei candori in sù si stese con la sua cima, sì che l’alto affetto ch’elli avieno a Maria mi fu palese. Indi rimaser lì nel mio cospetto, ‘Regina celi’ cantando sì dolce, che mai da me non si partì ’l diletto. Oh quanta è l’ubertà che si soffolce in quelle arche ricchissime che fuoro a seminar qua giù buone bobolce! Quivi si vive e gode del tesoro che s’acquistò piangendo ne lo essilio di Babillòn, ove si lasciò l’oro. Quivi trïunfa, sotto l’alto Filio di Dio e di Maria, di sua vittoria, e con l’antico e col novo concilio, colui che tien le chiavi di tal gloria. Paradiso · Canto XXIV «O sodalizio eletto a la gran cena del benedetto Agnello, il qual vi ciba sì, che la vostra voglia è sempre piena, se per grazia di Dio questi preliba di quel che cade de la vostra mensa, prima che morte tempo li prescriba, ponete mente a l’affezione immensa e roratelo alquanto: voi bevete sempre del fonte onde vien quel ch’ei pensa». Così Beatrice; e quelle anime liete si fero spere sopra fissi poli, fiammando, a volte, a guisa di comete. E come cerchi in tempra d’orïuoli si giran sì, che ’l primo a chi pon mente quïeto pare, e l’ultimo che voli; così quelle carole, differente- mente danzando, de la sua ricchezza mi facieno stimar, veloci e lente. Di quella ch’io notai di più carezza vid’ ïo uscire un foco sì felice, che nullo vi lasciò di più chiarezza; e tre fïate intorno di Beatrice si volse con un canto tanto divo, che la mia fantasia nol mi ridice. Però salta la penna e non lo scrivo: ché l’imagine nostra a cotai pieghe, non che ’l parlare, è troppo color vivo. «O santa suora mia che sì ne prieghe divota, per lo tuo ardente affetto da quella bella spera mi disleghe». Poscia fermato, il foco benedetto a la mia donna dirizzò lo spiro, che favellò così com’ i’ ho detto. Ed ella: «O luce etterna del gran viro a cui Nostro Segnor lasciò le chiavi, ch’ei portò giù, di questo gaudio miro, tenta costui di punti lievi e gravi, come ti piace, intorno de la fede, per la qual tu su per lo mare andavi. S’elli ama bene e bene spera e crede, non t’è occulto, perché ’l viso hai quivi dov’ ogne cosa dipinta si vede; ma perché questo regno ha fatto civi per la verace fede, a glorïarla, di lei parlare è ben ch’a lui arrivi». Sì come il baccialier s’arma e non parla fin che ’l maestro la question propone, per approvarla, non per terminarla, così m’armava io d’ogne ragione mentre ch’ella dicea, per esser presto a tal querente e a tal professione. «Dì, buon Cristiano, fatti manifesto: fede che è?». Ond’ io levai la fronte in quella luce onde spirava questo; poi mi volsi a Beatrice, ed essa pronte sembianze femmi perch’ ïo spandessi l’acqua di fuor del mio interno fonte. «La Grazia che mi dà ch’io mi confessi», comincia’ io, «da l’alto primipilo, faccia li miei concetti bene espressi». E seguitai: «Come ’l verace stilo ne scrisse, padre, del tuo caro frate che mise teco Roma nel buon filo, fede è sustanza di cose sperate e argomento de le non parventi; e questa pare a me sua quiditate». Allora udi’: «Dirittamente senti, se bene intendi perché la ripuose tra le sustanze, e poi tra li argomenti». E io appresso: «Le profonde cose che mi largiscon qui la lor parvenza, a li occhi di là giù son sì ascose, che l’esser loro v’è in sola credenza, sopra la qual si fonda l’alta spene; e però di sustanza prende intenza. E da questa credenza ci convene silogizzar, sanz’ avere altra vista: però intenza d’argomento tene». Allora udi’: «Se quantunque s’acquista giù per dottrina, fosse così ’nteso, non lì avria loco ingegno di sofista». Così spirò di quello amore acceso; indi soggiunse: «Assai bene è trascorsa d’esta moneta già la lega e ’l peso; ma dimmi se tu l’hai ne la tua borsa». Ond’ io: «Sì ho, sì lucida e sì tonda, che nel suo conio nulla mi s’inforsa». Appresso uscì de la luce profonda che lì splendeva: «Questa cara gioia sopra la quale ogne virtù si fonda, onde ti venne?». E io: «La larga ploia de lo Spirito Santo, ch’è diffusa in su le vecchie e ’n su le nuove cuoia, è silogismo che la m’ha conchiusa acutamente sì, che ’nverso d’ella ogne dimostrazion mi pare ottusa». Io udi’ poi: «L’antica e la novella proposizion che così ti conchiude, perché l’hai tu per divina favella?». E io: «La prova che ’l ver mi dischiude, son l’opere seguite, a che natura non scalda ferro mai né batte incude». Risposto fummi: «Dì, chi t’assicura che quell’ opere fosser? Quel medesmo che vuol provarsi, non altri, il ti giura». «Se ’l mondo si rivolse al cristianesmo», diss’ io, «sanza miracoli, quest’ uno è tal, che li altri non sono il centesmo: ché tu intrasti povero e digiuno in campo, a seminar la buona pianta che fu già vite e ora è fatta pruno». Finito questo, l’alta corte santa risonò per le spere un ‘Dio laudamo’ ne la melode che là sù si canta. E quel baron che sì di ramo in ramo, essaminando, già tratto m’avea, che a l’ultime fronde appressavamo, ricominciò: «La Grazia, che donnea con la tua mente, la bocca t’aperse infino a qui come aprir si dovea, sì ch’io approvo ciò che fuori emerse; ma or convien espremer quel che credi, e onde a la credenza tua s’offerse». «O santo padre, e spirito che vedi ciò che credesti sì, che tu vincesti ver’ lo sepulcro più giovani piedi», comincia’ io, «tu vuo’ ch’io manifesti la forma qui del pronto creder mio, e anche la cagion di lui chiedesti. E io rispondo: Io credo in uno Dio solo ed etterno, che tutto ’l ciel move, non moto, con amore e con disio; e a tal creder non ho io pur prove fisice e metafisice, ma dalmi anche la verità che quinci piove per Moïsè, per profeti e per salmi, per l’Evangelio e per voi che scriveste poi che l’ardente Spirto vi fé almi; e credo in tre persone etterne, e queste credo una essenza sì una e sì trina, che soffera congiunto ‘sono’ ed ‘este’. De la profonda condizion divina ch’io tocco mo, la mente mi sigilla più volte l’evangelica dottrina. Quest’ è ’l principio, quest’ è la favilla che si dilata in fiamma poi vivace, e come stella in cielo in me scintilla». Come ’l segnor ch’ascolta quel che i piace, da indi abbraccia il servo, gratulando per la novella, tosto ch’el si tace; così, benedicendomi cantando, tre volte cinse me, sì com’ io tacqui, l’appostolico lume al cui comando io avea detto: sì nel dir li piacqui! Paradiso · Canto XXV Se mai continga che ’l poema sacro al quale ha posto mano e cielo e terra, sì che m’ha fatto per molti anni macro, vinca la crudeltà che fuor mi serra del bello ovile ov’ io dormi’ agnello, nimico ai lupi che li danno guerra; con altra voce omai, con altro vello ritornerò poeta, e in sul fonte del mio battesmo prenderò ’l cappello; però che ne la fede, che fa conte l’anime a Dio, quivi intra’ io, e poi Pietro per lei sì mi girò la fronte. Indi si mosse un lume verso noi di quella spera ond’ uscì la primizia che lasciò Cristo d’i vicari suoi; e la mia donna, piena di letizia, mi disse: «Mira, mira: ecco il barone per cui là giù si vicita Galizia». Sì come quando il colombo si pone presso al compagno, l’uno a l’altro pande, girando e mormorando, l’affezione; così vid’ ïo l’un da l’altro grande principe glorïoso essere accolto, laudando il cibo che là sù li prande. Ma poi che ’l gratular si fu assolto, tacito coram me ciascun s’affisse, ignito sì che vincëa ’l mio volto. Ridendo allora Bëatrice disse: «Inclita vita per cui la larghezza de la nostra basilica si scrisse, fa risonar la spene in questa altezza: tu sai, che tante fiate la figuri, quante Iesù ai tre fé più carezza». «Leva la testa e fa che t’assicuri: che ciò che vien qua sù del mortal mondo, convien ch’ai nostri raggi si maturi». Questo conforto del foco secondo mi venne; ond’ io leväi li occhi a’ monti che li ’ncurvaron pria col troppo pondo. «Poi che per grazia vuol che tu t’affronti lo nostro Imperadore, anzi la morte, ne l’aula più secreta co’ suoi conti, sì che, veduto il ver di questa corte, la spene, che là giù bene innamora, in te e in altrui di ciò conforte, di’ quel ch’ell’ è, di’ come se ne ’nfiora la mente tua, e dì onde a te venne». Così seguì ’l secondo lume ancora. E quella pïa che guidò le penne de le mie ali a così alto volo, a la risposta così mi prevenne: «La Chiesa militante alcun figliuolo non ha con più speranza, com’ è scritto nel Sol che raggia tutto nostro stuolo: però li è conceduto che d’Egitto vegna in Ierusalemme per vedere, anzi che ’l militar li sia prescritto. Li altri due punti, che non per sapere son dimandati, ma perch’ ei rapporti quanto questa virtù t’è in piacere, a lui lasc’ io, ché non li saran forti né di iattanza; ed elli a ciò risponda, e la grazia di Dio ciò li comporti». Come discente ch’a dottor seconda pronto e libente in quel ch’elli è esperto, perché la sua bontà si disasconda, «Spene», diss’ io, «è uno attender certo de la gloria futura, il qual produce grazia divina e precedente merto. Da molte stelle mi vien questa luce; ma quei la distillò nel mio cor pria che fu sommo cantor del sommo duce. ‘Sperino in te’, ne la sua tëodia dice, ‘color che sanno il nome tuo’: e chi nol sa, s’elli ha la fede mia? Tu mi stillasti, con lo stillar suo, ne la pistola poi; sì ch’io son pieno, e in altrui vostra pioggia repluo». Mentr’ io diceva, dentro al vivo seno di quello incendio tremolava un lampo sùbito e spesso a guisa di baleno. Indi spirò: «L’amore ond’ ïo avvampo ancor ver’ la virtù che mi seguette infin la palma e a l’uscir del campo, vuol ch’io respiri a te che ti dilette di lei; ed emmi a grato che tu diche quello che la speranza ti ’mpromette». E io: «Le nove e le scritture antiche pongon lo segno, ed esso lo mi addita, de l’anime che Dio s’ha fatte amiche. Dice Isaia che ciascuna vestita ne la sua terra fia di doppia vesta: e la sua terra è questa dolce vita; e ’l tuo fratello assai vie più digesta, là dove tratta de le bianche stole, questa revelazion ci manifesta». E prima, appresso al fin d’este parole, ‘Sperent in te’ di sopr’ a noi s’udì; a che rispuoser tutte le carole. Poscia tra esse un lume si schiarì sì che, se ’l Cancro avesse un tal cristallo, l’inverno avrebbe un mese d’un sol dì. E come surge e va ed entra in ballo vergine lieta, sol per fare onore a la novizia, non per alcun fallo, così vid’ io lo schiarato splendore venire a’ due che si volgieno a nota qual conveniesi al loro ardente amore. Misesi lì nel canto e ne la rota; e la mia donna in lor tenea l’aspetto, pur come sposa tacita e immota. «Questi è colui che giacque sopra ’l petto del nostro pellicano, e questi fue di su la croce al grande officio eletto». La donna mia così; né però piùe mosser la vista sua di stare attenta poscia che prima le parole sue. Qual è colui ch’adocchia e s’argomenta di vedere eclissar lo sole un poco, che, per veder, non vedente diventa; tal mi fec’ ïo a quell’ ultimo foco mentre che detto fu: «Perché t’abbagli per veder cosa che qui non ha loco? In terra è terra il mio corpo, e saragli tanto con li altri, che ’l numero nostro con l’etterno proposito s’agguagli. Con le due stole nel beato chiostro son le due luci sole che saliro; e questo apporterai nel mondo vostro». A questa voce l’infiammato giro si quïetò con esso il dolce mischio che si facea nel suon del trino spiro, sì come, per cessar fatica o rischio, li remi, pria ne l’acqua ripercossi, tutti si posano al sonar d’un fischio. Ahi quanto ne la mente mi commossi, quando mi volsi per veder Beatrice, per non poter veder, benché io fossi presso di lei, e nel mondo felice! Paradiso · Canto XXVI Mentr’ io dubbiava per lo viso spento, de la fulgida fiamma che lo spense uscì un spiro che mi fece attento, dicendo: «Intanto che tu ti risense de la vista che haï in me consunta, ben è che ragionando la compense. Comincia dunque; e dì ove s’appunta l’anima tua, e fa ragion che sia la vista in te smarrita e non defunta: perché la donna che per questa dia regïon ti conduce, ha ne lo sguardo la virtù ch’ebbe la man d’Anania». Io dissi: «Al suo piacere e tosto e tardo vegna remedio a li occhi, che fuor porte quand’ ella entrò col foco ond’ io sempr’ ardo. Lo ben che fa contenta questa corte, Alfa e O è di quanta scrittura mi legge Amore o lievemente o forte». Quella medesma voce che paura tolta m’avea del sùbito abbarbaglio, di ragionare ancor mi mise in cura; e disse: «Certo a più angusto vaglio ti conviene schiarar: dicer convienti chi drizzò l’arco tuo a tal berzaglio». E io: «Per filosofici argomenti e per autorità che quinci scende cotale amor convien che in me si ’mprenti: ché ’l bene, in quanto ben, come s’intende, così accende amore, e tanto maggio quanto più di bontate in sé comprende. Dunque a l’essenza ov’ è tanto avvantaggio, che ciascun ben che fuor di lei si trova altro non è ch’un lume di suo raggio, più che in altra convien che si mova la mente, amando, di ciascun che cerne il vero in che si fonda questa prova. Tal vero a l’intelletto mïo sterne colui che mi dimostra il primo amore di tutte le sustanze sempiterne. Sternel la voce del verace autore, che dice a Moïsè, di sé parlando: ‘Io ti farò vedere ogne valore’. Sternilmi tu ancora, incominciando l’alto preconio che grida l’arcano di qui là giù sovra ogne altro bando». E io udi’: «Per intelletto umano e per autoritadi a lui concorde d’i tuoi amori a Dio guarda il sovrano. Ma dì ancor se tu senti altre corde tirarti verso lui, sì che tu suone con quanti denti questo amor ti morde». Non fu latente la santa intenzione de l’aguglia di Cristo, anzi m’accorsi dove volea menar mia professione. Però ricominciai: «Tutti quei morsi che posson far lo cor volgere a Dio, a la mia caritate son concorsi: ché l’essere del mondo e l’esser mio, la morte ch’el sostenne perch’ io viva, e quel che spera ogne fedel com’ io, con la predetta conoscenza viva, tratto m’hanno del mar de l’amor torto, e del diritto m’han posto a la riva. Le fronde onde s’infronda tutto l’orto de l’ortolano etterno, am’ io cotanto quanto da lui a lor di bene è porto». Sì com’ io tacqui, un dolcissimo canto risonò per lo cielo, e la mia donna dicea con li altri: «Santo, santo, santo!». E come a lume acuto si disonna per lo spirto visivo che ricorre a lo splendor che va di gonna in gonna, e lo svegliato ciò che vede aborre, sì nescïa è la sùbita vigilia fin che la stimativa non soccorre; così de li occhi miei ogne quisquilia fugò Beatrice col raggio d’i suoi, che rifulgea da più di mille milia: onde mei che dinanzi vidi poi; e quasi stupefatto domandai d’un quarto lume ch’io vidi tra noi. E la mia donna: «Dentro da quei rai vagheggia il suo fattor l’anima prima che la prima virtù creasse mai». Come la fronda che flette la cima nel transito del vento, e poi si leva per la propria virtù che la soblima, fec’ io in tanto in quant’ ella diceva, stupendo, e poi mi rifece sicuro un disio di parlare ond’ ïo ardeva. E cominciai: «O pomo che maturo solo prodotto fosti, o padre antico a cui ciascuna sposa è figlia e nuro, divoto quanto posso a te supplìco perché mi parli: tu vedi mia voglia, e per udirti tosto non la dico». Talvolta un animal coverto broglia, sì che l’affetto convien che si paia per lo seguir che face a lui la ’nvoglia; e similmente l’anima primaia mi facea trasparer per la coverta quant’ ella a compiacermi venìa gaia. Indi spirò: «Sanz’ essermi proferta da te, la voglia tua discerno meglio che tu qualunque cosa t’è più certa; perch’ io la veggio nel verace speglio che fa di sé pareglio a l’altre cose, e nulla face lui di sé pareglio. Tu vuogli udir quant’ è che Dio mi puose ne l’eccelso giardino, ove costei a così lunga scala ti dispuose, e quanto fu diletto a li occhi miei, e la propria cagion del gran disdegno, e l’idïoma ch’usai e che fei. Or, figluol mio, non il gustar del legno fu per sé la cagion di tanto essilio, ma solamente il trapassar del segno. Quindi onde mosse tua donna Virgilio, quattromilia trecento e due volumi di sol desiderai questo concilio; e vidi lui tornare a tutt’ i lumi de la sua strada novecento trenta fïate, mentre ch’ïo in terra fu’mi. La lingua ch’io parlai fu tutta spenta innanzi che a l’ovra inconsummabile fosse la gente di Nembròt attenta: ché nullo effetto mai razïonabile, per lo piacere uman che rinovella seguendo il cielo, sempre fu durabile. Opera naturale è ch’uom favella; ma così o così, natura lascia poi fare a voi secondo che v’abbella. Pria ch’i’ scendessi a l’infernale ambascia, I s’appellava in terra il sommo bene onde vien la letizia che mi fascia; e El si chiamò poi: e ciò convene, ché l’uso d’i mortali è come fronda in ramo, che sen va e altra vene. Nel monte che si leva più da l’onda, fu’ io, con vita pura e disonesta, da la prim’ ora a quella che seconda, come ’l sol muta quadra, l’ora sesta». Paradiso · Canto XXVII ‘Al Padre, al Figlio, a lo Spirito Santo’, cominciò, ‘gloria!’, tutto ’l paradiso, sì che m’inebrïava il dolce canto. Ciò ch’io vedeva mi sembiava un riso de l’universo; per che mia ebbrezza intrava per l’udire e per lo viso. Oh gioia! oh ineffabile allegrezza! oh vita intègra d’amore e di pace! oh sanza brama sicura ricchezza! Dinanzi a li occhi miei le quattro face stavano accese, e quella che pria venne incominciò a farsi più vivace, e tal ne la sembianza sua divenne, qual diverrebbe Iove, s’elli e Marte fossero augelli e cambiassersi penne. La provedenza, che quivi comparte vice e officio, nel beato coro silenzio posto avea da ogne parte, quand’ ïo udi’: «Se io mi trascoloro, non ti maravigliar, ché, dicend’ io, vedrai trascolorar tutti costoro. Quelli ch’usurpa in terra il luogo mio, il luogo mio, il luogo mio, che vaca ne la presenza del Figliuol di Dio, fatt’ ha del cimitero mio cloaca del sangue e de la puzza; onde ’l perverso che cadde di qua sù, là giù si placa». Di quel color che per lo sole avverso nube dipigne da sera e da mane, vid’ ïo allora tutto ’l ciel cosperso. E come donna onesta che permane di sé sicura, e per l’altrui fallanza, pur ascoltando, timida si fane, così Beatrice trasmutò sembianza; e tale eclissi credo che ’n ciel fue quando patì la supprema possanza. Poi procedetter le parole sue con voce tanto da sé trasmutata, che la sembianza non si mutò piùe: «Non fu la sposa di Cristo allevata del sangue mio, di Lin, di quel di Cleto, per essere ad acquisto d’oro usata; ma per acquisto d’esto viver lieto e Sisto e Pïo e Calisto e Urbano sparser lo sangue dopo molto fleto. Non fu nostra intenzion ch’a destra mano d’i nostri successor parte sedesse, parte da l’altra del popol cristiano; né che le chiavi che mi fuor concesse, divenisser signaculo in vessillo che contra battezzati combattesse; né ch’io fossi figura di sigillo a privilegi venduti e mendaci, ond’ io sovente arrosso e disfavillo. In vesta di pastor lupi rapaci si veggion di qua sù per tutti i paschi: o difesa di Dio, perché pur giaci? Del sangue nostro Caorsini e Guaschi s’apparecchian di bere: o buon principio, a che vil fine convien che tu caschi! Ma l’alta provedenza, che con Scipio difese a Roma la gloria del mondo, soccorrà tosto, sì com’ io concipio; e tu, figliuol, che per lo mortal pondo ancor giù tornerai, apri la bocca, e non asconder quel ch’io non ascondo». Sì come di vapor gelati fiocca in giuso l’aere nostro, quando ’l corno de la capra del ciel col sol si tocca, in sù vid’ io così l’etera addorno farsi e fioccar di vapor trïunfanti che fatto avien con noi quivi soggiorno. Lo viso mio seguiva i suoi sembianti, e seguì fin che ’l mezzo, per lo molto, li tolse il trapassar del più avanti. Onde la donna, che mi vide assolto de l’attendere in sù, mi disse: «Adima il viso e guarda come tu se’ vòlto». Da l’ora ch’ïo avea guardato prima i’ vidi mosso me per tutto l’arco che fa dal mezzo al fine il primo clima; sì ch’io vedea di là da Gade il varco folle d’Ulisse, e di qua presso il lito nel qual si fece Europa dolce carco. E più mi fora discoverto il sito di questa aiuola; ma ’l sol procedea sotto i mie’ piedi un segno e più partito. La mente innamorata, che donnea con la mia donna sempre, di ridure ad essa li occhi più che mai ardea; e se natura o arte fé pasture da pigliare occhi, per aver la mente, in carne umana o ne le sue pitture, tutte adunate, parrebber nïente ver’ lo piacer divin che mi refulse, quando mi volsi al suo viso ridente. E la virtù che lo sguardo m’indulse, del bel nido di Leda mi divelse, e nel ciel velocissimo m’impulse. Le parti sue vivissime ed eccelse sì uniforme son, ch’i’ non so dire qual Bëatrice per loco mi scelse. Ma ella, che vedëa ’l mio disire, incominciò, ridendo tanto lieta, che Dio parea nel suo volto gioire: «La natura del mondo, che quïeta il mezzo e tutto l’altro intorno move, quinci comincia come da sua meta; e questo cielo non ha altro dove che la mente divina, in che s’accende l’amor che ’l volge e la virtù ch’ei piove. Luce e amor d’un cerchio lui comprende, sì come questo li altri; e quel precinto colui che ’l cinge solamente intende. Non è suo moto per altro distinto, ma li altri son mensurati da questo, sì come diece da mezzo e da quinto; e come il tempo tegna in cotal testo le sue radici e ne li altri le fronde, omai a te può esser manifesto. Oh cupidigia che i mortali affonde sì sotto te, che nessuno ha podere di trarre li occhi fuor de le tue onde! Ben fiorisce ne li uomini il volere; ma la pioggia continüa converte in bozzacchioni le sosine vere. Fede e innocenza son reperte solo ne’ parvoletti; poi ciascuna pria fugge che le guance sian coperte. Tale, balbuzïendo ancor, digiuna, che poi divora, con la lingua sciolta, qualunque cibo per qualunque luna; e tal, balbuzïendo, ama e ascolta la madre sua, che, con loquela intera, disïa poi di vederla sepolta. Così si fa la pelle bianca nera nel primo aspetto de la bella figlia di quel ch’apporta mane e lascia sera. Tu, perché non ti facci maraviglia, pensa che ’n terra non è chi governi; onde sì svïa l’umana famiglia. Ma prima che gennaio tutto si sverni per la centesma ch’è là giù negletta, raggeran sì questi cerchi superni, che la fortuna che tanto s’aspetta, le poppe volgerà u’ son le prore, sì che la classe correrà diretta; e vero frutto verrà dopo ’l fiore». Paradiso · Canto XXVIII Poscia che ’ncontro a la vita presente d’i miseri mortali aperse ’l vero quella che ’mparadisa la mia mente, come in lo specchio fiamma di doppiero vede colui che se n’alluma retro, prima che l’abbia in vista o in pensiero, e sé rivolge per veder se ’l vetro li dice il vero, e vede ch’el s’accorda con esso come nota con suo metro; così la mia memoria si ricorda ch’io feci riguardando ne’ belli occhi onde a pigliarmi fece Amor la corda. E com’ io mi rivolsi e furon tocchi li miei da ciò che pare in quel volume, quandunque nel suo giro ben s’adocchi, un punto vidi che raggiava lume acuto sì, che ’l viso ch’elli affoca chiuder conviensi per lo forte acume; e quale stella par quinci più poca, parrebbe luna, locata con esso come stella con stella si collòca. Forse cotanto quanto pare appresso alo cigner la luce che ’l dipigne quando ’l vapor che ’l porta più è spesso, distante intorno al punto un cerchio d’igne si girava sì ratto, ch’avria vinto quel moto che più tosto il mondo cigne; e questo era d’un altro circumcinto, e quel dal terzo, e ’l terzo poi dal quarto, dal quinto il quarto, e poi dal sesto il quinto. Sopra seguiva il settimo sì sparto già di larghezza, che ’l messo di Iuno intero a contenerlo sarebbe arto. Così l’ottavo e ’l nono; e chiascheduno più tardo si movea, secondo ch’era in numero distante più da l’uno; e quello avea la fiamma più sincera cui men distava la favilla pura, credo, però che più di lei s’invera. La donna mia, che mi vedëa in cura forte sospeso, disse: «Da quel punto depende il cielo e tutta la natura. Mira quel cerchio che più li è congiunto; e sappi che ’l suo muovere è sì tosto per l’affocato amore ond’ elli è punto». E io a lei: «Se ’l mondo fosse posto con l’ordine ch’io veggio in quelle rote, sazio m’avrebbe ciò che m’è proposto; ma nel mondo sensibile si puote veder le volte tanto più divine, quant’ elle son dal centro più remote. Onde, se ’l mio disir dee aver fine in questo miro e angelico templo che solo amore e luce ha per confine, udir convienmi ancor come l’essemplo e l’essemplare non vanno d’un modo, ché io per me indarno a ciò contemplo». «Se li tuoi diti non sono a tal nodo sufficïenti, non è maraviglia: tanto, per non tentare, è fatto sodo!». Così la donna mia; poi disse: «Piglia quel ch’io ti dicerò, se vuo’ saziarti; e intorno da esso t’assottiglia. Li cerchi corporai sono ampi e arti secondo il più e ’l men de la virtute che si distende per tutte lor parti. Maggior bontà vuol far maggior salute; maggior salute maggior corpo cape, s’elli ha le parti igualmente compiute. Dunque costui che tutto quanto rape l’altro universo seco, corrisponde al cerchio che più ama e che più sape: per che, se tu a la virtù circonde la tua misura, non a la parvenza de le sustanze che t’appaion tonde, tu vederai mirabil consequenza di maggio a più e di minore a meno, in ciascun cielo, a süa intelligenza». Come rimane splendido e sereno l’emisperio de l’aere, quando soffia Borea da quella guancia ond’ è più leno, per che si purga e risolve la roffia che pria turbava, sì che ’l ciel ne ride con le bellezze d’ogne sua paroffia; così fec’ïo, poi che mi provide la donna mia del suo risponder chiaro, e come stella in cielo il ver si vide. E poi che le parole sue restaro, non altrimenti ferro disfavilla che bolle, come i cerchi sfavillaro. L’incendio suo seguiva ogne scintilla; ed eran tante, che ’l numero loro più che ’l doppiar de li scacchi s’inmilla. Io sentiva osannar di coro in coro al punto fisso che li tiene a li ubi, e terrà sempre, ne’ quai sempre fuoro. E quella che vedëa i pensier dubi ne la mia mente, disse: «I cerchi primi t’hanno mostrato Serafi e Cherubi. Così veloci seguono i suoi vimi, per somigliarsi al punto quanto ponno; e posson quanto a veder son soblimi. Quelli altri amori che ’ntorno li vonno, si chiaman Troni del divino aspetto, per che ’l primo ternaro terminonno; e dei saper che tutti hanno diletto quanto la sua veduta si profonda nel vero in che si queta ogne intelletto. Quinci si può veder come si fonda l’esser beato ne l’atto che vede, non in quel ch’ama, che poscia seconda; e del vedere è misura mercede, che grazia partorisce e buona voglia: così di grado in grado si procede. L’altro ternaro, che così germoglia in questa primavera sempiterna che notturno Arïete non dispoglia, perpetüalemente ‘Osanna’ sberna con tre melode, che suonano in tree ordini di letizia onde s’interna. In essa gerarcia son l’altre dee: prima Dominazioni, e poi Virtudi; l’ordine terzo di Podestadi èe. Poscia ne’ due penultimi tripudi Principati e Arcangeli si girano; l’ultimo è tutto d’Angelici ludi. Questi ordini di sù tutti s’ammirano, e di giù vincon sì, che verso Dio tutti tirati sono e tutti tirano. E Dïonisio con tanto disio a contemplar questi ordini si mise, che li nomò e distinse com’ io. Ma Gregorio da lui poi si divise; onde, sì tosto come li occhi aperse in questo ciel, di sé medesmo rise. E se tanto secreto ver proferse mortale in terra, non voglio ch’ammiri: ché chi ’l vide qua sù gliel discoperse con altro assai del ver di questi giri». Paradiso · Canto XXIX Quando ambedue li figli di Latona, coperti del Montone e de la Libra, fanno de l’orizzonte insieme zona, quant’ è dal punto che ’l cenìt inlibra infin che l’uno e l’altro da quel cinto, cambiando l’emisperio, si dilibra, tanto, col volto di riso dipinto, si tacque Bëatrice, riguardando fiso nel punto che m’avëa vinto. Poi cominciò: «Io dico, e non dimando, quel che tu vuoli udir, perch’ io l’ho visto là ’ve s’appunta ogne ubi e ogne quando. Non per aver a sé di bene acquisto, ch’esser non può, ma perché suo splendore potesse, risplendendo, dir “Subsisto”, in sua etternità di tempo fore, fuor d’ogne altro comprender, come i piacque, s’aperse in nuovi amor l’etterno amore. Né prima quasi torpente si giacque; ché né prima né poscia procedette lo discorrer di Dio sovra quest’ acque. Forma e materia, congiunte e purette, usciro ad esser che non avia fallo, come d’arco tricordo tre saette. E come in vetro, in ambra o in cristallo raggio resplende sì, che dal venire a l’esser tutto non è intervallo, così ’l triforme effetto del suo sire ne l’esser suo raggiò insieme tutto sanza distinzïone in essordire. Concreato fu ordine e costrutto a le sustanze; e quelle furon cima nel mondo in che puro atto fu produtto; pura potenza tenne la parte ima; nel mezzo strinse potenza con atto tal vime, che già mai non si divima. Ieronimo vi scrisse lungo tratto di secoli de li angeli creati anzi che l’altro mondo fosse fatto; ma questo vero è scritto in molti lati da li scrittor de lo Spirito Santo, e tu te n’avvedrai se bene agguati; e anche la ragione il vede alquanto, che non concederebbe che ’ motori sanza sua perfezion fosser cotanto. Or sai tu dove e quando questi amori furon creati e come: sì che spenti nel tuo disïo già son tre ardori. Né giugneriesi, numerando, al venti sì tosto, come de li angeli parte turbò il suggetto d’i vostri alimenti. L’altra rimase, e cominciò quest’ arte che tu discerni, con tanto diletto, che mai da circüir non si diparte. Principio del cader fu il maladetto superbir di colui che tu vedesti da tutti i pesi del mondo costretto. Quelli che vedi qui furon modesti a riconoscer sé da la bontate che li avea fatti a tanto intender presti: per che le viste lor furo essaltate con grazia illuminante e con lor merto, si c’hanno ferma e piena volontate; e non voglio che dubbi, ma sia certo, che ricever la grazia è meritorio secondo che l’affetto l’è aperto. Omai dintorno a questo consistorio puoi contemplare assai, se le parole mie son ricolte, sanz’ altro aiutorio. Ma perché ’n terra per le vostre scole si legge che l’angelica natura è tal, che ’ntende e si ricorda e vole, ancor dirò, perché tu veggi pura la verità che là giù si confonde, equivocando in sì fatta lettura. Queste sustanze, poi che fur gioconde de la faccia di Dio, non volser viso da essa, da cui nulla si nasconde: però non hanno vedere interciso da novo obietto, e però non bisogna rememorar per concetto diviso; sì che là giù, non dormendo, si sogna, credendo e non credendo dicer vero; ma ne l’uno è più colpa e più vergogna. Voi non andate giù per un sentiero filosofando: tanto vi trasporta l’amor de l’apparenza e ’l suo pensiero! E ancor questo qua sù si comporta con men disdegno che quando è posposta la divina Scrittura o quando è torta. Non vi si pensa quanto sangue costa seminarla nel mondo e quanto piace chi umilmente con essa s’accosta. Per apparer ciascun s’ingegna e face sue invenzioni; e quelle son trascorse da’ predicanti e ’l Vangelio si tace. Un dice che la luna si ritorse ne la passion di Cristo e s’interpuose, per che ’l lume del sol giù non si porse; e mente, ché la luce si nascose da sé: però a li Spani e a l’Indi come a’ Giudei tale eclissi rispuose. Non ha Fiorenza tanti Lapi e Bindi quante sì fatte favole per anno in pergamo si gridan quinci e quindi: sì che le pecorelle, che non sanno, tornan del pasco pasciute di vento, e non le scusa non veder lo danno. Non disse Cristo al suo primo convento: ‘Andate, e predicate al mondo ciance’; ma diede lor verace fondamento; e quel tanto sonò ne le sue guance, sì ch’a pugnar per accender la fede de l’Evangelio fero scudo e lance. Ora si va con motti e con iscede a predicare, e pur che ben si rida, gonfia il cappuccio e più non si richiede. Ma tale uccel nel becchetto s’annida, che se ’l vulgo il vedesse, vederebbe la perdonanza di ch’el si confida: per cui tanta stoltezza in terra crebbe, che, sanza prova d’alcun testimonio, ad ogne promession si correrebbe. Di questo ingrassa il porco sant’ Antonio, e altri assai che sono ancor più porci, pagando di moneta sanza conio. Ma perché siam digressi assai, ritorci li occhi oramai verso la dritta strada, sì che la via col tempo si raccorci. Questa natura sì oltre s’ingrada in numero, che mai non fu loquela né concetto mortal che tanto vada; e se tu guardi quel che si revela per Danïel, vedrai che ’n sue migliaia determinato numero si cela. La prima luce, che tutta la raia, per tanti modi in essa si recepe, quanti son li splendori a chi s’appaia. Onde, però che a l’atto che concepe segue l’affetto, d’amar la dolcezza diversamente in essa ferve e tepe. Vedi l’eccelso omai e la larghezza de l’etterno valor, poscia che tanti speculi fatti s’ha in che si spezza, uno manendo in sé come davanti». Paradiso · Canto XXX Forse semilia miglia di lontano ci ferve l’ora sesta, e questo mondo china già l’ombra quasi al letto piano, quando ’l mezzo del cielo, a noi profondo, comincia a farsi tal, ch’alcuna stella perde il parere infino a questo fondo; e come vien la chiarissima ancella del sol più oltre, così ’l ciel si chiude di vista in vista infino a la più bella. Non altrimenti il trïunfo che lude sempre dintorno al punto che mi vinse, parendo inchiuso da quel ch’elli ’nchiude, a poco a poco al mio veder si stinse: per che tornar con li occhi a Bëatrice nulla vedere e amor mi costrinse. Se quanto infino a qui di lei si dice fosse conchiuso tutto in una loda, poca sarebbe a fornir questa vice. La bellezza ch’io vidi si trasmoda non pur di là da noi, ma certo io credo che solo il suo fattor tutta la goda. Da questo passo vinto mi concedo più che già mai da punto di suo tema soprato fosse comico o tragedo: ché, come sole in viso che più trema, così lo rimembrar del dolce riso la mente mia da me medesmo scema. Dal primo giorno ch’i’ vidi il suo viso in questa vita, infino a questa vista, non m’è il seguire al mio cantar preciso; ma or convien che mio seguir desista più dietro a sua bellezza, poetando, come a l’ultimo suo ciascuno artista. Cotal qual io lascio a maggior bando che quel de la mia tuba, che deduce l’ardüa sua matera terminando, con atto e voce di spedito duce ricominciò: «Noi siamo usciti fore del maggior corpo al ciel ch’è pura luce: luce intellettüal, piena d’amore; amor di vero ben, pien di letizia; letizia che trascende ogne dolzore. Qui vederai l’una e l’altra milizia di paradiso, e l’una in quelli aspetti che tu vedrai a l’ultima giustizia». Come sùbito lampo che discetti li spiriti visivi, sì che priva da l’atto l’occhio di più forti obietti, così mi circunfulse luce viva, e lasciommi fasciato di tal velo del suo fulgor, che nulla m’appariva. «Sempre l’amor che queta questo cielo accoglie in sé con sì fatta salute, per far disposto a sua fiamma il candelo». Non fur più tosto dentro a me venute queste parole brievi, ch’io compresi me sormontar di sopr’ a mia virtute; e di novella vista mi raccesi tale, che nulla luce è tanto mera, che li occhi miei non si fosser difesi; e vidi lume in forma di rivera fulvido di fulgore, intra due rive dipinte di mirabil primavera. Di tal fiumana uscian faville vive, e d’ogne parte si mettien ne’ fiori, quasi rubin che oro circunscrive; poi, come inebrïate da li odori, riprofondavan sé nel miro gurge, e s’una intrava, un’altra n’uscia fori. «L’alto disio che mo t’infiamma e urge, d’aver notizia di ciò che tu vei, tanto mi piace più quanto più turge; ma di quest’ acqua convien che tu bei prima che tanta sete in te si sazi»: così mi disse il sol de li occhi miei. Anche soggiunse: «Il fiume e li topazi ch’entrano ed escono e ’l rider de l’erbe son di lor vero umbriferi prefazi. Non che da sé sian queste cose acerbe; ma è difetto da la parte tua, che non hai viste ancor tanto superbe». Non è fantin che sì sùbito rua col volto verso il latte, se si svegli molto tardato da l’usanza sua, come fec’ io, per far migliori spegli ancor de li occhi, chinandomi a l’onda che si deriva perché vi s’immegli; e sì come di lei bevve la gronda de le palpebre mie, così mi parve di sua lunghezza divenuta tonda. Poi, come gente stata sotto larve, che pare altro che prima, se si sveste la sembianza non süa in che disparve, così mi si cambiaro in maggior feste li fiori e le faville, sì ch’io vidi ambo le corti del ciel manifeste. O isplendor di Dio, per cu’ io vidi l’alto trïunfo del regno verace, dammi virtù a dir com’ ïo il vidi! Lume è là sù che visibile face lo creatore a quella creatura che solo in lui vedere ha la sua pace. E’ si distende in circular figura, in tanto che la sua circunferenza sarebbe al sol troppo larga cintura. Fassi di raggio tutta sua parvenza reflesso al sommo del mobile primo, che prende quindi vivere e potenza. E come clivo in acqua di suo imo si specchia, quasi per vedersi addorno, quando è nel verde e ne’ fioretti opimo, sì, soprastando al lume intorno intorno, vidi specchiarsi in più di mille soglie quanto di noi là sù fatto ha ritorno. E se l’infimo grado in sé raccoglie sì grande lume, quanta è la larghezza di questa rosa ne l’estreme foglie! La vista mia ne l’ampio e ne l’altezza non si smarriva, ma tutto prendeva il quanto e ’l quale di quella allegrezza. Presso e lontano, lì, né pon né leva: ché dove Dio sanza mezzo governa, la legge natural nulla rileva. Nel giallo de la rosa sempiterna, che si digrada e dilata e redole odor di lode al sol che sempre verna, qual è colui che tace e dicer vole, mi trasse Bëatrice, e disse: «Mira quanto è ’l convento de le bianche stole! Vedi nostra città quant’ ella gira; vedi li nostri scanni sì ripieni, che poca gente più ci si disira. E ’n quel gran seggio a che tu li occhi tieni per la corona che già v’è sù posta, prima che tu a queste nozze ceni, sederà l’alma, che fia giù agosta, de l’alto Arrigo, ch’a drizzare Italia verrà in prima ch’ella sia disposta. La cieca cupidigia che v’ammalia simili fatti v’ha al fantolino che muor per fame e caccia via la balia. E fia prefetto nel foro divino allora tal, che palese e coverto non anderà con lui per un cammino. Ma poco poi sarà da Dio sofferto nel santo officio; ch’el sarà detruso là dove Simon mago è per suo merto, e farà quel d’Alagna intrar più giuso». Paradiso · Canto XXXI In forma dunque di candida rosa mi si mostrava la milizia santa che nel suo sangue Cristo fece sposa; ma l’altra, che volando vede e canta la gloria di colui che la ’nnamora e la bontà che la fece cotanta, sì come schiera d’ape che s’infiora una fïata e una si ritorna là dove suo laboro s’insapora, nel gran fior discendeva che s’addorna di tante foglie, e quindi risaliva là dove ’l süo amor sempre soggiorna. Le facce tutte avean di fiamma viva e l’ali d’oro, e l’altro tanto bianco, che nulla neve a quel termine arriva. Quando scendean nel fior, di banco in banco porgevan de la pace e de l’ardore ch’elli acquistavan ventilando il fianco. Né l’interporsi tra ’l disopra e ’l fiore di tanta moltitudine volante impediva la vista e lo splendore: ché la luce divina è penetrante per l’universo secondo ch’è degno, sì che nulla le puote essere ostante. Questo sicuro e gaudïoso regno, frequente in gente antica e in novella, viso e amore avea tutto ad un segno. O trina luce che ’n unica stella scintillando a lor vista, sì li appaga! guarda qua giuso a la nostra procella! Se i barbari, venendo da tal plaga che ciascun giorno d’Elice si cuopra, rotante col suo figlio ond’ ella è vaga, veggendo Roma e l’ardüa sua opra, stupefaciensi, quando Laterano a le cose mortali andò di sopra; ïo, che al divino da l’umano, a l’etterno dal tempo era venuto, e di Fiorenza in popol giusto e sano, di che stupor dovea esser compiuto! Certo tra esso e ’l gaudio mi facea libito non udire e starmi muto. E quasi peregrin che si ricrea nel tempio del suo voto riguardando, e spera già ridir com’ ello stea, su per la viva luce passeggiando, menava ïo li occhi per li gradi, mo sù, mo giù e mo recirculando. Vedëa visi a carità süadi, d’altrui lume fregiati e di suo riso, e atti ornati di tutte onestadi. La forma general di paradiso già tutta mïo sguardo avea compresa, in nulla parte ancor fermato fiso; e volgeami con voglia rïaccesa per domandar la mia donna di cose di che la mente mia era sospesa. Uno intendëa, e altro mi rispuose: credea veder Beatrice e vidi un sene vestito con le genti glorïose. Diffuso era per li occhi e per le gene di benigna letizia, in atto pio quale a tenero padre si convene. E «Ov’ è ella?», sùbito diss’ io. Ond’ elli: «A terminar lo tuo disiro mosse Beatrice me del loco mio; e se riguardi sù nel terzo giro dal sommo grado, tu la rivedrai nel trono che suoi merti le sortiro». Sanza risponder, li occhi sù levai, e vidi lei che si facea corona reflettendo da sé li etterni rai. Da quella regïon che più sù tona occhio mortale alcun tanto non dista, qualunque in mare più giù s’abbandona, quanto lì da Beatrice la mia vista; ma nulla mi facea, ché süa effige non discendëa a me per mezzo mista. «O donna in cui la mia speranza vige, e che soffristi per la mia salute in inferno lasciar le tue vestige, di tante cose quant’ i’ ho vedute, dal tuo podere e da la tua bontate riconosco la grazia e la virtute. Tu m’hai di servo tratto a libertate per tutte quelle vie, per tutt’ i modi che di ciò fare avei la potestate. La tua magnificenza in me custodi, sì che l’anima mia, che fatt’ hai sana, piacente a te dal corpo si disnodi». Così orai; e quella, sì lontana come parea, sorrise e riguardommi; poi si tornò a l’etterna fontana. E ’l santo sene: «Acciò che tu assommi perfettamente», disse, «il tuo cammino, a che priego e amor santo mandommi, vola con li occhi per questo giardino; ché veder lui t’acconcerà lo sguardo più al montar per lo raggio divino. E la regina del cielo, ond’ ïo ardo tutto d’amor, ne farà ogne grazia, però ch’i’ sono il suo fedel Bernardo». Qual è colui che forse di Croazia viene a veder la Veronica nostra, che per l’antica fame non sen sazia, ma dice nel pensier, fin che si mostra: ‘Segnor mio Iesù Cristo, Dio verace, or fu sì fatta la sembianza vostra?’; tal era io mirando la vivace carità di colui che ’n questo mondo, contemplando, gustò di quella pace. «Figliuol di grazia, quest’ esser giocondo», cominciò elli, «non ti sarà noto, tenendo li occhi pur qua giù al fondo; ma guarda i cerchi infino al più remoto, tanto che veggi seder la regina cui questo regno è suddito e devoto». Io levai li occhi; e come da mattina la parte orïental de l’orizzonte soverchia quella dove ’l sol declina, così, quasi di valle andando a monte con li occhi, vidi parte ne lo stremo vincer di lume tutta l’altra fronte. E come quivi ove s’aspetta il temo che mal guidò Fetonte, più s’infiamma, e quinci e quindi il lume si fa scemo, così quella pacifica oriafiamma nel mezzo s’avvivava, e d’ogne parte per igual modo allentava la fiamma; e a quel mezzo, con le penne sparte, vid’ io più di mille angeli festanti, ciascun distinto di fulgore e d’arte. Vidi a lor giochi quivi e a lor canti ridere una bellezza, che letizia era ne li occhi a tutti li altri santi; e s’io avessi in dir tanta divizia quanta ad imaginar, non ardirei lo minimo tentar di sua delizia. Bernardo, come vide li occhi miei nel caldo suo caler fissi e attenti, li suoi con tanto affetto volse a lei, che ’ miei di rimirar fé più ardenti. Paradiso · Canto XXXII Affetto al suo piacer, quel contemplante libero officio di dottore assunse, e cominciò queste parole sante: «La piaga che Maria richiuse e unse, quella ch’è tanto bella da’ suoi piedi è colei che l’aperse e che la punse. Ne l’ordine che fanno i terzi sedi, siede Rachel di sotto da costei con Bëatrice, sì come tu vedi. Sarra e Rebecca, Iudìt e colei che fu bisava al cantor che per doglia del fallo disse ‘Miserere mei’, puoi tu veder così di soglia in soglia giù digradar, com’ io ch’a proprio nome vo per la rosa giù di foglia in foglia. E dal settimo grado in giù, sì come infino ad esso, succedono Ebree, dirimendo del fior tutte le chiome; perché, secondo lo sguardo che fée la fede in Cristo, queste sono il muro a che si parton le sacre scalee. Da questa parte onde ’l fiore è maturo di tutte le sue foglie, sono assisi quei che credettero in Cristo venturo; da l’altra parte onde sono intercisi di vòti i semicirculi, si stanno quei ch’a Cristo venuto ebber li visi. E come quinci il glorïoso scanno de la donna del cielo e li altri scanni di sotto lui cotanta cerna fanno, così di contra quel del gran Giovanni, che sempre santo ’l diserto e ’l martiro sofferse, e poi l’inferno da due anni; e sotto lui così cerner sortiro Francesco, Benedetto e Augustino e altri fin qua giù di giro in giro. Or mira l’alto proveder divino: ché l’uno e l’altro aspetto de la fede igualmente empierà questo giardino. E sappi che dal grado in giù che fiede a mezzo il tratto le due discrezioni, per nullo proprio merito si siede, ma per l’altrui, con certe condizioni: ché tutti questi son spiriti ascolti prima ch’avesser vere elezïoni. Ben te ne puoi accorger per li volti e anche per le voci püerili, se tu li guardi bene e se li ascolti. Or dubbi tu e dubitando sili; ma io discioglierò ’l forte legame in che ti stringon li pensier sottili. Dentro a l’ampiezza di questo reame casüal punto non puote aver sito, se non come tristizia o sete o fame: ché per etterna legge è stabilito quantunque vedi, sì che giustamente ci si risponde da l’anello al dito; e però questa festinata gente a vera vita non è sine causa intra sé qui più e meno eccellente. Lo rege per cui questo regno pausa in tanto amore e in tanto diletto, che nulla volontà è di più ausa, le menti tutte nel suo lieto aspetto creando, a suo piacer di grazia dota diversamente; e qui basti l’effetto. E ciò espresso e chiaro vi si nota ne la Scrittura santa in quei gemelli che ne la madre ebber l’ira commota. Però, secondo il color d’i capelli, di cotal grazia l’altissimo lume degnamente convien che s’incappelli. Dunque, sanza mercé di lor costume, locati son per gradi differenti, sol differendo nel primiero acume. Bastavasi ne’ secoli recenti con l’innocenza, per aver salute, solamente la fede d’i parenti; poi che le prime etadi fuor compiute, convenne ai maschi a l’innocenti penne per circuncidere acquistar virtute; ma poi che ’l tempo de la grazia venne, sanza battesmo perfetto di Cristo tale innocenza là giù si ritenne. Riguarda omai ne la faccia che a Cristo più si somiglia, ché la sua chiarezza sola ti può disporre a veder Cristo». Io vidi sopra lei tanta allegrezza piover, portata ne le menti sante create a trasvolar per quella altezza, che quantunque io avea visto davante, di tanta ammirazion non mi sospese, né mi mostrò di Dio tanto sembiante; e quello amor che primo lì discese, cantando ‘Ave, Maria, gratïa plena’, dinanzi a lei le sue ali distese. Rispuose a la divina cantilena da tutte parti la beata corte, sì ch’ogne vista sen fé più serena. «O santo padre, che per me comporte l’esser qua giù, lasciando il dolce loco nel qual tu siedi per etterna sorte, qual è quell’ angel che con tanto gioco guarda ne li occhi la nostra regina, innamorato sì che par di foco?». Così ricorsi ancora a la dottrina di colui ch’abbelliva di Maria, come del sole stella mattutina. Ed elli a me: «Baldezza e leggiadria quant’ esser puote in angelo e in alma, tutta è in lui; e sì volem che sia, perch’ elli è quelli che portò la palma giuso a Maria, quando ’l Figliuol di Dio carcar si volse de la nostra salma. Ma vieni omai con li occhi sì com’ io andrò parlando, e nota i gran patrici di questo imperio giustissimo e pio. Quei due che seggon là sù più felici per esser propinquissimi ad Agusta, son d’esta rosa quasi due radici: colui che da sinistra le s’aggiusta è il padre per lo cui ardito gusto l’umana specie tanto amaro gusta; dal destro vedi quel padre vetusto di Santa Chiesa a cui Cristo le chiavi raccomandò di questo fior venusto. E quei che vide tutti i tempi gravi, pria che morisse, de la bella sposa che s’acquistò con la lancia e coi clavi, siede lungh’ esso, e lungo l’altro posa quel duca sotto cui visse di manna la gente ingrata, mobile e retrosa. Di contr’ a Pietro vedi sedere Anna, tanto contenta di mirar sua figlia, che non move occhio per cantare osanna; e contro al maggior padre di famiglia siede Lucia, che mosse la tua donna quando chinavi, a rovinar, le ciglia. Ma perché ’l tempo fugge che t’assonna, qui farem punto, come buon sartore che com’ elli ha del panno fa la gonna; e drizzeremo li occhi al primo amore, sì che, guardando verso lui, penètri quant’ è possibil per lo suo fulgore. Veramente, ne forse tu t’arretri movendo l’ali tue, credendo oltrarti, orando grazia conven che s’impetri grazia da quella che puote aiutarti; e tu mi seguirai con l’affezione, sì che dal dicer mio lo cor non parti». E cominciò questa santa orazione: Paradiso · Canto XXXIII «Vergine Madre, figlia del tuo figlio, umile e alta più che creatura, termine fisso d’etterno consiglio, tu se’ colei che l’umana natura nobilitasti sì, che ’l suo fattore non disdegnò di farsi sua fattura. Nel ventre tuo si raccese l’amore, per lo cui caldo ne l’etterna pace così è germinato questo fiore. Qui se’ a noi meridïana face di caritate, e giuso, intra ’ mortali, se’ di speranza fontana vivace. Donna, se’ tanto grande e tanto vali, che qual vuol grazia e a te non ricorre, sua disïanza vuol volar sanz’ ali. La tua benignità non pur soccorre a chi domanda, ma molte fïate liberamente al dimandar precorre. In te misericordia, in te pietate, in te magnificenza, in te s’aduna quantunque in creatura è di bontate. Or questi, che da l’infima lacuna de l’universo infin qui ha vedute le vite spiritali ad una ad una, supplica a te, per grazia, di virtute tanto, che possa con li occhi levarsi più alto verso l’ultima salute. E io, che mai per mio veder non arsi più ch’i’ fo per lo suo, tutti miei prieghi ti porgo, e priego che non sieno scarsi, perché tu ogne nube li disleghi di sua mortalità co’ prieghi tuoi, sì che ’l sommo piacer li si dispieghi. Ancor ti priego, regina, che puoi ciò che tu vuoli, che conservi sani, dopo tanto veder, li affetti suoi. Vinca tua guardia i movimenti umani: vedi Beatrice con quanti beati per li miei prieghi ti chiudon le mani!». Li occhi da Dio diletti e venerati, fissi ne l’orator, ne dimostraro quanto i devoti prieghi le son grati; indi a l’etterno lume s’addrizzaro, nel qual non si dee creder che s’invii per creatura l’occhio tanto chiaro. E io ch’al fine di tutt’ i disii appropinquava, sì com’ io dovea, l’ardor del desiderio in me finii. Bernardo m’accennava, e sorridea, perch’ io guardassi suso; ma io era già per me stesso tal qual ei volea: ché la mia vista, venendo sincera, e più e più intrava per lo raggio de l’alta luce che da sé è vera. Da quinci innanzi il mio veder fu maggio che ’l parlar mostra, ch’a tal vista cede, e cede la memoria a tanto oltraggio. Qual è colüi che sognando vede, che dopo ’l sogno la passione impressa rimane, e l’altro a la mente non riede, cotal son io, ché quasi tutta cessa mia visïone, e ancor mi distilla nel core il dolce che nacque da essa. Così la neve al sol si disigilla; così al vento ne le foglie levi si perdea la sentenza di Sibilla. O somma luce che tanto ti levi da’ concetti mortali, a la mia mente ripresta un poco di quel che parevi, e fa la lingua mia tanto possente, ch’una favilla sol de la tua gloria possa lasciare a la futura gente; ché, per tornare alquanto a mia memoria e per sonare un poco in questi versi, più si conceperà di tua vittoria. Io credo, per l’acume ch’io soffersi del vivo raggio, ch’i’ sarei smarrito, se li occhi miei da lui fossero aversi. E’ mi ricorda ch’io fui più ardito per questo a sostener, tanto ch’i’ giunsi l’aspetto mio col valore infinito. Oh abbondante grazia ond’ io presunsi ficcar lo viso per la luce etterna, tanto che la veduta vi consunsi! Nel suo profondo vidi che s’interna, legato con amore in un volume, ciò che per l’universo si squaderna: sustanze e accidenti e lor costume quasi conflati insieme, per tal modo che ciò ch’i’ dico è un semplice lume. La forma universal di questo nodo credo ch’i’ vidi, perché più di largo, dicendo questo, mi sento ch’i’ godo. Un punto solo m’è maggior letargo che venticinque secoli a la ’mpresa che fé Nettuno ammirar l’ombra d’Argo. Così la mente mia, tutta sospesa, mirava fissa, immobile e attenta, e sempre di mirar faceasi accesa. A quella luce cotal si diventa, che volgersi da lei per altro aspetto è impossibil che mai si consenta; però che ’l ben, ch’è del volere obietto, tutto s’accoglie in lei, e fuor di quella è defettivo ciò ch’è lì perfetto. Omai sarà più corta mia favella, pur a quel ch’io ricordo, che d’un fante che bagni ancor la lingua a la mammella. Non perché più ch’un semplice sembiante fosse nel vivo lume ch’io mirava, che tal è sempre qual s’era davante; ma per la vista che s’avvalorava in me guardando, una sola parvenza, mutandom’ io, a me si travagliava. Ne la profonda e chiara sussistenza de l’alto lume parvermi tre giri di tre colori e d’una contenenza; e l’un da l’altro come iri da iri parea reflesso, e ’l terzo parea foco che quinci e quindi igualmente si spiri. Oh quanto è corto il dire e come fioco al mio concetto! e questo, a quel ch’i’ vidi, è tanto, che non basta a dicer ‘poco’. O luce etterna che sola in te sidi, sola t’intendi, e da te intelletta e intendente te ami e arridi! Quella circulazion che sì concetta pareva in te come lume reflesso, da li occhi miei alquanto circunspetta, dentro da sé, del suo colore stesso, mi parve pinta de la nostra effige: per che ’l mio viso in lei tutto era messo. Qual è ’l geomètra che tutto s’affige per misurar lo cerchio, e non ritrova, pensando, quel principio ond’ elli indige, tal era io a quella vista nova: veder voleva come si convenne l’imago al cerchio e come vi s’indova; ma non eran da ciò le proprie penne: se non che la mia mente fu percossa da un fulgore in che sua voglia venne. A l’alta fantasia qui mancò possa; ma già volgeva il mio disio e ’l velle, sì come rota ch’igualmente è mossa, l’amor che move il sole e l’altre stelle. ldc-1.1.0-beta3-src/runtime/druntime/benchmark/runbench.d0000664000175000017500000001530012776214756021365 0ustar kaikai/** * This is a driver script that runs the benchmarks. * * Copyright: Copyright Martin Nowak 2011 -. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ import std.stdio; extern(C) __gshared bool rt_cmdline_enabled = false; struct Config { string pattern = r".*\.d", dmd = "dmd", dflags = "-O -release -inline", args; bool help, verbose; uint repeat = 10; } string runCmd(string cmd, bool verbose) { import std.exception : enforce; import std.process : executeShell; if (verbose) writeln(cmd); auto res = executeShell(cmd); enforce(res.status == 0, res.output); return res.output; } string extraSourceOf(string path) { import std.path, std.string; string dir = path.dirName; while(dir != path) { string base = dir.baseName; if(base.endsWith(".extra")) return dir[0..$-6] ~ ".d"; path = dir; dir = path.dirName; } return null; } void runTests(Config cfg) { import std.algorithm, std.file, std.path, std.regex, std.string; if (exists("gcx.log")) remove("gcx.log"); string[] sources; string[string] extra_sources; auto re = regex(cfg.pattern, "g"); auto self = buildPath(".", "runbench.d"); foreach(DirEntry src; dirEntries(".", SpanMode.depth)) { if (!src.isFile || !endsWith(src.name, ".d") || src.name == self) continue; string mainsrc = extraSourceOf(src.name); if (mainsrc) { if (cfg.verbose) writeln(src.name, " is extra file for ", mainsrc); extra_sources[mainsrc] ~= " " ~ src.name; } else if (!match(src.name, re).empty) sources ~= src.name; } immutable bindir = absolutePath("bin"); foreach(ref src; sources) { writeln("COMPILING ", src); version (Windows) enum exe = "exe"; else enum exe = ""; auto bin = buildPath(bindir, src.chompPrefix("./").setExtension(exe)); auto cmd = std.string.format("%s %s -op -odobj -of%s %s", cfg.dmd, cfg.dflags, bin, src); if (auto ex = src in extra_sources) cmd ~= " -I" ~ src[0..$-2] ~ ".extra" ~ *ex; runCmd(cmd, cfg.verbose); src = bin; } foreach(bin; sources) { import std.datetime, std.algorithm : min; auto sw = StopWatch(AutoStart.yes); auto minDur = Duration.max; stdout.writef("R %-16s", bin.baseName.stripExtension); if (cfg.verbose) stdout.writeln(); stdout.flush(); auto cmd = bin ~ " " ~ cfg.args; string gcprof; foreach (_; 0 .. cfg.repeat) { sw.reset; auto output = runCmd(cmd, cfg.verbose); auto dur = cast(Duration)sw.peek; if (cfg.verbose) stdout.write(output); if (dur >= minDur) continue; minDur = dur; if (exists("gcx.log")) { auto tgt = bin.setExtension("gcx.log"); rename("gcx.log", tgt); auto lines = File(tgt, "r").byLine() .find!(ln => ln.canFind("GC summary:")); if (!lines.empty) gcprof = lines.front.find("GC summary:")[11..$].idup; } else { auto lines = output.splitter(ctRegex!`\r\n|\r|\n`) .find!(ln => ln.startsWith("GC summary:")); if (!lines.empty) gcprof = lines.front[11..$]; } } auto res = minDur.split!("seconds", "msecs"); if (gcprof.length) writefln(" %s.%03s s, %s", res.seconds, res.msecs, gcprof); else writefln(" %s.%03s s", res.seconds, res.msecs, gcprof); } } void printHelp() { import std.ascii : nl=newline; auto helpString = "usage: runbench [-h|--help] [-v|--verbose] [-r n|--repeat=n] [] [] [-- ]"~nl~nl~ " tests - Regular expressions to select tests. Default: '.*\\.d'"~nl~ " dflags - Flags passed to compiler. Default: '-O -release -inline'"~nl~ " runargs - Arguments passed to each test, e.g. '--DRT-gcopt=profile=1'"~nl~nl~ "Don't pass any argument to run all tests with optimized builds."; writeln(helpString); } Config parseArgs(string[] args) { import std.algorithm, std.string : join; Config cfg; { import std.range : only; string[] tmp = args; if (findSkip(tmp, only("--"))) { import std.process : escapeShellCommand; cfg.args = escapeShellCommand(tmp); args = args[0 .. $ - 1 - tmp.length]; } } import std.getopt; getopt(args, config.stopOnFirstNonOption, config.passThrough, "h|help", &cfg.help, "v|verbose", &cfg.verbose, "r|repeat", &cfg.repeat); if (args.length >= 2 && !args[1].startsWith("-")) { cfg.pattern = args[1]; args = args.remove(1); } if (args.length > 1) cfg.dflags = join(args[1 .. $], " "); return cfg; } unittest { template cfg(N...) { static Config cfg(T...)(T vals) if (T.length == N.length) { Config res; foreach (i, ref v; vals) __traits(getMember, res, N[i]) = v; return res; } } import std.typecons : t=tuple; auto check = [ t(["bin"], cfg), t(["bin", "-h"], cfg!("help")(true)), t(["bin", "-v"], cfg!("verbose")(true)), t(["bin", "-h", "-v"], cfg!("help", "verbose")(true, true)), t(["bin", "gcbench"], cfg!("pattern")("gcbench")), t(["bin", "-v", "gcbench"], cfg!("pattern", "verbose")("gcbench", true)), t(["bin", "-r", "4", "gcbench"], cfg!("pattern", "repeat")("gcbench", 4)), t(["bin", "-g"], cfg!("dflags")("-g")), t(["bin", "gcbench", "-g"], cfg!("pattern", "dflags")("gcbench", "-g")), t(["bin", "-r", "2", "gcbench", "-g"], cfg!("pattern", "dflags", "repeat")("gcbench", "-g", 2)), t(["bin", "--", "--DRT-gcopt=profile:1"], cfg!("args")("--DRT-gcopt=profile:1")), t(["bin", "--", "foo", "bar"], cfg!("args")("foo bar")), t(["bin", "gcbench", "--", "args"], cfg!("pattern", "args")("gcbench", "args")), t(["bin", "--repeat=5", "gcbench", "--", "args"], cfg!("pattern", "args", "repeat")("gcbench", "args", 5)), ]; foreach (pair; check) assert(parseArgs(pair[0]) == pair[1]); } void main() { import core.runtime; // use Runtime.args for --DRT-gcopt auto cfg = parseArgs(Runtime.args); if (cfg.help) return printHelp(); import std.process : env=environment; cfg.dmd = env.get("DMD", "dmd"); writeln("compiler: "~cfg.dmd~' '~cfg.dflags); runTests(cfg); } ldc-1.1.0-beta3-src/runtime/druntime/project.ddoc0000664000175000017500000000002112776214756017755 0ustar kaikaiPROJECT=druntime ldc-1.1.0-beta3-src/runtime/druntime/LICENSE0000664000175000017500000000265512776214756016500 0ustar kaikaiDRuntime: Runtime Library for the D Programming Language ======================================================== Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ldc-1.1.0-beta3-src/runtime/druntime/osmodel.mak0000664000175000017500000000210112776214756017611 0ustar kaikai# This Makefile snippet detects the OS and the architecture MODEL # Keep this file in sync between druntime, phobos, and dmd repositories! ifeq (,$(OS)) uname_S:=$(shell uname -s) ifeq (Darwin,$(uname_S)) OS:=osx endif ifeq (Linux,$(uname_S)) OS:=linux endif ifeq (FreeBSD,$(uname_S)) OS:=freebsd endif ifeq (OpenBSD,$(uname_S)) OS:=openbsd endif ifeq (Solaris,$(uname_S)) OS:=solaris endif ifeq (SunOS,$(uname_S)) OS:=solaris endif ifeq (,$(OS)) $(error Unrecognized or unsupported OS for uname: $(uname_S)) endif endif # When running make from XCode it may set environment var OS=MACOS. # Adjust it here: ifeq (MACOS,$(OS)) OS:=osx endif ifeq (,$(MODEL)) ifeq ($(OS), solaris) uname_M:=$(shell isainfo -n) else uname_M:=$(shell uname -m) endif ifneq (,$(findstring $(uname_M),x86_64 amd64)) MODEL:=64 endif ifneq (,$(findstring $(uname_M),i386 i586 i686)) MODEL:=32 endif ifeq (,$(MODEL)) $(error Cannot figure 32/64 model from uname -m: $(uname_M)) endif endif MODEL_FLAG:=-m$(MODEL) ldc-1.1.0-beta3-src/runtime/druntime/README.md0000664000175000017500000000342012776214756016741 0ustar kaikaiDRuntime: Runtime Library for the D Programming Language ======================================================== This is DRuntime. It is the low-level runtime library backing the D programming language. DRuntime is typically linked together with Phobos in a release such that the compiler only has to link to a single library to provide the user with the runtime and the standard library. Purpose ------- DRuntime is meant to be an abstraction layer above the compiler. Different compilers will likely have their own versions of DRuntime. While the implementations may differ, the interfaces should be the same. Features -------- The runtime library provides the following: * The Object class, the root of the class hierarchy. * Implementations of array operations. * The associative array implementation. * Type information and RTTI. * Common threading and fiber infrastructure. * Synchronization and coordination primitives. * Exception handling and stack tracing. * Garbage collection interface and implementation. * Program startup and shutdown routines. * Low-level math intrinsics and support code. * Interfaces to standard C99 functions and types. * Interfaces to operating system APIs. * Atomic load/store and binary operations. * CPU detection/identification for x86. * System-independent time/duration functionality. * D ABI demangling helpers. * Low-level bit operations/intrinsics. * Unit test, coverage, and trace support code. * Low-level helpers for compiler-inserted calls. Issues ------ To report a bug or look up known issues with the runtime library, please visit the [bug tracker](http://issues.dlang.org/). Licensing --------- See the LICENSE file for licensing information. Building -------- See the [wiki page](http://wiki.dlang.org/Building_DMD) for build instructions. ldc-1.1.0-beta3-src/runtime/druntime/posix.mak0000664000175000017500000001744212776214756017327 0ustar kaikai# This makefile is designed to be run by gnu make. # The default make program on FreeBSD 8.1 is not gnu make; to install gnu make: # pkg_add -r gmake # and then run as gmake rather than make. QUIET:= include osmodel.mak # Default to a release built, override with BUILD=debug ifeq (,$(BUILD)) BUILD_WAS_SPECIFIED=0 BUILD=release else BUILD_WAS_SPECIFIED=1 endif ifneq ($(BUILD),release) ifneq ($(BUILD),debug) $(error Unrecognized BUILD=$(BUILD), must be 'debug' or 'release') endif endif DMD=../dmd/src/dmd INSTALL_DIR=../install DOCDIR=doc IMPDIR=import OPTIONAL_PIC:=$(if $(PIC),-fPIC,) ifeq (osx,$(OS)) DOTDLL:=.dylib DOTLIB:=.a else DOTDLL:=.so DOTLIB:=.a endif DDOCFLAGS=-conf= -c -w -o- -Isrc -Iimport -version=CoreDdoc # Set CFLAGS CFLAGS=$(MODEL_FLAG) -fPIC -DHAVE_UNISTD_H ifeq ($(BUILD),debug) CFLAGS += -g else CFLAGS += -O3 endif ifeq (solaris,$(OS)) CFLAGS+=-D_REENTRANT # for thread-safe errno endif # Set DFLAGS UDFLAGS:=-conf= -Isrc -Iimport -w -dip25 $(MODEL_FLAG) $(OPTIONAL_PIC) ifeq ($(BUILD),debug) UDFLAGS += -g -debug DFLAGS:=$(UDFLAGS) else UDFLAGS += -O -release DFLAGS:=$(UDFLAGS) -inline # unittests don't compile with -inline endif ROOT_OF_THEM_ALL = generated ROOT = $(ROOT_OF_THEM_ALL)/$(OS)/$(BUILD)/$(MODEL) OBJDIR=obj/$(OS)/$(BUILD)/$(MODEL) DRUNTIME_BASE=druntime-$(OS)$(MODEL) DRUNTIME=$(ROOT)/libdruntime.a DRUNTIMESO=$(ROOT)/libdruntime.so DRUNTIMESOOBJ=$(ROOT)/libdruntime.so.o DRUNTIMESOLIB=$(ROOT)/libdruntime.so.a DOCFMT= include mak/COPY COPY:=$(subst \,/,$(COPY)) include mak/DOCS DOCS:=$(subst \,/,$(DOCS)) include mak/IMPORTS IMPORTS:=$(subst \,/,$(IMPORTS)) include mak/SRCS SRCS:=$(subst \,/,$(SRCS)) # NOTE: trace.d and cover.d are not necessary for a successful build # as both are used for debugging features (profiling and coverage) # NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and # minit.asm is not used by dmd for Linux OBJS= $(ROOT)/errno_c.o $(ROOT)/bss_section.o $(ROOT)/threadasm.o # build with shared library support SHARED=$(if $(findstring $(OS),linux freebsd),1,) LINKDL=$(if $(findstring $(OS),linux),-L-ldl,) MAKEFILE = $(firstword $(MAKEFILE_LIST)) # use timelimit to avoid deadlocks if available TIMELIMIT:=$(if $(shell which timelimit 2>/dev/null || true),timelimit -t 10 ,) ######################## All of'em ############################## ifneq (,$(SHARED)) target : import copy dll $(DRUNTIME) else target : import copy $(DRUNTIME) endif ######################## Doc .html file generation ############################## doc: $(DOCS) $(DOCDIR)/object.html : src/object.d $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< $(DOCDIR)/core_%.html : src/core/%.d $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< $(DOCDIR)/core_stdc_%.html : src/core/stdc/%.d $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< $(DOCDIR)/core_sync_%.html : src/core/sync/%.d $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< changelog.html: changelog.dd $(DMD) -Df$@ $< ######################## Header .di file generation ############################## import: $(IMPORTS) $(IMPDIR)/core/sync/%.di : src/core/sync/%.d @mkdir -p $(dir $@) $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $< ######################## Header .di file copy ############################## copy: $(COPY) $(IMPDIR)/object.d : src/object.d @mkdir -p $(dir $@) @rm -f $(IMPDIR)/object.di cp $< $@ $(IMPDIR)/%.di : src/%.di @mkdir -p $(dir $@) cp $< $@ $(IMPDIR)/%.d : src/%.d @mkdir -p $(dir $@) cp $< $@ ################### C/ASM Targets ############################ $(ROOT)/%.o : src/rt/%.c @mkdir -p $(dir $@) $(CC) -c $(CFLAGS) $< -o$@ $(ROOT)/errno_c.o : src/core/stdc/errno.c @mkdir -p $(dir $@) $(CC) -c $(CFLAGS) $< -o$@ $(ROOT)/threadasm.o : src/core/threadasm.S @mkdir -p $(dir $@) $(CC) -c $(CFLAGS) $< -o$@ ######################## Create a shared library ############################## $(DRUNTIMESO) $(DRUNTIMESOLIB) dll: DFLAGS+=-version=Shared -fPIC dll: $(DRUNTIMESOLIB) $(DRUNTIMESO): $(OBJS) $(SRCS) $(DMD) -shared -debuglib= -defaultlib= -of$(DRUNTIMESO) $(DFLAGS) $(SRCS) $(OBJS) $(LINKDL) $(DRUNTIMESOLIB): $(OBJS) $(SRCS) $(DMD) -c -fPIC -of$(DRUNTIMESOOBJ) $(DFLAGS) $(SRCS) $(DMD) -conf= -lib -of$(DRUNTIMESOLIB) $(DRUNTIMESOOBJ) $(OBJS) ################### Library generation ######################### $(DRUNTIME): $(OBJS) $(SRCS) $(DMD) -lib -of$(DRUNTIME) -Xfdruntime.json $(DFLAGS) $(SRCS) $(OBJS) UT_MODULES:=$(patsubst src/%.d,$(ROOT)/unittest/%,$(SRCS)) HAS_ADDITIONAL_TESTS:=$(shell test -d test && echo 1) ifeq ($(HAS_ADDITIONAL_TESTS),1) ADDITIONAL_TESTS:=test/init_fini test/exceptions test/coverage test/profile ADDITIONAL_TESTS+=$(if $(SHARED),test/shared,) endif .PHONY : unittest ifeq (1,$(BUILD_WAS_SPECIFIED)) unittest : $(UT_MODULES) $(addsuffix /.run,$(ADDITIONAL_TESTS)) @echo done else unittest : unittest-debug unittest-release unittest-%: $(MAKE) -f $(MAKEFILE) unittest OS=$(OS) MODEL=$(MODEL) DMD=$(DMD) BUILD=$* endif ifeq ($(OS),linux) old_kernel:=$(shell [ "$$(uname -r | cut -d'-' -f1)" \< "2.6.39" ] && echo 1) ifeq ($(old_kernel),1) UDFLAGS+=-version=Linux_Pre_2639 endif endif ifeq ($(OS),freebsd) DISABLED_TESTS = else DISABLED_TESTS = endif $(addprefix $(ROOT)/unittest/,$(DISABLED_TESTS)) : @echo $@ - disabled ifeq (,$(SHARED)) $(ROOT)/unittest/test_runner: $(OBJS) $(SRCS) src/test_runner.d $(DMD) $(UDFLAGS) -unittest -of$@ src/test_runner.d $(SRCS) $(OBJS) -debuglib= -defaultlib= else UT_DRUNTIME:=$(ROOT)/unittest/libdruntime-ut$(DOTDLL) $(UT_DRUNTIME): UDFLAGS+=-version=Shared -fPIC $(UT_DRUNTIME): $(OBJS) $(SRCS) $(DMD) $(UDFLAGS) -shared -unittest -of$@ $(SRCS) $(OBJS) $(LINKDL) -debuglib= -defaultlib= $(ROOT)/unittest/test_runner: $(UT_DRUNTIME) src/test_runner.d $(DMD) $(UDFLAGS) -of$@ src/test_runner.d -L$(UT_DRUNTIME) -debuglib= -defaultlib= endif # macro that returns the module name given the src path moduleName=$(subst rt.invariant,invariant,$(subst object_,object,$(subst /,.,$(1)))) $(ROOT)/unittest/% : $(ROOT)/unittest/test_runner @mkdir -p $(dir $@) # make the file very old so it builds and runs again if it fails @touch -t 197001230123 $@ # run unittest in its own directory $(QUIET)$(TIMELIMIT)$< $(call moduleName,$*) # succeeded, render the file new again @touch $@ $(addsuffix /.run,$(filter-out test/shared,$(ADDITIONAL_TESTS))): $(DRUNTIME) test/shared/.run: $(DRUNTIMESO) test/%/.run: test/%/Makefile $(QUIET)$(MAKE) -C test/$* MODEL=$(MODEL) OS=$(OS) DMD=$(abspath $(DMD)) BUILD=$(BUILD) \ DRUNTIME=$(abspath $(DRUNTIME)) DRUNTIMESO=$(abspath $(DRUNTIMESO)) LINKDL=$(LINKDL) \ QUIET=$(QUIET) TIMELIMIT='$(TIMELIMIT)' #################### test for undesired white spaces ########################## MANIFEST = $(shell git ls-tree --name-only -r HEAD) CWS_MAKEFILES = $(filter mak/% %.mak %/Makefile,$(MANIFEST)) NOT_MAKEFILES = $(filter-out $(CWS_MAKEFILES) src/rt/minit.obj test/%.exp,$(MANIFEST)) GREP = grep checkwhitespace: # restrict to linux, other platforms don't have a version of grep that supports -P ifeq (linux,$(OS)) $(GREP) -n -U -P "([ \t]$$|\r)" $(CWS_MAKEFILES) ; test "$$?" -ne 0 $(GREP) -n -U -P "( $$|\r|\t)" $(NOT_MAKEFILES) ; test "$$?" -ne 0 endif detab: detab $(MANIFEST) tolf $(MANIFEST) gitzip: git archive --format=zip HEAD > druntime.zip zip: druntime.zip druntime.zip: $(MANIFEST) rm -rf $@ zip $@ $^ install: target mkdir -p $(INSTALL_DIR)/src/druntime/import cp -r import/* $(INSTALL_DIR)/src/druntime/import/ cp LICENSE $(INSTALL_DIR)/druntime-LICENSE.txt clean: $(addsuffix /.clean,$(ADDITIONAL_TESTS)) rm -rf $(ROOT_OF_THEM_ALL) $(IMPDIR) $(DOCDIR) druntime.zip test/%/.clean: test/%/Makefile $(MAKE) -C test/$* clean .PHONY : auto-tester-build auto-tester-build: target checkwhitespace .PHONY : auto-tester-test auto-tester-test: unittest .DELETE_ON_ERROR: # GNU Make directive (delete output files on error) ldc-1.1.0-beta3-src/runtime/druntime/mak/0000775000175000017500000000000012776214756016233 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/mak/DOCS0000664000175000017500000000260212776214756016706 0ustar kaikaiDOCS=\ $(DOCDIR)\object.html \ $(DOCDIR)\core_atomic.html \ $(DOCDIR)\core_attribute.html \ $(DOCDIR)\core_bitop.html \ $(DOCDIR)\core_checkedint.html \ $(DOCDIR)\core_cpuid.html \ $(DOCDIR)\core_demangle.html \ $(DOCDIR)\core_exception.html \ $(DOCDIR)\core_math.html \ $(DOCDIR)\core_memory.html \ $(DOCDIR)\core_runtime.html \ $(DOCDIR)\core_simd.html \ $(DOCDIR)\core_thread.html \ $(DOCDIR)\core_time.html \ $(DOCDIR)\core_vararg.html \ \ $(DOCDIR)\core_stdc_complex.html \ $(DOCDIR)\core_stdc_ctype.html \ $(DOCDIR)\core_stdc_errno.html \ $(DOCDIR)\core_stdc_fenv.html \ $(DOCDIR)\core_stdc_float_.html \ $(DOCDIR)\core_stdc_inttypes.html \ $(DOCDIR)\core_stdc_limits.html \ $(DOCDIR)\core_stdc_locale.html \ $(DOCDIR)\core_stdc_math.html \ $(DOCDIR)\core_stdc_signal.html \ $(DOCDIR)\core_stdc_stdarg.html \ $(DOCDIR)\core_stdc_stddef.html \ $(DOCDIR)\core_stdc_stdint.html \ $(DOCDIR)\core_stdc_stdio.html \ $(DOCDIR)\core_stdc_stdlib.html \ $(DOCDIR)\core_stdc_string.html \ $(DOCDIR)\core_stdc_tgmath.html \ $(DOCDIR)\core_stdc_time.html \ $(DOCDIR)\core_stdc_wchar_.html \ $(DOCDIR)\core_stdc_wctype.html \ \ $(DOCDIR)\core_sync_barrier.html \ $(DOCDIR)\core_sync_condition.html \ $(DOCDIR)\core_sync_config.html \ $(DOCDIR)\core_sync_exception.html \ $(DOCDIR)\core_sync_mutex.html \ $(DOCDIR)\core_sync_rwmutex.html \ $(DOCDIR)\core_sync_semaphore.html ldc-1.1.0-beta3-src/runtime/druntime/mak/IMPORTS0000664000175000017500000000037112776214756017314 0ustar kaikaiIMPORTS=\ $(IMPDIR)\core\sync\barrier.di \ $(IMPDIR)\core\sync\condition.di \ $(IMPDIR)\core\sync\config.di \ $(IMPDIR)\core\sync\exception.di \ $(IMPDIR)\core\sync\mutex.di \ $(IMPDIR)\core\sync\rwmutex.di \ $(IMPDIR)\core\sync\semaphore.di ldc-1.1.0-beta3-src/runtime/druntime/mak/COPY0000664000175000017500000002707412776214756016742 0ustar kaikaiCOPY=\ $(IMPDIR)\object.d \ $(IMPDIR)\core\atomic.d \ $(IMPDIR)\core\attribute.d \ $(IMPDIR)\core\bitop.d \ $(IMPDIR)\core\checkedint.d \ $(IMPDIR)\core\cpuid.d \ $(IMPDIR)\core\demangle.d \ $(IMPDIR)\core\exception.d \ $(IMPDIR)\core\math.d \ $(IMPDIR)\core\memory.d \ $(IMPDIR)\core\runtime.d \ $(IMPDIR)\core\simd.d \ $(IMPDIR)\core\thread.d \ $(IMPDIR)\core\time.d \ $(IMPDIR)\core\vararg.d \ \ $(IMPDIR)\core\internal\abort.d \ $(IMPDIR)\core\internal\convert.d \ $(IMPDIR)\core\internal\hash.d \ $(IMPDIR)\core\internal\spinlock.d \ $(IMPDIR)\core\internal\string.d \ $(IMPDIR)\core\internal\traits.d \ \ $(IMPDIR)\core\stdc\complex.d \ $(IMPDIR)\core\stdc\config.d \ $(IMPDIR)\core\stdc\ctype.d \ $(IMPDIR)\core\stdc\errno.d \ $(IMPDIR)\core\stdc\fenv.d \ $(IMPDIR)\core\stdc\float_.d \ $(IMPDIR)\core\stdc\inttypes.d \ $(IMPDIR)\core\stdc\limits.d \ $(IMPDIR)\core\stdc\locale.d \ $(IMPDIR)\core\stdc\math.d \ $(IMPDIR)\core\stdc\signal.d \ $(IMPDIR)\core\stdc\stdarg.d \ $(IMPDIR)\core\stdc\stddef.d \ $(IMPDIR)\core\stdc\stdint.d \ $(IMPDIR)\core\stdc\stdio.d \ $(IMPDIR)\core\stdc\stdlib.d \ $(IMPDIR)\core\stdc\string.d \ $(IMPDIR)\core\stdc\tgmath.d \ $(IMPDIR)\core\stdc\time.d \ $(IMPDIR)\core\stdc\wchar_.d \ $(IMPDIR)\core\stdc\wctype.d \ \ $(IMPDIR)\core\stdcpp\typeinfo.d \ $(IMPDIR)\core\stdcpp\exception.d \ \ $(IMPDIR)\core\sys\freebsd\dlfcn.d \ $(IMPDIR)\core\sys\freebsd\execinfo.d \ \ $(IMPDIR)\core\sys\freebsd\sys\cdefs.d \ $(IMPDIR)\core\sys\freebsd\sys\elf.d \ $(IMPDIR)\core\sys\freebsd\sys\elf_common.d \ $(IMPDIR)\core\sys\freebsd\sys\elf32.d \ $(IMPDIR)\core\sys\freebsd\sys\elf64.d \ $(IMPDIR)\core\sys\freebsd\sys\event.d \ $(IMPDIR)\core\sys\freebsd\sys\link_elf.d \ $(IMPDIR)\core\sys\freebsd\sys\mman.d \ $(IMPDIR)\core\sys\freebsd\time.d \ \ $(IMPDIR)\core\sys\linux\config.d \ $(IMPDIR)\core\sys\linux\dlfcn.d \ $(IMPDIR)\core\sys\linux\elf.d \ $(IMPDIR)\core\sys\linux\epoll.d \ $(IMPDIR)\core\sys\linux\errno.d \ $(IMPDIR)\core\sys\linux\execinfo.d \ $(IMPDIR)\core\sys\linux\fcntl.d \ $(IMPDIR)\core\sys\linux\link.d \ $(IMPDIR)\core\sys\linux\termios.d \ $(IMPDIR)\core\sys\linux\time.d \ $(IMPDIR)\core\sys\linux\timerfd.d \ $(IMPDIR)\core\sys\linux\tipc.d \ $(IMPDIR)\core\sys\linux\unistd.d \ \ $(IMPDIR)\core\sys\linux\sys\auxv.d \ $(IMPDIR)\core\sys\linux\sys\inotify.d \ $(IMPDIR)\core\sys\linux\sys\mman.d \ $(IMPDIR)\core\sys\linux\sys\signalfd.d \ $(IMPDIR)\core\sys\linux\sys\socket.d \ $(IMPDIR)\core\sys\linux\sys\sysinfo.d \ $(IMPDIR)\core\sys\linux\sys\xattr.d \ \ $(IMPDIR)\core\sys\osx\execinfo.d \ $(IMPDIR)\core\sys\osx\pthread.d \ \ $(IMPDIR)\core\sys\osx\mach\dyld.d \ $(IMPDIR)\core\sys\osx\mach\getsect.d \ $(IMPDIR)\core\sys\osx\mach\kern_return.d \ $(IMPDIR)\core\sys\osx\mach\loader.d \ $(IMPDIR)\core\sys\osx\mach\port.d \ $(IMPDIR)\core\sys\osx\mach\semaphore.d \ $(IMPDIR)\core\sys\osx\mach\thread_act.d \ \ $(IMPDIR)\core\sys\osx\sys\cdefs.d \ $(IMPDIR)\core\sys\osx\sys\mman.d \ \ $(IMPDIR)\core\sys\posix\arpa\inet.d \ $(IMPDIR)\core\sys\posix\config.d \ $(IMPDIR)\core\sys\posix\dirent.d \ $(IMPDIR)\core\sys\posix\dlfcn.d \ $(IMPDIR)\core\sys\posix\fcntl.d \ $(IMPDIR)\core\sys\posix\grp.d \ $(IMPDIR)\core\sys\posix\inttypes.d \ $(IMPDIR)\core\sys\posix\netdb.d \ $(IMPDIR)\core\sys\posix\poll.d \ $(IMPDIR)\core\sys\posix\pthread.d \ $(IMPDIR)\core\sys\posix\pwd.d \ $(IMPDIR)\core\sys\posix\sched.d \ $(IMPDIR)\core\sys\posix\semaphore.d \ $(IMPDIR)\core\sys\posix\setjmp.d \ $(IMPDIR)\core\sys\posix\signal.d \ $(IMPDIR)\core\sys\posix\stdio.d \ $(IMPDIR)\core\sys\posix\stdlib.d \ $(IMPDIR)\core\sys\posix\syslog.d \ $(IMPDIR)\core\sys\posix\termios.d \ $(IMPDIR)\core\sys\posix\time.d \ $(IMPDIR)\core\sys\posix\ucontext.d \ $(IMPDIR)\core\sys\posix\unistd.d \ $(IMPDIR)\core\sys\posix\utime.d \ \ $(IMPDIR)\core\sys\posix\net\if_.d \ \ $(IMPDIR)\core\sys\posix\netinet\in_.d \ $(IMPDIR)\core\sys\posix\netinet\tcp.d \ \ $(IMPDIR)\core\sys\posix\sys\ioctl.d \ $(IMPDIR)\core\sys\posix\sys\ipc.d \ $(IMPDIR)\core\sys\posix\sys\mman.d \ $(IMPDIR)\core\sys\posix\sys\resource.d \ $(IMPDIR)\core\sys\posix\sys\select.d \ $(IMPDIR)\core\sys\posix\sys\shm.d \ $(IMPDIR)\core\sys\posix\sys\socket.d \ $(IMPDIR)\core\sys\posix\sys\stat.d \ $(IMPDIR)\core\sys\posix\sys\statvfs.d \ $(IMPDIR)\core\sys\posix\sys\time.d \ $(IMPDIR)\core\sys\posix\sys\types.d \ $(IMPDIR)\core\sys\posix\sys\uio.d \ $(IMPDIR)\core\sys\posix\sys\un.d \ $(IMPDIR)\core\sys\posix\sys\wait.d \ $(IMPDIR)\core\sys\posix\sys\utsname.d \ \ $(IMPDIR)\core\sys\solaris\dlfcn.d \ $(IMPDIR)\core\sys\solaris\elf.d \ $(IMPDIR)\core\sys\solaris\execinfo.d \ $(IMPDIR)\core\sys\solaris\libelf.d \ $(IMPDIR)\core\sys\solaris\link.d \ $(IMPDIR)\core\sys\solaris\time.d \ $(IMPDIR)\core\sys\solaris\sys\elf.d \ $(IMPDIR)\core\sys\solaris\sys\elf_386.d \ $(IMPDIR)\core\sys\solaris\sys\elf_amd64.d \ $(IMPDIR)\core\sys\solaris\sys\elf_notes.d \ $(IMPDIR)\core\sys\solaris\sys\elf_SPARC.d \ $(IMPDIR)\core\sys\solaris\sys\elftypes.d \ $(IMPDIR)\core\sys\solaris\sys\link.d \ $(IMPDIR)\core\sys\solaris\sys\procset.d \ $(IMPDIR)\core\sys\solaris\sys\types.d \ $(IMPDIR)\core\sys\solaris\sys\priocntl.d \ \ $(IMPDIR)\core\sys\windows\accctrl.d \ $(IMPDIR)\core\sys\windows\aclapi.d \ $(IMPDIR)\core\sys\windows\aclui.d \ $(IMPDIR)\core\sys\windows\basetsd.d \ $(IMPDIR)\core\sys\windows\basetyps.d \ $(IMPDIR)\core\sys\windows\cderr.d \ $(IMPDIR)\core\sys\windows\cguid.d \ $(IMPDIR)\core\sys\windows\com.d \ $(IMPDIR)\core\sys\windows\comcat.d \ $(IMPDIR)\core\sys\windows\commctrl.d \ $(IMPDIR)\core\sys\windows\commdlg.d \ $(IMPDIR)\core\sys\windows\core.d \ $(IMPDIR)\core\sys\windows\cpl.d \ $(IMPDIR)\core\sys\windows\cplext.d \ $(IMPDIR)\core\sys\windows\custcntl.d \ $(IMPDIR)\core\sys\windows\dbghelp.d \ $(IMPDIR)\core\sys\windows\dbghelp_types.d \ $(IMPDIR)\core\sys\windows\dbt.d \ $(IMPDIR)\core\sys\windows\dde.d \ $(IMPDIR)\core\sys\windows\ddeml.d \ $(IMPDIR)\core\sys\windows\dhcpcsdk.d \ $(IMPDIR)\core\sys\windows\dlgs.d \ $(IMPDIR)\core\sys\windows\dll.d \ $(IMPDIR)\core\sys\windows\docobj.d \ $(IMPDIR)\core\sys\windows\errorrep.d \ $(IMPDIR)\core\sys\windows\exdisp.d \ $(IMPDIR)\core\sys\windows\exdispid.d \ $(IMPDIR)\core\sys\windows\httpext.d \ $(IMPDIR)\core\sys\windows\idispids.d \ $(IMPDIR)\core\sys\windows\imagehlp.d \ $(IMPDIR)\core\sys\windows\imm.d \ $(IMPDIR)\core\sys\windows\intshcut.d \ $(IMPDIR)\core\sys\windows\ipexport.d \ $(IMPDIR)\core\sys\windows\iphlpapi.d \ $(IMPDIR)\core\sys\windows\ipifcons.d \ $(IMPDIR)\core\sys\windows\iprtrmib.d \ $(IMPDIR)\core\sys\windows\iptypes.d \ $(IMPDIR)\core\sys\windows\isguids.d \ $(IMPDIR)\core\sys\windows\lm.d \ $(IMPDIR)\core\sys\windows\lmaccess.d \ $(IMPDIR)\core\sys\windows\lmalert.d \ $(IMPDIR)\core\sys\windows\lmapibuf.d \ $(IMPDIR)\core\sys\windows\lmat.d \ $(IMPDIR)\core\sys\windows\lmaudit.d \ $(IMPDIR)\core\sys\windows\lmbrowsr.d \ $(IMPDIR)\core\sys\windows\lmchdev.d \ $(IMPDIR)\core\sys\windows\lmconfig.d \ $(IMPDIR)\core\sys\windows\lmcons.d \ $(IMPDIR)\core\sys\windows\lmerr.d \ $(IMPDIR)\core\sys\windows\lmerrlog.d \ $(IMPDIR)\core\sys\windows\lmmsg.d \ $(IMPDIR)\core\sys\windows\lmremutl.d \ $(IMPDIR)\core\sys\windows\lmrepl.d \ $(IMPDIR)\core\sys\windows\lmserver.d \ $(IMPDIR)\core\sys\windows\lmshare.d \ $(IMPDIR)\core\sys\windows\lmsname.d \ $(IMPDIR)\core\sys\windows\lmstats.d \ $(IMPDIR)\core\sys\windows\lmsvc.d \ $(IMPDIR)\core\sys\windows\lmuse.d \ $(IMPDIR)\core\sys\windows\lmuseflg.d \ $(IMPDIR)\core\sys\windows\lmwksta.d \ $(IMPDIR)\core\sys\windows\lzexpand.d \ $(IMPDIR)\core\sys\windows\mapi.d \ $(IMPDIR)\core\sys\windows\mciavi.d \ $(IMPDIR)\core\sys\windows\mcx.d \ $(IMPDIR)\core\sys\windows\mgmtapi.d \ $(IMPDIR)\core\sys\windows\mmsystem.d \ $(IMPDIR)\core\sys\windows\msacm.d \ $(IMPDIR)\core\sys\windows\mshtml.d \ $(IMPDIR)\core\sys\windows\mswsock.d \ $(IMPDIR)\core\sys\windows\nb30.d \ $(IMPDIR)\core\sys\windows\nddeapi.d \ $(IMPDIR)\core\sys\windows\nspapi.d \ $(IMPDIR)\core\sys\windows\ntdef.d \ $(IMPDIR)\core\sys\windows\ntdll.d \ $(IMPDIR)\core\sys\windows\ntldap.d \ $(IMPDIR)\core\sys\windows\ntsecapi.d \ $(IMPDIR)\core\sys\windows\ntsecpkg.d \ $(IMPDIR)\core\sys\windows\oaidl.d \ $(IMPDIR)\core\sys\windows\objbase.d \ $(IMPDIR)\core\sys\windows\objfwd.d \ $(IMPDIR)\core\sys\windows\objidl.d \ $(IMPDIR)\core\sys\windows\objsafe.d \ $(IMPDIR)\core\sys\windows\ocidl.d \ $(IMPDIR)\core\sys\windows\odbcinst.d \ $(IMPDIR)\core\sys\windows\ole.d \ $(IMPDIR)\core\sys\windows\ole2.d \ $(IMPDIR)\core\sys\windows\ole2ver.d \ $(IMPDIR)\core\sys\windows\oleacc.d \ $(IMPDIR)\core\sys\windows\oleauto.d \ $(IMPDIR)\core\sys\windows\olectl.d \ $(IMPDIR)\core\sys\windows\olectlid.d \ $(IMPDIR)\core\sys\windows\oledlg.d \ $(IMPDIR)\core\sys\windows\oleidl.d \ $(IMPDIR)\core\sys\windows\pbt.d \ $(IMPDIR)\core\sys\windows\powrprof.d \ $(IMPDIR)\core\sys\windows\prsht.d \ $(IMPDIR)\core\sys\windows\psapi.d \ $(IMPDIR)\core\sys\windows\rapi.d \ $(IMPDIR)\core\sys\windows\ras.d \ $(IMPDIR)\core\sys\windows\rasdlg.d \ $(IMPDIR)\core\sys\windows\raserror.d \ $(IMPDIR)\core\sys\windows\rassapi.d \ $(IMPDIR)\core\sys\windows\reason.d \ $(IMPDIR)\core\sys\windows\regstr.d \ $(IMPDIR)\core\sys\windows\richedit.d \ $(IMPDIR)\core\sys\windows\richole.d \ $(IMPDIR)\core\sys\windows\rpc.d \ $(IMPDIR)\core\sys\windows\rpcdce.d \ $(IMPDIR)\core\sys\windows\rpcdce2.d \ $(IMPDIR)\core\sys\windows\rpcdcep.d \ $(IMPDIR)\core\sys\windows\rpcndr.d \ $(IMPDIR)\core\sys\windows\rpcnsi.d \ $(IMPDIR)\core\sys\windows\rpcnsip.d \ $(IMPDIR)\core\sys\windows\rpcnterr.d \ $(IMPDIR)\core\sys\windows\schannel.d \ $(IMPDIR)\core\sys\windows\secext.d \ $(IMPDIR)\core\sys\windows\security.d \ $(IMPDIR)\core\sys\windows\servprov.d \ $(IMPDIR)\core\sys\windows\setupapi.d \ $(IMPDIR)\core\sys\windows\shellapi.d \ $(IMPDIR)\core\sys\windows\shldisp.d \ $(IMPDIR)\core\sys\windows\shlguid.d \ $(IMPDIR)\core\sys\windows\shlobj.d \ $(IMPDIR)\core\sys\windows\shlwapi.d \ $(IMPDIR)\core\sys\windows\snmp.d \ $(IMPDIR)\core\sys\windows\sql.d \ $(IMPDIR)\core\sys\windows\sqlext.d \ $(IMPDIR)\core\sys\windows\sqltypes.d \ $(IMPDIR)\core\sys\windows\sqlucode.d \ $(IMPDIR)\core\sys\windows\sspi.d \ $(IMPDIR)\core\sys\windows\stacktrace.d \ $(IMPDIR)\core\sys\windows\stat.d \ $(IMPDIR)\core\sys\windows\subauth.d \ $(IMPDIR)\core\sys\windows\threadaux.d \ $(IMPDIR)\core\sys\windows\tlhelp32.d \ $(IMPDIR)\core\sys\windows\tmschema.d \ $(IMPDIR)\core\sys\windows\unknwn.d \ $(IMPDIR)\core\sys\windows\uuid.d \ $(IMPDIR)\core\sys\windows\vfw.d \ $(IMPDIR)\core\sys\windows\w32api.d \ $(IMPDIR)\core\sys\windows\winbase.d \ $(IMPDIR)\core\sys\windows\winber.d \ $(IMPDIR)\core\sys\windows\wincon.d \ $(IMPDIR)\core\sys\windows\wincrypt.d \ $(IMPDIR)\core\sys\windows\windef.d \ $(IMPDIR)\core\sys\windows\windows.d \ $(IMPDIR)\core\sys\windows\winerror.d \ $(IMPDIR)\core\sys\windows\wingdi.d \ $(IMPDIR)\core\sys\windows\winhttp.d \ $(IMPDIR)\core\sys\windows\wininet.d \ $(IMPDIR)\core\sys\windows\winioctl.d \ $(IMPDIR)\core\sys\windows\winldap.d \ $(IMPDIR)\core\sys\windows\winnetwk.d \ $(IMPDIR)\core\sys\windows\winnls.d \ $(IMPDIR)\core\sys\windows\winnt.d \ $(IMPDIR)\core\sys\windows\winperf.d \ $(IMPDIR)\core\sys\windows\winreg.d \ $(IMPDIR)\core\sys\windows\winsock2.d \ $(IMPDIR)\core\sys\windows\winspool.d \ $(IMPDIR)\core\sys\windows\winsvc.d \ $(IMPDIR)\core\sys\windows\winuser.d \ $(IMPDIR)\core\sys\windows\winver.d \ $(IMPDIR)\core\sys\windows\wtsapi32.d \ $(IMPDIR)\core\sys\windows\wtypes.d \ \ $(IMPDIR)\etc\linux\memoryerror.d ldc-1.1.0-beta3-src/runtime/druntime/mak/SRCS0000664000175000017500000002307712776214756016741 0ustar kaikaiSRCS=\ src\object.d \ \ src\core\atomic.d \ src\core\attribute.d \ src\core\bitop.d \ src\core\checkedint.d \ src\core\cpuid.d \ src\core\demangle.d \ src\core\exception.d \ src\core\math.d \ src\core\memory.d \ src\core\runtime.d \ src\core\simd.d \ src\core\thread.d \ src\core\time.d \ src\core\vararg.d \ \ src\core\internal\abort.d \ src\core\internal\convert.d \ src\core\internal\hash.d \ src\core\internal\spinlock.d \ src\core\internal\string.d \ src\core\internal\traits.d \ \ src\core\stdc\config.d \ src\core\stdc\ctype.d \ src\core\stdc\errno.d \ src\core\stdc\fenv.d \ src\core\stdc\math.d \ src\core\stdc\signal.d \ src\core\stdc\stdarg.d \ src\core\stdc\stddef.d \ src\core\stdc\stdint.d \ src\core\stdc\stdio.d \ src\core\stdc\stdlib.d \ src\core\stdc\string.d \ src\core\stdc\time.d \ src\core\stdc\wchar_.d \ \ src\core\sync\barrier.d \ src\core\sync\condition.d \ src\core\sync\config.d \ src\core\sync\exception.d \ src\core\sync\mutex.d \ src\core\sync\rwmutex.d \ src\core\sync\semaphore.d \ \ src\core\sys\freebsd\execinfo.d \ src\core\sys\freebsd\sys\event.d \ \ src\core\sys\linux\stdio.d \ src\core\sys\linux\tipc.d \ \ src\core\sys\posix\signal.d \ src\core\sys\posix\dirent.d \ src\core\sys\posix\sys\resource.d \ src\core\sys\posix\sys\select.d \ src\core\sys\posix\sys\socket.d \ src\core\sys\posix\sys\stat.d \ src\core\sys\posix\sys\wait.d \ src\core\sys\posix\netdb.d \ src\core\sys\posix\sys\ioctl.d \ src\core\sys\posix\sys\utsname.d \ src\core\sys\posix\netinet\in_.d \ src\core\sys\posix\arpa\inet.d \ \ src\core\sys\solaris\sys\priocntl.d \ src\core\sys\solaris\sys\types.d \ src\core\sys\solaris\sys\procset.d \ \ src\core\sys\windows\accctrl.d \ src\core\sys\windows\aclapi.d \ src\core\sys\windows\aclui.d \ src\core\sys\windows\basetsd.d \ src\core\sys\windows\basetyps.d \ src\core\sys\windows\cderr.d \ src\core\sys\windows\cguid.d \ src\core\sys\windows\com.d \ src\core\sys\windows\comcat.d \ src\core\sys\windows\commctrl.d \ src\core\sys\windows\commdlg.d \ src\core\sys\windows\core.d \ src\core\sys\windows\cpl.d \ src\core\sys\windows\cplext.d \ src\core\sys\windows\custcntl.d \ src\core\sys\windows\dbghelp.d \ src\core\sys\windows\dbghelp_types.d \ src\core\sys\windows\dbt.d \ src\core\sys\windows\dde.d \ src\core\sys\windows\ddeml.d \ src\core\sys\windows\dhcpcsdk.d \ src\core\sys\windows\dlgs.d \ src\core\sys\windows\dll.d \ src\core\sys\windows\docobj.d \ src\core\sys\windows\errorrep.d \ src\core\sys\windows\exdisp.d \ src\core\sys\windows\exdispid.d \ src\core\sys\windows\httpext.d \ src\core\sys\windows\idispids.d \ src\core\sys\windows\imagehlp.d \ src\core\sys\windows\imm.d \ src\core\sys\windows\intshcut.d \ src\core\sys\windows\ipexport.d \ src\core\sys\windows\iphlpapi.d \ src\core\sys\windows\ipifcons.d \ src\core\sys\windows\iprtrmib.d \ src\core\sys\windows\iptypes.d \ src\core\sys\windows\isguids.d \ src\core\sys\windows\lm.d \ src\core\sys\windows\lmaccess.d \ src\core\sys\windows\lmalert.d \ src\core\sys\windows\lmapibuf.d \ src\core\sys\windows\lmat.d \ src\core\sys\windows\lmaudit.d \ src\core\sys\windows\lmbrowsr.d \ src\core\sys\windows\lmchdev.d \ src\core\sys\windows\lmconfig.d \ src\core\sys\windows\lmcons.d \ src\core\sys\windows\lmerr.d \ src\core\sys\windows\lmerrlog.d \ src\core\sys\windows\lmmsg.d \ src\core\sys\windows\lmremutl.d \ src\core\sys\windows\lmrepl.d \ src\core\sys\windows\lmserver.d \ src\core\sys\windows\lmshare.d \ src\core\sys\windows\lmsname.d \ src\core\sys\windows\lmstats.d \ src\core\sys\windows\lmsvc.d \ src\core\sys\windows\lmuse.d \ src\core\sys\windows\lmuseflg.d \ src\core\sys\windows\lmwksta.d \ src\core\sys\windows\lzexpand.d \ src\core\sys\windows\mapi.d \ src\core\sys\windows\mciavi.d \ src\core\sys\windows\mcx.d \ src\core\sys\windows\mgmtapi.d \ src\core\sys\windows\mmsystem.d \ src\core\sys\windows\msacm.d \ src\core\sys\windows\mshtml.d \ src\core\sys\windows\mswsock.d \ src\core\sys\windows\nb30.d \ src\core\sys\windows\nddeapi.d \ src\core\sys\windows\nspapi.d \ src\core\sys\windows\ntdef.d \ src\core\sys\windows\ntdll.d \ src\core\sys\windows\ntldap.d \ src\core\sys\windows\ntsecapi.d \ src\core\sys\windows\ntsecpkg.d \ src\core\sys\windows\oaidl.d \ src\core\sys\windows\objbase.d \ src\core\sys\windows\objfwd.d \ src\core\sys\windows\objidl.d \ src\core\sys\windows\objsafe.d \ src\core\sys\windows\ocidl.d \ src\core\sys\windows\odbcinst.d \ src\core\sys\windows\ole.d \ src\core\sys\windows\ole2.d \ src\core\sys\windows\ole2ver.d \ src\core\sys\windows\oleacc.d \ src\core\sys\windows\oleauto.d \ src\core\sys\windows\olectl.d \ src\core\sys\windows\olectlid.d \ src\core\sys\windows\oledlg.d \ src\core\sys\windows\oleidl.d \ src\core\sys\windows\pbt.d \ src\core\sys\windows\powrprof.d \ src\core\sys\windows\prsht.d \ src\core\sys\windows\psapi.d \ src\core\sys\windows\rapi.d \ src\core\sys\windows\ras.d \ src\core\sys\windows\rasdlg.d \ src\core\sys\windows\raserror.d \ src\core\sys\windows\rassapi.d \ src\core\sys\windows\reason.d \ src\core\sys\windows\regstr.d \ src\core\sys\windows\richedit.d \ src\core\sys\windows\richole.d \ src\core\sys\windows\rpc.d \ src\core\sys\windows\rpcdce.d \ src\core\sys\windows\rpcdce2.d \ src\core\sys\windows\rpcdcep.d \ src\core\sys\windows\rpcndr.d \ src\core\sys\windows\rpcnsi.d \ src\core\sys\windows\rpcnsip.d \ src\core\sys\windows\rpcnterr.d \ src\core\sys\windows\schannel.d \ src\core\sys\windows\secext.d \ src\core\sys\windows\security.d \ src\core\sys\windows\servprov.d \ src\core\sys\windows\setupapi.d \ src\core\sys\windows\shellapi.d \ src\core\sys\windows\shldisp.d \ src\core\sys\windows\shlguid.d \ src\core\sys\windows\shlobj.d \ src\core\sys\windows\shlwapi.d \ src\core\sys\windows\snmp.d \ src\core\sys\windows\sql.d \ src\core\sys\windows\sqlext.d \ src\core\sys\windows\sqltypes.d \ src\core\sys\windows\sqlucode.d \ src\core\sys\windows\sspi.d \ src\core\sys\windows\stacktrace.d \ src\core\sys\windows\stat.d \ src\core\sys\windows\subauth.d \ src\core\sys\windows\threadaux.d \ src\core\sys\windows\tlhelp32.d \ src\core\sys\windows\tmschema.d \ src\core\sys\windows\unknwn.d \ src\core\sys\windows\uuid.d \ src\core\sys\windows\vfw.d \ src\core\sys\windows\w32api.d \ src\core\sys\windows\winbase.d \ src\core\sys\windows\winber.d \ src\core\sys\windows\wincon.d \ src\core\sys\windows\wincrypt.d \ src\core\sys\windows\windef.d \ src\core\sys\windows\windows.d \ src\core\sys\windows\winerror.d \ src\core\sys\windows\wingdi.d \ src\core\sys\windows\winhttp.d \ src\core\sys\windows\wininet.d \ src\core\sys\windows\winioctl.d \ src\core\sys\windows\winldap.d \ src\core\sys\windows\winnetwk.d \ src\core\sys\windows\winnls.d \ src\core\sys\windows\winnt.d \ src\core\sys\windows\winperf.d \ src\core\sys\windows\winreg.d \ src\core\sys\windows\winsock2.d \ src\core\sys\windows\winspool.d \ src\core\sys\windows\winsvc.d \ src\core\sys\windows\winuser.d \ src\core\sys\windows\winver.d \ src\core\sys\windows\wtsapi32.d \ src\core\sys\windows\wtypes.d \ \ src\gc\bits.d \ src\gc\config.d \ src\gc\gc.d \ src\gc\os.d \ src\gc\pooltable.d \ src\gc\proxy.d \ src\gc\stats.d \ \ src\rt\aApply.d \ src\rt\aApplyR.d \ src\rt\aaA.d \ src\rt\adi.d \ src\rt\alloca.d \ src\rt\arrayassign.d \ src\rt\arraybyte.d \ src\rt\arraycast.d \ src\rt\arraycat.d \ src\rt\arraydouble.d \ src\rt\arrayfloat.d \ src\rt\arrayint.d \ src\rt\arrayreal.d \ src\rt\arrayshort.d \ src\rt\cast_.d \ src\rt\cmath2.d \ src\rt\config.d \ src\rt\cover.d \ src\rt\critical_.d \ src\rt\deh.d \ src\rt\deh_win32.d \ src\rt\deh_win64_posix.d \ src\rt\dmain2.d \ src\rt\dwarfeh.d \ src\rt\invariant.d \ src\rt\lifetime.d \ src\rt\llmath.d \ src\rt\memory.d \ src\rt\memset.d \ src\rt\minfo.d \ src\rt\monitor_.d \ src\rt\obj.d \ src\rt\profilegc.d \ src\rt\qsort.d \ src\rt\sections.d \ src\rt\sections_android.d \ src\rt\sections_elf_shared.d \ src\rt\sections_osx.d \ src\rt\sections_solaris.d \ src\rt\sections_win32.d \ src\rt\sections_win64.d \ src\rt\switch_.d \ src\rt\tlsgc.d \ src\rt\trace.d \ src\rt\tracegc.d \ src\rt\unwind.d \ \ src\rt\backtrace\dwarf.d \ src\rt\backtrace\elf.d \ \ src\rt\util\array.d \ src\rt\util\hash.d \ src\rt\util\random.d \ src\rt\util\typeinfo.d \ src\rt\util\utf.d \ src\rt\util\container\array.d \ src\rt\util\container\common.d \ src\rt\util\container\hashtab.d \ src\rt\util\container\treap.d \ \ src\rt\typeinfo\ti_AC.d \ src\rt\typeinfo\ti_Acdouble.d \ src\rt\typeinfo\ti_Acfloat.d \ src\rt\typeinfo\ti_Acreal.d \ src\rt\typeinfo\ti_Adouble.d \ src\rt\typeinfo\ti_Afloat.d \ src\rt\typeinfo\ti_Ag.d \ src\rt\typeinfo\ti_Aint.d \ src\rt\typeinfo\ti_Along.d \ src\rt\typeinfo\ti_Areal.d \ src\rt\typeinfo\ti_Ashort.d \ src\rt\typeinfo\ti_byte.d \ src\rt\typeinfo\ti_C.d \ src\rt\typeinfo\ti_cdouble.d \ src\rt\typeinfo\ti_cent.d \ src\rt\typeinfo\ti_cfloat.d \ src\rt\typeinfo\ti_char.d \ src\rt\typeinfo\ti_creal.d \ src\rt\typeinfo\ti_dchar.d \ src\rt\typeinfo\ti_delegate.d \ src\rt\typeinfo\ti_double.d \ src\rt\typeinfo\ti_float.d \ src\rt\typeinfo\ti_idouble.d \ src\rt\typeinfo\ti_ifloat.d \ src\rt\typeinfo\ti_int.d \ src\rt\typeinfo\ti_ireal.d \ src\rt\typeinfo\ti_long.d \ src\rt\typeinfo\ti_ptr.d \ src\rt\typeinfo\ti_real.d \ src\rt\typeinfo\ti_short.d \ src\rt\typeinfo\ti_ubyte.d \ src\rt\typeinfo\ti_ucent.d \ src\rt\typeinfo\ti_uint.d \ src\rt\typeinfo\ti_ulong.d \ src\rt\typeinfo\ti_ushort.d \ src\rt\typeinfo\ti_void.d \ src\rt\typeinfo\ti_wchar.d \ \ src\etc\linux\memoryerror.d ldc-1.1.0-beta3-src/runtime/druntime/src/0000775000175000017500000000000012776214756016252 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/object.d0000664000175000017500000026372212776214756017701 0ustar kaikai/** * Forms the symbols available to all D programs. Includes Object, which is * the root of the class object hierarchy. This module is implicitly * imported. * Macros: * WIKI = Object * * Copyright: Copyright Digital Mars 2000 - 2011. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2000 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module object; private { extern (C) Object _d_newclass(const TypeInfo_Class ci); extern (C) void rt_finalize(void *data, bool det=true); } // NOTE: For some reason, this declaration method doesn't work // in this particular file (and this file only). It must // be a DMD thing. //alias typeof(int.sizeof) size_t; //alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; version(D_LP64) { alias ulong size_t; alias long ptrdiff_t; } else { alias uint size_t; alias int ptrdiff_t; } alias ptrdiff_t sizediff_t; //For backwards compatibility only. alias size_t hash_t; //For backwards compatibility only. alias bool equals_t; //For backwards compatibility only. alias immutable(char)[] string; alias immutable(wchar)[] wstring; alias immutable(dchar)[] dstring; version (LDC) { // Layout of this struct must match __gnuc_va_list for C ABI compatibility. // Defined here for LDC as it is referenced from implicitly generated code // for D-style variadics, etc., and we do not require people to manually // import core.vararg like DMD does. version (X86_64) { struct __va_list_tag { uint offset_regs = 6 * 8; uint offset_fpregs = 6 * 8 + 8 * 16; void* stack_args; void* reg_args; } } else version (AArch64) { version( iOS ) {} else version( TVOS ) {} else { static import ldc.internal.vararg; alias __va_list = ldc.internal.vararg.std.__va_list; } } else version (ARM) { // Darwin does not use __va_list version( iOS ) {} else version( WatchOS ) {} else { static import ldc.internal.vararg; alias __va_list = ldc.internal.vararg.std.__va_list; } } } version (D_ObjectiveC) public import core.attribute : selector; /** * All D class objects inherit from Object. */ class Object { /** * Convert Object to a human readable string. */ string toString() { return typeid(this).name; } /** * Compute hash function for Object. */ size_t toHash() @trusted nothrow { // BUG: this prevents a compacting GC from working, needs to be fixed return cast(size_t)cast(void*)this; } /** * Compare with another Object obj. * Returns: * $(TABLE * $(TR $(TD this < obj) $(TD < 0)) * $(TR $(TD this == obj) $(TD 0)) * $(TR $(TD this > obj) $(TD > 0)) * ) */ int opCmp(Object o) { // BUG: this prevents a compacting GC from working, needs to be fixed //return cast(int)cast(void*)this - cast(int)cast(void*)o; throw new Exception("need opCmp for class " ~ typeid(this).name); //return this !is o; } /** * Returns !=0 if this object does have the same contents as obj. */ bool opEquals(Object o) { return this is o; } interface Monitor { void lock(); void unlock(); } /** * Create instance of class specified by the fully qualified name * classname. * The class must either have no constructors or have * a default constructor. * Returns: * null if failed * Example: * --- * module foo.bar; * * class C * { * this() { x = 10; } * int x; * } * * void main() * { * auto c = cast(C)Object.factory("foo.bar.C"); * assert(c !is null && c.x == 10); * } * --- */ static Object factory(string classname) { auto ci = TypeInfo_Class.find(classname); if (ci) { return ci.create(); } return null; } } auto opEquals(Object lhs, Object rhs) { // If aliased to the same object or both null => equal if (lhs is rhs) return true; // If either is null => non-equal if (lhs is null || rhs is null) return false; // If same exact type => one call to method opEquals if (typeid(lhs) is typeid(rhs) || !__ctfe && typeid(lhs).opEquals(typeid(rhs))) /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't (issue 7147). But CTFE also guarantees that equal TypeInfos are always identical. So, no opEquals needed during CTFE. */ { return lhs.opEquals(rhs); } // General case => symmetric calls to method opEquals return lhs.opEquals(rhs) && rhs.opEquals(lhs); } /************************ * Returns true if lhs and rhs are equal. */ auto opEquals(const Object lhs, const Object rhs) { // A hack for the moment. return opEquals(cast()lhs, cast()rhs); } private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow; void setSameMutex(shared Object ownee, shared Object owner) { _d_setSameMutex(ownee, owner); } /** * Information about an interface. * When an object is accessed via an interface, an Interface* appears as the * first entry in its vtbl. */ struct Interface { TypeInfo_Class classinfo; /// .classinfo for this interface (not for containing class) void*[] vtbl; size_t offset; /// offset to Interface 'this' from Object 'this' } /** * Array of pairs giving the offset and type information for each * member in an aggregate. */ struct OffsetTypeInfo { size_t offset; /// Offset of member from start of object TypeInfo ti; /// TypeInfo for this member } /** * Runtime type information about a type. * Can be retrieved for any type using a * $(GLINK2 expression,TypeidExpression, TypeidExpression). */ class TypeInfo { override string toString() const pure @safe nothrow { return typeid(this).name; } override size_t toHash() @trusted const { import core.internal.traits : externDFunc; alias hashOf = externDFunc!("rt.util.hash.hashOf", size_t function(const(void)*, size_t, size_t) @trusted pure nothrow); try { auto data = this.toString(); return hashOf(data.ptr, data.length, 0); } catch (Throwable) { // This should never happen; remove when toString() is made nothrow // BUG: this prevents a compacting GC from working, needs to be fixed return cast(size_t)cast(void*)this; } } override int opCmp(Object o) { import core.internal.traits : externDFunc; alias dstrcmp = externDFunc!("core.internal.string.dstrcmp", int function(in char[] s1, in char[] s2) @trusted pure nothrow @nogc); if (this is o) return 0; TypeInfo ti = cast(TypeInfo)o; if (ti is null) return 1; return dstrcmp(this.toString(), ti.toString()); } override bool opEquals(Object o) { /* TypeInfo instances are singletons, but duplicates can exist * across DLL's. Therefore, comparing for a name match is * sufficient. */ if (this is o) return true; auto ti = cast(const TypeInfo)o; return ti && this.toString() == ti.toString(); } /// Returns a hash of the instance of a type. size_t getHash(in void* p) @trusted nothrow const { return cast(size_t)p; } /// Compares two instances for equality. bool equals(in void* p1, in void* p2) const { return p1 == p2; } /// Compares two instances for <, ==, or >. int compare(in void* p1, in void* p2) const { return _xopCmp(p1, p2); } /// Returns size of the type. @property size_t tsize() nothrow pure const @safe @nogc { return 0; } /// Swaps two instances of the type. void swap(void* p1, void* p2) const { size_t n = tsize; for (size_t i = 0; i < n; i++) { byte t = (cast(byte *)p1)[i]; (cast(byte*)p1)[i] = (cast(byte*)p2)[i]; (cast(byte*)p2)[i] = t; } } /// Get TypeInfo for 'next' type, as defined by what kind of type this is, /// null if none. @property inout(TypeInfo) next() nothrow pure inout @nogc { return null; } /// Return default initializer. If the type should be initialized to all zeros, /// an array with a null ptr and a length equal to the type size will be returned. version(LDC) { // LDC uses TypeInfo's vtable for the typeof(null) type: // %"typeid(typeof(null))" = type { %object.TypeInfo.__vtbl*, i8* } // Therefore this class cannot be abstract, and all methods need implementations. // Tested by test14754() in runnable/inline.d, and a unittest below. const(void)[] initializer() nothrow pure const @safe @nogc { return null; } } else { abstract const(void)[] initializer() nothrow pure const @safe @nogc; } /// $(RED Scheduled for deprecation.) Please use `initializer` instead. alias init = initializer; // added in 2.070, to stay in 2.071 version(none) deprecated alias init = initializer; // planned for 2.072 version(none) @disable static const(void)[] init(); // planned for 2.073 /* Planned for 2.074: Remove init, making way for the init type property, fixing issue 12233. */ /// Get flags for type: 1 means GC should scan for pointers, /// 2 means arg of this type is passed in XMM register @property uint flags() nothrow pure const @safe @nogc { return 0; } /// Get type information on the contents of the type; null if not available const(OffsetTypeInfo)[] offTi() const { return null; } /// Run the destructor on the object and all its sub-objects void destroy(void* p) const {} /// Run the postblit on the object and all its sub-objects void postblit(void* p) const {} /// Return alignment of type @property size_t talign() nothrow pure const @safe @nogc { return tsize; } /** Return internal info on arguments fitting into 8byte. * See X86-64 ABI 3.2.3 */ version (X86_64) int argTypes(out TypeInfo arg1, out TypeInfo arg2) @safe nothrow { arg1 = this; return 0; } /** Return info used by the garbage collector to do precise collection. */ @property immutable(void)* rtInfo() nothrow pure const @safe @nogc { return null; } } version(LDC) unittest { auto t = new TypeInfo; // test that TypeInfo is not an abstract class. Needed for instantiating typeof(null). } class TypeInfo_Typedef : TypeInfo { override string toString() const { return name; } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_Typedef)o; return c && this.name == c.name && this.base == c.base; } override size_t getHash(in void* p) const { return base.getHash(p); } override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); } override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); } override @property size_t tsize() nothrow pure const { return base.tsize; } override void swap(void* p1, void* p2) const { return base.swap(p1, p2); } override @property inout(TypeInfo) next() nothrow pure inout { return base.next; } override @property uint flags() nothrow pure const { return base.flags; } override const(void)[] initializer() const { return m_init.length ? m_init : base.initializer(); } override @property size_t talign() nothrow pure const { return base.talign; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { return base.argTypes(arg1, arg2); } override @property immutable(void)* rtInfo() const { return base.rtInfo; } TypeInfo base; string name; void[] m_init; } class TypeInfo_Enum : TypeInfo_Typedef { } // Please make sure to keep this in sync with TypeInfo_P (src/rt/typeinfo/ti_ptr.d) class TypeInfo_Pointer : TypeInfo { override string toString() const { return m_next.toString() ~ "*"; } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_Pointer)o; return c && this.m_next == c.m_next; } override size_t getHash(in void* p) @trusted const { return cast(size_t)*cast(void**)p; } override bool equals(in void* p1, in void* p2) const { return *cast(void**)p1 == *cast(void**)p2; } override int compare(in void* p1, in void* p2) const { if (*cast(void**)p1 < *cast(void**)p2) return -1; else if (*cast(void**)p1 > *cast(void**)p2) return 1; else return 0; } override @property size_t tsize() nothrow pure const { return (void*).sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. (void*).sizeof]; } override void swap(void* p1, void* p2) const { void* tmp = *cast(void**)p1; *cast(void**)p1 = *cast(void**)p2; *cast(void**)p2 = tmp; } override @property inout(TypeInfo) next() nothrow pure inout { return m_next; } override @property uint flags() nothrow pure const { return 1; } TypeInfo m_next; } class TypeInfo_Array : TypeInfo { override string toString() const { return value.toString() ~ "[]"; } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_Array)o; return c && this.value == c.value; } override size_t getHash(in void* p) @trusted const { void[] a = *cast(void[]*)p; return getArrayHash(value, a.ptr, a.length); } override bool equals(in void* p1, in void* p2) const { void[] a1 = *cast(void[]*)p1; void[] a2 = *cast(void[]*)p2; if (a1.length != a2.length) return false; size_t sz = value.tsize; for (size_t i = 0; i < a1.length; i++) { if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) return false; } return true; } override int compare(in void* p1, in void* p2) const { void[] a1 = *cast(void[]*)p1; void[] a2 = *cast(void[]*)p2; size_t sz = value.tsize; size_t len = a1.length; if (a2.length < len) len = a2.length; for (size_t u = 0; u < len; u++) { int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz); if (result) return result; } return cast(int)a1.length - cast(int)a2.length; } override @property size_t tsize() nothrow pure const { return (void[]).sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. (void[]).sizeof]; } override void swap(void* p1, void* p2) const { void[] tmp = *cast(void[]*)p1; *cast(void[]*)p1 = *cast(void[]*)p2; *cast(void[]*)p2 = tmp; } TypeInfo value; override @property inout(TypeInfo) next() nothrow pure inout { return value; } override @property uint flags() nothrow pure const { return 1; } override @property size_t talign() nothrow pure const { return (void[]).alignof; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { arg1 = typeid(size_t); arg2 = typeid(void*); return 0; } } class TypeInfo_StaticArray : TypeInfo { override string toString() const { import core.internal.traits : externDFunc; alias sizeToTempString = externDFunc!("core.internal.string.unsignedToTempString", char[] function(ulong, char[], uint) @safe pure nothrow @nogc); char[20] tmpBuff = void; return value.toString() ~ "[" ~ sizeToTempString(len, tmpBuff, 10) ~ "]"; } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_StaticArray)o; return c && this.len == c.len && this.value == c.value; } override size_t getHash(in void* p) @trusted const { return getArrayHash(value, p, len); } override bool equals(in void* p1, in void* p2) const { size_t sz = value.tsize; for (size_t u = 0; u < len; u++) { if (!value.equals(p1 + u * sz, p2 + u * sz)) return false; } return true; } override int compare(in void* p1, in void* p2) const { size_t sz = value.tsize; for (size_t u = 0; u < len; u++) { int result = value.compare(p1 + u * sz, p2 + u * sz); if (result) return result; } return 0; } override @property size_t tsize() nothrow pure const { return len * value.tsize; } override void swap(void* p1, void* p2) const { import core.memory; import core.stdc.string : memcpy; void* tmp; size_t sz = value.tsize; ubyte[16] buffer; void* pbuffer; if (sz < buffer.sizeof) tmp = buffer.ptr; else tmp = pbuffer = (new void[sz]).ptr; for (size_t u = 0; u < len; u += sz) { size_t o = u * sz; memcpy(tmp, p1 + o, sz); memcpy(p1 + o, p2 + o, sz); memcpy(p2 + o, tmp, sz); } if (pbuffer) GC.free(pbuffer); } override const(void)[] initializer() nothrow pure const { return value.initializer(); } override @property inout(TypeInfo) next() nothrow pure inout { return value; } override @property uint flags() nothrow pure const { return value.flags; } override void destroy(void* p) const { auto sz = value.tsize; p += sz * len; foreach (i; 0 .. len) { p -= sz; value.destroy(p); } } override void postblit(void* p) const { auto sz = value.tsize; foreach (i; 0 .. len) { value.postblit(p); p += sz; } } TypeInfo value; size_t len; override @property size_t talign() nothrow pure const { return value.talign; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { arg1 = typeid(void*); return 0; } } class TypeInfo_AssociativeArray : TypeInfo { override string toString() const { return value.toString() ~ "[" ~ key.toString() ~ "]"; } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_AssociativeArray)o; return c && this.key == c.key && this.value == c.value; } override bool equals(in void* p1, in void* p2) @trusted const { return !!_aaEqual(this, *cast(const void**) p1, *cast(const void**) p2); } override hash_t getHash(in void* p) nothrow @trusted const { return _aaGetHash(cast(void*)p, this); } // BUG: need to add the rest of the functions override @property size_t tsize() nothrow pure const { return (char[int]).sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. (char[int]).sizeof]; } override @property inout(TypeInfo) next() nothrow pure inout { return value; } override @property uint flags() nothrow pure const { return 1; } TypeInfo value; TypeInfo key; override @property size_t talign() nothrow pure const { return (char[int]).alignof; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { arg1 = typeid(void*); return 0; } } class TypeInfo_Vector : TypeInfo { override string toString() const { return "__vector(" ~ base.toString() ~ ")"; } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_Vector)o; return c && this.base == c.base; } override size_t getHash(in void* p) const { return base.getHash(p); } override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); } override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); } override @property size_t tsize() nothrow pure const { return base.tsize; } override void swap(void* p1, void* p2) const { return base.swap(p1, p2); } override @property inout(TypeInfo) next() nothrow pure inout { return base.next; } override @property uint flags() nothrow pure const { return base.flags; } override const(void)[] initializer() nothrow pure const { return base.initializer(); } override @property size_t talign() nothrow pure const { return 16; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { return base.argTypes(arg1, arg2); } TypeInfo base; } class TypeInfo_Function : TypeInfo { override string toString() const { return cast(string)(next.toString() ~ "()"); } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_Function)o; return c && this.deco == c.deco; } // BUG: need to add the rest of the functions override @property size_t tsize() nothrow pure const { return 0; // no size for functions } override const(void)[] initializer() const @safe { return null; } TypeInfo next; string deco; } class TypeInfo_Delegate : TypeInfo { override string toString() const { return cast(string)(next.toString() ~ " delegate()"); } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_Delegate)o; return c && this.deco == c.deco; } override size_t getHash(in void* p) @trusted const { return hashOf(*cast(void delegate()*)p); } override bool equals(in void* p1, in void* p2) const { auto dg1 = *cast(void delegate()*)p1; auto dg2 = *cast(void delegate()*)p2; return dg1 == dg2; } override int compare(in void* p1, in void* p2) const { auto dg1 = *cast(void delegate()*)p1; auto dg2 = *cast(void delegate()*)p2; if (dg1 < dg2) return -1; else if (dg1 > dg2) return 1; else return 0; } override @property size_t tsize() nothrow pure const { alias int delegate() dg; return dg.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. (int delegate()).sizeof]; } override @property uint flags() nothrow pure const { return 1; } TypeInfo next; string deco; override @property size_t talign() nothrow pure const { alias int delegate() dg; return dg.alignof; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { arg1 = typeid(void*); arg2 = typeid(void*); return 0; } } unittest { // Bugzilla 15367 void f1() {} void f2() {} // TypeInfo_Delegate.getHash int[void delegate()] aa; assert(aa.length == 0); aa[&f1] = 1; assert(aa.length == 1); aa[&f1] = 1; assert(aa.length == 1); auto a1 = [&f2, &f1]; auto a2 = [&f2, &f1]; // TypeInfo_Delegate.equals for (auto i = 0; i < 2; i++) assert(a1[i] == a2[i]); assert(a1 == a2); // TypeInfo_Delegate.compare for (auto i = 0; i < 2; i++) assert(a1[i] <= a2[i]); assert(a1 <= a2); } /** * Runtime type information about a class. * Can be retrieved from an object instance by using the * $(DDSUBLINK spec/property,classinfo, .classinfo) property. */ class TypeInfo_Class : TypeInfo { override string toString() const { return info.name; } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_Class)o; return c && this.info.name == c.info.name; } override size_t getHash(in void* p) @trusted const { auto o = *cast(Object*)p; return o ? o.toHash() : 0; } override bool equals(in void* p1, in void* p2) const { Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; return (o1 is o2) || (o1 && o1.opEquals(o2)); } override int compare(in void* p1, in void* p2) const { Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; int c = 0; // Regard null references as always being "less than" if (o1 !is o2) { if (o1) { if (!o2) c = 1; else c = o1.opCmp(o2); } else c = -1; } return c; } override @property size_t tsize() nothrow pure const { return Object.sizeof; } override const(void)[] initializer() nothrow pure const @safe { return m_init; } override @property uint flags() nothrow pure const { return 1; } override @property const(OffsetTypeInfo)[] offTi() nothrow pure const { return m_offTi; } @property auto info() @safe nothrow pure const { return this; } @property auto typeinfo() @safe nothrow pure const { return this; } byte[] m_init; /** class static initializer * (init.length gives size in bytes of class) */ string name; /// class name void*[] vtbl; /// virtual function pointer table Interface[] interfaces; /// interfaces this class implements TypeInfo_Class base; /// base class void* destructor; void function(Object) classInvariant; enum ClassFlags : uint { isCOMclass = 0x1, noPointers = 0x2, hasOffTi = 0x4, hasCtor = 0x8, hasGetMembers = 0x10, hasTypeInfo = 0x20, isAbstract = 0x40, isCPPclass = 0x80, hasDtor = 0x100, } ClassFlags m_flags; void* deallocator; OffsetTypeInfo[] m_offTi; void function(Object) defaultConstructor; // default Constructor immutable(void)* m_RTInfo; // data for precise GC override @property immutable(void)* rtInfo() const { return m_RTInfo; } /** * Search all modules for TypeInfo_Class corresponding to classname. * Returns: null if not found */ static const(TypeInfo_Class) find(in char[] classname) { foreach (m; ModuleInfo) { if (m) //writefln("module %s, %d", m.name, m.localClasses.length); foreach (c; m.localClasses) { if (c is null) continue; //writefln("\tclass %s", c.name); if (c.name == classname) return c; } } return null; } /** * Create instance of Object represented by 'this'. */ Object create() const { if (m_flags & 8 && !defaultConstructor) return null; if (m_flags & 64) // abstract return null; Object o = _d_newclass(this); if (m_flags & 8 && defaultConstructor) { defaultConstructor(o); } return o; } } alias TypeInfo_Class ClassInfo; unittest { // Bugzilla 14401 static class X { int a; } assert(typeid(X).initializer is typeid(X).m_init); assert(typeid(X).initializer.length == typeid(const(X)).initializer.length); assert(typeid(X).initializer.length == typeid(shared(X)).initializer.length); assert(typeid(X).initializer.length == typeid(immutable(X)).initializer.length); } class TypeInfo_Interface : TypeInfo { override string toString() const { return info.name; } override bool opEquals(Object o) { if (this is o) return true; auto c = cast(const TypeInfo_Interface)o; return c && this.info.name == typeid(c).name; } override size_t getHash(in void* p) @trusted const { Interface* pi = **cast(Interface ***)*cast(void**)p; Object o = cast(Object)(*cast(void**)p - pi.offset); assert(o); return o.toHash(); } override bool equals(in void* p1, in void* p2) const { Interface* pi = **cast(Interface ***)*cast(void**)p1; Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); pi = **cast(Interface ***)*cast(void**)p2; Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); return o1 == o2 || (o1 && o1.opCmp(o2) == 0); } override int compare(in void* p1, in void* p2) const { Interface* pi = **cast(Interface ***)*cast(void**)p1; Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); pi = **cast(Interface ***)*cast(void**)p2; Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); int c = 0; // Regard null references as always being "less than" if (o1 != o2) { if (o1) { if (!o2) c = 1; else c = o1.opCmp(o2); } else c = -1; } return c; } override @property size_t tsize() nothrow pure const { return Object.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. Object.sizeof]; } override @property uint flags() nothrow pure const { return 1; } TypeInfo_Class info; } class TypeInfo_Struct : TypeInfo { override string toString() const { return name; } override bool opEquals(Object o) { if (this is o) return true; auto s = cast(const TypeInfo_Struct)o; return s && this.name == s.name && this.initializer().length == s.initializer().length; } override size_t getHash(in void* p) @safe pure nothrow const { assert(p); if (xtoHash) { return (*xtoHash)(p); } else { import core.internal.traits : externDFunc; alias hashOf = externDFunc!("rt.util.hash.hashOf", size_t function(const(void)*, size_t, size_t) @trusted pure nothrow); return hashOf(p, initializer().length, 0); } } override bool equals(in void* p1, in void* p2) @trusted pure nothrow const { import core.stdc.string : memcmp; if (!p1 || !p2) return false; else if (xopEquals) return (*xopEquals)(p1, p2); else if (p1 == p2) return true; else // BUG: relies on the GC not moving objects return memcmp(p1, p2, initializer().length) == 0; } override int compare(in void* p1, in void* p2) @trusted pure nothrow const { import core.stdc.string : memcmp; // Regard null references as always being "less than" if (p1 != p2) { if (p1) { if (!p2) return true; else if (xopCmp) return (*xopCmp)(p2, p1); else // BUG: relies on the GC not moving objects return memcmp(p1, p2, initializer().length); } else return -1; } return 0; } override @property size_t tsize() nothrow pure const { return initializer().length; } override const(void)[] initializer() nothrow pure const @safe { return m_init; } override @property uint flags() nothrow pure const { return m_flags; } override @property size_t talign() nothrow pure const { return m_align; } final override void destroy(void* p) const { if (xdtor) { if (m_flags & StructFlags.isDynamicType) (*xdtorti)(p, this); else (*xdtor)(p); } } override void postblit(void* p) const { if (xpostblit) (*xpostblit)(p); } string name; void[] m_init; // initializer; m_init.ptr == null if 0 initialize @safe pure nothrow { size_t function(in void*) xtoHash; bool function(in void*, in void*) xopEquals; int function(in void*, in void*) xopCmp; string function(in void*) xtoString; enum StructFlags : uint { hasPointers = 0x1, isDynamicType = 0x2, // built at runtime, needs type info in xdtor } StructFlags m_flags; } union { void function(void*) xdtor; void function(void*, const TypeInfo_Struct ti) xdtorti; } void function(void*) xpostblit; uint m_align; override @property immutable(void)* rtInfo() const { return m_RTInfo; } version (X86_64) { override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { arg1 = m_arg1; arg2 = m_arg2; return 0; } TypeInfo m_arg1; TypeInfo m_arg2; } immutable(void)* m_RTInfo; // data for precise GC } unittest { struct S { bool opEquals(ref const S rhs) const { return false; } } S s; assert(!typeid(S).equals(&s, &s)); } class TypeInfo_Tuple : TypeInfo { TypeInfo[] elements; override string toString() const { string s = "("; foreach (i, element; elements) { if (i) s ~= ','; s ~= element.toString(); } s ~= ")"; return s; } override bool opEquals(Object o) { if (this is o) return true; auto t = cast(const TypeInfo_Tuple)o; if (t && elements.length == t.elements.length) { for (size_t i = 0; i < elements.length; i++) { if (elements[i] != t.elements[i]) return false; } return true; } return false; } override size_t getHash(in void* p) const { assert(0); } override bool equals(in void* p1, in void* p2) const { assert(0); } override int compare(in void* p1, in void* p2) const { assert(0); } override @property size_t tsize() nothrow pure const { assert(0); } override const(void)[] initializer() const @trusted { assert(0); } override void swap(void* p1, void* p2) const { assert(0); } override void destroy(void* p) const { assert(0); } override void postblit(void* p) const { assert(0); } override @property size_t talign() nothrow pure const { assert(0); } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { assert(0); } } class TypeInfo_Const : TypeInfo { override string toString() const { return cast(string) ("const(" ~ base.toString() ~ ")"); } //override bool opEquals(Object o) { return base.opEquals(o); } override bool opEquals(Object o) { if (this is o) return true; if (typeid(this) != typeid(o)) return false; auto t = cast(TypeInfo_Const)o; return base.opEquals(t.base); } override size_t getHash(in void *p) const { return base.getHash(p); } override bool equals(in void *p1, in void *p2) const { return base.equals(p1, p2); } override int compare(in void *p1, in void *p2) const { return base.compare(p1, p2); } override @property size_t tsize() nothrow pure const { return base.tsize; } override void swap(void *p1, void *p2) const { return base.swap(p1, p2); } override @property inout(TypeInfo) next() nothrow pure inout { return base.next; } override @property uint flags() nothrow pure const { return base.flags; } override const(void)[] initializer() nothrow pure const { return base.initializer(); } override @property size_t talign() nothrow pure const { return base.talign; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { return base.argTypes(arg1, arg2); } TypeInfo base; } class TypeInfo_Invariant : TypeInfo_Const { override string toString() const { return cast(string) ("immutable(" ~ base.toString() ~ ")"); } } class TypeInfo_Shared : TypeInfo_Const { override string toString() const { return cast(string) ("shared(" ~ base.toString() ~ ")"); } } class TypeInfo_Inout : TypeInfo_Const { override string toString() const { return cast(string) ("inout(" ~ base.toString() ~ ")"); } } /////////////////////////////////////////////////////////////////////////////// // ModuleInfo /////////////////////////////////////////////////////////////////////////////// enum { MIctorstart = 0x1, // we've started constructing it MIctordone = 0x2, // finished construction MIstandalone = 0x4, // module ctor does not depend on other module // ctors being done first MItlsctor = 8, MItlsdtor = 0x10, MIctor = 0x20, MIdtor = 0x40, MIxgetMembers = 0x80, MIictor = 0x100, MIunitTest = 0x200, MIimportedModules = 0x400, MIlocalClasses = 0x800, MIname = 0x1000, } struct ModuleInfo { uint _flags; uint _index; // index into _moduleinfo_array[] version (all) { deprecated("ModuleInfo cannot be copy-assigned because it is a variable-sized struct.") void opAssign(in ModuleInfo m) { _flags = m._flags; _index = m._index; } } else { @disable this(); @disable this(this) const; } const: private void* addrOf(int flag) nothrow pure in { assert(flag >= MItlsctor && flag <= MIname); assert(!(flag & (flag - 1)) && !(flag & ~(flag - 1) << 1)); } body { import core.stdc.string : strlen; void* p = cast(void*)&this + ModuleInfo.sizeof; if (flags & MItlsctor) { if (flag == MItlsctor) return p; p += typeof(tlsctor).sizeof; } if (flags & MItlsdtor) { if (flag == MItlsdtor) return p; p += typeof(tlsdtor).sizeof; } if (flags & MIctor) { if (flag == MIctor) return p; p += typeof(ctor).sizeof; } if (flags & MIdtor) { if (flag == MIdtor) return p; p += typeof(dtor).sizeof; } if (flags & MIxgetMembers) { if (flag == MIxgetMembers) return p; p += typeof(xgetMembers).sizeof; } if (flags & MIictor) { if (flag == MIictor) return p; p += typeof(ictor).sizeof; } if (flags & MIunitTest) { if (flag == MIunitTest) return p; p += typeof(unitTest).sizeof; } if (flags & MIimportedModules) { if (flag == MIimportedModules) return p; p += size_t.sizeof + *cast(size_t*)p * typeof(importedModules[0]).sizeof; } if (flags & MIlocalClasses) { if (flag == MIlocalClasses) return p; p += size_t.sizeof + *cast(size_t*)p * typeof(localClasses[0]).sizeof; } if (true || flags & MIname) // always available for now { if (flag == MIname) return p; p += strlen(cast(immutable char*)p); } assert(0); } @property uint index() nothrow pure { return _index; } @property uint flags() nothrow pure { return _flags; } @property void function() tlsctor() nothrow pure { return flags & MItlsctor ? *cast(typeof(return)*)addrOf(MItlsctor) : null; } @property void function() tlsdtor() nothrow pure { return flags & MItlsdtor ? *cast(typeof(return)*)addrOf(MItlsdtor) : null; } @property void* xgetMembers() nothrow pure { return flags & MIxgetMembers ? *cast(typeof(return)*)addrOf(MIxgetMembers) : null; } @property void function() ctor() nothrow pure { return flags & MIctor ? *cast(typeof(return)*)addrOf(MIctor) : null; } @property void function() dtor() nothrow pure { return flags & MIdtor ? *cast(typeof(return)*)addrOf(MIdtor) : null; } @property void function() ictor() nothrow pure { return flags & MIictor ? *cast(typeof(return)*)addrOf(MIictor) : null; } @property void function() unitTest() nothrow pure { return flags & MIunitTest ? *cast(typeof(return)*)addrOf(MIunitTest) : null; } @property immutable(ModuleInfo*)[] importedModules() nothrow pure { if (flags & MIimportedModules) { auto p = cast(size_t*)addrOf(MIimportedModules); return (cast(immutable(ModuleInfo*)*)(p + 1))[0 .. *p]; } return null; } @property TypeInfo_Class[] localClasses() nothrow pure { if (flags & MIlocalClasses) { auto p = cast(size_t*)addrOf(MIlocalClasses); return (cast(TypeInfo_Class*)(p + 1))[0 .. *p]; } return null; } @property string name() nothrow pure { if (true || flags & MIname) // always available for now { import core.stdc.string : strlen; auto p = cast(immutable char*)addrOf(MIname); return p[0 .. strlen(p)]; } // return null; } static int opApply(scope int delegate(ModuleInfo*) dg) { import core.internal.traits : externDFunc; alias moduleinfos_apply = externDFunc!("rt.minfo.moduleinfos_apply", int function(scope int delegate(immutable(ModuleInfo*)))); // Bugzilla 13084 - enforcing immutable ModuleInfo would break client code return moduleinfos_apply( (immutable(ModuleInfo*)m) => dg(cast(ModuleInfo*)m)); } } unittest { ModuleInfo* m1; foreach (m; ModuleInfo) { m1 = m; } } /////////////////////////////////////////////////////////////////////////////// // Throwable /////////////////////////////////////////////////////////////////////////////// /** * The base class of all thrown objects. * * All thrown objects must inherit from Throwable. Class $(D Exception), which * derives from this class, represents the category of thrown objects that are * safe to catch and handle. In principle, one should not catch Throwable * objects that are not derived from $(D Exception), as they represent * unrecoverable runtime errors. Certain runtime guarantees may fail to hold * when these errors are thrown, making it unsafe to continue execution after * catching them. */ class Throwable : Object { interface TraceInfo { int opApply(scope int delegate(ref const(char[]))) const; int opApply(scope int delegate(ref size_t, ref const(char[]))) const; string toString() const; } string msg; /// A message describing the error. /** * The _file name and line number of the D source code corresponding with * where the error was thrown from. */ string file; size_t line; /// ditto /** * The stack trace of where the error happened. This is an opaque object * that can either be converted to $(D string), or iterated over with $(D * foreach) to extract the items in the stack trace (as strings). */ TraceInfo info; /** * A reference to the _next error in the list. This is used when a new * $(D Throwable) is thrown from inside a $(D catch) block. The originally * caught $(D Exception) will be chained to the new $(D Throwable) via this * field. */ Throwable next; @nogc @safe pure nothrow this(string msg, Throwable next = null) { this.msg = msg; this.next = next; //this.info = _d_traceContext(); } @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable next = null) { this(msg, next); this.file = file; this.line = line; //this.info = _d_traceContext(); } /** * Overrides $(D Object.toString) and returns the error message. * Internally this forwards to the $(D toString) overload that * takes a $(PARAM sink) delegate. */ override string toString() { string s; toString((buf) { s ~= buf; }); return s; } /** * The Throwable hierarchy uses a toString overload that takes a * $(PARAM sink) delegate to avoid GC allocations, which cannot be * performed in certain error situations. Override this $(D * toString) method to customize the error message. */ void toString(scope void delegate(in char[]) sink) const { import core.internal.traits : externDFunc; alias sizeToTempString = externDFunc!("core.internal.string.unsignedToTempString", char[] function(ulong, char[], uint) @safe pure nothrow @nogc); char[20] tmpBuff = void; sink(typeid(this).name); sink("@"); sink(file); sink("("); sink(sizeToTempString(line, tmpBuff, 10)); sink(")"); if (msg.length) { sink(": "); sink(msg); } if (info) { try { sink("\n----------------"); foreach (t; info) { sink("\n"); sink(t); } } catch (Throwable) { // ignore more errors } } } } /** * The base class of all errors that are safe to catch and handle. * * In principle, only thrown objects derived from this class are safe to catch * inside a $(D catch) block. Thrown objects not derived from Exception * represent runtime errors that should not be caught, as certain runtime * guarantees may not hold, making it unsafe to continue program execution. */ class Exception : Throwable { /** * Creates a new instance of Exception. The next parameter is used * internally and should always be $(D null) when passed by user code. * This constructor does not automatically throw the newly-created * Exception; the $(D throw) statement should be used for that purpose. */ @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(msg, file, line, next); } @nogc @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) { super(msg, file, line, next); } } unittest { { auto e = new Exception("msg"); assert(e.file == __FILE__); assert(e.line == __LINE__ - 2); assert(e.next is null); assert(e.msg == "msg"); } { auto e = new Exception("msg", new Exception("It's an Exception!"), "hello", 42); assert(e.file == "hello"); assert(e.line == 42); assert(e.next !is null); assert(e.msg == "msg"); } { auto e = new Exception("msg", "hello", 42, new Exception("It's an Exception!")); assert(e.file == "hello"); assert(e.line == 42); assert(e.next !is null); assert(e.msg == "msg"); } } /** * The base class of all unrecoverable runtime errors. * * This represents the category of $(D Throwable) objects that are $(B not) * safe to catch and handle. In principle, one should not catch Error * objects, as they represent unrecoverable runtime errors. * Certain runtime guarantees may fail to hold when these errors are * thrown, making it unsafe to continue execution after catching them. */ class Error : Throwable { /** * Creates a new instance of Error. The next parameter is used * internally and should always be $(D null) when passed by user code. * This constructor does not automatically throw the newly-created * Error; the $(D throw) statement should be used for that purpose. */ @nogc @safe pure nothrow this(string msg, Throwable next = null) { super(msg, next); bypassedException = null; } @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable next = null) { super(msg, file, line, next); bypassedException = null; } /// The first $(D Exception) which was bypassed when this Error was thrown, /// or $(D null) if no $(D Exception)s were pending. Throwable bypassedException; } unittest { { auto e = new Error("msg"); assert(e.file is null); assert(e.line == 0); assert(e.next is null); assert(e.msg == "msg"); assert(e.bypassedException is null); } { auto e = new Error("msg", new Exception("It's an Exception!")); assert(e.file is null); assert(e.line == 0); assert(e.next !is null); assert(e.msg == "msg"); assert(e.bypassedException is null); } { auto e = new Error("msg", "hello", 42, new Exception("It's an Exception!")); assert(e.file == "hello"); assert(e.line == 42); assert(e.next !is null); assert(e.msg == "msg"); assert(e.bypassedException is null); } } /* Used in Exception Handling LSDA tables to 'wrap' C++ type info * so it can be distinguished from D TypeInfo */ class __cpp_type_info_ptr { void* ptr; // opaque pointer to C++ RTTI type info } extern (C) { // from druntime/src/rt/aaA.d // size_t _aaLen(in void* p) pure nothrow @nogc; private void* _aaGetY(void** paa, const TypeInfo_AssociativeArray ti, in size_t valuesize, in void* pkey) pure nothrow; // inout(void)* _aaGetRvalueX(inout void* p, in TypeInfo keyti, in size_t valuesize, in void* pkey); inout(void)[] _aaValues(inout void* p, in size_t keysize, in size_t valuesize, const TypeInfo tiValArray) pure nothrow; inout(void)[] _aaKeys(inout void* p, in size_t keysize, const TypeInfo tiKeyArray) pure nothrow; void* _aaRehash(void** pp, in TypeInfo keyti) pure nothrow; void _aaClear(void* p) pure nothrow; // alias _dg_t = extern(D) int delegate(void*); // int _aaApply(void* aa, size_t keysize, _dg_t dg); // alias _dg2_t = extern(D) int delegate(void*, void*); // int _aaApply2(void* aa, size_t keysize, _dg2_t dg); private struct AARange { void* impl; size_t idx; } AARange _aaRange(void* aa) pure nothrow @nogc; bool _aaRangeEmpty(AARange r) pure nothrow @nogc; void* _aaRangeFrontKey(AARange r) pure nothrow @nogc; void* _aaRangeFrontValue(AARange r) pure nothrow @nogc; void _aaRangePopFront(ref AARange r) pure nothrow @nogc; int _aaEqual(in TypeInfo tiRaw, in void* e1, in void* e2); hash_t _aaGetHash(in void* aa, in TypeInfo tiRaw) nothrow; /* _d_assocarrayliteralTX marked as pure, because aaLiteral can be called from pure code. This is a typesystem hole, however this is existing hole. Early compiler didn't check purity of toHash or postblit functions, if key is a UDT thus copiler allowed to create AA literal with keys, which have impure unsafe toHash methods. */ void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] values) pure; } void* aaLiteral(Key, Value)(Key[] keys, Value[] values) @trusted pure { return _d_assocarrayliteralTX(typeid(Value[Key]), *cast(void[]*)&keys, *cast(void[]*)&values); } alias AssociativeArray(Key, Value) = Value[Key]; void clear(T : Value[Key], Value, Key)(T aa) { _aaClear(*cast(void **) &aa); } void clear(T : Value[Key], Value, Key)(T* aa) { _aaClear(*cast(void **) aa); } T rehash(T : Value[Key], Value, Key)(T aa) { _aaRehash(cast(void**)&aa, typeid(Value[Key])); return aa; } T rehash(T : Value[Key], Value, Key)(T* aa) { _aaRehash(cast(void**)aa, typeid(Value[Key])); return *aa; } T rehash(T : shared Value[Key], Value, Key)(T aa) { _aaRehash(cast(void**)&aa, typeid(Value[Key])); return aa; } T rehash(T : shared Value[Key], Value, Key)(T* aa) { _aaRehash(cast(void**)aa, typeid(Value[Key])); return *aa; } V[K] dup(T : V[K], K, V)(T aa) { //pragma(msg, "K = ", K, ", V = ", V); // Bug10720 - check whether V is copyable static assert(is(typeof({ V v = aa[K.init]; })), "cannot call " ~ T.stringof ~ ".dup because " ~ V.stringof ~ " is not copyable"); V[K] result; //foreach (k, ref v; aa) // result[k] = v; // Bug13701 - won't work if V is not mutable ref V duplicateElem(ref K k, ref const V v) @trusted pure nothrow { import core.stdc.string : memcpy; void* pv = _aaGetY(cast(void**)&result, typeid(V[K]), V.sizeof, &k); memcpy(pv, &v, V.sizeof); return *cast(V*)pv; } if (auto postblit = _getPostblit!V()) { foreach (k, ref v; aa) postblit(duplicateElem(k, v)); } else { foreach (k, ref v; aa) duplicateElem(k, v); } return result; } V[K] dup(T : V[K], K, V)(T* aa) { return (*aa).dup; } auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc { import core.internal.traits : substInout; static struct Result { AARange r; pure nothrow @nogc: @property bool empty() { return _aaRangeEmpty(r); } @property ref front() { return *cast(substInout!K*)_aaRangeFrontKey(r); } void popFront() { _aaRangePopFront(r); } @property Result save() { return this; } } return Result(_aaRange(cast(void*)aa)); } auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc { return (*aa).byKey(); } auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc { import core.internal.traits : substInout; static struct Result { AARange r; pure nothrow @nogc: @property bool empty() { return _aaRangeEmpty(r); } @property ref front() { return *cast(substInout!V*)_aaRangeFrontValue(r); } void popFront() { _aaRangePopFront(r); } @property Result save() { return this; } } return Result(_aaRange(cast(void*)aa)); } auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc { return (*aa).byValue(); } auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc { import core.internal.traits : substInout; static struct Result { AARange r; pure nothrow @nogc: @property bool empty() { return _aaRangeEmpty(r); } @property auto front() @trusted { static struct Pair { // We save the pointers here so that the Pair we return // won't mutate when Result.popFront is called afterwards. private void* keyp; private void* valp; @property ref key() inout { return *cast(substInout!K*)keyp; } @property ref value() inout { return *cast(substInout!V*)valp; } } return Pair(_aaRangeFrontKey(r), _aaRangeFrontValue(r)); } void popFront() { _aaRangePopFront(r); } @property Result save() { return this; } } return Result(_aaRange(cast(void*)aa)); } auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc { return (*aa).byKeyValue(); } Key[] keys(T : Value[Key], Value, Key)(T aa) @property { auto a = cast(void[])_aaKeys(cast(inout(void)*)aa, Key.sizeof, typeid(Key[])); auto res = *cast(Key[]*)&a; _doPostblit(res); return res; } Key[] keys(T : Value[Key], Value, Key)(T *aa) @property { return (*aa).keys; } Value[] values(T : Value[Key], Value, Key)(T aa) @property { auto a = cast(void[])_aaValues(cast(inout(void)*)aa, Key.sizeof, Value.sizeof, typeid(Value[])); auto res = *cast(Value[]*)&a; _doPostblit(res); return res; } Value[] values(T : Value[Key], Value, Key)(T *aa) @property { return (*aa).values; } unittest { static struct T { static size_t count; this(this) { ++count; } } T[int] aa; T t; aa[0] = t; aa[1] = t; assert(T.count == 2); auto vals = aa.values; assert(vals.length == 2); assert(T.count == 4); T.count = 0; int[T] aa2; aa2[t] = 0; assert(T.count == 1); aa2[t] = 1; assert(T.count == 1); auto keys = aa2.keys; assert(keys.length == 1); assert(T.count == 2); } inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue) { auto p = key in aa; return p ? *p : defaultValue; } inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue) { return (*aa).get(key, defaultValue); } pure nothrow unittest { int[int] a; foreach (i; a.byKey) { assert(false); } foreach (i; a.byValue) { assert(false); } } version (LDC) {} else pure /*nothrow @@@BUG5555@@@*/ unittest { auto a = [ 1:"one", 2:"two", 3:"three" ]; auto b = a.dup; assert(b == [ 1:"one", 2:"two", 3:"three" ]); int[] c; foreach (k; a.byKey) { c ~= k; } assert(c.length == 3); assert(c[0] == 1 || c[1] == 1 || c[2] == 1); assert(c[0] == 2 || c[1] == 2 || c[2] == 2); assert(c[0] == 3 || c[1] == 3 || c[2] == 3); } pure nothrow unittest { // test for bug 5925 const a = [4:0]; const b = [4:0]; assert(a == b); } pure nothrow unittest { // test for bug 9052 static struct Json { Json[string] aa; void opAssign(Json) {} size_t length() const { return aa.length; } // This length() instantiates AssociativeArray!(string, const(Json)) to call AA.length(), and // inside ref Slot opAssign(Slot p); (which is automatically generated by compiler in Slot), // this.value = p.value would actually fail, because both side types of the assignment // are const(Json). } } pure nothrow unittest { // test for bug 8583: ensure Slot and aaA are on the same page wrt value alignment string[byte] aa0 = [0: "zero"]; string[uint[3]] aa1 = [[1,2,3]: "onetwothree"]; ushort[uint[3]] aa2 = [[9,8,7]: 987]; ushort[uint[4]] aa3 = [[1,2,3,4]: 1234]; string[uint[5]] aa4 = [[1,2,3,4,5]: "onetwothreefourfive"]; assert(aa0.byValue.front == "zero"); assert(aa1.byValue.front == "onetwothree"); assert(aa2.byValue.front == 987); assert(aa3.byValue.front == 1234); assert(aa4.byValue.front == "onetwothreefourfive"); } pure nothrow unittest { // test for bug 10720 static struct NC { @disable this(this) { } } NC[string] aa; static assert(!is(aa.nonExistingField)); } pure nothrow unittest { // bug 5842 string[string] test = null; test["test1"] = "test1"; test.remove("test1"); test.rehash; test["test3"] = "test3"; // causes divide by zero if rehash broke the AA } pure nothrow unittest { string[] keys = ["a", "b", "c", "d", "e", "f"]; // Test forward range capabilities of byKey { int[string] aa; foreach (key; keys) aa[key] = 0; auto keyRange = aa.byKey(); auto savedKeyRange = keyRange.save; // Consume key range once size_t keyCount = 0; while (!keyRange.empty) { aa[keyRange.front]++; keyCount++; keyRange.popFront(); } foreach (key; keys) { assert(aa[key] == 1); } assert(keyCount == keys.length); // Verify it's possible to iterate the range the second time keyCount = 0; while (!savedKeyRange.empty) { aa[savedKeyRange.front]++; keyCount++; savedKeyRange.popFront(); } foreach (key; keys) { assert(aa[key] == 2); } assert(keyCount == keys.length); } // Test forward range capabilities of byValue { size_t[string] aa; foreach (i; 0 .. keys.length) { aa[keys[i]] = i; } auto valRange = aa.byValue(); auto savedValRange = valRange.save; // Consume value range once int[] hasSeen; hasSeen.length = keys.length; while (!valRange.empty) { assert(hasSeen[valRange.front] == 0); hasSeen[valRange.front]++; valRange.popFront(); } foreach (sawValue; hasSeen) { assert(sawValue == 1); } // Verify it's possible to iterate the range the second time hasSeen = null; hasSeen.length = keys.length; while (!savedValRange.empty) { assert(!hasSeen[savedValRange.front]); hasSeen[savedValRange.front] = true; savedValRange.popFront(); } foreach (sawValue; hasSeen) { assert(sawValue); } } } pure nothrow unittest { // expanded test for 5842: increase AA size past the point where the AA // stops using binit, in order to test another code path in rehash. int[int] aa; foreach (int i; 0 .. 32) aa[i] = i; foreach (int i; 0 .. 32) aa.remove(i); aa.rehash; aa[1] = 1; } pure nothrow unittest { // bug 13078 shared string[][string] map; map.rehash; } pure nothrow unittest { // bug 11761: test forward range functionality auto aa = ["a": 1]; void testFwdRange(R, T)(R fwdRange, T testValue) { assert(!fwdRange.empty); assert(fwdRange.front == testValue); static assert(is(typeof(fwdRange.save) == typeof(fwdRange))); auto saved = fwdRange.save; fwdRange.popFront(); assert(fwdRange.empty); assert(!saved.empty); assert(saved.front == testValue); saved.popFront(); assert(saved.empty); } testFwdRange(aa.byKey, "a"); testFwdRange(aa.byValue, 1); //testFwdRange(aa.byPair, tuple("a", 1)); } unittest { // Issue 9119 int[string] aa; assert(aa.byKeyValue.empty); aa["a"] = 1; aa["b"] = 2; aa["c"] = 3; auto pairs = aa.byKeyValue; auto savedPairs = pairs.save; size_t count = 0; while (!pairs.empty) { assert(pairs.front.key in aa); assert(pairs.front.value == aa[pairs.front.key]); count++; pairs.popFront(); } assert(count == aa.length); // Verify that saved range can iterate over the AA again count = 0; while (!savedPairs.empty) { assert(savedPairs.front.key in aa); assert(savedPairs.front.value == aa[savedPairs.front.key]); count++; savedPairs.popFront(); } assert(count == aa.length); } unittest { // Verify iteration with const. auto aa = [1:2, 3:4]; foreach (const t; aa.byKeyValue) { auto k = t.key; auto v = t.value; } } unittest { // test for bug 14626 static struct S { string[string] aa; inout(string) key() inout { return aa.byKey().front; } inout(string) val() inout { return aa.byValue().front; } auto keyval() inout { return aa.byKeyValue().front; } } S s = S(["a":"b"]); assert(s.key() == "a"); assert(s.val() == "b"); assert(s.keyval().key == "a"); assert(s.keyval().value == "b"); void testInoutKeyVal(inout(string) key) { inout(string)[typeof(key)] aa; foreach (i; aa.byKey()) {} foreach (i; aa.byValue()) {} foreach (i; aa.byKeyValue()) {} } const int[int] caa; static assert(is(typeof(caa.byValue().front) == const int)); } private void _destructRecurse(S)(ref S s) if (is(S == struct)) { static if (__traits(hasMember, S, "__xdtor") && // Bugzilla 14746: Check that it's the exact member of S. __traits(isSame, S, __traits(parent, s.__xdtor))) s.__xdtor(); } private void _destructRecurse(E, size_t n)(ref E[n] arr) { import core.internal.traits : hasElaborateDestructor; static if (hasElaborateDestructor!E) { foreach_reverse (ref elem; arr) _destructRecurse(elem); } } // Public and explicitly undocumented void _postblitRecurse(S)(ref S s) if (is(S == struct)) { static if (__traits(hasMember, S, "__xpostblit") && // Bugzilla 14746: Check that it's the exact member of S. __traits(isSame, S, __traits(parent, s.__xpostblit))) s.__xpostblit(); } // Ditto void _postblitRecurse(E, size_t n)(ref E[n] arr) { import core.internal.traits : hasElaborateCopyConstructor; static if (hasElaborateCopyConstructor!E) { size_t i; scope(failure) { for (; i != 0; --i) { _destructRecurse(arr[i - 1]); // What to do if this throws? } } for (i = 0; i < arr.length; ++i) _postblitRecurse(arr[i]); } } // Test destruction/postblit order @safe nothrow pure unittest { string[] order; struct InnerTop { ~this() @safe nothrow pure { order ~= "destroy inner top"; } this(this) @safe nothrow pure { order ~= "copy inner top"; } } struct InnerMiddle {} version(none) // @@@BUG@@@ 14242 struct InnerElement { static char counter = '1'; ~this() @safe nothrow pure { order ~= "destroy inner element #" ~ counter++; } this(this) @safe nothrow pure { order ~= "copy inner element #" ~ counter++; } } struct InnerBottom { ~this() @safe nothrow pure { order ~= "destroy inner bottom"; } this(this) @safe nothrow pure { order ~= "copy inner bottom"; } } struct S { char[] s; InnerTop top; InnerMiddle middle; version(none) InnerElement[3] array; // @@@BUG@@@ 14242 int a; InnerBottom bottom; ~this() @safe nothrow pure { order ~= "destroy outer"; } this(this) @safe nothrow pure { order ~= "copy outer"; } } string[] destructRecurseOrder; { S s; _destructRecurse(s); destructRecurseOrder = order; order = null; } assert(order.length); assert(destructRecurseOrder == order); order = null; S s; _postblitRecurse(s); assert(order.length); auto postblitRecurseOrder = order; order = null; S s2 = s; assert(order.length); assert(postblitRecurseOrder == order); } // Test static struct nothrow @safe @nogc unittest { static int i = 0; static struct S { ~this() nothrow @safe @nogc { i = 42; } } S s; _destructRecurse(s); assert(i == 42); } unittest { // Bugzilla 14746 static struct HasDtor { ~this() { assert(0); } } static struct Owner { HasDtor* ptr; alias ptr this; } Owner o; assert(o.ptr is null); destroy(o); // must not reach in HasDtor.__dtor() } unittest { // Bugzilla 14746 static struct HasPostblit { this(this) { assert(0); } } static struct Owner { HasPostblit* ptr; alias ptr this; } Owner o; assert(o.ptr is null); _postblitRecurse(o); // must not reach in HasPostblit.__postblit() } // Test handling of fixed-length arrays // Separate from first test because of @@@BUG@@@ 14242 unittest { string[] order; struct S { char id; this(this) { order ~= "copy #" ~ id; } ~this() { order ~= "destroy #" ~ id; } } string[] destructRecurseOrder; { S[3] arr = [S('1'), S('2'), S('3')]; _destructRecurse(arr); destructRecurseOrder = order; order = null; } assert(order.length); assert(destructRecurseOrder == order); order = null; S[3] arr = [S('1'), S('2'), S('3')]; _postblitRecurse(arr); assert(order.length); auto postblitRecurseOrder = order; order = null; auto arrCopy = arr; assert(order.length); assert(postblitRecurseOrder == order); } // Test handling of failed postblit // Not nothrow or @safe because of @@@BUG@@@ 14242 /+ nothrow @safe +/ unittest { static class FailedPostblitException : Exception { this() nothrow @safe { super(null); } } static string[] order; static struct Inner { char id; @safe: this(this) { order ~= "copy inner #" ~ id; if(id == '2') throw new FailedPostblitException(); } ~this() nothrow { order ~= "destroy inner #" ~ id; } } static struct Outer { Inner inner1, inner2, inner3; nothrow @safe: this(char first, char second, char third) { inner1 = Inner(first); inner2 = Inner(second); inner3 = Inner(third); } this(this) { order ~= "copy outer"; } ~this() { order ~= "destroy outer"; } } auto outer = Outer('1', '2', '3'); try _postblitRecurse(outer); catch(FailedPostblitException) {} catch(Exception) assert(false); auto postblitRecurseOrder = order; order = null; try auto copy = outer; catch(FailedPostblitException) {} catch(Exception) assert(false); assert(postblitRecurseOrder == order); order = null; Outer[3] arr = [Outer('1', '1', '1'), Outer('1', '2', '3'), Outer('3', '3', '3')]; try _postblitRecurse(arr); catch(FailedPostblitException) {} catch(Exception) assert(false); postblitRecurseOrder = order; order = null; try auto arrCopy = arr; catch(FailedPostblitException) {} catch(Exception) assert(false); assert(postblitRecurseOrder == order); } /++ Destroys the given object and puts it in an invalid state. It's used to destroy an object so that any cleanup which its destructor or finalizer does is done and so that it no longer references any other objects. It does $(I not) initiate a GC cycle or free any GC memory. +/ void destroy(T)(T obj) if (is(T == class)) { rt_finalize(cast(void*)obj); } void destroy(T)(T obj) if (is(T == interface)) { destroy(cast(Object)obj); } version(unittest) unittest { interface I { } { class A: I { string s = "A"; this() {} } auto a = new A, b = new A; a.s = b.s = "asd"; destroy(a); assert(a.s == "A"); I i = b; destroy(i); assert(b.s == "A"); } { static bool destroyed = false; class B: I { string s = "B"; this() {} ~this() { destroyed = true; } } auto a = new B, b = new B; a.s = b.s = "asd"; destroy(a); assert(destroyed); assert(a.s == "B"); destroyed = false; I i = b; destroy(i); assert(destroyed); assert(b.s == "B"); } // this test is invalid now that the default ctor is not run after clearing version(none) { class C { string s; this() { s = "C"; } } auto a = new C; a.s = "asd"; destroy(a); assert(a.s == "C"); } } void destroy(T)(ref T obj) if (is(T == struct)) { _destructRecurse(obj); () @trusted { auto buf = (cast(ubyte*) &obj)[0 .. T.sizeof]; auto init = cast(ubyte[])typeid(T).initializer(); if (init.ptr is null) // null ptr means initialize to 0s buf[] = 0; else buf[] = init[]; } (); } version(unittest) nothrow @safe @nogc unittest { { struct A { string s = "A"; } A a; a.s = "asd"; destroy(a); assert(a.s == "A"); } { static int destroyed = 0; struct C { string s = "C"; ~this() nothrow @safe @nogc { destroyed ++; } } struct B { C c; string s = "B"; ~this() nothrow @safe @nogc { destroyed ++; } } B a; a.s = "asd"; a.c.s = "jkl"; destroy(a); assert(destroyed == 2); assert(a.s == "B"); assert(a.c.s == "C" ); } } void destroy(T : U[n], U, size_t n)(ref T obj) if (!is(T == struct)) { foreach_reverse (ref e; obj[]) destroy(e); } version(unittest) unittest { int[2] a; a[0] = 1; a[1] = 2; destroy(a); assert(a == [ 0, 0 ]); } unittest { static struct vec2f { float[2] values; alias values this; } vec2f v; destroy!vec2f(v); } unittest { // Bugzilla 15009 static string op; static struct S { int x; this(int x) { op ~= "C" ~ cast(char)('0'+x); this.x = x; } this(this) { op ~= "P" ~ cast(char)('0'+x); } ~this() { op ~= "D" ~ cast(char)('0'+x); } } { S[2] a1 = [S(1), S(2)]; op = ""; } assert(op == "D2D1"); // built-in scope destruction { S[2] a1 = [S(1), S(2)]; op = ""; destroy(a1); assert(op == "D2D1"); // consistent with built-in behavior } { S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]]; op = ""; } assert(op == "D4D3D2D1"); { S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]]; op = ""; destroy(a2); assert(op == "D4D3D2D1", op); } } void destroy(T)(ref T obj) if (!is(T == struct) && !is(T == interface) && !is(T == class) && !_isStaticArray!T) { obj = T.init; } template _isStaticArray(T : U[N], U, size_t N) { enum bool _isStaticArray = true; } template _isStaticArray(T) { enum bool _isStaticArray = false; } version(unittest) unittest { { int a = 42; destroy(a); assert(a == 0); } { float a = 42; destroy(a); assert(isnan(a)); } } version (unittest) { bool isnan(float x) { return x != x; } } private { extern (C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow; extern (C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* arrptr) pure nothrow; } /** * (Property) Get the current capacity of a slice. The capacity is the size * that the slice can grow to before the underlying array must be * reallocated or extended. * * If an append must reallocate a slice with no possibility of extension, then * 0 is returned. This happens when the slice references a static array, or * if another slice references elements past the end of the current slice. * * Note: The capacity of a slice may be impacted by operations on other slices. */ @property size_t capacity(T)(T[] arr) pure nothrow { return _d_arraysetcapacity(typeid(T[]), 0, cast(void[]*)&arr); } /// unittest { //Static array slice: no capacity int[4] sarray = [1, 2, 3, 4]; int[] slice = sarray[]; assert(sarray.capacity == 0); //Appending to slice will reallocate to a new array slice ~= 5; assert(slice.capacity >= 5); //Dynamic array slices int[] a = [1, 2, 3, 4]; int[] b = a[1 .. $]; int[] c = a[1 .. $ - 1]; debug(SENTINEL) {} else // non-zero capacity very much depends on the array and GC implementation { assert(a.capacity != 0); assert(a.capacity == b.capacity + 1); //both a and b share the same tail } assert(c.capacity == 0); //an append to c must relocate c. } /** * Reserves capacity for a slice. The capacity is the size * that the slice can grow to before the underlying array must be * reallocated or extended. * * The return value is the new capacity of the array (which may be larger than * the requested capacity). */ size_t reserve(T)(ref T[] arr, size_t newcapacity) pure nothrow @trusted { return _d_arraysetcapacity(typeid(T[]), newcapacity, cast(void[]*)&arr); } /// unittest { //Static array slice: no capacity. Reserve relocates. int[4] sarray = [1, 2, 3, 4]; int[] slice = sarray[]; auto u = slice.reserve(8); assert(u >= 8); assert(sarray.ptr !is slice.ptr); assert(slice.capacity == u); //Dynamic array slices int[] a = [1, 2, 3, 4]; a.reserve(8); //prepare a for appending 4 more items auto p = a.ptr; u = a.capacity; a ~= [5, 6, 7, 8]; assert(p == a.ptr); //a should not have been reallocated assert(u == a.capacity); //a should not have been extended } // Issue 6646: should be possible to use array.reserve from SafeD. @safe unittest { int[] a; a.reserve(10); } /** * Assume that it is safe to append to this array. Appends made to this array * after calling this function may append in place, even if the array was a * slice of a larger array to begin with. * * Use this only when it is certain there are no elements in use beyond the * array in the memory block. If there are, those elements will be * overwritten by appending to this array. * * Calling this function, and then using references to data located after the * given array results in undefined behavior. * * Returns: * The input is returned. */ auto ref inout(T[]) assumeSafeAppend(T)(auto ref inout(T[]) arr) nothrow { _d_arrayshrinkfit(typeid(T[]), *(cast(void[]*)&arr)); return arr; } /// unittest { int[] a = [1, 2, 3, 4]; // Without assumeSafeAppend. Appending relocates. int[] b = a [0 .. 3]; b ~= 5; assert(a.ptr != b.ptr); debug(SENTINEL) {} else { // With assumeSafeAppend. Appending overwrites. int[] c = a [0 .. 3]; c.assumeSafeAppend() ~= 5; assert(a.ptr == c.ptr); } } unittest { int[] arr; auto newcap = arr.reserve(2000); assert(newcap >= 2000); assert(newcap == arr.capacity); auto ptr = arr.ptr; foreach(i; 0..2000) arr ~= i; assert(ptr == arr.ptr); arr = arr[0..1]; arr.assumeSafeAppend(); arr ~= 5; assert(ptr == arr.ptr); } unittest { int[] arr = [1, 2, 3]; void foo(ref int[] i) { i ~= 5; } arr = arr[0 .. 2]; foo(assumeSafeAppend(arr)); //pass by ref assert(arr[]==[1, 2, 5]); arr = arr[0 .. 1].assumeSafeAppend(); //pass by value } //@@@10574@@@ unittest { int[] a; immutable(int[]) b; auto a2 = &assumeSafeAppend(a); auto b2 = &assumeSafeAppend(b); auto a3 = assumeSafeAppend(a[]); auto b3 = assumeSafeAppend(b[]); assert(is(typeof(*a2) == int[])); assert(is(typeof(*b2) == immutable(int[]))); assert(is(typeof(a3) == int[])); assert(is(typeof(b3) == immutable(int[]))); } version (none) { // enforce() copied from Phobos std.contracts for destroy(), left out until // we decide whether to use it. T _enforce(T, string file = __FILE__, int line = __LINE__) (T value, lazy const(char)[] msg = null) { if (!value) bailOut(file, line, msg); return value; } T _enforce(T, string file = __FILE__, int line = __LINE__) (T value, scope void delegate() dg) { if (!value) dg(); return value; } T _enforce(T)(T value, lazy Exception ex) { if (!value) throw ex(); return value; } private void _bailOut(string file, int line, in char[] msg) { char[21] buf; throw new Exception(cast(string)(file ~ "(" ~ ulongToString(buf[], line) ~ "): " ~ (msg ? msg : "Enforcement failed"))); } } /*************************************** * Helper function used to see if two containers of different * types have the same contents in the same sequence. */ bool _ArrayEq(T1, T2)(T1[] a1, T2[] a2) { if (a1.length != a2.length) return false; foreach(i, a; a1) { if (a != a2[i]) return false; } return true; } /** Calculates the hash value of $(D arg) with $(D seed) initial value. Result may be non-equals with `typeid(T).getHash(&arg)` The $(D seed) value may be used for hash chaining: ---- struct Test { int a; string b; MyObject c; size_t toHash() const @safe pure nothrow { size_t hash = a.hashOf(); hash = b.hashOf(hash); size_t h1 = c.myMegaHash(); hash = h1.hashOf(hash); //Mix two hash values return hash; } } ---- */ size_t hashOf(T)(auto ref T arg, size_t seed = 0) { import core.internal.hash; return core.internal.hash.hashOf(arg, seed); } bool _xopEquals(in void*, in void*) { throw new Error("TypeInfo.equals is not implemented"); } bool _xopCmp(in void*, in void*) { throw new Error("TypeInfo.compare is not implemented"); } void __ctfeWrite(T...)(auto ref T) {} void __ctfeWriteln(T...)(auto ref T values) { __ctfeWrite(values, "\n"); } /****************************************** * Create RTInfo for type T */ template RTInfo(T) { enum RTInfo = null; } // Helper functions private inout(TypeInfo) getElement(inout TypeInfo value) @trusted pure nothrow { TypeInfo element = cast() value; for(;;) { if(auto qualified = cast(TypeInfo_Const) element) element = qualified.base; else if(auto redefined = cast(TypeInfo_Typedef) element) // typedef & enum element = redefined.base; else if(auto staticArray = cast(TypeInfo_StaticArray) element) element = staticArray.value; else if(auto vector = cast(TypeInfo_Vector) element) element = vector.base; else break; } return cast(inout) element; } private size_t getArrayHash(in TypeInfo element, in void* ptr, in size_t count) @trusted nothrow { if(!count) return 0; const size_t elementSize = element.tsize; if(!elementSize) return 0; static bool hasCustomToHash(in TypeInfo value) @trusted pure nothrow { const element = getElement(value); if(const struct_ = cast(const TypeInfo_Struct) element) return !!struct_.xtoHash; return cast(const TypeInfo_Array) element || cast(const TypeInfo_AssociativeArray) element || cast(const ClassInfo) element || cast(const TypeInfo_Interface) element; } import core.internal.traits : externDFunc; alias hashOf = externDFunc!("rt.util.hash.hashOf", size_t function(const(void)*, size_t, size_t) @trusted pure nothrow); if(!hasCustomToHash(element)) return hashOf(ptr, elementSize * count, 0); size_t hash = 0; foreach(size_t i; 0 .. count) hash += element.getHash(ptr + i * elementSize); return hash; } // @@@BUG5835@@@ tests: unittest { class C { int i; this(in int i) { this.i = i; } override hash_t toHash() { return 0; } } C[] a1 = [new C(11)], a2 = [new C(12)]; assert(typeid(C[]).getHash(&a1) == typeid(C[]).getHash(&a2)); // fails } unittest { struct S { int i; hash_t toHash() const @safe nothrow { return 0; } } S[] a1 = [S(11)], a2 = [S(12)]; assert(typeid(S[]).getHash(&a1) == typeid(S[]).getHash(&a2)); // fails } @safe unittest { struct S { int i; const @safe nothrow: hash_t toHash() { return 0; } bool opEquals(const S) { return true; } int opCmp(const S) { return 0; } } int[S[]] aa = [[S(11)] : 13]; assert(aa[[S(12)]] == 13); // fails } /// Provide the .dup array property. @property auto dup(T)(T[] a) if (!is(const(T) : T)) { import core.internal.traits : Unconst; static assert(is(T : Unconst!T), "Cannot implicitly convert type "~T.stringof~ " to "~Unconst!T.stringof~" in dup."); // wrap unsafe _dup in @trusted to preserve @safe postblit static if (__traits(compiles, (T b) @safe { T a = b; })) return _trustedDup!(T, Unconst!T)(a); else return _dup!(T, Unconst!T)(a); } /// ditto // const overload to support implicit conversion to immutable (unique result, see DIP29) @property T[] dup(T)(const(T)[] a) if (is(const(T) : T)) { // wrap unsafe _dup in @trusted to preserve @safe postblit static if (__traits(compiles, (T b) @safe { T a = b; })) return _trustedDup!(const(T), T)(a); else return _dup!(const(T), T)(a); } /// ditto @property T[] dup(T:void)(const(T)[] a) @trusted { if (__ctfe) assert(0, "Cannot dup a void[] array at compile time."); return cast(T[])_rawDup(a); } /// Provide the .idup array property. @property immutable(T)[] idup(T)(T[] a) { static assert(is(T : immutable(T)), "Cannot implicitly convert type "~T.stringof~ " to immutable in idup."); // wrap unsafe _dup in @trusted to preserve @safe postblit static if (__traits(compiles, (T b) @safe { T a = b; })) return _trustedDup!(T, immutable(T))(a); else return _dup!(T, immutable(T))(a); } /// ditto @property immutable(T)[] idup(T:void)(const(T)[] a) { return a.dup; } private U[] _trustedDup(T, U)(T[] a) @trusted { return _dup!(T, U)(a); } private U[] _dup(T, U)(T[] a) // pure nothrow depends on postblit { if (__ctfe) { U[] res; foreach (ref e; a) res ~= e; return res; } a = _rawDup(a); auto res = *cast(typeof(return)*)&a; _doPostblit(res); return res; } private extern (C) void[] _d_newarrayU(const TypeInfo ti, size_t length) pure nothrow; private inout(T)[] _rawDup(T)(inout(T)[] a) { import core.stdc.string : memcpy; void[] arr = _d_newarrayU(typeid(T[]), a.length); memcpy(arr.ptr, cast(void*)a.ptr, T.sizeof * a.length); return *cast(inout(T)[]*)&arr; } private template _PostBlitType(T) { // assume that ref T and void* are equivalent in abi level. static if (is(T == struct)) alias _PostBlitType = typeof(function (ref T t){ T a = t; }); else alias _PostBlitType = typeof(delegate (ref T t){ T a = t; }); } // Returns null, or a delegate to call postblit of T private auto _getPostblit(T)() @trusted pure nothrow @nogc { // infer static postblit type, run postblit if any static if (is(T == struct)) { import core.internal.traits : Unqual; // use typeid(Unqual!T) here to skip TypeInfo_Const/Shared/... return cast(_PostBlitType!T)typeid(Unqual!T).xpostblit; } else if ((&typeid(T).postblit).funcptr !is &TypeInfo.postblit) { return cast(_PostBlitType!T)&typeid(T).postblit; } else return null; } private void _doPostblit(T)(T[] arr) { // infer static postblit type, run postblit if any if (auto postblit = _getPostblit!T()) { foreach (ref elem; arr) postblit(elem); } } unittest { static struct S1 { int* p; } static struct S2 { @disable this(); } static struct S3 { @disable this(this); } int dg1() pure nothrow @safe { { char[] m; string i; m = m.dup; i = i.idup; m = i.dup; i = m.idup; } { S1[] m; immutable(S1)[] i; m = m.dup; i = i.idup; static assert(!is(typeof(m.idup))); static assert(!is(typeof(i.dup))); } { S3[] m; immutable(S3)[] i; static assert(!is(typeof(m.dup))); static assert(!is(typeof(i.idup))); } { shared(S1)[] m; m = m.dup; static assert(!is(typeof(m.idup))); } { int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0); } return 1; } int dg2() pure nothrow @safe { { S2[] m = [S2.init, S2.init]; immutable(S2)[] i = [S2.init, S2.init]; m = m.dup; m = i.dup; i = m.idup; i = i.idup; } return 2; } enum a = dg1(); enum b = dg2(); assert(dg1() == a); assert(dg2() == b); } unittest { static struct Sunpure { this(this) @safe nothrow {} } static struct Sthrow { this(this) @safe pure {} } static struct Sunsafe { this(this) @system pure nothrow {} } static assert( __traits(compiles, () { [].dup!Sunpure; })); static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); static assert( __traits(compiles, () { [].dup!Sthrow; })); static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); static assert( __traits(compiles, () { [].dup!Sunsafe; })); static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); static assert( __traits(compiles, () { [].idup!Sunpure; })); static assert(!__traits(compiles, () pure { [].idup!Sunpure; })); static assert( __traits(compiles, () { [].idup!Sthrow; })); static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; })); static assert( __traits(compiles, () { [].idup!Sunsafe; })); static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; })); } unittest { static int*[] pureFoo() pure { return null; } { char[] s; immutable x = s.dup; } { immutable x = (cast(int*[])null).dup; } { immutable x = pureFoo(); } { immutable x = pureFoo().dup; } } unittest { auto a = [1, 2, 3]; auto b = a.dup; debug(SENTINEL) {} else assert(b.capacity >= 3); } unittest { // Bugzilla 12580 void[] m = [0]; shared(void)[] s = [cast(shared)1]; immutable(void)[] i = [cast(immutable)2]; s = s.dup; static assert(is(typeof(s.dup) == shared(void)[])); m = i.dup; i = m.dup; i = i.idup; i = m.idup; i = s.idup; i = s.dup; static assert(!__traits(compiles, m = s.dup)); } unittest { // Bugzilla 13809 static struct S { this(this) {} ~this() {} } S[] arr; auto a = arr.dup; } ldc-1.1.0-beta3-src/runtime/druntime/src/gc/0000775000175000017500000000000012776214756016643 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/gc/config.d0000664000175000017500000001723312776214756020263 0ustar kaikai/** * Contains the garbage collector configuration. * * Copyright: Copyright Digital Mars 2014 * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). */ module gc.config; import core.stdc.stdlib; import core.stdc.stdio; import core.stdc.ctype; import core.stdc.string; import core.vararg; nothrow @nogc: extern extern(C) string[] rt_args(); extern extern(C) __gshared bool rt_envvars_enabled; extern extern(C) __gshared bool rt_cmdline_enabled; extern extern(C) __gshared string[] rt_options; struct Config { bool disable; // start disabled ubyte profile; // enable profiling with summary when terminating program bool precise; // enable precise scanning bool concurrent; // enable concurrent collection size_t initReserve; // initial reserve (MB) size_t minPoolSize = 1; // initial and minimum pool size (MB) size_t maxPoolSize = 64; // maximum pool size (MB) size_t incPoolSize = 3; // pool size increment (MB) float heapSizeFactor = 2.0; // heap size to used memory ratio @nogc nothrow: bool initialize() { import core.internal.traits : externDFunc; alias rt_configCallBack = string delegate(string) @nogc nothrow; alias fn_configOption = string function(string opt, scope rt_configCallBack dg, bool reverse) @nogc nothrow; alias rt_configOption = externDFunc!("rt.config.rt_configOption", fn_configOption); string parse(string opt) @nogc nothrow { if (!parseOptions(opt)) return "err"; return null; // continue processing } string s = rt_configOption("gcopt", &parse, true); return s is null; } void help() { version (unittest) if (inUnittest) return; string s = "GC options are specified as white space separated assignments: disable:0|1 - start disabled (%d) profile:0|1|2 - enable profiling with summary when terminating program (%d) precise:0|1 - enable precise scanning (not implemented yet) concurrent:0|1 - enable concurrent collection (not implemented yet) initReserve:N - initial memory to reserve in MB (%lld) minPoolSize:N - initial and minimum pool size in MB (%lld) maxPoolSize:N - maximum pool size in MB (%lld) incPoolSize:N - pool size increment MB (%lld) heapSizeFactor:N - targeted heap size to used memory ratio (%g) "; printf(s.ptr, disable, profile, cast(long)initReserve, cast(long)minPoolSize, cast(long)maxPoolSize, cast(long)incPoolSize, heapSizeFactor); } bool parseOptions(const(char)[] opt) { opt = skip!isspace(opt); while (opt.length) { auto tail = find!(c => c == ':' || c == '=' || c == ' ')(opt); auto name = opt[0 .. $ - tail.length]; if (name == "help") { help(); opt = skip!isspace(tail); continue; } if (tail.length <= 1 || tail[0] == ' ') return optError("Missing argument for", name); tail = tail[1 .. $]; switch (name) { foreach (field; __traits(allMembers, Config)) { static if (!is(typeof(__traits(getMember, this, field)) == function)) { case field: if (!parse(name, tail, __traits(getMember, this, field))) return false; break; } } break; default: return optError("Unknown", name); } opt = skip!isspace(tail); } return true; } } private: bool optError(in char[] msg, in char[] name) { version (unittest) if (inUnittest) return false; fprintf(stderr, "%.*s GC option '%.*s'.\n", cast(int)msg.length, msg.ptr, cast(int)name.length, name.ptr); return false; } inout(char)[] skip(alias pred)(inout(char)[] str) { return find!(c => !pred(c))(str); } inout(char)[] find(alias pred)(inout(char)[] str) { foreach (i; 0 .. str.length) if (pred(str[i])) return str[i .. $]; return null; } bool parse(T:size_t)(const(char)[] optname, ref const(char)[] str, ref T res) in { assert(str.length); } body { size_t i, v; for (; i < str.length && isdigit(str[i]); ++i) v = 10 * v + str[i] - '0'; if (!i) return parseError("a number", optname, str); if (v > res.max) return parseError("a number " ~ T.max.stringof ~ " or below", optname, str[0 .. i]); str = str[i .. $]; res = cast(T) v; return true; } bool parse(T:bool)(const(char)[] optname, ref const(char)[] str, ref T res) in { assert(str.length); } body { if (str[0] == '1' || str[0] == 'y' || str[0] == 'Y') res = true; else if (str[0] == '0' || str[0] == 'n' || str[0] == 'N') res = false; else return parseError("'0/n/N' or '1/y/Y'", optname, str); str = str[1 .. $]; return true; } bool parse(T:float)(const(char)[] optname, ref const(char)[] str, ref T res) in { assert(str.length); } body { // % uint f %n \0 char[1 + 10 + 1 + 2 + 1] fmt=void; // specify max-width immutable n = snprintf(fmt.ptr, fmt.length, "%%%uf%%n", cast(uint)str.length); assert(n > 4 && n < fmt.length); int nscanned; if (sscanf(str.ptr, fmt.ptr, &res, &nscanned) < 1) return parseError("a float", optname, str); str = str[nscanned .. $]; return true; } bool parseError(in char[] exp, in char[] opt, in char[] got) { version (unittest) if (inUnittest) return false; fprintf(stderr, "Expecting %.*s as argument for GC option '%.*s', got '%.*s' instead.\n", cast(int)exp.length, exp.ptr, cast(int)opt.length, opt.ptr, cast(int)got.length, got.ptr); return false; } size_t min(size_t a, size_t b) { return a <= b ? a : b; } version (unittest) __gshared bool inUnittest; unittest { inUnittest = true; scope (exit) inUnittest = false; Config conf; assert(!conf.parseOptions("disable")); assert(!conf.parseOptions("disable:")); assert(!conf.parseOptions("disable:5")); assert(conf.parseOptions("disable:y") && conf.disable); assert(conf.parseOptions("disable:n") && !conf.disable); assert(conf.parseOptions("disable:Y") && conf.disable); assert(conf.parseOptions("disable:N") && !conf.disable); assert(conf.parseOptions("disable:1") && conf.disable); assert(conf.parseOptions("disable:0") && !conf.disable); assert(conf.parseOptions("disable=y") && conf.disable); assert(conf.parseOptions("disable=n") && !conf.disable); assert(conf.parseOptions("profile=0") && conf.profile == 0); assert(conf.parseOptions("profile=1") && conf.profile == 1); assert(conf.parseOptions("profile=2") && conf.profile == 2); assert(!conf.parseOptions("profile=256")); assert(conf.parseOptions("disable:1 minPoolSize:16")); assert(conf.disable); assert(conf.minPoolSize == 16); assert(conf.parseOptions("heapSizeFactor:3.1")); assert(conf.heapSizeFactor == 3.1f); assert(conf.parseOptions("heapSizeFactor:3.1234567890 disable:0")); assert(conf.heapSizeFactor > 3.123f); assert(!conf.disable); assert(!conf.parseOptions("heapSizeFactor:3.0.2.5")); assert(conf.parseOptions("heapSizeFactor:2")); assert(conf.heapSizeFactor == 2.0f); assert(!conf.parseOptions("initReserve:foo")); assert(!conf.parseOptions("initReserve:y")); assert(!conf.parseOptions("initReserve:20.5")); assert(conf.parseOptions("help")); assert(conf.parseOptions("help profile:1")); assert(conf.parseOptions("help profile:1 help")); } ldc-1.1.0-beta3-src/runtime/druntime/src/gc/proxy.d0000664000175000017500000002227312776214756020177 0ustar kaikai/** * Contains the external GC interface. * * Copyright: Copyright Digital Mars 2005 - 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2005 - 2013. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module gc.proxy; import gc.gc; import gc.stats; import core.stdc.stdlib; private { __gshared GC _gc; static import core.memory; alias BlkInfo = core.memory.GC.BlkInfo; extern (C) void thread_init(); extern (C) void thread_term(); struct Proxy { extern (C) { void function() gc_enable; void function() gc_disable; nothrow: void function() gc_collect; void function() gc_minimize; uint function(void*) gc_getAttr; uint function(void*, uint) gc_setAttr; uint function(void*, uint) gc_clrAttr; void* function(size_t, uint, const TypeInfo) gc_malloc; BlkInfo function(size_t, uint, const TypeInfo) gc_qalloc; void* function(size_t, uint, const TypeInfo) gc_calloc; void* function(void*, size_t, uint ba, const TypeInfo) gc_realloc; size_t function(void*, size_t, size_t, const TypeInfo) gc_extend; size_t function(size_t) gc_reserve; void function(void*) gc_free; void* function(void*) gc_addrOf; size_t function(void*) gc_sizeOf; BlkInfo function(void*) gc_query; void function(void*) gc_addRoot; void function(void*, size_t, const TypeInfo ti) gc_addRange; void function(void*) gc_removeRoot; void function(void*) gc_removeRange; void function(in void[]) gc_runFinalizers; bool function() gc_inFinalizer; } } __gshared Proxy pthis; __gshared Proxy* proxy; void initProxy() { pthis.gc_enable = &gc_enable; pthis.gc_disable = &gc_disable; pthis.gc_collect = &gc_collect; pthis.gc_minimize = &gc_minimize; pthis.gc_getAttr = &gc_getAttr; pthis.gc_setAttr = &gc_setAttr; pthis.gc_clrAttr = &gc_clrAttr; pthis.gc_malloc = &gc_malloc; pthis.gc_qalloc = &gc_qalloc; pthis.gc_calloc = &gc_calloc; pthis.gc_realloc = &gc_realloc; pthis.gc_extend = &gc_extend; pthis.gc_reserve = &gc_reserve; pthis.gc_free = &gc_free; pthis.gc_addrOf = &gc_addrOf; pthis.gc_sizeOf = &gc_sizeOf; pthis.gc_query = &gc_query; pthis.gc_addRoot = &gc_addRoot; pthis.gc_addRange = &gc_addRange; pthis.gc_removeRoot = &gc_removeRoot; pthis.gc_removeRange = &gc_removeRange; pthis.gc_runFinalizers = &gc_runFinalizers; pthis.gc_inFinalizer = &gc_inFinalizer; } } extern (C) { void gc_init() { _gc.initialize(); // NOTE: The GC must initialize the thread library // before its first collection. thread_init(); initProxy(); } void gc_term() { // NOTE: There may be daemons threads still running when this routine is // called. If so, cleaning memory out from under then is a good // way to make them crash horribly. This probably doesn't matter // much since the app is supposed to be shutting down anyway, but // I'm disabling cleanup for now until I can think about it some // more. // // NOTE: Due to popular demand, this has been re-enabled. It still has // the problems mentioned above though, so I guess we'll see. _gc.fullCollectNoStack(); // not really a 'collect all' -- still scans // static data area, roots, and ranges. thread_term(); _gc.Dtor(); } void gc_enable() { if( proxy is null ) return _gc.enable(); return proxy.gc_enable(); } void gc_disable() { if( proxy is null ) return _gc.disable(); return proxy.gc_disable(); } void gc_collect() nothrow { if( proxy is null ) { _gc.fullCollect(); return; } return proxy.gc_collect(); } void gc_minimize() nothrow { if( proxy is null ) return _gc.minimize(); return proxy.gc_minimize(); } uint gc_getAttr( void* p ) nothrow { if( proxy is null ) return _gc.getAttr( p ); return proxy.gc_getAttr( p ); } uint gc_setAttr( void* p, uint a ) nothrow { if( proxy is null ) return _gc.setAttr( p, a ); return proxy.gc_setAttr( p, a ); } uint gc_clrAttr( void* p, uint a ) nothrow { if( proxy is null ) return _gc.clrAttr( p, a ); return proxy.gc_clrAttr( p, a ); } void* gc_malloc( size_t sz, uint ba = 0, const TypeInfo ti = null ) nothrow { if( proxy is null ) return _gc.malloc( sz, ba, null, ti ); return proxy.gc_malloc( sz, ba, ti ); } BlkInfo gc_qalloc( size_t sz, uint ba = 0, const TypeInfo ti = null ) nothrow { if( proxy is null ) { BlkInfo retval; retval.base = _gc.malloc( sz, ba, &retval.size, ti ); retval.attr = ba; return retval; } return proxy.gc_qalloc( sz, ba, ti ); } void* gc_calloc( size_t sz, uint ba = 0, const TypeInfo ti = null ) nothrow { if( proxy is null ) return _gc.calloc( sz, ba, null, ti ); return proxy.gc_calloc( sz, ba, ti ); } void* gc_realloc( void* p, size_t sz, uint ba = 0, const TypeInfo ti = null ) nothrow { if( proxy is null ) return _gc.realloc( p, sz, ba, null, ti ); return proxy.gc_realloc( p, sz, ba, ti ); } size_t gc_extend( void* p, size_t mx, size_t sz, const TypeInfo ti = null ) nothrow { if( proxy is null ) return _gc.extend( p, mx, sz, ti ); return proxy.gc_extend( p, mx, sz,ti ); } size_t gc_reserve( size_t sz ) nothrow { if( proxy is null ) return _gc.reserve( sz ); return proxy.gc_reserve( sz ); } void gc_free( void* p ) nothrow { if( proxy is null ) return _gc.free( p ); return proxy.gc_free( p ); } void* gc_addrOf( void* p ) nothrow { if( proxy is null ) return _gc.addrOf( p ); return proxy.gc_addrOf( p ); } size_t gc_sizeOf( void* p ) nothrow { if( proxy is null ) return _gc.sizeOf( p ); return proxy.gc_sizeOf( p ); } BlkInfo gc_query( void* p ) nothrow { if( proxy is null ) return _gc.query( p ); return proxy.gc_query( p ); } // NOTE: This routine is experimental. The stats or function name may change // before it is made officially available. GCStats gc_stats() nothrow { if( proxy is null ) { GCStats stats = void; _gc.getStats( stats ); return stats; } // TODO: Add proxy support for this once the layout of GCStats is // finalized. //return proxy.gc_stats(); return GCStats.init; } void gc_addRoot( void* p ) nothrow { if( proxy is null ) return _gc.addRoot( p ); return proxy.gc_addRoot( p ); } void gc_addRange( void* p, size_t sz, const TypeInfo ti = null ) nothrow { if( proxy is null ) return _gc.addRange( p, sz, ti ); return proxy.gc_addRange( p, sz, ti ); } void gc_removeRoot( void* p ) nothrow { if( proxy is null ) return _gc.removeRoot( p ); return proxy.gc_removeRoot( p ); } void gc_removeRange( void* p ) nothrow { if( proxy is null ) return _gc.removeRange( p ); return proxy.gc_removeRange( p ); } void gc_runFinalizers( in void[] segment ) nothrow { if( proxy is null ) return _gc.runFinalizers( segment ); return proxy.gc_runFinalizers( segment ); } bool gc_inFinalizer() nothrow { if( proxy is null ) return _gc.inFinalizer; return proxy.gc_inFinalizer(); } Proxy* gc_getProxy() nothrow { return &pthis; } export { void gc_setProxy( Proxy* p ) { if( proxy !is null ) { // TODO: Decide if this is an error condition. } proxy = p; foreach (r; _gc.rootIter) proxy.gc_addRoot( r ); foreach (r; _gc.rangeIter) proxy.gc_addRange( r.pbot, r.ptop - r.pbot, null ); } void gc_clrProxy() { foreach (r; _gc.rangeIter) proxy.gc_removeRange( r.pbot ); foreach (r; _gc.rootIter) proxy.gc_removeRoot( r ); proxy = null; } } } ldc-1.1.0-beta3-src/runtime/druntime/src/gc/bits.d0000664000175000017500000000457612776214756017765 0ustar kaikai/** * Contains a bitfield used by the GC. * * Copyright: Copyright Digital Mars 2005 - 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, David Friedman, Sean Kelly */ /* Copyright Digital Mars 2005 - 2013. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module gc.bits; import core.bitop; import core.stdc.string; import core.stdc.stdlib; import core.exception : onOutOfMemoryError; struct GCBits { alias size_t wordtype; enum BITS_PER_WORD = (wordtype.sizeof * 8); enum BITS_SHIFT = (wordtype.sizeof == 8 ? 6 : 5); enum BITS_MASK = (BITS_PER_WORD - 1); enum BITS_1 = cast(wordtype)1; wordtype* data; size_t nbits; void Dtor() nothrow { if (data) { free(data); data = null; } } void alloc(size_t nbits) nothrow { this.nbits = nbits; data = cast(typeof(data[0])*)calloc(nwords, data[0].sizeof); if (!data) onOutOfMemoryError(); } wordtype test(size_t i) const nothrow in { assert(i < nbits); } body { return core.bitop.bt(data, i); } int set(size_t i) nothrow in { assert(i < nbits); } body { return core.bitop.bts(data, i); } int clear(size_t i) nothrow in { assert(i <= nbits); } body { return core.bitop.btr(data, i); } void zero() nothrow { memset(data, 0, nwords * wordtype.sizeof); } void copy(GCBits *f) nothrow in { assert(nwords == f.nwords); } body { memcpy(data, f.data, nwords * wordtype.sizeof); } @property size_t nwords() const pure nothrow { return (nbits + (BITS_PER_WORD - 1)) >> BITS_SHIFT; } } unittest { GCBits b; b.alloc(786); assert(!b.test(123)); assert(!b.clear(123)); assert(!b.set(123)); assert(b.test(123)); assert(b.clear(123)); assert(!b.test(123)); b.set(785); b.set(0); assert(b.test(785)); assert(b.test(0)); b.zero(); assert(!b.test(785)); assert(!b.test(0)); GCBits b2; b2.alloc(786); b2.set(38); b.copy(&b2); assert(b.test(38)); b2.Dtor(); b.Dtor(); } ldc-1.1.0-beta3-src/runtime/druntime/src/gc/stats.d0000664000175000017500000000137012776214756020147 0ustar kaikai/** * Contains a struct for storing GC statistics. * * Copyright: Copyright Digital Mars 2005 - 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2005 - 2013. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module gc.stats; /** * */ struct GCStats { size_t poolsize; // total size of pool size_t usedsize; // bytes allocated size_t freeblocks; // number of blocks marked FREE size_t freelistsize; // total of memory on free lists size_t pageblocks; // number of blocks marked PAGE } ldc-1.1.0-beta3-src/runtime/druntime/src/gc/pooltable.d0000664000175000017500000001570512776214756021001 0ustar kaikai/** * A sorted array to quickly lookup pools. * * Copyright: Copyright Digital Mars 2001 -. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, David Friedman, Sean Kelly, Martin Nowak */ module gc.pooltable; static import cstdlib=core.stdc.stdlib; struct PoolTable(Pool) { import core.stdc.string : memmove; nothrow: void Dtor() { cstdlib.free(pools); pools = null; npools = 0; } bool insert(Pool* pool) { auto newpools = cast(Pool **)cstdlib.realloc(pools, (npools + 1) * pools[0].sizeof); if (!newpools) return false; pools = newpools; // Sort pool into newpooltable[] size_t i; for (; i < npools; ++i) { if (pool.baseAddr < pools[i].baseAddr) break; } if (i != npools) memmove(pools + i + 1, pools + i, (npools - i) * pools[0].sizeof); pools[i] = pool; ++npools; _minAddr = pools[0].baseAddr; _maxAddr = pools[npools - 1].topAddr; return true; } @property size_t length() pure const { return npools; } ref inout(Pool*) opIndex(size_t idx) inout pure in { assert(idx < length); } body { return pools[idx]; } inout(Pool*)[] opSlice(size_t a, size_t b) inout pure in { assert(a <= length && b <= length); } body { return pools[a .. b]; } alias opDollar = length; /** * Find Pool that pointer is in. * Return null if not in a Pool. * Assume pooltable[] is sorted. */ Pool *findPool(void *p) nothrow { if (p >= minAddr && p < maxAddr) { assert(npools); // let dmd allocate a register for this.pools auto pools = this.pools; if (npools == 1) return pools[0]; /* The pooltable[] is sorted by address, so do a binary search */ size_t low = 0; size_t high = npools - 1; while (low <= high) { size_t mid = (low + high) >> 1; auto pool = pools[mid]; if (p < pool.baseAddr) high = mid - 1; else if (p >= pool.topAddr) low = mid + 1; else return pool; } } return null; } // semi-stable partition, returns right half for which pred is false Pool*[] minimize() pure { static void swap(ref Pool* a, ref Pool* b) { auto c = a; a = b; b = c; } size_t i; // find first bad entry for (; i < npools; ++i) if (pools[i].isFree) break; // move good in front of bad entries size_t j = i + 1; for (; j < npools; ++j) { if (!pools[j].isFree) // keep swap(pools[i++], pools[j]); } // npooltable[0 .. i] => used pools // npooltable[i .. npools] => free pools if (i) { _minAddr = pools[0].baseAddr; _maxAddr = pools[i - 1].topAddr; } else { _minAddr = _maxAddr = null; } immutable len = npools; npools = i; // return freed pools to the caller return pools[npools .. len]; } void Invariant() const { if (!npools) return; foreach (i, pool; pools[0 .. npools - 1]) assert(pool.baseAddr < pools[i + 1].baseAddr); assert(_minAddr == pools[0].baseAddr); assert(_maxAddr == pools[npools - 1].topAddr); } @property const(byte)* minAddr() pure const { return _minAddr; } @property const(byte)* maxAddr() pure const { return _maxAddr; } package: Pool** pools; size_t npools; byte* _minAddr, _maxAddr; } unittest { enum NPOOLS = 6; enum NPAGES = 10; enum PAGESIZE = 4096; static struct MockPool { byte* baseAddr, topAddr; size_t freepages, npages; @property bool isFree() const pure nothrow { return freepages == npages; } } PoolTable!MockPool pooltable; void reset() { foreach(ref pool; pooltable[0 .. $]) pool.freepages = pool.npages; pooltable.minimize(); assert(pooltable.length == 0); foreach(i; 0 .. NPOOLS) { auto pool = cast(MockPool*)cstdlib.malloc(MockPool.sizeof); *pool = MockPool.init; assert(pooltable.insert(pool)); } } void usePools() { foreach(pool; pooltable[0 .. $]) { pool.npages = NPAGES; pool.freepages = NPAGES / 2; } } // all pools are free reset(); assert(pooltable.length == NPOOLS); auto freed = pooltable.minimize(); assert(freed.length == NPOOLS); assert(pooltable.length == 0); // all pools used reset(); usePools(); assert(pooltable.length == NPOOLS); freed = pooltable.minimize(); assert(freed.length == 0); assert(pooltable.length == NPOOLS); // preserves order of used pools reset(); usePools(); { MockPool*[NPOOLS] opools = pooltable[0 .. NPOOLS]; // make the 2nd pool free pooltable[2].freepages = NPAGES; pooltable.minimize(); assert(pooltable.length == NPOOLS - 1); assert(pooltable[0] == opools[0]); assert(pooltable[1] == opools[1]); assert(pooltable[2] == opools[3]); } // test that PoolTable reduces min/max address span reset(); usePools(); byte* base, top; { // fill with fake addresses size_t i; foreach(pool; pooltable[0 .. NPOOLS]) { pool.baseAddr = cast(byte*)(i++ * NPAGES * PAGESIZE); pool.topAddr = pool.baseAddr + NPAGES * PAGESIZE; } base = pooltable[0].baseAddr; top = pooltable[NPOOLS - 1].topAddr; } freed = pooltable.minimize(); assert(freed.length == 0); assert(pooltable.length == NPOOLS); assert(pooltable.minAddr == base); assert(pooltable.maxAddr == top); pooltable[NPOOLS - 1].freepages = NPAGES; pooltable[NPOOLS - 2].freepages = NPAGES; freed = pooltable.minimize(); assert(freed.length == 2); assert(pooltable.length == NPOOLS - 2); assert(pooltable.minAddr == base); assert(pooltable.maxAddr == pooltable[NPOOLS - 3].topAddr); pooltable[0].freepages = NPAGES; freed = pooltable.minimize(); assert(freed.length == 1); assert(pooltable.length == NPOOLS - 3); assert(pooltable.minAddr != base); assert(pooltable.minAddr == pooltable[0].baseAddr); assert(pooltable.maxAddr == pooltable[NPOOLS - 4].topAddr); // free all foreach(pool; pooltable[0 .. $]) pool.freepages = NPAGES; freed = pooltable.minimize(); assert(freed.length == NPOOLS - 3); assert(pooltable.length == 0); pooltable.Dtor(); } ldc-1.1.0-beta3-src/runtime/druntime/src/gc/os.d0000664000175000017500000001153712776214756017440 0ustar kaikai/** * Contains OS-level routines needed by the garbage collector. * * Copyright: Copyright Digital Mars 2005 - 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, David Friedman, Sean Kelly, Leandro Lucarella */ /* Copyright Digital Mars 2005 - 2013. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module gc.os; version (Windows) { import core.sys.windows.windows; alias int pthread_t; pthread_t pthread_self() nothrow { return cast(pthread_t) GetCurrentThreadId(); } //version = GC_Use_Alloc_Win32; } else version (Posix) { import core.sys.posix.sys.mman; version (FreeBSD) import core.sys.freebsd.sys.mman : MAP_ANON; version (CRuntime_Glibc) import core.sys.linux.sys.mman : MAP_ANON; version (OSX) import core.sys.osx.sys.mman : MAP_ANON; import core.stdc.stdlib; //version = GC_Use_Alloc_MMap; } else { import core.stdc.stdlib; //version = GC_Use_Alloc_Malloc; } /+ static if(is(typeof(VirtualAlloc))) version = GC_Use_Alloc_Win32; else static if (is(typeof(mmap))) version = GC_Use_Alloc_MMap; else static if (is(typeof(valloc))) version = GC_Use_Alloc_Valloc; else static if (is(typeof(malloc))) version = GC_Use_Alloc_Malloc; else static assert(false, "No supported allocation methods available."); +/ static if (is(typeof(VirtualAlloc))) // version (GC_Use_Alloc_Win32) { /** * Map memory. */ void *os_mem_map(size_t nbytes) nothrow { return VirtualAlloc(null, nbytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); } /** * Unmap memory allocated with os_mem_map(). * Returns: * 0 success * !=0 failure */ int os_mem_unmap(void *base, size_t nbytes) nothrow { return cast(int)(VirtualFree(base, 0, MEM_RELEASE) == 0); } } else static if (is(typeof(mmap))) // else version (GC_Use_Alloc_MMap) { void *os_mem_map(size_t nbytes) nothrow { void *p; p = mmap(null, nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); return (p == MAP_FAILED) ? null : p; } int os_mem_unmap(void *base, size_t nbytes) nothrow { return munmap(base, nbytes); } } else static if (is(typeof(valloc))) // else version (GC_Use_Alloc_Valloc) { void *os_mem_map(size_t nbytes) nothrow { return valloc(nbytes); } int os_mem_unmap(void *base, size_t nbytes) nothrow { free(base); return 0; } } else static if (is(typeof(malloc))) // else version (GC_Use_Alloc_Malloc) { // NOTE: This assumes malloc granularity is at least (void*).sizeof. If // (req_size + PAGESIZE) is allocated, and the pointer is rounded up // to PAGESIZE alignment, there will be space for a void* at the end // after PAGESIZE bytes used by the GC. import gc.gc; const size_t PAGE_MASK = PAGESIZE - 1; void *os_mem_map(size_t nbytes) nothrow { byte *p, q; p = cast(byte *) malloc(nbytes + PAGESIZE); q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK); * cast(void**)(q + nbytes) = p; return q; } int os_mem_unmap(void *base, size_t nbytes) nothrow { free( *cast(void**)( cast(byte*) base + nbytes ) ); return 0; } } else { static assert(false, "No supported allocation methods available."); } /** Check for any kind of memory pressure. Params: mapped = the amount of memory mapped by the GC in bytes Returns: true if memory is scarce */ // TOOD: get virtual mem sizes and current usage from OS // TODO: compare current RSS and avail. physical memory version (Windows) { bool isLowOnMem(size_t mapped) nothrow @nogc { version (D_LP64) return false; else { import core.sys.windows.windows; MEMORYSTATUS stat; GlobalMemoryStatus(&stat); // Less than 5 % of virtual address space available return stat.dwAvailVirtual < stat.dwTotalVirtual / 20; } } } else version (OSX) { bool isLowOnMem(size_t mapped) nothrow @nogc { enum GB = 2 ^^ 30; version (D_LP64) return false; else { // 80 % of available 4GB is used for GC (excluding malloc and mmap) enum size_t limit = 4UL * GB * 8 / 10; return mapped > limit; } } } else { bool isLowOnMem(size_t mapped) nothrow @nogc { enum GB = 2 ^^ 30; version (D_LP64) return false; else { // be conservative and assume 3GB enum size_t limit = 3UL * GB * 8 / 10; return mapped > limit; } } } ldc-1.1.0-beta3-src/runtime/druntime/src/gc/gc.d0000664000175000017500000027012312776214756017406 0ustar kaikai/** * Contains the garbage collector implementation. * * Copyright: Copyright Digital Mars 2001 - 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, David Friedman, Sean Kelly */ /* Copyright Digital Mars 2005 - 2013. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module gc.gc; // D Programming Language Garbage Collector implementation /************** Debugging ***************************/ //debug = PRINTF; // turn on printf's //debug = COLLECT_PRINTF; // turn on printf's //debug = PRINTF_TO_FILE; // redirect printf's ouptut to file "gcx.log" //debug = LOGGING; // log allocations / frees //debug = MEMSTOMP; // stomp on memory //debug = SENTINEL; // add underrun/overrrun protection // NOTE: this needs to be enabled globally in the makefiles // (-debug=SENTINEL) to pass druntime's unittests. //debug = PTRCHECK; // more pointer checking //debug = PTRCHECK2; // thorough but slow pointer checking //debug = INVARIANT; // enable invariants //debug = PROFILE_API; // profile API calls for config.profile > 1 /*************** Configuration *********************/ version = STACKGROWSDOWN; // growing the stack means subtracting from the stack pointer // (use for Intel X86 CPUs) // else growing the stack means adding to the stack pointer /***************************************************/ import gc.bits; import gc.stats; import gc.os; import gc.config; import rt.util.container.treap; import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc; import core.stdc.string : memcpy, memset, memmove; import core.bitop; import core.thread; static import core.memory; private alias BlkAttr = core.memory.GC.BlkAttr; private alias BlkInfo = core.memory.GC.BlkInfo; version (GNU) import gcc.builtins; debug (PRINTF_TO_FILE) import core.stdc.stdio : sprintf, fprintf, fopen, fflush, FILE; else import core.stdc.stdio : sprintf, printf; // needed to output profiling results import core.time; alias currTime = MonoTime.currTime; debug(PRINTF_TO_FILE) { private __gshared MonoTime gcStartTick; private __gshared FILE* gcx_fh; private int printf(ARGS...)(const char* fmt, ARGS args) nothrow { if (!gcx_fh) gcx_fh = fopen("gcx.log", "w"); if (!gcx_fh) return 0; int len; if (MonoTime.ticksPerSecond == 0) { len = fprintf(gcx_fh, "before init: "); } else { if (gcStartTick == MonoTime.init) gcStartTick = MonoTime.currTime; immutable timeElapsed = MonoTime.currTime - gcStartTick; immutable secondsAsDouble = timeElapsed.total!"hnsecs" / cast(double)convert!("seconds", "hnsecs")(1); len = fprintf(gcx_fh, "%10.6lf: ", secondsAsDouble); } len += fprintf(gcx_fh, fmt, args); fflush(gcx_fh); return len; } } debug(PRINTF) void printFreeInfo(Pool* pool) nothrow { uint nReallyFree; foreach(i; 0..pool.npages) { if(pool.pagetable[i] >= B_FREE) nReallyFree++; } printf("Pool %p: %d really free, %d supposedly free\n", pool, nReallyFree, pool.freepages); } // Track total time spent preparing for GC, // marking, sweeping and recovering pages. __gshared Duration prepTime; __gshared Duration markTime; __gshared Duration sweepTime; __gshared Duration recoverTime; __gshared Duration maxPauseTime; __gshared size_t numCollections; __gshared size_t maxPoolMemory; __gshared long numMallocs; __gshared long numFrees; __gshared long numReallocs; __gshared long numExtends; __gshared long numOthers; __gshared long mallocTime; // using ticks instead of MonoTime for better performance __gshared long freeTime; __gshared long reallocTime; __gshared long extendTime; __gshared long otherTime; __gshared long lockTime; private { extern (C) { // to allow compilation of this module without access to the rt package, // make these functions available from rt.lifetime void rt_finalizeFromGC(void* p, size_t size, uint attr) nothrow; int rt_hasFinalizerInSegment(void* p, size_t size, uint attr, in void[] segment) nothrow; // Declared as an extern instead of importing core.exception // to avoid inlining - see issue 13725. void onInvalidMemoryOperationError() @nogc nothrow; void onOutOfMemoryErrorNoGC() @nogc nothrow; } enum { OPFAIL = ~cast(size_t)0 } } alias GC gc_t; /* ======================= Leak Detector =========================== */ debug (LOGGING) { struct Log { void* p; size_t size; size_t line; char* file; void* parent; void print() nothrow { printf(" p = %p, size = %zd, parent = %p ", p, size, parent); if (file) { printf("%s(%u)", file, line); } printf("\n"); } } struct LogArray { size_t dim; size_t allocdim; Log *data; void Dtor() nothrow { if (data) cstdlib.free(data); data = null; } void reserve(size_t nentries) nothrow { assert(dim <= allocdim); if (allocdim - dim < nentries) { allocdim = (dim + nentries) * 2; assert(dim + nentries <= allocdim); if (!data) { data = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof); if (!data && allocdim) onOutOfMemoryErrorNoGC(); } else { Log *newdata; newdata = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof); if (!newdata && allocdim) onOutOfMemoryErrorNoGC(); memcpy(newdata, data, dim * Log.sizeof); cstdlib.free(data); data = newdata; } } } void push(Log log) nothrow { reserve(1); data[dim++] = log; } void remove(size_t i) nothrow { memmove(data + i, data + i + 1, (dim - i) * Log.sizeof); dim--; } size_t find(void *p) nothrow { for (size_t i = 0; i < dim; i++) { if (data[i].p == p) return i; } return OPFAIL; // not found } void copy(LogArray *from) nothrow { reserve(from.dim - dim); assert(from.dim <= allocdim); memcpy(data, from.data, from.dim * Log.sizeof); dim = from.dim; } } } /* ============================ GC =============================== */ const uint GCVERSION = 1; // increment every time we change interface // to GC. struct GC { // For passing to debug code (not thread safe) __gshared size_t line; __gshared char* file; uint gcversion = GCVERSION; Gcx *gcx; // implementation import core.internal.spinlock; static gcLock = shared(AlignedSpinLock)(SpinLock.Contention.lengthy); static bool inFinalizer; // lock GC, throw InvalidMemoryOperationError on recursive locking during finalization static void lockNR() @nogc nothrow { if (inFinalizer) onInvalidMemoryOperationError(); gcLock.lock(); } __gshared Config config; void initialize() { config.initialize(); gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof); if (!gcx) onOutOfMemoryErrorNoGC(); gcx.initialize(); if (config.initReserve) gcx.reserve(config.initReserve << 20); if (config.disable) gcx.disabled++; } void Dtor() { version (linux) { //debug(PRINTF) printf("Thread %x ", pthread_self()); //debug(PRINTF) printf("GC.Dtor()\n"); } if (gcx) { gcx.Dtor(); cstdlib.free(gcx); gcx = null; } } /** * */ void enable() { static void go(Gcx* gcx) nothrow { assert(gcx.disabled > 0); gcx.disabled--; } runLocked!(go, otherTime, numOthers)(gcx); } /** * */ void disable() { static void go(Gcx* gcx) nothrow { gcx.disabled++; } runLocked!(go, otherTime, numOthers)(gcx); } auto runLocked(alias func, Args...)(auto ref Args args) { debug(PROFILE_API) immutable tm = (GC.config.profile > 1 ? currTime.ticks : 0); lockNR(); scope (failure) gcLock.unlock(); debug(PROFILE_API) immutable tm2 = (GC.config.profile > 1 ? currTime.ticks : 0); static if (is(typeof(func(args)) == void)) func(args); else auto res = func(args); debug(PROFILE_API) if (GC.config.profile > 1) lockTime += tm2 - tm; gcLock.unlock(); static if (!is(typeof(func(args)) == void)) return res; } auto runLocked(alias func, alias time, alias count, Args...)(auto ref Args args) { debug(PROFILE_API) immutable tm = (GC.config.profile > 1 ? currTime.ticks : 0); lockNR(); scope (failure) gcLock.unlock(); debug(PROFILE_API) immutable tm2 = (GC.config.profile > 1 ? currTime.ticks : 0); static if (is(typeof(func(args)) == void)) func(args); else auto res = func(args); debug(PROFILE_API) if (GC.config.profile > 1) { count++; immutable now = currTime.ticks; lockTime += tm2 - tm; time += now - tm2; } gcLock.unlock(); static if (!is(typeof(func(args)) == void)) return res; } /** * */ uint getAttr(void* p) nothrow { if (!p) { return 0; } static uint go(Gcx* gcx, void* p) nothrow { Pool* pool = gcx.findPool(p); uint oldb = 0; if (pool) { p = sentinel_sub(p); auto biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy; oldb = pool.getBits(biti); } return oldb; } return runLocked!(go, otherTime, numOthers)(gcx, p); } /** * */ uint setAttr(void* p, uint mask) nothrow { if (!p) { return 0; } static uint go(Gcx* gcx, void* p, uint mask) nothrow { Pool* pool = gcx.findPool(p); uint oldb = 0; if (pool) { p = sentinel_sub(p); auto biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy; oldb = pool.getBits(biti); pool.setBits(biti, mask); } return oldb; } return runLocked!(go, otherTime, numOthers)(gcx, p, mask); } /** * */ uint clrAttr(void* p, uint mask) nothrow { if (!p) { return 0; } static uint go(Gcx* gcx, void* p, uint mask) nothrow { Pool* pool = gcx.findPool(p); uint oldb = 0; if (pool) { p = sentinel_sub(p); auto biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy; oldb = pool.getBits(biti); pool.clrBits(biti, mask); } return oldb; } return runLocked!(go, otherTime, numOthers)(gcx, p, mask); } /** * */ void *malloc(size_t size, uint bits = 0, size_t *alloc_size = null, const TypeInfo ti = null) nothrow { if (!size) { if(alloc_size) *alloc_size = 0; return null; } size_t localAllocSize = void; if(alloc_size is null) alloc_size = &localAllocSize; auto p = runLocked!(mallocNoSync, mallocTime, numMallocs)(size, bits, *alloc_size, ti); if (!(bits & BlkAttr.NO_SCAN)) { memset(p + size, 0, *alloc_size - size); } return p; } // // // private void *mallocNoSync(size_t size, uint bits, ref size_t alloc_size, const TypeInfo ti = null) nothrow { assert(size != 0); //debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p)\n", size, gcx); assert(gcx); //debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self()); auto p = gcx.alloc(size + SENTINEL_EXTRA, alloc_size, bits); if (!p) onOutOfMemoryErrorNoGC(); debug (SENTINEL) { p = sentinel_add(p); sentinel_init(p, size); alloc_size = size; } gcx.log_malloc(p, size); return p; } /** * */ void *calloc(size_t size, uint bits = 0, size_t *alloc_size = null, const TypeInfo ti = null) nothrow { if (!size) { if(alloc_size) *alloc_size = 0; return null; } size_t localAllocSize = void; if(alloc_size is null) alloc_size = &localAllocSize; auto p = runLocked!(mallocNoSync, mallocTime, numMallocs)(size, bits, *alloc_size, ti); memset(p, 0, size); if (!(bits & BlkAttr.NO_SCAN)) { memset(p + size, 0, *alloc_size - size); } return p; } /** * */ void *realloc(void *p, size_t size, uint bits = 0, size_t *alloc_size = null, const TypeInfo ti = null) nothrow { size_t localAllocSize = void; auto oldp = p; if(alloc_size is null) alloc_size = &localAllocSize; p = runLocked!(reallocNoSync, mallocTime, numMallocs)(p, size, bits, *alloc_size, ti); if (p !is oldp && !(bits & BlkAttr.NO_SCAN)) { memset(p + size, 0, *alloc_size - size); } return p; } // // bits will be set to the resulting bits of the new block // private void *reallocNoSync(void *p, size_t size, ref uint bits, ref size_t alloc_size, const TypeInfo ti = null) nothrow { if (!size) { if (p) { freeNoSync(p); p = null; } alloc_size = 0; } else if (!p) { p = mallocNoSync(size, bits, alloc_size, ti); } else { void *p2; size_t psize; //debug(PRINTF) printf("GC::realloc(p = %p, size = %zu)\n", p, size); debug (SENTINEL) { sentinel_Invariant(p); psize = *sentinel_size(p); if (psize != size) { if (psize) { Pool *pool = gcx.findPool(p); if (pool) { auto biti = cast(size_t)(sentinel_sub(p) - pool.baseAddr) >> pool.shiftBy; if (bits) { pool.clrBits(biti, ~BlkAttr.NONE); pool.setBits(biti, bits); } else { bits = pool.getBits(biti); } } } p2 = mallocNoSync(size, bits, alloc_size, ti); if (psize < size) size = psize; //debug(PRINTF) printf("\tcopying %d bytes\n",size); memcpy(p2, p, size); p = p2; } } else { auto pool = gcx.findPool(p); if (pool.isLargeObject) { auto lpool = cast(LargeObjectPool*) pool; psize = lpool.getSize(p); // get allocated size if (size <= PAGESIZE / 2) goto Lmalloc; // switching from large object pool to small object pool auto psz = psize / PAGESIZE; auto newsz = (size + PAGESIZE - 1) / PAGESIZE; if (newsz == psz) { alloc_size = psize; return p; } auto pagenum = lpool.pagenumOf(p); if (newsz < psz) { // Shrink in place debug (MEMSTOMP) memset(p + size, 0xF2, psize - size); lpool.freePages(pagenum + newsz, psz - newsz); } else if (pagenum + newsz <= pool.npages) { // Attempt to expand in place foreach (binsz; lpool.pagetable[pagenum + psz .. pagenum + newsz]) if (binsz != B_FREE) goto Lmalloc; debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize); debug(PRINTF) printFreeInfo(pool); memset(&lpool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz); gcx.usedLargePages += newsz - psz; lpool.freepages -= (newsz - psz); debug(PRINTF) printFreeInfo(pool); } else goto Lmalloc; // does not fit into current pool lpool.updateOffsets(pagenum); if (bits) { immutable biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy; pool.clrBits(biti, ~BlkAttr.NONE); pool.setBits(biti, bits); } alloc_size = newsz * PAGESIZE; return p; } psize = (cast(SmallObjectPool*) pool).getSize(p); // get allocated size if (psize < size || // if new size is bigger psize > size * 2) // or less than half { Lmalloc: if (psize && pool) { auto biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy; if (bits) { pool.clrBits(biti, ~BlkAttr.NONE); pool.setBits(biti, bits); } else { bits = pool.getBits(biti); } } p2 = mallocNoSync(size, bits, alloc_size, ti); if (psize < size) size = psize; //debug(PRINTF) printf("\tcopying %d bytes\n",size); memcpy(p2, p, size); p = p2; } else alloc_size = psize; } } return p; } /** * Attempt to in-place enlarge the memory block pointed to by p by at least * minsize bytes, up to a maximum of maxsize additional bytes. * This does not attempt to move the memory block (like realloc() does). * * Returns: * 0 if could not extend p, * total size of entire memory block if successful. */ size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti = null) nothrow { return runLocked!(extendNoSync, extendTime, numExtends)(p, minsize, maxsize, ti); } // // // private size_t extendNoSync(void* p, size_t minsize, size_t maxsize, const TypeInfo ti = null) nothrow in { assert(minsize <= maxsize); } body { //debug(PRINTF) printf("GC::extend(p = %p, minsize = %zu, maxsize = %zu)\n", p, minsize, maxsize); debug (SENTINEL) { return 0; } else { auto pool = gcx.findPool(p); if (!pool || !pool.isLargeObject) return 0; auto lpool = cast(LargeObjectPool*) pool; auto psize = lpool.getSize(p); // get allocated size if (psize < PAGESIZE) return 0; // cannot extend buckets auto psz = psize / PAGESIZE; auto minsz = (minsize + PAGESIZE - 1) / PAGESIZE; auto maxsz = (maxsize + PAGESIZE - 1) / PAGESIZE; auto pagenum = lpool.pagenumOf(p); size_t sz; for (sz = 0; sz < maxsz; sz++) { auto i = pagenum + psz + sz; if (i == lpool.npages) break; if (lpool.pagetable[i] != B_FREE) { if (sz < minsz) return 0; break; } } if (sz < minsz) return 0; debug (MEMSTOMP) memset(pool.baseAddr + (pagenum + psz) * PAGESIZE, 0xF0, sz * PAGESIZE); memset(lpool.pagetable + pagenum + psz, B_PAGEPLUS, sz); lpool.updateOffsets(pagenum); lpool.freepages -= sz; gcx.usedLargePages += sz; return (psz + sz) * PAGESIZE; } } /** * */ size_t reserve(size_t size) nothrow { if (!size) { return 0; } return runLocked!(reserveNoSync, otherTime, numOthers)(size); } // // // private size_t reserveNoSync(size_t size) nothrow { assert(size != 0); assert(gcx); return gcx.reserve(size); } /** * */ void free(void *p) nothrow { if (!p || inFinalizer) { return; } return runLocked!(freeNoSync, freeTime, numFrees)(p); } // // // private void freeNoSync(void *p) nothrow { debug(PRINTF) printf("Freeing %p\n", cast(size_t) p); assert (p); Pool* pool; size_t pagenum; Bins bin; size_t biti; // Find which page it is in pool = gcx.findPool(p); if (!pool) // if not one of ours return; // ignore pagenum = pool.pagenumOf(p); debug(PRINTF) printf("pool base = %p, PAGENUM = %d of %d, bin = %d\n", pool.baseAddr, pagenum, pool.npages, pool.pagetable[pagenum]); debug(PRINTF) if(pool.isLargeObject) printf("Block size = %d\n", pool.bPageOffsets[pagenum]); bin = cast(Bins)pool.pagetable[pagenum]; // Verify that the pointer is at the beginning of a block, // no action should be taken if p is an interior pointer if (bin > B_PAGE) // B_PAGEPLUS or B_FREE return; if ((sentinel_sub(p) - pool.baseAddr) & (binsize[bin] - 1)) return; sentinel_Invariant(p); p = sentinel_sub(p); biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy; pool.clrBits(biti, ~BlkAttr.NONE); if (pool.isLargeObject) // if large alloc { assert(bin == B_PAGE); auto lpool = cast(LargeObjectPool*) pool; // Free pages size_t npages = lpool.bPageOffsets[pagenum]; debug (MEMSTOMP) memset(p, 0xF2, npages * PAGESIZE); lpool.freePages(pagenum, npages); } else { // Add to free list List *list = cast(List*)p; debug (MEMSTOMP) memset(p, 0xF2, binsize[bin]); list.next = gcx.bucket[bin]; list.pool = pool; gcx.bucket[bin] = list; } gcx.log_free(sentinel_add(p)); } /** * Determine the base address of the block containing p. If p is not a gc * allocated pointer, return null. */ void* addrOf(void *p) nothrow { if (!p) { return null; } return runLocked!(addrOfNoSync, otherTime, numOthers)(p); } // // // void* addrOfNoSync(void *p) nothrow { if (!p) { return null; } auto q = gcx.findBase(p); if (q) q = sentinel_add(q); return q; } /** * Determine the allocated size of pointer p. If p is an interior pointer * or not a gc allocated pointer, return 0. */ size_t sizeOf(void *p) nothrow { if (!p) { return 0; } return runLocked!(sizeOfNoSync, otherTime, numOthers)(p); } // // // private size_t sizeOfNoSync(void *p) nothrow { assert (p); debug (SENTINEL) { p = sentinel_sub(p); size_t size = gcx.findSize(p); // Check for interior pointer // This depends on: // 1) size is a power of 2 for less than PAGESIZE values // 2) base of memory pool is aligned on PAGESIZE boundary if (cast(size_t)p & (size - 1) & (PAGESIZE - 1)) size = 0; return size ? size - SENTINEL_EXTRA : 0; } else { size_t size = gcx.findSize(p); // Check for interior pointer // This depends on: // 1) size is a power of 2 for less than PAGESIZE values // 2) base of memory pool is aligned on PAGESIZE boundary if (cast(size_t)p & (size - 1) & (PAGESIZE - 1)) return 0; return size; } } /** * Determine the base address of the block containing p. If p is not a gc * allocated pointer, return null. */ BlkInfo query(void *p) nothrow { if (!p) { BlkInfo i; return i; } return runLocked!(queryNoSync, otherTime, numOthers)(p); } // // // BlkInfo queryNoSync(void *p) nothrow { assert(p); BlkInfo info = gcx.getInfo(p); debug(SENTINEL) { if (info.base) { info.base = sentinel_add(info.base); info.size = *sentinel_size(info.base); } } return info; } /** * Verify that pointer p: * 1) belongs to this memory pool * 2) points to the start of an allocated piece of memory * 3) is not on a free list */ void check(void *p) nothrow { if (!p) { return; } return runLocked!(checkNoSync, otherTime, numOthers)(p); } // // // private void checkNoSync(void *p) nothrow { assert(p); sentinel_Invariant(p); debug (PTRCHECK) { Pool* pool; size_t pagenum; Bins bin; size_t size; p = sentinel_sub(p); pool = gcx.findPool(p); assert(pool); pagenum = pool.pagenumOf(p); bin = cast(Bins)pool.pagetable[pagenum]; assert(bin <= B_PAGE); size = binsize[bin]; assert((cast(size_t)p & (size - 1)) == 0); debug (PTRCHECK2) { if (bin < B_PAGE) { // Check that p is not on a free list List *list; for (list = gcx.bucket[bin]; list; list = list.next) { assert(cast(void*)list != p); } } } } } /** * add p to list of roots */ void addRoot(void *p) nothrow { if (!p) { return; } gcx.addRoot(p); } /** * remove p from list of roots */ void removeRoot(void *p) nothrow { if (!p) { return; } gcx.removeRoot(p); } /** * */ @property auto rootIter() @nogc { return &gcx.rootsApply; } /** * add range to scan for roots */ void addRange(void *p, size_t sz, const TypeInfo ti = null) nothrow @nogc { if (!p || !sz) { return; } gcx.addRange(p, p + sz, ti); } /** * remove range */ void removeRange(void *p) nothrow @nogc { if (!p) { return; } gcx.removeRange(p); } /** * */ @property auto rangeIter() @nogc { return &gcx.rangesApply; } /** * run finalizers */ void runFinalizers(in void[] segment) nothrow { static void go(Gcx* gcx, in void[] segment) nothrow { gcx.runFinalizers(segment); } return runLocked!(go, otherTime, numOthers)(gcx, segment); } /** * Do full garbage collection. * Return number of pages free'd. */ size_t fullCollect() nothrow { debug(PRINTF) printf("GC.fullCollect()\n"); // Since a finalizer could launch a new thread, we always need to lock // when collecting. static size_t go(Gcx* gcx) nothrow { return gcx.fullcollect(); } immutable result = runLocked!go(gcx); version (none) { GCStats stats; getStats(stats); debug(PRINTF) printf("poolsize = %zx, usedsize = %zx, freelistsize = %zx\n", stats.poolsize, stats.usedsize, stats.freelistsize); } gcx.log_collect(); return result; } /** * do full garbage collection ignoring roots */ void fullCollectNoStack() nothrow { // Since a finalizer could launch a new thread, we always need to lock // when collecting. static size_t go(Gcx* gcx) nothrow { return gcx.fullcollect(true); } runLocked!go(gcx); } /** * minimize free space usage */ void minimize() nothrow { static void go(Gcx* gcx) nothrow { gcx.minimize(); } runLocked!(go, otherTime, numOthers)(gcx); } /** * Retrieve statistics about garbage collection. * Useful for debugging and tuning. */ void getStats(out GCStats stats) nothrow { return runLocked!(getStatsNoSync, otherTime, numOthers)(stats); } // // // private void getStatsNoSync(out GCStats stats) nothrow { size_t psize = 0; size_t usize = 0; size_t flsize = 0; size_t n; size_t bsize = 0; //debug(PRINTF) printf("getStats()\n"); memset(&stats, 0, GCStats.sizeof); for (n = 0; n < gcx.npools; n++) { Pool *pool = gcx.pooltable[n]; psize += pool.npages * PAGESIZE; for (size_t j = 0; j < pool.npages; j++) { Bins bin = cast(Bins)pool.pagetable[j]; if (bin == B_FREE) stats.freeblocks++; else if (bin == B_PAGE) stats.pageblocks++; else if (bin < B_PAGE) bsize += PAGESIZE; } } for (n = 0; n < B_PAGE; n++) { //debug(PRINTF) printf("bin %d\n", n); for (List *list = gcx.bucket[n]; list; list = list.next) { //debug(PRINTF) printf("\tlist %p\n", list); flsize += binsize[n]; } } usize = bsize - flsize; stats.poolsize = psize; stats.usedsize = bsize - flsize; stats.freelistsize = flsize; } } /* ============================ Gcx =============================== */ enum { PAGESIZE = 4096, POOLSIZE = (4096*256), } enum { B_16, B_32, B_64, B_128, B_256, B_512, B_1024, B_2048, B_PAGE, // start of large alloc B_PAGEPLUS, // continuation of large alloc B_FREE, // free page B_MAX } alias ubyte Bins; struct List { List *next; Pool *pool; } struct Range { void *pbot; void *ptop; alias pbot this; // only consider pbot for relative ordering (opCmp) } struct Root { void *proot; alias proot this; } immutable uint[B_MAX] binsize = [ 16,32,64,128,256,512,1024,2048,4096 ]; immutable size_t[B_MAX] notbinsize = [ ~(16-1),~(32-1),~(64-1),~(128-1),~(256-1), ~(512-1),~(1024-1),~(2048-1),~(4096-1) ]; alias PageBits = GCBits.wordtype[PAGESIZE / 16 / GCBits.BITS_PER_WORD]; static assert(PAGESIZE % (GCBits.BITS_PER_WORD * 16) == 0); private void set(ref PageBits bits, size_t i) @nogc pure nothrow { assert(i < PageBits.sizeof * 8); bts(bits.ptr, i); } /* ============================ Gcx =============================== */ struct Gcx { import core.internal.spinlock; auto rootsLock = shared(AlignedSpinLock)(SpinLock.Contention.brief); auto rangesLock = shared(AlignedSpinLock)(SpinLock.Contention.brief); Treap!Root roots; Treap!Range ranges; bool log; // turn on logging debug(INVARIANT) bool initialized; uint disabled; // turn off collections if >0 import gc.pooltable; @property size_t npools() pure const nothrow { return pooltable.length; } PoolTable!Pool pooltable; List*[B_PAGE] bucket; // free list for each small size // run a collection when reaching those thresholds (number of used pages) float smallCollectThreshold, largeCollectThreshold; uint usedSmallPages, usedLargePages; // total number of mapped pages uint mappedPages; void initialize() { (cast(byte*)&this)[0 .. Gcx.sizeof] = 0; log_init(); roots.initialize(); ranges.initialize(); smallCollectThreshold = largeCollectThreshold = 0.0f; usedSmallPages = usedLargePages = 0; mappedPages = 0; //printf("gcx = %p, self = %x\n", &this, self); debug(INVARIANT) initialized = true; } void Dtor() { if (GC.config.profile) { printf("\tNumber of collections: %llu\n", cast(ulong)numCollections); printf("\tTotal GC prep time: %lld milliseconds\n", prepTime.total!("msecs")); printf("\tTotal mark time: %lld milliseconds\n", markTime.total!("msecs")); printf("\tTotal sweep time: %lld milliseconds\n", sweepTime.total!("msecs")); printf("\tTotal page recovery time: %lld milliseconds\n", recoverTime.total!("msecs")); long maxPause = maxPauseTime.total!("msecs"); printf("\tMax Pause Time: %lld milliseconds\n", maxPause); long gcTime = (recoverTime + sweepTime + markTime + prepTime).total!("msecs"); printf("\tGrand total GC time: %lld milliseconds\n", gcTime); long pauseTime = (markTime + prepTime).total!("msecs"); char[30] apitxt; apitxt[0] = 0; debug(PROFILE_API) if (GC.config.profile > 1) { static Duration toDuration(long dur) { return MonoTime(dur) - MonoTime(0); } printf("\n"); printf("\tmalloc: %llu calls, %lld ms\n", cast(ulong)numMallocs, toDuration(mallocTime).total!"msecs"); printf("\trealloc: %llu calls, %lld ms\n", cast(ulong)numReallocs, toDuration(reallocTime).total!"msecs"); printf("\tfree: %llu calls, %lld ms\n", cast(ulong)numFrees, toDuration(freeTime).total!"msecs"); printf("\textend: %llu calls, %lld ms\n", cast(ulong)numExtends, toDuration(extendTime).total!"msecs"); printf("\tother: %llu calls, %lld ms\n", cast(ulong)numOthers, toDuration(otherTime).total!"msecs"); printf("\tlock time: %lld ms\n", toDuration(lockTime).total!"msecs"); long apiTime = mallocTime + reallocTime + freeTime + extendTime + otherTime + lockTime; printf("\tGC API: %lld ms\n", toDuration(apiTime).total!"msecs"); sprintf(apitxt.ptr, " API%5ld ms", toDuration(apiTime).total!"msecs"); } printf("GC summary:%5lld MB,%5lld GC%5lld ms, Pauses%5lld ms <%5lld ms%s\n", cast(long) maxPoolMemory >> 20, cast(ulong)numCollections, gcTime, pauseTime, maxPause, apitxt.ptr); } debug(INVARIANT) initialized = false; for (size_t i = 0; i < npools; i++) { Pool *pool = pooltable[i]; mappedPages -= pool.npages; pool.Dtor(); cstdlib.free(pool); } assert(!mappedPages); pooltable.Dtor(); roots.removeAll(); ranges.removeAll(); toscan.reset(); } void Invariant() const { } debug(INVARIANT) invariant() { if (initialized) { //printf("Gcx.invariant(): this = %p\n", &this); pooltable.Invariant(); rangesLock.lock(); foreach (range; ranges) { assert(range.pbot); assert(range.ptop); assert(range.pbot <= range.ptop); } rangesLock.unlock(); for (size_t i = 0; i < B_PAGE; i++) { for (auto list = cast(List*)bucket[i]; list; list = list.next) { } } } } /** * */ void addRoot(void *p) nothrow { rootsLock.lock(); scope (failure) rootsLock.unlock(); roots.insert(Root(p)); rootsLock.unlock(); } /** * */ void removeRoot(void *p) nothrow { rootsLock.lock(); scope (failure) rootsLock.unlock(); roots.remove(Root(p)); rootsLock.unlock(); } /** * */ int rootsApply(scope int delegate(ref Root) nothrow dg) nothrow { rootsLock.lock(); scope (failure) rootsLock.unlock(); auto ret = roots.opApply(dg); rootsLock.unlock(); return ret; } /** * */ void addRange(void *pbot, void *ptop, const TypeInfo ti) nothrow @nogc { //debug(PRINTF) printf("Thread %x ", pthread_self()); debug(PRINTF) printf("%p.Gcx::addRange(%p, %p)\n", &this, pbot, ptop); rangesLock.lock(); scope (failure) rangesLock.unlock(); ranges.insert(Range(pbot, ptop)); rangesLock.unlock(); } /** * */ void removeRange(void *pbot) nothrow @nogc { //debug(PRINTF) printf("Thread %x ", pthread_self()); debug(PRINTF) printf("Gcx.removeRange(%p)\n", pbot); rangesLock.lock(); scope (failure) rangesLock.unlock(); ranges.remove(Range(pbot, pbot)); // only pbot is used, see Range.opCmp rangesLock.unlock(); // debug(PRINTF) printf("Wrong thread\n"); // This is a fatal error, but ignore it. // The problem is that we can get a Close() call on a thread // other than the one the range was allocated on. //assert(zero); } /** * */ int rangesApply(scope int delegate(ref Range) nothrow dg) nothrow { rangesLock.lock(); scope (failure) rangesLock.unlock(); auto ret = ranges.opApply(dg); rangesLock.unlock(); return ret; } /** * */ void runFinalizers(in void[] segment) nothrow { GC.inFinalizer = true; scope (failure) GC.inFinalizer = false; foreach (pool; pooltable[0 .. npools]) { if (!pool.finals.nbits) continue; if (pool.isLargeObject) { auto lpool = cast(LargeObjectPool*) pool; lpool.runFinalizers(segment); } else { auto spool = cast(SmallObjectPool*) pool; spool.runFinalizers(segment); } } GC.inFinalizer = false; } Pool* findPool(void* p) pure nothrow { return pooltable.findPool(p); } /** * Find base address of block containing pointer p. * Returns null if not a gc'd pointer */ void* findBase(void *p) nothrow { Pool *pool; pool = findPool(p); if (pool) { size_t offset = cast(size_t)(p - pool.baseAddr); size_t pn = offset / PAGESIZE; Bins bin = cast(Bins)pool.pagetable[pn]; // Adjust bit to be at start of allocated memory block if (bin <= B_PAGE) { return pool.baseAddr + (offset & notbinsize[bin]); } else if (bin == B_PAGEPLUS) { auto pageOffset = pool.bPageOffsets[pn]; offset -= pageOffset * PAGESIZE; pn -= pageOffset; return pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1))); } else { // we are in a B_FREE page assert(bin == B_FREE); return null; } } return null; } /** * Find size of pointer p. * Returns 0 if not a gc'd pointer */ size_t findSize(void *p) nothrow { Pool* pool = findPool(p); if (pool) return pool.slGetSize(p); return 0; } /** * */ BlkInfo getInfo(void* p) nothrow { Pool* pool = findPool(p); if (pool) return pool.slGetInfo(p); return BlkInfo(); } /** * Computes the bin table using CTFE. */ static byte[2049] ctfeBins() nothrow { byte[2049] ret; size_t p = 0; for (Bins b = B_16; b <= B_2048; b++) for ( ; p <= binsize[b]; p++) ret[p] = b; return ret; } static const byte[2049] binTable = ctfeBins(); /** * Allocate a new pool of at least size bytes. * Sort it into pooltable[]. * Mark all memory in the pool as B_FREE. * Return the actual number of bytes reserved or 0 on error. */ size_t reserve(size_t size) nothrow { size_t npages = (size + PAGESIZE - 1) / PAGESIZE; // Assume reserve() is for small objects. Pool* pool = newPool(npages, false); if (!pool) return 0; return pool.npages * PAGESIZE; } /** * Update the thresholds for when to collect the next time */ void updateCollectThresholds() nothrow { static float max(float a, float b) nothrow { return a >= b ? a : b; } // instantly increases, slowly decreases static float smoothDecay(float oldVal, float newVal) nothrow { // decay to 63.2% of newVal over 5 collections // http://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter enum alpha = 1.0 / (5 + 1); immutable decay = (newVal - oldVal) * alpha + oldVal; return max(newVal, decay); } immutable smTarget = usedSmallPages * GC.config.heapSizeFactor; smallCollectThreshold = smoothDecay(smallCollectThreshold, smTarget); immutable lgTarget = usedLargePages * GC.config.heapSizeFactor; largeCollectThreshold = smoothDecay(largeCollectThreshold, lgTarget); } /** * Minimizes physical memory usage by returning free pools to the OS. */ void minimize() nothrow { debug(PRINTF) printf("Minimizing.\n"); foreach (pool; pooltable.minimize()) { debug(PRINTF) printFreeInfo(pool); mappedPages -= pool.npages; pool.Dtor(); cstdlib.free(pool); } debug(PRINTF) printf("Done minimizing.\n"); } private @property bool lowMem() const nothrow { return isLowOnMem(mappedPages * PAGESIZE); } void* alloc(size_t size, ref size_t alloc_size, uint bits) nothrow { return size <= 2048 ? smallAlloc(binTable[size], alloc_size, bits) : bigAlloc(size, alloc_size, bits); } void* smallAlloc(Bins bin, ref size_t alloc_size, uint bits) nothrow { alloc_size = binsize[bin]; void* p; bool tryAlloc() nothrow { if (!bucket[bin]) { bucket[bin] = allocPage(bin); if (!bucket[bin]) return false; } p = bucket[bin]; return true; } if (!tryAlloc()) { if (!lowMem && (disabled || usedSmallPages < smallCollectThreshold)) { // disabled or threshold not reached => allocate a new pool instead of collecting if (!newPool(1, false)) { // out of memory => try to free some memory fullcollect(); if (lowMem) minimize(); } } else { fullcollect(); if (lowMem) minimize(); } // tryAlloc will succeed if a new pool was allocated above, if it fails allocate a new pool now if (!tryAlloc() && (!newPool(1, false) || !tryAlloc())) // out of luck or memory onOutOfMemoryErrorNoGC(); } assert(p !is null); // Return next item from free list bucket[bin] = (cast(List*)p).next; auto pool = (cast(List*)p).pool; if (bits) pool.setBits((p - pool.baseAddr) >> pool.shiftBy, bits); //debug(PRINTF) printf("\tmalloc => %p\n", p); debug (MEMSTOMP) memset(p, 0xF0, alloc_size); return p; } /** * Allocate a chunk of memory that is larger than a page. * Return null if out of memory. */ void* bigAlloc(size_t size, ref size_t alloc_size, uint bits, const TypeInfo ti = null) nothrow { debug(PRINTF) printf("In bigAlloc. Size: %d\n", size); LargeObjectPool* pool; size_t pn; immutable npages = (size + PAGESIZE - 1) / PAGESIZE; bool tryAlloc() nothrow { foreach (p; pooltable[0 .. npools]) { if (!p.isLargeObject || p.freepages < npages) continue; auto lpool = cast(LargeObjectPool*) p; if ((pn = lpool.allocPages(npages)) == OPFAIL) continue; pool = lpool; return true; } return false; } bool tryAllocNewPool() nothrow { pool = cast(LargeObjectPool*) newPool(npages, true); if (!pool) return false; pn = pool.allocPages(npages); assert(pn != OPFAIL); return true; } if (!tryAlloc()) { if (!lowMem && (disabled || usedLargePages < largeCollectThreshold)) { // disabled or threshold not reached => allocate a new pool instead of collecting if (!tryAllocNewPool()) { // disabled but out of memory => try to free some memory fullcollect(); minimize(); } } else { fullcollect(); minimize(); } // If alloc didn't yet succeed retry now that we collected/minimized if (!pool && !tryAlloc() && !tryAllocNewPool()) // out of luck or memory return null; } assert(pool); debug(PRINTF) printFreeInfo(&pool.base); pool.pagetable[pn] = B_PAGE; if (npages > 1) memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1); pool.updateOffsets(pn); usedLargePages += npages; pool.freepages -= npages; debug(PRINTF) printFreeInfo(&pool.base); auto p = pool.baseAddr + pn * PAGESIZE; debug(PRINTF) printf("Got large alloc: %p, pt = %d, np = %d\n", p, pool.pagetable[pn], npages); debug (MEMSTOMP) memset(p, 0xF1, size); alloc_size = npages * PAGESIZE; //debug(PRINTF) printf("\tp = %p\n", p); if (bits) pool.setBits(pn, bits); return p; } /** * Allocate a new pool with at least npages in it. * Sort it into pooltable[]. * Return null if failed. */ Pool *newPool(size_t npages, bool isLargeObject) nothrow { //debug(PRINTF) printf("************Gcx::newPool(npages = %d)****************\n", npages); // Minimum of POOLSIZE size_t minPages = (GC.config.minPoolSize << 20) / PAGESIZE; if (npages < minPages) npages = minPages; else if (npages > minPages) { // Give us 150% of requested size, so there's room to extend auto n = npages + (npages >> 1); if (n < size_t.max/PAGESIZE) npages = n; } // Allocate successively larger pools up to 8 megs if (npools) { size_t n; n = GC.config.minPoolSize + GC.config.incPoolSize * npools; if (n > GC.config.maxPoolSize) n = GC.config.maxPoolSize; // cap pool size n *= (1 << 20) / PAGESIZE; // convert MB to pages if (npages < n) npages = n; } //printf("npages = %d\n", npages); auto pool = cast(Pool *)cstdlib.calloc(1, isLargeObject ? LargeObjectPool.sizeof : SmallObjectPool.sizeof); if (pool) { pool.initialize(npages, isLargeObject); if (!pool.baseAddr || !pooltable.insert(pool)) { pool.Dtor(); cstdlib.free(pool); return null; } } mappedPages += npages; if (GC.config.profile) { if (mappedPages * PAGESIZE > maxPoolMemory) maxPoolMemory = mappedPages * PAGESIZE; } return pool; } /** * Allocate a page of bin's. * Returns: * head of a single linked list of new entries */ List* allocPage(Bins bin) nothrow { //debug(PRINTF) printf("Gcx::allocPage(bin = %d)\n", bin); for (size_t n = 0; n < npools; n++) { Pool* pool = pooltable[n]; if(pool.isLargeObject) continue; if (List* p = (cast(SmallObjectPool*)pool).allocPage(bin)) { ++usedSmallPages; return p; } } return null; } static struct ToScanStack { nothrow: @disable this(this); void reset() { _length = 0; os_mem_unmap(_p, _cap * Range.sizeof); _p = null; _cap = 0; } void push(Range rng) { if (_length == _cap) grow(); _p[_length++] = rng; } Range pop() in { assert(!empty); } body { return _p[--_length]; } ref inout(Range) opIndex(size_t idx) inout in { assert(idx < _length); } body { return _p[idx]; } @property size_t length() const { return _length; } @property bool empty() const { return !length; } private: void grow() { enum initSize = 64 * 1024; // Windows VirtualAlloc granularity immutable ncap = _cap ? 2 * _cap : initSize / Range.sizeof; auto p = cast(Range*)os_mem_map(ncap * Range.sizeof); if (p is null) onOutOfMemoryErrorNoGC(); if (_p !is null) { p[0 .. _length] = _p[0 .. _length]; os_mem_unmap(_p, _cap * Range.sizeof); } _p = p; _cap = ncap; } size_t _length; Range* _p; size_t _cap; } ToScanStack toscan; /** * Search a range of memory values and mark any pointers into the GC pool. */ void mark(void *pbot, void *ptop) nothrow { void **p1 = cast(void **)pbot; void **p2 = cast(void **)ptop; // limit the amount of ranges added to the toscan stack enum FANOUT_LIMIT = 32; size_t stackPos; Range[FANOUT_LIMIT] stack = void; Lagain: size_t pcache = 0; // let dmd allocate a register for this.pools auto pools = pooltable.pools; const highpool = pooltable.npools - 1; const minAddr = pooltable.minAddr; const maxAddr = pooltable.maxAddr; //printf("marking range: [%p..%p] (%#zx)\n", p1, p2, cast(size_t)p2 - cast(size_t)p1); Lnext: for (; p1 < p2; p1++) { auto p = cast(byte *)(*p1); //if (log) debug(PRINTF) printf("\tmark %p\n", p); if (p >= minAddr && p < maxAddr) { if ((cast(size_t)p & ~cast(size_t)(PAGESIZE-1)) == pcache) continue; Pool* pool = void; if (npools > 0) { size_t low = 0; size_t high = highpool; while (true) { size_t mid = (low + high) >> 1; pool = pools[mid]; if (p < pool.baseAddr) high = mid - 1; else if (p >= pool.topAddr) low = mid + 1; else break; if (low > high) continue Lnext; } } else { pool = pools[0]; } size_t offset = cast(size_t)(p - pool.baseAddr); size_t biti = void; size_t pn = offset / PAGESIZE; Bins bin = cast(Bins)pool.pagetable[pn]; void* base = void; //debug(PRINTF) printf("\t\tfound pool %p, base=%p, pn = %zd, bin = %d, biti = x%x\n", pool, pool.baseAddr, pn, bin, biti); // Adjust bit to be at start of allocated memory block if (bin < B_PAGE) { // We don't care abou setting pointsToBase correctly // because it's ignored for small object pools anyhow. auto offsetBase = offset & notbinsize[bin]; biti = offsetBase >> pool.shiftBy; base = pool.baseAddr + offsetBase; //debug(PRINTF) printf("\t\tbiti = x%x\n", biti); if (!pool.mark.set(biti) && !pool.noscan.test(biti)) { stack[stackPos++] = Range(base, base + binsize[bin]); if (stackPos == stack.length) break; } } else if (bin == B_PAGE) { auto offsetBase = offset & notbinsize[bin]; base = pool.baseAddr + offsetBase; biti = offsetBase >> pool.shiftBy; //debug(PRINTF) printf("\t\tbiti = x%x\n", biti); pcache = cast(size_t)p & ~cast(size_t)(PAGESIZE-1); // For the NO_INTERIOR attribute. This tracks whether // the pointer is an interior pointer or points to the // base address of a block. bool pointsToBase = (base == sentinel_sub(p)); if(!pointsToBase && pool.nointerior.nbits && pool.nointerior.test(biti)) continue; if (!pool.mark.set(biti) && !pool.noscan.test(biti)) { stack[stackPos++] = Range(base, base + pool.bPageOffsets[pn] * PAGESIZE); if (stackPos == stack.length) break; } } else if (bin == B_PAGEPLUS) { pn -= pool.bPageOffsets[pn]; base = pool.baseAddr + (pn * PAGESIZE); biti = pn * (PAGESIZE >> pool.shiftBy); pcache = cast(size_t)p & ~cast(size_t)(PAGESIZE-1); if(pool.nointerior.nbits && pool.nointerior.test(biti)) continue; if (!pool.mark.set(biti) && !pool.noscan.test(biti)) { stack[stackPos++] = Range(base, base + pool.bPageOffsets[pn] * PAGESIZE); if (stackPos == stack.length) break; } } else { // Don't mark bits in B_FREE pages assert(bin == B_FREE); continue; } } } Range next=void; if (p1 < p2) { // local stack is full, push it to the global stack assert(stackPos == stack.length); toscan.push(Range(p1, p2)); // reverse order for depth-first-order traversal foreach_reverse (ref rng; stack[0 .. $ - 1]) toscan.push(rng); stackPos = 0; next = stack[$-1]; } else if (stackPos) { // pop range from local stack and recurse next = stack[--stackPos]; } else if (!toscan.empty) { // pop range from global stack and recurse next = toscan.pop(); } else { // nothing more to do return; } p1 = cast(void**)next.pbot; p2 = cast(void**)next.ptop; // printf(" pop [%p..%p] (%#zx)\n", p1, p2, cast(size_t)p2 - cast(size_t)p1); goto Lagain; } // collection step 1: prepare freebits and mark bits void prepare() nothrow { size_t n; Pool* pool; for (n = 0; n < npools; n++) { pool = pooltable[n]; pool.mark.zero(); if(!pool.isLargeObject) pool.freebits.zero(); } debug(COLLECT_PRINTF) printf("Set bits\n"); // Mark each free entry, so it doesn't get scanned for (n = 0; n < B_PAGE; n++) { for (List *list = bucket[n]; list; list = list.next) { pool = list.pool; assert(pool); pool.freebits.set(cast(size_t)(cast(byte*)list - pool.baseAddr) / 16); } } debug(COLLECT_PRINTF) printf("Marked free entries.\n"); for (n = 0; n < npools; n++) { pool = pooltable[n]; if(!pool.isLargeObject) { pool.mark.copy(&pool.freebits); } } } // collection step 2: mark roots and heap void markAll(bool nostack) nothrow { if (!nostack) { debug(COLLECT_PRINTF) printf("\tscan stacks.\n"); // Scan stacks and registers for each paused thread thread_scanAll(&mark); } // Scan roots[] debug(COLLECT_PRINTF) printf("\tscan roots[]\n"); foreach (root; roots) { mark(cast(void*)&root.proot, cast(void*)(&root.proot + 1)); } // Scan ranges[] debug(COLLECT_PRINTF) printf("\tscan ranges[]\n"); //log++; foreach (range; ranges) { debug(COLLECT_PRINTF) printf("\t\t%p .. %p\n", range.pbot, range.ptop); mark(range.pbot, range.ptop); } //log--; } // collection step 3: free all unreferenced objects size_t sweep() nothrow { // Free up everything not marked debug(COLLECT_PRINTF) printf("\tfree'ing\n"); size_t freedLargePages; size_t freed; for (size_t n = 0; n < npools; n++) { size_t pn; Pool* pool = pooltable[n]; if(pool.isLargeObject) { for(pn = 0; pn < pool.npages; pn++) { Bins bin = cast(Bins)pool.pagetable[pn]; if(bin > B_PAGE) continue; size_t biti = pn; if (!pool.mark.test(biti)) { byte *p = pool.baseAddr + pn * PAGESIZE; void* q = sentinel_add(p); sentinel_Invariant(q); if (pool.finals.nbits && pool.finals.clear(biti)) { size_t size = pool.bPageOffsets[pn] * PAGESIZE - SENTINEL_EXTRA; uint attr = pool.getBits(biti); rt_finalizeFromGC(q, size, attr); } pool.clrBits(biti, ~BlkAttr.NONE ^ BlkAttr.FINALIZE); debug(COLLECT_PRINTF) printf("\tcollecting big %p\n", p); log_free(q); pool.pagetable[pn] = B_FREE; if(pn < pool.searchStart) pool.searchStart = pn; freedLargePages++; pool.freepages++; debug (MEMSTOMP) memset(p, 0xF3, PAGESIZE); while (pn + 1 < pool.npages && pool.pagetable[pn + 1] == B_PAGEPLUS) { pn++; pool.pagetable[pn] = B_FREE; // Don't need to update searchStart here because // pn is guaranteed to be greater than last time // we updated it. pool.freepages++; freedLargePages++; debug (MEMSTOMP) { p += PAGESIZE; memset(p, 0xF3, PAGESIZE); } } pool.largestFree = pool.freepages; // invalidate } } } else { for (pn = 0; pn < pool.npages; pn++) { Bins bin = cast(Bins)pool.pagetable[pn]; if (bin < B_PAGE) { immutable size = binsize[bin]; byte *p = pool.baseAddr + pn * PAGESIZE; byte *ptop = p + PAGESIZE; immutable base = pn * (PAGESIZE/16); immutable bitstride = size / 16; bool freeBits; PageBits toFree; for (size_t i; p < ptop; p += size, i += bitstride) { immutable biti = base + i; if (!pool.mark.test(biti)) { void* q = sentinel_add(p); sentinel_Invariant(q); if (pool.finals.nbits && pool.finals.test(biti)) rt_finalizeFromGC(q, size - SENTINEL_EXTRA, pool.getBits(biti)); freeBits = true; toFree.set(i); debug(COLLECT_PRINTF) printf("\tcollecting %p\n", p); log_free(sentinel_add(p)); debug (MEMSTOMP) memset(p, 0xF3, size); freed += size; } } if (freeBits) pool.freePageBits(pn, toFree); } } } } assert(freedLargePages <= usedLargePages); usedLargePages -= freedLargePages; debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n", freed, freedLargePages, npools); return freedLargePages; } // collection step 4: recover pages with no live objects, rebuild free lists size_t recover() nothrow { // init tail list List**[B_PAGE] tail = void; foreach (i, ref next; tail) next = &bucket[i]; // Free complete pages, rebuild free list debug(COLLECT_PRINTF) printf("\tfree complete pages\n"); size_t freedSmallPages; for (size_t n = 0; n < npools; n++) { size_t pn; Pool* pool = pooltable[n]; if(pool.isLargeObject) continue; for (pn = 0; pn < pool.npages; pn++) { Bins bin = cast(Bins)pool.pagetable[pn]; size_t biti; size_t u; if (bin < B_PAGE) { size_t size = binsize[bin]; size_t bitstride = size / 16; size_t bitbase = pn * (PAGESIZE / 16); size_t bittop = bitbase + (PAGESIZE / 16); byte* p; biti = bitbase; for (biti = bitbase; biti < bittop; biti += bitstride) { if (!pool.freebits.test(biti)) goto Lnotfree; } pool.pagetable[pn] = B_FREE; if(pn < pool.searchStart) pool.searchStart = pn; pool.freepages++; freedSmallPages++; continue; Lnotfree: p = pool.baseAddr + pn * PAGESIZE; for (u = 0; u < PAGESIZE; u += size) { biti = bitbase + u / 16; if (!pool.freebits.test(biti)) continue; auto elem = cast(List *)(p + u); elem.pool = pool; *tail[bin] = elem; tail[bin] = &elem.next; } } } } // terminate tail list foreach (ref next; tail) *next = null; assert(freedSmallPages <= usedSmallPages); usedSmallPages -= freedSmallPages; debug(COLLECT_PRINTF) printf("\trecovered pages = %d\n", freedSmallPages); return freedSmallPages; } /** * Return number of full pages free'd. */ size_t fullcollect(bool nostack = false) nothrow { MonoTime start, stop, begin; if (GC.config.profile) { begin = start = currTime; } debug(COLLECT_PRINTF) printf("Gcx.fullcollect()\n"); //printf("\tpool address range = %p .. %p\n", minAddr, maxAddr); { // lock roots and ranges around suspending threads b/c they're not reentrant safe rangesLock.lock(); rootsLock.lock(); scope (exit) { rangesLock.unlock(); rootsLock.unlock(); } thread_suspendAll(); prepare(); if (GC.config.profile) { stop = currTime; prepTime += (stop - start); start = stop; } markAll(nostack); thread_processGCMarks(&isMarked); thread_resumeAll(); } if (GC.config.profile) { stop = currTime; markTime += (stop - start); Duration pause = stop - begin; if (pause > maxPauseTime) maxPauseTime = pause; start = stop; } GC.inFinalizer = true; size_t freedLargePages=void; { scope (failure) GC.inFinalizer = false; freedLargePages = sweep(); GC.inFinalizer = false; } if (GC.config.profile) { stop = currTime; sweepTime += (stop - start); start = stop; } immutable freedSmallPages = recover(); if (GC.config.profile) { stop = currTime; recoverTime += (stop - start); ++numCollections; } updateCollectThresholds(); return freedLargePages + freedSmallPages; } /** * Returns true if the addr lies within a marked block. * * Warning! This should only be called while the world is stopped inside * the fullcollect function. */ int isMarked(void *addr) nothrow { // first, we find the Pool this block is in, then check to see if the // mark bit is clear. auto pool = findPool(addr); if(pool) { auto offset = cast(size_t)(addr - pool.baseAddr); auto pn = offset / PAGESIZE; auto bins = cast(Bins)pool.pagetable[pn]; size_t biti = void; if(bins <= B_PAGE) { biti = (offset & notbinsize[bins]) >> pool.shiftBy; } else if(bins == B_PAGEPLUS) { pn -= pool.bPageOffsets[pn]; biti = pn * (PAGESIZE >> pool.shiftBy); } else // bins == B_FREE { assert(bins == B_FREE); return IsMarked.no; } return pool.mark.test(biti) ? IsMarked.yes : IsMarked.no; } return IsMarked.unknown; } /***** Leak Detector ******/ debug (LOGGING) { LogArray current; LogArray prev; void log_init() { //debug(PRINTF) printf("+log_init()\n"); current.reserve(1000); prev.reserve(1000); //debug(PRINTF) printf("-log_init()\n"); } void log_malloc(void *p, size_t size) nothrow { //debug(PRINTF) printf("+log_malloc(p = %p, size = %zd)\n", p, size); Log log; log.p = p; log.size = size; log.line = GC.line; log.file = GC.file; log.parent = null; GC.line = 0; GC.file = null; current.push(log); //debug(PRINTF) printf("-log_malloc()\n"); } void log_free(void *p) nothrow { //debug(PRINTF) printf("+log_free(%p)\n", p); auto i = current.find(p); if (i == OPFAIL) { debug(PRINTF) printf("free'ing unallocated memory %p\n", p); } else current.remove(i); //debug(PRINTF) printf("-log_free()\n"); } void log_collect() nothrow { //debug(PRINTF) printf("+log_collect()\n"); // Print everything in current that is not in prev debug(PRINTF) printf("New pointers this cycle: --------------------------------\n"); size_t used = 0; for (size_t i = 0; i < current.dim; i++) { auto j = prev.find(current.data[i].p); if (j == OPFAIL) current.data[i].print(); else used++; } debug(PRINTF) printf("All roots this cycle: --------------------------------\n"); for (size_t i = 0; i < current.dim; i++) { void* p = current.data[i].p; if (!findPool(current.data[i].parent)) { auto j = prev.find(current.data[i].p); debug(PRINTF) printf(j == OPFAIL ? "N" : " "); current.data[i].print(); } } debug(PRINTF) printf("Used = %d-------------------------------------------------\n", used); prev.copy(¤t); debug(PRINTF) printf("-log_collect()\n"); } void log_parent(void *p, void *parent) nothrow { //debug(PRINTF) printf("+log_parent()\n"); auto i = current.find(p); if (i == OPFAIL) { debug(PRINTF) printf("parent'ing unallocated memory %p, parent = %p\n", p, parent); Pool *pool; pool = findPool(p); assert(pool); size_t offset = cast(size_t)(p - pool.baseAddr); size_t biti; size_t pn = offset / PAGESIZE; Bins bin = cast(Bins)pool.pagetable[pn]; biti = (offset & notbinsize[bin]); debug(PRINTF) printf("\tbin = %d, offset = x%x, biti = x%x\n", bin, offset, biti); } else { current.data[i].parent = parent; } //debug(PRINTF) printf("-log_parent()\n"); } } else { void log_init() nothrow { } void log_malloc(void *p, size_t size) nothrow { } void log_free(void *p) nothrow { } void log_collect() nothrow { } void log_parent(void *p, void *parent) nothrow { } } } /* ============================ Pool =============================== */ struct Pool { byte* baseAddr; byte* topAddr; GCBits mark; // entries already scanned, or should not be scanned GCBits freebits; // entries that are on the free list GCBits finals; // entries that need finalizer run on them GCBits structFinals;// struct entries that need a finalzier run on them GCBits noscan; // entries that should not be scanned GCBits appendable; // entries that are appendable GCBits nointerior; // interior pointers should be ignored. // Only implemented for large object pools. size_t npages; size_t freepages; // The number of pages not in use. ubyte* pagetable; bool isLargeObject; uint shiftBy; // shift count for the divisor used for determining bit indices. // This tracks how far back we have to go to find the nearest B_PAGE at // a smaller address than a B_PAGEPLUS. To save space, we use a uint. // This limits individual allocations to 16 terabytes, assuming a 4k // pagesize. uint* bPageOffsets; // This variable tracks a conservative estimate of where the first free // page in this pool is, so that if a lot of pages towards the beginning // are occupied, we can bypass them in O(1). size_t searchStart; size_t largestFree; // upper limit for largest free chunk in large object pool void initialize(size_t npages, bool isLargeObject) nothrow { this.isLargeObject = isLargeObject; size_t poolsize; shiftBy = isLargeObject ? 12 : 4; //debug(PRINTF) printf("Pool::Pool(%u)\n", npages); poolsize = npages * PAGESIZE; assert(poolsize >= POOLSIZE); baseAddr = cast(byte *)os_mem_map(poolsize); // Some of the code depends on page alignment of memory pools assert((cast(size_t)baseAddr & (PAGESIZE - 1)) == 0); if (!baseAddr) { //debug(PRINTF) printf("GC fail: poolsize = x%zx, errno = %d\n", poolsize, errno); //debug(PRINTF) printf("message = '%s'\n", sys_errlist[errno]); npages = 0; poolsize = 0; } //assert(baseAddr); topAddr = baseAddr + poolsize; auto nbits = cast(size_t)poolsize >> shiftBy; mark.alloc(nbits); // pagetable already keeps track of what's free for the large object // pool. if(!isLargeObject) { freebits.alloc(nbits); } noscan.alloc(nbits); appendable.alloc(nbits); pagetable = cast(ubyte*)cstdlib.malloc(npages); if (!pagetable) onOutOfMemoryErrorNoGC(); if(isLargeObject) { bPageOffsets = cast(uint*)cstdlib.malloc(npages * uint.sizeof); if (!bPageOffsets) onOutOfMemoryErrorNoGC(); } memset(pagetable, B_FREE, npages); this.npages = npages; this.freepages = npages; this.searchStart = 0; this.largestFree = npages; } void Dtor() nothrow { if (baseAddr) { int result; if (npages) { result = os_mem_unmap(baseAddr, npages * PAGESIZE); assert(result == 0); npages = 0; } baseAddr = null; topAddr = null; } if (pagetable) { cstdlib.free(pagetable); pagetable = null; } if(bPageOffsets) cstdlib.free(bPageOffsets); mark.Dtor(); if(isLargeObject) { nointerior.Dtor(); } else { freebits.Dtor(); } finals.Dtor(); structFinals.Dtor(); noscan.Dtor(); appendable.Dtor(); } /** * */ uint getBits(size_t biti) nothrow { uint bits; if (finals.nbits && finals.test(biti)) bits |= BlkAttr.FINALIZE; if (structFinals.nbits && structFinals.test(biti)) bits |= BlkAttr.STRUCTFINAL; if (noscan.test(biti)) bits |= BlkAttr.NO_SCAN; if (nointerior.nbits && nointerior.test(biti)) bits |= BlkAttr.NO_INTERIOR; if (appendable.test(biti)) bits |= BlkAttr.APPENDABLE; return bits; } /** * */ void clrBits(size_t biti, uint mask) nothrow { immutable dataIndex = biti >> GCBits.BITS_SHIFT; immutable bitOffset = biti & GCBits.BITS_MASK; immutable keep = ~(GCBits.BITS_1 << bitOffset); if (mask & BlkAttr.FINALIZE && finals.nbits) finals.data[dataIndex] &= keep; if (structFinals.nbits && (mask & BlkAttr.STRUCTFINAL)) structFinals.data[dataIndex] &= keep; if (mask & BlkAttr.NO_SCAN) noscan.data[dataIndex] &= keep; if (mask & BlkAttr.APPENDABLE) appendable.data[dataIndex] &= keep; if (nointerior.nbits && (mask & BlkAttr.NO_INTERIOR)) nointerior.data[dataIndex] &= keep; } /** * */ void setBits(size_t biti, uint mask) nothrow { // Calculate the mask and bit offset once and then use it to // set all of the bits we need to set. immutable dataIndex = biti >> GCBits.BITS_SHIFT; immutable bitOffset = biti & GCBits.BITS_MASK; immutable orWith = GCBits.BITS_1 << bitOffset; if (mask & BlkAttr.STRUCTFINAL) { if (!structFinals.nbits) structFinals.alloc(mark.nbits); structFinals.data[dataIndex] |= orWith; } if (mask & BlkAttr.FINALIZE) { if (!finals.nbits) finals.alloc(mark.nbits); finals.data[dataIndex] |= orWith; } if (mask & BlkAttr.NO_SCAN) { noscan.data[dataIndex] |= orWith; } // if (mask & BlkAttr.NO_MOVE) // { // if (!nomove.nbits) // nomove.alloc(mark.nbits); // nomove.data[dataIndex] |= orWith; // } if (mask & BlkAttr.APPENDABLE) { appendable.data[dataIndex] |= orWith; } if (isLargeObject && (mask & BlkAttr.NO_INTERIOR)) { if(!nointerior.nbits) nointerior.alloc(mark.nbits); nointerior.data[dataIndex] |= orWith; } } void freePageBits(size_t pagenum, in ref PageBits toFree) nothrow { assert(!isLargeObject); assert(!nointerior.nbits); // only for large objects import core.internal.traits : staticIota; immutable beg = pagenum * (PAGESIZE / 16 / GCBits.BITS_PER_WORD); foreach (i; staticIota!(0, PageBits.length)) { immutable w = toFree[i]; if (!w) continue; immutable wi = beg + i; freebits.data[wi] |= w; noscan.data[wi] &= ~w; appendable.data[wi] &= ~w; } if (finals.nbits) { foreach (i; staticIota!(0, PageBits.length)) if (toFree[i]) finals.data[beg + i] &= ~toFree[i]; } if (structFinals.nbits) { foreach (i; staticIota!(0, PageBits.length)) if (toFree[i]) structFinals.data[beg + i] &= ~toFree[i]; } } /** * Given a pointer p in the p, return the pagenum. */ size_t pagenumOf(void *p) const nothrow in { assert(p >= baseAddr); assert(p < topAddr); } body { return cast(size_t)(p - baseAddr) / PAGESIZE; } @property bool isFree() const pure nothrow { return npages == freepages; } size_t slGetSize(void* p) nothrow { if (isLargeObject) return (cast(LargeObjectPool*)&this).getSize(p); else return (cast(SmallObjectPool*)&this).getSize(p); } BlkInfo slGetInfo(void* p) nothrow { if (isLargeObject) return (cast(LargeObjectPool*)&this).getInfo(p); else return (cast(SmallObjectPool*)&this).getInfo(p); } void Invariant() const {} debug(INVARIANT) invariant() { //mark.Invariant(); //scan.Invariant(); //freebits.Invariant(); //finals.Invariant(); //structFinals.Invariant(); //noscan.Invariant(); //appendable.Invariant(); //nointerior.Invariant(); if (baseAddr) { //if (baseAddr + npages * PAGESIZE != topAddr) //printf("baseAddr = %p, npages = %d, topAddr = %p\n", baseAddr, npages, topAddr); assert(baseAddr + npages * PAGESIZE == topAddr); } if(pagetable !is null) { for (size_t i = 0; i < npages; i++) { Bins bin = cast(Bins)pagetable[i]; assert(bin < B_MAX); } } } } struct LargeObjectPool { Pool base; alias base this; void updateOffsets(size_t fromWhere) nothrow { assert(pagetable[fromWhere] == B_PAGE); size_t pn = fromWhere + 1; for(uint offset = 1; pn < npages; pn++, offset++) { if(pagetable[pn] != B_PAGEPLUS) break; bPageOffsets[pn] = offset; } // Store the size of the block in bPageOffsets[fromWhere]. bPageOffsets[fromWhere] = cast(uint) (pn - fromWhere); } /** * Allocate n pages from Pool. * Returns OPFAIL on failure. */ size_t allocPages(size_t n) nothrow { if(largestFree < n || searchStart + n > npages) return OPFAIL; //debug(PRINTF) printf("Pool::allocPages(n = %d)\n", n); size_t largest = 0; if (pagetable[searchStart] == B_PAGEPLUS) { searchStart -= bPageOffsets[searchStart]; // jump to B_PAGE searchStart += bPageOffsets[searchStart]; } while (searchStart < npages && pagetable[searchStart] == B_PAGE) searchStart += bPageOffsets[searchStart]; for (size_t i = searchStart; i < npages; ) { assert(pagetable[i] == B_FREE); size_t p = 1; while (p < n && i + p < npages && pagetable[i + p] == B_FREE) p++; if (p == n) return i; if (p > largest) largest = p; i += p; while(i < npages && pagetable[i] == B_PAGE) { // we have the size information, so we skip a whole bunch of pages. i += bPageOffsets[i]; } } // not enough free pages found, remember largest free chunk largestFree = largest; return OPFAIL; } /** * Free npages pages starting with pagenum. */ void freePages(size_t pagenum, size_t npages) nothrow { //memset(&pagetable[pagenum], B_FREE, npages); if(pagenum < searchStart) searchStart = pagenum; for(size_t i = pagenum; i < npages + pagenum; i++) { if(pagetable[i] < B_FREE) { freepages++; } pagetable[i] = B_FREE; } largestFree = freepages; // invalidate } /** * Get size of pointer p in pool. */ size_t getSize(void *p) const nothrow in { assert(p >= baseAddr); assert(p < topAddr); } body { size_t pagenum = pagenumOf(p); Bins bin = cast(Bins)pagetable[pagenum]; assert(bin == B_PAGE); return bPageOffsets[pagenum] * PAGESIZE; } /** * */ BlkInfo getInfo(void* p) nothrow { BlkInfo info; size_t offset = cast(size_t)(p - baseAddr); size_t pn = offset / PAGESIZE; Bins bin = cast(Bins)pagetable[pn]; if (bin == B_PAGEPLUS) pn -= bPageOffsets[pn]; else if (bin != B_PAGE) return info; // no info for free pages info.base = baseAddr + pn * PAGESIZE; info.size = bPageOffsets[pn] * PAGESIZE; info.attr = getBits(pn); return info; } void runFinalizers(in void[] segment) nothrow { foreach (pn; 0 .. npages) { Bins bin = cast(Bins)pagetable[pn]; if (bin > B_PAGE) continue; size_t biti = pn; if (!finals.test(biti)) continue; auto p = sentinel_add(baseAddr + pn * PAGESIZE); size_t size = bPageOffsets[pn] * PAGESIZE - SENTINEL_EXTRA; uint attr = getBits(biti); if(!rt_hasFinalizerInSegment(p, size, attr, segment)) continue; rt_finalizeFromGC(p, size, attr); clrBits(biti, ~BlkAttr.NONE); if (pn < searchStart) searchStart = pn; debug(COLLECT_PRINTF) printf("\tcollecting big %p\n", p); //log_free(sentinel_add(p)); size_t n = 1; for (; pn + n < npages; ++n) if (pagetable[pn + n] != B_PAGEPLUS) break; debug (MEMSTOMP) memset(baseAddr + pn * PAGESIZE, 0xF3, n * PAGESIZE); freePages(pn, n); } } } struct SmallObjectPool { Pool base; alias base this; /** * Get size of pointer p in pool. */ size_t getSize(void *p) const nothrow in { assert(p >= baseAddr); assert(p < topAddr); } body { size_t pagenum = pagenumOf(p); Bins bin = cast(Bins)pagetable[pagenum]; assert(bin < B_PAGE); return binsize[bin]; } BlkInfo getInfo(void* p) nothrow { BlkInfo info; size_t offset = cast(size_t)(p - baseAddr); size_t pn = offset / PAGESIZE; Bins bin = cast(Bins)pagetable[pn]; if (bin >= B_PAGE) return info; info.base = cast(void*)((cast(size_t)p) & notbinsize[bin]); info.size = binsize[bin]; offset = info.base - baseAddr; info.attr = getBits(cast(size_t)(offset >> shiftBy)); return info; } void runFinalizers(in void[] segment) nothrow { foreach (pn; 0 .. npages) { Bins bin = cast(Bins)pagetable[pn]; if (bin >= B_PAGE) continue; immutable size = binsize[bin]; auto p = baseAddr + pn * PAGESIZE; const ptop = p + PAGESIZE; immutable base = pn * (PAGESIZE/16); immutable bitstride = size / 16; bool freeBits; PageBits toFree; for (size_t i; p < ptop; p += size, i += bitstride) { immutable biti = base + i; if (!finals.test(biti)) continue; auto q = sentinel_add(p); uint attr = getBits(biti); if(!rt_hasFinalizerInSegment(q, size, attr, segment)) continue; rt_finalizeFromGC(q, size, attr); freeBits = true; toFree.set(i); debug(COLLECT_PRINTF) printf("\tcollecting %p\n", p); //log_free(sentinel_add(p)); debug (MEMSTOMP) memset(p, 0xF3, size); } if (freeBits) freePageBits(pn, toFree); } } /** * Allocate a page of bin's. * Returns: * head of a single linked list of new entries */ List* allocPage(Bins bin) nothrow { size_t pn; for (pn = searchStart; pn < npages; pn++) if (pagetable[pn] == B_FREE) goto L1; return null; L1: searchStart = pn + 1; pagetable[pn] = cast(ubyte)bin; freepages--; // Convert page to free list size_t size = binsize[bin]; void* p = baseAddr + pn * PAGESIZE; void* ptop = p + PAGESIZE - size; auto first = cast(List*) p; for (; p < ptop; p += size) { (cast(List *)p).next = cast(List *)(p + size); (cast(List *)p).pool = &base; } (cast(List *)p).next = null; (cast(List *)p).pool = &base; return first; } } unittest // bugzilla 14467 { int[] arr = new int[10]; assert(arr.capacity); arr = arr[$..$]; assert(arr.capacity); } unittest // bugzilla 15353 { import core.memory : GC; static struct Foo { ~this() { GC.free(buf); // ignored in finalizer } void* buf; } new Foo(GC.malloc(10)); GC.collect(); } unittest // bugzilla 15822 { import core.memory : GC; ubyte[16] buf; static struct Foo { ~this() { GC.removeRange(ptr); GC.removeRoot(ptr); } ubyte* ptr; } GC.addRoot(buf.ptr); GC.addRange(buf.ptr, buf.length); new Foo(buf.ptr); GC.collect(); } /* ============================ SENTINEL =============================== */ debug (SENTINEL) { const size_t SENTINEL_PRE = cast(size_t) 0xF4F4F4F4F4F4F4F4UL; // 32 or 64 bits const ubyte SENTINEL_POST = 0xF5; // 8 bits const uint SENTINEL_EXTRA = 2 * size_t.sizeof + 1; inout(size_t*) sentinel_size(inout void *p) nothrow { return &(cast(inout size_t *)p)[-2]; } inout(size_t*) sentinel_pre(inout void *p) nothrow { return &(cast(inout size_t *)p)[-1]; } inout(ubyte*) sentinel_post(inout void *p) nothrow { return &(cast(inout ubyte *)p)[*sentinel_size(p)]; } void sentinel_init(void *p, size_t size) nothrow { *sentinel_size(p) = size; *sentinel_pre(p) = SENTINEL_PRE; *sentinel_post(p) = SENTINEL_POST; } void sentinel_Invariant(const void *p) nothrow { debug { assert(*sentinel_pre(p) == SENTINEL_PRE); assert(*sentinel_post(p) == SENTINEL_POST); } else if(*sentinel_pre(p) != SENTINEL_PRE || *sentinel_post(p) != SENTINEL_POST) onInvalidMemoryOperationError(); // also trigger in release build } void *sentinel_add(void *p) nothrow { return p + 2 * size_t.sizeof; } void *sentinel_sub(void *p) nothrow { return p - 2 * size_t.sizeof; } } else { const uint SENTINEL_EXTRA = 0; void sentinel_init(void *p, size_t size) nothrow { } void sentinel_Invariant(const void *p) nothrow { } void *sentinel_add(void *p) nothrow { return p; } void *sentinel_sub(void *p) nothrow { return p; } } debug (MEMSTOMP) unittest { import core.memory; auto p = cast(uint*)GC.malloc(uint.sizeof*3); assert(*p == 0xF0F0F0F0); p[2] = 0; // First two will be used for free list GC.free(p); assert(p[2] == 0xF2F2F2F2); } debug (SENTINEL) unittest { import core.memory; auto p = cast(ubyte*)GC.malloc(1); assert(p[-1] == 0xF4); assert(p[ 1] == 0xF5); /* p[1] = 0; bool thrown; try GC.free(p); catch (Error e) thrown = true; p[1] = 0xF5; assert(thrown); */ } ldc-1.1.0-beta3-src/runtime/druntime/src/etc/0000775000175000017500000000000012776214756017025 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/etc/linux/0000775000175000017500000000000012776214756020164 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/etc/linux/memoryerror.d0000664000175000017500000002013212776214756022711 0ustar kaikai/** * Handle page protection errors using D errors (exceptions). $(D NullPointerError) is * thrown when dereferencing null pointers. A system-dependent error is thrown in other * cases. * * Note: Only x86 and x86_64 are supported for now. * * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE_1_0.txt) * Authors: Amaury SECHET, FeepingCreature, Vladimir Panteleev * Source: $(DRUNTIMESRC src/etc/linux/memory.d) */ module etc.linux.memoryerror; version (CRuntime_Glibc) { version (X86) version = MemoryErrorSupported; version (X86_64) version = MemoryErrorSupported; } version (MemoryErrorSupported): @system: import core.sys.posix.signal; import core.sys.posix.ucontext; // Register and unregister memory error handler. bool registerMemoryErrorHandler() { sigaction_t action; action.sa_sigaction = &handleSignal; action.sa_flags = SA_SIGINFO; auto oldptr = &old_sigaction; return !sigaction(SIGSEGV, &action, oldptr); } bool deregisterMemoryErrorHandler() { auto oldptr = &old_sigaction; return !sigaction(SIGSEGV, oldptr, null); } /** * Thrown on POSIX systems when a SIGSEGV signal is received. */ class InvalidPointerError : Error { this(string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super("", file, line, next); } this(Throwable next, string file = __FILE__, size_t line = __LINE__) { super("", file, line, next); } } /** * Thrown on null pointer dereferences. */ class NullPointerError : InvalidPointerError { this(string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(file, line, next); } this(Throwable next, string file = __FILE__, size_t line = __LINE__) { super(file, line, next); } } version (unittest) { int* getNull() { return null; } } unittest { assert(registerMemoryErrorHandler()); bool b; try { *getNull() = 42; } catch (NullPointerError) { b = true; } assert(b); b = false; try { *getNull() = 42; } catch (InvalidPointerError) { b = true; } assert(b); assert(deregisterMemoryErrorHandler()); } // Signal handler space. private: __gshared sigaction_t old_sigaction; alias typeof(ucontext_t.init.uc_mcontext.gregs[0]) RegType; version (X86_64) { static RegType savedRDI, savedRSI; extern(C) void handleSignal(int signum, siginfo_t* info, void* contextPtr) nothrow { auto context = cast(ucontext_t*)contextPtr; // Save registers into global thread local, to allow recovery. savedRDI = context.uc_mcontext.gregs[REG_RDI]; savedRSI = context.uc_mcontext.gregs[REG_RSI]; // Hijack current context so we call our handler. auto rip = context.uc_mcontext.gregs[REG_RIP]; auto addr = cast(RegType) info.si_addr; context.uc_mcontext.gregs[REG_RDI] = addr; context.uc_mcontext.gregs[REG_RSI] = rip; context.uc_mcontext.gregs[REG_RIP] = cast(RegType) ((rip != addr)?&sigsegvDataHandler:&sigsegvCodeHandler); } // All handler functions must be called with faulting address in RDI and original RIP in RSI. // This function is called when the segfault's cause is to call an invalid function pointer. void sigsegvCodeHandler() { asm { naked; // Handle the stack for an invalid function call (segfault at RIP). // With the return pointer, the stack is now alligned. push RBP; mov RBP, RSP; jmp sigsegvDataHandler; } } void sigsegvDataHandler() { asm { naked; push RSI; // return address (original RIP). push RBP; // old RBP mov RBP, RSP; pushfq; // Save flags. push RAX; // RAX, RCX, RDX, and R8 to R11 are trash registers and must be preserved as local variables. push RCX; push RDX; push R8; push R9; push R10; push R11; // With 10 pushes, the stack is still aligned. // Parameter address is already set as RAX. call sigsegvUserspaceProcess; // Restore RDI and RSI values. call restoreRDI; push RAX; // RDI is in RAX. It is pushed and will be poped back to RDI. call restoreRSI; mov RSI, RAX; pop RDI; // Restore trash registers value. pop R11; pop R10; pop R9; pop R8; pop RDX; pop RCX; pop RAX; popfq; // Restore flags. // Return pop RBP; ret; } } // The return value is stored in EAX and EDX, so this function restore the correct value for theses registers. RegType restoreRDI() { return savedRDI; } RegType restoreRSI() { return savedRSI; } } else version (X86) { static RegType savedEAX, savedEDX; extern(C) void handleSignal(int signum, siginfo_t* info, void* contextPtr) nothrow { auto context = cast(ucontext_t*)contextPtr; // Save registers into global thread local, to allow recovery. savedEAX = context.uc_mcontext.gregs[REG_EAX]; savedEDX = context.uc_mcontext.gregs[REG_EDX]; // Hijack current context so we call our handler. auto eip = context.uc_mcontext.gregs[REG_EIP]; auto addr = cast(RegType) info.si_addr; context.uc_mcontext.gregs[REG_EAX] = addr; context.uc_mcontext.gregs[REG_EDX] = eip; context.uc_mcontext.gregs[REG_EIP] = cast(RegType) ((eip != addr)?&sigsegvDataHandler:&sigsegvCodeHandler); } // All handler functions must be called with faulting address in EAX and original EIP in EDX. // This function is called when the segfault's cause is to call an invalid function pointer. void sigsegvCodeHandler() { asm { naked; // Handle the stack for an invalid function call (segfault at EIP). // 4 bytes are used for function pointer; We need 12 byte to keep stack aligned. sub ESP, 12; mov 8[ESP], EBP; mov EBP, ESP; jmp sigsegvDataHandler; } } void sigsegvDataHandler() { asm { naked; // We jump directly here if we are in a valid function call case. push EDX; // return address (original EIP). push EBP; // old EBP mov EBP, ESP; pushfd; // Save flags. push ECX; // ECX is a trash register and must be preserved as local variable. // 4 pushes have been done. The stack is aligned. // Parameter address is already set as EAX. call sigsegvUserspaceProcess; // Restore register values and return. call restoreRegisters; pop ECX; popfd; // Restore flags. // Return pop EBP; ret; } } // The return value is stored in EAX and EDX, so this function restore the correct value for theses registers. RegType[2] restoreRegisters() { RegType[2] restore; restore[0] = savedEAX; restore[1] = savedEDX; return restore; } } else { static assert(false, "Unsupported architecture."); } // This should be calculated by druntime. // TODO: Add a core.memory function for this. enum PAGE_SIZE = 4096; // The first 64Kb are reserved for detecting null pointer dereferences. enum MEMORY_RESERVED_FOR_NULL_DEREFERENCE = 4096 * 16; // User space handler void sigsegvUserspaceProcess(void* address) { // SEGV_MAPERR, SEGV_ACCERR. // The first page is protected to detect null dereferences. if((cast(size_t) address) < MEMORY_RESERVED_FOR_NULL_DEREFERENCE) { throw new NullPointerError(); } throw new InvalidPointerError(); } ldc-1.1.0-beta3-src/runtime/druntime/src/test_runner.d0000664000175000017500000000272112776214756020771 0ustar kaikaiimport core.runtime, core.time : MonoTime; import core.stdc.stdio; ModuleInfo* getModuleInfo(string name) { foreach (m; ModuleInfo) if (m.name == name) return m; assert(0, "module '"~name~"' not found"); } bool tester() { assert(Runtime.args.length == 2); auto name = Runtime.args[1]; immutable pkg = ".package"; immutable pkgLen = pkg.length; debug string mode = "debug"; else string mode = "release"; static if ((void*).sizeof == 4) mode ~= "32"; else static if ((void*).sizeof == 8) mode ~= "64"; else static assert(0, "You must be from the future!"); if (name.length > pkgLen && name[$ - pkgLen .. $] == pkg) name = name[0 .. $ - pkgLen]; if (auto fp = getModuleInfo(name).unitTest) { try { immutable t0 = MonoTime.currTime; fp(); printf("%.3fs PASS %.*s %.*s\n", (MonoTime.currTime - t0).total!"msecs" / 1000.0, cast(uint)mode.length, mode.ptr, cast(uint)name.length, name.ptr); } catch (Throwable e) { auto msg = e.toString(); printf("****** FAIL %.*s %.*s\n%.*s\n", cast(uint)mode.length, mode.ptr, cast(uint)name.length, name.ptr, cast(uint)msg.length, msg.ptr); return false; } } return true; } shared static this() { Runtime.moduleUnitTester = &tester; } void main() { } ldc-1.1.0-beta3-src/runtime/druntime/src/core/0000775000175000017500000000000012776214756017202 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/0000775000175000017500000000000012776214756020137 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/float_.d0000664000175000017500000000412312776214756021550 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_float.h.html, _float.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_float_.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.float_; extern (C): @trusted: // Constants only. nothrow: @nogc: /// enum FLT_ROUNDS = 1; /// enum FLT_EVAL_METHOD = 2; /// enum FLT_RADIX = 2; /// enum DECIMAL_DIG = real.dig; /// enum FLT_DIG = float.dig; /// enum DBL_DIG = double.dig; /// enum LDBL_DIG = real.dig; /// enum FLT_MANT_DIG = float.mant_dig; /// enum DBL_MANT_DIG = double.mant_dig; /// enum LDBL_MANT_DIG = real.mant_dig; /// enum FLT_MIN = float.min_normal; /// enum DBL_MIN = double.min_normal; /// enum LDBL_MIN = real.min_normal; /// enum FLT_MAX = float.max; /// enum DBL_MAX = double.max; /// enum LDBL_MAX = real.max; /// enum FLT_EPSILON = float.epsilon; /// enum DBL_EPSILON = double.epsilon; /// enum LDBL_EPSILON = real.epsilon; /// enum FLT_MIN_EXP = float.min_exp; /// enum DBL_MIN_EXP = double.min_exp; /// enum LDBL_MIN_EXP = real.min_exp; /// enum FLT_MAX_EXP = float.max_exp; /// enum DBL_MAX_EXP = double.max_exp; /// enum LDBL_MAX_EXP = real.max_exp; /// enum FLT_MIN_10_EXP = float.min_10_exp; /// enum DBL_MIN_10_EXP = double.min_10_exp; /// enum LDBL_MIN_10_EXP = real.min_10_exp; /// enum FLT_MAX_10_EXP = float.max_10_exp; /// enum DBL_MAX_10_EXP = double.max_10_exp; /// enum LDBL_MAX_10_EXP = real.max_10_exp; ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/wctype.d0000664000175000017500000000255512776214756021626 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_wctype.h.html, _wctype.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_wctype.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.wctype; public import core.stdc.wchar_; // for wint_t, WEOF extern (C): @trusted: // Only a couple of functions below operate on unsafe C strings. nothrow: @nogc: /// alias wchar_t wctrans_t; /// alias wchar_t wctype_t; /// pure int iswalnum(wint_t wc); /// pure int iswalpha(wint_t wc); /// pure int iswblank(wint_t wc); /// pure int iswcntrl(wint_t wc); /// pure int iswdigit(wint_t wc); /// pure int iswgraph(wint_t wc); /// pure int iswlower(wint_t wc); /// pure int iswprint(wint_t wc); /// pure int iswpunct(wint_t wc); /// pure int iswspace(wint_t wc); /// pure int iswupper(wint_t wc); /// pure int iswxdigit(wint_t wc); /// int iswctype(wint_t wc, wctype_t desc); /// @system wctype_t wctype(in char* property); /// pure wint_t towlower(wint_t wc); /// pure wint_t towupper(wint_t wc); /// wint_t towctrans(wint_t wc, wctrans_t desc); /// @system wctrans_t wctrans(in char* property); ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/stdio.d0000664000175000017500000007511712776214756021441 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_stdio.h.html, _stdio.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, * Alex Rønne Petersen * Source: $(DRUNTIMESRC core/stdc/_stdio.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.stdio; private { import core.stdc.config; import core.stdc.stdarg; // for va_list import core.stdc.stdint : intptr_t; version (FreeBSD) { import core.sys.posix.sys.types; } else version (OpenBSD) { import core.sys.posix.sys.types; } } extern (C): @system: nothrow: @nogc: version( CRuntime_DigitalMars ) { enum { /// BUFSIZ = 0x4000, /// EOF = -1, /// FOPEN_MAX = 20, /// FILENAME_MAX = 256, // 255 plus NULL /// TMP_MAX = 32767, /// SYS_OPEN = 20, // non-standard } /// enum int _NFILE = 60; // non-standard /// enum string _P_tmpdir = "\\"; // non-standard /// enum wstring _wP_tmpdir = "\\"; // non-standard /// enum int L_tmpnam = _P_tmpdir.length + 12; } else version( CRuntime_Microsoft ) { enum { /// BUFSIZ = 512, /// EOF = -1, /// FOPEN_MAX = 20, /// FILENAME_MAX = 260, /// Actually int.max since Visual Studio 2015. TMP_MAX = 32767, /// _SYS_OPEN = 20, // non-standard } /// enum int _NFILE = 512; // non-standard /// Removed since Visual Studio 2015. enum string _P_tmpdir = "\\"; // non-standard /// Removed since Visual Studio 2015. enum wstring _wP_tmpdir = "\\"; // non-standard /// Actually 260 since Visual Studio 2015. enum int L_tmpnam = _P_tmpdir.length + 12; } else version( CRuntime_Glibc ) { enum { /// BUFSIZ = 8192, /// EOF = -1, /// FOPEN_MAX = 16, /// FILENAME_MAX = 4095, /// TMP_MAX = 238328, /// L_tmpnam = 20 } } else version( OSX ) { enum { /// BUFSIZ = 1024, /// EOF = -1, /// FOPEN_MAX = 20, /// FILENAME_MAX = 1024, /// TMP_MAX = 308915776, /// L_tmpnam = 1024, } private { struct __sbuf { ubyte* _base; int _size; } struct __sFILEX { } } } else version ( FreeBSD ) { enum { /// BUFSIZ = 1024, /// EOF = -1, /// FOPEN_MAX = 20, /// FILENAME_MAX = 1024, /// TMP_MAX = 308915776, /// L_tmpnam = 1024 } struct __sbuf { ubyte *_base; int _size; } union __mbstate_t // { char[128] _mbstate8; long _mbstateL; } } else version ( OpenBSD ) { enum { /// BUFSIZ = 1024, /// EOF = -1, /// FOPEN_MAX = 20, /// FILENAME_MAX = 1024, /// TMP_MAX = 0x7fffffff, /// L_tmpnam = 1024 } struct __sbuf { ubyte *_base; int _size; } union __mbstate_t // { char[128] __mbstate8; long __mbstateL; } } else version (Solaris) { enum { /// BUFSIZ = 1024, /// EOF = -1, /// FOPEN_MAX = _NFILE, /// FILENAME_MAX = 1024, /// TMP_MAX = 17576, /// L_tmpnam = 25, } version (X86) /// enum int _NFILE = 60; else /// enum int _NFILE = 20; } else version( CRuntime_Bionic ) { enum { /// BUFSIZ = 1024, /// EOF = -1, /// FOPEN_MAX = 20, /// FILENAME_MAX = 1024, /// TMP_MAX = 308915776, /// L_tmpnam = 1024 } struct __sbuf { ubyte* _base; int _size; } } else { static assert( false, "Unsupported platform" ); } enum { /// Offset is relative to the beginning SEEK_SET, /// Offset is relative to the current position SEEK_CUR, /// Offset is relative to the end SEEK_END } version( CRuntime_DigitalMars ) { /// alias c_long fpos_t; /// struct _iobuf { char* _ptr; int _cnt; char* _base; int _flag; int _file; int _charbuf; int _bufsiz; char* __tmpnum; } /// alias shared(_iobuf) FILE; } else version( CRuntime_Microsoft ) { /// alias long fpos_t; /// struct _iobuf { void* undefined; } /// alias shared(_iobuf) FILE; } else version( CRuntime_Glibc ) { import core.stdc.wchar_ : mbstate_t; /// struct fpos_t { long __pos; // couldn't use off_t because of static if issue mbstate_t __state; } /// struct _IO_FILE { int _flags; char* _read_ptr; char* _read_end; char* _read_base; char* _write_base; char* _write_ptr; char* _write_end; char* _buf_base; char* _buf_end; char* _save_base; char* _backup_base; char* _save_end; void* _markers; _IO_FILE* _chain; int _fileno; int _blksize; int _old_offset; ushort _cur_column; byte _vtable_offset; char[1] _shortbuf; void* _lock; } /// alias _IO_FILE _iobuf; /// alias shared(_IO_FILE) FILE; } else version( OSX ) { /// alias long fpos_t; /// struct __sFILE { ubyte* _p; int _r; int _w; short _flags; short _file; __sbuf _bf; int _lbfsize; void* _cookie; int function(void*) _close; int function(void*, char*, int) _read; fpos_t function(void*, fpos_t, int) _seek; int function(void*, char *, int) _write; __sbuf _ub; __sFILEX* _extra; int _ur; ubyte[3] _ubuf; ubyte[1] _nbuf; __sbuf _lb; int _blksize; fpos_t _offset; } /// alias __sFILE _iobuf; /// alias shared(__sFILE) FILE; } else version( FreeBSD ) { /// alias off_t fpos_t; /// struct __sFILE { ubyte* _p; int _r; int _w; short _flags; short _file; __sbuf _bf; int _lbfsize; void* _cookie; int function(void*) _close; int function(void*, char*, int) _read; fpos_t function(void*, fpos_t, int) _seek; int function(void*, in char*, int) _write; __sbuf _ub; ubyte* _up; int _ur; ubyte[3] _ubuf; ubyte[1] _nbuf; __sbuf _lb; int _blksize; fpos_t _offset; pthread_mutex_t _fl_mutex; pthread_t _fl_owner; int _fl_count; int _orientation; __mbstate_t _mbstate; } /// alias __sFILE _iobuf; /// alias shared(__sFILE) FILE; } else version( OpenBSD ) { /// alias fpos_t = off_t; /// struct __sFILE { ubyte* _p; int _r; int _w; short _flags; short _file; __sbuf _bf; int _lbfsize; void* _cookie; int function(void*) _close; int function(void*, char*, int) _read; fpos_t function(void*, fpos_t, int) _seek; int function(void*, in char*, int) _write; __sbuf _ext; ubyte* _up; int _ur; ubyte[3] _ubuf; ubyte[1] _nbuf; __sbuf _lb; int _blksize; fpos_t _offset; } /// alias shared(__sFILE) FILE; } else version (Solaris) { import core.stdc.wchar_ : __mbstate_t; /// alias mbstate_t = __mbstate_t; /// alias c_long fpos_t; version (D_LP64) { /// struct _iobuf { char* _ptr; /* next character from/to here in buffer */ char* _base; /* the buffer */ char* _end; /* the end of the buffer */ size_t _cnt; /* number of available characters in buffer */ int _file; /* UNIX System file descriptor */ int _flag; /* the state of the stream */ ubyte[24] _lock; //rmutex_t _lock; /* lock for this structure */ mbstate_t _state; /* mbstate_t */ ubyte[32] __fill; /* filler to bring size to 128 bytes */ } } else { /// struct _iobuf { char* _ptr; int _cnt; char* _base; char _flag; char _magic; ushort __flags; // __orientation:2 // __ionolock:1 // __seekable:1 // __extendedfd:1 // __xf_nocheck:1 // __filler:10 } } /// alias shared(_iobuf) FILE; } else version( CRuntime_Bionic ) { import core.sys.posix.sys.types : off_t; /// alias off_t fpos_t; /// struct __sFILE { ubyte* _p; int _r; int _w; short _flags; short _file; __sbuf _bf; int _lbfsize; void* _cookie; int function(void*) _close; int function(void*, char*, int) _read; fpos_t function(void*, fpos_t, int) _seek; int function(void*, in char*, int) _write; __sbuf _ext; ubyte* _up; int _ur; ubyte[3] _ubuf; ubyte[1] _nbuf; __sbuf _lb; int _blksize; fpos_t _offset; } /// alias __sFILE _iobuf; /// alias shared(__sFILE) FILE; } else { static assert( false, "Unsupported platform" ); } enum { /// _F_RDWR = 0x0003, // non-standard /// _F_READ = 0x0001, // non-standard /// _F_WRIT = 0x0002, // non-standard /// _F_BUF = 0x0004, // non-standard /// _F_LBUF = 0x0008, // non-standard /// _F_ERR = 0x0010, // non-standard /// _F_EOF = 0x0020, // non-standard /// _F_BIN = 0x0040, // non-standard /// _F_IN = 0x0080, // non-standard /// _F_OUT = 0x0100, // non-standard /// _F_TERM = 0x0200, // non-standard } version( CRuntime_DigitalMars ) { enum { /// _IOFBF = 0, /// _IOLBF = 0x40, /// _IONBF = 4, /// _IOREAD = 1, // non-standard /// _IOWRT = 2, // non-standard /// _IOMYBUF = 8, // non-standard /// _IOEOF = 0x10, // non-standard /// _IOERR = 0x20, // non-standard /// _IOSTRG = 0x40, // non-standard /// _IORW = 0x80, // non-standard /// _IOTRAN = 0x100, // non-standard /// _IOAPP = 0x200, // non-standard } extern shared void function() _fcloseallp; private extern shared FILE[_NFILE] _iob; /// shared stdin = &_iob[0]; /// shared stdout = &_iob[1]; /// shared stderr = &_iob[2]; /// shared stdaux = &_iob[3]; /// shared stdprn = &_iob[4]; } else version( CRuntime_Microsoft ) { enum { /// _IOFBF = 0, /// _IOLBF = 0x40, /// _IONBF = 4, /// Removed since Visual Studio 2015. _IOREAD = 1, // non-standard /// Removed since Visual Studio 2015. _IOWRT = 2, // non-standard /// Removed since Visual Studio 2015. _IOMYBUF = 8, // non-standard /// Removed since Visual Studio 2015. _IOEOF = 0x10, // non-standard /// Removed since Visual Studio 2015. _IOERR = 0x20, // non-standard /// Removed since Visual Studio 2015. _IOSTRG = 0x40, // non-standard /// Removed since Visual Studio 2015. _IORW = 0x80, // non-standard /// Removed since Visual Studio 2015. _IOAPP = 0x200, // non-standard /// Removed since Visual Studio 2015. _IOAPPEND = 0x200, // non-standard } extern shared void function() _fcloseallp; /// shared FILE* stdin; // = &__iob_func()[0]; /// shared FILE* stdout; // = &__iob_func()[1]; /// shared FILE* stderr; // = &__iob_func()[2]; } else version( CRuntime_Glibc ) { enum { /// _IOFBF = 0, /// _IOLBF = 1, /// _IONBF = 2, } /// extern shared FILE* stdin; /// extern shared FILE* stdout; /// extern shared FILE* stderr; } else version( OSX ) { enum { /// _IOFBF = 0, /// _IOLBF = 1, /// _IONBF = 2, } private extern shared FILE* __stdinp; private extern shared FILE* __stdoutp; private extern shared FILE* __stderrp; /// alias __stdinp stdin; /// alias __stdoutp stdout; /// alias __stderrp stderr; } else version( FreeBSD ) { enum { /// _IOFBF = 0, /// _IOLBF = 1, /// _IONBF = 2, } private extern shared FILE* __stdinp; private extern shared FILE* __stdoutp; private extern shared FILE* __stderrp; /// alias __stdinp stdin; /// alias __stdoutp stdout; /// alias __stderrp stderr; } else version( OpenBSD ) { enum { /// _IOFBF = 0, /// _IOLBF = 1, /// _IONBF = 2, } private extern shared FILE[] __sF; /// shared stdin = &__sF[0]; /// shared stdout = &__sF[1]; /// shared stderr = &__sF[2]; } else version (Solaris) { enum { /// _IOFBF = 0x00, /// _IOLBF = 0x40, /// _IONBF = 0x04, /// _IOEOF = 0x20, /// _IOERR = 0x40, /// _IOREAD = 0x01, /// _IOWRT = 0x02, /// _IORW = 0x80, /// _IOMYBUF = 0x08, } private extern shared FILE[_NFILE] __iob; /// shared stdin = &__iob[0]; /// shared stdout = &__iob[1]; /// shared stderr = &__iob[2]; } else version( CRuntime_Bionic ) { enum { /// _IOFBF = 0, /// _IOLBF = 1, /// _IONBF = 2, } private extern shared FILE[3] __sF; /// shared stdin = &__sF[0]; /// shared stdout = &__sF[1]; /// shared stderr = &__sF[2]; } else { static assert( false, "Unsupported platform" ); } /// int remove(in char* filename); /// int rename(in char* from, in char* to); /// @trusted FILE* tmpfile(); // No unsafe pointer manipulation. /// char* tmpnam(char* s); /// int fclose(FILE* stream); // No unsafe pointer manipulation. @trusted { /// int fflush(FILE* stream); } /// FILE* fopen(in char* filename, in char* mode); /// FILE* freopen(in char* filename, in char* mode, FILE* stream); /// void setbuf(FILE* stream, char* buf); /// int setvbuf(FILE* stream, char* buf, int mode, size_t size); version (MinGW) { // Prefer the MinGW versions over the MSVC ones, as the latter don't handle // reals at all. /// int __mingw_fprintf(FILE* stream, in char* format, ...); /// alias __mingw_fprintf fprintf; /// int __mingw_fscanf(FILE* stream, in char* format, ...); /// alias __mingw_fscanf fscanf; /// int __mingw_sprintf(char* s, in char* format, ...); /// alias __mingw_sprintf sprintf; /// int __mingw_sscanf(in char* s, in char* format, ...); /// alias __mingw_sscanf sscanf; /// int __mingw_vfprintf(FILE* stream, in char* format, va_list arg); /// alias __mingw_vfprintf vfprintf; /// int __mingw_vfscanf(FILE* stream, in char* format, va_list arg); /// alias __mingw_vfscanf vfscanf; /// int __mingw_vsprintf(char* s, in char* format, va_list arg); /// alias __mingw_vsprintf vsprintf; /// int __mingw_vsscanf(in char* s, in char* format, va_list arg); /// alias __mingw_vsscanf vsscanf; /// int __mingw_vprintf(in char* format, va_list arg); /// alias __mingw_vprintf vprintf; /// int __mingw_vscanf(in char* format, va_list arg); /// alias __mingw_vscanf vscanf; /// int __mingw_printf(in char* format, ...); /// alias __mingw_printf printf; /// int __mingw_scanf(in char* format, ...); /// alias __mingw_scanf scanf; } else { /// int fprintf(FILE* stream, in char* format, ...); /// int fscanf(FILE* stream, in char* format, ...); /// int sprintf(char* s, in char* format, ...); /// int sscanf(in char* s, in char* format, ...); /// int vfprintf(FILE* stream, in char* format, va_list arg); /// int vfscanf(FILE* stream, in char* format, va_list arg); /// int vsprintf(char* s, in char* format, va_list arg); /// int vsscanf(in char* s, in char* format, va_list arg); /// int vprintf(in char* format, va_list arg); /// int vscanf(in char* format, va_list arg); /// int printf(in char* format, ...); /// int scanf(in char* format, ...); } // No unsafe pointer manipulation. @trusted { /// int fgetc(FILE* stream); /// int fputc(int c, FILE* stream); } /// char* fgets(char* s, int n, FILE* stream); /// int fputs(in char* s, FILE* stream); /// char* gets(char* s); /// int puts(in char* s); // No unsafe pointer manipulation. extern (D) @trusted { /// int getchar() { return getc(stdin); } /// int putchar(int c) { return putc(c,stdout); } /// int getc(FILE* stream) { return fgetc(stream); } /// int putc(int c, FILE* stream) { return fputc(c,stream); } } /// @trusted int ungetc(int c, FILE* stream); // No unsafe pointer manipulation. /// size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream); /// size_t fwrite(in void* ptr, size_t size, size_t nmemb, FILE* stream); // No unsafe pointer manipulation. @trusted { /// int fgetpos(FILE* stream, fpos_t * pos); /// int fsetpos(FILE* stream, in fpos_t* pos); /// int fseek(FILE* stream, c_long offset, int whence); /// c_long ftell(FILE* stream); } version( MinGW ) { // No unsafe pointer manipulation. extern (D) @trusted { /// void rewind(FILE* stream) { fseek(stream,0L,SEEK_SET); stream._flag = stream._flag & ~_IOERR; } /// pure void clearerr(FILE* stream) { stream._flag = stream._flag & ~(_IOERR|_IOEOF); } /// pure int feof(FILE* stream) { return stream._flag&_IOEOF; } /// pure int ferror(FILE* stream) { return stream._flag&_IOERR; } } /// int __mingw_snprintf(char* s, size_t n, in char* fmt, ...); /// alias __mingw_snprintf _snprintf; /// alias __mingw_snprintf snprintf; /// int __mingw_vsnprintf(char* s, size_t n, in char* format, va_list arg); /// alias __mingw_vsnprintf _vsnprintf; /// alias __mingw_vsnprintf vsnprintf; uint _set_output_format(uint format); enum _TWO_DIGIT_EXPONENT = 1; intptr_t _get_osfhandle(int fd); int _open_osfhandle(intptr_t osfhandle, int flags); } else version( CRuntime_DigitalMars ) { // No unsafe pointer manipulation. extern (D) @trusted { /// void rewind(FILE* stream) { fseek(stream,0L,SEEK_SET); stream._flag= stream._flag & ~_IOERR; } /// pure void clearerr(FILE* stream) { stream._flag = stream._flag & ~(_IOERR|_IOEOF); } /// pure int feof(FILE* stream) { return stream._flag&_IOEOF; } /// pure int ferror(FILE* stream) { return stream._flag&_IOERR; } /// pure int fileno(FILE* stream) { return stream._file; } } /// int _snprintf(char* s, size_t n, in char* fmt, ...); /// alias _snprintf snprintf; /// int _vsnprintf(char* s, size_t n, in char* format, va_list arg); /// alias _vsnprintf vsnprintf; } else version( CRuntime_Microsoft ) { // No unsafe pointer manipulation. @trusted { /// void rewind(FILE* stream); /// pure void clearerr(FILE* stream); /// pure int feof(FILE* stream); /// pure int ferror(FILE* stream); /// pure int fileno(FILE* stream); } /// int _snprintf(char* s, size_t n, in char* format, ...); /// int snprintf(char* s, size_t n, in char* format, ...); /// int _vsnprintf(char* s, size_t n, in char* format, va_list arg); /// int vsnprintf(char* s, size_t n, in char* format, va_list arg); /// int _fputc_nolock(int c, FILE *fp); /// int _fgetc_nolock(FILE *fp); /// int _lock_file(FILE *fp); /// int _unlock_file(FILE *fp); /// intptr_t _get_osfhandle(int fd); /// int _open_osfhandle(intptr_t osfhandle, int flags); } else version( CRuntime_Glibc ) { // No unsafe pointer manipulation. @trusted { /// void rewind(FILE* stream); /// pure void clearerr(FILE* stream); /// pure int feof(FILE* stream); /// pure int ferror(FILE* stream); /// int fileno(FILE *); } /// int snprintf(char* s, size_t n, in char* format, ...); /// int vsnprintf(char* s, size_t n, in char* format, va_list arg); } else version( OSX ) { // No unsafe pointer manipulation. @trusted { /// void rewind(FILE*); /// pure void clearerr(FILE*); /// pure int feof(FILE*); /// pure int ferror(FILE*); /// int fileno(FILE*); } /// int snprintf(char* s, size_t n, in char* format, ...); /// int vsnprintf(char* s, size_t n, in char* format, va_list arg); } else version( FreeBSD ) { // No unsafe pointer manipulation. @trusted { /// void rewind(FILE*); /// pure void clearerr(FILE*); /// pure int feof(FILE*); /// pure int ferror(FILE*); /// int fileno(FILE*); } /// int snprintf(char* s, size_t n, in char* format, ...); /// int vsnprintf(char* s, size_t n, in char* format, va_list arg); } else version( OpenBSD ) { // No unsafe pointer manipulation. @trusted { /// void rewind(FILE*); } @trusted private { /// pure void clearerr(FILE*); alias __clearerr = clearerr; /// pure int feof(FILE*); alias __feof = feof; /// pure int ferror(FILE*); alias __ferror = ferror; /// int fileno(FILE*); alias __fileno = fileno; } enum __SLBF = 0x0001; enum __SNBF = 0x0002; enum __SRD = 0x0004; enum __SWR = 0x0008; enum __SRW = 0x0010; enum __SEOF = 0x0020; enum __SERR = 0x0040; enum __SMBF = 0x0080; enum __SAPP = 0x0100; enum __SSTR = 0x0200; enum __SOPT = 0x0400; enum __SNPT = 0x0800; enum __SOFF = 0x1000; enum __SMOD = 0x2000; enum __SALC = 0x4000; enum __SIGN = 0x8000; extern int __isthreaded; extern (D) { void __sclearerr(FILE* p) { p._flags &= ~(__SERR|__SEOF); } int __sfeof(FILE* p) { return (p._flags & __SEOF) != 0; } int __sferror(FILE* p) { return (p._flags & __SERR) != 0; } int __sfileno(FILE* p) { return p._file; } int clearerr(FILE* file) { return !__isthreaded ? __sclearerr(file) : __clearerr(file); } int feof(FILE* file) { return !__isthreaded ? __sfeof(file) : __feof(file); } int ferror(FILE* file) { return !__isthreaded ? __sferror(file) : __ferror(file); } int fileno(FILE* file) { return !__isthreaded ? __sfileno(file) : __fileno(file); } } /// int snprintf(char* s, size_t n, in char* format, ...); /// int vsnprintf(char* s, size_t n, in char* format, va_list arg); } else version (Solaris) { // No unsafe pointer manipulation. @trusted { /// void rewind(FILE*); /// pure void clearerr(FILE*); /// pure int feof(FILE*); /// pure int ferror(FILE*); /// int fileno(FILE*); } /// int snprintf(char* s, size_t n, in char* format, ...); /// int vsnprintf(char* s, size_t n, in char* format, va_list arg); } else version( CRuntime_Bionic ) { // No unsafe pointer manipulation. @trusted { /// void rewind(FILE*); /// pure void clearerr(FILE*); /// pure int feof(FILE*); /// pure int ferror(FILE*); /// int fileno(FILE*); } /// int snprintf(char* s, size_t n, in char* format, ...); /// int vsnprintf(char* s, size_t n, in char* format, va_list arg); } else { static assert( false, "Unsupported platform" ); } /// void perror(in char* s); version(CRuntime_DigitalMars) { import core.sys.windows.windows; enum { /// FHND_APPEND = 0x04, /// FHND_DEVICE = 0x08, /// FHND_TEXT = 0x10, /// FHND_BYTE = 0x20, /// FHND_WCHAR = 0x40, } private enum _MAX_SEMAPHORES = 10 + _NFILE; private enum _semIO = 3; private extern __gshared short[_MAX_SEMAPHORES] _iSemLockCtrs; private extern __gshared int[_MAX_SEMAPHORES] _iSemThreadIds; private extern __gshared int[_MAX_SEMAPHORES] _iSemNestCount; private extern __gshared HANDLE[_NFILE] _osfhnd; extern shared ubyte[_NFILE] __fhnd_info; private void _WaitSemaphore(int iSemaphore); private void _ReleaseSemaphore(int iSemaphore); // this is copied from semlock.h in DMC's runtime. private void LockSemaphore(uint num) { asm nothrow @nogc { mov EDX, num; lock; inc _iSemLockCtrs[EDX * 2]; jz lsDone; push EDX; call _WaitSemaphore; add ESP, 4; } lsDone: {} } // this is copied from semlock.h in DMC's runtime. private void UnlockSemaphore(uint num) { asm nothrow @nogc { mov EDX, num; lock; dec _iSemLockCtrs[EDX * 2]; js usDone; push EDX; call _ReleaseSemaphore; add ESP, 4; } usDone: {} } // This converts a HANDLE to a file descriptor in DMC's runtime /// int _handleToFD(HANDLE h, int flags) { LockSemaphore(_semIO); scope(exit) UnlockSemaphore(_semIO); foreach (fd; 0 .. _NFILE) { if (!_osfhnd[fd]) { _osfhnd[fd] = h; __fhnd_info[fd] = cast(ubyte)flags; return fd; } } return -1; } /// HANDLE _fdToHandle(int fd) { // no semaphore is required, once inserted, a file descriptor // doesn't change. if (fd < 0 || fd >= _NFILE) return null; return _osfhnd[fd]; } enum { /// STDIN_FILENO = 0, /// STDOUT_FILENO = 1, /// STDERR_FILENO = 2, } int open(const(char)* filename, int flags, ...); /// alias _open = open; /// int _wopen(const wchar* filename, int oflag, ...); /// int sopen(const char* filename, int oflag, int shflag, ...); /// alias _sopen = sopen; /// int _wsopen(const wchar* filename, int oflag, int shflag, ...); /// int close(int fd); /// alias _close = close; /// FILE *fdopen(int fd, const(char)* flags); /// alias _fdopen = fdopen; /// FILE *_wfdopen(int fd, const(wchar)* flags); /// } else version (CRuntime_Microsoft) { int _open(const char* filename, int oflag, ...); /// int _wopen(const wchar* filename, int oflag, ...); /// int _sopen(const char* filename, int oflag, int shflag, ...); /// int _wsopen(const wchar* filename, int oflag, int shflag, ...); /// int _close(int fd); /// FILE *_fdopen(int fd, const(char)* flags); /// FILE *_wfdopen(int fd, const(wchar)* flags); /// } version (Windows) { // file open flags enum { _O_RDONLY = 0x0000, /// O_RDONLY = _O_RDONLY, /// _O_WRONLY = 0x0001, /// O_WRONLY = _O_WRONLY, /// _O_RDWR = 0x0002, /// O_RDWR = _O_RDWR, /// _O_APPEND = 0x0008, /// O_APPEND = _O_APPEND, /// _O_CREAT = 0x0100, /// O_CREAT = _O_CREAT, /// _O_TRUNC = 0x0200, /// O_TRUNC = _O_TRUNC, /// _O_EXCL = 0x0400, /// O_EXCL = _O_EXCL, /// _O_TEXT = 0x4000, /// O_TEXT = _O_TEXT, /// _O_BINARY = 0x8000, /// O_BINARY = _O_BINARY, /// } enum { _S_IREAD = 0x0100, /// read permission, owner S_IREAD = _S_IREAD, /// read permission, owner _S_IWRITE = 0x0080, /// write permission, owner S_IWRITE = _S_IWRITE, /// write permission, owner } enum { _SH_DENYRW = 0x10, /// deny read/write mode SH_DENYRW = _SH_DENYRW, /// deny read/write mode _SH_DENYWR = 0x20, /// deny write mode SH_DENYWR = _SH_DENYWR, /// deny write mode _SH_DENYRD = 0x30, /// deny read mode SH_DENYRD = _SH_DENYRD, /// deny read mode _SH_DENYNO = 0x40, /// deny none mode SH_DENYNO = _SH_DENYNO, /// deny none mode } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/math.d0000664000175000017500000020572312776214756021246 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_math.h.html, _math.h) * * Copyright: Copyright Sean Kelly 2005 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_math.d) */ module core.stdc.math; private import core.stdc.config; extern (C): @trusted: // All functions here operate on floating point and integer values only. nothrow: pure: @nogc: /// alias float float_t; /// alias double double_t; /// enum double HUGE_VAL = double.infinity; /// enum double HUGE_VALF = float.infinity; /// enum double HUGE_VALL = real.infinity; /// enum float INFINITY = float.infinity; /// enum float NAN = float.nan; version (FreeBSD) { /// enum int FP_ILOGB0 = -int.max; /// enum int FP_ILOGBNAN = int.max; } else version (OpenBSD) { /// enum int FP_ILOGB0 = -int.max; /// enum int FP_ILOGBNAN = int.max; } else version (CRuntime_Bionic) { /// enum int FP_ILOGB0 = -int.max; /// enum int FP_ILOGBNAN = int.max; } else { /// enum int FP_ILOGB0 = int.min; /// enum int FP_ILOGBNAN = int.min; } /// enum int MATH_ERRNO = 1; /// enum int MATH_ERREXCEPT = 2; /// enum int math_errhandling = MATH_ERRNO | MATH_ERREXCEPT; version( none ) { // // these functions are all macros in C // //int fpclassify(real-floating x); int fpclassify(float x); int fpclassify(double x); int fpclassify(real x); //int isfinite(real-floating x); int isfinite(float x); int isfinite(double x); int isfinite(real x); //int isinf(real-floating x); int isinf(float x); int isinf(double x); int isinf(real x); //int isnan(real-floating x); int isnan(float x); int isnan(double x); int isnan(real x); //int isnormal(real-floating x); int isnormal(float x); int isnormal(double x); int isnormal(real x); //int signbit(real-floating x); int signbit(float x); int signbit(double x); int signbit(real x); //int isgreater(real-floating x, real-floating y); int isgreater(float x, float y); int isgreater(double x, double y); int isgreater(real x, real y); //int isgreaterequal(real-floating x, real-floating y); int isgreaterequal(float x, float y); int isgreaterequal(double x, double y); int isgreaterequal(real x, real y); //int isless(real-floating x, real-floating y); int isless(float x, float y); int isless(double x, double y); int isless(real x, real y); //int islessequal(real-floating x, real-floating y); int islessequal(float x, float y); int islessequal(double x, double y); int islessequal(real x, real y); //int islessgreater(real-floating x, real-floating y); int islessgreater(float x, float y); int islessgreater(double x, double y); int islessgreater(real x, real y); //int isunordered(real-floating x, real-floating y); int isunordered(float x, float y); int isunordered(double x, double y); int isunordered(real x, real y); } version( CRuntime_DigitalMars ) { enum { /// FP_NANS = 0, /// FP_NANQ = 1, /// FP_INFINITE = 2, /// FP_NORMAL = 3, /// FP_SUBNORMAL = 4, /// FP_ZERO = 5, /// FP_NAN = FP_NANQ, /// FP_EMPTY = 6, /// FP_UNSUPPORTED = 7, } enum { /// FP_FAST_FMA = 0, /// FP_FAST_FMAF = 0, /// FP_FAST_FMAL = 0, } uint __fpclassify_f(float x); uint __fpclassify_d(double x); uint __fpclassify_ld(real x); extern (D) { //int fpclassify(real-floating x); /// int fpclassify(float x) { return __fpclassify_f(x); } /// int fpclassify(double x) { return __fpclassify_d(x); } /// int fpclassify(real x) { return (real.sizeof == double.sizeof) ? __fpclassify_d(x) : __fpclassify_ld(x); } //int isfinite(real-floating x); /// int isfinite(float x) { return fpclassify(x) >= FP_NORMAL; } /// int isfinite(double x) { return fpclassify(x) >= FP_NORMAL; } /// int isfinite(real x) { return fpclassify(x) >= FP_NORMAL; } //int isinf(real-floating x); /// int isinf(float x) { return fpclassify(x) == FP_INFINITE; } /// int isinf(double x) { return fpclassify(x) == FP_INFINITE; } /// int isinf(real x) { return fpclassify(x) == FP_INFINITE; } //int isnan(real-floating x); /// int isnan(float x) { return fpclassify(x) <= FP_NANQ; } /// int isnan(double x) { return fpclassify(x) <= FP_NANQ; } /// int isnan(real x) { return fpclassify(x) <= FP_NANQ; } //int isnormal(real-floating x); /// int isnormal(float x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal(double x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal(real x) { return fpclassify(x) == FP_NORMAL; } //int signbit(real-floating x); /// int signbit(float x) { return (cast(short*)&(x))[1] & 0x8000; } /// int signbit(double x) { return (cast(short*)&(x))[3] & 0x8000; } /// int signbit(real x) { return (real.sizeof == double.sizeof) ? (cast(short*)&(x))[3] & 0x8000 : (cast(short*)&(x))[4] & 0x8000; } } } else version( CRuntime_Microsoft ) // fully supported since MSVCRT 12 (VS 2013) only { version( all ) // legacy stuff to be removed in the future { enum { _FPCLASS_SNAN = 1, _FPCLASS_QNAN = 2, _FPCLASS_NINF = 4, _FPCLASS_NN = 8, _FPCLASS_ND = 0x10, _FPCLASS_NZ = 0x20, _FPCLASS_PZ = 0x40, _FPCLASS_PD = 0x80, _FPCLASS_PN = 0x100, _FPCLASS_PINF = 0x200, } //deprecated("Please use the standard C99 function copysignf() instead.") float _copysignf(float x, float s); //deprecated("_chgsignf(x) is a non-standard MS extension. Please consider using -x instead.") float _chgsignf(float x); version( Win64 ) // not available in 32-bit runtimes { //deprecated("Please use the standard C99 function isfinite() instead.") int _finitef(float x); //deprecated("Please use the standard C99 function isnan() instead.") int _isnanf(float x); //deprecated("Please use the standard C99 function fpclassify() instead.") int _fpclassf(float x); } //deprecated("Please use the standard C99 function copysign() instead.") double _copysign(double x, double s); //deprecated("_chgsign(x) is a non-standard MS extension. Please consider using -x instead.") double _chgsign(double x); //deprecated("Please use the standard C99 function isfinite() instead.") int _finite(double x); //deprecated("Please use the standard C99 function isnan() instead.") int _isnan(double x); //deprecated("Please use the standard C99 function fpclassify() instead.") int _fpclass(double x); } enum { /// FP_SUBNORMAL = -2, /// FP_NORMAL = -1, /// FP_ZERO = 0, /// FP_INFINITE = 1, /// FP_NAN = 2, } private short _fdclass(float x); private short _dclass(double x); private int _fdsign(float x); private int _dsign(double x); extern(D) { //int fpclassify(real-floating x); /// int fpclassify()(float x) { return _fdclass(x); } /// int fpclassify()(double x) { return _dclass(x); } /// int fpclassify()(real x) { static if (real.sizeof == double.sizeof) return _dclass(cast(double) x); else static assert(false, "fpclassify(real) not supported by MS C runtime"); } //int isfinite(real-floating x); /// int isfinite()(float x) { return fpclassify(x) <= 0; } /// int isfinite()(double x) { return fpclassify(x) <= 0; } /// int isfinite()(real x) { return fpclassify(x) <= 0; } //int isinf(real-floating x); /// int isinf()(float x) { return fpclassify(x) == FP_INFINITE; } /// int isinf()(double x) { return fpclassify(x) == FP_INFINITE; } /// int isinf()(real x) { return fpclassify(x) == FP_INFINITE; } //int isnan(real-floating x); version( none ) // requires MSVCRT 12+ (VS 2013) { /// int isnan(float x) { return fpclassify(x) == FP_NAN; } /// int isnan(double x) { return fpclassify(x) == FP_NAN; } /// int isnan(real x) { return fpclassify(x) == FP_NAN; } } else // for backward compatibility with older runtimes { /// int isnan(float x) { version(Win64) return _isnanf(x); else return _isnan(cast(double) x); } /// int isnan(double x) { return _isnan(x); } /// int isnan(real x) { return _isnan(cast(double) x); } } //int isnormal(real-floating x); /// int isnormal()(float x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal()(double x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal()(real x) { return fpclassify(x) == FP_NORMAL; } //int signbit(real-floating x); /// int signbit()(float x) { return _fdsign(x); } /// int signbit()(double x) { return _dsign(x); } /// int signbit()(real x) { static if (real.sizeof == double.sizeof) return _dsign(cast(double) x); else return (cast(short*)&(x))[4] & 0x8000; } } } else version( CRuntime_Glibc ) { enum { /// FP_NAN, /// FP_INFINITE, /// FP_ZERO, /// FP_SUBNORMAL, /// FP_NORMAL, } enum { /// FP_FAST_FMA = 0, /// FP_FAST_FMAF = 0, /// FP_FAST_FMAL = 0, } int __fpclassifyf(float x); int __fpclassify(double x); int __fpclassifyl(real x); int __finitef(float x); int __finite(double x); int __finitel(real x); int __isinff(float x); int __isinf(double x); int __isinfl(real x); int __isnanf(float x); int __isnan(double x); int __isnanl(real x); int __signbitf(float x); int __signbit(double x); int __signbitl(real x); extern (D) { //int fpclassify(real-floating x); /// int fpclassify(float x) { return __fpclassifyf(x); } /// int fpclassify(double x) { return __fpclassify(x); } /// int fpclassify(real x) { return (real.sizeof == double.sizeof) ? __fpclassify(x) : __fpclassifyl(x); } //int isfinite(real-floating x); /// int isfinite(float x) { return __finitef(x); } /// int isfinite(double x) { return __finite(x); } /// int isfinite(real x) { return (real.sizeof == double.sizeof) ? __finite(x) : __finitel(x); } //int isinf(real-floating x); /// int isinf(float x) { return __isinff(x); } /// int isinf(double x) { return __isinf(x); } /// int isinf(real x) { return (real.sizeof == double.sizeof) ? __isinf(x) : __isinfl(x); } //int isnan(real-floating x); /// int isnan(float x) { return __isnanf(x); } /// int isnan(double x) { return __isnan(x); } /// int isnan(real x) { return (real.sizeof == double.sizeof) ? __isnan(x) : __isnanl(x); } //int isnormal(real-floating x); /// int isnormal(float x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal(double x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal(real x) { return fpclassify(x) == FP_NORMAL; } //int signbit(real-floating x); /// int signbit(float x) { return __signbitf(x); } /// int signbit(double x) { return __signbit(x); } /// int signbit(real x) { return (real.sizeof == double.sizeof) ? __signbit(x) : __signbitl(x); } } } else version( MinGW ) { enum { /// FP_NAN = 0x0100, /// FP_NORMAL = 0x0400, /// FP_INFINITE = FP_NAN | FP_NORMAL, /// FP_ZERO = 0x0400, /// FP_SUBNORMAL = FP_NORMAL | FP_ZERO } int __fpclassifyf(float x); int __fpclassify(double x); int __fpclassifyl(real x); int __isnanf(float x); int __isnan(double x); int __isnanl(real x); int __signbitf(float x); int __signbit(double x); int __signbitl(real x); extern (D) { //int fpclassify(real-floating x); /// int fpclassify(float x) { return __fpclassifyf(x); } /// int fpclassify(double x) { return __fpclassify(x); } /// int fpclassify(real x) { return (real.sizeof == double.sizeof) ? __fpclassify(x) : __fpclassifyl(x); } //int isfinite(real-floating x); /// int isfinite(float x) { return (fpclassify(x) & FP_NORMAL) == 0; } /// int isfinite(double x) { return (fpclassify(x) & FP_NORMAL) == 0; } /// int isfinite(real x) { return (fpclassify(x) & FP_NORMAL) == 0; } //int isinf(real-floating x); /// int isinf(float x) { return fpclassify(x) == FP_INFINITE; } /// int isinf(double x) { return fpclassify(x) == FP_INFINITE; } /// int isinf(real x) { return fpclassify(x) == FP_INFINITE; } //int isnan(real-floating x); /// int isnan(float x) { return __isnanf(x); } /// int isnan(double x) { return __isnan(x); } /// int isnan(real x) { return (real.sizeof == double.sizeof) ? __isnan(x) : __isnanl(x); } //int isnormal(real-floating x); /// int isnormal(float x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal(double x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal(real x) { return fpclassify(x) == FP_NORMAL; } //int signbit(real-floating x); /// int signbit(float x) { return __signbitf(x); } /// int signbit(double x) { return __signbit(x); } /// int signbit(real x) { return (real.sizeof == double.sizeof) ? __signbit(x) : __signbitl(x); } } } else version( OSX ) { enum { /// FP_NAN = 1, /// FP_INFINITE = 2, /// FP_ZERO = 3, /// FP_NORMAL = 4, /// FP_SUBNORMAL = 5, /// FP_SUPERNORMAL = 6, } enum { /// FP_FAST_FMA = 0, /// FP_FAST_FMAF = 0, /// FP_FAST_FMAL = 0, } int __fpclassifyf(float x); int __fpclassifyd(double x); int __fpclassify(real x); int __isfinitef(float x); int __isfinited(double x); int __isfinite(real x); int __isinff(float x); int __isinfd(double x); int __isinf(real x); int __isnanf(float x); int __isnand(double x); int __isnan(real x); int __signbitf(float x); int __signbitd(double x); int __signbitl(real x); extern (D) { //int fpclassify(real-floating x); /// int fpclassify(float x) { return __fpclassifyf(x); } /// int fpclassify(double x) { return __fpclassifyd(x); } /// int fpclassify(real x) { return (real.sizeof == double.sizeof) ? __fpclassifyd(x) : __fpclassify(x); } //int isfinite(real-floating x); /// int isfinite(float x) { return __isfinitef(x); } /// int isfinite(double x) { return __isfinited(x); } /// int isfinite(real x) { return (real.sizeof == double.sizeof) ? __isfinited(x) : __isfinite(x); } //int isinf(real-floating x); /// int isinf(float x) { return __isinff(x); } /// int isinf(double x) { return __isinfd(x); } /// int isinf(real x) { return (real.sizeof == double.sizeof) ? __isinfd(x) : __isinf(x); } //int isnan(real-floating x); /// int isnan(float x) { return __isnanf(x); } /// int isnan(double x) { return __isnand(x); } /// int isnan(real x) { return (real.sizeof == double.sizeof) ? __isnand(x) : __isnan(x); } //int isnormal(real-floating x); /// int isnormal(float x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal(double x) { return fpclassify(x) == FP_NORMAL; } /// int isnormal(real x) { return fpclassify(x) == FP_NORMAL; } //int signbit(real-floating x); /// int signbit(float x) { return __signbitf(x); } /// int signbit(double x) { return __signbitd(x); } /// int signbit(real x) { return (real.sizeof == double.sizeof) ? __signbitd(x) : __signbitl(x); } } } else version( FreeBSD ) { enum { /// FP_INFINITE = 0x01, /// FP_NAN = 0x02, /// FP_NORMAL = 0x04, /// FP_SUBNORMAL = 0x08, /// FP_ZERO = 0x10, } enum { /// FP_FAST_FMA = 0, /// FP_FAST_FMAF = 0, /// FP_FAST_FMAL = 0, } int __fpclassifyd(double); int __fpclassifyf(float); int __fpclassifyl(real); int __isfinitef(float); int __isfinite(double); int __isfinitel(real); int __isinff(float); int __isinfl(real); int __isnanl(real); int __isnormalf(float); int __isnormal(double); int __isnormall(real); int __signbit(double); int __signbitf(float); int __signbitl(real); extern (D) { //int fpclassify(real-floating x); /// int fpclassify(float x) { return __fpclassifyf(x); } /// int fpclassify(double x) { return __fpclassifyd(x); } /// int fpclassify(real x) { return __fpclassifyl(x); } //int isfinite(real-floating x); /// int isfinite(float x) { return __isfinitef(x); } /// int isfinite(double x) { return __isfinite(x); } /// int isfinite(real x) { return __isfinitel(x); } //int isinf(real-floating x); /// int isinf(float x) { return __isinff(x); } /// int isinf(double x) { return __isinfl(x); } /// int isinf(real x) { return __isinfl(x); } //int isnan(real-floating x); /// int isnan(float x) { return __isnanl(x); } /// int isnan(double x) { return __isnanl(x); } /// int isnan(real x) { return __isnanl(x); } //int isnormal(real-floating x); /// int isnormal(float x) { return __isnormalf(x); } /// int isnormal(double x) { return __isnormal(x); } /// int isnormal(real x) { return __isnormall(x); } //int signbit(real-floating x); /// int signbit(float x) { return __signbitf(x); } /// int signbit(double x) { return __signbit(x); } /// int signbit(real x) { return __signbit(x); } } } else version( OpenBSD ) { enum { /// FP_INFINITE = 0x01, /// FP_NAN = 0x02, /// FP_NORMAL = 0x04, /// FP_SUBNORMAL = 0x08, /// FP_ZERO = 0x10, } enum { /// FP_FAST_FMA = 1, /// FP_FAST_FMAF = 1, /// FP_FAST_FMAL = 1, } int __fpclassifyd(double); int __fpclassifyf(float); int __fpclassifyl(real); int __isfinitef(float); int __isfinite(double); int __isfinitel(real); int __isinff(float); int __isinfl(real); int __isnanl(real); int __isnormalf(float); int __isnormal(double); int __isnormall(real); int __signbit(double); int __signbitf(float); int __signbitl(real); extern (D) { //int fpclassify(real-floating x); /// int fpclassify(float x) { return __fpclassifyf(x); } /// int fpclassify(double x) { return __fpclassifyd(x); } /// int fpclassify(real x) { return __fpclassifyl(x); } //int isfinite(real-floating x); /// int isfinite(float x) { return __isfinitef(x); } /// int isfinite(double x) { return __isfinite(x); } /// int isfinite(real x) { return __isfinitel(x); } //int isinf(real-floating x); /// int isinf(float x) { return __isinff(x); } /// int isinf(double x) { return __isinfl(x); } /// int isinf(real x) { return __isinfl(x); } //int isnan(real-floating x); /// int isnan(float x) { return __isnanl(x); } /// int isnan(double x) { return __isnanl(x); } /// int isnan(real x) { return __isnanl(x); } //int isnormal(real-floating x); /// int isnormal(float x) { return __isnormalf(x); } /// int isnormal(double x) { return __isnormal(x); } /// int isnormal(real x) { return __isnormall(x); } //int signbit(real-floating x); /// int signbit(float x) { return __signbitf(x); } /// int signbit(double x) { return __signbit(x); } /// int signbit(real x) { return __signbit(x); } } } else version( Solaris ) { int __isnanf(float x); int __isnan(double x); int __isnanl(real x); extern (D) { //int isnan(real-floating x); /// int isnan(float x) { return __isnanf(x); } /// int isnan(double x) { return __isnan(x); } /// int isnan(real x) { return (real.sizeof == double.sizeof) ? __isnan(x) : __isnanl(x); } } } else version( CRuntime_Bionic ) { enum { /// FP_INFINITE = 0x01, /// FP_NAN = 0x02, /// FP_NORMAL = 0x04, /// FP_SUBNORMAL = 0x08, /// FP_ZERO = 0x10, } /// enum FP_FAST_FMAF; int __fpclassifyd(double); int __fpclassifyf(float); int __fpclassifyl(real); int __isfinitef(float); int __isfinite(double); int __isfinitel(real); int __isinff(float); int __isinf(double); int __isinfl(real); int isnanf(float); int isnan(double); int __isnanl(real); int __isnormalf(float); int __isnormal(double); int __isnormall(real); int __signbit(double); int __signbitf(float); int __signbitl(real); extern (D) { //int fpclassify(real-floating x); /// int fpclassify(float x) { return __fpclassifyf(x); } /// int fpclassify(double x) { return __fpclassifyd(x); } /// int fpclassify(real x) { return __fpclassifyl(x); } //int isfinite(real-floating x); /// int isfinite(float x) { return __isfinitef(x); } /// int isfinite(double x) { return __isfinite(x); } /// int isfinite(real x) { return __isfinitel(x); } //int isinf(real-floating x); /// int isinf(float x) { return __isinff(x); } /// int isinf(double x) { return __isinf(x); } /// int isinf(real x) { return __isinfl(x); } //int isnan(real-floating x); /// int isnan(float x) { return isnanf(x); } /// int isnan(real x) { return __isnanl(x); } //int isnormal(real-floating x); /// int isnormal(float x) { return __isnormalf(x); } /// int isnormal(double x) { return __isnormal(x); } /// int isnormal(real x) { return __isnormall(x); } //int signbit(real-floating x); /// int signbit(float x) { return __signbitf(x); } /// int signbit(double x) { return __signbit(x); } /// int signbit(real x) { return __signbitl(x); } } } extern (D) { //int isgreater(real-floating x, real-floating y); /// int isgreater(float x, float y) { return x > y && !isunordered(x, y); } /// int isgreater(double x, double y) { return x > y && !isunordered(x, y); } /// int isgreater(real x, real y) { return x > y && !isunordered(x, y); } //int isgreaterequal(real-floating x, real-floating y); /// int isgreaterequal(float x, float y) { return x >= y && !isunordered(x, y); } /// int isgreaterequal(double x, double y) { return x >= y && !isunordered(x, y); } /// int isgreaterequal(real x, real y) { return x >= y && !isunordered(x, y); } //int isless(real-floating x, real-floating y); /// int isless(float x, float y) { return x < y && !isunordered(x, y); } /// int isless(double x, double y) { return x < y && !isunordered(x, y); } /// int isless(real x, real y) { return x < y && !isunordered(x, y); } //int islessequal(real-floating x, real-floating y); /// int islessequal(float x, float y) { return x <= y && !isunordered(x, y); } /// int islessequal(double x, double y) { return x <= y && !isunordered(x, y); } /// int islessequal(real x, real y) { return x <= y && !isunordered(x, y); } //int islessgreater(real-floating x, real-floating y); /// int islessgreater(float x, float y) { return x != y && !isunordered(x, y); } /// int islessgreater(double x, double y) { return x != y && !isunordered(x, y); } /// int islessgreater(real x, real y) { return x != y && !isunordered(x, y); } //int isunordered(real-floating x, real-floating y); /// int isunordered(float x, float y) { return isnan(x) || isnan(y); } /// int isunordered(double x, double y) { return isnan(x) || isnan(y); } /// int isunordered(real x, real y) { return isnan(x) || isnan(y); } } /* MS define some functions inline. * Additionally, their *l functions work with a 64-bit long double and are thus * useless for 80-bit D reals. So we use our own wrapper implementations working * internally with reduced 64-bit precision. * This also enables relaxing real to 64-bit double. */ version( CRuntime_Microsoft ) // fully supported since MSVCRT 12 (VS 2013) only { /// double acos(double x); /// float acosf(float x); /// extern(D) real acosl()(real x) { return acos(cast(double) x); } /// double asin(double x); /// float asinf(float x); /// extern(D) real asinl()(real x) { return asin(cast(double) x); } /// double atan(double x); /// float atanf(float x); /// extern(D) real atanl()(real x) { return atan(cast(double) x); } /// double atan2(double y, double x); /// float atan2f(float y, float x); /// extern(D) real atan2l()(real y, real x) { return atan2(cast(double) y, cast(double) x); } /// double cos(double x); /// float cosf(float x); /// extern(D) real cosl()(real x) { return cos(cast(double) x); } /// double sin(double x); /// float sinf(float x); /// extern(D) real sinl()(real x) { return sin(cast(double) x); } /// double tan(double x); /// float tanf(float x); /// extern(D) real tanl()(real x) { return tan(cast(double) x); } /// double acosh(double x); /// float acoshf(float x); /// extern(D) real acoshl()(real x) { return acosh(cast(double) x); } /// double asinh(double x); /// float asinhf(float x); /// extern(D) real asinhl()(real x) { return asinh(cast(double) x); } /// double atanh(double x); /// float atanhf(float x); /// extern(D) real atanhl()(real x) { return atanh(cast(double) x); } /// double cosh(double x); /// float coshf(float x); /// extern(D) real coshl()(real x) { return cosh(cast(double) x); } /// double sinh(double x); /// float sinhf(float x); /// extern(D) real sinhl()(real x) { return sinh(cast(double) x); } /// double tanh(double x); /// float tanhf(float x); /// extern(D) real tanhl()(real x) { return tanh(cast(double) x); } /// double exp(double x); /// float expf(float x); /// extern(D) real expl()(real x) { return exp(cast(double) x); } /// double exp2(double x); /// float exp2f(float x); /// extern(D) real exp2l()(real x) { return exp2(cast(double) x); } /// double expm1(double x); /// float expm1f(float x); /// extern(D) real expm1l()(real x) { return expm1(cast(double) x); } /// double frexp(double value, int* exp); /// extern(D) float frexpf()(float value, int* exp) { return cast(float) frexp(value, exp); } /// extern(D) real frexpl()(real value, int* exp) { return frexp(cast(double) value, exp); } /// int ilogb(double x); /// int ilogbf(float x); /// extern(D) int ilogbl()(real x) { return ilogb(cast(double) x); } /// double ldexp(double x, int exp); /// extern(D) float ldexpf()(float x, int exp) { return cast(float) ldexp(x, exp); } /// extern(D) real ldexpl()(real x, int exp) { return ldexp(cast(double) x, exp); } /// double log(double x); /// float logf(float x); /// extern(D) real logl()(real x) { return log(cast(double) x); } /// double log10(double x); /// float log10f(float x); /// extern(D) real log10l()(real x) { return log10(cast(double) x); } /// double log1p(double x); /// float log1pf(float x); /// extern(D) real log1pl()(real x) { return log1p(cast(double) x); } /// double log2(double x); /// float log2f(float x); /// extern(D) real log2l()(real x) { return log2(cast(double) x); } /// double logb(double x); /// float logbf(float x); /// extern(D) real logbl()(real x) { return logb(cast(double) x); } /// double modf(double value, double* iptr); /// float modff(float value, float* iptr); /// extern(D) real modfl()(real value, real* iptr) { double i; double r = modf(cast(double) value, &i); *iptr = i; return r; } /// double scalbn(double x, int n); /// float scalbnf(float x, int n); /// extern(D) real scalbnl()(real x, int n) { return scalbn(cast(double) x, n); } /// double scalbln(double x, c_long n); /// float scalblnf(float x, c_long n); /// extern(D) real scalblnl()(real x, c_long n) { return scalbln(cast(double) x, n); } /// double cbrt(double x); /// float cbrtf(float x); /// extern(D) real cbrtl()(real x) { return cbrt(cast(double) x); } /// double fabs(double x); /// extern(D) float fabsf()(float x) { return cast(float) fabs(x); } /// extern(D) real fabsl()(real x) { return fabs(cast(double) x); } private double _hypot(double x, double y); private float _hypotf(float x, float y); /// extern(D) double hypot(double x, double y) { return _hypot(x, y); } /// extern(D) float hypotf(float x, float y) { return _hypotf(x, y); } /// extern(D) real hypotl(real x, real y) { return _hypot(cast(double) x, cast(double) y); } /// double pow(double x, double y); /// float powf(float x, float y); /// extern(D) real powl()(real x, real y) { return pow(cast(double) x, cast(double) y); } /// double sqrt(double x); /// float sqrtf(float x); /// extern(D) real sqrtl()(real x) { return sqrt(cast(double) x); } /// double erf(double x); /// float erff(float x); /// extern(D) real erfl()(real x) { return erf(cast(double) x); } /// double erfc(double x); /// float erfcf(float x); /// extern(D) real erfcl()(real x) { return erfc(cast(double) x); } /// double lgamma(double x); /// float lgammaf(float x); /// extern(D) real lgammal()(real x) { return lgamma(cast(double) x); } /// double tgamma(double x); /// float tgammaf(float x); /// extern(D) real tgammal()(real x) { return tgamma(cast(double) x); } /// double ceil(double x); /// float ceilf(float x); /// extern(D) real ceill()(real x) { return ceil(cast(double) x); } /// double floor(double x); /// float floorf(float x); /// extern(D) real floorl()(real x) { return floor(cast(double) x); } /// double nearbyint(double x); /// float nearbyintf(float x); /// extern(D) real nearbyintl()(real x) { return nearbyint(cast(double) x); } /// double rint(double x); /// float rintf(float x); /// extern(D) real rintl()(real x) { return rint(cast(double) x); } /// c_long lrint(double x); /// c_long lrintf(float x); /// extern(D) c_long lrintl()(real x) { return lrint(cast(double) x); } /// long llrint(double x); /// long llrintf(float x); /// extern(D) long llrintl()(real x) { return llrint(cast(double) x); } /// double round(double x); /// float roundf(float x); /// extern(D) real roundl()(real x) { return round(cast(double) x); } /// c_long lround(double x); /// c_long lroundf(float x); /// extern(D) c_long lroundl()(real x) { return lround(cast(double) x); } /// long llround(double x); /// long llroundf(float x); /// extern(D) long llroundl()(real x) { return llround(cast(double) x); } /// double trunc(double x); /// float truncf(float x); /// extern(D) real truncl()(real x) { return trunc(cast(double) x); } /// double fmod(double x, double y); /// float fmodf(float x, float y); /// extern(D) real fmodl()(real x, real y) { return fmod(cast(double) x, cast(double) y); } /// double remainder(double x, double y); /// float remainderf(float x, float y); /// extern(D) real remainderl()(real x, real y) { return remainder(cast(double) x, cast(double) y); } /// double remquo(double x, double y, int* quo); /// float remquof(float x, float y, int* quo); /// extern(D) real remquol()(real x, real y, int* quo) { return remquo(cast(double) x, cast(double) y, quo); } /// double copysign(double x, double y); /// float copysignf(float x, float y); /// extern(D) real copysignl()(real x, real y) { return copysign(cast(double) x, cast(double) y); } /// double nan(char* tagp); /// float nanf(char* tagp); /// extern(D) real nanl()(char* tagp) { return nan(tagp); } /// double nextafter(double x, double y); /// float nextafterf(float x, float y); /// extern(D) real nextafterl()(real x, real y) { return nextafter(cast(double) x, cast(double) y); } /// double nexttoward(double x, real y); /// float nexttowardf(float x, real y); /// extern(D) real nexttowardl()(real x, real y) { return nexttoward(cast(double) x, cast(double) y); } /// double fdim(double x, double y); /// float fdimf(float x, float y); /// extern(D) real fdiml()(real x, real y) { return fdim(cast(double) x, cast(double) y); } /// double fmax(double x, double y); /// float fmaxf(float x, float y); /// extern(D) real fmaxl()(real x, real y) { return fmax(cast(double) x, cast(double) y); } /// double fmin(double x, double y); /// float fminf(float x, float y); /// extern(D) real fminl()(real x, real y) { return fmin(cast(double) x, cast(double) y); } /// double fma(double x, double y, double z); /// float fmaf(float x, float y, float z); /// extern(D) real fmal()(real x, real y, real z) { return fma(cast(double) x, cast(double) y, cast(double) z); } } /* NOTE: freebsd < 8-CURRENT doesn't appear to support *l, but we can * approximate. * A lot of them were added in 8.0-RELEASE, and so a lot of these workarounds * should then be removed. */ // NOTE: FreeBSD 8.0-RELEASE doesn't support log2* nor these *l functions: // acoshl, asinhl, atanhl, coshl, sinhl, tanhl, cbrtl, powl, expl, // expm1l, logl, log1pl, log10l, erfcl, erfl, lgammal, tgammal; // but we can approximate. else version( FreeBSD ) { version (none) // < 8-CURRENT { real acosl(real x) { return acos(x); } real asinl(real x) { return asin(x); } real atanl(real x) { return atan(x); } real atan2l(real y, real x) { return atan2(y, x); } real cosl(real x) { return cos(x); } real sinl(real x) { return sin(x); } real tanl(real x) { return tan(x); } real exp2l(real x) { return exp2(x); } real frexpl(real value, int* exp) { return frexp(value, exp); } int ilogbl(real x) { return ilogb(x); } real ldexpl(real x, int exp) { return ldexp(x, exp); } real logbl(real x) { return logb(x); } //real modfl(real value, real *iptr); // nontrivial conversion real scalbnl(real x, int n) { return scalbn(x, n); } real scalblnl(real x, c_long n) { return scalbln(x, n); } real fabsl(real x) { return fabs(x); } real hypotl(real x, real y) { return hypot(x, y); } real sqrtl(real x) { return sqrt(x); } real ceill(real x) { return ceil(x); } real floorl(real x) { return floor(x); } real nearbyintl(real x) { return nearbyint(x); } real rintl(real x) { return rint(x); } c_long lrintl(real x) { return lrint(x); } real roundl(real x) { return round(x); } c_long lroundl(real x) { return lround(x); } long llroundl(real x) { return llround(x); } real truncl(real x) { return trunc(x); } real fmodl(real x, real y) { return fmod(x, y); } real remainderl(real x, real y) { return remainder(x, y); } real remquol(real x, real y, int* quo) { return remquo(x, y, quo); } real copysignl(real x, real y) { return copysign(x, y); } // double nan(char* tagp); // float nanf(char* tagp); // real nanl(char* tagp); real nextafterl(real x, real y) { return nextafter(x, y); } real nexttowardl(real x, real y) { return nexttoward(x, y); } real fdiml(real x, real y) { return fdim(x, y); } real fmaxl(real x, real y) { return fmax(x, y); } real fminl(real x, real y) { return fmin(x, y); } real fmal(real x, real y, real z) { return fma(x, y, z); } } else { /// real acosl(real x); /// real asinl(real x); /// real atanl(real x); /// real atan2l(real y, real x); /// real cosl(real x); /// real sinl(real x); /// real tanl(real x); /// real exp2l(real x); /// real frexpl(real value, int* exp); /// int ilogbl(real x); /// real ldexpl(real x, int exp); /// real logbl(real x); /// real modfl(real value, real *iptr); /// real scalbnl(real x, int n); /// real scalblnl(real x, c_long n); /// real fabsl(real x); /// real hypotl(real x, real y); /// real sqrtl(real x); /// real ceill(real x); /// real floorl(real x); /// real nearbyintl(real x); /// real rintl(real x); /// c_long lrintl(real x); /// real roundl(real x); /// c_long lroundl(real x); /// long llroundl(real x); /// real truncl(real x); /// real fmodl(real x, real y); /// real remainderl(real x, real y); /// real remquol(real x, real y, int* quo); /// real copysignl(real x, real y); /// double nan(char* tagp); /// float nanf(char* tagp); /// real nanl(char* tagp); /// real nextafterl(real x, real y); /// real nexttowardl(real x, real y); /// real fdiml(real x, real y); /// real fmaxl(real x, real y); /// real fminl(real x, real y); /// real fmal(real x, real y, real z); } /// double acos(double x); /// float acosf(float x); /// double asin(double x); /// float asinf(float x); /// double atan(double x); /// float atanf(float x); /// double atan2(double y, double x); /// float atan2f(float y, float x); /// double cos(double x); /// float cosf(float x); /// double sin(double x); /// float sinf(float x); /// double tan(double x); /// float tanf(float x); /// double acosh(double x); /// float acoshf(float x); /// real acoshl(real x) { return acosh(x); } /// double asinh(double x); /// float asinhf(float x); /// real asinhl(real x) { return asinh(x); } /// double atanh(double x); /// float atanhf(float x); /// real atanhl(real x) { return atanh(x); } /// double cosh(double x); /// float coshf(float x); /// real coshl(real x) { return cosh(x); } /// double sinh(double x); /// float sinhf(float x); /// real sinhl(real x) { return sinh(x); } /// double tanh(double x); /// float tanhf(float x); /// real tanhl(real x) { return tanh(x); } /// double exp(double x); /// float expf(float x); /// real expl(real x) { return exp(x); } /// double exp2(double x); /// float exp2f(float x); /// double expm1(double x); /// float expm1f(float x); /// real expm1l(real x) { return expm1(x); } /// double frexp(double value, int* exp); /// float frexpf(float value, int* exp); /// int ilogb(double x); /// int ilogbf(float x); /// double ldexp(double x, int exp); /// float ldexpf(float x, int exp); /// double log(double x); /// float logf(float x); /// real logl(real x) { return log(x); } /// double log10(double x); /// float log10f(float x); /// real log10l(real x) { return log10(x); } /// double log1p(double x); /// float log1pf(float x); /// real log1pl(real x) { return log1p(x); } private enum real ONE_LN2 = 1 / 0x1.62e42fefa39ef358p-1L; /// double log2(double x) { return log(x) * ONE_LN2; } /// float log2f(float x) { return logf(x) * ONE_LN2; } /// real log2l(real x) { return logl(x) * ONE_LN2; } /// double logb(double x); /// float logbf(float x); /// double modf(double value, double* iptr); /// float modff(float value, float* iptr); /// double scalbn(double x, int n); /// float scalbnf(float x, int n); /// double scalbln(double x, c_long n); /// float scalblnf(float x, c_long n); /// double cbrt(double x); /// float cbrtf(float x); /// real cbrtl(real x) { return cbrt(x); } /// double fabs(double x); /// float fabsf(float x); /// double hypot(double x, double y); /// float hypotf(float x, float y); /// double pow(double x, double y); /// float powf(float x, float y); /// real powl(real x, real y) { return pow(x, y); } /// double sqrt(double x); /// float sqrtf(float x); /// double erf(double x); /// float erff(float x); /// real erfl(real x) { return erf(x); } /// double erfc(double x); /// float erfcf(float x); /// real erfcl(real x) { return erfc(x); } /// double lgamma(double x); /// float lgammaf(float x); /// real lgammal(real x) { return lgamma(x); } /// double tgamma(double x); /// float tgammaf(float x); /// real tgammal(real x) { return tgamma(x); } /// double ceil(double x); /// float ceilf(float x); /// double floor(double x); /// float floorf(float x); /// double nearbyint(double x); /// float nearbyintf(float x); /// double rint(double x); /// float rintf(float x); /// c_long lrint(double x); /// c_long lrintf(float x); /// long llrint(double x); /// long llrintf(float x); /// long llrintl(real x) { return llrint(x); } /// double round(double x); /// float roundf(float x); /// c_long lround(double x); /// c_long lroundf(float x); /// long llround(double x); /// long llroundf(float x); /// double trunc(double x); /// float truncf(float x); /// double fmod(double x, double y); /// float fmodf(float x, float y); /// double remainder(double x, double y); /// float remainderf(float x, float y); /// double remquo(double x, double y, int* quo); /// float remquof(float x, float y, int* quo); /// double copysign(double x, double y); /// float copysignf(float x, float y); /// double nextafter(double x, double y); /// float nextafterf(float x, float y); /// double nexttoward(double x, real y); /// float nexttowardf(float x, real y); /// double fdim(double x, double y); /// float fdimf(float x, float y); /// double fmax(double x, double y); /// float fmaxf(float x, float y); /// double fmin(double x, double y); /// float fminf(float x, float y); /// double fma(double x, double y, double z); /// float fmaf(float x, float y, float z); } else version( OpenBSD ) { /// real acosl(real x); /// real asinl(real x); /// real atanl(real x); /// real atan2l(real y, real x); /// real cosl(real x); /// real sinl(real x); /// real tanl(real x); /// real acoshl(real x); /// real asinhl(real x); /// real atanhl(real x); /// real coshl(real x); /// real sinhl(real x); /// real tanhl(real x); /// real expl(real x); /// real exp2l(real x); /// real expm1l(real x); /// real frexpl(real value, int* exp); /// int ilogbl(real x); /// real ldexpl(real x, int exp); /// real logbl(real x); /// real logb10l(real x); /// real logb1pl(real x); /// real logb2l(real x); /// real logbl(real x); /// real modfl(real value, real *iptr); /// real scalbnl(real x, int n); /// real scalblnl(real x, c_long n); /// real cbrtl(real x); /// real fabsl(real x); /// real hypotl(real x, real y); /// real powl(real x, real y); /// real sqrtl(real x); /// real ceill(real x); /// real floorl(real x); /// real nearbyintl(real x); /// real rintl(real x); /// c_long lrintl(real x); /// long llrintl(real x); /// real roundl(real x); /// c_long lroundl(real x); /// long llroundl(real x); /// real truncl(real x); /// real fmodl(real x, real y); /// real remainderl(real x, real y); /// real remquol(real x, real y, int* quo); /// real copysignl(real x, real y); /// double nan(char* tagp); /// float nanf(char* tagp); /// real nanl(char* tagp); /// real nextafterl(real x, real y); /// real nexttowardl(real x, real y); /// real fdiml(real x, real y); /// real fmaxl(real x, real y); /// real fminl(real x, real y); /// real fmal(real x, real y, real z); /// double acos(double x); /// float acosf(float x); /// double asin(double x); /// float asinf(float x); /// double atan(double x); /// float atanf(float x); /// double atan2(double y, double x); /// float atan2f(float y, float x); /// double cos(double x); /// float cosf(float x); /// double sin(double x); /// float sinf(float x); /// double tan(double x); /// float tanf(float x); /// double acosh(double x); /// float acoshf(float x); /// double asinh(double x); /// float asinhf(float x); /// double atanh(double x); /// float atanhf(float x); /// double cosh(double x); /// float coshf(float x); /// double sinh(double x); /// float sinhf(float x); /// double tanh(double x); /// float tanhf(float x); /// double exp(double x); /// float expf(float x); /// double exp2(double x); /// float exp2f(float x); /// real exp2l(real x); /// double expm1(double x); /// float expm1f(float x); /// double frexp(double value, int* exp); /// float frexpf(float value, int* exp); /// int ilogb(double x); /// int ilogbf(float x); /// double ldexp(double x, int exp); /// float ldexpf(float x, int exp); /// double log(double x); /// float logf(float x); /// double log10(double x); /// float log10f(float x); /// double log1p(double x); /// float log1pf(float x); /// double log2(double x); /// float log2f(float x); /// real log2l(real x); /// double logb(double x); /// float logbf(float x); /// double modf(double value, double* iptr); /// float modff(float value, float* iptr); /// double scalbn(double x, int n); /// float scalbnf(float x, int n); /// double scalbln(double x, c_long n); /// float scalblnf(float x, c_long n); /// double cbrt(double x); /// float cbrtf(float x); /// double fabs(double x); /// float fabsf(float x); /// double hypot(double x, double y); /// float hypotf(float x, float y); /// double pow(double x, double y); /// float powf(float x, float y); /// double sqrt(double x); /// float sqrtf(float x); /// double erf(double x); /// float erff(float x); /// real erfl(real x); /// double erfc(double x); /// float erfcf(float x); /// real erfcl(real x); /// double lgamma(double x); /// float lgammaf(float x); /// real lgammal(real x); /// double tgamma(double x); /// float tgammaf(float x); /// real tgammal(real x); /// double ceil(double x); /// float ceilf(float x); /// double floor(double x); /// float floorf(float x); /// double nearbyint(double x); /// float nearbyintf(float x); /// double rint(double x); /// float rintf(float x); /// c_long lrint(double x); /// c_long lrintf(float x); /// long llrint(double x); /// long llrintf(float x); /// double round(double x); /// float roundf(float x); /// c_long lround(double x); /// c_long lroundf(float x); /// long llround(double x); /// long llroundf(float x); /// double trunc(double x); /// float truncf(float x); /// double fmod(double x, double y); /// float fmodf(float x, float y); /// double remainder(double x, double y); /// float remainderf(float x, float y); /// double remquo(double x, double y, int* quo); /// float remquof(float x, float y, int* quo); /// double copysign(double x, double y); /// float copysignf(float x, float y); /// double nextafter(double x, double y); /// float nextafterf(float x, float y); /// double nexttoward(double x, real y); /// float nexttowardf(float x, real y); /// double fdim(double x, double y); /// float fdimf(float x, float y); /// double fmax(double x, double y); /// float fmaxf(float x, float y); /// double fmin(double x, double y); /// float fminf(float x, float y); /// double fma(double x, double y, double z); /// float fmaf(float x, float y, float z); } else version(CRuntime_Bionic) { // Bionic defines long double as 64 bits, same as double, so several long // double functions are missing. nexttoward was modified to reflect this. /// double acos(double x); /// float acosf(float x); //real acosl(real x); /// double asin(double x); /// float asinf(float x); //real asinl(real x); /// double atan(double x); /// float atanf(float x); //real atanl(real x); /// double atan2(double y, double x); /// float atan2f(float y, float x); //real atan2l(real y, real x); /// double cos(double x); /// float cosf(float x); //real cosl(real x); /// double sin(double x); /// float sinf(float x); //real sinl(real x); /// double tan(double x); /// float tanf(float x); //real tanl(real x); /// double acosh(double x); /// float acoshf(float x); //real acoshl(real x); /// double asinh(double x); /// float asinhf(float x); //real asinhl(real x); /// double atanh(double x); /// float atanhf(float x); //real atanhl(real x); /// double cosh(double x); /// float coshf(float x); //real coshl(real x); /// double sinh(double x); /// float sinhf(float x); //real sinhl(real x); /// double tanh(double x); /// float tanhf(float x); //real tanhl(real x); /// double exp(double x); /// float expf(float x); //real expl(real x); /// double exp2(double x); /// float exp2f(float x); /// real exp2l(real x) { return exp2(x); } /// double expm1(double x); /// float expm1f(float x); //real expm1l(real x); /// double frexp(double value, int* exp); /// float frexpf(float value, int* exp); // alias for double: real frexpl(real value, int* exp); /// int ilogb(double x); /// int ilogbf(float x); /// int ilogbl(real x) { return ilogb(x); } /// double ldexp(double x, int exp); /// float ldexpf(float x, int exp); /// real ldexpl(real x, int exp); /// double log(double x); /// float logf(float x); //real logl(real x); /// double log10(double x); /// float log10f(float x); //real log10l(real x); /// double log1p(double x); /// float log1pf(float x); //real log1pl(real x); //double log2(double x); //float log2f(float x); //real log2l(real x); /// double logb(double x); /// float logbf(float x); /// real logbl(real x) { return logb(x); } /// double modf(double value, double* iptr); /// float modff(float value, float* iptr); /// real modfl(real value, real *iptr) { return modf(value, cast(double*)iptr); } /// double scalbn(double x, int n); /// float scalbnf(float x, int n); /// real scalbnl(real x, int n); /// double scalbln(double x, c_long n); /// float scalblnf(float x, c_long n); // alias for double: real scalblnl(real x, c_long n); /// double cbrt(double x); /// float cbrtf(float x); /// real cbrtl(real x) { return cbrt(x); } /// double fabs(double x); /// float fabsf(float x); // alias for double: real fabsl(real x); /// double hypot(double x, double y); /// float hypotf(float x, float y); //real hypotl(real x, real y); /// double pow(double x, double y); /// float powf(float x, float y); //real powl(real x, real y); /// double sqrt(double x); /// float sqrtf(float x); //real sqrtl(real x); /// double erf(double x); /// float erff(float x); //real erfl(real x); /// double erfc(double x); /// float erfcf(float x); //real erfcl(real x); /// double lgamma(double x); /// float lgammaf(float x); //real lgammal(real x); /// double tgamma(double x); //float tgammaf(float x); //real tgammal(real x); /// double ceil(double x); /// float ceilf(float x); // alias for double: real ceill(real x); /// double floor(double x); /// float floorf(float x); // alias for double: real floorl(real x); /// double nearbyint(double x); /// float nearbyintf(float x); /// real nearbyintl(real x) { return nearbyint(x); } /// double rint(double x); /// float rintf(float x); //real rintl(real x); /// c_long lrint(double x); /// c_long lrintf(float x); //c_long lrintl(real x); /// long llrint(double x); /// long llrintf(float x); //long llrintl(real x); /// double round(double x); /// float roundf(float x); /// real roundl(real x) { return round(x); } /// c_long lround(double x); /// c_long lroundf(float x); // alias for double: c_long lroundl(real x); /// long llround(double x); /// long llroundf(float x); /// long llroundl(real x) { return llround(x); } /// double trunc(double x); /// float truncf(float x); /// real truncl(real x) { return trunc(x); } /// double fmod(double x, double y); /// float fmodf(float x, float y); /// real fmodl(real x, real y) { return fmod(x,y); } /// double remainder(double x, double y); /// float remainderf(float x, float y); /// real remainderl(real x, real y) { return remainder(x,y); } /// double remquo(double x, double y, int* quo); /// float remquof(float x, float y, int* quo); /// real remquol(real x, real y, int* quo) { return remquo(x,y,quo); } /// double copysign(double x, double y); /// float copysignf(float x, float y); // alias for double: real copysignl(real x, real y); //double nan(char* tagp); //float nanf(char* tagp); //real nanl(char* tagp); /// double nextafter(double x, double y); /// float nextafterf(float x, float y); // alias for double: real nextafterl(real x, real y); /// double nexttoward(double x, double y); /// float nexttowardf(float x, double y); // alias for double: real nexttowardl(real x, real y); /// double fdim(double x, double y); /// float fdimf(float x, float y); // alias for double: real fdiml(real x, real y); /// double fmax(double x, double y); /// float fmaxf(float x, float y); // alias for double: real fmaxl(real x, real y); /// double fmin(double x, double y); /// float fminf(float x, float y); // alias for double: real fminl(real x, real y); /// double fma(double x, double y, double z); /// float fmaf(float x, float y, float z); // alias for double: real fmal(real x, real y, real z); } else { /// double acos(double x); /// float acosf(float x); /// real acosl(real x); /// double asin(double x); /// float asinf(float x); /// real asinl(real x); /// double atan(double x); /// float atanf(float x); /// real atanl(real x); /// double atan2(double y, double x); /// float atan2f(float y, float x); /// real atan2l(real y, real x); /// double cos(double x); /// float cosf(float x); /// real cosl(real x); /// double sin(double x); /// float sinf(float x); /// real sinl(real x); /// double tan(double x); /// float tanf(float x); /// real tanl(real x); /// double acosh(double x); /// float acoshf(float x); /// real acoshl(real x); /// double asinh(double x); /// float asinhf(float x); /// real asinhl(real x); /// double atanh(double x); /// float atanhf(float x); /// real atanhl(real x); /// double cosh(double x); /// float coshf(float x); /// real coshl(real x); /// double sinh(double x); /// float sinhf(float x); /// real sinhl(real x); /// double tanh(double x); /// float tanhf(float x); /// real tanhl(real x); /// double exp(double x); /// float expf(float x); /// real expl(real x); /// double exp2(double x); /// float exp2f(float x); /// real exp2l(real x); /// double expm1(double x); /// float expm1f(float x); /// real expm1l(real x); /// double frexp(double value, int* exp); /// float frexpf(float value, int* exp); /// real frexpl(real value, int* exp); /// int ilogb(double x); /// int ilogbf(float x); /// int ilogbl(real x); /// double ldexp(double x, int exp); /// float ldexpf(float x, int exp); /// real ldexpl(real x, int exp); /// double log(double x); /// float logf(float x); /// real logl(real x); /// double log10(double x); /// float log10f(float x); /// real log10l(real x); /// double log1p(double x); /// float log1pf(float x); /// real log1pl(real x); /// double log2(double x); /// float log2f(float x); /// real log2l(real x); /// double logb(double x); /// float logbf(float x); /// real logbl(real x); /// double modf(double value, double* iptr); /// float modff(float value, float* iptr); /// real modfl(real value, real *iptr); /// double scalbn(double x, int n); /// float scalbnf(float x, int n); /// real scalbnl(real x, int n); /// double scalbln(double x, c_long n); /// float scalblnf(float x, c_long n); /// real scalblnl(real x, c_long n); /// double cbrt(double x); /// float cbrtf(float x); /// real cbrtl(real x); /// double fabs(double x); version( CRuntime_Microsoft ) { } else { /// float fabsf(float x); /// real fabsl(real x); } /// double hypot(double x, double y); /// float hypotf(float x, float y); /// real hypotl(real x, real y); /// double pow(double x, double y); /// float powf(float x, float y); /// real powl(real x, real y); /// double sqrt(double x); /// float sqrtf(float x); /// real sqrtl(real x); /// double erf(double x); /// float erff(float x); /// real erfl(real x); /// double erfc(double x); /// float erfcf(float x); /// real erfcl(real x); /// double lgamma(double x); /// float lgammaf(float x); /// real lgammal(real x); /// double tgamma(double x); /// float tgammaf(float x); /// real tgammal(real x); /// double ceil(double x); /// float ceilf(float x); /// real ceill(real x); /// double floor(double x); /// float floorf(float x); /// real floorl(real x); /// double nearbyint(double x); /// float nearbyintf(float x); /// real nearbyintl(real x); /// double rint(double x); /// float rintf(float x); /// real rintl(real x); /// c_long lrint(double x); /// c_long lrintf(float x); /// c_long lrintl(real x); /// long llrint(double x); /// long llrintf(float x); /// long llrintl(real x); /// double round(double x); /// float roundf(float x); /// real roundl(real x); /// c_long lround(double x); /// c_long lroundf(float x); /// c_long lroundl(real x); /// long llround(double x); /// long llroundf(float x); /// long llroundl(real x); /// double trunc(double x); /// float truncf(float x); /// real truncl(real x); /// double fmod(double x, double y); /// float fmodf(float x, float y); /// real fmodl(real x, real y); /// double remainder(double x, double y); /// float remainderf(float x, float y); /// real remainderl(real x, real y); /// double remquo(double x, double y, int* quo); /// float remquof(float x, float y, int* quo); /// real remquol(real x, real y, int* quo); /// double copysign(double x, double y); /// float copysignf(float x, float y); /// real copysignl(real x, real y); /// double nan(char* tagp); /// float nanf(char* tagp); /// real nanl(char* tagp); /// double nextafter(double x, double y); /// float nextafterf(float x, float y); /// real nextafterl(real x, real y); /// double nexttoward(double x, real y); /// float nexttowardf(float x, real y); /// real nexttowardl(real x, real y); /// double fdim(double x, double y); /// float fdimf(float x, float y); /// real fdiml(real x, real y); /// double fmax(double x, double y); /// float fmaxf(float x, float y); /// real fmaxl(real x, real y); /// double fmin(double x, double y); /// float fminf(float x, float y); /// real fminl(real x, real y); /// double fma(double x, double y, double z); /// float fmaf(float x, float y, float z); /// real fmal(real x, real y, real z); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/wchar_.d0000664000175000017500000001272712776214756021560 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_wchar.h.html, _wchar.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_wchar_.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.wchar_; private import core.stdc.config; private import core.stdc.stdarg; // for va_list private import core.stdc.stdio; // for FILE, not exposed per spec public import core.stdc.stddef; // for wchar_t public import core.stdc.time; // for tm public import core.stdc.stdint; // for WCHAR_MIN, WCHAR_MAX extern (C): @system: nothrow: @nogc: version( CRuntime_Glibc ) { /// struct mbstate_t { int __count; union ___value { wint_t __wch; char[4] __wchb; } ___value __value; } } else version (OpenBSD) { union __mbstate_t { char[128] __mbstate8; int64_t __mbstateL; } alias mbstate_t = __mbstate_t; } else version (Solaris) { /// struct __mbstate_t { version (D_LP64) { long[4] __filler; } else { int[6] __filler; } } } else { /// alias int mbstate_t; } /// alias wchar_t wint_t; /// enum wchar_t WEOF = 0xFFFF; /// int fwprintf(FILE* stream, in wchar_t* format, ...); /// int fwscanf(FILE* stream, in wchar_t* format, ...); /// int swprintf(wchar_t* s, size_t n, in wchar_t* format, ...); /// int swscanf(in wchar_t* s, in wchar_t* format, ...); /// int vfwprintf(FILE* stream, in wchar_t* format, va_list arg); /// int vfwscanf(FILE* stream, in wchar_t* format, va_list arg); /// int vswprintf(wchar_t* s, size_t n, in wchar_t* format, va_list arg); /// int vswscanf(in wchar_t* s, in wchar_t* format, va_list arg); /// int vwprintf(in wchar_t* format, va_list arg); /// int vwscanf(in wchar_t* format, va_list arg); /// int wprintf(in wchar_t* format, ...); /// int wscanf(in wchar_t* format, ...); // No unsafe pointer manipulation. @trusted { /// wint_t fgetwc(FILE* stream); /// wint_t fputwc(wchar_t c, FILE* stream); } /// wchar_t* fgetws(wchar_t* s, int n, FILE* stream); /// int fputws(in wchar_t* s, FILE* stream); // No unsafe pointer manipulation. extern (D) @trusted { /// wint_t getwchar() { return fgetwc(stdin); } /// wint_t putwchar(wchar_t c) { return fputwc(c,stdout); } /// wint_t getwc(FILE* stream) { return fgetwc(stream); } /// wint_t putwc(wchar_t c, FILE* stream) { return fputwc(c, stream); } } // No unsafe pointer manipulation. @trusted { /// wint_t ungetwc(wint_t c, FILE* stream); /// version( CRuntime_Microsoft ) { // MSVC defines this as an inline function. int fwide(FILE* stream, int mode) { return mode; } } else { int fwide(FILE* stream, int mode); } } /// double wcstod(in wchar_t* nptr, wchar_t** endptr); /// float wcstof(in wchar_t* nptr, wchar_t** endptr); /// real wcstold(in wchar_t* nptr, wchar_t** endptr); /// c_long wcstol(in wchar_t* nptr, wchar_t** endptr, int base); /// long wcstoll(in wchar_t* nptr, wchar_t** endptr, int base); /// c_ulong wcstoul(in wchar_t* nptr, wchar_t** endptr, int base); /// ulong wcstoull(in wchar_t* nptr, wchar_t** endptr, int base); /// wchar_t* wcscpy(wchar_t* s1, in wchar_t* s2); /// wchar_t* wcsncpy(wchar_t* s1, in wchar_t* s2, size_t n); /// wchar_t* wcscat(wchar_t* s1, in wchar_t* s2); /// wchar_t* wcsncat(wchar_t* s1, in wchar_t* s2, size_t n); /// int wcscmp(in wchar_t* s1, in wchar_t* s2); /// int wcscoll(in wchar_t* s1, in wchar_t* s2); /// int wcsncmp(in wchar_t* s1, in wchar_t* s2, size_t n); /// size_t wcsxfrm(wchar_t* s1, in wchar_t* s2, size_t n); /// wchar_t* wcschr(in wchar_t* s, wchar_t c); /// size_t wcscspn(in wchar_t* s1, in wchar_t* s2); /// wchar_t* wcspbrk(in wchar_t* s1, in wchar_t* s2); /// wchar_t* wcsrchr(in wchar_t* s, wchar_t c); /// size_t wcsspn(in wchar_t* s1, in wchar_t* s2); /// wchar_t* wcsstr(in wchar_t* s1, in wchar_t* s2); /// wchar_t* wcstok(wchar_t* s1, in wchar_t* s2, wchar_t** ptr); /// size_t wcslen(in wchar_t* s); /// wchar_t* wmemchr(in wchar_t* s, wchar_t c, size_t n); /// int wmemcmp(in wchar_t* s1, in wchar_t* s2, size_t n); /// wchar_t* wmemcpy(wchar_t* s1, in wchar_t* s2, size_t n); /// wchar_t* wmemmove(wchar_t*s1, in wchar_t* s2, size_t n); /// wchar_t* wmemset(wchar_t* s, wchar_t c, size_t n); /// size_t wcsftime(wchar_t* s, size_t maxsize, in wchar_t* format, in tm* timeptr); version( Windows ) { /// wchar_t* _wasctime(tm*); // non-standard /// wchar_t* _wctime(time_t*); // non-standard /// wchar_t* _wstrdate(wchar_t*); // non-standard /// wchar_t* _wstrtime(wchar_t*); // non-standard } // No unsafe pointer manipulation. @trusted { /// wint_t btowc(int c); /// int wctob(wint_t c); } /// int mbsinit(in mbstate_t* ps); /// size_t mbrlen(in char* s, size_t n, mbstate_t* ps); /// size_t mbrtowc(wchar_t* pwc, in char* s, size_t n, mbstate_t* ps); /// size_t wcrtomb(char* s, wchar_t wc, mbstate_t* ps); /// size_t mbsrtowcs(wchar_t* dst, in char** src, size_t len, mbstate_t* ps); /// size_t wcsrtombs(char* dst, in wchar_t** src, size_t len, mbstate_t* ps); ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/config.d0000664000175000017500000000764512776214756021565 0ustar kaikai/** * D header file for C99. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_config.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.config; extern (C): @trusted: // Types only. nothrow: @nogc: version( Windows ) { struct __c_long { pure nothrow @nogc @safe: this(int x) { lng = x; } int lng; alias lng this; } struct __c_ulong { pure nothrow @nogc @safe: this(uint x) { lng = x; } uint lng; alias lng this; } /* * This is cpp_long instead of c_long because: * 1. Implicit casting of an int to __c_long doesn't happen, because D doesn't * allow constructor calls in implicit conversions. * 2. long lng; * cast(__c_long)lng; * does not work because lng has to be implicitly cast to an int in the constructor, * and since that truncates it is not done. * Both of these break existing code, so until we find a resolution the types are named * cpp_xxxx. */ alias __c_long cpp_long; alias __c_ulong cpp_ulong; alias int c_long; alias uint c_ulong; } else version( Posix ) { static if( (void*).sizeof > int.sizeof ) { alias long c_long; alias ulong c_ulong; } else { struct __c_long { pure nothrow @nogc @safe: this(int x) { lng = x; } int lng; alias lng this; } struct __c_ulong { pure nothrow @nogc @safe: this(uint x) { lng = x; } uint lng; alias lng this; } alias __c_long cpp_long; alias __c_ulong cpp_ulong; alias int c_long; alias uint c_ulong; } } version( CRuntime_Microsoft ) { /* long double is 64 bits, not 80 bits, but is mangled differently * than double. To distinguish double from long double, create a wrapper to represent * long double, then recognize that wrapper specially in the compiler * to generate the correct name mangling and correct function call/return * ABI conformance. */ struct __c_long_double { pure nothrow @nogc @safe: this(double d) { ld = d; } double ld; alias ld this; } alias __c_long_double c_long_double; } else version( DigitalMars ) { version( X86 ) { alias real c_long_double; } else version( X86_64 ) { version( linux ) alias real c_long_double; else version( FreeBSD ) alias real c_long_double; else version( OpenBSD ) alias real c_long_double; else version( Solaris ) alias real c_long_double; else version( OSX ) alias real c_long_double; } } else version( GNU ) alias real c_long_double; else version( LDC ) { version( X86 ) alias real c_long_double; else version( X86_64 ) alias real c_long_double; else version( AArch64 ) alias real c_long_double; else version( ARM ) alias real c_long_double; else version( MIPS ) alias real c_long_double; else version( MIPS64 ) alias real c_long_double; else version( PPC ) alias real c_long_double; else version( PPC64 ) alias real c_long_double; else version( SPARC ) alias real c_long_double; else version( SPARC64 ) alias real c_long_double; else version( SystemZ ) alias real c_long_double; else static assert("c_long_double not declared for this platform/architecture."); } else version( SDC ) { version( X86 ) alias real c_long_double; else version( X86_64 ) alias real c_long_double; } static assert(is(c_long_double), "c_long_double needs to be declared for this platform/architecture."); ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/stddef.d0000664000175000017500000000130612776214756021555 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_stddef.h.html, _stddef.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_stddef.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.stddef; extern (C): @trusted: // Types only. nothrow: @nogc: // size_t and ptrdiff_t are defined in the object module. version( Windows ) { /// alias wchar wchar_t; } else version( Posix ) { /// alias dchar wchar_t; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/limits.d0000664000175000017500000000234712776214756021613 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_limits.h.html, _limits.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_limits.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.limits; private import core.stdc.config; extern (C): @trusted: // Constants only. nothrow: @nogc: /// enum CHAR_BIT = 8; /// enum SCHAR_MIN = byte.min; /// enum SCHAR_MAX = byte.max; /// enum UCHAR_MAX = ubyte.max; /// enum CHAR_MIN = char.min; /// enum CHAR_MAX = char.max; /// enum MB_LEN_MAX = 2; /// enum SHRT_MIN = short.min; /// enum SHRT_MAX = short.max; /// enum USHRT_MAX = ushort.max; /// enum INT_MIN = int.min; /// enum INT_MAX = int.max; /// enum UINT_MAX = uint.max; /// enum LONG_MIN = c_long.min; /// enum LONG_MAX = c_long.max; /// enum ULONG_MAX = c_ulong.max; /// enum LLONG_MIN = long.min; /// enum LLONG_MAX = long.max; /// enum ULLONG_MAX = ulong.max; ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/stdint.d0000664000175000017500000001166712776214756021624 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_stdint.h.html, _stdint.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_stdint.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.stdint; private import core.stdc.stddef; // for wchar_t private import core.stdc.signal; // for sig_atomic_t private import core.stdc.wchar_; // for wint_t // Can't be `private` because of @@@BUG11173@@@. T _typify(T)(T val) @safe pure nothrow { return val; } extern (C): @trusted: // Types and constants only. nothrow: @nogc: /// alias int8_t = byte ; /// alias int16_t = short; /// alias int32_t = int ; /// alias int64_t = long ; /// static if (is(ucent)) alias int128_t = cent; /// alias uint8_t = ubyte ; /// alias uint16_t = ushort; /// alias uint32_t = uint ; /// alias uint64_t = ulong ; /// static if (is(ucent)) alias uint128_t = ucent; /// alias int_least8_t = byte ; /// alias int_least16_t = short; /// alias int_least32_t = int ; /// alias int_least64_t = long ; /// alias uint_least8_t = ubyte ; /// alias uint_least16_t = ushort; /// alias uint_least32_t = uint ; /// alias uint_least64_t = ulong ; /// alias int_fast8_t = byte; /// alias int_fast16_t = int ; /// alias int_fast32_t = int ; /// alias int_fast64_t = long; /// alias uint_fast8_t = ubyte; /// alias uint_fast16_t = uint ; /// alias uint_fast32_t = uint ; /// alias uint_fast64_t = ulong; version( D_LP64 ) { /// alias intptr_t = long ; /// alias uintptr_t = ulong; } else { /// alias intptr_t = int ; /// alias uintptr_t = uint; } /// alias intmax_t = long ; /// alias uintmax_t = ulong; /// enum int8_t INT8_MIN = int8_t.min; /// enum int8_t INT8_MAX = int8_t.max; /// enum int16_t INT16_MIN = int16_t.min; /// enum int16_t INT16_MAX = int16_t.max; /// enum int32_t INT32_MIN = int32_t.min; /// enum int32_t INT32_MAX = int32_t.max; /// enum int64_t INT64_MIN = int64_t.min; /// enum int64_t INT64_MAX = int64_t.max; /// enum uint8_t UINT8_MAX = uint8_t.max; /// enum uint16_t UINT16_MAX = uint16_t.max; /// enum uint32_t UINT32_MAX = uint32_t.max; /// enum uint64_t UINT64_MAX = uint64_t.max; /// enum int_least8_t INT_LEAST8_MIN = int_least8_t.min; /// enum int_least8_t INT_LEAST8_MAX = int_least8_t.max; /// enum int_least16_t INT_LEAST16_MIN = int_least16_t.min; /// enum int_least16_t INT_LEAST16_MAX = int_least16_t.max; /// enum int_least32_t INT_LEAST32_MIN = int_least32_t.min; /// enum int_least32_t INT_LEAST32_MAX = int_least32_t.max; /// enum int_least64_t INT_LEAST64_MIN = int_least64_t.min; /// enum int_least64_t INT_LEAST64_MAX = int_least64_t.max; /// enum uint_least8_t UINT_LEAST8_MAX = uint_least8_t.max; /// enum uint_least16_t UINT_LEAST16_MAX = uint_least16_t.max; /// enum uint_least32_t UINT_LEAST32_MAX = uint_least32_t.max; /// enum uint_least64_t UINT_LEAST64_MAX = uint_least64_t.max; /// enum int_fast8_t INT_FAST8_MIN = int_fast8_t.min; /// enum int_fast8_t INT_FAST8_MAX = int_fast8_t.max; /// enum int_fast16_t INT_FAST16_MIN = int_fast16_t.min; /// enum int_fast16_t INT_FAST16_MAX = int_fast16_t.max; /// enum int_fast32_t INT_FAST32_MIN = int_fast32_t.min; /// enum int_fast32_t INT_FAST32_MAX = int_fast32_t.max; /// enum int_fast64_t INT_FAST64_MIN = int_fast64_t.min; /// enum int_fast64_t INT_FAST64_MAX = int_fast64_t.max; /// enum uint_fast8_t UINT_FAST8_MAX = uint_fast8_t.max; /// enum uint_fast16_t UINT_FAST16_MAX = uint_fast16_t.max; /// enum uint_fast32_t UINT_FAST32_MAX = uint_fast32_t.max; /// enum uint_fast64_t UINT_FAST64_MAX = uint_fast64_t.max; /// enum intptr_t INTPTR_MIN = intptr_t.min; /// enum intptr_t INTPTR_MAX = intptr_t.max; /// enum uintptr_t UINTPTR_MIN = uintptr_t.min; /// enum uintptr_t UINTPTR_MAX = uintptr_t.max; /// enum intmax_t INTMAX_MIN = intmax_t.min; /// enum intmax_t INTMAX_MAX = intmax_t.max; /// enum uintmax_t UINTMAX_MAX = uintmax_t.max; /// enum ptrdiff_t PTRDIFF_MIN = ptrdiff_t.min; /// enum ptrdiff_t PTRDIFF_MAX = ptrdiff_t.max; /// enum sig_atomic_t SIG_ATOMIC_MIN = sig_atomic_t.min; /// enum sig_atomic_t SIG_ATOMIC_MAX = sig_atomic_t.max; /// enum size_t SIZE_MAX = size_t.max; /// enum wchar_t WCHAR_MIN = wchar_t.min; /// enum wchar_t WCHAR_MAX = wchar_t.max; /// enum wint_t WINT_MIN = wint_t.min; /// enum wint_t WINT_MAX = wint_t.max; /// alias INT8_C = _typify!int8_t ; /// alias INT16_C = _typify!int16_t; /// alias INT32_C = _typify!int32_t; /// alias INT64_C = _typify!int64_t; /// alias UINT8_C = _typify!uint8_t ; /// alias UINT16_C = _typify!uint16_t; /// alias UINT32_C = _typify!uint32_t; /// alias UINT64_C = _typify!uint64_t; /// alias INTMAX_C = _typify!intmax_t ; /// alias UINTMAX_C = _typify!uintmax_t; ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/tgmath.d0000664000175000017500000011360512776214756021576 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_tgmath.h.html, _tgmath.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_tgmath.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.tgmath; private import core.stdc.config; private static import core.stdc.math; private static import core.stdc.complex; extern (C): @trusted: // Everything here operates on floating point and integer values. nothrow: @nogc: version( FreeBSD ) { /// alias core.stdc.math.acos acos; /// alias core.stdc.math.acosf acos; /// alias core.stdc.math.acosl acos; /// alias core.stdc.complex.cacos acos; /// alias core.stdc.complex.cacosf acos; /// alias core.stdc.complex.cacosl acos; /// alias core.stdc.math.asin asin; /// alias core.stdc.math.asinf asin; /// alias core.stdc.math.asinl asin; /// alias core.stdc.complex.casin asin; /// alias core.stdc.complex.casinf asin; /// alias core.stdc.complex.casinl asin; /// alias core.stdc.math.atan atan; /// alias core.stdc.math.atanf atan; /// alias core.stdc.math.atanl atan; /// alias core.stdc.complex.catan atan; /// alias core.stdc.complex.catanf atan; /// alias core.stdc.complex.catanl atan; /// alias core.stdc.math.atan2 atan2; /// alias core.stdc.math.atan2f atan2; /// alias core.stdc.math.atan2l atan2; /// alias core.stdc.math.cos cos; /// alias core.stdc.math.cosf cos; /// alias core.stdc.math.cosl cos; /// alias core.stdc.complex.ccos cos; /// alias core.stdc.complex.ccosf cos; /// alias core.stdc.complex.ccosl cos; /// alias core.stdc.math.sin sin; /// alias core.stdc.math.sinf sin; /// alias core.stdc.math.sinl sin; /// alias core.stdc.complex.csin csin; /// alias core.stdc.complex.csinf csin; /// alias core.stdc.complex.csinl csin; /// alias core.stdc.math.tan tan; /// alias core.stdc.math.tanf tan; /// alias core.stdc.math.tanl tan; /// alias core.stdc.complex.ctan tan; /// alias core.stdc.complex.ctanf tan; /// alias core.stdc.complex.ctanl tan; /// alias core.stdc.math.acosh acosh; /// alias core.stdc.math.acoshf acosh; /// alias core.stdc.math.acoshl acosh; /// alias core.stdc.complex.cacosh acosh; /// alias core.stdc.complex.cacoshf acosh; /// alias core.stdc.complex.cacoshl acosh; /// alias core.stdc.math.asinh asinh; /// alias core.stdc.math.asinhf asinh; /// alias core.stdc.math.asinhl asinh; /// alias core.stdc.complex.casinh asinh; /// alias core.stdc.complex.casinhf asinh; /// alias core.stdc.complex.casinhl asinh; /// alias core.stdc.math.atanh atanh; /// alias core.stdc.math.atanhf atanh; /// alias core.stdc.math.atanhl atanh; /// alias core.stdc.complex.catanh atanh; /// alias core.stdc.complex.catanhf atanh; /// alias core.stdc.complex.catanhl atanh; /// alias core.stdc.math.cosh cosh; /// alias core.stdc.math.coshf cosh; /// alias core.stdc.math.coshl cosh; /// alias core.stdc.complex.ccosh cosh; /// alias core.stdc.complex.ccoshf cosh; /// alias core.stdc.complex.ccoshl cosh; /// alias core.stdc.math.sinh sinh; /// alias core.stdc.math.sinhf sinh; /// alias core.stdc.math.sinhl sinh; /// alias core.stdc.complex.csinh sinh; /// alias core.stdc.complex.csinhf sinh; /// alias core.stdc.complex.csinhl sinh; /// alias core.stdc.math.tanh tanh; /// alias core.stdc.math.tanhf tanh; /// alias core.stdc.math.tanhl tanh; /// alias core.stdc.complex.ctanh tanh; /// alias core.stdc.complex.ctanhf tanh; /// alias core.stdc.complex.ctanhl tanh; /// alias core.stdc.math.exp exp; /// alias core.stdc.math.expf exp; /// alias core.stdc.math.expl exp; /// alias core.stdc.complex.cexp exp; /// alias core.stdc.complex.cexpf exp; /// alias core.stdc.complex.cexpl exp; /// alias core.stdc.math.exp2 exp2; /// alias core.stdc.math.exp2f exp2; /// alias core.stdc.math.exp2l exp2; /// alias core.stdc.math.expm1 expm1; /// alias core.stdc.math.expm1f expm1; /// alias core.stdc.math.expm1l expm1; /// alias core.stdc.math.frexp frexp; /// alias core.stdc.math.frexpf frexp; /// alias core.stdc.math.frexpl frexp; /// alias core.stdc.math.ilogb ilogb; /// alias core.stdc.math.ilogbf ilogb; /// alias core.stdc.math.ilogbl ilogb; /// alias core.stdc.math.ldexp ldexp; /// alias core.stdc.math.ldexpf ldexp; /// alias core.stdc.math.ldexpl ldexp; /// alias core.stdc.math.log log; /// alias core.stdc.math.logf log; /// alias core.stdc.math.logl log; /// alias core.stdc.complex.clog log; /// alias core.stdc.complex.clogf log; /// alias core.stdc.complex.clogl log; /// alias core.stdc.math.log10 log10; /// alias core.stdc.math.log10f log10; /// alias core.stdc.math.log10l log10; /// alias core.stdc.math.log1p log1p; /// alias core.stdc.math.log1pf log1p; /// alias core.stdc.math.log1pl log1p; /// alias core.stdc.math.log2 log2; /// alias core.stdc.math.log2f log2; /// alias core.stdc.math.log2l log2; /// alias core.stdc.math.logb logb; /// alias core.stdc.math.logbf logb; /// alias core.stdc.math.logbl logb; /// alias core.stdc.math.modf modf; /// alias core.stdc.math.modff modf; // alias core.stdc.math.modfl modf; /// alias core.stdc.math.scalbn scalbn; /// alias core.stdc.math.scalbnf scalbn; /// alias core.stdc.math.scalbnl scalbn; /// alias core.stdc.math.scalbln scalbln; /// alias core.stdc.math.scalblnf scalbln; /// alias core.stdc.math.scalblnl scalbln; /// alias core.stdc.math.cbrt cbrt; /// alias core.stdc.math.cbrtf cbrt; /// alias core.stdc.math.cbrtl cbrt; /// alias core.stdc.math.fabs fabs; /// alias core.stdc.math.fabsf fabs; /// alias core.stdc.math.fabsl fabs; /// alias core.stdc.complex.cabs fabs; /// alias core.stdc.complex.cabsf fabs; /// alias core.stdc.complex.cabsl fabs; /// alias core.stdc.math.hypot hypot; /// alias core.stdc.math.hypotf hypot; /// alias core.stdc.math.hypotl hypot; /// alias core.stdc.math.pow pow; /// alias core.stdc.math.powf pow; /// alias core.stdc.math.powl pow; /// alias core.stdc.complex.cpow pow; /// alias core.stdc.complex.cpowf pow; /// alias core.stdc.complex.cpowl pow; /// alias core.stdc.math.sqrt sqrt; /// alias core.stdc.math.sqrtf sqrt; /// alias core.stdc.math.sqrtl sqrt; /// alias core.stdc.complex.csqrt sqrt; /// alias core.stdc.complex.csqrtf sqrt; /// alias core.stdc.complex.csqrtl sqrt; /// alias core.stdc.math.erf erf; /// alias core.stdc.math.erff erf; /// alias core.stdc.math.erfl erf; /// alias core.stdc.math.erfc erfc; /// alias core.stdc.math.erfcf erfc; /// alias core.stdc.math.erfcl erfc; /// alias core.stdc.math.lgamma lgamma; /// alias core.stdc.math.lgammaf lgamma; /// alias core.stdc.math.lgammal lgamma; /// alias core.stdc.math.tgamma tgamma; /// alias core.stdc.math.tgammaf tgamma; /// alias core.stdc.math.tgammal tgamma; /// alias core.stdc.math.ceil ceil; /// alias core.stdc.math.ceilf ceil; /// alias core.stdc.math.ceill ceil; /// alias core.stdc.math.floor floor; /// alias core.stdc.math.floorf floor; /// alias core.stdc.math.floorl floor; /// alias core.stdc.math.nearbyint nearbyint; /// alias core.stdc.math.nearbyintf nearbyint; /// alias core.stdc.math.nearbyintl nearbyint; /// alias core.stdc.math.rint rint; /// alias core.stdc.math.rintf rint; /// alias core.stdc.math.rintl rint; /// alias core.stdc.math.lrint lrint; /// alias core.stdc.math.lrintf lrint; /// alias core.stdc.math.lrintl lrint; /// alias core.stdc.math.llrint llrint; /// alias core.stdc.math.llrintf llrint; /// alias core.stdc.math.llrintl llrint; /// alias core.stdc.math.round round; /// alias core.stdc.math.roundf round; /// alias core.stdc.math.roundl round; /// alias core.stdc.math.lround lround; /// alias core.stdc.math.lroundf lround; /// alias core.stdc.math.lroundl lround; /// alias core.stdc.math.llround llround; /// alias core.stdc.math.llroundf llround; /// alias core.stdc.math.llroundl llround; /// alias core.stdc.math.trunc trunc; /// alias core.stdc.math.truncf trunc; /// alias core.stdc.math.truncl trunc; /// alias core.stdc.math.fmod fmod; /// alias core.stdc.math.fmodf fmod; /// alias core.stdc.math.fmodl fmod; /// alias core.stdc.math.remainder remainder; /// alias core.stdc.math.remainderf remainder; /// alias core.stdc.math.remainderl remainder; /// alias core.stdc.math.remquo remquo; /// alias core.stdc.math.remquof remquo; /// alias core.stdc.math.remquol remquo; /// alias core.stdc.math.copysign copysign; /// alias core.stdc.math.copysignf copysign; /// alias core.stdc.math.copysignl copysign; // alias core.stdc.math.nan nan; // alias core.stdc.math.nanf nan; // alias core.stdc.math.nanl nan; /// alias core.stdc.math.nextafter nextafter; /// alias core.stdc.math.nextafterf nextafter; /// alias core.stdc.math.nextafterl nextafter; /// alias core.stdc.math.nexttoward nexttoward; /// alias core.stdc.math.nexttowardf nexttoward; /// alias core.stdc.math.nexttowardl nexttoward; /// alias core.stdc.math.fdim fdim; /// alias core.stdc.math.fdimf fdim; /// alias core.stdc.math.fdiml fdim; /// alias core.stdc.math.fmax fmax; /// alias core.stdc.math.fmaxf fmax; /// alias core.stdc.math.fmaxl fmax; /// alias core.stdc.math.fmin fmin; /// alias core.stdc.math.fmin fmin; /// alias core.stdc.math.fminl fmin; /// alias core.stdc.math.fma fma; /// alias core.stdc.math.fmaf fma; /// alias core.stdc.math.fmal fma; /// alias core.stdc.complex.carg carg; /// alias core.stdc.complex.cargf carg; /// alias core.stdc.complex.cargl carg; /// alias core.stdc.complex.cimag cimag; /// alias core.stdc.complex.cimagf cimag; /// alias core.stdc.complex.cimagl cimag; /// alias core.stdc.complex.conj conj; /// alias core.stdc.complex.conjf conj; /// alias core.stdc.complex.conjl conj; /// alias core.stdc.complex.cproj cproj; /// alias core.stdc.complex.cprojf cproj; /// alias core.stdc.complex.cprojl cproj; // alias core.stdc.complex.creal creal; // alias core.stdc.complex.crealf creal; // alias core.stdc.complex.creall creal; } else version( OpenBSD ) { /// alias core.stdc.math.acos acos; /// alias core.stdc.math.acosf acos; /// alias core.stdc.math.acosl acos; /// alias core.stdc.complex.cacos acos; /// alias core.stdc.complex.cacosf acos; /// alias core.stdc.complex.cacosl acos; /// alias core.stdc.math.asin asin; /// alias core.stdc.math.asinf asin; /// alias core.stdc.math.asinl asin; /// alias core.stdc.complex.casin asin; /// alias core.stdc.complex.casinf asin; /// alias core.stdc.complex.casinl asin; /// alias core.stdc.math.atan atan; /// alias core.stdc.math.atanf atan; /// alias core.stdc.math.atanl atan; /// alias core.stdc.complex.catan atan; /// alias core.stdc.complex.catanf atan; /// alias core.stdc.complex.catanl atan; /// alias core.stdc.math.atan2 atan2; /// alias core.stdc.math.atan2f atan2; /// alias core.stdc.math.atan2l atan2; /// alias core.stdc.math.cos cos; /// alias core.stdc.math.cosf cos; /// alias core.stdc.math.cosl cos; /// alias core.stdc.complex.ccos cos; /// alias core.stdc.complex.ccosf cos; /// alias core.stdc.complex.ccosl cos; /// alias core.stdc.math.sin sin; /// alias core.stdc.math.sinf sin; /// alias core.stdc.math.sinl sin; /// alias core.stdc.complex.csin csin; /// alias core.stdc.complex.csinf csin; /// alias core.stdc.complex.csinl csin; /// alias core.stdc.math.tan tan; /// alias core.stdc.math.tanf tan; /// alias core.stdc.math.tanl tan; /// alias core.stdc.complex.ctan tan; /// alias core.stdc.complex.ctanf tan; /// alias core.stdc.complex.ctanl tan; /// alias core.stdc.math.acosh acosh; /// alias core.stdc.math.acoshf acosh; /// alias core.stdc.math.acoshl acosh; /// alias core.stdc.complex.cacosh acosh; /// alias core.stdc.complex.cacoshf acosh; /// alias core.stdc.complex.cacoshl acosh; /// alias core.stdc.math.asinh asinh; /// alias core.stdc.math.asinhf asinh; /// alias core.stdc.math.asinhl asinh; /// alias core.stdc.complex.casinh asinh; /// alias core.stdc.complex.casinhf asinh; /// alias core.stdc.complex.casinhl asinh; /// alias core.stdc.math.atanh atanh; /// alias core.stdc.math.atanhf atanh; /// alias core.stdc.math.atanhl atanh; /// alias core.stdc.complex.catanh atanh; /// alias core.stdc.complex.catanhf atanh; /// alias core.stdc.complex.catanhl atanh; /// alias core.stdc.math.cosh cosh; /// alias core.stdc.math.coshf cosh; /// alias core.stdc.math.coshl cosh; /// alias core.stdc.complex.ccosh cosh; /// alias core.stdc.complex.ccoshf cosh; /// alias core.stdc.complex.ccoshl cosh; /// alias core.stdc.math.sinh sinh; /// alias core.stdc.math.sinhf sinh; /// alias core.stdc.math.sinhl sinh; /// alias core.stdc.complex.csinh sinh; /// alias core.stdc.complex.csinhf sinh; /// alias core.stdc.complex.csinhl sinh; /// alias core.stdc.math.tanh tanh; /// alias core.stdc.math.tanhf tanh; /// alias core.stdc.math.tanhl tanh; /// alias core.stdc.complex.ctanh tanh; /// alias core.stdc.complex.ctanhf tanh; /// alias core.stdc.complex.ctanhl tanh; /// alias core.stdc.math.exp exp; /// alias core.stdc.math.expf exp; /// alias core.stdc.math.expl exp; /// alias core.stdc.complex.cexp exp; /// alias core.stdc.complex.cexpf exp; /// alias core.stdc.complex.cexpl exp; /// alias core.stdc.math.exp2 exp2; /// alias core.stdc.math.exp2f exp2; /// alias core.stdc.math.exp2l exp2; /// alias core.stdc.math.expm1 expm1; /// alias core.stdc.math.expm1f expm1; /// alias core.stdc.math.expm1l expm1; /// alias core.stdc.math.frexp frexp; /// alias core.stdc.math.frexpf frexp; /// alias core.stdc.math.frexpl frexp; /// alias core.stdc.math.ilogb ilogb; /// alias core.stdc.math.ilogbf ilogb; /// alias core.stdc.math.ilogbl ilogb; /// alias core.stdc.math.ldexp ldexp; /// alias core.stdc.math.ldexpf ldexp; /// alias core.stdc.math.ldexpl ldexp; /// alias core.stdc.math.log log; /// alias core.stdc.math.logf log; /// alias core.stdc.math.logl log; /// alias core.stdc.complex.clog log; /// alias core.stdc.complex.clogf log; /// alias core.stdc.complex.clogl log; /// alias core.stdc.math.log10 log10; /// alias core.stdc.math.log10f log10; /// alias core.stdc.math.log10l log10; /// alias core.stdc.math.log1p log1p; /// alias core.stdc.math.log1pf log1p; /// alias core.stdc.math.log1pl log1p; /// alias core.stdc.math.log2 log2; /// alias core.stdc.math.log2f log2; /// alias core.stdc.math.log2l log2; /// alias core.stdc.math.logb logb; /// alias core.stdc.math.logbf logb; /// alias core.stdc.math.logbl logb; /// alias core.stdc.math.fmod fmod; /// alias core.stdc.math.fmodf fmod; /// alias core.stdc.math.fmodl fmod; /// alias core.stdc.math.scalbn scalbn; /// alias core.stdc.math.scalbnf scalbn; /// alias core.stdc.math.scalbnl scalbn; /// alias core.stdc.math.scalbln scalbln; /// alias core.stdc.math.scalblnf scalbln; /// alias core.stdc.math.scalblnl scalbln; /// alias core.stdc.math.cbrt cbrt; /// alias core.stdc.math.cbrtf cbrt; /// alias core.stdc.math.cbrtl cbrt; /// alias core.stdc.math.fabs fabs; /// alias core.stdc.math.fabsf fabs; /// alias core.stdc.math.fabsl fabs; /// alias core.stdc.complex.cabs fabs; /// alias core.stdc.complex.cabsf fabs; /// alias core.stdc.complex.cabsl fabs; /// alias core.stdc.math.hypot hypot; /// alias core.stdc.math.hypotf hypot; /// alias core.stdc.math.hypotl hypot; /// alias core.stdc.math.pow pow; /// alias core.stdc.math.powf pow; /// alias core.stdc.math.powl pow; /// alias core.stdc.complex.cpow pow; /// alias core.stdc.complex.cpowf pow; /// alias core.stdc.complex.cpowl pow; /// alias core.stdc.math.sqrt sqrt; /// alias core.stdc.math.sqrtf sqrt; /// alias core.stdc.math.sqrtl sqrt; /// alias core.stdc.complex.csqrt sqrt; /// alias core.stdc.complex.csqrtf sqrt; /// alias core.stdc.complex.csqrtl sqrt; /// alias core.stdc.math.erf erf; /// alias core.stdc.math.erff erf; /// alias core.stdc.math.erfl erf; /// alias core.stdc.math.erfc erfc; /// alias core.stdc.math.erfcf erfc; /// alias core.stdc.math.erfcl erfc; /// alias core.stdc.math.lgamma lgamma; /// alias core.stdc.math.lgammaf lgamma; /// alias core.stdc.math.lgammal lgamma; /// alias core.stdc.math.tgamma tgamma; /// alias core.stdc.math.tgammaf tgamma; /// alias core.stdc.math.tgammal tgamma; /// alias core.stdc.math.ceil ceil; /// alias core.stdc.math.ceilf ceil; /// alias core.stdc.math.ceill ceil; /// alias core.stdc.math.floor floor; /// alias core.stdc.math.floorf floor; /// alias core.stdc.math.floorl floor; /// alias core.stdc.math.nearbyint nearbyint; /// alias core.stdc.math.nearbyintf nearbyint; /// alias core.stdc.math.nearbyintl nearbyint; /// alias core.stdc.math.rint rint; /// alias core.stdc.math.rintf rint; /// alias core.stdc.math.rintl rint; /// alias core.stdc.math.lrint lrint; /// alias core.stdc.math.lrintf lrint; /// alias core.stdc.math.lrintl lrint; /// alias core.stdc.math.llrint llrint; /// alias core.stdc.math.llrintf llrint; /// alias core.stdc.math.llrintl llrint; /// alias core.stdc.math.round round; /// alias core.stdc.math.roundf round; /// alias core.stdc.math.roundl round; /// alias core.stdc.math.lround lround; /// alias core.stdc.math.lroundf lround; /// alias core.stdc.math.lroundl lround; /// alias core.stdc.math.llround llround; /// alias core.stdc.math.llroundf llround; /// alias core.stdc.math.llroundl llround; /// alias core.stdc.math.trunc trunc; /// alias core.stdc.math.truncf trunc; /// alias core.stdc.math.truncl trunc; /// alias core.stdc.math.remainder remainder; /// alias core.stdc.math.remainderf remainder; /// alias core.stdc.math.remainderl remainder; /// alias core.stdc.math.remquo remquo; /// alias core.stdc.math.remquof remquo; /// alias core.stdc.math.remquol remquo; /// alias core.stdc.math.copysign copysign; /// alias core.stdc.math.copysignf copysign; /// alias core.stdc.math.copysignl copysign; /// alias core.stdc.math.nextafter nextafter; /// alias core.stdc.math.nextafterf nextafter; /// alias core.stdc.math.nextafterl nextafter; /// alias core.stdc.math.nexttoward nexttoward; /// alias core.stdc.math.nexttowardf nexttoward; /// alias core.stdc.math.nexttowardl nexttoward; /// alias core.stdc.math.fdim fdim; /// alias core.stdc.math.fdimf fdim; /// alias core.stdc.math.fdiml fdim; /// alias core.stdc.math.fmax fmax; /// alias core.stdc.math.fmaxf fmax; /// alias core.stdc.math.fmaxl fmax; /// alias core.stdc.math.fmin fmin; /// alias core.stdc.math.fmin fmin; /// alias core.stdc.math.fminl fmin; /// alias core.stdc.math.fma fma; /// alias core.stdc.math.fmaf fma; /// alias core.stdc.math.fmal fma; /// alias core.stdc.complex.carg carg; /// alias core.stdc.complex.cargf carg; /// alias core.stdc.complex.cargl carg; /// alias core.stdc.complex.cimag cimag; /// alias core.stdc.complex.cimagf cimag; /// alias core.stdc.complex.cimagl cimag; /// alias core.stdc.complex.conj conj; /// alias core.stdc.complex.conjf conj; /// alias core.stdc.complex.conjl conj; /// alias core.stdc.complex.cproj cproj; /// alias core.stdc.complex.cprojf cproj; /// alias core.stdc.complex.cprojl cproj; // alias core.stdc.complex.creal creal; // alias core.stdc.complex.crealf creal; // alias core.stdc.complex.creall creal; } else { /// alias core.stdc.math.acos acos; /// alias core.stdc.math.acosf acos; /// alias core.stdc.math.acosl acos; /// alias core.stdc.complex.cacos acos; /// alias core.stdc.complex.cacosf acos; /// alias core.stdc.complex.cacosl acos; /// alias core.stdc.math.asin asin; /// alias core.stdc.math.asinf asin; /// alias core.stdc.math.asinl asin; /// alias core.stdc.complex.casin asin; /// alias core.stdc.complex.casinf asin; /// alias core.stdc.complex.casinl asin; /// alias core.stdc.math.atan atan; /// alias core.stdc.math.atanf atan; /// alias core.stdc.math.atanl atan; /// alias core.stdc.complex.catan atan; /// alias core.stdc.complex.catanf atan; /// alias core.stdc.complex.catanl atan; /// alias core.stdc.math.atan2 atan2; /// alias core.stdc.math.atan2f atan2; /// alias core.stdc.math.atan2l atan2; /// alias core.stdc.math.cos cos; /// alias core.stdc.math.cosf cos; /// alias core.stdc.math.cosl cos; /// alias core.stdc.complex.ccos cos; /// alias core.stdc.complex.ccosf cos; /// alias core.stdc.complex.ccosl cos; /// alias core.stdc.math.sin sin; /// alias core.stdc.math.sinf sin; /// alias core.stdc.math.sinl sin; /// alias core.stdc.complex.csin csin; /// alias core.stdc.complex.csinf csin; /// alias core.stdc.complex.csinl csin; /// alias core.stdc.math.tan tan; /// alias core.stdc.math.tanf tan; /// alias core.stdc.math.tanl tan; /// alias core.stdc.complex.ctan tan; /// alias core.stdc.complex.ctanf tan; /// alias core.stdc.complex.ctanl tan; /// alias core.stdc.math.acosh acosh; /// alias core.stdc.math.acoshf acosh; /// alias core.stdc.math.acoshl acosh; /// alias core.stdc.complex.cacosh acosh; /// alias core.stdc.complex.cacoshf acosh; /// alias core.stdc.complex.cacoshl acosh; /// alias core.stdc.math.asinh asinh; /// alias core.stdc.math.asinhf asinh; /// alias core.stdc.math.asinhl asinh; /// alias core.stdc.complex.casinh asinh; /// alias core.stdc.complex.casinhf asinh; /// alias core.stdc.complex.casinhl asinh; /// alias core.stdc.math.atanh atanh; /// alias core.stdc.math.atanhf atanh; /// alias core.stdc.math.atanhl atanh; /// alias core.stdc.complex.catanh atanh; /// alias core.stdc.complex.catanhf atanh; /// alias core.stdc.complex.catanhl atanh; /// alias core.stdc.math.cosh cosh; /// alias core.stdc.math.coshf cosh; /// alias core.stdc.math.coshl cosh; /// alias core.stdc.complex.ccosh cosh; /// alias core.stdc.complex.ccoshf cosh; /// alias core.stdc.complex.ccoshl cosh; /// alias core.stdc.math.sinh sinh; /// alias core.stdc.math.sinhf sinh; /// alias core.stdc.math.sinhl sinh; /// alias core.stdc.complex.csinh sinh; /// alias core.stdc.complex.csinhf sinh; /// alias core.stdc.complex.csinhl sinh; /// alias core.stdc.math.tanh tanh; /// alias core.stdc.math.tanhf tanh; /// alias core.stdc.math.tanhl tanh; /// alias core.stdc.complex.ctanh tanh; /// alias core.stdc.complex.ctanhf tanh; /// alias core.stdc.complex.ctanhl tanh; /// alias core.stdc.math.exp exp; /// alias core.stdc.math.expf exp; /// alias core.stdc.math.expl exp; /// alias core.stdc.complex.cexp exp; /// alias core.stdc.complex.cexpf exp; /// alias core.stdc.complex.cexpl exp; /// alias core.stdc.math.exp2 exp2; /// alias core.stdc.math.exp2f exp2; /// alias core.stdc.math.exp2l exp2; /// alias core.stdc.math.expm1 expm1; /// alias core.stdc.math.expm1f expm1; /// alias core.stdc.math.expm1l expm1; /// alias core.stdc.math.frexp frexp; /// alias core.stdc.math.frexpf frexp; /// alias core.stdc.math.frexpl frexp; /// alias core.stdc.math.ilogb ilogb; /// alias core.stdc.math.ilogbf ilogb; /// alias core.stdc.math.ilogbl ilogb; /// alias core.stdc.math.ldexp ldexp; /// alias core.stdc.math.ldexpf ldexp; /// alias core.stdc.math.ldexpl ldexp; /// alias core.stdc.math.log log; /// alias core.stdc.math.logf log; /// alias core.stdc.math.logl log; /// alias core.stdc.complex.clog log; /// alias core.stdc.complex.clogf log; /// alias core.stdc.complex.clogl log; /// alias core.stdc.math.log10 log10; /// alias core.stdc.math.log10f log10; /// alias core.stdc.math.log10l log10; /// alias core.stdc.math.log1p log1p; /// alias core.stdc.math.log1pf log1p; /// alias core.stdc.math.log1pl log1p; /// alias core.stdc.math.log2 log2; /// alias core.stdc.math.log2f log2; /// alias core.stdc.math.log2l log2; /// alias core.stdc.math.logb logb; /// alias core.stdc.math.logbf logb; /// alias core.stdc.math.logbl logb; /// alias core.stdc.math.modf modf; /// alias core.stdc.math.modff modf; /// alias core.stdc.math.modfl modf; /// alias core.stdc.math.scalbn scalbn; /// alias core.stdc.math.scalbnf scalbn; /// alias core.stdc.math.scalbnl scalbn; /// alias core.stdc.math.scalbln scalbln; /// alias core.stdc.math.scalblnf scalbln; /// alias core.stdc.math.scalblnl scalbln; /// alias core.stdc.math.cbrt cbrt; /// alias core.stdc.math.cbrtf cbrt; /// alias core.stdc.math.cbrtl cbrt; /// alias core.stdc.math.fabs fabs; version( CRuntime_Microsoft ) { } else { /// alias core.stdc.math.fabsf fabs; /// alias core.stdc.math.fabsl fabs; } /// alias core.stdc.complex.cabs fabs; /// alias core.stdc.complex.cabsf fabs; /// alias core.stdc.complex.cabsl fabs; /// alias core.stdc.math.hypot hypot; /// alias core.stdc.math.hypotf hypot; /// alias core.stdc.math.hypotl hypot; /// alias core.stdc.math.pow pow; /// alias core.stdc.math.powf pow; /// alias core.stdc.math.powl pow; /// alias core.stdc.complex.cpow pow; /// alias core.stdc.complex.cpowf pow; /// alias core.stdc.complex.cpowl pow; /// alias core.stdc.math.sqrt sqrt; /// alias core.stdc.math.sqrtf sqrt; /// alias core.stdc.math.sqrtl sqrt; /// alias core.stdc.complex.csqrt sqrt; /// alias core.stdc.complex.csqrtf sqrt; /// alias core.stdc.complex.csqrtl sqrt; /// alias core.stdc.math.erf erf; /// alias core.stdc.math.erff erf; /// alias core.stdc.math.erfl erf; /// alias core.stdc.math.erfc erfc; /// alias core.stdc.math.erfcf erfc; /// alias core.stdc.math.erfcl erfc; /// alias core.stdc.math.lgamma lgamma; /// alias core.stdc.math.lgammaf lgamma; /// alias core.stdc.math.lgammal lgamma; /// alias core.stdc.math.tgamma tgamma; /// alias core.stdc.math.tgammaf tgamma; /// alias core.stdc.math.tgammal tgamma; /// alias core.stdc.math.ceil ceil; /// alias core.stdc.math.ceilf ceil; /// alias core.stdc.math.ceill ceil; /// alias core.stdc.math.floor floor; /// alias core.stdc.math.floorf floor; /// alias core.stdc.math.floorl floor; /// alias core.stdc.math.nearbyint nearbyint; /// alias core.stdc.math.nearbyintf nearbyint; /// alias core.stdc.math.nearbyintl nearbyint; /// alias core.stdc.math.rint rint; /// alias core.stdc.math.rintf rint; /// alias core.stdc.math.rintl rint; /// alias core.stdc.math.lrint lrint; /// alias core.stdc.math.lrintf lrint; /// alias core.stdc.math.lrintl lrint; /// alias core.stdc.math.llrint llrint; /// alias core.stdc.math.llrintf llrint; /// alias core.stdc.math.llrintl llrint; /// alias core.stdc.math.round round; /// alias core.stdc.math.roundf round; /// alias core.stdc.math.roundl round; /// alias core.stdc.math.lround lround; /// alias core.stdc.math.lroundf lround; /// alias core.stdc.math.lroundl lround; /// alias core.stdc.math.llround llround; /// alias core.stdc.math.llroundf llround; /// alias core.stdc.math.llroundl llround; /// alias core.stdc.math.trunc trunc; /// alias core.stdc.math.truncf trunc; /// alias core.stdc.math.truncl trunc; /// alias core.stdc.math.fmod fmod; /// alias core.stdc.math.fmodf fmod; /// alias core.stdc.math.fmodl fmod; /// alias core.stdc.math.remainder remainder; /// alias core.stdc.math.remainderf remainder; /// alias core.stdc.math.remainderl remainder; /// alias core.stdc.math.remquo remquo; /// alias core.stdc.math.remquof remquo; /// alias core.stdc.math.remquol remquo; /// alias core.stdc.math.copysign copysign; /// alias core.stdc.math.copysignf copysign; /// alias core.stdc.math.copysignl copysign; /// alias core.stdc.math.nan nan; /// alias core.stdc.math.nanf nan; /// alias core.stdc.math.nanl nan; /// alias core.stdc.math.nextafter nextafter; /// alias core.stdc.math.nextafterf nextafter; /// alias core.stdc.math.nextafterl nextafter; /// alias core.stdc.math.nexttoward nexttoward; /// alias core.stdc.math.nexttowardf nexttoward; /// alias core.stdc.math.nexttowardl nexttoward; /// alias core.stdc.math.fdim fdim; /// alias core.stdc.math.fdimf fdim; /// alias core.stdc.math.fdiml fdim; /// alias core.stdc.math.fmax fmax; /// alias core.stdc.math.fmaxf fmax; /// alias core.stdc.math.fmaxl fmax; /// alias core.stdc.math.fmin fmin; /// alias core.stdc.math.fmin fmin; /// alias core.stdc.math.fminl fmin; /// alias core.stdc.math.fma fma; /// alias core.stdc.math.fmaf fma; /// alias core.stdc.math.fmal fma; /// alias core.stdc.complex.carg carg; /// alias core.stdc.complex.cargf carg; /// alias core.stdc.complex.cargl carg; /// alias core.stdc.complex.cimag cimag; /// alias core.stdc.complex.cimagf cimag; /// alias core.stdc.complex.cimagl cimag; /// alias core.stdc.complex.conj conj; /// alias core.stdc.complex.conjf conj; /// alias core.stdc.complex.conjl conj; /// alias core.stdc.complex.cproj cproj; /// alias core.stdc.complex.cprojf cproj; /// alias core.stdc.complex.cprojl cproj; // alias core.stdc.complex.creal creal; // alias core.stdc.complex.crealf creal; // alias core.stdc.complex.creall creal; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/inttypes.d0000664000175000017500000002055612776214756022173 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_inttypes.h.html, _inttypes.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_inttypes.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.inttypes; public import core.stdc.stddef; // for wchar_t public import core.stdc.stdint; // required by spec extern (C): @trusted: // Types and constants only. nothrow: @nogc: /// struct imaxdiv_t { intmax_t quot, rem; } private alias immutable(char)* _cstr; /// enum _cstr PRId8 = "hhd"; /// enum _cstr PRId16 = "hd"; /// enum _cstr PRId32 = "ld"; /// enum _cstr PRId64 = "lld"; /// enum _cstr PRIdLEAST8 = "hhd"; /// enum _cstr PRIdLEAST16 = "hd"; /// enum _cstr PRIdLEAST32 = "ld"; /// enum _cstr PRIdLEAST64 = "lld"; /// enum _cstr PRIdFAST8 = "hhd"; /// enum _cstr PRIdFAST16 = "d"; /// enum _cstr PRIdFAST32 = "ld"; /// enum _cstr PRIdFAST64 = "lld"; /// enum _cstr PRIi8 = "hhi"; /// enum _cstr PRIi16 = "hi"; /// enum _cstr PRIi32 = "li"; /// enum _cstr PRIi64 = "lli"; /// enum _cstr PRIiLEAST8 = "hhi"; /// enum _cstr PRIiLEAST16 = "hi"; /// enum _cstr PRIiLEAST32 = "li"; /// enum _cstr PRIiLEAST64 = "lli"; /// enum _cstr PRIiFAST8 = "hhi"; /// enum _cstr PRIiFAST16 = "i"; /// enum _cstr PRIiFAST32 = "li"; /// enum _cstr PRIiFAST64 = "lli"; /// enum _cstr PRIo8 = "hho"; /// enum _cstr PRIo16 = "ho"; /// enum _cstr PRIo32 = "lo"; /// enum _cstr PRIo64 = "llo"; /// enum _cstr PRIoLEAST8 = "hho"; /// enum _cstr PRIoLEAST16 = "ho"; /// enum _cstr PRIoLEAST32 = "lo"; /// enum _cstr PRIoLEAST64 = "llo"; /// enum _cstr PRIoFAST8 = "hho"; /// enum _cstr PRIoFAST16 = "o"; /// enum _cstr PRIoFAST32 = "lo"; /// enum _cstr PRIoFAST64 = "llo"; /// enum _cstr PRIu8 = "hhu"; /// enum _cstr PRIu16 = "hu"; /// enum _cstr PRIu32 = "lu"; /// enum _cstr PRIu64 = "llu"; /// enum _cstr PRIuLEAST8 = "hhu"; /// enum _cstr PRIuLEAST16 = "hu"; /// enum _cstr PRIuLEAST32 = "lu"; /// enum _cstr PRIuLEAST64 = "llu"; /// enum _cstr PRIuFAST8 = "hhu"; /// enum _cstr PRIuFAST16 = "u"; /// enum _cstr PRIuFAST32 = "lu"; /// enum _cstr PRIuFAST64 = "llu"; /// enum _cstr PRIx8 = "hhx"; /// enum _cstr PRIx16 = "hx"; /// enum _cstr PRIx32 = "lx"; /// enum _cstr PRIx64 = "llx"; /// enum _cstr PRIxLEAST8 = "hhx"; /// enum _cstr PRIxLEAST16 = "hx"; /// enum _cstr PRIxLEAST32 = "lx"; /// enum _cstr PRIxLEAST64 = "llx"; /// enum _cstr PRIxFAST8 = "hhx"; /// enum _cstr PRIxFAST16 = "x"; /// enum _cstr PRIxFAST32 = "lx"; /// enum _cstr PRIxFAST64 = "llx"; /// enum _cstr PRIX8 = "hhX"; /// enum _cstr PRIX16 = "hX"; /// enum _cstr PRIX32 = "lX"; /// enum _cstr PRIX64 = "llX"; /// enum _cstr PRIXLEAST8 = "hhX"; /// enum _cstr PRIXLEAST16 = "hX"; /// enum _cstr PRIXLEAST32 = "lX"; /// enum _cstr PRIXLEAST64 = "llX"; /// enum _cstr PRIXFAST8 = "hhX"; /// enum _cstr PRIXFAST16 = "X"; /// enum _cstr PRIXFAST32 = "lX"; /// enum _cstr PRIXFAST64 = "llX"; /// enum _cstr SCNd8 = "hhd"; /// enum _cstr SCNd16 = "hd"; /// enum _cstr SCNd32 = "ld"; /// enum _cstr SCNd64 = "lld"; /// enum _cstr SCNdLEAST8 = "hhd"; /// enum _cstr SCNdLEAST16 = "hd"; /// enum _cstr SCNdLEAST32 = "ld"; /// enum _cstr SCNdLEAST64 = "lld"; /// enum _cstr SCNdFAST8 = "hhd"; /// enum _cstr SCNdFAST16 = "d"; /// enum _cstr SCNdFAST32 = "ld"; /// enum _cstr SCNdFAST64 = "lld"; /// enum _cstr SCNi8 = "hhd"; /// enum _cstr SCNi16 = "hi"; /// enum _cstr SCNi32 = "li"; /// enum _cstr SCNi64 = "lli"; /// enum _cstr SCNiLEAST8 = "hhd"; /// enum _cstr SCNiLEAST16 = "hi"; /// enum _cstr SCNiLEAST32 = "li"; /// enum _cstr SCNiLEAST64 = "lli"; /// enum _cstr SCNiFAST8 = "hhd"; /// enum _cstr SCNiFAST16 = "i"; /// enum _cstr SCNiFAST32 = "li"; /// enum _cstr SCNiFAST64 = "lli"; /// enum _cstr SCNo8 = "hhd"; /// enum _cstr SCNo16 = "ho"; /// enum _cstr SCNo32 = "lo"; /// enum _cstr SCNo64 = "llo"; /// enum _cstr SCNoLEAST8 = "hhd"; /// enum _cstr SCNoLEAST16 = "ho"; /// enum _cstr SCNoLEAST32 = "lo"; /// enum _cstr SCNoLEAST64 = "llo"; /// enum _cstr SCNoFAST8 = "hhd"; /// enum _cstr SCNoFAST16 = "o"; /// enum _cstr SCNoFAST32 = "lo"; /// enum _cstr SCNoFAST64 = "llo"; /// enum _cstr SCNu8 = "hhd"; /// enum _cstr SCNu16 = "hu"; /// enum _cstr SCNu32 = "lu"; /// enum _cstr SCNu64 = "llu"; /// enum _cstr SCNuLEAST8 = "hhd"; /// enum _cstr SCNuLEAST16 = "hu"; /// enum _cstr SCNuLEAST32 = "lu"; /// enum _cstr SCNuLEAST64 = "llu"; /// enum _cstr SCNuFAST8 = "hhd"; /// enum _cstr SCNuFAST16 = "u"; /// enum _cstr SCNuFAST32 = "lu"; /// enum _cstr SCNuFAST64 = "llu"; /// enum _cstr SCNx8 = "hhd"; /// enum _cstr SCNx16 = "hx"; /// enum _cstr SCNx32 = "lx"; /// enum _cstr SCNx64 = "llx"; /// enum _cstr SCNxLEAST8 = "hhd"; /// enum _cstr SCNxLEAST16 = "hx"; /// enum _cstr SCNxLEAST32 = "lx"; /// enum _cstr SCNxLEAST64 = "llx"; /// enum _cstr SCNxFAST8 = "hhd"; /// enum _cstr SCNxFAST16 = "x"; /// enum _cstr SCNxFAST32 = "lx"; /// enum _cstr SCNxFAST64 = "llx"; version( D_LP64 ) { /// enum _cstr PRIdMAX = PRId64; /// enum _cstr PRIiMAX = PRIi64; /// enum _cstr PRIoMAX = PRIo64; /// enum _cstr PRIuMAX = PRIu64; /// enum _cstr PRIxMAX = PRIx64; /// enum _cstr PRIXMAX = PRIX64; /// enum _cstr SCNdMAX = SCNd64; /// enum _cstr SCNiMAX = SCNi64; /// enum _cstr SCNoMAX = SCNo64; /// enum _cstr SCNuMAX = SCNu64; /// enum _cstr SCNxMAX = SCNx64; /// enum _cstr PRIdPTR = PRId64; /// enum _cstr PRIiPTR = PRIi64; /// enum _cstr PRIoPTR = PRIo64; /// enum _cstr PRIuPTR = PRIu64; /// enum _cstr PRIxPTR = PRIx64; /// enum _cstr PRIXPTR = PRIX64; /// enum _cstr SCNdPTR = SCNd64; /// enum _cstr SCNiPTR = SCNi64; /// enum _cstr SCNoPTR = SCNo64; /// enum _cstr SCNuPTR = SCNu64; /// enum _cstr SCNxPTR = SCNx64; } else { /// enum _cstr PRIdMAX = PRId32; /// enum _cstr PRIiMAX = PRIi32; /// enum _cstr PRIoMAX = PRIo32; /// enum _cstr PRIuMAX = PRIu32; /// enum _cstr PRIxMAX = PRIx32; /// enum _cstr PRIXMAX = PRIX32; /// enum _cstr SCNdMAX = SCNd32; /// enum _cstr SCNiMAX = SCNi32; /// enum _cstr SCNoMAX = SCNo32; /// enum _cstr SCNuMAX = SCNu32; /// enum _cstr SCNxMAX = SCNx32; /// enum _cstr PRIdPTR = PRId32; /// enum _cstr PRIiPTR = PRIi32; /// enum _cstr PRIoPTR = PRIo32; /// enum _cstr PRIuPTR = PRIu32; /// enum _cstr PRIxPTR = PRIx32; /// enum _cstr PRIXPTR = PRIX32; /// enum _cstr SCNdPTR = SCNd32; /// enum _cstr SCNiPTR = SCNi32; /// enum _cstr SCNoPTR = SCNo32; /// enum _cstr SCNuPTR = SCNu32; /// enum _cstr SCNxPTR = SCNx32; } /// intmax_t imaxabs(intmax_t j); /// imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom); /// intmax_t strtoimax(in char* nptr, char** endptr, int base); /// uintmax_t strtoumax(in char* nptr, char** endptr, int base); /// intmax_t wcstoimax(in wchar_t* nptr, wchar_t** endptr, int base); /// uintmax_t wcstoumax(in wchar_t* nptr, wchar_t** endptr, int base); ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/stdlib.d0000664000175000017500000001123112776214756021563 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_stdlib.h.html, _stdlib.h) * * Copyright: Copyright Sean Kelly 2005 - 2014. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Standards: ISO/IEC 9899:1999 (E) * Source: $(DRUNTIMESRC src/core/stdc/_stdlib.d) */ module core.stdc.stdlib; private import core.stdc.config; public import core.stdc.stddef; // for wchar_t extern (C): @system: /* Placed outside @nogc in order to not constrain what the callback does. */ /// alias int function(in void*, in void*) _compare_fp_t; /// void* bsearch(in void* key, in void* base, size_t nmemb, size_t size, _compare_fp_t compar); /// void qsort(void* base, size_t nmemb, size_t size, _compare_fp_t compar); nothrow: @nogc: /// struct div_t { int quot, rem; } /// struct ldiv_t { int quot, rem; } /// struct lldiv_t { long quot, rem; } /// enum EXIT_SUCCESS = 0; /// enum EXIT_FAILURE = 1; /// enum MB_CUR_MAX = 1; /// version(Windows) enum RAND_MAX = 0x7fff; else version(CRuntime_Glibc) enum RAND_MAX = 0x7fffffff; else version(OSX) enum RAND_MAX = 0x7fffffff; else version(FreeBSD) enum RAND_MAX = 0x7fffffff; else version(OpenBSD) enum RAND_MAX = 0x7fffffff; else version(Solaris) enum RAND_MAX = 0x7fff; else version(CRuntime_Bionic) enum RAND_MAX = 0x7fffffff; else static assert( false, "Unsupported platform" ); /// double atof(in char* nptr); /// int atoi(in char* nptr); /// c_long atol(in char* nptr); /// long atoll(in char* nptr); /// double strtod(in char* nptr, char** endptr); /// float strtof(in char* nptr, char** endptr); /// c_long strtol(in char* nptr, char** endptr, int base); /// long strtoll(in char* nptr, char** endptr, int base); /// c_ulong strtoul(in char* nptr, char** endptr, int base); /// ulong strtoull(in char* nptr, char** endptr, int base); version (CRuntime_Microsoft) { // strtold exists starting from VS2013, so we make this a template to avoid link errors /// real strtold()(in char* nptr, char** endptr) { // Fake it 'till we make it return strtod(nptr, endptr); } } else version (MinGW) { /// real __mingw_strtold(in char* nptr, char** endptr); /// alias __mingw_strtold strtold; } else version (CRuntime_Bionic) { /// real strtold(in char* nptr, char** endptr) { // Fake it again till we make it return strtod(nptr, endptr); } } else { /// real strtold(in char* nptr, char** endptr); } // No unsafe pointer manipulation. @trusted { version(CRuntime_Bionic) { import core.sys.posix.stdlib: lrand48, srand48; /// alias core.sys.posix.stdlib.lrand48 rand; /// alias core.sys.posix.stdlib.srand48 srand; } else { /// int rand(); /// void srand(uint seed); } } // We don't mark these @trusted. Given that they return a void*, one has // to do a pointer cast to do anything sensible with the result. Thus, // functions using these already have to be @trusted, allowing them to // call @system stuff anyway. /// void* malloc(size_t size); /// void* calloc(size_t nmemb, size_t size); /// void* realloc(void* ptr, size_t size); /// void free(void* ptr); /// void abort() @safe; /// void exit(int status); /// int atexit(void function() func); /// void _Exit(int status); /// char* getenv(in char* name); /// int system(in char* string); // These only operate on integer values. @trusted { /// pure int abs(int j); /// pure c_long labs(c_long j); /// pure long llabs(long j); /// div_t div(int numer, int denom); /// ldiv_t ldiv(c_long numer, c_long denom); /// lldiv_t lldiv(long numer, long denom); } /// int mblen(in char* s, size_t n); /// int mbtowc(wchar_t* pwc, in char* s, size_t n); /// int wctomb(char*s, wchar_t wc); /// size_t mbstowcs(wchar_t* pwcs, in char* s, size_t n); /// size_t wcstombs(char* s, in wchar_t* pwcs, size_t n); /// version( DigitalMars ) { // See malloc comment about @trusted. void* alloca(size_t size); // non-standard } else version( GNU ) { void* alloca(size_t size); // compiler intrinsic } version( CRuntime_Microsoft ) { /// ulong _strtoui64(in char *,char **,int); /// ulong _wcstoui64(in wchar *,wchar **,int); /// long _strtoi64(in char *,char **,int); /// long _wcstoi64(in wchar *,wchar **,int); } version( LDC ) { pragma(LDC_alloca) void* alloca(size_t size); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/time.d0000664000175000017500000001025612776214756021246 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_time.h.html, _time.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, * Alex Rønne Petersen * Source: $(DRUNTIMESRC core/stdc/_time.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.time; private import core.stdc.config; extern (C): @trusted: // There are only a few functions here that use unsafe C strings. nothrow: @nogc: version( Windows ) { /// struct tm { int tm_sec; /// seconds after the minute - [0, 60] int tm_min; /// minutes after the hour - [0, 59] int tm_hour; /// hours since midnight - [0, 23] int tm_mday; /// day of the month - [1, 31] int tm_mon; /// months since January - [0, 11] int tm_year; /// years since 1900 int tm_wday; /// days since Sunday - [0, 6] int tm_yday; /// days since January 1 - [0, 365] int tm_isdst; /// Daylight Saving Time flag } } else version( Posix ) { /// struct tm { int tm_sec; /// seconds after the minute [0-60] int tm_min; /// minutes after the hour [0-59] int tm_hour; /// hours since midnight [0-23] int tm_mday; /// day of the month [1-31] int tm_mon; /// months since January [0-11] int tm_year; /// years since 1900 int tm_wday; /// days since Sunday [0-6] int tm_yday; /// days since January 1 [0-365] int tm_isdst; /// Daylight Savings Time flag c_long tm_gmtoff; /// offset from CUT in seconds char* tm_zone; /// timezone abbreviation } } version ( Posix ) { public import core.sys.posix.sys.types : time_t, clock_t; } else version ( Windows ) { /// alias c_long time_t; /// alias c_long clock_t; } /// version( Windows ) { enum clock_t CLOCKS_PER_SEC = 1000; } else version( OSX ) { enum clock_t CLOCKS_PER_SEC = 100; } else version( FreeBSD ) { enum clock_t CLOCKS_PER_SEC = 128; } else version( OpenBSD ) { enum clock_t CLOCKS_PER_SEC = 100; } else version (CRuntime_Glibc) { enum clock_t CLOCKS_PER_SEC = 1_000_000; } else version (CRuntime_Bionic) { enum clock_t CLOCKS_PER_SEC = 1_000_000; } /// clock_t clock(); /// double difftime(time_t time1, time_t time0); /// time_t mktime(tm* timeptr); /// time_t time(time_t* timer); /// char* asctime(in tm* timeptr); /// char* ctime(in time_t* timer); /// tm* gmtime(in time_t* timer); /// tm* localtime(in time_t* timer); /// @system size_t strftime(char* s, size_t maxsize, in char* format, in tm* timeptr); version( Windows ) { /// void tzset(); // non-standard /// void _tzset(); // non-standard /// @system char* _strdate(char* s); // non-standard /// @system char* _strtime(char* s); // non-standard /// extern __gshared const(char)*[2] tzname; // non-standard } else version( OSX ) { /// void tzset(); // non-standard /// extern __gshared const(char)*[2] tzname; // non-standard } else version( CRuntime_Glibc ) { /// void tzset(); // non-standard /// extern __gshared const(char)*[2] tzname; // non-standard } else version( FreeBSD ) { /// void tzset(); // non-standard /// extern __gshared const(char)*[2] tzname; // non-standard } else version( OpenBSD ) { /// void tzset(); // non-standard /// extern __gshared const(char)*[2] tzname; // non-standard } else version (Solaris) { /// void tzset(); /// extern __gshared const(char)*[2] tzname; } else version( CRuntime_Bionic ) { /// void tzset(); /// extern __gshared const(char)*[2] tzname; } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/locale.d0000664000175000017500000000777012776214756021556 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_locale.h.html, _locale.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_locale.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.locale; extern (C): @trusted: // Only setlocale operates on C strings. nothrow: @nogc: /// struct lconv { char* decimal_point; char* thousands_sep; char* grouping; char* int_curr_symbol; char* currency_symbol; char* mon_decimal_point; char* mon_thousands_sep; char* mon_grouping; char* positive_sign; char* negative_sign; byte int_frac_digits; byte frac_digits; byte p_cs_precedes; byte p_sep_by_space; byte n_cs_precedes; byte n_sep_by_space; byte p_sign_posn; byte n_sign_posn; byte int_p_cs_precedes; byte int_p_sep_by_space; byte int_n_cs_precedes; byte int_n_sep_by_space; byte int_p_sign_posn; byte int_n_sign_posn; } version(CRuntime_Glibc) { /// enum LC_CTYPE = 0; /// enum LC_NUMERIC = 1; /// enum LC_TIME = 2; /// enum LC_COLLATE = 3; /// enum LC_MONETARY = 4; /// enum LC_MESSAGES = 5; /// enum LC_ALL = 6; /// enum LC_PAPER = 7; // non-standard /// enum LC_NAME = 8; // non-standard /// enum LC_ADDRESS = 9; // non-standard /// enum LC_TELEPHONE = 10; // non-standard /// enum LC_MEASUREMENT = 11; // non-standard /// enum LC_IDENTIFICATION = 12; // non-standard } else version(Windows) { /// enum LC_ALL = 0; /// enum LC_COLLATE = 1; /// enum LC_CTYPE = 2; /// enum LC_MONETARY = 3; /// enum LC_NUMERIC = 4; /// enum LC_TIME = 5; } else version(OSX) { /// enum LC_ALL = 0; /// enum LC_COLLATE = 1; /// enum LC_CTYPE = 2; /// enum LC_MONETARY = 3; /// enum LC_NUMERIC = 4; /// enum LC_TIME = 5; /// enum LC_MESSAGES = 6; } else version(FreeBSD) { /// enum LC_ALL = 0; /// enum LC_COLLATE = 1; /// enum LC_CTYPE = 2; /// enum LC_MONETARY = 3; /// enum LC_NUMERIC = 4; /// enum LC_TIME = 5; /// enum LC_MESSAGES = 6; } else version(OpenBSD) { /// enum LC_ALL = 0; /// enum LC_COLLATE = 1; /// enum LC_CTYPE = 2; /// enum LC_MONETARY = 3; /// enum LC_NUMERIC = 4; /// enum LC_TIME = 5; /// enum LC_MESSAGES = 6; } else version(CRuntime_Bionic) { enum { /// LC_CTYPE = 0, /// LC_NUMERIC = 1, /// LC_TIME = 2, /// LC_COLLATE = 3, /// LC_MONETARY = 4, /// LC_MESSAGES = 5, /// LC_ALL = 6, /// LC_PAPER = 7, /// LC_NAME = 8, /// LC_ADDRESS = 9, /// LC_TELEPHONE = 10, /// LC_MEASUREMENT = 11, /// LC_IDENTIFICATION = 12, } } else version(Solaris) { /// enum LC_CTYPE = 0; /// enum LC_NUMERIC = 1; /// enum LC_TIME = 2; /// enum LC_COLLATE = 3; /// enum LC_MONETARY = 4; /// enum LC_MESSAGES = 5; /// enum LC_ALL = 6; } else { static assert(false, "Unsupported platform"); } /// @system char* setlocale(int category, in char* locale); /// lconv* localeconv(); ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/stdarg.d0000664000175000017500000006340412776214756021577 0ustar kaikai/** * D header file for C99. * * Copyright: Copyright Digital Mars 2000 - 2009. * License: Distributed under the * Boost Software License 1.0. * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) * Authors: Walter Bright, Hauke Duden * Standards: ISO/IEC 9899:1999 (E) * Source: $(DRUNTIMESRC core/stdc/_stdarg.d) */ module core.stdc.stdarg; @system: //@nogc: // Not yet, need to make TypeInfo's member functions @nogc first nothrow: version ( PPC ) version = AnyPPC; version ( PPC64 ) version = AnyPPC; version( ARM ) { // iOS uses older APCS variant instead of AAPCS version( iOS ) {} else version = AAPCS; } version( AArch64 ) { // iOS, tvOS are AAPCS64, but don't follow it for va_list version( iOS ) {} else version( TVOS ) {} else version = AAPCS64; } version( X86_64 ) { // Determine if type is a vector type template isVectorType(T) { enum isVectorType = false; } template isVectorType(T : __vector(T[N]), size_t N) { enum isVectorType = true; } alias __va_list = __va_list_tag; void va_arg_x86_64(T)(__va_list *ap, ref T parmn) { static if (is(T U == __argTypes)) { static if (U.length == 0 || T.sizeof > 16 || (U[0].sizeof > 8 && !isVectorType!(U[0]))) { // Always passed in memory // The arg may have more strict alignment than the stack auto p = (cast(size_t)ap.stack_args + T.alignof - 1) & ~(T.alignof - 1); ap.stack_args = cast(void*)(p + ((T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); parmn = *cast(T*)p; } else static if (U.length == 1) { // Arg is passed in one register alias U[0] T1; static if (is(T1 == double) || is(T1 == float) || isVectorType!(T1)) { // Passed in XMM register if (ap.offset_fpregs < (6 * 8 + 16 * 8)) { parmn = *cast(T*)(ap.reg_args + ap.offset_fpregs); ap.offset_fpregs += 16; } else { parmn = *cast(T*)ap.stack_args; ap.stack_args += (T1.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); } } else { // Passed in regular register if (ap.offset_regs < 6 * 8 && T.sizeof <= 8) { parmn = *cast(T*)(ap.reg_args + ap.offset_regs); ap.offset_regs += 8; } else { auto p = (cast(size_t)ap.stack_args + T.alignof - 1) & ~(T.alignof - 1); ap.stack_args = cast(void*)(p + ((T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); parmn = *cast(T*)p; } } } else static if (U.length == 2) { // Arg is passed in two registers alias U[0] T1; alias U[1] T2; auto p = cast(void*)&parmn + 8; // Both must be in registers, or both on stack, hence 4 cases static if ((is(T1 == double) || is(T1 == float)) && (is(T2 == double) || is(T2 == float))) { if (ap.offset_fpregs < (6 * 8 + 16 * 8) - 16) { *cast(T1*)&parmn = *cast(T1*)(ap.reg_args + ap.offset_fpregs); *cast(T2*)p = *cast(T2*)(ap.reg_args + ap.offset_fpregs + 16); ap.offset_fpregs += 32; } else { *cast(T1*)&parmn = *cast(T1*)ap.stack_args; ap.stack_args += (T1.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); *cast(T2*)p = *cast(T2*)ap.stack_args; ap.stack_args += (T2.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); } } else static if (is(T1 == double) || is(T1 == float)) { void* a = void; if (ap.offset_fpregs < (6 * 8 + 16 * 8) && ap.offset_regs < 6 * 8 && T2.sizeof <= 8) { *cast(T1*)&parmn = *cast(T1*)(ap.reg_args + ap.offset_fpregs); ap.offset_fpregs += 16; a = ap.reg_args + ap.offset_regs; ap.offset_regs += 8; } else { *cast(T1*)&parmn = *cast(T1*)ap.stack_args; ap.stack_args += (T1.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); a = ap.stack_args; ap.stack_args += 8; } // Be careful not to go past the size of the actual argument const sz2 = T.sizeof - 8; p[0..sz2] = a[0..sz2]; } else static if (is(T2 == double) || is(T2 == float)) { if (ap.offset_regs < 6 * 8 && T1.sizeof <= 8 && ap.offset_fpregs < (6 * 8 + 16 * 8)) { *cast(T1*)&parmn = *cast(T1*)(ap.reg_args + ap.offset_regs); ap.offset_regs += 8; *cast(T2*)p = *cast(T2*)(ap.reg_args + ap.offset_fpregs); ap.offset_fpregs += 16; } else { *cast(T1*)&parmn = *cast(T1*)ap.stack_args; ap.stack_args += 8; *cast(T2*)p = *cast(T2*)ap.stack_args; ap.stack_args += (T2.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); } } else // both in regular registers { void* a = void; if (ap.offset_regs < 5 * 8 && T1.sizeof <= 8 && T2.sizeof <= 8) { *cast(T1*)&parmn = *cast(T1*)(ap.reg_args + ap.offset_regs); ap.offset_regs += 8; a = ap.reg_args + ap.offset_regs; ap.offset_regs += 8; } else { *cast(T1*)&parmn = *cast(T1*)ap.stack_args; ap.stack_args += 8; a = ap.stack_args; ap.stack_args += 8; } // Be careful not to go past the size of the actual argument const sz2 = T.sizeof - 8; p[0..sz2] = a[0..sz2]; } } else { static assert(false); } } else { static assert(false, "not a valid argument type for va_arg"); } } void va_arg_x86_64()(__va_list *ap, TypeInfo ti, void* parmn) { TypeInfo arg1, arg2; if (!ti.argTypes(arg1, arg2)) { bool inXMMregister(TypeInfo arg) pure nothrow @safe { return (arg.flags & 2) != 0; } TypeInfo_Vector v1 = arg1 ? cast(TypeInfo_Vector)arg1 : null; if (arg1 && (arg1.tsize <= 8 || v1)) { // Arg is passed in one register auto tsize = arg1.tsize; void* p; bool stack = false; auto offset_fpregs_save = ap.offset_fpregs; auto offset_regs_save = ap.offset_regs; L1: if (inXMMregister(arg1) || v1) { // Passed in XMM register if (ap.offset_fpregs < (6 * 8 + 16 * 8) && !stack) { p = ap.reg_args + ap.offset_fpregs; ap.offset_fpregs += 16; } else { p = ap.stack_args; ap.stack_args += (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); stack = true; } } else { // Passed in regular register if (ap.offset_regs < 6 * 8 && !stack) { p = ap.reg_args + ap.offset_regs; ap.offset_regs += 8; } else { p = ap.stack_args; ap.stack_args += 8; stack = true; } } parmn[0..tsize] = p[0..tsize]; if (arg2) { if (inXMMregister(arg2)) { // Passed in XMM register if (ap.offset_fpregs < (6 * 8 + 16 * 8) && !stack) { p = ap.reg_args + ap.offset_fpregs; ap.offset_fpregs += 16; } else { if (!stack) { // arg1 is really on the stack, so rewind and redo ap.offset_fpregs = offset_fpregs_save; ap.offset_regs = offset_regs_save; stack = true; goto L1; } p = ap.stack_args; ap.stack_args += (arg2.tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); } } else { // Passed in regular register if (ap.offset_regs < 6 * 8 && !stack) { p = ap.reg_args + ap.offset_regs; ap.offset_regs += 8; } else { if (!stack) { // arg1 is really on the stack, so rewind and redo ap.offset_fpregs = offset_fpregs_save; ap.offset_regs = offset_regs_save; stack = true; goto L1; } p = ap.stack_args; ap.stack_args += 8; } } auto sz = ti.tsize - 8; (parmn + 8)[0..sz] = p[0..sz]; } } else { // Always passed in memory // The arg may have more strict alignment than the stack auto talign = ti.talign; auto tsize = ti.tsize; auto p = cast(void*)((cast(size_t)ap.stack_args + talign - 1) & ~(talign - 1)); ap.stack_args = cast(void*)(cast(size_t)p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); parmn[0..tsize] = p[0..tsize]; } } else { assert(false, "not a valid argument type for va_arg"); } } } version( LDC ) { version( AArch64 ) { void va_arg_aarch64(T)(ref __va_list ap, ref T parmn) { assert(false, "Not yet implemented"); } void va_arg_aarch64()(ref __va_list ap, TypeInfo ti, void* parmn) { assert(false, "Not yet implemented"); } } version( X86_64 ) { version( Win64 ) {} else version = SystemV_AMD64; } // Type va_list: // On most platforms, really struct va_list { void* ptr; }, // but for compatibility with x86-style code that uses char*, // we just define it as the raw pointer. // For System V AMD64 ABI, really __va_list[1], i.e., a 24-bytes // struct passed by reference. We define va_list as a raw pointer // (to the actual struct) for the byref semantics and allocate // the struct in LDC's va_start and va_copy intrinsics. version (SystemV_AMD64) { alias va_list = __va_list_tag*; } else version (AAPCS64) { alias va_list = __va_list; } else version (ARM) { // __va_list will be defined for ARM AAPCS targets that need // it by object.d. Use a .ptr property so ARM code below can // be common static if (is(__va_list)) { alias va_list = __va_list; private ref auto ptr(ref va_list ap) @property { return ap.__ap; } private auto ptr(ref va_list ap, void* ptr) @property { return ap.__ap = ptr; } } else { alias va_list = char*; private ref auto ptr(ref va_list ap) @property { return ap; } private auto ptr(ref va_list ap, void* ptr) @property { return ap = cast(va_list)ptr; } } } else { alias va_list = char*; } pragma(LDC_va_start) void va_start(T)(out va_list ap, ref T); private pragma(LDC_va_arg) T va_arg_intrinsic(T)(ref va_list ap); T va_arg(T)(ref va_list ap) { version( SystemV_AMD64 ) { T arg; va_arg(ap, arg); return arg; } else version( AAPCS64 ) { T arg; va_arg(ap, arg); return arg; } else version( Win64 ) { // dynamic arrays are passed as 2 separate 64-bit values import std.traits: isDynamicArray; static if (isDynamicArray!T) { auto length = *cast(size_t*)ap; ap += size_t.sizeof; auto ptr = *cast(typeof(T.init.ptr)*)ap; ap += size_t.sizeof; return ptr[0..length]; } else { // passed as byval reference if > 64 bits or of a size that is not a power of 2 static if (T.sizeof > size_t.sizeof || (T.sizeof & (T.sizeof - 1)) != 0) T arg = **cast(T**)ap; else T arg = *cast(T*)ap; ap += size_t.sizeof; return arg; } } else version( X86 ) { T arg = *cast(T*)ap; ap += (T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); return arg; } else version( AArch64 ) { T arg = *cast(T*)ap; ap += (T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); return arg; } else version( ARM ) { // AAPCS sec 5.5 B.5: type with alignment >= 8 is 8-byte aligned // instead of normal 4-byte alignment (APCS doesn't do this). version( AAPCS ) { if (T.alignof >= 8) ap.ptr = cast(void*)((cast(size_t)ap.ptr + 7) & ~7); } T arg = *cast(T*)ap.ptr; ap.ptr += (T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); return arg; } else version( AnyPPC ) { /* * The rules are described in the 64bit PowerPC ELF ABI Supplement 1.9, * available here: * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#PARAM-PASS */ // This works for all types because only the rules for non-floating, // non-vector types are used. auto p = (T.sizeof < size_t.sizeof ? ap + (size_t.sizeof - T.sizeof) : ap); T arg = *cast(T*)p; ap += (T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); return arg; } else version( MIPS64 ) { T arg = *cast(T*)ap; ap += (T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); return arg; } else return va_arg_intrinsic!T(ap); } void va_arg(T)(ref va_list ap, ref T parmn) { version( SystemV_AMD64 ) { va_arg_x86_64(cast(__va_list*)ap, parmn); } else version( AAPCS64 ) { va_arg_aarch64(ap, parmn); } else version( Win64 ) { import std.traits: isDynamicArray; static if (isDynamicArray!T) { parmn = *cast(T*)ap; ap += T.sizeof; } else { static if (T.sizeof > size_t.sizeof || (T.sizeof & (T.sizeof - 1)) != 0) parmn = **cast(T**)ap; else parmn = *cast(T*)ap; ap += size_t.sizeof; } } else version( X86 ) { parmn = *cast(T*)ap; ap += (T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); } else version( AArch64 ) { parmn = *cast(T*)ap; ap += (T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); } else version( ARM ) { // AAPCS sec 5.5 B.5: type with alignment >= 8 is 8-byte aligned // instead of normal 4-byte alignment (APCS doesn't do this). version( AAPCS ) { if (T.alignof >= 8) ap.ptr = cast(void*)((cast(size_t)ap.ptr + 7) & ~7); } parmn = *cast(T*)ap.ptr; ap.ptr += (T.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1); } else parmn = va_arg!T(ap); } void va_arg()(ref va_list ap, TypeInfo ti, void* parmn) { version( SystemV_AMD64 ) { va_arg_x86_64(cast(__va_list*)ap, ti, parmn); } else version( AAPCS64 ) { va_arg_aarch64(ap, ti, parmn); } else { auto tsize = ti.tsize; version( X86 ) { // Wait until everyone updates to get TypeInfo.talign //auto talign = ti.talign; //auto p = cast(va_list) ((cast(size_t)ap + talign - 1) & ~(talign - 1)); auto p = ap; ap = p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1)); } else version( Win64 ) { char* p; auto ti_dynArray = cast(TypeInfo_Array) ti; if (ti_dynArray !is null) { p = ap; ap += tsize; } else { p = (tsize > size_t.sizeof || (tsize & (tsize - 1)) != 0) ? *cast(char**)ap : ap; ap += size_t.sizeof; } } else version( AArch64 ) { auto p = ap; ap = p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1)); } else version( ARM ) { // AAPCS sec 5.5 B.5: type with alignment >= 8 is 8-byte aligned // instead of normal 4-byte alignment (APCS doesn't do this). version( AAPCS ) { if (ti.talign >= 8) ap.ptr = cast(void*)((cast(size_t)ap.ptr + 7) & ~7); } auto p = ap.ptr; ap.ptr = p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1)); } else version( AnyPPC ) { /* * The rules are described in the 64bit PowerPC ELF ABI Supplement 1.9, * available here: * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#PARAM-PASS */ // This works for all types because only the rules for non-floating, // non-vector types are used. auto p = (tsize < size_t.sizeof ? ap + (size_t.sizeof - tsize) : ap); ap += (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); } else version( MIPS64 ) { // This works for all types because only the rules for non-floating, // non-vector types are used. auto p = (tsize < size_t.sizeof ? ap + (size_t.sizeof - tsize) : ap); ap += (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); } else { static assert(false, "Unsupported platform"); } parmn[0..tsize] = (cast(void*)p)[0..tsize]; } } pragma(LDC_va_end) void va_end(va_list ap); pragma(LDC_va_copy) void va_copy(out va_list dest, va_list src); } else version( X86 ) { /********************* * The argument pointer type. */ alias va_list = char*; /********** * Initialize ap. * For 32 bit code, parmn should be the last named parameter. * For 64 bit code, parmn should be __va_argsave. */ void va_start(T)(out va_list ap, ref T parmn) { ap = cast(va_list)( cast(void*) &parmn + ( ( T.sizeof + int.sizeof - 1 ) & ~( int.sizeof - 1 ) ) ); } /************ * Retrieve and return the next value that is type T. * Should use the other va_arg instead, as this won't work for 64 bit code. */ T va_arg(T)(ref va_list ap) { T arg = *cast(T*) ap; ap = cast(va_list)( cast(void*) ap + ( ( T.sizeof + int.sizeof - 1 ) & ~( int.sizeof - 1 ) ) ); return arg; } /************ * Retrieve and return the next value that is type T. * This is the preferred version. */ void va_arg(T)(ref va_list ap, ref T parmn) { parmn = *cast(T*)ap; ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1))); } /************* * Retrieve and store through parmn the next value that is of TypeInfo ti. * Used when the static type is not known. */ void va_arg()(ref va_list ap, TypeInfo ti, void* parmn) { // Wait until everyone updates to get TypeInfo.talign //auto talign = ti.talign; //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1); auto p = ap; auto tsize = ti.tsize; ap = cast(void*)(cast(size_t)p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); parmn[0..tsize] = p[0..tsize]; } /*********************** * End use of ap. */ void va_end(va_list ap) { } void va_copy(out va_list dest, va_list src) { dest = src; } } else version (Windows) // Win64 { /* Win64 is characterized by all arguments fitting into a register size. * Smaller ones are padded out to register size, and larger ones are passed by * reference. */ /********************* * The argument pointer type. */ alias void* va_list; /********** * Initialize ap. * parmn should be the last named parameter. */ void va_start(T)(out va_list ap, ref T parmn) { ap = cast(va_list)(cast(void*)&parmn + ((size_t.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); } /************ * Retrieve and return the next value that is type T. */ T va_arg(T)(ref va_list ap) { static if (T.sizeof > size_t.sizeof) T arg = **cast(T**)ap; else T arg = *cast(T*)ap; ap = cast(va_list)(cast(void*)ap + ((size_t.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); return arg; } /************ * Retrieve and return the next value that is type T. * This is the preferred version. */ void va_arg(T)(ref va_list ap, ref T parmn) { static if (T.sizeof > size_t.sizeof) parmn = **cast(T**)ap; else parmn = *cast(T*)ap; ap = cast(va_list)(cast(void*)ap + ((size_t.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); } /************* * Retrieve and store through parmn the next value that is of TypeInfo ti. * Used when the static type is not known. */ void va_arg()(ref va_list ap, TypeInfo ti, void* parmn) { // Wait until everyone updates to get TypeInfo.talign //auto talign = ti.talign; //auto p = cast(void*)(cast(size_t)ap + talign - 1) & ~(talign - 1); auto p = ap; auto tsize = ti.tsize; ap = cast(void*)(cast(size_t)p + ((size_t.sizeof + size_t.sizeof - 1) & ~(size_t.sizeof - 1))); void* q = (tsize > size_t.sizeof) ? *cast(void**)p : p; parmn[0..tsize] = q[0..tsize]; } /*********************** * End use of ap. */ void va_end(va_list ap) { } void va_copy(out va_list dest, va_list src) { dest = src; } } else version ( X86_64 ) { align(16) struct __va_argsave_t { size_t[6] regs; // RDI,RSI,RDX,RCX,R8,R9 real[8] fpregs; // XMM0..XMM7 __va_list va; } /* * Making it an array of 1 causes va_list to be passed as a pointer in * function argument lists */ alias void* va_list; void va_start(T)(out va_list ap, ref T parmn) { ap = &parmn.va; } T va_arg(T)(va_list ap) { T a; va_arg(ap, a); return a; } void va_arg(T)(va_list apx, ref T parmn) { __va_list* ap = cast(__va_list*)apx; va_arg_x86_64(ap, parmn); } void va_arg()(va_list apx, TypeInfo ti, void* parmn) { __va_list* ap = cast(__va_list*)apx; va_arg_x86_64(ap, ti, parmn); } void va_end(va_list ap) { } void va_copy(out va_list dest, va_list src) { dest = src; } } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/ctype.d0000664000175000017500000000171212776214756021431 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_ctype.h.html, _ctype.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_ctype.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.ctype; extern (C): @trusted: // All of these operate on integers only. nothrow: @nogc: /// pure int isalnum(int c); /// pure int isalpha(int c); /// pure int isblank(int c); /// pure int iscntrl(int c); /// pure int isdigit(int c); /// pure int isgraph(int c); /// pure int islower(int c); /// pure int isprint(int c); /// pure int ispunct(int c); /// pure int isspace(int c); /// pure int isupper(int c); /// pure int isxdigit(int c); /// pure int tolower(int c); /// pure int toupper(int c); ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/fenv.d0000664000175000017500000002145212776214756021246 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_fenv.h.html, _fenv.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_fenv.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.fenv; extern (C): @system: nothrow: @nogc: version (PPC) version = PPC_Any; version (PPC64) version = PPC_Any; version( MinGW ) version = GNUFP; version( CRuntime_Glibc ) version = GNUFP; version( GNUFP ) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/x86/fpu/bits/fenv.h version (X86) { struct fenv_t { ushort __control_word; ushort __unused1; ushort __status_word; ushort __unused2; ushort __tags; ushort __unused3; uint __eip; ushort __cs_selector; ushort __opcode; uint __data_offset; ushort __data_selector; ushort __unused5; } alias fexcept_t = ushort; } // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/x86/fpu/bits/fenv.h else version (X86_64) { struct fenv_t { ushort __control_word; ushort __unused1; ushort __status_word; ushort __unused2; ushort __tags; ushort __unused3; uint __eip; ushort __cs_selector; ushort __opcode; uint __data_offset; ushort __data_selector; ushort __unused5; uint __mxcsr; } alias fexcept_t = ushort; } // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/mips/bits/fenv.h else version (MIPS32) { struct fenv_t { uint __fp_control_register; } alias fexcept_t = ushort; } // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/mips/bits/fenv.h else version (MIPS64) { struct fenv_t { uint __fp_control_register; } alias fexcept_t = ushort; } // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/aarch64/bits/fenv.h else version (AArch64) { struct fenv_t { uint __fpcr; uint __fpsr; } alias fexcept_t = uint; } // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/bits/fenv.h else version (ARM) { struct fenv_t { uint __cw; } alias fexcept_t = uint; } // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/powerpc/bits/fenv.h else version (PPC_Any) { alias fenv_t = double; alias fexcept_t = uint; } // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/s390/fpu/bits/fenv.h else version (SystemZ) { struct fenv_t { fexcept_t __fpc; void* __unused; } alias fexcept_t = uint; } else { static assert(0, "Unimplemented architecture"); } } else version( CRuntime_DigitalMars ) { struct fenv_t { ushort status; ushort control; ushort round; ushort[2] reserved; } alias fexcept_t = int; } else version( CRuntime_Microsoft ) { struct fenv_t { uint ctl; uint stat; } alias fexcept_t = uint; } else version ( OSX ) { version ( BigEndian ) { alias uint fenv_t; alias uint fexcept_t; } version ( LittleEndian ) { struct fenv_t { ushort __control; ushort __status; uint __mxcsr; byte[8] __reserved; } alias ushort fexcept_t; } } else version ( FreeBSD ) { struct fenv_t { ushort __control; ushort __mxcsr_hi; ushort __status; ushort __mxcsr_lo; uint __tag; byte[16] __other; } alias ushort fexcept_t; } else version ( OpenBSD ) { struct fenv_t { struct __x87 { uint __control; uint __status; uint __tag; uint[4] __others; } } uint __mxcsr; alias fexcept_t = uint; } else version( CRuntime_Bionic ) { version(X86) { struct fenv_t { ushort __control; ushort __mxcsr_hi; ushort __status; ushort __mxcsr_lo; uint __tag; byte[16] __other; } alias ushort fexcept_t; } else version(ARM) { alias uint fenv_t; alias uint fexcept_t; } else { static assert(false, "Architecture not supported."); } } else version( Solaris ) { import core.stdc.config : c_ulong; enum FEX_NUM_EXC = 12; struct fex_handler_t { int __mode; void function() __handler; } struct fenv_t { fex_handler_t[FEX_NUM_EXC] __handler; c_ulong __fsr; } alias int fexcept_t; } else { static assert( false, "Unsupported platform" ); } version( CRuntime_Microsoft ) { enum { FE_INEXACT = 1, /// FE_UNDERFLOW = 2, /// FE_OVERFLOW = 4, /// FE_DIVBYZERO = 8, /// FE_INVALID = 0x10, /// FE_ALL_EXCEPT = 0x1F, /// FE_TONEAREST = 0, /// FE_UPWARD = 0x100, /// FE_DOWNWARD = 0x200, /// FE_TOWARDZERO = 0x300, /// } } else { enum { FE_INVALID = 1, /// FE_DENORMAL = 2, /// non-standard FE_DIVBYZERO = 4, /// FE_OVERFLOW = 8, /// FE_UNDERFLOW = 0x10, /// FE_INEXACT = 0x20, /// FE_ALL_EXCEPT = 0x3F, /// FE_TONEAREST = 0, /// FE_UPWARD = 0x800, /// FE_DOWNWARD = 0x400, /// FE_TOWARDZERO = 0xC00, /// } } version( GNUFP ) { /// enum FE_DFL_ENV = cast(fenv_t*)(-1); } else version( CRuntime_DigitalMars ) { private extern __gshared fenv_t _FE_DFL_ENV; /// enum fenv_t* FE_DFL_ENV = &_FE_DFL_ENV; } else version( CRuntime_Microsoft ) { private extern __gshared fenv_t _Fenv0; /// enum FE_DFL_ENV = &_Fenv0; } else version( OSX ) { private extern __gshared fenv_t _FE_DFL_ENV; /// enum FE_DFL_ENV = &_FE_DFL_ENV; } else version( FreeBSD ) { private extern const fenv_t __fe_dfl_env; /// enum FE_DFL_ENV = &__fe_dfl_env; } else version( OpenBSD ) { private extern const fenv_t __fe_dfl_env; /// enum FE_DFL_ENV = &__fe_dfl_env; } else version( CRuntime_Bionic ) { private extern const fenv_t __fe_dfl_env; /// enum FE_DFL_ENV = &__fe_dfl_env; } else version( Solaris ) { private extern const fenv_t __fenv_def_env; /// enum FE_DFL_ENV = &__fenv_def_env; } else version( Solaris ) { private extern const fenv_t __fenv_def_env; const fenv_t* FE_DFL_ENV = &__fenv_def_env; } else { static assert( false, "Unsupported platform" ); } /// int feclearexcept(int excepts); /// int fetestexcept(int excepts); /// int feholdexcept(fenv_t* envp); /// int fegetexceptflag(fexcept_t* flagp, int excepts); /// int fesetexceptflag(in fexcept_t* flagp, int excepts); /// int fegetround(); /// int fesetround(int round); /// int fegetenv(fenv_t* envp); /// int fesetenv(in fenv_t* envp); // MS define feraiseexcept() and feupdateenv() inline. version( CRuntime_Microsoft ) // supported since MSVCRT 12 (VS 2013) only { /// int feraiseexcept()(int excepts) { struct Entry { int exceptVal; double num; double denom; } static __gshared immutable(Entry[5]) table = [ // Raise exception by evaluating num / denom: { FE_INVALID, 0.0, 0.0 }, { FE_DIVBYZERO, 1.0, 0.0 }, { FE_OVERFLOW, 1e+300, 1e-300 }, { FE_UNDERFLOW, 1e-300, 1e+300 }, { FE_INEXACT, 2.0, 3.0 } ]; if ((excepts &= FE_ALL_EXCEPT) == 0) return 0; // Raise the exceptions not masked: double ans = void; foreach (i; 0 .. table.length) { if ((excepts & table[i].exceptVal) != 0) ans = table[i].num / table[i].denom; } return 0; } /// int feupdateenv()(in fenv_t* envp) { int excepts = fetestexcept(FE_ALL_EXCEPT); return (fesetenv(envp) != 0 || feraiseexcept(excepts) != 0 ? 1 : 0); } } else { /// int feraiseexcept(int excepts); /// int feupdateenv(in fenv_t* envp); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/signal.d0000664000175000017500000000340412776214756021562 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_signal.h.html, _signal.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_signal.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.signal; extern (C): @system: nothrow: @nogc: // this should be volatile /// alias int sig_atomic_t; private alias void function(int) sigfn_t; version( Posix ) { /// enum SIG_ERR = cast(sigfn_t) -1; /// enum SIG_DFL = cast(sigfn_t) 0; /// enum SIG_IGN = cast(sigfn_t) 1; // standard C signals /// enum SIGABRT = 6; // Abnormal termination /// enum SIGFPE = 8; // Floating-point error /// enum SIGILL = 4; // Illegal hardware instruction /// enum SIGINT = 2; // Terminal interrupt character /// enum SIGSEGV = 11; // Invalid memory reference /// enum SIGTERM = 15; // Termination } else version( Windows ) { /// enum SIG_ERR = cast(sigfn_t) -1; /// enum SIG_DFL = cast(sigfn_t) 0; /// enum SIG_IGN = cast(sigfn_t) 1; // standard C signals /// enum SIGABRT = 22; // Abnormal termination /// enum SIGFPE = 8; // Floating-point error /// enum SIGILL = 4; // Illegal hardware instruction /// enum SIGINT = 2; // Terminal interrupt character /// enum SIGSEGV = 11; // Invalid memory reference /// enum SIGTERM = 15; // Termination } /// sigfn_t signal(int sig, sigfn_t func); /// int raise(int sig); ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/errno.c0000664000175000017500000000073612776214756021436 0ustar kaikai/** * This file contains wrapper functions for macro-defined C routines. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/errno.c) */ #include int getErrno() { return errno; } int setErrno( int val ) { errno = val; return val; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/complex.d0000664000175000017500000000510712776214756021756 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_complex.h.html, _complex.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_complex.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.complex; extern (C): @trusted: // All of these operate on floating point values only. nothrow: @nogc: /// alias creal complex; /// alias ireal imaginary; /// cdouble cacos(cdouble z); /// cfloat cacosf(cfloat z); /// creal cacosl(creal z); /// cdouble casin(cdouble z); /// cfloat casinf(cfloat z); /// creal casinl(creal z); /// cdouble catan(cdouble z); /// cfloat catanf(cfloat z); /// creal catanl(creal z); /// cdouble ccos(cdouble z); /// cfloat ccosf(cfloat z); /// creal ccosl(creal z); /// cdouble csin(cdouble z); /// cfloat csinf(cfloat z); /// creal csinl(creal z); /// cdouble ctan(cdouble z); /// cfloat ctanf(cfloat z); /// creal ctanl(creal z); /// cdouble cacosh(cdouble z); /// cfloat cacoshf(cfloat z); /// creal cacoshl(creal z); /// cdouble casinh(cdouble z); /// cfloat casinhf(cfloat z); /// creal casinhl(creal z); /// cdouble catanh(cdouble z); /// cfloat catanhf(cfloat z); /// creal catanhl(creal z); /// cdouble ccosh(cdouble z); /// cfloat ccoshf(cfloat z); /// creal ccoshl(creal z); /// cdouble csinh(cdouble z); /// cfloat csinhf(cfloat z); /// creal csinhl(creal z); /// cdouble ctanh(cdouble z); /// cfloat ctanhf(cfloat z); /// creal ctanhl(creal z); /// cdouble cexp(cdouble z); /// cfloat cexpf(cfloat z); /// creal cexpl(creal z); /// cdouble clog(cdouble z); /// cfloat clogf(cfloat z); /// creal clogl(creal z); /// double cabs(cdouble z); /// float cabsf(cfloat z); /// real cabsl(creal z); /// cdouble cpow(cdouble x, cdouble y); /// cfloat cpowf(cfloat x, cfloat y); /// creal cpowl(creal x, creal y); /// cdouble csqrt(cdouble z); /// cfloat csqrtf(cfloat z); /// creal csqrtl(creal z); /// double carg(cdouble z); /// float cargf(cfloat z); /// real cargl(creal z); /// double cimag(cdouble z); /// float cimagf(cfloat z); /// real cimagl(creal z); /// cdouble conj(cdouble z); /// cfloat conjf(cfloat z); /// creal conjl(creal z); /// cdouble cproj(cdouble z); /// cfloat cprojf(cfloat z); /// creal cprojl(creal z); // double creal(cdouble z); /// float crealf(cfloat z); /// real creall(creal z); ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/errno.d0000664000175000017500000021231212776214756021432 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_errno.h.html, _errno.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, Alex Rønne Petersen * Source: $(DRUNTIMESRC core/stdc/_errno.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.errno; @trusted: // Only manipulates errno. nothrow: @nogc: /// @property int errno() { return getErrno(); } /// @property int errno(int n) { return setErrno(n); } extern (C): private extern (C) int getErrno(); // for internal use private extern (C) int setErrno(int); // for internal use version( Windows ) { enum EPERM = 1; /// Operation not permitted enum ENOENT = 2; /// No such file or directory enum ESRCH = 3; /// No such process enum EINTR = 4; /// Interrupted system call enum EIO = 5; /// I/O error enum ENXIO = 6; /// No such device or address enum E2BIG = 7; /// Argument list too long enum ENOEXEC = 8; /// Exec format error enum EBADF = 9; /// Bad file number enum ECHILD = 10; /// No child processes enum EAGAIN = 11; /// Try again enum ENOMEM = 12; /// Out of memory enum EACCES = 13; /// Permission denied enum EFAULT = 14; /// Bad address enum EBUSY = 16; /// Device or resource busy enum EEXIST = 17; /// File exists enum EXDEV = 18; /// Cross-device link enum ENODEV = 19; /// No such device enum ENOTDIR = 20; /// Not a directory enum EISDIR = 21; /// Is a directory enum EINVAL = 22; /// Invalid argument enum ENFILE = 23; /// File table overflow enum EMFILE = 24; /// Too many open files enum ENOTTY = 25; /// Not a typewriter enum EFBIG = 27; /// File too large enum ENOSPC = 28; /// No space left on device enum ESPIPE = 29; /// Illegal seek enum EROFS = 30; /// Read-only file system enum EMLINK = 31; /// Too many links enum EPIPE = 32; /// Broken pipe enum EDOM = 33; /// Math argument out of domain of func enum ERANGE = 34; /// Math result not representable enum EDEADLK = 36; /// Resource deadlock would occur enum ENAMETOOLONG = 38; /// File name too long enum ENOLCK = 39; /// No record locks available enum ENOSYS = 40; /// Function not implemented enum ENOTEMPTY = 41; /// Directory not empty enum EILSEQ = 42; /// Illegal byte sequence enum EDEADLOCK = EDEADLK; /// Resource deadlock would occur } else version( linux ) { enum EPERM = 1; /// enum ENOENT = 2; /// enum ESRCH = 3; /// enum EINTR = 4; /// enum EIO = 5; /// enum ENXIO = 6; /// enum E2BIG = 7; /// enum ENOEXEC = 8; /// enum EBADF = 9; /// enum ECHILD = 10; /// enum EAGAIN = 11; /// enum ENOMEM = 12; /// enum EACCES = 13; /// enum EFAULT = 14; /// enum ENOTBLK = 15; /// enum EBUSY = 16; /// enum EEXIST = 17; /// enum EXDEV = 18; /// enum ENODEV = 19; /// enum ENOTDIR = 20; /// enum EISDIR = 21; /// enum EINVAL = 22; /// enum ENFILE = 23; /// enum EMFILE = 24; /// enum ENOTTY = 25; /// enum ETXTBSY = 26; /// enum EFBIG = 27; /// enum ENOSPC = 28; /// enum ESPIPE = 29; /// enum EROFS = 30; /// enum EMLINK = 31; /// enum EPIPE = 32; /// enum EDOM = 33; /// enum ERANGE = 34; /// version(X86) { enum EDEADLK = 35; /// enum ENAMETOOLONG = 36; /// enum ENOLCK = 37; /// enum ENOSYS = 38; /// enum ENOTEMPTY = 39; /// enum ELOOP = 40; /// enum EWOULDBLOCK = EAGAIN; /// enum ENOMSG = 42; /// enum EIDRM = 43; /// enum ECHRNG = 44; /// enum EL2NSYNC = 45; /// enum EL3HLT = 46; /// enum EL3RST = 47; /// enum ELNRNG = 48; /// enum EUNATCH = 49; /// enum ENOCSI = 50; /// enum EL2HLT = 51; /// enum EBADE = 52; /// enum EBADR = 53; /// enum EXFULL = 54; /// enum ENOANO = 55; /// enum EBADRQC = 56; /// enum EBADSLT = 57; /// enum EDEADLOCK = EDEADLK; /// enum EBFONT = 59; /// enum ENOSTR = 60; /// enum ENODATA = 61; /// enum ETIME = 62; /// enum ENOSR = 63; /// enum ENONET = 64; /// enum ENOPKG = 65; /// enum EREMOTE = 66; /// enum ENOLINK = 67; /// enum EADV = 68; /// enum ESRMNT = 69; /// enum ECOMM = 70; /// enum EPROTO = 71; /// enum EMULTIHOP = 72; /// enum EDOTDOT = 73; /// enum EBADMSG = 74; /// enum EOVERFLOW = 75; /// enum ENOTUNIQ = 76; /// enum EBADFD = 77; /// enum EREMCHG = 78; /// enum ELIBACC = 79; /// enum ELIBBAD = 80; /// enum ELIBSCN = 81; /// enum ELIBMAX = 82; /// enum ELIBEXEC = 83; /// enum EILSEQ = 84; /// enum ERESTART = 85; /// enum ESTRPIPE = 86; /// enum EUSERS = 87; /// enum ENOTSOCK = 88; /// enum EDESTADDRREQ = 89; /// enum EMSGSIZE = 90; /// enum EPROTOTYPE = 91; /// enum ENOPROTOOPT = 92; /// enum EPROTONOSUPPORT = 93; /// enum ESOCKTNOSUPPORT = 94; /// enum EOPNOTSUPP = 95; /// enum ENOTSUP = EOPNOTSUPP; /// enum EPFNOSUPPORT = 96; /// enum EAFNOSUPPORT = 97; /// enum EADDRINUSE = 98; /// enum EADDRNOTAVAIL = 99; /// enum ENETDOWN = 100; /// enum ENETUNREACH = 101; /// enum ENETRESET = 102; /// enum ECONNABORTED = 103; /// enum ECONNRESET = 104; /// enum ENOBUFS = 105; /// enum EISCONN = 106; /// enum ENOTCONN = 107; /// enum ESHUTDOWN = 108; /// enum ETOOMANYREFS = 109; /// enum ETIMEDOUT = 110; /// enum ECONNREFUSED = 111; /// enum EHOSTDOWN = 112; /// enum EHOSTUNREACH = 113; /// enum EALREADY = 114; /// enum EINPROGRESS = 115; /// enum ESTALE = 116; /// enum EUCLEAN = 117; /// enum ENOTNAM = 118; /// enum ENAVAIL = 119; /// enum EISNAM = 120; /// enum EREMOTEIO = 121; /// enum EDQUOT = 122; /// enum ENOMEDIUM = 123; /// enum EMEDIUMTYPE = 124; /// enum ECANCELED = 125; /// enum ENOKEY = 126; /// enum EKEYEXPIRED = 127; /// enum EKEYREVOKED = 128; /// enum EKEYREJECTED = 129; /// enum EOWNERDEAD = 130; /// enum ENOTRECOVERABLE = 131; /// } else version(X86_64) { enum EDEADLK = 35; /// enum ENAMETOOLONG = 36; /// enum ENOLCK = 37; /// enum ENOSYS = 38; /// enum ENOTEMPTY = 39; /// enum ELOOP = 40; /// enum EWOULDBLOCK = EAGAIN; /// enum ENOMSG = 42; /// enum EIDRM = 43; /// enum ECHRNG = 44; /// enum EL2NSYNC = 45; /// enum EL3HLT = 46; /// enum EL3RST = 47; /// enum ELNRNG = 48; /// enum EUNATCH = 49; /// enum ENOCSI = 50; /// enum EL2HLT = 51; /// enum EBADE = 52; /// enum EBADR = 53; /// enum EXFULL = 54; /// enum ENOANO = 55; /// enum EBADRQC = 56; /// enum EBADSLT = 57; /// enum EDEADLOCK = EDEADLK; /// enum EBFONT = 59; /// enum ENOSTR = 60; /// enum ENODATA = 61; /// enum ETIME = 62; /// enum ENOSR = 63; /// enum ENONET = 64; /// enum ENOPKG = 65; /// enum EREMOTE = 66; /// enum ENOLINK = 67; /// enum EADV = 68; /// enum ESRMNT = 69; /// enum ECOMM = 70; /// enum EPROTO = 71; /// enum EMULTIHOP = 72; /// enum EDOTDOT = 73; /// enum EBADMSG = 74; /// enum EOVERFLOW = 75; /// enum ENOTUNIQ = 76; /// enum EBADFD = 77; /// enum EREMCHG = 78; /// enum ELIBACC = 79; /// enum ELIBBAD = 80; /// enum ELIBSCN = 81; /// enum ELIBMAX = 82; /// enum ELIBEXEC = 83; /// enum EILSEQ = 84; /// enum ERESTART = 85; /// enum ESTRPIPE = 86; /// enum EUSERS = 87; /// enum ENOTSOCK = 88; /// enum EDESTADDRREQ = 89; /// enum EMSGSIZE = 90; /// enum EPROTOTYPE = 91; /// enum ENOPROTOOPT = 92; /// enum EPROTONOSUPPORT = 93; /// enum ESOCKTNOSUPPORT = 94; /// enum EOPNOTSUPP = 95; /// enum ENOTSUP = EOPNOTSUPP; /// enum EPFNOSUPPORT = 96; /// enum EAFNOSUPPORT = 97; /// enum EADDRINUSE = 98; /// enum EADDRNOTAVAIL = 99; /// enum ENETDOWN = 100; /// enum ENETUNREACH = 101; /// enum ENETRESET = 102; /// enum ECONNABORTED = 103; /// enum ECONNRESET = 104; /// enum ENOBUFS = 105; /// enum EISCONN = 106; /// enum ENOTCONN = 107; /// enum ESHUTDOWN = 108; /// enum ETOOMANYREFS = 109; /// enum ETIMEDOUT = 110; /// enum ECONNREFUSED = 111; /// enum EHOSTDOWN = 112; /// enum EHOSTUNREACH = 113; /// enum EALREADY = 114; /// enum EINPROGRESS = 115; /// enum ESTALE = 116; /// enum EUCLEAN = 117; /// enum ENOTNAM = 118; /// enum ENAVAIL = 119; /// enum EISNAM = 120; /// enum EREMOTEIO = 121; /// enum EDQUOT = 122; /// enum ENOMEDIUM = 123; /// enum EMEDIUMTYPE = 124; /// enum ECANCELED = 125; /// enum ENOKEY = 126; /// enum EKEYEXPIRED = 127; /// enum EKEYREVOKED = 128; /// enum EKEYREJECTED = 129; /// enum EOWNERDEAD = 130; /// enum ENOTRECOVERABLE = 131; /// } else version(ARM) { enum EDEADLK = 35; /// enum ENAMETOOLONG = 36; /// enum ENOLCK = 37; /// enum ENOSYS = 38; /// enum ENOTEMPTY = 39; /// enum ELOOP = 40; /// enum EWOULDBLOCK = EAGAIN; /// enum ENOMSG = 42; /// enum EIDRM = 43; /// enum ECHRNG = 44; /// enum EL2NSYNC = 45; /// enum EL3HLT = 46; /// enum EL3RST = 47; /// enum ELNRNG = 48; /// enum EUNATCH = 49; /// enum ENOCSI = 50; /// enum EL2HLT = 51; /// enum EBADE = 52; /// enum EBADR = 53; /// enum EXFULL = 54; /// enum ENOANO = 55; /// enum EBADRQC = 56; /// enum EBADSLT = 57; /// enum EDEADLOCK = EDEADLK; /// enum EBFONT = 59; /// enum ENOSTR = 60; /// enum ENODATA = 61; /// enum ETIME = 62; /// enum ENOSR = 63; /// enum ENONET = 64; /// enum ENOPKG = 65; /// enum EREMOTE = 66; /// enum ENOLINK = 67; /// enum EADV = 68; /// enum ESRMNT = 69; /// enum ECOMM = 70; /// enum EPROTO = 71; /// enum EMULTIHOP = 72; /// enum EDOTDOT = 73; /// enum EBADMSG = 74; /// enum EOVERFLOW = 75; /// enum ENOTUNIQ = 76; /// enum EBADFD = 77; /// enum EREMCHG = 78; /// enum ELIBACC = 79; /// enum ELIBBAD = 80; /// enum ELIBSCN = 81; /// enum ELIBMAX = 82; /// enum ELIBEXEC = 83; /// enum EILSEQ = 84; /// enum ERESTART = 85; /// enum ESTRPIPE = 86; /// enum EUSERS = 87; /// enum ENOTSOCK = 88; /// enum EDESTADDRREQ = 89; /// enum EMSGSIZE = 90; /// enum EPROTOTYPE = 91; /// enum ENOPROTOOPT = 92; /// enum EPROTONOSUPPORT = 93; /// enum ESOCKTNOSUPPORT = 94; /// enum EOPNOTSUPP = 95; /// enum ENOTSUP = EOPNOTSUPP; /// enum EPFNOSUPPORT = 96; /// enum EAFNOSUPPORT = 97; /// enum EADDRINUSE = 98; /// enum EADDRNOTAVAIL = 99; /// enum ENETDOWN = 100; /// enum ENETUNREACH = 101; /// enum ENETRESET = 102; /// enum ECONNABORTED = 103; /// enum ECONNRESET = 104; /// enum ENOBUFS = 105; /// enum EISCONN = 106; /// enum ENOTCONN = 107; /// enum ESHUTDOWN = 108; /// enum ETOOMANYREFS = 109; /// enum ETIMEDOUT = 110; /// enum ECONNREFUSED = 111; /// enum EHOSTDOWN = 112; /// enum EHOSTUNREACH = 113; /// enum EALREADY = 114; /// enum EINPROGRESS = 115; /// enum ESTALE = 116; /// enum EUCLEAN = 117; /// enum ENOTNAM = 118; /// enum ENAVAIL = 119; /// enum EISNAM = 120; /// enum EREMOTEIO = 121; /// enum EDQUOT = 122; /// enum ENOMEDIUM = 123; /// enum EMEDIUMTYPE = 124; /// enum ECANCELED = 125; /// enum ENOKEY = 126; /// enum EKEYEXPIRED = 127; /// enum EKEYREVOKED = 128; /// enum EKEYREJECTED = 129; /// enum EOWNERDEAD = 130; /// enum ENOTRECOVERABLE = 131; /// } else version(AArch64) { enum EDEADLK = 35; /// enum ENAMETOOLONG = 36; /// enum ENOLCK = 37; /// enum ENOSYS = 38; /// enum ENOTEMPTY = 39; /// enum ELOOP = 40; /// enum EWOULDBLOCK = EAGAIN; /// enum ENOMSG = 42; /// enum EIDRM = 43; /// enum ECHRNG = 44; /// enum EL2NSYNC = 45; /// enum EL3HLT = 46; /// enum EL3RST = 47; /// enum ELNRNG = 48; /// enum EUNATCH = 49; /// enum ENOCSI = 50; /// enum EL2HLT = 51; /// enum EBADE = 52; /// enum EBADR = 53; /// enum EXFULL = 54; /// enum ENOANO = 55; /// enum EBADRQC = 56; /// enum EBADSLT = 57; /// enum EDEADLOCK = EDEADLK; /// enum EBFONT = 59; /// enum ENOSTR = 60; /// enum ENODATA = 61; /// enum ETIME = 62; /// enum ENOSR = 63; /// enum ENONET = 64; /// enum ENOPKG = 65; /// enum EREMOTE = 66; /// enum ENOLINK = 67; /// enum EADV = 68; /// enum ESRMNT = 69; /// enum ECOMM = 70; /// enum EPROTO = 71; /// enum EMULTIHOP = 72; /// enum EDOTDOT = 73; /// enum EBADMSG = 74; /// enum EOVERFLOW = 75; /// enum ENOTUNIQ = 76; /// enum EBADFD = 77; /// enum EREMCHG = 78; /// enum ELIBACC = 79; /// enum ELIBBAD = 80; /// enum ELIBSCN = 81; /// enum ELIBMAX = 82; /// enum ELIBEXEC = 83; /// enum EILSEQ = 84; /// enum ERESTART = 85; /// enum ESTRPIPE = 86; /// enum EUSERS = 87; /// enum ENOTSOCK = 88; /// enum EDESTADDRREQ = 89; /// enum EMSGSIZE = 90; /// enum EPROTOTYPE = 91; /// enum ENOPROTOOPT = 92; /// enum EPROTONOSUPPORT = 93; /// enum ESOCKTNOSUPPORT = 94; /// enum EOPNOTSUPP = 95; /// enum EPFNOSUPPORT = 96; /// enum EAFNOSUPPORT = 97; /// enum EADDRINUSE = 98; /// enum EADDRNOTAVAIL = 99; /// enum ENETDOWN = 100; /// enum ENETUNREACH = 101; /// enum ENETRESET = 102; /// enum ECONNABORTED = 103; /// enum ECONNRESET = 104; /// enum ENOBUFS = 105; /// enum EISCONN = 106; /// enum ENOTCONN = 107; /// enum ESHUTDOWN = 108; /// enum ETOOMANYREFS = 109; /// enum ETIMEDOUT = 110; /// enum ECONNREFUSED = 111; /// enum EHOSTDOWN = 112; /// enum EHOSTUNREACH = 113; /// enum EALREADY = 114; /// enum EINPROGRESS = 115; /// enum ESTALE = 116; /// enum EUCLEAN = 117; /// enum ENOTNAM = 118; /// enum ENAVAIL = 119; /// enum EISNAM = 120; /// enum EREMOTEIO = 121; /// enum EDQUOT = 122; /// enum ENOMEDIUM = 123; /// enum EMEDIUMTYPE = 124; /// enum ECANCELED = 125; /// enum ENOKEY = 126; /// enum EKEYEXPIRED = 127; /// enum EKEYREVOKED = 128; /// enum EKEYREJECTED = 129; /// enum EOWNERDEAD = 130; /// enum ERFKILL = 132; /// enum EHWPOISON = 133; /// } else version(MIPS64) { enum ENOMSG = 35; /// enum EIDRM = 36; /// enum ECHRNG = 37; /// enum EL2NSYNC = 38; /// enum EL3HLT = 39; /// enum EL3RST = 40; /// enum ELNRNG = 41; /// enum EUNATCH = 42; /// enum ENOCSI = 43; /// enum EL2HLT = 44; /// enum EDEADLK = 45; /// enum ENOLCK = 46; /// enum EBADE = 50; /// enum EBADR = 51; /// enum EXFULL = 52; /// enum ENOANO = 53; /// enum EBADRQC = 54; /// enum EBADSLT = 55; /// enum EDEADLOCK = 56; /// enum EBFONT = 59; /// enum ENOSTR = 60; /// enum ENODATA = 61; /// enum ETIME = 62; /// enum ENOSR = 63; /// enum ENONET = 64; /// enum ENOPKG = 65; /// enum EREMOTE = 66; /// enum ENOLINK = 67; /// enum EADV = 68; /// enum ESRMNT = 69; /// enum ECOMM = 70; /// enum EPROTO = 71; /// enum EDOTDOT = 73; /// enum EMULTIHOP = 74; /// enum EBADMSG = 77; /// enum ENAMETOOLONG = 78; /// enum EOVERFLOW = 79; /// enum ENOTUNIQ = 80; /// enum EBADFD = 81; /// enum EREMCHG = 82; /// enum ELIBACC = 83; /// enum ELIBBAD = 84; /// enum ELIBSCN = 85; /// enum ELIBMAX = 86; /// enum ELIBEXEC = 87; /// enum EILSEQ = 88; /// enum ENOSYS = 89; /// enum ELOOP = 90; /// enum ERESTART = 91; /// enum ESTRPIPE = 92; /// enum ENOTEMPTY = 93; /// enum EUSERS = 94; /// enum ENOTSOCK = 95; /// enum EDESTADDRREQ = 96; /// enum EMSGSIZE = 97; /// enum EPROTOTYPE = 98; /// enum ENOPROTOOPT = 99; /// enum EPROTONOSUPPORT = 120; /// enum ESOCKTNOSUPPORT = 121; /// enum EOPNOTSUPP = 122; /// enum EPFNOSUPPORT = 123; /// enum EAFNOSUPPORT = 124; /// enum EADDRINUSE = 125; /// enum EADDRNOTAVAIL = 126; /// enum ENETDOWN = 127; /// enum ENETUNREACH = 128; /// enum ENETRESET = 129; /// enum ECONNABORTED = 130; /// enum ECONNRESET = 131; /// enum ENOBUFS = 132; /// enum EISCONN = 133; /// enum ENOTCONN = 134; /// enum EUCLEAN = 135; /// enum ENOTNAM = 137; /// enum ENAVAIL = 138; /// enum EISNAM = 139; /// enum EREMOTEIO = 140; /// enum EINIT = 141; /// enum EREMDEV = 142; /// enum ESHUTDOWN = 143; /// enum ETOOMANYREFS = 144; /// enum ETIMEDOUT = 145; /// enum ECONNREFUSED = 146; /// enum EHOSTDOWN = 147; /// enum EHOSTUNREACH = 148; /// enum EWOULDBLOCK = EAGAIN; /// enum EALREADY = 149; /// enum EINPROGRESS = 150; /// enum ESTALE = 151; /// enum ECANCELED = 158; /// enum ENOMEDIUM = 159; /// enum EMEDIUMTYPE = 160; /// enum ENOKEY = 161; /// enum EKEYEXPIRED = 162; /// enum EKEYREVOKED = 163; /// enum EKEYREJECTED = 164; /// enum EOWNERDEAD = 165; /// enum ENOTRECOVERABLE = 166; /// enum ERFKILL = 167; /// enum EHWPOISON = 168; /// enum EDQUOT = 1133; /// } else version(PPC) { enum EDEADLK = 35; /// enum ENAMETOOLONG = 36; /// enum ENOLCK = 37; /// enum ENOSYS = 38; /// enum ENOTEMPTY = 39; /// enum ELOOP = 40; /// enum EWOULDBLOCK = EAGAIN; /// enum ENOMSG = 42; /// enum EIDRM = 43; /// enum ECHRNG = 44; /// enum EL2NSYNC = 45; /// enum EL3HLT = 46; /// enum EL3RST = 47; /// enum ELNRNG = 48; /// enum EUNATCH = 49; /// enum ENOCSI = 50; /// enum EL2HLT = 51; /// enum EBADE = 52; /// enum EBADR = 53; /// enum EXFULL = 54; /// enum ENOANO = 55; /// enum EBADRQC = 56; /// enum EBADSLT = 57; /// enum EDEADLOCK = EDEADLK; /// enum EBFONT = 59; /// enum ENOSTR = 60; /// enum ENODATA = 61; /// enum ETIME = 62; /// enum ENOSR = 63; /// enum ENONET = 64; /// enum ENOPKG = 65; /// enum EREMOTE = 66; /// enum ENOLINK = 67; /// enum EADV = 68; /// enum ESRMNT = 69; /// enum ECOMM = 70; /// enum EPROTO = 71; /// enum EMULTIHOP = 72; /// enum EDOTDOT = 73; /// enum EBADMSG = 74; /// enum EOVERFLOW = 75; /// enum ENOTUNIQ = 76; /// enum EBADFD = 77; /// enum EREMCHG = 78; /// enum ELIBACC = 79; /// enum ELIBBAD = 80; /// enum ELIBSCN = 81; /// enum ELIBMAX = 82; /// enum ELIBEXEC = 83; /// enum EILSEQ = 84; /// enum ERESTART = 85; /// enum ESTRPIPE = 86; /// enum EUSERS = 87; /// enum ENOTSOCK = 88; /// enum EDESTADDRREQ = 89; /// enum EMSGSIZE = 90; /// enum EPROTOTYPE = 91; /// enum ENOPROTOOPT = 92; /// enum EPROTONOSUPPORT = 93; /// enum ESOCKTNOSUPPORT = 94; /// enum EOPNOTSUPP = 95; /// enum EPFNOSUPPORT = 96; /// enum EAFNOSUPPORT = 97; /// enum EADDRINUSE = 98; /// enum EADDRNOTAVAIL = 99; /// enum ENETDOWN = 100; /// enum ENETUNREACH = 101; /// enum ENETRESET = 102; /// enum ECONNABORTED = 103; /// enum ECONNRESET = 104; /// enum ENOBUFS = 105; /// enum EISCONN = 106; /// enum ENOTCONN = 107; /// enum ESHUTDOWN = 108; /// enum ETOOMANYREFS = 109; /// enum ETIMEDOUT = 110; /// enum ECONNREFUSED = 111; /// enum EHOSTDOWN = 112; /// enum EHOSTUNREACH = 113; /// enum EALREADY = 114; /// enum EINPROGRESS = 115; /// enum ESTALE = 116; /// enum EUCLEAN = 117; /// enum ENOTNAM = 118; /// enum ENAVAIL = 119; /// enum EISNAM = 120; /// enum EREMOTEIO = 121; /// enum EDQUOT = 122; /// enum ENOMEDIUM = 123; /// enum EMEDIUMTYPE = 124; /// enum ECANCELED = 125; /// enum ENOKEY = 126; /// enum EKEYEXPIRED = 127; /// enum EKEYREVOKED = 128; /// enum EKEYREJECTED = 129; /// enum EOWNERDEAD = 130; /// enum ERFKILL = 132; /// enum EHWPOISON = 133; /// } else version(PPC64) { enum EDEADLK = 35; /// enum ENAMETOOLONG = 36; /// enum ENOLCK = 37; /// enum ENOSYS = 38; /// enum ENOTEMPTY = 39; /// enum ELOOP = 40; /// enum EWOULDBLOCK = EAGAIN; /// enum ENOMSG = 42; /// enum EIDRM = 43; /// enum ECHRNG = 44; /// enum EL2NSYNC = 45; /// enum EL3HLT = 46; /// enum EL3RST = 47; /// enum ELNRNG = 48; /// enum EUNATCH = 49; /// enum ENOCSI = 50; /// enum EL2HLT = 51; /// enum EBADE = 52; /// enum EBADR = 53; /// enum EXFULL = 54; /// enum ENOANO = 55; /// enum EBADRQC = 56; /// enum EBADSLT = 57; /// enum EDEADLOCK = EDEADLK; /// enum EBFONT = 59; /// enum ENOSTR = 60; /// enum ENODATA = 61; /// enum ETIME = 62; /// enum ENOSR = 63; /// enum ENONET = 64; /// enum ENOPKG = 65; /// enum EREMOTE = 66; /// enum ENOLINK = 67; /// enum EADV = 68; /// enum ESRMNT = 69; /// enum ECOMM = 70; /// enum EPROTO = 71; /// enum EMULTIHOP = 72; /// enum EDOTDOT = 73; /// enum EBADMSG = 74; /// enum EOVERFLOW = 75; /// enum ENOTUNIQ = 76; /// enum EBADFD = 77; /// enum EREMCHG = 78; /// enum ELIBACC = 79; /// enum ELIBBAD = 80; /// enum ELIBSCN = 81; /// enum ELIBMAX = 82; /// enum ELIBEXEC = 83; /// enum EILSEQ = 84; /// enum ERESTART = 85; /// enum ESTRPIPE = 86; /// enum EUSERS = 87; /// enum ENOTSOCK = 88; /// enum EDESTADDRREQ = 89; /// enum EMSGSIZE = 90; /// enum EPROTOTYPE = 91; /// enum ENOPROTOOPT = 92; /// enum EPROTONOSUPPORT = 93; /// enum ESOCKTNOSUPPORT = 94; /// enum EOPNOTSUPP = 95; /// enum EPFNOSUPPORT = 96; /// enum EAFNOSUPPORT = 97; /// enum EADDRINUSE = 98; /// enum EADDRNOTAVAIL = 99; /// enum ENETDOWN = 100; /// enum ENETUNREACH = 101; /// enum ENETRESET = 102; /// enum ECONNABORTED = 103; /// enum ECONNRESET = 104; /// enum ENOBUFS = 105; /// enum EISCONN = 106; /// enum ENOTCONN = 107; /// enum ESHUTDOWN = 108; /// enum ETOOMANYREFS = 109; /// enum ETIMEDOUT = 110; /// enum ECONNREFUSED = 111; /// enum EHOSTDOWN = 112; /// enum EHOSTUNREACH = 113; /// enum EALREADY = 114; /// enum EINPROGRESS = 115; /// enum ESTALE = 116; /// enum EUCLEAN = 117; /// enum ENOTNAM = 118; /// enum ENAVAIL = 119; /// enum EISNAM = 120; /// enum EREMOTEIO = 121; /// enum EDQUOT = 122; /// enum ENOMEDIUM = 123; /// enum EMEDIUMTYPE = 124; /// enum ECANCELED = 125; /// enum ENOKEY = 126; /// enum EKEYEXPIRED = 127; /// enum EKEYREVOKED = 128; /// enum EKEYREJECTED = 129; /// enum EOWNERDEAD = 130; /// enum ERFKILL = 132; /// enum EHWPOISON = 133; /// } else version(SystemZ) { enum EDEADLK = 35; /// enum ENAMETOOLONG = 36; /// enum ENOLCK = 37; /// enum ENOSYS = 38; /// enum ENOTEMPTY = 39; /// enum ELOOP = 40; /// enum EWOULDBLOCK = EAGAIN; /// enum ENOMSG = 42; /// enum EIDRM = 43; /// enum ECHRNG = 44; /// enum EL2NSYNC = 45; /// enum EL3HLT = 46; /// enum EL3RST = 47; /// enum ELNRNG = 48; /// enum EUNATCH = 49; /// enum ENOCSI = 50; /// enum EL2HLT = 51; /// enum EBADE = 52; /// enum EBADR = 53; /// enum EXFULL = 54; /// enum ENOANO = 55; /// enum EBADRQC = 56; /// enum EBADSLT = 57; /// enum EDEADLOCK = EDEADLK; /// enum EBFONT = 59; /// enum ENOSTR = 60; /// enum ENODATA = 61; /// enum ETIME = 62; /// enum ENOSR = 63; /// enum ENONET = 64; /// enum ENOPKG = 65; /// enum EREMOTE = 66; /// enum ENOLINK = 67; /// enum EADV = 68; /// enum ESRMNT = 69; /// enum ECOMM = 70; /// enum EPROTO = 71; /// enum EMULTIHOP = 72; /// enum EDOTDOT = 73; /// enum EBADMSG = 74; /// enum EOVERFLOW = 75; /// enum ENOTUNIQ = 76; /// enum EBADFD = 77; /// enum EREMCHG = 78; /// enum ELIBACC = 79; /// enum ELIBBAD = 80; /// enum ELIBSCN = 81; /// enum ELIBMAX = 82; /// enum ELIBEXEC = 83; /// enum EILSEQ = 84; /// enum ERESTART = 85; /// enum ESTRPIPE = 86; /// enum EUSERS = 87; /// enum ENOTSOCK = 88; /// enum EDESTADDRREQ = 89; /// enum EMSGSIZE = 90; /// enum EPROTOTYPE = 91; /// enum ENOPROTOOPT = 92; /// enum EPROTONOSUPPORT = 93; /// enum ESOCKTNOSUPPORT = 94; /// enum EOPNOTSUPP = 95; /// enum EPFNOSUPPORT = 96; /// enum EAFNOSUPPORT = 97; /// enum EADDRINUSE = 98; /// enum EADDRNOTAVAIL = 99; /// enum ENETDOWN = 100; /// enum ENETUNREACH = 101; /// enum ENETRESET = 102; /// enum ECONNABORTED = 103; /// enum ECONNRESET = 104; /// enum ENOBUFS = 105; /// enum EISCONN = 106; /// enum ENOTCONN = 107; /// enum ESHUTDOWN = 108; /// enum ETOOMANYREFS = 109; /// enum ETIMEDOUT = 110; /// enum ECONNREFUSED = 111; /// enum EHOSTDOWN = 112; /// enum EHOSTUNREACH = 113; /// enum EALREADY = 114; /// enum EINPROGRESS = 115; /// enum ESTALE = 116; /// enum EUCLEAN = 117; /// enum ENOTNAM = 118; /// enum ENAVAIL = 119; /// enum EISNAM = 120; /// enum EREMOTEIO = 121; /// enum EDQUOT = 122; /// enum ENOMEDIUM = 123; /// enum EMEDIUMTYPE = 124; /// enum ECANCELED = 125; /// enum ENOKEY = 126; /// enum EKEYEXPIRED = 127; /// enum EKEYREVOKED = 128; /// enum EKEYREJECTED = 129; /// enum EOWNERDEAD = 130; /// enum ERFKILL = 132; /// enum EHWPOISON = 133; /// } else { static assert(false, "Architecture not supported."); } } else version( OSX ) { enum EPERM = 1; /// Operation not permitted enum ENOENT = 2; /// No such file or directory enum ESRCH = 3; /// No such process enum EINTR = 4; /// Interrupted system call enum EIO = 5; /// Input/output error enum ENXIO = 6; /// Device not configured enum E2BIG = 7; /// Argument list too long enum ENOEXEC = 8; /// Exec format error enum EBADF = 9; /// Bad file descriptor enum ECHILD = 10; /// No child processes enum EDEADLK = 11; /// Resource deadlock avoided enum ENOMEM = 12; /// Cannot allocate memory enum EACCES = 13; /// Permission denied enum EFAULT = 14; /// Bad address enum EBUSY = 16; /// Device busy enum EEXIST = 17; /// File exists enum EXDEV = 18; /// Cross-device link enum ENODEV = 19; /// Operation not supported by device enum ENOTDIR = 20; /// Not a directory enum EISDIR = 21; /// Is a directory enum EINVAL = 22; /// Invalid argument enum ENFILE = 23; /// Too many open files in system enum EMFILE = 24; /// Too many open files enum ENOTTY = 25; /// Inappropriate ioctl for device enum ETXTBSY = 26; /// Text file busy enum EFBIG = 27; /// File too large enum ENOSPC = 28; /// No space left on device enum ESPIPE = 29; /// Illegal seek enum EROFS = 30; /// Read-only file system enum EMLINK = 31; /// Too many links enum EPIPE = 32; /// Broken pipe enum EDOM = 33; /// Numerical argument out of domain enum ERANGE = 34; /// Result too large enum EAGAIN = 35; /// Resource temporarily unavailable enum EWOULDBLOCK = EAGAIN; /// Operation would block enum EINPROGRESS = 36; /// Operation now in progress enum EALREADY = 37; /// Operation already in progress enum ENOTSOCK = 38; /// Socket operation on non-socket enum EDESTADDRREQ = 39; /// Destination address required enum EMSGSIZE = 40; /// Message too long enum EPROTOTYPE = 41; /// Protocol wrong type for socket enum ENOPROTOOPT = 42; /// Protocol not available enum EPROTONOSUPPORT = 43; /// Protocol not supported enum ENOTSUP = 45; /// Operation not supported enum EOPNOTSUPP = ENOTSUP; /// Operation not supported on socket enum EAFNOSUPPORT = 47; /// Address family not supported by protocol family enum EADDRINUSE = 48; /// Address already in use enum EADDRNOTAVAIL = 49; /// Can't assign requested address enum ENETDOWN = 50; /// Network is down enum ENETUNREACH = 51; /// Network is unreachable enum ENETRESET = 52; /// Network dropped connection on reset enum ECONNABORTED = 53; /// Software caused connection abort enum ECONNRESET = 54; /// Connection reset by peer enum ENOBUFS = 55; /// No buffer space available enum EISCONN = 56; /// Socket is already connected enum ENOTCONN = 57; /// Socket is not connected enum ETIMEDOUT = 60; /// Operation timed out enum ECONNREFUSED = 61; /// Connection refused enum ELOOP = 62; /// Too many levels of symbolic links enum ENAMETOOLONG = 63; /// File name too long enum EHOSTUNREACH = 65; /// No route to host enum ENOTEMPTY = 66; /// Directory not empty enum EDQUOT = 69; /// Disc quota exceeded enum ESTALE = 70; /// Stale NFS file handle enum ENOLCK = 77; /// No locks available enum ENOSYS = 78; /// Function not implemented enum EOVERFLOW = 84; /// Value too large to be stored in data type enum ECANCELED = 89; /// Operation canceled enum EIDRM = 90; /// Identifier removed enum ENOMSG = 91; /// No message of desired type enum EILSEQ = 92; /// Illegal byte sequence enum EBADMSG = 94; /// Bad message enum EMULTIHOP = 95; /// Reserved enum ENODATA = 96; /// No message available on STREAM enum ENOLINK = 97; /// Reserved enum ENOSR = 98; /// No STREAM resources enum ENOSTR = 99; /// Not a STREAM enum EPROTO = 100; /// Protocol error enum ETIME = 101; /// STREAM ioctl timeout enum ELAST = 101; /// Must be equal largest errno } else version( FreeBSD ) { enum EPERM = 1; /// Operation not permitted enum ENOENT = 2; /// No such file or directory enum ESRCH = 3; /// No such process enum EINTR = 4; /// Interrupted system call enum EIO = 5; /// Input/output error enum ENXIO = 6; /// Device not configured enum E2BIG = 7; /// Argument list too long enum ENOEXEC = 8; /// Exec format error enum EBADF = 9; /// Bad file descriptor enum ECHILD = 10; /// No child processes enum EDEADLK = 11; /// Resource deadlock avoided enum ENOMEM = 12; /// Cannot allocate memory enum EACCES = 13; /// Permission denied enum EFAULT = 14; /// Bad address enum ENOTBLK = 15; /// Block device required enum EBUSY = 16; /// Device busy enum EEXIST = 17; /// File exists enum EXDEV = 18; /// Cross-device link enum ENODEV = 19; /// Operation not supported by device enum ENOTDIR = 20; /// Not a directory enum EISDIR = 21; /// Is a directory enum EINVAL = 22; /// Invalid argument enum ENFILE = 23; /// Too many open files in system enum EMFILE = 24; /// Too many open files enum ENOTTY = 25; /// Inappropriate ioctl for device enum ETXTBSY = 26; /// Text file busy enum EFBIG = 27; /// File too large enum ENOSPC = 28; /// No space left on device enum ESPIPE = 29; /// Illegal seek enum EROFS = 30; /// Read-only file system enum EMLINK = 31; /// Too many links enum EPIPE = 32; /// Broken pipe enum EDOM = 33; /// Numerical argument out of domain enum ERANGE = 34; /// Result too large enum EAGAIN = 35; /// Resource temporarily unavailable enum EWOULDBLOCK = EAGAIN; /// Operation would block enum EINPROGRESS = 36; /// Operation now in progress enum EALREADY = 37; /// Operation already in progress enum ENOTSOCK = 38; /// Socket operation on non-socket enum EDESTADDRREQ = 39; /// Destination address required enum EMSGSIZE = 40; /// Message too long enum EPROTOTYPE = 41; /// Protocol wrong type for socket enum ENOPROTOOPT = 42; /// Protocol not available enum EPROTONOSUPPORT = 43; /// Protocol not supported enum ENOTSUP = 45; /// Operation not supported enum EOPNOTSUPP = ENOTSUP; /// Operation not supported on socket enum EAFNOSUPPORT = 47; /// Address family not supported by protocol family enum EADDRINUSE = 48; /// Address already in use enum EADDRNOTAVAIL = 49; /// Can't assign requested address enum ENETDOWN = 50; /// Network is down enum ENETUNREACH = 51; /// Network is unreachable enum ENETRESET = 52; /// Network dropped connection on reset enum ECONNABORTED = 53; /// Software caused connection abort enum ECONNRESET = 54; /// Connection reset by peer enum ENOBUFS = 55; /// No buffer space available enum EISCONN = 56; /// Socket is already connected enum ENOTCONN = 57; /// Socket is not connected enum ESHUTDOWN = 58; /// Can't send after socket shutdown enum ETOOMANYREFS = 59; /// Too many refrences; can't splice enum ETIMEDOUT = 60; /// Operation timed out enum ECONNREFUSED = 61; /// Connection refused enum ELOOP = 62; /// Too many levels of symbolic links enum ENAMETOOLONG = 63; /// File name too long enum EHOSTUNREACH = 65; /// No route to host enum ENOTEMPTY = 66; /// Directory not empty enum EPROCLIM = 67; /// Too many processes enum EUSERS = 68; /// Too many users enum EDQUOT = 69; /// Disc quota exceeded enum ESTALE = 70; /// Stale NFS file handle enum EREMOTE = 71; /// Too many levels of remote in path enum EBADRPC = 72; /// RPC struct is bad enum ERPCMISMATCH = 73; /// RPC version wrong enum EPROGUNAVAIL = 74; /// RPC prog. not avail enum EPROGMISMATCH = 75; /// Program version wrong enum EPROCUNAVAIL = 76; /// Bad procedure for program enum ENOLCK = 77; /// No locks available enum ENOSYS = 78; /// Function not implemented enum EFTYPE = 79; /// Inappropriate file type or format enum EAUTH = 80; /// Authentication error enum ENEEDAUTH = 81; /// Need authenticator enum EIDRM = 82; /// Itendifier removed enum ENOMSG = 83; /// No message of desired type enum EOVERFLOW = 84; /// Value too large to be stored in data type enum ECANCELED = 85; /// Operation canceled enum EILSEQ = 86; /// Illegal byte sequence enum ENOATTR = 87; /// Attribute not found enum EDOOFUS = 88; /// Programming error enum EBADMSG = 89; /// Bad message enum EMULTIHOP = 90; /// Multihop attempted enum ENOLINK = 91; /// Link has been severed enum EPROTO = 92; /// Protocol error enum ELAST = 92; /// Must be equal largest errno } else version( OpenBSD ) { enum EPERM = 1; /// Operation not permitted enum ENOENT = 2; /// No such file or directory enum ESRCH = 3; /// No such process enum EINTR = 4; /// Interrupted system call enum EIO = 5; /// Input/output error enum ENXIO = 6; /// Device not configured enum E2BIG = 7; /// Argument list too long enum ENOEXEC = 8; /// Exec format error enum EBADF = 9; /// Bad file descriptor enum ECHILD = 10; /// No child processes enum EDEADLK = 11; /// Resource deadlock avoided enum ENOMEM = 12; /// Cannot allocate memory enum EACCES = 13; /// Permission denied enum EFAULT = 14; /// Bad address enum ENOTBLK = 15; /// Block device required enum EBUSY = 16; /// Device busy enum EEXIST = 17; /// File exists enum EXDEV = 18; /// Cross-device link enum ENODEV = 19; /// Operation not supported by device enum ENOTDIR = 20; /// Not a directory enum EISDIR = 21; /// Is a directory enum EINVAL = 22; /// Invalid argument enum ENFILE = 23; /// Too many open files in system enum EMFILE = 24; /// Too many open files enum ENOTTY = 25; /// Inappropriate ioctl for device enum ETXTBSY = 26; /// Text file busy enum EFBIG = 27; /// File too large enum ENOSPC = 28; /// No space left on device enum ESPIPE = 29; /// Illegal seek enum EROFS = 30; /// Read-only file system enum EMLINK = 31; /// Too many links enum EPIPE = 32; /// Broken pipe enum EDOM = 33; /// Numerical argument out of domain enum ERANGE = 34; /// Result too large enum EAGAIN = 35; /// Resource temporarily unavailable enum EWOULDBLOCK = EAGAIN; /// Operation would block enum EINPROGRESS = 36; /// Operation now in progress enum EALREADY = 37; /// Operation already in progress enum ENOTSOCK = 38; /// Socket operation on non-socket enum EDESTADDRREQ = 39; /// Destination address required enum EMSGSIZE = 40; /// Message too long enum EPROTOTYPE = 41; /// Protocol wrong type for socket enum ENOPROTOOPT = 42; /// Protocol not available enum EPROTONOSUPPORT = 43; /// Protocol not supported enum ESOCKTNOSUPPORT = 44; /// Socket type not supported enum EOPNOTSUPP = 45; /// Operation not supported enum EPFNOSUPPORT = 46; /// Protocol family not supported enum EAFNOSUPPORT = 47; /// Address family not supported by protocol family enum EADDRINUSE = 48; /// Address already in use enum EADDRNOTAVAIL = 49; /// Can't assign requested address enum ENETDOWN = 50; /// Network is down enum ENETUNREACH = 51; /// Network is unreachable enum ENETRESET = 52; /// Network dropped connection on reset enum ECONNABORTED = 53; /// Software caused connection abort enum ECONNRESET = 54; /// Connection reset by peer enum ENOBUFS = 55; /// No buffer space available enum EISCONN = 56; /// Socket is already connected enum ENOTCONN = 57; /// Socket is not connected enum ESHUTDOWN = 58; /// Can't send after socket shutdown enum ETOOMANYREFS = 59; /// Too many references: can't splice enum ETIMEDOUT = 60; /// Operation timed out enum ECONNREFUSED = 61; /// Connection refused enum ELOOP = 62; /// Too many levels of symbolic links enum ENAMETOOLONG = 63; /// File name too long enum EHOSTDOWN = 64; /// Host is down enum EHOSTUNREACH = 65; /// No route to host enum ENOTEMPTY = 66; /// Directory not empty enum EPROCLIM = 67; /// Too many processes enum EUSERS = 68; /// Too many users enum EDQUOT = 69; /// Disk quota exceeded enum ESTALE = 70; /// Stale NFS file handle enum EREMOTE = 71; /// Too many levels of remote in path enum EBADRPC = 72; /// RPC struct is bad enum ERPCMISMATCH = 73; /// RPC version wrong enum EPROGUNAVAIL = 74; /// RPC program not available enum EPROGMISMATCH = 75; /// Program version wrong enum EPROCUNAVAIL = 76; /// Bad procedure for program enum ENOLCK = 77; /// No locks available enum ENOSYS = 78; /// Function not implemented enum EFTYPE = 79; /// Inappropriate file type or format enum EAUTH = 80; /// Authentication error enum ENEEDAUTH = 81; /// Need authenticator enum EIPSEC = 82; /// IPsec processing failure enum ENOATTR = 83; /// Attribute not found enum EILSEQ = 84; /// Illegal byte sequence enum ENOMEDIUM = 85; /// No medium found enum EMEDIUMTYPE = 86; /// Wrong medium type enum EOVERFLOW = 87; /// Value too large to be stored in data type enum ECANCELED = 88; /// Operation canceled enum EIDRM = 89; /// Identifier removed enum ENOMSG = 90; /// No message of desired type enum ENOTSUP = 91; /// Not supported enum ELAST = 91; /// Must be equal largest errno } else version (Solaris) { enum EPERM = 1 /** Not super-user */; enum ENOENT = 2 /** No such file or directory */; enum ESRCH = 3 /** No such process */; enum EINTR = 4 /** interrupted system call */; enum EIO = 5 /** I/O error */; enum ENXIO = 6 /** No such device or address */; enum E2BIG = 7 /** Arg list too long */; enum ENOEXEC = 8 /** Exec format error */; enum EBADF = 9 /** Bad file number */; enum ECHILD = 10 /** No children */; enum EAGAIN = 11 /** Resource temporarily unavailable */; enum ENOMEM = 12 /** Not enough core */; enum EACCES = 13 /** Permission denied */; enum EFAULT = 14 /** Bad address */; enum ENOTBLK = 15 /** Block device required */; enum EBUSY = 16 /** Mount device busy */; enum EEXIST = 17 /** File exists */; enum EXDEV = 18 /** Cross-device link */; enum ENODEV = 19 /** No such device */; enum ENOTDIR = 20 /** Not a directory */; enum EISDIR = 21 /** Is a directory */; enum EINVAL = 22 /** Invalid argument */; enum ENFILE = 23 /** File table overflow */; enum EMFILE = 24 /** Too many open files */; enum ENOTTY = 25 /** Inappropriate ioctl for device */; enum ETXTBSY = 26 /** Text file busy */; enum EFBIG = 27 /** File too large */; enum ENOSPC = 28 /** No space left on device */; enum ESPIPE = 29 /** Illegal seek */; enum EROFS = 30 /** Read only file system */; enum EMLINK = 31 /** Too many links */; enum EPIPE = 32 /** Broken pipe */; enum EDOM = 33 /** Math arg out of domain of func */; enum ERANGE = 34 /** Math result not representable */; enum ENOMSG = 35 /** No message of desired type */; enum EIDRM = 36 /** Identifier removed */; enum ECHRNG = 37 /** Channel number out of range */; enum EL2NSYNC = 38 /** Level 2 not synchronized */; enum EL3HLT = 39 /** Level 3 halted */; enum EL3RST = 40 /** Level 3 reset */; enum ELNRNG = 41 /** Link number out of range */; enum EUNATCH = 42 /** Protocol driver not attached */; enum ENOCSI = 43 /** No CSI structure available */; enum EL2HLT = 44 /** Level 2 halted */; enum EDEADLK = 45 /** Deadlock condition. */; enum ENOLCK = 46 /** No record locks available. */; enum ECANCELED = 47 /** Operation canceled */; enum ENOTSUP = 48 /** Operation not supported */; enum EDQUOT = 49 /** Disc quota exceeded */; enum EBADE = 50 /** invalid exchange */; enum EBADR = 51 /** invalid request descriptor */; enum EXFULL = 52 /** exchange full */; enum ENOANO = 53 /** no anode */; enum EBADRQC = 54 /** invalid request code */; enum EBADSLT = 55 /** invalid slot */; enum EDEADLOCK = 56 /** file locking deadlock error */; enum EBFONT = 57 /** bad font file fmt */; enum EOWNERDEAD = 58 /** process died with the lock */; enum ENOTRECOVERABLE = 59 /** lock is not recoverable */; enum ENOSTR = 60 /** Device not a stream */; enum ENODATA = 61 /** no data (for no delay io) */; enum ETIME = 62 /** timer expired */; enum ENOSR = 63 /** out of streams resources */; enum ENONET = 64 /** Machine is not on the network */; enum ENOPKG = 65 /** Package not installed */; enum EREMOTE = 66 /** The object is remote */; enum ENOLINK = 67 /** the link has been severed */; enum EADV = 68 /** advertise error */; enum ESRMNT = 69 /** srmount error */; enum ECOMM = 70 /** Communication error on send */; enum EPROTO = 71 /** Protocol error */; enum ELOCKUNMAPPED = 72 /** locked lock was unmapped */; enum ENOTACTIVE = 73 /** Facility is not active */; enum EMULTIHOP = 74 /** multihop attempted */; enum EBADMSG = 77 /** trying to read unreadable message */; enum ENAMETOOLONG = 78 /** path name is too long */; enum EOVERFLOW = 79 /** value too large to be stored in data type */; enum ENOTUNIQ = 80 /** given log. name not unique */; enum EBADFD = 81 /** f.d. invalid for this operation */; enum EREMCHG = 82 /** Remote address changed */; enum ELIBACC = 83 /** Can't access a needed shared lib. */; enum ELIBBAD = 84 /** Accessing a corrupted shared lib. */; enum ELIBSCN = 85 /** .lib section in a.out corrupted. */; enum ELIBMAX = 86 /** Attempting to link in too many libs. */; enum ELIBEXEC = 87 /** Attempting to exec a shared library. */; enum EILSEQ = 88 /** Illegal byte sequence. */; enum ENOSYS = 89 /** Unsupported file system operation */; enum ELOOP = 90 /** Symbolic link loop */; enum ERESTART = 91 /** Restartable system call */; enum ESTRPIPE = 92 /** if pipe/FIFO, don't sleep in stream head */; enum ENOTEMPTY = 93 /** directory not empty */; enum EUSERS = 94 /** Too many users (for UFS) */; enum ENOTSOCK = 95 /** Socket operation on non-socket */; enum EDESTADDRREQ = 96 /** Destination address required */; enum EMSGSIZE = 97 /** Message too long */; enum EPROTOTYPE = 98 /** Protocol wrong type for socket */; enum ENOPROTOOPT = 99 /** Protocol not available */; enum EPROTONOSUPPORT = 120 /** Protocol not supported */; enum ESOCKTNOSUPPORT = 121 /** Socket type not supported */; enum EOPNOTSUPP = 122 /** Operation not supported on socket */; enum EPFNOSUPPORT = 123 /** Protocol family not supported */; enum EAFNOSUPPORT = 124 /** Address family not supported by the protocol family */; enum EADDRINUSE = 125 /** Address already in use */; enum EADDRNOTAVAIL = 126 /** Can't assign requested address */; enum ENETDOWN = 127 /** Network is down */; enum ENETUNREACH = 128 /** Network is unreachable */; enum ENETRESET = 129 /** Network dropped connection because of reset */; enum ECONNABORTED = 130 /** Software caused connection abort */; enum ECONNRESET = 131 /** Connection reset by peer */; enum ENOBUFS = 132 /** No buffer space available */; enum EISCONN = 133 /** Socket is already connected */; enum ENOTCONN = 134 /** Socket is not connected */; enum ESHUTDOWN = 143 /** Can't send after socket shutdown */; enum ETOOMANYREFS = 144 /** Too many references: can't splice */; enum ETIMEDOUT = 145 /** Connection timed out */; enum ECONNREFUSED = 146 /** Connection refused */; enum EHOSTDOWN = 147 /** Host is down */; enum EHOSTUNREACH = 148 /** No route to host */; enum EWOULDBLOCK = EAGAIN; /** Resource temporarily unavailable */; enum EALREADY = 149 /** operation already in progress */; enum EINPROGRESS = 150 /** operation now in progress */; enum ESTALE = 151 /** Stale NFS file handle */; } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdc/string.d0000664000175000017500000000433512776214756021617 0ustar kaikai/** * D header file for C99. * * $(C_HEADER_DESCRIPTION pubs.opengroup.org/onlinepubs/009695399/basedefs/_string.h.html, _string.h) * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/stdc/_string.d) * Standards: ISO/IEC 9899:1999 (E) */ module core.stdc.string; extern (C): @system: nothrow: @nogc: /// pure void* memchr(in void* s, int c, size_t n); /// pure int memcmp(in void* s1, in void* s2, size_t n); /// pure void* memcpy(void* s1, in void* s2, size_t n); version (Windows) { /// int memicmp(in char* s1, in char* s2, size_t n); } /// pure void* memmove(void* s1, in void* s2, size_t n); /// pure void* memset(void* s, int c, size_t n); /// pure char* strcpy(char* s1, in char* s2); /// pure char* strncpy(char* s1, in char* s2, size_t n); /// pure char* strcat(char* s1, in char* s2); /// pure char* strncat(char* s1, in char* s2, size_t n); /// pure int strcmp(in char* s1, in char* s2); /// int strcoll(in char* s1, in char* s2); /// pure int strncmp(in char* s1, in char* s2, size_t n); /// size_t strxfrm(char* s1, in char* s2, size_t n); /// pure char* strchr(in char* s, int c); /// pure size_t strcspn(in char* s1, in char* s2); /// pure char* strpbrk(in char* s1, in char* s2); /// pure char* strrchr(in char* s, int c); /// pure size_t strspn(in char* s1, in char* s2); /// pure char* strstr(in char* s1, in char* s2); /// char* strtok(char* s1, in char* s2); /// char* strerror(int errnum); version (CRuntime_Glibc) { /// const(char)* strerror_r(int errnum, char* buf, size_t buflen); } else version (OSX) { int strerror_r(int errnum, char* buf, size_t buflen); } else version (FreeBSD) { int strerror_r(int errnum, char* buf, size_t buflen); } else version (OpenBSD) { int strerror_r(int errnum, char* buf, size_t buflen); } else version (Solaris) { int strerror_r(int errnum, char* buf, size_t buflen); } else version (CRuntime_Bionic) { /// int strerror_r(int errnum, char* buf, size_t buflen); } /// pure size_t strlen(in char* s); /// char* strdup(in char *s); ldc-1.1.0-beta3-src/runtime/druntime/src/core/memory.d0000664000175000017500000007074612776214756020675 0ustar kaikai/** * This module provides an interface to the garbage collector used by * applications written in the D programming language. It allows the * garbage collector in the runtime to be swapped without affecting * binary compatibility of applications. * * Using this module is not necessary in typical D code. It is mostly * useful when doing low-level _memory management. * * Notes_to_users: * $(OL $(LI The GC is a conservative mark-and-sweep collector. It only runs a collection cycle when an allocation is requested of it, never otherwise. Hence, if the program is not doing allocations, there will be no GC collection pauses. The pauses occur because all threads the GC knows about are halted so the threads' stacks and registers can be scanned for references to GC allocated data. ) $(LI The GC does not know about threads that were created by directly calling the OS/C runtime thread creation APIs and D threads that were detached from the D runtime after creation. Such threads will not be paused for a GC collection, and the GC might not detect references to GC allocated data held by them. This can cause memory corruption. There are several ways to resolve this issue: $(OL $(LI Do not hold references to GC allocated data in such threads.) $(LI Register/unregister such data with calls to $(LREF addRoot)/$(LREF removeRoot) and $(LREF addRange)/$(LREF removeRange).) $(LI Maintain another reference to that same data in another thread that the GC does know about.) $(LI Disable GC collection cycles while that thread is active with $(LREF disable)/$(LREF enable).) $(LI Register the thread with the GC using $(CXREF thread, thread_attachThis)/$(CXREF thread, thread_detachThis).) ) ) ) * * Notes_to_implementors: * $(UL * $(LI On POSIX systems, the signals SIGUSR1 and SIGUSR2 are reserved * by this module for use in the garbage collector implementation. * Typically, they will be used to stop and resume other threads * when performing a collection, but an implementation may choose * not to use this mechanism (or not stop the world at all, in the * case of concurrent garbage collectors).) * * $(LI Registers, the stack, and any other _memory locations added through * the $(D GC.$(LREF addRange)) function are always scanned conservatively. * This means that even if a variable is e.g. of type $(D float), * it will still be scanned for possible GC pointers. And, if the * word-interpreted representation of the variable matches a GC-managed * _memory block's address, that _memory block is considered live.) * * $(LI Implementations are free to scan the non-root heap in a precise * manner, so that fields of types like $(D float) will not be considered * relevant when scanning the heap. Thus, casting a GC pointer to an * integral type (e.g. $(D size_t)) and storing it in a field of that * type inside the GC heap may mean that it will not be recognized * if the _memory block was allocated with precise type info or with * the $(D GC.BlkAttr.$(LREF NO_SCAN)) attribute.) * * $(LI Destructors will always be executed while other threads are * active; that is, an implementation that stops the world must not * execute destructors until the world has been resumed.) * * $(LI A destructor of an object must not access object references * within the object. This means that an implementation is free to * optimize based on this rule.) * * $(LI An implementation is free to perform heap compaction and copying * so long as no valid GC pointers are invalidated in the process. * However, _memory allocated with $(D GC.BlkAttr.$(LREF NO_MOVE)) must * not be moved/copied.) * * $(LI Implementations must support interior pointers. That is, if the * only reference to a GC-managed _memory block points into the * middle of the block rather than the beginning (for example), the * GC must consider the _memory block live. The exception to this * rule is when a _memory block is allocated with the * $(D GC.BlkAttr.$(LREF NO_INTERIOR)) attribute; it is the user's * responsibility to make sure such _memory blocks have a proper pointer * to them when they should be considered live.) * * $(LI It is acceptable for an implementation to store bit flags into * pointer values and GC-managed _memory blocks, so long as such a * trick is not visible to the application. In practice, this means * that only a stop-the-world collector can do this.) * * $(LI Implementations are free to assume that GC pointers are only * stored on word boundaries. Unaligned pointers may be ignored * entirely.) * * $(LI Implementations are free to run collections at any point. It is, * however, recommendable to only do so when an allocation attempt * happens and there is insufficient _memory available.) * ) * * Copyright: Copyright Sean Kelly 2005 - 2015. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly, Alex Rønne Petersen * Source: $(DRUNTIMESRC core/_memory.d) */ module core.memory; private { extern (C) void gc_init(); extern (C) void gc_term(); extern (C) void gc_enable() nothrow; extern (C) void gc_disable() nothrow; extern (C) void gc_collect() nothrow; extern (C) void gc_minimize() nothrow; extern (C) uint gc_getAttr( void* p ) pure nothrow; extern (C) uint gc_setAttr( void* p, uint a ) pure nothrow; extern (C) uint gc_clrAttr( void* p, uint a ) pure nothrow; extern (C) void* gc_malloc( size_t sz, uint ba = 0, const TypeInfo = null ) pure nothrow; extern (C) void* gc_calloc( size_t sz, uint ba = 0, const TypeInfo = null ) pure nothrow; extern (C) BlkInfo_ gc_qalloc( size_t sz, uint ba = 0, const TypeInfo = null ) pure nothrow; extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0, const TypeInfo = null ) pure nothrow; extern (C) size_t gc_extend( void* p, size_t mx, size_t sz, const TypeInfo = null ) pure nothrow; extern (C) size_t gc_reserve( size_t sz ) nothrow; extern (C) void gc_free( void* p ) pure nothrow; extern (C) void* gc_addrOf( void* p ) pure nothrow; extern (C) size_t gc_sizeOf( void* p ) pure nothrow; struct BlkInfo_ { void* base; size_t size; uint attr; } extern (C) BlkInfo_ gc_query( void* p ) pure nothrow; extern (C) void gc_addRoot( in void* p ) nothrow; extern (C) void gc_addRange( in void* p, size_t sz, const TypeInfo ti = null ) nothrow @nogc; extern (C) void gc_removeRoot( in void* p ) nothrow; extern (C) void gc_removeRange( in void* p ) nothrow @nogc; extern (C) void gc_runFinalizers( in void[] segment ); package extern (C) bool gc_inFinalizer(); } /** * This struct encapsulates all garbage collection functionality for the D * programming language. */ struct GC { @disable this(); /** * Enables automatic garbage collection behavior 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 * automatic collections are enabled. */ static void enable() nothrow /* FIXME pure */ { gc_enable(); } /** * Disables automatic garbage collections performed to minimize the * process footprint. Collections may continue to occur in instances * where the implementation deems necessary for correct program behavior, * such as during an out of memory condition. This function is reentrant, * but enable must be called once for each call to disable. */ static void disable() nothrow /* FIXME pure */ { 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() nothrow /* FIXME pure */ { gc_collect(); } /** * Indicates that the managed memory space be minimized by returning free * physical memory to the operating system. The amount of free memory * returned depends on the allocator design and on program behavior. */ static void minimize() nothrow /* FIXME pure */ { gc_minimize(); } /** * Elements for a bit field representing memory block attributes. These * are manipulated via the getAttr, setAttr, clrAttr functions. */ enum BlkAttr : uint { NONE = 0b0000_0000, /// No attributes set. 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. /** This block contains the info to allow appending. This can be used to manually allocate arrays. Initial slice size is 0. Note: The slice's useable size will not match the block size. Use $(LREF capacity) to retrieve actual useable capacity. Example: ---- // Allocate the underlying array. int* pToArray = cast(int*)GC.malloc(10 * int.sizeof, GC.BlkAttr.NO_SCAN | GC.BlkAttr.APPENDABLE); // Bind a slice. Check the slice has capacity information. int[] slice = pToArray[0 .. 0]; assert(capacity(slice) > 0); // Appending to the slice will not relocate it. slice.length = 5; slice ~= 1; assert(slice.ptr == p); ---- */ APPENDABLE = 0b0000_1000, /** This block is guaranteed to have a pointer to its base while it is alive. Interior pointers can be safely ignored. This attribute is useful for eliminating false pointers in very large data structures and is only implemented for data structures at least a page in size. */ NO_INTERIOR = 0b0001_0000, STRUCTFINAL = 0b0010_0000, // the block has a finalizer for (an array of) structs } /** * 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( in void* p ) nothrow { return getAttr(cast()p); } /// ditto static uint getAttr(void* p) pure nothrow { 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. * * Returns: * The result of a call to getAttr after the specified bits have been * set. */ static uint setAttr( in void* p, uint a ) nothrow { return setAttr(cast()p, a); } /// ditto static uint setAttr(void* p, uint a) pure nothrow { 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( in void* p, uint a ) nothrow { return clrAttr(cast()p, a); } /// ditto static uint clrAttr(void* p, uint a) pure nothrow { 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 OutOfMemoryError. * * Params: * sz = The desired allocation size in bytes. * ba = A bitmask of the attributes to set on this block. * ti = TypeInfo to describe the memory. The GC might use this information * to improve scanning for pointers or to call finalizers. * * Returns: * A reference to the allocated memory or null if insufficient memory * is available. * * Throws: * OutOfMemoryError on allocation failure. */ static void* malloc( size_t sz, uint ba = 0, const TypeInfo ti = null ) pure nothrow { return gc_malloc( sz, ba, ti ); } /** * 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 OutOfMemoryError. * * Params: * sz = The desired allocation size in bytes. * ba = A bitmask of the attributes to set on this block. * ti = TypeInfo to describe the memory. The GC might use this information * to improve scanning for pointers or to call finalizers. * * Returns: * Information regarding the allocated memory block or BlkInfo.init on * error. * * Throws: * OutOfMemoryError on allocation failure. */ static BlkInfo qalloc( size_t sz, uint ba = 0, const TypeInfo ti = null ) pure nothrow { return gc_qalloc( sz, ba, ti ); } /** * 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 * OutOfMemoryError. * * Params: * sz = The desired allocation size in bytes. * ba = A bitmask of the attributes to set on this block. * ti = TypeInfo to describe the memory. The GC might use this information * to improve scanning for pointers or to call finalizers. * * Returns: * A reference to the allocated memory or null if insufficient memory * is available. * * Throws: * OutOfMemoryError on allocation failure. */ static void* calloc( size_t sz, uint ba = 0, const TypeInfo ti = null ) pure nothrow { return gc_calloc( sz, ba, ti ); } /** * 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 OutOfMemoryError. 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. * ti = TypeInfo to describe the memory. The GC might use this information * to improve scanning for pointers or to call finalizers. * * 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: * OutOfMemoryError on allocation failure. */ static void* realloc( void* p, size_t sz, uint ba = 0, const TypeInfo ti = null ) pure nothrow { return gc_realloc( p, sz, ba, ti ); } /// Issue 13111 unittest { enum size1 = 1 << 11 + 1; // page in large object pool enum size2 = 1 << 22 + 1; // larger than large object pool size auto data1 = cast(ubyte*)GC.calloc(size1); auto data2 = cast(ubyte*)GC.realloc(data1, size2); BlkInfo info = query(data2); assert(info.size >= size2); } /** * 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 or if p references memory * not originally allocated by this garbage collector, no action will be * taken. * * Params: * p = A pointer to the root of a valid memory block or to null. * mx = The minimum extension size in bytes. * sz = The desired extension size in bytes. * ti = TypeInfo to describe the full memory block. The GC might use * this information to improve scanning for pointers or to * call finalizers. * * Returns: * The size in bytes of the extended memory block referenced by p or zero * if no extension occurred. * * Note: * Extend may also be used to extend slices (or memory blocks with * $(LREF APPENDABLE) info). However, use the return value only * as an indicator of success. $(LREF capacity) should be used to * retrieve actual useable slice capacity. */ static size_t extend( void* p, size_t mx, size_t sz, const TypeInfo ti = null ) pure nothrow { return gc_extend( p, mx, sz, ti ); } /// Standard extending unittest { size_t size = 1000; int* p = cast(int*)GC.malloc(size * int.sizeof, GC.BlkAttr.NO_SCAN); //Try to extend the allocated data by 1000 elements, preferred 2000. size_t u = GC.extend(p, 1000 * int.sizeof, 2000 * int.sizeof); if (u != 0) size = u / int.sizeof; } /// slice extending unittest { int[] slice = new int[](1000); int* p = slice.ptr; //Check we have access to capacity before attempting the extend if (slice.capacity) { //Try to extend slice by 1000 elements, preferred 2000. size_t u = GC.extend(p, 1000 * int.sizeof, 2000 * int.sizeof); if (u != 0) { slice.length = slice.capacity; assert(slice.length >= 2000); } } } /** * Requests that at least sz bytes of memory be obtained from the operating * system and marked as free. * * Params: * sz = The desired size in bytes. * * Returns: * The actual number of bytes reserved or zero on error. */ static size_t reserve( size_t sz ) nothrow /* FIXME pure */ { return gc_reserve( 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, if p points to the interior of a memory block, or if this * method is called from a finalizer, 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 ) pure nothrow { 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 inout(void)* addrOf( inout(void)* p ) nothrow /* FIXME pure */ { return cast(inout(void)*)gc_addrOf(cast(void*)p); } /// ditto static void* addrOf(void* p) pure nothrow { 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( in void* p ) nothrow { return gc_sizeOf(cast(void*)p); } /// ditto static size_t sizeOf(void* p) pure nothrow { return gc_sizeOf( p ); } // verify that the reallocation doesn't leave the size cache in a wrong state unittest { auto data = cast(int*)realloc(null, 4096); size_t size = GC.sizeOf(data); assert(size >= 4096); data = cast(int*)GC.realloc(data, 4100); size = GC.sizeOf(data); assert(size >= 4100); } /** * 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( in void* p ) nothrow { return gc_query(cast(void*)p); } /// ditto static BlkInfo query(void* p) pure nothrow { return gc_query( p ); } /** * Adds an internal root pointing to the GC memory block referenced by p. * As a result, the block referenced by p itself and any blocks accessible * via it will be considered live until the root is removed again. * * If p is null, no operation is performed. * * Params: * p = A pointer into a GC-managed memory block or null. * * Example: * --- * // Typical C-style callback mechanism; the passed function * // is invoked with the user-supplied context pointer at a * // later point. * extern(C) void addCallback(void function(void*), void*); * * // Allocate an object on the GC heap (this would usually be * // some application-specific context data). * auto context = new Object; * * // Make sure that it is not collected even if it is no * // longer referenced from D code (stack, GC heap, …). * GC.addRoot(cast(void*)context); * * // Also ensure that a moving collector does not relocate * // the object. * GC.setAttr(cast(void*)context, GC.BlkAttr.NO_MOVE); * * // Now context can be safely passed to the C library. * addCallback(&myHandler, cast(void*)context); * * extern(C) void myHandler(void* ctx) * { * // Assuming that the callback is invoked only once, the * // added root can be removed again now to allow the GC * // to collect it later. * GC.removeRoot(ctx); * GC.clrAttr(ctx, GC.BlkAttr.NO_MOVE); * * auto context = cast(Object)ctx; * // Use context here… * } * --- */ static void addRoot( in void* p ) nothrow /* FIXME pure */ { gc_addRoot( p ); } /** * Removes the memory block referenced by p from an internal list of roots * to be scanned during a collection. If p is null or is not a value * previously passed to addRoot() then no operation is performed. * * Params: * p = A pointer into a GC-managed memory block or null. */ static void removeRoot( in void* p ) nothrow /* FIXME pure */ { gc_removeRoot( p ); } /** * Adds $(D p[0 .. sz]) to the list of memory ranges to be scanned for * pointers during a collection. If p is null, no operation is performed. * * Note that $(D p[0 .. sz]) is treated as an opaque range of memory assumed * to be suitably managed by the caller. In particular, if p points into a * GC-managed memory block, addRange does $(I not) mark this block as live. * * 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. * ti = TypeInfo to describe the memory. The GC might use this information * to improve scanning for pointers or to call finalizers * * Example: * --- * // Allocate a piece of memory on the C heap. * enum size = 1_000; * auto rawMemory = core.stdc.stdlib.malloc(size); * * // Add it as a GC range. * GC.addRange(rawMemory, size); * * // Now, pointers to GC-managed memory stored in * // rawMemory will be recognized on collection. * --- */ static void addRange( in void* p, size_t sz, const TypeInfo ti = null ) @nogc nothrow /* FIXME pure */ { gc_addRange( p, sz, ti ); } /** * Removes the memory range starting at 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 addRange() then no operation is * performed. * * Params: * p = A pointer to a valid memory address or to null. */ static void removeRange( in void* p ) nothrow @nogc /* FIXME pure */ { gc_removeRange( p ); } /** * Runs any finalizer that is located in address range of the * given code segment. This is used before unloading shared * libraries. All matching objects which have a finalizer in this * code segment are assumed to be dead, using them while or after * calling this method has undefined behavior. * * Params: * segment = address range of a code segment. */ static void runFinalizers( in void[] segment ) { gc_runFinalizers( segment ); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/threadasm.S0000664000175000017500000004673612776214756021316 0ustar kaikai/** * Support code for mutithreading. * * Copyright: Copyright Mikola Lysenko 2005 - 2012. * License: Boost License 1.0. * Authors: Mikola Lysenko, Martin Nowak, Kai Nacke */ /* * Copyright Mikola Lysenko 2005 - 2012. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ #if (defined(__linux__) || defined(__FreeBSD__)) && defined(__ELF__) /* * Mark the resulting object file as not requiring execution permissions on * stack memory. The absence of this section would mark the whole resulting * library as requiring an executable stack, making it impossible to * dynamically load druntime on several Linux platforms where this is * forbidden due to security policies. */ .section .note.GNU-stack,"",%progbits #endif /* Let preprocessor tell us if C symbols have a prefix: __USER_LABEL_PREFIX__ */ #ifdef __USER_LABEL_PREFIX__ #define GLUE2(a, b) a ## b #define GLUE(a, b) GLUE2(a, b) #define CSYM(name) GLUE(__USER_LABEL_PREFIX__, name) #else #define CSYM(name) name #endif /************************************************************************************ * POWER PC ASM BITS ************************************************************************************/ #if defined( __PPC64__ ) /** * Performs a context switch. * r3: location where to store current stack pointer * r4: new stack pointer * * The stack frame uses the standard layout except for floating point and * vector registers. * * ELFv2: * +------------------------+ * | TOC Pointer Doubleword | SP+24 * +------------------------+ * | LR Save Doubleword | SP+16 * +------------------------+ * | Reserved | SP+12 * +------------------------+ * | CR Save Word | SP+8 * +------------------------+ * | Back Chain | SP+176 <-- Previous function * +------------------------+ * | GPR Save Area (14-31) | SP+32 * +------------------------+ * | TOC Pointer Doubleword | SP+24 * +------------------------+ * | LR Save Doubleword | SP+16 * +------------------------+ * | Reserved | SP+12 * +------------------------+ * | CR Save Word | SP+8 * +------------------------+ * | Back Chain | SP+0 <-- Stored stack pointer * +------------------------+ * | VR Save Area (20-31) | SP-16 * +------------------------+ * | FPR Save Area (14-31) | SP-200 * +------------------------+ * * ELFv1: * +------------------------+ * | Parameter Save Area | SP+48 * +------------------------+ * | TOC Pointer Doubleword | SP+40 * +------------------------+ * | Link editor doubleword | SP+32 * +------------------------+ * | Compiler Doubleword | SP+24 * +------------------------+ * | LR Save Doubleword | SP+16 * +------------------------+ * | Reserved | SP+12 * +------------------------+ * | CR Save Word | SP+8 * +------------------------+ * | Back Chain | SP+256 <-- Previous function * +------------------------+ * | GPR Save Area (14-31) | SP+112 * +------------------------+ * | Parameter Save Area | SP+48 * +------------------------+ * | TOC Pointer Doubleword | SP+40 * +------------------------+ * | Link editor doubleword | SP+32 * +------------------------+ * | Compiler Doubleword | SP+24 * +------------------------+ * | LR Save Doubleword | SP+16 * +------------------------+ * | Reserved | SP+12 * +------------------------+ * | CR Save Word | SP+8 * +------------------------+ * | Back Chain | SP+0 <-- Stored stack pointer * +------------------------+ * | VR Save Area (20-31) | SP-16 * +------------------------+ * | FPR Save Area (14-31) | SP-200 * +------------------------+ */ #if defined(_CALL_ELF) && _CALL_ELF == 2 #define USE_ABI_2 #define LINKAGE_SZ 32 #define CR_OFS 8 #define LR_OFS 16 #define TOC_OFS 24 #define GPR_OFS 32 #define STACK_SZ (LINKAGE_SZ + 18*8) #else #define LINKAGE_SZ 48 #define CR_OFS 8 #define LR_OFS 16 #define TOC_OFS 40 #define GPR_OFS 112 #define STACK_SZ (LINKAGE_SZ + 8*8 + 18*8) #endif .text #if defined( USE_ABI_2 ) .abiversion 2 #endif .align 2 .globl fiber_switchContext .type fiber_switchContext,@function #if defined( USE_ABI_2 ) .section .text.fiber_switchContext,"a",@progbits #else .section .opd,"aw",@progbits #endif fiber_switchContext: #if !defined( USE_ABI_2 ) .align 3 .quad .L.fiber_switchContext .quad .TOC.@tocbase .quad 0 .text #endif .L.fiber_switchContext: .cfi_startproc #if defined( USE_ABI_2 ) addis 2, 12, .TOC.-.L.fiber_switchContext@ha addi 2, 2, .TOC.-.L.fiber_switchContext@l .localentry fiber_switchContext, .-.L.fiber_switchContext #endif mflr 0 std 0, LR_OFS(1) stdu 1, -STACK_SZ(1) .cfi_def_cfa_offset STACK_SZ .cfi_offset lr, LR_OFS /* Update the old stack pointer */ std 1, 0(3) /* Save CC and TOC */ mfcr 0 sth 0, CR_OFS(1) std 2, TOC_OFS(1) /* Save GPRs */ std 14, (GPR_OFS + 0 * 8)(1) std 15, (GPR_OFS + 1 * 8)(1) std 16, (GPR_OFS + 2 * 8)(1) std 17, (GPR_OFS + 3 * 8)(1) std 18, (GPR_OFS + 4 * 8)(1) std 19, (GPR_OFS + 5 * 8)(1) std 20, (GPR_OFS + 6 * 8)(1) std 21, (GPR_OFS + 7 * 8)(1) std 22, (GPR_OFS + 8 * 8)(1) std 23, (GPR_OFS + 9 * 8)(1) std 24, (GPR_OFS + 10 * 8)(1) std 25, (GPR_OFS + 11 * 8)(1) std 26, (GPR_OFS + 12 * 8)(1) std 27, (GPR_OFS + 13 * 8)(1) std 28, (GPR_OFS + 14 * 8)(1) std 29, (GPR_OFS + 15 * 8)(1) std 30, (GPR_OFS + 16 * 8)(1) std 31, (GPR_OFS + 17 * 8)(1) /* Save VRs */ addi 0, 1, (- 1 * 16) stvx 20, 0, 0 addi 0, 1, (- 2 * 16) stvx 21, 0, 0 addi 0, 1, (- 3 * 16) stvx 22, 0, 0 addi 0, 1, (- 4 * 16) stvx 23, 0, 0 addi 0, 1, (- 5 * 16) stvx 24, 0, 0 addi 0, 1, (- 6 * 16) stvx 25, 0, 0 addi 0, 1, (- 7 * 16) stvx 26, 0, 0 addi 0, 1, (- 8 * 16) stvx 27, 0, 0 addi 0, 1, (- 9 * 16) stvx 28, 0, 0 addi 0, 1, (-10 * 16) stvx 29, 0, 0 addi 0, 1, (-11 * 16) stvx 30, 0, 0 addi 0, 1, (-12 * 16) stvx 31, 0, 0 /* Save FPRs */ stfd 14, ( -1 * 8 -12 * 16)(1) stfd 15, ( -2 * 8 -12 * 16)(1) stfd 16, ( -3 * 8 -12 * 16)(1) stfd 17, ( -4 * 8 -12 * 16)(1) stfd 18, ( -5 * 8 -12 * 16)(1) stfd 19, ( -6 * 8 -12 * 16)(1) stfd 20, ( -7 * 8 -12 * 16)(1) stfd 21, ( -8 * 8 -12 * 16)(1) stfd 22, ( -9 * 8 -12 * 16)(1) stfd 23, (-10 * 8 -12 * 16)(1) stfd 24, (-11 * 8 -12 * 16)(1) stfd 25, (-12 * 8 -12 * 16)(1) stfd 26, (-13 * 8 -12 * 16)(1) stfd 27, (-14 * 8 -12 * 16)(1) stfd 28, (-15 * 8 -12 * 16)(1) stfd 29, (-16 * 8 -12 * 16)(1) stfd 30, (-17 * 8 -12 * 16)(1) stfd 31, (-18 * 8 -12 * 16)(1) /* Set new stack pointer */ mr 1, 4 /* Restore GPRs */ ld 14, (GPR_OFS + 0 * 8)(1) ld 15, (GPR_OFS + 1 * 8)(1) ld 16, (GPR_OFS + 2 * 8)(1) ld 17, (GPR_OFS + 3 * 8)(1) ld 18, (GPR_OFS + 4 * 8)(1) ld 19, (GPR_OFS + 5 * 8)(1) ld 20, (GPR_OFS + 6 * 8)(1) ld 21, (GPR_OFS + 7 * 8)(1) ld 22, (GPR_OFS + 8 * 8)(1) ld 23, (GPR_OFS + 9 * 8)(1) ld 24, (GPR_OFS + 10 * 8)(1) ld 25, (GPR_OFS + 11 * 8)(1) ld 26, (GPR_OFS + 12 * 8)(1) ld 27, (GPR_OFS + 13 * 8)(1) ld 28, (GPR_OFS + 14 * 8)(1) ld 29, (GPR_OFS + 15 * 8)(1) ld 30, (GPR_OFS + 16 * 8)(1) ld 31, (GPR_OFS + 17 * 8)(1) /* Load VRs */ addi 0, 1, (- 1 * 16) lvx 20, 0, 0 addi 0, 1, (- 2 * 16) lvx 21, 0, 0 addi 0, 1, (- 3 * 16) lvx 22, 0, 0 addi 0, 1, (- 4 * 16) lvx 23, 0, 0 addi 0, 1, (- 5 * 16) lvx 24, 0, 0 addi 0, 1, (- 6 * 16) lvx 25, 0, 0 addi 0, 1, (- 7 * 16) lvx 26, 0, 0 addi 0, 1, (- 8 * 16) lvx 27, 0, 0 addi 0, 1, (- 9 * 16) lvx 28, 0, 0 addi 0, 1, (-10 * 16) lvx 29, 0, 0 addi 0, 1, (-11 * 16) lvx 30, 0, 0 addi 0, 1, (-12 * 16) lvx 31, 0, 0 /* Restore FPRs */ lfd 14, ( -1 * 8 -12 * 16)(1) lfd 15, ( -2 * 8 -12 * 16)(1) lfd 16, ( -3 * 8 -12 * 16)(1) lfd 17, ( -4 * 8 -12 * 16)(1) lfd 18, ( -5 * 8 -12 * 16)(1) lfd 19, ( -6 * 8 -12 * 16)(1) lfd 20, ( -7 * 8 -12 * 16)(1) lfd 21, ( -8 * 8 -12 * 16)(1) lfd 22, ( -9 * 8 -12 * 16)(1) lfd 23, (-10 * 8 -12 * 16)(1) lfd 24, (-11 * 8 -12 * 16)(1) lfd 25, (-12 * 8 -12 * 16)(1) lfd 26, (-13 * 8 -12 * 16)(1) lfd 27, (-14 * 8 -12 * 16)(1) lfd 28, (-15 * 8 -12 * 16)(1) lfd 29, (-16 * 8 -12 * 16)(1) lfd 30, (-17 * 8 -12 * 16)(1) lfd 31, (-18 * 8 -12 * 16)(1) /* Set condition and TOC register */ lhz 0, CR_OFS(1) mtcr 0 ld 2, TOC_OFS(1) /* Return and switch context */ addi 1, 1, STACK_SZ ld 0, LR_OFS(1) mtlr 0 blr .long 0 .quad 0 .size fiber_switchContext,.-.L.fiber_switchContext .cfi_endproc #elif defined( __ppc__ ) || defined( __PPC__ ) || defined( __powerpc__ ) .section ".text" /** * Performs a context switch. * * r3 - old context pointer * r4 - new context pointer * */ .align 2 .globl fiber_switchContext .type fiber_switchContext, @function fiber_switchContext: /* Save linkage area */ mflr 0 mfcr 5 stw 0, 8(1) stw 5, 4(1) /* Save GPRs */ stw 11, (-1 * 4)(1) stw 13, (-2 * 4)(1) stw 14, (-3 * 4)(1) stw 15, (-4 * 4)(1) stw 16, (-5 * 4)(1) stw 17, (-6 * 4)(1) stw 18, (-7 * 4)(1) stw 19, (-8 * 4)(1) stw 20, (-9 * 4)(1) stw 21, (-10 * 4)(1) stw 22, (-11 * 4)(1) stw 23, (-12 * 4)(1) stw 24, (-13 * 4)(1) stw 25, (-14 * 4)(1) stw 26, (-15 * 4)(1) stw 27, (-16 * 4)(1) stw 28, (-17 * 4)(1) stw 29, (-18 * 4)(1) stw 30, (-19 * 4)(1) stwu 31, (-20 * 4)(1) /* We update the stack pointer here, since we do not want the GC to scan the floating point registers. */ /* Save FPRs */ stfd 14, (-1 * 8)(1) stfd 15, (-2 * 8)(1) stfd 16, (-3 * 8)(1) stfd 17, (-4 * 8)(1) stfd 18, (-5 * 8)(1) stfd 19, (-6 * 8)(1) stfd 20, (-7 * 8)(1) stfd 21, (-8 * 8)(1) stfd 22, (-9 * 8)(1) stfd 23, (-10 * 8)(1) stfd 24, (-11 * 8)(1) stfd 25, (-12 * 8)(1) stfd 26, (-13 * 8)(1) stfd 27, (-14 * 8)(1) stfd 28, (-15 * 8)(1) stfd 29, (-16 * 8)(1) stfd 30, (-17 * 8)(1) stfd 31, (-18 * 8)(1) /* Update the old stack pointer */ stw 1, 0(3) /* Set new stack pointer */ addi 1, 4, 20 * 4 /* Restore linkage area */ lwz 0, 8(1) lwz 5, 4(1) /* Restore GPRs */ lwz 11, (-1 * 4)(1) lwz 13, (-2 * 4)(1) lwz 14, (-3 * 4)(1) lwz 15, (-4 * 4)(1) lwz 16, (-5 * 4)(1) lwz 17, (-6 * 4)(1) lwz 18, (-7 * 4)(1) lwz 19, (-8 * 4)(1) lwz 20, (-9 * 4)(1) lwz 21, (-10 * 4)(1) lwz 22, (-11 * 4)(1) lwz 23, (-12 * 4)(1) lwz 24, (-13 * 4)(1) lwz 25, (-14 * 4)(1) lwz 26, (-15 * 4)(1) lwz 27, (-16 * 4)(1) lwz 28, (-17 * 4)(1) lwz 29, (-18 * 4)(1) lwz 30, (-19 * 4)(1) lwz 31, (-20 * 4)(1) /* Restore FPRs */ lfd 14, (-1 * 8)(4) lfd 15, (-2 * 8)(4) lfd 16, (-3 * 8)(4) lfd 17, (-4 * 8)(4) lfd 18, (-5 * 8)(4) lfd 19, (-6 * 8)(4) lfd 20, (-7 * 8)(4) lfd 21, (-8 * 8)(4) lfd 22, (-9 * 8)(4) lfd 23, (-10 * 8)(4) lfd 24, (-11 * 8)(4) lfd 25, (-12 * 8)(4) lfd 26, (-13 * 8)(4) lfd 27, (-14 * 8)(4) lfd 28, (-15 * 8)(4) lfd 29, (-16 * 8)(4) lfd 30, (-17 * 8)(4) lfd 31, (-18 * 8)(4) /* Set condition and link register */ mtcr 5 mtlr 0 /* Return and switch context */ blr .size fiber_switchContext,.-fiber_switchContext #elif defined(__mips__) && _MIPS_SIM == _ABIO32 /************************************************************************************ * MIPS ASM BITS ************************************************************************************/ /** * Performs a context switch. * * $a0 - void** - ptr to old stack pointer * $a1 - void* - new stack pointer * */ .text .globl fiber_switchContext fiber_switchContext: addiu $sp, $sp, -(10 * 4) // fp regs and return address are stored below the stack // because we don't want the GC to scan them. #ifdef __mips_hard_float #define ALIGN8(val) (val + (-val & 7)) #define BELOW (ALIGN8(6 * 8 + 4)) sdcl $f20, (0 * 8 - BELOW)($sp) sdcl $f22, (1 * 8 - BELOW)($sp) sdcl $f24, (2 * 8 - BELOW)($sp) sdcl $f26, (3 * 8 - BELOW)($sp) sdcl $f28, (4 * 8 - BELOW)($sp) sdcl $f30, (5 * 8 - BELOW)($sp) #endif sw $ra, -4($sp) sw $s0, (0 * 4)($sp) sw $s1, (1 * 4)($sp) sw $s2, (2 * 4)($sp) sw $s3, (3 * 4)($sp) sw $s4, (4 * 4)($sp) sw $s5, (5 * 4)($sp) sw $s6, (6 * 4)($sp) sw $s7, (7 * 4)($sp) sw $s8, (8 * 4)($sp) sw $gp, (9 * 4)($sp) // swap stack pointer sw $sp, 0($a0) move $sp, $a1 #ifdef __mips_hard_float ldcl $f20, (0 * 8 - BELOW)($sp) ldcl $f22, (1 * 8 - BELOW)($sp) ldcl $f24, (2 * 8 - BELOW)($sp) ldcl $f26, (3 * 8 - BELOW)($sp) ldcl $f28, (4 * 8 - BELOW)($sp) ldcl $f30, (5 * 8 - BELOW)($sp) #endif lw $ra, -4($sp) lw $s0, (0 * 4)($sp) lw $s1, (1 * 4)($sp) lw $s2, (2 * 4)($sp) lw $s3, (3 * 4)($sp) lw $s4, (4 * 4)($sp) lw $s5, (5 * 4)($sp) lw $s6, (6 * 4)($sp) lw $s7, (7 * 4)($sp) lw $s8, (8 * 4)($sp) lw $gp, (9 * 4)($sp) addiu $sp, $sp, (10 * 4) jr $ra // return #elif defined(__arm__) && defined(__ARM_EABI__) /************************************************************************************ * ARM ASM BITS ************************************************************************************/ /** * Performs a context switch. * * Parameters: * r0 - void** - ptr to old stack pointer * r1 - void* - new stack pointer * * ARM EABI registers: * r0-r3 : argument/scratch registers * r4-r10 : callee-save registers * r11 : frame pointer (or a callee save register if fp isn't needed) * r12 =ip : inter procedure register. We can treat it like any other scratch register * r13 =sp : stack pointer * r14 =lr : link register, it contains the return address (belonging to the function which called us) * r15 =pc : program counter * * For floating point registers: * According to AAPCS (version 2.09, section 5.1.2) only the d8-d15 registers need to be preserved * across method calls. This applies to all ARM FPU variants, whether they have 16 or 32 double registers * NEON support or not, half-float support or not and so on does not matter. * * Note: If this file was compiled with -mfloat-abi=soft but the code runs on a softfp system with fpu the d8-d15 * registers won't be saved (we do not know that the system has got a fpu in that case) but the registers might actually * be used by other code if it was compiled with -mfloat-abi=softfp. * * Interworking is only supported on ARMv5+, not on ARM v4T as ARM v4t requires special stubs when changing * from thumb to arm mode or the other way round. */ .text .align 2 .global fiber_switchContext .type fiber_switchContext, %function fiber_switchContext: .fnstart push {r4-r11} // update the oldp pointer. Link register and floating point registers stored later to prevent the GC from // scanning them. str sp, [r0] // push r0 (or any other register) as well to keep stack 8byte aligned push {r0, lr} #if defined(__ARM_PCS_VFP) || (defined(__ARM_PCS) && !defined(__SOFTFP__)) // ARM_HardFloat || ARM_SoftFP vpush {d8-d15} // now switch over to the new stack. Need to subtract (8*8[d8-d15]+2*4[r0, lr]) to position stack pointer // below the last saved register. Remember we saved the SP before pushing [r0, lr, d8-d15] sub sp, r1, #72 vpop {d8-d15} #else sub sp, r1, #8 #endif // we don't really care about r0, we only used that for padding. // r1 is now what used to be in the link register when saving. pop {r0, r1, r4-r11} /** * The link register for the initial jump to fiber_entryPoint must be zero: The jump actually * looks like a normal method call as we jump to the start of the fiber_entryPoint function. * Although fiber_entryPoint never returns and therefore never accesses lr, it saves lr to the stack. * ARM unwinding will then look at the stack, find lr and think that fiber_entryPoint was called by * the function in lr! So if we have some address in lr the unwinder will try to continue stack unwinding, * although it's already at the stack base and crash. * In all other cases the content of lr doesn't matter. * Note: If we simply loaded into lr above and then moved lr into pc, the initial method call * to fiber_entryPoint would look as if it was called from fiber_entryPoint itself, as the fiber_entryPoint * address is in lr on the initial context switch. */ mov lr, #0 // return by writing lr into pc mov pc, r1 .fnend #elif defined(__aarch64__) /************************************************************************************ * AArch64 (arm64) ASM BITS ************************************************************************************/ /** * preserve/restore AAPCS64 registers * x19-x28 5.1.1 64-bit callee saved * x29 fp, or possibly callee saved reg - depends on platform choice 5.2.3) * x30 lr * d8-d15 5.1.2 says callee only must save bottom 64-bits (the "d" regs) * * saved regs on stack will look like: * 19: x19 * 18: x20 * ... * 10: x28 * 9: x29 (fp) <-- oldp / *newp save stack top * 8: x30 (lr) * 7: d8 * ... * 0: d15 <-- sp */ .text .global CSYM(fiber_switchContext) .p2align 2 CSYM(fiber_switchContext): stp d15, d14, [sp, #-20*8]! stp d13, d12, [sp, #2*8] stp d11, d10, [sp, #4*8] stp d9, d8, [sp, #6*8] stp x30, x29, [sp, #8*8] // lr, fp stp x28, x27, [sp, #10*8] stp x26, x25, [sp, #12*8] stp x24, x23, [sp, #14*8] stp x22, x21, [sp, #16*8] stp x20, x19, [sp, #18*8] // oldp is set above saved lr (x30) to hide it and float regs // from GC add x19, sp, #9*8 str x19, [x0] // *oldp tstack sub sp, x1, #9*8 // switch to newp sp ldp x20, x19, [sp, #18*8] ldp x22, x21, [sp, #16*8] ldp x24, x23, [sp, #14*8] ldp x26, x25, [sp, #12*8] ldp x28, x27, [sp, #10*8] ldp x30, x29, [sp, #8*8] // lr, fp ldp d9, d8, [sp, #6*8] ldp d11, d10, [sp, #4*8] ldp d13, d12, [sp, #2*8] ldp d15, d14, [sp], #20*8 ret #endif ldc-1.1.0-beta3-src/runtime/druntime/src/core/runtime.d0000664000175000017500000006001512776214756021034 0ustar kaikai/** * The runtime module exposes information specific to the D runtime code. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/_runtime.d) */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.runtime; version (Windows) import core.stdc.wchar_ : wchar_t; /// C interface for Runtime.loadLibrary extern (C) void* rt_loadLibrary(const char* name); /// ditto version (Windows) extern (C) void* rt_loadLibraryW(const wchar_t* name); /// C interface for Runtime.unloadLibrary, returns 1/0 instead of bool extern (C) int rt_unloadLibrary(void* ptr); /// C interface for Runtime.initialize, returns 1/0 instead of bool extern(C) int rt_init(); /// C interface for Runtime.terminate, returns 1/0 instead of bool extern(C) int rt_term(); private { alias bool function() ModuleUnitTester; alias bool function(Object) CollectHandler; alias Throwable.TraceInfo function( void* ptr ) TraceHandler; extern (C) void rt_setCollectHandler( CollectHandler h ); extern (C) CollectHandler rt_getCollectHandler(); extern (C) void rt_setTraceHandler( TraceHandler h ); extern (C) TraceHandler rt_getTraceHandler(); alias void delegate( Throwable ) ExceptionHandler; extern (C) void _d_print_throwable(Throwable t); extern (C) void* thread_stackBottom(); extern (C) string[] rt_args(); extern (C) CArgs rt_cArgs() @nogc; } static this() { // NOTE: Some module ctors will run before this handler is set, so it's // still possible the app could exit without a stack trace. If // this becomes an issue, the handler could be set in C main // before the module ctors are run. Runtime.traceHandler = &defaultTraceHandler; } /////////////////////////////////////////////////////////////////////////////// // Runtime /////////////////////////////////////////////////////////////////////////////// /** * Stores the unprocessed arguments supplied when the * process was started. */ struct CArgs { int argc; /// The argument count. char** argv; /// The arguments as a C array of strings. } /** * This struct encapsulates all functionality related to the underlying runtime * module for the calling context. */ struct Runtime { /** * Initializes the runtime. This call is to be used in instances where the * standard program initialization process is not executed. This is most * often in shared libraries or in libraries linked to a C program. * If the runtime was already successfully initialized this returns true. * Each call to initialize must be paired by a call to $(LREF terminate). * * Returns: * true if initialization succeeded or false if initialization failed. */ static bool initialize() { return !!rt_init(); } deprecated("Please use the overload of Runtime.initialize that takes no argument.") static bool initialize(ExceptionHandler dg = null) { return !!rt_init(); } /** * Terminates the runtime. This call is to be used in instances where the * standard program termination process will not be not executed. This is * most often in shared libraries or in libraries linked to a C program. * If the runtime was not successfully initialized the function returns false. * * Returns: * true if termination succeeded or false if termination failed. */ static bool terminate() { return !!rt_term(); } deprecated("Please use the overload of Runtime.terminate that takes no argument.") static bool terminate(ExceptionHandler dg = null) { return !!rt_term(); } /** * Returns the arguments supplied when the process was started. * * Returns: * The arguments supplied when this process was started. */ static @property string[] args() { return rt_args(); } /** * Returns the unprocessed C arguments supplied when the process was started. * Use this when you need to supply argc and argv to C libraries. * * Returns: * A $(LREF CArgs) struct with the arguments supplied when this process was started. * * Example: * --- * import core.runtime; * * // A C library function requiring char** arguments * extern(C) void initLibFoo(int argc, char** argv); * * void main() * { * auto args = Runtime.cArgs; * initLibFoo(args.argc, args.argv); * } * --- */ static @property CArgs cArgs() @nogc { return rt_cArgs(); } /** * Locates a dynamic library with the supplied library name and dynamically * loads it into the caller's address space. If the library contains a D * runtime it will be integrated with the current runtime. * * Params: * name = The name of the dynamic library to load. * * Returns: * A reference to the library or null on error. */ static void* loadLibrary()(in char[] name) { import core.stdc.stdlib : free, malloc; version (Windows) { import core.sys.windows.windows; if (name.length == 0) return null; // Load a DLL at runtime auto len = MultiByteToWideChar( CP_UTF8, 0, name.ptr, cast(int)name.length, null, 0); if (len == 0) return null; auto buf = cast(wchar_t*)malloc((len+1) * wchar_t.sizeof); if (buf is null) return null; scope (exit) free(buf); len = MultiByteToWideChar( CP_UTF8, 0, name.ptr, cast(int)name.length, buf, len); if (len == 0) return null; buf[len] = '\0'; return rt_loadLibraryW(buf); } else version (Posix) { /* Need a 0-terminated C string for the dll name */ immutable len = name.length; auto buf = cast(char*)malloc(len + 1); if (!buf) return null; scope (exit) free(buf); buf[0 .. len] = name[]; buf[len] = 0; return rt_loadLibrary(buf); } } /** * Unloads the dynamic library referenced by p. If this library contains a * D runtime then any necessary finalization or cleanup of that runtime * will be performed. * * Params: * p = A reference to the library to unload. */ static bool unloadLibrary()(void* p) { return !!rt_unloadLibrary(p); } /** * Overrides the default trace mechanism with a user-supplied version. A * trace represents the context from which an exception was thrown, and the * trace handler will be called when this occurs. The pointer supplied to * this routine indicates the base address from which tracing should occur. * If the supplied pointer is null then the trace routine should determine * an appropriate calling context from which to begin the trace. * * Params: * h = The new trace handler. Set to null to use the default handler. */ static @property void traceHandler( TraceHandler h ) { rt_setTraceHandler( h ); } /** * Gets the current trace handler. * * Returns: * The current trace handler or null if none has been set. */ static @property TraceHandler traceHandler() { return rt_getTraceHandler(); } /** * Overrides the default collect hander with a user-supplied version. This * routine will be called for each resource object that is finalized in a * non-deterministic manner--typically during a garbage collection cycle. * If the supplied routine returns true then the object's dtor will called * as normal, but if the routine returns false than the dtor will not be * called. The default behavior is for all object dtors to be called. * * Params: * h = The new collect handler. Set to null to use the default handler. */ static @property void collectHandler( CollectHandler h ) { rt_setCollectHandler( h ); } /** * Gets the current collect handler. * * Returns: * The current collect handler or null if none has been set. */ static @property CollectHandler collectHandler() { return rt_getCollectHandler(); } /** * Overrides the default module unit tester with a user-supplied version. * This routine will be called once on program initialization. The return * value of this routine indicates to the runtime whether the tests ran * without error. * * Params: * h = The new unit tester. Set to null to use the default unit tester. */ static @property void moduleUnitTester( ModuleUnitTester h ) { sm_moduleUnitTester = h; } /** * Gets the current module unit tester. * * Returns: * The current module unit tester handler or null if none has been set. */ static @property ModuleUnitTester moduleUnitTester() { return sm_moduleUnitTester; } private: // NOTE: This field will only ever be set in a static ctor and should // never occur within any but the main thread, so it is safe to // make it __gshared. __gshared ModuleUnitTester sm_moduleUnitTester = null; } /** * Set source file path for coverage reports. * * Params: * path = The new path name. * Note: * This is a dmd specific setting. */ extern (C) void dmd_coverSourcePath(string path); /** * Set output path for coverage reports. * * Params: * path = The new path name. * Note: * This is a dmd specific setting. */ extern (C) void dmd_coverDestPath(string path); /** * Enable merging of coverage reports with existing data. * * Params: * flag = enable/disable coverage merge mode * Note: * This is a dmd specific setting. */ extern (C) void dmd_coverSetMerge(bool flag); /** * Set the output file name for profile reports (-profile switch). * An empty name will set the output to stdout. * * Params: * name = file name * Note: * This is a dmd specific setting. */ extern (C) void trace_setlogfilename(string name); /** * Set the output file name for the optimized profile linker DEF file (-profile switch). * An empty name will set the output to stdout. * * Params: * name = file name * Note: * This is a dmd specific setting. */ extern (C) void trace_setdeffilename(string name); /** * Set the output file name for memory profile reports (-profile=gc switch). * An empty name will set the output to stdout. * * Params: * name = file name * Note: * This is a dmd specific setting. */ extern (C) void profilegc_setlogfilename(string name); /////////////////////////////////////////////////////////////////////////////// // 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() { // backtrace version( CRuntime_Glibc ) import core.sys.linux.execinfo; else version( OSX ) import core.sys.osx.execinfo; else version( FreeBSD ) import core.sys.freebsd.execinfo; else version( Windows ) import core.sys.windows.stacktrace; else version( Solaris ) import core.sys.solaris.execinfo; static if( __traits( compiles, backtrace ) ) { import core.sys.posix.signal; // segv handler static extern (C) void unittestSegvHandler( int signum, siginfo_t* info, void* ptr ) nothrow { static enum MAXFRAMES = 128; void*[MAXFRAMES] callstack; int numframes; numframes = backtrace( callstack.ptr, MAXFRAMES ); backtrace_symbols_fd( callstack.ptr, numframes, 2 ); } sigaction_t action = void; sigaction_t oldseg = void; sigaction_t oldbus = void; (cast(byte*) &action)[0 .. action.sizeof] = 0; sigfillset( &action.sa_mask ); // block other signals action.sa_flags = SA_SIGINFO | SA_RESETHAND; action.sa_sigaction = &unittestSegvHandler; sigaction( SIGSEGV, &action, &oldseg ); sigaction( SIGBUS, &action, &oldbus ); scope( exit ) { sigaction( SIGSEGV, &oldseg, null ); sigaction( SIGBUS, &oldbus, null ); } } if( Runtime.sm_moduleUnitTester is null ) { size_t failed = 0; foreach( m; ModuleInfo ) { if( m ) { auto fp = m.unitTest; if( fp ) { try { fp(); } catch( Throwable e ) { _d_print_throwable(e); failed++; } } } } return failed == 0; } return Runtime.sm_moduleUnitTester(); } /////////////////////////////////////////////////////////////////////////////// // Default Implementations /////////////////////////////////////////////////////////////////////////////// /** * */ Throwable.TraceInfo defaultTraceHandler( void* ptr = null ) { // backtrace version( CRuntime_Glibc ) import core.sys.linux.execinfo; else version( OSX ) import core.sys.osx.execinfo; else version( FreeBSD ) import core.sys.freebsd.execinfo; else version( Windows ) import core.sys.windows.stacktrace; else version( Solaris ) import core.sys.solaris.execinfo; // avoid recursive GC calls in finalizer, trace handlers should be made @nogc instead import core.memory : gc_inFinalizer; if (gc_inFinalizer) return null; //printf("runtime.defaultTraceHandler()\n"); static if( __traits( compiles, backtrace ) ) { import core.demangle; import core.stdc.stdlib : free; import core.stdc.string : strlen, memchr, memmove; class DefaultTraceInfo : Throwable.TraceInfo { this() { numframes = 0; //backtrace( callstack, MAXFRAMES ); if (numframes < 2) // backtrace() failed, do it ourselves { static void** getBasePtr() { version( D_InlineAsm_X86 ) asm { naked; mov EAX, EBP; ret; } else version( D_InlineAsm_X86_64 ) asm { naked; mov RAX, RBP; ret; } else return null; } auto stackTop = getBasePtr(); auto stackBottom = cast(void**) thread_stackBottom(); void* dummy; if( stackTop && &dummy < stackTop && stackTop < stackBottom ) { auto stackPtr = stackTop; for( numframes = 0; stackTop <= stackPtr && stackPtr < stackBottom && numframes < MAXFRAMES; ) { enum CALL_INSTRUCTION_SIZE = 1; // it may not be 1 but it is good enough to get // in CALL instruction address range for backtrace callstack[numframes++] = *(stackPtr + 1) - CALL_INSTRUCTION_SIZE; stackPtr = cast(void**) *stackPtr; } } } } override int opApply( scope int delegate(ref const(char[])) dg ) const { return opApply( (ref size_t, ref const(char[]) buf) { return dg( buf ); } ); } override int opApply( scope int delegate(ref size_t, ref const(char[])) dg ) const { version(Posix) { // NOTE: The first 4 frames with the current implementation are // inside core.runtime and the object code, so eliminate // these for readability. The alternative would be to // exclude the first N frames that are in a list of // mangled function names. enum FIRSTFRAME = 4; } else version(Windows) { // NOTE: On Windows, the number of frames to exclude is based on // whether the exception is user or system-generated, so // it may be necessary to exclude a list of function names // instead. enum FIRSTFRAME = 0; } version(linux) enum enableDwarf = true; else version(FreeBSD) enum enableDwarf = true; else enum enableDwarf = false; static if (enableDwarf) { import core.internal.traits : externDFunc; alias traceHandlerOpApplyImpl = externDFunc!( "rt.backtrace.dwarf.traceHandlerOpApplyImpl", int function(const void*[], scope int delegate(ref size_t, ref const(char[]))) ); if (numframes >= FIRSTFRAME) { return traceHandlerOpApplyImpl( callstack[FIRSTFRAME .. numframes], dg ); } else { return 0; } } else { const framelist = backtrace_symbols( callstack.ptr, numframes ); scope(exit) free(cast(void*) framelist); int ret = 0; for( int i = FIRSTFRAME; i < numframes; ++i ) { char[4096] fixbuf; auto buf = framelist[i][0 .. strlen(framelist[i])]; auto pos = cast(size_t)(i - FIRSTFRAME); buf = fixline( buf, fixbuf ); ret = dg( pos, buf ); if( ret ) break; } return ret; } } override string toString() const { string buf; foreach( i, line; this ) buf ~= i ? "\n" ~ line : line; return buf; } private: int numframes; static enum MAXFRAMES = 128; void*[MAXFRAMES] callstack = void; private: const(char)[] fixline( const(char)[] buf, return ref char[4096] fixbuf ) const { size_t symBeg, symEnd; version( OSX ) { // format is: // 1 module 0x00000000 D6module4funcAFZv + 0 for( size_t i = 0, n = 0; i < buf.length; i++ ) { if( ' ' == buf[i] ) { n++; while( i < buf.length && ' ' == buf[i] ) i++; if( 3 > n ) continue; symBeg = i; while( i < buf.length && ' ' != buf[i] ) i++; symEnd = i; break; } } } else version( CRuntime_Glibc ) { // format is: module(_D6module4funcAFZv) [0x00000000] // or: module(_D6module4funcAFZv+0x78) [0x00000000] auto bptr = cast(char*) memchr( buf.ptr, '(', buf.length ); auto eptr = cast(char*) memchr( buf.ptr, ')', buf.length ); auto pptr = cast(char*) memchr( buf.ptr, '+', buf.length ); if (pptr && pptr < eptr) eptr = pptr; if( bptr++ && eptr ) { symBeg = bptr - buf.ptr; symEnd = eptr - buf.ptr; } } else version( FreeBSD ) { // format is: 0x00000000 <_D6module4funcAFZv+0x78> at module auto bptr = cast(char*) memchr( buf.ptr, '<', buf.length ); auto eptr = cast(char*) memchr( buf.ptr, '+', buf.length ); if( bptr++ && eptr ) { symBeg = bptr - buf.ptr; symEnd = eptr - buf.ptr; } } else version( Solaris ) { // format is object'symbol+offset [pc] auto bptr = cast(char*) memchr( buf.ptr, '\'', buf.length ); auto eptr = cast(char*) memchr( buf.ptr, '+', buf.length ); if( bptr++ && eptr ) { symBeg = bptr - buf.ptr; symEnd = eptr - buf.ptr; } } else { // fallthrough } assert(symBeg < buf.length && symEnd < buf.length); assert(symBeg <= symEnd); enum min = (size_t a, size_t b) => a <= b ? a : b; if (symBeg == symEnd || symBeg >= fixbuf.length) { immutable len = min(buf.length, fixbuf.length); fixbuf[0 .. len] = buf[0 .. len]; return fixbuf[0 .. len]; } else { fixbuf[0 .. symBeg] = buf[0 .. symBeg]; auto sym = demangle(buf[symBeg .. symEnd], fixbuf[symBeg .. $]); if (sym.ptr !is fixbuf.ptr + symBeg) { // demangle reallocated the buffer, copy the symbol to fixbuf immutable len = min(fixbuf.length - symBeg, sym.length); memmove(fixbuf.ptr + symBeg, sym.ptr, len); if (symBeg + len == fixbuf.length) return fixbuf[]; } immutable pos = symBeg + sym.length; assert(pos < fixbuf.length); immutable tail = buf.length - symEnd; immutable len = min(fixbuf.length - pos, tail); fixbuf[pos .. pos + len] = buf[symEnd .. symEnd + len]; return fixbuf[0 .. pos + len]; } } } return new DefaultTraceInfo; } else static if( __traits( compiles, new StackTrace(0, null) ) ) { version (Win64) { static enum FIRSTFRAME = 4; } else version (Win32) { static enum FIRSTFRAME = 0; } import core.sys.windows.windows : CONTEXT; auto s = new StackTrace(FIRSTFRAME, cast(CONTEXT*)ptr); return s; } else { return null; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdcpp/0000775000175000017500000000000012776214756020477 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/stdcpp/typeinfo.d0000664000175000017500000001000612776214756022476 0ustar kaikai// Written in the D programming language. /** * Interface to C++ * * Copyright: Copyright (c) 2016 D Language Foundation * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * Source: $(DRUNTIMESRC core/stdcpp/_typeinfo.d) */ module core.stdcpp.typeinfo; version (CRuntime_DigitalMars) { import core.stdcpp.exception; extern (C++, std) { class type_info { void* pdata; public: //virtual ~this(); void dtor() { } // reserve slot in vtbl[] //bool operator==(const type_info rhs) const; //bool operator!=(const type_info rhs) const; final bool before(const type_info rhs) const; final const(char)* name() const; protected: //type_info(); private: //this(const type_info rhs); //type_info operator=(const type_info rhs); } class bad_cast : core.stdcpp.exception.std.exception { this() nothrow { } this(const bad_cast) nothrow { } //bad_cast operator=(const bad_cast) nothrow { return this; } //virtual ~this() nothrow; override const(char)* what() const nothrow; } class bad_typeid : core.stdcpp.exception.std.exception { this() nothrow { } this(const bad_typeid) nothrow { } //bad_typeid operator=(const bad_typeid) nothrow { return this; } //virtual ~this() nothrow; override const (char)* what() const nothrow; } } } else version (CRuntime_Microsoft) { import core.stdcpp.exception; struct __type_info_node { void* _MemPtr; __type_info_node* _Next; } extern __gshared __type_info_node __type_info_root_node; extern (C++, std) { class type_info { public: //virtual ~this(); void dtor() { } // reserve slot in vtbl[] //bool operator==(const type_info rhs) const; //bool operator!=(const type_info rhs) const; final bool before(const type_info rhs) const; final const(char)* name(__type_info_node* p = &__type_info_root_node) const; private: void* pdata; char _name[1]; //this(const type_info rhs); //type_info operator=(const type_info rhs); } class bad_cast : core.stdcpp.exception.std.exception { this(const(char)* msg = "bad cast") { } this(const bad_cast) { } //virtual ~this(); } class bad_typeid : core.stdcpp.exception.std.exception { this(const(char)* msg = "bad typeid") { } this(const bad_typeid) { } //virtual ~this(); } } } else version (CRuntime_Glibc) { import core.stdcpp.exception; extern (C++, __cxxabiv1) { class __class_type_info; } extern (C++, std) { class type_info { void dtor1(); // consume destructor slot in vtbl[] void dtor2(); // consume destructor slot in vtbl[] final const(char)* name(); final bool before(const type_info) const; //bool operator==(const type_info) const; bool __is_pointer_p() const; bool __is_function_p() const; bool __do_catch(const type_info, void**, uint) const; bool __do_upcast(const __cxxabiv1.__class_type_info, void**) const; const(char)* _name; this(const(char)*); } class bad_cast : core.stdcpp.exception.std.exception { this(); //~this(); const(char)* what() const; } class bad_typeid : core.stdcpp.exception.std.exception { this(); //~this(); const(char)* what() const; } } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/stdcpp/exception.d0000664000175000017500000000527112776214756022647 0ustar kaikai// Written in the D programming language. /** * Interface to C++ * * Copyright: Copyright (c) 2016 D Language Foundation * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright) * Source: $(DRUNTIMESRC core/stdcpp/_exception.d) */ module core.stdcpp.exception; version (CRuntime_DigitalMars) { import core.stdcpp.typeinfo; extern (C++, std) { alias void function() unexpected_handler; unexpected_handler set_unexpected(unexpected_handler f) nothrow; void unexpected(); alias void function() terminate_handler; terminate_handler set_terminate(terminate_handler f) nothrow; void terminate(); bool uncaught_exception(); class exception { this() nothrow { } this(const exception) nothrow { } //exception operator=(const exception) nothrow { return this; } //virtual ~this() nothrow; void dtor() { } const(char)* what() const nothrow; } class bad_exception : exception { this() nothrow { } this(const bad_exception) nothrow { } //bad_exception operator=(const bad_exception) nothrow { return this; } //virtual ~this() nothrow; override const(char)* what() const nothrow; } } } else version (CRuntime_Glibc) { extern (C++, std) { alias void function() unexpected_handler; unexpected_handler set_unexpected(unexpected_handler f) nothrow; void unexpected(); alias void function() terminate_handler; terminate_handler set_terminate(terminate_handler f) nothrow; void terminate(); void unexpected(); pure bool uncaught_exception(); class exception { this(); //virtual ~this(); void dtor1(); void dtor2(); const(char)* what() const; } class bad_exception : exception { this(); //virtual ~this(); const(char)* what() const; } } } else version (CRuntime_Microsoft) { extern (C++, std) { class exception { this(); this(const exception); //exception operator=(const exception) { return this; } //virtual ~this(); void dtor() { } const(char)* what() const; private: const(char)* mywhat; bool dofree; } class bad_exception : exception { this(const(char)* msg = "bad exception"); //virtual ~this(); } } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/simd.d0000664000175000017500000002773612776214756020322 0ustar kaikai// Written in the D programming language. /** * Builtin SIMD intrinsics * * Source: $(DRUNTIMESRC core/_simd.d) * * Copyright: Copyright Digital Mars 2012. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright), */ module core.simd; pure: nothrow: @safe: @nogc: /******************************* * Create a vector type. * * Parameters: * T = one of double[2], float[4], void[16], byte[16], ubyte[16], * short[8], ushort[8], int[4], uint[4], long[2], ulong[2]. * For 256 bit vectors, * one of double[4], float[8], void[32], byte[32], ubyte[32], * short[16], ushort[16], int[8], uint[8], long[4], ulong[4] */ template Vector(T) { /* __vector is compiler magic, hide it behind a template. * The compiler will reject T's that don't work. */ alias __vector(T) Vector; } /* Handy aliases */ static if (is(Vector!(void[16]))) alias Vector!(void[16]) void16; /// static if (is(Vector!(double[2]))) alias Vector!(double[2]) double2; /// static if (is(Vector!(float[4]))) alias Vector!(float[4]) float4; /// static if (is(Vector!(byte[16]))) alias Vector!(byte[16]) byte16; /// static if (is(Vector!(ubyte[16]))) alias Vector!(ubyte[16]) ubyte16; /// static if (is(Vector!(short[8]))) alias Vector!(short[8]) short8; /// static if (is(Vector!(ushort[8]))) alias Vector!(ushort[8]) ushort8; /// static if (is(Vector!(int[4]))) alias Vector!(int[4]) int4; /// static if (is(Vector!(uint[4]))) alias Vector!(uint[4]) uint4; /// static if (is(Vector!(long[2]))) alias Vector!(long[2]) long2; /// static if (is(Vector!(ulong[2]))) alias Vector!(ulong[2]) ulong2; /// static if (is(Vector!(void[32]))) alias Vector!(void[32]) void32; /// static if (is(Vector!(double[4]))) alias Vector!(double[4]) double4; /// static if (is(Vector!(float[8]))) alias Vector!(float[8]) float8; /// static if (is(Vector!(byte[32]))) alias Vector!(byte[32]) byte32; /// static if (is(Vector!(ubyte[32]))) alias Vector!(ubyte[32]) ubyte32; /// static if (is(Vector!(short[16]))) alias Vector!(short[16]) short16; /// static if (is(Vector!(ushort[16]))) alias Vector!(ushort[16]) ushort16; /// static if (is(Vector!(int[8]))) alias Vector!(int[8]) int8; /// static if (is(Vector!(uint[8]))) alias Vector!(uint[8]) uint8; /// static if (is(Vector!(long[4]))) alias Vector!(long[4]) long4; /// static if (is(Vector!(ulong[4]))) alias Vector!(ulong[4]) ulong4; /// version ( D_SIMD ) { /** XMM opcodes that conform to the following: * * opcode xmm1,xmm2/mem * * and do not have side effects (i.e. do not write to memory). */ enum XMM { ADDSS = 0xF30F58, ADDSD = 0xF20F58, ADDPS = 0x000F58, ADDPD = 0x660F58, PADDB = 0x660FFC, PADDW = 0x660FFD, PADDD = 0x660FFE, PADDQ = 0x660FD4, SUBSS = 0xF30F5C, SUBSD = 0xF20F5C, SUBPS = 0x000F5C, SUBPD = 0x660F5C, PSUBB = 0x660FF8, PSUBW = 0x660FF9, PSUBD = 0x660FFA, PSUBQ = 0x660FFB, MULSS = 0xF30F59, MULSD = 0xF20F59, MULPS = 0x000F59, MULPD = 0x660F59, PMULLW = 0x660FD5, DIVSS = 0xF30F5E, DIVSD = 0xF20F5E, DIVPS = 0x000F5E, DIVPD = 0x660F5E, PAND = 0x660FDB, POR = 0x660FEB, UCOMISS = 0x000F2E, UCOMISD = 0x660F2E, XORPS = 0x000F57, XORPD = 0x660F57, // Use STO and LOD instead of MOV to distinguish the direction STOSS = 0xF30F11, STOSD = 0xF20F11, STOAPS = 0x000F29, STOAPD = 0x660F29, STODQA = 0x660F7F, STOD = 0x660F7E, // MOVD reg/mem64, xmm 66 0F 7E /r STOQ = 0x660FD6, LODSS = 0xF30F10, LODSD = 0xF20F10, LODAPS = 0x000F28, LODAPD = 0x660F28, LODDQA = 0x660F6F, LODD = 0x660F6E, // MOVD xmm, reg/mem64 66 0F 6E /r LODQ = 0xF30F7E, LODDQU = 0xF30F6F, // MOVDQU xmm1, xmm2/mem128 F3 0F 6F /r STODQU = 0xF30F7F, // MOVDQU xmm1/mem128, xmm2 F3 0F 7F /r MOVDQ2Q = 0xF20FD6, // MOVDQ2Q mmx, xmm F2 0F D6 /r MOVHLPS = 0x0F12, // MOVHLPS xmm1, xmm2 0F 12 /r LODHPD = 0x660F16, STOHPD = 0x660F17, // MOVHPD mem64, xmm 66 0F 17 /r LODHPS = 0x0F16, STOHPS = 0x0F17, MOVLHPS = 0x0F16, LODLPD = 0x660F12, STOLPD = 0x660F13, LODLPS = 0x0F12, STOLPS = 0x0F13, MOVMSKPD = 0x660F50, MOVMSKPS = 0x0F50, MOVNTDQ = 0x660FE7, MOVNTI = 0x0FC3, MOVNTPD = 0x660F2B, MOVNTPS = 0x0F2B, MOVNTQ = 0x0FE7, MOVQ2DQ = 0xF30FD6, LODUPD = 0x660F10, STOUPD = 0x660F11, LODUPS = 0x0F10, STOUPS = 0x0F11, PACKSSDW = 0x660F6B, PACKSSWB = 0x660F63, PACKUSWB = 0x660F67, PADDSB = 0x660FEC, PADDSW = 0x660FED, PADDUSB = 0x660FDC, PADDUSW = 0x660FDD, PANDN = 0x660FDF, PCMPEQB = 0x660F74, PCMPEQD = 0x660F76, PCMPEQW = 0x660F75, PCMPGTB = 0x660F64, PCMPGTD = 0x660F66, PCMPGTW = 0x660F65, PMADDWD = 0x660FF5, PSLLW = 0x660FF1, PSLLD = 0x660FF2, PSLLQ = 0x660FF3, PSRAW = 0x660FE1, PSRAD = 0x660FE2, PSRLW = 0x660FD1, PSRLD = 0x660FD2, PSRLQ = 0x660FD3, PSUBSB = 0x660FE8, PSUBSW = 0x660FE9, PSUBUSB = 0x660FD8, PSUBUSW = 0x660FD9, PUNPCKHBW = 0x660F68, PUNPCKHDQ = 0x660F6A, PUNPCKHWD = 0x660F69, PUNPCKLBW = 0x660F60, PUNPCKLDQ = 0x660F62, PUNPCKLWD = 0x660F61, PXOR = 0x660FEF, ANDPD = 0x660F54, ANDPS = 0x0F54, ANDNPD = 0x660F55, ANDNPS = 0x0F55, CMPPS = 0x0FC2, CMPPD = 0x660FC2, CMPSD = 0xF20FC2, CMPSS = 0xF30FC2, COMISD = 0x660F2F, COMISS = 0x0F2F, CVTDQ2PD = 0xF30FE6, CVTDQ2PS = 0x0F5B, CVTPD2DQ = 0xF20FE6, CVTPD2PI = 0x660F2D, CVTPD2PS = 0x660F5A, CVTPI2PD = 0x660F2A, CVTPI2PS = 0x0F2A, CVTPS2DQ = 0x660F5B, CVTPS2PD = 0x0F5A, CVTPS2PI = 0x0F2D, CVTSD2SI = 0xF20F2D, CVTSD2SS = 0xF20F5A, CVTSI2SD = 0xF20F2A, CVTSI2SS = 0xF30F2A, CVTSS2SD = 0xF30F5A, CVTSS2SI = 0xF30F2D, CVTTPD2PI = 0x660F2C, CVTTPD2DQ = 0x660FE6, CVTTPS2DQ = 0xF30F5B, CVTTPS2PI = 0x0F2C, CVTTSD2SI = 0xF20F2C, CVTTSS2SI = 0xF30F2C, MASKMOVDQU = 0x660FF7, MASKMOVQ = 0x0FF7, MAXPD = 0x660F5F, MAXPS = 0x0F5F, MAXSD = 0xF20F5F, MAXSS = 0xF30F5F, MINPD = 0x660F5D, MINPS = 0x0F5D, MINSD = 0xF20F5D, MINSS = 0xF30F5D, ORPD = 0x660F56, ORPS = 0x0F56, PAVGB = 0x660FE0, PAVGW = 0x660FE3, PMAXSW = 0x660FEE, //PINSRW = 0x660FC4, PMAXUB = 0x660FDE, PMINSW = 0x660FEA, PMINUB = 0x660FDA, //PMOVMSKB = 0x660FD7, PMULHUW = 0x660FE4, PMULHW = 0x660FE5, PMULUDQ = 0x660FF4, PSADBW = 0x660FF6, PUNPCKHQDQ = 0x660F6D, PUNPCKLQDQ = 0x660F6C, RCPPS = 0x0F53, RCPSS = 0xF30F53, RSQRTPS = 0x0F52, RSQRTSS = 0xF30F52, SQRTPD = 0x660F51, SHUFPD = 0x660FC6, SHUFPS = 0x0FC6, SQRTPS = 0x0F51, SQRTSD = 0xF20F51, SQRTSS = 0xF30F51, UNPCKHPD = 0x660F15, UNPCKHPS = 0x0F15, UNPCKLPD = 0x660F14, UNPCKLPS = 0x0F14, PSHUFD = 0x660F70, PSHUFHW = 0xF30F70, PSHUFLW = 0xF20F70, PSHUFW = 0x0F70, PSLLDQ = 0x07660F73, PSRLDQ = 0x03660F73, //PREFETCH = 0x0F18, // SSE3 Pentium 4 (Prescott) ADDSUBPD = 0x660FD0, ADDSUBPS = 0xF20FD0, HADDPD = 0x660F7C, HADDPS = 0xF20F7C, HSUBPD = 0x660F7D, HSUBPS = 0xF20F7D, MOVDDUP = 0xF20F12, MOVSHDUP = 0xF30F16, MOVSLDUP = 0xF30F12, LDDQU = 0xF20FF0, MONITOR = 0x0F01C8, MWAIT = 0x0F01C9, // SSSE3 PALIGNR = 0x660F3A0F, PHADDD = 0x660F3802, PHADDW = 0x660F3801, PHADDSW = 0x660F3803, PABSB = 0x660F381C, PABSD = 0x660F381E, PABSW = 0x660F381D, PSIGNB = 0x660F3808, PSIGND = 0x660F380A, PSIGNW = 0x660F3809, PSHUFB = 0x660F3800, PMADDUBSW = 0x660F3804, PMULHRSW = 0x660F380B, PHSUBD = 0x660F3806, PHSUBW = 0x660F3805, PHSUBSW = 0x660F3807, // SSE4.1 BLENDPD = 0x660F3A0D, BLENDPS = 0x660F3A0C, BLENDVPD = 0x660F3815, BLENDVPS = 0x660F3814, DPPD = 0x660F3A41, DPPS = 0x660F3A40, EXTRACTPS = 0x660F3A17, INSERTPS = 0x660F3A21, MPSADBW = 0x660F3A42, PBLENDVB = 0x660F3810, PBLENDW = 0x660F3A0E, PEXTRD = 0x660F3A16, PEXTRQ = 0x660F3A16, PINSRB = 0x660F3A20, PINSRD = 0x660F3A22, PINSRQ = 0x660F3A22, MOVNTDQA = 0x660F382A, PACKUSDW = 0x660F382B, PCMPEQQ = 0x660F3829, PEXTRB = 0x660F3A14, PHMINPOSUW = 0x660F3841, PMAXSB = 0x660F383C, PMAXSD = 0x660F383D, PMAXUD = 0x660F383F, PMAXUW = 0x660F383E, PMINSB = 0x660F3838, PMINSD = 0x660F3839, PMINUD = 0x660F383B, PMINUW = 0x660F383A, PMOVSXBW = 0x660F3820, PMOVSXBD = 0x660F3821, PMOVSXBQ = 0x660F3822, PMOVSXWD = 0x660F3823, PMOVSXWQ = 0x660F3824, PMOVSXDQ = 0x660F3825, PMOVZXBW = 0x660F3830, PMOVZXBD = 0x660F3831, PMOVZXBQ = 0x660F3832, PMOVZXWD = 0x660F3833, PMOVZXWQ = 0x660F3834, PMOVZXDQ = 0x660F3835, PMULDQ = 0x660F3828, PMULLD = 0x660F3840, PTEST = 0x660F3817, ROUNDPD = 0x660F3A09, ROUNDPS = 0x660F3A08, ROUNDSD = 0x660F3A0B, ROUNDSS = 0x660F3A0A, // SSE4.2 PCMPESTRI = 0x660F3A61, PCMPESTRM = 0x660F3A60, PCMPISTRI = 0x660F3A63, PCMPISTRM = 0x660F3A62, PCMPGTQ = 0x660F3837, //CRC32 // SSE4a (AMD only) // EXTRQ,INSERTQ,MOVNTSD,MOVNTSS // POPCNT and LZCNT (have their own CPUID bits) POPCNT = 0xF30FB8, // LZCNT } /** * Generate two operand instruction with XMM 128 bit operands. * * This is a compiler magic function - it doesn't behave like * regular D functions. * * Parameters: * opcode any of the XMM opcodes; it must be a compile time constant * op1 first operand * op2 second operand * Returns: * result of opcode */ pure @safe void16 __simd(XMM opcode, void16 op1, void16 op2); /** * Unary SIMD instructions. */ pure @safe void16 __simd(XMM opcode, void16 op1); pure @safe void16 __simd(XMM opcode, double d); /// pure @safe void16 __simd(XMM opcode, float f); /// /**** * For instructions: * CMPPD, CMPSS, CMPSD, CMPPS, * PSHUFD, PSHUFHW, PSHUFLW, * BLENDPD, BLENDPS, DPPD, DPPS, * MPSADBW, PBLENDW, * ROUNDPD, ROUNDPS, ROUNDSD, ROUNDSS * Parameters: * opcode any of the above XMM opcodes; it must be a compile time constant * op1 first operand * op2 second operand * imm8 third operand; must be a compile time constant * Returns: * result of opcode */ pure @safe void16 __simd(XMM opcode, void16 op1, void16 op2, ubyte imm8); /*** * For instructions with the imm8 version: * PSLLD, PSLLQ, PSLLW, PSRAD, PSRAW, PSRLD, PSRLQ, PSRLW, * PSRLDQ, PSLLDQ * Parameters: * opcode any of the XMM opcodes; it must be a compile time constant * op1 first operand * imm8 second operand; must be a compile time constant * Returns: * result of opcode */ pure @safe void16 __simd_ib(XMM opcode, void16 op1, ubyte imm8); /***** * For "store" operations of the form: * op1 op= op2 * Returns: * op2 * These cannot be marked as pure, as semantic() doesn't check them. */ @safe void16 __simd_sto(XMM opcode, void16 op1, void16 op2); @safe void16 __simd_sto(XMM opcode, double op1, void16 op2); /// @safe void16 __simd_sto(XMM opcode, float op1, void16 op2); /// /* The following use overloading to ensure correct typing. * Compile with inlining on for best performance. */ pure @safe short8 pcmpeq()(short8 v1, short8 v2) { return __simd(XMM.PCMPEQW, v1, v2); } pure @safe ushort8 pcmpeq()(ushort8 v1, ushort8 v2) { return __simd(XMM.PCMPEQW, v1, v2); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/vararg.d0000664000175000017500000000131512776214756020631 0ustar kaikai/** * The vararg module is intended to facilitate vararg manipulation in D. * It should be interface compatible with the C module "stdarg," and the * two modules may share a common implementation if possible (as is done * here). * Copyright: Copyright Digital Mars 2000 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Walter Bright, Hauke Duden * Source: $(DRUNTIMESRC core/_vararg.d) */ /* Copyright Digital Mars 2000 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.vararg; public import core.stdc.stdarg; ldc-1.1.0-beta3-src/runtime/druntime/src/core/math.d0000664000175000017500000001573012776214756020306 0ustar kaikai// Written in the D programming language. /** * Builtin mathematical intrinsics * * Source: $(DRUNTIMESRC core/_math.d) * Macros: * TABLE_SV = * * $0
Special Values
* * NAN = $(RED NAN) * SUP = $0 * POWER = $1$2 * PLUSMN = ± * INFIN = ∞ * PLUSMNINF = ±∞ * LT = < * GT = > * * Copyright: Copyright Digital Mars 2000 - 2011. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(WEB digitalmars.com, Walter Bright), * Don Clugston */ module core.math; version (LDC) { import stdc = core.stdc.math; import ldc.intrinsics; } public: @nogc: /*********************************** * Returns cosine of x. x is in radians. * * $(TABLE_SV * $(TR $(TH x) $(TH cos(x)) $(TH invalid?)) * $(TR $(TD $(NAN)) $(TD $(NAN)) $(TD yes) ) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(NAN)) $(TD yes) ) * ) * Bugs: * Results are undefined if |x| >= $(POWER 2,64). */ version (LDC) real cos(real x) @safe pure nothrow { return llvm_cos(x); } else real cos(real x) @safe pure nothrow; /* intrinsic */ /*********************************** * Returns sine of x. x is in radians. * * $(TABLE_SV * $(TR $(TH x) $(TH sin(x)) $(TH invalid?)) * $(TR $(TD $(NAN)) $(TD $(NAN)) $(TD yes)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no)) * $(TR $(TD $(PLUSMNINF)) $(TD $(NAN)) $(TD yes)) * ) * Bugs: * Results are undefined if |x| >= $(POWER 2,64). */ version (LDC) real sin(real x) @safe pure nothrow { return llvm_sin(x); } else real sin(real x) @safe pure nothrow; /* intrinsic */ /***************************************** * Returns x rounded to a long value using the current rounding mode. * If the integer value of x is * greater than long.max, the result is * indeterminate. */ version (LDC) long rndtol(real x) @safe pure nothrow { return stdc.llroundl(x); } else long rndtol(real x) @safe pure nothrow; /* intrinsic */ /***************************************** * Returns x rounded to a long value using the FE_TONEAREST rounding mode. * If the integer value of x is * greater than long.max, the result is * indeterminate. */ extern (C) real rndtonl(real x); /*************************************** * Compute square root of x. * * $(TABLE_SV * $(TR $(TH x) $(TH sqrt(x)) $(TH invalid?)) * $(TR $(TD -0.0) $(TD -0.0) $(TD no)) * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD yes)) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no)) * ) */ @safe pure nothrow { version (LDC) { extern(D) float sqrt(float x) { return x < 0 ? float.nan : llvm_sqrt(x); } extern(D) double sqrt(double x) { return x < 0 ? double.nan : llvm_sqrt(x); } extern(D) real sqrt(real x) { return x < 0 ? real.nan : llvm_sqrt(x); } } else { float sqrt(float x); /* intrinsic */ double sqrt(double x); /* intrinsic */ /// ditto real sqrt(real x); /* intrinsic */ /// ditto } } /******************************************* * Compute n * 2$(SUPERSCRIPT exp) * References: frexp */ version (LDC) { real ldexp(real n, int exp) @trusted pure nothrow { version (MinGW) { // The MinGW runtime only provides a double precision ldexp, and // it doesn't seem to reliably possible to express the fscale // semantics (two FP stack inputs/returns) in an inline asm // expression clobber list. version (D_InlineAsm_X86_64) { asm { naked; push RCX; // push exp (8 bytes), passed in ECX fild int ptr [RSP]; // push exp onto FPU stack pop RCX; // return stack to initial state fld real ptr [RDX]; // push n onto FPU stack, passed in [RDX] fscale; // ST(0) = ST(0) * 2^ST(1) fstp ST(1); // pop stack maintaining top value => function return value ret; // no arguments passed via stack } } else { asm { naked; push EAX; fild int ptr [ESP]; fld real ptr [ESP+8]; fscale; fstp ST(1); pop EAX; ret 12; } } } else { return stdc.ldexpl(n, exp); } } } else real ldexp(real n, int exp) @safe pure nothrow; /* intrinsic */ unittest { static if (real.mant_dig == 113) { assert(ldexp(1, -16384) == 0x1p-16384L); assert(ldexp(1, -16382) == 0x1p-16382L); } else static if (real.mant_dig == 106) { assert(ldexp(1, 1023) == 0x1p1023L); assert(ldexp(1, -1022) == 0x1p-1022L); assert(ldexp(1, -1021) == 0x1p-1021L); } else static if (real.mant_dig == 64) { assert(ldexp(1, -16384) == 0x1p-16384L); assert(ldexp(1, -16382) == 0x1p-16382L); } else static if (real.mant_dig == 53) { assert(ldexp(1, 1023) == 0x1p1023L); assert(ldexp(1, -1022) == 0x1p-1022L); assert(ldexp(1, -1021) == 0x1p-1021L); } else assert(false, "Only 128bit, 80bit and 64bit reals expected here"); } /******************************* * Returns |x| * * $(TABLE_SV * $(TR $(TH x) $(TH fabs(x))) * $(TR $(TD $(PLUSMN)0.0) $(TD +0.0) ) * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) ) * ) */ version (LDC) real fabs(real x) @safe pure nothrow { return llvm_fabs(x); } else real fabs(real x) @safe pure nothrow; /* intrinsic */ /********************************** * Rounds x to the nearest integer value, using the current rounding * mode. * If the return value is not equal to x, the FE_INEXACT * exception is raised. * $(B nearbyint) performs * the same operation, but does not set the FE_INEXACT exception. */ version (LDC) real rint(real x) @safe pure nothrow { return llvm_rint(x); } else real rint(real x) @safe pure nothrow; /* intrinsic */ /*********************************** * Building block functions, they * translate to a single x87 instruction. */ version (LDC) {} else { real yl2x(real x, real y) @safe pure nothrow; // y * log2(x) real yl2xp1(real x, real y) @safe pure nothrow; // y * log2(x + 1) unittest { version (INLINE_YL2X) { assert(yl2x(1024, 1) == 10); assert(yl2xp1(1023, 1) == 10); } } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/demangle.d0000664000175000017500000015010612776214756021126 0ustar kaikai/** * The demangle module converts mangled D symbols to a representation similar * to what would have existed in code. * * Copyright: Copyright Sean Kelly 2010 - 2014. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/_demangle.d) */ module core.demangle; debug(trace) import core.stdc.stdio : printf; debug(info) import core.stdc.stdio : printf; private struct Demangle { // NOTE: This implementation currently only works with mangled function // names as they exist in an object file. Type names mangled via // the .mangleof property are effectively incomplete as far as the // ABI is concerned and so are not considered to be mangled symbol // names. // NOTE: This implementation builds the demangled buffer in place by // writing data as it is decoded and then rearranging it later as // needed. In practice this results in very little data movement, // and the performance cost is more than offset by the gain from // not allocating dynamic memory to assemble the name piecemeal. // // If the destination buffer is too small, parsing will restart // with a larger buffer. Since this generally means only one // allocation during the course of a parsing run, this is still // faster than assembling the result piecemeal. enum AddType { no, yes } this( const(char)[] buf_, char[] dst_ = null ) { this( buf_, AddType.yes, dst_ ); } this( const(char)[] buf_, AddType addType_, char[] dst_ = null ) { buf = buf_; addType = addType_; dst = dst_; } enum size_t minBufSize = 4000; const(char)[] buf = null; char[] dst = null; size_t pos = 0; size_t len = 0; AddType addType = AddType.yes; static class ParseException : Exception { @safe pure nothrow this( string msg ) { super( msg ); } } static class OverflowException : Exception { @safe pure nothrow this( string msg ) { super( msg ); } } static void error( string msg = "Invalid symbol" ) { //throw new ParseException( msg ); debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); throw __ctfe ? new ParseException(msg) : cast(ParseException) cast(void*) typeid(ParseException).initializer; } static void overflow( string msg = "Buffer overflow" ) { //throw new OverflowException( msg ); debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr ); throw cast(OverflowException) cast(void*) typeid(OverflowException).initializer; } ////////////////////////////////////////////////////////////////////////// // Type Testing and Conversion ////////////////////////////////////////////////////////////////////////// static bool isAlpha( char val ) { return ('a' <= val && 'z' >= val) || ('A' <= val && 'Z' >= val) || (0x80 & val); // treat all unicode as alphabetic } static bool isDigit( char val ) { return '0' <= val && '9' >= val; } static bool isHexDigit( char val ) { return ('0' <= val && '9' >= val) || ('a' <= val && 'f' >= val) || ('A' <= val && 'F' >= val); } static ubyte ascii2hex( char val ) { if (val >= 'a' && val <= 'f') return cast(ubyte)(val - 'a' + 10); if (val >= 'A' && val <= 'F') return cast(ubyte)(val - 'A' + 10); if (val >= '0' && val <= '9') return cast(ubyte)(val - '0'); error(); return 0; } ////////////////////////////////////////////////////////////////////////// // Data Output ////////////////////////////////////////////////////////////////////////// static bool contains( const(char)[] a, const(char)[] b ) { if (a.length && b.length) { auto bend = b.ptr + b.length; auto aend = a.ptr + a.length; return a.ptr <= b.ptr && bend <= aend; } return false; } char[] shift( const(char)[] val ) { void exch( size_t a, size_t b ) { char t = dst[a]; dst[a] = dst[b]; dst[b] = t; } if( val.length ) { assert( contains( dst[0 .. len], val ) ); debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr ); for( size_t n = 0; n < val.length; n++ ) { for( size_t v = val.ptr - dst.ptr; v + 1 < len; v++ ) { exch( v, v + 1 ); } } return dst[len - val.length .. len]; } return null; } char[] append( const(char)[] val ) { if( val.length ) { if( !dst.length ) dst.length = minBufSize; assert( !contains( dst[0 .. len], val ) ); debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr ); if( dst.ptr + len == val.ptr && dst.length - len >= val.length ) { // data is already in place auto t = dst[len .. len + val.length]; len += val.length; return t; } if( dst.length - len >= val.length ) { dst[len .. len + val.length] = val[]; auto t = dst[len .. len + val.length]; len += val.length; return t; } overflow(); } return null; } void putComma(size_t n) { pragma(inline, false); if (n) put(", "); } char[] put(char c) { char[1] val = c; return put(val[]); } char[] put( const(char)[] val ) { if( val.length ) { if( !contains( dst[0 .. len], val ) ) return append( val ); return shift( val ); } return null; } void putAsHex( size_t val, int width = 0 ) { import core.internal.string; UnsignedStringBuf buf; auto s = unsignedToTempString(val, buf, 16); int slen = cast(int)s.length; if (slen < width) { foreach(i; slen .. width) put('0'); } put(s); } void pad( const(char)[] val ) { if( val.length ) { append( " " ); put( val ); } } void silent( lazy void dg ) { debug(trace) printf( "silent+\n" ); debug(trace) scope(success) printf( "silent-\n" ); auto n = len; dg(); len = n; } ////////////////////////////////////////////////////////////////////////// // Parsing Utility ////////////////////////////////////////////////////////////////////////// @property bool empty() { return pos >= buf.length; } @property char front() { if( pos < buf.length ) return buf[pos]; return char.init; } void test( char val ) { if( val != front ) error(); } void popFront() { if( pos++ >= buf.length ) error(); } void match( char val ) { test( val ); popFront(); } void match( const(char)[] val ) { foreach(char e; val ) { test( e ); popFront(); } } void eat( char val ) { if( val == front ) popFront(); } ////////////////////////////////////////////////////////////////////////// // Parsing Implementation ////////////////////////////////////////////////////////////////////////// /* Number: Digit Digit Number */ const(char)[] sliceNumber() { debug(trace) printf( "sliceNumber+\n" ); debug(trace) scope(success) printf( "sliceNumber-\n" ); auto beg = pos; while( true ) { auto t = front; if (t >= '0' && t <= '9') popFront(); else return buf[beg .. pos]; } } size_t decodeNumber() { debug(trace) printf( "decodeNumber+\n" ); debug(trace) scope(success) printf( "decodeNumber-\n" ); return decodeNumber( sliceNumber() ); } size_t decodeNumber( const(char)[] num ) { debug(trace) printf( "decodeNumber+\n" ); debug(trace) scope(success) printf( "decodeNumber-\n" ); size_t val = 0; foreach( c; num ) { import core.checkedint : mulu, addu; bool overflow = false; val = mulu(val, 10, overflow); val = addu(val, c - '0', overflow); if (overflow) error(); } return val; } void parseReal() { debug(trace) printf( "parseReal+\n" ); debug(trace) scope(success) printf( "parseReal-\n" ); char[64] tbuf = void; size_t tlen = 0; real val = void; if( 'I' == front ) { match( "INF" ); put( "real.infinity" ); return; } if( 'N' == front ) { popFront(); if( 'I' == front ) { match( "INF" ); put( "-real.infinity" ); return; } if( 'A' == front ) { match( "AN" ); put( "real.nan" ); return; } tbuf[tlen++] = '-'; } tbuf[tlen++] = '0'; tbuf[tlen++] = 'X'; if( !isHexDigit( front ) ) error( "Expected hex digit" ); tbuf[tlen++] = front; tbuf[tlen++] = '.'; popFront(); while( isHexDigit( front ) ) { tbuf[tlen++] = front; popFront(); } match( 'P' ); tbuf[tlen++] = 'p'; if( 'N' == front ) { tbuf[tlen++] = '-'; popFront(); } else { tbuf[tlen++] = '+'; } while( isDigit( front ) ) { tbuf[tlen++] = front; popFront(); } tbuf[tlen] = 0; debug(info) printf( "got (%s)\n", tbuf.ptr ); import core.stdc.stdlib : strtold; val = strtold( tbuf.ptr, null ); import core.stdc.stdio : snprintf; tlen = snprintf( tbuf.ptr, tbuf.length, "%#Lg", val ); debug(info) printf( "converted (%.*s)\n", cast(int) tlen, tbuf.ptr ); put( tbuf[0 .. tlen] ); } /* LName: Number Name Name: Namestart Namestart Namechars Namestart: _ Alpha Namechar: Namestart Digit Namechars: Namechar Namechar Namechars */ void parseLName() { debug(trace) printf( "parseLName+\n" ); debug(trace) scope(success) printf( "parseLName-\n" ); auto n = decodeNumber(); if( !n || n > buf.length || n > buf.length - pos ) error( "LName must be at least 1 character" ); if( '_' != front && !isAlpha( front ) ) error( "Invalid character in LName" ); foreach(char e; buf[pos + 1 .. pos + n] ) { if( '_' != e && !isAlpha( e ) && !isDigit( e ) ) error( "Invalid character in LName" ); } put( buf[pos .. pos + n] ); pos += n; } /* Type: Shared Const Immutable Wild TypeArray TypeVector TypeStaticArray TypeAssocArray TypePointer TypeFunction TypeIdent TypeClass TypeStruct TypeEnum TypeTypedef TypeDelegate TypeNone TypeVoid TypeByte TypeUbyte TypeShort TypeUshort TypeInt TypeUint TypeLong TypeUlong TypeCent TypeUcent TypeFloat TypeDouble TypeReal TypeIfloat TypeIdouble TypeIreal TypeCfloat TypeCdouble TypeCreal TypeBool TypeChar TypeWchar TypeDchar TypeTuple Shared: O Type Const: x Type Immutable: y Type Wild: Ng Type TypeArray: A Type TypeVector: Nh Type TypeStaticArray: G Number Type TypeAssocArray: H Type Type TypePointer: P Type TypeFunction: CallConvention FuncAttrs Arguments ArgClose Type TypeIdent: I LName TypeClass: C LName TypeStruct: S LName TypeEnum: E LName TypeTypedef: T LName TypeDelegate: D TypeFunction TypeNone: n TypeVoid: v TypeByte: g TypeUbyte: h TypeShort: s TypeUshort: t TypeInt: i TypeUint: k TypeLong: l TypeUlong: m TypeCent zi TypeUcent zk TypeFloat: f TypeDouble: d TypeReal: e TypeIfloat: o TypeIdouble: p TypeIreal: j TypeCfloat: q TypeCdouble: r TypeCreal: c TypeBool: b TypeChar: a TypeWchar: u TypeDchar: w TypeTuple: B Number Arguments */ char[] parseType( char[] name = null ) { static immutable string[23] primitives = [ "char", // a "bool", // b "creal", // c "double", // d "real", // e "float", // f "byte", // g "ubyte", // h "int", // i "ireal", // j "uint", // k "long", // l "ulong", // m null, // n "ifloat", // o "idouble", // p "cfloat", // q "cdouble", // r "short", // s "ushort", // t "wchar", // u "void", // v "dchar", // w ]; debug(trace) printf( "parseType+\n" ); debug(trace) scope(success) printf( "parseType-\n" ); auto beg = len; auto t = front; switch( t ) { case 'O': // Shared (O Type) popFront(); put( "shared(" ); parseType(); put( ')' ); pad( name ); return dst[beg .. len]; case 'x': // Const (x Type) popFront(); put( "const(" ); parseType(); put( ')' ); pad( name ); return dst[beg .. len]; case 'y': // Immutable (y Type) popFront(); put( "immutable(" ); parseType(); put( ')' ); pad( name ); return dst[beg .. len]; case 'N': popFront(); switch( front ) { case 'g': // Wild (Ng Type) popFront(); // TODO: Anything needed here? put( "inout(" ); parseType(); put( ')' ); return dst[beg .. len]; case 'h': // TypeVector (Nh Type) popFront(); put( "__vector(" ); parseType(); put( ')' ); return dst[beg .. len]; default: error(); assert( 0 ); } case 'A': // TypeArray (A Type) popFront(); parseType(); put( "[]" ); pad( name ); return dst[beg .. len]; case 'G': // TypeStaticArray (G Number Type) popFront(); auto num = sliceNumber(); parseType(); put( '[' ); put( num ); put( ']' ); pad( name ); return dst[beg .. len]; case 'H': // TypeAssocArray (H Type Type) popFront(); // skip t1 auto tx = parseType(); parseType(); put( '[' ); put( tx ); put( ']' ); pad( name ); return dst[beg .. len]; case 'P': // TypePointer (P Type) popFront(); parseType(); put( '*' ); pad( name ); return dst[beg .. len]; case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction return parseTypeFunction( name ); case 'I': // TypeIdent (I LName) case 'C': // TypeClass (C LName) case 'S': // TypeStruct (S LName) case 'E': // TypeEnum (E LName) case 'T': // TypeTypedef (T LName) popFront(); parseQualifiedName(); pad( name ); return dst[beg .. len]; case 'D': // TypeDelegate (D TypeFunction) popFront(); parseTypeFunction( name, IsDelegate.yes ); return dst[beg .. len]; case 'n': // TypeNone (n) popFront(); // TODO: Anything needed here? return dst[beg .. len]; case 'B': // TypeTuple (B Number Arguments) popFront(); // TODO: Handle this. return dst[beg .. len]; case 'Z': // Internal symbol // This 'type' is used for untyped internal symbols, i.e.: // __array // __init // __vtbl // __Class // __Interface // __ModuleInfo popFront(); return dst[beg .. len]; default: if (t >= 'a' && t <= 'w') { popFront(); put( primitives[cast(size_t)(t - 'a')] ); pad( name ); return dst[beg .. len]; } else if (t == 'z') { popFront(); switch( front ) { case 'i': popFront(); put( "cent" ); pad( name ); return dst[beg .. len]; case 'k': popFront(); put( "ucent" ); pad( name ); return dst[beg .. len]; default: error(); assert( 0 ); } } error(); return null; } } /* TypeFunction: CallConvention FuncAttrs Arguments ArgClose Type CallConvention: F // D U // C W // Windows V // Pascal R // C++ FuncAttrs: FuncAttr FuncAttr FuncAttrs FuncAttr: empty FuncAttrPure FuncAttrNothrow FuncAttrProperty FuncAttrRef FuncAttrTrusted FuncAttrSafe FuncAttrPure: Na FuncAttrNothrow: Nb FuncAttrRef: Nc FuncAttrProperty: Nd FuncAttrTrusted: Ne FuncAttrSafe: Nf FuncAttrNogc: Ni FuncAttrReturn: Nj Arguments: Argument Argument Arguments Argument: Argument2 M Argument2 // scope Argument2: Type J Type // out K Type // ref L Type // lazy ArgClose X // variadic T t,...) style Y // variadic T t...) style Z // not variadic */ void parseCallConvention() { // CallConvention switch( front ) { case 'F': // D popFront(); break; case 'U': // C popFront(); put( "extern (C) " ); break; case 'W': // Windows popFront(); put( "extern (Windows) " ); break; case 'V': // Pascal popFront(); put( "extern (Pascal) " ); break; case 'R': // C++ popFront(); put( "extern (C++) " ); break; default: error(); } } void parseFuncAttr() { // FuncAttrs breakFuncAttrs: while( 'N' == front ) { popFront(); switch( front ) { case 'a': // FuncAttrPure popFront(); put( "pure " ); continue; case 'b': // FuncAttrNoThrow popFront(); put( "nothrow " ); continue; case 'c': // FuncAttrRef popFront(); put( "ref " ); continue; case 'd': // FuncAttrProperty popFront(); put( "@property " ); continue; case 'e': // FuncAttrTrusted popFront(); put( "@trusted " ); continue; case 'f': // FuncAttrSafe popFront(); put( "@safe " ); continue; case 'g': case 'h': case 'k': // NOTE: The inout parameter type is represented as "Ng". // The vector parameter type is represented as "Nh". // The return parameter type is represented as "Nk". // These make it look like a FuncAttr, but infact // if we see these, then we know we're really in // the parameter list. Rewind and break. pos--; break breakFuncAttrs; case 'i': // FuncAttrNogc popFront(); put( "@nogc " ); continue; case 'j': // FuncAttrReturn popFront(); put( "return " ); continue; default: error(); } } } void parseFuncArguments() { // Arguments for( size_t n = 0; true; n++ ) { debug(info) printf( "tok (%c)\n", front ); switch( front ) { case 'X': // ArgClose (variadic T t...) style) popFront(); put( "..." ); return; case 'Y': // ArgClose (variadic T t,...) style) popFront(); put( ", ..." ); return; case 'Z': // ArgClose (not variadic) popFront(); return; default: break; } putComma(n); if( 'M' == front ) { popFront(); put( "scope " ); } if( 'N' == front ) { popFront(); if( 'k' == front ) // Return (Nk Parameter2) { popFront(); put( "return " ); } else pos--; } switch( front ) { case 'J': // out (J Type) popFront(); put( "out " ); parseType(); continue; case 'K': // ref (K Type) popFront(); put( "ref " ); parseType(); continue; case 'L': // lazy (L Type) popFront(); put( "lazy " ); parseType(); continue; default: parseType(); } } } enum IsDelegate { no, yes } // returns the argument list with the left parenthesis, but not the right char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) { debug(trace) printf( "parseTypeFunction+\n" ); debug(trace) scope(success) printf( "parseTypeFunction-\n" ); auto beg = len; parseCallConvention(); parseFuncAttr(); beg = len; put( '(' ); scope(success) { put( ')' ); auto t = len; parseType(); put( ' ' ); if( name.length ) { if( !contains( dst[0 .. len], name ) ) put( name ); else if( shift( name ).ptr != name.ptr ) { beg -= name.length; t -= name.length; } } else if( IsDelegate.yes == isdg ) put( "delegate" ); else put( "function" ); shift( dst[beg .. t] ); } parseFuncArguments(); return dst[beg..len]; } static bool isCallConvention( char ch ) { switch( ch ) { case 'F', 'U', 'V', 'W', 'R': return true; default: return false; } } /* Value: n Number i Number N Number e HexFloat c HexFloat c HexFloat A Number Value... HexFloat: NAN INF NINF N HexDigits P Exponent HexDigits P Exponent Exponent: N Number Number HexDigits: HexDigit HexDigit HexDigits HexDigit: Digit A B C D E F */ void parseValue( char[] name = null, char type = '\0' ) { debug(trace) printf( "parseValue+\n" ); debug(trace) scope(success) printf( "parseValue-\n" ); // printf( "*** %c\n", front ); switch( front ) { case 'n': popFront(); put( "null" ); return; case 'i': popFront(); if( '0' > front || '9' < front ) error( "Number expected" ); goto case; case '0': .. case '9': parseIntegerValue( name, type ); return; case 'N': popFront(); put( '-' ); parseIntegerValue( name, type ); return; case 'e': popFront(); parseReal(); return; case 'c': popFront(); parseReal(); put( '+' ); match( 'c' ); parseReal(); put( 'i' ); return; case 'a': case 'w': case 'd': char t = front; popFront(); auto n = decodeNumber(); match( '_' ); put( '"' ); foreach (i; 0..n) { auto a = ascii2hex( front ); popFront(); auto b = ascii2hex( front ); popFront(); auto v = cast(char)((a << 4) | b); if (' ' <= v && v <= '~') // ASCII printable { put(v); } else { put("\\x"); putAsHex(v, 2); } } put( '"' ); if( 'a' != t ) put(t); return; case 'A': // NOTE: This is kind of a hack. An associative array literal // [1:2, 3:4] is represented as HiiA2i1i2i3i4, so the type // is "Hii" and the value is "A2i1i2i3i4". Thus the only // way to determine that this is an AA value rather than an // array value is for the caller to supply the type char. // Hopefully, this will change so that the value is // "H2i1i2i3i4", rendering this unnecesary. if( 'H' == type ) goto LassocArray; // A Number Value... // An array literal. Value is repeated Number times. popFront(); put( '[' ); auto n = decodeNumber(); foreach( i; 0 .. n ) { putComma(i); parseValue(); } put( ']' ); return; case 'H': LassocArray: // H Number Value... // An associative array literal. Value is repeated 2*Number times. popFront(); put( '[' ); auto n = decodeNumber(); foreach( i; 0 .. n ) { putComma(i); parseValue(); put(':'); parseValue(); } put( ']' ); return; case 'S': // S Number Value... // A struct literal. Value is repeated Number times. popFront(); if( name.length ) put( name ); put( '(' ); auto n = decodeNumber(); foreach( i; 0 .. n ) { putComma(i); parseValue(); } put( ')' ); return; default: error(); } } void parseIntegerValue( char[] name = null, char type = '\0' ) { debug(trace) printf( "parseIntegerValue+\n" ); debug(trace) scope(success) printf( "parseIntegerValue-\n" ); switch( type ) { case 'a': // char case 'u': // wchar case 'w': // dchar { auto val = sliceNumber(); auto num = decodeNumber( val ); switch( num ) { case '\'': put( "'\\''" ); return; // \", \? case '\\': put( "'\\\\'" ); return; case '\a': put( "'\\a'" ); return; case '\b': put( "'\\b'" ); return; case '\f': put( "'\\f'" ); return; case '\n': put( "'\\n'" ); return; case '\r': put( "'\\r'" ); return; case '\t': put( "'\\t'" ); return; case '\v': put( "'\\v'" ); return; default: switch( type ) { case 'a': if( num >= 0x20 && num < 0x7F ) { put( '\'' ); put( cast(char)num ); put( '\'' ); return; } put( "\\x" ); putAsHex( num, 2 ); return; case 'u': put( "'\\u" ); putAsHex( num, 4 ); put( '\'' ); return; case 'w': put( "'\\U" ); putAsHex( num, 8 ); put( '\'' ); return; default: assert( 0 ); } } } case 'b': // bool put( decodeNumber() ? "true" : "false" ); return; case 'h', 't', 'k': // ubyte, ushort, uint put( sliceNumber() ); put( 'u' ); return; case 'l': // long put( sliceNumber() ); put( 'L' ); return; case 'm': // ulong put( sliceNumber() ); put( "uL" ); return; default: put( sliceNumber() ); return; } } /* TemplateArgs: TemplateArg TemplateArg TemplateArgs TemplateArg: TemplateArgX H TemplateArgX TemplateArgX: T Type V Type Value S LName */ void parseTemplateArgs() { debug(trace) printf( "parseTemplateArgs+\n" ); debug(trace) scope(success) printf( "parseTemplateArgs-\n" ); for( size_t n = 0; true; n++ ) { if( front == 'H' ) popFront(); switch( front ) { case 'T': popFront(); putComma(n); parseType(); continue; case 'V': popFront(); putComma(n); // NOTE: In the few instances where the type is actually // desired in the output it should precede the value // generated by parseValue, so it is safe to simply // decrement len and let put/append do its thing. char t = front; // peek at type for parseValue char[] name; silent( name = parseType() ); parseValue( name, t ); continue; case 'S': popFront(); putComma(n); if ( mayBeMangledNameArg() ) { auto l = len; auto p = pos; try { debug(trace) printf( "may be mangled name arg\n" ); parseMangledNameArg(); continue; } catch( ParseException e ) { len = l; pos = p; debug(trace) printf( "not a mangled name arg\n" ); } } parseQualifiedName(); continue; default: return; } } } bool mayBeMangledNameArg() { debug(trace) printf( "mayBeMangledNameArg+\n" ); debug(trace) scope(success) printf( "mayBeMangledNameArg-\n" ); auto p = pos; scope(exit) pos = p; auto n = decodeNumber(); return n >= 4 && pos < buf.length && '_' == buf[pos++] && pos < buf.length && 'D' == buf[pos++] && isDigit(buf[pos]); } void parseMangledNameArg() { debug(trace) printf( "parseMangledNameArg+\n" ); debug(trace) scope(success) printf( "parseMangledNameArg-\n" ); auto n = decodeNumber(); parseMangledName( n ); } /* TemplateInstanceName: Number __T LName TemplateArgs Z */ void parseTemplateInstanceName() { debug(trace) printf( "parseTemplateInstanceName+\n" ); debug(trace) scope(success) printf( "parseTemplateInstanceName-\n" ); auto sav = pos; scope(failure) pos = sav; auto n = decodeNumber(); auto beg = pos; match( "__T" ); parseLName(); put( "!(" ); parseTemplateArgs(); match( 'Z' ); if( pos - beg != n ) error( "Template name length mismatch" ); put( ')' ); } bool mayBeTemplateInstanceName() { debug(trace) printf( "mayBeTemplateInstanceName+\n" ); debug(trace) scope(success) printf( "mayBeTemplateInstanceName-\n" ); auto p = pos; scope(exit) pos = p; auto n = decodeNumber(); return n >= 5 && pos < buf.length && '_' == buf[pos++] && pos < buf.length && '_' == buf[pos++] && pos < buf.length && 'T' == buf[pos++]; } /* SymbolName: LName TemplateInstanceName */ void parseSymbolName() { debug(trace) printf( "parseSymbolName+\n" ); debug(trace) scope(success) printf( "parseSymbolName-\n" ); // LName -> Number // TemplateInstanceName -> Number "__T" switch( front ) { case '0': .. case '9': if( mayBeTemplateInstanceName() ) { auto t = len; try { debug(trace) printf( "may be template instance name\n" ); parseTemplateInstanceName(); return; } catch( ParseException e ) { debug(trace) printf( "not a template instance name\n" ); len = t; } } parseLName(); return; default: error(); } } /* QualifiedName: SymbolName SymbolName QualifiedName */ char[] parseQualifiedName() { debug(trace) printf( "parseQualifiedName+\n" ); debug(trace) scope(success) printf( "parseQualifiedName-\n" ); size_t beg = len; size_t n = 0; do { if( n++ ) put( '.' ); parseSymbolName(); if( isCallConvention( front ) ) { // try to demangle a function, in case we are pointing to some function local auto prevpos = pos; auto prevlen = len; // we don't want calling convention and attributes in the qualified name parseCallConvention(); parseFuncAttr(); len = prevlen; put( '(' ); parseFuncArguments(); put( ')' ); if( !isDigit( front ) ) // voldemort types don't have a return type on the function { auto funclen = len; parseType(); if( !isDigit( front ) ) { // not part of a qualified name, so back up pos = prevpos; len = prevlen; } else len = funclen; // remove return type from qualified name } } } while( isDigit( front ) ); return dst[beg .. len]; } /* MangledName: _D QualifiedName Type _D QualifiedName M Type */ void parseMangledName(size_t n = 0) { debug(trace) printf( "parseMangledName+\n" ); debug(trace) scope(success) printf( "parseMangledName-\n" ); char[] name = null; auto end = pos + n; eat( '_' ); match( 'D' ); do { name = parseQualifiedName(); debug(info) printf( "name (%.*s)\n", cast(int) name.length, name.ptr ); if( 'M' == front ) popFront(); // has 'this' pointer if( AddType.yes == addType ) parseType( name ); if( pos >= buf.length || (n != 0 && pos >= end) ) return; put( '.' ); } while( true ); } char[] doDemangle(alias FUNC)() { while( true ) { try { debug(info) printf( "demangle(%.*s)\n", cast(int) buf.length, buf.ptr ); FUNC(); return dst[0 .. len]; } catch( OverflowException e ) { debug(trace) printf( "overflow... restarting\n" ); auto a = minBufSize; auto b = 2 * dst.length; auto newsz = a < b ? b : a; debug(info) printf( "growing dst to %lu bytes\n", newsz ); dst.length = newsz; pos = len = 0; continue; } catch( ParseException e ) { debug(info) { auto msg = e.toString(); printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); } if( dst.length < buf.length ) dst.length = buf.length; dst[0 .. buf.length] = buf[]; return dst[0 .. buf.length]; } } } char[] demangleName() { return doDemangle!parseMangledName(); } char[] demangleType() { return doDemangle!parseType(); } } /** * Demangles D mangled names. If it is not a D mangled name, it returns its * argument name. * * Params: * buf = The string to demangle. * dst = An optional destination buffer. * * Returns: * The demangled name or the original string if the name is not a mangled D * name. */ char[] demangle( const(char)[] buf, char[] dst = null ) { //return Demangle(buf, dst)(); auto d = Demangle(buf, dst); return d.demangleName(); } /** * Demangles a D mangled type. * * Params: * buf = The string to demangle. * dst = An optional destination buffer. * * Returns: * The demangled type name or the original string if the name is not a * mangled D type. */ char[] demangleType( const(char)[] buf, char[] dst = null ) { auto d = Demangle(buf, dst); return d.demangleType(); } /** * Mangles a D symbol. * * Params: * T = The type of the symbol. * fqn = The fully qualified name of the symbol. * dst = An optional destination buffer. * * Returns: * The mangled name for a symbols of type T and the given fully * qualified name. */ char[] mangle(T)(const(char)[] fqn, char[] dst = null) @safe pure nothrow { import core.internal.string : numDigits, unsignedToTempString; static struct DotSplitter { @safe pure nothrow: const(char)[] s; @property bool empty() const { return !s.length; } @property const(char)[] front() const { immutable i = indexOfDot(); return i == -1 ? s[0 .. $] : s[0 .. i]; } void popFront() { immutable i = indexOfDot(); s = i == -1 ? s[$ .. $] : s[i+1 .. $]; } private ptrdiff_t indexOfDot() const { foreach (i, c; s) if (c == '.') return i; return -1; } } size_t len = "_D".length; foreach (comp; DotSplitter(fqn)) len += numDigits(comp.length) + comp.length; len += T.mangleof.length; if (dst.length < len) dst.length = len; size_t i = "_D".length; dst[0 .. i] = "_D"; foreach (comp; DotSplitter(fqn)) { const ndigits = numDigits(comp.length); unsignedToTempString(comp.length, dst[i .. i + ndigits]); i += ndigits; dst[i .. i + comp.length] = comp[]; i += comp.length; } dst[i .. i + T.mangleof.length] = T.mangleof[]; i += T.mangleof.length; return dst[0 .. i]; } /// unittest { assert(mangle!int("a.b") == "_D1a1bi"); assert(mangle!(char[])("test.foo") == "_D4test3fooAa"); assert(mangle!(int function(int))("a.b") == "_D1a1bPFiZi"); } unittest { static assert(mangle!int("a.b") == "_D1a1bi"); auto buf = new char[](10); buf = mangle!int("a.b", buf); assert(buf == "_D1a1bi"); buf = mangle!(char[])("test.foo", buf); assert(buf == "_D4test3fooAa"); buf = mangle!(real delegate(int))("modµ.dg"); assert(buf == "_D5modµ2dgDFiZe", buf); } /** * Mangles a D function. * * Params: * T = function pointer type. * fqn = The fully qualified name of the symbol. * dst = An optional destination buffer. * * Returns: * The mangled name for a function with function pointer type T and * the given fully qualified name. */ char[] mangleFunc(T:FT*, FT)(const(char)[] fqn, char[] dst = null) @safe pure nothrow if (is(FT == function)) { static if (isExternD!FT) { return mangle!FT(fqn, dst); } else static if (hasPlainMangling!FT) { dst.length = fqn.length; dst[] = fqn[]; return dst; } else static if (isExternCPP!FT) { static assert(0, "Can't mangle extern(C++) functions."); } else { static assert(0, "Can't mangle function with unknown linkage ("~FT.stringof~")."); } } /// unittest { assert(mangleFunc!(int function(int))("a.b") == "_D1a1bFiZi"); assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFC6ObjectZi"); } unittest { int function(lazy int[], ...) fp; assert(mangle!(typeof(fp))("demangle.test") == "_D8demangle4testPFLAiYi"); assert(mangle!(typeof(*fp))("demangle.test") == "_D8demangle4testFLAiYi"); } private template isExternD(FT) if (is(FT == function)) { enum isExternD = FT.mangleof[0] == 'F'; } private template isExternCPP(FT) if (is(FT == function)) { enum isExternCPP = FT.mangleof[0] == 'R'; } private template hasPlainMangling(FT) if (is(FT == function)) { enum c = FT.mangleof[0]; // C || Pascal || Windows enum hasPlainMangling = c == 'U' || c == 'V' || c == 'W'; } unittest { static extern(D) void fooD(); static extern(C) void fooC(); static extern(Pascal) void fooP(); static extern(Windows) void fooW(); static extern(C++) void fooCPP(); bool check(FT)(bool isD, bool isCPP, bool isPlain) { return isExternD!FT == isD && isExternCPP!FT == isCPP && hasPlainMangling!FT == isPlain; } static assert(check!(typeof(fooD))(true, false, false)); static assert(check!(typeof(fooC))(false, false, true)); static assert(check!(typeof(fooP))(false, false, true)); static assert(check!(typeof(fooW))(false, false, true)); static assert(check!(typeof(fooCPP))(false, true, false)); static assert(__traits(compiles, mangleFunc!(typeof(&fooD))(""))); static assert(__traits(compiles, mangleFunc!(typeof(&fooC))(""))); static assert(__traits(compiles, mangleFunc!(typeof(&fooP))(""))); static assert(__traits(compiles, mangleFunc!(typeof(&fooW))(""))); static assert(!__traits(compiles, mangleFunc!(typeof(&fooCPP))(""))); } /*** * C name mangling is done by adding a prefix on some platforms. */ version(Win32) enum string cPrefix = "_"; else version(OSX) enum string cPrefix = "_"; else enum string cPrefix = ""; version(unittest) { immutable string[2][] table = [ ["printf", "printf"], ["_foo", "_foo"], ["_D88", "_D88"], ["_D4test3fooAa", "char[] test.foo"], ["_D8demangle8demangleFAaZAa", "char[] demangle.demangle(char[])"], ["_D6object6Object8opEqualsFC6ObjectZi", "int object.Object.opEquals(Object)"], ["_D4test2dgDFiYd", "double test.dg(int, ...)"], //["_D4test58__T9factorialVde67666666666666860140VG5aa5_68656c6c6fVPvnZ9factorialf", ""], //["_D4test101__T9factorialVde67666666666666860140Vrc9a999999999999d9014000000000000000c00040VG5aa5_68656c6c6fVPvnZ9factorialf", ""], ["_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi", "int test.bar!(\"abc\"w, \"def\"d).x"], ["_D8demangle4testFLC6ObjectLDFLiZiZi", "int demangle.test(lazy Object, lazy int delegate(lazy int))"], ["_D8demangle4testFAiXi", "int demangle.test(int[]...)"], ["_D8demangle4testFAiYi", "int demangle.test(int[], ...)"], ["_D8demangle4testFLAiXi", "int demangle.test(lazy int[]...)"], ["_D8demangle4testFLAiYi", "int demangle.test(lazy int[], ...)"], ["_D6plugin8generateFiiZAya", "immutable(char)[] plugin.generate(int, int)"], ["_D6plugin8generateFiiZAxa", "const(char)[] plugin.generate(int, int)"], ["_D6plugin8generateFiiZAOa", "shared(char)[] plugin.generate(int, int)"], ["_D8demangle3fnAFZ3fnBMFZv", "void demangle.fnA().fnB()"], ["_D8demangle4mainFZ1S3fnCMFZv", "void demangle.main().S.fnC()"], ["_D8demangle4mainFZ1S3fnDMFZv", "void demangle.main().S.fnD()"], ["_D8demangle20__T2fnVAiA4i1i2i3i4Z2fnFZv", "void demangle.fn!([1, 2, 3, 4]).fn()"], ["_D8demangle10__T2fnVi1Z2fnFZv", "void demangle.fn!(1).fn()"], ["_D8demangle26__T2fnVS8demangle1SS2i1i2Z2fnFZv", "void demangle.fn!(demangle.S(1, 2)).fn()"], ["_D8demangle13__T2fnVeeNANZ2fnFZv", "void demangle.fn!(real.nan).fn()"], ["_D8demangle14__T2fnVeeNINFZ2fnFZv", "void demangle.fn!(-real.infinity).fn()"], ["_D8demangle13__T2fnVeeINFZ2fnFZv", "void demangle.fn!(real.infinity).fn()"], ["_D8demangle21__T2fnVHiiA2i1i2i3i4Z2fnFZv", "void demangle.fn!([1:2, 3:4]).fn()"], ["_D8demangle2fnFNgiZNgi", "inout(int) demangle.fn(inout(int))"], ["_D8demangle29__T2fnVa97Va9Va0Vu257Vw65537Z2fnFZv", "void demangle.fn!('a', '\\t', \\x00, '\\u0101', '\\U00010001').fn()"], ["_D2gc11gctemplates56__T8mkBitmapTS3std5range13__T4iotaTiTiZ4iotaFiiZ6ResultZ8mkBitmapFNbNiNfPmmZv", "nothrow @nogc @safe void gc.gctemplates.mkBitmap!(std.range.iota!(int, int).iota(int, int).Result).mkBitmap(ulong*, ulong)"], ["_D8serenity9persister6Sqlite69__T15SqlitePersisterTS8serenity9persister6Sqlite11__unittest6FZ4TestZ15SqlitePersister12__T7opIndexZ7opIndexMFmZS8serenity9persister6Sqlite11__unittest6FZ4Test", "serenity.persister.Sqlite.__unittest6().Test serenity.persister.Sqlite.SqlitePersister!(serenity.persister.Sqlite.__unittest6().Test).SqlitePersister.opIndex!().opIndex(ulong)"], ["_D8bug100274mainFZ5localMFZi","int bug10027.main().local()"], ["_D8demangle4testFNhG16gZv", "void demangle.test(__vector(byte[16]))"], ["_D8demangle4testFNhG8sZv", "void demangle.test(__vector(short[8]))"], ["_D8demangle4testFNhG4iZv", "void demangle.test(__vector(int[4]))"], ["_D8demangle4testFNhG2lZv", "void demangle.test(__vector(long[2]))"], ["_D8demangle4testFNhG4fZv", "void demangle.test(__vector(float[4]))"], ["_D8demangle4testFNhG2dZv", "void demangle.test(__vector(double[2]))"], ["_D8demangle4testFNhG4fNhG4fZv", "void demangle.test(__vector(float[4]), __vector(float[4]))"], ["_D8bug1119234__T3fooS23_D8bug111924mainFZ3bariZ3fooMFZv","void bug11192.foo!(int bug11192.main().bar).foo()"], ["_D13libd_demangle12__ModuleInfoZ", "libd_demangle.__ModuleInfo"], ["_D15TypeInfo_Struct6__vtblZ", "TypeInfo_Struct.__vtbl"], ["_D3std5stdio12__ModuleInfoZ", "std.stdio.__ModuleInfo"], ["_D3std6traits15__T8DemangleTkZ8Demangle6__initZ", "std.traits.Demangle!(uint).Demangle.__init"], ["_D3foo3Bar7__ClassZ", "foo.Bar.__Class"], ["_D3foo3Bar6__vtblZ", "foo.Bar.__vtbl"], ["_D3foo3Bar11__interfaceZ", "foo.Bar.__interface"], ["_D3foo7__arrayZ", "foo.__array"], ["_D8link657428__T3fooVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"], ["_D8link657429__T3fooHVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"], ["_D4test22__T4funcVAyaa3_610a62Z4funcFNaNbNiNfZAya", `pure nothrow @nogc @safe immutable(char)[] test.func!("a\x0ab").func()`], ["_D3foo3barFzkZzi", "cent foo.bar(ucent)"], ]; template staticIota(int x) { template Seq(T...){ alias T Seq; } static if (x == 0) alias Seq!() staticIota; else alias Seq!(staticIota!(x - 1), x - 1) staticIota; } } unittest { foreach( i, name; table ) { auto r = demangle( name[0] ); assert( r == name[1], "demangled \"" ~ name[0] ~ "\" as \"" ~ r ~ "\" but expected \"" ~ name[1] ~ "\""); } foreach( i; staticIota!(table.length) ) { enum r = demangle( table[i][0] ); static assert( r == table[i][1], "demangled \"" ~ table[i][0] ~ "\" as \"" ~ r ~ "\" but expected \"" ~ table[i][1] ~ "\""); } } /* * */ string decodeDmdString( const(char)[] ln, ref size_t p ) { string s; uint zlen, zpos; // decompress symbol while( p < ln.length ) { int ch = cast(ubyte) ln[p++]; if( (ch & 0xc0) == 0xc0 ) { zlen = (ch & 0x7) + 1; zpos = ((ch >> 3) & 7) + 1; // + zlen; if( zpos > s.length ) break; s ~= s[$ - zpos .. $ - zpos + zlen]; } else if( ch >= 0x80 ) { if( p >= ln.length ) break; int ch2 = cast(ubyte) ln[p++]; zlen = (ch2 & 0x7f) | ((ch & 0x38) << 4); if( p >= ln.length ) break; int ch3 = cast(ubyte) ln[p++]; zpos = (ch3 & 0x7f) | ((ch & 7) << 7); if( zpos > s.length ) break; s ~= s[$ - zpos .. $ - zpos + zlen]; } else if( Demangle.isAlpha(cast(char)ch) || Demangle.isDigit(cast(char)ch) || ch == '_' ) s ~= cast(char) ch; else { p--; break; } } return s; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/time.d0000664000175000017500000051372512776214756020322 0ustar kaikai//Written in the D programming language /++ Module containing core time functionality, such as $(LREF Duration) (which represents a duration of time) or $(LREF MonoTime) (which represents a timestamp of the system's monotonic clock). Various functions take a string (or strings) to represent a unit of time (e.g. $(D convert!("days", "hours")(numDays))). The valid strings to use with such functions are "years", "months", "weeks", "days", "hours", "minutes", "seconds", "msecs" (milliseconds), "usecs" (microseconds), "hnsecs" (hecto-nanoseconds - i.e. 100 ns) or some subset thereof. There are a few functions that also allow "nsecs", but very little actually has precision greater than hnsecs. $(BOOKTABLE Cheat Sheet, $(TR $(TH Symbol) $(TH Description)) $(LEADINGROW Types) $(TR $(TDNW $(LREF Duration)) $(TD Represents a duration of time of weeks or less (kept internally as hnsecs). (e.g. 22 days or 700 seconds).)) $(TR $(TDNW $(LREF TickDuration)) $(TD Represents a duration of time in system clock ticks, using the highest precision that the system provides.)) $(TR $(TDNW $(LREF MonoTime)) $(TD Represents a monotonic timestamp in system clock ticks, using the highest precision that the system provides.)) $(TR $(TDNW $(LREF FracSec)) $(TD Represents fractional seconds (portions of time smaller than a second).)) $(LEADINGROW Functions) $(TR $(TDNW $(LREF convert)) $(TD Generic way of converting between two time units.)) $(TR $(TDNW $(LREF dur)) $(TD Allows constructing a $(LREF Duration) from the given time units with the given length.)) $(TR $(TDNW $(LREF weeks)$(NBSP)$(LREF days)$(NBSP)$(LREF hours)$(BR) $(LREF minutes)$(NBSP)$(LREF seconds)$(NBSP)$(LREF msecs)$(BR) $(LREF usecs)$(NBSP)$(LREF hnsecs)$(NBSP)$(LREF nsecs)) $(TD Convenience aliases for $(LREF dur).)) $(TR $(TDNW $(LREF abs)) $(TD Returns the absolute value of a duration.)) ) $(BOOKTABLE Conversions, $(TR $(TH ) $(TH From $(LREF Duration)) $(TH From $(LREF TickDuration)) $(TH From $(LREF FracSec)) $(TH From units) ) $(TR $(TD $(B To $(LREF Duration))) $(TD -) $(TD $(D tickDuration.)$(SXREF conv, to)$(D !Duration())) $(TD -) $(TD $(D dur!"msecs"(5)) or $(D 5.msecs())) ) $(TR $(TD $(B To $(LREF TickDuration))) $(TD $(D duration.)$(SXREF conv, to)$(D !TickDuration())) $(TD -) $(TD -) $(TD $(D TickDuration.from!"msecs"(msecs))) ) $(TR $(TD $(B To $(LREF FracSec))) $(TD $(D duration.fracSec)) $(TD -) $(TD -) $(TD $(D FracSec.from!"msecs"(msecs))) ) $(TR $(TD $(B To units)) $(TD $(D duration.total!"days")) $(TD $(D tickDuration.msecs)) $(TD $(D fracSec.msecs)) $(TD $(D convert!("days", "msecs")(msecs))) )) Copyright: Copyright 2010 - 2012 License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jonathan M Davis and Kato Shoichi Source: $(DRUNTIMESRC core/_time.d) Macros: NBSP=  SXREF=$(D $2) +/ module core.time; import core.exception; import core.stdc.time; import core.stdc.stdio; import core.internal.traits : _Unqual = Unqual; import core.internal.string; version(Windows) { import core.sys.windows.windows; } else version(Posix) { import core.sys.posix.time; import core.sys.posix.sys.time; } //This probably should be moved somewhere else in druntime which //is OSX-specific. version(OSX) { public import core.sys.osx.mach.kern_return; extern(C) nothrow @nogc { struct mach_timebase_info_data_t { uint numer; uint denom; } alias mach_timebase_info_data_t* mach_timebase_info_t; kern_return_t mach_timebase_info(mach_timebase_info_t); ulong mach_absolute_time(); } } //To verify that an lvalue isn't required. version(unittest) T copy(T)(T t) { return t; } /++ What type of clock to use with $(LREF MonoTime) / $(LREF MonoTimeImpl) or $(D std.datetime.Clock.currTime). They default to $(D ClockType.normal), and most programs do not need to ever deal with the others. The other $(D ClockType)s are provided so that other clocks provided by the underlying C, system calls can be used with $(LREF MonoTimeImpl) or $(D std.datetime.Clock.currTime) without having to use the C API directly. In the case of the monotonic time, $(LREF MonoTimeImpl) is templatized on $(D ClockType), whereas with $(D std.datetime.Clock.currTime), its a runtime argument, since in the case of the monotonic time, the type of the clock affects the resolution of a $(LREF MonoTimeImpl) object, whereas with $(XREF datetime, SysTime), its resolution is always hecto-nanoseconds regardless of the source of the time. $(D ClockType.normal), $(D ClockType.coarse), and $(D ClockType.precise) work with both $(D Clock.currTime) and $(LREF MonoTimeImpl). $(D ClockType.second) only works with $(D Clock.currTime). The others only work with $(LREF MonoTimeImpl). +/ version(CoreDdoc) enum ClockType { /++ Use the normal clock. +/ normal = 0, /++ $(BLUE Linux-Only) Uses $(D CLOCK_BOOTTIME). +/ bootTime = 1, /++ Use the coarse clock, not the normal one (e.g. on Linux, that would be $(D CLOCK_REALTIME_COARSE) instead of $(D CLOCK_REALTIME) for $(D clock_gettime) if a function is using the realtime clock). It's generally faster to get the time with the coarse clock than the normal clock, but it's less precise (e.g. 1 msec instead of 1 usec or 1 nsec). Howeover, it $(I is) guaranteed to still have sub-second precision (just not as high as with $(D ClockType.normal)). On systems which do not support a coarser clock, $(D MonoTimeImpl!(ClockType.coarse)) will internally use the same clock as $(D Monotime) does, and $(D Clock.currTime!(ClockType.coarse)) will use the same clock as $(D Clock.currTime). This is because the coarse clock is doing the same thing as the normal clock (just at lower precision), whereas some of the other clock types (e.g. $(D ClockType.processCPUTime)) mean something fundamentally different. So, treating those as $(D ClockType.normal) on systems where they weren't natively supported would give misleading results. Most programs should not use the coarse clock, exactly because it's less precise, and most programs don't need to get the time often enough to care, but for those rare programs that need to get the time extremely frequently (e.g. hundreds of thousands of times a second) but don't care about high precision, the coarse clock might be appropriate. Currently, only Linux and FreeBSD support a coarser clock, and on other platforms, it's treated as $(D ClockType.normal). +/ coarse = 2, /++ Uses a more precise clock than the normal one (which is already very precise), but it takes longer to get the time. Similarly to $(D ClockType.coarse), if it's used on a system that does not support a more precise clock than the normal one, it's treated as equivalent to $(D ClockType.normal). Currently, only FreeBSD supports a more precise clock, where it uses $(D CLOCK_MONOTONIC_PRECISE) for the monotonic time and $(D CLOCK_REALTIME_PRECISE) for the wall clock time. +/ precise = 3, /++ $(BLUE Linux,Solaris-Only) Uses $(D CLOCK_PROCESS_CPUTIME_ID). +/ processCPUTime = 4, /++ $(BLUE Linux-Only) Uses $(D CLOCK_MONOTONIC_RAW). +/ raw = 5, /++ Uses a clock that has a precision of one second (contrast to the coarse clock, which has sub-second precision like the normal clock does). FreeBSD is the only system which specifically has a clock set up for this (it has $(D CLOCK_SECOND) to use with $(D clock_gettime) which takes advantage of an in-kernel cached value), but on other systems, the fastest function available will be used, and the resulting $(D SysTime) will be rounded down to the second if the clock that was used gave the time at a more precise resolution. So, it's guaranteed that the time will be given at a precision of one second and it's likely the case that will be faster than $(D ClockType.normal), since there tend to be several options on a system to get the time at low resolutions, and they tend to be faster than getting the time at high resolutions. So, the primary difference between $(D ClockType.coarse) and $(D ClockType.second) is that $(D ClockType.coarse) sacrifices some precision in order to get speed but is still fairly precise, whereas $(D ClockType.second) tries to be as fast as possible at the expense of all sub-second precision. +/ second = 6, /++ $(BLUE Linux,Solaris-Only) Uses $(D CLOCK_THREAD_CPUTIME_ID). +/ threadCPUTime = 7, /++ $(BLUE FreeBSD-Only) Uses $(D CLOCK_UPTIME). +/ uptime = 8, /++ $(BLUE FreeBSD-Only) Uses $(D CLOCK_UPTIME_FAST). +/ uptimeCoarse = 9, /++ $(BLUE FreeBSD-Only) Uses $(D CLOCK_UPTIME_PRECISE). +/ uptimePrecise = 10, } else version(Windows) enum ClockType { normal = 0, coarse = 2, precise = 3, second = 6, } else version(OSX) enum ClockType { normal = 0, coarse = 2, precise = 3, second = 6, } else version(linux) enum ClockType { normal = 0, bootTime = 1, coarse = 2, precise = 3, processCPUTime = 4, raw = 5, second = 6, threadCPUTime = 7, } else version(FreeBSD) enum ClockType { normal = 0, coarse = 2, precise = 3, second = 6, uptime = 8, uptimeCoarse = 9, uptimePrecise = 10, } else version(Solaris) enum ClockType { normal = 0, coarse = 2, precise = 3, processCPUTime = 4, second = 6, threadCPUTime = 7, } else { // It needs to be decided (and implemented in an appropriate version branch // here) which clock types new platforms are going to support. At minimum, // the ones _not_ marked with $(D Blue Foo-Only) should be supported. static assert(0, "What are the clock types supported by this system?"); } // private, used to translate clock type to proper argument to clock_xxx // functions on posix systems version(CoreDdoc) private int _posixClock(ClockType clockType) { return 0; } else version(Posix) { private auto _posixClock(ClockType clockType) { version(linux) { import core.sys.linux.time; with(ClockType) final switch(clockType) { case bootTime: return CLOCK_BOOTTIME; case coarse: return CLOCK_MONOTONIC_COARSE; case normal: return CLOCK_MONOTONIC; case precise: return CLOCK_MONOTONIC; case processCPUTime: return CLOCK_PROCESS_CPUTIME_ID; case raw: return CLOCK_MONOTONIC_RAW; case threadCPUTime: return CLOCK_THREAD_CPUTIME_ID; case second: assert(0); } } else version(FreeBSD) { import core.sys.freebsd.time; with(ClockType) final switch(clockType) { case coarse: return CLOCK_MONOTONIC_FAST; case normal: return CLOCK_MONOTONIC; case precise: return CLOCK_MONOTONIC_PRECISE; case uptime: return CLOCK_UPTIME; case uptimeCoarse: return CLOCK_UPTIME_FAST; case uptimePrecise: return CLOCK_UPTIME_PRECISE; case second: assert(0); } } else version(Solaris) { import core.sys.solaris.time; with(ClockType) final switch(clockType) { case coarse: return CLOCK_MONOTONIC; case normal: return CLOCK_MONOTONIC; case precise: return CLOCK_MONOTONIC; case processCPUTime: return CLOCK_PROCESS_CPUTIME_ID; case threadCPUTime: return CLOCK_THREAD_CPUTIME_ID; case second: assert(0); } } else // It needs to be decided (and implemented in an appropriate // version branch here) which clock types new platforms are going // to support. Also, ClockType's documentation should be updated to // mention it if a new platform uses anything that's not supported // on all platforms.. assert(0, "What are the monotonic clock types supported by this system?"); } } unittest { // Make sure that the values are the same across platforms. static if(is(typeof(ClockType.normal))) static assert(ClockType.normal == 0); static if(is(typeof(ClockType.bootTime))) static assert(ClockType.bootTime == 1); static if(is(typeof(ClockType.coarse))) static assert(ClockType.coarse == 2); static if(is(typeof(ClockType.precise))) static assert(ClockType.precise == 3); static if(is(typeof(ClockType.processCPUTime))) static assert(ClockType.processCPUTime == 4); static if(is(typeof(ClockType.raw))) static assert(ClockType.raw == 5); static if(is(typeof(ClockType.second))) static assert(ClockType.second == 6); static if(is(typeof(ClockType.threadCPUTime))) static assert(ClockType.threadCPUTime == 7); static if(is(typeof(ClockType.uptime))) static assert(ClockType.uptime == 8); static if(is(typeof(ClockType.uptimeCoarse))) static assert(ClockType.uptimeCoarse == 9); static if(is(typeof(ClockType.uptimePrecise))) static assert(ClockType.uptimePrecise == 10); } /++ Represents a duration of time of weeks or less (kept internally as hnsecs). (e.g. 22 days or 700 seconds). It is used when representing a duration of time - such as how long to sleep with $(CXREF thread, Thread.sleep). In std.datetime, it is also used as the result of various arithmetic operations on time points. Use the $(LREF dur) function or one of its non-generic aliases to create $(D Duration)s. It's not possible to create a Duration of months or years, because the variable number of days in a month or year makes it impossible to convert between months or years and smaller units without a specific date. So, nothing uses $(D Duration)s when dealing with months or years. Rather, functions specific to months and years are defined. For instance, $(XREF datetime, Date) has $(D add!"years") and $(D add!"months") for adding years and months rather than creating a Duration of years or months and adding that to a $(XREF datetime, Date). But Duration is used when dealing with weeks or smaller. Examples: -------------------- assert(dur!"days"(12) == dur!"hnsecs"(10_368_000_000_000L)); assert(dur!"hnsecs"(27) == dur!"hnsecs"(27)); assert(std.datetime.Date(2010, 9, 7) + dur!"days"(5) == std.datetime.Date(2010, 9, 12)); assert(days(-12) == dur!"hnsecs"(-10_368_000_000_000L)); assert(hnsecs(-27) == dur!"hnsecs"(-27)); assert(std.datetime.Date(2010, 9, 7) - std.datetime.Date(2010, 10, 3) == days(-26)); -------------------- +/ struct Duration { @safe pure: public: /++ A $(D Duration) of $(D 0). It's shorter than doing something like $(D dur!"seconds"(0)) and more explicit than $(D Duration.init). +/ static @property nothrow @nogc Duration zero() { return Duration(0); } /++ Largest $(D Duration) possible. +/ static @property nothrow @nogc Duration max() { return Duration(long.max); } /++ Most negative $(D Duration) possible. +/ static @property nothrow @nogc Duration min() { return Duration(long.min); } unittest { assert(zero == dur!"seconds"(0)); assert(Duration.max == Duration(long.max)); assert(Duration.min == Duration(long.min)); assert(Duration.min < Duration.zero); assert(Duration.zero < Duration.max); assert(Duration.min < Duration.max); assert(Duration.min - dur!"hnsecs"(1) == Duration.max); assert(Duration.max + dur!"hnsecs"(1) == Duration.min); } /++ Compares this $(D Duration) with the given $(D Duration). Returns: $(TABLE $(TR $(TD this < rhs) $(TD < 0)) $(TR $(TD this == rhs) $(TD 0)) $(TR $(TD this > rhs) $(TD > 0)) ) +/ int opCmp(Duration rhs) const nothrow @nogc { if(_hnsecs < rhs._hnsecs) return -1; if(_hnsecs > rhs._hnsecs) return 1; return 0; } unittest { foreach(T; _TypeTuple!(Duration, const Duration, immutable Duration)) { foreach(U; _TypeTuple!(Duration, const Duration, immutable Duration)) { T t = 42; U u = t; assert(t == u); assert(copy(t) == u); assert(t == copy(u)); } } foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { foreach(E; _TypeTuple!(Duration, const Duration, immutable Duration)) { assert((cast(D)Duration(12)).opCmp(cast(E)Duration(12)) == 0); assert((cast(D)Duration(-12)).opCmp(cast(E)Duration(-12)) == 0); assert((cast(D)Duration(10)).opCmp(cast(E)Duration(12)) < 0); assert((cast(D)Duration(-12)).opCmp(cast(E)Duration(12)) < 0); assert((cast(D)Duration(12)).opCmp(cast(E)Duration(10)) > 0); assert((cast(D)Duration(12)).opCmp(cast(E)Duration(-12)) > 0); assert(copy(cast(D)Duration(12)).opCmp(cast(E)Duration(12)) == 0); assert(copy(cast(D)Duration(-12)).opCmp(cast(E)Duration(-12)) == 0); assert(copy(cast(D)Duration(10)).opCmp(cast(E)Duration(12)) < 0); assert(copy(cast(D)Duration(-12)).opCmp(cast(E)Duration(12)) < 0); assert(copy(cast(D)Duration(12)).opCmp(cast(E)Duration(10)) > 0); assert(copy(cast(D)Duration(12)).opCmp(cast(E)Duration(-12)) > 0); assert((cast(D)Duration(12)).opCmp(copy(cast(E)Duration(12))) == 0); assert((cast(D)Duration(-12)).opCmp(copy(cast(E)Duration(-12))) == 0); assert((cast(D)Duration(10)).opCmp(copy(cast(E)Duration(12))) < 0); assert((cast(D)Duration(-12)).opCmp(copy(cast(E)Duration(12))) < 0); assert((cast(D)Duration(12)).opCmp(copy(cast(E)Duration(10))) > 0); assert((cast(D)Duration(12)).opCmp(copy(cast(E)Duration(-12))) > 0); } } } /++ Adds, subtracts or calculates the modulo of two durations. The legal types of arithmetic for $(D Duration) using this operator are $(TABLE $(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD %) $(TD Duration) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD +) $(TD TickDuration) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD -) $(TD TickDuration) $(TD -->) $(TD Duration)) ) Params: rhs = The duration to add to or subtract from this $(D Duration). +/ Duration opBinary(string op, D)(D rhs) const nothrow @nogc if(((op == "+" || op == "-" || op == "%") && is(_Unqual!D == Duration)) || ((op == "+" || op == "-") && is(_Unqual!D == TickDuration))) { static if(is(_Unqual!D == Duration)) return Duration(mixin("_hnsecs " ~ op ~ " rhs._hnsecs")); else if(is(_Unqual!D == TickDuration)) return Duration(mixin("_hnsecs " ~ op ~ " rhs.hnsecs")); } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { foreach(E; _TypeTuple!(Duration, const Duration, immutable Duration)) { assert((cast(D)Duration(5)) + (cast(E)Duration(7)) == Duration(12)); assert((cast(D)Duration(5)) - (cast(E)Duration(7)) == Duration(-2)); assert((cast(D)Duration(5)) % (cast(E)Duration(7)) == Duration(5)); assert((cast(D)Duration(7)) + (cast(E)Duration(5)) == Duration(12)); assert((cast(D)Duration(7)) - (cast(E)Duration(5)) == Duration(2)); assert((cast(D)Duration(7)) % (cast(E)Duration(5)) == Duration(2)); assert((cast(D)Duration(5)) + (cast(E)Duration(-7)) == Duration(-2)); assert((cast(D)Duration(5)) - (cast(E)Duration(-7)) == Duration(12)); assert((cast(D)Duration(5)) % (cast(E)Duration(-7)) == Duration(5)); assert((cast(D)Duration(7)) + (cast(E)Duration(-5)) == Duration(2)); assert((cast(D)Duration(7)) - (cast(E)Duration(-5)) == Duration(12)); assert((cast(D)Duration(7)) % (cast(E)Duration(-5)) == Duration(2)); assert((cast(D)Duration(-5)) + (cast(E)Duration(7)) == Duration(2)); assert((cast(D)Duration(-5)) - (cast(E)Duration(7)) == Duration(-12)); assert((cast(D)Duration(-5)) % (cast(E)Duration(7)) == Duration(-5)); assert((cast(D)Duration(-7)) + (cast(E)Duration(5)) == Duration(-2)); assert((cast(D)Duration(-7)) - (cast(E)Duration(5)) == Duration(-12)); assert((cast(D)Duration(-7)) % (cast(E)Duration(5)) == Duration(-2)); assert((cast(D)Duration(-5)) + (cast(E)Duration(-7)) == Duration(-12)); assert((cast(D)Duration(-5)) - (cast(E)Duration(-7)) == Duration(2)); assert((cast(D)Duration(-5)) % (cast(E)Duration(7)) == Duration(-5)); assert((cast(D)Duration(-7)) + (cast(E)Duration(-5)) == Duration(-12)); assert((cast(D)Duration(-7)) - (cast(E)Duration(-5)) == Duration(-2)); assert((cast(D)Duration(-7)) % (cast(E)Duration(5)) == Duration(-2)); } foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { assertApprox((cast(D)Duration(5)) + cast(T)TickDuration.from!"usecs"(7), Duration(70), Duration(80)); assertApprox((cast(D)Duration(5)) - cast(T)TickDuration.from!"usecs"(7), Duration(-70), Duration(-60)); assertApprox((cast(D)Duration(7)) + cast(T)TickDuration.from!"usecs"(5), Duration(52), Duration(62)); assertApprox((cast(D)Duration(7)) - cast(T)TickDuration.from!"usecs"(5), Duration(-48), Duration(-38)); assertApprox((cast(D)Duration(5)) + cast(T)TickDuration.from!"usecs"(-7), Duration(-70), Duration(-60)); assertApprox((cast(D)Duration(5)) - cast(T)TickDuration.from!"usecs"(-7), Duration(70), Duration(80)); assertApprox((cast(D)Duration(7)) + cast(T)TickDuration.from!"usecs"(-5), Duration(-48), Duration(-38)); assertApprox((cast(D)Duration(7)) - cast(T)TickDuration.from!"usecs"(-5), Duration(52), Duration(62)); assertApprox((cast(D)Duration(-5)) + cast(T)TickDuration.from!"usecs"(7), Duration(60), Duration(70)); assertApprox((cast(D)Duration(-5)) - cast(T)TickDuration.from!"usecs"(7), Duration(-80), Duration(-70)); assertApprox((cast(D)Duration(-7)) + cast(T)TickDuration.from!"usecs"(5), Duration(38), Duration(48)); assertApprox((cast(D)Duration(-7)) - cast(T)TickDuration.from!"usecs"(5), Duration(-62), Duration(-52)); assertApprox((cast(D)Duration(-5)) + cast(T)TickDuration.from!"usecs"(-7), Duration(-80), Duration(-70)); assertApprox((cast(D)Duration(-5)) - cast(T)TickDuration.from!"usecs"(-7), Duration(60), Duration(70)); assertApprox((cast(D)Duration(-7)) + cast(T)TickDuration.from!"usecs"(-5), Duration(-62), Duration(-52)); assertApprox((cast(D)Duration(-7)) - cast(T)TickDuration.from!"usecs"(-5), Duration(38), Duration(48)); } } } /++ Adds or subtracts two durations. The legal types of arithmetic for $(D Duration) using this operator are $(TABLE $(TR $(TD TickDuration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration)) $(TR $(TD TickDuration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration)) ) Params: lhs = The $(D TickDuration) to add to this $(D Duration) or to subtract this $(D Duration) from. +/ Duration opBinaryRight(string op, D)(D lhs) const nothrow @nogc if((op == "+" || op == "-") && is(_Unqual!D == TickDuration)) { return Duration(mixin("lhs.hnsecs " ~ op ~ " _hnsecs")); } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { assertApprox((cast(T)TickDuration.from!"usecs"(7)) + cast(D)Duration(5), Duration(70), Duration(80)); assertApprox((cast(T)TickDuration.from!"usecs"(7)) - cast(D)Duration(5), Duration(60), Duration(70)); assertApprox((cast(T)TickDuration.from!"usecs"(5)) + cast(D)Duration(7), Duration(52), Duration(62)); assertApprox((cast(T)TickDuration.from!"usecs"(5)) - cast(D)Duration(7), Duration(38), Duration(48)); assertApprox((cast(T)TickDuration.from!"usecs"(-7)) + cast(D)Duration(5), Duration(-70), Duration(-60)); assertApprox((cast(T)TickDuration.from!"usecs"(-7)) - cast(D)Duration(5), Duration(-80), Duration(-70)); assertApprox((cast(T)TickDuration.from!"usecs"(-5)) + cast(D)Duration(7), Duration(-48), Duration(-38)); assertApprox((cast(T)TickDuration.from!"usecs"(-5)) - cast(D)Duration(7), Duration(-62), Duration(-52)); assertApprox((cast(T)TickDuration.from!"usecs"(7)) + (cast(D)Duration(-5)), Duration(60), Duration(70)); assertApprox((cast(T)TickDuration.from!"usecs"(7)) - (cast(D)Duration(-5)), Duration(70), Duration(80)); assertApprox((cast(T)TickDuration.from!"usecs"(5)) + (cast(D)Duration(-7)), Duration(38), Duration(48)); assertApprox((cast(T)TickDuration.from!"usecs"(5)) - (cast(D)Duration(-7)), Duration(52), Duration(62)); assertApprox((cast(T)TickDuration.from!"usecs"(-7)) + cast(D)Duration(-5), Duration(-80), Duration(-70)); assertApprox((cast(T)TickDuration.from!"usecs"(-7)) - cast(D)Duration(-5), Duration(-70), Duration(-60)); assertApprox((cast(T)TickDuration.from!"usecs"(-5)) + cast(D)Duration(-7), Duration(-62), Duration(-52)); assertApprox((cast(T)TickDuration.from!"usecs"(-5)) - cast(D)Duration(-7), Duration(-48), Duration(-38)); } } } /++ Adds, subtracts or calculates the modulo of two durations as well as assigning the result to this $(D Duration). The legal types of arithmetic for $(D Duration) using this operator are $(TABLE $(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD %) $(TD Duration) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD +) $(TD TickDuration) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD -) $(TD TickDuration) $(TD -->) $(TD Duration)) ) Params: rhs = The duration to add to or subtract from this $(D Duration). +/ ref Duration opOpAssign(string op, D)(in D rhs) nothrow @nogc if(((op == "+" || op == "-" || op == "%") && is(_Unqual!D == Duration)) || ((op == "+" || op == "-") && is(_Unqual!D == TickDuration))) { static if(is(_Unqual!D == Duration)) mixin("_hnsecs " ~ op ~ "= rhs._hnsecs;"); else if(is(_Unqual!D == TickDuration)) mixin("_hnsecs " ~ op ~ "= rhs.hnsecs;"); return this; } unittest { static void test1(string op, E)(Duration actual, in E rhs, Duration expected, size_t line = __LINE__) { if(mixin("actual " ~ op ~ " rhs") != expected) throw new AssertError("op failed", __FILE__, line); if(actual != expected) throw new AssertError("op assign failed", __FILE__, line); } static void test2(string op, E) (Duration actual, in E rhs, Duration lower, Duration upper, size_t line = __LINE__) { assertApprox(mixin("actual " ~ op ~ " rhs"), lower, upper, "op failed", line); assertApprox(actual, lower, upper, "op assign failed", line); } foreach(E; _TypeTuple!(Duration, const Duration, immutable Duration)) { test1!"+="(Duration(5), (cast(E)Duration(7)), Duration(12)); test1!"-="(Duration(5), (cast(E)Duration(7)), Duration(-2)); test1!"%="(Duration(5), (cast(E)Duration(7)), Duration(5)); test1!"+="(Duration(7), (cast(E)Duration(5)), Duration(12)); test1!"-="(Duration(7), (cast(E)Duration(5)), Duration(2)); test1!"%="(Duration(7), (cast(E)Duration(5)), Duration(2)); test1!"+="(Duration(5), (cast(E)Duration(-7)), Duration(-2)); test1!"-="(Duration(5), (cast(E)Duration(-7)), Duration(12)); test1!"%="(Duration(5), (cast(E)Duration(-7)), Duration(5)); test1!"+="(Duration(7), (cast(E)Duration(-5)), Duration(2)); test1!"-="(Duration(7), (cast(E)Duration(-5)), Duration(12)); test1!"%="(Duration(7), (cast(E)Duration(-5)), Duration(2)); test1!"+="(Duration(-5), (cast(E)Duration(7)), Duration(2)); test1!"-="(Duration(-5), (cast(E)Duration(7)), Duration(-12)); test1!"%="(Duration(-5), (cast(E)Duration(7)), Duration(-5)); test1!"+="(Duration(-7), (cast(E)Duration(5)), Duration(-2)); test1!"-="(Duration(-7), (cast(E)Duration(5)), Duration(-12)); test1!"%="(Duration(-7), (cast(E)Duration(5)), Duration(-2)); test1!"+="(Duration(-5), (cast(E)Duration(-7)), Duration(-12)); test1!"-="(Duration(-5), (cast(E)Duration(-7)), Duration(2)); test1!"%="(Duration(-5), (cast(E)Duration(-7)), Duration(-5)); test1!"+="(Duration(-7), (cast(E)Duration(-5)), Duration(-12)); test1!"-="(Duration(-7), (cast(E)Duration(-5)), Duration(-2)); test1!"%="(Duration(-7), (cast(E)Duration(-5)), Duration(-2)); } foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { test2!"+="(Duration(5), cast(T)TickDuration.from!"usecs"(7), Duration(70), Duration(80)); test2!"-="(Duration(5), cast(T)TickDuration.from!"usecs"(7), Duration(-70), Duration(-60)); test2!"+="(Duration(7), cast(T)TickDuration.from!"usecs"(5), Duration(52), Duration(62)); test2!"-="(Duration(7), cast(T)TickDuration.from!"usecs"(5), Duration(-48), Duration(-38)); test2!"+="(Duration(5), cast(T)TickDuration.from!"usecs"(-7), Duration(-70), Duration(-60)); test2!"-="(Duration(5), cast(T)TickDuration.from!"usecs"(-7), Duration(70), Duration(80)); test2!"+="(Duration(7), cast(T)TickDuration.from!"usecs"(-5), Duration(-48), Duration(-38)); test2!"-="(Duration(7), cast(T)TickDuration.from!"usecs"(-5), Duration(52), Duration(62)); test2!"+="(Duration(-5), cast(T)TickDuration.from!"usecs"(7), Duration(60), Duration(70)); test2!"-="(Duration(-5), cast(T)TickDuration.from!"usecs"(7), Duration(-80), Duration(-70)); test2!"+="(Duration(-7), cast(T)TickDuration.from!"usecs"(5), Duration(38), Duration(48)); test2!"-="(Duration(-7), cast(T)TickDuration.from!"usecs"(5), Duration(-62), Duration(-52)); test2!"+="(Duration(-5), cast(T)TickDuration.from!"usecs"(-7), Duration(-80), Duration(-70)); test2!"-="(Duration(-5), cast(T)TickDuration.from!"usecs"(-7), Duration(60), Duration(70)); test2!"+="(Duration(-7), cast(T)TickDuration.from!"usecs"(-5), Duration(-62), Duration(-52)); test2!"-="(Duration(-7), cast(T)TickDuration.from!"usecs"(-5), Duration(38), Duration(48)); } foreach(D; _TypeTuple!(const Duration, immutable Duration)) { foreach(E; _TypeTuple!(Duration, const Duration, immutable Duration, TickDuration, const TickDuration, immutable TickDuration)) { D lhs = D(120); E rhs = E(120); static assert(!__traits(compiles, lhs += rhs), D.stringof ~ " " ~ E.stringof); } } } /++ Multiplies or divides the duration by an integer value. The legal types of arithmetic for $(D Duration) using this operator overload are $(TABLE $(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration)) ) Params: value = The value to multiply this $(D Duration) by. +/ Duration opBinary(string op)(long value) const nothrow @nogc if(op == "*" || op == "/") { mixin("return Duration(_hnsecs " ~ op ~ " value);"); } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { assert((cast(D)Duration(5)) * 7 == Duration(35)); assert((cast(D)Duration(7)) * 5 == Duration(35)); assert((cast(D)Duration(5)) * -7 == Duration(-35)); assert((cast(D)Duration(7)) * -5 == Duration(-35)); assert((cast(D)Duration(-5)) * 7 == Duration(-35)); assert((cast(D)Duration(-7)) * 5 == Duration(-35)); assert((cast(D)Duration(-5)) * -7 == Duration(35)); assert((cast(D)Duration(-7)) * -5 == Duration(35)); assert((cast(D)Duration(5)) * 0 == Duration(0)); assert((cast(D)Duration(-5)) * 0 == Duration(0)); } } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { assert((cast(D)Duration(5)) / 7 == Duration(0)); assert((cast(D)Duration(7)) / 5 == Duration(1)); assert((cast(D)Duration(5)) / -7 == Duration(0)); assert((cast(D)Duration(7)) / -5 == Duration(-1)); assert((cast(D)Duration(-5)) / 7 == Duration(0)); assert((cast(D)Duration(-7)) / 5 == Duration(-1)); assert((cast(D)Duration(-5)) / -7 == Duration(0)); assert((cast(D)Duration(-7)) / -5 == Duration(1)); } } /++ Multiplies/Divides the duration by an integer value as well as assigning the result to this $(D Duration). The legal types of arithmetic for $(D Duration) using this operator overload are $(TABLE $(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration)) $(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration)) ) Params: value = The value to multiply/divide this $(D Duration) by. +/ ref Duration opOpAssign(string op)(long value) nothrow @nogc if(op == "*" || op == "/") { mixin("_hnsecs " ~ op ~ "= value;"); return this; } unittest { static void test(D)(D actual, long value, Duration expected, size_t line = __LINE__) { if((actual *= value) != expected) throw new AssertError("op failed", __FILE__, line); if(actual != expected) throw new AssertError("op assign failed", __FILE__, line); } test(Duration(5), 7, Duration(35)); test(Duration(7), 5, Duration(35)); test(Duration(5), -7, Duration(-35)); test(Duration(7), -5, Duration(-35)); test(Duration(-5), 7, Duration(-35)); test(Duration(-7), 5, Duration(-35)); test(Duration(-5), -7, Duration(35)); test(Duration(-7), -5, Duration(35)); test(Duration(5), 0, Duration(0)); test(Duration(-5), 0, Duration(0)); const cdur = Duration(12); immutable idur = Duration(12); static assert(!__traits(compiles, cdur *= 12)); static assert(!__traits(compiles, idur *= 12)); } unittest { static void test(Duration actual, long value, Duration expected, size_t line = __LINE__) { if((actual /= value) != expected) throw new AssertError("op failed", __FILE__, line); if(actual != expected) throw new AssertError("op assign failed", __FILE__, line); } test(Duration(5), 7, Duration(0)); test(Duration(7), 5, Duration(1)); test(Duration(5), -7, Duration(0)); test(Duration(7), -5, Duration(-1)); test(Duration(-5), 7, Duration(0)); test(Duration(-7), 5, Duration(-1)); test(Duration(-5), -7, Duration(0)); test(Duration(-7), -5, Duration(1)); const cdur = Duration(12); immutable idur = Duration(12); static assert(!__traits(compiles, cdur /= 12)); static assert(!__traits(compiles, idur /= 12)); } /++ Divides two durations. The legal types of arithmetic for $(D Duration) using this operator are $(TABLE $(TR $(TD Duration) $(TD /) $(TD Duration) $(TD -->) $(TD long)) ) Params: rhs = The duration to divide this $(D Duration) by. +/ long opBinary(string op)(Duration rhs) const nothrow @nogc if(op == "/") { return _hnsecs / rhs._hnsecs; } unittest { assert(Duration(5) / Duration(7) == 0); assert(Duration(7) / Duration(5) == 1); assert(Duration(8) / Duration(4) == 2); assert(Duration(5) / Duration(-7) == 0); assert(Duration(7) / Duration(-5) == -1); assert(Duration(8) / Duration(-4) == -2); assert(Duration(-5) / Duration(7) == 0); assert(Duration(-7) / Duration(5) == -1); assert(Duration(-8) / Duration(4) == -2); assert(Duration(-5) / Duration(-7) == 0); assert(Duration(-7) / Duration(-5) == 1); assert(Duration(-8) / Duration(-4) == 2); } /++ Multiplies an integral value and a $(D Duration). The legal types of arithmetic for $(D Duration) using this operator overload are $(TABLE $(TR $(TD long) $(TD *) $(TD Duration) $(TD -->) $(TD Duration)) ) Params: value = The number of units to multiply this $(D Duration) by. +/ Duration opBinaryRight(string op)(long value) const nothrow @nogc if(op == "*") { return opBinary!op(value); } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { assert(5 * cast(D)Duration(7) == Duration(35)); assert(7 * cast(D)Duration(5) == Duration(35)); assert(5 * cast(D)Duration(-7) == Duration(-35)); assert(7 * cast(D)Duration(-5) == Duration(-35)); assert(-5 * cast(D)Duration(7) == Duration(-35)); assert(-7 * cast(D)Duration(5) == Duration(-35)); assert(-5 * cast(D)Duration(-7) == Duration(35)); assert(-7 * cast(D)Duration(-5) == Duration(35)); assert(0 * cast(D)Duration(-5) == Duration(0)); assert(0 * cast(D)Duration(5) == Duration(0)); } } /++ Returns the negation of this $(D Duration). +/ Duration opUnary(string op)() const nothrow @nogc if(op == "-") { return Duration(-_hnsecs); } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { assert(-(cast(D)Duration(7)) == Duration(-7)); assert(-(cast(D)Duration(5)) == Duration(-5)); assert(-(cast(D)Duration(-7)) == Duration(7)); assert(-(cast(D)Duration(-5)) == Duration(5)); assert(-(cast(D)Duration(0)) == Duration(0)); } } /++ Returns a $(LREF TickDuration) with the same number of hnsecs as this $(D Duration). Note that the conventional way to convert between $(D Duration) and $(D TickDuration) is using $(XREF conv, to), e.g.: $(D duration.to!TickDuration()) +/ TickDuration opCast(T)() const nothrow @nogc if(is(_Unqual!T == TickDuration)) { return TickDuration.from!"hnsecs"(_hnsecs); } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { foreach(units; _TypeTuple!("seconds", "msecs", "usecs", "hnsecs")) { enum unitsPerSec = convert!("seconds", units)(1); if(TickDuration.ticksPerSec >= unitsPerSec) { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { auto t = TickDuration.from!units(1); assertApprox(cast(T)cast(D)dur!units(1), t - TickDuration(1), t + TickDuration(1), units); t = TickDuration.from!units(2); assertApprox(cast(T)cast(D)dur!units(2), t - TickDuration(1), t + TickDuration(1), units); } } else { auto t = TickDuration.from!units(1); assert(t.to!(units, long)() == 0, units); t = TickDuration.from!units(1_000_000); assert(t.to!(units, long)() >= 900_000, units); assert(t.to!(units, long)() <= 1_100_000, units); } } } } //Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=5747 is fixed. Duration opCast(T)() const nothrow @nogc if(is(_Unqual!T == Duration)) { return this; } /++ Splits out the Duration into the given units. split takes the list of time units to split out as template arguments. The time unit strings must be given in decreasing order. How it returns the values for those units depends on the overload used. The overload which accepts function arguments takes integral types in the order that the time unit strings were given, and those integers are passed by $(D ref). split assigns the values for the units to each corresponding integer. Any integral type may be used, but no attempt is made to prevent integer overflow, so don't use small integral types in circumstances where the values for those units aren't likely to fit in an integral type that small. The overload with no arguments returns the values for the units in a struct with members whose names are the same as the given time unit strings. The members are all $(D long)s. This overload will also work with no time strings being given, in which case $(I all) of the time units from weeks through hnsecs will be provided (but no nsecs, since it would always be $(D 0)). For both overloads, the entire value of the Duration is split among the units (rather than splitting the Duration across all units and then only providing the values for the requested units), so if only one unit is given, the result is equivalent to $(LREF total). $(D "nsecs") is accepted by split, but $(D "years") and $(D "months") are not. For negative durations, all of the split values will be negative. +/ template split(units...) if(allAreAcceptedUnits!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs", "nsecs")(units) && unitsAreInDescendingOrder(units)) { /++ Ditto +/ void split(Args...)(out Args args) const nothrow @nogc if(units.length != 0 && args.length == units.length && allAreMutableIntegralTypes!Args) { long hnsecs = _hnsecs; foreach(i, unit; units) { static if(unit == "nsecs") args[i] = cast(typeof(args[i]))convert!("hnsecs", "nsecs")(hnsecs); else args[i] = cast(typeof(args[i]))splitUnitsFromHNSecs!unit(hnsecs); } } /++ Ditto +/ auto split() const nothrow @nogc { static if(units.length == 0) return split!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs")(); else { static string genMemberDecls() { string retval; foreach(unit; units) { retval ~= "long "; retval ~= unit; retval ~= "; "; } return retval; } static struct SplitUnits { mixin(genMemberDecls()); } static string genSplitCall() { auto retval = "split("; foreach(i, unit; units) { retval ~= "su."; retval ~= unit; if(i < units.length - 1) retval ~= ", "; else retval ~= ");"; } return retval; } SplitUnits su = void; mixin(genSplitCall()); return su; } } /+ Whether all of the given arguments are integral types. +/ private template allAreMutableIntegralTypes(Args...) { static if(Args.length == 0) enum allAreMutableIntegralTypes = true; else static if(!is(Args[0] == long) && !is(Args[0] == int) && !is(Args[0] == short) && !is(Args[0] == byte) && !is(Args[0] == ulong) && !is(Args[0] == uint) && !is(Args[0] == ushort) && !is(Args[0] == ubyte)) { enum allAreMutableIntegralTypes = false; } else enum allAreMutableIntegralTypes = allAreMutableIntegralTypes!(Args[1 .. $]); } unittest { foreach(T; _TypeTuple!(long, int, short, byte, ulong, uint, ushort, ubyte)) static assert(allAreMutableIntegralTypes!T); foreach(T; _TypeTuple!(long, int, short, byte, ulong, uint, ushort, ubyte)) static assert(!allAreMutableIntegralTypes!(const T)); foreach(T; _TypeTuple!(char, wchar, dchar, float, double, real, string)) static assert(!allAreMutableIntegralTypes!T); static assert(allAreMutableIntegralTypes!(long, int, short, byte)); static assert(!allAreMutableIntegralTypes!(long, int, short, char, byte)); static assert(!allAreMutableIntegralTypes!(long, int*, short)); } } /// unittest { { auto d = dur!"days"(12) + dur!"minutes"(7) + dur!"usecs"(501223); long days; int seconds; short msecs; d.split!("days", "seconds", "msecs")(days, seconds, msecs); assert(days == 12); assert(seconds == 7 * 60); assert(msecs == 501); auto splitStruct = d.split!("days", "seconds", "msecs")(); assert(splitStruct.days == 12); assert(splitStruct.seconds == 7 * 60); assert(splitStruct.msecs == 501); auto fullSplitStruct = d.split(); assert(fullSplitStruct.weeks == 1); assert(fullSplitStruct.days == 5); assert(fullSplitStruct.hours == 0); assert(fullSplitStruct.minutes == 7); assert(fullSplitStruct.seconds == 0); assert(fullSplitStruct.msecs == 501); assert(fullSplitStruct.usecs == 223); assert(fullSplitStruct.hnsecs == 0); assert(d.split!"minutes"().minutes == d.total!"minutes"); } { auto d = dur!"days"(12); assert(d.split!"weeks"().weeks == 1); assert(d.split!"days"().days == 12); assert(d.split().weeks == 1); assert(d.split().days == 5); } { auto d = dur!"days"(7) + dur!"hnsecs"(42); assert(d.split!("seconds", "nsecs")().nsecs == 4200); } { auto d = dur!"days"(-7) + dur!"hours"(-9); auto result = d.split!("days", "hours")(); assert(result.days == -7); assert(result.hours == -9); } } pure nothrow unittest { foreach(D; _TypeTuple!(const Duration, immutable Duration)) { D d = dur!"weeks"(3) + dur!"days"(5) + dur!"hours"(19) + dur!"minutes"(7) + dur!"seconds"(2) + dur!"hnsecs"(1234567); byte weeks; ubyte days; short hours; ushort minutes; int seconds; uint msecs; long usecs; ulong hnsecs; long nsecs; d.split!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs", "nsecs") (weeks, days, hours, minutes, seconds, msecs, usecs, hnsecs, nsecs); assert(weeks == 3); assert(days == 5); assert(hours == 19); assert(minutes == 7); assert(seconds == 2); assert(msecs == 123); assert(usecs == 456); assert(hnsecs == 7); assert(nsecs == 0); d.split!("weeks", "days", "hours", "seconds", "usecs")(weeks, days, hours, seconds, usecs); assert(weeks == 3); assert(days == 5); assert(hours == 19); assert(seconds == 422); assert(usecs == 123456); d.split!("days", "minutes", "seconds", "nsecs")(days, minutes, seconds, nsecs); assert(days == 26); assert(minutes == 1147); assert(seconds == 2); assert(nsecs == 123456700); d.split!("minutes", "msecs", "usecs", "hnsecs")(minutes, msecs, usecs, hnsecs); assert(minutes == 38587); assert(msecs == 2123); assert(usecs == 456); assert(hnsecs == 7); { auto result = d.split!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs", "nsecs"); assert(result.weeks == 3); assert(result.days == 5); assert(result.hours == 19); assert(result.minutes == 7); assert(result.seconds == 2); assert(result.msecs == 123); assert(result.usecs == 456); assert(result.hnsecs == 7); assert(result.nsecs == 0); } { auto result = d.split!("weeks", "days", "hours", "seconds", "usecs"); assert(result.weeks == 3); assert(result.days == 5); assert(result.hours == 19); assert(result.seconds == 422); assert(result.usecs == 123456); } { auto result = d.split!("days", "minutes", "seconds", "nsecs")(); assert(result.days == 26); assert(result.minutes == 1147); assert(result.seconds == 2); assert(result.nsecs == 123456700); } { auto result = d.split!("minutes", "msecs", "usecs", "hnsecs")(); assert(result.minutes == 38587); assert(result.msecs == 2123); assert(result.usecs == 456); assert(result.hnsecs == 7); } { auto result = d.split(); assert(result.weeks == 3); assert(result.days == 5); assert(result.hours == 19); assert(result.minutes == 7); assert(result.seconds == 2); assert(result.msecs == 123); assert(result.usecs == 456); assert(result.hnsecs == 7); static assert(!is(typeof(result.nsecs))); } static assert(!is(typeof(d.split("seconds", "hnsecs")(seconds)))); static assert(!is(typeof(d.split("hnsecs", "seconds", "minutes")(hnsecs, seconds, minutes)))); static assert(!is(typeof(d.split("hnsecs", "seconds", "msecs")(hnsecs, seconds, msecs)))); static assert(!is(typeof(d.split("seconds", "hnecs", "msecs")(seconds, hnsecs, msecs)))); static assert(!is(typeof(d.split("seconds", "msecs", "msecs")(seconds, msecs, msecs)))); static assert(!is(typeof(d.split("hnsecs", "seconds", "minutes")()))); static assert(!is(typeof(d.split("hnsecs", "seconds", "msecs")()))); static assert(!is(typeof(d.split("seconds", "hnecs", "msecs")()))); static assert(!is(typeof(d.split("seconds", "msecs", "msecs")()))); alias _TypeTuple!("nsecs", "hnsecs", "usecs", "msecs", "seconds", "minutes", "hours", "days", "weeks") timeStrs; foreach(i, str; timeStrs[1 .. $]) static assert(!is(typeof(d.split!(timeStrs[i - 1], str)()))); D nd = -d; { auto result = nd.split(); assert(result.weeks == -3); assert(result.days == -5); assert(result.hours == -19); assert(result.minutes == -7); assert(result.seconds == -2); assert(result.msecs == -123); assert(result.usecs == -456); assert(result.hnsecs == -7); } { auto result = nd.split!("weeks", "days", "hours", "minutes", "seconds", "nsecs")(); assert(result.weeks == -3); assert(result.days == -5); assert(result.hours == -19); assert(result.minutes == -7); assert(result.seconds == -2); assert(result.nsecs == -123456700); } } } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated("Please use split instead. get was too frequently confused for total.") long get(string units)() const nothrow @nogc if(units == "weeks" || units == "days" || units == "hours" || units == "minutes" || units == "seconds") { static if(units == "weeks") return getUnitsFromHNSecs!"weeks"(_hnsecs); else { immutable hnsecs = removeUnitsFromHNSecs!(nextLargerTimeUnits!units)(_hnsecs); return getUnitsFromHNSecs!units(hnsecs); } } /// deprecated unittest { assert(dur!"weeks"(12).get!"weeks" == 12); assert(dur!"weeks"(12).get!"days" == 0); assert(dur!"days"(13).get!"weeks" == 1); assert(dur!"days"(13).get!"days" == 6); assert(dur!"hours"(49).get!"days" == 2); assert(dur!"hours"(49).get!"hours" == 1); } deprecated unittest { foreach(D; _TypeTuple!(const Duration, immutable Duration)) { assert((cast(D)dur!"weeks"(12)).get!"weeks" == 12); assert((cast(D)dur!"weeks"(12)).get!"days" == 0); assert((cast(D)dur!"days"(13)).get!"weeks" == 1); assert((cast(D)dur!"days"(13)).get!"days" == 6); assert((cast(D)dur!"hours"(49)).get!"days" == 2); assert((cast(D)dur!"hours"(49)).get!"hours" == 1); } } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated(`Please use split instead. The functions which wrapped get were too frequently confused with total.`) @property long weeks() const nothrow @nogc { return get!"weeks"(); } /// deprecated unittest { assert(dur!"weeks"(12).weeks == 12); assert(dur!"days"(13).weeks == 1); } deprecated unittest { foreach(D; _TypeTuple!(const Duration, immutable Duration)) { assert((cast(D)dur!"weeks"(12)).weeks == 12); assert((cast(D)dur!"days"(13)).weeks == 1); } } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated(`Please use split instead. days was too frequently confused for total!"days".`) @property long days() const nothrow @nogc { return get!"days"(); } /// deprecated unittest { assert(dur!"weeks"(12).days == 0); assert(dur!"days"(13).days == 6); assert(dur!"hours"(49).days == 2); } deprecated unittest { foreach(D; _TypeTuple!(const Duration, immutable Duration)) { assert((cast(D)dur!"weeks"(12)).days == 0); assert((cast(D)dur!"days"(13)).days == 6); assert((cast(D)dur!"hours"(49)).days == 2); } } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated(`Please use split instead. hours was too frequently confused for total!"hours".`) @property long hours() const nothrow @nogc { return get!"hours"(); } /// deprecated unittest { assert(dur!"days"(8).hours == 0); assert(dur!"hours"(49).hours == 1); assert(dur!"minutes"(121).hours == 2); } deprecated unittest { foreach(D; _TypeTuple!(const Duration, immutable Duration)) { assert((cast(D)dur!"days"(8)).hours == 0); assert((cast(D)dur!"hours"(49)).hours == 1); assert((cast(D)dur!"minutes"(121)).hours == 2); } } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated(`Please use split instead. minutes was too frequently confused for total!"minutes".`) @property long minutes() const nothrow @nogc { return get!"minutes"(); } /// deprecated unittest { assert(dur!"hours"(47).minutes == 0); assert(dur!"minutes"(127).minutes == 7); assert(dur!"seconds"(121).minutes == 2); } deprecated unittest { foreach(D; _TypeTuple!(const Duration, immutable Duration)) { assert((cast(D)dur!"hours"(47)).minutes == 0); assert((cast(D)dur!"minutes"(127)).minutes == 7); assert((cast(D)dur!"seconds"(121)).minutes == 2); } } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated(`Please use split instead. seconds was too frequently confused for total!"seconds".`) @property long seconds() const nothrow @nogc { return get!"seconds"(); } /// deprecated unittest { assert(dur!"minutes"(47).seconds == 0); assert(dur!"seconds"(127).seconds == 7); assert(dur!"msecs"(1217).seconds == 1); } deprecated unittest { foreach(D; _TypeTuple!(const Duration, immutable Duration)) { assert((cast(D)dur!"minutes"(47)).seconds == 0); assert((cast(D)dur!"seconds"(127)).seconds == 7); assert((cast(D)dur!"msecs"(1217)).seconds == 1); } } // Explicitly undocumented. It will be removed in August 2016. @@@DEPRECATED_2016-08@@@ deprecated(`Please use split instead.`) @property FracSec fracSec() const nothrow { try { immutable hnsecs = removeUnitsFromHNSecs!("seconds")(_hnsecs); return FracSec.from!"hnsecs"(hnsecs); } catch(Exception e) assert(0, "FracSec.from!\"hnsecs\"() threw."); } /// deprecated unittest { assert(dur!"msecs"(1000).fracSec == FracSec.from!"msecs"(0)); assert(dur!"msecs"(1217).fracSec == FracSec.from!"msecs"(217)); assert(dur!"usecs"(43).fracSec == FracSec.from!"usecs"(43)); assert(dur!"hnsecs"(50_007).fracSec == FracSec.from!"hnsecs"(50_007)); assert(dur!"nsecs"(62_127).fracSec == FracSec.from!"nsecs"(62_100)); assert(dur!"msecs"(-1000).fracSec == FracSec.from!"msecs"(-0)); assert(dur!"msecs"(-1217).fracSec == FracSec.from!"msecs"(-217)); assert(dur!"usecs"(-43).fracSec == FracSec.from!"usecs"(-43)); assert(dur!"hnsecs"(-50_007).fracSec == FracSec.from!"hnsecs"(-50_007)); assert(dur!"nsecs"(-62_127).fracSec == FracSec.from!"nsecs"(-62_100)); } deprecated unittest { foreach(D; _TypeTuple!(const Duration, immutable Duration)) { assert((cast(D)dur!"msecs"(1000)).fracSec == FracSec.from!"msecs"(0)); assert((cast(D)dur!"msecs"(1217)).fracSec == FracSec.from!"msecs"(217)); assert((cast(D)dur!"usecs"(43)).fracSec == FracSec.from!"usecs"(43)); assert((cast(D)dur!"hnsecs"(50_007)).fracSec == FracSec.from!"hnsecs"(50_007)); assert((cast(D)dur!"nsecs"(62_127)).fracSec == FracSec.from!"nsecs"(62_100)); assert((cast(D)dur!"msecs"(-1000)).fracSec == FracSec.from!"msecs"(-0)); assert((cast(D)dur!"msecs"(-1217)).fracSec == FracSec.from!"msecs"(-217)); assert((cast(D)dur!"usecs"(-43)).fracSec == FracSec.from!"usecs"(-43)); assert((cast(D)dur!"hnsecs"(-50_007)).fracSec == FracSec.from!"hnsecs"(-50_007)); assert((cast(D)dur!"nsecs"(-62_127)).fracSec == FracSec.from!"nsecs"(-62_100)); } } /++ Returns the total number of the given units in this $(D Duration). So, unlike $(D split), it does not strip out the larger units. +/ @property long total(string units)() const nothrow @nogc if(units == "weeks" || units == "days" || units == "hours" || units == "minutes" || units == "seconds" || units == "msecs" || units == "usecs" || units == "hnsecs" || units == "nsecs") { static if(units == "nsecs") return convert!("hnsecs", "nsecs")(_hnsecs); else return getUnitsFromHNSecs!units(_hnsecs); } /// unittest { assert(dur!"weeks"(12).total!"weeks" == 12); assert(dur!"weeks"(12).total!"days" == 84); assert(dur!"days"(13).total!"weeks" == 1); assert(dur!"days"(13).total!"days" == 13); assert(dur!"hours"(49).total!"days" == 2); assert(dur!"hours"(49).total!"hours" == 49); assert(dur!"nsecs"(2007).total!"hnsecs" == 20); assert(dur!"nsecs"(2007).total!"nsecs" == 2000); } unittest { foreach(D; _TypeTuple!(const Duration, immutable Duration)) { assert((cast(D)dur!"weeks"(12)).total!"weeks" == 12); assert((cast(D)dur!"weeks"(12)).total!"days" == 84); assert((cast(D)dur!"days"(13)).total!"weeks" == 1); assert((cast(D)dur!"days"(13)).total!"days" == 13); assert((cast(D)dur!"hours"(49)).total!"days" == 2); assert((cast(D)dur!"hours"(49)).total!"hours" == 49); assert((cast(D)dur!"nsecs"(2007)).total!"hnsecs" == 20); assert((cast(D)dur!"nsecs"(2007)).total!"nsecs" == 2000); } } /+ Converts this $(D Duration) to a $(D string). +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() { return _toStringImpl(); } /++ Converts this $(D Duration) to a $(D string). +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() const nothrow { return _toStringImpl(); } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { assert((cast(D)Duration(0)).toString() == "0 hnsecs"); assert((cast(D)Duration(1)).toString() == "1 hnsec"); assert((cast(D)Duration(7)).toString() == "7 hnsecs"); assert((cast(D)Duration(10)).toString() == "1 μs"); assert((cast(D)Duration(20)).toString() == "2 μs"); assert((cast(D)Duration(10_000)).toString() == "1 ms"); assert((cast(D)Duration(20_000)).toString() == "2 ms"); assert((cast(D)Duration(10_000_000)).toString() == "1 sec"); assert((cast(D)Duration(20_000_000)).toString() == "2 secs"); assert((cast(D)Duration(600_000_000)).toString() == "1 minute"); assert((cast(D)Duration(1_200_000_000)).toString() == "2 minutes"); assert((cast(D)Duration(36_000_000_000)).toString() == "1 hour"); assert((cast(D)Duration(72_000_000_000)).toString() == "2 hours"); assert((cast(D)Duration(864_000_000_000)).toString() == "1 day"); assert((cast(D)Duration(1_728_000_000_000)).toString() == "2 days"); assert((cast(D)Duration(6_048_000_000_000)).toString() == "1 week"); assert((cast(D)Duration(12_096_000_000_000)).toString() == "2 weeks"); assert((cast(D)Duration(12)).toString() == "1 μs and 2 hnsecs"); assert((cast(D)Duration(120_795)).toString() == "12 ms, 79 μs, and 5 hnsecs"); assert((cast(D)Duration(12_096_020_900_003)).toString() == "2 weeks, 2 secs, 90 ms, and 3 hnsecs"); assert((cast(D)Duration(-1)).toString() == "-1 hnsecs"); assert((cast(D)Duration(-7)).toString() == "-7 hnsecs"); assert((cast(D)Duration(-10)).toString() == "-1 μs"); assert((cast(D)Duration(-20)).toString() == "-2 μs"); assert((cast(D)Duration(-10_000)).toString() == "-1 ms"); assert((cast(D)Duration(-20_000)).toString() == "-2 ms"); assert((cast(D)Duration(-10_000_000)).toString() == "-1 secs"); assert((cast(D)Duration(-20_000_000)).toString() == "-2 secs"); assert((cast(D)Duration(-600_000_000)).toString() == "-1 minutes"); assert((cast(D)Duration(-1_200_000_000)).toString() == "-2 minutes"); assert((cast(D)Duration(-36_000_000_000)).toString() == "-1 hours"); assert((cast(D)Duration(-72_000_000_000)).toString() == "-2 hours"); assert((cast(D)Duration(-864_000_000_000)).toString() == "-1 days"); assert((cast(D)Duration(-1_728_000_000_000)).toString() == "-2 days"); assert((cast(D)Duration(-6_048_000_000_000)).toString() == "-1 weeks"); assert((cast(D)Duration(-12_096_000_000_000)).toString() == "-2 weeks"); assert((cast(D)Duration(-12)).toString() == "-1 μs and -2 hnsecs"); assert((cast(D)Duration(-120_795)).toString() == "-12 ms, -79 μs, and -5 hnsecs"); assert((cast(D)Duration(-12_096_020_900_003)).toString() == "-2 weeks, -2 secs, -90 ms, and -3 hnsecs"); } } /++ Returns whether this $(D Duration) is negative. +/ @property bool isNegative() const nothrow @nogc { return _hnsecs < 0; } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { assert(!(cast(D)Duration(100)).isNegative); assert(!(cast(D)Duration(1)).isNegative); assert(!(cast(D)Duration(0)).isNegative); assert((cast(D)Duration(-1)).isNegative); assert((cast(D)Duration(-100)).isNegative); } } private: /+ Since we have two versions of toString, we have _toStringImpl so that they can share implementations. +/ string _toStringImpl() const nothrow { static void appListSep(ref string res, uint pos, bool last) nothrow { if (pos == 0) return; if (!last) res ~= ", "; else res ~= pos == 1 ? " and " : ", and "; } static void appUnitVal(string units)(ref string res, long val) nothrow { immutable plural = val != 1; string unit; static if (units == "seconds") unit = plural ? "secs" : "sec"; else static if (units == "msecs") unit = "ms"; else static if (units == "usecs") unit = "μs"; else unit = plural ? units : units[0 .. $-1]; res ~= signedToTempString(val, 10); res ~= " "; res ~= unit; } if (_hnsecs == 0) return "0 hnsecs"; template TT(T...) { alias T TT; } alias units = TT!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs"); long hnsecs = _hnsecs; string res; uint pos; foreach (unit; units) { if (auto val = splitUnitsFromHNSecs!unit(hnsecs)) { appListSep(res, pos++, hnsecs == 0); appUnitVal!unit(res, val); } if (hnsecs == 0) break; } if (hnsecs != 0) { appListSep(res, pos++, true); appUnitVal!"hnsecs"(res, hnsecs); } return res; } /+ Params: hnsecs = The total number of hecto-nanoseconds in this $(D Duration). +/ this(long hnsecs) nothrow @nogc { _hnsecs = hnsecs; } long _hnsecs; } /// unittest { import core.time; // using the dur template auto numDays = dur!"days"(12); // using the days function numDays = days(12); // alternatively using UFCS syntax numDays = 12.days; auto myTime = 100.msecs + 20_000.usecs + 30_000.hnsecs; assert(myTime == 123.msecs); } /++ Converts a $(D TickDuration) to the given units as either an integral value or a floating point value. Params: units = The units to convert to. Accepts $(D "seconds") and smaller only. T = The type to convert to (either an integral type or a floating point type). td = The TickDuration to convert +/ T to(string units, T, D)(D td) @safe pure nothrow @nogc if(is(_Unqual!D == TickDuration) && (units == "seconds" || units == "msecs" || units == "usecs" || units == "hnsecs" || units == "nsecs")) { static if(__traits(isIntegral, T) && T.sizeof >= 4) { enum unitsPerSec = convert!("seconds", units)(1); return cast(T) (td.length / (TickDuration.ticksPerSec / cast(real) unitsPerSec)); } else static if(__traits(isFloating, T)) { static if(units == "seconds") return td.length / cast(T)TickDuration.ticksPerSec; else { enum unitsPerSec = convert!("seconds", units)(1); return cast(T) (td.length / (TickDuration.ticksPerSec / cast(real) unitsPerSec)); } } else static assert(0, "Incorrect template constraint."); } /// unittest { auto t = TickDuration.from!"seconds"(1000); long tl = to!("seconds",long)(t); assert(tl == 1000); double td = to!("seconds",double)(t); assert(_abs(td - 1000) < 0.001); } unittest { void testFun(string U)() { auto t1v = 1000; auto t2v = 333; auto t1 = TickDuration.from!U(t1v); auto t2 = TickDuration.from!U(t2v); auto _str(F)(F val) { static if(is(F == int) || is(F == long)) return signedToTempString(val, 10); else return unsignedToTempString(val, 10); } foreach (F; _TypeTuple!(int,uint,long,ulong,float,double,real)) { F t1f = to!(U,F)(t1); F t2f = to!(U,F)(t2); auto t12d = t1 / t2v; auto t12m = t1 - t2; F t3f = to!(U,F)(t12d); F t4f = to!(U,F)(t12m); static if(is(F == float) || is(F == double) || is(F == real)) { assert((t1f - cast(F)t1v) <= 3.0, F.stringof ~ " " ~ U ~ " " ~ doubleToString(t1f) ~ " " ~ doubleToString(cast(F)t1v) ); assert((t2f - cast(F)t2v) <= 3.0, F.stringof ~ " " ~ U ~ " " ~ doubleToString(t2f) ~ " " ~ doubleToString(cast(F)t2v) ); assert(t3f - (cast(F)t1v) / (cast(F)t2v) <= 3.0, F.stringof ~ " " ~ U ~ " " ~ doubleToString(t3f) ~ " " ~ doubleToString((cast(F)t1v)/(cast(F)t2v)) ); assert(t4f - (cast(F)(t1v - t2v)) <= 3.0, F.stringof ~ " " ~ U ~ " " ~ doubleToString(t4f) ~ " " ~ doubleToString(cast(F)(t1v - t2v)) ); } else { // even though this should be exact math it is not as internal // in "to" floating point is used assert(_abs(t1f) - _abs(cast(F)t1v) <= 3, F.stringof ~ " " ~ U ~ " " ~ _str(t1f) ~ " " ~ _str(cast(F)t1v) ); assert(_abs(t2f) - _abs(cast(F)t2v) <= 3, F.stringof ~ " " ~ U ~ " " ~ _str(t2f) ~ " " ~ _str(cast(F)t2v) ); assert(_abs(t3f) - _abs((cast(F)t1v) / (cast(F)t2v)) <= 3, F.stringof ~ " " ~ U ~ " " ~ _str(t3f) ~ " " ~ _str((cast(F)t1v) / (cast(F)t2v)) ); assert(_abs(t4f) - _abs((cast(F)t1v) - (cast(F)t2v)) <= 3, F.stringof ~ " " ~ U ~ " " ~ _str(t4f) ~ " " ~ _str((cast(F)t1v) - (cast(F)t2v)) ); } } } testFun!"seconds"(); testFun!"msecs"(); testFun!"usecs"(); } /++ These allow you to construct a $(D Duration) from the given time units with the given length. You can either use the generic function $(D dur) and give it the units as a $(D string) or use the named aliases. The possible values for units are $(D "weeks"), $(D "days"), $(D "hours"), $(D "minutes"), $(D "seconds"), $(D "msecs") (milliseconds), $(D "usecs"), (microseconds), $(D "hnsecs") (hecto-nanoseconds, i.e. 100 ns), and $(D "nsecs"). Params: units = The time units of the $(D Duration) (e.g. $(D "days")). length = The number of units in the $(D Duration). +/ Duration dur(string units)(long length) @safe pure nothrow @nogc if(units == "weeks" || units == "days" || units == "hours" || units == "minutes" || units == "seconds" || units == "msecs" || units == "usecs" || units == "hnsecs" || units == "nsecs") { return Duration(convert!(units, "hnsecs")(length)); } alias weeks = dur!"weeks"; /// Ditto alias days = dur!"days"; /// Ditto alias hours = dur!"hours"; /// Ditto alias minutes = dur!"minutes"; /// Ditto alias seconds = dur!"seconds"; /// Ditto alias msecs = dur!"msecs"; /// Ditto alias usecs = dur!"usecs"; /// Ditto alias hnsecs = dur!"hnsecs"; /// Ditto alias nsecs = dur!"nsecs"; /// Ditto /// unittest { // Generic assert(dur!"weeks"(142).total!"weeks" == 142); assert(dur!"days"(142).total!"days" == 142); assert(dur!"hours"(142).total!"hours" == 142); assert(dur!"minutes"(142).total!"minutes" == 142); assert(dur!"seconds"(142).total!"seconds" == 142); assert(dur!"msecs"(142).total!"msecs" == 142); assert(dur!"usecs"(142).total!"usecs" == 142); assert(dur!"hnsecs"(142).total!"hnsecs" == 142); assert(dur!"nsecs"(142).total!"nsecs" == 100); // Non-generic assert(weeks(142).total!"weeks" == 142); assert(days(142).total!"days" == 142); assert(hours(142).total!"hours" == 142); assert(minutes(142).total!"minutes" == 142); assert(seconds(142).total!"seconds" == 142); assert(msecs(142).total!"msecs" == 142); assert(usecs(142).total!"usecs" == 142); assert(hnsecs(142).total!"hnsecs" == 142); assert(nsecs(142).total!"nsecs" == 100); } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { assert(dur!"weeks"(7).total!"weeks" == 7); assert(dur!"days"(7).total!"days" == 7); assert(dur!"hours"(7).total!"hours" == 7); assert(dur!"minutes"(7).total!"minutes" == 7); assert(dur!"seconds"(7).total!"seconds" == 7); assert(dur!"msecs"(7).total!"msecs" == 7); assert(dur!"usecs"(7).total!"usecs" == 7); assert(dur!"hnsecs"(7).total!"hnsecs" == 7); assert(dur!"nsecs"(7).total!"nsecs" == 0); assert(dur!"weeks"(1007) == weeks(1007)); assert(dur!"days"(1007) == days(1007)); assert(dur!"hours"(1007) == hours(1007)); assert(dur!"minutes"(1007) == minutes(1007)); assert(dur!"seconds"(1007) == seconds(1007)); assert(dur!"msecs"(1007) == msecs(1007)); assert(dur!"usecs"(1007) == usecs(1007)); assert(dur!"hnsecs"(1007) == hnsecs(1007)); assert(dur!"nsecs"(10) == nsecs(10)); } } // used in MonoTimeImpl private string _clockTypeName(ClockType clockType) { final switch(clockType) { foreach(name; __traits(allMembers, ClockType)) { case __traits(getMember, ClockType, name): return name; } } assert(0); } // used in MonoTimeImpl private size_t _clockTypeIdx(ClockType clockType) { final switch(clockType) { foreach(i, name; __traits(allMembers, ClockType)) { case __traits(getMember, ClockType, name): return i; } } assert(0); } /++ alias for $(D MonoTimeImpl) instantiated with $(D ClockType.normal). This is what most programs should use. It's also what much of $(D MonoTimeImpl) uses in its documentation (particularly in the examples), because that's what's going to be used in most code. +/ alias MonoTime = MonoTimeImpl!(ClockType.normal); /++ Represents a timestamp of the system's monotonic clock. A monotonic clock is one which always goes forward and never moves backwards, unlike the system's wall clock time (as represented by $(XREF datetime, SysTime)). The system's wall clock time can be adjusted by the user or by the system itself via services such as NTP, so it is unreliable to use the wall clock time for timing. Timers which use the wall clock time could easily end up never going off due to changes made to the wall clock time or otherwise waiting for a different period of time than that specified by the programmer. However, because the monotonic clock always increases at a fixed rate and is not affected by adjustments to the wall clock time, it is ideal for use with timers or anything which requires high precision timing. So, MonoTime should be used for anything involving timers and timing, whereas $(XREF datetime, SysTime) should be used when the wall clock time is required. The monotonic clock has no relation to wall clock time. Rather, it holds its time as the number of ticks of the clock which have occurred since the clock started (typically when the system booted up). So, to determine how much time has passed between two points in time, one monotonic time is subtracted from the other to determine the number of ticks which occurred between the two points of time, and those ticks are divided by the number of ticks that occur every second (as represented by MonoTime.ticksPerSecond) to get a meaningful duration of time. Normally, MonoTime does these calculations for the programmer, but the $(D ticks) and $(D ticksPerSecond) properties are provided for those who require direct access to the system ticks. The normal way that MonoTime would be used is -------------------- MonoTime before = MonoTime.currTime; // do stuff... MonoTime after = MonoTime.currTime; Duration timeElapsed = after - before; -------------------- $(LREF MonoTime) is an alias to $(D MonoTimeImpl!(ClockType.normal)) and is what most programs should use for the monotonic clock, so that's what is used in most of $(D MonoTimeImpl)'s documentation. But $(D MonoTimeImpl) can be instantiated with other clock types for those rare programs that need it. See_Also: $(LREF ClockType) +/ struct MonoTimeImpl(ClockType clockType) { private enum _clockIdx = _clockTypeIdx(clockType); private enum _clockName = _clockTypeName(clockType); @safe: version(Windows) { static if(clockType != ClockType.coarse && clockType != ClockType.normal && clockType != ClockType.precise) { static assert(0, "ClockType." ~ _clockName ~ " is not supported by MonoTimeImpl on this system."); } } else version(OSX) { static if(clockType != ClockType.coarse && clockType != ClockType.normal && clockType != ClockType.precise) { static assert(0, "ClockType." ~ _clockName ~ " is not supported by MonoTimeImpl on this system."); } } else version(Posix) { enum clockArg = _posixClock(clockType); } else static assert(0, "Unsupported platform"); // POD value, test mutable/const/immutable conversion unittest { MonoTimeImpl m; const MonoTimeImpl cm = m; immutable MonoTimeImpl im = m; m = cm; m = im; } /++ The current time of the system's monotonic clock. This has no relation to the wall clock time, as the wall clock time can be adjusted (e.g. by NTP), whereas the monotonic clock always moves forward. The source of the monotonic time is system-specific. On Windows, $(D QueryPerformanceCounter) is used. On Mac OS X, $(D mach_absolute_time) is used, while on other POSIX systems, $(D clock_gettime) is used. $(RED Warning): On some systems, the monotonic clock may stop counting when the computer goes to sleep or hibernates. So, the monotonic clock may indicate less time than has actually passed if that occurs. This is known to happen on Mac OS X. It has not been tested whether it occurs on either Windows or Linux. +/ static @property MonoTimeImpl currTime() @trusted nothrow @nogc { if(ticksPerSecond == 0) { import core.internal.abort : abort; abort("MonoTimeImpl!(ClockType." ~ _clockName ~ ") failed to get the frequency of the system's monotonic clock."); } version(Windows) { long ticks; if(QueryPerformanceCounter(&ticks) == 0) { // This probably cannot happen on Windows 95 or later import core.internal.abort : abort; abort("Call to QueryPerformanceCounter failed."); } return MonoTimeImpl(ticks); } else version(OSX) return MonoTimeImpl(mach_absolute_time()); else version(Posix) { timespec ts; if(clock_gettime(clockArg, &ts) != 0) { import core.internal.abort : abort; abort("Call to clock_gettime failed."); } return MonoTimeImpl(convClockFreq(ts.tv_sec * 1_000_000_000L + ts.tv_nsec, 1_000_000_000L, ticksPerSecond)); } } static @property pure nothrow @nogc { /++ A $(D MonoTime) of $(D 0) ticks. It's provided to be consistent with $(D Duration.zero), and it's more explicit than $(D MonoTime.init). +/ MonoTimeImpl zero() { return MonoTimeImpl(0); } /++ Largest $(D MonoTime) possible. +/ MonoTimeImpl max() { return MonoTimeImpl(long.max); } /++ Most negative $(D MonoTime) possible. +/ MonoTimeImpl min() { return MonoTimeImpl(long.min); } } unittest { assert(MonoTimeImpl.zero == MonoTimeImpl(0)); assert(MonoTimeImpl.max == MonoTimeImpl(long.max)); assert(MonoTimeImpl.min == MonoTimeImpl(long.min)); assert(MonoTimeImpl.min < MonoTimeImpl.zero); assert(MonoTimeImpl.zero < MonoTimeImpl.max); assert(MonoTimeImpl.min < MonoTimeImpl.max); } /++ Compares this MonoTime with the given MonoTime. Returns: $(BOOKTABLE, $(TR $(TD this < rhs) $(TD < 0)) $(TR $(TD this == rhs) $(TD 0)) $(TR $(TD this > rhs) $(TD > 0)) ) +/ int opCmp(MonoTimeImpl rhs) const pure nothrow @nogc { if(_ticks < rhs._ticks) return -1; return _ticks > rhs._ticks ? 1 : 0; } unittest { const t = MonoTimeImpl.currTime; assert(t == copy(t)); } unittest { const before = MonoTimeImpl.currTime; auto after = MonoTimeImpl(before._ticks + 42); assert(before < after); assert(copy(before) <= before); assert(copy(after) > before); assert(after >= copy(after)); } unittest { const currTime = MonoTimeImpl.currTime; assert(MonoTimeImpl(long.max) > MonoTimeImpl(0)); assert(MonoTimeImpl(0) > MonoTimeImpl(long.min)); assert(MonoTimeImpl(long.max) > currTime); assert(currTime > MonoTimeImpl(0)); assert(MonoTimeImpl(0) < currTime); assert(MonoTimeImpl(0) < MonoTimeImpl(long.max)); assert(MonoTimeImpl(long.min) < MonoTimeImpl(0)); } /++ Subtracting two MonoTimes results in a $(LREF Duration) representing the amount of time which elapsed between them. The primary way that programs should time how long something takes is to do -------------------- MonoTime before = MonoTime.currTime; // do stuff MonoTime after = MonoTime.currTime; // How long it took. Duration timeElapsed = after - before; -------------------- or to use a wrapper (such as a stop watch type) which does that. $(RED Warning): Because $(LREF Duration) is in hnsecs, whereas MonoTime is in system ticks, it's usually the case that this assertion will fail -------------------- auto before = MonoTime.currTime; // do stuff auto after = MonoTime.currTime; auto timeElapsed = after - before; assert(before + timeElapsed == after). -------------------- This is generally fine, and by its very nature, converting from system ticks to any type of seconds (hnsecs, nsecs, etc.) will introduce rounding errors, but if code needs to avoid any of the small rounding errors introduced by conversion, then it needs to use MonoTime's $(D ticks) property and keep all calculations in ticks rather than using $(LREF Duration). +/ Duration opBinary(string op)(MonoTimeImpl rhs) const pure nothrow @nogc if(op == "-") { immutable diff = _ticks - rhs._ticks; return Duration(convClockFreq(diff , ticksPerSecond, hnsecsPer!"seconds")); } unittest { const t = MonoTimeImpl.currTime; assert(t - copy(t) == Duration.zero); static assert(!__traits(compiles, t + t)); } unittest { static void test(in MonoTimeImpl before, in MonoTimeImpl after, in Duration min) { immutable diff = after - before; assert(diff >= min); auto calcAfter = before + diff; assertApprox(calcAfter, calcAfter - Duration(1), calcAfter + Duration(1)); assert(before - after == -diff); } const before = MonoTimeImpl.currTime; test(before, MonoTimeImpl(before._ticks + 4202), Duration.zero); test(before, MonoTimeImpl.currTime, Duration.zero); const durLargerUnits = dur!"minutes"(7) + dur!"seconds"(22); test(before, before + durLargerUnits + dur!"msecs"(33) + dur!"hnsecs"(571), durLargerUnits); } /++ Adding or subtracting a $(LREF Duration) to/from a MonoTime results in a MonoTime which is adjusted by that amount. +/ MonoTimeImpl opBinary(string op)(Duration rhs) const pure nothrow @nogc if(op == "+" || op == "-") { immutable rhsConverted = convClockFreq(rhs._hnsecs, hnsecsPer!"seconds", ticksPerSecond); mixin("return MonoTimeImpl(_ticks " ~ op ~ " rhsConverted);"); } unittest { const t = MonoTimeImpl.currTime; assert(t + Duration(0) == t); assert(t - Duration(0) == t); } unittest { const t = MonoTimeImpl.currTime; // We reassign ticks in order to get the same rounding errors // that we should be getting with Duration (e.g. MonoTimeImpl may be // at a higher precision than hnsecs, meaning that 7333 would be // truncated when converting to hnsecs). long ticks = 7333; auto hnsecs = convClockFreq(ticks, ticksPerSecond, hnsecsPer!"seconds"); ticks = convClockFreq(hnsecs, hnsecsPer!"seconds", ticksPerSecond); assert(t - Duration(hnsecs) == MonoTimeImpl(t._ticks - ticks)); assert(t + Duration(hnsecs) == MonoTimeImpl(t._ticks + ticks)); } /++ Ditto +/ ref MonoTimeImpl opOpAssign(string op)(Duration rhs) pure nothrow @nogc if(op == "+" || op == "-") { immutable rhsConverted = convClockFreq(rhs._hnsecs, hnsecsPer!"seconds", ticksPerSecond); mixin("_ticks " ~ op ~ "= rhsConverted;"); return this; } unittest { auto mt = MonoTimeImpl.currTime; const initial = mt; mt += Duration(0); assert(mt == initial); mt -= Duration(0); assert(mt == initial); // We reassign ticks in order to get the same rounding errors // that we should be getting with Duration (e.g. MonoTimeImpl may be // at a higher precision than hnsecs, meaning that 7333 would be // truncated when converting to hnsecs). long ticks = 7333; auto hnsecs = convClockFreq(ticks, ticksPerSecond, hnsecsPer!"seconds"); ticks = convClockFreq(hnsecs, hnsecsPer!"seconds", ticksPerSecond); auto before = MonoTimeImpl(initial._ticks - ticks); assert((mt -= Duration(hnsecs)) == before); assert(mt == before); assert((mt += Duration(hnsecs)) == initial); assert(mt == initial); } /++ The number of ticks in the monotonic time. Most programs should not use this directly, but it's exposed for those few programs that need it. The main reasons that a program might need to use ticks directly is if the system clock has higher precision than hnsecs, and the program needs that higher precision, or if the program needs to avoid the rounding errors caused by converting to hnsecs. +/ @property long ticks() const pure nothrow @nogc { return _ticks; } unittest { const mt = MonoTimeImpl.currTime; assert(mt.ticks == mt._ticks); } /++ The number of ticks that MonoTime has per second - i.e. the resolution or frequency of the system's monotonic clock. e.g. if the system clock had a resolution of microseconds, then ticksPerSecond would be $(D 1_000_000). +/ static @property long ticksPerSecond() pure nothrow @nogc { return _ticksPerSecond[_clockIdx]; } unittest { assert(MonoTimeImpl.ticksPerSecond == _ticksPerSecond[_clockIdx]); } /// string toString() const pure nothrow { static if(clockType == ClockType.normal) return "MonoTime(" ~ signedToTempString(_ticks, 10) ~ " ticks, " ~ signedToTempString(ticksPerSecond, 10) ~ " ticks per second)"; else return "MonoTimeImpl!(ClockType." ~ _clockName ~ ")(" ~ signedToTempString(_ticks, 10) ~ " ticks, " ~ signedToTempString(ticksPerSecond, 10) ~ " ticks per second)"; } unittest { static min(T)(T a, T b) { return a < b ? a : b; } static void eat(ref string s, const(char)[] exp) { assert(s[0 .. min($, exp.length)] == exp, s~" != "~exp); s = s[exp.length .. $]; } immutable mt = MonoTimeImpl.currTime; auto str = mt.toString(); static if(is(typeof(this) == MonoTime)) eat(str, "MonoTime("); else eat(str, "MonoTimeImpl!(ClockType."~_clockName~")("); eat(str, signedToTempString(mt._ticks, 10)); eat(str, " ticks, "); eat(str, signedToTempString(ticksPerSecond, 10)); eat(str, " ticks per second)"); } private: // static immutable long _ticksPerSecond; unittest { assert(_ticksPerSecond[_clockIdx]); } long _ticks; } // This is supposed to be a static variable in MonoTimeImpl with the static // constructor being in there, but https://issues.dlang.org/show_bug.cgi?id=14517 // prevents that from working. However, moving it back to a static ctor will // reraise issues with other systems using MonoTime, so we should leave this // here even when that bug is fixed. private immutable long[__traits(allMembers, ClockType).length] _ticksPerSecond; // This is called directly from the runtime initilization function (rt_init), // instead of using a static constructor. Other subsystems inside the runtime // (namely, the GC) may need time functionality, but cannot wait until the // static ctors have run. Therefore, we initialize these specially. Because // it's a normal function, we need to do some dangerous casting PLEASE take // care when modifying this function, and it should NOT be called except from // the runtime init. // // NOTE: the code below SPECIFICALLY does not assert when it cannot initialize // the ticks per second array. This allows cases where a clock is never used on // a system that doesn't support it. See bugzilla issue // https://issues.dlang.org/show_bug.cgi?id=14863 // The assert will occur when someone attempts to use _ticksPerSecond for that // value. extern(C) void _d_initMonoTime() { // We need a mutable pointer to the ticksPerSecond array. Although this // would appear to break immutability, it is logically the same as a static // ctor. So we should ONLY write these values once (we will check for 0 // values when setting to ensure this is truly only called once). auto tps = cast(long[])_ticksPerSecond[]; // If we try to do anything with ClockType in the documentation build, it'll // trigger the static assertions related to ClockType, since the // documentation build defines all of the possible ClockTypes, which won't // work when they're used in the static ifs, because no system supports them // all. version(CoreDdoc) {} else version(Windows) { long ticksPerSecond; if(QueryPerformanceFrequency(&ticksPerSecond) != 0) { foreach(i, typeStr; __traits(allMembers, ClockType)) { // ensure we are only writing immutable data once if(tps[i] != 0) // should only be called once assert(0); tps[i] = ticksPerSecond; } } } else version(OSX) { immutable long ticksPerSecond = machTicksPerSecond(); foreach(i, typeStr; __traits(allMembers, ClockType)) { // ensure we are only writing immutable data once if(tps[i] != 0) // should only be called once assert(0); tps[i] = ticksPerSecond; } } else version(Posix) { timespec ts; foreach(i, typeStr; __traits(allMembers, ClockType)) { static if(typeStr != "second") { enum clockArg = _posixClock(__traits(getMember, ClockType, typeStr)); if(clock_getres(clockArg, &ts) == 0) { // ensure we are only writing immutable data once if(tps[i] != 0) // should only be called once assert(0); // For some reason, on some systems, clock_getres returns // a resolution which is clearly wrong (it's a millisecond // or worse, but the time is updated much more frequently // than that). In such cases, we'll just use nanosecond // resolution. tps[i] = ts.tv_nsec >= 1000 ? 1_000_000_000L : 1_000_000_000L / ts.tv_nsec; } } } } } // Tests for MonoTimeImpl.currTime. It has to be outside, because MonoTimeImpl // is a template. This unittest block also makes sure that MonoTimeImpl actually // is instantiated with all of the various ClockTypes so that those types and // their tests are compiled and run. unittest { // This test is separate so that it can be tested with MonoTime and not just // MonoTimeImpl. auto norm1 = MonoTime.currTime; auto norm2 = MonoTimeImpl!(ClockType.normal).currTime; assert(norm1 <= norm2); static bool clockSupported(ClockType c) { version (Linux_Pre_2639) // skip CLOCK_BOOTTIME on older linux kernels return c != ClockType.second && c != ClockType.bootTime; else return c != ClockType.second; // second doesn't work with MonoTimeImpl } foreach(typeStr; __traits(allMembers, ClockType)) { mixin("alias type = ClockType." ~ typeStr ~ ";"); static if (clockSupported(type)) { auto v1 = MonoTimeImpl!type.currTime; auto v2 = MonoTimeImpl!type.currTime; scope(failure) { printf("%s: v1 %s, v2 %s, tps %s\n", (type.stringof ~ "\0").ptr, numToStringz(v1._ticks), numToStringz(v2._ticks), numToStringz(typeof(v1).ticksPerSecond)); } assert(v1 <= v2); foreach(otherStr; __traits(allMembers, ClockType)) { mixin("alias other = ClockType." ~ otherStr ~ ";"); static if (clockSupported(other)) { static assert(is(typeof({auto o1 = MonTimeImpl!other.currTime; auto b = v1 <= o1;})) == is(type == other)); } } } } } /++ Converts the given time from one clock frequency/resolution to another. See_Also: $(LREF ticksToNSecs) +/ long convClockFreq(long ticks, long srcTicksPerSecond, long dstTicksPerSecond) @safe pure nothrow @nogc { // This would be more straightforward with floating point arithmetic, // but we avoid it here in order to avoid the rounding errors that that // introduces. Also, by splitting out the units in this way, we're able // to deal with much larger values before running into problems with // integer overflow. return ticks / srcTicksPerSecond * dstTicksPerSecond + ticks % srcTicksPerSecond * dstTicksPerSecond / srcTicksPerSecond; } /// unittest { // one tick is one second -> one tick is a hecto-nanosecond assert(convClockFreq(45, 1, 10_000_000) == 450_000_000); // one tick is one microsecond -> one tick is a millisecond assert(convClockFreq(9029, 1_000_000, 1_000) == 9); // one tick is 1/3_515_654 of a second -> 1/1_001_010 of a second assert(convClockFreq(912_319, 3_515_654, 1_001_010) == 259_764); // one tick is 1/MonoTime.ticksPerSecond -> one tick is a nanosecond // Equivalent to ticksToNSecs auto nsecs = convClockFreq(1982, MonoTime.ticksPerSecond, 1_000_000_000); } unittest { assert(convClockFreq(99, 43, 57) == 131); assert(convClockFreq(131, 57, 43) == 98); assert(convClockFreq(1234567890, 10_000_000, 1_000_000_000) == 123456789000); assert(convClockFreq(1234567890, 1_000_000_000, 10_000_000) == 12345678); assert(convClockFreq(123456789000, 1_000_000_000, 10_000_000) == 1234567890); assert(convClockFreq(12345678, 10_000_000, 1_000_000_000) == 1234567800); assert(convClockFreq(13131, 3_515_654, 10_000_000) == 37350); assert(convClockFreq(37350, 10_000_000, 3_515_654) == 13130); assert(convClockFreq(37350, 3_515_654, 10_000_000) == 106239); assert(convClockFreq(106239, 10_000_000, 3_515_654) == 37349); // It would be too expensive to cover a large range of possible values for // ticks, so we use random values in an attempt to get reasonable coverage. import core.stdc.stdlib; immutable seed = cast(int)time(null); srand(seed); scope(failure) printf("seed %d\n", seed); enum freq1 = 5_527_551L; enum freq2 = 10_000_000L; enum freq3 = 1_000_000_000L; enum freq4 = 98_123_320L; immutable freq5 = MonoTime.ticksPerSecond; // This makes it so that freq6 is the first multiple of 10 which is greater // than or equal to freq5, which at one point was considered for MonoTime's // ticksPerSecond rather than using the system's actual clock frequency, so // it seemed like a good test case to have. import core.stdc.math; immutable numDigitsMinus1 = cast(int)floor(log10(freq5)); auto freq6 = cast(long)pow(10, numDigitsMinus1); if(freq5 > freq6) freq6 *= 10; foreach(_; 0 .. 10_000) { long[2] values = [rand(), cast(long)rand() * (rand() % 16)]; foreach(i; values) { scope(failure) printf("i %s\n", numToStringz(i)); assertApprox(convClockFreq(convClockFreq(i, freq1, freq2), freq2, freq1), i - 10, i + 10); assertApprox(convClockFreq(convClockFreq(i, freq2, freq1), freq1, freq2), i - 10, i + 10); assertApprox(convClockFreq(convClockFreq(i, freq3, freq4), freq4, freq3), i - 100, i + 100); assertApprox(convClockFreq(convClockFreq(i, freq4, freq3), freq3, freq4), i - 100, i + 100); scope(failure) printf("sys %s mt %s\n", numToStringz(freq5), numToStringz(freq6)); assertApprox(convClockFreq(convClockFreq(i, freq5, freq6), freq6, freq5), i - 10, i + 10); assertApprox(convClockFreq(convClockFreq(i, freq6, freq5), freq5, freq6), i - 10, i + 10); // This is here rather than in a unittest block immediately after // ticksToNSecs in order to avoid code duplication in the unit tests. assert(convClockFreq(i, MonoTime.ticksPerSecond, 1_000_000_000) == ticksToNSecs(i)); } } } /++ Convenience wrapper around $(LREF convClockFreq) which converts ticks at a clock frequency of $(D MonoTime.ticksPerSecond) to nanoseconds. It's primarily of use when $(D MonoTime.ticksPerSecond) is greater than hecto-nanosecond resolution, and an application needs a higher precision than hecto-nanoceconds. See_Also: $(LREF convClockFreq) +/ long ticksToNSecs(long ticks) @safe pure nothrow @nogc { return convClockFreq(ticks, MonoTime.ticksPerSecond, 1_000_000_000); } /// unittest { auto before = MonoTime.currTime; // do stuff auto after = MonoTime.currTime; auto diffInTicks = after.ticks - before.ticks; auto diffInNSecs = ticksToNSecs(diffInTicks); assert(diffInNSecs == convClockFreq(diffInTicks, MonoTime.ticksPerSecond, 1_000_000_000)); } /++ The reverse of $(LREF ticksToNSecs). +/ long nsecsToTicks(long ticks) @safe pure nothrow @nogc { return convClockFreq(ticks, 1_000_000_000, MonoTime.ticksPerSecond); } unittest { long ticks = 123409832717333; auto nsecs = convClockFreq(ticks, MonoTime.ticksPerSecond, 1_000_000_000); ticks = convClockFreq(nsecs, 1_000_000_000, MonoTime.ticksPerSecond); assert(nsecsToTicks(nsecs) == ticks); } /++ $(RED Warning: TickDuration will be deprecated in the near future (once all uses of it in Phobos have been deprecated). Please use $(LREF MonoTime) for the cases where a monotonic timestamp is needed and $(LREF Duration) when a duration is needed, rather than using TickDuration. It has been decided that TickDuration is too confusing (e.g. it conflates a monotonic timestamp and a duration in monotonic clock ticks) and that having multiple duration types is too awkward and confusing.) Represents a duration of time in system clock ticks. The system clock ticks are the ticks of the system clock at the highest precision that the system provides. +/ struct TickDuration { /++ The number of ticks that the system clock has in one second. If $(D ticksPerSec) is $(D 0), then then $(D TickDuration) failed to get the value of $(D ticksPerSec) on the current system, and $(D TickDuration) is not going to work. That would be highly abnormal though. +/ static immutable long ticksPerSec; /++ The tick of the system clock (as a $(D TickDuration)) when the application started. +/ static immutable TickDuration appOrigin; static @property @safe pure nothrow @nogc { /++ It's the same as $(D TickDuration(0)), but it's provided to be consistent with $(D Duration) and $(D FracSec), which provide $(D zero) properties. +/ TickDuration zero() { return TickDuration(0); } /++ Largest $(D TickDuration) possible. +/ TickDuration max() { return TickDuration(long.max); } /++ Most negative $(D TickDuration) possible. +/ TickDuration min() { return TickDuration(long.min); } } unittest { assert(zero == TickDuration(0)); assert(TickDuration.max == TickDuration(long.max)); assert(TickDuration.min == TickDuration(long.min)); assert(TickDuration.min < TickDuration.zero); assert(TickDuration.zero < TickDuration.max); assert(TickDuration.min < TickDuration.max); assert(TickDuration.min - TickDuration(1) == TickDuration.max); assert(TickDuration.max + TickDuration(1) == TickDuration.min); } @trusted shared static this() { version(Windows) { if(QueryPerformanceFrequency(cast(long*)&ticksPerSec) == 0) ticksPerSec = 0; } else version(OSX) { ticksPerSec = machTicksPerSecond(); } else version(Posix) { static if(is(typeof(clock_gettime))) { timespec ts; if(clock_getres(CLOCK_MONOTONIC, &ts) != 0) ticksPerSec = 0; else { //For some reason, on some systems, clock_getres returns //a resolution which is clearly wrong (it's a millisecond //or worse, but the time is updated much more frequently //than that). In such cases, we'll just use nanosecond //resolution. ticksPerSec = ts.tv_nsec >= 1000 ? 1_000_000_000 : 1_000_000_000 / ts.tv_nsec; } } else ticksPerSec = 1_000_000; } if(ticksPerSec != 0) appOrigin = TickDuration.currSystemTick; } unittest { assert(ticksPerSec); } /++ The number of system ticks in this $(D TickDuration). You can convert this $(D length) into the number of seconds by dividing it by $(D ticksPerSec) (or using one the appropriate property function to do it). +/ long length; /++ Returns the total number of seconds in this $(D TickDuration). +/ @property long seconds() @safe const pure nothrow @nogc { return this.to!("seconds", long)(); } unittest { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { assert((cast(T)TickDuration(ticksPerSec)).seconds == 1); assert((cast(T)TickDuration(ticksPerSec - 1)).seconds == 0); assert((cast(T)TickDuration(ticksPerSec * 2)).seconds == 2); assert((cast(T)TickDuration(ticksPerSec * 2 - 1)).seconds == 1); assert((cast(T)TickDuration(-1)).seconds == 0); assert((cast(T)TickDuration(-ticksPerSec - 1)).seconds == -1); assert((cast(T)TickDuration(-ticksPerSec)).seconds == -1); } } /++ Returns the total number of milliseconds in this $(D TickDuration). +/ @property long msecs() @safe const pure nothrow @nogc { return this.to!("msecs", long)(); } /++ Returns the total number of microseconds in this $(D TickDuration). +/ @property long usecs() @safe const pure nothrow @nogc { return this.to!("usecs", long)(); } /++ Returns the total number of hecto-nanoseconds in this $(D TickDuration). +/ @property long hnsecs() @safe const pure nothrow @nogc { return this.to!("hnsecs", long)(); } /++ Returns the total number of nanoseconds in this $(D TickDuration). +/ @property long nsecs() @safe const pure nothrow @nogc { return this.to!("nsecs", long)(); } /++ This allows you to construct a $(D TickDuration) from the given time units with the given length. Params: units = The time units of the $(D TickDuration) (e.g. $(D "msecs")). length = The number of units in the $(D TickDuration). +/ static TickDuration from(string units)(long length) @safe pure nothrow @nogc if(units == "seconds" || units == "msecs" || units == "usecs" || units == "hnsecs" || units == "nsecs") { enum unitsPerSec = convert!("seconds", units)(1); return TickDuration(cast(long)(length * (ticksPerSec / cast(real)unitsPerSec))); } unittest { foreach(units; _TypeTuple!("seconds", "msecs", "usecs", "nsecs")) { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { assertApprox((cast(T)TickDuration.from!units(1000)).to!(units, long)(), 500, 1500, units); assertApprox((cast(T)TickDuration.from!units(1_000_000)).to!(units, long)(), 900_000, 1_100_000, units); assertApprox((cast(T)TickDuration.from!units(2_000_000)).to!(units, long)(), 1_900_000, 2_100_000, units); } } } /++ Returns a $(LREF Duration) with the same number of hnsecs as this $(D TickDuration). Note that the conventional way to convert between $(D TickDuration) and $(D Duration) is using $(XREF conv, to), e.g.: $(D tickDuration.to!Duration()) +/ Duration opCast(T)() @safe const pure nothrow @nogc if(is(_Unqual!T == Duration)) { return Duration(hnsecs); } unittest { foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration)) { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { auto expected = dur!"seconds"(1); assert(cast(D)cast(T)TickDuration.from!"seconds"(1) == expected); foreach(units; _TypeTuple!("msecs", "usecs", "hnsecs")) { D actual = cast(D)cast(T)TickDuration.from!units(1_000_000); assertApprox(actual, dur!units(900_000), dur!units(1_100_000)); } } } } //Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=5747 is fixed. TickDuration opCast(T)() @safe const pure nothrow @nogc if(is(_Unqual!T == TickDuration)) { return this; } /++ Adds or subtracts two $(D TickDuration)s as well as assigning the result to this $(D TickDuration). The legal types of arithmetic for $(D TickDuration) using this operator are $(TABLE $(TR $(TD TickDuration) $(TD +=) $(TD TickDuration) $(TD -->) $(TD TickDuration)) $(TR $(TD TickDuration) $(TD -=) $(TD TickDuration) $(TD -->) $(TD TickDuration)) ) Params: rhs = The $(D TickDuration) to add to or subtract from this $(D $(D TickDuration)). +/ ref TickDuration opOpAssign(string op)(TickDuration rhs) @safe pure nothrow @nogc if(op == "+" || op == "-") { mixin("length " ~ op ~ "= rhs.length;"); return this; } unittest { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { auto a = TickDuration.currSystemTick; auto result = a += cast(T)TickDuration.currSystemTick; assert(a == result); assert(a.to!("seconds", real)() >= 0); auto b = TickDuration.currSystemTick; result = b -= cast(T)TickDuration.currSystemTick; assert(b == result); assert(b.to!("seconds", real)() <= 0); foreach(U; _TypeTuple!(const TickDuration, immutable TickDuration)) { U u = TickDuration(12); static assert(!__traits(compiles, u += cast(T)TickDuration.currSystemTick)); static assert(!__traits(compiles, u -= cast(T)TickDuration.currSystemTick)); } } } /++ Adds or subtracts two $(D TickDuration)s. The legal types of arithmetic for $(D TickDuration) using this operator are $(TABLE $(TR $(TD TickDuration) $(TD +) $(TD TickDuration) $(TD -->) $(TD TickDuration)) $(TR $(TD TickDuration) $(TD -) $(TD TickDuration) $(TD -->) $(TD TickDuration)) ) Params: rhs = The $(D TickDuration) to add to or subtract from this $(D TickDuration). +/ TickDuration opBinary(string op)(TickDuration rhs) @safe const pure nothrow @nogc if(op == "+" || op == "-") { return TickDuration(mixin("length " ~ op ~ " rhs.length")); } unittest { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { T a = TickDuration.currSystemTick; T b = TickDuration.currSystemTick; assert((a + b).seconds > 0); assert((a - b).seconds <= 0); } } /++ Returns the negation of this $(D TickDuration). +/ TickDuration opUnary(string op)() @safe const pure nothrow @nogc if(op == "-") { return TickDuration(-length); } unittest { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { assert(-(cast(T)TickDuration(7)) == TickDuration(-7)); assert(-(cast(T)TickDuration(5)) == TickDuration(-5)); assert(-(cast(T)TickDuration(-7)) == TickDuration(7)); assert(-(cast(T)TickDuration(-5)) == TickDuration(5)); assert(-(cast(T)TickDuration(0)) == TickDuration(0)); } } /++ operator overloading "<, >, <=, >=" +/ int opCmp(TickDuration rhs) @safe const pure nothrow @nogc { return length < rhs.length ? -1 : (length == rhs.length ? 0 : 1); } unittest { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { foreach(U; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { T t = TickDuration.currSystemTick; U u = t; assert(t == u); assert(copy(t) == u); assert(t == copy(u)); } } foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { foreach(U; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { T t = TickDuration.currSystemTick; U u = t + t; assert(t < u); assert(t <= t); assert(u > t); assert(u >= u); assert(copy(t) < u); assert(copy(t) <= t); assert(copy(u) > t); assert(copy(u) >= u); assert(t < copy(u)); assert(t <= copy(t)); assert(u > copy(t)); assert(u >= copy(u)); } } } /++ The legal types of arithmetic for $(D TickDuration) using this operator overload are $(TABLE $(TR $(TD TickDuration) $(TD *) $(TD long) $(TD -->) $(TD TickDuration)) $(TR $(TD TickDuration) $(TD *) $(TD floating point) $(TD -->) $(TD TickDuration)) ) Params: value = The value to divide from this duration. +/ void opOpAssign(string op, T)(T value) @safe pure nothrow @nogc if(op == "*" && (__traits(isIntegral, T) || __traits(isFloating, T))) { length = cast(long)(length * value); } unittest { immutable curr = TickDuration.currSystemTick; TickDuration t1 = curr; immutable t2 = curr + curr; t1 *= 2; assert(t1 == t2); t1 = curr; t1 *= 2.0; immutable tol = TickDuration(cast(long)(_abs(t1.length) * double.epsilon * 2.0)); assertApprox(t1, t2 - tol, t2 + tol); t1 = curr; t1 *= 2.1; assert(t1 > t2); foreach(T; _TypeTuple!(const TickDuration, immutable TickDuration)) { T t = TickDuration.currSystemTick; assert(!__traits(compiles, t *= 12)); assert(!__traits(compiles, t *= 12.0)); } } /++ The legal types of arithmetic for $(D TickDuration) using this operator overload are $(TABLE $(TR $(TD TickDuration) $(TD /) $(TD long) $(TD -->) $(TD TickDuration)) $(TR $(TD TickDuration) $(TD /) $(TD floating point) $(TD -->) $(TD TickDuration)) ) Params: value = The value to divide from this $(D TickDuration). Throws: $(D TimeException) if an attempt to divide by $(D 0) is made. +/ void opOpAssign(string op, T)(T value) @safe pure if(op == "/" && (__traits(isIntegral, T) || __traits(isFloating, T))) { if(value == 0) throw new TimeException("Attempted division by 0."); length = cast(long)(length / value); } unittest { immutable curr = TickDuration.currSystemTick; immutable t1 = curr; TickDuration t2 = curr + curr; t2 /= 2; assert(t1 == t2); t2 = curr + curr; t2 /= 2.0; immutable tol = TickDuration(cast(long)(_abs(t2.length) * double.epsilon / 2.0)); assertApprox(t1, t2 - tol, t2 + tol); t2 = curr + curr; t2 /= 2.1; assert(t1 > t2); _assertThrown!TimeException(t2 /= 0); foreach(T; _TypeTuple!(const TickDuration, immutable TickDuration)) { T t = TickDuration.currSystemTick; assert(!__traits(compiles, t /= 12)); assert(!__traits(compiles, t /= 12.0)); } } /++ The legal types of arithmetic for $(D TickDuration) using this operator overload are $(TABLE $(TR $(TD TickDuration) $(TD *) $(TD long) $(TD -->) $(TD TickDuration)) $(TR $(TD TickDuration) $(TD *) $(TD floating point) $(TD -->) $(TD TickDuration)) ) Params: value = The value to divide from this $(D TickDuration). +/ TickDuration opBinary(string op, T)(T value) @safe const pure nothrow @nogc if(op == "*" && (__traits(isIntegral, T) || __traits(isFloating, T))) { return TickDuration(cast(long)(length * value)); } unittest { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { T t1 = TickDuration.currSystemTick; T t2 = t1 + t1; assert(t1 * 2 == t2); immutable tol = TickDuration(cast(long)(_abs(t1.length) * double.epsilon * 2.0)); assertApprox(t1 * 2.0, t2 - tol, t2 + tol); assert(t1 * 2.1 > t2); } } /++ The legal types of arithmetic for $(D TickDuration) using this operator overload are $(TABLE $(TR $(TD TickDuration) $(TD /) $(TD long) $(TD -->) $(TD TickDuration)) $(TR $(TD TickDuration) $(TD /) $(TD floating point) $(TD -->) $(TD TickDuration)) ) Params: value = The value to divide from this $(D TickDuration). Throws: $(D TimeException) if an attempt to divide by $(D 0) is made. +/ TickDuration opBinary(string op, T)(T value) @safe const pure if(op == "/" && (__traits(isIntegral, T) || __traits(isFloating, T))) { if(value == 0) throw new TimeException("Attempted division by 0."); return TickDuration(cast(long)(length / value)); } unittest { foreach(T; _TypeTuple!(TickDuration, const TickDuration, immutable TickDuration)) { T t1 = TickDuration.currSystemTick; T t2 = t1 + t1; assert(t2 / 2 == t1); immutable tol = TickDuration(cast(long)(_abs(t2.length) * double.epsilon / 2.0)); assertApprox(t2 / 2.0, t1 - tol, t1 + tol); assert(t2 / 2.1 < t1); _assertThrown!TimeException(t2 / 0); } } /++ Params: ticks = The number of ticks in the TickDuration. +/ @safe pure nothrow @nogc this(long ticks) { this.length = ticks; } unittest { foreach(i; [-42, 0, 42]) assert(TickDuration(i).length == i); } /++ The current system tick. The number of ticks per second varies from system to system. $(D currSystemTick) uses a monotonic clock, so it's intended for precision timing by comparing relative time values, not for getting the current system time. On Windows, $(D QueryPerformanceCounter) is used. On Mac OS X, $(D mach_absolute_time) is used, while on other Posix systems, $(D clock_gettime) is used. If $(D mach_absolute_time) or $(D clock_gettime) is unavailable, then Posix systems use $(D gettimeofday) (the decision is made when $(D TickDuration) is compiled), which unfortunately, is not monotonic, but if $(D mach_absolute_time) and $(D clock_gettime) aren't available, then $(D gettimeofday) is the the best that there is. $(RED Warning): On some systems, the monotonic clock may stop counting when the computer goes to sleep or hibernates. So, the monotonic clock could be off if that occurs. This is known to happen on Mac OS X. It has not been tested whether it occurs on either Windows or on Linux. Throws: $(D TimeException) if it fails to get the time. +/ static @property TickDuration currSystemTick() @trusted nothrow @nogc { import core.internal.abort : abort; version(Windows) { ulong ticks; if(QueryPerformanceCounter(cast(long*)&ticks) == 0) abort("Failed in QueryPerformanceCounter()."); return TickDuration(ticks); } else version(OSX) { static if(is(typeof(mach_absolute_time))) return TickDuration(cast(long)mach_absolute_time()); else { timeval tv; if(gettimeofday(&tv, null) != 0) abort("Failed in gettimeofday()."); return TickDuration(tv.tv_sec * TickDuration.ticksPerSec + tv.tv_usec * TickDuration.ticksPerSec / 1000 / 1000); } } else version(Posix) { static if(is(typeof(clock_gettime))) { timespec ts; if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) abort("Failed in clock_gettime()."); return TickDuration(ts.tv_sec * TickDuration.ticksPerSec + ts.tv_nsec * TickDuration.ticksPerSec / 1000 / 1000 / 1000); } else { timeval tv; if(gettimeofday(&tv, null) != 0) abort("Failed in gettimeofday()."); return TickDuration(tv.tv_sec * TickDuration.ticksPerSec + tv.tv_usec * TickDuration.ticksPerSec / 1000 / 1000); } } } @safe nothrow unittest { assert(TickDuration.currSystemTick.length > 0); } } /++ Generic way of converting between two time units. Conversions to smaller units use truncating division. Years and months can be converted to each other, small units can be converted to each other, but years and months cannot be converted to or from smaller units (due to the varying number of days in a month or year). Params: from = The units of time to convert from. to = The units of time to convert to. value = The value to convert. +/ long convert(string from, string to)(long value) @safe pure nothrow @nogc if(((from == "weeks" || from == "days" || from == "hours" || from == "minutes" || from == "seconds" || from == "msecs" || from == "usecs" || from == "hnsecs" || from == "nsecs") && (to == "weeks" || to == "days" || to == "hours" || to == "minutes" || to == "seconds" || to == "msecs" || to == "usecs" || to == "hnsecs" || to == "nsecs")) || ((from == "years" || from == "months") && (to == "years" || to == "months"))) { static if(from == "years") { static if(to == "years") return value; else static if(to == "months") return value * 12; else static assert(0, "A generic month or year cannot be converted to or from smaller units."); } else static if(from == "months") { static if(to == "years") return value / 12; else static if(to == "months") return value; else static assert(0, "A generic month or year cannot be converted to or from smaller units."); } else static if(from == "nsecs" && to == "nsecs") return value; else static if(from == "nsecs") return convert!("hnsecs", to)(value / 100); else static if(to == "nsecs") return convert!(from, "hnsecs")(value) * 100; else return (hnsecsPer!from * value) / hnsecsPer!to; } /// unittest { assert(convert!("years", "months")(1) == 12); assert(convert!("months", "years")(12) == 1); assert(convert!("weeks", "days")(1) == 7); assert(convert!("hours", "seconds")(1) == 3600); assert(convert!("seconds", "days")(1) == 0); assert(convert!("seconds", "days")(86_400) == 1); assert(convert!("nsecs", "nsecs")(1) == 1); assert(convert!("nsecs", "hnsecs")(1) == 0); assert(convert!("hnsecs", "nsecs")(1) == 100); assert(convert!("nsecs", "seconds")(1) == 0); assert(convert!("seconds", "nsecs")(1) == 1_000_000_000); } unittest { foreach(units; _TypeTuple!("weeks", "days", "hours", "seconds", "msecs", "usecs", "hnsecs", "nsecs")) { static assert(!__traits(compiles, convert!("years", units)(12)), units); static assert(!__traits(compiles, convert!(units, "years")(12)), units); } foreach(units; _TypeTuple!("years", "months", "weeks", "days", "hours", "seconds", "msecs", "usecs", "hnsecs", "nsecs")) { assert(convert!(units, units)(12) == 12); } assert(convert!("weeks", "hnsecs")(1) == 6_048_000_000_000L); assert(convert!("days", "hnsecs")(1) == 864_000_000_000L); assert(convert!("hours", "hnsecs")(1) == 36_000_000_000L); assert(convert!("minutes", "hnsecs")(1) == 600_000_000L); assert(convert!("seconds", "hnsecs")(1) == 10_000_000L); assert(convert!("msecs", "hnsecs")(1) == 10_000); assert(convert!("usecs", "hnsecs")(1) == 10); assert(convert!("hnsecs", "weeks")(6_048_000_000_000L) == 1); assert(convert!("hnsecs", "days")(864_000_000_000L) == 1); assert(convert!("hnsecs", "hours")(36_000_000_000L) == 1); assert(convert!("hnsecs", "minutes")(600_000_000L) == 1); assert(convert!("hnsecs", "seconds")(10_000_000L) == 1); assert(convert!("hnsecs", "msecs")(10_000) == 1); assert(convert!("hnsecs", "usecs")(10) == 1); assert(convert!("weeks", "days")(1) == 7); assert(convert!("days", "weeks")(7) == 1); assert(convert!("days", "hours")(1) == 24); assert(convert!("hours", "days")(24) == 1); assert(convert!("hours", "minutes")(1) == 60); assert(convert!("minutes", "hours")(60) == 1); assert(convert!("minutes", "seconds")(1) == 60); assert(convert!("seconds", "minutes")(60) == 1); assert(convert!("seconds", "msecs")(1) == 1000); assert(convert!("msecs", "seconds")(1000) == 1); assert(convert!("msecs", "usecs")(1) == 1000); assert(convert!("usecs", "msecs")(1000) == 1); assert(convert!("usecs", "hnsecs")(1) == 10); assert(convert!("hnsecs", "usecs")(10) == 1); assert(convert!("weeks", "nsecs")(1) == 604_800_000_000_000L); assert(convert!("days", "nsecs")(1) == 86_400_000_000_000L); assert(convert!("hours", "nsecs")(1) == 3_600_000_000_000L); assert(convert!("minutes", "nsecs")(1) == 60_000_000_000L); assert(convert!("seconds", "nsecs")(1) == 1_000_000_000L); assert(convert!("msecs", "nsecs")(1) == 1_000_000); assert(convert!("usecs", "nsecs")(1) == 1000); assert(convert!("hnsecs", "nsecs")(1) == 100); assert(convert!("nsecs", "weeks")(604_800_000_000_000L) == 1); assert(convert!("nsecs", "days")(86_400_000_000_000L) == 1); assert(convert!("nsecs", "hours")(3_600_000_000_000L) == 1); assert(convert!("nsecs", "minutes")(60_000_000_000L) == 1); assert(convert!("nsecs", "seconds")(1_000_000_000L) == 1); assert(convert!("nsecs", "msecs")(1_000_000) == 1); assert(convert!("nsecs", "usecs")(1000) == 1); assert(convert!("nsecs", "hnsecs")(100) == 1); } /++ Represents fractional seconds. This is the portion of the time which is smaller than a second and it cannot hold values which would be greater than or equal to a second (or less than or equal to a negative second). It holds hnsecs internally, but you can create it using either milliseconds, microseconds, or hnsecs. What it does is allow for a simple way to set or adjust the fractional seconds portion of a $(D Duration) or a $(XREF datetime, SysTime) without having to worry about whether you're dealing with milliseconds, microseconds, or hnsecs. $(D FracSec)'s functions which take time unit strings do accept $(D "nsecs"), but because the resolution of $(D Duration) and $(XREF datetime, SysTime) is hnsecs, you don't actually get precision higher than hnsecs. $(D "nsecs") is accepted merely for convenience. Any values given as nsecs will be converted to hnsecs using $(D convert) (which uses truncating division when converting to smaller units). +/ struct FracSec { @safe pure: public: /++ A $(D FracSec) of $(D 0). It's shorter than doing something like $(D FracSec.from!"msecs"(0)) and more explicit than $(D FracSec.init). +/ static @property nothrow @nogc FracSec zero() { return FracSec(0); } unittest { assert(zero == FracSec.from!"msecs"(0)); } /++ Create a $(D FracSec) from the given units ($(D "msecs"), $(D "usecs"), or $(D "hnsecs")). Params: units = The units to create a FracSec from. value = The number of the given units passed the second. Throws: $(D TimeException) if the given value would result in a $(D FracSec) greater than or equal to $(D 1) second or less than or equal to $(D -1) seconds. +/ static FracSec from(string units)(long value) if(units == "msecs" || units == "usecs" || units == "hnsecs" || units == "nsecs") { immutable hnsecs = cast(int)convert!(units, "hnsecs")(value); _enforceValid(hnsecs); return FracSec(hnsecs); } unittest { assert(FracSec.from!"msecs"(0) == FracSec(0)); assert(FracSec.from!"usecs"(0) == FracSec(0)); assert(FracSec.from!"hnsecs"(0) == FracSec(0)); foreach(sign; [1, -1]) { _assertThrown!TimeException(from!"msecs"(1000 * sign)); assert(FracSec.from!"msecs"(1 * sign) == FracSec(10_000 * sign)); assert(FracSec.from!"msecs"(999 * sign) == FracSec(9_990_000 * sign)); _assertThrown!TimeException(from!"usecs"(1_000_000 * sign)); assert(FracSec.from!"usecs"(1 * sign) == FracSec(10 * sign)); assert(FracSec.from!"usecs"(999 * sign) == FracSec(9990 * sign)); assert(FracSec.from!"usecs"(999_999 * sign) == FracSec(9999_990 * sign)); _assertThrown!TimeException(from!"hnsecs"(10_000_000 * sign)); assert(FracSec.from!"hnsecs"(1 * sign) == FracSec(1 * sign)); assert(FracSec.from!"hnsecs"(999 * sign) == FracSec(999 * sign)); assert(FracSec.from!"hnsecs"(999_999 * sign) == FracSec(999_999 * sign)); assert(FracSec.from!"hnsecs"(9_999_999 * sign) == FracSec(9_999_999 * sign)); assert(FracSec.from!"nsecs"(1 * sign) == FracSec(0)); assert(FracSec.from!"nsecs"(10 * sign) == FracSec(0)); assert(FracSec.from!"nsecs"(99 * sign) == FracSec(0)); assert(FracSec.from!"nsecs"(100 * sign) == FracSec(1 * sign)); assert(FracSec.from!"nsecs"(99_999 * sign) == FracSec(999 * sign)); assert(FracSec.from!"nsecs"(99_999_999 * sign) == FracSec(999_999 * sign)); assert(FracSec.from!"nsecs"(999_999_999 * sign) == FracSec(9_999_999 * sign)); } } /++ Returns the negation of this $(D FracSec). +/ FracSec opUnary(string op)() const nothrow @nogc if(op == "-") { return FracSec(-_hnsecs); } unittest { foreach(val; [-7, -5, 0, 5, 7]) { foreach(F; _TypeTuple!(FracSec, const FracSec, immutable FracSec)) { F fs = FracSec(val); assert(-fs == FracSec(-val)); } } } /++ The value of this $(D FracSec) as milliseconds. +/ @property int msecs() const nothrow @nogc { return cast(int)convert!("hnsecs", "msecs")(_hnsecs); } unittest { foreach(F; _TypeTuple!(FracSec, const FracSec, immutable FracSec)) { assert(FracSec(0).msecs == 0); foreach(sign; [1, -1]) { assert((cast(F)FracSec(1 * sign)).msecs == 0); assert((cast(F)FracSec(999 * sign)).msecs == 0); assert((cast(F)FracSec(999_999 * sign)).msecs == 99 * sign); assert((cast(F)FracSec(9_999_999 * sign)).msecs == 999 * sign); } } } /++ The value of this $(D FracSec) as milliseconds. Params: milliseconds = The number of milliseconds passed the second. Throws: $(D TimeException) if the given value is not less than $(D 1) second and greater than a $(D -1) seconds. +/ @property void msecs(int milliseconds) { immutable hnsecs = cast(int)convert!("msecs", "hnsecs")(milliseconds); _enforceValid(hnsecs); _hnsecs = hnsecs; } unittest { static void test(int msecs, FracSec expected = FracSec.init, size_t line = __LINE__) { FracSec fs; fs.msecs = msecs; if(fs != expected) throw new AssertError("unittest failure", __FILE__, line); } _assertThrown!TimeException(test(-1000)); _assertThrown!TimeException(test(1000)); test(0, FracSec(0)); foreach(sign; [1, -1]) { test(1 * sign, FracSec(10_000 * sign)); test(999 * sign, FracSec(9_990_000 * sign)); } foreach(F; _TypeTuple!(const FracSec, immutable FracSec)) { F fs = FracSec(1234567); static assert(!__traits(compiles, fs.msecs = 12), F.stringof); } } /++ The value of this $(D FracSec) as microseconds. +/ @property int usecs() const nothrow @nogc { return cast(int)convert!("hnsecs", "usecs")(_hnsecs); } unittest { foreach(F; _TypeTuple!(FracSec, const FracSec, immutable FracSec)) { assert(FracSec(0).usecs == 0); foreach(sign; [1, -1]) { assert((cast(F)FracSec(1 * sign)).usecs == 0); assert((cast(F)FracSec(999 * sign)).usecs == 99 * sign); assert((cast(F)FracSec(999_999 * sign)).usecs == 99_999 * sign); assert((cast(F)FracSec(9_999_999 * sign)).usecs == 999_999 * sign); } } } /++ The value of this $(D FracSec) as microseconds. Params: microseconds = The number of microseconds passed the second. Throws: $(D TimeException) if the given value is not less than $(D 1) second and greater than a $(D -1) seconds. +/ @property void usecs(int microseconds) { immutable hnsecs = cast(int)convert!("usecs", "hnsecs")(microseconds); _enforceValid(hnsecs); _hnsecs = hnsecs; } unittest { static void test(int usecs, FracSec expected = FracSec.init, size_t line = __LINE__) { FracSec fs; fs.usecs = usecs; if(fs != expected) throw new AssertError("unittest failure", __FILE__, line); } _assertThrown!TimeException(test(-1_000_000)); _assertThrown!TimeException(test(1_000_000)); test(0, FracSec(0)); foreach(sign; [1, -1]) { test(1 * sign, FracSec(10 * sign)); test(999 * sign, FracSec(9990 * sign)); test(999_999 * sign, FracSec(9_999_990 * sign)); } foreach(F; _TypeTuple!(const FracSec, immutable FracSec)) { F fs = FracSec(1234567); static assert(!__traits(compiles, fs.usecs = 12), F.stringof); } } /++ The value of this $(D FracSec) as hnsecs. +/ @property int hnsecs() const nothrow @nogc { return _hnsecs; } unittest { foreach(F; _TypeTuple!(FracSec, const FracSec, immutable FracSec)) { assert(FracSec(0).hnsecs == 0); foreach(sign; [1, -1]) { assert((cast(F)FracSec(1 * sign)).hnsecs == 1 * sign); assert((cast(F)FracSec(999 * sign)).hnsecs == 999 * sign); assert((cast(F)FracSec(999_999 * sign)).hnsecs == 999_999 * sign); assert((cast(F)FracSec(9_999_999 * sign)).hnsecs == 9_999_999 * sign); } } } /++ The value of this $(D FracSec) as hnsecs. Params: hnsecs = The number of hnsecs passed the second. Throws: $(D TimeException) if the given value is not less than $(D 1) second and greater than a $(D -1) seconds. +/ @property void hnsecs(int hnsecs) { _enforceValid(hnsecs); _hnsecs = hnsecs; } unittest { static void test(int hnsecs, FracSec expected = FracSec.init, size_t line = __LINE__) { FracSec fs; fs.hnsecs = hnsecs; if(fs != expected) throw new AssertError("unittest failure", __FILE__, line); } _assertThrown!TimeException(test(-10_000_000)); _assertThrown!TimeException(test(10_000_000)); test(0, FracSec(0)); foreach(sign; [1, -1]) { test(1 * sign, FracSec(1 * sign)); test(999 * sign, FracSec(999 * sign)); test(999_999 * sign, FracSec(999_999 * sign)); test(9_999_999 * sign, FracSec(9_999_999 * sign)); } foreach(F; _TypeTuple!(const FracSec, immutable FracSec)) { F fs = FracSec(1234567); static assert(!__traits(compiles, fs.hnsecs = 12), F.stringof); } } /++ The value of this $(D FracSec) as nsecs. Note that this does not give you any greater precision than getting the value of this $(D FracSec) as hnsecs. +/ @property int nsecs() const nothrow @nogc { return cast(int)convert!("hnsecs", "nsecs")(_hnsecs); } unittest { foreach(F; _TypeTuple!(FracSec, const FracSec, immutable FracSec)) { assert(FracSec(0).nsecs == 0); foreach(sign; [1, -1]) { assert((cast(F)FracSec(1 * sign)).nsecs == 100 * sign); assert((cast(F)FracSec(999 * sign)).nsecs == 99_900 * sign); assert((cast(F)FracSec(999_999 * sign)).nsecs == 99_999_900 * sign); assert((cast(F)FracSec(9_999_999 * sign)).nsecs == 999_999_900 * sign); } } } /++ The value of this $(D FracSec) as nsecs. Note that this does not give you any greater precision than setting the value of this $(D FracSec) as hnsecs. Params: nsecs = The number of nsecs passed the second. Throws: $(D TimeException) if the given value is not less than $(D 1) second and greater than a $(D -1) seconds. +/ @property void nsecs(long nsecs) { immutable hnsecs = cast(int)convert!("nsecs", "hnsecs")(nsecs); _enforceValid(hnsecs); _hnsecs = hnsecs; } unittest { static void test(int nsecs, FracSec expected = FracSec.init, size_t line = __LINE__) { FracSec fs; fs.nsecs = nsecs; if(fs != expected) throw new AssertError("unittest failure", __FILE__, line); } _assertThrown!TimeException(test(-1_000_000_000)); _assertThrown!TimeException(test(1_000_000_000)); test(0, FracSec(0)); foreach(sign; [1, -1]) { test(1 * sign, FracSec(0)); test(10 * sign, FracSec(0)); test(100 * sign, FracSec(1 * sign)); test(999 * sign, FracSec(9 * sign)); test(999_999 * sign, FracSec(9999 * sign)); test(9_999_999 * sign, FracSec(99_999 * sign)); } foreach(F; _TypeTuple!(const FracSec, immutable FracSec)) { F fs = FracSec(1234567); static assert(!__traits(compiles, fs.nsecs = 12), F.stringof); } } /+ Converts this $(D TickDuration) to a string. +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() { return _toStringImpl(); } /++ Converts this $(D TickDuration) to a string. +/ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't //have versions of toString() with extra modifiers, so we define one version //with modifiers and one without. string toString() const nothrow { return _toStringImpl(); } unittest { auto fs = FracSec(12); const cfs = FracSec(12); immutable ifs = FracSec(12); assert(fs.toString() == "12 hnsecs"); assert(cfs.toString() == "12 hnsecs"); assert(ifs.toString() == "12 hnsecs"); } private: /+ Since we have two versions of $(D toString), we have $(D _toStringImpl) so that they can share implementations. +/ string _toStringImpl() const nothrow { long hnsecs = _hnsecs; immutable milliseconds = splitUnitsFromHNSecs!"msecs"(hnsecs); immutable microseconds = splitUnitsFromHNSecs!"usecs"(hnsecs); if(hnsecs == 0) { if(microseconds == 0) { if(milliseconds == 0) return "0 hnsecs"; else { if(milliseconds == 1) return "1 ms"; else { auto r = signedToTempString(milliseconds, 10).idup; r ~= " ms"; return r; } } } else { immutable fullMicroseconds = getUnitsFromHNSecs!"usecs"(_hnsecs); if(fullMicroseconds == 1) return "1 μs"; else { auto r = signedToTempString(fullMicroseconds, 10).idup; r ~= " μs"; return r; } } } else { if(_hnsecs == 1) return "1 hnsec"; else { auto r = signedToTempString(_hnsecs, 10).idup; r ~= " hnsecs"; return r; } } } unittest { foreach(sign; [1 , -1]) { immutable signStr = sign == 1 ? "" : "-"; assert(FracSec.from!"msecs"(0 * sign).toString() == "0 hnsecs"); assert(FracSec.from!"msecs"(1 * sign).toString() == signStr ~ "1 ms"); assert(FracSec.from!"msecs"(2 * sign).toString() == signStr ~ "2 ms"); assert(FracSec.from!"msecs"(100 * sign).toString() == signStr ~ "100 ms"); assert(FracSec.from!"msecs"(999 * sign).toString() == signStr ~ "999 ms"); assert(FracSec.from!"usecs"(0* sign).toString() == "0 hnsecs"); assert(FracSec.from!"usecs"(1* sign).toString() == signStr ~ "1 μs"); assert(FracSec.from!"usecs"(2* sign).toString() == signStr ~ "2 μs"); assert(FracSec.from!"usecs"(100* sign).toString() == signStr ~ "100 μs"); assert(FracSec.from!"usecs"(999* sign).toString() == signStr ~ "999 μs"); assert(FracSec.from!"usecs"(1000* sign).toString() == signStr ~ "1 ms"); assert(FracSec.from!"usecs"(2000* sign).toString() == signStr ~ "2 ms"); assert(FracSec.from!"usecs"(9999* sign).toString() == signStr ~ "9999 μs"); assert(FracSec.from!"usecs"(10_000* sign).toString() == signStr ~ "10 ms"); assert(FracSec.from!"usecs"(20_000* sign).toString() == signStr ~ "20 ms"); assert(FracSec.from!"usecs"(100_000* sign).toString() == signStr ~ "100 ms"); assert(FracSec.from!"usecs"(100_001* sign).toString() == signStr ~ "100001 μs"); assert(FracSec.from!"usecs"(999_999* sign).toString() == signStr ~ "999999 μs"); assert(FracSec.from!"hnsecs"(0* sign).toString() == "0 hnsecs"); assert(FracSec.from!"hnsecs"(1* sign).toString() == (sign == 1 ? "1 hnsec" : "-1 hnsecs")); assert(FracSec.from!"hnsecs"(2* sign).toString() == signStr ~ "2 hnsecs"); assert(FracSec.from!"hnsecs"(100* sign).toString() == signStr ~ "10 μs"); assert(FracSec.from!"hnsecs"(999* sign).toString() == signStr ~ "999 hnsecs"); assert(FracSec.from!"hnsecs"(1000* sign).toString() == signStr ~ "100 μs"); assert(FracSec.from!"hnsecs"(2000* sign).toString() == signStr ~ "200 μs"); assert(FracSec.from!"hnsecs"(9999* sign).toString() == signStr ~ "9999 hnsecs"); assert(FracSec.from!"hnsecs"(10_000* sign).toString() == signStr ~ "1 ms"); assert(FracSec.from!"hnsecs"(20_000* sign).toString() == signStr ~ "2 ms"); assert(FracSec.from!"hnsecs"(100_000* sign).toString() == signStr ~ "10 ms"); assert(FracSec.from!"hnsecs"(100_001* sign).toString() == signStr ~ "100001 hnsecs"); assert(FracSec.from!"hnsecs"(200_000* sign).toString() == signStr ~ "20 ms"); assert(FracSec.from!"hnsecs"(999_999* sign).toString() == signStr ~ "999999 hnsecs"); assert(FracSec.from!"hnsecs"(1_000_001* sign).toString() == signStr ~ "1000001 hnsecs"); assert(FracSec.from!"hnsecs"(9_999_999* sign).toString() == signStr ~ "9999999 hnsecs"); } } /+ Returns whether the given number of hnsecs fits within the range of $(D FracSec). Params: hnsecs = The number of hnsecs. +/ static bool _valid(int hnsecs) nothrow @nogc { immutable second = convert!("seconds", "hnsecs")(1); return hnsecs > -second && hnsecs < second; } /+ Throws: $(D TimeException) if $(D valid(hnsecs)) is $(D false). +/ static void _enforceValid(int hnsecs) { if(!_valid(hnsecs)) throw new TimeException("FracSec must be greater than equal to 0 and less than 1 second."); } /+ Params: hnsecs = The number of hnsecs passed the second. +/ this(int hnsecs) nothrow @nogc { _hnsecs = hnsecs; } invariant() { if(!_valid(_hnsecs)) throw new AssertError("Invariant Failure: hnsecs [" ~ signedToTempString(_hnsecs, 10).idup ~ "]", __FILE__, __LINE__); } int _hnsecs; } /++ Exception type used by core.time. +/ class TimeException : Exception { /++ Params: msg = The message for the exception. file = The file where the exception occurred. line = The line number where the exception occurred. next = The previous exception in the chain of exceptions, if any. +/ this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @safe pure nothrow { super(msg, file, line, next); } /++ Params: msg = The message for the exception. next = The previous exception in the chain of exceptions. file = The file where the exception occurred. line = The line number where the exception occurred. +/ this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @safe pure nothrow { super(msg, file, line, next); } } unittest { { auto e = new TimeException("hello"); assert(e.msg == "hello"); assert(e.file == __FILE__); assert(e.line == __LINE__ - 3); assert(e.next is null); } { auto next = new Exception("foo"); auto e = new TimeException("goodbye", next); assert(e.msg == "goodbye"); assert(e.file == __FILE__); assert(e.line == __LINE__ - 3); assert(e.next is next); } } /++ Returns the absolute value of a duration. +/ Duration abs(Duration duration) @safe pure nothrow @nogc { return Duration(_abs(duration._hnsecs)); } /++ Ditto +/ TickDuration abs(TickDuration duration) @safe pure nothrow @nogc { return TickDuration(_abs(duration.length)); } unittest { assert(abs(dur!"msecs"(5)) == dur!"msecs"(5)); assert(abs(dur!"msecs"(-5)) == dur!"msecs"(5)); assert(abs(TickDuration(17)) == TickDuration(17)); assert(abs(TickDuration(-17)) == TickDuration(17)); } //============================================================================== // Private Section. // // Much of this is a copy or simplified copy of what's in std.datetime. //============================================================================== private: /+ Template to help with converting between time units. +/ template hnsecsPer(string units) if(units == "weeks" || units == "days" || units == "hours" || units == "minutes" || units == "seconds" || units == "msecs" || units == "usecs" || units == "hnsecs") { static if(units == "hnsecs") enum hnsecsPer = 1L; else static if(units == "usecs") enum hnsecsPer = 10L; else static if(units == "msecs") enum hnsecsPer = 1000 * hnsecsPer!"usecs"; else static if(units == "seconds") enum hnsecsPer = 1000 * hnsecsPer!"msecs"; else static if(units == "minutes") enum hnsecsPer = 60 * hnsecsPer!"seconds"; else static if(units == "hours") enum hnsecsPer = 60 * hnsecsPer!"minutes"; else static if(units == "days") enum hnsecsPer = 24 * hnsecsPer!"hours"; else static if(units == "weeks") enum hnsecsPer = 7 * hnsecsPer!"days"; } /+ Splits out a particular unit from hnsecs and gives you the value for that unit and the remaining hnsecs. It really shouldn't be used unless all units larger than the given units have already been split out. Params: units = The units to split out. hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left after splitting out the given units. Returns: The number of the given units from converting hnsecs to those units. +/ long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow @nogc if(units == "weeks" || units == "days" || units == "hours" || units == "minutes" || units == "seconds" || units == "msecs" || units == "usecs" || units == "hnsecs") { immutable value = convert!("hnsecs", units)(hnsecs); hnsecs -= convert!(units, "hnsecs")(value); return value; } /// unittest { auto hnsecs = 2595000000007L; immutable days = splitUnitsFromHNSecs!"days"(hnsecs); assert(days == 3); assert(hnsecs == 3000000007); immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); assert(minutes == 5); assert(hnsecs == 7); } /+ This function is used to split out the units without getting the remaining hnsecs. See_Also: $(LREF splitUnitsFromHNSecs) Params: units = The units to split out. hnsecs = The current total hnsecs. Returns: The split out value. +/ long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow @nogc if(units == "weeks" || units == "days" || units == "hours" || units == "minutes" || units == "seconds" || units == "msecs" || units == "usecs" || units == "hnsecs") { return convert!("hnsecs", units)(hnsecs); } /// unittest { auto hnsecs = 2595000000007L; immutable days = getUnitsFromHNSecs!"days"(hnsecs); assert(days == 3); assert(hnsecs == 2595000000007L); } /+ This function is used to split out the units without getting the units but just the remaining hnsecs. See_Also: $(LREF splitUnitsFromHNSecs) Params: units = The units to split out. hnsecs = The current total hnsecs. Returns: The remaining hnsecs. +/ long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow @nogc if(units == "weeks" || units == "days" || units == "hours" || units == "minutes" || units == "seconds" || units == "msecs" || units == "usecs" || units == "hnsecs") { immutable value = convert!("hnsecs", units)(hnsecs); return hnsecs - convert!(units, "hnsecs")(value); } /// unittest { auto hnsecs = 2595000000007L; auto returned = removeUnitsFromHNSecs!"days"(hnsecs); assert(returned == 3000000007); assert(hnsecs == 2595000000007L); } /+ Whether all of the given strings are among the accepted strings. +/ bool allAreAcceptedUnits(acceptedUnits...)(string[] units...) { foreach(unit; units) { bool found = false; foreach(acceptedUnit; acceptedUnits) { if(unit == acceptedUnit) { found = true; break; } } if(!found) return false; } return true; } unittest { assert(allAreAcceptedUnits!("hours", "seconds")("seconds", "hours")); assert(!allAreAcceptedUnits!("hours", "seconds")("minutes", "hours")); assert(!allAreAcceptedUnits!("hours", "seconds")("seconds", "minutes")); assert(allAreAcceptedUnits!("days", "hours", "minutes", "seconds", "msecs")("minutes")); assert(!allAreAcceptedUnits!("days", "hours", "minutes", "seconds", "msecs")("usecs")); assert(!allAreAcceptedUnits!("days", "hours", "minutes", "seconds", "msecs")("secs")); } /+ Whether the given time unit strings are arranged in order from largest to smallest. +/ bool unitsAreInDescendingOrder(string[] units...) { if(units.length <= 1) return true; immutable string[] timeStrings = ["nsecs", "hnsecs", "usecs", "msecs", "seconds", "minutes", "hours", "days", "weeks", "months", "years"]; size_t currIndex = 42; foreach(i, timeStr; timeStrings) { if(units[0] == timeStr) { currIndex = i; break; } } assert(currIndex != 42); foreach(unit; units[1 .. $]) { size_t nextIndex = 42; foreach(i, timeStr; timeStrings) { if(unit == timeStr) { nextIndex = i; break; } } assert(nextIndex != 42); if(currIndex <= nextIndex) return false; currIndex = nextIndex; } return true; } unittest { assert(unitsAreInDescendingOrder("years", "months", "weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs", "nsecs")); assert(unitsAreInDescendingOrder("weeks", "hours", "msecs")); assert(unitsAreInDescendingOrder("days", "hours", "minutes")); assert(unitsAreInDescendingOrder("hnsecs")); assert(!unitsAreInDescendingOrder("days", "hours", "hours")); assert(!unitsAreInDescendingOrder("days", "hours", "days")); } /+ The time units which are one step larger than the given units. +/ template nextLargerTimeUnits(string units) if(units == "days" || units == "hours" || units == "minutes" || units == "seconds" || units == "msecs" || units == "usecs" || units == "hnsecs" || units == "nsecs") { static if(units == "days") enum nextLargerTimeUnits = "weeks"; else static if(units == "hours") enum nextLargerTimeUnits = "days"; else static if(units == "minutes") enum nextLargerTimeUnits = "hours"; else static if(units == "seconds") enum nextLargerTimeUnits = "minutes"; else static if(units == "msecs") enum nextLargerTimeUnits = "seconds"; else static if(units == "usecs") enum nextLargerTimeUnits = "msecs"; else static if(units == "hnsecs") enum nextLargerTimeUnits = "usecs"; else static if(units == "nsecs") enum nextLargerTimeUnits = "hnsecs"; else static assert(0, "Broken template constraint"); } /// unittest { assert(nextLargerTimeUnits!"minutes" == "hours"); assert(nextLargerTimeUnits!"hnsecs" == "usecs"); } unittest { assert(nextLargerTimeUnits!"nsecs" == "hnsecs"); assert(nextLargerTimeUnits!"hnsecs" == "usecs"); assert(nextLargerTimeUnits!"usecs" == "msecs"); assert(nextLargerTimeUnits!"msecs" == "seconds"); assert(nextLargerTimeUnits!"seconds" == "minutes"); assert(nextLargerTimeUnits!"minutes" == "hours"); assert(nextLargerTimeUnits!"hours" == "days"); assert(nextLargerTimeUnits!"days" == "weeks"); static assert(!__traits(compiles, nextLargerTimeUnits!"weeks")); static assert(!__traits(compiles, nextLargerTimeUnits!"months")); static assert(!__traits(compiles, nextLargerTimeUnits!"years")); } version(OSX) long machTicksPerSecond() { // Be optimistic that ticksPerSecond (1e9*denom/numer) is integral. So far // so good on Darwin based platforms OS X, iOS. import core.internal.abort : abort; mach_timebase_info_data_t info; if(mach_timebase_info(&info) != 0) abort("Failed in mach_timebase_info()."); long scaledDenom = 1_000_000_000L * info.denom; if(scaledDenom % info.numer != 0) abort("Non integral ticksPerSecond from mach_timebase_info."); return scaledDenom / info.numer; } /+ Local version of abs, since std.math.abs is in Phobos, not druntime. +/ long _abs(long val) @safe pure nothrow @nogc { return val >= 0 ? val : -val; } double _abs(double val) @safe pure nothrow @nogc { return val >= 0.0 ? val : -val; } version(unittest) string doubleToString(double value) @safe pure nothrow { string result; if(value < 0 && cast(long)value == 0) result = "-0"; else result = signedToTempString(cast(long)value, 10).idup; result ~= '.'; result ~= unsignedToTempString(cast(ulong)(_abs((value - cast(long)value) * 1_000_000) + .5), 10); while (result[$-1] == '0') result = result[0 .. $-1]; return result; } unittest { auto a = 1.337; auto aStr = doubleToString(a); assert(aStr == "1.337", aStr); a = 0.337; aStr = doubleToString(a); assert(aStr == "0.337", aStr); a = -0.337; aStr = doubleToString(a); assert(aStr == "-0.337", aStr); } version(unittest) const(char)* numToStringz()(long value) @safe pure nothrow { return (signedToTempString(value, 10) ~ "\0").ptr; } /+ A copy of std.typecons.TypeTuple. +/ template _TypeTuple(TList...) { alias TList _TypeTuple; } /+ An adjusted copy of std.exception.assertThrown. +/ version(unittest) void _assertThrown(T : Throwable = Exception, E) (lazy E expression, string msg = null, string file = __FILE__, size_t line = __LINE__) { bool thrown = false; try expression(); catch(T t) thrown = true; if(!thrown) { immutable tail = msg.length == 0 ? "." : ": " ~ msg; throw new AssertError("assertThrown() failed: No " ~ T.stringof ~ " was thrown" ~ tail, file, line); } } unittest { void throwEx(Throwable t) { throw t; } void nothrowEx() {} try _assertThrown!Exception(throwEx(new Exception("It's an Exception"))); catch(AssertError) assert(0); try _assertThrown!Exception(throwEx(new Exception("It's an Exception")), "It's a message"); catch(AssertError) assert(0); try _assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__))); catch(AssertError) assert(0); try _assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)), "It's a message"); catch(AssertError) assert(0); { bool thrown = false; try _assertThrown!Exception(nothrowEx()); catch(AssertError) thrown = true; assert(thrown); } { bool thrown = false; try _assertThrown!Exception(nothrowEx(), "It's a message"); catch(AssertError) thrown = true; assert(thrown); } { bool thrown = false; try _assertThrown!AssertError(nothrowEx()); catch(AssertError) thrown = true; assert(thrown); } { bool thrown = false; try _assertThrown!AssertError(nothrowEx(), "It's a message"); catch(AssertError) thrown = true; assert(thrown); } } version(unittest) void assertApprox(D, E)(D actual, E lower, E upper, string msg = "unittest failure", size_t line = __LINE__) if(is(D : const Duration) && is(E : const Duration)) { if(actual < lower) throw new AssertError(msg ~ ": lower: " ~ actual.toString(), __FILE__, line); if(actual > upper) throw new AssertError(msg ~ ": upper: " ~ actual.toString(), __FILE__, line); } version(unittest) void assertApprox(D, E)(D actual, E lower, E upper, string msg = "unittest failure", size_t line = __LINE__) if(is(D : const TickDuration) && is(E : const TickDuration)) { if(actual.length < lower.length || actual.length > upper.length) { throw new AssertError(msg ~ (": [" ~ signedToTempString(lower.length, 10) ~ "] [" ~ signedToTempString(actual.length, 10) ~ "] [" ~ signedToTempString(upper.length, 10) ~ "]").idup, __FILE__, line); } } version(unittest) void assertApprox(MT)(MT actual, MT lower, MT upper, string msg = "unittest failure", size_t line = __LINE__) if(is(MT == MonoTimeImpl!type, ClockType type)) { assertApprox(actual._ticks, lower._ticks, upper._ticks, msg, line); } version(unittest) void assertApprox()(long actual, long lower, long upper, string msg = "unittest failure", size_t line = __LINE__) { if(actual < lower) throw new AssertError(msg ~ ": lower: " ~ signedToTempString(actual, 10).idup, __FILE__, line); if(actual > upper) throw new AssertError(msg ~ ": upper: " ~ signedToTempString(actual, 10).idup, __FILE__, line); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/checkedint.d0000664000175000017500000005470412776214756021462 0ustar kaikai /********************************************** * This module implements integral arithmetic primitives that check * for out-of-range results. * * Integral arithmetic operators operate on fixed width types. * Results that are not representable in those fixed widths are silently * truncated to fit. * This module offers integral arithmetic primitives that produce the * same results, but set an 'overflow' flag when such truncation occurs. * The setting is sticky, meaning that numerous operations can be cascaded * and then the flag need only be checked at the end. * Whether the operation is signed or unsigned is indicated by an 's' or 'u' * suffix, respectively. While this could be achieved without such suffixes by * using overloading on the signedness of the types, the suffix makes it clear * which is happening without needing to examine the types. * * While the generic versions of these functions are computationally expensive * relative to the cost of the operation itself, compiler implementations are free * to recognize them and generate equivalent and faster code. * * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks) * Copyright: Copyright (c) Walter Bright 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Walter Bright * Source: $(DRUNTIMESRC core/_checkedint.d) */ module core.checkedint; version(LDC) { import ldc.intrinsics; // llvm.(u)mul.with.overflow.i64 might fall back to a software implementation // in the form of __mulodi4, which only exists in compiler-rt and not // libgcc. Thus, we need to be sure not to emit it for now (see GitHub #818). version (X86_64) version = LDC_HasNativeI64Mul; } nothrow: @safe: @nogc: pure: /******************************* * Add two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the sum */ pragma(inline, true) int adds(int x, int y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_sadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } long r = cast(long)x + cast(long)y; if (r < int.min || r > int.max) overflow = true; return cast(int)r; } unittest { bool overflow; assert(adds(2, 3, overflow) == 5); assert(!overflow); assert(adds(1, int.max - 1, overflow) == int.max); assert(!overflow); assert(adds(int.min + 1, -1, overflow) == int.min); assert(!overflow); assert(adds(int.max, 1, overflow) == int.min); assert(overflow); overflow = false; assert(adds(int.min, -1, overflow) == int.max); assert(overflow); assert(adds(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) long adds(long x, long y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_sadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } long r = cast(ulong)x + cast(ulong)y; if (x < 0 && y < 0 && r >= 0 || x >= 0 && y >= 0 && r < 0) overflow = true; return r; } unittest { bool overflow; assert(adds(2L, 3L, overflow) == 5); assert(!overflow); assert(adds(1L, long.max - 1, overflow) == long.max); assert(!overflow); assert(adds(long.min + 1, -1, overflow) == long.min); assert(!overflow); assert(adds(long.max, 1, overflow) == long.min); assert(overflow); overflow = false; assert(adds(long.min, -1, overflow) == long.max); assert(overflow); assert(adds(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(cent)) { /// ditto cent adds(cent x, cent y, ref bool overflow) { version(LDC) { pragma(inline, true); if (!__ctfe) { auto res = llvm_sadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } cent r = cast(ucent)x + cast(ucent)y; if (x < 0 && y < 0 && r >= 0 || x >= 0 && y >= 0 && r < 0) overflow = true; return r; } unittest { bool overflow; assert(adds(cast(cent)2L, 3L, overflow) == 5); assert(!overflow); assert(adds(1L, cent.max - 1, overflow) == cent.max); assert(!overflow); assert(adds(cent.min + 1, -1, overflow) == cent.min); assert(!overflow); assert(adds(cent.max, 1, overflow) == cent.min); assert(overflow); overflow = false; assert(adds(cent.min, -1, overflow) == cent.max); assert(overflow); assert(adds(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Add two unsigned integers, checking for overflow (aka carry). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the sum */ pragma(inline, true) uint addu(uint x, uint y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_uadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } uint r = x + y; if (r < x || r < y) overflow = true; return r; } unittest { bool overflow; assert(addu(2, 3, overflow) == 5); assert(!overflow); assert(addu(1, uint.max - 1, overflow) == uint.max); assert(!overflow); assert(addu(uint.min, -1, overflow) == uint.max); assert(!overflow); assert(addu(uint.max, 1, overflow) == uint.min); assert(overflow); overflow = false; assert(addu(uint.min + 1, -1, overflow) == uint.min); assert(overflow); assert(addu(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) ulong addu(ulong x, ulong y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_uadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } ulong r = x + y; if (r < x || r < y) overflow = true; return r; } unittest { bool overflow; assert(addu(2L, 3L, overflow) == 5); assert(!overflow); assert(addu(1, ulong.max - 1, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.min, -1L, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.max, 1, overflow) == ulong.min); assert(overflow); overflow = false; assert(addu(ulong.min + 1, -1L, overflow) == ulong.min); assert(overflow); assert(addu(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(ucent)) { /// ditto ucent addu(ucent x, ucent y, ref bool overflow) { version(LDC) { pragma(inline, true); if (!__ctfe) { auto res = llvm_uadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } ucent r = x + y; if (r < x || r < y) overflow = true; return r; } unittest { bool overflow; assert(addu(cast(ucent)2L, 3L, overflow) == 5); assert(!overflow); assert(addu(1, ulong.max - 1, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.min, -1L, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.max, 1, overflow) == ulong.min); assert(overflow); overflow = false; assert(addu(ulong.min + 1, -1L, overflow) == ulong.min); assert(overflow); assert(addu(cast(ucent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Subtract two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the difference */ pragma(inline, true) int subs(int x, int y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_ssub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } long r = cast(long)x - cast(long)y; if (r < int.min || r > int.max) overflow = true; return cast(int)r; } unittest { bool overflow; assert(subs(2, -3, overflow) == 5); assert(!overflow); assert(subs(1, -int.max + 1, overflow) == int.max); assert(!overflow); assert(subs(int.min + 1, 1, overflow) == int.min); assert(!overflow); assert(subs(int.max, -1, overflow) == int.min); assert(overflow); overflow = false; assert(subs(int.min, 1, overflow) == int.max); assert(overflow); assert(subs(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) long subs(long x, long y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_ssub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } long r = cast(ulong)x - cast(ulong)y; if (x < 0 && y >= 0 && r >= 0 || x >= 0 && y < 0 && (r < 0 || y == long.min)) overflow = true; return r; } unittest { bool overflow; assert(subs(2L, -3L, overflow) == 5); assert(!overflow); assert(subs(1L, -long.max + 1, overflow) == long.max); assert(!overflow); assert(subs(long.min + 1, 1, overflow) == long.min); assert(!overflow); assert(subs(-1L, long.min, overflow) == long.max); assert(!overflow); assert(subs(long.max, -1, overflow) == long.min); assert(overflow); overflow = false; assert(subs(long.min, 1, overflow) == long.max); assert(overflow); assert(subs(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(cent)) { /// ditto cent subs(cent x, cent y, ref bool overflow) { version(LDC) { pragma(inline, true); if (!__ctfe) { auto res = llvm_ssub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } cent r = cast(ucent)x - cast(ucent)y; if (x < 0 && y >= 0 && r >= 0 || x >= 0 && y < 0 && r < 0 || y == cent.min) overflow = true; return r; } unittest { bool overflow; assert(subs(cast(cent)2L, -3L, overflow) == 5); assert(!overflow); assert(subs(1L, -cent.max + 1, overflow) == cent.max); assert(!overflow); assert(subs(cent.min + 1, 1, overflow) == cent.min); assert(!overflow); assert(subs(cent.max, -1, overflow) == cent.min); assert(overflow); overflow = false; assert(subs(cent.min, 1, overflow) == cent.max); assert(overflow); assert(subs(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Subtract two unsigned integers, checking for overflow (aka borrow). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the difference */ pragma(inline, true) uint subu(uint x, uint y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_usub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } if (x < y) overflow = true; return x - y; } unittest { bool overflow; assert(subu(3, 2, overflow) == 1); assert(!overflow); assert(subu(uint.max, 1, overflow) == uint.max - 1); assert(!overflow); assert(subu(1, 1, overflow) == uint.min); assert(!overflow); assert(subu(0, 1, overflow) == uint.max); assert(overflow); overflow = false; assert(subu(uint.max - 1, uint.max, overflow) == uint.max); assert(overflow); assert(subu(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) ulong subu(ulong x, ulong y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_usub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } if (x < y) overflow = true; return x - y; } unittest { bool overflow; assert(subu(3UL, 2UL, overflow) == 1); assert(!overflow); assert(subu(ulong.max, 1, overflow) == ulong.max - 1); assert(!overflow); assert(subu(1UL, 1UL, overflow) == ulong.min); assert(!overflow); assert(subu(0UL, 1UL, overflow) == ulong.max); assert(overflow); overflow = false; assert(subu(ulong.max - 1, ulong.max, overflow) == ulong.max); assert(overflow); assert(subu(0UL, 0UL, overflow) == 0); assert(overflow); // sticky } static if (is(ucent)) { /// ditto ucent subu(ucent x, ucent y, ref bool overflow) { version(LDC) { pragma(inline, true); if (!__ctfe) { auto res = llvm_usub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } if (x < y) overflow = true; return x - y; } unittest { bool overflow; assert(subu(cast(ucent)3UL, 2UL, overflow) == 1); assert(!overflow); assert(subu(ucent.max, 1, overflow) == ucent.max - 1); assert(!overflow); assert(subu(1UL, 1UL, overflow) == ucent.min); assert(!overflow); assert(subu(0UL, 1UL, overflow) == ucent.max); assert(overflow); overflow = false; assert(subu(ucent.max - 1, ucent.max, overflow) == ucent.max); assert(overflow); assert(subu(cast(ucent)0UL, 0UL, overflow) == 0); assert(overflow); // sticky } } /*********************************************** * Negate an integer. * * Params: * x = operand * overflow = set if x cannot be negated, is not affected otherwise * Returns: * the negation of x */ pragma(inline, true) int negs(int x, ref bool overflow) { if (x == int.min) overflow = true; return -x; } unittest { bool overflow; assert(negs(0, overflow) == -0); assert(!overflow); assert(negs(1234, overflow) == -1234); assert(!overflow); assert(negs(-5678, overflow) == 5678); assert(!overflow); assert(negs(int.min, overflow) == -int.min); assert(overflow); assert(negs(0, overflow) == -0); assert(overflow); // sticky } /// ditto pragma(inline, true) long negs(long x, ref bool overflow) { if (x == long.min) overflow = true; return -x; } unittest { bool overflow; assert(negs(0L, overflow) == -0); assert(!overflow); assert(negs(1234L, overflow) == -1234); assert(!overflow); assert(negs(-5678L, overflow) == 5678); assert(!overflow); assert(negs(long.min, overflow) == -long.min); assert(overflow); assert(negs(0L, overflow) == -0); assert(overflow); // sticky } static if (is(cent)) { /// ditto cent negs(cent x, ref bool overflow) { if (x == cent.min) overflow = true; return -x; } unittest { bool overflow; assert(negs(cast(cent)0L, overflow) == -0); assert(!overflow); assert(negs(cast(cent)1234L, overflow) == -1234); assert(!overflow); assert(negs(cast(cent)-5678L, overflow) == 5678); assert(!overflow); assert(negs(cent.min, overflow) == -cent.min); assert(overflow); assert(negs(cast(cent)0L, overflow) == -0); assert(overflow); // sticky } } /******************************* * Multiply two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the product */ pragma(inline, true) int muls(int x, int y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_smul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } long r = cast(long)x * cast(long)y; if (r < int.min || r > int.max) overflow = true; return cast(int)r; } unittest { bool overflow; assert(muls(2, 3, overflow) == 6); assert(!overflow); assert(muls(-200, 300, overflow) == -60_000); assert(!overflow); assert(muls(1, int.max, overflow) == int.max); assert(!overflow); assert(muls(int.min, 1, overflow) == int.min); assert(!overflow); assert(muls(int.max, 2, overflow) == (int.max * 2)); assert(overflow); overflow = false; assert(muls(int.min, -1, overflow) == int.min); assert(overflow); assert(muls(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) long muls(long x, long y, ref bool overflow) { version(LDC_HasNativeI64Mul) { if (!__ctfe) { auto res = llvm_smul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } long r = cast(ulong)x * cast(ulong)y; enum not0or1 = ~1L; if((x & not0or1) && ((r == y)? r : (r / x) != y)) overflow = true; return r; } unittest { bool overflow; assert(muls(2L, 3L, overflow) == 6); assert(!overflow); assert(muls(-200L, 300L, overflow) == -60_000); assert(!overflow); assert(muls(1, long.max, overflow) == long.max); assert(!overflow); assert(muls(long.min, 1L, overflow) == long.min); assert(!overflow); assert(muls(long.max, 2L, overflow) == (long.max * 2)); assert(overflow); overflow = false; assert(muls(-1L, long.min, overflow) == long.min); assert(overflow); overflow = false; assert(muls(long.min, -1L, overflow) == long.min); assert(overflow); assert(muls(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(cent)) { /// ditto cent muls(cent x, cent y, ref bool overflow) { version(LDC_HasNativeI64Mul) { if (!__ctfe) { auto res = llvm_smul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } cent r = cast(ucent)x * cast(ucent)y; if (x && (r / x) != y) overflow = true; return r; } unittest { bool overflow; assert(muls(cast(cent)2L, 3L, overflow) == 6); assert(!overflow); assert(muls(cast(cent)-200L, 300L, overflow) == -60_000); assert(!overflow); assert(muls(1, cent.max, overflow) == cent.max); assert(!overflow); assert(muls(cent.min, 1L, overflow) == cent.min); assert(!overflow); assert(muls(cent.max, 2L, overflow) == (cent.max * 2)); assert(overflow); overflow = false; assert(muls(cent.min, -1L, overflow) == cent.min); assert(overflow); assert(muls(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Multiply two unsigned integers, checking for overflow (aka carry). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the product */ pragma(inline, true) uint mulu(uint x, uint y, ref bool overflow) { version(LDC) { if (!__ctfe) { auto res = llvm_umul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } ulong r = ulong(x) * ulong(y); if (r > uint.max) overflow = true; return cast(uint)r; } unittest { void test(uint x, uint y, uint r, bool overflow) @nogc nothrow { bool o; assert(mulu(x, y, o) == r); assert(o == overflow); } test(2, 3, 6, false); test(1, uint.max, uint.max, false); test(0, 1, 0, false); test(0, uint.max, 0, false); test(uint.max, 2, 2 * uint.max, true); test(1 << 16, 1U << 16, 0, true); bool overflow = true; assert(mulu(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) ulong mulu(ulong x, ulong y, ref bool overflow) { version(LDC_HasNativeI64Mul) { if (!__ctfe) { auto res = llvm_umul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } ulong r = x * y; if (x && (r / x) != y) overflow = true; return r; } unittest { void test(ulong x, ulong y, ulong r, bool overflow) @nogc nothrow { bool o; assert(mulu(x, y, o) == r); assert(o == overflow); } test(2, 3, 6, false); test(1, ulong.max, ulong.max, false); test(0, 1, 0, false); test(0, ulong.max, 0, false); test(ulong.max, 2, 2 * ulong.max, true); test(1UL << 32, 1UL << 32, 0, true); bool overflow = true; assert(mulu(0UL, 0UL, overflow) == 0); assert(overflow); // sticky } static if(is(ucent)) { /// ditto ucent mulu(ucent x, ucent y, ref bool overflow) { version(LDC_HasNativeI64Mul) { if (!__ctfe) { auto res = llvm_umul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } else { ucent r = x * y; if (x && (r / x) != y) overflow = true; return r; } } unittest { void test(ucent x, ucent y, ucent r, bool overflow) @nogc nothrow { bool o; assert(mulu(x, y, o) == r); assert(o == overflow); } test(2, 3, 6, false); test(1, ucent.max, ucent.max, false); test(0, 1, 0, false); test(0, ucent.max, 0, false); test(ucent.max, 2, 2 * ucent.max, true); test(cast(ucent)1UL << 64, cast(ucent)1UL << 64, 0, true); bool overflow = true; assert(mulu(0UL, 0UL, overflow) == 0); assert(overflow); // sticky } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/atomic.d0000664000175000017500000015417612776214756020641 0ustar kaikai/** * The atomic module provides basic support for lock-free * concurrent programming. * * Copyright: Copyright Sean Kelly 2005 - 2010. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly, Alex Rønne Petersen * Source: $(DRUNTIMESRC core/_atomic.d) */ /* Copyright Sean Kelly 2005 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.atomic; version (LDC) { enum has64BitCAS = true; // Enable 128bit CAS on 64bit platforms if supported. version(D_LP64) { version (PPC64) enum has128BitCAS = false; else enum has128BitCAS = true; } else enum has128BitCAS = false; } else version( D_InlineAsm_X86 ) { version = AsmX86; version = AsmX86_32; enum has64BitCAS = true; enum has128BitCAS = false; } else version( D_InlineAsm_X86_64 ) { version = AsmX86; version = AsmX86_64; enum has64BitCAS = true; enum has128BitCAS = true; } else { enum has64BitCAS = false; enum has128BitCAS = false; } private { template HeadUnshared(T) { static if( is( T U : shared(U*) ) ) alias shared(U)* HeadUnshared; else alias T HeadUnshared; } } version( AsmX86 ) { // NOTE: Strictly speaking, the x86 supports atomic operations on // unaligned values. However, this is far slower than the // common case, so such behavior should be prohibited. private bool atomicValueIsProperlyAligned(T)( size_t addr ) pure nothrow { return addr % T.sizeof == 0; } } version( CoreDdoc ) { /** * Performs the binary operation 'op' on val using 'mod' as the modifier. * * Params: * val = The target variable. * mod = The modifier to apply. * * Returns: * The result of the operation. */ HeadUnshared!(T) atomicOp(string op, T, V1)( ref shared T val, V1 mod ) pure nothrow @nogc if( __traits( compiles, mixin( "*cast(T*)&val" ~ op ~ "mod" ) ) ) { return HeadUnshared!(T).init; } /** * Stores 'writeThis' to the memory referenced by 'here' if the value * referenced by 'here' is equal to 'ifThis'. This operation is both * lock-free and atomic. * * Params: * here = The address of the destination variable. * writeThis = The value to store. * ifThis = The comparison value. * * Returns: * true if the store occurred, false if not. */ bool cas(T,V1,V2)( shared(T)* here, const V1 ifThis, V2 writeThis ) pure nothrow @nogc if( !is(T == class) && !is(T U : U*) && __traits( compiles, { *here = writeThis; } ) ); /// Ditto bool cas(T,V1,V2)( shared(T)* here, const shared(V1) ifThis, shared(V2) writeThis ) pure nothrow @nogc if( is(T == class) && __traits( compiles, { *here = writeThis; } ) ); /// Ditto bool cas(T,V1,V2)( shared(T)* here, const shared(V1)* ifThis, shared(V2)* writeThis ) pure nothrow @nogc if( is(T U : U*) && __traits( compiles, { *here = writeThis; } ) ); /** * Loads 'val' from memory and returns it. The memory barrier specified * by 'ms' is applied to the operation, which is fully sequenced by * default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq, * and MemoryOrder.seq. * * Params: * val = The target variable. * * Returns: * The value of 'val'. */ HeadUnshared!(T) atomicLoad(MemoryOrder ms = MemoryOrder.seq,T)( ref const shared T val ) pure nothrow @nogc { return HeadUnshared!(T).init; } /** * Writes 'newval' into 'val'. The memory barrier specified by 'ms' is * applied to the operation, which is fully sequenced by default. * Valid memory orders are MemoryOrder.raw, MemoryOrder.rel, and * MemoryOrder.seq. * * Params: * val = The target variable. * newval = The value to store. */ void atomicStore(MemoryOrder ms = MemoryOrder.seq,T,V1)( ref shared T val, V1 newval ) pure nothrow @nogc if( __traits( compiles, { val = newval; } ) ) { } /** * Specifies the memory ordering semantics of an atomic operation. */ enum MemoryOrder { raw, /// Not sequenced. acq, /// Hoist-load + hoist-store barrier. rel, /// Sink-load + sink-store barrier. seq, /// Fully sequenced (acquire + release). } deprecated("Please use MemoryOrder instead.") alias MemoryOrder msync; /** * Inserts a full load/store memory fence (on platforms that need it). This ensures * that all loads and stores before a call to this function are executed before any * loads and stores after the call. */ void atomicFence() nothrow @nogc; } else version( LDC ) { import ldc.intrinsics; pragma(inline, true): HeadUnshared!(T) atomicOp(string op, T, V1)( ref shared T val, V1 mod ) if( __traits( compiles, mixin( "*cast(T*)&val" ~ op ~ "mod" ) ) ) { enum suitedForAtomicRmw = (__traits(isIntegral, T) && __traits(isIntegral, V1) && T.sizeof <= AtomicRmwSizeLimit && V1.sizeof <= AtomicRmwSizeLimit); // binary operators // // + - * / % ^^ & // | ^ << >> >>> ~ in // == != < <= > >= static if( op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^" || op == "&" || op == "|" || op == "^" || op == "<<" || op == ">>" || op == ">>>" || op == "~" || // skip "in" op == "==" || op == "!=" || op == "<" || op == "<=" || op == ">" || op == ">=" ) { HeadUnshared!(T) get = atomicLoad!(MemoryOrder.raw)( val ); mixin( "return get " ~ op ~ " mod;" ); } else // assignment operators // // += -= *= /= %= ^^= &= // |= ^= <<= >>= >>>= ~= static if( op == "+=" && suitedForAtomicRmw ) { T m = cast(T) mod; return cast(T)(llvm_atomic_rmw_add(&val, m) + m); } else static if( op == "-=" && suitedForAtomicRmw ) { T m = cast(T) mod; return cast(T)(llvm_atomic_rmw_sub(&val, m) - m); } else static if( op == "&=" && suitedForAtomicRmw ) { T m = cast(T) mod; return cast(T)(llvm_atomic_rmw_and(&val, m) & m); } else static if( op == "|=" && suitedForAtomicRmw ) { T m = cast(T) mod; return cast(T)(llvm_atomic_rmw_or(&val, m) | m); } else static if( op == "^=" && suitedForAtomicRmw ) { T m = cast(T) mod; return cast(T)(llvm_atomic_rmw_xor(&val, m) ^ m); } else static if( op == "+=" || op == "-=" || op == "*=" || op == "/=" || op == "%=" || op == "^^=" || op == "&=" || op == "|=" || op == "^=" || op == "<<=" || op == ">>=" || op == ">>>=" ) // skip "~=" { HeadUnshared!(T) get, set; do { get = set = atomicLoad!(MemoryOrder.raw)( val ); mixin( "set " ~ op ~ " mod;" ); } while( !cas( &val, get, set ) ); return set; } else { static assert( false, "Operation not supported." ); } } bool cas(T,V1,V2)( shared(T)* here, const V1 ifThis, V2 writeThis ) if( !is(T == class) && !is(T U : U*) && __traits( compiles, { *here = writeThis; } ) ) { return casImpl(here, ifThis, writeThis); } bool cas(T,V1,V2)( shared(T)* here, const shared(V1) ifThis, shared(V2) writeThis ) if( is(T == class) && __traits( compiles, { *here = writeThis; } ) ) { return casImpl(here, ifThis, writeThis); } bool cas(T,V1,V2)( shared(T)* here, const shared(V1)* ifThis, shared(V2)* writeThis ) if( is(T U : U*) && __traits( compiles, { *here = writeThis; } ) ) { return casImpl(here, ifThis, writeThis); } private bool casImpl(T,V1,V2)( shared(T)* here, V1 ifThis, V2 writeThis ) { T res = void; static if (__traits(isFloating, T)) { static if(T.sizeof == int.sizeof) { static assert(is(T : float)); int rawRes = llvm_atomic_cmp_xchg!int( cast(shared int*)here, *cast(int*)&ifThis, *cast(int*)&writeThis); res = *(cast(T*)&rawRes); } else static if(T.sizeof == long.sizeof) { static assert(is(T : double)); long rawRes = cast(T)llvm_atomic_cmp_xchg!long( cast(shared long*)here, *cast(long*)&ifThis, *cast(long*)&writeThis); res = *(cast(T*)&rawRes); } else { static assert(0, "Cannot atomically store 80-bit reals."); } } else static if (is(T P == U*, U) || is(T == class) || is(T == interface)) { res = cast(T)cast(void*)llvm_atomic_cmp_xchg!(size_t)( cast(shared size_t*)cast(void**)here, cast(size_t)cast(void*)ifThis, cast(size_t)cast(void*)writeThis ); } else static if (is(T : bool)) { res = llvm_atomic_cmp_xchg!(ubyte)(cast(shared ubyte*)here, ifThis ? 1 : 0, writeThis ? 1 : 0) ? 1 : 0; } else { res = llvm_atomic_cmp_xchg!(T)(here, cast(T)ifThis, cast(T)writeThis); } return res is cast(T)ifThis; } enum MemoryOrder { raw, acq, rel, seq, } deprecated alias MemoryOrder msync; template _ordering(MemoryOrder ms) { static if (ms == MemoryOrder.acq) { enum _ordering = AtomicOrdering.Acquire; } else static if (ms == MemoryOrder.rel) { enum _ordering = AtomicOrdering.Release; } else static if (ms == MemoryOrder.seq) { enum _ordering = AtomicOrdering.SequentiallyConsistent; } else static if (ms == MemoryOrder.raw) { // Note that C/C++ 'relaxed' is not the same as NoAtomic/Unordered, // but Monotonic. enum _ordering = AtomicOrdering.Monotonic; } else { static assert(0); } } private template _AtomicType(T) { static if (T.sizeof == ubyte.sizeof) alias _AtomicType = ubyte; else static if (T.sizeof == ushort.sizeof) alias _AtomicType = ushort; else static if (T.sizeof == uint.sizeof) alias _AtomicType = uint; else static if (T.sizeof == ulong.sizeof) alias _AtomicType = ulong; else static if (T.sizeof == 2*ulong.sizeof && has128BitCAS) { struct UCent { ulong value1; ulong value2; } alias _AtomicType = UCent; } else static assert(is(_AtomicType!T), "Cannot atomically load/store type of size " ~ T.sizeof.stringof); } // This could also handle floating-point types, the constraint is just there // to avoid ambiguities with below "general" floating point definition from // the upstream runtime. HeadUnshared!T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref const shared T val) if( !__traits(isFloating, T) ) { alias Int = _AtomicType!T; auto asInt = llvm_atomic_load!Int(cast(shared(Int)*)cast(void*)&val, _ordering!(ms)); return *cast(HeadUnshared!T*)&asInt; } void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V1)( ref shared T val, V1 newval ) if( __traits( compiles, { val = newval; } ) ) { alias Int = _AtomicType!T; auto target = cast(shared(Int)*)cast(void*)&val; auto newPtr = cast(Int*)&newval; llvm_atomic_store!Int(*newPtr, target, _ordering!(ms)); } void atomicFence() nothrow { llvm_memory_fence(); } } else version( AsmX86_32 ) { // Uses specialized asm for fast fetch and add operations private HeadUnshared!(T) atomicFetchAdd(T, V1)( ref shared T val, V1 mod ) pure nothrow @nogc if( T.sizeof <= 4 && V1.sizeof <= 4) { size_t tmp = mod; // convert all operands to size_t asm pure nothrow @nogc { mov EAX, tmp; mov EDX, val; } static if (T.sizeof == 1) asm pure nothrow @nogc { lock; xadd[EDX], AL; } else static if (T.sizeof == 2) asm pure nothrow @nogc { lock; xadd[EDX], AX; } else static if (T.sizeof == 4) asm pure nothrow @nogc { lock; xadd[EDX], EAX; } asm pure nothrow @nogc { mov tmp, EAX; } return cast(T)tmp; } private HeadUnshared!(T) atomicFetchSub(T, V1)( ref shared T val, V1 mod ) pure nothrow @nogc if( T.sizeof <= 4 && V1.sizeof <= 4) { return atomicFetchAdd(val, -mod); } HeadUnshared!(T) atomicOp(string op, T, V1)( ref shared T val, V1 mod ) pure nothrow @nogc if( __traits( compiles, mixin( "*cast(T*)&val" ~ op ~ "mod" ) ) ) in { // NOTE: 32 bit x86 systems support 8 byte CAS, which only requires // 4 byte alignment, so use size_t as the align type here. static if( T.sizeof > size_t.sizeof ) assert( atomicValueIsProperlyAligned!(size_t)( cast(size_t) &val ) ); else assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) ); } body { // binary operators // // + - * / % ^^ & // | ^ << >> >>> ~ in // == != < <= > >= static if( op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^" || op == "&" || op == "|" || op == "^" || op == "<<" || op == ">>" || op == ">>>" || op == "~" || // skip "in" op == "==" || op == "!=" || op == "<" || op == "<=" || op == ">" || op == ">=" ) { HeadUnshared!(T) get = atomicLoad!(MemoryOrder.raw)( val ); mixin( "return get " ~ op ~ " mod;" ); } else // assignment operators // // += -= *= /= %= ^^= &= // |= ^= <<= >>= >>>= ~= static if( op == "+=" && __traits(isIntegral, T) && T.sizeof <= 4 && V1.sizeof <= 4) { return cast(T)(atomicFetchAdd!(T)(val, mod) + mod); } else static if( op == "-=" && __traits(isIntegral, T) && T.sizeof <= 4 && V1.sizeof <= 4) { return cast(T)(atomicFetchSub!(T)(val, mod) - mod); } else static if( op == "+=" || op == "-=" || op == "*=" || op == "/=" || op == "%=" || op == "^^=" || op == "&=" || op == "|=" || op == "^=" || op == "<<=" || op == ">>=" || op == ">>>=" ) // skip "~=" { HeadUnshared!(T) get, set; do { get = set = atomicLoad!(MemoryOrder.raw)( val ); mixin( "set " ~ op ~ " mod;" ); } while( !cas( &val, get, set ) ); return set; } else { static assert( false, "Operation not supported." ); } } bool cas(T,V1,V2)( shared(T)* here, const V1 ifThis, V2 writeThis ) pure nothrow @nogc if( !is(T == class) && !is(T U : U*) && __traits( compiles, { *here = writeThis; } ) ) { return casImpl(here, ifThis, writeThis); } bool cas(T,V1,V2)( shared(T)* here, const shared(V1) ifThis, shared(V2) writeThis ) pure nothrow @nogc if( is(T == class) && __traits( compiles, { *here = writeThis; } ) ) { return casImpl(here, ifThis, writeThis); } bool cas(T,V1,V2)( shared(T)* here, const shared(V1)* ifThis, shared(V2)* writeThis ) pure nothrow @nogc if( is(T U : U*) && __traits( compiles, { *here = writeThis; } ) ) { return casImpl(here, ifThis, writeThis); } private bool casImpl(T,V1,V2)( shared(T)* here, V1 ifThis, V2 writeThis ) pure nothrow @nogc in { // NOTE: 32 bit x86 systems support 8 byte CAS, which only requires // 4 byte alignment, so use size_t as the align type here. static if( T.sizeof > size_t.sizeof ) assert( atomicValueIsProperlyAligned!(size_t)( cast(size_t) here ) ); else assert( atomicValueIsProperlyAligned!(T)( cast(size_t) here ) ); } body { static if( T.sizeof == byte.sizeof ) { ////////////////////////////////////////////////////////////////// // 1 Byte CAS ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { mov DL, writeThis; mov AL, ifThis; mov ECX, here; lock; // lock always needed to make this op atomic cmpxchg [ECX], DL; setz AL; } } else static if( T.sizeof == short.sizeof ) { ////////////////////////////////////////////////////////////////// // 2 Byte CAS ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { mov DX, writeThis; mov AX, ifThis; mov ECX, here; lock; // lock always needed to make this op atomic cmpxchg [ECX], DX; setz AL; } } else static if( T.sizeof == int.sizeof ) { ////////////////////////////////////////////////////////////////// // 4 Byte CAS ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { mov EDX, writeThis; mov EAX, ifThis; mov ECX, here; lock; // lock always needed to make this op atomic cmpxchg [ECX], EDX; setz AL; } } else static if( T.sizeof == long.sizeof && has64BitCAS ) { ////////////////////////////////////////////////////////////////// // 8 Byte CAS on a 32-Bit Processor ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { push EDI; push EBX; lea EDI, writeThis; mov EBX, [EDI]; mov ECX, 4[EDI]; lea EDI, ifThis; mov EAX, [EDI]; mov EDX, 4[EDI]; mov EDI, here; lock; // lock always needed to make this op atomic cmpxchg8b [EDI]; setz AL; pop EBX; pop EDI; } } else { static assert( false, "Invalid template type specified." ); } } enum MemoryOrder { raw, acq, rel, seq, } deprecated("Please use MemoryOrder instead.") alias MemoryOrder msync; private { // NOTE: x86 loads implicitly have acquire semantics so a memory // barrier is only necessary on releases. template needsLoadBarrier( MemoryOrder ms ) { enum bool needsLoadBarrier = ms == MemoryOrder.seq; } // NOTE: x86 stores implicitly have release semantics so a memory // barrier is only necessary on acquires. template needsStoreBarrier( MemoryOrder ms ) { enum bool needsStoreBarrier = ms == MemoryOrder.seq; } } HeadUnshared!(T) atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)( ref const shared T val ) pure nothrow @nogc if(!__traits(isFloating, T)) { static assert( ms != MemoryOrder.rel, "invalid MemoryOrder for atomicLoad()" ); static assert( __traits(isPOD, T), "argument to atomicLoad() must be POD" ); static if( T.sizeof == byte.sizeof ) { ////////////////////////////////////////////////////////////////// // 1 Byte Load ////////////////////////////////////////////////////////////////// static if( needsLoadBarrier!(ms) ) { asm pure nothrow @nogc { mov DL, 0; mov AL, 0; mov ECX, val; lock; // lock always needed to make this op atomic cmpxchg [ECX], DL; } } else { asm pure nothrow @nogc { mov EAX, val; mov AL, [EAX]; } } } else static if( T.sizeof == short.sizeof ) { ////////////////////////////////////////////////////////////////// // 2 Byte Load ////////////////////////////////////////////////////////////////// static if( needsLoadBarrier!(ms) ) { asm pure nothrow @nogc { mov DX, 0; mov AX, 0; mov ECX, val; lock; // lock always needed to make this op atomic cmpxchg [ECX], DX; } } else { asm pure nothrow @nogc { mov EAX, val; mov AX, [EAX]; } } } else static if( T.sizeof == int.sizeof ) { ////////////////////////////////////////////////////////////////// // 4 Byte Load ////////////////////////////////////////////////////////////////// static if( needsLoadBarrier!(ms) ) { asm pure nothrow @nogc { mov EDX, 0; mov EAX, 0; mov ECX, val; lock; // lock always needed to make this op atomic cmpxchg [ECX], EDX; } } else { asm pure nothrow @nogc { mov EAX, val; mov EAX, [EAX]; } } } else static if( T.sizeof == long.sizeof && has64BitCAS ) { ////////////////////////////////////////////////////////////////// // 8 Byte Load on a 32-Bit Processor ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { push EDI; push EBX; mov EBX, 0; mov ECX, 0; mov EAX, 0; mov EDX, 0; mov EDI, val; lock; // lock always needed to make this op atomic cmpxchg8b [EDI]; pop EBX; pop EDI; } } else { static assert( false, "Invalid template type specified." ); } } void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V1)( ref shared T val, V1 newval ) pure nothrow @nogc if( __traits( compiles, { val = newval; } ) ) { static assert( ms != MemoryOrder.acq, "invalid MemoryOrder for atomicStore()" ); static assert( __traits(isPOD, T), "argument to atomicStore() must be POD" ); static if( T.sizeof == byte.sizeof ) { ////////////////////////////////////////////////////////////////// // 1 Byte Store ////////////////////////////////////////////////////////////////// static if( needsStoreBarrier!(ms) ) { asm pure nothrow @nogc { mov EAX, val; mov DL, newval; lock; xchg [EAX], DL; } } else { asm pure nothrow @nogc { mov EAX, val; mov DL, newval; mov [EAX], DL; } } } else static if( T.sizeof == short.sizeof ) { ////////////////////////////////////////////////////////////////// // 2 Byte Store ////////////////////////////////////////////////////////////////// static if( needsStoreBarrier!(ms) ) { asm pure nothrow @nogc { mov EAX, val; mov DX, newval; lock; xchg [EAX], DX; } } else { asm pure nothrow @nogc { mov EAX, val; mov DX, newval; mov [EAX], DX; } } } else static if( T.sizeof == int.sizeof ) { ////////////////////////////////////////////////////////////////// // 4 Byte Store ////////////////////////////////////////////////////////////////// static if( needsStoreBarrier!(ms) ) { asm pure nothrow @nogc { mov EAX, val; mov EDX, newval; lock; xchg [EAX], EDX; } } else { asm pure nothrow @nogc { mov EAX, val; mov EDX, newval; mov [EAX], EDX; } } } else static if( T.sizeof == long.sizeof && has64BitCAS ) { ////////////////////////////////////////////////////////////////// // 8 Byte Store on a 32-Bit Processor ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { push EDI; push EBX; lea EDI, newval; mov EBX, [EDI]; mov ECX, 4[EDI]; mov EDI, val; mov EAX, [EDI]; mov EDX, 4[EDI]; L1: lock; // lock always needed to make this op atomic cmpxchg8b [EDI]; jne L1; pop EBX; pop EDI; } } else { static assert( false, "Invalid template type specified." ); } } void atomicFence() nothrow { import core.cpuid; asm pure nothrow @nogc { naked; call sse2; test AL, AL; jne Lcpuid; // Fast path: We have SSE2, so just use mfence. mfence; jmp Lend; Lcpuid: // Slow path: We use cpuid to serialize. This is // significantly slower than mfence, but is the // only serialization facility we have available // on older non-SSE2 chips. push EBX; mov EAX, 0; cpuid; pop EBX; Lend: ret; } } } else version( AsmX86_64 ) { // Uses specialized asm for fast fetch and add operations private HeadUnshared!(T) atomicFetchAdd(T, V1)( ref shared T val, V1 mod ) pure nothrow @nogc if( __traits(isIntegral, T) && __traits(isIntegral, V1) ) in { // NOTE: 32 bit x86 systems support 8 byte CAS, which only requires // 4 byte alignment, so use size_t as the align type here. static if( T.sizeof > size_t.sizeof ) assert( atomicValueIsProperlyAligned!(size_t)( cast(size_t) &val ) ); else assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) ); } body { size_t tmp = mod; // convert all operands to size_t asm pure nothrow @nogc { mov RAX, tmp; mov RDX, val; } static if (T.sizeof == 1) asm pure nothrow @nogc { lock; xadd[RDX], AL; } else static if (T.sizeof == 2) asm pure nothrow @nogc { lock; xadd[RDX], AX; } else static if (T.sizeof == 4) asm pure nothrow @nogc { lock; xadd[RDX], EAX; } else static if (T.sizeof == 8) asm pure nothrow @nogc { lock; xadd[RDX], RAX; } asm pure nothrow @nogc { mov tmp, RAX; } return cast(T)tmp; } private HeadUnshared!(T) atomicFetchSub(T, V1)( ref shared T val, V1 mod ) pure nothrow @nogc if( __traits(isIntegral, T) && __traits(isIntegral, V1) ) { return atomicFetchAdd(val, -mod); } HeadUnshared!(T) atomicOp(string op, T, V1)( ref shared T val, V1 mod ) pure nothrow @nogc if( __traits( compiles, mixin( "*cast(T*)&val" ~ op ~ "mod" ) ) ) in { // NOTE: 32 bit x86 systems support 8 byte CAS, which only requires // 4 byte alignment, so use size_t as the align type here. static if( T.sizeof > size_t.sizeof ) assert( atomicValueIsProperlyAligned!(size_t)( cast(size_t) &val ) ); else assert( atomicValueIsProperlyAligned!(T)( cast(size_t) &val ) ); } body { // binary operators // // + - * / % ^^ & // | ^ << >> >>> ~ in // == != < <= > >= static if( op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op == "^^" || op == "&" || op == "|" || op == "^" || op == "<<" || op == ">>" || op == ">>>" || op == "~" || // skip "in" op == "==" || op == "!=" || op == "<" || op == "<=" || op == ">" || op == ">=" ) { HeadUnshared!(T) get = atomicLoad!(MemoryOrder.raw)( val ); mixin( "return get " ~ op ~ " mod;" ); } else // assignment operators // // += -= *= /= %= ^^= &= // |= ^= <<= >>= >>>= ~= static if( op == "+=" && __traits(isIntegral, T) && __traits(isIntegral, V1)) { return cast(T)(atomicFetchAdd!(T)(val, mod) + mod); } else static if( op == "-=" && __traits(isIntegral, T) && __traits(isIntegral, V1)) { return cast(T)(atomicFetchSub!(T)(val, mod) - mod); } else static if( op == "+=" || op == "-=" || op == "*=" || op == "/=" || op == "%=" || op == "^^=" || op == "&=" || op == "|=" || op == "^=" || op == "<<=" || op == ">>=" || op == ">>>=" ) // skip "~=" { HeadUnshared!(T) get, set; do { get = set = atomicLoad!(MemoryOrder.raw)( val ); mixin( "set " ~ op ~ " mod;" ); } while( !cas( &val, get, set ) ); return set; } else { static assert( false, "Operation not supported." ); } } bool cas(T,V1,V2)( shared(T)* here, const V1 ifThis, V2 writeThis ) pure nothrow @nogc if( !is(T == class) && !is(T U : U*) && __traits( compiles, { *here = writeThis; } ) ) { return casImpl(here, ifThis, writeThis); } bool cas(T,V1,V2)( shared(T)* here, const shared(V1) ifThis, shared(V2) writeThis ) pure nothrow @nogc if( is(T == class) && __traits( compiles, { *here = writeThis; } ) ) { return casImpl(here, ifThis, writeThis); } bool cas(T,V1,V2)( shared(T)* here, const shared(V1)* ifThis, shared(V2)* writeThis ) pure nothrow @nogc if( is(T U : U*) && __traits( compiles, { *here = writeThis; } ) ) { return casImpl(here, ifThis, writeThis); } private bool casImpl(T,V1,V2)( shared(T)* here, V1 ifThis, V2 writeThis ) pure nothrow @nogc in { // NOTE: 32 bit x86 systems support 8 byte CAS, which only requires // 4 byte alignment, so use size_t as the align type here. static if( T.sizeof > size_t.sizeof ) assert( atomicValueIsProperlyAligned!(size_t)( cast(size_t) here ) ); else assert( atomicValueIsProperlyAligned!(T)( cast(size_t) here ) ); } body { static if( T.sizeof == byte.sizeof ) { ////////////////////////////////////////////////////////////////// // 1 Byte CAS ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { mov DL, writeThis; mov AL, ifThis; mov RCX, here; lock; // lock always needed to make this op atomic cmpxchg [RCX], DL; setz AL; } } else static if( T.sizeof == short.sizeof ) { ////////////////////////////////////////////////////////////////// // 2 Byte CAS ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { mov DX, writeThis; mov AX, ifThis; mov RCX, here; lock; // lock always needed to make this op atomic cmpxchg [RCX], DX; setz AL; } } else static if( T.sizeof == int.sizeof ) { ////////////////////////////////////////////////////////////////// // 4 Byte CAS ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { mov EDX, writeThis; mov EAX, ifThis; mov RCX, here; lock; // lock always needed to make this op atomic cmpxchg [RCX], EDX; setz AL; } } else static if( T.sizeof == long.sizeof ) { ////////////////////////////////////////////////////////////////// // 8 Byte CAS on a 64-Bit Processor ////////////////////////////////////////////////////////////////// asm pure nothrow @nogc { mov RDX, writeThis; mov RAX, ifThis; mov RCX, here; lock; // lock always needed to make this op atomic cmpxchg [RCX], RDX; setz AL; } } else static if( T.sizeof == long.sizeof*2 && has128BitCAS) { ////////////////////////////////////////////////////////////////// // 16 Byte CAS on a 64-Bit Processor ////////////////////////////////////////////////////////////////// version(Win64){ //Windows 64 calling convention uses different registers. //DMD appears to reverse the register order. asm pure nothrow @nogc { push RDI; push RBX; mov R9, writeThis; mov R10, ifThis; mov R11, here; mov RDI, R9; mov RBX, [RDI]; mov RCX, 8[RDI]; mov RDI, R10; mov RAX, [RDI]; mov RDX, 8[RDI]; mov RDI, R11; lock; cmpxchg16b [RDI]; setz AL; pop RBX; pop RDI; } }else{ asm pure nothrow @nogc { push RDI; push RBX; lea RDI, writeThis; mov RBX, [RDI]; mov RCX, 8[RDI]; lea RDI, ifThis; mov RAX, [RDI]; mov RDX, 8[RDI]; mov RDI, here; lock; // lock always needed to make this op atomic cmpxchg16b [RDI]; setz AL; pop RBX; pop RDI; } } } else { static assert( false, "Invalid template type specified." ); } } enum MemoryOrder { raw, acq, rel, seq, } deprecated("Please use MemoryOrder instead.") alias MemoryOrder msync; private { // NOTE: x86 loads implicitly have acquire semantics so a memory // barrier is only necessary on releases. template needsLoadBarrier( MemoryOrder ms ) { enum bool needsLoadBarrier = ms == MemoryOrder.seq; } // NOTE: x86 stores implicitly have release semantics so a memory // barrier is only necessary on acquires. template needsStoreBarrier( MemoryOrder ms ) { enum bool needsStoreBarrier = ms == MemoryOrder.seq; } } HeadUnshared!(T) atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)( ref const shared T val ) pure nothrow @nogc if(!__traits(isFloating, T)) { static assert( ms != MemoryOrder.rel, "invalid MemoryOrder for atomicLoad()" ); static assert( __traits(isPOD, T), "argument to atomicLoad() must be POD" ); static if( T.sizeof == byte.sizeof ) { ////////////////////////////////////////////////////////////////// // 1 Byte Load ////////////////////////////////////////////////////////////////// static if( needsLoadBarrier!(ms) ) { asm pure nothrow @nogc { mov DL, 0; mov AL, 0; mov RCX, val; lock; // lock always needed to make this op atomic cmpxchg [RCX], DL; } } else { asm pure nothrow @nogc { mov RAX, val; mov AL, [RAX]; } } } else static if( T.sizeof == short.sizeof ) { ////////////////////////////////////////////////////////////////// // 2 Byte Load ////////////////////////////////////////////////////////////////// static if( needsLoadBarrier!(ms) ) { asm pure nothrow @nogc { mov DX, 0; mov AX, 0; mov RCX, val; lock; // lock always needed to make this op atomic cmpxchg [RCX], DX; } } else { asm pure nothrow @nogc { mov RAX, val; mov AX, [RAX]; } } } else static if( T.sizeof == int.sizeof ) { ////////////////////////////////////////////////////////////////// // 4 Byte Load ////////////////////////////////////////////////////////////////// static if( needsLoadBarrier!(ms) ) { asm pure nothrow @nogc { mov EDX, 0; mov EAX, 0; mov RCX, val; lock; // lock always needed to make this op atomic cmpxchg [RCX], EDX; } } else { asm pure nothrow @nogc { mov RAX, val; mov EAX, [RAX]; } } } else static if( T.sizeof == long.sizeof ) { ////////////////////////////////////////////////////////////////// // 8 Byte Load ////////////////////////////////////////////////////////////////// static if( needsLoadBarrier!(ms) ) { asm pure nothrow @nogc { mov RDX, 0; mov RAX, 0; mov RCX, val; lock; // lock always needed to make this op atomic cmpxchg [RCX], RDX; } } else { asm pure nothrow @nogc { mov RAX, val; mov RAX, [RAX]; } } } else static if( T.sizeof == long.sizeof*2 && has128BitCAS ) { ////////////////////////////////////////////////////////////////// // 16 Byte Load on a 64-Bit Processor ////////////////////////////////////////////////////////////////// version(Win64){ size_t[2] retVal; asm pure nothrow @nogc { push RDI; push RBX; mov RDI, val; mov RBX, 0; mov RCX, 0; mov RAX, 0; mov RDX, 0; lock; // lock always needed to make this op atomic cmpxchg16b [RDI]; lea RDI, retVal; mov [RDI], RAX; mov 8[RDI], RDX; pop RBX; pop RDI; } return cast(typeof(return)) retVal; }else{ asm pure nothrow @nogc { push RDI; push RBX; mov RBX, 0; mov RCX, 0; mov RAX, 0; mov RDX, 0; mov RDI, val; lock; // lock always needed to make this op atomic cmpxchg16b [RDI]; pop RBX; pop RDI; } } } else { static assert( false, "Invalid template type specified." ); } } void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V1)( ref shared T val, V1 newval ) pure nothrow @nogc if( __traits( compiles, { val = newval; } ) ) { static assert( ms != MemoryOrder.acq, "invalid MemoryOrder for atomicStore()" ); static assert( __traits(isPOD, T), "argument to atomicStore() must be POD" ); static if( T.sizeof == byte.sizeof ) { ////////////////////////////////////////////////////////////////// // 1 Byte Store ////////////////////////////////////////////////////////////////// static if( needsStoreBarrier!(ms) ) { asm pure nothrow @nogc { mov RAX, val; mov DL, newval; lock; xchg [RAX], DL; } } else { asm pure nothrow @nogc { mov RAX, val; mov DL, newval; mov [RAX], DL; } } } else static if( T.sizeof == short.sizeof ) { ////////////////////////////////////////////////////////////////// // 2 Byte Store ////////////////////////////////////////////////////////////////// static if( needsStoreBarrier!(ms) ) { asm pure nothrow @nogc { mov RAX, val; mov DX, newval; lock; xchg [RAX], DX; } } else { asm pure nothrow @nogc { mov RAX, val; mov DX, newval; mov [RAX], DX; } } } else static if( T.sizeof == int.sizeof ) { ////////////////////////////////////////////////////////////////// // 4 Byte Store ////////////////////////////////////////////////////////////////// static if( needsStoreBarrier!(ms) ) { asm pure nothrow @nogc { mov RAX, val; mov EDX, newval; lock; xchg [RAX], EDX; } } else { asm pure nothrow @nogc { mov RAX, val; mov EDX, newval; mov [RAX], EDX; } } } else static if( T.sizeof == long.sizeof && has64BitCAS ) { ////////////////////////////////////////////////////////////////// // 8 Byte Store on a 64-Bit Processor ////////////////////////////////////////////////////////////////// static if( needsStoreBarrier!(ms) ) { asm pure nothrow @nogc { mov RAX, val; mov RDX, newval; lock; xchg [RAX], RDX; } } else { asm pure nothrow @nogc { mov RAX, val; mov RDX, newval; mov [RAX], RDX; } } } else static if( T.sizeof == long.sizeof*2 && has128BitCAS ) { ////////////////////////////////////////////////////////////////// // 16 Byte Store on a 64-Bit Processor ////////////////////////////////////////////////////////////////// version(Win64){ asm pure nothrow @nogc { push RDI; push RBX; mov R9, val; mov R10, newval; mov RDI, R10; mov RBX, [RDI]; mov RCX, 8[RDI]; mov RDI, R9; mov RAX, [RDI]; mov RDX, 8[RDI]; L1: lock; // lock always needed to make this op atomic cmpxchg16b [RDI]; jne L1; pop RBX; pop RDI; } }else{ asm pure nothrow @nogc { push RDI; push RBX; lea RDI, newval; mov RBX, [RDI]; mov RCX, 8[RDI]; mov RDI, val; mov RAX, [RDI]; mov RDX, 8[RDI]; L1: lock; // lock always needed to make this op atomic cmpxchg16b [RDI]; jne L1; pop RBX; pop RDI; } } } else { static assert( false, "Invalid template type specified." ); } } void atomicFence() nothrow @nogc { // SSE2 is always present in 64-bit x86 chips. asm nothrow @nogc { naked; mfence; ret; } } } // This is an ABI adapter that works on all architectures. It type puns // floats and doubles to ints and longs, atomically loads them, then puns // them back. This is necessary so that they get returned in floating // point instead of integer registers. HeadUnshared!(T) atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)( ref const shared T val ) pure nothrow @nogc if(__traits(isFloating, T)) { version (LDC) pragma(inline, true); static if(T.sizeof == int.sizeof) { static assert(is(T : float)); auto ptr = cast(const shared int*) &val; auto asInt = atomicLoad!(ms)(*ptr); return *(cast(typeof(return)*) &asInt); } else static if(T.sizeof == long.sizeof) { static assert(is(T : double)); auto ptr = cast(const shared long*) &val; auto asLong = atomicLoad!(ms)(*ptr); return *(cast(typeof(return)*) &asLong); } else { static assert(0, "Cannot atomically load 80-bit reals."); } } //////////////////////////////////////////////////////////////////////////////// // Unit Tests //////////////////////////////////////////////////////////////////////////////// version( unittest ) { void testCAS(T)( T val ) pure nothrow in { assert(val !is T.init); } body { T base; shared(T) atom; assert( base !is val, T.stringof ); assert( atom is base, T.stringof ); assert( cas( &atom, base, val ), T.stringof ); assert( atom is val, T.stringof ); assert( !cas( &atom, base, base ), T.stringof ); assert( atom is val, T.stringof ); } void testLoadStore(MemoryOrder ms = MemoryOrder.seq, T)( T val = T.init + 1 ) pure nothrow { T base = cast(T) 0; shared(T) atom = cast(T) 0; assert( base !is val ); assert( atom is base ); atomicStore!(ms)( atom, val ); base = atomicLoad!(ms)( atom ); assert( base is val, T.stringof ); assert( atom is val ); } void testType(T)( T val = T.init + 1 ) pure nothrow { testCAS!(T)( val ); testLoadStore!(MemoryOrder.seq, T)( val ); testLoadStore!(MemoryOrder.raw, T)( val ); } //@@@BUG@@@ http://d.puremagic.com/issues/show_bug.cgi?id=8081 /+pure nothrow+/ unittest { testType!(bool)(); testType!(byte)(); testType!(ubyte)(); testType!(short)(); testType!(ushort)(); testType!(int)(); testType!(uint)(); testType!(shared int*)(); static class Klass {} testCAS!(shared Klass)( new shared(Klass) ); testType!(float)(1.0f); testType!(double)(1.0); static if( has64BitCAS ) { testType!(long)(); testType!(ulong)(); } static if (has128BitCAS) { struct DoubleValue { long value1; long value2; } align(16) shared DoubleValue a; atomicStore(a, DoubleValue(1,2)); assert(a.value1 == 1 && a.value2 ==2); while(!cas(&a, DoubleValue(1,2), DoubleValue(3,4))){} assert(a.value1 == 3 && a.value2 ==4); align(16) DoubleValue b = atomicLoad(a); assert(b.value1 == 3 && b.value2 ==4); } version (D_LP64) { enum hasDWCAS = has128BitCAS; } else { enum hasDWCAS = has64BitCAS; } static if (hasDWCAS) { static struct List { size_t gen; List* next; } shared(List) head; assert(cas(&head, shared(List)(0, null), shared(List)(1, cast(List*)1))); assert(head.gen == 1); assert(cast(size_t)head.next == 1); } shared(size_t) i; atomicOp!"+="( i, cast(size_t) 1 ); assert( i == 1 ); atomicOp!"-="( i, cast(size_t) 1 ); assert( i == 0 ); shared float f = 0; atomicOp!"+="( f, 1 ); assert( f == 1 ); shared double d = 0; atomicOp!"+="( d, 1 ); assert( d == 1 ); } //@@@BUG@@@ http://d.puremagic.com/issues/show_bug.cgi?id=8081 /+pure nothrow+/ unittest { static struct S { int val; } auto s = shared(S)(1); shared(S*) ptr; // head unshared shared(S)* ifThis = null; shared(S)* writeThis = &s; assert(ptr is null); assert(cas(&ptr, ifThis, writeThis)); assert(ptr is writeThis); // head shared shared(S*) ifThis2 = writeThis; shared(S*) writeThis2 = null; assert(cas(&ptr, ifThis2, writeThis2)); assert(ptr is null); // head unshared target doesn't want atomic CAS shared(S)* ptr2; static assert(!__traits(compiles, cas(&ptr2, ifThis, writeThis))); static assert(!__traits(compiles, cas(&ptr2, ifThis2, writeThis2))); } unittest { import core.thread; // Use heap memory to ensure an optimizing // compiler doesn't put things in registers. uint* x = new uint(); bool* f = new bool(); uint* r = new uint(); auto thr = new Thread(() { while (!*f) { } atomicFence(); *r = *x; }); thr.start(); *x = 42; atomicFence(); *f = true; atomicFence(); thr.join(); assert(*r == 42); } // === atomicFetchAdd and atomicFetchSub operations ==== unittest { shared ubyte u8 = 1; shared ushort u16 = 2; shared uint u32 = 3; shared byte i8 = 5; shared short i16 = 6; shared int i32 = 7; assert(atomicOp!"+="(u8, 8) == 9); assert(atomicOp!"+="(u16, 8) == 10); assert(atomicOp!"+="(u32, 8) == 11); assert(atomicOp!"+="(i8, 8) == 13); assert(atomicOp!"+="(i16, 8) == 14); assert(atomicOp!"+="(i32, 8) == 15); version( AsmX86_64 ) { shared ulong u64 = 4; shared long i64 = 8; assert(atomicOp!"+="(u64, 8) == 12); assert(atomicOp!"+="(i64, 8) == 16); } } unittest { shared ubyte u8 = 1; shared ushort u16 = 2; shared uint u32 = 3; shared byte i8 = 5; shared short i16 = 6; shared int i32 = 7; assert(atomicOp!"-="(u8, 1) == 0); assert(atomicOp!"-="(u16, 1) == 1); assert(atomicOp!"-="(u32, 1) == 2); assert(atomicOp!"-="(i8, 1) == 4); assert(atomicOp!"-="(i16, 1) == 5); assert(atomicOp!"-="(i32, 1) == 6); version( AsmX86_64 ) { shared ulong u64 = 4; shared long i64 = 8; assert(atomicOp!"-="(u64, 1) == 3); assert(atomicOp!"-="(i64, 1) == 7); } } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/bitop.d0000664000175000017500000005302712776214756020473 0ustar kaikai/** * This module contains a collection of bit-level operations. * * Copyright: Copyright Don Clugston 2005 - 2013. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Don Clugston, Sean Kelly, Walter Bright, Alex Rønne Petersen, Thomas Stuart Bockman * Source: $(DRUNTIMESRC core/_bitop.d) * * Some of the LDC-specific parts came »From GDC ... public domain!« */ module core.bitop; nothrow: @safe: @nogc: version (LDC) { import ldc.intrinsics; // Do not use the DMD inline assembler. } else { version( D_InlineAsm_X86_64 ) version = AsmX86; else version( D_InlineAsm_X86 ) version = AsmX86; version (X86_64) version = AnyX86; else version (X86) version = AnyX86; } // Use to implement 64-bit bitops on 32-bit arch. private union Split64 { ulong u64; struct { version(LittleEndian) { uint lo; uint hi; } else { uint hi; uint lo; } } pragma(inline, true) this(ulong u64) @safe pure nothrow @nogc { if (__ctfe) { lo = cast(uint) u64; hi = cast(uint) (u64 >>> 32); } else this.u64 = u64; } } unittest { const rt = Split64(1); assert((rt.lo == 1) && (rt.hi == 0)); enum ct = Split64(1); assert((ct.lo == rt.lo) && (ct.hi == rt.hi)); } /** * Scans the bits in v starting with bit 0, looking * for the first set bit. * Returns: * The bit number of the first bit set. * The return value is undefined if v is zero. */ version (LDC) { // KLUDGE: Need to adapt the return type. pragma(inline, true) int bsf(size_t v) pure { return cast(int)llvm_cttz(v, true); } } else { int bsf(size_t v) pure; } /// ditto static if (size_t.sizeof < ulong.sizeof) // IN_LLVM int bsf(ulong v) pure { static if (size_t.sizeof == ulong.sizeof) return bsf(cast(size_t) v); else static if (size_t.sizeof == uint.sizeof) { const sv = Split64(v); return (sv.lo == 0)? bsf(sv.hi) + 32 : bsf(sv.lo); } else static assert(false); } /// unittest { assert(bsf(0x21) == 0); assert(bsf(ulong.max << 39) == 39); } unittest { // Make sure bsf() is available at CTFE enum test_ctfe = bsf(ulong.max); assert(test_ctfe == 0); } /** * 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. */ version (LDC) { pragma(inline, true) int bsr(size_t v) pure { return cast(int)(size_t.sizeof * 8 - 1 - llvm_ctlz(v, true)); } } else { int bsr(size_t v) pure; } /// ditto static if (size_t.sizeof < ulong.sizeof) // IN_LLVM int bsr(ulong v) pure { static if (size_t.sizeof == ulong.sizeof) return bsr(cast(size_t) v); else static if (size_t.sizeof == uint.sizeof) { const sv = Split64(v); return (sv.hi == 0)? bsr(sv.lo) : bsr(sv.hi) + 32; } else static assert(false); } /// unittest { assert(bsr(0x21) == 5); assert(bsr((ulong.max >> 15) - 1) == 48); } unittest { // Make sure bsr() is available at CTFE enum test_ctfe = bsr(ulong.max); assert(test_ctfe == 63); } /** * Tests the bit. * (No longer an intrisic - the compiler recognizes the patterns * in the body.) */ version (none) { // Our implementation returns an arbitrary non-zero value if the bit was // set, which is not what std.bitmanip expects. pragma(LDC_intrinsic, "ldc.bitop.bt") int bt(in size_t* p, size_t bitnum) pure @system; } else int bt(in size_t* p, size_t bitnum) pure @system { static if (size_t.sizeof == 8) return ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0; else static if (size_t.sizeof == 4) return ((p[bitnum >> 5] & (1 << (bitnum & 31)))) != 0; else static assert(0); } /// @system pure unittest { size_t[2] array; array[0] = 2; array[1] = 0x100; assert(bt(array.ptr, 1)); assert(array[0] == 2); assert(array[1] == 0x100); } /** * Tests and complements the bit. */ version (LDC) { pragma(LDC_intrinsic, "ldc.bitop.btc") int btc(size_t* p, size_t bitnum) pure @system; } else int btc(size_t* p, size_t bitnum) pure @system; /** * Tests and resets (sets to 0) the bit. */ version (LDC) { pragma(LDC_intrinsic, "ldc.bitop.btr") int btr(size_t* p, size_t bitnum) pure @system; } else int btr(size_t* p, size_t bitnum) pure @system; /** * Tests and sets the bit. * Params: * p = a non-NULL pointer to an array of size_ts. * bitnum = a bit number, starting with bit 0 of p[0], * and progressing. It addresses bits like the expression: --- p[index / (size_t.sizeof*8)] & (1 << (index & ((size_t.sizeof*8) - 1))) --- * Returns: * A non-zero value if the bit was set, and a zero * if it was clear. */ version (LDC) { pragma(LDC_intrinsic, "ldc.bitop.bts") int bts(size_t* p, size_t bitnum) pure @system; } else int bts(size_t* p, size_t bitnum) pure @system; /// @system pure unittest { size_t[2] array; array[0] = 2; array[1] = 0x100; assert(btc(array.ptr, 35) == 0); if (size_t.sizeof == 8) { assert(array[0] == 0x8_0000_0002); assert(array[1] == 0x100); } else { assert(array[0] == 2); assert(array[1] == 0x108); } assert(btc(array.ptr, 35)); assert(array[0] == 2); assert(array[1] == 0x100); assert(bts(array.ptr, 35) == 0); if (size_t.sizeof == 8) { assert(array[0] == 0x8_0000_0002); assert(array[1] == 0x100); } else { assert(array[0] == 2); assert(array[1] == 0x108); } assert(btr(array.ptr, 35)); assert(array[0] == 2); assert(array[1] == 0x100); } /** * Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes * byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3 * becomes byte 0. */ version (LDC) { alias bswap = llvm_bswap!uint; } else uint bswap(uint v) pure; /** * Swaps bytes in an 8 byte ulong end-to-end, i.e. byte 0 becomes * byte 7, byte 1 becomes byte 6, etc. */ version (LDC) { alias bswap = llvm_bswap!ulong; } else { ulong bswap(ulong v) pure { auto sv = Split64(v); const temp = sv.lo; sv.lo = bswap(sv.hi); sv.hi = bswap(temp); return (cast(ulong) sv.hi << 32) | sv.lo; } } version (DigitalMars) version (AnyX86) @system // not pure { /** * 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); } version(LDC) @system // not pure { /** * Reads I/O port at port_address. */ uint inp(uint port_address) { assert(false, "inp not yet implemented for LDC."); } /** * ditto */ uint inpw(uint port_address) { assert(false, "inpw not yet implemented for LDC."); } /** * ditto */ uint inpl(uint port_address) { assert(false, "inpl not yet implemented for LDC."); } /** * Writes and returns value to I/O port at port_address. */ ubyte outp(uint port_address, uint value) { assert(false, "outp not yet implemented for LDC."); } /** * ditto */ ushort outpw(uint port_address, uint value) { assert(false, "outpw not yet implemented for LDC."); } /** * ditto */ uint outpl(uint port_address, uint value) { assert(false, "outpl not yet implemented for LDC."); } } version (LDC) { pragma(inline, true): ushort _popcnt(ushort x) pure { return llvm_ctpop(x); } int _popcnt(uint x) pure { return cast(int)llvm_ctpop(x); } int _popcnt(ulong x) pure { return cast(int)llvm_ctpop(x); } } /** * Calculates the number of set bits in an integer. */ int popcnt(uint x) pure { // Select the fastest method depending on the compiler and CPU architecture version(LDC) { pragma(inline, true); if (!__ctfe) return _popcnt(x); } else version(DigitalMars) { static if (is(typeof(_popcnt(uint.max)))) { import core.cpuid; if (!__ctfe && hasPopcnt) return _popcnt(x); } } return softPopcnt!uint(x); } 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 ); // Make sure popcnt() is available at CTFE enum test_ctfe = popcnt(uint.max); assert(test_ctfe == 32); } /// ditto int popcnt(ulong x) pure { version(LDC) { pragma(inline, true); if (!__ctfe) return _popcnt(x); } // Select the fastest method depending on the compiler and CPU architecture import core.cpuid; static if (size_t.sizeof == uint.sizeof) { const sx = Split64(x); version(DigitalMars) { static if (is(typeof(_popcnt(uint.max)))) { if (!__ctfe && hasPopcnt) return _popcnt(sx.lo) + _popcnt(sx.hi); } } return softPopcnt!uint(sx.lo) + softPopcnt!uint(sx.hi); } else static if (size_t.sizeof == ulong.sizeof) { version(DigitalMars) { static if (is(typeof(_popcnt(ulong.max)))) { if (!__ctfe && hasPopcnt) return _popcnt(x); } } return softPopcnt!ulong(x); } else static assert(false); } unittest { assert(popcnt(0uL) == 0); assert(popcnt(1uL) == 1); assert(popcnt((1uL << 32) - 1) == 32); assert(popcnt(0x48_65_6C_6C_6F_3F_21_00uL) == 28); assert(popcnt(ulong.max) == 64); // Make sure popcnt() is available at CTFE enum test_ctfe = popcnt(ulong.max); assert(test_ctfe == 64); } private int softPopcnt(N)(N x) pure if (is(N == uint) || is(N == ulong)) { // 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. enum mask1 = cast(N) 0x5555_5555_5555_5555L; x = x - ((x>>1) & mask1); // now each two bits of x is a number 00,01 or 10. // now add neighbouring pairs enum mask2a = cast(N) 0xCCCC_CCCC_CCCC_CCCCL; enum mask2b = cast(N) 0x3333_3333_3333_3333L; x = ((x & mask2a)>>2) + (x & mask2b); // now each nibble holds 0000-0100. Adding them won't // overflow any more, so we don't need to mask any more enum mask4 = cast(N) 0x0F0F_0F0F_0F0F_0F0FL; x = (x + (x >> 4)) & mask4; enum shiftbits = is(N == uint)? 24 : 56; enum maskMul = cast(N) 0x0101_0101_0101_0101L; x = (x * maskMul) >> shiftbits; return cast(int) x; } version (DigitalMars) version (AnyX86) { /** * Calculates the number of set bits in an integer * using the X86 SSE4 POPCNT instruction. * POPCNT is not available on all X86 CPUs. */ ushort _popcnt( ushort x ) pure; /// ditto int _popcnt( uint x ) pure; version (X86_64) { /// ditto int _popcnt( ulong x ) pure; } unittest { // Not everyone has SSE4 instructions import core.cpuid; if (!hasPopcnt) return; static int popcnt_x(ulong u) nothrow @nogc { int c; while (u) { c += u & 1; u >>= 1; } return c; } for (uint u = 0; u < 0x1_0000; ++u) { //writefln("%x %x %x", u, _popcnt(cast(ushort)u), popcnt_x(cast(ushort)u)); assert(_popcnt(cast(ushort)u) == popcnt_x(cast(ushort)u)); assert(_popcnt(cast(uint)u) == popcnt_x(cast(uint)u)); uint ui = u * 0x3_0001; assert(_popcnt(ui) == popcnt_x(ui)); version (X86_64) { assert(_popcnt(cast(ulong)u) == popcnt_x(cast(ulong)u)); ulong ul = u * 0x3_0003_0001; assert(_popcnt(ul) == popcnt_x(ul)); } } } } /************************************* * Read/write value from/to the memory location indicated by ptr. * * These functions are recognized by the compiler, and calls to them are guaranteed * to not be removed (as dead assignment elimination or presumed to have no effect) * or reordered in the same thread. * * These reordering guarantees are only made with regards to other * operations done through these functions; the compiler is free to reorder regular * loads/stores with regards to loads/stores done through these functions. * * This is useful when dealing with memory-mapped I/O (MMIO) where a store can * have an effect other than just writing a value, or where sequential loads * with no intervening stores can retrieve * different values from the same location due to external stores to the location. * * These functions will, when possible, do the load/store as a single operation. In * general, this is possible when the size of the operation is less than or equal to * $(D (void*).sizeof), although some targets may support larger operations. If the * load/store cannot be done as a single operation, multiple smaller operations will be used. * * These are not to be conflated with atomic operations. They do not guarantee any * atomicity. This may be provided by coincidence as a result of the instructions * used on the target, but this should not be relied on for portable programs. * Further, no memory fences are implied by these functions. * They should not be used for communication between threads. * They may be used to guarantee a write or read cycle occurs at a specified address. */ version (LDC) { pragma(LDC_intrinsic, "ldc.bitop.vld") ubyte volatileLoad(ubyte* ptr); pragma(LDC_intrinsic, "ldc.bitop.vld") ushort volatileLoad(ushort* ptr); pragma(LDC_intrinsic, "ldc.bitop.vld") uint volatileLoad(uint* ptr); pragma(LDC_intrinsic, "ldc.bitop.vld") ulong volatileLoad(ulong* ptr); pragma(LDC_intrinsic, "ldc.bitop.vst") void volatileStore(ubyte* ptr, ubyte value); pragma(LDC_intrinsic, "ldc.bitop.vst") void volatileStore(ushort* ptr, ushort value); pragma(LDC_intrinsic, "ldc.bitop.vst") void volatileStore(uint* ptr, uint value); pragma(LDC_intrinsic, "ldc.bitop.vst") void volatileStore(ulong* ptr, ulong value); } else { ubyte volatileLoad(ubyte * ptr); ushort volatileLoad(ushort* ptr); /// ditto uint volatileLoad(uint * ptr); /// ditto ulong volatileLoad(ulong * ptr); /// ditto void volatileStore(ubyte * ptr, ubyte value); /// ditto void volatileStore(ushort* ptr, ushort value); /// ditto void volatileStore(uint * ptr, uint value); /// ditto void volatileStore(ulong * ptr, ulong value); /// ditto } @system unittest { alias TT(T...) = T; foreach (T; TT!(ubyte, ushort, uint, ulong)) { T u; T* p = &u; volatileStore(p, 1); T r = volatileLoad(p); assert(r == u); } } /** * Reverses the order of bits in a 32-bit integer. */ pragma(inline, true) uint bitswap( uint x ) pure { if (!__ctfe) { version (LDC) { static if (is(typeof(llvm_bitreverse(x)))) return llvm_bitreverse(x); } else static if (is(typeof(asmBitswap32(x)))) return asmBitswap32(x); } return softBitswap!uint(x); } unittest { static void test(alias impl)() { assert (impl( 0x8000_0100 ) == 0x0080_0001); foreach(i; 0 .. 32) assert (impl(1 << i) == 1 << 32 - i - 1); } test!(bitswap)(); test!(softBitswap!uint)(); static if (is(typeof(asmBitswap32(0u)))) test!(asmBitswap32)(); // Make sure bitswap() is available at CTFE enum test_ctfe = bitswap(1U); assert(test_ctfe == (1U << 31)); } /** * Reverses the order of bits in a 64-bit integer. */ pragma(inline, true) ulong bitswap ( ulong x ) pure { if (!__ctfe) { version (LDC) { static if (is(typeof(llvm_bitreverse(x)))) return llvm_bitreverse(x); } else static if (is(typeof(asmBitswap64(x)))) return asmBitswap64(x); } return softBitswap!ulong(x); } unittest { static void test(alias impl)() { assert (impl( 0b1000000000000000000000010000000000000000100000000000000000000001) == 0b1000000000000000000000010000000000000000100000000000000000000001); assert (impl( 0b1110000000000000000000010000000000000000100000000000000000000001) == 0b1000000000000000000000010000000000000000100000000000000000000111); foreach (i; 0 .. 64) assert (impl(1UL << i) == 1UL << 64 - i - 1); } test!(bitswap)(); test!(softBitswap!ulong)(); static if (is(typeof(asmBitswap64(0uL)))) test!(asmBitswap64)(); // Make sure bitswap() is available at CTFE enum test_ctfe = bitswap(1UL); assert(test_ctfe == (1UL << 63)); } private N softBitswap(N)(N x) pure if (is(N == uint) || is(N == ulong)) { // swap 1-bit pairs: enum mask1 = cast(N) 0x5555_5555_5555_5555L; x = ((x >> 1) & mask1) | ((x & mask1) << 1); // swap 2-bit pairs: enum mask2 = cast(N) 0x3333_3333_3333_3333L; x = ((x >> 2) & mask2) | ((x & mask2) << 2); // swap 4-bit pairs: enum mask4 = cast(N) 0x0F0F_0F0F_0F0F_0F0FL; x = ((x >> 4) & mask4) | ((x & mask4) << 4); // reverse the order of all bytes: x = bswap(x); return x; } version (AsmX86) { private uint asmBitswap32(uint x) @trusted pure { asm pure nothrow @nogc { naked; } version (D_InlineAsm_X86_64) { version (Win64) asm pure nothrow @nogc { mov EAX, ECX; } else asm pure nothrow @nogc { mov EAX, EDI; } } asm pure nothrow @nogc { // 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; ret; } } } version (D_InlineAsm_X86_64) { private ulong asmBitswap64(ulong x) @trusted pure { asm pure nothrow @nogc { naked; } version (Win64) asm pure nothrow @nogc { mov RAX, RCX; } else asm pure nothrow @nogc { mov RAX, RDI; } asm pure nothrow @nogc { // Author: Tiago Gasiba. mov RDX, RAX; shr RAX, 1; mov RCX, 0x5555_5555_5555_5555L; and RDX, RCX; and RAX, RCX; shl RDX, 1; or RAX, RDX; mov RDX, RAX; shr RAX, 2; mov RCX, 0x3333_3333_3333_3333L; and RDX, RCX; and RAX, RCX; shl RDX, 2; or RAX, RDX; mov RDX, RAX; shr RAX, 4; mov RCX, 0x0f0f_0f0f_0f0f_0f0fL; and RDX, RCX; and RAX, RCX; shl RDX, 4; or RAX, RDX; bswap RAX; ret; } } } /** * Bitwise rotate `value` left (`rol`) or right (`ror`) by * `count` bit positions. */ pure T rol(T)(in T value, in uint count) if (__traits(isIntegral, T) && __traits(isUnsigned, T)) { assert(count < 8 * T.sizeof); return cast(T) ((value << count) | (value >> (-count & (T.sizeof * 8 - 1)))); } /// ditto pure T ror(T)(in T value, in uint count) if (__traits(isIntegral, T) && __traits(isUnsigned, T)) { assert(count < 8 * T.sizeof); return cast(T) ((value >> count) | (value << (-count & (T.sizeof * 8 - 1)))); } /// ditto pure T rol(uint count, T)(in T value) if (__traits(isIntegral, T) && __traits(isUnsigned, T)) { static assert(count < 8 * T.sizeof); return cast(T) ((value << count) | (value >> (-count & (T.sizeof * 8 - 1)))); } /// ditto pure T ror(uint count, T)(in T value) if (__traits(isIntegral, T) && __traits(isUnsigned, T)) { static assert(count < 8 * T.sizeof); return cast(T) ((value >> count) | (value << (-count & (T.sizeof * 8 - 1)))); } /// unittest { ubyte a = 0b10101010U; ulong b = ulong.max; assert(rol(a, 1) == 0b01010101); assert(ror(a, 1) == 0b01010101); assert(rol(a, 3) == 0b01010101); assert(ror(a, 3) == 0b01010101); assert(rol(a, 0) == a); assert(ror(a, 0) == a); assert(rol(b, 63) == ulong.max); assert(ror(b, 63) == ulong.max); assert(rol!3(a) == 0b01010101); assert(ror!3(a) == 0b01010101); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sync/0000775000175000017500000000000012776214756020156 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sync/semaphore.d0000664000175000017500000002730312776214756022313 0ustar kaikai/** * The semaphore module provides a general use semaphore for synchronization. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/sync/_semaphore.d) */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sync.semaphore; public import core.sync.exception; public import core.time; version( Windows ) { private import core.sys.windows.windows; } else version( OSX ) { private import core.sync.config; private import core.stdc.errno; private import core.sys.posix.time; private import core.sys.osx.mach.semaphore; } else version( Posix ) { private import core.sync.config; private import core.stdc.errno; private import core.sys.posix.pthread; private import core.sys.posix.semaphore; } else { static assert(false, "Platform not supported"); } //////////////////////////////////////////////////////////////////////////////// // Semaphore // // void wait(); // void notify(); // bool tryWait(); //////////////////////////////////////////////////////////////////////////////// /** * This class represents a general counting semaphore as concieved by Edsger * Dijkstra. As per Mesa type monitors however, "signal" has been replaced * with "notify" to indicate that control is not transferred to the waiter when * a notification is sent. */ class Semaphore { //////////////////////////////////////////////////////////////////////////// // Initialization //////////////////////////////////////////////////////////////////////////// /** * Initializes a semaphore object with the specified initial count. * * Params: * count = The initial count for the semaphore. * * Throws: * SyncError on error. */ this( uint count = 0 ) { version( Windows ) { m_hndl = CreateSemaphoreA( null, count, int.max, null ); if( m_hndl == m_hndl.init ) throw new SyncError( "Unable to create semaphore" ); } else version( OSX ) { auto rc = semaphore_create( mach_task_self(), &m_hndl, SYNC_POLICY_FIFO, count ); if( rc ) throw new SyncError( "Unable to create semaphore" ); } else version( Posix ) { int rc = sem_init( &m_hndl, 0, count ); if( rc ) throw new SyncError( "Unable to create semaphore" ); } } ~this() { version( Windows ) { BOOL rc = CloseHandle( m_hndl ); assert( rc, "Unable to destroy semaphore" ); } else version( OSX ) { auto rc = semaphore_destroy( mach_task_self(), m_hndl ); assert( !rc, "Unable to destroy semaphore" ); } else version( Posix ) { int rc = sem_destroy( &m_hndl ); assert( !rc, "Unable to destroy semaphore" ); } } //////////////////////////////////////////////////////////////////////////// // General Actions //////////////////////////////////////////////////////////////////////////// /** * Wait until the current count is above zero, then atomically decrement * the count by one and return. * * Throws: * SyncError on error. */ void wait() { version( Windows ) { DWORD rc = WaitForSingleObject( m_hndl, INFINITE ); if( rc != WAIT_OBJECT_0 ) throw new SyncError( "Unable to wait for semaphore" ); } else version( OSX ) { while( true ) { auto rc = semaphore_wait( m_hndl ); if( !rc ) return; if( rc == KERN_ABORTED && errno == EINTR ) continue; throw new SyncError( "Unable to wait for semaphore" ); } } else version( Posix ) { while( true ) { if( !sem_wait( &m_hndl ) ) return; if( errno != EINTR ) throw new SyncError( "Unable to wait for semaphore" ); } } } /** * Suspends the calling thread until the current count moves above zero or * until the supplied time period has elapsed. If the count moves above * zero in this interval, then atomically decrement the count by one and * return true. Otherwise, return false. * * Params: * period = The time to wait. * * In: * period must be non-negative. * * Throws: * SyncError on error. * * Returns: * true if notified before the timeout and false if not. */ bool wait( Duration period ) in { assert( !period.isNegative ); } body { version( Windows ) { auto maxWaitMillis = dur!("msecs")( uint.max - 1 ); while( period > maxWaitMillis ) { auto rc = WaitForSingleObject( m_hndl, cast(uint) maxWaitMillis.total!"msecs" ); switch( rc ) { case WAIT_OBJECT_0: return true; case WAIT_TIMEOUT: period -= maxWaitMillis; continue; default: throw new SyncError( "Unable to wait for semaphore" ); } } switch( WaitForSingleObject( m_hndl, cast(uint) period.total!"msecs" ) ) { case WAIT_OBJECT_0: return true; case WAIT_TIMEOUT: return false; default: throw new SyncError( "Unable to wait for semaphore" ); } } else version( OSX ) { mach_timespec_t t = void; (cast(byte*) &t)[0 .. t.sizeof] = 0; if( period.total!"seconds" > t.tv_sec.max ) { t.tv_sec = t.tv_sec.max; t.tv_nsec = cast(typeof(t.tv_nsec)) period.split!("seconds", "nsecs")().nsecs; } else period.split!("seconds", "nsecs")(t.tv_sec, t.tv_nsec); while( true ) { auto rc = semaphore_timedwait( m_hndl, t ); if( !rc ) return true; if( rc == KERN_OPERATION_TIMED_OUT ) return false; if( rc != KERN_ABORTED || errno != EINTR ) throw new SyncError( "Unable to wait for semaphore" ); } } else version( Posix ) { timespec t = void; mktspec( t, period ); while( true ) { if( !sem_timedwait( &m_hndl, &t ) ) return true; if( errno == ETIMEDOUT ) return false; if( errno != EINTR ) throw new SyncError( "Unable to wait for semaphore" ); } } } /** * Atomically increment the current count by one. This will notify one * waiter, if there are any in the queue. * * Throws: * SyncError on error. */ void notify() { version( Windows ) { if( !ReleaseSemaphore( m_hndl, 1, null ) ) throw new SyncError( "Unable to notify semaphore" ); } else version( OSX ) { auto rc = semaphore_signal( m_hndl ); if( rc ) throw new SyncError( "Unable to notify semaphore" ); } else version( Posix ) { int rc = sem_post( &m_hndl ); if( rc ) throw new SyncError( "Unable to notify semaphore" ); } } /** * If the current count is equal to zero, return. Otherwise, atomically * decrement the count by one and return true. * * Throws: * SyncError on error. * * Returns: * true if the count was above zero and false if not. */ bool tryWait() { version( Windows ) { switch( WaitForSingleObject( m_hndl, 0 ) ) { case WAIT_OBJECT_0: return true; case WAIT_TIMEOUT: return false; default: throw new SyncError( "Unable to wait for semaphore" ); } } else version( OSX ) { return wait( dur!"hnsecs"(0) ); } else version( Posix ) { while( true ) { if( !sem_trywait( &m_hndl ) ) return true; if( errno == EAGAIN ) return false; if( errno != EINTR ) throw new SyncError( "Unable to wait for semaphore" ); } } } private: version( Windows ) { HANDLE m_hndl; } else version( OSX ) { semaphore_t m_hndl; } else version( Posix ) { sem_t m_hndl; } } //////////////////////////////////////////////////////////////////////////////// // Unit Tests //////////////////////////////////////////////////////////////////////////////// version( unittest ) { import core.thread, core.atomic; void testWait() { auto semaphore = new Semaphore; shared bool stopConsumption = false; immutable numToProduce = 20; immutable numConsumers = 10; shared size_t numConsumed; shared size_t numComplete; void consumer() { while (true) { semaphore.wait(); if (atomicLoad(stopConsumption)) break; atomicOp!"+="(numConsumed, 1); } atomicOp!"+="(numComplete, 1); } void producer() { assert(!semaphore.tryWait()); foreach (_; 0 .. numToProduce) semaphore.notify(); // wait until all items are consumed while (atomicLoad(numConsumed) != numToProduce) Thread.yield(); // mark consumption as finished atomicStore(stopConsumption, true); // wake all consumers foreach (_; 0 .. numConsumers) semaphore.notify(); // wait until all consumers completed while (atomicLoad(numComplete) != numConsumers) Thread.yield(); assert(!semaphore.tryWait()); semaphore.notify(); assert(semaphore.tryWait()); assert(!semaphore.tryWait()); } auto group = new ThreadGroup; for( int i = 0; i < numConsumers; ++i ) group.create(&consumer); group.create(&producer); group.joinAll(); } void testWaitTimeout() { auto sem = new Semaphore; shared bool semReady; bool alertedOne, alertedTwo; void waiter() { while (!atomicLoad(semReady)) Thread.yield(); alertedOne = sem.wait(dur!"msecs"(1)); alertedTwo = sem.wait(dur!"msecs"(1)); assert(alertedOne && !alertedTwo); } auto thread = new Thread(&waiter); thread.start(); sem.notify(); atomicStore(semReady, true); thread.join(); assert(alertedOne && !alertedTwo); } unittest { testWait(); testWaitTimeout(); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sync/config.d0000664000175000017500000000346612776214756021601 0ustar kaikai/** * The config module contains utility routines and configuration information * specific to this package. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/sync/_config.d) */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sync.config; version( Posix ) { private import core.sys.posix.time; private import core.sys.posix.sys.time; private import core.time; void mktspec( ref timespec t ) nothrow { static if( false && is( typeof( clock_gettime ) ) ) { clock_gettime( CLOCK_REALTIME, &t ); } else { timeval tv; gettimeofday( &tv, null ); (cast(byte*) &t)[0 .. t.sizeof] = 0; t.tv_sec = cast(typeof(t.tv_sec)) tv.tv_sec; t.tv_nsec = cast(typeof(t.tv_nsec)) tv.tv_usec * 1_000; } } void mktspec( ref timespec t, Duration delta ) nothrow { mktspec( t ); mvtspec( t, delta ); } void mvtspec( ref timespec t, Duration delta ) nothrow { auto val = delta; val += dur!"seconds"( t.tv_sec ); val += dur!"nsecs"( t.tv_nsec ); //auto val = delta + dur!"seconds"( t.tv_sec ) + // + dur!"nsecs"( t.tv_nsec ); if( val.total!"seconds" > t.tv_sec.max ) { t.tv_sec = t.tv_sec.max; t.tv_nsec = cast(typeof(t.tv_nsec)) val.split!("seconds", "nsecs")().nsecs; } else val.split!("seconds", "nsecs")(t.tv_sec, t.tv_nsec); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sync/mutex.d0000664000175000017500000001427312776214756021474 0ustar kaikai/** * The mutex module provides a primitive for maintaining mutually exclusive * access. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/sync/_mutex.d) */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sync.mutex; public import core.sync.exception; version( Windows ) { private import core.sys.windows.windows; } else version( Posix ) { private import core.sys.posix.pthread; } else { static assert(false, "Platform not supported"); } //////////////////////////////////////////////////////////////////////////////// // Mutex // // void lock(); // void unlock(); // bool tryLock(); //////////////////////////////////////////////////////////////////////////////// /** * This class represents a general purpose, recursive mutex. */ class Mutex : Object.Monitor { //////////////////////////////////////////////////////////////////////////// // Initialization //////////////////////////////////////////////////////////////////////////// /** * Initializes a mutex object. * * Throws: * SyncError on error. */ this() nothrow @trusted { version( Windows ) { InitializeCriticalSection( &m_hndl ); } else version( Posix ) { pthread_mutexattr_t attr = void; if( pthread_mutexattr_init( &attr ) ) throw new SyncError( "Unable to initialize mutex" ); scope(exit) pthread_mutexattr_destroy( &attr ); if( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ) ) throw new SyncError( "Unable to initialize mutex" ); if( pthread_mutex_init( &m_hndl, &attr ) ) throw new SyncError( "Unable to initialize mutex" ); } m_proxy.link = this; this.__monitor = &m_proxy; } /** * Initializes a mutex object and sets it as the monitor for o. * * In: * o must not already have a monitor. */ this( Object o ) nothrow @trusted in { assert( o.__monitor is null ); } body { this(); o.__monitor = &m_proxy; } ~this() { version( Windows ) { DeleteCriticalSection( &m_hndl ); } else version( Posix ) { int rc = pthread_mutex_destroy( &m_hndl ); assert( !rc, "Unable to destroy mutex" ); } this.__monitor = null; } //////////////////////////////////////////////////////////////////////////// // General Actions //////////////////////////////////////////////////////////////////////////// /** * If this lock is not already held by the caller, the lock is acquired, * then the internal counter is incremented by one. * * Throws: * SyncError on error. */ @trusted void lock() { lock_nothrow(); } // undocumented function for internal use final void lock_nothrow() nothrow @trusted @nogc { version( Windows ) { EnterCriticalSection( &m_hndl ); } else version( Posix ) { int rc = pthread_mutex_lock( &m_hndl ); if( rc ) { SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer; syncErr.msg = "Unable to lock mutex."; throw syncErr; } } } /** * Decrements the internal lock count by one. If this brings the count to * zero, the lock is released. * * Throws: * SyncError on error. */ @trusted void unlock() { unlock_nothrow(); } // undocumented function for internal use final void unlock_nothrow() nothrow @trusted @nogc { version( Windows ) { LeaveCriticalSection( &m_hndl ); } else version( Posix ) { int rc = pthread_mutex_unlock( &m_hndl ); if( rc ) { SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer; syncErr.msg = "Unable to unlock mutex."; throw syncErr; } } } /** * If the lock is held by another caller, the method returns. Otherwise, * the lock is acquired if it is not already held, and then the internal * counter is incremented by one. * * Throws: * SyncError on error. * * Returns: * true if the lock was acquired and false if not. */ bool tryLock() { version( Windows ) { return TryEnterCriticalSection( &m_hndl ) != 0; } else version( Posix ) { return pthread_mutex_trylock( &m_hndl ) == 0; } } private: version( Windows ) { CRITICAL_SECTION m_hndl; } else version( Posix ) { pthread_mutex_t m_hndl; } struct MonitorProxy { Object.Monitor link; } MonitorProxy m_proxy; package: version( Posix ) { pthread_mutex_t* handleAddr() { return &m_hndl; } } } //////////////////////////////////////////////////////////////////////////////// // Unit Tests //////////////////////////////////////////////////////////////////////////////// version( unittest ) { private import core.thread; unittest { auto mutex = new Mutex; int numThreads = 10; int numTries = 1000; int lockCount = 0; void testFn() { for( int i = 0; i < numTries; ++i ) { synchronized( mutex ) { ++lockCount; } } } auto group = new ThreadGroup; for( int i = 0; i < numThreads; ++i ) group.create( &testFn ); group.joinAll(); assert( lockCount == numThreads * numTries ); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sync/barrier.d0000664000175000017500000000664712776214756021766 0ustar kaikai/** * The barrier module provides a primitive for synchronizing the progress of * a group of threads. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/sync/_barrier.d) */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sync.barrier; public import core.sync.exception; private import core.sync.condition; private import core.sync.mutex; version( Posix ) { private import core.stdc.errno; private import core.sys.posix.pthread; } //////////////////////////////////////////////////////////////////////////////// // Barrier // // void wait(); //////////////////////////////////////////////////////////////////////////////// /** * This class represents a barrier across which threads may only travel in * groups of a specific size. */ class Barrier { //////////////////////////////////////////////////////////////////////////// // Initialization //////////////////////////////////////////////////////////////////////////// /** * Initializes a barrier object which releases threads in groups of limit * in size. * * Params: * limit = The number of waiting threads to release in unison. * * Throws: * SyncError on error. */ this( uint limit ) in { assert( limit > 0 ); } body { m_lock = new Mutex; m_cond = new Condition( m_lock ); m_group = 0; m_limit = limit; m_count = limit; } //////////////////////////////////////////////////////////////////////////// // General Actions //////////////////////////////////////////////////////////////////////////// /** * Wait for the pre-determined number of threads and then proceed. * * Throws: * SyncError on error. */ void wait() { synchronized( m_lock ) { uint group = m_group; if( --m_count == 0 ) { m_group++; m_count = m_limit; m_cond.notifyAll(); } while( group == m_group ) m_cond.wait(); } } private: Mutex m_lock; Condition m_cond; uint m_group; uint m_limit; uint m_count; } //////////////////////////////////////////////////////////////////////////////// // Unit Tests //////////////////////////////////////////////////////////////////////////////// version( unittest ) { private import core.thread; unittest { int numThreads = 10; auto barrier = new Barrier( numThreads ); auto synInfo = new Object; int numReady = 0; int numPassed = 0; void threadFn() { synchronized( synInfo ) { ++numReady; } barrier.wait(); synchronized( synInfo ) { ++numPassed; } } auto group = new ThreadGroup; for( int i = 0; i < numThreads; ++i ) { group.create( &threadFn ); } group.joinAll(); assert( numReady == numThreads && numPassed == numThreads ); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sync/rwmutex.d0000664000175000017500000003507512776214756022050 0ustar kaikai/** * The read/write mutex module provides a primitive for maintaining shared read * access and mutually exclusive write access. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/sync/_rwmutex.d) */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sync.rwmutex; public import core.sync.exception; private import core.sync.condition; private import core.sync.mutex; private import core.memory; version( Posix ) { private import core.sys.posix.pthread; } //////////////////////////////////////////////////////////////////////////////// // ReadWriteMutex // // Reader reader(); // Writer writer(); //////////////////////////////////////////////////////////////////////////////// /** * This class represents a mutex that allows any number of readers to enter, * but when a writer enters, all other readers and writers are blocked. * * Please note that this mutex is not recursive and is intended to guard access * to data only. Also, no deadlock checking is in place because doing so would * require dynamic memory allocation, which would reduce performance by an * unacceptable amount. As a result, any attempt to recursively acquire this * mutex may well deadlock the caller, particularly if a write lock is acquired * while holding a read lock, or vice-versa. In practice, this should not be * an issue however, because it is uncommon to call deeply into unknown code * while holding a lock that simply protects data. */ class ReadWriteMutex { /** * Defines the policy used by this mutex. Currently, two policies are * defined. * * The first will queue writers until no readers hold the mutex, then * pass the writers through one at a time. If a reader acquires the mutex * while there are still writers queued, the reader will take precedence. * * The second will queue readers if there are any writers queued. Writers * are passed through one at a time, and once there are no writers present, * all queued readers will be alerted. * * Future policies may offer a more even balance between reader and writer * precedence. */ enum Policy { PREFER_READERS, /// Readers get preference. This may starve writers. PREFER_WRITERS /// Writers get preference. This may starve readers. } //////////////////////////////////////////////////////////////////////////// // Initialization //////////////////////////////////////////////////////////////////////////// /** * Initializes a read/write mutex object with the supplied policy. * * Params: * policy = The policy to use. * * Throws: * SyncError on error. */ this( Policy policy = Policy.PREFER_WRITERS ) { m_commonMutex = new Mutex; if( !m_commonMutex ) throw new SyncError( "Unable to initialize mutex" ); m_readerQueue = new Condition( m_commonMutex ); if( !m_readerQueue ) throw new SyncError( "Unable to initialize mutex" ); m_writerQueue = new Condition( m_commonMutex ); if( !m_writerQueue ) throw new SyncError( "Unable to initialize mutex" ); m_policy = policy; m_reader = new Reader; m_writer = new Writer; } //////////////////////////////////////////////////////////////////////////// // General Properties //////////////////////////////////////////////////////////////////////////// /** * Gets the policy used by this mutex. * * Returns: * The policy used by this mutex. */ @property Policy policy() { return m_policy; } //////////////////////////////////////////////////////////////////////////// // Reader/Writer Handles //////////////////////////////////////////////////////////////////////////// /** * Gets an object representing the reader lock for the associated mutex. * * Returns: * A reader sub-mutex. */ @property Reader reader() { return m_reader; } /** * Gets an object representing the writer lock for the associated mutex. * * Returns: * A writer sub-mutex. */ @property Writer writer() { return m_writer; } //////////////////////////////////////////////////////////////////////////// // Reader //////////////////////////////////////////////////////////////////////////// /** * This class can be considered a mutex in its own right, and is used to * negotiate a read lock for the enclosing mutex. */ class Reader : Object.Monitor { /** * Initializes a read/write mutex reader proxy object. */ this() { m_proxy.link = this; this.__monitor = &m_proxy; } /** * Acquires a read lock on the enclosing mutex. */ @trusted void lock() { synchronized( m_commonMutex ) { ++m_numQueuedReaders; scope(exit) --m_numQueuedReaders; while( shouldQueueReader ) m_readerQueue.wait(); ++m_numActiveReaders; } } /** * Releases a read lock on the enclosing mutex. */ @trusted void unlock() { synchronized( m_commonMutex ) { if( --m_numActiveReaders < 1 ) { if( m_numQueuedWriters > 0 ) m_writerQueue.notify(); } } } /** * Attempts to acquire a read lock on the enclosing mutex. If one can * be obtained without blocking, the lock is acquired and true is * returned. If not, the lock is not acquired and false is returned. * * Returns: * true if the lock was acquired and false if not. */ bool tryLock() { synchronized( m_commonMutex ) { if( shouldQueueReader ) return false; ++m_numActiveReaders; return true; } } private: @property bool shouldQueueReader() { if( m_numActiveWriters > 0 ) return true; switch( m_policy ) { case Policy.PREFER_WRITERS: return m_numQueuedWriters > 0; case Policy.PREFER_READERS: default: break; } return false; } struct MonitorProxy { Object.Monitor link; } MonitorProxy m_proxy; } //////////////////////////////////////////////////////////////////////////// // Writer //////////////////////////////////////////////////////////////////////////// /** * This class can be considered a mutex in its own right, and is used to * negotiate a write lock for the enclosing mutex. */ class Writer : Object.Monitor { /** * Initializes a read/write mutex writer proxy object. */ this() { m_proxy.link = this; this.__monitor = &m_proxy; } /** * Acquires a write lock on the enclosing mutex. */ @trusted void lock() { synchronized( m_commonMutex ) { ++m_numQueuedWriters; scope(exit) --m_numQueuedWriters; while( shouldQueueWriter ) m_writerQueue.wait(); ++m_numActiveWriters; } } /** * Releases a write lock on the enclosing mutex. */ @trusted void unlock() { synchronized( m_commonMutex ) { if( --m_numActiveWriters < 1 ) { switch( m_policy ) { default: case Policy.PREFER_READERS: if( m_numQueuedReaders > 0 ) m_readerQueue.notifyAll(); else if( m_numQueuedWriters > 0 ) m_writerQueue.notify(); break; case Policy.PREFER_WRITERS: if( m_numQueuedWriters > 0 ) m_writerQueue.notify(); else if( m_numQueuedReaders > 0 ) m_readerQueue.notifyAll(); } } } } /** * Attempts to acquire a write lock on the enclosing mutex. If one can * be obtained without blocking, the lock is acquired and true is * returned. If not, the lock is not acquired and false is returned. * * Returns: * true if the lock was acquired and false if not. */ bool tryLock() { synchronized( m_commonMutex ) { if( shouldQueueWriter ) return false; ++m_numActiveWriters; return true; } } private: @property bool shouldQueueWriter() { if( m_numActiveWriters > 0 || m_numActiveReaders > 0 ) return true; switch( m_policy ) { case Policy.PREFER_READERS: return m_numQueuedReaders > 0; case Policy.PREFER_WRITERS: default: break; } return false; } struct MonitorProxy { Object.Monitor link; } MonitorProxy m_proxy; } private: Policy m_policy; Reader m_reader; Writer m_writer; Mutex m_commonMutex; Condition m_readerQueue; Condition m_writerQueue; int m_numQueuedReaders; int m_numActiveReaders; int m_numQueuedWriters; int m_numActiveWriters; } //////////////////////////////////////////////////////////////////////////////// // Unit Tests //////////////////////////////////////////////////////////////////////////////// unittest { import core.atomic, core.thread, core.sync.semaphore; static void runTest(ReadWriteMutex.Policy policy) { scope mutex = new ReadWriteMutex(policy); scope rdSemA = new Semaphore, rdSemB = new Semaphore, wrSemA = new Semaphore, wrSemB = new Semaphore; shared size_t numReaders, numWriters; void readerFn() { synchronized (mutex.reader) { atomicOp!"+="(numReaders, 1); rdSemA.notify(); rdSemB.wait(); atomicOp!"-="(numReaders, 1); } } void writerFn() { synchronized (mutex.writer) { atomicOp!"+="(numWriters, 1); wrSemA.notify(); wrSemB.wait(); atomicOp!"-="(numWriters, 1); } } void waitQueued(size_t queuedReaders, size_t queuedWriters) { for (;;) { synchronized (mutex.m_commonMutex) { if (mutex.m_numQueuedReaders == queuedReaders && mutex.m_numQueuedWriters == queuedWriters) break; } Thread.yield(); } } scope group = new ThreadGroup; // 2 simultaneous readers group.create(&readerFn); group.create(&readerFn); rdSemA.wait(); rdSemA.wait(); assert(numReaders == 2); rdSemB.notify(); rdSemB.notify(); group.joinAll(); assert(numReaders == 0); foreach (t; group) group.remove(t); // 1 writer at a time group.create(&writerFn); group.create(&writerFn); wrSemA.wait(); assert(!wrSemA.tryWait()); assert(numWriters == 1); wrSemB.notify(); wrSemA.wait(); assert(numWriters == 1); wrSemB.notify(); group.joinAll(); assert(numWriters == 0); foreach (t; group) group.remove(t); // reader and writer are mutually exclusive group.create(&readerFn); rdSemA.wait(); group.create(&writerFn); waitQueued(0, 1); assert(!wrSemA.tryWait()); assert(numReaders == 1 && numWriters == 0); rdSemB.notify(); wrSemA.wait(); assert(numReaders == 0 && numWriters == 1); wrSemB.notify(); group.joinAll(); assert(numReaders == 0 && numWriters == 0); foreach (t; group) group.remove(t); // writer and reader are mutually exclusive group.create(&writerFn); wrSemA.wait(); group.create(&readerFn); waitQueued(1, 0); assert(!rdSemA.tryWait()); assert(numReaders == 0 && numWriters == 1); wrSemB.notify(); rdSemA.wait(); assert(numReaders == 1 && numWriters == 0); rdSemB.notify(); group.joinAll(); assert(numReaders == 0 && numWriters == 0); foreach (t; group) group.remove(t); // policy determines whether queued reader or writers progress first group.create(&writerFn); wrSemA.wait(); group.create(&readerFn); group.create(&writerFn); waitQueued(1, 1); assert(numReaders == 0 && numWriters == 1); wrSemB.notify(); if (policy == ReadWriteMutex.Policy.PREFER_READERS) { rdSemA.wait(); assert(numReaders == 1 && numWriters == 0); rdSemB.notify(); wrSemA.wait(); assert(numReaders == 0 && numWriters == 1); wrSemB.notify(); } else if (policy == ReadWriteMutex.Policy.PREFER_WRITERS) { wrSemA.wait(); assert(numReaders == 0 && numWriters == 1); wrSemB.notify(); rdSemA.wait(); assert(numReaders == 1 && numWriters == 0); rdSemB.notify(); } group.joinAll(); assert(numReaders == 0 && numWriters == 0); foreach (t; group) group.remove(t); } runTest(ReadWriteMutex.Policy.PREFER_READERS); runTest(ReadWriteMutex.Policy.PREFER_WRITERS); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sync/exception.d0000664000175000017500000000160712776214756022325 0ustar kaikai/** * Define base class for synchronization exceptions. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/sync/_exception.d) */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sync.exception; /** * Base class for synchronization errors. */ class SyncError : Error { @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(msg, file, line, next); } @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) { super(msg, file, line, next); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sync/condition.d0000664000175000017500000004076412776214756022324 0ustar kaikai/** * The condition module provides a primitive for synchronized condition * checking. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/sync/_condition.d) */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sync.condition; public import core.sync.exception; public import core.sync.mutex; public import core.time; version( Windows ) { private import core.sync.semaphore; private import core.sys.windows.windows; } else version( Posix ) { private import core.sync.config; private import core.stdc.errno; private import core.sys.posix.pthread; private import core.sys.posix.time; } else { static assert(false, "Platform not supported"); } //////////////////////////////////////////////////////////////////////////////// // Condition // // void wait(); // void notify(); // void notifyAll(); //////////////////////////////////////////////////////////////////////////////// /** * This class represents a condition variable as conceived by C.A.R. Hoare. As * per Mesa type monitors however, "signal" has been replaced with "notify" to * indicate that control is not transferred to the waiter when a notification * is sent. */ class Condition { //////////////////////////////////////////////////////////////////////////// // Initialization //////////////////////////////////////////////////////////////////////////// /** * Initializes a condition object which is associated with the supplied * mutex object. * * Params: * m = The mutex with which this condition will be associated. * * Throws: * SyncError on error. */ this( Mutex m ) nothrow @safe { version( Windows ) { m_blockLock = CreateSemaphoreA( null, 1, 1, null ); if( m_blockLock == m_blockLock.init ) throw new SyncError( "Unable to initialize condition" ); scope(failure) CloseHandle( m_blockLock ); m_blockQueue = CreateSemaphoreA( null, 0, int.max, null ); if( m_blockQueue == m_blockQueue.init ) throw new SyncError( "Unable to initialize condition" ); scope(failure) CloseHandle( m_blockQueue ); InitializeCriticalSection( &m_unblockLock ); m_assocMutex = m; } else version( Posix ) { m_assocMutex = m; int rc = pthread_cond_init( &m_hndl, null ); if( rc ) throw new SyncError( "Unable to initialize condition" ); } } ~this() { version( Windows ) { BOOL rc = CloseHandle( m_blockLock ); assert( rc, "Unable to destroy condition" ); rc = CloseHandle( m_blockQueue ); assert( rc, "Unable to destroy condition" ); DeleteCriticalSection( &m_unblockLock ); } else version( Posix ) { int rc = pthread_cond_destroy( &m_hndl ); assert( !rc, "Unable to destroy condition" ); } } //////////////////////////////////////////////////////////////////////////// // General Properties //////////////////////////////////////////////////////////////////////////// /** * Gets the mutex associated with this condition. * * Returns: * The mutex associated with this condition. */ @property Mutex mutex() { return m_assocMutex; } // undocumented function for internal use final @property Mutex mutex_nothrow() pure nothrow @safe @nogc { return m_assocMutex; } //////////////////////////////////////////////////////////////////////////// // General Actions //////////////////////////////////////////////////////////////////////////// /** * Wait until notified. * * Throws: * SyncError on error. */ void wait() { version( Windows ) { timedWait( INFINITE ); } else version( Posix ) { int rc = pthread_cond_wait( &m_hndl, m_assocMutex.handleAddr() ); if( rc ) throw new SyncError( "Unable to wait for condition" ); } } /** * Suspends the calling thread until a notification occurs or until the * supplied time period has elapsed. * * Params: * val = The time to wait. * * In: * val must be non-negative. * * Throws: * SyncError on error. * * Returns: * true if notified before the timeout and false if not. */ bool wait( Duration val ) in { assert( !val.isNegative ); } body { version( Windows ) { auto maxWaitMillis = dur!("msecs")( uint.max - 1 ); while( val > maxWaitMillis ) { if( timedWait( cast(uint) maxWaitMillis.total!"msecs" ) ) return true; val -= maxWaitMillis; } return timedWait( cast(uint) val.total!"msecs" ); } else version( Posix ) { timespec t = void; mktspec( t, val ); int rc = pthread_cond_timedwait( &m_hndl, m_assocMutex.handleAddr(), &t ); if( !rc ) return true; if( rc == ETIMEDOUT ) return false; throw new SyncError( "Unable to wait for condition" ); } } /** * Notifies one waiter. * * Throws: * SyncError on error. */ void notify() { version( Windows ) { notify( false ); } else version( Posix ) { int rc = pthread_cond_signal( &m_hndl ); if( rc ) throw new SyncError( "Unable to notify condition" ); } } /** * Notifies all waiters. * * Throws: * SyncError on error. */ void notifyAll() { version( Windows ) { notify( true ); } else version( Posix ) { int rc = pthread_cond_broadcast( &m_hndl ); if( rc ) throw new SyncError( "Unable to notify condition" ); } } private: version( Windows ) { bool timedWait( DWORD timeout ) { int numSignalsLeft; int numWaitersGone; DWORD rc; rc = WaitForSingleObject( m_blockLock, INFINITE ); assert( rc == WAIT_OBJECT_0 ); m_numWaitersBlocked++; rc = ReleaseSemaphore( m_blockLock, 1, null ); assert( rc ); m_assocMutex.unlock(); scope(failure) m_assocMutex.lock(); rc = WaitForSingleObject( m_blockQueue, timeout ); assert( rc == WAIT_OBJECT_0 || rc == WAIT_TIMEOUT ); bool timedOut = (rc == WAIT_TIMEOUT); EnterCriticalSection( &m_unblockLock ); scope(failure) LeaveCriticalSection( &m_unblockLock ); if( (numSignalsLeft = m_numWaitersToUnblock) != 0 ) { if ( timedOut ) { // timeout (or canceled) if( m_numWaitersBlocked != 0 ) { m_numWaitersBlocked--; // do not unblock next waiter below (already unblocked) numSignalsLeft = 0; } else { // spurious wakeup pending!! m_numWaitersGone = 1; } } if( --m_numWaitersToUnblock == 0 ) { if( m_numWaitersBlocked != 0 ) { // open the gate rc = ReleaseSemaphore( m_blockLock, 1, null ); assert( rc ); // do not open the gate below again numSignalsLeft = 0; } else if( (numWaitersGone = m_numWaitersGone) != 0 ) { m_numWaitersGone = 0; } } } else if( ++m_numWaitersGone == int.max / 2 ) { // timeout/canceled or spurious event :-) rc = WaitForSingleObject( m_blockLock, INFINITE ); assert( rc == WAIT_OBJECT_0 ); // something is going on here - test of timeouts? m_numWaitersBlocked -= m_numWaitersGone; rc = ReleaseSemaphore( m_blockLock, 1, null ); assert( rc == WAIT_OBJECT_0 ); m_numWaitersGone = 0; } LeaveCriticalSection( &m_unblockLock ); if( numSignalsLeft == 1 ) { // better now than spurious later (same as ResetEvent) for( ; numWaitersGone > 0; --numWaitersGone ) { rc = WaitForSingleObject( m_blockQueue, INFINITE ); assert( rc == WAIT_OBJECT_0 ); } // open the gate rc = ReleaseSemaphore( m_blockLock, 1, null ); assert( rc ); } else if( numSignalsLeft != 0 ) { // unblock next waiter rc = ReleaseSemaphore( m_blockQueue, 1, null ); assert( rc ); } m_assocMutex.lock(); return !timedOut; } void notify( bool all ) { DWORD rc; EnterCriticalSection( &m_unblockLock ); scope(failure) LeaveCriticalSection( &m_unblockLock ); if( m_numWaitersToUnblock != 0 ) { if( m_numWaitersBlocked == 0 ) { LeaveCriticalSection( &m_unblockLock ); return; } if( all ) { m_numWaitersToUnblock += m_numWaitersBlocked; m_numWaitersBlocked = 0; } else { m_numWaitersToUnblock++; m_numWaitersBlocked--; } LeaveCriticalSection( &m_unblockLock ); } else if( m_numWaitersBlocked > m_numWaitersGone ) { rc = WaitForSingleObject( m_blockLock, INFINITE ); assert( rc == WAIT_OBJECT_0 ); if( 0 != m_numWaitersGone ) { m_numWaitersBlocked -= m_numWaitersGone; m_numWaitersGone = 0; } if( all ) { m_numWaitersToUnblock = m_numWaitersBlocked; m_numWaitersBlocked = 0; } else { m_numWaitersToUnblock = 1; m_numWaitersBlocked--; } LeaveCriticalSection( &m_unblockLock ); rc = ReleaseSemaphore( m_blockQueue, 1, null ); assert( rc ); } else { LeaveCriticalSection( &m_unblockLock ); } } // NOTE: This implementation uses Algorithm 8c as described here: // http://groups.google.com/group/comp.programming.threads/ // browse_frm/thread/1692bdec8040ba40/e7a5f9d40e86503a HANDLE m_blockLock; // auto-reset event (now semaphore) HANDLE m_blockQueue; // auto-reset event (now semaphore) Mutex m_assocMutex; // external mutex/CS CRITICAL_SECTION m_unblockLock; // internal mutex/CS int m_numWaitersGone = 0; int m_numWaitersBlocked = 0; int m_numWaitersToUnblock = 0; } else version( Posix ) { Mutex m_assocMutex; pthread_cond_t m_hndl; } } //////////////////////////////////////////////////////////////////////////////// // Unit Tests //////////////////////////////////////////////////////////////////////////////// version( unittest ) { private import core.thread; private import core.sync.mutex; private import core.sync.semaphore; void testNotify() { auto mutex = new Mutex; auto condReady = new Condition( mutex ); auto semDone = new Semaphore; auto synLoop = new Object; int numWaiters = 10; int numTries = 10; int numReady = 0; int numTotal = 0; int numDone = 0; int numPost = 0; void waiter() { for( int i = 0; i < numTries; ++i ) { synchronized( mutex ) { while( numReady < 1 ) { condReady.wait(); } --numReady; ++numTotal; } synchronized( synLoop ) { ++numDone; } semDone.wait(); } } auto group = new ThreadGroup; for( int i = 0; i < numWaiters; ++i ) group.create( &waiter ); for( int i = 0; i < numTries; ++i ) { for( int j = 0; j < numWaiters; ++j ) { synchronized( mutex ) { ++numReady; condReady.notify(); } } while( true ) { synchronized( synLoop ) { if( numDone >= numWaiters ) break; } Thread.yield(); } for( int j = 0; j < numWaiters; ++j ) { semDone.notify(); } } group.joinAll(); assert( numTotal == numWaiters * numTries ); } void testNotifyAll() { auto mutex = new Mutex; auto condReady = new Condition( mutex ); int numWaiters = 10; int numReady = 0; int numDone = 0; bool alert = false; void waiter() { synchronized( mutex ) { ++numReady; while( !alert ) condReady.wait(); ++numDone; } } auto group = new ThreadGroup; for( int i = 0; i < numWaiters; ++i ) group.create( &waiter ); while( true ) { synchronized( mutex ) { if( numReady >= numWaiters ) { alert = true; condReady.notifyAll(); break; } } Thread.yield(); } group.joinAll(); assert( numReady == numWaiters && numDone == numWaiters ); } void testWaitTimeout() { auto mutex = new Mutex; auto condReady = new Condition( mutex ); bool waiting = false; bool alertedOne = true; bool alertedTwo = true; void waiter() { synchronized( mutex ) { waiting = true; // we never want to miss the notification (30s) alertedOne = condReady.wait( dur!"seconds"(30) ); // but we don't want to wait long for the timeout (10ms) alertedTwo = condReady.wait( dur!"msecs"(10) ); } } auto thread = new Thread( &waiter ); thread.start(); while( true ) { synchronized( mutex ) { if( waiting ) { condReady.notify(); break; } } Thread.yield(); } thread.join(); assert( waiting ); assert( alertedOne ); assert( !alertedTwo ); } unittest { testNotify(); testNotifyAll(); testWaitTimeout(); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/thread.d0000664000175000017500000054414612776214756020634 0ustar kaikai/** * The thread module provides support for thread creation and management. * * Copyright: Copyright Sean Kelly 2005 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak * Source: $(DRUNTIMESRC core/_thread.d) */ module core.thread; public import core.time; // for Duration import core.exception : onOutOfMemoryError; private { // interface to rt.tlsgc import core.internal.traits : externDFunc; alias rt_tlsgc_init = externDFunc!("rt.tlsgc.init", void* function()); alias rt_tlsgc_destroy = externDFunc!("rt.tlsgc.destroy", void function(void*)); alias ScanDg = void delegate(void* pstart, void* pend) nothrow; alias rt_tlsgc_scan = externDFunc!("rt.tlsgc.scan", void function(void*, scope ScanDg) nothrow); alias rt_tlsgc_processGCMarks = externDFunc!("rt.tlsgc.processGCMarks", void function(void*, scope IsMarkedDg) nothrow); } version( Solaris ) { import core.sys.solaris.sys.priocntl; import core.sys.solaris.sys.types; } // this should be true for most architectures version = StackGrowsDown; /** * Returns the process ID of the calling process, which is guaranteed to be * unique on the system. This call is always successful. * * Example: * --- * writefln("Current process id: %s", getpid()); * --- */ version(Posix) { alias core.sys.posix.unistd.getpid getpid; } else version (Windows) { alias core.sys.windows.windows.GetCurrentProcessId getpid; } /////////////////////////////////////////////////////////////////////////////// // Thread and Fiber Exceptions /////////////////////////////////////////////////////////////////////////////// /** * Base class for thread exceptions. */ class ThreadException : Exception { @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(msg, file, line, next); } @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) { super(msg, file, line, next); } } /** * Base class for thread errors to be used for function inside GC when allocations are unavailable. */ class ThreadError : Error { @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { super(msg, file, line, next); } @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) { super(msg, file, line, next); } } private { import core.atomic, core.memory, core.sync.mutex; // // exposed by compiler runtime // extern (C) void rt_moduleTlsCtor(); extern (C) void rt_moduleTlsDtor(); /** * Hook for whatever EH implementation is used to save/restore some data * per stack. * * Params: * newContext = The return value of the prior call to this function * where the stack was last swapped out, or null when a fiber stack * is switched in for the first time. */ extern(C) void* _d_eh_swapContext(void* newContext) nothrow; version (DigitalMars) { version (Windows) alias _d_eh_swapContext swapContext; else { extern(C) void* _d_eh_swapContextDwarf(void* newContext) nothrow; void* swapContext(void* newContext) nothrow { /* Detect at runtime which scheme is being used. * Eventually, determine it statically. */ static int which = 0; final switch (which) { case 0: { assert(newContext == null); auto p = _d_eh_swapContext(newContext); auto pdwarf = _d_eh_swapContextDwarf(newContext); if (p) { which = 1; return p; } else if (pdwarf) { which = 2; return pdwarf; } return null; } case 1: return _d_eh_swapContext(newContext); case 2: return _d_eh_swapContextDwarf(newContext); } } } } else alias _d_eh_swapContext swapContext; } /////////////////////////////////////////////////////////////////////////////// // Thread Entry Point and Signal Handlers /////////////////////////////////////////////////////////////////////////////// version( Windows ) { private { import core.stdc.stdint : uintptr_t; // for _beginthreadex decl below import core.stdc.stdlib; // for malloc, atexit import core.sys.windows.windows; import core.sys.windows.threadaux; // for OpenThreadHandle extern (Windows) alias uint function(void*) btex_fptr; extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*) nothrow; // // Entry point for Windows threads // extern (Windows) uint thread_entryPoint( void* arg ) { Thread obj = cast(Thread) arg; assert( obj ); assert( obj.m_curr is &obj.m_main ); obj.m_main.bstack = getStackBottom(); obj.m_main.tstack = obj.m_main.bstack; obj.m_tlsgcdata = rt_tlsgc_init(); Thread.setThis(obj); Thread.add(obj); scope (exit) { Thread.remove(obj); } Thread.add(&obj.m_main); // NOTE: No GC allocations may occur until the stack pointers have // been set and Thread.getThis returns a valid reference to // this thread object (this latter condition is not strictly // necessary on Windows but it should be followed for the // sake of consistency). // TODO: Consider putting an auto exception object here (using // alloca) forOutOfMemoryError plus something to track // whether an exception is in-flight? void append( Throwable t ) { if( obj.m_unhandled is null ) obj.m_unhandled = t; else { Throwable last = obj.m_unhandled; while( last.next !is null ) last = last.next; last.next = t; } } version( D_InlineAsm_X86 ) { asm nothrow @nogc { fninit; } } try { rt_moduleTlsCtor(); try { obj.run(); } catch( Throwable t ) { append( t ); } rt_moduleTlsDtor(); } catch( Throwable t ) { append( t ); } return 0; } HANDLE GetCurrentThreadHandle() { const uint DUPLICATE_SAME_ACCESS = 0x00000002; HANDLE curr = GetCurrentThread(), proc = GetCurrentProcess(), hndl; DuplicateHandle( proc, curr, proc, &hndl, 0, TRUE, DUPLICATE_SAME_ACCESS ); return hndl; } } } else version( Posix ) { private { import core.stdc.errno; import core.sys.posix.semaphore; import core.sys.posix.stdlib; // for malloc, valloc, free, atexit import core.sys.posix.pthread; import core.sys.posix.signal; import core.sys.posix.time; version( OSX ) { import core.sys.osx.mach.thread_act; import core.sys.osx.pthread : pthread_mach_thread_np; } version( GNU ) { import gcc.builtins; } // // Entry point for POSIX threads // extern (C) void* thread_entryPoint( void* arg ) { version (Shared) { import rt.sections; Thread obj = cast(Thread)(cast(void**)arg)[0]; auto loadedLibraries = (cast(void**)arg)[1]; .free(arg); } else { Thread obj = cast(Thread)arg; } assert( obj ); // loadedLibraries need to be inherited from parent thread // before initilizing GC for TLS (rt_tlsgc_init) version (Shared) inheritLoadedLibraries(loadedLibraries); assert( obj.m_curr is &obj.m_main ); obj.m_main.bstack = getStackBottom(); obj.m_main.tstack = obj.m_main.bstack; obj.m_tlsgcdata = rt_tlsgc_init(); atomicStore!(MemoryOrder.raw)(obj.m_isRunning, true); Thread.setThis(obj); // allocates lazy TLS (see Issue 11981) Thread.add(obj); // can only receive signals from here on scope (exit) { Thread.remove(obj); atomicStore!(MemoryOrder.raw)(obj.m_isRunning, false); } Thread.add(&obj.m_main); static extern (C) void thread_cleanupHandler( void* arg ) nothrow { Thread obj = cast(Thread) arg; assert( obj ); // NOTE: If the thread terminated abnormally, just set it as // not running and let thread_suspendAll remove it from // the thread list. This is safer and is consistent // with the Windows thread code. atomicStore!(MemoryOrder.raw)(obj.m_isRunning,false); } // NOTE: Using void to skip the initialization here relies on // knowledge of how pthread_cleanup is implemented. It may // not be appropriate for all platforms. However, it does // avoid the need to link the pthread module. If any // implementation actually requires default initialization // then pthread_cleanup should be restructured to maintain // the current lack of a link dependency. static if( __traits( compiles, pthread_cleanup ) ) { pthread_cleanup cleanup = void; cleanup.push( &thread_cleanupHandler, cast(void*) obj ); } else static if( __traits( compiles, pthread_cleanup_push ) ) { pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj ); } else { static assert( false, "Platform not supported." ); } // NOTE: No GC allocations may occur until the stack pointers have // been set and Thread.getThis returns a valid reference to // this thread object (this latter condition is not strictly // necessary on Windows but it should be followed for the // sake of consistency). // TODO: Consider putting an auto exception object here (using // alloca) forOutOfMemoryError plus something to track // whether an exception is in-flight? void append( Throwable t ) { if( obj.m_unhandled is null ) obj.m_unhandled = t; else { Throwable last = obj.m_unhandled; while( last.next !is null ) last = last.next; last.next = t; } } try { rt_moduleTlsCtor(); try { obj.run(); } catch( Throwable t ) { append( t ); } rt_moduleTlsDtor(); version (Shared) cleanupLoadedLibraries(); } catch( Throwable t ) { append( t ); } // NOTE: Normal cleanup is handled by scope(exit). static if( __traits( compiles, pthread_cleanup ) ) { cleanup.pop( 0 ); } else static if( __traits( compiles, pthread_cleanup_push ) ) { pthread_cleanup_pop( 0 ); } return null; } // // Used to track the number of suspended threads // __gshared sem_t suspendCount; extern (C) void thread_suspendHandler( int sig ) nothrow in { assert( sig == suspendSignalNumber ); } body { void op(void* sp) nothrow { // NOTE: Since registers are being pushed and popped from the // stack, any other stack data used by this function should // be gone before the stack cleanup code is called below. Thread obj = Thread.getThis(); assert(obj !is null); if( !obj.m_lock ) { obj.m_curr.tstack = getStackTop(); } sigset_t sigres = void; int status; status = sigfillset( &sigres ); assert( status == 0 ); status = sigdelset( &sigres, resumeSignalNumber ); assert( status == 0 ); version (FreeBSD) obj.m_suspendagain = false; status = sem_post( &suspendCount ); assert( status == 0 ); sigsuspend( &sigres ); if( !obj.m_lock ) { obj.m_curr.tstack = obj.m_curr.bstack; } } // avoid deadlocks on FreeBSD, see Issue 13416 version (FreeBSD) { auto obj = Thread.getThis(); if (THR_IN_CRITICAL(obj.m_addr)) { obj.m_suspendagain = true; if (sem_post(&suspendCount)) assert(0); return; } } callWithStackShell(&op); } extern (C) void thread_resumeHandler( int sig ) nothrow in { assert( sig == resumeSignalNumber ); } body { } // HACK libthr internal (thr_private.h) macro, used to // avoid deadlocks in signal handler, see Issue 13416 version (FreeBSD) bool THR_IN_CRITICAL(pthread_t p) nothrow @nogc { import core.sys.posix.config : c_long; import core.sys.posix.sys.types : lwpid_t; // If the begin of pthread would be changed in libthr (unlikely) // we'll run into undefined behavior, compare with thr_private.h. static struct pthread { c_long tid; static struct umutex { lwpid_t owner; uint flags; uint[2] ceilings; uint[4] spare; } umutex lock; uint cycle; int locklevel; int critical_count; // ... } auto priv = cast(pthread*)p; return priv.locklevel > 0 || priv.critical_count > 0; } } } else { // NOTE: This is the only place threading versions are checked. If a new // version is added, the module code will need to be searched for // places where version-specific code may be required. This can be // easily accomlished by searching for 'Windows' or 'Posix'. static assert( false, "Unknown threading implementation." ); } /////////////////////////////////////////////////////////////////////////////// // Thread /////////////////////////////////////////////////////////////////////////////// /** * This class encapsulates all threading functionality for the D * programming language. As thread manipulation is a required facility * for garbage collection, all user threads should derive from this * class, and instances of this class should never be explicitly deleted. * A new thread may be created using either derivation or composition, as * in the following example. */ class Thread { /////////////////////////////////////////////////////////////////////////// // Initialization /////////////////////////////////////////////////////////////////////////// /** * Initializes a thread object which is associated with a static * D function. * * Params: * fn = The thread function. * sz = The stack size for this thread. * * In: * fn must not be null. */ this( void function() fn, size_t sz = 0 ) in { assert( fn ); } body { this(sz); m_fn = fn; m_call = Call.FN; m_curr = &m_main; } /** * Initializes a thread object which is associated with a dynamic * D function. * * Params: * dg = The thread function. * sz = The stack size for this thread. * * In: * dg must not be null. */ this( void delegate() dg, size_t sz = 0 ) in { assert( dg ); } body { this(sz); m_dg = dg; m_call = Call.DG; m_curr = &m_main; } /** * Cleans up any remaining resources used by this object. */ ~this() { if( m_addr == m_addr.init ) { return; } version( Windows ) { m_addr = m_addr.init; CloseHandle( m_hndl ); m_hndl = m_hndl.init; } else version( Posix ) { pthread_detach( m_addr ); m_addr = m_addr.init; } version( OSX ) { m_tmach = m_tmach.init; } rt_tlsgc_destroy( m_tlsgcdata ); m_tlsgcdata = null; } /////////////////////////////////////////////////////////////////////////// // General Actions /////////////////////////////////////////////////////////////////////////// /** * Starts the thread and invokes the function or delegate passed upon * construction. * * In: * This routine may only be called once per thread instance. * * Throws: * ThreadException if the thread fails to start. */ final Thread start() nothrow in { assert( !next && !prev ); } body { auto wasThreaded = multiThreadedFlag; multiThreadedFlag = true; scope( failure ) { if( !wasThreaded ) multiThreadedFlag = false; } version( Windows ) {} else version( Posix ) { pthread_attr_t attr; if( pthread_attr_init( &attr ) ) onThreadError( "Error initializing thread attributes" ); if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) ) onThreadError( "Error initializing thread stack size" ); } version( Windows ) { // NOTE: If a thread is just executing DllMain() // while another thread is started here, it holds an OS internal // lock that serializes DllMain with CreateThread. As the code // might request a synchronization on slock (e.g. in thread_findByAddr()), // we cannot hold that lock while creating the thread without // creating a deadlock // // Solution: Create the thread in suspended state and then // add and resume it with slock acquired assert(m_sz <= uint.max, "m_sz must be less than or equal to uint.max"); m_hndl = cast(HANDLE) _beginthreadex( null, cast(uint) m_sz, &thread_entryPoint, cast(void*) this, CREATE_SUSPENDED, &m_addr ); if( cast(size_t) m_hndl == 0 ) onThreadError( "Error creating thread" ); } slock.lock_nothrow(); scope(exit) slock.unlock_nothrow(); { ++nAboutToStart; pAboutToStart = cast(Thread*)realloc(pAboutToStart, Thread.sizeof * nAboutToStart); pAboutToStart[nAboutToStart - 1] = this; version( Windows ) { if( ResumeThread( m_hndl ) == -1 ) onThreadError( "Error resuming thread" ); } else version( Posix ) { // NOTE: This is also set to true by thread_entryPoint, but set it // here as well so the calling thread will see the isRunning // state immediately. atomicStore!(MemoryOrder.raw)(m_isRunning, true); scope( failure ) atomicStore!(MemoryOrder.raw)(m_isRunning, false); version (Shared) { import rt.sections; auto libs = pinLoadedLibraries(); auto ps = cast(void**).malloc(2 * size_t.sizeof); if (ps is null) onOutOfMemoryError(); ps[0] = cast(void*)this; ps[1] = cast(void*)libs; if( pthread_create( &m_addr, &attr, &thread_entryPoint, ps ) != 0 ) { unpinLoadedLibraries(libs); .free(ps); onThreadError( "Error creating thread" ); } } else { if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 ) onThreadError( "Error creating thread" ); } } version( OSX ) { m_tmach = pthread_mach_thread_np( m_addr ); if( m_tmach == m_tmach.init ) onThreadError( "Error creating thread" ); } return this; } } /** * Waits for this thread to complete. If the thread terminated as the * result of an unhandled exception, this exception will be rethrown. * * Params: * rethrow = Rethrow any unhandled exception which may have caused this * thread to terminate. * * Throws: * ThreadException if the operation fails. * Any exception not handled by the joined thread. * * Returns: * Any exception not handled by this thread if rethrow = false, null * otherwise. */ final Throwable join( bool rethrow = true ) { version( Windows ) { if( WaitForSingleObject( m_hndl, INFINITE ) != WAIT_OBJECT_0 ) throw new ThreadException( "Unable to join thread" ); // NOTE: m_addr must be cleared before m_hndl is closed to avoid // a race condition with isRunning. The operation is done // with atomicStore to prevent compiler reordering. atomicStore!(MemoryOrder.raw)(*cast(shared)&m_addr, m_addr.init); CloseHandle( m_hndl ); m_hndl = m_hndl.init; } else version( Posix ) { if( pthread_join( m_addr, null ) != 0 ) throw new ThreadException( "Unable to join thread" ); // NOTE: pthread_join acts as a substitute for pthread_detach, // which is normally called by the dtor. Setting m_addr // to zero ensures that pthread_detach will not be called // on object destruction. m_addr = m_addr.init; } if( m_unhandled ) { if( rethrow ) throw m_unhandled; return m_unhandled; } return null; } /////////////////////////////////////////////////////////////////////////// // General Properties /////////////////////////////////////////////////////////////////////////// /** * Gets the OS identifier for this thread. * * Returns: * If the thread hasn't been started yet, returns $(LREF ThreadID)$(D.init). * Otherwise, returns the result of $(D GetCurrentThreadId) on Windows, * and $(D pthread_self) on POSIX. * * The value is unique for the current process. */ final @property ThreadID id() { synchronized( this ) { return m_addr; } } /** * Gets the user-readable label for this thread. * * Returns: * The name of this thread. */ final @property string name() { synchronized( this ) { return m_name; } } /** * Sets the user-readable label for this thread. * * Params: * val = The new name of this thread. */ final @property void name( string val ) { synchronized( this ) { m_name = val; } } /** * Gets the daemon status for this thread. While the runtime will wait for * all normal threads to complete before tearing down the process, daemon * threads are effectively ignored and thus will not prevent the process * from terminating. In effect, daemon threads will be terminated * automatically by the OS when the process exits. * * Returns: * true if this is a daemon thread. */ final @property bool isDaemon() { synchronized( this ) { return m_isDaemon; } } /** * Sets the daemon status for this thread. While the runtime will wait for * all normal threads to complete before tearing down the process, daemon * threads are effectively ignored and thus will not prevent the process * from terminating. In effect, daemon threads will be terminated * automatically by the OS when the process exits. * * Params: * val = The new daemon status for this thread. */ final @property void isDaemon( bool val ) { synchronized( this ) { m_isDaemon = val; } } /** * Tests whether this thread is running. * * Returns: * true if the thread is running, false if not. */ final @property bool isRunning() nothrow { if( m_addr == m_addr.init ) { return false; } version( Windows ) { uint ecode = 0; GetExitCodeThread( m_hndl, &ecode ); return ecode == STILL_ACTIVE; } else version( Posix ) { return atomicLoad(m_isRunning); } } /////////////////////////////////////////////////////////////////////////// // Thread Priority Actions /////////////////////////////////////////////////////////////////////////// /** * The minimum scheduling priority that may be set for a thread. On * systems where multiple scheduling policies are defined, this value * represents the minimum valid priority for the scheduling policy of * the process. */ __gshared const int PRIORITY_MIN; /** * The maximum scheduling priority that may be set for a thread. On * systems where multiple scheduling policies are defined, this value * represents the maximum valid priority for the scheduling policy of * the process. */ __gshared const int PRIORITY_MAX; /** * The default scheduling priority that is set for a thread. On * systems where multiple scheduling policies are defined, this value * represents the default priority for the scheduling policy of * the process. */ __gshared const int PRIORITY_DEFAULT; /** * Gets the scheduling priority for the associated thread. * * Note: Getting the priority of a thread that already terminated * might return the default priority. * * Returns: * The scheduling priority of this thread. */ final @property int priority() { version( Windows ) { return GetThreadPriority( m_hndl ); } else version( Posix ) { int policy; sched_param param; if (auto err = pthread_getschedparam(m_addr, &policy, ¶m)) { // ignore error if thread is not running => Bugzilla 8960 if (!atomicLoad(m_isRunning)) return PRIORITY_DEFAULT; throw new ThreadException("Unable to get thread priority"); } return param.sched_priority; } } /** * Sets the scheduling priority for the associated thread. * * Note: Setting the priority of a thread that already terminated * might have no effect. * * Params: * val = The new scheduling priority of this thread. */ final @property void priority( int val ) in { assert(val >= PRIORITY_MIN); assert(val <= PRIORITY_MAX); } body { version( Windows ) { if( !SetThreadPriority( m_hndl, val ) ) throw new ThreadException( "Unable to set thread priority" ); } else version( Solaris ) { // the pthread_setschedprio(3c) and pthread_setschedparam functions // are broken for the default (TS / time sharing) scheduling class. // instead, we use priocntl(2) which gives us the desired behavior. // We hardcode the min and max priorities to the current value // so this is a no-op for RT threads. if (m_isRTClass) return; pcparms_t pcparm; pcparm.pc_cid = PC_CLNULL; if (priocntl(idtype_t.P_LWPID, P_MYID, PC_GETPARMS, &pcparm) == -1) throw new ThreadException( "Unable to get scheduling class" ); pri_t* clparms = cast(pri_t*)&pcparm.pc_clparms; // clparms is filled in by the PC_GETPARMS call, only necessary // to adjust the element that contains the thread priority clparms[1] = cast(pri_t) val; if (priocntl(idtype_t.P_LWPID, P_MYID, PC_SETPARMS, &pcparm) == -1) throw new ThreadException( "Unable to set scheduling class" ); } else version( Posix ) { static if(__traits(compiles, pthread_setschedprio)) { if (auto err = pthread_setschedprio(m_addr, val)) { // ignore error if thread is not running => Bugzilla 8960 if (!atomicLoad(m_isRunning)) return; throw new ThreadException("Unable to set thread priority"); } } else { // NOTE: pthread_setschedprio is not implemented on OSX or FreeBSD, so use // the more complicated get/set sequence below. int policy; sched_param param; if (auto err = pthread_getschedparam(m_addr, &policy, ¶m)) { // ignore error if thread is not running => Bugzilla 8960 if (!atomicLoad(m_isRunning)) return; throw new ThreadException("Unable to set thread priority"); } param.sched_priority = val; if (auto err = pthread_setschedparam(m_addr, policy, ¶m)) { // ignore error if thread is not running => Bugzilla 8960 if (!atomicLoad(m_isRunning)) return; throw new ThreadException("Unable to set thread priority"); } } } } unittest { auto thr = Thread.getThis(); immutable prio = thr.priority; scope (exit) thr.priority = prio; assert(prio == PRIORITY_DEFAULT); assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX); thr.priority = PRIORITY_MIN; assert(thr.priority == PRIORITY_MIN); thr.priority = PRIORITY_MAX; assert(thr.priority == PRIORITY_MAX); } unittest // Bugzilla 8960 { import core.sync.semaphore; auto thr = new Thread({}); thr.start(); Thread.sleep(1.msecs); // wait a little so the thread likely has finished thr.priority = PRIORITY_MAX; // setting priority doesn't cause error auto prio = thr.priority; // getting priority doesn't cause error assert(prio >= PRIORITY_MIN && prio <= PRIORITY_MAX); } /////////////////////////////////////////////////////////////////////////// // Actions on Calling Thread /////////////////////////////////////////////////////////////////////////// /** * Suspends the calling thread for at least the supplied period. This may * result in multiple OS calls if period is greater than the maximum sleep * duration supported by the operating system. * * Params: * val = The minimum duration the calling thread should be suspended. * * In: * period must be non-negative. * * Example: * ------------------------------------------------------------------------ * * Thread.sleep( dur!("msecs")( 50 ) ); // sleep for 50 milliseconds * Thread.sleep( dur!("seconds")( 5 ) ); // sleep for 5 seconds * * ------------------------------------------------------------------------ */ static void sleep( Duration val ) @nogc nothrow in { assert( !val.isNegative ); } body { version( Windows ) { auto maxSleepMillis = dur!("msecs")( uint.max - 1 ); // avoid a non-zero time to be round down to 0 if( val > dur!"msecs"( 0 ) && val < dur!"msecs"( 1 ) ) val = dur!"msecs"( 1 ); // NOTE: In instances where all other threads in the process have a // lower priority than the current thread, the current thread // will not yield with a sleep time of zero. However, unlike // yield(), the user is not asking for a yield to occur but // only for execution to suspend for the requested interval. // Therefore, expected performance may not be met if a yield // is forced upon the user. while( val > maxSleepMillis ) { Sleep( cast(uint) maxSleepMillis.total!"msecs" ); val -= maxSleepMillis; } Sleep( cast(uint) val.total!"msecs" ); } else version( Posix ) { timespec tin = void; timespec tout = void; val.split!("seconds", "nsecs")(tin.tv_sec, tin.tv_nsec); if( val.total!"seconds" > tin.tv_sec.max ) tin.tv_sec = tin.tv_sec.max; while( true ) { if( !nanosleep( &tin, &tout ) ) return; if( errno != EINTR ) assert(0, "Unable to sleep for the specified duration"); tin = tout; } } } /** * Forces a context switch to occur away from the calling thread. */ static void yield() @nogc nothrow { version( Windows ) SwitchToThread(); else version( Posix ) sched_yield(); } /////////////////////////////////////////////////////////////////////////// // Thread Accessors /////////////////////////////////////////////////////////////////////////// /** * Provides a reference to the calling thread. * * Returns: * The thread object representing the calling thread. The result of * deleting this object is undefined. If the current thread is not * attached to the runtime, a null reference is returned. */ static Thread getThis() nothrow { // NOTE: This function may not be called until thread_init has // completed. See thread_suspendAll for more information // on why this might occur. return sm_this; } /** * Provides a list of all threads currently being tracked by the system. * Note that threads in the returned array might no longer run (see * $(D Thread.)$(LREF isRunning)). * * Returns: * An array containing references to all threads currently being * tracked by the system. The result of deleting any contained * objects is undefined. */ static Thread[] getAll() { static void resize(ref Thread[] buf, size_t nlen) { buf.length = nlen; } return getAllImpl!resize(); } /** * Operates on all threads currently being tracked by the system. The * result of deleting any Thread object is undefined. * Note that threads passed to the callback might no longer run (see * $(D Thread.)$(LREF isRunning)). * * Params: * dg = The supplied code as a delegate. * * Returns: * Zero if all elemented are visited, nonzero if not. */ static int opApply(scope int delegate(ref Thread) dg) { import core.stdc.stdlib : free, realloc; static void resize(ref Thread[] buf, size_t nlen) { buf = (cast(Thread*)realloc(buf.ptr, nlen * Thread.sizeof))[0 .. nlen]; } auto buf = getAllImpl!resize; scope(exit) if (buf.ptr) free(buf.ptr); foreach (t; buf) { if (auto res = dg(t)) return res; } return 0; } unittest { auto t1 = new Thread({ foreach (_; 0 .. 20) Thread.getAll; }).start; auto t2 = new Thread({ foreach (_; 0 .. 20) GC.collect; }).start; t1.join(); t2.join(); } private static Thread[] getAllImpl(alias resize)() { import core.atomic; Thread[] buf; while (true) { immutable len = atomicLoad!(MemoryOrder.raw)(*cast(shared)&sm_tlen); resize(buf, len); assert(buf.length == len); synchronized (slock) { if (len == sm_tlen) { size_t pos; for (Thread t = sm_tbeg; t; t = t.next) buf[pos++] = t; return buf; } } } } /////////////////////////////////////////////////////////////////////////// // Static Initalizer /////////////////////////////////////////////////////////////////////////// /** * This initializer is used to set thread constants. All functional * initialization occurs within thread_init(). */ shared static this() { version( Windows ) { PRIORITY_MIN = THREAD_PRIORITY_IDLE; PRIORITY_DEFAULT = THREAD_PRIORITY_NORMAL; PRIORITY_MAX = THREAD_PRIORITY_TIME_CRITICAL; } else version( Solaris ) { pcparms_t pcParms; pcinfo_t pcInfo; pcParms.pc_cid = PC_CLNULL; if (priocntl(idtype_t.P_PID, P_MYID, PC_GETPARMS, &pcParms) == -1) throw new ThreadException( "Unable to get scheduling class" ); pcInfo.pc_cid = pcParms.pc_cid; // PC_GETCLINFO ignores the first two args, use dummy values if (priocntl(idtype_t.P_PID, 0, PC_GETCLINFO, &pcInfo) == -1) throw new ThreadException( "Unable to get scheduling class info" ); pri_t* clparms = cast(pri_t*)&pcParms.pc_clparms; pri_t* clinfo = cast(pri_t*)&pcInfo.pc_clinfo; if (pcInfo.pc_clname == "RT") { m_isRTClass = true; // For RT class, just assume it can't be changed PRIORITY_MAX = clparms[0]; PRIORITY_MIN = clparms[0]; PRIORITY_DEFAULT = clparms[0]; } else { m_isRTClass = false; // For all other scheduling classes, there are // two key values -- uprilim and maxupri. // maxupri is the maximum possible priority defined // for the scheduling class, and valid priorities // range are in [-maxupri, maxupri]. // // However, uprilim is an upper limit that the // current thread can set for the current scheduling // class, which can be less than maxupri. As such, // use this value for PRIORITY_MAX since this is // the effective maximum. // uprilim PRIORITY_MAX = clparms[0]; // maxupri PRIORITY_MIN = -clinfo[0]; // by definition PRIORITY_DEFAULT = 0; } } else version( Posix ) { int policy; sched_param param; pthread_t self = pthread_self(); int status = pthread_getschedparam( self, &policy, ¶m ); assert( status == 0 ); PRIORITY_MIN = sched_get_priority_min( policy ); assert( PRIORITY_MIN != -1 ); PRIORITY_DEFAULT = param.sched_priority; PRIORITY_MAX = sched_get_priority_max( policy ); assert( PRIORITY_MAX != -1 ); } } /////////////////////////////////////////////////////////////////////////// // Stuff That Should Go Away /////////////////////////////////////////////////////////////////////////// private: // // Initializes a thread object which has no associated executable function. // This is used for the main thread initialized in thread_init(). // this(size_t sz = 0) { if (sz) { version (Posix) { // stack size must be a multiple of PAGESIZE sz += PAGESIZE - 1; sz -= sz % PAGESIZE; // and at least PTHREAD_STACK_MIN if (PTHREAD_STACK_MIN > sz) sz = PTHREAD_STACK_MIN; } m_sz = sz; } m_call = Call.NO; m_curr = &m_main; } // // Thread entry point. Invokes the function or delegate passed on // construction (if any). // final void run() { switch( m_call ) { case Call.FN: m_fn(); break; case Call.DG: m_dg(); break; default: break; } } private: // // The type of routine passed on thread construction. // enum Call { NO, FN, DG } // // Standard types // version( Windows ) { alias uint TLSKey; } else version( Posix ) { alias pthread_key_t TLSKey; } // // Local storage // static Thread sm_this; // // Main process thread // __gshared Thread sm_main; version (FreeBSD) { // set when suspend failed and should be retried, see Issue 13416 shared bool m_suspendagain; } // // Standard thread data // version( Windows ) { HANDLE m_hndl; } else version( OSX ) { mach_port_t m_tmach; } ThreadID m_addr; Call m_call; string m_name; union { void function() m_fn; void delegate() m_dg; } size_t m_sz; version( Posix ) { shared bool m_isRunning; } bool m_isDaemon; bool m_isInCriticalRegion; Throwable m_unhandled; version( Solaris ) { __gshared immutable bool m_isRTClass; } private: /////////////////////////////////////////////////////////////////////////// // Storage of Active Thread /////////////////////////////////////////////////////////////////////////// // // Sets a thread-local reference to the current thread object. // static void setThis( Thread t ) { sm_this = t; } private: /////////////////////////////////////////////////////////////////////////// // Thread Context and GC Scanning Support /////////////////////////////////////////////////////////////////////////// final void pushContext( Context* c ) nothrow in { assert( !c.within ); } body { m_curr.ehContext = swapContext(c.ehContext); c.within = m_curr; m_curr = c; } final void popContext() nothrow in { assert( m_curr && m_curr.within ); } body { Context* c = m_curr; m_curr = c.within; c.ehContext = swapContext(m_curr.ehContext); c.within = null; } final Context* topContext() nothrow in { assert( m_curr ); } body { return m_curr; } static struct Context { void* bstack, tstack; /// Slot for the EH implementation to keep some state for each stack /// (will be necessary for exception chaining, etc.). Opaque as far as /// we are concerned here. void* ehContext; Context* within; Context* next, prev; } Context m_main; Context* m_curr; bool m_lock; void* m_tlsgcdata; version( Windows ) { version( X86 ) { uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax } else version( X86_64 ) { ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax // r8,r9,r10,r11,r12,r13,r14,r15 } else { static assert(false, "Architecture not supported." ); } } else version( OSX ) { version( X86 ) { uint[8] m_reg; // edi,esi,ebp,esp,ebx,edx,ecx,eax } else version( X86_64 ) { ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax // r8,r9,r10,r11,r12,r13,r14,r15 } else { static assert(false, "Architecture not supported." ); } } private: /////////////////////////////////////////////////////////////////////////// // GC Scanning Support /////////////////////////////////////////////////////////////////////////// // NOTE: The GC scanning process works like so: // // 1. Suspend all threads. // 2. Scan the stacks of all suspended threads for roots. // 3. Resume all threads. // // Step 1 and 3 require a list of all threads in the system, while // step 2 requires a list of all thread stacks (each represented by // a Context struct). Traditionally, there was one stack per thread // and the Context structs were not necessary. However, Fibers have // changed things so that each thread has its own 'main' stack plus // an arbitrary number of nested stacks (normally referenced via // m_curr). Also, there may be 'free-floating' stacks in the system, // which are Fibers that are not currently executing on any specific // thread but are still being processed and still contain valid // roots. // // To support all of this, the Context struct has been created to // represent a stack range, and a global list of Context structs has // been added to enable scanning of these stack ranges. The lifetime // (and presence in the Context list) of a thread's 'main' stack will // be equivalent to the thread's lifetime. So the Ccontext will be // added to the list on thread entry, and removed from the list on // thread exit (which is essentially the same as the presence of a // Thread object in its own global list). The lifetime of a Fiber's // context, however, will be tied to the lifetime of the Fiber object // itself, and Fibers are expected to add/remove their Context struct // on construction/deletion. // // All use of the global thread lists/array should synchronize on this lock. // // Careful as the GC acquires this lock after the GC lock to suspend all // threads any GC usage with slock held can result in a deadlock through // lock order inversion. @property static Mutex slock() nothrow { return cast(Mutex)_locks[0].ptr; } @property static Mutex criticalRegionLock() nothrow { return cast(Mutex)_locks[1].ptr; } __gshared void[__traits(classInstanceSize, Mutex)][2] _locks; static void initLocks() { foreach (ref lock; _locks) { lock[] = typeid(Mutex).initializer[]; (cast(Mutex)lock.ptr).__ctor(); } } static void termLocks() { foreach (ref lock; _locks) (cast(Mutex)lock.ptr).__dtor(); } __gshared Context* sm_cbeg; __gshared Thread sm_tbeg; __gshared size_t sm_tlen; // can't use rt.util.array in public code __gshared Thread* pAboutToStart; __gshared size_t nAboutToStart; // // Used for ordering threads in the global thread list. // Thread prev; Thread next; /////////////////////////////////////////////////////////////////////////// // Global Context List Operations /////////////////////////////////////////////////////////////////////////// // // Add a context to the global context list. // static void add( Context* c ) nothrow in { assert( c ); assert( !c.next && !c.prev ); } body { slock.lock_nothrow(); scope(exit) slock.unlock_nothrow(); assert(!suspendDepth); // must be 0 b/c it's only set with slock held if (sm_cbeg) { c.next = sm_cbeg; sm_cbeg.prev = c; } sm_cbeg = c; } // // Remove a context from the global context list. // // This assumes slock being acquired. This isn't done here to // avoid double locking when called from remove(Thread) static void remove( Context* c ) nothrow in { assert( c ); assert( c.next || c.prev ); } body { if( c.prev ) c.prev.next = c.next; if( c.next ) c.next.prev = c.prev; if( sm_cbeg == c ) sm_cbeg = c.next; // NOTE: Don't null out c.next or c.prev because opApply currently // follows c.next after removing a node. This could be easily // addressed by simply returning the next node from this // function, however, a context should never be re-added to the // list anyway and having next and prev be non-null is a good way // to ensure that. } /////////////////////////////////////////////////////////////////////////// // Global Thread List Operations /////////////////////////////////////////////////////////////////////////// // // Add a thread to the global thread list. // static void add( Thread t, bool rmAboutToStart = true ) nothrow in { assert( t ); assert( !t.next && !t.prev ); } body { slock.lock_nothrow(); scope(exit) slock.unlock_nothrow(); assert(t.isRunning); // check this with slock to ensure pthread_create already returned assert(!suspendDepth); // must be 0 b/c it's only set with slock held if (rmAboutToStart) { size_t idx = -1; foreach (i, thr; pAboutToStart[0 .. nAboutToStart]) { if (thr is t) { idx = i; break; } } assert(idx != -1); import core.stdc.string : memmove; memmove(pAboutToStart + idx, pAboutToStart + idx + 1, Thread.sizeof * (nAboutToStart - idx - 1)); pAboutToStart = cast(Thread*)realloc(pAboutToStart, Thread.sizeof * --nAboutToStart); } if (sm_tbeg) { t.next = sm_tbeg; sm_tbeg.prev = t; } sm_tbeg = t; ++sm_tlen; } // // Remove a thread from the global thread list. // static void remove( Thread t ) nothrow in { assert( t ); } body { // Thread was already removed earlier, might happen b/c of thread_detachInstance if (!t.next && !t.prev) return; slock.lock_nothrow(); { // NOTE: When a thread is removed from the global thread list its // main context is invalid and should be removed as well. // It is possible that t.m_curr could reference more // than just the main context if the thread exited abnormally // (if it was terminated), but we must assume that the user // retains a reference to them and that they may be re-used // elsewhere. Therefore, it is the responsibility of any // object that creates contexts to clean them up properly // when it is done with them. remove( &t.m_main ); if( t.prev ) t.prev.next = t.next; if( t.next ) t.next.prev = t.prev; if( sm_tbeg is t ) sm_tbeg = t.next; t.prev = t.next = null; --sm_tlen; } // NOTE: Don't null out t.next or t.prev because opApply currently // follows t.next after removing a node. This could be easily // addressed by simply returning the next node from this // function, however, a thread should never be re-added to the // list anyway and having next and prev be non-null is a good way // to ensure that. slock.unlock_nothrow(); } } /// unittest { class DerivedThread : Thread { this() { super(&run); } private: void run() { // Derived thread running. } } void threadFunc() { // Composed thread running. } // create and start instances of each type auto derived = new DerivedThread().start(); auto composed = new Thread(&threadFunc).start(); new Thread({ // Codes to run in the newly created thread. }).start(); } unittest { int x = 0; new Thread( { x++; }).start().join(); assert( x == 1 ); } unittest { enum MSG = "Test message."; string caughtMsg; try { new Thread( { throw new Exception( MSG ); }).start().join(); assert( false, "Expected rethrown exception." ); } catch( Throwable t ) { assert( t.msg == MSG ); } } /////////////////////////////////////////////////////////////////////////////// // GC Support Routines /////////////////////////////////////////////////////////////////////////////// version( CoreDdoc ) { /** * Instruct the thread module, when initialized, to use a different set of * signals besides SIGUSR1 and SIGUSR2 for suspension and resumption of threads. * This function should be called at most once, prior to thread_init(). * This function is Posix-only. */ extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) { } } else version( Posix ) { extern (C) void thread_setGCSignals(int suspendSignalNo, int resumeSignalNo) in { assert(suspendSignalNumber == 0); assert(resumeSignalNumber == 0); assert(suspendSignalNo != 0); assert(resumeSignalNo != 0); } out { assert(suspendSignalNumber != 0); assert(resumeSignalNumber != 0); } body { suspendSignalNumber = suspendSignalNo; resumeSignalNumber = resumeSignalNo; } } version( Posix ) { __gshared int suspendSignalNumber; __gshared int resumeSignalNumber; } /** * Initializes the thread module. This function must be called by the * garbage collector on startup and before any other thread routines * are called. */ extern (C) void thread_init() { // NOTE: If thread_init itself performs any allocations then the thread // routines reserved for garbage collector use may be called while // thread_init is being processed. However, since no memory should // exist to be scanned at this point, it is sufficient for these // functions to detect the condition and return immediately. Thread.initLocks(); version( OSX ) { } else version( Posix ) { if( suspendSignalNumber == 0 ) { suspendSignalNumber = SIGUSR1; } if( resumeSignalNumber == 0 ) { resumeSignalNumber = SIGUSR2; } int status; sigaction_t sigusr1 = void; sigaction_t sigusr2 = void; // This is a quick way to zero-initialize the structs without using // memset or creating a link dependency on their static initializer. (cast(byte*) &sigusr1)[0 .. sigaction_t.sizeof] = 0; (cast(byte*) &sigusr2)[0 .. sigaction_t.sizeof] = 0; // NOTE: SA_RESTART indicates that system calls should restart if they // are interrupted by a signal, but this is not available on all // Posix systems, even those that support multithreading. static if( __traits( compiles, SA_RESTART ) ) sigusr1.sa_flags = SA_RESTART; else sigusr1.sa_flags = 0; sigusr1.sa_handler = &thread_suspendHandler; // NOTE: We want to ignore all signals while in this handler, so fill // sa_mask to indicate this. status = sigfillset( &sigusr1.sa_mask ); assert( status == 0 ); // NOTE: Since resumeSignalNumber should only be issued for threads within the // suspend handler, we don't want this signal to trigger a // restart. sigusr2.sa_flags = 0; sigusr2.sa_handler = &thread_resumeHandler; // NOTE: We want to ignore all signals while in this handler, so fill // sa_mask to indicate this. status = sigfillset( &sigusr2.sa_mask ); assert( status == 0 ); status = sigaction( suspendSignalNumber, &sigusr1, null ); assert( status == 0 ); status = sigaction( resumeSignalNumber, &sigusr2, null ); assert( status == 0 ); status = sem_init( &suspendCount, 0, 0 ); assert( status == 0 ); } Thread.sm_main = thread_attachThis(); } /** * Terminates the thread module. No other thread routine may be called * afterwards. */ extern (C) void thread_term() { assert(Thread.sm_tbeg && Thread.sm_tlen == 1); assert(!Thread.nAboutToStart); if (Thread.pAboutToStart) // in case realloc(p, 0) doesn't return null { free(Thread.pAboutToStart); Thread.pAboutToStart = null; } Thread.termLocks(); } /** * */ extern (C) bool thread_isMainThread() { return Thread.getThis() is Thread.sm_main; } /** * Registers the calling thread for use with the D Runtime. If this routine * is called for a thread which is already registered, no action is performed. * * NOTE: This routine does not run thread-local static constructors when called. * If full functionality as a D thread is desired, the following function * must be called after thread_attachThis: * * extern (C) void rt_moduleTlsCtor(); */ extern (C) Thread thread_attachThis() { GC.disable(); scope(exit) GC.enable(); if (auto t = Thread.getThis()) return t; Thread thisThread = new Thread(); Thread.Context* thisContext = &thisThread.m_main; assert( thisContext == thisThread.m_curr ); version( Windows ) { thisThread.m_addr = GetCurrentThreadId(); thisThread.m_hndl = GetCurrentThreadHandle(); thisContext.bstack = getStackBottom(); thisContext.tstack = thisContext.bstack; } else version( Posix ) { thisThread.m_addr = pthread_self(); thisContext.bstack = getStackBottom(); thisContext.tstack = thisContext.bstack; atomicStore!(MemoryOrder.raw)(thisThread.m_isRunning, true); } thisThread.m_isDaemon = true; thisThread.m_tlsgcdata = rt_tlsgc_init(); Thread.setThis( thisThread ); version( OSX ) { thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr ); assert( thisThread.m_tmach != thisThread.m_tmach.init ); } Thread.add( thisThread, false ); Thread.add( thisContext ); if( Thread.sm_main !is null ) multiThreadedFlag = true; return thisThread; } version( Windows ) { // NOTE: These calls are not safe on Posix systems that use signals to // perform garbage collection. The suspendHandler uses getThis() // to get the thread handle so getThis() must be a simple call. // Mutexes can't safely be acquired inside signal handlers, and // even if they could, the mutex needed (Thread.slock) is held by // thread_suspendAll(). So in short, these routines will remain // Windows-specific. If they are truly needed elsewhere, the // suspendHandler will need a way to call a version of getThis() // that only does the TLS lookup without the fancy fallback stuff. /// ditto extern (C) Thread thread_attachByAddr( ThreadID addr ) { return thread_attachByAddrB( addr, getThreadStackBottom( addr ) ); } /// ditto extern (C) Thread thread_attachByAddrB( ThreadID addr, void* bstack ) { GC.disable(); scope(exit) GC.enable(); if (auto t = thread_findByAddr(addr)) return t; Thread thisThread = new Thread(); Thread.Context* thisContext = &thisThread.m_main; assert( thisContext == thisThread.m_curr ); thisThread.m_addr = addr; thisContext.bstack = bstack; thisContext.tstack = thisContext.bstack; thisThread.m_isDaemon = true; if( addr == GetCurrentThreadId() ) { thisThread.m_hndl = GetCurrentThreadHandle(); thisThread.m_tlsgcdata = rt_tlsgc_init(); Thread.setThis( thisThread ); } else { thisThread.m_hndl = OpenThreadHandle( addr ); impersonate_thread(addr, { thisThread.m_tlsgcdata = rt_tlsgc_init(); Thread.setThis( thisThread ); }); } Thread.add( thisThread, false ); Thread.add( thisContext ); if( Thread.sm_main !is null ) multiThreadedFlag = true; return thisThread; } } /** * Deregisters the calling thread from use with the runtime. If this routine * is called for a thread which is not registered, the result is undefined. * * NOTE: This routine does not run thread-local static destructors when called. * If full functionality as a D thread is desired, the following function * must be called after thread_detachThis, particularly if the thread is * being detached at some indeterminate time before program termination: * * $(D extern(C) void rt_moduleTlsDtor();) */ extern (C) void thread_detachThis() nothrow { if (auto t = Thread.getThis()) Thread.remove(t); } /** * Deregisters the given thread from use with the runtime. If this routine * is called for a thread which is not registered, the result is undefined. * * NOTE: This routine does not run thread-local static destructors when called. * If full functionality as a D thread is desired, the following function * must be called by the detached thread, particularly if the thread is * being detached at some indeterminate time before program termination: * * $(D extern(C) void rt_moduleTlsDtor();) */ extern (C) void thread_detachByAddr( ThreadID addr ) { if( auto t = thread_findByAddr( addr ) ) Thread.remove( t ); } /// ditto extern (C) void thread_detachInstance( Thread t ) { Thread.remove( t ); } unittest { import core.sync.semaphore; auto sem = new Semaphore(); auto t = new Thread( { sem.notify(); Thread.sleep(100.msecs); }).start(); sem.wait(); // thread cannot be detached while being started thread_detachInstance(t); foreach (t2; Thread) assert(t !is t2); t.join(); } /** * Search the list of all threads for a thread with the given thread identifier. * * Params: * addr = The thread identifier to search for. * Returns: * The thread object associated with the thread identifier, null if not found. */ static Thread thread_findByAddr( ThreadID addr ) { Thread.slock.lock_nothrow(); scope(exit) Thread.slock.unlock_nothrow(); // also return just spawned thread so that // DLL_THREAD_ATTACH knows it's a D thread foreach (t; Thread.pAboutToStart[0 .. Thread.nAboutToStart]) if (t.m_addr == addr) return t; foreach (t; Thread) if (t.m_addr == addr) return t; return null; } /** * Sets the current thread to a specific reference. Only to be used * when dealing with externally-created threads (in e.g. C code). * The primary use of this function is when Thread.getThis() must * return a sensible value in, for example, TLS destructors. In * other words, don't touch this unless you know what you're doing. * * Params: * t = A reference to the current thread. May be null. */ extern (C) void thread_setThis(Thread t) { Thread.setThis(t); } /** * Joins all non-daemon threads that are currently running. This is done by * performing successive scans through the thread list until a scan consists * of only daemon threads. */ extern (C) void thread_joinAll() { Lagain: Thread.slock.lock_nothrow(); // wait for just spawned threads if (Thread.nAboutToStart) { Thread.slock.unlock_nothrow(); Thread.yield(); goto Lagain; } // join all non-daemon threads, the main thread is also a daemon auto t = Thread.sm_tbeg; while (t) { if (!t.isRunning) { auto tn = t.next; Thread.remove(t); t = tn; } else if (t.isDaemon) { t = t.next; } else { Thread.slock.unlock_nothrow(); t.join(); // might rethrow goto Lagain; // must restart iteration b/c of unlock } } Thread.slock.unlock_nothrow(); } /** * Performs intermediate shutdown of the thread module. */ shared static ~this() { // NOTE: The functionality related to garbage collection must be minimally // operable after this dtor completes. Therefore, only minimal // cleanup may occur. auto t = Thread.sm_tbeg; while (t) { auto tn = t.next; if (!t.isRunning) Thread.remove(t); t = tn; } } // Used for needLock below. private __gshared bool multiThreadedFlag = false; version (ExternStackShell) { extern(D) public void callWithStackShell(scope void delegate(void* sp) nothrow fn) nothrow; } else { // Calls the given delegate, passing the current thread's stack pointer to it. private void callWithStackShell(scope void delegate(void* sp) nothrow fn) nothrow in { assert(fn); } body { // The purpose of the 'shell' is to ensure all the registers get // put on the stack so they'll be scanned. We only need to push // the callee-save registers. void *sp = void; version (GNU) { __builtin_unwind_init(); sp = &sp; } else version (AsmX86_Posix) { size_t[3] regs = void; asm pure nothrow @nogc { mov [regs + 0 * 4], EBX; mov [regs + 1 * 4], ESI; mov [regs + 2 * 4], EDI; mov sp[EBP], ESP; } } else version (AsmX86_Windows) { size_t[3] regs = void; asm pure nothrow @nogc { mov [regs + 0 * 4], EBX; mov [regs + 1 * 4], ESI; mov [regs + 2 * 4], EDI; mov sp[EBP], ESP; } } else version (AsmX86_64_Posix) { size_t[5] regs = void; asm pure nothrow @nogc { mov [regs + 0 * 8], RBX; mov [regs + 1 * 8], R12; mov [regs + 2 * 8], R13; mov [regs + 3 * 8], R14; mov [regs + 4 * 8], R15; mov sp[RBP], RSP; } } else version (AsmX86_64_Windows) { size_t[7] regs = void; asm pure nothrow @nogc { mov [regs + 0 * 8], RBX; mov [regs + 1 * 8], RSI; mov [regs + 2 * 8], RDI; mov [regs + 3 * 8], R12; mov [regs + 4 * 8], R13; mov [regs + 5 * 8], R14; mov [regs + 6 * 8], R15; mov sp[RBP], RSP; } } else version (LDC) { version (PPC) { import ldc.llvmasm; // Nonvolatile registers, according to: // System V Application Binary Interface // PowerPC Processor Supplement, September 1995 size_t[18] regs = void; __asm("std 14, $0", "=*m", regs.ptr + 0); __asm("std 15, $0", "=*m", regs.ptr + 1); __asm("std 16, $0", "=*m", regs.ptr + 2); __asm("std 17, $0", "=*m", regs.ptr + 3); __asm("std 18, $0", "=*m", regs.ptr + 4); __asm("std 19, $0", "=*m", regs.ptr + 5); __asm("std 20, $0", "=*m", regs.ptr + 6); // Work around LLVM bug 21443 (http://llvm.org/bugs/show_bug.cgi?id=21443) // Because we clobber r0 a different register is choosen __asm("std 21, $0", "=*m,~{r0}", regs.ptr + 7); __asm("std 22, $0", "=*m", regs.ptr + 8); __asm("std 23, $0", "=*m", regs.ptr + 9); __asm("std 24, $0", "=*m", regs.ptr + 10); __asm("std 25, $0", "=*m", regs.ptr + 11); __asm("std 26, $0", "=*m", regs.ptr + 12); __asm("std 27, $0", "=*m", regs.ptr + 13); __asm("std 28, $0", "=*m", regs.ptr + 14); __asm("std 29, $0", "=*m", regs.ptr + 15); __asm("std 30, $0", "=*m", regs.ptr + 16); __asm("std 31, $0", "=*m", regs.ptr + 17); __asm("std 1, $0", "=*m", &sp); } else version (PPC64) { import ldc.llvmasm; // Nonvolatile registers, according to: // ELFv1: 64-bit PowerPC ELF ABI Supplement 1.9, July 2004 // ELFv2: Power Architecture, 64-Bit ELV V2 ABI Specification, // OpenPOWER ABI for Linux Supplement, July 2014 size_t[18] regs = void; __asm("std 14, $0", "=*m", regs.ptr + 0); __asm("std 15, $0", "=*m", regs.ptr + 1); __asm("std 16, $0", "=*m", regs.ptr + 2); __asm("std 17, $0", "=*m", regs.ptr + 3); __asm("std 18, $0", "=*m", regs.ptr + 4); __asm("std 19, $0", "=*m", regs.ptr + 5); __asm("std 20, $0", "=*m", regs.ptr + 6); // Work around LLVM bug 21443 (http://llvm.org/bugs/show_bug.cgi?id=21443) // Because we clobber r0 a different register is choosen __asm("std 21, $0", "=*m,~{r0}", regs.ptr + 7); __asm("std 22, $0", "=*m", regs.ptr + 8); __asm("std 23, $0", "=*m", regs.ptr + 9); __asm("std 24, $0", "=*m", regs.ptr + 10); __asm("std 25, $0", "=*m", regs.ptr + 11); __asm("std 26, $0", "=*m", regs.ptr + 12); __asm("std 27, $0", "=*m", regs.ptr + 13); __asm("std 28, $0", "=*m", regs.ptr + 14); __asm("std 29, $0", "=*m", regs.ptr + 15); __asm("std 30, $0", "=*m", regs.ptr + 16); __asm("std 31, $0", "=*m", regs.ptr + 17); __asm("std 1, $0", "=*m", &sp); } else version (AArch64) { import ldc.llvmasm; // Callee-save registers, x19-x28 according to AAPCS64, section // 5.1.1. Include x29 fp because it optionally can be a callee // saved reg size_t[11] regs = void; __asm("stp x19, x20, $0", "=*m", regs.ptr + 0); __asm("stp x21, x22, $0", "=*m", regs.ptr + 2); __asm("stp x23, x24, $0", "=*m", regs.ptr + 4); __asm("stp x25, x26, $0", "=*m", regs.ptr + 6); __asm("stp x27, x28, $0", "=*m", regs.ptr + 8); __asm("str x29, $0", "=*m", regs.ptr + 10); sp = __asm!(void*)("mov $0, sp", "=r"); } else version (ARM) { import ldc.llvmasm; // Callee-save registers, according to AAPCS, section 5.1.1. // arm and thumb2 instructions size_t[8] regs = void; __asm("stm $0, {r4-r11}", "r", regs.ptr); sp = __asm!(void*)("mov $0, sp", "=r"); } else version (MIPS64) { import ldc.llvmasm; // Callee-save registers, according to MIPSpro N32 ABI Handbook, // chapter 2, table 2-1. // FIXME: Should $28 (gp), $29 (sp) and $30 (s8) be saved, too? size_t[8] regs = void; __asm(`sd $$16, 0($0); sd $$17, 8($0); sd $$18, 16($0); sd $$19, 24($0); sd $$20, 32($0); sd $$21, 40($0); sd $$22, 48($0); sd $$23, 56($0)`, "r", regs.ptr); } else { static assert(false, "Architecture not supported."); } } else { static assert(false, "Architecture not supported."); } fn(sp); } } // Used for suspendAll/resumeAll below. private __gshared uint suspendDepth = 0; /** * Suspend the specified thread and load stack and register information for * use by thread_scanAll. If the supplied thread is the calling thread, * stack and register information will be loaded but the thread will not * be suspended. If the suspend operation fails and the thread is not * running then it will be removed from the global thread list, otherwise * an exception will be thrown. * * Params: * t = The thread to suspend. * * Throws: * ThreadError if the suspend operation fails for a running thread. * Returns: * Whether the thread is now suspended (true) or terminated (false). */ private bool suspend( Thread t ) nothrow { Duration waittime = dur!"usecs"(10); Lagain: if (!t.isRunning) { Thread.remove(t); return false; } else if (t.m_isInCriticalRegion) { Thread.criticalRegionLock.unlock_nothrow(); Thread.sleep(waittime); if (waittime < dur!"msecs"(10)) waittime *= 2; Thread.criticalRegionLock.lock_nothrow(); goto Lagain; } version( Windows ) { if( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF ) { if( !t.isRunning ) { Thread.remove( t ); return false; } onThreadError( "Unable to suspend thread" ); } CONTEXT context = void; context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; if( !GetThreadContext( t.m_hndl, &context ) ) onThreadError( "Unable to load thread context" ); version( X86 ) { if( !t.m_lock ) t.m_curr.tstack = cast(void*) context.Esp; // eax,ebx,ecx,edx,edi,esi,ebp,esp t.m_reg[0] = context.Eax; t.m_reg[1] = context.Ebx; t.m_reg[2] = context.Ecx; t.m_reg[3] = context.Edx; t.m_reg[4] = context.Edi; t.m_reg[5] = context.Esi; t.m_reg[6] = context.Ebp; t.m_reg[7] = context.Esp; } else version( X86_64 ) { if( !t.m_lock ) t.m_curr.tstack = cast(void*) context.Rsp; // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp t.m_reg[0] = context.Rax; t.m_reg[1] = context.Rbx; t.m_reg[2] = context.Rcx; t.m_reg[3] = context.Rdx; t.m_reg[4] = context.Rdi; t.m_reg[5] = context.Rsi; t.m_reg[6] = context.Rbp; t.m_reg[7] = context.Rsp; // r8,r9,r10,r11,r12,r13,r14,r15 t.m_reg[8] = context.R8; t.m_reg[9] = context.R9; t.m_reg[10] = context.R10; t.m_reg[11] = context.R11; t.m_reg[12] = context.R12; t.m_reg[13] = context.R13; t.m_reg[14] = context.R14; t.m_reg[15] = context.R15; } else { static assert(false, "Architecture not supported." ); } } else version( OSX ) { if( t.m_addr != pthread_self() && thread_suspend( t.m_tmach ) != KERN_SUCCESS ) { if( !t.isRunning ) { Thread.remove( t ); return false; } onThreadError( "Unable to suspend thread" ); } version( X86 ) { x86_thread_state32_t state = void; mach_msg_type_number_t count = x86_THREAD_STATE32_COUNT; if( thread_get_state( t.m_tmach, x86_THREAD_STATE32, &state, &count ) != KERN_SUCCESS ) onThreadError( "Unable to load thread state" ); if( !t.m_lock ) t.m_curr.tstack = cast(void*) state.esp; // eax,ebx,ecx,edx,edi,esi,ebp,esp t.m_reg[0] = state.eax; t.m_reg[1] = state.ebx; t.m_reg[2] = state.ecx; t.m_reg[3] = state.edx; t.m_reg[4] = state.edi; t.m_reg[5] = state.esi; t.m_reg[6] = state.ebp; t.m_reg[7] = state.esp; } else version( X86_64 ) { x86_thread_state64_t state = void; mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; if( thread_get_state( t.m_tmach, x86_THREAD_STATE64, &state, &count ) != KERN_SUCCESS ) onThreadError( "Unable to load thread state" ); if( !t.m_lock ) t.m_curr.tstack = cast(void*) state.rsp; // rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp t.m_reg[0] = state.rax; t.m_reg[1] = state.rbx; t.m_reg[2] = state.rcx; t.m_reg[3] = state.rdx; t.m_reg[4] = state.rdi; t.m_reg[5] = state.rsi; t.m_reg[6] = state.rbp; t.m_reg[7] = state.rsp; // r8,r9,r10,r11,r12,r13,r14,r15 t.m_reg[8] = state.r8; t.m_reg[9] = state.r9; t.m_reg[10] = state.r10; t.m_reg[11] = state.r11; t.m_reg[12] = state.r12; t.m_reg[13] = state.r13; t.m_reg[14] = state.r14; t.m_reg[15] = state.r15; } else { static assert(false, "Architecture not supported." ); } } else version( Posix ) { if( t.m_addr != pthread_self() ) { if( pthread_kill( t.m_addr, suspendSignalNumber ) != 0 ) { if( !t.isRunning ) { Thread.remove( t ); return false; } onThreadError( "Unable to suspend thread" ); } } else if( !t.m_lock ) { t.m_curr.tstack = getStackTop(); } } return true; } /** * Suspend all threads but the calling thread for "stop the world" garbage * collection runs. This function may be called multiple times, and must * be followed by a matching number of calls to thread_resumeAll before * processing is resumed. * * Throws: * ThreadError if the suspend operation fails for a running thread. */ extern (C) void thread_suspendAll() nothrow { // NOTE: We've got an odd chicken & egg problem here, because while the GC // is required to call thread_init before calling any other thread // routines, thread_init may allocate memory which could in turn // trigger a collection. Thus, thread_suspendAll, thread_scanAll, // and thread_resumeAll must be callable before thread_init // completes, with the assumption that no other GC memory has yet // been allocated by the system, and thus there is no risk of losing // data if the global thread list is empty. The check of // Thread.sm_tbeg below is done to ensure thread_init has completed, // and therefore that calling Thread.getThis will not result in an // error. For the short time when Thread.sm_tbeg is null, there is // no reason not to simply call the multithreaded code below, with // the expectation that the foreach loop will never be entered. if( !multiThreadedFlag && Thread.sm_tbeg ) { if( ++suspendDepth == 1 ) suspend( Thread.getThis() ); return; } Thread.slock.lock_nothrow(); { if( ++suspendDepth > 1 ) return; Thread.criticalRegionLock.lock_nothrow(); scope (exit) Thread.criticalRegionLock.unlock_nothrow(); size_t cnt; auto t = Thread.sm_tbeg; while (t) { auto tn = t.next; if (suspend(t)) ++cnt; t = tn; } version (OSX) {} else version (Posix) { // subtract own thread assert(cnt >= 1); --cnt; Lagain: // wait for semaphore notifications for (; cnt; --cnt) { while (sem_wait(&suspendCount) != 0) { if (errno != EINTR) onThreadError("Unable to wait for semaphore"); errno = 0; } } version (FreeBSD) { // avoid deadlocks, see Issue 13416 t = Thread.sm_tbeg; while (t) { auto tn = t.next; if (t.m_suspendagain && suspend(t)) ++cnt; t = tn; } if (cnt) goto Lagain; } } } } /** * Resume the specified thread and unload stack and register information. * If the supplied thread is the calling thread, stack and register * information will be unloaded but the thread will not be resumed. If * the resume operation fails and the thread is not running then it will * be removed from the global thread list, otherwise an exception will be * thrown. * * Params: * t = The thread to resume. * * Throws: * ThreadError if the resume fails for a running thread. */ private void resume( Thread t ) nothrow { version( Windows ) { if( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF ) { if( !t.isRunning ) { Thread.remove( t ); return; } onThreadError( "Unable to resume thread" ); } if( !t.m_lock ) t.m_curr.tstack = t.m_curr.bstack; t.m_reg[0 .. $] = 0; } else version( OSX ) { if( t.m_addr != pthread_self() && thread_resume( t.m_tmach ) != KERN_SUCCESS ) { if( !t.isRunning ) { Thread.remove( t ); return; } onThreadError( "Unable to resume thread" ); } if( !t.m_lock ) t.m_curr.tstack = t.m_curr.bstack; t.m_reg[0 .. $] = 0; } else version( Posix ) { if( t.m_addr != pthread_self() ) { if( pthread_kill( t.m_addr, resumeSignalNumber ) != 0 ) { if( !t.isRunning ) { Thread.remove( t ); return; } onThreadError( "Unable to resume thread" ); } } else if( !t.m_lock ) { t.m_curr.tstack = t.m_curr.bstack; } } } /** * Resume all threads but the calling thread for "stop the world" garbage * collection runs. This function must be called once for each preceding * call to thread_suspendAll before the threads are actually resumed. * * In: * This routine must be preceded by a call to thread_suspendAll. * * Throws: * ThreadError if the resume operation fails for a running thread. */ extern (C) void thread_resumeAll() nothrow in { assert( suspendDepth > 0 ); } body { // NOTE: See thread_suspendAll for the logic behind this. if( !multiThreadedFlag && Thread.sm_tbeg ) { if( --suspendDepth == 0 ) resume( Thread.getThis() ); return; } scope(exit) Thread.slock.unlock_nothrow(); { if( --suspendDepth > 0 ) return; for( Thread t = Thread.sm_tbeg; t; t = t.next ) { // NOTE: We do not need to care about critical regions at all // here. thread_suspendAll takes care of everything. resume( t ); } } } /** * Indicates the kind of scan being performed by $(D thread_scanAllType). */ enum ScanType { stack, /// The stack and/or registers are being scanned. tls, /// TLS data is being scanned. } alias void delegate(void*, void*) nothrow ScanAllThreadsFn; /// The scanning function. alias void delegate(ScanType, void*, void*) nothrow ScanAllThreadsTypeFn; /// ditto /** * The main entry point for garbage collection. The supplied delegate * will be passed ranges representing both stack and register values. * * Params: * scan = The scanner function. It should scan from p1 through p2 - 1. * * In: * This routine must be preceded by a call to thread_suspendAll. */ extern (C) void thread_scanAllType( scope ScanAllThreadsTypeFn scan ) nothrow in { assert( suspendDepth > 0 ); } body { callWithStackShell(sp => scanAllTypeImpl(scan, sp)); } private void scanAllTypeImpl( scope ScanAllThreadsTypeFn scan, void* curStackTop ) nothrow { Thread thisThread = null; void* oldStackTop = null; if( Thread.sm_tbeg ) { thisThread = Thread.getThis(); if( !thisThread.m_lock ) { oldStackTop = thisThread.m_curr.tstack; thisThread.m_curr.tstack = curStackTop; } } scope( exit ) { if( Thread.sm_tbeg ) { if( !thisThread.m_lock ) { thisThread.m_curr.tstack = oldStackTop; } } } // NOTE: Synchronizing on Thread.slock is not needed because this // function may only be called after all other threads have // been suspended from within the same lock. if (Thread.nAboutToStart) scan(ScanType.stack, Thread.pAboutToStart, Thread.pAboutToStart + Thread.nAboutToStart); for( Thread.Context* c = Thread.sm_cbeg; c; c = c.next ) { version( StackGrowsDown ) { // NOTE: We can't index past the bottom of the stack // so don't do the "+1" for StackGrowsDown. if( c.tstack && c.tstack < c.bstack ) scan( ScanType.stack, c.tstack, c.bstack ); } else { if( c.bstack && c.bstack < c.tstack ) scan( ScanType.stack, c.bstack, c.tstack + 1 ); } } for( Thread t = Thread.sm_tbeg; t; t = t.next ) { version( Windows ) { // Ideally, we'd pass ScanType.regs or something like that, but this // would make portability annoying because it only makes sense on Windows. scan( ScanType.stack, t.m_reg.ptr, t.m_reg.ptr + t.m_reg.length ); } if (t.m_tlsgcdata !is null) rt_tlsgc_scan(t.m_tlsgcdata, (p1, p2) => scan(ScanType.tls, p1, p2)); } } /** * The main entry point for garbage collection. The supplied delegate * will be passed ranges representing both stack and register values. * * Params: * scan = The scanner function. It should scan from p1 through p2 - 1. * * In: * This routine must be preceded by a call to thread_suspendAll. */ extern (C) void thread_scanAll( scope ScanAllThreadsFn scan ) nothrow { thread_scanAllType((type, p1, p2) => scan(p1, p2)); } /** * Signals that the code following this call is a critical region. Any code in * this region must finish running before the calling thread can be suspended * by a call to thread_suspendAll. * * This function is, in particular, meant to help maintain garbage collector * invariants when a lock is not used. * * A critical region is exited with thread_exitCriticalRegion. * * $(RED Warning): * Using critical regions is extremely error-prone. For instance, using locks * inside a critical region can easily result in a deadlock when another thread * holding the lock already got suspended. * * The term and concept of a 'critical region' comes from * $(LINK2 https://github.com/mono/mono/blob/521f4a198e442573c400835ef19bbb36b60b0ebb/mono/metadata/sgen-gc.h#L925 Mono's SGen garbage collector). * * In: * The calling thread must be attached to the runtime. */ extern (C) void thread_enterCriticalRegion() in { assert(Thread.getThis()); } body { synchronized (Thread.criticalRegionLock) Thread.getThis().m_isInCriticalRegion = true; } /** * Signals that the calling thread is no longer in a critical region. Following * a call to this function, the thread can once again be suspended. * * In: * The calling thread must be attached to the runtime. */ extern (C) void thread_exitCriticalRegion() in { assert(Thread.getThis()); } body { synchronized (Thread.criticalRegionLock) Thread.getThis().m_isInCriticalRegion = false; } /** * Returns true if the current thread is in a critical region; otherwise, false. * * In: * The calling thread must be attached to the runtime. */ extern (C) bool thread_inCriticalRegion() in { assert(Thread.getThis()); } body { synchronized (Thread.criticalRegionLock) return Thread.getThis().m_isInCriticalRegion; } /** * A callback for thread errors in D during collections. Since an allocation is not possible * a preallocated ThreadError will be used as the Error instance * * Throws: * ThreadError. */ private void onThreadError(string msg = null, Throwable next = null) nothrow { __gshared ThreadError error = new ThreadError(null); error.msg = msg; error.next = next; import core.exception : SuppressTraceInfo; error.info = SuppressTraceInfo.instance; throw error; } unittest { assert(!thread_inCriticalRegion()); { thread_enterCriticalRegion(); scope (exit) thread_exitCriticalRegion(); assert(thread_inCriticalRegion()); } assert(!thread_inCriticalRegion()); } unittest { // NOTE: This entire test is based on the assumption that no // memory is allocated after the child thread is // started. If an allocation happens, a collection could // trigger, which would cause the synchronization below // to cause a deadlock. // NOTE: DO NOT USE LOCKS IN CRITICAL REGIONS IN NORMAL CODE. import core.sync.semaphore; auto sema = new Semaphore(), semb = new Semaphore(); auto thr = new Thread( { thread_enterCriticalRegion(); assert(thread_inCriticalRegion()); sema.notify(); semb.wait(); assert(thread_inCriticalRegion()); thread_exitCriticalRegion(); assert(!thread_inCriticalRegion()); sema.notify(); semb.wait(); assert(!thread_inCriticalRegion()); }); thr.start(); sema.wait(); synchronized (Thread.criticalRegionLock) assert(thr.m_isInCriticalRegion); semb.notify(); sema.wait(); synchronized (Thread.criticalRegionLock) assert(!thr.m_isInCriticalRegion); semb.notify(); thr.join(); } unittest { import core.sync.semaphore; shared bool inCriticalRegion; auto sema = new Semaphore(), semb = new Semaphore(); auto thr = new Thread( { thread_enterCriticalRegion(); inCriticalRegion = true; sema.notify(); semb.wait(); Thread.sleep(dur!"msecs"(1)); inCriticalRegion = false; thread_exitCriticalRegion(); }); thr.start(); sema.wait(); assert(inCriticalRegion); semb.notify(); thread_suspendAll(); assert(!inCriticalRegion); thread_resumeAll(); } /** * Indicates whether an address has been marked by the GC. */ enum IsMarked : int { no, /// Address is not marked. yes, /// Address is marked. unknown, /// Address is not managed by the GC. } alias int delegate( void* addr ) nothrow IsMarkedDg; /// The isMarked callback function. /** * This routine allows the runtime to process any special per-thread handling * for the GC. This is needed for taking into account any memory that is * referenced by non-scanned pointers but is about to be freed. That currently * means the array append cache. * * Params: * isMarked = The function used to check if $(D addr) is marked. * * In: * This routine must be called just prior to resuming all threads. */ extern(C) void thread_processGCMarks( scope IsMarkedDg isMarked ) nothrow { for( Thread t = Thread.sm_tbeg; t; t = t.next ) { /* Can be null if collection was triggered between adding a * thread and calling rt_tlsgc_init. */ if (t.m_tlsgcdata !is null) rt_tlsgc_processGCMarks(t.m_tlsgcdata, isMarked); } } extern (C) { nothrow: version (CRuntime_Glibc) int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr); version (FreeBSD) int pthread_attr_get_np(pthread_t thread, pthread_attr_t* attr); version (Solaris) int thr_stksegment(stack_t* stk); version (CRuntime_Bionic) int pthread_getattr_np(pthread_t thid, pthread_attr_t* attr); } private void* getStackTop() nothrow { version (LDC) { import ldc.llvmasm; /* The inline assembler is written in a style that the code can be * inlined. * The use of intrinsic llvm_frameaddress is a reasonable default for * cpu architectures without assembler support from LLVM. Because of * the slightly different meaning the code must not be inlined. */ version (X86) { return __asm!(void *)("movl %esp, $0", "=r"); } else version (X86_64) { return __asm!(void *)("movq %rsp, $0", "=r"); } else version (AArch64) { return __asm!(void *)("mov $0, sp", "=r"); } else version (ARM) { return __asm!(void *)("mov $0, sp", "=r"); } else version (PPC) { return __asm!(void *)("mr $0, 1", "=r"); } else version (PPC64) { return __asm!(void *)("mr $0, 1", "=r"); } else version (MIPS) { return __asm!(void *)("move $0, $$sp", "=r"); } else version (MIPS64) { return __asm!(void *)("move $0, $$sp", "=r"); } else { import ldc.intrinsics; pragma(LDC_never_inline); return llvm_frameaddress(0); } } else version (D_InlineAsm_X86) asm pure nothrow @nogc { naked; mov EAX, ESP; ret; } else version (D_InlineAsm_X86_64) asm pure nothrow @nogc { naked; mov RAX, RSP; ret; } else version (GNU) return __builtin_frame_address(0); else static assert(false, "Architecture not supported."); } private void* getStackBottom() nothrow { version (Windows) { version (LDC) { // Use LLVM inline assembler to enable inlining. import ldc.llvmasm; version (X86) { return __asm!(void*)("movl %fs:(4), $0", "=r"); } else version (X86_64) { return __asm!(void*)("movq %gs:0($0), %rax", "={rax},r", 8); } else static assert(false, "Architecture not supported."); } else { version (D_InlineAsm_X86) asm pure nothrow @nogc { naked; mov EAX, FS:4; ret; } else version(D_InlineAsm_X86_64) asm pure nothrow @nogc { naked; mov RAX, 8; mov RAX, GS:[RAX]; ret; } else static assert(false, "Architecture not supported."); } } else version (OSX) { import core.sys.osx.pthread; return pthread_get_stackaddr_np(pthread_self()); } else version (CRuntime_Glibc) { pthread_attr_t attr; void* addr; size_t size; pthread_getattr_np(pthread_self(), &attr); pthread_attr_getstack(&attr, &addr, &size); pthread_attr_destroy(&attr); return addr + size; } else version (FreeBSD) { pthread_attr_t attr; void* addr; size_t size; pthread_attr_init(&attr); pthread_attr_get_np(pthread_self(), &attr); pthread_attr_getstack(&attr, &addr, &size); pthread_attr_destroy(&attr); return addr + size; } else version (Solaris) { stack_t stk; thr_stksegment(&stk); return stk.ss_sp; } else version (CRuntime_Bionic) { pthread_attr_t attr; void* addr; size_t size; pthread_getattr_np(pthread_self(), &attr); pthread_attr_getstack(&attr, &addr, &size); pthread_attr_destroy(&attr); return addr + size; } else static assert(false, "Platform not supported."); } /** * Returns the stack top of the currently active stack within the calling * thread. * * In: * The calling thread must be attached to the runtime. * * Returns: * The address of the stack top. */ extern (C) void* thread_stackTop() nothrow in { // Not strictly required, but it gives us more flexibility. assert(Thread.getThis()); } body { return getStackTop(); } /** * Returns the stack bottom of the currently active stack within the calling * thread. * * In: * The calling thread must be attached to the runtime. * * Returns: * The address of the stack bottom. */ extern (C) void* thread_stackBottom() nothrow in { assert(Thread.getThis()); } body { return Thread.getThis().topContext().bstack; } /////////////////////////////////////////////////////////////////////////////// // Thread Group /////////////////////////////////////////////////////////////////////////////// /** * This class is intended to simplify certain common programming techniques. */ class ThreadGroup { /** * Creates and starts a new Thread object that executes fn and adds it to * the list of tracked threads. * * Params: * fn = The thread function. * * Returns: * A reference to the newly created thread. */ final Thread create( void function() fn ) { Thread t = new Thread( fn ).start(); synchronized( this ) { m_all[t] = t; } return t; } /** * Creates and starts a new Thread object that executes dg and adds it to * the list of tracked threads. * * Params: * dg = The thread function. * * Returns: * A reference to the newly created thread. */ final Thread create( void delegate() dg ) { Thread t = new Thread( dg ).start(); synchronized( this ) { m_all[t] = t; } return t; } /** * Add t to the list of tracked threads if it is not already being tracked. * * Params: * t = The thread to add. * * In: * t must not be null. */ final void add( Thread t ) in { assert( t ); } body { synchronized( this ) { m_all[t] = t; } } /** * Removes t from the list of tracked threads. No operation will be * performed if t is not currently being tracked by this object. * * Params: * t = The thread to remove. * * In: * t must not be null. */ final void remove( Thread t ) in { assert( t ); } body { synchronized( this ) { m_all.remove( t ); } } /** * Operates on all threads currently tracked by this object. */ final int opApply( scope int delegate( ref Thread ) dg ) { synchronized( this ) { int ret = 0; // NOTE: This loop relies on the knowledge that m_all uses the // Thread object for both the key and the mapped value. foreach( Thread t; m_all.keys ) { ret = dg( t ); if( ret ) break; } return ret; } } /** * Iteratively joins all tracked threads. This function will block add, * remove, and opApply until it completes. * * Params: * rethrow = Rethrow any unhandled exception which may have caused the * current thread to terminate. * * Throws: * Any exception not handled by the joined threads. */ final void joinAll( bool rethrow = true ) { synchronized( this ) { // NOTE: This loop relies on the knowledge that m_all uses the // Thread object for both the key and the mapped value. foreach( Thread t; m_all.keys ) { t.join( rethrow ); } } } private: Thread[Thread] m_all; } /////////////////////////////////////////////////////////////////////////////// // Fiber Platform Detection and Memory Allocation /////////////////////////////////////////////////////////////////////////////// private { version( D_InlineAsm_X86 ) { version( Windows ) version = AsmX86_Windows; else version( Posix ) version = AsmX86_Posix; version( OSX ) version = AlignFiberStackTo16Byte; } else version( D_InlineAsm_X86_64 ) { version( Windows ) { version = AsmX86_64_Windows; version = AlignFiberStackTo16Byte; } else version( Posix ) { version = AsmX86_64_Posix; version = AlignFiberStackTo16Byte; } } else version( PPC ) { version( Posix ) { version = AsmPPC_Posix; version = AsmExternal; } } else version( PPC64 ) { version( Posix ) { version = AsmPPC64_Posix; version = AsmExternal; version = AlignFiberStackTo16Byte; } } else version( MIPS_O32 ) { version( Posix ) { version = AsmMIPS_O32_Posix; version = AsmExternal; } } else version( AArch64 ) { version( Posix ) { version = AsmAArch64_Posix; version = AsmExternal; version = AlignFiberStackTo16Byte; } } else version( ARM ) { version( Posix ) { version = AsmARM_Posix; version = AsmExternal; } } version( Posix ) { import core.sys.posix.unistd; // for sysconf version( AsmX86_Windows ) {} else version( AsmX86_Posix ) {} else version( AsmX86_64_Windows ) {} else version( AsmX86_64_Posix ) {} else version( AsmExternal ) {} else { // NOTE: The ucontext implementation requires architecture specific // data definitions to operate so testing for it must be done // by checking for the existence of ucontext_t rather than by // a version identifier. Please note that this is considered // an obsolescent feature according to the POSIX spec, so a // custom solution is still preferred. import core.sys.posix.ucontext; } } static immutable size_t PAGESIZE; version (Posix) static immutable size_t PTHREAD_STACK_MIN; } shared static this() { version (Windows) { SYSTEM_INFO info; GetSystemInfo(&info); PAGESIZE = info.dwPageSize; assert(PAGESIZE < int.max); } else version (Posix) { PAGESIZE = cast(size_t)sysconf(_SC_PAGESIZE); PTHREAD_STACK_MIN = cast(size_t)sysconf(_SC_THREAD_STACK_MIN); } else { static assert(0, "unimplemented"); } } /////////////////////////////////////////////////////////////////////////////// // Fiber Entry Point and Context Switch /////////////////////////////////////////////////////////////////////////////// private { extern (C) void fiber_entryPoint() { Fiber obj = Fiber.getThis(); assert( obj ); assert( Thread.getThis().m_curr is obj.m_ctxt ); atomicStore!(MemoryOrder.raw)(*cast(shared)&Thread.getThis().m_lock, false); obj.m_ctxt.tstack = obj.m_ctxt.bstack; obj.m_state = Fiber.State.EXEC; try { obj.run(); } catch( Throwable t ) { obj.m_unhandled = t; } static if( __traits( compiles, ucontext_t ) ) obj.m_ucur = &obj.m_utxt; obj.m_state = Fiber.State.TERM; obj.switchOut(); } // Look above the definition of 'class Fiber' for some information about the implementation of this routine version( AsmExternal ) extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow; else extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow { // NOTE: The data pushed and popped in this routine must match the // default stack created by Fiber.initStack or the initial // switch into a new context will fail. version( AsmX86_Windows ) { asm pure nothrow @nogc { naked; // save current stack state push EBP; mov EBP, ESP; push EDI; push ESI; push EBX; push dword ptr FS:[0]; push dword ptr FS:[4]; push dword ptr FS:[8]; push EAX; // store oldp again with more accurate address mov EAX, dword ptr 8[EBP]; mov [EAX], ESP; // load newp to begin context switch mov ESP, dword ptr 12[EBP]; // load saved state from new stack pop EAX; pop dword ptr FS:[8]; pop dword ptr FS:[4]; pop dword ptr FS:[0]; pop EBX; pop ESI; pop EDI; pop EBP; // 'return' to complete switch pop ECX; jmp ECX; } } else version( AsmX86_64_Windows ) { asm pure nothrow @nogc { naked; // save current stack state // NOTE: When changing the layout of registers on the stack, // make sure that the XMM registers are still aligned. // On function entry, the stack is guaranteed to not // be aligned to 16 bytes because of the return address // on the stack. push RBP; mov RBP, RSP; push R12; push R13; push R14; push R15; push RDI; push RSI; // 7 registers = 56 bytes; stack is now aligned to 16 bytes sub RSP, 160; movdqa [RSP + 144], XMM6; movdqa [RSP + 128], XMM7; movdqa [RSP + 112], XMM8; movdqa [RSP + 96], XMM9; movdqa [RSP + 80], XMM10; movdqa [RSP + 64], XMM11; movdqa [RSP + 48], XMM12; movdqa [RSP + 32], XMM13; movdqa [RSP + 16], XMM14; movdqa [RSP], XMM15; push RBX; xor RAX,RAX; push qword ptr GS:[RAX]; push qword ptr GS:8[RAX]; push qword ptr GS:16[RAX]; // store oldp mov [RCX], RSP; // load newp to begin context switch mov RSP, RDX; // load saved state from new stack pop qword ptr GS:16[RAX]; pop qword ptr GS:8[RAX]; pop qword ptr GS:[RAX]; pop RBX; movdqa XMM15, [RSP]; movdqa XMM14, [RSP + 16]; movdqa XMM13, [RSP + 32]; movdqa XMM12, [RSP + 48]; movdqa XMM11, [RSP + 64]; movdqa XMM10, [RSP + 80]; movdqa XMM9, [RSP + 96]; movdqa XMM8, [RSP + 112]; movdqa XMM7, [RSP + 128]; movdqa XMM6, [RSP + 144]; add RSP, 160; pop RSI; pop RDI; pop R15; pop R14; pop R13; pop R12; pop RBP; // 'return' to complete switch pop RCX; jmp RCX; } } else version( AsmX86_Posix ) { asm pure nothrow @nogc { naked; // save current stack state push EBP; mov EBP, ESP; push EDI; push ESI; push EBX; push EAX; // store oldp again with more accurate address mov EAX, dword ptr 8[EBP]; mov [EAX], ESP; // load newp to begin context switch mov ESP, dword ptr 12[EBP]; // load saved state from new stack pop EAX; pop EBX; pop ESI; pop EDI; pop EBP; // 'return' to complete switch pop ECX; jmp ECX; } } else version( AsmX86_64_Posix ) { asm pure nothrow @nogc { naked; // save current stack state push RBP; mov RBP, RSP; push RBX; push R12; push R13; push R14; push R15; // store oldp mov [RDI], RSP; // load newp to begin context switch mov RSP, RSI; // load saved state from new stack pop R15; pop R14; pop R13; pop R12; pop RBX; pop RBP; // 'return' to complete switch pop RCX; jmp RCX; } } else static if( __traits( compiles, ucontext_t ) ) { Fiber cfib = Fiber.getThis(); void* ucur = cfib.m_ucur; *oldp = &ucur; swapcontext( **(cast(ucontext_t***) oldp), *(cast(ucontext_t**) newp) ); } else static assert(0, "Not implemented"); } } // Detect when a Fiber migrates between Threads for systems in which it may be // unsafe to do so. A unittest below helps decide if CheckFiberMigration // should be set for your system. version( LDC ) { version( OSX ) { version( ARM ) version = CheckFiberMigration; version( AArch64 ) version = CheckFiberMigration; version( X86 ) version = CheckFiberMigration; version( X86_64 ) version = CheckFiberMigration; } } // Fiber support for SjLj style exceptions // // Exception handling based on setjmp/longjmp tracks the unwind points with a // linked list stack managed by _Unwind_SjLj_Register and // _Unwind_SjLj_Unregister. In the context of Fibers, the stack needs to be // Fiber local, otherwise unwinding could weave through functions on other // Fibers as opposed to just the current Fiber. The solution is to give each // Fiber a m_sjljExStackTop. // // Two implementations known to have this SjLj stack design are GCC's libgcc // and darwin libunwind for ARM (iOS). Functions to get/set the current SjLj // stack are named differently in each implmentation: // // https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-sjlj.c // // libgcc // struct SjLj_Function_Context* _Unwind_SjLj_GetContext(void) // void _Unwind_SjLj_SetContext(struct SjLj_Function_Context *fc) // // http://www.opensource.apple.com/source/libunwind/libunwind-30/src/Unwind-sjlj.c // // darwin (OS X) // _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack(); // void __Unwind_SjLj_SetTopOfFunctionStack(_Unwind_FunctionContext* fc); // // These functions are not extern but if we peek at the implementations it // turns out that _Unwind_SjLj_Register and _Unwind_SjLj_Unregister in both // libraries will manipulate the stack as we need. version( GNU_SjLj_Exceptions ) version = SjLj_Exceptions; version( iOS ) version( ARM ) version = SjLj_Exceptions; version( SjLj_Exceptions ) private { // libgcc struct SjLj_Function_Context and darwin struct // _Unwind_FunctionContext have same initial layout so can get away with // one type to mimic header of both here. struct SjLjFuncContext { SjLjFuncContext* prev; // rest of this struc we don't care about in swapSjLjStackTop below. } extern(C) @nogc nothrow { void _Unwind_SjLj_Register(SjLjFuncContext* fc); void _Unwind_SjLj_Unregister(SjLjFuncContext* fc); } // Swap in a new stack top, returning the previous one SjLjFuncContext* swapSjLjStackTop(SjLjFuncContext* newtop) @nogc nothrow { // register a dummy context to retrieve stack top, then plop our new // stack top in its place before unregistering, making it the new top. SjLjFuncContext fc; _Unwind_SjLj_Register(&fc); SjLjFuncContext* prevtop = fc.prev; fc.prev = newtop; _Unwind_SjLj_Unregister(&fc); return prevtop; } } /////////////////////////////////////////////////////////////////////////////// // Fiber /////////////////////////////////////////////////////////////////////////////// /* * Documentation of Fiber internals: * * The main routines to implement when porting Fibers to new architectures are * fiber_switchContext and initStack. Some version constants have to be defined * for the new platform as well, search for "Fiber Platform Detection and Memory Allocation". * * Fibers are based on a concept called 'Context'. A Context describes the execution * state of a Fiber or main thread which is fully described by the stack, some * registers and a return address at which the Fiber/Thread should continue executing. * Please note that not only each Fiber has a Context, but each thread also has got a * Context which describes the threads stack and state. If you call Fiber fib; fib.call * the first time in a thread you switch from Threads Context into the Fibers Context. * If you call fib.yield in that Fiber you switch out of the Fibers context and back * into the Thread Context. (However, this is not always the case. You can call a Fiber * from within another Fiber, then you switch Contexts between the Fibers and the Thread * Context is not involved) * * In all current implementations the registers and the return address are actually * saved on a Contexts stack. * * The fiber_switchContext routine has got two parameters: * void** a: This is the _location_ where we have to store the current stack pointer, * the stack pointer of the currently executing Context (Fiber or Thread). * void* b: This is the pointer to the stack of the Context which we want to switch into. * Note that we get the same pointer here as the one we stored into the void** a * in a previous call to fiber_switchContext. * * In the simplest case, a fiber_switchContext rountine looks like this: * fiber_switchContext: * push {return Address} * push {registers} * copy {stack pointer} into {location pointed to by a} * //We have now switch to the stack of a different Context! * copy {b} into {stack pointer} * pop {registers} * pop {return Address} * jump to {return Address} * * The GC uses the value returned in parameter a to scan the Fibers stack. It scans from * the stack base to that value. As the GC dislikes false pointers we can actually optimize * this a little: By storing registers which can not contain references to memory managed * by the GC outside of the region marked by the stack base pointer and the stack pointer * saved in fiber_switchContext we can prevent the GC from scanning them. * Such registers are usually floating point registers and the return address. In order to * implement this, we return a modified stack pointer from fiber_switchContext. However, * we have to remember that when we restore the registers from the stack! * * --------------------------- <= Stack Base * | Frame | <= Many other stack frames * | Frame | * |-------------------------| <= The last stack frame. This one is created by fiber_switchContext * | registers with pointers | * | | <= Stack pointer. GC stops scanning here * | return address | * |floating point registers | * --------------------------- <= Real Stack End * * fiber_switchContext: * push {registers with pointers} * copy {stack pointer} into {location pointed to by a} * push {return Address} * push {Floating point registers} * //We have now switch to the stack of a different Context! * copy {b} into {stack pointer} * //We now have to adjust the stack pointer to point to 'Real Stack End' so we can pop * //the FP registers * //+ or - depends on if your stack grows downwards or upwards * {stack pointer} = {stack pointer} +- ({FPRegisters}.sizeof + {return address}.sizeof} * pop {Floating point registers} * pop {return Address} * pop {registers with pointers} * jump to {return Address} * * So the question now is which registers need to be saved? This depends on the specific * architecture ABI of course, but here are some general guidelines: * - If a register is callee-save (if the callee modifies the register it must saved and * restored by the callee) it needs to be saved/restored in switchContext * - If a register is caller-save it needn't be saved/restored. (Calling fiber_switchContext * is a function call and the compiler therefore already must save these registers before * calling fiber_switchContext) * - Argument registers used for passing parameters to functions needn't be saved/restored * - The return register needn't be saved/restored (fiber_switchContext hasn't got a return type) * - All scratch registers needn't be saved/restored * - The link register usually needn't be saved/restored (but sometimes it must be cleared - * see below for details) * - The frame pointer register - if it exists - is usually callee-save * - All current implementations do not save control registers * * What happens on the first switch into a Fiber? We never saved a state for this fiber before, * but the initial state is prepared in the initStack routine. (This routine will also be called * when a Fiber is being resetted). initStack must produce exactly the same stack layout as the * part of fiber_switchContext which saves the registers. Pay special attention to set the stack * pointer correctly if you use the GC optimization mentioned before. the return Address saved in * initStack must be the address of fiber_entrypoint. * * There's now a small but important difference between the first context switch into a fiber and * further context switches. On the first switch, Fiber.call is used and the returnAddress in * fiber_switchContext will point to fiber_entrypoint. The important thing here is that this jump * is a _function call_, we call fiber_entrypoint by jumping before it's function prologue. On later * calls, the user used yield() in a function, and therefore the return address points into a user * function, after the yield call. So here the jump in fiber_switchContext is a _function return_, * not a function call! * * The most important result of this is that on entering a function, i.e. fiber_entrypoint, we * would have to provide a return address / set the link register once fiber_entrypoint * returns. Now fiber_entrypoint does never return and therefore the actual value of the return * address / link register is never read/used and therefore doesn't matter. When fiber_switchContext * performs a _function return_ the value in the link register doesn't matter either. * However, the link register will still be saved to the stack in fiber_entrypoint and some * exception handling / stack unwinding code might read it from this stack location and crash. * The exact solution depends on your architecture, but see the ARM implementation for a way * to deal with this issue. * * The ARM implementation is meant to be used as a kind of documented example implementation. * Look there for a concrete example. * * FIXME: fiber_entrypoint might benefit from a @noreturn attribute, but D doesn't have one. */ /** * This class provides a cooperative concurrency mechanism integrated with the * threading and garbage collection functionality. Calling a fiber may be * considered a blocking operation that returns when the fiber yields (via * Fiber.yield()). Execution occurs within the context of the calling thread * so synchronization is not necessary to guarantee memory visibility so long * as the same thread calls the fiber each time. Please note that there is no * requirement that a fiber be bound to one specific thread. Rather, fibers * may be freely passed between threads so long as they are not currently * executing. Like threads, a new fiber thread may be created using either * derivation or composition, as in the following example. * * Warning: * Status registers are not saved by the current implementations. This means * floating point exception status bits (overflow, divide by 0), rounding mode * and similar stuff is set per-thread, not per Fiber! * * Warning: * On ARM FPU registers are not saved if druntime was compiled as ARM_SoftFloat. * If such a build is used on a ARM_SoftFP system which actually has got a FPU * and other libraries are using the FPU registers (other code is compiled * as ARM_SoftFP) this can cause problems. Druntime must be compiled as * ARM_SoftFP in this case. * * Example: * ---------------------------------------------------------------------- * * class DerivedFiber : Fiber * { * this() * { * super( &run ); * } * * private : * void run() * { * printf( "Derived fiber running.\n" ); * } * } * * void fiberFunc() * { * printf( "Composed fiber running.\n" ); * Fiber.yield(); * printf( "Composed fiber running.\n" ); * } * * // create instances of each type * Fiber derived = new DerivedFiber(); * Fiber composed = new Fiber( &fiberFunc ); * * // call both fibers once * derived.call(); * composed.call(); * printf( "Execution returned to calling context.\n" ); * composed.call(); * * // since each fiber has run to completion, each should have state TERM * assert( derived.state == Fiber.State.TERM ); * assert( composed.state == Fiber.State.TERM ); * * ---------------------------------------------------------------------- * * Authors: Based on a design by Mikola Lysenko. */ class Fiber { /////////////////////////////////////////////////////////////////////////// // Initialization /////////////////////////////////////////////////////////////////////////// /** * Initializes a fiber object which is associated with a static * D function. * * Params: * fn = The fiber function. * sz = The stack size for this fiber. * * In: * fn must not be null. */ this( void function() fn, size_t sz = PAGESIZE*4 ) nothrow in { assert( fn ); } body { allocStack( sz ); reset( fn ); } /** * Initializes a fiber object which is associated with a dynamic * D function. * * Params: * dg = The fiber function. * sz = The stack size for this fiber. * * In: * dg must not be null. */ this( void delegate() dg, size_t sz = PAGESIZE*4 ) nothrow in { assert( dg ); } body { allocStack( sz ); reset( dg ); } /** * Cleans up any remaining resources used by this object. */ ~this() nothrow { // NOTE: A live reference to this object will exist on its associated // stack from the first time its call() method has been called // until its execution completes with State.TERM. Thus, the only // times this dtor should be called are either if the fiber has // terminated (and therefore has no active stack) or if the user // explicitly deletes this object. The latter case is an error // but is not easily tested for, since State.HOLD may imply that // the fiber was just created but has never been run. There is // not a compelling case to create a State.INIT just to offer a // means of ensuring the user isn't violating this object's // contract, so for now this requirement will be enforced by // documentation only. freeStack(); } /////////////////////////////////////////////////////////////////////////// // General Actions /////////////////////////////////////////////////////////////////////////// /** * Transfers execution to this fiber object. The calling context will be * suspended until the fiber calls Fiber.yield() or until it terminates * via an unhandled exception. * * Params: * rethrow = Rethrow any unhandled exception which may have caused this * fiber to terminate. * * In: * This fiber must be in state HOLD. * * Throws: * Any exception not handled by the joined thread. * * Returns: * Any exception not handled by this fiber if rethrow = false, null * otherwise. */ final Throwable call( Rethrow rethrow = Rethrow.yes ) { return rethrow ? call!(Rethrow.yes)() : call!(Rethrow.no); } /// ditto final Throwable call( Rethrow rethrow )() { callImpl(); if( m_unhandled ) { Throwable t = m_unhandled; m_unhandled = null; static if( rethrow ) throw t; else return t; } return null; } /// ditto deprecated("Please pass Fiber.Rethrow.yes or .no instead of a boolean.") final Throwable call( bool rethrow ) { return rethrow ? call!(Rethrow.yes)() : call!(Rethrow.no); } private void callImpl() nothrow in { assert( m_state == State.HOLD ); } body { Fiber cur = getThis(); static if( __traits( compiles, ucontext_t ) ) m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt; setThis( this ); this.switchIn(); setThis( cur ); static if( __traits( compiles, ucontext_t ) ) m_ucur = null; // NOTE: If the fiber has terminated then the stack pointers must be // reset. This ensures that the stack for this fiber is not // scanned if the fiber has terminated. This is necessary to // prevent any references lingering on the stack from delaying // the collection of otherwise dead objects. The most notable // being the current object, which is referenced at the top of // fiber_entryPoint. if( m_state == State.TERM ) { m_ctxt.tstack = m_ctxt.bstack; } } /// Flag to control rethrow behavior of $(D $(LREF call)) enum Rethrow : bool { no, yes } /** * Resets this fiber so that it may be re-used, optionally with a * new function/delegate. This routine should only be called for * fibers that have terminated, as doing otherwise could result in * scope-dependent functionality that is not executed. * Stack-based classes, for example, may not be cleaned up * properly if a fiber is reset before it has terminated. * * In: * This fiber must be in state TERM or HOLD. */ final void reset() nothrow in { assert( m_state == State.TERM || m_state == State.HOLD ); } body { m_ctxt.tstack = m_ctxt.bstack; m_state = State.HOLD; initStack(); m_unhandled = null; } /// ditto final void reset( void function() fn ) nothrow { reset(); m_fn = fn; m_call = Call.FN; } /// ditto final void reset( void delegate() dg ) nothrow { reset(); m_dg = dg; m_call = Call.DG; } /////////////////////////////////////////////////////////////////////////// // General Properties /////////////////////////////////////////////////////////////////////////// /** * A fiber may occupy one of three states: HOLD, EXEC, and TERM. The HOLD * state applies to any fiber that is suspended and ready to be called. * The EXEC state will be set for any fiber that is currently executing. * And the TERM state is set when a fiber terminates. Once a fiber * terminates, it must be reset before it may be called again. */ enum State { HOLD, /// EXEC, /// TERM /// } /** * Gets the current state of this fiber. * * Returns: * The state of this fiber as an enumerated value. */ final @property State state() const nothrow { return m_state; } /** * Return true if migrating a Fiber between Threads is unsafe on this * system. This is due to compiler optimizations that cache thread local * variable addresses. When Fiber.yield() returns on a different * Thread, the addresses refer to the previous Thread's variables. */ static @property bool migrationUnsafe() nothrow { version( CheckFiberMigration ) return true; else return false; } /** * Allow this Fiber to be resumed on a different thread for systems where * Fiber migration is unsafe (migrationUnsafe() is true). Otherwise the * first time a Fiber is resumed on a different Thread, a ThreadException * is thrown. This provides the programmer a reminder to be careful and * helps detect such usage in libraries being ported from other systems. * * Fiber migration on such systems can be done safely if you control all * the code and know that thread locals are not involved. * * For systems without this issue, allowMigration does nothing, as you are * always free to migrate. */ final void allowMigration() nothrow { // Does nothing if checking is disabled version( CheckFiberMigration ) m_allowMigration = true; } /////////////////////////////////////////////////////////////////////////// // Actions on Calling Fiber /////////////////////////////////////////////////////////////////////////// /** * Forces a context switch to occur away from the calling fiber. */ static void yield() nothrow { Fiber cur = getThis(); assert( cur, "Fiber.yield() called with no active fiber" ); assert( cur.m_state == State.EXEC ); static if( __traits( compiles, ucontext_t ) ) cur.m_ucur = &cur.m_utxt; cur.m_state = State.HOLD; cur.switchOut(); cur.m_state = State.EXEC; } /** * Forces a context switch to occur away from the calling fiber and then * throws obj in the calling fiber. * * Params: * t = The object to throw. * * In: * t must not be null. */ static void yieldAndThrow( Throwable t ) nothrow in { assert( t ); } body { Fiber cur = getThis(); assert( cur, "Fiber.yield() called with no active fiber" ); assert( cur.m_state == State.EXEC ); static if( __traits( compiles, ucontext_t ) ) cur.m_ucur = &cur.m_utxt; cur.m_unhandled = t; cur.m_state = State.HOLD; cur.switchOut(); cur.m_state = State.EXEC; } /////////////////////////////////////////////////////////////////////////// // Fiber Accessors /////////////////////////////////////////////////////////////////////////// /** * Provides a reference to the calling fiber or null if no fiber is * currently active. * * Returns: * The fiber object representing the calling fiber or null if no fiber * is currently active within this thread. The result of deleting this object is undefined. */ static Fiber getThis() nothrow { return sm_this; } /////////////////////////////////////////////////////////////////////////// // Static Initialization /////////////////////////////////////////////////////////////////////////// version( Posix ) { static this() { static if( __traits( compiles, ucontext_t ) ) { int status = getcontext( &sm_utxt ); assert( status == 0 ); } } } private: // // Initializes a fiber object which has no associated executable function. // this() nothrow { m_call = Call.NO; } // // Fiber entry point. Invokes the function or delegate passed on // construction (if any). // final void run() { switch( m_call ) { case Call.FN: m_fn(); break; case Call.DG: m_dg(); break; default: break; } } private: // // The type of routine passed on fiber construction. // enum Call { NO, FN, DG } // // Standard fiber data // Call m_call; union { void function() m_fn; void delegate() m_dg; } bool m_isRunning; Throwable m_unhandled; State m_state; // Set first time switchIn called to indicate this Fiber's Thread Thread m_curThread; version( CheckFiberMigration ) { bool m_allowMigration; } version( SjLj_Exceptions ) { SjLjFuncContext* m_sjljExStackTop; } private: /////////////////////////////////////////////////////////////////////////// // Stack Management /////////////////////////////////////////////////////////////////////////// // // Allocate a new stack for this fiber. // final void allocStack( size_t sz ) nothrow in { assert( !m_pmem && !m_ctxt ); } body { // adjust alloc size to a multiple of PAGESIZE sz += PAGESIZE - 1; sz -= sz % PAGESIZE; // NOTE: This instance of Thread.Context is dynamic so Fiber objects // can be collected by the GC so long as no user level references // to the object exist. If m_ctxt were not dynamic then its // presence in the global context list would be enough to keep // this object alive indefinitely. An alternative to allocating // room for this struct explicitly would be to mash it into the // base of the stack being allocated below. However, doing so // requires too much special logic to be worthwhile. m_ctxt = new Thread.Context; static if( __traits( compiles, VirtualAlloc ) ) { // reserve memory for stack m_pmem = VirtualAlloc( null, sz + PAGESIZE, MEM_RESERVE, PAGE_NOACCESS ); if( !m_pmem ) onOutOfMemoryError(); version( StackGrowsDown ) { void* stack = m_pmem + PAGESIZE; void* guard = m_pmem; void* pbase = stack + sz; } else { void* stack = m_pmem; void* guard = m_pmem + sz; void* pbase = stack; } // allocate reserved stack segment stack = VirtualAlloc( stack, sz, MEM_COMMIT, PAGE_READWRITE ); if( !stack ) onOutOfMemoryError(); // allocate reserved guard page guard = VirtualAlloc( guard, PAGESIZE, MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD ); if( !guard ) onOutOfMemoryError(); m_ctxt.bstack = pbase; m_ctxt.tstack = pbase; m_size = sz; } else { version (Posix) import core.sys.posix.sys.mman; // mmap version (FreeBSD) import core.sys.freebsd.sys.mman : MAP_ANON; version (CRuntime_Glibc) import core.sys.linux.sys.mman : MAP_ANON; version (OSX) import core.sys.osx.sys.mman : MAP_ANON; static if( __traits( compiles, mmap ) ) { m_pmem = mmap( null, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0 ); if( m_pmem == MAP_FAILED ) m_pmem = null; } else static if( __traits( compiles, valloc ) ) { m_pmem = valloc( sz ); } else static if( __traits( compiles, malloc ) ) { m_pmem = malloc( sz ); } else { m_pmem = null; } if( !m_pmem ) onOutOfMemoryError(); version( StackGrowsDown ) { m_ctxt.bstack = m_pmem + sz; m_ctxt.tstack = m_pmem + sz; } else { m_ctxt.bstack = m_pmem; m_ctxt.tstack = m_pmem; } m_size = sz; } Thread.add( m_ctxt ); } // // Free this fiber's stack. // final void freeStack() nothrow in { assert( m_pmem && m_ctxt ); } body { // NOTE: m_ctxt is guaranteed to be alive because it is held in the // global context list. Thread.slock.lock_nothrow(); scope(exit) Thread.slock.unlock_nothrow(); Thread.remove( m_ctxt ); static if( __traits( compiles, VirtualAlloc ) ) { VirtualFree( m_pmem, 0, MEM_RELEASE ); } else { import core.sys.posix.sys.mman; // munmap static if( __traits( compiles, mmap ) ) { munmap( m_pmem, m_size ); } else static if( __traits( compiles, valloc ) ) { free( m_pmem ); } else static if( __traits( compiles, malloc ) ) { free( m_pmem ); } } m_pmem = null; m_ctxt = null; } // // Initialize the allocated stack. // Look above the definition of 'class Fiber' for some information about the implementation of this routine // final void initStack() nothrow in { assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack ); assert( cast(size_t) m_ctxt.bstack % (void*).sizeof == 0 ); } body { void* pstack = m_ctxt.tstack; scope( exit ) m_ctxt.tstack = pstack; void push( size_t val ) nothrow { version( StackGrowsDown ) { pstack -= size_t.sizeof; *(cast(size_t*) pstack) = val; } else { pstack += size_t.sizeof; *(cast(size_t*) pstack) = val; } } // NOTE: On OS X the stack must be 16-byte aligned according // to the IA-32 call spec. For x86_64 the stack also needs to // be aligned to 16-byte according to SysV AMD64 ABI. version( AlignFiberStackTo16Byte ) { version( StackGrowsDown ) { pstack = cast(void*)(cast(size_t)(pstack) - (cast(size_t)(pstack) & 0x0F)); } else { pstack = cast(void*)(cast(size_t)(pstack) + (cast(size_t)(pstack) & 0x0F)); } } version( AsmX86_Windows ) { version( StackGrowsDown ) {} else static assert( false ); // On Windows Server 2008 and 2008 R2, an exploit mitigation // technique known as SEHOP is activated by default. To avoid // hijacking of the exception handler chain, the presence of a // Windows-internal handler (ntdll.dll!FinalExceptionHandler) at // its end is tested by RaiseException. If it is not present, all // handlers are disregarded, and the program is thus aborted // (see http://blogs.technet.com/b/srd/archive/2009/02/02/ // preventing-the-exploitation-of-seh-overwrites-with-sehop.aspx). // For new threads, this handler is installed by Windows immediately // after creation. To make exception handling work in fibers, we // have to insert it for our new stacks manually as well. // // To do this, we first determine the handler by traversing the SEH // chain of the current thread until its end, and then construct a // registration block for the last handler on the newly created // thread. We then continue to push all the initial register values // for the first context switch as for the other implementations. // // Note that this handler is never actually invoked, as we install // our own one on top of it in the fiber entry point function. // Thus, it should not have any effects on OSes not implementing // exception chain verification. alias void function() fp_t; // Actual signature not relevant. static struct EXCEPTION_REGISTRATION { EXCEPTION_REGISTRATION* next; // sehChainEnd if last one. fp_t handler; } enum sehChainEnd = cast(EXCEPTION_REGISTRATION*) 0xFFFFFFFF; __gshared static fp_t finalHandler = null; if ( finalHandler is null ) { static EXCEPTION_REGISTRATION* fs0() nothrow { asm pure nothrow @nogc { naked; mov EAX, FS:[0]; ret; } } auto reg = fs0(); while ( reg.next != sehChainEnd ) reg = reg.next; // Benign races are okay here, just to avoid re-lookup on every // fiber creation. finalHandler = reg.handler; } // When linking with /safeseh (supported by LDC, but not DMD) // the exception chain must not extend to the very top // of the stack, otherwise the exception chain is also considered // invalid. Reserving additional 4 bytes at the top of the stack will // keep the EXCEPTION_REGISTRATION below that limit size_t reserve = EXCEPTION_REGISTRATION.sizeof + 4; pstack -= reserve; *(cast(EXCEPTION_REGISTRATION*)pstack) = EXCEPTION_REGISTRATION( sehChainEnd, finalHandler ); push( cast(size_t) &fiber_entryPoint ); // EIP push( cast(size_t) m_ctxt.bstack - reserve ); // EBP push( 0x00000000 ); // EDI push( 0x00000000 ); // ESI push( 0x00000000 ); // EBX push( cast(size_t) m_ctxt.bstack - reserve ); // FS:[0] push( cast(size_t) m_ctxt.bstack ); // FS:[4] push( cast(size_t) m_ctxt.bstack - m_size ); // FS:[8] push( 0x00000000 ); // EAX } else version( AsmX86_64_Windows ) { // Using this trampoline instead of the raw fiber_entryPoint // ensures that during context switches, source and destination // stacks have the same alignment. Otherwise, the stack would need // to be shifted by 8 bytes for the first call, as fiber_entryPoint // is an actual function expecting a stack which is not aligned // to 16 bytes. static void trampoline() { asm pure nothrow @nogc { naked; sub RSP, 32; // Shadow space (Win64 calling convention) call fiber_entryPoint; xor RCX, RCX; // This should never be reached, as jmp RCX; // fiber_entryPoint must never return. } } push( cast(size_t) &trampoline ); // RIP push( 0x00000000_00000000 ); // RBP push( 0x00000000_00000000 ); // R12 push( 0x00000000_00000000 ); // R13 push( 0x00000000_00000000 ); // R14 push( 0x00000000_00000000 ); // R15 push( 0x00000000_00000000 ); // RDI push( 0x00000000_00000000 ); // RSI push( 0x00000000_00000000 ); // XMM6 (high) push( 0x00000000_00000000 ); // XMM6 (low) push( 0x00000000_00000000 ); // XMM7 (high) push( 0x00000000_00000000 ); // XMM7 (low) push( 0x00000000_00000000 ); // XMM8 (high) push( 0x00000000_00000000 ); // XMM8 (low) push( 0x00000000_00000000 ); // XMM9 (high) push( 0x00000000_00000000 ); // XMM9 (low) push( 0x00000000_00000000 ); // XMM10 (high) push( 0x00000000_00000000 ); // XMM10 (low) push( 0x00000000_00000000 ); // XMM11 (high) push( 0x00000000_00000000 ); // XMM11 (low) push( 0x00000000_00000000 ); // XMM12 (high) push( 0x00000000_00000000 ); // XMM12 (low) push( 0x00000000_00000000 ); // XMM13 (high) push( 0x00000000_00000000 ); // XMM13 (low) push( 0x00000000_00000000 ); // XMM14 (high) push( 0x00000000_00000000 ); // XMM14 (low) push( 0x00000000_00000000 ); // XMM15 (high) push( 0x00000000_00000000 ); // XMM15 (low) push( 0x00000000_00000000 ); // RBX push( 0xFFFFFFFF_FFFFFFFF ); // GS:[0] version( StackGrowsDown ) { push( cast(size_t) m_ctxt.bstack ); // GS:[8] push( cast(size_t) m_ctxt.bstack - m_size ); // GS:[16] } else { push( cast(size_t) m_ctxt.bstack ); // GS:[8] push( cast(size_t) m_ctxt.bstack + m_size ); // GS:[16] } } else version( AsmX86_Posix ) { push( 0x00000000 ); // Return address of fiber_entryPoint call push( cast(size_t) &fiber_entryPoint ); // EIP push( cast(size_t) m_ctxt.bstack ); // EBP push( 0x00000000 ); // EDI push( 0x00000000 ); // ESI push( 0x00000000 ); // EBX push( 0x00000000 ); // EAX } else version( AsmX86_64_Posix ) { push( 0x00000000_00000000 ); // Return address of fiber_entryPoint call push( cast(size_t) &fiber_entryPoint ); // RIP push( cast(size_t) m_ctxt.bstack ); // RBP push( 0x00000000_00000000 ); // RBX push( 0x00000000_00000000 ); // R12 push( 0x00000000_00000000 ); // R13 push( 0x00000000_00000000 ); // R14 push( 0x00000000_00000000 ); // R15 } else version( AsmPPC_Posix ) { version( StackGrowsDown ) { pstack -= int.sizeof * 5; } else { pstack += int.sizeof * 5; } push( cast(size_t) &fiber_entryPoint ); // link register push( 0x00000000 ); // control register push( 0x00000000 ); // old stack pointer // GPR values version( StackGrowsDown ) { pstack -= int.sizeof * 20; } else { pstack += int.sizeof * 20; } assert( (cast(size_t) pstack & 0x0f) == 0 ); } else version( AsmPPC64_Posix ) { version( StackGrowsDown ) {} else static assert(0); /* * The stack frame uses the standard layout except for floating * point and vector registers. * * ELFv2: * +------------------------+ * | TOC Pointer Doubleword | SP+24 * +------------------------+ * | LR Save Doubleword | SP+16 * +------------------------+ * | Reserved | SP+12 * +------------------------+ * | CR Save Word | SP+8 * +------------------------+ * | Back Chain | SP+176 <-- Previous function * +------------------------+ * | GPR Save Area (14-31) | SP+32 * +------------------------+ * | TOC Pointer Doubleword | SP+24 * +------------------------+ * | LR Save Doubleword | SP+16 * +------------------------+ * | Reserved | SP+12 * +------------------------+ * | CR Save Word | SP+8 * +------------------------+ * | Back Chain | SP+0 <-- Stored stack pointer * +------------------------+ * | VR Save Area (20-31) | SP-16 * +------------------------+ * | FPR Save Area (14-31) | SP-200 * +------------------------+ * * ELFv1: * +------------------------+ * | Parameter Save Area | SP+48 * +------------------------+ * | TOC Pointer Doubleword | SP+40 * +------------------------+ * | Link editor doubleword | SP+32 * +------------------------+ * | Compiler Doubleword | SP+24 * +------------------------+ * | LR Save Doubleword | SP+16 * +------------------------+ * | Reserved | SP+12 * +------------------------+ * | CR Save Word | SP+8 * +------------------------+ * | Back Chain | SP+256 <-- Previous function * +------------------------+ * | GPR Save Area (14-31) | SP+112 * +------------------------+ * | Parameter Save Area | SP+48 * +------------------------+ * | TOC Pointer Doubleword | SP+40 * +------------------------+ * | Link editor doubleword | SP+32 * +------------------------+ * | Compiler Doubleword | SP+24 * +------------------------+ * | LR Save Doubleword | SP+16 * +------------------------+ * | Reserved | SP+12 * +------------------------+ * | CR Save Word | SP+8 * +------------------------+ * | Back Chain | SP+0 <-- Stored stack pointer * +------------------------+ * | VR Save Area (20-31) | SP-16 * +------------------------+ * | FPR Save Area (14-31) | SP-200 * +------------------------+ */ assert( (cast(size_t) pstack & 0x0f) == 0 ); version( ELFv1 ) { pstack -= size_t.sizeof * 8; // Parameter Save Area push( 0x00000000_00000000 ); // TOC Pointer Doubleword push( 0x00000000_00000000 ); // Link editor doubleword push( 0x00000000_00000000 ); // Compiler Doubleword push( cast(size_t) &fiber_entryPoint ); // LR Save Doubleword push( 0x00000000_00000000 ); // CR Save Word push( 0x00000000_00000000 ); // Back Chain size_t backchain = cast(size_t) pstack; // Save back chain pstack -= size_t.sizeof * 18; // GPR Save Area pstack -= size_t.sizeof * 8; // Parameter Save Area push( 0x00000000_00000000 ); // TOC Pointer Doubleword push( 0x00000000_00000000 ); // Link editor doubleword push( 0x00000000_00000000 ); // Compiler Doubleword push( 0x00000000_00000000 ); // LR Save Doubleword push( 0x00000000_00000000 ); // CR Save Word push( backchain ); // Back Chain } else { push( 0x00000000_00000000 ); // TOC Pointer Doubleword push( cast(size_t) &fiber_entryPoint ); // LR Save Doubleword push( 0x00000000_00000000 ); // CR Save Word push( 0x00000000_00000000 ); // Back Chain size_t backchain = cast(size_t) pstack; // Save back chain pstack -= size_t.sizeof * 18; // GPR Save Area push( 0x00000000_00000000 ); // TOC Pointer Doubleword push( 0x00000000_00000000 ); // LR Save Doubleword push( 0x00000000_00000000 ); // CR Save Word push( backchain ); // Back Chain } assert( (cast(size_t) pstack & 0x0f) == 0 ); } else version( AsmMIPS_O32_Posix ) { version (StackGrowsDown) {} else static assert(0); /* We keep the FP registers and the return address below * the stack pointer, so they don't get scanned by the * GC. The last frame before swapping the stack pointer is * organized like the following. * * |-----------|<= frame pointer * | $gp | * | $s0-8 | * |-----------|<= stack pointer * | $ra | * | align(8) | * | $f20-30 | * |-----------| * */ enum SZ_GP = 10 * size_t.sizeof; // $gp + $s0-8 enum SZ_RA = size_t.sizeof; // $ra version (MIPS_HardFloat) { enum SZ_FP = 6 * 8; // $f20-30 enum ALIGN = -(SZ_FP + SZ_RA) & (8 - 1); } else { enum SZ_FP = 0; enum ALIGN = 0; } enum BELOW = SZ_FP + ALIGN + SZ_RA; enum ABOVE = SZ_GP; enum SZ = BELOW + ABOVE; (cast(ubyte*)pstack - SZ)[0 .. SZ] = 0; pstack -= ABOVE; *cast(size_t*)(pstack - SZ_RA) = cast(size_t)&fiber_entryPoint; } else version( AsmAArch64_Posix ) { // Like others, FP registers and return address (lr) are kept // below the saved stack top (tstack) to hide from GC scanning. // fiber_switchContext expects newp sp to look like this: // 19: x19 // ... // 9: x29 (fp) <-- newp tstack // 8: x30 (lr) [&fiber_entryPoint] // 7: d8 // ... // 0: d15 version( StackGrowsDown ) {} else static assert(false, "Only full descending stacks supported on AArch64"); // Only need to set return address (lr). Everything else is fine // zero initialized. pstack -= size_t.sizeof * 11; // skip past x19-x29 push(cast(size_t) &fiber_entryPoint); pstack += size_t.sizeof; // adjust sp (newp) above lr } else version( AsmARM_Posix ) { /* We keep the FP registers and the return address below * the stack pointer, so they don't get scanned by the * GC. The last frame before swapping the stack pointer is * organized like the following. * * | |-----------|<= 'frame starts here' * | | fp | (the actual frame pointer, r11 isn't * | | r10-r4 | updated and still points to the previous frame) * | |-----------|<= stack pointer * | | lr | * | | 4byte pad | * | | d15-d8 |(if FP supported) * | |-----------| * Y * stack grows down: The pointer value here is smaller than some lines above */ // frame pointer can be zero, r10-r4 also zero initialized version( StackGrowsDown ) pstack -= int.sizeof * 8; else static assert(false, "Only full descending stacks supported on ARM"); // link register push( cast(size_t) &fiber_entryPoint ); /* * We do not push padding and d15-d8 as those are zero initialized anyway * Position the stack pointer above the lr register */ pstack += int.sizeof * 1; } else static if( __traits( compiles, ucontext_t ) ) { getcontext( &m_utxt ); m_utxt.uc_stack.ss_sp = m_pmem; m_utxt.uc_stack.ss_size = m_size; makecontext( &m_utxt, &fiber_entryPoint, 0 ); // NOTE: If ucontext is being used then the top of the stack will // be a pointer to the ucontext_t struct for that fiber. push( cast(size_t) &m_utxt ); } else static assert(0, "Not implemented"); } Thread.Context* m_ctxt; size_t m_size; void* m_pmem; static if( __traits( compiles, ucontext_t ) ) { // NOTE: The static ucontext instance is used to represent the context // of the executing thread. static ucontext_t sm_utxt = void; ucontext_t m_utxt = void; ucontext_t* m_ucur = null; } private: /////////////////////////////////////////////////////////////////////////// // Storage of Active Fiber /////////////////////////////////////////////////////////////////////////// // // Sets a thread-local reference to the current fiber object. // static void setThis( Fiber f ) nothrow { sm_this = f; } static Fiber sm_this; private: /////////////////////////////////////////////////////////////////////////// // Context Switching /////////////////////////////////////////////////////////////////////////// // // Switches into the stack held by this fiber. // final void switchIn() nothrow { Thread tobj = Thread.getThis(); void** oldp = &tobj.m_curr.tstack; void* newp = m_ctxt.tstack; version( CheckFiberMigration ) { if (m_curThread is null || m_allowMigration) m_curThread = tobj; else if (tobj !is m_curThread) { m_unhandled = new ThreadException ("Migrating Fibers between Threads on this platform may lead " "to incorrect thread local variable access. To allow " "migration anyway, call Fiber.allowMigration()"); return; } } else { m_curThread = tobj; } version( SjLj_Exceptions ) SjLjFuncContext* oldsjlj = swapSjLjStackTop(m_sjljExStackTop); // NOTE: The order of operations here is very important. The current // stack top must be stored before m_lock is set, and pushContext // must not be called until after m_lock is set. This process // is intended to prevent a race condition with the suspend // mechanism used for garbage collection. If it is not followed, // a badly timed collection could cause the GC to scan from the // bottom of one stack to the top of another, or to miss scanning // a stack that still contains valid data. The old stack pointer // oldp will be set again before the context switch to guarantee // that it points to exactly the correct stack location so the // successive pop operations will succeed. *oldp = getStackTop(); atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true); tobj.pushContext( m_ctxt ); fiber_switchContext( oldp, newp ); // NOTE: As above, these operations must be performed in a strict order // to prevent Bad Things from happening. tobj.popContext(); atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false); tobj.m_curr.tstack = tobj.m_curr.bstack; version( SjLj_Exceptions ) m_sjljExStackTop = swapSjLjStackTop(oldsjlj); } // // Switches out of the current stack and into the enclosing stack. // final void switchOut() nothrow { Thread tobj = m_curThread; void** oldp = &m_ctxt.tstack; void* newp = tobj.m_curr.within.tstack; // NOTE: The order of operations here is very important. The current // stack top must be stored before m_lock is set, and pushContext // must not be called until after m_lock is set. This process // is intended to prevent a race condition with the suspend // mechanism used for garbage collection. If it is not followed, // a badly timed collection could cause the GC to scan from the // bottom of one stack to the top of another, or to miss scanning // a stack that still contains valid data. The old stack pointer // oldp will be set again before the context switch to guarantee // that it points to exactly the correct stack location so the // successive pop operations will succeed. *oldp = getStackTop(); atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true); fiber_switchContext( oldp, newp ); // NOTE: As above, these operations must be performed in a strict order // to prevent Bad Things from happening. // NOTE: If use of this fiber is multiplexed across threads, the thread // executing here may be different from the one above, so get the // current thread handle before unlocking, etc. tobj = m_curThread; atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false); tobj.m_curr.tstack = tobj.m_curr.bstack; } } version( unittest ) { class TestFiber : Fiber { this() { super(&run); } void run() { foreach(i; 0 .. 1000) { sum += i; Fiber.yield(); } } enum expSum = 1000 * 999 / 2; size_t sum; } void runTen() { TestFiber[10] fibs; foreach(ref fib; fibs) fib = new TestFiber(); bool cont; do { cont = false; foreach(fib; fibs) { if (fib.state == Fiber.State.HOLD) { fib.call(); cont |= fib.state != Fiber.State.TERM; } } } while (cont); foreach(fib; fibs) { assert(fib.sum == TestFiber.expSum); } } } // Single thread running separate fibers unittest { runTen(); } // Multiple threads running separate fibers unittest { auto group = new ThreadGroup(); foreach(_; 0 .. 4) { group.create(&runTen); } group.joinAll(); } // Try to detect if version CheckFiberMigration should be set, or if it is // set, make sure it behaves properly. The issue is that thread local addr // may be cached by the compiler and that doesn't play well when Fibers // migrate between Threads. This may only happen when optimization // enabled. For that reason, should run this unittest with various // optimization levels. // // https://github.com/ldc-developers/ldc/issues/666 unittest { static int tls; static yield_noinline() { import ldc.intrinsics; pragma(LDC_never_inline); Fiber.yield(); } auto f = new Fiber( { ++tls; // happens on main thread yield_noinline(); ++tls; // happens on other thread, // 1 if tls addr uncached, 2 if addr was cached }); auto t = new Thread( { assert(tls == 0); version( CheckFiberMigration ) { try { f.call(); assert(false, "Should get ThreadException when Fiber migrated"); } catch (ThreadException ex) { } f.allowMigration(); } f.call(); // tls may be 0 (wrong) or 1 (good) depending on thread local handling // by compiler }); assert(tls == 0); f.call(); assert(tls == 1); t.start(); t.join(); version( CheckFiberMigration ) { assert(Fiber.migrationUnsafe); } else version( FiberMigrationTest ) { assert(!Fiber.migrationUnsafe); // If thread local addr not cached (correct behavior), then tls should // still be 1. assert(tls != 2, "Not safe to migrate Fibers between Threads on your system. " "Consider setting version CheckFiberMigration for this system " "in thread.d"); // verify un-cached correct case assert(tls == 1); } else { if (tls == 2) { import core.stdc.stdio : puts; puts("Not safe to migrate Fibers between Threads on your system. " "Consider setting version CheckFiberMigration for this system " "in thread.d"); } } } // Multiple threads running shared fibers unittest { shared bool[10] locks; TestFiber[10] fibs; void runShared() { bool cont; do { cont = false; foreach(idx; 0 .. 10) { if (cas(&locks[idx], false, true)) { if (fibs[idx].state == Fiber.State.HOLD) { fibs[idx].call(); cont |= fibs[idx].state != Fiber.State.TERM; } locks[idx] = false; } else { cont = true; } } } while (cont); } foreach(ref fib; fibs) { fib = new TestFiber(); fib.allowMigration(); } auto group = new ThreadGroup(); foreach(_; 0 .. 4) { group.create(&runShared); } group.joinAll(); foreach(fib; fibs) { assert(fib.sum == TestFiber.expSum); } } // Test exception handling inside fibers. version (Win32) { // broken on win32 under windows server 2012: bug 13821 } else unittest { enum MSG = "Test message."; string caughtMsg; (new Fiber({ try { throw new Exception(MSG); } catch (Exception e) { caughtMsg = e.msg; } })).call(); assert(caughtMsg == MSG); } unittest { int x = 0; (new Fiber({ x++; })).call(); assert( x == 1 ); } nothrow unittest { new Fiber({}).call!(Fiber.Rethrow.no)(); } unittest { new Fiber({}).call(Fiber.Rethrow.yes); new Fiber({}).call(Fiber.Rethrow.no); } deprecated unittest { new Fiber({}).call(true); new Fiber({}).call(false); } version (Win32) { // broken on win32 under windows server 2012: bug 13821 } else unittest { enum MSG = "Test message."; try { (new Fiber({ throw new Exception( MSG ); })).call(); assert( false, "Expected rethrown exception." ); } catch( Throwable t ) { assert( t.msg == MSG ); } } // Test exception chaining when switching contexts in finally blocks. unittest { static void throwAndYield(string msg) { try { throw new Exception(msg); } finally { Fiber.yield(); } } static void fiber(string name) { try { try { throwAndYield(name ~ ".1"); } finally { throwAndYield(name ~ ".2"); } } catch (Exception e) { assert(e.msg == name ~ ".1"); assert(e.next); assert(e.next.msg == name ~ ".2"); assert(!e.next.next); } } auto first = new Fiber(() => fiber("first")); auto second = new Fiber(() => fiber("second")); first.call(); second.call(); first.call(); second.call(); first.call(); second.call(); assert(first.state == Fiber.State.TERM); assert(second.state == Fiber.State.TERM); } // Test Fiber resetting unittest { static string method; static void foo() { method = "foo"; } void bar() { method = "bar"; } static void expect(Fiber fib, string s) { assert(fib.state == Fiber.State.HOLD); fib.call(); assert(fib.state == Fiber.State.TERM); assert(method == s); method = null; } auto fib = new Fiber(&foo); expect(fib, "foo"); fib.reset(); expect(fib, "foo"); fib.reset(&foo); expect(fib, "foo"); fib.reset(&bar); expect(fib, "bar"); fib.reset(function void(){method = "function";}); expect(fib, "function"); fib.reset(delegate void(){method = "delegate";}); expect(fib, "delegate"); } // Test unsafe reset in hold state unittest { auto fib = new Fiber(function {ubyte[2048] buf = void; Fiber.yield();}, 4096); foreach (_; 0 .. 10) { fib.call(); assert(fib.state == Fiber.State.HOLD); fib.reset(); } } // stress testing GC stack scanning unittest { import core.memory; static void unreferencedThreadObject() { static void sleep() { Thread.sleep(dur!"msecs"(100)); } auto thread = new Thread(&sleep).start(); } unreferencedThreadObject(); GC.collect(); static class Foo { this(int value) { _value = value; } int bar() { return _value; } int _value; } static void collect() { auto foo = new Foo(2); assert(foo.bar() == 2); GC.collect(); Fiber.yield(); GC.collect(); assert(foo.bar() == 2); } auto fiber = new Fiber(&collect); fiber.call(); GC.collect(); fiber.call(); // thread reference auto foo = new Foo(2); void collect2() { assert(foo.bar() == 2); GC.collect(); Fiber.yield(); GC.collect(); assert(foo.bar() == 2); } fiber = new Fiber(&collect2); fiber.call(); GC.collect(); fiber.call(); static void recurse(size_t cnt) { --cnt; Fiber.yield(); if (cnt) { auto fib = new Fiber(() { recurse(cnt); }); fib.call(); GC.collect(); fib.call(); } } fiber = new Fiber(() { recurse(20); }); fiber.call(); } version( AsmX86_64_Windows ) { // Test Windows x64 calling convention unittest { void testNonvolatileRegister(alias REG)() { auto zeroRegister = new Fiber(() { mixin("asm pure nothrow @nogc { naked; xor "~REG~", "~REG~"; ret; }"); }); long after; mixin("asm pure nothrow @nogc { mov "~REG~", 0xFFFFFFFFFFFFFFFF; }"); zeroRegister.call(); mixin("asm pure nothrow @nogc { mov after, "~REG~"; }"); assert(after == -1); } void testNonvolatileRegisterSSE(alias REG)() { auto zeroRegister = new Fiber(() { mixin("asm pure nothrow @nogc { naked; xorpd "~REG~", "~REG~"; ret; }"); }); long[2] before = [0xFFFFFFFF_FFFFFFFF, 0xFFFFFFFF_FFFFFFFF], after; mixin("asm pure nothrow @nogc { movdqu "~REG~", before; }"); zeroRegister.call(); mixin("asm pure nothrow @nogc { movdqu after, "~REG~"; }"); assert(before == after); } testNonvolatileRegister!("R12")(); testNonvolatileRegister!("R13")(); testNonvolatileRegister!("R14")(); testNonvolatileRegister!("R15")(); testNonvolatileRegister!("RDI")(); testNonvolatileRegister!("RSI")(); testNonvolatileRegister!("RBX")(); testNonvolatileRegisterSSE!("XMM6")(); testNonvolatileRegisterSSE!("XMM7")(); testNonvolatileRegisterSSE!("XMM8")(); testNonvolatileRegisterSSE!("XMM9")(); testNonvolatileRegisterSSE!("XMM10")(); testNonvolatileRegisterSSE!("XMM11")(); testNonvolatileRegisterSSE!("XMM12")(); testNonvolatileRegisterSSE!("XMM13")(); testNonvolatileRegisterSSE!("XMM14")(); testNonvolatileRegisterSSE!("XMM15")(); } } version( D_InlineAsm_X86_64 ) { unittest { void testStackAlignment() { void* pRSP; asm pure nothrow @nogc { mov pRSP, RSP; } assert((cast(size_t)pRSP & 0xF) == 0); } auto fib = new Fiber(&testStackAlignment); fib.call(); } } // regression test for Issue 13416 version (FreeBSD) unittest { static void loop() { pthread_attr_t attr; pthread_attr_init(&attr); auto thr = pthread_self(); foreach (i; 0 .. 50) pthread_attr_get_np(thr, &attr); pthread_attr_destroy(&attr); } auto thr = new Thread(&loop).start(); foreach (i; 0 .. 50) { thread_suspendAll(); thread_resumeAll(); } thr.join(); } unittest { // use >PAGESIZE to avoid stack overflow (e.g. in an syscall) auto thr = new Thread(function{}, 4096 + 1).start(); thr.join(); } /** * Represents the ID of a thread, as returned by $(D Thread.)$(LREF id). * The exact type varies from platform to platform. */ version (Windows) alias ThreadID = uint; else version (Posix) alias ThreadID = pthread_t; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/0000775000175000017500000000000012776214756020020 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/0000775000175000017500000000000012776214756021512 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rpcnterr.d0000664000175000017500000000236412776214756023523 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rpcnterr.d) */ module core.sys.windows.rpcnterr; version (Windows): import core.sys.windows.winerror; enum : uint { RPC_S_OK = ERROR_SUCCESS, RPC_S_INVALID_ARG = ERROR_INVALID_PARAMETER, RPC_S_OUT_OF_MEMORY = ERROR_OUTOFMEMORY, RPC_S_OUT_OF_THREADS = ERROR_MAX_THRDS_REACHED, RPC_S_INVALID_LEVEL = ERROR_INVALID_PARAMETER, RPC_S_BUFFER_TOO_SMALL = ERROR_INSUFFICIENT_BUFFER, RPC_S_INVALID_SECURITY_DESC = ERROR_INVALID_SECURITY_DESCR, RPC_S_ACCESS_DENIED = ERROR_ACCESS_DENIED, RPC_S_SERVER_OUT_OF_MEMORY = ERROR_NOT_ENOUGH_SERVER_MEMORY, RPC_X_NO_MEMORY = RPC_S_OUT_OF_MEMORY, RPC_X_INVALID_BOUND = RPC_S_INVALID_BOUND, RPC_X_INVALID_TAG = RPC_S_INVALID_TAG, RPC_X_ENUM_VALUE_TOO_LARGE = RPC_X_ENUM_VALUE_OUT_OF_RANGE, RPC_X_SS_CONTEXT_MISMATCH = ERROR_INVALID_HANDLE, RPC_X_INVALID_BUFFER = ERROR_INVALID_USER_BUFFER, RPC_X_INVALID_PIPE_OPERATION = RPC_X_WRONG_PIPE_ORDER } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ntsecpkg.d0000664000175000017500000004403212776214756023500 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Ellery Newcomer * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ntsecpkg.d) */ module core.sys.windows.ntsecpkg; version (Windows): import core.sys.windows.windef, core.sys.windows.ntsecapi, core.sys.windows.security, core.sys.windows.ntdef, core.sys.windows.sspi; import core.sys.windows.basetyps : GUID; import core.sys.windows.winbase; extern(Windows): enum :ULONG{ ISC_REQ_DELEGATE = 1, ISC_REQ_MUTUAL_AUTH = 2, ISC_REQ_REPLAY_DETECT = 4, ISC_REQ_SEQUENCE_DETECT = 8, ISC_REQ_CONFIDENTIALITY = 16, ISC_REQ_USE_SESSION_KEY = 32, ISC_REQ_PROMPT_FOR_CREDS = 64, ISC_REQ_USE_SUPPLIED_CREDS = 128, ISC_REQ_ALLOCATE_MEMORY = 256, ISC_REQ_USE_DCE_STYLE = 512, ISC_REQ_DATAGRAM = 1024, ISC_REQ_CONNECTION = 2048, ISC_REQ_EXTENDED_ERROR = 16384, ISC_REQ_STREAM = 32768, ISC_REQ_INTEGRITY = 65536, ISC_REQ_MANUAL_CRED_VALIDATION = 524288, ISC_REQ_HTTP = 268435456, } enum ISC_RET_EXTENDED_ERROR = 16384; enum :ULONG{ ASC_REQ_DELEGATE = 1, ASC_REQ_MUTUAL_AUTH = 2, ASC_REQ_REPLAY_DETECT = 4, ASC_REQ_SEQUENCE_DETECT = 8, ASC_REQ_CONFIDENTIALITY = 16, ASC_REQ_USE_SESSION_KEY = 32, ASC_REQ_ALLOCATE_MEMORY = 256, ASC_REQ_USE_DCE_STYLE = 512, ASC_REQ_DATAGRAM = 1024, ASC_REQ_CONNECTION = 2048, ASC_REQ_EXTENDED_ERROR = 32768, ASC_REQ_STREAM = 65536, ASC_REQ_INTEGRITY = 131072, } enum SECURITY_NATIVE_DREP = 16; enum SECURITY_NETWORK_DREP = 0; enum :ULONG{ SECPKG_STATE_ENCRYPTION_PERMITTED = 0x01, SECPKG_STATE_STRONG_ENCRYPTION_PERMITTED = 0x02, SECPKG_STATE_DOMAIN_CONTROLLER = 0x04, SECPKG_STATE_WORKSTATION = 0x08, SECPKG_STATE_STANDALONE = 0x10, } /* enum definitions for Secure Service Provider/Authentication Packages */ enum LSA_TOKEN_INFORMATION_TYPE { LsaTokenInformationNull, LsaTokenInformationV1 } alias LSA_TOKEN_INFORMATION_TYPE* PLSA_TOKEN_INFORMATION_TYPE; enum SECPKG_EXTENDED_INFORMATION_CLASS { SecpkgGssInfo = 1, SecpkgContextThunks, SecpkgMutualAuthLevel, SecpkgMaxInfo } enum SECPKG_NAME_TYPE { SecNameSamCompatible, SecNameAlternateId, SecNameFlat, SecNameDN } /* struct definitions for SSP/AP */ struct SECPKG_PRIMARY_CRED { LUID LogonId; UNICODE_STRING DownlevelName; UNICODE_STRING DomainName; UNICODE_STRING Password; UNICODE_STRING OldPassword; PSID UserSid; ULONG Flags; UNICODE_STRING DnsDomainName; UNICODE_STRING Upn; UNICODE_STRING LogonServer; UNICODE_STRING Spare1; UNICODE_STRING Spare2; UNICODE_STRING Spare3; UNICODE_STRING Spare4; } alias SECPKG_PRIMARY_CRED* PSECPKG_PRIMARY_CRED; struct SECPKG_SUPPLEMENTAL_CRED { UNICODE_STRING PackageName; ULONG CredentialSize; PUCHAR Credentials; } alias SECPKG_SUPPLEMENTAL_CRED* PSECPKG_SUPPLEMENTAL_CRED; struct SECPKG_SUPPLEMENTAL_CRED_ARRAY { ULONG CredentialCount; SECPKG_SUPPLEMENTAL_CRED[1] Credentials; } alias SECPKG_SUPPLEMENTAL_CRED_ARRAY* PSECPKG_SUPPLEMENTAL_CRED_ARRAY; struct SECPKG_PARAMETERS { ULONG Version; ULONG MachineState; ULONG SetupMode; PSID DomainSid; UNICODE_STRING DomainName; UNICODE_STRING DnsDomainName; GUID DomainGuid; } alias SECPKG_PARAMETERS* PSECPKG_PARAMETERS,PSECPKG_EVENT_DOMAIN_CHANGE; alias SECPKG_PARAMETERS SECPKG_EVENT_DOMAIN_CHANGE; struct SECPKG_CLIENT_INFO { LUID LogonId; ULONG ProcessID; ULONG ThreadID; BOOLEAN HasTcbPrivilege; BOOLEAN Impersonating; BOOLEAN Restricted; } alias SECPKG_CLIENT_INFO* PSECPKG_CLIENT_INFO; struct SECURITY_USER_DATA { SECURITY_STRING UserName; SECURITY_STRING LogonDomainName; SECURITY_STRING LogonServer; PSID pSid; } alias SECURITY_USER_DATA* PSECURITY_USER_DATA,PSecurityUserData; alias SECURITY_USER_DATA SecurityUserData; struct SECPKG_GSS_INFO { ULONG EncodedIdLength; UCHAR[4] EncodedId; } alias SECPKG_GSS_INFO* PSECPKG_GSS_INFO; struct SECPKG_CONTEXT_THUNKS { ULONG InfoLevelCount; ULONG[1] Levels; } alias SECPKG_CONTEXT_THUNKS* PSECPKG_CONTEXT_THUNKS; struct SECPKG_MUTUAL_AUTH_LEVEL { ULONG MutualAuthLevel; } alias SECPKG_MUTUAL_AUTH_LEVEL* PSECPKG_MUTUAL_AUTH_LEVEL; struct SECPKG_CALL_INFO { ULONG ProcessId; ULONG ThreadId; ULONG Attributes; ULONG CallCount; } alias SECPKG_CALL_INFO* PSECPKG_CALL_INFO; struct SECPKG_EXTENDED_INFORMATION { SECPKG_EXTENDED_INFORMATION_CLASS Class; union _Info{ SECPKG_GSS_INFO GssInfo; SECPKG_CONTEXT_THUNKS ContextThunks; SECPKG_MUTUAL_AUTH_LEVEL MutualAuthLevel; } _Info Info; } alias SECPKG_EXTENDED_INFORMATION* PSECPKG_EXTENDED_INFORMATION; /* callbacks implemented by SSP/AP dlls and called by the LSA */ alias void function(ULONG_PTR, ULONG_PTR, PSecBuffer, PSecBuffer) PLSA_CALLBACK_FUNCTION; /* misc typedefs used in the below prototypes */ alias PVOID* PLSA_CLIENT_REQUEST; alias ULONG LSA_SEC_HANDLE; alias ULONG* PLSA_SEC_HANDLE; alias LPTHREAD_START_ROUTINE SEC_THREAD_START; alias PSECURITY_ATTRIBUTES SEC_ATTRS; /* functions used by SSP/AP obtainable by dispatch tables */ alias NTSTATUS function(ULONG, PLSA_CALLBACK_FUNCTION) PLSA_REGISTER_CALLBACK; alias NTSTATUS function(PLUID) PLSA_CREATE_LOGON_SESSION; alias NTSTATUS function(PLUID) PLSA_DELETE_LOGON_SESSION; alias NTSTATUS function(PLUID, ULONG, PLSA_STRING, PLSA_STRING) PLSA_ADD_CREDENTIAL; alias NTSTATUS function(PLUID, ULONG, PULONG, BOOLEAN, PLSA_STRING, PULONG, PLSA_STRING) PLSA_GET_CREDENTIALS; alias NTSTATUS function(PLUID, ULONG, PLSA_STRING) PLSA_DELETE_CREDENTIAL; alias PVOID function(ULONG) PLSA_ALLOCATE_LSA_HEAP; alias void function(PVOID) PLSA_FREE_LSA_HEAP; alias NTSTATUS function(PLSA_CLIENT_REQUEST, ULONG, PVOID*) PLSA_ALLOCATE_CLIENT_BUFFER; alias NTSTATUS function(PLSA_CLIENT_REQUEST, PVOID) PLSA_FREE_CLIENT_BUFFER; alias NTSTATUS function(PLSA_CLIENT_REQUEST, ULONG, PVOID, PVOID) PLSA_COPY_TO_CLIENT_BUFFER; alias NTSTATUS function(PLSA_CLIENT_REQUEST, ULONG, PVOID, PVOID) PLSA_COPY_FROM_CLIENT_BUFFER; alias NTSTATUS function() PLSA_IMPERSONATE_CLIENT; alias NTSTATUS function() PLSA_UNLOAD_PACKAGE; alias NTSTATUS function(HANDLE, PHANDLE) PLSA_DUPLICATE_HANDLE; alias NTSTATUS function(PLUID, ULONG, PVOID, BOOLEAN) PLSA_SAVE_SUPPLEMENTAL_CREDENTIALS; alias HANDLE function(SEC_ATTRS, ULONG, SEC_THREAD_START, PVOID, ULONG, PULONG) PLSA_CREATE_THREAD; alias NTSTATUS function(PSECPKG_CLIENT_INFO) PLSA_GET_CLIENT_INFO; alias HANDLE function(SEC_THREAD_START, PVOID, ULONG, ULONG, ULONG, ULONG, HANDLE) PLSA_REGISTER_NOTIFICATION; alias NTSTATUS function(HANDLE) PLSA_CANCEL_NOTIFICATION; alias NTSTATUS function(PSecBuffer, PSecBuffer) PLSA_MAP_BUFFER; alias NTSTATUS function(PLUID, PTOKEN_SOURCE, SECURITY_LOGON_TYPE, SECURITY_IMPERSONATION_LEVEL, LSA_TOKEN_INFORMATION_TYPE, PVOID, PTOKEN_GROUPS, PUNICODE_STRING, PUNICODE_STRING, PUNICODE_STRING, PUNICODE_STRING, PHANDLE, PNTSTATUS) PLSA_CREATE_TOKEN; alias void function(NTSTATUS, NTSTATUS, PUNICODE_STRING, PUNICODE_STRING, PUNICODE_STRING, PSID, SECURITY_LOGON_TYPE, PTOKEN_SOURCE, PLUID) PLSA_AUDIT_LOGON; alias NTSTATUS function(PUNICODE_STRING, PVOID, ULONG, PVOID*, PULONG, PNTSTATUS) PLSA_CALL_PACKAGE; alias BOOLEAN function(PSECPKG_CALL_INFO) PLSA_GET_CALL_INFO; alias NTSTATUS function(PUNICODE_STRING, PVOID, PVOID, ULONG, PVOID*, PULONG, PNTSTATUS) PLSA_CALL_PACKAGEEX; alias PVOID function(ULONG, ULONG) PLSA_CREATE_SHARED_MEMORY; alias PVOID function(PVOID, ULONG) PLSA_ALLOCATE_SHARED_MEMORY; alias void function(PVOID, PVOID) PLSA_FREE_SHARED_MEMORY; alias BOOLEAN function(PVOID) PLSA_DELETE_SHARED_MEMORY; alias NTSTATUS function(PSECURITY_STRING, SECPKG_NAME_TYPE, PSECURITY_STRING, BOOLEAN, ULONG, PVOID*) PLSA_OPEN_SAM_USER; alias NTSTATUS function(PVOID, PVOID *, PULONG, PVOID *, PULONG) PLSA_GET_USER_CREDENTIALS; alias NTSTATUS function(PVOID, PUCHAR *, PULONG) PLSA_GET_USER_AUTH_DATA; alias NTSTATUS function(PVOID) PLSA_CLOSE_SAM_USER; alias NTSTATUS function(PVOID, ULONG, SECURITY_IMPERSONATION_LEVEL, PTOKEN_SOURCE, SECURITY_LOGON_TYPE, PUNICODE_STRING, PHANDLE, PLUID, PUNICODE_STRING, PNTSTATUS) PLSA_CONVERT_AUTH_DATA_TO_TOKEN; alias NTSTATUS function(PCHAR, ULONG_PTR, ULONG_PTR, PSecBuffer, PSecBuffer) PLSA_CLIENT_CALLBACK; alias NTSTATUS function(PSECPKG_PRIMARY_CRED, PSECPKG_SUPPLEMENTAL_CRED_ARRAY) PLSA_UPDATE_PRIMARY_CREDENTIALS; alias NTSTATUS function(PSECURITY_STRING, SECPKG_NAME_TYPE, PSECURITY_STRING, PUCHAR *, PULONG, PUNICODE_STRING) PLSA_GET_AUTH_DATA_FOR_USER; alias NTSTATUS function(ULONG, BOOLEAN, PUNICODE_STRING, PUNICODE_STRING, ULONG, PUNICODE_STRING, PUNICODE_STRING, PULONG) PLSA_CRACK_SINGLE_NAME; alias NTSTATUS function(ULONG, BOOLEAN, PUNICODE_STRING, PUNICODE_STRING, PUNICODE_STRING, NTSTATUS) PLSA_AUDIT_ACCOUNT_LOGON; alias NTSTATUS function(PUNICODE_STRING, PVOID, PVOID, ULONG, PVOID*, PULONG, PNTSTATUS) PLSA_CALL_PACKAGE_PASSTHROUGH; /* Dispatch tables of functions used by SSP/AP */ struct SECPKG_DLL_FUNCTIONS { PLSA_ALLOCATE_LSA_HEAP AllocateHeap; PLSA_FREE_LSA_HEAP FreeHeap; PLSA_REGISTER_CALLBACK RegisterCallback; } alias SECPKG_DLL_FUNCTIONS* PSECPKG_DLL_FUNCTIONS; struct LSA_DISPATCH_TABLE { PLSA_CREATE_LOGON_SESSION CreateLogonSession; PLSA_DELETE_LOGON_SESSION DeleteLogonSession; PLSA_ADD_CREDENTIAL AddCredential; PLSA_GET_CREDENTIALS GetCredentials; PLSA_DELETE_CREDENTIAL DeleteCredential; PLSA_ALLOCATE_LSA_HEAP AllocateLsaHeap; PLSA_FREE_LSA_HEAP FreeLsaHeap; PLSA_ALLOCATE_CLIENT_BUFFER AllocateClientBuffer; PLSA_FREE_CLIENT_BUFFER FreeClientBuffer; PLSA_COPY_TO_CLIENT_BUFFER CopyToClientBuffer; PLSA_COPY_FROM_CLIENT_BUFFER CopyFromClientBuffer; } alias LSA_DISPATCH_TABLE* PLSA_DISPATCH_TABLE; struct LSA_SECPKG_FUNCTION_TABLE { PLSA_CREATE_LOGON_SESSION CreateLogonSession; PLSA_DELETE_LOGON_SESSION DeleteLogonSession; PLSA_ADD_CREDENTIAL AddCredential; PLSA_GET_CREDENTIALS GetCredentials; PLSA_DELETE_CREDENTIAL DeleteCredential; PLSA_ALLOCATE_LSA_HEAP AllocateLsaHeap; PLSA_FREE_LSA_HEAP FreeLsaHeap; PLSA_ALLOCATE_CLIENT_BUFFER AllocateClientBuffer; PLSA_FREE_CLIENT_BUFFER FreeClientBuffer; PLSA_COPY_TO_CLIENT_BUFFER CopyToClientBuffer; PLSA_COPY_FROM_CLIENT_BUFFER CopyFromClientBuffer; PLSA_IMPERSONATE_CLIENT ImpersonateClient; PLSA_UNLOAD_PACKAGE UnloadPackage; PLSA_DUPLICATE_HANDLE DuplicateHandle; PLSA_SAVE_SUPPLEMENTAL_CREDENTIALS SaveSupplementalCredentials; PLSA_CREATE_THREAD CreateThread; PLSA_GET_CLIENT_INFO GetClientInfo; PLSA_REGISTER_NOTIFICATION RegisterNotification; PLSA_CANCEL_NOTIFICATION CancelNotification; PLSA_MAP_BUFFER MapBuffer; PLSA_CREATE_TOKEN CreateToken; PLSA_AUDIT_LOGON AuditLogon; PLSA_CALL_PACKAGE CallPackage; PLSA_FREE_LSA_HEAP FreeReturnBuffer; PLSA_GET_CALL_INFO GetCallInfo; PLSA_CALL_PACKAGEEX CallPackageEx; PLSA_CREATE_SHARED_MEMORY CreateSharedMemory; PLSA_ALLOCATE_SHARED_MEMORY AllocateSharedMemory; PLSA_FREE_SHARED_MEMORY FreeSharedMemory; PLSA_DELETE_SHARED_MEMORY DeleteSharedMemory; PLSA_OPEN_SAM_USER OpenSamUser; PLSA_GET_USER_CREDENTIALS GetUserCredentials; PLSA_GET_USER_AUTH_DATA GetUserAuthData; PLSA_CLOSE_SAM_USER CloseSamUser; PLSA_CONVERT_AUTH_DATA_TO_TOKEN ConvertAuthDataToToken; PLSA_CLIENT_CALLBACK ClientCallback; PLSA_UPDATE_PRIMARY_CREDENTIALS UpdateCredentials; PLSA_GET_AUTH_DATA_FOR_USER GetAuthDataForUser; PLSA_CRACK_SINGLE_NAME CrackSingleName; PLSA_AUDIT_ACCOUNT_LOGON AuditAccountLogon; PLSA_CALL_PACKAGE_PASSTHROUGH CallPackagePassthrough; } alias LSA_SECPKG_FUNCTION_TABLE* PLSA_SECPKG_FUNCTION_TABLE; /* functions implemented by SSP/AP obtainable by dispatch tables */ alias NTSTATUS function(ULONG, PLSA_DISPATCH_TABLE, PLSA_STRING, PLSA_STRING, PLSA_STRING *) PLSA_AP_INITIALIZE_PACKAGE; alias NTSTATUS function(LPWSTR, LPWSTR, LPWSTR, LPWSTR, DWORD, DWORD, PHANDLE) PLSA_AP_LOGON_USER; alias NTSTATUS function(PUNICODE_STRING, PVOID, ULONG, PVOID *, PULONG, PNTSTATUS) PLSA_AP_CALL_PACKAGE; alias void function(PLUID) PLSA_AP_LOGON_TERMINATED; alias NTSTATUS function(PLSA_CLIENT_REQUEST, PVOID, PVOID, ULONG, PVOID *, PULONG, PNTSTATUS) PLSA_AP_CALL_PACKAGE_UNTRUSTED; alias NTSTATUS function(PUNICODE_STRING, PVOID, PVOID, ULONG, PVOID *, PULONG, PNTSTATUS) PLSA_AP_CALL_PACKAGE_PASSTHROUGH; alias NTSTATUS function(PLSA_CLIENT_REQUEST, SECURITY_LOGON_TYPE, PVOID, PVOID, ULONG, PVOID *, PULONG, PLUID, PNTSTATUS, PLSA_TOKEN_INFORMATION_TYPE, PVOID *, PUNICODE_STRING *, PUNICODE_STRING *, PUNICODE_STRING *) PLSA_AP_LOGON_USER_EX; alias NTSTATUS function(PLSA_CLIENT_REQUEST, SECURITY_LOGON_TYPE, PVOID, PVOID, ULONG, PVOID *, PULONG, PLUID, PNTSTATUS, PLSA_TOKEN_INFORMATION_TYPE, PVOID *, PUNICODE_STRING *, PUNICODE_STRING *, PUNICODE_STRING *, PSECPKG_PRIMARY_CRED, PSECPKG_SUPPLEMENTAL_CRED_ARRAY *) PLSA_AP_LOGON_USER_EX2; alias NTSTATUS function(ULONG_PTR, PSECPKG_PARAMETERS, PLSA_SECPKG_FUNCTION_TABLE) SpInitializeFn; alias NTSTATUS function() SpShutDownFn; alias NTSTATUS function(PSecPkgInfoW) SpGetInfoFn; alias NTSTATUS function(SECURITY_LOGON_TYPE, PUNICODE_STRING, PSECPKG_PRIMARY_CRED, PSECPKG_SUPPLEMENTAL_CRED) SpAcceptCredentialsFn; alias NTSTATUS function(PUNICODE_STRING, ULONG, PLUID, PVOID, PVOID, PVOID, PLSA_SEC_HANDLE, PTimeStamp) SpAcquireCredentialsHandleFn; alias NTSTATUS function(LSA_SEC_HANDLE, ULONG, PVOID) SpQueryCredentialsAttributesFn; alias NTSTATUS function(LSA_SEC_HANDLE) SpFreeCredentialsHandleFn; alias NTSTATUS function(LSA_SEC_HANDLE, PSecBuffer) SpSaveCredentialsFn; alias NTSTATUS function(LSA_SEC_HANDLE, PSecBuffer) SpGetCredentialsFn; alias NTSTATUS function(LSA_SEC_HANDLE, PSecBuffer) SpDeleteCredentialsFn; alias NTSTATUS function(LSA_SEC_HANDLE, LSA_SEC_HANDLE, PUNICODE_STRING, ULONG, ULONG, PSecBufferDesc, PLSA_SEC_HANDLE, PSecBufferDesc, PULONG, PTimeStamp, PBOOLEAN, PSecBuffer) SpInitLsaModeContextFn; alias NTSTATUS function(LSA_SEC_HANDLE, LSA_SEC_HANDLE, PSecBufferDesc, ULONG, ULONG, PLSA_SEC_HANDLE, PSecBufferDesc, PULONG, PTimeStamp, PBOOLEAN, PSecBuffer) SpAcceptLsaModeContextFn; alias NTSTATUS function(LSA_SEC_HANDLE) SpDeleteContextFn; alias NTSTATUS function(LSA_SEC_HANDLE, PSecBufferDesc) SpApplyControlTokenFn; alias NTSTATUS function(PLUID, ULONG, PSecurityUserData *) SpGetUserInfoFn; alias NTSTATUS function(SECPKG_EXTENDED_INFORMATION_CLASS, PSECPKG_EXTENDED_INFORMATION *) SpGetExtendedInformationFn; alias NTSTATUS function(LSA_SEC_HANDLE, ULONG, PVOID) SpQueryContextAttributesFn; alias NTSTATUS function(LSA_SEC_HANDLE, PUNICODE_STRING, PUNICODE_STRING, ULONG, PVOID, PVOID, PVOID, PTimeStamp) SpAddCredentialsFn; alias NTSTATUS function( SECPKG_EXTENDED_INFORMATION_CLASS, PSECPKG_EXTENDED_INFORMATION) SpSetExtendedInformationFn; alias NTSTATUS function(ULONG, PSECPKG_DLL_FUNCTIONS, PVOID *) SpInstanceInitFn; alias NTSTATUS function(LSA_SEC_HANDLE, PSecBuffer) SpInitUserModeContextFn; alias NTSTATUS function(LSA_SEC_HANDLE, ULONG, PSecBufferDesc, ULONG) SpMakeSignatureFn; alias NTSTATUS function(LSA_SEC_HANDLE, PSecBufferDesc, ULONG, PULONG) SpVerifySignatureFn; alias NTSTATUS function(LSA_SEC_HANDLE, ULONG, PSecBufferDesc, ULONG) SpSealMessageFn; alias NTSTATUS function(LSA_SEC_HANDLE, PSecBufferDesc, ULONG, PULONG) SpUnsealMessageFn; alias NTSTATUS function(LSA_SEC_HANDLE, PHANDLE) SpGetContextTokenFn; alias NTSTATUS function(LSA_SEC_HANDLE, PSecBufferDesc) SpCompleteAuthTokenFn; alias NTSTATUS function(PSecBuffer, PSecBuffer) SpFormatCredentialsFn; alias NTSTATUS function(ULONG, PUCHAR, PULONG, PVOID *) SpMarshallSupplementalCredsFn; alias NTSTATUS function(LSA_SEC_HANDLE, ULONG, PSecBuffer, PHANDLE) SpExportSecurityContextFn; alias NTSTATUS function(PSecBuffer, HANDLE, PLSA_SEC_HANDLE) SpImportSecurityContextFn; /* Dispatch tables of functions implemented by SSP/AP */ struct SECPKG_FUNCTION_TABLE { PLSA_AP_INITIALIZE_PACKAGE InitializePackage; PLSA_AP_LOGON_USER LogonUser; PLSA_AP_CALL_PACKAGE CallPackage; PLSA_AP_LOGON_TERMINATED LogonTerminated; PLSA_AP_CALL_PACKAGE_UNTRUSTED CallPackageUntrusted; PLSA_AP_CALL_PACKAGE_PASSTHROUGH CallPackagePassthrough; PLSA_AP_LOGON_USER_EX LogonUserEx; PLSA_AP_LOGON_USER_EX2 LogonUserEx2; SpInitializeFn *Initialize; SpShutDownFn *Shutdown; SpGetInfoFn *GetInfo; SpAcceptCredentialsFn *AcceptCredentials; SpAcquireCredentialsHandleFn *AcquireCredentialsHandle; SpQueryCredentialsAttributesFn *QueryCredentialsAttributes; SpFreeCredentialsHandleFn *FreeCredentialsHandle; SpSaveCredentialsFn *SaveCredentials; SpGetCredentialsFn *GetCredentials; SpDeleteCredentialsFn *DeleteCredentials; SpInitLsaModeContextFn *InitLsaModeContext; SpAcceptLsaModeContextFn *AcceptLsaModeContext; SpDeleteContextFn *DeleteContext; SpApplyControlTokenFn *ApplyControlToken; SpGetUserInfoFn *GetUserInfo; SpGetExtendedInformationFn *GetExtendedInformation; SpQueryContextAttributesFn *QueryContextAttributes; SpAddCredentialsFn *AddCredentials; SpSetExtendedInformationFn *SetExtendedInformation; } alias SECPKG_FUNCTION_TABLE* PSECPKG_FUNCTION_TABLE; struct SECPKG_USER_FUNCTION_TABLE { SpInstanceInitFn *InstanceInit; SpInitUserModeContextFn *InitUserModeContext; SpMakeSignatureFn *MakeSignature; SpVerifySignatureFn *VerifySignature; SpSealMessageFn *SealMessage; SpUnsealMessageFn *UnsealMessage; SpGetContextTokenFn *GetContextToken; SpQueryContextAttributesFn *QueryContextAttributes; SpCompleteAuthTokenFn *CompleteAuthToken; SpDeleteContextFn *DeleteUserModeContext; SpFormatCredentialsFn *FormatCredentials; SpMarshallSupplementalCredsFn *MarshallSupplementalCreds; SpExportSecurityContextFn *ExportContext; SpImportSecurityContextFn *ImportContext; } alias SECPKG_USER_FUNCTION_TABLE* PSECPKG_USER_FUNCTION_TABLE; /* Entry points to SSP/AP */ alias NTSTATUS function(ULONG, PULONG, PSECPKG_FUNCTION_TABLE *, PULONG) SpLsaModeInitializeFn; alias NTSTATUS function(ULONG, PULONG, PSECPKG_USER_FUNCTION_TABLE *, PULONG) SpUserModeInitializeFn; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winioctl.d0000664000175000017500000005761412776214756023524 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winioctl.d) */ module core.sys.windows.winioctl; version (Windows): // FIXME: check types of some constants private import core.sys.windows.basetyps, core.sys.windows.windef; enum size_t HIST_NO_OF_BUCKETS = 24, HISTOGRAM_BUCKET_SIZE = HISTOGRAM_BUCKET.sizeof, DISK_HISTOGRAM_SIZE = DISK_HISTOGRAM.sizeof; alias DWORD DEVICE_TYPE; enum : DEVICE_TYPE { FILE_DEVICE_BEEP = 1, FILE_DEVICE_CD_ROM, FILE_DEVICE_CD_ROM_FILE_SYSTEM, FILE_DEVICE_CONTROLLER, FILE_DEVICE_DATALINK, FILE_DEVICE_DFS, FILE_DEVICE_DISK, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_FILE_SYSTEM, FILE_DEVICE_INPORT_PORT, FILE_DEVICE_KEYBOARD, FILE_DEVICE_MAILSLOT, FILE_DEVICE_MIDI_IN, FILE_DEVICE_MIDI_OUT, FILE_DEVICE_MOUSE, FILE_DEVICE_MULTI_UNC_PROVIDER, FILE_DEVICE_NAMED_PIPE, FILE_DEVICE_NETWORK, FILE_DEVICE_NETWORK_BROWSER, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_NULL, FILE_DEVICE_PARALLEL_PORT, FILE_DEVICE_PHYSICAL_NETCARD, FILE_DEVICE_PRINTER, FILE_DEVICE_SCANNER, FILE_DEVICE_SERIAL_MOUSE_PORT, FILE_DEVICE_SERIAL_PORT, FILE_DEVICE_SCREEN, FILE_DEVICE_SOUND, FILE_DEVICE_STREAMS, FILE_DEVICE_TAPE, FILE_DEVICE_TAPE_FILE_SYSTEM, FILE_DEVICE_TRANSPORT, FILE_DEVICE_UNKNOWN, FILE_DEVICE_VIDEO, FILE_DEVICE_VIRTUAL_DISK, FILE_DEVICE_WAVE_IN, FILE_DEVICE_WAVE_OUT, FILE_DEVICE_8042_PORT, FILE_DEVICE_NETWORK_REDIRECTOR, FILE_DEVICE_BATTERY, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_MODEM, FILE_DEVICE_VDM, FILE_DEVICE_MASS_STORAGE, FILE_DEVICE_SMB, FILE_DEVICE_KS, FILE_DEVICE_CHANGER, FILE_DEVICE_SMARTCARD, FILE_DEVICE_ACPI, FILE_DEVICE_DVD, FILE_DEVICE_FULLSCREEN_VIDEO, FILE_DEVICE_DFS_FILE_SYSTEM, FILE_DEVICE_DFS_VOLUME, FILE_DEVICE_SERENUM, FILE_DEVICE_TERMSRV, FILE_DEVICE_KSEC // = 57 } enum { METHOD_BUFFERED, METHOD_IN_DIRECT, METHOD_OUT_DIRECT, METHOD_NEITHER } enum { FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS = 0, FILE_READ_ACCESS, FILE_WRITE_ACCESS } /* Bit pattern: * tttttttt tttttttt aaffffff ffffffmm */ /+ #define CTL_CODE(t, f, m, a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) +/ template CTL_CODE_T(DEVICE_TYPE t, uint f, uint m, uint a) { enum DWORD CTL_CODE_T = (t << 16) | (a << 14) | (f << 2) | m; } DEVICE_TYPE DEVICE_TYPE_FROM_CTL_CODE(DWORD c) { return (c & 0xFFFF0000) >> 16; } enum DEVICE_TYPE IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE, IOCTL_DISK_BASE = FILE_DEVICE_DISK, IOCTL_VOLUME_BASE = 'V'; enum : DWORD { IOCTL_STORAGE_CHECK_VERIFY = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_STORAGE_CHECK_VERIFY2 = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_STORAGE_MEDIA_REMOVAL = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_STORAGE_EJECT_MEDIA = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_STORAGE_LOAD_MEDIA = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_STORAGE_LOAD_MEDIA2 = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_STORAGE_RESERVE = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_STORAGE_RELEASE = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_STORAGE_FIND_NEW_DEVICES = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_STORAGE_EJECTION_CONTROL = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_STORAGE_MCN_CONTROL = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_STORAGE_GET_MEDIA_TYPES = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_STORAGE_GET_MEDIA_TYPES_EX = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_STORAGE_RESET_BUS = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_STORAGE_RESET_DEVICE = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_STORAGE_GET_DEVICE_NUMBER = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_STORAGE_PREDICT_FAILURE = CTL_CODE_T!(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_GET_DRIVE_GEOMETRY = CTL_CODE_T!(IOCTL_DISK_BASE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_GET_PARTITION_INFO = CTL_CODE_T!(IOCTL_DISK_BASE, 1, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_SET_PARTITION_INFO = CTL_CODE_T!(IOCTL_DISK_BASE, 2, METHOD_BUFFERED, FILE_READ_ACCESS|FILE_WRITE_ACCESS), IOCTL_DISK_GET_DRIVE_LAYOUT = CTL_CODE_T!(IOCTL_DISK_BASE, 3, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_SET_DRIVE_LAYOUT = CTL_CODE_T!(IOCTL_DISK_BASE, 4, METHOD_BUFFERED, FILE_READ_ACCESS|FILE_WRITE_ACCESS), IOCTL_DISK_VERIFY = CTL_CODE_T!(IOCTL_DISK_BASE, 5, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_FORMAT_TRACKS = CTL_CODE_T!(IOCTL_DISK_BASE, 6, METHOD_BUFFERED, FILE_READ_ACCESS|FILE_WRITE_ACCESS), IOCTL_DISK_REASSIGN_BLOCKS = CTL_CODE_T!(IOCTL_DISK_BASE, 7, METHOD_BUFFERED, FILE_READ_ACCESS|FILE_WRITE_ACCESS), IOCTL_DISK_PERFORMANCE = CTL_CODE_T!(IOCTL_DISK_BASE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_IS_WRITABLE = CTL_CODE_T!(IOCTL_DISK_BASE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_LOGGING = CTL_CODE_T!(IOCTL_DISK_BASE, 10, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_FORMAT_TRACKS_EX = CTL_CODE_T!(IOCTL_DISK_BASE, 11, METHOD_BUFFERED, FILE_READ_ACCESS|FILE_WRITE_ACCESS), IOCTL_DISK_HISTOGRAM_STRUCTURE = CTL_CODE_T!(IOCTL_DISK_BASE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_HISTOGRAM_DATA = CTL_CODE_T!(IOCTL_DISK_BASE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_HISTOGRAM_RESET = CTL_CODE_T!(IOCTL_DISK_BASE, 14, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_REQUEST_STRUCTURE = CTL_CODE_T!(IOCTL_DISK_BASE, 15, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_REQUEST_DATA = CTL_CODE_T!(IOCTL_DISK_BASE, 16, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_GET_PARTITION_INFO_EX = CTL_CODE_T!(IOCTL_DISK_BASE, 0x12, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_SET_PARTITION_INFO_EX = CTL_CODE_T!(IOCTL_DISK_BASE, 0x13, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), IOCTL_DISK_GET_DRIVE_LAYOUT_EX = CTL_CODE_T!(IOCTL_DISK_BASE, 0x14, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_SET_DRIVE_LAYOUT_EX = CTL_CODE_T!(IOCTL_DISK_BASE, 0x15, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), IOCTL_DISK_CREATE_DISK = CTL_CODE_T!(IOCTL_DISK_BASE, 0x16, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), IOCTL_DISK_GET_LENGTH_INFO = CTL_CODE_T!(IOCTL_DISK_BASE, 0x17, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_PERFORMANCE_OFF = CTL_CODE_T!(IOCTL_DISK_BASE, 0x18, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_GET_DRIVE_GEOMETRY_EX = CTL_CODE_T!(IOCTL_DISK_BASE, 0x28, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_GROW_PARTITION = CTL_CODE_T!(IOCTL_DISK_BASE, 0x34, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), IOCTL_DISK_GET_CACHE_INFORMATION = CTL_CODE_T!(IOCTL_DISK_BASE, 0x35, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_SET_CACHE_INFORMATION = CTL_CODE_T!(IOCTL_DISK_BASE, 0x36, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), IOCTL_DISK_DELETE_DRIVE_LAYOUT = CTL_CODE_T!(IOCTL_DISK_BASE, 0x40, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), IOCTL_DISK_UPDATE_PROPERTIES = CTL_CODE_T!(IOCTL_DISK_BASE, 0x50, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_CHECK_VERIFY = CTL_CODE_T!(IOCTL_DISK_BASE, 0x200, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_MEDIA_REMOVAL = CTL_CODE_T!(IOCTL_DISK_BASE, 0x201, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_EJECT_MEDIA = CTL_CODE_T!(IOCTL_DISK_BASE, 0x202, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_LOAD_MEDIA = CTL_CODE_T!(IOCTL_DISK_BASE, 0x203, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_RESERVE = CTL_CODE_T!(IOCTL_DISK_BASE, 0x204, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_RELEASE = CTL_CODE_T!(IOCTL_DISK_BASE, 0x205, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_FIND_NEW_DEVICES = CTL_CODE_T!(IOCTL_DISK_BASE, 0x206, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_REMOVE_DEVICE = CTL_CODE_T!(IOCTL_DISK_BASE, 0x207, METHOD_BUFFERED, FILE_READ_ACCESS), IOCTL_DISK_GET_MEDIA_TYPES = CTL_CODE_T!(IOCTL_DISK_BASE, 0x300, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_DISK_UPDATE_DRIVE_SIZE = CTL_CODE_T!(IOCTL_DISK_BASE, 0x0032, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS), IOCTL_SERIAL_LSRMST_INSERT = CTL_CODE_T!(FILE_DEVICE_SERIAL_PORT, 31, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = CTL_CODE_T!(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS), IOCTL_VOLUME_IS_CLUSTERED = CTL_CODE_T!(IOCTL_VOLUME_BASE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_LOCK_VOLUME = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_UNLOCK_VOLUME = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_DISMOUNT_VOLUME = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_MOUNT_DBLS_VOLUME = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 13, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_GET_COMPRESSION = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_SET_COMPRESSION = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA), FSCTL_READ_COMPRESSION = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 17, METHOD_NEITHER, FILE_READ_DATA), FSCTL_WRITE_COMPRESSION = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 18, METHOD_NEITHER, FILE_WRITE_DATA), FSCTL_GET_NTFS_VOLUME_DATA = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 25, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_GET_VOLUME_BITMAP = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 27, METHOD_NEITHER, FILE_ANY_ACCESS), FSCTL_GET_RETRIEVAL_POINTERS = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 28, METHOD_NEITHER, FILE_ANY_ACCESS), FSCTL_MOVE_FILE = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 29, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_GET_REPARSE_POINT = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_SET_REPARSE_POINT = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_DELETE_REPARSE_POINT = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_ANY_ACCESS), FSCTL_SET_SPARSE = CTL_CODE_T!(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_SPECIAL_ACCESS), } enum : BYTE { PARTITION_ENTRY_UNUSED, PARTITION_FAT_12, PARTITION_XENIX_1, PARTITION_XENIX_2, PARTITION_FAT_16, PARTITION_EXTENDED, PARTITION_HUGE, PARTITION_IFS, // = 0x07 PARTITION_FAT32 = 0x0B, PARTITION_FAT32_XINT13 = 0x0C, PARTITION_XINT13 = 0x0E, PARTITION_XINT13_EXTENDED = 0x0F, PARTITION_PREP = 0x41, PARTITION_LDM = 0x42, PARTITION_UNIX = 0x63 } enum BYTE PARTITION_NTFT = 0x80, VALID_NTFT = 0xC0; enum { SERIAL_LSRMST_ESCAPE, SERIAL_LSRMST_LSR_DATA, SERIAL_LSRMST_LSR_NODATA, SERIAL_LSRMST_MST } enum { DISK_LOGGING_START, DISK_LOGGING_STOP, DISK_LOGGING_DUMP, DISK_BINNING } alias WORD BAD_TRACK_NUMBER; alias WORD* PBAD_TRACK_NUMBER; enum BIN_TYPES { RequestSize, RequestLocation } struct BIN_RANGE { LARGE_INTEGER StartValue; LARGE_INTEGER Length; } alias BIN_RANGE* PBIN_RANGE; struct BIN_COUNT { BIN_RANGE BinRange; DWORD BinCount; } alias BIN_COUNT* PBIN_COUNT; struct BIN_RESULTS { DWORD NumberOfBins; BIN_COUNT _BinCounts; BIN_COUNT* BinCounts() return { return &_BinCounts; } } alias BIN_RESULTS* PBIN_RESULTS; enum PARTITION_STYLE { PARTITION_STYLE_MBR, PARTITION_STYLE_GPT, PARTITION_STYLE_RAW } struct CREATE_DISK_GPT { GUID DiskId; DWORD MaxPartitionCount; } alias CREATE_DISK_GPT* PCREATE_DISK_GPT; struct CREATE_DISK_MBR { DWORD Signature; } alias CREATE_DISK_MBR* PCREATE_DISK_MBR; struct CREATE_DISK { PARTITION_STYLE PartitionStyle; union { CREATE_DISK_MBR Mbr; CREATE_DISK_GPT Gpt; } } alias CREATE_DISK* PCREATE_DISK; enum DISK_CACHE_RETENTION_PRIORITY { EqualPriority, KeepPrefetchedData, KeepReadData } struct DISK_CACHE_INFORMATION { BOOLEAN ParametersSavable; BOOLEAN ReadCacheEnabled; BOOLEAN WriteCacheEnabled; DISK_CACHE_RETENTION_PRIORITY ReadRetentionPriority; DISK_CACHE_RETENTION_PRIORITY WriteRetentionPriority; WORD DisablePrefetchTransferLength; BOOLEAN PrefetchScalar; union { struct _ScalarPrefetch { WORD Minimum; WORD Maximum; WORD MaximumBlocks; } _ScalarPrefetch ScalarPrefetch; struct _BlockPrefetch { WORD Minimum; WORD Maximum; } _BlockPrefetch BlockPrefetch; } } alias DISK_CACHE_INFORMATION* PDISK_CACHE_INFORMATION; enum DETECTION_TYPE { DetectNone, DetectInt13, DetectExInt13 } struct DISK_INT13_INFO { WORD DriveSelect; DWORD MaxCylinders; WORD SectorsPerTrack; WORD MaxHeads; WORD NumberDrives; } alias DISK_INT13_INFO* PDISK_INT13_INFO; struct DISK_EX_INT13_INFO { WORD ExBufferSize; WORD ExFlags; DWORD ExCylinders; DWORD ExHeads; DWORD ExSectorsPerTrack; DWORD64 ExSectorsPerDrive; WORD ExSectorSize; WORD ExReserved; } alias DISK_EX_INT13_INFO* PDISK_EX_INT13_INFO; struct DISK_DETECTION_INFO { DWORD SizeOfDetectInfo; DETECTION_TYPE DetectionType; DISK_INT13_INFO Int13; DISK_EX_INT13_INFO ExInt13; } alias DISK_DETECTION_INFO* PDISK_DETECTION_INFO; enum MEDIA_TYPE { Unknown, F5_1Pt2_512, F3_1Pt44_512, F3_2Pt88_512, F3_20Pt8_512, F3_720_512, F5_360_512, F5_320_512, F5_320_1024, F5_180_512, F5_160_512, RemovableMedia, FixedMedia, F3_120M_512, F3_640_512, F5_640_512, F5_720_512, F3_1Pt2_512, F3_1Pt23_1024, F5_1Pt23_1024, F3_128Mb_512, F3_230Mb_512, F8_256_128, F3_200Mb_512, F3_240M_512, F3_32M_512 } alias MEDIA_TYPE* PMEDIA_TYPE; struct DISK_GEOMETRY { LARGE_INTEGER Cylinders; MEDIA_TYPE MediaType; DWORD TracksPerCylinder; DWORD SectorsPerTrack; DWORD BytesPerSector; } alias DISK_GEOMETRY* PDISK_GEOMETRY; struct DISK_GEOMETRY_EX { DISK_GEOMETRY Geometry; LARGE_INTEGER DiskSize; BYTE _Data; BYTE* Data() return { return &_Data; } } alias DISK_GEOMETRY_EX* PDISK_GEOMETRY_EX; struct DISK_GROW_PARTITION { DWORD PartitionNumber; LARGE_INTEGER BytesToGrow; } alias DISK_GROW_PARTITION* PDISK_GROW_PARTITION; struct DISK_PARTITION_INFO { DWORD SizeOfPartitionInfo; PARTITION_STYLE PartitionStyle; union { //struct { DWORD Signature; //} Mbr; //struct { GUID DiskId; //} Gpt; } } alias DISK_PARTITION_INFO* PDISK_PARTITION_INFO; struct DISK_PERFORMANCE { LARGE_INTEGER BytesRead; LARGE_INTEGER BytesWritten; LARGE_INTEGER ReadTime; LARGE_INTEGER WriteTime; DWORD ReadCount; DWORD WriteCount; DWORD QueueDepth; } alias DISK_PERFORMANCE* PDISK_PERFORMANCE; struct DISK_RECORD { LARGE_INTEGER ByteOffset; LARGE_INTEGER StartTime; LARGE_INTEGER EndTime; PVOID VirtualAddress; DWORD NumberOfBytes; BYTE DeviceNumber; BOOLEAN ReadRequest; } alias DISK_RECORD* PDISK_RECORD; struct DISK_LOGGING { BYTE Function; PVOID BufferAddress; DWORD BufferSize; } alias DISK_LOGGING* PDISK_LOGGING; struct DISKQUOTA_USER_INFORMATION { LONGLONG QuotaUsed; LONGLONG QuotaThreshold; LONGLONG QuotaLimit; } alias DISKQUOTA_USER_INFORMATION* PDISKQUOTA_USER_INFORMATION; struct FORMAT_PARAMETERS { MEDIA_TYPE MediaType; DWORD StartCylinderNumber; DWORD EndCylinderNumber; DWORD StartHeadNumber; DWORD EndHeadNumber; } alias FORMAT_PARAMETERS* PFORMAT_PARAMETERS; struct FORMAT_EX_PARAMETERS { MEDIA_TYPE MediaType; DWORD StartCylinderNumber; DWORD EndCylinderNumber; DWORD StartHeadNumber; DWORD EndHeadNumber; WORD FormatGapLength; WORD SectorsPerTrack; WORD _SectorNumber; WORD* SectorNumber() return { return &_SectorNumber; } } alias FORMAT_EX_PARAMETERS* PFORMAT_EX_PARAMETERS; struct GET_LENGTH_INFORMATION { LARGE_INTEGER Length; } struct HISTOGRAM_BUCKET { DWORD Reads; DWORD Writes; } alias HISTOGRAM_BUCKET* PHISTOGRAM_BUCKET; struct DISK_HISTOGRAM { LARGE_INTEGER DiskSize; LARGE_INTEGER Start; LARGE_INTEGER End; LARGE_INTEGER Average; LARGE_INTEGER AverageRead; LARGE_INTEGER AverageWrite; DWORD Granularity; DWORD Size; DWORD ReadCount; DWORD WriteCount; PHISTOGRAM_BUCKET Histogram; } alias DISK_HISTOGRAM* PDISK_HISTOGRAM; struct DISK_EXTENT { DWORD DiskNumber; LARGE_INTEGER StartingOffset; LARGE_INTEGER ExtentLength; } alias DISK_EXTENT* PDISK_EXTENT; struct VOLUME_DISK_EXTENTS { DWORD NumberOfDiskExtents; DISK_EXTENT _Extents; DISK_EXTENT* Extents() return { return &_Extents; } } alias VOLUME_DISK_EXTENTS* PVOLUME_DISK_EXTENTS; struct PARTITION_INFORMATION { LARGE_INTEGER StartingOffset; LARGE_INTEGER PartitionLength; DWORD HiddenSectors; DWORD PartitionNumber; BYTE PartitionType; BOOLEAN BootIndicator; BOOLEAN RecognizedPartition; BOOLEAN RewritePartition; } alias PARTITION_INFORMATION* PPARTITION_INFORMATION; struct DRIVE_LAYOUT_INFORMATION { DWORD PartitionCount; DWORD Signature; PARTITION_INFORMATION _PartitionEntry; PARTITION_INFORMATION* PartitionEntry() return { return &_PartitionEntry; } } alias DRIVE_LAYOUT_INFORMATION* PDRIVE_LAYOUT_INFORMATION; struct DRIVE_LAYOUT_INFORMATION_GPT { GUID DiskId; LARGE_INTEGER StartingUsableOffset; LARGE_INTEGER UsableLength; ULONG MaxPartitionCount; } alias DRIVE_LAYOUT_INFORMATION_GPT* PDRIVE_LAYOUT_INFORMATION_GPT; struct DRIVE_LAYOUT_INFORMATION_MBR { ULONG Signature; } alias DRIVE_LAYOUT_INFORMATION_MBR* PDRIVE_LAYOUT_INFORMATION_MBR; struct PARTITION_INFORMATION_MBR { BYTE PartitionType; BOOLEAN BootIndicator; BOOLEAN RecognizedPartition; DWORD HiddenSectors; } struct PARTITION_INFORMATION_GPT { GUID PartitionType; GUID PartitionId; DWORD64 Attributes; WCHAR[36] Name; } struct PARTITION_INFORMATION_EX { PARTITION_STYLE PartitionStyle; LARGE_INTEGER StartingOffset; LARGE_INTEGER PartitionLength; DWORD PartitionNumber; BOOLEAN RewritePartition; union { PARTITION_INFORMATION_MBR Mbr; PARTITION_INFORMATION_GPT Gpt; } } struct DRIVE_LAYOUT_INFORMATION_EX { DWORD PartitionStyle; DWORD PartitionCount; union { DRIVE_LAYOUT_INFORMATION_MBR Mbr; DRIVE_LAYOUT_INFORMATION_GPT Gpt; } PARTITION_INFORMATION_EX _PartitionEntry; PARTITION_INFORMATION_EX* PartitionEntry() return { return &_PartitionEntry; } } alias DRIVE_LAYOUT_INFORMATION_EX* PDRIVE_LAYOUT_INFORMATION_EX; struct MOVE_FILE_DATA { HANDLE FileHandle; LARGE_INTEGER StartingVcn; LARGE_INTEGER StartingLcn; DWORD ClusterCount; } alias MOVE_FILE_DATA* PMOVE_FILE_DATA; struct PERF_BIN { DWORD NumberOfBins; DWORD TypeOfBin; BIN_RANGE _BinsRanges; BIN_RANGE* BinsRanges() return { return &_BinsRanges; } } alias PERF_BIN* PPERF_BIN; struct PREVENT_MEDIA_REMOVAL { BOOLEAN PreventMediaRemoval; } alias PREVENT_MEDIA_REMOVAL* PPREVENT_MEDIA_REMOVAL; struct RETRIEVAL_POINTERS_BUFFER { DWORD ExtentCount; LARGE_INTEGER StartingVcn; // In MinGW, this is declared as struct { ... } Extents[1]; struct Extent { LARGE_INTEGER NextVcn; LARGE_INTEGER Lcn; } Extent _Extents; Extent* Extents() return { return &_Extents; } } alias RETRIEVAL_POINTERS_BUFFER* PRETRIEVAL_POINTERS_BUFFER; struct REASSIGN_BLOCKS { WORD Reserved; WORD Count; DWORD _BlockNumber; DWORD* BlockNumber() return { return &_BlockNumber; } } alias REASSIGN_BLOCKS* PREASSIGN_BLOCKS; struct SET_PARTITION_INFORMATION { BYTE PartitionType; } alias SET_PARTITION_INFORMATION* PSET_PARTITION_INFORMATION; struct STARTING_LCN_INPUT_BUFFER { LARGE_INTEGER StartingLcn; } alias STARTING_LCN_INPUT_BUFFER* PSTARTING_LCN_INPUT_BUFFER; struct STARTING_VCN_INPUT_BUFFER { LARGE_INTEGER StartingVcn; } alias STARTING_VCN_INPUT_BUFFER* PSTARTING_VCN_INPUT_BUFFER; struct VERIFY_INFORMATION { LARGE_INTEGER StartingOffset; DWORD Length; } alias VERIFY_INFORMATION* PVERIFY_INFORMATION; struct VOLUME_BITMAP_BUFFER { LARGE_INTEGER StartingLcn; LARGE_INTEGER BitmapSize; BYTE _Buffer; BYTE* Buffer() return { return &_Buffer; } } alias VOLUME_BITMAP_BUFFER* PVOLUME_BITMAP_BUFFER; struct NTFS_VOLUME_DATA_BUFFER { LARGE_INTEGER VolumeSerialNumber; LARGE_INTEGER NumberSectors; LARGE_INTEGER TotalClusters; LARGE_INTEGER FreeClusters; LARGE_INTEGER TotalReserved; DWORD BytesPerSector; DWORD BytesPerCluster; DWORD BytesPerFileRecordSegment; DWORD ClustersPerFileRecordSegment; LARGE_INTEGER MftValidDataLength; LARGE_INTEGER MftStartLcn; LARGE_INTEGER Mft2StartLcn; LARGE_INTEGER MftZoneStart; LARGE_INTEGER MftZoneEnd; } alias NTFS_VOLUME_DATA_BUFFER* PNTFS_VOLUME_DATA_BUFFER; bool IsRecognizedPartition(BYTE t) { return ((t & PARTITION_NTFT) && ((t & ~VALID_NTFT) == PARTITION_FAT_12 || (t & ~VALID_NTFT) == PARTITION_FAT_16 || (t & ~VALID_NTFT) == PARTITION_IFS || (t & ~VALID_NTFT) == PARTITION_HUGE || (t & ~VALID_NTFT) == PARTITION_FAT32 || (t & ~VALID_NTFT) == PARTITION_FAT32_XINT13 || (t & ~VALID_NTFT) == PARTITION_XINT13)) || (t & ~PARTITION_NTFT) == PARTITION_FAT_12 || (t & ~PARTITION_NTFT) == PARTITION_FAT_16 || (t & ~PARTITION_NTFT) == PARTITION_IFS || (t & ~PARTITION_NTFT) == PARTITION_HUGE || (t & ~PARTITION_NTFT) == PARTITION_FAT32 || (t & ~PARTITION_NTFT) == PARTITION_FAT32_XINT13 || (t & ~PARTITION_NTFT) == PARTITION_XINT13; } bool IsContainerPartition(BYTE t) { return ((t & PARTITION_NTFT) && ((t & ~VALID_NTFT) == PARTITION_EXTENDED || (t & ~VALID_NTFT) == PARTITION_XINT13_EXTENDED)) || (t & ~PARTITION_NTFT) == PARTITION_EXTENDED || (t & ~PARTITION_NTFT) == PARTITION_XINT13_EXTENDED; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/shlobj.d0000664000175000017500000012713712776214756023153 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 4.0 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_shlobj.d) */ module core.sys.windows.shlobj; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "shell32"); // TODO: fix bitfields // TODO: CMIC_VALID_SEE_FLAGS // SHGetFolderPath in shfolder.dll on W9x, NT4, also in shell32.dll on W2K import core.sys.windows.commctrl, core.sys.windows.ole2, core.sys.windows.shlguid, core.sys.windows.shellapi; private import core.sys.windows.prsht, core.sys.windows.unknwn, core.sys.windows.w32api, core.sys.windows.winbase, core.sys.windows.winnt, core.sys.windows.winuser, core.sys.windows.wtypes, core.sys.windows.objfwd, core.sys.windows.objidl; private import core.sys.windows.winnetwk; // for NETRESOURCE private import core.sys.windows.oaidl : VARIANT; // FIXME: clean up Windows version support align(1): enum BIF_RETURNONLYFSDIRS = 1; enum BIF_DONTGOBELOWDOMAIN = 2; enum BIF_STATUSTEXT = 4; enum BIF_RETURNFSANCESTORS = 8; enum BIF_EDITBOX = 16; enum BIF_VALIDATE = 32; enum BIF_NEWDIALOGSTYLE = 64; enum BIF_BROWSEINCLUDEURLS = 128; enum BIF_USENEWUI = BIF_EDITBOX | BIF_NEWDIALOGSTYLE; enum BIF_BROWSEFORCOMPUTER = 0x1000; enum BIF_BROWSEFORPRINTER = 0x2000; enum BIF_BROWSEINCLUDEFILES = 0x4000; enum BIF_SHAREABLE = 0x8000; enum BFFM_INITIALIZED = 1; enum BFFM_SELCHANGED = 2; enum BFFM_VALIDATEFAILEDA = 3; enum BFFM_VALIDATEFAILEDW = 4; enum BFFM_SETSTATUSTEXTA = WM_USER + 100; enum BFFM_ENABLEOK = WM_USER + 101; enum BFFM_SETSELECTIONA = WM_USER + 102; enum BFFM_SETSELECTIONW = WM_USER + 103; enum BFFM_SETSTATUSTEXTW = WM_USER + 104; enum BFFM_SETOKTEXT = WM_USER + 105; enum BFFM_SETEXPANDED = WM_USER + 106; version(Unicode) { alias BFFM_SETSTATUSTEXTW BFFM_SETSTATUSTEXT; alias BFFM_SETSELECTIONW BFFM_SETSELECTION; alias BFFM_VALIDATEFAILEDW BFFM_VALIDATEFAILED; } else { alias BFFM_SETSTATUSTEXTA BFFM_SETSTATUSTEXT; alias BFFM_SETSELECTIONA BFFM_SETSELECTION; alias BFFM_VALIDATEFAILEDA BFFM_VALIDATEFAILED; } enum DVASPECT_SHORTNAME = 2; enum SHARD { SHARD_PIDL = 1, SHARD_PATHA, SHARD_PATHW, SHARD_APPIDINFO, SHARD_APPIDINFOIDLIST, SHARD_LINK, SHARD_APPIDINFOLINK, SHARD_SHELLITEM, // = 8 SHARD_PATH = (_WIN32_UNICODE ? SHARD_PATHW : SHARD_PATHA) } enum SHCNE_RENAMEITEM = 1; enum SHCNE_CREATE = 2; enum SHCNE_DELETE = 4; enum SHCNE_MKDIR = 8; enum SHCNE_RMDIR = 16; enum SHCNE_MEDIAINSERTED = 32; enum SHCNE_MEDIAREMOVED = 64; enum SHCNE_DRIVEREMOVED = 128; enum SHCNE_DRIVEADD = 256; enum SHCNE_NETSHARE = 512; enum SHCNE_NETUNSHARE = 1024; enum SHCNE_ATTRIBUTES = 2048; enum SHCNE_UPDATEDIR = 4096; enum SHCNE_UPDATEITEM = 8192; enum SHCNE_SERVERDISCONNECT = 16384; enum SHCNE_UPDATEIMAGE = 32768; enum SHCNE_DRIVEADDGUI = 65536; enum SHCNE_RENAMEFOLDER = 0x20000; enum SHCNE_FREESPACE = 0x40000; enum SHCNE_ASSOCCHANGED = 0x8000000; enum SHCNE_DISKEVENTS = 0x2381F; enum SHCNE_GLOBALEVENTS = 0xC0581E0; enum SHCNE_ALLEVENTS = 0x7FFFFFFF; enum SHCNE_INTERRUPT = 0x80000000; enum SHCNF_IDLIST = 0; enum SHCNF_PATHA = 1; enum SHCNF_PRINTERA = 2; enum SHCNF_DWORD = 3; enum SHCNF_PATHW = 5; enum SHCNF_PRINTERW = 6; enum SHCNF_TYPE = 0xFF; enum SHCNF_FLUSH = 0x1000; enum SHCNF_FLUSHNOWAIT = 0x2000; version(Unicode) { alias SHCNF_PATHW SHCNF_PATH; alias SHCNF_PRINTERW SHCNF_PRINTER; } else { alias SHCNF_PATHA SHCNF_PATH; alias SHCNF_PRINTERA SHCNF_PRINTER; } enum SFGAOF : DWORD { SFGAO_CANCOPY = DROPEFFECT.DROPEFFECT_COPY, SFGAO_CANMOVE = DROPEFFECT.DROPEFFECT_MOVE, SFGAO_CANLINK = DROPEFFECT.DROPEFFECT_LINK, SFGAO_CANRENAME = 0x00000010L, SFGAO_CANDELETE = 0x00000020L, SFGAO_HASPROPSHEET = 0x00000040L, SFGAO_DROPTARGET = 0x00000100L, SFGAO_CAPABILITYMASK = 0x00000177L, SFGAO_ISSLOW = 0x00004000L, SFGAO_GHOSTED = 0x00008000L, SFGAO_LINK = 0x00010000L, SFGAO_SHARE = 0x00020000L, SFGAO_READONLY = 0x00040000L, SFGAO_HIDDEN = 0x00080000L, SFGAO_DISPLAYATTRMASK = (SFGAO_ISSLOW | SFGAO_GHOSTED | SFGAO_LINK | SFGAO_SHARE | SFGAO_READONLY | SFGAO_HIDDEN), SFGAO_FILESYSANCESTOR = 0x10000000L, SFGAO_FOLDER = 0x20000000L, SFGAO_FILESYSTEM = 0x40000000L, SFGAO_HASSUBFOLDER = 0x80000000L, SFGAO_CONTENTSMASK = 0x80000000L, SFGAO_VALIDATE = 0x01000000L, SFGAO_REMOVABLE = 0x02000000L, SFGAO_COMPRESSED = 0x04000000L } enum STRRET_WSTR = 0; enum STRRET_OFFSET = 1; enum STRRET_CSTR = 2; enum { SHGDFIL_FINDDATA = 1, SHGDFIL_NETRESOURCE, SHGDFIL_DESCRIPTIONID } enum { SHDID_ROOT_REGITEM = 1, SHDID_FS_FILE, SHDID_FS_DIRECTORY, SHDID_FS_OTHER, SHDID_COMPUTER_DRIVE35, SHDID_COMPUTER_DRIVE525, SHDID_COMPUTER_REMOVABLE, SHDID_COMPUTER_FIXED, SHDID_COMPUTER_NETDRIVE, SHDID_COMPUTER_CDROM, SHDID_COMPUTER_RAMDISK, SHDID_COMPUTER_OTHER, SHDID_NET_DOMAIN, SHDID_NET_SERVER, SHDID_NET_SHARE, SHDID_NET_RESTOFNET, SHDID_NET_OTHER } const TCHAR[] REGSTR_PATH_EXPLORER = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"; const TCHAR[] REGSTR_PATH_SPECIAL_FOLDERS=REGSTR_PATH_EXPLORER ~ "\\Shell Folders"; enum { CSIDL_DESKTOP = 0, CSIDL_INTERNET, CSIDL_PROGRAMS, CSIDL_CONTROLS, CSIDL_PRINTERS, CSIDL_PERSONAL, CSIDL_FAVORITES, CSIDL_STARTUP, CSIDL_RECENT, CSIDL_SENDTO, CSIDL_BITBUCKET, CSIDL_STARTMENU, // = 11 CSIDL_MYMUSIC = 13, CSIDL_MYVIDEO, // = 14 CSIDL_DESKTOPDIRECTORY = 16, CSIDL_DRIVES, CSIDL_NETWORK, CSIDL_NETHOOD, CSIDL_FONTS, CSIDL_TEMPLATES, CSIDL_COMMON_STARTMENU, CSIDL_COMMON_PROGRAMS, CSIDL_COMMON_STARTUP, CSIDL_COMMON_DESKTOPDIRECTORY, CSIDL_APPDATA, CSIDL_PRINTHOOD, CSIDL_LOCAL_APPDATA, CSIDL_ALTSTARTUP, CSIDL_COMMON_ALTSTARTUP, CSIDL_COMMON_FAVORITES, CSIDL_INTERNET_CACHE, CSIDL_COOKIES, CSIDL_HISTORY, CSIDL_COMMON_APPDATA, CSIDL_WINDOWS, CSIDL_SYSTEM, CSIDL_PROGRAM_FILES, CSIDL_MYPICTURES, CSIDL_PROFILE, CSIDL_SYSTEMX86, CSIDL_PROGRAM_FILESX86, CSIDL_PROGRAM_FILES_COMMON, CSIDL_PROGRAM_FILES_COMMONX86, CSIDL_COMMON_TEMPLATES, CSIDL_COMMON_DOCUMENTS, CSIDL_COMMON_ADMINTOOLS, CSIDL_ADMINTOOLS, CSIDL_CONNECTIONS, // = 49 CSIDL_COMMON_MUSIC = 53, CSIDL_COMMON_PICTURES, CSIDL_COMMON_VIDEO, CSIDL_RESOURCES, CSIDL_RESOURCES_LOCALIZED, CSIDL_COMMON_OEM_LINKS, CSIDL_CDBURN_AREA, // = 59 CSIDL_COMPUTERSNEARME = 61, CSIDL_FLAG_DONT_VERIFY = 0x4000, CSIDL_FLAG_CREATE = 0x8000, CSIDL_FLAG_MASK = 0xFF00 } const TCHAR[] CFSTR_SHELLIDLIST = "Shell IDList Array", CFSTR_SHELLIDLISTOFFSET = "Shell Object Offsets", CFSTR_NETRESOURCES = "Net Resource", CFSTR_FILECONTENTS = "FileContents", CFSTR_FILENAMEA = "FileName", CFSTR_FILENAMEMAPA = "FileNameMap", CFSTR_FILEDESCRIPTORA = "FileGroupDescriptor", CFSTR_INETURLA = "UniformResourceLocator", CFSTR_SHELLURL = CFSTR_INETURLA, CFSTR_FILENAMEW = "FileNameW", CFSTR_FILENAMEMAPW = "FileNameMapW", CFSTR_FILEDESCRIPTORW = "FileGroupDescriptorW", CFSTR_INETURLW = "UniformResourceLocatorW"; version(Unicode) { alias CFSTR_FILENAMEW CFSTR_FILENAME; alias CFSTR_FILENAMEMAPW CFSTR_FILENAMEMAP; alias CFSTR_FILEDESCRIPTORW CFSTR_FILEDESCRIPTOR; alias CFSTR_INETURLW CFSTR_INETURL; } else { alias CFSTR_FILENAMEA CFSTR_FILENAME; alias CFSTR_FILENAMEMAPA CFSTR_FILENAMEMAP; alias CFSTR_FILEDESCRIPTORA CFSTR_FILEDESCRIPTOR; alias CFSTR_INETURLA CFSTR_INETURL; } const TCHAR[] CFSTR_PRINTERGROUP = "PrinterFriendlyName", CFSTR_INDRAGLOOP = "InShellDragLoop", CFSTR_PASTESUCCEEDED = "Paste Succeeded", CFSTR_PERFORMEDDROPEFFECT = "Performed DropEffect", CFSTR_PREFERREDDROPEFFECT = "Preferred DropEffect"; enum CMF_NORMAL=0; enum CMF_DEFAULTONLY=1; enum CMF_VERBSONLY=2; enum CMF_EXPLORE=4; enum CMF_NOVERBS=8; enum CMF_CANRENAME=16; enum CMF_NODEFAULT=32; enum CMF_INCLUDESTATIC=64; enum CMF_RESERVED=0xffff0000; enum GCS_VERBA=0; enum GCS_HELPTEXTA=1; enum GCS_VALIDATEA=2; enum GCS_VERBW=4; enum GCS_HELPTEXTW=5; enum GCS_VALIDATEW=6; enum GCS_UNICODE=4; version(Unicode) { alias GCS_VERBW GCS_VERB; alias GCS_HELPTEXTW GCS_HELPTEXT; alias GCS_VALIDATEW GCS_VALIDATE; } else { alias GCS_VERBA GCS_VERB; alias GCS_HELPTEXTA GCS_HELPTEXT; alias GCS_VALIDATEA GCS_VALIDATE; } const TCHAR[] CMDSTR_NEWFOLDER = "NewFolder", CMDSTR_VIEWLIST = "ViewList", CMDSTR_VIEWDETAILS = "ViewDetails"; enum CMIC_MASK_HOTKEY = SEE_MASK_HOTKEY; enum CMIC_MASK_ICON = SEE_MASK_ICON; enum CMIC_MASK_FLAG_NO_UI = SEE_MASK_FLAG_NO_UI; enum CMIC_MASK_MODAL = 0x80000000; // TODO: This isn't defined anywhere in MinGW. //const CMIC_VALID_SEE_FLAGS=SEE_VALID_CMIC_FLAGS; enum GIL_OPENICON = 1; enum GIL_FORSHELL = 2; enum GIL_SIMULATEDOC = 1; enum GIL_PERINSTANCE = 2; enum GIL_PERCLASS = 4; enum GIL_NOTFILENAME = 8; enum GIL_DONTCACHE = 16; enum FVSIF_RECT = 1; enum FVSIF_PINNED = 2; enum FVSIF_NEWFAILED = 0x8000000; enum FVSIF_NEWFILE = 0x80000000; enum FVSIF_CANVIEWIT = 0x40000000; enum CDBOSC_SETFOCUS = 0; enum CDBOSC_KILLFOCUS = 1; enum CDBOSC_SELCHANGE = 2; enum CDBOSC_RENAME = 3; enum FCIDM_SHVIEWFIRST = 0; enum FCIDM_SHVIEWLAST = 0x7fff; enum FCIDM_BROWSERFIRST = 0xa000; enum FCIDM_BROWSERLAST = 0xbf00; enum FCIDM_GLOBALFIRST = 0x8000; enum FCIDM_GLOBALLAST = 0x9fff; enum FCIDM_MENU_FILE = FCIDM_GLOBALFIRST; enum FCIDM_MENU_EDIT = FCIDM_GLOBALFIRST+0x0040; enum FCIDM_MENU_VIEW = FCIDM_GLOBALFIRST+0x0080; enum FCIDM_MENU_VIEW_SEP_OPTIONS = FCIDM_GLOBALFIRST+0x0081; enum FCIDM_MENU_TOOLS = FCIDM_GLOBALFIRST+0x00c0; enum FCIDM_MENU_TOOLS_SEP_GOTO = FCIDM_GLOBALFIRST+0x00c1; enum FCIDM_MENU_HELP = FCIDM_GLOBALFIRST+0x0100; enum FCIDM_MENU_FIND = FCIDM_GLOBALFIRST+0x0140; enum FCIDM_MENU_EXPLORE = FCIDM_GLOBALFIRST+0x0150; enum FCIDM_MENU_FAVORITES = FCIDM_GLOBALFIRST+0x0170; enum FCIDM_TOOLBAR = FCIDM_BROWSERFIRST; enum FCIDM_STATUS = FCIDM_BROWSERFIRST+1; enum SBSP_DEFBROWSER = 0; enum SBSP_SAMEBROWSER = 1; enum SBSP_NEWBROWSER = 2; enum SBSP_DEFMODE = 0; enum SBSP_OPENMODE = 16; enum SBSP_EXPLOREMODE = 32; enum SBSP_ABSOLUTE = 0; enum SBSP_RELATIVE = 0x1000; enum SBSP_PARENT = 0x2000; enum SBSP_INITIATEDBYHLINKFRAME = 0x80000000; enum SBSP_REDIRECT = 0x40000000; enum { FCW_STATUS=1, FCW_TOOLBAR, FCW_TREE } enum FCT_MERGE=1; enum FCT_CONFIGABLE=2; enum FCT_ADDTOEND=4; enum SVSI_DESELECT=0; enum SVSI_SELECT=1; enum SVSI_EDIT=3; enum SVSI_DESELECTOTHERS=4; enum SVSI_ENSUREVISIBLE=8; enum SVSI_FOCUSED=16; enum SVGIO_BACKGROUND=0; enum SVGIO_SELECTION=1; enum SVGIO_ALLVIEW=2; enum UINT SV2GV_CURRENTVIEW=-1; enum UINT SV2GV_DEFAULTVIEW=-2; alias DWORD SHGDNF; struct CIDA { UINT cidl; UINT[1] aoffset; } alias CIDA* LPIDA; struct SHITEMID { USHORT cb; BYTE[1] abID; } alias SHITEMID* LPSHITEMID; alias const(SHITEMID)* LPCSHITEMID; struct ITEMIDLIST { SHITEMID mkid; } alias ITEMIDLIST* LPITEMIDLIST; alias const(ITEMIDLIST)* LPCITEMIDLIST; alias int function(HWND, UINT, LPARAM, LPARAM) BFFCALLBACK; struct BROWSEINFOA { HWND hwndOwner; LPCITEMIDLIST pidlRoot; LPSTR pszDisplayName; LPCSTR lpszTitle; UINT ulFlags; BFFCALLBACK lpfn; LPARAM lParam; int iImage; } alias BROWSEINFOA* PBROWSEINFOA, LPBROWSEINFOA; struct BROWSEINFOW { HWND hwndOwner; LPCITEMIDLIST pidlRoot; LPWSTR pszDisplayName; LPCWSTR lpszTitle; UINT ulFlags; BFFCALLBACK lpfn; LPARAM lParam; int iImage; } alias BROWSEINFOW* PBROWSEINFOW, LPBROWSEINFOW; struct CMINVOKECOMMANDINFO { DWORD cbSize = this.sizeof; DWORD fMask; HWND hwnd; LPCSTR lpVerb; LPCSTR lpParameters; LPCSTR lpDirectory; int nShow; DWORD dwHotKey; HANDLE hIcon; } alias CMINVOKECOMMANDINFO* LPCMINVOKECOMMANDINFO; struct DROPFILES { DWORD pFiles; POINT pt; BOOL fNC; BOOL fWide; } alias DROPFILES* LPDROPFILES; enum SHGNO { SHGDN_NORMAL = 0, SHGDN_INFOLDER, SHGDN_FOREDITING = 0x1000, SHGDN_INCLUDE_NONFILESYS = 0x2000, SHGDN_FORADDRESSBAR = 0x4000, SHGDN_FORPARSING = 0x8000 } enum SHCONTF { SHCONTF_FOLDERS = 32, SHCONTF_NONFOLDERS = 64, SHCONTF_INCLUDEHIDDEN = 128, SHCONTF_INIT_ON_FIRST_NEXT = 256, SHCONTF_NETPRINTERSRCH = 512, SHCONTF_SHAREABLE = 1024, SHCONTF_STORAGE = 2048 } struct STRRET { UINT uType; union { LPWSTR pOleStr; UINT uOffset; char[MAX_PATH] cStr; } } alias STRRET* LPSTRRET; enum FD_FLAGS { FD_CLSID = 1, FD_SIZEPOINT = 2, FD_ATTRIBUTES = 4, FD_CREATETIME = 8, FD_ACCESSTIME = 16, FD_WRITESTIME = 32, FD_FILESIZE = 64, FD_LINKUI = 0x8000 } struct FILEDESCRIPTORA { DWORD dwFlags; CLSID clsid; SIZEL sizel; POINTL pointl; DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; CHAR[MAX_PATH] cFileName; } alias FILEDESCRIPTORA* LPFILEDESCRIPTORA; struct FILEDESCRIPTORW { DWORD dwFlags; CLSID clsid; SIZEL sizel; POINTL pointl; DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; WCHAR[MAX_PATH] cFileName; } alias FILEDESCRIPTORW* LPFILEDESCRIPTORW; struct FILEGROUPDESCRIPTORA { UINT cItems; FILEDESCRIPTORA[1] fgd; } alias FILEGROUPDESCRIPTORA* LPFILEGROUPDESCRIPTORA; struct FILEGROUPDESCRIPTORW { UINT cItems; FILEDESCRIPTORW[1] fgd; } alias FILEGROUPDESCRIPTORW* LPFILEGROUPDESCRIPTORW; enum SLR_FLAGS { SLR_NO_UI = 1, SLR_ANY_MATCH = 2, SLR_UPDATE = 4, SLR_NOUPDATE = 8, SLR_NOSEARCH = 16, SLR_NOTRACK = 32, SLR_NOLINKINFO = 64, SLR_INVOKE_MSI = 128 } enum SLGP_FLAGS { SLGP_SHORTPATH=1, SLGP_UNCPRIORITY=2, SLGP_RAWPATH=4 } alias PBYTE LPVIEWSETTINGS; enum FOLDERFLAGS { FWF_AUTOARRANGE = 1, FWF_ABBREVIATEDNAMES = 2, FWF_SNAPTOGRID = 4, FWF_OWNERDATA = 8, FWF_BESTFITWINDOW = 16, FWF_DESKTOP = 32, FWF_SINGLESEL = 64, FWF_NOSUBFOLDERS = 128, FWF_TRANSPARENT = 256, FWF_NOCLIENTEDGE = 512, FWF_NOSCROLL = 0x400, FWF_ALIGNLEFT = 0x800, FWF_SINGLECLICKACTIVATE = 0x8000 } enum FOLDERVIEWMODE { FVM_ICON = 1, FVM_SMALLICON, FVM_LIST, FVM_DETAILS } struct FOLDERSETTINGS { UINT ViewMode; UINT fFlags; } alias FOLDERSETTINGS* LPFOLDERSETTINGS; alias const(FOLDERSETTINGS)* LPCFOLDERSETTINGS; struct FVSHOWINFO { DWORD cbSize = this.sizeof; HWND hwndOwner; int iShow; DWORD dwFlags; RECT rect; LPUNKNOWN punkRel; OLECHAR[MAX_PATH] strNewFile; } alias FVSHOWINFO* LPFVSHOWINFO; struct NRESARRAY { UINT cItems; NETRESOURCE[1] nr; } alias NRESARRAY* LPNRESARRAY; enum { SBSC_HIDE, SBSC_SHOW, SBSC_TOGGLE, SBSC_QUERY } enum { SBCMDID_ENABLESHOWTREE, SBCMDID_SHOWCONTROL, SBCMDID_CANCELNAVIGATION, SBCMDID_MAYSAVECHANGES, SBCMDID_SETHLINKFRAME, SBCMDID_ENABLESTOP, SBCMDID_OPTIONS } enum SVUIA_STATUS { SVUIA_DEACTIVATE, SVUIA_ACTIVATE_NOFOCUS, SVUIA_ACTIVATE_FOCUS, SVUIA_INPLACEACTIVATE } static if (_WIN32_IE >= 0x500) { struct EXTRASEARCH { GUID guidSearch; WCHAR[80] wszFriendlyName; WCHAR[2084] wszUrl; } alias EXTRASEARCH* LPEXTRASEARCH; alias DWORD SHCOLSTATEF; struct SHCOLUMNID { GUID fmtid; DWORD pid; } alias SHCOLUMNID* LPSHCOLUMNID; alias const(SHCOLUMNID)* LPCSHCOLUMNID; struct SHELLDETAILS { int fmt; int cxChar; STRRET str; } alias SHELLDETAILS* LPSHELLDETAILS; struct PERSIST_FOLDER_TARGET_INFO { LPITEMIDLIST pidlTargetFolder; WCHAR[MAX_PATH] szTargetParsingName; WCHAR[MAX_PATH] szNetworkProvider; DWORD dwAttributes; int csidl; } enum SHGFP_TYPE { SHGFP_TYPE_CURRENT = 0, SHGFP_TYPE_DEFAULT = 1, } } interface IEnumIDList : IUnknown { HRESULT Next(ULONG, LPITEMIDLIST*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumIDList*); } alias IEnumIDList LPENUMIDLIST; interface IObjMgr : IUnknown { HRESULT Append(IUnknown); HRESULT Remove(IUnknown); } interface IContextMenu : IUnknown { HRESULT QueryContextMenu(HMENU, UINT, UINT, UINT, UINT); HRESULT InvokeCommand(LPCMINVOKECOMMANDINFO); HRESULT GetCommandString(UINT, UINT, PUINT, LPSTR, UINT); } alias IContextMenu LPCONTEXTMENU; interface IContextMenu2 : IContextMenu { HRESULT HandleMenuMsg(UINT, WPARAM, LPARAM); }; alias IContextMenu2 LPCONTEXTMENU2; static if (_WIN32_IE >= 0x500) { align(8) { struct SHCOLUMNINIT { ULONG dwFlags; ULONG dwReserved; WCHAR[MAX_PATH] wszFolder; } alias SHCOLUMNINIT* LPSHCOLUMNINIT; alias const(SHCOLUMNINIT)* LPCSHCOLUMNINIT; struct SHCOLUMNDATA { ULONG dwFlags; DWORD dwFileAttributes; ULONG dwReserved; WCHAR *pwszExt; WCHAR[MAX_PATH] wszFile; } alias SHCOLUMNDATA* LPSHCOLUMNDATA; alias const(SHCOLUMNDATA)* LPCSHCOLUMNDATA; } enum MAX_COLUMN_NAME_LEN = 80; enum MAX_COLUMN_DESC_LEN = 128; align(1) struct SHCOLUMNINFO { SHCOLUMNID scid; VARTYPE vt; DWORD fmt; UINT cChars; DWORD csFlags; WCHAR[MAX_COLUMN_NAME_LEN] wszTitle; WCHAR[MAX_COLUMN_DESC_LEN] wszDescription; } alias SHCOLUMNINFO* LPSHCOLUMNINFO; alias const(SHCOLUMNINFO)* LPCSHCOLUMNINFO; enum SHCOLSTATE { SHCOLSTATE_TYPE_STR = 0x00000001, SHCOLSTATE_TYPE_INT = 0x00000002, SHCOLSTATE_TYPE_DATE = 0x00000003, SHCOLSTATE_TYPEMASK = 0x0000000f, SHCOLSTATE_ONBYDEFAULT = 0x00000010, SHCOLSTATE_SLOW = 0x00000020, SHCOLSTATE_EXTENDED = 0x00000040, SHCOLSTATE_SECONDARYUI = 0x00000080, SHCOLSTATE_HIDDEN = 0x00000100, SHCOLSTATE_PREFER_VARCMP = 0x00000200 } interface IColumnProvider : IUnknown { HRESULT Initialize(LPCSHCOLUMNINIT); HRESULT GetColumnInfo(DWORD, SHCOLUMNINFO*); HRESULT GetItemData(LPCSHCOLUMNID, LPCSHCOLUMNDATA, VARIANT*); } }/* _WIN32_IE >= 0x500 */ interface IQueryInfo : IUnknown { HRESULT GetInfoTip(DWORD, WCHAR**); HRESULT GetInfoFlags(DWORD*); } interface IShellExtInit : IUnknown { HRESULT Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY); } alias IShellExtInit LPSHELLEXTINIT; interface IShellPropSheetExt : IUnknown { HRESULT AddPages(LPFNADDPROPSHEETPAGE, LPARAM); HRESULT ReplacePage(UINT, LPFNADDPROPSHEETPAGE, LPARAM); } alias IShellPropSheetExt LPSHELLPROPSHEETEXT; interface IExtractIconA : IUnknown { HRESULT GetIconLocation(UINT, LPSTR, UINT, int*, PUINT); HRESULT Extract(LPCSTR, UINT, HICON*, HICON*, UINT); }; alias IExtractIconA LPEXTRACTICONA; interface IExtractIconW : IUnknown { HRESULT GetIconLocation(UINT, LPWSTR, UINT, int*, PUINT); HRESULT Extract(LPCWSTR, UINT, HICON*, HICON*, UINT); } alias IExtractIconW LPEXTRACTICONW; version(Unicode) { alias IExtractIconW IExtractIcon; alias LPEXTRACTICONW LPEXTRACTICON; } else { alias IExtractIconA IExtractIcon; alias LPEXTRACTICONA LPEXTRACTICON; } interface IShellLinkA : IUnknown { HRESULT GetPath(LPSTR, int, WIN32_FIND_DATAA*, DWORD); HRESULT GetIDList(LPITEMIDLIST*); HRESULT SetIDList(LPCITEMIDLIST); HRESULT GetDescription(LPSTR, int); HRESULT SetDescription(LPCSTR); HRESULT GetWorkingDirectory(LPSTR, int); HRESULT SetWorkingDirectory(LPCSTR); HRESULT GetArguments(LPSTR, int); HRESULT SetArguments(LPCSTR); HRESULT GetHotkey(PWORD); HRESULT SetHotkey(WORD); HRESULT GetShowCmd(int*); HRESULT SetShowCmd(int); HRESULT GetIconLocation(LPSTR, int, int*); HRESULT SetIconLocation(LPCSTR, int); HRESULT SetRelativePath(LPCSTR , DWORD); HRESULT Resolve(HWND, DWORD); HRESULT SetPath(LPCSTR); } interface IShellLinkW : IUnknown { HRESULT GetPath(LPWSTR, int, WIN32_FIND_DATAW*, DWORD); HRESULT GetIDList(LPITEMIDLIST*); HRESULT SetIDList(LPCITEMIDLIST); HRESULT GetDescription(LPWSTR, int); HRESULT SetDescription(LPCWSTR); HRESULT GetWorkingDirectory(LPWSTR, int); HRESULT SetWorkingDirectory(LPCWSTR); HRESULT GetArguments(LPWSTR, int); HRESULT SetArguments(LPCWSTR); HRESULT GetHotkey(PWORD); HRESULT SetHotkey(WORD); HRESULT GetShowCmd(int*); HRESULT SetShowCmd(int); HRESULT GetIconLocation(LPWSTR, int, int*); HRESULT SetIconLocation(LPCWSTR, int); HRESULT SetRelativePath(LPCWSTR , DWORD); HRESULT Resolve(HWND, DWORD); HRESULT SetPath(LPCWSTR); } interface IShellFolder : IUnknown { HRESULT ParseDisplayName(HWND, LPBC, LPOLESTR, PULONG, LPITEMIDLIST*, PULONG); HRESULT EnumObjects(HWND, DWORD, LPENUMIDLIST*); HRESULT BindToObject(LPCITEMIDLIST, LPBC, REFIID, PVOID*); HRESULT BindToStorage(LPCITEMIDLIST, LPBC, REFIID, PVOID*); HRESULT CompareIDs(LPARAM, LPCITEMIDLIST, LPCITEMIDLIST); HRESULT CreateViewObject(HWND, REFIID, PVOID*); HRESULT GetAttributesOf(UINT, LPCITEMIDLIST*, PULONG); HRESULT GetUIObjectOf(HWND, UINT, LPCITEMIDLIST*, REFIID, PUINT, PVOID*); HRESULT GetDisplayNameOf(LPCITEMIDLIST, DWORD, LPSTRRET); HRESULT SetNameOf(HWND, LPCITEMIDLIST, LPCOLESTR, DWORD, LPITEMIDLIST*); } alias IShellFolder LPSHELLFOLDER; static if (_WIN32_IE >= 0x500) { interface IEnumExtraSearch: IUnknown { HRESULT Next(ULONG, LPEXTRASEARCH*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumExtraSearch*); } alias IEnumExtraSearch LPENUMEXTRASEARCH; interface IShellFolder2 : IShellFolder { HRESULT ParseDisplayName(HWND, LPBC, LPOLESTR, PULONG, LPITEMIDLIST*, PULONG); HRESULT EnumObjects(HWND, DWORD, LPENUMIDLIST*); HRESULT BindToObject(LPCITEMIDLIST, LPBC, REFIID, PVOID*); HRESULT BindToStorage(LPCITEMIDLIST, LPBC, REFIID, PVOID*); HRESULT CompareIDs(LPARAM, LPCITEMIDLIST, LPCITEMIDLIST); HRESULT CreateViewObject(HWND, REFIID, PVOID*); HRESULT GetAttributesOf(UINT, LPCITEMIDLIST*, PULONG); HRESULT GetUIObjectOf(HWND, UINT, LPCITEMIDLIST*, REFIID, PUINT, PVOID*); HRESULT GetDisplayNameOf(LPCITEMIDLIST, DWORD, LPSTRRET); HRESULT SetNameOf(HWND, LPCITEMIDLIST, LPCOLESTR, DWORD, LPITEMIDLIST*); HRESULT GetDefaultSearchGUID(GUID*); HRESULT EnumSearches(IEnumExtraSearch*); HRESULT GetDefaultColumn(DWORD, ULONG*, ULONG*); HRESULT GetDefaultColumnState(UINT, SHCOLSTATEF*); HRESULT GetDetailsEx(LPCITEMIDLIST, const(SHCOLUMNID)*, VARIANT*); HRESULT GetDetailsOf(LPCITEMIDLIST, UINT, SHELLDETAILS*); HRESULT MapColumnToSCID(UINT, SHCOLUMNID*); } alias IShellFolder2 LPSHELLFOLDER2; } /* _WIN32_IE >= 0x500 */ interface ICopyHook : IUnknown { UINT CopyCallback(HWND, UINT, UINT, LPCSTR, DWORD, LPCSTR, DWORD); } alias ICopyHook LPCOPYHOOK; interface IFileViewerSite : IUnknown { HRESULT SetPinnedWindow(HWND); HRESULT GetPinnedWindow(HWND*); } alias IFileViewerSite LPFILEVIEWERSITE; interface IFileViewer : IUnknown { HRESULT ShowInitialize(LPFILEVIEWERSITE); HRESULT Show(LPFVSHOWINFO); HRESULT PrintTo(LPSTR, BOOL); } alias IFileViewer LPFILEVIEWER; interface IFileSystemBindData : IUnknown { HRESULT SetFindData(const(WIN32_FIND_DATAW)*); HRESULT GetFindData(WIN32_FIND_DATAW*); } interface IPersistFolder : IPersist { HRESULT GetClassID(CLSID*); HRESULT Initialize(LPCITEMIDLIST); } alias IPersistFolder LPPERSISTFOLDER; static if (_WIN32_IE >= 0x400 || _WIN32_WINNT >= 0x500) { interface IPersistFolder2 : IPersistFolder { HRESULT GetClassID(CLSID*); HRESULT Initialize(LPCITEMIDLIST); HRESULT GetCurFolder(LPITEMIDLIST*); } alias IPersistFolder2 LPPERSISTFOLDER2; }/* _WIN32_IE >= 0x400 || _WIN32_WINNT >= 0x500 */ static if (_WIN32_IE >= 0x500) { interface IPersistFolder3 : IPersistFolder2 { HRESULT GetClassID(CLSID*); HRESULT Initialize(LPCITEMIDLIST); HRESULT GetCurFolder(LPITEMIDLIST*); HRESULT InitializeEx(IBindCtx, LPCITEMIDLIST, const(PERSIST_FOLDER_TARGET_INFO)*); HRESULT GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO*); } alias IPersistFolder3 LPPERSISTFOLDER3; } /* _WIN32_IE >= 0x500 */ alias IShellBrowser LPSHELLBROWSER; alias IShellView LPSHELLVIEW; interface IShellBrowser : IOleWindow { HRESULT GetWindow(HWND*); HRESULT ContextSensitiveHelp(BOOL); HRESULT InsertMenusSB(HMENU, LPOLEMENUGROUPWIDTHS); HRESULT SetMenuSB(HMENU, HOLEMENU, HWND); HRESULT RemoveMenusSB(HMENU); HRESULT SetStatusTextSB(LPCOLESTR); HRESULT EnableModelessSB(BOOL); HRESULT TranslateAcceleratorSB(LPMSG, WORD); HRESULT BrowseObject(LPCITEMIDLIST, UINT); HRESULT GetViewStateStream(DWORD, LPSTREAM*); HRESULT GetControlWindow(UINT, HWND*); HRESULT SendControlMsg(UINT, UINT, WPARAM, LPARAM, LRESULT*); HRESULT QueryActiveShellView(LPSHELLVIEW*); HRESULT OnViewWindowActive(LPSHELLVIEW); HRESULT SetToolbarItems(LPTBBUTTON, UINT, UINT); } interface IShellView : IOleWindow { HRESULT GetWindow(HWND*); HRESULT ContextSensitiveHelp(BOOL); HRESULT TranslateAccelerator(LPMSG); //[No] #ifdef _FIX_ENABLEMODELESS_CONFLICT //[No] STDMETHOD(EnableModelessSV)(THIS_ BOOL) PURE; //[Yes] #else HRESULT EnableModeless(BOOL); //[Yes] #endif HRESULT UIActivate(UINT); HRESULT Refresh(); HRESULT CreateViewWindow(IShellView, LPCFOLDERSETTINGS, LPSHELLBROWSER, RECT*, HWND*); HRESULT DestroyViewWindow(); HRESULT GetCurrentInfo(LPFOLDERSETTINGS); HRESULT AddPropertySheetPages(DWORD, LPFNADDPROPSHEETPAGE, LPARAM); HRESULT SaveViewState(); HRESULT SelectItem(LPCITEMIDLIST, UINT); HRESULT GetItemObject(UINT, REFIID, PVOID*); } interface ICommDlgBrowser : IUnknown { HRESULT OnDefaultCommand(IShellView); HRESULT OnStateChange(IShellView, ULONG); HRESULT IncludeObject(IShellView, LPCITEMIDLIST); } alias ICommDlgBrowser LPCOMMDLGBROWSER; alias GUID SHELLVIEWID; struct SV2CVW2_PARAMS { DWORD cbSize = this.sizeof; IShellView psvPrev; FOLDERSETTINGS *pfs; IShellBrowser psbOwner; RECT *prcView; const(SHELLVIEWID)* pvid; HWND hwndView; } alias SV2CVW2_PARAMS* LPSV2CVW2_PARAMS; interface IShellView2 : IShellView { HRESULT GetWindow(HWND*); HRESULT ContextSensitiveHelp(BOOL); HRESULT TranslateAccelerator(LPMSG); //[No] #ifdef _FIX_ENABLEMODELESS_CONFLICT //[No] STDMETHOD(EnableModelessSV)(THIS_ BOOL) PURE; //[Yes] #else HRESULT EnableModeless(BOOL); //[Yes] #endif HRESULT UIActivate(UINT); HRESULT Refresh(); HRESULT CreateViewWindow(IShellView, LPCFOLDERSETTINGS, LPSHELLBROWSER, RECT*, HWND*); HRESULT DestroyViewWindow(); HRESULT GetCurrentInfo(LPFOLDERSETTINGS); HRESULT AddPropertySheetPages(DWORD, LPFNADDPROPSHEETPAGE, LPARAM); HRESULT SaveViewState(); HRESULT SelectItem(LPCITEMIDLIST, UINT); HRESULT GetItemObject(UINT, REFIID, PVOID*); HRESULT GetView(SHELLVIEWID*, ULONG); HRESULT CreateViewWindow2(LPSV2CVW2_PARAMS); } interface IShellExecuteHookA : IUnknown { HRESULT Execute(LPSHELLEXECUTEINFOA); } interface IShellExecuteHookW : IUnknown { HRESULT Execute(LPSHELLEXECUTEINFOW); } interface IShellIcon : IUnknown { HRESULT GetIconOf(LPCITEMIDLIST, UINT, PINT); } alias IShellIcon LPSHELLICON; struct SHELLFLAGSTATE { short _bf; /* BOOL fShowAllObjects : 1; BOOL fShowExtensions : 1; BOOL fNoConfirmRecycle : 1; BOOL fShowSysFiles : 1; BOOL fShowCompColor : 1; BOOL fDoubleClickInWebView : 1; BOOL fDesktopHTML : 1; BOOL fWin95Classic : 1; BOOL fDontPrettyPath : 1; BOOL fShowAttribCol : 1; BOOL fMapNetDrvBtn : 1; BOOL fShowInfoTip : 1; BOOL fHideIcons : 1; UINT fRestFlags : 3; */ @property bool fShowAllObjects() { return cast(bool) (_bf & 0x0001); } @property bool fShowExtensions() { return cast(bool) (_bf & 0x0002); } @property bool fNoConfirmRecycle() { return cast(bool) (_bf & 0x0004); } @property bool fShowSysFiles() { return cast(bool) (_bf & 0x0008); } @property bool fShowCompColor() { return cast(bool) (_bf & 0x0010); } @property bool fDoubleClickInWebView() { return cast(bool) (_bf & 0x0020); } @property bool fDesktopHTML() { return cast(bool) (_bf & 0x0040); } @property bool fWin95Classic() { return cast(bool) (_bf & 0x0080); } @property bool fDontPrettyPath() { return cast(bool) (_bf & 0x0100); } @property bool fShowAttribCol() { return cast(bool) (_bf & 0x0200); } @property bool fMapNetDrvBtn() { return cast(bool) (_bf & 0x0400); } @property bool fShowInfoTip() { return cast(bool) (_bf & 0x0800); } @property bool fHideIcons() { return cast(bool) (_bf & 0x1000); } @property ubyte fRestFlags() { return cast(ubyte) (_bf >> 13); } @property bool fShowAllObjects(bool f) { _bf = cast(ushort) ((_bf & ~0xFFFE) | f); return f; } @property bool fShowExtensions(bool f) { _bf = cast(ushort) ((_bf & ~0xFFFD) | (f << 1)); return f; } @property bool fNoConfirmRecycle(bool f) { _bf = cast(ushort) ((_bf & ~0xFFFB) | (f << 2)); return f; } @property bool fShowSysFiles(bool f) { _bf = cast(ushort) ((_bf & ~0xFFF8) | (f << 3)); return f; } @property bool fShowCompColor(bool f) { _bf = cast(ushort) ((_bf & ~0xFFEF) | (f << 4)); return f; } @property bool fDoubleClickInWebView(bool f) { _bf = cast(ushort) ((_bf & ~0xFFDF) | (f << 5)); return f; } @property bool fDesktopHTML(bool f) { _bf = cast(ushort) ((_bf & ~0xFFBF) | (f << 6)); return f; } @property bool fWin95Classic(bool f) { _bf = cast(ushort) ((_bf & ~0xFF8F) | (f << 7)); return f; } @property bool fDontPrettyPath(bool f) { _bf = cast(ushort) ((_bf & ~0xFEFF) | (f << 8)); return f; } @property bool fShowAttribCol(bool f) { _bf = cast(ushort) ((_bf & ~0xFDFF) | (f << 9)); return f; } @property bool fMapNetDrvBtn(bool f) { _bf = cast(ushort) ((_bf & ~0xFBFF) | (f << 10)); return f; } @property bool fShowInfoTip(bool f) { _bf = cast(ushort) ((_bf & ~0xF8FF) | (f << 11)); return f; } @property bool fHideIcons(bool f) { _bf = cast(ushort) ((_bf & ~0xEFFF) | (f << 12)); return f; } @property ubyte fRestFlags(ubyte f) { _bf = cast(ushort) ((_bf & ~0x1FFF) | (f << 13)); return cast(ubyte) (f & 7); } } alias SHELLFLAGSTATE* LPSHELLFLAGSTATE; enum SSF_SHOWALLOBJECTS = 0x1; enum SSF_SHOWEXTENSIONS = 0x2; enum SSF_SHOWCOMPCOLOR = 0x8; enum SSF_SHOWSYSFILES = 0x20; enum SSF_DOUBLECLICKINWEBVIEW = 0x80; enum SSF_SHOWATTRIBCOL = 0x100; enum SSF_DESKTOPHTML = 0x200; enum SSF_WIN95CLASSIC = 0x400; enum SSF_DONTPRETTYPATH = 0x800; enum SSF_MAPNETDRVBUTTON = 0x1000; enum SSF_SHOWINFOTIP = 0x2000; enum SSF_HIDEICONS = 0x4000; enum SSF_NOCONFIRMRECYCLE = 0x8000; interface IShellIconOverlayIdentifier : IUnknown { HRESULT IsMemberOf(LPCWSTR, DWORD); HRESULT GetOverlayInfo(LPWSTR, int, int*, DWORD*); HRESULT GetPriority(int*); } enum ISIOI_ICONFILE = 0x00000001; enum ISIOI_ICONINDEX = 0x00000002; static if (_WIN32_WINNT >= 0x500) { struct SHELLSTATE { uint _bf1; DWORD dwWin95Unused; UINT uWin95Unused; LONG lParamSort; int iSortDirection; UINT _version; UINT uNotUsed; uint _bf2; /* BOOL fShowAllObjects : 1; BOOL fShowExtensions : 1; BOOL fNoConfirmRecycle : 1; BOOL fShowSysFiles : 1; BOOL fShowCompColor : 1; BOOL fDoubleClickInWebView : 1; BOOL fDesktopHTML : 1; BOOL fWin95Classic : 1; BOOL fDontPrettyPath : 1; BOOL fShowAttribCol : 1; BOOL fMapNetDrvBtn : 1; BOOL fShowInfoTip : 1; BOOL fHideIcons : 1; BOOL fWebView : 1; BOOL fFilter : 1; BOOL fShowSuperHidden : 1; BOOL fNoNetCrawling : 1; */ @property bool fShowAllObjects() { return cast(bool) (_bf1 & 0x00000001); } @property bool fShowExtensions() { return cast(bool) (_bf1 & 0x00000002); } @property bool fNoConfirmRecycle() { return cast(bool) (_bf1 & 0x00000004); } @property bool fShowSysFiles() { return cast(bool) (_bf1 & 0x00000008); } @property bool fShowCompColor() { return cast(bool) (_bf1 & 0x00000010); } @property bool fDoubleClickInWebView() { return cast(bool) (_bf1 & 0x00000020); } @property bool fDesktopHTML() { return cast(bool) (_bf1 & 0x00000040); } @property bool fWin95Classic() { return cast(bool) (_bf1 & 0x00000080); } @property bool fDontPrettyPath() { return cast(bool) (_bf1 & 0x00000100); } @property bool fShowAttribCol() { return cast(bool) (_bf1 & 0x00000200); } @property bool fMapNetDrvBtn() { return cast(bool) (_bf1 & 0x00000400); } @property bool fShowInfoTip() { return cast(bool) (_bf1 & 0x00000800); } @property bool fHideIcons() { return cast(bool) (_bf1 & 0x00001000); } @property bool fWebView() { return cast(bool) (_bf1 & 0x00002000); } @property bool fFilter() { return cast(bool) (_bf1 & 0x00004000); } @property bool fShowSuperHidden() { return cast(bool) (_bf1 & 0x00008000); } @property bool fNoNetCrawling() { return cast(bool) (_bf1 & 0x00010000); } @property bool fShowAllObjects(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFFFE) | f); return f; } @property bool fShowExtensions(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFFFD) | (f << 1)); return f; } @property bool fNoConfirmRecycle(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFFFB) | (f << 2)); return f; } @property bool fShowSysFiles(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFFF8) | (f << 3)); return f; } @property bool fShowCompColor(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFFEF) | (f << 4)); return f; } @property bool fDoubleClickInWebView(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFFDF) | (f << 5)); return f; } @property bool fDesktopHTML(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFFBF) | (f << 6)); return f; } @property bool fWin95Classic(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFF8F) | (f << 7)); return f; } @property bool fDontPrettyPath(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFEFF) | (f << 8)); return f; } @property bool fShowAttribCol(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFDFF) | (f << 9)); return f; } @property bool fMapNetDrvBtn(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFFBFF) | (f << 10)); return f; } @property bool fShowInfoTip(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFF8FF) | (f << 11)); return f; } @property bool fHideIcons(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFEFFF) | (f << 12)); return f; } @property bool fWebView(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFDFFF) | (f << 13)); return f; } @property bool fFilter(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFFBFFF) | (f << 14)); return f; } @property bool fShowSuperHidden(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFF8FFF) | (f << 15)); return f; } @property bool fNoNetCrawling(bool f) { _bf1 = cast(uint) ((_bf1 & ~0xFFFEFFFF) | (f << 16)); return f; } /* BOOL fSepProcess : 1; BOOL fStartPanelOn : 1; BOOL fShowStartPage : 1; UINT fSpareFlags : 13; */ @property bool fSepProcess() { return cast(bool) (_bf2 & 0x00000001); } @property bool fStartPanelOn() { return cast(bool) (_bf2 & 0x00000002); } @property bool fShowStartPage() { return cast(bool) (_bf2 & 0x00000004); } @property ushort fSpareFlags() { return cast(ushort) ((_bf2 & 0x0000FFF8) >> 3); } @property bool fSepProcess(bool f) { _bf2 = cast(uint) ((_bf2 & ~0xFFFFFFFE) | f); return f; } @property bool fStartPanelOn(bool f) { _bf2 = cast(uint) ((_bf2 & ~0xFFFFFFFD) | (f << 1)); return f; } @property bool fShowStartPage(bool f) { _bf2 = cast(uint) ((_bf2 & ~0xFFFFFFFB) | (f << 2)); return f; } @property ushort fSpareFlags(ushort f) { _bf2 = cast(ushort) ((_bf2 & ~0xFFFF0007) | ((f & 0x1FFF) << 3)); return cast(ushort) (f & 0x1FFF); } } alias SHELLSTATE* LPSHELLSTATE; } static if (_WIN32_IE >= 0x500) { align(8) { struct SHDRAGIMAGE { SIZE sizeDragImage; POINT ptOffset; HBITMAP hbmpDragImage; COLORREF crColorKey; } alias SHDRAGIMAGE* LPSHDRAGIMAGE; } interface IDragSourceHelper : IUnknown { HRESULT InitializeFromBitmap(LPSHDRAGIMAGE pshdi, IDataObject pDataObject); HRESULT InitializeFromWindow(HWND hwnd, POINT* ppt, IDataObject pDataObject); } interface IDropTargetHelper : IUnknown { HRESULT DragEnter(HWND hwndTarget, IDataObject pDataObject, POINT* ppt, DWORD dwEffect); HRESULT DragLeave(); HRESULT DragOver(POINT* ppt, DWORD dwEffect); HRESULT Drop(IDataObject pDataObject, POINT* ppt, DWORD dwEffect); HRESULT Show(BOOL fShow); } } extern (Windows): void SHAddToRecentDocs(UINT, PCVOID); LPITEMIDLIST SHBrowseForFolderA(PBROWSEINFOA); LPITEMIDLIST SHBrowseForFolderW(PBROWSEINFOW); void SHChangeNotify(LONG, UINT, PCVOID, PCVOID); HRESULT SHGetDataFromIDListA(LPSHELLFOLDER, LPCITEMIDLIST, int, PVOID, int); HRESULT SHGetDataFromIDListW(LPSHELLFOLDER, LPCITEMIDLIST, int, PVOID, int); HRESULT SHGetDesktopFolder(LPSHELLFOLDER*); HRESULT SHGetInstanceExplorer(IUnknown*); HRESULT SHGetMalloc(LPMALLOC*); BOOL SHGetPathFromIDListA(LPCITEMIDLIST, LPSTR); BOOL SHGetPathFromIDListW(LPCITEMIDLIST, LPWSTR); HRESULT SHGetSpecialFolderLocation(HWND, int, LPITEMIDLIST*); HRESULT SHLoadInProc(REFCLSID); static if (_WIN32_IE >= 0x400) { BOOL SHGetSpecialFolderPathA(HWND, LPSTR, int, BOOL); BOOL SHGetSpecialFolderPathW(HWND, LPWSTR, int, BOOL); } /* SHGetFolderPath in shfolder.dll on W9x, NT4, also in shell32.dll on W2K */ HRESULT SHGetFolderPathA(HWND, int, HANDLE, DWORD, LPSTR); HRESULT SHGetFolderPathW(HWND, int, HANDLE, DWORD, LPWSTR); static if (_WIN32_WINNT >= 0x500) { INT SHGetIconOverlayIndexW(LPCWSTR pszIconPath, int iIconIndex); INT SHGetIconOverlayIndexA(LPCSTR pszIconPath, int iIconIndex); HRESULT SHGetFolderLocation(HWND, int, HANDLE, DWORD, LPITEMIDLIST*); INT SHCreateDirectoryExA(HWND, LPCSTR, LPSECURITY_ATTRIBUTES); INT SHCreateDirectoryExW(HWND, LPCWSTR, LPSECURITY_ATTRIBUTES); HRESULT SHBindToParent(LPCITEMIDLIST, REFIID, VOID**, LPCITEMIDLIST*); } static if (_WIN32_WINNT >= 0x501) { enum { PRF_VERIFYEXISTS = 0x0001, PRF_TRYPROGRAMEXTENSIONS = (0x0002 | PRF_VERIFYEXISTS), PRF_FIRSTDIRDEF = 0x0004, PRF_DONTFINDLNK = 0x0008, IDO_SHGIOI_SHARE = 0x0FFFFFFF, IDO_SHGIOI_LINK = 0x0FFFFFFE, IDO_SHGIOI_SLOWFILE = 0x0FFFFFFD, IDO_SHGIOI_DEFAULT = 0x0FFFFFFC } struct SHDESCRIPTIONID { DWORD dwDescriptionId; CLSID clsid; } alias SHDESCRIPTIONID* LPSHDESCRIPTIONID; BOOL PathResolve(LPWSTR, LPCWSTR*, UINT); HRESULT SHGetFolderPathAndSubDirA(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR); HRESULT SHGetFolderPathAndSubDirW(HWND, int, HANDLE, DWORD, LPCWSTR, LPWSTR); HRESULT SHParseDisplayName(LPCWSTR, IBindCtx, LPITEMIDLIST, SFGAOF, SFGAOF*); } void SHGetSettings(LPSHELLFLAGSTATE, DWORD); static if (_WIN32_WINNT >= 0x500) { void SHGetSetSettings(LPSHELLSTATE, DWORD, BOOL); BOOL ILIsEqual(LPCITEMIDLIST, LPCITEMIDLIST); BOOL ILIsParent(LPCITEMIDLIST, LPCITEMIDLIST, BOOL); BOOL ILRemoveLastID(LPITEMIDLIST); HRESULT ILLoadFromStream(IStream, LPITEMIDLIST*); HRESULT ILSaveToStream(IStream, LPCITEMIDLIST); LPITEMIDLIST ILAppendID(LPITEMIDLIST, LPCSHITEMID, BOOL); LPITEMIDLIST ILClone(LPCITEMIDLIST); LPITEMIDLIST ILCloneFirst(LPCITEMIDLIST); LPITEMIDLIST ILCombine(LPCITEMIDLIST, LPCITEMIDLIST); LPITEMIDLIST ILFindChild(LPCITEMIDLIST, LPCITEMIDLIST); LPITEMIDLIST ILFindLastID(LPCITEMIDLIST); LPITEMIDLIST ILGetNext(LPCITEMIDLIST); UINT ILGetSize(LPCITEMIDLIST); void ILFree(LPITEMIDLIST); HRESULT SHCoCreateInstance(LPCWSTR, REFCLSID, IUnknown, REFIID, void**); } version(Unicode) { alias IShellExecuteHookW IShellExecuteHook; alias IShellLinkW IShellLink; alias BROWSEINFOW BROWSEINFO; alias SHBrowseForFolderW SHBrowseForFolder; alias SHGetDataFromIDListW SHGetDataFromIDList; alias SHGetPathFromIDListW SHGetPathFromIDList; static if (_WIN32_IE >= 0x400) { alias SHGetSpecialFolderPathW SHGetSpecialFolderPath; } alias SHGetFolderPathW SHGetFolderPath; static if (_WIN32_WINNT >= 0x500) { alias SHGetIconOverlayIndexW SHGetIconOverlayIndex; alias SHCreateDirectoryExW SHCreateDirectoryEx; } static if (_WIN32_WINNT >= 0x501) { alias SHGetFolderPathAndSubDirW SHGetFolderPathAndSubDir; } alias FILEDESCRIPTORW FILEDESCRIPTOR; alias LPFILEDESCRIPTORW LPFILEDESCRIPTOR; alias FILEGROUPDESCRIPTORW FILEGROUPDESCRIPTOR; alias LPFILEGROUPDESCRIPTORW LPFILEGROUPDESCRIPTOR; } else { alias IShellExecuteHookA IShellExecuteHook; alias IShellLinkA IShellLink; alias BROWSEINFOA BROWSEINFO; alias SHBrowseForFolderA SHBrowseForFolder; alias SHGetDataFromIDListA SHGetDataFromIDList; alias SHGetPathFromIDListA SHGetPathFromIDList; static if (_WIN32_IE >= 0x400) { alias SHGetSpecialFolderPathA SHGetSpecialFolderPath; } alias SHGetFolderPathA SHGetFolderPath; static if (_WIN32_WINNT >= 0x500) { alias SHGetIconOverlayIndexA SHGetIconOverlayIndex; alias SHCreateDirectoryExA SHCreateDirectoryEx; } static if (_WIN32_WINNT >= 0x501) { alias SHGetFolderPathAndSubDirA SHGetFolderPathAndSubDir; } alias FILEDESCRIPTORA FILEDESCRIPTOR; alias LPFILEDESCRIPTORA LPFILEDESCRIPTOR; alias FILEGROUPDESCRIPTORA FILEGROUPDESCRIPTOR; alias LPFILEGROUPDESCRIPTORA LPFILEGROUPDESCRIPTOR; } alias BROWSEINFO* PBROWSEINFO, LPBROWSEINFO; static if (_WIN32_WINNT >= 0x501) { interface IFolderView : IUnknown { HRESULT GetAutoArrange(); HRESULT GetCurrentViewMode(UINT); HRESULT GetDefaultSpacing(POINT*); HRESULT GetFocusedItem(int*); HRESULT GetFolder(REFIID, PVOID*); HRESULT GetItemPosition(LPCITEMIDLIST, POINT*); HRESULT GetSelectionMarkedItem(int*); HRESULT GetSpacing(POINT*); HRESULT Item(int, LPITEMIDLIST*); HRESULT ItemCount(UINT, int*); HRESULT Items(UINT, REFIID, PVOID*); HRESULT SelectAndPositionItems(UINT, LPCITEMIDLIST*, POINT*, DWORD); HRESULT SelectItem(int, DWORD); HRESULT SetCurrentViewMode(UINT); } alias IFolderView LPFOLDERVIEW; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/stat.d0000664000175000017500000000213512776214756022633 0ustar kaikai /// $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) /// Author: Walter Bright module core.sys.windows.stat; version (Windows): extern (C) nothrow @nogc: // Posix version is in core.sys.posix.sys.stat enum S_IFMT = 0xF000; enum S_IFDIR = 0x4000; enum S_IFCHR = 0x2000; enum S_IFIFO = 0x1000; enum S_IFREG = 0x8000; enum S_IREAD = 0x0100; enum S_IWRITE = 0x0080; enum S_IEXEC = 0x0040; enum S_IFBLK = 0x6000; enum S_IFNAM = 0x5000; @safe pure { int S_ISREG(int m) { return (m & S_IFMT) == S_IFREG; } int S_ISBLK(int m) { return (m & S_IFMT) == S_IFBLK; } int S_ISNAM(int m) { return (m & S_IFMT) == S_IFNAM; } int S_ISDIR(int m) { return (m & S_IFMT) == S_IFDIR; } int S_ISCHR(int m) { return (m & S_IFMT) == S_IFCHR; } } struct struct_stat { short st_dev; ushort st_ino; ushort st_mode; short st_nlink; ushort st_uid; ushort st_gid; short st_rdev; short dummy; int st_size; int st_atime; int st_mtime; int st_ctime; } int stat(char *, struct_stat *); int fstat(int, struct_stat *) @trusted; int _wstat(wchar *, struct_stat *); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/unknwn.d0000664000175000017500000000377712776214756023215 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_unknwn.d) */ module core.sys.windows.unknwn; version (Windows): import core.sys.windows.objfwd, core.sys.windows.windef, core.sys.windows.wtypes; private import core.sys.windows.basetyps; extern (Windows) { void* MIDL_user_allocate(size_t); void MIDL_user_free(void*); } extern (Windows) { interface IUnknown { HRESULT QueryInterface(IID* riid, void** pvObject); ULONG AddRef(); ULONG Release(); } alias IUnknown LPUNKNOWN; interface IClassFactory : IUnknown { HRESULT CreateInstance(IUnknown UnkOuter, IID* riid, void** pvObject); HRESULT LockServer(BOOL fLock); } alias IClassFactory LPCLASSFACTORY; /+ // These do not seem to be necessary (or desirable) for D. HRESULT IUnknown_QueryInterface_Proxy(IUnknown,REFIID,void**); ULONG IUnknown_AddRef_Proxy(IUnknown); ULONG IUnknown_Release_Proxy(IUnknown); HRESULT IClassFactory_RemoteCreateInstance_Proxy(IClassFactory,REFIID,IUnknown*); HRESULT IClassFactory_RemoteLockServer_Proxy(IClassFactory,BOOL); HRESULT IClassFactory_CreateInstance_Proxy(IClassFactory,IUnknown,REFIID,void**); HRESULT IClassFactory_CreateInstance_Stub(IClassFactory,REFIID,IUnknown*); HRESULT IClassFactory_LockServer_Proxy(IClassFactory,BOOL); HRESULT IClassFactory_LockServer_Stub(IClassFactory,BOOL); void IUnknown_QueryInterface_Stub(LPRPCSTUBBUFFER,LPRPCCHANNELBUFFER,PRPC_MESSAGE,PDWORD); void IUnknown_AddRef_Stub(LPRPCSTUBBUFFER,LPRPCCHANNELBUFFER,PRPC_MESSAGE,PDWORD); void IUnknown_Release_Stub(LPRPCSTUBBUFFER,LPRPCCHANNELBUFFER,PRPC_MESSAGE,PDWORD); void IClassFactory_RemoteCreateInstance_Stub(LPRPCSTUBBUFFER,LPRPCCHANNELBUFFER,PRPC_MESSAGE,PDWORD); void IClassFactory_RemoteLockServer_Stub(LPRPCSTUBBUFFER,LPRPCCHANNELBUFFER,PRPC_MESSAGE,PDWORD); +/ } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmchdev.d0000664000175000017500000000530712776214756023306 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmchdev.d) */ module core.sys.windows.lmchdev; version (Windows): // COMMENT: This file might be deprecated. private import core.sys.windows.lmcons, core.sys.windows.windef; enum CHARDEVQ_NO_REQUESTS = -1; enum CHARDEV_CLOSE = 0; enum CHARDEVQ_MAX_PRIORITY = 1; enum CHARDEVQ_DEV_PARMNUM = 1; enum HANDLE_INFO_LEVEL_1 = 1; enum HANDLE_CHARTIME_PARMNUM = 1; enum HANDLE_CHARCOUNT_PARMNUM = 2; enum CHARDEV_STAT_OPENED = 2; enum CHARDEVQ_PRIORITY_PARMNUM = 2; enum CHARDEVQ_DEVS_PARMNUM = 3; enum CHARDEV_STAT_ERROR = 4; enum CHARDEVQ_NUMUSERS_PARMNUM = 4; enum CHARDEVQ_NUMAHEAD_PARMNUM = 5; enum CHARDEVQ_DEF_PRIORITY = 5; enum CHARDEVQ_PRIORITY_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+CHARDEVQ_PRIORITY_PARMNUM; enum CHARDEVQ_DEVS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+CHARDEVQ_DEVS_PARMNUM; enum CHARDEVQ_MIN_PRIORITY = 9; struct CHARDEV_INFO_0 { LPWSTR ch0_dev; } alias CHARDEV_INFO_0* PCHARDEV_INFO_0, LPCHARDEV_INFO_0; struct CHARDEV_INFO_1{ LPWSTR ch1_dev; DWORD ch1_status; LPWSTR ch1_username; DWORD ch1_time; } alias CHARDEV_INFO_1* PCHARDEV_INFO_1, LPCHARDEV_INFO_1; struct CHARDEVQ_INFO_0 { LPWSTR cq0_dev; } alias CHARDEVQ_INFO_0* PCHARDEVQ_INFO_0, LPCHARDEVQ_INFO_0; struct CHARDEVQ_INFO_1{ LPWSTR cq1_dev; DWORD cq1_priority; LPWSTR cq1_devs; DWORD cq1_numusers; DWORD cq1_numahead; } alias CHARDEVQ_INFO_1* PCHARDEVQ_INFO_1, LPCHARDEVQ_INFO_1; struct CHARDEVQ_INFO_1002 { DWORD cq1002_priority; } alias CHARDEVQ_INFO_1002* PCHARDEVQ_INFO_1002, LPCHARDEVQ_INFO_1002; struct CHARDEVQ_INFO_1003 { LPWSTR cq1003_devs; } alias CHARDEVQ_INFO_1003* PCHARDEVQ_INFO_1003, LPCHARDEVQ_INFO_1003; struct HANDLE_INFO_1{ DWORD hdli1_chartime; DWORD hdli1_charcount; } alias HANDLE_INFO_1* PHANDLE_INFO_1, LPHANDLE_INFO_1; extern (Windows) { NET_API_STATUS NetCharDevEnum(LPCWSTR, DWORD, PBYTE*, DWORD, PDWORD, PDWORD, PDWORD); NET_API_STATUS NetCharDevGetInfo(LPCWSTR, LPCWSTR, DWORD, PBYTE*); NET_API_STATUS NetCharDevControl(LPCWSTR, LPCWSTR, DWORD); NET_API_STATUS NetCharDevQEnum(LPCWSTR, LPCWSTR, DWORD, PBYTE*, DWORD, PDWORD, PDWORD, PDWORD); NET_API_STATUS NetCharDevQGetInfo(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, PBYTE*); NET_API_STATUS NetCharDevQSetInfo(LPCWSTR, LPCWSTR, DWORD, PBYTE, PDWORD); NET_API_STATUS NetCharDevQPurge(LPCWSTR, LPCWSTR); NET_API_STATUS NetCharDevQPurgeSelf(LPCWSTR, LPCWSTR, LPCWSTR); NET_API_STATUS NetHandleGetInfo(HANDLE, DWORD, PBYTE*); NET_API_STATUS NetHandleSetInfo(HANDLE, DWORD, PBYTE, DWORD, PDWORD); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/dbt.d0000664000175000017500000001263712776214756022441 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Vladimir Vlasov * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_dbt.d) */ module core.sys.windows.dbt; version (Windows): version (ANSI) {} else version = Unicode; import core.sys.windows.w32api, core.sys.windows.windef; import core.sys.windows.basetyps; // for GUID // FIXME: clean up Windows version support enum : DWORD { DBT_NO_DISK_SPACE = 0x47, DBT_CONFIGMGPRIVATE = 0x7FFF, DBT_DEVICEARRIVAL = 0x8000, DBT_DEVICEQUERYREMOVE = 0x8001, DBT_DEVICEQUERYREMOVEFAILED = 0x8002, DBT_DEVICEREMOVEPENDING = 0x8003, DBT_DEVICEREMOVECOMPLETE = 0x8004, DBT_DEVICETYPESPECIFIC = 0x8005, DBT_DEVTYP_OEM = 0, DBT_DEVTYP_DEVNODE, DBT_DEVTYP_VOLUME, DBT_DEVTYP_PORT, DBT_DEVTYP_NET, DBT_DEVTYP_DEVICEINTERFACE, DBT_DEVTYP_HANDLE // = 6 } enum : DWORD { DBT_APPYBEGIN, DBT_APPYEND, DBT_DEVNODES_CHANGED = 7, DBT_QUERYCHANGECONFIG = 0x17, DBT_CONFIGCHANGED = 0x18, DBT_CONFIGCHANGECANCELED = 0x19, DBT_MONITORCHANGE = 0x1B, DBT_SHELLLOGGEDON = 32, DBT_CONFIGMGAPI32 = 34, DBT_VXDINITCOMPLETE = 35, DBT_VOLLOCKQUERYLOCK = 0x8041, DBT_VOLLOCKLOCKTAKEN = 0x8042, DBT_VOLLOCKLOCKFAILED = 0x8043, DBT_VOLLOCKQUERYUNLOCK = 0x8044, DBT_VOLLOCKLOCKRELEASED = 0x8045, DBT_VOLLOCKUNLOCKFAILED = 0x8046, DBT_USERDEFINED = 0xFFFF } enum : WORD { DBTF_MEDIA = 1, DBTF_NET = 2 } enum : DWORD { BSM_ALLCOMPONENTS = 0, BSM_APPLICATIONS = 8, BSM_ALLDESKTOPS = 16, BSM_INSTALLABLEDRIVERS = 4, BSM_NETDRIVER = 2, BSM_VXDS = 1, BSF_FLUSHDISK = 0x00000004, BSF_FORCEIFHUNG = 0x00000020, BSF_IGNORECURRENTTASK = 0x00000002, BSF_NOHANG = 0x00000008, BSF_NOTIMEOUTIFNOTHUNG = 0x00000040, BSF_POSTMESSAGE = 0x00000010, BSF_QUERY = 0x00000001, BSF_MSGSRV32ISOK_BIT = 31, BSF_MSGSRV32ISOK = 0x80000000 } //static if (_WIN32_WINNT >= 0x500) { enum : DWORD { BSF_ALLOWSFW = 0x00000080, BSF_SENDNOTIFYMESSAGE = 0x00000100 } //} static if (_WIN32_WINNT >= 0x501) { enum : DWORD { BSF_LUID = 0x00000400, BSF_RETURNHDESK = 0x00000200 } } struct DEV_BROADCAST_HDR { DWORD dbch_size = DEV_BROADCAST_HDR.sizeof; DWORD dbch_devicetype; DWORD dbch_reserved; } alias DEV_BROADCAST_HDR* PDEV_BROADCAST_HDR; struct DEV_BROADCAST_OEM { DWORD dbco_size = DEV_BROADCAST_OEM.sizeof; DWORD dbco_devicetype; DWORD dbco_reserved; DWORD dbco_identifier; DWORD dbco_suppfunc; } alias DEV_BROADCAST_OEM* PDEV_BROADCAST_OEM; struct DEV_BROADCAST_PORT_A { DWORD dbcp_size = DEV_BROADCAST_PORT_A.sizeof; DWORD dbcp_devicetype; DWORD dbcp_reserved; char _dbcp_name; char* dbcp_name() return { return &_dbcp_name; } } alias DEV_BROADCAST_PORT_A* PDEV_BROADCAST_PORT_A; struct DEV_BROADCAST_PORT_W { DWORD dbcp_size = DEV_BROADCAST_PORT_W.sizeof; DWORD dbcp_devicetype; DWORD dbcp_reserved; WCHAR _dbcp_name; WCHAR* dbcp_name() return { return &_dbcp_name; } } alias DEV_BROADCAST_PORT_W* PDEV_BROADCAST_PORT_W; struct DEV_BROADCAST_USERDEFINED { DEV_BROADCAST_HDR dbud_dbh; char _dbud_szName; char* dbud_szName() return { return &_dbud_szName; } } struct DEV_BROADCAST_VOLUME { DWORD dbcv_size = DEV_BROADCAST_VOLUME.sizeof; DWORD dbcv_devicetype; DWORD dbcv_reserved; DWORD dbcv_unitmask; WORD dbcv_flags; } alias DEV_BROADCAST_VOLUME* PDEV_BROADCAST_VOLUME; version (Unicode) { alias DEV_BROADCAST_PORT_W DEV_BROADCAST_PORT; } else { alias DEV_BROADCAST_PORT_A DEV_BROADCAST_PORT; } alias DEV_BROADCAST_PORT* PDEV_BROADCAST_PORT; //static if (_WIN32_WINNT >= 0x500) { struct DEV_BROADCAST_DEVICEINTERFACE_A { DWORD dbcc_size = DEV_BROADCAST_DEVICEINTERFACE_A.sizeof; DWORD dbcc_devicetype; DWORD dbcc_reserved; GUID dbcc_classguid; char _dbcc_name; char* dbcc_name() return { return &_dbcc_name; } } alias DEV_BROADCAST_DEVICEINTERFACE_A* PDEV_BROADCAST_DEVICEINTERFACE_A; struct DEV_BROADCAST_DEVICEINTERFACE_W { DWORD dbcc_size = DEV_BROADCAST_DEVICEINTERFACE_W.sizeof; DWORD dbcc_devicetype; DWORD dbcc_reserved; GUID dbcc_classguid; WCHAR _dbcc_name; WCHAR* dbcc_name() return { return &_dbcc_name; } } alias DEV_BROADCAST_DEVICEINTERFACE_W* PDEV_BROADCAST_DEVICEINTERFACE_W; version (Unicode) { alias DEV_BROADCAST_DEVICEINTERFACE_W DEV_BROADCAST_DEVICEINTERFACE; } else { alias DEV_BROADCAST_DEVICEINTERFACE_A DEV_BROADCAST_DEVICEINTERFACE; } alias DEV_BROADCAST_DEVICEINTERFACE* PDEV_BROADCAST_DEVICEINTERFACE; struct DEV_BROADCAST_HANDLE { DWORD dbch_size = DEV_BROADCAST_HANDLE.sizeof; DWORD dbch_devicetype; DWORD dbch_reserved; HANDLE dbch_handle; DWORD dbch_hdevnotify; GUID dbch_eventguid; LONG dbch_nameoffset; BYTE _dbch_data; BYTE* dbch_data() return { return &_dbch_data; } } alias DEV_BROADCAST_HANDLE* PDEV_BROADCAST_HANDLE; //} ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmshare.d0000664000175000017500000001264312776214756023320 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmshare.d) */ module core.sys.windows.lmshare; version (Windows): pragma(lib, "netapi32"); import core.sys.windows.lmcons; private import core.sys.windows.w32api, core.sys.windows.windef; enum SHARE_NETNAME_PARMNUM = 1; enum SHARE_TYPE_PARMNUM = 3; enum SHARE_REMARK_PARMNUM = 4; enum SHARE_PERMISSIONS_PARMNUM = 5; enum SHARE_MAX_USES_PARMNUM = 6; enum SHARE_CURRENT_USES_PARMNUM = 7; enum SHARE_PATH_PARMNUM = 8; enum SHARE_PASSWD_PARMNUM = 9; enum SHARE_FILE_SD_PARMNUM = 501; enum SHARE_REMARK_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + SHARE_REMARK_PARMNUM; enum SHARE_MAX_USES_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + SHARE_MAX_USES_PARMNUM; enum SHARE_FILE_SD_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + SHARE_FILE_SD_PARMNUM; enum SHI1_NUM_ELEMENTS = 4; enum SHI2_NUM_ELEMENTS = 10; enum STYPE_DISKTREE = 0; enum STYPE_PRINTQ = 1; enum STYPE_DEVICE = 2; enum STYPE_IPC = 3; enum STYPE_DFS = 100; enum STYPE_SPECIAL = 0x80000000; enum DWORD SHI_USES_UNLIMITED = -1; enum SESS_GUEST = 1; enum SESS_NOENCRYPTION = 2; enum SESI1_NUM_ELEMENTS = 8; enum SESI2_NUM_ELEMENTS = 9; enum PERM_FILE_READ = 1; enum PERM_FILE_WRITE = 2; enum PERM_FILE_CREATE = 4; struct FILE_INFO_2 { DWORD fi2_id; } alias FILE_INFO_2* PFILE_INFO_2, LPFILE_INFO_2; struct FILE_INFO_3 { DWORD fi3_id; DWORD fi3_permissions; DWORD fi3_num_locks; LPTSTR fi3_pathname; LPTSTR fi3_username; } alias FILE_INFO_3* PFILE_INFO_3, LPFILE_INFO_3; struct SHARE_INFO_0 { LPTSTR shi0_netname; } alias SHARE_INFO_0* PSHARE_INFO_0, LPSHARE_INFO_0; struct SHARE_INFO_1 { LPTSTR shi1_netname; DWORD shi1_type; LPTSTR shi1_remark; } alias SHARE_INFO_1* PSHARE_INFO_1, LPSHARE_INFO_1; struct SHARE_INFO_2 { LPTSTR shi2_netname; DWORD shi2_type; LPTSTR shi2_remark; DWORD shi2_permissions; DWORD shi2_max_uses; DWORD shi2_current_uses; LPTSTR shi2_path; LPTSTR shi2_passwd; } alias SHARE_INFO_2* PSHARE_INFO_2, LPSHARE_INFO_2; struct SHARE_INFO_502 { LPTSTR shi502_netname; DWORD shi502_type; LPTSTR shi502_remark; DWORD shi502_permissions; DWORD shi502_max_uses; DWORD shi502_current_uses; LPTSTR shi502_path; LPTSTR shi502_passwd; DWORD shi502_reserved; PSECURITY_DESCRIPTOR shi502_security_descriptor; } alias SHARE_INFO_502* PSHARE_INFO_502, LPSHARE_INFO_502; struct SHARE_INFO_1004 { LPTSTR shi1004_remark; } alias SHARE_INFO_1004* PSHARE_INFO_1004, LPSHARE_INFO_1004; struct SHARE_INFO_1006 { DWORD shi1006_max_uses; } alias SHARE_INFO_1006* PSHARE_INFO_1006, LPSHARE_INFO_1006; struct SHARE_INFO_1501 { DWORD shi1501_reserved; PSECURITY_DESCRIPTOR shi1501_security_descriptor; } alias SHARE_INFO_1501* PSHARE_INFO_1501, LPSHARE_INFO_1501; struct SESSION_INFO_0 { LPWSTR sesi0_cname; } alias SESSION_INFO_0* PSESSION_INFO_0, LPSESSION_INFO_0; struct SESSION_INFO_1 { LPTSTR sesi1_cname; LPTSTR sesi1_username; DWORD sesi1_num_opens; DWORD sesi1_time; DWORD sesi1_idle_time; DWORD sesi1_user_flags; } alias SESSION_INFO_1* PSESSION_INFO_1, LPSESSION_INFO_1; struct SESSION_INFO_2 { LPTSTR sesi2_cname; LPTSTR sesi2_username; DWORD sesi2_num_opens; DWORD sesi2_time; DWORD sesi2_idle_time; DWORD sesi2_user_flags; LPWSTR sesi2_cltype_name; } alias SESSION_INFO_2* PSESSION_INFO_2, LPSESSION_INFO_2; struct SESSION_INFO_10 { LPWSTR sesi10_cname; LPWSTR sesi10_username; DWORD sesi10_time; DWORD sesi10_idle_time; } alias SESSION_INFO_10* PSESSION_INFO_10, LPSESSION_INFO_10; struct SESSION_INFO_502 { LPWSTR sesi502_cname; LPWSTR sesi502_username; DWORD sesi502_num_opens; DWORD sesi502_time; DWORD sesi502_idle_time; DWORD sesi502_user_flags; LPWSTR sesi502_cltype_name; LPWSTR sesi502_transport; } alias SESSION_INFO_502* PSESSION_INFO_502, LPSESSION_INFO_502; struct CONNECTION_INFO_0 { DWORD coni0_id; } alias CONNECTION_INFO_0* PCONNECTION_INFO_0, LPCONNECTION_INFO_0; struct CONNECTION_INFO_1 { DWORD coni1_id; DWORD coni1_type; DWORD coni1_num_opens; DWORD coni1_num_users; DWORD coni1_time; LPWSTR coni1_username; LPWSTR coni1_netname; } alias CONNECTION_INFO_1* PCONNECTION_INFO_1, LPCONNECTION_INFO_1; extern (Windows) { NET_API_STATUS NetShareAdd(LPWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetShareEnum(LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetShareEnumSticky(LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD resume_handle); NET_API_STATUS NetShareGetInfo(LPWSTR,LPWSTR,DWORD,PBYTE*); NET_API_STATUS NetShareSetInfo(LPWSTR,LPWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetShareDel(LPWSTR,LPWSTR,DWORD); NET_API_STATUS NetShareDelSticky(LPWSTR,LPWSTR,DWORD); NET_API_STATUS NetShareCheck(LPWSTR,LPWSTR,PDWORD); NET_API_STATUS NetSessionEnum(LPWSTR,LPWSTR,LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetSessionDel(LPWSTR,LPWSTR,LPWSTR); NET_API_STATUS NetSessionGetInfo(LPWSTR,LPWSTR,LPWSTR,DWORD,PBYTE*); NET_API_STATUS NetConnectionEnum(LPWSTR,LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetFileClose(LPWSTR,DWORD); NET_API_STATUS NetFileEnum(LPWSTR,LPWSTR,LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetFileGetInfo(LPWSTR,DWORD,DWORD,PBYTE*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winerror.d0000664000175000017500000025264412776214756023543 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winerror.d) */ module core.sys.windows.winerror; version (Windows): /* Comments from the Mingw header: * WAIT_TIMEOUT is also defined in winbase.h */ private import core.sys.windows.windef; alias int SCODE; // was in core.sys.windows.wtypes. enum : uint { ERROR_SUCCESS = 0, NO_ERROR = 0, ERROR_INVALID_FUNCTION, ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_TOO_MANY_OPEN_FILES, ERROR_ACCESS_DENIED, ERROR_INVALID_HANDLE, ERROR_ARENA_TRASHED, ERROR_NOT_ENOUGH_MEMORY, ERROR_INVALID_BLOCK, ERROR_BAD_ENVIRONMENT, ERROR_BAD_FORMAT, ERROR_INVALID_ACCESS, ERROR_INVALID_DATA, ERROR_OUTOFMEMORY, ERROR_INVALID_DRIVE, ERROR_CURRENT_DIRECTORY, ERROR_NOT_SAME_DEVICE, ERROR_NO_MORE_FILES, ERROR_WRITE_PROTECT, ERROR_BAD_UNIT, ERROR_NOT_READY, ERROR_BAD_COMMAND, ERROR_CRC, ERROR_BAD_LENGTH, ERROR_SEEK, ERROR_NOT_DOS_DISK, ERROR_SECTOR_NOT_FOUND, ERROR_OUT_OF_PAPER, ERROR_WRITE_FAULT, ERROR_READ_FAULT, ERROR_GEN_FAILURE, ERROR_SHARING_VIOLATION, ERROR_LOCK_VIOLATION, ERROR_WRONG_DISK, // = 34 ERROR_SHARING_BUFFER_EXCEEDED = 36, ERROR_HANDLE_EOF = 38, ERROR_HANDLE_DISK_FULL, // = 39 ERROR_NOT_SUPPORTED = 50, ERROR_REM_NOT_LIST, ERROR_DUP_NAME, ERROR_BAD_NETPATH, ERROR_NETWORK_BUSY, ERROR_DEV_NOT_EXIST, ERROR_TOO_MANY_CMDS, ERROR_ADAP_HDW_ERR, ERROR_BAD_NET_RESP, ERROR_UNEXP_NET_ERR, ERROR_BAD_REM_ADAP, ERROR_PRINTQ_FULL, ERROR_NO_SPOOL_SPACE, ERROR_PRINT_CANCELLED, ERROR_NETNAME_DELETED, ERROR_NETWORK_ACCESS_DENIED, ERROR_BAD_DEV_TYPE, ERROR_BAD_NET_NAME, ERROR_TOO_MANY_NAMES, ERROR_TOO_MANY_SESS, ERROR_SHARING_PAUSED, ERROR_REQ_NOT_ACCEP, ERROR_REDIR_PAUSED, // = 72 ERROR_FILE_EXISTS = 80, ERROR_CANNOT_MAKE = 82, ERROR_FAIL_I24, ERROR_OUT_OF_STRUCTURES, ERROR_ALREADY_ASSIGNED, ERROR_INVALID_PASSWORD, ERROR_INVALID_PARAMETER, ERROR_NET_WRITE_FAULT, ERROR_NO_PROC_SLOTS, // = 89 ERROR_TOO_MANY_SEMAPHORES = 100, ERROR_EXCL_SEM_ALREADY_OWNED, ERROR_SEM_IS_SET, ERROR_TOO_MANY_SEM_REQUESTS, ERROR_INVALID_AT_INTERRUPT_TIME, ERROR_SEM_OWNER_DIED, ERROR_SEM_USER_LIMIT, ERROR_DISK_CHANGE, ERROR_DRIVE_LOCKED, ERROR_BROKEN_PIPE, ERROR_OPEN_FAILED, ERROR_BUFFER_OVERFLOW, ERROR_DISK_FULL, ERROR_NO_MORE_SEARCH_HANDLES, ERROR_INVALID_TARGET_HANDLE, // = 114 ERROR_INVALID_CATEGORY = 117, ERROR_INVALID_VERIFY_SWITCH, ERROR_BAD_DRIVER_LEVEL, ERROR_CALL_NOT_IMPLEMENTED, ERROR_SEM_TIMEOUT, ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_NAME, ERROR_INVALID_LEVEL, ERROR_NO_VOLUME_LABEL, ERROR_MOD_NOT_FOUND, ERROR_PROC_NOT_FOUND, ERROR_WAIT_NO_CHILDREN, ERROR_CHILD_NOT_COMPLETE, ERROR_DIRECT_ACCESS_HANDLE, ERROR_NEGATIVE_SEEK, ERROR_SEEK_ON_DEVICE, ERROR_IS_JOIN_TARGET, ERROR_IS_JOINED, ERROR_IS_SUBSTED, ERROR_NOT_JOINED, ERROR_NOT_SUBSTED, ERROR_JOIN_TO_JOIN, ERROR_SUBST_TO_SUBST, ERROR_JOIN_TO_SUBST, ERROR_SUBST_TO_JOIN, ERROR_BUSY_DRIVE, ERROR_SAME_DRIVE, ERROR_DIR_NOT_ROOT, ERROR_DIR_NOT_EMPTY, ERROR_IS_SUBST_PATH, ERROR_IS_JOIN_PATH, ERROR_PATH_BUSY, ERROR_IS_SUBST_TARGET, ERROR_SYSTEM_TRACE, ERROR_INVALID_EVENT_COUNT, ERROR_TOO_MANY_MUXWAITERS, ERROR_INVALID_LIST_FORMAT, ERROR_LABEL_TOO_LONG, ERROR_TOO_MANY_TCBS, ERROR_SIGNAL_REFUSED, ERROR_DISCARDED, ERROR_NOT_LOCKED, ERROR_BAD_THREADID_ADDR, ERROR_BAD_ARGUMENTS, ERROR_BAD_PATHNAME, ERROR_SIGNAL_PENDING, // = 162 ERROR_MAX_THRDS_REACHED = 164, ERROR_LOCK_FAILED = 167, ERROR_BUSY = 170, ERROR_CANCEL_VIOLATION = 173, ERROR_ATOMIC_LOCKS_NOT_SUPPORTED, // = 174 ERROR_INVALID_SEGMENT_NUMBER = 180, ERROR_INVALID_ORDINAL = 182, ERROR_ALREADY_EXISTS, // = 183 ERROR_INVALID_FLAG_NUMBER = 186, ERROR_SEM_NOT_FOUND, ERROR_INVALID_STARTING_CODESEG, ERROR_INVALID_STACKSEG, ERROR_INVALID_MODULETYPE, ERROR_INVALID_EXE_SIGNATURE, ERROR_EXE_MARKED_INVALID, ERROR_BAD_EXE_FORMAT, ERROR_ITERATED_DATA_EXCEEDS_64k, ERROR_INVALID_MINALLOCSIZE, ERROR_DYNLINK_FROM_INVALID_RING, ERROR_IOPL_NOT_ENABLED, ERROR_INVALID_SEGDPL, ERROR_AUTODATASEG_EXCEEDS_64k, ERROR_RING2SEG_MUST_BE_MOVABLE, ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ERROR_INFLOOP_IN_RELOC_CHAIN, ERROR_ENVVAR_NOT_FOUND, // = 203 ERROR_NO_SIGNAL_SENT = 205, ERROR_FILENAME_EXCED_RANGE, ERROR_RING2_STACK_IN_USE, ERROR_META_EXPANSION_TOO_LONG, ERROR_INVALID_SIGNAL_NUMBER, ERROR_THREAD_1_INACTIVE, // = 210 ERROR_LOCKED = 212, ERROR_TOO_MANY_MODULES = 214, ERROR_NESTING_NOT_ALLOWED, ERROR_EXE_MACHINE_TYPE_MISMATCH, ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY, ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY, // = 218 ERROR_BAD_PIPE = 230, ERROR_PIPE_BUSY, ERROR_NO_DATA, ERROR_PIPE_NOT_CONNECTED, ERROR_MORE_DATA, // = 234 ERROR_VC_DISCONNECTED = 240, ERROR_INVALID_EA_NAME = 254, ERROR_EA_LIST_INCONSISTENT, // = 255 WAIT_TIMEOUT = 258, ERROR_NO_MORE_ITEMS, // = 259 ERROR_CANNOT_COPY = 266, ERROR_DIRECTORY, // = 267 ERROR_EAS_DIDNT_FIT = 275, ERROR_EA_FILE_CORRUPT, ERROR_EA_TABLE_FULL, ERROR_INVALID_EA_HANDLE, // = 278 ERROR_EAS_NOT_SUPPORTED = 282, ERROR_NOT_OWNER = 288, ERROR_TOO_MANY_POSTS = 298, ERROR_PARTIAL_COPY, ERROR_OPLOCK_NOT_GRANTED, ERROR_INVALID_OPLOCK_PROTOCOL, ERROR_DISK_TOO_FRAGMENTED, ERROR_DELETE_PENDING, // = 303 ERROR_MR_MID_NOT_FOUND = 317, ERROR_SCOPE_NOT_FOUND, // = 318 ERROR_INVALID_ADDRESS = 487, ERROR_ARITHMETIC_OVERFLOW = 534, ERROR_PIPE_CONNECTED, ERROR_PIPE_LISTENING, // = 536 ERROR_EA_ACCESS_DENIED = 994, ERROR_OPERATION_ABORTED, ERROR_IO_INCOMPLETE, ERROR_IO_PENDING, ERROR_NOACCESS, ERROR_SWAPERROR, // = 999 ERROR_STACK_OVERFLOW = 1001, ERROR_INVALID_MESSAGE, ERROR_CAN_NOT_COMPLETE, ERROR_INVALID_FLAGS, ERROR_UNRECOGNIZED_VOLUME, ERROR_FILE_INVALID, ERROR_FULLSCREEN_MODE, ERROR_NO_TOKEN, ERROR_BADDB, ERROR_BADKEY, ERROR_CANTOPEN, ERROR_CANTREAD, ERROR_CANTWRITE, ERROR_REGISTRY_RECOVERED, ERROR_REGISTRY_CORRUPT, ERROR_REGISTRY_IO_FAILED, ERROR_NOT_REGISTRY_FILE, ERROR_KEY_DELETED, ERROR_NO_LOG_SPACE, ERROR_KEY_HAS_CHILDREN, ERROR_CHILD_MUST_BE_VOLATILE, ERROR_NOTIFY_ENUM_DIR, // = 1022 ERROR_DEPENDENT_SERVICES_RUNNING = 1051, ERROR_INVALID_SERVICE_CONTROL, ERROR_SERVICE_REQUEST_TIMEOUT, ERROR_SERVICE_NO_THREAD, ERROR_SERVICE_DATABASE_LOCKED, ERROR_SERVICE_ALREADY_RUNNING, ERROR_INVALID_SERVICE_ACCOUNT, ERROR_SERVICE_DISABLED, ERROR_CIRCULAR_DEPENDENCY, ERROR_SERVICE_DOES_NOT_EXIST, ERROR_SERVICE_CANNOT_ACCEPT_CTRL, ERROR_SERVICE_NOT_ACTIVE, ERROR_FAILED_SERVICE_CONTROLLER_CONNECT, ERROR_EXCEPTION_IN_SERVICE, ERROR_DATABASE_DOES_NOT_EXIST, ERROR_SERVICE_SPECIFIC_ERROR, ERROR_PROCESS_ABORTED, ERROR_SERVICE_DEPENDENCY_FAIL, ERROR_SERVICE_LOGON_FAILED, ERROR_SERVICE_START_HANG, ERROR_INVALID_SERVICE_LOCK, ERROR_SERVICE_MARKED_FOR_DELETE, ERROR_SERVICE_EXISTS, ERROR_ALREADY_RUNNING_LKG, ERROR_SERVICE_DEPENDENCY_DELETED, ERROR_BOOT_ALREADY_ACCEPTED, ERROR_SERVICE_NEVER_STARTED, ERROR_DUPLICATE_SERVICE_NAME, ERROR_DIFFERENT_SERVICE_ACCOUNT, ERROR_CANNOT_DETECT_DRIVER_FAILURE, ERROR_CANNOT_DETECT_PROCESS_ABORT, ERROR_NO_RECOVERY_PROGRAM, ERROR_SERVICE_NOT_IN_EXE, ERROR_NOT_SAFEBOOT_SERVICE, // = 1084 ERROR_END_OF_MEDIA = 1100, ERROR_FILEMARK_DETECTED, ERROR_BEGINNING_OF_MEDIA, ERROR_SETMARK_DETECTED, ERROR_NO_DATA_DETECTED, ERROR_PARTITION_FAILURE, ERROR_INVALID_BLOCK_LENGTH, ERROR_DEVICE_NOT_PARTITIONED, ERROR_UNABLE_TO_LOCK_MEDIA, ERROR_UNABLE_TO_UNLOAD_MEDIA, ERROR_MEDIA_CHANGED, ERROR_BUS_RESET, ERROR_NO_MEDIA_IN_DRIVE, ERROR_NO_UNICODE_TRANSLATION, ERROR_DLL_INIT_FAILED, ERROR_SHUTDOWN_IN_PROGRESS, ERROR_NO_SHUTDOWN_IN_PROGRESS, ERROR_IO_DEVICE, ERROR_SERIAL_NO_DEVICE, ERROR_IRQ_BUSY, ERROR_MORE_WRITES, ERROR_COUNTER_TIMEOUT, ERROR_FLOPPY_ID_MARK_NOT_FOUND, ERROR_FLOPPY_WRONG_CYLINDER, ERROR_FLOPPY_UNKNOWN_ERROR, ERROR_FLOPPY_BAD_REGISTERS, ERROR_DISK_RECALIBRATE_FAILED, ERROR_DISK_OPERATION_FAILED, ERROR_DISK_RESET_FAILED, ERROR_EOM_OVERFLOW, ERROR_NOT_ENOUGH_SERVER_MEMORY, ERROR_POSSIBLE_DEADLOCK, ERROR_MAPPED_ALIGNMENT, // = 1132 ERROR_SET_POWER_STATE_VETOED = 1140, ERROR_SET_POWER_STATE_FAILED, ERROR_TOO_MANY_LINKS, // = 1142 ERROR_OLD_WIN_VERSION = 1150, ERROR_APP_WRONG_OS, ERROR_SINGLE_INSTANCE_APP, ERROR_RMODE_APP, ERROR_INVALID_DLL, ERROR_NO_ASSOCIATION, ERROR_DDE_FAIL, ERROR_DLL_NOT_FOUND, ERROR_NO_MORE_USER_HANDLES, ERROR_MESSAGE_SYNC_ONLY, ERROR_SOURCE_ELEMENT_EMPTY, ERROR_DESTINATION_ELEMENT_FULL, ERROR_ILLEGAL_ELEMENT_ADDRESS, ERROR_MAGAZINE_NOT_PRESENT, ERROR_DEVICE_REINITIALIZATION_NEEDED, ERROR_DEVICE_REQUIRES_CLEANING, ERROR_DEVICE_DOOR_OPEN, ERROR_DEVICE_NOT_CONNECTED, ERROR_NOT_FOUND, ERROR_NO_MATCH, ERROR_SET_NOT_FOUND, ERROR_POINT_NOT_FOUND, ERROR_NO_TRACKING_SERVICE, ERROR_NO_VOLUME_ID, // = 1173 ERROR_UNABLE_TO_REMOVE_REPLACED = 1175, ERROR_UNABLE_TO_MOVE_REPLACEMENT, ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, ERROR_JOURNAL_DELETE_IN_PROGRESS, ERROR_JOURNAL_NOT_ACTIVE, ERROR_POTENTIAL_FILE_FOUND, ERROR_JOURNAL_ENTRY_DELETED, // = 1181 ERROR_BAD_DEVICE = 1200, ERROR_CONNECTION_UNAVAIL, ERROR_DEVICE_ALREADY_REMEMBERED, ERROR_NO_NET_OR_BAD_PATH, ERROR_BAD_PROVIDER, ERROR_CANNOT_OPEN_PROFILE, ERROR_BAD_PROFILE, ERROR_NOT_CONTAINER, ERROR_EXTENDED_ERROR, ERROR_INVALID_GROUPNAME, ERROR_INVALID_COMPUTERNAME, ERROR_INVALID_EVENTNAME, ERROR_INVALID_DOMAINNAME, ERROR_INVALID_SERVICENAME, ERROR_INVALID_NETNAME, ERROR_INVALID_SHARENAME, ERROR_INVALID_PASSWORDNAME, ERROR_INVALID_MESSAGENAME, ERROR_INVALID_MESSAGEDEST, ERROR_SESSION_CREDENTIAL_CONFLICT, ERROR_REMOTE_SESSION_LIMIT_EXCEEDED, ERROR_DUP_DOMAINNAME, ERROR_NO_NETWORK, ERROR_CANCELLED, ERROR_USER_MAPPED_FILE, ERROR_CONNECTION_REFUSED, ERROR_GRACEFUL_DISCONNECT, ERROR_ADDRESS_ALREADY_ASSOCIATED, ERROR_ADDRESS_NOT_ASSOCIATED, ERROR_CONNECTION_INVALID, ERROR_CONNECTION_ACTIVE, ERROR_NETWORK_UNREACHABLE, ERROR_HOST_UNREACHABLE, ERROR_PROTOCOL_UNREACHABLE, ERROR_PORT_UNREACHABLE, ERROR_REQUEST_ABORTED, ERROR_CONNECTION_ABORTED, ERROR_RETRY, ERROR_CONNECTION_COUNT_LIMIT, ERROR_LOGIN_TIME_RESTRICTION, ERROR_LOGIN_WKSTA_RESTRICTION, ERROR_INCORRECT_ADDRESS, ERROR_ALREADY_REGISTERED, ERROR_SERVICE_NOT_FOUND, ERROR_NOT_AUTHENTICATED, ERROR_NOT_LOGGED_ON, ERROR_CONTINUE, ERROR_ALREADY_INITIALIZED, ERROR_NO_MORE_DEVICES, ERROR_NO_SUCH_SITE, ERROR_DOMAIN_CONTROLLER_EXISTS, ERROR_ONLY_IF_CONNECTED, ERROR_OVERRIDE_NOCHANGES, ERROR_BAD_USER_PROFILE, ERROR_NOT_SUPPORTED_ON_SBS, ERROR_SERVER_SHUTDOWN_IN_PROGRESS, ERROR_HOST_DOWN, ERROR_NON_ACCOUNT_SID, ERROR_NON_DOMAIN_SID, ERROR_APPHELP_BLOCK, ERROR_ACCESS_DISABLED_BY_POLICY, ERROR_REG_NAT_CONSUMPTION, ERROR_CSCSHARE_OFFLINE, ERROR_PKINIT_FAILURE, ERROR_SMARTCARD_SUBSYSTEM_FAILURE, ERROR_DOWNGRADE_DETECTED, SEC_E_SMARTCARD_CERT_REVOKED, SEC_E_ISSUING_CA_UNTRUSTED, SEC_E_REVOCATION_OFFLINE_C, SEC_E_PKINIT_CLIENT_FAILUR, SEC_E_SMARTCARD_CERT_EXPIRED, ERROR_MACHINE_LOCKED, // = 1271 ERROR_CALLBACK_SUPPLIED_INVALID_DATA = 1273, ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED, ERROR_DRIVER_BLOCKED, ERROR_INVALID_IMPORT_OF_NON_DLL, ERROR_ACCESS_DISABLED_WEBBLADE, ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER, ERROR_RECOVERY_FAILURE, ERROR_ALREADY_FIBER, ERROR_ALREADY_THREAD, ERROR_STACK_BUFFER_OVERRUN, ERROR_PARAMETER_QUOTA_EXCEEDED, ERROR_DEBUGGER_INACTIVE, // = 1284 ERROR_NOT_ALL_ASSIGNED = 1300, ERROR_SOME_NOT_MAPPED, ERROR_NO_QUOTAS_FOR_ACCOUNT, ERROR_LOCAL_USER_SESSION_KEY, ERROR_NULL_LM_PASSWORD, ERROR_UNKNOWN_REVISION, ERROR_REVISION_MISMATCH, ERROR_INVALID_OWNER, ERROR_INVALID_PRIMARY_GROUP, ERROR_NO_IMPERSONATION_TOKEN, ERROR_CANT_DISABLE_MANDATORY, ERROR_NO_LOGON_SERVERS, ERROR_NO_SUCH_LOGON_SESSION, ERROR_NO_SUCH_PRIVILEGE, ERROR_PRIVILEGE_NOT_HELD, ERROR_INVALID_ACCOUNT_NAME, ERROR_USER_EXISTS, ERROR_NO_SUCH_USER, ERROR_GROUP_EXISTS, ERROR_NO_SUCH_GROUP, ERROR_MEMBER_IN_GROUP, ERROR_MEMBER_NOT_IN_GROUP, ERROR_LAST_ADMIN, ERROR_WRONG_PASSWORD, ERROR_ILL_FORMED_PASSWORD, ERROR_PASSWORD_RESTRICTION, ERROR_LOGON_FAILURE, ERROR_ACCOUNT_RESTRICTION, ERROR_INVALID_LOGON_HOURS, ERROR_INVALID_WORKSTATION, ERROR_PASSWORD_EXPIRED, ERROR_ACCOUNT_DISABLED, ERROR_NONE_MAPPED, ERROR_TOO_MANY_LUIDS_REQUESTED, ERROR_LUIDS_EXHAUSTED, ERROR_INVALID_SUB_AUTHORITY, ERROR_INVALID_ACL, ERROR_INVALID_SID, ERROR_INVALID_SECURITY_DESCR, // = 1338 ERROR_BAD_INHERITANCE_ACL = 1340, ERROR_SERVER_DISABLED, ERROR_SERVER_NOT_DISABLED, ERROR_INVALID_ID_AUTHORITY, ERROR_ALLOTTED_SPACE_EXCEEDED, ERROR_INVALID_GROUP_ATTRIBUTES, ERROR_BAD_IMPERSONATION_LEVEL, ERROR_CANT_OPEN_ANONYMOUS, ERROR_BAD_VALIDATION_CLASS, ERROR_BAD_TOKEN_TYPE, ERROR_NO_SECURITY_ON_OBJECT, ERROR_CANT_ACCESS_DOMAIN_INFO, ERROR_INVALID_SERVER_STATE, ERROR_INVALID_DOMAIN_STATE, ERROR_INVALID_DOMAIN_ROLE, ERROR_NO_SUCH_DOMAIN, ERROR_DOMAIN_EXISTS, ERROR_DOMAIN_LIMIT_EXCEEDED, ERROR_INTERNAL_DB_CORRUPTION, ERROR_INTERNAL_ERROR, ERROR_GENERIC_NOT_MAPPED, ERROR_BAD_DESCRIPTOR_FORMAT, ERROR_NOT_LOGON_PROCESS, ERROR_LOGON_SESSION_EXISTS, ERROR_NO_SUCH_PACKAGE, ERROR_BAD_LOGON_SESSION_STATE, ERROR_LOGON_SESSION_COLLISION, ERROR_INVALID_LOGON_TYPE, ERROR_CANNOT_IMPERSONATE, ERROR_RXACT_INVALID_STATE, ERROR_RXACT_COMMIT_FAILURE, ERROR_SPECIAL_ACCOUNT, ERROR_SPECIAL_GROUP, ERROR_SPECIAL_USER, ERROR_MEMBERS_PRIMARY_GROUP, ERROR_TOKEN_ALREADY_IN_USE, ERROR_NO_SUCH_ALIAS, ERROR_MEMBER_NOT_IN_ALIAS, ERROR_MEMBER_IN_ALIAS, ERROR_ALIAS_EXISTS, ERROR_LOGON_NOT_GRANTED, ERROR_TOO_MANY_SECRETS, ERROR_SECRET_TOO_LONG, ERROR_INTERNAL_DB_ERROR, ERROR_TOO_MANY_CONTEXT_IDS, ERROR_LOGON_TYPE_NOT_GRANTED, ERROR_NT_CROSS_ENCRYPTION_REQUIRED, ERROR_NO_SUCH_MEMBER, ERROR_INVALID_MEMBER, ERROR_TOO_MANY_SIDS, ERROR_LM_CROSS_ENCRYPTION_REQUIRED, ERROR_NO_INHERITANCE, ERROR_FILE_CORRUPT, ERROR_DISK_CORRUPT, ERROR_NO_USER_SESSION_KEY, ERROR_LICENSE_QUOTA_EXCEEDED, ERROR_WRONG_TARGET_NAME, ERROR_MUTUAL_AUTH_FAILED, ERROR_TIME_SKEW, ERROR_CURRENT_DOMAIN_NOT_ALLOWED, ERROR_INVALID_WINDOW_HANDLE, ERROR_INVALID_MENU_HANDLE, ERROR_INVALID_CURSOR_HANDLE, ERROR_INVALID_ACCEL_HANDLE, ERROR_INVALID_HOOK_HANDLE, ERROR_INVALID_DWP_HANDLE, ERROR_TLW_WITH_WSCHILD, ERROR_CANNOT_FIND_WND_CLASS, ERROR_WINDOW_OF_OTHER_THREAD, ERROR_HOTKEY_ALREADY_REGISTERED, ERROR_CLASS_ALREADY_EXISTS, ERROR_CLASS_DOES_NOT_EXIST, ERROR_CLASS_HAS_WINDOWS, ERROR_INVALID_INDEX, ERROR_INVALID_ICON_HANDLE, ERROR_PRIVATE_DIALOG_INDEX, ERROR_LISTBOX_ID_NOT_FOUND, ERROR_NO_WILDCARD_CHARACTERS, ERROR_CLIPBOARD_NOT_OPEN, ERROR_HOTKEY_NOT_REGISTERED, ERROR_WINDOW_NOT_DIALOG, ERROR_CONTROL_ID_NOT_FOUND, ERROR_INVALID_COMBOBOX_MESSAGE, ERROR_WINDOW_NOT_COMBOBOX, ERROR_INVALID_EDIT_HEIGHT, ERROR_DC_NOT_FOUND, ERROR_INVALID_HOOK_FILTER, ERROR_INVALID_FILTER_PROC, ERROR_HOOK_NEEDS_HMOD, ERROR_GLOBAL_ONLY_HOOK, ERROR_JOURNAL_HOOK_SET, ERROR_HOOK_NOT_INSTALLED, ERROR_INVALID_LB_MESSAGE, ERROR_SETCOUNT_ON_BAD_LB, ERROR_LB_WITHOUT_TABSTOPS, ERROR_DESTROY_OBJECT_OF_OTHER_THREAD, ERROR_CHILD_WINDOW_MENU, ERROR_NO_SYSTEM_MENU, ERROR_INVALID_MSGBOX_STYLE, ERROR_INVALID_SPI_VALUE, ERROR_SCREEN_ALREADY_LOCKED, ERROR_HWNDS_HAVE_DIFF_PARENT, ERROR_NOT_CHILD_WINDOW, ERROR_INVALID_GW_COMMAND, ERROR_INVALID_THREAD_ID, ERROR_NON_MDICHILD_WINDOW, ERROR_POPUP_ALREADY_ACTIVE, ERROR_NO_SCROLLBARS, ERROR_INVALID_SCROLLBAR_RANGE, ERROR_INVALID_SHOWWIN_COMMAND, ERROR_NO_SYSTEM_RESOURCES, ERROR_NONPAGED_SYSTEM_RESOURCES, ERROR_PAGED_SYSTEM_RESOURCES, ERROR_WORKING_SET_QUOTA, ERROR_PAGEFILE_QUOTA, ERROR_COMMITMENT_LIMIT, ERROR_MENU_ITEM_NOT_FOUND, ERROR_INVALID_KEYBOARD_HANDLE, ERROR_HOOK_TYPE_NOT_ALLOWED, ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION, ERROR_TIMEOUT, ERROR_INVALID_MONITOR_HANDLE, // = 1461 ERROR_EVENTLOG_FILE_CORRUPT = 1500, ERROR_EVENTLOG_CANT_START, ERROR_LOG_FILE_FULL, ERROR_EVENTLOG_FILE_CHANGED, // = 1503 ERROR_INSTALL_SERVICE_FAILURE = 1601, ERROR_INSTALL_USEREXIT, ERROR_INSTALL_FAILURE, ERROR_INSTALL_SUSPEND, ERROR_UNKNOWN_PRODUCT, ERROR_UNKNOWN_FEATURE, ERROR_UNKNOWN_COMPONENT, ERROR_UNKNOWN_PROPERTY, ERROR_INVALID_HANDLE_STATE, ERROR_BAD_CONFIGURATION, ERROR_INDEX_ABSENT, ERROR_INSTALL_SOURCE_ABSENT, ERROR_INSTALL_PACKAGE_VERSION, ERROR_PRODUCT_UNINSTALLED, ERROR_BAD_QUERY_SYNTAX, ERROR_INVALID_FIELD, ERROR_DEVICE_REMOVED, ERROR_INSTALL_ALREADY_RUNNING, ERROR_INSTALL_PACKAGE_OPEN_FAILED, ERROR_INSTALL_PACKAGE_INVALID, ERROR_INSTALL_UI_FAILURE, ERROR_INSTALL_LOG_FAILURE, ERROR_INSTALL_LANGUAGE_UNSUPPORTED, ERROR_INSTALL_TRANSFORM_FAILURE, ERROR_INSTALL_PACKAGE_REJECTED, ERROR_FUNCTION_NOT_CALLED, ERROR_FUNCTION_FAILED, ERROR_INVALID_TABLE, ERROR_DATATYPE_MISMATCH, ERROR_UNSUPPORTED_TYPE, ERROR_CREATE_FAILED, ERROR_INSTALL_TEMP_UNWRITABLE, ERROR_INSTALL_PLATFORM_UNSUPPORTED, ERROR_INSTALL_NOTUSED, ERROR_PATCH_PACKAGE_OPEN_FAILED, ERROR_PATCH_PACKAGE_INVALID, ERROR_PATCH_PACKAGE_UNSUPPORTED, ERROR_PRODUCT_VERSION, ERROR_INVALID_COMMAND_LINE, ERROR_INSTALL_REMOTE_DISALLOWED, ERROR_SUCCESS_REBOOT_INITIATED, ERROR_PATCH_TARGET_NOT_FOUND, ERROR_PATCH_PACKAGE_REJECTED, ERROR_INSTALL_TRANSFORM_REJECTED, ERROR_INSTALL_REMOTE_PROHIBITED, // = 1645 RPC_S_INVALID_STRING_BINDING = 1700, RPC_S_WRONG_KIND_OF_BINDING, RPC_S_INVALID_BINDING, RPC_S_PROTSEQ_NOT_SUPPORTED, RPC_S_INVALID_RPC_PROTSEQ, RPC_S_INVALID_STRING_UUID, RPC_S_INVALID_ENDPOINT_FORMAT, RPC_S_INVALID_NET_ADDR, RPC_S_NO_ENDPOINT_FOUND, RPC_S_INVALID_TIMEOUT, RPC_S_OBJECT_NOT_FOUND, RPC_S_ALREADY_REGISTERED, RPC_S_TYPE_ALREADY_REGISTERED, RPC_S_ALREADY_LISTENING, RPC_S_NO_PROTSEQS_REGISTERED, RPC_S_NOT_LISTENING, RPC_S_UNKNOWN_MGR_TYPE, RPC_S_UNKNOWN_IF, RPC_S_NO_BINDINGS, RPC_S_NO_PROTSEQS, RPC_S_CANT_CREATE_ENDPOINT, RPC_S_OUT_OF_RESOURCES, RPC_S_SERVER_UNAVAILABLE, RPC_S_SERVER_TOO_BUSY, RPC_S_INVALID_NETWORK_OPTIONS, RPC_S_NO_CALL_ACTIVE, RPC_S_CALL_FAILED, RPC_S_CALL_FAILED_DNE, RPC_S_PROTOCOL_ERROR, // = 1728 RPC_S_UNSUPPORTED_TRANS_SYN = 1730, RPC_S_UNSUPPORTED_TYPE = 1732, RPC_S_INVALID_TAG, RPC_S_INVALID_BOUND, RPC_S_NO_ENTRY_NAME, RPC_S_INVALID_NAME_SYNTAX, RPC_S_UNSUPPORTED_NAME_SYNTAX, // = 1737 RPC_S_UUID_NO_ADDRESS = 1739, RPC_S_DUPLICATE_ENDPOINT, RPC_S_UNKNOWN_AUTHN_TYPE, RPC_S_MAX_CALLS_TOO_SMALL, RPC_S_STRING_TOO_LONG, RPC_S_PROTSEQ_NOT_FOUND, RPC_S_PROCNUM_OUT_OF_RANGE, RPC_S_BINDING_HAS_NO_AUTH, RPC_S_UNKNOWN_AUTHN_SERVICE, RPC_S_UNKNOWN_AUTHN_LEVEL, RPC_S_INVALID_AUTH_IDENTITY, RPC_S_UNKNOWN_AUTHZ_SERVICE, EPT_S_INVALID_ENTRY, EPT_S_CANT_PERFORM_OP, EPT_S_NOT_REGISTERED, RPC_S_NOTHING_TO_EXPORT, RPC_S_INCOMPLETE_NAME, RPC_S_INVALID_VERS_OPTION, RPC_S_NO_MORE_MEMBERS, RPC_S_NOT_ALL_OBJS_UNEXPORTED, RPC_S_INTERFACE_NOT_FOUND, RPC_S_ENTRY_ALREADY_EXISTS, RPC_S_ENTRY_NOT_FOUND, RPC_S_NAME_SERVICE_UNAVAILABLE, RPC_S_INVALID_NAF_ID, RPC_S_CANNOT_SUPPORT, RPC_S_NO_CONTEXT_AVAILABLE, RPC_S_INTERNAL_ERROR, RPC_S_ZERO_DIVIDE, RPC_S_ADDRESS_ERROR, RPC_S_FP_DIV_ZERO, RPC_S_FP_UNDERFLOW, RPC_S_FP_OVERFLOW, RPC_X_NO_MORE_ENTRIES, RPC_X_SS_CHAR_TRANS_OPEN_FAIL, RPC_X_SS_CHAR_TRANS_SHORT_FILE, RPC_X_SS_IN_NULL_CONTEXT, // = 1775 RPC_X_SS_CONTEXT_DAMAGED = 1777, RPC_X_SS_HANDLES_MISMATCH, RPC_X_SS_CANNOT_GET_CALL_HANDLE, RPC_X_NULL_REF_POINTER, RPC_X_ENUM_VALUE_OUT_OF_RANGE, RPC_X_BYTE_COUNT_TOO_SMALL, RPC_X_BAD_STUB_DATA, ERROR_INVALID_USER_BUFFER, ERROR_UNRECOGNIZED_MEDIA, ERROR_NO_TRUST_LSA_SECRET, ERROR_NO_TRUST_SAM_ACCOUNT, ERROR_TRUSTED_DOMAIN_FAILURE, ERROR_TRUSTED_RELATIONSHIP_FAILURE, ERROR_TRUST_FAILURE, RPC_S_CALL_IN_PROGRESS, ERROR_NETLOGON_NOT_STARTED, ERROR_ACCOUNT_EXPIRED, ERROR_REDIRECTOR_HAS_OPEN_HANDLES, ERROR_PRINTER_DRIVER_ALREADY_INSTALLED, ERROR_UNKNOWN_PORT, ERROR_UNKNOWN_PRINTER_DRIVER, ERROR_UNKNOWN_PRINTPROCESSOR, ERROR_INVALID_SEPARATOR_FILE, ERROR_INVALID_PRIORITY, ERROR_INVALID_PRINTER_NAME, ERROR_PRINTER_ALREADY_EXISTS, ERROR_INVALID_PRINTER_COMMAND, ERROR_INVALID_DATATYPE, ERROR_INVALID_ENVIRONMENT, RPC_S_NO_MORE_BINDINGS, ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT, ERROR_NOLOGON_SERVER_TRUST_ACCOUNT, ERROR_DOMAIN_TRUST_INCONSISTENT, ERROR_SERVER_HAS_OPEN_HANDLES, ERROR_RESOURCE_DATA_NOT_FOUND, ERROR_RESOURCE_TYPE_NOT_FOUND, ERROR_RESOURCE_NAME_NOT_FOUND, ERROR_RESOURCE_LANG_NOT_FOUND, ERROR_NOT_ENOUGH_QUOTA, RPC_S_NO_INTERFACES, RPC_S_CALL_CANCELLED, RPC_S_BINDING_INCOMPLETE, RPC_S_COMM_FAILURE, RPC_S_UNSUPPORTED_AUTHN_LEVEL, RPC_S_NO_PRINC_NAME, RPC_S_NOT_RPC_ERROR, RPC_S_UUID_LOCAL_ONLY, RPC_S_SEC_PKG_ERROR, RPC_S_NOT_CANCELLED, RPC_X_INVALID_ES_ACTION, RPC_X_WRONG_ES_VERSION, RPC_X_WRONG_STUB_VERSION, RPC_X_INVALID_PIPE_OBJECT, RPC_X_WRONG_PIPE_ORDER, RPC_X_WRONG_PIPE_VERSION, // = 1832 RPC_S_GROUP_MEMBER_NOT_FOUND = 1898, EPT_S_CANT_CREATE, RPC_S_INVALID_OBJECT, ERROR_INVALID_TIME, ERROR_INVALID_FORM_NAME, ERROR_INVALID_FORM_SIZE, ERROR_ALREADY_WAITING, ERROR_PRINTER_DELETED, ERROR_INVALID_PRINTER_STATE, ERROR_PASSWORD_MUST_CHANGE, ERROR_DOMAIN_CONTROLLER_NOT_FOUND, ERROR_ACCOUNT_LOCKED_OUT, OR_INVALID_OXID, OR_INVALID_OID, OR_INVALID_SET, RPC_S_SEND_INCOMPLETE, RPC_S_INVALID_ASYNC_HANDLE, RPC_S_INVALID_ASYNC_CALL, RPC_X_PIPE_CLOSED, RPC_X_PIPE_DISCIPLINE_ERROR, RPC_X_PIPE_EMPTY, ERROR_NO_SITENAME, ERROR_CANT_ACCESS_FILE, ERROR_CANT_RESOLVE_FILENAME, RPC_S_ENTRY_TYPE_MISMATCH, RPC_S_NOT_ALL_OBJS_EXPORTED, RPC_S_INTERFACE_NOT_EXPORTED, RPC_S_PROFILE_NOT_ADDED, RPC_S_PRF_ELT_NOT_ADDED, RPC_S_PRF_ELT_NOT_REMOVED, RPC_S_GRP_ELT_NOT_ADDED, RPC_S_GRP_ELT_NOT_REMOVED, ERROR_KM_DRIVER_BLOCKED, ERROR_CONTEXT_EXPIRED, ERROR_PER_USER_TRUST_QUOTA_EXCEEDED, ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED, ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED, // = 1934 ERROR_INVALID_PIXEL_FORMAT = 2000, ERROR_BAD_DRIVER, ERROR_INVALID_WINDOW_STYLE, ERROR_METAFILE_NOT_SUPPORTED, ERROR_TRANSFORM_NOT_SUPPORTED, ERROR_CLIPPING_NOT_SUPPORTED, // = 2005 ERROR_INVALID_CMM = 2010, ERROR_INVALID_PROFILE, ERROR_TAG_NOT_FOUND, ERROR_TAG_NOT_PRESENT, ERROR_DUPLICATE_TAG, ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE, ERROR_PROFILE_NOT_FOUND, ERROR_INVALID_COLORSPACE, ERROR_ICM_NOT_ENABLED, ERROR_DELETING_ICM_XFORM, ERROR_INVALID_TRANSFORM, ERROR_COLORSPACE_MISMATCH, ERROR_INVALID_COLORINDEX, // = 2022 ERROR_CONNECTED_OTHER_PASSWORD = 2108, ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT, // = 2109 ERROR_BAD_USERNAME = 2202, ERROR_NOT_CONNECTED = 2250, ERROR_OPEN_FILES = 2401, ERROR_ACTIVE_CONNECTIONS, // = 2402 ERROR_DEVICE_IN_USE = 2404, ERROR_UNKNOWN_PRINT_MONITOR = 3000, ERROR_PRINTER_DRIVER_IN_USE, ERROR_SPOOL_FILE_NOT_FOUND, ERROR_SPL_NO_STARTDOC, ERROR_SPL_NO_ADDJOB, ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED, ERROR_PRINT_MONITOR_ALREADY_INSTALLED, ERROR_INVALID_PRINT_MONITOR, ERROR_PRINT_MONITOR_IN_USE, ERROR_PRINTER_HAS_JOBS_QUEUED, ERROR_SUCCESS_REBOOT_REQUIRED, ERROR_SUCCESS_RESTART_REQUIRED, ERROR_PRINTER_NOT_FOUND, ERROR_PRINTER_DRIVER_WARNED, ERROR_PRINTER_DRIVER_BLOCKED, // = 3014 ERROR_WINS_INTERNAL = 4000, ERROR_CAN_NOT_DEL_LOCAL_WINS, ERROR_STATIC_INIT, ERROR_INC_BACKUP, ERROR_FULL_BACKUP, ERROR_REC_NON_EXISTENT, ERROR_RPL_NOT_ALLOWED, // = 4006 ERROR_DHCP_ADDRESS_CONFLICT = 4100, ERROR_WMI_GUID_NOT_FOUND = 4200, ERROR_WMI_INSTANCE_NOT_FOUND, ERROR_WMI_ITEMID_NOT_FOUND, ERROR_WMI_TRY_AGAIN, ERROR_WMI_DP_NOT_FOUND, ERROR_WMI_UNRESOLVED_INSTANCE_REF, ERROR_WMI_ALREADY_ENABLED, ERROR_WMI_GUID_DISCONNECTED, ERROR_WMI_SERVER_UNAVAILABLE, ERROR_WMI_DP_FAILED, ERROR_WMI_INVALID_MOF, ERROR_WMI_INVALID_REGINFO, ERROR_WMI_ALREADY_DISABLED, ERROR_WMI_READ_ONLY, ERROR_WMI_SET_FAILURE, // = 4214 ERROR_INVALID_MEDIA = 4300, ERROR_INVALID_LIBRARY, ERROR_INVALID_MEDIA_POOL, ERROR_DRIVE_MEDIA_MISMATCH, ERROR_MEDIA_OFFLINE, ERROR_LIBRARY_OFFLINE, ERROR_EMPTY, ERROR_NOT_EMPTY, ERROR_MEDIA_UNAVAILABLE, ERROR_RESOURCE_DISABLED, ERROR_INVALID_CLEANER, ERROR_UNABLE_TO_CLEAN, ERROR_OBJECT_NOT_FOUND, ERROR_DATABASE_FAILURE, ERROR_DATABASE_FULL, ERROR_MEDIA_INCOMPATIBLE, ERROR_RESOURCE_NOT_PRESENT, ERROR_INVALID_OPERATION, ERROR_MEDIA_NOT_AVAILABLE, ERROR_DEVICE_NOT_AVAILABLE, ERROR_REQUEST_REFUSED, ERROR_INVALID_DRIVE_OBJECT, ERROR_LIBRARY_FULL, ERROR_MEDIUM_NOT_ACCESSIBLE, ERROR_UNABLE_TO_LOAD_MEDIUM, ERROR_UNABLE_TO_INVENTORY_DRIVE, ERROR_UNABLE_TO_INVENTORY_SLOT, ERROR_UNABLE_TO_INVENTORY_TRANSPORT, ERROR_TRANSPORT_FULL, ERROR_CONTROLLING_IEPORT, ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA, ERROR_CLEANER_SLOT_SET, ERROR_CLEANER_SLOT_NOT_SET, ERROR_CLEANER_CARTRIDGE_SPENT, ERROR_UNEXPECTED_OMID, ERROR_CANT_DELETE_LAST_ITEM, ERROR_MESSAGE_EXCEEDS_MAX_SIZE, ERROR_VOLUME_CONTAINS_SYS_FILES, ERROR_INDIGENOUS_TYPE, ERROR_NO_SUPPORTING_DRIVES, ERROR_CLEANER_CARTRIDGE_INSTALLED, // = 4340 ERROR_FILE_OFFLINE = 4350, ERROR_REMOTE_STORAGE_NOT_ACTIVE, ERROR_REMOTE_STORAGE_MEDIA_ERROR, // = 4352 ERROR_NOT_A_REPARSE_POINT = 4390, ERROR_REPARSE_ATTRIBUTE_CONFLICT, ERROR_INVALID_REPARSE_DATA, ERROR_REPARSE_TAG_INVALID, ERROR_REPARSE_TAG_MISMATCH, // = 4394 ERROR_VOLUME_NOT_SIS_ENABLED = 4500, ERROR_DEPENDENT_RESOURCE_EXISTS = 5001, ERROR_DEPENDENCY_NOT_FOUND, ERROR_DEPENDENCY_ALREADY_EXISTS, ERROR_RESOURCE_NOT_ONLINE, ERROR_HOST_NODE_NOT_AVAILABLE, ERROR_RESOURCE_NOT_AVAILABLE, ERROR_RESOURCE_NOT_FOUND, ERROR_SHUTDOWN_CLUSTER, ERROR_CANT_EVICT_ACTIVE_NODE, ERROR_OBJECT_ALREADY_EXISTS, ERROR_OBJECT_IN_LIST, ERROR_GROUP_NOT_AVAILABLE, ERROR_GROUP_NOT_FOUND, ERROR_GROUP_NOT_ONLINE, ERROR_HOST_NODE_NOT_RESOURCE_OWNER, ERROR_HOST_NODE_NOT_GROUP_OWNER, ERROR_RESMON_CREATE_FAILED, ERROR_RESMON_ONLINE_FAILED, ERROR_RESOURCE_ONLINE, ERROR_QUORUM_RESOURCE, ERROR_NOT_QUORUM_CAPABLE, ERROR_CLUSTER_SHUTTING_DOWN, ERROR_INVALID_STATE, ERROR_RESOURCE_PROPERTIES_STORED, ERROR_NOT_QUORUM_CLASS, ERROR_CORE_RESOURCE, ERROR_QUORUM_RESOURCE_ONLINE_FAILED, ERROR_QUORUMLOG_OPEN_FAILED, ERROR_CLUSTERLOG_CORRUPT, ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE, ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE, ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND, ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE, ERROR_QUORUM_OWNER_ALIVE, ERROR_NETWORK_NOT_AVAILABLE, ERROR_NODE_NOT_AVAILABLE, ERROR_ALL_NODES_NOT_AVAILABLE, ERROR_RESOURCE_FAILED, ERROR_CLUSTER_INVALID_NODE, ERROR_CLUSTER_NODE_EXISTS, ERROR_CLUSTER_JOIN_IN_PROGRESS, ERROR_CLUSTER_NODE_NOT_FOUND, ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND, ERROR_CLUSTER_NETWORK_EXISTS, ERROR_CLUSTER_NETWORK_NOT_FOUND, ERROR_CLUSTER_NETINTERFACE_EXISTS, ERROR_CLUSTER_NETINTERFACE_NOT_FOUND, ERROR_CLUSTER_INVALID_REQUEST, ERROR_CLUSTER_INVALID_NETWORK_PROVIDER, ERROR_CLUSTER_NODE_DOWN, ERROR_CLUSTER_NODE_UNREACHABLE, ERROR_CLUSTER_NODE_NOT_MEMBER, ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS, ERROR_CLUSTER_INVALID_NETWORK, // = 5054 ERROR_CLUSTER_NODE_UP = 5056, ERROR_CLUSTER_IPADDR_IN_USE, ERROR_CLUSTER_NODE_NOT_PAUSED, ERROR_CLUSTER_NO_SECURITY_CONTEXT, ERROR_CLUSTER_NETWORK_NOT_INTERNAL, ERROR_CLUSTER_NODE_ALREADY_UP, ERROR_CLUSTER_NODE_ALREADY_DOWN, ERROR_CLUSTER_NETWORK_ALREADY_ONLINE, ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE, ERROR_CLUSTER_NODE_ALREADY_MEMBER, ERROR_CLUSTER_LAST_INTERNAL_NETWORK, ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS, ERROR_INVALID_OPERATION_ON_QUORUM, ERROR_DEPENDENCY_NOT_ALLOWED, ERROR_CLUSTER_NODE_PAUSED, ERROR_NODE_CANT_HOST_RESOURCE, ERROR_CLUSTER_NODE_NOT_READY, ERROR_CLUSTER_NODE_SHUTTING_DOWN, ERROR_CLUSTER_JOIN_ABORTED, ERROR_CLUSTER_INCOMPATIBLE_VERSIONS, ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED, ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED, ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND, ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED, ERROR_CLUSTER_RESNAME_NOT_FOUND, ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED, ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST, ERROR_CLUSTER_DATABASE_SEQMISMATCH, ERROR_RESMON_INVALID_STATE, ERROR_CLUSTER_GUM_NOT_LOCKER, ERROR_QUORUM_DISK_NOT_FOUND, ERROR_DATABASE_BACKUP_CORRUPT, ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT, ERROR_RESOURCE_PROPERTY_UNCHANGEABLE, // = 5089 ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE = 5890, ERROR_CLUSTER_QUORUMLOG_NOT_FOUND, ERROR_CLUSTER_MEMBERSHIP_HALT, ERROR_CLUSTER_INSTANCE_ID_MISMATCH, ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP, ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH, ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP, ERROR_CLUSTER_PARAMETER_MISMATCH, ERROR_NODE_CANNOT_BE_CLUSTERED, ERROR_CLUSTER_WRONG_OS_VERSION, ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME, ERROR_CLUSCFG_ALREADY_COMMITTED, ERROR_CLUSCFG_ROLLBACK_FAILED, ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT, ERROR_CLUSTER_OLD_VERSION, ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME, // = 5905 ERROR_ENCRYPTION_FAILED = 6000, ERROR_DECRYPTION_FAILED, ERROR_FILE_ENCRYPTED, ERROR_NO_RECOVERY_POLICY, ERROR_NO_EFS, ERROR_WRONG_EFS, ERROR_NO_USER_KEYS, ERROR_FILE_NOT_ENCRYPTED, ERROR_NOT_EXPORT_FORMAT, ERROR_FILE_READ_ONLY, ERROR_DIR_EFS_DISALLOWED, ERROR_EFS_SERVER_NOT_TRUSTED, ERROR_BAD_RECOVERY_POLICY, ERROR_EFS_ALG_BLOB_TOO_BIG, ERROR_VOLUME_NOT_SUPPORT_EFS, ERROR_EFS_DISABLED, ERROR_EFS_VERSION_NOT_SUPPORT, // = 6016 ERROR_NO_BROWSER_SERVERS_FOUND = 6118, SCHED_E_SERVICE_NOT_LOCALSYSTEM = 6200, ERROR_CTX_WINSTATION_NAME_INVALID = 7001, ERROR_CTX_INVALID_PD, ERROR_CTX_PD_NOT_FOUND, ERROR_CTX_WD_NOT_FOUND, ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY, ERROR_CTX_SERVICE_NAME_COLLISION, ERROR_CTX_CLOSE_PENDING, ERROR_CTX_NO_OUTBUF, ERROR_CTX_MODEM_INF_NOT_FOUND, ERROR_CTX_INVALID_MODEMNAME, ERROR_CTX_MODEM_RESPONSE_ERROR, ERROR_CTX_MODEM_RESPONSE_TIMEOUT, ERROR_CTX_MODEM_RESPONSE_NO_CARRIER, ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE, ERROR_CTX_MODEM_RESPONSE_BUSY, ERROR_CTX_MODEM_RESPONSE_VOICE, ERROR_CTX_TD_ERROR, // = 7017 ERROR_CTX_WINSTATION_NOT_FOUND = 7022, ERROR_CTX_WINSTATION_ALREADY_EXISTS, ERROR_CTX_WINSTATION_BUSY, ERROR_CTX_BAD_VIDEO_MODE, // = 7025 ERROR_CTX_GRAPHICS_INVALID = 7035, ERROR_CTX_LOGON_DISABLED = 7037, ERROR_CTX_NOT_CONSOLE, // = 7038 ERROR_CTX_CLIENT_QUERY_TIMEOUT = 7040, ERROR_CTX_CONSOLE_DISCONNECT, ERROR_CTX_CONSOLE_CONNECT, // = 7042 ERROR_CTX_SHADOW_DENIED = 7044, ERROR_CTX_WINSTATION_ACCESS_DENIED, // = 7045 ERROR_CTX_INVALID_WD = 7049, ERROR_CTX_SHADOW_INVALID, ERROR_CTX_SHADOW_DISABLED, ERROR_CTX_CLIENT_LICENSE_IN_USE, ERROR_CTX_CLIENT_LICENSE_NOT_SET, ERROR_CTX_LICENSE_NOT_AVAILABLE, ERROR_CTX_LICENSE_CLIENT_INVALID, ERROR_CTX_LICENSE_EXPIRED, ERROR_CTX_SHADOW_NOT_RUNNING, ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE, ERROR_ACTIVATION_COUNT_EXCEEDED, // = 7059 FRS_ERR_INVALID_API_SEQUENCE = 8001, FRS_ERR_STARTING_SERVICE, FRS_ERR_STOPPING_SERVICE, FRS_ERR_INTERNAL_API, FRS_ERR_INTERNAL, FRS_ERR_SERVICE_COMM, FRS_ERR_INSUFFICIENT_PRIV, FRS_ERR_AUTHENTICATION, FRS_ERR_PARENT_INSUFFICIENT_PRIV, FRS_ERR_PARENT_AUTHENTICATION, FRS_ERR_CHILD_TO_PARENT_COMM, FRS_ERR_PARENT_TO_CHILD_COMM, FRS_ERR_SYSVOL_POPULATE, FRS_ERR_SYSVOL_POPULATE_TIMEOUT, FRS_ERR_SYSVOL_IS_BUSY, FRS_ERR_SYSVOL_DEMOTE, FRS_ERR_INVALID_SERVICE_PARAMETER, // = 8017 ERROR_DS_NOT_INSTALLED = 8200, ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY, ERROR_DS_NO_ATTRIBUTE_OR_VALUE, ERROR_DS_INVALID_ATTRIBUTE_SYNTAX, ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED, ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS, ERROR_DS_BUSY, ERROR_DS_UNAVAILABLE, ERROR_DS_NO_RIDS_ALLOCATED, ERROR_DS_NO_MORE_RIDS, ERROR_DS_INCORRECT_ROLE_OWNER, ERROR_DS_RIDMGR_INIT_ERROR, ERROR_DS_OBJ_CLASS_VIOLATION, ERROR_DS_CANT_ON_NON_LEAF, ERROR_DS_CANT_ON_RDN, ERROR_DS_CANT_MOD_OBJ_CLASS, ERROR_DS_CROSS_DOM_MOVE_ERROR, ERROR_DS_GC_NOT_AVAILABLE, ERROR_SHARED_POLICY, ERROR_POLICY_OBJECT_NOT_FOUND, ERROR_POLICY_ONLY_IN_DS, ERROR_PROMOTION_ACTIVE, ERROR_NO_PROMOTION_ACTIVE, // = 8222 ERROR_DS_OPERATIONS_ERROR = 8224, ERROR_DS_PROTOCOL_ERROR, ERROR_DS_TIMELIMIT_EXCEEDED, ERROR_DS_SIZELIMIT_EXCEEDED, ERROR_DS_ADMIN_LIMIT_EXCEEDED, ERROR_DS_COMPARE_FALSE, ERROR_DS_COMPARE_TRUE, ERROR_DS_AUTH_METHOD_NOT_SUPPORTED, ERROR_DS_STRONG_AUTH_REQUIRED, ERROR_DS_INAPPROPRIATE_AUTH, ERROR_DS_AUTH_UNKNOWN, ERROR_DS_REFERRAL, ERROR_DS_UNAVAILABLE_CRIT_EXTENSION, ERROR_DS_CONFIDENTIALITY_REQUIRED, ERROR_DS_INAPPROPRIATE_MATCHING, ERROR_DS_CONSTRAINT_VIOLATION, ERROR_DS_NO_SUCH_OBJECT, ERROR_DS_ALIAS_PROBLEM, ERROR_DS_INVALID_DN_SYNTAX, ERROR_DS_IS_LEAF, ERROR_DS_ALIAS_DEREF_PROBLEM, ERROR_DS_UNWILLING_TO_PERFORM, ERROR_DS_LOOP_DETECT, ERROR_DS_NAMING_VIOLATION, ERROR_DS_OBJECT_RESULTS_TOO_LARGE, ERROR_DS_AFFECTS_MULTIPLE_DSAS, ERROR_DS_SERVER_DOWN, ERROR_DS_LOCAL_ERROR, ERROR_DS_ENCODING_ERROR, ERROR_DS_DECODING_ERROR, ERROR_DS_FILTER_UNKNOWN, ERROR_DS_PARAM_ERROR, ERROR_DS_NOT_SUPPORTED, ERROR_DS_NO_RESULTS_RETURNED, ERROR_DS_CONTROL_NOT_FOUND, ERROR_DS_CLIENT_LOOP, ERROR_DS_REFERRAL_LIMIT_EXCEEDED, ERROR_DS_SORT_CONTROL_MISSING, ERROR_DS_OFFSET_RANGE_ERROR, // = 8262 ERROR_DS_ROOT_MUST_BE_NC = 8301, ERROR_DS_ADD_REPLICA_INHIBITED, ERROR_DS_ATT_NOT_DEF_IN_SCHEMA, ERROR_DS_MAX_OBJ_SIZE_EXCEEDED, ERROR_DS_OBJ_STRING_NAME_EXISTS, ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA, ERROR_DS_RDN_DOESNT_MATCH_SCHEMA, ERROR_DS_NO_REQUESTED_ATTS_FOUND, ERROR_DS_USER_BUFFER_TO_SMALL, ERROR_DS_ATT_IS_NOT_ON_OBJ, ERROR_DS_ILLEGAL_MOD_OPERATION, ERROR_DS_OBJ_TOO_LARGE, ERROR_DS_BAD_INSTANCE_TYPE, ERROR_DS_MASTERDSA_REQUIRED, ERROR_DS_OBJECT_CLASS_REQUIRED, ERROR_DS_MISSING_REQUIRED_ATT, ERROR_DS_ATT_NOT_DEF_FOR_CLASS, ERROR_DS_ATT_ALREADY_EXISTS, // = 8318 ERROR_DS_CANT_ADD_ATT_VALUES = 8320, ERROR_DS_SINGLE_VALUE_CONSTRAINT, ERROR_DS_RANGE_CONSTRAINT, ERROR_DS_ATT_VAL_ALREADY_EXISTS, ERROR_DS_CANT_REM_MISSING_ATT, ERROR_DS_CANT_REM_MISSING_ATT_VAL, ERROR_DS_ROOT_CANT_BE_SUBREF, ERROR_DS_NO_CHAINING, ERROR_DS_NO_CHAINED_EVAL, ERROR_DS_NO_PARENT_OBJECT, ERROR_DS_PARENT_IS_AN_ALIAS, ERROR_DS_CANT_MIX_MASTER_AND_REPS, ERROR_DS_CHILDREN_EXIST, ERROR_DS_OBJ_NOT_FOUND, ERROR_DS_ALIASED_OBJ_MISSING, ERROR_DS_BAD_NAME_SYNTAX, ERROR_DS_ALIAS_POINTS_TO_ALIAS, ERROR_DS_CANT_DEREF_ALIAS, ERROR_DS_OUT_OF_SCOPE, ERROR_DS_OBJECT_BEING_REMOVED, ERROR_DS_CANT_DELETE_DSA_OBJ, ERROR_DS_GENERIC_ERROR, ERROR_DS_DSA_MUST_BE_INT_MASTER, ERROR_DS_CLASS_NOT_DSA, ERROR_DS_INSUFF_ACCESS_RIGHTS, ERROR_DS_ILLEGAL_SUPERIOR, ERROR_DS_ATTRIBUTE_OWNED_BY_SAM, ERROR_DS_NAME_TOO_MANY_PARTS, ERROR_DS_NAME_TOO_LONG, ERROR_DS_NAME_VALUE_TOO_LONG, ERROR_DS_NAME_UNPARSEABLE, ERROR_DS_NAME_TYPE_UNKNOWN, ERROR_DS_NOT_AN_OBJECT, ERROR_DS_SEC_DESC_TOO_SHORT, ERROR_DS_SEC_DESC_INVALID, ERROR_DS_NO_DELETED_NAME, ERROR_DS_SUBREF_MUST_HAVE_PARENT, ERROR_DS_NCNAME_MUST_BE_NC, ERROR_DS_CANT_ADD_SYSTEM_ONLY, ERROR_DS_CLASS_MUST_BE_CONCRETE, ERROR_DS_INVALID_DMD, ERROR_DS_OBJ_GUID_EXISTS, ERROR_DS_NOT_ON_BACKLINK, ERROR_DS_NO_CROSSREF_FOR_NC, ERROR_DS_SHUTTING_DOWN, ERROR_DS_UNKNOWN_OPERATION, ERROR_DS_INVALID_ROLE_OWNER, ERROR_DS_COULDNT_CONTACT_FSMO, ERROR_DS_CROSS_NC_DN_RENAME, ERROR_DS_CANT_MOD_SYSTEM_ONLY, ERROR_DS_REPLICATOR_ONLY, ERROR_DS_OBJ_CLASS_NOT_DEFINED, ERROR_DS_OBJ_CLASS_NOT_SUBCLASS, ERROR_DS_NAME_REFERENCE_INVALID, ERROR_DS_CROSS_REF_EXISTS, ERROR_DS_CANT_DEL_MASTER_CROSSREF, ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD, ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX, ERROR_DS_DUP_RDN, ERROR_DS_DUP_OID, ERROR_DS_DUP_MAPI_ID, ERROR_DS_DUP_SCHEMA_ID_GUID, ERROR_DS_DUP_LDAP_DISPLAY_NAME, ERROR_DS_SEMANTIC_ATT_TEST, ERROR_DS_SYNTAX_MISMATCH, ERROR_DS_EXISTS_IN_MUST_HAVE, ERROR_DS_EXISTS_IN_MAY_HAVE, ERROR_DS_NONEXISTENT_MAY_HAVE, ERROR_DS_NONEXISTENT_MUST_HAVE, ERROR_DS_AUX_CLS_TEST_FAIL, ERROR_DS_NONEXISTENT_POSS_SUP, ERROR_DS_SUB_CLS_TEST_FAIL, ERROR_DS_BAD_RDN_ATT_ID_SYNTAX, ERROR_DS_EXISTS_IN_AUX_CLS, ERROR_DS_EXISTS_IN_SUB_CLS, ERROR_DS_EXISTS_IN_POSS_SUP, ERROR_DS_RECALCSCHEMA_FAILED, ERROR_DS_TREE_DELETE_NOT_FINISHED, ERROR_DS_CANT_DELETE, ERROR_DS_ATT_SCHEMA_REQ_ID, ERROR_DS_BAD_ATT_SCHEMA_SYNTAX, ERROR_DS_CANT_CACHE_ATT, ERROR_DS_CANT_CACHE_CLASS, ERROR_DS_CANT_REMOVE_ATT_CACHE, ERROR_DS_CANT_REMOVE_CLASS_CACHE, ERROR_DS_CANT_RETRIEVE_DN, ERROR_DS_MISSING_SUPREF, ERROR_DS_CANT_RETRIEVE_INSTANCE, ERROR_DS_CODE_INCONSISTENCY, ERROR_DS_DATABASE_ERROR, ERROR_DS_GOVERNSID_MISSING, ERROR_DS_MISSING_EXPECTED_ATT, ERROR_DS_NCNAME_MISSING_CR_REF, ERROR_DS_SECURITY_CHECKING_ERROR, ERROR_DS_SCHEMA_NOT_LOADED, ERROR_DS_SCHEMA_ALLOC_FAILED, ERROR_DS_ATT_SCHEMA_REQ_SYNTAX, ERROR_DS_GCVERIFY_ERROR, ERROR_DS_DRA_SCHEMA_MISMATCH, ERROR_DS_CANT_FIND_DSA_OBJ, ERROR_DS_CANT_FIND_EXPECTED_NC, ERROR_DS_CANT_FIND_NC_IN_CACHE, ERROR_DS_CANT_RETRIEVE_CHILD, ERROR_DS_SECURITY_ILLEGAL_MODIFY, ERROR_DS_CANT_REPLACE_HIDDEN_REC, ERROR_DS_BAD_HIERARCHY_FILE, ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED, ERROR_DS_CONFIG_PARAM_MISSING, ERROR_DS_COUNTING_AB_INDICES_FAILED, ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED, ERROR_DS_INTERNAL_FAILURE, ERROR_DS_UNKNOWN_ERROR, ERROR_DS_ROOT_REQUIRES_CLASS_TOP, ERROR_DS_REFUSING_FSMO_ROLES, ERROR_DS_MISSING_FSMO_SETTINGS, ERROR_DS_UNABLE_TO_SURRENDER_ROLES, ERROR_DS_DRA_GENERIC, ERROR_DS_DRA_INVALID_PARAMETER, ERROR_DS_DRA_BUSY, ERROR_DS_DRA_BAD_DN, ERROR_DS_DRA_BAD_NC, ERROR_DS_DRA_DN_EXISTS, ERROR_DS_DRA_INTERNAL_ERROR, ERROR_DS_DRA_INCONSISTENT_DIT, ERROR_DS_DRA_CONNECTION_FAILED, ERROR_DS_DRA_BAD_INSTANCE_TYPE, ERROR_DS_DRA_OUT_OF_MEM, ERROR_DS_DRA_MAIL_PROBLEM, ERROR_DS_DRA_REF_ALREADY_EXISTS, ERROR_DS_DRA_REF_NOT_FOUND, ERROR_DS_DRA_OBJ_IS_REP_SOURCE, ERROR_DS_DRA_DB_ERROR, ERROR_DS_DRA_NO_REPLICA, ERROR_DS_DRA_ACCESS_DENIED, ERROR_DS_DRA_NOT_SUPPORTED, ERROR_DS_DRA_RPC_CANCELLED, ERROR_DS_DRA_SOURCE_DISABLED, ERROR_DS_DRA_SINK_DISABLED, ERROR_DS_DRA_NAME_COLLISION, ERROR_DS_DRA_SOURCE_REINSTALLED, ERROR_DS_DRA_MISSING_PARENT, ERROR_DS_DRA_PREEMPTED, ERROR_DS_DRA_ABANDON_SYNC, ERROR_DS_DRA_SHUTDOWN, ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET, ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA, ERROR_DS_DRA_EXTN_CONNECTION_FAILED, ERROR_DS_INSTALL_SCHEMA_MISMATCH, ERROR_DS_DUP_LINK_ID, ERROR_DS_NAME_ERROR_RESOLVING, ERROR_DS_NAME_ERROR_NOT_FOUND, ERROR_DS_NAME_ERROR_NOT_UNIQUE, ERROR_DS_NAME_ERROR_NO_MAPPING, ERROR_DS_NAME_ERROR_DOMAIN_ONLY, ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING, ERROR_DS_CONSTRUCTED_ATT_MOD, ERROR_DS_WRONG_OM_OBJ_CLASS, ERROR_DS_DRA_REPL_PENDING, ERROR_DS_DS_REQUIRED, ERROR_DS_INVALID_LDAP_DISPLAY_NAME, ERROR_DS_NON_BASE_SEARCH, ERROR_DS_CANT_RETRIEVE_ATTS, ERROR_DS_BACKLINK_WITHOUT_LINK, ERROR_DS_EPOCH_MISMATCH, ERROR_DS_SRC_NAME_MISMATCH, ERROR_DS_SRC_AND_DST_NC_IDENTICAL, ERROR_DS_DST_NC_MISMATCH, ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC, ERROR_DS_SRC_GUID_MISMATCH, ERROR_DS_CANT_MOVE_DELETED_OBJECT, ERROR_DS_PDC_OPERATION_IN_PROGRESS, ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD, ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION, ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS, ERROR_DS_NC_MUST_HAVE_NC_PARENT, ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE, ERROR_DS_DST_DOMAIN_NOT_NATIVE, ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER, ERROR_DS_CANT_MOVE_ACCOUNT_GROUP, ERROR_DS_CANT_MOVE_RESOURCE_GROUP, ERROR_DS_INVALID_SEARCH_FLAG, ERROR_DS_NO_TREE_DELETE_ABOVE_NC, ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE, ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE, ERROR_DS_SAM_INIT_FAILURE, ERROR_DS_SENSITIVE_GROUP_VIOLATION, ERROR_DS_CANT_MOD_PRIMARYGROUPID, ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD, ERROR_DS_NONSAFE_SCHEMA_CHANGE, ERROR_DS_SCHEMA_UPDATE_DISALLOWED, ERROR_DS_CANT_CREATE_UNDER_SCHEMA, ERROR_DS_INSTALL_NO_SRC_SCH_VERSION, ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE, ERROR_DS_INVALID_GROUP_TYPE, ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN, ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN, ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER, ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER, ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER, ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER, ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER, ERROR_DS_HAVE_PRIMARY_MEMBERS, ERROR_DS_STRING_SD_CONVERSION_FAILED, ERROR_DS_NAMING_MASTER_GC, ERROR_DS_LOOKUP_FAILURE, ERROR_DS_COULDNT_UPDATE_SPNS, ERROR_DS_CANT_RETRIEVE_SD, ERROR_DS_KEY_NOT_UNIQUE, ERROR_DS_WRONG_LINKED_ATT_SYNTAX, ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD, ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY, ERROR_DS_CANT_START, ERROR_DS_INIT_FAILURE, ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION, ERROR_DS_SOURCE_DOMAIN_IN_FOREST, ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST, ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED, ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN, ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER, ERROR_DS_SRC_SID_EXISTS_IN_FOREST, ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH, ERROR_SAM_INIT_FAILURE, ERROR_DS_DRA_SCHEMA_INFO_SHIP, ERROR_DS_DRA_SCHEMA_CONFLICT, ERROR_DS_DRA_EARLIER_SCHEMA_CONLICT, ERROR_DS_DRA_OBJ_NC_MISMATCH, ERROR_DS_NC_STILL_HAS_DSAS, ERROR_DS_GC_REQUIRED, ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY, ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS, ERROR_DS_CANT_ADD_TO_GC, ERROR_DS_NO_CHECKPOINT_WITH_PDC, ERROR_DS_SOURCE_AUDITING_NOT_ENABLED, ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC, ERROR_DS_INVALID_NAME_FOR_SPN, ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS, ERROR_DS_UNICODEPWD_NOT_IN_QUOTES, ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED, ERROR_DS_MUST_BE_RUN_ON_DST_DC, ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER, ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ, ERROR_DS_INIT_FAILURE_CONSOLE, ERROR_DS_SAM_INIT_FAILURE_CONSOLE, ERROR_DS_FOREST_VERSION_TOO_HIGH, ERROR_DS_DOMAIN_VERSION_TOO_HIGH, ERROR_DS_FOREST_VERSION_TOO_LOW, ERROR_DS_DOMAIN_VERSION_TOO_LOW, ERROR_DS_INCOMPATIBLE_VERSION, ERROR_DS_LOW_DSA_VERSION, ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN, ERROR_DS_NOT_SUPPORTED_SORT_ORDER, ERROR_DS_NAME_NOT_UNIQUE, ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4, ERROR_DS_OUT_OF_VERSION_STORE, ERROR_DS_INCOMPATIBLE_CONTROLS_USED, ERROR_DS_NO_REF_DOMAIN, ERROR_DS_RESERVED_LINK_ID, ERROR_DS_LINK_ID_NOT_AVAILABLE, ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER, ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE, ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC, ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG, ERROR_DS_MODIFYDN_WRONG_GRANDPARENT, ERROR_DS_NAME_ERROR_TRUST_REFERRAL, ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER, ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD, ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2, ERROR_DS_THREAD_LIMIT_EXCEEDED, ERROR_DS_NOT_CLOSEST, ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF, ERROR_DS_SINGLE_USER_MODE_FAILED, ERROR_DS_NTDSCRIPT_SYNTAX_ERROR, ERROR_DS_NTDSCRIPT_PROCESS_ERROR, ERROR_DS_DIFFERENT_REPL_EPOCHS, ERROR_DS_DRS_EXTENSIONS_CHANGED, ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR, ERROR_DS_NO_MSDS_INTID, ERROR_DS_DUP_MSDS_INTID, ERROR_DS_EXISTS_IN_RDNATTID, ERROR_DS_AUTHORIZATION_FAILED, ERROR_DS_INVALID_SCRIPT, ERROR_DS_REMOTE_CROSSREF_OP_FAILED, ERROR_DS_CROSS_REF_BUSY, ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN, ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC, ERROR_DS_DUPLICATE_ID_FOUND, ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT, ERROR_DS_GROUP_CONVERSION_ERROR, ERROR_DS_CANT_MOVE_APP_BASIC_GROUP, ERROR_DS_CANT_MOVE_APP_QUERY_GROUP, ERROR_DS_ROLE_NOT_VERIFIED, ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL, ERROR_DS_DOMAIN_RENAME_IN_PROGRESS, ERROR_DS_EXISTING_AD_CHILD_NC, // = 8613 DNS_ERROR_RCODE_FORMAT_ERROR = 9001, DNS_ERROR_RCODE_SERVER_FAILURE, DNS_ERROR_RCODE_NAME_ERROR, DNS_ERROR_RCODE_NOT_IMPLEMENTED, DNS_ERROR_RCODE_REFUSED, DNS_ERROR_RCODE_YXDOMAIN, DNS_ERROR_RCODE_YXRRSET, DNS_ERROR_RCODE_NXRRSET, DNS_ERROR_RCODE_NOTAUTH, DNS_ERROR_RCODE_NOTZONE, // = 9010 DNS_ERROR_RCODE_BADSIG = 9016, DNS_ERROR_RCODE_BADKEY, DNS_ERROR_RCODE_BADTIME, // = 9018 DNS_INFO_NO_RECORDS = 9501, DNS_ERROR_BAD_PACKET, DNS_ERROR_NO_PACKET, DNS_ERROR_RCODE, DNS_ERROR_UNSECURE_PACKET, // = 9505 DNS_ERROR_INVALID_TYPE = 9551, DNS_ERROR_INVALID_IP_ADDRESS, DNS_ERROR_INVALID_PROPERTY, DNS_ERROR_TRY_AGAIN_LATER, DNS_ERROR_NOT_UNIQUE, DNS_ERROR_NON_RFC_NAME, DNS_STATUS_FQDN, DNS_STATUS_DOTTED_NAME, DNS_STATUS_SINGLE_PART_NAME, DNS_ERROR_INVALID_NAME_CHAR, DNS_ERROR_NUMERIC_NAME, DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER, DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION, DNS_ERROR_CANNOT_FIND_ROOT_HINTS, DNS_ERROR_INCONSISTENT_ROOT_HINTS, // = 9565 DNS_ERROR_ZONE_DOES_NOT_EXIST = 9601, DNS_ERROR_NO_ZONE_INFO, DNS_ERROR_INVALID_ZONE_OPERATION, DNS_ERROR_ZONE_CONFIGURATION_ERROR, DNS_ERROR_ZONE_HAS_NO_SOA_RECORD, DNS_ERROR_ZONE_HAS_NO_NS_RECORDS, DNS_ERROR_ZONE_LOCKED, DNS_ERROR_ZONE_CREATION_FAILED, DNS_ERROR_ZONE_ALREADY_EXISTS, DNS_ERROR_AUTOZONE_ALREADY_EXISTS, DNS_ERROR_INVALID_ZONE_TYPE, DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP, DNS_ERROR_ZONE_NOT_SECONDARY, DNS_ERROR_NEED_SECONDARY_ADDRESSES, DNS_ERROR_WINS_INIT_FAILED, DNS_ERROR_NEED_WINS_SERVERS, DNS_ERROR_NBSTAT_INIT_FAILED, DNS_ERROR_SOA_DELETE_INVALID, DNS_ERROR_FORWARDER_ALREADY_EXISTS, DNS_ERROR_ZONE_REQUIRES_MASTER_IP, DNS_ERROR_ZONE_IS_SHUTDOWN, // = 9621 DNS_ERROR_PRIMARY_REQUIRES_DATAFILE = 9651, DNS_ERROR_INVALID_DATAFILE_NAME, DNS_ERROR_DATAFILE_OPEN_FAILURE, DNS_ERROR_FILE_WRITEBACK_FAILED, DNS_ERROR_DATAFILE_PARSING, // = 9655 DNS_ERROR_RECORD_DOES_NOT_EXIST = 9701, DNS_ERROR_RECORD_FORMAT, DNS_ERROR_NODE_CREATION_FAILED, DNS_ERROR_UNKNOWN_RECORD_TYPE, DNS_ERROR_RECORD_TIMED_OUT, DNS_ERROR_NAME_NOT_IN_ZONE, DNS_ERROR_CNAME_LOOP, DNS_ERROR_NODE_IS_CNAME, DNS_ERROR_CNAME_COLLISION, DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT, DNS_ERROR_RECORD_ALREADY_EXISTS, DNS_ERROR_SECONDARY_DATA, DNS_ERROR_NO_CREATE_CACHE_DATA, DNS_ERROR_NAME_DOES_NOT_EXIST, DNS_WARNING_PTR_CREATE_FAILED, DNS_WARNING_DOMAIN_UNDELETED, DNS_ERROR_DS_UNAVAILABLE, DNS_ERROR_DS_ZONE_ALREADY_EXISTS, DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE, // = 9719 DNS_INFO_AXFR_COMPLETE = 9751, DNS_ERROR_AXFR, DNS_INFO_ADDED_LOCAL_WINS, // = 9753 DNS_STATUS_CONTINUE_NEEDED = 9801, DNS_ERROR_NO_TCPIP = 9851, DNS_ERROR_NO_DNS_SERVERS, // = 9852 DNS_ERROR_DP_DOES_NOT_EXIST = 9901, DNS_ERROR_DP_ALREADY_EXISTS, DNS_ERROR_DP_NOT_ENLISTED, DNS_ERROR_DP_ALREADY_ENLISTED, DNS_ERROR_DP_NOT_AVAILABLE, // = 9905 /+ already in winsock2.d defined! WSABASEERR = 10000, WSAEINTR = 10004, WSAEBADF = 10009, WSAEACCES = 10013, WSAEFAULT, // = 10014 WSAEINVAL = 10022, WSAEMFILE = 10024, WSAEWOULDBLOCK = 10035, WSAEINPROGRESS, WSAEALREADY, WSAENOTSOCK, WSAEDESTADDRREQ, WSAEMSGSIZE, WSAEPROTOTYPE, WSAENOPROTOOPT, WSAEPROTONOSUPPORT, WSAESOCKTNOSUPPORT, WSAEOPNOTSUPP, WSAEPFNOSUPPORT, WSAEAFNOSUPPORT, WSAEADDRINUSE, WSAEADDRNOTAVAIL, WSAENETDOWN, WSAENETUNREACH, WSAENETRESET, WSAECONNABORTED, WSAECONNRESET, WSAENOBUFS, WSAEISCONN, WSAENOTCONN, WSAESHUTDOWN, WSAETOOMANYREFS, WSAETIMEDOUT, WSAECONNREFUSED, WSAELOOP, WSAENAMETOOLONG, WSAEHOSTDOWN, WSAEHOSTUNREACH, WSAENOTEMPTY, WSAEPROCLIM, WSAEUSERS, WSAEDQUOT, WSAESTALE, WSAEREMOTE, // = 10071 WSASYSNOTREADY = 10091, WSAVERNOTSUPPORTED, WSANOTINITIALISED, // = 10093 WSAEDISCON = 10101, WSAENOMORE, WSAECANCELLED, WSAEINVALIDPROCTABLE, WSAEINVALIDPROVIDER, WSAEPROVIDERFAILEDINIT, WSASYSCALLFAILURE, WSASERVICE_NOT_FOUND, WSATYPE_NOT_FOUND, WSA_E_NO_MORE, WSA_E_CANCELLED, WSAEREFUSED, // = 10112 WSAHOST_NOT_FOUND = 11001, WSATRY_AGAIN, WSANO_RECOVERY, WSANO_DATA, WSA_QOS_RECEIVERS, WSA_QOS_SENDERS, WSA_QOS_NO_SENDERS, WSA_QOS_NO_RECEIVERS, WSA_QOS_REQUEST_CONFIRMED, WSA_QOS_ADMISSION_FAILURE, WSA_QOS_POLICY_FAILURE, WSA_QOS_BAD_STYLE, WSA_QOS_BAD_OBJECT, WSA_QOS_TRAFFIC_CTRL_ERROR, WSA_QOS_GENERIC_ERROR, WSA_QOS_ESERVICETYPE, WSA_QOS_EFLOWSPEC, WSA_QOS_EPROVSPECBUF, WSA_QOS_EFILTERSTYLE, WSA_QOS_EFILTERTYPE, WSA_QOS_EFILTERCOUNT, WSA_QOS_EOBJLENGTH, WSA_QOS_EFLOWCOUNT, WSA_QOS_EUNKNOWNPSOBJ, WSA_QOS_EPOLICYOBJ, WSA_QOS_EFLOWDESC, WSA_QOS_EPSFLOWSPEC, WSA_QOS_EPSFILTERSPEC, WSA_QOS_ESDMODEOBJ, WSA_QOS_ESHAPERATEOBJ, WSA_QOS_RESERVED_PETYPE, // = 11031 +/ ERROR_IPSEC_QM_POLICY_EXISTS = 13000, ERROR_IPSEC_QM_POLICY_NOT_FOUND, ERROR_IPSEC_QM_POLICY_IN_USE, ERROR_IPSEC_MM_POLICY_EXISTS, ERROR_IPSEC_MM_POLICY_NOT_FOUND, ERROR_IPSEC_MM_POLICY_IN_USE, ERROR_IPSEC_MM_FILTER_EXISTS, ERROR_IPSEC_MM_FILTER_NOT_FOUND, ERROR_IPSEC_TRANSPORT_FILTER_EXISTS, ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND, ERROR_IPSEC_MM_AUTH_EXISTS, ERROR_IPSEC_MM_AUTH_NOT_FOUND, ERROR_IPSEC_MM_AUTH_IN_USE, ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND, ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND, ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND, ERROR_IPSEC_TUNNEL_FILTER_EXISTS, ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND, ERROR_IPSEC_MM_FILTER_PENDING_DELETION, ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION, ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION, ERROR_IPSEC_MM_POLICY_PENDING_DELETION, ERROR_IPSEC_MM_AUTH_PENDING_DELETION, ERROR_IPSEC_QM_POLICY_PENDING_DELETION, WARNING_IPSEC_MM_POLICY_PRUNED, WARNING_IPSEC_QM_POLICY_PRUNED, // = 13025 ERROR_IPSEC_IKE_AUTH_FAIL = 13801, ERROR_IPSEC_IKE_ATTRIB_FAIL, ERROR_IPSEC_IKE_NEGOTIATION_PENDING, ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR, ERROR_IPSEC_IKE_TIMED_OUT, ERROR_IPSEC_IKE_NO_CERT, ERROR_IPSEC_IKE_SA_DELETED, ERROR_IPSEC_IKE_SA_REAPED, ERROR_IPSEC_IKE_MM_ACQUIRE_DROP, ERROR_IPSEC_IKE_QM_ACQUIRE_DROP, ERROR_IPSEC_IKE_QUEUE_DROP_MM, ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM, ERROR_IPSEC_IKE_DROP_NO_RESPONSE, ERROR_IPSEC_IKE_MM_DELAY_DROP, ERROR_IPSEC_IKE_QM_DELAY_DROP, ERROR_IPSEC_IKE_ERROR, ERROR_IPSEC_IKE_CRL_FAILED, ERROR_IPSEC_IKE_INVALID_KEY_USAGE, ERROR_IPSEC_IKE_INVALID_CERT_TYPE, ERROR_IPSEC_IKE_NO_PRIVATE_KEY, // = 13820 ERROR_IPSEC_IKE_DH_FAIL = 13822, ERROR_IPSEC_IKE_INVALID_HEADER = 13824, ERROR_IPSEC_IKE_NO_POLICY, ERROR_IPSEC_IKE_INVALID_SIGNATURE, ERROR_IPSEC_IKE_KERBEROS_ERROR, ERROR_IPSEC_IKE_NO_PUBLIC_KEY, ERROR_IPSEC_IKE_PROCESS_ERR, ERROR_IPSEC_IKE_PROCESS_ERR_SA, ERROR_IPSEC_IKE_PROCESS_ERR_PROP, ERROR_IPSEC_IKE_PROCESS_ERR_TRANS, ERROR_IPSEC_IKE_PROCESS_ERR_KE, ERROR_IPSEC_IKE_PROCESS_ERR_ID, ERROR_IPSEC_IKE_PROCESS_ERR_CERT, ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ, ERROR_IPSEC_IKE_PROCESS_ERR_HASH, ERROR_IPSEC_IKE_PROCESS_ERR_SIG, ERROR_IPSEC_IKE_PROCESS_ERR_NONCE, ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY, ERROR_IPSEC_IKE_PROCESS_ERR_DELETE, ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR, ERROR_IPSEC_IKE_INVALID_PAYLOAD, ERROR_IPSEC_IKE_LOAD_SOFT_SA, ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN, ERROR_IPSEC_IKE_INVALID_COOKIE, ERROR_IPSEC_IKE_NO_PEER_CERT, ERROR_IPSEC_IKE_PEER_CRL_FAILED, ERROR_IPSEC_IKE_POLICY_CHANGE, ERROR_IPSEC_IKE_NO_MM_POLICY, ERROR_IPSEC_IKE_NOTCBPRIV, ERROR_IPSEC_IKE_SECLOADFAIL, ERROR_IPSEC_IKE_FAILSSPINIT, ERROR_IPSEC_IKE_FAILQUERYSSP, ERROR_IPSEC_IKE_SRVACQFAIL, ERROR_IPSEC_IKE_SRVQUERYCRED, ERROR_IPSEC_IKE_GETSPIFAIL, ERROR_IPSEC_IKE_INVALID_FILTER, ERROR_IPSEC_IKE_OUT_OF_MEMORY, ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED, ERROR_IPSEC_IKE_INVALID_POLICY, ERROR_IPSEC_IKE_UNKNOWN_DOI, ERROR_IPSEC_IKE_INVALID_SITUATION, ERROR_IPSEC_IKE_DH_FAILURE, ERROR_IPSEC_IKE_INVALID_GROUP, ERROR_IPSEC_IKE_ENCRYPT, ERROR_IPSEC_IKE_DECRYPT, ERROR_IPSEC_IKE_POLICY_MATCH, ERROR_IPSEC_IKE_UNSUPPORTED_ID, ERROR_IPSEC_IKE_INVALID_HASH, ERROR_IPSEC_IKE_INVALID_HASH_ALG, ERROR_IPSEC_IKE_INVALID_HASH_SIZE, ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG, ERROR_IPSEC_IKE_INVALID_AUTH_ALG, ERROR_IPSEC_IKE_INVALID_SIG, ERROR_IPSEC_IKE_LOAD_FAILED, ERROR_IPSEC_IKE_RPC_DELETE, ERROR_IPSEC_IKE_BENIGN_REINIT, ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY, // = 13879 ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN = 13881, ERROR_IPSEC_IKE_MM_LIMIT, ERROR_IPSEC_IKE_NEGOTIATION_DISABLED, ERROR_IPSEC_IKE_NEG_STATUS_END, ERROR_SXS_SECTION_NOT_FOUND, ERROR_SXS_CANT_GEN_ACTCTX, ERROR_SXS_INVALID_ACTCTXDATA_FORMAT, ERROR_SXS_ASSEMBLY_NOT_FOUND, ERROR_SXS_MANIFEST_FORMAT_ERROR, ERROR_SXS_MANIFEST_PARSE_ERROR, ERROR_SXS_ACTIVATION_CONTEXT_DISABLED, ERROR_SXS_KEY_NOT_FOUND, ERROR_SXS_VERSION_CONFLICT, ERROR_SXS_WRONG_SECTION_TYPE, ERROR_SXS_THREAD_QUERIES_DISABLED, ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET, ERROR_SXS_UNKNOWN_ENCODING_GROUP, ERROR_SXS_UNKNOWN_ENCODING, ERROR_SXS_INVALID_XML_NAMESPACE_URI, ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED, ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED, ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE, ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE, ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE, ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT, ERROR_SXS_DUPLICATE_DLL_NAME, ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME, ERROR_SXS_DUPLICATE_CLSID, ERROR_SXS_DUPLICATE_IID, ERROR_SXS_DUPLICATE_TLBID, ERROR_SXS_DUPLICATE_PROGID, ERROR_SXS_DUPLICATE_ASSEMBLY_NAME, ERROR_SXS_FILE_HASH_MISMATCH, ERROR_SXS_POLICY_PARSE_ERROR, ERROR_SXS_XML_E_MISSINGQUOTE, ERROR_SXS_XML_E_COMMENTSYNTAX, ERROR_SXS_XML_E_BADSTARTNAMECHAR, ERROR_SXS_XML_E_BADNAMECHAR, ERROR_SXS_XML_E_BADCHARINSTRING, ERROR_SXS_XML_E_XMLDECLSYNTAX, ERROR_SXS_XML_E_BADCHARDATA, ERROR_SXS_XML_E_MISSINGWHITESPACE, ERROR_SXS_XML_E_EXPECTINGTAGEND, ERROR_SXS_XML_E_MISSINGSEMICOLON, ERROR_SXS_XML_E_UNBALANCEDPAREN, ERROR_SXS_XML_E_INTERNALERROR, ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE, ERROR_SXS_XML_E_INCOMPLETE_ENCODING, ERROR_SXS_XML_E_MISSING_PAREN, ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE, ERROR_SXS_XML_E_MULTIPLE_COLONS, ERROR_SXS_XML_E_INVALID_DECIMAL, ERROR_SXS_XML_E_INVALID_HEXIDECIMAL, ERROR_SXS_XML_E_INVALID_UNICODE, ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK, ERROR_SXS_XML_E_UNEXPECTEDENDTAG, ERROR_SXS_XML_E_UNCLOSEDTAG, ERROR_SXS_XML_E_DUPLICATEATTRIBUTE, ERROR_SXS_XML_E_MULTIPLEROOTS, ERROR_SXS_XML_E_INVALIDATROOTLEVEL, ERROR_SXS_XML_E_BADXMLDECL, ERROR_SXS_XML_E_MISSINGROOT, ERROR_SXS_XML_E_UNEXPECTEDEOF, ERROR_SXS_XML_E_BADPEREFINSUBSET, ERROR_SXS_XML_E_UNCLOSEDSTARTTAG, ERROR_SXS_XML_E_UNCLOSEDENDTAG, ERROR_SXS_XML_E_UNCLOSEDSTRING, ERROR_SXS_XML_E_UNCLOSEDCOMMENT, ERROR_SXS_XML_E_UNCLOSEDDECL, ERROR_SXS_XML_E_UNCLOSEDCDATA, ERROR_SXS_XML_E_RESERVEDNAMESPACE, ERROR_SXS_XML_E_INVALIDENCODING, ERROR_SXS_XML_E_INVALIDSWITCH, ERROR_SXS_XML_E_BADXMLCASE, ERROR_SXS_XML_E_INVALID_STANDALONE, ERROR_SXS_XML_E_UNEXPECTED_STANDALONE, ERROR_SXS_XML_E_INVALID_VERSION, ERROR_SXS_XML_E_MISSINGEQUALS, ERROR_SXS_PROTECTION_RECOVERY_FAILED, ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT, ERROR_SXS_PROTECTION_CATALOG_NOT_VALID, ERROR_SXS_UNTRANSLATABLE_HRESULT, ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING, ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE, ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME // = 14080 } enum : HRESULT { S_OK = 0x00000000, S_FALSE = 0x00000001, NOERROR = 0x00000000, E_PENDING = 0x8000000A, E_NOTIMPL = 0x80004001, E_NOINTERFACE = 0x80004002, E_POINTER = 0x80004003, E_ABORT = 0x80004004, E_FAIL = 0x80004005, E_ACCESSDENIED = 0x80070005, E_HANDLE = 0x80070006, E_OUTOFMEMORY = 0x8007000E, E_INVALIDARG = 0x80070057, E_UNEXPECTED = 0x8000FFFF, CO_E_INIT_TLS = 0x80004006, CO_E_INIT_SHARED_ALLOCATOR = 0x80004007, CO_E_INIT_MEMORY_ALLOCATOR = 0x80004008, CO_E_INIT_CLASS_CACHE = 0x80004009, CO_E_INIT_RPC_CHANNEL = 0x8000400A, CO_E_INIT_TLS_SET_CHANNEL_CONTROL = 0x8000400B, CO_E_INIT_TLS_CHANNEL_CONTROL = 0x8000400C, CO_E_INIT_UNACCEPTED_USER_ALLOCATOR = 0x8000400D, CO_E_INIT_SCM_MUTEX_EXISTS = 0x8000400E, CO_E_INIT_SCM_FILE_MAPPING_EXISTS = 0x8000400F, CO_E_INIT_SCM_MAP_VIEW_OF_FILE = 0x80004010, CO_E_INIT_SCM_EXEC_FAILURE = 0x80004011, CO_E_INIT_ONLY_SINGLE_THREADED = 0x80004012, RPC_E_CALL_REJECTED = 0x80010001, RPC_E_CALL_CANCELED = 0x80010002, RPC_E_CANTPOST_INSENDCALL = 0x80010003, RPC_E_CANTCALLOUT_INASYNCCALL = 0x80010004, RPC_E_CANTCALLOUT_INEXTERNALCALL = 0x80010005, RPC_E_CONNECTION_TERMINATED = 0x80010006, RPC_E_SERVER_DIED = 0x80010007, RPC_E_CLIENT_DIED = 0x80010008, RPC_E_INVALID_DATAPACKET = 0x80010009, RPC_E_CANTTRANSMIT_CALL = 0x8001000A, RPC_E_CLIENT_CANTMARSHAL_DATA = 0x8001000B, RPC_E_CLIENT_CANTUNMARSHAL_DATA = 0x8001000C, RPC_E_SERVER_CANTMARSHAL_DATA = 0x8001000D, RPC_E_SERVER_CANTUNMARSHAL_DATA = 0x8001000E, RPC_E_INVALID_DATA = 0x8001000F, RPC_E_INVALID_PARAMETER = 0x80010010, RPC_E_CANTCALLOUT_AGAIN = 0x80010011, RPC_E_SERVER_DIED_DNE = 0x80010012, RPC_E_SYS_CALL_FAILED = 0x80010100, RPC_E_OUT_OF_RESOURCES = 0x80010101, RPC_E_ATTEMPTED_MULTITHREAD = 0x80010102, RPC_E_NOT_REGISTERED = 0x80010103, RPC_E_FAULT = 0x80010104, RPC_E_SERVERFAULT = 0x80010105, RPC_E_CHANGED_MODE = 0x80010106, RPC_E_INVALIDMETHOD = 0x80010107, RPC_E_DISCONNECTED = 0x80010108, RPC_E_RETRY = 0x80010109, RPC_E_SERVERCALL_RETRYLATER = 0x8001010A, RPC_E_SERVERCALL_REJECTED = 0x8001010B, RPC_E_INVALID_CALLDATA = 0x8001010C, RPC_E_CANTCALLOUT_ININPUTSYNCCALL = 0x8001010D, RPC_E_WRONG_THREAD = 0x8001010E, RPC_E_THREAD_NOT_INIT = 0x8001010F, RPC_E_UNEXPECTED = 0x8001FFFF, DISP_E_UNKNOWNINTERFACE = 0x80020001, DISP_E_MEMBERNOTFOUND = 0x80020003, DISP_E_PARAMNOTFOUND = 0x80020004, DISP_E_TYPEMISMATCH = 0x80020005, DISP_E_UNKNOWNNAME = 0x80020006, DISP_E_NONAMEDARGS = 0x80020007, DISP_E_BADVARTYPE = 0x80020008, DISP_E_EXCEPTION = 0x80020009, DISP_E_OVERFLOW = 0x8002000A, DISP_E_BADINDEX = 0x8002000B, DISP_E_UNKNOWNLCID = 0x8002000C, DISP_E_ARRAYISLOCKED = 0x8002000D, DISP_E_BADPARAMCOUNT = 0x8002000E, DISP_E_PARAMNOTOPTIONAL = 0x8002000F, DISP_E_BADCALLEE = 0x80020010, DISP_E_NOTACOLLECTION = 0x80020011, DISP_E_DIVBYZERO = 0x80020012, TYPE_E_BUFFERTOOSMALL = 0x80028016, TYPE_E_INVDATAREAD = 0x80028018, TYPE_E_UNSUPFORMAT = 0x80028019, TYPE_E_REGISTRYACCESS = 0x8002801C, TYPE_E_LIBNOTREGISTERED = 0x8002801D, TYPE_E_UNDEFINEDTYPE = 0x80028027, TYPE_E_QUALIFIEDNAMEDISALLOWED = 0x80028028, TYPE_E_INVALIDSTATE = 0x80028029, TYPE_E_WRONGTYPEKIND = 0x8002802A, TYPE_E_ELEMENTNOTFOUND = 0x8002802B, TYPE_E_AMBIGUOUSNAME = 0x8002802C, TYPE_E_NAMECONFLICT = 0x8002802D, TYPE_E_UNKNOWNLCID = 0x8002802E, TYPE_E_DLLFUNCTIONNOTFOUND = 0x8002802F, TYPE_E_BADMODULEKIND = 0x800288BD, TYPE_E_SIZETOOBIG = 0x800288C5, TYPE_E_DUPLICATEID = 0x800288C6, TYPE_E_INVALIDID = 0x800288CF, TYPE_E_TYPEMISMATCH = 0x80028CA0, TYPE_E_OUTOFBOUNDS = 0x80028CA1, TYPE_E_IOERROR = 0x80028CA2, TYPE_E_CANTCREATETMPFILE = 0x80028CA3, TYPE_E_CANTLOADLIBRARY = 0x80029C4A, TYPE_E_INCONSISTENTPROPFUNCS = 0x80029C83, TYPE_E_CIRCULARTYPE = 0x80029C84, STG_E_INVALIDFUNCTION = 0x80030001, STG_E_FILENOTFOUND = 0x80030002, STG_E_PATHNOTFOUND = 0x80030003, STG_E_TOOMANYOPENFILES = 0x80030004, STG_E_ACCESSDENIED = 0x80030005, STG_E_INVALIDHANDLE = 0x80030006, STG_E_INSUFFICIENTMEMORY = 0x80030008, STG_E_INVALIDPOINTER = 0x80030009, STG_E_NOMOREFILES = 0x80030012, STG_E_DISKISWRITEPROTECTED = 0x80030013, STG_E_SEEKERROR = 0x80030019, STG_E_WRITEFAULT = 0x8003001D, STG_E_READFAULT = 0x8003001E, STG_E_SHAREVIOLATION = 0x80030020, STG_E_LOCKVIOLATION = 0x80030021, STG_E_FILEALREADYEXISTS = 0x80030050, STG_E_INVALIDPARAMETER = 0x80030057, STG_E_MEDIUMFULL = 0x80030070, STG_E_ABNORMALAPIEXIT = 0x800300FA, STG_E_INVALIDHEADER = 0x800300FB, STG_E_INVALIDNAME = 0x800300FC, STG_E_UNKNOWN = 0x800300FD, STG_E_UNIMPLEMENTEDFUNCTION = 0x800300FE, STG_E_INVALIDFLAG = 0x800300FF, STG_E_INUSE = 0x80030100, STG_E_NOTCURRENT = 0x80030101, STG_E_REVERTED = 0x80030102, STG_E_CANTSAVE = 0x80030103, STG_E_OLDFORMAT = 0x80030104, STG_E_OLDDLL = 0x80030105, STG_E_SHAREREQUIRED = 0x80030106, STG_E_NOTFILEBASEDSTORAGE = 0x80030107, STG_E_EXTANTMARSHALLINGS = 0x80030108, STG_S_CONVERTED = 0x00030200, OLE_E_FIRST = 0x80040000, OLE_S_FIRST = 0x00040000, OLE_E_OLEVERB = 0x80040000, OLE_S_USEREG = 0x00040000, OLE_E_ADVF = 0x80040001, OLE_S_STATIC = 0x00040001, OLE_E_ENUM_NOMORE = 0x80040002, OLE_S_MAC_CLIPFORMAT = 0x00040002, OLE_E_ADVISENOTSUPPORTED = 0x80040003, OLE_E_NOCONNECTION = 0x80040004, OLE_E_NOTRUNNING = 0x80040005, OLE_E_NOCACHE = 0x80040006, OLE_E_BLANK = 0x80040007, OLE_E_CLASSDIFF = 0x80040008, OLE_E_CANT_GETMONIKER = 0x80040009, OLE_E_CANT_BINDTOSOURCE = 0x8004000A, OLE_E_STATIC = 0x8004000B, OLE_E_PROMPTSAVECANCELLED = 0x8004000C, OLE_E_INVALIDRECT = 0x8004000D, OLE_E_WRONGCOMPOBJ = 0x8004000E, OLE_E_INVALIDHWND = 0x8004000F, OLE_E_NOT_INPLACEACTIVE = 0x80040010, OLE_E_CANTCONVERT = 0x80040011, OLE_E_NOSTORAGE = 0x80040012, DV_E_FORMATETC = 0x80040064, DV_E_DVTARGETDEVICE = 0x80040065, DV_E_STGMEDIUM = 0x80040066, DV_E_STATDATA = 0x80040067, DV_E_LINDEX = 0x80040068, DV_E_TYMED = 0x80040069, DV_E_CLIPFORMAT = 0x8004006A, DV_E_DVASPECT = 0x8004006B, DV_E_DVTARGETDEVICE_SIZE = 0x8004006C, DV_E_NOIVIEWOBJECT = 0x8004006D, OLE_E_LAST = 0x800400FF, OLE_S_LAST = 0x000400FF, DRAGDROP_E_FIRST = 0x80040100, DRAGDROP_S_FIRST = 0x00040100, DRAGDROP_E_NOTREGISTERED = 0x80040100, DRAGDROP_S_DROP = 0x00040100, DRAGDROP_E_ALREADYREGISTERED = 0x80040101, DRAGDROP_S_CANCEL = 0x00040101, DRAGDROP_E_INVALIDHWND = 0x80040102, DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102, DRAGDROP_E_LAST = 0x8004010F, DRAGDROP_S_LAST = 0x0004010F, CLASSFACTORY_E_FIRST = 0x80040110, CLASSFACTORY_S_FIRST = 0x00040110, CLASS_E_NOAGGREGATION = 0x80040110, CLASS_E_CLASSNOTAVAILABLE = 0x80040111, CLASSFACTORY_E_LAST = 0x8004011F, CLASSFACTORY_S_LAST = 0x0004011F, MARSHAL_E_FIRST = 0x80040120, MARSHAL_S_FIRST = 0x00040120, MARSHAL_E_LAST = 0x8004012F, MARSHAL_S_LAST = 0x0004012F, DATA_E_FIRST = 0x80040130, DATA_S_FIRST = 0x00040130, DATA_S_SAMEFORMATETC = 0x00040130, DATA_E_LAST = 0x8004013F, DATA_S_LAST = 0x0004013F, VIEW_E_FIRST = 0x80040140, VIEW_S_FIRST = 0x00040140, VIEW_E_DRAW = 0x80040140, VIEW_S_ALREADY_FROZEN = 0x00040140, VIEW_E_LAST = 0x8004014F, VIEW_S_LAST = 0x0004014F, REGDB_E_FIRST = 0x80040150, REGDB_S_FIRST = 0x00040150, REGDB_E_READREGDB = 0x80040150, REGDB_E_WRITEREGDB = 0x80040151, REGDB_E_KEYMISSING = 0x80040152, REGDB_E_INVALIDVALUE = 0x80040153, REGDB_E_CLASSNOTREG = 0x80040154, REGDB_E_IIDNOTREG = 0x80040155, REGDB_E_LAST = 0x8004015F, REGDB_S_LAST = 0x0004015F, CACHE_E_FIRST = 0x80040170, CACHE_S_FIRST = 0x00040170, CACHE_E_NOCACHE_UPDATED = 0x80040170, CACHE_S_FORMATETC_NOTSUPPORTED = 0x00040170, CACHE_S_SAMECACHE = 0x00040171, CACHE_S_SOMECACHES_NOTUPDATED = 0x00040172, CACHE_E_LAST = 0x8004017F, CACHE_S_LAST = 0x0004017F, OLEOBJ_E_FIRST = 0x80040180, OLEOBJ_S_FIRST = 0x00040180, OLEOBJ_E_NOVERBS = 0x80040180, OLEOBJ_S_INVALIDVERB = 0x00040180, OLEOBJ_E_INVALIDVERB = 0x80040181, OLEOBJ_S_CANNOT_DOVERB_NOW = 0x00040181, OLEOBJ_S_INVALIDHWND = 0x00040182, OLEOBJ_E_LAST = 0x8004018F, OLEOBJ_S_LAST = 0x0004018F, CLIENTSITE_E_FIRST = 0x80040190, CLIENTSITE_S_FIRST = 0x00040190, CLIENTSITE_E_LAST = 0x8004019F, CLIENTSITE_S_LAST = 0x0004019F, INPLACE_E_NOTUNDOABLE = 0x800401A0, INPLACE_E_FIRST = 0x800401A0, INPLACE_S_FIRST = 0x000401A0, INPLACE_S_TRUNCATED = 0x000401A0, INPLACE_E_NOTOOLSPACE = 0x800401A1, INPLACE_E_LAST = 0x800401AF, INPLACE_S_LAST = 0x000401AF, ENUM_E_FIRST = 0x800401B0, ENUM_S_FIRST = 0x000401B0, ENUM_E_LAST = 0x800401BF, ENUM_S_LAST = 0x000401BF, CONVERT10_E_FIRST = 0x800401C0, CONVERT10_S_FIRST = 0x000401C0, CONVERT10_E_OLESTREAM_GET = 0x800401C0, CONVERT10_S_NO_PRESENTATION = 0x000401C0, CONVERT10_E_OLESTREAM_PUT = 0x800401C1, CONVERT10_E_OLESTREAM_FMT = 0x800401C2, CONVERT10_E_OLESTREAM_BITMAP_TO_DIB = 0x800401C3, CONVERT10_E_STG_FMT = 0x800401C4, CONVERT10_E_STG_NO_STD_STREAM = 0x800401C5, CONVERT10_E_STG_DIB_TO_BITMAP = 0x800401C6, CONVERT10_E_LAST = 0x800401CF, CONVERT10_S_LAST = 0x000401CF, CLIPBRD_E_FIRST = 0x800401D0, CLIPBRD_S_FIRST = 0x000401D0, CLIPBRD_E_CANT_OPEN = 0x800401D0, CLIPBRD_E_CANT_EMPTY = 0x800401D1, CLIPBRD_E_CANT_SET = 0x800401D2, CLIPBRD_E_BAD_DATA = 0x800401D3, CLIPBRD_E_CANT_CLOSE = 0x800401D4, CLIPBRD_E_LAST = 0x800401DF, CLIPBRD_S_LAST = 0x000401DF, MK_E_FIRST = 0x800401E0, MK_S_FIRST = 0x000401E0, MK_E_CONNECTMANUALLY = 0x800401E0, MK_E_EXCEEDEDDEADLINE = 0x800401E1, MK_E_NEEDGENERIC = 0x800401E2, MK_S_REDUCED_TO_SELF = 0x000401E2, MK_E_UNAVAILABLE = 0x800401E3, MK_E_SYNTAX = 0x800401E4, MK_S_ME = 0x000401E4, MK_E_NOOBJECT = 0x800401E5, MK_S_HIM = 0x000401E5, MK_E_INVALIDEXTENSION = 0x800401E6, MK_S_US = 0x000401E6, MK_E_INTERMEDIATEINTERFACENOTSUPPORTED = 0x800401E7, MK_S_MONIKERALREADYREGISTERED = 0x000401E7, MK_E_NOTBINDABLE = 0x800401E8, MK_E_NOTBOUND = 0x800401E9, MK_E_CANTOPENFILE = 0x800401EA, MK_E_MUSTBOTHERUSER = 0x800401EB, MK_E_NOINVERSE = 0x800401EC, MK_E_NOSTORAGE = 0x800401ED, MK_E_NOPREFIX = 0x800401EE, MK_E_LAST = 0x800401EF, MK_S_LAST = 0x000401EF, MK_E_ENUMERATION_FAILED = 0x800401EF, CO_E_FIRST = 0x800401F0, CO_S_FIRST = 0x000401F0, CO_E_NOTINITIALIZED = 0x800401F0, CO_E_ALREADYINITIALIZED = 0x800401F1, CO_E_CANTDETERMINECLASS = 0x800401F2, CO_E_CLASSSTRING = 0x800401F3, CO_E_IIDSTRING = 0x800401F4, CO_E_APPNOTFOUND = 0x800401F5, CO_E_APPSINGLEUSE = 0x800401F6, CO_E_ERRORINAPP = 0x800401F7, CO_E_DLLNOTFOUND = 0x800401F8, CO_E_ERRORINDLL = 0x800401F9, CO_E_WRONGOSFORAPP = 0x800401FA, CO_E_OBJNOTREG = 0x800401FB, CO_E_OBJISREG = 0x800401FC, CO_E_OBJNOTCONNECTED = 0x800401FD, CO_E_APPDIDNTREG = 0x800401FE, CO_E_LAST = 0x800401FF, CO_S_LAST = 0x000401FF, CO_E_RELEASED = 0x800401FF, CO_E_CLASS_CREATE_FAILED = 0x80080001, CO_E_SCM_ERROR = 0x80080002, CO_E_SCM_RPC_FAILURE = 0x80080003, CO_E_BAD_PATH = 0x80080004, CO_E_SERVER_EXEC_FAILURE = 0x80080005, CO_E_OBJSRV_RPC_FAILURE = 0x80080006, MK_E_NO_NORMALIZED = 0x80080007, CO_E_SERVER_STOPPING = 0x80080008, MEM_E_INVALID_ROOT = 0x80080009, MEM_E_INVALID_LINK = 0x80080010, MEM_E_INVALID_SIZE = 0x80080011, CO_S_NOTALLINTERFACES = 0x00080012, NTE_BAD_UID = 0x80090001, NTE_BAD_HASH = 0x80090002, NTE_BAD_KEY = 0x80090003, NTE_BAD_LEN = 0x80090004, NTE_BAD_DATA = 0x80090005, NTE_BAD_SIGNATURE = 0x80090006, NTE_BAD_VER = 0x80090007, NTE_BAD_ALGID = 0x80090008, NTE_BAD_FLAGS = 0x80090009, NTE_BAD_TYPE = 0x8009000A, NTE_BAD_KEY_STATE = 0x8009000B, NTE_BAD_HASH_STATE = 0x8009000C, NTE_NO_KEY = 0x8009000D, NTE_NO_MEMORY = 0x8009000E, NTE_EXISTS = 0x8009000F, NTE_PERM = 0x80090010, NTE_NOT_FOUND = 0x80090011, NTE_DOUBLE_ENCRYPT = 0x80090012, NTE_BAD_PROVIDER = 0x80090013, NTE_BAD_PROV_TYPE = 0x80090014, NTE_BAD_PUBLIC_KEY = 0x80090015, NTE_BAD_KEYSET = 0x80090016, NTE_PROV_TYPE_NOT_DEF = 0x80090017, NTE_PROV_TYPE_ENTRY_BAD = 0x80090018, NTE_KEYSET_NOT_DEF = 0x80090019, NTE_KEYSET_ENTRY_BAD = 0x8009001A, NTE_PROV_TYPE_NO_MATCH = 0x8009001B, NTE_SIGNATURE_FILE_BAD = 0x8009001C, NTE_PROVIDER_DLL_FAIL = 0x8009001D, NTE_PROV_DLL_NOT_FOUND = 0x8009001E, NTE_BAD_KEYSET_PARAM = 0x8009001F, NTE_FAIL = 0x80090020, NTE_SYS_ERR = 0x80090021 } enum : bool { SEVERITY_SUCCESS = 0, SEVERITY_ERROR = 1 } enum : uint { FACILITY_NULL = 0, FACILITY_RPC, FACILITY_DISPATCH, FACILITY_STORAGE, FACILITY_ITF, // = 4 FACILITY_WIN32 = 7, FACILITY_WINDOWS = 8, FACILITY_CONTROL = 10, FACILITY_NT_BIT = 0x10000000 } // C Macros pure nothrow @nogc { bool SUCCEEDED(HRESULT Status) { return Status >= 0; } bool FAILED(HRESULT Status) { return Status < 0; } bool IS_ERROR(HRESULT Status) { return (Status >>> 31) == SEVERITY_ERROR; } ushort HRESULT_CODE(HRESULT r) { return cast(ushort) (r & 0xFFFF); } ushort SCODE_CODE(SCODE r) { return cast(ushort) (r & 0xFFFF); } ushort HRESULT_FACILITY(HRESULT r) { return cast(ushort) ((r>>16) & 0x1fff); } ushort SCODE_FACILITY(SCODE r) { return cast(ushort) ((r>>16) & 0x1fff); } ushort HRESULT_SEVERITY(HRESULT r) { return cast(ushort) ((r>>31) & 0x1); } ushort SCODE_SEVERITY(SCODE r) { return cast(ushort) ((r>>31) & 0x1); } HRESULT MAKE_HRESULT(bool s, uint f, uint c) { return (s << 31) | (f << 16) | c; } SCODE MAKE_SCODE(bool s, uint f, uint c) { return (s << 31) | (f << 16) | c; } SCODE GetScode(HRESULT hr) { return hr; } HRESULT ResultFromScode(SCODE c) { return c; } HRESULT HRESULT_FROM_NT(HRESULT x) { return x | FACILITY_NT_BIT; } HRESULT HRESULT_FROM_WIN32(HRESULT x) { return x ? (x & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000 : 0; } HRESULT PropagateResult(HRESULT hrPrevious, SCODE scBase) { return scBase; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rpcnsi.d0000664000175000017500000001535012776214756023161 0ustar kaikai/** * Windows API header module * * RPC Name Service (RpcNs APIs) * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rpcnsi.d) */ module core.sys.windows.rpcnsi; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "rpcns4"); private import core.sys.windows.basetyps, core.sys.windows.rpcdcep, core.sys.windows.rpcnsi, core.sys.windows.rpcdce, core.sys.windows.w32api; private import core.sys.windows.windef; // for HANDLE mixin DECLARE_HANDLE!("RPC_NS_HANDLE"); enum RPC_C_NS_SYNTAX_DEFAULT=0; enum RPC_C_NS_SYNTAX_DCE=3; enum RPC_C_PROFILE_DEFAULT_ELT=0; enum RPC_C_PROFILE_ALL_ELT=1; enum RPC_C_PROFILE_MATCH_BY_IF=2; enum RPC_C_PROFILE_MATCH_BY_MBR=3; enum RPC_C_PROFILE_MATCH_BY_BOTH=4; enum RPC_C_NS_DEFAULT_EXP_AGE=-1; extern (Windows) { RPC_STATUS RpcNsBindingExportA(uint, ubyte*, RPC_IF_HANDLE, RPC_BINDING_VECTOR*, UUID_VECTOR*); RPC_STATUS RpcNsBindingUnexportA(uint, ubyte*, RPC_IF_HANDLE, UUID_VECTOR*); RPC_STATUS RpcNsBindingLookupBeginA(uint, ubyte*, RPC_IF_HANDLE, UUID*, uint, RPC_NS_HANDLE*); RPC_STATUS RpcNsBindingLookupNext(RPC_NS_HANDLE, RPC_BINDING_VECTOR**); RPC_STATUS RpcNsBindingLookupDone(RPC_NS_HANDLE*); RPC_STATUS RpcNsGroupDeleteA(uint, ubyte*); RPC_STATUS RpcNsGroupMbrAddA(uint, ubyte*, uint, ubyte*); RPC_STATUS RpcNsGroupMbrRemoveA(uint, ubyte*, uint, ubyte*); RPC_STATUS RpcNsGroupMbrInqBeginA(uint, ubyte*, uint, RPC_NS_HANDLE*); RPC_STATUS RpcNsGroupMbrInqNextA(RPC_NS_HANDLE, ubyte**); RPC_STATUS RpcNsGroupMbrInqDone(RPC_NS_HANDLE*); RPC_STATUS RpcNsProfileDeleteA(uint, ubyte*); RPC_STATUS RpcNsProfileEltAddA(uint, ubyte*, RPC_IF_ID*, uint, ubyte*, uint, ubyte*); RPC_STATUS RpcNsProfileEltRemoveA(uint, ubyte*, RPC_IF_ID*, uint, ubyte*); RPC_STATUS RpcNsProfileEltInqBeginA(uint, ubyte*, uint, RPC_IF_ID*, uint, uint, ubyte*, RPC_NS_HANDLE*); RPC_STATUS RpcNsProfileEltInqNextA(RPC_NS_HANDLE, RPC_IF_ID*, ubyte**, uint*, ubyte**); RPC_STATUS RpcNsProfileEltInqDone(RPC_NS_HANDLE*); RPC_STATUS RpcNsEntryObjectInqNext(RPC_NS_HANDLE, UUID*); RPC_STATUS RpcNsEntryObjectInqDone(RPC_NS_HANDLE*); RPC_STATUS RpcNsEntryExpandNameA(uint, ubyte*, ubyte**); RPC_STATUS RpcNsMgmtBindingUnexportA(uint, ubyte*, RPC_IF_ID*, uint, UUID_VECTOR*); RPC_STATUS RpcNsMgmtEntryCreateA(uint, ubyte*); RPC_STATUS RpcNsMgmtEntryDeleteA(uint, ubyte*); RPC_STATUS RpcNsMgmtEntryInqIfIdsA(uint, ubyte*, RPC_IF_ID_VECTOR**); RPC_STATUS RpcNsMgmtHandleSetExpAge(RPC_NS_HANDLE, uint); RPC_STATUS RpcNsMgmtInqExpAge(uint*); RPC_STATUS RpcNsMgmtSetExpAge(uint); RPC_STATUS RpcNsBindingImportNext(RPC_NS_HANDLE, RPC_BINDING_HANDLE*); RPC_STATUS RpcNsBindingImportDone(RPC_NS_HANDLE*); RPC_STATUS RpcNsBindingSelect(RPC_BINDING_VECTOR*, RPC_BINDING_HANDLE*); } version (Unicode) { } else { RPC_STATUS RpcNsEntryObjectInqBeginA(uint, ubyte*, RPC_NS_HANDLE*); RPC_STATUS RpcNsBindingImportBeginA(uint, ubyte*, RPC_IF_HANDLE, UUID*, RPC_NS_HANDLE*); } RPC_STATUS RpcNsBindingExportW(uint, ushort*, RPC_IF_HANDLE, RPC_BINDING_VECTOR*, UUID_VECTOR*); RPC_STATUS RpcNsBindingUnexportW(uint, ushort*, RPC_IF_HANDLE, UUID_VECTOR*); RPC_STATUS RpcNsBindingLookupBeginW(uint, ushort*, RPC_IF_HANDLE, UUID*, uint, RPC_NS_HANDLE*); RPC_STATUS RpcNsGroupDeleteW(uint, ushort*); RPC_STATUS RpcNsGroupMbrAddW(uint, ushort*, uint, ushort*); RPC_STATUS RpcNsGroupMbrRemoveW(uint, ushort*, uint, ushort*); RPC_STATUS RpcNsGroupMbrInqBeginW(uint, ushort*, uint, RPC_NS_HANDLE*); RPC_STATUS RpcNsGroupMbrInqNextW(RPC_NS_HANDLE, ushort**); RPC_STATUS RpcNsProfileDeleteW(uint, ushort*); RPC_STATUS RpcNsProfileEltAddW(uint, ushort*, RPC_IF_ID*, uint, ushort*, uint, ushort*); RPC_STATUS RpcNsProfileEltRemoveW(uint, ushort*, RPC_IF_ID*, uint, ushort*); RPC_STATUS RpcNsProfileEltInqBeginW(uint, ushort*, uint, RPC_IF_ID*, uint, uint, ushort*, RPC_NS_HANDLE*); RPC_STATUS RpcNsProfileEltInqNextW(RPC_NS_HANDLE, RPC_IF_ID*, ushort**, uint*, ushort**); RPC_STATUS RpcNsEntryObjectInqBeginW(uint, ushort*, RPC_NS_HANDLE*); RPC_STATUS RpcNsEntryExpandNameW(uint, ushort*, ushort**); RPC_STATUS RpcNsMgmtBindingUnexportW(uint, ushort*, RPC_IF_ID*, uint, UUID_VECTOR*); RPC_STATUS RpcNsMgmtEntryCreateW(uint, ushort*); RPC_STATUS RpcNsMgmtEntryDeleteW(uint, ushort*); RPC_STATUS RpcNsMgmtEntryInqIfIdsW(uint, ushort , RPC_IF_ID_VECTOR**); RPC_STATUS RpcNsBindingImportBeginW(uint, ushort*, RPC_IF_HANDLE, UUID*, RPC_NS_HANDLE*); version (Unicode) { alias RpcNsBindingLookupBeginW RpcNsBindingLookupBegin; alias RpcNsBindingImportBeginW RpcNsBindingImportBegin; alias RpcNsBindingExportW RpcNsBindingExport; alias RpcNsBindingUnexportW RpcNsBindingUnexport; alias RpcNsGroupDeleteW RpcNsGroupDelete; alias RpcNsGroupMbrAddW RpcNsGroupMbrAdd; alias RpcNsGroupMbrRemoveW RpcNsGroupMbrRemove; alias RpcNsGroupMbrInqBeginW RpcNsGroupMbrInqBegin; alias RpcNsGroupMbrInqNextW RpcNsGroupMbrInqNext; alias RpcNsEntryExpandNameW RpcNsEntryExpandName; alias RpcNsEntryObjectInqBeginW RpcNsEntryObjectInqBegin; alias RpcNsMgmtBindingUnexportW RpcNsMgmtBindingUnexport; alias RpcNsMgmtEntryCreateW RpcNsMgmtEntryCreate; alias RpcNsMgmtEntryDeleteW RpcNsMgmtEntryDelete; alias RpcNsMgmtEntryInqIfIdsW RpcNsMgmtEntryInqIfIds; alias RpcNsProfileDeleteW RpcNsProfileDelete; alias RpcNsProfileEltAddW RpcNsProfileEltAdd; alias RpcNsProfileEltRemoveW RpcNsProfileEltRemove; alias RpcNsProfileEltInqBeginW RpcNsProfileEltInqBegin; alias RpcNsProfileEltInqNextW RpcNsProfileEltInqNext; } else { alias RpcNsBindingLookupBeginA RpcNsBindingLookupBegin; alias RpcNsBindingImportBeginA RpcNsBindingImportBegin; alias RpcNsBindingExportA RpcNsBindingExport; alias RpcNsBindingUnexportA RpcNsBindingUnexport; alias RpcNsGroupDeleteA RpcNsGroupDelete; alias RpcNsGroupMbrAddA RpcNsGroupMbrAdd; alias RpcNsGroupMbrRemoveA RpcNsGroupMbrRemove; alias RpcNsGroupMbrInqBeginA RpcNsGroupMbrInqBegin; alias RpcNsGroupMbrInqNextA RpcNsGroupMbrInqNext; alias RpcNsEntryExpandNameA RpcNsEntryExpandName; alias RpcNsEntryObjectInqBeginA RpcNsEntryObjectInqBegin; alias RpcNsMgmtBindingUnexportA RpcNsMgmtBindingUnexport; alias RpcNsMgmtEntryCreateA RpcNsMgmtEntryCreate; alias RpcNsMgmtEntryDeleteA RpcNsMgmtEntryDelete; alias RpcNsMgmtEntryInqIfIdsA RpcNsMgmtEntryInqIfIds; alias RpcNsProfileDeleteA RpcNsProfileDelete; alias RpcNsProfileEltAddA RpcNsProfileEltAdd; alias RpcNsProfileEltRemoveA RpcNsProfileEltRemove; alias RpcNsProfileEltInqBeginA RpcNsProfileEltInqBegin; alias RpcNsProfileEltInqNextA RpcNsProfileEltInqNext; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmuse.d0000664000175000017500000000326312776214756023010 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmuse.d) */ module core.sys.windows.lmuse; version (Windows): pragma(lib, "netapi32"); import core.sys.windows.lmuseflg; private import core.sys.windows.lmcons, core.sys.windows.windef; enum { USE_LOCAL_PARMNUM = 1, USE_REMOTE_PARMNUM, USE_PASSWORD_PARMNUM, USE_ASGTYPE_PARMNUM, USE_USERNAME_PARMNUM, USE_DOMAINNAME_PARMNUM } enum { USE_OK, USE_PAUSED, USE_SESSLOST, USE_DISCONN = USE_SESSLOST, USE_NETERR, USE_CONN, USE_RECONN } enum DWORD USE_WILDCARD = -1; enum { USE_DISKDEV, USE_SPOOLDEV, USE_CHARDEV, USE_IPC } struct USE_INFO_0 { LPWSTR ui0_local; LPWSTR ui0_remote; } alias USE_INFO_0* PUSE_INFO_0, LPUSE_INFO_0; struct USE_INFO_1 { LPWSTR ui1_local; LPWSTR ui1_remote; LPWSTR ui1_password; DWORD ui1_status; DWORD ui1_asg_type; DWORD ui1_refcount; DWORD ui1_usecount; } alias USE_INFO_1* PUSE_INFO_1, LPUSE_INFO_1; struct USE_INFO_2 { LPWSTR ui2_local; LPWSTR ui2_remote; LPWSTR ui2_password; DWORD ui2_status; DWORD ui2_asg_type; DWORD ui2_refcount; DWORD ui2_usecount; LPWSTR ui2_username; LPWSTR ui2_domainname; } alias USE_INFO_2* PUSE_INFO_2, LPUSE_INFO_2; extern (Windows) { NET_API_STATUS NetUseAdd(LPWSTR, DWORD, PBYTE, PDWORD); NET_API_STATUS NetUseDel(LPWSTR, LPWSTR, DWORD); NET_API_STATUS NetUseEnum(LPWSTR, DWORD, PBYTE*, DWORD, PDWORD, PDWORD, PDWORD); NET_API_STATUS NetUseGetInfo(LPWSTR, LPWSTR, DWORD, PBYTE*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/dlgs.d0000664000175000017500000001007012776214756022606 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_dlgs.d) */ module core.sys.windows.dlgs; version (Windows): private import core.sys.windows.windef; enum : ushort { FILEOPENORD = 1536, MULTIFILEOPENORD = 1537, PRINTDLGORD = 1538, PRNSETUPDLGORD = 1539, FINDDLGORD = 1540, REPLACEDLGORD = 1541, FONTDLGORD = 1542, FORMATDLGORD31 = 1543, FORMATDLGORD30 = 1544, PAGESETUPDLGORD = 1546 } enum : int { ctlFirst = 0x400, ctlLast = 0x4ff, chx1 = 0x410, chx2 = 0x411, chx3 = 0x412, chx4 = 0x413, chx5 = 0x414, chx6 = 0x415, chx7 = 0x416, chx8 = 0x417, chx9 = 0x418, chx10 = 0x419, chx11 = 0x41a, chx12 = 0x41b, chx13 = 0x41c, chx14 = 0x41d, chx15 = 0x41e, chx16 = 0x41f, cmb1 = 0x470, cmb2 = 0x471, cmb3 = 0x472, cmb4 = 0x473, cmb5 = 0x474, cmb6 = 0x475, cmb7 = 0x476, cmb8 = 0x477, cmb9 = 0x478, cmb10 = 0x479, cmb11 = 0x47a, cmb12 = 0x47b, cmb13 = 0x47c, cmb14 = 0x47d, cmb15 = 0x47e, cmb16 = 0x47f, edt1 = 0x480, edt2 = 0x481, edt3 = 0x482, edt4 = 0x483, edt5 = 0x484, edt6 = 0x485, edt7 = 0x486, edt8 = 0x487, edt9 = 0x488, edt10 = 0x489, edt11 = 0x48a, edt12 = 0x48b, edt13 = 0x48c, edt14 = 0x48d, edt15 = 0x48e, edt16 = 0x48f, frm1 = 0x434, frm2 = 0x435, frm3 = 0x436, frm4 = 0x437, grp1 = 0x430, grp2 = 0x431, grp3 = 0x432, grp4 = 0x433, ico1 = 0x43c, ico2 = 0x43d, ico3 = 0x43e, ico4 = 0x43f, lst1 = 0x460, lst2 = 0x461, lst3 = 0x462, lst4 = 0x463, lst5 = 0x464, lst6 = 0x465, lst7 = 0x466, lst8 = 0x467, lst9 = 0x468, lst10 = 0x469, lst11 = 0x46a, lst12 = 0x46b, lst13 = 0x46c, lst14 = 0x46d, lst15 = 0x46e, lst16 = 0x46f, psh1 = 0x400, psh2 = 0x401, psh3 = 0x402, psh4 = 0x403, psh5 = 0x404, psh6 = 0x405, psh7 = 0x406, psh8 = 0x407, psh9 = 0x408, psh10 = 0x409, psh11 = 0x40a, psh12 = 0x40b, psh13 = 0x40c, psh14 = 0x40d, psh15 = 0x40e, pshHelp = 0x40e, psh16 = 0x40f, rad1 = 0x420, rad2 = 0x421, rad3 = 0x422, rad4 = 0x423, rad5 = 0x424, rad6 = 0x425, rad7 = 0x426, rad8 = 0x427, rad9 = 0x428, rad10 = 0x429, rad11 = 0x42a, rad12 = 0x42b, rad13 = 0x42c, rad14 = 0x42d, rad15 = 0x42e, rad16 = 0x42f, rct1 = 0x438, rct2 = 0x439, rct3 = 0x43a, rct4 = 0x43b, scr1 = 0x490, scr2 = 0x491, scr3 = 0x492, scr4 = 0x493, scr5 = 0x494, scr6 = 0x495, scr7 = 0x496, scr8 = 0x497, stc1 = 0x440, stc2 = 0x441, stc3 = 0x442, stc4 = 0x443, stc5 = 0x444, stc6 = 0x445, stc7 = 0x446, stc8 = 0x447, stc9 = 0x448, stc10 = 0x449, stc11 = 0x44a, stc12 = 0x44b, stc13 = 0x44c, stc14 = 0x44d, stc15 = 0x44e, stc16 = 0x44f, stc17 = 0x450, stc18 = 0x451, stc19 = 0x452, stc20 = 0x453, stc21 = 0x454, stc22 = 0x455, stc23 = 0x456, stc24 = 0x457, stc25 = 0x458, stc26 = 0x459, stc27 = 0x45a, stc28 = 0x45b, stc29 = 0x45c, stc30 = 0x45d, stc31 = 0x45e, stc32 = 0x45f } struct CRGB { ubyte bRed; ubyte bGreen; ubyte bBlue; ubyte bExtra; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/servprov.d0000664000175000017500000000075512776214756023554 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_servprov.d) */ module core.sys.windows.servprov; version (Windows): private import core.sys.windows.basetyps, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.wtypes; interface IServiceProvider : IUnknown { HRESULT QueryService(REFGUID, REFIID, void**); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/subauth.d0000664000175000017500000001735412776214756023344 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_subauth.d) */ module core.sys.windows.subauth; version (Windows): private import core.sys.windows.ntdef, core.sys.windows.windef; /+ alias LONG NTSTATUS; alias NTSTATUS* PNTSTATUS; +/ enum : ULONG { MSV1_0_PASSTHRU = 1, MSV1_0_GUEST_LOGON = 2 } // USER_ALL_INFORMATION.WhichFields (Undocumented) enum ULONG MSV1_0_VALIDATION_LOGOFF_TIME = 1, MSV1_0_VALIDATION_KICKOFF_TIME = 2, MSV1_0_VALIDATION_LOGON_SERVER = 4, MSV1_0_VALIDATION_LOGON_DOMAIN = 8, MSV1_0_VALIDATION_SESSION_KEY = 16, MSV1_0_VALIDATION_USER_FLAGS = 32, MSV1_0_VALIDATION_USER_ID = 64; // ?ActionsPerformed? (Undocumented) enum MSV1_0_SUBAUTH_ACCOUNT_DISABLED = 1; enum MSV1_0_SUBAUTH_PASSWORD = 2; enum MSV1_0_SUBAUTH_WORKSTATIONS = 4; enum MSV1_0_SUBAUTH_LOGON_HOURS = 8; enum MSV1_0_SUBAUTH_ACCOUNT_EXPIRY = 16; enum MSV1_0_SUBAUTH_PASSWORD_EXPIRY = 32; enum MSV1_0_SUBAUTH_ACCOUNT_TYPE = 64; enum MSV1_0_SUBAUTH_LOCKOUT = 128; enum NEXT_FREE_ACCOUNT_CONTROL_BIT = 131072; enum SAM_DAYS_PER_WEEK = 7; enum SAM_HOURS_PER_WEEK = 168; enum SAM_MINUTES_PER_WEEK = 10080; enum : NTSTATUS { STATUS_SUCCESS = 0, STATUS_INVALID_INFO_CLASS = 0xC0000003, STATUS_NO_SUCH_USER = 0xC0000064, STATUS_WRONG_PASSWORD = 0xC000006A, STATUS_PASSWORD_RESTRICTION = 0xC000006C, STATUS_LOGON_FAILURE = 0xC000006D, STATUS_ACCOUNT_RESTRICTION = 0xC000006E, STATUS_INVALID_LOGON_HOURS = 0xC000006F, STATUS_INVALID_WORKSTATION = 0xC0000070, STATUS_PASSWORD_EXPIRED = 0xC0000071, STATUS_ACCOUNT_DISABLED = 0xC0000072, STATUS_INSUFFICIENT_RESOURCES = 0xC000009A, STATUS_ACCOUNT_EXPIRED = 0xC0000193, STATUS_PASSWORD_MUST_CHANGE = 0xC0000224, STATUS_ACCOUNT_LOCKED_OUT = 0xC0000234 } // Note: undocumented in MSDN // USER_ALL_INFORMATION.UserAccountControl enum ULONG USER_ACCOUNT_DISABLED = 1, USER_HOME_DIRECTORY_REQUIRED = 2, USER_PASSWORD_NOT_REQUIRED = 4, USER_TEMP_DUPLICATE_ACCOUNT = 8, USER_NORMAL_ACCOUNT = 16, USER_MNS_LOGON_ACCOUNT = 32, USER_INTERDOMAIN_TRUST_ACCOUNT = 64, USER_WORKSTATION_TRUST_ACCOUNT = 128, USER_SERVER_TRUST_ACCOUNT = 256, USER_DONT_EXPIRE_PASSWORD = 512, USER_ACCOUNT_AUTO_LOCKED = 1024, USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 2048, USER_SMARTCARD_REQUIRED = 4096, USER_TRUSTED_FOR_DELEGATION = 8192, USER_NOT_DELEGATED = 16384, USER_USE_DES_KEY_ONLY = 32768, USER_DONT_REQUIRE_PREAUTH = 65536, USER_MACHINE_ACCOUNT_MASK = 448, USER_ACCOUNT_TYPE_MASK = 472, USER_ALL_PARAMETERS = 2097152; /+ struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } alias UNICODE_STRING* PUNICODE_STRING; struct STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } alias STRING* PSTRING; +/ mixin DECLARE_HANDLE!("SAM_HANDLE"); alias SAM_HANDLE* PSAM_HANDLE; struct OLD_LARGE_INTEGER { ULONG LowPart; LONG HighPart; } alias OLD_LARGE_INTEGER* POLD_LARGE_INTEGER; enum NETLOGON_LOGON_INFO_CLASS { NetlogonInteractiveInformation = 1, NetlogonNetworkInformation, NetlogonServiceInformation, NetlogonGenericInformation, NetlogonInteractiveTransitiveInformation, NetlogonNetworkTransitiveInformation, NetlogonServiceTransitiveInformation } enum CYPHER_BLOCK_LENGTH = 8; enum USER_SESSION_KEY_LENGTH = CYPHER_BLOCK_LENGTH * 2; enum CLEAR_BLOCK_LENGTH = 8; struct CYPHER_BLOCK { CHAR[CYPHER_BLOCK_LENGTH] data; } alias CYPHER_BLOCK* PCYPHER_BLOCK; struct CLEAR_BLOCK { CHAR[CLEAR_BLOCK_LENGTH] data; } alias CLEAR_BLOCK* PCLEAR_BLOCK; struct LM_OWF_PASSWORD { CYPHER_BLOCK[2] data; } alias LM_OWF_PASSWORD* PLM_OWF_PASSWORD; struct USER_SESSION_KEY { CYPHER_BLOCK[2] data; } alias USER_SESSION_KEY* PUSER_SESSION_KEY; alias CLEAR_BLOCK LM_CHALLENGE; alias LM_CHALLENGE* PLM_CHALLENGE; alias LM_OWF_PASSWORD NT_OWF_PASSWORD; alias NT_OWF_PASSWORD* PNT_OWF_PASSWORD; alias LM_CHALLENGE NT_CHALLENGE; alias NT_CHALLENGE* PNT_CHALLENGE; struct LOGON_HOURS { USHORT UnitsPerWeek; PUCHAR LogonHours; } alias LOGON_HOURS* PLOGON_HOURS; struct SR_SECURITY_DESCRIPTOR { ULONG Length; PUCHAR SecurityDescriptor; } alias SR_SECURITY_DESCRIPTOR* PSR_SECURITY_DESCRIPTOR; align(4): struct USER_ALL_INFORMATION { LARGE_INTEGER LastLogon; LARGE_INTEGER LastLogoff; LARGE_INTEGER PasswordLastSet; LARGE_INTEGER AccountExpires; LARGE_INTEGER PasswordCanChange; LARGE_INTEGER PasswordMustChange; UNICODE_STRING UserName; UNICODE_STRING FullName; UNICODE_STRING HomeDirectory; UNICODE_STRING HomeDirectoryDrive; UNICODE_STRING ScriptPath; UNICODE_STRING ProfilePath; UNICODE_STRING AdminComment; UNICODE_STRING WorkStations; UNICODE_STRING UserComment; UNICODE_STRING Parameters; UNICODE_STRING LmPassword; UNICODE_STRING NtPassword; UNICODE_STRING PrivateData; SR_SECURITY_DESCRIPTOR SecurityDescriptor; ULONG UserId; ULONG PrimaryGroupId; ULONG UserAccountControl; ULONG WhichFields; LOGON_HOURS LogonHours; USHORT BadPasswordCount; USHORT LogonCount; USHORT CountryCode; USHORT CodePage; BOOLEAN LmPasswordPresent; BOOLEAN NtPasswordPresent; BOOLEAN PasswordExpired; BOOLEAN PrivateDataSensitive; } alias USER_ALL_INFORMATION* PUSER_ALL_INFORMATION; align: struct MSV1_0_VALIDATION_INFO { LARGE_INTEGER LogoffTime; LARGE_INTEGER KickoffTime; UNICODE_STRING LogonServer; UNICODE_STRING LogonDomainName; USER_SESSION_KEY SessionKey; BOOLEAN Authoritative; ULONG UserFlags; ULONG WhichFields; ULONG UserId; } alias MSV1_0_VALIDATION_INFO* PMSV1_0_VALIDATION_INFO; struct NETLOGON_LOGON_IDENTITY_INFO { UNICODE_STRING LogonDomainName; ULONG ParameterControl; OLD_LARGE_INTEGER LogonId; UNICODE_STRING UserName; UNICODE_STRING Workstation; } alias NETLOGON_LOGON_IDENTITY_INFO* PNETLOGON_LOGON_IDENTITY_INFO; struct NETLOGON_INTERACTIVE_INFO { NETLOGON_LOGON_IDENTITY_INFO Identity; LM_OWF_PASSWORD LmOwfPassword; NT_OWF_PASSWORD NtOwfPassword; } alias NETLOGON_INTERACTIVE_INFO* PNETLOGON_INTERACTIVE_INFO; struct NETLOGON_GENERIC_INFO { NETLOGON_LOGON_IDENTITY_INFO Identity; UNICODE_STRING PackageName; ULONG DataLength; PUCHAR LogonData; } alias NETLOGON_GENERIC_INFO* PNETLOGON_GENERIC_INFO; struct NETLOGON_NETWORK_INFO { NETLOGON_LOGON_IDENTITY_INFO Identity; LM_CHALLENGE LmChallenge; STRING NtChallengeResponse; STRING LmChallengeResponse; } alias NETLOGON_NETWORK_INFO* PNETLOGON_NETWORK_INFO; struct NETLOGON_SERVICE_INFO { NETLOGON_LOGON_IDENTITY_INFO Identity; LM_OWF_PASSWORD LmOwfPassword; NT_OWF_PASSWORD NtOwfPassword; } alias NETLOGON_SERVICE_INFO* PNETLOGON_SERVICE_INFO; extern (Windows) { NTSTATUS Msv1_0SubAuthenticationRoutine(NETLOGON_LOGON_INFO_CLASS,PVOID, ULONG,PUSER_ALL_INFORMATION,PULONG,PULONG, PBOOLEAN,PLARGE_INTEGER,PLARGE_INTEGER); NTSTATUS Msv1_0SubAuthenticationFilter(NETLOGON_LOGON_INFO_CLASS,PVOID, ULONG,PUSER_ALL_INFORMATION,PULONG,PULONG, PBOOLEAN,PLARGE_INTEGER,PLARGE_INTEGER); NTSTATUS Msv1_0SubAuthenticationRoutineGeneric(PVOID,ULONG,PULONG,PVOID*); NTSTATUS Msv1_0SubAuthenticationRoutineEx(NETLOGON_LOGON_INFO_CLASS,PVOID, ULONG,PUSER_ALL_INFORMATION,SAM_HANDLE, PMSV1_0_VALIDATION_INFO,PULONG); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/windows.d0000664000175000017500000000402612776214756023353 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 4.0 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_windows.d) */ module core.sys.windows.windows; version (Windows): /* windows.h - main header file for the Win32 API Written by Anders Norlander This file is part of a free library for the Win32 API. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ public import core.sys.windows.w32api; public import core.sys.windows.core; public import core.sys.windows.cderr; public import core.sys.windows.dde; public import core.sys.windows.ddeml; public import core.sys.windows.dlgs; public import core.sys.windows.imm; public import core.sys.windows.lzexpand; public import core.sys.windows.mmsystem; public import core.sys.windows.nb30; public import core.sys.windows.winsvc; public import core.sys.windows.rpc; public import core.sys.windows.shellapi; public import core.sys.windows.winperf; public import core.sys.windows.commdlg; public import core.sys.windows.winspool; public import core.sys.windows.ole2; public import core.sys.windows.winreg; // Select correct version of winsock. Importing the incorrect // module will cause a static assert to prevent problems later on. version (Win32_Winsock1) { public import core.sys.windows.winsock; } else { public import core.sys.windows.winsock2; //public import core.sys.windows.ws2tcpip; } /+ #if (_WIN32_WINNT >= 0x400) #include /* * MS likes to include mswsock.h here as well, * but that can cause undefined symbols if * winsock2.h is included before windows.h */ #else #include #endif /* (_WIN32_WINNT >= 0x400) */ +/ // For compatibility with previous // core.sys.windows.windows... public import core.sys.windows.imagehlp; public import core.sys.windows.dbghelp_types; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/basetsd.d0000664000175000017500000001133312776214756023305 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.12 * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_basetsd.d) */ module core.sys.windows.basetsd; version (Windows): /* This template is used in these modules to declare constant pointer types, * in order to support both D 1.x and 2.x. * Since removed - now supporting only D2 */ /*template CPtr(T) { version (D_Version2) { // must use mixin so that it doesn't cause a syntax error under D1 mixin("alias const(T)* CPtr;"); } else { alias T* CPtr; } }*/ /* [CyberShadow VP 2011.12.22] typedef is now deprecated in D2. */ template TypeDef(T) { version (D_Version2) { alias T TypeDef; } else { // must use mixin so that it doesn't cause a deprecation error under D2 mixin("typedef T TypeDef;"); } } // [SnakE 2009-02-23] Moved HANDLE definition here from winnt.d to avoid // 'forwatd template reference' to CPtr from winnt.d caused by a circular // import. alias TypeDef!(void*) HANDLE; /+struct HANDLE { const(void)* h; alias h this; }+/ package template DECLARE_HANDLE(string name, base = HANDLE) { mixin ("alias " ~ base.stringof ~ " " ~ name ~ ";"); } alias HANDLE* PHANDLE, LPHANDLE; version (Win64) { alias long __int3264; enum ulong ADDRESS_TAG_BIT = 0x40000000000; alias long INT_PTR, LONG_PTR; alias long* PINT_PTR, PLONG_PTR; alias ulong UINT_PTR, ULONG_PTR, HANDLE_PTR; alias ulong* PUINT_PTR, PULONG_PTR; alias int HALF_PTR; alias int* PHALF_PTR; alias uint UHALF_PTR; alias uint* PUHALF_PTR; uint HandleToULong(void* h) { return(cast(uint) cast(ULONG_PTR) h); } int HandleToLong(void* h) { return(cast(int) cast(LONG_PTR) h); } void* ULongToHandle(uint h) { return(cast(void*) cast(UINT_PTR) h); } void* LongToHandle(int h) { return(cast(void*) cast(INT_PTR) h); } uint PtrToUlong(void* p) { return(cast(uint) cast(ULONG_PTR) p); } uint PtrToUint(void* p) { return(cast(uint) cast(UINT_PTR) p); } ushort PtrToUshort(void* p) { return(cast(ushort) cast(uint) cast(ULONG_PTR) p); } int PtrToLong(void* p) { return(cast(int) cast(LONG_PTR) p); } int PtrToInt(void* p) { return(cast(int) cast(INT_PTR) p); } short PtrToShort(void* p) { return(cast(short) cast(int) cast(LONG_PTR) p); } void* IntToPtr(int i) { return(cast(void*) cast(INT_PTR) i); } void* UIntToPtr(uint ui) { return(cast(void*) cast(UINT_PTR) ui); } void* LongToPtr(int l) { return(cast(void*) cast(LONG_PTR) l); } void* ULongToPtr(uint ul) { return(cast(void*) cast(ULONG_PTR) ul); } } else { alias int __int3264; enum uint ADDRESS_TAG_BIT = 0x80000000; alias int INT_PTR, LONG_PTR; alias int* PINT_PTR, PLONG_PTR; alias uint UINT_PTR, ULONG_PTR, HANDLE_PTR; alias uint* PUINT_PTR, PULONG_PTR; alias short HALF_PTR; alias short* PHALF_PTR; alias ushort UHALF_PTR; alias ushort* PUHALF_PTR; uint HandleToUlong(HANDLE h) { return cast(uint) h; } int HandleToLong(HANDLE h) { return cast(int) h; } HANDLE LongToHandle(LONG_PTR h) { return cast(HANDLE)h; } uint PtrToUlong(const(void)* p) { return cast(uint) p; } uint PtrToUint(const(void)* p) { return cast(uint) p; } int PtrToInt(const(void)* p) { return cast(int) p; } ushort PtrToUshort(const(void)* p) { return cast(ushort) p; } short PtrToShort(const(void)* p) { return cast(short) p; } void* IntToPtr(int i) { return cast(void*) i; } void* UIntToPtr(uint ui) { return cast(void*) ui; } alias IntToPtr LongToPtr; alias UIntToPtr ULongToPtr; } alias UIntToPtr UintToPtr, UlongToPtr; enum : UINT_PTR { MAXUINT_PTR = UINT_PTR.max } enum : INT_PTR { MAXINT_PTR = INT_PTR.max, MININT_PTR = INT_PTR.min } enum : ULONG_PTR { MAXULONG_PTR = ULONG_PTR.max } enum : LONG_PTR { MAXLONG_PTR = LONG_PTR.max, MINLONG_PTR = LONG_PTR.min } enum : UHALF_PTR { MAXUHALF_PTR = UHALF_PTR.max } enum : HALF_PTR { MAXHALF_PTR = HALF_PTR.max, MINHALF_PTR = HALF_PTR.min } alias byte INT8; alias byte* PINT8; alias ubyte UINT8; alias ubyte* PUINT8; alias short INT16; alias short* PINT16; alias ushort UINT16; alias ushort* PUINT16; alias int LONG32, INT32; alias int* PLONG32, PINT32; alias uint ULONG32, DWORD32, UINT32; alias uint* PULONG32, PDWORD32, PUINT32; alias ULONG_PTR SIZE_T, DWORD_PTR; alias ULONG_PTR* PSIZE_T, PDWORD_PTR; alias LONG_PTR SSIZE_T; alias LONG_PTR* PSSIZE_T; alias long LONG64, INT64; alias long* PLONG64, PINT64; alias ulong ULONG64, DWORD64, UINT64; alias ulong* PULONG64, PDWORD64, PUINT64; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lzexpand.d0000664000175000017500000000232312776214756023504 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lzexpand.d) */ module core.sys.windows.lzexpand; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "lz32"); private import core.sys.windows.winbase, core.sys.windows.windef; enum : LONG { LZERROR_BADINHANDLE = -1, LZERROR_BADOUTHANDLE = -2, LZERROR_READ = -3, LZERROR_WRITE = -4, LZERROR_GLOBALLOC = -5, LZERROR_GLOBLOCK = -6, LZERROR_BADVALUE = -7, LZERROR_UNKNOWNALG = -8 } extern (Windows): deprecated { LONG CopyLZFile(INT, INT); void LZDone(); INT LZStart(); } INT GetExpandedNameA(LPSTR, LPSTR); INT GetExpandedNameW(LPWSTR, LPWSTR); void LZClose(INT); LONG LZCopy(INT, INT); INT LZInit(INT); INT LZOpenFileA(LPSTR, LPOFSTRUCT, WORD); INT LZOpenFileW(LPWSTR, LPOFSTRUCT, WORD); INT LZRead(INT, LPSTR, INT); LONG LZSeek(INT, LONG, INT); version (Unicode) { alias GetExpandedNameW GetExpandedName; alias LZOpenFileW LZOpenFile; } else { alias GetExpandedNameA GetExpandedName; alias LZOpenFileA LZOpenFile; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/reason.d0000664000175000017500000000400412776214756023144 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_reason.d) */ module core.sys.windows.reason; version (Windows): private import core.sys.windows.w32api, core.sys.windows.windef; static assert (_WIN32_WINNT >= 0x501, "core.sys.windows.reason is only available on WindowsXP and later"); enum : DWORD { SHTDN_REASON_MAJOR_OTHER = 0x00000000, SHTDN_REASON_MAJOR_HARDWARE = 0x00010000, SHTDN_REASON_MAJOR_OPERATINGSYSTEM = 0x00020000, SHTDN_REASON_MAJOR_SOFTWARE = 0x00030000, SHTDN_REASON_MAJOR_APPLICATION = 0x00040000, SHTDN_REASON_MAJOR_SYSTEM = 0x00050000, SHTDN_REASON_MAJOR_POWER = 0x00060000, SHTDN_REASON_MAJOR_LEGACY_API = 0x00070000 } enum : DWORD { SHTDN_REASON_MINOR_OTHER, SHTDN_REASON_MINOR_MAINTENANCE, SHTDN_REASON_MINOR_INSTALLATION, SHTDN_REASON_MINOR_UPGRADE, SHTDN_REASON_MINOR_RECONFIG, SHTDN_REASON_MINOR_HUNG, SHTDN_REASON_MINOR_UNSTABLE, SHTDN_REASON_MINOR_DISK, SHTDN_REASON_MINOR_PROCESSOR, SHTDN_REASON_MINOR_NETWORKCARD, SHTDN_REASON_MINOR_POWER_SUPPLY, SHTDN_REASON_MINOR_CORDUNPLUGGED, SHTDN_REASON_MINOR_ENVIRONMENT, SHTDN_REASON_MINOR_HARDWARE_DRIVER, SHTDN_REASON_MINOR_OTHERDRIVER, SHTDN_REASON_MINOR_BLUESCREEN, SHTDN_REASON_MINOR_SERVICEPACK, SHTDN_REASON_MINOR_HOTFIX, SHTDN_REASON_MINOR_SECURITYFIX, SHTDN_REASON_MINOR_SECURITY, SHTDN_REASON_MINOR_NETWORK_CONNECTIVITY, SHTDN_REASON_MINOR_WMI, SHTDN_REASON_MINOR_SERVICEPACK_UNINSTALL, SHTDN_REASON_MINOR_HOTFIX_UNINSTALL, SHTDN_REASON_MINOR_SECURITYFIX_UNINSTALL, SHTDN_REASON_MINOR_MMC, // = 0x00000019 SHTDN_REASON_MINOR_TERMSRV = 0x00000020 } enum : DWORD { SHTDN_REASON_FLAG_USER_DEFINED = 0x40000000, SHTDN_REASON_FLAG_PLANNED = 0x80000000 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/mswsock.d0000664000175000017500000001470412776214756023353 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Daniel Keep * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_mswsock.d) */ module core.sys.windows.mswsock; version (Windows): import core.sys.windows.winbase, core.sys.windows.windef; private import core.sys.windows.basetyps, core.sys.windows.w32api; // FIXME: clean up Windows version support version (Win32_Winsock2) pragma(msg, "Version Win32_Winsock2 is deprecated; Winsock2 is now imported by default"); // Pull in Winsock1 if the user has put "Win32_Winsock1" on the compile // line; otherwise, default to Winsock2. version (Win32_Winsock1) { import core.sys.windows.winsock; } else { import core.sys.windows.winsock2; } //static if (_WIN32_WINNT >= 0x500) { enum { /* WinNT5+: ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/socket_options.htm */ SO_MAXDG = 0x7009, SO_MAXPATHDG = 0x700A, } //} enum { /* WinNT4+: ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/socket_options_for_windows_nt_4_0_2.htm */ SO_CONNDATA = 0x7000, SO_CONNOPT = 0x7001, SO_DISCDATA = 0x7002, SO_DISCOPT = 0x7003, SO_CONNDATALEN = 0x7004, SO_CONNOPTLEN = 0x7005, SO_DISCDATALEN = 0x7006, SO_DISCOPTLEN = 0x7007, /* WinNT4: ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/socket_options.htm */ SO_UPDATE_ACCEPT_CONTENT = 0x700B, } enum { /* Win95+, WinNT4+ but apparently shouldn't used: mark as deprecated? ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/socket_options.htm */ SO_OPENTYPE = 0x7008, /* Win95+; these two are passed to the SO_OPENTYPE option as arguments, so would they be deprecated as well? ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/socket_options.htm */ SO_SYNCHRONOUS_ALERT = 0x0010, SO_SYNCHRONOUS_NONALERT = 0x0020, /* Win95: ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/socket_options.htm */ SO_CONNECT_TIME = 0x700C, } enum { TCP_BSDURGENT = 0x7000, } /* These *appear* to be constants for passing to the TransmitFile / TransmitPackets functions, which are available in WinNT3.51+ ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/transmitfile_2.htm */ enum { TF_DISCONNECT = 1, TF_REUSE_SOCKET = 2, TF_WRITE_BEHIND = 4, TF_USE_DEFAULT_WORKER = 0, TF_USE_SYSTEM_THREAD = 16, TF_USE_KERNEL_APC = 32 } /* Win95+, WinNT3.51+ ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/transmit_file_buffers_2.htm */ struct TRANSMIT_FILE_BUFFERS { PVOID Head; DWORD HeadLength; PVOID Tail; DWORD TailLength; } alias TRANSMIT_FILE_BUFFERS* PTRANSMIT_FILE_BUFFERS, LPTRANSMIT_FILE_BUFFERS; extern(Windows) { /* Win95+, WinNT3.51+ ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/wsarecvex_2.htm */ int WSARecvEx(SOCKET, char*, int, int*); /* Win95+, WinNT3.51+ ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/getacceptexSOCKADDRs_2.htm */ VOID GetAcceptExSockaddrs(PVOID, DWORD, DWORD, DWORD, SOCKADDR**, LPINT, SOCKADDR**, LPINT); /* WinNT3.51+ ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/transmitfile_2.htm */ BOOL TransmitFile(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD); /* WinNT3.51+ ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/acceptex_2.htm */ alias BOOL function(SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED) LPFN_ACCEPTEX; enum GUID WSAID_ACCEPTEX = {0xb5367df1,0xcbac,0x11cf,[0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]}; alias BOOL function(SOCKET, SOCKADDR*, int, PVOID, DWORD, LPDWORD, LPOVERLAPPED) LPFN_CONNECTEX; enum GUID WSAID_CONNECTEX = {0x25a207b9,0xddf3,0x4660,[0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e]}; } version(Win32_Winsock1) { } else { static if (_WIN32_WINNT > 0x501) { /* These appear to be constants for the TRANSMIT_PACKETS_ELEMENT * structure below, so I've given them the same minimum version */ enum { TP_ELEMENT_FILE = 1, TP_ELEMENT_MEMORY = 2, TP_ELEMENT_EOP = 4 } /* WinXP+, Srv2k3+ * ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/transmit_packets_element_2.htm */ struct TRANSMIT_PACKETS_ELEMENT { ULONG dwElFlags; ULONG cLength; union { struct { LARGE_INTEGER nFileOffset; HANDLE hFile; } PVOID pBuffer; } } /* WinXP+, Server2003+: * ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/wsamsg_2.htm */ struct WSAMSG { LPSOCKADDR name; INT namelen; LPWSABUF lpBuffers; DWORD dwBufferCount; WSABUF Control; DWORD dwFlags; } alias WSAMSG* PWSAMSG, LPWSAMSG; /* According to MSDN docs, the WSAMSG.Control buffer starts with a cmsghdr header of the following form. See also RFC 2292. */ /* DK: Confirmed. So I suppose these should get the same version as WSAMSG... */ struct WSACMSGHDR { UINT cmsg_len; INT cmsg_level; INT cmsg_type; // followed by UCHAR cmsg_data[]; } /* TODO: Standard Posix.1g macros as per RFC 2292, with WSA_uglification. */ /* DK: MinGW doesn't define these, and neither does the MSDN docs. Might have to actually look up RFC 2292... */ /+ #if 0 #define WSA_CMSG_FIRSTHDR(mhdr) #define WSA_CMSG_NXTHDR(mhdr, cmsg) #define WSA_CMSG_SPACE(length) #define WSA_CMSG_LEN(length) #endif +/ extern(Windows) { /* WinXP+, Srv2k3+ * ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/disconnectex_2.htm */ BOOL DisconnectEx(SOCKET, LPOVERLAPPED, DWORD, DWORD); /* WinXP+, Srv2k3+ * ms-help://MS.MSDNQTR.2003FEB.1033/winsock/winsock/wsarecvmsg_2.htm */ int WSARecvMsg(SOCKET, LPWSAMSG, LPDWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); } } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ntldap.d0000664000175000017500000000610312776214756023141 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ntldap.d) */ module core.sys.windows.ntldap; version (Windows): version (ANSI) {} else version = Unicode; /* TOTHINKABOUT: These constants don't have ANSI/Unicode versioned * aliases. Should we merge them anyway? */ const char[] LDAP_SERVER_ASQ_OID = "1.2.840.113556.1.4.1504", LDAP_SERVER_DIRSYNC_OID = "1.2.840.113556.1.4.841", LDAP_SERVER_SD_FLAGS_OID = "1.2.840.113556.1.4.801", LDAP_SERVER_FAST_BIND_OID = "1.2.840.113556.1.4.1781", LDAP_MATCHING_RULE_BIT_OR = "1.2.840.113556.1.4.804", LDAP_MATCHING_RULE_BIT_AND = "1.2.840.113556.1.4.803", LDAP_SERVER_EXTENDED_DN_OID = "1.2.840.113556.1.4.529", LDAP_SERVER_LAZY_COMMIT_OID = "1.2.840.113556.1.4.619", LDAP_SERVER_TREE_DELETE_OID = "1.2.840.113556.1.4.805", LDAP_SERVER_VERIFY_NAME_OID = "1.2.840.113556.1.4.1338", LDAP_SERVER_SHOW_DELETED_OID = "1.2.840.113556.1.4.417", LDAP_SERVER_NOTIFICATION_OID = "1.2.840.113556.1.4.528", LDAP_SERVER_DOMAIN_SCOPE_OID = "1.2.840.113556.1.4.1339", LDAP_CAP_ACTIVE_DIRECTORY_OID = "1.2.840.113556.1.4.800", LDAP_SERVER_SEARCH_OPTIONS_OID = "1.2.840.113556.1.4.1340", LDAP_CAP_ACTIVE_DIRECTORY_V51_OID = "1.2.840.113556.1.4.1670", LDAP_SERVER_PERMISSIVE_MODIFY_OID = "1.2.840.113556.1.4.1413", LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID = "1.2.840.113556.1.4.521"; const wchar[] LDAP_SERVER_ASQ_OID_W = "1.2.840.113556.1.4.1504", LDAP_SERVER_DIRSYNC_OID_W = "1.2.840.113556.1.4.841", LDAP_SERVER_SD_FLAGS_OID_W = "1.2.840.113556.1.4.801", LDAP_SERVER_FAST_BIND_OID_W = "1.2.840.113556.1.4.1781", LDAP_MATCHING_RULE_BIT_OR_W = "1.2.840.113556.1.4.804", LDAP_MATCHING_RULE_BIT_AND_W = "1.2.840.113556.1.4.803", LDAP_SERVER_EXTENDED_DN_OID_W = "1.2.840.113556.1.4.529", LDAP_SERVER_LAZY_COMMIT_OID_W = "1.2.840.113556.1.4.619", LDAP_SERVER_TREE_DELETE_OID_W = "1.2.840.113556.1.4.805", LDAP_SERVER_VERIFY_NAME_OID_W = "1.2.840.113556.1.4.1338", LDAP_SERVER_SHOW_DELETED_OID_W = "1.2.840.113556.1.4.417", LDAP_SERVER_NOTIFICATION_OID_W = "1.2.840.113556.1.4.528", LDAP_SERVER_DOMAIN_SCOPE_OID_W = "1.2.840.113556.1.4.1339", LDAP_CAP_ACTIVE_DIRECTORY_OID_W = "1.2.840.113556.1.4.800", LDAP_SERVER_SEARCH_OPTIONS_OID_W = "1.2.840.113556.1.4.1340", LDAP_CAP_ACTIVE_DIRECTORY_V51_OID_W = "1.2.840.113556.1.4.1670", LDAP_SERVER_PERMISSIVE_MODIFY_OID_W = "1.2.840.113556.1.4.1413", LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID_W = "1.2.840.113556.1.4.521"; enum SERVER_SEARCH_FLAG_DOMAIN_SCOPE = 1; enum SERVER_SEARCH_FLAG_PHANTOM_ROOT = 2; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/accctrl.d0000664000175000017500000003026112776214756023274 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_accctrl.d) */ module core.sys.windows.accctrl; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.basetyps, core.sys.windows.w32api, core.sys.windows.winbase, core.sys.windows.windef; // FIXME: check types and grouping of constants // FIXME: check Windows version support alias LocalFree AccFree; enum uint ACTRL_RESERVED = 0x00000000, ACTRL_ACCESS_PROTECTED = 0x00000001, ACTRL_ACCESS_ALLOWED = 0x00000001, ACTRL_ACCESS_DENIED = 0x00000002, ACTRL_AUDIT_SUCCESS = 0x00000004, ACTRL_AUDIT_FAILURE = 0x00000008, ACTRL_SYSTEM_ACCESS = 0x04000000, ACTRL_DELETE = 0x08000000, ACTRL_READ_CONTROL = 0x10000000, ACTRL_CHANGE_ACCESS = 0x20000000, ACTRL_CHANGE_OWNER = 0x40000000, ACTRL_SYNCHRONIZE = 0x80000000, ACTRL_STD_RIGHTS_ALL = 0xf8000000; enum uint ACTRL_FILE_READ = 0x00000001, ACTRL_FILE_WRITE = 0x00000002, ACTRL_FILE_APPEND = 0x00000004, ACTRL_FILE_READ_PROP = 0x00000008, ACTRL_FILE_WRITE_PROP = 0x00000010, ACTRL_FILE_EXECUTE = 0x00000020, ACTRL_FILE_READ_ATTRIB = 0x00000080, ACTRL_FILE_WRITE_ATTRIB = 0x00000100, ACTRL_FILE_CREATE_PIPE = 0x00000200; enum uint ACTRL_DIR_LIST = 0x00000001, ACTRL_DIR_CREATE_OBJECT = 0x00000002, ACTRL_DIR_CREATE_CHILD = 0x00000004, ACTRL_DIR_DELETE_CHILD = 0x00000040, ACTRL_DIR_TRAVERSE = 0x00000020; enum uint ACTRL_KERNEL_TERMINATE = 0x00000001, ACTRL_KERNEL_THREAD = 0x00000002, ACTRL_KERNEL_VM = 0x00000004, ACTRL_KERNEL_VM_READ = 0x00000008, ACTRL_KERNEL_VM_WRITE = 0x00000010, ACTRL_KERNEL_DUP_HANDLE = 0x00000020, ACTRL_KERNEL_PROCESS = 0x00000040, ACTRL_KERNEL_SET_INFO = 0x00000080, ACTRL_KERNEL_GET_INFO = 0x00000100, ACTRL_KERNEL_CONTROL = 0x00000200, ACTRL_KERNEL_ALERT = 0x00000400, ACTRL_KERNEL_GET_CONTEXT = 0x00000800, ACTRL_KERNEL_SET_CONTEXT = 0x00001000, ACTRL_KERNEL_TOKEN = 0x00002000, ACTRL_KERNEL_IMPERSONATE = 0x00004000, ACTRL_KERNEL_DIMPERSONATE = 0x00008000; enum uint ACTRL_PRINT_SADMIN = 0x00000001, ACTRL_PRINT_SLIST = 0x00000002, ACTRL_PRINT_PADMIN = 0x00000004, ACTRL_PRINT_PUSE = 0x00000008, ACTRL_PRINT_JADMIN = 0x00000010; enum uint ACTRL_SVC_GET_INFO = 0x00000001, ACTRL_SVC_SET_INFO = 0x00000002, ACTRL_SVC_STATUS = 0x00000004, ACTRL_SVC_LIST = 0x00000008, ACTRL_SVC_START = 0x00000010, ACTRL_SVC_STOP = 0x00000020, ACTRL_SVC_PAUSE = 0x00000040, ACTRL_SVC_INTERROGATE = 0x00000080, ACTRL_SVC_UCONTROL = 0x00000100; enum uint ACTRL_REG_QUERY = 0x00000001, ACTRL_REG_SET = 0x00000002, ACTRL_REG_CREATE_CHILD = 0x00000004, ACTRL_REG_LIST = 0x00000008, ACTRL_REG_NOTIFY = 0x00000010, ACTRL_REG_LINK = 0x00000020; enum uint ACTRL_WIN_CLIPBRD = 0x00000001, ACTRL_WIN_GLOBAL_ATOMS = 0x00000002, ACTRL_WIN_CREATE = 0x00000004, ACTRL_WIN_LIST_DESK = 0x00000008, ACTRL_WIN_LIST = 0x00000010, ACTRL_WIN_READ_ATTRIBS = 0x00000020, ACTRL_WIN_WRITE_ATTRIBS = 0x00000040, ACTRL_WIN_SCREEN = 0x00000080, ACTRL_WIN_EXIT = 0x00000100; enum : uint { ACTRL_ACCESS_NO_OPTIONS = 0x00000000, ACTRL_ACCESS_SUPPORTS_OBJECT_ENTRIES = 0x00000001 } const TCHAR[] ACCCTRL_DEFAULT_PROVIDER = "Windows NT Access Provider"; enum uint TRUSTEE_ACCESS_ALLOWED = 0x00000001, TRUSTEE_ACCESS_READ = 0x00000002, TRUSTEE_ACCESS_WRITE = 0x00000004, TRUSTEE_ACCESS_EXPLICIT = 0x00000001, TRUSTEE_ACCESS_READ_WRITE = 0x00000006, TRUSTEE_ACCESS_ALL = 0xFFFFFFFF; enum uint NO_INHERITANCE = 0x0, SUB_OBJECTS_ONLY_INHERIT = 0x1, SUB_CONTAINERS_ONLY_INHERIT = 0x2, SUB_CONTAINERS_AND_OBJECTS_INHERIT = 0x3, INHERIT_NO_PROPAGATE = 0x4, INHERIT_ONLY = 0x8, INHERITED_ACCESS_ENTRY = 0x10, INHERITED_PARENT = 0x10000000, INHERITED_GRANDPARENT = 0x20000000; alias ULONG INHERIT_FLAGS, ACCESS_RIGHTS; alias ULONG* PINHERIT_FLAGS, PACCESS_RIGHTS; enum ACCESS_MODE { NOT_USED_ACCESS, GRANT_ACCESS, SET_ACCESS, DENY_ACCESS, REVOKE_ACCESS, SET_AUDIT_SUCCESS, SET_AUDIT_FAILURE } enum SE_OBJECT_TYPE { SE_UNKNOWN_OBJECT_TYPE, SE_FILE_OBJECT, SE_SERVICE, SE_PRINTER, SE_REGISTRY_KEY, SE_LMSHARE, SE_KERNEL_OBJECT, SE_WINDOW_OBJECT, SE_DS_OBJECT, SE_DS_OBJECT_ALL, SE_PROVIDER_DEFINED_OBJECT, SE_WMIGUID_OBJECT, SE_REGISTRY_WOW64_32KEY } enum TRUSTEE_TYPE { TRUSTEE_IS_UNKNOWN, TRUSTEE_IS_USER, TRUSTEE_IS_GROUP, TRUSTEE_IS_DOMAIN, TRUSTEE_IS_ALIAS, TRUSTEE_IS_WELL_KNOWN_GROUP, TRUSTEE_IS_DELETED, TRUSTEE_IS_INVALID, TRUSTEE_IS_COMPUTER } enum TRUSTEE_FORM { TRUSTEE_IS_SID, TRUSTEE_IS_NAME, TRUSTEE_BAD_FORM, TRUSTEE_IS_OBJECTS_AND_SID, TRUSTEE_IS_OBJECTS_AND_NAME } enum MULTIPLE_TRUSTEE_OPERATION { NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_IMPERSONATE } struct TRUSTEE_A { TRUSTEE_A* pMultipleTrustee; MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation; TRUSTEE_FORM TrusteeForm; TRUSTEE_TYPE TrusteeType; LPSTR ptstrName; } alias TRUSTEE_A TRUSTEEA; alias TRUSTEE_A* PTRUSTEE_A, PTRUSTEEA; struct TRUSTEE_W { TRUSTEE_W* pMultipleTrustee; MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation; TRUSTEE_FORM TrusteeForm; TRUSTEE_TYPE TrusteeType; LPWSTR ptstrName; } alias TRUSTEE_W TRUSTEEW; alias TRUSTEEW* PTRUSTEE_W, PTRUSTEEW; struct ACTRL_ACCESS_ENTRYA { TRUSTEE_A Trustee; ULONG fAccessFlags; ACCESS_RIGHTS Access; ACCESS_RIGHTS ProvSpecificAccess; INHERIT_FLAGS Inheritance; LPCSTR lpInheritProperty; } alias ACTRL_ACCESS_ENTRYA* PACTRL_ACCESS_ENTRYA; struct ACTRL_ACCESS_ENTRYW { TRUSTEE_W Trustee; ULONG fAccessFlags; ACCESS_RIGHTS Access; ACCESS_RIGHTS ProvSpecificAccess; INHERIT_FLAGS Inheritance; LPCWSTR lpInheritProperty; } alias ACTRL_ACCESS_ENTRYW* PACTRL_ACCESS_ENTRYW; struct ACTRL_ACCESS_ENTRY_LISTA { ULONG cEntries; ACTRL_ACCESS_ENTRYA* pAccessList; } alias ACTRL_ACCESS_ENTRY_LISTA* PACTRL_ACCESS_ENTRY_LISTA; struct ACTRL_ACCESS_ENTRY_LISTW { ULONG cEntries; ACTRL_ACCESS_ENTRYW* pAccessList; } alias ACTRL_ACCESS_ENTRY_LISTW* PACTRL_ACCESS_ENTRY_LISTW; struct ACTRL_PROPERTY_ENTRYA { LPCSTR lpProperty; PACTRL_ACCESS_ENTRY_LISTA pAccessEntryList; ULONG fListFlags; } alias ACTRL_PROPERTY_ENTRYA* PACTRL_PROPERTY_ENTRYA; struct ACTRL_PROPERTY_ENTRYW { LPCWSTR lpProperty; PACTRL_ACCESS_ENTRY_LISTW pAccessEntryList; ULONG fListFlags; } alias ACTRL_PROPERTY_ENTRYW* PACTRL_PROPERTY_ENTRYW; struct ACTRL_ACCESSA { ULONG cEntries; PACTRL_PROPERTY_ENTRYA pPropertyAccessList; } alias ACTRL_ACCESSA ACTRL_AUDITA; alias ACTRL_ACCESSA* PACTRL_ACCESSA, PACTRL_AUDITA; struct ACTRL_ACCESSW { ULONG cEntries; PACTRL_PROPERTY_ENTRYW pPropertyAccessList; } alias ACTRL_ACCESSW ACTRL_AUDITW; alias ACTRL_ACCESSW* PACTRL_ACCESSW, PACTRL_AUDITW; struct TRUSTEE_ACCESSA { LPSTR lpProperty; ACCESS_RIGHTS Access; ULONG fAccessFlags; ULONG fReturnedAccess; } alias TRUSTEE_ACCESSA* PTRUSTEE_ACCESSA; struct TRUSTEE_ACCESSW { LPWSTR lpProperty; ACCESS_RIGHTS Access; ULONG fAccessFlags; ULONG fReturnedAccess; } alias TRUSTEE_ACCESSW* PTRUSTEE_ACCESSW; struct ACTRL_OVERLAPPED { union { PVOID Provider; ULONG Reserved1; } ULONG Reserved2; HANDLE hEvent; } alias ACTRL_OVERLAPPED* PACTRL_OVERLAPPED; struct ACTRL_ACCESS_INFOA { ULONG fAccessPermission; LPSTR lpAccessPermissionName; } alias ACTRL_ACCESS_INFOA* PACTRL_ACCESS_INFOA; struct ACTRL_ACCESS_INFOW { ULONG fAccessPermission; LPWSTR lpAccessPermissionName; } alias ACTRL_ACCESS_INFOW* PACTRL_ACCESS_INFOW; struct ACTRL_CONTROL_INFOA { LPSTR lpControlId; LPSTR lpControlName; } alias ACTRL_CONTROL_INFOA* PACTRL_CONTROL_INFOA; struct ACTRL_CONTROL_INFOW { LPWSTR lpControlId; LPWSTR lpControlName; } alias ACTRL_CONTROL_INFOW* PACTRL_CONTROL_INFOW; struct EXPLICIT_ACCESS_A { DWORD grfAccessPermissions; ACCESS_MODE grfAccessMode; DWORD grfInheritance; TRUSTEE_A Trustee; } alias EXPLICIT_ACCESS_A EXPLICIT_ACCESSA; alias EXPLICIT_ACCESS_A* PEXPLICIT_ACCESS_A, PEXPLICIT_ACCESSA; struct EXPLICIT_ACCESS_W { DWORD grfAccessPermissions; ACCESS_MODE grfAccessMode; DWORD grfInheritance; TRUSTEE_W Trustee; } alias EXPLICIT_ACCESS_W EXPLICIT_ACCESSW; alias EXPLICIT_ACCESS_W* PEXPLICIT_ACCESS_W, PEXPLICIT_ACCESSW; struct OBJECTS_AND_SID { DWORD ObjectsPresent; GUID ObjectTypeGuid; GUID InheritedObjectTypeGuid; SID* pSid; } alias OBJECTS_AND_SID* POBJECTS_AND_SID; struct OBJECTS_AND_NAME_A { DWORD ObjectsPresent; SE_OBJECT_TYPE ObjectType; LPSTR ObjectTypeName; LPSTR InheritedObjectTypeName; LPSTR ptstrName; } alias OBJECTS_AND_NAME_A* POBJECTS_AND_NAME_A; struct OBJECTS_AND_NAME_W { DWORD ObjectsPresent; SE_OBJECT_TYPE ObjectType; LPWSTR ObjectTypeName; LPWSTR InheritedObjectTypeName; LPWSTR ptstrName; } alias OBJECTS_AND_NAME_W* POBJECTS_AND_NAME_W; static if (_WIN32_WINNT >= 0x501) { struct INHERITED_FROMA { LONG GenerationGap; LPSTR AncestorName; } alias INHERITED_FROMA* PINHERITED_FROMA; struct INHERITED_FROMW { LONG GenerationGap; LPWSTR AncestorName; } alias INHERITED_FROMW* PINHERITED_FROMW; } version (Unicode) { alias TRUSTEEW TRUSTEE; alias ACTRL_ACCESSW ACTRL_ACCESS; alias ACTRL_ACCESS_ENTRY_LISTW ACTRL_ACCESS_ENTRY_LIST; alias ACTRL_ACCESS_INFOW ACTRL_ACCESS_INFO; alias ACTRL_ACCESS_ENTRYW ACTRL_ACCESS_ENTRY; alias ACTRL_AUDITW ACTRL_AUDIT; alias ACTRL_CONTROL_INFOW ACTRL_CONTROL_INFO; alias EXPLICIT_ACCESSW EXPLICIT_ACCESS; alias TRUSTEE_ACCESSW TRUSTEE_ACCESS; alias OBJECTS_AND_NAME_W OBJECTS_AND_NAME_; static if (_WIN32_WINNT >= 0x501) { alias INHERITED_FROMW INHERITED_FROM; } } else { alias TRUSTEEA TRUSTEE; alias ACTRL_ACCESSA ACTRL_ACCESS; alias ACTRL_ACCESS_ENTRY_LISTA ACTRL_ACCESS_ENTRY_LIST; alias ACTRL_ACCESS_INFOA ACTRL_ACCESS_INFO; alias ACTRL_ACCESS_ENTRYA ACTRL_ACCESS_ENTRY; alias ACTRL_AUDITA ACTRL_AUDIT; alias ACTRL_CONTROL_INFOA ACTRL_CONTROL_INFO; alias EXPLICIT_ACCESSA EXPLICIT_ACCESS; alias TRUSTEE_ACCESSA TRUSTEE_ACCESS; alias OBJECTS_AND_NAME_A OBJECTS_AND_NAME_; static if (_WIN32_WINNT >= 0x501) { alias INHERITED_FROMA INHERITED_FROM; } } alias TRUSTEE TRUSTEE_; alias TRUSTEE* PTRUSTEE, PTRUSTEE_; alias ACTRL_ACCESS* PACTRL_ACCESS; alias ACTRL_ACCESS_ENTRY_LIST* PACTRL_ACCESS_ENTRY_LIST; alias ACTRL_ACCESS_INFO* PACTRL_ACCESS_INFO; alias ACTRL_ACCESS_ENTRY* PACTRL_ACCESS_ENTRY; alias ACTRL_AUDIT* PACTRL_AUDIT; alias ACTRL_CONTROL_INFO* PACTRL_CONTROL_INFO; alias EXPLICIT_ACCESS EXPLICIT_ACCESS_; alias EXPLICIT_ACCESS* PEXPLICIT_ACCESS, PEXPLICIT_ACCESS_; alias TRUSTEE_ACCESS* PTRUSTEE_ACCESS; alias OBJECTS_AND_NAME_* POBJECTS_AND_NAME_; static if (_WIN32_WINNT >= 0x501) { alias INHERITED_FROM* PINHERITED_FROM; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/objsafe.d0000664000175000017500000000120612776214756023267 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_objsafe.d) */ module core.sys.windows.objsafe; version (Windows): private import core.sys.windows.basetyps, core.sys.windows.unknwn, core.sys.windows.windef; enum { INTERFACESAFE_FOR_UNTRUSTED_CALLER = 1, INTERFACESAFE_FOR_UNTRUSTED_DATA } interface IObjectSafety : IUnknown { HRESULT GetInterfaceSafetyOptions(REFIID, DWORD*, DWORD*); HRESULT SetInterfaceSafetyOptions(REFIID, DWORD, DWORD); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/sqlucode.d0000664000175000017500000002514112776214756023501 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_sqlucode.d) */ module core.sys.windows.sqlucode; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.sqlext; enum SQL_WCHAR = -8; enum SQL_WVARCHAR = -9; enum SQL_WLONGVARCHAR = -10; enum SQL_C_WCHAR = SQL_WCHAR; enum SQL_SQLSTATE_SIZEW = 10; version(Unicode) { enum SQL_C_TCHAR = SQL_C_WCHAR; } else { enum SQL_C_TCHAR = SQL_C_CHAR; } // Moved from sqlext static if (ODBCVER <= 0x0300) { enum SQL_UNICODE = -95; enum SQL_UNICODE_VARCHAR = -96; enum SQL_UNICODE_LONGVARCHAR = -97; enum SQL_UNICODE_CHAR = SQL_UNICODE; } else { enum SQL_UNICODE = SQL_WCHAR; enum SQL_UNICODE_VARCHAR = SQL_WVARCHAR; enum SQL_UNICODE_LONGVARCHAR = SQL_WLONGVARCHAR; enum SQL_UNICODE_CHAR = SQL_WCHAR; } extern (Windows) { SQLRETURN SQLBrowseConnectA(SQLHDBC, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLBrowseConnectW(SQLHDBC, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLColAttributeA(SQLHSTMT, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*, SQLPOINTER); SQLRETURN SQLColAttributeW(SQLHSTMT, SQLUSMALLINT, SQLUSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*, SQLPOINTER); SQLRETURN SQLColAttributesA(SQLHSTMT, SQLUSMALLINT, SQLUSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*, SQLLEN*); SQLRETURN SQLColAttributesW(SQLHSTMT, SQLUSMALLINT, SQLUSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*, SQLLEN*); SQLRETURN SQLColumnPrivilegesA( SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT , SQLCHAR*, SQLSMALLINT ); SQLRETURN SQLColumnPrivilegesW( SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT ); SQLRETURN SQLColumnsA(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT , SQLCHAR*, SQLSMALLINT ); SQLRETURN SQLColumnsW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT , SQLWCHAR*, SQLSMALLINT ); SQLRETURN SQLConnectA(SQLHDBC, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLConnectW(SQLHDBC, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT); SQLRETURN SQLDataSourcesA(SQLHENV, SQLUSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLDataSourcesW(SQLHENV, SQLUSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLDescribeColA(SQLHSTMT, SQLUSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLSMALLINT*, SQLULEN*, SQLSMALLINT*, SQLSMALLINT*); SQLRETURN SQLDescribeColW(SQLHSTMT, SQLUSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLSMALLINT*, SQLULEN*, SQLSMALLINT*, SQLSMALLINT*); SQLRETURN SQLDriverConnectA(SQLHDBC, SQLHWND, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLUSMALLINT); SQLRETURN SQLDriverConnectW(SQLHDBC, SQLHWND, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLUSMALLINT); SQLRETURN SQLDriversA(SQLHENV, SQLUSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLDriversW(SQLHENV, SQLUSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLErrorA(SQLHENV, SQLHDBC, SQLHSTMT, SQLCHAR*, SQLINTEGER*, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLErrorW(SQLHENV, SQLHDBC, SQLHSTMT, SQLWCHAR*, SQLINTEGER*, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLExecDirectA(SQLHSTMT, SQLCHAR*, SQLINTEGER); SQLRETURN SQLExecDirectW(SQLHSTMT, SQLWCHAR*, SQLINTEGER); SQLRETURN SQLForeignKeysA(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLForeignKeysW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT); SQLRETURN SQLGetConnectAttrA(SQLHDBC, SQLINTEGER, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLGetConnectAttrW(SQLHDBC, SQLINTEGER, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLGetConnectOptionA(SQLHDBC, SQLUSMALLINT, SQLPOINTER); SQLRETURN SQLGetConnectOptionW(SQLHDBC, SQLUSMALLINT, SQLPOINTER); SQLRETURN SQLGetCursorNameA(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetCursorNameW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetInfoA(SQLHDBC, SQLUSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetInfoW(SQLHDBC, SQLUSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetTypeInfoA(SQLHSTMT, SQLSMALLINT); SQLRETURN SQLGetTypeInfoW(SQLHSTMT, SQLSMALLINT); SQLRETURN SQLNativeSqlA(SQLHDBC, SQLCHAR*, SQLINTEGER, SQLCHAR*, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLNativeSqlW(SQLHDBC, SQLWCHAR*, SQLINTEGER, SQLWCHAR*, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLPrepareA(SQLHSTMT, SQLCHAR*, SQLINTEGER); SQLRETURN SQLPrepareW(SQLHSTMT, SQLWCHAR*, SQLINTEGER); SQLRETURN SQLPrimaryKeysA(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT ); SQLRETURN SQLPrimaryKeysW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT); SQLRETURN SQLProcedureColumnsA(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLProcedureColumnsW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT); SQLRETURN SQLProceduresA(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLProceduresW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT); SQLRETURN SQLSetConnectAttrA(SQLHDBC, SQLINTEGER, SQLPOINTER, SQLINTEGER); SQLRETURN SQLSetConnectAttrW(SQLHDBC, SQLINTEGER, SQLPOINTER, SQLINTEGER); SQLRETURN SQLSetConnectOptionA(SQLHDBC, SQLUSMALLINT, SQLULEN); SQLRETURN SQLSetConnectOptionW(SQLHDBC, SQLUSMALLINT, SQLULEN); SQLRETURN SQLSetCursorNameA(SQLHSTMT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLSetCursorNameW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT); SQLRETURN SQLSpecialColumnsA(SQLHSTMT, SQLUSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT , SQLUSMALLINT, SQLUSMALLINT); SQLRETURN SQLSpecialColumnsW(SQLHSTMT, SQLUSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT , SQLUSMALLINT, SQLUSMALLINT); SQLRETURN SQLStatisticsA(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT , SQLUSMALLINT, SQLUSMALLINT); SQLRETURN SQLStatisticsW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT , SQLUSMALLINT, SQLUSMALLINT); SQLRETURN SQLTablePrivilegesA(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLTablePrivilegesW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT ); SQLRETURN SQLTablesA(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLTablesW(SQLHSTMT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT); static if (ODBCVER >= 0x0300) { SQLRETURN SQLGetDescFieldA(SQLHDESC, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLGetDescFieldW(SQLHDESC, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLSetDescFieldA(SQLHDESC, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLINTEGER); SQLRETURN SQLSetDescFieldW(SQLHDESC, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLINTEGER); SQLRETURN SQLGetDescRecA(SQLHDESC, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLSMALLINT*, SQLSMALLINT*, SQLLEN*, SQLSMALLINT*, SQLSMALLINT*, SQLSMALLINT*); SQLRETURN SQLGetDescRecW(SQLHDESC, SQLSMALLINT, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLSMALLINT*, SQLSMALLINT*, SQLLEN*, SQLSMALLINT*, SQLSMALLINT*, SQLSMALLINT*); SQLRETURN SQLGetDiagFieldA(SQLSMALLINT, SQLHANDLE, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetDiagFieldW(SQLSMALLINT, SQLHANDLE, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetDiagRecA(SQLSMALLINT, SQLHANDLE, SQLSMALLINT, SQLCHAR*, SQLINTEGER*, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetDiagRecW(SQLSMALLINT, SQLHANDLE, SQLSMALLINT, SQLWCHAR*, SQLINTEGER*, SQLWCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetStmtAttrA(SQLHSTMT, SQLINTEGER, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLGetStmtAttrW(SQLHSTMT, SQLINTEGER, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLSetStmtAttrA(SQLHSTMT, SQLINTEGER, SQLPOINTER, SQLINTEGER); SQLRETURN SQLSetStmtAttrW(SQLHSTMT, SQLINTEGER, SQLPOINTER, SQLINTEGER); } // #endif /* (ODBCVER >= 0x0300) */ } version (Unicode) { alias SQLBrowseConnectW SQLBrowseConnect; alias SQLColAttributeW SQLColAttribute; alias SQLColAttributesW SQLColAttributes; alias SQLColumnPrivilegesW SQLColumnPrivileges; alias SQLColumnsW SQLColumns; alias SQLConnectW SQLConnect; alias SQLDataSourcesW SQLDataSources; alias SQLDescribeColW SQLDescribeCol; alias SQLDriverConnectW SQLDriverConnect; alias SQLDriversW SQLDrivers; alias SQLErrorW SQLError; alias SQLExecDirectW SQLExecDirect; alias SQLForeignKeysW SQLForeignKeys; alias SQLGetConnectAttrW SQLGetConnectAttr; alias SQLGetConnectOptionW SQLGetConnectOption; alias SQLGetCursorNameW SQLGetCursorName; alias SQLGetDescFieldW SQLGetDescField; alias SQLGetDescRecW SQLGetDescRec; alias SQLGetDiagFieldW SQLGetDiagField; alias SQLGetDiagRecW SQLGetDiagRec; alias SQLGetInfoW SQLGetInfo; alias SQLGetStmtAttrW SQLGetStmtAttr; alias SQLGetTypeInfoW SQLGetTypeInfo; alias SQLNativeSqlW SQLNativeSql; alias SQLPrepareW SQLPrepare; alias SQLPrimaryKeysW SQLPrimaryKeys; alias SQLProcedureColumnsW SQLProcedureColumns; alias SQLProceduresW SQLProcedures; alias SQLSetConnectAttrW SQLSetConnectAttr; alias SQLSetConnectOptionW SQLSetConnectOption; alias SQLSetCursorNameW SQLSetCursorName; alias SQLSetDescFieldW SQLSetDescField; alias SQLSetStmtAttrW SQLSetStmtAttr; alias SQLSpecialColumnsW SQLSpecialColumns; alias SQLStatisticsW SQLStatistics; alias SQLTablePrivilegesW SQLTablePrivileges; alias SQLTablesW SQLTables; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winperf.d0000664000175000017500000001525112776214756023335 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winperf.d) */ module core.sys.windows.winperf; version (Windows): import core.sys.windows.windef; import core.sys.windows.winbase; // for SYSTEMTIME enum PERF_DATA_VERSION=1; enum PERF_DATA_REVISION=1; enum PERF_NO_INSTANCES=-1; enum PERF_SIZE_DWORD=0; enum PERF_SIZE_LARGE=256; enum PERF_SIZE_ZERO=512; enum PERF_SIZE_VARIABLE_LEN=768; enum PERF_TYPE_NUMBER=0; enum PERF_TYPE_COUNTER=1024; enum PERF_TYPE_TEXT=2048; enum PERF_TYPE_ZERO=0xC00; enum PERF_NUMBER_HEX=0; enum PERF_NUMBER_DECIMAL=0x10000; enum PERF_NUMBER_DEC_1000=0x20000; enum PERF_COUNTER_VALUE=0; enum PERF_COUNTER_RATE=0x10000; enum PERF_COUNTER_FRACTION=0x20000; enum PERF_COUNTER_BASE=0x30000; enum PERF_COUNTER_ELAPSED=0x40000; enum PERF_COUNTER_QUEUELEN=0x50000; enum PERF_COUNTER_HISTOGRAM=0x60000; enum PERF_TEXT_UNICODE=0; enum PERF_TEXT_ASCII=0x10000; enum PERF_TIMER_TICK=0; enum PERF_TIMER_100NS=0x100000; enum PERF_OBJECT_TIMER=0x200000; enum PERF_DELTA_COUNTER=0x400000; enum PERF_DELTA_BASE=0x800000; enum PERF_INVERSE_COUNTER=0x1000000; enum PERF_MULTI_COUNTER=0x2000000; enum PERF_DISPLAY_NO_SUFFIX=0; enum PERF_DISPLAY_PER_SEC=0x10000000; enum PERF_DISPLAY_PERCENT=0x20000000; enum PERF_DISPLAY_SECONDS=0x30000000; enum PERF_DISPLAY_NOSHOW=0x40000000; enum PERF_COUNTER_HISTOGRAM_TYPE=0x80000000; enum PERF_NO_UNIQUE_ID=(-1); enum PERF_DETAIL_NOVICE=100; enum PERF_DETAIL_ADVANCED=200; enum PERF_DETAIL_EXPERT=300; enum PERF_DETAIL_WIZARD=400; enum PERF_COUNTER_COUNTER=(PERF_SIZE_DWORD|PERF_TYPE_COUNTER|PERF_COUNTER_RATE|PERF_TIMER_TICK|PERF_DELTA_COUNTER|PERF_DISPLAY_PER_SEC); enum PERF_COUNTER_TIMER=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_RATE|PERF_TIMER_TICK|PERF_DELTA_COUNTER|PERF_DISPLAY_PERCENT); enum PERF_COUNTER_QUEUELEN_TYPE=(PERF_SIZE_DWORD|PERF_TYPE_COUNTER|PERF_COUNTER_QUEUELEN|PERF_TIMER_TICK|PERF_DELTA_COUNTER|PERF_DISPLAY_NO_SUFFIX); enum PERF_COUNTER_BULK_COUNT=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_RATE|PERF_TIMER_TICK|PERF_DELTA_COUNTER|PERF_DISPLAY_PER_SEC); enum PERF_COUNTER_TEXT=(PERF_SIZE_VARIABLE_LEN|PERF_TYPE_TEXT|PERF_TEXT_UNICODE|PERF_DISPLAY_NO_SUFFIX); enum PERF_COUNTER_RAWCOUNT=(PERF_SIZE_DWORD|PERF_TYPE_NUMBER|PERF_NUMBER_DECIMAL|PERF_DISPLAY_NO_SUFFIX); enum PERF_COUNTER_LARGE_RAWCOUNT=(PERF_SIZE_LARGE|PERF_TYPE_NUMBER|PERF_NUMBER_DECIMAL|PERF_DISPLAY_NO_SUFFIX); enum PERF_COUNTER_RAWCOUNT_HEX=(PERF_SIZE_DWORD|PERF_TYPE_NUMBER|PERF_NUMBER_HEX|PERF_DISPLAY_NO_SUFFIX); enum PERF_COUNTER_LARGE_RAWCOUNT_HEX=(PERF_SIZE_LARGE|PERF_TYPE_NUMBER|PERF_NUMBER_HEX|PERF_DISPLAY_NO_SUFFIX); enum PERF_SAMPLE_FRACTION=(PERF_SIZE_DWORD|PERF_TYPE_COUNTER|PERF_COUNTER_FRACTION|PERF_DELTA_COUNTER|PERF_DELTA_BASE|PERF_DISPLAY_PERCENT); enum PERF_SAMPLE_COUNTER=(PERF_SIZE_DWORD|PERF_TYPE_COUNTER|PERF_COUNTER_RATE|PERF_TIMER_TICK|PERF_DELTA_COUNTER|PERF_DISPLAY_NO_SUFFIX); enum PERF_COUNTER_NODATA=(PERF_SIZE_ZERO|PERF_DISPLAY_NOSHOW); enum PERF_COUNTER_TIMER_INV=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_RATE|PERF_TIMER_TICK|PERF_DELTA_COUNTER|PERF_INVERSE_COUNTER|PERF_DISPLAY_PERCENT); enum PERF_SAMPLE_BASE=(PERF_SIZE_DWORD|PERF_TYPE_COUNTER|PERF_COUNTER_BASE|PERF_DISPLAY_NOSHOW|1); enum PERF_AVERAGE_TIMER=(PERF_SIZE_DWORD|PERF_TYPE_COUNTER|PERF_COUNTER_FRACTION|PERF_DISPLAY_SECONDS); enum PERF_AVERAGE_BASE=(PERF_SIZE_DWORD|PERF_TYPE_COUNTER|PERF_COUNTER_BASE|PERF_DISPLAY_NOSHOW|2); enum PERF_AVERAGE_BULK=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_FRACTION|PERF_DISPLAY_NOSHOW); enum PERF_100NSEC_TIMER=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_RATE|PERF_TIMER_100NS|PERF_DELTA_COUNTER|PERF_DISPLAY_PERCENT); enum PERF_100NSEC_TIMER_INV=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_RATE|PERF_TIMER_100NS|PERF_DELTA_COUNTER|PERF_INVERSE_COUNTER|PERF_DISPLAY_PERCENT); enum PERF_COUNTER_MULTI_TIMER=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_RATE|PERF_DELTA_COUNTER|PERF_TIMER_TICK|PERF_MULTI_COUNTER|PERF_DISPLAY_PERCENT); enum PERF_COUNTER_MULTI_TIMER_INV=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_RATE|PERF_DELTA_COUNTER|PERF_MULTI_COUNTER|PERF_TIMER_TICK|PERF_INVERSE_COUNTER|PERF_DISPLAY_PERCENT); enum PERF_COUNTER_MULTI_BASE=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_BASE|PERF_MULTI_COUNTER|PERF_DISPLAY_NOSHOW); enum PERF_100NSEC_MULTI_TIMER=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_DELTA_COUNTER|PERF_COUNTER_RATE|PERF_TIMER_100NS|PERF_MULTI_COUNTER|PERF_DISPLAY_PERCENT); enum PERF_100NSEC_MULTI_TIMER_INV=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_DELTA_COUNTER|PERF_COUNTER_RATE|PERF_TIMER_100NS|PERF_MULTI_COUNTER|PERF_INVERSE_COUNTER|PERF_DISPLAY_PERCENT); enum PERF_RAW_FRACTION=(PERF_SIZE_DWORD|PERF_TYPE_COUNTER|PERF_COUNTER_FRACTION|PERF_DISPLAY_PERCENT); enum PERF_RAW_BASE=(PERF_SIZE_DWORD|PERF_TYPE_COUNTER|PERF_COUNTER_BASE|PERF_DISPLAY_NOSHOW|3); enum PERF_ELAPSED_TIME=(PERF_SIZE_LARGE|PERF_TYPE_COUNTER|PERF_COUNTER_ELAPSED|PERF_OBJECT_TIMER|PERF_DISPLAY_SECONDS); struct PERF_DATA_BLOCK { WCHAR[4] Signature; DWORD LittleEndian; DWORD Version; DWORD Revision; DWORD TotalByteLength; DWORD HeaderLength; DWORD NumObjectTypes; LONG DefaultObject; SYSTEMTIME SystemTime; LARGE_INTEGER PerfTime; LARGE_INTEGER PerfFreq; LARGE_INTEGER PerfTime100nSec; DWORD SystemNameLength; DWORD SystemNameOffset; } alias PERF_DATA_BLOCK * PPERF_DATA_BLOCK; struct PERF_OBJECT_TYPE { DWORD TotalByteLength; DWORD DefinitionLength; DWORD HeaderLength; DWORD ObjectNameTitleIndex; LPWSTR ObjectNameTitle; DWORD ObjectHelpTitleIndex; LPWSTR ObjectHelpTitle; DWORD DetailLevel; DWORD NumCounters; LONG DefaultCounter; LONG NumInstances; DWORD CodePage; LARGE_INTEGER PerfTime; LARGE_INTEGER PerfFreq; } alias PERF_OBJECT_TYPE * PPERF_OBJECT_TYPE; struct PERF_COUNTER_DEFINITION { DWORD ByteLength; DWORD CounterNameTitleIndex; LPWSTR CounterNameTitle; DWORD CounterHelpTitleIndex; LPWSTR CounterHelpTitle; LONG DefaultScale; DWORD DetailLevel; DWORD CounterType; DWORD CounterSize; DWORD CounterOffset; } alias PERF_COUNTER_DEFINITION * PPERF_COUNTER_DEFINITION; struct PERF_INSTANCE_DEFINITION { DWORD ByteLength; DWORD ParentObjectTitleIndex; DWORD ParentObjectInstance; LONG UniqueID; DWORD NameOffset; DWORD NameLength; } alias PERF_INSTANCE_DEFINITION * PPERF_INSTANCE_DEFINITION; struct PERF_COUNTER_BLOCK { DWORD ByteLength; } alias PERF_COUNTER_BLOCK * PPERF_COUNTER_BLOCK; extern (Windows): alias DWORD function (LPWSTR) PM_OPEN_PROC; alias DWORD function (LPWSTR,PVOID*,PDWORD,PDWORD) PM_COLLECT_PROC; alias DWORD function () PM_CLOSE_PROC; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/mmsystem.d0000664000175000017500000020277412776214756023551 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_mmsystem.d) */ module core.sys.windows.mmsystem; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "winmm"); /* The #defines MAKEFOURCC, mmioFOURCC, sndAlias are used to define * compile-time constants, so they are implemented as templates. */ private import core.sys.windows.w32api, core.sys.windows.windef, core.sys.windows.winver; align(1): enum MAXPNAMELEN = 32; enum MAXERRORLENGTH = 256; enum MAX_JOYSTICKOEMVXDNAME = 260; enum TIME_MS = 1; enum TIME_SAMPLES = 2; enum TIME_BYTES = 4; enum TIME_SMPTE = 8; enum TIME_MIDI = 16; enum TIME_TICKS = 32; template MAKEFOURCC(char c0, char c1, char c2, char c3) { enum DWORD MAKEFOURCC = c0 | (c1<<8) | (c2<<16) | (cast(DWORD)c3 <<24); } template mmioFOURCC(char c0, char c1, char c2, char c3) { enum DWORD mmioFOURCC = c0 | (c1<<8) | (c2<<16) | (cast(DWORD)c3 <<24); } enum { MM_JOY1MOVE = 0x3A0, MM_JOY2MOVE, MM_JOY1ZMOVE, MM_JOY2ZMOVE, // = 0x3A3 MM_JOY1BUTTONDOWN = 0x3B5, MM_JOY2BUTTONDOWN, MM_JOY1BUTTONUP, MM_JOY2BUTTONUP, MM_MCINOTIFY, // = 0x3B9 MM_WOM_OPEN = 0x3BB, MM_WOM_CLOSE, MM_WOM_DONE, MM_WIM_OPEN, MM_WIM_CLOSE, MM_WIM_DATA, MM_MIM_OPEN, MM_MIM_CLOSE, MM_MIM_DATA, MM_MIM_LONGDATA, MM_MIM_ERROR, MM_MIM_LONGERROR, MM_MOM_OPEN, MM_MOM_CLOSE, MM_MOM_DONE, // = 0x3C9 MM_DRVM_OPEN = 0x3D0, MM_DRVM_CLOSE, MM_DRVM_DATA, MM_DRVM_ERROR, MM_STREAM_OPEN, MM_STREAM_CLOSE, MM_STREAM_DONE, MM_STREAM_ERROR, // = 0x3D7 MM_MOM_POSITIONCB = 0x3CA, MM_MCISIGNAL, MM_MIM_MOREDATA, // = 0x3CC MM_MIXM_LINE_CHANGE = 0x3D0, MM_MIXM_CONTROL_CHANGE = 0x3D1 } enum MMSYSERR_BASE = 0; enum WAVERR_BASE = 32; enum MIDIERR_BASE = 64; enum TIMERR_BASE = 96; enum JOYERR_BASE = 160; enum MCIERR_BASE = 256; enum MIXERR_BASE = 1024; enum MCI_STRING_OFFSET = 512; enum MCI_VD_OFFSET = 1024; enum MCI_CD_OFFSET = 1088; enum MCI_WAVE_OFFSET = 1152; enum MCI_SEQ_OFFSET = 1216; enum { MMSYSERR_NOERROR = 0, MMSYSERR_ERROR = MMSYSERR_BASE+1, MMSYSERR_BADDEVICEID, MMSYSERR_NOTENABLED, MMSYSERR_ALLOCATED, MMSYSERR_INVALHANDLE, MMSYSERR_NODRIVER, MMSYSERR_NOMEM, MMSYSERR_NOTSUPPORTED, MMSYSERR_BADERRNUM, MMSYSERR_INVALFLAG, MMSYSERR_INVALPARAM, MMSYSERR_HANDLEBUSY, MMSYSERR_INVALIDALIAS, MMSYSERR_BADDB, MMSYSERR_KEYNOTFOUND, MMSYSERR_READERROR, MMSYSERR_WRITEERROR, MMSYSERR_DELETEERROR, MMSYSERR_VALNOTFOUND, MMSYSERR_NODRIVERCB, // = MMSYSERR_BASE+20 MMSYSERR_LASTERROR = MMSYSERR_NODRIVERCB } enum { DRV_LOAD = 1, DRV_ENABLE, DRV_OPEN, DRV_CLOSE, DRV_DISABLE, DRV_FREE, DRV_CONFIGURE, DRV_QUERYCONFIGURE, DRV_INSTALL, DRV_REMOVE, DRV_EXITSESSION, DRV_POWER } enum DRV_RESERVED = 0x800; enum DRV_USER = 0x4000; enum DRVCNF_CANCEL = 0; enum DRVCNF_OK = 1; enum DRVCNF_RESTART = 2; enum DRV_CANCEL = DRVCNF_CANCEL; enum DRV_OK = DRVCNF_OK; enum DRV_RESTART = DRVCNF_RESTART; enum DRV_MCI_FIRST = DRV_RESERVED; enum DRV_MCI_LAST = DRV_RESERVED + 0xFFF; enum CALLBACK_TYPEMASK = 0x70000; enum CALLBACK_NULL = 0; enum CALLBACK_WINDOW = 0x10000; enum CALLBACK_TASK = 0x20000; enum CALLBACK_FUNCTION = 0x30000; enum CALLBACK_THREAD = CALLBACK_TASK; enum CALLBACK_EVENT = 0x50000; enum SND_SYNC=0; enum SND_ASYNC=1; enum SND_NODEFAULT=2; enum SND_MEMORY=4; enum SND_LOOP=8; enum SND_NOSTOP=16; enum SND_NOWAIT=0x2000; enum SND_ALIAS=0x10000; enum SND_ALIAS_ID=0x110000; enum SND_FILENAME=0x20000; enum SND_RESOURCE=0x40004; enum SND_PURGE=0x40; enum SND_APPLICATION=0x80; enum SND_ALIAS_START=0; template sndAlias(char c0, char c1) { enum DWORD sndAlias = SND_ALIAS_START + c0 | (c1<<8); } enum SND_ALIAS_SYSTEMASTERISK = sndAlias!('S', '*'); enum SND_ALIAS_SYSTEMQUESTION = sndAlias!('S', '?'); enum SND_ALIAS_SYSTEMHAND = sndAlias!('S', 'H'); enum SND_ALIAS_SYSTEMEXIT = sndAlias!('S', 'E'); enum SND_ALIAS_SYSTEMSTART = sndAlias!('S', 'S'); enum SND_ALIAS_SYSTEMWELCOME = sndAlias!('S', 'W'); enum SND_ALIAS_SYSTEMEXCLAMATION = sndAlias!('S', '!'); enum SND_ALIAS_SYSTEMDEFAULT = sndAlias!('S', 'D'); enum { WAVERR_BADFORMAT = (WAVERR_BASE + 0), WAVERR_STILLPLAYING, WAVERR_UNPREPARED, WAVERR_SYNC, // = WAVERR_BASE + 3; WAVERR_LASTERROR = WAVERR_SYNC } enum WOM_OPEN = MM_WOM_OPEN; enum WOM_CLOSE = MM_WOM_CLOSE; enum WOM_DONE = MM_WOM_DONE; enum WIM_OPEN = MM_WIM_OPEN; enum WIM_CLOSE = MM_WIM_CLOSE; enum WIM_DATA = MM_WIM_DATA; enum UINT WAVE_MAPPER= -1; // FIXME: This doesn't make sense! enum WAVE_FORMAT_QUERY=1; enum WAVE_ALLOWSYNC=2; enum WAVE_MAPPED=4; enum WAVE_FORMAT_DIRECT=8; enum WAVE_FORMAT_DIRECT_QUERY=(WAVE_FORMAT_QUERY|WAVE_FORMAT_DIRECT); enum WHDR_DONE=1; enum WHDR_PREPARED=2; enum WHDR_BEGINLOOP=4; enum WHDR_ENDLOOP=8; enum WHDR_INQUEUE=16; enum WAVECAPS_PITCH=1; enum WAVECAPS_PLAYBACKRATE=2; enum WAVECAPS_VOLUME=4; enum WAVECAPS_LRVOLUME=8; enum WAVECAPS_SYNC=16; enum WAVECAPS_SAMPLEACCURATE=32; enum WAVECAPS_DIRECTSOUND=64; enum WAVE_INVALIDFORMAT=0; enum WAVE_FORMAT_1M08=1; enum WAVE_FORMAT_1S08=2; enum WAVE_FORMAT_1M16=4; enum WAVE_FORMAT_1S16=8; enum WAVE_FORMAT_2M08=16; enum WAVE_FORMAT_2S08=32; enum WAVE_FORMAT_2M16=64; enum WAVE_FORMAT_2S16=128; enum WAVE_FORMAT_4M08=256; enum WAVE_FORMAT_4S08=512; enum WAVE_FORMAT_4M16=1024; enum WAVE_FORMAT_4S16=2048; enum WAVE_FORMAT_PCM=1; enum { MIDIERR_UNPREPARED = MIDIERR_BASE, MIDIERR_STILLPLAYING, MIDIERR_NOMAP, MIDIERR_NOTREADY, MIDIERR_NODEVICE, MIDIERR_INVALIDSETUP, MIDIERR_BADOPENMODE, MIDIERR_DONT_CONTINUE, // = MIDIERR_BASE+7 MIDIERR_LASTERROR = MIDIERR_DONT_CONTINUE } enum MIDIPATCHSIZE=128; enum MIM_OPEN=MM_MIM_OPEN; enum MIM_CLOSE=MM_MIM_CLOSE; enum MIM_DATA=MM_MIM_DATA; enum MIM_LONGDATA=MM_MIM_LONGDATA; enum MIM_ERROR=MM_MIM_ERROR; enum MIM_LONGERROR=MM_MIM_LONGERROR; enum MOM_OPEN=MM_MOM_OPEN; enum MOM_CLOSE=MM_MOM_CLOSE; enum MOM_DONE=MM_MOM_DONE; enum MIM_MOREDATA=MM_MIM_MOREDATA; enum MOM_POSITIONCB=MM_MOM_POSITIONCB; enum UINT MIDIMAPPER= -1; // FIXME: uint is nonsense for this! enum UINT MIDI_MAPPER= -1; // FIXME: uint is nonsense for this! enum MIDI_IO_STATUS=32; enum MIDI_CACHE_ALL=1; enum MIDI_CACHE_BESTFIT=2; enum MIDI_CACHE_QUERY=3; enum MIDI_UNCACHE=4; enum MOD_MIDIPORT=1; enum MOD_SYNTH=2; enum MOD_SQSYNTH=3; enum MOD_FMSYNTH=4; enum MOD_MAPPER=5; enum MIDICAPS_VOLUME=1; enum MIDICAPS_LRVOLUME=2; enum MIDICAPS_CACHE=4; enum MIDICAPS_STREAM=8; enum MHDR_DONE=1; enum MHDR_PREPARED=2; enum MHDR_INQUEUE=4; enum MHDR_ISSTRM=8; enum MEVT_F_SHORT=0; enum MEVT_F_LONG=0x80000000; enum MEVT_F_CALLBACK=0x40000000; BYTE MEVT_EVENTTYPE(DWORD x) { return cast(BYTE)((x>>24) &0xFF); } DWORD MEVT_EVENTPARM(DWORD x) { return x & 0xFFFFFF; } enum MEVT_SHORTMSG=0; enum MEVT_TEMPO=1; enum MEVT_NOP=2; enum BYTE MEVT_LONGMSG = 0x80; enum BYTE MEVT_COMMENT = 0x82; enum BYTE MEVT_VERSION = 0x84; enum MIDISTRM_ERROR = -2; enum MIDIPROP_SET = 0x80000000; enum MIDIPROP_GET = 0x40000000; enum MIDIPROP_TIMEDIV = 1; enum MIDIPROP_TEMPO = 2; enum UINT AUX_MAPPER = -1; enum AUXCAPS_CDAUDIO=1; enum AUXCAPS_AUXIN=2; enum AUXCAPS_VOLUME=1; enum AUXCAPS_LRVOLUME=2; enum MIXER_SHORT_NAME_CHARS=16; enum MIXER_LONG_NAME_CHARS=64; enum MIXERR_INVALLINE=MIXERR_BASE; enum MIXERR_INVALCONTROL=(MIXERR_BASE+1); enum MIXERR_INVALVALUE=(MIXERR_BASE+2); enum MIXERR_LASTERROR=(MIXERR_BASE+2); enum MIXER_OBJECTF_HANDLE=0x80000000; enum MIXER_OBJECTF_MIXER=0; enum MIXER_OBJECTF_HMIXER=(MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_MIXER); enum MIXER_OBJECTF_WAVEOUT=0x10000000; enum MIXER_OBJECTF_HWAVEOUT=(MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_WAVEOUT); enum MIXER_OBJECTF_WAVEIN=0x20000000; enum MIXER_OBJECTF_HWAVEIN=(MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_WAVEIN); enum MIXER_OBJECTF_MIDIOUT=0x30000000; enum MIXER_OBJECTF_HMIDIOUT=(MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_MIDIOUT); enum MIXER_OBJECTF_MIDIIN=0x40000000; enum MIXER_OBJECTF_HMIDIIN=(MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_MIDIIN); enum MIXER_OBJECTF_AUX=0x50000000; enum MIXERLINE_LINEF_ACTIVE=1; enum MIXERLINE_LINEF_DISCONNECTED=0x8000; enum MIXERLINE_LINEF_SOURCE=0x80000000; enum MIXERLINE_COMPONENTTYPE_DST_FIRST=0; enum MIXERLINE_COMPONENTTYPE_DST_UNDEFINED=MIXERLINE_COMPONENTTYPE_DST_FIRST; enum MIXERLINE_COMPONENTTYPE_DST_DIGITAL=(MIXERLINE_COMPONENTTYPE_DST_FIRST+1); enum MIXERLINE_COMPONENTTYPE_DST_LINE=(MIXERLINE_COMPONENTTYPE_DST_FIRST+2); enum MIXERLINE_COMPONENTTYPE_DST_MONITOR=(MIXERLINE_COMPONENTTYPE_DST_FIRST+3); enum MIXERLINE_COMPONENTTYPE_DST_SPEAKERS=(MIXERLINE_COMPONENTTYPE_DST_FIRST+4); enum MIXERLINE_COMPONENTTYPE_DST_HEADPHONES=(MIXERLINE_COMPONENTTYPE_DST_FIRST+5); enum MIXERLINE_COMPONENTTYPE_DST_TELEPHONE=(MIXERLINE_COMPONENTTYPE_DST_FIRST+6); enum MIXERLINE_COMPONENTTYPE_DST_WAVEIN=(MIXERLINE_COMPONENTTYPE_DST_FIRST+7); enum MIXERLINE_COMPONENTTYPE_DST_VOICEIN=(MIXERLINE_COMPONENTTYPE_DST_FIRST+8); enum MIXERLINE_COMPONENTTYPE_DST_LAST=(MIXERLINE_COMPONENTTYPE_DST_FIRST+8); enum MIXERLINE_COMPONENTTYPE_SRC_FIRST=0x1000; enum MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED=MIXERLINE_COMPONENTTYPE_SRC_FIRST; enum MIXERLINE_COMPONENTTYPE_SRC_DIGITAL=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+1); enum MIXERLINE_COMPONENTTYPE_SRC_LINE=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+2); enum MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+3); enum MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+4); enum MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+5); enum MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+6); enum MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+7); enum MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+8); enum MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+9); enum MIXERLINE_COMPONENTTYPE_SRC_ANALOG=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+10); enum MIXERLINE_COMPONENTTYPE_SRC_LAST=(MIXERLINE_COMPONENTTYPE_SRC_FIRST+10); enum { MIXERLINE_TARGETTYPE_UNDEFINED = 0, MIXERLINE_TARGETTYPE_WAVEOUT, MIXERLINE_TARGETTYPE_WAVEIN, MIXERLINE_TARGETTYPE_MIDIOUT, MIXERLINE_TARGETTYPE_MIDIIN, MIXERLINE_TARGETTYPE_AUX // =5 } enum MIXER_GETLINEINFOF_DESTINATION=0; enum MIXER_GETLINEINFOF_SOURCE=1; enum MIXER_GETLINEINFOF_LINEID=2; enum MIXER_GETLINEINFOF_COMPONENTTYPE=3; enum MIXER_GETLINEINFOF_TARGETTYPE=4; enum MIXER_GETLINEINFOF_QUERYMASK=15; enum MIXERCONTROL_CONTROLF_UNIFORM=1; enum MIXERCONTROL_CONTROLF_MULTIPLE=2; enum MIXERCONTROL_CONTROLF_DISABLED=0x80000000; enum MIXERCONTROL_CT_CLASS_MASK=0xF0000000; enum MIXERCONTROL_CT_CLASS_CUSTOM=0; enum MIXERCONTROL_CT_CLASS_METER=0x10000000; enum MIXERCONTROL_CT_CLASS_SWITCH=0x20000000; enum MIXERCONTROL_CT_CLASS_NUMBER=0x30000000; enum MIXERCONTROL_CT_CLASS_SLIDER=0x40000000; enum MIXERCONTROL_CT_CLASS_FADER=0x50000000; enum MIXERCONTROL_CT_CLASS_TIME=0x60000000; enum MIXERCONTROL_CT_CLASS_LIST=0x70000000; enum MIXERCONTROL_CT_SUBCLASS_MASK=0xF000000; enum MIXERCONTROL_CT_SC_SWITCH_BOOLEAN=0; enum MIXERCONTROL_CT_SC_SWITCH_BUTTON=0x1000000; enum MIXERCONTROL_CT_SC_METER_POLLED=0; enum MIXERCONTROL_CT_SC_TIME_MICROSECS=0; enum MIXERCONTROL_CT_SC_TIME_MILLISECS=0x1000000; enum MIXERCONTROL_CT_SC_LIST_SINGLE=0; enum MIXERCONTROL_CT_SC_LIST_MULTIPLE=0x1000000; enum MIXERCONTROL_CT_UNITS_MASK=0xFF0000; enum MIXERCONTROL_CT_UNITS_CUSTOM=0; enum MIXERCONTROL_CT_UNITS_BOOLEAN=0x10000; enum MIXERCONTROL_CT_UNITS_SIGNED=0x20000; enum MIXERCONTROL_CT_UNITS_UNSIGNED=0x30000; enum MIXERCONTROL_CT_UNITS_DECIBELS=0x40000; enum MIXERCONTROL_CT_UNITS_PERCENT=0x50000; enum MIXERCONTROL_CONTROLTYPE_CUSTOM=(MIXERCONTROL_CT_CLASS_CUSTOM|MIXERCONTROL_CT_UNITS_CUSTOM); enum MIXERCONTROL_CONTROLTYPE_BOOLEANMETER=(MIXERCONTROL_CT_CLASS_METER|MIXERCONTROL_CT_SC_METER_POLLED|MIXERCONTROL_CT_UNITS_BOOLEAN); enum MIXERCONTROL_CONTROLTYPE_SIGNEDMETER=(MIXERCONTROL_CT_CLASS_METER|MIXERCONTROL_CT_SC_METER_POLLED|MIXERCONTROL_CT_UNITS_SIGNED); enum MIXERCONTROL_CONTROLTYPE_PEAKMETER=(MIXERCONTROL_CONTROLTYPE_SIGNEDMETER+1); enum MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER=(MIXERCONTROL_CT_CLASS_METER|MIXERCONTROL_CT_SC_METER_POLLED|MIXERCONTROL_CT_UNITS_UNSIGNED); enum MIXERCONTROL_CONTROLTYPE_BOOLEAN=(MIXERCONTROL_CT_CLASS_SWITCH|MIXERCONTROL_CT_SC_SWITCH_BOOLEAN|MIXERCONTROL_CT_UNITS_BOOLEAN); enum MIXERCONTROL_CONTROLTYPE_ONOFF=(MIXERCONTROL_CONTROLTYPE_BOOLEAN+1); enum MIXERCONTROL_CONTROLTYPE_MUTE=(MIXERCONTROL_CONTROLTYPE_BOOLEAN+2); enum MIXERCONTROL_CONTROLTYPE_MONO=(MIXERCONTROL_CONTROLTYPE_BOOLEAN+3); enum MIXERCONTROL_CONTROLTYPE_LOUDNESS=(MIXERCONTROL_CONTROLTYPE_BOOLEAN+4); enum MIXERCONTROL_CONTROLTYPE_STEREOENH=(MIXERCONTROL_CONTROLTYPE_BOOLEAN+5); enum MIXERCONTROL_CONTROLTYPE_BUTTON=(MIXERCONTROL_CT_CLASS_SWITCH|MIXERCONTROL_CT_SC_SWITCH_BUTTON|MIXERCONTROL_CT_UNITS_BOOLEAN); enum MIXERCONTROL_CONTROLTYPE_DECIBELS=(MIXERCONTROL_CT_CLASS_NUMBER|MIXERCONTROL_CT_UNITS_DECIBELS); enum MIXERCONTROL_CONTROLTYPE_SIGNED=(MIXERCONTROL_CT_CLASS_NUMBER|MIXERCONTROL_CT_UNITS_SIGNED); enum MIXERCONTROL_CONTROLTYPE_UNSIGNED=(MIXERCONTROL_CT_CLASS_NUMBER|MIXERCONTROL_CT_UNITS_UNSIGNED); enum MIXERCONTROL_CONTROLTYPE_PERCENT=(MIXERCONTROL_CT_CLASS_NUMBER|MIXERCONTROL_CT_UNITS_PERCENT); enum MIXERCONTROL_CONTROLTYPE_SLIDER=(MIXERCONTROL_CT_CLASS_SLIDER|MIXERCONTROL_CT_UNITS_SIGNED); enum MIXERCONTROL_CONTROLTYPE_PAN=(MIXERCONTROL_CONTROLTYPE_SLIDER+1); enum MIXERCONTROL_CONTROLTYPE_QSOUNDPAN=(MIXERCONTROL_CONTROLTYPE_SLIDER+2); enum MIXERCONTROL_CONTROLTYPE_FADER=(MIXERCONTROL_CT_CLASS_FADER|MIXERCONTROL_CT_UNITS_UNSIGNED); enum MIXERCONTROL_CONTROLTYPE_VOLUME=(MIXERCONTROL_CONTROLTYPE_FADER+1); enum MIXERCONTROL_CONTROLTYPE_BASS=(MIXERCONTROL_CONTROLTYPE_FADER+2); enum MIXERCONTROL_CONTROLTYPE_TREBLE=(MIXERCONTROL_CONTROLTYPE_FADER+3); enum MIXERCONTROL_CONTROLTYPE_EQUALIZER=(MIXERCONTROL_CONTROLTYPE_FADER+4); enum MIXERCONTROL_CONTROLTYPE_SINGLESELECT=(MIXERCONTROL_CT_CLASS_LIST|MIXERCONTROL_CT_SC_LIST_SINGLE|MIXERCONTROL_CT_UNITS_BOOLEAN); enum MIXERCONTROL_CONTROLTYPE_MUX=(MIXERCONTROL_CONTROLTYPE_SINGLESELECT+1); enum MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT=(MIXERCONTROL_CT_CLASS_LIST|MIXERCONTROL_CT_SC_LIST_MULTIPLE|MIXERCONTROL_CT_UNITS_BOOLEAN); enum MIXERCONTROL_CONTROLTYPE_MIXER=(MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT+1); enum MIXERCONTROL_CONTROLTYPE_MICROTIME=(MIXERCONTROL_CT_CLASS_TIME|MIXERCONTROL_CT_SC_TIME_MICROSECS|MIXERCONTROL_CT_UNITS_UNSIGNED); enum MIXERCONTROL_CONTROLTYPE_MILLITIME=(MIXERCONTROL_CT_CLASS_TIME|MIXERCONTROL_CT_SC_TIME_MILLISECS|MIXERCONTROL_CT_UNITS_UNSIGNED); enum MIXER_GETLINECONTROLSF_ALL=0; enum MIXER_GETLINECONTROLSF_ONEBYID=1; enum MIXER_GETLINECONTROLSF_ONEBYTYPE=2; enum MIXER_GETLINECONTROLSF_QUERYMASK=15; enum MIXER_GETCONTROLDETAILSF_VALUE=0; enum MIXER_GETCONTROLDETAILSF_LISTTEXT=1; enum MIXER_GETCONTROLDETAILSF_QUERYMASK=15; enum MIXER_SETCONTROLDETAILSF_VALUE=0; enum MIXER_SETCONTROLDETAILSF_CUSTOM=1; enum MIXER_SETCONTROLDETAILSF_QUERYMASK=15; enum TIMERR_NOERROR=0; enum TIMERR_NOCANDO=(TIMERR_BASE+1); enum TIMERR_STRUCT=(TIMERR_BASE+33); enum TIME_ONESHOT=0; enum TIME_PERIODIC=1; enum TIME_CALLBACK_FUNCTION=0; enum TIME_CALLBACK_EVENT_SET=16; enum TIME_CALLBACK_EVENT_PULSE=32; static if (_WIN32_WINNT >= 0x501) { enum TIME_KILL_SYNCHRONOUS=0x0100; } enum JOYERR_NOERROR = 0; enum JOYERR_PARMS=(JOYERR_BASE+5); enum JOYERR_NOCANDO=(JOYERR_BASE+6); enum JOYERR_UNPLUGGED=(JOYERR_BASE+7); enum JOY_BUTTON1=1; enum JOY_BUTTON2=2; enum JOY_BUTTON3=4; enum JOY_BUTTON4=8; enum JOY_BUTTON1CHG=256; enum JOY_BUTTON2CHG=512; enum JOY_BUTTON3CHG=1024; enum JOY_BUTTON4CHG=2048; enum JOY_BUTTON5=257; enum JOY_BUTTON6=513; enum JOY_BUTTON7=1025; enum JOY_BUTTON8=2049; enum JOY_BUTTON9=256; enum JOY_BUTTON10=512; enum JOY_BUTTON11=1024; enum JOY_BUTTON12=2048; enum JOY_BUTTON13=4096; enum JOY_BUTTON14=8192; enum JOY_BUTTON15=16384; enum JOY_BUTTON16=32768; enum JOY_BUTTON17=65536; enum JOY_BUTTON18=0x20000; enum JOY_BUTTON19=0x40000; enum JOY_BUTTON20=0x80000; enum JOY_BUTTON21=0x100000; enum JOY_BUTTON22=0x200000; enum JOY_BUTTON23=0x400000; enum JOY_BUTTON24=0x800000; enum JOY_BUTTON25=0x1000000; enum JOY_BUTTON26=0x2000000; enum JOY_BUTTON27=0x4000000; enum JOY_BUTTON28=0x8000000; enum JOY_BUTTON29=0x10000000; enum JOY_BUTTON30=0x20000000; enum JOY_BUTTON31=0x40000000; enum JOY_BUTTON32=0x80000000; enum : DWORD { JOY_POVCENTERED = -1, JOY_POVFORWARD = 0, JOY_POVBACKWARD = 18000, JOY_POVLEFT = 27000, JOY_POVRIGHT = 9000 } enum DWORD JOY_RETURNX = 0x00000001, JOY_RETURNY = 0x00000002, JOY_RETURNZ = 0x00000004, JOY_RETURNR = 0x00000008, JOY_RETURNU = 0x00000010, JOY_RETURNV = 0x00000020, JOY_RETURNPOV = 0x00000040, JOY_RETURNBUTTONS = 0x00000080, JOY_RETURNRAWDATA = 0x00000100, JOY_RETURNPOVCTS = 0x00000200, JOY_RETURNCENTERED = 0x00000400, JOY_USEDEADZONE = 0x00000800, JOY_RETURNALL = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNR | JOY_RETURNU | JOY_RETURNV | JOY_RETURNPOV | JOY_RETURNBUTTONS, JOY_CAL_READALWAYS = 0x00010000, JOY_CAL_READXYONLY = 0x00020000, JOY_CAL_READ3 = 0x00040000, JOY_CAL_READ4 = 0x00080000, JOY_CAL_READXONLY = 0x00100000, JOY_CAL_READYONLY = 0x00200000, JOY_CAL_READ5 = 0x00400000, JOY_CAL_READ6 = 0x00800000, JOY_CAL_READZONLY = 0x01000000, JOY_CAL_READRONLY = 0x02000000, JOY_CAL_READUONLY = 0x04000000, JOY_CAL_READVONLY = 0x08000000; enum JOYSTICKID1=0; enum JOYSTICKID2=1; enum JOYCAPS_HASZ=1; enum JOYCAPS_HASR=2; enum JOYCAPS_HASU=4; enum JOYCAPS_HASV=8; enum JOYCAPS_HASPOV=16; enum JOYCAPS_POV4DIR=32; enum JOYCAPS_POVCTS=64; enum MMIOERR_BASE=256; enum MMIOERR_FILENOTFOUND=(MMIOERR_BASE+1); enum MMIOERR_OUTOFMEMORY=(MMIOERR_BASE+2); enum MMIOERR_CANNOTOPEN=(MMIOERR_BASE+3); enum MMIOERR_CANNOTCLOSE=(MMIOERR_BASE+4); enum MMIOERR_CANNOTREAD=(MMIOERR_BASE+5); enum MMIOERR_CANNOTWRITE=(MMIOERR_BASE+6); enum MMIOERR_CANNOTSEEK=(MMIOERR_BASE+7); enum MMIOERR_CANNOTEXPAND=(MMIOERR_BASE+8); enum MMIOERR_CHUNKNOTFOUND=(MMIOERR_BASE+9); enum MMIOERR_UNBUFFERED=(MMIOERR_BASE+10); enum MMIOERR_PATHNOTFOUND=(MMIOERR_BASE+11); enum MMIOERR_ACCESSDENIED=(MMIOERR_BASE+12); enum MMIOERR_SHARINGVIOLATION=(MMIOERR_BASE+13); enum MMIOERR_NETWORKERROR=(MMIOERR_BASE+14); enum MMIOERR_TOOMANYOPENFILES=(MMIOERR_BASE+15); enum MMIOERR_INVALIDFILE=(MMIOERR_BASE+16); enum CFSEPCHAR='+'; enum MMIO_RWMODE=3; enum MMIO_SHAREMODE=0x70; enum MMIO_CREATE=0x1000; enum MMIO_PARSE=256; enum MMIO_DELETE=512; enum MMIO_EXIST=0x4000; enum MMIO_ALLOCBUF=0x10000; enum MMIO_GETTEMP=0x20000; enum MMIO_DIRTY=0x10000000; enum MMIO_READ=0; enum MMIO_WRITE=1; enum MMIO_READWRITE=2; enum MMIO_COMPAT=0; enum MMIO_EXCLUSIVE=16; enum MMIO_DENYWRITE=32; enum MMIO_DENYREAD=0x30; enum MMIO_DENYNONE=64; enum MMIO_FHOPEN=16; enum MMIO_EMPTYBUF=16; enum MMIO_TOUPPER=16; enum MMIO_INSTALLPROC=0x10000; enum MMIO_GLOBALPROC=0x10000000; enum MMIO_REMOVEPROC=0x20000; enum MMIO_UNICODEPROC=0x1000000; enum MMIO_FINDPROC=0x40000; enum MMIO_FINDCHUNK=16; enum MMIO_FINDRIFF=32; enum MMIO_FINDLIST=64; enum MMIO_CREATERIFF=32; enum MMIO_CREATELIST=64; enum MMIOM_READ=MMIO_READ; enum MMIOM_WRITE=MMIO_WRITE; enum MMIOM_SEEK=2; enum MMIOM_OPEN=3; enum MMIOM_CLOSE=4; enum MMIOM_WRITEFLUSH=5; enum MMIOM_RENAME=6; enum MMIOM_USER=0x8000; enum FOURCC_RIFF = mmioFOURCC!('R', 'I', 'F', 'F'); enum FOURCC_LIST = mmioFOURCC!('L', 'I', 'S', 'T'); enum FOURCC_DOS = mmioFOURCC!('D', 'O', 'S', ' '); enum FOURCC_MEM = mmioFOURCC!('M', 'E', 'M', ' '); enum MMIO_DEFAULTBUFFER=8192; enum { MCIERR_INVALID_DEVICE_ID = MCIERR_BASE + 1, MCIERR_UNRECOGNIZED_KEYWORD = MCIERR_BASE + 3, MCIERR_UNRECOGNIZED_COMMAND = MCIERR_BASE + 5, MCIERR_HARDWARE, MCIERR_INVALID_DEVICE_NAME, MCIERR_OUT_OF_MEMORY, MCIERR_DEVICE_OPEN, MCIERR_CANNOT_LOAD_DRIVER, MCIERR_MISSING_COMMAND_STRING, MCIERR_PARAM_OVERFLOW, MCIERR_MISSING_STRING_ARGUMENT, MCIERR_BAD_INTEGER, MCIERR_PARSER_INTERNAL, MCIERR_DRIVER_INTERNAL, MCIERR_MISSING_PARAMETER, MCIERR_UNSUPPORTED_FUNCTION, MCIERR_FILE_NOT_FOUND, MCIERR_DEVICE_NOT_READY, MCIERR_INTERNAL, MCIERR_DRIVER, MCIERR_CANNOT_USE_ALL, MCIERR_MULTIPLE, MCIERR_EXTENSION_NOT_FOUND, MCIERR_OUTOFRANGE, // = MCIERR_BASE+26 MCIERR_FLAGS_NOT_COMPATIBLE = MCIERR_BASE + 28, MCIERR_FILE_NOT_SAVED = MCIERR_BASE + 30, MCIERR_DEVICE_TYPE_REQUIRED, MCIERR_DEVICE_LOCKED, MCIERR_DUPLICATE_ALIAS, MCIERR_BAD_CONSTANT, MCIERR_MUST_USE_SHAREABLE, MCIERR_MISSING_DEVICE_NAME, MCIERR_BAD_TIME_FORMAT, MCIERR_NO_CLOSING_QUOTE, MCIERR_DUPLICATE_FLAGS, MCIERR_INVALID_FILE, MCIERR_NULL_PARAMETER_BLOCK, MCIERR_UNNAMED_RESOURCE, MCIERR_NEW_REQUIRES_ALIAS, MCIERR_NOTIFY_ON_AUTO_OPEN, MCIERR_NO_ELEMENT_ALLOWED, MCIERR_NONAPPLICABLE_FUNCTION, MCIERR_ILLEGAL_FOR_AUTO_OPEN, MCIERR_FILENAME_REQUIRED, MCIERR_EXTRA_CHARACTERS, MCIERR_DEVICE_NOT_INSTALLED, MCIERR_GET_CD, MCIERR_SET_CD, MCIERR_SET_DRIVE, MCIERR_DEVICE_LENGTH, MCIERR_DEVICE_ORD_LENGTH, MCIERR_NO_INTEGER, // = MCIERR_BASE + 56 MCIERR_WAVE_OUTPUTSINUSE = MCIERR_BASE + 64, MCIERR_WAVE_SETOUTPUTINUSE, MCIERR_WAVE_INPUTSINUSE, MCIERR_WAVE_SETINPUTINUSE, MCIERR_WAVE_OUTPUTUNSPECIFIED, MCIERR_WAVE_INPUTUNSPECIFIED, MCIERR_WAVE_OUTPUTSUNSUITABLE, MCIERR_WAVE_SETOUTPUTUNSUITABLE, MCIERR_WAVE_INPUTSUNSUITABLE, MCIERR_WAVE_SETINPUTUNSUITABLE, // = MCIERR_BASE + 73 MCIERR_SEQ_DIV_INCOMPATIBLE = MCIERR_BASE + 80, MCIERR_SEQ_PORT_INUSE, MCIERR_SEQ_PORT_NONEXISTENT, MCIERR_SEQ_PORT_MAPNODEVICE, MCIERR_SEQ_PORT_MISCERROR, MCIERR_SEQ_TIMER, MCIERR_SEQ_PORTUNSPECIFIED, MCIERR_SEQ_NOMIDIPRESENT, // = MCIERR_BASE + 87 MCIERR_NO_WINDOW = MCIERR_BASE + 90, MCIERR_CREATEWINDOW, MCIERR_FILE_READ, MCIERR_FILE_WRITE, MCIERR_NO_IDENTITY // = MCIERR_BASE + 94 } enum MCIERR_CUSTOM_DRIVER_BASE = MCIERR_BASE + 256; enum MCI_FIRST=DRV_MCI_FIRST; enum MCI_OPEN=0x803; enum MCI_CLOSE=0x804; enum MCI_ESCAPE=0x805; enum MCI_PLAY=0x806; enum MCI_SEEK=0x807; enum MCI_STOP=0x808; enum MCI_PAUSE=0x809; enum MCI_INFO=0x80A; enum MCI_GETDEVCAPS=0x80B; enum MCI_SPIN=0x80C; enum MCI_SET=0x80D; enum MCI_STEP=0x80E; enum MCI_RECORD=0x80F; enum MCI_SYSINFO=0x810; enum MCI_BREAK=0x811; enum MCI_SAVE=0x813; enum MCI_STATUS=0x814; enum MCI_CUE=0x830; enum MCI_REALIZE=0x840; enum MCI_WINDOW=0x841; enum MCI_PUT=0x842; enum MCI_WHERE=0x843; enum MCI_FREEZE=0x844; enum MCI_UNFREEZE=0x845; enum MCI_LOAD=0x850; enum MCI_CUT=0x851; enum MCI_COPY=0x852; enum MCI_PASTE=0x853; enum MCI_UPDATE=0x854; enum MCI_RESUME=0x855; enum MCI_DELETE=0x856; enum MCI_USER_MESSAGES=(DRV_MCI_FIRST+0x400); enum MCI_LAST=0xFFF; enum MCIDEVICEID MCI_ALL_DEVICE_ID = -1; enum MCI_DEVTYPE_VCR=513; enum MCI_DEVTYPE_VIDEODISC=514; enum MCI_DEVTYPE_OVERLAY=515; enum MCI_DEVTYPE_CD_AUDIO=516; enum MCI_DEVTYPE_DAT=517; enum MCI_DEVTYPE_SCANNER=518; enum MCI_DEVTYPE_ANIMATION=519; enum MCI_DEVTYPE_DIGITAL_VIDEO=520; enum MCI_DEVTYPE_OTHER=521; enum MCI_DEVTYPE_WAVEFORM_AUDIO=522; enum MCI_DEVTYPE_SEQUENCER=523; enum MCI_DEVTYPE_FIRST=MCI_DEVTYPE_VCR; enum MCI_DEVTYPE_LAST=MCI_DEVTYPE_SEQUENCER; enum MCI_DEVTYPE_FIRST_USER=0x1000; enum MCI_MODE_NOT_READY=(MCI_STRING_OFFSET+12); enum MCI_MODE_STOP=(MCI_STRING_OFFSET+13); enum MCI_MODE_PLAY=(MCI_STRING_OFFSET+14); enum MCI_MODE_RECORD=(MCI_STRING_OFFSET+15); enum MCI_MODE_SEEK=(MCI_STRING_OFFSET+16); enum MCI_MODE_PAUSE=(MCI_STRING_OFFSET+17); enum MCI_MODE_OPEN=(MCI_STRING_OFFSET+18); enum MCI_FORMAT_MILLISECONDS=0; enum MCI_FORMAT_HMS=1; enum MCI_FORMAT_MSF=2; enum MCI_FORMAT_FRAMES=3; enum MCI_FORMAT_SMPTE_24=4; enum MCI_FORMAT_SMPTE_25=5; enum MCI_FORMAT_SMPTE_30=6; enum MCI_FORMAT_SMPTE_30DROP=7; enum MCI_FORMAT_BYTES=8; enum MCI_FORMAT_SAMPLES=9; enum MCI_FORMAT_TMSF=10; // Macros BYTE MCI_HMS_HOUR(DWORD t) { return cast(BYTE)(t); } BYTE MCI_HMS_MINUTE(DWORD t) { return cast(BYTE)(t>>>8); } BYTE MCI_HMS_SECOND(DWORD t) { return cast(BYTE)( t>>>16); } DWORD MCI_MAKE_HMS(BYTE h, BYTE m, BYTE s) { return h |(m<<8)|(cast(DWORD)(s)<<16); } DWORD MCI_MAKE_MSF(BYTE m, BYTE s, BYTE f) { return m |(s<<8)|(cast(DWORD)(f)<<16); } DWORD MCI_MAKE_TMSF(BYTE t, BYTE m, BYTE s, BYTE f) { return t |(m<<8)|(s<<16)|(cast(DWORD)(f)<< 24); } BYTE MCI_MSF_MINUTE(DWORD t) { return cast(BYTE)(t); } BYTE MCI_MSF_SECOND(DWORD t) { return cast(BYTE)(t >>> 8); } BYTE MCI_MSF_FRAME(DWORD t) { return cast(BYTE)(t >>> 16); } BYTE MCI_TMSF_TRACK(DWORD t) { return cast(BYTE)(t); } BYTE MCI_TMSF_MINUTE(DWORD t) { return cast(BYTE)(t>>8); } BYTE MCI_TMSF_SECOND(DWORD t) { return cast(BYTE)(t>>16); } BYTE MCI_TMSF_FRAME(DWORD t) { return cast(BYTE)(t>>24); } enum MCI_NOTIFY_SUCCESSFUL=1; enum MCI_NOTIFY_SUPERSEDED=2; enum MCI_NOTIFY_ABORTED=4; enum MCI_NOTIFY_FAILURE=8; enum MCI_NOTIFY=1; enum MCI_WAIT=2; enum MCI_FROM=4; enum MCI_TO=8; enum MCI_TRACK=16; enum MCI_OPEN_SHAREABLE=256; enum MCI_OPEN_ELEMENT=512; enum MCI_OPEN_ALIAS=1024; enum MCI_OPEN_ELEMENT_ID=2048; enum MCI_OPEN_TYPE_ID=0x1000; enum MCI_OPEN_TYPE=0x2000; enum MCI_SEEK_TO_START=256; enum MCI_SEEK_TO_END=512; enum MCI_STATUS_ITEM=256; enum MCI_STATUS_START=512; enum MCI_STATUS_LENGTH=1; enum MCI_STATUS_POSITION=2; enum MCI_STATUS_NUMBER_OF_TRACKS=3; enum MCI_STATUS_MODE=4; enum MCI_STATUS_MEDIA_PRESENT=5; enum MCI_STATUS_TIME_FORMAT=6; enum MCI_STATUS_READY=7; enum MCI_STATUS_CURRENT_TRACK=8; enum MCI_INFO_PRODUCT=256; enum MCI_INFO_FILE=512; enum MCI_INFO_MEDIA_UPC=1024; enum MCI_INFO_MEDIA_IDENTITY=2048; enum MCI_INFO_NAME=0x1000; enum MCI_INFO_COPYRIGHT=0x2000; enum MCI_GETDEVCAPS_ITEM=256; enum MCI_GETDEVCAPS_CAN_RECORD=1; enum MCI_GETDEVCAPS_HAS_AUDIO=2; enum MCI_GETDEVCAPS_HAS_VIDEO=3; enum MCI_GETDEVCAPS_DEVICE_TYPE=4; enum MCI_GETDEVCAPS_USES_FILES=5; enum MCI_GETDEVCAPS_COMPOUND_DEVICE=6; enum MCI_GETDEVCAPS_CAN_EJECT=7; enum MCI_GETDEVCAPS_CAN_PLAY=8; enum MCI_GETDEVCAPS_CAN_SAVE=9; enum MCI_SYSINFO_QUANTITY=256; enum MCI_SYSINFO_OPEN=512; enum MCI_SYSINFO_NAME=1024; enum MCI_SYSINFO_INSTALLNAME=2048; enum MCI_SET_DOOR_OPEN=256; enum MCI_SET_DOOR_CLOSED=512; enum MCI_SET_TIME_FORMAT=1024; enum MCI_SET_AUDIO=2048; enum MCI_SET_VIDEO=0x1000; enum MCI_SET_ON=0x2000; enum MCI_SET_OFF=0x4000; enum MCI_SET_AUDIO_ALL=0; enum MCI_SET_AUDIO_LEFT=1; enum MCI_SET_AUDIO_RIGHT=2; enum MCI_BREAK_KEY=256; enum MCI_BREAK_HWND=512; enum MCI_BREAK_OFF=1024; enum MCI_RECORD_INSERT=256; enum MCI_RECORD_OVERWRITE=512; enum MCI_SAVE_FILE=256; enum MCI_LOAD_FILE=256; enum MCI_VD_MODE_PARK=(MCI_VD_OFFSET+1); enum MCI_VD_MEDIA_CLV=(MCI_VD_OFFSET+2); enum MCI_VD_MEDIA_CAV=(MCI_VD_OFFSET+3); enum MCI_VD_MEDIA_OTHER=(MCI_VD_OFFSET+4); enum MCI_VD_FORMAT_TRACK=0x4001; enum MCI_VD_PLAY_REVERSE=0x10000; enum MCI_VD_PLAY_FAST=0x20000; enum MCI_VD_PLAY_SPEED=0x40000; enum MCI_VD_PLAY_SCAN=0x80000; enum MCI_VD_PLAY_SLOW=0x100000; enum MCI_VD_SEEK_REVERSE=0x10000; enum MCI_VD_STATUS_SPEED=0x4002; enum MCI_VD_STATUS_FORWARD=0x4003; enum MCI_VD_STATUS_MEDIA_TYPE=0x4004; enum MCI_VD_STATUS_SIDE=0x4005; enum MCI_VD_STATUS_DISC_SIZE=0x4006; enum MCI_VD_GETDEVCAPS_CLV=0x10000; enum MCI_VD_GETDEVCAPS_CAV=0x20000; enum MCI_VD_SPIN_UP=0x10000; enum MCI_VD_SPIN_DOWN=0x20000; enum MCI_VD_GETDEVCAPS_CAN_REVERSE=0x4002; enum MCI_VD_GETDEVCAPS_FAST_RATE=0x4003; enum MCI_VD_GETDEVCAPS_SLOW_RATE=0x4004; enum MCI_VD_GETDEVCAPS_NORMAL_RATE=0x4005; enum MCI_VD_STEP_FRAMES=0x10000; enum MCI_VD_STEP_REVERSE=0x20000; enum MCI_VD_ESCAPE_STRING=256; enum MCI_CDA_STATUS_TYPE_TRACK=0x4001; enum MCI_CDA_TRACK_AUDIO=MCI_CD_OFFSET; enum MCI_CDA_TRACK_OTHER=(MCI_CD_OFFSET+1); enum MCI_WAVE_PCM=MCI_WAVE_OFFSET; enum MCI_WAVE_MAPPER=(MCI_WAVE_OFFSET+1); enum MCI_WAVE_OPEN_BUFFER=0x10000; enum MCI_WAVE_SET_FORMATTAG=0x10000; enum MCI_WAVE_SET_CHANNELS=0x20000; enum MCI_WAVE_SET_SAMPLESPERSEC=0x40000; enum MCI_WAVE_SET_AVGBYTESPERSEC=0x80000; enum MCI_WAVE_SET_BLOCKALIGN=0x100000; enum MCI_WAVE_SET_BITSPERSAMPLE=0x200000; enum MCI_WAVE_INPUT=0x400000; enum MCI_WAVE_OUTPUT=0x800000; enum MCI_WAVE_STATUS_FORMATTAG=0x4001; enum MCI_WAVE_STATUS_CHANNELS=0x4002; enum MCI_WAVE_STATUS_SAMPLESPERSEC=0x4003; enum MCI_WAVE_STATUS_AVGBYTESPERSEC=0x4004; enum MCI_WAVE_STATUS_BLOCKALIGN=0x4005; enum MCI_WAVE_STATUS_BITSPERSAMPLE=0x4006; enum MCI_WAVE_STATUS_LEVEL=0x4007; enum MCI_WAVE_SET_ANYINPUT=0x4000000; enum MCI_WAVE_SET_ANYOUTPUT=0x8000000; enum MCI_WAVE_GETDEVCAPS_INPUTS=0x4001; enum MCI_WAVE_GETDEVCAPS_OUTPUTS=0x4002; enum MCI_SEQ_DIV_PPQN=MCI_SEQ_OFFSET; enum MCI_SEQ_DIV_SMPTE_24=(MCI_SEQ_OFFSET+1); enum MCI_SEQ_DIV_SMPTE_25=(MCI_SEQ_OFFSET+2); enum MCI_SEQ_DIV_SMPTE_30DROP=(MCI_SEQ_OFFSET+3); enum MCI_SEQ_DIV_SMPTE_30=(MCI_SEQ_OFFSET+4); enum MCI_SEQ_FORMAT_SONGPTR=0x4001; enum MCI_SEQ_FILE=0x4002; enum MCI_SEQ_MIDI=0x4003; enum MCI_SEQ_SMPTE=0x4004; enum MCI_SEQ_NONE=65533; enum MCI_SEQ_MAPPER=65535; enum MCI_SEQ_STATUS_TEMPO=0x4002; enum MCI_SEQ_STATUS_PORT=0x4003; enum MCI_SEQ_STATUS_SLAVE=0x4007; enum MCI_SEQ_STATUS_MASTER=0x4008; enum MCI_SEQ_STATUS_OFFSET=0x4009; enum MCI_SEQ_STATUS_DIVTYPE=0x400A; enum MCI_SEQ_STATUS_NAME=0x400B; enum MCI_SEQ_STATUS_COPYRIGHT=0x400C; enum MCI_SEQ_SET_TEMPO=0x10000; enum MCI_SEQ_SET_PORT=0x20000; enum MCI_SEQ_SET_SLAVE=0x40000; enum MCI_SEQ_SET_MASTER=0x80000; enum MCI_SEQ_SET_OFFSET=0x1000000; enum MCI_ANIM_OPEN_WS=0x10000; enum MCI_ANIM_OPEN_PARENT=0x20000; enum MCI_ANIM_OPEN_NOSTATIC=0x40000; enum MCI_ANIM_PLAY_SPEED=0x10000; enum MCI_ANIM_PLAY_REVERSE=0x20000; enum MCI_ANIM_PLAY_FAST=0x40000; enum MCI_ANIM_PLAY_SLOW=0x80000; enum MCI_ANIM_PLAY_SCAN=0x100000; enum MCI_ANIM_STEP_REVERSE=0x10000; enum MCI_ANIM_STEP_FRAMES=0x20000; enum MCI_ANIM_STATUS_SPEED=0x4001; enum MCI_ANIM_STATUS_FORWARD=0x4002; enum MCI_ANIM_STATUS_HWND=0x4003; enum MCI_ANIM_STATUS_HPAL=0x4004; enum MCI_ANIM_STATUS_STRETCH=0x4005; enum MCI_ANIM_INFO_TEXT=0x10000; enum MCI_ANIM_GETDEVCAPS_CAN_REVERSE=0x4001; enum MCI_ANIM_GETDEVCAPS_FAST_RATE=0x4002; enum MCI_ANIM_GETDEVCAPS_SLOW_RATE=0x4003; enum MCI_ANIM_GETDEVCAPS_NORMAL_RATE=0x4004; enum MCI_ANIM_GETDEVCAPS_PALETTES=0x4006; enum MCI_ANIM_GETDEVCAPS_CAN_STRETCH=0x4007; enum MCI_ANIM_GETDEVCAPS_MAX_WINDOWS=0x4008; enum MCI_ANIM_REALIZE_NORM=0x10000; enum MCI_ANIM_REALIZE_BKGD=0x20000; enum MCI_ANIM_WINDOW_HWND=0x10000; enum MCI_ANIM_WINDOW_STATE=0x40000; enum MCI_ANIM_WINDOW_TEXT=0x80000; enum MCI_ANIM_WINDOW_ENABLE_STRETCH=0x100000; enum MCI_ANIM_WINDOW_DISABLE_STRETCH=0x200000; enum MCI_ANIM_WINDOW_DEFAULT=0x0; enum MCI_ANIM_RECT=0x10000; enum MCI_ANIM_PUT_SOURCE=0x20000; enum MCI_ANIM_PUT_DESTINATION=0x40000; enum MCI_ANIM_WHERE_SOURCE=0x20000; enum MCI_ANIM_WHERE_DESTINATION=0x40000; enum MCI_ANIM_UPDATE_HDC=0x20000; enum MCI_OVLY_OPEN_WS=0x10000; enum MCI_OVLY_OPEN_PARENT=0x20000; enum MCI_OVLY_STATUS_HWND=0x4001; enum MCI_OVLY_STATUS_STRETCH=0x4002; enum MCI_OVLY_INFO_TEXT=0x10000; enum MCI_OVLY_GETDEVCAPS_CAN_STRETCH=0x4001; enum MCI_OVLY_GETDEVCAPS_CAN_FREEZE=0x4002; enum MCI_OVLY_GETDEVCAPS_MAX_WINDOWS=0x4003; enum MCI_OVLY_WINDOW_HWND=0x10000; enum MCI_OVLY_WINDOW_STATE=0x40000; enum MCI_OVLY_WINDOW_TEXT=0x80000; enum MCI_OVLY_WINDOW_ENABLE_STRETCH=0x100000; enum MCI_OVLY_WINDOW_DISABLE_STRETCH=0x200000; enum MCI_OVLY_WINDOW_DEFAULT=0x0; enum MCI_OVLY_RECT=0x10000; enum MCI_OVLY_PUT_SOURCE=0x20000; enum MCI_OVLY_PUT_DESTINATION=0x40000; enum MCI_OVLY_PUT_FRAME=0x80000; enum MCI_OVLY_PUT_VIDEO=0x100000; enum MCI_OVLY_WHERE_SOURCE=0x20000; enum MCI_OVLY_WHERE_DESTINATION=0x40000; enum MCI_OVLY_WHERE_FRAME=0x80000; enum MCI_OVLY_WHERE_VIDEO=0x100000; enum NEWTRANSPARENT=3; enum QUERYROPSUPPORT=40; enum SELECTDIB=41; LONG DIBINDEX(WORD n) { return MAKELONG(n, 0x10FF); } enum CAPS1=94; enum C1_TRANSPARENT=1; //const SEEK_SET=0; //const SEEK_CUR=1; //const SEEK_END=2; public import core.stdc.stdio : SEEK_SET, SEEK_CUR, SEEK_END; alias DWORD MCIERROR; alias UINT MCIDEVICEID; alias UINT function (MCIDEVICEID, DWORD) YIELDPROC; alias UINT MMVERSION; alias UINT MMRESULT; struct MMTIME { UINT wType; union { DWORD ms; DWORD sample; DWORD cb; DWORD ticks; struct smpte { BYTE hour; BYTE min; BYTE sec; BYTE frame; BYTE fps; BYTE dummy; BYTE[2] pad; }; struct midi { DWORD songptrpos; } } } alias MMTIME* PMMTIME, LPMMTIME; alias TypeDef!(HANDLE) HDRVR; struct DRVCONFIGINFO { DWORD dwDCISize; LPCWSTR lpszDCISectionName; LPCWSTR lpszDCIAliasName; } alias DRVCONFIGINFO * PDRVCONFIGINFO, LPDRVCONFIGINFO; struct DRVCONFIGINFOEX { DWORD dwDCISize; LPCWSTR lpszDCISectionName; LPCWSTR lpszDCIAliasName; DWORD dnDevNode; } alias DRVCONFIGINFOEX* PDRVCONFIGINFOEX, LPDRVCONFIGINFOEX; extern(Windows): /+FIXME: I couldn't find these in MSDN. alias void function (HDRVR, UINT, DWORD, DWORD, DWORD) DRVCALLBACK; LRESULT DRIVERPROC (DWORD, HDRVR, UINT, LPARAM, LPARAM); alias DRVCALLBACK* LPDRVCALLBACK, PDRVCALLBACK; alias DRVCALLBACK WAVECALLBACK; alias WAVECALLBACK* LPWAVECALLBACK; alias DRVCALLBACK MIDICALLBACK; alias MIDICALLBACK* LPMIDICALLBACK; +/ alias TypeDef!(HANDLE) HWAVE; alias TypeDef!(HANDLE) HWAVEIN; alias TypeDef!(HANDLE) HWAVEOUT; alias HWAVEIN* LPHWAVEIN; alias HWAVEOUT* LPHWAVEOUT; struct WAVEHDR { LPSTR lpData; DWORD dwBufferLength; DWORD dwBytesRecorded; DWORD dwUser; DWORD dwFlags; DWORD dwLoops; WAVEHDR *lpNext; DWORD reserved; } alias WAVEHDR* PWAVEHDR, LPWAVEHDR; struct WAVEOUTCAPSA { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR[MAXPNAMELEN] szPname; DWORD dwFormats; WORD wChannels; WORD wReserved1; DWORD dwSupport; } alias WAVEOUTCAPSA* PWAVEOUTCAPSA, LPWAVEOUTCAPSA; struct WAVEOUTCAPSW { WORD wMid; WORD wPid; MMVERSION vDriverVersion; WCHAR[MAXPNAMELEN] szPname; DWORD dwFormats; WORD wChannels; WORD wReserved1; DWORD dwSupport; } alias WAVEOUTCAPSW* PWAVEOUTCAPSW, LPWAVEOUTCAPSW; struct WAVEINCAPSA { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR[MAXPNAMELEN] szPname; DWORD dwFormats; WORD wChannels; WORD wReserved1; } alias WAVEINCAPSA* PWAVEINCAPSA, LPWAVEINCAPSA; struct WAVEINCAPSW { WORD wMid; WORD wPid; MMVERSION vDriverVersion; WCHAR[MAXPNAMELEN] szPname; DWORD dwFormats; WORD wChannels; WORD wReserved1; } alias WAVEINCAPSW* PWAVEINCAPSW, LPWAVEINCAPSW; struct WAVEFORMAT { WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; } alias WAVEFORMAT* PWAVEFORMAT, LPWAVEFORMAT; struct PCMWAVEFORMAT { WAVEFORMAT wf; WORD wBitsPerSample; } alias PCMWAVEFORMAT* PPCMWAVEFORMAT, LPPCMWAVEFORMAT; struct WAVEFORMATEX { WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; WORD wBitsPerSample; WORD cbSize; } alias WAVEFORMATEX* PWAVEFORMATEX, LPWAVEFORMATEX; alias const(WAVEFORMATEX)* LPCWAVEFORMATEX; alias TypeDef!(HANDLE) HMIDI; alias TypeDef!(HANDLE) HMIDIIN; alias TypeDef!(HANDLE) HMIDIOUT; alias TypeDef!(HANDLE) HMIDISTRM; alias HMIDI* LPHMIDI; alias HMIDIIN* LPHMIDIIN; alias HMIDIOUT* LPHMIDIOUT; alias HMIDISTRM* LPHMIDISTRM; alias WORD[MIDIPATCHSIZE] PATCHARRAY; alias WORD* LPPATCHARRAY; alias WORD[MIDIPATCHSIZE] KEYARRAY; alias WORD* LPKEYARRAY; struct MIDIOUTCAPSA { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR[MAXPNAMELEN] szPname; WORD wTechnology; WORD wVoices; WORD wNotes; WORD wChannelMask; DWORD dwSupport; } alias MIDIOUTCAPSA* PMIDIOUTCAPSA, LPMIDIOUTCAPSA; struct MIDIOUTCAPSW { WORD wMid; WORD wPid; MMVERSION vDriverVersion; WCHAR[MAXPNAMELEN] szPname; WORD wTechnology; WORD wVoices; WORD wNotes; WORD wChannelMask; DWORD dwSupport; } alias MIDIOUTCAPSW* PMIDIOUTCAPSW, LPMIDIOUTCAPSW; struct MIDIINCAPSA { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR[MAXPNAMELEN] szPname; DWORD dwSupport; } alias MIDIINCAPSA* PMIDIINCAPSA, LPMIDIINCAPSA; struct MIDIINCAPSW { WORD wMid; WORD wPid; MMVERSION vDriverVersion; WCHAR[MAXPNAMELEN] szPname; DWORD dwSupport; } alias MIDIINCAPSW* PMIDIINCAPSW, LPMIDIINCAPSW; struct MIDIHDR { LPSTR lpData; DWORD dwBufferLength; DWORD dwBytesRecorded; DWORD dwUser; DWORD dwFlags; MIDIHDR *lpNext; DWORD reserved; DWORD dwOffset; DWORD[8] dwReserved; } alias MIDIHDR* PMIDIHDR, LPMIDIHDR; struct MIDIEVENT { DWORD dwDeltaTime; DWORD dwStreamID; DWORD dwEvent; DWORD[1] dwParms; } struct MIDISTRMBUFFVER { DWORD dwVersion; DWORD dwMid; DWORD dwOEMVersion; } struct MIDIPROPTIMEDIV { DWORD cbStruct; DWORD dwTimeDiv; } alias MIDIPROPTIMEDIV* LPMIDIPROPTIMEDIV; struct MIDIPROPTEMPO { DWORD cbStruct; DWORD dwTempo; } alias MIDIPROPTEMPO* LPMIDIPROPTEMPO; struct AUXCAPSA { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR[MAXPNAMELEN] szPname; WORD wTechnology; WORD wReserved1; DWORD dwSupport; } alias AUXCAPSA* PAUXCAPSA, LPAUXCAPSA; struct AUXCAPSW { WORD wMid; WORD wPid; MMVERSION vDriverVersion; WCHAR[MAXPNAMELEN] szPname; WORD wTechnology; WORD wReserved1; DWORD dwSupport; } alias AUXCAPSW* PAUXCAPSW, LPAUXCAPSW; alias TypeDef!(HANDLE) HMIXEROBJ; alias HMIXEROBJ* LPHMIXEROBJ; alias TypeDef!(HANDLE) HMIXER; alias HMIXER* LPHMIXER; struct MIXERCAPSA { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR[MAXPNAMELEN] szPname; DWORD fdwSupport; DWORD cDestinations; } alias MIXERCAPSA* PMIXERCAPSA, LPMIXERCAPSA; struct MIXERCAPSW { WORD wMid; WORD wPid; MMVERSION vDriverVersion; WCHAR[MAXPNAMELEN] szPname; DWORD fdwSupport; DWORD cDestinations; } alias MIXERCAPSW* PMIXERCAPSW, LPMIXERCAPSW; struct MIXERLINEA { DWORD cbStruct; DWORD dwDestination; DWORD dwSource; DWORD dwLineID; DWORD fdwLine; DWORD dwUser; DWORD dwComponentType; DWORD cChannels; DWORD cConnections; DWORD cControls; CHAR[MIXER_SHORT_NAME_CHARS] szShortName; CHAR[MIXER_LONG_NAME_CHARS] szName; struct Target { DWORD dwType; DWORD dwDeviceID; WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR[MAXPNAMELEN] szPname; } } alias MIXERLINEA* PMIXERLINEA, LPMIXERLINEA; struct MIXERLINEW { DWORD cbStruct; DWORD dwDestination; DWORD dwSource; DWORD dwLineID; DWORD fdwLine; DWORD dwUser; DWORD dwComponentType; DWORD cChannels; DWORD cConnections; DWORD cControls; WCHAR[MIXER_SHORT_NAME_CHARS] szShortName; WCHAR[MIXER_LONG_NAME_CHARS] szName; struct Target { DWORD dwType; DWORD dwDeviceID; WORD wMid; WORD wPid; MMVERSION vDriverVersion; WCHAR[MAXPNAMELEN] szPname; } } alias MIXERLINEW* PMIXERLINEW, LPMIXERLINEW; struct MIXERCONTROLA { DWORD cbStruct; DWORD dwControlID; DWORD dwControlType; DWORD fdwControl; DWORD cMultipleItems; CHAR[MIXER_SHORT_NAME_CHARS] szShortName; CHAR[MIXER_LONG_NAME_CHARS] szName; union _Bounds { struct { LONG lMinimum; LONG lMaximum; } struct { DWORD dwMinimum; DWORD dwMaximum; } DWORD[6] dwReserved; } _Bounds Bounds; union _Metrics { DWORD cSteps; DWORD cbCustomData; DWORD[6] dwReserved; } _Metrics Metrics; } alias MIXERCONTROLA* PMIXERCONTROLA, LPMIXERCONTROLA; struct MIXERCONTROLW { DWORD cbStruct; DWORD dwControlID; DWORD dwControlType; DWORD fdwControl; DWORD cMultipleItems; WCHAR[MIXER_SHORT_NAME_CHARS] szShortName; WCHAR[MIXER_LONG_NAME_CHARS] szName; union _Bounds { struct { LONG lMinimum; LONG lMaximum; } struct { DWORD dwMinimum; DWORD dwMaximum; } DWORD[6] dwReserved; } _Bounds Bounds; union _Metrics { DWORD cSteps; DWORD cbCustomData; DWORD[6] dwReserved; } _Metrics Metrics; } alias MIXERCONTROLW* PMIXERCONTROLW, LPMIXERCONTROLW; struct MIXERLINECONTROLSA { DWORD cbStruct; DWORD dwLineID; union { DWORD dwControlID; DWORD dwControlType; } DWORD cControls; DWORD cbmxctrl; LPMIXERCONTROLA pamxctrl; } alias MIXERLINECONTROLSA* PMIXERLINECONTROLSA, LPMIXERLINECONTROLSA; struct MIXERLINECONTROLSW { DWORD cbStruct; DWORD dwLineID; union { DWORD dwControlID; DWORD dwControlType; } DWORD cControls; DWORD cbmxctrl; LPMIXERCONTROLW pamxctrl; } alias MIXERLINECONTROLSW* PMIXERLINECONTROLSW, LPMIXERLINECONTROLSW; struct MIXERCONTROLDETAILS { DWORD cbStruct; DWORD dwControlID; DWORD cChannels; union { HWND hwndOwner; DWORD cMultipleItems; } DWORD cbDetails; PVOID paDetails; } alias MIXERCONTROLDETAILS* PMIXERCONTROLDETAILS, LPMIXERCONTROLDETAILS; struct MIXERCONTROLDETAILS_LISTTEXTA { DWORD dwParam1; DWORD dwParam2; CHAR[MIXER_LONG_NAME_CHARS] szName; } alias MIXERCONTROLDETAILS_LISTTEXTA* PMIXERCONTROLDETAILS_LISTTEXTA, LPMIXERCONTROLDETAILS_LISTTEXTA; struct MIXERCONTROLDETAILS_LISTTEXTW { DWORD dwParam1; DWORD dwParam2; WCHAR[MIXER_LONG_NAME_CHARS] szName; } alias MIXERCONTROLDETAILS_LISTTEXTW* PMIXERCONTROLDETAILS_LISTTEXTW, LPMIXERCONTROLDETAILS_LISTTEXTW; struct MIXERCONTROLDETAILS_BOOLEAN { LONG fValue; } alias MIXERCONTROLDETAILS_BOOLEAN* PMIXERCONTROLDETAILS_BOOLEAN, LPMIXERCONTROLDETAILS_BOOLEAN; struct MIXERCONTROLDETAILS_SIGNED { LONG lValue; } alias MIXERCONTROLDETAILS_SIGNED* PMIXERCONTROLDETAILS_SIGNED, LPMIXERCONTROLDETAILS_SIGNED; struct MIXERCONTROLDETAILS_UNSIGNED { DWORD dwValue; } alias MIXERCONTROLDETAILS_UNSIGNED* PMIXERCONTROLDETAILS_UNSIGNED, LPMIXERCONTROLDETAILS_UNSIGNED; alias void function (UINT, UINT, DWORD, DWORD, DWORD) LPTIMECALLBACK; struct TIMECAPS { UINT wPeriodMin; UINT wPeriodMax; } alias TIMECAPS* PTIMECAPS, LPTIMECAPS; struct JOYCAPSA { WORD wMid; WORD wPid; CHAR[MAXPNAMELEN] szPname; UINT wXmin; UINT wXmax; UINT wYmin; UINT wYmax; UINT wZmin; UINT wZmax; UINT wNumButtons; UINT wPeriodMin; UINT wPeriodMax; UINT wRmin; UINT wRmax; UINT wUmin; UINT wUmax; UINT wVmin; UINT wVmax; UINT wCaps; UINT wMaxAxes; UINT wNumAxes; UINT wMaxButtons; CHAR[MAXPNAMELEN] szRegKey; CHAR[MAX_JOYSTICKOEMVXDNAME] szOEMVxD; } alias JOYCAPSA* PJOYCAPSA, LPJOYCAPSA; struct JOYCAPSW { WORD wMid; WORD wPid; WCHAR[MAXPNAMELEN] szPname; UINT wXmin; UINT wXmax; UINT wYmin; UINT wYmax; UINT wZmin; UINT wZmax; UINT wNumButtons; UINT wPeriodMin; UINT wPeriodMax; UINT wRmin; UINT wRmax; UINT wUmin; UINT wUmax; UINT wVmin; UINT wVmax; UINT wCaps; UINT wMaxAxes; UINT wNumAxes; UINT wMaxButtons; WCHAR[MAXPNAMELEN] szRegKey; WCHAR[MAX_JOYSTICKOEMVXDNAME] szOEMVxD; } alias JOYCAPSW* PJOYCAPSW, LPJOYCAPSW; struct JOYINFO { UINT wXpos; UINT wYpos; UINT wZpos; UINT wButtons; } alias JOYINFO* PJOYINFO, LPJOYINFO; struct JOYINFOEX { DWORD dwSize; DWORD dwFlags; DWORD dwXpos; DWORD dwYpos; DWORD dwZpos; DWORD dwRpos; DWORD dwUpos; DWORD dwVpos; DWORD dwButtons; DWORD dwButtonNumber; DWORD dwPOV; DWORD dwReserved1; DWORD dwReserved2; } alias JOYINFOEX* PJOYINFOEX, LPJOYINFOEX; alias DWORD FOURCC; alias char* HPSTR; alias TypeDef!(HANDLE) HMMIO; alias LRESULT function (LPSTR, UINT, LPARAM, LPARAM) LPMMIOPROC; struct MMIOINFO { DWORD dwFlags; FOURCC fccIOProc; LPMMIOPROC pIOProc; UINT wErrorRet; HTASK htask; LONG cchBuffer; HPSTR pchBuffer; HPSTR pchNext; HPSTR pchEndRead; HPSTR pchEndWrite; LONG lBufOffset; LONG lDiskOffset; DWORD[3] adwInfo; DWORD dwReserved1; DWORD dwReserved2; HMMIO hmmio; } alias MMIOINFO* PMMIOINFO, LPMMIOINFO; alias const(MMIOINFO)* LPCMMIOINFO; struct MMCKINFO { FOURCC ckid; DWORD cksize; FOURCC fccType; DWORD dwDataOffset; DWORD dwFlags; } alias MMCKINFO* PMMCKINFO, LPMMCKINFO; alias const(MMCKINFO)* LPCMMCKINFO; struct MCI_GENERIC_PARMS { DWORD dwCallback; } alias MCI_GENERIC_PARMS* PMCI_GENERIC_PARMS, LPMCI_GENERIC_PARMS; struct MCI_OPEN_PARMSA { DWORD dwCallback; MCIDEVICEID wDeviceID; LPCSTR lpstrDeviceType; LPCSTR lpstrElementName; LPCSTR lpstrAlias; } alias MCI_OPEN_PARMSA* PMCI_OPEN_PARMSA, LPMCI_OPEN_PARMSA; struct MCI_OPEN_PARMSW { DWORD dwCallback; MCIDEVICEID wDeviceID; LPCWSTR lpstrDeviceType; LPCWSTR lpstrElementName; LPCWSTR lpstrAlias; } alias MCI_OPEN_PARMSW* PMCI_OPEN_PARMSW, LPMCI_OPEN_PARMSW; struct MCI_PLAY_PARMS { DWORD dwCallback; DWORD dwFrom; DWORD dwTo; } alias MCI_PLAY_PARMS* PMCI_PLAY_PARMS, LPMCI_PLAY_PARMS; struct MCI_SEEK_PARMS { DWORD dwCallback; DWORD dwTo; } alias MCI_SEEK_PARMS* PMCI_SEEK_PARMS, LPMCI_SEEK_PARMS; struct MCI_STATUS_PARMS { DWORD dwCallback; DWORD dwReturn; DWORD dwItem; DWORD dwTrack; } alias MCI_STATUS_PARMS* PMCI_STATUS_PARMS, LPMCI_STATUS_PARMS; struct MCI_INFO_PARMSA { DWORD dwCallback; LPSTR lpstrReturn; DWORD dwRetSize; } alias MCI_INFO_PARMSA* LPMCI_INFO_PARMSA; struct MCI_INFO_PARMSW { DWORD dwCallback; LPWSTR lpstrReturn; DWORD dwRetSize; } alias MCI_INFO_PARMSW* LPMCI_INFO_PARMSW; struct MCI_GETDEVCAPS_PARMS { DWORD dwCallback; DWORD dwReturn; DWORD dwItem; } alias MCI_GETDEVCAPS_PARMS* PMCI_GETDEVCAPS_PARMS, LPMCI_GETDEVCAPS_PARMS; struct MCI_SYSINFO_PARMSA { DWORD dwCallback; LPSTR lpstrReturn; DWORD dwRetSize; DWORD dwNumber; UINT wDeviceType; } alias MCI_SYSINFO_PARMSA* PMCI_SYSINFO_PARMSA, LPMCI_SYSINFO_PARMSA; struct MCI_SYSINFO_PARMSW { DWORD dwCallback; LPWSTR lpstrReturn; DWORD dwRetSize; DWORD dwNumber; UINT wDeviceType; } alias MCI_SYSINFO_PARMSW* PMCI_SYSINFO_PARMSW, LPMCI_SYSINFO_PARMSW; struct MCI_SET_PARMS { DWORD dwCallback; DWORD dwTimeFormat; DWORD dwAudio; } alias MCI_SET_PARMS* PMCI_SET_PARMS, LPMCI_SET_PARMS; struct MCI_BREAK_PARMS { DWORD dwCallback; int nVirtKey; HWND hwndBreak; } alias MCI_BREAK_PARMS* PMCI_BREAK_PARMS, LPMCI_BREAK_PARMS; struct MCI_SAVE_PARMSA { DWORD dwCallback; LPCSTR lpfilename; } alias MCI_SAVE_PARMSA* PMCI_SAVE_PARMSA, LPMCI_SAVE_PARMSA; struct MCI_SAVE_PARMSW { DWORD dwCallback; LPCWSTR lpfilename; } alias MCI_SAVE_PARMSW* PMCI_SAVE_PARMSW, LPMCI_SAVE_PARMSW; struct MCI_LOAD_PARMSA { DWORD dwCallback; LPCSTR lpfilename; } alias MCI_LOAD_PARMSA* PMCI_LOAD_PARMSA, LPMCI_LOAD_PARMSA; struct MCI_LOAD_PARMSW { DWORD dwCallback; LPCWSTR lpfilename; } alias MCI_LOAD_PARMSW* PMCI_LOAD_PARMSW, LPMCI_LOAD_PARMSW; struct MCI_RECORD_PARMS { DWORD dwCallback; DWORD dwFrom; DWORD dwTo; } alias MCI_RECORD_PARMS* LPMCI_RECORD_PARMS; struct MCI_VD_PLAY_PARMS { DWORD dwCallback; DWORD dwFrom; DWORD dwTo; DWORD dwSpeed; } alias MCI_VD_PLAY_PARMS* PMCI_VD_PLAY_PARMS, LPMCI_VD_PLAY_PARMS; struct MCI_VD_STEP_PARMS { DWORD dwCallback; DWORD dwFrames; } alias MCI_VD_STEP_PARMS* PMCI_VD_STEP_PARMS, LPMCI_VD_STEP_PARMS; struct MCI_VD_ESCAPE_PARMSA { DWORD dwCallback; LPCSTR lpstrCommand; } alias MCI_VD_ESCAPE_PARMSA* PMCI_VD_ESCAPE_PARMSA, LPMCI_VD_ESCAPE_PARMSA; struct MCI_VD_ESCAPE_PARMSW { DWORD dwCallback; LPCWSTR lpstrCommand; } alias MCI_VD_ESCAPE_PARMSW* PMCI_VD_ESCAPE_PARMSW, LPMCI_VD_ESCAPE_PARMSW; struct MCI_WAVE_OPEN_PARMSA { DWORD dwCallback; MCIDEVICEID wDeviceID; LPCSTR lpstrDeviceType; LPCSTR lpstrElementName; LPCSTR lpstrAlias; DWORD dwBufferSeconds; } alias MCI_WAVE_OPEN_PARMSA* PMCI_WAVE_OPEN_PARMSA, LPMCI_WAVE_OPEN_PARMSA; struct MCI_WAVE_OPEN_PARMSW { DWORD dwCallback; MCIDEVICEID wDeviceID; LPCWSTR lpstrDeviceType; LPCWSTR lpstrElementName; LPCWSTR lpstrAlias; DWORD dwBufferSeconds; } alias MCI_WAVE_OPEN_PARMSW* PMCI_WAVE_OPEN_PARMSW, LPMCI_WAVE_OPEN_PARMSW; struct MCI_WAVE_DELETE_PARMS { DWORD dwCallback; DWORD dwFrom; DWORD dwTo; } alias MCI_WAVE_DELETE_PARMS* PMCI_WAVE_DELETE_PARMS, LPMCI_WAVE_DELETE_PARMS; struct MCI_WAVE_SET_PARMS { DWORD dwCallback; DWORD dwTimeFormat; DWORD dwAudio; UINT wInput; UINT wOutput; WORD wFormatTag; WORD wReserved2; WORD nChannels; WORD wReserved3; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; WORD wReserved4; WORD wBitsPerSample; WORD wReserved5; } alias MCI_WAVE_SET_PARMS* PMCI_WAVE_SET_PARMS, LPMCI_WAVE_SET_PARMS; extern (Windows) nothrow @nogc: LRESULT CloseDriver(HDRVR, LONG, LONG); HDRVR OpenDriver(LPCWSTR, LPCWSTR, LONG); LRESULT SendDriverMessage(HDRVR, UINT, LONG, LONG); HMODULE DrvGetModuleHandle(HDRVR); HMODULE GetDriverModuleHandle(HDRVR); LRESULT DefDriverProc(DWORD, HDRVR, UINT, LPARAM, LPARAM); UINT mmsystemGetVersion(); // FIXME: I believe this next line is a mistake //alias OutputDebugString OutputDebugStr; BOOL sndPlaySoundA(LPCSTR, UINT); BOOL sndPlaySoundW(LPCWSTR, UINT); BOOL PlaySoundA(LPCSTR, HMODULE, DWORD); BOOL PlaySoundW(LPCWSTR, HMODULE, DWORD); UINT waveOutGetNumDevs(); MMRESULT waveOutGetDevCapsA(UINT, LPWAVEOUTCAPSA, UINT); MMRESULT waveOutGetDevCapsW(UINT, LPWAVEOUTCAPSW, UINT); MMRESULT waveOutGetVolume(HWAVEOUT, PDWORD); MMRESULT waveOutSetVolume(HWAVEOUT, DWORD); MMRESULT waveOutGetErrorTextA(MMRESULT, LPSTR, UINT); MMRESULT waveOutGetErrorTextW(MMRESULT, LPWSTR, UINT); MMRESULT waveOutOpen(LPHWAVEOUT, UINT, LPCWAVEFORMATEX, DWORD, DWORD, DWORD); MMRESULT waveOutClose(HWAVEOUT); MMRESULT waveOutPrepareHeader(HWAVEOUT, LPWAVEHDR, UINT); MMRESULT waveOutUnprepareHeader(HWAVEOUT, LPWAVEHDR, UINT); MMRESULT waveOutWrite(HWAVEOUT, LPWAVEHDR, UINT); MMRESULT waveOutPause(HWAVEOUT); MMRESULT waveOutRestart(HWAVEOUT); MMRESULT waveOutReset(HWAVEOUT); MMRESULT waveOutBreakLoop(HWAVEOUT); MMRESULT waveOutGetPosition(HWAVEOUT, LPMMTIME, UINT); MMRESULT waveOutGetPitch(HWAVEOUT, PDWORD); MMRESULT waveOutSetPitch(HWAVEOUT, DWORD); MMRESULT waveOutGetPlaybackRate(HWAVEOUT, PDWORD); MMRESULT waveOutSetPlaybackRate(HWAVEOUT, DWORD); MMRESULT waveOutGetID(HWAVEOUT, LPUINT); MMRESULT waveOutMessage(HWAVEOUT, UINT, DWORD, DWORD); UINT waveInGetNumDevs(); MMRESULT waveInGetDevCapsA(UINT, LPWAVEINCAPSA, UINT); MMRESULT waveInGetDevCapsW(UINT, LPWAVEINCAPSW, UINT); MMRESULT waveInGetErrorTextA(MMRESULT, LPSTR, UINT); MMRESULT waveInGetErrorTextW(MMRESULT, LPWSTR, UINT); MMRESULT waveInOpen(LPHWAVEIN, UINT, LPCWAVEFORMATEX, DWORD, DWORD, DWORD); MMRESULT waveInClose(HWAVEIN); MMRESULT waveInPrepareHeader(HWAVEIN, LPWAVEHDR, UINT); MMRESULT waveInUnprepareHeader(HWAVEIN, LPWAVEHDR, UINT); MMRESULT waveInAddBuffer(HWAVEIN, LPWAVEHDR, UINT); MMRESULT waveInStart(HWAVEIN); MMRESULT waveInStop(HWAVEIN); MMRESULT waveInReset(HWAVEIN); MMRESULT waveInGetPosition(HWAVEIN, LPMMTIME, UINT); MMRESULT waveInGetID(HWAVEIN, LPUINT); MMRESULT waveInMessage(HWAVEIN, UINT, DWORD, DWORD); UINT midiOutGetNumDevs(); MMRESULT midiStreamOpen(LPHMIDISTRM, LPUINT, DWORD, DWORD, DWORD, DWORD); MMRESULT midiStreamClose(HMIDISTRM); MMRESULT midiStreamProperty(HMIDISTRM, LPBYTE, DWORD); MMRESULT midiStreamPosition(HMIDISTRM, LPMMTIME, UINT); MMRESULT midiStreamOut(HMIDISTRM, LPMIDIHDR, UINT); MMRESULT midiStreamPause(HMIDISTRM); MMRESULT midiStreamRestart(HMIDISTRM); MMRESULT midiStreamStop(HMIDISTRM); MMRESULT midiConnect(HMIDI, HMIDIOUT, PVOID); MMRESULT midiDisconnect(HMIDI, HMIDIOUT, PVOID); MMRESULT midiOutGetDevCapsA(UINT, LPMIDIOUTCAPSA, UINT); MMRESULT midiOutGetDevCapsW(UINT, LPMIDIOUTCAPSW, UINT); MMRESULT midiOutGetVolume(HMIDIOUT, PDWORD); MMRESULT midiOutSetVolume(HMIDIOUT, DWORD); MMRESULT midiOutGetErrorTextA(MMRESULT, LPSTR, UINT); MMRESULT midiOutGetErrorTextW(MMRESULT, LPWSTR, UINT); MMRESULT midiOutOpen(LPHMIDIOUT, UINT, DWORD, DWORD, DWORD); MMRESULT midiOutClose(HMIDIOUT); MMRESULT midiOutPrepareHeader(HMIDIOUT, LPMIDIHDR, UINT); MMRESULT midiOutUnprepareHeader(HMIDIOUT, LPMIDIHDR, UINT); MMRESULT midiOutShortMsg(HMIDIOUT, DWORD); MMRESULT midiOutLongMsg(HMIDIOUT, LPMIDIHDR, UINT); MMRESULT midiOutReset(HMIDIOUT); MMRESULT midiOutCachePatches(HMIDIOUT, UINT, LPWORD, UINT); MMRESULT midiOutCacheDrumPatches(HMIDIOUT, UINT, LPWORD, UINT); MMRESULT midiOutGetID(HMIDIOUT, LPUINT); MMRESULT midiOutMessage(HMIDIOUT, UINT, DWORD, DWORD); UINT midiInGetNumDevs(); MMRESULT midiInGetDevCapsA(UINT, LPMIDIINCAPSA, UINT); MMRESULT midiInGetDevCapsW(UINT, LPMIDIINCAPSW, UINT); MMRESULT midiInGetErrorTextA(MMRESULT, LPSTR, UINT); MMRESULT midiInGetErrorTextW(MMRESULT, LPWSTR, UINT); MMRESULT midiInOpen(LPHMIDIIN, UINT, DWORD, DWORD, DWORD); MMRESULT midiInClose(HMIDIIN); MMRESULT midiInPrepareHeader(HMIDIIN, LPMIDIHDR, UINT); MMRESULT midiInUnprepareHeader(HMIDIIN, LPMIDIHDR, UINT); MMRESULT midiInAddBuffer(HMIDIIN, LPMIDIHDR, UINT); MMRESULT midiInStart(HMIDIIN); MMRESULT midiInStop(HMIDIIN); MMRESULT midiInReset(HMIDIIN); MMRESULT midiInGetID(HMIDIIN, LPUINT); MMRESULT midiInMessage(HMIDIIN, UINT, DWORD, DWORD); UINT auxGetNumDevs(); MMRESULT auxGetDevCapsA(UINT, LPAUXCAPSA, UINT); MMRESULT auxGetDevCapsW(UINT, LPAUXCAPSW, UINT); MMRESULT auxSetVolume(UINT, DWORD); MMRESULT auxGetVolume(UINT, PDWORD); MMRESULT auxOutMessage(UINT, UINT, DWORD, DWORD); UINT mixerGetNumDevs(); MMRESULT mixerGetDevCapsA(UINT, LPMIXERCAPSA, UINT); MMRESULT mixerGetDevCapsW(UINT, LPMIXERCAPSW, UINT); MMRESULT mixerOpen(LPHMIXER, UINT, DWORD, DWORD, DWORD); MMRESULT mixerClose(HMIXER); DWORD mixerMessage(HMIXER, UINT, DWORD, DWORD); MMRESULT mixerGetLineInfoA(HMIXEROBJ, LPMIXERLINEA, DWORD); MMRESULT mixerGetLineInfoW(HMIXEROBJ, LPMIXERLINEW, DWORD); MMRESULT mixerGetID(HMIXEROBJ, PUINT, DWORD); MMRESULT mixerGetLineControlsA(HMIXEROBJ, LPMIXERLINECONTROLSA, DWORD); MMRESULT mixerGetLineControlsW(HMIXEROBJ, LPMIXERLINECONTROLSW, DWORD); MMRESULT mixerGetControlDetailsA(HMIXEROBJ, LPMIXERCONTROLDETAILS, DWORD); MMRESULT mixerGetControlDetailsW(HMIXEROBJ, LPMIXERCONTROLDETAILS, DWORD); MMRESULT mixerSetControlDetails(HMIXEROBJ, LPMIXERCONTROLDETAILS, DWORD); MMRESULT timeGetSystemTime(LPMMTIME, UINT); DWORD timeGetTime(); MMRESULT timeSetEvent(UINT, UINT, LPTIMECALLBACK, DWORD, UINT); MMRESULT timeKillEvent(UINT); MMRESULT timeGetDevCaps(LPTIMECAPS, UINT); MMRESULT timeBeginPeriod(UINT); MMRESULT timeEndPeriod(UINT); UINT joyGetNumDevs(); MMRESULT joyGetDevCapsA(UINT, LPJOYCAPSA, UINT); MMRESULT joyGetDevCapsW(UINT, LPJOYCAPSW, UINT); MMRESULT joyGetPos(UINT, LPJOYINFO); MMRESULT joyGetPosEx(UINT, LPJOYINFOEX); MMRESULT joyGetThreshold(UINT, LPUINT); MMRESULT joyReleaseCapture(UINT); MMRESULT joySetCapture(HWND, UINT, UINT, BOOL); MMRESULT joySetThreshold(UINT, UINT); FOURCC mmioStringToFOURCCA(LPCSTR, UINT); FOURCC mmioStringToFOURCCW(LPCWSTR, UINT); LPMMIOPROC mmioInstallIOProcA(FOURCC, LPMMIOPROC, DWORD); LPMMIOPROC mmioInstallIOProcW(FOURCC, LPMMIOPROC, DWORD); HMMIO mmioOpenA(LPSTR, LPMMIOINFO, DWORD); HMMIO mmioOpenW(LPWSTR, LPMMIOINFO, DWORD); MMRESULT mmioRenameA(LPCSTR, LPCSTR, LPCMMIOINFO, DWORD); MMRESULT mmioRenameW(LPCWSTR, LPCWSTR, LPCMMIOINFO, DWORD); MMRESULT mmioClose(HMMIO, UINT); LONG mmioRead(HMMIO, HPSTR, LONG); LONG mmioWrite(HMMIO, LPCSTR, LONG); LONG mmioSeek(HMMIO, LONG, int); MMRESULT mmioGetInfo(HMMIO, LPMMIOINFO, UINT); MMRESULT mmioSetInfo(HMMIO, LPCMMIOINFO, UINT); MMRESULT mmioSetBuffer(HMMIO, LPSTR, LONG, UINT); MMRESULT mmioFlush(HMMIO, UINT); MMRESULT mmioAdvance(HMMIO, LPMMIOINFO, UINT); LRESULT mmioSendMessage(HMMIO, UINT, LPARAM, LPARAM); MMRESULT mmioDescend(HMMIO, LPMMCKINFO, const(MMCKINFO)*, UINT); MMRESULT mmioAscend(HMMIO, LPMMCKINFO, UINT); MMRESULT mmioCreateChunk(HMMIO, LPMMCKINFO, UINT); MCIERROR mciSendCommandA(MCIDEVICEID, UINT, DWORD, DWORD); MCIERROR mciSendCommandW(MCIDEVICEID, UINT, DWORD, DWORD); MCIERROR mciSendStringA(LPCSTR, LPSTR, UINT, HWND); MCIERROR mciSendStringW(LPCWSTR, LPWSTR, UINT, HWND); MCIDEVICEID mciGetDeviceIDA(LPCSTR); MCIDEVICEID mciGetDeviceIDW(LPCWSTR); MCIDEVICEID mciGetDeviceIDFromElementIDA(DWORD, LPCSTR); MCIDEVICEID mciGetDeviceIDFromElementIDW(DWORD, LPCWSTR); BOOL mciGetErrorStringA(MCIERROR, LPSTR, UINT); BOOL mciGetErrorStringW(MCIERROR, LPWSTR, UINT); BOOL mciSetYieldProc(MCIDEVICEID, YIELDPROC, DWORD); HTASK mciGetCreatorTask(MCIDEVICEID); YIELDPROC mciGetYieldProc(MCIDEVICEID, PDWORD); struct MCI_SEQ_SET_PARMS { DWORD dwCallback; DWORD dwTimeFormat; DWORD dwAudio; DWORD dwTempo; DWORD dwPort; DWORD dwSlave; DWORD dwMaster; DWORD dwOffset; } alias MCI_SEQ_SET_PARMS* PMCI_SEQ_SET_PARMS, LPMCI_SEQ_SET_PARMS; struct MCI_ANIM_OPEN_PARMSA { DWORD dwCallback; MCIDEVICEID wDeviceID; LPCSTR lpstrDeviceType; LPCSTR lpstrElementName; LPCSTR lpstrAlias; DWORD dwStyle; HWND hWndParent; } alias MCI_ANIM_OPEN_PARMSA* PMCI_ANIM_OPEN_PARMSA, LPMCI_ANIM_OPEN_PARMSA; struct MCI_ANIM_OPEN_PARMSW { DWORD dwCallback; MCIDEVICEID wDeviceID; LPCWSTR lpstrDeviceType; LPCWSTR lpstrElementName; LPCWSTR lpstrAlias; DWORD dwStyle; HWND hWndParent; } alias MCI_ANIM_OPEN_PARMSW* PMCI_ANIM_OPEN_PARMSW, LPMCI_ANIM_OPEN_PARMSW; struct MCI_ANIM_PLAY_PARMS { DWORD dwCallback; DWORD dwFrom; DWORD dwTo; DWORD dwSpeed; } alias MCI_ANIM_PLAY_PARMS* PMCI_ANIM_PLAY_PARMS, LPMCI_ANIM_PLAY_PARMS; struct MCI_ANIM_STEP_PARMS { DWORD dwCallback; DWORD dwFrames; } alias MCI_ANIM_STEP_PARMS* PMCI_ANIM_STEP_PARMS, LPMCI_ANIM_STEP_PARMS; struct MCI_ANIM_WINDOW_PARMSA { DWORD dwCallback; HWND hWnd; UINT nCmdShow; LPCSTR lpstrText; } alias MCI_ANIM_WINDOW_PARMSA* PMCI_ANIM_WINDOW_PARMSA, LPMCI_ANIM_WINDOW_PARMSA; struct MCI_ANIM_WINDOW_PARMSW { DWORD dwCallback; HWND hWnd; UINT nCmdShow; LPCWSTR lpstrText; } alias MCI_ANIM_WINDOW_PARMSW* PMCI_ANIM_WINDOW_PARMSW, LPMCI_ANIM_WINDOW_PARMSW; struct MCI_ANIM_RECT_PARMS { DWORD dwCallback; //#ifdef MCI_USE_OFFEXT // POINT ptOffset; // POINT ptExtent; //#else RECT rc; //#endif } alias MCI_ANIM_RECT_PARMS* PMCI_ANIM_RECT_PARMS, LPMCI_ANIM_RECT_PARMS; struct MCI_ANIM_UPDATE_PARMS { DWORD dwCallback; RECT rc; HDC hDC; } alias MCI_ANIM_UPDATE_PARMS* PMCI_ANIM_UPDATE_PARMS, LPMCI_ANIM_UPDATE_PARMS; struct MCI_OVLY_OPEN_PARMSA { DWORD dwCallback; MCIDEVICEID wDeviceID; LPCSTR lpstrDeviceType; LPCSTR lpstrElementName; LPCSTR lpstrAlias; DWORD dwStyle; HWND hWndParent; } alias MCI_OVLY_OPEN_PARMSA* PMCI_OVLY_OPEN_PARMSA, LPMCI_OVLY_OPEN_PARMSA; struct MCI_OVLY_OPEN_PARMSW { DWORD dwCallback; MCIDEVICEID wDeviceID; LPCWSTR lpstrDeviceType; LPCWSTR lpstrElementName; LPCWSTR lpstrAlias; DWORD dwStyle; HWND hWndParent; } alias MCI_OVLY_OPEN_PARMSW* PMCI_OVLY_OPEN_PARMSW, LPMCI_OVLY_OPEN_PARMSW; struct MCI_OVLY_WINDOW_PARMSA { DWORD dwCallback; HWND hWnd; UINT nCmdShow; LPCSTR lpstrText; } alias MCI_OVLY_WINDOW_PARMSA* PMCI_OVLY_WINDOW_PARMSA, LPMCI_OVLY_WINDOW_PARMSA; struct MCI_OVLY_WINDOW_PARMSW { DWORD dwCallback; HWND hWnd; UINT nCmdShow; LPCWSTR lpstrText; } alias MCI_OVLY_WINDOW_PARMSW* PMCI_OVLY_WINDOW_PARMSW, LPMCI_OVLY_WINDOW_PARMSW; struct MCI_OVLY_RECT_PARMS { DWORD dwCallback; //#ifdef MCI_USE_OFFEXT // POINT ptOffset; // POINT ptExtent; //#else RECT rc; //#endif } alias MCI_OVLY_RECT_PARMS* PMCI_OVLY_RECT_PARMS, LPMCI_OVLY_RECT_PARMS; struct MCI_OVLY_SAVE_PARMSA { DWORD dwCallback; LPCSTR lpfilename; RECT rc; } alias MCI_OVLY_SAVE_PARMSA* PMCI_OVLY_SAVE_PARMSA, LPMCI_OVLY_SAVE_PARMSA; struct MCI_OVLY_SAVE_PARMSW { DWORD dwCallback; LPCWSTR lpfilename; RECT rc; } alias MCI_OVLY_SAVE_PARMSW* PMCI_OVLY_SAVE_PARMSW, LPMCI_OVLY_SAVE_PARMSW; struct MCI_OVLY_LOAD_PARMSA { DWORD dwCallback; LPCSTR lpfilename; RECT rc; } alias MCI_OVLY_LOAD_PARMSA* PMCI_OVLY_LOAD_PARMSA, LPMCI_OVLY_LOAD_PARMSA; struct MCI_OVLY_LOAD_PARMSW { DWORD dwCallback; LPCWSTR lpfilename; RECT rc; } alias MCI_OVLY_LOAD_PARMSW* PMCI_OVLY_LOAD_PARMSW, LPMCI_OVLY_LOAD_PARMSW; version(Unicode) { alias WAVEOUTCAPSW WAVEOUTCAPS; alias WAVEINCAPSW WAVEINCAPS; alias MIDIOUTCAPSW MIDIOUTCAPS; alias MIDIINCAPSW MIDIINCAPS; alias AUXCAPSW AUXCAPS; alias MIXERCAPSW MIXERCAPS; alias MIXERLINEW MIXERLINE; alias MIXERCONTROLA MIXERCONTROL; alias MIXERLINECONTROLSW MIXERLINECONTROLS; alias MIXERCONTROLDETAILS_LISTTEXTW MIXERCONTROLDETAILS_LISTTEXT; alias JOYCAPSW JOYCAPS; alias MCI_OPEN_PARMSW MCI_OPEN_PARMS; alias MCI_INFO_PARMSW MCI_INFO_PARMS; alias MCI_SYSINFO_PARMSW MCI_SYSINFO_PARMS; alias MCI_SAVE_PARMSW MCI_SAVE_PARMS; alias MCI_LOAD_PARMSW MCI_LOAD_PARMS; alias MCI_VD_ESCAPE_PARMSW MCI_VD_ESCAPE_PARMS; alias MCI_WAVE_OPEN_PARMSW MCI_WAVE_OPEN_PARMS; alias MCI_ANIM_OPEN_PARMSW MCI_ANIM_OPEN_PARMS; alias MCI_ANIM_WINDOW_PARMSW MCI_ANIM_WINDOW_PARMS; alias MCI_OVLY_OPEN_PARMSW MCI_OVLY_OPEN_PARMS; alias MCI_OVLY_WINDOW_PARMSW MCI_OVLY_WINDOW_PARMS; alias MCI_OVLY_SAVE_PARMSW MCI_OVLY_SAVE_PARMS; alias sndPlaySoundW sndPlaySound; alias PlaySoundW PlaySound; alias waveOutGetDevCapsW waveOutGetDevCaps; alias waveOutGetErrorTextW waveOutGetErrorText; alias waveInGetDevCapsW waveInGetDevCaps; alias waveInGetErrorTextW waveInGetErrorText; alias midiOutGetDevCapsW midiOutGetDevCaps; alias midiOutGetErrorTextW midiOutGetErrorText; alias midiInGetDevCapsW midiInGetDevCaps; alias midiInGetErrorTextW midiInGetErrorText; alias auxGetDevCapsW auxGetDevCaps; alias mixerGetDevCapsW mixerGetDevCaps; alias mixerGetLineInfoW mixerGetLineInfo; alias mixerGetLineControlsW mixerGetLineControls; alias mixerGetControlDetailsW mixerGetControlDetails; alias joyGetDevCapsW joyGetDevCaps; alias mmioInstallIOProcW mmioInstallIOProc; alias mmioStringToFOURCCW mmioStringToFOURCC; alias mmioOpenW mmioOpen; alias mmioRenameW mmioRename; alias mciSendCommandW mciSendCommand; alias mciSendStringW mciSendString; alias mciGetDeviceIDW mciGetDeviceID; alias mciGetDeviceIDFromElementIDW mciGetDeviceIDFromElementID; alias mciGetErrorStringW mciGetErrorString; } else { alias WAVEOUTCAPSA WAVEOUTCAPS; alias WAVEINCAPSA WAVEINCAPS; alias MIDIOUTCAPSA MIDIOUTCAPS; alias MIDIINCAPSA MIDIINCAPS; alias AUXCAPSA AUXCAPS; alias MIXERCAPSA MIXERCAPS; alias MIXERLINEA MIXERLINE; alias MIXERCONTROLA MIXERCONTROL; alias MIXERLINECONTROLSA MIXERLINECONTROLS; alias MIXERCONTROLDETAILS_LISTTEXTA MIXERCONTROLDETAILS_LISTTEXT; alias JOYCAPSA JOYCAPS; alias MCI_OPEN_PARMSA MCI_OPEN_PARMS; alias MCI_INFO_PARMSA MCI_INFO_PARMS; alias MCI_SYSINFO_PARMSA MCI_SYSINFO_PARMS; alias MCI_SAVE_PARMSA MCI_SAVE_PARMS; alias MCI_LOAD_PARMSA MCI_LOAD_PARMS; alias MCI_VD_ESCAPE_PARMSA MCI_VD_ESCAPE_PARMS; alias MCI_WAVE_OPEN_PARMSA MCI_WAVE_OPEN_PARMS; alias MCI_ANIM_OPEN_PARMSA MCI_ANIM_OPEN_PARMS; alias MCI_ANIM_WINDOW_PARMSA MCI_ANIM_WINDOW_PARMS; alias MCI_OVLY_OPEN_PARMSA MCI_OVLY_OPEN_PARMS; alias MCI_OVLY_WINDOW_PARMSA MCI_OVLY_WINDOW_PARMS; alias MCI_OVLY_SAVE_PARMSA MCI_OVLY_SAVE_PARMS; alias sndPlaySoundA sndPlaySound; alias PlaySoundA PlaySound; alias waveOutGetDevCapsA waveOutGetDevCaps; alias waveOutGetErrorTextA waveOutGetErrorText; alias waveInGetDevCapsA waveInGetDevCaps; alias waveInGetErrorTextA waveInGetErrorText; alias midiOutGetDevCapsA midiOutGetDevCaps; alias midiOutGetErrorTextA midiOutGetErrorText; alias midiInGetDevCapsA midiInGetDevCaps; alias midiInGetErrorTextA midiInGetErrorText; alias auxGetDevCapsA auxGetDevCaps; alias mixerGetDevCapsA mixerGetDevCaps; alias mixerGetLineInfoA mixerGetLineInfo; alias mixerGetLineControlsA mixerGetLineControls; alias mixerGetControlDetailsA mixerGetControlDetails; alias joyGetDevCapsA joyGetDevCaps; alias mmioInstallIOProcA mmioInstallIOProc; alias mmioStringToFOURCCA mmioStringToFOURCC; alias mmioOpenA mmioOpen; alias mmioRenameA mmioRename; alias mciSendCommandA mciSendCommand; alias mciSendStringA mciSendString; alias mciGetDeviceIDA mciGetDeviceID; alias mciGetDeviceIDFromElementIDA mciGetDeviceIDFromElementID; alias mciGetErrorStringA mciGetErrorString; } alias WAVEOUTCAPS* PWAVEOUTCAPS, LPWAVEOUTCAPS; alias WAVEINCAPS* PWAVEINCAPS, LPWAVEINCAPS; alias MIDIOUTCAPS* PMIDIOUTCAPS, LPMIDIOUTCAPS; alias MIDIINCAPS* PMIDIINCAPS, LPMIDIINCAPS; alias AUXCAPS* PAUXCAPS, LPAUXCAPS; alias MIXERCAPS* PMIXERCAPS, LPMIXERCAPS; alias MIXERLINE* PMIXERLINE, LPMIXERLINE; alias MIXERCONTROL* PMIXERCONTROL, LPMIXERCONTROL; alias MIXERLINECONTROLS* PMIXERLINECONTROLS, LPMIXERLINECONTROLS; alias MIXERCONTROLDETAILS_LISTTEXT* PMIXERCONTROLDETAILS_LISTTEXT, LPMIXERCONTROLDETAILS_LISTTEXT; alias JOYCAPS* PJOYCAPS, LPJOYCAPS; alias MCI_OPEN_PARMS* PMCI_OPEN_PARMS, LPMCI_OPEN_PARMS; alias MCI_INFO_PARMS* LPMCI_INFO_PARMS; alias MCI_SYSINFO_PARMS* PMCI_SYSINFO_PARMS, LPMCI_SYSINFO_PARMS; alias MCI_SAVE_PARMS* PMCI_SAVE_PARMS, LPMCI_SAVE_PARMS; alias MCI_LOAD_PARMS* PMCI_LOAD_PARMS, LPMCI_LOAD_PARMS; alias MCI_VD_ESCAPE_PARMS* PMCI_VD_ESCAPE_PARMS, LPMCI_VD_ESCAPE_PARMS; alias MCI_WAVE_OPEN_PARMS* PMCI_WAVE_OPEN_PARMS, LPMCI_WAVE_OPEN_PARMS; alias MCI_ANIM_OPEN_PARMS* PMCI_ANIM_OPEN_PARMS, LPMCI_ANIM_OPEN_PARMS; alias MCI_ANIM_WINDOW_PARMS* PMCI_ANIM_WINDOW_PARMS, LPMCI_ANIM_WINDOW_PARMS; alias MCI_OVLY_OPEN_PARMS* PMCI_OVLY_OPEN_PARMS, LPMCI_OVLY_OPEN_PARMS; alias MCI_OVLY_WINDOW_PARMS* PMCI_OVLY_WINDOW_PARMS, LPMCI_OVLY_WINDOW_PARMS; alias MCI_OVLY_SAVE_PARMS* PMCI_OVLY_SAVE_PARMS, LPMCI_OVLY_SAVE_PARMS; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ole2.d0000664000175000017500000001266712776214756022534 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ole2.d) */ module core.sys.windows.ole2; version (Windows): pragma(lib, "ole32"); public import core.sys.windows.basetyps, core.sys.windows.objbase, core.sys.windows.oleauto, core.sys.windows.olectlid, core.sys.windows.oleidl, core.sys.windows.unknwn, core.sys.windows.winerror, core.sys.windows.uuid; private import core.sys.windows.objfwd, core.sys.windows.objidl, core.sys.windows.windef, core.sys.windows.wtypes; private import core.sys.windows.winuser; // for LPMSG enum E_DRAW = VIEW_E_DRAW; enum DATA_E_FORMATETC = DV_E_FORMATETC; enum { OLEIVERB_PRIMARY = 0, OLEIVERB_SHOW = -1, OLEIVERB_OPEN = -2, OLEIVERB_HIDE = -3, OLEIVERB_UIACTIVATE = -4, OLEIVERB_INPLACEACTIVATE = -5, OLEIVERB_DISCARDUNDOSTATE = -6 } enum EMBDHLP_INPROC_HANDLER = 0x0000L; enum EMBDHLP_INPROC_SERVER = 0x0001L; enum EMBDHLP_CREATENOW = 0x00000000L; enum EMBDHLP_DELAYCREATE = 0x00010000L; align(8): struct OLESTREAM { LPOLESTREAMVTBL lpstbl; } alias OLESTREAM* LPOLESTREAM; extern (Windows) { struct OLESTREAMVTBL { DWORD function (LPOLESTREAM, void*, DWORD) Get; DWORD function (LPOLESTREAM, const(void)*, DWORD) Put; } } alias OLESTREAMVTBL* LPOLESTREAMVTBL; extern (Windows) { HRESULT CreateDataAdviseHolder(LPDATAADVISEHOLDER*); DWORD OleBuildVersion(); HRESULT ReadClassStg(LPSTORAGE, CLSID*); HRESULT WriteClassStg(LPSTORAGE, REFCLSID); HRESULT ReadClassStm(LPSTREAM, CLSID*); HRESULT WriteClassStm(LPSTREAM, REFCLSID); HRESULT WriteFmtUserTypeStg(LPSTORAGE, CLIPFORMAT, LPOLESTR); HRESULT ReadFmtUserTypeStg(LPSTORAGE, CLIPFORMAT*, LPOLESTR*); HRESULT OleInitialize(PVOID); void OleUninitialize(); HRESULT OleQueryLinkFromData(LPDATAOBJECT); HRESULT OleQueryCreateFromData(LPDATAOBJECT); HRESULT OleCreate(REFCLSID, REFIID, DWORD, LPFORMATETC, LPOLECLIENTSITE, LPSTORAGE, PVOID*); HRESULT OleCreateFromData(LPDATAOBJECT, REFIID, DWORD, LPFORMATETC, LPOLECLIENTSITE, LPSTORAGE, PVOID*); HRESULT OleCreateLinkFromData(LPDATAOBJECT, REFIID, DWORD, LPFORMATETC, LPOLECLIENTSITE, LPSTORAGE, PVOID*); HRESULT OleCreateStaticFromData(LPDATAOBJECT, REFIID, DWORD, LPFORMATETC, LPOLECLIENTSITE, LPSTORAGE, PVOID*); HRESULT OleCreateLink(LPMONIKER, REFIID, DWORD, LPFORMATETC, LPOLECLIENTSITE, LPSTORAGE, PVOID*); HRESULT OleCreateLinkToFile(LPCOLESTR, REFIID, DWORD, LPFORMATETC, LPOLECLIENTSITE, LPSTORAGE, PVOID*); HRESULT OleCreateFromFile(REFCLSID, LPCOLESTR, REFIID, DWORD, LPFORMATETC, LPOLECLIENTSITE, LPSTORAGE, PVOID*); HRESULT OleLoad(LPSTORAGE, REFIID, LPOLECLIENTSITE, PVOID*); HRESULT OleSave(LPPERSISTSTORAGE, LPSTORAGE, BOOL); HRESULT OleLoadFromStream(LPSTREAM, REFIID, PVOID*); HRESULT OleSaveToStream(LPPERSISTSTREAM, LPSTREAM); HRESULT OleSetContainedObject(LPUNKNOWN, BOOL); HRESULT OleNoteObjectVisible(LPUNKNOWN, BOOL); HRESULT RegisterDragDrop(HWND, LPDROPTARGET); HRESULT RevokeDragDrop(HWND); HRESULT DoDragDrop(LPDATAOBJECT, LPDROPSOURCE, DWORD, PDWORD); HRESULT OleSetClipboard(LPDATAOBJECT); HRESULT OleGetClipboard(LPDATAOBJECT*); HRESULT OleFlushClipboard(); HRESULT OleIsCurrentClipboard(LPDATAOBJECT); HOLEMENU OleCreateMenuDescriptor(HMENU, LPOLEMENUGROUPWIDTHS); HRESULT OleSetMenuDescriptor(HOLEMENU, HWND, HWND, LPOLEINPLACEFRAME, LPOLEINPLACEACTIVEOBJECT); HRESULT OleDestroyMenuDescriptor(HOLEMENU); HRESULT OleTranslateAccelerator(LPOLEINPLACEFRAME, LPOLEINPLACEFRAMEINFO, LPMSG); HANDLE OleDuplicateData(HANDLE, CLIPFORMAT, UINT); HRESULT OleDraw(LPUNKNOWN, DWORD, HDC, LPCRECT); HRESULT OleRun(LPUNKNOWN); BOOL OleIsRunning(LPOLEOBJECT); HRESULT OleLockRunning(LPUNKNOWN, BOOL, BOOL); void ReleaseStgMedium(LPSTGMEDIUM); HRESULT CreateOleAdviseHolder(LPOLEADVISEHOLDER*); HRESULT OleCreateDefaultHandler(REFCLSID, LPUNKNOWN, REFIID, PVOID*); HRESULT OleCreateEmbeddingHelper(REFCLSID, LPUNKNOWN, DWORD, LPCLASSFACTORY, REFIID, PVOID*); BOOL IsAccelerator(HACCEL, int, LPMSG, WORD*); HGLOBAL OleGetIconOfFile(LPOLESTR, BOOL); HGLOBAL OleGetIconOfClass(REFCLSID, LPOLESTR, BOOL); HGLOBAL OleMetafilePictFromIconAndLabel(HICON, LPOLESTR, LPOLESTR, UINT); HRESULT OleRegGetUserType(REFCLSID, DWORD, LPOLESTR*); HRESULT OleRegGetMiscStatus(REFCLSID, DWORD, DWORD*); HRESULT OleRegEnumFormatEtc (REFCLSID, DWORD, LPENUMFORMATETC*); HRESULT OleRegEnumVerbs (REFCLSID, LPENUMOLEVERB*); HRESULT OleConvertOLESTREAMToIStorage(LPOLESTREAM, LPSTORAGE, const(DVTARGETDEVICE)*); HRESULT OleConvertIStorageToOLESTREAM(LPSTORAGE, LPOLESTREAM); HRESULT GetHGlobalFromILockBytes(LPLOCKBYTES, HGLOBAL*); HRESULT CreateILockBytesOnHGlobal(HGLOBAL, BOOL, LPLOCKBYTES*); HRESULT GetHGlobalFromStream(LPSTREAM, HGLOBAL*); HRESULT CreateStreamOnHGlobal(HGLOBAL, BOOL, LPSTREAM*); HRESULT OleDoAutoConvert(LPSTORAGE, LPCLSID); HRESULT OleGetAutoConvert(REFCLSID, LPCLSID); HRESULT OleSetAutoConvert(REFCLSID, REFCLSID); HRESULT GetConvertStg(LPSTORAGE); HRESULT SetConvertStg(LPSTORAGE, BOOL); HRESULT OleConvertIStorageToOLESTREAMEx(LPSTORAGE, CLIPFORMAT, LONG, LONG, DWORD, LPSTGMEDIUM, LPOLESTREAM); HRESULT OleConvertOLESTREAMToIStorageEx(LPOLESTREAM, LPSTORAGE, CLIPFORMAT*, LONG*, LONG*, DWORD*, LPSTGMEDIUM); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/oledlg.d0000664000175000017500000007266612776214756023146 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_oledlg.d) */ module core.sys.windows.oledlg; version (Windows): version (ANSI) {} else version = Unicode; import core.sys.windows.commdlg, core.sys.windows.dlgs, core.sys.windows.ole2, core.sys.windows.prsht, core.sys.windows.shellapi, core.sys.windows.windows; private import core.sys.windows.winbase, core.sys.windows.objidl, core.sys.windows.objfwd, core.sys.windows.winnt; // FIXME: remove inherited methods from interface definitions enum PS_MAXLINKTYPES=8; const TCHAR[] OLESTDDELIM = "\\"; const TCHAR[] SZOLEUI_MSG_HELP = "OLEUI_MSG_HELP"; const TCHAR[] SZOLEUI_MSG_ENDDIALOG = "OLEUI_MSG_ENDDIALOG"; const TCHAR[] SZOLEUI_MSG_BROWSE = "OLEUI_MSG_BROWSE"; const TCHAR[] SZOLEUI_MSG_CHANGEICON = "OLEUI_MSG_CHANGEICON"; const TCHAR[] SZOLEUI_MSG_CLOSEBUSYDIALOG = "OLEUI_MSG_CLOSEBUSYDIALOG"; const TCHAR[] SZOLEUI_MSG_CONVERT = "OLEUI_MSG_CONVERT"; const TCHAR[] SZOLEUI_MSG_CHANGESOURCE = "OLEUI_MSG_CHANGESOURCE"; const TCHAR[] SZOLEUI_MSG_ADDCONTROL = "OLEUI_MSG_ADDCONTROL"; const TCHAR[] SZOLEUI_MSG_BROWSE_OFN = "OLEUI_MSG_BROWSE_OFN"; const TCHAR[] PROP_HWND_CHGICONDLG = "HWND_CIDLG"; enum IDC_OLEUIHELP=99; enum { IDC_IO_CREATENEW = 2100, IDC_IO_CREATEFROMFILE, IDC_IO_LINKFILE, IDC_IO_OBJECTTYPELIST, IDC_IO_DISPLAYASICON, IDC_IO_CHANGEICON, IDC_IO_FILE, IDC_IO_FILEDISPLAY, IDC_IO_RESULTIMAGE, IDC_IO_RESULTTEXT, IDC_IO_ICONDISPLAY, IDC_IO_OBJECTTYPETEXT, IDC_IO_FILETEXT, IDC_IO_FILETYPE, IDC_IO_INSERTCONTROL, IDC_IO_ADDCONTROL, IDC_IO_CONTROLTYPELIST // = 2116 } enum IDC_PS_PASTE=500; enum IDC_PS_PASTELINK=501; enum IDC_PS_SOURCETEXT=502; enum IDC_PS_PASTELIST=503; enum IDC_PS_PASTELINKLIST=504; enum IDC_PS_DISPLAYLIST=505; enum IDC_PS_DISPLAYASICON=506; enum IDC_PS_ICONDISPLAY=507; enum IDC_PS_CHANGEICON=508; enum IDC_PS_RESULTIMAGE=509; enum IDC_PS_RESULTTEXT=510; enum IDC_CI_GROUP=120; enum IDC_CI_CURRENT=121; enum IDC_CI_CURRENTICON=122; enum IDC_CI_DEFAULT=123; enum IDC_CI_DEFAULTICON=124; enum IDC_CI_FROMFILE=125; enum IDC_CI_FROMFILEEDIT=126; enum IDC_CI_ICONLIST=127; enum IDC_CI_LABEL=128; enum IDC_CI_LABELEDIT=129; enum IDC_CI_BROWSE=130; enum IDC_CI_ICONDISPLAY=131; enum IDC_CV_OBJECTTYPE=150; enum IDC_CV_DISPLAYASICON=152; enum IDC_CV_CHANGEICON=153; enum IDC_CV_ACTIVATELIST=154; enum IDC_CV_CONVERTTO=155; enum IDC_CV_ACTIVATEAS=156; enum IDC_CV_RESULTTEXT=157; enum IDC_CV_CONVERTLIST=158; enum IDC_CV_ICONDISPLAY=165; enum IDC_EL_CHANGESOURCE=201; enum IDC_EL_AUTOMATIC=202; enum IDC_EL_CANCELLINK=209; enum IDC_EL_UPDATENOW=210; enum IDC_EL_OPENSOURCE=211; enum IDC_EL_MANUAL=212; enum IDC_EL_LINKSOURCE=216; enum IDC_EL_LINKTYPE=217; enum IDC_EL_LINKSLISTBOX=206; enum IDC_EL_COL1=220; enum IDC_EL_COL2=221; enum IDC_EL_COL3=222; enum IDC_BZ_RETRY=600; enum IDC_BZ_ICON=601; enum IDC_BZ_MESSAGE1=602; enum IDC_BZ_SWITCHTO=604; enum IDC_UL_METER=1029; enum IDC_UL_STOP=1030; enum IDC_UL_PERCENT=1031; enum IDC_UL_PROGRESS=1032; enum IDC_PU_LINKS=900; enum IDC_PU_TEXT=901; enum IDC_PU_CONVERT=902; enum IDC_PU_ICON=908; enum IDC_GP_OBJECTNAME=1009; enum IDC_GP_OBJECTTYPE=1010; enum IDC_GP_OBJECTSIZE=1011; enum IDC_GP_CONVERT=1013; enum IDC_GP_OBJECTICON=1014; enum IDC_GP_OBJECTLOCATION=1022; enum IDC_VP_PERCENT=1000; enum IDC_VP_CHANGEICON=1001; enum IDC_VP_EDITABLE=1002; enum IDC_VP_ASICON=1003; enum IDC_VP_RELATIVE=1005; enum IDC_VP_SPIN=1006; enum IDC_VP_SCALETXT=1034; enum IDC_VP_ICONDISPLAY=1021; enum IDC_VP_RESULTIMAGE=1033; enum IDC_LP_OPENSOURCE=1006; enum IDC_LP_UPDATENOW=1007; enum IDC_LP_BREAKLINK=1008; enum IDC_LP_LINKSOURCE=1012; enum IDC_LP_CHANGESOURCE=1015; enum IDC_LP_AUTOMATIC=1016; enum IDC_LP_MANUAL=1017; enum IDC_LP_DATE=1018; enum IDC_LP_TIME=1019; enum IDD_INSERTOBJECT=1000; enum IDD_CHANGEICON=1001; enum IDD_CONVERT=1002; enum IDD_PASTESPECIAL=1003; enum IDD_EDITLINKS=1004; enum IDD_BUSY=1006; enum IDD_UPDATELINKS=1007; enum IDD_CHANGESOURCE=1009; enum IDD_INSERTFILEBROWSE=1010; enum IDD_CHANGEICONBROWSE=1011; enum IDD_CONVERTONLY=1012; enum IDD_CHANGESOURCE4=1013; enum IDD_GNRLPROPS=1100; enum IDD_VIEWPROPS=1101; enum IDD_LINKPROPS=1102; enum IDD_CANNOTUPDATELINK=1008; enum IDD_LINKSOURCEUNAVAILABLE=1020; enum IDD_SERVERNOTFOUND=1023; enum IDD_OUTOFMEMORY=1024; enum IDD_SERVERNOTREGW=1021; enum IDD_LINKTYPECHANGEDW=1022; enum IDD_SERVERNOTREGA=1025; enum IDD_LINKTYPECHANGEDA=1026; enum ID_BROWSE_CHANGEICON=1; enum ID_BROWSE_INSERTFILE=2; enum ID_BROWSE_ADDCONTROL=3; enum ID_BROWSE_CHANGESOURCE=4; enum OLEUI_FALSE=0; enum OLEUI_SUCCESS=1; enum OLEUI_OK=1; enum OLEUI_CANCEL=2; enum OLEUI_ERR_STANDARDMIN=100; enum OLEUI_ERR_STRUCTURENULL=101; enum OLEUI_ERR_STRUCTUREINVALID=102; enum OLEUI_ERR_CBSTRUCTINCORRECT=103; enum OLEUI_ERR_HWNDOWNERINVALID=104; enum OLEUI_ERR_LPSZCAPTIONINVALID=105; enum OLEUI_ERR_LPFNHOOKINVALID=106; enum OLEUI_ERR_HINSTANCEINVALID=107; enum OLEUI_ERR_LPSZTEMPLATEINVALID=108; enum OLEUI_ERR_HRESOURCEINVALID=109; enum OLEUI_ERR_FINDTEMPLATEFAILURE=110; enum OLEUI_ERR_LOADTEMPLATEFAILURE=111; enum OLEUI_ERR_DIALOGFAILURE=112; enum OLEUI_ERR_LOCALMEMALLOC=113; enum OLEUI_ERR_GLOBALMEMALLOC=114; enum OLEUI_ERR_LOADSTRING=115; enum OLEUI_ERR_OLEMEMALLOC=116; enum OLEUI_ERR_STANDARDMAX=116; enum OPF_OBJECTISLINK=1; enum OPF_NOFILLDEFAULT=2; enum OPF_SHOWHELP=4; enum OPF_DISABLECONVERT=8; enum OLEUI_OPERR_SUBPROPNULL=OLEUI_ERR_STANDARDMAX; enum OLEUI_OPERR_SUBPROPINVALID=(OLEUI_ERR_STANDARDMAX+1); enum OLEUI_OPERR_PROPSHEETNULL=(OLEUI_ERR_STANDARDMAX+2); enum OLEUI_OPERR_PROPSHEETINVALID=(OLEUI_ERR_STANDARDMAX+3); enum OLEUI_OPERR_SUPPROP=(OLEUI_ERR_STANDARDMAX+4); enum OLEUI_OPERR_PROPSINVALID=(OLEUI_ERR_STANDARDMAX+5); enum OLEUI_OPERR_PAGESINCORRECT=(OLEUI_ERR_STANDARDMAX+6); enum OLEUI_OPERR_INVALIDPAGES=(OLEUI_ERR_STANDARDMAX+7); enum OLEUI_OPERR_NOTSUPPORTED=(OLEUI_ERR_STANDARDMAX+8); enum OLEUI_OPERR_DLGPROCNOTNULL=(OLEUI_ERR_STANDARDMAX+9); enum OLEUI_OPERR_LPARAMNOTZERO=(OLEUI_ERR_STANDARDMAX+10); enum OLEUI_GPERR_STRINGINVALID=(OLEUI_ERR_STANDARDMAX+11); enum OLEUI_GPERR_CLASSIDINVALID=(OLEUI_ERR_STANDARDMAX+12); enum OLEUI_GPERR_LPCLSIDEXCLUDEINVALID=(OLEUI_ERR_STANDARDMAX+13); enum OLEUI_GPERR_CBFORMATINVALID=(OLEUI_ERR_STANDARDMAX+14); enum OLEUI_VPERR_METAPICTINVALID=(OLEUI_ERR_STANDARDMAX+15); enum OLEUI_VPERR_DVASPECTINVALID=(OLEUI_ERR_STANDARDMAX+16); enum OLEUI_LPERR_LINKCNTRNULL=(OLEUI_ERR_STANDARDMAX+17); enum OLEUI_LPERR_LINKCNTRINVALID=(OLEUI_ERR_STANDARDMAX+18); enum OLEUI_OPERR_PROPERTYSHEET=(OLEUI_ERR_STANDARDMAX+19); enum OLEUI_OPERR_OBJINFOINVALID=(OLEUI_ERR_STANDARDMAX+20); enum OLEUI_OPERR_LINKINFOINVALID=(OLEUI_ERR_STANDARDMAX+21); enum OLEUI_QUERY_GETCLASSID=65280; enum OLEUI_QUERY_LINKBROKEN=65281; enum IOF_SHOWHELP=1; enum IOF_SELECTCREATENEW=2; enum IOF_SELECTCREATEFROMFILE=4; enum IOF_CHECKLINK=8; enum IOF_CHECKDISPLAYASICON=16; enum IOF_CREATENEWOBJECT=32; enum IOF_CREATEFILEOBJECT=64; enum IOF_CREATELINKOBJECT=128; enum IOF_DISABLELINK=256; enum IOF_VERIFYSERVERSEXIST=512; enum IOF_DISABLEDISPLAYASICON=1024; enum IOF_HIDECHANGEICON=2048; enum IOF_SHOWINSERTCONTROL=4096; enum IOF_SELECTCREATECONTROL=8192; enum OLEUI_IOERR_LPSZFILEINVALID=OLEUI_ERR_STANDARDMAX; enum OLEUI_IOERR_LPSZLABELINVALID=(OLEUI_ERR_STANDARDMAX+1); enum OLEUI_IOERR_HICONINVALID=(OLEUI_ERR_STANDARDMAX+2); enum OLEUI_IOERR_LPFORMATETCINVALID=(OLEUI_ERR_STANDARDMAX+3); enum OLEUI_IOERR_PPVOBJINVALID=(OLEUI_ERR_STANDARDMAX+4); enum OLEUI_IOERR_LPIOLECLIENTSITEINVALID=(OLEUI_ERR_STANDARDMAX+5); enum OLEUI_IOERR_LPISTORAGEINVALID=(OLEUI_ERR_STANDARDMAX+6); enum OLEUI_IOERR_SCODEHASERROR=(OLEUI_ERR_STANDARDMAX+7); enum OLEUI_IOERR_LPCLSIDEXCLUDEINVALID=(OLEUI_ERR_STANDARDMAX+8); enum OLEUI_IOERR_CCHFILEINVALID=(OLEUI_ERR_STANDARDMAX+9); enum PSF_SHOWHELP=1; enum PSF_SELECTPASTE=2; enum PSF_SELECTPASTELINK=4; enum PSF_CHECKDISPLAYASICON=8; enum PSF_DISABLEDISPLAYASICON=16; enum PSF_HIDECHANGEICON=32; enum PSF_STAYONCLIPBOARDCHANGE=64; enum PSF_NOREFRESHDATAOBJECT=128; enum OLEUI_IOERR_SRCDATAOBJECTINVALID=OLEUI_ERR_STANDARDMAX; enum OLEUI_IOERR_ARRPASTEENTRIESINVALID=(OLEUI_ERR_STANDARDMAX+1); enum OLEUI_IOERR_ARRLINKTYPESINVALID=(OLEUI_ERR_STANDARDMAX+2); enum OLEUI_PSERR_CLIPBOARDCHANGED=(OLEUI_ERR_STANDARDMAX+3); enum OLEUI_PSERR_GETCLIPBOARDFAILED=(OLEUI_ERR_STANDARDMAX+4); enum OLEUI_ELERR_LINKCNTRNULL=OLEUI_ERR_STANDARDMAX; enum OLEUI_ELERR_LINKCNTRINVALID=(OLEUI_ERR_STANDARDMAX+1); enum ELF_SHOWHELP=1; enum ELF_DISABLEUPDATENOW=2; enum ELF_DISABLEOPENSOURCE=4; enum ELF_DISABLECHANGESOURCE=8; enum ELF_DISABLECANCELLINK=16; enum CIF_SHOWHELP=1; enum CIF_SELECTCURRENT=2; enum CIF_SELECTDEFAULT=4; enum CIF_SELECTFROMFILE=8; enum CIF_USEICONEXE=16; enum OLEUI_CIERR_MUSTHAVECLSID=OLEUI_ERR_STANDARDMAX; enum OLEUI_CIERR_MUSTHAVECURRENTMETAFILE=OLEUI_ERR_STANDARDMAX+1; enum OLEUI_CIERR_SZICONEXEINVALID=OLEUI_ERR_STANDARDMAX+2; enum CF_SHOWHELPBUTTON=1; enum CF_SETCONVERTDEFAULT=2; enum CF_SETACTIVATEDEFAULT=4; enum CF_SELECTCONVERTTO=8; enum CF_SELECTACTIVATEAS=16; enum CF_DISABLEDISPLAYASICON=32; enum CF_DISABLEACTIVATEAS=64; enum CF_HIDECHANGEICON=128; enum CF_CONVERTONLY=256; enum OLEUI_CTERR_CLASSIDINVALID = OLEUI_ERR_STANDARDMAX+1; enum OLEUI_CTERR_DVASPECTINVALID = OLEUI_ERR_STANDARDMAX+2; enum OLEUI_CTERR_CBFORMATINVALID = OLEUI_ERR_STANDARDMAX+3; enum OLEUI_CTERR_HMETAPICTINVALID = OLEUI_ERR_STANDARDMAX+4; enum OLEUI_CTERR_STRINGINVALID = OLEUI_ERR_STANDARDMAX+5; enum BZ_DISABLECANCELBUTTON = 1; enum BZ_DISABLESWITCHTOBUTTON = 2; enum BZ_DISABLERETRYBUTTON = 4; enum BZ_NOTRESPONDINGDIALOG = 8; enum OLEUI_BZERR_HTASKINVALID = OLEUI_ERR_STANDARDMAX; enum OLEUI_BZ_SWITCHTOSELECTED = OLEUI_ERR_STANDARDMAX+1; enum OLEUI_BZ_RETRYSELECTED = OLEUI_ERR_STANDARDMAX+2; enum OLEUI_BZ_CALLUNBLOCKED = OLEUI_ERR_STANDARDMAX+3; enum CSF_SHOWHELP = 1; enum CSF_VALIDSOURCE = 2; enum CSF_ONLYGETSOURCE = 4; enum CSF_EXPLORER = 8; enum OLEUI_CSERR_LINKCNTRNULL = OLEUI_ERR_STANDARDMAX; enum OLEUI_CSERR_LINKCNTRINVALID = OLEUI_ERR_STANDARDMAX+1; enum OLEUI_CSERR_FROMNOTNULL = OLEUI_ERR_STANDARDMAX+2; enum OLEUI_CSERR_TONOTNULL = OLEUI_ERR_STANDARDMAX+3; enum OLEUI_CSERR_SOURCENULL = OLEUI_ERR_STANDARDMAX+4; enum OLEUI_CSERR_SOURCEINVALID = OLEUI_ERR_STANDARDMAX+5; enum OLEUI_CSERR_SOURCEPARSERROR = OLEUI_ERR_STANDARDMAX+6; enum OLEUI_CSERR_SOURCEPARSEERROR = OLEUI_ERR_STANDARDMAX+7; enum VPF_SELECTRELATIVE=1; enum VPF_DISABLERELATIVE=2; enum VPF_DISABLESCALE=4; align(8): extern (Windows) { alias UINT function(HWND, UINT, WPARAM, LPARAM) LPFNOLEUIHOOK; } struct OLEUIINSERTOBJECTW { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCWSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCWSTR lpszTemplate; HRSRC hResource; CLSID clsid; LPWSTR lpszFile; UINT cchFile; UINT cClsidExclude; LPCLSID lpClsidExclude; IID iid; DWORD oleRender; LPFORMATETC lpFormatEtc; LPOLECLIENTSITE lpIOleClientSite; LPSTORAGE lpIStorage; PVOID *ppvObj; SCODE sc; HGLOBAL hMetaPict; } alias OLEUIINSERTOBJECTW* POLEUIINSERTOBJECTW, LPOLEUIINSERTOBJECTW; struct OLEUIINSERTOBJECTA { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCSTR lpszTemplate; HRSRC hResource; CLSID clsid; LPSTR lpszFile; UINT cchFile; UINT cClsidExclude; LPCLSID lpClsidExclude; IID iid; DWORD oleRender; LPFORMATETC lpFormatEtc; LPOLECLIENTSITE lpIOleClientSite; LPSTORAGE lpIStorage; PVOID *ppvObj; SCODE sc; HGLOBAL hMetaPict; } alias OLEUIINSERTOBJECTA* POLEUIINSERTOBJECTA, LPOLEUIINSERTOBJECTA; UINT OleUIInsertObjectW(LPOLEUIINSERTOBJECTW); UINT OleUIInsertObjectA(LPOLEUIINSERTOBJECTA); enum OLEUIPASTEFLAG { OLEUIPASTE_PASTEONLY, OLEUIPASTE_LINKTYPE1, OLEUIPASTE_LINKTYPE2, OLEUIPASTE_LINKTYPE3 = 4, OLEUIPASTE_LINKTYPE4 = 8, OLEUIPASTE_LINKTYPE5 = 16, OLEUIPASTE_LINKTYPE6 = 32, OLEUIPASTE_LINKTYPE7 = 64, OLEUIPASTE_LINKTYPE8 = 128, OLEUIPASTE_PASTE = 512, OLEUIPASTE_LINKANYTYPE = 1024, OLEUIPASTE_ENABLEICON = 2048 } struct OLEUIPASTEENTRYW { FORMATETC fmtetc; LPCWSTR lpstrFormatName; LPCWSTR lpstrResultText; DWORD dwFlags; DWORD dwScratchSpace; } alias OLEUIPASTEENTRYW* POLEUIPASTEENTRYW, LPOLEUIPASTEENTRYW; struct OLEUIPASTEENTRYA { FORMATETC fmtetc; LPCSTR lpstrFormatName; LPCSTR lpstrResultText; DWORD dwFlags; DWORD dwScratchSpace; } alias OLEUIPASTEENTRYA* POLEUIPASTEENTRYA, LPOLEUIPASTEENTRYA; struct OLEUIPASTESPECIALW { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCWSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCWSTR lpszTemplate; HRSRC hResource; LPDATAOBJECT lpSrcDataObj; LPOLEUIPASTEENTRYW arrPasteEntries; int cPasteEntries; UINT *arrLinkTypes; int cLinkTypes; UINT cClsidExclude; LPCLSID lpClsidExclude; int nSelectedIndex; BOOL fLink; HGLOBAL hMetaPict; SIZEL sizel; } alias OLEUIPASTESPECIALW* POLEUIPASTESPECIALW, LPOLEUIPASTESPECIALW; struct OLEUIPASTESPECIALA { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCSTR lpszTemplate; HRSRC hResource; LPDATAOBJECT lpSrcDataObj; LPOLEUIPASTEENTRYA arrPasteEntries; int cPasteEntries; UINT* arrLinkTypes; int cLinkTypes; UINT cClsidExclude; LPCLSID lpClsidExclude; int nSelectedIndex; BOOL fLink; HGLOBAL hMetaPict; SIZEL sizel; } alias OLEUIPASTESPECIALA* POLEUIPASTESPECIALA, LPOLEUIPASTESPECIALA; interface IOleUILinkContainerW : IUnknown { HRESULT QueryInterface(REFIID, PVOID*); ULONG AddRef(); ULONG Release(); DWORD GetNextLink(DWORD dwLink); HRESULT SetLinkUpdateOptions(DWORD, DWORD); HRESULT GetLinkUpdateOptions(DWORD, PDWORD); HRESULT SetLinkSource(DWORD, LPWSTR, ULONG, PULONG, BOOL); HRESULT GetLinkSource(DWORD, LPWSTR*, PULONG, LPWSTR*, LPWSTR*, BOOL*, BOOL*); HRESULT OpenLinkSource(DWORD); HRESULT UpdateLink(DWORD, BOOL, BOOL); HRESULT CancelLink(DWORD); } alias IOleUILinkContainerW LPOLEUILINKCONTAINERW; interface IOleUILinkContainerA : IUnknown { HRESULT QueryInterface(REFIID, PVOID*); ULONG AddRef(); ULONG Release(); DWORD GetNextLink(DWORD); HRESULT SetLinkUpdateOptions(DWORD, DWORD); HRESULT GetLinkUpdateOptions(DWORD, PDWORD); HRESULT SetLinkSource(DWORD, LPSTR, ULONG, PULONG, BOOL); HRESULT GetLinkSource(DWORD, LPSTR*, PULONG, LPSTR*, LPSTR*, BOOL*, BOOL*); HRESULT OpenLinkSource(DWORD); HRESULT UpdateLink(DWORD, BOOL, BOOL); HRESULT CancelLink(DWORD); } alias IOleUILinkContainerA LPOLEUILINKCONTAINERA; struct OLEUIEDITLINKSW { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCWSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCWSTR lpszTemplate; HRSRC hResource; LPOLEUILINKCONTAINERW lpOleUILinkContainer; } alias OLEUIEDITLINKSW* POLEUIEDITLINKSW, LPOLEUIEDITLINKSW; struct OLEUIEDITLINKSA { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCSTR lpszTemplate; HRSRC hResource; LPOLEUILINKCONTAINERA lpOleUILinkContainer; } alias OLEUIEDITLINKSA* POLEUIEDITLINKSA, LPOLEUIEDITLINKSA; struct OLEUICHANGEICONW { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCWSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCWSTR lpszTemplate; HRSRC hResource; HGLOBAL hMetaPict; CLSID clsid; WCHAR[MAX_PATH] szIconExe; int cchIconExe; } alias OLEUICHANGEICONW* POLEUICHANGEICONW, LPOLEUICHANGEICONW; struct OLEUICHANGEICONA { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCSTR lpszTemplate; HRSRC hResource; HGLOBAL hMetaPict; CLSID clsid; CHAR[MAX_PATH] szIconExe; int cchIconExe; } alias OLEUICHANGEICONA* POLEUICHANGEICONA, LPOLEUICHANGEICONA; struct OLEUICONVERTW { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCWSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCWSTR lpszTemplate; HRSRC hResource; CLSID clsid; CLSID clsidConvertDefault; CLSID clsidActivateDefault; CLSID clsidNew; DWORD dvAspect; WORD wFormat; BOOL fIsLinkedObject; HGLOBAL hMetaPict; LPWSTR lpszUserType; BOOL fObjectsIconChanged; LPWSTR lpszDefLabel; UINT cClsidExclude; LPCLSID lpClsidExclude; } alias OLEUICONVERTW* POLEUICONVERTW, LPOLEUICONVERTW; struct OLEUICONVERTA { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCSTR lpszTemplate; HRSRC hResource; CLSID clsid; CLSID clsidConvertDefault; CLSID clsidActivateDefault; CLSID clsidNew; DWORD dvAspect; WORD wFormat; BOOL fIsLinkedObject; HGLOBAL hMetaPict; LPSTR lpszUserType; BOOL fObjectsIconChanged; LPSTR lpszDefLabel; UINT cClsidExclude; LPCLSID lpClsidExclude; } alias OLEUICONVERTA* POLEUICONVERTA, LPOLEUICONVERTA; struct OLEUIBUSYW { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCWSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCWSTR lpszTemplate; HRSRC hResource; HTASK hTask; HWND *lphWndDialog; } alias OLEUIBUSYW* POLEUIBUSYW, LPOLEUIBUSYW; struct OLEUIBUSYA { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCSTR lpszTemplate; HRSRC hResource; HTASK hTask; HWND *lphWndDialog; } alias OLEUIBUSYA* POLEUIBUSYA, LPOLEUIBUSYA; struct OLEUICHANGESOURCEW { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCWSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCWSTR lpszTemplate; HRSRC hResource; OPENFILENAMEW* lpOFN; DWORD[4] dwReserved1; LPOLEUILINKCONTAINERW lpOleUILinkContainer; DWORD dwLink; LPWSTR lpszDisplayName; ULONG nFileLength; LPWSTR lpszFrom; LPWSTR lpszTo; } alias OLEUICHANGESOURCEW* POLEUICHANGESOURCEW, LPOLEUICHANGESOURCEW; struct OLEUICHANGESOURCEA { DWORD cbStruct; DWORD dwFlags; HWND hWndOwner; LPCSTR lpszCaption; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; HINSTANCE hInstance; LPCSTR lpszTemplate; HRSRC hResource; OPENFILENAMEA *lpOFN; DWORD[4] dwReserved1; LPOLEUILINKCONTAINERA lpOleUILinkContainer; DWORD dwLink; LPSTR lpszDisplayName; ULONG nFileLength; LPSTR lpszFrom; LPSTR lpszTo; } alias OLEUICHANGESOURCEA* POLEUICHANGESOURCEA, LPOLEUICHANGESOURCEA; interface IOleUIObjInfoW : IUnknown { HRESULT QueryInterface(REFIID, PVOID*); ULONG AddRef(); ULONG Release(); HRESULT GetObjectInfo(DWORD, PDWORD, LPWSTR*, LPWSTR*, LPWSTR*, LPWSTR*); HRESULT GetConvertInfo(DWORD, CLSID*, PWORD, CLSID*, LPCLSID*, UINT*); HRESULT ConvertObject(DWORD, REFCLSID); HRESULT GetViewInfo(DWORD, HGLOBAL*, PDWORD, int*); HRESULT SetViewInfo(DWORD, HGLOBAL, DWORD, int, BOOL); } alias IOleUIObjInfoW LPOLEUIOBJINFOW; interface IOleUIObjInfoA : IUnknown { HRESULT QueryInterface(REFIID, PVOID*); ULONG AddRef(); ULONG Release(); HRESULT GetObjectInfo(DWORD, PDWORD, LPSTR*, LPSTR*, LPSTR*, LPSTR*); HRESULT GetConvertInfo(DWORD, CLSID*, PWORD, CLSID*, LPCLSID*, UINT*); HRESULT ConvertObject(DWORD, REFCLSID); HRESULT GetViewInfo(DWORD, HGLOBAL*, PDWORD, int*); HRESULT SetViewInfo(DWORD, HGLOBAL, DWORD, int, BOOL); } alias IOleUIObjInfoA LPOLEUIOBJINFOA; interface IOleUILinkInfoW : IOleUILinkContainerW { HRESULT QueryInterface(REFIID, PVOID*); ULONG AddRef(); ULONG Release(); DWORD GetNextLink(DWORD); HRESULT SetLinkUpdateOptions(DWORD, DWORD); HRESULT GetLinkUpdateOptions(DWORD, DWORD*); HRESULT SetLinkSource(DWORD, LPWSTR, ULONG, PULONG, BOOL); HRESULT GetLinkSource(DWORD, LPWSTR*, PULONG, LPWSTR*, LPWSTR*, BOOL*, BOOL*); HRESULT OpenLinkSource(DWORD); HRESULT UpdateLink(DWORD, BOOL, BOOL); HRESULT CancelLink(DWORD); HRESULT GetLastUpdate(DWORD, FILETIME*); } alias IOleUILinkInfoW LPOLEUILINKINFOW; interface IOleUILinkInfoA : IOleUILinkContainerA { HRESULT QueryInterface(REFIID, PVOID*); ULONG AddRef(); ULONG Release(); DWORD GetNextLink(DWORD); HRESULT SetLinkUpdateOptions(DWORD, DWORD); HRESULT GetLinkUpdateOptions(DWORD, DWORD*); HRESULT SetLinkSource(DWORD, LPSTR, ULONG, PULONG, BOOL); HRESULT GetLinkSource(DWORD, LPSTR*, PULONG, LPSTR*, LPSTR*, BOOL*, BOOL*); HRESULT OpenLinkSource(DWORD); HRESULT UpdateLink(DWORD, BOOL, BOOL); HRESULT CancelLink(DWORD); HRESULT GetLastUpdate(DWORD, FILETIME*); } alias IOleUILinkInfoA LPOLEUILINKINFOA; struct OLEUIGNRLPROPSW { DWORD cbStruct; DWORD dwFlags; DWORD[2] dwReserved1; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; DWORD[3] dwReserved2; OLEUIOBJECTPROPSW* lpOP; } alias OLEUIGNRLPROPSW* POLEUIGNRLPROPSW, LPOLEUIGNRLPROPSW; struct OLEUIGNRLPROPSA { DWORD cbStruct; DWORD dwFlags; DWORD[2] dwReserved1; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; DWORD[3] dwReserved2; OLEUIOBJECTPROPSA* lpOP; } alias OLEUIGNRLPROPSA* POLEUIGNRLPROPSA, LPOLEUIGNRLPROPSA; struct OLEUIVIEWPROPSW { DWORD cbStruct; DWORD dwFlags; DWORD[2] dwReserved1; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; DWORD[3] dwReserved2; OLEUIOBJECTPROPSW* lpOP; int nScaleMin; int nScaleMax; } alias OLEUIVIEWPROPSW* POLEUIVIEWPROPSW, LPOLEUIVIEWPROPSW; struct OLEUIVIEWPROPSA { DWORD cbStruct; DWORD dwFlags; DWORD[2] dwReserved1; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; DWORD[3] dwReserved2; OLEUIOBJECTPROPSA *lpOP; int nScaleMin; int nScaleMax; } alias OLEUIVIEWPROPSA* POLEUIVIEWPROPSA, LPOLEUIVIEWPROPSA; struct OLEUILINKPROPSW { DWORD cbStruct; DWORD dwFlags; DWORD[2] dwReserved1; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; DWORD[3] dwReserved2; OLEUIOBJECTPROPSW *lpOP; } alias OLEUILINKPROPSW* POLEUILINKPROPSW, LPOLEUILINKPROPSW; struct OLEUILINKPROPSA { DWORD cbStruct; DWORD dwFlags; DWORD[2] dwReserved1; LPFNOLEUIHOOK lpfnHook; LPARAM lCustData; DWORD[3] dwReserved2; OLEUIOBJECTPROPSA* lpOP; } alias OLEUILINKPROPSA* POLEUILINKPROPSA, LPOLEUILINKPROPSA; struct OLEUIOBJECTPROPSW { DWORD cbStruct; DWORD dwFlags; LPPROPSHEETHEADERW lpPS; DWORD dwObject; LPOLEUIOBJINFOW lpObjInfo; DWORD dwLink; LPOLEUILINKINFOW lpLinkInfo; LPOLEUIGNRLPROPSW lpGP; LPOLEUIVIEWPROPSW lpVP; LPOLEUILINKPROPSW lpLP; } alias OLEUIOBJECTPROPSW* POLEUIOBJECTPROPSW, LPOLEUIOBJECTPROPSW; struct OLEUIOBJECTPROPSA { DWORD cbStruct; DWORD dwFlags; LPPROPSHEETHEADERA lpPS; DWORD dwObject; LPOLEUIOBJINFOA lpObjInfo; DWORD dwLink; LPOLEUILINKINFOA lpLinkInfo; LPOLEUIGNRLPROPSA lpGP; LPOLEUIVIEWPROPSA lpVP; LPOLEUILINKPROPSA lpLP; } alias OLEUIOBJECTPROPSA* POLEUIOBJECTPROPSA, LPOLEUIOBJECTPROPSA; extern (Windows) { BOOL OleUIAddVerbMenuW(LPOLEOBJECT, LPCWSTR, HMENU, UINT, UINT, UINT, BOOL, UINT, HMENU*); BOOL OleUIAddVerbMenuA(LPOLEOBJECT, LPCSTR, HMENU, UINT, UINT, UINT, BOOL, UINT, HMENU*); UINT OleUIBusyW(LPOLEUIBUSYW); UINT OleUIBusyA(LPOLEUIBUSYA); BOOL OleUICanConvertOrActivateAs(REFCLSID, BOOL, WORD); UINT OleUIChangeIconW(LPOLEUICHANGEICONW); UINT OleUIChangeIconA(LPOLEUICHANGEICONA); UINT OleUIChangeSourceW(LPOLEUICHANGESOURCEW); UINT OleUIChangeSourceA(LPOLEUICHANGESOURCEA); UINT OleUIConvertW(LPOLEUICONVERTW); UINT OleUIConvertA(LPOLEUICONVERTA); UINT OleUIEditLinksW(LPOLEUIEDITLINKSW); UINT OleUIEditLinksA(LPOLEUIEDITLINKSA); UINT OleUIObjectPropertiesW(LPOLEUIOBJECTPROPSW); UINT OleUIObjectPropertiesA(LPOLEUIOBJECTPROPSA); UINT OleUIPasteSpecialW(LPOLEUIPASTESPECIALW); UINT OleUIPasteSpecialA(LPOLEUIPASTESPECIALA); BOOL OleUIUpdateLinksW(LPOLEUILINKCONTAINERW, HWND, LPWSTR, int); BOOL OleUIUpdateLinksA(LPOLEUILINKCONTAINERA, HWND, LPSTR, int); } extern (C) { int OleUIPromptUserW(int, HWND, ...); int OleUIPromptUserA(int, HWND, ...); } version(Unicode) { alias IDD_SERVERNOTREGW IDD_SERVERNOTREG; alias IDD_LINKTYPECHANGEDW IDD_LINKTYPECHANGED; alias OleUIUpdateLinksW OleUIUpdateLinks; alias OleUIAddVerbMenuW OleUIAddVerbMenu; alias OLEUIOBJECTPROPSW OLEUIOBJECTPROPS; alias POLEUIOBJECTPROPSW POLEUIOBJECTPROPS; alias LPOLEUIOBJECTPROPSW LPOLEUIOBJECTPROPS; alias OleUIObjectPropertiesW OleUIObjectProperties; alias OLEUIINSERTOBJECTW OLEUIINSERTOBJECT; alias POLEUIINSERTOBJECTW POLEUIINSERTOBJECT; alias LPOLEUIINSERTOBJECTW LPOLEUIINSERTOBJECT; alias OleUIInsertObjectW OleUIInsertObject; alias OleUIPromptUserW OleUIPromptUser; alias OLEUIPASTEENTRYW OLEUIPASTEENTRY; alias POLEUIPASTEENTRYW POLEUIPASTEENTRY; alias LPOLEUIPASTEENTRYW LPOLEUIPASTEENTRY; alias OLEUIPASTESPECIALW OLEUIPASTESPECIAL; alias POLEUIPASTESPECIALW POLEUIPASTESPECIAL; alias LPOLEUIPASTESPECIALW LPOLEUIPASTESPECIAL; alias OleUIPasteSpecialW OleUIPasteSpecial; alias IOleUILinkContainerW IOleUILinkContainer; alias LPOLEUILINKCONTAINERW LPOLEUILINKCONTAINER; alias OLEUIEDITLINKSW OLEUIEDITLINKS; alias POLEUIEDITLINKSW POLEUIEDITLINKS; alias LPOLEUIEDITLINKSW LPOLEUIEDITLINKS; alias OleUIEditLinksW OleUIEditLinks; alias OLEUICHANGEICONW OLEUICHANGEICON; alias POLEUICHANGEICONW POLEUICHANGEICON; alias LPOLEUICHANGEICONW LPOLEUICHANGEICON; alias OleUIChangeIconW OleUIChangeIcon; alias OLEUICONVERTW OLEUICONVERT; alias POLEUICONVERTW POLEUICONVERT; alias LPOLEUICONVERTW LPOLEUICONVERT; alias OleUIConvertW OleUIConvert; alias OLEUIBUSYW OLEUIBUSY; alias POLEUIBUSYW POLEUIBUSY; alias LPOLEUIBUSYW LPOLEUIBUSY; alias OleUIBusyW OleUIBusy; alias OLEUICHANGESOURCEW OLEUICHANGESOURCE; alias POLEUICHANGESOURCEW POLEUICHANGESOURCE; alias LPOLEUICHANGESOURCEW LPOLEUICHANGESOURCE; alias OleUIChangeSourceW OleUIChangeSource; alias IOleUIObjInfoW IOleUIObjInfo; alias LPOLEUIOBJINFOW LPOLEUIOBJINFO; alias IOleUILinkInfoW IOleUILinkInfo; //alias IOleUILinkInfoWVtbl IOleUILinkInfoVtbl; alias LPOLEUILINKINFOW LPOLEUILINKINFO; alias OLEUIGNRLPROPSW OLEUIGNRLPROPS; alias POLEUIGNRLPROPSW POLEUIGNRLPROPS; alias LPOLEUIGNRLPROPSW LPOLEUIGNRLPROPS; alias OLEUIVIEWPROPSW OLEUIVIEWPROPS; alias POLEUIVIEWPROPSW POLEUIVIEWPROPS; alias LPOLEUIVIEWPROPSW LPOLEUIVIEWPROPS; alias OLEUILINKPROPSW OLEUILINKPROPS; alias POLEUILINKPROPSW POLEUILINKPROPS; alias LPOLEUILINKPROPSW LPOLEUILINKPROPS; } else { alias IDD_SERVERNOTREGA IDD_SERVERNOTREG; alias IDD_LINKTYPECHANGEDA IDD_LINKTYPECHANGED; alias OleUIUpdateLinksA OleUIUpdateLinks; alias OleUIAddVerbMenuA OleUIAddVerbMenu; alias OLEUIOBJECTPROPSA OLEUIOBJECTPROPS; alias POLEUIOBJECTPROPSA POLEUIOBJECTPROPS; alias LPOLEUIOBJECTPROPSA LPOLEUIOBJECTPROPS; alias OleUIObjectPropertiesA OleUIObjectProperties; alias OLEUIINSERTOBJECTA OLEUIINSERTOBJECT; alias POLEUIINSERTOBJECTA POLEUIINSERTOBJECT; alias LPOLEUIINSERTOBJECTA LPOLEUIINSERTOBJECT; alias OleUIInsertObjectA OleUIInsertObject; alias OleUIPromptUserA OleUIPromptUser; alias OLEUIPASTEENTRYA OLEUIPASTEENTRY; alias POLEUIPASTEENTRYA POLEUIPASTEENTRY; alias LPOLEUIPASTEENTRYA LPOLEUIPASTEENTRY; alias OLEUIPASTESPECIALA OLEUIPASTESPECIAL; alias POLEUIPASTESPECIALA POLEUIPASTESPECIAL; alias LPOLEUIPASTESPECIALA LPOLEUIPASTESPECIAL; alias OleUIPasteSpecialA OleUIPasteSpecial; alias IOleUILinkContainerA IOleUILinkContainer; alias LPOLEUILINKCONTAINERA LPOLEUILINKCONTAINER; alias OLEUIEDITLINKSA OLEUIEDITLINKS; alias POLEUIEDITLINKSA POLEUIEDITLINKS; alias LPOLEUIEDITLINKSA LPOLEUIEDITLINKS; alias OleUIEditLinksA OleUIEditLinks; alias OLEUICHANGEICONA OLEUICHANGEICON; alias POLEUICHANGEICONA POLEUICHANGEICON; alias LPOLEUICHANGEICONA LPOLEUICHANGEICON; alias OleUIChangeIconA OleUIChangeIcon; alias OLEUICONVERTA OLEUICONVERT; alias POLEUICONVERTA POLEUICONVERT; alias LPOLEUICONVERTA LPOLEUICONVERT; alias OleUIConvertA OleUIConvert; alias OLEUIBUSYA OLEUIBUSY; alias POLEUIBUSYA POLEUIBUSY; alias LPOLEUIBUSYA LPOLEUIBUSY; alias OleUIBusyA OleUIBusy; alias OLEUICHANGESOURCEA OLEUICHANGESOURCE; alias POLEUICHANGESOURCEA POLEUICHANGESOURCE; alias LPOLEUICHANGESOURCEA LPOLEUICHANGESOURCE; alias OleUIChangeSourceA OleUIChangeSource; alias IOleUIObjInfoA IOleUIObjInfo; alias LPOLEUIOBJINFOA LPOLEUIOBJINFO; alias IOleUILinkInfoA IOleUILinkInfo; //alias IOleUILinkInfoAVtbl IOleUILinkInfoVtbl; alias LPOLEUILINKINFOA LPOLEUILINKINFO; alias OLEUIGNRLPROPSA OLEUIGNRLPROPS; alias POLEUIGNRLPROPSA POLEUIGNRLPROPS; alias LPOLEUIGNRLPROPSA LPOLEUIGNRLPROPS; alias OLEUIVIEWPROPSA OLEUIVIEWPROPS; alias POLEUIVIEWPROPSA POLEUIVIEWPROPS; alias LPOLEUIVIEWPROPSA LPOLEUIVIEWPROPS; alias OLEUILINKPROPSA OLEUILINKPROPS; alias POLEUILINKPROPSA POLEUILINKPROPS; alias LPOLEUILINKPROPSA LPOLEUILINKPROPS; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/dhcpcsdk.d0000664000175000017500000000311412776214756023441 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_dhcpcsdk.d) */ module core.sys.windows.dhcpcsdk; version (Windows): private import core.sys.windows.w32api, core.sys.windows.windef; /*static assert (_WIN32_WINNT >= 0x500, "core.sys.windows.dhcpcsdk is available only if version Windows2000, WindowsXP, Windows2003 or WindowsVista is set");*/ //#if (_WIN32_WINNT >= 0x500) // FIXME: check type enum DHCPCAPI_REGISTER_HANDLE_EVENT = 1; enum DHCPCAPI_REQUEST_PERSISTENT = 1; enum DHCPCAPI_REQUEST_SYNCHRONOUS = 2; struct DHCPCAPI_CLASSID { ULONG Flags; LPBYTE Data; ULONG nBytesData; } alias DHCPCAPI_CLASSID* PDHCPCAPI_CLASSID, LPDHCPCAPI_CLASSID; struct DHCPAPI_PARAMS { ULONG Flags; ULONG OptionId; BOOL IsVendor; LPBYTE Data; DWORD nBytesData; } alias DHCPAPI_PARAMS* PDHCPAPI_PARAMS, LPDHCPAPI_PARAMS; struct DHCPCAPI_PARAMS_ARRAY { ULONG nParams; LPDHCPAPI_PARAMS Params; } alias DHCPCAPI_PARAMS_ARRAY* PDHCPCAPI_PARAMS_ARRAY, LPDHCPCAPI_PARAMS_ARRAY; extern (Windows) { void DhcpCApiCleanup(); DWORD DhcpCApiInitialize(LPDWORD); DWORD DhcpDeRegisterParamChange(DWORD, LPVOID, LPVOID); DWORD DhcpRegisterParamChange(DWORD, LPVOID, PWSTR, LPDHCPCAPI_CLASSID, DHCPCAPI_PARAMS_ARRAY, LPVOID); DWORD DhcpRemoveDNSRegistrations(); DWORD DhcpUndoRequestParams(DWORD, LPVOID, LPWSTR, LPWSTR); } //#endif // (_WIN32_WINNT >= 0x500) ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/odbcinst.d0000664000175000017500000001472112776214756023471 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_odbcinst.d) */ module core.sys.windows.odbcinst; version (Windows): version (ANSI) {} else version = Unicode; import core.sys.windows.sql; private import core.sys.windows.windef; /* FIXME: The Unicode/Ansi functions situation is a mess. How do the xxxA * versions of these functions fit into the scheme? */ // SQLConfigDataSource() enum : WORD { ODBC_ADD_DSN = 1, ODBC_CONFIG_DSN = 2, ODBC_REMOVE_DSN = 3, ODBC_ADD_SYS_DSN = 4, ODBC_CONFIG_SYS_DSN = 5, ODBC_REMOVE_SYS_DSN = 6, ODBC_REMOVE_DEFAULT_DSN = 7 } // ODBC 3.0+ enum : WORD { ODBC_INSTALL_INQUIRY = 1, ODBC_INSTALL_COMPLETE = 2 } // ODBC 2.5+ enum : WORD { ODBC_INSTALL_DRIVER = 1, ODBC_REMOVE_DRIVER = 2, ODBC_CONFIG_DRIVER = 3, ODBC_CONFIG_DRIVER_MAX = 100 } // ODBC 3.0+ // SQLSetConfigMode() enum : UWORD { ODBC_BOTH_DSN = 0, ODBC_USER_DSN = 1, ODBC_SYSTEM_DSN = 2 } enum : DWORD { ODBC_ERROR_GENERAL_ERR = 1, ODBC_ERROR_INVALID_BUFF_LEN = 2, ODBC_ERROR_INVALID_HWND = 3, ODBC_ERROR_INVALID_STR = 4, ODBC_ERROR_INVALID_REQUEST_TYPE = 5, ODBC_ERROR_COMPONENT_NOT_FOUND = 6, ODBC_ERROR_INVALID_NAME = 7, ODBC_ERROR_INVALID_KEYWORD_VALUE = 8, ODBC_ERROR_INVALID_DSN = 9, ODBC_ERROR_INVALID_INF = 10, ODBC_ERROR_REQUEST_FAILED = 11, ODBC_ERROR_INVALID_PATH = 12, ODBC_ERROR_LOAD_LIB_FAILED = 13, ODBC_ERROR_INVALID_PARAM_SEQUENCE = 14, ODBC_ERROR_INVALID_LOG_FILE = 15, ODBC_ERROR_USER_CANCELED = 16, ODBC_ERROR_USAGE_UPDATE_FAILED = 17, ODBC_ERROR_CREATE_DSN_FAILED = 18, ODBC_ERROR_WRITING_SYSINFO_FAILED = 19, ODBC_ERROR_REMOVE_DSN_FAILED = 20, ODBC_ERROR_OUT_OF_MEM = 21, ODBC_ERROR_OUTPUT_STRING_TRUNCATED = 22 } extern (Windows): BOOL ConfigDSN(HWND,WORD,LPCSTR,LPCSTR); BOOL ConfigDSNW(HWND,WORD,LPCWSTR,LPCWSTR); BOOL ConfigTranslator(HWND,DWORD*); BOOL SQLConfigDataSource(HWND,WORD,LPCSTR,LPCSTR); BOOL SQLConfigDataSourceW(HWND,WORD,LPCWSTR,LPCWSTR); BOOL SQLCreateDataSource(HWND,LPCSTR); BOOL SQLCreateDataSourceW(HWND,LPCWSTR); BOOL SQLGetAvailableDrivers(LPCSTR,LPSTR,WORD,WORD*); BOOL SQLGetAvailableDriversW(LPCWSTR,LPWSTR,WORD,WORD*); BOOL SQLGetInstalledDrivers(LPSTR,WORD,WORD*); BOOL SQLGetInstalledDriversW(LPWSTR,WORD,WORD*); int SQLGetPrivateProfileString(LPCSTR,LPCSTR,LPCSTR,LPSTR,int,LPCSTR); int SQLGetPrivateProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR,LPWSTR,int,LPCWSTR); BOOL SQLGetTranslator(HWND,LPSTR,WORD,WORD*,LPSTR,WORD,WORD*,DWORD*); BOOL SQLGetTranslatorW(HWND,LPWSTR,WORD,WORD*,LPWSTR,WORD,WORD*,DWORD*); BOOL SQLInstallDriver(LPCSTR,LPCSTR,LPSTR,WORD,WORD*); BOOL SQLInstallDriverManager(LPSTR,WORD,WORD*); BOOL SQLInstallDriverManagerW(LPWSTR,WORD,WORD*); BOOL SQLInstallDriverW(LPCWSTR,LPCWSTR,LPWSTR,WORD,WORD*); BOOL SQLInstallODBC(HWND,LPCSTR,LPCSTR,LPCSTR); BOOL SQLInstallODBCW(HWND,LPCWSTR,LPCWSTR,LPCWSTR); BOOL SQLManageDataSources(HWND); BOOL SQLRemoveDefaultDataSource(); BOOL SQLRemoveDSNFromIni(LPCSTR); BOOL SQLRemoveDSNFromIniW(LPCWSTR); BOOL SQLValidDSN(LPCSTR); BOOL SQLValidDSNW(LPCWSTR); BOOL SQLWriteDSNToIni(LPCSTR,LPCSTR); BOOL SQLWriteDSNToIniW(LPCWSTR,LPCWSTR); BOOL SQLWritePrivateProfileString(LPCSTR,LPCSTR,LPCSTR,LPCSTR); BOOL SQLWritePrivateProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR); static if (ODBCVER >= 0x0250) { BOOL ConfigDriver(HWND,WORD,LPCSTR,LPCSTR,LPSTR,WORD,WORD*); BOOL ConfigDriverW(HWND,WORD,LPCWSTR,LPCWSTR,LPWSTR,WORD,WORD*); BOOL SQLConfigDriver(HWND,WORD,LPCSTR,LPCSTR,LPSTR,WORD,WORD*); BOOL SQLConfigDriverW(HWND,WORD,LPCWSTR,LPCWSTR,LPWSTR,WORD,WORD*); deprecated { BOOL SQLInstallTranslator(LPCSTR,LPCSTR,LPCSTR,LPSTR,WORD,WORD*,WORD,LPDWORD); BOOL SQLInstallTranslatorW(LPCWSTR,LPCWSTR,LPCWSTR,LPWSTR,WORD,WORD*,WORD,LPDWORD); } BOOL SQLRemoveDriver(LPCSTR,BOOL,LPDWORD); BOOL SQLRemoveDriverManager(LPDWORD); BOOL SQLRemoveDriverW(LPCWSTR,BOOL,LPDWORD); BOOL SQLRemoveTranslator(LPCSTR,LPDWORD); BOOL SQLRemoveTranslatorW(LPCWSTR,LPDWORD); } static if (ODBCVER >= 0x0300) { BOOL SQLGetConfigMode(UWORD*); BOOL SQLInstallDriverEx(LPCSTR,LPCSTR,LPSTR,WORD,WORD*,WORD,LPDWORD); BOOL SQLInstallDriverExW(LPCWSTR,LPCWSTR,LPWSTR,WORD,WORD*,WORD,LPDWORD); SQLRETURN SQLInstallerError(WORD,DWORD*,LPSTR,WORD,WORD*); SQLRETURN SQLInstallerErrorW(WORD,DWORD*,LPWSTR,WORD,WORD*); BOOL SQLInstallTranslatorEx(LPCSTR,LPCSTR,LPSTR,WORD,WORD*,WORD,LPDWORD); BOOL SQLInstallTranslatorExW(LPCWSTR,LPCWSTR,LPWSTR,WORD,WORD*,WORD,LPDWORD); SQLRETURN SQLPostInstallerError(DWORD,LPCSTR); SQLRETURN SQLPostInstallerErrorW(DWORD,LPCWSTR); BOOL SQLReadFileDSN(LPCSTR,LPCSTR,LPCSTR,LPSTR,WORD,WORD*); BOOL SQLReadFileDSNW(LPCWSTR,LPCWSTR,LPCWSTR,LPWSTR,WORD,WORD*); BOOL SQLSetConfigMode(UWORD); BOOL SQLWriteFileDSN(LPCSTR,LPCSTR,LPCSTR,LPCSTR); BOOL SQLWriteFileDSNW(LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR); } version (Unicode) { alias SQLConfigDataSourceW SQLConfigDataSource; alias SQLConfigDriverW SQLConfigDriver; alias SQLCreateDataSourceW SQLCreateDataSource; alias SQLGetAvailableDriversW SQLGetAvailableDrivers; alias SQLGetInstalledDriversW SQLGetInstalledDrivers; alias SQLGetPrivateProfileStringW SQLGetPrivateProfileString; alias SQLGetTranslatorW SQLGetTranslator; alias SQLInstallDriverW SQLInstallDriver; alias SQLInstallDriverExW SQLInstallDriverEx; alias SQLInstallDriverManagerW SQLInstallDriverManager; alias SQLInstallerErrorW SQLInstallerError; alias SQLInstallODBCW SQLInstallODBC; deprecated alias SQLInstallTranslatorW SQLInstallTranslator; alias SQLInstallTranslatorExW SQLInstallTranslatorEx; alias SQLPostInstallerErrorW SQLPostInstallerError; alias SQLReadFileDSNW SQLReadFileDSN; alias SQLRemoveDriverW SQLRemoveDriver; alias SQLRemoveDSNFromIniW SQLRemoveDSNFromIni; alias SQLRemoveTranslatorW SQLRemoveTranslator; alias SQLValidDSNW SQLValidDSN; alias SQLWriteDSNToIniW SQLWriteDSNToIni; alias SQLWriteFileDSNW SQLWriteFileDSN; alias SQLWritePrivateProfileStringW SQLWritePrivateProfileString; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winnls.d0000664000175000017500000006051312776214756023176 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winnls.d) */ module core.sys.windows.winnls; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "kernel32"); private import core.sys.windows.basetsd, core.sys.windows.w32api, core.sys.windows.winbase, core.sys.windows.windef; alias DWORD LCTYPE, CALTYPE, CALID, LGRPID, GEOID, GEOTYPE, GEOCLASS; enum size_t MAX_DEFAULTCHAR = 2, MAX_LEADBYTES = 12; enum LCTYPE LOCALE_USE_CP_ACP = 0x40000000, LOCALE_RETURN_NUMBER = 0x20000000; enum : LCTYPE { LOCALE_ILANGUAGE = 1, LOCALE_SLANGUAGE, LOCALE_SABBREVLANGNAME, LOCALE_SNATIVELANGNAME, LOCALE_ICOUNTRY, LOCALE_SCOUNTRY, LOCALE_SABBREVCTRYNAME, LOCALE_SNATIVECTRYNAME, LOCALE_IDEFAULTLANGUAGE, LOCALE_IDEFAULTCOUNTRY, LOCALE_IDEFAULTCODEPAGE, LOCALE_SLIST, LOCALE_IMEASURE, LOCALE_SDECIMAL, LOCALE_STHOUSAND, LOCALE_SGROUPING, LOCALE_IDIGITS, LOCALE_ILZERO, LOCALE_SNATIVEDIGITS, LOCALE_SCURRENCY, LOCALE_SINTLSYMBOL, LOCALE_SMONDECIMALSEP, LOCALE_SMONTHOUSANDSEP, LOCALE_SMONGROUPING, LOCALE_ICURRDIGITS, LOCALE_IINTLCURRDIGITS, LOCALE_ICURRENCY, LOCALE_INEGCURR, LOCALE_SDATE, LOCALE_STIME, LOCALE_SSHORTDATE, LOCALE_SLONGDATE, LOCALE_IDATE, LOCALE_ILDATE, LOCALE_ITIME, LOCALE_ICENTURY, LOCALE_ITLZERO, LOCALE_IDAYLZERO, LOCALE_IMONLZERO, LOCALE_S1159, LOCALE_S2359, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7, LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, LOCALE_SPOSITIVESIGN, LOCALE_SNEGATIVESIGN, LOCALE_IPOSSIGNPOSN, LOCALE_INEGSIGNPOSN, LOCALE_IPOSSYMPRECEDES, LOCALE_IPOSSEPBYSPACE, LOCALE_INEGSYMPRECEDES, LOCALE_INEGSEPBYSPACE, LOCALE_FONTSIGNATURE, LOCALE_SISO639LANGNAME, LOCALE_SISO3166CTRYNAME, // = 90 LOCALE_SENGLANGUAGE = 0x1001, LOCALE_SENGCOUNTRY = 0x1002, LOCALE_IDEFAULTANSICODEPAGE = 0x1004, LOCALE_INEGNUMBER = 0x1010, LOCALE_STIMEFORMAT = 0x1003, LOCALE_ITIMEMARKPOSN = 0x1005, LOCALE_ICALENDARTYPE = 0x1009, LOCALE_IOPTIONALCALENDAR = 0x100B, LOCALE_IFIRSTDAYOFWEEK = 0x100C, LOCALE_IFIRSTWEEKOFYEAR = 0x100D, LOCALE_SMONTHNAME13 = 0x100E, LOCALE_SABBREVMONTHNAME13 = 0x100F } enum : LCID { LOCALE_USER_DEFAULT = 0x400, LOCALE_SYSTEM_DEFAULT = 0x800 } enum DWORD NORM_IGNORECASE = 1, NORM_IGNORENONSPACE = 2, NORM_IGNORESYMBOLS = 4, SORT_STRINGSORT = 0x01000, NORM_IGNOREKANATYPE = 0x10000, NORM_IGNOREWIDTH = 0x20000; enum DWORD LCMAP_LOWERCASE = 0x00000100, LCMAP_UPPERCASE = 0x00000200, LCMAP_SORTKEY = 0x00000400, LCMAP_BYTEREV = 0x00000800, LCMAP_HIRAGANA = 0x00100000, LCMAP_KATAKANA = 0x00200000, LCMAP_HALFWIDTH = 0x00400000, LCMAP_FULLWIDTH = 0x00800000, LCMAP_LINGUISTIC_CASING = 0x01000000, LCMAP_SIMPLIFIED_CHINESE = 0x02000000, LCMAP_TRADITIONAL_CHINESE = 0x04000000; enum CALID ENUM_ALL_CALENDARS = -1; enum DWORD DATE_SHORTDATE = 1, DATE_LONGDATE = 2, DATE_USE_ALT_CALENDAR = 4, LOCALE_NOUSEROVERRIDE = 0x80000000; enum : DWORD { CP_INSTALLED = 1, CP_SUPPORTED } enum : DWORD { LCID_INSTALLED = 1, LCID_SUPPORTED = 2, LCID_ALTERNATE_SORTS = 4 } enum DWORD MAP_FOLDCZONE = 16, MAP_PRECOMPOSED = 32, MAP_COMPOSITE = 64, MAP_FOLDDIGITS = 128; enum : UINT { CP_ACP, CP_OEMCP, CP_MACCP, CP_THREAD_ACP, // = 3 CP_SYMBOL = 42, CP_UTF7 = 65000, CP_UTF8 = 65001 } enum : DWORD { CT_CTYPE1 = 1, CT_CTYPE2 = 2, CT_CTYPE3 = 4 } enum WORD C1_UPPER = 1, C1_LOWER = 2, C1_DIGIT = 4, C1_SPACE = 8, C1_PUNCT = 16, C1_CNTRL = 32, C1_BLANK = 64, C1_XDIGIT = 128, C1_ALPHA = 256; enum : WORD { C2_NOTAPPLICABLE, C2_LEFTTORIGHT, C2_RIGHTTOLEFT, C2_EUROPENUMBER, C2_EUROPESEPARATOR, C2_EUROPETERMINATOR, C2_ARABICNUMBER, C2_COMMONSEPARATOR, C2_BLOCKSEPARATOR, C2_SEGMENTSEPARATOR, C2_WHITESPACE, C2_OTHERNEUTRAL // = 11 } enum WORD C3_NOTAPPLICABLE = 0, C3_NONSPACING = 1, C3_DIACRITIC = 2, C3_VOWELMARK = 4, C3_SYMBOL = 8, C3_KATAKANA = 0x0010, C3_HIRAGANA = 0x0020, C3_HALFWIDTH = 0x0040, C3_FULLWIDTH = 0x0080, C3_IDEOGRAPH = 0x0100, C3_KASHIDA = 0x0200, C3_LEXICAL = 0x0400, C3_ALPHA = 0x8000; enum DWORD TIME_NOMINUTESORSECONDS = 1, TIME_NOSECONDS = 2, TIME_NOTIMEMARKER = 4, TIME_FORCE24HOURFORMAT = 8; enum DWORD MB_PRECOMPOSED = 1, MB_COMPOSITE = 2, MB_USEGLYPHCHARS = 4, MB_ERR_INVALID_CHARS = 8; enum DWORD WC_DISCARDNS = 16, WC_SEPCHARS = 32, WC_DEFAULTCHAR = 64, WC_COMPOSITECHECK = 512; enum : LONG { CTRY_DEFAULT = 0, CTRY_DOMINICAN_REPUBLIC = 1, CTRY_PUERTO_RICO = 1, CTRY_CARIBBEAN = 1, CTRY_JAMAICA = 1, CTRY_UNITED_STATES = 1, CTRY_TRINIDAD_Y_TOBAGO = 1, CTRY_CANADA = 2, CTRY_RUSSIA = 7, CTRY_UZBEKISTAN = 7, CTRY_KAZAKSTAN = 7, CTRY_TATARSTAN = 7, CTRY_EGYPT = 20, CTRY_SOUTH_AFRICA = 27, CTRY_GREECE = 30, CTRY_NETHERLANDS = 31, CTRY_BELGIUM = 32, CTRY_FRANCE = 33, CTRY_MONACO = 33, CTRY_SPAIN = 34, CTRY_HUNGARY = 36, CTRY_ITALY = 39, CTRY_ROMANIA = 40, CTRY_SWITZERLAND = 41, CTRY_LIECHTENSTEIN = 41, CTRY_AUSTRIA = 43, CTRY_UNITED_KINGDOM = 44, CTRY_DENMARK = 45, CTRY_SWEDEN = 46, CTRY_NORWAY = 47, CTRY_POLAND = 48, CTRY_GERMANY = 49, CTRY_PERU = 51, CTRY_MEXICO = 52, CTRY_ARGENTINA = 54, CTRY_BRAZIL = 55, CTRY_CHILE = 56, CTRY_COLOMBIA = 57, CTRY_VENEZUELA = 58, CTRY_MALAYSIA = 60, CTRY_AUSTRALIA = 61, CTRY_INDONESIA = 62, CTRY_PHILIPPINES = 63, CTRY_NEW_ZEALAND = 64, CTRY_SINGAPORE = 65, CTRY_THAILAND = 66, CTRY_JAPAN = 81, CTRY_SOUTH_KOREA = 82, CTRY_VIET_NAM = 84, CTRY_PRCHINA = 86, CTRY_TURKEY = 90, CTRY_INDIA = 91, CTRY_PAKISTAN = 92, CTRY_MOROCCO = 212, CTRY_ALGERIA = 213, CTRY_TUNISIA = 216, CTRY_LIBYA = 218, CTRY_KENYA = 254, CTRY_ZIMBABWE = 263, CTRY_FAEROE_ISLANDS = 298, CTRY_PORTUGAL = 351, CTRY_LUXEMBOURG = 352, CTRY_IRELAND = 353, CTRY_ICELAND = 354, CTRY_ALBANIA = 355, CTRY_FINLAND = 358, CTRY_BULGARIA = 359, CTRY_LITHUANIA = 370, CTRY_LATVIA = 371, CTRY_ESTONIA = 372, CTRY_ARMENIA = 374, CTRY_BELARUS = 375, CTRY_UKRAINE = 380, CTRY_SERBIA = 381, CTRY_CROATIA = 385, CTRY_SLOVENIA = 386, CTRY_MACEDONIA = 389, CTRY_CZECH = 420, CTRY_SLOVAK = 421, CTRY_BELIZE = 501, CTRY_GUATEMALA = 502, CTRY_EL_SALVADOR = 503, CTRY_HONDURAS = 504, CTRY_NICARAGUA = 505, CTRY_COSTA_RICA = 506, CTRY_PANAMA = 507, CTRY_BOLIVIA = 591, CTRY_ECUADOR = 593, CTRY_PARAGUAY = 595, CTRY_URUGUAY = 598, CTRY_BRUNEI_DARUSSALAM = 673, CTRY_HONG_KONG = 852, CTRY_MACAU = 853, CTRY_TAIWAN = 886, CTRY_MALDIVES = 960, CTRY_LEBANON = 961, CTRY_JORDAN = 962, CTRY_SYRIA = 963, CTRY_IRAQ = 964, CTRY_KUWAIT = 965, CTRY_SAUDI_ARABIA = 966, CTRY_YEMEN = 967, CTRY_OMAN = 968, CTRY_UAE = 971, CTRY_ISRAEL = 972, CTRY_BAHRAIN = 973, CTRY_QATAR = 974, CTRY_MONGOLIA = 976, CTRY_IRAN = 981, CTRY_AZERBAIJAN = 994, CTRY_GEORGIA = 995, CTRY_KYRGYZSTAN = 996 } enum : CALTYPE { CAL_ICALINTVALUE = 1, CAL_SCALNAME, CAL_IYEAROFFSETRANGE, CAL_SERASTRING, CAL_SSHORTDATE, CAL_SLONGDATE, CAL_SDAYNAME1, CAL_SDAYNAME2, CAL_SDAYNAME3, CAL_SDAYNAME4, CAL_SDAYNAME5, CAL_SDAYNAME6, CAL_SDAYNAME7, CAL_SABBREVDAYNAME1, CAL_SABBREVDAYNAME2, CAL_SABBREVDAYNAME3, CAL_SABBREVDAYNAME4, CAL_SABBREVDAYNAME5, CAL_SABBREVDAYNAME6, CAL_SABBREVDAYNAME7, CAL_SMONTHNAME1, CAL_SMONTHNAME2, CAL_SMONTHNAME3, CAL_SMONTHNAME4, CAL_SMONTHNAME5, CAL_SMONTHNAME6, CAL_SMONTHNAME7, CAL_SMONTHNAME8, CAL_SMONTHNAME9, CAL_SMONTHNAME10, CAL_SMONTHNAME11, CAL_SMONTHNAME12, CAL_SMONTHNAME13, CAL_SABBREVMONTHNAME1, CAL_SABBREVMONTHNAME2, CAL_SABBREVMONTHNAME3, CAL_SABBREVMONTHNAME4, CAL_SABBREVMONTHNAME5, CAL_SABBREVMONTHNAME6, CAL_SABBREVMONTHNAME7, CAL_SABBREVMONTHNAME8, CAL_SABBREVMONTHNAME9, CAL_SABBREVMONTHNAME10, CAL_SABBREVMONTHNAME11, CAL_SABBREVMONTHNAME12, CAL_SABBREVMONTHNAME13 // = 46 } enum : CALTYPE { CAL_GREGORIAN = 1, CAL_GREGORIAN_US, CAL_JAPAN, CAL_TAIWAN, CAL_KOREA, CAL_HIJRI, CAL_THAI, CAL_HEBREW, CAL_GREGORIAN_ME_FRENCH, CAL_GREGORIAN_ARABIC, CAL_GREGORIAN_XLIT_ENGLISH, CAL_GREGORIAN_XLIT_FRENCH // = 12 } enum : int { CSTR_LESS_THAN = 1, CSTR_EQUAL, CSTR_GREATER_THAN } enum : DWORD { LGRPID_INSTALLED = 1, LGRPID_SUPPORTED } enum : LGRPID { LGRPID_WESTERN_EUROPE = 1, LGRPID_CENTRAL_EUROPE, LGRPID_BALTIC, LGRPID_GREEK, LGRPID_CYRILLIC, LGRPID_TURKISH, LGRPID_JAPANESE, LGRPID_KOREAN, LGRPID_TRADITIONAL_CHINESE, LGRPID_SIMPLIFIED_CHINESE, LGRPID_THAI, LGRPID_HEBREW, LGRPID_ARABIC, LGRPID_VIETNAMESE, LGRPID_INDIC, LGRPID_GEORGIAN, LGRPID_ARMENIAN // = 17 } static if (_WIN32_WINNT >= 0x500) { enum : LCTYPE { LOCALE_SYEARMONTH = 0x1006, LOCALE_SENGCURRNAME = 0x1007, LOCALE_SNATIVECURRNAME = 0x1008, LOCALE_IDEFAULTEBCDICCODEPAGE = 0x1012, LOCALE_SSORTNAME = 0x1013, LOCALE_IDIGITSUBSTITUTION = 0x1014, LOCALE_IPAPERSIZE = 0x100A } enum DWORD DATE_YEARMONTH = 8, DATE_LTRREADING = 16, DATE_RTLREADING = 32; enum DWORD MAP_EXPAND_LIGATURES = 0x2000; enum DWORD WC_NO_BEST_FIT_CHARS = 1024; enum : CALTYPE { CAL_SYEARMONTH = 47, CAL_ITWODIGITYEARMAX = 48, CAL_NOUSEROVERRIDE = LOCALE_NOUSEROVERRIDE, CAL_RETURN_NUMBER = LOCALE_RETURN_NUMBER, CAL_USE_CP_ACP = LOCALE_USE_CP_ACP } } // (_WIN32_WINNT >= 0x500) extern (Windows) { alias BOOL function(LPSTR) CALINFO_ENUMPROCA; alias BOOL function(LPWSTR) CALINFO_ENUMPROCW; alias BOOL function(LPSTR, CALID) CALINFO_ENUMPROCEXA; alias BOOL function(LPWSTR, CALID) CALINFO_ENUMPROCEXW; alias BOOL function(LGRPID, LPSTR, LPSTR, DWORD, LONG_PTR) LANGUAGEGROUP_ENUMPROCA; alias BOOL function(LGRPID, LPWSTR, LPWSTR, DWORD, LONG_PTR) LANGUAGEGROUP_ENUMPROCW; alias BOOL function(LGRPID, LCID, LPSTR, LONG_PTR) LANGGROUPLOCALE_ENUMPROCA; alias BOOL function(LGRPID, LCID, LPWSTR, LONG_PTR) LANGGROUPLOCALE_ENUMPROCW; alias BOOL function(LPWSTR, LONG_PTR) UILANGUAGE_ENUMPROCW; alias BOOL function(LPSTR, LONG_PTR) UILANGUAGE_ENUMPROCA; alias BOOL function(LPSTR) LOCALE_ENUMPROCA; alias BOOL function(LPWSTR) LOCALE_ENUMPROCW; alias BOOL function(LPSTR) CODEPAGE_ENUMPROCA; alias BOOL function(LPWSTR) CODEPAGE_ENUMPROCW; alias BOOL function(LPSTR) DATEFMT_ENUMPROCA; alias BOOL function(LPWSTR) DATEFMT_ENUMPROCW; alias BOOL function(LPSTR, CALID) DATEFMT_ENUMPROCEXA; alias BOOL function(LPWSTR, CALID) DATEFMT_ENUMPROCEXW; alias BOOL function(LPSTR) TIMEFMT_ENUMPROCA; alias BOOL function(LPWSTR) TIMEFMT_ENUMPROCW; alias BOOL function(GEOID) GEO_ENUMPROC; } enum NLS_FUNCTION { COMPARE_STRING = 0x0001 } enum SYSGEOCLASS { GEOCLASS_NATION = 16, GEOCLASS_REGION = 14 } enum SYSGEOTYPE { GEO_NATION = 0x0001, GEO_LATITUDE = 0x0002, GEO_LONGITUDE = 0x0003, GEO_ISO2 = 0x0004, GEO_ISO3 = 0x0005, GEO_RFC1766 = 0x0006, GEO_LCID = 0x0007, GEO_FRIENDLYNAME = 0x0008, GEO_OFFICIALNAME = 0x0009, GEO_TIMEZONES = 0x000a, GEO_OFFICIALLANGUAGES = 0x000a } struct CPINFO { UINT MaxCharSize; BYTE[MAX_DEFAULTCHAR] DefaultChar; BYTE[MAX_LEADBYTES] LeadByte; } alias CPINFO* LPCPINFO; struct CPINFOEXA { UINT MaxCharSize; BYTE[MAX_DEFAULTCHAR] DefaultChar; BYTE[MAX_LEADBYTES] LeadByte; WCHAR UnicodeDefaultChar; UINT CodePage; CHAR[MAX_PATH] CodePageName; } alias CPINFOEXA* LPCPINFOEXA; struct CPINFOEXW { UINT MaxCharSize; BYTE[MAX_DEFAULTCHAR] DefaultChar; BYTE[MAX_LEADBYTES] LeadByte; WCHAR UnicodeDefaultChar; UINT CodePage; WCHAR[MAX_PATH] CodePageName; } alias CPINFOEXW* LPCPINFOEXW; struct CURRENCYFMTA { UINT NumDigits; UINT LeadingZero; UINT Grouping; LPSTR lpDecimalSep; LPSTR lpThousandSep; UINT NegativeOrder; UINT PositiveOrder; LPSTR lpCurrencySymbol; } alias CURRENCYFMTA* LPCURRENCYFMTA; struct CURRENCYFMTW { UINT NumDigits; UINT LeadingZero; UINT Grouping; LPWSTR lpDecimalSep; LPWSTR lpThousandSep; UINT NegativeOrder; UINT PositiveOrder; LPWSTR lpCurrencySymbol; } alias CURRENCYFMTW* LPCURRENCYFMTW; struct NLSVERSIONINFO { DWORD dwNLSVersionInfoSize; DWORD dwNLSVersion; DWORD dwDefinedVersion; } alias NLSVERSIONINFO* LPNLSVERSIONINFO; struct NUMBERFMTA { UINT NumDigits; UINT LeadingZero; UINT Grouping; LPSTR lpDecimalSep; LPSTR lpThousandSep; UINT NegativeOrder; } alias NUMBERFMTA* LPNUMBERFMTA; struct NUMBERFMTW { UINT NumDigits; UINT LeadingZero; UINT Grouping; LPWSTR lpDecimalSep; LPWSTR lpThousandSep; UINT NegativeOrder; } alias NUMBERFMTW* LPNUMBERFMTW; extern (Windows) nothrow @nogc { int CompareStringA(LCID, DWORD, LPCSTR, int, LPCSTR, int); int CompareStringW(LCID, DWORD, LPCWSTR, int, LPCWSTR, int); LCID ConvertDefaultLocale(LCID); BOOL EnumCalendarInfoA(CALINFO_ENUMPROCA, LCID, CALID, CALTYPE); BOOL EnumCalendarInfoW(CALINFO_ENUMPROCW, LCID, CALID, CALTYPE); BOOL EnumDateFormatsA(DATEFMT_ENUMPROCA, LCID, DWORD); BOOL EnumDateFormatsW(DATEFMT_ENUMPROCW, LCID, DWORD); BOOL EnumSystemCodePagesA(CODEPAGE_ENUMPROCA, DWORD); BOOL EnumSystemCodePagesW(CODEPAGE_ENUMPROCW, DWORD); BOOL EnumSystemGeoID(GEOCLASS, GEOID, GEO_ENUMPROC); BOOL EnumSystemLocalesA(LOCALE_ENUMPROCA, DWORD); BOOL EnumSystemLocalesW(LOCALE_ENUMPROCW, DWORD); BOOL EnumTimeFormatsA(TIMEFMT_ENUMPROCA, LCID, DWORD); BOOL EnumTimeFormatsW(TIMEFMT_ENUMPROCW, LCID, DWORD); int FoldStringA(DWORD, LPCSTR, int, LPSTR, int); int FoldStringW(DWORD, LPCWSTR, int, LPWSTR, int); UINT GetACP(); int GetCalendarInfoA(LCID, CALID, CALTYPE, LPSTR, int, LPDWORD); int GetCalendarInfoW(LCID, CALID, CALTYPE, LPWSTR, int, LPDWORD); BOOL GetCPInfo(UINT, LPCPINFO); BOOL GetCPInfoExA(UINT, DWORD, LPCPINFOEXA); BOOL GetCPInfoExW(UINT, DWORD, LPCPINFOEXW); int GetCurrencyFormatA(LCID, DWORD, LPCSTR, const(CURRENCYFMTA)*, LPSTR, int); int GetCurrencyFormatW(LCID, DWORD, LPCWSTR, const(CURRENCYFMTW)*, LPWSTR, int); int GetDateFormatA(LCID, DWORD, const(SYSTEMTIME)*, LPCSTR, LPSTR, int); int GetDateFormatW(LCID, DWORD, const(SYSTEMTIME)*, LPCWSTR, LPWSTR, int); int GetGeoInfoA(GEOID, GEOTYPE, LPSTR, int, LANGID); int GetGeoInfoW(GEOID, GEOTYPE, LPWSTR, int, LANGID); int GetLocaleInfoA(LCID, LCTYPE, LPSTR, int); int GetLocaleInfoW(LCID, LCTYPE, LPWSTR, int); BOOL GetNLSVersion(NLS_FUNCTION, LCID, LPNLSVERSIONINFO); int GetNumberFormatA(LCID, DWORD, LPCSTR, const(NUMBERFMTA)*, LPSTR, int); int GetNumberFormatW(LCID, DWORD, LPCWSTR, const(NUMBERFMTW)*, LPWSTR, int); UINT GetOEMCP(); BOOL GetStringTypeA(LCID, DWORD, LPCSTR, int, LPWORD); BOOL GetStringTypeW(DWORD, LPCWSTR, int, LPWORD); BOOL GetStringTypeExA(LCID, DWORD, LPCSTR, int, LPWORD); BOOL GetStringTypeExW(LCID, DWORD, LPCWSTR, int, LPWORD); LANGID GetSystemDefaultLangID(); LCID GetSystemDefaultLCID(); LCID GetThreadLocale(); int GetTimeFormatA(LCID, DWORD, const(SYSTEMTIME)*, LPCSTR, LPSTR, int); int GetTimeFormatW(LCID, DWORD, const(SYSTEMTIME)*, LPCWSTR, LPWSTR, int); LANGID GetUserDefaultLangID(); LCID GetUserDefaultLCID(); GEOID GetUserGeoID(GEOCLASS); BOOL IsDBCSLeadByte(BYTE); BOOL IsDBCSLeadByteEx(UINT, BYTE); BOOL IsNLSDefinedString(NLS_FUNCTION, DWORD, LPNLSVERSIONINFO, LPCWSTR, int); BOOL IsValidCodePage(UINT); BOOL IsValidLocale(LCID, DWORD); int LCMapStringA(LCID, DWORD, LPCSTR, int, LPSTR, int); int LCMapStringW(LCID, DWORD, LPCWSTR, int, LPWSTR, int); int MultiByteToWideChar(UINT, DWORD, LPCSTR, int, LPWSTR, int); int SetCalendarInfoA(LCID, CALID, CALTYPE, LPCSTR); int SetCalendarInfoW(LCID, CALID, CALTYPE, LPCWSTR); BOOL SetLocaleInfoA(LCID, LCTYPE, LPCSTR); BOOL SetLocaleInfoW(LCID, LCTYPE, LPCWSTR); BOOL SetThreadLocale(LCID); BOOL SetUserGeoID(GEOID); int WideCharToMultiByte(UINT, DWORD, LPCWSTR, int, LPSTR, int, LPCSTR, LPBOOL); static if (_WIN32_WINNT >= 0x410) { BOOL EnumCalendarInfoExA(CALINFO_ENUMPROCEXA, LCID, CALID, CALTYPE); BOOL EnumCalendarInfoExW(CALINFO_ENUMPROCEXW, LCID, CALID, CALTYPE); BOOL EnumDateFormatsExA(DATEFMT_ENUMPROCEXA, LCID, DWORD); BOOL EnumDateFormatsExW(DATEFMT_ENUMPROCEXW, LCID, DWORD); BOOL IsValidLanguageGroup(LGRPID, DWORD); } static if (_WIN32_WINNT >= 0x500) { LANGID GetSystemDefaultUILanguage(); LANGID GetUserDefaultUILanguage(); BOOL EnumSystemLanguageGroupsA(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR); BOOL EnumSystemLanguageGroupsW(LANGUAGEGROUP_ENUMPROCW, DWORD, LONG_PTR); BOOL EnumLanguageGroupLocalesA(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR); BOOL EnumLanguageGroupLocalesW(LANGGROUPLOCALE_ENUMPROCW, LGRPID, DWORD, LONG_PTR); BOOL EnumUILanguagesA(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR); BOOL EnumUILanguagesW(UILANGUAGE_ENUMPROCW, DWORD, LONG_PTR); } } version (Unicode) { alias CALINFO_ENUMPROCW CALINFO_ENUMPROC; alias CALINFO_ENUMPROCEXW CALINFO_ENUMPROCEX; alias LOCALE_ENUMPROCW LOCALE_ENUMPROC; alias CODEPAGE_ENUMPROCW CODEPAGE_ENUMPROC; alias DATEFMT_ENUMPROCW DATEFMT_ENUMPROC; alias DATEFMT_ENUMPROCEXW DATEFMT_ENUMPROCEX; alias TIMEFMT_ENUMPROCW TIMEFMT_ENUMPROC; alias LANGUAGEGROUP_ENUMPROCW LANGUAGEGROUP_ENUMPROC; alias LANGGROUPLOCALE_ENUMPROCW LANGGROUPLOCALE_ENUMPROC; alias UILANGUAGE_ENUMPROCW UILANGUAGE_ENUMPROC; alias CPINFOEXW CPINFOEX; alias LPCPINFOEXW LPCPINFOEX; alias CURRENCYFMTW CURRENCYFMT; alias LPCURRENCYFMTW LPCURRENCYFMT; alias NUMBERFMTW NUMBERFMT; alias LPNUMBERFMTW LPNUMBERFMT; alias CompareStringW CompareString; alias EnumCalendarInfoW EnumCalendarInfo; alias EnumSystemCodePagesW EnumSystemCodePages; alias EnumSystemLocalesW EnumSystemLocales; alias EnumTimeFormatsW EnumTimeFormats; alias FoldStringW FoldString; alias GetCalendarInfoW GetCalendarInfo; alias GetCPInfoExW GetCPInfoEx; alias GetCurrencyFormatW GetCurrencyFormat; alias GetDateFormatW GetDateFormat; alias GetGeoInfoW GetGeoInfo; alias GetLocaleInfoW GetLocaleInfo; alias GetNumberFormatW GetNumberFormat; alias GetStringTypeExW GetStringTypeEx; alias GetTimeFormatW GetTimeFormat; alias LCMapStringW LCMapString; alias SetCalendarInfoW SetCalendarInfo; alias SetLocaleInfoW SetLocaleInfo; static if (_WIN32_WINNT >= 0x410) { alias EnumCalendarInfoExW EnumCalendarInfoEx; alias EnumDateFormatsExW EnumDateFormatsEx; } static if (_WIN32_WINNT >= 0x500) { alias EnumSystemLanguageGroupsW EnumSystemLanguageGroups; alias EnumLanguageGroupLocalesW EnumLanguageGroupLocales; alias EnumUILanguagesW EnumUILanguages; } } else { alias CALINFO_ENUMPROCA CALINFO_ENUMPROC; alias CALINFO_ENUMPROCEXA CALINFO_ENUMPROCEX; alias LOCALE_ENUMPROCA LOCALE_ENUMPROC; alias CODEPAGE_ENUMPROCA CODEPAGE_ENUMPROC; alias DATEFMT_ENUMPROCA DATEFMT_ENUMPROC; alias DATEFMT_ENUMPROCEXA DATEFMT_ENUMPROCEX; alias TIMEFMT_ENUMPROCA TIMEFMT_ENUMPROC; alias LANGUAGEGROUP_ENUMPROCA LANGUAGEGROUP_ENUMPROC; alias LANGGROUPLOCALE_ENUMPROCA LANGGROUPLOCALE_ENUMPROC; alias UILANGUAGE_ENUMPROCA UILANGUAGE_ENUMPROC; alias CPINFOEXA CPINFOEX; alias LPCPINFOEXA LPCPINFOEX; alias CURRENCYFMTA CURRENCYFMT; alias LPCURRENCYFMTA LPCURRENCYFMT; alias NUMBERFMTA NUMBERFMT; alias LPNUMBERFMTA LPNUMBERFMT; alias CompareStringA CompareString; alias EnumCalendarInfoA EnumCalendarInfo; alias EnumSystemCodePagesA EnumSystemCodePages; alias EnumSystemLocalesA EnumSystemLocales; alias EnumTimeFormatsA EnumTimeFormats; alias FoldStringA FoldString; alias GetCalendarInfoA GetCalendarInfo; alias GetCPInfoExA GetCPInfoEx; alias GetCurrencyFormatA GetCurrencyFormat; alias GetDateFormatA GetDateFormat; alias GetGeoInfoA GetGeoInfo; alias GetLocaleInfoA GetLocaleInfo; alias GetNumberFormatA GetNumberFormat; alias GetStringTypeExA GetStringTypeEx; alias GetTimeFormatA GetTimeFormat; alias LCMapStringA LCMapString; alias SetCalendarInfoA SetCalendarInfo; alias SetLocaleInfoA SetLocaleInfo; static if (_WIN32_WINNT >= 0x410) { alias EnumCalendarInfoExA EnumCalendarInfoEx; alias EnumDateFormatsExA EnumDateFormatsEx; } static if (_WIN32_WINNT >= 0x500) { alias EnumSystemLanguageGroupsA EnumSystemLanguageGroups; alias EnumLanguageGroupLocalesA EnumLanguageGroupLocales; alias EnumUILanguagesA EnumUILanguages; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/objidl.d0000664000175000017500000015115112776214756023126 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_objidl.d) */ // TODO (Don): // # why is "alias IPSFactoryBuffer* LPPSFACTORYBUFFER;" in this file, // rather than in objfwd ? // # do we need the proxies that are defined in this file? module core.sys.windows.objidl; version (Windows): import core.sys.windows.unknwn; import core.sys.windows.objfwd; private import core.sys.windows.windef; private import core.sys.windows.basetyps; private import core.sys.windows.oleidl; private import core.sys.windows.wtypes; private import core.sys.windows.winbase; // for FILETIME private import core.sys.windows.rpcdce; struct STATSTG { LPOLESTR pwcsName; DWORD type; ULARGE_INTEGER cbSize; FILETIME mtime; FILETIME ctime; FILETIME atime; DWORD grfMode; DWORD grfLocksSupported; CLSID clsid; DWORD grfStateBits; DWORD reserved; } enum STGTY { STGTY_STORAGE = 1, STGTY_STREAM, STGTY_LOCKBYTES, STGTY_PROPERTY } enum STREAM_SEEK { STREAM_SEEK_SET, STREAM_SEEK_CUR, STREAM_SEEK_END } struct INTERFACEINFO { LPUNKNOWN pUnk; IID iid; WORD wMethod; } alias INTERFACEINFO* LPINTERFACEINFO; enum CALLTYPE { CALLTYPE_TOPLEVEL = 1, CALLTYPE_NESTED, CALLTYPE_ASYNC, CALLTYPE_TOPLEVEL_CALLPENDING, CALLTYPE_ASYNC_CALLPENDING } enum PENDINGTYPE { PENDINGTYPE_TOPLEVEL = 1, PENDINGTYPE_NESTED } enum PENDINGMSG { PENDINGMSG_CANCELCALL = 0, PENDINGMSG_WAITNOPROCESS, PENDINGMSG_WAITDEFPROCESS } alias OLECHAR** SNB; enum DATADIR { DATADIR_GET = 1, DATADIR_SET } alias WORD CLIPFORMAT; alias CLIPFORMAT* LPCLIPFORMAT; struct DVTARGETDEVICE { DWORD tdSize; WORD tdDriverNameOffset; WORD tdDeviceNameOffset; WORD tdPortNameOffset; WORD tdExtDevmodeOffset; BYTE[1] tdData; } struct FORMATETC { CLIPFORMAT cfFormat; DVTARGETDEVICE* ptd; DWORD dwAspect; LONG lindex; DWORD tymed; } alias FORMATETC* LPFORMATETC; struct RemSTGMEDIUM { DWORD tymed; DWORD dwHandleType; ULONG pData; uint pUnkForRelease; uint cbData; BYTE[1] data; } struct HLITEM { ULONG uHLID; LPWSTR pwzFriendlyName; } struct STATDATA { FORMATETC formatetc; DWORD grfAdvf; IAdviseSink pAdvSink; DWORD dwConnection; } struct STATPROPSETSTG { FMTID fmtid; CLSID clsid; DWORD grfFlags; FILETIME mtime; FILETIME ctime; FILETIME atime; } enum EXTCONN { EXTCONN_STRONG = 1, EXTCONN_WEAK = 2, EXTCONN_CALLABLE = 4 } struct MULTI_QI { const(IID)* pIID; IUnknown pItf; HRESULT hr; } struct AUTH_IDENTITY { USHORT* User; ULONG UserLength; USHORT* Domain; ULONG DomainLength; USHORT* Password; ULONG PasswordLength; ULONG Flags; } struct COAUTHINFO { DWORD dwAuthnSvc; DWORD dwAuthzSvc; LPWSTR pwszServerPrincName; DWORD dwAuthnLevel; DWORD dwImpersonationLevel; AUTH_IDENTITY* pAuthIdentityData; DWORD dwCapabilities; } struct COSERVERINFO { DWORD dwReserved1; LPWSTR pwszName; COAUTHINFO* pAuthInfo; DWORD dwReserved2; } struct BIND_OPTS { DWORD cbStruct; DWORD grfFlags; DWORD grfMode; DWORD dwTickCountDeadline; } alias BIND_OPTS* LPBIND_OPTS; struct BIND_OPTS2 { DWORD cbStruct; DWORD grfFlags; DWORD grfMode; DWORD dwTickCountDeadline; DWORD dwTrackFlags; DWORD dwClassContext; LCID locale; COSERVERINFO* pServerInfo; } alias BIND_OPTS2* LPBIND_OPTS2; enum BIND_FLAGS { BIND_MAYBOTHERUSER = 1, BIND_JUSTTESTEXISTENCE } struct STGMEDIUM { DWORD tymed; union { HBITMAP hBitmap; PVOID hMetaFilePict; HENHMETAFILE hEnhMetaFile; HGLOBAL hGlobal; LPWSTR lpszFileName; LPSTREAM pstm; LPSTORAGE pstg; } LPUNKNOWN pUnkForRelease; } alias STGMEDIUM* LPSTGMEDIUM; enum LOCKTYPE { LOCK_WRITE = 1, LOCK_EXCLUSIVE = 2, LOCK_ONLYONCE = 4 } alias uint RPCOLEDATAREP; struct RPCOLEMESSAGE { PVOID reserved1; RPCOLEDATAREP dataRepresentation; PVOID Buffer; ULONG cbBuffer; ULONG iMethod; PVOID[5] reserved2; ULONG rpcFlags; } alias RPCOLEMESSAGE* PRPCOLEMESSAGE; enum MKSYS { MKSYS_NONE, MKSYS_GENERICCOMPOSITE, MKSYS_FILEMONIKER, MKSYS_ANTIMONIKER, MKSYS_ITEMMONIKER, MKSYS_POINTERMONIKER } enum MKREDUCE { MKRREDUCE_ALL, MKRREDUCE_ONE = 196608, MKRREDUCE_TOUSER = 131072, MKRREDUCE_THROUGHUSER = 65536 } struct RemSNB { uint ulCntStr; uint ulCntChar; OLECHAR[1] rgString; } enum ADVF { ADVF_NODATA = 1, ADVF_PRIMEFIRST = 2, ADVF_ONLYONCE = 4, ADVFCACHE_NOHANDLER = 8, ADVFCACHE_FORCEBUILTIN = 16, ADVFCACHE_ONSAVE = 32, ADVF_DATAONSTOP = 64 } enum TYMED { TYMED_HGLOBAL = 1, TYMED_FILE = 2, TYMED_ISTREAM = 4, TYMED_ISTORAGE = 8, TYMED_GDI = 16, TYMED_MFPICT = 32, TYMED_ENHMF = 64, TYMED_NULL = 0 } enum SERVERCALL { SERVERCALL_ISHANDLED, SERVERCALL_REJECTED, SERVERCALL_RETRYLATER } struct CAUB { ULONG cElems; ubyte* pElems; } struct CAI { ULONG cElems; short* pElems; } struct CAUI { ULONG cElems; USHORT* pElems; } struct CAL { ULONG cElems; int* pElems; } struct CAUL { ULONG cElems; ULONG* pElems; } struct CAFLT { ULONG cElems; float* pElems; } struct CADBL { ULONG cElems; double* pElems; } struct CACY { ULONG cElems; CY* pElems; } struct CADATE { ULONG cElems; DATE* pElems; } struct CABSTR { ULONG cElems; BSTR* pElems; } struct CABSTRBLOB { ULONG cElems; BSTRBLOB* pElems; } struct CABOOL { ULONG cElems; VARIANT_BOOL* pElems; } struct CASCODE { ULONG cElems; SCODE* pElems; } struct CAH { ULONG cElems; LARGE_INTEGER* pElems; } struct CAUH { ULONG cElems; ULARGE_INTEGER* pElems; } struct CALPSTR { ULONG cElems; LPSTR* pElems; } struct CALPWSTR { ULONG cElems; LPWSTR* pElems; } struct CAFILETIME { ULONG cElems; FILETIME* pElems; } struct CACLIPDATA { ULONG cElems; CLIPDATA* pElems; } struct CACLSID { ULONG cElems; CLSID* pElems; } alias PROPVARIANT* LPPROPVARIANT; struct CAPROPVARIANT { ULONG cElems; LPPROPVARIANT pElems; } struct PROPVARIANT { VARTYPE vt; WORD wReserved1; WORD wReserved2; WORD wReserved3; union { CHAR cVal; UCHAR bVal; short iVal; USHORT uiVal; VARIANT_BOOL boolVal; int lVal; ULONG ulVal; float fltVal; SCODE scode; LARGE_INTEGER hVal; ULARGE_INTEGER uhVal; double dblVal; CY cyVal; DATE date; FILETIME filetime; CLSID* puuid; BLOB blob; CLIPDATA* pclipdata; LPSTREAM pStream; LPSTORAGE pStorage; BSTR bstrVal; BSTRBLOB bstrblobVal; LPSTR pszVal; LPWSTR pwszVal; CAUB caub; CAI cai; CAUI caui; CABOOL cabool; CAL cal; CAUL caul; CAFLT caflt; CASCODE cascode; CAH cah; CAUH cauh; CADBL cadbl; CACY cacy; CADATE cadate; CAFILETIME cafiletime; CACLSID cauuid; CACLIPDATA caclipdata; CABSTR cabstr; CABSTRBLOB cabstrblob; CALPSTR calpstr; CALPWSTR calpwstr; CAPROPVARIANT capropvar; } } struct PROPSPEC { ULONG ulKind; union { PROPID propid; LPOLESTR lpwstr; } } struct STATPROPSTG { LPOLESTR lpwstrName; PROPID propid; VARTYPE vt; } enum PROPSETFLAG { PROPSETFLAG_DEFAULT, PROPSETFLAG_NONSIMPLE, PROPSETFLAG_ANSI, PROPSETFLAG_UNBUFFERED = 4 } struct STORAGELAYOUT { DWORD LayoutType; OLECHAR* pwcsElementName; LARGE_INTEGER cOffset; LARGE_INTEGER cBytes; } struct SOLE_AUTHENTICATION_SERVICE { DWORD dwAuthnSvc; DWORD dwAuthzSvc; OLECHAR* pPrincipalName; HRESULT hr; } enum OLECHAR* COLE_DEFAULT_PRINCIPAL = cast ( OLECHAR* )(-1); enum EOLE_AUTHENTICATION_CAPABILITIES { EOAC_NONE = 0, EOAC_MUTUAL_AUTH = 0x1, EOAC_SECURE_REFS = 0x2, EOAC_ACCESS_CONTROL = 0x4, EOAC_APPID = 0x8, EOAC_DYNAMIC = 0x10, EOAC_STATIC_CLOAKING = 0x20, EOAC_DYNAMIC_CLOAKING = 0x40, EOAC_ANY_AUTHORITY = 0x80, EOAC_MAKE_FULLSIC = 0x100, EOAC_REQUIRE_FULLSIC = 0x200, EOAC_AUTO_IMPERSONATE = 0x400, EOAC_DEFAULT = 0x800, EOAC_DISABLE_AAA = 0x1000, EOAC_NO_CUSTOM_MARSHAL = 0x2000 } struct SOLE_AUTHENTICATION_INFO { DWORD dwAuthnSvc; DWORD dwAuthzSvc; void* pAuthInfo; } enum void* COLE_DEFAULT_AUTHINFO = cast( void* )(-1 ); struct SOLE_AUTHENTICATION_LIST { DWORD cAuthInfo; SOLE_AUTHENTICATION_INFO* aAuthInfo; } interface IEnumFORMATETC : IUnknown { HRESULT Next(ULONG, FORMATETC*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumFORMATETC*); } interface IEnumHLITEM : IUnknown { HRESULT Next(ULONG, HLITEM*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumHLITEM*); } interface IEnumSTATDATA : IUnknown { HRESULT Next(ULONG, STATDATA*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumSTATDATA*); } interface IEnumSTATPROPSETSTG : IUnknown { HRESULT Next(ULONG, STATPROPSETSTG*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumSTATPROPSETSTG*); } interface IEnumSTATPROPSTG : IUnknown { HRESULT Next(ULONG, STATPROPSTG*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumSTATPROPSTG*); } interface IEnumSTATSTG : IUnknown { HRESULT Next(ULONG, STATSTG*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumSTATSTG*); } interface IEnumString : IUnknown { HRESULT Next(ULONG, LPOLESTR*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumString*); } interface IEnumMoniker : IUnknown { HRESULT Next(ULONG, IMoniker*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumMoniker*); } interface IEnumUnknown : IUnknown { HRESULT Next(ULONG, IUnknown*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumUnknown*); } interface ISequentialStream : IUnknown { HRESULT Read(void*, ULONG, ULONG*); HRESULT Write(void* , ULONG, ULONG*); } interface IStream : ISequentialStream { HRESULT Seek(LARGE_INTEGER, DWORD, ULARGE_INTEGER*); HRESULT SetSize(ULARGE_INTEGER); HRESULT CopyTo(IStream, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*); HRESULT Commit(DWORD); HRESULT Revert(); HRESULT LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD); HRESULT UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD); HRESULT Stat(STATSTG*, DWORD); HRESULT Clone(LPSTREAM*); } interface IMarshal : IUnknown { HRESULT GetUnmarshalClass(REFIID, PVOID, DWORD, PVOID, DWORD, CLSID*); HRESULT GetMarshalSizeMax(REFIID, PVOID, DWORD, PVOID, PDWORD, ULONG*); HRESULT MarshalInterface(IStream, REFIID, PVOID, DWORD, PVOID, DWORD); HRESULT UnmarshalInterface(IStream, REFIID, void**); HRESULT ReleaseMarshalData(IStream); HRESULT DisconnectObject(DWORD); } interface IStdMarshalInfo : IUnknown { HRESULT GetClassForHandler(DWORD, PVOID, CLSID*); } interface IMalloc : IUnknown { void* Alloc(ULONG); void* Realloc(void*, ULONG); void Free(void*); ULONG GetSize(void*); int DidAlloc(void*); void HeapMinimize(); } interface IMallocSpy : IUnknown { ULONG PreAlloc(ULONG); void* PostAlloc(void*); void* PreFree(void*, BOOL); void PostFree(BOOL); ULONG PreRealloc(void*, ULONG, void**, BOOL); void* PostRealloc(void*, BOOL); void* PreGetSize(void*, BOOL); ULONG PostGetSize(ULONG, BOOL); void* PreDidAlloc(void*, BOOL); int PostDidAlloc(void*, BOOL, int); void PreHeapMinimize(); void PostHeapMinimize(); } interface IMessageFilter : IUnknown { DWORD HandleInComingCall(DWORD, HTASK, DWORD, LPINTERFACEINFO); DWORD RetryRejectedCall(HTASK, DWORD, DWORD); DWORD MessagePending(HTASK, DWORD, DWORD); } interface IPersist : IUnknown { HRESULT GetClassID(CLSID*); } interface IPersistStream : IPersist { HRESULT IsDirty(); HRESULT Load(IStream); HRESULT Save(IStream, BOOL); HRESULT GetSizeMax(PULARGE_INTEGER); } interface IRunningObjectTable : IUnknown { HRESULT Register(DWORD, LPUNKNOWN, LPMONIKER, PDWORD); HRESULT Revoke(DWORD); HRESULT IsRunning(LPMONIKER); HRESULT GetObject(LPMONIKER, LPUNKNOWN*); HRESULT NoteChangeTime(DWORD, LPFILETIME); HRESULT GetTimeOfLastChange(LPMONIKER, LPFILETIME); HRESULT EnumRunning(IEnumMoniker*); } interface IBindCtx : IUnknown { HRESULT RegisterObjectBound(LPUNKNOWN); HRESULT RevokeObjectBound(LPUNKNOWN); HRESULT ReleaseBoundObjects(); HRESULT SetBindOptions(LPBIND_OPTS); HRESULT GetBindOptions(LPBIND_OPTS); HRESULT GetRunningObjectTable(IRunningObjectTable*); HRESULT RegisterObjectParam(LPOLESTR, IUnknown); HRESULT GetObjectParam(LPOLESTR, IUnknown*); HRESULT EnumObjectParam(IEnumString*); HRESULT RevokeObjectParam(LPOLESTR); } interface IMoniker: IPersistStream { HRESULT BindToObject(IBindCtx, IMoniker, REFIID, PVOID*); HRESULT BindToStorage(IBindCtx, IMoniker, REFIID, PVOID*); HRESULT Reduce(IBindCtx, DWORD, IMoniker*, IMoniker*); HRESULT ComposeWith(IMoniker, BOOL, IMoniker*); HRESULT Enum(BOOL, IEnumMoniker*); HRESULT IsEqual(IMoniker); HRESULT Hash(PDWORD); HRESULT IsRunning(IBindCtx, IMoniker, IMoniker); HRESULT GetTimeOfLastChange(IBindCtx, IMoniker, LPFILETIME); HRESULT Inverse(IMoniker*); HRESULT CommonPrefixWith(IMoniker, IMoniker*); HRESULT RelativePathTo(IMoniker, IMoniker*); HRESULT GetDisplayName(IBindCtx, IMoniker, LPOLESTR*); HRESULT ParseDisplayName(IBindCtx, IMoniker, LPOLESTR, ULONG*, IMoniker*); HRESULT IsSystemMoniker(PDWORD); } interface IPersistStorage : IPersist { HRESULT IsDirty(); HRESULT InitNew(LPSTORAGE); HRESULT Load(LPSTORAGE); HRESULT Save(LPSTORAGE, BOOL); HRESULT SaveCompleted(LPSTORAGE); HRESULT HandsOffStorage(); } interface IPersistFile : IPersist { HRESULT IsDirty(); HRESULT Load(LPCOLESTR, DWORD); HRESULT Save(LPCOLESTR, BOOL); HRESULT SaveCompleted(LPCOLESTR); HRESULT GetCurFile(LPOLESTR*); } interface IAdviseSink : IUnknown { HRESULT QueryInterface(REFIID, PVOID*); ULONG AddRef(); ULONG Release(); void OnDataChange(FORMATETC*, STGMEDIUM*); void OnViewChange(DWORD, LONG); void OnRename(IMoniker); void OnSave(); void OnClose(); } interface IAdviseSink2 : IAdviseSink { void OnLinkSrcChange(IMoniker); } interface IDataObject : IUnknown { HRESULT GetData(FORMATETC*, STGMEDIUM*); HRESULT GetDataHere(FORMATETC*, STGMEDIUM*); HRESULT QueryGetData(FORMATETC*); HRESULT GetCanonicalFormatEtc(FORMATETC*, FORMATETC*); HRESULT SetData(FORMATETC*, STGMEDIUM*, BOOL); HRESULT EnumFormatEtc(DWORD, IEnumFORMATETC*); HRESULT DAdvise(FORMATETC*, DWORD, IAdviseSink, PDWORD); HRESULT DUnadvise(DWORD); HRESULT EnumDAdvise(IEnumSTATDATA*); } interface IDataAdviseHolder : IUnknown { HRESULT Advise(IDataObject, FORMATETC*, DWORD, IAdviseSink, PDWORD); HRESULT Unadvise(DWORD); HRESULT EnumAdvise(IEnumSTATDATA*); HRESULT SendOnDataChange(IDataObject, DWORD, DWORD); } interface IStorage : IUnknown { HRESULT CreateStream(LPCWSTR, DWORD, DWORD, DWORD, IStream); HRESULT OpenStream(LPCWSTR, PVOID, DWORD, DWORD, IStream); HRESULT CreateStorage(LPCWSTR, DWORD, DWORD, DWORD, IStorage); HRESULT OpenStorage(LPCWSTR, IStorage, DWORD, SNB, DWORD, IStorage); HRESULT CopyTo(DWORD, IID* , SNB, IStorage); HRESULT MoveElementTo(LPCWSTR, IStorage, LPCWSTR, DWORD); HRESULT Commit(DWORD); HRESULT Revert(); HRESULT EnumElements(DWORD, PVOID, DWORD, IEnumSTATSTG); HRESULT DestroyElement(LPCWSTR); HRESULT RenameElement(LPCWSTR, LPCWSTR); HRESULT SetElementTimes(LPCWSTR, FILETIME* , FILETIME* , FILETIME* ); HRESULT SetClass(REFCLSID); HRESULT SetStateBits(DWORD, DWORD); HRESULT Stat(STATSTG*, DWORD); } // FIXME: GetClassID from IPersist not there - what to do about it? interface IRootStorage : IPersist { HRESULT QueryInterface(REFIID, PVOID*); ULONG AddRef(); ULONG Release(); HRESULT SwitchToFile(LPOLESTR); } interface IRpcChannelBuffer : IUnknown { HRESULT GetBuffer(RPCOLEMESSAGE*, REFIID); HRESULT SendReceive(RPCOLEMESSAGE*, PULONG); HRESULT FreeBuffer(RPCOLEMESSAGE*); HRESULT GetDestCtx(PDWORD, PVOID*); HRESULT IsConnected(); } interface IRpcProxyBuffer : IUnknown { HRESULT Connect(IRpcChannelBuffer); void Disconnect(); } interface IRpcStubBuffer : IUnknown { HRESULT Connect(LPUNKNOWN); void Disconnect(); HRESULT Invoke(RPCOLEMESSAGE*, LPRPCSTUBBUFFER); LPRPCSTUBBUFFER IsIIDSupported(REFIID); ULONG CountRefs(); HRESULT DebugServerQueryInterface(PVOID*); HRESULT DebugServerRelease(PVOID); } interface IPSFactoryBuffer : IUnknown { HRESULT CreateProxy(LPUNKNOWN, REFIID, LPRPCPROXYBUFFER*, PVOID*); HRESULT CreateStub(REFIID, LPUNKNOWN, LPRPCSTUBBUFFER*); } alias IPSFactoryBuffer LPPSFACTORYBUFFER; interface ILockBytes : IUnknown { HRESULT ReadAt(ULARGE_INTEGER, PVOID, ULONG, ULONG*); HRESULT WriteAt(ULARGE_INTEGER, PCVOID, ULONG, ULONG*); HRESULT Flush(); HRESULT SetSize(ULARGE_INTEGER); HRESULT LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD); HRESULT UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD); HRESULT Stat(STATSTG*, DWORD); } interface IExternalConnection : IUnknown { HRESULT AddConnection(DWORD, DWORD); HRESULT ReleaseConnection(DWORD, DWORD, BOOL); } interface IRunnableObject : IUnknown { HRESULT GetRunningClass(LPCLSID); HRESULT Run(LPBC); BOOL IsRunning(); HRESULT LockRunning(BOOL, BOOL); HRESULT SetContainedObject(BOOL); } interface IROTData : IUnknown { HRESULT GetComparisonData(PVOID, ULONG, PULONG); } interface IChannelHook : IUnknown { void ClientGetSize(REFGUID, REFIID, PULONG); void ClientFillBuffer(REFGUID, REFIID, PULONG, PVOID); void ClientNotify(REFGUID, REFIID, ULONG, PVOID, DWORD, HRESULT); void ServerNotify(REFGUID, REFIID, ULONG, PVOID, DWORD); void ServerGetSize(REFGUID, REFIID, HRESULT, PULONG); void ServerFillBuffer(REFGUID, REFIID, PULONG, PVOID, HRESULT); } interface IPropertyStorage : IUnknown { HRESULT ReadMultiple(ULONG, PROPSPEC* , PROPVARIANT*); HRESULT WriteMultiple(ULONG, PROPSPEC* , PROPVARIANT*, PROPID); HRESULT DeleteMultiple(ULONG, PROPSPEC* ); HRESULT ReadPropertyNames(ULONG, PROPID* , LPWSTR*); HRESULT WritePropertyNames(ULONG, PROPID* , LPWSTR* ); HRESULT DeletePropertyNames(ULONG, PROPID* ); HRESULT SetClass(REFCLSID); HRESULT Commit(DWORD); HRESULT Revert(); HRESULT Enum(IEnumSTATPROPSTG*); HRESULT Stat(STATPROPSTG*); HRESULT SetTimes(FILETIME* , FILETIME* , FILETIME* ); } interface IPropertySetStorage : IUnknown { HRESULT Create(REFFMTID, CLSID*, DWORD, DWORD, LPPROPERTYSTORAGE*); HRESULT Open(REFFMTID, DWORD, LPPROPERTYSTORAGE*); HRESULT Delete(REFFMTID); HRESULT Enum(IEnumSTATPROPSETSTG*); } interface IClientSecurity : IUnknown { HRESULT QueryBlanket(PVOID, PDWORD, PDWORD, OLECHAR**, PDWORD, PDWORD, RPC_AUTH_IDENTITY_HANDLE**, PDWORD*); HRESULT SetBlanket(PVOID, DWORD, DWORD, LPWSTR, DWORD, DWORD, RPC_AUTH_IDENTITY_HANDLE*, DWORD); HRESULT CopyProxy(LPUNKNOWN, LPUNKNOWN*); } interface IServerSecurity : IUnknown { HRESULT QueryBlanket(PDWORD, PDWORD, OLECHAR**, PDWORD, PDWORD, RPC_AUTHZ_HANDLE*, PDWORD*); HRESULT ImpersonateClient(); HRESULT RevertToSelf(); HRESULT IsImpersonating(); } interface IClassActivator : IUnknown { HRESULT GetClassObject(REFCLSID, DWORD, LCID, REFIID, PVOID*); } interface IFillLockBytes : IUnknown { HRESULT FillAppend(void* , ULONG, PULONG); HRESULT FillAt(ULARGE_INTEGER, void* , ULONG, PULONG); HRESULT SetFillSize(ULARGE_INTEGER); HRESULT Terminate(BOOL); } interface IProgressNotify : IUnknown { HRESULT OnProgress(DWORD, DWORD, BOOL, BOOL); } interface ILayoutStorage : IUnknown { HRESULT LayoutScript(STORAGELAYOUT*, DWORD, DWORD); HRESULT BeginMonitor(); HRESULT EndMonitor(); HRESULT ReLayoutDocfile(OLECHAR*); } interface IGlobalInterfaceTable : IUnknown { HRESULT RegisterInterfaceInGlobal(IUnknown, REFIID, DWORD*); HRESULT RevokeInterfaceFromGlobal(DWORD); HRESULT GetInterfaceFromGlobal(DWORD, REFIID, void**); } /+ // These are probably unnecessary for D. extern (Windows) { HRESULT IMarshal_GetUnmarshalClass_Proxy(IMarshal, REFIID, void*, DWORD, void*, DWORD, CLSID*); void IMarshal_GetUnmarshalClass_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMarshal_GetMarshalSizeMax_Proxy(IMarshal, REFIID, void*, DWORD, void*, DWORD, DWORD*); void IMarshal_GetMarshalSizeMax_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMarshal_MarshalInterface_Proxy(IMarshal, IStream, REFIID, void*, DWORD, void*, DWORD); void IMarshal_MarshalInterface_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMarshal_UnmarshalInterface_Proxy(IMarshal, IStream, REFIID, void**); void IMarshal_UnmarshalInterface_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMarshal_ReleaseMarshalData_Proxy(IMarshal, IStream); void IMarshal_ReleaseMarshalData_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMarshal_DisconnectObject_Proxy(IMarshal, DWORD); void IMarshal_DisconnectObject_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void* IMalloc_Alloc_Proxy(IMalloc, ULONG); void IMalloc_Alloc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void* IMalloc_Realloc_Proxy(IMalloc, void*, ULONG); void IMalloc_Realloc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IMalloc_Free_Proxy(IMalloc, void*); void IMalloc_Free_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); ULONG IMalloc_GetSize_Proxy(IMalloc, void*); void IMalloc_GetSize_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); int IMalloc_DidAlloc_Proxy(IMalloc, void*); void IMalloc_DidAlloc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IMalloc_HeapMinimize_Proxy(IMalloc); void IMalloc_HeapMinimize_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); ULONG IMallocSpy_PreAlloc_Proxy(IMallocSpy, ULONG cbRequest); void IMallocSpy_PreAlloc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void* IMallocSpy_PostAlloc_Proxy(IMallocSpy, void*); void IMallocSpy_PostAlloc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void* IMallocSpy_PreFree_Proxy(IMallocSpy, void*, BOOL); void IMallocSpy_PreFree_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IMallocSpy_PostFree_Proxy(IMallocSpy, BOOL); void IMallocSpy_PostFree_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); ULONG IMallocSpy_PreRealloc_Proxy(IMallocSpy, void*, ULONG, void**, BOOL); void IMallocSpy_PreRealloc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void* IMallocSpy_PostRealloc_Proxy(IMallocSpy, void*, BOOL); void IMallocSpy_PostRealloc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void* IMallocSpy_PreGetSize_Proxy(IMallocSpy, void*, BOOL); void IMallocSpy_PreGetSize_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); ULONG IMallocSpy_PostGetSize_Proxy(IMallocSpy, ULONG, BOOL); void IMallocSpy_PostGetSize_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void* IMallocSpy_PreDidAlloc_Proxy(IMallocSpy, void*, BOOL); void IMallocSpy_PreDidAlloc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); int IMallocSpy_PostDidAlloc_Proxy(IMallocSpy, void*, BOOL, int); void IMallocSpy_PostDidAlloc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IMallocSpy_PreHeapMinimize_Proxy(IMallocSpy ); void IMallocSpy_PreHeapMinimize_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IMallocSpy_PostHeapMinimize_Proxy(IMallocSpy); void IMallocSpy_PostHeapMinimize_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStdMarshalInfo_GetClassForHandler_Proxy(IStdMarshalInfo, DWORD, void*, CLSID*); void IStdMarshalInfo_GetClassForHandler_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); DWORD IExternalConnection_AddConnection_Proxy(IExternalConnection, DWORD, DWORD); void IExternalConnection_AddConnection_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); DWORD IExternalConnection_ReleaseConnection_Proxy(IExternalConnection, DWORD, DWORD, BOOL); void IExternalConnection_ReleaseConnection_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumUnknown_RemoteNext_Proxy(IEnumUnknown, ULONG, IUnknown*, ULONG*); void IEnumUnknown_RemoteNext_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumUnknown_Skip_Proxy(IEnumUnknown, ULONG); void IEnumUnknown_Skip_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumUnknown_Reset_Proxy(IEnumUnknown ); void IEnumUnknown_Reset_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumUnknown_Clone_Proxy(IEnumUnknown, IEnumUnknown*); void IEnumUnknown_Clone_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_RegisterObjectBound_Proxy(IBindCtx, IUnknownpunk); void IBindCtx_RegisterObjectBound_Stub(IRpcStubBuffer, IRpcChannelBuffer_pRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_RevokeObjectBound_Proxy(IBindCtx, IUnknownpunk); void IBindCtx_RevokeObjectBound_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_ReleaseBoundObjects_Proxy(IBindCtx); void IBindCtx_ReleaseBoundObjects_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_SetBindOptions_Proxy(IBindCtx, BIND_OPTS*); void IBindCtx_SetBindOptions_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_GetBindOptions_Proxy(IBindCtx, BIND_OPTS*pbindopts); void IBindCtx_GetBindOptions_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_GetRunningObjectTable_Proxy(IBindCtx, IRunningObjectTable*); void IBindCtx_GetRunningObjectTable_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_RegisterObjectParam_Proxy(IBindCtx, LPCSTR, IUnknown); void IBindCtx_RegisterObjectParam_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_GetObjectParam_Proxy(IBindCtx, LPCSTR, IUnknown*); void IBindCtx_GetObjectParam_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_EnumObjectParam_Proxy(IBindCtx, IEnumString*); void IBindCtx_EnumObjectParam_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IBindCtx_RevokeObjectParam_Proxy(IBindCtx, LPCSTR); void IBindCtx_RevokeObjectParam_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumMoniker_RemoteNext_Proxy(IEnumMoniker, ULONG, IMoniker*, ULONG*); void IEnumMoniker_RemoteNext_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumMoniker_Skip_Proxy(IEnumMoniker, ULONG); void IEnumMoniker_Skip_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumMoniker_Reset_Proxy(IEnumMoniker); void IEnumMoniker_Reset_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumMoniker_Clone_Proxy(IEnumMoniker, IEnumMoniker*); void IEnumMoniker_Clone_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunnableObject_GetRunningClass_Proxy(IRunnableObject, LPCLSID); void IRunnableObject_GetRunningClass_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunnableObject_Run_Proxy(IRunnableObject, LPBINDCTX); void IRunnableObject_Run_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); BOOL IRunnableObject_IsRunning_Proxy(IRunnableObject); void IRunnableObject_IsRunning_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunnableObject_LockRunning_Proxy(IRunnableObject, BOOL, BOOL); void IRunnableObject_LockRunning_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunnableObject_SetContainedObject_Proxy(IRunnableObject, BOOL); void IRunnableObject_SetContainedObject_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunningObjectTable_Register_Proxy(IRunningObjectTable, DWORD, IUnknown, IMoniker, DWORD*); void IRunningObjectTable_Register_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunningObjectTable_Revoke_Proxy(IRunningObjectTable, DWORD); void IRunningObjectTable_Revoke_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunningObjectTable_IsRunning_Proxy(IRunningObjectTable, IMoniker); void IRunningObjectTable_IsRunning_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunningObjectTable_GetObject_Proxy(IRunningObjectTable, IMoniker, IUnknown*); void IRunningObjectTable_GetObject_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunningObjectTable_NoteChangeTime_Proxy(IRunningObjectTable, DWORD, FILETIME*); void IRunningObjectTable_NoteChangeTime_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunningObjectTable_GetTimeOfLastChange_Proxy(IRunningObjectTable, IMoniker, FILETIME*); void IRunningObjectTable_GetTimeOfLastChange_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRunningObjectTable_EnumRunning_Proxy(IRunningObjectTable, IEnumMoniker*); void IRunningObjectTable_EnumRunning_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersist_GetClassID_Proxy(IPersist, CLSID*); void IPersist_GetClassID_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStream_IsDirty_Proxy(IPersistStream); void IPersistStream_IsDirty_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStream_Load_Proxy(IPersistStream, IStream); void IPersistStream_Load_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStream_Save_Proxy(IPersistStream, IStream, BOOL); void IPersistStream_Save_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStream_GetSizeMax_Proxy(IPersistStream, ULARGE_INTEGER*); void IPersistStream_GetSizeMax_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_RemoteBindToObject_Proxy(IMoniker, IBindCtx, IMoniker, REFIID, IUnknown*); void IMoniker_RemoteBindToObject_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_RemoteBindToStorage_Proxy(IMoniker, IBindCtx, IMoniker, REFIID, IUnknown*); void IMoniker_RemoteBindToStorage_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_Reduce_Proxy(IMoniker, IBindCtx, DWORD, IMoniker*, IMoniker*); void IMoniker_Reduce_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_ComposeWith_Proxy(IMoniker, IMoniker, BOOL, IMoniker*); void IMoniker_ComposeWith_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_Enum_Proxy(IMoniker, BOOL, IEnumMoniker*); void IMoniker_Enum_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_IsEqual_Proxy(IMoniker, IMoniker); void IMoniker_IsEqual_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_Hash_Proxy(IMoniker, DWORD*); void IMoniker_Hash_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_IsRunning_Proxy(IMoniker, IBindCtx, IMoniker, IMoniker); void IMoniker_IsRunning_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_GetTimeOfLastChange_Proxy(IMoniker, IBindCtx, IMoniker, FILETIME*); void IMoniker_GetTimeOfLastChange_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_Inverse_Proxy(IMoniker, IMoniker*); void IMoniker_Inverse_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_CommonPrefixWith_Proxy(IMoniker, IMoniker, IMoniker*); void IMoniker_CommonPrefixWith_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_RelativePathTo_Proxy(IMoniker, IMoniker, IMoniker*); void IMoniker_RelativePathTo_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_GetDisplayName_Proxy(IMoniker, IBindCtx, IMoniker, LPCSTR*); void IMoniker_GetDisplayName_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_ParseDisplayName_Proxy(IMoniker, IBindCtx, IMoniker, LPCSTR, ULONG*, IMoniker*); void IMoniker_ParseDisplayName_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IMoniker_IsSystemMoniker_Proxy(IMoniker, DWORD*); void IMoniker_IsSystemMoniker_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IROTData_GetComparisonData_Proxy(IROTData, BYTE*, ULONG cbMax, ULONG*); void IROTData_GetComparisonData_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumString_RemoteNext_Proxy(IEnumString, ULONG, LPCSTR*rgelt, ULONG*); void IEnumString_RemoteNext_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumString_Skip_Proxy(IEnumString, ULONG); void IEnumString_Skip_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumString_Reset_Proxy(IEnumString); void IEnumString_Reset_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumString_Clone_Proxy(IEnumString, IEnumString*); void IEnumString_Clone_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_RemoteRead_Proxy(IStream, BYTE*, ULONG, ULONG*); void IStream_RemoteRead_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_RemoteWrite_Proxy(IStream, BYTE*pv, ULONG, ULONG*); void IStream_RemoteWrite_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_RemoteSeek_Proxy(IStream, LARGE_INTEGER, DWORD, ULARGE_INTEGER*); void IStream_RemoteSeek_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_SetSize_Proxy(IStream, ULARGE_INTEGER); void IStream_SetSize_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_RemoteCopyTo_Proxy(IStream, IStream, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*); void IStream_RemoteCopyTo_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_Commit_Proxy(IStream, DWORD); void IStream_Commit_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_Revert_Proxy(IStream); void IStream_Revert_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_LockRegion_Proxy(IStream, ULARGE_INTEGER, ULARGE_INTEGER, DWORD); void IStream_LockRegion_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_UnlockRegion_Proxy(IStream, ULARGE_INTEGER, ULARGE_INTEGER, DWORD); void IStream_UnlockRegion_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_Stat_Proxy(IStream, STATSTG*, DWORD); void IStream_Stat_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStream_Clone_Proxy(IStream, IStream*); void IStream_Clone_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumSTATSTG_RemoteNext_Proxy(IEnumSTATSTG, ULONG, STATSTG*, ULONG*); void IEnumSTATSTG_RemoteNext_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumSTATSTG_Skip_Proxy(IEnumSTATSTG, ULONG celt); void IEnumSTATSTG_Skip_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumSTATSTG_Reset_Proxy(IEnumSTATSTG); void IEnumSTATSTG_Reset_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumSTATSTG_Clone_Proxy(IEnumSTATSTG, IEnumSTATSTG*); void IEnumSTATSTG_Clone_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_CreateStream_Proxy(IStorage, OLECHAR*, DWORD, DWORD, DWORD, IStream*); void IStorage_CreateStream_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_RemoteOpenStream_Proxy(IStorage, const(OLECHAR)*, uint, BYTE*, DWORD, DWORD, IStream*); void IStorage_RemoteOpenStream_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_CreateStorage_Proxy(IStorage, OLECHAR*, DWORD, DWORD, DWORD, IStorage*); void IStorage_CreateStorage_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_OpenStorage_Proxy(IStorage, OLECHAR*, IStorage, DWORD, SNB, DWORD, IStorage*); void IStorage_OpenStorage_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_CopyTo_Proxy(IStorage, DWORD, const(IID)*, SNB, IStorage); void IStorage_CopyTo_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_MoveElementTo_Proxy(IStorage, const(OLECHAR)*, IStorage, const(OLECHAR)*, DWORD); void IStorage_MoveElementTo_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_Commit_Proxy(IStorage, DWORD); void IStorage_Commit_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_Revert_Proxy(IStorage); void IStorage_Revert_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_RemoteEnumElements_Proxy(IStorage, DWORD, uint, BYTE*, DWORD, IEnumSTATSTG*); void IStorage_RemoteEnumElements_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_DestroyElement_Proxy(IStorage, OLECHAR*); void IStorage_DestroyElement_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_RenameElement_Proxy(IStorage, const(OLECHAR)*, const(OLECHAR)*); void IStorage_RenameElement_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_SetElementTimes_Proxy(IStorage, const(OLECHAR)*, const(FILETIME)*, const(FILETIME)*, const(FILETIME)*); void IStorage_SetElementTimes_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_SetClass_Proxy(IStorage, REFCLSID); void IStorage_SetClass_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_SetStateBits_Proxy(IStorage, DWORD, DWORD); void IStorage_SetStateBits_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IStorage_Stat_Proxy(IStorage, STATSTG*, DWORD); void IStorage_Stat_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistFile_IsDirty_Proxy(IPersistFile); void IPersistFile_IsDirty_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistFile_Load_Proxy(IPersistFile, LPCOLESTR, DWORD); void IPersistFile_Load_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistFile_Save_Proxy(IPersistFile, LPCOLESTR pszFileName, BOOL); void IPersistFile_Save_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistFile_SaveCompleted_Proxy(IPersistFile, LPCOLESTR); void IPersistFile_SaveCompleted_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistFile_GetCurFile_Proxy(IPersistFile, LPCSTR*); void IPersistFile_GetCurFile_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStorage_IsDirty_Proxy(IPersistStorage); void IPersistStorage_IsDirty_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStorage_InitNew_Proxy(IPersistStorage, IStorage); void IPersistStorage_InitNew_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStorage_Load_Proxy(IPersistStorage, IStorage); void IPersistStorage_Load_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStorage_Save_Proxy(IPersistStorage, IStorage, BOOL); void IPersistStorage_Save_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStorage_SaveCompleted_Proxy(IPersistStorage, IStorage); void IPersistStorage_SaveCompleted_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPersistStorage_HandsOffStorage_Proxy(IPersistStorage); void IPersistStorage_HandsOffStorage_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT ILockBytes_RemoteReadAt_Proxy(ILockBytes, ULARGE_INTEGER, BYTE*, ULONG, ULONG*); void ILockBytes_RemoteReadAt_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT ILockBytes_RemoteWriteAt_Proxy(ILockBytes, ULARGE_INTEGER, BYTE*pv, ULONG, ULONG*); void ILockBytes_RemoteWriteAt_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT ILockBytes_Flush_Proxy(ILockBytes); void ILockBytes_Flush_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT ILockBytes_SetSize_Proxy(ILockBytes, ULARGE_INTEGER); void ILockBytes_SetSize_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT ILockBytes_LockRegion_Proxy(ILockBytes, ULARGE_INTEGER, ULARGE_INTEGER, DWORD); void ILockBytes_LockRegion_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT ILockBytes_UnlockRegion_Proxy(ILockBytes, ULARGE_INTEGER, ULARGE_INTEGER, DWORD); void ILockBytes_UnlockRegion_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT ILockBytes_Stat_Proxy(ILockBytes, STATSTG*, DWORD); void ILockBytes_Stat_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumFORMATETC_RemoteNext_Proxy(IEnumFORMATETC, ULONG, FORMATETC*, ULONG*); void IEnumFORMATETC_RemoteNext_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumFORMATETC_Skip_Proxy(IEnumFORMATETC, ULONG); void IEnumFORMATETC_Skip_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumFORMATETC_Reset_Proxy(IEnumFORMATETC); void IEnumFORMATETC_Reset_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumFORMATETC_Clone_Proxy(IEnumFORMATETC, IEnumFORMATETC*); void IEnumFORMATETC_Clone_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumFORMATETC_Next_Proxy(IEnumFORMATETC, ULONG, FORMATETC*, ULONG*); HRESULT IEnumFORMATETC_Next_Stub(IEnumFORMATETC, ULONG, FORMATETC*, ULONG*); HRESULT IEnumSTATDATA_RemoteNext_Proxy(IEnumSTATDATA, ULONG, STATDATA*, ULONG*); void IEnumSTATDATA_RemoteNext_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumSTATDATA_Skip_Proxy(IEnumSTATDATA, ULONG); void IEnumSTATDATA_Skip_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumSTATDATA_Reset_Proxy(IEnumSTATDATA); void IEnumSTATDATA_Reset_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumSTATDATA_Clone_Proxy(IEnumSTATDATA, IEnumSTATDATA*); void IEnumSTATDATA_Clone_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IEnumSTATDATA_Next_Proxy(IEnumSTATDATA, ULONG, STATDATA*, ULONG*); HRESULT IEnumSTATDATA_Next_Stub(IEnumSTATDATA, ULONG, STATDATA*, ULONG*); HRESULT IRootStorage_SwitchToFile_Proxy(IRootStorage, LPCSTR); void IRootStorage_SwitchToFile_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IAdviseSink_RemoteOnDataChange_Proxy(IAdviseSink, FORMATETC*, RemSTGMEDIUM*); void IAdviseSink_RemoteOnDataChange_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IAdviseSink_RemoteOnViewChange_Proxy(IAdviseSink, DWORD, LONG); void IAdviseSink_RemoteOnViewChange_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IAdviseSink_RemoteOnRename_Proxy(IAdviseSink, IMoniker); void IAdviseSink_RemoteOnRename_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IAdviseSink_RemoteOnSave_Proxy(IAdviseSink); void IAdviseSink_RemoteOnSave_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IAdviseSink_RemoteOnClose_Proxy(IAdviseSink); void IAdviseSink_RemoteOnClose_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IAdviseSink_OnDataChange_Proxy(IAdviseSink, FORMATETC*, STGMEDIUM*); void IAdviseSink_OnDataChange_Stub(IAdviseSink, FORMATETC*, RemSTGMEDIUM*); void IAdviseSink_OnViewChange_Proxy(IAdviseSink, DWORD, LONG); void IAdviseSink_OnViewChange_Stub(IAdviseSink, DWORD, LONG); void IAdviseSink_OnRename_Proxy(IAdviseSink, IMoniker); void IAdviseSink_OnRename_Stub(IAdviseSink, IMoniker); void IAdviseSink_OnSave_Proxy(IAdviseSink); void IAdviseSink_OnSave_Stub(IAdviseSink); void IAdviseSink_OnClose_Proxy(IAdviseSink); HRESULT IAdviseSink_OnClose_Stub(IAdviseSink); void IAdviseSink2_RemoteOnLinkSrcChange_Proxy(IAdviseSink2, IMoniker); void IAdviseSink2_RemoteOnLinkSrcChange_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IAdviseSink2_OnLinkSrcChange_Proxy(IAdviseSink2, IMoniker); void IAdviseSink2_OnLinkSrcChange_Stub(IAdviseSink2, IMoniker); HRESULT IDataObject_RemoteGetData_Proxy(IDataObject, FORMATETC*, RemSTGMEDIUM**); void IDataObject_RemoteGetData_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataObject_RemoteGetDataHere_Proxy(IDataObject, FORMATETC*, RemSTGMEDIUM**); void IDataObject_RemoteGetDataHere_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataObject_QueryGetData_Proxy(IDataObject, FORMATETC*); void IDataObject_QueryGetData_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataObject_GetCanonicalFormatEtc_Proxy(IDataObject, FORMATETC*, FORMATETC*); void IDataObject_GetCanonicalFormatEtc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataObject_RemoteSetData_Proxy(IDataObject, FORMATETC*, RemSTGMEDIUM*, BOOL); void IDataObject_RemoteSetData_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataObject_EnumFormatEtc_Proxy(IDataObject, DWORD, IEnumFORMATETC*); void IDataObject_EnumFormatEtc_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataObject_DAdvise_Proxy(IDataObject, FORMATETC*, DWORD, IAdviseSink, DWORD*); void IDataObject_DAdvise_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataObject_DUnadvise_Proxy(IDataObject, DWORD); void IDataObject_DUnadvise_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataObject_EnumDAdvise_Proxy(IDataObject, IEnumSTATDATA*); void IDataObject_EnumDAdvise_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataObject_GetData_Proxy(IDataObject, FORMATETC*, STGMEDIUM*); HRESULT IDataObject_GetData_Stub(IDataObject, FORMATETC*, RemSTGMEDIUM**); HRESULT IDataObject_GetDataHere_Proxy(IDataObject, FORMATETC*, STGMEDIUM*); HRESULT IDataObject_GetDataHere_Stub(IDataObject, FORMATETC*, RemSTGMEDIUM**); HRESULT IDataObject_SetData_Proxy(IDataObject, FORMATETC*, STGMEDIUM*, BOOL); HRESULT IDataObject_SetData_Stub(IDataObject, FORMATETC*, RemSTGMEDIUM*, BOOL); HRESULT IDataAdviseHolder_Advise_Proxy(IDataAdviseHolder, IDataObject, FORMATETC*, DWORD, IAdviseSink, DWORD*); void IDataAdviseHolder_Advise_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataAdviseHolder_Unadvise_Proxy(IDataAdviseHolder, DWORD); void IDataAdviseHolder_Unadvise_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataAdviseHolder_EnumAdvise_Proxy(IDataAdviseHolder, IEnumSTATDATA*); void IDataAdviseHolder_EnumAdvise_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IDataAdviseHolder_SendOnDataChange_Proxy(IDataAdviseHolder, IDataObject, DWORD, DWORD); void IDataAdviseHolder_SendOnDataChange_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); DWORD IMessageFilter_HandleInComingCall_Proxy(IMessageFilter, DWORD, HTASK, DWORD, LPINTERFACEINFO); void IMessageFilter_HandleInComingCall_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); DWORD IMessageFilter_RetryRejectedCall_Proxy(IMessageFilter, HTASK, DWORD, DWORD); void IMessageFilter_RetryRejectedCall_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); DWORD IMessageFilter_MessagePending_Proxy(IMessageFilter, HTASK, DWORD, DWORD); void IMessageFilter_MessagePending_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRpcChannelBuffer_GetBuffer_Proxy(IRpcChannelBuffer, RPCOLEMESSAGE*, REFIID); void IRpcChannelBuffer_GetBuffer_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRpcChannelBuffer_SendReceive_Proxy(IRpcChannelBuffer, RPCOLEMESSAGE*, ULONG*); void IRpcChannelBuffer_SendReceive_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRpcChannelBuffer_FreeBuffer_Proxy(IRpcChannelBuffer, RPCOLEMESSAGE*); void IRpcChannelBuffer_FreeBuffer_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRpcChannelBuffer_GetDestCtx_Proxy(IRpcChannelBuffer, DWORD*, void**); void IRpcChannelBuffer_GetDestCtx_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRpcChannelBuffer_IsConnected_Proxy(IRpcChannelBuffer); void IRpcChannelBuffer_IsConnected_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRpcProxyBuffer_Connect_Proxy(IRpcProxyBuffer, IRpcChannelBufferpRpcChannelBuffer); void IRpcProxyBuffer_Connect_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IRpcProxyBuffer_Disconnect_Proxy(IRpcProxyBuffer); void IRpcProxyBuffer_Disconnect_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRpcStubBuffer_Connect_Proxy(IRpcStubBuffer, IUnknown); void IRpcStubBuffer_Connect_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IRpcStubBuffer_Disconnect_Proxy(IRpcStubBuffer); void IRpcStubBuffer_Disconnect_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRpcStubBuffer_Invoke_Proxy(IRpcStubBuffer, RPCOLEMESSAGE*, IRpcChannelBuffer); void IRpcStubBuffer_Invoke_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); IRpcStubBufferIRpcStubBuffer_IsIIDSupported_Proxy(IRpcStubBuffer, REFIID); void IRpcStubBuffer_IsIIDSupported_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); ULONG IRpcStubBuffer_CountRefs_Proxy(IRpcStubBuffer); void IRpcStubBuffer_CountRefs_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IRpcStubBuffer_DebugServerQueryInterface_Proxy(IRpcStubBuffer, void**); void IRpcStubBuffer_DebugServerQueryInterface_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void IRpcStubBuffer_DebugServerRelease_Proxy(IRpcStubBuffer, void*); void IRpcStubBuffer_DebugServerRelease_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPSFactoryBuffer_CreateProxy_Proxy(IPSFactoryBuffer, IUnknown, REFIID, IRpcProxyBuffer*, void**); void IPSFactoryBuffer_CreateProxy_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); HRESULT IPSFactoryBuffer_CreateStub_Proxy(IPSFactoryBuffer, REFIID, IUnknown, IRpcStubBuffer*); void IPSFactoryBuffer_CreateStub_Stub(IRpcStubBuffer, IRpcChannelBuffer, PRPC_MESSAGE, PDWORD); void SNB_to_xmit(SNB*, RemSNB**); void SNB_from_xmit(RemSNB*, SNB*); void SNB_free_inst(SNB*); void SNB_free_xmit(RemSNB*); HRESULT IEnumUnknown_Next_Proxy(IEnumUnknown, ULONG, IUnknown*, ULONG*); HRESULT IEnumUnknown_Next_Stub(IEnumUnknown, ULONG, IUnknown*, ULONG*); HRESULT IEnumMoniker_Next_Proxy(IEnumMoniker, ULONG, IMoniker*, ULONG*); HRESULT IEnumMoniker_Next_Stub(IEnumMoniker, ULONG, IMoniker*, ULONG*); HRESULT IMoniker_BindToObject_Proxy(IMoniker, IBindCtx, IMoniker, REFIID, void**); HRESULT IMoniker_BindToObject_Stub(IMoniker, IBindCtx, IMoniker, REFIID, IUnknown*); HRESULT IMoniker_BindToStorage_Proxy(IMoniker, IBindCtx, IMoniker, REFIID, void**); HRESULT IMoniker_BindToStorage_Stub(IMoniker, IBindCtx, IMoniker, REFIID, IUnknown*); HRESULT IEnumString_Next_Proxy(IEnumString, ULONG, LPCSTR*, ULONG*); HRESULT IEnumString_Next_Stub(IEnumString, ULONG, LPCSTR*, ULONG*); HRESULT IStream_Read_Proxy(IStream, void*, ULONG, ULONG*); HRESULT IStream_Read_Stub(IStream, BYTE*, ULONG, ULONG*); HRESULT IStream_Write_Proxy(IStream, void*, ULONG, ULONG*); HRESULT IStream_Write_Stub(IStream, BYTE*, ULONG, ULONG*); HRESULT IStream_Seek_Proxy(IStream, LARGE_INTEGER, DWORD, ULARGE_INTEGER*); HRESULT IStream_Seek_Stub(IStream, LARGE_INTEGER, DWORD, ULARGE_INTEGER*); HRESULT IStream_CopyTo_Proxy(IStream, IStream, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*); HRESULT IStream_CopyTo_Stub(IStream, IStream, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*); HRESULT IEnumSTATSTG_Next_Proxy(IEnumSTATSTG, ULONG, STATSTG*, ULONG*); HRESULT IEnumSTATSTG_Next_Stub(IEnumSTATSTG, ULONG, STATSTG*, ULONG*); HRESULT IStorage_OpenStream_Proxy(IStorage, OLECHAR*, void*, DWORD, DWORD, IStream*); HRESULT IStorage_OpenStream_Stub(IStorage, OLECHAR*, uint, BYTE*, DWORD, DWORD, IStream* ); HRESULT IStorage_EnumElements_Proxy(IStorage, DWORD, void*, DWORD, IEnumSTATSTG*); HRESULT IStorage_EnumElements_Stub(IStorage, DWORD, uint, BYTE*, DWORD, IEnumSTATSTG*); HRESULT ILockBytes_ReadAt_Proxy(ILockBytes, ULARGE_INTEGER, void*, ULONG, ULONG*); HRESULT ILockBytes_ReadAt_Stub(ILockBytes, ULARGE_INTEGER, BYTE*, ULONG, ULONG*); HRESULT ILockBytes_WriteAt_Proxy(ILockBytes, ULARGE_INTEGER, const(void)*, ULONG, ULONG*); HRESULT ILockBytes_WriteAt_Stub(ILockBytes, ULARGE_INTEGER, BYTE*, ULONG, ULONG*); } +/ ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/iptypes.d0000664000175000017500000000547312776214756023365 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_iptypes.d) */ module core.sys.windows.iptypes; version (Windows): import core.sys.windows.windef; version(Tango){ private import tango.stdc.time; }else{ version (D_Version2) import core.stdc.time; else import std.c.time; } //#include enum size_t DEFAULT_MINIMUM_ENTITIES = 32, MAX_ADAPTER_ADDRESS_LENGTH = 8, MAX_ADAPTER_DESCRIPTION_LENGTH = 128, MAX_ADAPTER_NAME_LENGTH = 256, MAX_DOMAIN_NAME_LEN = 128, MAX_HOSTNAME_LEN = 128, MAX_SCOPE_ID_LEN = 256; enum UINT BROADCAST_NODETYPE = 1, PEER_TO_PEER_NODETYPE = 2, MIXED_NODETYPE = 4, HYBRID_NODETYPE = 8; enum : UINT { IF_OTHER_ADAPTERTYPE, IF_ETHERNET_ADAPTERTYPE, IF_TOKEN_RING_ADAPTERTYPE, IF_FDDI_ADAPTERTYPE, IF_PPP_ADAPTERTYPE, IF_LOOPBACK_ADAPTERTYPE // = 5 } struct IP_ADDRESS_STRING { char[16] String; } alias IP_ADDRESS_STRING IP_MASK_STRING; alias IP_ADDRESS_STRING* PIP_ADDRESS_STRING, PIP_MASK_STRING; struct IP_ADDR_STRING { IP_ADDR_STRING* Next; IP_ADDRESS_STRING IpAddress; IP_MASK_STRING IpMask; DWORD Context; } alias IP_ADDR_STRING* PIP_ADDR_STRING; struct IP_ADAPTER_INFO { IP_ADAPTER_INFO* Next; DWORD ComboIndex; char[MAX_ADAPTER_NAME_LENGTH+4] AdapterName; char[MAX_ADAPTER_DESCRIPTION_LENGTH+4] Description; UINT AddressLength; BYTE[MAX_ADAPTER_ADDRESS_LENGTH] Address; DWORD Index; UINT Type; UINT DhcpEnabled; PIP_ADDR_STRING CurrentIpAddress; IP_ADDR_STRING IpAddressList; IP_ADDR_STRING GatewayList; IP_ADDR_STRING DhcpServer; BOOL HaveWins; IP_ADDR_STRING PrimaryWinsServer; IP_ADDR_STRING SecondaryWinsServer; time_t LeaseObtained; time_t LeaseExpires; } alias IP_ADAPTER_INFO* PIP_ADAPTER_INFO; struct IP_PER_ADAPTER_INFO { UINT AutoconfigEnabled; UINT AutoconfigActive; PIP_ADDR_STRING CurrentDnsServer; IP_ADDR_STRING DnsServerList; } alias IP_PER_ADAPTER_INFO* PIP_PER_ADAPTER_INFO; struct FIXED_INFO { char[MAX_HOSTNAME_LEN+4] HostName; char[MAX_DOMAIN_NAME_LEN+4] DomainName; PIP_ADDR_STRING CurrentDnsServer; IP_ADDR_STRING DnsServerList; UINT NodeType; char[MAX_SCOPE_ID_LEN+4] ScopeId; UINT EnableRouting; UINT EnableProxy; UINT EnableDns; } alias FIXED_INFO* PFIXED_INFO; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ipexport.d0000664000175000017500000000505112776214756023532 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ipexport.d) */ module core.sys.windows.ipexport; version (Windows): private import core.sys.windows.windef; enum size_t MAX_ADAPTER_NAME = 128; // IP STATUS flags enum : IP_STATUS { IP_SUCCESS = 0, IP_STATUS_BASE = 11000, IP_BUF_TOO_SMALL, IP_DEST_NET_UNREACHABLE, IP_DEST_HOST_UNREACHABLE, IP_DEST_PROT_UNREACHABLE, IP_DEST_PORT_UNREACHABLE, IP_NO_RESOURCES, IP_BAD_OPTION, IP_HW_ERROR, IP_PACKET_TOO_BIG, IP_REQ_TIMED_OUT, IP_BAD_REQ, IP_BAD_ROUTE, IP_TTL_EXPIRED_TRANSIT, IP_TTL_EXPIRED_REASSEM, IP_PARAM_PROBLEM, IP_SOURCE_QUENCH, IP_OPTION_TOO_BIG, IP_BAD_DESTINATION, IP_ADDR_DELETED, IP_SPEC_MTU_CHANGE, IP_MTU_CHANGE, IP_UNLOAD, // = IP_STATUS_BASE + 22 IP_GENERAL_FAILURE = IP_STATUS_BASE + 50, MAX_IP_STATUS = IP_GENERAL_FAILURE, IP_PENDING = IP_STATUS_BASE + 255 } // IP header Flags values enum byte IP_FLAG_DF = 2; // IP Option types enum : ubyte { IP_OPT_EOL = 0, IP_OPT_NOP = 0x01, IP_OPT_RR = 0x07, IP_OPT_SECURITY = 0x82, IP_OPT_LSRR = 0x83, IP_OPT_SSRR = 0x89, IP_OPT_TS = 0x44, IP_OPT_SID = 0x88, IP_OPT_ROUTER_ALERT = 0x94 } enum ubyte MAX_OPT_SIZE = 40; alias uint IPAddr, IPMask, IP_STATUS; struct IP_OPTION_INFORMATION { ubyte Ttl; ubyte Tos; ubyte Flags; ubyte OptionsSize; ubyte* OptionsData; } alias IP_OPTION_INFORMATION* PIP_OPTION_INFORMATION; struct ICMP_ECHO_REPLY { IPAddr Address; uint Status; uint RoundTripTime; ushort DataSize; ushort Reserved; void* Data; IP_OPTION_INFORMATION Options; } alias ICMP_ECHO_REPLY* PICMP_ECHO_REPLY; struct IP_ADAPTER_INDEX_MAP { ULONG Index; WCHAR[MAX_ADAPTER_NAME] Name; } alias IP_ADAPTER_INDEX_MAP* PIP_ADAPTER_INDEX_MAP; struct IP_INTERFACE_INFO { LONG NumAdapters; IP_ADAPTER_INDEX_MAP[1] _Adapter; IP_ADAPTER_INDEX_MAP* Adapter() return { return _Adapter.ptr; } } alias IP_INTERFACE_INFO* PIP_INTERFACE_INFO; struct IP_UNIDIRECTIONAL_ADAPTER_ADDRESS { ULONG NumAdapters; IPAddr[1] _Address; IPAddr* Address() return { return _Address.ptr; } } alias IP_UNIDIRECTIONAL_ADAPTER_ADDRESS* PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/oleacc.d0000664000175000017500000001544712776214756023120 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_oleacc.d) */ module core.sys.windows.oleacc; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "oleacc"); private import core.sys.windows.basetyps, core.sys.windows.oaidl, core.sys.windows.unknwn, core.sys.windows.wtypes, core.sys.windows.windef; enum { DISPID_ACC_PARENT = -5000, DISPID_ACC_CHILDCOUNT = -5001, DISPID_ACC_CHILD = -5002, DISPID_ACC_NAME = -5003, DISPID_ACC_VALUE = -5004, DISPID_ACC_DESCRIPTION = -5005, DISPID_ACC_ROLE = -5006, DISPID_ACC_STATE = -5007, DISPID_ACC_HELP = -5008, DISPID_ACC_HELPTOPIC = -5009, DISPID_ACC_KEYBOARDSHORTCUT = -5010, DISPID_ACC_FOCUS = -5011, DISPID_ACC_SELECTION = -5012, DISPID_ACC_DEFAULTACTION = -5013, DISPID_ACC_SELECT = -5014, DISPID_ACC_LOCATION = -5015, DISPID_ACC_NAVIGATE = -5016, DISPID_ACC_HITTEST = -5017, DISPID_ACC_DODEFAULTACTION = -5018 } enum { NAVDIR_UP = 1, NAVDIR_DOWN, NAVDIR_LEFT, NAVDIR_RIGHT, NAVDIR_NEXT, NAVDIR_PREVIOUS, NAVDIR_FIRSTCHILD, NAVDIR_LASTCHILD // = 8 } enum { ROLE_SYSTEM_TITLEBAR = 1, ROLE_SYSTEM_MENUBAR, ROLE_SYSTEM_SCROLLBAR, ROLE_SYSTEM_GRIP, ROLE_SYSTEM_SOUND, ROLE_SYSTEM_CURSOR, ROLE_SYSTEM_CARET, ROLE_SYSTEM_ALERT, ROLE_SYSTEM_WINDOW, ROLE_SYSTEM_CLIENT, ROLE_SYSTEM_MENUPOPUP, ROLE_SYSTEM_MENUITEM, ROLE_SYSTEM_TOOLTIP, ROLE_SYSTEM_APPLICATION, ROLE_SYSTEM_DOCUMENT, ROLE_SYSTEM_PANE, ROLE_SYSTEM_CHART, ROLE_SYSTEM_DIALOG, ROLE_SYSTEM_BORDER, ROLE_SYSTEM_GROUPING, ROLE_SYSTEM_SEPARATOR, ROLE_SYSTEM_TOOLBAR, ROLE_SYSTEM_STATUSBAR, ROLE_SYSTEM_TABLE, ROLE_SYSTEM_COLUMNHEADER, ROLE_SYSTEM_ROWHEADER, ROLE_SYSTEM_COLUMN, ROLE_SYSTEM_ROW, ROLE_SYSTEM_CELL, ROLE_SYSTEM_LINK, ROLE_SYSTEM_HELPBALLOON, ROLE_SYSTEM_CHARACTER, ROLE_SYSTEM_LIST, ROLE_SYSTEM_LISTITEM, ROLE_SYSTEM_OUTLINE, ROLE_SYSTEM_OUTLINEITEM, ROLE_SYSTEM_PAGETAB, ROLE_SYSTEM_PROPERTYPAGE, ROLE_SYSTEM_INDICATOR, ROLE_SYSTEM_GRAPHIC, ROLE_SYSTEM_STATICTEXT, ROLE_SYSTEM_TEXT, ROLE_SYSTEM_PUSHBUTTON, ROLE_SYSTEM_CHECKBUTTON, ROLE_SYSTEM_RADIOBUTTON, ROLE_SYSTEM_COMBOBOX, ROLE_SYSTEM_DROPLIST, ROLE_SYSTEM_PROGRESSBAR, ROLE_SYSTEM_DIAL, ROLE_SYSTEM_HOTKEYFIELD, ROLE_SYSTEM_SLIDER, ROLE_SYSTEM_SPINBUTTON, ROLE_SYSTEM_DIAGRAM, ROLE_SYSTEM_ANIMATION, ROLE_SYSTEM_EQUATION, ROLE_SYSTEM_BUTTONDROPDOWN, ROLE_SYSTEM_BUTTONMENU, ROLE_SYSTEM_BUTTONDROPDOWNGRID, ROLE_SYSTEM_WHITESPACE, ROLE_SYSTEM_PAGETABLIST, ROLE_SYSTEM_CLOCK // = 61 } enum { STATE_SYSTEM_UNAVAILABLE = 0x00000001, STATE_SYSTEM_SELECTED = 0x00000002, STATE_SYSTEM_FOCUSED = 0x00000004, STATE_SYSTEM_PRESSED = 0x00000008, STATE_SYSTEM_CHECKED = 0x00000010, STATE_SYSTEM_MIXED = 0x00000020, STATE_SYSTEM_READONLY = 0x00000040, STATE_SYSTEM_HOTTRACKED = 0x00000080, STATE_SYSTEM_DEFAULT = 0x00000100, STATE_SYSTEM_EXPANDED = 0x00000200, STATE_SYSTEM_COLLAPSED = 0x00000400, STATE_SYSTEM_BUSY = 0x00000800, STATE_SYSTEM_FLOATING = 0x00001000, STATE_SYSTEM_MARQUEED = 0x00002000, STATE_SYSTEM_ANIMATED = 0x00004000, STATE_SYSTEM_INVISIBLE = 0x00008000, STATE_SYSTEM_OFFSCREEN = 0x00010000, STATE_SYSTEM_SIZEABLE = 0x00020000, STATE_SYSTEM_MOVEABLE = 0x00040000, STATE_SYSTEM_SELFVOICING = 0x00080000, STATE_SYSTEM_FOCUSABLE = 0x00100000, STATE_SYSTEM_SELECTABLE = 0x00200000, STATE_SYSTEM_LINKED = 0x00400000, STATE_SYSTEM_TRAVERSED = 0x00800000, STATE_SYSTEM_MULTISELECTABLE = 0x01000000, STATE_SYSTEM_EXTSELECTABLE = 0x02000000, STATE_SYSTEM_ALERT_LOW = 0x04000000, STATE_SYSTEM_ALERT_MEDIUM = 0x08000000, STATE_SYSTEM_ALERT_HIGH = 0x10000000, STATE_SYSTEM_VALID = 0x1fffffff } enum SELFLAG { SELFLAG_NONE = 0, SELFLAG_TAKEFOCUS = 1, SELFLAG_TAKESELECTION = 2, SELFLAG_EXTENDSELECTION = 4, SELFLAG_ADDSELECTION = 8, SELFLAG_REMOVESELECTION = 16 } enum SELFLAG_VALID = 0x0000001F; interface IAccessible : IDispatch { HRESULT get_accParent(IDispatch*); HRESULT get_accChildCount(int*); HRESULT get_accChild(VARIANT, IDispatch*); HRESULT get_accName(VARIANT, BSTR*); HRESULT get_accValue(VARIANT, BSTR*); HRESULT get_accDescription(VARIANT, BSTR*); HRESULT get_accRole(VARIANT, VARIANT*); HRESULT get_accState(VARIANT, VARIANT*); HRESULT get_accHelp(VARIANT, BSTR*); HRESULT get_accHelpTopic(BSTR*, VARIANT, int*); HRESULT get_accKeyboardShortcut(VARIANT, BSTR*); HRESULT get_accFocus(VARIANT*); HRESULT get_accSelection(VARIANT*); HRESULT get_accDefaultAction(VARIANT, BSTR*); HRESULT accSelect(int, VARIANT); HRESULT accLocation(int*, int*, int*, int*, VARIANT); HRESULT accNavigate(int, VARIANT, VARIANT*); HRESULT accHitTest(int, int, VARIANT*); HRESULT accDoDefaultAction(VARIANT); HRESULT put_accName(VARIANT, BSTR); HRESULT put_accValue(VARIANT, BSTR); } alias IAccessible LPACCESSIBLE; extern (Windows) { HRESULT AccessibleChildren(IAccessible, LONG, LONG, VARIANT*, LONG*); HRESULT AccessibleObjectFromEvent(HWND, DWORD, DWORD, IAccessible, VARIANT*); HRESULT AccessibleObjectFromPoint(POINT, IAccessible*, VARIANT*); HRESULT AccessibleObjectFromWindow(HWND, DWORD, REFIID, void**); HRESULT CreateStdAccessibleObject(HWND, LONG, REFIID, void**); HRESULT CreateStdAccessibleProxyA(HWND, LPCSTR, LONG, REFIID, void**); HRESULT CreateStdAccessibleProxyW(HWND, LPCWSTR, LONG, REFIID, void**); void GetOleaccVersionInfo(DWORD*, DWORD*); UINT GetRoleTextA(DWORD, LPSTR, UINT); UINT GetRoleTextW(DWORD, LPWSTR, UINT); UINT GetStateTextA(DWORD, LPSTR, UINT); UINT GetStateTextW(DWORD, LPWSTR, UINT); LRESULT LresultFromObject(REFIID, WPARAM, LPUNKNOWN); HRESULT ObjectFromLresult(LRESULT, REFIID, WPARAM, void**); HRESULT WindowFromAccessibleObject(IAccessible, HWND*); } version(Unicode) { alias CreateStdAccessibleProxyW CreateStdAccessibleProxy; alias GetRoleTextW GetRoleText; alias GetStateTextW GetStateText; } else { alias CreateStdAccessibleProxyA CreateStdAccessibleProxy; alias GetRoleTextA GetRoleText; alias GetStateTextA GetStateText; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winver.d0000664000175000017500000001117212776214756023173 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winver.d) */ module core.sys.windows.winver; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "version"); private import core.sys.windows.windef; // FIXME: type weirdness enum { VS_FILE_INFO = 16, VS_VERSION_INFO = 1, VS_USER_DEFINED = 100 } enum { VS_FFI_SIGNATURE = 0xFEEF04BD, VS_FFI_STRUCVERSION = 0x10000, VS_FFI_FILEFLAGSMASK = 0x3F } enum { VS_FF_DEBUG = 1, VS_FF_PRERELEASE = 2, VS_FF_PATCHED = 4, VS_FF_PRIVATEBUILD = 8, VS_FF_INFOINFERRED = 16, VS_FF_SPECIALBUILD = 32 } enum { VOS_UNKNOWN = 0, VOS_DOS = 0x10000, VOS_OS216 = 0x20000, VOS_OS232 = 0x30000, VOS_NT = 0x40000, VOS__BASE = 0, VOS__WINDOWS16 = 1, VOS__PM16 = 2, VOS__PM32 = 3, VOS__WINDOWS32 = 4, VOS_DOS_WINDOWS16 = 0x10001, VOS_DOS_WINDOWS32 = 0x10004, VOS_OS216_PM16 = 0x20002, VOS_OS232_PM32 = 0x30003, VOS_NT_WINDOWS32 = 0x40004 } enum { VFT_UNKNOWN = 0, VFT_APP = 1, VFT_DLL = 2, VFT_DRV = 3, VFT_FONT = 4, VFT_VXD = 5, VFT_STATIC_LIB = 7 } enum { VFT2_UNKNOWN = 0, VFT2_DRV_PRINTER = 1, VFT2_DRV_KEYBOARD = 2, VFT2_DRV_LANGUAGE = 3, VFT2_DRV_DISPLAY = 4, VFT2_DRV_MOUSE = 5, VFT2_DRV_NETWORK = 6, VFT2_DRV_SYSTEM = 7, VFT2_DRV_INSTALLABLE = 8, VFT2_DRV_SOUND = 9, VFT2_DRV_COMM = 10, VFT2_DRV_INPUTMETHOD = 11, VFT2_FONT_RASTER = 1, VFT2_FONT_VECTOR = 2, VFT2_FONT_TRUETYPE = 3 } enum : DWORD { VFFF_ISSHAREDFILE = 1 } enum : DWORD { VFF_CURNEDEST = 1, VFF_FILEINUSE = 2, VFF_BUFFTOOSMALL = 4 } enum : DWORD { VIFF_FORCEINSTALL = 1, VIFF_DONTDELETEOLD } enum { VIF_TEMPFILE = 0x00001, VIF_MISMATCH = 0x00002, VIF_SRCOLD = 0x00004, VIF_DIFFLANG = 0x00008, VIF_DIFFCODEPG = 0x00010, VIF_DIFFTYPE = 0x00020, VIF_WRITEPROT = 0x00040, VIF_FILEINUSE = 0x00080, VIF_OUTOFSPACE = 0x00100, VIF_ACCESSVIOLATION = 0x00200, VIF_SHARINGVIOLATION = 0x00400, VIF_CANNOTCREATE = 0x00800, VIF_CANNOTDELETE = 0x01000, VIF_CANNOTRENAME = 0x02000, VIF_CANNOTDELETECUR = 0x04000, VIF_OUTOFMEMORY = 0x08000, VIF_CANNOTREADSRC = 0x10000, VIF_CANNOTREADDST = 0x20000, VIF_BUFFTOOSMALL = 0x40000 } struct VS_FIXEDFILEINFO { DWORD dwSignature; DWORD dwStrucVersion; DWORD dwFileVersionMS; DWORD dwFileVersionLS; DWORD dwProductVersionMS; DWORD dwProductVersionLS; DWORD dwFileFlagsMask; DWORD dwFileFlags; DWORD dwFileOS; DWORD dwFileType; DWORD dwFileSubtype; DWORD dwFileDateMS; DWORD dwFileDateLS; } extern (Windows) { DWORD VerFindFileA(DWORD, LPCSTR, LPCSTR, LPCSTR, LPSTR, PUINT, LPSTR, PUINT); DWORD VerFindFileW(DWORD, LPCWSTR, LPCWSTR, LPCWSTR, LPWSTR, PUINT, LPWSTR, PUINT); DWORD VerInstallFileA(DWORD, LPCSTR, LPCSTR, LPCSTR, LPCSTR, LPCSTR, LPSTR, PUINT); DWORD VerInstallFileW(DWORD, LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR, LPWSTR, PUINT); DWORD GetFileVersionInfoSizeA(LPCSTR, PDWORD); DWORD GetFileVersionInfoSizeW(LPCWSTR, PDWORD); BOOL GetFileVersionInfoA(LPCSTR, DWORD, DWORD, PVOID); BOOL GetFileVersionInfoW(LPCWSTR, DWORD, DWORD, PVOID); DWORD VerLanguageNameA(DWORD, LPSTR, DWORD); DWORD VerLanguageNameW(DWORD, LPWSTR, DWORD); BOOL VerQueryValueA(LPCVOID, LPCSTR, LPVOID*, PUINT); BOOL VerQueryValueW(LPCVOID, LPCWSTR, LPVOID*, PUINT); } version (Unicode) { alias VerFindFileW VerFindFile; alias VerQueryValueW VerQueryValue; alias VerInstallFileW VerInstallFile; alias GetFileVersionInfoSizeW GetFileVersionInfoSize; alias GetFileVersionInfoW GetFileVersionInfo; alias VerLanguageNameW VerLanguageName; alias VerQueryValueW VerQueryValue; } else { alias VerQueryValueA VerQueryValue; alias VerFindFileA VerFindFile; alias VerInstallFileA VerInstallFile; alias GetFileVersionInfoSizeA GetFileVersionInfoSize; alias GetFileVersionInfoA GetFileVersionInfo; alias VerLanguageNameA VerLanguageName; alias VerQueryValueA VerQueryValue; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/cderr.d0000664000175000017500000000240212776214756022754 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_cderr.d) */ module core.sys.windows.cderr; version (Windows): enum { CDERR_DIALOGFAILURE = 0xFFFF, CDERR_GENERALCODES = 0x0000, CDERR_STRUCTSIZE, CDERR_INITIALIZATION, CDERR_NOTEMPLATE, CDERR_NOHINSTANCE, CDERR_LOADSTRFAILURE, CDERR_FINDRESFAILURE, CDERR_LOADRESFAILURE, CDERR_LOCKRESFAILURE, CDERR_MEMALLOCFAILURE, CDERR_MEMLOCKFAILURE, CDERR_NOHOOK, CDERR_REGISTERMSGFAIL, PDERR_PRINTERCODES = 0x1000, PDERR_SETUPFAILURE, PDERR_PARSEFAILURE, PDERR_RETDEFFAILURE, PDERR_LOADDRVFAILURE, PDERR_GETDEVMODEFAIL, PDERR_INITFAILURE, PDERR_NODEVICES, PDERR_NODEFAULTPRN, PDERR_DNDMMISMATCH, PDERR_CREATEICFAILURE, PDERR_PRINTERNOTFOUND, PDERR_DEFAULTDIFFERENT, CFERR_CHOOSEFONTCODES = 0x2000, CFERR_NOFONTS, CFERR_MAXLESSTHANMIN, FNERR_FILENAMECODES = 0x3000, FNERR_SUBCLASSFAILURE, FNERR_INVALIDFILENAME, FNERR_BUFFERTOOSMALL, FRERR_FINDREPLACECODES = 0x4000, FRERR_BUFFERLENGTHZERO, CCERR_CHOOSECOLORCODES = 0x5000 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/shldisp.d0000664000175000017500000000133512776214756023327 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_shldisp.d) */ module core.sys.windows.shldisp; version (Windows): private import core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.wtypes; // options for IAutoComplete2 enum DWORD ACO_AUTOSUGGEST = 0x01; interface IAutoComplete : IUnknown { HRESULT Init(HWND, IUnknown, LPCOLESTR, LPCOLESTR); HRESULT Enable(BOOL); } alias IAutoComplete LPAUTOCOMPLETE; interface IAutoComplete2 : IAutoComplete { HRESULT SetOptions(DWORD); HRESULT GetOptions(DWORD*); } alias IAutoComplete2 LPAUTOCOMPLETE2; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rpcdce.d0000664000175000017500000004155212776214756023126 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rpcdce.d) */ module core.sys.windows.rpcdce; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "Rpcrt4"); // TODO: I think MinGW got this wrong. RPC_UNICODE_SUPPORTED should be // replaced aliases for version(Unicode) public import core.sys.windows.rpcdcep; private import core.sys.windows.basetyps, core.sys.windows.w32api, core.sys.windows.windef; // FIXME: clean up Windows version support alias UUID uuid_t; alias UUID_VECTOR uuid_vector_t; alias void RPC_MGR_EPV; // for RpcMgmtSetComTimeout() enum : uint { RPC_C_BINDING_MIN_TIMEOUT = 0, RPC_C_BINDING_DEFAULT_TIMEOUT = 5, RPC_C_BINDING_MAX_TIMEOUT = 9, RPC_C_BINDING_INFINITE_TIMEOUT = 10 } enum RPC_C_CANCEL_INFINITE_TIMEOUT= -1; enum RPC_C_LISTEN_MAX_CALLS_DEFAULT=1234; enum RPC_C_PROTSEQ_MAX_REQS_DEFAULT=10; enum RPC_C_BIND_TO_ALL_NICS=1; enum RPC_C_USE_INTERNET_PORT=1; enum RPC_C_USE_INTRANET_PORT=2; // for RPC_STATS_VECTOR, used by RpcMgmyInqStats enum : uint { RPC_C_STATS_CALLS_IN = 0, RPC_C_STATS_CALLS_OUT, RPC_C_STATS_PKTS_IN, RPC_C_STATS_PKTS_OUT } enum RPC_IF_AUTOLISTEN=0x0001; enum RPC_IF_OLE=2; enum RPC_C_MGMT_INQ_IF_IDS=0; enum RPC_C_MGMT_INQ_PRINC_NAME=1; enum RPC_C_MGMT_INQ_STATS=2; enum RPC_C_MGMT_IS_SERVER_LISTEN=3; enum RPC_C_MGMT_STOP_SERVER_LISTEN=4; // Inquiry Type for RpcMgmtEpEltInqBegin() enum : uint { RPC_C_EP_ALL_ELTS = 0, RPC_C_EP_MATCH_BY_IF, RPC_C_EP_MATCH_BY_OBJ, RPC_C_EP_MATCH_BY_BOTH } // for RpcMgmtEpEltInqNext() enum : uint { RPC_C_VERS_ALL = 1, RPC_C_VERS_COMPATIBLE, RPC_C_VERS_EXACT, RPC_C_VERS_MAJOR_ONLY, RPC_C_VERS_UPTO } enum DCE_C_ERROR_STRING_LEN=256; enum RPC_C_PARM_MAX_PACKET_LENGTH=1; enum RPC_C_PARM_BUFFER_LENGTH=2; enum RPC_C_AUTHN_LEVEL_DEFAULT=0; enum RPC_C_AUTHN_LEVEL_NONE=1; enum RPC_C_AUTHN_LEVEL_CONNECT=2; enum RPC_C_AUTHN_LEVEL_CALL=3; enum RPC_C_AUTHN_LEVEL_PKT=4; enum RPC_C_AUTHN_LEVEL_PKT_INTEGRITY=5; enum RPC_C_AUTHN_LEVEL_PKT_PRIVACY=6; enum RPC_C_IMP_LEVEL_ANONYMOUS=1; enum RPC_C_IMP_LEVEL_IDENTIFY=2; enum RPC_C_IMP_LEVEL_IMPERSONATE=3; enum RPC_C_IMP_LEVEL_DELEGATE=4; enum RPC_C_QOS_IDENTITY_STATIC=0; enum RPC_C_QOS_IDENTITY_DYNAMIC=1; enum RPC_C_QOS_CAPABILITIES_DEFAULT=0; enum RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH=1; // These enums were buggy in MinGW ! enum RPC_C_PROTECT_LEVEL_DEFAULT = RPC_C_AUTHN_LEVEL_DEFAULT; enum RPC_C_PROTECT_LEVEL_NONE = RPC_C_AUTHN_LEVEL_NONE; enum RPC_C_PROTECT_LEVEL_CONNECT = RPC_C_AUTHN_LEVEL_CONNECT; enum RPC_C_PROTECT_LEVEL_CALL = RPC_C_AUTHN_LEVEL_CALL; enum RPC_C_PROTECT_LEVEL_PKT = RPC_C_AUTHN_LEVEL_PKT; enum RPC_C_PROTECT_LEVEL_PKT_INTEGRITY = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY; enum RPC_C_PROTECT_LEVEL_PKT_PRIVACY = RPC_C_AUTHN_LEVEL_PKT_PRIVACY; enum RPC_C_AUTHN_NONE=0; enum RPC_C_AUTHN_DCE_PRIVATE=1; enum RPC_C_AUTHN_DCE_PUBLIC=2; enum RPC_C_AUTHN_DEC_PUBLIC=4; enum RPC_C_AUTHN_WINNT=10; enum RPC_C_AUTHN_DEFAULT=0xFFFFFFFF; //const RPC_C_SECURITY_QOS_VERSION=L; // FIXME(MinGW): This is nonsense! enum SEC_WINNT_AUTH_IDENTITY_ANSI=0x1; enum SEC_WINNT_AUTH_IDENTITY_UNICODE=0x2; enum RPC_C_AUTHZ_NONE=0; enum RPC_C_AUTHZ_NAME=1; enum RPC_C_AUTHZ_DCE=2; enum RPC_C_AUTHZ_DEFAULT=0xFFFFFFFF; alias I_RPC_HANDLE RPC_BINDING_HANDLE; alias RPC_BINDING_HANDLE handle_t; struct RPC_BINDING_VECTOR { uint Count; RPC_BINDING_HANDLE[1] BindingH; } alias RPC_BINDING_HANDLE rpc_binding_handle_t; alias RPC_BINDING_VECTOR rpc_binding_vector_t; struct UUID_VECTOR { uint Count; UUID*[1] Uuid; } alias void* RPC_IF_HANDLE; struct RPC_IF_ID { UUID Uuid; ushort VersMajor; ushort VersMinor; } struct RPC_POLICY { uint Length; uint EndpointFlags; uint NICFlags; } alias RPC_POLICY* PRPC_POLICY; extern (Windows) { alias void function(UUID*, UUID*, RPC_STATUS*) RPC_OBJECT_INQ_FN; alias RPC_STATUS function(RPC_IF_HANDLE, void*) RPC_IF_CALLBACK_FN; } struct RPC_STATS_VECTOR { uint Count; uint[1] Stats; } struct RPC_IF_ID_VECTOR { uint Count; RPC_IF_ID*[1] IfId; } mixin DECLARE_HANDLE!("RPC_AUTH_IDENTITY_HANDLE"); mixin DECLARE_HANDLE!("RPC_AUTHZ_HANDLE"); struct RPC_SECURITY_QOS { uint Version; uint Capabilities; uint IdentityTracking; uint ImpersonationType; } alias RPC_SECURITY_QOS* PRPC_SECURITY_QOS; struct SEC_WINNT_AUTH_IDENTITY_W { ushort* User; uint UserLength; ushort* Domain; uint DomainLength; ushort* Password; uint PasswordLength; uint Flags; } alias SEC_WINNT_AUTH_IDENTITY_W* PSEC_WINNT_AUTH_IDENTITY_W; struct SEC_WINNT_AUTH_IDENTITY_A { ubyte* User; uint UserLength; ubyte* Domain; uint DomainLength; ubyte* Password; uint PasswordLength; uint Flags; } alias SEC_WINNT_AUTH_IDENTITY_A* PSEC_WINNT_AUTH_IDENTITY_A; struct RPC_CLIENT_INFORMATION1 { ubyte* UserName; ubyte* ComputerName; ushort Privilege; uint AuthFlags; } alias RPC_CLIENT_INFORMATION1* PRPC_CLIENT_INFORMATION1; alias I_RPC_HANDLE* RPC_EP_INQ_HANDLE; extern (Windows) { alias int function(RPC_BINDING_HANDLE, uint, RPC_STATUS*) RPC_MGMT_AUTHORIZATION_FN; } struct RPC_PROTSEQ_VECTORA { uint Count; ubyte*[1] Protseq; } struct RPC_PROTSEQ_VECTORW { uint Count; ushort*[1] Protseq; } extern (Windows) { RPC_STATUS RpcBindingFromStringBindingA(char*, RPC_BINDING_HANDLE*); RPC_STATUS RpcBindingFromStringBindingW(wchar*, RPC_BINDING_HANDLE*); RPC_STATUS RpcBindingToStringBindingA(RPC_BINDING_HANDLE, char**); RPC_STATUS RpcBindingToStringBindingW(RPC_BINDING_HANDLE, wchar**); RPC_STATUS RpcStringBindingComposeA(char*, char*, char*, char*, char*, char**); RPC_STATUS RpcStringBindingComposeW(wchar*, wchar*, wchar*, wchar*, wchar*, wchar**); RPC_STATUS RpcStringBindingParseA(char*, char**, char**, char**, char**, char**); RPC_STATUS RpcStringBindingParseW(wchar*, wchar**, wchar**, wchar**, wchar**, wchar**); RPC_STATUS RpcStringFreeA(char**); RPC_STATUS RpcStringFreeW(wchar**); RPC_STATUS RpcNetworkIsProtseqValidA(char*); RPC_STATUS RpcNetworkIsProtseqValidW(wchar*); RPC_STATUS RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA**); RPC_STATUS RpcNetworkInqProtseqsW(RPC_PROTSEQ_VECTORW**); RPC_STATUS RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA**); RPC_STATUS RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW**); RPC_STATUS RpcServerUseProtseqA(char*, uint, void*); RPC_STATUS RpcServerUseProtseqW(wchar*, uint, void*); RPC_STATUS RpcServerUseProtseqExA(char*, uint MaxCalls, void*, PRPC_POLICY); RPC_STATUS RpcServerUseProtseqExW(wchar*, uint, void*, PRPC_POLICY); RPC_STATUS RpcServerUseProtseqEpA(char*, uint, char*, void*); RPC_STATUS RpcServerUseProtseqEpExA(char*, uint, char*, void*, PRPC_POLICY); RPC_STATUS RpcServerUseProtseqEpW(wchar*, uint, wchar*, void*); RPC_STATUS RpcServerUseProtseqEpExW(wchar*, uint, wchar*, void*, PRPC_POLICY); RPC_STATUS RpcServerUseProtseqIfA(char*, uint, RPC_IF_HANDLE, void*); RPC_STATUS RpcServerUseProtseqIfExA(char*, uint, RPC_IF_HANDLE, void*, PRPC_POLICY); RPC_STATUS RpcServerUseProtseqIfW(wchar*, uint, RPC_IF_HANDLE, void*); RPC_STATUS RpcServerUseProtseqIfExW(wchar*, uint, RPC_IF_HANDLE, void*, PRPC_POLICY); RPC_STATUS RpcMgmtInqServerPrincNameA(RPC_BINDING_HANDLE, uint, char**); RPC_STATUS RpcMgmtInqServerPrincNameW(RPC_BINDING_HANDLE, uint, wchar**); RPC_STATUS RpcServerInqDefaultPrincNameA(uint, char**); RPC_STATUS RpcServerInqDefaultPrincNameW(uint, wchar**); RPC_STATUS RpcNsBindingInqEntryNameA(RPC_BINDING_HANDLE, uint, char**); RPC_STATUS RpcNsBindingInqEntryNameW(RPC_BINDING_HANDLE, uint, wchar**); RPC_STATUS RpcBindingInqAuthClientA(RPC_BINDING_HANDLE, RPC_AUTHZ_HANDLE*, char**, uint*, uint*, uint*); RPC_STATUS RpcBindingInqAuthClientW(RPC_BINDING_HANDLE, RPC_AUTHZ_HANDLE*, wchar**, uint*, uint*, uint*); RPC_STATUS RpcBindingInqAuthInfoA(RPC_BINDING_HANDLE, char**, uint*, uint*, RPC_AUTH_IDENTITY_HANDLE*, uint*); RPC_STATUS RpcBindingInqAuthInfoW(RPC_BINDING_HANDLE, wchar**, uint*, uint*, RPC_AUTH_IDENTITY_HANDLE*, uint*); RPC_STATUS RpcBindingSetAuthInfoA(RPC_BINDING_HANDLE, char*, uint, uint, RPC_AUTH_IDENTITY_HANDLE, uint); RPC_STATUS RpcBindingSetAuthInfoExA(RPC_BINDING_HANDLE, char*, uint, uint, RPC_AUTH_IDENTITY_HANDLE, uint, RPC_SECURITY_QOS*); RPC_STATUS RpcBindingSetAuthInfoW(RPC_BINDING_HANDLE, wchar*, uint, uint, RPC_AUTH_IDENTITY_HANDLE, uint); RPC_STATUS RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE, wchar*, uint, uint, RPC_AUTH_IDENTITY_HANDLE, uint, RPC_SECURITY_QOS*); RPC_STATUS RpcBindingInqAuthInfoExA(RPC_BINDING_HANDLE, char**, uint*, uint*, RPC_AUTH_IDENTITY_HANDLE*, uint*, uint, RPC_SECURITY_QOS*); RPC_STATUS RpcBindingInqAuthInfoExW(RPC_BINDING_HANDLE, wchar**, uint*, uint*, RPC_AUTH_IDENTITY_HANDLE*, uint*, uint, RPC_SECURITY_QOS*); alias void function(void*, wchar*, uint, void**, RPC_STATUS*) RPC_AUTH_KEY_RETRIEVAL_FN; RPC_STATUS RpcServerRegisterAuthInfoA(char*, uint, RPC_AUTH_KEY_RETRIEVAL_FN, void*); RPC_STATUS RpcServerRegisterAuthInfoW(wchar*, uint, RPC_AUTH_KEY_RETRIEVAL_FN, void*); RPC_STATUS UuidToStringA(UUID*, char**); RPC_STATUS UuidFromStringA(char*, UUID*); RPC_STATUS UuidToStringW(UUID*, wchar**); RPC_STATUS UuidFromStringW(wchar*, UUID*); RPC_STATUS RpcEpRegisterNoReplaceA(RPC_IF_HANDLE, RPC_BINDING_VECTOR*, UUID_VECTOR*, char*); RPC_STATUS RpcEpRegisterNoReplaceW(RPC_IF_HANDLE, RPC_BINDING_VECTOR*, UUID_VECTOR*, wchar*); RPC_STATUS RpcEpRegisterA(RPC_IF_HANDLE, RPC_BINDING_VECTOR*, UUID_VECTOR*, char*); RPC_STATUS RpcEpRegisterW(RPC_IF_HANDLE, RPC_BINDING_VECTOR*, UUID_VECTOR*, wchar*); RPC_STATUS DceErrorInqTextA(RPC_STATUS, char*); RPC_STATUS DceErrorInqTextW(RPC_STATUS, wchar*); RPC_STATUS RpcMgmtEpEltInqNextA(RPC_EP_INQ_HANDLE, RPC_IF_ID*, RPC_BINDING_HANDLE*, UUID*, char**); RPC_STATUS RpcMgmtEpEltInqNextW(RPC_EP_INQ_HANDLE, RPC_IF_ID*, RPC_BINDING_HANDLE*, UUID*, wchar**); // MinGW erroneously had these in rpc.h RPC_STATUS RpcImpersonateClient(RPC_BINDING_HANDLE); RPC_STATUS RpcRevertToSelf(); } version (Unicode) { alias RPC_PROTSEQ_VECTORW RPC_PROTSEQ_VECTOR; alias SEC_WINNT_AUTH_IDENTITY_W SEC_WINNT_AUTH_IDENTITY; alias PSEC_WINNT_AUTH_IDENTITY_W PSEC_WINNT_AUTH_IDENTITY; alias RpcMgmtEpEltInqNextW RpcMgmtEpEltInqNext; alias RpcBindingFromStringBindingW RpcBindingFromStringBinding; alias RpcBindingToStringBindingW RpcBindingToStringBinding; alias RpcStringBindingComposeW RpcStringBindingCompose; alias RpcStringBindingParseW RpcStringBindingParse; alias RpcStringFreeW RpcStringFree; alias RpcNetworkIsProtseqValidW RpcNetworkIsProtseqValid; alias RpcNetworkInqProtseqsW RpcNetworkInqProtseqs; alias RpcProtseqVectorFreeW RpcProtseqVectorFree; alias RpcServerUseProtseqW RpcServerUseProtseq; alias RpcServerUseProtseqExW RpcServerUseProtseqEx; alias RpcServerUseProtseqEpW RpcServerUseProtseqEp; alias RpcServerUseProtseqEpExW RpcServerUseProtseqEpEx; alias RpcServerUseProtseqIfW RpcServerUseProtseqIf; alias RpcServerUseProtseqIfExW RpcServerUseProtseqIfEx; alias RpcMgmtInqServerPrincNameW RpcMgmtInqServerPrincName; alias RpcServerInqDefaultPrincNameW RpcServerInqDefaultPrincName; alias RpcNsBindingInqEntryNameW RpcNsBindingInqEntryName; alias RpcBindingInqAuthClientW RpcBindingInqAuthClient; alias RpcBindingInqAuthInfoW RpcBindingInqAuthInfo; alias RpcBindingSetAuthInfoW RpcBindingSetAuthInfo; alias RpcServerRegisterAuthInfoW RpcServerRegisterAuthInfo; alias RpcBindingInqAuthInfoExW RpcBindingInqAuthInfoEx; alias RpcBindingSetAuthInfoExW RpcBindingSetAuthInfoEx; alias UuidFromStringW UuidFromString; alias UuidToStringW UuidToString; alias RpcEpRegisterNoReplaceW RpcEpRegisterNoReplace; alias RpcEpRegisterW RpcEpRegister; alias DceErrorInqTextW DceErrorInqText; } else { // Ansi alias RPC_PROTSEQ_VECTORA RPC_PROTSEQ_VECTOR; alias SEC_WINNT_AUTH_IDENTITY_A SEC_WINNT_AUTH_IDENTITY; alias PSEC_WINNT_AUTH_IDENTITY_A PSEC_WINNT_AUTH_IDENTITY; alias RpcMgmtEpEltInqNextA RpcMgmtEpEltInqNext; alias RpcBindingFromStringBindingA RpcBindingFromStringBinding; alias RpcBindingToStringBindingA RpcBindingToStringBinding; alias RpcStringBindingComposeA RpcStringBindingCompose; alias RpcStringBindingParseA RpcStringBindingParse; alias RpcStringFreeA RpcStringFree; alias RpcNetworkIsProtseqValidA RpcNetworkIsProtseqValid; alias RpcNetworkInqProtseqsA RpcNetworkInqProtseqs; alias RpcProtseqVectorFreeA RpcProtseqVectorFree; alias RpcServerUseProtseqA RpcServerUseProtseq; alias RpcServerUseProtseqExA RpcServerUseProtseqEx; alias RpcServerUseProtseqEpA RpcServerUseProtseqEp; alias RpcServerUseProtseqEpExA RpcServerUseProtseqEpEx; alias RpcServerUseProtseqIfA RpcServerUseProtseqIf; alias RpcServerUseProtseqIfExA RpcServerUseProtseqIfEx; alias RpcMgmtInqServerPrincNameA RpcMgmtInqServerPrincName; alias RpcServerInqDefaultPrincNameA RpcServerInqDefaultPrincName; alias RpcNsBindingInqEntryNameA RpcNsBindingInqEntryName; alias RpcBindingInqAuthClientA RpcBindingInqAuthClient; alias RpcBindingInqAuthInfoA RpcBindingInqAuthInfo; alias RpcBindingSetAuthInfoA RpcBindingSetAuthInfo; alias RpcServerRegisterAuthInfoA RpcServerRegisterAuthInfo; alias RpcBindingInqAuthInfoExA RpcBindingInqAuthInfoEx; alias RpcBindingSetAuthInfoExA RpcBindingSetAuthInfoEx; alias UuidFromStringA UuidFromString; alias UuidToStringA UuidToString; alias RpcEpRegisterNoReplaceA RpcEpRegisterNoReplace; alias RpcEpRegisterA RpcEpRegister; alias DceErrorInqTextA DceErrorInqText; } //#endif // UNICODE RPC_STATUS RpcBindingCopy(RPC_BINDING_HANDLE, RPC_BINDING_HANDLE*); RPC_STATUS RpcBindingFree(RPC_BINDING_HANDLE*); RPC_STATUS RpcBindingInqObject(RPC_BINDING_HANDLE, UUID*); RPC_STATUS RpcBindingReset(RPC_BINDING_HANDLE); RPC_STATUS RpcBindingSetObject(RPC_BINDING_HANDLE, UUID*); RPC_STATUS RpcMgmtInqDefaultProtectLevel(uint, uint*); RPC_STATUS RpcBindingVectorFree(RPC_BINDING_VECTOR**); RPC_STATUS RpcIfInqId(RPC_IF_HANDLE, RPC_IF_ID*); RPC_STATUS RpcMgmtInqComTimeout(RPC_BINDING_HANDLE, uint*); RPC_STATUS RpcMgmtSetComTimeout(RPC_BINDING_HANDLE, uint); RPC_STATUS RpcMgmtSetCancelTimeout(int Timeout); RPC_STATUS RpcObjectInqType(UUID*, UUID*); RPC_STATUS RpcObjectSetInqFn(RPC_OBJECT_INQ_FN*); RPC_STATUS RpcObjectSetType(UUID*, UUID*); RPC_STATUS RpcProtseqVectorFree(RPC_PROTSEQ_VECTOR**); RPC_STATUS RpcServerInqIf(RPC_IF_HANDLE, UUID*, RPC_MGR_EPV**); RPC_STATUS RpcServerListen(uint, uint, uint); RPC_STATUS RpcServerRegisterIf(RPC_IF_HANDLE, UUID*, RPC_MGR_EPV*); RPC_STATUS RpcServerRegisterIfEx(RPC_IF_HANDLE, UUID*, RPC_MGR_EPV*, uint, uint, RPC_IF_CALLBACK_FN*); RPC_STATUS RpcServerRegisterIf2(RPC_IF_HANDLE, UUID*, RPC_MGR_EPV*, uint, uint, uint, RPC_IF_CALLBACK_FN*); RPC_STATUS RpcServerUnregisterIf(RPC_IF_HANDLE, UUID*, uint); RPC_STATUS RpcServerUseAllProtseqs(uint, void*); RPC_STATUS RpcServerUseAllProtseqsEx(uint, void*, PRPC_POLICY); RPC_STATUS RpcServerUseAllProtseqsIf(uint, RPC_IF_HANDLE, void*); RPC_STATUS RpcServerUseAllProtseqsIfEx(uint, RPC_IF_HANDLE, void*, PRPC_POLICY); RPC_STATUS RpcMgmtStatsVectorFree(RPC_STATS_VECTOR**); RPC_STATUS RpcMgmtInqStats(RPC_BINDING_HANDLE, RPC_STATS_VECTOR**); RPC_STATUS RpcMgmtIsServerListening(RPC_BINDING_HANDLE); RPC_STATUS RpcMgmtStopServerListening(RPC_BINDING_HANDLE); RPC_STATUS RpcMgmtWaitServerListen(); RPC_STATUS RpcMgmtSetServerStackSize(uint); void RpcSsDontSerializeContext(); RPC_STATUS RpcMgmtEnableIdleCleanup(); RPC_STATUS RpcMgmtInqIfIds(RPC_BINDING_HANDLE, RPC_IF_ID_VECTOR**); RPC_STATUS RpcIfIdVectorFree(RPC_IF_ID_VECTOR**); RPC_STATUS RpcEpResolveBinding(RPC_BINDING_HANDLE, RPC_IF_HANDLE); RPC_STATUS RpcBindingServerFromClient(RPC_BINDING_HANDLE, RPC_BINDING_HANDLE*); // never returns void RpcRaiseException(RPC_STATUS); RPC_STATUS RpcTestCancel(); RPC_STATUS RpcCancelThread(void*); RPC_STATUS UuidCreate(UUID*); int UuidCompare(UUID*, UUID*, RPC_STATUS*); RPC_STATUS UuidCreateNil(UUID*); int UuidEqual(UUID*, UUID*, RPC_STATUS*); ushort UuidHash(UUID*, RPC_STATUS*); int UuidIsNil(UUID*, RPC_STATUS*); RPC_STATUS RpcEpUnregister(RPC_IF_HANDLE, RPC_BINDING_VECTOR*, UUID_VECTOR*); RPC_STATUS RpcMgmtEpEltInqBegin(RPC_BINDING_HANDLE, uint, RPC_IF_ID*, uint, UUID*, RPC_EP_INQ_HANDLE*); RPC_STATUS RpcMgmtEpEltInqDone(RPC_EP_INQ_HANDLE*); RPC_STATUS RpcMgmtEpUnregister(RPC_BINDING_HANDLE, RPC_IF_ID*, RPC_BINDING_HANDLE, UUID*); RPC_STATUS RpcMgmtSetAuthorizationFn(RPC_MGMT_AUTHORIZATION_FN); RPC_STATUS RpcMgmtInqParameter(uint, uint*); RPC_STATUS RpcMgmtSetParameter(uint, uint); RPC_STATUS RpcMgmtBindingInqParameter(RPC_BINDING_HANDLE, uint, uint*); RPC_STATUS RpcMgmtBindingSetParameter(RPC_BINDING_HANDLE, uint, uint); //static if (_WIN32_WINNT >= 0x500) { RPC_STATUS UuidCreateSequential(UUID*); //} ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/dde.d0000664000175000017500000001617112776214756022421 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_dde.d) */ module core.sys.windows.dde; version (Windows): pragma(lib, "user32"); private import core.sys.windows.windef; enum : uint { WM_DDE_FIRST = 0x03E0, WM_DDE_INITIATE = WM_DDE_FIRST, WM_DDE_TERMINATE, WM_DDE_ADVISE, WM_DDE_UNADVISE, WM_DDE_ACK, WM_DDE_DATA, WM_DDE_REQUEST, WM_DDE_POKE, WM_DDE_EXECUTE, WM_DDE_LAST = WM_DDE_EXECUTE } struct DDEACK { ubyte bAppReturnCode; ubyte _bf; @property ubyte reserved() { return cast(ubyte) (_bf & 0x3F); } @property bool fBusy() { return cast(bool) (_bf & 0x40); } @property bool fAck() { return cast(bool) (_bf & 0x80); } @property ubyte reserved(ubyte r) { _bf = cast(ubyte) ((_bf & ~0x3F) | (r & 0x3F)); return cast(ubyte)(r & 0x3F); } @property bool fBusy(bool f) { _bf = cast(ubyte) ((_bf & ~0x40) | (f << 6)); return f; } @property bool fAck(bool f) { _bf = cast(ubyte) ((_bf & ~0x80) | (f << 7)); return f; } } struct DDEADVISE { ushort _bf; short cfFormat; @property ushort reserved() { return cast(ushort) (_bf & 0x3FFF); } @property bool fDeferUpd() { return cast(bool) (_bf & 0x4000); } @property bool fAckReq() { return cast(bool) (_bf & 0x8000); } @property ushort reserved(ushort r) { _bf = cast(ushort) ((_bf & ~0x3FFF) | (r & 0x3FFF)); return cast(ushort)(r & 0x3FFF); } @property bool fDeferUpd(bool f) { _bf = cast(ushort) ((_bf & ~0x4000) | (f << 14)); return f; } @property bool fAckReq(bool f) { _bf = cast(ushort) ((_bf & ~0x8000) | (f << 15)); return f; } } struct DDEDATA { ushort _bf; short cfFormat; byte _Value; @property ushort unused() { return cast(ushort) (_bf & 0x0FFF); } @property bool fResponse() { return cast(bool) (_bf & 0x1000); } @property bool fRelease() { return cast(bool) (_bf & 0x2000); } @property bool reserved() { return cast(bool) (_bf & 0x4000); } @property bool fAckReq() { return cast(bool) (_bf & 0x8000); } @property byte* Value() return { return &_Value; } @property ushort unused(ushort r) { _bf = cast(ushort) ((_bf & ~0x0FFF) | (r & 0x0FFF)); return cast(ushort)(r & 0x0FFF); } @property bool fResponse(bool f) { _bf = cast(ushort) ((_bf & ~0x1000) | (f << 12)); return f; } @property bool fRelease(bool f) { _bf = cast(ushort) ((_bf & ~0x2000) | (f << 13)); return f; } @property bool reserved(bool f) { _bf = cast(ushort) ((_bf & ~0x4000) | (f << 14)); return f; } @property bool fAckReq(bool f) { _bf = cast(ushort) ((_bf & ~0x8000) | (f << 15)); return f; } } struct DDEPOKE { ushort _bf; short cfFormat; byte _Value; @property ushort unused() { return cast(ushort) (_bf & 0x1FFF); } @property bool fRelease() { return cast(bool) (_bf & 0x2000); } @property ubyte fReserved() { return cast(ubyte) ((_bf & 0xC000) >>> 14); } @property byte* Value() return { return &_Value; } @property ushort unused(ushort u) { _bf = cast(ushort) ((_bf & ~0x1FFF) | (u & 0x1FFF)); return cast(ushort)(u & 0x1FFF); } @property bool fRelease(bool f) { _bf = cast(ushort) ((_bf & ~0x2000) | (f << 13)); return f; } @property ubyte fReserved(ubyte r) { _bf = cast(ushort) ((_bf & ~0xC000) | (r << 14)); return r; } } deprecated struct DDELN { ushort _bf; short cfFormat; @property ushort unused() { return cast(ushort) (_bf & 0x1FFF); } @property bool fRelease() { return cast(bool) (_bf & 0x2000); } @property bool fDeferUpd() { return cast(bool) (_bf & 0x4000); } @property bool fAckReq() { return cast(bool) (_bf & 0x8000); } @property ushort unused(ushort u) { _bf = cast(ushort)((_bf & ~0x1FFF) | (u & 0x1FFF)); return cast(ushort)(u & 0x1FFF); } @property bool fRelease(bool f) { _bf = cast(ushort) ((_bf & ~0x2000) | (f << 13)); return f; } @property bool fDeferUpd(bool f) { _bf = cast(ushort) ((_bf & ~0x4000) | (f << 14)); return f; } @property bool fAckReq(bool f) { _bf = cast(ushort) ((_bf & ~0x8000) | (f << 15)); return f; } } deprecated struct DDEUP { ushort _bf; short cfFormat; byte _rgb; @property ushort unused() { return cast(ushort) (_bf & 0x0FFF); } @property bool fAck() { return cast(bool) (_bf & 0x1000); } @property bool fRelease() { return cast(bool) (_bf & 0x2000); } @property bool fReserved() { return cast(bool) (_bf & 0x4000); } @property bool fAckReq() { return cast(bool) (_bf & 0x8000); } @property byte* rgb() return { return &_rgb; } @property ushort unused(ushort r) { _bf = cast(ushort) ((_bf & ~0x0FFF) | (r & 0x0FFF)); return cast(ushort)(r & 0x0FFF); } @property bool fAck(bool f) { _bf = cast(ushort) ((_bf & ~0x1000) | (f << 12)); return f; } @property bool fRelease(bool f) { _bf = cast(ushort) ((_bf & ~0x2000) | (f << 13)); return f; } @property bool fReserved(bool f) { _bf = cast(ushort) ((_bf & ~0x4000) | (f << 14)); return f; } @property bool fAckReq(bool f) { _bf = cast(ushort) ((_bf & ~0x8000) | (f << 15)); return f; } } extern (Windows) { BOOL DdeSetQualityOfService(HWND, const(SECURITY_QUALITY_OF_SERVICE)*, PSECURITY_QUALITY_OF_SERVICE); BOOL ImpersonateDdeClientWindow(HWND, HWND); LPARAM PackDDElParam(UINT, UINT_PTR, UINT_PTR); BOOL UnpackDDElParam(UINT, LPARAM, PUINT_PTR, PUINT_PTR); BOOL FreeDDElParam(UINT, LPARAM); LPARAM ReuseDDElParam(LPARAM, UINT, UINT, UINT_PTR, UINT_PTR); } debug (WindowsUnitTest) { unittest { DDEACK ddeack; with (ddeack) { reserved = 10; assert (_bf == 0x0A); fBusy = true; assert (_bf == 0x4A); fAck = true; assert (_bf == 0xCA); assert (reserved == 10); assert (fBusy == true); assert (fAck == true); reserved = 43; assert (_bf == 0xEB); fBusy = false; assert (_bf == 0xAB); fAck = false; assert (_bf == 0x2B); assert (reserved == 43); assert (fBusy == false); assert (fAck == false); } DDEPOKE ddepoke; with (ddepoke) { unused = 3456; assert (_bf == 0x0D80); fRelease = true; assert (_bf == 0x2D80); fReserved = 2; assert (_bf == 0xAD80); assert (unused == 3456); assert (fRelease == true); assert (fReserved == 2); unused = 2109; assert (_bf == 0xa83d); fRelease = false; assert (_bf == 0x883d); fReserved = 1; assert (_bf == 0x483d); assert (unused == 2109); assert (fRelease == false); assert (fReserved == 1); } } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmerrlog.d0000664000175000017500000002313612776214756023507 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmerrlog.d) */ module core.sys.windows.lmerrlog; version (Windows): // COMMENT: This appears to be only for Win16. All functions are deprecated. private import core.sys.windows.lmcons, core.sys.windows.windef; private import core.sys.windows.lmaudit; // for LPHLOG enum ERRLOG_BASE=3100; enum ERRLOG2_BASE=5700; enum LOGFLAGS_FORWARD=0; enum LOGFLAGS_BACKWARD=1; enum LOGFLAGS_SEEK=2; enum NELOG_Internal_Error=ERRLOG_BASE; enum NELOG_Resource_Shortage=(ERRLOG_BASE+1); enum NELOG_Unable_To_Lock_Segment=(ERRLOG_BASE+2); enum NELOG_Unable_To_Unlock_Segment=(ERRLOG_BASE+3); enum NELOG_Uninstall_Service=(ERRLOG_BASE+4); enum NELOG_Init_Exec_Fail=(ERRLOG_BASE+5); enum NELOG_Ncb_Error=(ERRLOG_BASE+6); enum NELOG_Net_Not_Started=(ERRLOG_BASE+7); enum NELOG_Ioctl_Error=(ERRLOG_BASE+8); enum NELOG_System_Semaphore=(ERRLOG_BASE+9); enum NELOG_Init_OpenCreate_Err=(ERRLOG_BASE+10); enum NELOG_NetBios=(ERRLOG_BASE+11); enum NELOG_SMB_Illegal=(ERRLOG_BASE+12); enum NELOG_Service_Fail=(ERRLOG_BASE+13); enum NELOG_Entries_Lost=(ERRLOG_BASE+14); enum NELOG_Init_Seg_Overflow=(ERRLOG_BASE+20); enum NELOG_Srv_No_Mem_Grow=(ERRLOG_BASE+21); enum NELOG_Access_File_Bad=(ERRLOG_BASE+22); enum NELOG_Srvnet_Not_Started=(ERRLOG_BASE+23); enum NELOG_Init_Chardev_Err=(ERRLOG_BASE+24); enum NELOG_Remote_API=(ERRLOG_BASE+25); enum NELOG_Ncb_TooManyErr=(ERRLOG_BASE+26); enum NELOG_Mailslot_err=(ERRLOG_BASE+27); enum NELOG_ReleaseMem_Alert=(ERRLOG_BASE+28); enum NELOG_AT_cannot_write=(ERRLOG_BASE+29); enum NELOG_Cant_Make_Msg_File=(ERRLOG_BASE+30); enum NELOG_Exec_Netservr_NoMem=(ERRLOG_BASE+31); enum NELOG_Server_Lock_Failure=(ERRLOG_BASE+32); enum NELOG_Msg_Shutdown=(ERRLOG_BASE+40); enum NELOG_Msg_Sem_Shutdown=(ERRLOG_BASE+41); enum NELOG_Msg_Log_Err=(ERRLOG_BASE+50); enum NELOG_VIO_POPUP_ERR=(ERRLOG_BASE+51); enum NELOG_Msg_Unexpected_SMB_Type=(ERRLOG_BASE+52); enum NELOG_Wksta_Infoseg=(ERRLOG_BASE+60); enum NELOG_Wksta_Compname=(ERRLOG_BASE+61); enum NELOG_Wksta_BiosThreadFailure=(ERRLOG_BASE+62); enum NELOG_Wksta_IniSeg=(ERRLOG_BASE+63); enum NELOG_Wksta_HostTab_Full=(ERRLOG_BASE+64); enum NELOG_Wksta_Bad_Mailslot_SMB=(ERRLOG_BASE+65); enum NELOG_Wksta_UASInit=(ERRLOG_BASE+66); enum NELOG_Wksta_SSIRelogon=(ERRLOG_BASE+67); enum NELOG_Build_Name=(ERRLOG_BASE+70); enum NELOG_Name_Expansion=(ERRLOG_BASE+71); enum NELOG_Message_Send=(ERRLOG_BASE+72); enum NELOG_Mail_Slt_Err=(ERRLOG_BASE+73); enum NELOG_AT_cannot_read=(ERRLOG_BASE+74); enum NELOG_AT_sched_err=(ERRLOG_BASE+75); enum NELOG_AT_schedule_file_created=(ERRLOG_BASE+76); enum NELOG_Srvnet_NB_Open=(ERRLOG_BASE+77); enum NELOG_AT_Exec_Err=(ERRLOG_BASE+78); enum NELOG_Lazy_Write_Err=(ERRLOG_BASE+80); enum NELOG_HotFix=(ERRLOG_BASE+81); enum NELOG_HardErr_From_Server=(ERRLOG_BASE+82); enum NELOG_LocalSecFail1=(ERRLOG_BASE+83); enum NELOG_LocalSecFail2=(ERRLOG_BASE+84); enum NELOG_LocalSecFail3=(ERRLOG_BASE+85); enum NELOG_LocalSecGeneralFail=(ERRLOG_BASE+86); enum NELOG_NetWkSta_Internal_Error=(ERRLOG_BASE+90); enum NELOG_NetWkSta_No_Resource=(ERRLOG_BASE+91); enum NELOG_NetWkSta_SMB_Err=(ERRLOG_BASE+92); enum NELOG_NetWkSta_VC_Err=(ERRLOG_BASE+93); enum NELOG_NetWkSta_Stuck_VC_Err=(ERRLOG_BASE+94); enum NELOG_NetWkSta_NCB_Err=(ERRLOG_BASE+95); enum NELOG_NetWkSta_Write_Behind_Err=(ERRLOG_BASE+96); enum NELOG_NetWkSta_Reset_Err=(ERRLOG_BASE+97); enum NELOG_NetWkSta_Too_Many=(ERRLOG_BASE+98); enum NELOG_Srv_Thread_Failure=(ERRLOG_BASE+104); enum NELOG_Srv_Close_Failure=(ERRLOG_BASE+105); enum NELOG_ReplUserCurDir=(ERRLOG_BASE+106); enum NELOG_ReplCannotMasterDir=(ERRLOG_BASE+107); enum NELOG_ReplUpdateError=(ERRLOG_BASE+108); enum NELOG_ReplLostMaster=(ERRLOG_BASE+109); enum NELOG_NetlogonAuthDCFail=(ERRLOG_BASE+110); enum NELOG_ReplLogonFailed=(ERRLOG_BASE+111); enum NELOG_ReplNetErr=(ERRLOG_BASE+112); enum NELOG_ReplMaxFiles=(ERRLOG_BASE+113); enum NELOG_ReplMaxTreeDepth=(ERRLOG_BASE+114); enum NELOG_ReplBadMsg=(ERRLOG_BASE+115); enum NELOG_ReplSysErr=(ERRLOG_BASE+116); enum NELOG_ReplUserLoged=(ERRLOG_BASE+117); enum NELOG_ReplBadImport=(ERRLOG_BASE+118); enum NELOG_ReplBadExport=(ERRLOG_BASE+119); enum NELOG_ReplSignalFileErr=(ERRLOG_BASE+120); enum NELOG_DiskFT=(ERRLOG_BASE+121); enum NELOG_ReplAccessDenied=(ERRLOG_BASE+122); enum NELOG_NetlogonFailedPrimary=(ERRLOG_BASE+123); enum NELOG_NetlogonPasswdSetFailed=(ERRLOG_BASE+124); enum NELOG_NetlogonTrackingError=(ERRLOG_BASE+125); enum NELOG_NetlogonSyncError=(ERRLOG_BASE+126); enum NELOG_UPS_PowerOut=(ERRLOG_BASE+130); enum NELOG_UPS_Shutdown=(ERRLOG_BASE+131); enum NELOG_UPS_CmdFileError=(ERRLOG_BASE+132); enum NELOG_UPS_CannotOpenDriver=(ERRLOG_BASE+133); enum NELOG_UPS_PowerBack=(ERRLOG_BASE+134); enum NELOG_UPS_CmdFileConfig=(ERRLOG_BASE+135); enum NELOG_UPS_CmdFileExec=(ERRLOG_BASE+136); enum NELOG_Missing_Parameter=(ERRLOG_BASE+150); enum NELOG_Invalid_Config_Line=(ERRLOG_BASE+151); enum NELOG_Invalid_Config_File=(ERRLOG_BASE+152); enum NELOG_File_Changed=(ERRLOG_BASE+153); enum NELOG_Files_Dont_Fit=(ERRLOG_BASE+154); enum NELOG_Wrong_DLL_Version=(ERRLOG_BASE+155); enum NELOG_Error_in_DLL=(ERRLOG_BASE+156); enum NELOG_System_Error=(ERRLOG_BASE+157); enum NELOG_FT_ErrLog_Too_Large=(ERRLOG_BASE+158); enum NELOG_FT_Update_In_Progress=(ERRLOG_BASE+159); enum NELOG_OEM_Code=(ERRLOG_BASE+199); enum NELOG_NetlogonSSIInitError=ERRLOG2_BASE; enum NELOG_NetlogonFailedToUpdateTrustList=(ERRLOG2_BASE+1); enum NELOG_NetlogonFailedToAddRpcInterface=(ERRLOG2_BASE+2); enum NELOG_NetlogonFailedToReadMailslot=(ERRLOG2_BASE+3); enum NELOG_NetlogonFailedToRegisterSC=(ERRLOG2_BASE+4); enum NELOG_NetlogonChangeLogCorrupt=(ERRLOG2_BASE+5); enum NELOG_NetlogonFailedToCreateShare=(ERRLOG2_BASE+6); enum NELOG_NetlogonDownLevelLogonFailed=(ERRLOG2_BASE+7); enum NELOG_NetlogonDownLevelLogoffFailed=(ERRLOG2_BASE+8); enum NELOG_NetlogonNTLogonFailed=(ERRLOG2_BASE+9); enum NELOG_NetlogonNTLogoffFailed=(ERRLOG2_BASE+10); enum NELOG_NetlogonPartialSyncCallSuccess=(ERRLOG2_BASE+11); enum NELOG_NetlogonPartialSyncCallFailed=(ERRLOG2_BASE+12); enum NELOG_NetlogonFullSyncCallSuccess=(ERRLOG2_BASE+13); enum NELOG_NetlogonFullSyncCallFailed=(ERRLOG2_BASE+14); enum NELOG_NetlogonPartialSyncSuccess=(ERRLOG2_BASE+15); enum NELOG_NetlogonPartialSyncFailed=(ERRLOG2_BASE+16); enum NELOG_NetlogonFullSyncSuccess=(ERRLOG2_BASE+17); enum NELOG_NetlogonFullSyncFailed=(ERRLOG2_BASE+18); enum NELOG_NetlogonAuthNoDomainController=(ERRLOG2_BASE+19); enum NELOG_NetlogonAuthNoTrustLsaSecret=(ERRLOG2_BASE+20); enum NELOG_NetlogonAuthNoTrustSamAccount=(ERRLOG2_BASE+21); enum NELOG_NetlogonServerAuthFailed=(ERRLOG2_BASE+22); enum NELOG_NetlogonServerAuthNoTrustSamAccount=(ERRLOG2_BASE+23); enum NELOG_FailedToRegisterSC=(ERRLOG2_BASE+24); enum NELOG_FailedToSetServiceStatus=(ERRLOG2_BASE+25); enum NELOG_FailedToGetComputerName=(ERRLOG2_BASE+26); enum NELOG_DriverNotLoaded=(ERRLOG2_BASE+27); enum NELOG_NoTranportLoaded=(ERRLOG2_BASE+28); enum NELOG_NetlogonFailedDomainDelta=(ERRLOG2_BASE+29); enum NELOG_NetlogonFailedGlobalGroupDelta=(ERRLOG2_BASE+30); enum NELOG_NetlogonFailedLocalGroupDelta=(ERRLOG2_BASE+31); enum NELOG_NetlogonFailedUserDelta=(ERRLOG2_BASE+32); enum NELOG_NetlogonFailedPolicyDelta=(ERRLOG2_BASE+33); enum NELOG_NetlogonFailedTrustedDomainDelta=(ERRLOG2_BASE+34); enum NELOG_NetlogonFailedAccountDelta=(ERRLOG2_BASE+35); enum NELOG_NetlogonFailedSecretDelta=(ERRLOG2_BASE+36); enum NELOG_NetlogonSystemError=(ERRLOG2_BASE+37); enum NELOG_NetlogonDuplicateMachineAccounts=(ERRLOG2_BASE+38); enum NELOG_NetlogonTooManyGlobalGroups=(ERRLOG2_BASE+39); enum NELOG_NetlogonBrowserDriver=(ERRLOG2_BASE+40); enum NELOG_NetlogonAddNameFailure=(ERRLOG2_BASE+41); enum NELOG_RplMessages=(ERRLOG2_BASE+42); enum NELOG_RplXnsBoot=(ERRLOG2_BASE+43); enum NELOG_RplSystem=(ERRLOG2_BASE+44); enum NELOG_RplWkstaTimeout=(ERRLOG2_BASE+45); enum NELOG_RplWkstaFileOpen=(ERRLOG2_BASE+46); enum NELOG_RplWkstaFileRead=(ERRLOG2_BASE+47); enum NELOG_RplWkstaMemory=(ERRLOG2_BASE+48); enum NELOG_RplWkstaFileChecksum=(ERRLOG2_BASE+49); enum NELOG_RplWkstaFileLineCount=(ERRLOG2_BASE+50); enum NELOG_RplWkstaBbcFile=(ERRLOG2_BASE+51); enum NELOG_RplWkstaFileSize=(ERRLOG2_BASE+52); enum NELOG_RplWkstaInternal=(ERRLOG2_BASE+53); enum NELOG_RplWkstaWrongVersion=(ERRLOG2_BASE+54); enum NELOG_RplWkstaNetwork=(ERRLOG2_BASE+55); enum NELOG_RplAdapterResource=(ERRLOG2_BASE+56); enum NELOG_RplFileCopy=(ERRLOG2_BASE+57); enum NELOG_RplFileDelete=(ERRLOG2_BASE+58); enum NELOG_RplFilePerms=(ERRLOG2_BASE+59); enum NELOG_RplCheckConfigs=(ERRLOG2_BASE+60); enum NELOG_RplCreateProfiles=(ERRLOG2_BASE+61); enum NELOG_RplRegistry=(ERRLOG2_BASE+62); enum NELOG_RplReplaceRPLDISK=(ERRLOG2_BASE+63); enum NELOG_RplCheckSecurity=(ERRLOG2_BASE+64); enum NELOG_RplBackupDatabase=(ERRLOG2_BASE+65); enum NELOG_RplInitDatabase=(ERRLOG2_BASE+66); enum NELOG_RplRestoreDatabaseFailure=(ERRLOG2_BASE+67); enum NELOG_RplRestoreDatabaseSuccess=(ERRLOG2_BASE+68); enum NELOG_RplInitRestoredDatabase=(ERRLOG2_BASE+69); enum NELOG_NetlogonSessionTypeWrong=(ERRLOG2_BASE+70); struct ERROR_LOG { DWORD el_len; DWORD el_reserved; DWORD el_time; DWORD el_error; LPWSTR el_name; LPWSTR el_text; LPBYTE el_data; DWORD el_data_size; DWORD el_nstrings; } alias ERROR_LOG* PERROR_LOG, LPERROR_LOG; extern (Windows) { deprecated { NET_API_STATUS NetErrorLogClear(LPCWSTR, LPCWSTR, LPBYTE); NET_API_STATUS NetErrorLogRead(LPCWSTR, LPWSTR, LPHLOG, DWORD, LPDWORD, DWORD, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD); NET_API_STATUS NetErrorLogWrite(LPBYTE, DWORD, LPCWSTR, LPBYTE, DWORD, LPBYTE, DWORD, LPBYTE); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ddeml.d0000664000175000017500000002424212776214756022750 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ddeml.d) */ module core.sys.windows.ddeml; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "user32"); private import core.sys.windows.basetsd, core.sys.windows.windef, core.sys.windows.winnt; enum : int { CP_WINANSI = 1004, CP_WINUNICODE = 1200 } enum : UINT { XTYPF_NOBLOCK = 2, XTYPF_NODATA = 4, XTYPF_ACKREQ = 8 } enum : UINT { XCLASS_MASK = 0xFC00, XCLASS_BOOL = 0x1000, XCLASS_DATA = 0x2000, XCLASS_FLAGS = 0x4000, XCLASS_NOTIFICATION = 0x8000 } enum : UINT { XST_NULL, XST_INCOMPLETE, XST_CONNECTED, XST_INIT1, XST_INIT2, XST_REQSENT, XST_DATARCVD, XST_POKESENT, XST_POKEACKRCVD, XST_EXECSENT, XST_EXECACKRCVD, XST_ADVSENT, XST_UNADVSENT, XST_ADVACKRCVD, XST_UNADVACKRCVD, XST_ADVDATASENT, XST_ADVDATAACKRCVD // = 16 } enum : UINT { XTYP_ERROR = XCLASS_NOTIFICATION | XTYPF_NOBLOCK, XTYP_ADVDATA = 0x0010 | XCLASS_FLAGS, XTYP_ADVREQ = 0x0020 | XCLASS_DATA | XTYPF_NOBLOCK, XTYP_ADVSTART = 0x0030 | XCLASS_BOOL, XTYP_ADVSTOP = 0x0040 | XCLASS_NOTIFICATION, XTYP_EXECUTE = 0x0050 | XCLASS_FLAGS, XTYP_CONNECT = 0x0060 | XCLASS_BOOL | XTYPF_NOBLOCK, XTYP_CONNECT_CONFIRM = 0x0070 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK, XTYP_XACT_COMPLETE = 0x0080 | XCLASS_NOTIFICATION, XTYP_POKE = 0x0090 | XCLASS_FLAGS, XTYP_REGISTER = 0x00A0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK, XTYP_REQUEST = 0x00B0 | XCLASS_DATA, XTYP_DISCONNECT = 0x00C0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK, XTYP_UNREGISTER = 0x00D0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK, XTYP_WILDCONNECT = 0x00E0 | XCLASS_DATA | XTYPF_NOBLOCK, XTYP_MONITOR = 0X00F0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK, XTYP_MASK = 0x00F0, XTYP_SHIFT = 4 } /+ #define TIMEOUT_ASYNC 0xFFFFFFFF #define QID_SYNC 0xFFFFFFFF +/ enum : UINT { ST_CONNECTED = 1, ST_ADVISE = 2, ST_ISLOCAL = 4, ST_BLOCKED = 8, ST_CLIENT = 16, ST_TERMINATED = 32, ST_INLIST = 64, ST_BLOCKNEXT = 128, ST_ISSELF = 256 } /+ #define CADV_LATEACK 0xFFFF +/ enum : UINT { DMLERR_NO_ERROR = 0, DMLERR_FIRST = 0x4000, DMLERR_ADVACKTIMEOUT = DMLERR_FIRST, DMLERR_BUSY, DMLERR_DATAACKTIMEOUT, DMLERR_DLL_NOT_INITIALIZED, DMLERR_DLL_USAGE, DMLERR_EXECACKTIMEOUT, DMLERR_INVALIDPARAMETER, DMLERR_LOW_MEMORY, DMLERR_MEMORY_ERROR, DMLERR_NOTPROCESSED, DMLERR_NO_CONV_ESTABLISHED, DMLERR_POKEACKTIMEOUT, DMLERR_POSTMSG_FAILED, DMLERR_REENTRANCY, DMLERR_SERVER_DIED, DMLERR_SYS_ERROR, DMLERR_UNADVACKTIMEOUT, DMLERR_UNFOUND_QUEUE_ID, // = 0x4011 DMLERR_LAST = DMLERR_UNFOUND_QUEUE_ID } /+ #define DDE_FACK 0x8000 #define DDE_FBUSY 0x4000 #define DDE_FDEFERUPD 0x4000 #define DDE_FACKREQ 0x8000 #define DDE_FRELEASE 0x2000 #define DDE_FREQUESTED 0x1000 #define DDE_FAPPSTATUS 0x00ff #define DDE_FNOTPROCESSED 0 #define DDE_FACKRESERVED (~(DDE_FACK|DDE_FBUSY|DDE_FAPPSTATUS)) #define DDE_FADVRESERVED (~(DDE_FACKREQ|DDE_FDEFERUPD)) #define DDE_FDATRESERVED (~(DDE_FACKREQ|DDE_FRELEASE|DDE_FREQUESTED)) #define DDE_FPOKRESERVED (~DDE_FRELEASE) #define MSGF_DDEMGR 0x8001 #define CBR_BLOCK ((HDDEDATA)0xffffffff) +/ enum DWORD APPCLASS_STANDARD = 0, APPCLASS_MONITOR = 0x00000001, APPCLASS_MASK = 0x0000000F, APPCMD_CLIENTONLY = 0x00000010, APPCMD_FILTERINITS = 0x00000020, APPCMD_MASK = 0x00000FF0, CBF_FAIL_SELFCONNECTIONS = 0x00001000, CBF_FAIL_CONNECTIONS = 0x00002000, CBF_FAIL_ADVISES = 0x00004000, CBF_FAIL_EXECUTES = 0x00008000, CBF_FAIL_POKES = 0x00010000, CBF_FAIL_REQUESTS = 0x00020000, CBF_FAIL_ALLSVRXACTIONS = 0x0003f000, CBF_SKIP_CONNECT_CONFIRMS = 0x00040000, CBF_SKIP_REGISTRATIONS = 0x00080000, CBF_SKIP_UNREGISTRATIONS = 0x00100000, CBF_SKIP_DISCONNECTS = 0x00200000, CBF_SKIP_ALLNOTIFICATIONS = 0x003c0000, MF_HSZ_INFO = 0x01000000, MF_SENDMSGS = 0x02000000, MF_POSTMSGS = 0x04000000, MF_CALLBACKS = 0x08000000, MF_ERRORS = 0x10000000, MF_LINKS = 0x20000000, MF_CONV = 0x40000000, MF_MASK = 0xFF000000; enum : UINT { EC_ENABLEALL = 0, EC_ENABLEONE = ST_BLOCKNEXT, EC_DISABLE = ST_BLOCKED, EC_QUERYWAITING = 2 } enum : UINT { DNS_REGISTER = 1, DNS_UNREGISTER = 2, DNS_FILTERON = 4, DNS_FILTEROFF = 8 } /+ #define HDATA_APPOWNED 1 #define MAX_MONITORS 4 +/ enum : int { MH_CREATE = 1, MH_KEEP = 2, MH_DELETE = 3, MH_CLEANUP = 4 } mixin DECLARE_HANDLE!("HCONVLIST"); mixin DECLARE_HANDLE!("HCONV"); mixin DECLARE_HANDLE!("HSZ"); mixin DECLARE_HANDLE!("HDDEDATA"); extern (Windows) alias HDDEDATA function(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD) PFNCALLBACK; struct HSZPAIR { HSZ hszSvc; HSZ hszTopic; } alias HSZPAIR* PHSZPAIR; struct CONVCONTEXT { UINT cb = CONVCONTEXT.sizeof; UINT wFlags; UINT wCountryID; int iCodePage; DWORD dwLangID; DWORD dwSecurity; SECURITY_QUALITY_OF_SERVICE qos; } alias CONVCONTEXT* PCONVCONTEXT; struct CONVINFO { DWORD cb = CONVINFO.sizeof; DWORD hUser; HCONV hConvPartner; HSZ hszSvcPartner; HSZ hszServiceReq; HSZ hszTopic; HSZ hszItem; UINT wFmt; UINT wType; UINT wStatus; UINT wConvst; UINT wLastError; HCONVLIST hConvList; CONVCONTEXT ConvCtxt; HWND hwnd; HWND hwndPartner; } alias CONVINFO* PCONVINFO; struct DDEML_MSG_HOOK_DATA { UINT_PTR uiLo; UINT_PTR uiHi; DWORD cbData; DWORD[8] Data; } struct MONHSZSTRUCT { UINT cb = MONHSZSTRUCT.sizeof; int fsAction; DWORD dwTime; HSZ hsz; HANDLE hTask; TCHAR[1] _str; TCHAR* str() return { return _str.ptr; } } alias MONHSZSTRUCT* PMONHSZSTRUCT; struct MONLINKSTRUCT { UINT cb = MONLINKSTRUCT.sizeof; DWORD dwTime; HANDLE hTask; BOOL fEstablished; BOOL fNoData; HSZ hszSvc; HSZ hszTopic; HSZ hszItem; UINT wFmt; BOOL fServer; HCONV hConvServer; HCONV hConvClient; } alias MONLINKSTRUCT* PMONLINKSTRUCT; struct MONCONVSTRUCT { UINT cb = MONCONVSTRUCT.sizeof; BOOL fConnect; DWORD dwTime; HANDLE hTask; HSZ hszSvc; HSZ hszTopic; HCONV hConvClient; HCONV hConvServer; } alias MONCONVSTRUCT* PMONCONVSTRUCT; struct MONCBSTRUCT { UINT cb = MONCBSTRUCT.sizeof; DWORD dwTime; HANDLE hTask; DWORD dwRet; UINT wType; UINT wFmt; HCONV hConv; HSZ hsz1; HSZ hsz2; HDDEDATA hData; ULONG_PTR dwData1; ULONG_PTR dwData2; CONVCONTEXT cc; DWORD cbData; DWORD[8] Data; } alias MONCBSTRUCT* PMONCBSTRUCT; struct MONERRSTRUCT { UINT cb = MONERRSTRUCT.sizeof; UINT wLastError; DWORD dwTime; HANDLE hTask; } alias MONERRSTRUCT* PMONERRSTRUCT; struct MONMSGSTRUCT { UINT cb = MONMSGSTRUCT.sizeof; HWND hwndTo; DWORD dwTime; HANDLE hTask; UINT wMsg; WPARAM wParam; LPARAM lParam; DDEML_MSG_HOOK_DATA dmhd; } alias MONMSGSTRUCT* PMONMSGSTRUCT; extern (Windows) { BOOL DdeAbandonTransaction(DWORD, HCONV, DWORD); PBYTE DdeAccessData(HDDEDATA, PDWORD); HDDEDATA DdeAddData(HDDEDATA, PBYTE, DWORD, DWORD); HDDEDATA DdeClientTransaction(PBYTE, DWORD, HCONV, HSZ, UINT, UINT, DWORD, PDWORD); int DdeCmpStringHandles(HSZ, HSZ); HCONV DdeConnect(DWORD, HSZ, HSZ, PCONVCONTEXT); HCONVLIST DdeConnectList(DWORD, HSZ, HSZ, HCONVLIST, PCONVCONTEXT); HDDEDATA DdeCreateDataHandle(DWORD, PBYTE, DWORD, DWORD, HSZ, UINT, UINT); HSZ DdeCreateStringHandleA(DWORD, LPSTR, int); HSZ DdeCreateStringHandleW(DWORD, LPWSTR, int); BOOL DdeDisconnect(HCONV); BOOL DdeDisconnectList(HCONVLIST); BOOL DdeEnableCallback(DWORD, HCONV, UINT); BOOL DdeFreeDataHandle(HDDEDATA); BOOL DdeFreeStringHandle(DWORD, HSZ); DWORD DdeGetData(HDDEDATA, PBYTE, DWORD, DWORD); UINT DdeGetLastError(DWORD); BOOL DdeImpersonateClient(HCONV); UINT DdeInitializeA(PDWORD, PFNCALLBACK, DWORD, DWORD); UINT DdeInitializeW(PDWORD, PFNCALLBACK, DWORD, DWORD); BOOL DdeKeepStringHandle(DWORD, HSZ); HDDEDATA DdeNameService(DWORD, HSZ, HSZ, UINT); BOOL DdePostAdvise(DWORD, HSZ, HSZ); UINT DdeQueryConvInfo(HCONV, DWORD, PCONVINFO); HCONV DdeQueryNextServer(HCONVLIST, HCONV); DWORD DdeQueryStringA(DWORD, HSZ, LPSTR, DWORD, int); DWORD DdeQueryStringW(DWORD, HSZ, LPWSTR, DWORD, int); HCONV DdeReconnect(HCONV); BOOL DdeSetUserHandle(HCONV, DWORD, DWORD); BOOL DdeUnaccessData(HDDEDATA); BOOL DdeUninitialize(DWORD); } const TCHAR[] SZDDESYS_TOPIC = "System", SZDDESYS_ITEM_TOPICS = "Topics", SZDDESYS_ITEM_SYSITEMS = "SysItems", SZDDESYS_ITEM_RTNMSG = "ReturnMessage", SZDDESYS_ITEM_STATUS = "Status", SZDDESYS_ITEM_FORMATS = "Formats", SZDDESYS_ITEM_HELP = "Help", SZDDE_ITEM_ITEMLIST = "TopicItemList"; version (Unicode) { alias DdeCreateStringHandleW DdeCreateStringHandle; alias DdeInitializeW DdeInitialize; alias DdeQueryStringW DdeQueryString; } else { alias DdeCreateStringHandleA DdeCreateStringHandle; alias DdeInitializeA DdeInitialize; alias DdeQueryStringA DdeQueryString; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winsvc.d0000664000175000017500000003466112776214756023202 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winsvc.d) */ module core.sys.windows.winsvc; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "advapi32"); private import core.sys.windows.w32api, core.sys.windows.windef; // FIXME: check Windows version support const TCHAR[] SERVICES_ACTIVE_DATABASE = "ServicesActive", SERVICES_FAILED_DATABASE = "ServicesFailed"; const TCHAR SC_GROUP_IDENTIFIER = '+'; enum DWORD SC_MANAGER_ALL_ACCESS = 0xf003f, SC_MANAGER_CONNECT = 1, SC_MANAGER_CREATE_SERVICE = 2, SC_MANAGER_ENUMERATE_SERVICE = 4, SC_MANAGER_LOCK = 8, SC_MANAGER_QUERY_LOCK_STATUS = 16, SC_MANAGER_MODIFY_BOOT_CONFIG = 32; enum DWORD SERVICE_NO_CHANGE = 0xffffffff; enum : DWORD { SERVICE_STOPPED = 1, SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_RUNNING, SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING, SERVICE_PAUSED // = 7 } enum DWORD SERVICE_ACCEPT_STOP = 1, SERVICE_ACCEPT_PAUSE_CONTINUE = 2, SERVICE_ACCEPT_SHUTDOWN = 4, SERVICE_ACCEPT_PARAMCHANGE = 8, SERVICE_ACCEPT_NETBINDCHANGE = 16, SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32, SERVICE_ACCEPT_POWEREVENT = 64, SERVICE_ACCEPT_SESSIONCHANGE = 128; enum : DWORD { SERVICE_CONTROL_STOP = 1, SERVICE_CONTROL_PAUSE, SERVICE_CONTROL_CONTINUE, SERVICE_CONTROL_INTERROGATE, SERVICE_CONTROL_SHUTDOWN, SERVICE_CONTROL_PARAMCHANGE, SERVICE_CONTROL_NETBINDADD, SERVICE_CONTROL_NETBINDREMOVE, SERVICE_CONTROL_NETBINDENABLE, SERVICE_CONTROL_NETBINDDISABLE, SERVICE_CONTROL_DEVICEEVENT, SERVICE_CONTROL_HARDWAREPROFILECHANGE, SERVICE_CONTROL_POWEREVENT, SERVICE_CONTROL_SESSIONCHANGE, // = 14 } enum : DWORD { SERVICE_ACTIVE = 1, SERVICE_INACTIVE, SERVICE_STATE_ALL } enum DWORD SERVICE_QUERY_CONFIG = 0x0001, SERVICE_CHANGE_CONFIG = 0x0002, SERVICE_QUERY_STATUS = 0x0004, SERVICE_ENUMERATE_DEPENDENTS = 0x0008, SERVICE_START = 0x0010, SERVICE_STOP = 0x0020, SERVICE_PAUSE_CONTINUE = 0x0040, SERVICE_INTERROGATE = 0x0080, SERVICE_USER_DEFINED_CONTROL = 0x0100, SERVICE_ALL_ACCESS = 0x01FF | STANDARD_RIGHTS_REQUIRED; // This is not documented on the MSDN site enum SERVICE_RUNS_IN_SYSTEM_PROCESS = 1; enum : DWORD { SERVICE_CONFIG_DESCRIPTION = 1, SERVICE_CONFIG_FAILURE_ACTIONS, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, SERVICE_CONFIG_SERVICE_SID_INFO, SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, SERVICE_CONFIG_PRESHUTDOWN_INFO // = 7 } struct SERVICE_STATUS { DWORD dwServiceType; DWORD dwCurrentState; DWORD dwControlsAccepted; DWORD dwWin32ExitCode; DWORD dwServiceSpecificExitCode; DWORD dwCheckPoint; DWORD dwWaitHint; } alias SERVICE_STATUS* LPSERVICE_STATUS; struct ENUM_SERVICE_STATUSA { LPSTR lpServiceName; LPSTR lpDisplayName; SERVICE_STATUS ServiceStatus; } alias ENUM_SERVICE_STATUSA* LPENUM_SERVICE_STATUSA; struct ENUM_SERVICE_STATUSW { LPWSTR lpServiceName; LPWSTR lpDisplayName; SERVICE_STATUS ServiceStatus; } alias ENUM_SERVICE_STATUSW* LPENUM_SERVICE_STATUSW; struct QUERY_SERVICE_CONFIGA { DWORD dwServiceType; DWORD dwStartType; DWORD dwErrorControl; LPSTR lpBinaryPathName; LPSTR lpLoadOrderGroup; DWORD dwTagId; LPSTR lpDependencies; LPSTR lpServiceStartName; LPSTR lpDisplayName; } alias QUERY_SERVICE_CONFIGA* LPQUERY_SERVICE_CONFIGA; struct QUERY_SERVICE_CONFIGW { DWORD dwServiceType; DWORD dwStartType; DWORD dwErrorControl; LPWSTR lpBinaryPathName; LPWSTR lpLoadOrderGroup; DWORD dwTagId; LPWSTR lpDependencies; LPWSTR lpServiceStartName; LPWSTR lpDisplayName; } alias QUERY_SERVICE_CONFIGW* LPQUERY_SERVICE_CONFIGW; struct QUERY_SERVICE_LOCK_STATUSA { DWORD fIsLocked; LPSTR lpLockOwner; DWORD dwLockDuration; } alias QUERY_SERVICE_LOCK_STATUSA* LPQUERY_SERVICE_LOCK_STATUSA; struct QUERY_SERVICE_LOCK_STATUSW { DWORD fIsLocked; LPWSTR lpLockOwner; DWORD dwLockDuration; } alias QUERY_SERVICE_LOCK_STATUSW* LPQUERY_SERVICE_LOCK_STATUSW; extern (Windows) { alias void function(DWORD, LPSTR*) LPSERVICE_MAIN_FUNCTIONA; alias void function(DWORD, LPWSTR*) LPSERVICE_MAIN_FUNCTIONW; } struct SERVICE_TABLE_ENTRYA { LPSTR lpServiceName; LPSERVICE_MAIN_FUNCTIONA lpServiceProc; } alias SERVICE_TABLE_ENTRYA* LPSERVICE_TABLE_ENTRYA; struct SERVICE_TABLE_ENTRYW { LPWSTR lpServiceName; LPSERVICE_MAIN_FUNCTIONW lpServiceProc; } alias SERVICE_TABLE_ENTRYW* LPSERVICE_TABLE_ENTRYW; mixin DECLARE_HANDLE!("SC_HANDLE"); alias SC_HANDLE* LPSC_HANDLE; alias void* SC_LOCK; mixin DECLARE_HANDLE!("SERVICE_STATUS_HANDLE"); extern (Windows) { alias void function(DWORD) LPHANDLER_FUNCTION; alias DWORD function(DWORD, DWORD, LPVOID, LPVOID) LPHANDLER_FUNCTION_EX; } static if (_WIN32_WINNT >= 0x500) { struct SERVICE_STATUS_PROCESS { DWORD dwServiceType; DWORD dwCurrentState; DWORD dwControlsAccepted; DWORD dwWin32ExitCode; DWORD dwServiceSpecificExitCode; DWORD dwCheckPoint; DWORD dwWaitHint; DWORD dwProcessId; DWORD dwServiceFlags; } alias SERVICE_STATUS_PROCESS* LPSERVICE_STATUS_PROCESS; enum SC_STATUS_TYPE { SC_STATUS_PROCESS_INFO = 0 } enum SC_ENUM_TYPE { SC_ENUM_PROCESS_INFO = 0 } struct ENUM_SERVICE_STATUS_PROCESSA { LPSTR lpServiceName; LPSTR lpDisplayName; SERVICE_STATUS_PROCESS ServiceStatusProcess; } alias ENUM_SERVICE_STATUS_PROCESSA* LPENUM_SERVICE_STATUS_PROCESSA; struct ENUM_SERVICE_STATUS_PROCESSW { LPWSTR lpServiceName; LPWSTR lpDisplayName; SERVICE_STATUS_PROCESS ServiceStatusProcess; } alias ENUM_SERVICE_STATUS_PROCESSW* LPENUM_SERVICE_STATUS_PROCESSW; struct SERVICE_DESCRIPTIONA { LPSTR lpDescription; } alias SERVICE_DESCRIPTIONA* LPSERVICE_DESCRIPTIONA; struct SERVICE_DESCRIPTIONW { LPWSTR lpDescription; } alias SERVICE_DESCRIPTIONW* LPSERVICE_DESCRIPTIONW; enum SC_ACTION_TYPE { SC_ACTION_NONE, SC_ACTION_RESTART, SC_ACTION_REBOOT, SC_ACTION_RUN_COMMAND } struct SC_ACTION { SC_ACTION_TYPE Type; DWORD Delay; } alias SC_ACTION* LPSC_ACTION; struct SERVICE_FAILURE_ACTIONSA { DWORD dwResetPeriod; LPSTR lpRebootMsg; LPSTR lpCommand; DWORD cActions; SC_ACTION* lpsaActions; } alias SERVICE_FAILURE_ACTIONSA* LPSERVICE_FAILURE_ACTIONSA; struct SERVICE_FAILURE_ACTIONSW { DWORD dwResetPeriod; LPWSTR lpRebootMsg; LPWSTR lpCommand; DWORD cActions; SC_ACTION* lpsaActions; } alias SERVICE_FAILURE_ACTIONSW* LPSERVICE_FAILURE_ACTIONSW; } extern (Windows) { BOOL ChangeServiceConfigA(SC_HANDLE, DWORD, DWORD, DWORD, LPCSTR, LPCSTR, LPDWORD, LPCSTR, LPCSTR, LPCSTR, LPCSTR); BOOL ChangeServiceConfigW(SC_HANDLE, DWORD, DWORD, DWORD, LPCWSTR, LPCWSTR, LPDWORD, LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR); BOOL CloseServiceHandle(SC_HANDLE); BOOL ControlService(SC_HANDLE, DWORD, LPSERVICE_STATUS); SC_HANDLE CreateServiceA(SC_HANDLE, LPCSTR, LPCSTR, DWORD, DWORD, DWORD, DWORD, LPCSTR, LPCSTR, PDWORD, LPCSTR, LPCSTR, LPCSTR); SC_HANDLE CreateServiceW(SC_HANDLE, LPCWSTR, LPCWSTR, DWORD, DWORD, DWORD, DWORD, LPCWSTR, LPCWSTR, PDWORD, LPCWSTR, LPCWSTR, LPCWSTR); BOOL DeleteService(SC_HANDLE); BOOL EnumDependentServicesA(SC_HANDLE, DWORD, LPENUM_SERVICE_STATUSA, DWORD, PDWORD, PDWORD); BOOL EnumDependentServicesW(SC_HANDLE, DWORD, LPENUM_SERVICE_STATUSW, DWORD, PDWORD, PDWORD); BOOL EnumServicesStatusA(SC_HANDLE, DWORD, DWORD, LPENUM_SERVICE_STATUSA, DWORD, PDWORD, PDWORD, PDWORD); BOOL EnumServicesStatusW(SC_HANDLE, DWORD, DWORD, LPENUM_SERVICE_STATUSW, DWORD, PDWORD, PDWORD, PDWORD); BOOL GetServiceDisplayNameA(SC_HANDLE, LPCSTR, LPSTR, PDWORD); BOOL GetServiceDisplayNameW(SC_HANDLE, LPCWSTR, LPWSTR, PDWORD); BOOL GetServiceKeyNameA(SC_HANDLE, LPCSTR, LPSTR, PDWORD); BOOL GetServiceKeyNameW(SC_HANDLE, LPCWSTR, LPWSTR, PDWORD); SC_LOCK LockServiceDatabase(SC_HANDLE); BOOL NotifyBootConfigStatus(BOOL); SC_HANDLE OpenSCManagerA(LPCSTR, LPCSTR, DWORD); SC_HANDLE OpenSCManagerW(LPCWSTR, LPCWSTR, DWORD); SC_HANDLE OpenServiceA(SC_HANDLE, LPCSTR, DWORD); SC_HANDLE OpenServiceW(SC_HANDLE, LPCWSTR, DWORD); BOOL QueryServiceConfigA(SC_HANDLE, LPQUERY_SERVICE_CONFIGA, DWORD, PDWORD); BOOL QueryServiceConfigW(SC_HANDLE, LPQUERY_SERVICE_CONFIGW, DWORD, PDWORD); BOOL QueryServiceLockStatusA(SC_HANDLE, LPQUERY_SERVICE_LOCK_STATUSA, DWORD, PDWORD); BOOL QueryServiceLockStatusW(SC_HANDLE, LPQUERY_SERVICE_LOCK_STATUSW, DWORD, PDWORD); BOOL QueryServiceObjectSecurity(SC_HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, LPDWORD); BOOL QueryServiceStatus(SC_HANDLE, LPSERVICE_STATUS); SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerA(LPCSTR, LPHANDLER_FUNCTION); SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerW(LPCWSTR, LPHANDLER_FUNCTION); BOOL SetServiceObjectSecurity(SC_HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); BOOL SetServiceStatus(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS); BOOL StartServiceA(SC_HANDLE, DWORD, LPCSTR*); BOOL StartServiceW(SC_HANDLE, DWORD, LPCWSTR*); BOOL StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA); BOOL StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW); BOOL UnlockServiceDatabase(SC_LOCK); static if (_WIN32_WINNT >= 0x500) { BOOL EnumServicesStatusExA(SC_HANDLE, SC_ENUM_TYPE, DWORD, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD, LPDWORD, LPCSTR); BOOL EnumServicesStatusExW(SC_HANDLE, SC_ENUM_TYPE, DWORD, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD, LPDWORD, LPCWSTR); BOOL QueryServiceConfig2A(SC_HANDLE, DWORD, LPBYTE, DWORD, LPDWORD); BOOL QueryServiceConfig2W(SC_HANDLE, DWORD, LPBYTE, DWORD, LPDWORD); BOOL QueryServiceStatusEx(SC_HANDLE, SC_STATUS_TYPE, LPBYTE, DWORD, LPDWORD); SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerExA(LPCSTR, LPHANDLER_FUNCTION_EX, LPVOID); SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerExW(LPCWSTR, LPHANDLER_FUNCTION_EX, LPVOID); } static if (_WIN32_WINNT >= 0x501) { BOOL ChangeServiceConfig2A(SC_HANDLE, DWORD, LPVOID); BOOL ChangeServiceConfig2W(SC_HANDLE, DWORD, LPVOID); } } version (Unicode) { alias ENUM_SERVICE_STATUSW ENUM_SERVICE_STATUS; alias QUERY_SERVICE_CONFIGW QUERY_SERVICE_CONFIG; alias QUERY_SERVICE_LOCK_STATUSW QUERY_SERVICE_LOCK_STATUS; alias LPSERVICE_MAIN_FUNCTIONW LPSERVICE_MAIN_FUNCTION; alias SERVICE_TABLE_ENTRYW SERVICE_TABLE_ENTRY; alias ChangeServiceConfigW ChangeServiceConfig; alias CreateServiceW CreateService; alias EnumDependentServicesW EnumDependentServices; alias EnumServicesStatusW EnumServicesStatus; alias GetServiceDisplayNameW GetServiceDisplayName; alias GetServiceKeyNameW GetServiceKeyName; alias OpenSCManagerW OpenSCManager; alias OpenServiceW OpenService; alias QueryServiceConfigW QueryServiceConfig; alias QueryServiceLockStatusW QueryServiceLockStatus; alias RegisterServiceCtrlHandlerW RegisterServiceCtrlHandler; alias StartServiceW StartService; alias StartServiceCtrlDispatcherW StartServiceCtrlDispatcher; static if (_WIN32_WINNT >= 0x500) { alias ENUM_SERVICE_STATUS_PROCESSW ENUM_SERVICE_STATUS_PROCESS; alias SERVICE_DESCRIPTIONW SERVICE_DESCRIPTION; alias SERVICE_FAILURE_ACTIONSW SERVICE_FAILURE_ACTIONS; alias EnumServicesStatusExW EnumServicesStatusEx; alias QueryServiceConfig2W QueryServiceConfig2; alias RegisterServiceCtrlHandlerExW RegisterServiceCtrlHandlerEx; } static if (_WIN32_WINNT >= 0x501) { alias ChangeServiceConfig2W ChangeServiceConfig2; } } else { alias ENUM_SERVICE_STATUSA ENUM_SERVICE_STATUS; alias QUERY_SERVICE_CONFIGA QUERY_SERVICE_CONFIG; alias QUERY_SERVICE_LOCK_STATUSA QUERY_SERVICE_LOCK_STATUS; alias LPSERVICE_MAIN_FUNCTIONA LPSERVICE_MAIN_FUNCTION; alias SERVICE_TABLE_ENTRYA SERVICE_TABLE_ENTRY; alias ChangeServiceConfigA ChangeServiceConfig; alias CreateServiceA CreateService; alias EnumDependentServicesA EnumDependentServices; alias EnumServicesStatusA EnumServicesStatus; alias GetServiceDisplayNameA GetServiceDisplayName; alias GetServiceKeyNameA GetServiceKeyName; alias OpenSCManagerA OpenSCManager; alias OpenServiceA OpenService; alias QueryServiceConfigA QueryServiceConfig; alias QueryServiceLockStatusA QueryServiceLockStatus; alias RegisterServiceCtrlHandlerA RegisterServiceCtrlHandler; alias StartServiceA StartService; alias StartServiceCtrlDispatcherA StartServiceCtrlDispatcher; static if (_WIN32_WINNT >= 0x500) { alias ENUM_SERVICE_STATUS_PROCESSA ENUM_SERVICE_STATUS_PROCESS; alias SERVICE_DESCRIPTIONA SERVICE_DESCRIPTION; alias SERVICE_FAILURE_ACTIONSA SERVICE_FAILURE_ACTIONS; alias EnumServicesStatusExA EnumServicesStatusEx; alias QueryServiceConfig2A QueryServiceConfig2; alias RegisterServiceCtrlHandlerExA RegisterServiceCtrlHandlerEx; } static if (_WIN32_WINNT >= 0x501) { alias ChangeServiceConfig2A ChangeServiceConfig2; } } alias ENUM_SERVICE_STATUS* LPENUM_SERVICE_STATUS; alias QUERY_SERVICE_CONFIG* LPQUERY_SERVICE_CONFIG; alias QUERY_SERVICE_LOCK_STATUS* LPQUERY_SERVICE_LOCK_STATUS; alias SERVICE_TABLE_ENTRY* LPSERVICE_TABLE_ENTRY; static if (_WIN32_WINNT >= 0x500) { alias ENUM_SERVICE_STATUS_PROCESS* LPENUM_SERVICE_STATUS_PROCESS; alias SERVICE_DESCRIPTION* LPSERVICE_DESCRIPTION; alias SERVICE_FAILURE_ACTIONS* LPSERVICE_FAILURE_ACTIONS; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/mgmtapi.d0000664000175000017500000000273212776214756023321 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_mgmtapi.d) */ module core.sys.windows.mgmtapi; version (Windows): import core.sys.windows.snmp; private import core.sys.windows.windef; enum { SNMP_MGMTAPI_TIMEOUT = 40, SNMP_MGMTAPI_SELECT_FDERRORS, SNMP_MGMTAPI_TRAP_ERRORS, SNMP_MGMTAPI_TRAP_DUPINIT, SNMP_MGMTAPI_NOTRAPS, SNMP_MGMTAPI_AGAIN, SNMP_MGMTAPI_INVALID_CTL, SNMP_MGMTAPI_INVALID_SESSION, SNMP_MGMTAPI_INVALID_BUFFER // = 48 } enum MGMCTL_SETAGENTPORT = 1; alias PVOID LPSNMP_MGR_SESSION; extern (Windows) { BOOL SnmpMgrClose(LPSNMP_MGR_SESSION); BOOL SnmpMgrCtl(LPSNMP_MGR_SESSION, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD); BOOL SnmpMgrGetTrap(AsnObjectIdentifier*, AsnNetworkAddress*, AsnInteger*, AsnInteger*, AsnTimeticks*, SnmpVarBindList*); BOOL SnmpMgrGetTrapEx(AsnObjectIdentifier*, AsnNetworkAddress*, AsnNetworkAddress*, AsnInteger*, AsnInteger*, AsnOctetString*, AsnTimeticks*, SnmpVarBindList*); BOOL SnmpMgrOidToStr(AsnObjectIdentifier*, LPSTR*); LPSNMP_MGR_SESSION SnmpMgrOpen(LPSTR, LPSTR, INT, INT); INT SnmpMgrRequest(LPSNMP_MGR_SESSION, BYTE, SnmpVarBindList*, AsnInteger*, AsnInteger*); BOOL SnmpMgrStrToOid(LPSTR, AsnObjectIdentifier*); BOOL SnmpMgrTrapListen(HANDLE*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rassapi.d0000664000175000017500000001400512776214756023321 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rassapi.d) */ module core.sys.windows.rassapi; version (Windows): private import core.sys.windows.lmcons, core.sys.windows.windef; // FIXME: check types of constants enum size_t RASSAPI_MAX_PHONENUMBER_SIZE = 128, RASSAPI_MAX_MEDIA_NAME = 16, RASSAPI_MAX_PORT_NAME = 16, RASSAPI_MAX_DEVICE_NAME = 128, RASSAPI_MAX_DEVICETYPE_NAME = 16, RASSAPI_MAX_PARAM_KEY_SIZE = 32; enum RASPRIV_NoCallback = 0x01; enum RASPRIV_AdminSetCallback = 0x02; enum RASPRIV_CallerSetCallback = 0x04; enum RASPRIV_DialinPrivilege = 0x08; enum RASPRIV_CallbackType = 0x07; enum { RAS_MODEM_OPERATIONAL = 1, RAS_MODEM_NOT_RESPONDING, RAS_MODEM_HARDWARE_FAILURE, RAS_MODEM_INCORRECT_RESPONSE, RAS_MODEM_UNKNOWN // = 5 } enum { RAS_PORT_NON_OPERATIONAL = 1, RAS_PORT_DISCONNECTED, RAS_PORT_CALLING_BACK, RAS_PORT_LISTENING, RAS_PORT_AUTHENTICATING, RAS_PORT_AUTHENTICATED, RAS_PORT_INITIALIZING // = 7 } enum { MEDIA_UNKNOWN, MEDIA_SERIAL, MEDIA_RAS10_SERIAL, MEDIA_X25, MEDIA_ISDN } enum USER_AUTHENTICATED = 0x0001; enum MESSENGER_PRESENT = 0x0002; enum PPP_CLIENT = 0x0004; enum GATEWAY_ACTIVE = 0x0008; enum REMOTE_LISTEN = 0x0010; enum PORT_MULTILINKED = 0x0020; enum size_t RAS_IPADDRESSLEN = 15, RAS_IPXADDRESSLEN = 22, RAS_ATADDRESSLEN = 32; // FIXME: should these be grouped together? enum { RASDOWNLEVEL = 10, RASADMIN_35 = 35, RASADMIN_CURRENT = 40 } alias ULONG IPADDR; enum RAS_PARAMS_FORMAT { ParamNumber = 0, ParamString } union RAS_PARAMS_VALUE { DWORD Number; struct _String { DWORD Length; PCHAR Data; } _String String; } struct RAS_PARAMETERS { CHAR[RASSAPI_MAX_PARAM_KEY_SIZE] P_Key; RAS_PARAMS_FORMAT P_Type; BYTE P_Attributes; RAS_PARAMS_VALUE P_Value; } struct RAS_USER_0 { BYTE bfPrivilege; WCHAR[RASSAPI_MAX_PHONENUMBER_SIZE + 1] szPhoneNumber; } alias RAS_USER_0* PRAS_USER_0; struct RAS_PORT_0 { WCHAR[RASSAPI_MAX_PORT_NAME] wszPortName; WCHAR[RASSAPI_MAX_DEVICETYPE_NAME] wszDeviceType; WCHAR[RASSAPI_MAX_DEVICE_NAME] wszDeviceName; WCHAR[RASSAPI_MAX_MEDIA_NAME] wszMediaName; DWORD reserved; DWORD Flags; WCHAR[UNLEN + 1] wszUserName; WCHAR[NETBIOS_NAME_LEN] wszComputer; DWORD dwStartSessionTime; // seconds from 1/1/1970 WCHAR[DNLEN + 1] wszLogonDomain; BOOL fAdvancedServer; } alias RAS_PORT_0* PRAS_PORT_0; struct RAS_PPP_NBFCP_RESULT { DWORD dwError; DWORD dwNetBiosError; CHAR[NETBIOS_NAME_LEN + 1] szName; WCHAR[NETBIOS_NAME_LEN + 1] wszWksta; } struct RAS_PPP_IPCP_RESULT { DWORD dwError; WCHAR[RAS_IPADDRESSLEN + 1] wszAddress; } struct RAS_PPP_IPXCP_RESULT { DWORD dwError; WCHAR[RAS_IPXADDRESSLEN + 1] wszAddress; } struct RAS_PPP_ATCP_RESULT { DWORD dwError; WCHAR[RAS_ATADDRESSLEN + 1] wszAddress; } struct RAS_PPP_PROJECTION_RESULT { RAS_PPP_NBFCP_RESULT nbf; RAS_PPP_IPCP_RESULT ip; RAS_PPP_IPXCP_RESULT ipx; RAS_PPP_ATCP_RESULT at; } struct RAS_PORT_1 { RAS_PORT_0 rasport0; DWORD LineCondition; DWORD HardwareCondition; DWORD LineSpeed; WORD NumStatistics; WORD NumMediaParms; DWORD SizeMediaParms; RAS_PPP_PROJECTION_RESULT ProjResult; } alias RAS_PORT_1* PRAS_PORT_1; struct RAS_PORT_STATISTICS { DWORD dwBytesXmited; DWORD dwBytesRcved; DWORD dwFramesXmited; DWORD dwFramesRcved; DWORD dwCrcErr; DWORD dwTimeoutErr; DWORD dwAlignmentErr; DWORD dwHardwareOverrunErr; DWORD dwFramingErr; DWORD dwBufferOverrunErr; DWORD dwBytesXmitedUncompressed; DWORD dwBytesRcvedUncompressed; DWORD dwBytesXmitedCompressed; DWORD dwBytesRcvedCompressed; DWORD dwPortBytesXmited; DWORD dwPortBytesRcved; DWORD dwPortFramesXmited; DWORD dwPortFramesRcved; DWORD dwPortCrcErr; DWORD dwPortTimeoutErr; DWORD dwPortAlignmentErr; DWORD dwPortHardwareOverrunErr; DWORD dwPortFramingErr; DWORD dwPortBufferOverrunErr; DWORD dwPortBytesXmitedUncompressed; DWORD dwPortBytesRcvedUncompressed; DWORD dwPortBytesXmitedCompressed; DWORD dwPortBytesRcvedCompressed; } alias RAS_PORT_STATISTICS* PRAS_PORT_STATISTICS; struct RAS_SERVER_0 { WORD TotalPorts; WORD PortsInUse; DWORD RasVersion; } alias RAS_SERVER_0* PRAS_SERVER_0; extern (Windows) { DWORD RasAdminServerGetInfo(const(WCHAR)*, PRAS_SERVER_0); DWORD RasAdminGetUserAccountServer(const(WCHAR)*, const(WCHAR)*, LPWSTR); DWORD RasAdminUserGetInfo(const(WCHAR)*, const(WCHAR)*, PRAS_USER_0); DWORD RasAdminUserSetInfo(const(WCHAR)*, const(WCHAR)*, PRAS_USER_0); DWORD RasAdminPortEnum(WCHAR*, PRAS_PORT_0*, WORD*); DWORD RasAdminPortGetInfo(const(WCHAR)*, const(WCHAR)*, RAS_PORT_1*, RAS_PORT_STATISTICS*, RAS_PARAMETERS**); DWORD RasAdminPortClearStatistics(const(WCHAR)*, const(WCHAR)*); DWORD RasAdminPortDisconnect(const(WCHAR)*, const(WCHAR)*); DWORD RasAdminFreeBuffer(PVOID); DWORD RasAdminGetErrorString(UINT, WCHAR*, DWORD); BOOL RasAdminAcceptNewConnection(RAS_PORT_1*, RAS_PORT_STATISTICS*, RAS_PARAMETERS*); VOID RasAdminConnectionHangupNotification(RAS_PORT_1*, RAS_PORT_STATISTICS*, RAS_PARAMETERS*); DWORD RasAdminGetIpAddressForUser (WCHAR*, WCHAR*, IPADDR*, BOOL*); VOID RasAdminReleaseIpAddress (WCHAR*, WCHAR*,IPADDR*); DWORD RasAdminGetUserParms(WCHAR*, PRAS_USER_0); DWORD RasAdminSetUserParms(WCHAR*, DWORD, PRAS_USER_0); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/setupapi.d0000664000175000017500000025100712776214756023516 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Vladimir Vlasov * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_setupapi.d) */ module core.sys.windows.setupapi; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "setupapi"); private import core.sys.windows.basetyps, core.sys.windows.commctrl, core.sys.windows.prsht, core.sys.windows.w32api, core.sys.windows.winreg, core.sys.windows.windef; private import core.sys.windows.winbase; // for SYSTEMTIME /*static if(_WIN32_WINNT < _WIN32_WINDOWS) { enum UINT _SETUPAPI_VER = _WIN32_WINNT; // SetupAPI version follows Windows NT version } else static if(_WIN32_WINDOWS) { static if(_WIN32_WINDOWS >= 0x0490) { enum UINT _SETUPAPI_VER = 0x0500; // WinME uses same version of SetupAPI as Win2k } else static if(_WIN32_WINDOWS >= 0x0410) { enum UINT _SETUPAPI_VER = 0x0410; // Indicates version of SetupAPI shipped with Win98 } else { enum UINT _SETUPAPI_VER = 0x0400; // Earliest SetupAPI version } } else { enum UINT _SETUPAPI_VER = 0x0501; } version (WindowsNTonly) { static if (_WIN32_WINNT >= 0x500) { enum UINT USE_SP_DRVINFO_DATA_V1 = 0; } else { enum UINT USE_SP_DRVINFO_DATA_V1 = 1; } } else { enum UINT USE_SP_DRVINFO_DATA_V1 = 1; }*/ /+ enum UINT _SETUPAPI_VER = 0x0400; // Earliest SetupAPI version enum UINT USE_SP_DRVINFO_DATA_V1 = 1; +/ enum UINT _SETUPAPI_VER = _WIN32_WINNT; enum bool USE_SP_DRVINFO_DATA_V1 = _WIN32_WINNT < 0x500; enum : uint { LINE_LEN = 256, MAX_INF_STRING_LENGTH = 4096, MAX_TITLE_LEN = 60, MAX_INSTRUCTION_LEN = 256, MAX_LABEL_LEN = 30, MAX_SERVICE_NAME_LEN = 256, MAX_SUBTITLE_LEN = 256, SP_MAX_MACHINENAME_LENGTH = MAX_PATH + 3 } enum : DWORD { COPYFLG_WARN_IF_SKIP = 0x00000001, COPYFLG_NOSKIP = 0x00000002, COPYFLG_NOVERSIONCHECK = 0x00000004, COPYFLG_FORCE_FILE_IN_USE = 0x00000008, COPYFLG_NO_OVERWRITE = 0x00000010, COPYFLG_NO_VERSION_DIALOG = 0x00000020, COPYFLG_OVERWRITE_OLDER_ONLY = 0x00000040, COPYFLG_REPLACEONLY = 0x00000400, COPYFLG_NODECOMP = 0x00000800, COPYFLG_REPLACE_BOOT_FILE = 0x00001000, COPYFLG_NOPRUNE = 0x00002000 } enum : DWORD { DELFLG_IN_USE = 0x00000001, DELFLG_IN_USE1 = 0x00010000 } enum : DWORD { DI_REMOVEDEVICE_GLOBAL = 0x00000001, DI_REMOVEDEVICE_CONFIGSPECIFIC = 0x00000002, DI_UNREMOVEDEVICE_CONFIGSPECIFIC = 0x00000002, DI_SHOWOEM = 0x00000001, DI_SHOWCOMPAT = 0x00000002, DI_SHOWCLASS = 0x00000004, DI_SHOWALL = 0x00000007, DI_NOVCP = 0x00000008, DI_DIDCOMPAT = 0x00000010, DI_DIDCLASS = 0x00000020, DI_AUTOASSIGNRES = 0x00000040, DI_NEEDRESTART = 0x00000080, DI_NEEDREBOOT = 0x00000100, DI_NOBROWSE = 0x00000200, DI_MULTMFGS = 0x00000400, DI_DISABLED = 0x00000800, DI_GENERALPAGE_ADDED = 0x00001000, DI_RESOURCEPAGE_ADDED = 0x00002000, DI_PROPERTIES_CHANGE = 0x00004000, DI_INF_IS_SORTED = 0x00008000, DI_ENUMSINGLEINF = 0x00010000, DI_DONOTCALLCONFIGMG = 0x00020000, DI_INSTALLDISABLED = 0x00040000, DI_COMPAT_FROM_CLASS = 0x00080000, DI_CLASSINSTALLPARAMS = 0x00100000, DI_NODI_DEFAULTACTION = 0x00200000, DI_QUIETINSTALL = 0x00800000, DI_NOFILECOPY = 0x01000000, DI_FORCECOPY = 0x02000000, DI_DRIVERPAGE_ADDED = 0x04000000, DI_USECI_SELECTSTRINGS = 0x08000000, DI_OVERRIDE_INFFLAGS = 0x10000000, DI_PROPS_NOCHANGEUSAGE = 0x20000000, DI_NOSELECTICONS = 0x40000000, DI_NOWRITE_IDS = 0x80000000, DI_FLAGSEX_USEOLDINFSEARCH = 0x00000001, DI_FLAGSEX_AUTOSELECTRANK0 = 0x00000002, DI_FLAGSEX_CI_FAILED = 0x00000004, DI_FLAGSEX_DIDINFOLIST = 0x00000010, DI_FLAGSEX_DIDCOMPATINFO = 0x00000020, DI_FLAGSEX_FILTERCLASSES = 0x00000040, DI_FLAGSEX_SETFAILEDINSTALL = 0x00000080, DI_FLAGSEX_DEVICECHANGE = 0x00000100, DI_FLAGSEX_ALWAYSWRITEIDS = 0x00000200, DI_FLAGSEX_PROPCHANGE_PENDING = 0x00000400, DI_FLAGSEX_ALLOWEXCLUDEDDRVS = 0x00000800, DI_FLAGSEX_NOUIONQUERYREMOVE = 0x00001000, DI_FLAGSEX_USECLASSFORCOMPAT = 0x00002000, DI_FLAGSEX_OLDINF_IN_CLASSLIST = 0x00004000, DI_FLAGSEX_NO_DRVREG_MODIFY = 0x00008000, DI_FLAGSEX_IN_SYSTEM_SETUP = 0x00010000, DI_FLAGSEX_INET_DRIVER = 0x00020000, DI_FLAGSEX_APPENDDRIVERLIST = 0x00040000, DI_FLAGSEX_PREINSTALLBACKUP = 0x00080000, DI_FLAGSEX_BACKUPONREPLACE = 0x00100000, DI_FLAGSEX_DRIVERLIST_FROM_URL = 0x00200000, DI_FLAGSEX_RESERVED1 = 0x00400000, DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS = 0x00800000, DI_FLAGSEX_POWERPAGE_ADDED = 0x01000000 } enum : DWORD { DIBCI_NOINSTALLCLASS = 0x00000001, DIBCI_NODISPLAYCLASS = 0x00000002 } enum : DWORD { DICD_GENERATE_ID = 0x00000001, DICD_INHERIT_CLASSDRVS = 0x00000002 } enum : DWORD { DICS_ENABLE = 1, DICS_DISABLE, DICS_PROPCHANGE, DICS_START, DICS_STOP // = 5 } enum : DWORD { DICS_FLAG_GLOBAL = 1, DICS_FLAG_CONFIGSPECIFIC = 2, DICS_FLAG_CONFIGGENERAL = 4 } alias UINT DI_FUNCTION; enum : DI_FUNCTION { DIF_SELECTDEVICE = 1, DIF_INSTALLDEVICE, DIF_ASSIGNRESOURCES, DIF_PROPERTIES, DIF_REMOVE, DIF_FIRSTTIMESETUP, DIF_FOUNDDEVICE, DIF_SELECTCLASSDRIVERS, DIF_VALIDATECLASSDRIVERS, DIF_INSTALLCLASSDRIVERS, DIF_CALCDISKSPACE, DIF_DESTROYPRIVATEDATA, DIF_VALIDATEDRIVER, DIF_MOVEDEVICE, DIF_DETECT, DIF_INSTALLWIZARD, DIF_DESTROYWIZARDDATA, DIF_PROPERTYCHANGE, DIF_ENABLECLASS, DIF_DETECTVERIFY, DIF_INSTALLDEVICEFILES, DIF_UNREMOVE, DIF_SELECTBESTCOMPATDRV, DIF_ALLOW_INSTALL, DIF_REGISTERDEVICE, DIF_NEWDEVICEWIZARD_PRESELECT, DIF_NEWDEVICEWIZARD_SELECT, DIF_NEWDEVICEWIZARD_PREANALYZE, DIF_NEWDEVICEWIZARD_POSTANALYZE, DIF_NEWDEVICEWIZARD_FINISHINSTALL, DIF_UNUSED1, DIF_INSTALLINTERFACES, DIF_DETECTCANCEL, DIF_REGISTER_COINSTALLERS, DIF_ADDPROPERTYPAGE_ADVANCED, DIF_ADDPROPERTYPAGE_BASIC, DIF_RESERVED1, DIF_TROUBLESHOOTER, DIF_POWERMESSAGEWAKE // = 39 } enum : DWORD { DIGCF_DEFAULT = 0x00000001, DIGCF_PRESENT = 0x00000002, DIGCF_ALLCLASSES = 0x00000004, DIGCF_PROFILE = 0x00000008, DIGCF_DEVICEINTERFACE = 0x00000010 } deprecated enum : DWORD { DIGCF_INTERFACEDEVICE = DIGCF_DEVICEINTERFACE } enum : DWORD { DIGCDP_FLAG_BASIC = 0x00000001, DIGCDP_FLAG_ADVANCED = 0x00000002 } enum : DWORD { DIOCR_INSTALLER = 0x00000001, DIOCR_INTERFACE = 0x00000002 } enum : DWORD { DIODI_NO_ADD = 0x00000001 } enum : DWORD { DIOD_INHERIT_CLASSDRVS = 0x00000002, DIOD_CANCEL_REMOVE = 0x00000004 } enum : DWORD { DIREG_DEV = 0x00000001, DIREG_DRV = 0x00000002, DIREG_BOTH = 0x00000004 } enum : int { DIRID_ABSOLUTE = -1, DIRID_NULL = 0, DIRID_SRCPATH = 1, DIRID_WINDOWS = 10, DIRID_SYSTEM = 11, DIRID_DRIVERS = 12, DIRID_IOSUBSYS = DIRID_DRIVERS, DIRID_INF = 17, DIRID_HELP = 18, DIRID_FONTS = 20, DIRID_VIEWERS = 21, DIRID_COLOR = 23, DIRID_APPS = 24, DIRID_SHARED = 25, DIRID_BOOT = 30, DIRID_SYSTEM16 = 50, DIRID_SPOOL = 51, DIRID_SPOOLDRIVERS = 52, DIRID_USERPROFILE = 53, DIRID_LOADER = 54, DIRID_PRINTPROCESSOR = 55, DIRID_DEFAULT = DIRID_SYSTEM } enum : int { DIRID_COMMON_STARTMENU = 16406, DIRID_COMMON_PROGRAMS = 16407, DIRID_COMMON_STARTUP = 16408, DIRID_COMMON_DESKTOPDIRECTORY = 16409, DIRID_COMMON_FAVORITES = 16415, DIRID_COMMON_APPDATA = 16419, DIRID_PROGRAM_FILES = 16422, DIRID_SYSTEM_X86 = 16425, DIRID_PROGRAM_FILES_X86 = 16426, DIRID_PROGRAM_FILES_COMMON = 16427, DIRID_PROGRAM_FILES_COMMONX86 = 16428, DIRID_COMMON_TEMPLATES = 16429, DIRID_COMMON_DOCUMENTS = 16430, DIRID_USER = 0x8000, DIRID_ABSOLUTE_16BIT = 0xffff } enum : DWORD { DMI_MASK = 0x00000001, DMI_BKCOLOR = 0x00000002, DMI_USERECT = 0x00000004 } enum : DWORD { DNF_DUPDESC = 0x00000001, DNF_OLDDRIVER = 0x00000002, DNF_EXCLUDEFROMLIST = 0x00000004, DNF_NODRIVER = 0x00000008, DNF_LEGACYINF = 0x00000010, DNF_CLASS_DRIVER = 0x00000020, DNF_COMPATIBLE_DRIVER = 0x00000040, DNF_INET_DRIVER = 0x00000080, DNF_UNUSED1 = 0x00000100, DNF_INDEXED_DRIVER = 0x00000200, DNF_OLD_INET_DRIVER = 0x00000400, DNF_BAD_DRIVER = 0x00000800, DNF_DUPPROVIDER = 0x00001000 } enum : UINT { DPROMPT_SUCCESS, DPROMPT_CANCEL, DPROMPT_SKIPFILE, DPROMPT_BUFFERTOOSMALL, DPROMPT_OUTOFMEMORY // = 4 } enum : DWORD { DRIVER_HARDWAREID_RANK = 0x00000FFF, DRIVER_COMPATID_RANK = 0x00003FFF, DRIVER_UNTRUSTED_RANK = 0x00008000, DRIVER_UNTRUSTED_HARDWAREID_RANK = 0x00008FFF, DRIVER_UNTRUSTED_COMPATID_RANK = 0x0000BFFF, DRIVER_W9X_SUSPECT_RANK = 0x0000C000, DRIVER_W9X_SUSPECT_HARDWAREID_RANK = 0x0000CFFF, DRIVER_W9X_SUSPECT_COMPATID_RANK = 0x0000FFFF } enum : DWORD { DYNAWIZ_FLAG_PAGESADDED = 0x00000001, DYNAWIZ_FLAG_INSTALLDET_NEXT = 0x00000002, DYNAWIZ_FLAG_INSTALLDET_PREV = 0x00000004, DYNAWIZ_FLAG_ANALYZE_HANDLECONFLICT = 0x00000008 } enum : WORD { ENABLECLASS_QUERY, ENABLECLASS_SUCCESS, ENABLECLASS_FAILURE // = 2 } enum : DWORD { ERROR_EXPECTED_SECTION_NAME = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0, ERROR_BAD_SECTION_NAME_LINE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 1, ERROR_SECTION_NAME_TOO_LONG = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 2, ERROR_GENERAL_SYNTAX = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 3, ERROR_WRONG_INF_STYLE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x100, ERROR_NOT_INSTALLED = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x1000, ERROR_SECTION_NOT_FOUND = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x101, ERROR_LINE_NOT_FOUND = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x102, ERROR_NO_BACKUP = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x103, ERROR_NO_ASSOCIATED_CLASS = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x200, ERROR_CLASS_MISMATCH = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x201, ERROR_DUPLICATE_FOUND = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x202, ERROR_NO_DRIVER_SELECTED = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x203, ERROR_KEY_DOES_NOT_EXIST = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x204, ERROR_INVALID_DEVINST_NAME = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x205, ERROR_INVALID_CLASS = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x206, ERROR_DEVINST_ALREADY_EXISTS = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x207, ERROR_DEVINFO_NOT_REGISTERED = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x208, ERROR_INVALID_REG_PROPERTY = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x209, ERROR_NO_INF = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20A, ERROR_NO_SUCH_DEVINST = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20B, ERROR_CANT_LOAD_CLASS_ICON = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20C, ERROR_INVALID_CLASS_INSTALLER = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20D, ERROR_DI_DO_DEFAULT = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20E, ERROR_DI_NOFILECOPY = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20F, ERROR_INVALID_HWPROFILE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x210, ERROR_NO_DEVICE_SELECTED = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x211, ERROR_DEVINFO_LIST_LOCKED = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x212, ERROR_DEVINFO_DATA_LOCKED = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x213, ERROR_DI_BAD_PATH = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x214, ERROR_NO_CLASSINSTALL_PARAMS = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x215, ERROR_FILEQUEUE_LOCKED = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x216, ERROR_BAD_SERVICE_INSTALLSECT = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x217, ERROR_NO_CLASS_DRIVER_LIST = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x218, ERROR_NO_ASSOCIATED_SERVICE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x219, ERROR_NO_DEFAULT_DEVICE_INTERFACE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x21A, ERROR_DEVICE_INTERFACE_ACTIVE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x21B, ERROR_DEVICE_INTERFACE_REMOVED = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x21C, ERROR_BAD_INTERFACE_INSTALLSECT = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x21D, ERROR_NO_SUCH_INTERFACE_CLASS = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x21E, ERROR_INVALID_REFERENCE_STRING = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x21F, ERROR_INVALID_MACHINENAME = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x220, ERROR_REMOTE_COMM_FAILURE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x221, ERROR_MACHINE_UNAVAILABLE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x222, ERROR_NO_CONFIGMGR_SERVICES = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x223, ERROR_INVALID_PROPPAGE_PROVIDER = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x224, ERROR_NO_SUCH_DEVICE_INTERFACE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x225, ERROR_DI_POSTPROCESSING_REQUIRED = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x226, ERROR_INVALID_COINSTALLER = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x227, ERROR_NO_COMPAT_DRIVERS = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x228, ERROR_NO_DEVICE_ICON = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x229, ERROR_INVALID_INF_LOGCONFIG = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x22A, ERROR_DI_DONT_INSTALL = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x22B, ERROR_INVALID_FILTER_DRIVER = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x22C, ERROR_NON_WINDOWS_NT_DRIVER = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x22D, ERROR_NON_WINDOWS_DRIVER = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x22E, ERROR_NO_CATALOG_FOR_OEM_INF = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x22F, ERROR_DEVINSTALL_QUEUE_NONNATIVE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x230, ERROR_NOT_DISABLEABLE = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x231, ERROR_CANT_REMOVE_DEVINST = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x232 } deprecated enum : DWORD { ERROR_NO_DEFAULT_INTERFACE_DEVICE = ERROR_NO_DEFAULT_DEVICE_INTERFACE, ERROR_INTERFACE_DEVICE_ACTIVE = ERROR_DEVICE_INTERFACE_ACTIVE, ERROR_INTERFACE_DEVICE_REMOVED = ERROR_DEVICE_INTERFACE_REMOVED, ERROR_NO_SUCH_INTERFACE_DEVICE = ERROR_NO_SUCH_DEVICE_INTERFACE, } enum : UINT { FILEOP_COPY, FILEOP_RENAME, FILEOP_DELETE, FILEOP_BACKUP, FILEOP_NEWPATH, // = 4 FILEOP_ABORT = 0, FILEOP_DOIT, FILEOP_SKIP, // = 2 FILEOP_RETRY = FILEOP_DOIT } enum : UINT { FILE_COMPRESSION_NONE, FILE_COMPRESSION_WINLZA, FILE_COMPRESSION_MSZIP, FILE_COMPRESSION_NTCAB // = 3 } enum : DWORD { FLG_ADDREG_TYPE_SZ = 0x00000000, FLG_ADDREG_BINVALUETYPE = 0x00000001, FLG_ADDREG_NOCLOBBER = 0x00000002, FLG_ADDREG_DELVAL = 0x00000004, FLG_ADDREG_APPEND = 0x00000008, FLG_ADDREG_KEYONLY = 0x00000010, FLG_ADDREG_OVERWRITEONLY = 0x00000020, FLG_ADDREG_TYPE_MULTI_SZ = 0x00010000, FLG_ADDREG_TYPE_EXPAND_SZ = 0x00020000, FLG_ADDREG_TYPE_BINARY = 0x00000000 | FLG_ADDREG_BINVALUETYPE, FLG_ADDREG_TYPE_DWORD = 0x00010000 | FLG_ADDREG_BINVALUETYPE, FLG_ADDREG_TYPE_NONE = 0x00020000 | FLG_ADDREG_BINVALUETYPE, FLG_ADDREG_TYPE_MASK = 0xFFFF0000 | FLG_ADDREG_BINVALUETYPE } static if(_SETUPAPI_VER >= 0x0501) { enum : DWORD { FLG_ADDREG_64BITKEY = 0x00001000, FLG_ADDREG_KEYONLY_COMMON = 0x00002000, FLG_ADDREG_32BITKEY = 0x00004000, FLG_ADDREG_DELREG_BIT = 0x00008000 } } enum : DWORD { FLG_DELREG_VALUE = 0x00000000 } static if(_SETUPAPI_VER >= 0x0501) { enum : DWORD { FLG_DELREG_TYPE_MASK = FLG_ADDREG_TYPE_MASK, FLG_DELREG_TYPE_SZ = FLG_ADDREG_TYPE_SZ, FLG_DELREG_TYPE_MULTI_SZ = FLG_ADDREG_TYPE_MULTI_SZ, FLG_DELREG_TYPE_EXPAND_SZ = FLG_ADDREG_TYPE_EXPAND_SZ, FLG_DELREG_TYPE_BINARY = FLG_ADDREG_TYPE_BINARY, FLG_DELREG_TYPE_DWORD = FLG_ADDREG_TYPE_DWORD, FLG_DELREG_TYPE_NONE = FLG_ADDREG_TYPE_NONE, FLG_DELREG_64BITKEY = FLG_ADDREG_64BITKEY, FLG_DELREG_KEYONLY_COMMON = FLG_ADDREG_KEYONLY_COMMON, FLG_DELREG_32BITKEY = FLG_ADDREG_32BITKEY, FLG_DELREG_OPERATION_MASK = 0x000000FE, FLG_DELREG_MULTI_SZ_DELSTRING = 0x00000002 | FLG_DELREG_TYPE_MULTI_SZ | FLG_ADDREG_DELREG_BIT } } enum : DWORD { FLG_BITREG_CLEARBITS = 0x00000000, FLG_BITREG_SETBITS = 0x00000001 } static if(_SETUPAPI_VER >= 0x0501) { enum : DWORD { FLG_BITREG_64BITKEY = 0x00001000, FLG_BITREG_32BITKEY = 0x00004000 } } enum : DWORD { FLG_PROFITEM_CURRENTUSER = 0x00000001, FLG_PROFITEM_DELETE = 0x00000002, FLG_PROFITEM_GROUP = 0x00000004, FLG_PROFITEM_CSIDL = 0x00000008 } enum : DWORD { FLG_REGSVR_DLLREGISTER = 0x00000001, FLG_REGSVR_DLLINSTALL = 0x00000002 } enum { IDD_DYNAWIZ_FIRSTPAGE = 10000, IDD_DYNAWIZ_SELECT_PREVPAGE, IDD_DYNAWIZ_SELECT_NEXTPAGE, IDD_DYNAWIZ_ANALYZE_PREVPAGE, IDD_DYNAWIZ_ANALYZE_NEXTPAGE, // = 1004 IDD_DYNAWIZ_INSTALLDETECTED_PREVPAGE = 10006, IDD_DYNAWIZ_INSTALLDETECTED_NEXTPAGE, IDD_DYNAWIZ_INSTALLDETECTED_NODEVS, IDD_DYNAWIZ_SELECTDEV_PAGE, IDD_DYNAWIZ_ANALYZEDEV_PAGE, IDD_DYNAWIZ_INSTALLDETECTEDDEVS_PAGE, IDD_DYNAWIZ_SELECTCLASS_PAGE, // = 10012 MIN_IDD_DYNAWIZ_RESOURCE_ID = 10000, MAX_IDD_DYNAWIZ_RESOURCE_ID = 11000 } enum : DWORD { IDF_NOBROWSE = 0x00000001, IDF_NOSKIP = 0x00000002, IDF_NODETAILS = 0x00000004, IDF_NOCOMPRESSED = 0x00000008, IDF_CHECKFIRST = 0x00000100, IDF_NOBEEP = 0x00000200, IDF_NOFOREGROUND = 0x00000400, IDF_WARNIFSKIP = 0x00000800 } static if(_SETUPAPI_VER >= 0x0501) { enum : DWORD { IDF_NOREMOVABLEMEDIAPROMPT = 0x00001000, IDF_USEDISKNAMEASPROMPT = 0x00002000, IDF_OEMDISK = 0x80000000 } } enum { IDI_RESOURCEFIRST = 159, IDI_RESOURCE = 159, IDI_RESOURCELAST = 161, IDI_RESOURCEOVERLAYFIRST = 161, IDI_RESOURCEOVERLAYLAST = 161, IDI_CONFLICT = 161, IDI_PROBLEM_OVL = 500, IDI_DISABLED_OVL = 501, IDI_FORCED_OVL = 502, IDI_CLASSICON_OVERLAYFIRST = 500, IDI_CLASSICON_OVERLAYLAST = 502 } enum : DWORD { INF_STYLE_NONE = 0x00000000, INF_STYLE_OLDNT = 0x00000001, INF_STYLE_WIN4 = 0x00000002, INF_STYLE_CACHE_ENABLE = 0x00000010, INF_STYLE_CACHE_DISABLE = 0x00000020 } enum : DWORD { INFINFO_INF_SPEC_IS_HINF = 1, INFINFO_INF_NAME_IS_ABSOLUTE, INFINFO_DEFAULT_SEARCH, INFINFO_REVERSE_DEFAULT_SEARCH, INFINFO_INF_PATH_LIST_SEARCH // = 5 } alias DWORD LogSeverity; enum : LogSeverity { LogSevInformation, LogSevWarning, LogSevError, LogSevFatalError, LogSevMaximum // = 4 } enum MAX_INSTALLWIZARD_DYNAPAGES = 20; enum : DWORD { NDW_INSTALLFLAG_DIDFACTDEFS = 0x00000001, NDW_INSTALLFLAG_HARDWAREALLREADYIN = 0x00000002, NDW_INSTALLFLAG_NEEDSHUTDOWN = 0x00000200, NDW_INSTALLFLAG_EXPRESSINTRO = 0x00000400, NDW_INSTALLFLAG_SKIPISDEVINSTALLED = 0x00000800, NDW_INSTALLFLAG_NODETECTEDDEVS = 0x00001000, NDW_INSTALLFLAG_INSTALLSPECIFIC = 0x00002000, NDW_INSTALLFLAG_SKIPCLASSLIST = 0x00004000, NDW_INSTALLFLAG_CI_PICKED_OEM = 0x00008000, NDW_INSTALLFLAG_PCMCIAMODE = 0x00010000, NDW_INSTALLFLAG_PCMCIADEVICE = 0x00020000, NDW_INSTALLFLAG_USERCANCEL = 0x00040000, NDW_INSTALLFLAG_KNOWNCLASS = 0x00080000, NDW_INSTALLFLAG_NEEDRESTART = 0x00000080, NDW_INSTALLFLAG_NEEDREBOOT = 0x00000100 } enum : DWORD { SETDIRID_NOT_FULL_PATH = 0x00000001 } enum : DWORD { SP_COPY_DELETESOURCE = 0x0000001, SP_COPY_REPLACEONLY = 0x0000002, SP_COPY_NEWER = 0x0000004, SP_COPY_NEWER_OR_SAME = 0x0000004, SP_COPY_NOOVERWRITE = 0x0000008, SP_COPY_NODECOMP = 0x0000010, SP_COPY_LANGUAGEAWARE = 0x0000020, SP_COPY_SOURCE_ABSOLUTE = 0x0000040, SP_COPY_SOURCEPATH_ABSOLUTE = 0x0000080, SP_COPY_IN_USE_NEEDS_REBOOT = 0x0000100, SP_COPY_FORCE_IN_USE = 0x0000200, SP_COPY_NOSKIP = 0x0000400, SP_FLAG_CABINETCONTINUATION = 0x0000800, SP_COPY_FORCE_NOOVERWRITE = 0x0001000, SP_COPY_FORCE_NEWER = 0x0002000, SP_COPY_WARNIFSKIP = 0x0004000, SP_COPY_NOBROWSE = 0x0008000, SP_COPY_NEWER_ONLY = 0x0010000, SP_COPY_SOURCE_SIS_MASTER = 0x0020000, SP_COPY_OEMINF_CATALOG_ONLY = 0x0040000, SP_COPY_REPLACE_BOOT_FILE = 0x0080000, SP_COPY_NOPRUNE = 0x0100000 } static if(_SETUPAPI_VER >= 0x0501) { enum : DWORD { SP_COPY_OEM_F6_INF = 0x0200000 } } enum : DWORD { SPCRP_SECURITY = 23, SPCRP_SECURITY_SDS, SPCRP_DEVTYPE, SPCRP_EXCLUSIVE, SPCRP_CHARACTERISTICS, SPCRP_MAXIMUM_PROPERTY // = 28 } enum : DWORD { SPDIT_NODRIVER, SPDIT_CLASSDRIVER, SPDIT_COMPATDRIVER // = 2 } enum : DWORD { SPDRP_DEVICEDESC, SPDRP_HARDWAREID, SPDRP_COMPATIBLEIDS, SPDRP_UNUSED0, SPDRP_SERVICE, SPDRP_UNUSED1, SPDRP_UNUSED2, SPDRP_CLASS, SPDRP_CLASSGUID, SPDRP_DRIVER, SPDRP_CONFIGFLAGS, SPDRP_MFG, SPDRP_FRIENDLYNAME, SPDRP_LOCATION_INFORMATION, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, SPDRP_CAPABILITIES, SPDRP_UI_NUMBER, SPDRP_UPPERFILTERS, SPDRP_LOWERFILTERS, SPDRP_BUSTYPEGUID, SPDRP_LEGACYBUSTYPE, SPDRP_BUSNUMBER, SPDRP_ENUMERATOR_NAME, SPDRP_SECURITY, SPDRP_SECURITY_SDS, SPDRP_DEVTYPE, SPDRP_EXCLUSIVE, SPDRP_CHARACTERISTICS, SPDRP_ADDRESS, // = 28 SPDRP_UI_NUMBER_DESC_FORMAT = 30, SPDRP_MAXIMUM_PROPERTY = 31 } enum : UINT { SPDSL_IGNORE_DISK = 1, SPDSL_DISALLOW_NEGATIVE_ADJUST } enum : UINT { SPFILENOTIFY_STARTQUEUE = 1, SPFILENOTIFY_ENDQUEUE, SPFILENOTIFY_STARTSUBQUEUE, SPFILENOTIFY_ENDSUBQUEUE, SPFILENOTIFY_STARTDELETE, SPFILENOTIFY_ENDDELETE, SPFILENOTIFY_DELETEERROR, SPFILENOTIFY_STARTRENAME, SPFILENOTIFY_ENDRENAME, SPFILENOTIFY_RENAMEERROR, SPFILENOTIFY_STARTCOPY, SPFILENOTIFY_ENDCOPY, SPFILENOTIFY_COPYERROR, SPFILENOTIFY_NEEDMEDIA, SPFILENOTIFY_QUEUESCAN, SPFILENOTIFY_CABINETINFO, SPFILENOTIFY_FILEINCABINET, SPFILENOTIFY_NEEDNEWCABINET, SPFILENOTIFY_FILEEXTRACTED, SPFILENOTIFY_FILEOPDELAYED, SPFILENOTIFY_STARTBACKUP, SPFILENOTIFY_BACKUPERROR, SPFILENOTIFY_ENDBACKUP, SPFILENOTIFY_QUEUESCAN_EX, SPFILENOTIFY_STARTREGISTRATION, // = 25 SPFILENOTIFY_ENDREGISTRATION = 32, SPFILENOTIFY_LANGMISMATCH = 0x00010000, SPFILENOTIFY_TARGETEXISTS = 0x00020000, SPFILENOTIFY_TARGETNEWER = 0x00040000 } static if(_SETUPAPI_VER >= 0x0501) { enum : UINT { SPFILENOTIFY_QUEUESCAN_SIGNERINFO = 0x00000040 } } enum : DWORD { SPFILELOG_SYSTEMLOG = 0x00000001, SPFILELOG_OEMFILE = 0x00000001, SPFILELOG_FORCENEW = 0x00000002, SPFILELOG_QUERYONLY = 0x00000004 } enum : INT { SPFILEQ_FILE_IN_USE = 0x00000001, SPFILEQ_REBOOT_RECOMMENDED = 0x00000002, SPFILEQ_REBOOT_IN_PROGRESS = 0x00000004 } enum : DWORD { SPINT_ACTIVE = 0x00000001, SPINT_DEFAULT = 0x00000002, SPINT_REMOVED = 0x00000004 } deprecated enum : DWORD { SPID_ACTIVE = SPINT_ACTIVE, SPID_DEFAULT = SPINT_DEFAULT, SPID_REMOVED = SPINT_REMOVED } enum : UINT { SPINST_LOGCONFIG = 0x00000001, SPINST_INIFILES = 0x00000002, SPINST_REGISTRY = 0x00000004, SPINST_INI2REG = 0x00000008, SPINST_FILES = 0x00000010, SPINST_BITREG = 0x00000020, SPINST_REGSVR = 0x00000040, SPINST_UNREGSVR = 0x00000080, SPINST_PROFILEITEMS = 0x00000100, SPINST_SINGLESECTION = 0x00010000, SPINST_LOGCONFIG_IS_FORCED = 0x00020000, SPINST_LOGCONFIGS_ARE_OVERRIDES = 0x00040000 } static if(_SETUPAPI_VER >= 0x0501) { enum : UINT { SPINST_COPYINF = 0x00000200, SPINST_ALL = 0x000003ff, SPINST_REGISTERCALLBACKAWARE = 0x00080000 } } else { enum : UINT { SPINST_ALL = 0x000001ff } } enum : DWORD { SPOST_NONE, SPOST_PATH, SPOST_URL, SPOST_MAX // = 3 } enum : DWORD { SPPSR_SELECT_DEVICE_RESOURCES = 1, SPPSR_ENUM_BASIC_DEVICE_PROPERTIES, SPPSR_ENUM_ADV_DEVICE_PROPERTIES } enum : DWORD { SPQ_SCAN_FILE_PRESENCE = 0x00000001, SPQ_SCAN_FILE_VALIDITY = 0x00000002, SPQ_SCAN_USE_CALLBACK = 0x00000004, SPQ_SCAN_USE_CALLBACKEX = 0x00000008, SPQ_SCAN_INFORM_USER = 0x00000010, SPQ_SCAN_PRUNE_COPY_QUEUE = 0x00000020 } static if(_SETUPAPI_VER >= 0x0501) { enum : DWORD { SPQ_SCAN_USE_CALLBACK_SIGNERINFO = 0x00000040, SPQ_SCAN_PRUNE_DELREN = 0x00000080 } } enum : UINT_PTR { SPQ_DELAYED_COPY = 0x00000001 } enum : DWORD { SPRDI_FIND_DUPS = 0x00000001, } enum : DWORD { SPSVCINST_TAGTOFRONT = 0x00000001, SPSVCINST_ASSOCSERVICE = 0x00000002, SPSVCINST_DELETEEVENTLOGENTRY = 0x00000004, SPSVCINST_NOCLOBBER_DISPLAYNAME = 0x00000008, SPSVCINST_NOCLOBBER_STARTTYPE = 0x00000010, SPSVCINST_NOCLOBBER_ERRORCONTROL = 0x00000020, SPSVCINST_NOCLOBBER_LOADORDERGROUP = 0x00000040, SPSVCINST_NOCLOBBER_DEPENDENCIES = 0x00000080, SPSVCINST_NOCLOBBER_DESCRIPTION = 0x00000100, SPSVCINST_STOPSERVICE = 0x00000200 } static if(_SETUPAPI_VER >= 0x0501) { enum : DWORD { SPSVCINST_CLOBBER_SECURITY = 0x00000400 } } enum : DWORD { SPWPT_SELECTDEVICE = 0x00000001 } enum : DWORD { SPWP_USE_DEVINFO_DATA = 0x00000001 } enum : UINT { SRCINFO_PATH = 1, SRCINFO_TAGFILE, SRCINFO_DESCRIPTION, SRCINFO_FLAGS // = 4 } enum : DWORD { SRCLIST_TEMPORARY = 0x00000001, SRCLIST_NOBROWSE = 0x00000002, SRCLIST_SYSTEM = 0x00000010, SRCLIST_USER = 0x00000020, SRCLIST_SYSIFADMIN = 0x00000040, SRCLIST_SUBDIRS = 0x00000100, SRCLIST_APPEND = 0x00000200, SRCLIST_NOSTRIPPLATFORM = 0x00000400 } alias PVOID HINF; alias PVOID HDSKSPC; mixin DECLARE_HANDLE!("HDEVINFO"); alias PVOID HSPFILEQ; alias PVOID HSPFILELOG; enum SetupFileLogInfo { SetupFileLogSourceFilename, SetupFileLogChecksum, SetupFileLogDiskTagfile, SetupFileLogDiskDescription, SetupFileLogOtherInfo, SetupFileLogMax } align(1): struct INFCONTEXT { PVOID Inf; PVOID CurrentInf; UINT Section; UINT Line; } alias INFCONTEXT* PINFCONTEXT; struct SP_INF_INFORMATION { DWORD InfStyle; DWORD InfCount; BYTE[1] _VersionData; BYTE* VersionData() return { return _VersionData.ptr; } } alias SP_INF_INFORMATION* PSP_INF_INFORMATION; struct SP_ALTPLATFORM_INFO { DWORD cbSize = SP_ALTPLATFORM_INFO.sizeof; DWORD Platform; DWORD MajorVersion; DWORD MinorVersion; WORD ProcessorArchitecture; WORD Reserved; } alias SP_ALTPLATFORM_INFO* PSP_ALTPLATFORM_INFO; struct SP_ORIGINAL_FILE_INFO_A { DWORD cbSize = SP_ORIGINAL_FILE_INFO_A.sizeof; CHAR[MAX_PATH] OriginalInfName; CHAR[MAX_PATH] OriginalCatalogName; } alias SP_ORIGINAL_FILE_INFO_A* PSP_ORIGINAL_FILE_INFO_A; struct SP_ORIGINAL_FILE_INFO_W { DWORD cbSize = SP_ORIGINAL_FILE_INFO_W.sizeof; WCHAR[MAX_PATH] OriginalInfName; WCHAR[MAX_PATH] OriginalCatalogName; } alias SP_ORIGINAL_FILE_INFO_W* PSP_ORIGINAL_FILE_INFO_W; struct FILEPATHS_A { PCSTR Target; PCSTR Source; UINT Win32Error; DWORD Flags; } alias FILEPATHS_A* PFILEPATHS_A; struct FILEPATHS_W { PCWSTR Target; PCWSTR Source; UINT Win32Error; DWORD Flags; } alias FILEPATHS_W* PFILEPATHS_W; struct SOURCE_MEDIA_A { PCSTR Reserved; PCSTR Tagfile; PCSTR Description; PCSTR SourcePath; PCSTR SourceFile; DWORD Flags; } alias SOURCE_MEDIA_A* PSOURCE_MEDIA_A; struct SOURCE_MEDIA_W { PCWSTR Reserved; PCWSTR Tagfile; PCWSTR Description; PCWSTR SourcePath; PCWSTR SourceFile; DWORD Flags; } alias SOURCE_MEDIA_W* PSOURCE_MEDIA_W; struct CABINET_INFO_A { PCSTR CabinetPath; PCSTR CabinetFile; PCSTR DiskName; USHORT SetId; USHORT CabinetNumber; } alias CABINET_INFO_A* PCABINET_INFO_A; struct CABINET_INFO_W { PCWSTR CabinetPath; PCWSTR CabinetFile; PCWSTR DiskName; USHORT SetId; USHORT CabinetNumber; } alias CABINET_INFO_W* PCABINET_INFO_W; struct FILE_IN_CABINET_INFO_A { PCSTR NameInCabinet; DWORD FileSize; DWORD Win32Error; WORD DosDate; WORD DosTime; WORD DosAttribs; CHAR[MAX_PATH] FullTargetName; } alias FILE_IN_CABINET_INFO_A* PFILE_IN_CABINET_INFO_A; struct FILE_IN_CABINET_INFO_W { PCWSTR NameInCabinet; DWORD FileSize; DWORD Win32Error; WORD DosDate; WORD DosTime; WORD DosAttribs; WCHAR[MAX_PATH] FullTargetName; } alias FILE_IN_CABINET_INFO_W* PFILE_IN_CABINET_INFO_W; struct SP_FILE_COPY_PARAMS_A { DWORD cbSize = SP_FILE_COPY_PARAMS_A.sizeof; HSPFILEQ QueueHandle; PCSTR SourceRootPath; PCSTR SourcePath; PCSTR SourceFilename; PCSTR SourceDescription; PCSTR SourceTagfile; PCSTR TargetDirectory; PCSTR TargetFilename; DWORD CopyStyle; HINF LayoutInf; PCSTR SecurityDescriptor; } alias SP_FILE_COPY_PARAMS_A* PSP_FILE_COPY_PARAMS_A; struct SP_FILE_COPY_PARAMS_W { DWORD cbSize = SP_FILE_COPY_PARAMS_W.sizeof; HSPFILEQ QueueHandle; PCWSTR SourceRootPath; PCWSTR SourcePath; PCWSTR SourceFilename; PCWSTR SourceDescription; PCWSTR SourceTagfile; PCWSTR TargetDirectory; PCWSTR TargetFilename; DWORD CopyStyle; HINF LayoutInf; PCWSTR SecurityDescriptor; } alias SP_FILE_COPY_PARAMS_W* PSP_FILE_COPY_PARAMS_W; struct SP_DEVINFO_DATA { DWORD cbSize = SP_DEVINFO_DATA.sizeof; GUID ClassGuid; DWORD DevInst; ULONG_PTR Reserved; } alias SP_DEVINFO_DATA* PSP_DEVINFO_DATA; struct SP_DEVICE_INTERFACE_DATA { DWORD cbSize = SP_DEVICE_INTERFACE_DATA.sizeof; GUID InterfaceClassGuid; DWORD Flags; ULONG_PTR Reserved; } alias SP_DEVICE_INTERFACE_DATA* PSP_DEVICE_INTERFACE_DATA; deprecated alias SP_DEVICE_INTERFACE_DATA SP_INTERFACE_DEVICE_DATA; deprecated alias SP_DEVICE_INTERFACE_DATA* PSP_INTERFACE_DEVICE_DATA; struct SP_DEVICE_INTERFACE_DETAIL_DATA_A { DWORD cbSize = SP_DEVICE_INTERFACE_DETAIL_DATA_A.sizeof; CHAR[1] _DevicePath; CHAR* DevicePath() return { return _DevicePath.ptr; } } alias SP_DEVICE_INTERFACE_DETAIL_DATA_A* PSP_DEVICE_INTERFACE_DETAIL_DATA_A; struct SP_DEVICE_INTERFACE_DETAIL_DATA_W { DWORD cbSize = SP_DEVICE_INTERFACE_DETAIL_DATA_W.sizeof; WCHAR[1] _DevicePath; WCHAR* DevicePath() return { return _DevicePath.ptr; } } alias SP_DEVICE_INTERFACE_DETAIL_DATA_W* PSP_DEVICE_INTERFACE_DETAIL_DATA_W; deprecated alias SP_DEVICE_INTERFACE_DETAIL_DATA_A SP_INTERFACE_DEVICE_DETAIL_DATA_A; deprecated alias SP_DEVICE_INTERFACE_DETAIL_DATA_A* PSP_INTERFACE_DEVICE_DETAIL_DATA_A; deprecated alias SP_DEVICE_INTERFACE_DETAIL_DATA_W SP_INTERFACE_DEVICE_DETAIL_DATA_W; deprecated alias SP_DEVICE_INTERFACE_DETAIL_DATA_W* PSP_INTERFACE_DEVICE_DETAIL_DATA_W; struct SP_DEVINFO_LIST_DETAIL_DATA_A { DWORD cbSize = SP_DEVINFO_LIST_DETAIL_DATA_A.sizeof; GUID ClassGuid; HANDLE RemoteMachineHandle; CHAR[SP_MAX_MACHINENAME_LENGTH] RemoteMachineName; } alias SP_DEVINFO_LIST_DETAIL_DATA_A* PSP_DEVINFO_LIST_DETAIL_DATA_A; struct SP_DEVINFO_LIST_DETAIL_DATA_W { DWORD cbSize = SP_DEVINFO_LIST_DETAIL_DATA_W.sizeof; GUID ClassGuid; HANDLE RemoteMachineHandle; WCHAR[SP_MAX_MACHINENAME_LENGTH] RemoteMachineName; } alias SP_DEVINFO_LIST_DETAIL_DATA_W* PSP_DEVINFO_LIST_DETAIL_DATA_W; extern(Windows) alias UINT function(PVOID, UINT, UINT_PTR, UINT_PTR) PSP_FILE_CALLBACK_A; extern(Windows) alias UINT function(PVOID, UINT, UINT_PTR, UINT_PTR) PSP_FILE_CALLBACK_W; struct SP_DEVINSTALL_PARAMS_A { DWORD cbSize = SP_DEVINSTALL_PARAMS_A.sizeof; DWORD Flags; DWORD FlagsEx; HWND hwndParent; PSP_FILE_CALLBACK_A InstallMsgHandler; PVOID InstallMsgHandlerContext; HSPFILEQ FileQueue; ULONG_PTR ClassInstallReserved; DWORD Reserved; CHAR[MAX_PATH] DriverPath; } alias SP_DEVINSTALL_PARAMS_A* PSP_DEVINSTALL_PARAMS_A; struct SP_DEVINSTALL_PARAMS_W { DWORD cbSize = SP_DEVINSTALL_PARAMS_W.sizeof; DWORD Flags; DWORD FlagsEx; HWND hwndParent; PSP_FILE_CALLBACK_W InstallMsgHandler; PVOID InstallMsgHandlerContext; HSPFILEQ FileQueue; ULONG_PTR ClassInstallReserved; DWORD Reserved; WCHAR[MAX_PATH] DriverPath; } alias SP_DEVINSTALL_PARAMS_W* PSP_DEVINSTALL_PARAMS_W; struct SP_CLASSINSTALL_HEADER { DWORD cbSize = SP_CLASSINSTALL_HEADER.sizeof; DI_FUNCTION InstallFunction; } alias SP_CLASSINSTALL_HEADER* PSP_CLASSINSTALL_HEADER; struct SP_ENABLECLASS_PARAMS { SP_CLASSINSTALL_HEADER ClassInstallHeader; GUID ClassGuid; DWORD EnableMessage; } alias SP_ENABLECLASS_PARAMS* PSP_ENABLECLASS_PARAMS; struct SP_MOVEDEV_PARAMS { SP_CLASSINSTALL_HEADER ClassInstallHeader; SP_DEVINFO_DATA SourceDeviceInfoData; } alias SP_MOVEDEV_PARAMS* PSP_MOVEDEV_PARAMS; struct SP_PROPCHANGE_PARAMS { SP_CLASSINSTALL_HEADER ClassInstallHeader; DWORD StateChange; DWORD Scope; DWORD HwProfile; } alias SP_PROPCHANGE_PARAMS* PSP_PROPCHANGE_PARAMS; struct SP_REMOVEDEVICE_PARAMS { SP_CLASSINSTALL_HEADER ClassInstallHeader; DWORD Scope; DWORD HwProfile; } alias SP_REMOVEDEVICE_PARAMS* PSP_REMOVEDEVICE_PARAMS; struct SP_UNREMOVEDEVICE_PARAMS { SP_CLASSINSTALL_HEADER ClassInstallHeader; DWORD Scope; DWORD HwProfile; } alias SP_UNREMOVEDEVICE_PARAMS* PSP_UNREMOVEDEVICE_PARAMS; struct SP_SELECTDEVICE_PARAMS_A { SP_CLASSINSTALL_HEADER ClassInstallHeader; CHAR[MAX_TITLE_LEN] Title; CHAR[MAX_INSTRUCTION_LEN] Instructions; CHAR[MAX_LABEL_LEN] ListLabel; CHAR[MAX_SUBTITLE_LEN] SubTitle; BYTE[2] Reserved; } alias SP_SELECTDEVICE_PARAMS_A* PSP_SELECTDEVICE_PARAMS_A; struct SP_SELECTDEVICE_PARAMS_W { SP_CLASSINSTALL_HEADER ClassInstallHeader; WCHAR[MAX_TITLE_LEN] Title; WCHAR[MAX_INSTRUCTION_LEN] Instructions; WCHAR[MAX_LABEL_LEN] ListLabel; WCHAR[MAX_SUBTITLE_LEN] SubTitle; } alias SP_SELECTDEVICE_PARAMS_W* PSP_SELECTDEVICE_PARAMS_W; extern(Windows) alias BOOL function(PVOID, DWORD) PDETECT_PROGRESS_NOTIFY; struct SP_DETECTDEVICE_PARAMS { SP_CLASSINSTALL_HEADER ClassInstallHeader; PDETECT_PROGRESS_NOTIFY DetectProgressNotify; PVOID ProgressNotifyParam; } alias SP_DETECTDEVICE_PARAMS* PSP_DETECTDEVICE_PARAMS; struct SP_INSTALLWIZARD_DATA { SP_CLASSINSTALL_HEADER ClassInstallHeader; DWORD Flags; HPROPSHEETPAGE[MAX_INSTALLWIZARD_DYNAPAGES] DynamicPages; DWORD NumDynamicPages; DWORD DynamicPageFlags; DWORD PrivateFlags; LPARAM PrivateData; HWND hwndWizardDlg; } alias SP_INSTALLWIZARD_DATA* PSP_INSTALLWIZARD_DATA; struct SP_NEWDEVICEWIZARD_DATA { SP_CLASSINSTALL_HEADER ClassInstallHeader; DWORD Flags; HPROPSHEETPAGE[MAX_INSTALLWIZARD_DYNAPAGES] DynamicPages; DWORD NumDynamicPages; HWND hwndWizardDlg; } alias SP_NEWDEVICEWIZARD_DATA* PSP_NEWDEVICEWIZARD_DATA; alias SP_NEWDEVICEWIZARD_DATA SP_ADDPROPERTYPAGE_DATA; alias SP_NEWDEVICEWIZARD_DATA* PSP_ADDPROPERTYPAGE_DATA; struct SP_TROUBLESHOOTER_PARAMS_A { SP_CLASSINSTALL_HEADER ClassInstallHeader; CHAR[MAX_PATH] ChmFile; CHAR[MAX_PATH] HtmlTroubleShooter; } alias SP_TROUBLESHOOTER_PARAMS_A* PSP_TROUBLESHOOTER_PARAMS_A; struct SP_TROUBLESHOOTER_PARAMS_W { SP_CLASSINSTALL_HEADER ClassInstallHeader; WCHAR[MAX_PATH] ChmFile; WCHAR[MAX_PATH] HtmlTroubleShooter; } alias SP_TROUBLESHOOTER_PARAMS_W* PSP_TROUBLESHOOTER_PARAMS_W; struct SP_POWERMESSAGEWAKE_PARAMS_A { SP_CLASSINSTALL_HEADER ClassInstallHeader; CHAR[LINE_LEN*2] PowerMessageWake; } alias SP_POWERMESSAGEWAKE_PARAMS_A* PSP_POWERMESSAGEWAKE_PARAMS_A; struct SP_POWERMESSAGEWAKE_PARAMS_W { SP_CLASSINSTALL_HEADER ClassInstallHeader; WCHAR[LINE_LEN*2] PowerMessageWake; } alias SP_POWERMESSAGEWAKE_PARAMS_W* PSP_POWERMESSAGEWAKE_PARAMS_W; struct SP_DRVINFO_DATA_V2_A { DWORD cbSize = SP_DRVINFO_DATA_V2_A.sizeof; DWORD DriverType; ULONG_PTR Reserved; CHAR[LINE_LEN] Description; CHAR[LINE_LEN] MfgName; CHAR[LINE_LEN] ProviderName; FILETIME DriverDate; DWORDLONG DriverVersion; } alias SP_DRVINFO_DATA_V2_A* PSP_DRVINFO_DATA_V2_A; struct SP_DRVINFO_DATA_V2_W { DWORD cbSize = SP_DRVINFO_DATA_V2_A.sizeof; DWORD DriverType; ULONG_PTR Reserved; WCHAR[LINE_LEN] Description; WCHAR[LINE_LEN] MfgName; WCHAR[LINE_LEN] ProviderName; FILETIME DriverDate; DWORDLONG DriverVersion; } alias SP_DRVINFO_DATA_V2_W* PSP_DRVINFO_DATA_V2_W; struct SP_DRVINFO_DATA_V1_A { DWORD cbSize = SP_DRVINFO_DATA_V1_A.sizeof; DWORD DriverType; ULONG_PTR Reserved; CHAR[LINE_LEN] Description; CHAR[LINE_LEN] MfgName; CHAR[LINE_LEN] ProviderName; } alias SP_DRVINFO_DATA_V1_A* PSP_DRVINFO_DATA_V1_A; struct SP_DRVINFO_DATA_V1_W { DWORD cbSize = SP_DRVINFO_DATA_V1_W.sizeof; DWORD DriverType; ULONG_PTR Reserved; WCHAR[LINE_LEN] Description; WCHAR[LINE_LEN] MfgName; WCHAR[LINE_LEN] ProviderName; } alias SP_DRVINFO_DATA_V1_W* PSP_DRVINFO_DATA_V1_W; version (Unicode) { alias SP_DRVINFO_DATA_V1_W SP_DRVINFO_DATA_V1; alias SP_DRVINFO_DATA_V2_W SP_DRVINFO_DATA_V2; } else { alias SP_DRVINFO_DATA_V1_A SP_DRVINFO_DATA_V1; alias SP_DRVINFO_DATA_V2_A SP_DRVINFO_DATA_V2; } alias SP_DRVINFO_DATA_V1* PSP_DRVINFO_DATA_V1; alias SP_DRVINFO_DATA_V2* PSP_DRVINFO_DATA_V2; static if(USE_SP_DRVINFO_DATA_V1) { alias SP_DRVINFO_DATA_V1_A SP_DRVINFO_DATA_A; alias SP_DRVINFO_DATA_V1_A* PSP_DRVINFO_DATA_A; alias SP_DRVINFO_DATA_V1_W SP_DRVINFO_DATA_W; alias SP_DRVINFO_DATA_V1_W* PSP_DRVINFO_DATA_W; alias SP_DRVINFO_DATA_V1 SP_DRVINFO_DATA; alias SP_DRVINFO_DATA_V1* PSP_DRVINFO_DATA; } else { alias SP_DRVINFO_DATA_V2_A SP_DRVINFO_DATA_A; alias SP_DRVINFO_DATA_V2_A* PSP_DRVINFO_DATA_A; alias SP_DRVINFO_DATA_V2_W SP_DRVINFO_DATA_W; alias SP_DRVINFO_DATA_V2_W* PSP_DRVINFO_DATA_W; alias SP_DRVINFO_DATA_V2 SP_DRVINFO_DATA; alias SP_DRVINFO_DATA_V2* PSP_DRVINFO_DATA; } extern(Windows) alias DWORD function(HDEVINFO, PSP_DEVINFO_DATA, PSP_DEVINFO_DATA, PVOID) PSP_DETSIG_CMPPROC; struct SP_DRVINFO_DETAIL_DATA_A { DWORD cbSize = SP_DRVINFO_DETAIL_DATA_A.sizeof; FILETIME InfDate; DWORD CompatIDsOffset; DWORD CompatIDsLength; ULONG_PTR Reserved; CHAR[LINE_LEN] SectionName; CHAR[MAX_PATH] InfFileName; CHAR[LINE_LEN] DrvDescription; CHAR[1] _HardwareID; CHAR* HardwareID() return { return _HardwareID.ptr; } } alias SP_DRVINFO_DETAIL_DATA_A* PSP_DRVINFO_DETAIL_DATA_A; struct SP_DRVINFO_DETAIL_DATA_W { DWORD cbSize = SP_DRVINFO_DETAIL_DATA_W.sizeof; FILETIME InfDate; DWORD CompatIDsOffset; DWORD CompatIDsLength; ULONG_PTR Reserved; WCHAR[LINE_LEN] SectionName; WCHAR[MAX_PATH] InfFileName; WCHAR[LINE_LEN] DrvDescription; WCHAR[1] _HardwareID; WCHAR* HardwareID() return { return _HardwareID.ptr; } } alias SP_DRVINFO_DETAIL_DATA_W* PSP_DRVINFO_DETAIL_DATA_W; struct SP_DRVINSTALL_PARAMS { DWORD cbSize = SP_DRVINSTALL_PARAMS.sizeof; DWORD Rank; DWORD Flags; DWORD_PTR PrivateData; DWORD Reserved; } alias SP_DRVINSTALL_PARAMS* PSP_DRVINSTALL_PARAMS; struct COINSTALLER_CONTEXT_DATA { BOOL PostProcessing; DWORD InstallResult; PVOID PrivateData; } alias COINSTALLER_CONTEXT_DATA* PCOINSTALLER_CONTEXT_DATA; struct SP_CLASSIMAGELIST_DATA { DWORD cbSize = SP_CLASSIMAGELIST_DATA.sizeof; HIMAGELIST ImageList; ULONG_PTR Reserved; } alias SP_CLASSIMAGELIST_DATA* PSP_CLASSIMAGELIST_DATA; struct SP_PROPSHEETPAGE_REQUEST { DWORD cbSize = SP_PROPSHEETPAGE_REQUEST.sizeof; DWORD PageRequested; HDEVINFO DeviceInfoSet; PSP_DEVINFO_DATA DeviceInfoData; } alias SP_PROPSHEETPAGE_REQUEST* PSP_PROPSHEETPAGE_REQUEST; struct SP_BACKUP_QUEUE_PARAMS_A { DWORD cbSize = SP_BACKUP_QUEUE_PARAMS_A.sizeof; CHAR[MAX_PATH] FullInfPath; INT FilenameOffset; } alias SP_BACKUP_QUEUE_PARAMS_A* PSP_BACKUP_QUEUE_PARAMS_A; struct SP_BACKUP_QUEUE_PARAMS_W { DWORD cbSize = SP_BACKUP_QUEUE_PARAMS_W.sizeof; WCHAR[MAX_PATH] FullInfPath; INT FilenameOffset; } alias SP_BACKUP_QUEUE_PARAMS_W* PSP_BACKUP_QUEUE_PARAMS_W; version (Unicode) { alias SP_ORIGINAL_FILE_INFO_W SP_ORIGINAL_FILE_INFO; alias SP_ORIGINAL_FILE_INFO_W* PSP_ORIGINAL_FILE_INFO; alias FILEPATHS_W FILEPATHS; alias FILEPATHS_W* PFILEPATHS; alias SOURCE_MEDIA_W SOURCE_MEDIA; alias SOURCE_MEDIA_W* PSOURCE_MEDIA; alias CABINET_INFO_W CABINET_INFO; alias CABINET_INFO_W* PCABINET_INFO; alias FILE_IN_CABINET_INFO_W FILE_IN_CABINET_INFO; alias FILE_IN_CABINET_INFO_W* PFILE_IN_CABINET_INFO; alias SP_FILE_COPY_PARAMS_W SP_FILE_COPY_PARAMS; alias SP_FILE_COPY_PARAMS_W* PSP_FILE_COPY_PARAMS; alias SP_DEVICE_INTERFACE_DETAIL_DATA_W SP_DEVICE_INTERFACE_DETAIL_DATA; alias SP_DEVICE_INTERFACE_DETAIL_DATA_W* PSP_DEVICE_INTERFACE_DETAIL_DATA; deprecated { alias SP_DEVICE_INTERFACE_DETAIL_DATA_W SP_INTERFACE_DEVICE_DETAIL_DATA; alias SP_DEVICE_INTERFACE_DETAIL_DATA_W* PSP_INTERFACE_DEVICE_DETAIL_DATA; } alias SP_DEVINFO_LIST_DETAIL_DATA_W SP_DEVINFO_LIST_DETAIL_DATA; alias SP_DEVINFO_LIST_DETAIL_DATA_W *PSP_DEVINFO_LIST_DETAIL_DATA; alias SP_DEVINSTALL_PARAMS_W SP_DEVINSTALL_PARAMS; alias SP_DEVINSTALL_PARAMS_W* PSP_DEVINSTALL_PARAMS; alias SP_SELECTDEVICE_PARAMS_W SP_SELECTDEVICE_PARAMS; alias SP_SELECTDEVICE_PARAMS_W* PSP_SELECTDEVICE_PARAMS; alias SP_TROUBLESHOOTER_PARAMS_W SP_TROUBLESHOOTER_PARAMS; alias SP_TROUBLESHOOTER_PARAMS_W* PSP_TROUBLESHOOTER_PARAMS; alias SP_POWERMESSAGEWAKE_PARAMS_W SP_POWERMESSAGEWAKE_PARAMS; alias SP_POWERMESSAGEWAKE_PARAMS_W* PSP_POWERMESSAGEWAKE_PARAMS; alias SP_DRVINFO_DETAIL_DATA_W SP_DRVINFO_DETAIL_DATA; alias SP_DRVINFO_DETAIL_DATA_W* PSP_DRVINFO_DETAIL_DATA; alias SP_BACKUP_QUEUE_PARAMS_W SP_BACKUP_QUEUE_PARAMS; alias SP_BACKUP_QUEUE_PARAMS_W* PSP_BACKUP_QUEUE_PARAMS; } else { alias SP_ORIGINAL_FILE_INFO_A SP_ORIGINAL_FILE_INFO; alias SP_ORIGINAL_FILE_INFO_A* PSP_ORIGINAL_FILE_INFO; alias FILEPATHS_A FILEPATHS; alias FILEPATHS_A* PFILEPATHS; alias SOURCE_MEDIA_A SOURCE_MEDIA; alias SOURCE_MEDIA_A* PSOURCE_MEDIA; alias CABINET_INFO_A CABINET_INFO; alias CABINET_INFO_A* PCABINET_INFO; alias FILE_IN_CABINET_INFO_A FILE_IN_CABINET_INFO; alias FILE_IN_CABINET_INFO_A* PFILE_IN_CABINET_INFO; alias SP_FILE_COPY_PARAMS_A SP_FILE_COPY_PARAMS; alias SP_FILE_COPY_PARAMS_A* PSP_FILE_COPY_PARAMS; alias SP_DEVICE_INTERFACE_DETAIL_DATA_A SP_DEVICE_INTERFACE_DETAIL_DATA; alias SP_DEVICE_INTERFACE_DETAIL_DATA_A* PSP_DEVICE_INTERFACE_DETAIL_DATA; deprecated { alias SP_DEVICE_INTERFACE_DETAIL_DATA_A SP_INTERFACE_DEVICE_DETAIL_DATA; alias SP_DEVICE_INTERFACE_DETAIL_DATA_A* PSP_INTERFACE_DEVICE_DETAIL_DATA; } alias SP_DEVINFO_LIST_DETAIL_DATA_A SP_DEVINFO_LIST_DETAIL_DATA; alias SP_DEVINFO_LIST_DETAIL_DATA_A* PSP_DEVINFO_LIST_DETAIL_DATA; alias SP_DEVINSTALL_PARAMS_A SP_DEVINSTALL_PARAMS; alias SP_DEVINSTALL_PARAMS_A* PSP_DEVINSTALL_PARAMS; alias SP_SELECTDEVICE_PARAMS_A SP_SELECTDEVICE_PARAMS; alias SP_SELECTDEVICE_PARAMS_A* PSP_SELECTDEVICE_PARAMS; alias SP_TROUBLESHOOTER_PARAMS_A SP_TROUBLESHOOTER_PARAMS; alias SP_TROUBLESHOOTER_PARAMS_A* PSP_TROUBLESHOOTER_PARAMS; alias SP_POWERMESSAGEWAKE_PARAMS_A SP_POWERMESSAGEWAKE_PARAMS; alias SP_POWERMESSAGEWAKE_PARAMS_A* PSP_POWERMESSAGEWAKE_PARAMS; alias SP_DRVINFO_DETAIL_DATA_A SP_DRVINFO_DETAIL_DATA; alias SP_DRVINFO_DETAIL_DATA_A* PSP_DRVINFO_DETAIL_DATA; alias SP_BACKUP_QUEUE_PARAMS_A SP_BACKUP_QUEUE_PARAMS; alias SP_BACKUP_QUEUE_PARAMS_A* PSP_BACKUP_QUEUE_PARAMS; } extern (Windows) { BOOL SetupAddInstallSectionToDiskSpaceListA(HDSKSPC, HINF, HINF, PCSTR, PVOID, UINT); BOOL SetupAddInstallSectionToDiskSpaceListW(HDSKSPC, HINF, HINF, PCWSTR, PVOID, UINT); BOOL SetupAddSectionToDiskSpaceListA(HDSKSPC, HINF, HINF, PCSTR, UINT, PVOID, UINT); BOOL SetupAddSectionToDiskSpaceListW(HDSKSPC, HINF, HINF, PCWSTR, UINT, PVOID, UINT); BOOL SetupAddToDiskSpaceListA(HDSKSPC, PCSTR, LONGLONG, UINT, PVOID, UINT); BOOL SetupAddToDiskSpaceListW(HDSKSPC, PCWSTR, LONGLONG, UINT, PVOID, UINT); BOOL SetupAddToSourceListA(DWORD, PCSTR); BOOL SetupAddToSourceListW(DWORD, PCWSTR); BOOL SetupQuerySourceListA(DWORD, PCSTR**List, PUINT); BOOL SetupQuerySourceListW(DWORD, PCWSTR**List, PUINT); BOOL SetupFreeSourceListA(PCSTR**List, UINT); BOOL SetupFreeSourceListW(PCWSTR**List, UINT); BOOL SetupAdjustDiskSpaceListA(HDSKSPC, LPCSTR, LONGLONG, PVOID, UINT); BOOL SetupAdjustDiskSpaceListW(HDSKSPC, LPCWSTR, LONGLONG, PVOID, UINT); UINT SetupBackupErrorA(HWND, PCSTR, PCSTR, PCSTR, UINT, DWORD); UINT SetupBackupErrorW(HWND, PCWSTR, PCWSTR, PCWSTR, UINT, DWORD); BOOL SetupCancelTemporary(); BOOL SetupCloseFileQueue(HSPFILEQ); VOID SetupCloseInfFile(HINF); VOID SetupCloseLog(); BOOL SetupCommitFileQueueA(HWND, HSPFILEQ, PSP_FILE_CALLBACK_A, PVOID); BOOL SetupCommitFileQueueW(HWND, HSPFILEQ, PSP_FILE_CALLBACK_W, PVOID); UINT SetupCopyErrorA(HWND, PCSTR, PCSTR, PCSTR, PCSTR, PCSTR, UINT, DWORD, PSTR, DWORD, PDWORD); UINT SetupCopyErrorW(HWND, PCWSTR, PCWSTR, PCWSTR, PCWSTR, PCWSTR, UINT, DWORD, PWSTR, DWORD, PDWORD); BOOL SetupCopyOEMInfA(PCSTR, PCSTR, DWORD, DWORD, PSTR, DWORD, PDWORD, PSTR*); BOOL SetupCopyOEMInfW(PCWSTR, PCWSTR, DWORD, DWORD, PWSTR, DWORD, PDWORD, PWSTR*); HDSKSPC SetupCreateDiskSpaceListA(PVOID, DWORD, UINT); HDSKSPC SetupCreateDiskSpaceListW(PVOID, DWORD, UINT); DWORD SetupDecompressOrCopyFileA(PCSTR, PCSTR, PUINT); DWORD SetupDecompressOrCopyFileW(PCWSTR, PCWSTR, PUINT); UINT SetupDefaultQueueCallbackA(PVOID, UINT, UINT_PTR, UINT_PTR); UINT SetupDefaultQueueCallbackW(PVOID, UINT, UINT_PTR, UINT_PTR); UINT SetupDeleteErrorA(HWND, PCSTR, PCSTR, UINT, DWORD); UINT SetupDeleteErrorW(HWND, PCWSTR, PCWSTR, UINT, DWORD); BOOL SetupDestroyDiskSpaceList(HDSKSPC); BOOL SetupDiAskForOEMDisk(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiBuildClassInfoList(DWORD, LPGUID, DWORD, PDWORD); BOOL SetupDiBuildClassInfoListExA(DWORD, LPGUID, DWORD, PDWORD, PCSTR, PVOID); BOOL SetupDiBuildClassInfoListExW(DWORD, LPGUID, DWORD, PDWORD, PCWSTR, PVOID); BOOL SetupDiBuildDriverInfoList(HDEVINFO, PSP_DEVINFO_DATA, DWORD); BOOL SetupDiCallClassInstaller(DI_FUNCTION, HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiCancelDriverInfoSearch(HDEVINFO); BOOL SetupDiChangeState(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiClassGuidsFromNameA(PCSTR, LPGUID, DWORD, PDWORD); BOOL SetupDiClassGuidsFromNameW(PCWSTR, LPGUID, DWORD, PDWORD); BOOL SetupDiClassGuidsFromNameExA(PCSTR, LPGUID, DWORD, PDWORD, PCSTR, PVOID); BOOL SetupDiClassGuidsFromNameExW(PCWSTR, LPGUID, DWORD, PDWORD, PCWSTR, PVOID); BOOL SetupDiClassNameFromGuidA(const(GUID)*, PSTR, DWORD, PDWORD); BOOL SetupDiClassNameFromGuidW(const(GUID)*, PWSTR, DWORD, PDWORD); BOOL SetupDiClassNameFromGuidExA(const(GUID)*, PSTR, DWORD, PDWORD, PCSTR, PVOID); BOOL SetupDiClassNameFromGuidExW(const(GUID)*, PWSTR, DWORD, PDWORD, PCWSTR, PVOID); BOOL SetupDiCreateDeviceInfoA(HDEVINFO, PCSTR, const(GUID)*, PCSTR, HWND, DWORD, PSP_DEVINFO_DATA); BOOL SetupDiCreateDeviceInfoW(HDEVINFO, PCWSTR, const(GUID)*, PCWSTR, HWND, DWORD, PSP_DEVINFO_DATA); HDEVINFO SetupDiCreateDeviceInfoList(const(GUID)*, HWND); HDEVINFO SetupDiCreateDeviceInfoListExA(const(GUID)*, HWND, PCSTR, PVOID); HDEVINFO SetupDiCreateDeviceInfoListExW(const(GUID)*, HWND, PCWSTR, PVOID); BOOL SetupDiCreateDeviceInterfaceA(HDEVINFO, PSP_DEVINFO_DATA, const(GUID)*, PCSTR, DWORD, PSP_DEVICE_INTERFACE_DATA); BOOL SetupDiCreateDeviceInterfaceW(HDEVINFO, PSP_DEVINFO_DATA, const(GUID)*, PCWSTR, DWORD, PSP_DEVICE_INTERFACE_DATA); HKEY SetupDiCreateDeviceInterfaceRegKeyA(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, REGSAM, HINF, PCSTR); HKEY SetupDiCreateDeviceInterfaceRegKeyW(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, REGSAM, HINF, PCWSTR); HKEY SetupDiCreateDevRegKeyA(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, HINF, PCSTR); HKEY SetupDiCreateDevRegKeyW(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, HINF, PCWSTR); BOOL SetupDiDeleteDeviceInfo(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiDeleteDeviceInterfaceData(HDEVINFO, PSP_DEVICE_INTERFACE_DATA); BOOL SetupDiDeleteDeviceInterfaceRegKey(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD); BOOL SetupDiDeleteDevRegKey(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD); BOOL SetupDiDestroyClassImageList(PSP_CLASSIMAGELIST_DATA); BOOL SetupDiDestroyDeviceInfoList(HDEVINFO); BOOL SetupDiDestroyDriverInfoList(HDEVINFO, PSP_DEVINFO_DATA, DWORD); INT SetupDiDrawMiniIcon(HDC, RECT, INT, DWORD); BOOL SetupDiEnumDeviceInfo(HDEVINFO, DWORD, PSP_DEVINFO_DATA); BOOL SetupDiEnumDeviceInterfaces(HDEVINFO, PSP_DEVINFO_DATA, const(GUID)*, DWORD, PSP_DEVICE_INTERFACE_DATA); BOOL SetupDiEnumDriverInfoA(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, PSP_DRVINFO_DATA_A); BOOL SetupDiEnumDriverInfoW(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, PSP_DRVINFO_DATA_W); BOOL SetupDiGetActualSectionToInstallA(HINF, PCSTR, PSTR, DWORD, PDWORD, PSTR*); BOOL SetupDiGetActualSectionToInstallW(HINF, PCWSTR, PWSTR, DWORD, PDWORD, PWSTR*); BOOL SetupDiGetClassBitmapIndex(const(GUID)*, PINT); BOOL SetupDiGetClassDescriptionA(const(GUID)*, PSTR, DWORD, PDWORD); BOOL SetupDiGetClassDescriptionW(const(GUID)*, PWSTR, DWORD, PDWORD); BOOL SetupDiGetClassDescriptionExA(const(GUID)*, PSTR, DWORD, PDWORD, PCSTR, PVOID); BOOL SetupDiGetClassDescriptionExW(const(GUID)*, PWSTR, DWORD, PDWORD, PCWSTR, PVOID); BOOL SetupDiGetClassDevPropertySheetsA(HDEVINFO, PSP_DEVINFO_DATA, LPPROPSHEETHEADERA, DWORD, PDWORD, DWORD); BOOL SetupDiGetClassDevPropertySheetsW(HDEVINFO, PSP_DEVINFO_DATA, LPPROPSHEETHEADERW, DWORD, PDWORD, DWORD); HDEVINFO SetupDiGetClassDevsA(const(GUID)*, PCSTR, HWND, DWORD); HDEVINFO SetupDiGetClassDevsW(const(GUID)*, PCWSTR, HWND, DWORD); HDEVINFO SetupDiGetClassDevsExA(const(GUID)*, PCSTR, HWND, DWORD, HDEVINFO, PCSTR, PVOID); HDEVINFO SetupDiGetClassDevsExW(const(GUID)*, PCWSTR, HWND, DWORD, HDEVINFO, PCWSTR, PVOID); BOOL SetupDiGetClassImageIndex(PSP_CLASSIMAGELIST_DATA, const(GUID)*, PINT); BOOL SetupDiGetClassImageList(PSP_CLASSIMAGELIST_DATA); BOOL SetupDiGetClassImageListExA(PSP_CLASSIMAGELIST_DATA, PCSTR, PVOID); BOOL SetupDiGetClassImageListExW(PSP_CLASSIMAGELIST_DATA, PCWSTR, PVOID); BOOL SetupDiGetClassInstallParamsA(HDEVINFO, PSP_DEVINFO_DATA, PSP_CLASSINSTALL_HEADER, DWORD, PDWORD); BOOL SetupDiGetClassInstallParamsW(HDEVINFO, PSP_DEVINFO_DATA, PSP_CLASSINSTALL_HEADER, DWORD, PDWORD); BOOL SetupDiGetClassRegistryPropertyA(LPGUID, DWORD, PDWORD, PBYTE, DWORD, PDWORD, PCSTR, PVOID); BOOL SetupDiGetClassRegistryPropertyW(LPGUID, DWORD, PDWORD, PBYTE, DWORD, PDWORD, PCWSTR, PVOID); BOOL SetupDiGetDeviceInfoListClass(HDEVINFO, LPGUID); BOOL SetupDiGetDeviceInfoListDetailA(HDEVINFO, PSP_DEVINFO_LIST_DETAIL_DATA_A); BOOL SetupDiGetDeviceInfoListDetailW(HDEVINFO, PSP_DEVINFO_LIST_DETAIL_DATA_W); BOOL SetupDiGetDeviceInstallParamsA(HDEVINFO, PSP_DEVINFO_DATA, PSP_DEVINSTALL_PARAMS_A); BOOL SetupDiGetDeviceInstallParamsW(HDEVINFO, PSP_DEVINFO_DATA, PSP_DEVINSTALL_PARAMS_W); BOOL SetupDiGetDeviceInstanceIdA(HDEVINFO, PSP_DEVINFO_DATA, PSTR, DWORD, PDWORD); BOOL SetupDiGetDeviceInstanceIdW(HDEVINFO, PSP_DEVINFO_DATA, PWSTR, DWORD, PDWORD); BOOL SetupDiGetDeviceInterfaceAlias(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, const(GUID)*, PSP_DEVICE_INTERFACE_DATA); BOOL SetupDiGetDeviceInterfaceDetailA(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA); BOOL SetupDiGetDeviceInterfaceDetailW(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_W, DWORD, PDWORD, PSP_DEVINFO_DATA); BOOL SetupDiGetDeviceRegistryPropertyA(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD); BOOL SetupDiGetDeviceRegistryPropertyW(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD); BOOL SetupDiGetDriverInfoDetailA(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_A, PSP_DRVINFO_DETAIL_DATA_A, DWORD, PDWORD); BOOL SetupDiGetDriverInfoDetailW(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_W, PSP_DRVINFO_DETAIL_DATA_W, DWORD, PDWORD); BOOL SetupDiGetDriverInstallParamsA(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_A, PSP_DRVINSTALL_PARAMS); BOOL SetupDiGetDriverInstallParamsW(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_W, PSP_DRVINSTALL_PARAMS); BOOL SetupDiGetHwProfileFriendlyNameA(DWORD, PSTR, DWORD, PDWORD); BOOL SetupDiGetHwProfileFriendlyNameExA(DWORD, PSTR, DWORD, PDWORD, PCSTR, PVOID); BOOL SetupDiGetHwProfileFriendlyNameExW(DWORD, PWSTR, DWORD, PDWORD, PCWSTR, PVOID); BOOL SetupDiGetHwProfileFriendlyNameW(DWORD, PWSTR, DWORD, PDWORD); BOOL SetupDiGetHwProfileList(PDWORD, DWORD, PDWORD, PDWORD); BOOL SetupDiGetHwProfileListExA(PDWORD, DWORD, PDWORD, PDWORD, PCSTR, PVOID); BOOL SetupDiGetHwProfileListExW(PDWORD, DWORD, PDWORD, PDWORD, PCWSTR, PVOID); BOOL SetupDiGetINFClassA(PCSTR, LPGUID, PSTR, DWORD, PDWORD); BOOL SetupDiGetINFClassW(PCWSTR, LPGUID, PWSTR, DWORD, PDWORD); BOOL SetupDiGetSelectedDevice(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiGetSelectedDriverA(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_A); BOOL SetupDiGetSelectedDriverW(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_W); HPROPSHEETPAGE SetupDiGetWizardage(HDEVINFO, PSP_DEVINFO_DATA, PSP_INSTALLWIZARD_DATA, DWORD, DWORD); BOOL SetupDiInstallClassA(HWND, PCSTR, DWORD, HSPFILEQ); BOOL SetupDiInstallClassW(HWND, PCWSTR, DWORD, HSPFILEQ); BOOL SetupDiInstallClassExA(HWND, PCSTR, DWORD, HSPFILEQ, const(GUID)*, PVOID, PVOID); BOOL SetupDiInstallClassExW(HWND, PCWSTR, DWORD, HSPFILEQ, const(GUID)*, PVOID, PVOID); BOOL SetupDiInstallDevice(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiInstallDeviceInterfaces(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiInstallDriverFiles(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiLoadClassIcon(const(GUID)*, HICON*, PINT); BOOL SetupDiMoveDuplicateDevice(HDEVINFO, PSP_DEVINFO_DATA); HKEY SetupDiOpenClassRegKey(const(GUID)*, REGSAM); HKEY SetupDiOpenClassRegKeyExA(const(GUID)*, REGSAM, DWORD, PCSTR, PVOID); HKEY SetupDiOpenClassRegKeyExW(const(GUID)*, REGSAM, DWORD, PCWSTR, PVOID); BOOL SetupDiOpenDeviceInfoA(HDEVINFO, PCSTR, HWND, DWORD, PSP_DEVINFO_DATA); BOOL SetupDiOpenDeviceInfoW(HDEVINFO, PCWSTR, HWND, DWORD, PSP_DEVINFO_DATA); BOOL SetupDiOpenDeviceInterfaceA(HDEVINFO, PCSTR, DWORD, PSP_DEVICE_INTERFACE_DATA); BOOL SetupDiOpenDeviceInterfaceW(HDEVINFO, PCWSTR, DWORD, PSP_DEVICE_INTERFACE_DATA); HKEY SetupDiOpenDeviceInterfaceRegKey(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, REGSAM); HKEY SetupDiOpenDevRegKey(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM); BOOL SetupDiRegisterCoDeviceInstallers(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiRegisterDeviceInfo(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PSP_DETSIG_CMPPROC, PVOID, PSP_DEVINFO_DATA); BOOL SetupDiRemoveDevice(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiRemoveDeviceInterface(HDEVINFO, PSP_DEVICE_INTERFACE_DATA); BOOL SetupDiSelectBestCompatDrv(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiSelectDevice(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiSelectOEMDrv(HWND, HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiSetClassInstallParamsA(HDEVINFO, PSP_DEVINFO_DATA, PSP_CLASSINSTALL_HEADER, DWORD); BOOL SetupDiSetClassInstallParamsW(HDEVINFO, PSP_DEVINFO_DATA, PSP_CLASSINSTALL_HEADER, DWORD); BOOL SetupDiSetClassRegistryPropertyA(LPGUID, DWORD, const(BYTE)*, DWORD, PCSTR, PVOID); BOOL SetupDiSetClassRegistryPropertyW(LPGUID, DWORD, const(BYTE)*, DWORD, PCWSTR, PVOID); BOOL SetupDiSetDeviceInstallParamsA(HDEVINFO, PSP_DEVINFO_DATA, PSP_DEVINSTALL_PARAMS_A); BOOL SetupDiSetDeviceInstallParamsW(HDEVINFO, PSP_DEVINFO_DATA, PSP_DEVINSTALL_PARAMS_W); BOOL SetupDiSetDeviceRegistryPropertyA(HDEVINFO, PSP_DEVINFO_DATA, DWORD, const(BYTE)*, DWORD); BOOL SetupDiSetDeviceRegistryPropertyW(HDEVINFO, PSP_DEVINFO_DATA, DWORD, const(BYTE)*, DWORD); BOOL SetupDiSetDriverInstallParamsA(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_A, PSP_DRVINSTALL_PARAMS); BOOL SetupDiSetDriverInstallParamsW(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_W, PSP_DRVINSTALL_PARAMS); BOOL SetupDiSetSelectedDevice(HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupDiSetSelectedDriverA(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_A); BOOL SetupDiSetSelectedDriverW(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_W); BOOL SetupDiUnremoveDevice(HDEVINFO, PSP_DEVINFO_DATA); HDSKSPC SetupDuplicateDiskSpaceListA(HDSKSPC, PVOID, DWORD, UINT); HDSKSPC SetupDuplicateDiskSpaceListW(HDSKSPC, PVOID, DWORD, UINT); BOOL SetupFindFirstLineA(HINF, PCSTR, PCSTR, PINFCONTEXT); BOOL SetupFindFirstLineW(HINF, PCWSTR, PCWSTR, PINFCONTEXT); BOOL SetupFindNextLine(PINFCONTEXT, PINFCONTEXT); BOOL SetupFindNextMatchLineA(PINFCONTEXT, PCSTR, PINFCONTEXT); BOOL SetupFindNextMatchLineW(PINFCONTEXT, PCWSTR, PINFCONTEXT); BOOL SetupFreeA(PCSTR**, UINT); BOOL SetupFreeW(PCWSTR**, UINT); BOOL SetupGetBackupInformationA(HSPFILEQ, PSP_BACKUP_QUEUE_PARAMS_A); BOOL SetupGetBackupInformationW(HSPFILEQ, PSP_BACKUP_QUEUE_PARAMS_W); BOOL SetupGetBinaryField(PINFCONTEXT, DWORD, PBYTE, DWORD, LPDWORD); DWORD SetupGetFieldCount(PINFCONTEXT); DWORD SetupGetFileCompressionInfoA(PCSTR, PSTR*, PDWORD, PDWORD, PUINT); DWORD SetupGetFileCompressionInfoW(PCWSTR, PWSTR*, PDWORD, PDWORD, PUINT); BOOL SetupGetInfFileListA(PCSTR, DWORD, PSTR, DWORD, PDWORD); BOOL SetupGetInfFileListW(PCWSTR, DWORD, PWSTR, DWORD, PDWORD); BOOL SetupGetInfInformationA(LPCVOID, DWORD, PSP_INF_INFORMATION, DWORD, PDWORD); BOOL SetupGetInfInformationW(LPCVOID, DWORD, PSP_INF_INFORMATION, DWORD, PDWORD); BOOL SetupGetIntField(PINFCONTEXT, DWORD, PINT); BOOL SetupGetLineByIndexA(HINF, PCSTR, DWORD, PINFCONTEXT); BOOL SetupGetLineByIndexW(HINF, PCWSTR, DWORD, PINFCONTEXT); LONG SetupGetLineCountA(HINF, PCSTR); LONG SetupGetLineCountW(HINF, PCWSTR); BOOL SetupGetLineTextA(PINFCONTEXT, HINF, PCSTR, PCSTR, PSTR, DWORD, PDWORD); BOOL SetupGetLineTextW(PINFCONTEXT, HINF, PCWSTR, PCWSTR, PWSTR, DWORD, PDWORD); BOOL SetupGetMultiSzFieldA(PINFCONTEXT, DWORD, PSTR, DWORD, LPDWORD); BOOL SetupGetMultiSzFieldW(PINFCONTEXT, DWORD, PWSTR, DWORD, LPDWORD); BOOL SetupGetSourceFileLocationA(HINF, PINFCONTEXT, PCSTR, PUINT, PSTR, DWORD, PDWORD); BOOL SetupGetSourceFileLocationW(HINF, PINFCONTEXT, PCWSTR, PUINT, PWSTR, DWORD, PDWORD); BOOL SetupGetSourceFileSizeA(HINF, PINFCONTEXT, PCSTR, PCSTR, PDWORD, UINT); BOOL SetupGetSourceFileSizeW(HINF, PINFCONTEXT, PCWSTR, PCWSTR, PDWORD, UINT); BOOL SetupGetSourceInfoA(HINF, UINT, UINT, PSTR, DWORD, PDWORD); BOOL SetupGetSourceInfoW(HINF, UINT, UINT, PWSTR, DWORD, PDWORD); BOOL SetupGetStringFieldA(PINFCONTEXT, DWORD, PSTR, DWORD, PDWORD); BOOL SetupGetStringFieldW(PINFCONTEXT, DWORD, PWSTR, DWORD, PDWORD); BOOL SetupGetTargetPathA(HINF, PINFCONTEXT, PCSTR, PSTR, DWORD, PDWORD); BOOL SetupGetTargetPathW(HINF, PINFCONTEXT, PCWSTR, PWSTR, DWORD, PDWORD); PVOID SetupInitDefaultQueueCallback(HWND); PVOID SetupInitDefaultQueueCallbackEx(HWND, HWND, UINT, DWORD, PVOID); HSPFILELOG SetupInitializeFileLogA(PCSTR, DWORD); HSPFILELOG SetupInitializeFileLogW(PCWSTR, DWORD); BOOL SetupInstallFileA(HINF, PINFCONTEXT, PCSTR, PCSTR, PCSTR, DWORD, PSP_FILE_CALLBACK_A, PVOID); BOOL SetupInstallFileW(HINF, PINFCONTEXT, PCWSTR, PCWSTR, PCWSTR, DWORD, PSP_FILE_CALLBACK_W, PVOID); BOOL SetupInstallFileExA(HINF, PINFCONTEXT, PCSTR, PCSTR, PCSTR, DWORD, PSP_FILE_CALLBACK_A, PVOID, PBOOL); BOOL SetupInstallFileExW(HINF, PINFCONTEXT, PCWSTR, PCWSTR, PCWSTR, DWORD, PSP_FILE_CALLBACK_W, PVOID, PBOOL); BOOL SetupInstallFilesFromInfSectionA(HINF, HINF, HSPFILEQ, PCSTR, PCSTR, UINT); BOOL SetupInstallFilesFromInfSectionW(HINF, HINF, HSPFILEQ, PCWSTR, PCWSTR, UINT); BOOL SetupInstallFromInfSectionA(HWND, HINF, PCSTR, UINT, HKEY, PCSTR, UINT, PSP_FILE_CALLBACK_A, PVOID, HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupInstallFromInfSectionW(HWND, HINF, PCWSTR, UINT, HKEY, PCWSTR, UINT, PSP_FILE_CALLBACK_W, PVOID, HDEVINFO, PSP_DEVINFO_DATA); BOOL SetupInstallServicesFromInfSectionA(HINF, PCSTR, DWORD); BOOL SetupInstallServicesFromInfSectionW(HINF, PCWSTR, DWORD); BOOL SetupInstallServicesFromInfSectionExA(HINF, PCSTR, DWORD, HDEVINFO, PSP_DEVINFO_DATA, PVOID, PVOID); BOOL SetupInstallServicesFromInfSectionExW(HINF, PCWSTR, DWORD, HDEVINFO, PSP_DEVINFO_DATA, PVOID, PVOID); BOOL SetupIterateCabinetA(PCSTR, DWORD, PSP_FILE_CALLBACK_A, PVOID); BOOL SetupIterateCabinetW(PCWSTR, DWORD, PSP_FILE_CALLBACK_W, PVOID); BOOL SetupLogErrorA(LPCSTR, LogSeverity); BOOL SetupLogErrorW(LPCWSTR, LogSeverity); BOOL SetupLogFileA(HSPFILELOG, PCSTR, PCSTR, PCSTR, DWORD, PCSTR, PCSTR, PCSTR, DWORD); BOOL SetupLogFileW(HSPFILELOG, PCWSTR, PCWSTR, PCWSTR, DWORD, PCWSTR, PCWSTR, PCWSTR, DWORD); BOOL SetupOpenAppendInfFileA(PCSTR, HINF, PUINT); BOOL SetupOpenAppendInfFileW(PCWSTR, HINF, PUINT); HSPFILEQ SetupOpenFileQueue(); HINF SetupOpenInfFileA(PCSTR, PCSTR, DWORD, PUINT); HINF SetupOpenInfFileW(PCWSTR, PCWSTR, DWORD, PUINT); BOOL SetupOpenLog(BOOL); HINF SetupOpenMasterInf(); UINT SetupPromptForDiskA(HWND, PCSTR, PCSTR, PCSTR, PCSTR, PCSTR, DWORD, PSTR, DWORD, PDWORD); UINT SetupPromptForDiskW(HWND, PCWSTR, PCWSTR, PCWSTR, PCWSTR, PCWSTR, DWORD, PWSTR, DWORD, PDWORD); INT SetupPromptReboot(HSPFILEQ, HWND, BOOL); BOOL SetupQueryA(DWORD, PCSTR**, PUINT); BOOL SetupQueryW(DWORD, PCWSTR**, PUINT); BOOL SetupQueryDrivesInDiskSpaceListA(HDSKSPC, PSTR, DWORD, PDWORD); BOOL SetupQueryDrivesInDiskSpaceListW(HDSKSPC, PWSTR, DWORD, PDWORD); BOOL SetupQueryFileLogA(HSPFILELOG, PCSTR, PCSTR, SetupFileLogInfo, PSTR, DWORD, PDWORD); BOOL SetupQueryFileLogW(HSPFILELOG, PCWSTR, PCWSTR, SetupFileLogInfo, PWSTR, DWORD, PDWORD); BOOL SetupQueryInfFileInformationA(PSP_INF_INFORMATION, UINT, PSTR, DWORD, PDWORD); BOOL SetupQueryInfFileInformationW(PSP_INF_INFORMATION, UINT, PWSTR, DWORD, PDWORD); BOOL SetupQueryInfOriginalFileInformationA(PSP_INF_INFORMATION, UINT, PSP_ALTPLATFORM_INFO, PSP_ORIGINAL_FILE_INFO_A); BOOL SetupQueryInfOriginalFileInformationW(PSP_INF_INFORMATION, UINT, PSP_ALTPLATFORM_INFO, PSP_ORIGINAL_FILE_INFO_W); BOOL SetupQueryInfVersionInformationA(PSP_INF_INFORMATION, UINT, PSTR, PSTR, DWORD, PDWORD); BOOL SetupQueryInfVersionInformationW(PSP_INF_INFORMATION, UINT, PCWSTR, PWSTR, DWORD, PDWORD); BOOL SetupQuerySpaceRequiredOnDriveA(HDSKSPC, PCSTR, LONGLONG*, PVOID, UINT); BOOL SetupQuerySpaceRequiredOnDriveW(HDSKSPC, PCWSTR, LONGLONG*, PVOID, UINT); BOOL SetupQueueCopyA(HSPFILEQ, PCSTR, PCSTR, PCSTR, PCSTR, PCSTR, PCSTR, PCSTR, DWORD); BOOL SetupQueueCopyW(HSPFILEQ, PCWSTR, PCWSTR, PCWSTR, PCWSTR, PCWSTR, PCWSTR, PCWSTR, DWORD); BOOL SetupQueueCopyIndirectA(PSP_FILE_COPY_PARAMS_A); BOOL SetupQueueCopyIndirectW(PSP_FILE_COPY_PARAMS_W); BOOL SetupQueueCopySectionA(HSPFILEQ, PCSTR, HINF, HINF, PCSTR, DWORD); BOOL SetupQueueCopySectionW(HSPFILEQ, PCWSTR, HINF, HINF, PCWSTR, DWORD); BOOL SetupQueueDefaultCopyA(HSPFILEQ, HINF, PCSTR, PCSTR, PCSTR, DWORD); BOOL SetupQueueDefaultCopyW(HSPFILEQ, HINF, PCWSTR, PCWSTR, PCWSTR, DWORD); BOOL SetupQueueDeleteA(HSPFILEQ, PCSTR, PCSTR); BOOL SetupQueueDeleteW(HSPFILEQ, PCWSTR, PCWSTR); BOOL SetupQueueDeleteSectionA(HSPFILEQ, HINF, HINF, PCSTR); BOOL SetupQueueDeleteSectionW(HSPFILEQ, HINF, HINF, PCWSTR); BOOL SetupQueueRenameA(HSPFILEQ, PCSTR, PCSTR, PCSTR, PCSTR); BOOL SetupQueueRenameW(HSPFILEQ, PCWSTR, PCWSTR, PCWSTR, PCWSTR); BOOL SetupQueueRenameSectionA(HSPFILEQ, HINF, HINF, PCSTR); BOOL SetupQueueRenameSectionW(HSPFILEQ, HINF, HINF, PCWSTR); BOOL SetupRemoveFileLogEntryA(HSPFILELOG, PCSTR, PCSTR); BOOL SetupRemoveFileLogEntryW(HSPFILELOG, PCWSTR, PCWSTR); BOOL SetupRemoveFromDiskSpaceListA(HDSKSPC, PCSTR, UINT, PVOID, UINT); BOOL SetupRemoveFromDiskSpaceListW(HDSKSPC, PCWSTR, UINT, PVOID, UINT); BOOL SetupRemoveFromSourceListA(DWORD, PCSTR); BOOL SetupRemoveFromSourceListW(DWORD, PCWSTR); BOOL SetupRemoveInstallSectionFromDiskSpaceListA(HDSKSPC, HINF, HINF, PCSTR, PVOID, UINT); BOOL SetupRemoveInstallSectionFromDiskSpaceListW(HDSKSPC, HINF, HINF, PCWSTR, PVOID, UINT); BOOL SetupRemoveSectionFromDiskSpaceListA(HDSKSPC, HINF, HINF, PCSTR, UINT, PVOID, UINT); BOOL SetupRemoveSectionFromDiskSpaceListW(HDSKSPC, HINF, HINF, PCWSTR, UINT, PVOID, UINT); UINT SetupRenameErrorA(HWND, PCSTR, PCSTR, PCSTR, UINT, DWORD); UINT SetupRenameErrorW(HWND, PCWSTR, PCWSTR, PCWSTR, UINT, DWORD); BOOL SetupScanFileQueueA(HSPFILEQ, DWORD, HWND, PSP_FILE_CALLBACK_A, PVOID, PDWORD); BOOL SetupScanFileQueueW(HSPFILEQ, DWORD, HWND, PSP_FILE_CALLBACK_W, PVOID, PDWORD); BOOL SetupSetDirectoryIdA(HINF, DWORD, PCSTR); BOOL SetupSetDirectoryIdW(HINF, DWORD, PCWSTR); BOOL SetupSetDirectoryIdExA(HINF, DWORD, PCSTR, DWORD, DWORD, PVOID); BOOL SetupSetDirectoryIdExW(HINF, DWORD, PCWSTR, DWORD, DWORD, PVOID); BOOL SetupSetFileQueueAlternatePlatformA(HSPFILEQ, PSP_ALTPLATFORM_INFO, PCSTR); BOOL SetupSetFileQueueAlternatePlatformW(HSPFILEQ, PSP_ALTPLATFORM_INFO, PCWSTR); BOOL SetupSetPlatformPathOverrideA(PCSTR); BOOL SetupSetPlatformPathOverrideW(PCWSTR); BOOL SetupSetSourceListA(DWORD, PCSTR*, UINT); BOOL SetupSetSourceListW(DWORD, PCWSTR*, UINT); VOID SetupTermDefaultQueueCallback(PVOID); BOOL SetupTerminateFileLog(HSPFILELOG); } deprecated { alias SetupDiCreateDeviceInterfaceW SetupDiCreateInterfaceDeviceW; alias SetupDiCreateDeviceInterfaceRegKeyW SetupDiCreateInterfaceDeviceRegKeyW; alias SetupDiOpenDeviceInterfaceW SetupDiOpenInterfaceDeviceW; alias SetupDiGetDeviceInterfaceDetailW SetupDiGetInterfaceDeviceDetailW; alias SetupDiCreateDeviceInterfaceA SetupDiCreateInterfaceDeviceA; alias SetupDiCreateDeviceInterfaceRegKeyA SetupDiCreateInterfaceDeviceRegKeyA; alias SetupDiOpenDeviceInterfaceA SetupDiOpenInterfaceDeviceA; alias SetupDiGetDeviceInterfaceDetailA SetupDiGetInterfaceDeviceDetailA; } version (Unicode) { alias PSP_FILE_CALLBACK_W PSP_FILE_CALLBACK; alias SetupAddInstallSectionToDiskSpaceListW SetupAddInstallSectionToDiskSpaceList; alias SetupAddSectionToDiskSpaceListW SetupAddSectionToDiskSpaceList; alias SetupAddToDiskSpaceListW SetupAddToDiskSpaceList; alias SetupAddToSourceListW SetupAddToSourceList; alias SetupAdjustDiskSpaceListW SetupAdjustDiskSpaceList; alias SetupBackupErrorW SetupBackupError; alias SetupCommitFileQueueW SetupCommitFileQueue; alias SetupCopyErrorW SetupCopyError; alias SetupCopyOEMInfW SetupCopyOEMInf; alias SetupCreateDiskSpaceListW SetupCreateDiskSpaceList; alias SetupDecompressOrCopyFileW SetupDecompressOrCopyFile; alias SetupDefaultQueueCallbackW SetupDefaultQueueCallback; alias SetupDeleteErrorW SetupDeleteError; alias SetupDiBuildClassInfoListExW SetupDiBuildClassInfoListEx; alias SetupDiClassGuidsFromNameExW SetupDiClassGuidsFromNameEx; alias SetupDiClassGuidsFromNameW SetupDiClassGuidsFromName; alias SetupDiClassNameFromGuidExW SetupDiClassNameFromGuidEx; alias SetupDiClassNameFromGuidW SetupDiClassNameFromGuid; alias SetupDiCreateDeviceInfoListExW SetupDiCreateDeviceInfoListEx; alias SetupDiCreateDeviceInfoW SetupDiCreateDeviceInfo; alias SetupDiCreateDeviceInterfaceRegKeyW SetupDiCreateDeviceInterfaceRegKey; deprecated alias SetupDiCreateDeviceInterfaceRegKeyW SetupDiCreateInterfaceDeviceRegKey; alias SetupDiCreateDeviceInterfaceW SetupDiCreateDeviceInterface; deprecated alias SetupDiCreateDeviceInterfaceW SetupDiCreateInterfaceDevice; alias SetupDiCreateDevRegKeyW SetupDiCreateDevRegKey; alias SetupDiEnumDriverInfoW SetupDiEnumDriverInfo; alias SetupDiGetActualSectionToInstallW SetupDiGetActualSectionToInstall; alias SetupDiGetClassDescriptionExW SetupDiGetClassDescriptionEx; alias SetupDiGetClassDescriptionW SetupDiGetClassDescription; alias SetupDiGetClassDevPropertySheetsW SetupDiGetClassDevPropertySheets; alias SetupDiGetClassDevsExW SetupDiGetClassDevsEx; alias SetupDiGetClassDevsW SetupDiGetClassDevs; alias SetupDiGetClassImageListExW SetupDiGetClassImageListEx; alias SetupDiGetClassInstallParamsW SetupDiGetClassInstallParams; alias SetupDiGetClassRegistryPropertyW SetupDiGetClassRegistryProperty; alias SetupDiGetDeviceInfoListDetailW SetupDiGetDeviceInfoListDetail; alias SetupDiGetDeviceInstallParamsW SetupDiGetDeviceInstallParams; alias SetupDiGetDeviceInstanceIdW SetupDiGetDeviceInstanceId; alias SetupDiGetDeviceInterfaceDetailW SetupDiGetDeviceInterfaceDetail; deprecated alias SetupDiGetDeviceInterfaceDetailW SetupDiGetInterfaceDeviceDetail; alias SetupDiGetDeviceRegistryPropertyW SetupDiGetDeviceRegistryProperty; alias SetupDiGetDriverInfoDetailW SetupDiGetDriverInfoDetail; alias SetupDiGetDriverInstallParamsW SetupDiGetDriverInstallParams; alias SetupDiGetHwProfileFriendlyNameExW SetupDiGetHwProfileFriendlyNameEx; alias SetupDiGetHwProfileFriendlyNameW SetupDiGetHwProfileFriendlyName; alias SetupDiGetHwProfileListExW SetupDiGetHwProfileListEx; alias SetupDiGetINFClassW SetupDiGetINFClass; alias SetupDiGetSelectedDriverW SetupDiGetSelectedDriver; alias SetupDiInstallClassExW SetupDiInstallClassEx; alias SetupDiInstallClassW SetupDiInstallClass; alias SetupDiOpenClassRegKeyExW SetupDiOpenClassRegKeyEx; alias SetupDiOpenDeviceInfoW SetupDiOpenDeviceInfo; alias SetupDiOpenDeviceInterfaceW SetupDiOpenDeviceInterface; deprecated alias SetupDiOpenDeviceInterfaceW SetupDiOpenInterfaceDevice; alias SetupDiSetClassInstallParamsW SetupDiSetClassInstallParams; alias SetupDiSetClassRegistryPropertyW SetupDiSetClassRegistryProperty; alias SetupDiSetDeviceInstallParamsW SetupDiSetDeviceInstallParams; alias SetupDiSetDeviceRegistryPropertyW SetupDiSetDeviceRegistryProperty; alias SetupDiSetDriverInstallParamsW SetupDiSetDriverInstallParams; alias SetupDiSetSelectedDriverW SetupDiSetSelectedDriver; alias SetupDuplicateDiskSpaceListW SetupDuplicateDiskSpaceList; alias SetupFindFirstLineW SetupFindFirstLine; alias SetupFindNextMatchLineW SetupFindNextMatchLine; alias SetupFreeSourceListW SetupFreeSourceList; alias SetupGetBackupInformationW SetupGetBackupInformation; alias SetupGetFileCompressionInfoW SetupGetFileCompressionInfo; alias SetupGetInfFileListW SetupGetInfFileList; alias SetupGetInfInformationW SetupGetInfInformation; alias SetupGetLineByIndexW SetupGetLineByIndex; alias SetupGetLineCountW SetupGetLineCount; alias SetupGetLineTextW SetupGetLineText; alias SetupGetMultiSzFieldW SetupGetMultiSzField; alias SetupGetSourceFileLocationW SetupGetSourceFileLocation; alias SetupGetSourceFileSizeW SetupGetSourceFileSize; alias SetupGetSourceInfoW SetupGetSourceInfo; alias SetupGetStringFieldW SetupGetStringField; alias SetupGetTargetPathW SetupGetTargetPath; alias SetupInitializeFileLogW SetupInitializeFileLog; alias SetupInstallFileExW SetupInstallFileEx; alias SetupInstallFilesFromInfSectionW SetupInstallFilesFromInfSection; alias SetupInstallFileW SetupInstallFile; alias SetupInstallFromInfSectionW SetupInstallFromInfSection; alias SetupInstallServicesFromInfSectionExW SetupInstallServicesFromInfSectionEx; alias SetupInstallServicesFromInfSectionW SetupInstallServicesFromInfSection; alias SetupIterateCabinetW SetupIterateCabinet; alias SetupLogErrorW SetupLogError; alias SetupLogFileW SetupLogFile; alias SetupOpenAppendInfFileW SetupOpenAppendInfFile; alias SetupOpenInfFileW SetupOpenInfFile; alias SetupPromptForDiskW SetupPromptForDisk; alias SetupQueryDrivesInDiskSpaceListW SetupQueryDrivesInDiskSpaceList; alias SetupQueryFileLogW SetupQueryFileLog; alias SetupQueryInfFileInformationW SetupQueryInfFileInformation; alias SetupQueryInfOriginalFileInformationW SetupQueryInfOriginalFileInformation; alias SetupQueryInfVersionInformationW SetupQueryInfVersionInformation; alias SetupQuerySourceListW SetupQuerySourceList; alias SetupQuerySpaceRequiredOnDriveW SetupQuerySpaceRequiredOnDrive; alias SetupQueueCopyIndirectW SetupQueueCopyIndirect; alias SetupQueueCopySectionW SetupQueueCopySection; alias SetupQueueCopyW SetupQueueCopy; alias SetupQueueDefaultCopyW SetupQueueDefaultCopy; alias SetupQueueDeleteSectionW SetupQueueDeleteSection; alias SetupQueueDeleteW SetupQueueDelete; alias SetupQueueRenameSectionW SetupQueueRenameSection; alias SetupQueueRenameW SetupQueueRename; alias SetupRemoveFileLogEntryW SetupRemoveFileLogEntry; alias SetupRemoveFromDiskSpaceListW SetupRemoveFromDiskSpaceList; alias SetupRemoveFromSourceListW SetupRemoveFromSourceList; alias SetupRemoveInstallSectionFromDiskSpaceListW SetupRemoveInstallSectionFromDiskSpaceList; alias SetupRemoveSectionFromDiskSpaceListW SetupRemoveSectionFromDiskSpaceList; alias SetupRenameErrorW SetupRenameError; alias SetupScanFileQueueW SetupScanFileQueue; alias SetupSetDirectoryIdExW SetupSetDirectoryIdEx; alias SetupSetDirectoryIdW SetupSetDirectoryId; alias SetupSetFileQueueAlternatePlatformW SetupSetFileQueueAlternatePlatform; alias SetupSetPlatformPathOverrideW SetupSetPlatformPathOverride; alias SetupSetSourceListW SetupSetSourceList; } else { alias PSP_FILE_CALLBACK_A PSP_FILE_CALLBACK; alias SetupAddInstallSectionToDiskSpaceListA SetupAddInstallSectionToDiskSpaceList; alias SetupAddSectionToDiskSpaceListA SetupAddSectionToDiskSpaceList; alias SetupAddToDiskSpaceListA SetupAddToDiskSpaceList; alias SetupAddToSourceListA SetupAddToSourceList; alias SetupAdjustDiskSpaceListA SetupAdjustDiskSpaceList; alias SetupBackupErrorA SetupBackupError; alias SetupCommitFileQueueA SetupCommitFileQueue; alias SetupCopyErrorA SetupCopyError; alias SetupCopyOEMInfA SetupCopyOEMInf; alias SetupCreateDiskSpaceListA SetupCreateDiskSpaceList; alias SetupDecompressOrCopyFileA SetupDecompressOrCopyFile; alias SetupDefaultQueueCallbackA SetupDefaultQueueCallback; alias SetupDeleteErrorA SetupDeleteError; alias SetupDiBuildClassInfoListExA SetupDiBuildClassInfoListEx; alias SetupDiClassGuidsFromNameA SetupDiClassGuidsFromName; alias SetupDiClassGuidsFromNameExA SetupDiClassGuidsFromNameEx; alias SetupDiClassNameFromGuidA SetupDiClassNameFromGuid; alias SetupDiClassNameFromGuidExA SetupDiClassNameFromGuidEx; alias SetupDiCreateDeviceInfoA SetupDiCreateDeviceInfo; alias SetupDiCreateDeviceInfoListExA SetupDiCreateDeviceInfoListEx; alias SetupDiCreateDeviceInterfaceA SetupDiCreateDeviceInterface; deprecated alias SetupDiCreateDeviceInterfaceA SetupDiCreateInterfaceDevice; alias SetupDiCreateDeviceInterfaceRegKeyA SetupDiCreateDeviceInterfaceRegKey; deprecated alias SetupDiCreateDeviceInterfaceRegKeyA SetupDiCreateInterfaceDeviceRegKey; alias SetupDiCreateDevRegKeyA SetupDiCreateDevRegKey; alias SetupDiDeleteDeviceInterfaceData SetupDiDeleteInterfaceDeviceData; alias SetupDiEnumDriverInfoA SetupDiEnumDriverInfo; alias SetupDiGetActualSectionToInstallA SetupDiGetActualSectionToInstall; alias SetupDiGetClassDescriptionA SetupDiGetClassDescription; alias SetupDiGetClassDescriptionExA SetupDiGetClassDescriptionEx; alias SetupDiGetClassDevPropertySheetsA SetupDiGetClassDevPropertySheets; alias SetupDiGetClassDevsA SetupDiGetClassDevs; alias SetupDiGetClassDevsExA SetupDiGetClassDevsEx; alias SetupDiGetClassImageListExA SetupDiGetClassImageListEx; alias SetupDiGetClassInstallParamsA SetupDiGetClassInstallParams; alias SetupDiGetClassRegistryPropertyA SetupDiGetClassRegistryProperty; alias SetupDiGetDeviceInfoListDetailA SetupDiGetDeviceInfoListDetail; alias SetupDiGetDeviceInstallParamsA SetupDiGetDeviceInstallParams; alias SetupDiGetDeviceInstanceIdA SetupDiGetDeviceInstanceId; alias SetupDiGetDeviceInterfaceDetailA SetupDiGetDeviceInterfaceDetail; deprecated alias SetupDiGetDeviceInterfaceDetailA SetupDiGetInterfaceDeviceDetail; alias SetupDiGetDeviceRegistryPropertyA SetupDiGetDeviceRegistryProperty; alias SetupDiGetDriverInfoDetailA SetupDiGetDriverInfoDetail; alias SetupDiGetDriverInstallParamsA SetupDiGetDriverInstallParams; alias SetupDiGetHwProfileFriendlyNameA SetupDiGetHwProfileFriendlyName; alias SetupDiGetHwProfileFriendlyNameExA SetupDiGetHwProfileFriendlyNameEx; alias SetupDiGetHwProfileListExA SetupDiGetHwProfileListEx; alias SetupDiGetINFClassA SetupDiGetINFClass; alias SetupDiGetSelectedDriverA SetupDiGetSelectedDriver; alias SetupDiInstallClassA SetupDiInstallClass; alias SetupDiInstallClassExA SetupDiInstallClassEx; alias SetupDiOpenClassRegKeyExA SetupDiOpenClassRegKeyEx; alias SetupDiOpenDeviceInfoA SetupDiOpenDeviceInfo; alias SetupDiOpenDeviceInterfaceA SetupDiOpenDeviceInterface; deprecated alias SetupDiOpenDeviceInterfaceA SetupDiOpenInterfaceDevice; alias SetupDiSetClassInstallParamsA SetupDiSetClassInstallParams; alias SetupDiSetClassRegistryPropertyA SetupDiSetClassRegistryProperty; alias SetupDiSetDeviceInstallParamsA SetupDiSetDeviceInstallParams; alias SetupDiSetDeviceRegistryPropertyA SetupDiSetDeviceRegistryProperty; alias SetupDiSetDriverInstallParamsA SetupDiSetDriverInstallParams; alias SetupDiSetSelectedDriverA SetupDiSetSelectedDriver; alias SetupDuplicateDiskSpaceListA SetupDuplicateDiskSpaceList; alias SetupFindFirstLineA SetupFindFirstLine; alias SetupFindNextMatchLineA SetupFindNextMatchLine; alias SetupFreeSourceListA SetupFreeSourceList; alias SetupGetBackupInformationA SetupGetBackupInformation; alias SetupGetFileCompressionInfoA SetupGetFileCompressionInfo; alias SetupGetInfFileListA SetupGetInfFileList; alias SetupGetInfInformationA SetupGetInfInformation; alias SetupGetLineByIndexA SetupGetLineByIndex; alias SetupGetLineCountA SetupGetLineCount; alias SetupGetLineTextA SetupGetLineText; alias SetupGetMultiSzFieldA SetupGetMultiSzField; alias SetupGetSourceFileLocationA SetupGetSourceFileLocation; alias SetupGetSourceFileSizeA SetupGetSourceFileSize; alias SetupGetSourceInfoA SetupGetSourceInfo; alias SetupGetStringFieldA SetupGetStringField; alias SetupGetTargetPathA SetupGetTargetPath; alias SetupInitializeFileLogA SetupInitializeFileLog; alias SetupInstallFileA SetupInstallFile; alias SetupInstallFileExA SetupInstallFileEx; alias SetupInstallFilesFromInfSectionA SetupInstallFilesFromInfSection; alias SetupInstallFromInfSectionA SetupInstallFromInfSection; alias SetupInstallServicesFromInfSectionA SetupInstallServicesFromInfSection; alias SetupInstallServicesFromInfSectionExA SetupInstallServicesFromInfSectionEx; alias SetupIterateCabinetA SetupIterateCabinet; alias SetupLogErrorA SetupLogError; alias SetupLogFileA SetupLogFile; alias SetupOpenAppendInfFileA SetupOpenAppendInfFile; alias SetupOpenInfFileA SetupOpenInfFile; alias SetupPromptForDiskA SetupPromptForDisk; alias SetupQueryDrivesInDiskSpaceListA SetupQueryDrivesInDiskSpaceList; alias SetupQueryFileLogA SetupQueryFileLog; alias SetupQueryInfFileInformationA SetupQueryInfFileInformation; alias SetupQueryInfOriginalFileInformationA SetupQueryInfOriginalFileInformation; alias SetupQueryInfVersionInformationA SetupQueryInfVersionInformation; alias SetupQuerySourceListA SetupQuerySourceList; alias SetupQuerySpaceRequiredOnDriveA SetupQuerySpaceRequiredOnDrive; alias SetupQueueCopyA SetupQueueCopy; alias SetupQueueCopyIndirectA SetupQueueCopyIndirect; alias SetupQueueCopySectionA SetupQueueCopySection; alias SetupQueueDefaultCopyA SetupQueueDefaultCopy; alias SetupQueueDeleteA SetupQueueDelete; alias SetupQueueDeleteSectionA SetupQueueDeleteSection; alias SetupQueueRenameA SetupQueueRename; alias SetupQueueRenameSectionA SetupQueueRenameSection; alias SetupRemoveFileLogEntryA SetupRemoveFileLogEntry; alias SetupRemoveFromDiskSpaceListA SetupRemoveFromDiskSpaceList; alias SetupRemoveFromSourceListA SetupRemoveFromSourceList; alias SetupRemoveInstallSectionFromDiskSpaceListA SetupRemoveInstallSectionFromDiskSpaceList; alias SetupRemoveSectionFromDiskSpaceListA SetupRemoveSectionFromDiskSpaceList; alias SetupRenameErrorA SetupRenameError; alias SetupScanFileQueueA SetupScanFileQueue; alias SetupSetDirectoryIdA SetupSetDirectoryId; alias SetupSetDirectoryIdExA SetupSetDirectoryIdEx; alias SetupSetFileQueueAlternatePlatformA SetupSetFileQueueAlternatePlatform; alias SetupSetPlatformPathOverrideA SetupSetPlatformPathOverride; alias SetupSetSourceListA SetupSetSourceList; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/mapi.d0000664000175000017500000001251312776214756022607 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_mapi.d) */ module core.sys.windows.mapi; version (Windows): private import core.sys.windows.windef; // FIXME: check types and grouping of constants enum { SUCCESS_SUCCESS, MAPI_USER_ABORT, MAPI_E_USER_ABORT = MAPI_USER_ABORT, MAPI_E_FAILURE, MAPI_E_LOGIN_FAILURE, MAPI_E_LOGON_FAILURE = MAPI_E_LOGIN_FAILURE, MAPI_E_DISK_FULL = 4, MAPI_E_INSUFFICIENT_MEMORY, MAPI_E_ACCESS_DENIED, MAPI_E_BLK_TOO_SMALL = MAPI_E_ACCESS_DENIED, // = 6 MAPI_E_TOO_MANY_SESSIONS = 8, MAPI_E_TOO_MANY_FILES, MAPI_E_TOO_MANY_RECIPIENTS, MAPI_E_ATTACHMENT_NOT_FOUND, MAPI_E_ATTACHMENT_OPEN_FAILURE, MAPI_E_ATTACHMENT_WRITE_FAILURE, MAPI_E_UNKNOWN_RECIPIENT, MAPI_E_BAD_RECIPTYPE, MAPI_E_NO_MESSAGES, MAPI_E_INVALID_MESSAGE, MAPI_E_TEXT_TOO_LARGE, MAPI_E_INVALID_SESSION, MAPI_E_TYPE_NOT_SUPPORTED, MAPI_E_AMBIGUOUS_RECIPIENT, MAPI_E_AMBIGUOUS_RECIP = MAPI_E_AMBIGUOUS_RECIPIENT, MAPI_E_MESSAGE_IN_USE, MAPI_E_NETWORK_FAILURE, MAPI_E_INVALID_EDITFIELDS, MAPI_E_INVALID_RECIPS, MAPI_E_NOT_SUPPORTED // = 26 } enum { MAPI_ORIG, MAPI_TO, MAPI_CC, MAPI_BCC } enum MAPI_LOGON_UI = 0x0001; enum MAPI_NEW_SESSION = 0x0002; enum MAPI_FORCE_DOWNLOAD = 0x1000; enum MAPI_LOGOFF_SHARED = 0x0001; enum MAPI_LOGOFF_UI = 0x0002; enum MAPI_DIALOG = 0x0008; enum MAPI_UNREAD_ONLY = 0x0020; enum MAPI_LONG_MSGID = 0x4000; enum MAPI_GUARANTEE_FIFO = 0x0100; enum MAPI_ENVELOPE_ONLY = 0x0040; enum MAPI_PEEK = 0x0080; enum MAPI_BODY_AS_FILE = 0x0200; enum MAPI_SUPPRESS_ATTACH = 0x0800; enum MAPI_AB_NOMODIFY = 0x0400; enum MAPI_OLE = 0x0001; enum MAPI_OLE_STATIC = 0x0002; enum MAPI_UNREAD = 0x0001; enum MAPI_RECEIPT_REQUESTED = 0x0002; enum MAPI_SENT = 0x0004; alias uint FLAGS, LHANDLE; alias uint* LPLHANDLE, LPULONG; struct MapiRecipDesc { ULONG ulReserved; ULONG ulRecipClass; LPSTR lpszName; LPSTR lpszAddress; ULONG ulEIDSize; LPVOID lpEntryID; } alias MapiRecipDesc* lpMapiRecipDesc; struct MapiFileDesc { ULONG ulReserved; ULONG flFlags; ULONG nPosition; LPSTR lpszPathName; LPSTR lpszFileName; LPVOID lpFileType; } alias MapiFileDesc* lpMapiFileDesc; struct MapiFileTagExt { ULONG ulReserved; ULONG cbTag; LPBYTE lpTag; ULONG cbEncoding; LPBYTE lpEncoding; } alias MapiFileTagExt* lpMapiFileTagExt; struct MapiMessage { ULONG ulReserved; LPSTR lpszSubject; LPSTR lpszNoteText; LPSTR lpszMessageType; LPSTR lpszDateReceived; LPSTR lpszConversationID; FLAGS flFlags; lpMapiRecipDesc lpOriginator; ULONG nRecipCount; lpMapiRecipDesc lpRecips; ULONG nFileCount; lpMapiFileDesc lpFiles; } alias MapiMessage* lpMapiMessage; extern (Pascal) { ULONG MAPILogon(ULONG, LPSTR, LPSTR, FLAGS, ULONG, LPLHANDLE); ULONG MAPISendMail(LHANDLE, ULONG, lpMapiMessage, FLAGS, ULONG); ULONG MAPISendDocuments(ULONG, LPSTR, LPSTR, LPSTR, ULONG); ULONG MAPIReadMail(LHANDLE, ULONG, LPSTR, FLAGS, ULONG, lpMapiMessage*); ULONG MAPIFindNext(LHANDLE, ULONG, LPSTR, LPSTR, FLAGS, ULONG, LPSTR); ULONG MAPIResolveName(LHANDLE, ULONG, LPSTR, FLAGS, ULONG, lpMapiRecipDesc*); ULONG MAPIAddress(LHANDLE, ULONG, LPSTR, ULONG, LPSTR, ULONG, lpMapiRecipDesc, FLAGS, ULONG, LPULONG, lpMapiRecipDesc*); ULONG MAPIFreeBuffer(LPVOID); ULONG MAPIDetails(LHANDLE, ULONG, lpMapiRecipDesc, FLAGS, ULONG); ULONG MAPISaveMail(LHANDLE, ULONG, lpMapiMessage lpszMessage, FLAGS, ULONG, LPSTR); ULONG MAPIDeleteMail(LHANDLE lpSession, ULONG, LPSTR, FLAGS, ULONG); ULONG MAPILogoff(LHANDLE, ULONG, FLAGS, ULONG); // Netscape extensions ULONG MAPIGetNetscapeVersion(); ULONG MAPI_NSCP_SynchronizeClient(LHANDLE, ULONG); // Handles for use with GetProcAddress alias ULONG function(ULONG, LPSTR, LPSTR, FLAGS, ULONG, LPLHANDLE) LPMAPILOGON; alias ULONG function(LHANDLE, ULONG, lpMapiMessage, FLAGS, ULONG) LPMAPISENDMAIL; alias ULONG function(ULONG, LPSTR, LPSTR, LPSTR, ULONG) LPMAPISENDDOCUMENTS; alias ULONG function(LHANDLE, ULONG, LPSTR, FLAGS, ULONG, lpMapiMessage*) LPMAPIREADMAIL; alias ULONG function(LHANDLE, ULONG, LPSTR, LPSTR, FLAGS, ULONG, LPSTR) LPMAPIFINDNEXT; alias ULONG function(LHANDLE, ULONG, LPSTR, FLAGS, ULONG, lpMapiRecipDesc*) LPMAPIRESOLVENAME; alias ULONG function(LHANDLE, ULONG, LPSTR, ULONG, LPSTR, ULONG, lpMapiRecipDesc, FLAGS, ULONG, LPULONG, lpMapiRecipDesc*) LPMAPIADDRESS; alias ULONG function(LPVOID lpv) LPMAPIFREEBUFFER; alias ULONG function(LHANDLE, ULONG, lpMapiRecipDesc, FLAGS, ULONG) LPMAPIDETAILS; alias ULONG function(LHANDLE, ULONG, lpMapiMessage, FLAGS, ULONG, LPSTR) LPMAPISAVEMAIL; alias ULONG function(LHANDLE lpSession, ULONG, LPSTR, FLAGS, ULONG) LPMAPIDELETEMAIL; alias ULONG function(LHANDLE, ULONG, FLAGS, ULONG) LPMAPILOGOFF; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/psapi.d0000664000175000017500000001321112776214756022771 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_psapi.d) */ /* Comment from MinGW * Process status API (PSAPI) * http://windowssdk.msdn.microsoft.com/library/ms684884.aspx */ module core.sys.windows.psapi; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.w32api; private import core.sys.windows.winbase; private import core.sys.windows.windef; struct MODULEINFO { LPVOID lpBaseOfDll; DWORD SizeOfImage; LPVOID EntryPoint; } alias MODULEINFO* LPMODULEINFO; struct PSAPI_WS_WATCH_INFORMATION { LPVOID FaultingPc; LPVOID FaultingVa; } alias PSAPI_WS_WATCH_INFORMATION* PPSAPI_WS_WATCH_INFORMATION; struct PSAPI_WS_WATCH_INFORMATION_EX { PSAPI_WS_WATCH_INFORMATION BasicInfo; ULONG_PTR FaultingThreadId; ULONG_PTR Flags; } alias PSAPI_WS_WATCH_INFORMATION_EX* PPSAPI_WS_WATCH_INFORMATION_EX; struct PROCESS_MEMORY_COUNTERS { DWORD cb; DWORD PageFaultCount; DWORD PeakWorkingSetSize; DWORD WorkingSetSize; DWORD QuotaPeakPagedPoolUsage; DWORD QuotaPagedPoolUsage; DWORD QuotaPeakNonPagedPoolUsage; DWORD QuotaNonPagedPoolUsage; DWORD PagefileUsage; DWORD PeakPagefileUsage; } alias PROCESS_MEMORY_COUNTERS* PPROCESS_MEMORY_COUNTERS; struct PERFORMANCE_INFORMATION { DWORD cb; SIZE_T CommitTotal; SIZE_T CommitLimit; SIZE_T CommitPeak; SIZE_T PhysicalTotal; SIZE_T PhysicalAvailable; SIZE_T SystemCache; SIZE_T KernelTotal; SIZE_T KernelPaged; SIZE_T KernelNonpaged; SIZE_T PageSize; DWORD HandleCount; DWORD ProcessCount; DWORD ThreadCount; } alias PERFORMANCE_INFORMATION* PPERFORMANCE_INFORMATION; struct ENUM_PAGE_FILE_INFORMATION { DWORD cb; DWORD Reserved; SIZE_T TotalSize; SIZE_T TotalInUse; SIZE_T PeakUsage; } alias ENUM_PAGE_FILE_INFORMATION* PENUM_PAGE_FILE_INFORMATION; /* application-defined callback function used with the EnumPageFiles() * http://windowssdk.msdn.microsoft.com/library/ms682627.aspx */ version (Unicode) { alias BOOL function(LPVOID, PENUM_PAGE_FILE_INFORMATION, LPCWSTR) PENUM_PAGE_FILE_CALLBACK; } else { alias BOOL function(LPVOID, PENUM_PAGE_FILE_INFORMATION, LPCSTR) PENUM_PAGE_FILE_CALLBACK; } // Grouped by application, not in alphabetical order. extern (Windows) { /* Process Information * http://windowssdk.msdn.microsoft.com/library/ms684870.aspx */ BOOL EnumProcesses(DWORD*, DWORD, DWORD*); /* NT/2000/XP/Server2003/Vista/Longhorn */ DWORD GetProcessImageFileNameA(HANDLE, LPSTR, DWORD); /* XP/Server2003/Vista/Longhorn */ DWORD GetProcessImageFileNameW(HANDLE, LPWSTR, DWORD); /* XP/Server2003/Vista/Longhorn */ /* Module Information * http://windowssdk.msdn.microsoft.com/library/ms684232.aspx */ BOOL EnumProcessModules(HANDLE, HMODULE*, DWORD, LPDWORD); BOOL EnumProcessModulesEx(HANDLE, HMODULE*, DWORD, LPDWORD, DWORD); /* Vista/Longhorn */ DWORD GetModuleBaseNameA(HANDLE, HMODULE, LPSTR, DWORD); DWORD GetModuleBaseNameW(HANDLE, HMODULE, LPWSTR, DWORD); DWORD GetModuleFileNameExA(HANDLE, HMODULE, LPSTR, DWORD); DWORD GetModuleFileNameExW(HANDLE, HMODULE, LPWSTR, DWORD); BOOL GetModuleInformation(HANDLE, HMODULE, LPMODULEINFO, DWORD); /* Device Driver Information * http://windowssdk.msdn.microsoft.com/library/ms682578.aspx */ BOOL EnumDeviceDrivers(LPVOID*, DWORD, LPDWORD); DWORD GetDeviceDriverBaseNameA(LPVOID, LPSTR, DWORD); DWORD GetDeviceDriverBaseNameW(LPVOID, LPWSTR, DWORD); DWORD GetDeviceDriverFileNameA(LPVOID, LPSTR, DWORD); DWORD GetDeviceDriverFileNameW(LPVOID, LPWSTR, DWORD); /* Process Memory Usage Information * http://windowssdk.msdn.microsoft.com/library/ms684879.aspx */ BOOL GetProcessMemoryInfo(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD); /* Working Set Information * http://windowssdk.msdn.microsoft.com/library/ms687398.aspx */ BOOL EmptyWorkingSet(HANDLE); BOOL GetWsChanges(HANDLE, PPSAPI_WS_WATCH_INFORMATION, DWORD); BOOL GetWsChangesEx(HANDLE, PPSAPI_WS_WATCH_INFORMATION_EX, DWORD); /* Vista/Longhorn */ BOOL InitializeProcessForWsWatch(HANDLE); BOOL QueryWorkingSet(HANDLE, PVOID, DWORD); BOOL QueryWorkingSetEx(HANDLE, PVOID, DWORD); /* Memory-Mapped File Information * http://windowssdk.msdn.microsoft.com/library/ms684212.aspx */ DWORD GetMappedFileNameW(HANDLE, LPVOID, LPWSTR, DWORD); DWORD GetMappedFileNameA(HANDLE, LPVOID, LPSTR, DWORD); /* Resources Information */ BOOL GetPerformanceInfo(PPERFORMANCE_INFORMATION, DWORD); /* XP/Server2003/Vista/Longhorn */ BOOL EnumPageFilesW(PENUM_PAGE_FILE_CALLBACK, LPVOID); /* 2000/XP/Server2003/Vista/Longhorn */ BOOL EnumPageFilesA(PENUM_PAGE_FILE_CALLBACK, LPVOID); /* 2000/XP/Server2003/Vista/Longhorn */ } version (Unicode) { alias GetModuleBaseNameW GetModuleBaseName; alias GetModuleFileNameExW GetModuleFileNameEx; alias GetMappedFileNameW GetMappedFileName; alias GetDeviceDriverBaseNameW GetDeviceDriverBaseName; alias GetDeviceDriverFileNameW GetDeviceDriverFileName; alias EnumPageFilesW EnumPageFiles; alias GetProcessImageFileNameW GetProcessImageFileName; } else { alias GetModuleBaseNameA GetModuleBaseName; alias GetModuleFileNameExA GetModuleFileNameEx; alias GetMappedFileNameA GetMappedFileName; alias GetDeviceDriverBaseNameA GetDeviceDriverBaseName; alias GetDeviceDriverFileNameA GetDeviceDriverFileName; alias EnumPageFilesA EnumPageFiles; alias GetProcessImageFileNameA GetProcessImageFileName; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/shlwapi.d0000664000175000017500000006370112776214756023335 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_shlwapi.d) */ module core.sys.windows.shlwapi; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "shlwapi"); /* Changes compared to MinGW: wnsprintf functions are not included. // Macros unneeded for D #define StrCmpIA lstrcmpiA; #define StrCmpA lstrcmpA; #define StrCpyA lstrcpyA; #define StrCpyNA lstrcpynA; #define MAKEDLLVERULL(major, minor, build, qfe) \ (((ULONGLONG)(major) << 48) | \ ((ULONGLONG)(minor) << 32) | \ ((ULONGLONG)(build) << 16) | \ ((ULONGLONG)( qfe) << 0)) */ import core.sys.windows.objbase, core.sys.windows.shlobj; private import core.sys.windows.basetyps, core.sys.windows.objidl, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.winbase, core.sys.windows.winreg; enum DLLVER_PLATFORM_WINDOWS = 0x00000001; enum DLLVER_PLATFORM_NT = 0x00000002; enum URL_DONT_ESCAPE_EXTRA_INFO = 0x02000000; enum URL_DONT_SIMPLIFY = 0x08000000; enum URL_ESCAPE_PERCENT = 0x00001000; enum URL_ESCAPE_SEGMENT_ONLY = 0x00002000; enum URL_ESCAPE_SPACES_ONLY = 0x04000000; enum URL_ESCAPE_UNSAFE = 0x20000000; enum URL_INTERNAL_PATH = 0x00800000; enum URL_PARTFLAG_KEEPSCHEME = 0x00000001; enum URL_PLUGGABLE_PROTOCOL = 0x40000000; enum URL_UNESCAPE = 0x10000000; enum URL_UNESCAPE_HIGH_ANSI_ONLY = 0x00400000; enum URL_UNESCAPE_INPLACE = 0x00100000; align(1): struct DLLVERSIONINFO { DWORD cbSize = this.sizeof; DWORD dwMajorVersion; DWORD dwMinorVersion; DWORD dwBuildNumber; DWORD dwPlatformID; } struct DLLVERSIONINFO2 { DLLVERSIONINFO info1; DWORD dwFlags; ULONGLONG ullVersion; } enum ASSOCSTR { ASSOCSTR_COMMAND, ASSOCSTR_EXECUTABLE, ASSOCSTR_FRIENDLYDOCNAME, ASSOCSTR_FRIENDLYAPPNAME, ASSOCSTR_NOOPEN, ASSOCSTR_SHELLNEWVALUE, ASSOCSTR_DDECOMMAND, ASSOCSTR_DDEIFEXEC, ASSOCSTR_DDEAPPLICATION, ASSOCSTR_DDETOPIC } enum ASSOCKEY { ASSOCKEY_SHELLEXECCLASS = 1, ASSOCKEY_APP, ASSOCKEY_CLASS, ASSOCKEY_BASECLASS } enum ASSOCDATA { ASSOCDATA_MSIDESCRIPTOR = 1, ASSOCDATA_NOACTIVATEHANDLER, ASSOCDATA_QUERYCLASSSTORE } alias DWORD ASSOCF; enum SHREGDEL_FLAGS { SHREGDEL_DEFAULT = 0x00000000, SHREGDEL_HKCU = 0x00000001, SHREGDEL_HKLM = 0x00000010, SHREGDEL_BOTH = 0x00000011 } enum SHREGENUM_FLAGS { SHREGENUM_DEFAULT = 0x00000000, SHREGENUM_HKCU = 0x00000001, SHREGENUM_HKLM = 0x00000010, SHREGENUM_BOTH = 0x00000011 } enum URLIS { URLIS_URL, URLIS_OPAQUE, URLIS_NOHISTORY, URLIS_FILEURL, URLIS_APPLIABLE, URLIS_DIRECTORY, URLIS_HASQUERY } mixin DECLARE_HANDLE!("HUSKEY"); alias HUSKEY* PHUSKEY; extern (Windows) { alias HRESULT function (DLLVERSIONINFO *) DLLGETVERSIONPROC; } BOOL IntlStrEqNA(LPCSTR pStr1, LPCSTR pStr2, int nChar) { return IntlStrEqWorkerA(TRUE, pStr1, pStr2, nChar); } BOOL IntlStrEqNW(LPCWSTR pStr1, LPCWSTR pStr2, int nChar) { return IntlStrEqWorkerW(TRUE, pStr1, pStr2, nChar); } BOOL IntlStrEqNIA(LPCSTR pStr1, LPCSTR pStr2, int nChar) { return IntlStrEqWorkerA(FALSE, pStr1, pStr2, nChar); } BOOL IntlStrEqNIW(LPCWSTR pStr1, LPCWSTR pStr2, int nChar) { return IntlStrEqWorkerW(FALSE, pStr1, pStr2, nChar); } BOOL UrlIsFileUrlA(LPCSTR pszURL) { return UrlIsA(pszURL, URLIS.URLIS_FILEURL); } BOOL UrlIsFileUrlW(LPCWSTR pszURL) { return UrlIsW(pszURL, URLIS.URLIS_FILEURL); } HRESULT UrlUnescapeInPlaceA(LPSTR pszUrl, DWORD dwFlags) { return UrlUnescapeA(pszUrl, null, null, dwFlags | URL_UNESCAPE_INPLACE); } HRESULT UrlUnescapeInPlaceW(LPWSTR pszUrl, DWORD dwFlags) { return UrlUnescapeW(pszUrl, null, null, dwFlags | URL_UNESCAPE_INPLACE); } extern (Windows): BOOL ChrCmpIA(WORD, WORD); BOOL ChrCmpIW(WCHAR, WCHAR); BOOL IntlStrEqWorkerA(BOOL, LPCSTR, LPCSTR, int); BOOL IntlStrEqWorkerW(BOOL, LPCWSTR, LPCWSTR, int); HRESULT SHStrDupA(LPCSTR, LPWSTR*); HRESULT SHStrDupW(LPCWSTR, LPWSTR*); LPSTR StrCatA(LPSTR, LPCSTR); LPWSTR StrCatW(LPWSTR, LPCWSTR); LPSTR StrCatBuffA(LPSTR, LPCSTR, int); LPWSTR StrCatBuffW(LPWSTR, LPCWSTR, int); DWORD StrCatChainW(LPWSTR, DWORD, DWORD, LPCWSTR); LPSTR StrChrA(LPCSTR, WORD); LPWSTR StrChrW(LPCWSTR, WCHAR); LPSTR StrChrIA(LPCSTR, WORD); LPWSTR StrChrIW(LPCWSTR, WCHAR); int StrCmpIW(LPCWSTR, LPCWSTR); int StrCmpW(LPCWSTR, LPCWSTR); LPWSTR StrCpyW(LPWSTR, LPCWSTR); LPWSTR StrCpyNW(LPWSTR, LPCWSTR, int); int StrCmpNA(LPCSTR, LPCSTR, int); int StrCmpNW(LPCWSTR, LPCWSTR, int); int StrCmpNIA(LPCSTR, LPCSTR, int); int StrCmpNIW(LPCWSTR, LPCWSTR, int); int StrCSpnA(LPCSTR, LPCSTR); int StrCSpnW(LPCWSTR, LPCWSTR); int StrCSpnIA(LPCSTR, LPCSTR); int StrCSpnIW(LPCWSTR, LPCWSTR); LPSTR StrDupA(LPCSTR); LPWSTR StrDupW(LPCWSTR); LPSTR StrFormatByteSize64A(LONGLONG, LPSTR, UINT); LPSTR StrFormatByteSizeA(DWORD, LPSTR, UINT); LPWSTR StrFormatByteSizeW(LONGLONG, LPWSTR, UINT); LPSTR StrFormatKBSizeA(LONGLONG, LPSTR, UINT); LPWSTR StrFormatKBSizeW(LONGLONG, LPWSTR, UINT); int StrFromTimeIntervalA(LPSTR, UINT, DWORD, int); int StrFromTimeIntervalW(LPWSTR, UINT, DWORD, int); BOOL StrIsIntlEqualA(BOOL, LPCSTR, LPCSTR, int); BOOL StrIsIntlEqualW(BOOL, LPCWSTR, LPCWSTR, int); LPSTR StrNCatA(LPSTR, LPCSTR, int); LPWSTR StrNCatW(LPWSTR, LPCWSTR, int); LPSTR StrPBrkA(LPCSTR, LPCSTR); LPWSTR StrPBrkW(LPCWSTR, LPCWSTR); LPSTR StrRChrA(LPCSTR, LPCSTR, WORD); LPWSTR StrRChrW(LPCWSTR, LPCWSTR, WCHAR); LPSTR StrRChrIA(LPCSTR, LPCSTR, WORD); LPWSTR StrRChrIW(LPCWSTR, LPCWSTR, WCHAR); LPSTR StrRStrIA(LPCSTR, LPCSTR, LPCSTR); LPWSTR StrRStrIW(LPCWSTR, LPCWSTR, LPCWSTR); int StrSpnA(LPCSTR, LPCSTR); int StrSpnW(LPCWSTR, LPCWSTR); LPSTR StrStrA(LPCSTR, LPCSTR); LPSTR StrStrIA(LPCSTR, LPCSTR); LPWSTR StrStrIW(LPCWSTR, LPCWSTR); LPWSTR StrStrW(LPCWSTR, LPCWSTR); int StrToIntA(LPCSTR); int StrToIntW(LPCWSTR); BOOL StrToIntExA(LPCSTR, DWORD, int*); BOOL StrToIntExW(LPCWSTR, DWORD, int*); BOOL StrTrimA(LPSTR, LPCSTR); BOOL StrTrimW(LPWSTR, LPCWSTR); LPSTR PathAddBackslashA(LPSTR); LPWSTR PathAddBackslashW(LPWSTR); BOOL PathAddExtensionA(LPSTR, LPCSTR); BOOL PathAddExtensionW(LPWSTR, LPCWSTR); BOOL PathAppendA(LPSTR, LPCSTR); BOOL PathAppendW(LPWSTR, LPCWSTR); LPSTR PathBuildRootA(LPSTR, int); LPWSTR PathBuildRootW(LPWSTR, int); BOOL PathCanonicalizeA(LPSTR, LPCSTR); BOOL PathCanonicalizeW(LPWSTR, LPCWSTR); LPSTR PathCombineA(LPSTR, LPCSTR, LPCSTR); LPWSTR PathCombineW(LPWSTR, LPCWSTR, LPCWSTR); int PathCommonPrefixA(LPCSTR, LPCSTR, LPSTR); int PathCommonPrefixW(LPCWSTR, LPCWSTR, LPWSTR); BOOL PathCompactPathA(HDC, LPSTR, UINT); BOOL PathCompactPathW(HDC, LPWSTR, UINT); BOOL PathCompactPathExA(LPSTR, LPCSTR, UINT, DWORD); BOOL PathCompactPathExW(LPWSTR, LPCWSTR, UINT, DWORD); HRESULT PathCreateFromUrlA(LPCSTR, LPSTR, LPDWORD, DWORD); HRESULT PathCreateFromUrlW(LPCWSTR, LPWSTR, LPDWORD, DWORD); BOOL PathFileExistsA(LPCSTR); BOOL PathFileExistsW(LPCWSTR); LPSTR PathFindExtensionA(LPCSTR); LPWSTR PathFindExtensionW(LPCWSTR); LPSTR PathFindFileNameA(LPCSTR); LPWSTR PathFindFileNameW(LPCWSTR); LPSTR PathFindNextComponentA(LPCSTR); LPWSTR PathFindNextComponentW(LPCWSTR); BOOL PathFindOnPathA(LPSTR, LPCSTR*); BOOL PathFindOnPathW(LPWSTR, LPCWSTR*); LPCSTR PathFindSuffixArrayA(LPCSTR, LPCSTR*, int); LPCWSTR PathFindSuffixArrayW(LPCWSTR, LPCWSTR*, int); LPSTR PathGetArgsA(LPCSTR); LPWSTR PathGetArgsW(LPCWSTR); UINT PathGetCharTypeA(UCHAR); UINT PathGetCharTypeW(WCHAR); int PathGetDriveNumberA(LPCSTR); int PathGetDriveNumberW(LPCWSTR); BOOL PathIsContentTypeA(LPCSTR, LPCSTR); BOOL PathIsContentTypeW(LPCWSTR, LPCWSTR); BOOL PathIsDirectoryA(LPCSTR); BOOL PathIsDirectoryEmptyA(LPCSTR); BOOL PathIsDirectoryEmptyW(LPCWSTR); BOOL PathIsDirectoryW(LPCWSTR); BOOL PathIsFileSpecA(LPCSTR); BOOL PathIsFileSpecW(LPCWSTR); BOOL PathIsLFNFileSpecA(LPCSTR); BOOL PathIsLFNFileSpecW(LPCWSTR); BOOL PathIsNetworkPathA(LPCSTR); BOOL PathIsNetworkPathW(LPCWSTR); BOOL PathIsPrefixA(LPCSTR, LPCSTR); BOOL PathIsPrefixW(LPCWSTR, LPCWSTR); BOOL PathIsRelativeA(LPCSTR); BOOL PathIsRelativeW(LPCWSTR); BOOL PathIsRootA(LPCSTR); BOOL PathIsRootW(LPCWSTR); BOOL PathIsSameRootA(LPCSTR, LPCSTR); BOOL PathIsSameRootW(LPCWSTR, LPCWSTR); BOOL PathIsSystemFolderA(LPCSTR, DWORD); BOOL PathIsSystemFolderW(LPCWSTR, DWORD); BOOL PathIsUNCA(LPCSTR); BOOL PathIsUNCServerA(LPCSTR); BOOL PathIsUNCServerShareA(LPCSTR); BOOL PathIsUNCServerShareW(LPCWSTR); BOOL PathIsUNCServerW(LPCWSTR); BOOL PathIsUNCW(LPCWSTR); BOOL PathIsURLA(LPCSTR); BOOL PathIsURLW(LPCWSTR); BOOL PathMakePrettyA(LPSTR); BOOL PathMakePrettyW(LPWSTR); BOOL PathMakeSystemFolderA(LPSTR); BOOL PathMakeSystemFolderW(LPWSTR); BOOL PathMatchSpecA(LPCSTR, LPCSTR); BOOL PathMatchSpecW(LPCWSTR, LPCWSTR); int PathParseIconLocationA(LPSTR); int PathParseIconLocationW(LPWSTR); void PathQuoteSpacesA(LPSTR); void PathQuoteSpacesW(LPWSTR); BOOL PathRelativePathToA(LPSTR, LPCSTR, DWORD, LPCSTR, DWORD); BOOL PathRelativePathToW(LPWSTR, LPCWSTR, DWORD, LPCWSTR, DWORD); void PathRemoveArgsA(LPSTR); void PathRemoveArgsW(LPWSTR); LPSTR PathRemoveBackslashA(LPSTR); LPWSTR PathRemoveBackslashW(LPWSTR); void PathRemoveBlanksA(LPSTR); void PathRemoveBlanksW(LPWSTR); void PathRemoveExtensionA(LPSTR); void PathRemoveExtensionW(LPWSTR); BOOL PathRemoveFileSpecA(LPSTR); BOOL PathRemoveFileSpecW(LPWSTR); BOOL PathRenameExtensionA(LPSTR, LPCSTR); BOOL PathRenameExtensionW(LPWSTR, LPCWSTR); BOOL PathSearchAndQualifyA(LPCSTR, LPSTR, UINT); BOOL PathSearchAndQualifyW(LPCWSTR, LPWSTR, UINT); void PathSetDlgItemPathA(HWND, int, LPCSTR); void PathSetDlgItemPathW(HWND, int, LPCWSTR); LPSTR PathSkipRootA(LPCSTR); LPWSTR PathSkipRootW(LPCWSTR); void PathStripPathA(LPSTR); void PathStripPathW(LPWSTR); BOOL PathStripToRootA(LPSTR); BOOL PathStripToRootW(LPWSTR); void PathUndecorateA(LPSTR); void PathUndecorateW(LPWSTR); BOOL PathUnExpandEnvStringsA(LPCSTR, LPSTR, UINT); BOOL PathUnExpandEnvStringsW(LPCWSTR, LPWSTR, UINT); BOOL PathUnmakeSystemFolderA(LPSTR); BOOL PathUnmakeSystemFolderW(LPWSTR); void PathUnquoteSpacesA(LPSTR); void PathUnquoteSpacesW(LPWSTR); HRESULT SHAutoComplete(HWND, DWORD); BOOL SHCreateThread(LPTHREAD_START_ROUTINE, void*, DWORD, LPTHREAD_START_ROUTINE); DWORD SHCopyKeyA(HKEY, LPCSTR, HKEY, DWORD); DWORD SHCopyKeyW(HKEY, LPCWSTR, HKEY, DWORD); DWORD SHDeleteEmptyKeyA(HKEY, LPCSTR); DWORD SHDeleteEmptyKeyW(HKEY, LPCWSTR); DWORD SHDeleteKeyA(HKEY, LPCSTR); DWORD SHDeleteKeyW(HKEY, LPCWSTR); DWORD SHEnumKeyExA(HKEY, DWORD, LPSTR, LPDWORD); DWORD SHEnumKeyExW(HKEY, DWORD, LPWSTR, LPDWORD); DWORD SHQueryInfoKeyA(HKEY, LPDWORD, LPDWORD, LPDWORD, LPDWORD); DWORD SHQueryInfoKeyW(HKEY, LPDWORD, LPDWORD, LPDWORD, LPDWORD); DWORD SHQueryValueExA(HKEY, LPCSTR, LPDWORD, LPDWORD, LPVOID, LPDWORD); DWORD SHQueryValueExW(HKEY, LPCWSTR, LPDWORD, LPDWORD, LPVOID, LPDWORD); HRESULT SHGetThreadRef(IUnknown*); HRESULT SHSetThreadRef(IUnknown); BOOL SHSkipJunction(IBindCtx, const(CLSID)*); DWORD SHEnumValueA(HKEY, DWORD, LPSTR, LPDWORD, LPDWORD, LPVOID, LPDWORD); DWORD SHEnumValueW(HKEY, DWORD, LPWSTR, LPDWORD, LPDWORD, LPVOID, LPDWORD); DWORD SHGetValueA(HKEY, LPCSTR, LPCSTR, LPDWORD, LPVOID, LPDWORD); DWORD SHGetValueW(HKEY, LPCWSTR, LPCWSTR, LPDWORD, LPVOID, LPDWORD); DWORD SHSetValueA(HKEY, LPCSTR, LPCSTR, DWORD, LPCVOID, DWORD); DWORD SHSetValueW(HKEY, LPCWSTR, LPCWSTR, DWORD, LPCVOID, DWORD); DWORD SHDeleteValueA(HKEY, LPCSTR, LPCSTR); DWORD SHDeleteValueW(HKEY, LPCWSTR, LPCWSTR); HRESULT AssocCreate(CLSID, const(IID)* , const(LPVOID)*); HRESULT AssocQueryKeyA(ASSOCF, ASSOCKEY, LPCSTR, LPCSTR, HKEY*); HRESULT AssocQueryKeyW(ASSOCF, ASSOCKEY, LPCWSTR, LPCWSTR, HKEY*); HRESULT AssocQueryStringA(ASSOCF, ASSOCSTR, LPCSTR, LPCSTR, LPSTR, DWORD*); HRESULT AssocQueryStringByKeyA(ASSOCF, ASSOCSTR, HKEY, LPCSTR, LPSTR, DWORD*); HRESULT AssocQueryStringByKeyW(ASSOCF, ASSOCSTR, HKEY, LPCWSTR, LPWSTR, DWORD*); HRESULT AssocQueryStringW(ASSOCF, ASSOCSTR, LPCWSTR, LPCWSTR, LPWSTR, DWORD*); HRESULT UrlApplySchemeA(LPCSTR, LPSTR, LPDWORD, DWORD); HRESULT UrlApplySchemeW(LPCWSTR, LPWSTR, LPDWORD, DWORD); HRESULT UrlCanonicalizeA(LPCSTR, LPSTR, LPDWORD, DWORD); HRESULT UrlCanonicalizeW(LPCWSTR, LPWSTR, LPDWORD, DWORD); HRESULT UrlCombineA(LPCSTR, LPCSTR, LPSTR, LPDWORD, DWORD); HRESULT UrlCombineW(LPCWSTR, LPCWSTR, LPWSTR, LPDWORD, DWORD); int UrlCompareA(LPCSTR, LPCSTR, BOOL); int UrlCompareW(LPCWSTR, LPCWSTR, BOOL); HRESULT UrlCreateFromPathA(LPCSTR, LPSTR, LPDWORD, DWORD); HRESULT UrlCreateFromPathW(LPCWSTR, LPWSTR, LPDWORD, DWORD); HRESULT UrlEscapeA(LPCSTR, LPSTR, LPDWORD, DWORD); HRESULT UrlEscapeW(LPCWSTR, LPWSTR, LPDWORD, DWORD); LPCSTR UrlGetLocationA(LPCSTR); LPCWSTR UrlGetLocationW(LPCWSTR); HRESULT UrlGetPartA(LPCSTR, LPSTR, LPDWORD, DWORD, DWORD); HRESULT UrlGetPartW(LPCWSTR, LPWSTR, LPDWORD, DWORD, DWORD); HRESULT UrlHashA(LPCSTR, LPBYTE, DWORD); HRESULT UrlHashW(LPCWSTR, LPBYTE, DWORD); BOOL UrlIsA(LPCSTR, URLIS); BOOL UrlIsW(LPCWSTR, URLIS); BOOL UrlIsNoHistoryA(LPCSTR); BOOL UrlIsNoHistoryW(LPCWSTR); BOOL UrlIsOpaqueA(LPCSTR); BOOL UrlIsOpaqueW(LPCWSTR); HRESULT UrlUnescapeA(LPSTR, LPSTR, LPDWORD, DWORD); HRESULT UrlUnescapeW(LPWSTR, LPWSTR, LPDWORD, DWORD); DWORD SHRegCloseUSKey(HUSKEY); LONG SHRegCreateUSKeyA(LPCSTR, REGSAM, HUSKEY, PHUSKEY, DWORD); LONG SHRegCreateUSKeyW(LPCWSTR, REGSAM, HUSKEY, PHUSKEY, DWORD); LONG SHRegDeleteEmptyUSKeyA(HUSKEY, LPCSTR, SHREGDEL_FLAGS); LONG SHRegDeleteEmptyUSKeyW(HUSKEY, LPCWSTR, SHREGDEL_FLAGS); LONG SHRegDeleteUSValueA(HUSKEY, LPCSTR, SHREGDEL_FLAGS); LONG SHRegDeleteUSValueW(HUSKEY, LPCWSTR, SHREGDEL_FLAGS); HKEY SHRegDuplicateHKey(HKEY); DWORD SHRegEnumUSKeyA(HUSKEY, DWORD, LPSTR, LPDWORD, SHREGENUM_FLAGS); DWORD SHRegEnumUSKeyW(HUSKEY, DWORD, LPWSTR, LPDWORD, SHREGENUM_FLAGS); DWORD SHRegEnumUSValueA(HUSKEY, DWORD, LPSTR, LPDWORD, LPDWORD, LPVOID, LPDWORD, SHREGENUM_FLAGS); DWORD SHRegEnumUSValueW(HUSKEY, DWORD, LPWSTR, LPDWORD, LPDWORD, LPVOID, LPDWORD, SHREGENUM_FLAGS); BOOL SHRegGetBoolUSValueA(LPCSTR, LPCSTR, BOOL, BOOL); BOOL SHRegGetBoolUSValueW(LPCWSTR, LPCWSTR, BOOL, BOOL); DWORD SHRegGetPathA(HKEY, LPCSTR, LPCSTR, LPSTR, DWORD); DWORD SHRegGetPathW(HKEY, LPCWSTR, LPCWSTR, LPWSTR, DWORD); LONG SHRegGetUSValueA(LPCSTR, LPCSTR, LPDWORD, LPVOID, LPDWORD, BOOL, LPVOID, DWORD); LONG SHRegGetUSValueW(LPCWSTR, LPCWSTR, LPDWORD, LPVOID, LPDWORD, BOOL, LPVOID, DWORD); LONG SHRegOpenUSKeyA(LPCSTR, REGSAM, HUSKEY, PHUSKEY, BOOL); LONG SHRegOpenUSKeyW(LPCWSTR, REGSAM, HUSKEY, PHUSKEY, BOOL); DWORD SHRegQueryInfoUSKeyA(HUSKEY, LPDWORD, LPDWORD, LPDWORD, LPDWORD, SHREGENUM_FLAGS); DWORD SHRegQueryInfoUSKeyW(HUSKEY, LPDWORD, LPDWORD, LPDWORD, LPDWORD, SHREGENUM_FLAGS); LONG SHRegQueryUSValueA(HUSKEY, LPCSTR, LPDWORD, LPVOID, LPDWORD, BOOL, LPVOID, DWORD); LONG SHRegQueryUSValueW(HUSKEY, LPCWSTR, LPDWORD, LPVOID, LPDWORD, BOOL, LPVOID, DWORD); DWORD SHRegSetPathA(HKEY, LPCSTR, LPCSTR, LPCSTR, DWORD); DWORD SHRegSetPathW(HKEY, LPCWSTR, LPCWSTR, LPCWSTR, DWORD); LONG SHRegSetUSValueA(LPCSTR, LPCSTR, DWORD, LPVOID, DWORD, DWORD); LONG SHRegSetUSValueW(LPCWSTR, LPCWSTR, DWORD, LPVOID, DWORD, DWORD); LONG SHRegWriteUSValueA(HUSKEY, LPCSTR, DWORD, LPVOID, DWORD, DWORD); LONG SHRegWriteUSValueW(HUSKEY, LPCWSTR, DWORD, LPVOID, DWORD, DWORD); HRESULT HashData(LPBYTE, DWORD, LPBYTE, DWORD); HPALETTE SHCreateShellPalette(HDC); COLORREF ColorHLSToRGB(WORD, WORD, WORD); COLORREF ColorAdjustLuma(COLORREF, int, BOOL); void ColorRGBToHLS(COLORREF, WORD*, WORD*, WORD*); /** Should not be necessary for D? extern (C): int wnsprintfA(LPSTR, int, LPCSTR, ...); int wnsprintfW(LPWSTR, int, LPCWSTR, ...); extern (Windows): int wvnsprintfA(LPSTR, int, LPCSTR, va_list); int wvnsprintfW(LPWSTR, int, LPCWSTR, va_list); */ HINSTANCE MLLoadLibraryA(LPCSTR, HANDLE, DWORD, LPCSTR, BOOL); HINSTANCE MLLoadLibraryW(LPCWSTR, HANDLE, DWORD, LPCWSTR, BOOL); HRESULT DllInstall(BOOL, LPCWSTR); HRESULT StrRetToBufA(LPSTRRET, LPCITEMIDLIST, LPSTR, UINT); HRESULT StrRetToBufW(LPSTRRET, LPCITEMIDLIST, LPWSTR, UINT); HRESULT StrRetToStrA(LPSTRRET, LPCITEMIDLIST, LPSTR*); HRESULT StrRetToStrW(LPSTRRET, LPCITEMIDLIST, LPWSTR*); HRESULT SHCreateStreamOnFileA(LPCSTR, DWORD, IStream*); HRESULT SHCreateStreamOnFileW(LPCWSTR, DWORD, IStream*); IStream SHOpenRegStream2A(HKEY, LPCSTR, LPCSTR, DWORD); IStream SHOpenRegStream2W(HKEY, LPCWSTR, LPCWSTR, DWORD); IStream SHOpenRegStreamA(HKEY, LPCSTR, LPCSTR, DWORD); IStream SHOpenRegStreamW(HKEY, LPCWSTR, LPCWSTR, DWORD); version(Unicode) { alias ChrCmpIW ChrCmpI; alias IntlStrEqNW IntlStrEqN; alias IntlStrEqNIW IntlStrEqNI; alias IntlStrEqWorkerW IntlStrEqWorker; alias SHStrDupW SHStrDup; alias StrCatW StrCat; alias StrCatBuffW StrCatBuff; alias StrChrW StrChr; alias StrChrIW StrChrI; alias StrCmpW StrCmp; alias StrCmpIW StrCmpI; alias StrCmpNIW StrCmpNI; alias StrCmpNW StrCmpN; alias StrCpyNW StrCpyN; alias StrCpyW StrCpy; alias StrCSpnIW StrCSpnI; alias StrCSpnW StrCSpn; alias StrDupW StrDup; alias StrFormatByteSizeW StrFormatByteSize; alias StrFormatKBSizeW StrFormatKBSize; alias StrFromTimeIntervalW StrFromTimeInterval; alias StrIsIntlEqualW StrIsIntlEqual; alias StrNCatW StrNCat; alias StrPBrkW StrPBrk; alias StrRChrW StrRChr; alias StrRChrIW StrRChrI; alias StrRetToBufW StrRetToBuf; alias StrRetToStrW StrRetToStr; alias StrRStrIW StrRStrI; alias StrSpnW StrSpn; alias StrStrIW StrStrI; alias StrStrW StrStr; alias StrToIntW StrToInt; alias StrToIntExW StrToIntEx; alias StrTrimW StrTrim; alias PathAddBackslashW PathAddBackslash; alias PathAddExtensionW PathAddExtension; alias PathAppendW PathAppend; alias PathBuildRootW PathBuildRoot; alias PathCanonicalizeW PathCanonicalize; alias PathCombineW PathCombine; alias PathCommonPrefixW PathCommonPrefix; alias PathCompactPathW PathCompactPath; alias PathCompactPathExW PathCompactPathEx; alias PathCreateFromUrlW PathCreateFromUrl; alias PathFileExistsW PathFileExists; alias PathFindExtensionW PathFindExtension; alias PathFindFileNameW PathFindFileName; alias PathFindNextComponentW PathFindNextComponent; alias PathFindOnPathW PathFindOnPath; alias PathFindSuffixArrayW PathFindSuffixArray; alias PathGetArgsW PathGetArgs; alias PathGetCharTypeW PathGetCharType; alias PathGetDriveNumberW PathGetDriveNumber; alias PathIsContentTypeW PathIsContentType; alias PathIsDirectoryEmptyW PathIsDirectoryEmpty; alias PathIsDirectoryW PathIsDirectory; alias PathIsFileSpecW PathIsFileSpec; alias PathIsLFNFileSpecW PathIsLFNFileSpec; alias PathIsNetworkPathW PathIsNetworkPath; alias PathIsPrefixW PathIsPrefix; alias PathIsRelativeW PathIsRelative; alias PathIsRootW PathIsRoot; alias PathIsSameRootW PathIsSameRoot; alias PathIsSystemFolderW PathIsSystemFolder; alias PathIsUNCServerShareW PathIsUNCServerShare; alias PathIsUNCServerW PathIsUNCServer; alias PathIsUNCW PathIsUNC; alias PathIsURLW PathIsURL; alias PathMakePrettyW PathMakePretty; alias PathMakeSystemFolderW PathMakeSystemFolder; alias PathMatchSpecW PathMatchSpec; alias PathParseIconLocationW PathParseIconLocation; alias PathQuoteSpacesW PathQuoteSpaces; alias PathRelativePathToW PathRelativePathTo; alias PathRemoveArgsW PathRemoveArgs; alias PathRemoveBackslashW PathRemoveBackslash; alias PathRemoveBlanksW PathRemoveBlanks; alias PathRemoveExtensionW PathRemoveExtension; alias PathRemoveFileSpecW PathRemoveFileSpec; alias PathRenameExtensionW PathRenameExtension; alias PathSearchAndQualifyW PathSearchAndQualify; alias PathSetDlgItemPathW PathSetDlgItemPath; alias PathSkipRootW PathSkipRoot; alias PathStripPathW PathStripPath; alias PathStripToRootW PathStripToRoot; alias PathUndecorateW PathUndecorate; alias PathUnExpandEnvStringsW PathUnExpandEnvStrings; alias PathUnmakeSystemFolderW PathUnmakeSystemFolder; alias PathUnquoteSpacesW PathUnquoteSpaces; alias SHCreateStreamOnFileW SHCreateStreamOnFile; alias SHOpenRegStreamW SHOpenRegStream; alias SHOpenRegStream2W SHOpenRegStream2; alias SHCopyKeyW SHCopyKey; alias SHDeleteEmptyKeyW SHDeleteEmptyKey; alias SHDeleteKeyW SHDeleteKey; alias SHEnumKeyExW SHEnumKeyEx; alias SHQueryInfoKeyW SHQueryInfoKey; alias SHQueryValueExW SHQueryValueEx; alias SHEnumValueW SHEnumValue; alias SHGetValueW SHGetValue; alias SHSetValueW SHSetValue; alias SHDeleteValueW SHDeleteValue; alias AssocQueryKeyW AssocQueryKey; alias AssocQueryStringByKeyW AssocQueryStringByKey; alias AssocQueryStringW AssocQueryString; alias UrlApplySchemeW UrlApplyScheme; alias UrlCanonicalizeW UrlCanonicalize; alias UrlCombineW UrlCombine; alias UrlCompareW UrlCompare; alias UrlCreateFromPathW UrlCreateFromPath; alias UrlEscapeW UrlEscape; alias UrlGetLocationW UrlGetLocation; alias UrlGetPartW UrlGetPart; alias UrlHashW UrlHash; alias UrlIsW UrlIs; alias UrlIsFileUrlW UrlIsFileUrl; alias UrlIsNoHistoryW UrlIsNoHistory; alias UrlIsOpaqueW UrlIsOpaque; alias UrlUnescapeW UrlUnescape; alias UrlUnescapeInPlaceW UrlUnescapeInPlace; alias SHRegCreateUSKeyW SHRegCreateUSKey; alias SHRegDeleteEmptyUSKeyW SHRegDeleteEmptyUSKey; alias SHRegDeleteUSValueW SHRegDeleteUSValue; alias SHRegEnumUSKeyW SHRegEnumUSKey; alias SHRegEnumUSValueW SHRegEnumUSValue; alias SHRegGetBoolUSValueW SHRegGetBoolUSValue; alias SHRegGetPathW SHRegGetPath; alias SHRegGetUSValueW SHRegGetUSValue; alias SHRegOpenUSKeyW SHRegOpenUSKey; alias SHRegQueryInfoUSKeyW SHRegQueryInfoUSKey; alias SHRegQueryUSValueW SHRegQueryUSValue; alias SHRegSetPathW SHRegSetPath; alias SHRegSetUSValueW SHRegSetUSValue; alias SHRegWriteUSValueW SHRegWriteUSValue; //alias wnsprintfW wnsprintf; //alias wvnsprintfW wvnsprintf; } else { alias ChrCmpIA ChrCmpI; alias IntlStrEqNA IntlStrEqN; alias IntlStrEqNIA IntlStrEqNI; alias IntlStrEqWorkerA IntlStrEqWorker; alias SHStrDupA SHStrDup; alias StrCatBuffA StrCatBuff; alias StrChrA StrChr; alias StrChrIA StrChrI; alias StrCmpNIA StrCmpNI; alias StrCmpNA StrCmpN; alias StrCSpnIA StrCSpnI; alias StrCSpnA StrCSpn; alias StrDupA StrDup; alias StrFormatByteSizeA StrFormatByteSize; alias StrFormatKBSizeA StrFormatKBSize; alias StrFromTimeIntervalA StrFromTimeInterval; alias StrIsIntlEqualA StrIsIntlEqual; alias StrNCatA StrNCat; alias StrPBrkA StrPBrk; alias StrRChrA StrRChr; alias StrRChrIA StrRChrI; alias StrRetToBufA StrRetToBuf; alias StrRetToStrA StrRetToStr; alias StrRStrIA StrRStrI; alias StrSpnA StrSpn; alias StrStrIA StrStrI; alias StrStrA StrStr; alias StrToIntA StrToInt; alias StrToIntExA StrToIntEx; alias StrTrimA StrTrim; alias PathAddBackslashA PathAddBackslash; alias PathAddExtensionA PathAddExtension; alias PathAppendA PathAppend; alias PathBuildRootA PathBuildRoot; alias PathCanonicalizeA PathCanonicalize; alias PathCombineA PathCombine; alias PathCommonPrefixA PathCommonPrefix; alias PathCompactPathA PathCompactPath; alias PathCompactPathExA PathCompactPathEx; alias PathCreateFromUrlA PathCreateFromUrl; alias PathFileExistsA PathFileExists; alias PathFindExtensionA PathFindExtension; alias PathFindFileNameA PathFindFileName; alias PathFindNextComponentA PathFindNextComponent; alias PathFindOnPathA PathFindOnPath; alias PathFindSuffixArrayA PathFindSuffixArray; alias PathGetArgsA PathGetArgs; alias PathGetCharTypeA PathGetCharType; alias PathGetDriveNumberA PathGetDriveNumber; alias PathIsContentTypeA PathIsContentType; alias PathIsDirectoryEmptyA PathIsDirectoryEmpty; alias PathIsDirectoryA PathIsDirectory; alias PathIsFileSpecA PathIsFileSpec; alias PathIsLFNFileSpecA PathIsLFNFileSpec; alias PathIsNetworkPathA PathIsNetworkPath; alias PathIsPrefixA PathIsPrefix; alias PathIsRelativeA PathIsRelative; alias PathIsRootA PathIsRoot; alias PathIsSameRootA PathIsSameRoot; alias PathIsSystemFolderA PathIsSystemFolder; alias PathIsUNCServerShareA PathIsUNCServerShare; alias PathIsUNCServerA PathIsUNCServer; alias PathIsUNCA PathIsUNC; alias PathIsURLA PathIsURL; alias PathMakePrettyA PathMakePretty; alias PathMakeSystemFolderA PathMakeSystemFolder; alias PathMatchSpecA PathMatchSpec; alias PathParseIconLocationA PathParseIconLocation; alias PathQuoteSpacesA PathQuoteSpaces; alias PathRelativePathToA PathRelativePathTo; alias PathRemoveArgsA PathRemoveArgs; alias PathRemoveBackslashA PathRemoveBackslash; alias PathRemoveBlanksA PathRemoveBlanks; alias PathRemoveExtensionA PathRemoveExtension; alias PathRemoveFileSpecA PathRemoveFileSpec; alias PathRenameExtensionA PathRenameExtension; alias PathSearchAndQualifyA PathSearchAndQualify; alias PathSetDlgItemPathA PathSetDlgItemPath; alias PathSkipRootA PathSkipRoot; alias PathStripPathA PathStripPath; alias PathStripToRootA PathStripToRoot; alias PathUndecorateA PathUndecorate; alias PathUnExpandEnvStringsA PathUnExpandEnvStrings; alias PathUnmakeSystemFolderA PathUnmakeSystemFolder; alias PathUnquoteSpacesA PathUnquoteSpaces; alias SHCreateStreamOnFileA SHCreateStreamOnFile; alias SHOpenRegStreamA SHOpenRegStream; alias SHOpenRegStream2A SHOpenRegStream2; alias SHCopyKeyA SHCopyKey; alias SHDeleteEmptyKeyA SHDeleteEmptyKey; alias SHDeleteKeyA SHDeleteKey; alias SHEnumKeyExA SHEnumKeyEx; alias SHQueryInfoKeyA SHQueryInfoKey; alias SHQueryValueExA SHQueryValueEx; alias SHEnumValueA SHEnumValue; alias SHGetValueA SHGetValue; alias SHSetValueA SHSetValue; alias SHDeleteValueA SHDeleteValue; alias AssocQueryKeyA AssocQueryKey; alias AssocQueryStringByKeyA AssocQueryStringByKey; alias AssocQueryStringA AssocQueryString; alias UrlApplySchemeA UrlApplyScheme; alias UrlCanonicalizeA UrlCanonicalize; alias UrlCombineA UrlCombine; alias UrlCompareA UrlCompare; alias UrlCreateFromPathA UrlCreateFromPath; alias UrlEscapeA UrlEscape; alias UrlGetLocationA UrlGetLocation; alias UrlGetPartA UrlGetPart; alias UrlHashA UrlHash; alias UrlIsA UrlIs; alias UrlIsNoHistoryA UrlIsNoHistory; alias UrlIsOpaqueA UrlIsOpaque; alias UrlUnescapeA UrlUnescape; alias UrlUnescapeInPlaceA UrlUnescapeInPlace; alias SHRegCreateUSKeyA SHRegCreateUSKey; alias SHRegDeleteEmptyUSKeyA SHRegDeleteEmptyUSKey; alias SHRegDeleteUSValueA SHRegDeleteUSValue; alias SHRegEnumUSKeyA SHRegEnumUSKey; alias SHRegEnumUSValueA SHRegEnumUSValue; alias SHRegGetBoolUSValueA SHRegGetBoolUSValue; alias SHRegGetPathA SHRegGetPath; alias SHRegGetUSValueA SHRegGetUSValue; alias SHRegOpenUSKeyA SHRegOpenUSKey; alias SHRegQueryInfoUSKeyA SHRegQueryInfoUSKey; alias SHRegQueryUSValueA SHRegQueryUSValue; alias SHRegSetPathA SHRegSetPath; alias SHRegSetUSValueA SHRegSetUSValue; alias SHRegWriteUSValueA SHRegWriteUSValue; //alias wnsprintfA wnsprintf; //alias wvnsprintfA wvnsprintf; } alias StrToInt StrToLong; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmrepl.d0000664000175000017500000000760412776214756023161 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmrepl.d) */ module core.sys.windows.lmrepl; version (Windows): pragma(lib, "netapi32"); private import core.sys.windows.lmcons, core.sys.windows.windef; enum REPL_ROLE_EXPORT=1; enum REPL_ROLE_IMPORT=2; enum REPL_ROLE_BOTH=3; enum REPL_INTERVAL_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+0; enum REPL_PULSE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+1; enum REPL_GUARDTIME_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+2; enum REPL_RANDOM_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+3; enum REPL_UNLOCK_NOFORCE=0; enum REPL_UNLOCK_FORCE=1; enum REPL_STATE_OK=0; enum REPL_STATE_NO_MASTER=1; enum REPL_STATE_NO_SYNC=2; enum REPL_STATE_NEVER_REPLICATED=3; enum REPL_INTEGRITY_FILE=1; enum REPL_INTEGRITY_TREE=2; enum REPL_EXTENT_FILE=1; enum REPL_EXTENT_TREE=2; enum REPL_EXPORT_INTEGRITY_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+0; enum REPL_EXPORT_EXTENT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+1; struct REPL_INFO_0 { DWORD rp0_role; LPWSTR rp0_exportpath; LPWSTR rp0_exportlist; LPWSTR rp0_importpath; LPWSTR rp0_importlist; LPWSTR rp0_logonusername; DWORD rp0_interval; DWORD rp0_pulse; DWORD rp0_guardtime; DWORD rp0_random; } alias REPL_INFO_0* PREPL_INFO_0, LPREPL_INFO_0; struct REPL_INFO_1000 { DWORD rp1000_interval; } alias REPL_INFO_1000* PREPL_INFO_1000, LPREPL_INFO_1000; struct REPL_INFO_1001 { DWORD rp1001_pulse; } alias REPL_INFO_1001* PREPL_INFO_1001, LPREPL_INFO_1001; struct REPL_INFO_1002 { DWORD rp1002_guardtime; } alias REPL_INFO_1002* PREPL_INFO_1002, LPREPL_INFO_1002; struct REPL_INFO_1003 { DWORD rp1003_random; } alias REPL_INFO_1003* PREPL_INFO_1003, LPREPL_INFO_1003; struct REPL_EDIR_INFO_0 { LPWSTR rped0_dirname; } alias REPL_EDIR_INFO_0* PREPL_EDIR_INFO_0, LPREPL_EDIR_INFO_0; struct REPL_EDIR_INFO_1 { LPWSTR rped1_dirname; DWORD rped1_integrity; DWORD rped1_extent; } alias REPL_EDIR_INFO_1* PREPL_EDIR_INFO_1, LPREPL_EDIR_INFO_1; struct REPL_EDIR_INFO_2 { LPWSTR rped2_dirname; DWORD rped2_integrity; DWORD rped2_extent; DWORD rped2_lockcount; DWORD rped2_locktime; } alias REPL_EDIR_INFO_2* PREPL_EDIR_INFO_2, LPREPL_EDIR_INFO_2; struct REPL_EDIR_INFO_1000 { DWORD rped1000_integrity; } alias REPL_EDIR_INFO_1000* PREPL_EDIR_INFO_1000, LPREPL_EDIR_INFO_1000; struct REPL_EDIR_INFO_1001 { DWORD rped1001_extent; } alias REPL_EDIR_INFO_1001* PREPL_EDIR_INFO_1001, LPREPL_EDIR_INFO_1001; struct REPL_IDIR_INFO_0 { LPWSTR rpid0_dirname; } alias REPL_IDIR_INFO_0* PREPL_IDIR_INFO_0, LPREPL_IDIR_INFO_0; struct REPL_IDIR_INFO_1 { LPWSTR rpid1_dirname; DWORD rpid1_state; LPWSTR rpid1_mastername; DWORD rpid1_last_update_time; DWORD rpid1_lockcount; DWORD rpid1_locktime; } alias REPL_IDIR_INFO_1* PREPL_IDIR_INFO_1, LPREPL_IDIR_INFO_1; extern (Windows) { NET_API_STATUS NetReplGetInfo(LPCWSTR,DWORD,PBYTE*); NET_API_STATUS NetReplSetInfo(LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetReplExportDirAdd(LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetReplExportDirDel(LPCWSTR,LPCWSTR); NET_API_STATUS NetReplExportDirEnum(LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetReplExportDirGetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE*); NET_API_STATUS NetReplExportDirSetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetReplExportDirLock(LPCWSTR,LPCWSTR); NET_API_STATUS NetReplExportDirUnlock(LPCWSTR,LPCWSTR,DWORD); NET_API_STATUS NetReplImportDirAdd(LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetReplImportDirDel(LPCWSTR,LPCWSTR); NET_API_STATUS NetReplImportDirEnum(LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetReplImportDirGetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE*); NET_API_STATUS NetReplImportDirLock(LPCWSTR,LPCWSTR); NET_API_STATUS NetReplImportDirUnlock(LPCWSTR,LPCWSTR,DWORD); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/snmp.d0000664000175000017500000002103212776214756022632 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_snmp.d) */ module core.sys.windows.snmp; version (Windows): private import core.sys.windows.windows; // These are not documented on MSDN enum { DEFAULT_SNMP_PORT_UDP = 161, DEFAULT_SNMP_PORT_IPX = 36879, DEFAULT_SNMPTRAP_PORT_UDP = 162, DEFAULT_SNMPTRAP_PORT_IPX = 36880 } enum : BYTE { ASN_UNIVERSAL = 0x00, ASN_PRIMITIVE = 0x00, ASN_CONSTRUCTOR = 0x20, ASN_APPLICATION = 0x40, ASN_CONTEXT = 0x80, ASN_PRIVATE = 0xC0, SNMP_PDU_GET = ASN_CONTEXT | ASN_CONSTRUCTOR, SNMP_PDU_GETNEXT, SNMP_PDU_RESPONSE, SNMP_PDU_SET, SNMP_PDU_GETBULK, // = ASN_CONTEXT | ASN_CONSTRUCTOR | 4 SNMP_PDU_V1TRAP = ASN_CONTEXT | ASN_CONSTRUCTOR | 4, SNMP_PDU_INFORM = ASN_CONTEXT | ASN_CONSTRUCTOR | 6, SNMP_PDU_TRAP, SNMP_PDU_REPORT, ASN_INTEGER = ASN_UNIVERSAL | ASN_PRIMITIVE | 2, ASN_BITS, ASN_OCTETSTRING, ASN_NULL, ASN_OBJECTIDENTIFIER, // = ASN_UNIVERSAL | ASN_PRIMITIVE | 6 ASN_INTEGER32 = ASN_INTEGER, ASN_SEQUENCE = ASN_UNIVERSAL | ASN_CONSTRUCTOR | 0x10, ASN_SEQUENCEOF = ASN_SEQUENCE, ASN_IPADDRESS = ASN_APPLICATION | ASN_PRIMITIVE, ASN_COUNTER32, ASN_GAUGE32, ASN_TIMETICKS, ASN_OPAQUE, // = ASN_APPLICATION | ASN_PRIMITIVE | 4 ASN_COUNTER64 = ASN_APPLICATION | ASN_PRIMITIVE | 6, ASN_UNSIGNED32, // = ASN_APPLICATION | ASN_PRIMITIVE | 7 SNMP_EXCEPTION_NOSUCHOBJECT = ASN_CONTEXT | ASN_PRIMITIVE, SNMP_EXCEPTION_NOSUCHINSTANCE, SNMP_EXCEPTION_ENDOFMIBVIEW, SNMP_EXTENSION_GET = SNMP_PDU_GET, SNMP_EXTENSION_GET_NEXT = SNMP_PDU_GETNEXT, SNMP_EXTENSION_GET_BULK = SNMP_PDU_GETBULK, SNMP_EXTENSION_SET_TEST = ASN_PRIVATE | ASN_CONSTRUCTOR, SNMP_EXTENSION_SET_COMMIT = SNMP_PDU_SET, SNMP_EXTENSION_SET_UNDO = ASN_PRIVATE | ASN_CONSTRUCTOR | 1, SNMP_EXTENSION_SET_CLEANUP } enum : AsnInteger { SNMP_ERRORSTATUS_NOERROR, SNMP_ERRORSTATUS_TOOBIG, SNMP_ERRORSTATUS_NOSUCHNAME, SNMP_ERRORSTATUS_BADVALUE, SNMP_ERRORSTATUS_READONLY, SNMP_ERRORSTATUS_GENERR, SNMP_ERRORSTATUS_NOACCESS, SNMP_ERRORSTATUS_WRONGTYPE, SNMP_ERRORSTATUS_WRONGLENGTH, SNMP_ERRORSTATUS_WRONGENCODING, SNMP_ERRORSTATUS_WRONGVALUE, SNMP_ERRORSTATUS_NOCREATION, SNMP_ERRORSTATUS_INCONSISTENTVALUE, SNMP_ERRORSTATUS_RESOURCEUNAVAILABLE, SNMP_ERRORSTATUS_COMMITFAILED, SNMP_ERRORSTATUS_UNDOFAILED, SNMP_ERRORSTATUS_AUTHORIZATIONERROR, SNMP_ERRORSTATUS_NOTWRITABLE, SNMP_ERRORSTATUS_INCONSISTENTNAME } enum : AsnInteger { SNMP_GENERICTRAP_COLDSTART, SNMP_GENERICTRAP_WARMSTART, SNMP_GENERICTRAP_LINKDOWN, SNMP_GENERICTRAP_LINKUP, SNMP_GENERICTRAP_AUTHFAILURE, SNMP_GENERICTRAP_EGPNEIGHLOSS, SNMP_GENERICTRAP_ENTERSPECIFIC } // These are not documented on MSDN enum { SNMP_ACCESS_NONE, SNMP_ACCESS_NOTIFY, SNMP_ACCESS_READ_ONLY, SNMP_ACCESS_READ_WRITE, SNMP_ACCESS_READ_CREATE } enum : BOOL { SNMPAPI_ERROR = false, SNMPAPI_NOERROR = true } enum : INT { SNMP_LOG_SILENT, SNMP_LOG_FATAL, SNMP_LOG_ERROR, SNMP_LOG_WARNING, SNMP_LOG_TRACE, SNMP_LOG_VERBOSE } enum INT SNMP_OUTPUT_TO_CONSOLE = 1, SNMP_OUTPUT_TO_LOGFILE = 2, SNMP_OUTPUT_TO_EVENTLOG = 4, SNMP_OUTPUT_TO_DEBUGGER = 8; enum size_t SNMP_MAX_OID_LEN = 128; enum : DWORD { SNMP_MEM_ALLOC_ERROR = 1, SNMP_BERAPI_INVALID_LENGTH = 10, SNMP_BERAPI_INVALID_TAG, SNMP_BERAPI_OVERFLOW, SNMP_BERAPI_SHORT_BUFFER, SNMP_BERAPI_INVALID_OBJELEM, SNMP_PDUAPI_UNRECOGNIZED_PDU = 20, SNMP_PDUAPI_INVALID_ES, SNMP_PDUAPI_INVALID_GT, SNMP_AUTHAPI_INVALID_VERSION = 30, SNMP_AUTHAPI_INVALID_MSG_TYPE, SNMP_AUTHAPI_TRIV_AUTH_FAILED, } alias INT SNMPAPI; alias LONG AsnInteger32; alias ULONG AsnUnsigned32, AsnCounter32, AsnGauge32, AsnTimeticks; alias ULARGE_INTEGER AsnCounter64; align (4): struct AsnOctetString { BYTE* stream; UINT length; BOOL dynamic; } alias AsnOctetString AsnBits, AsnSequence, AsnImplicitSequence, AsnIPAddress, AsnNetworkAddress, AsnDisplayString, AsnOpaque; struct AsnObjectIdentifier { UINT idLength; UINT* ids; } alias AsnObjectIdentifier AsnObjectName; struct AsnAny { BYTE asnType; union _asnValue { AsnInteger32 number; AsnUnsigned32 unsigned32; AsnCounter64 counter64; AsnOctetString string; AsnBits bits; AsnObjectIdentifier object; AsnSequence sequence; AsnIPAddress address; AsnCounter32 counter; AsnGauge32 gauge; AsnTimeticks ticks; AsnOpaque arbitrary; } _asnValue asnValue; } alias AsnAny AsnObjectSyntax; struct SnmpVarBind { AsnObjectName name; AsnObjectSyntax value; } struct SnmpVarBindList { SnmpVarBind* list; UINT len; } extern (Windows) { VOID SnmpExtensionClose(); BOOL SnmpExtensionInit(DWORD, HANDLE*, AsnObjectIdentifier*); BOOL SnmpExtensionInitEx(AsnObjectIdentifier*); BOOL SnmpExtensionMonitor(LPVOID); BOOL SnmpExtensionQuery(BYTE, SnmpVarBindList*, AsnInteger32*, AsnInteger32*); BOOL SnmpExtensionQueryEx(DWORD, DWORD, SnmpVarBindList*, AsnOctetString*, AsnInteger32*, AsnInteger32*); BOOL SnmpExtensionTrap(AsnObjectIdentifier*, AsnInteger32*, AsnInteger32*, AsnTimeticks*, SnmpVarBindList*); DWORD SnmpSvcGetUptime(); VOID SnmpSvcSetLogLevel(INT); VOID SnmpSvcSetLogType(INT); SNMPAPI SnmpUtilAsnAnyCpy(AsnAny*, AsnAny*); VOID SnmpUtilAsnAnyFree(AsnAny*); VOID SnmpUtilDbgPrint(INT, LPSTR, ...); LPSTR SnmpUtilIdsToA(UINT*, UINT); LPVOID SnmpUtilMemAlloc(UINT); VOID SnmpUtilMemFree(LPVOID); LPVOID SnmpUtilMemReAlloc(LPVOID, UINT); SNMPAPI SnmpUtilOctetsCmp(AsnOctetString*, AsnOctetString*); SNMPAPI SnmpUtilOctetsCpy(AsnOctetString*, AsnOctetString*); VOID SnmpUtilOctetsFree(AsnOctetString*); SNMPAPI SnmpUtilOctetsNCmp(AsnOctetString*, AsnOctetString*, UINT); SNMPAPI SnmpUtilOidAppend(AsnObjectIdentifier*, AsnObjectIdentifier*); SNMPAPI SnmpUtilOidCmp(AsnObjectIdentifier*, AsnObjectIdentifier*); SNMPAPI SnmpUtilOidCpy(AsnObjectIdentifier*, AsnObjectIdentifier*); VOID SnmpUtilOidFree(AsnObjectIdentifier*); SNMPAPI SnmpUtilOidNCmp(AsnObjectIdentifier*, AsnObjectIdentifier*, UINT); LPSTR SnmpUtilOidToA(AsnObjectIdentifier*); VOID SnmpUtilPrintAsnAny(AsnAny*); VOID SnmpUtilPrintOid(AsnObjectIdentifier*); SNMPAPI SnmpUtilVarBindCpy(SnmpVarBind*, SnmpVarBind*); SNMPAPI SnmpUtilVarBindListCpy(SnmpVarBindList*, SnmpVarBindList*); VOID SnmpUtilVarBindFree(SnmpVarBind*); VOID SnmpUtilVarBindListFree(SnmpVarBindList*); } alias SnmpUtilMemAlloc SNMP_malloc; alias SnmpUtilMemFree SNMP_free; alias SnmpUtilMemReAlloc SNMP_realloc; alias SnmpUtilMemAlloc SNMP_DBG_malloc; alias SnmpUtilMemFree SNMP_DBG_free; alias SnmpUtilMemReAlloc SNMP_DBG_realloc; alias SnmpUtilOidAppend SNMP_oidappend; alias SnmpUtilOidCmp SNMP_oidcmp; alias SnmpUtilOidCpy SNMP_oidcpy; alias SnmpUtilOidFree SNMP_oidfree; alias SnmpUtilOidNCmp SNMP_oidncmp; alias SnmpUtilPrintAsnAny SNMP_printany; alias SnmpUtilVarBindCpy SNMP_CopyVarBind; alias SnmpUtilVarBindListCpy SNMP_CopyVarBindList; alias SnmpUtilVarBindFree SNMP_FreeVarBind; alias SnmpUtilVarBindListFree SNMP_FreeVarBindList; alias ASN_IPADDRESS ASN_RFC1155_IPADDRESS; alias ASN_COUNTER32 ASN_RFC1155_COUNTER; alias ASN_GAUGE32 ASN_RFC1155_GAUGE; alias ASN_TIMETICKS ASN_RFC1155_TIMETICKS; alias ASN_OPAQUE ASN_RFC1155_OPAQUE; alias ASN_OCTETSTRING ASN_RFC1213_DISPSTRING; alias SNMP_PDU_GET ASN_RFC1157_GETREQUEST; alias SNMP_PDU_GETNEXT ASN_RFC1157_GETNEXTREQUEST; alias SNMP_PDU_RESPONSE ASN_RFC1157_GETRESPONSE; alias SNMP_PDU_SET ASN_RFC1157_SETREQUEST; alias SNMP_PDU_V1TRAP ASN_RFC1157_TRAP; alias ASN_CONTEXT ASN_CONTEXTSPECIFIC; alias ASN_PRIMITIVE ASN_PRIMATIVE; alias SnmpVarBindList RFC1157VarBindList; alias SnmpVarBind RFC1157VarBind; alias AsnInteger32 AsnInteger; alias AsnCounter32 AsnCounter; alias AsnGauge32 AsnGauge; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/dbghelp.d0000664000175000017500000001464512776214756023276 0ustar kaikai/** * ... * * Copyright: Copyright Benjamin Thaut 2010 - 2011. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Benjamin Thaut, Sean Kelly * Source: $(DRUNTIMESRC core/sys/windows/_stacktrace.d) */ module core.sys.windows.dbghelp; version (Windows): import core.sys.windows.windows; public import core.sys.windows.dbghelp_types; extern(System) { alias BOOL function(HANDLE hProcess, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead) ReadProcessMemoryProc64; alias PVOID function(HANDLE hProcess, DWORD64 AddrBase) FunctionTableAccessProc64; alias DWORD64 function(HANDLE hProcess, DWORD64 Address) GetModuleBaseProc64; alias DWORD64 function(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr) TranslateAddressProc64; alias BOOL function(HANDLE hProcess, PCSTR UserSearchPath, bool fInvadeProcess) SymInitializeFunc; alias BOOL function(HANDLE hProcess) SymCleanupFunc; alias DWORD function(DWORD SymOptions) SymSetOptionsFunc; alias DWORD function() SymGetOptionsFunc; alias PVOID function(HANDLE hProcess, DWORD64 AddrBase) SymFunctionTableAccess64Func; alias BOOL function(DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, PVOID ContextRecord, ReadProcessMemoryProc64 ReadMemoryRoutine, FunctionTableAccessProc64 FunctoinTableAccess, GetModuleBaseProc64 GetModuleBaseRoutine, TranslateAddressProc64 TranslateAddress) StackWalk64Func; alias BOOL function(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, IMAGEHLP_LINEA64 *line) SymGetLineFromAddr64Func; alias DWORD64 function(HANDLE hProcess, DWORD64 dwAddr) SymGetModuleBase64Func; alias BOOL function(HANDLE hProcess, DWORD64 dwAddr, IMAGEHLP_MODULEA64 *ModuleInfo) SymGetModuleInfo64Func; alias BOOL function(HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, IMAGEHLP_SYMBOLA64 *Symbol) SymGetSymFromAddr64Func; alias DWORD function(PCTSTR DecoratedName, PTSTR UnDecoratedName, DWORD UndecoratedLength, DWORD Flags) UnDecorateSymbolNameFunc; alias DWORD64 function(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll) SymLoadModule64Func; alias BOOL function(HANDLE HProcess, PTSTR SearchPath, DWORD SearchPathLength) SymGetSearchPathFunc; alias BOOL function(HANDLE hProcess, DWORD64 Address) SymUnloadModule64Func; alias BOOL function(HANDLE hProcess, ULONG ActionCode, ulong CallbackContext, ulong UserContext) PSYMBOL_REGISTERED_CALLBACK64; alias BOOL function(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, ulong UserContext) SymRegisterCallback64Func; alias API_VERSION* function() ImagehlpApiVersionFunc; } struct DbgHelp { SymInitializeFunc SymInitialize; SymCleanupFunc SymCleanup; StackWalk64Func StackWalk64; SymGetOptionsFunc SymGetOptions; SymSetOptionsFunc SymSetOptions; SymFunctionTableAccess64Func SymFunctionTableAccess64; SymGetLineFromAddr64Func SymGetLineFromAddr64; SymGetModuleBase64Func SymGetModuleBase64; SymGetModuleInfo64Func SymGetModuleInfo64; SymGetSymFromAddr64Func SymGetSymFromAddr64; UnDecorateSymbolNameFunc UnDecorateSymbolName; SymLoadModule64Func SymLoadModule64; SymGetSearchPathFunc SymGetSearchPath; SymUnloadModule64Func SymUnloadModule64; SymRegisterCallback64Func SymRegisterCallback64; ImagehlpApiVersionFunc ImagehlpApiVersion; static DbgHelp* get() { if( sm_hndl != sm_hndl.init ) return &sm_inst; if( (sm_hndl = LoadLibraryA( "dbghelp.dll" )) != sm_hndl.init ) { sm_inst.SymInitialize = cast(SymInitializeFunc) GetProcAddress(sm_hndl,"SymInitialize"); sm_inst.SymCleanup = cast(SymCleanupFunc) GetProcAddress(sm_hndl,"SymCleanup"); sm_inst.StackWalk64 = cast(StackWalk64Func) GetProcAddress(sm_hndl,"StackWalk64"); sm_inst.SymGetOptions = cast(SymGetOptionsFunc) GetProcAddress(sm_hndl,"SymGetOptions"); sm_inst.SymSetOptions = cast(SymSetOptionsFunc) GetProcAddress(sm_hndl,"SymSetOptions"); sm_inst.SymFunctionTableAccess64 = cast(SymFunctionTableAccess64Func) GetProcAddress(sm_hndl,"SymFunctionTableAccess64"); sm_inst.SymGetLineFromAddr64 = cast(SymGetLineFromAddr64Func) GetProcAddress(sm_hndl,"SymGetLineFromAddr64"); sm_inst.SymGetModuleBase64 = cast(SymGetModuleBase64Func) GetProcAddress(sm_hndl,"SymGetModuleBase64"); sm_inst.SymGetModuleInfo64 = cast(SymGetModuleInfo64Func) GetProcAddress(sm_hndl,"SymGetModuleInfo64"); sm_inst.SymGetSymFromAddr64 = cast(SymGetSymFromAddr64Func) GetProcAddress(sm_hndl,"SymGetSymFromAddr64"); sm_inst.SymLoadModule64 = cast(SymLoadModule64Func) GetProcAddress(sm_hndl,"SymLoadModule64"); sm_inst.SymGetSearchPath = cast(SymGetSearchPathFunc) GetProcAddress(sm_hndl,"SymGetSearchPath"); sm_inst.SymUnloadModule64 = cast(SymUnloadModule64Func) GetProcAddress(sm_hndl,"SymUnloadModule64"); sm_inst.SymRegisterCallback64 = cast(SymRegisterCallback64Func) GetProcAddress(sm_hndl, "SymRegisterCallback64"); sm_inst.ImagehlpApiVersion = cast(ImagehlpApiVersionFunc) GetProcAddress(sm_hndl, "ImagehlpApiVersion"); assert( sm_inst.SymInitialize && sm_inst.SymCleanup && sm_inst.StackWalk64 && sm_inst.SymGetOptions && sm_inst.SymSetOptions && sm_inst.SymFunctionTableAccess64 && sm_inst.SymGetLineFromAddr64 && sm_inst.SymGetModuleBase64 && sm_inst.SymGetModuleInfo64 && sm_inst.SymGetSymFromAddr64 && sm_inst.SymLoadModule64 && sm_inst.SymGetSearchPath && sm_inst.SymUnloadModule64 && sm_inst.SymRegisterCallback64 && sm_inst.ImagehlpApiVersion); return &sm_inst; } return null; } shared static ~this() { if( sm_hndl != sm_hndl.init ) FreeLibrary( sm_hndl ); } private: __gshared DbgHelp sm_inst; __gshared HANDLE sm_hndl; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winreg.d0000664000175000017500000002243412776214756023157 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winreg.d) */ module core.sys.windows.winreg; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "advapi32"); private import core.sys.windows.w32api, core.sys.windows.winbase, core.sys.windows.windef; enum : HKEY { // for some reason, DMD errors if I don't give all the values explicitly HKEY_CLASSES_ROOT = cast(HKEY) 0x80000000, HKEY_CURRENT_USER = cast(HKEY) 0x80000001, HKEY_LOCAL_MACHINE = cast(HKEY) 0x80000002, HKEY_USERS = cast(HKEY) 0x80000003, HKEY_PERFORMANCE_DATA = cast(HKEY) 0x80000004, HKEY_CURRENT_CONFIG = cast(HKEY) 0x80000005, HKEY_DYN_DATA = cast(HKEY) 0x80000006, HKEY_PERFORMANCE_TEXT = cast(HKEY) 0x80000050, HKEY_PERFORMANCE_NLSTEXT = cast(HKEY) 0x80000060, } //enum : DWORD { // REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE //} enum : DWORD { REG_CREATED_NEW_KEY = 1, REG_OPENED_EXISTING_KEY } enum : DWORD { REG_NONE = 0, REG_SZ, REG_EXPAND_SZ, REG_BINARY, REG_DWORD_LITTLE_ENDIAN, REG_DWORD = REG_DWORD_LITTLE_ENDIAN, REG_DWORD_BIG_ENDIAN, REG_LINK, REG_MULTI_SZ, REG_RESOURCE_LIST, REG_FULL_RESOURCE_DESCRIPTOR, REG_RESOURCE_REQUIREMENTS_LIST, REG_QWORD_LITTLE_ENDIAN, REG_QWORD = REG_QWORD_LITTLE_ENDIAN } enum DWORD REG_NOTIFY_CHANGE_NAME = 1, REG_NOTIFY_CHANGE_ATTRIBUTES = 2, REG_NOTIFY_CHANGE_LAST_SET = 4, REG_NOTIFY_CHANGE_SECURITY = 8; alias ACCESS_MASK REGSAM; struct VALENTA { LPSTR ve_valuename; DWORD ve_valuelen; DWORD ve_valueptr; DWORD ve_type; } alias VALENTA* PVALENTA; struct VALENTW { LPWSTR ve_valuename; DWORD ve_valuelen; DWORD ve_valueptr; DWORD ve_type; } alias VALENTW* PVALENTW; // RRF - Registry Routine Flags (for RegGetValue) static if (_WIN32_WINNT >= 0x600) { enum : DWORD { RRF_RT_REG_NONE = 0x00000001, RRF_RT_REG_SZ = 0x00000002, RRF_RT_REG_EXPAND_SZ = 0x00000004, RRF_RT_REG_BINARY = 0x00000008, RRF_RT_REG_DWORD = 0x00000010, RRF_RT_REG_MULTI_SZ = 0x00000020, RRF_RT_REG_QWORD = 0x00000040, RRF_RT_DWORD = RRF_RT_REG_BINARY | RRF_RT_REG_DWORD, RRF_RT_QWORD = RRF_RT_REG_BINARY | RRF_RT_REG_QWORD, RRF_RT_ANY = 0x0000FFFF, RRF_NOEXPAND = 0x10000000, RRF_ZEROONFAILURE = 0x20000000 } } extern (Windows) nothrow @nogc { LONG RegCloseKey(in HKEY); LONG RegConnectRegistryA(LPCSTR, HKEY, PHKEY); LONG RegConnectRegistryW(LPCWSTR, HKEY, PHKEY); LONG RegCreateKeyExA(in HKEY, LPCSTR, DWORD, LPSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, PDWORD); LONG RegCreateKeyExW(in HKEY, LPCWSTR, DWORD, LPWSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, PDWORD); LONG RegDeleteKeyA(in HKEY, LPCSTR); LONG RegDeleteKeyW(in HKEY, LPCWSTR); LONG RegDeleteValueA(in HKEY, LPCSTR); LONG RegDeleteValueW(in HKEY, LPCWSTR); LONG RegEnumKeyExA(in HKEY, DWORD, LPSTR, PDWORD, PDWORD, LPSTR, PDWORD, PFILETIME); LONG RegEnumKeyExW(in HKEY, DWORD, LPWSTR, PDWORD, PDWORD, LPWSTR, PDWORD, PFILETIME); LONG RegEnumValueA(in HKEY, DWORD, LPSTR, PDWORD, PDWORD, PDWORD, LPBYTE, PDWORD); LONG RegEnumValueW(in HKEY, DWORD, LPWSTR, PDWORD, PDWORD, PDWORD, LPBYTE, PDWORD); LONG RegFlushKey(in HKEY); LONG RegLoadKeyA(in HKEY, LPCSTR, LPCSTR); LONG RegLoadKeyW(in HKEY, LPCWSTR, LPCWSTR); LONG RegOpenKeyExA(in HKEY, LPCSTR, DWORD, REGSAM, PHKEY); LONG RegOpenKeyExW(in HKEY, LPCWSTR, DWORD, REGSAM, PHKEY); LONG RegQueryInfoKeyA(in HKEY, LPSTR, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PFILETIME); LONG RegQueryInfoKeyW(in HKEY, LPWSTR, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PFILETIME); LONG RegQueryMultipleValuesA(in HKEY, PVALENTA, DWORD, LPSTR, LPDWORD); LONG RegQueryMultipleValuesW(in HKEY, PVALENTW, DWORD, LPWSTR, LPDWORD); LONG RegQueryValueExA(in HKEY, LPCSTR, LPDWORD, LPDWORD, /*LPBYTE*/LPVOID, LPDWORD); LONG RegQueryValueExW(in HKEY, LPCWSTR, LPDWORD, LPDWORD, /*LPBYTE*/LPVOID, LPDWORD); LONG RegReplaceKeyA(in HKEY, LPCSTR, LPCSTR, LPCSTR); LONG RegReplaceKeyW(in HKEY, LPCWSTR, LPCWSTR, LPCWSTR); LONG RegSaveKeyA(in HKEY, LPCSTR, LPSECURITY_ATTRIBUTES); LONG RegSaveKeyW(in HKEY, LPCWSTR, LPSECURITY_ATTRIBUTES); LONG RegSetKeySecurity(in HKEY, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); LONG RegSetValueExA(in HKEY, LPCSTR, DWORD, DWORD, const(BYTE)*, DWORD); LONG RegSetValueExW(in HKEY, LPCWSTR, DWORD, DWORD, const(BYTE)*, DWORD); LONG RegUnLoadKeyA(in HKEY, LPCSTR); LONG RegUnLoadKeyW(in HKEY, LPCWSTR); LONG RegNotifyChangeKeyValue(in HKEY, BOOL, DWORD, HANDLE, BOOL); BOOL AbortSystemShutdownA(LPCSTR); BOOL AbortSystemShutdownW(LPCWSTR); BOOL InitiateSystemShutdownA(LPSTR, LPSTR, DWORD, BOOL, BOOL); BOOL InitiateSystemShutdownW(LPWSTR, LPWSTR, DWORD, BOOL, BOOL); LONG RegGetKeySecurity(in HKEY, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, PDWORD); LONG RegRestoreKeyA(in HKEY, LPCSTR, DWORD); LONG RegRestoreKeyW(in HKEY, LPCWSTR, DWORD); LONG RegSetKeySecurity(in HKEY, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); static if (_WIN32_WINNT >= 0x500) { LONG RegDisablePredefinedCache(); LONG RegOpenCurrentUser(REGSAM, PHKEY); LONG RegOpenUserClassesRoot(HANDLE, DWORD, REGSAM, PHKEY); } static if (_WIN32_WINNT >= 0x501) { LONG RegSaveKeyExA(in HKEY, LPCSTR, LPSECURITY_ATTRIBUTES, DWORD); LONG RegSaveKeyExW(in HKEY, LPCWSTR, LPSECURITY_ATTRIBUTES, DWORD); } static if (_WIN32_WINNT >= 0x600) { LONG RegGetValueA(in HKEY hkey, LPCSTR lpSubKey, LPCSTR lpValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData); LONG RegGetValueW(in HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData); } //deprecated { LONG RegCreateKeyA(in HKEY, LPCSTR, PHKEY); LONG RegCreateKeyW(in HKEY, LPCWSTR, PHKEY); LONG RegEnumKeyA(in HKEY, DWORD, LPSTR, DWORD); LONG RegEnumKeyW(in HKEY, DWORD, LPWSTR, DWORD); LONG RegOpenKeyA(in HKEY, LPCSTR, PHKEY); LONG RegOpenKeyW(in HKEY, LPCWSTR, PHKEY); LONG RegQueryValueA(in HKEY, LPCSTR, LPSTR, PLONG); LONG RegQueryValueW(in HKEY, LPCWSTR, LPWSTR, PLONG); LONG RegSetValueA(in HKEY, LPCSTR, DWORD, LPCSTR, DWORD); LONG RegSetValueW(in HKEY, LPCWSTR, DWORD, LPCWSTR, DWORD); //} } version (Unicode) { alias VALENTW VALENT; alias RegConnectRegistryW RegConnectRegistry; alias RegCreateKeyExW RegCreateKeyEx; alias RegDeleteKeyW RegDeleteKey; alias RegDeleteValueW RegDeleteValue; alias RegEnumKeyExW RegEnumKeyEx; alias RegEnumValueW RegEnumValue; alias RegLoadKeyW RegLoadKey; alias RegOpenKeyExW RegOpenKeyEx; alias RegQueryInfoKeyW RegQueryInfoKey; alias RegQueryMultipleValuesW RegQueryMultipleValues; alias RegQueryValueExW RegQueryValueEx; alias RegReplaceKeyW RegReplaceKey; alias RegSaveKeyW RegSaveKey; alias RegSetValueExW RegSetValueEx; alias RegUnLoadKeyW RegUnLoadKey; alias AbortSystemShutdownW AbortSystemShutdown; alias InitiateSystemShutdownW InitiateSystemShutdown; alias RegRestoreKeyW RegRestoreKey; static if (_WIN32_WINNT >= 0x501) { alias RegSaveKeyExA RegSaveKeyEx; } static if (_WIN32_WINNT >= 0x600) { alias RegGetValueW RegGetValue; } //deprecated { alias RegCreateKeyW RegCreateKey; alias RegEnumKeyW RegEnumKey; alias RegOpenKeyW RegOpenKey; alias RegQueryValueW RegQueryValue; alias RegSetValueW RegSetValue; //} } else { alias VALENTA VALENT; alias RegConnectRegistryA RegConnectRegistry; alias RegCreateKeyExA RegCreateKeyEx; alias RegDeleteKeyA RegDeleteKey; alias RegDeleteValueA RegDeleteValue; alias RegEnumKeyExA RegEnumKeyEx; alias RegEnumValueA RegEnumValue; alias RegLoadKeyA RegLoadKey; alias RegOpenKeyExA RegOpenKeyEx; alias RegQueryInfoKeyA RegQueryInfoKey; alias RegQueryMultipleValuesA RegQueryMultipleValues; alias RegQueryValueExA RegQueryValueEx; alias RegReplaceKeyA RegReplaceKey; alias RegSaveKeyA RegSaveKey; alias RegSetValueExA RegSetValueEx; alias RegUnLoadKeyA RegUnLoadKey; alias AbortSystemShutdownA AbortSystemShutdown; alias InitiateSystemShutdownA InitiateSystemShutdown; alias RegRestoreKeyW RegRestoreKey; static if (_WIN32_WINNT >= 0x501) { alias RegSaveKeyExA RegSaveKeyEx; } static if (_WIN32_WINNT >= 0x600) { alias RegGetValueA RegGetValue; } //deprecated { alias RegCreateKeyA RegCreateKey; alias RegEnumKeyA RegEnumKey; alias RegOpenKeyA RegOpenKey; alias RegQueryValueA RegQueryValue; alias RegSetValueA RegSetValue; //} } alias VALENT* PVALENT; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/cpl.d0000664000175000017500000000317312776214756022441 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_cpl.d) */ module core.sys.windows.cpl; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.windef, core.sys.windows.winuser; enum : uint { WM_CPL_LAUNCH = WM_USER + 1000, WM_CPL_LAUNCHED } enum : uint { CPL_DYNAMIC_RES, CPL_INIT, CPL_GETCOUNT, CPL_INQUIRE, CPL_SELECT, CPL_DBLCLK, CPL_STOP, CPL_EXIT, CPL_NEWINQUIRE, CPL_STARTWPARMSA, CPL_STARTWPARMSW, // = 10 CPL_SETUP = 200 } extern (Windows) alias LONG function(HWND, UINT, LONG, LONG) APPLET_PROC; struct CPLINFO { int idIcon; int idName; int idInfo; LONG lData; } alias CPLINFO* LPCPLINFO; struct NEWCPLINFOA { DWORD dwSize = NEWCPLINFOA.sizeof; DWORD dwFlags; DWORD dwHelpContext; LONG lData; HICON hIcon; CHAR[32] szName; CHAR[64] szInfo; CHAR[128] szHelpFile; } alias NEWCPLINFOA* LPNEWCPLINFOA; struct NEWCPLINFOW { DWORD dwSize = NEWCPLINFOW.sizeof; DWORD dwFlags; DWORD dwHelpContext; LONG lData; HICON hIcon; WCHAR[32] szName; WCHAR[64] szInfo; WCHAR[128] szHelpFile; } alias NEWCPLINFOW* LPNEWCPLINFOW; version (Unicode) { alias CPL_STARTWPARMSW CPL_STARTWPARMS; alias NEWCPLINFOW NEWCPLINFO; } else { alias CPL_STARTWPARMSA CPL_STARTWPARMS; alias NEWCPLINFOA NEWCPLINFO; } alias NEWCPLINFO* LPNEWCPLINFO; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/security.d0000664000175000017500000000256512776214756023536 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Ellery Newcomer * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_security.d) */ module core.sys.windows.security; version (Windows): enum :SECURITY_STATUS{ SEC_E_OK = 0, SEC_E_CERT_EXPIRED = (-2146893016), SEC_E_INCOMPLETE_MESSAGE = (-2146893032), SEC_E_INSUFFICIENT_MEMORY = (-2146893056), SEC_E_INTERNAL_ERROR = (-2146893052), SEC_E_INVALID_HANDLE = (-2146893055), SEC_E_INVALID_TOKEN = (-2146893048), SEC_E_LOGON_DENIED = (-2146893044), SEC_E_NO_AUTHENTICATING_AUTHORITY = (-2146893039), SEC_E_NO_CREDENTIALS = (-2146893042), SEC_E_TARGET_UNKNOWN = (-2146893053), SEC_E_UNSUPPORTED_FUNCTION = (-2146893054), SEC_E_UNTRUSTED_ROOT = (-2146893019), SEC_E_WRONG_PRINCIPAL = (-2146893022), SEC_E_SECPKG_NOT_FOUND = (-2146893051), SEC_E_QOP_NOT_SUPPORTED = (-2146893046), SEC_E_UNKNOWN_CREDENTIALS = (-2146893043), SEC_E_NOT_OWNER = (-2146893050), } enum :SECURITY_STATUS { SEC_I_RENEGOTIATE = 590625, SEC_I_COMPLETE_AND_CONTINUE = 590612, SEC_I_COMPLETE_NEEDED = 590611, SEC_I_CONTINUE_NEEDED = 590610, SEC_I_INCOMPLETE_CREDENTIALS = 590624, } /* always a char */ alias char SEC_CHAR; alias wchar SEC_WCHAR; alias int SECURITY_STATUS; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/secext.d0000664000175000017500000000327712776214756023163 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_secext.d) */ // Don't include this file directly, use core.sys.windows.security instead. module core.sys.windows.secext; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "secur32"); private import core.sys.windows.w32api, core.sys.windows.windef; static assert (_WIN32_WINNT >= 0x501, "SecExt is only available on WindowsXP and later"); enum EXTENDED_NAME_FORMAT { NameUnknown, NameFullyQualifiedDN, NameSamCompatible, NameDisplay, // = 3 NameUniqueId = 6, NameCanonical, NameUserPrincipal, NameCanonicalEx, NameServicePrincipal, // = 10 NameDnsDomain = 12 } alias EXTENDED_NAME_FORMAT* PEXTENDED_NAME_FORMAT; extern (Windows) { BOOLEAN GetComputerObjectNameA(EXTENDED_NAME_FORMAT, LPSTR, PULONG); BOOLEAN GetComputerObjectNameW(EXTENDED_NAME_FORMAT, LPWSTR, PULONG); BOOLEAN GetUserNameExA(EXTENDED_NAME_FORMAT, LPSTR, PULONG); BOOLEAN GetUserNameExW(EXTENDED_NAME_FORMAT, LPWSTR, PULONG); BOOLEAN TranslateNameA(LPCSTR, EXTENDED_NAME_FORMAT, EXTENDED_NAME_FORMAT, LPSTR, PULONG); BOOLEAN TranslateNameW(LPCWSTR, EXTENDED_NAME_FORMAT, EXTENDED_NAME_FORMAT, LPWSTR, PULONG); } version (Unicode) { alias GetComputerObjectNameW GetComputerObjectName; alias GetUserNameExW GetUserNameEx; alias TranslateNameW TranslateName; } else { alias GetComputerObjectNameA GetComputerObjectName; alias GetUserNameExA GetUserNameEx; alias TranslateNameA TranslateName; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winspool.d0000664000175000017500000007230112776214756023534 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winspool.d) */ module core.sys.windows.winspool; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "winspool"); private import core.sys.windows.w32api, core.sys.windows.windef, core.sys.windows.wingdi; private import core.sys.windows.winbase; // for SYSTEMTIME // FIXME: clean up Windows version support enum DI_CHANNEL=1; enum DI_CHANNEL_WRITE=2; enum DI_READ_SPOOL_JOB=3; enum FORM_BUILTIN=1; enum JOB_CONTROL_PAUSE=1; enum JOB_CONTROL_RESUME=2; enum JOB_CONTROL_CANCEL=3; enum JOB_CONTROL_RESTART=4; enum JOB_CONTROL_DELETE=5; enum JOB_STATUS_PAUSED=1; enum JOB_STATUS_ERROR=2; enum JOB_STATUS_DELETING=4; enum JOB_STATUS_SPOOLING=8; enum JOB_STATUS_PRINTING=16; enum JOB_STATUS_OFFLINE=32; enum JOB_STATUS_PAPEROUT=0x40; enum JOB_STATUS_PRINTED=0x80; enum JOB_STATUS_DELETED=0x100; enum JOB_STATUS_BLOCKED_DEVQ=0x200; enum JOB_STATUS_USER_INTERVENTION=0x400; enum JOB_POSITION_UNSPECIFIED=0; enum JOB_NOTIFY_TYPE=1; enum JOB_NOTIFY_FIELD_PRINTER_NAME=0; enum JOB_NOTIFY_FIELD_MACHINE_NAME=1; enum JOB_NOTIFY_FIELD_PORT_NAME=2; enum JOB_NOTIFY_FIELD_USER_NAME=3; enum JOB_NOTIFY_FIELD_NOTIFY_NAME=4; enum JOB_NOTIFY_FIELD_DATATYPE=5; enum JOB_NOTIFY_FIELD_PRINT_PROCESSOR=6; enum JOB_NOTIFY_FIELD_PARAMETERS=7; enum JOB_NOTIFY_FIELD_DRIVER_NAME=8; enum JOB_NOTIFY_FIELD_DEVMODE=9; enum JOB_NOTIFY_FIELD_STATUS=10; enum JOB_NOTIFY_FIELD_STATUS_STRING=11; enum JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR=12; enum JOB_NOTIFY_FIELD_DOCUMENT=13; enum JOB_NOTIFY_FIELD_PRIORITY=14; enum JOB_NOTIFY_FIELD_POSITION=15; enum JOB_NOTIFY_FIELD_SUBMITTED=16; enum JOB_NOTIFY_FIELD_START_TIME=17; enum JOB_NOTIFY_FIELD_UNTIL_TIME=18; enum JOB_NOTIFY_FIELD_TIME=19; enum JOB_NOTIFY_FIELD_TOTAL_PAGES=20; enum JOB_NOTIFY_FIELD_PAGES_PRINTED=21; enum JOB_NOTIFY_FIELD_TOTAL_BYTES=22; enum JOB_NOTIFY_FIELD_BYTES_PRINTED=23; enum JOB_ACCESS_ADMINISTER = 16; enum JOB_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | JOB_ACCESS_ADMINISTER; enum JOB_READ = STANDARD_RIGHTS_READ | JOB_ACCESS_ADMINISTER; enum JOB_WRITE = STANDARD_RIGHTS_WRITE | JOB_ACCESS_ADMINISTER; enum JOB_EXECUTE = STANDARD_RIGHTS_EXECUTE | JOB_ACCESS_ADMINISTER; enum PRINTER_NOTIFY_OPTIONS_REFRESH=1; enum PRINTER_ACCESS_ADMINISTER=4; enum PRINTER_ACCESS_USE=8; enum PRINTER_ERROR_INFORMATION=0x80000000; enum PRINTER_ERROR_WARNING=0x40000000; enum PRINTER_ERROR_SEVERE=0x20000000; enum PRINTER_ERROR_OUTOFPAPER=1; enum PRINTER_ERROR_JAM=2; enum PRINTER_ERROR_OUTOFTONER=4; enum PRINTER_CONTROL_PAUSE=1; enum PRINTER_CONTROL_RESUME=2; enum PRINTER_CONTROL_PURGE=3; enum PRINTER_CONTROL_SET_STATUS=4; enum PRINTER_STATUS_PAUSED = 1; enum PRINTER_STATUS_ERROR = 2; enum PRINTER_STATUS_PENDING_DELETION = 4; enum PRINTER_STATUS_PAPER_JAM = 8; enum PRINTER_STATUS_PAPER_OUT = 0x10; enum PRINTER_STATUS_MANUAL_FEED = 0x20; enum PRINTER_STATUS_PAPER_PROBLEM = 0x40; enum PRINTER_STATUS_OFFLINE = 0x80; enum PRINTER_STATUS_IO_ACTIVE = 0x100; enum PRINTER_STATUS_BUSY = 0x200; enum PRINTER_STATUS_PRINTING = 0x400; enum PRINTER_STATUS_OUTPUT_BIN_FULL = 0x800; enum PRINTER_STATUS_NOT_AVAILABLE = 0x1000; enum PRINTER_STATUS_WAITING = 0x2000; enum PRINTER_STATUS_PROCESSING = 0x4000; enum PRINTER_STATUS_INITIALIZING = 0x8000; enum PRINTER_STATUS_WARMING_UP = 0x10000; enum PRINTER_STATUS_TONER_LOW = 0x20000; enum PRINTER_STATUS_NO_TONER = 0x40000; enum PRINTER_STATUS_PAGE_PUNT = 0x80000; enum PRINTER_STATUS_USER_INTERVENTION = 0x100000; enum PRINTER_STATUS_OUT_OF_MEMORY = 0x200000; enum PRINTER_STATUS_DOOR_OPEN = 0x400000; enum PRINTER_STATUS_SERVER_UNKNOWN = 0x800000; enum PRINTER_STATUS_POWER_SAVE = 0x1000000; enum PRINTER_ATTRIBUTE_QUEUED=1; enum PRINTER_ATTRIBUTE_DIRECT=2; enum PRINTER_ATTRIBUTE_DEFAULT=4; enum PRINTER_ATTRIBUTE_SHARED=8; enum PRINTER_ATTRIBUTE_NETWORK=0x10; enum PRINTER_ATTRIBUTE_HIDDEN=0x20; enum PRINTER_ATTRIBUTE_LOCAL=0x40; enum PRINTER_ATTRIBUTE_ENABLE_DEVQ=0x80; enum PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS=0x100; enum PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST=0x200; enum PRINTER_ATTRIBUTE_WORK_OFFLINE=0x400; enum PRINTER_ATTRIBUTE_ENABLE_BIDI=0x800; enum PRINTER_ATTRIBUTE_RAW_ONLY=0x1000; enum PRINTER_ATTRIBUTE_PUBLISHED=0x2000; enum PRINTER_ENUM_DEFAULT=1; enum PRINTER_ENUM_LOCAL=2; enum PRINTER_ENUM_CONNECTIONS=4; enum PRINTER_ENUM_FAVORITE=4; enum PRINTER_ENUM_NAME=8; enum PRINTER_ENUM_REMOTE=16; enum PRINTER_ENUM_SHARED=32; enum PRINTER_ENUM_NETWORK=0x40; enum PRINTER_ENUM_EXPAND=0x4000; enum PRINTER_ENUM_CONTAINER=0x8000; enum PRINTER_ENUM_ICONMASK=0xff0000; enum PRINTER_ENUM_ICON1=0x10000; enum PRINTER_ENUM_ICON2=0x20000; enum PRINTER_ENUM_ICON3=0x40000; enum PRINTER_ENUM_ICON4=0x80000; enum PRINTER_ENUM_ICON5=0x100000; enum PRINTER_ENUM_ICON6=0x200000; enum PRINTER_ENUM_ICON7=0x400000; enum PRINTER_ENUM_ICON8=0x800000; enum PRINTER_NOTIFY_TYPE=0; enum PRINTER_NOTIFY_FIELD_SERVER_NAME=0; enum PRINTER_NOTIFY_FIELD_PRINTER_NAME=1; enum PRINTER_NOTIFY_FIELD_SHARE_NAME=2; enum PRINTER_NOTIFY_FIELD_PORT_NAME=3; enum PRINTER_NOTIFY_FIELD_DRIVER_NAME=4; enum PRINTER_NOTIFY_FIELD_COMMENT=5; enum PRINTER_NOTIFY_FIELD_LOCATION=6; enum PRINTER_NOTIFY_FIELD_DEVMODE=7; enum PRINTER_NOTIFY_FIELD_SEPFILE=8; enum PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR=9; enum PRINTER_NOTIFY_FIELD_PARAMETERS=10; enum PRINTER_NOTIFY_FIELD_DATATYPE=11; enum PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR=12; enum PRINTER_NOTIFY_FIELD_ATTRIBUTES=13; enum PRINTER_NOTIFY_FIELD_PRIORITY=14; enum PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY=15; enum PRINTER_NOTIFY_FIELD_START_TIME=16; enum PRINTER_NOTIFY_FIELD_UNTIL_TIME=17; enum PRINTER_NOTIFY_FIELD_STATUS=18; enum PRINTER_NOTIFY_FIELD_STATUS_STRING=19; enum PRINTER_NOTIFY_FIELD_CJOBS=20; enum PRINTER_NOTIFY_FIELD_AVERAGE_PPM=21; enum PRINTER_NOTIFY_FIELD_TOTAL_PAGES=22; enum PRINTER_NOTIFY_FIELD_PAGES_PRINTED=23; enum PRINTER_NOTIFY_FIELD_TOTAL_BYTES=24; enum PRINTER_NOTIFY_FIELD_BYTES_PRINTED=25; enum PRINTER_CHANGE_ADD_PRINTER=1; enum PRINTER_CHANGE_SET_PRINTER=2; enum PRINTER_CHANGE_DELETE_PRINTER=4; enum PRINTER_CHANGE_FAILED_CONNECTION_PRINTER=8; enum PRINTER_CHANGE_PRINTER=0xFF; enum PRINTER_CHANGE_ADD_JOB=0x100; enum PRINTER_CHANGE_SET_JOB=0x200; enum PRINTER_CHANGE_DELETE_JOB=0x400; enum PRINTER_CHANGE_WRITE_JOB=0x800; enum PRINTER_CHANGE_JOB=0xFF00; enum PRINTER_CHANGE_ADD_FORM=0x10000; enum PRINTER_CHANGE_SET_FORM=0x20000; enum PRINTER_CHANGE_DELETE_FORM=0x40000; enum PRINTER_CHANGE_FORM=0x70000; enum PRINTER_CHANGE_ADD_PORT=0x100000; enum PRINTER_CHANGE_CONFIGURE_PORT=0x200000; enum PRINTER_CHANGE_DELETE_PORT=0x400000; enum PRINTER_CHANGE_PORT=0x700000; enum PRINTER_CHANGE_ADD_PRINT_PROCESSOR=0x1000000; enum PRINTER_CHANGE_DELETE_PRINT_PROCESSOR=0x4000000; enum PRINTER_CHANGE_PRINT_PROCESSOR=0x7000000; enum PRINTER_CHANGE_ADD_PRINTER_DRIVER=0x10000000; enum PRINTER_CHANGE_SET_PRINTER_DRIVER=0x20000000; enum PRINTER_CHANGE_DELETE_PRINTER_DRIVER=0x40000000; enum PRINTER_CHANGE_PRINTER_DRIVER=0x70000000; enum PRINTER_CHANGE_TIMEOUT=0x80000000; enum PRINTER_CHANGE_ALL=0x7777FFFF; enum PRINTER_NOTIFY_INFO_DISCARDED=1; enum PRINTER_ALL_ACCESS=(STANDARD_RIGHTS_REQUIRED|PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE); enum PRINTER_READ=(STANDARD_RIGHTS_READ|PRINTER_ACCESS_USE); enum PRINTER_WRITE=(STANDARD_RIGHTS_WRITE|PRINTER_ACCESS_USE); enum PRINTER_EXECUTE=(STANDARD_RIGHTS_EXECUTE|PRINTER_ACCESS_USE); enum NO_PRIORITY=0; enum MAX_PRIORITY=99; enum MIN_PRIORITY=1; enum DEF_PRIORITY=1; enum PORT_TYPE_WRITE=1; enum PORT_TYPE_READ=2; enum PORT_TYPE_REDIRECTED=4; enum PORT_TYPE_NET_ATTACHED=8; enum SERVER_ACCESS_ADMINISTER=1; enum SERVER_ACCESS_ENUMERATE=2; enum SERVER_ALL_ACCESS=(STANDARD_RIGHTS_REQUIRED|SERVER_ACCESS_ADMINISTER|SERVER_ACCESS_ENUMERATE); enum SERVER_READ=(STANDARD_RIGHTS_READ|SERVER_ACCESS_ENUMERATE); enum SERVER_WRITE=(STANDARD_RIGHTS_WRITE|SERVER_ACCESS_ADMINISTER|SERVER_ACCESS_ENUMERATE); enum SERVER_EXECUTE=(STANDARD_RIGHTS_EXECUTE|SERVER_ACCESS_ENUMERATE); enum PORT_STATUS_TYPE_ERROR=1; enum PORT_STATUS_TYPE_WARNING=2; enum PORT_STATUS_TYPE_INFO=3; enum PORT_STATUS_OFFLINE=1; enum PORT_STATUS_PAPER_JAM=2; enum PORT_STATUS_PAPER_OUT=3; enum PORT_STATUS_OUTPUT_BIN_FULL=4; enum PORT_STATUS_PAPER_PROBLEM=5; enum PORT_STATUS_NO_TONER=6; enum PORT_STATUS_DOOR_OPEN=7; enum PORT_STATUS_USER_INTERVENTION=8; enum PORT_STATUS_OUT_OF_MEMORY=9; enum PORT_STATUS_TONER_LOW=10; enum PORT_STATUS_WARMING_UP=11; enum PORT_STATUS_POWER_SAVE=12; struct ADDJOB_INFO_1A { LPSTR Path; DWORD JobId; } alias ADDJOB_INFO_1A* PADDJOB_INFO_1A, LPADDJOB_INFO_1A; struct ADDJOB_INFO_1W { LPWSTR Path; DWORD JobId; } alias ADDJOB_INFO_1W* PADDJOB_INFO_1W, LPADDJOB_INFO_1W; struct DATATYPES_INFO_1A { LPSTR pName; } alias DATATYPES_INFO_1A* PDATATYPES_INFO_1A, LPDATATYPES_INFO_1A; struct DATATYPES_INFO_1W { LPWSTR pName; } alias DATATYPES_INFO_1W* PDATATYPES_INFO_1W, LPDATATYPES_INFO_1W; struct JOB_INFO_1A { DWORD JobId; LPSTR pPrinterName; LPSTR pMachineName; LPSTR pUserName; LPSTR pDocument; LPSTR pDatatype; LPSTR pStatus; DWORD Status; DWORD Priority; DWORD Position; DWORD TotalPages; DWORD PagesPrinted; SYSTEMTIME Submitted; } alias JOB_INFO_1A* PJOB_INFO_1A, LPJOB_INFO_1A; struct JOB_INFO_1W { DWORD JobId; LPWSTR pPrinterName; LPWSTR pMachineName; LPWSTR pUserName; LPWSTR pDocument; LPWSTR pDatatype; LPWSTR pStatus; DWORD Status; DWORD Priority; DWORD Position; DWORD TotalPages; DWORD PagesPrinted; SYSTEMTIME Submitted; } alias JOB_INFO_1W* PJOB_INFO_1W, LPJOB_INFO_1W; struct JOB_INFO_2A { DWORD JobId; LPSTR pPrinterName; LPSTR pMachineName; LPSTR pUserName; LPSTR pDocument; LPSTR pNotifyName; LPSTR pDatatype; LPSTR pPrintProcessor; LPSTR pParameters; LPSTR pDriverName; LPDEVMODEA pDevMode; LPSTR pStatus; PSECURITY_DESCRIPTOR pSecurityDescriptor; DWORD Status; DWORD Priority; DWORD Position; DWORD StartTime; DWORD UntilTime; DWORD TotalPages; DWORD Size; SYSTEMTIME Submitted; DWORD Time; DWORD PagesPrinted; } alias JOB_INFO_2A* PJOB_INFO_2A, LPJOB_INFO_2A; struct JOB_INFO_2W { DWORD JobId; LPWSTR pPrinterName; LPWSTR pMachineName; LPWSTR pUserName; LPWSTR pDocument; LPWSTR pNotifyName; LPWSTR pDatatype; LPWSTR pPrintProcessor; LPWSTR pParameters; LPWSTR pDriverName; LPDEVMODEW pDevMode; LPWSTR pStatus; PSECURITY_DESCRIPTOR pSecurityDescriptor; DWORD Status; DWORD Priority; DWORD Position; DWORD StartTime; DWORD UntilTime; DWORD TotalPages; DWORD Size; SYSTEMTIME Submitted; DWORD Time; DWORD PagesPrinted; } alias JOB_INFO_2W* PJOB_INFO_2W, LPJOB_INFO_2W; struct DOC_INFO_1A { LPSTR pDocName; LPSTR pOutputFile; LPSTR pDatatype; } alias DOC_INFO_1A* PDOC_INFO_1A, LPDOC_INFO_1A; struct DOC_INFO_1W { LPWSTR pDocName; LPWSTR pOutputFile; LPWSTR pDatatype; } alias DOC_INFO_1W* PDOC_INFO_1W, LPDOC_INFO_1W; struct DOC_INFO_2A { LPSTR pDocName; LPSTR pOutputFile; LPSTR pDatatype; DWORD dwMode; DWORD JobId; } alias DOC_INFO_2A* PDOC_INFO_2A, LPDOC_INFO_2A; struct DOC_INFO_2W { LPWSTR pDocName; LPWSTR pOutputFile; LPWSTR pDatatype; DWORD dwMode; DWORD JobId; } alias DOC_INFO_2W* PDOC_INFO_2W, LPDOC_INFO_2W; struct DRIVER_INFO_1A { LPSTR pName; } alias DRIVER_INFO_1A* PDRIVER_INFO_1A, LPDRIVER_INFO_1A; struct DRIVER_INFO_1W { LPWSTR pName; } alias DRIVER_INFO_1W* PDRIVER_INFO_1W, LPDRIVER_INFO_1W; struct DRIVER_INFO_2A { DWORD cVersion; LPSTR pName; LPSTR pEnvironment; LPSTR pDriverPath; LPSTR pDataFile; LPSTR pConfigFile; } alias DRIVER_INFO_2A* PDRIVER_INFO_2A, LPDRIVER_INFO_2A; struct DRIVER_INFO_2W { DWORD cVersion; LPWSTR pName; LPWSTR pEnvironment; LPWSTR pDriverPath; LPWSTR pDataFile; LPWSTR pConfigFile; } alias DRIVER_INFO_2W* PDRIVER_INFO_2W, LPDRIVER_INFO_2W; struct DRIVER_INFO_3A { DWORD cVersion; LPSTR pName; LPSTR pEnvironment; LPSTR pDriverPath; LPSTR pDataFile; LPSTR pConfigFile; LPSTR pHelpFile; LPSTR pDependentFiles; LPSTR pMonitorName; LPSTR pDefaultDataType; } alias DRIVER_INFO_3A* PDRIVER_INFO_3A, LPDRIVER_INFO_3A; struct DRIVER_INFO_3W { DWORD cVersion; LPWSTR pName; LPWSTR pEnvironment; LPWSTR pDriverPath; LPWSTR pDataFile; LPWSTR pConfigFile; LPWSTR pHelpFile; LPWSTR pDependentFiles; LPWSTR pMonitorName; LPWSTR pDefaultDataType; } alias DRIVER_INFO_3W* PDRIVER_INFO_3W, LPDRIVER_INFO_3W; struct MONITOR_INFO_1A { LPSTR pName; } alias MONITOR_INFO_1A* PMONITOR_INFO_1A, LPMONITOR_INFO_1A; struct MONITOR_INFO_1W { LPWSTR pName; } alias MONITOR_INFO_1W* PMONITOR_INFO_1W, LPMONITOR_INFO_1W; struct PORT_INFO_1A { LPSTR pName; } alias PORT_INFO_1A* PPORT_INFO_1A, LPPORT_INFO_1A; struct PORT_INFO_1W { LPWSTR pName; } alias PORT_INFO_1W* PPORT_INFO_1W, LPPORT_INFO_1W; struct MONITOR_INFO_2A { LPSTR pName; LPSTR pEnvironment; LPSTR pDLLName; } alias MONITOR_INFO_2A* PMONITOR_INFO_2A, LPMONITOR_INFO_2A; struct MONITOR_INFO_2W { LPWSTR pName; LPWSTR pEnvironment; LPWSTR pDLLName; } alias MONITOR_INFO_2W* PMONITOR_INFO_2W, LPMONITOR_INFO_2W; struct PORT_INFO_2A { LPSTR pPortName; LPSTR pMonitorName; LPSTR pDescription; DWORD fPortType; DWORD Reserved; } alias PORT_INFO_2A* PPORT_INFO_2A, LPPORT_INFO_2A; struct PORT_INFO_2W { LPWSTR pPortName; LPWSTR pMonitorName; LPWSTR pDescription; DWORD fPortType; DWORD Reserved; } alias PORT_INFO_2W* PPORT_INFO_2W, LPPORT_INFO_2W; struct PORT_INFO_3A { DWORD dwStatus; LPSTR pszStatus; DWORD dwSeverity; } alias PORT_INFO_3A* PPORT_INFO_3A, LPPORT_INFO_3A; struct PORT_INFO_3W { DWORD dwStatus; LPWSTR pszStatus; DWORD dwSeverity; } alias PORT_INFO_3W* PPORT_INFO_3W, LPPORT_INFO_3W; struct PRINTER_INFO_1A { DWORD Flags; LPSTR pDescription; LPSTR pName; LPSTR pComment; } alias PRINTER_INFO_1A* PPRINTER_INFO_1A, LPPRINTER_INFO_1A; struct PRINTER_INFO_1W { DWORD Flags; LPWSTR pDescription; LPWSTR pName; LPWSTR pComment; } alias PRINTER_INFO_1W* PPRINTER_INFO_1W, LPPRINTER_INFO_1W; struct PRINTER_INFO_2A { LPSTR pServerName; LPSTR pPrinterName; LPSTR pShareName; LPSTR pPortName; LPSTR pDriverName; LPSTR pComment; LPSTR pLocation; LPDEVMODEA pDevMode; LPSTR pSepFile; LPSTR pPrintProcessor; LPSTR pDatatype; LPSTR pParameters; PSECURITY_DESCRIPTOR pSecurityDescriptor; DWORD Attributes; DWORD Priority; DWORD DefaultPriority; DWORD StartTime; DWORD UntilTime; DWORD Status; DWORD cJobs; DWORD AveragePPM; } alias PRINTER_INFO_2A* PPRINTER_INFO_2A, LPPRINTER_INFO_2A; struct PRINTER_INFO_2W { LPWSTR pServerName; LPWSTR pPrinterName; LPWSTR pShareName; LPWSTR pPortName; LPWSTR pDriverName; LPWSTR pComment; LPWSTR pLocation; LPDEVMODEW pDevMode; LPWSTR pSepFile; LPWSTR pPrintProcessor; LPWSTR pDatatype; LPWSTR pParameters; PSECURITY_DESCRIPTOR pSecurityDescriptor; DWORD Attributes; DWORD Priority; DWORD DefaultPriority; DWORD StartTime; DWORD UntilTime; DWORD Status; DWORD cJobs; DWORD AveragePPM; } alias PRINTER_INFO_2W* PPRINTER_INFO_2W, LPPRINTER_INFO_2W; struct PRINTER_INFO_3 { PSECURITY_DESCRIPTOR pSecurityDescriptor; } alias PRINTER_INFO_3* PPRINTER_INFO_3, LPPRINTER_INFO_3; struct PRINTER_INFO_4A { LPSTR pPrinterName; LPSTR pServerName; DWORD Attributes; } alias PRINTER_INFO_4A* PPRINTER_INFO_4A, LPPRINTER_INFO_4A; struct PRINTER_INFO_4W { LPWSTR pPrinterName; LPWSTR pServerName; DWORD Attributes; } alias PRINTER_INFO_4W* PPRINTER_INFO_4W, LPPRINTER_INFO_4W; struct PRINTER_INFO_5A { LPSTR pPrinterName; LPSTR pPortName; DWORD Attributes; DWORD DeviceNotSelectedTimeout; DWORD TransmissionRetryTimeout; } alias PRINTER_INFO_5A* PPRINTER_INFO_5A, LPPRINTER_INFO_5A; struct PRINTER_INFO_5W { LPWSTR pPrinterName; LPWSTR pPortName; DWORD Attributes; DWORD DeviceNotSelectedTimeout; DWORD TransmissionRetryTimeout; } alias PRINTER_INFO_5W* PPRINTER_INFO_5W, LPPRINTER_INFO_5W; struct PRINTER_INFO_6 { DWORD dwStatus; } alias PRINTER_INFO_6* PPRINTER_INFO_6, LPPRINTER_INFO_6; struct PRINTPROCESSOR_INFO_1A { LPSTR pName; } alias PRINTPROCESSOR_INFO_1A* PPRINTPROCESSOR_INFO_1A, LPPRINTPROCESSOR_INFO_1A; struct PRINTPROCESSOR_INFO_1W { LPWSTR pName; } alias PRINTPROCESSOR_INFO_1W* PPRINTPROCESSOR_INFO_1W, LPPRINTPROCESSOR_INFO_1W; struct PRINTER_NOTIFY_INFO_DATA { WORD Type; WORD Field; DWORD Reserved; DWORD Id; union _NotifyData { DWORD[2] adwData; struct Data { DWORD cbBuf; PVOID pBuf; } } _NotifyData NotifyData; } alias PRINTER_NOTIFY_INFO_DATA* PPRINTER_NOTIFY_INFO_DATA, LPPRINTER_NOTIFY_INFO_DATA; struct PRINTER_NOTIFY_INFO { DWORD Version; DWORD Flags; DWORD Count; PRINTER_NOTIFY_INFO_DATA[1] aData; } alias PRINTER_NOTIFY_INFO* PPRINTER_NOTIFY_INFO, LPPRINTER_NOTIFY_INFO; struct FORM_INFO_1A { DWORD Flags; LPSTR pName; SIZEL Size; RECTL ImageableArea; } alias FORM_INFO_1A* PFORM_INFO_1A, LPFORM_INFO_1A; struct FORM_INFO_1W { DWORD Flags; LPWSTR pName; SIZEL Size; RECTL ImageableArea; } alias FORM_INFO_1W* PFORM_INFO_1W, LPFORM_INFO_1W; struct PRINTER_DEFAULTSA { LPSTR pDatatype; LPDEVMODE pDevMode; ACCESS_MASK DesiredAccess; } alias PRINTER_DEFAULTSA* PPRINTER_DEFAULTSA, LPPRINTER_DEFAULTSA; struct PRINTER_DEFAULTSW { LPWSTR pDatatype; LPDEVMODE pDevMode; ACCESS_MASK DesiredAccess; } alias PRINTER_DEFAULTSW* PPRINTER_DEFAULTSW, LPPRINTER_DEFAULTSW; extern (Windows): BOOL AbortPrinter(HANDLE); BOOL AddFormA(HANDLE, DWORD, PBYTE); BOOL AddFormW(HANDLE, DWORD, PBYTE); BOOL AddJobA(HANDLE, DWORD, PBYTE, DWORD, PDWORD); BOOL AddJobW(HANDLE, DWORD, PBYTE, DWORD, PDWORD); BOOL AddMonitorA(LPSTR, DWORD, PBYTE); BOOL AddMonitorW(LPWSTR, DWORD, PBYTE); BOOL AddPortA(LPSTR, HWND, LPSTR); BOOL AddPortW(LPWSTR, HWND, LPWSTR); HANDLE AddPrinterA(LPSTR, DWORD, PBYTE); HANDLE AddPrinterW(LPWSTR, DWORD, PBYTE); BOOL AddPrinterConnectionA(LPSTR); BOOL AddPrinterConnectionW(LPWSTR); BOOL AddPrinterDriverA(LPSTR, DWORD, PBYTE); BOOL AddPrinterDriverW(LPWSTR, DWORD, PBYTE); BOOL AddPrintProcessorA(LPSTR, LPSTR, LPSTR, LPSTR); BOOL AddPrintProcessorW(LPWSTR, LPWSTR, LPWSTR, LPWSTR); BOOL AddPrintProvidorA(LPSTR, DWORD, PBYTE); BOOL AddPrintProvidorW(LPWSTR, DWORD, PBYTE); LONG AdvancedDocumentPropertiesA(HWND, HANDLE, LPSTR, PDEVMODE, PDEVMODEA); LONG AdvancedDocumentPropertiesW(HWND, HANDLE, LPWSTR, PDEVMODE, PDEVMODEW); BOOL ClosePrinter(HANDLE); BOOL ConfigurePortA(LPSTR, HWND, LPSTR); BOOL ConfigurePortW(LPWSTR, HWND, LPWSTR); HANDLE ConnectToPrinterDlg(HWND, DWORD); BOOL DeleteFormA(HANDLE, LPSTR); BOOL DeleteFormW(HANDLE, LPWSTR); BOOL DeleteMonitorA(LPSTR, LPSTR, LPSTR); BOOL DeleteMonitorW(LPWSTR, LPWSTR, LPWSTR); BOOL DeletePortA(LPSTR, HWND, LPSTR); BOOL DeletePortW(LPWSTR, HWND, LPWSTR); BOOL DeletePrinter(HANDLE); BOOL DeletePrinterConnectionA(LPSTR); BOOL DeletePrinterConnectionW(LPWSTR); DWORD DeletePrinterDataA(HANDLE, LPSTR); DWORD DeletePrinterDataW(HANDLE, LPWSTR); BOOL DeletePrinterDriverA(LPSTR, LPSTR, LPSTR); BOOL DeletePrinterDriverW(LPWSTR, LPWSTR, LPWSTR); BOOL DeletePrintProcessorA(LPSTR, LPSTR, LPSTR); BOOL DeletePrintProcessorW(LPWSTR, LPWSTR, LPWSTR); BOOL DeletePrintProvidorA(LPSTR, LPSTR, LPSTR); BOOL DeletePrintProvidorW(LPWSTR, LPWSTR, LPWSTR); LONG DocumentPropertiesA(HWND, HANDLE, LPSTR, PDEVMODEA, PDEVMODEA, DWORD); LONG DocumentPropertiesW(HWND, HANDLE, LPWSTR, PDEVMODEW, PDEVMODEW, DWORD); BOOL EndDocPrinter(HANDLE); BOOL EndPagePrinter(HANDLE); BOOL EnumFormsA(HANDLE, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumFormsW(HANDLE, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumJobsA(HANDLE, DWORD, DWORD, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumJobsW(HANDLE, DWORD, DWORD, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumMonitorsA(LPSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumMonitorsW(LPWSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumPortsA(LPSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumPortsW(LPWSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); DWORD EnumPrinterDataA(HANDLE, DWORD, LPSTR, DWORD, PDWORD, PDWORD, PBYTE, DWORD, PDWORD); DWORD EnumPrinterDataW(HANDLE, DWORD, LPWSTR, DWORD, PDWORD, PDWORD, PBYTE, DWORD, PDWORD); BOOL EnumPrinterDriversA(LPSTR, LPSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumPrinterDriversW(LPWSTR, LPWSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumPrintersA(DWORD, LPSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumPrintersW(DWORD, LPWSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumPrintProcessorDatatypesA(LPSTR, LPSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumPrintProcessorDatatypesW(LPWSTR, LPWSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumPrintProcessorsA(LPSTR, LPSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL EnumPrintProcessorsW(LPWSTR, LPWSTR, DWORD, PBYTE, DWORD, PDWORD, PDWORD); BOOL FindClosePrinterChangeNotification(HANDLE); HANDLE FindFirstPrinterChangeNotification(HANDLE, DWORD, DWORD, PVOID); HANDLE FindNextPrinterChangeNotification(HANDLE, PDWORD, PVOID, PVOID*); BOOL FreePrinterNotifyInfo(PPRINTER_NOTIFY_INFO); static if (_WIN32_WINNT >= 0x500) { BOOL GetDefaultPrinterA(LPSTR, LPDWORD); BOOL GetDefaultPrinterW(LPWSTR, LPDWORD); } BOOL GetFormA(HANDLE, LPSTR, DWORD, PBYTE, DWORD, PDWORD); BOOL GetFormW(HANDLE, LPWSTR, DWORD, PBYTE, DWORD, PDWORD); BOOL GetJobA(HANDLE, DWORD, DWORD, PBYTE, DWORD, PDWORD); BOOL GetJobW(HANDLE, DWORD, DWORD, PBYTE, DWORD, PDWORD); BOOL GetPrinterA(HANDLE, DWORD, PBYTE, DWORD, PDWORD); BOOL GetPrinterW(HANDLE, DWORD, PBYTE, DWORD, PDWORD); DWORD GetPrinterDataA(HANDLE, LPSTR, PDWORD, PBYTE, DWORD, PDWORD); DWORD GetPrinterDataW(HANDLE, LPWSTR, PDWORD, PBYTE, DWORD, PDWORD); DWORD GetPrinterDriverA(HANDLE, LPSTR, DWORD, PBYTE, DWORD, PDWORD); DWORD GetPrinterDriverW(HANDLE, LPWSTR, DWORD, PBYTE, DWORD, PDWORD); DWORD GetPrinterDriverDirectoryA(LPSTR, LPSTR, DWORD, PBYTE, DWORD, PDWORD); DWORD GetPrinterDriverDirectoryW(LPWSTR, LPWSTR, DWORD, PBYTE, DWORD, PDWORD); DWORD GetPrintProcessorDirectoryA(LPSTR, LPSTR, DWORD, PBYTE, DWORD, PDWORD); DWORD GetPrintProcessorDirectoryW(LPWSTR, LPWSTR, DWORD, PBYTE, DWORD, PDWORD); BOOL OpenPrinterA(LPSTR, PHANDLE, LPPRINTER_DEFAULTSA); BOOL OpenPrinterW(LPWSTR, PHANDLE, LPPRINTER_DEFAULTSW); DWORD PrinterMessageBoxA(HANDLE, DWORD, HWND, LPSTR, LPSTR, DWORD); DWORD PrinterMessageBoxW(HANDLE, DWORD, HWND, LPWSTR, LPWSTR, DWORD); BOOL PrinterProperties(HWND, HANDLE); BOOL ReadPrinter(HANDLE, PVOID, DWORD, PDWORD); BOOL ResetPrinterA(HANDLE, LPPRINTER_DEFAULTSA); BOOL ResetPrinterW(HANDLE, LPPRINTER_DEFAULTSW); BOOL ScheduleJob(HANDLE, DWORD); BOOL SetFormA(HANDLE, LPSTR, DWORD, PBYTE); BOOL SetFormW(HANDLE, LPWSTR, DWORD, PBYTE); BOOL SetJobA(HANDLE, DWORD, DWORD, PBYTE, DWORD); BOOL SetJobW(HANDLE, DWORD, DWORD, PBYTE, DWORD); BOOL SetPrinterA(HANDLE, DWORD, PBYTE, DWORD); BOOL SetPrinterW(HANDLE, DWORD, PBYTE, DWORD); BOOL SetPrinterDataA(HANDLE, LPSTR, DWORD, PBYTE, DWORD); BOOL SetPrinterDataW(HANDLE, LPWSTR, DWORD, PBYTE, DWORD); DWORD StartDocPrinterA(HANDLE, DWORD, PBYTE); DWORD StartDocPrinterW(HANDLE, DWORD, PBYTE); BOOL StartPagePrinter(HANDLE); DWORD WaitForPrinterChange(HANDLE, DWORD); BOOL WritePrinter(HANDLE, PVOID, DWORD, PDWORD); version(Unicode) { alias JOB_INFO_1W JOB_INFO_1; alias JOB_INFO_2W JOB_INFO_2; alias ADDJOB_INFO_1W ADDJOB_INFO_1; alias DATATYPES_INFO_1W DATATYPES_INFO_1; alias MONITOR_INFO_1W MONITOR_INFO_1; alias MONITOR_INFO_2W MONITOR_INFO_2; alias DOC_INFO_1W DOC_INFO_1; alias DOC_INFO_2W DOC_INFO_2; alias PORT_INFO_1W PORT_INFO_1; alias PORT_INFO_2W PORT_INFO_2; alias PORT_INFO_3W PORT_INFO_3; alias DRIVER_INFO_2W DRIVER_INFO_2; alias PRINTER_INFO_1W PRINTER_INFO_1; alias PRINTER_INFO_2W PRINTER_INFO_2; alias PRINTER_INFO_4W PRINTER_INFO_4; alias PRINTER_INFO_5W PRINTER_INFO_5; alias PRINTPROCESSOR_INFO_1W PRINTPROCESSOR_INFO_1; alias FORM_INFO_1W FORM_INFO_1; alias PRINTER_DEFAULTSW PRINTER_DEFAULTS; alias AddFormW AddForm; alias AddJobW AddJob; alias AddMonitorW AddMonitor; alias AddPortW AddPort; alias AddPrinterW AddPrinter; alias AddPrinterConnectionW AddPrinterConnection; alias AddPrinterDriverW AddPrinterDriver; alias AddPrintProcessorW AddPrintProcessor; alias AddPrintProvidorW AddPrintProvidor; alias AdvancedDocumentPropertiesW AdvancedDocumentProperties; alias ConfigurePortW ConfigurePort; alias DeleteFormW DeleteForm; alias DeleteMonitorW DeleteMonitor; alias DeletePortW DeletePort; alias DeletePrinterConnectionW DeletePrinterConnection; alias DeletePrinterDataW DeletePrinterData; alias DeletePrinterDriverW DeletePrinterDriver; alias DeletePrintProcessorW DeletePrintProcessor; alias DeletePrintProvidorW DeletePrintProvidor; alias DocumentPropertiesW DocumentProperties; alias EnumFormsW EnumForms; alias EnumJobsW EnumJobs; alias EnumMonitorsW EnumMonitors; alias EnumPortsW EnumPorts; alias EnumPrinterDataW EnumPrinterData; alias EnumPrinterDriversW EnumPrinterDrivers; alias EnumPrintersW EnumPrinters; alias EnumPrintProcessorDatatypesW EnumPrintProcessorDatatypes; alias EnumPrintProcessorsW EnumPrintProcessors; static if (_WIN32_WINNT >= 0x500) { alias GetDefaultPrinterW GetDefaultPrinter; } alias GetFormW GetForm; alias GetJobW GetJob; alias GetPrinterW GetPrinter; alias GetPrinterDataW GetPrinterData; alias GetPrinterDriverW GetPrinterDriver; alias GetPrinterDriverDirectoryW GetPrinterDriverDirectory; alias GetPrintProcessorDirectoryW GetPrintProcessorDirectory; alias OpenPrinterW OpenPrinter; alias PrinterMessageBoxW PrinterMessageBox; alias ResetPrinterW ResetPrinter; alias SetFormW SetForm; alias SetJobW SetJob; alias SetPrinterW SetPrinter; alias SetPrinterDataW SetPrinterData; alias StartDocPrinterW StartDocPrinter; } else { alias JOB_INFO_1A JOB_INFO_1; alias JOB_INFO_2A JOB_INFO_2; alias ADDJOB_INFO_1A ADDJOB_INFO_1; alias DATATYPES_INFO_1A DATATYPES_INFO_1; alias MONITOR_INFO_1A MONITOR_INFO_1; alias MONITOR_INFO_2A MONITOR_INFO_2; alias DOC_INFO_1A DOC_INFO_1; alias DOC_INFO_2A DOC_INFO_2; alias PORT_INFO_1A PORT_INFO_1; alias PORT_INFO_2A PORT_INFO_2; alias PORT_INFO_3A PORT_INFO_3; alias DRIVER_INFO_2A DRIVER_INFO_2; alias PRINTER_INFO_1A PRINTER_INFO_1; alias PRINTER_INFO_2A PRINTER_INFO_2; alias PRINTER_INFO_4A PRINTER_INFO_4; alias PRINTER_INFO_5A PRINTER_INFO_5; alias PRINTPROCESSOR_INFO_1A PRINTPROCESSOR_INFO_1; alias FORM_INFO_1A FORM_INFO_1; alias PRINTER_DEFAULTSA PRINTER_DEFAULTS; alias AddFormA AddForm; alias AddJobA AddJob; alias AddMonitorA AddMonitor; alias AddPortA AddPort; alias AddPrinterA AddPrinter; alias AddPrinterConnectionA AddPrinterConnection; alias AddPrinterDriverA AddPrinterDriver; alias AddPrintProcessorA AddPrintProcessor; alias AddPrintProvidorA AddPrintProvidor; alias AdvancedDocumentPropertiesA AdvancedDocumentProperties; alias ConfigurePortA ConfigurePort; alias DeleteFormA DeleteForm; alias DeleteMonitorA DeleteMonitor; alias DeletePortA DeletePort; alias DeletePrinterConnectionA DeletePrinterConnection; alias DeletePrinterDataA DeletePrinterData; alias DeletePrinterDriverA DeletePrinterDriver; alias DeletePrintProcessorA DeletePrintProcessor; alias DeletePrintProvidorA DeletePrintProvidor; alias DocumentPropertiesA DocumentProperties; alias EnumFormsA EnumForms; alias EnumJobsA EnumJobs; alias EnumMonitorsA EnumMonitors; alias EnumPortsA EnumPorts; alias EnumPrinterDataA EnumPrinterData; alias EnumPrinterDriversA EnumPrinterDrivers; alias EnumPrintersA EnumPrinters; alias EnumPrintProcessorDatatypesA EnumPrintProcessorDatatypes; alias EnumPrintProcessorsA EnumPrintProcessors; static if (_WIN32_WINNT >= 0x500) { alias GetDefaultPrinterA GetDefaultPrinter; } alias GetFormA GetForm; alias GetJobA GetJob; alias GetPrinterA GetPrinter; alias GetPrinterDataA GetPrinterData; alias GetPrinterDriverA GetPrinterDriver; alias GetPrinterDriverDirectoryA GetPrinterDriverDirectory; alias GetPrintProcessorDirectoryA GetPrintProcessorDirectory; alias OpenPrinterA OpenPrinter; alias PrinterMessageBoxA PrinterMessageBox; alias ResetPrinterA ResetPrinter; alias SetFormA SetForm; alias SetJobA SetJob; alias SetPrinterA SetPrinter; alias SetPrinterDataA SetPrinterData; alias StartDocPrinterA StartDocPrinter; } alias JOB_INFO_1* PJOB_INFO_1, LPJOB_INFO_1; alias JOB_INFO_2* PJOB_INFO_2, LPJOB_INFO_2; alias ADDJOB_INFO_1* PADDJOB_INFO_1, LPADDJOB_INFO_1; alias DATATYPES_INFO_1* PDATATYPES_INFO_1, LPDATATYPES_INFO_1; alias MONITOR_INFO_1* PMONITOR_INFO_1, LPMONITOR_INFO_1; alias MONITOR_INFO_2* PMONITOR_INFO_2, LPMONITOR_INFO_2; alias DOC_INFO_1* PDOC_INFO_1, LPDOC_INFO_1; alias DOC_INFO_2* PDOC_INFO_2, LPDOC_INFO_2; alias PORT_INFO_1* PPORT_INFO_1, LPPORT_INFO_1; alias PORT_INFO_2* PPORT_INFO_2, LPPORT_INFO_2; alias PORT_INFO_3* PPORT_INFO_3, LPPORT_INFO_3; alias DRIVER_INFO_2* PDRIVER_INFO_2, LPDRIVER_INFO_2; alias PRINTER_INFO_1* PPRINTER_INFO_1, LPPRINTER_INFO_1; alias PRINTER_INFO_2* PPRINTER_INFO_2, LPPRINTER_INFO_2; alias PRINTER_INFO_4* PPRINTER_INFO_4, LPPRINTER_INFO_4; alias PRINTER_INFO_5* PPRINTER_INFO_5, LPPRINTER_INFO_5; alias PRINTPROCESSOR_INFO_1* PPRINTPROCESSOR_INFO_1, LPPRINTPROCESSOR_INFO_1; alias FORM_INFO_1* PFORM_INFO_1, LPFORM_INFO_1; alias PRINTER_DEFAULTS* PPRINTER_DEFAULTS, LPPRINTER_DEFAULTS; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/shellapi.d0000664000175000017500000002615412776214756023470 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_shellapi.d) */ module core.sys.windows.shellapi; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "shell32"); private import core.sys.windows.w32api, core.sys.windows.windef, core.sys.windows.basetyps; enum : UINT { ABE_LEFT, ABE_TOP, ABE_RIGHT, ABE_BOTTOM // = 3 } enum : UINT { ABS_AUTOHIDE = 1, ABS_ALWAYSONTOP } enum ULONG SEE_MASK_CLASSNAME = 1, SEE_MASK_CLASSKEY = 3, SEE_MASK_IDLIST = 4, SEE_MASK_INVOKEIDLIST = 12, SEE_MASK_ICON = 0x000010, SEE_MASK_HOTKEY = 0x000020, SEE_MASK_NOCLOSEPROCESS = 0x000040, SEE_MASK_CONNECTNETDRV = 0x000080, SEE_MASK_FLAG_DDEWAIT = 0x000100, SEE_MASK_DOENVSUBST = 0x000200, SEE_MASK_FLAG_NO_UI = 0x000400, SEE_MASK_NO_CONSOLE = 0x008000, SEE_MASK_UNICODE = 0x010000, SEE_MASK_ASYNCOK = 0x100000, SEE_MASK_HMONITOR = 0x200000; enum : DWORD { ABM_NEW, ABM_REMOVE, ABM_QUERYPOS, ABM_SETPOS, ABM_GETSTATE, ABM_GETTASKBARPOS, ABM_ACTIVATE, ABM_GETAUTOHIDEBAR, ABM_SETAUTOHIDEBAR, ABM_WINDOWPOSCHANGED // = 9 } static if (_WIN32_WINNT >= 0x501) { enum DWORD ABM_SETSTATE = 10; } enum : UINT { ABN_STATECHANGE, ABN_POSCHANGED, ABN_FULLSCREENAPP, ABN_WINDOWARRANGE } enum : DWORD { NIM_ADD, NIM_MODIFY, NIM_DELETE } static if (_WIN32_IE >= 0x500) { enum NOTIFYICON_VERSION = 3; enum : DWORD { NIM_SETFOCUS = 3, NIM_SETVERSION } } enum UINT NIF_MESSAGE = 1, NIF_ICON = 2, NIF_TIP = 4, NIF_STATE = 8; static if (_WIN32_IE >= 0x500) { enum UINT NIF_INFO = 0x00000010; } static if (_WIN32_IE >= 0x600) { enum UINT NIF_GUID = 0x00000020; } static if (_WIN32_IE >= 0x500) { enum : DWORD { NIIF_NONE, NIIF_INFO, NIIF_WARNING, NIIF_ERROR } } static if (_WIN32_IE >= 0x600) { enum : DWORD { NIIF_ICON_MASK = 15, NIIF_NOSOUND } } enum DWORD NIS_HIDDEN = 1, NIS_SHAREDICON = 2; enum HINSTANCE SE_ERR_FNF = cast(HINSTANCE) 2, SE_ERR_PNF = cast(HINSTANCE) 3, SE_ERR_ACCESSDENIED = cast(HINSTANCE) 5, SE_ERR_OOM = cast(HINSTANCE) 8, SE_ERR_DLLNOTFOUND = cast(HINSTANCE) 32, SE_ERR_SHARE = cast(HINSTANCE) 26, SE_ERR_ASSOCINCOMPLETE = cast(HINSTANCE) 27, SE_ERR_DDETIMEOUT = cast(HINSTANCE) 28, SE_ERR_DDEFAIL = cast(HINSTANCE) 29, SE_ERR_DDEBUSY = cast(HINSTANCE) 30, SE_ERR_NOASSOC = cast(HINSTANCE) 31; enum : UINT { FO_MOVE = 1, FO_COPY, FO_DELETE, FO_RENAME } enum FILEOP_FLAGS FOF_MULTIDESTFILES = 0x0001, FOF_CONFIRMMOUSE = 0x0002, FOF_SILENT = 0x0004, FOF_RENAMEONCOLLISION = 0x0008, FOF_NOCONFIRMATION = 0x0010, FOF_WANTMAPPINGHANDLE = 0x0020, FOF_ALLOWUNDO = 0x0040, FOF_FILESONLY = 0x0080, FOF_SIMPLEPROGRESS = 0x0100, FOF_NOCONFIRMMKDIR = 0x0200, FOF_NOERRORUI = 0x0400, FOF_NOCOPYSECURITYATTRIBS = 0x0800; // these are not documented on the MSDN site enum { PO_DELETE = 19, PO_RENAME = 20, PO_PORTCHANGE = 32, PO_REN_PORT = 52 } enum UINT SHGFI_LARGEICON = 0x000000, SHGFI_SMALLICON = 0x000001, SHGFI_OPENICON = 0x000002, SHGFI_SHELLICONSIZE = 0x000004, SHGFI_PIDL = 0x000008, SHGFI_USEFILEATTRIBUTES = 0x000010, SHGFI_ICON = 0x000100, SHGFI_DISPLAYNAME = 0x000200, SHGFI_TYPENAME = 0x000400, SHGFI_ATTRIBUTES = 0x000800, SHGFI_ICONLOCATION = 0x001000, SHGFI_EXETYPE = 0x002000, SHGFI_SYSICONINDEX = 0x004000, SHGFI_LINKOVERLAY = 0x008000, SHGFI_SELECTED = 0x010000, SHGFI_ATTR_SPECIFIED = 0x020000; static if (_WIN32_IE >= 0x500) { enum uint SHGFI_ADDOVERLAYS = 0x000020, SHGFI_OVERLAYINDEX = 0x000040; } enum SHERB_NOCONFIRMATION = 1; enum SHERB_NOPROGRESSUI = 2; enum SHERB_NOSOUND = 4; alias WORD FILEOP_FLAGS, PRINTEROP_FLAGS; mixin DECLARE_HANDLE!("HDROP"); align(2): struct APPBARDATA { DWORD cbSize = APPBARDATA.sizeof; HWND hWnd; UINT uCallbackMessage; UINT uEdge; RECT rc; LPARAM lParam; } alias APPBARDATA* PAPPBARDATA; struct NOTIFYICONDATAA { DWORD cbSize = NOTIFYICONDATAA.sizeof; HWND hWnd; UINT uID; UINT uFlags; UINT uCallbackMessage; HICON hIcon; static if (_WIN32_IE >= 0x500) { CHAR[128] szTip; DWORD dwState; DWORD dwStateMask; CHAR[256] szInfo; union { UINT uTimeout; UINT uVersion; } CHAR[64] szInfoTitle; DWORD dwInfoFlags; } else { CHAR[64] szTip; } static if (_WIN32_IE >= 0x600) { GUID guidItem; } } alias NOTIFYICONDATAA* PNOTIFYICONDATAA; struct NOTIFYICONDATAW { DWORD cbSize = NOTIFYICONDATAW.sizeof; HWND hWnd; UINT uID; UINT uFlags; UINT uCallbackMessage; HICON hIcon; static if (_WIN32_IE >= 0x500) { WCHAR[128] szTip; DWORD dwState; DWORD dwStateMask; WCHAR[256] szInfo; union { UINT uTimeout; UINT uVersion; } WCHAR[64] szInfoTitle; DWORD dwInfoFlags; } else { WCHAR[64] szTip; } static if (_WIN32_IE >= 0x600) { GUID guidItem; } } alias NOTIFYICONDATAW* PNOTIFYICONDATAW; struct SHELLEXECUTEINFOA { DWORD cbSize = SHELLEXECUTEINFOA.sizeof; ULONG fMask; HWND hwnd; LPCSTR lpVerb; LPCSTR lpFile; LPCSTR lpParameters; LPCSTR lpDirectory; int nShow; HINSTANCE hInstApp; PVOID lpIDList; LPCSTR lpClass; HKEY hkeyClass; DWORD dwHotKey; HANDLE hIcon; HANDLE hProcess; } alias SHELLEXECUTEINFOA* LPSHELLEXECUTEINFOA; struct SHELLEXECUTEINFOW { DWORD cbSize = SHELLEXECUTEINFOW.sizeof; ULONG fMask; HWND hwnd; LPCWSTR lpVerb; LPCWSTR lpFile; LPCWSTR lpParameters; LPCWSTR lpDirectory; int nShow; HINSTANCE hInstApp; PVOID lpIDList; LPCWSTR lpClass; HKEY hkeyClass; DWORD dwHotKey; HANDLE hIcon; HANDLE hProcess; } alias SHELLEXECUTEINFOW* LPSHELLEXECUTEINFOW; struct SHFILEOPSTRUCTA { HWND hwnd; UINT wFunc; LPCSTR pFrom; LPCSTR pTo; FILEOP_FLAGS fFlags; BOOL fAnyOperationsAborted; PVOID hNameMappings; LPCSTR lpszProgressTitle; } alias SHFILEOPSTRUCTA* LPSHFILEOPSTRUCTA; struct SHFILEOPSTRUCTW { HWND hwnd; UINT wFunc; LPCWSTR pFrom; LPCWSTR pTo; FILEOP_FLAGS fFlags; BOOL fAnyOperationsAborted; PVOID hNameMappings; LPCWSTR lpszProgressTitle; } alias SHFILEOPSTRUCTW* LPSHFILEOPSTRUCTW; struct SHFILEINFOA { HICON hIcon; int iIcon; DWORD dwAttributes; CHAR[MAX_PATH] szDisplayName; CHAR[80] szTypeName; } struct SHFILEINFOW { HICON hIcon; int iIcon; DWORD dwAttributes; WCHAR[MAX_PATH] szDisplayName; WCHAR[80] szTypeName; } align(1) struct SHQUERYRBINFO { DWORD cbSize = SHQUERYRBINFO.sizeof; long i64Size; long i64NumItems; } alias SHQUERYRBINFO* LPSHQUERYRBINFO; extern (Windows) nothrow @nogc { LPWSTR* CommandLineToArgvW(LPCWSTR, int*); void DragAcceptFiles(HWND, BOOL); void DragFinish(HDROP); UINT DragQueryFileA(HDROP, UINT, LPSTR, UINT); UINT DragQueryFileW(HDROP, UINT, LPWSTR, UINT); BOOL DragQueryPoint(HDROP, LPPOINT); HICON DuplicateIcon(HINSTANCE, HICON); HICON ExtractAssociatedIconA(HINSTANCE, LPCSTR, PWORD); HICON ExtractAssociatedIconW(HINSTANCE, LPCWSTR, PWORD); HICON ExtractIconA(HINSTANCE, LPCSTR, UINT); HICON ExtractIconW(HINSTANCE, LPCWSTR, UINT); UINT ExtractIconExA(LPCSTR, int, HICON*, HICON*, UINT); UINT ExtractIconExW(LPCWSTR, int, HICON*, HICON*, UINT); HINSTANCE FindExecutableA(LPCSTR, LPCSTR, LPSTR); HINSTANCE FindExecutableW(LPCWSTR, LPCWSTR, LPWSTR); UINT SHAppBarMessage(DWORD, PAPPBARDATA); BOOL Shell_NotifyIconA(DWORD, PNOTIFYICONDATAA); BOOL Shell_NotifyIconW(DWORD, PNOTIFYICONDATAW); int ShellAboutA(HWND, LPCSTR, LPCSTR, HICON); int ShellAboutW(HWND, LPCWSTR, LPCWSTR, HICON); HINSTANCE ShellExecuteA(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT); HINSTANCE ShellExecuteW(HWND, LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR, INT); BOOL ShellExecuteExA(LPSHELLEXECUTEINFOA); BOOL ShellExecuteExW(LPSHELLEXECUTEINFOW); int SHFileOperationA(LPSHFILEOPSTRUCTA); int SHFileOperationW(LPSHFILEOPSTRUCTW); void SHFreeNameMappings(HANDLE); DWORD SHGetFileInfoA(LPCSTR, DWORD, SHFILEINFOA*, UINT, UINT); DWORD SHGetFileInfoW(LPCWSTR, DWORD, SHFILEINFOW*, UINT, UINT); HRESULT SHQueryRecycleBinA(LPCSTR, LPSHQUERYRBINFO); HRESULT SHQueryRecycleBinW(LPCWSTR, LPSHQUERYRBINFO); HRESULT SHEmptyRecycleBinA(HWND, LPCSTR, DWORD); HRESULT SHEmptyRecycleBinW(HWND, LPCWSTR, DWORD); } version (Unicode) { alias NOTIFYICONDATAW NOTIFYICONDATA; alias SHELLEXECUTEINFOW SHELLEXECUTEINFO; alias SHFILEOPSTRUCTW SHFILEOPSTRUCT; alias SHFILEINFOW SHFILEINFO; alias DragQueryFileW DragQueryFile; alias ExtractAssociatedIconW ExtractAssociatedIcon; alias ExtractIconW ExtractIcon; alias ExtractIconExW ExtractIconEx; alias FindExecutableW FindExecutable; alias Shell_NotifyIconW Shell_NotifyIcon; alias ShellAboutW ShellAbout; alias ShellExecuteW ShellExecute; alias ShellExecuteExW ShellExecuteEx; alias SHFileOperationW SHFileOperation; alias SHGetFileInfoW SHGetFileInfo; alias SHQueryRecycleBinW SHQueryRecycleBin; alias SHEmptyRecycleBinW SHEmptyRecycleBin; } else { alias NOTIFYICONDATAA NOTIFYICONDATA; alias SHELLEXECUTEINFOA SHELLEXECUTEINFO; alias SHFILEOPSTRUCTA SHFILEOPSTRUCT; alias SHFILEINFOA SHFILEINFO; alias DragQueryFileA DragQueryFile; alias ExtractAssociatedIconA ExtractAssociatedIcon; alias ExtractIconA ExtractIcon; alias ExtractIconExA ExtractIconEx; alias FindExecutableA FindExecutable; alias Shell_NotifyIconA Shell_NotifyIcon; alias ShellAboutA ShellAbout; alias ShellExecuteA ShellExecute; alias ShellExecuteExA ShellExecuteEx; alias SHFileOperationA SHFileOperation; alias SHGetFileInfoA SHGetFileInfo; alias SHQueryRecycleBinA SHQueryRecycleBin; alias SHEmptyRecycleBinA SHEmptyRecycleBin; } alias NOTIFYICONDATA* PNOTIFYICONDATA; alias SHELLEXECUTEINFO* LPSHELLEXECUTEINFO; alias SHFILEOPSTRUCT* LPSHFILEOPSTRUCT; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/mciavi.d0000664000175000017500000000224712776214756023134 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_mciavi.d) */ module core.sys.windows.mciavi; version (Windows): private import core.sys.windows.mmsystem; // FIXME: check types and grouping of constants enum MCI_MCIAVI_PLAY_WINDOW = 0x01000000; enum MCI_MCIAVI_PLAY_FULLSCREEN = 0x02000000; enum MCI_MCIAVI_PLAY_FULLBY2 = 0x04000000; enum { MCI_AVI_STATUS_FRAMES_SKIPPED = 0x00008001, MCI_AVI_STATUS_LAST_PLAY_SPEED = 0x00008002, MCI_AVI_STATUS_AUDIO_BREAKS = 0x00008003, MCI_AVI_SETVIDEO_DRAW_PROCEDURE = 0x00008000, MCI_AVI_SETVIDEO_PALETTE_COLOR = 0x00008100, MCI_AVI_SETVIDEO_PALETTE_HALFTONE = 0x0000FFFF } enum { MCIERR_AVI_OLDAVIFORMAT = MCIERR_CUSTOM_DRIVER_BASE + 100, MCIERR_AVI_NOTINTERLEAVED, MCIERR_AVI_NODISPDIB, MCIERR_AVI_CANTPLAYFULLSCREEN, MCIERR_AVI_TOOBIGFORVGA, MCIERR_AVI_NOCOMPRESSOR, MCIERR_AVI_DISPLAYERROR, MCIERR_AVI_AUDIOERROR, MCIERR_AVI_BADPALETTE // = MCIERR_CUSTOM_DRIVER_BASE + 108 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/imm.d0000664000175000017500000003460412776214756022450 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_imm.d) */ module core.sys.windows.imm; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "imm32"); import core.sys.windows.windef, core.sys.windows.wingdi; import core.sys.windows.winuser; // for the MFS_xxx enums. private import core.sys.windows.w32api; enum WM_CONVERTREQUESTEX = 0x108; enum WM_IME_STARTCOMPOSITION = 0x10D; enum WM_IME_ENDCOMPOSITION = 0x10E; enum WM_IME_COMPOSITION = 0x10F; enum WM_IME_KEYLAST = 0x10F; enum WM_IME_SETCONTEXT = 0x281; enum WM_IME_NOTIFY = 0x282; enum WM_IME_CONTROL = 0x283; enum WM_IME_COMPOSITIONFULL = 0x284; enum WM_IME_SELECT = 0x285; enum WM_IME_CHAR = 0x286; //static if (_WIN32_WINNT >= 0x500) { enum WM_IME_REQUEST = 0x288; //} enum WM_IME_KEYDOWN = 0x290; enum WM_IME_KEYUP = 0x291; enum IMC_GETCANDIDATEPOS=7; enum IMC_SETCANDIDATEPOS=8; enum IMC_GETCOMPOSITIONFONT=9; enum IMC_SETCOMPOSITIONFONT=10; enum IMC_GETCOMPOSITIONWINDOW=11; enum IMC_SETCOMPOSITIONWINDOW=12; enum IMC_GETSTATUSWINDOWPOS=15; enum IMC_SETSTATUSWINDOWPOS=16; enum IMC_CLOSESTATUSWINDOW=0x21; enum IMC_OPENSTATUSWINDOW=0x22; enum IMN_CLOSESTATUSWINDOW=1; enum IMN_OPENSTATUSWINDOW=2; enum IMN_CHANGECANDIDATE=3; enum IMN_CLOSECANDIDATE=4; enum IMN_OPENCANDIDATE=5; enum IMN_SETCONVERSIONMODE=6; enum IMN_SETSENTENCEMODE=7; enum IMN_SETOPENSTATUS=8; enum IMN_SETCANDIDATEPOS=9; enum IMN_SETCOMPOSITIONFONT=10; enum IMN_SETCOMPOSITIONWINDOW=11; enum IMN_SETSTATUSWINDOWPOS=12; enum IMN_GUIDELINE=13; enum IMN_PRIVATE=14; enum NI_OPENCANDIDATE=16; enum NI_CLOSECANDIDATE=17; enum NI_SELECTCANDIDATESTR=18; enum NI_CHANGECANDIDATELIST=19; enum NI_FINALIZECONVERSIONRESULT=20; enum NI_COMPOSITIONSTR=21; enum NI_SETCANDIDATE_PAGESTART=22; enum NI_SETCANDIDATE_PAGESIZE=23; enum NI_IMEMENUSELECTED=24; enum ISC_SHOWUICANDIDATEWINDOW=1; enum ISC_SHOWUICOMPOSITIONWINDOW=0x80000000; enum ISC_SHOWUIGUIDELINE=0x40000000; enum ISC_SHOWUIALLCANDIDATEWINDOW=15; enum ISC_SHOWUIALL=0xC000000F; enum CPS_COMPLETE=1; enum CPS_CONVERT=2; enum CPS_REVERT=3; enum CPS_CANCEL=4; enum IME_CHOTKEY_IME_NONIME_TOGGLE=16; enum IME_CHOTKEY_SHAPE_TOGGLE=17; enum IME_CHOTKEY_SYMBOL_TOGGLE=18; enum IME_JHOTKEY_CLOSE_OPEN=0x30; enum IME_KHOTKEY_SHAPE_TOGGLE=0x50; enum IME_KHOTKEY_HANJACONVERT=0x51; enum IME_KHOTKEY_ENGLISH=0x52; enum IME_THOTKEY_IME_NONIME_TOGGLE=0x70; enum IME_THOTKEY_SHAPE_TOGGLE=0x71; enum IME_THOTKEY_SYMBOL_TOGGLE=0x72; enum IME_HOTKEY_DSWITCH_FIRST=256; enum IME_HOTKEY_DSWITCH_LAST=0x11F; enum IME_ITHOTKEY_RESEND_RESULTSTR=512; enum IME_ITHOTKEY_PREVIOUS_COMPOSITION=513; enum IME_ITHOTKEY_UISTYLE_TOGGLE=514; enum GCS_COMPREADSTR=1; enum GCS_COMPREADATTR=2; enum GCS_COMPREADCLAUSE=4; enum GCS_COMPSTR=8; enum GCS_COMPATTR=16; enum GCS_COMPCLAUSE=32; enum GCS_CURSORPOS=128; enum GCS_DELTASTART=256; enum GCS_RESULTREADSTR=512; enum GCS_RESULTREADCLAUSE=1024; enum GCS_RESULTSTR=2048; enum GCS_RESULTCLAUSE=4096; enum CS_INSERTCHAR=0x2000; enum CS_NOMOVECARET=0x4000; enum IMEVER_0310=0x3000A; enum IMEVER_0400=0x40000; enum IME_PROP_AT_CARET=0x10000; enum IME_PROP_SPECIAL_UI=0x20000; enum IME_PROP_CANDLIST_START_FROM_1=0x40000; enum IME_PROP_UNICODE=0x80000; enum UI_CAP_2700=1; enum UI_CAP_ROT90=2; enum UI_CAP_ROTANY=4; enum SCS_CAP_COMPSTR=1; enum SCS_CAP_MAKEREAD=2; enum SELECT_CAP_CONVERSION=1; enum SELECT_CAP_SENTENCE=2; enum GGL_LEVEL=1; enum GGL_INDEX=2; enum GGL_STRING=3; enum GGL_PRIVATE=4; enum GL_LEVEL_NOGUIDELINE=0; enum GL_LEVEL_FATAL=1; enum GL_LEVEL_ERROR=2; enum GL_LEVEL_WARNING=3; enum GL_LEVEL_INFORMATION=4; enum GL_ID_UNKNOWN=0; enum GL_ID_NOMODULE=1; enum GL_ID_NODICTIONARY=16; enum GL_ID_CANNOTSAVE=17; enum GL_ID_NOCONVERT=32; enum GL_ID_TYPINGERROR=33; enum GL_ID_TOOMANYSTROKE=34; enum GL_ID_READINGCONFLICT=35; enum GL_ID_INPUTREADING=36; enum GL_ID_INPUTRADICAL=37; enum GL_ID_INPUTCODE=38; enum GL_ID_INPUTSYMBOL=39; enum GL_ID_CHOOSECANDIDATE=40; enum GL_ID_REVERSECONVERSION=41; enum GL_ID_PRIVATE_FIRST=0x8000; enum GL_ID_PRIVATE_LAST=0xFFFF; enum DWORD IGP_GETIMEVERSION = -4; enum IGP_PROPERTY=4; enum IGP_CONVERSION=8; enum IGP_SENTENCE=12; enum IGP_UI=16; enum IGP_SETCOMPSTR=0x14; enum IGP_SELECT=0x18; enum SCS_SETSTR = GCS_COMPREADSTR|GCS_COMPSTR; enum SCS_CHANGEATTR = GCS_COMPREADATTR|GCS_COMPATTR; enum SCS_CHANGECLAUSE = GCS_COMPREADCLAUSE|GCS_COMPCLAUSE; enum ATTR_INPUT=0; enum ATTR_TARGET_CONVERTED=1; enum ATTR_CONVERTED=2; enum ATTR_TARGET_NOTCONVERTED=3; enum ATTR_INPUT_ERROR=4; enum ATTR_FIXEDCONVERTED=5; enum CFS_DEFAULT=0; enum CFS_RECT=1; enum CFS_POINT=2; enum CFS_SCREEN=4; enum CFS_FORCE_POSITION=32; enum CFS_CANDIDATEPOS=64; enum CFS_EXCLUDE=128; enum GCL_CONVERSION=1; enum GCL_REVERSECONVERSION=2; enum GCL_REVERSE_LENGTH=3; enum IME_CMODE_ALPHANUMERIC=0; enum IME_CMODE_NATIVE=1; enum IME_CMODE_CHINESE=IME_CMODE_NATIVE; enum IME_CMODE_HANGEUL=IME_CMODE_NATIVE; enum IME_CMODE_HANGUL=IME_CMODE_NATIVE; enum IME_CMODE_JAPANESE=IME_CMODE_NATIVE; enum IME_CMODE_KATAKANA=2; enum IME_CMODE_LANGUAGE=3; enum IME_CMODE_FULLSHAPE=8; enum IME_CMODE_ROMAN=16; enum IME_CMODE_CHARCODE=32; enum IME_CMODE_HANJACONVERT=64; enum IME_CMODE_SOFTKBD=128; enum IME_CMODE_NOCONVERSION=256; enum IME_CMODE_EUDC=512; enum IME_CMODE_SYMBOL=1024; enum IME_CMODE_FIXED=2048; enum IME_SMODE_NONE=0; enum IME_SMODE_PLAURALCLAUSE=1; enum IME_SMODE_SINGLECONVERT=2; enum IME_SMODE_AUTOMATIC=4; enum IME_SMODE_PHRASEPREDICT=8; enum IME_CAND_UNKNOWN=0; enum IME_CAND_READ=1; enum IME_CAND_CODE=2; enum IME_CAND_MEANING=3; enum IME_CAND_RADICAL=4; enum IME_CAND_STROKE=5; enum IMM_ERROR_NODATA=(-1); enum IMM_ERROR_GENERAL=(-2); enum IME_CONFIG_GENERAL=1; enum IME_CONFIG_REGISTERWORD=2; enum IME_CONFIG_SELECTDICTIONARY=3; enum IME_ESC_QUERY_SUPPORT=3; enum IME_ESC_RESERVED_FIRST=4; enum IME_ESC_RESERVED_LAST=0x7FF; enum IME_ESC_PRIVATE_FIRST=0x800; enum IME_ESC_PRIVATE_LAST=0xFFF; enum IME_ESC_SEQUENCE_TO_INTERNAL=0x1001; enum IME_ESC_GET_EUDC_DICTIONARY=0x1003; enum IME_ESC_SET_EUDC_DICTIONARY=0x1004; enum IME_ESC_MAX_KEY=0x1005; enum IME_ESC_IME_NAME=0x1006; enum IME_ESC_SYNC_HOTKEY=0x1007; enum IME_ESC_HANJA_MODE=0x1008; enum IME_ESC_AUTOMATA=0x1009; enum IME_REGWORD_STYLE_EUDC=1; enum IME_REGWORD_STYLE_USER_FIRST=0x80000000; enum IME_REGWORD_STYLE_USER_LAST=0xFFFFFFFF; enum SOFTKEYBOARD_TYPE_T1=1; enum SOFTKEYBOARD_TYPE_C1=2; enum IMEMENUITEM_STRING_SIZE=80; enum MOD_ALT=1; enum MOD_CONTROL=2; enum MOD_SHIFT=4; enum MOD_WIN=8; enum MOD_IGNORE_ALL_MODIFIER=1024; enum MOD_ON_KEYUP=2048; enum MOD_RIGHT=16384; enum MOD_LEFT=32768; enum IACE_CHILDREN=1; enum IACE_DEFAULT=16; enum IACE_IGNORENOCONTEXT=32; enum IGIMIF_RIGHTMENU=1; enum IGIMII_CMODE=1; enum IGIMII_SMODE=2; enum IGIMII_CONFIGURE=4; enum IGIMII_TOOLS=8; enum IGIMII_HELP=16; enum IGIMII_OTHER=32; enum IGIMII_INPUTTOOLS=64; enum IMFT_RADIOCHECK=1; enum IMFT_SEPARATOR=2; enum IMFT_SUBMENU=4; enum IMFS_GRAYED=MFS_GRAYED; enum IMFS_DISABLED=MFS_DISABLED; enum IMFS_CHECKED=MFS_CHECKED; enum IMFS_HILITE=MFS_HILITE; enum IMFS_ENABLED=MFS_ENABLED; enum IMFS_UNCHECKED=MFS_UNCHECKED; enum IMFS_UNHILITE=MFS_UNHILITE; enum IMFS_DEFAULT=MFS_DEFAULT; enum STYLE_DESCRIPTION_SIZE=32; alias DWORD HIMC; alias DWORD HIMCC; alias HKL* LPHKL; struct COMPOSITIONFORM{ DWORD dwStyle; POINT ptCurrentPos; RECT rcArea; } alias COMPOSITIONFORM* PCOMPOSITIONFORM, LPCOMPOSITIONFORM; struct CANDIDATEFORM{ DWORD dwIndex; DWORD dwStyle; POINT ptCurrentPos; RECT rcArea; } alias CANDIDATEFORM* PCANDIDATEFORM, LPCANDIDATEFORM; struct CANDIDATELIST{ DWORD dwSize; DWORD dwStyle; DWORD dwCount; DWORD dwSelection; DWORD dwPageStart; DWORD dwPageSize; DWORD[1] dwOffset; } alias CANDIDATELIST* PCANDIDATELIST, LPCANDIDATELIST; struct REGISTERWORDA{ LPSTR lpReading; LPSTR lpWord; } alias REGISTERWORDA* PREGISTERWORDA, LPREGISTERWORDA; struct REGISTERWORDW{ LPWSTR lpReading; LPWSTR lpWord; } alias REGISTERWORDW* PREGISTERWORDW, LPREGISTERWORDW; struct STYLEBUFA{ DWORD dwStyle; CHAR[STYLE_DESCRIPTION_SIZE] szDescription; } alias STYLEBUFA* PSTYLEBUFA, LPSTYLEBUFA; struct STYLEBUFW{ DWORD dwStyle; WCHAR[STYLE_DESCRIPTION_SIZE] szDescription; } alias STYLEBUFW* PSTYLEBUFW, LPSTYLEBUFW; struct IMEMENUITEMINFOA{ UINT cbSize = this.sizeof; UINT fType; UINT fState; UINT wID; HBITMAP hbmpChecked; HBITMAP hbmpUnchecked; DWORD dwItemData; CHAR[IMEMENUITEM_STRING_SIZE] szString; HBITMAP hbmpItem; } alias IMEMENUITEMINFOA* PIMEMENUITEMINFOA, LPIMEMENUITEMINFOA; struct IMEMENUITEMINFOW{ UINT cbSize = this.sizeof; UINT fType; UINT fState; UINT wID; HBITMAP hbmpChecked; HBITMAP hbmpUnchecked; DWORD dwItemData; WCHAR[IMEMENUITEM_STRING_SIZE] szString; HBITMAP hbmpItem; } alias IMEMENUITEMINFOW* PIMEMENUITEMINFOW, LPIMEMENUITEMINFOW; alias int function (LPCSTR, DWORD, LPCSTR, LPVOID) REGISTERWORDENUMPROCA; alias int function (LPCWSTR, DWORD, LPCWSTR, LPVOID) REGISTERWORDENUMPROCW; version(Unicode) { alias REGISTERWORDENUMPROCW REGISTERWORDENUMPROC; alias REGISTERWORDW REGISTERWORD; alias IMEMENUITEMINFOW IMEMENUITEMINFO; alias STYLEBUFW STYLEBUF; } else { alias REGISTERWORDENUMPROCA REGISTERWORDENUMPROC; alias REGISTERWORDA REGISTERWORD; alias IMEMENUITEMINFOA IMEMENUITEMINFO; alias STYLEBUFA STYLEBUF; } alias STYLEBUF* PSTYLEBUF, LPSTYLEBUF; alias REGISTERWORD* PREGISTERWORD, LPREGISTERWORD; alias IMEMENUITEMINFO* PIMEMENUITEMINFO, LPIMEMENUITEMINFO; extern (Windows): HKL ImmInstallIMEA(LPCSTR, LPCSTR); HKL ImmInstallIMEW(LPCWSTR, LPCWSTR); HWND ImmGetDefaultIMEWnd(HWND); UINT ImmGetDescriptionA(HKL, LPSTR, UINT); UINT ImmGetDescriptionW(HKL, LPWSTR, UINT); UINT ImmGetIMEFileNameA(HKL, LPSTR, UINT); UINT ImmGetIMEFileNameW(HKL, LPWSTR, UINT); DWORD ImmGetProperty(HKL, DWORD); BOOL ImmIsIME(HKL); BOOL ImmSimulateHotKey(HWND, DWORD); HIMC ImmCreateContext(); BOOL ImmDestroyContext(HIMC); HIMC ImmGetContext(HWND); BOOL ImmReleaseContext(HWND, HIMC); HIMC ImmAssociateContext(HWND, HIMC); LONG ImmGetCompositionStringA(HIMC, DWORD, PVOID, DWORD); LONG ImmGetCompositionStringW(HIMC, DWORD, PVOID, DWORD); BOOL ImmSetCompositionStringA(HIMC, DWORD, PCVOID, DWORD, PCVOID, DWORD); BOOL ImmSetCompositionStringW(HIMC, DWORD, PCVOID, DWORD, PCVOID, DWORD); DWORD ImmGetCandidateListCountA(HIMC, PDWORD); DWORD ImmGetCandidateListCountW(HIMC, PDWORD); DWORD ImmGetCandidateListA(HIMC, DWORD, PCANDIDATELIST, DWORD); DWORD ImmGetCandidateListW(HIMC, DWORD, PCANDIDATELIST, DWORD); DWORD ImmGetGuideLineA(HIMC, DWORD, LPSTR, DWORD); DWORD ImmGetGuideLineW(HIMC, DWORD, LPWSTR, DWORD); BOOL ImmGetConversionStatus(HIMC, LPDWORD, PDWORD); BOOL ImmSetConversionStatus(HIMC, DWORD, DWORD); BOOL ImmGetOpenStatus(HIMC); BOOL ImmSetOpenStatus(HIMC, BOOL); BOOL ImmGetCompositionFontA(HIMC, LPLOGFONTA); BOOL ImmGetCompositionFontW(HIMC, LPLOGFONTW); BOOL ImmSetCompositionFontA(HIMC, LPLOGFONTA); BOOL ImmSetCompositionFontW(HIMC, LPLOGFONTW); BOOL ImmConfigureIMEA(HKL, HWND, DWORD, PVOID); BOOL ImmConfigureIMEW(HKL, HWND, DWORD, PVOID); LRESULT ImmEscapeA(HKL, HIMC, UINT, PVOID); LRESULT ImmEscapeW(HKL, HIMC, UINT, PVOID); DWORD ImmGetConversionListA(HKL, HIMC, LPCSTR, PCANDIDATELIST, DWORD, UINT); DWORD ImmGetConversionListW(HKL, HIMC, LPCWSTR, PCANDIDATELIST, DWORD, UINT); BOOL ImmNotifyIME(HIMC, DWORD, DWORD, DWORD); BOOL ImmGetStatusWindowPos(HIMC, LPPOINT); BOOL ImmSetStatusWindowPos(HIMC, LPPOINT); BOOL ImmGetCompositionWindow(HIMC, PCOMPOSITIONFORM); BOOL ImmSetCompositionWindow(HIMC, PCOMPOSITIONFORM); BOOL ImmGetCandidateWindow(HIMC, DWORD, PCANDIDATEFORM); BOOL ImmSetCandidateWindow(HIMC, PCANDIDATEFORM); BOOL ImmIsUIMessageA(HWND, UINT, WPARAM, LPARAM); BOOL ImmIsUIMessageW(HWND, UINT, WPARAM, LPARAM); UINT ImmGetVirtualKey(HWND); BOOL ImmRegisterWordA(HKL, LPCSTR, DWORD, LPCSTR); BOOL ImmRegisterWordW(HKL, LPCWSTR, DWORD, LPCWSTR); BOOL ImmUnregisterWordA(HKL, LPCSTR, DWORD, LPCSTR); BOOL ImmUnregisterWordW(HKL, LPCWSTR, DWORD, LPCWSTR); UINT ImmGetRegisterWordStyleA(HKL, UINT, PSTYLEBUFA); UINT ImmGetRegisterWordStyleW(HKL, UINT, PSTYLEBUFW); UINT ImmEnumRegisterWordA(HKL, REGISTERWORDENUMPROCA, LPCSTR, DWORD, LPCSTR, PVOID); UINT ImmEnumRegisterWordW(HKL, REGISTERWORDENUMPROCW, LPCWSTR, DWORD, LPCWSTR, PVOID); BOOL EnableEUDC(BOOL); BOOL ImmDisableIME(DWORD); DWORD ImmGetImeMenuItemsA(HIMC, DWORD, DWORD, LPIMEMENUITEMINFOA, LPIMEMENUITEMINFOA, DWORD); DWORD ImmGetImeMenuItemsW(HIMC, DWORD, DWORD, LPIMEMENUITEMINFOW, LPIMEMENUITEMINFOW, DWORD); version(Unicode) { alias ImmEnumRegisterWordW ImmEnumRegisterWord; alias ImmGetRegisterWordStyleW ImmGetRegisterWordStyle; alias ImmUnregisterWordW ImmUnregisterWord; alias ImmRegisterWordW ImmRegisterWord; alias ImmInstallIMEW ImmInstallIME; alias ImmIsUIMessageW ImmIsUIMessage; alias ImmGetConversionListW ImmGetConversionList; alias ImmEscapeW ImmEscape; alias ImmConfigureIMEW ImmConfigureIME; alias ImmSetCompositionFontW ImmSetCompositionFont; alias ImmGetCompositionFontW ImmGetCompositionFont; alias ImmGetGuideLineW ImmGetGuideLine; alias ImmGetCandidateListW ImmGetCandidateList; alias ImmGetCandidateListCountW ImmGetCandidateListCount; alias ImmSetCompositionStringW ImmSetCompositionString; alias ImmGetCompositionStringW ImmGetCompositionString; alias ImmGetDescriptionW ImmGetDescription; alias ImmGetIMEFileNameW ImmGetIMEFileName; alias ImmGetImeMenuItemsW ImmGetImeMenuItems; } else { alias ImmEnumRegisterWordA ImmEnumRegisterWord; alias ImmGetRegisterWordStyleA ImmGetRegisterWordStyle; alias ImmUnregisterWordA ImmUnregisterWord; alias ImmRegisterWordA ImmRegisterWord; alias ImmInstallIMEA ImmInstallIME; alias ImmIsUIMessageA ImmIsUIMessage; alias ImmGetConversionListA ImmGetConversionList; alias ImmEscapeA ImmEscape; alias ImmConfigureIMEA ImmConfigureIME; alias ImmSetCompositionFontA ImmSetCompositionFont; alias ImmGetCompositionFontA ImmGetCompositionFont; alias ImmGetGuideLineA ImmGetGuideLine; alias ImmGetCandidateListA ImmGetCandidateList; alias ImmGetCandidateListCountA ImmGetCandidateListCount; alias ImmSetCompositionStringA ImmSetCompositionString; alias ImmGetCompositionStringA ImmGetCompositionString; alias ImmGetDescriptionA ImmGetDescription; alias ImmGetIMEFileNameA ImmGetIMEFileName; alias ImmGetImeMenuItemsW ImmGetImeMenuItems; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/exdisp.d0000664000175000017500000001044512776214756023157 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_exdisp.d) */ module core.sys.windows.exdisp; version (Windows): import core.sys.windows.docobj, core.sys.windows.oaidl, core.sys.windows.ocidl; private import core.sys.windows.basetyps, core.sys.windows.windef, core.sys.windows.wtypes; enum BrowserNavConstants { navOpenInNewWindow = 0x01, navNoHistory = 0x02, navNoReadFromCache = 0x04, navNoWriteTocache = 0x08, navAllowAutosearch = 0x10, navBrowserBar = 0x20, navHyperLink = 0x40 } interface IWebBrowser : IDispatch { HRESULT GoBack(); HRESULT GoForward(); HRESULT GoHome(); HRESULT GoSearch(); HRESULT Navigate(BSTR, VARIANT*, VARIANT*, VARIANT*, VARIANT*); HRESULT Refresh(); HRESULT Refresh2(VARIANT*); HRESULT Stop(); HRESULT get_Application(IDispatch* ppDisp); HRESULT get_Parent(IDispatch* ppDisp); HRESULT get_Container(IDispatch* ppDisp); HRESULT get_Document(IDispatch* ppDisp); HRESULT get_TopLevelContainer(VARIANT_BOOL*); HRESULT get_Type(BSTR*); HRESULT get_Left(LONG*); HRESULT put_Left(LONG); HRESULT get_Top(LONG*); HRESULT put_Top(LONG); HRESULT get_Width(LONG*); HRESULT put_Width(LONG); HRESULT get_Height(LONG*); HRESULT put_Height(LONG); HRESULT get_LocationName(BSTR*); HRESULT get_LocationURL(BSTR*); HRESULT get_Busy(VARIANT_BOOL*); } interface IWebBrowserApp : IWebBrowser { HRESULT Quit(); HRESULT ClientToWindow(int*, int*); HRESULT PutProperty(BSTR, VARIANT); HRESULT GetProperty(BSTR, VARIANT*); HRESULT get_Name(BSTR*); HRESULT get_HWND(LONG*); HRESULT get_FullName(BSTR*); HRESULT get_Path(BSTR*); HRESULT get_Visible(VARIANT_BOOL*); HRESULT put_Visible(VARIANT_BOOL); HRESULT get_StatusBar(VARIANT_BOOL*); HRESULT put_StatusBar(VARIANT_BOOL); HRESULT get_StatusText(BSTR*); HRESULT put_StatusText(BSTR); HRESULT get_ToolBar(int*); HRESULT put_ToolBar(int); HRESULT get_MenuBar(VARIANT_BOOL*); HRESULT put_MenuBar(VARIANT_BOOL); HRESULT get_FullScreen(VARIANT_BOOL*); HRESULT put_FullScreen(VARIANT_BOOL); } interface IWebBrowser2 : IWebBrowserApp { HRESULT Navigate2(VARIANT*, VARIANT*, VARIANT*, VARIANT*, VARIANT*); HRESULT QueryStatusWB(OLECMDID, OLECMDF*); HRESULT ExecWB(OLECMDID, OLECMDEXECOPT, VARIANT*, VARIANT*); HRESULT ShowBrowserBar(VARIANT*, VARIANT*, VARIANT*); HRESULT get_ReadyState(READYSTATE*); HRESULT get_Offline(VARIANT_BOOL*); HRESULT put_Offline(VARIANT_BOOL); HRESULT get_Silent(VARIANT_BOOL*); HRESULT put_Silent(VARIANT_BOOL); HRESULT get_RegistaerAsBrowser(VARIANT_BOOL*); HRESULT put_RegisterAsBrowser(VARIANT_BOOL); HRESULT get_RegistaerAsDropTarget(VARIANT_BOOL*); HRESULT put_RegisterAsDropTarget(VARIANT_BOOL); HRESULT get_TheaterMode(VARIANT_BOOL*); HRESULT put_TheaterMode(VARIANT_BOOL); HRESULT get_AddressBar(VARIANT_BOOL*); HRESULT put_AddressBar(VARIANT_BOOL); HRESULT get_Resizable(VARIANT_BOOL*); HRESULT put_Resizable(VARIANT_BOOL); } interface DWebBrowserEvents2 : IDispatch { void StatusTextChange(BSTR); void ProgressChange(LONG, LONG); void CommandStateChange(LONG, VARIANT_BOOL); void DownloadBegin(); void DownloadComplete(); void TitleChange(BSTR); void PropertyChange(BSTR); void BeforeNavigate2(IDispatch pDisp, VARIANT*, VARIANT*, VARIANT*, VARIANT*, VARIANT*, VARIANT_BOOL*); void NewWindow2(IDispatch* ppDisp, VARIANT_BOOL*); void NavigateComplete(IDispatch pDisp, VARIANT*); void DocumentComplete(IDispatch pDisp, VARIANT*); void OnQuit(); void OnVisible(VARIANT_BOOL); void OnToolBar(VARIANT_BOOL); void OnMenuBar(VARIANT_BOOL); void OnStatusBar(VARIANT_BOOL); void OnFullScreen(VARIANT_BOOL); void OnTheaterMode(VARIANT_BOOL); void WindowSetResizable(VARIANT_BOOL); void WindowSetLeft(LONG); void WindowSetTop(LONG); void WindowSetWidth(LONG); void WindowSetHeight(LONG); void WindowClosing(VARIANT_BOOL, VARIANT_BOOL*); void ClientToHostWindow(LONG*, LONG*); void SetSecureLockIcon(LONG); void FileDownload(VARIANT_BOOL*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmcons.d0000664000175000017500000000430712776214756023156 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmcons.d) */ module core.sys.windows.lmcons; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.windef; private import core.sys.windows.lmerr; // for NERR_BASE const TCHAR[] MESSAGE_FILENAME = "NETMSG", OS2MSG_FILENAME = "BASE", HELP_MSG_FILENAME = "NETH"; alias DWORD NET_API_STATUS, API_RET_TYPE; enum MIN_LANMAN_MESSAGE_ID = NERR_BASE; enum MAX_LANMAN_MESSAGE_ID = 5799; enum CNLEN = 15; /* also in nddeapi.h */ enum UNCLEN = CNLEN + 2; enum DNLEN = 15; enum LM20_CNLEN = 15; enum LM20_DNLEN = 15; enum LM20_SNLEN = 15; enum LM20_STXTLEN = 63; enum LM20_UNCLEN = LM20_CNLEN + 2; enum LM20_NNLEN = 12; enum LM20_RMLEN = LM20_UNCLEN + 1 + LM20_NNLEN; enum NNLEN = 80; enum RMLEN = UNCLEN + 1 + NNLEN; enum SNLEN = 80; enum STXTLEN = 256; enum PATHLEN = 256; enum LM20_PATHLEN = 256; enum DEVLEN = 80; enum LM20_DEVLEN = 8; enum EVLEN = 16; enum UNLEN = 256; enum LM20_UNLEN = 20; enum GNLEN = UNLEN; enum LM20_GNLEN = LM20_UNLEN; enum PWLEN = 256; enum LM20_PWLEN = 14; enum SHPWLEN = 8; enum CLTYPE_LEN = 12; enum QNLEN = NNLEN; enum LM20_QNLEN = LM20_NNLEN; enum MAXCOMMENTSZ = 256; enum LM20_MAXCOMMENTSZ = 48; enum ALERTSZ = 128; enum MAXDEVENTRIES = 32;// (sizeof(int)*8); enum NETBIOS_NAME_LEN = 16; enum DWORD MAX_PREFERRED_LENGTH = -1; enum CRYPT_KEY_LEN = 7; enum CRYPT_TXT_LEN = 8; enum ENCRYPTED_PWLEN = 16; enum SESSION_PWLEN = 24; enum SESSION_CRYPT_KLEN = 21; enum PARMNUM_ALL = 0; enum DWORD PARM_ERROR_UNKNOWN = -1; enum PARM_ERROR_NONE = 0; enum PARMNUM_BASE_INFOLEVEL = 1000; enum PLATFORM_ID_DOS = 300; enum PLATFORM_ID_OS2 = 400; enum PLATFORM_ID_NT = 500; enum PLATFORM_ID_OSF = 600; enum PLATFORM_ID_VMS = 700; // this is a new typedef in W2K, but it should be harmless for earlier Windows versions. version (Unicode) { alias LPWSTR LMSTR; alias LPCWSTR LMCSTR; } else { alias LPSTR LMSTR; alias LPCSTR LMCSTR; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/wingdi.d0000664000175000017500000034244612776214756023155 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_wingdi.d) */ module core.sys.windows.wingdi; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "gdi32"); // FIXME: clean up Windows version support private import core.sys.windows.w32api, core.sys.windows.windef, core.sys.windows.winver; // BITMAPINFOHEADER.biCompression enum : DWORD { BI_RGB = 0, BI_RLE8, BI_RLE4, BI_BITFIELDS, BI_JPEG, BI_PNG } // --- // COLORADJUSTMENT -- only for NT 3.1+, Win2000+ enum WORD CA_NEGATIVE = 1, CA_LOG_FILTER = 2; // COLORADJUSTMENT enum : WORD { ILLUMINANT_DEVICE_DEFAULT = 0, ILLUMINANT_A, ILLUMINANT_B, ILLUMINANT_C, ILLUMINANT_D50, ILLUMINANT_D55, ILLUMINANT_D65, ILLUMINANT_D75, ILLUMINANT_F2, ILLUMINANT_MAX_INDEX = ILLUMINANT_F2, ILLUMINANT_TUNGSTEN = ILLUMINANT_A, ILLUMINANT_DAYLIGHT = ILLUMINANT_C, ILLUMINANT_FLUORESCENT = ILLUMINANT_F2, ILLUMINANT_NTSC = ILLUMINANT_C } enum { RGB_GAMMA_MIN = 2500, RGB_GAMMA_MAX = 65000, REFERENCE_WHITE_MIN = 6000, REFERENCE_WHITE_MAX = 10000, REFERENCE_BLACK_MIN = 0, REFERENCE_BLACK_MAX = 4000, COLOR_ADJ_MIN = -100, COLOR_ADJ_MAX = 100, } //--- /* FIXME: move to core.sys.windows.winuser ? */ // DrawIconEx() enum : UINT { DI_MASK = 1, DI_IMAGE = 2, DI_NORMAL = 3, DI_COMPAT = 4, DI_DEFAULTSIZE = 8 } // DOCINFO enum : DWORD { DI_APPBANDING = 1, DI_ROPS_READ_DESTINATION = 2, } // ENHMETAHEADER enum : DWORD { EMR_HEADER = 1, EMR_POLYBEZIER, EMR_POLYGON, EMR_POLYLINE, EMR_POLYBEZIERTO, EMR_POLYLINETO, EMR_POLYPOLYLINE, EMR_POLYPOLYGON, EMR_SETWINDOWEXTEX, EMR_SETWINDOWORGEX, EMR_SETVIEWPORTEXTEX, EMR_SETVIEWPORTORGEX, EMR_SETBRUSHORGEX, EMR_EOF, EMR_SETPIXELV, EMR_SETMAPPERFLAGS, EMR_SETMAPMODE, EMR_SETBKMODE, EMR_SETPOLYFILLMODE, EMR_SETROP2, EMR_SETSTRETCHBLTMODE, EMR_SETTEXTALIGN, EMR_SETCOLORADJUSTMENT, EMR_SETTEXTCOLOR, EMR_SETBKCOLOR, EMR_OFFSETCLIPRGN, EMR_MOVETOEX, EMR_SETMETARGN, EMR_EXCLUDECLIPRECT, EMR_INTERSECTCLIPRECT, EMR_SCALEVIEWPORTEXTEX, EMR_SCALEWINDOWEXTEX, EMR_SAVEDC, EMR_RESTOREDC, EMR_SETWORLDTRANSFORM, EMR_MODIFYWORLDTRANSFORM, EMR_SELECTOBJECT, EMR_CREATEPEN, EMR_CREATEBRUSHINDIRECT, EMR_DELETEOBJECT, EMR_ANGLEARC, EMR_ELLIPSE, EMR_RECTANGLE, EMR_ROUNDRECT, EMR_ARC, EMR_CHORD, EMR_PIE, EMR_SELECTPALETTE, EMR_CREATEPALETTE, EMR_SETPALETTEENTRIES, EMR_RESIZEPALETTE, EMR_REALIZEPALETTE, EMR_EXTFLOODFILL, EMR_LINETO, EMR_ARCTO, EMR_POLYDRAW, EMR_SETARCDIRECTION, EMR_SETMITERLIMIT, EMR_BEGINPATH, EMR_ENDPATH, EMR_CLOSEFIGURE, EMR_FILLPATH, EMR_STROKEANDFILLPATH, EMR_STROKEPATH, EMR_FLATTENPATH, EMR_WIDENPATH, EMR_SELECTCLIPPATH, EMR_ABORTPATH, // 68 // reserved 69 EMR_GDICOMMENT = 70, EMR_FILLRGN, EMR_FRAMERGN, EMR_INVERTRGN, EMR_PAINTRGN, EMR_EXTSELECTCLIPRGN, EMR_BITBLT, EMR_STRETCHBLT, EMR_MASKBLT, EMR_PLGBLT, EMR_SETDIBITSTODEVICE, EMR_STRETCHDIBITS, EMR_EXTCREATEFONTINDIRECTW, EMR_EXTTEXTOUTA, EMR_EXTTEXTOUTW, EMR_POLYBEZIER16, EMR_POLYGON16, EMR_POLYLINE16, EMR_POLYBEZIERTO16, EMR_POLYLINETO16, EMR_POLYPOLYLINE16, EMR_POLYPOLYGON16, EMR_POLYDRAW16, EMR_CREATEMONOBRUSH, EMR_CREATEDIBPATTERNBRUSHPT, EMR_EXTCREATEPEN, EMR_POLYTEXTOUTA, EMR_POLYTEXTOUTW, // 97 EMR_SETICMMODE, EMR_CREATECOLORSPACE, EMR_SETCOLORSPACE, EMR_DELETECOLORSPACE, EMR_GLSRECORD, EMR_GLSBOUNDEDRECORD, EMR_PIXELFORMAT, // = 104 // reserved 105 - 110 EMR_COLORCORRECTPALETTE = 111, EMR_SETICMPROFILEA, EMR_SETICMPROFILEW, EMR_ALPHABLEND, EMR_SETLAYOUT, EMR_TRANSPARENTBLT, // 116 // reserved 117 EMR_GRADIENTFILL = 118, // reserved 119, 120 EMR_COLORMATCHTOTARGETW = 121, EMR_CREATECOLORSPACEW // 122 } enum EMR_MIN = EMR_HEADER; static if (_WIN32_WINNT >= 0x500) { enum EMR_MAX = EMR_CREATECOLORSPACEW; } else { enum EMR_MAX = EMR_PIXELFORMAT; } // ENHMETAHEADER.dSignature, ENHMETAHEADER3.dSignature, // EMRFORMAT.dSignature enum : DWORD { ENHMETA_SIGNATURE = 1179469088, EPS_SIGNATURE = 0x46535045 } static if (_WIN32_WINNT >= 0x500) { // AddFontResourceEx() enum : DWORD { FR_PRIVATE = 0x10, FR_NOT_ENUM = 0x20 } } enum { META_SAVEDC = 0x1E, META_REALIZEPALETTE = 0x35, META_SETPALENTRIES = 0x37, META_CREATEPALETTE = 0xf7, META_SETBKMODE = 0x102, META_SETMAPMODE = 0x103, META_SETROP2 = 0x104, META_SETRELABS = 0x105, META_SETPOLYFILLMODE = 0x106, META_SETSTRETCHBLTMODE = 0x107, META_SETTEXTCHAREXTRA = 0x108, META_RESTOREDC = 0x127, META_INVERTREGION = 0x12A, META_PAINTREGION = 0x12B, META_SELECTCLIPREGION = 0x12C, META_SELECTOBJECT = 0x12D, META_SETTEXTALIGN = 0x12E, META_RESIZEPALETTE = 0x139, META_DIBCREATEPATTERNBRUSH = 0x142, META_SETLAYOUT = 0x149, META_DELETEOBJECT = 0x1F0, META_CREATEPATTERNBRUSH = 0x1F9, META_SETBKCOLOR = 0x201, META_SETTEXTCOLOR = 0x209, META_SETTEXTJUSTIFICATION = 0x20A, META_SETWINDOWORG = 0x20B, META_SETWINDOWEXT = 0x20C, META_SETVIEWPORTORG = 0x20D, META_SETVIEWPORTEXT = 0x20E, META_OFFSETWINDOWORG = 0x20F, META_OFFSETVIEWPORTORG = 0x211, META_LINETO = 0x213, META_MOVETO = 0x214, META_OFFSETCLIPRGN = 0x220, META_FILLREGION = 0x228, META_SETMAPPERFLAGS = 0x231, META_SELECTPALETTE = 0x234, META_CREATEPENINDIRECT = 0x2FA, META_CREATEFONTINDIRECT = 0x2FB, META_CREATEBRUSHINDIRECT = 0x2FC, META_POLYGON = 0x324, META_POLYLINE = 0x325, META_SCALEWINDOWEXT = 0x410, META_SCALEVIEWPORTEXT = 0x412, META_EXCLUDECLIPRECT = 0x415, META_INTERSECTCLIPRECT = 0x416, META_ELLIPSE = 0x418, META_FLOODFILL = 0x419, META_RECTANGLE = 0x41B, META_SETPIXEL = 0x41F, META_FRAMEREGION = 0x429, META_ANIMATEPALETTE = 0x436, META_TEXTOUT = 0x521, META_POLYPOLYGON = 0x538, META_EXTFLOODFILL = 0x548, META_ROUNDRECT = 0x61C, META_PATBLT = 0x61D, META_ESCAPE = 0x626, META_CREATEREGION = 0x6FF, META_ARC = 0x817, META_PIE = 0x81A, META_CHORD = 0x830, META_BITBLT = 0x922, META_DIBBITBLT = 0x940, META_EXTTEXTOUT = 0xA32, META_STRETCHBLT = 0xB23, META_DIBSTRETCHBLT = 0xB41, META_SETDIBTODEV = 0xD33, META_STRETCHDIB = 0xF43 } // EMRPOLYDRAW enum : BYTE { PT_CLOSEFIGURE = 1, PT_LINETO = 2, PT_BEZIERTO = 4, PT_MOVETO = 6 } // ---- // PIXELFORMATDESCRIPTOR.iPixelType enum : BYTE { PFD_TYPE_RGBA = 0, PFD_TYPE_COLORINDEX = 1 } //deprecated { // PIXELFORMATDESCRIPTOR. enum byte PFD_MAIN_PLANE = 0, PFD_OVERLAY_PLANE = 1, PFD_UNDERLAY_PLANE = -1; //} // PIXELFORMATDESCRIPTOR.dwFlags enum DWORD PFD_DOUBLEBUFFER = 0x00000001, PFD_STEREO = 0x00000002, PFD_DRAW_TO_WINDOW = 0x00000004, PFD_DRAW_TO_BITMAP = 0x00000008, PFD_SUPPORT_GDI = 0x00000010, PFD_SUPPORT_OPENGL = 0x00000020, PFD_GENERIC_FORMAT = 0x00000040, PFD_NEED_PALETTE = 0x00000080, PFD_NEED_SYSTEM_PALETTE = 0x00000100, PFD_SWAP_EXCHANGE = 0x00000200, PFD_SWAP_COPY = 0x00000400, PFD_SWAP_LAYER_BUFFERS = 0x00000800, PFD_GENERIC_ACCELERATED = 0x00001000, PFD_SUPPORT_DIRECTDRAW = 0x00002000, PFD_DIRECT3D_ACCELERATED = 0x00004000, PFD_SUPPORT_COMPOSITION = 0x00008000, /* PIXELFORMATDESCRIPTOR flags for use in ChoosePixelFormat only */ PFD_DEPTH_DONTCARE = 0x20000000, PFD_DOUBLEBUFFER_DONTCARE = 0x40000000, PFD_STEREO_DONTCARE = 0x80000000; // ---- enum DWORD BLACKNESS = 0x000042, NOTSRCERASE = 0x1100A6, NOTSRCCOPY = 0x330008, SRCERASE = 0x440328, DSTINVERT = 0x550009, PATINVERT = 0x5A0049, SRCINVERT = 0x660046, SRCAND = 0x8800C6, MERGEPAINT = 0xBB0226, MERGECOPY = 0xC000CA, SRCCOPY = 0xCC0020, SRCPAINT = 0xEE0086, PATCOPY = 0xF00021, PATPAINT = 0xFB0A09, WHITENESS = 0xFF0062; static if (_WIN32_WINNT >= 0x500) { enum DWORD NOMIRRORBITMAP = 0x80000000, CAPTUREBLT = 0x40000000; } // GetROP2(), SetROP2() enum : int { R2_BLACK = 1, R2_NOTMERGEPEN = 2, R2_MASKNOTPEN = 3, R2_NOTCOPYPEN = 4, R2_MASKPENNOT = 5, R2_NOT = 6, R2_XORPEN = 7, R2_NOTMASKPEN = 8, R2_MASKPEN = 9, R2_NOTXORPEN = 10, R2_NOP = 11, R2_MERGENOTPEN = 12, R2_COPYPEN = 13, R2_MERGEPENNOT = 14, R2_MERGEPEN = 15, R2_WHITE = 16 } enum R2_LAST = R2_WHITE; // CheckColorsInGamut() enum ubyte CM_IN_GAMUT = 0, CM_OUT_OF_GAMUT = 255; /* UpdateICMRegKey Constants */ enum int ICM_ADDPROFILE = 1, ICM_DELETEPROFILE = 2, ICM_QUERYPROFILE = 3, ICM_SETDEFAULTPROFILE = 4, ICM_REGISTERICMATCHER = 5, ICM_UNREGISTERICMATCHER = 6, ICM_QUERYMATCH = 7; enum : int { RGN_AND = 1, RGN_OR = 2, RGN_XOR = 3, RGN_DIFF = 4, RGN_COPY = 5 } enum RGN_MIN = RGN_AND; enum RGN_MAX = RGN_COPY; // Return values for CombineRgn() enum { NULLREGION = 1, SIMPLEREGION = 2, COMPLEXREGION = 3 } enum ERROR = 0; alias ERROR RGN_ERROR; // CreateDIBitmap() enum DWORD CBM_INIT = 4; // CreateDIBitmap() enum : UINT { DIB_RGB_COLORS = 0, DIB_PAL_COLORS = 1 } // --- // Values for LOGFONT and CreateFont() // FIXME: For D, replace with lfFaceName.length() enum LF_FACESIZE = 32; enum LF_FULLFACESIZE = 64; // FIXME: Not needed for D, only EXTLOGFONT enum ELF_VENDOR_SIZE = 4; // ??? enum ELF_VERSION = 0; enum ELF_CULTURE_LATIN = 0; // LOGFONT.lfWeight enum LONG FW_DONTCARE = 0, FW_THIN = 100, FW_EXTRALIGHT = 200, FW_ULTRALIGHT = FW_EXTRALIGHT, FW_LIGHT = 300, FW_NORMAL = 400, FW_REGULAR = FW_NORMAL, FW_MEDIUM = 500, FW_SEMIBOLD = 600, FW_DEMIBOLD = FW_SEMIBOLD, FW_BOLD = 700, FW_EXTRABOLD = 800, FW_ULTRABOLD = FW_EXTRABOLD, FW_HEAVY = 900, FW_BLACK = FW_HEAVY; // LOGFONT.lfCharSet enum : DWORD { ANSI_CHARSET = 0, DEFAULT_CHARSET = 1, SYMBOL_CHARSET = 2, MAC_CHARSET = 77, SHIFTJIS_CHARSET = 128, HANGEUL_CHARSET = 129, HANGUL_CHARSET = 129, JOHAB_CHARSET = 130, GB2312_CHARSET = 134, CHINESEBIG5_CHARSET = 136, GREEK_CHARSET = 161, TURKISH_CHARSET = 162, VIETNAMESE_CHARSET = 163, HEBREW_CHARSET = 177, ARABIC_CHARSET = 178, BALTIC_CHARSET = 186, RUSSIAN_CHARSET = 204, THAI_CHARSET = 222, EASTEUROPE_CHARSET = 238, OEM_CHARSET = 255 } // LOGFONT.lfOutPrecision enum : BYTE { OUT_DEFAULT_PRECIS = 0, OUT_STRING_PRECIS, OUT_CHARACTER_PRECIS, OUT_STROKE_PRECIS, OUT_TT_PRECIS, OUT_DEVICE_PRECIS, OUT_RASTER_PRECIS, OUT_TT_ONLY_PRECIS, OUT_OUTLINE_PRECIS, OUT_SCREEN_OUTLINE_PRECIS, OUT_PS_ONLY_PRECIS, // 10 } // LOGFONT.lfClipPrecision enum : BYTE { CLIP_DEFAULT_PRECIS = 0, CLIP_CHARACTER_PRECIS = 1, CLIP_STROKE_PRECIS = 2, CLIP_MASK = 15, CLIP_LH_ANGLES = 16, CLIP_TT_ALWAYS = 32, CLIP_DFA_DISABLE = 64, CLIP_EMBEDDED = 128 } // LOGFONT.lfQuality enum : BYTE { DEFAULT_QUALITY = 0, DRAFT_QUALITY, PROOF_QUALITY, NONANTIALIASED_QUALITY, ANTIALIASED_QUALITY } // LOGFONT.lfPitchAndFamily enum BYTE DEFAULT_PITCH = 0, FIXED_PITCH = 1, VARIABLE_PITCH = 2, MONO_FONT = 8, FF_DONTCARE = 0, FF_ROMAN = 16, FF_SWISS = 32, FF_SCRIPT = 64, FF_MODERN = 48, FF_DECORATIVE = 80; // ---- // Enums for the PANOSE struct enum PANOSE_COUNT=10; enum { PAN_FAMILYTYPE_INDEX = 0, PAN_SERIFSTYLE_INDEX, PAN_WEIGHT_INDEX, PAN_PROPORTION_INDEX, PAN_CONTRAST_INDEX, PAN_STROKEVARIATION_INDEX, PAN_ARMSTYLE_INDEX, PAN_LETTERFORM_INDEX, PAN_MIDLINE_INDEX, PAN_XHEIGHT_INDEX } enum PAN_CULTURE_LATIN=0; // NOTE: the first two values (PAN_ANY and PAN_NO_FIT) apply to all these enums! enum : BYTE { PAN_ANY = 0, PAN_NO_FIT = 1, } enum : BYTE { PAN_FAMILY_TEXT_DISPLAY = 2, PAN_FAMILY_SCRIPT, PAN_FAMILY_DECORATIVE, PAN_FAMILY_PICTORIAL } enum : BYTE { PAN_SERIF_COVE = 2, PAN_SERIF_OBTUSE_COVE, PAN_SERIF_SQUARE_COVE, PAN_SERIF_OBTUSE_SQUARE_COVE, PAN_SERIF_SQUARE, PAN_SERIF_THIN, PAN_SERIF_BONE, PAN_SERIF_EXAGGERATED, PAN_SERIF_TRIANGLE, PAN_SERIF_NORMAL_SANS, PAN_SERIF_OBTUSE_SANS, PAN_SERIF_PERP_SANS, PAN_SERIF_FLARED, PAN_SERIF_ROUNDED } enum : BYTE { PAN_WEIGHT_VERY_LIGHT = 2, PAN_WEIGHT_LIGHT, PAN_WEIGHT_THIN, PAN_WEIGHT_BOOK, PAN_WEIGHT_MEDIUM, PAN_WEIGHT_DEMI, PAN_WEIGHT_BOLD, PAN_WEIGHT_HEAVY, PAN_WEIGHT_BLACK, PAN_WEIGHT_NORD } enum : BYTE { PAN_PROP_OLD_STYLE = 2, PAN_PROP_MODERN, PAN_PROP_EVEN_WIDTH, PAN_PROP_EXPANDED, PAN_PROP_CONDENSED, PAN_PROP_VERY_EXPANDED, PAN_PROP_VERY_CONDENSED, PAN_PROP_MONOSPACED } enum : BYTE { PAN_CONTRAST_NONE = 2, PAN_CONTRAST_VERY_LOW, PAN_CONTRAST_LOW, PAN_CONTRAST_MEDIUM_LOW, PAN_CONTRAST_MEDIUM, PAN_CONTRAST_MEDIUM_HIGH, PAN_CONTRAST_HIGH, PAN_CONTRAST_VERY_HIGH } // PANOSE.bStrokeVariation enum : BYTE { PAN_STROKE_GRADUAL_DIAG = 2, PAN_STROKE_GRADUAL_TRAN, PAN_STROKE_GRADUAL_VERT, PAN_STROKE_GRADUAL_HORZ, PAN_STROKE_RAPID_VERT, PAN_STROKE_RAPID_HORZ, PAN_STROKE_INSTANT_VERT } // PANOSE.bArmStyle enum : BYTE { PAN_STRAIGHT_ARMS_HORZ = 2, PAN_STRAIGHT_ARMS_WEDGE, PAN_STRAIGHT_ARMS_VERT, PAN_STRAIGHT_ARMS_SINGLE_SERIF, PAN_STRAIGHT_ARMS_DOUBLE_SERIF, PAN_BENT_ARMS_HORZ, PAN_BENT_ARMS_WEDGE, PAN_BENT_ARMS_VERT, PAN_BENT_ARMS_SINGLE_SERIF, PAN_BENT_ARMS_DOUBLE_SERIF } // PANOSE.bLetterForm enum : BYTE { PAN_LETT_NORMAL_CONTACT = 2, PAN_LETT_NORMAL_WEIGHTED, PAN_LETT_NORMAL_BOXED, PAN_LETT_NORMAL_FLATTENED, PAN_LETT_NORMAL_ROUNDED, PAN_LETT_NORMAL_OFF_CENTER, PAN_LETT_NORMAL_SQUARE, PAN_LETT_OBLIQUE_CONTACT, PAN_LETT_OBLIQUE_WEIGHTED, PAN_LETT_OBLIQUE_BOXED, PAN_LETT_OBLIQUE_FLATTENED, PAN_LETT_OBLIQUE_ROUNDED, PAN_LETT_OBLIQUE_OFF_CENTER, PAN_LETT_OBLIQUE_SQUARE } // PANOSE.bMidLine enum : BYTE { PAN_MIDLINE_STANDARD_TRIMMED = 2, PAN_MIDLINE_STANDARD_POINTED, PAN_MIDLINE_STANDARD_SERIFED, PAN_MIDLINE_HIGH_TRIMMED, PAN_MIDLINE_HIGH_POINTED, PAN_MIDLINE_HIGH_SERIFED, PAN_MIDLINE_CONSTANT_TRIMMED, PAN_MIDLINE_CONSTANT_POINTED, PAN_MIDLINE_CONSTANT_SERIFED, PAN_MIDLINE_LOW_TRIMMED, PAN_MIDLINE_LOW_POINTED, PAN_MIDLINE_LOW_SERIFED } // PANOSE.bXHeight enum : BYTE { PAN_XHEIGHT_CONSTANT_SMALL = 2, PAN_XHEIGHT_CONSTANT_STD, PAN_XHEIGHT_CONSTANT_LARGE, PAN_XHEIGHT_DUCKING_SMALL, PAN_XHEIGHT_DUCKING_STD, PAN_XHEIGHT_DUCKING_LARGE } // ---- // ??? enum FS_LATIN1 = 0x00000001; enum FS_LATIN2 = 0x00000002; enum FS_CYRILLIC = 0x00000004; enum FS_GREEK = 0x00000008; enum FS_TURKISH = 0x00000010; enum FS_HEBREW = 0x00000020; enum FS_ARABIC = 0x00000040; enum FS_BALTIC = 0x00000080; enum FS_VIETNAMESE = 0x00000100; enum FS_THAI = 0x00010000; enum FS_JISJAPAN = 0x00020000; enum FS_CHINESESIMP = 0x00040000; enum FS_WANSUNG = 0x00080000; enum FS_CHINESETRAD = 0x00100000; enum FS_JOHAB = 0x00200000; enum FS_SYMBOL = 0x80000000; // ---- // Poly Fill Mode enum : int { ALTERNATE = 1, WINDING = 2 } enum int POLYFILL_LAST = WINDING; //--- // LOGBRUSH enum : LONG { HS_HORIZONTAL = 0, HS_VERTICAL, HS_FDIAGONAL, HS_BDIAGONAL, HS_CROSS, HS_DIAGCROSS } //LOGBRUSH.lbStyle enum : UINT { BS_SOLID = 0, BS_NULL = 1, BS_HOLLOW = BS_NULL, BS_HATCHED, BS_PATTERN, BS_INDEXED, BS_DIBPATTERN, BS_DIBPATTERNPT, BS_PATTERN8X8, BS_DIBPATTERN8X8, BS_MONOPATTERN, } //----- // EXTLOGPEN, ExtCreatePen() // EXTLOGPEN.elpPenStyle enum : DWORD { PS_SOLID = 0, PS_DASH = 1, PS_DOT = 2, PS_DASHDOT = 3, PS_DASHDOTDOT = 4, PS_NULL = 5, PS_INSIDEFRAME = 6, PS_USERSTYLE = 7, PS_ALTERNATE = 8, PS_STYLE_MASK = 15, } enum : DWORD { PS_COSMETIC = 0x00000000, PS_GEOMETRIC = 0x00010000, PS_TYPE_MASK = 0x000F0000, } enum : DWORD { PS_ENDCAP_ROUND = 0x00000000, PS_ENDCAP_SQUARE = 0x00000100, PS_ENDCAP_FLAT = 0x00000200, PS_ENDCAP_MASK = 0x00000F00, } enum : DWORD { PS_JOIN_ROUND = 0x00000000, PS_JOIN_BEVEL = 0x00001000, PS_JOIN_MITER = 0x00002000, PS_JOIN_MASK = 0x0000F000, } // --- // DeviceCapabilities() enum : WORD { DC_FIELDS = 1, DC_PAPERS, DC_PAPERSIZE, DC_MINEXTENT, DC_MAXEXTENT, DC_BINS, DC_DUPLEX, DC_SIZE, DC_EXTRA, DC_VERSION, DC_DRIVER, DC_BINNAMES, DC_ENUMRESOLUTIONS, DC_FILEDEPENDENCIES, DC_TRUETYPE, DC_PAPERNAMES, DC_ORIENTATION, DC_COPIES, DC_BINADJUST, DC_EMF_COMPLIANT, DC_DATATYPE_PRODUCED, DC_COLLATE, DC_MANUFACTURER, DC_MODEL, } static if (_WIN32_WINNT >= 0x500) { enum { DC_PERSONALITY = 25, DC_PRINTRATE = 26, DC_PRINTRATEUNIT = 27, DC_PRINTERMEM = 28, DC_MEDIAREADY = 29, DC_STAPLE = 30, DC_PRINTRATEPPM = 31, DC_COLORDEVICE = 32, DC_NUP = 33, DC_MEDIATYPENAMES = 34, DC_MEDIATYPES = 35, } enum { PRINTRATEUNIT_PPM = 1, PRINTRATEUNIT_CPS = 2, PRINTRATEUNIT_LPM = 3, PRINTRATEUNIT_IPM = 4, } } // return from DC_TRUETYPE enum DWORD DCTT_BITMAP = 1, DCTT_DOWNLOAD = 2, DCTT_SUBDEV = 4, DCTT_DOWNLOAD_OUTLINE = 8; // return from DC_BINADJUST enum : DWORD { DCBA_FACEUPNONE = 0x0000, DCBA_FACEUPCENTER = 0x0001, DCBA_FACEUPLEFT = 0x0002, DCBA_FACEUPRIGHT = 0x0003, DCBA_FACEDOWNNONE = 0x0100, DCBA_FACEDOWNCENTER = 0x0101, DCBA_FACEDOWNLEFT = 0x0102, DCBA_FACEDOWNRIGHT = 0x0103, } //--- enum FLOODFILLBORDER = 0; enum FLOODFILLSURFACE = 1; // ExtTextOut() enum UINT ETO_OPAQUE = 0x0002, ETO_CLIPPED = 0x0004, ETO_GLYPH_INDEX = 0x0010, ETO_RTLREADING = 0x0080, ETO_NUMERICSLOCAL = 0x0400, ETO_NUMERICSLATIN = 0x0800, ETO_IGNORELANGUAGE = 0x1000; static if (_WIN32_WINNT >= 0x500) { enum UINT ETO_PDY = 0x2000; } // GdiComment() enum { GDICOMMENT_BEGINGROUP = 0x00000002, GDICOMMENT_ENDGROUP = 0x00000003, GDICOMMENT_UNICODE_STRING = 0x00000040, GDICOMMENT_UNICODE_END = 0x00000080, GDICOMMENT_MULTIFORMATS = 0x40000004, GDICOMMENT_IDENTIFIER = 0x43494447, GDICOMMENT_WINDOWS_METAFILE = 0x80000001, } // Get/SetArcDirection() enum : int { AD_COUNTERCLOCKWISE = 1, AD_CLOCKWISE = 2 } enum RDH_RECTANGLES = 1; // GCPRESULTS.lpClass enum { GCPCLASS_LATIN = 1, GCPCLASS_HEBREW = 2, GCPCLASS_ARABIC = 2, GCPCLASS_NEUTRAL, GCPCLASS_LOCALNUMBER, GCPCLASS_LATINNUMBER, GCPCLASS_LATINNUMERICTERMINATOR, GCPCLASS_LATINNUMERICSEPARATOR, GCPCLASS_NUMERICSEPARATOR, // = 8, GCPCLASS_POSTBOUNDRTL = 16, GCPCLASS_POSTBOUNDLTR = 32, GCPCLASS_PREBOUNDRTL = 64, GCPCLASS_PREBOUNDLTR = 128, GCPGLYPH_LINKAFTER = 0x4000, GCPGLYPH_LINKBEFORE = 0x8000 } // GetBoundsRect(), SetBoundsRect() enum UINT DCB_RESET = 1, DCB_ACCUMULATE = 2, DCB_SET = DCB_RESET | DCB_ACCUMULATE, DCB_ENABLE = 4, DCB_DISABLE = 8, DCB_DIRTY = DCB_ACCUMULATE; //--- // GetObjectType() enum : DWORD { OBJ_PEN = 1, OBJ_BRUSH, OBJ_DC, OBJ_METADC, OBJ_PAL, OBJ_FONT, OBJ_BITMAP, OBJ_REGION, OBJ_METAFILE, OBJ_MEMDC, OBJ_EXTPEN, OBJ_ENHMETADC, OBJ_ENHMETAFILE, OBJ_COLORSPACE, } //--------------------- // Capabilities for GetDeviceCaps(dc, xxx) enum : int { DRIVERVERSION = 0, TECHNOLOGY = 2, HORZSIZE = 4, VERTSIZE = 6, HORZRES = 8, VERTRES = 10, BITSPIXEL = 12, PLANES = 14, NUMBRUSHES = 16, NUMPENS = 18, NUMMARKERS = 20, NUMFONTS = 22, NUMCOLORS = 24, PDEVICESIZE = 26, CURVECAPS = 28, LINECAPS = 30, POLYGONALCAPS = 32, TEXTCAPS = 34, CLIPCAPS = 36, RASTERCAPS = 38, ASPECTX = 40, ASPECTY = 42, ASPECTXY = 44, LOGPIXELSX = 88, LOGPIXELSY = 90, SIZEPALETTE = 104, NUMRESERVED = 106, COLORRES = 108, PHYSICALWIDTH = 110, PHYSICALHEIGHT = 111, PHYSICALOFFSETX = 112, PHYSICALOFFSETY = 113, SCALINGFACTORX = 114, SCALINGFACTORY = 115, VREFRESH = 116, DESKTOPVERTRES = 117, DESKTOPHORZRES = 118, BLTALIGNMENT = 119 } static if (_WIN32_WINNT >= 0x500) { enum : int { SHADEBLENDCAPS = 120, COLORMGMTCAPS = 121, } } // Return values for GetDeviceCaps(dc, TECHNOLOGY) enum : int { DT_PLOTTER = 0, DT_RASDISPLAY, DT_RASPRINTER, DT_RASCAMERA, DT_CHARSTREAM, DT_METAFILE, DT_DISPFILE // = 6 } // Return values for GetDeviceCaps(dc, RASTERCAPS) enum int RC_NONE = 0, RC_BITBLT = 1, RC_BANDING = 2, RC_SCALING = 4, RC_BITMAP64 = 8, RC_GDI20_OUTPUT = 16, RC_GDI20_STATE = 32, RC_SAVEBITMAP = 64, RC_DI_BITMAP = 128, RC_PALETTE = 256, RC_DIBTODEV = 512, RC_BIGFONT = 1024, RC_STRETCHBLT = 2048, RC_FLOODFILL = 4096, RC_STRETCHDIB = 8192, RC_OP_DX_OUTPUT = 0x4000, RC_DEVBITS = 0x8000; static if (_WIN32_WINNT >= 0x500) { /* Shading and blending caps */ enum SB_NONE = 0x00000000; enum SB_CONST_ALPHA = 0x00000001; enum SB_PIXEL_ALPHA = 0x00000002; enum SB_PREMULT_ALPHA = 0x00000004; enum SB_GRAD_RECT = 0x00000010; enum SB_GRAD_TRI = 0x00000020; /* Color Management caps */ enum CM_NONE = 0x00000000; enum CM_DEVICE_ICM = 0x00000001; enum CM_GAMMA_RAMP = 0x00000002; enum CM_CMYK_COLOR = 0x00000004; } // Return values for GetDeviceCaps(dc, CURVECAPS) enum int CC_NONE = 0, CC_CIRCLES = 1, CC_PIE = 2, CC_CHORD = 4, CC_ELLIPSES = 8, CC_WIDE = 16, CC_STYLED = 32, CC_WIDESTYLED = 64, CC_INTERIORS = 128, CC_ROUNDRECT = 256; // Return values for GetDeviceCaps(dc, LINECAPS) enum int LC_NONE = 0, LC_POLYLINE = 2, LC_MARKER = 4, LC_POLYMARKER = 8, LC_WIDE = 16, LC_STYLED = 32, LC_WIDESTYLED = 64, LC_INTERIORS = 128; // Return values for GetDeviceCaps(dc, POLYGONALCAPS) enum int PC_NONE = 0, PC_POLYGON = 1, PC_RECTANGLE = 2, PC_WINDPOLYGON = 4, PC_TRAPEZOID = 4, PC_SCANLINE = 8, PC_WIDE = 16, PC_STYLED = 32, PC_WIDESTYLED = 64, PC_INTERIORS = 128, PC_POLYPOLYGON = 256, PC_PATHS = 512; /* Clipping Capabilities */ enum int CP_NONE = 0, CP_RECTANGLE = 1, CP_REGION = 2; // Return values for GetDeviceCaps(dc, TEXTCAPS) enum int TC_OP_CHARACTER = 1, TC_OP_STROKE = 2, TC_CP_STROKE = 4, TC_CR_90 = 8, TC_CR_ANY = 16, TC_SF_X_YINDEP = 32, TC_SA_DOUBLE = 64, TC_SA_INTEGER = 128, TC_SA_CONTIN = 256, TC_EA_DOUBLE = 512, TC_IA_ABLE = 1024, TC_UA_ABLE = 2048, TC_SO_ABLE = 4096, TC_RA_ABLE = 8192, TC_VA_ABLE = 16384, TC_RESERVED = 32768, TC_SCROLLBLT = 65536; // End GetDeviceCaps //--------------------- // GetCharacterPlacement(), and GetFontLanguageInfo() enum DWORD GCP_DBCS = 1, GCP_REORDER = 2, GCP_USEKERNING = 8, GCP_GLYPHSHAPE = 16, GCP_LIGATE = 32, GCP_DIACRITIC = 256, GCP_KASHIDA = 1024, GCP_ERROR = 0x8000, GCP_JUSTIFY = 0x10000, GCP_CLASSIN = 0x80000, GCP_MAXEXTENT = 0x100000, GCP_JUSTIFYIN = 0x200000, GCP_DISPLAYZWG = 0x400000, GCP_SYMSWAPOFF = 0x800000, GCP_NUMERICOVERRIDE = 0x1000000, GCP_NEUTRALOVERRIDE = 0x2000000, GCP_NUMERICSLATIN = 0x4000000, GCP_NUMERICSLOCAL = 0x8000000, // Only for GetFontLanguageInfo() FLI_GLYPHS = 0x40000, FLI_MASK = 0x103b; // GetGlyphOutline() enum : UINT { GGO_METRICS = 0, GGO_BITMAP = 1, GGO_NATIVE = 2, GGO_BEZIER = 3, GGO_GRAY2_BITMAP = 4, GGO_GRAY4_BITMAP = 5, GGO_GRAY8_BITMAP = 6, GGO_GLYPH_INDEX = 128, GGO_UNHINTED = 256 } enum : int { GM_COMPATIBLE = 1, GM_ADVANCED } enum GM_LAST = GM_ADVANCED; enum : int { MM_TEXT = 1, MM_LOMETRIC, MM_HIMETRIC, MM_LOENGLISH, MM_HIENGLISH, MM_TWIPS, MM_ISOTROPIC, MM_ANISOTROPIC, } enum int MM_MIN = MM_TEXT, MM_MAX = MM_ANISOTROPIC, MM_MAX_FIXEDSCALE = MM_TWIPS; enum ABSOLUTE = 1; enum RELATIVE = 2; enum : BYTE { PC_RESERVED = 1, PC_EXPLICIT = 2, PC_NOCOLLAPSE = 4 } /* FIXME: move to core.sys.windows.commctrl ? */ // ImageList enum COLORREF CLR_NONE = 0xffffffff, CLR_INVALID = CLR_NONE, CLR_DEFAULT = 0xff000000; // RASTERIZER_STATUS.wFlags enum short TT_AVAILABLE = 1, TT_ENABLED = 2; // GetStockObject() enum : int { WHITE_BRUSH = 0, LTGRAY_BRUSH, GRAY_BRUSH, DKGRAY_BRUSH, BLACK_BRUSH, HOLLOW_BRUSH, // = 5 NULL_BRUSH = HOLLOW_BRUSH, WHITE_PEN = 6, BLACK_PEN, NULL_PEN, // = 8 OEM_FIXED_FONT = 10, ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_PALETTE, SYSTEM_FIXED_FONT, DEFAULT_GUI_FONT = SYSTEM_FIXED_FONT + 1, } static if (_WIN32_WINNT >= 0x500) { enum : int { DC_BRUSH = DEFAULT_GUI_FONT + 1, DC_PEN, } } static if (_WIN32_WINNT >= 0x500) { enum STOCK_LAST = DC_PEN; } else { enum STOCK_LAST = DEFAULT_GUI_FONT; } // Get/SetSystemPaletteUse() enum : UINT { SYSPAL_ERROR = 0, SYSPAL_STATIC = 1, SYSPAL_NOSTATIC = 2, SYSPAL_NOSTATIC256 = 3, } // SetTextAlign() enum UINT TA_TOP = 0, TA_CENTER = 6, TA_BOTTOM = 8, TA_BASELINE = 24, TA_LEFT = 0, TA_RIGHT = 2, TA_RTLREADING = 256, TA_NOUPDATECP = 0, TA_UPDATECP = 1, TA_MASK = TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING, VTA_BASELINE = TA_BASELINE, VTA_CENTER = TA_CENTER, VTA_LEFT = TA_BOTTOM, VTA_RIGHT = TA_TOP, VTA_BOTTOM = TA_RIGHT, VTA_TOP = TA_LEFT; // EMRMODIFYWORLDTRANSFORM.iMode enum : DWORD { MWT_IDENTITY = 1, MWT_LEFTMULTIPLY, MWT_RIGHTMULTIPLY } enum DWORD MWT_MIN = MWT_IDENTITY, MWT_MAX = MWT_RIGHTMULTIPLY; enum { TRANSPARENT = 1, OPAQUE = 2 } // Get/SetStretchMode() enum : int { BLACKONWHITE = 1, WHITEONBLACK = 2, COLORONCOLOR = 3, HALFTONE = 4, STRETCH_ANDSCANS = 1, STRETCH_ORSCANS = 2, STRETCH_DELETESCANS = 3, STRETCH_HALFTONE = 4, MAXSTRETCHBLTMODE = 4 } // TranslateCharsetInfo() enum : DWORD { TCI_SRCCHARSET = 1, TCI_SRCCODEPAGE = 2, TCI_SRCFONTSIG = 3, TCI_SRCLOCALE = 0x1000, } // SetICMMode() enum : int { ICM_OFF = 1, ICM_ON = 2, ICM_QUERY = 3, ICM_DONE_OUTSIDEDC = 4, } // ---- // Escape() Spooler Error Codes enum : int { SP_NOTREPORTED = 0x4000, SP_ERROR = -1, SP_APPABORT = -2, SP_USERABORT = -3, SP_OUTOFDISK = -4, SP_OUTOFMEMORY = -5 } // Escape(), ExtEscape() // Most of the following are deprecated (Win16 only) enum : int { NEWFRAME = 1, ABORTDOC = 2, NEXTBAND = 3, SETCOLORTABLE = 4, GETCOLORTABLE = 5, FLUSHOUTPUT = 6, DRAFTMODE = 7, QUERYESCSUPPORT = 8, SETABORTPROC = 9, STARTDOC = 10, ENDDOC = 11, GETPHYSPAGESIZE = 12, GETPRINTINGOFFSET = 13, GETSCALINGFACTOR = 14, MFCOMMENT = 15, GETPENWIDTH = 16, SETCOPYCOUNT = 17, SELECTPAPERSOURCE = 18, DEVICEDATA = 19, PASSTHROUGH = 19, GETTECHNOLOGY = 20, SETLINECAP = 21, SETLINEJOIN = 22, SETMITERLIMIT = 23, BANDINFO = 24, DRAWPATTERNRECT = 25, GETVECTORPENSIZE = 26, GETVECTORBRUSHSIZE = 27, ENABLEDUPLEX = 28, GETSETPAPERBINS = 29, GETSETPRINTORIENT = 30, ENUMPAPERBINS = 31, SETDIBSCALING = 32, EPSPRINTING = 33, ENUMPAPERMETRICS = 34, GETSETPAPERMETRICS = 35, POSTSCRIPT_DATA = 37, POSTSCRIPT_IGNORE = 38, MOUSETRAILS = 39, GETDEVICEUNITS = 42, GETEXTENDEDTEXTMETRICS = 256, GETEXTENTTABLE = 257, GETPAIRKERNTABLE = 258, GETTRACKKERNTABLE = 259, EXTTEXTOUT = 512, GETFACENAME = 513, DOWNLOADFACE = 514, ENABLERELATIVEWIDTHS = 768, ENABLEPAIRKERNING = 769, SETKERNTRACK = 770, SETALLJUSTVALUES = 771, SETCHARSET = 772, STRETCHBLT = 2048, METAFILE_DRIVER = 2049, GETSETSCREENPARAMS = 3072, QUERYDIBSUPPORT = 3073, BEGIN_PATH = 4096, CLIP_TO_PATH = 4097, END_PATH = 4098, EXT_DEVICE_CAPS = 4099, RESTORE_CTM = 4100, SAVE_CTM = 4101, SET_ARC_DIRECTION = 4102, SET_BACKGROUND_COLOR = 4103, SET_POLY_MODE = 4104, SET_SCREEN_ANGLE = 4105, SET_SPREAD = 4106, TRANSFORM_CTM = 4107, SET_CLIP_BOX = 4108, SET_BOUNDS = 4109, SET_MIRROR_MODE = 4110, OPENCHANNEL = 4110, DOWNLOADHEADER = 4111, CLOSECHANNEL = 4112, POSTSCRIPT_PASSTHROUGH = 4115, ENCAPSULATED_POSTSCRIPT = 4116, POSTSCRIPT_IDENTIFY = 4117, POSTSCRIPT_INJECTION = 4118, CHECKJPEGFORMAT = 4119, CHECKPNGFORMAT = 4120, GET_PS_FEATURESETTING = 4121, SPCLPASSTHROUGH2 = 4568, } enum : int { PSIDENT_GDICENTRIC = 0, PSIDENT_PSCENTRIC = 1, } /* * Header structure for the input buffer to POSTSCRIPT_INJECTION escape */ struct PSINJECTDATA { DWORD DataBytes; WORD InjectionPoint; WORD PageNumber; } alias PSINJECTDATA* PPSINJECTDATA; /* Constants for PSINJECTDATA.InjectionPoint field */ enum { PSINJECT_BEGINSTREAM = 1, PSINJECT_PSADOBE = 2, PSINJECT_PAGESATEND = 3, PSINJECT_PAGES = 4, PSINJECT_DOCNEEDEDRES = 5, PSINJECT_DOCSUPPLIEDRES = 6, PSINJECT_PAGEORDER = 7, PSINJECT_ORIENTATION = 8, PSINJECT_BOUNDINGBOX = 9, PSINJECT_DOCUMENTPROCESSCOLORS = 10, PSINJECT_COMMENTS = 11, PSINJECT_BEGINDEFAULTS = 12, PSINJECT_ENDDEFAULTS = 13, PSINJECT_BEGINPROLOG = 14, PSINJECT_ENDPROLOG = 15, PSINJECT_BEGINSETUP = 16, PSINJECT_ENDSETUP = 17, PSINJECT_TRAILER = 18, PSINJECT_EOF = 19, PSINJECT_ENDSTREAM = 20, PSINJECT_DOCUMENTPROCESSCOLORSATEND = 21, PSINJECT_PAGENUMBER = 100, PSINJECT_BEGINPAGESETUP = 101, PSINJECT_ENDPAGESETUP = 102, PSINJECT_PAGETRAILER = 103, PSINJECT_PLATECOLOR = 104, PSINJECT_SHOWPAGE = 105, PSINJECT_PAGEBBOX = 106, PSINJECT_ENDPAGECOMMENTS = 107, PSINJECT_VMSAVE = 200, PSINJECT_VMRESTORE = 201, } /* Parameter for GET_PS_FEATURESETTING escape */ enum { FEATURESETTING_NUP = 0, FEATURESETTING_OUTPUT = 1, FEATURESETTING_PSLEVEL = 2, FEATURESETTING_CUSTPAPER = 3, FEATURESETTING_MIRROR = 4, FEATURESETTING_NEGATIVE = 5, FEATURESETTING_PROTOCOL = 6, } enum { FEATURESETTING_PRIVATE_BEGIN = 0x1000, FEATURESETTING_PRIVATE_END = 0x1FFF, } /* Value returned for FEATURESETTING_PROTOCOL */ enum PSPROTOCOL_ASCII = 0; enum PSPROTOCOL_BCP = 1; enum PSPROTOCOL_TBCP = 2; enum PSPROTOCOL_BINARY = 3; // ---- enum WPARAM PR_JOBSTATUS = 0; // ??? enum QDI_SETDIBITS = 1; enum QDI_GETDIBITS = 2; enum QDI_DIBTOSCREEN = 4; enum QDI_STRETCHDIB = 8; enum ASPECT_FILTERING = 1; // LOGCOLORSPACE.lcsCSType enum : LCSCSTYPE { LCS_CALIBRATED_RGB = 0, LCS_DEVICE_RGB, LCS_DEVICE_CMYK } /* What this for? */ // LOGCOLORSPACE.lcsIntent enum : LCSGAMUTMATCH { LCS_GM_BUSINESS = 1, LCS_GM_GRAPHICS = 2, LCS_GM_IMAGES = 4, LCS_GM_ABS_COLORIMETRIC = 8, } enum DWORD RASTER_FONTTYPE = 1, DEVICE_FONTTYPE = 2, TRUETYPE_FONTTYPE = 4; // --- // DEVMODE struct // FIXME: Not needed for D (use .length instead) enum CCHDEVICENAME = 32; enum CCHFORMNAME = 32; // DEVMODE.dmSpecVersion // current version of specification enum WORD DM_SPECVERSION = 0x0401; // DEVMODE.dmOrientation enum : short { DMORIENT_PORTRAIT = 1, DMORIENT_LANDSCAPE = 2 } // DEVMODE.dmPaperSize enum : short { DMPAPER_LETTER = 1, DMPAPER_LETTERSMALL, DMPAPER_TABLOID, DMPAPER_LEDGER, DMPAPER_LEGAL, DMPAPER_STATEMENT, DMPAPER_EXECUTIVE, DMPAPER_A3, DMPAPER_A4, DMPAPER_A4SMALL, DMPAPER_A5, DMPAPER_B4, DMPAPER_B5, DMPAPER_FOLIO, DMPAPER_QUARTO, DMPAPER_10X14, DMPAPER_11X17, DMPAPER_NOTE, DMPAPER_ENV_9, DMPAPER_ENV_10, DMPAPER_ENV_11, DMPAPER_ENV_12, DMPAPER_ENV_14, DMPAPER_CSHEET, DMPAPER_DSHEET, DMPAPER_ESHEET, DMPAPER_ENV_DL, DMPAPER_ENV_C5, DMPAPER_ENV_C3, DMPAPER_ENV_C4, DMPAPER_ENV_C6, DMPAPER_ENV_C65, DMPAPER_ENV_B4, DMPAPER_ENV_B5, DMPAPER_ENV_B6, DMPAPER_ENV_ITALY, DMPAPER_ENV_MONARCH, DMPAPER_ENV_PERSONAL, DMPAPER_FANFOLD_US, DMPAPER_FANFOLD_STD_GERMAN, DMPAPER_FANFOLD_LGL_GERMAN, DMPAPER_ISO_B4, DMPAPER_JAPANESE_POSTCARD, DMPAPER_9X11, DMPAPER_10X11, DMPAPER_15X11, DMPAPER_ENV_INVITE, DMPAPER_RESERVED_48, DMPAPER_RESERVED_49, DMPAPER_LETTER_EXTRA, DMPAPER_LEGAL_EXTRA, DMPAPER_TABLOID_EXTRA, DMPAPER_A4_EXTRA, DMPAPER_LETTER_TRANSVERSE, DMPAPER_A4_TRANSVERSE, DMPAPER_LETTER_EXTRA_TRANSVERSE, DMPAPER_A_PLUS, DMPAPER_B_PLUS, DMPAPER_LETTER_PLUS, DMPAPER_A4_PLUS, DMPAPER_A5_TRANSVERSE, DMPAPER_B5_TRANSVERSE, DMPAPER_A3_EXTRA, DMPAPER_A5_EXTRA, DMPAPER_B5_EXTRA, DMPAPER_A2, DMPAPER_A3_TRANSVERSE, DMPAPER_A3_EXTRA_TRANSVERSE // = 68 } static if (_WIN32_WINNT >= 0x500) { enum : short { DMPAPER_DBL_JAPANESE_POSTCARD = 69, DMPAPER_A6, DMPAPER_JENV_KAKU2, DMPAPER_JENV_KAKU3, DMPAPER_JENV_CHOU3, DMPAPER_JENV_CHOU4, DMPAPER_LETTER_ROTATED, DMPAPER_A3_ROTATED, DMPAPER_A4_ROTATED, DMPAPER_A5_ROTATED, DMPAPER_B4_JIS_ROTATED, DMPAPER_B5_JIS_ROTATED, DMPAPER_JAPANESE_POSTCARD_ROTATED, DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED, DMPAPER_A6_ROTATED, DMPAPER_JENV_KAKU2_ROTATED, DMPAPER_JENV_KAKU3_ROTATED, DMPAPER_JENV_CHOU3_ROTATED, DMPAPER_JENV_CHOU4_ROTATED, DMPAPER_B6_JIS, DMPAPER_B6_JIS_ROTATED, DMPAPER_12X11, DMPAPER_JENV_YOU4, DMPAPER_JENV_YOU4_ROTATED, DMPAPER_P16K, DMPAPER_P32K, DMPAPER_P32KBIG, DMPAPER_PENV_1, DMPAPER_PENV_2, DMPAPER_PENV_3, DMPAPER_PENV_4, DMPAPER_PENV_5, DMPAPER_PENV_6, DMPAPER_PENV_7, DMPAPER_PENV_8, DMPAPER_PENV_9, DMPAPER_PENV_10, DMPAPER_P16K_ROTATED, DMPAPER_P32K_ROTATED, DMPAPER_P32KBIG_ROTATED, DMPAPER_PENV_1_ROTATED, DMPAPER_PENV_2_ROTATED, DMPAPER_PENV_3_ROTATED, DMPAPER_PENV_4_ROTATED, DMPAPER_PENV_5_ROTATED, DMPAPER_PENV_6_ROTATED, DMPAPER_PENV_7_ROTATED, DMPAPER_PENV_8_ROTATED, DMPAPER_PENV_9_ROTATED, DMPAPER_PENV_10_ROTATED // 118 } } enum short DMPAPER_FIRST = DMPAPER_LETTER; static if (_WIN32_WINNT >= 0x500) { enum short DMPAPER_LAST = DMPAPER_PENV_10_ROTATED; } else { enum short DMPAPER_LAST = DMPAPER_A3_EXTRA_TRANSVERSE; } enum short DMPAPER_USER = 256; // DEVMODE.dmDefaultSource enum : short { DMBIN_ONLYONE = 1, DMBIN_UPPER = 1, DMBIN_LOWER, DMBIN_MIDDLE, DMBIN_MANUAL, DMBIN_ENVELOPE, DMBIN_ENVMANUAL, DMBIN_AUTO, DMBIN_TRACTOR, DMBIN_SMALLFMT, DMBIN_LARGEFMT, DMBIN_LARGECAPACITY, // = 11 DMBIN_CASSETTE = 14, DMBIN_FORMSOURCE, } enum : short { DMBIN_FIRST = DMBIN_UPPER, DMBIN_LAST = DMBIN_FORMSOURCE, DMBIN_USER = 256, } // DEVMODE.dmPrintQuality enum : short { DMRES_DRAFT = -1, DMRES_LOW = -2, DMRES_MEDIUM = -3, DMRES_HIGH = -4 } // DEVMODE.dmColor enum : short { DMCOLOR_MONOCHROME = 1, DMCOLOR_COLOR = 2 } // DEVMODE.dmDuplex enum : short { DMDUP_SIMPLEX = 1, DMDUP_VERTICAL = 2, DMDUP_HORIZONTAL = 3 } // DEVMODE.dmTTOption enum : short { DMTT_BITMAP = 1, DMTT_DOWNLOAD, DMTT_SUBDEV, DMTT_DOWNLOAD_OUTLINE } // DEVMODE.dmCollate enum : short { DMCOLLATE_FALSE = 0, DMCOLLATE_TRUE } static if (_WIN32_WINNT >= 0x501) { /* DEVMODE dmDisplayOrientation specifiations */ enum : short { DMDO_DEFAULT = 0, DMDO_90 = 1, DMDO_180 = 2, DMDO_270 = 3, } /* DEVMODE dmDisplayFixedOutput specifiations */ enum : short { DMDFO_DEFAULT = 0, DMDFO_STRETCH = 1, DMDFO_CENTER = 2, } } /* FIXME: this flags are deprecated ? */ // DEVMODE.dmDisplayFlags enum DWORD DM_GRAYSCALE = 1, DM_INTERLACED = 2; enum DWORD DMDISPLAYFLAGS_TEXTMODE = 0x00000004; /* dmNup , multiple logical page per physical page options */ enum DWORD DMNUP_SYSTEM = 1, DMNUP_ONEUP = 2; // DEVMODE.dmFields enum DWORD DM_ORIENTATION = 0x00000001, DM_PAPERSIZE = 0x00000002, DM_PAPERLENGTH = 0x00000004, DM_PAPERWIDTH = 0x00000008, DM_SCALE = 0x00000010; static if (_WIN32_WINNT >= 0x500) { enum DWORD DM_POSITION = 0x00000020, DM_NUP = 0x00000040; } static if (_WIN32_WINNT >= 0x501) { enum DWORD DM_DISPLAYORIENTATION = 0x00000080; } enum DWORD DM_COPIES = 0x00000100, DM_DEFAULTSOURCE = 0x00000200, DM_PRINTQUALITY = 0x00000400, DM_COLOR = 0x00000800, DM_DUPLEX = 0x00001000, DM_YRESOLUTION = 0x00002000, DM_TTOPTION = 0x00004000, DM_COLLATE = 0x00008000, DM_FORMNAME = 0x00010000, DM_LOGPIXELS = 0x00020000, DM_BITSPERPEL = 0x00040000, DM_PELSWIDTH = 0x00080000, DM_PELSHEIGHT = 0x00100000, DM_DISPLAYFLAGS = 0x00200000, DM_DISPLAYFREQUENCY = 0x00400000, DM_ICMMETHOD = 0x00800000, DM_ICMINTENT = 0x01000000, DM_MEDIATYPE = 0x02000000, DM_DITHERTYPE = 0x04000000, DM_PANNINGWIDTH = 0x08000000, DM_PANNINGHEIGHT = 0x10000000; static if (_WIN32_WINNT >= 0x501) { enum DWORD DM_DISPLAYFIXEDOUTPUT = 0x20000000; } // DEVMODE.dmICMMethod enum : DWORD { DMICMMETHOD_NONE = 1, DMICMMETHOD_SYSTEM = 2, DMICMMETHOD_DRIVER = 3, DMICMMETHOD_DEVICE = 4, DMICMMETHOD_USER = 256 } // DEVMODE.dmICMIntent enum : DWORD { DMICM_SATURATE = 1, DMICM_CONTRAST = 2, DMICM_COLORIMETRIC = 3, DMICM_ABS_COLORIMETRIC = 4, DMICM_USER = 256 } // DEVMODE.dmMediaType enum : DWORD { DMMEDIA_STANDARD = 1, DMMEDIA_TRANSPARENCY = 2, DMMEDIA_GLOSSY = 3, DMMEDIA_USER = 256 } // DEVMODE.dmDitherType enum : DWORD { DMDITHER_NONE = 1, DMDITHER_COARSE, DMDITHER_FINE, DMDITHER_LINEART, DMDITHER_ERRORDIFFUSION, DMDITHER_RESERVED6, DMDITHER_RESERVED7, DMDITHER_RESERVED8, DMDITHER_RESERVED9, DMDITHER_GRAYSCALE, DMDITHER_USER = 256 } // ---- // DocumentProperties() enum DWORD DM_UPDATE = 1, DM_COPY = 2, DM_PROMPT = 4, DM_MODIFY = 8, DM_IN_BUFFER = DM_MODIFY, DM_IN_PROMPT = DM_PROMPT, DM_OUT_BUFFER = DM_COPY, DM_OUT_DEFAULT = DM_UPDATE; // --- enum GDI_ERROR = 0xFFFFFFFF; enum HGDI_ERROR= cast(HANDLE)GDI_ERROR; // TEXTMETRIC.tmPitchAndFamily enum BYTE TMPF_FIXED_PITCH = 1, TMPF_VECTOR = 2, TMPF_TRUETYPE = 4, TMPF_DEVICE = 8; // NEWTEXTMETRIC.ntmFlags enum DWORD NTM_ITALIC = 0x00000001, NTM_BOLD = 0x00000020, NTM_REGULAR = 0x00000040, NTM_NONNEGATIVE_AC = 0x00010000, NTM_PS_OPENTYPE = 0x00020000, NTM_TT_OPENTYPE = 0x00040000, NTM_MULTIPLEMASTER = 0x00080000, NTM_TYPE1 = 0x00100000, NTM_DSIG = 0x00200000; // --- enum DWORD TT_POLYGON_TYPE = 24; // TTPOLYCURVE enum : WORD { TT_PRIM_LINE = 1, TT_PRIM_QSPLINE = 2, TT_PRIM_CSPLINE = 3, } // --- enum FONTMAPPER_MAX = 10; enum ENHMETA_STOCK_OBJECT = 0x80000000; enum WGL_FONT_LINES = 0; enum WGL_FONT_POLYGONS = 1; // --- // LAYERPLANEDESCRIPTOR.dwFlags enum DWORD LPD_DOUBLEBUFFER = 1, LPD_STEREO = 2, LPD_SUPPORT_GDI = 16, LPD_SUPPORT_OPENGL = 32, LPD_SHARE_DEPTH = 64, LPD_SHARE_STENCIL = 128, LPD_SHARE_ACCUM = 256, LPD_SWAP_EXCHANGE = 512, LPD_SWAP_COPY = 1024, LPD_TRANSPARENT = 4096; // LAYERPLANEDESCRIPTOR.iPixelType enum : BYTE { LPD_TYPE_RGBA = 0, LPD_TYPE_COLORINDEX = 1 } // --- // wglSwapLayerBuffers() enum UINT WGL_SWAP_MAIN_PLANE = 1, WGL_SWAP_OVERLAY1 = 2, WGL_SWAP_OVERLAY2 = 4, WGL_SWAP_OVERLAY3 = 8, WGL_SWAP_OVERLAY4 = 16, WGL_SWAP_OVERLAY5 = 32, WGL_SWAP_OVERLAY6 = 64, WGL_SWAP_OVERLAY7 = 128, WGL_SWAP_OVERLAY8 = 256, WGL_SWAP_OVERLAY9 = 512, WGL_SWAP_OVERLAY10 = 1024, WGL_SWAP_OVERLAY11 = 2048, WGL_SWAP_OVERLAY12 = 4096, WGL_SWAP_OVERLAY13 = 8192, WGL_SWAP_OVERLAY14 = 16384, WGL_SWAP_OVERLAY15 = 32768, WGL_SWAP_UNDERLAY1 = 65536, WGL_SWAP_UNDERLAY2 = 0x20000, WGL_SWAP_UNDERLAY3 = 0x40000, WGL_SWAP_UNDERLAY4 = 0x80000, WGL_SWAP_UNDERLAY5 = 0x100000, WGL_SWAP_UNDERLAY6 = 0x200000, WGL_SWAP_UNDERLAY7 = 0x400000, WGL_SWAP_UNDERLAY8 = 0x800000, WGL_SWAP_UNDERLAY9 = 0x1000000, WGL_SWAP_UNDERLAY10 = 0x2000000, WGL_SWAP_UNDERLAY11 = 0x4000000, WGL_SWAP_UNDERLAY12 = 0x8000000, WGL_SWAP_UNDERLAY13 = 0x10000000, WGL_SWAP_UNDERLAY14 = 0x20000000, WGL_SWAP_UNDERLAY15 = 0x40000000; enum AC_SRC_OVER = 0x00; enum AC_SRC_ALPHA = 0x01; // ??? enum AC_SRC_NO_PREMULT_ALPHA = 0x01; enum AC_SRC_NO_ALPHA = 0x02; enum AC_DST_NO_PREMULT_ALPHA = 0x10; enum AC_DST_NO_ALPHA = 0x20; enum LAYOUT_RTL = 1; enum LAYOUT_BTT = 2; enum LAYOUT_VBH = 4; enum LAYOUT_BITMAPORIENTATIONPRESERVED = 8; enum CS_ENABLE = 0x00000001; enum CS_DISABLE = 0x00000002; enum CS_DELETE_TRANSFORM = 0x00000003; static if (_WIN32_WINNT > 0x500) { enum GRADIENT_FILL_RECT_H=0x00; enum GRADIENT_FILL_RECT_V=0x01; enum GRADIENT_FILL_TRIANGLE=0x02; enum GRADIENT_FILL_OP_FLAG=0xff; enum COLORMATCHTOTARGET_EMBEDED=0x00000001; enum CREATECOLORSPACE_EMBEDED=0x00000001; enum SETICMPROFILE_EMBEDED=0x00000001; } // DISPLAY_DEVICE.StateFlags enum DWORD DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = 0x00000001, DISPLAY_DEVICE_MULTI_DRIVER = 0x00000002, DISPLAY_DEVICE_PRIMARY_DEVICE = 0x00000004, DISPLAY_DEVICE_MIRRORING_DRIVER = 0x00000008, DISPLAY_DEVICE_VGA_COMPATIBLE = 0x00000010, DISPLAY_DEVICE_REMOVABLE = 0x00000020, DISPLAY_DEVICE_DISCONNECT = 0x02000000, DISPLAY_DEVICE_REMOTE = 0x04000000, DISPLAY_DEVICE_MODESPRUNED = 0x08000000; /* Child device state */ enum DWORD DISPLAY_DEVICE_ACTIVE = 0x00000001, DISPLAY_DEVICE_ATTACHED = 0x00000002; static if (_WIN32_WINNT >= 0x500) { enum GGI_MARK_NONEXISTING_GLYPHS = 1; } // ---------- // STRUCTS // ---------- struct ABC { int abcA; UINT abcB; int abcC; } alias ABC* PABC, NPABC, LPABC; struct ABCFLOAT { FLOAT abcfA; FLOAT abcfB; FLOAT abcfC; } alias ABCFLOAT* PABCFLOAT, NPABCFLOAT, LPABCFLOAT; struct BITMAP { LONG bmType; LONG bmWidth; LONG bmHeight; LONG bmWidthBytes; WORD bmPlanes; WORD bmBitsPixel; LPVOID bmBits; } alias BITMAP* PBITMAP, NPBITMAP, LPBITMAP; struct BITMAPCOREHEADER { DWORD bcSize; WORD bcWidth; WORD bcHeight; WORD bcPlanes; WORD bcBitCount; } alias BITMAPCOREHEADER* PBITMAPCOREHEADER, LPBITMAPCOREHEADER; align(1): struct RGBTRIPLE { BYTE rgbtBlue; BYTE rgbtGreen; BYTE rgbtRed; } alias RGBTRIPLE* LPRGBTRIPLE; align(2): struct BITMAPFILEHEADER { align(2): WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } alias BITMAPFILEHEADER* LPBITMAPFILEHEADER, PBITMAPFILEHEADER; align: struct BITMAPCOREINFO { BITMAPCOREHEADER bmciHeader; RGBTRIPLE[1] bmciColors; } alias BITMAPCOREINFO* LPBITMAPCOREINFO, PBITMAPCOREINFO; struct BITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } alias BITMAPINFOHEADER* LPBITMAPINFOHEADER, PBITMAPINFOHEADER; struct RGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; }; alias RGBQUAD* LPRGBQUAD; struct BITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD[1] bmiColors; }; alias BITMAPINFO* PBITMAPINFO, LPBITMAPINFO; alias int FXPT16DOT16; alias int* LPFXPT16DOT16; alias int FXPT2DOT30; alias int* LPFXPT2DOT30; struct CIEXYZ { FXPT2DOT30 ciexyzX; FXPT2DOT30 ciexyzY; FXPT2DOT30 ciexyzZ; } alias CIEXYZ* LPCIEXYZ; struct CIEXYZTRIPLE { CIEXYZ ciexyzRed; CIEXYZ ciexyzGreen; CIEXYZ ciexyzBlue; } alias CIEXYZTRIPLE* LPCIEXYZTRIPLE; struct BITMAPV4HEADER { DWORD bV4Size; LONG bV4Width; LONG bV4Height; WORD bV4Planes; WORD bV4BitCount; DWORD bV4V4Compression; DWORD bV4SizeImage; LONG bV4XPelsPerMeter; LONG bV4YPelsPerMeter; DWORD bV4ClrUsed; DWORD bV4ClrImportant; DWORD bV4RedMask; DWORD bV4GreenMask; DWORD bV4BlueMask; DWORD bV4AlphaMask; DWORD bV4CSType; CIEXYZTRIPLE bV4Endpoints; DWORD bV4GammaRed; DWORD bV4GammaGreen; DWORD bV4GammaBlue; } alias BITMAPV4HEADER* LPBITMAPV4HEADER, PBITMAPV4HEADER; struct BITMAPV5HEADER { DWORD bV5Size; LONG bV5Width; LONG bV5Height; WORD bV5Planes; WORD bV5BitCount; DWORD bV5Compression; DWORD bV5SizeImage; LONG bV5XPelsPerMeter; LONG bV5YPelsPerMeter; DWORD bV5ClrUsed; DWORD bV5ClrImportant; DWORD bV5RedMask; DWORD bV5GreenMask; DWORD bV5BlueMask; DWORD bV5AlphaMask; DWORD bV5CSType; CIEXYZTRIPLE bV5Endpoints; DWORD bV5GammaRed; DWORD bV5GammaGreen; DWORD bV5GammaBlue; DWORD bV5Intent; DWORD bV5ProfileData; DWORD bV5ProfileSize; DWORD bV5Reserved; } alias BITMAPV5HEADER* LPBITMAPV5HEADER, PBITMAPV5HEADER; struct FONTSIGNATURE { DWORD[4] fsUsb; DWORD[2] fsCsb; } alias FONTSIGNATURE* PFONTSIGNATURE, LPFONTSIGNATURE; struct CHARSETINFO { UINT ciCharset; UINT ciACP; FONTSIGNATURE fs; } alias CHARSETINFO* PCHARSETINFO, NPCHARSETINFO, LPCHARSETINFO; struct COLORADJUSTMENT { WORD caSize; WORD caFlags; WORD caIlluminantIndex; WORD caRedGamma; WORD caGreenGamma; WORD caBlueGamma; WORD caReferenceBlack; WORD caReferenceWhite; SHORT caContrast; SHORT caBrightness; SHORT caColorfulness; SHORT caRedGreenTint; } alias COLORADJUSTMENT* PCOLORADJUSTMENT, LPCOLORADJUSTMENT; struct DEVMODEA { BYTE[CCHDEVICENAME] dmDeviceName; WORD dmSpecVersion; WORD dmDriverVersion; WORD dmSize; WORD dmDriverExtra; DWORD dmFields; union { struct { short dmOrientation; short dmPaperSize; short dmPaperLength; short dmPaperWidth; short dmScale; short dmCopies; short dmDefaultSource; short dmPrintQuality; } struct { POINTL dmPosition; DWORD dmDisplayOrientation; DWORD dmDisplayFixedOutput; } } short dmColor; short dmDuplex; short dmYResolution; short dmTTOption; short dmCollate; BYTE[CCHFORMNAME] dmFormName; WORD dmLogPixels; DWORD dmBitsPerPel; DWORD dmPelsWidth; DWORD dmPelsHeight; union { DWORD dmDisplayFlags; DWORD dmNup; } DWORD dmDisplayFrequency; DWORD dmICMMethod; DWORD dmICMIntent; DWORD dmMediaType; DWORD dmDitherType; DWORD dmReserved1; DWORD dmReserved2; DWORD dmPanningWidth; DWORD dmPanningHeight; } alias DEVMODEA* PDEVMODEA, NPDEVMODEA, LPDEVMODEA; struct DEVMODEW { WCHAR[CCHDEVICENAME] dmDeviceName; WORD dmSpecVersion; WORD dmDriverVersion; WORD dmSize; WORD dmDriverExtra; DWORD dmFields; union { struct { short dmOrientation; short dmPaperSize; short dmPaperLength; short dmPaperWidth; short dmScale; short dmCopies; short dmDefaultSource; short dmPrintQuality; } struct { POINTL dmPosition; DWORD dmDisplayOrientation; DWORD dmDisplayFixedOutput; } } short dmColor; short dmDuplex; short dmYResolution; short dmTTOption; short dmCollate; WCHAR[CCHFORMNAME] dmFormName; WORD dmLogPixels; DWORD dmBitsPerPel; DWORD dmPelsWidth; DWORD dmPelsHeight; union { DWORD dmDisplayFlags; DWORD dmNup; } DWORD dmDisplayFrequency; DWORD dmICMMethod; DWORD dmICMIntent; DWORD dmMediaType; DWORD dmDitherType; DWORD dmReserved1; DWORD dmReserved2; DWORD dmPanningWidth; DWORD dmPanningHeight; } alias DEVMODEW* PDEVMODEW, NPDEVMODEW, LPDEVMODEW; /* * Information about output options */ struct PSFEATURE_OUTPUT { BOOL bPageIndependent; BOOL bSetPageDevice; } alias PSFEATURE_OUTPUT* PPSFEATURE_OUTPUT; /* * Information about custom paper size */ struct PSFEATURE_CUSTPAPER { LONG lOrientation; LONG lWidth; LONG lHeight; LONG lWidthOffset; LONG lHeightOffset; } alias PSFEATURE_CUSTPAPER* PPSFEATURE_CUSTPAPER; struct DIBSECTION { BITMAP dsBm; BITMAPINFOHEADER dsBmih; DWORD[3] dsBitfields; HANDLE dshSection; DWORD dsOffset; } alias DIBSECTION* PDIBSECTION; struct DOCINFOA { int cbSize = DOCINFOA.sizeof; LPCSTR lpszDocName; LPCSTR lpszOutput; LPCSTR lpszDatatype; DWORD fwType; } alias DOCINFOA* LPDOCINFOA; struct DOCINFOW { int cbSize = DOCINFOW.sizeof; LPCWSTR lpszDocName; LPCWSTR lpszOutput; LPCWSTR lpszDatatype; DWORD fwType; } alias DOCINFOW* LPDOCINFOW; struct PANOSE { BYTE bFamilyType; BYTE bSerifStyle; BYTE bWeight; BYTE bProportion; BYTE bContrast; BYTE bStrokeVariation; BYTE bArmStyle; BYTE bLetterform; BYTE bMidline; BYTE bXHeight; } alias PANOSE* LPPANOSE; struct LOGFONTA { LONG lfHeight; LONG lfWidth; LONG lfEscapement; LONG lfOrientation; LONG lfWeight; BYTE lfItalic; BYTE lfUnderline; BYTE lfStrikeOut; BYTE lfCharSet; BYTE lfOutPrecision; BYTE lfClipPrecision; BYTE lfQuality; BYTE lfPitchAndFamily; CHAR[LF_FACESIZE] lfFaceName; } alias LOGFONTA* PLOGFONTA, NPLOGFONTA, LPLOGFONTA; struct LOGFONTW { LONG lfHeight; LONG lfWidth; LONG lfEscapement; LONG lfOrientation; LONG lfWeight; BYTE lfItalic; BYTE lfUnderline; BYTE lfStrikeOut; BYTE lfCharSet; BYTE lfOutPrecision; BYTE lfClipPrecision; BYTE lfQuality; BYTE lfPitchAndFamily; WCHAR[LF_FACESIZE] lfFaceName; } alias LOGFONTW* PLOGFONTW, NPLOGFONTW, LPLOGFONTW; struct EXTLOGFONTA { LOGFONTA elfLogFont; BYTE[LF_FULLFACESIZE] elfFullName; BYTE[LF_FACESIZE] elfStyle; DWORD elfVersion; DWORD elfStyleSize; DWORD elfMatch; DWORD elfReserved; BYTE[ELF_VENDOR_SIZE] elfVendorId; DWORD elfCulture; PANOSE elfPanose; } alias EXTLOGFONTA* PEXTLOGFONTA, NPEXTLOGFONTA, LPEXTLOGFONTA; struct EXTLOGFONTW { LOGFONTW elfLogFont; WCHAR[LF_FULLFACESIZE] elfFullName; WCHAR[LF_FACESIZE] elfStyle; DWORD elfVersion; DWORD elfStyleSize; DWORD elfMatch; DWORD elfReserved; BYTE[ELF_VENDOR_SIZE] elfVendorId; DWORD elfCulture; PANOSE elfPanose; } alias EXTLOGFONTW* PEXTLOGFONTW, NPEXTLOGFONTW, LPEXTLOGFONTW; struct LOGPEN { UINT lopnStyle; POINT lopnWidth; COLORREF lopnColor; } alias LOGPEN* PLOGPEN, NPLOGPEN, LPLOGPEN; // ---------------------- EMR ------------ struct EMR { DWORD iType; DWORD nSize; } alias EMR* PEMR; struct EMRANGLEARC { EMR emr; POINTL ptlCenter; DWORD nRadius; FLOAT eStartAngle; FLOAT eSweepAngle; } alias EMRANGLEARC* PEMRANGLEARC; struct EMRARC { EMR emr; RECTL rclBox; POINTL ptlStart; POINTL ptlEnd; } alias EMRARC* PEMRARC; alias TypeDef!(EMRARC) EMRARCTO; alias EMRARCTO* PEMRARCTO; alias TypeDef!(EMRARC) EMRCHORD; alias EMRCHORD* PEMRCHORD; alias TypeDef!(EMRARC) EMRPIE; alias EMRPIE* PEMRPIE; struct XFORM { FLOAT eM11; FLOAT eM12; FLOAT eM21; FLOAT eM22; FLOAT eDx; FLOAT eDy; } alias XFORM* PXFORM, LPXFORM; struct EMRBITBLT { EMR emr; RECTL rclBounds; LONG xDest; LONG yDest; LONG cxDest; LONG cyDest; DWORD dwRop; LONG xSrc; LONG ySrc; XFORM xformSrc; COLORREF crBkColorSrc; DWORD iUsageSrc; DWORD offBmiSrc; DWORD cbBmiSrc; DWORD offBitsSrc; DWORD cbBitsSrc; } alias EMRBITBLT* PEMRBITBLT; struct LOGBRUSH { UINT lbStyle; COLORREF lbColor; LONG lbHatch; } alias TypeDef!(LOGBRUSH) PATTERN; alias LOGBRUSH* PLOGBRUSH, NPLOGBRUSH, LPLOGBRUSH; alias PATTERN* PPATTERN, NPPATTERN, LPPATTERN; struct LOGBRUSH32 { UINT lbStyle; COLORREF lbColor; ULONG lbHatch; } alias LOGBRUSH32* PLOGBRUSH32, NPLOGBRUSH32, LPLOGBRUSH32; struct EMRCREATEBRUSHINDIRECT { EMR emr; DWORD ihBrush; LOGBRUSH32 lb; } alias EMRCREATEBRUSHINDIRECT* PEMRCREATEBRUSHINDIRECT; alias LONG LCSCSTYPE, LCSGAMUTMATCH; struct LOGCOLORSPACEA { DWORD lcsSignature; DWORD lcsVersion; DWORD lcsSize; LCSCSTYPE lcsCSType; LCSGAMUTMATCH lcsIntent; CIEXYZTRIPLE lcsEndpoints; DWORD lcsGammaRed; DWORD lcsGammaGreen; DWORD lcsGammaBlue; CHAR[MAX_PATH] lcsFilename; } alias LOGCOLORSPACEA* LPLOGCOLORSPACEA; struct LOGCOLORSPACEW { DWORD lcsSignature; DWORD lcsVersion; DWORD lcsSize; LCSCSTYPE lcsCSType; LCSGAMUTMATCH lcsIntent; CIEXYZTRIPLE lcsEndpoints; DWORD lcsGammaRed; DWORD lcsGammaGreen; DWORD lcsGammaBlue; WCHAR[MAX_PATH] lcsFilename; } alias LOGCOLORSPACEW* LPLOGCOLORSPACEW; alias USHORT COLOR16; struct TRIVERTEX { LONG x; LONG y; COLOR16 Red; COLOR16 Green; COLOR16 Blue; COLOR16 Alpha; } alias TRIVERTEX* PTRIVERTEX, LPTRIVERTEX; struct EMRGLSRECORD { EMR emr; DWORD cbData; BYTE[1] Data; } alias EMRGLSRECORD* PEMRGLSRECORD; struct EMRGLSBOUNDEDRECORD { EMR emr; RECTL rclBounds; DWORD cbData; BYTE[1] Data; } alias EMRGLSBOUNDEDRECORD* PEMRGLSBOUNDEDRECORD; struct EMRPIXELFORMAT { EMR emr; PIXELFORMATDESCRIPTOR pfd; } alias EMRPIXELFORMAT* PEMRPIXELFORMAT; struct EMRCREATECOLORSPACE { EMR emr; DWORD ihCS; LOGCOLORSPACE lcs; } alias EMRCREATECOLORSPACE* PEMRCREATECOLORSPACE; struct EMRSETCOLORSPACE { EMR emr; DWORD ihCS; } alias EMRSETCOLORSPACE* PEMRSETCOLORSPACE; alias TypeDef!(EMRSETCOLORSPACE) EMRSELECTCOLORSPACE; alias EMRSELECTCOLORSPACE* PEMRSELECTCOLORSPACE; alias TypeDef!(EMRSETCOLORSPACE) EMRDELETECOLORSPACE; alias EMRDELETECOLORSPACE* PEMRDELETECOLORSPACE; static if (_WIN32_WINNT >= 0x500) { struct EMREXTESCAPE { EMR emr; INT iEscape; INT cbEscData; BYTE[1] EscData; } alias EMREXTESCAPE* PEMREXTESCAPE; alias TypeDef!(EMREXTESCAPE) EMRDRAWESCAPE; alias EMRDRAWESCAPE* PEMRDRAWESCAPE; struct EMRNAMEDESCAPE { EMR emr; INT iEscape; INT cbDriver; INT cbEscData; BYTE[1] EscData; } alias EMRNAMEDESCAPE* PEMRNAMEDESCAPE; struct EMRSETICMPROFILE { EMR emr; DWORD dwFlags; DWORD cbName; DWORD cbData; BYTE[1] Data; } alias EMRSETICMPROFILE* PEMRSETICMPROFILE; alias TypeDef!(EMRSETICMPROFILE) EMRSETICMPROFILEA; alias EMRSETICMPROFILEA* PEMRSETICMPROFILEA; alias TypeDef!(EMRSETICMPROFILE) EMRSETICMPROFILEW; alias EMRSETICMPROFILEW* PEMRSETICMPROFILEW; struct EMRCREATECOLORSPACEW { EMR emr; DWORD ihCS; LOGCOLORSPACEW lcs; DWORD dwFlags; DWORD cbData; BYTE[1] Data; } alias EMRCREATECOLORSPACEW* PEMRCREATECOLORSPACEW; struct EMRCOLORMATCHTOTARGET { EMR emr; DWORD dwAction; DWORD dwFlags; DWORD cbName; DWORD cbData; BYTE[1] Data; } alias EMRCOLORMATCHTOTARGET* PEMRCOLORMATCHTOTARGET; struct EMRCOLORCORRECTPALETTE { EMR emr; DWORD ihPalette; DWORD nFirstEntry; DWORD nPalEntries; DWORD nReserved; } alias EMRCOLORCORRECTPALETTE* PEMRCOLORCORRECTPALETTE; struct EMRALPHABLEND { EMR emr; RECTL rclBounds; LONG xDest; LONG yDest; LONG cxDest; LONG cyDest; DWORD dwRop; LONG xSrc; LONG ySrc; XFORM xformSrc; COLORREF crBkColorSrc; DWORD iUsageSrc; DWORD offBmiSrc; DWORD cbBmiSrc; DWORD offBitsSrc; DWORD cbBitsSrc; LONG cxSrc; LONG cySrc; } alias EMRALPHABLEND* PEMRALPHABLEND; struct EMRGRADIENTFILL { EMR emr; RECTL rclBounds; DWORD nVer; DWORD nTri; ULONG ulMode; TRIVERTEX[1] Ver; } alias EMRGRADIENTFILL* PEMRGRADIENTFILL; struct EMRTRANSPARENTBLT { EMR emr; RECTL rclBounds; LONG xDest; LONG yDest; LONG cxDest; LONG cyDest; DWORD dwRop; LONG xSrc; LONG ySrc; XFORM xformSrc; COLORREF crBkColorSrc; DWORD iUsageSrc; DWORD offBmiSrc; DWORD cbBmiSrc; DWORD offBitsSrc; DWORD cbBitsSrc; LONG cxSrc; LONG cySrc; } alias EMRTRANSPARENTBLT* PEMRTRANSPARENTBLT; } struct EMRCREATEDIBPATTERNBRUSHPT { EMR emr; DWORD ihBrush; DWORD iUsage; DWORD offBmi; DWORD cbBmi; DWORD offBits; DWORD cbBits; } alias EMRCREATEDIBPATTERNBRUSHPT* PEMRCREATEDIBPATTERNBRUSHPT; struct EMRCREATEMONOBRUSH { EMR emr; DWORD ihBrush; DWORD iUsage; DWORD offBmi; DWORD cbBmi; DWORD offBits; DWORD cbBits; } alias EMRCREATEMONOBRUSH* PEMRCREATEMONOBRUSH; struct PALETTEENTRY { BYTE peRed; BYTE peGreen; BYTE peBlue; BYTE peFlags; } alias PALETTEENTRY* PPALETTEENTRY, LPPALETTEENTRY; struct LOGPALETTE { WORD palVersion; WORD palNumEntries; PALETTEENTRY[1] palPalEntry; } alias LOGPALETTE* PLOGPALETTE, NPLOGPALETTE, LPLOGPALETTE; struct EMRCREATEPALETTE { EMR emr; DWORD ihPal; LOGPALETTE lgpl; } alias EMRCREATEPALETTE* PEMRCREATEPALETTE; struct EMRCREATEPEN { EMR emr; DWORD ihPen; LOGPEN lopn; } alias EMRCREATEPEN* PEMRCREATEPEN; struct EMRELLIPSE { EMR emr; RECTL rclBox; } alias EMRELLIPSE* PEMRELLIPSE; alias TypeDef!(EMRELLIPSE) EMRRECTANGLE; alias EMRRECTANGLE* PEMRRECTANGLE; struct EMREOF { EMR emr; DWORD nPalEntries; DWORD offPalEntries; DWORD nSizeLast; } alias EMREOF* PEMREOF; struct EMREXCLUDECLIPRECT { EMR emr; RECTL rclClip; } alias EMREXCLUDECLIPRECT* PEMREXCLUDECLIPRECT; alias TypeDef!(EMREXCLUDECLIPRECT) EMRINTERSECTCLIPRECT; alias EMRINTERSECTCLIPRECT* PEMRINTERSECTCLIPRECT; struct EMREXTCREATEFONTINDIRECTW { EMR emr; DWORD ihFont; EXTLOGFONTW elfw; } alias EMREXTCREATEFONTINDIRECTW* PEMREXTCREATEFONTINDIRECTW; struct EXTLOGPEN { UINT elpPenStyle; UINT elpWidth; UINT elpBrushStyle; COLORREF elpColor; LONG elpHatch; DWORD elpNumEntries; DWORD[1] elpStyleEntry; } alias EXTLOGPEN* PEXTLOGPEN, NPEXTLOGPEN, LPEXTLOGPEN; struct EMREXTCREATEPEN { EMR emr; DWORD ihPen; DWORD offBmi; DWORD cbBmi; DWORD offBits; DWORD cbBits; EXTLOGPEN elp; } alias EMREXTCREATEPEN* PEMREXTCREATEPEN; struct EMREXTFLOODFILL { EMR emr; POINTL ptlStart; COLORREF crColor; DWORD iMode; } alias EMREXTFLOODFILL* PEMREXTFLOODFILL; struct EMREXTSELECTCLIPRGN { EMR emr; DWORD cbRgnData; DWORD iMode; BYTE [1]RgnData; } alias EMREXTSELECTCLIPRGN* PEMREXTSELECTCLIPRGN; struct EMRTEXT { POINTL ptlReference; DWORD nChars; DWORD offString; DWORD fOptions; RECTL rcl; DWORD offDx; } alias EMRTEXT* PEMRTEXT; struct EMREXTTEXTOUTA { EMR emr; RECTL rclBounds; DWORD iGraphicsMode; FLOAT exScale; FLOAT eyScale; EMRTEXT emrtext; } alias EMREXTTEXTOUTA* PEMREXTTEXTOUTA; alias TypeDef!(EMREXTTEXTOUTA) EMREXTTEXTOUTW; alias EMREXTTEXTOUTW* PEMREXTTEXTOUTW; struct EMRFILLPATH { EMR emr; RECTL rclBounds; } alias EMRFILLPATH* PEMRFILLPATH; alias TypeDef!(EMRFILLPATH) EMRSTROKEANDFILLPATH; alias EMRSTROKEANDFILLPATH* PEMRSTROKEANDFILLPATH; alias TypeDef!(EMRFILLPATH) EMRSTROKEPATH; alias EMRSTROKEPATH* PEMRSTROKEPATH; struct EMRFILLRGN { EMR emr; RECTL rclBounds; DWORD cbRgnData; DWORD ihBrush; BYTE[1] RgnData; } alias EMRFILLRGN* PEMRFILLRGN; struct EMRFORMAT { DWORD dSignature; DWORD nVersion; DWORD cbData; DWORD offData; } alias EMRFORMAT* PEMRFORMAT; struct EMRFRAMERGN { EMR emr; RECTL rclBounds; DWORD cbRgnData; DWORD ihBrush; SIZEL szlStroke; BYTE[1] RgnData; } alias EMRFRAMERGN* PEMRFRAMERGN; struct EMRGDICOMMENT { EMR emr; DWORD cbData; BYTE[1] Data; } alias EMRGDICOMMENT* PEMRGDICOMMENT; struct EMRINVERTRGN { EMR emr; RECTL rclBounds; DWORD cbRgnData; BYTE[1] RgnData; } alias EMRINVERTRGN* PEMRINVERTRGN; alias TypeDef!(EMRINVERTRGN) EMRPAINTRGN; alias EMRPAINTRGN* PEMRPAINTRGN; struct EMRLINETO { EMR emr; POINTL ptl; } alias EMRLINETO* PEMRLINETO; alias TypeDef!(EMRLINETO) EMRMOVETOEX; alias EMRMOVETOEX* PEMRMOVETOEX; struct EMRMASKBLT { EMR emr; RECTL rclBounds; LONG xDest; LONG yDest; LONG cxDest; LONG cyDest; DWORD dwRop; LONG xSrc; LONG ySrc; XFORM xformSrc; COLORREF crBkColorSrc; DWORD iUsageSrc; DWORD offBmiSrc; DWORD cbBmiSrc; DWORD offBitsSrc; DWORD cbBitsSrc; LONG xMask; LONG yMask; DWORD iUsageMask; DWORD offBmiMask; DWORD cbBmiMask; DWORD offBitsMask; DWORD cbBitsMask; } alias EMRMASKBLT* PEMRMASKBLT; struct EMRMODIFYWORLDTRANSFORM { EMR emr; XFORM xform; DWORD iMode; } alias EMRMODIFYWORLDTRANSFORM* PEMRMODIFYWORLDTRANSFORM; struct EMROFFSETCLIPRGN { EMR emr; POINTL ptlOffset; } alias EMROFFSETCLIPRGN* PEMROFFSETCLIPRGN; struct EMRPLGBLT { EMR emr; RECTL rclBounds; POINTL[3] aptlDest; LONG xSrc; LONG ySrc; LONG cxSrc; LONG cySrc; XFORM xformSrc; COLORREF crBkColorSrc; DWORD iUsageSrc; DWORD offBmiSrc; DWORD cbBmiSrc; DWORD offBitsSrc; DWORD cbBitsSrc; LONG xMask; LONG yMask; DWORD iUsageMask; DWORD offBmiMask; DWORD cbBmiMask; DWORD offBitsMask; DWORD cbBitsMask; } alias EMRPLGBLT* PEMRPLGBLT; struct EMRPOLYDRAW { EMR emr; RECTL rclBounds; DWORD cptl; POINTL[1] aptl; BYTE[1] abTypes; } alias EMRPOLYDRAW* PEMRPOLYDRAW; struct EMRPOLYDRAW16 { EMR emr; RECTL rclBounds; DWORD cpts; POINTS[1] apts; BYTE[1] abTypes; } alias EMRPOLYDRAW16* PEMRPOLYDRAW16; struct EMRPOLYLINE { EMR emr; RECTL rclBounds; DWORD cptl; POINTL[1] aptl; } alias EMRPOLYLINE* PEMRPOLYLINE; alias TypeDef!(EMRPOLYLINE) EMRPOLYBEZIER; alias EMRPOLYBEZIER* PEMRPOLYBEZIER; alias TypeDef!(EMRPOLYLINE) EMRPOLYGON; alias EMRPOLYGON* PEMRPOLYGON; alias TypeDef!(EMRPOLYLINE) EMRPOLYBEZIERTO; alias EMRPOLYBEZIERTO* PEMRPOLYBEZIERTO; alias TypeDef!(EMRPOLYLINE) EMRPOLYLINETO; alias EMRPOLYLINETO* PEMRPOLYLINETO; struct EMRPOLYLINE16 { EMR emr; RECTL rclBounds; DWORD cpts; POINTS[1] apts; } alias EMRPOLYLINE16* PEMRPOLYLINE16; alias TypeDef!(EMRPOLYLINE16) EMRPOLYBEZIER16; alias EMRPOLYBEZIER16* PEMRPOLYBEZIER16; alias TypeDef!(EMRPOLYLINE16) EMRPOLYGON16; alias EMRPOLYGON16* PEMRPOLYGON16; alias TypeDef!(EMRPOLYLINE16) EMRPOLYBEZIERTO16; alias EMRPOLYBEZIERTO16* PEMRPOLYBEZIERTO16; alias TypeDef!(EMRPOLYLINE16) EMRPOLYLINETO16; alias EMRPOLYLINETO16* PEMRPOLYLINETO16; struct EMRPOLYPOLYLINE { EMR emr; RECTL rclBounds; DWORD nPolys; DWORD cptl; DWORD[1] aPolyCounts; POINTL[1] aptl; } alias EMRPOLYPOLYLINE* PEMRPOLYPOLYLINE; alias TypeDef!(EMRPOLYPOLYLINE) EMRPOLYPOLYGON; alias EMRPOLYPOLYGON* PEMRPOLYPOLYGON; struct EMRPOLYPOLYLINE16 { EMR emr; RECTL rclBounds; DWORD nPolys; DWORD cpts; DWORD[1] aPolyCounts; POINTS[1] apts; } alias EMRPOLYPOLYLINE16* PEMRPOLYPOLYLINE16; alias TypeDef!(EMRPOLYPOLYLINE16) EMRPOLYPOLYGON16; alias EMRPOLYPOLYGON16* PEMRPOLYPOLYGON16; struct EMRPOLYTEXTOUTA { EMR emr; RECTL rclBounds; DWORD iGraphicsMode; FLOAT exScale; FLOAT eyScale; LONG cStrings; EMRTEXT[1] aemrtext; } alias EMRPOLYTEXTOUTA* PEMRPOLYTEXTOUTA; alias TypeDef!(EMRPOLYTEXTOUTA) EMRPOLYTEXTOUTW; alias EMRPOLYTEXTOUTW* PEMRPOLYTEXTOUTW; struct EMRRESIZEPALETTE { EMR emr; DWORD ihPal; DWORD cEntries; } alias EMRRESIZEPALETTE* PEMRRESIZEPALETTE; struct EMRRESTOREDC { EMR emr; LONG iRelative; } alias EMRRESTOREDC* PEMRRESTOREDC; struct EMRROUNDRECT { EMR emr; RECTL rclBox; SIZEL szlCorner; } alias EMRROUNDRECT* PEMRROUNDRECT; struct EMRSCALEVIEWPORTEXTEX { EMR emr; LONG xNum; LONG xDenom; LONG yNum; LONG yDenom; } alias EMRSCALEVIEWPORTEXTEX* PEMRSCALEVIEWPORTEXTEX; alias TypeDef!(EMRSCALEVIEWPORTEXTEX) EMRSCALEWINDOWEXTEX; alias EMRSCALEWINDOWEXTEX* PEMRSCALEWINDOWEXTEX; struct EMRSELECTOBJECT { EMR emr; DWORD ihObject; } alias EMRSELECTOBJECT* PEMRSELECTOBJECT; alias TypeDef!(EMRSELECTOBJECT) EMRDELETEOBJECT; alias EMRDELETEOBJECT* PEMRDELETEOBJECT; struct EMRSELECTPALETTE { EMR emr; DWORD ihPal; } alias EMRSELECTPALETTE* PEMRSELECTPALETTE; struct EMRSETARCDIRECTION { EMR emr; DWORD iArcDirection; } alias EMRSETARCDIRECTION* PEMRSETARCDIRECTION; struct EMRSETTEXTCOLOR { EMR emr; COLORREF crColor; } alias EMRSETTEXTCOLOR* PEMRSETTEXTCOLOR; alias TypeDef!(EMRSETTEXTCOLOR) EMRSETBKCOLOR; alias EMRSETBKCOLOR* PEMRSETBKCOLOR; struct EMRSETCOLORADJUSTMENT { EMR emr; COLORADJUSTMENT ColorAdjustment; } alias EMRSETCOLORADJUSTMENT* PEMRSETCOLORADJUSTMENT; struct EMRSETDIBITSTODEVICE { EMR emr; RECTL rclBounds; LONG xDest; LONG yDest; LONG xSrc; LONG ySrc; LONG cxSrc; LONG cySrc; DWORD offBmiSrc; DWORD cbBmiSrc; DWORD offBitsSrc; DWORD cbBitsSrc; DWORD iUsageSrc; DWORD iStartScan; DWORD cScans; } alias EMRSETDIBITSTODEVICE* PEMRSETDIBITSTODEVICE; struct EMRSETMAPPERFLAGS { EMR emr; DWORD dwFlags; } alias EMRSETMAPPERFLAGS* PEMRSETMAPPERFLAGS; struct EMRSETMITERLIMIT { EMR emr; FLOAT eMiterLimit; } alias EMRSETMITERLIMIT* PEMRSETMITERLIMIT; struct EMRSETPALETTEENTRIES { EMR emr; DWORD ihPal; DWORD iStart; DWORD cEntries; PALETTEENTRY[1] aPalEntries; } alias EMRSETPALETTEENTRIES* PEMRSETPALETTEENTRIES; struct EMRSETPIXELV { EMR emr; POINTL ptlPixel; COLORREF crColor; } alias EMRSETPIXELV* PEMRSETPIXELV; struct EMRSETVIEWPORTEXTEX { EMR emr; SIZEL szlExtent; } alias EMRSETVIEWPORTEXTEX* PEMRSETVIEWPORTEXTEX; alias TypeDef!(EMRSETVIEWPORTEXTEX) EMRSETWINDOWEXTEX; alias EMRSETWINDOWEXTEX* PEMRSETWINDOWEXTEX; struct EMRSETVIEWPORTORGEX { EMR emr; POINTL ptlOrigin; } alias EMRSETVIEWPORTORGEX* PEMRSETVIEWPORTORGEX; alias TypeDef!(EMRSETVIEWPORTORGEX) EMRSETWINDOWORGEX; alias EMRSETWINDOWORGEX* PEMRSETWINDOWORGEX; alias TypeDef!(EMRSETVIEWPORTORGEX) EMRSETBRUSHORGEX; alias EMRSETBRUSHORGEX* PEMRSETBRUSHORGEX; struct EMRSETWORLDTRANSFORM { EMR emr; XFORM xform; } alias EMRSETWORLDTRANSFORM* PEMRSETWORLDTRANSFORM; struct EMRSTRETCHBLT { EMR emr; RECTL rclBounds; LONG xDest; LONG yDest; LONG cxDest; LONG cyDest; DWORD dwRop; LONG xSrc; LONG ySrc; XFORM xformSrc; COLORREF crBkColorSrc; DWORD iUsageSrc; DWORD offBmiSrc; DWORD cbBmiSrc; DWORD offBitsSrc; DWORD cbBitsSrc; LONG cxSrc; LONG cySrc; } alias EMRSTRETCHBLT* PEMRSTRETCHBLT; struct EMRSTRETCHDIBITS { EMR emr; RECTL rclBounds; LONG xDest; LONG yDest; LONG xSrc; LONG ySrc; LONG cxSrc; LONG cySrc; DWORD offBmiSrc; DWORD cbBmiSrc; DWORD offBitsSrc; DWORD cbBitsSrc; DWORD iUsageSrc; DWORD dwRop; LONG cxDest; LONG cyDest; } alias EMRSTRETCHDIBITS* PEMRSTRETCHDIBITS; struct EMRABORTPATH { EMR emr; } alias EMRABORTPATH* PEMRABORTPATH; alias TypeDef!(EMRABORTPATH) EMRBEGINPATH; alias EMRBEGINPATH* PEMRBEGINPATH; alias TypeDef!(EMRABORTPATH) EMRENDPATH; alias EMRENDPATH* PEMRENDPATH; alias TypeDef!(EMRABORTPATH) EMRCLOSEFIGURE; alias EMRCLOSEFIGURE* PEMRCLOSEFIGURE; alias TypeDef!(EMRABORTPATH) EMRFLATTENPATH; alias EMRFLATTENPATH* PEMRFLATTENPATH; alias TypeDef!(EMRABORTPATH) EMRWIDENPATH; alias EMRWIDENPATH* PEMRWIDENPATH; alias TypeDef!(EMRABORTPATH) EMRSETMETARGN; alias EMRSETMETARGN* PEMRSETMETARGN; alias TypeDef!(EMRABORTPATH) EMRSAVEDC; alias EMRSAVEDC* PEMRSAVEDC; alias TypeDef!(EMRABORTPATH) EMRREALIZEPALETTE; alias EMRREALIZEPALETTE* PEMRREALIZEPALETTE; struct EMRSELECTCLIPPATH { EMR emr; DWORD iMode; } alias EMRSELECTCLIPPATH* PEMRSELECTCLIPPATH; alias TypeDef!(EMRSELECTCLIPPATH) EMRSETBKMODE; alias EMRSETBKMODE* PEMRSETBKMODE; alias TypeDef!(EMRSELECTCLIPPATH) EMRSETMAPMODE; alias EMRSETMAPMODE* PEMRSETMAPMODE; alias TypeDef!(EMRSELECTCLIPPATH) EMRSETPOLYFILLMODE; alias EMRSETPOLYFILLMODE* PEMRSETPOLYFILLMODE; alias TypeDef!(EMRSELECTCLIPPATH) EMRSETROP2; alias EMRSETROP2* PEMRSETROP2; alias TypeDef!(EMRSELECTCLIPPATH) EMRSETSTRETCHBLTMODE; alias EMRSETSTRETCHBLTMODE* PEMRSETSTRETCHBLTMODE; alias TypeDef!(EMRSELECTCLIPPATH) EMRSETICMMODE; alias EMRSETICMMODE* PEMRSETICMMODE; alias TypeDef!(EMRSELECTCLIPPATH) EMRSETTEXTALIGN; alias EMRSETTEXTALIGN* PEMRSETTEXTALIGN; alias TypeDef!(EMRSELECTCLIPPATH) EMRENABLEICM; alias EMRENABLEICM* PEMRENABLEICM; static if (_WIN32_WINNT >= 0x500) { alias TypeDef!(EMRSELECTCLIPPATH) EMRSETLAYOUT; alias EMRSETLAYOUT* PEMRSETLAYOUT; } align(2): struct METAHEADER { align(2): WORD mtType; WORD mtHeaderSize; WORD mtVersion; DWORD mtSize; WORD mtNoObjects; DWORD mtMaxRecord; WORD mtNoParameters; } alias METAHEADER* PMETAHEADER; alias METAHEADER* LPMETAHEADER; align: struct ENHMETAHEADER { DWORD iType = EMR_HEADER; DWORD nSize = ENHMETAHEADER.sizeof; RECTL rclBounds; RECTL rclFrame; DWORD dSignature = ENHMETA_SIGNATURE; DWORD nVersion; DWORD nBytes; DWORD nRecords; WORD nHandles; WORD sReserved; DWORD nDescription; DWORD offDescription; DWORD nPalEntries; SIZEL szlDevice; SIZEL szlMillimeters; DWORD cbPixelFormat; DWORD offPixelFormat; DWORD bOpenGL; static if (_WIN32_WINNT >= 0x500) { SIZEL szlMicrometers; } } alias ENHMETAHEADER* PENHMETAHEADER, LPENHMETAHEADER; struct METARECORD { DWORD rdSize; WORD rdFunction; WORD[1] rdParm; } alias METARECORD* PMETARECORD; alias METARECORD* LPMETARECORD; struct ENHMETARECORD { DWORD iType; DWORD nSize; DWORD[1] dParm; } alias ENHMETARECORD* PENHMETARECORD, LPENHMETARECORD; // --- struct HANDLETABLE { HGDIOBJ[1] objectHandle; } alias HANDLETABLE* PHANDLETABLE, LPHANDLETABLE; struct TEXTMETRICA { LONG tmHeight; LONG tmAscent; LONG tmDescent; LONG tmInternalLeading; LONG tmExternalLeading; LONG tmAveCharWidth; LONG tmMaxCharWidth; LONG tmWeight; LONG tmOverhang; LONG tmDigitizedAspectX; LONG tmDigitizedAspectY; BYTE tmFirstChar; BYTE tmLastChar; BYTE tmDefaultChar; BYTE tmBreakChar; BYTE tmItalic; BYTE tmUnderlined; BYTE tmStruckOut; BYTE tmPitchAndFamily; BYTE tmCharSet; } alias TEXTMETRICA* PTEXTMETRICA, NPTEXTMETRICA, LPTEXTMETRICA; struct TEXTMETRICW { LONG tmHeight; LONG tmAscent; LONG tmDescent; LONG tmInternalLeading; LONG tmExternalLeading; LONG tmAveCharWidth; LONG tmMaxCharWidth; LONG tmWeight; LONG tmOverhang; LONG tmDigitizedAspectX; LONG tmDigitizedAspectY; WCHAR tmFirstChar; WCHAR tmLastChar; WCHAR tmDefaultChar; WCHAR tmBreakChar; BYTE tmItalic; BYTE tmUnderlined; BYTE tmStruckOut; BYTE tmPitchAndFamily; BYTE tmCharSet; } alias TEXTMETRICW* PTEXTMETRICW, NPTEXTMETRICW, LPTEXTMETRICW; struct RGNDATAHEADER { DWORD dwSize; DWORD iType; DWORD nCount; DWORD nRgnSize; RECT rcBound; } alias RGNDATAHEADER* PRGNDATAHEADER; struct RGNDATA { RGNDATAHEADER rdh; char[1] Buffer; } alias RGNDATA* PRGNDATA, NPRGNDATA, LPRGNDATA; /* for GetRandomRgn */ enum SYSRGN=4; struct GCP_RESULTSA { DWORD lStructSize; LPSTR lpOutString; UINT* lpOrder; INT* lpDx; INT* lpCaretPos; LPSTR lpClass; LPWSTR lpGlyphs; UINT nGlyphs; UINT nMaxFit; } alias GCP_RESULTSA* LPGCP_RESULTSA; struct GCP_RESULTSW { DWORD lStructSize; LPWSTR lpOutString; UINT* lpOrder; INT* lpDx; INT* lpCaretPos; LPWSTR lpClass; LPWSTR lpGlyphs; UINT nGlyphs; UINT nMaxFit; } alias GCP_RESULTSW* LPGCP_RESULTSW; struct GLYPHMETRICS { UINT gmBlackBoxX; UINT gmBlackBoxY; POINT gmptGlyphOrigin; short gmCellIncX; short gmCellIncY; } alias GLYPHMETRICS* LPGLYPHMETRICS; static if (_WIN32_WINNT >= 0x500) { struct WCRANGE { WCHAR wcLow; USHORT cGlyphs; } alias WCRANGE* PWCRANGE, LPWCRANGE; struct GLYPHSET { DWORD cbThis; DWORD flAccel; DWORD cGlyphsSupported; DWORD cRanges; WCRANGE[1] ranges; } alias GLYPHSET* PGLYPHSET, LPGLYPHSET; enum DWORD GS_8BIT_INDICES = 0x00000001; } struct KERNINGPAIR { WORD wFirst; WORD wSecond; int iKernAmount; } alias KERNINGPAIR* LPKERNINGPAIR; struct FIXED { WORD fract; short value; } struct MAT2 { FIXED eM11; FIXED eM12; FIXED eM21; FIXED eM22; } alias MAT2* LPMAT2; struct OUTLINETEXTMETRICA { UINT otmSize; TEXTMETRICA otmTextMetrics; BYTE otmFiller; PANOSE otmPanoseNumber; UINT otmfsSelection; UINT otmfsType; int otmsCharSlopeRise; int otmsCharSlopeRun; int otmItalicAngle; UINT otmEMSquare; int otmAscent; int otmDescent; UINT otmLineGap; UINT otmsCapEmHeight; UINT otmsXHeight; RECT otmrcFontBox; int otmMacAscent; int otmMacDescent; UINT otmMacLineGap; UINT otmusMinimumPPEM; POINT otmptSubscriptSize; POINT otmptSubscriptOffset; POINT otmptSuperscriptSize; POINT otmptSuperscriptOffset; UINT otmsStrikeoutSize; int otmsStrikeoutPosition; int otmsUnderscoreSize; int otmsUnderscorePosition; PSTR otmpFamilyName; PSTR otmpFaceName; PSTR otmpStyleName; PSTR otmpFullName; } alias OUTLINETEXTMETRICA* POUTLINETEXTMETRICA, NPOUTLINETEXTMETRICA, LPOUTLINETEXTMETRICA; struct OUTLINETEXTMETRICW { UINT otmSize; TEXTMETRICW otmTextMetrics; BYTE otmFiller; PANOSE otmPanoseNumber; UINT otmfsSelection; UINT otmfsType; int otmsCharSlopeRise; int otmsCharSlopeRun; int otmItalicAngle; UINT otmEMSquare; int otmAscent; int otmDescent; UINT otmLineGap; UINT otmsCapEmHeight; UINT otmsXHeight; RECT otmrcFontBox; int otmMacAscent; int otmMacDescent; UINT otmMacLineGap; UINT otmusMinimumPPEM; POINT otmptSubscriptSize; POINT otmptSubscriptOffset; POINT otmptSuperscriptSize; POINT otmptSuperscriptOffset; UINT otmsStrikeoutSize; int otmsStrikeoutPosition; int otmsUnderscoreSize; int otmsUnderscorePosition; PSTR otmpFamilyName; PSTR otmpFaceName; PSTR otmpStyleName; PSTR otmpFullName; } alias OUTLINETEXTMETRICW* POUTLINETEXTMETRICW, NPOUTLINETEXTMETRICW, LPOUTLINETEXTMETRICW; struct RASTERIZER_STATUS { short nSize; short wFlags; short nLanguageID; } alias RASTERIZER_STATUS* LPRASTERIZER_STATUS; struct POLYTEXTA { int x; int y; UINT n; LPCSTR lpstr; UINT uiFlags; RECT rcl; int* pdx; } alias POLYTEXTA* PPOLYTEXTA, NPPOLYTEXTA, LPPOLYTEXTA; struct POLYTEXTW { int x; int y; UINT n; LPCWSTR lpstr; UINT uiFlags; RECT rcl; int* pdx; } alias POLYTEXTW* PPOLYTEXTW, NPPOLYTEXTW, LPPOLYTEXTW; struct PIXELFORMATDESCRIPTOR { WORD nSize; WORD nVersion; DWORD dwFlags; BYTE iPixelType; BYTE cColorBits; BYTE cRedBits; BYTE cRedShift; BYTE cGreenBits; BYTE cGreenShift; BYTE cBlueBits; BYTE cBlueShift; BYTE cAlphaBits; BYTE cAlphaShift; BYTE cAccumBits; BYTE cAccumRedBits; BYTE cAccumGreenBits; BYTE cAccumBlueBits; BYTE cAccumAlphaBits; BYTE cDepthBits; BYTE cStencilBits; BYTE cAuxBuffers; BYTE iLayerType; BYTE bReserved; DWORD dwLayerMask; DWORD dwVisibleMask; DWORD dwDamageMask; } alias PIXELFORMATDESCRIPTOR* PPIXELFORMATDESCRIPTOR, LPPIXELFORMATDESCRIPTOR; struct METAFILEPICT { LONG mm; LONG xExt; LONG yExt; HMETAFILE hMF; } alias METAFILEPICT* LPMETAFILEPICT; struct LOCALESIGNATURE { DWORD[4] lsUsb; DWORD[2] lsCsbDefault; DWORD[2] lsCsbSupported; } alias LOCALESIGNATURE* PLOCALESIGNATURE, LPLOCALESIGNATURE; alias LONG LCSTYPE; /* What this for? */ align(4): struct NEWTEXTMETRICA { LONG tmHeight; LONG tmAscent; LONG tmDescent; LONG tmInternalLeading; LONG tmExternalLeading; LONG tmAveCharWidth; LONG tmMaxCharWidth; LONG tmWeight; LONG tmOverhang; LONG tmDigitizedAspectX; LONG tmDigitizedAspectY; BYTE tmFirstChar; BYTE tmLastChar; BYTE tmDefaultChar; BYTE tmBreakChar; BYTE tmItalic; BYTE tmUnderlined; BYTE tmStruckOut; BYTE tmPitchAndFamily; BYTE tmCharSet; DWORD ntmFlags; UINT ntmSizeEM; UINT ntmCellHeight; UINT ntmAvgWidth; } alias NEWTEXTMETRICA* PNEWTEXTMETRICA, NPNEWTEXTMETRICA, LPNEWTEXTMETRICA; struct NEWTEXTMETRICW { LONG tmHeight; LONG tmAscent; LONG tmDescent; LONG tmInternalLeading; LONG tmExternalLeading; LONG tmAveCharWidth; LONG tmMaxCharWidth; LONG tmWeight; LONG tmOverhang; LONG tmDigitizedAspectX; LONG tmDigitizedAspectY; WCHAR tmFirstChar; WCHAR tmLastChar; WCHAR tmDefaultChar; WCHAR tmBreakChar; BYTE tmItalic; BYTE tmUnderlined; BYTE tmStruckOut; BYTE tmPitchAndFamily; BYTE tmCharSet; DWORD ntmFlags; UINT ntmSizeEM; UINT ntmCellHeight; UINT ntmAvgWidth; } alias NEWTEXTMETRICW* PNEWTEXTMETRICW, NPNEWTEXTMETRICW, LPNEWTEXTMETRICW; align: struct NEWTEXTMETRICEXA { NEWTEXTMETRICA ntmTm; FONTSIGNATURE ntmFontSig; } struct NEWTEXTMETRICEXW { NEWTEXTMETRICW ntmTm; FONTSIGNATURE ntmFontSig; } struct PELARRAY { LONG paXCount; LONG paYCount; LONG paXExt; LONG paYExt; BYTE paRGBs; } alias PELARRAY* PPELARRAY, NPPELARRAY, LPPELARRAY; struct ENUMLOGFONTA { LOGFONTA elfLogFont; BYTE[LF_FULLFACESIZE] elfFullName; BYTE[LF_FACESIZE] elfStyle; } alias ENUMLOGFONTA* LPENUMLOGFONTA; struct ENUMLOGFONTW { LOGFONTW elfLogFont; WCHAR[LF_FULLFACESIZE] elfFullName; WCHAR[LF_FACESIZE] elfStyle; } alias ENUMLOGFONTW* LPENUMLOGFONTW; struct ENUMLOGFONTEXA { LOGFONTA elfLogFont; BYTE[LF_FULLFACESIZE] elfFullName; BYTE[LF_FACESIZE] elfStyle; BYTE[LF_FACESIZE] elfScript; } alias ENUMLOGFONTEXA* LPENUMLOGFONTEXA; struct ENUMLOGFONTEXW { LOGFONTW elfLogFont; WCHAR[LF_FULLFACESIZE] elfFullName; WCHAR[LF_FACESIZE] elfStyle; WCHAR[LF_FACESIZE] elfScript; } alias ENUMLOGFONTEXW* LPENUMLOGFONTEXW; struct POINTFX { FIXED x; FIXED y; } alias POINTFX* LPPOINTFX; struct TTPOLYCURVE { WORD wType; WORD cpfx; POINTFX[1] apfx; } alias TTPOLYCURVE* LPTTPOLYCURVE; struct TTPOLYGONHEADER { DWORD cb; DWORD dwType; POINTFX pfxStart; } alias TTPOLYGONHEADER* LPTTPOLYGONHEADER; struct POINTFLOAT { FLOAT x; FLOAT y; } alias POINTFLOAT* PPOINTFLOAT; struct GLYPHMETRICSFLOAT { FLOAT gmfBlackBoxX; FLOAT gmfBlackBoxY; POINTFLOAT gmfptGlyphOrigin; FLOAT gmfCellIncX; FLOAT gmfCellIncY; } alias GLYPHMETRICSFLOAT* PGLYPHMETRICSFLOAT, LPGLYPHMETRICSFLOAT; struct LAYERPLANEDESCRIPTOR { WORD nSize; WORD nVersion; DWORD dwFlags; BYTE iPixelType; BYTE cColorBits; BYTE cRedBits; BYTE cRedShift; BYTE cGreenBits; BYTE cGreenShift; BYTE cBlueBits; BYTE cBlueShift; BYTE cAlphaBits; BYTE cAlphaShift; BYTE cAccumBits; BYTE cAccumRedBits; BYTE cAccumGreenBits; BYTE cAccumBlueBits; BYTE cAccumAlphaBits; BYTE cDepthBits; BYTE cStencilBits; BYTE cAuxBuffers; BYTE iLayerPlane; BYTE bReserved; COLORREF crTransparent; } alias LAYERPLANEDESCRIPTOR* PLAYERPLANEDESCRIPTOR, LPLAYERPLANEDESCRIPTOR; struct BLENDFUNCTION { BYTE BlendOp; BYTE BlendFlags; BYTE SourceConstantAlpha; BYTE AlphaFormat; } alias BLENDFUNCTION* PBLENDFUNCTION, LPBLENDFUNCTION; enum MM_MAX_NUMAXES = 16; struct DESIGNVECTOR { DWORD dvReserved; DWORD dvNumAxes; LONG[MM_MAX_NUMAXES] dvValues; } alias DESIGNVECTOR* PDESIGNVECTOR, LPDESIGNVECTOR; enum STAMP_DESIGNVECTOR = 0x8000000 + 'd' + ('v' << 8); enum STAMP_AXESLIST = 0x8000000 + 'a' + ('l' << 8); static if (_WIN32_WINNT >= 0x500) { enum MM_MAX_AXES_NAMELEN = 16; struct AXISINFOA { LONG axMinValue; LONG axMaxValue; BYTE[MM_MAX_AXES_NAMELEN] axAxisName; } alias AXISINFOA* PAXISINFOA, LPAXISINFOA; struct AXISINFOW { LONG axMinValue; LONG axMaxValue; WCHAR[MM_MAX_AXES_NAMELEN] axAxisName; } alias AXISINFOW* PAXISINFOW, LPAXISINFOW; version (Unicode) { alias AXISINFOW AXISINFO; alias PAXISINFOW PAXISINFO; alias LPAXISINFOW LPAXISINFO; } else { alias AXISINFOA AXISINFO; alias PAXISINFOA PAXISINFO; alias LPAXISINFOA LPAXISINFO; } struct AXESLISTA { DWORD axlReserved; DWORD axlNumAxes; AXISINFOA[MM_MAX_NUMAXES] axlAxisInfo; } alias AXESLISTA* PAXESLISTA, LPAXESLISTA; struct AXESLISTW { DWORD axlReserved; DWORD axlNumAxes; AXISINFOW[MM_MAX_NUMAXES] axlAxisInfo; } alias AXESLISTW* PAXESLISTW, LPAXESLISTW; version (Unicode) { alias AXESLISTW AXESLIST; alias PAXESLISTW PAXESLIST; alias LPAXESLISTW LPAXESLIST; } else { alias AXESLISTA AXESLIST; alias PAXESLISTA PAXESLIST; alias LPAXESLISTA LPAXESLIST; } struct ENUMLOGFONTEXDVA { ENUMLOGFONTEXA elfEnumLogfontEx; DESIGNVECTOR elfDesignVector; } alias ENUMLOGFONTEXDVA* PENUMLOGFONTEXDVA, LPENUMLOGFONTEXDVA; struct ENUMLOGFONTEXDVW { ENUMLOGFONTEXW elfEnumLogfontEx; DESIGNVECTOR elfDesignVector; } alias ENUMLOGFONTEXDVW* PENUMLOGFONTEXDVW, LPENUMLOGFONTEXDVW; HFONT CreateFontIndirectExA(const(ENUMLOGFONTEXDVA)*); HFONT CreateFontIndirectExW(const(ENUMLOGFONTEXDVW)*); version (Unicode) alias CreateFontIndirectExW CreateFontIndirectEx; else alias CreateFontIndirectExA CreateFontIndirectEx; struct ENUMTEXTMETRICA { NEWTEXTMETRICEXA etmNewTextMetricEx; AXESLISTA etmAxesList; } alias ENUMTEXTMETRICA* PENUMTEXTMETRICA, LPENUMTEXTMETRICA; struct ENUMTEXTMETRICW { NEWTEXTMETRICEXW etmNewTextMetricEx; AXESLISTW etmAxesList; } alias ENUMTEXTMETRICW* PENUMTEXTMETRICW, LPENUMTEXTMETRICW; version (Unicode) { alias ENUMTEXTMETRICW ENUMTEXTMETRIC; alias PENUMTEXTMETRICW PENUMTEXTMETRIC; alias LPENUMTEXTMETRICW LPENUMTEXTMETRIC; } else { alias ENUMTEXTMETRICA ENUMTEXTMETRIC; alias PENUMTEXTMETRICA PENUMTEXTMETRIC; alias LPENUMTEXTMETRICA LPENUMTEXTMETRIC; } } /* _WIN32_WINNT >= 0x500 */ struct GRADIENT_TRIANGLE { ULONG Vertex1; ULONG Vertex2; ULONG Vertex3; } alias GRADIENT_TRIANGLE* PGRADIENT_TRIANGLE, LPGRADIENT_TRIANGLE; struct GRADIENT_RECT { ULONG UpperLeft; ULONG LowerRight; } alias GRADIENT_RECT* PGRADIENT_RECT, LPGRADIENT_RECT; struct DISPLAY_DEVICEA { DWORD cb; CHAR[32] DeviceName; CHAR[128] DeviceString; DWORD StateFlags; CHAR[128] DeviceID; CHAR[128] DeviceKey; } alias DISPLAY_DEVICEA* PDISPLAY_DEVICEA, LPDISPLAY_DEVICEA; struct DISPLAY_DEVICEW { DWORD cb; WCHAR[32] DeviceName; WCHAR[128] DeviceString; DWORD StateFlags; WCHAR[128] DeviceID; WCHAR[128] DeviceKey; } alias DISPLAY_DEVICEW* PDISPLAY_DEVICEW, LPDISPLAY_DEVICEW; struct DRAWPATRECT { POINT ptPosition; POINT ptSize; WORD wStyle; WORD wPattern; } alias DRAWPATRECT* PDRAWPATRECT; // --------- // Callbacks alias BOOL function (HDC, int) ABORTPROC; alias int function (HDC, HANDLETABLE*, METARECORD*, int, LPARAM) MFENUMPROC; alias int function (HDC, HANDLETABLE*, const(ENHMETARECORD)*, int, LPARAM) ENHMFENUMPROC; alias int function (const(LOGFONTA)*, const(TEXTMETRICA)*, DWORD, LPARAM) FONTENUMPROCA, OLDFONTENUMPROCA; alias int function (const(LOGFONTW)*, const(TEXTMETRICW)*, DWORD, LPARAM) FONTENUMPROCW, OLDFONTENUMPROCW; alias int function (LPSTR, LPARAM) ICMENUMPROCA; alias int function (LPWSTR, LPARAM) ICMENUMPROCW; alias void function (LPVOID, LPARAM) GOBJENUMPROC; alias void function (int, int, LPARAM) LINEDDAPROC; alias UINT function (HWND, HMODULE, LPDEVMODEA, LPSTR, LPSTR, LPDEVMODEA, LPSTR, UINT) LPFNDEVMODE; alias DWORD function (LPSTR, LPSTR, UINT, LPSTR, LPDEVMODEA) LPFNDEVCAPS; // --------- // C Macros. // FIXME: //POINTS MAKEPOINTS(DWORD dwValue) #define MAKEPOINTS(l) (*((POINTS*)&(l))) nothrow @nogc { DWORD MAKEROP4(DWORD fore, DWORD back) { return ((back<<8) & 0xFF000000) | (fore); } COLORREF CMYK(BYTE c, BYTE m, BYTE y, BYTE k) { return cast(COLORREF)(k | (y << 8) | (m << 16) | (c << 24)); } BYTE GetCValue(COLORREF cmyk) { return cast(BYTE)(cmyk >> 24); } BYTE GetMValue(COLORREF cmyk) { return cast(BYTE)(cmyk >> 16); } BYTE GetYValue(COLORREF cmyk) { return cast(BYTE)(cmyk >> 8); } BYTE GetKValue(COLORREF cmyk) { return cast(BYTE)cmyk; } COLORREF RGB(/*BYTE*/uint r, /*BYTE*/uint g, /*BYTE*/uint b) { return cast(COLORREF)(r | (g << 8) | (b << 16)); } BYTE GetRValue(COLORREF c) { return cast(BYTE)c; } BYTE GetGValue(COLORREF c) { return cast(BYTE)(c >> 8); } BYTE GetBValue(COLORREF c) { return cast(BYTE)(c >> 16); } COLORREF PALETTEINDEX(WORD i) { return 0x01000000 | cast(COLORREF) i; } COLORREF PALETTERGB(BYTE r, BYTE g, BYTE b) { return 0x02000000|RGB(r, g, b); } } extern(Windows) nothrow @nogc { int AbortDoc(HDC); BOOL AbortPath(HDC); int AddFontResourceA(LPCSTR); int AddFontResourceW(LPCWSTR); BOOL AngleArc(HDC, int, int, DWORD, FLOAT, FLOAT); BOOL AnimatePalette(HPALETTE, UINT, UINT, const(PALETTEENTRY)*); BOOL Arc(HDC, int, int, int, int, int, int, int, int); BOOL ArcTo(HDC, int, int, int, int, int, int, int, int); BOOL BeginPath(HDC); BOOL BitBlt(HDC, int, int, int, int, HDC, int, int, DWORD); BOOL CancelDC(HDC); BOOL CheckColorsInGamut(HDC, PVOID, PVOID, DWORD); BOOL Chord(HDC, int, int, int, int, int, int, int, int); int ChoosePixelFormat(HDC, const(PIXELFORMATDESCRIPTOR)*); HENHMETAFILE CloseEnhMetaFile(HDC); BOOL CloseFigure(HDC); HMETAFILE CloseMetaFile(HDC); BOOL ColorMatchToTarget(HDC, HDC, DWORD); BOOL ColorCorrectPalette(HDC, HPALETTE, DWORD, DWORD); int CombineRgn(HRGN, HRGN, HRGN, int); BOOL CombineTransform(LPXFORM, const(XFORM)*, const(XFORM)*); HENHMETAFILE CopyEnhMetaFileA(HENHMETAFILE, LPCSTR); HENHMETAFILE CopyEnhMetaFileW(HENHMETAFILE, LPCWSTR); HMETAFILE CopyMetaFileA(HMETAFILE, LPCSTR); HMETAFILE CopyMetaFileW(HMETAFILE, LPCWSTR); HBITMAP CreateBitmap(int, int, UINT, UINT, PCVOID); HBITMAP CreateBitmapIndirect(const(BITMAP)*); HBRUSH CreateBrushIndirect(const(LOGBRUSH)*); HCOLORSPACE CreateColorSpaceA(LPLOGCOLORSPACEA); HCOLORSPACE CreateColorSpaceW(LPLOGCOLORSPACEW); HBITMAP CreateCompatibleBitmap(HDC, int, int); HDC CreateCompatibleDC(HDC); HDC CreateDCA(LPCSTR, LPCSTR, LPCSTR, const(DEVMODEA)*); HDC CreateDCW(LPCWSTR, LPCWSTR, LPCWSTR, const(DEVMODEW)*); HBITMAP CreateDIBitmap(HDC, const(BITMAPINFOHEADER)*, DWORD, PCVOID, const(BITMAPINFO)*, UINT); HBRUSH CreateDIBPatternBrush(HGLOBAL, UINT); HBRUSH CreateDIBPatternBrushPt(PCVOID, UINT); HBITMAP CreateDIBSection(HDC, const(BITMAPINFO)*, UINT, void**, HANDLE, DWORD); HBITMAP CreateDiscardableBitmap(HDC, int, int); HRGN CreateEllipticRgn(int, int, int, int); HRGN CreateEllipticRgnIndirect(LPCRECT); HDC CreateEnhMetaFileA(HDC, LPCSTR, LPCRECT, LPCSTR); HDC CreateEnhMetaFileW(HDC, LPCWSTR, LPCRECT, LPCWSTR); HFONT CreateFontA(int, int, int, int, int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPCSTR); HFONT CreateFontW(int, int, int, int, int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPCWSTR); HFONT CreateFontIndirectA(const(LOGFONTA)*); HFONT CreateFontIndirectW(const(LOGFONTW)*); HPALETTE CreateHalftonePalette(HDC); HBRUSH CreateHatchBrush(int, COLORREF); HDC CreateICA(LPCSTR, LPCSTR, LPCSTR, const(DEVMODEA)*); HDC CreateICW(LPCWSTR, LPCWSTR, LPCWSTR, const(DEVMODEW)*); HDC CreateMetaFileA(LPCSTR); HDC CreateMetaFileW(LPCWSTR); HPALETTE CreatePalette(const(LOGPALETTE)*); HBRUSH CreatePatternBrush(HBITMAP); HPEN CreatePen(int, int, COLORREF); HPEN CreatePenIndirect(const(LOGPEN)*); HRGN CreatePolygonRgn(const(POINT)*, int, int); HRGN CreatePolyPolygonRgn(const(POINT)*, const(INT)*, int, int); HRGN CreateRectRgn(int, int, int, int); HRGN CreateRectRgnIndirect(LPCRECT); HRGN CreateRoundRectRgn(int, int, int, int, int, int); BOOL CreateScalableFontResourceA(DWORD, LPCSTR, LPCSTR, LPCSTR); BOOL CreateScalableFontResourceW(DWORD, LPCWSTR, LPCWSTR, LPCWSTR); HBRUSH CreateSolidBrush(COLORREF); BOOL DeleteColorSpace(HCOLORSPACE); BOOL DeleteDC(HDC); BOOL DeleteEnhMetaFile(HENHMETAFILE); BOOL DeleteMetaFile(HMETAFILE); BOOL DeleteObject(HGDIOBJ); int DescribePixelFormat(HDC, int, UINT, LPPIXELFORMATDESCRIPTOR); DWORD DeviceCapabilitiesA(LPCSTR, LPCSTR, WORD, LPSTR, const(DEVMODEA)*); DWORD DeviceCapabilitiesW(LPCWSTR, LPCWSTR, WORD, LPWSTR, const(DEVMODEW)*); BOOL DPtoLP(HDC, LPPOINT, int); int DrawEscape(HDC, int, int, LPCSTR); BOOL Ellipse(HDC, int, int, int, int); int EndDoc(HDC); int EndPage(HDC); BOOL EndPath(HDC); BOOL EnumEnhMetaFile(HDC, HENHMETAFILE, ENHMFENUMPROC, PVOID, LPCRECT); int EnumFontFamiliesA(HDC, LPCSTR, FONTENUMPROCA, LPARAM); int EnumFontFamiliesW(HDC, LPCWSTR, FONTENUMPROCW, LPARAM); int EnumFontFamiliesExA(HDC, PLOGFONTA, FONTENUMPROCA, LPARAM, DWORD); int EnumFontFamiliesExW(HDC, PLOGFONTW, FONTENUMPROCW, LPARAM, DWORD); int EnumFontsA(HDC, LPCSTR, FONTENUMPROCA, LPARAM); int EnumFontsW(HDC, LPCWSTR, FONTENUMPROCW, LPARAM); int EnumICMProfilesA(HDC, ICMENUMPROCA, LPARAM); int EnumICMProfilesW(HDC, ICMENUMPROCW, LPARAM); BOOL EnumMetaFile(HDC, HMETAFILE, MFENUMPROC, LPARAM); int EnumObjects(HDC, int, GOBJENUMPROC, LPARAM); BOOL EqualRgn(HRGN, HRGN); int Escape(HDC, int, int, LPCSTR, PVOID); int ExcludeClipRect(HDC, int, int, int, int); int ExcludeUpdateRgn(HDC, HWND); HPEN ExtCreatePen(DWORD, DWORD, const(LOGBRUSH)*, DWORD, const(DWORD)*); HRGN ExtCreateRegion(const(XFORM)*, DWORD, const(RGNDATA)*); int ExtEscape(HDC, int, int, LPCSTR, int, LPSTR); BOOL ExtFloodFill(HDC, int, int, COLORREF, UINT); int ExtSelectClipRgn(HDC, HRGN, int); BOOL ExtTextOutA(HDC, int, int, UINT, LPCRECT, LPCSTR, UINT, const(INT)*); BOOL ExtTextOutW(HDC, int, int, UINT, LPCRECT, LPCWSTR, UINT, const(INT)*); BOOL FillPath(HDC); int FillRect(HDC, LPCRECT, HBRUSH); int FillRgn(HDC, HRGN, HBRUSH); BOOL FixBrushOrgEx(HDC, int, int, LPPOINT); BOOL FlattenPath(HDC); BOOL FloodFill(HDC, int, int, COLORREF); BOOL FrameRgn(HDC, HRGN, HBRUSH, int, int); BOOL GdiComment(HDC, UINT, const(BYTE)*); BOOL GdiFlush(); DWORD GdiGetBatchLimit(); DWORD GdiSetBatchLimit(DWORD); int GetArcDirection(HDC); BOOL GetAspectRatioFilterEx(HDC, LPSIZE); LONG GetBitmapBits(HBITMAP, LONG, PVOID); BOOL GetBitmapDimensionEx(HBITMAP, LPSIZE); COLORREF GetBkColor(HDC); int GetBkMode(HDC); UINT GetBoundsRect(HDC, LPRECT, UINT); BOOL GetBrushOrgEx(HDC, LPPOINT); BOOL GetCharABCWidthsA(HDC, UINT, UINT, LPABC); BOOL GetCharABCWidthsW(HDC, UINT, UINT, LPABC); BOOL GetCharABCWidthsFloatA(HDC, UINT, UINT, LPABCFLOAT); BOOL GetCharABCWidthsFloatW(HDC, UINT, UINT, LPABCFLOAT); DWORD GetCharacterPlacementA(HDC, LPCSTR, int, int, LPGCP_RESULTSA, DWORD); DWORD GetCharacterPlacementW(HDC, LPCWSTR, int, int, LPGCP_RESULTSW, DWORD); BOOL GetCharWidth32A(HDC, UINT, UINT, LPINT); BOOL GetCharWidth32W(HDC, UINT, UINT, LPINT); BOOL GetCharWidthA(HDC, UINT, UINT, LPINT); BOOL GetCharWidthW(HDC, UINT, UINT, LPINT); BOOL GetCharWidthFloatA(HDC, UINT, UINT, PFLOAT); BOOL GetCharWidthFloatW(HDC, UINT, UINT, PFLOAT); int GetClipBox(HDC, LPRECT); int GetClipRgn(HDC, HRGN); BOOL GetColorAdjustment(HDC, LPCOLORADJUSTMENT); HANDLE GetColorSpace(HDC); HGDIOBJ GetCurrentObject(HDC, UINT); BOOL GetCurrentPositionEx(HDC, LPPOINT); HCURSOR GetCursor(); BOOL GetDCOrgEx(HDC, LPPOINT); static if (_WIN32_WINNT >= 0x500) { DWORD GetDCPenColor(HGDIOBJ); COLORREF GetDCBrushColor(HGDIOBJ); } int GetDeviceCaps(HDC, int); BOOL GetDeviceGammaRamp(HDC, PVOID); UINT GetDIBColorTable(HDC, UINT, UINT, RGBQUAD*); int GetDIBits(HDC, HBITMAP, UINT, UINT, PVOID, LPBITMAPINFO, UINT); HENHMETAFILE GetEnhMetaFileA(LPCSTR); HENHMETAFILE GetEnhMetaFileW(LPCWSTR); UINT GetEnhMetaFileBits(HENHMETAFILE, UINT, LPBYTE); UINT GetEnhMetaFileDescriptionA(HENHMETAFILE, UINT, LPSTR); UINT GetEnhMetaFileDescriptionW(HENHMETAFILE, UINT, LPWSTR); UINT GetEnhMetaFileHeader(HENHMETAFILE, UINT, LPENHMETAHEADER); UINT GetEnhMetaFilePaletteEntries(HENHMETAFILE, UINT, LPPALETTEENTRY); UINT GetEnhMetaFilePixelFormat(HENHMETAFILE, DWORD, const(PIXELFORMATDESCRIPTOR)*); DWORD GetFontData(HDC, DWORD, DWORD, PVOID, DWORD); DWORD GetFontLanguageInfo(HDC); DWORD GetGlyphOutlineA(HDC, UINT, UINT, LPGLYPHMETRICS, DWORD, PVOID, const(MAT2)*); DWORD GetGlyphOutlineW(HDC, UINT, UINT, LPGLYPHMETRICS, DWORD, PVOID, const(MAT2)*); int GetGraphicsMode(HDC); BOOL GetICMProfileA(HDC, DWORD, LPSTR); BOOL GetICMProfileW(HDC, DWORD, LPWSTR); DWORD GetKerningPairsA(HDC, DWORD, LPKERNINGPAIR); DWORD GetKerningPairsW(HDC, DWORD, LPKERNINGPAIR); BOOL GetLogColorSpaceA(HCOLORSPACE, LPLOGCOLORSPACEA, DWORD); BOOL GetLogColorSpaceW(HCOLORSPACE, LPLOGCOLORSPACEW, DWORD); int GetMapMode(HDC); HMETAFILE GetMetaFileA(LPCSTR); HMETAFILE GetMetaFileW(LPCWSTR); UINT GetMetaFileBitsEx(HMETAFILE, UINT, PVOID); int GetMetaRgn(HDC, HRGN); BOOL GetMiterLimit(HDC, PFLOAT); COLORREF GetNearestColor(HDC, COLORREF); UINT GetNearestPaletteIndex(HPALETTE, COLORREF); int GetObjectA(HGDIOBJ, int, PVOID); int GetObjectW(HGDIOBJ, int, PVOID); DWORD GetObjectType(HGDIOBJ); UINT GetOutlineTextMetricsA(HDC, UINT, LPOUTLINETEXTMETRICA); UINT GetOutlineTextMetricsW(HDC, UINT, LPOUTLINETEXTMETRICW); UINT GetPaletteEntries(HPALETTE, UINT, UINT, LPPALETTEENTRY); int GetPath(HDC, LPPOINT, PBYTE, int); COLORREF GetPixel(HDC, int, int); int GetPixelFormat(HDC); int GetPolyFillMode(HDC); BOOL GetRasterizerCaps(LPRASTERIZER_STATUS, UINT); int GetRandomRgn (HDC, HRGN, INT); DWORD GetRegionData(HRGN, DWORD, LPRGNDATA); int GetRgnBox(HRGN, LPRECT); int GetROP2(HDC); HGDIOBJ GetStockObject(int); int GetStretchBltMode(HDC); UINT GetSystemPaletteEntries(HDC, UINT, UINT, LPPALETTEENTRY); UINT GetSystemPaletteUse(HDC); UINT GetTextAlign(HDC); int GetTextCharacterExtra(HDC); int GetTextCharset(HDC); int GetTextCharsetInfo(HDC, LPFONTSIGNATURE, DWORD); COLORREF GetTextColor(HDC); BOOL GetTextExtentExPointA(HDC, LPCSTR, int, int, LPINT, LPINT, LPSIZE); BOOL GetTextExtentExPointW(HDC, LPCWSTR, int, int, LPINT, LPINT, LPSIZE); BOOL GetTextExtentPointA(HDC, LPCSTR, int, LPSIZE); BOOL GetTextExtentPointW(HDC, LPCWSTR, int, LPSIZE); BOOL GetTextExtentPoint32A(HDC, LPCSTR, int, LPSIZE); BOOL GetTextExtentPoint32W(HDC, LPCWSTR, int, LPSIZE); int GetTextFaceA(HDC, int, LPSTR); int GetTextFaceW(HDC, int, LPWSTR); BOOL GetTextMetricsA(HDC, LPTEXTMETRICA); BOOL GetTextMetricsW(HDC, LPTEXTMETRICW); BOOL GetViewportExtEx(HDC, LPSIZE); BOOL GetViewportOrgEx(HDC, LPPOINT); BOOL GetWindowExtEx(HDC, LPSIZE); BOOL GetWindowOrgEx(HDC, LPPOINT); UINT GetWinMetaFileBits(HENHMETAFILE, UINT, LPBYTE, INT, HDC); BOOL GetWorldTransform(HDC, LPXFORM); int IntersectClipRect(HDC, int, int, int, int); BOOL InvertRgn(HDC, HRGN); BOOL LineDDA(int, int, int, int, LINEDDAPROC, LPARAM); BOOL LineTo(HDC, int, int); BOOL LPtoDP(HDC, LPPOINT, int); BOOL MaskBlt(HDC, int, int, int, int, HDC, int, int, HBITMAP, int, int, DWORD); BOOL ModifyWorldTransform(HDC, const(XFORM)*, DWORD); BOOL MoveToEx(HDC, int, int, LPPOINT); int OffsetClipRgn(HDC, int, int); int OffsetRgn(HRGN, int, int); BOOL OffsetViewportOrgEx(HDC, int, int, LPPOINT); BOOL OffsetWindowOrgEx(HDC, int, int, LPPOINT); BOOL PaintRgn(HDC, HRGN); BOOL PatBlt(HDC, int, int, int, int, DWORD); HRGN PathToRegion(HDC); BOOL Pie(HDC, int, int, int, int, int, int, int, int); BOOL PlayEnhMetaFile(HDC, HENHMETAFILE, LPCRECT); BOOL PlayEnhMetaFileRecord(HDC, LPHANDLETABLE, const(ENHMETARECORD)*, UINT); BOOL PlayMetaFile(HDC, HMETAFILE); BOOL PlayMetaFileRecord(HDC, LPHANDLETABLE, LPMETARECORD, UINT); BOOL PlgBlt(HDC, const(POINT)*, HDC, int, int, int, int, HBITMAP, int, int); BOOL PolyBezier(HDC, const(POINT)*, DWORD); BOOL PolyBezierTo(HDC, const(POINT)*, DWORD); BOOL PolyDraw(HDC, const(POINT)*, const(BYTE)*, int); BOOL Polygon(HDC, const(POINT)*, int); BOOL Polyline(HDC, const(POINT)*, int); BOOL PolylineTo(HDC, const(POINT)*, DWORD); BOOL PolyPolygon(HDC, const(POINT)*, const(INT)*, int); BOOL PolyPolyline(HDC, const(POINT)*, const(DWORD)*, DWORD); BOOL PolyTextOutA(HDC, const(POLYTEXTA)*, int); BOOL PolyTextOutW(HDC, const(POLYTEXTW)*, int); BOOL PtInRegion(HRGN, int, int); BOOL PtVisible(HDC, int, int); UINT RealizePalette(HDC); BOOL Rectangle(HDC, int, int, int, int); BOOL RectInRegion(HRGN, LPCRECT); BOOL RectVisible(HDC, LPCRECT); BOOL RemoveFontResourceA(LPCSTR); BOOL RemoveFontResourceW(LPCWSTR); HDC ResetDCA(HDC, const(DEVMODEA)*); HDC ResetDCW(HDC, const(DEVMODEW)*); BOOL ResizePalette(HPALETTE, UINT); BOOL RestoreDC(HDC, int); BOOL RoundRect(HDC, int, int, int, int, int, int); int SaveDC(HDC); BOOL ScaleViewportExtEx(HDC, int, int, int, int, LPSIZE); BOOL ScaleWindowExtEx(HDC, int, int, int, int, LPSIZE); BOOL SelectClipPath(HDC, int); int SelectClipRgn(HDC, HRGN); HGDIOBJ SelectObject(HDC, HGDIOBJ); HPALETTE SelectPalette(HDC, HPALETTE, BOOL); int SetAbortProc(HDC, ABORTPROC); int SetArcDirection(HDC, int); LONG SetBitmapBits(HBITMAP, DWORD, PCVOID); BOOL SetBitmapDimensionEx(HBITMAP, int, int, LPSIZE); COLORREF SetBkColor(HDC, COLORREF); int SetBkMode(HDC, int); UINT SetBoundsRect(HDC, LPCRECT, UINT); BOOL SetBrushOrgEx(HDC, int, int, LPPOINT); BOOL SetColorAdjustment(HDC, const(COLORADJUSTMENT)*); BOOL SetColorSpace(HDC, HCOLORSPACE); BOOL SetDeviceGammaRamp(HDC, PVOID); UINT SetDIBColorTable(HDC, UINT, UINT, const(RGBQUAD)*); int SetDIBits(HDC, HBITMAP, UINT, UINT, PCVOID, const(BITMAPINFO)*, UINT); int SetDIBitsToDevice(HDC, int, int, DWORD, DWORD, int, int, UINT, UINT, PCVOID, const(BITMAPINFO)*, UINT); HENHMETAFILE SetEnhMetaFileBits(UINT, const(BYTE)*); int SetGraphicsMode(HDC, int); int SetICMMode(HDC, int); BOOL SetICMProfileA(HDC, LPSTR); BOOL SetICMProfileW(HDC, LPWSTR); int SetMapMode(HDC, int); static if (_WIN32_WINNT >= 0x500) { DWORD SetLayout(HDC hdc, DWORD l); DWORD GetLayout(HDC hdc); } DWORD SetMapperFlags(HDC, DWORD); HMETAFILE SetMetaFileBitsEx(UINT, const(BYTE)*); int SetMetaRgn(HDC); BOOL SetMiterLimit(HDC, FLOAT, PFLOAT); UINT SetPaletteEntries(HPALETTE, UINT, UINT, const(PALETTEENTRY)*); COLORREF SetPixel(HDC, int, int, COLORREF); BOOL SetPixelFormat(HDC, int, const(PIXELFORMATDESCRIPTOR)*); BOOL SetPixelV(HDC, int, int, COLORREF); int SetPolyFillMode(HDC, int); BOOL SetRectRgn(HRGN, int, int, int, int); int SetROP2(HDC, int); int SetStretchBltMode(HDC, int); UINT SetSystemPaletteUse(HDC, UINT); UINT SetTextAlign(HDC, UINT); int SetTextCharacterExtra(HDC, int); COLORREF SetTextColor(HDC, COLORREF); BOOL SetTextJustification(HDC, int, int); BOOL SetViewportExtEx(HDC, int, int, LPSIZE); BOOL SetViewportOrgEx(HDC, int, int, LPPOINT); BOOL SetWindowExtEx(HDC, int, int, LPSIZE); BOOL SetWindowOrgEx(HDC, int, int, LPPOINT); HENHMETAFILE SetWinMetaFileBits(UINT, const(BYTE)*, HDC, const(METAFILEPICT)*); BOOL SetWorldTransform(HDC, const(XFORM)*); int StartDocA(HDC, const(DOCINFOA)*); int StartDocW(HDC, const(DOCINFOW)*); int StartPage(HDC); BOOL StretchBlt(HDC, int, int, int, int, HDC, int, int, int, int, DWORD); int StretchDIBits(HDC, int, int, int, int, int, int, int, int, const(VOID)* , const(BITMAPINFO)* , UINT, DWORD); BOOL StrokeAndFillPath(HDC); BOOL StrokePath(HDC); BOOL SwapBuffers(HDC); BOOL TextOutA(HDC, int, int, LPCSTR, int); BOOL TextOutW(HDC, int, int, LPCWSTR, int); BOOL TranslateCharsetInfo(PDWORD, LPCHARSETINFO, DWORD); BOOL UnrealizeObject(HGDIOBJ); BOOL UpdateColors(HDC); BOOL UpdateICMRegKeyA(DWORD, DWORD, LPSTR, UINT); BOOL UpdateICMRegKeyW(DWORD, DWORD, LPWSTR, UINT); BOOL WidenPath(HDC); BOOL wglCopyContext(HGLRC, HGLRC, UINT); HGLRC wglCreateContext(HDC); HGLRC wglCreateLayerContext(HDC, int); BOOL wglDeleteContext(HGLRC); BOOL wglDescribeLayerPlane(HDC, int, int, UINT, LPLAYERPLANEDESCRIPTOR); HGLRC wglGetCurrentContext(); HDC wglGetCurrentDC(); int wglGetLayerPaletteEntries(HDC, int, int, int, COLORREF*); PROC wglGetProcAddress(LPCSTR); BOOL wglMakeCurrent(HDC, HGLRC); BOOL wglRealizeLayerPalette(HDC, int, BOOL); int wglSetLayerPaletteEntries(HDC, int, int, int, const(COLORREF)*); BOOL wglShareLists(HGLRC, HGLRC); BOOL wglSwapLayerBuffers(HDC, UINT); BOOL wglUseFontBitmapsA(HDC, DWORD, DWORD, DWORD); BOOL wglUseFontBitmapsW(HDC, DWORD, DWORD, DWORD); BOOL wglUseFontOutlinesA(HDC, DWORD, DWORD, DWORD, FLOAT, FLOAT, int, LPGLYPHMETRICSFLOAT); BOOL wglUseFontOutlinesW(HDC, DWORD, DWORD, DWORD, FLOAT, FLOAT, int, LPGLYPHMETRICSFLOAT); static if (_WIN32_WINNT >= 0x500) { alias WGLSWAP* PWGLSWAP; struct WGLSWAP { HDC hdc; UINT uiFlags; } enum WGL_SWAPMULTIPLE_MAX = 16; DWORD wglSwapMultipleBuffers(UINT, WGLSWAP*); } static if (_WIN32_WINNT >= 0x500) { BOOL AlphaBlend(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION); BOOL GradientFill(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); BOOL TransparentBlt(HDC, int, int, int, int, HDC, int, int, int, int, UINT); } static if (_WIN32_WINNT >= 0x500) { COLORREF SetDCBrushColor(HDC, COLORREF); COLORREF SetDCPenColor(HDC, COLORREF); HANDLE AddFontMemResourceEx(PVOID, DWORD, PVOID, DWORD*); int AddFontResourceExA(LPCSTR, DWORD, PVOID); int AddFontResourceExW(LPCWSTR, DWORD, PVOID); BOOL RemoveFontMemResourceEx(HANDLE); BOOL RemoveFontResourceExA(LPCSTR, DWORD, PVOID); BOOL RemoveFontResourceExW(LPCWSTR, DWORD, PVOID); DWORD GetFontUnicodeRanges(HDC, LPGLYPHSET); DWORD GetGlyphIndicesA(HDC, LPCSTR, int, LPWORD, DWORD); DWORD GetGlyphIndicesW(HDC, LPCWSTR, int, LPWORD, DWORD); BOOL GetTextExtentPointI(HDC, LPWORD, int, LPSIZE); BOOL GetTextExtentExPointI(HDC, LPWORD, int, int, LPINT, LPINT, LPSIZE); BOOL GetCharWidthI(HDC, UINT, UINT, LPWORD, LPINT); BOOL GetCharABCWidthsI(HDC, UINT, UINT, LPWORD, LPABC); } } // extern (Windows) version(Unicode) { alias WCHAR BCHAR; alias DOCINFOW DOCINFO; alias LOGFONTW LOGFONT; alias TEXTMETRICW TEXTMETRIC; alias NPTEXTMETRICW NPTEXTMETRIC; alias ICMENUMPROCW ICMENUMPROC; alias FONTENUMPROCW FONTENUMPROC; alias DEVMODEW DEVMODE; alias EXTLOGFONTW EXTLOGFONT; alias GCP_RESULTSW GCP_RESULTS; alias OUTLINETEXTMETRICW OUTLINETEXTMETRIC; alias POLYTEXTW POLYTEXT; alias LOGCOLORSPACEW LOGCOLORSPACE; alias NEWTEXTMETRICW NEWTEXTMETRIC; alias NEWTEXTMETRICEXW NEWTEXTMETRICEX; alias ENUMLOGFONTW ENUMLOGFONT; alias ENUMLOGFONTEXW ENUMLOGFONTEX; alias DISPLAY_DEVICEW DISPLAY_DEVICE; alias AddFontResourceW AddFontResource; alias CopyEnhMetaFileW CopyEnhMetaFile; alias CopyMetaFileW CopyMetaFile; alias CreateColorSpaceW CreateColorSpace; alias CreateDCW CreateDC; alias CreateEnhMetaFileW CreateEnhMetaFile; alias CreateFontW CreateFont; alias CreateFontIndirectW CreateFontIndirect; alias CreateICW CreateIC; alias CreateMetaFileW CreateMetaFile; alias CreateScalableFontResourceW CreateScalableFontResource; alias DeviceCapabilitiesW DeviceCapabilities; alias EnumFontFamiliesW EnumFontFamilies; alias EnumFontFamiliesExW EnumFontFamiliesEx; alias EnumFontsW EnumFonts; alias EnumICMProfilesW EnumICMProfiles; alias ExtTextOutW ExtTextOut; alias GetCharABCWidthsFloatW GetCharABCWidthsFloat; alias GetCharABCWidthsW GetCharABCWidths; alias GetCharacterPlacementW GetCharacterPlacement; alias GetCharWidth32W GetCharWidth32; alias GetCharWidthFloatW GetCharWidthFloat; alias GetCharWidthW GetCharWidth; alias GetEnhMetaFileW GetEnhMetaFile; alias GetEnhMetaFileDescriptionW GetEnhMetaFileDescription; alias GetGlyphOutlineW GetGlyphOutline; alias GetICMProfileW GetICMProfile; alias GetKerningPairsW GetKerningPairs; alias GetLogColorSpaceW GetLogColorSpace; alias GetMetaFileW GetMetaFile; alias GetObjectW GetObject; alias GetOutlineTextMetricsW GetOutlineTextMetrics; alias GetTextExtentPointW GetTextExtentPoint; alias GetTextExtentExPointW GetTextExtentExPoint; alias GetTextExtentPoint32W GetTextExtentPoint32; alias GetTextFaceW GetTextFace; alias GetTextMetricsW GetTextMetrics; alias PolyTextOutW PolyTextOut; alias RemoveFontResourceW RemoveFontResource; alias ResetDCW ResetDC; alias SetICMProfileW SetICMProfile; alias StartDocW StartDoc; alias TextOutW TextOut; alias UpdateICMRegKeyW UpdateICMRegKey; alias wglUseFontBitmapsW wglUseFontBitmaps; alias wglUseFontOutlinesW wglUseFontOutlines; static if (_WIN32_WINNT >= 0x500) { alias ENUMLOGFONTEXDVW ENUMLOGFONTEXDV; alias PENUMLOGFONTEXDVW PENUMLOGFONTEXDV; alias LPENUMLOGFONTEXDVW LPENUMLOGFONTEXDV; alias AddFontResourceExW AddFontResourceEx; alias RemoveFontResourceExW RemoveFontResourceEx; alias GetGlyphIndicesW GetGlyphIndices; } } else { /* non-unicode build */ alias BYTE BCHAR; alias DOCINFOA DOCINFO; alias LOGFONTA LOGFONT; alias TEXTMETRICA TEXTMETRIC; alias NPTEXTMETRICA NPTEXTMETRIC; alias ICMENUMPROCA ICMENUMPROC; alias FONTENUMPROCA FONTENUMPROC; alias DEVMODEA DEVMODE; alias EXTLOGFONTA EXTLOGFONT; alias GCP_RESULTSA GCP_RESULTS; alias OUTLINETEXTMETRICA OUTLINETEXTMETRIC; alias POLYTEXTA POLYTEXT; alias LOGCOLORSPACEA LOGCOLORSPACE; alias NEWTEXTMETRICA NEWTEXTMETRIC; alias NEWTEXTMETRICEXA NEWTEXTMETRICEX; alias ENUMLOGFONTA ENUMLOGFONT; alias ENUMLOGFONTEXA ENUMLOGFONTEX; alias DISPLAY_DEVICEA DISPLAY_DEVICE; alias AddFontResourceA AddFontResource; alias CopyEnhMetaFileA CopyEnhMetaFile; alias CopyMetaFileA CopyMetaFile; alias CreateColorSpaceA CreateColorSpace; alias CreateDCA CreateDC; alias CreateEnhMetaFileA CreateEnhMetaFile; alias CreateFontA CreateFont; alias CreateFontIndirectA CreateFontIndirect; alias CreateICA CreateIC; alias CreateMetaFileA CreateMetaFile; alias CreateScalableFontResourceA CreateScalableFontResource; alias DeviceCapabilitiesA DeviceCapabilities; alias EnumFontFamiliesA EnumFontFamilies; alias EnumFontFamiliesExA EnumFontFamiliesEx; alias EnumFontsA EnumFonts; alias EnumICMProfilesA EnumICMProfiles; alias ExtTextOutA ExtTextOut; alias GetCharWidthFloatA GetCharWidthFloat; alias GetCharWidthA GetCharWidth; alias GetCharacterPlacementA GetCharacterPlacement; alias GetCharABCWidthsA GetCharABCWidths; alias GetCharABCWidthsFloatA GetCharABCWidthsFloat; alias GetCharWidth32A GetCharWidth32; alias GetEnhMetaFileA GetEnhMetaFile; alias GetEnhMetaFileDescriptionA GetEnhMetaFileDescription; alias GetGlyphOutlineA GetGlyphOutline; alias GetICMProfileA GetICMProfile; alias GetKerningPairsA GetKerningPairs; alias GetLogColorSpaceA GetLogColorSpace; alias GetMetaFileA GetMetaFile; alias GetObjectA GetObject; alias GetOutlineTextMetricsA GetOutlineTextMetrics; alias GetTextExtentPointA GetTextExtentPoint; alias GetTextExtentExPointA GetTextExtentExPoint; alias GetTextExtentPoint32A GetTextExtentPoint32; alias GetTextFaceA GetTextFace; alias GetTextMetricsA GetTextMetrics; alias PolyTextOutA PolyTextOut; alias RemoveFontResourceA RemoveFontResource; alias ResetDCA ResetDC; alias SetICMProfileA SetICMProfile; alias StartDocA StartDoc; alias TextOutA TextOut; alias UpdateICMRegKeyA UpdateICMRegKey; alias wglUseFontBitmapsA wglUseFontBitmaps; alias wglUseFontOutlinesA wglUseFontOutlines; static if (_WIN32_WINNT >= 0x500) { alias ENUMLOGFONTEXDVA ENUMLOGFONTEXDV; alias PENUMLOGFONTEXDVA PENUMLOGFONTEXDV; alias LPENUMLOGFONTEXDVA LPENUMLOGFONTEXDV; alias AddFontResourceExA AddFontResourceEx; alias RemoveFontResourceExA RemoveFontResourceEx; alias GetGlyphIndicesA GetGlyphIndices; } } // Common to both ASCII & UNICODE alias DOCINFO* LPDOCINFO; alias LOGFONT* PLOGFONT, NPLOGFONT, LPLOGFONT; alias TEXTMETRIC* PTEXTMETRIC, LPTEXTMETRIC; alias DEVMODE* PDEVMODE, NPDEVMODE, LPDEVMODE; alias EXTLOGFONT* PEXTLOGFONT, NPEXTLOGFONT, LPEXTLOGFONT; alias GCP_RESULTS* LPGCP_RESULTS; alias OUTLINETEXTMETRIC* POUTLINETEXTMETRIC, NPOUTLINETEXTMETRIC, LPOUTLINETEXTMETRIC; alias POLYTEXT* PPOLYTEXT, NPPOLYTEXT, LPPOLYTEXT; alias LOGCOLORSPACE* LPLOGCOLORSPACE; alias NEWTEXTMETRIC* PNEWTEXTMETRIC, NPNEWTEXTMETRIC, LPNEWTEXTMETRIC; alias ENUMLOGFONT* LPENUMLOGFONT; alias ENUMLOGFONTEX* LPENUMLOGFONTEX; alias DISPLAY_DEVICE* PDISPLAY_DEVICE, LPDISPLAY_DEVICE; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/commdlg.d0000664000175000017500000005322712776214756023312 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.12 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_commdlg.d) */ module core.sys.windows.commdlg; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "comdlg32"); private import core.sys.windows.w32api; import core.sys.windows.windef, core.sys.windows.winuser; import core.sys.windows.wingdi; // for LPLOGFONTA const TCHAR[] LBSELCHSTRING = "commdlg_LBSelChangedNotify", SHAREVISTRING = "commdlg_ShareViolation", FILEOKSTRING = "commdlg_FileNameOK", COLOROKSTRING = "commdlg_ColorOK", SETRGBSTRING = "commdlg_SetRGBColor", HELPMSGSTRING = "commdlg_help", FINDMSGSTRING = "commdlg_FindReplace"; enum : UINT { CDN_FIRST = -601, // also in commctrl.h CDN_LAST = -699, CDN_INITDONE = CDN_FIRST, CDN_SELCHANGE = CDN_FIRST - 1, CDN_FOLDERCHANGE = CDN_FIRST - 2, CDN_SHAREVIOLATION = CDN_FIRST - 3, CDN_HELP = CDN_FIRST - 4, CDN_FILEOK = CDN_FIRST - 5, CDN_TYPECHANGE = CDN_FIRST - 6, } //static if(_WIN32_WINNT >= 0x500) { enum : UINT { CDN_INCLUDEITEM = CDN_FIRST - 7, } //} enum : UINT { CDM_FIRST = WM_USER + 100, CDM_LAST = WM_USER + 200, CDM_GETSPEC = CDM_FIRST, CDM_GETFILEPATH, CDM_GETFOLDERPATH, CDM_GETFOLDERIDLIST, CDM_SETCONTROLTEXT, CDM_HIDECONTROL, CDM_SETDEFEXT // = CDM_FIRST + 6 } // flags for ChooseColor enum : DWORD { CC_RGBINIT = 0x0001, CC_FULLOPEN = 0x0002, CC_PREVENTFULLOPEN = 0x0004, CC_SHOWHELP = 0x0008, CC_ENABLEHOOK = 0x0010, CC_ENABLETEMPLATE = 0x0020, CC_ENABLETEMPLATEHANDLE = 0x0040, CC_SOLIDCOLOR = 0x0080, CC_ANYCOLOR = 0x0100 } // flags for ChooseFont enum : DWORD { CF_SCREENFONTS = 0x00000001, CF_PRINTERFONTS = 0x00000002, CF_BOTH = 0x00000003, CF_SHOWHELP = 0x00000004, CF_ENABLEHOOK = 0x00000008, CF_ENABLETEMPLATE = 0x00000010, CF_ENABLETEMPLATEHANDLE = 0x00000020, CF_INITTOLOGFONTSTRUCT = 0x00000040, CF_USESTYLE = 0x00000080, CF_EFFECTS = 0x00000100, CF_APPLY = 0x00000200, CF_ANSIONLY = 0x00000400, CF_SCRIPTSONLY = CF_ANSIONLY, CF_NOVECTORFONTS = 0x00000800, CF_NOOEMFONTS = 0x00000800, CF_NOSIMULATIONS = 0x00001000, CF_LIMITSIZE = 0x00002000, CF_FIXEDPITCHONLY = 0x00004000, CF_WYSIWYG = 0x00008000, CF_FORCEFONTEXIST = 0x00010000, CF_SCALABLEONLY = 0x00020000, CF_TTONLY = 0x00040000, CF_NOFACESEL = 0x00080000, CF_NOSTYLESEL = 0x00100000, CF_NOSIZESEL = 0x00200000, CF_SELECTSCRIPT = 0x00400000, CF_NOSCRIPTSEL = 0x00800000, CF_NOVERTFONTS = 0x01000000 } // Font type for ChooseFont enum : WORD { BOLD_FONTTYPE = 0x0100, ITALIC_FONTTYPE = 0x0200, REGULAR_FONTTYPE = 0x0400, SCREEN_FONTTYPE = 0x2000, PRINTER_FONTTYPE = 0x4000, SIMULATED_FONTTYPE = 0x8000 } enum : UINT { WM_CHOOSEFONT_GETLOGFONT = WM_USER + 1, WM_CHOOSEFONT_SETLOGFONT = WM_USER + 101, WM_CHOOSEFONT_SETFLAGS = WM_USER + 102 } // flags for OpenFileName enum : DWORD { OFN_SHAREWARN = 0, OFN_SHARENOWARN = 0x000001, OFN_READONLY = 0x000001, OFN_SHAREFALLTHROUGH = 0x000002, OFN_OVERWRITEPROMPT = 0x000002, OFN_HIDEREADONLY = 0x000004, OFN_NOCHANGEDIR = 0x000008, OFN_SHOWHELP = 0x000010, OFN_ENABLEHOOK = 0x000020, OFN_ENABLETEMPLATE = 0x000040, OFN_ENABLETEMPLATEHANDLE = 0x000080, OFN_NOVALIDATE = 0x000100, OFN_ALLOWMULTISELECT = 0x000200, OFN_EXTENSIONDIFFERENT = 0x000400, OFN_PATHMUSTEXIST = 0x000800, OFN_FILEMUSTEXIST = 0x001000, OFN_CREATEPROMPT = 0x002000, OFN_SHAREAWARE = 0x004000, OFN_NOREADONLYRETURN = 0x008000, OFN_NOTESTFILECREATE = 0x010000, OFN_NONETWORKBUTTON = 0x020000, OFN_NOLONGNAMES = 0x040000, OFN_EXPLORER = 0x080000, OFN_NODEREFERENCELINKS = 0x100000, OFN_LONGNAMES = 0x200000, OFN_ENABLESIZING = 0x800000 } enum : DWORD { FR_DOWN = 0x00000001, FR_WHOLEWORD = 0x00000002, FR_MATCHCASE = 0x00000004, FR_FINDNEXT = 0x00000008, FR_REPLACE = 0x00000010, FR_REPLACEALL = 0x00000020, FR_DIALOGTERM = 0x00000040, FR_SHOWHELP = 0x00000080, FR_ENABLEHOOK = 0x00000100, FR_ENABLETEMPLATE = 0x00000200, FR_NOUPDOWN = 0x00000400, FR_NOMATCHCASE = 0x00000800, FR_NOWHOLEWORD = 0x00001000, FR_ENABLETEMPLATEHANDLE = 0x00002000, FR_HIDEUPDOWN = 0x00004000, FR_HIDEMATCHCASE = 0x00008000, FR_HIDEWHOLEWORD = 0x00010000, FR_MATCHDIAC = 0x20000000, FR_MATCHKASHIDA = 0x40000000, FR_MATCHALEFHAMZA = 0x80000000 } enum : DWORD { PD_ALLPAGES = 0, PD_SELECTION = 0x000001, PD_PAGENUMS = 0x000002, PD_NOSELECTION = 0x000004, PD_NOPAGENUMS = 0x000008, PD_COLLATE = 0x000010, PD_PRINTTOFILE = 0x000020, PD_PRINTSETUP = 0x000040, PD_NOWARNING = 0x000080, PD_RETURNDC = 0x000100, PD_RETURNIC = 0x000200, PD_RETURNDEFAULT = 0x000400, PD_SHOWHELP = 0x000800, PD_ENABLEPRINTHOOK = 0x001000, PD_ENABLESETUPHOOK = 0x002000, PD_ENABLEPRINTTEMPLATE = 0x004000, PD_ENABLESETUPTEMPLATE = 0x008000, PD_ENABLEPRINTTEMPLATEHANDLE = 0x010000, PD_ENABLESETUPTEMPLATEHANDLE = 0x020000, PD_USEDEVMODECOPIES = 0x040000, PD_USEDEVMODECOPIESANDCOLLATE = 0x040000, PD_DISABLEPRINTTOFILE = 0x080000, PD_HIDEPRINTTOFILE = 0x100000, PD_NONETWORKBUTTON = 0x200000 } //static if (_WIN32_WINNT >= 0x500) { enum : DWORD { PD_CURRENTPAGE = 0x00400000, PD_NOCURRENTPAGE = 0x00800000, PD_EXCLUSIONFLAGS = 0x01000000, PD_USELARGETEMPLATE = 0x10000000, } enum : HRESULT { PD_RESULT_CANCEL, PD_RESULT_PRINT, PD_RESULT_APPLY } enum DWORD START_PAGE_GENERAL = 0xFFFFFFFF; //} enum { PSD_DEFAULTMINMARGINS = 0, PSD_INWININIINTLMEASURE = 0, PSD_MINMARGINS = 0x000001, PSD_MARGINS = 0x000002, PSD_INTHOUSANDTHSOFINCHES = 0x000004, PSD_INHUNDREDTHSOFMILLIMETERS = 0x000008, PSD_DISABLEMARGINS = 0x000010, PSD_DISABLEPRINTER = 0x000020, PSD_NOWARNING = 0x000080, PSD_DISABLEORIENTATION = 0x000100, PSD_DISABLEPAPER = 0x000200, PSD_RETURNDEFAULT = 0x000400, PSD_SHOWHELP = 0x000800, PSD_ENABLEPAGESETUPHOOK = 0x002000, PSD_ENABLEPAGESETUPTEMPLATE = 0x008000, PSD_ENABLEPAGESETUPTEMPLATEHANDLE = 0x020000, PSD_ENABLEPAGEPAINTHOOK = 0x040000, PSD_DISABLEPAGEPAINTING = 0x080000 } enum : UINT { WM_PSD_PAGESETUPDLG = WM_USER, WM_PSD_FULLPAGERECT, WM_PSD_MINMARGINRECT, WM_PSD_MARGINRECT, WM_PSD_GREEKTEXTRECT, WM_PSD_ENVSTAMPRECT, WM_PSD_YAFULLPAGERECT // = WM_USER + 6 } enum : int { CD_LBSELNOITEMS = -1, CD_LBSELCHANGE, CD_LBSELSUB, CD_LBSELADD } enum WORD DN_DEFAULTPRN = 1; /+ // Both MinGW and the windows docs indicate that there are macros for the send messages // the controls. These seem to be totally unnecessary -- and at least one of MinGW or // Windows Docs is buggy! int CommDlg_OpenSave_GetSpec(HWND hWndControl, LPARAM lparam, WPARAM wParam) { return SendMessage(hWndControl, CDM_GETSPEC, wParam, lParam); } int CommDlg_OpenSave_GetFilePath(HWND hWndControl, LPARAM lparam, WPARAM wParam) { return SendMessage(hWndControl, CDM_GETFILEPATH, wParam, lParam); } int CommDlg_OpenSave_GetFolderPath(HWND hWndControl, LPARAM lparam, WPARAM wParam) { return SendMessage(hWndControl, CDM_GETFOLDERPATH, wParam, lParam); } int CommDlg_OpenSave_GetFolderIDList(HWND hWndControl, LPARAM lparam, WPARAM wParam) { return SendMessage(hWndControl, CDM_GETFOLDERIDLIST, wParam, lParam); } void CommDlg_OpenSave_SetControlText(HWND hWndControl, LPARAM lparam, WPARAM wParam) { return SendMessage(hWndControl, CDM_SETCONTROLTEXT, wParam, lParam); } void CommDlg_OpenSave_HideControl(HWND hWndControl, WPARAM wParam) { return SendMessage(hWndControl, CDM_HIDECONTROL, wParam, 0); } void CommDlg_OpenSave_SetDefExt(HWND hWndControl, TCHAR* lparam) { return SendMessage(hWndControl, CDM_SETCONTROLTEXT, 0, cast(LPARAM)lParam); } // These aliases seem even more unnecessary alias CommDlg_OpenSave_GetSpec CommDlg_OpenSave_GetSpecA, CommDlg_OpenSave_GetSpecW; alias CommDlg_OpenSave_GetFilePath CommDlg_OpenSave_GetFilePathA, CommDlg_OpenSave_GetFilePathW; alias CommDlg_OpenSave_GetFolderPath CommDlg_OpenSave_GetFolderPathA, CommDlg_OpenSave_GetFolderPathW; +/ // Callbacks. extern(Windows) { alias UINT_PTR function (HWND, UINT, WPARAM, LPARAM) nothrow LPCCHOOKPROC, LPCFHOOKPROC, LPFRHOOKPROC, LPOFNHOOKPROC, LPPAGEPAINTHOOK, LPPAGESETUPHOOK, LPSETUPHOOKPROC, LPPRINTHOOKPROC; } align (1): struct CHOOSECOLORA { DWORD lStructSize = CHOOSECOLORA.sizeof; HWND hwndOwner; HWND hInstance; COLORREF rgbResult; COLORREF* lpCustColors; DWORD Flags; LPARAM lCustData; LPCCHOOKPROC lpfnHook; LPCSTR lpTemplateName; } alias CHOOSECOLORA* LPCHOOSECOLORA; struct CHOOSECOLORW { DWORD lStructSize = CHOOSECOLORW.sizeof; HWND hwndOwner; HWND hInstance; COLORREF rgbResult; COLORREF* lpCustColors; DWORD Flags; LPARAM lCustData; LPCCHOOKPROC lpfnHook; LPCWSTR lpTemplateName; } alias CHOOSECOLORW* LPCHOOSECOLORW; align (4) struct CHOOSEFONTA { DWORD lStructSize = CHOOSEFONTA.sizeof; HWND hwndOwner; HDC hDC; LPLOGFONTA lpLogFont; INT iPointSize; DWORD Flags; DWORD rgbColors; LPARAM lCustData; LPCFHOOKPROC lpfnHook; LPCSTR lpTemplateName; HINSTANCE hInstance; LPSTR lpszStyle; WORD nFontType; //WORD ___MISSING_ALIGNMENT__; INT nSizeMin; INT nSizeMax; } alias CHOOSEFONTA* LPCHOOSEFONTA; align (4) struct CHOOSEFONTW { DWORD lStructSize = CHOOSEFONTW.sizeof; HWND hwndOwner; HDC hDC; LPLOGFONTW lpLogFont; INT iPointSize; DWORD Flags; DWORD rgbColors; LPARAM lCustData; LPCFHOOKPROC lpfnHook; LPCWSTR lpTemplateName; HINSTANCE hInstance; LPWSTR lpszStyle; WORD nFontType; //WORD ___MISSING_ALIGNMENT__; INT nSizeMin; INT nSizeMax; } alias CHOOSEFONTW* LPCHOOSEFONTW; struct DEVNAMES { WORD wDriverOffset; WORD wDeviceOffset; WORD wOutputOffset; WORD wDefault; } alias DEVNAMES* LPDEVNAMES; struct FINDREPLACEA { DWORD lStructSize = FINDREPLACEA.sizeof; HWND hwndOwner; HINSTANCE hInstance; DWORD Flags; LPSTR lpstrFindWhat; LPSTR lpstrReplaceWith; WORD wFindWhatLen; WORD wReplaceWithLen; LPARAM lCustData; LPFRHOOKPROC lpfnHook; LPCSTR lpTemplateName; } alias FINDREPLACEA* LPFINDREPLACEA; struct FINDREPLACEW { DWORD lStructSize = FINDREPLACEW.sizeof; HWND hwndOwner; HINSTANCE hInstance; DWORD Flags; LPWSTR lpstrFindWhat; LPWSTR lpstrReplaceWith; WORD wFindWhatLen; WORD wReplaceWithLen; LPARAM lCustData; LPFRHOOKPROC lpfnHook; LPCWSTR lpTemplateName; } alias FINDREPLACEW* LPFINDREPLACEW; struct OPENFILENAMEA { DWORD lStructSize = OPENFILENAMEA.sizeof; HWND hwndOwner; HINSTANCE hInstance; LPCSTR lpstrFilter; LPSTR lpstrCustomFilter; DWORD nMaxCustFilter; DWORD nFilterIndex; LPSTR lpstrFile; DWORD nMaxFile; LPSTR lpstrFileTitle; DWORD nMaxFileTitle; LPCSTR lpstrInitialDir; LPCSTR lpstrTitle; DWORD Flags; WORD nFileOffset; WORD nFileExtension; LPCSTR lpstrDefExt; LPARAM lCustData; LPOFNHOOKPROC lpfnHook; LPCSTR lpTemplateName; //static if (_WIN32_WINNT >= 0x500) { void *pvReserved; DWORD dwReserved; DWORD FlagsEx; //} } alias OPENFILENAMEA* LPOPENFILENAMEA; struct OPENFILENAMEW { DWORD lStructSize = OPENFILENAMEW.sizeof; HWND hwndOwner; HINSTANCE hInstance; LPCWSTR lpstrFilter; LPWSTR lpstrCustomFilter; DWORD nMaxCustFilter; DWORD nFilterIndex; LPWSTR lpstrFile; DWORD nMaxFile; LPWSTR lpstrFileTitle; DWORD nMaxFileTitle; LPCWSTR lpstrInitialDir; LPCWSTR lpstrTitle; DWORD Flags; WORD nFileOffset; WORD nFileExtension; LPCWSTR lpstrDefExt; LPARAM lCustData; LPOFNHOOKPROC lpfnHook; LPCWSTR lpTemplateName; //static if (_WIN32_WINNT >= 0x500) { void *pvReserved; DWORD dwReserved; DWORD FlagsEx; //} } alias OPENFILENAMEW* LPOPENFILENAMEW; enum size_t OPENFILENAME_SIZE_VERSION_400 = 76; struct OFNOTIFYA { NMHDR hdr; LPOPENFILENAMEA lpOFN; LPSTR pszFile; } alias OFNOTIFYA* LPOFNOTIFYA; struct OFNOTIFYW { NMHDR hdr; LPOPENFILENAMEW lpOFN; LPWSTR pszFile; } alias OFNOTIFYW* LPOFNOTIFYW; struct PAGESETUPDLGA { DWORD lStructSize = PAGESETUPDLGA.sizeof; HWND hwndOwner; HGLOBAL hDevMode; HGLOBAL hDevNames; DWORD Flags; POINT ptPaperSize; RECT rtMinMargin; RECT rtMargin; HINSTANCE hInstance; LPARAM lCustData; LPPAGESETUPHOOK lpfnPageSetupHook; LPPAGEPAINTHOOK lpfnPagePaintHook; LPCSTR lpPageSetupTemplateName; HGLOBAL hPageSetupTemplate; } alias PAGESETUPDLGA* LPPAGESETUPDLGA; struct PAGESETUPDLGW { DWORD lStructSize = PAGESETUPDLGW.sizeof; HWND hwndOwner; HGLOBAL hDevMode; HGLOBAL hDevNames; DWORD Flags; POINT ptPaperSize; RECT rtMinMargin; RECT rtMargin; HINSTANCE hInstance; LPARAM lCustData; LPPAGESETUPHOOK lpfnPageSetupHook; LPPAGEPAINTHOOK lpfnPagePaintHook; LPCWSTR lpPageSetupTemplateName; HGLOBAL hPageSetupTemplate; } alias PAGESETUPDLGW* LPPAGESETUPDLGW; struct PRINTDLGA { DWORD lStructSize = PRINTDLGA.sizeof; HWND hwndOwner; HANDLE hDevMode; HANDLE hDevNames; HDC hDC; DWORD Flags; WORD nFromPage; WORD nToPage; WORD nMinPage; WORD nMaxPage; WORD nCopies; HINSTANCE hInstance; LPARAM lCustData; LPPRINTHOOKPROC lpfnPrintHook; LPSETUPHOOKPROC lpfnSetupHook; LPCSTR lpPrintTemplateName; LPCSTR lpSetupTemplateName; HANDLE hPrintTemplate; HANDLE hSetupTemplate; } alias PRINTDLGA* LPPRINTDLGA; struct PRINTDLGW { DWORD lStructSize = PRINTDLGW.sizeof; HWND hwndOwner; HANDLE hDevMode; HANDLE hDevNames; HDC hDC; DWORD Flags; WORD nFromPage; WORD nToPage; WORD nMinPage; WORD nMaxPage; WORD nCopies; HINSTANCE hInstance; LPARAM lCustData; LPPRINTHOOKPROC lpfnPrintHook; LPSETUPHOOKPROC lpfnSetupHook; LPCWSTR lpPrintTemplateName; LPCWSTR lpSetupTemplateName; HANDLE hPrintTemplate; HANDLE hSetupTemplate; } alias PRINTDLGW* LPPRINTDLGW; //static if (_WIN32_WINNT >= 0x500) { import core.sys.windows.unknwn; // for LPUNKNOWN import core.sys.windows.prsht; // for HPROPSHEETPAGE struct PRINTPAGERANGE { DWORD nFromPage; DWORD nToPage; } alias PRINTPAGERANGE* LPPRINTPAGERANGE; struct PRINTDLGEXA { DWORD lStructSize = PRINTDLGEXA.sizeof; HWND hwndOwner; HGLOBAL hDevMode; HGLOBAL hDevNames; HDC hDC; DWORD Flags; DWORD Flags2; DWORD ExclusionFlags; DWORD nPageRanges; DWORD nMaxPageRanges; LPPRINTPAGERANGE lpPageRanges; DWORD nMinPage; DWORD nMaxPage; DWORD nCopies; HINSTANCE hInstance; LPCSTR lpPrintTemplateName; LPUNKNOWN lpCallback; DWORD nPropertyPages; HPROPSHEETPAGE* lphPropertyPages; DWORD nStartPage; DWORD dwResultAction; } alias PRINTDLGEXA* LPPRINTDLGEXA; struct PRINTDLGEXW { DWORD lStructSize = PRINTDLGEXW.sizeof; HWND hwndOwner; HGLOBAL hDevMode; HGLOBAL hDevNames; HDC hDC; DWORD Flags; DWORD Flags2; DWORD ExclusionFlags; DWORD nPageRanges; DWORD nMaxPageRanges; LPPRINTPAGERANGE lpPageRanges; DWORD nMinPage; DWORD nMaxPage; DWORD nCopies; HINSTANCE hInstance; LPCWSTR lpPrintTemplateName; LPUNKNOWN lpCallback; DWORD nPropertyPages; HPROPSHEETPAGE* lphPropertyPages; DWORD nStartPage; DWORD dwResultAction; } alias PRINTDLGEXW* LPPRINTDLGEXW; //} // _WIN32_WINNT >= 0x500 extern (Windows) nothrow @nogc { BOOL ChooseColorA(LPCHOOSECOLORA); BOOL ChooseColorW(LPCHOOSECOLORW); BOOL ChooseFontA(LPCHOOSEFONTA); BOOL ChooseFontW(LPCHOOSEFONTW); DWORD CommDlgExtendedError(); HWND FindTextA(LPFINDREPLACEA); HWND FindTextW(LPFINDREPLACEW); short GetFileTitleA(LPCSTR, LPSTR, WORD); short GetFileTitleW(LPCWSTR, LPWSTR, WORD); BOOL GetOpenFileNameA(LPOPENFILENAMEA); BOOL GetOpenFileNameW(LPOPENFILENAMEW); BOOL GetSaveFileNameA(LPOPENFILENAMEA); BOOL GetSaveFileNameW(LPOPENFILENAMEW); BOOL PageSetupDlgA(LPPAGESETUPDLGA); BOOL PageSetupDlgW(LPPAGESETUPDLGW); BOOL PrintDlgA(LPPRINTDLGA); BOOL PrintDlgW(LPPRINTDLGW); HWND ReplaceTextA(LPFINDREPLACEA); HWND ReplaceTextW(LPFINDREPLACEW); //static if (_WIN32_WINNT >= 0x500) { HRESULT PrintDlgExA(LPPRINTDLGEXA); HRESULT PrintDlgExW(LPPRINTDLGEXW); //} } version (Unicode) { alias CHOOSECOLORW CHOOSECOLOR; alias CHOOSEFONTW CHOOSEFONT; alias FINDREPLACEW FINDREPLACE; alias OPENFILENAMEW OPENFILENAME; alias OFNOTIFYW OFNOTIFY; alias PAGESETUPDLGW PAGESETUPDLG; alias PRINTDLGW PRINTDLG; alias ChooseColorW ChooseColor; alias ChooseFontW ChooseFont; alias FindTextW FindText; alias GetFileTitleW GetFileTitle; alias GetOpenFileNameW GetOpenFileName; alias GetSaveFileNameW GetSaveFileName; alias PageSetupDlgW PageSetupDlg; alias PrintDlgW PrintDlg; alias ReplaceTextW ReplaceText; //static if (_WIN32_WINNT >= 0x500) { alias PRINTDLGEXW PRINTDLGEX; alias PrintDlgExW PrintDlgEx; //} } else { // UNICODE alias CHOOSECOLORA CHOOSECOLOR; alias CHOOSEFONTA CHOOSEFONT; alias FINDREPLACEA FINDREPLACE; alias OPENFILENAMEA OPENFILENAME; alias OFNOTIFYA OFNOTIFY; alias PAGESETUPDLGA PAGESETUPDLG; alias PRINTDLGA PRINTDLG; alias ChooseColorA ChooseColor; alias ChooseFontA ChooseFont; alias FindTextA FindText; alias GetFileTitleA GetFileTitle; alias GetOpenFileNameA GetOpenFileName; alias GetSaveFileNameA GetSaveFileName; alias PageSetupDlgA PageSetupDlg; alias PrintDlgA PrintDlg; alias ReplaceTextA ReplaceText; //static if (_WIN32_WINNT >= 0x500) { alias PRINTDLGEXA PRINTDLGEX; alias PrintDlgExA PrintDlgEx; //} } // UNICODE alias CHOOSECOLOR* LPCHOOSECOLOR; alias CHOOSEFONT* LPCHOOSEFONT; alias FINDREPLACE* LPFINDREPLACE; alias OPENFILENAME* LPOPENFILENAME; alias OFNOTIFY* LPOFNOTIFY; alias PAGESETUPDLG* LPPAGESETUPDLG; alias PRINTDLG* LPPRINTDLG; //static if (_WIN32_WINNT >= 0x500) { alias PRINTDLGEX* LPPRINTDLGEX; //} ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rpcndr.d0000664000175000017500000006131612776214756023156 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rpcndr.d) */ module core.sys.windows.rpcndr; version (Windows): pragma(lib, "rpcrt4"); /* Translation notes: RPC_CLIENT_ALLOC*, RPC_CLIENT_FREE* were replaced with PRPC_CLIENT_ALLOC, PRPC_CLIENT_FREE */ // TODO: Bitfields in MIDL_STUB_MESSAGE. // Macros need to be converted. enum __RPCNDR_H_VERSION__= 450; import core.sys.windows.rpcnsip; private import core.sys.windows.rpc, core.sys.windows.rpcdce, core.sys.windows.unknwn, core.sys.windows.windef; private import core.sys.windows.objidl; // for IRpcChannelBuffer, IRpcStubBuffer private import core.sys.windows.basetyps; extern (Windows): enum uint NDR_CHAR_REP_MASK = 0xF, NDR_INT_REP_MASK = 0xF0, NDR_FLOAT_REP_MASK = 0xFF00, NDR_LITTLE_ENDIAN = 0x10, NDR_BIG_ENDIAN = 0, NDR_IEEE_FLOAT = 0, NDR_VAX_FLOAT = 0x100, NDR_ASCII_CHAR = 0, NDR_EBCDIC_CHAR = 1, NDR_LOCAL_DATA_REPRESENTATION = 0x10, NDR_LOCAL_ENDIAN = NDR_LITTLE_ENDIAN; alias MIDL_user_allocate midl_user_allocate; alias MIDL_user_free midl_user_free; alias long hyper; alias ulong MIDL_uhyper; alias char small; enum cbNDRContext=20; //MACRO #define NDRSContextValue(hContext) (&(hContext)->userContext) //MACRO #define byte_from_ndr(source, target) { *(target) = *(*(char**)&(source)->Buffer)++; } //MACRO #define byte_array_from_ndr(Source, LowerIndex, UpperIndex, Target) { NDRcopy ((((char *)(Target))+(LowerIndex)), (Source)->Buffer, (unsigned int)((UpperIndex)-(LowerIndex))); *(unsigned long *)&(Source)->Buffer += ((UpperIndex)-(LowerIndex)); } //MACRO #define boolean_from_ndr(source, target) { *(target) = *(*(char**)&(source)->Buffer)++; } //MACRO #define boolean_array_from_ndr(Source, LowerIndex, UpperIndex, Target) { NDRcopy ((((char *)(Target))+(LowerIndex)), (Source)->Buffer, (unsigned int)((UpperIndex)-(LowerIndex))); *(unsigned long *)&(Source)->Buffer += ((UpperIndex)-(LowerIndex)); } //MACRO #define small_from_ndr(source, target) { *(target) = *(*(char**)&(source)->Buffer)++; } //MACRO #define small_from_ndr_temp(source, target, format) { *(target) = *(*(char**)(source))++; } //MACRO #define small_array_from_ndr(Source, LowerIndex, UpperIndex, Target) { NDRcopy ((((char *)(Target))+(LowerIndex)), (Source)->Buffer, (unsigned int)((UpperIndex)-(LowerIndex))); *(unsigned long *)&(Source)->Buffer += ((UpperIndex)-(LowerIndex)); } //MACRO #define MIDL_ascii_strlen(string) strlen(string) //MACRO #define MIDL_ascii_strcpy(target,source) strcpy(target,source) //MACRO #define MIDL_memset(s,c,n) memset(s,c,n) //MACRO #define _midl_ma1( p, cast ) *(*( cast **)&p)++ //MACRO #define _midl_ma2( p, cast ) *(*( cast **)&p)++ //MACRO #define _midl_ma4( p, cast ) *(*( cast **)&p)++ //MACRO #define _midl_ma8( p, cast ) *(*( cast **)&p)++ //MACRO #define _midl_unma1( p, cast ) *(( cast *)p)++ //MACRO #define _midl_unma2( p, cast ) *(( cast *)p)++ //MACRO #define _midl_unma3( p, cast ) *(( cast *)p)++ //MACRO #define _midl_unma4( p, cast ) *(( cast *)p)++ //MACRO #define _midl_fa2( p ) (p = (RPC_BUFPTR )((unsigned long)(p+1) & 0xfffffffe)) //MACRO #define _midl_fa4( p ) (p = (RPC_BUFPTR )((unsigned long)(p+3) & 0xfffffffc)) //MACRO #define _midl_fa8( p ) (p = (RPC_BUFPTR )((unsigned long)(p+7) & 0xfffffff8)) //MACRO #define _midl_addp( p, n ) (p += n) //MACRO #define _midl_marsh_lhs( p, cast ) *(*( cast **)&p)++ //MACRO #define _midl_marsh_up( mp, p ) *(*(unsigned long **)&mp)++ = (unsigned long)p //MACRO #define _midl_advmp( mp ) *(*(unsigned long **)&mp)++ //MACRO #define _midl_unmarsh_up( p ) (*(*(unsigned long **)&p)++) //MACRO #define NdrMarshConfStringHdr( p, s, l ) (_midl_ma4( p, unsigned long) = s, _midl_ma4( p, unsigned long) = 0, _midl_ma4( p, unsigned long) = l) //MACRO #define NdrUnMarshConfStringHdr(p, s, l) ((s=_midl_unma4(p,unsigned long), (_midl_addp(p,4)), (l=_midl_unma4(p,unsigned long)) //MACRO #define NdrMarshCCtxtHdl(pc,p) (NDRCContextMarshall( (NDR_CCONTEXT)pc, p ),p+20) //MACRO #define NdrUnMarshCCtxtHdl(pc,p,h,drep) (NDRCContextUnmarshall((NDR_CONTEXT)pc,h,p,drep), p+20) //MACRO #define NdrUnMarshSCtxtHdl(pc, p,drep) (pc = NdrSContextUnMarshall(p,drep )) //MACRO #define NdrMarshSCtxtHdl(pc,p,rd) (NdrSContextMarshall((NDR_SCONTEXT)pc,p, (NDR_RUNDOWN)rd) //MACRO #define NdrFieldOffset(s,f) (long)(& (((s *)0)->f)) //MACRO #define NdrFieldPad(s,f,p,t) (NdrFieldOffset(s,f) - NdrFieldOffset(s,p) - sizeof(t)) //MACRO #define NdrFcShort(s) (unsigned char)(s & 0xff), (unsigned char)(s >> 8) //MACRO #define NdrFcLong(s) (unsigned char)(s & 0xff), (unsigned char)((s & 0x0000ff00) >> 8), (unsigned char)((s & 0x00ff0000) >> 16), (unsigned char)(s >> 24) alias void * NDR_CCONTEXT; struct tagNDR_SCONTEXT { void*[2] pad; void *userContext; } alias tagNDR_SCONTEXT * NDR_SCONTEXT; struct SCONTEXT_QUEUE { uint NumberOfObjects; NDR_SCONTEXT *ArrayOfObjects; } alias SCONTEXT_QUEUE * PSCONTEXT_QUEUE; struct _MIDL_STUB_MESSAGE; struct _MIDL_STUB_DESC; struct _FULL_PTR_XLAT_TABLES; alias ubyte *RPC_BUFPTR; alias uint RPC_LENGTH; alias const(char)* PFORMAT_STRING; struct ARRAY_INFO { int Dimension; uint *BufferConformanceMark; uint *BufferVarianceMark; uint *MaxCountArray; uint *OffsetArray; uint *ActualCountArray; } alias ARRAY_INFO * PARRAY_INFO; RPC_BINDING_HANDLE NDRCContextBinding(NDR_CCONTEXT); void NDRCContextMarshall(NDR_CCONTEXT,void*); void NDRCContextUnmarshall(NDR_CCONTEXT*,RPC_BINDING_HANDLE,void*,uint); void NDRSContextMarshall(NDR_SCONTEXT,void*,NDR_RUNDOWN); NDR_SCONTEXT NDRSContextUnmarshall(void*pBuff,uint); void RpcSsDestroyClientContext(void**); void NDRcopy(void*,void*,uint); uint MIDL_wchar_strlen(wchar *); void MIDL_wchar_strcpy(void*,wchar *); void char_from_ndr(PRPC_MESSAGE,ubyte*); void char_array_from_ndr(PRPC_MESSAGE,uint,uint,ubyte*); void short_from_ndr(PRPC_MESSAGE,ushort*); void short_array_from_ndr(PRPC_MESSAGE,uint,uint,ushort*); void short_from_ndr_temp(ubyte**,ushort*,uint); void int_from_ndr(PRPC_MESSAGE,uint*); void int_array_from_ndr(PRPC_MESSAGE,uint,uint,uint*); void int_from_ndr_temp(ubyte**,uint*,uint); void enum_from_ndr(PRPC_MESSAGE,uint*); void float_from_ndr(PRPC_MESSAGE,void*); void float_array_from_ndr(PRPC_MESSAGE,uint,uint,void*); void double_from_ndr(PRPC_MESSAGE,void*); void double_array_from_ndr(PRPC_MESSAGE,uint,uint,void*); void hyper_from_ndr(PRPC_MESSAGE,hyper*); void hyper_array_from_ndr(PRPC_MESSAGE,uint,uint,hyper*); void hyper_from_ndr_temp(ubyte**,hyper*,uint); void data_from_ndr(PRPC_MESSAGE,void*,char*,ubyte); void data_into_ndr(void*,PRPC_MESSAGE,char*,ubyte); void tree_into_ndr(void*,PRPC_MESSAGE,char*,ubyte); void data_size_ndr(void*,PRPC_MESSAGE,char*,ubyte); void tree_size_ndr(void*,PRPC_MESSAGE,char*,ubyte); void tree_peek_ndr(PRPC_MESSAGE,ubyte**,char*,ubyte); void * midl_allocate(int); align(4): struct MIDL_STUB_MESSAGE { PRPC_MESSAGE RpcMsg; ubyte *Buffer; ubyte *BufferStart; ubyte *BufferEnd; ubyte *BufferMark; uint BufferLength; uint MemorySize; ubyte *Memory; int IsClient; int ReuseBuffer; ubyte *AllocAllNodesMemory; ubyte *AllocAllNodesMemoryEnd; int IgnoreEmbeddedPointers; ubyte *PointerBufferMark; ubyte fBufferValid; ubyte Unused; uint MaxCount; uint Offset; uint ActualCount; void* function (uint) pfnAllocate; void function (void*) pfnFree; ubyte * StackTop; ubyte * pPresentedType; ubyte * pTransmitType; handle_t SavedHandle; const(_MIDL_STUB_DESC)* StubDesc; _FULL_PTR_XLAT_TABLES *FullPtrXlatTables; uint FullPtrRefId; int fCheckBounds; // FIXME: byte bit_fields_for_D; // FIXME: Bitfields // int fInDontFree :1; // int fDontCallFreeInst :1; // int fInOnlyParam :1; // int fHasReturn :1; uint dwDestContext; void* pvDestContext; NDR_SCONTEXT * SavedContextHandles; int ParamNumber; IRpcChannelBuffer pRpcChannelBuffer; PARRAY_INFO pArrayInfo; uint * SizePtrCountArray; uint * SizePtrOffsetArray; uint * SizePtrLengthArray; void* pArgQueue; uint dwStubPhase; uint[5] w2kReserved; } alias MIDL_STUB_MESSAGE * PMIDL_STUB_MESSAGE; extern (Windows) { alias void* function (void*) GENERIC_BINDING_ROUTINE; alias void function (void*,ubyte*) GENERIC_UNBIND_ROUTINE; alias uint function (uint *,uint,void *) USER_MARSHAL_SIZING_ROUTINE; alias ubyte * function (uint *,ubyte *,void *) USER_MARSHAL_MARSHALLING_ROUTINE; alias ubyte * function (uint *,ubyte *,void *) USER_MARSHAL_UNMARSHALLING_ROUTINE; alias void function (uint *,void *) USER_MARSHAL_FREEING_ROUTINE; alias void function () NDR_NOTIFY_ROUTINE; } align: struct GENERIC_BINDING_ROUTINE_PAIR { GENERIC_BINDING_ROUTINE pfnBind; GENERIC_UNBIND_ROUTINE pfnUnbind; } alias GENERIC_BINDING_ROUTINE_PAIR * PGENERIC_BINDING_ROUTINE_PAIR; struct GENERIC_BINDING_INFO { void *pObj; uint Size; GENERIC_BINDING_ROUTINE pfnBind; GENERIC_UNBIND_ROUTINE pfnUnbind; } alias GENERIC_BINDING_INFO * PGENERIC_BINDING_INFO; struct XMIT_ROUTINE_QUINTUPLE { XMIT_HELPER_ROUTINE pfnTranslateToXmit; XMIT_HELPER_ROUTINE pfnTranslateFromXmit; XMIT_HELPER_ROUTINE pfnFreeXmit; XMIT_HELPER_ROUTINE pfnFreeInst; } alias XMIT_ROUTINE_QUINTUPLE * PXMIT_ROUTINE_QUINTUPLE; struct MALLOC_FREE_STRUCT { void* function (uint) pfnAllocate; void function (void*) pfnFree; } struct COMM_FAULT_OFFSETS { short CommOffset; short FaultOffset; } struct USER_MARSHAL_ROUTINE_QUADRUPLE { USER_MARSHAL_SIZING_ROUTINE pfnBufferSize; USER_MARSHAL_MARSHALLING_ROUTINE pfnMarshall; USER_MARSHAL_UNMARSHALLING_ROUTINE pfnUnmarshall; USER_MARSHAL_FREEING_ROUTINE pfnFree; } enum IDL_CS_CONVERT { IDL_CS_NO_CONVERT, IDL_CS_IN_PLACE_CONVERT, IDL_CS_NEW_BUFFER_CONVERT } struct NDR_CS_SIZE_CONVERT_ROUTINES { CS_TYPE_NET_SIZE_ROUTINE pfnNetSize; CS_TYPE_TO_NETCS_ROUTINE pfnToNetCs; CS_TYPE_LOCAL_SIZE_ROUTINE pfnLocalSize; CS_TYPE_FROM_NETCS_ROUTINE pfnFromNetCs; } struct NDR_CS_ROUTINES { NDR_CS_SIZE_CONVERT_ROUTINES *pSizeConvertRoutines; CS_TAG_GETTING_ROUTINE *pTagGettingRoutines; } struct MIDL_STUB_DESC { void* RpcInterfaceInformation; void* function(uint) pfnAllocate; void function (void*) pfnFree; union _IMPLICIT_HANDLE_INFO { handle_t *pAutoHandle; handle_t *pPrimitiveHandle; PGENERIC_BINDING_INFO pGenericBindingInfo; } _IMPLICIT_HANDLE_INFO IMPLICIT_HANDLE_INFO; const(NDR_RUNDOWN)* apfnNdrRundownRoutines; const(GENERIC_BINDING_ROUTINE_PAIR)* aGenericBindingRoutinePairs; const(EXPR_EVAL)* apfnExprEval; const(XMIT_ROUTINE_QUINTUPLE)* aXmitQuintuple; const(char)* *pFormatTypes; int fCheckBounds; uint Version; MALLOC_FREE_STRUCT *pMallocFreeStruct; int MIDLVersion; const(COMM_FAULT_OFFSETS)* CommFaultOffsets; const(USER_MARSHAL_ROUTINE_QUADRUPLE)* aUserMarshalQuadruple; const(NDR_NOTIFY_ROUTINE)* NotifyRoutineTable; ULONG_PTR mFlags; const(NDR_CS_ROUTINES)* CsRoutineTables; void *Reserved4; ULONG_PTR Reserved5; } alias const(MIDL_STUB_DESC)* PMIDL_STUB_DESC; alias void * PMIDL_XMIT_TYPE; struct MIDL_FORMAT_STRING { short Pad; ubyte[1] Format; } struct MIDL_SERVER_INFO { PMIDL_STUB_DESC pStubDesc; const(SERVER_ROUTINE)* DispatchTable; PFORMAT_STRING ProcString; const(ushort)* FmtStringOffset; const(STUB_THUNK)* ThunkTable; } alias MIDL_SERVER_INFO * PMIDL_SERVER_INFO; struct MIDL_STUBLESS_PROXY_INFO { PMIDL_STUB_DESC pStubDesc; PFORMAT_STRING ProcFormatString; const(ushort)* FormatStringOffset; } alias MIDL_STUBLESS_PROXY_INFO *PMIDL_STUBLESS_PROXY_INFO; union CLIENT_CALL_RETURN { void *Pointer; int Simple; } enum XLAT_SIDE { XLAT_SERVER = 1, XLAT_CLIENT } struct FULL_PTR_TO_REFID_ELEMENT { FULL_PTR_TO_REFID_ELEMENT * Next; void* Pointer; uint RefId; ubyte State; } alias FULL_PTR_TO_REFID_ELEMENT * PFULL_PTR_TO_REFID_ELEMENT; struct FULL_PTR_XLAT_TABLES { struct RefIdToPointer { void **XlatTable; ubyte *StateTable; uint NumberOfEntries; } struct PointerToRefId { PFULL_PTR_TO_REFID_ELEMENT *XlatTable; uint NumberOfBuckets; uint HashMask; } uint NextRefId; XLAT_SIDE XlatSide; } alias FULL_PTR_XLAT_TABLES * PFULL_PTR_XLAT_TABLES; enum STUB_PHASE { STUB_UNMARSHAL, STUB_CALL_SERVER, STUB_MARSHAL, STUB_CALL_SERVER_NO_HRESULT } enum PROXY_PHASE { PROXY_CALCSIZE, PROXY_GETBUFFER, PROXY_MARSHAL, PROXY_SENDRECEIVE, PROXY_UNMARSHAL } alias TypeDef!(void *) RPC_SS_THREAD_HANDLE; extern (Windows) { alias void function (void*) NDR_RUNDOWN; alias void function (_MIDL_STUB_MESSAGE*) EXPR_EVAL; alias void function(PMIDL_STUB_MESSAGE) XMIT_HELPER_ROUTINE; alias void function (RPC_BINDING_HANDLE,uint,uint,IDL_CS_CONVERT*,uint*,error_status_t*) CS_TYPE_NET_SIZE_ROUTINE; alias void function (RPC_BINDING_HANDLE,uint,uint,IDL_CS_CONVERT*,uint*,error_status_t*) CS_TYPE_LOCAL_SIZE_ROUTINE; alias void function (RPC_BINDING_HANDLE,uint,void*,uint,byte*,uint*,error_status_t*) CS_TYPE_TO_NETCS_ROUTINE; alias void function (RPC_BINDING_HANDLE,uint,byte*,uint,uint,void*,uint*,error_status_t*) CS_TYPE_FROM_NETCS_ROUTINE; alias void function (RPC_BINDING_HANDLE,int,uint*,uint*,uint*,error_status_t*) CS_TAG_GETTING_ROUTINE; //alias void* RPC_CLIENT_ALLOC(uint); //alias void RPC_CLIENT_FREE(void*); alias void* function(uint) PRPC_CLIENT_ALLOC; alias void function(void*) PRPC_CLIENT_FREE; alias void function (PMIDL_STUB_MESSAGE) STUB_THUNK; alias int function() SERVER_ROUTINE; } void NdrSimpleTypeMarshall(PMIDL_STUB_MESSAGE,ubyte*,ubyte); ubyte * NdrPointerMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING pFormat); ubyte * NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrConformantStructMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrConformantVaryingStructMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrHardStructMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrComplexStructMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrFixedArrayMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrConformantArrayMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrConformantVaryingArrayMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrVaryingArrayMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrNonConformantStringMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrConformantStringMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrEncapsulatedUnionMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrNonEncapsulatedUnionMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrByteCountPointerMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrXmitOrRepAsMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte * NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrClientContextMarshall(PMIDL_STUB_MESSAGE,NDR_CCONTEXT,int); void NdrServerContextMarshall(PMIDL_STUB_MESSAGE,NDR_SCONTEXT,NDR_RUNDOWN); void NdrSimpleTypeUnmarshall(PMIDL_STUB_MESSAGE,ubyte*,ubyte); ubyte * NdrPointerUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrConformantStructUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrConformantVaryingStructUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrHardStructUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrFixedArrayUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrConformantArrayUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrConformantVaryingArrayUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrVaryingArrayUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrNonConformantStringUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrConformantStringUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrNonEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrByteCountPointerUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrXmitOrRepAsUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); ubyte * NdrInterfacePointerUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); void NdrClientContextUnmarshall(PMIDL_STUB_MESSAGE,NDR_CCONTEXT*,RPC_BINDING_HANDLE); NDR_SCONTEXT NdrServerContextUnmarshall(PMIDL_STUB_MESSAGE); void NdrPointerBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConformantStructBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConformantVaryingStructBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrHardStructBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrFixedArrayBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConformantVaryingArrayBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrVaryingArrayBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConformantStringBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrNonConformantStringBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrEncapsulatedUnionBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrNonEncapsulatedUnionBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrByteCountPointerBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrXmitOrRepAsBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrInterfacePointerBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrContextHandleSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); uint NdrPointerMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrSimpleStructMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrConformantStructMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrConformantVaryingStructMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrHardStructMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrFixedArrayMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrConformantArrayMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrConformantVaryingArrayMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrVaryingArrayMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrComplexArrayMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrConformantStringMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrNonConformantStringMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrEncapsulatedUnionMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrNonEncapsulatedUnionMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrXmitOrRepAsMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); uint NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); void NdrPointerFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrSimpleStructFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConformantStructFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConformantVaryingStructFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrHardStructFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrComplexStructFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrFixedArrayFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConformantArrayFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConformantVaryingArrayFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrVaryingArrayFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrComplexArrayFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrEncapsulatedUnionFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrNonEncapsulatedUnionFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrByteCountPointerFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrXmitOrRepAsFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrInterfacePointerFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); void NdrConvert(PMIDL_STUB_MESSAGE,PFORMAT_STRING); void NdrClientInitializeNew(PRPC_MESSAGE,PMIDL_STUB_MESSAGE,PMIDL_STUB_DESC,uint); ubyte * NdrServerInitializeNew(PRPC_MESSAGE,PMIDL_STUB_MESSAGE,PMIDL_STUB_DESC); void NdrClientInitialize(PRPC_MESSAGE,PMIDL_STUB_MESSAGE,PMIDL_STUB_DESC,uint); ubyte * NdrServerInitialize(PRPC_MESSAGE,PMIDL_STUB_MESSAGE,PMIDL_STUB_DESC); ubyte * NdrServerInitializeUnmarshall(PMIDL_STUB_MESSAGE,PMIDL_STUB_DESC,PRPC_MESSAGE); void NdrServerInitializeMarshall(PRPC_MESSAGE,PMIDL_STUB_MESSAGE); ubyte * NdrGetBuffer(PMIDL_STUB_MESSAGE,uint,RPC_BINDING_HANDLE); ubyte * NdrNsGetBuffer(PMIDL_STUB_MESSAGE,uint,RPC_BINDING_HANDLE); ubyte * NdrSendReceive(PMIDL_STUB_MESSAGE,ubyte*); ubyte * NdrNsSendReceive(PMIDL_STUB_MESSAGE,ubyte*,RPC_BINDING_HANDLE*); void NdrFreeBuffer(PMIDL_STUB_MESSAGE); CLIENT_CALL_RETURN NdrClientCall(PMIDL_STUB_DESC,PFORMAT_STRING,...); int NdrStubCall(IRpcStubBuffer, IRpcChannelBuffer,PRPC_MESSAGE,uint*); void NdrServerCall(PRPC_MESSAGE); int NdrServerUnmarshall(IRpcChannelBuffer, PRPC_MESSAGE,PMIDL_STUB_MESSAGE,PMIDL_STUB_DESC,PFORMAT_STRING,void*); void NdrServerMarshall(IRpcStubBuffer, IRpcChannelBuffer,PMIDL_STUB_MESSAGE,PFORMAT_STRING); RPC_STATUS NdrMapCommAndFaultStatus(PMIDL_STUB_MESSAGE,uint*,uint*,RPC_STATUS); int NdrSH_UPDecision(PMIDL_STUB_MESSAGE,ubyte**,RPC_BUFPTR); int NdrSH_TLUPDecision(PMIDL_STUB_MESSAGE,ubyte**); int NdrSH_TLUPDecisionBuffer(PMIDL_STUB_MESSAGE,ubyte**); int NdrSH_IfAlloc(PMIDL_STUB_MESSAGE,ubyte**,uint); int NdrSH_IfAllocRef(PMIDL_STUB_MESSAGE,ubyte**,uint); int NdrSH_IfAllocSet(PMIDL_STUB_MESSAGE,ubyte**,uint); RPC_BUFPTR NdrSH_IfCopy(PMIDL_STUB_MESSAGE,ubyte**,uint); RPC_BUFPTR NdrSH_IfAllocCopy(PMIDL_STUB_MESSAGE,ubyte**,uint); uint NdrSH_Copy(ubyte*,ubyte*,uint); void NdrSH_IfFree(PMIDL_STUB_MESSAGE,ubyte*); RPC_BUFPTR NdrSH_StringMarshall(PMIDL_STUB_MESSAGE,ubyte*,uint,int); RPC_BUFPTR NdrSH_StringUnMarshall(PMIDL_STUB_MESSAGE,ubyte**,int); void* RpcSsAllocate(uint); void RpcSsDisableAllocate(); void RpcSsEnableAllocate(); void RpcSsFree(void*); RPC_SS_THREAD_HANDLE RpcSsGetThreadHandle(); void RpcSsSetClientAllocFree(PRPC_CLIENT_ALLOC,PRPC_CLIENT_FREE); void RpcSsSetThreadHandle(RPC_SS_THREAD_HANDLE); void RpcSsSwapClientAllocFree(PRPC_CLIENT_ALLOC,PRPC_CLIENT_FREE,PRPC_CLIENT_ALLOC*,PRPC_CLIENT_FREE*); void* RpcSmAllocate(uint,RPC_STATUS*); RPC_STATUS RpcSmClientFree(void*); RPC_STATUS RpcSmDestroyClientContext(void**); RPC_STATUS RpcSmDisableAllocate(); RPC_STATUS RpcSmEnableAllocate(); RPC_STATUS RpcSmFree(void*); RPC_SS_THREAD_HANDLE RpcSmGetThreadHandle(RPC_STATUS*); RPC_STATUS RpcSmSetClientAllocFree(PRPC_CLIENT_ALLOC,PRPC_CLIENT_FREE); RPC_STATUS RpcSmSetThreadHandle(RPC_SS_THREAD_HANDLE); RPC_STATUS RpcSmSwapClientAllocFree(PRPC_CLIENT_ALLOC,PRPC_CLIENT_FREE,PRPC_CLIENT_ALLOC*,PRPC_CLIENT_FREE*); void NdrRpcSsEnableAllocate(PMIDL_STUB_MESSAGE); void NdrRpcSsDisableAllocate(PMIDL_STUB_MESSAGE); void NdrRpcSmSetClientToOsf(PMIDL_STUB_MESSAGE); void* NdrRpcSmClientAllocate(uint); void NdrRpcSmClientFree(void*); void* NdrRpcSsDefaultAllocate(uint); void NdrRpcSsDefaultFree(void*); PFULL_PTR_XLAT_TABLES NdrFullPointerXlatInit(uint,XLAT_SIDE); void NdrFullPointerXlatFree(PFULL_PTR_XLAT_TABLES); int NdrFullPointerQueryPointer(PFULL_PTR_XLAT_TABLES,void*,ubyte,uint*); int NdrFullPointerQueryRefId(PFULL_PTR_XLAT_TABLES,uint,ubyte,void**); void NdrFullPointerInsertRefId(PFULL_PTR_XLAT_TABLES,uint,void*); int NdrFullPointerFree(PFULL_PTR_XLAT_TABLES,void*); void* NdrAllocate(PMIDL_STUB_MESSAGE,uint); void NdrClearOutParameters(PMIDL_STUB_MESSAGE,PFORMAT_STRING,void*); void* NdrOleAllocate(uint); void NdrOleFree(void*); ubyte* NdrUserMarshalMarshall(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ubyte* NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE,ubyte**,PFORMAT_STRING,ubyte); void NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); uint NdrUserMarshalMemorySize(PMIDL_STUB_MESSAGE,PFORMAT_STRING); void NdrUserMarshalFree(PMIDL_STUB_MESSAGE,ubyte*,PFORMAT_STRING); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/aclui.d0000664000175000017500000000743512776214756022765 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_aclui.d) */ module core.sys.windows.aclui; version (Windows): pragma(lib, "aclui"); private import core.sys.windows.w32api; /* static assert (_WIN32_WINNT >= 0x500, "core.sys.windows.aclui is available only if version Windows2000, WindowsXP, Windows2003 " "or WindowsVista is set"); */ import core.sys.windows.accctrl, core.sys.windows.commctrl, core.sys.windows.objbase; private import core.sys.windows.basetyps, core.sys.windows.prsht, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.winuser; struct SI_OBJECT_INFO { DWORD dwFlags; HINSTANCE hInstance; LPWSTR pszServerName; LPWSTR pszObjectName; LPWSTR pszPageTitle; GUID guidObjectType; } alias SI_OBJECT_INFO* PSI_OBJECT_INFO; // values for SI_OBJECT_INFO.dwFlags enum DWORD SI_EDIT_PERMS = 0x00000000, SI_EDIT_OWNER = 0x00000001, SI_EDIT_AUDITS = 0x00000002, SI_CONTAINER = 0x00000004, SI_READONLY = 0x00000008, SI_ADVANCED = 0x00000010, SI_RESET = 0x00000020, SI_OWNER_READONLY = 0x00000040, SI_EDIT_PROPERTIES = 0x00000080, SI_OWNER_RECURSE = 0x00000100, SI_NO_ACL_PROTECT = 0x00000200, SI_NO_TREE_APPLY = 0x00000400, SI_PAGE_TITLE = 0x00000800, SI_SERVER_IS_DC = 0x00001000, SI_RESET_DACL_TREE = 0x00004000, SI_RESET_SACL_TREE = 0x00008000, SI_OBJECT_GUID = 0x00010000, SI_EDIT_EFFECTIVE = 0x00020000, SI_RESET_DACL = 0x00040000, SI_RESET_SACL = 0x00080000, SI_RESET_OWNER = 0x00100000, SI_NO_ADDITIONAL_PERMISSION = 0x00200000, SI_MAY_WRITE = 0x10000000, SI_EDIT_ALL = SI_EDIT_PERMS | SI_EDIT_OWNER | SI_EDIT_AUDITS; struct SI_ACCESS { const(GUID)* pguid; ACCESS_MASK mask; LPCWSTR pszName; DWORD dwFlags; } alias SI_ACCESS* PSI_ACCESS; // values for SI_ACCESS.dwFlags enum DWORD SI_ACCESS_SPECIFIC = 0x00010000, SI_ACCESS_GENERAL = 0x00020000, SI_ACCESS_CONTAINER = 0x00040000, SI_ACCESS_PROPERTY = 0x00080000; struct SI_INHERIT_TYPE { const(GUID)* pguid; ULONG dwFlags; LPCWSTR pszName; } alias SI_INHERIT_TYPE* PSI_INHERIT_TYPE; /* values for SI_INHERIT_TYPE.dwFlags INHERIT_ONLY_ACE, CONTAINER_INHERIT_ACE, OBJECT_INHERIT_ACE defined elsewhere */ enum SI_PAGE_TYPE { SI_PAGE_PERM, SI_PAGE_ADVPERM, SI_PAGE_AUDIT, SI_PAGE_OWNER } enum uint PSPCB_SI_INITDIALOG = WM_USER + 1; interface ISecurityInformation : IUnknown { HRESULT GetObjectInformation(PSI_OBJECT_INFO); HRESULT GetSecurity(SECURITY_INFORMATION, PSECURITY_DESCRIPTOR*, BOOL); HRESULT SetSecurity(SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); HRESULT GetAccessRights(const(GUID)*, DWORD, PSI_ACCESS*, ULONG*, ULONG*); HRESULT MapGeneric(const(GUID)*, UCHAR*, ACCESS_MASK*); HRESULT GetInheritTypes(PSI_INHERIT_TYPE*, ULONG*); HRESULT PropertySheetPageCallback(HWND, UINT, SI_PAGE_TYPE); } alias ISecurityInformation LPSECURITYINFO; /* Comment from MinGW * TODO: ISecurityInformation2, IEffectivePermission, ISecurityObjectTypeInfo */ // FIXME: linkage attribute? extern (C) /+DECLSPEC_IMPORT+/ extern const IID IID_ISecurityInformation; extern (Windows) { HPROPSHEETPAGE CreateSecurityPage(LPSECURITYINFO psi); BOOL EditSecurity(HWND hwndOwner, LPSECURITYINFO psi); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/dll.d0000664000175000017500000004353612776214756022445 0ustar kaikai/** * This module provides OS specific helper function for DLL support * * Copyright: Copyright Digital Mars 2010 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Rainer Schuetze * Source: $(DRUNTIMESRC src/core/sys/windows/_dll.d) */ module core.sys.windows.dll; version (Windows): import core.sys.windows.windows; import core.stdc.string; import core.runtime; public import core.sys.windows.threadaux; /////////////////////////////////////////////////////////////////// // support fixing implicit TLS for dynamically loaded DLLs on Windows XP // in this special case, we have to treat _tlsstart and _tlsend as non-TLS variables // as they are used to simulate TLS when it is not set up under XP. In this case we must // not access tls_array[tls_index] as needed for thread local _tlsstart and _tlsend extern (C) { version (Win32) { version(CRuntime_DigitalMars) { extern __gshared byte _tlsstart; extern __gshared byte _tlsend; extern __gshared void* _tls_callbacks_a; } else version(CRuntime_Microsoft) { extern __gshared byte _tls_start; extern __gshared byte _tls_end; extern __gshared void* __xl_a; alias _tls_start _tlsstart; alias _tls_end _tlsend; alias __xl_a _tls_callbacks_a; } extern __gshared int _tls_index; } } extern (C) // rt.minfo { void rt_moduleTlsCtor(); void rt_moduleTlsDtor(); } private: version (Win32) { struct dll_aux { // don't let symbols leak into other modules struct LdrpTlsListEntry { LdrpTlsListEntry* next; LdrpTlsListEntry* prev; void* tlsstart; void* tlsend; void* ptr_tlsindex; void* callbacks; void* zerofill; int tlsindex; } alias fnRtlAllocateHeap = extern(Windows) void* function(void* HeapHandle, uint Flags, size_t Size) nothrow; // find a code sequence and return the address after the sequence static void* findCodeSequence( void* adr, int len, ref ubyte[] pattern ) nothrow { if( !adr ) return null; ubyte* code = cast(ubyte*) adr; for( int p = 0; p < len; p++ ) { if( code[ p .. p + pattern.length ] == pattern[ 0 .. $ ] ) { ubyte* padr = code + p + pattern.length; return padr; } } return null; } // find a code sequence and return the (relative) address that follows static void* findCodeReference( void* adr, int len, ref ubyte[] pattern, bool relative ) nothrow { if( !adr ) return null; ubyte* padr = cast(ubyte*) findCodeSequence( adr, len, pattern ); if( padr ) { if( relative ) return padr + 4 + *cast(int*) padr; return *cast(void**) padr; } return null; } // crawl through ntdll to find function _LdrpAllocateTls@0 and references // to _LdrpNumberOfTlsEntries, _NtdllBaseTag and _LdrpTlsList // LdrInitializeThunk // -> _LdrpInitialize@12 // -> _LdrpInitializeThread@4 // -> _LdrpAllocateTls@0 // -> je chunk // _LdrpNumberOfTlsEntries - number of entries in TlsList // _NtdllBaseTag - tag used for RtlAllocateHeap // _LdrpTlsList - root of the double linked list with TlsList entries static __gshared int* pNtdllBaseTag; // remembered for reusage in addTlsData static __gshared ubyte[] jmp_LdrpInitialize = [ 0x33, 0xED, 0xE9 ]; // xor ebp,ebp; jmp _LdrpInitialize static __gshared ubyte[] jmp__LdrpInitialize = [ 0x5D, 0xE9 ]; // pop ebp; jmp __LdrpInitialize static __gshared ubyte[] jmp__LdrpInitialize_xp64 = [ 0x5D, 0x90, 0x90, 0x90, 0x90, 0x90 ]; // pop ebp; nop; nop; nop; nop; nop; static __gshared ubyte[] call_LdrpInitializeThread = [ 0xFF, 0x75, 0x08, 0xE8 ]; // push [ebp+8]; call _LdrpInitializeThread static __gshared ubyte[] call_LdrpAllocateTls = [ 0x00, 0x00, 0xE8 ]; // jne 0xc3; call _LdrpAllocateTls static __gshared ubyte[] call_LdrpAllocateTls_svr03 = [ 0x65, 0xfc, 0x00, 0xE8 ]; // and [ebp+fc], 0; call _LdrpAllocateTls static __gshared ubyte[] jne_LdrpAllocateTls = [ 0x0f, 0x85 ]; // jne body_LdrpAllocateTls static __gshared ubyte[] mov_LdrpNumberOfTlsEntries = [ 0x8B, 0x0D ]; // mov ecx, _LdrpNumberOfTlsEntries static __gshared ubyte[] mov_NtdllBaseTag = [ 0x51, 0x8B, 0x0D ]; // push ecx; mov ecx, _NtdllBaseTag static __gshared ubyte[] mov_NtdllBaseTag_srv03 = [ 0x50, 0xA1 ]; // push eax; mov eax, _NtdllBaseTag static __gshared ubyte[] mov_LdrpTlsList = [ 0x8B, 0x3D ]; // mov edi, _LdrpTlsList static LdrpTlsListEntry* addTlsListEntry( void** peb, void* tlsstart, void* tlsend, void* tls_callbacks_a, int* tlsindex ) nothrow { HANDLE hnd = GetModuleHandleA( "NTDLL" ); assert( hnd, "cannot get module handle for ntdll" ); ubyte* fn = cast(ubyte*) GetProcAddress( hnd, "LdrInitializeThunk" ); assert( fn, "cannot find LdrInitializeThunk in ntdll" ); void* pLdrpInitialize = findCodeReference( fn, 20, jmp_LdrpInitialize, true ); void* p_LdrpInitialize = findCodeReference( pLdrpInitialize, 40, jmp__LdrpInitialize, true ); if( !p_LdrpInitialize ) p_LdrpInitialize = findCodeSequence( pLdrpInitialize, 40, jmp__LdrpInitialize_xp64 ); void* pLdrpInitializeThread = findCodeReference( p_LdrpInitialize, 200, call_LdrpInitializeThread, true ); void* pLdrpAllocateTls = findCodeReference( pLdrpInitializeThread, 40, call_LdrpAllocateTls, true ); if(!pLdrpAllocateTls) pLdrpAllocateTls = findCodeReference( pLdrpInitializeThread, 100, call_LdrpAllocateTls_svr03, true ); void* pBodyAllocateTls = findCodeReference( pLdrpAllocateTls, 40, jne_LdrpAllocateTls, true ); int* pLdrpNumberOfTlsEntries = cast(int*) findCodeReference( pBodyAllocateTls, 60, mov_LdrpNumberOfTlsEntries, false ); pNtdllBaseTag = cast(int*) findCodeReference( pBodyAllocateTls, 30, mov_NtdllBaseTag, false ); if(!pNtdllBaseTag) pNtdllBaseTag = cast(int*) findCodeReference( pBodyAllocateTls, 30, mov_NtdllBaseTag_srv03, false ); LdrpTlsListEntry* pLdrpTlsList = cast(LdrpTlsListEntry*)findCodeReference( pBodyAllocateTls, 80, mov_LdrpTlsList, false ); if( !pLdrpNumberOfTlsEntries || !pNtdllBaseTag || !pLdrpTlsList ) return null; fnRtlAllocateHeap fnAlloc = cast(fnRtlAllocateHeap) GetProcAddress( hnd, "RtlAllocateHeap" ); if( !fnAlloc ) return null; // allocate new TlsList entry (adding 0xC0000 to the tag is obviously a flag also usesd by // the nt-loader, could be the result of HEAP_MAKE_TAG_FLAGS(0,HEAP_NO_SERIALIZE|HEAP_GROWABLE) // but this is not documented in the msdn entry for RtlAlloateHeap void* heap = peb[6]; LdrpTlsListEntry* entry = cast(LdrpTlsListEntry*) (*fnAlloc)( heap, *pNtdllBaseTag | 0xc0000, LdrpTlsListEntry.sizeof ); if( !entry ) return null; // fill entry entry.tlsstart = tlsstart; entry.tlsend = tlsend; entry.ptr_tlsindex = tlsindex; entry.callbacks = tls_callbacks_a; entry.zerofill = null; entry.tlsindex = *pLdrpNumberOfTlsEntries; // and add it to the end of TlsList *tlsindex = *pLdrpNumberOfTlsEntries; entry.next = pLdrpTlsList; entry.prev = pLdrpTlsList.prev; pLdrpTlsList.prev.next = entry; pLdrpTlsList.prev = entry; (*pLdrpNumberOfTlsEntries)++; return entry; } // reallocate TLS array and create a copy of the TLS data section static bool addTlsData( void** teb, void* tlsstart, void* tlsend, int tlsindex ) nothrow { HANDLE hnd = GetModuleHandleA( "NTDLL" ); assert( hnd, "cannot get module handle for ntdll" ); fnRtlAllocateHeap fnAlloc = cast(fnRtlAllocateHeap) GetProcAddress( hnd, "RtlAllocateHeap" ); if( !fnAlloc || !pNtdllBaseTag ) return false; void** peb = cast(void**) teb[12]; void* heap = peb[6]; auto sz = tlsend - tlsstart; void* tlsdata = cast(void*) (*fnAlloc)( heap, *pNtdllBaseTag | 0xc0000, sz ); if( !tlsdata ) return false; // no relocations! not even self-relocations. Windows does not do them. core.stdc.string.memcpy( tlsdata, tlsstart, sz ); // create copy of tls pointer array void** array = cast(void**) (*fnAlloc)( heap, *pNtdllBaseTag | 0xc0000, (tlsindex + 1) * (void*).sizeof ); if( !array ) return false; if( tlsindex > 0 && teb[11] ) core.stdc.string.memcpy( array, teb[11], tlsindex * (void*).sizeof); array[tlsindex] = tlsdata; teb[11] = cast(void*) array; // let the old array leak, in case a oncurrent thread is still relying on it return true; } alias bool BOOLEAN; struct UNICODE_STRING { short Length; short MaximumLength; wchar* Buffer; } struct LIST_ENTRY { LIST_ENTRY* next; LIST_ENTRY* prev; } // the following structures can be found here: http://undocumented.ntinternals.net/ struct LDR_MODULE { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; LIST_ENTRY HashTableEntry; ULONG TimeDateStamp; } struct PEB_LDR_DATA { ULONG Length; BOOLEAN Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; } static LDR_MODULE* findLdrModule( HINSTANCE hInstance, void** peb ) nothrow { PEB_LDR_DATA* ldrData = cast(PEB_LDR_DATA*) peb[3]; LIST_ENTRY* root = &ldrData.InLoadOrderModuleList; for(LIST_ENTRY* entry = root.next; entry != root; entry = entry.next) { LDR_MODULE *ldrMod = cast(LDR_MODULE*) entry; if(ldrMod.BaseAddress == hInstance) return ldrMod; } return null; } static bool setDllTlsUsage( HINSTANCE hInstance, void** peb ) nothrow { LDR_MODULE *thisMod = findLdrModule( hInstance, peb ); if( !thisMod ) return false; thisMod.TlsIndex = -1; // uses TLS (not the index itself) thisMod.LoadCount = -1; // never unload return true; } } } public: /* ***************************************************** * Fix implicit thread local storage for the case when a DLL is loaded * dynamically after process initialization. * The link time variables are passed to allow placing this function into * an RTL DLL itself. * The problem is described in Bugzilla 3342 and * http://www.nynaeve.net/?p=187, to quote from the latter: * * "When a DLL using implicit TLS is loaded, because the loader doesn't process the TLS * directory, the _tls_index value is not initialized by the loader, nor is there space * allocated for module's TLS data in the ThreadLocalStoragePointer arrays of running * threads. The DLL continues to load, however, and things will appear to work... until the * first access to a __declspec(thread) variable occurs, that is." * * _tls_index is initialized by the compiler to 0, so we can use this as a test. */ bool dll_fixTLS( HINSTANCE hInstance, void* tlsstart, void* tlsend, void* tls_callbacks_a, int* tlsindex ) nothrow { version (Win64) return true; // fixed else version (Win32) { /* If the OS has allocated a TLS slot for us, we don't have to do anything * tls_index 0 means: the OS has not done anything, or it has allocated slot 0 * Vista and later Windows systems should do this correctly and not need * this function. */ if( *tlsindex != 0 ) return true; void** peb; asm pure nothrow @nogc { mov EAX,FS:[0x30]; mov peb, EAX; } dll_aux.LDR_MODULE *ldrMod = dll_aux.findLdrModule( hInstance, peb ); if( !ldrMod ) return false; // not in module list, bail out if( ldrMod.TlsIndex != 0 ) return true; // the OS has already setup TLS dll_aux.LdrpTlsListEntry* entry = dll_aux.addTlsListEntry( peb, tlsstart, tlsend, tls_callbacks_a, tlsindex ); if( !entry ) return false; scope (failure) assert(0); // enforce nothrow, Bugzilla 13561 if( !enumProcessThreads( function (uint id, void* context) nothrow { dll_aux.LdrpTlsListEntry* entry = cast(dll_aux.LdrpTlsListEntry*) context; return dll_aux.addTlsData( getTEB( id ), entry.tlsstart, entry.tlsend, entry.tlsindex ); }, entry ) ) return false; ldrMod.TlsIndex = -1; // flag TLS usage (not the index itself) ldrMod.LoadCount = -1; // prevent unloading of the DLL, // since XP does not keep track of used TLS entries return true; } } // fixup TLS storage, initialize runtime and attach to threads // to be called from DllMain with reason DLL_PROCESS_ATTACH bool dll_process_attach( HINSTANCE hInstance, bool attach_threads, void* tlsstart, void* tlsend, void* tls_callbacks_a, int* tlsindex ) { version (Win32) { if( !dll_fixTLS( hInstance, tlsstart, tlsend, tls_callbacks_a, tlsindex ) ) return false; } Runtime.initialize(); if( !attach_threads ) return true; // attach to all other threads return enumProcessThreads( function (uint id, void* context) { if( !thread_findByAddr( id ) ) { // if the OS has not prepared TLS for us, don't attach to the thread if( GetTlsDataAddress( id ) ) { thread_attachByAddr( id ); thread_moduleTlsCtor( id ); } } return true; }, null ); } // same as above, but only usable if druntime is linked statically bool dll_process_attach( HINSTANCE hInstance, bool attach_threads = true ) { version (Win64) { return dll_process_attach( hInstance, attach_threads, null, null, null, null ); } else version (Win32) { return dll_process_attach( hInstance, attach_threads, &_tlsstart, &_tlsend, &_tls_callbacks_a, &_tls_index ); } } // to be called from DllMain with reason DLL_PROCESS_DETACH void dll_process_detach( HINSTANCE hInstance, bool detach_threads = true ) { // detach from all other threads if( detach_threads ) enumProcessThreads( function (uint id, void* context) { if( id != GetCurrentThreadId() && thread_findByAddr( id ) ) { thread_moduleTlsDtor( id ); thread_detachByAddr( id ); } return true; }, null ); Runtime.terminate(); } /* Make sure that tlsCtorRun is itself a tls variable */ static bool tlsCtorRun; static this() { tlsCtorRun = true; } static ~this() { tlsCtorRun = false; } // to be called from DllMain with reason DLL_THREAD_ATTACH bool dll_thread_attach( bool attach_thread = true, bool initTls = true ) { // if the OS has not prepared TLS for us, don't attach to the thread // (happened when running under x64 OS) if( !GetTlsDataAddress( GetCurrentThreadId() ) ) return false; if( !thread_findByAddr( GetCurrentThreadId() ) ) { // only attach to thread and initalize it if it is not in the thread list (so it's not created by "new Thread") if( attach_thread ) thread_attachThis(); if( initTls && !tlsCtorRun ) // avoid duplicate calls rt_moduleTlsCtor(); } return true; } // to be called from DllMain with reason DLL_THREAD_DETACH bool dll_thread_detach( bool detach_thread = true, bool exitTls = true ) { // if the OS has not prepared TLS for us, we did not attach to the thread if( !GetTlsDataAddress( GetCurrentThreadId() ) ) return false; if( thread_findByAddr( GetCurrentThreadId() ) ) { if( exitTls && tlsCtorRun ) // avoid dtors to be run twice rt_moduleTlsDtor(); if( detach_thread ) thread_detachThis(); } return true; } /// A simple mixin to provide a $(D DllMain) which calls the necessary /// runtime initialization and termination functions automatically. /// /// Instead of writing a custom $(D DllMain), simply write: /// /// --- /// mixin SimpleDllMain; /// --- mixin template SimpleDllMain() { import core.sys.windows.windows : HINSTANCE; extern(Windows) bool DllMain(HINSTANCE hInstance, uint ulReason, void* reserved) { import core.sys.windows.windows; import core.sys.windows.dll : dll_process_attach, dll_process_detach, dll_thread_attach, dll_thread_detach; switch(ulReason) { default: assert(0); case DLL_PROCESS_ATTACH: return dll_process_attach( hInstance, true ); case DLL_PROCESS_DETACH: dll_process_detach( hInstance, true ); return true; case DLL_THREAD_ATTACH: return dll_thread_attach( true, true ); case DLL_THREAD_DETACH: return dll_thread_detach( true, true ); } } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/wininet.d0000664000175000017500000013256712776214756023352 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_wininet.d) */ module core.sys.windows.wininet; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "wininet"); // FIXME: check types and grouping of constants import core.sys.windows.windows; enum { INTERNET_INVALID_PORT_NUMBER = 0, INTERNET_DEFAULT_FTP_PORT = 21, INTERNET_DEFAULT_GOPHER_PORT = 70, INTERNET_DEFAULT_HTTP_PORT = 80, INTERNET_DEFAULT_HTTPS_PORT = 443, INTERNET_DEFAULT_SOCKS_PORT = 1080 } enum size_t MAX_CACHE_ENTRY_INFO_SIZE = 4096, INTERNET_MAX_HOST_NAME_LENGTH = 256, INTERNET_MAX_USER_NAME_LENGTH = 128, INTERNET_MAX_PASSWORD_LENGTH = 128, INTERNET_MAX_PORT_NUMBER_LENGTH = 5, INTERNET_MAX_PORT_NUMBER_VALUE = 65535, INTERNET_MAX_PATH_LENGTH = 2048, INTERNET_MAX_SCHEME_LENGTH = 32, INTERNET_MAX_URL_LENGTH = INTERNET_MAX_SCHEME_LENGTH + "://".length + INTERNET_MAX_PATH_LENGTH; enum : DWORD { INTERNET_KEEP_ALIVE_UNKNOWN = DWORD.max, INTERNET_KEEP_ALIVE_DISABLED = 0, INTERNET_KEEP_ALIVE_ENABLED } enum { INTERNET_REQFLAG_FROM_CACHE = 1, INTERNET_REQFLAG_ASYNC = 2 } enum DWORD INTERNET_FLAG_RELOAD = 0x80000000, INTERNET_FLAG_RAW_DATA = 0x40000000, INTERNET_FLAG_EXISTING_CONNECT = 0x20000000, INTERNET_FLAG_ASYNC = 0x10000000, INTERNET_FLAG_PASSIVE = 0x08000000, INTERNET_FLAG_NO_CACHE_WRITE = 0x04000000, INTERNET_FLAG_DONT_CACHE = INTERNET_FLAG_NO_CACHE_WRITE, INTERNET_FLAG_MAKE_PERSISTENT = 0x02000000, INTERNET_FLAG_OFFLINE = 0x01000000, INTERNET_FLAG_SECURE = 0x00800000, INTERNET_FLAG_KEEP_CONNECTION = 0x00400000, INTERNET_FLAG_NO_AUTO_REDIRECT = 0x00200000, INTERNET_FLAG_READ_PREFETCH = 0x00100000, INTERNET_FLAG_NO_COOKIES = 0x00080000, INTERNET_FLAG_NO_AUTH = 0x00040000, INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP = 0x00008000, INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS = 0x00004000, INTERNET_FLAG_IGNORE_CERT_DATE_INVALID = 0x00002000, INTERNET_FLAG_IGNORE_CERT_CN_INVALID = 0x00001000, INTERNET_FLAG_RESYNCHRONIZE = 0x00000800, INTERNET_FLAG_HYPERLINK = 0x00000400, INTERNET_FLAG_NO_UI = 0x00000200, INTERNET_FLAG_PRAGMA_NOCACHE = 0x00000100, INTERNET_FLAG_MUST_CACHE_REQUEST = 0x00000010, INTERNET_FLAG_TRANSFER_ASCII = FTP_TRANSFER_TYPE_ASCII, INTERNET_FLAG_TRANSFER_BINARY = FTP_TRANSFER_TYPE_BINARY, SECURITY_INTERNET_MASK = 0x0000F000, SECURITY_SET_MASK = SECURITY_INTERNET_MASK, INTERNET_FLAGS_MASK = 0xFFFCFE13, INTERNET_OPTIONS_MASK = ~INTERNET_FLAGS_MASK; enum INTERNET_NO_CALLBACK = 0; enum INTERNET_RFC1123_FORMAT = 0; enum size_t INTERNET_RFC1123_BUFSIZE = 30; enum DWORD ICU_ESCAPE = 0x80000000, ICU_USERNAME = 0x40000000, ICU_NO_ENCODE = 0x20000000, ICU_DECODE = 0x10000000, ICU_NO_META = 0x08000000, ICU_ENCODE_SPACES_ONLY = 0x04000000, ICU_BROWSER_MODE = 0x02000000; enum { INTERNET_OPEN_TYPE_PRECONFIG = 0, INTERNET_OPEN_TYPE_DIRECT = 1, INTERNET_OPEN_TYPE_PROXY = 3, PRE_CONFIG_INTERNET_ACCESS = INTERNET_OPEN_TYPE_PRECONFIG, LOCAL_INTERNET_ACCESS = INTERNET_OPEN_TYPE_DIRECT, GATEWAY_INTERNET_ACCESS = 2, CERN_PROXY_INTERNET_ACCESS = INTERNET_OPEN_TYPE_PROXY, } enum ISO_GLOBAL = 1; enum ISO_REGISTRY = 2; enum ISO_VALID_FLAGS = ISO_GLOBAL | ISO_REGISTRY; enum { INTERNET_OPTION_CALLBACK = 1, INTERNET_OPTION_CONNECT_TIMEOUT, INTERNET_OPTION_CONNECT_RETRIES, INTERNET_OPTION_CONNECT_BACKOFF, INTERNET_OPTION_SEND_TIMEOUT, INTERNET_OPTION_CONTROL_SEND_TIMEOUT = INTERNET_OPTION_SEND_TIMEOUT, INTERNET_OPTION_RECEIVE_TIMEOUT, INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT = INTERNET_OPTION_RECEIVE_TIMEOUT, INTERNET_OPTION_DATA_SEND_TIMEOUT, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT, INTERNET_OPTION_HANDLE_TYPE, INTERNET_OPTION_CONTEXT_VALUE, INTERNET_OPTION_LISTEN_TIMEOUT, INTERNET_OPTION_READ_BUFFER_SIZE, INTERNET_OPTION_WRITE_BUFFER_SIZE, // = 13 INTERNET_OPTION_ASYNC_ID = 15, INTERNET_OPTION_ASYNC_PRIORITY, // = 16 INTERNET_OPTION_PARENT_HANDLE = 21, INTERNET_OPTION_KEEP_CONNECTION, INTERNET_OPTION_REQUEST_FLAGS, INTERNET_OPTION_EXTENDED_ERROR, // = 24 INTERNET_OPTION_OFFLINE_MODE = 26, INTERNET_OPTION_CACHE_STREAM_HANDLE, INTERNET_OPTION_USERNAME, INTERNET_OPTION_PASSWORD, INTERNET_OPTION_ASYNC, INTERNET_OPTION_SECURITY_FLAGS, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT, INTERNET_OPTION_DATAFILE_NAME, INTERNET_OPTION_URL, INTERNET_OPTION_SECURITY_CERTIFICATE, INTERNET_OPTION_SECURITY_KEY_BITNESS, INTERNET_OPTION_REFRESH, INTERNET_OPTION_PROXY, INTERNET_OPTION_SETTINGS_CHANGED, INTERNET_OPTION_VERSION, INTERNET_OPTION_USER_AGENT, INTERNET_OPTION_END_BROWSER_SESSION, INTERNET_OPTION_PROXY_USERNAME, INTERNET_OPTION_PROXY_PASSWORD, // = 44 INTERNET_FIRST_OPTION = INTERNET_OPTION_CALLBACK, // why? INTERNET_LAST_OPTION = INTERNET_OPTION_USER_AGENT } enum INTERNET_PRIORITY_FOREGROUND = 1000; enum { INTERNET_HANDLE_TYPE_INTERNET = 1, INTERNET_HANDLE_TYPE_CONNECT_FTP, INTERNET_HANDLE_TYPE_CONNECT_GOPHER, INTERNET_HANDLE_TYPE_CONNECT_HTTP, INTERNET_HANDLE_TYPE_FTP_FIND, INTERNET_HANDLE_TYPE_FTP_FIND_HTML, INTERNET_HANDLE_TYPE_FTP_FILE, INTERNET_HANDLE_TYPE_FTP_FILE_HTML, INTERNET_HANDLE_TYPE_GOPHER_FIND, INTERNET_HANDLE_TYPE_GOPHER_FIND_HTML, INTERNET_HANDLE_TYPE_GOPHER_FILE, INTERNET_HANDLE_TYPE_GOPHER_FILE_HTML, INTERNET_HANDLE_TYPE_HTTP_REQUEST } enum DWORD SECURITY_FLAG_SECURE = 0x00000001, SECURITY_FLAG_SSL = 0x00000002, SECURITY_FLAG_SSL3 = 0x00000004, SECURITY_FLAG_PCT = 0x00000008, SECURITY_FLAG_PCT4 = 0x00000010, SECURITY_FLAG_IETFSSL4 = 0x00000020, SECURITY_FLAG_IGNORE_REVOCATION = 0x00000080, SECURITY_FLAG_IGNORE_UNKNOWN_CA = 0x00000100, SECURITY_FLAG_IGNORE_WRONG_USAGE = 0x00000200, SECURITY_FLAG_40BIT = 0x10000000, SECURITY_FLAG_128BIT = 0x20000000, SECURITY_FLAG_56BIT = 0x40000000, SECURITY_FLAG_UNKNOWNBIT = 0x80000000, SECURITY_FLAG_NORMALBITNESS = SECURITY_FLAG_40BIT, SECURITY_FLAG_IGNORE_CERT_CN_INVALID = INTERNET_FLAG_IGNORE_CERT_CN_INVALID, SECURITY_FLAG_IGNORE_CERT_DATE_INVALID = INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTPS = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS, SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTP = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP; enum { INTERNET_SERVICE_FTP = 1, INTERNET_SERVICE_GOPHER, INTERNET_SERVICE_HTTP } enum { INTERNET_STATUS_RESOLVING_NAME = 10, INTERNET_STATUS_NAME_RESOLVED = 11, INTERNET_STATUS_CONNECTING_TO_SERVER = 20, INTERNET_STATUS_CONNECTED_TO_SERVER = 21, INTERNET_STATUS_SENDING_REQUEST = 30, INTERNET_STATUS_REQUEST_SENT = 31, INTERNET_STATUS_RECEIVING_RESPONSE = 40, INTERNET_STATUS_RESPONSE_RECEIVED = 41, INTERNET_STATUS_CTL_RESPONSE_RECEIVED = 42, INTERNET_STATUS_PREFETCH = 43, INTERNET_STATUS_CLOSING_CONNECTION = 50, INTERNET_STATUS_CONNECTION_CLOSED = 51, INTERNET_STATUS_HANDLE_CREATED = 60, INTERNET_STATUS_HANDLE_CLOSING = 70, INTERNET_STATUS_REQUEST_COMPLETE = 100, INTERNET_STATUS_REDIRECT = 110 } enum { FTP_TRANSFER_TYPE_UNKNOWN = 0, FTP_TRANSFER_TYPE_ASCII = 1, FTP_TRANSFER_TYPE_BINARY = 2, FTP_TRANSFER_TYPE_MASK = 3 } enum size_t MAX_GOPHER_DISPLAY_TEXT = 128, MAX_GOPHER_SELECTOR_TEXT = 256, MAX_GOPHER_HOST_NAME = INTERNET_MAX_HOST_NAME_LENGTH, MAX_GOPHER_LOCATOR_LENGTH = 1 + MAX_GOPHER_DISPLAY_TEXT + 1 + MAX_GOPHER_SELECTOR_TEXT + 1 + MAX_GOPHER_HOST_NAME + 1 + INTERNET_MAX_PORT_NUMBER_LENGTH + 4; enum DWORD GOPHER_TYPE_TEXT_FILE = 0x00000001, GOPHER_TYPE_DIRECTORY = 0x00000002, GOPHER_TYPE_CSO = 0x00000004, GOPHER_TYPE_ERROR = 0x00000008, GOPHER_TYPE_MAC_BINHEX = 0x00000010, GOPHER_TYPE_DOS_ARCHIVE = 0x00000020, GOPHER_TYPE_UNIX_UUENCODED = 0x00000040, GOPHER_TYPE_INDEX_SERVER = 0x00000080, GOPHER_TYPE_TELNET = 0x00000100, GOPHER_TYPE_BINARY = 0x00000200, GOPHER_TYPE_REDUNDANT = 0x00000400, GOPHER_TYPE_TN3270 = 0x00000800, GOPHER_TYPE_GIF = 0x00001000, GOPHER_TYPE_IMAGE = 0x00002000, GOPHER_TYPE_BITMAP = 0x00004000, GOPHER_TYPE_MOVIE = 0x00008000, GOPHER_TYPE_SOUND = 0x00010000, GOPHER_TYPE_HTML = 0x00020000, GOPHER_TYPE_PDF = 0x00040000, GOPHER_TYPE_CALENDAR = 0x00080000, GOPHER_TYPE_INLINE = 0x00100000, GOPHER_TYPE_UNKNOWN = 0x20000000, GOPHER_TYPE_ASK = 0x40000000, GOPHER_TYPE_GOPHER_PLUS = 0x80000000, GOPHER_TYPE_FILE_MASK = 0x001FF271; BOOL IS_GOPHER_FILE(DWORD t) { return !!(t & GOPHER_TYPE_FILE_MASK); } BOOL IS_GOPHER_DIRECTORY(DWORD t) { return !!(t & GOPHER_TYPE_DIRECTORY); } BOOL IS_GOPHER_PHONE_SERVER(DWORD t) { return !!(t & GOPHER_TYPE_CSO); } BOOL IS_GOPHER_ERROR(DWORD t) { return !!(t & GOPHER_TYPE_ERROR); } BOOL IS_GOPHER_INDEX_SERVER(DWORD t) { return !!(t & GOPHER_TYPE_INDEX_SERVER); } BOOL IS_GOPHER_TELNET_SESSION(DWORD t) { return !!(t & GOPHER_TYPE_TELNET); } BOOL IS_GOPHER_BACKUP_SERVER(DWORD t) { return !!(t & GOPHER_TYPE_REDUNDANT); } BOOL IS_GOPHER_TN3270_SESSION(DWORD t) { return !!(t & GOPHER_TYPE_TN3270); } BOOL IS_GOPHER_ASK(DWORD t) { return !!(t & GOPHER_TYPE_ASK); } BOOL IS_GOPHER_PLUS(DWORD t) { return !!(t & GOPHER_TYPE_GOPHER_PLUS); } BOOL IS_GOPHER_TYPE_KNOWN(DWORD t) { return !(t & GOPHER_TYPE_UNKNOWN); } enum size_t MAX_GOPHER_CATEGORY_NAME = 128, MAX_GOPHER_ATTRIBUTE_NAME = 128, MIN_GOPHER_ATTRIBUTE_LENGTH = 256; const TCHAR[] GOPHER_INFO_CATEGORY = "+INFO", GOPHER_ADMIN_CATEGORY = "+ADMIN", GOPHER_VIEWS_CATEGORY = "+VIEWS", GOPHER_ABSTRACT_CATEGORY = "+ABSTRACT", GOPHER_VERONICA_CATEGORY = "+VERONICA", GOPHER_ADMIN_ATTRIBUTE = "Admin", GOPHER_MOD_DATE_ATTRIBUTE = "Mod-Date", GOPHER_TTL_ATTRIBUTE = "TTL", GOPHER_SCORE_ATTRIBUTE = "Score", GOPHER_RANGE_ATTRIBUTE = "Score-range", GOPHER_SITE_ATTRIBUTE = "Site", GOPHER_ORG_ATTRIBUTE = "Org", GOPHER_LOCATION_ATTRIBUTE = "Loc", GOPHER_GEOG_ATTRIBUTE = "Geog", GOPHER_TIMEZONE_ATTRIBUTE = "TZ", GOPHER_PROVIDER_ATTRIBUTE = "Provider", GOPHER_VERSION_ATTRIBUTE = "Version", GOPHER_ABSTRACT_ATTRIBUTE = "Abstract", GOPHER_VIEW_ATTRIBUTE = "View", GOPHER_TREEWALK_ATTRIBUTE = "treewalk"; enum : DWORD { GOPHER_ATTRIBUTE_ID_BASE = 0xABCCCC00, GOPHER_CATEGORY_ID_ALL, GOPHER_CATEGORY_ID_INFO, GOPHER_CATEGORY_ID_ADMIN, GOPHER_CATEGORY_ID_VIEWS, GOPHER_CATEGORY_ID_ABSTRACT, GOPHER_CATEGORY_ID_VERONICA, GOPHER_CATEGORY_ID_ASK, GOPHER_CATEGORY_ID_UNKNOWN, GOPHER_ATTRIBUTE_ID_ALL, GOPHER_ATTRIBUTE_ID_ADMIN, GOPHER_ATTRIBUTE_ID_MOD_DATE, GOPHER_ATTRIBUTE_ID_TTL, GOPHER_ATTRIBUTE_ID_SCORE, GOPHER_ATTRIBUTE_ID_RANGE, GOPHER_ATTRIBUTE_ID_SITE, GOPHER_ATTRIBUTE_ID_ORG, GOPHER_ATTRIBUTE_ID_LOCATION, GOPHER_ATTRIBUTE_ID_GEOG, GOPHER_ATTRIBUTE_ID_TIMEZONE, GOPHER_ATTRIBUTE_ID_PROVIDER, GOPHER_ATTRIBUTE_ID_VERSION, GOPHER_ATTRIBUTE_ID_ABSTRACT, GOPHER_ATTRIBUTE_ID_VIEW, GOPHER_ATTRIBUTE_ID_TREEWALK, GOPHER_ATTRIBUTE_ID_UNKNOWN } enum HTTP_MAJOR_VERSION = 1; enum HTTP_MINOR_VERSION = 0; const TCHAR[] HTTP_VERSION = "HTTP/1.0"; enum : DWORD { HTTP_QUERY_MIME_VERSION, HTTP_QUERY_CONTENT_TYPE, HTTP_QUERY_CONTENT_TRANSFER_ENCODING, HTTP_QUERY_CONTENT_ID, HTTP_QUERY_CONTENT_DESCRIPTION, HTTP_QUERY_CONTENT_LENGTH, HTTP_QUERY_CONTENT_LANGUAGE, HTTP_QUERY_ALLOW, HTTP_QUERY_PUBLIC, HTTP_QUERY_DATE, HTTP_QUERY_EXPIRES, HTTP_QUERY_LAST_MODIFIED, HTTP_QUERY_MESSAGE_ID, HTTP_QUERY_URI, HTTP_QUERY_DERIVED_FROM, HTTP_QUERY_COST, HTTP_QUERY_LINK, HTTP_QUERY_PRAGMA, HTTP_QUERY_VERSION, HTTP_QUERY_STATUS_CODE, HTTP_QUERY_STATUS_TEXT, HTTP_QUERY_RAW_HEADERS, HTTP_QUERY_RAW_HEADERS_CRLF, HTTP_QUERY_CONNECTION, HTTP_QUERY_ACCEPT, HTTP_QUERY_ACCEPT_CHARSET, HTTP_QUERY_ACCEPT_ENCODING, HTTP_QUERY_ACCEPT_LANGUAGE, HTTP_QUERY_AUTHORIZATION, HTTP_QUERY_CONTENT_ENCODING, HTTP_QUERY_FORWARDED, HTTP_QUERY_FROM, HTTP_QUERY_IF_MODIFIED_SINCE, HTTP_QUERY_LOCATION, HTTP_QUERY_ORIG_URI, HTTP_QUERY_REFERER, HTTP_QUERY_RETRY_AFTER, HTTP_QUERY_SERVER, HTTP_QUERY_TITLE, HTTP_QUERY_USER_AGENT, HTTP_QUERY_WWW_AUTHENTICATE, HTTP_QUERY_PROXY_AUTHENTICATE, HTTP_QUERY_ACCEPT_RANGES, HTTP_QUERY_SET_COOKIE, HTTP_QUERY_COOKIE, HTTP_QUERY_REQUEST_METHOD, HTTP_QUERY_MAX = 45, HTTP_QUERY_CUSTOM = 65535 } enum DWORD HTTP_QUERY_FLAG_REQUEST_HEADERS = 0x80000000, HTTP_QUERY_FLAG_SYSTEMTIME = 0x40000000, HTTP_QUERY_FLAG_NUMBER = 0x20000000, HTTP_QUERY_FLAG_COALESCE = 0x10000000, HTTP_QUERY_MODIFIER_FLAGS_MASK = 0xF0000000, HTTP_QUERY_HEADER_MASK = ~HTTP_QUERY_MODIFIER_FLAGS_MASK; enum { HTTP_STATUS_OK = 200, HTTP_STATUS_CREATED, HTTP_STATUS_ACCEPTED, HTTP_STATUS_PARTIAL, HTTP_STATUS_NO_CONTENT, // = 204 HTTP_STATUS_AMBIGUOUS = 300, HTTP_STATUS_MOVED, HTTP_STATUS_REDIRECT, HTTP_STATUS_REDIRECT_METHOD, HTTP_STATUS_NOT_MODIFIED, // = 304 HTTP_STATUS_BAD_REQUEST = 400, HTTP_STATUS_DENIED, HTTP_STATUS_PAYMENT_REQ, HTTP_STATUS_FORBIDDEN, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_BAD_METHOD, HTTP_STATUS_NONE_ACCEPTABLE, HTTP_STATUS_PROXY_AUTH_REQ, HTTP_STATUS_REQUEST_TIMEOUT, HTTP_STATUS_CONFLICT, HTTP_STATUS_GONE, HTTP_STATUS_AUTH_REFUSED, // = 411 HTTP_STATUS_SERVER_ERROR = 500, HTTP_STATUS_NOT_SUPPORTED, HTTP_STATUS_BAD_GATEWAY, HTTP_STATUS_SERVICE_UNAVAIL, HTTP_STATUS_GATEWAY_TIMEOUT // = 504 } enum { INTERNET_PREFETCH_PROGRESS, INTERNET_PREFETCH_COMPLETE, INTERNET_PREFETCH_ABORTED } enum FLAGS_ERROR_UI_FILTER_FOR_ERRORS = 0x01; enum FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS = 0x02; enum FLAGS_ERROR_UI_FLAGS_GENERATE_DATA = 0x04; enum FLAGS_ERROR_UI_FLAGS_NO_UI = 0x08; enum DWORD HTTP_ADDREQ_INDEX_MASK = 0x0000FFFF, HTTP_ADDREQ_FLAGS_MASK = 0xFFFF0000, HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON = 0x01000000, HTTP_ADDREQ_FLAG_ADD_IF_NEW = 0x10000000, HTTP_ADDREQ_FLAG_ADD = 0x20000000, HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA = 0x40000000, HTTP_ADDREQ_FLAG_COALESCE = HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA, HTTP_ADDREQ_FLAG_REPLACE = 0x80000000; enum { INTERNET_ERROR_BASE = 12000, ERROR_INTERNET_OUT_OF_HANDLES, ERROR_INTERNET_TIMEOUT, ERROR_INTERNET_EXTENDED_ERROR, ERROR_INTERNET_INTERNAL_ERROR, ERROR_INTERNET_INVALID_URL, ERROR_INTERNET_UNRECOGNIZED_SCHEME, ERROR_INTERNET_NAME_NOT_RESOLVED, ERROR_INTERNET_PROTOCOL_NOT_FOUND, ERROR_INTERNET_INVALID_OPTION, ERROR_INTERNET_BAD_OPTION_LENGTH, ERROR_INTERNET_OPTION_NOT_SETTABLE, ERROR_INTERNET_SHUTDOWN, ERROR_INTERNET_INCORRECT_USER_NAME, ERROR_INTERNET_INCORRECT_PASSWORD, ERROR_INTERNET_LOGIN_FAILURE, ERROR_INTERNET_INVALID_OPERATION, ERROR_INTERNET_OPERATION_CANCELLED, ERROR_INTERNET_INCORRECT_HANDLE_TYPE, ERROR_INTERNET_INCORRECT_HANDLE_STATE, ERROR_INTERNET_NOT_PROXY_REQUEST, ERROR_INTERNET_REGISTRY_VALUE_NOT_FOUND, ERROR_INTERNET_BAD_REGISTRY_PARAMETER, ERROR_INTERNET_NO_DIRECT_ACCESS, ERROR_INTERNET_NO_CONTEXT, ERROR_INTERNET_NO_CALLBACK, ERROR_INTERNET_REQUEST_PENDING, ERROR_INTERNET_INCORRECT_FORMAT, ERROR_INTERNET_ITEM_NOT_FOUND, ERROR_INTERNET_CANNOT_CONNECT, ERROR_INTERNET_CONNECTION_ABORTED, ERROR_INTERNET_CONNECTION_RESET, ERROR_INTERNET_FORCE_RETRY, ERROR_INTERNET_INVALID_PROXY_REQUEST, ERROR_INTERNET_NEED_UI, // = INTERNET_ERROR_BASE + 34 ERROR_INTERNET_HANDLE_EXISTS = INTERNET_ERROR_BASE + 36, ERROR_INTERNET_SEC_CERT_DATE_INVALID, ERROR_INTERNET_SEC_CERT_CN_INVALID, ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR, ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR, ERROR_INTERNET_MIXED_SECURITY, ERROR_INTERNET_CHG_POST_IS_NON_SECURE, ERROR_INTERNET_POST_IS_NON_SECURE, ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED, ERROR_INTERNET_INVALID_CA, ERROR_INTERNET_CLIENT_AUTH_NOT_SETUP, ERROR_INTERNET_ASYNC_THREAD_FAILED, ERROR_INTERNET_REDIRECT_SCHEME_CHANGE, // = INTERNET_ERROR_BASE + 48 ERROR_FTP_TRANSFER_IN_PROGRESS = INTERNET_ERROR_BASE + 110, ERROR_FTP_DROPPED, // = INTERNET_ERROR_BASE + 111 ERROR_GOPHER_PROTOCOL_ERROR = INTERNET_ERROR_BASE + 130, ERROR_GOPHER_NOT_FILE, ERROR_GOPHER_DATA_ERROR, ERROR_GOPHER_END_OF_DATA, ERROR_GOPHER_INVALID_LOCATOR, ERROR_GOPHER_INCORRECT_LOCATOR_TYPE, ERROR_GOPHER_NOT_GOPHER_PLUS, ERROR_GOPHER_ATTRIBUTE_NOT_FOUND, ERROR_GOPHER_UNKNOWN_LOCATOR, // = INTERNET_ERROR_BASE + 138, ERROR_HTTP_HEADER_NOT_FOUND = INTERNET_ERROR_BASE + 150, ERROR_HTTP_DOWNLEVEL_SERVER, ERROR_HTTP_INVALID_SERVER_RESPONSE, ERROR_HTTP_INVALID_HEADER, ERROR_HTTP_INVALID_QUERY_REQUEST, ERROR_HTTP_HEADER_ALREADY_EXISTS, ERROR_HTTP_REDIRECT_FAILED, ERROR_INTERNET_SECURITY_CHANNEL_ERROR, ERROR_INTERNET_UNABLE_TO_CACHE_FILE, ERROR_INTERNET_TCPIP_NOT_INSTALLED, ERROR_HTTP_NOT_REDIRECTED, // = INTERNET_ERROR_BASE + 160 // why? INTERNET_ERROR_LAST = ERROR_INTERNET_TCPIP_NOT_INSTALLED } enum NORMAL_CACHE_ENTRY = 0x000001; enum STABLE_CACHE_ENTRY = 0x000002; enum STICKY_CACHE_ENTRY = 0x000004; enum SPARSE_CACHE_ENTRY = 0x010000; enum OCX_CACHE_ENTRY = 0x020000; enum COOKIE_CACHE_ENTRY = 0x100000; enum URLHISTORY_CACHE_ENTRY = 0x200000; enum CACHE_ENTRY_ATTRIBUTE_FC = 0x0004; enum CACHE_ENTRY_HITRATE_FC = 0x0010; enum CACHE_ENTRY_MODTIME_FC = 0x0040; enum CACHE_ENTRY_EXPTIME_FC = 0x0080; enum CACHE_ENTRY_ACCTIME_FC = 0x0100; enum CACHE_ENTRY_SYNCTIME_FC = 0x0200; enum CACHE_ENTRY_HEADERINFO_FC = 0x0400; enum { WININET_API_FLAG_ASYNC = 1, WININET_API_FLAG_SYNC = 4, WININET_API_FLAG_USE_CONTEXT = 8 } // FIXME: how should these really be grouped? enum { IRF_ASYNC = WININET_API_FLAG_ASYNC, IRF_SYNC = WININET_API_FLAG_SYNC, IRF_USE_CONTEXT = WININET_API_FLAG_USE_CONTEXT, } enum IRF_NO_WAIT = 8; enum { HSR_ASYNC = WININET_API_FLAG_ASYNC, HSR_SYNC = WININET_API_FLAG_SYNC, HSR_USE_CONTEXT = WININET_API_FLAG_USE_CONTEXT, } enum HSR_INITIATE = 8; enum HSR_DOWNLOAD = 16; enum HSR_CHUNKED = 32; enum INTERNET_DIAL_UNATTENDED = 0x8000; enum INTERNET_DIALSTATE_DISCONNECTED = 1; enum INTERENT_GOONLINE_REFRESH = 1; enum INTERENT_GOONLINE_MASK = 1; enum INTERNET_AUTODIAL_FORCE_ONLINE = 1; enum INTERNET_AUTODIAL_FORCE_UNATTENDED = 2; enum INTERNET_AUTODIAL_FAILIFSECURITYCHECK = 4; enum INTERNET_CONNECTION_MODEM = 0x01; enum INTERNET_CONNECTION_LAN = 0x02; enum INTERNET_CONNECTION_PROXY = 0x04; enum INTERNET_CONNECTION_MODEM_BUSY = 0x08; enum INTERNET_RAS_INSTALLED = 0x10; enum INTERNET_CONNECTION_OFFLINE = 0x20; enum INTERNET_CONNECTION_CONFIGURED = 0x40; enum { CACHEGROUP_SEARCH_ALL = 0, CACHEGROUP_SEARCH_BYURL = 1 } enum { INTERNET_CACHE_GROUP_ADD = 0, INTERNET_CACHE_GROUP_REMOVE = 1 } mixin DECLARE_HANDLE!("HINTERNET"); // doesn't work - bug /*struct HINTERNET { HANDLE h; alias h this; }*/ alias HINTERNET* LPHINTERNET; alias LONGLONG GROUPID; alias WORD INTERNET_PORT; alias WORD* LPINTERNET_PORT; enum INTERNET_SCHEME { INTERNET_SCHEME_PARTIAL = -2, INTERNET_SCHEME_UNKNOWN, INTERNET_SCHEME_DEFAULT, INTERNET_SCHEME_FTP, INTERNET_SCHEME_GOPHER, INTERNET_SCHEME_HTTP, INTERNET_SCHEME_HTTPS, INTERNET_SCHEME_FILE, INTERNET_SCHEME_NEWS, INTERNET_SCHEME_MAILTO, INTERNET_SCHEME_SOCKS, INTERNET_SCHEME_FIRST = INTERNET_SCHEME_FTP, INTERNET_SCHEME_LAST = INTERNET_SCHEME_SOCKS } alias INTERNET_SCHEME* LPINTERNET_SCHEME; struct INTERNET_ASYNC_RESULT { DWORD dwResult; DWORD dwError; } alias INTERNET_ASYNC_RESULT* LPINTERNET_ASYNC_RESULT; struct INTERNET_PREFETCH_STATUS { DWORD dwStatus; DWORD dwSize; } alias INTERNET_PREFETCH_STATUS* LPINTERNET_PREFETCH_STATUS; struct INTERNET_PROXY_INFO { DWORD dwAccessType; LPCTSTR lpszProxy; LPCTSTR lpszProxyBypass; } alias INTERNET_PROXY_INFO* LPINTERNET_PROXY_INFO; struct INTERNET_VERSION_INFO { DWORD dwMajorVersion; DWORD dwMinorVersion; } alias INTERNET_VERSION_INFO* LPINTERNET_VERSION_INFO; struct URL_COMPONENTSA { DWORD dwStructSize = URL_COMPONENTSA.sizeof; LPSTR lpszScheme; DWORD dwSchemeLength; INTERNET_SCHEME nScheme; LPSTR lpszHostName; DWORD dwHostNameLength; INTERNET_PORT nPort; LPSTR lpszUserName; DWORD dwUserNameLength; LPSTR lpszPassword; DWORD dwPasswordLength; LPSTR lpszUrlPath; DWORD dwUrlPathLength; LPSTR lpszExtraInfo; DWORD dwExtraInfoLength; } alias URL_COMPONENTSA* LPURL_COMPONENTSA; struct URL_COMPONENTSW { DWORD dwStructSize = URL_COMPONENTSW.sizeof; LPWSTR lpszScheme; DWORD dwSchemeLength; INTERNET_SCHEME nScheme; LPWSTR lpszHostName; DWORD dwHostNameLength; INTERNET_PORT nPort; LPWSTR lpszUserName; DWORD dwUserNameLength; LPWSTR lpszPassword; DWORD dwPasswordLength; LPWSTR lpszUrlPath; DWORD dwUrlPathLength; LPWSTR lpszExtraInfo; DWORD dwExtraInfoLength; } alias URL_COMPONENTSW* LPURL_COMPONENTSW; struct INTERNET_CERTIFICATE_INFO { FILETIME ftExpiry; FILETIME ftStart; LPTSTR lpszSubjectInfo; LPTSTR lpszIssuerInfo; LPTSTR lpszProtocolName; LPTSTR lpszSignatureAlgName; LPTSTR lpszEncryptionAlgName; DWORD dwKeySize; } alias INTERNET_CERTIFICATE_INFO* LPINTERNET_CERTIFICATE_INFO; extern (Windows) alias void function(HINTERNET, DWORD, DWORD, PVOID, DWORD) INTERNET_STATUS_CALLBACK; alias INTERNET_STATUS_CALLBACK* LPINTERNET_STATUS_CALLBACK; enum INTERNET_INVALID_STATUS_CALLBACK = cast(INTERNET_STATUS_CALLBACK) -1; struct GOPHER_FIND_DATAA { CHAR[MAX_GOPHER_DISPLAY_TEXT+1] DisplayString; DWORD GopherType; DWORD SizeLow; DWORD SizeHigh; FILETIME LastModificationTime; CHAR[MAX_GOPHER_LOCATOR_LENGTH+1] Locator; } alias GOPHER_FIND_DATAA* LPGOPHER_FIND_DATAA; struct GOPHER_FIND_DATAW { WCHAR[MAX_GOPHER_DISPLAY_TEXT+1] DisplayString; DWORD GopherType; DWORD SizeLow; DWORD SizeHigh; FILETIME LastModificationTime; WCHAR[MAX_GOPHER_LOCATOR_LENGTH+1] Locator; } alias GOPHER_FIND_DATAW* LPGOPHER_FIND_DATAW; struct GOPHER_ADMIN_ATTRIBUTE_TYPE { LPCTSTR Comment; LPCTSTR EmailAddress; } alias GOPHER_ADMIN_ATTRIBUTE_TYPE* LPGOPHER_ADMIN_ATTRIBUTE_TYPE; struct GOPHER_MOD_DATE_ATTRIBUTE_TYPE { FILETIME DateAndTime; } alias GOPHER_MOD_DATE_ATTRIBUTE_TYPE* LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE; struct GOPHER_TTL_ATTRIBUTE_TYPE { DWORD Ttl; } alias GOPHER_TTL_ATTRIBUTE_TYPE* LPGOPHER_TTL_ATTRIBUTE_TYPE; struct GOPHER_SCORE_ATTRIBUTE_TYPE { INT Score; } alias GOPHER_SCORE_ATTRIBUTE_TYPE* LPGOPHER_SCORE_ATTRIBUTE_TYPE; struct GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE { INT LowerBound; INT UpperBound; } alias GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE* LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE; struct GOPHER_SITE_ATTRIBUTE_TYPE { LPCTSTR Site; } alias GOPHER_SITE_ATTRIBUTE_TYPE* LPGOPHER_SITE_ATTRIBUTE_TYPE; struct GOPHER_ORGANIZATION_ATTRIBUTE_TYPE { LPCTSTR Organization; } alias GOPHER_ORGANIZATION_ATTRIBUTE_TYPE* LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPE; struct GOPHER_LOCATION_ATTRIBUTE_TYPE { LPCTSTR Location; } alias GOPHER_LOCATION_ATTRIBUTE_TYPE* LPGOPHER_LOCATION_ATTRIBUTE_TYPE; struct GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE { INT DegreesNorth; INT MinutesNorth; INT SecondsNorth; INT DegreesEast; INT MinutesEast; INT SecondsEast; } alias GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE* LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE; struct GOPHER_TIMEZONE_ATTRIBUTE_TYPE { INT Zone; } alias GOPHER_TIMEZONE_ATTRIBUTE_TYPE* LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE; struct GOPHER_PROVIDER_ATTRIBUTE_TYPE { LPCTSTR Provider; } alias GOPHER_PROVIDER_ATTRIBUTE_TYPE* LPGOPHER_PROVIDER_ATTRIBUTE_TYPE; struct GOPHER_VERSION_ATTRIBUTE_TYPE { LPCTSTR Version; } alias GOPHER_VERSION_ATTRIBUTE_TYPE* LPGOPHER_VERSION_ATTRIBUTE_TYPE; struct GOPHER_ABSTRACT_ATTRIBUTE_TYPE { LPCTSTR ShortAbstract; LPCTSTR AbstractFile; } alias GOPHER_ABSTRACT_ATTRIBUTE_TYPE* LPGOPHER_ABSTRACT_ATTRIBUTE_TYPE; struct GOPHER_VIEW_ATTRIBUTE_TYPE { LPCTSTR ContentType; LPCTSTR Language; DWORD Size; } alias GOPHER_VIEW_ATTRIBUTE_TYPE* LPGOPHER_VIEW_ATTRIBUTE_TYPE; struct GOPHER_VERONICA_ATTRIBUTE_TYPE { BOOL TreeWalk; } alias GOPHER_VERONICA_ATTRIBUTE_TYPE* LPGOPHER_VERONICA_ATTRIBUTE_TYPE; struct GOPHER_ASK_ATTRIBUTE_TYPE { LPCTSTR QuestionType; LPCTSTR QuestionText; } alias GOPHER_ASK_ATTRIBUTE_TYPE* LPGOPHER_ASK_ATTRIBUTE_TYPE; struct GOPHER_UNKNOWN_ATTRIBUTE_TYPE { LPCTSTR Text; } alias GOPHER_UNKNOWN_ATTRIBUTE_TYPE* LPGOPHER_UNKNOWN_ATTRIBUTE_TYPE; struct GOPHER_ATTRIBUTE_TYPE { DWORD CategoryId; DWORD AttributeId; union { GOPHER_ADMIN_ATTRIBUTE_TYPE Admin; GOPHER_MOD_DATE_ATTRIBUTE_TYPE ModDate; GOPHER_TTL_ATTRIBUTE_TYPE Ttl; GOPHER_SCORE_ATTRIBUTE_TYPE Score; GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE ScoreRange; GOPHER_SITE_ATTRIBUTE_TYPE Site; GOPHER_ORGANIZATION_ATTRIBUTE_TYPE Organization; GOPHER_LOCATION_ATTRIBUTE_TYPE Location; GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE GeographicalLocation; GOPHER_TIMEZONE_ATTRIBUTE_TYPE TimeZone; GOPHER_PROVIDER_ATTRIBUTE_TYPE Provider; GOPHER_VERSION_ATTRIBUTE_TYPE Version; GOPHER_ABSTRACT_ATTRIBUTE_TYPE Abstract; GOPHER_VIEW_ATTRIBUTE_TYPE View; GOPHER_VERONICA_ATTRIBUTE_TYPE Veronica; GOPHER_ASK_ATTRIBUTE_TYPE Ask; GOPHER_UNKNOWN_ATTRIBUTE_TYPE Unknown; } /+AttributeType;+/ } alias GOPHER_ATTRIBUTE_TYPE* LPGOPHER_ATTRIBUTE_TYPE; alias BOOL function(LPGOPHER_ATTRIBUTE_TYPE, DWORD) GOPHER_ATTRIBUTE_ENUMERATOR; struct INTERNET_CACHE_ENTRY_INFOA { DWORD dwStructSize = INTERNET_CACHE_ENTRY_INFOA.sizeof; LPSTR lpszSourceUrlName; LPSTR lpszLocalFileName; DWORD CacheEntryType; DWORD dwUseCount; DWORD dwHitRate; DWORD dwSizeLow; DWORD dwSizeHigh; FILETIME LastModifiedTime; FILETIME ExpireTime; FILETIME LastAccessTime; FILETIME LastSyncTime; PBYTE lpHeaderInfo; DWORD dwHeaderInfoSize; LPSTR lpszFileExtension; DWORD dwReserved; } alias INTERNET_CACHE_ENTRY_INFOA* LPINTERNET_CACHE_ENTRY_INFOA; struct INTERNET_CACHE_ENTRY_INFOW { DWORD dwStructSize = INTERNET_CACHE_ENTRY_INFOW.sizeof; LPWSTR lpszSourceUrlName; LPWSTR lpszLocalFileName; DWORD CacheEntryType; DWORD dwUseCount; DWORD dwHitRate; DWORD dwSizeLow; DWORD dwSizeHigh; FILETIME LastModifiedTime; FILETIME ExpireTime; FILETIME LastAccessTime; FILETIME LastSyncTime; PBYTE lpHeaderInfo; DWORD dwHeaderInfoSize; LPWSTR lpszFileExtension; DWORD dwReserved; } alias INTERNET_CACHE_ENTRY_INFOW* LPINTERNET_CACHE_ENTRY_INFOW; struct INTERNET_BUFFERSA { DWORD dwStructSize = INTERNET_BUFFERSA.sizeof; INTERNET_BUFFERSA* Next; LPCSTR lpcszHeader; DWORD dwHeadersLength; DWORD dwHeadersTotal; LPVOID lpvBuffer; DWORD dwBufferLength; DWORD dwBufferTotal; DWORD dwOffsetLow; DWORD dwOffsetHigh; } alias INTERNET_BUFFERSA* LPINTERNET_BUFFERSA; struct INTERNET_BUFFERSW { DWORD dwStructSize = INTERNET_BUFFERSW.sizeof; INTERNET_BUFFERSW* Next; LPCWSTR lpcszHeader; DWORD dwHeadersLength; DWORD dwHeadersTotal; LPVOID lpvBuffer; DWORD dwBufferLength; DWORD dwBufferTotal; DWORD dwOffsetLow; DWORD dwOffsetHigh; } alias INTERNET_BUFFERSW* LPINTERNET_BUFFERSW; enum size_t GROUP_OWNER_STORAGE_SIZE = 4, GROUPNAME_MAX_LENGTH = 120; struct INTERNET_CACHE_GROUP_INFOA { DWORD dwGroupSize; DWORD dwGroupFlags; DWORD dwGroupType; DWORD dwDiskUsage; DWORD dwDiskQuota; DWORD[GROUP_OWNER_STORAGE_SIZE] dwOwnerStorage; CHAR[GROUPNAME_MAX_LENGTH] szGroupName; } alias INTERNET_CACHE_GROUP_INFOA* LPINTERNET_CACHE_GROUP_INFOA; struct INTERNET_CACHE_GROUP_INFOW { DWORD dwGroupSize; DWORD dwGroupFlags; DWORD dwGroupType; DWORD dwDiskUsage; DWORD dwDiskQuota; DWORD[GROUP_OWNER_STORAGE_SIZE] dwOwnerStorage; WCHAR[GROUPNAME_MAX_LENGTH] szGroupName; } alias INTERNET_CACHE_GROUP_INFOW* LPINTERNET_CACHE_GROUP_INFOW; extern (Windows) { BOOL InternetTimeFromSystemTime(SYSTEMTIME*, DWORD, LPSTR, DWORD); BOOL InternetTimeToSystemTime(LPCSTR, SYSTEMTIME*, DWORD); BOOL InternetDebugGetLocalTime(SYSTEMTIME*, PDWORD); BOOL InternetCrackUrlA(LPCSTR, DWORD, DWORD, LPURL_COMPONENTSA); BOOL InternetCrackUrlW(LPCWSTR, DWORD, DWORD, LPURL_COMPONENTSW); BOOL InternetCreateUrlA(LPURL_COMPONENTSA, DWORD, LPSTR, PDWORD); BOOL InternetCreateUrlW(LPURL_COMPONENTSW, DWORD, LPWSTR, PDWORD); BOOL InternetCanonicalizeUrlA(LPCSTR, LPSTR, PDWORD, DWORD); BOOL InternetCanonicalizeUrlW(LPCWSTR, LPWSTR, PDWORD, DWORD); BOOL InternetCheckConnectionA(LPCSTR, DWORD, DWORD); BOOL InternetCheckConnectionW(LPCWSTR, DWORD, DWORD); BOOL InternetCombineUrlA(LPCSTR, LPCSTR, LPSTR, PDWORD, DWORD); BOOL InternetCombineUrlW(LPCWSTR, LPCWSTR, LPWSTR, PDWORD, DWORD); HINTERNET InternetOpenA(LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD); HINTERNET InternetOpenW(LPCWSTR, DWORD, LPCWSTR, LPCWSTR, DWORD); BOOL InternetCloseHandle(HINTERNET); HINTERNET InternetConnectA(HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD); HINTERNET InternetConnectW(HINTERNET, LPCWSTR, INTERNET_PORT, LPCWSTR, LPCWSTR, DWORD, DWORD, DWORD); HINTERNET InternetOpenUrlA(HINTERNET, LPCSTR, LPCSTR, DWORD, DWORD, DWORD); HINTERNET InternetOpenUrlW(HINTERNET, LPCWSTR, LPCWSTR, DWORD, DWORD, DWORD); BOOL InternetReadFile(HINTERNET, PVOID, DWORD, PDWORD); DWORD InternetSetFilePointer(HINTERNET, LONG, PVOID, DWORD, DWORD); BOOL InternetWriteFile(HINTERNET, LPCVOID, DWORD, PDWORD); BOOL InternetQueryDataAvailable(HINTERNET, PDWORD, DWORD, DWORD); BOOL InternetFindNextFileA(HINTERNET, PVOID); BOOL InternetFindNextFileW(HINTERNET, PVOID); BOOL InternetQueryOptionA(HINTERNET, DWORD, PVOID, PDWORD); BOOL InternetQueryOptionW(HINTERNET, DWORD, PVOID, PDWORD); BOOL InternetSetOptionA(HINTERNET, DWORD, PVOID, DWORD); BOOL InternetSetOptionW(HINTERNET, DWORD, PVOID, DWORD); BOOL InternetSetOptionExA(HINTERNET, DWORD, PVOID, DWORD, DWORD); BOOL InternetSetOptionExW(HINTERNET, DWORD, PVOID, DWORD, DWORD); BOOL InternetGetLastResponseInfoA(PDWORD, LPSTR, PDWORD); BOOL InternetGetLastResponseInfoW(PDWORD, LPWSTR, PDWORD); INTERNET_STATUS_CALLBACK InternetSetStatusCallback(HINTERNET, INTERNET_STATUS_CALLBACK); DWORD FtpGetFileSize(HINTERNET, LPDWORD); HINTERNET FtpFindFirstFileA(HINTERNET, LPCSTR, LPWIN32_FIND_DATA, DWORD, DWORD); HINTERNET FtpFindFirstFileW(HINTERNET, LPCWSTR, LPWIN32_FIND_DATA, DWORD, DWORD); BOOL FtpGetFileA(HINTERNET, LPCSTR, LPCSTR, BOOL, DWORD, DWORD, DWORD); BOOL FtpGetFileW(HINTERNET, LPCWSTR, LPCWSTR, BOOL, DWORD, DWORD, DWORD); BOOL FtpPutFileA(HINTERNET, LPCSTR, LPCSTR, DWORD, DWORD); BOOL FtpPutFileW(HINTERNET, LPCWSTR, LPCWSTR, DWORD, DWORD); BOOL FtpDeleteFileA(HINTERNET, LPCSTR); BOOL FtpDeleteFileW(HINTERNET, LPCWSTR); BOOL FtpRenameFileA(HINTERNET, LPCSTR, LPCSTR); BOOL FtpRenameFileW(HINTERNET, LPCWSTR, LPCWSTR); HINTERNET FtpOpenFileA(HINTERNET, LPCSTR, DWORD, DWORD, DWORD); HINTERNET FtpOpenFileW(HINTERNET, LPCWSTR, DWORD, DWORD, DWORD); BOOL FtpCreateDirectoryA(HINTERNET, LPCSTR); BOOL FtpCreateDirectoryW(HINTERNET, LPCWSTR); BOOL FtpRemoveDirectoryA(HINTERNET, LPCSTR); BOOL FtpRemoveDirectoryW(HINTERNET, LPCWSTR); BOOL FtpSetCurrentDirectoryA(HINTERNET, LPCSTR); BOOL FtpSetCurrentDirectoryW(HINTERNET, LPCWSTR); BOOL FtpGetCurrentDirectoryA(HINTERNET, LPSTR, PDWORD); BOOL FtpGetCurrentDirectoryW(HINTERNET, LPWSTR, PDWORD); BOOL FtpCommandA(HINTERNET, BOOL, DWORD, LPCSTR, DWORD_PTR, HINTERNET*); BOOL FtpCommandW(HINTERNET, BOOL, DWORD, LPCWSTR, DWORD_PTR, HINTERNET*); BOOL GopherCreateLocatorA(LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, LPSTR, PDWORD); BOOL GopherCreateLocatorW(LPCWSTR, INTERNET_PORT, LPCWSTR, LPCWSTR, DWORD, LPWSTR, PDWORD); BOOL GopherGetLocatorTypeA(LPCSTR, PDWORD); BOOL GopherGetLocatorTypeW(LPCWSTR, PDWORD); HINTERNET GopherFindFirstFileA(HINTERNET, LPCSTR, LPCSTR, LPGOPHER_FIND_DATAA, DWORD, DWORD); HINTERNET GopherFindFirstFileW(HINTERNET, LPCWSTR, LPCWSTR, LPGOPHER_FIND_DATAW, DWORD, DWORD); HINTERNET GopherOpenFileA(HINTERNET, LPCSTR, LPCSTR, DWORD, DWORD); HINTERNET GopherOpenFileW(HINTERNET, LPCWSTR, LPCWSTR, DWORD, DWORD); BOOL GopherGetAttributeA(HINTERNET, LPCSTR, LPCSTR, LPBYTE, DWORD, PDWORD, GOPHER_ATTRIBUTE_ENUMERATOR, DWORD); BOOL GopherGetAttributeW(HINTERNET, LPCWSTR, LPCWSTR, LPBYTE, DWORD, PDWORD, GOPHER_ATTRIBUTE_ENUMERATOR, DWORD); HINTERNET HttpOpenRequestA(HINTERNET, LPCSTR, LPCSTR, LPCSTR, LPCSTR, LPCSTR*, DWORD, DWORD); HINTERNET HttpOpenRequestW(HINTERNET, LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR*, DWORD, DWORD); BOOL HttpAddRequestHeadersA(HINTERNET, LPCSTR, DWORD, DWORD); BOOL HttpAddRequestHeadersW(HINTERNET, LPCWSTR, DWORD, DWORD); BOOL HttpSendRequestA(HINTERNET, LPCSTR, DWORD, PVOID, DWORD); BOOL HttpSendRequestW(HINTERNET, LPCWSTR, DWORD, PVOID, DWORD); BOOL HttpQueryInfoA(HINTERNET, DWORD, PVOID, PDWORD, PDWORD); BOOL HttpQueryInfoW(HINTERNET, DWORD, PVOID, PDWORD, PDWORD); BOOL InternetSetCookieA(LPCSTR, LPCSTR, LPCSTR); BOOL InternetSetCookieW(LPCWSTR, LPCWSTR, LPCWSTR); BOOL InternetGetCookieA(LPCSTR, LPCSTR, LPSTR, PDWORD); BOOL InternetGetCookieW(LPCWSTR, LPCWSTR, LPWSTR, PDWORD); DWORD InternetAttemptConnect(DWORD); DWORD InternetErrorDlg(HWND, HINTERNET, DWORD, DWORD, PVOID*); DWORD InternetConfirmZoneCrossing(HWND, LPSTR, LPSTR, BOOL); BOOL CreateUrlCacheEntryA(LPCSTR, DWORD, LPCSTR, LPSTR, DWORD); BOOL CreateUrlCacheEntryW(LPCWSTR, DWORD, LPCWSTR, LPWSTR, DWORD); BOOL CommitUrlCacheEntryA(LPCSTR, LPCSTR, FILETIME, FILETIME, DWORD, LPBYTE, DWORD, LPCSTR, DWORD); BOOL CommitUrlCacheEntryW(LPCWSTR, LPCWSTR, FILETIME, FILETIME, DWORD, LPBYTE, DWORD, LPCWSTR, DWORD); BOOL RetrieveUrlCacheEntryFileA(LPCSTR, LPINTERNET_CACHE_ENTRY_INFOA, PDWORD, DWORD); BOOL RetrieveUrlCacheEntryFileW(LPCWSTR, LPINTERNET_CACHE_ENTRY_INFOW, PDWORD, DWORD); BOOL UnlockUrlCacheEntryFile(LPCSTR, DWORD); HANDLE RetrieveUrlCacheEntryStreamA(LPCSTR, LPINTERNET_CACHE_ENTRY_INFOA, PDWORD, BOOL, DWORD); HANDLE RetrieveUrlCacheEntryStreamW(LPCWSTR, LPINTERNET_CACHE_ENTRY_INFOW, PDWORD, BOOL, DWORD); BOOL ReadUrlCacheEntryStream(HANDLE, DWORD, PVOID, PDWORD, DWORD); BOOL UnlockUrlCacheEntryStream(HANDLE, DWORD); BOOL GetUrlCacheEntryInfoA(LPCSTR, LPINTERNET_CACHE_ENTRY_INFOA, PDWORD); BOOL GetUrlCacheEntryInfoW(LPCWSTR, LPINTERNET_CACHE_ENTRY_INFOW, PDWORD); BOOL SetUrlCacheEntryInfoA(LPCSTR, LPINTERNET_CACHE_ENTRY_INFOA, DWORD); BOOL SetUrlCacheEntryInfoW(LPCWSTR, LPINTERNET_CACHE_ENTRY_INFOW, DWORD); HANDLE FindFirstUrlCacheEntryA(LPCSTR, LPINTERNET_CACHE_ENTRY_INFOA, PDWORD); HANDLE FindFirstUrlCacheEntryW(LPCWSTR, LPINTERNET_CACHE_ENTRY_INFOW, PDWORD); BOOL FindNextUrlCacheEntryA(HANDLE, LPINTERNET_CACHE_ENTRY_INFOA, PDWORD); BOOL FindNextUrlCacheEntryW(HANDLE, LPINTERNET_CACHE_ENTRY_INFOW, PDWORD); BOOL FindCloseUrlCache(HANDLE); BOOL DeleteUrlCacheEntry(LPCSTR); DWORD AuthenticateUser(PVOID*, LPSTR, LPSTR, DWORD, LPSTR, DWORD, LPSTR, LPSTR); BOOL HttpSendRequestExA(HINTERNET, LPINTERNET_BUFFERSA, LPINTERNET_BUFFERSA, DWORD, DWORD); BOOL HttpSendRequestExW(HINTERNET, LPINTERNET_BUFFERSW, LPINTERNET_BUFFERSW, DWORD, DWORD); BOOL HttpEndRequestA(HINTERNET, LPINTERNET_BUFFERSA, DWORD, DWORD); BOOL HttpEndRequestW(HINTERNET, LPINTERNET_BUFFERSW, DWORD, DWORD); DWORD InternetDial(HWND, LPTSTR, DWORD, LPDWORD, DWORD); DWORD InternetHangUp(DWORD, DWORD); BOOL InternetGoOnline(LPTSTR, HWND, DWORD); BOOL InternetAutodial(DWORD, DWORD); BOOL InternetAutodialHangup(DWORD); BOOL InternetGetConnectedState(LPDWORD, DWORD); BOOL InternetSetDialState(LPCTSTR, DWORD, DWORD); BOOL InternetReadFileExA(HINTERNET, LPINTERNET_BUFFERSA, DWORD, DWORD_PTR); BOOL InternetReadFileExW(HINTERNET, LPINTERNET_BUFFERSW, DWORD, DWORD_PTR); GROUPID CreateUrlCacheGroup(DWORD, LPVOID); BOOL DeleteUrlCacheGroup(GROUPID, DWORD, LPVOID); HANDLE FindFirstUrlCacheGroup(DWORD, DWORD, LPVOID, DWORD, GROUPID*, LPVOID); BOOL FindNextUrlCacheGroup(HANDLE, GROUPID*, LPVOID); BOOL GetUrlCacheGroupAttributeA(GROUPID, DWORD, DWORD, LPINTERNET_CACHE_GROUP_INFOA, LPDWORD, LPVOID); BOOL GetUrlCacheGroupAttributeW(GROUPID, DWORD, DWORD, LPINTERNET_CACHE_GROUP_INFOW, LPDWORD, LPVOID); BOOL SetUrlCacheGroupAttributeA(GROUPID, DWORD, DWORD, LPINTERNET_CACHE_GROUP_INFOA, LPVOID); BOOL SetUrlCacheGroupAttributeW(GROUPID, DWORD, DWORD, LPINTERNET_CACHE_GROUP_INFOW, LPVOID); } version (Unicode) { alias URL_COMPONENTSW URL_COMPONENTS; alias LPURL_COMPONENTSW LPURL_COMPONENTS; alias GOPHER_FIND_DATAW GOPHER_FIND_DATA; alias LPGOPHER_FIND_DATAW LPGOPHER_FIND_DATA; alias INTERNET_CACHE_ENTRY_INFOW INTERNET_CACHE_ENTRY_INFO; alias LPINTERNET_CACHE_ENTRY_INFOW LPINTERNET_CACHE_ENTRY_INFO; alias INTERNET_BUFFERSW INTERNET_BUFFERS; alias INTERNET_CACHE_GROUP_INFOW INTERNET_CACHE_GROUP_INFO; alias LPINTERNET_CACHE_GROUP_INFOW LPINTERNET_CACHE_GROUP_INFO; alias InternetCrackUrlW InternetCrackUrl; alias InternetCreateUrlW InternetCreateUrl; alias InternetCanonicalizeUrlW InternetCanonicalizeUrl; alias InternetCheckConnectionW InternetCheckConnection; alias InternetCombineUrlW InternetCombineUrl; alias InternetOpenW InternetOpen; alias InternetConnectW InternetConnect; alias InternetOpenUrlW InternetOpenUrl; alias InternetFindNextFileW InternetFindNextFile; alias InternetQueryOptionW InternetQueryOption; alias InternetSetOptionW InternetSetOption; alias InternetSetOptionExW InternetSetOptionEx; alias InternetGetLastResponseInfoW InternetGetLastResponseInfo; alias InternetReadFileExW InternetReadFileEx; alias FtpFindFirstFileW FtpFindFirstFile; alias FtpGetFileW FtpGetFile; alias FtpPutFileW FtpPutFile; alias FtpDeleteFileW FtpDeleteFile; alias FtpRenameFileW FtpRenameFile; alias FtpOpenFileW FtpOpenFile; alias FtpCreateDirectoryW FtpCreateDirectory; alias FtpRemoveDirectoryW FtpRemoveDirectory; alias FtpSetCurrentDirectoryW FtpSetCurrentDirectory; alias FtpGetCurrentDirectoryW FtpGetCurrentDirectory; alias FtpCommandW FtpCommand; alias GopherGetLocatorTypeW GopherGetLocatorType; alias GopherCreateLocatorW GopherCreateLocator; alias GopherFindFirstFileW GopherFindFirstFile; alias GopherOpenFileW GopherOpenFile; alias GopherGetAttributeW GopherGetAttribute; alias HttpSendRequestW HttpSendRequest; alias HttpOpenRequestW HttpOpenRequest; alias HttpAddRequestHeadersW HttpAddRequestHeaders; alias HttpQueryInfoW HttpQueryInfo; alias InternetSetCookieW InternetSetCookie; alias InternetGetCookieW InternetGetCookie; alias CreateUrlCacheEntryW CreateUrlCacheEntry; alias RetrieveUrlCacheEntryStreamW RetrieveUrlCacheEntryStream; alias FindNextUrlCacheEntryW FindNextUrlCacheEntry; alias CommitUrlCacheEntryW CommitUrlCacheEntry; alias GetUrlCacheEntryInfoW GetUrlCacheEntryInfo; alias SetUrlCacheEntryInfoW SetUrlCacheEntryInfo; alias FindFirstUrlCacheEntryW FindFirstUrlCacheEntry; alias RetrieveUrlCacheEntryFileW RetrieveUrlCacheEntryFile; alias HttpSendRequestExW HttpSendRequestEx; alias HttpEndRequestW HttpEndRequest; alias GetUrlCacheGroupAttributeW GetUrlCacheGroupAttribute; alias SetUrlCacheGroupAttributeW SetUrlCacheGroupAttribute; } else { alias URL_COMPONENTSA URL_COMPONENTS; alias LPURL_COMPONENTSA LPURL_COMPONENTS; alias GOPHER_FIND_DATAA GOPHER_FIND_DATA; alias LPGOPHER_FIND_DATAA LPGOPHER_FIND_DATA; alias INTERNET_CACHE_ENTRY_INFOA INTERNET_CACHE_ENTRY_INFO; alias LPINTERNET_CACHE_ENTRY_INFOA LPINTERNET_CACHE_ENTRY_INFO; alias INTERNET_BUFFERSA INTERNET_BUFFERS; alias INTERNET_CACHE_GROUP_INFOA INTERNET_CACHE_GROUP_INFO; alias LPINTERNET_CACHE_GROUP_INFOA LPINTERNET_CACHE_GROUP_INFO; alias GopherGetAttributeA GopherGetAttribute; alias InternetCrackUrlA InternetCrackUrl; alias InternetCreateUrlA InternetCreateUrl; alias InternetCanonicalizeUrlA InternetCanonicalizeUrl; alias InternetCheckConnectionA InternetCheckConnection; alias InternetCombineUrlA InternetCombineUrl; alias InternetOpenA InternetOpen; alias InternetConnectA InternetConnect; alias InternetOpenUrlA InternetOpenUrl; alias InternetFindNextFileA InternetFindNextFile; alias InternetQueryOptionA InternetQueryOption; alias InternetSetOptionA InternetSetOption; alias InternetSetOptionExA InternetSetOptionEx; alias InternetGetLastResponseInfoA InternetGetLastResponseInfo; alias InternetReadFileExA InternetReadFileEx; alias FtpFindFirstFileA FtpFindFirstFile; alias FtpGetFileA FtpGetFile; alias FtpPutFileA FtpPutFile; alias FtpDeleteFileA FtpDeleteFile; alias FtpRenameFileA FtpRenameFile; alias FtpOpenFileA FtpOpenFile; alias FtpCreateDirectoryA FtpCreateDirectory; alias FtpRemoveDirectoryA FtpRemoveDirectory; alias FtpSetCurrentDirectoryA FtpSetCurrentDirectory; alias FtpGetCurrentDirectoryA FtpGetCurrentDirectory; alias FtpCommandA FtpCommand; alias GopherGetLocatorTypeA GopherGetLocatorType; alias GopherCreateLocatorA GopherCreateLocator; alias GopherFindFirstFileA GopherFindFirstFile; alias GopherOpenFileA GopherOpenFile; alias HttpSendRequestA HttpSendRequest; alias HttpOpenRequestA HttpOpenRequest; alias HttpAddRequestHeadersA HttpAddRequestHeaders; alias HttpQueryInfoA HttpQueryInfo; alias InternetSetCookieA InternetSetCookie; alias InternetGetCookieA InternetGetCookie; alias CreateUrlCacheEntryA CreateUrlCacheEntry; alias RetrieveUrlCacheEntryStreamA RetrieveUrlCacheEntryStream; alias FindNextUrlCacheEntryA FindNextUrlCacheEntry; alias CommitUrlCacheEntryA CommitUrlCacheEntry; alias GetUrlCacheEntryInfoA GetUrlCacheEntryInfo; alias SetUrlCacheEntryInfoA SetUrlCacheEntryInfo; alias FindFirstUrlCacheEntryA FindFirstUrlCacheEntry; alias RetrieveUrlCacheEntryFileA RetrieveUrlCacheEntryFile; alias HttpSendRequestExA HttpSendRequestEx; alias HttpEndRequestA HttpEndRequest; alias GetUrlCacheGroupAttributeA GetUrlCacheGroupAttribute; alias SetUrlCacheGroupAttributeA SetUrlCacheGroupAttribute; } alias INTERNET_BUFFERS* LPINTERNET_BUFFERS; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/idispids.d0000664000175000017500000000064712776214756023476 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_idispids.d) */ module core.sys.windows.idispids; version (Windows): enum : int { DISPID_AMBIENT_OFFLINEIFNOTCONNECTED = -5501, DISPID_AMBIENT_SILENT = -5502 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/iphlpapi.d0000664000175000017500000000505012776214756023465 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_iphlpapi.d) */ module core.sys.windows.iphlpapi; version (Windows): import core.sys.windows.ipexport, core.sys.windows.iprtrmib, core.sys.windows.iptypes; private import core.sys.windows.winbase, core.sys.windows.windef; extern (Windows) { DWORD AddIPAddress(IPAddr, IPMask, DWORD, PULONG, PULONG); DWORD CreateIpForwardEntry(PMIB_IPFORWARDROW); DWORD CreateIpNetEntry(PMIB_IPNETROW); DWORD CreateProxyArpEntry(DWORD, DWORD, DWORD); DWORD DeleteIPAddress(ULONG); DWORD DeleteIpForwardEntry(PMIB_IPFORWARDROW); DWORD DeleteIpNetEntry(PMIB_IPNETROW); DWORD DeleteProxyArpEntry(DWORD, DWORD, DWORD); DWORD EnableRouter(HANDLE*, OVERLAPPED*); DWORD FlushIpNetTable(DWORD); DWORD GetAdapterIndex(LPWSTR, PULONG); DWORD GetAdaptersInfo(PIP_ADAPTER_INFO, PULONG); DWORD GetBestInterface(IPAddr, PDWORD); DWORD GetBestRoute(DWORD, DWORD, PMIB_IPFORWARDROW); DWORD GetFriendlyIfIndex(DWORD); DWORD GetIcmpStatistics(PMIB_ICMP); DWORD GetIfEntry(PMIB_IFROW); DWORD GetIfTable(PMIB_IFTABLE, PULONG, BOOL); DWORD GetInterfaceInfo(PIP_INTERFACE_INFO, PULONG); DWORD GetIpAddrTable(PMIB_IPADDRTABLE, PULONG, BOOL); DWORD GetIpForwardTable(PMIB_IPFORWARDTABLE, PULONG, BOOL); DWORD GetIpNetTable(PMIB_IPNETTABLE, PULONG, BOOL); DWORD GetIpStatistics(PMIB_IPSTATS); DWORD GetNetworkParams(PFIXED_INFO, PULONG); DWORD GetNumberOfInterfaces(PDWORD); DWORD GetPerAdapterInfo(ULONG, PIP_PER_ADAPTER_INFO, PULONG); BOOL GetRTTAndHopCount(IPAddr, PULONG, ULONG, PULONG); DWORD GetTcpStatistics(PMIB_TCPSTATS); DWORD GetTcpTable(PMIB_TCPTABLE, PDWORD, BOOL); DWORD GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS, PULONG); DWORD GetUdpStatistics(PMIB_UDPSTATS); DWORD GetUdpTable(PMIB_UDPTABLE, PDWORD, BOOL); DWORD IpReleaseAddress(PIP_ADAPTER_INDEX_MAP); DWORD IpRenewAddress(PIP_ADAPTER_INDEX_MAP); DWORD NotifyAddrChange(PHANDLE, LPOVERLAPPED); DWORD NotifyRouteChange(PHANDLE, LPOVERLAPPED); DWORD SendARP(IPAddr, IPAddr, PULONG, PULONG); DWORD SetIfEntry(PMIB_IFROW); DWORD SetIpForwardEntry(PMIB_IPFORWARDROW); DWORD SetIpNetEntry(PMIB_IPNETROW); DWORD SetIpStatistics(PMIB_IPSTATS); DWORD SetIpTTL(UINT); DWORD SetTcpEntry(PMIB_TCPROW); DWORD UnenableRouter(OVERLAPPED*, LPDWORD); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/regstr.d0000664000175000017500000012771012776214756023175 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_regstr.d) */ module core.sys.windows.regstr; version (Windows): // TODO: fix possible conflict with shloj. Sort out NEC_98 issue. private import core.sys.windows.windef; enum REGSTR_MAX_VALUE_LENGTH = 256; enum { IT_COMPACT = 0, IT_TYPICAL, IT_PORTABLE, IT_CUSTOM // = 3 } enum DOSOPTGF_DEFCLEAN = 1; enum DOSOPTF_DEFAULT = 0x01; enum DOSOPTF_SUPPORTED = 0x02; enum DOSOPTF_ALWAYSUSE = 0x04; enum DOSOPTF_USESPMODE = 0x08; enum DOSOPTF_PROVIDESUMB = 0x10; enum DOSOPTF_NEEDSETUP = 0x20; enum DOSOPTF_INDOSSTART = 0x40; enum DOSOPTF_MULTIPLE = 0x80; enum SUF_FIRSTTIME = 0x0001; enum SUF_EXPRESS = 0x0002; enum SUF_BATCHINF = 0x0004; enum SUF_CLEAN = 0x0008; enum SUF_INSETUP = 0x0010; enum SUF_NETSETUP = 0x0020; enum SUF_NETHDBOOT = 0x0040; enum SUF_NETRPLBOOT = 0x0080; enum SUF_SBSCOPYOK = 0x0100; enum VPDF_DISABLEPWRMGMT = 1; enum VPDF_FORCEAPM10MODE = 2; enum VPDF_SKIPINTELSLCHECK = 4; enum VPDF_DISABLEPWRSTATUSPOLL = 8; enum PCMCIA_OPT_HAVE_SOCKET = 0x01; enum PCMCIA_OPT_AUTOMEM = 0x04; enum PCMCIA_OPT_NO_SOUND = 0x08; enum PCMCIA_OPT_NO_AUDIO = 0x10; enum PCMCIA_OPT_NO_APMREMOVE = 0x20; enum PCMCIA_DEF_MEMBEGIN = 0x0C0000; enum PCMCIA_DEF_MEMEND = 0xFFFFFF; enum PCMCIA_DEF_MEMLEN = 0x001000; enum PCMCIA_DEF_MIN_REGION = 0x010000; enum { PCI_OPTIONS_USE_BIOS = 1, PCI_OPTIONS_USE_IRQ_STEERING = 2 } enum PCI_FLAG_NO_VIDEO_IRQ = 0x0001; enum PCI_FLAG_PCMCIA_WANT_IRQ = 0x0002; enum PCI_FLAG_DUAL_IDE = 0x0004; enum PCI_FLAG_NO_ENUM_AT_ALL = 0x0008; enum PCI_FLAG_ENUM_NO_RESOURCE = 0x0010; enum PCI_FLAG_NEED_DWORD_ACCESS = 0x0020; enum PCI_FLAG_SINGLE_FUNCTION = 0x0040; enum PCI_FLAG_ALWAYS_ENABLED = 0x0080; enum PCI_FLAG_IS_IDE = 0x0100; enum PCI_FLAG_IS_VIDEO = 0x0200; enum PCI_FLAG_FAIL_START = 0x0400; enum size_t REGSTR_VAL_MAX_HCID_LEN = 1024; enum REGDF_NOTDETIO = 0x00000001; enum REGDF_NOTDETMEM = 0x00000002; enum REGDF_NOTDETIRQ = 0x00000004; enum REGDF_NOTDETDMA = 0x00000008; enum REGDF_NOTDETALL = REGDF_NOTDETIO | REGDF_NOTDETMEM | REGDF_NOTDETIRQ | REGDF_NOTDETDMA; enum REGDF_NEEDFULLCONFIG = 0x00000010; enum REGDF_GENFORCEDCONFIG = 0x00000020; enum REGDF_NODETCONFIG = 0x00008000; enum REGDF_CONFLICTIO = 0x00010000; enum REGDF_CONFLICTMEM = 0x00020000; enum REGDF_CONFLICTIRQ = 0x00040000; enum REGDF_CONFLICTDMA = 0x00080000; enum REGDF_CONFLICTALL = REGDF_CONFLICTIO | REGDF_CONFLICTMEM | REGDF_CONFLICTIRQ | REGDF_CONFLICTDMA; enum REGDF_MAPIRQ2TO9 = 0x00100000; enum REGDF_NOTVERIFIED = 0x80000000; enum CONFIGFLAG_DISABLED = 0x0001; enum CONFIGFLAG_REMOVED = 0x0002; enum CONFIGFLAG_MANUAL_INSTALL = 0x0004; enum CONFIGFLAG_IGNORE_BOOT_LC = 0x0008; enum CONFIGFLAG_NET_BOOT = 0x0010; enum CONFIGFLAG_REINSTALL = 0x0020; enum CONFIGFLAG_FAILEDINSTALL = 0x0040; enum CONFIGFLAG_CANTSTOPACHILD = 0x0080; enum CONFIGFLAG_OKREMOVEROM = 0x0100; enum CONFIGFLAG_NOREMOVEEXIT = 0x0200; enum CSCONFIGFLAG_DISABLED = 1; enum CSCONFIGFLAG_DO_NOT_CREATE = 2; enum CSCONFIGFLAG_DO_NOT_START = 4; enum CSCONFIGFLAG_BITS = 7; enum DMSTATEFLAG_APPLYTOALL = 1; enum NUM_RESOURCE_MAP = 256; enum MF_FLAGS_EVEN_IF_NO_RESOURCE = 1; enum MF_FLAGS_NO_CREATE_IF_NO_RESOURCE = 2; enum MF_FLAGS_FILL_IN_UNKNOWN_RESOURCE = 4; enum MF_FLAGS_CREATE_BUT_NO_SHOW_DISABLED = 8; enum EISAFLAG_NO_IO_MERGE = 1; enum EISAFLAG_SLOT_IO_FIRST = 2; enum EISA_NO_MAX_FUNCTION = 0xFF; enum NUM_EISA_RANGES = 4; enum APMMENUSUSPEND_DISABLED = 0; enum APMMENUSUSPEND_ENABLED = 1; enum APMMENUSUSPEND_UNDOCKED = 2; enum APMMENUSUSPEND_NOCHANGE = 128; //#ifndef NEC_98 const TCHAR[] REGSTR_KEY_ISAENUM = "ISAPnP", REGSTR_KEY_EISAENUM = "EISA", REGSTR_VAL_EISA_RANGES = "EISARanges", REGSTR_VAL_EISA_FUNCTIONS = "EISAFunctions", REGSTR_VAL_EISA_FUNCTIONS_MASK = "EISAFunctionsMask", REGSTR_VAL_EISA_FLAGS = "EISAFlags", REGSTR_VAL_EISA_SIMULATE_INT15 = "EISASimulateInt15"; // #else // #define REGSTR_KEY_ISAENUM TEXT("C98PnP") // #define REGSTR_KEY_EISAENUM TEXT("NESA") // #define REGSTR_VAL_EISA_RANGES TEXT("NESARanges") // #define REGSTR_VAL_EISA_FUNCTIONS TEXT("NESAFunctions") // #define REGSTR_VAL_EISA_FUNCTIONS_MASK TEXT("NESAFunctionsMask") // #define REGSTR_VAL_EISA_FLAGS TEXT("NESAFlags") // #define REGSTR_VAL_EISA_SIMULATE_INT15 TEXT("NESASimulateInt15") // #endif const TCHAR[] REGSTR_KEY_CLASS = `Class`, REGSTR_KEY_CONFIG = `Config`, REGSTR_KEY_ENUM = `Enum`, REGSTR_KEY_ROOTENUM = `Root`, REGSTR_KEY_BIOSENUM = `BIOS`, REGSTR_KEY_PCMCIAENUM = `PCMCIA`, REGSTR_KEY_PCIENUM = `PCI`, REGSTR_KEY_LOGCONFIG = `LogConfig`, REGSTR_KEY_SYSTEMBOARD = `*PNP0C01`, REGSTR_KEY_APM = `*PNP0C05`, REGSTR_KEY_INIUPDATE = `IniUpdate`, REG_KEY_INSTDEV = `Installed`, REGSTR_KEY_DOSOPTCDROM = `CD-ROM`, REGSTR_KEY_DOSOPTMOUSE = `MOUSE`, REGSTR_DEFAULT_INSTANCE = `0000`, REGSTR_PATH_MOTHERBOARD = REGSTR_KEY_SYSTEMBOARD ~ `\` ~ REGSTR_DEFAULT_INSTANCE, REGSTR_PATH_SETUP = `Software\Microsoft\Windows\CurrentVersion`, REGSTR_PATH_PIFCONVERT = `Software\Microsoft\Windows\CurrentVersion\PIFConvert`, REGSTR_PATH_MSDOSOPTS = `Software\Microsoft\Windows\CurrentVersion\MS-DOSOptions`, REGSTR_PATH_MSDOSEMU = `Software\Microsoft\Windows\CurrentVersion\MS-DOS Emulation`, REGSTR_PATH_NEWDOSBOX = `Software\Microsoft\Windows\CurrentVersion\MS-DOS Emulation\AppCompat`, REGSTR_PATH_RUNONCE = `Software\Microsoft\Windows\CurrentVersion\RunOnce`, REGSTR_PATH_RUN = `Software\Microsoft\Windows\CurrentVersion\Run`, REGSTR_PATH_RUNSERVICESONCE = `Software\Microsoft\Windows\CurrentVersion\RunServicesOnce`, REGSTR_PATH_RUNSERVICES = `Software\Microsoft\Windows\CurrentVersion\RunServices`, //#ifndef REGSTR_PATH_EXPLORER /* also in shlobj.h */ REGSTR_PATH_EXPLORER = `Software\Microsoft\Windows\CurrentVersion\Explorer`, //#endif REGSTR_PATH_DETECT = `Software\Microsoft\Windows\CurrentVersion\Detect`, REGSTR_PATH_APPPATHS = `Software\Microsoft\Windows\CurrentVersion\App Paths`, REGSTR_PATH_UNINSTALL = `Software\Microsoft\Windows\CurrentVersion\Uninstall`, REGSTR_PATH_REALMODENET = `Software\Microsoft\Windows\CurrentVersion\Network\Real Mode Net`, REGSTR_PATH_NETEQUIV = `Software\Microsoft\Windows\CurrentVersion\Network\Equivalent`, REGSTR_PATH_CVNETWORK = `Software\Microsoft\Windows\CurrentVersion\Network`, REGSTR_PATH_IDCONFIGDB = `System\CurrentControlSet\Control\IDConfigDB`, REGSTR_PATH_CLASS = `System\CurrentControlSet\Services\Class`, REGSTR_PATH_DISPLAYSETTINGS = `Display\Settings`, REGSTR_PATH_FONTS = `Display\Fonts`, REGSTR_PATH_ENUM = `Enum`, REGSTR_PATH_ROOT = `Enum\Root`, REGSTR_PATH_SERVICES = `System\CurrentControlSet\Services`, REGSTR_PATH_VXD = `System\CurrentControlSet\Services\VxD`, REGSTR_PATH_IOS = `System\CurrentControlSet\Services\VxD\IOS`, REGSTR_PATH_VMM = `System\CurrentControlSet\Services\VxD\VMM`, REGSTR_PATH_VPOWERD = `System\CurrentControlSet\Services\VxD\VPOWERD`, REGSTR_PATH_VNETSUP = `System\CurrentControlSet\Services\VxD\VNETSUP`, REGSTR_PATH_NWREDIR = `System\CurrentControlSet\Services\VxD\NWREDIR`, REGSTR_PATH_NCPSERVER = `System\CurrentControlSet\Services\NcpServer\Parameters`, REGSTR_PATH_IOARB = `System\CurrentControlSet\Services\Arbitrators\IOArb`, REGSTR_PATH_ADDRARB = `System\CurrentControlSet\Services\Arbitrators\AddrArb`, REGSTR_PATH_DMAARB = `System\CurrentControlSet\Services\Arbitrators\DMAArb`, REGSTR_PATH_IRQARB = `System\CurrentControlSet\Services\Arbitrators\IRQArb`, REGSTR_PATH_CODEPAGE = `System\CurrentControlSet\Control\Nls\Codepage`, REGSTR_PATH_FILESYSTEM = `System\CurrentControlSet\Control\FileSystem`, REGSTR_PATH_FILESYSTEM_NOVOLTRACK = `System\CurrentControlSet\Control\FileSystem\NoVolTrack`, REGSTR_PATH_CDFS = `System\CurrentControlSet\Control\FileSystem\CDFS`, REGSTR_PATH_WINBOOT = `System\CurrentControlSet\Control\WinBoot`, REGSTR_PATH_INSTALLEDFILES = `System\CurrentControlSet\Control\InstalledFiles`, REGSTR_PATH_VMM32FILES = `System\CurrentControlSet\Control\VMM32Files`, REGSTR_VAL_BITSPERPIXEL = `BitsPerPixel`, REGSTR_VAL_RESOLUTION = `Resolution`, REGSTR_VAL_DPILOGICALX = `DPILogicalX`, REGSTR_VAL_DPILOGICALY = `DPILogicalY`, REGSTR_VAL_DPIPHYSICALX = `DPIPhysicalX`, REGSTR_VAL_DPIPHYSICALY = `DPIPhysicalY`, REGSTR_VAL_REFRESHRATE = `RefreshRate`, REGSTR_VAL_DISPLAYFLAGS = `DisplayFlags`, REGSTR_PATH_CONTROLPANEL = `Control Panel`, REGSTR_PATH_CONTROLSFOLDER = `Software\Microsoft\Windows\CurrentVersion\Controls Folder`, REGSTR_VAL_DOSCP = `OEMCP`, REGSTR_VAL_WINCP = `ACP`, REGSTR_PATH_DYNA_ENUM = `Config Manager\Enum`, REGSTR_VAL_HARDWARE_KEY = `HardWareKey`, REGSTR_VAL_ALLOCATION = `Allocation`, REGSTR_VAL_PROBLEM = `Problem`, REGSTR_VAL_STATUS = `Status`, REGSTR_VAL_DONTUSEMEM = `DontAllocLastMem`, REGSTR_VAL_SYSTEMROOT = `SystemRoot`, REGSTR_VAL_BOOTCOUNT = `BootCount`, REGSTR_VAL_REALNETSTART = `RealNetStart`, REGSTR_VAL_MEDIA = `MediaPath`, REGSTR_VAL_CONFIG = `ConfigPath`, REGSTR_VAL_DEVICEPATH = `DevicePath`, REGSTR_VAL_SRCPATH = `SourcePath`, REGSTR_VAL_OLDWINDIR = `OldWinDir`, REGSTR_VAL_SETUPFLAGS = `SetupFlags`, REGSTR_VAL_REGOWNER = `RegisteredOwner`, REGSTR_VAL_REGORGANIZATION = `RegisteredOrganization`, REGSTR_VAL_LICENSINGINFO = `LicensingInfo`, REGSTR_VAL_OLDMSDOSVER = `OldMSDOSVer`, REGSTR_VAL_FIRSTINSTALLDATETIME = `FirstInstallDateTime`, REGSTR_VAL_INSTALLTYPE = `InstallType`, REGSTR_VAL_WRAPPER = `Wrapper`, REGSTR_KEY_SETUP = `\Setup`, REGSTR_VAL_BOOTDIR = `BootDir`, REGSTR_VAL_WINBOOTDIR = `WinbootDir`, REGSTR_VAL_WINDIR = `WinDir`, REGSTR_VAL_APPINSTPATH = `AppInstallPath`, REGSTR_PATH_EBD = REGSTR_PATH_SETUP ~ REGSTR_KEY_SETUP ~ `\EBD`, REGSTR_KEY_EBDFILESLOCAL = `EBDFilesLocale`, REGSTR_KEY_EBDFILESKEYBOARD = `EBDFilesKeyboard`, REGSTR_KEY_EBDAUTOEXECBATLOCAL = `EBDAutoexecBatLocale`, REGSTR_KEY_EBDAUTOEXECBATKEYBOARD = `EBDAutoexecBatKeyboard`, REGSTR_KEY_EBDCONFIGSYSLOCAL = `EBDConfigSysLocale`, REGSTR_KEY_EBDCONFIGSYSKEYBOARD = `EBDConfigSysKeyboard`, REGSTR_VAL_MSDOSMODE = `MSDOSMode`, REGSTR_VAL_MSDOSMODEDISCARD = `Discard`, REGSTR_VAL_DOSOPTGLOBALFLAGS = `GlobalFlags`, REGSTR_VAL_DOSOPTFLAGS = `Flags`, REGSTR_VAL_OPTORDER = `Order`, REGSTR_VAL_CONFIGSYS = `Config.Sys`, REGSTR_VAL_AUTOEXEC = `Autoexec.Bat`, REGSTR_VAL_STDDOSOPTION = `StdOption`, REGSTR_VAL_DOSOPTTIP = `TipText`, REGSTR_VAL_DOSPAGER = `DOSPager`, REGSTR_VAL_VXDGROUPS = `VXDGroups`, REGSTR_VAL_VPOWERDFLAGS = `Flags`, REGSTR_VAL_WORKGROUP = `Workgroup`, REGSTR_VAL_DIRECTHOST = `DirectHost`, REGSTR_VAL_FILESHARING = `FileSharing`, REGSTR_VAL_PRINTSHARING = `PrintSharing`, REGSTR_VAL_FIRSTNETDRIVE = `FirstNetworkDrive`, REGSTR_VAL_MAXCONNECTIONS = `MaxConnections`, REGSTR_VAL_APISUPPORT = `APISupport`, REGSTR_VAL_MAXRETRY = `MaxRetry`, REGSTR_VAL_MINRETRY = `MinRetry`, REGSTR_VAL_SUPPORTLFN = `SupportLFN`, REGSTR_VAL_SUPPORTBURST = `SupportBurst`, REGSTR_VAL_SUPPORTTUNNELLING = `SupportTunnelling`, REGSTR_VAL_FULLTRACE = `FullTrace`, REGSTR_VAL_READCACHING = `ReadCaching`, REGSTR_VAL_SHOWDOTS = `ShowDots`, REGSTR_VAL_GAPTIME = `GapTime`, REGSTR_VAL_SEARCHMODE = `SearchMode`, REGSTR_VAL_SHELLVERSION = `ShellVersion`, REGSTR_VAL_MAXLIP = `MaxLIP`, REGSTR_VAL_PRESERVECASE = `PreserveCase`, REGSTR_VAL_OPTIMIZESFN = `OptimizeSFN`, REGSTR_VAL_NCP_BROWSEMASTER = `BrowseMaster`, REGSTR_VAL_NCP_USEPEERBROWSING = `Use_PeerBrowsing`, REGSTR_VAL_NCP_USESAP = `Use_Sap`, REGSTR_VAL_WIN31FILESYSTEM = `Win31FileSystem`, REGSTR_VAL_PRESERVELONGNAMES = `PreserveLongNames`, REGSTR_VAL_DRIVEWRITEBEHIND = `DriveWriteBehind`, REGSTR_VAL_ASYNCFILECOMMIT = `AsyncFileCommit`, REGSTR_VAL_PATHCACHECOUNT = `PathCache`, REGSTR_VAL_NAMECACHECOUNT = `NameCache`, REGSTR_VAL_CONTIGFILEALLOC = `ContigFileAllocSize`, REGSTR_VAL_VOLIDLETIMEOUT = `VolumeIdleTimeout`, REGSTR_VAL_BUFFIDLETIMEOUT = `BufferIdleTimeout`, REGSTR_VAL_BUFFAGETIMEOUT = `BufferAgeTimeout`, REGSTR_VAL_NAMENUMERICTAIL = `NameNumericTail`, REGSTR_VAL_READAHEADTHRESHOLD = `ReadAheadThreshold`, REGSTR_VAL_DOUBLEBUFFER = `DoubleBuffer`, REGSTR_VAL_SOFTCOMPATMODE = `SoftCompatMode`, REGSTR_VAL_DRIVESPINDOWN = `DriveSpinDown`, REGSTR_VAL_FORCEPMIO = `ForcePMIO`, REGSTR_VAL_FORCERMIO = `ForceRMIO`, REGSTR_VAL_LASTBOOTPMDRVS = `LastBootPMDrvs`, REGSTR_VAL_VIRTUALHDIRQ = `VirtualHDIRQ`, REGSTR_VAL_SRVNAMECACHECOUNT = `ServerNameCacheMax`, REGSTR_VAL_SRVNAMECACHE = `ServerNameCache`, REGSTR_VAL_SRVNAMECACHENETPROV = `ServerNameCacheNumNets`, REGSTR_VAL_AUTOMOUNT = `AutoMountDrives`, REGSTR_VAL_COMPRESSIONMETHOD = `CompressionAlgorithm`, REGSTR_VAL_COMPRESSIONTHRESHOLD = `CompressionThreshold`, REGSTR_VAL_CDCACHESIZE = `CacheSize`, REGSTR_VAL_CDPREFETCH = `Prefetch`, REGSTR_VAL_CDPREFETCHTAIL = `PrefetchTail`, REGSTR_VAL_CDRAWCACHE = `RawCache`, REGSTR_VAL_CDEXTERRORS = `ExtendedErrors`, REGSTR_VAL_CDSVDSENSE = `SVDSense`, REGSTR_VAL_CDSHOWVERSIONS = `ShowVersions`, REGSTR_VAL_CDCOMPATNAMES = `MSCDEXCompatNames`, REGSTR_VAL_CDNOREADAHEAD = `NoReadAhead`, REGSTR_VAL_SCSI = `SCSI\`, REGSTR_VAL_ESDI = `ESDI\`, REGSTR_VAL_FLOP = `FLOP\`, REGSTR_VAL_DISK = `GenDisk`, REGSTR_VAL_CDROM = `GenCD`, REGSTR_VAL_TAPE = `TAPE`, REGSTR_VAL_SCANNER = `SCANNER`, REGSTR_VAL_FLOPPY = `FLOPPY`, REGSTR_VAL_SCSITID = `SCSITargetID`, REGSTR_VAL_SCSILUN = `SCSILUN`, REGSTR_VAL_REVLEVEL = `RevisionLevel`, REGSTR_VAL_PRODUCTID = `ProductId`, REGSTR_VAL_PRODUCTTYPE = `ProductType`, REGSTR_VAL_DEVTYPE = `DeviceType`, REGSTR_VAL_REMOVABLE = `Removable`, REGSTR_VAL_CURDRVLET = `CurrentDriveLetterAssignment`, REGSTR_VAL_USRDRVLET = `UserDriveLetterAssignment`, REGSTR_VAL_SYNCDATAXFER = `SyncDataXfer`, REGSTR_VAL_AUTOINSNOTE = `AutoInsertNotification`, REGSTR_VAL_DISCONNECT = `Disconnect`, REGSTR_VAL_INT13 = `Int13`, REGSTR_VAL_PMODE_INT13 = `PModeInt13`, REGSTR_VAL_USERSETTINGS = `AdapterSettings`, REGSTR_VAL_NOIDE = `NoIDE`, REGSTR_VAL_DISKCLASSNAME = `DiskDrive`, REGSTR_VAL_CDROMCLASSNAME = `CDROM`, REGSTR_VAL_FORCELOAD = `ForceLoadPD`, REGSTR_VAL_FORCEFIFO = `ForceFIFO`, REGSTR_VAL_FORCECL = `ForceChangeLine`, REGSTR_VAL_NOUSECLASS = `NoUseClass`, REGSTR_VAL_NOINSTALLCLASS = `NoInstallClass`, REGSTR_VAL_NODISPLAYCLASS = `NoDisplayClass`, REGSTR_VAL_SILENTINSTALL = `SilentInstall`, REGSTR_KEY_PCMCIA_CLASS = `PCMCIA`, REGSTR_KEY_SCSI_CLASS = `SCSIAdapter`, REGSTR_KEY_PORTS_CLASS = `ports`, REGSTR_KEY_MEDIA_CLASS = `MEDIA`, REGSTR_KEY_DISPLAY_CLASS = `Display`, REGSTR_KEY_KEYBOARD_CLASS = `Keyboard`, REGSTR_KEY_MOUSE_CLASS = `Mouse`, REGSTR_KEY_MONITOR_CLASS = `Monitor`, REGSTR_VAL_PCMCIA_OPT = `Options`, REGSTR_VAL_PCMCIA_MEM = `Memory`, REGSTR_VAL_PCMCIA_ALLOC = `AllocMemWin`, REGSTR_VAL_PCMCIA_ATAD = `ATADelay`, REGSTR_VAL_PCMCIA_SIZ = `MinRegionSize`, REGSTR_VAL_P1284MDL = `Model`, REGSTR_VAL_P1284MFG = `Manufacturer`, REGSTR_VAL_ISAPNP = `ISAPNP`, REGSTR_VAL_ISAPNP_RDP_OVERRIDE = `RDPOverRide`, REGSTR_VAL_PCI = `PCI`, REGSTR_PCI_OPTIONS = `Options`, REGSTR_PCI_DUAL_IDE = `PCIDualIDE`, REGSTR_KEY_CRASHES = `Crashes`, REGSTR_KEY_DANGERS = `Dangers`, REGSTR_KEY_DETMODVARS = `DetModVars`, REGSTR_KEY_NDISINFO = `NDISInfo`, REGSTR_VAL_PROTINIPATH = `ProtIniPath`, REGSTR_VAL_RESOURCES = `Resources`, REGSTR_VAL_CRASHFUNCS = `CrashFuncs`, REGSTR_VAL_CLASS = `Class`, REGSTR_VAL_DEVDESC = `DeviceDesc`, REGSTR_VAL_BOOTCONFIG = `BootConfig`, REGSTR_VAL_DETFUNC = `DetFunc`, REGSTR_VAL_DETFLAGS = `DetFlags`, REGSTR_VAL_COMPATIBLEIDS = `CompatibleIDs`, REGSTR_VAL_DETCONFIG = `DetConfig`, REGSTR_VAL_VERIFYKEY = `VerifyKey`, REGSTR_VAL_COMINFO = `ComInfo`, REGSTR_VAL_INFNAME = `InfName`, REGSTR_VAL_CARDSPECIFIC = `CardSpecific`, REGSTR_VAL_NETOSTYPE = `NetOSType`, REGSTR_DATA_NETOS_NDIS = `NDIS`, REGSTR_DATA_NETOS_ODI = `ODI`, REGSTR_DATA_NETOS_IPX = `IPX`, REGSTR_VAL_MFG = `Mfg`, REGSTR_VAL_SCAN_ONLY_FIRST = `ScanOnlyFirstDrive`, REGSTR_VAL_SHARE_IRQ = `ForceIRQSharing`, REGSTR_VAL_NONSTANDARD_ATAPI = `NonStandardATAPI`, REGSTR_VAL_IDE_FORCE_SERIALIZE = `ForceSerialization`, REGSTR_VAL_HWREV = `HWRevision`, REGSTR_VAL_ENABLEINTS = `EnableInts`, REGSTR_VAL_APMBIOSVER = `APMBiosVer`, REGSTR_VAL_APMFLAGS = `APMFlags`, REGSTR_VAL_SLSUPPORT = `SLSupport`, REGSTR_VAL_MACHINETYPE = `MachineType`, REGSTR_VAL_SETUPMACHINETYPE = `SetupMachineType`, REGSTR_MACHTYPE_UNKNOWN = `Unknown`, REGSTR_MACHTYPE_IBMPC = `IBM PC`, REGSTR_MACHTYPE_IBMPCJR = `IBM PCjr`, REGSTR_MACHTYPE_IBMPCCONV = `IBM PC Convertible`, REGSTR_MACHTYPE_IBMPCXT = `IBM PC/XT`, REGSTR_MACHTYPE_IBMPCXT_286 = `IBM PC/XT 286`, REGSTR_MACHTYPE_IBMPCAT = `IBM PC/AT`, REGSTR_MACHTYPE_IBMPS2_25 = `IBM PS/2-25`, REGSTR_MACHTYPE_IBMPS2_30_286 = `IBM PS/2-30 286`, REGSTR_MACHTYPE_IBMPS2_30 = `IBM PS/2-30`, REGSTR_MACHTYPE_IBMPS2_50 = `IBM PS/2-50`, REGSTR_MACHTYPE_IBMPS2_50Z = `IBM PS/2-50Z`, REGSTR_MACHTYPE_IBMPS2_55SX = `IBM PS/2-55SX`, REGSTR_MACHTYPE_IBMPS2_60 = `IBM PS/2-60`, REGSTR_MACHTYPE_IBMPS2_65SX = `IBM PS/2-65SX`, REGSTR_MACHTYPE_IBMPS2_70 = `IBM PS/2-70`, REGSTR_MACHTYPE_IBMPS2_P70 = `IBM PS/2-P70`, REGSTR_MACHTYPE_IBMPS2_70_80 = `IBM PS/2-70/80`, REGSTR_MACHTYPE_IBMPS2_80 = `IBM PS/2-80`, REGSTR_MACHTYPE_IBMPS2_90 = `IBM PS/2-90`, REGSTR_MACHTYPE_IBMPS1 = `IBM PS/1`, REGSTR_MACHTYPE_PHOENIX_PCAT = `Phoenix PC/AT Compatible`, REGSTR_MACHTYPE_HP_VECTRA = `HP Vectra`, REGSTR_MACHTYPE_ATT_PC = `AT&T PC`, REGSTR_MACHTYPE_ZENITH_PC = `Zenith PC`, REGSTR_VAL_APMMENUSUSPEND = `APMMenuSuspend`, REGSTR_VAL_BUSTYPE = `BusType`, REGSTR_VAL_CPU = `CPU`, REGSTR_VAL_NDP = `NDP`, REGSTR_VAL_PNPBIOSVER = `PnPBIOSVer`, REGSTR_VAL_PNPSTRUCOFFSET = `PnPStrucOffset`, REGSTR_VAL_PCIBIOSVER = `PCIBIOSVer`, REGSTR_VAL_HWMECHANISM = `HWMechanism`, REGSTR_VAL_LASTPCIBUSNUM = `LastPCIBusNum`, REGSTR_VAL_CONVMEM = `ConvMem`, REGSTR_VAL_EXTMEM = `ExtMem`, REGSTR_VAL_COMPUTERNAME = `ComputerName`, REGSTR_VAL_BIOSNAME = `BIOSName`, REGSTR_VAL_BIOSVERSION = `BIOSVersion`, REGSTR_VAL_BIOSDATE = `BIOSDate`, REGSTR_VAL_MODEL = `Model`, REGSTR_VAL_SUBMODEL = `Submodel`, REGSTR_VAL_REVISION = `Revision`, REGSTR_VAL_FIFODEPTH = `FIFODepth`, REGSTR_VAL_RDINTTHRESHOLD = `RDIntThreshold`, REGSTR_VAL_WRINTTHRESHOLD = `WRIntThreshold`, REGSTR_VAL_PRIORITY = `Priority`, REGSTR_VAL_DRIVER = `Driver`, REGSTR_VAL_FUNCDESC = `FunctionDesc`, REGSTR_VAL_FORCEDCONFIG = `ForcedConfig`, REGSTR_VAL_CONFIGFLAGS = `ConfigFlags`, REGSTR_VAL_CSCONFIGFLAGS = `CSConfigFlags`, REGSTR_VAL_ROOT_DEVNODE = `HTREE\ROOT\0`, REGSTR_VAL_RESERVED_DEVNODE = `HTREE\RESERVED\0`, REGSTR_PATH_READDATAPORT = REGSTR_KEY_ISAENUM ~ `\ReadDataPort\0`, REGSTR_PATH_MULTI_FUNCTION = `MF`, REGSTR_VAL_RESOURCE_MAP = `ResourceMap`, REGSTR_PATH_CHILD_PREFIX = `Child`, REGSTR_VAL_MF_FLAGS = `MFFlags`, REGSTR_VAL_DRVDESC = `DriverDesc`, REGSTR_VAL_DEVLOADER = `DevLoader`, REGSTR_VAL_STATICVXD = `StaticVxD`, REGSTR_VAL_PROPERTIES = `Properties`, REGSTR_VAL_MANUFACTURER = `Manufacturer`, REGSTR_VAL_EXISTS = `Exists`, REGSTR_VAL_CMENUMFLAGS = `CMEnumFlags`, REGSTR_VAL_CMDRIVFLAGS = `CMDrivFlags`, REGSTR_VAL_ENUMERATOR = `Enumerator`, REGSTR_VAL_DEVICEDRIVER = `DeviceDriver`, REGSTR_VAL_PORTNAME = `PortName`, REGSTR_VAL_INFPATH = `InfPath`, REGSTR_VAL_INFSECTION = `InfSection`, REGSTR_VAL_POLLING = `Polling`, REGSTR_VAL_DONTLOADIFCONFLICT = `DontLoadIfConflict`, REGSTR_VAL_PORTSUBCLASS = `PortSubClass`, REGSTR_VAL_NETCLEAN = `NetClean`, REGSTR_VAL_IDE_NO_SERIALIZE = `IDENoSerialize`, REGSTR_VAL_NOCMOSORFDPT = `NoCMOSorFDPT`, REGSTR_VAL_COMVERIFYBASE = `COMVerifyBase`, REGSTR_KEY_OVERRIDE = `Override`, REGSTR_VAL_CONFIGMG = `CONFIGMG`, REGSTR_VAL_SYSDM = `SysDM`, REGSTR_VAL_SYSDMFUNC = `SysDMFunc`, REGSTR_VAL_PRIVATE = `Private`, REGSTR_VAL_PRIVATEFUNC = `PrivateFunc`, REGSTR_VAL_DETECT = `Detect`, REGSTR_VAL_DETECTFUNC = `DetectFunc`, REGSTR_VAL_ASKFORCONFIG = `AskForConfig`, REGSTR_VAL_ASKFORCONFIGFUNC = `AskForConfigFunc`, REGSTR_VAL_WAITFORUNDOCK = `WaitForUndock`, REGSTR_VAL_WAITFORUNDOCKFUNC = `WaitForUndockFunc`, REGSTR_VAL_REMOVEROMOKAY = `RemoveRomOkay`, REGSTR_VAL_REMOVEROMOKAYFUNC = `RemoveRomOkayFunc`, REGSTR_VAL_CURCONFIG = `CurrentConfig`, REGSTR_VAL_FRIENDLYNAME = `FriendlyName`, REGSTR_VAL_CURRENTCONFIG = `CurrentConfig`, REGSTR_VAL_MAP = `Map`, REGSTR_VAL_ID = `CurrentID`, REGSTR_VAL_DOCKED = `CurrentDockedState`, REGSTR_VAL_CHECKSUM = `CurrentChecksum`, REGSTR_VAL_HWDETECT = `HardwareDetect`, REGSTR_VAL_INHIBITRESULTS = `InhibitResults`, REGSTR_VAL_PROFILEFLAGS = `ProfileFlags`, REGSTR_KEY_PCMCIA = `PCMCIA\`, REGSTR_KEY_PCUNKNOWN = `UNKNOWN_MANUFACTURER`, REGSTR_VAL_PCSSDRIVER = `Driver`, REGSTR_KEY_PCMTD = `MTD-`, REGSTR_VAL_PCMTDRIVER = `MTD`, REGSTR_VAL_HARDWAREID = `HardwareID`, REGSTR_VAL_INSTALLER = `Installer`, REGSTR_VAL_INSICON = `Icon`, REGSTR_VAL_ENUMPROPPAGES = `EnumPropPages`, REGSTR_VAL_BASICPROPERTIES = `BasicProperties`, REGSTR_VAL_PRIVATEPROBLEM = `PrivateProblem`, REGSTR_KEY_CURRENT = `Current`, REGSTR_KEY_DEFAULT = `Default`, REGSTR_KEY_MODES = `Modes`, REGSTR_VAL_MODE = `Mode`, REGSTR_VAL_BPP = `BPP`, REGSTR_VAL_HRES = `HRes`, REGSTR_VAL_VRES = `VRes`, REGSTR_VAL_FONTSIZE = `FontSize`, REGSTR_VAL_DRV = `drv`, REGSTR_VAL_GRB = `grb`, REGSTR_VAL_VDD = `vdd`, REGSTR_VAL_VER = `Ver`, REGSTR_VAL_MAXRES = `MaxResolution`, REGSTR_VAL_DPMS = `DPMS`, REGSTR_VAL_RESUMERESET = `ResumeReset`, REGSTR_VAL_DESCRIPTION = `Description`, REGSTR_KEY_SYSTEM = `System`, REGSTR_KEY_USER = `User`, REGSTR_VAL_DPI = `dpi`, REGSTR_VAL_PCICOPTIONS = `PCICOptions`, REGSTR_VAL_PCICIRQMAP = `PCICIRQMap`, REGSTR_PATH_APPEARANCE = `Control Panel\Appearance`, REGSTR_PATH_LOOKSCHEMES = `Control Panel\Appearance\Schemes`, REGSTR_VAL_CUSTOMCOLORS = `CustomColors`, REGSTR_PATH_SCREENSAVE = `Control Panel\Desktop`, REGSTR_VALUE_USESCRPASSWORD = `ScreenSaveUsePassword`, REGSTR_VALUE_SCRPASSWORD = `ScreenSave_Data`, REGSTR_VALUE_LOWPOWERTIMEOUT = `ScreenSaveLowPowerTimeout`, REGSTR_VALUE_POWEROFFTIMEOUT = `ScreenSavePowerOffTimeout`, REGSTR_VALUE_LOWPOWERACTIVE = `ScreenSaveLowPowerActive`, REGSTR_VALUE_POWEROFFACTIVE = `ScreenSavePowerOffActive`, REGSTR_PATH_WINDOWSAPPLETS = `Software\Microsoft\Windows\CurrentVersion\Applets`, REGSTR_PATH_SYSTRAY = `Software\Microsoft\Windows\CurrentVersion\Applets\SysTray`, REGSTR_VAL_SYSTRAYSVCS = `Services`, REGSTR_VAL_SYSTRAYBATFLAGS = `PowerFlags`, REGSTR_VAL_SYSTRAYPCCARDFLAGS = `PCMCIAFlags`, REGSTR_PATH_NETWORK_USERSETTINGS = `Network`, REGSTR_KEY_NETWORK_PERSISTENT = `\Persistent`, REGSTR_KEY_NETWORK_RECENT = `\Recent`, REGSTR_VAL_REMOTE_PATH = `RemotePath`, REGSTR_VAL_USER_NAME = `UserName`, REGSTR_VAL_PROVIDER_NAME = `ProviderName`, REGSTR_VAL_CONNECTION_TYPE = `ConnectionType`, REGSTR_VAL_UPGRADE = `Upgrade`, REGSTR_KEY_LOGON = `\Logon`, REGSTR_VAL_MUSTBEVALIDATED = `MustBeValidated`, REGSTR_VAL_RUNLOGINSCRIPT = `ProcessLoginScript`, REGSTR_KEY_NETWORKPROVIDER = `\NetworkProvider`, REGSTR_PATH_NW32NETPROVIDER =REGSTR_PATH_SERVICES ~ `\NWNP32` ~ REGSTR_KEY_NETWORKPROVIDER, REGSTR_PATH_MS32NETPROVIDER =REGSTR_PATH_SERVICES ~ `\MSNP32` ~ REGSTR_KEY_NETWORKPROVIDER, REGSTR_VAL_AUTHENT_AGENT = `AuthenticatingAgent`, REGSTR_VAL_PREFREDIR = `PreferredRedir`, REGSTR_VAL_AUTOSTART = `AutoStart`, REGSTR_VAL_AUTOLOGON = `AutoLogon`, REGSTR_VAL_NETCARD = `Netcard`, REGSTR_VAL_TRANSPORT = `Transport`, REGSTR_VAL_DYNAMIC = `Dynamic`, REGSTR_VAL_TRANSITION = `Transition`, REGSTR_VAL_STATICDRIVE = `StaticDrive`, REGSTR_VAL_LOADHI = `LoadHi`, REGSTR_VAL_LOADRMDRIVERS = `LoadRMDrivers`, REGSTR_VAL_SETUPN = `SetupN`, REGSTR_VAL_SETUPNPATH = `SetupNPath`, REGSTR_VAL_WRKGRP_FORCEMAPPING = `WrkgrpForceMapping`, REGSTR_VAL_WRKGRP_REQUIRED = `WrkgrpRequired`, REGSTR_PATH_CURRENT_CONTROL_SET = `System\CurrentControlSet\Control`, REGSTR_VAL_CURRENT_USER = `Current User`, REGSTR_PATH_PWDPROVIDER = `System\CurrentControlSet\Control\PwdProvider`, REGSTR_VAL_PWDPROVIDER_PATH = `ProviderPath`, REGSTR_VAL_PWDPROVIDER_DESC = `Description`, REGSTR_VAL_PWDPROVIDER_CHANGEPWD = `ChangePassword`, REGSTR_VAL_PWDPROVIDER_CHANGEPWDHWND = `ChangePasswordHwnd`, REGSTR_VAL_PWDPROVIDER_GETPWDSTATUS = `GetPasswordStatus`, REGSTR_VAL_PWDPROVIDER_ISNP = `NetworkProvider`, REGSTR_VAL_PWDPROVIDER_CHANGEORDER = `ChangeOrder`, REGSTR_PATH_POLICIES = `Software\Microsoft\Windows\CurrentVersion\Policies`, REGSTR_PATH_UPDATE = `System\CurrentControlSet\Control\Update`, REGSTR_VALUE_ENABLE = `Enable`, REGSTR_VALUE_VERBOSE = `Verbose`, REGSTR_VALUE_NETPATH = `NetworkPath`, REGSTR_VALUE_DEFAULTLOC = `UseDefaultNetLocation`, REGSTR_KEY_NETWORK = `Network`, // [Redefined] REGSTR_KEY_SYSTEM = `System`) REGSTR_KEY_PRINTERS = `Printers`, REGSTR_KEY_WINOLDAPP = `WinOldApp`, REGSTR_VAL_NOFILESHARING = `NoFileSharing`, REGSTR_VAL_NOPRINTSHARING = `NoPrintSharing`, REGSTR_VAL_NOFILESHARINGCTRL = `NoFileSharingControl`, REGSTR_VAL_NOPRINTSHARINGCTRL = `NoPrintSharingControl`, REGSTR_VAL_HIDESHAREPWDS = `HideSharePwds`, REGSTR_VAL_DISABLEPWDCACHING = `DisablePwdCaching`, REGSTR_VAL_ALPHANUMPWDS = `AlphanumPwds`, REGSTR_VAL_NETSETUP_DISABLE = `NoNetSetup`, REGSTR_VAL_NETSETUP_NOCONFIGPAGE = `NoNetSetupConfigPage`, REGSTR_VAL_NETSETUP_NOIDPAGE = `NoNetSetupIDPage`, REGSTR_VAL_NETSETUP_NOSECURITYPAGE = `NoNetSetupSecurityPage`, REGSTR_VAL_SYSTEMCPL_NOVIRTMEMPAGE = `NoVirtMemPage`, REGSTR_VAL_SYSTEMCPL_NODEVMGRPAGE = `NoDevMgrPage`, REGSTR_VAL_SYSTEMCPL_NOCONFIGPAGE = `NoConfigPage`, REGSTR_VAL_SYSTEMCPL_NOFILESYSPAGE = `NoFileSysPage`, REGSTR_VAL_DISPCPL_NODISPCPL = `NoDispCPL`, REGSTR_VAL_DISPCPL_NOBACKGROUNDPAGE = `NoDispBackgroundPage`, REGSTR_VAL_DISPCPL_NOSCRSAVPAGE = `NoDispScrSavPage`, REGSTR_VAL_DISPCPL_NOAPPEARANCEPAGE = `NoDispAppearancePage`, REGSTR_VAL_DISPCPL_NOSETTINGSPAGE = `NoDispSettingsPage`, REGSTR_VAL_SECCPL_NOSECCPL = `NoSecCPL`, REGSTR_VAL_SECCPL_NOPWDPAGE = `NoPwdPage`, REGSTR_VAL_SECCPL_NOADMINPAGE = `NoAdminPage`, REGSTR_VAL_SECCPL_NOPROFILEPAGE = `NoProfilePage`, REGSTR_VAL_PRINTERS_HIDETABS = `NoPrinterTabs`, REGSTR_VAL_PRINTERS_NODELETE = `NoDeletePrinter`, REGSTR_VAL_PRINTERS_NOADD = `NoAddPrinter`, REGSTR_VAL_WINOLDAPP_DISABLED = `Disabled`, REGSTR_VAL_WINOLDAPP_NOREALMODE = `NoRealMode`, REGSTR_VAL_NOENTIRENETWORK = `NoEntireNetwork`, REGSTR_VAL_NOWORKGROUPCONTENTS = `NoWorkgroupContents`, REGSTR_VAL_MINPWDLEN = `MinPwdLen`, REGSTR_VAL_PWDEXPIRATION = `PwdExpiration`, REGSTR_VAL_WIN31PROVIDER = `Win31Provider`, REGSTR_VAL_DISABLEREGTOOLS = `DisableRegistryTools`, REGSTR_PATH_WINLOGON = `Software\Microsoft\Windows\CurrentVersion\Winlogon`, REGSTR_VAL_LEGALNOTICECAPTION = `LegalNoticeCaption`, REGSTR_VAL_LEGALNOTICETEXT = `LegalNoticeText`, REGSTR_VAL_RESTRICTRUN = `RestrictRun`, REGSTR_KEY_POL_USERS = `Users`, REGSTR_KEY_POL_COMPUTERS = `Computers`, REGSTR_KEY_POL_USERGROUPS = `UserGroups`, REGSTR_KEY_POL_DEFAULT = `.default`, REGSTR_KEY_POL_USERGROUPDATA = `GroupData\UserGroups\Priority`, REGSTR_PATH_TIMEZONE = `System\CurrentControlSet\Control\TimeZoneInformation`, REGSTR_VAL_TZBIAS = `Bias`, REGSTR_VAL_TZDLTBIAS = `DaylightBias`, REGSTR_VAL_TZSTDBIAS = `StandardBias`, REGSTR_VAL_TZACTBIAS = `ActiveTimeBias`, REGSTR_VAL_TZDLTFLAG = `DaylightFlag`, REGSTR_VAL_TZSTDSTART = `StandardStart`, REGSTR_VAL_TZDLTSTART = `DaylightStart`, REGSTR_VAL_TZDLTNAME = `DaylightName`, REGSTR_VAL_TZSTDNAME = `StandardName`, REGSTR_VAL_TZNOCHANGESTART = `NoChangeStart`, REGSTR_VAL_TZNOCHANGEEND = `NoChangeEnd`, REGSTR_VAL_TZNOAUTOTIME = `DisableAutoDaylightTimeSet`, REGSTR_PATH_FLOATINGPOINTPROCESSOR = `HARDWARE\DESCRIPTION\System\FloatingPointProcessor`, REGSTR_PATH_FLOATINGPOINTPROCESSOR0 = `HARDWARE\DESCRIPTION\System\FloatingPointProcessor\0`, REGSTR_PATH_COMPUTRNAME = `System\CurrentControlSet\Control\ComputerName\ComputerName`, REGSTR_VAL_COMPUTRNAME = `ComputerName`, REGSTR_PATH_SHUTDOWN = `System\CurrentControlSet\Control\Shutdown`, REGSTR_VAL_FORCEREBOOT = `ForceReboot`, REGSTR_VAL_SETUPPROGRAMRAN = `SetupProgramRan`, REGSTR_VAL_DOES_POLLING = `PollingSupportNeeded`, REGSTR_PATH_KNOWNDLLS = `System\CurrentControlSet\Control\SessionManager\KnownDLLs`, REGSTR_PATH_KNOWN16DLLS = `System\CurrentControlSet\Control\SessionManager\Known16DLLs`, REGSTR_PATH_CHECKVERDLLS = `System\CurrentControlSet\Control\SessionManager\CheckVerDLLs`, REGSTR_PATH_WARNVERDLLS = `System\CurrentControlSet\Control\SessionManager\WarnVerDLLs`, REGSTR_PATH_HACKINIFILE = `System\CurrentControlSet\Control\SessionManager\HackIniFiles`, REGSTR_PATH_CHECKBADAPPS = `System\CurrentControlSet\Control\SessionManager\CheckBadApps`, REGSTR_PATH_APPPATCH = `System\CurrentControlSet\Control\SessionManager\AppPatches`, REGSTR_PATH_KNOWNVXDS = `System\CurrentControlSet\Control\SessionManager\KnownVxDs`, REGSTR_VAL_UNINSTALLER_DISPLAYNAME = `DisplayName`, REGSTR_VAL_UNINSTALLER_COMMANDLINE = `UninstallString`, REGSTR_PATH_DESKTOP = REGSTR_PATH_SCREENSAVE, REGSTR_PATH_MOUSE = `Control Panel\Mouse`, REGSTR_PATH_KEYBOARD = `Control Panel\Keyboard`, REGSTR_PATH_COLORS = `Control Panel\Colors`, REGSTR_PATH_SOUND = `Control Panel\Sound`, REGSTR_PATH_METRICS = `Control Panel\Desktop\WindowMetrics`, REGSTR_PATH_ICONS = `Control Panel\Icons`, REGSTR_PATH_CURSORS = `Control Panel\Cursors`, REGSTR_PATH_CHECKDISK = `Software\Microsoft\Windows\CurrentVersion\Applets\Check Drive`, REGSTR_PATH_CHECKDISKSET = `Settings`, REGSTR_PATH_CHECKDISKUDRVS = `NoUnknownDDErrDrvs`, REGSTR_PATH_FAULT = `Software\Microsoft\Windows\CurrentVersion\Fault`, REGSTR_VAL_FAULT_LOGFILE = `LogFile`, REGSTR_PATH_AEDEBUG = `Software\Microsoft\Windows NT\CurrentVersion\AeDebug`, REGSTR_VAL_AEDEBUG_DEBUGGER = `Debugger`, REGSTR_VAL_AEDEBUG_AUTO = `Auto`, REGSTR_PATH_GRPCONV = `Software\Microsoft\Windows\CurrentVersion\GrpConv`, REGSTR_VAL_REGITEMDELETEMESSAGE = `Removal Message`, REGSTR_PATH_LASTCHECK = `Software\Microsoft\Windows\CurrentVersion\Explorer\LastCheck`, REGSTR_PATH_LASTOPTIMIZE = `Software\Microsoft\Windows\CurrentVersion\Explorer\LastOptimize`, REGSTR_PATH_LASTBACKUP = `Software\Microsoft\Windows\CurrentVersion\Explorer\LastBackup`, REGSTR_PATH_CHKLASTCHECK = `Software\Microsoft\Windows\CurrentVersion\Applets\Check Drive\LastCheck`, REGSTR_PATH_CHKLASTSURFAN = `Software\Microsoft\Windows\CurrentVersion\Applets\Check Drive\LastSurfaceAnalysis`, REGSTR_KEY_SHARES = `Software\Microsoft\Windows\CurrentVersion\Network\LanMan`, REGSTR_VAL_SHARES_FLAGS = `Flags`, REGSTR_VAL_SHARES_TYPE = `Type`, REGSTR_VAL_SHARES_PATH = `Path`, REGSTR_VAL_SHARES_REMARK = `Remark`, REGSTR_VAL_SHARES_RW_PASS = `Parm1`, REGSTR_VAL_SHARES_RO_PASS = `Parm2`, REGSTR_PATH_PRINT = `System\CurrentControlSet\Control\Print`, REGSTR_PATH_PRINTERS = `System\CurrentControlSet\Control\Print\Printers`, REGSTR_PATH_PROVIDERS = `System\CurrentControlSet\Control\Print\Providers`, REGSTR_PATH_MONITORS = `System\CurrentControlSet\Control\Print\Monitors`, REGSTR_PATH_ENVIRONMENTS = `System\CurrentControlSet\Control\Print\Environments`, REGSTR_VAL_START_ON_BOOT = `StartOnBoot`, REGSTR_VAL_PRINTERS_MASK = `PrintersMask`, REGSTR_VAL_DOS_SPOOL_MASK = `DOSSpoolMask`, REGSTR_KEY_CURRENT_ENV = `\Windows 4.0`, REGSTR_KEY_DRIVERS = `\Drivers`, REGSTR_KEY_PRINT_PROC = `\Print Processors`, REGSTR_PATH_EVENTLABELS = `AppEvents\EventLabels`, REGSTR_PATH_SCHEMES = `AppEvents\Schemes`, REGSTR_PATH_APPS = REGSTR_PATH_SCHEMES ~ `\Apps`, REGSTR_PATH_APPS_DEFAULT = REGSTR_PATH_SCHEMES ~ `\Apps\.Default`, REGSTR_PATH_NAMES = REGSTR_PATH_SCHEMES ~ `\Names`, REGSTR_PATH_MULTIMEDIA = REGSTR_PATH_SETUP ~ `\Multimedia`, REGSTR_PATH_MULTIMEDIA_AUDIO = `Software\Microsoft\Multimedia\Audio`, REGSTR_PATH_MEDIARESOURCES = REGSTR_PATH_CURRENT_CONTROL_SET ~ `\MediaResources`, REGSTR_PATH_MEDIAPROPERTIES = REGSTR_PATH_CURRENT_CONTROL_SET ~ `\MediaProperties`, REGSTR_PATH_PRIVATEPROPERTIES = REGSTR_PATH_MEDIAPROPERTIES ~ `\PrivateProperties`, REGSTR_PATH_PUBLICPROPERTIES = REGSTR_PATH_MEDIAPROPERTIES ~ `\PublicProperties`, REGSTR_PATH_JOYOEM = REGSTR_PATH_PRIVATEPROPERTIES ~ `\Joystick\OEM`, REGSTR_PATH_JOYCONFIG = REGSTR_PATH_MEDIARESOURCES ~ `\Joystick`, REGSTR_KEY_JOYCURR = `CurrentJoystickSettings`, REGSTR_KEY_JOYSETTINGS = `JoystickSettings`, REGSTR_VAL_JOYUSERVALUES = `JoystickUserValues`, REGSTR_VAL_JOYCALLOUT = `JoystickCallout`, REGSTR_VAL_JOYNCONFIG = `Joystick%dConfiguration`, REGSTR_VAL_JOYNOEMNAME = `Joystick%dOEMName`, REGSTR_VAL_JOYNOEMCALLOUT = `Joystick%dOEMCallout`, REGSTR_VAL_JOYOEMCALLOUT = `OEMCallout`, REGSTR_VAL_JOYOEMNAME = `OEMName`, REGSTR_VAL_JOYOEMDATA = `OEMData`, REGSTR_VAL_JOYOEMXYLABEL = `OEMXYLabel`, REGSTR_VAL_JOYOEMZLABEL = `OEMZLabel`, REGSTR_VAL_JOYOEMRLABEL = `OEMRLabel`, REGSTR_VAL_JOYOEMPOVLABEL = `OEMPOVLabel`, REGSTR_VAL_JOYOEMULABEL = `OEMULabel`, REGSTR_VAL_JOYOEMVLABEL = `OEMVLabel`, REGSTR_VAL_JOYOEMTESTMOVEDESC = `OEMTestMoveDesc`, REGSTR_VAL_JOYOEMTESTBUTTONDESC = `OEMTestButtonDesc`, REGSTR_VAL_JOYOEMTESTMOVECAP = `OEMTestMoveCap`, REGSTR_VAL_JOYOEMTESTBUTTONCAP = `OEMTestButtonCap`, REGSTR_VAL_JOYOEMTESTWINCAP = `OEMTestWinCap`, REGSTR_VAL_JOYOEMCALCAP = `OEMCalCap`, REGSTR_VAL_JOYOEMCALWINCAP = `OEMCalWinCap`, REGSTR_VAL_JOYOEMCAL1 = `OEMCal1`, REGSTR_VAL_JOYOEMCAL2 = `OEMCal2`, REGSTR_VAL_JOYOEMCAL3 = `OEMCal3`, REGSTR_VAL_JOYOEMCAL4 = `OEMCal4`, REGSTR_VAL_JOYOEMCAL5 = `OEMCal5`, REGSTR_VAL_JOYOEMCAL6 = `OEMCal6`, REGSTR_VAL_JOYOEMCAL7 = `OEMCal7`, REGSTR_VAL_JOYOEMCAL8 = `OEMCal8`, REGSTR_VAL_JOYOEMCAL9 = `OEMCal9`, REGSTR_VAL_JOYOEMCAL10 = `OEMCal10`, REGSTR_VAL_JOYOEMCAL11 = `OEMCal11`, REGSTR_VAL_JOYOEMCAL12 = `OEMCal12`; enum { DTRESULTOK, DTRESULTFIX, DTRESULTPROB, DTRESULTPART } //#ifndef NEC_98 enum PCIC_DEFAULT_IRQMASK = 0x4EB8; //#else //#define PCIC_DEFAULT_IRQMASK 0x1468 //#endif enum PCIC_DEFAULT_NUMSOCKETS = 0; struct DSKTLSYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; WORD wResult; } alias DSKTLSYSTEMTIME* PDSKTLSYSTEMTIME, LPDSKTLSYSTEMTIME; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmerr.d0000664000175000017500000002226612776214756023010 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmerr.d) */ module core.sys.windows.lmerr; version (Windows): import core.sys.windows.winerror; enum { NERR_Success = 0, NERR_BASE = 2100, NERR_NetNotStarted = NERR_BASE + 2, NERR_UnknownServer, NERR_ShareMem, NERR_NoNetworkResource, NERR_RemoteOnly, NERR_DevNotRedirected, NERR_ServerNotStarted = NERR_BASE + 14, NERR_ItemNotFound, NERR_UnknownDevDir, NERR_RedirectedPath, NERR_DuplicateShare, NERR_NoRoom, NERR_TooManyItems = NERR_BASE + 21, NERR_InvalidMaxUsers, NERR_BufTooSmall, NERR_RemoteErr = NERR_BASE + 27, NERR_LanmanIniError = NERR_BASE + 31, NERR_NetworkError = NERR_BASE + 36, NERR_WkstaInconsistentState, NERR_WkstaNotStarted, NERR_BrowserNotStarted, NERR_InternalError, NERR_BadTransactConfig, NERR_InvalidAPI, NERR_BadEventName, NERR_DupNameReboot, NERR_CfgCompNotFound = NERR_BASE + 46, NERR_CfgParamNotFound, NERR_LineTooLong = NERR_BASE + 49, NERR_QNotFound, NERR_JobNotFound, NERR_DestNotFound, NERR_DestExists, NERR_QExists, NERR_QNoRoom, NERR_JobNoRoom, NERR_DestNoRoom, NERR_DestIdle, NERR_DestInvalidOp, NERR_ProcNoRespond, NERR_SpoolerNotLoaded, NERR_DestInvalidState, NERR_QInvalidState, NERR_JobInvalidState, NERR_SpoolNoMemory, NERR_DriverNotFound, NERR_DataTypeInvalid, NERR_ProcNotFound, NERR_ServiceTableLocked = NERR_BASE + 80, NERR_ServiceTableFull, NERR_ServiceInstalled, NERR_ServiceEntryLocked, NERR_ServiceNotInstalled, NERR_BadServiceName, NERR_ServiceCtlTimeout, NERR_ServiceCtlBusy, NERR_BadServiceProgName, NERR_ServiceNotCtrl, NERR_ServiceKillProc, NERR_ServiceCtlNotValid, NERR_NotInDispatchTbl, NERR_BadControlRecv, NERR_ServiceNotStarting, NERR_AlreadyLoggedOn = NERR_BASE + 100, NERR_NotLoggedOn, NERR_BadUsername, NERR_BadPassword, NERR_UnableToAddName_W, NERR_UnableToAddName_F, NERR_UnableToDelName_W, NERR_UnableToDelName_F, NERR_LogonsPaused = NERR_BASE + 109, NERR_LogonServerConflict, NERR_LogonNoUserPath, NERR_LogonScriptError, NERR_StandaloneLogon = NERR_BASE + 114, NERR_LogonServerNotFound, NERR_LogonDomainExists, NERR_NonValidatedLogon, NERR_ACFNotFound = NERR_BASE + 119, NERR_GroupNotFound, NERR_UserNotFound, NERR_ResourceNotFound, NERR_GroupExists, NERR_UserExists, NERR_ResourceExists, NERR_NotPrimary, NERR_ACFNotLoaded, NERR_ACFNoRoom, NERR_ACFFileIOFail, NERR_ACFTooManyLists, NERR_UserLogon, NERR_ACFNoParent, NERR_CanNotGrowSegment, NERR_SpeGroupOp, NERR_NotInCache, NERR_UserInGroup, NERR_UserNotInGroup, NERR_AccountUndefined, NERR_AccountExpired, NERR_InvalidWorkstation, NERR_InvalidLogonHours, NERR_PasswordExpired, NERR_PasswordCantChange, NERR_PasswordHistConflict, NERR_PasswordTooShort, NERR_PasswordTooRecent, NERR_InvalidDatabase, NERR_DatabaseUpToDate, NERR_SyncRequired, NERR_UseNotFound, NERR_BadAsgType, NERR_DeviceIsShared, NERR_NoComputerName = NERR_BASE + 170, NERR_MsgAlreadyStarted, NERR_MsgInitFailed, NERR_NameNotFound, NERR_AlreadyForwarded, NERR_AddForwarded, NERR_AlreadyExists, NERR_TooManyNames, NERR_DelComputerName, NERR_LocalForward, NERR_GrpMsgProcessor, NERR_PausedRemote, NERR_BadReceive, NERR_NameInUse, NERR_MsgNotStarted, NERR_NotLocalName, NERR_NoForwardName, NERR_RemoteFull, NERR_NameNotForwarded, NERR_TruncatedBroadcast, NERR_InvalidDevice = NERR_BASE + 194, NERR_WriteFault, NERR_DuplicateName = NERR_BASE + 197, NERR_DeleteLater, NERR_IncompleteDel, NERR_MultipleNets, NERR_NetNameNotFound = NERR_BASE + 210, NERR_DeviceNotShared, NERR_ClientNameNotFound, NERR_FileIdNotFound = NERR_BASE + 214, NERR_ExecFailure, NERR_TmpFile, NERR_TooMuchData, NERR_DeviceShareConflict, NERR_BrowserTableIncomplete, NERR_NotLocalDomain, NERR_DevInvalidOpCode = NERR_BASE + 231, NERR_DevNotFound, NERR_DevNotOpen, NERR_BadQueueDevString, NERR_BadQueuePriority, NERR_NoCommDevs = NERR_BASE + 237, NERR_QueueNotFound, NERR_BadDevString = NERR_BASE + 240, NERR_BadDev, NERR_InUseBySpooler, NERR_CommDevInUse, NERR_InvalidComputer = NERR_BASE + 251, NERR_MaxLenExceeded = NERR_BASE + 254, NERR_BadComponent = NERR_BASE + 256, NERR_CantType, NERR_TooManyEntries = NERR_BASE + 262, NERR_ProfileFileTooBig = NERR_BASE + 270, NERR_ProfileOffset, NERR_ProfileCleanup, NERR_ProfileUnknownCmd, NERR_ProfileLoadErr, NERR_ProfileSaveErr, NERR_LogOverflow = NERR_BASE + 277, NERR_LogFileChanged, NERR_LogFileCorrupt, NERR_SourceIsDir, NERR_BadSource, NERR_BadDest, NERR_DifferentServers, NERR_RunSrvPaused = NERR_BASE + 285, NERR_ErrCommRunSrv = NERR_BASE + 289, NERR_ErrorExecingGhost = NERR_BASE + 291, NERR_ShareNotFound, NERR_InvalidLana = NERR_BASE + 300, NERR_OpenFiles, NERR_ActiveConns, NERR_BadPasswordCore, NERR_DevInUse, NERR_LocalDrive, NERR_AlertExists = NERR_BASE + 330, NERR_TooManyAlerts, NERR_NoSuchAlert, NERR_BadRecipient, NERR_AcctLimitExceeded, NERR_InvalidLogSeek = NERR_BASE + 340, NERR_BadUasConfig = NERR_BASE + 350, NERR_InvalidUASOp, NERR_LastAdmin, NERR_DCNotFound, NERR_LogonTrackingError, NERR_NetlogonNotStarted, NERR_CanNotGrowUASFile, NERR_TimeDiffAtDC, NERR_PasswordMismatch, NERR_NoSuchServer = NERR_BASE + 360, NERR_NoSuchSession, NERR_NoSuchConnection, NERR_TooManyServers, NERR_TooManySessions, NERR_TooManyConnections, NERR_TooManyFiles, NERR_NoAlternateServers, NERR_TryDownLevel = NERR_BASE + 370, NERR_UPSDriverNotStarted = NERR_BASE + 380, NERR_UPSInvalidConfig, NERR_UPSInvalidCommPort, NERR_UPSSignalAsserted, NERR_UPSShutdownFailed, NERR_BadDosRetCode = NERR_BASE + 400, NERR_ProgNeedsExtraMem, NERR_BadDosFunction, NERR_RemoteBootFailed, NERR_BadFileCheckSum, NERR_NoRplBootSystem, NERR_RplLoadrNetBiosErr, NERR_RplLoadrDiskErr, NERR_ImageParamErr, NERR_TooManyImageParams, NERR_NonDosFloppyUsed, NERR_RplBootRestart, NERR_RplSrvrCallFailed, NERR_CantConnectRplSrvr, NERR_CantOpenImageFile, NERR_CallingRplSrvr, NERR_StartingRplBoot, NERR_RplBootServiceTerm, NERR_RplBootStartFailed, NERR_RPL_CONNECTED, NERR_BrowserConfiguredToNotRun = NERR_BASE + 450, NERR_RplNoAdaptersStarted = NERR_BASE + 510, NERR_RplBadRegistry, NERR_RplBadDatabase, NERR_RplRplfilesShare, NERR_RplNotRplServer, NERR_RplCannotEnum, NERR_RplWkstaInfoCorrupted, NERR_RplWkstaNotFound, NERR_RplWkstaNameUnavailable, NERR_RplProfileInfoCorrupted, NERR_RplProfileNotFound, NERR_RplProfileNameUnavailable, NERR_RplProfileNotEmpty, NERR_RplConfigInfoCorrupted, NERR_RplConfigNotFound, NERR_RplAdapterInfoCorrupted, NERR_RplInternal, NERR_RplVendorInfoCorrupted, NERR_RplBootInfoCorrupted, NERR_RplWkstaNeedsUserAcct, NERR_RplNeedsRPLUSERAcct, NERR_RplBootNotFound, NERR_RplIncompatibleProfile, NERR_RplAdapterNameUnavailable, NERR_RplConfigNotEmpty, NERR_RplBootInUse, NERR_RplBackupDatabase, NERR_RplAdapterNotFound, NERR_RplVendorNotFound, NERR_RplVendorNameUnavailable, NERR_RplBootNameUnavailable, NERR_RplConfigNameUnavailable, NERR_DfsInternalCorruption = NERR_BASE + 560, NERR_DfsVolumeDataCorrupt, NERR_DfsNoSuchVolume, NERR_DfsVolumeAlreadyExists, NERR_DfsAlreadyShared, NERR_DfsNoSuchShare, NERR_DfsNotALeafVolume, NERR_DfsLeafVolume, NERR_DfsVolumeHasMultipleServers, NERR_DfsCantCreateJunctionPoint, NERR_DfsServerNotDfsAware, NERR_DfsBadRenamePath, NERR_DfsVolumeIsOffline, NERR_DfsNoSuchServer, NERR_DfsCyclicalName, NERR_DfsNotSupportedInServerDfs, NERR_DfsDuplicateService, NERR_DfsCantRemoveLastServerShare, NERR_DfsVolumeIsInterDfs, NERR_DfsInconsistent, NERR_DfsServerUpgraded, NERR_DfsDataIsIdentical, NERR_DfsCantRemoveDfsRoot, NERR_DfsChildOrParentInDfs, NERR_DfsInternalError = NERR_BASE + 590, MAX_NERR = NERR_BASE + 899 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/exdispid.d0000664000175000017500000000102512776214756023466 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_exdispid.d) */ module core.sys.windows.exdispid; version (Windows): enum : int { DISPID_STATUSTEXTCHANGE = 102, DISPID_PROGRESSCHANGE = 108, DISPID_TITLECHANGE = 113, DISPID_BEFORENAVIGATE2 = 250, DISPID_NEWWINDOW2 = 251, DISPID_DOCUMENTCOMPLETE = 259 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmaccess.d0000664000175000017500000005753612776214756023471 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmaccess.d) */ module core.sys.windows.lmaccess; version (Windows): pragma(lib, "netapi32"); /** Changes relative to MinGW: USER_POSIX_ID_PARMNUM and GROUP_POSIX_ID_PARMNUM aren't in MinGW or in the Platform SDK docs, so they have been dropped from this file. */ private import core.sys.windows.lmcons, core.sys.windows.windef; const wchar[] GROUP_SPECIALGRP_USERS = "USERS", GROUP_SPECIALGRP_ADMINS = "ADMINS", GROUP_SPECIALGRP_GUESTS = "GUESTS", GROUP_SPECIALGRP_LOCAL = "LOCAL"; enum ACCESS_LETTERS = "RWCXDAP "; enum NETLOGON_CONTROL_QUERY=1; enum NETLOGON_CONTROL_REPLICATE=2; enum NETLOGON_CONTROL_SYNCHRONIZE=3; enum NETLOGON_CONTROL_PDC_REPLICATE=4; enum NETLOGON_CONTROL_REDISCOVER=5; enum NETLOGON_CONTROL_TC_QUERY=6; enum NETLOGON_CONTROL_BACKUP_CHANGE_LOG=65532; enum NETLOGON_CONTROL_TRUNCATE_LOG=65533; enum NETLOGON_CONTROL_SET_DBFLAG=65534; enum NETLOGON_CONTROL_BREAKPOINT=65535; enum UF_SCRIPT=1; enum UF_ACCOUNTDISABLE=2; enum UF_HOMEDIR_REQUIRED=8; enum UF_LOCKOUT=16; enum UF_PASSWD_NOTREQD=32; enum UF_PASSWD_CANT_CHANGE=64; enum UF_TEMP_DUPLICATE_ACCOUNT=256; enum UF_NORMAL_ACCOUNT=512; enum UF_INTERDOMAIN_TRUST_ACCOUNT=2048; enum UF_WORKSTATION_TRUST_ACCOUNT=4096; enum UF_SERVER_TRUST_ACCOUNT=8192; enum UF_MNS_LOGON_ACCOUNT=131072; enum UF_MACHINE_ACCOUNT_MASK=UF_INTERDOMAIN_TRUST_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT|UF_SERVER_TRUST_ACCOUNT; enum UF_ACCOUNT_TYPE_MASK=UF_TEMP_DUPLICATE_ACCOUNT|UF_NORMAL_ACCOUNT|UF_INTERDOMAIN_TRUST_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT|UF_SERVER_TRUST_ACCOUNT; enum UF_DONT_EXPIRE_PASSWD=65536; enum UF_SETTABLE_BITS=UF_SCRIPT|UF_ACCOUNTDISABLE|UF_LOCKOUT|UF_HOMEDIR_REQUIRED|UF_PASSWD_NOTREQD|UF_PASSWD_CANT_CHANGE|UF_ACCOUNT_TYPE_MASK|UF_DONT_EXPIRE_PASSWD; enum FILTER_TEMP_DUPLICATE_ACCOUNT=1; enum FILTER_NORMAL_ACCOUNT=2; enum FILTER_INTERDOMAIN_TRUST_ACCOUNT=8; enum FILTER_WORKSTATION_TRUST_ACCOUNT=16; enum FILTER_SERVER_TRUST_ACCOUNT=32; enum LG_INCLUDE_INDIRECT=1; enum AF_OP_PRINT=1; enum AF_OP_COMM=2; enum AF_OP_SERVER=4; enum AF_OP_ACCOUNTS=8; enum AF_SETTABLE_BITS=(AF_OP_PRINT|AF_OP_COMM|AF_OP_SERVER|AF_OP_ACCOUNTS); enum UAS_ROLE_STANDALONE=0; enum UAS_ROLE_MEMBER=1; enum UAS_ROLE_BACKUP=2; enum UAS_ROLE_PRIMARY=3; enum USER_NAME_PARMNUM=1; enum USER_PASSWORD_PARMNUM=3; enum USER_PASSWORD_AGE_PARMNUM=4; enum USER_PRIV_PARMNUM=5; enum USER_HOME_DIR_PARMNUM=6; enum USER_COMMENT_PARMNUM=7; enum USER_FLAGS_PARMNUM=8; enum USER_SCRIPT_PATH_PARMNUM=9; enum USER_AUTH_FLAGS_PARMNUM=10; enum USER_FULL_NAME_PARMNUM=11; enum USER_USR_COMMENT_PARMNUM=12; enum USER_PARMS_PARMNUM=13; enum USER_WORKSTATIONS_PARMNUM=14; enum USER_LAST_LOGON_PARMNUM=15; enum USER_LAST_LOGOFF_PARMNUM=16; enum USER_ACCT_EXPIRES_PARMNUM=17; enum USER_MAX_STORAGE_PARMNUM=18; enum USER_UNITS_PER_WEEK_PARMNUM=19; enum USER_LOGON_HOURS_PARMNUM=20; enum USER_PAD_PW_COUNT_PARMNUM=21; enum USER_NUM_LOGONS_PARMNUM=22; enum USER_LOGON_SERVER_PARMNUM=23; enum USER_COUNTRY_CODE_PARMNUM=24; enum USER_CODE_PAGE_PARMNUM=25; enum USER_PRIMARY_GROUP_PARMNUM=51; enum USER_PROFILE=52; enum USER_PROFILE_PARMNUM=52; enum USER_HOME_DIR_DRIVE_PARMNUM=53; enum USER_NAME_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_NAME_PARMNUM; enum USER_PASSWORD_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_PASSWORD_PARMNUM; enum USER_PASSWORD_AGE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_PASSWORD_AGE_PARMNUM; enum USER_PRIV_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_PRIV_PARMNUM; enum USER_HOME_DIR_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_HOME_DIR_PARMNUM; enum USER_COMMENT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_COMMENT_PARMNUM; enum USER_FLAGS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_FLAGS_PARMNUM; enum USER_SCRIPT_PATH_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_SCRIPT_PATH_PARMNUM; enum USER_AUTH_FLAGS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_AUTH_FLAGS_PARMNUM; enum USER_FULL_NAME_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_FULL_NAME_PARMNUM; enum USER_USR_COMMENT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_USR_COMMENT_PARMNUM; enum USER_PARMS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_PARMS_PARMNUM; enum USER_WORKSTATIONS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_WORKSTATIONS_PARMNUM; enum USER_LAST_LOGON_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_LAST_LOGON_PARMNUM; enum USER_LAST_LOGOFF_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_LAST_LOGOFF_PARMNUM; enum USER_ACCT_EXPIRES_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_ACCT_EXPIRES_PARMNUM; enum USER_MAX_STORAGE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_MAX_STORAGE_PARMNUM; enum USER_UNITS_PER_WEEK_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_UNITS_PER_WEEK_PARMNUM; enum USER_LOGON_HOURS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_LOGON_HOURS_PARMNUM; enum USER_PAD_PW_COUNT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_PAD_PW_COUNT_PARMNUM; enum USER_NUM_LOGONS_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_NUM_LOGONS_PARMNUM; enum USER_LOGON_SERVER_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_LOGON_SERVER_PARMNUM; enum USER_COUNTRY_CODE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_COUNTRY_CODE_PARMNUM; enum USER_CODE_PAGE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_CODE_PAGE_PARMNUM; enum USER_PRIMARY_GROUP_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_PRIMARY_GROUP_PARMNUM; // USER_POSIX_ID_PARMNUM isn't in MinGW or in the Platform SDK docs. //const USER_POSIX_ID_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_POSIX_ID_PARMNUM; enum USER_HOME_DIR_DRIVE_INFOLEVEL = PARMNUM_BASE_INFOLEVEL+USER_HOME_DIR_DRIVE_PARMNUM; enum NULL_USERSETINFO_PASSWD=" "; enum ULONG TIMEQ_FOREVER=-1; enum ULONG USER_MAXSTORAGE_UNLIMITED=-1; enum ULONG USER_NO_LOGOFF=-1; enum UNITS_PER_DAY=24; enum UNITS_PER_WEEK=168; enum USER_PRIV_MASK=3; enum USER_PRIV_GUEST=0; enum USER_PRIV_USER=1; enum USER_PRIV_ADMIN=2; enum MAX_PASSWD_LEN=PWLEN; enum DEF_MIN_PWLEN=6; enum DEF_PWUNIQUENESS=5; enum DEF_MAX_PWHIST=8; enum DEF_MAX_PWAGE=TIMEQ_FOREVER; enum DEF_MIN_PWAGE=0; enum ULONG DEF_FORCE_LOGOFF=0xffffffff; enum DEF_MAX_BADPW=0; enum ONE_DAY=86400; enum VALIDATED_LOGON=0; enum PASSWORD_EXPIRED=2; enum NON_VALIDATED_LOGON=3; enum VALID_LOGOFF=1; enum MODALS_MIN_PASSWD_LEN_PARMNUM=1; enum MODALS_MAX_PASSWD_AGE_PARMNUM=2; enum MODALS_MIN_PASSWD_AGE_PARMNUM=3; enum MODALS_FORCE_LOGOFF_PARMNUM=4; enum MODALS_PASSWD_HIST_LEN_PARMNUM=5; enum MODALS_ROLE_PARMNUM=6; enum MODALS_PRIMARY_PARMNUM=7; enum MODALS_DOMAIN_NAME_PARMNUM=8; enum MODALS_DOMAIN_ID_PARMNUM=9; enum MODALS_LOCKOUT_DURATION_PARMNUM=10; enum MODALS_LOCKOUT_OBSERVATION_WINDOW_PARMNUM=11; enum MODALS_LOCKOUT_THRESHOLD_PARMNUM=12; enum MODALS_MIN_PASSWD_LEN_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+MODALS_MIN_PASSWD_LEN_PARMNUM); enum MODALS_MAX_PASSWD_AGE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+MODALS_MAX_PASSWD_AGE_PARMNUM); enum MODALS_MIN_PASSWD_AGE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+MODALS_MIN_PASSWD_AGE_PARMNUM); enum MODALS_FORCE_LOGOFF_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+MODALS_FORCE_LOGOFF_PARMNUM); enum MODALS_PASSWD_HIST_LEN_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+MODALS_PASSWD_HIST_LEN_PARMNUM); enum MODALS_ROLE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+MODALS_ROLE_PARMNUM); enum MODALS_PRIMARY_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+MODALS_PRIMARY_PARMNUM); enum MODALS_DOMAIN_NAME_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+MODALS_DOMAIN_NAME_PARMNUM); enum MODALS_DOMAIN_ID_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+MODALS_DOMAIN_ID_PARMNUM); enum GROUPIDMASK=0x8000; enum GROUP_ALL_PARMNUM=0; enum GROUP_NAME_PARMNUM=1; enum GROUP_COMMENT_PARMNUM=2; enum GROUP_ATTRIBUTES_PARMNUM=3; enum GROUP_ALL_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + GROUP_ALL_PARMNUM; enum GROUP_NAME_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + GROUP_NAME_PARMNUM; enum GROUP_COMMENT_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + GROUP_COMMENT_PARMNUM; enum GROUP_ATTRIBUTES_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + GROUP_ATTRIBUTES_PARMNUM; // GROUP_POSIX_ID_PARMNUM isn't in MinGW or in the Platform SDK docs. //const GROUP_POSIX_ID_INFOLEVEL = PARMNUM_BASE_INFOLEVEL + GROUP_POSIX_ID_PARMNUM; enum LOCALGROUP_NAME_PARMNUM=1; enum LOCALGROUP_COMMENT_PARMNUM=2; enum MAXPERMENTRIES=64; enum ACCESS_NONE=0; enum ACCESS_READ=1; enum ACCESS_WRITE=2; enum ACCESS_CREATE=4; enum ACCESS_EXEC=8; enum ACCESS_DELETE=16; enum ACCESS_ATRIB=32; enum ACCESS_PERM=64; enum ACCESS_ALL = ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE|ACCESS_EXEC|ACCESS_DELETE|ACCESS_ATRIB|ACCESS_PERM; enum ACCESS_GROUP=0x8000; enum ACCESS_AUDIT=1; enum ACCESS_SUCCESS_OPEN=16; enum ACCESS_SUCCESS_WRITE=32; enum ACCESS_SUCCESS_DELETE=64; enum ACCESS_SUCCESS_ACL=128; enum ACCESS_SUCCESS_MASK=240; enum ACCESS_FAIL_OPEN=256; enum ACCESS_FAIL_WRITE=512; enum ACCESS_FAIL_DELETE=1024; enum ACCESS_FAIL_ACL=2048; enum ACCESS_FAIL_MASK=3840; enum ACCESS_FAIL_SHIFT=4; enum ACCESS_RESOURCE_NAME_PARMNUM=1; enum ACCESS_ATTR_PARMNUM=2; enum ACCESS_COUNT_PARMNUM=3; enum ACCESS_ACCESS_LIST_PARMNUM=4; enum ACCESS_RESOURCE_NAME_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+ACCESS_RESOURCE_NAME_PARMNUM); enum ACCESS_ATTR_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+ACCESS_ATTR_PARMNUM); enum ACCESS_COUNT_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+ACCESS_COUNT_PARMNUM); enum ACCESS_ACCESS_LIST_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+ACCESS_ACCESS_LIST_PARMNUM); enum NETLOGON_REPLICATION_NEEDED=1; enum NETLOGON_REPLICATION_IN_PROGRESS=2; enum NETLOGON_FULL_SYNC_REPLICATION=4; enum NETLOGON_REDO_NEEDED=8; struct USER_INFO_0 { LPWSTR usri0_name; } alias USER_INFO_0* PUSER_INFO_0, LPUSER_INFO_0; struct USER_INFO_1{ LPWSTR usri1_name; LPWSTR usri1_password; DWORD usri1_password_age; DWORD usri1_priv; LPWSTR usri1_home_dir; LPWSTR usri1_comment; DWORD usri1_flags; LPWSTR usri1_script_path; } alias USER_INFO_1* PUSER_INFO_1, LPUSER_INFO_1; struct USER_INFO_2{ LPWSTR usri2_name; LPWSTR usri2_password; DWORD usri2_password_age; DWORD usri2_priv; LPWSTR usri2_home_dir; LPWSTR usri2_comment; DWORD usri2_flags; LPWSTR usri2_script_path; DWORD usri2_auth_flags; LPWSTR usri2_full_name; LPWSTR usri2_usr_comment; LPWSTR usri2_parms; LPWSTR usri2_workstations; DWORD usri2_last_logon; DWORD usri2_last_logoff; DWORD usri2_acct_expires; DWORD usri2_max_storage; DWORD usri2_units_per_week; PBYTE usri2_logon_hours; DWORD usri2_bad_pw_count; DWORD usri2_num_logons; LPWSTR usri2_logon_server; DWORD usri2_country_code; DWORD usri2_code_page; } alias USER_INFO_2* PUSER_INFO_2, LPUSER_INFO_2; struct USER_INFO_3{ LPWSTR usri3_name; LPWSTR usri3_password; DWORD usri3_password_age; DWORD usri3_priv; LPWSTR usri3_home_dir; LPWSTR usri3_comment; DWORD usri3_flags; LPWSTR usri3_script_path; DWORD usri3_auth_flags; LPWSTR usri3_full_name; LPWSTR usri3_usr_comment; LPWSTR usri3_parms; LPWSTR usri3_workstations; DWORD usri3_last_logon; DWORD usri3_last_logoff; DWORD usri3_acct_expires; DWORD usri3_max_storage; DWORD usri3_units_per_week; PBYTE usri3_logon_hours; DWORD usri3_bad_pw_count; DWORD usri3_num_logons; LPWSTR usri3_logon_server; DWORD usri3_country_code; DWORD usri3_code_page; DWORD usri3_user_id; DWORD usri3_primary_group_id; LPWSTR usri3_profile; LPWSTR usri3_home_dir_drive; DWORD usri3_password_expired; } alias USER_INFO_3* PUSER_INFO_3, LPUSER_INFO_3; struct USER_INFO_10{ LPWSTR usri10_name; LPWSTR usri10_comment; LPWSTR usri10_usr_comment; LPWSTR usri10_full_name; } alias USER_INFO_10* PUSER_INFO_10, LPUSER_INFO_10; struct USER_INFO_11{ LPWSTR usri11_name; LPWSTR usri11_comment; LPWSTR usri11_usr_comment; LPWSTR usri11_full_name; DWORD usri11_priv; DWORD usri11_auth_flags; DWORD usri11_password_age; LPWSTR usri11_home_dir; LPWSTR usri11_parms; DWORD usri11_last_logon; DWORD usri11_last_logoff; DWORD usri11_bad_pw_count; DWORD usri11_num_logons; LPWSTR usri11_logon_server; DWORD usri11_country_code; LPWSTR usri11_workstations; DWORD usri11_max_storage; DWORD usri11_units_per_week; PBYTE usri11_logon_hours; DWORD usri11_code_page; } alias USER_INFO_11* PUSER_INFO_11, LPUSER_INFO_11; struct USER_INFO_20 { LPWSTR usri20_name; LPWSTR usri20_full_name; LPWSTR usri20_comment; DWORD usri20_flags; DWORD usri20_user_id; } alias USER_INFO_20* PUSER_INFO_20, LPUSER_INFO_20; struct USER_INFO_21 { BYTE[ENCRYPTED_PWLEN] usri21_password; } alias USER_INFO_21* PUSER_INFO_21, LPUSER_INFO_21; struct USER_INFO_22{ LPWSTR usri22_name; BYTE[ENCRYPTED_PWLEN] usri22_password; DWORD usri22_password_age; DWORD usri22_priv; LPWSTR usri22_home_dir; LPWSTR usri22_comment; DWORD usri22_flags; LPWSTR usri22_script_path; DWORD usri22_auth_flags; LPWSTR usri22_full_name; LPWSTR usri22_usr_comment; LPWSTR usri22_parms; LPWSTR usri22_workstations; DWORD usri22_last_logon; DWORD usri22_last_logoff; DWORD usri22_acct_expires; DWORD usri22_max_storage; DWORD usri22_units_per_week; PBYTE usri22_logon_hours; DWORD usri22_bad_pw_count; DWORD usri22_num_logons; LPWSTR usri22_logon_server; DWORD usri22_country_code; DWORD usri22_code_page; } alias USER_INFO_22* PUSER_INFO_22, LPUSER_INFO_22; struct USER_INFO_1003{ LPWSTR usri1003_password; } alias USER_INFO_1003* PUSER_INFO_1003, LPUSER_INFO_1003; struct USER_INFO_1005{ DWORD usri1005_priv; } alias USER_INFO_1005* PUSER_INFO_1005, LPUSER_INFO_1005; struct USER_INFO_1006{ LPWSTR usri1006_home_dir; } alias USER_INFO_1006* PUSER_INFO_1006, LPUSER_INFO_1006; struct USER_INFO_1007{ LPWSTR usri1007_comment; } alias USER_INFO_1007* PUSER_INFO_1007, LPUSER_INFO_1007; struct USER_INFO_1008{ DWORD usri1008_flags; } alias USER_INFO_1008* PUSER_INFO_1008, LPUSER_INFO_1008; struct USER_INFO_1009{ LPWSTR usri1009_script_path; } alias USER_INFO_1009* PUSER_INFO_1009, LPUSER_INFO_1009; struct USER_INFO_1010{ DWORD usri1010_auth_flags; } alias USER_INFO_1010* PUSER_INFO_1010, LPUSER_INFO_1010; struct USER_INFO_1011{ LPWSTR usri1011_full_name; } alias USER_INFO_1011* PUSER_INFO_1011, LPUSER_INFO_1011; struct USER_INFO_1012{ LPWSTR usri1012_usr_comment; } alias USER_INFO_1012* PUSER_INFO_1012, LPUSER_INFO_1012; struct USER_INFO_1013{ LPWSTR usri1013_parms; } alias USER_INFO_1013* PUSER_INFO_1013, LPUSER_INFO_1013; struct USER_INFO_1014{ LPWSTR usri1014_workstations; } alias USER_INFO_1014* PUSER_INFO_1014, LPUSER_INFO_1014; struct USER_INFO_1017{ DWORD usri1017_acct_expires; } alias USER_INFO_1017* PUSER_INFO_1017, LPUSER_INFO_1017; struct USER_INFO_1018{ DWORD usri1018_max_storage; } alias USER_INFO_1018* PUSER_INFO_1018, LPUSER_INFO_1018; struct USER_INFO_1020{ DWORD usri1020_units_per_week; PBYTE usri1020_logon_hours; } alias USER_INFO_1020* PUSER_INFO_1020, LPUSER_INFO_1020; struct USER_INFO_1023{ LPWSTR usri1023_logon_server; } alias USER_INFO_1023* PUSER_INFO_1023, LPUSER_INFO_1023; struct USER_INFO_1024{ DWORD usri1024_country_code; } alias USER_INFO_1024* PUSER_INFO_1024, LPUSER_INFO_1024; struct USER_INFO_1025{ DWORD usri1025_code_page; } alias USER_INFO_1025* PUSER_INFO_1025, LPUSER_INFO_1025; struct USER_INFO_1051{ DWORD usri1051_primary_group_id; } alias USER_INFO_1051* PUSER_INFO_1051, LPUSER_INFO_1051; struct USER_INFO_1052{ LPWSTR usri1052_profile; } alias USER_INFO_1052* PUSER_INFO_1052, LPUSER_INFO_1052; struct USER_INFO_1053{ LPWSTR usri1053_home_dir_drive; } alias USER_INFO_1053* PUSER_INFO_1053, LPUSER_INFO_1053; struct USER_MODALS_INFO_0{ DWORD usrmod0_min_passwd_len; DWORD usrmod0_max_passwd_age; DWORD usrmod0_min_passwd_age; DWORD usrmod0_force_logoff; DWORD usrmod0_password_hist_len; } alias USER_MODALS_INFO_0* PUSER_MODALS_INFO_0, LPUSER_MODALS_INFO_0; struct USER_MODALS_INFO_1{ DWORD usrmod1_role; LPWSTR usrmod1_primary; } alias USER_MODALS_INFO_1* PUSER_MODALS_INFO_1, LPUSER_MODALS_INFO_1; struct USER_MODALS_INFO_2{ LPWSTR usrmod2_domain_name; PSID usrmod2_domain_id; } alias USER_MODALS_INFO_2* PUSER_MODALS_INFO_2, LPUSER_MODALS_INFO_2; struct USER_MODALS_INFO_3{ DWORD usrmod3_lockout_duration; DWORD usrmod3_lockout_observation_window; DWORD usrmod3_lockout_threshold; } alias USER_MODALS_INFO_3* PUSER_MODALS_INFO_3, LPUSER_MODALS_INFO_3; struct USER_MODALS_INFO_1001{ DWORD usrmod1001_min_passwd_len; } alias USER_MODALS_INFO_1001* PUSER_MODALS_INFO_1001, LPUSER_MODALS_INFO_1001; struct USER_MODALS_INFO_1002{ DWORD usrmod1002_max_passwd_age; } alias USER_MODALS_INFO_1002* PUSER_MODALS_INFO_1002, LPUSER_MODALS_INFO_1002; struct USER_MODALS_INFO_1003{ DWORD usrmod1003_min_passwd_age; } alias USER_MODALS_INFO_1003* PUSER_MODALS_INFO_1003, LPUSER_MODALS_INFO_1003; struct USER_MODALS_INFO_1004{ DWORD usrmod1004_force_logoff; } alias USER_MODALS_INFO_1004* PUSER_MODALS_INFO_1004, LPUSER_MODALS_INFO_1004; struct USER_MODALS_INFO_1005{ DWORD usrmod1005_password_hist_len; } alias USER_MODALS_INFO_1005* PUSER_MODALS_INFO_1005, LPUSER_MODALS_INFO_1005; struct USER_MODALS_INFO_1006{ DWORD usrmod1006_role; } alias USER_MODALS_INFO_1006* PUSER_MODALS_INFO_1006, LPUSER_MODALS_INFO_1006; struct USER_MODALS_INFO_1007{ LPWSTR usrmod1007_primary; } alias USER_MODALS_INFO_1007* PUSER_MODALS_INFO_1007, LPUSER_MODALS_INFO_1007; struct GROUP_INFO_0{ LPWSTR grpi0_name; } alias GROUP_INFO_0* PGROUP_INFO_0, LPGROUP_INFO_0; struct GROUP_INFO_1{ LPWSTR grpi1_name; LPWSTR grpi1_comment; } alias GROUP_INFO_1* PGROUP_INFO_1, LPGROUP_INFO_1; struct GROUP_INFO_2{ LPWSTR grpi2_name; LPWSTR grpi2_comment; DWORD grpi2_group_id; DWORD grpi2_attributes; } alias GROUP_INFO_2* PGROUP_INFO_2; struct GROUP_INFO_1002{ LPWSTR grpi1002_comment; } alias GROUP_INFO_1002* PGROUP_INFO_1002, LPGROUP_INFO_1002; struct GROUP_INFO_1005{ DWORD grpi1005_attributes; } alias GROUP_INFO_1005* PGROUP_INFO_1005, LPGROUP_INFO_1005; struct GROUP_USERS_INFO_0{ LPWSTR grui0_name; } alias GROUP_USERS_INFO_0* PGROUP_USERS_INFO_0, LPGROUP_USERS_INFO_0; struct GROUP_USERS_INFO_1{ LPWSTR grui1_name; DWORD grui1_attributes; } alias GROUP_USERS_INFO_1* PGROUP_USERS_INFO_1, LPGROUP_USERS_INFO_1; struct LOCALGROUP_INFO_0{ LPWSTR lgrpi0_name; } alias LOCALGROUP_INFO_0* PLOCALGROUP_INFO_0, LPLOCALGROUP_INFO_0; struct LOCALGROUP_INFO_1{ LPWSTR lgrpi1_name; LPWSTR lgrpi1_comment; } alias LOCALGROUP_INFO_1* PLOCALGROUP_INFO_1, LPLOCALGROUP_INFO_1; struct LOCALGROUP_INFO_1002{ LPWSTR lgrpi1002_comment; } alias LOCALGROUP_INFO_1002* PLOCALGROUP_INFO_1002, LPLOCALGROUP_INFO_1002; struct LOCALGROUP_MEMBERS_INFO_0{ PSID lgrmi0_sid; } alias LOCALGROUP_MEMBERS_INFO_0* PLOCALGROUP_MEMBERS_INFO_0, LPLOCALGROUP_MEMBERS_INFO_0; struct LOCALGROUP_MEMBERS_INFO_1{ PSID lgrmi1_sid; SID_NAME_USE lgrmi1_sidusage; LPWSTR lgrmi1_name; } alias LOCALGROUP_MEMBERS_INFO_1* PLOCALGROUP_MEMBERS_INFO_1, LPLOCALGROUP_MEMBERS_INFO_1; struct LOCALGROUP_MEMBERS_INFO_2{ PSID lgrmi2_sid; SID_NAME_USE lgrmi2_sidusage; LPWSTR lgrmi2_domainandname; } alias LOCALGROUP_MEMBERS_INFO_2* PLOCALGROUP_MEMBERS_INFO_2, LPLOCALGROUP_MEMBERS_INFO_2; struct LOCALGROUP_MEMBERS_INFO_3{ LPWSTR lgrmi3_domainandname; } alias LOCALGROUP_MEMBERS_INFO_3* PLOCALGROUP_MEMBERS_INFO_3, LPLOCALGROUP_MEMBERS_INFO_3; struct LOCALGROUP_USERS_INFO_0{ LPWSTR lgrui0_name; } alias LOCALGROUP_USERS_INFO_0* PLOCALGROUP_USERS_INFO_0, LPLOCALGROUP_USERS_INFO_0; struct NET_DISPLAY_USER{ LPWSTR usri1_name; LPWSTR usri1_comment; DWORD usri1_flags; LPWSTR usri1_full_name; DWORD usri1_user_id; DWORD usri1_next_index; } alias NET_DISPLAY_USER* PNET_DISPLAY_USER; struct NET_DISPLAY_MACHINE{ LPWSTR usri2_name; LPWSTR usri2_comment; DWORD usri2_flags; DWORD usri2_user_id; DWORD usri2_next_index; } alias NET_DISPLAY_MACHINE* PNET_DISPLAY_MACHINE; struct NET_DISPLAY_GROUP{ LPWSTR grpi3_name; LPWSTR grpi3_comment; DWORD grpi3_group_id; DWORD grpi3_attributes; DWORD grpi3_next_index; } alias NET_DISPLAY_GROUP* PNET_DISPLAY_GROUP; struct ACCESS_INFO_0{ LPTSTR acc0_resource_name; } alias ACCESS_INFO_0* PACCESS_INFO_0, LPACCESS_INFO_0; struct ACCESS_INFO_1{ LPTSTR acc1_resource_name; DWORD acc1_attr; DWORD acc1_count; } alias ACCESS_INFO_1* PACCESS_INFO_1, LPACCESS_INFO_1; struct ACCESS_INFO_1002{ DWORD acc1002_attr; } alias ACCESS_INFO_1002* PACCESS_INFO_1002, LPACCESS_INFO_1002; struct ACCESS_LIST{ LPTSTR acl_ugname; DWORD acl_access; } alias ACCESS_LIST* PACCESS_LIST, LPACCESS_LIST; struct NETLOGON_INFO_1{ DWORD netlog1_flags; NET_API_STATUS netlog1_pdc_connection_status; } alias NETLOGON_INFO_1* PNETLOGON_INFO_1; struct NETLOGON_INFO_2{ DWORD netlog2_flags; NET_API_STATUS netlog2_pdc_connection_status; LPWSTR netlog2_trusted_dc_name; NET_API_STATUS netlog2_tc_connection_status; } alias NETLOGON_INFO_2* PNETLOGON_INFO_2; struct NETLOGON_INFO_3{ DWORD netlog3_flags; DWORD netlog3_logon_attempts; DWORD netlog3_reserved1; DWORD netlog3_reserved2; DWORD netlog3_reserved3; DWORD netlog3_reserved4; DWORD netlog3_reserved5; } alias NETLOGON_INFO_3* PNETLOGON_INFO_3; extern (Windows) { deprecated { /* These are obsolete */ NET_API_STATUS NetAccessAdd(LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetAccessEnum(LPCWSTR,LPCWSTR,DWORD,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetAccessGetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE*); NET_API_STATUS NetAccessSetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetAccessDel(LPCWSTR,LPCWSTR); NET_API_STATUS NetAccessGetUserPerms(LPCWSTR,LPCWSTR,LPCWSTR,PDWORD); } NET_API_STATUS NetUserAdd(LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetUserEnum(LPCWSTR,DWORD,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetUserGetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE*); NET_API_STATUS NetUserSetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetUserDel(LPCWSTR,LPCWSTR); NET_API_STATUS NetUserGetGroups(LPCWSTR,LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD); NET_API_STATUS NetUserSetGroups(LPCWSTR,LPCWSTR,DWORD,PBYTE,DWORD); NET_API_STATUS NetUserGetLocalGroups(LPCWSTR,LPCWSTR,DWORD,DWORD,PBYTE*,DWORD,PDWORD,PDWORD); NET_API_STATUS NetUserModalsGet(LPCWSTR,DWORD,PBYTE*); NET_API_STATUS NetUserModalsSet(LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetUserChangePassword(LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR); NET_API_STATUS NetGroupAdd(LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetGroupAddUser(LPCWSTR,LPCWSTR,LPCWSTR); NET_API_STATUS NetGroupEnum(LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetGroupGetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE*); NET_API_STATUS NetGroupSetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetGroupDel(LPCWSTR,LPCWSTR); NET_API_STATUS NetGroupDelUser(LPCWSTR,LPCWSTR,LPCWSTR); NET_API_STATUS NetGroupGetUsers(LPCWSTR,LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetGroupSetUsers(LPCWSTR,LPCWSTR,DWORD,PBYTE,DWORD); NET_API_STATUS NetLocalGroupAdd(LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetLocalGroupAddMember(LPCWSTR,LPCWSTR,PSID); NET_API_STATUS NetLocalGroupEnum(LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetLocalGroupGetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE*); NET_API_STATUS NetLocalGroupSetInfo(LPCWSTR,LPCWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetLocalGroupDel(LPCWSTR,LPCWSTR); NET_API_STATUS NetLocalGroupDelMember(LPCWSTR,LPCWSTR,PSID); NET_API_STATUS NetLocalGroupGetMembers(LPCWSTR,LPCWSTR,DWORD,PBYTE*,DWORD, PDWORD,PDWORD,PDWORD); NET_API_STATUS NetLocalGroupSetMembers(LPCWSTR,LPCWSTR,DWORD,PBYTE,DWORD); NET_API_STATUS NetLocalGroupAddMembers(LPCWSTR,LPCWSTR,DWORD,PBYTE,DWORD); NET_API_STATUS NetLocalGroupDelMembers(LPCWSTR,LPCWSTR,DWORD,PBYTE,DWORD); NET_API_STATUS NetQueryDisplayInformation(LPCWSTR,DWORD,DWORD,DWORD,DWORD,PDWORD,PVOID*); NET_API_STATUS NetGetDisplayInformationIndex(LPCWSTR,DWORD,LPCWSTR,PDWORD); NET_API_STATUS NetGetDCName(LPCWSTR,LPCWSTR,PBYTE*); NET_API_STATUS NetGetAnyDCName(LPCWSTR,LPCWSTR,PBYTE*); NET_API_STATUS I_NetLogonControl(LPCWSTR,DWORD,DWORD,PBYTE*); NET_API_STATUS I_NetLogonControl2(LPCWSTR,DWORD,DWORD,PBYTE,PBYTE*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmaudit.d0000664000175000017500000001536212776214756023325 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmaudit.d) */ // COMMENT: This file may be deprecated. module core.sys.windows.lmaudit; version (Windows): private import core.sys.windows.lmcons, core.sys.windows.windef; enum LOGFLAGS_FORWARD = 0; enum LOGFLAGS_BACKWARD = 1; enum LOGFLAGS_SEEK = 2; enum ACTION_LOCKOUT = 0; enum ACTION_ADMINUNLOCK = 1; enum AE_GUEST=0; enum AE_USER=1; enum AE_ADMIN=2; enum AE_NORMAL=0; enum AE_USERLIMIT=0; enum AE_GENERAL=0; enum AE_ERROR=1; enum AE_SESSDIS=1; enum AE_BADPW=1; enum AE_AUTODIS=2; enum AE_UNSHARE=2; enum AE_ADMINPRIVREQD=2; enum AE_ADMINDIS=3; enum AE_NOACCESSPERM=3; enum AE_ACCRESTRICT=4; enum AE_NORMAL_CLOSE=0; enum AE_SES_CLOSE=1; enum AE_ADMIN_CLOSE=2; enum AE_LIM_UNKNOWN=0; enum AE_LIM_LOGONHOURS=1; enum AE_LIM_EXPIRED=2; enum AE_LIM_INVAL_WKSTA=3; enum AE_LIM_DISABLED=4; enum AE_LIM_DELETED=5; enum AE_MOD=0; enum AE_DELETE=1; enum AE_ADD=2; enum AE_UAS_USER = 0; enum AE_UAS_GROUP = 1; enum AE_UAS_MODALS = 2; enum SVAUD_SERVICE = 1; enum SVAUD_GOODSESSLOGON = 6; enum SVAUD_BADSESSLOGON = 24; enum SVAUD_SESSLOGON = SVAUD_GOODSESSLOGON|SVAUD_BADSESSLOGON; enum SVAUD_GOODNETLOGON = 96; enum SVAUD_BADNETLOGON = 384; enum SVAUD_NETLOGON = SVAUD_GOODNETLOGON|SVAUD_BADNETLOGON; enum SVAUD_LOGON = SVAUD_NETLOGON|SVAUD_SESSLOGON; enum SVAUD_GOODUSE = 0x600; enum SVAUD_BADUSE = 0x1800; enum SVAUD_USE = SVAUD_GOODUSE|SVAUD_BADUSE; enum SVAUD_USERLIST = 8192; enum SVAUD_PERMISSIONS = 16384; enum SVAUD_RESOURCE = 32768; enum SVAUD_LOGONLIM = 65536; enum AA_AUDIT_ALL=1; enum AA_A_OWNER=4; enum AA_CLOSE=8; enum AA_S_OPEN=16; enum AA_S_WRITE=32; enum AA_S_CREATE=32; enum AA_S_DELETE=64; enum AA_S_ACL=128; enum AA_S_ALL=253; enum AA_F_OPEN=256; enum AA_F_WRITE=512; enum AA_F_CREATE=512; enum AA_F_DELETE=1024; enum AA_F_ACL=2048; enum AA_F_ALL = AA_F_OPEN|AA_F_WRITE|AA_F_DELETE|AA_F_ACL; enum AA_A_OPEN=2048; enum AA_A_WRITE=4096; enum AA_A_CREATE=8192; enum AA_A_DELETE=16384; enum AA_A_ACL=32768; enum AA_A_ALL = AA_F_OPEN|AA_F_WRITE|AA_F_DELETE|AA_F_ACL; struct AUDIT_ENTRY{ DWORD ae_len; DWORD ae_reserved; DWORD ae_time; DWORD ae_type; DWORD ae_data_offset; DWORD ae_data_size; } alias AUDIT_ENTRY* PAUDIT_ENTRY, LPAUDIT_ENTRY; struct HLOG{ DWORD time; DWORD last_flags; DWORD offset; DWORD rec_offset; } alias HLOG* PHLOG, LPHLOG; struct AE_SRVSTATUS{ DWORD ae_sv_status; } alias AE_SRVSTATUS* PAE_SRVSTATUS, LPAE_SRVSTATUS; struct AE_SESSLOGON{ DWORD ae_so_compname; DWORD ae_so_username; DWORD ae_so_privilege; } alias AE_SESSLOGON* PAE_SESSLOGON, LPAE_SESSLOGON; struct AE_SESSLOGOFF{ DWORD ae_sf_compname; DWORD ae_sf_username; DWORD ae_sf_reason; } alias AE_SESSLOGOFF* PAE_SESSLOGOFF, LPAE_SESSLOGOFF; struct AE_SESSPWERR{ DWORD ae_sp_compname; DWORD ae_sp_username; } alias AE_SESSPWERR* PAE_SESSPWERR, LPAE_SESSPWERR; struct AE_CONNSTART{ DWORD ae_ct_compname; DWORD ae_ct_username; DWORD ae_ct_netname; DWORD ae_ct_connid; } alias AE_CONNSTART* PAE_CONNSTART, LPAE_CONNSTART; struct AE_CONNSTOP{ DWORD ae_cp_compname; DWORD ae_cp_username; DWORD ae_cp_netname; DWORD ae_cp_connid; DWORD ae_cp_reason; } alias AE_CONNSTOP* PAE_CONNSTOP, LPAE_CONNSTOP; struct AE_CONNREJ{ DWORD ae_cr_compname; DWORD ae_cr_username; DWORD ae_cr_netname; DWORD ae_cr_reason; } alias AE_CONNREJ* PAE_CONNREJ, LPAE_CONNREJ; struct AE_RESACCESS{ DWORD ae_ra_compname; DWORD ae_ra_username; DWORD ae_ra_resname; DWORD ae_ra_operation; DWORD ae_ra_returncode; DWORD ae_ra_restype; DWORD ae_ra_fileid; } alias AE_RESACCESS* PAE_RESACCESS, LPAE_RESACCESS; struct AE_RESACCESSREJ{ DWORD ae_rr_compname; DWORD ae_rr_username; DWORD ae_rr_resname; DWORD ae_rr_operation; } alias AE_RESACCESSREJ* PAE_RESACCESSREJ, LPAE_RESACCESSREJ; struct AE_CLOSEFILE{ DWORD ae_cf_compname; DWORD ae_cf_username; DWORD ae_cf_resname; DWORD ae_cf_fileid; DWORD ae_cf_duration; DWORD ae_cf_reason; } alias AE_CLOSEFILE* PAE_CLOSEFILE, LPAE_CLOSEFILE; struct AE_SERVICESTAT{ DWORD ae_ss_compname; DWORD ae_ss_username; DWORD ae_ss_svcname; DWORD ae_ss_status; DWORD ae_ss_code; DWORD ae_ss_text; DWORD ae_ss_returnval; } alias AE_SERVICESTAT* PAE_SERVICESTAT, LPAE_SERVICESTAT; struct AE_ACLMOD{ DWORD ae_am_compname; DWORD ae_am_username; DWORD ae_am_resname; DWORD ae_am_action; DWORD ae_am_datalen; } alias AE_ACLMOD* PAE_ACLMOD, LPAE_ACLMOD; struct AE_UASMOD{ DWORD ae_um_compname; DWORD ae_um_username; DWORD ae_um_resname; DWORD ae_um_rectype; DWORD ae_um_action; DWORD ae_um_datalen; } alias AE_UASMOD* PAE_UASMOD, LPAE_UASMOD; struct AE_NETLOGON{ DWORD ae_no_compname; DWORD ae_no_username; DWORD ae_no_privilege; DWORD ae_no_authflags; } alias AE_NETLOGON* PAE_NETLOGON, LPAE_NETLOGON; struct AE_NETLOGOFF{ DWORD ae_nf_compname; DWORD ae_nf_username; DWORD ae_nf_reserved1; DWORD ae_nf_reserved2; } alias AE_NETLOGOFF* PAE_NETLOGOFF, LPAE_NETLOGOFF; struct AE_ACCLIM{ DWORD ae_al_compname; DWORD ae_al_username; DWORD ae_al_resname; DWORD ae_al_limit; } alias AE_ACCLIM* PAE_ACCLIM, LPAE_ACCLIM; struct AE_LOCKOUT{ DWORD ae_lk_compname; DWORD ae_lk_username; DWORD ae_lk_action; DWORD ae_lk_bad_pw_count; } alias AE_LOCKOUT* PAE_LOCKOUT, LPAE_LOCKOUT; struct AE_GENERIC{ DWORD ae_ge_msgfile; DWORD ae_ge_msgnum; DWORD ae_ge_params; DWORD ae_ge_param1; DWORD ae_ge_param2; DWORD ae_ge_param3; DWORD ae_ge_param4; DWORD ae_ge_param5; DWORD ae_ge_param6; DWORD ae_ge_param7; DWORD ae_ge_param8; DWORD ae_ge_param9; } alias AE_GENERIC* PAE_GENERIC, LPAE_GENERIC; extern (Windows) { deprecated { NET_API_STATUS NetAuditClear(LPCWSTR,LPCWSTR,LPCWSTR); NET_API_STATUS NetAuditRead(LPTSTR,LPTSTR,LPHLOG,DWORD,PDWORD,DWORD,DWORD,PBYTE*,DWORD,PDWORD,PDWORD); NET_API_STATUS NetAuditWrite(DWORD,PBYTE,DWORD,LPTSTR,PBYTE); } } /+ /* MinGW: These conflict with struct typedefs, why? */ enum AE_SRVSTATUS=0; enum AE_SESSLOGON=1; enum AE_SESSLOGOFF=2; enum AE_SESSPWERR=3; enum AE_CONNSTART=4; enum AE_CONNSTOP=5; enum AE_CONNREJ=6; enum AE_RESACCESS=7; enum AE_RESACCESSREJ=8; enum AE_CLOSEFILE=9; enum AE_SERVICESTAT=11; enum AE_ACLMOD=12; enum AE_UASMOD=13; enum AE_NETLOGON=14; enum AE_NETLOGOFF=15; enum AE_NETLOGDENIED=16; enum AE_ACCLIMITEXCD=17; enum AE_RESACCESS2=18; enum AE_ACLMODFAIL=19; enum AE_LOCKOUT=20; enum AE_GENERIC_TYPE=21; enum AE_SRVSTART=0; enum AE_SRVPAUSED=1; enum AE_SRVCONT=2; enum AE_SRVSTOP=3; +/ ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ole.d0000664000175000017500000003023012776214756022434 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ole.d) */ module core.sys.windows.ole; version (Windows): pragma(lib, "ole32"); private import core.sys.windows.windef, core.sys.windows.wingdi, core.sys.windows.uuid; alias LPCSTR OLE_LPCSTR; /+#define LRESULT LONG #define HGLOBAL HANDLE+/ enum { OT_LINK = 1, OT_EMBEDDED, OT_STATIC } enum OLEVERB_PRIMARY = 0; enum OF_SET = 1; enum OF_GET = 2; enum OF_HANDLER = 4; struct OLETARGETDEVICE { USHORT otdDeviceNameOffset; USHORT otdDriverNameOffset; USHORT otdPortNameOffset; USHORT otdExtDevmodeOffset; USHORT otdExtDevmodeSize; USHORT otdEnvironmentOffset; USHORT otdEnvironmentSize; BYTE _otdData; BYTE* otdData() return { return &_otdData; } } alias OLETARGETDEVICE* LPOLETARGETDEVICE; enum OLESTATUS { OLE_OK, OLE_WAIT_FOR_RELEASE, OLE_BUSY, OLE_ERROR_PROTECT_ONLY, OLE_ERROR_MEMORY, OLE_ERROR_STREAM, OLE_ERROR_STATIC, OLE_ERROR_BLANK, OLE_ERROR_DRAW, OLE_ERROR_METAFILE, OLE_ERROR_ABORT, OLE_ERROR_CLIPBOARD, OLE_ERROR_FORMAT, OLE_ERROR_OBJECT, OLE_ERROR_OPTION, OLE_ERROR_PROTOCOL, OLE_ERROR_ADDRESS, OLE_ERROR_NOT_EQUAL, OLE_ERROR_HANDLE, OLE_ERROR_GENERIC, OLE_ERROR_CLASS, OLE_ERROR_SYNTAX, OLE_ERROR_DATATYPE, OLE_ERROR_PALETTE, OLE_ERROR_NOT_LINK, OLE_ERROR_NOT_EMPTY, OLE_ERROR_SIZE, OLE_ERROR_DRIVE, OLE_ERROR_NETWORK, OLE_ERROR_NAME, OLE_ERROR_TEMPLATE, OLE_ERROR_NEW, OLE_ERROR_EDIT, OLE_ERROR_OPEN, OLE_ERROR_NOT_OPEN, OLE_ERROR_LAUNCH, OLE_ERROR_COMM, OLE_ERROR_TERMINATE, OLE_ERROR_COMMAND, OLE_ERROR_SHOW, OLE_ERROR_DOVERB, OLE_ERROR_ADVISE_NATIVE, OLE_ERROR_ADVISE_PICT, OLE_ERROR_ADVISE_RENAME, OLE_ERROR_POKE_NATIVE, OLE_ERROR_REQUEST_NATIVE, OLE_ERROR_REQUEST_PICT, OLE_ERROR_SERVER_BLOCKED, OLE_ERROR_REGISTRATION, OLE_ERROR_ALREADY_REGISTERED, OLE_ERROR_TASK, OLE_ERROR_OUTOFDATE, OLE_ERROR_CANT_UPDATE_CLIENT, OLE_ERROR_UPDATE, OLE_ERROR_SETDATA_FORMAT, OLE_ERROR_STATIC_FROM_OTHER_OS, OLE_ERROR_FILE_VER, OLE_WARN_DELETE_DATA = 1000 } enum OLE_NOTIFICATION { OLE_CHANGED, OLE_SAVED, OLE_CLOSED, OLE_RENAMED, OLE_QUERY_PAINT, OLE_RELEASE, OLE_QUERY_RETRY } enum OLE_RELEASE_METHOD { OLE_NONE, OLE_DELETE, OLE_LNKPASTE, OLE_EMBPASTE, OLE_SHOW, OLE_RUN, OLE_ACTIVATE, OLE_UPDATE, OLE_CLOSE, OLE_RECONNECT, OLE_SETUPDATEOPTIONS, OLE_SERVERUNLAUNCH, OLE_LOADFROMSTREAM, OLE_SETDATA, OLE_REQUESTDATA, OLE_OTHER, OLE_CREATE, OLE_CREATEFROMTEMPLATE, OLE_CREATELINKFROMFILE, OLE_COPYFROMLNK, OLE_CREATEFROMFILE, OLE_CREATEINVISIBLE } enum OLEOPT_RENDER { olerender_none, olerender_draw, olerender_format } alias WORD OLECLIPFORMAT; enum OLEOPT_UPDATE { oleupdate_always, oleupdate_onsave, oleupdate_oncall, // #ifdef OLE_INTERNAL oleupdate_onclose // #endif } mixin DECLARE_HANDLE!("HOBJECT"); alias LONG LHSERVER, LHCLIENTDOC, LHSERVERDOC; struct OLEOBJECTVTBL { extern (Windows) { void* function(LPOLEOBJECT, OLE_LPCSTR) QueryProtocol; OLESTATUS function(LPOLEOBJECT) Release; OLESTATUS function(LPOLEOBJECT, BOOL) Show; OLESTATUS function(LPOLEOBJECT, UINT, BOOL, BOOL) DoVerb; OLESTATUS function(LPOLEOBJECT, OLECLIPFORMAT, HANDLE*) GetData; OLESTATUS function(LPOLEOBJECT, OLECLIPFORMAT, HANDLE) SetData; OLESTATUS function(LPOLEOBJECT, HGLOBAL) SetTargetDevice; OLESTATUS function(LPOLEOBJECT, RECT*) SetBounds; OLECLIPFORMAT function(LPOLEOBJECT, OLECLIPFORMAT) EnumFormats; OLESTATUS function(LPOLEOBJECT, LOGPALETTE*) SetColorScheme; //#ifndef SERVERONLY OLESTATUS function(LPOLEOBJECT) Delete; OLESTATUS function(LPOLEOBJECT, OLE_LPCSTR, OLE_LPCSTR) SetHostNames; OLESTATUS function(LPOLEOBJECT, LPOLESTREAM) SaveToStream; OLESTATUS function(LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT*) Clone; OLESTATUS function(LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT*) CopyFromLink; OLESTATUS function(LPOLEOBJECT, LPOLEOBJECT) Equal; OLESTATUS function(LPOLEOBJECT) CopyToClipboard; OLESTATUS function(LPOLEOBJECT, HDC, RECT*, RECT*, HDC) Draw; OLESTATUS function(LPOLEOBJECT, UINT, BOOL, BOOL, HWND, RECT*) Activate; OLESTATUS function(LPOLEOBJECT, HGLOBAL, UINT) Execute; OLESTATUS function(LPOLEOBJECT) Close; OLESTATUS function(LPOLEOBJECT) Update; OLESTATUS function(LPOLEOBJECT) Reconnect; OLESTATUS function(LPOLEOBJECT, OLE_LPCSTR, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT*) ObjectConvert; OLESTATUS function(LPOLEOBJECT, OLEOPT_UPDATE*) GetLinkUpdateOptions; OLESTATUS function(LPOLEOBJECT, OLEOPT_UPDATE) SetLinkUpdateOptions; OLESTATUS function(LPOLEOBJECT, OLE_LPCSTR) Rename; OLESTATUS function(LPOLEOBJECT, LPSTR, UINT*) QueryName; OLESTATUS function(LPOLEOBJECT, LONG*) QueryType; OLESTATUS function(LPOLEOBJECT, RECT*) QueryBounds; OLESTATUS function(LPOLEOBJECT, DWORD*) QuerySize; OLESTATUS function(LPOLEOBJECT) QueryOpen; OLESTATUS function(LPOLEOBJECT) QueryOutOfDate; OLESTATUS function(LPOLEOBJECT) QueryReleaseStatus; OLESTATUS function(LPOLEOBJECT) QueryReleaseError; OLE_RELEASE_METHOD function(LPOLEOBJECT) QueryReleaseMethod; OLESTATUS function(LPOLEOBJECT, OLECLIPFORMAT) RequestData; OLESTATUS function(LPOLEOBJECT, UINT, LONG*) ObjectLong; OLESTATUS function(LPOLEOBJECT, HANDLE, LPOLECLIENT, BOOL) ChangeData; //#endif } } alias OLEOBJECTVTBL* LPOLEOBJECTVTBL; //#ifndef OLE_INTERNAL struct OLEOBJECT { LPOLEOBJECTVTBL lpvtbl; } alias OLEOBJECT* LPOLEOBJECT; //#endif struct OLECLIENTVTBL { int function(LPOLECLIENT, OLE_NOTIFICATION, LPOLEOBJECT) CallBack; } alias OLECLIENTVTBL* LPOLECLIENTVTBL; struct OLECLIENT { LPOLECLIENTVTBL lpvtbl; } alias OLECLIENT* LPOLECLIENT; struct OLESTREAMVTBL { DWORD function(LPOLESTREAM, void*, DWORD) Get; DWORD function(LPOLESTREAM, void*, DWORD) Put; } alias OLESTREAMVTBL* LPOLESTREAMVTBL; struct OLESTREAM { LPOLESTREAMVTBL lpstbl; } alias OLESTREAM* LPOLESTREAM; enum OLE_SERVER_USE { OLE_SERVER_MULTI, OLE_SERVER_SINGLE } struct OLESERVERVTBL { OLESTATUS function(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, LPOLESERVERDOC*) Open; OLESTATUS function(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC*) Create; OLESTATUS function(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC*) CreateFromTemplate; OLESTATUS function(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC*) Edit; OLESTATUS function(LPOLESERVER) Exit; OLESTATUS function(LPOLESERVER) Release; OLESTATUS function(LPOLESERVER, HGLOBAL) Execute; } alias TypeDef!(OLESERVERVTBL*) LPOLESERVERVTBL; struct OLESERVER { LPOLESERVERVTBL lpvtbl; } alias OLESERVER* LPOLESERVER; struct OLESERVERDOCVTBL { OLESTATUS function(LPOLESERVERDOC) Save; OLESTATUS function(LPOLESERVERDOC) Close; OLESTATUS function(LPOLESERVERDOC, OLE_LPCSTR, OLE_LPCSTR) SetHostNames; OLESTATUS function(LPOLESERVERDOC, RECT*) SetDocDimensions; OLESTATUS function(LPOLESERVERDOC, OLE_LPCSTR, LPOLEOBJECT*, LPOLECLIENT) GetObject; OLESTATUS function(LPOLESERVERDOC) Release; OLESTATUS function(LPOLESERVERDOC, LOGPALETTE*) SetColorScheme; OLESTATUS function(LPOLESERVERDOC, HGLOBAL) Execute; } alias OLESERVERDOCVTBL* LPOLESERVERDOCVTBL; struct OLESERVERDOC { LPOLESERVERDOCVTBL lpvtbl; } alias OLESERVERDOC* LPOLESERVERDOC; extern (Windows) { OLESTATUS OleDelete(LPOLEOBJECT); OLESTATUS OleRelease(LPOLEOBJECT); OLESTATUS OleSaveToStream(LPOLEOBJECT, LPOLESTREAM); OLESTATUS OleEqual(LPOLEOBJECT, LPOLEOBJECT); OLESTATUS OleCopyToClipboard(LPOLEOBJECT); OLESTATUS OleSetHostNames(LPOLEOBJECT, LPCSTR, LPCSTR); OLESTATUS OleSetTargetDevice(LPOLEOBJECT, HGLOBAL); OLESTATUS OleSetBounds(LPOLEOBJECT, LPCRECT); OLESTATUS OleSetColorScheme(LPOLEOBJECT, const(LOGPALETTE)*); OLESTATUS OleQueryBounds(LPOLEOBJECT, RECT*); OLESTATUS OleQuerySize(LPOLEOBJECT, DWORD*); OLESTATUS OleDraw(LPOLEOBJECT, HDC, LPCRECT, LPCRECT, HDC); OLESTATUS OleQueryOpen(LPOLEOBJECT); OLESTATUS OleActivate(LPOLEOBJECT, UINT, BOOL, BOOL, HWND, LPCRECT); OLESTATUS OleExecute(LPOLEOBJECT, HGLOBAL, UINT); OLESTATUS OleClose(LPOLEOBJECT); OLESTATUS OleUpdate(LPOLEOBJECT); OLESTATUS OleReconnect(LPOLEOBJECT); OLESTATUS OleGetLinkUpdateOptions(LPOLEOBJECT, OLEOPT_UPDATE*); OLESTATUS OleSetLinkUpdateOptions(LPOLEOBJECT, OLEOPT_UPDATE); void* OleQueryProtocol(LPOLEOBJECT, LPCSTR); OLESTATUS OleQueryReleaseStatus(LPOLEOBJECT); OLESTATUS OleQueryReleaseError(LPOLEOBJECT); OLE_RELEASE_METHOD OleQueryReleaseMethod(LPOLEOBJECT); OLESTATUS OleQueryType(LPOLEOBJECT, LONG*); DWORD OleQueryClientVersion(); DWORD OleQueryServerVersion(); OLECLIPFORMAT OleEnumFormats(LPOLEOBJECT, OLECLIPFORMAT); OLESTATUS OleGetData(LPOLEOBJECT, OLECLIPFORMAT, HANDLE*); OLESTATUS OleSetData(LPOLEOBJECT, OLECLIPFORMAT, HANDLE); OLESTATUS OleQueryOutOfDate(LPOLEOBJECT); OLESTATUS OleRequestData(LPOLEOBJECT, OLECLIPFORMAT); OLESTATUS OleQueryLinkFromClip(LPCSTR, OLEOPT_RENDER, OLECLIPFORMAT); OLESTATUS OleQueryCreateFromClip(LPCSTR, OLEOPT_RENDER, OLECLIPFORMAT); OLESTATUS OleCreateFromClip(LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*, OLEOPT_RENDER, OLECLIPFORMAT); OLESTATUS OleCreateLinkFromClip(LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*, OLEOPT_RENDER, OLECLIPFORMAT); OLESTATUS OleCreateFromFile(LPCSTR, LPOLECLIENT, LPCSTR, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*, OLEOPT_RENDER, OLECLIPFORMAT); OLESTATUS OleCreateLinkFromFile(LPCSTR, LPOLECLIENT, LPCSTR, LPCSTR, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*, OLEOPT_RENDER, OLECLIPFORMAT); OLESTATUS OleLoadFromStream(LPOLESTREAM, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*); OLESTATUS OleCreate(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*, OLEOPT_RENDER, OLECLIPFORMAT); OLESTATUS OleCreateInvisible(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*, OLEOPT_RENDER, OLECLIPFORMAT, BOOL); OLESTATUS OleCreateFromTemplate(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*, OLEOPT_RENDER, OLECLIPFORMAT); OLESTATUS OleClone(LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*); OLESTATUS OleCopyFromLink(LPOLEOBJECT, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*); OLESTATUS OleObjectConvert(LPOLEOBJECT, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT*); OLESTATUS OleRename(LPOLEOBJECT, LPCSTR); OLESTATUS OleQueryName(LPOLEOBJECT, LPSTR, UINT*); OLESTATUS OleRevokeObject(LPOLECLIENT); BOOL OleIsDcMeta(HDC); OLESTATUS OleRegisterClientDoc(LPCSTR, LPCSTR, LONG, LHCLIENTDOC*); OLESTATUS OleRevokeClientDoc(LHCLIENTDOC); OLESTATUS OleRenameClientDoc(LHCLIENTDOC, LPCSTR); OLESTATUS OleRevertClientDoc(LHCLIENTDOC); OLESTATUS OleSavedClientDoc(LHCLIENTDOC); OLESTATUS OleEnumObjects(LHCLIENTDOC, LPOLEOBJECT*); OLESTATUS OleRegisterServer(LPCSTR, LPOLESERVER, LHSERVER*, HINSTANCE, OLE_SERVER_USE); OLESTATUS OleRevokeServer(LHSERVER); OLESTATUS OleBlockServer(LHSERVER); OLESTATUS OleUnblockServer(LHSERVER, BOOL*); OLESTATUS OleLockServer(LPOLEOBJECT, LHSERVER*); OLESTATUS OleUnlockServer(LHSERVER); OLESTATUS OleRegisterServerDoc(LHSERVER, LPCSTR, LPOLESERVERDOC, LHSERVERDOC*); OLESTATUS OleRevokeServerDoc(LHSERVERDOC); OLESTATUS OleRenameServerDoc(LHSERVERDOC, LPCSTR); OLESTATUS OleRevertServerDoc(LHSERVERDOC); OLESTATUS OleSavedServerDoc(LHSERVERDOC); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/objbase.d0000664000175000017500000002047612776214756023275 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_objbase.d) */ module core.sys.windows.objbase; version (Windows): pragma(lib, "ole32"); import core.sys.windows.cguid, core.sys.windows.objidl, core.sys.windows.unknwn, core.sys.windows.wtypes; private import core.sys.windows.basetyps, core.sys.windows.objfwd, core.sys.windows.rpcdce, core.sys.windows.winbase, core.sys.windows.windef; // DAC: Not needed for D? //MACRO #define LISet32(li, v) ((li).HighPart=(v)<0?-1:0, (li).LowPart=(v)) //MACRO #define ULISet32(li, v) ((li).HighPart=0, (li).LowPart=(v)) enum CLSCTX_ALL = CLSCTX.CLSCTX_INPROC_SERVER|CLSCTX.CLSCTX_INPROC_HANDLER|CLSCTX.CLSCTX_LOCAL_SERVER; enum CLSCTX_INPROC = CLSCTX.CLSCTX_INPROC_SERVER|CLSCTX.CLSCTX_INPROC_HANDLER; enum CLSCTX_SERVER = CLSCTX.CLSCTX_INPROC_SERVER|CLSCTX.CLSCTX_LOCAL_SERVER|CLSCTX.CLSCTX_REMOTE_SERVER; enum MARSHALINTERFACE_MIN=500; enum CWCSTORAGENAME=32; enum STGM_DIRECT = 0; enum STGM_TRANSACTED = 0x10000L; enum STGM_SIMPLE = 0x8000000L; enum STGM_READ = 0; enum STGM_WRITE = 1; enum STGM_READWRITE = 2; enum STGM_SHARE_DENY_NONE = 0x40; enum STGM_SHARE_DENY_READ = 0x30; enum STGM_SHARE_DENY_WRITE = 0x20; enum STGM_SHARE_EXCLUSIVE = 0x10; enum STGM_PRIORITY = 0x40000L; enum STGM_DELETEONRELEASE = 0x4000000; enum STGM_NOSCRATCH = 0x100000; enum STGM_CREATE = 0x1000; enum STGM_CONVERT = 0x20000; enum STGM_NOSNAPSHOT = 0x200000; enum STGM_FAILIFTHERE = 0; enum ASYNC_MODE_COMPATIBILITY = 1; enum ASYNC_MODE_DEFAULT = 0; enum STGTY_REPEAT = 256; enum STG_TOEND = 0xFFFFFFFF; enum STG_LAYOUT_SEQUENTIAL = 0; enum STG_LAYOUT_INTERLEAVED = 1; enum COM_RIGHTS_EXECUTE = 1; enum COM_RIGHTS_SAFE_FOR_SCRIPTING = 2; enum STGOPTIONS_VERSION = 2; enum STGFMT { STGFMT_STORAGE = 0, STGFMT_FILE = 3, STGFMT_ANY = 4, STGFMT_DOCFILE = 5 } struct STGOPTIONS { USHORT usVersion; USHORT reserved; ULONG ulSectorSize; const(WCHAR)* pwcsTemplateFile; } enum REGCLS { REGCLS_SINGLEUSE = 0, REGCLS_MULTIPLEUSE = 1, REGCLS_MULTI_SEPARATE = 2 } /* BOOL IsEqualGUID(GUID rguid1, GUID rguid2) { return rguid1 == rguid2; } */ extern (Windows) BOOL IsEqualGUID( REFGUID rguid1, REFGUID rguid2 ); alias IsEqualGUID IsEqualIID; alias IsEqualGUID IsEqualCLSID; enum COINIT { COINIT_APARTMENTTHREADED = 2, COINIT_MULTITHREADED = 0, COINIT_DISABLE_OLE1DDE = 4, COINIT_SPEED_OVER_MEMORY = 8 } enum STDMSHLFLAGS { SMEXF_SERVER = 1, SMEXF_HANDLER } extern(Windows) { alias HRESULT function(REFCLSID, REFIID, PVOID*) LPFNGETCLASSOBJECT; alias HRESULT function() LPFNCANUNLOADNOW; DWORD CoBuildVersion(); HRESULT CoInitialize(PVOID); HRESULT CoInitializeEx(LPVOID, DWORD); void CoUninitialize(); HRESULT CoGetMalloc(DWORD, LPMALLOC*); DWORD CoGetCurrentProcess(); HRESULT CoRegisterMallocSpy(LPMALLOCSPY); HRESULT CoRevokeMallocSpy(); HRESULT CoCreateStandardMalloc(DWORD, IMalloc*); //#ifdef DBG ULONG DebugCoGetRpcFault(); void DebugCoSetRpcFault(ULONG); //#endif HRESULT CoGetClassObject(REFCLSID, DWORD, COSERVERINFO*, REFIID, PVOID*); HRESULT CoRegisterClassObject(REFCLSID, LPUNKNOWN, DWORD, DWORD, PDWORD); HRESULT CoRevokeClassObject(DWORD); HRESULT CoGetMarshalSizeMax(ULONG*, REFIID, LPUNKNOWN, DWORD, PVOID, DWORD); HRESULT CoMarshalInterface(LPSTREAM, REFIID, LPUNKNOWN, DWORD, PVOID, DWORD); HRESULT CoUnmarshalInterface(LPSTREAM, REFIID, PVOID*); HRESULT CoMarshalHresult(LPSTREAM, HRESULT); HRESULT CoUnmarshalHresult(LPSTREAM, HRESULT*); HRESULT CoReleaseMarshalData(LPSTREAM); HRESULT CoDisconnectObject(LPUNKNOWN, DWORD); HRESULT CoLockObjectExternal(LPUNKNOWN, BOOL, BOOL); HRESULT CoGetStandardMarshal(REFIID, LPUNKNOWN, DWORD, PVOID, DWORD, LPMARSHAL*); HRESULT CoGetStdMarshalEx(LPUNKNOWN, DWORD, LPUNKNOWN*); BOOL CoIsHandlerConnected(LPUNKNOWN); BOOL CoHasStrongExternalConnections(LPUNKNOWN); HRESULT CoMarshalInterThreadInterfaceInStream(REFIID, LPUNKNOWN, LPSTREAM*); HRESULT CoGetInterfaceAndReleaseStream(LPSTREAM, REFIID, PVOID*); HRESULT CoCreateFreeThreadedMarshaler(LPUNKNOWN, LPUNKNOWN*); HINSTANCE CoLoadLibrary(LPOLESTR, BOOL); void CoFreeLibrary(HINSTANCE); void CoFreeAllLibraries(); void CoFreeUnusedLibraries(); HRESULT CoCreateInstance(REFCLSID, LPUNKNOWN, DWORD, REFIID, PVOID*); HRESULT CoCreateInstanceEx(REFCLSID, IUnknown, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); HRESULT StringFromCLSID(REFCLSID, LPOLESTR*); HRESULT CLSIDFromString(LPOLESTR, LPCLSID); HRESULT StringFromIID(REFIID, LPOLESTR*); HRESULT IIDFromString(LPOLESTR, LPIID); BOOL CoIsOle1Class(REFCLSID); HRESULT ProgIDFromCLSID(REFCLSID, LPOLESTR*); HRESULT CLSIDFromProgID(LPCOLESTR, LPCLSID); int StringFromGUID2(REFGUID, LPOLESTR, int); HRESULT CoCreateGuid(GUID*); BOOL CoFileTimeToDosDateTime(FILETIME*, LPWORD, LPWORD); BOOL CoDosDateTimeToFileTime(WORD, WORD, FILETIME*); HRESULT CoFileTimeNow(FILETIME*); HRESULT CoRegisterMessageFilter(LPMESSAGEFILTER, LPMESSAGEFILTER*); HRESULT CoGetTreatAsClass(REFCLSID, LPCLSID); HRESULT CoTreatAsClass(REFCLSID, REFCLSID); HRESULT DllGetClassObject(REFCLSID, REFIID, PVOID*); HRESULT DllCanUnloadNow(); PVOID CoTaskMemAlloc(ULONG); PVOID CoTaskMemRealloc(PVOID, ULONG); void CoTaskMemFree(PVOID); HRESULT CreateDataAdviseHolder(LPDATAADVISEHOLDER*); HRESULT CreateDataCache(LPUNKNOWN, REFCLSID, REFIID, PVOID*); HRESULT StgCreateDocfile(const(OLECHAR)*, DWORD, DWORD, IStorage*); HRESULT StgCreateDocfileOnILockBytes(ILockBytes, DWORD, DWORD, IStorage*); HRESULT StgOpenStorage(const(OLECHAR)*, IStorage, DWORD, SNB, DWORD, IStorage*); HRESULT StgOpenStorageOnILockBytes(ILockBytes, IStorage, DWORD, SNB, DWORD, IStorage*); HRESULT StgIsStorageFile(const(OLECHAR)*); HRESULT StgIsStorageILockBytes(ILockBytes); HRESULT StgSetTimes(OLECHAR *, FILETIME *, FILETIME *, FILETIME *); HRESULT StgCreateStorageEx(const(WCHAR)*, DWORD, DWORD, DWORD, STGOPTIONS*, void*, REFIID, void**); HRESULT StgOpenStorageEx(const(WCHAR)*, DWORD, DWORD, DWORD, STGOPTIONS*, void*, REFIID, void**); HRESULT BindMoniker(LPMONIKER, DWORD, REFIID, PVOID*); HRESULT CoGetObject(LPCWSTR, BIND_OPTS*, REFIID, void**); HRESULT MkParseDisplayName(LPBC, LPCOLESTR, ULONG*, LPMONIKER*); HRESULT MonikerRelativePathTo(LPMONIKER, LPMONIKER, LPMONIKER*, BOOL); HRESULT MonikerCommonPrefixWith(LPMONIKER, LPMONIKER, LPMONIKER*); HRESULT CreateBindCtx(DWORD, LPBC*); HRESULT CreateGenericComposite(LPMONIKER, LPMONIKER, LPMONIKER*); HRESULT GetClassFile (LPCOLESTR, CLSID*); HRESULT CreateFileMoniker(LPCOLESTR, LPMONIKER*); HRESULT CreateItemMoniker(LPCOLESTR, LPCOLESTR, LPMONIKER*); HRESULT CreateAntiMoniker(LPMONIKER*); HRESULT CreatePointerMoniker(LPUNKNOWN, LPMONIKER*); HRESULT GetRunningObjectTable(DWORD, LPRUNNINGOBJECTTABLE*); HRESULT CoInitializeSecurity(PSECURITY_DESCRIPTOR, LONG, SOLE_AUTHENTICATION_SERVICE*, void*, DWORD, DWORD, void*, DWORD, void*); HRESULT CoGetCallContext(REFIID, void**); HRESULT CoQueryProxyBlanket(IUnknown*, DWORD*, DWORD*, OLECHAR**, DWORD*, DWORD*, RPC_AUTH_IDENTITY_HANDLE*, DWORD*); HRESULT CoSetProxyBlanket(IUnknown*, DWORD, DWORD, OLECHAR*, DWORD, DWORD, RPC_AUTH_IDENTITY_HANDLE, DWORD); HRESULT CoCopyProxy(IUnknown*, IUnknown**); HRESULT CoQueryClientBlanket(DWORD*, DWORD*, OLECHAR**, DWORD*, DWORD*, RPC_AUTHZ_HANDLE*, DWORD*); HRESULT CoImpersonateClient(); HRESULT CoRevertToSelf(); HRESULT CoQueryAuthenticationServices(DWORD*, SOLE_AUTHENTICATION_SERVICE**); HRESULT CoSwitchCallContext(IUnknown*, IUnknown**); HRESULT CoGetInstanceFromFile(COSERVERINFO*, CLSID*, IUnknown*, DWORD, DWORD, OLECHAR*, DWORD, MULTI_QI*); HRESULT CoGetInstanceFromIStorage(COSERVERINFO*, CLSID*, IUnknown*, DWORD, IStorage*, DWORD, MULTI_QI*); ULONG CoAddRefServerProcess(); ULONG CoReleaseServerProcess(); HRESULT CoResumeClassObjects(); HRESULT CoSuspendClassObjects(); HRESULT CoGetPSClsid(REFIID, CLSID*); HRESULT CoRegisterPSClsid(REFIID, REFCLSID); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winnetwk.d0000664000175000017500000003612012776214756023527 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winnetwk.d) */ module core.sys.windows.winnetwk; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "mpr"); private import core.sys.windows.winbase, core.sys.windows.winerror, core.sys.windows.winnt; enum : DWORD { WNNC_NET_MSNET = 0x00010000, WNNC_NET_LANMAN = 0x00020000, WNNC_NET_NETWARE = 0x00030000, WNNC_NET_VINES = 0x00040000, WNNC_NET_10NET = 0x00050000, WNNC_NET_LOCUS = 0x00060000, WNNC_NET_SUN_PC_NFS = 0x00070000, WNNC_NET_LANSTEP = 0x00080000, WNNC_NET_9TILES = 0x00090000, WNNC_NET_LANTASTIC = 0x000A0000, WNNC_NET_AS400 = 0x000B0000, WNNC_NET_FTP_NFS = 0x000C0000, WNNC_NET_PATHWORKS = 0x000D0000, WNNC_NET_LIFENET = 0x000E0000, WNNC_NET_POWERLAN = 0x000F0000, WNNC_NET_BWNFS = 0x00100000, WNNC_NET_COGENT = 0x00110000, WNNC_NET_FARALLON = 0x00120000, WNNC_NET_APPLETALK = 0x00130000, WNNC_NET_INTERGRAPH = 0x00140000, WNNC_NET_SYMFONET = 0x00150000, WNNC_NET_CLEARCASE = 0x00160000, WNNC_NET_FRONTIER = 0x00170000, WNNC_NET_BMC = 0x00180000, WNNC_NET_DCE = 0x00190000, WNNC_NET_AVID = 0x001A0000, WNNC_NET_DOCUSPACE = 0x001B0000, WNNC_NET_MANGOSOFT = 0x001C0000, WNNC_NET_SERNET = 0x001D0000, WNNC_NET_DECORB = 0x00200000, WNNC_NET_PROTSTOR = 0x00210000, WNNC_NET_FJ_REDIR = 0x00220000, WNNC_NET_DISTINCT = 0x00230000, WNNC_NET_TWINS = 0x00240000, WNNC_NET_RDR2SAMPLE = 0x00250000, WNNC_NET_CSC = 0x00260000, WNNC_NET_3IN1 = 0x00270000, WNNC_NET_EXTENDNET = 0x00290000, WNNC_NET_OBJECT_DIRE = 0x00300000, WNNC_NET_MASFAX = 0x00310000, WNNC_NET_HOB_NFS = 0x00320000, WNNC_NET_SHIVA = 0x00330000, WNNC_NET_IBMAL = 0x00340000, WNNC_CRED_MANAGER = 0xFFFF0000 } enum : DWORD { RESOURCE_CONNECTED = 1, RESOURCE_GLOBALNET = 2, RESOURCE_REMEMBERED = 3, RESOURCE_RECENT = 4, RESOURCE_CONTEXT = 5 } enum DWORD RESOURCETYPE_ANY = 0, RESOURCETYPE_DISK = 1, RESOURCETYPE_PRINT = 2, RESOURCETYPE_RESERVED = 8, RESOURCETYPE_UNKNOWN = 0xFFFFFFFF; enum DWORD RESOURCEUSAGE_CONNECTABLE = 0x00000001, RESOURCEUSAGE_CONTAINER = 0x00000002, RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004, RESOURCEUSAGE_SIBLING = 0x00000008, RESOURCEUSAGE_ATTACHED = 0x00000010, RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED), RESOURCEUSAGE_RESERVED = 0x80000000; enum : DWORD { RESOURCEDISPLAYTYPE_GENERIC, RESOURCEDISPLAYTYPE_DOMAIN, RESOURCEDISPLAYTYPE_SERVER, RESOURCEDISPLAYTYPE_SHARE, RESOURCEDISPLAYTYPE_FILE, RESOURCEDISPLAYTYPE_GROUP, RESOURCEDISPLAYTYPE_NETWORK, RESOURCEDISPLAYTYPE_ROOT, RESOURCEDISPLAYTYPE_SHAREADMIN, RESOURCEDISPLAYTYPE_DIRECTORY, RESOURCEDISPLAYTYPE_TREE // = 10 } enum NETPROPERTY_PERSISTENT = 1; enum DWORD CONNECT_UPDATE_PROFILE = 1, CONNECT_UPDATE_RECENT = 2, CONNECT_TEMPORARY = 4, CONNECT_INTERACTIVE = 8, CONNECT_PROMPT = 16, CONNECT_NEED_DRIVE = 32, CONNECT_REFCOUNT = 64, CONNECT_REDIRECT = 128, CONNECT_LOCALDRIVE = 256, CONNECT_CURRENT_MEDIA = 512; enum DWORD CONNDLG_RO_PATH = 1, CONNDLG_CONN_POINT = 2, CONNDLG_USE_MRU = 4, CONNDLG_HIDE_BOX = 8, CONNDLG_PERSIST = 16, CONNDLG_NOT_PERSIST = 32; enum DWORD DISC_UPDATE_PROFILE = 1, DISC_NO_FORCE = 64; enum DWORD WNFMT_MULTILINE = 1, WNFMT_ABBREVIATED = 2, WNFMT_INENUM = 16, WNFMT_CONNECTION = 32; enum : DWORD { WN_SUCCESS = NO_ERROR, WN_NO_ERROR = NO_ERROR, WN_NOT_SUPPORTED = ERROR_NOT_SUPPORTED, WN_CANCEL = ERROR_CANCELLED, WN_RETRY = ERROR_RETRY, WN_NET_ERROR = ERROR_UNEXP_NET_ERR, WN_MORE_DATA = ERROR_MORE_DATA, WN_BAD_POINTER = ERROR_INVALID_ADDRESS, WN_BAD_VALUE = ERROR_INVALID_PARAMETER, WN_BAD_USER = ERROR_BAD_USERNAME, WN_BAD_PASSWORD = ERROR_INVALID_PASSWORD, WN_ACCESS_DENIED = ERROR_ACCESS_DENIED, WN_FUNCTION_BUSY = ERROR_BUSY, WN_WINDOWS_ERROR = ERROR_UNEXP_NET_ERR, WN_OUT_OF_MEMORY = ERROR_NOT_ENOUGH_MEMORY, WN_NO_NETWORK = ERROR_NO_NETWORK, WN_EXTENDED_ERROR = ERROR_EXTENDED_ERROR, WN_BAD_LEVEL = ERROR_INVALID_LEVEL, WN_BAD_HANDLE = ERROR_INVALID_HANDLE, WN_NOT_INITIALIZING = ERROR_ALREADY_INITIALIZED, WN_NO_MORE_DEVICES = ERROR_NO_MORE_DEVICES, WN_NOT_CONNECTED = ERROR_NOT_CONNECTED, WN_OPEN_FILES = ERROR_OPEN_FILES, WN_DEVICE_IN_USE = ERROR_DEVICE_IN_USE, WN_BAD_NETNAME = ERROR_BAD_NET_NAME, WN_BAD_LOCALNAME = ERROR_BAD_DEVICE, WN_ALREADY_CONNECTED = ERROR_ALREADY_ASSIGNED, WN_DEVICE_ERROR = ERROR_GEN_FAILURE, WN_CONNECTION_CLOSED = ERROR_CONNECTION_UNAVAIL, WN_NO_NET_OR_BAD_PATH = ERROR_NO_NET_OR_BAD_PATH, WN_BAD_PROVIDER = ERROR_BAD_PROVIDER, WN_CANNOT_OPEN_PROFILE = ERROR_CANNOT_OPEN_PROFILE, WN_BAD_PROFILE = ERROR_BAD_PROFILE, WN_BAD_DEV_TYPE = ERROR_BAD_DEV_TYPE, WN_DEVICE_ALREADY_REMEMBERED = ERROR_DEVICE_ALREADY_REMEMBERED, WN_NO_MORE_ENTRIES = ERROR_NO_MORE_ITEMS, WN_NOT_CONTAINER = ERROR_NOT_CONTAINER, WN_NOT_AUTHENTICATED = ERROR_NOT_AUTHENTICATED, WN_NOT_LOGGED_ON = ERROR_NOT_LOGGED_ON, WN_NOT_VALIDATED = ERROR_NO_LOGON_SERVERS } enum : DWORD { UNIVERSAL_NAME_INFO_LEVEL = 1, REMOTE_NAME_INFO_LEVEL } enum DWORD NETINFO_DLL16 = 1, NETINFO_DISKRED = 4, NETINFO_PRINTERRED = 8; enum DWORD RP_LOGON = 1, RP_INIFILE = 2; enum DWORD PP_DISPLAYERRORS = 1; enum DWORD WNCON_FORNETCARD = 1, WNCON_NOTROUTED = 2, WNCON_SLOWLINK = 4, WNCON_DYNAMIC = 8; struct NETRESOURCEA { DWORD dwScope; DWORD dwType; DWORD dwDisplayType; DWORD dwUsage; LPSTR lpLocalName; LPSTR lpRemoteName; LPSTR lpComment; LPSTR lpProvider; } alias NETRESOURCEA* LPNETRESOURCEA; struct NETRESOURCEW { DWORD dwScope; DWORD dwType; DWORD dwDisplayType; DWORD dwUsage; LPWSTR lpLocalName; LPWSTR lpRemoteName; LPWSTR lpComment ; LPWSTR lpProvider; } alias NETRESOURCEW* LPNETRESOURCEW; struct CONNECTDLGSTRUCTA { DWORD cbStructure; HWND hwndOwner; LPNETRESOURCEA lpConnRes; DWORD dwFlags; DWORD dwDevNum; } alias CONNECTDLGSTRUCTA* LPCONNECTDLGSTRUCTA; struct CONNECTDLGSTRUCTW { DWORD cbStructure; HWND hwndOwner; LPNETRESOURCEW lpConnRes; DWORD dwFlags; DWORD dwDevNum; } alias CONNECTDLGSTRUCTW* LPCONNECTDLGSTRUCTW; struct DISCDLGSTRUCTA { DWORD cbStructure; HWND hwndOwner; LPSTR lpLocalName; LPSTR lpRemoteName; DWORD dwFlags; } alias DISCDLGSTRUCTA* LPDISCDLGSTRUCTA; struct DISCDLGSTRUCTW { DWORD cbStructure; HWND hwndOwner; LPWSTR lpLocalName; LPWSTR lpRemoteName; DWORD dwFlags; } alias DISCDLGSTRUCTW* LPDISCDLGSTRUCTW; struct UNIVERSAL_NAME_INFOA { LPSTR lpUniversalName; } alias UNIVERSAL_NAME_INFOA* LPUNIVERSAL_NAME_INFOA; struct UNIVERSAL_NAME_INFOW { LPWSTR lpUniversalName; } alias UNIVERSAL_NAME_INFOW* LPUNIVERSAL_NAME_INFOW; struct REMOTE_NAME_INFOA { LPSTR lpUniversalName; LPSTR lpConnectionName; LPSTR lpRemainingPath; } alias REMOTE_NAME_INFOA* LPREMOTE_NAME_INFOA; struct REMOTE_NAME_INFOW { LPWSTR lpUniversalName; LPWSTR lpConnectionName; LPWSTR lpRemainingPath; } alias REMOTE_NAME_INFOW* LPREMOTE_NAME_INFOW; struct NETINFOSTRUCT { DWORD cbStructure; DWORD dwProviderVersion; DWORD dwStatus; DWORD dwCharacteristics; DWORD dwHandle; WORD wNetType; DWORD dwPrinters; DWORD dwDrives; } alias NETINFOSTRUCT* LPNETINFOSTRUCT; extern (Pascal) { alias UINT function(LPCSTR, LPSTR, UINT) PFNGETPROFILEPATHA; alias UINT function(LPCWSTR, LPWSTR, UINT) PFNGETPROFILEPATHW; alias UINT function(LPCSTR, LPCSTR, DWORD) PFNRECONCILEPROFILEA; alias UINT function(LPCWSTR, LPCWSTR, DWORD) PFNRECONCILEPROFILEW; alias BOOL function(HWND, LPCSTR, LPCSTR, LPCSTR, DWORD) PFNPROCESSPOLICIESA; alias BOOL function(HWND, LPCWSTR, LPCWSTR, LPCWSTR, DWORD) PFNPROCESSPOLICIESW; } struct NETCONNECTINFOSTRUCT { DWORD cbStructure; DWORD dwFlags; DWORD dwSpeed; DWORD dwDelay; DWORD dwOptDataSize; } alias NETCONNECTINFOSTRUCT* LPNETCONNECTINFOSTRUCT; extern (Windows) { DWORD WNetAddConnection2A(LPNETRESOURCEA, LPCSTR, LPCSTR, DWORD); DWORD WNetAddConnection2W(LPNETRESOURCEW, LPCWSTR, LPCWSTR, DWORD); DWORD WNetAddConnection3A(HWND, LPNETRESOURCEA, LPCSTR, LPCSTR, DWORD); DWORD WNetAddConnection3W(HWND, LPNETRESOURCEW, LPCWSTR, LPCWSTR, DWORD); DWORD WNetCancelConnection2A(LPCSTR, DWORD, BOOL); DWORD WNetCancelConnection2W(LPCWSTR, DWORD, BOOL); DWORD WNetGetConnectionA(LPCSTR, LPSTR, PDWORD); DWORD WNetGetConnectionW(LPCWSTR, LPWSTR, PDWORD); DWORD WNetUseConnectionA(HWND, LPNETRESOURCEA, LPCSTR, LPCSTR, DWORD, LPSTR, PDWORD, PDWORD); DWORD WNetUseConnectionW(HWND, LPNETRESOURCEW, LPCWSTR, LPCWSTR, DWORD, LPWSTR, PDWORD, PDWORD); DWORD WNetSetConnectionA(LPCSTR, DWORD, PVOID); DWORD WNetSetConnectionW(LPCWSTR, DWORD, PVOID); DWORD WNetConnectionDialog(HWND, DWORD); DWORD WNetDisconnectDialog(HWND, DWORD); DWORD WNetConnectionDialog1A(LPCONNECTDLGSTRUCTA); DWORD WNetConnectionDialog1W(LPCONNECTDLGSTRUCTW); DWORD WNetDisconnectDialog1A(LPDISCDLGSTRUCTA); DWORD WNetDisconnectDialog1W(LPDISCDLGSTRUCTW); DWORD WNetOpenEnumA(DWORD, DWORD, DWORD, LPNETRESOURCEA, LPHANDLE); DWORD WNetOpenEnumW(DWORD, DWORD, DWORD, LPNETRESOURCEW, LPHANDLE); DWORD WNetEnumResourceA(HANDLE, PDWORD, PVOID, PDWORD); DWORD WNetEnumResourceW(HANDLE, PDWORD, PVOID, PDWORD); DWORD WNetCloseEnum(HANDLE); DWORD WNetGetUniversalNameA(LPCSTR, DWORD, PVOID, PDWORD); DWORD WNetGetUniversalNameW(LPCWSTR, DWORD, PVOID, PDWORD); DWORD WNetGetUserA(LPCSTR, LPSTR, PDWORD); DWORD WNetGetUserW(LPCWSTR, LPWSTR, PDWORD); DWORD WNetGetProviderNameA(DWORD, LPSTR, PDWORD); DWORD WNetGetProviderNameW(DWORD, LPWSTR, PDWORD); DWORD WNetGetNetworkInformationA(LPCSTR, LPNETINFOSTRUCT); DWORD WNetGetNetworkInformationW(LPCWSTR, LPNETINFOSTRUCT); DWORD WNetGetResourceInformationA(LPNETRESOURCEA, LPVOID, LPDWORD, LPSTR*); DWORD WNetGetResourceInformationW(LPNETRESOURCEA, LPVOID, LPDWORD, LPWSTR*); DWORD WNetGetResourceParentA(LPNETRESOURCEA, LPVOID, LPDWORD); DWORD WNetGetResourceParentW(LPNETRESOURCEW, LPVOID, LPDWORD); DWORD WNetGetLastErrorA(PDWORD, LPSTR, DWORD, LPSTR, DWORD); DWORD WNetGetLastErrorW(PDWORD, LPWSTR, DWORD, LPWSTR, DWORD); DWORD MultinetGetConnectionPerformanceA(LPNETRESOURCEA, LPNETCONNECTINFOSTRUCT); DWORD MultinetGetConnectionPerformanceW(LPNETRESOURCEW, LPNETCONNECTINFOSTRUCT); deprecated { DWORD WNetAddConnectionA(LPCSTR, LPCSTR, LPCSTR); DWORD WNetAddConnectionW(LPCWSTR, LPCWSTR, LPCWSTR); DWORD WNetCancelConnectionA(LPCSTR, BOOL); DWORD WNetCancelConnectionW(LPCWSTR, BOOL); } } version (Unicode) { alias PFNGETPROFILEPATHW PFNGETPROFILEPATH; alias PFNRECONCILEPROFILEW PFNRECONCILEPROFILE; alias PFNPROCESSPOLICIESW PFNPROCESSPOLICIES; alias NETRESOURCEW NETRESOURCE; alias CONNECTDLGSTRUCTW CONNECTDLGSTRUCT; alias DISCDLGSTRUCTW DISCDLGSTRUCT; alias REMOTE_NAME_INFOW REMOTE_NAME_INFO; alias UNIVERSAL_NAME_INFOW UNIVERSAL_NAME_INFO; alias WNetAddConnection2W WNetAddConnection2; alias WNetAddConnection3W WNetAddConnection3; alias WNetCancelConnection2W WNetCancelConnection2; alias WNetGetConnectionW WNetGetConnection; alias WNetUseConnectionW WNetUseConnection; alias WNetSetConnectionW WNetSetConnection; alias WNetConnectionDialog1W WNetConnectionDialog1; alias WNetDisconnectDialog1W WNetDisconnectDialog1; alias WNetOpenEnumW WNetOpenEnum; alias WNetEnumResourceW WNetEnumResource; alias WNetGetUniversalNameW WNetGetUniversalName; alias WNetGetUserW WNetGetUser; alias WNetGetProviderNameW WNetGetProviderName; alias WNetGetNetworkInformationW WNetGetNetworkInformation; alias WNetGetResourceInformationW WNetGetResourceInformation; alias WNetGetResourceParentW WNetGetResourceParent; alias WNetGetLastErrorW WNetGetLastError; alias MultinetGetConnectionPerformanceW MultinetGetConnectionPerformance; deprecated { alias WNetAddConnectionW WNetAddConnection; alias WNetCancelConnectionW WNetCancelConnection; } } else { alias PFNGETPROFILEPATHA PFNGETPROFILEPATH; alias PFNRECONCILEPROFILEA PFNRECONCILEPROFILE; alias PFNPROCESSPOLICIESA PFNPROCESSPOLICIES; alias NETRESOURCEA NETRESOURCE; alias CONNECTDLGSTRUCTA CONNECTDLGSTRUCT; alias DISCDLGSTRUCTA DISCDLGSTRUCT; alias REMOTE_NAME_INFOA REMOTE_NAME_INFO; alias UNIVERSAL_NAME_INFOA UNIVERSAL_NAME_INFO; alias WNetAddConnection2A WNetAddConnection2; alias WNetAddConnection3A WNetAddConnection3; alias WNetCancelConnection2A WNetCancelConnection2; alias WNetGetConnectionA WNetGetConnection; alias WNetUseConnectionA WNetUseConnection; alias WNetSetConnectionA WNetSetConnection; alias WNetConnectionDialog1A WNetConnectionDialog1; alias WNetDisconnectDialog1A WNetDisconnectDialog1; alias WNetOpenEnumA WNetOpenEnum; alias WNetEnumResourceA WNetEnumResource; alias WNetGetUniversalNameA WNetGetUniversalName; alias WNetGetUserA WNetGetUser; alias WNetGetProviderNameA WNetGetProviderName; alias WNetGetNetworkInformationA WNetGetNetworkInformation; alias WNetGetResourceInformationA WNetGetResourceInformation; alias WNetGetResourceParentA WNetGetResourceParent; alias WNetGetLastErrorA WNetGetLastError; alias MultinetGetConnectionPerformanceA MultinetGetConnectionPerformance; deprecated { alias WNetAddConnectionA WNetAddConnection; alias WNetCancelConnectionA WNetCancelConnection; } } alias NETRESOURCE* LPNETRESOURCE; alias CONNECTDLGSTRUCT* LPCONNECTDLGSTRUCT; alias DISCDLGSTRUCT* LPDISCDLGSTRUCT; alias REMOTE_NAME_INFO* LPREMOTE_NAME_INFO; alias UNIVERSAL_NAME_INFO* LPUNIVERSAL_NAME_INFO; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/threadaux.d0000664000175000017500000002552012776214756023650 0ustar kaikai/** * This module provides OS specific helper function for threads support * * Copyright: Copyright Digital Mars 2010 - 2010. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Source: $(DRUNTIMESRC core/sys/windows/_threadaux.d) * Authors: Rainer Schuetze */ module core.sys.windows.threadaux; version (Windows): import core.sys.windows.windows; import core.stdc.stdlib; public import core.thread; extern(Windows) HANDLE OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId) nothrow; extern (C) extern __gshared int _tls_index; extern (C) // rt.minfo { void rt_moduleTlsCtor(); void rt_moduleTlsDtor(); } private: /////////////////////////////////////////////////////////////////// struct thread_aux { // don't let symbols leak into other modules enum SystemProcessInformation = 5; enum STATUS_INFO_LENGTH_MISMATCH = 0xc0000004; // structs subject to change according to MSDN, more info at http://undocumented.ntinternals.net // declarations according to http://processhacker.sourceforge.net/doc/ntexapi_8h_source.html // NOTE: the declarations assume default alignment for Win64 and contain some padding data struct UNICODE_STRING { short Length; short MaximumLength; wchar* Buffer; } // process or thread ID, documentation says it is a HANDLE, but it's actually the ID (a DWORD) alias size_t PTID; struct _SYSTEM_PROCESS_INFORMATION { int NextEntryOffset; // When this entry is 0, there are no more processes to be read. int NumberOfThreads; long WorkingSetPrivateSize; uint HardFaultCount; uint NumberOfThreadsHighWatermark; ulong CycleTime; long CreateTime; long UserTime; long KernelTime; UNICODE_STRING ImageName; int BasePriority; PTID /*Unique*/ProcessId; PTID InheritedFromUniqueProcessId; uint HandleCount; uint SessionId; size_t UniqueProcessKey; size_t PeakVirtualSize; size_t VirtualSize; uint PageFaultCount; size_t PeakWorkingSetSize; size_t WorkingSetSize; size_t QuotaPeakPagedPoolUsage; size_t QuotaPagedPoolUsage; size_t QuotaPeakNonPagedPoolUsage; size_t QuotaNonPagedPoolUsage; size_t PagefileUsage; size_t PeakPagefileUsage; size_t PrivatePageCount; long ReadOperationCount; long WriteOperationCount; long OtherOperationCount; long ReadTransferCount; long WriteTransferCount; long OtherTransferCount; // SYSTEM_THREAD_INFORMATION or SYSTEM_EXTENDED_THREAD_INFORMATION structures follow. } struct _SYSTEM_THREAD_INFORMATION { long KernelTime; long UserTime; long CreateTime; uint WaitTime; void* StartAddress; PTID ProcessId; PTID ThreadId; int Priority; int BasePriority; uint ContextSwitches; uint ThreadState; int WaitReason; int reserved; } alias fnNtQuerySystemInformation = extern(Windows) HRESULT function( uint SystemInformationClass, void* info, uint infoLength, uint* ReturnLength ) nothrow; enum ThreadBasicInformation = 0; struct THREAD_BASIC_INFORMATION { int ExitStatus; void** TebBaseAddress; PTID ProcessId; PTID ThreadId; size_t AffinityMask; int Priority; int BasePriority; } alias fnNtQueryInformationThread = extern(Windows) int function( HANDLE ThreadHandle, uint ThreadInformationClass, void* buf, uint size, uint* ReturnLength ) nothrow; enum SYNCHRONIZE = 0x00100000; enum THREAD_GET_CONTEXT = 8; enum THREAD_QUERY_INFORMATION = 0x40; enum THREAD_SUSPEND_RESUME = 2; /////////////////////////////////////////////////////////////////// // get the thread environment block (TEB) of the thread with the given handle static void** getTEB( HANDLE hnd ) nothrow { HANDLE nthnd = GetModuleHandleA( "NTDLL" ); assert( nthnd, "cannot get module handle for ntdll" ); fnNtQueryInformationThread fn = cast(fnNtQueryInformationThread) GetProcAddress( nthnd, "NtQueryInformationThread" ); assert( fn, "cannot find NtQueryInformationThread in ntdll" ); THREAD_BASIC_INFORMATION tbi; int Status = (*fn)(hnd, ThreadBasicInformation, &tbi, tbi.sizeof, null); assert(Status == 0); return tbi.TebBaseAddress; } // get the thread environment block (TEB) of the thread with the given identifier static void** getTEB( uint id ) nothrow { HANDLE hnd = OpenThread( THREAD_QUERY_INFORMATION, FALSE, id ); assert( hnd, "OpenThread failed" ); void** teb = getTEB( hnd ); CloseHandle( hnd ); return teb; } // get linear address of TEB of current thread static void** getTEB() nothrow { version(Win32) { asm pure nothrow @nogc { naked; mov EAX,FS:[0x18]; ret; } } else version(Win64) { asm pure nothrow @nogc { naked; mov RAX,0x30; mov RAX,GS:[RAX]; // immediate value causes fixup ret; } } else { static assert(false); } } // get the stack bottom (the top address) of the thread with the given handle static void* getThreadStackBottom( HANDLE hnd ) nothrow { void** teb = getTEB( hnd ); return teb[1]; } // get the stack bottom (the top address) of the thread with the given identifier static void* getThreadStackBottom( uint id ) nothrow { void** teb = getTEB( id ); return teb[1]; } // create a thread handle with full access to the thread with the given identifier static HANDLE OpenThreadHandle( uint id ) nothrow { return OpenThread( SYNCHRONIZE|THREAD_GET_CONTEXT|THREAD_QUERY_INFORMATION|THREAD_SUSPEND_RESUME, FALSE, id ); } /////////////////////////////////////////////////////////////////// // enumerate threads of the given process calling the passed function on each thread // using function instead of delegate here to avoid allocating closure static bool enumProcessThreads( uint procid, bool function( uint id, void* context ) dg, void* context ) { HANDLE hnd = GetModuleHandleA( "NTDLL" ); fnNtQuerySystemInformation fn = cast(fnNtQuerySystemInformation) GetProcAddress( hnd, "NtQuerySystemInformation" ); if( !fn ) return false; uint sz = 16384; uint retLength; HRESULT rc; char* buf; for( ; ; ) { buf = cast(char*) core.stdc.stdlib.malloc(sz); if(!buf) return false; rc = fn( SystemProcessInformation, buf, sz, &retLength ); if( rc != STATUS_INFO_LENGTH_MISMATCH ) break; core.stdc.stdlib.free( buf ); sz *= 2; } scope(exit) core.stdc.stdlib.free( buf ); if(rc != 0) return false; auto pinfo = cast(_SYSTEM_PROCESS_INFORMATION*) buf; auto pend = cast(_SYSTEM_PROCESS_INFORMATION*) (buf + retLength); for( ; pinfo < pend; ) { if( pinfo.ProcessId == procid ) { auto tinfo = cast(_SYSTEM_THREAD_INFORMATION*)(pinfo + 1); for( int i = 0; i < pinfo.NumberOfThreads; i++, tinfo++ ) if( tinfo.ProcessId == procid ) if( !dg( cast(uint) tinfo.ThreadId, context ) ) // IDs are actually DWORDs return false; } if( pinfo.NextEntryOffset == 0 ) break; pinfo = cast(_SYSTEM_PROCESS_INFORMATION*) (cast(char*) pinfo + pinfo.NextEntryOffset); } return true; } static bool enumProcessThreads( bool function( uint id, void* context ) dg, void* context ) { return enumProcessThreads( GetCurrentProcessId(), dg, context ); } // execute function on the TLS for the given thread alias extern(C) void function() externCVoidFunc; static void impersonate_thread( uint id, externCVoidFunc fn ) { impersonate_thread(id, () => fn()); } static void impersonate_thread( uint id, scope void delegate() dg) { if( id == GetCurrentThreadId() ) { dg(); return; } // temporarily set current TLS array pointer to the array pointer of the referenced thread void** curteb = getTEB(); void** teb = getTEB( id ); assert( teb && curteb ); void** curtlsarray = cast(void**) curteb[11]; void** tlsarray = cast(void**) teb[11]; if( !curtlsarray || !tlsarray ) return; curteb[11] = tlsarray; dg(); curteb[11] = curtlsarray; } } public: // forward as few symbols as possible into the "global" name space alias thread_aux.getTEB getTEB; alias thread_aux.getThreadStackBottom getThreadStackBottom; alias thread_aux.OpenThreadHandle OpenThreadHandle; alias thread_aux.enumProcessThreads enumProcessThreads; alias thread_aux.impersonate_thread impersonate_thread; // get the start of the TLS memory of the thread with the given handle void* GetTlsDataAddress( HANDLE hnd ) nothrow { if( void** teb = getTEB( hnd ) ) if( void** tlsarray = cast(void**) teb[11] ) return tlsarray[_tls_index]; return null; } // get the start of the TLS memory of the thread with the given identifier void* GetTlsDataAddress( uint id ) nothrow { HANDLE hnd = OpenThread( thread_aux.THREAD_QUERY_INFORMATION, FALSE, id ); assert( hnd, "OpenThread failed" ); void* tls = GetTlsDataAddress( hnd ); CloseHandle( hnd ); return tls; } // get the address of the entry in the TLS array for the current thread // use C mangling to access it from msvc.c extern(C) void** GetTlsEntryAdr() { if( void** teb = getTEB() ) if( void** tlsarray = cast(void**) teb[11] ) return tlsarray + _tls_index; return null; } /////////////////////////////////////////////////////////////////// // run rt_moduleTlsCtor in the context of the given thread void thread_moduleTlsCtor( uint id ) { thread_aux.impersonate_thread(id, &rt_moduleTlsCtor); } /////////////////////////////////////////////////////////////////// // run rt_moduleTlsDtor in the context of the given thread void thread_moduleTlsDtor( uint id ) { thread_aux.impersonate_thread(id, &rt_moduleTlsDtor); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/sqlext.d0000664000175000017500000013576212776214756023215 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_sqlext.d) */ module core.sys.windows.sqlext; version (Windows): /* Conversion notes: The MinGW file was a horrible mess. All of the #defines were sorted alphabetically, which is crazy. This file needs a lot of work. In MinGW, sqlext #includes sqlucode, but sqlucode #includes sqlext, creating a circular dependency! */ public import core.sys.windows.sql; private import core.sys.windows.windef; enum SQL_SPEC_MAJOR = 3; enum SQL_SPEC_MINOR = 51; const char[] SQL_SPEC_STRING = "03.51"; enum SQL_ACCESS_MODE = 101; enum SQL_ACTIVE_CONNECTIONS = 0; enum SQL_ACTIVE_STATEMENTS = 1; enum SQL_DATE = 9; enum SQL_TIME = 10; enum SQL_SIGNED_OFFSET = -20; enum SQL_TINYINT = -6; enum SQL_TIMESTAMP = 11; enum SQL_UNSIGNED_OFFSET = -22; enum SQL_ADD = 4; enum SQL_ALL_EXCEPT_LIKE = 2; enum SQL_API_ALL_FUNCTIONS = 0; enum SQL_API_SQLCOLATTRIBUTES = 6; enum SQL_API_SQLDRIVERCONNECT = 41; enum SQL_API_SQLBROWSECONNECT = 55; enum SQL_API_SQLCOLUMNPRIVILEGES = 56; enum SQL_API_SQLDESCRIBEPARAM = 58; enum SQL_API_SQLEXTENDEDFETCH = 59; enum SQL_API_SQLFOREIGNKEYS = 60; enum SQL_API_SQLMORERESULTS = 61; enum SQL_API_SQLNATIVESQL = 62; enum SQL_API_SQLNUMPARAMS = 63; enum SQL_API_SQLPARAMOPTIONS = 64; enum SQL_API_SQLPRIMARYKEYS = 65; enum SQL_API_SQLPROCEDURECOLUMNS = 66; enum SQL_API_SQLPROCEDURES = 67; enum SQL_API_SQLSETPOS = 68; enum SQL_API_SQLSETSCROLLOPTIONS = 69; enum SQL_API_SQLTABLEPRIVILEGES = 70; enum SQL_API_SQLDRIVERS = 71; enum SQL_API_SQLBINDPARAMETER = 72; enum SQL_API_LOADBYORDINAL = 199; enum SQL_ASYNC_ENABLE = 4; enum SQL_ASYNC_ENABLE_OFF = 0UL; enum SQL_ASYNC_ENABLE_ON = 1UL; enum SQL_ASYNC_ENABLE_DEFAULT = SQL_ASYNC_ENABLE_OFF; enum SQL_ATTR_CONNECTION_DEAD = 1209; enum SQL_ATTR_READONLY = 0; enum SQL_ATTR_READWRITE_UNKNOWN = 2; enum SQL_ATTR_WRITE = 1; enum SQL_AUTOCOMMIT = 102; enum SQL_AUTOCOMMIT_OFF = 0UL; enum SQL_AUTOCOMMIT_ON = 1UL; enum SQL_AUTOCOMMIT_DEFAULT = SQL_AUTOCOMMIT_ON; enum SQL_BEST_ROWID = 1; enum SQL_BIGINT = -5; enum SQL_BINARY = -2; enum SQL_BIND_BY_COLUMN = 0UL; enum SQL_BIND_TYPE = 5; enum SQL_BIND_TYPE_DEFAULT = SQL_BIND_BY_COLUMN; enum SQL_BIT = -7; enum SQL_BOOKMARK_PERSISTENCE = 82; // for BOOKMARK_PERSISTENCE enum SQL_BP_CLOSE = 1; enum SQL_BP_DELETE = 2; enum SQL_BP_DROP = 4; enum SQL_BP_TRANSACTION = 8; enum SQL_BP_UPDATE = 16; enum SQL_BP_OTHER_HSTMT = 32; enum SQL_BP_SCROLL = 64; enum SQL_C_BINARY = SQL_BINARY; enum SQL_C_BIT = SQL_BIT; enum SQL_C_CHAR = SQL_CHAR; enum SQL_C_DATE = SQL_DATE; enum SQL_C_DOUBLE = SQL_DOUBLE; enum SQL_C_FLOAT = SQL_REAL; enum SQL_C_LONG = SQL_INTEGER; enum SQL_C_SHORT = SQL_SMALLINT; enum SQL_C_SLONG = SQL_C_LONG+SQL_SIGNED_OFFSET; enum SQL_C_SSHORT = SQL_C_SHORT+SQL_SIGNED_OFFSET; enum SQL_C_STINYINT = SQL_TINYINT+SQL_SIGNED_OFFSET; enum SQL_C_TIME = SQL_TIME; enum SQL_C_TIMESTAMP = SQL_TIMESTAMP; enum SQL_C_TINYINT = SQL_TINYINT; enum SQL_C_ULONG = SQL_C_LONG+SQL_UNSIGNED_OFFSET; enum SQL_C_USHORT = SQL_C_SHORT+SQL_UNSIGNED_OFFSET; enum SQL_C_UTINYINT = SQL_TINYINT+SQL_UNSIGNED_OFFSET; enum SQL_C_BOOKMARK = SQL_C_ULONG; enum SQL_C_DEFAULT = 99; enum SQL_CASCADE = 0; enum SQL_CB_NON_NULL = 1; enum SQL_CB_NULL = 0; deprecated { enum SQL_CC_CLOSE = SQL_CB_CLOSE;/* deprecated */ enum SQL_CC_DELETE = SQL_CB_DELETE;/* deprecated */ enum SQL_CC_PRESERVE = SQL_CB_PRESERVE;/* deprecated */ } enum SQL_CD_FALSE = 0L; enum SQL_CD_TRUE = 1L; enum SQL_CN_ANY = 2; enum SQL_CN_DIFFERENT = 1; enum SQL_CN_NONE = 0; enum SQL_COLUMN_ALIAS = 87; enum SQL_COLUMN_COUNT = 0; enum SQL_COLUMN_NAME = 1; enum SQL_COLUMN_DISPLAY_SIZE = 6; enum SQL_COLUMN_LABEL = 18; enum SQL_COLUMN_LENGTH = 3; enum SQL_COLUMN_MONEY = 9; enum SQL_COLUMN_NULLABLE = 7; enum SQL_COLUMN_OWNER_NAME = 16; enum SQL_COLUMN_PRECISION = 4; enum SQL_COLUMN_QUALIFIER_NAME = 17; enum SQL_COLUMN_SCALE = 5; enum SQL_COLUMN_UNSIGNED = 8; enum SQL_COLUMN_UPDATABLE = 10; enum SQL_COLUMN_AUTO_INCREMENT = 11; enum SQL_COLUMN_CASE_SENSITIVE = 12; enum SQL_COLUMN_SEARCHABLE = 13; enum SQL_COLUMN_TYPE = 2; enum SQL_COLUMN_TYPE_NAME = 14; enum SQL_COLUMN_TABLE_NAME = 15; enum SQL_CONCAT_NULL_BEHAVIOR = 22; enum SQL_CONCUR_READ_ONLY = 1; enum SQL_CONCUR_DEFAULT = SQL_CONCUR_READ_ONLY; enum SQL_CONCUR_LOCK = 2; enum SQL_CONCUR_ROWVER = 3; enum SQL_CONCUR_TIMESTAMP = SQL_CONCUR_ROWVER;/* deprecated */ enum SQL_CONCUR_VALUES = 4; enum SQL_CONCURRENCY = 7; enum SQL_CONVERT_BIGINT = 53; enum SQL_CONVERT_BINARY = 54; enum SQL_CONVERT_BIT = 55; enum SQL_CONVERT_CHAR = 56; enum SQL_CONVERT_DATE = 57; enum SQL_CONVERT_DECIMAL = 58; enum SQL_CONVERT_DOUBLE = 59; enum SQL_CONVERT_FLOAT = 60; enum SQL_CONVERT_FUNCTIONS = 48; enum SQL_CONVERT_INTEGER = 61; enum SQL_CONVERT_LONGVARBINARY = 71; enum SQL_CONVERT_LONGVARCHAR = 62; enum SQL_CONVERT_NUMERIC = 63; enum SQL_CONVERT_REAL = 64; enum SQL_CONVERT_SMALLINT = 65; enum SQL_CONVERT_TIME = 66; enum SQL_CONVERT_TIMESTAMP = 67; enum SQL_CONVERT_TINYINT = 68; enum SQL_CONVERT_VARBINARY = 69; enum SQL_CONVERT_VARCHAR = 70; enum SQL_CORRELATION_NAME = 74; enum SQL_CR_CLOSE = SQL_CB_CLOSE;/* deprecated */ enum SQL_CR_DELETE = SQL_CB_DELETE;/* deprecated */ enum SQL_CR_PRESERVE = SQL_CB_PRESERVE;/* deprecated */ enum : ULONG { SQL_CUR_USE_IF_NEEDED = 0, SQL_CUR_USE_ODBC, SQL_CUR_USE_DRIVER, SQL_CUR_DEFAULT = SQL_CUR_USE_DRIVER } enum SQL_CURRENT_QUALIFIER = 109; enum SQL_CURSOR_DYNAMIC = 2UL; enum SQL_CURSOR_FORWARD_ONLY = 0UL; enum SQL_CURSOR_KEYSET_DRIVEN = 1UL; enum SQL_CURSOR_ROLLBACK_BEHAVIOR = 24; enum SQL_CURSOR_STATIC = 3UL; enum SQL_CURSOR_TYPE = 6; enum SQL_CURSOR_TYPE_DEFAULT = SQL_CURSOR_FORWARD_ONLY; enum SQL_CV_CASCADED = 0x00000004L; enum SQL_CV_CHECK_OPTION = 0x00000002L; enum SQL_CV_CREATE_VIEW = 0x00000001L; enum SQL_CV_LOCAL = 0x00000008L; enum SQL_CVT_BIGINT = 0x00004000L; enum SQL_CVT_BINARY = 0x00000400L; enum SQL_CVT_BIT = 0x00001000L; enum SQL_CVT_CHAR = 0x00000001L; enum SQL_CVT_DATE = 0x00008000L; enum SQL_CVT_DECIMAL = 0x00000004L; enum SQL_CVT_DOUBLE = 0x00000080L; enum SQL_CVT_FLOAT = 0x00000020L; enum SQL_CVT_INTEGER = 0x00000008L; enum SQL_CVT_LONGVARBINARY = 0x00040000L; enum SQL_CVT_LONGVARCHAR = 0x00000200L; enum SQL_CVT_NUMERIC = 0x00000002L; enum SQL_CVT_REAL = 0x00000040L; enum SQL_CVT_SMALLINT = 0x00000010L; enum SQL_CVT_TIME = 0x00010000L; enum SQL_CVT_TIMESTAMP = 0x00020000L; enum SQL_CVT_TINYINT = 0x00002000L; enum SQL_CVT_VARBINARY = 0x00000800L; enum SQL_CVT_VARCHAR = 0x00000100L; enum SQL_DATABASE_NAME = 16;/* deprecated */ enum SQL_DEFAULT_PARAM = -5; enum SQL_DELETE = 3; enum SQL_DRIVER_COMPLETE = 1; enum SQL_DRIVER_COMPLETE_REQUIRED = 3; enum SQL_DRIVER_HDBC = 3; enum SQL_DRIVER_HENV = 4; enum SQL_DRIVER_HLIB = 76; enum SQL_DRIVER_HSTMT = 5; enum SQL_DRIVER_NAME = 6; enum SQL_DRIVER_NOPROMPT = 0; enum SQL_DRIVER_ODBC_VER = 77; enum SQL_DRIVER_PROMPT = 2; enum SQL_DRIVER_VER = 7; enum SQL_DTC_ENLIST_EXPENSIVE = 1; enum SQL_DTC_UNENLIST_EXPENSIVE = 2; enum SQL_DTC_TRANSITION_COST = 1750; enum SQL_ENSURE = 1; enum SQL_ENTIRE_ROWSET = 0; enum SQL_EXPRESSIONS_IN_ORDERBY = 27; enum SQL_FD_FETCH_BOOKMARK = 128; enum SQL_FD_FETCH_PREV = SQL_FD_FETCH_PRIOR;/* deprecated */ enum SQL_FD_FETCH_RESUME = 64; enum SQL_FETCH_BOOKMARK = 8; enum SQL_FETCH_PREV = SQL_FETCH_PRIOR;/* deprecated */ enum SQL_FETCH_RESUME = 7;/* deprecated */ enum SQL_FILE_NOT_SUPPORTED = 0x0000; enum SQL_FILE_TABLE = 0x0001; enum SQL_FILE_QUALIFIER = 0x0002; enum SQL_FILE_CATALOG = SQL_FILE_QUALIFIER; enum SQL_FILE_USAGE = 84; enum SQL_FN_CVT_CONVERT = 0x00000001L; enum SQL_FN_NUM_ABS = 0x00000001L; enum SQL_FN_NUM_ACOS = 0x00000002L; enum SQL_FN_NUM_ASIN = 0x00000004L; enum SQL_FN_NUM_ATAN = 0x00000008L; enum SQL_FN_NUM_ATAN2 = 0x00000010L; enum SQL_FN_NUM_CEILING = 0x00000020L; enum SQL_FN_NUM_COS = 0x00000040L; enum SQL_FN_NUM_COT = 0x00000080L; enum SQL_FN_NUM_DEGREES = 0x00040000L; enum SQL_FN_NUM_EXP = 0x00000100L; enum SQL_FN_NUM_FLOOR = 0x00000200L; enum SQL_FN_NUM_LOG = 0x00000400L; enum SQL_FN_NUM_LOG10 = 0x00080000L; enum SQL_FN_NUM_MOD = 0x00000800L; enum SQL_FN_NUM_PI = 0x00010000L; enum SQL_FN_NUM_POWER = 0x00100000L; enum SQL_FN_NUM_RADIANS = 0x00200000L; enum SQL_FN_NUM_RAND = 0x00020000L; enum SQL_FN_NUM_ROUND = 0x00400000L; enum SQL_FN_NUM_SIGN = 0x00001000L; enum SQL_FN_NUM_SIN = 0x00002000L; enum SQL_FN_NUM_SQRT = 0x00004000L; enum SQL_FN_NUM_TAN = 0x00008000L; enum SQL_FN_NUM_TRUNCATE = 0x00800000L; enum SQL_FN_STR_ASCII = 0x00002000L; enum SQL_FN_STR_CHAR = 0x00004000L; enum SQL_FN_STR_CONCAT = 0x00000001L; enum SQL_FN_STR_DIFFERENCE = 0x00008000L; enum SQL_FN_STR_INSERT = 0x00000002L; enum SQL_FN_STR_LCASE = 0x00000040L; enum SQL_FN_STR_LEFT = 0x00000004L; enum SQL_FN_STR_LENGTH = 0x00000010L; enum SQL_FN_STR_LOCATE = 0x00000020L; enum SQL_FN_STR_LOCATE_2 = 0x00010000L; enum SQL_FN_STR_LTRIM = 0x00000008L; enum SQL_FN_STR_REPEAT = 0x00000080L; enum SQL_FN_STR_REPLACE = 0x00000100L; enum SQL_FN_STR_RIGHT = 0x00000200L; enum SQL_FN_STR_RTRIM = 0x00000400L; enum SQL_FN_STR_SOUNDEX = 0x00020000L; enum SQL_FN_STR_SPACE = 0x00040000L; enum SQL_FN_STR_SUBSTRING = 0x00000800L; enum SQL_FN_STR_UCASE = 0x00001000L; enum SQL_FN_SYS_DBNAME = 0x00000002L; enum SQL_FN_SYS_IFNULL = 0x00000004L; enum SQL_FN_SYS_USERNAME = 0x00000001L; enum SQL_FN_TD_CURDATE = 0x00000002L; enum SQL_FN_TD_CURTIME = 0x00000200L; enum SQL_FN_TD_DAYNAME = 0x00008000L; enum SQL_FN_TD_DAYOFMONTH = 0x00000004L; enum SQL_FN_TD_DAYOFWEEK = 0x00000008L; enum SQL_FN_TD_DAYOFYEAR = 0x00000010L; enum SQL_FN_TD_HOUR = 0x00000400L; enum SQL_FN_TD_MINUTE = 0x00000800L; enum SQL_FN_TD_MONTH = 0x00000020L; enum SQL_FN_TD_MONTHNAME = 0x00010000L; enum SQL_FN_TD_NOW = 0x00000001L; enum SQL_FN_TD_QUARTER = 0x00000040L; enum SQL_FN_TD_SECOND = 0x00001000L; enum SQL_FN_TD_TIMESTAMPADD = 0x00002000L; enum SQL_FN_TD_TIMESTAMPDIFF = 0x00004000L; enum SQL_FN_TD_WEEK = 0x00000080L; enum SQL_FN_TD_YEAR = 0x00000100L; enum SQL_FN_TSI_DAY = 0x00000010L; enum SQL_FN_TSI_FRAC_SECOND = 0x00000001L; enum SQL_FN_TSI_HOUR = 0x00000008L; enum SQL_FN_TSI_MINUTE = 0x00000004L; enum SQL_FN_TSI_MONTH = 0x00000040L; enum SQL_FN_TSI_QUARTER = 0x00000080L; enum SQL_FN_TSI_SECOND = 0x00000002L; enum SQL_FN_TSI_WEEK = 0x00000020L; enum SQL_FN_TSI_YEAR = 0x00000100L; enum SQL_GB_GROUP_BY_CONTAINS_SELECT = 2; enum SQL_GB_GROUP_BY_EQUALS_SELECT = 1; enum SQL_GB_NO_RELATION = 3; enum SQL_GB_NOT_SUPPORTED = 0; enum SQL_GD_BLOCK = 4; enum SQL_GD_BOUND = 8; enum SQL_GET_BOOKMARK = 13; enum SQL_GROUP_BY = 88; enum SQL_IGNORE = -6; enum SQL_INFO_FIRST = 0; enum SQL_KEYSET_SIZE = 8; enum SQL_KEYSET_SIZE_DEFAULT = 0UL; enum SQL_KEYWORDS = 89; enum SQL_LCK_EXCLUSIVE = 2; enum SQL_LCK_NO_CHANGE = 1; enum SQL_LCK_UNLOCK = 4; enum SQL_LEN_BINARY_ATTR_OFFSET = -100; enum SQL_LEN_DATA_AT_EXEC_OFFSET = -100; //MACRO #define SQL_LEN_BINARY_ATTR(length) (-(length)+SQL_LEN_BINARY_ATTR_OFFSET) //MACRO #define SQL_LEN_DATA_AT_EXEC(length) (-(length)+SQL_LEN_DATA_AT_EXEC_OFFSET) enum SQL_LIKE_ESCAPE_CLAUSE = 113; enum SQL_LIKE_ONLY = 1; enum SQL_LOCK_EXCLUSIVE = 1; enum SQL_LOCK_NO_CHANGE = 0; enum SQL_LOCK_TYPES = 78; enum SQL_LOCK_UNLOCK = 2; enum SQL_LOGIN_TIMEOUT = 103; enum SQL_LOGIN_TIMEOUT_DEFAULT = 15UL; enum SQL_LONGVARBINARY = -4; enum SQL_LONGVARCHAR = -1; enum SQL_MAX_BINARY_LITERAL_LEN = 112; enum SQL_MAX_CHAR_LITERAL_LEN = 108; enum SQL_MAX_DSN_LENGTH = 32; enum SQL_MAX_LENGTH = 3; enum SQL_MAX_LENGTH_DEFAULT = 0UL; enum SQL_MAX_OPTION_STRING_LENGTH = 256; enum SQL_MAX_OWNER_NAME_LEN = 32; enum SQL_MAX_PROCEDURE_NAME_LEN = 33; enum SQL_MAX_QUALIFIER_NAME_LEN = 34; enum SQL_MAX_ROW_SIZE_INCLUDES_LONG = 103; enum SQL_MAX_ROWS = 1; enum SQL_MAX_ROWS_DEFAULT = 0UL; enum SQL_MODE_READ_WRITE = 0UL; enum SQL_MODE_READ_ONLY = 1UL; enum SQL_MODE_DEFAULT = SQL_MODE_READ_WRITE; enum SQL_MULT_RESULT_SETS = 36; enum SQL_MULTIPLE_ACTIVE_TXN = 37; enum SQL_NC_END = 0x0004; enum SQL_NC_START = 0x0002; enum SQL_NEED_LONG_DATA_LEN = 111; enum SQL_NNC_NON_NULL = 0x0001; enum SQL_NNC_NULL = 0x0000; enum SQL_NO_TOTAL = -4; enum SQL_NON_NULLABLE_COLUMNS = 75; enum SQL_NOSCAN_OFF = 0UL; enum SQL_NOSCAN_ON = 1UL; enum SQL_NOSCAN = 2; enum SQL_NOSCAN_DEFAULT = SQL_NOSCAN_OFF; enum SQL_NUMERIC_FUNCTIONS = 49; enum SQL_OAC_LEVEL1 = 0x0001; enum SQL_OAC_LEVEL2 = 0x0002; enum SQL_OAC_NONE = 0x0000; enum SQL_ODBC_API_CONFORMANCE = 9; enum SQL_ODBC_CURSORS = 110; enum SQL_ODBC_SAG_CLI_CONFORMANCE = 12; enum SQL_ODBC_SQL_CONFORMANCE = 15; enum SQL_ODBC_SQL_OPT_IEF = 73; enum SQL_ODBC_VER = 10; enum SQL_OPT_TRACE = 104; enum SQL_OPT_TRACE_FILE_DEFAULT = "\\SQL.LOG"; enum SQL_OPT_TRACE_OFF = 0UL; enum SQL_OPT_TRACE_DEFAULT = SQL_OPT_TRACE_OFF; enum SQL_OPT_TRACE_ON = 1UL; enum SQL_OPT_TRACEFILE = 105; enum SQL_OSC_CORE = 1; enum SQL_OSC_EXTENDED = 2; enum SQL_OSC_MINIMUM = 0; enum SQL_OSCC_COMPLIANT = 1; enum SQL_OSCC_NOT_COMPLIANT = 0; enum SQL_OU_DML_STATEMENTS = 1; enum SQL_OU_INDEX_DEFINITION = 8; enum SQL_OU_PRIVILEGE_DEFINITION = 16; enum SQL_OU_PROCEDURE_INVOCATION = 2; enum SQL_OU_TABLE_DEFINITION = 4; enum SQL_OUTER_JOINS = 38; enum SQL_OWNER_TERM = 39; enum SQL_OWNER_USAGE = 91; enum SQL_PACKET_SIZE = 112; enum SQL_PARAM_INPUT = 1; enum SQL_PARAM_INPUT_OUTPUT = 2; enum SQL_PARAM_OUTPUT = 4; enum SQL_PARAM_TYPE_DEFAULT = SQL_PARAM_INPUT_OUTPUT; enum SQL_PARAM_TYPE_UNKNOWN = 0; enum SQL_PC_NOT_PSEUDO = 1; enum SQL_POS_ADD = 16; enum SQL_POS_DELETE = 8; enum SQL_POS_OPERATIONS = 79; enum SQL_POS_POSITION = 1; enum SQL_POS_REFRESH = 2; enum SQL_POS_UPDATE = 4; enum SQL_POSITION = 0; enum SQL_POSITIONED_STATEMENTS = 80; enum SQL_PROCEDURE_TERM = 40; enum SQL_PROCEDURES = 21; enum SQL_PS_POSITIONED_DELETE = 1; enum SQL_PS_POSITIONED_UPDATE = 2; enum SQL_PS_SELECT_FOR_UPDATE = 4; enum SQL_PT_FUNCTION = 2; enum SQL_PT_PROCEDURE = 1; enum SQL_PT_UNKNOWN = 0; enum SQL_QL_END = 0x0002; enum SQL_QL_START = 0x0001; enum SQL_QU_DML_STATEMENTS = 1; enum SQL_QU_INDEX_DEFINITION = 8; enum SQL_QU_PRIVILEGE_DEFINITION = 16; enum SQL_QU_PROCEDURE_INVOCATION = 2; enum SQL_QU_TABLE_DEFINITION = 4; enum SQL_QUALIFIER_LOCATION = 114; enum SQL_QUALIFIER_NAME_SEPARATOR = 41; enum SQL_QUALIFIER_TERM = 42; enum SQL_QUALIFIER_USAGE = 92; enum SQL_QUERY_TIMEOUT = 0; enum SQL_QUERY_TIMEOUT_DEFAULT = 0UL; enum SQL_QUICK = 0; enum SQL_QUIET_MODE = 111; enum SQL_QUOTED_IDENTIFIER_CASE = 93; enum SQL_RD_OFF = 0UL; enum SQL_RD_ON = 1UL; enum SQL_RD_DEFAULT = SQL_RD_ON; enum SQL_REFRESH = 1; enum SQL_RESTRICT = 1; enum SQL_RESULT_COL = 3; enum SQL_RETRIEVE_DATA = 11; enum SQL_RETURN_VALUE = 5; enum SQL_ROW_ADDED = 4; enum SQL_ROW_DELETED = 1; enum SQL_ROW_ERROR = 5; enum SQL_ROW_NOROW = 3; enum SQL_ROW_NUMBER = 14; enum SQL_ROW_SUCCESS = 0; enum SQL_ROW_UPDATED = 2; enum SQL_ROW_UPDATES = 11; enum SQL_ROWSET_SIZE = 9; enum SQL_ROWSET_SIZE_DEFAULT = 1UL; enum SQL_ROWVER = 2; enum SQL_SC_NON_UNIQUE = 0UL; enum SQL_SC_TRY_UNIQUE = 1UL; enum SQL_SC_UNIQUE = 2UL; enum SQL_SCCO_OPT_TIMESTAMP = SQL_SCCO_OPT_ROWVER;/* deprecated */ enum SQL_SCROLL_DYNAMIC = -2L;/* deprecated */ enum SQL_SCROLL_FORWARD_ONLY = 0L;/* deprecated */ enum SQL_SCROLL_KEYSET_DRIVEN = -1L;/* deprecated */ enum SQL_SCROLL_OPTIONS = 44; enum SQL_SCROLL_STATIC = -3L;/* deprecated */ enum SQL_SEARCHABLE = 3; enum SQL_SET_NULL = 2; enum SQL_SETPARAM_VALUE_MAX = -1L; enum SQL_SETPOS_MAX_LOCK_VALUE = SQL_LOCK_UNLOCK; enum SQL_SETPOS_MAX_OPTION_VALUE = SQL_ADD; enum SQL_SIMULATE_CURSOR = 10; enum SQL_SO_DYNAMIC = 4; enum SQL_SO_FORWARD_ONLY = 1; enum SQL_SO_KEYSET_DRIVEN = 2; enum SQL_SO_MIXED = 8; enum SQL_SO_STATIC = 16; enum SQL_SQ_COMPARISON = 1; enum SQL_SQ_CORRELATED_SUBQUERIES = 16; enum SQL_SQ_EXISTS = 2; enum SQL_SQ_IN = 4; enum SQL_SQ_QUANTIFIED = 8; enum SQL_SQLSTATE_SIZE = 5; enum SQL_SS_ADDITIONS = 1; enum SQL_SS_DELETIONS = 2; enum SQL_SS_UPDATES = 4; enum SQL_STATIC_SENSITIVITY = 83; enum SQL_STRING_FUNCTIONS = 50; enum SQL_SUBQUERIES = 95; enum SQL_SYSTEM_FUNCTIONS = 51; enum SQL_TABLE_STAT = 0; enum SQL_TABLE_TERM = 45; enum SQL_TIMEDATE_ADD_INTERVALS = 109; enum SQL_TIMEDATE_DIFF_INTERVALS = 110; enum SQL_TIMEDATE_FUNCTIONS = 52; enum SQL_TRANSLATE_DLL = 106; enum SQL_TRANSLATE_OPTION = 107; enum SQL_TXN_ISOLATION = 108; enum SQL_TXN_VERSIONING = 16; enum SQL_TYPE_NULL = 0; enum SQL_U_UNION = 1; enum SQL_U_UNION_ALL = 2; enum SQL_UB_OFF = 0UL; enum SQL_UB_DEFAULT = SQL_UB_OFF; enum SQL_UB_ON = 01UL; enum SQL_UNION = 96; enum SQL_UNSEARCHABLE = 0; enum SQL_UPDATE = 2; enum SQL_USE_BOOKMARKS = 12; enum SQL_VARBINARY = -3; enum SQL_COLATT_OPT_MAX = SQL_COLUMN_LABEL; enum SQL_COLATT_OPT_MIN = SQL_COLUMN_COUNT; enum SQL_PRED_SEARCHABLE = SQL_SEARCHABLE; //MACRO #define SQL_POSITION_TO(s, r) SQLSetPos(s, r, SQL_POSITION, SQL_LOCK_NO_CHANGE) //MACRO #define SQL_LOCK_RECORD(s, r, l) SQLSetPos(s, r, SQL_POSITION, l) //MACRO #define SQL_REFRESH_RECORD(s, r, l) SQLSetPos(s, r, SQL_REFRESH, l) //MACRO #define SQL_UPDATE_RECORD(s, r) SQLSetPos(s, r, SQL_UPDATE, SQL_LOCK_NO_CHANGE) //MACRO #define SQL_DELETE_RECORD(s, r) SQLSetPos(s, r, SQL_DELETE, SQL_LOCK_NO_CHANGE) //MACRO #define SQL_ADD_RECORD(s, r) SQLSetPos(s, r, SQL_ADD, SQL_LOCK_NO_CHANGE) static if (ODBCVER < 0x0300) { enum SQL_CONNECT_OPT_DRVR_START = 1000; enum SQL_CONN_OPT_MAX = SQL_PACKET_SIZE; enum SQL_CONN_OPT_MIN = SQL_ACCESS_MODE; enum SQL_STMT_OPT_MAX = SQL_ROW_NUMBER; enum SQL_STMT_OPT_MIN = SQL_QUERY_TIMEOUT; enum SQL_TYPE_DRIVER_START = SQL_INTERVAL_YEAR; enum SQL_TYPE_DRIVER_END = SQL_UNICODE_LONGVARCHAR; enum SQL_TYPE_MIN = SQL_BIT; enum SQL_TYPE_MAX = SQL_VARCHAR; } static if (ODBCVER < 0x0300) { enum SQL_NO_DATA_FOUND = 100; enum SQL_INTERVAL_YEAR = -80; enum SQL_INTERVAL_MONTH = -81; enum SQL_INTERVAL_YEAR_TO_MONTH = -82; enum SQL_INTERVAL_DAY = -83; enum SQL_INTERVAL_HOUR = -84; enum SQL_INTERVAL_MINUTE = -85; enum SQL_INTERVAL_SECOND = -86; enum SQL_INTERVAL_DAY_TO_HOUR = -87; enum SQL_INTERVAL_DAY_TO_MINUTE = -88; enum SQL_INTERVAL_DAY_TO_SECOND = -89; enum SQL_INTERVAL_HOUR_TO_MINUTE = -90; enum SQL_INTERVAL_HOUR_TO_SECOND = -91; enum SQL_INTERVAL_MINUTE_TO_SECOND = -92; } else { enum SQL_NO_DATA_FOUND = SQL_NO_DATA; enum SQL_CODE_YEAR = 1; enum SQL_CODE_MONTH = 2; enum SQL_CODE_DAY = 3; enum SQL_CODE_HOUR = 4; enum SQL_CODE_MINUTE = 5; enum SQL_CODE_SECOND = 6; enum SQL_CODE_YEAR_TO_MONTH = 7; enum SQL_CODE_DAY_TO_HOUR = 8; enum SQL_CODE_DAY_TO_MINUTE = 9; enum SQL_CODE_DAY_TO_SECOND = 10; enum SQL_CODE_HOUR_TO_MINUTE = 11; enum SQL_CODE_HOUR_TO_SECOND = 12; enum SQL_CODE_MINUTE_TO_SECOND = 13; enum SQL_INTERVAL_YEAR = 100 + SQL_CODE_YEAR; enum SQL_INTERVAL_MONTH = 100 + SQL_CODE_MONTH; enum SQL_INTERVAL_DAY = 100 + SQL_CODE_DAY; enum SQL_INTERVAL_HOUR = 100 + SQL_CODE_HOUR; enum SQL_INTERVAL_MINUTE = 100 + SQL_CODE_MINUTE; enum SQL_INTERVAL_SECOND = 100 + SQL_CODE_SECOND; enum SQL_INTERVAL_YEAR_TO_MONTH = 100 + SQL_CODE_YEAR_TO_MONTH; enum SQL_INTERVAL_DAY_TO_HOUR = 100 + SQL_CODE_DAY_TO_HOUR; enum SQL_INTERVAL_DAY_TO_MINUTE = 100 + SQL_CODE_DAY_TO_MINUTE; enum SQL_INTERVAL_DAY_TO_SECOND = 100 + SQL_CODE_DAY_TO_SECOND; enum SQL_INTERVAL_HOUR_TO_MINUTE = 100 + SQL_CODE_HOUR_TO_MINUTE; enum SQL_INTERVAL_HOUR_TO_SECOND = 100 + SQL_CODE_HOUR_TO_SECOND; enum SQL_INTERVAL_MINUTE_TO_SECOND = 100 + SQL_CODE_MINUTE_TO_SECOND; }//[Yes] #endif static if ((ODBCVER >= 0x0201) && (ODBCVER < 0x0300)) { enum SQL_OJ_CAPABILITIES = 65003; } static if (ODBCVER >= 0x0250) { enum SQL_NO_ACTION = 3; enum SQL_SET_DEFAULT = 4; } static if (ODBCVER >= 0x0300) { enum SQL_ACTIVE_ENVIRONMENTS = 116; enum SQL_AD_ADD_CONSTRAINT_DEFERRABLE = 0x00000080L; enum SQL_AD_ADD_CONSTRAINT_INITIALLY_DEFERRED = 0x00000020L; enum SQL_AD_ADD_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00000040L; enum SQL_AD_ADD_CONSTRAINT_NON_DEFERRABLE = 0x00000100L; enum SQL_AD_ADD_DOMAIN_CONSTRAINT = 0x00000002L; enum SQL_AD_ADD_DOMAIN_DEFAULT = 0x00000008L; enum SQL_AD_CONSTRAINT_NAME_DEFINITION = 0x00000001L; enum SQL_AD_DROP_DOMAIN_CONSTRAINT = 0x00000004L; enum SQL_AD_DROP_DOMAIN_DEFAULT = 0x00000010L; enum SQL_AF_ALL = 0x00000040L; enum SQL_AF_AVG = 0x00000001L; enum SQL_AF_COUNT = 0x00000002L; enum SQL_AF_DISTINCT = 0x00000020L; enum SQL_AF_MAX = 0x00000004L; enum SQL_AF_MIN = 0x00000008L; enum SQL_AF_SUM = 0x00000010L; enum SQL_AGGREGATE_FUNCTIONS = 169; enum SQL_ALL_CATALOGS = "%"; enum SQL_ALL_SCHEMAS = "%"; enum SQL_ALL_TABLE_TYPES = "%"; enum SQL_ALTER_DOMAIN = 117; enum SQL_AM_CONNECTION = 1; enum SQL_AM_NONE = 0; enum SQL_AM_STATEMENT = 2; enum SQL_API_ODBC3_ALL_FUNCTIONS = 999; enum SQL_API_ODBC3_ALL_FUNCTIONS_SIZE = 250; enum SQL_API_SQLALLOCHANDLESTD = 73; enum SQL_API_SQLBULKOPERATIONS = 24; enum SQL_ASYNC_MODE = 10021; enum SQL_AT_ADD_COLUMN_COLLATION = 0x00000080L; enum SQL_AT_ADD_COLUMN_DEFAULT = 0x00000040L; enum SQL_AT_ADD_COLUMN_SINGLE = 0x00000020L; enum SQL_AT_ADD_TABLE_CONSTRAINT = 0x00001000L; enum SQL_AT_CONSTRAINT_DEFERRABLE = 0x00040000L; enum SQL_AT_CONSTRAINT_INITIALLY_DEFERRED = 0x00010000L; enum SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00020000L; enum SQL_AT_CONSTRAINT_NAME_DEFINITION = 0x00008000L; enum SQL_AT_CONSTRAINT_NON_DEFERRABLE = 0x00080000L; enum SQL_AT_DROP_COLUMN_CASCADE = 0x00000400L; enum SQL_AT_DROP_COLUMN_DEFAULT = 0x00000200L; enum SQL_AT_DROP_COLUMN_RESTRICT = 0x00000800L; enum SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE = 0x00002000L; enum SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT = 0x00004000L; enum SQL_AT_SET_COLUMN_DEFAULT = 0x00000100L; enum SQL_ATTR_ACCESS_MODE = SQL_ACCESS_MODE; enum SQL_ATTR_ASYNC_ENABLE = 4; enum SQL_ATTR_AUTOCOMMIT = SQL_AUTOCOMMIT; enum SQL_ATTR_CONCURRENCY = SQL_CONCURRENCY; enum SQL_ATTR_CONNECTION_POOLING = 201; enum SQL_ATTR_CONNECTION_TIMEOUT = 113; enum SQL_ATTR_CP_MATCH = 202; enum SQL_ATTR_CURRENT_CATALOG = SQL_CURRENT_QUALIFIER; enum SQL_ATTR_CURSOR_TYPE = SQL_CURSOR_TYPE; enum SQL_ATTR_DISCONNECT_BEHAVIOR = 114; enum SQL_ATTR_ENABLE_AUTO_IPD = 15; enum SQL_ATTR_ENLIST_IN_DTC = 1207; enum SQL_ATTR_ENLIST_IN_XA = 1208; enum SQL_ATTR_FETCH_BOOKMARK_PTR = 16; enum SQL_ATTR_KEYSET_SIZE = SQL_KEYSET_SIZE; enum SQL_ATTR_LOGIN_TIMEOUT = SQL_LOGIN_TIMEOUT; enum SQL_ATTR_MAX_LENGTH = SQL_MAX_LENGTH; enum SQL_ATTR_MAX_ROWS = SQL_MAX_ROWS; enum SQL_ATTR_NOSCAN = SQL_NOSCAN; enum SQL_ATTR_ODBC_CURSORS = SQL_ODBC_CURSORS; enum SQL_ATTR_ODBC_VERSION = 200; enum SQL_ATTR_PACKET_SIZE = SQL_PACKET_SIZE; enum SQL_ATTR_PARAM_BIND_OFFSET_PTR = 17; enum SQL_ATTR_PARAM_BIND_TYPE = 18; enum SQL_ATTR_PARAM_OPERATION_PTR = 19; enum SQL_ATTR_PARAM_STATUS_PTR = 20; enum SQL_ATTR_PARAMS_PROCESSED_PTR = 21; enum SQL_ATTR_PARAMSET_SIZE = 22; enum SQL_ATTR_QUERY_TIMEOUT = SQL_QUERY_TIMEOUT; enum SQL_ATTR_QUIET_MODE = SQL_QUIET_MODE; enum SQL_ATTR_RETRIEVE_DATA = SQL_RETRIEVE_DATA; enum SQL_ATTR_ROW_ARRAY_SIZE = 27; enum SQL_ATTR_ROW_BIND_OFFSET_PTR = 23; enum SQL_ATTR_ROW_BIND_TYPE = SQL_BIND_TYPE; enum SQL_ATTR_ROW_NUMBER = SQL_ROW_NUMBER; enum SQL_ATTR_ROW_OPERATION_PTR = 24; enum SQL_ATTR_ROW_STATUS_PTR = 25; enum SQL_ATTR_ROWS_FETCHED_PTR = 26; enum SQL_ATTR_SIMULATE_CURSOR = SQL_SIMULATE_CURSOR; enum SQL_ATTR_TRACE = SQL_OPT_TRACE; enum SQL_ATTR_TRACEFILE = SQL_OPT_TRACEFILE; enum SQL_ATTR_TRANSLATE_LIB = SQL_TRANSLATE_DLL; enum SQL_ATTR_TRANSLATE_OPTION = SQL_TRANSLATE_OPTION; enum SQL_ATTR_TXN_ISOLATION = SQL_TXN_ISOLATION; enum SQL_ATTR_USE_BOOKMARKS = SQL_USE_BOOKMARKS; enum SQL_BATCH_ROW_COUNT = 120; enum SQL_BATCH_SUPPORT = 121; enum SQL_BRC_EXPLICIT = 0x0000002; enum SQL_BRC_PROCEDURES = 0x0000001; enum SQL_BRC_ROLLED_UP = 0x0000004; enum SQL_BS_ROW_COUNT_EXPLICIT = 0x00000002L; enum SQL_BS_ROW_COUNT_PROC = 0x00000008L; enum SQL_BS_SELECT_EXPLICIT = 0x00000001L; enum SQL_BS_SELECT_PROC = 0x00000004L; enum SQL_C_INTERVAL_DAY = SQL_INTERVAL_DAY; enum SQL_C_INTERVAL_DAY_TO_HOUR = SQL_INTERVAL_DAY_TO_HOUR; enum SQL_C_INTERVAL_DAY_TO_MINUTE = SQL_INTERVAL_DAY_TO_MINUTE; enum SQL_C_INTERVAL_DAY_TO_SECOND = SQL_INTERVAL_DAY_TO_SECOND; enum SQL_C_INTERVAL_HOUR = SQL_INTERVAL_HOUR; enum SQL_C_INTERVAL_HOUR_TO_MINUTE = SQL_INTERVAL_HOUR_TO_MINUTE; enum SQL_C_INTERVAL_HOUR_TO_SECOND = SQL_INTERVAL_HOUR_TO_SECOND; enum SQL_C_INTERVAL_MINUTE = SQL_INTERVAL_MINUTE; enum SQL_C_INTERVAL_MINUTE_TO_SECOND = SQL_INTERVAL_MINUTE_TO_SECOND; enum SQL_C_INTERVAL_MONTH = SQL_INTERVAL_MONTH; enum SQL_C_INTERVAL_SECOND = SQL_INTERVAL_SECOND; enum SQL_C_INTERVAL_YEAR = SQL_INTERVAL_YEAR; enum SQL_C_INTERVAL_YEAR_TO_MONTH = SQL_INTERVAL_YEAR_TO_MONTH; enum SQL_C_NUMERIC = SQL_NUMERIC; enum SQL_C_SBIGINT = SQL_BIGINT+SQL_SIGNED_OFFSET; enum SQL_C_TYPE_DATE = SQL_TYPE_DATE; enum SQL_C_TYPE_TIME = SQL_TYPE_TIME; enum SQL_C_TYPE_TIMESTAMP = SQL_TYPE_TIMESTAMP; enum SQL_C_UBIGINT = SQL_BIGINT+SQL_UNSIGNED_OFFSET; enum SQL_C_VARBOOKMARK = SQL_C_BINARY; enum SQL_CA_CONSTRAINT_DEFERRABLE = 0x00000040L; enum SQL_CA_CONSTRAINT_INITIALLY_DEFERRED = 0x00000010L; enum SQL_CA_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00000020L; enum SQL_CA_CONSTRAINT_NON_DEFERRABLE = 0x00000080L; enum SQL_CA_CREATE_ASSERTION = 0x00000001L; enum SQL_CA1_ABSOLUTE = 0x00000002L; enum SQL_CA1_BOOKMARK = 0x00000008L; enum SQL_CA1_BULK_ADD = 0x00010000L; enum SQL_CA1_BULK_DELETE_BY_BOOKMARK = 0x00040000L; enum SQL_CA1_BULK_FETCH_BY_BOOKMARK = 0x00080000L; enum SQL_CA1_BULK_UPDATE_BY_BOOKMARK = 0x00020000L; enum SQL_CA1_LOCK_EXCLUSIVE = 0x00000080L; enum SQL_CA1_LOCK_NO_CHANGE = 0x00000040L; enum SQL_CA1_LOCK_UNLOCK = 0x00000100L; enum SQL_CA1_NEXT = 0x00000001L; enum SQL_CA1_POS_DELETE = 0x00000800L; enum SQL_CA1_POS_POSITION = 0x00000200L; enum SQL_CA1_POS_REFRESH = 0x00001000L; enum SQL_CA1_POS_UPDATE = 0x00000400L; enum SQL_CA1_POSITIONED_DELETE = 0x00004000L; enum SQL_CA1_POSITIONED_UPDATE = 0x00002000L; enum SQL_CA1_RELATIVE = 0x00000004L; enum SQL_CA1_SELECT_FOR_UPDATE = 0x00008000L; enum SQL_CA2_CRC_APPROXIMATE = 0x00002000L; enum SQL_CA2_CRC_EXACT = 0x00001000L; enum SQL_CA2_LOCK_CONCURRENCY = 0x00000002L; enum SQL_CA2_MAX_ROWS_CATALOG = 0x00000800L; enum SQL_CA2_MAX_ROWS_DELETE = 0x00000200L; enum SQL_CA2_MAX_ROWS_INSERT = 0x00000100L; enum SQL_CA2_MAX_ROWS_SELECT = 0x00000080L; enum SQL_CA2_MAX_ROWS_UPDATE = 0x00000400L; enum SQL_CA2_MAX_ROWS_AFFECTS_ALL = SQL_CA2_MAX_ROWS_SELECT | SQL_CA2_MAX_ROWS_INSERT | SQL_CA2_MAX_ROWS_DELETE | SQL_CA2_MAX_ROWS_UPDATE | SQL_CA2_MAX_ROWS_CATALOG; enum SQL_CA2_OPT_ROWVER_CONCURRENCY = 0x00000004L; enum SQL_CA2_OPT_VALUES_CONCURRENCY = 0x00000008L; enum SQL_CA2_READ_ONLY_CONCURRENCY = 0x00000001L; enum SQL_CA2_SENSITIVITY_ADDITIONS = 0x00000010L; enum SQL_CA2_SENSITIVITY_DELETIONS = 0x00000020L; enum SQL_CA2_SENSITIVITY_UPDATES = 0x00000040L; enum SQL_CA2_SIMULATE_NON_UNIQUE = 0x00004000L; enum SQL_CA2_SIMULATE_TRY_UNIQUE = 0x00008000L; enum SQL_CA2_SIMULATE_UNIQUE = 0x00010000L; enum SQL_CATALOG_LOCATION = SQL_QUALIFIER_LOCATION; enum SQL_CATALOG_NAME_SEPARATOR = SQL_QUALIFIER_NAME_SEPARATOR; enum SQL_CATALOG_TERM = SQL_QUALIFIER_TERM; enum SQL_CATALOG_USAGE = SQL_QUALIFIER_USAGE; enum SQL_CCOL_CREATE_COLLATION = 0x00000001L; enum SQL_CCS_COLLATE_CLAUSE = 0x00000002L; enum SQL_CCS_CREATE_CHARACTER_SET = 0x00000001L; enum SQL_CCS_LIMITED_COLLATION = 0x00000004L; enum SQL_CDO_COLLATION = 0x00000008L; enum SQL_CDO_CONSTRAINT = 0x00000004L; enum SQL_CDO_CONSTRAINT_DEFERRABLE = 0x00000080L; enum SQL_CDO_CONSTRAINT_INITIALLY_DEFERRED = 0x00000020L; enum SQL_CDO_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00000040L; enum SQL_CDO_CONSTRAINT_NAME_DEFINITION = 0x00000010L; enum SQL_CDO_CONSTRAINT_NON_DEFERRABLE = 0x00000100L; enum SQL_CDO_CREATE_DOMAIN = 0x00000001L; enum SQL_CDO_DEFAULT = 0x00000002L; enum SQL_CL_END = SQL_QL_END; enum SQL_CL_START = SQL_QL_START; enum SQL_COL_PRED_BASIC = SQL_ALL_EXCEPT_LIKE; enum SQL_COL_PRED_CHAR = SQL_LIKE_ONLY; enum SQL_COLUMN_DRIVER_START = 1000; enum SQL_COLUMN_IGNORE = SQL_IGNORE; enum SQL_COLUMN_NUMBER_UNKNOWN = -2; enum SQL_CONVERT_GUID = 173; enum SQL_CONVERT_WCHAR = 122; enum SQL_CONVERT_INTERVAL_DAY_TIME = 123; enum SQL_CONVERT_INTERVAL_YEAR_MONTH = 124; enum SQL_CONVERT_WLONGVARCHAR = 125; enum SQL_CONVERT_WVARCHAR = 126; enum SQL_CREATE_ASSERTION = 127; enum SQL_CREATE_CHARACTER_SET = 128; enum SQL_CREATE_COLLATION = 129; enum SQL_CREATE_DOMAIN = 130; enum SQL_CREATE_SCHEMA = 131; enum SQL_CREATE_TABLE = 132; enum SQL_CREATE_TRANSLATION = 133; enum SQL_CREATE_VIEW = 134; enum SQL_CP_OFF = 0UL; enum SQL_CP_DEFAULT = SQL_CP_OFF; enum SQL_CP_ONE_PER_DRIVER = 1UL; enum SQL_CP_ONE_PER_HENV = 2UL; enum SQL_CP_STRICT_MATCH = 0UL; enum SQL_CP_MATCH_DEFAULT = SQL_CP_STRICT_MATCH; enum SQL_CP_RELAXED_MATCH = 1UL; enum SQL_CS_CREATE_SCHEMA = 0x00000001L; enum SQL_CS_AUTHORIZATION = 0x00000002L; enum SQL_CS_DEFAULT_CHARACTER_SET = 0x00000004L; enum SQL_CT_COLUMN_COLLATION = 0x00000800L; enum SQL_CT_COLUMN_CONSTRAINT = 0x00000200L; enum SQL_CT_COLUMN_DEFAULT = 0x00000400L; enum SQL_CT_COMMIT_DELETE = 0x00000004L; enum SQL_CT_COMMIT_PRESERVE = 0x00000002L; enum SQL_CT_CONSTRAINT_DEFERRABLE = 0x00000080L; enum SQL_CT_CONSTRAINT_INITIALLY_DEFERRED = 0x00000020L; enum SQL_CT_CONSTRAINT_INITIALLY_IMMEDIATE = 0x00000040L; enum SQL_CT_CONSTRAINT_NAME_DEFINITION = 0x00002000L; enum SQL_CT_CONSTRAINT_NON_DEFERRABLE = 0x00000100L; enum SQL_CT_CREATE_TABLE = 0x00000001L; enum SQL_CT_GLOBAL_TEMPORARY = 0x00000008L; enum SQL_CT_LOCAL_TEMPORARY = 0x00000010L; enum SQL_CT_TABLE_CONSTRAINT = 0x00001000L; enum SQL_CTR_CREATE_TRANSLATION = 0x00000001L; enum SQL_CU_DML_STATEMENTS = SQL_QU_DML_STATEMENTS; enum SQL_CU_INDEX_DEFINITION = SQL_QU_INDEX_DEFINITION; enum SQL_CU_PRIVILEGE_DEFINITION = SQL_QU_PRIVILEGE_DEFINITION; enum SQL_CU_PROCEDURE_INVOCATION = SQL_QU_PROCEDURE_INVOCATION; enum SQL_CU_TABLE_DEFINITION = SQL_QU_TABLE_DEFINITION; enum SQL_CVT_INTERVAL_YEAR_MONTH = 0x00080000L; enum SQL_CVT_INTERVAL_DAY_TIME = 0x00100000L; enum SQL_CVT_WCHAR = 0x00200000L; enum SQL_CVT_WLONGVARCHAR = 0x00400000L; enum SQL_CVT_WVARCHAR = 0x00800000L; enum SQL_CVT_GUID = 0x01000000L; enum SQL_DA_DROP_ASSERTION = 0x00000001L; enum SQL_DATETIME_LITERALS = 119; enum SQL_DB_DISCONNECT = 1UL; enum SQL_DB_RETURN_TO_POOL = 0UL; enum SQL_DB_DEFAULT = SQL_DB_RETURN_TO_POOL; enum SQL_DC_DROP_COLLATION = 0x00000001L; enum SQL_DCS_DROP_CHARACTER_SET = 0x00000001L; enum SQL_DD_CASCADE = 0x00000004L; enum SQL_DD_DROP_DOMAIN = 0x00000001L; enum SQL_DD_RESTRICT = 0x00000002L; enum SQL_DDL_INDEX = 170; enum SQL_DELETE_BY_BOOKMARK = 6; enum SQL_DESC_ARRAY_SIZE = 20; enum SQL_DESC_ARRAY_STATUS_PTR = 21; enum SQL_DESC_AUTO_UNIQUE_VALUE = SQL_COLUMN_AUTO_INCREMENT; enum SQL_DESC_BASE_COLUMN_NAME = 22; enum SQL_DESC_BASE_TABLE_NAME = 23; enum SQL_DESC_BIND_OFFSET_PTR = 24; enum SQL_DESC_BIND_TYPE = 25; enum SQL_DESC_CASE_SENSITIVE = SQL_COLUMN_CASE_SENSITIVE; enum SQL_DESC_CATALOG_NAME = SQL_COLUMN_QUALIFIER_NAME; enum SQL_DESC_CONCISE_TYPE = SQL_COLUMN_TYPE; enum SQL_DESC_DATETIME_INTERVAL_PRECISION = 26; enum SQL_DESC_DISPLAY_SIZE = SQL_COLUMN_DISPLAY_SIZE; enum SQL_DESC_FIXED_PREC_SCALE = SQL_COLUMN_MONEY; enum SQL_DESC_LABEL = SQL_COLUMN_LABEL; enum SQL_DESC_LITERAL_PREFIX = 27; enum SQL_DESC_LITERAL_SUFFIX = 28; enum SQL_DESC_LOCAL_TYPE_NAME = 29; enum SQL_DESC_MAXIMUM_SCALE = 30; enum SQL_DESC_MINIMUM_SCALE = 31; enum SQL_DESC_NUM_PREC_RADIX = 32; enum SQL_DESC_PARAMETER_TYPE = 33; enum SQL_DESC_ROWS_PROCESSED_PTR = 34; enum SQL_DESC_SCHEMA_NAME = SQL_COLUMN_OWNER_NAME; enum SQL_DESC_SEARCHABLE = SQL_COLUMN_SEARCHABLE; enum SQL_DESC_TABLE_NAME = SQL_COLUMN_TABLE_NAME; enum SQL_DESC_TYPE_NAME = SQL_COLUMN_TYPE_NAME; enum SQL_DESC_UNSIGNED = SQL_COLUMN_UNSIGNED; enum SQL_DESC_UPDATABLE = SQL_COLUMN_UPDATABLE; enum SQL_DI_CREATE_INDEX = 0x00000001L; enum SQL_DI_DROP_INDEX = 0x00000002L; enum SQL_DIAG_COLUMN_NUMBER = -1247; enum SQL_DIAG_ROW_NUMBER = -1248; enum SQL_DIAG_CURSOR_ROW_COUNT = -1249; enum SQL_DL_SQL92_DATE = 0x00000001L; enum SQL_DL_SQL92_INTERVAL_DAY = 0x00000020L; enum SQL_DL_SQL92_INTERVAL_DAY_TO_HOUR = 0x00000400L; enum SQL_DL_SQL92_INTERVAL_DAY_TO_MINUTE = 0x00000800L; enum SQL_DL_SQL92_INTERVAL_DAY_TO_SECOND = 0x00001000L; enum SQL_DL_SQL92_INTERVAL_HOUR = 0x00000040L; enum SQL_DL_SQL92_INTERVAL_HOUR_TO_MINUTE = 0x00002000L; enum SQL_DL_SQL92_INTERVAL_HOUR_TO_SECOND = 0x00004000L; enum SQL_DL_SQL92_INTERVAL_MINUTE = 0x00000080L; enum SQL_DL_SQL92_INTERVAL_MINUTE_TO_SECOND = 0x00008000L; enum SQL_DL_SQL92_INTERVAL_MONTH = 0x00000010L; enum SQL_DL_SQL92_INTERVAL_SECOND = 0x00000100L; enum SQL_DL_SQL92_INTERVAL_YEAR = 0x00000008L; enum SQL_DL_SQL92_INTERVAL_YEAR_TO_MONTH = 0x00000200L; enum SQL_DL_SQL92_TIME = 0x00000002L; enum SQL_DL_SQL92_TIMESTAMP = 0x00000004L; enum SQL_DM_VER = 171; enum SQL_DRIVER_HDESC = 135; enum SQL_DROP_ASSERTION = 136; enum SQL_DROP_CHARACTER_SET = 137; enum SQL_DROP_COLLATION = 138; enum SQL_DROP_DOMAIN = 139; enum SQL_DROP_SCHEMA = 140; enum SQL_DROP_TABLE = 141; enum SQL_DROP_TRANSLATION = 142; enum SQL_DROP_VIEW = 143; enum SQL_DS_CASCADE = 0x00000004L; enum SQL_DS_DROP_SCHEMA = 0x00000001L; enum SQL_DS_RESTRICT = 0x00000002L; enum SQL_DT_CASCADE = 0x00000004L; enum SQL_DT_DROP_TABLE = 0x00000001L; enum SQL_DT_RESTRICT = 0x00000002L; enum SQL_DTC_DONE = 0L; enum SQL_DTR_DROP_TRANSLATION = 0x00000001L; enum SQL_DV_CASCADE = 0x00000004L; enum SQL_DV_DROP_VIEW = 0x00000001L; enum SQL_DV_RESTRICT = 0x00000002L; enum SQL_DYNAMIC_CURSOR_ATTRIBUTES1 = 144; enum SQL_DYNAMIC_CURSOR_ATTRIBUTES2 = 145; enum SQL_EXT_API_LAST = SQL_API_SQLBINDPARAMETER; enum SQL_EXT_API_START = 40; enum SQL_FETCH_BY_BOOKMARK = 7; enum SQL_FETCH_FIRST_SYSTEM = 32; enum SQL_FETCH_FIRST_USER = 31; enum SQL_FN_CVT_CAST = 0x00000002L; enum SQL_FN_STR_BIT_LENGTH = 0x00080000L; enum SQL_FN_STR_CHAR_LENGTH = 0x00100000L; enum SQL_FN_STR_CHARACTER_LENGTH = 0x00200000L; enum SQL_FN_STR_OCTET_LENGTH = 0x00400000L; enum SQL_FN_STR_POSITION = 0x00800000L; enum SQL_FN_TD_CURRENT_DATE = 0x00020000L; enum SQL_FN_TD_CURRENT_TIME = 0x00040000L; enum SQL_FN_TD_CURRENT_TIMESTAMP = 0x00080000L; enum SQL_FN_TD_EXTRACT = 0x00100000L; enum SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 = 146; enum SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 = 147; /* #define SQL_FUNC_EXISTS(exists, api) ((*(((UWORD*) (exists)) + ((api) >> 4)) & (1 << ((api) & 15)) ) ? SQL_TRUE : SQL_FALSE ) */ enum SQL_GB_COLLATE = 0x0004; enum SQL_HANDLE_SENV = 5; enum SQL_IK_NONE = 0; enum SQL_IK_ASC = 1; enum SQL_IK_DESC = 2; enum SQL_IK_ALL = SQL_IK_ASC | SQL_IK_DESC; enum SQL_INDEX_KEYWORDS = 148; enum SQL_INFO_DRIVER_START = 1000; enum SQL_INFO_LAST = SQL_QUALIFIER_LOCATION; enum SQL_INFO_SCHEMA_VIEWS = 149; enum SQL_INITIALLY_DEFERRED = 5; enum SQL_INITIALLY_IMMEDIATE = 6; enum SQL_INSERT_STATEMENT = 172; enum SQL_INTERVAL = 10; enum SQL_IS_INSERT_LITERALS = 0x00000001L; enum SQL_IS_INSERT_SEARCHED = 0x00000002L; enum SQL_IS_INTEGER = -6; enum SQL_IS_POINTER = -4; enum SQL_IS_SELECT_INTO = 0x00000004L; enum SQL_IS_SMALLINT = -8; enum SQL_IS_UINTEGER = -5; enum SQL_IS_USMALLINT = -7; enum SQL_ISV_ASSERTIONS = 0x00000001L; enum SQL_ISV_CHARACTER_SETS = 0x00000002L; enum SQL_ISV_CHECK_CONSTRAINTS = 0x00000004L; enum SQL_ISV_COLLATIONS = 0x00000008L; enum SQL_ISV_COLUMN_DOMAIN_USAGE = 0x00000010L; enum SQL_ISV_COLUMN_PRIVILEGES = 0x00000020L; enum SQL_ISV_COLUMNS = 0x00000040L; enum SQL_ISV_CONSTRAINT_COLUMN_USAGE = 0x00000080L; enum SQL_ISV_CONSTRAINT_TABLE_USAGE = 0x00000100L; enum SQL_ISV_DOMAIN_CONSTRAINTS = 0x00000200L; enum SQL_ISV_DOMAINS = 0x00000400L; enum SQL_ISV_KEY_COLUMN_USAGE = 0x00000800L; enum SQL_ISV_REFERENTIAL_CONSTRAINTS = 0x00001000L; enum SQL_ISV_SCHEMATA = 0x00002000L; enum SQL_ISV_SQL_LANGUAGES = 0x00004000L; enum SQL_ISV_TABLE_CONSTRAINTS = 0x00008000L; enum SQL_ISV_TABLE_PRIVILEGES = 0x00010000L; enum SQL_ISV_TABLES = 0x00020000L; enum SQL_ISV_TRANSLATIONS = 0x00040000L; enum SQL_ISV_USAGE_PRIVILEGES = 0x00080000L; enum SQL_ISV_VIEW_COLUMN_USAGE = 0x00100000L; enum SQL_ISV_VIEW_TABLE_USAGE = 0x00200000L; enum SQL_ISV_VIEWS = 0x00400000L; enum SQL_KEYSET_CURSOR_ATTRIBUTES1 = 150; enum SQL_KEYSET_CURSOR_ATTRIBUTES2 = 151; enum SQL_MAX_ASYNC_CONCURRENT_STATEMENTS = 10022; enum SQL_NO_COLUMN_NUMBER = -1; enum SQL_NO_ROW_NUMBER = -1; enum SQL_NOT_DEFERRABLE = 7; enum SQL_NUM_EXTENSIONS = SQL_EXT_API_LAST-SQL_EXT_API_START+1; enum SQL_NUM_FUNCTIONS = 23; enum SQL_ODBC_INTERFACE_CONFORMANCE = 152; enum : ULONG { SQL_OIC_CORE = 1, SQL_OIC_LEVEL1, SQL_OIC_LEVEL2 } enum : ULONG { SQL_OV_ODBC2 = 2, SQL_OV_ODBC3 = 3 } enum ULONG SQL_PARAM_BIND_BY_COLUMN = 0, SQL_PARAM_BIND_TYPE_DEFAULT = SQL_PARAM_BIND_BY_COLUMN; enum SQL_PARAM_ARRAY_ROW_COUNTS = 153; enum SQL_PARAM_ARRAY_SELECTS = 154; enum SQL_PARAM_DIAG_UNAVAILABLE = 1; enum SQL_PARAM_ERROR = 5; enum SQL_PARAM_IGNORE = 1; enum SQL_PARAM_PROCEED = 0; enum SQL_PARAM_SUCCESS = 0; enum SQL_PARAM_SUCCESS_WITH_INFO = 6; enum SQL_PARAM_UNUSED = 7; enum SQL_PARC_BATCH = 1; enum SQL_PARC_NO_BATCH = 2; enum SQL_PAS_BATCH = 1; enum SQL_PAS_NO_BATCH = 2; enum SQL_PAS_NO_SELECT = 3; enum SQL_ROW_IGNORE = 1; enum SQL_ROW_NUMBER_UNKNOWN = -2; enum SQL_ROW_PROCEED = 0; enum SQL_ROW_SUCCESS_WITH_INFO = 6; enum SQL_SC_FIPS127_2_TRANSITIONAL = 0x00000002L; enum SQL_SC_SQL92_ENTRY = 0x00000001L; enum SQL_SC_SQL92_FULL = 0x00000008L; enum SQL_SC_SQL92_INTERMEDIATE = 0x00000004L; enum SQL_SCC_ISO92_CLI = 0x00000002L; enum SQL_SCC_XOPEN_CLI_VERSION1 = 0x00000001L; enum SQL_SCHEMA_TERM = SQL_OWNER_TERM; enum SQL_SCHEMA_USAGE = SQL_OWNER_USAGE; enum SQL_SDF_CURRENT_DATE = 0x00000001L; enum SQL_SDF_CURRENT_TIME = 0x00000002L; enum SQL_SDF_CURRENT_TIMESTAMP = 0x00000004L; enum SQL_SFKD_CASCADE = 0x00000001L; enum SQL_SFKD_NO_ACTION = 0x00000002L; enum SQL_SFKD_SET_DEFAULT = 0x00000004L; enum SQL_SFKD_SET_NULL = 0x00000008L; enum SQL_SFKU_CASCADE = 0x00000001L; enum SQL_SFKU_NO_ACTION = 0x00000002L; enum SQL_SFKU_SET_DEFAULT = 0x00000004L; enum SQL_SFKU_SET_NULL = 0x00000008L; enum SQL_SG_DELETE_TABLE = 0x00000020L; enum SQL_SG_INSERT_COLUMN = 0x00000080L; enum SQL_SG_INSERT_TABLE = 0x00000040L; enum SQL_SG_REFERENCES_COLUMN = 0x00000200L; enum SQL_SG_REFERENCES_TABLE = 0x00000100L; enum SQL_SG_SELECT_TABLE = 0x00000400L; enum SQL_SG_UPDATE_COLUMN = 0x00001000L; enum SQL_SG_UPDATE_TABLE = 0x00000800L; enum SQL_SG_USAGE_ON_CHARACTER_SET = 0x00000002L; enum SQL_SG_USAGE_ON_COLLATION = 0x00000004L; enum SQL_SG_USAGE_ON_DOMAIN = 0x00000001L; enum SQL_SG_USAGE_ON_TRANSLATION = 0x00000008L; enum SQL_SG_WITH_GRANT_OPTION = 0x00000010L; enum SQL_SNVF_BIT_LENGTH = 0x00000001L; enum SQL_SNVF_CHAR_LENGTH = 0x00000002L; enum SQL_SNVF_CHARACTER_LENGTH = 0x00000004L; enum SQL_SNVF_EXTRACT = 0x00000008L; enum SQL_SNVF_OCTET_LENGTH = 0x00000010L; enum SQL_SNVF_POSITION = 0x00000020L; enum SQL_SP_BETWEEN = 0x00000800L; enum SQL_SP_COMPARISON = 0x00001000L; enum SQL_SP_EXISTS = 0x00000001L; enum SQL_SP_IN = 0x00000400L; enum SQL_SP_ISNOTNULL = 0x00000002L; enum SQL_SP_ISNULL = 0x00000004L; enum SQL_SP_LIKE = 0x00000200L; enum SQL_SP_MATCH_FULL = 0x00000008L; enum SQL_SP_MATCH_PARTIAL = 0x00000010L; enum SQL_SP_MATCH_UNIQUE_FULL = 0x00000020L; enum SQL_SP_MATCH_UNIQUE_PARTIAL = 0x00000040L; enum SQL_SP_OVERLAPS = 0x00000080L; enum SQL_SP_QUANTIFIED_COMPARISON = 0x00002000L; enum SQL_SP_UNIQUE = 0x00000100L; enum SQL_SQL_CONFORMANCE = 118; enum SQL_SQL92_DATETIME_FUNCTIONS = 155; enum SQL_SQL92_FOREIGN_KEY_DELETE_RULE = 156; enum SQL_SQL92_FOREIGN_KEY_UPDATE_RULE = 157; enum SQL_SQL92_GRANT = 158; enum SQL_SQL92_NUMERIC_VALUE_FUNCTIONS = 159; enum SQL_SQL92_PREDICATES = 160; enum SQL_SQL92_RELATIONAL_JOIN_OPERATORS = 161; enum SQL_SQL92_REVOKE = 162; enum SQL_SQL92_ROW_VALUE_CONSTRUCTOR = 163; enum SQL_SQL92_STRING_FUNCTIONS = 164; enum SQL_SQL92_VALUE_EXPRESSIONS = 165; enum SQL_SR_CASCADE = 0x00000020L; enum SQL_SR_DELETE_TABLE = 0x00000080L; enum SQL_SR_GRANT_OPTION_FOR = 0x00000010L; enum SQL_SR_INSERT_COLUMN = 0x00000200L; enum SQL_SR_INSERT_TABLE = 0x00000100L; enum SQL_SR_REFERENCES_COLUMN = 0x00000800L; enum SQL_SR_REFERENCES_TABLE = 0x00000400L; enum SQL_SR_RESTRICT = 0x00000040L; enum SQL_SR_SELECT_TABLE = 0x00001000L; enum SQL_SR_UPDATE_COLUMN = 0x00004000L; enum SQL_SR_UPDATE_TABLE = 0x00002000L; enum SQL_SR_USAGE_ON_CHARACTER_SET = 0x00000002L; enum SQL_SR_USAGE_ON_COLLATION = 0x00000004L; enum SQL_SR_USAGE_ON_DOMAIN = 0x00000001L; enum SQL_SR_USAGE_ON_TRANSLATION = 0x00000008L; enum SQL_SRJO_CORRESPONDING_CLAUSE = 0x00000001L; enum SQL_SRJO_CROSS_JOIN = 0x00000002L; enum SQL_SRJO_EXCEPT_JOIN = 0x00000004L; enum SQL_SRJO_FULL_OUTER_JOIN = 0x00000008L; enum SQL_SRJO_INNER_JOIN = 0x00000010L; enum SQL_SRJO_INTERSECT_JOIN = 0x00000020L; enum SQL_SRJO_LEFT_OUTER_JOIN = 0x00000040L; enum SQL_SRJO_NATURAL_JOIN = 0x00000080L; enum SQL_SRJO_RIGHT_OUTER_JOIN = 0x00000100L; enum SQL_SRJO_UNION_JOIN = 0x00000200L; enum SQL_SRVC_DEFAULT = 0x00000004L; enum SQL_SRVC_NULL = 0x00000002L; enum SQL_SRVC_ROW_SUBQUERY = 0x00000008L; enum SQL_SRVC_VALUE_EXPRESSION = 0x00000001L; enum SQL_SSF_CONVERT = 0x00000001L; enum SQL_SSF_LOWER = 0x00000002L; enum SQL_SSF_SUBSTRING = 0x00000008L; enum SQL_SSF_TRANSLATE = 0x00000010L; enum SQL_SSF_TRIM_BOTH = 0x00000020L; enum SQL_SSF_TRIM_LEADING = 0x00000040L; enum SQL_SSF_TRIM_TRAILING = 0x00000080L; enum SQL_SSF_UPPER = 0x00000004L; enum SQL_STANDARD_CLI_CONFORMANCE = 166; enum SQL_STATIC_CURSOR_ATTRIBUTES1 = 167; enum SQL_STATIC_CURSOR_ATTRIBUTES2 = 168; enum SQL_SU_DML_STATEMENTS = SQL_OU_DML_STATEMENTS; enum SQL_SU_INDEX_DEFINITION = SQL_OU_INDEX_DEFINITION; enum SQL_SU_PRIVILEGE_DEFINITION = SQL_OU_PRIVILEGE_DEFINITION; enum SQL_SU_PROCEDURE_INVOCATION = SQL_OU_PROCEDURE_INVOCATION; enum SQL_SU_TABLE_DEFINITION = SQL_OU_TABLE_DEFINITION; enum SQL_SVE_CASE = 0x00000001L; enum SQL_SVE_CAST = 0x00000002L; enum SQL_SVE_COALESCE = 0x00000004L; enum SQL_SVE_NULLIF = 0x00000008L; enum SQL_UB_FIXED = SQL_UB_ON; enum SQL_UB_VARIABLE = 2UL; enum SQL_UNION_STATEMENT = SQL_UNION; enum SQL_UPDATE_BY_BOOKMARK = 5; enum SQL_US_UNION = SQL_U_UNION; enum SQL_US_UNION_ALL = SQL_U_UNION_ALL; }//[Yes] #endif /* ODBCVER >= 0x300 */ static if (ODBCVER >= 0x0350) { enum SQL_DESC_ROWVER = 35; enum SQL_GUID = -11; enum SQL_C_GUID = SQL_GUID; //#ifdef ODBC_STD //#define SQLAllocHandle SQLAllocHandleStd //#define SQLAllocEnv(p) SQLAllocHandleStd(SQL_HANDLE_ENV, SQL_NULL_HANDLE, p) //#define SQL_YEAR SQL_CODE_YEAR //#define SQL_MONTH SQL_CODE_MONTH //#define SQL_DAY SQL_CODE_DAY //#define SQL_HOUR SQL_CODE_HOUR //#define SQL_MINUTE SQL_CODE_MINUTE //#define SQL_SECOND SQL_CODE_SECOND //#define SQL_YEAR_TO_MONTH SQL_CODE_YEAR_TO_MONTH //#define SQL_DAY_TO_HOUR SQL_CODE_DAY_TO_HOUR //#define SQL_DAY_TO_MINUTE SQL_CODE_DAY_TO_MINUTE //#define SQL_DAY_TO_SECOND SQL_CODE_DAY_TO_SECOND //#define SQL_HOUR_TO_MINUTE SQL_CODE_HOUR_TO_MINUTE //#define SQL_HOUR_TO_SECOND SQL_CODE_HOUR_TO_SECOND //#define SQL_MINUTE_TO_SECOND SQL_CODE_MINUTE_TO_SECOND //#endif /* ODBC_STD */ }//#endif /* ODBCVER >= 0x0350 */ //static if (ODBCVER >= 0x0351) { enum SQL_ATTR_ANSI_APP=115; enum SQL_AA_TRUE=1L; enum SQL_AA_FALSE=0L; //}//[Yes] #endif enum TRACE_VERSION=1000; enum TRACE_ON=1; const char [] SQL_ODBC_KEYWORDS = "ABSOLUTE, ACTION, ADA, ADD, ALL, ALLOCATE, ALTER, AND, ANY, ARE, AS, " ~ "ASC, ASSERTION, AT, AUTHORIZATION, AVG, " ~ "BEGIN, BETWEEN, BIT, BIT_LENGTH, BOTH, BY, CASCADE, CASCADED, CASE, CAST, CATALOG, " ~ "CHAR, CHAR_LENGTH, CHARACTER, CHARACTER_LENGTH, CHECK, CLOSE, COALESCE, " ~ "COLLATE, COLLATION, COLUMN, COMMIT, CONNECT, CONNECTION, CONSTRAINT, " ~ "CONSTRAINTS, CONTINUE, CONVERT, CORRESPONDING, COUNT, CREATE, CROSS, CURRENT, " ~ "CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, " ~ "DATE, DAY, DEALLOCATE, DEC, DECIMAL, DECLARE, DEFAULT, DEFERRABLE, " ~ "DEFERRED, DELETE, DESC, DESCRIBE, DESCRIPTOR, DIAGNOSTICS, DISCONNECT, " ~ "DISTINCT, DOMAIN, DOUBLE, DROP, " ~ "ELSE, END, END-EXEC, ESCAPE, EXCEPT, EXCEPTION, EXEC, EXECUTE, " ~ "EXISTS, EXTERNAL, EXTRACT, " ~ "FALSE, FETCH, FIRST, FLOAT, FOR, FOREIGN, FORTRAN, FOUND, FROM, FULL, " ~ "GET, GLOBAL, GO, GOTO, GRANT, GROUP, HAVING, HOUR, " ~ "IDENTITY, IMMEDIATE, IN, INCLUDE, INDEX, INDICATOR, INITIALLY, INNER, " ~ "INPUT, INSENSITIVE, INSERT, INT, INTEGER, INTERSECT, INTERVAL, INTO, IS, ISOLATION, " ~ "JOIN, KEY, LANGUAGE, LAST, LEADING, LEFT, LEVEL, LIKE, LOCAL, LOWER, " ~ "MATCH, MAX, MIN, MINUTE, MODULE, MONTH, " ~ "NAMES, NATIONAL, NATURAL, NCHAR, NEXT, NO, NONE, NOT, NULL, NULLIF, NUMERIC, " ~ "OCTET_LENGTH, OF, ON, ONLY, OPEN, OPTION, OR, ORDER, OUTER, OUTPUT, OVERLAPS, " ~ "PAD, PARTIAL, PASCAL, PLI, POSITION, PRECISION, PREPARE, PRESERVE, " ~ "PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PUBLIC, " ~ "READ, REAL, REFERENCES, RELATIVE, RESTRICT, REVOKE, RIGHT, ROLLBACK, ROWS" ~ "SCHEMA, SCROLL, SECOND, SECTION, SELECT, SESSION, SESSION_USER, SET, SIZE, " ~ "SMALLINT, SOME, SPACE, SQL, SQLCA, SQLCODE, SQLERROR, SQLSTATE, SQLWARNING, " ~ "SUBSTRING, SUM, SYSTEM_USER, " ~ "TABLE, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE, " ~ "TO, TRAILING, TRANSACTION, TRANSLATE, TRANSLATION, TRIM, TRUE, " ~ "UNION, UNIQUE, UNKNOWN, UPDATE, UPPER, USAGE, USER, USING, " ~ "VALUE, VALUES, VARCHAR, VARYING, VIEW, WHEN, WHENEVER, WHERE, WITH, WORK, WRITE, " ~ "YEAR, ZONE"; extern (Windows) { SQLRETURN SQLDriverConnect(SQLHDBC, SQLHWND, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLUSMALLINT); SQLRETURN SQLBrowseConnect(SQLHDBC, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLColumnPrivileges(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLColAttributes(SQLHSTMT, SQLUSMALLINT, SQLUSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*, SQLLEN*); SQLRETURN SQLDescribeParam(SQLHSTMT, SQLUSMALLINT, SQLSMALLINT*, SQLULEN*, SQLSMALLINT*, SQLSMALLINT*); SQLRETURN SQLExtendedFetch(SQLHSTMT, SQLUSMALLINT, SQLINTEGER, SQLUINTEGER*, SQLUSMALLINT*); SQLRETURN SQLForeignKeys(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLMoreResults(SQLHSTMT); SQLRETURN SQLNativeSql(SQLHDBC, SQLCHAR*, SQLINTEGER, SQLCHAR*, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLNumParams(SQLHSTMT, SQLSMALLINT*); SQLRETURN SQLParamOptions(SQLHSTMT, SQLUINTEGER, SQLUINTEGER*); SQLRETURN SQLPrimaryKeys(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLProcedureColumns(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLProcedures(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLSetPos(SQLHSTMT, SQLUSMALLINT, SQLUSMALLINT, SQLUSMALLINT); SQLRETURN SQLTablePrivileges(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLDrivers(SQLHENV, SQLUSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLBindParameter(SQLHSTMT, SQLUSMALLINT, SQLSMALLINT, SQLSMALLINT, SQLSMALLINT, SQLULEN, SQLSMALLINT, SQLPOINTER, SQLLEN, SQLLEN*); SQLRETURN SQLSetScrollOptions(SQLHSTMT, SQLUSMALLINT, SQLLEN, SQLUSMALLINT);/* deprecated */ DWORD ODBCGetTryWaitValue(); BOOL ODBCSetTryWaitValue(DWORD); RETCODE TraceOpenLogFile(LPWSTR, LPWSTR, DWORD); RETCODE TraceCloseLogFile(); VOID TraceReturn(RETCODE, RETCODE); DWORD TraceVersion(); //static if (ODBCVER >= 0x0300) { SQLRETURN SQLBulkOperations(SQLHSTMT, SQLSMALLINT); SQLRETURN SQLAllocHandleStd( SQLSMALLINT, SQLHANDLE, SQLHANDLE*); //} } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winldap.d0000664000175000017500000007530612776214756023330 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winldap.d) */ module core.sys.windows.winldap; version (Windows): version (ANSI) {} else version = Unicode; /* Comment from MinGW winldap.h - Header file for the Windows LDAP API Written by Filip Navara References: The C LDAP Application Program Interface http://www.watersprings.org/pub/id/draft-ietf-ldapext-ldap-c-api-05.txt Lightweight Directory Access Protocol Reference http://msdn.microsoft.com/library/en-us/netdir/ldap/ldap_reference.asp This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ import core.sys.windows.schannel, core.sys.windows.winber; private import core.sys.windows.wincrypt, core.sys.windows.windef; version(Tango){ private import tango.stdc.stdio; } align(4): enum { LDAP_VERSION1 = 1, LDAP_VERSION2 = 2, LDAP_VERSION3 = 3, LDAP_VERSION = LDAP_VERSION2, LDAP_VERSION_MIN = LDAP_VERSION2, LDAP_VERSION_MAX = LDAP_VERSION3 } /* MinGW defines ANSI and Unicode versions as LDAP_VENDOR_NAME and * LDAP_VENDOR_NAME_W respectively; similarly with other string constants * defined in this module. */ const TCHAR[] LDAP_VENDOR_NAME = "Microsoft Corporation."; enum LDAP_API_VERSION = 2004; enum LDAP_VENDOR_VERSION = 510; enum LDAP_API_INFO_VERSION = 1; enum LDAP_FEATURE_INFO_VERSION = 1; enum { LDAP_SUCCESS = 0x00, LDAP_OPT_SUCCESS = LDAP_SUCCESS, LDAP_OPERATIONS_ERROR, LDAP_PROTOCOL_ERROR, LDAP_TIMELIMIT_EXCEEDED, LDAP_SIZELIMIT_EXCEEDED, LDAP_COMPARE_FALSE, LDAP_COMPARE_TRUE, LDAP_STRONG_AUTH_NOT_SUPPORTED, LDAP_AUTH_METHOD_NOT_SUPPORTED = LDAP_STRONG_AUTH_NOT_SUPPORTED, LDAP_STRONG_AUTH_REQUIRED, LDAP_REFERRAL_V2, LDAP_PARTIAL_RESULTS = LDAP_REFERRAL_V2, LDAP_REFERRAL, LDAP_ADMIN_LIMIT_EXCEEDED, LDAP_UNAVAILABLE_CRIT_EXTENSION, LDAP_CONFIDENTIALITY_REQUIRED, LDAP_SASL_BIND_IN_PROGRESS, // = 0x0e LDAP_NO_SUCH_ATTRIBUTE = 0x10, LDAP_UNDEFINED_TYPE, LDAP_INAPPROPRIATE_MATCHING, LDAP_CONSTRAINT_VIOLATION, LDAP_TYPE_OR_VALUE_EXISTS, LDAP_ATTRIBUTE_OR_VALUE_EXISTS = LDAP_TYPE_OR_VALUE_EXISTS, LDAP_INVALID_SYNTAX, // = 0x15 LDAP_NO_SUCH_OBJECT = 0x20, LDAP_ALIAS_PROBLEM, LDAP_INVALID_DN_SYNTAX, LDAP_IS_LEAF, LDAP_ALIAS_DEREF_PROBLEM, // = 0x24 LDAP_INAPPROPRIATE_AUTH = 0x30, LDAP_INVALID_CREDENTIALS, LDAP_INSUFFICIENT_ACCESS, LDAP_INSUFFICIENT_RIGHTS = LDAP_INSUFFICIENT_ACCESS, LDAP_BUSY, LDAP_UNAVAILABLE, LDAP_UNWILLING_TO_PERFORM, LDAP_LOOP_DETECT, // = 0x36 LDAP_NAMING_VIOLATION = 0x40, LDAP_OBJECT_CLASS_VIOLATION, LDAP_NOT_ALLOWED_ON_NONLEAF, LDAP_NOT_ALLOWED_ON_RDN, LDAP_ALREADY_EXISTS, LDAP_NO_OBJECT_CLASS_MODS, LDAP_RESULTS_TOO_LARGE, LDAP_AFFECTS_MULTIPLE_DSAS, // = 0x47 LDAP_OTHER = 0x50, LDAP_SERVER_DOWN, LDAP_LOCAL_ERROR, LDAP_ENCODING_ERROR, LDAP_DECODING_ERROR, LDAP_TIMEOUT, LDAP_AUTH_UNKNOWN, LDAP_FILTER_ERROR, LDAP_USER_CANCELLED, LDAP_PARAM_ERROR, LDAP_NO_MEMORY, LDAP_CONNECT_ERROR, LDAP_NOT_SUPPORTED, LDAP_CONTROL_NOT_FOUND, LDAP_NO_RESULTS_RETURNED, LDAP_MORE_RESULTS_TO_RETURN, LDAP_CLIENT_LOOP, LDAP_REFERRAL_LIMIT_EXCEEDED // = 0x61 } enum { LDAP_PORT = 389, LDAP_SSL_PORT = 636, LDAP_GC_PORT = 3268, LDAP_SSL_GC_PORT = 3269 } enum void* LDAP_OPT_OFF = null, LDAP_OPT_ON = cast(void*) 1; enum { LDAP_OPT_API_INFO = 0x00, LDAP_OPT_DESC, LDAP_OPT_DEREF, LDAP_OPT_SIZELIMIT, LDAP_OPT_TIMELIMIT, LDAP_OPT_THREAD_FN_PTRS, LDAP_OPT_REBIND_FN, LDAP_OPT_REBIND_ARG, LDAP_OPT_REFERRALS, LDAP_OPT_RESTART, LDAP_OPT_SSL, LDAP_OPT_TLS = LDAP_OPT_SSL, LDAP_OPT_IO_FN_PTRS, // = 0x0b LDAP_OPT_CACHE_FN_PTRS = 0x0d, LDAP_OPT_CACHE_STRATEGY, LDAP_OPT_CACHE_ENABLE, LDAP_OPT_REFERRAL_HOP_LIMIT, LDAP_OPT_PROTOCOL_VERSION, LDAP_OPT_VERSION = LDAP_OPT_PROTOCOL_VERSION, LDAP_OPT_SERVER_CONTROLS, LDAP_OPT_CLIENT_CONTROLS, // = 0x13 LDAP_OPT_API_FEATURE_INFO = 0x15, LDAP_OPT_HOST_NAME = 0x30, LDAP_OPT_ERROR_NUMBER, LDAP_OPT_ERROR_STRING, LDAP_OPT_SERVER_ERROR, LDAP_OPT_SERVER_EXT_ERROR, // = 0x34 LDAP_OPT_PING_KEEP_ALIVE = 0x36, LDAP_OPT_PING_WAIT_TIME, LDAP_OPT_PING_LIMIT, // = 0x38 LDAP_OPT_DNSDOMAIN_NAME = 0x3b, LDAP_OPT_GETDSNAME_FLAGS = 0x3d, LDAP_OPT_HOST_REACHABLE, LDAP_OPT_PROMPT_CREDENTIALS, LDAP_OPT_TCP_KEEPALIVE, // = 0x40 LDAP_OPT_REFERRAL_CALLBACK = 0x70, LDAP_OPT_CLIENT_CERTIFICATE = 0x80, LDAP_OPT_SERVER_CERTIFICATE, // = 0x81 LDAP_OPT_AUTO_RECONNECT = 0x91, LDAP_OPT_SSPI_FLAGS, LDAP_OPT_SSL_INFO, LDAP_OPT_TLS_INFO = LDAP_OPT_SSL_INFO, LDAP_OPT_REF_DEREF_CONN_PER_MSG, LDAP_OPT_SIGN, LDAP_OPT_ENCRYPT, LDAP_OPT_SASL_METHOD, LDAP_OPT_AREC_EXCLUSIVE, LDAP_OPT_SECURITY_CONTEXT, LDAP_OPT_ROOTDSE_CACHE // = 0x9a } enum { LDAP_DEREF_NEVER, LDAP_DEREF_SEARCHING, LDAP_DEREF_FINDING, LDAP_DEREF_ALWAYS } enum LDAP_NO_LIMIT = 0; const TCHAR[] LDAP_CONTROL_REFERRALS = "1.2.840.113556.1.4.616"; // FIXME: check type (declared with U suffix in MinGW) enum : uint { LDAP_CHASE_SUBORDINATE_REFERRALS = 0x20, LDAP_CHASE_EXTERNAL_REFERRALS = 0x40 } enum { LDAP_SCOPE_DEFAULT = -1, LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE } enum { LDAP_MOD_ADD, LDAP_MOD_DELETE, LDAP_MOD_REPLACE, LDAP_MOD_BVALUES = 0x80 } enum : int { LDAP_RES_BIND = 0x61, LDAP_RES_SEARCH_ENTRY = 0x64, LDAP_RES_SEARCH_RESULT = 0x65, LDAP_RES_MODIFY = 0x67, LDAP_RES_ADD = 0x69, LDAP_RES_DELETE = 0x6b, LDAP_RES_MODRDN = 0x6d, LDAP_RES_COMPARE = 0x6f, LDAP_RES_SEARCH_REFERENCE = 0x73, LDAP_RES_EXTENDED = 0x78, LDAP_RES_ANY = -1 } enum { LDAP_MSG_ONE, LDAP_MSG_ALL, LDAP_MSG_RECEIVED } const TCHAR[] LDAP_SERVER_SORT_OID = "1.2.840.113556.1.4.473", LDAP_SERVER_RESP_SORT_OID = "1.2.840.113556.1.4.474", LDAP_PAGED_RESULT_OID_STRING = "1.2.840.113556.1.4.319", LDAP_CONTROL_VLVREQUEST = "2.16.840.1.113730.3.4.9", LDAP_CONTROL_VLVRESPONSE = "2.16.840.1.113730.3.4.10", LDAP_START_TLS_OID = "1.3.6.1.4.1.1466.20037", LDAP_TTL_EXTENDED_OP_OID = "1.3.6.1.4.1.1466.101.119.1"; enum { LDAP_AUTH_NONE = 0x00U, LDAP_AUTH_SIMPLE = 0x80U, LDAP_AUTH_SASL = 0x83U, LDAP_AUTH_OTHERKIND = 0x86U, LDAP_AUTH_EXTERNAL = LDAP_AUTH_OTHERKIND | 0x0020U, LDAP_AUTH_SICILY = LDAP_AUTH_OTHERKIND | 0x0200U, LDAP_AUTH_NEGOTIATE = LDAP_AUTH_OTHERKIND | 0x0400U, LDAP_AUTH_MSN = LDAP_AUTH_OTHERKIND | 0x0800U, LDAP_AUTH_NTLM = LDAP_AUTH_OTHERKIND | 0x1000U, LDAP_AUTH_DIGEST = LDAP_AUTH_OTHERKIND | 0x4000U, LDAP_AUTH_DPA = LDAP_AUTH_OTHERKIND | 0x2000U, LDAP_AUTH_SSPI = LDAP_AUTH_NEGOTIATE } enum { LDAP_FILTER_AND = 0xa0, LDAP_FILTER_OR, LDAP_FILTER_NOT, LDAP_FILTER_EQUALITY, LDAP_FILTER_SUBSTRINGS, LDAP_FILTER_GE, LDAP_FILTER_LE, // = 0xa6 LDAP_FILTER_APPROX = 0xa8, LDAP_FILTER_EXTENSIBLE, LDAP_FILTER_PRESENT = 0x87 } enum { LDAP_SUBSTRING_INITIAL = 0x80, LDAP_SUBSTRING_ANY, LDAP_SUBSTRING_FINAL } struct LDAP { char[76] Reserved; PCHAR ld_host; ULONG ld_version; UCHAR ld_lberoptions; int ld_deref; int ld_timelimit; int ld_sizelimit; int ld_errno; PCHAR ld_matched; PCHAR ld_error; } alias LDAP* PLDAP; struct LDAPMessage { ULONG lm_msgid; ULONG lm_msgtype; BerElement* lm_ber; LDAPMessage* lm_chain; LDAPMessage* lm_next; ULONG lm_time; } alias LDAPMessage* PLDAPMessage; struct LDAP_TIMEVAL { LONG tv_sec; LONG tv_usec; } alias LDAP_TIMEVAL* PLDAP_TIMEVAL; struct LDAPAPIInfoA { int ldapai_info_version; int ldapai_api_version; int ldapai_protocol_version; char** ldapai_extensions; char* ldapai_vendor_name; int ldapai_vendor_version; } alias LDAPAPIInfoA* PLDAPAPIInfoA; struct LDAPAPIInfoW { int ldapai_info_version; int ldapai_api_version; int ldapai_protocol_version; PWCHAR* ldapai_extensions; PWCHAR ldapai_vendor_name; int ldapai_vendor_version; } alias LDAPAPIInfoW* PLDAPAPIInfoW; struct LDAPAPIFeatureInfoA { int ldapaif_info_version; char* ldapaif_name; int ldapaif_version; } alias LDAPAPIFeatureInfoA* PLDAPAPIFeatureInfoA; struct LDAPAPIFeatureInfoW { int ldapaif_info_version; PWCHAR ldapaif_name; int ldapaif_version; } alias LDAPAPIFeatureInfoW* PLDAPAPIFeatureInfoW; struct LDAPControlA { PCHAR ldctl_oid; BerValue ldctl_value; BOOLEAN ldctl_iscritical; } alias LDAPControlA* PLDAPControlA; struct LDAPControlW { PWCHAR ldctl_oid; BerValue ldctl_value; BOOLEAN ldctl_iscritical; } alias LDAPControlW* PLDAPControlW; /* Do we really need these? In MinGW, LDAPModA/W have only mod_op, mod_type * and mod_vals, and macros are used to simulate anonymous unions in those * structures. */ union mod_vals_u_tA { PCHAR* modv_strvals; BerValue** modv_bvals; } union mod_vals_u_tW { PWCHAR* modv_strvals; BerValue** modv_bvals; } struct LDAPModA { ULONG mod_op; PCHAR mod_type; union { mod_vals_u_tA mod_vals; // The following members are defined as macros in MinGW. PCHAR* mod_values; BerValue** mod_bvalues; } } alias LDAPModA* PLDAPModA; struct LDAPModW { ULONG mod_op; PWCHAR mod_type; union { mod_vals_u_tW mod_vals; // The following members are defined as macros in MinGW. PWCHAR* mod_values; BerValue** mod_bvalues; } } alias LDAPModW* PLDAPModW; /* Opaque structure * http://msdn.microsoft.com/library/en-us/ldap/ldap/ldapsearch.asp */ struct LDAPSearch; alias LDAPSearch* PLDAPSearch; struct LDAPSortKeyA { PCHAR sk_attrtype; PCHAR sk_matchruleoid; BOOLEAN sk_reverseorder; } alias LDAPSortKeyA* PLDAPSortKeyA; struct LDAPSortKeyW { PWCHAR sk_attrtype; PWCHAR sk_matchruleoid; BOOLEAN sk_reverseorder; } alias LDAPSortKeyW* PLDAPSortKeyW; /* MinGW defines these as immediate function typedefs, which don't translate * well into D. */ extern (C) { alias ULONG function(PLDAP, PLDAP, PWCHAR, PCHAR, ULONG, PVOID, PVOID, PLDAP*) QUERYFORCONNECTION; alias BOOLEAN function(PLDAP, PLDAP, PWCHAR, PCHAR, PLDAP, ULONG, PVOID, PVOID, ULONG) NOTIFYOFNEWCONNECTION; alias ULONG function(PLDAP, PLDAP) DEREFERENCECONNECTION; alias BOOLEAN function(PLDAP, PSecPkgContext_IssuerListInfoEx, PCCERT_CONTEXT*) QUERYCLIENTCERT; } struct LDAP_REFERRAL_CALLBACK { ULONG SizeOfCallbacks; QUERYFORCONNECTION* QueryForConnection; NOTIFYOFNEWCONNECTION* NotifyRoutine; DEREFERENCECONNECTION* DereferenceRoutine; } alias LDAP_REFERRAL_CALLBACK* PLDAP_REFERRAL_CALLBACK; struct LDAPVLVInfo { int ldvlv_version; uint ldvlv_before_count; uint ldvlv_after_count; uint ldvlv_offset; uint ldvlv_count; BerValue* ldvlv_attrvalue; BerValue* ldvlv_context; void* ldvlv_extradata; } /* * Under Microsoft WinLDAP the function ldap_error is only stub. * This macro uses LDAP structure to get error string and pass it to the user. */ private extern (C) int printf(in char* format, ...); int ldap_perror(LDAP* handle, char* message) { return printf("%s: %s\n", message, handle.ld_error); } /* FIXME: In MinGW, these are WINLDAPAPI == DECLSPEC_IMPORT. Linkage * attribute? */ extern (C) { PLDAP ldap_initA(PCHAR, ULONG); PLDAP ldap_initW(PWCHAR, ULONG); PLDAP ldap_openA(PCHAR, ULONG); PLDAP ldap_openW(PWCHAR, ULONG); PLDAP cldap_openA(PCHAR, ULONG); PLDAP cldap_openW(PWCHAR, ULONG); ULONG ldap_connect(LDAP*, LDAP_TIMEVAL*); PLDAP ldap_sslinitA(PCHAR, ULONG, int); PLDAP ldap_sslinitW(PWCHAR, ULONG, int); ULONG ldap_start_tls_sA(LDAP*, PLDAPControlA*, PLDAPControlA*); ULONG ldap_start_tls_sW(LDAP*, PLDAPControlW*, PLDAPControlW*); BOOLEAN ldap_stop_tls_s(LDAP*); ULONG ldap_get_optionA(LDAP*, int, void*); ULONG ldap_get_optionW(LDAP*, int, void*); ULONG ldap_set_optionA(LDAP*, int, void*); ULONG ldap_set_optionW(LDAP*, int, void*); ULONG ldap_control_freeA(LDAPControlA*); ULONG ldap_control_freeW(LDAPControlW*); ULONG ldap_controls_freeA(LDAPControlA**); ULONG ldap_controls_freeW(LDAPControlW**); ULONG ldap_free_controlsA(LDAPControlA**); ULONG ldap_free_controlsW(LDAPControlW**); ULONG ldap_sasl_bindA(LDAP*, PCHAR, PCHAR, BERVAL*, PLDAPControlA*, PLDAPControlA*, int*); ULONG ldap_sasl_bindW(LDAP*, PWCHAR, PWCHAR, BERVAL*, PLDAPControlW*, PLDAPControlW*, int*); ULONG ldap_sasl_bind_sA(LDAP*, PCHAR, PCHAR, BERVAL*, PLDAPControlA*, PLDAPControlA*, PBERVAL*); ULONG ldap_sasl_bind_sW(LDAP*, PWCHAR, PWCHAR, BERVAL*, PLDAPControlW*, PLDAPControlW*, PBERVAL*); ULONG ldap_simple_bindA(LDAP*, PCHAR, PCHAR); ULONG ldap_simple_bindW(LDAP*, PWCHAR, PWCHAR); ULONG ldap_simple_bind_sA(LDAP*, PCHAR, PCHAR); ULONG ldap_simple_bind_sW(LDAP*, PWCHAR, PWCHAR); ULONG ldap_unbind(LDAP*); ULONG ldap_unbind_s(LDAP*); ULONG ldap_search_extA(LDAP*, PCHAR, ULONG, PCHAR, PCHAR[], ULONG, PLDAPControlW*, PLDAPControlW*, ULONG, ULONG, ULONG*); ULONG ldap_search_extW(LDAP*, PWCHAR, ULONG, PWCHAR, PWCHAR[], ULONG, PLDAPControlW*, PLDAPControlW*, ULONG, ULONG, ULONG*); ULONG ldap_search_ext_sA(LDAP*, PCHAR, ULONG, PCHAR, PCHAR[], ULONG, PLDAPControlA*, PLDAPControlA*, LDAP_TIMEVAL*, ULONG, LDAPMessage**); ULONG ldap_search_ext_sW(LDAP*, PWCHAR, ULONG, PWCHAR, PWCHAR[], ULONG, PLDAPControlW*, PLDAPControlW*, LDAP_TIMEVAL*, ULONG, LDAPMessage**); ULONG ldap_searchA(LDAP*, PCHAR, ULONG, PCHAR, PCHAR[], ULONG); ULONG ldap_searchW(LDAP*, PWCHAR, ULONG, PWCHAR, PWCHAR[], ULONG); ULONG ldap_search_sA(LDAP*, PCHAR, ULONG, PCHAR, PCHAR[], ULONG, LDAPMessage**); ULONG ldap_search_sW(LDAP*, PWCHAR, ULONG, PWCHAR, PWCHAR[], ULONG, LDAPMessage**); ULONG ldap_search_stA(LDAP*, PCHAR, ULONG, PCHAR, PCHAR[], ULONG, LDAP_TIMEVAL*, LDAPMessage**); ULONG ldap_search_stW(LDAP*, PWCHAR, ULONG, PWCHAR, PWCHAR[], ULONG, LDAP_TIMEVAL*, LDAPMessage**); ULONG ldap_compare_extA(LDAP*, PCHAR, PCHAR, PCHAR, BerValue*, PLDAPControlA*, PLDAPControlA*, ULONG*); ULONG ldap_compare_extW(LDAP*, PWCHAR, PWCHAR, PWCHAR, BerValue*, PLDAPControlW*, PLDAPControlW*, ULONG*); ULONG ldap_compare_ext_sA(LDAP*, PCHAR, PCHAR, PCHAR, BerValue*, PLDAPControlA*, PLDAPControlA*); ULONG ldap_compare_ext_sW(LDAP*, PWCHAR, PWCHAR, PWCHAR, BerValue*, PLDAPControlW*, PLDAPControlW*); ULONG ldap_compareA(LDAP*, PCHAR, PCHAR, PCHAR); ULONG ldap_compareW(LDAP*, PWCHAR, PWCHAR, PWCHAR); ULONG ldap_compare_sA(LDAP*, PCHAR, PCHAR, PCHAR); ULONG ldap_compare_sW(LDAP*, PWCHAR, PWCHAR, PWCHAR); ULONG ldap_modify_extA(LDAP*, PCHAR, LDAPModA*[], PLDAPControlA*, PLDAPControlA*, ULONG*); ULONG ldap_modify_extW(LDAP*, PWCHAR, LDAPModW*[], PLDAPControlW*, PLDAPControlW*, ULONG*); ULONG ldap_modify_ext_sA(LDAP*, PCHAR, LDAPModA*[], PLDAPControlA*, PLDAPControlA*); ULONG ldap_modify_ext_sW(LDAP*, PWCHAR, LDAPModW*[], PLDAPControlW*, PLDAPControlW*); ULONG ldap_modifyA(LDAP*, PCHAR, LDAPModA*[]); ULONG ldap_modifyW(LDAP*, PWCHAR, LDAPModW*[]); ULONG ldap_modify_sA(LDAP*, PCHAR, LDAPModA*[]); ULONG ldap_modify_sW(LDAP*, PWCHAR, LDAPModW*[]); ULONG ldap_rename_extA(LDAP*, PCHAR, PCHAR, PCHAR, INT, PLDAPControlA*, PLDAPControlA*, ULONG*); ULONG ldap_rename_extW(LDAP*, PWCHAR, PWCHAR, PWCHAR, INT, PLDAPControlW*, PLDAPControlW*, ULONG*); ULONG ldap_rename_ext_sA(LDAP*, PCHAR, PCHAR, PCHAR, INT, PLDAPControlA*, PLDAPControlA*); ULONG ldap_rename_ext_sW(LDAP*, PWCHAR, PWCHAR, PWCHAR, INT, PLDAPControlW*, PLDAPControlW*); ULONG ldap_add_extA(LDAP*, PCHAR, LDAPModA*[], PLDAPControlA*, PLDAPControlA*, ULONG*); ULONG ldap_add_extW(LDAP*, PWCHAR, LDAPModW*[], PLDAPControlW*, PLDAPControlW*, ULONG*); ULONG ldap_add_ext_sA(LDAP*, PCHAR, LDAPModA*[], PLDAPControlA*, PLDAPControlA*); ULONG ldap_add_ext_sW(LDAP*, PWCHAR, LDAPModW*[], PLDAPControlW*, PLDAPControlW*); ULONG ldap_addA(LDAP*, PCHAR, LDAPModA*[]); ULONG ldap_addW(LDAP*, PWCHAR, LDAPModW*[]); ULONG ldap_add_sA(LDAP*, PCHAR, LDAPModA*[]); ULONG ldap_add_sW(LDAP*, PWCHAR, LDAPModW*[]); ULONG ldap_delete_extA(LDAP*, PCHAR, PLDAPControlA*, PLDAPControlA*, ULONG*); ULONG ldap_delete_extW(LDAP*, PWCHAR, PLDAPControlW*, PLDAPControlW*, ULONG*); ULONG ldap_delete_ext_sA(LDAP*, PCHAR, PLDAPControlA*, PLDAPControlA*); ULONG ldap_delete_ext_sW(LDAP*, PWCHAR, PLDAPControlW*, PLDAPControlW*); ULONG ldap_deleteA(LDAP*, PCHAR); ULONG ldap_deleteW(LDAP*, PWCHAR); ULONG ldap_delete_sA(LDAP*, PCHAR); ULONG ldap_delete_sW(LDAP*, PWCHAR); ULONG ldap_extended_operationA(LDAP*, PCHAR, BerValue*, PLDAPControlA*, PLDAPControlA*, ULONG*); ULONG ldap_extended_operationW(LDAP*, PWCHAR, BerValue*, PLDAPControlW*, PLDAPControlW*, ULONG*); ULONG ldap_extended_operation_sA(LDAP*, PCHAR, BerValue*, PLDAPControlA*, PLDAPControlA*, PCHAR*, BerValue**); ULONG ldap_extended_operation_sW(LDAP*, PWCHAR, BerValue*, PLDAPControlW*, PLDAPControlW*, PWCHAR*, BerValue**); ULONG ldap_close_extended_op(LDAP*, ULONG); ULONG ldap_abandon(LDAP*, ULONG); ULONG ldap_result(LDAP*, ULONG, ULONG, LDAP_TIMEVAL*, LDAPMessage**); ULONG ldap_msgfree(LDAPMessage*); ULONG ldap_parse_resultA(LDAP*, LDAPMessage*, ULONG*, PCHAR*, PCHAR*, PCHAR**, PLDAPControlA**, BOOLEAN); ULONG ldap_parse_resultW(LDAP*, LDAPMessage*, ULONG*, PWCHAR*, PWCHAR*, PWCHAR**, PLDAPControlW**, BOOLEAN); ULONG ldap_parse_extended_resultA(LDAP, LDAPMessage*, PCHAR*, BerValue**, BOOLEAN); ULONG ldap_parse_extended_resultW(LDAP, LDAPMessage*, PWCHAR*, BerValue**, BOOLEAN); PCHAR ldap_err2stringA(ULONG); PWCHAR ldap_err2stringW(ULONG); ULONG LdapGetLastError(); ULONG LdapMapErrorToWin32(ULONG); ULONG ldap_result2error(LDAP*, LDAPMessage*, ULONG); PLDAPMessage ldap_first_entry(LDAP*, LDAPMessage*); PLDAPMessage ldap_next_entry(LDAP*, LDAPMessage*); PLDAPMessage ldap_first_reference(LDAP*, LDAPMessage*); PLDAPMessage ldap_next_reference(LDAP*, LDAPMessage*); ULONG ldap_count_entries(LDAP*, LDAPMessage*); ULONG ldap_count_references(LDAP*, LDAPMessage*); PCHAR ldap_first_attributeA(LDAP*, LDAPMessage*, BerElement**); PWCHAR ldap_first_attributeW(LDAP*, LDAPMessage*, BerElement**); PCHAR ldap_next_attributeA(LDAP*, LDAPMessage*, BerElement*); PWCHAR ldap_next_attributeW(LDAP*, LDAPMessage*, BerElement*); VOID ldap_memfreeA(PCHAR); VOID ldap_memfreeW(PWCHAR); PCHAR* ldap_get_valuesA(LDAP*, LDAPMessage*, PCHAR); PWCHAR* ldap_get_valuesW(LDAP*, LDAPMessage*, PWCHAR); BerValue** ldap_get_values_lenA(LDAP*, LDAPMessage*, PCHAR); BerValue** ldap_get_values_lenW(LDAP*, LDAPMessage*, PWCHAR); ULONG ldap_count_valuesA(PCHAR*); ULONG ldap_count_valuesW(PWCHAR*); ULONG ldap_count_values_len(BerValue**); ULONG ldap_value_freeA(PCHAR*); ULONG ldap_value_freeW(PWCHAR*); ULONG ldap_value_free_len(BerValue**); PCHAR ldap_get_dnA(LDAP*, LDAPMessage*); PWCHAR ldap_get_dnW(LDAP*, LDAPMessage*); PCHAR ldap_explode_dnA(PCHAR, ULONG); PWCHAR ldap_explode_dnW(PWCHAR, ULONG); PCHAR ldap_dn2ufnA(PCHAR); PWCHAR ldap_dn2ufnW(PWCHAR); ULONG ldap_ufn2dnA(PCHAR, PCHAR*); ULONG ldap_ufn2dnW(PWCHAR, PWCHAR*); ULONG ldap_parse_referenceA(LDAP*, LDAPMessage*, PCHAR**); ULONG ldap_parse_referenceW(LDAP*, LDAPMessage*, PWCHAR**); ULONG ldap_check_filterA(LDAP*, PCHAR); ULONG ldap_check_filterW(LDAP*, PWCHAR); ULONG ldap_create_page_controlA(PLDAP, ULONG, BerValue*, UCHAR, PLDAPControlA*); ULONG ldap_create_page_controlW(PLDAP, ULONG, BerValue*, UCHAR, PLDAPControlW*); ULONG ldap_create_sort_controlA(PLDAP, PLDAPSortKeyA*, UCHAR, PLDAPControlA*); ULONG ldap_create_sort_controlW(PLDAP, PLDAPSortKeyW*, UCHAR, PLDAPControlW*); INT ldap_create_vlv_controlA(LDAP*, LDAPVLVInfo*, UCHAR, LDAPControlA**); INT ldap_create_vlv_controlW(LDAP*, LDAPVLVInfo*, UCHAR, LDAPControlW**); ULONG ldap_encode_sort_controlA(PLDAP, PLDAPSortKeyA*, PLDAPControlA, BOOLEAN); ULONG ldap_encode_sort_controlW(PLDAP, PLDAPSortKeyW*, PLDAPControlW, BOOLEAN); ULONG ldap_escape_filter_elementA(PCHAR, ULONG, PCHAR, ULONG); ULONG ldap_escape_filter_elementW(PWCHAR, ULONG, PWCHAR, ULONG); ULONG ldap_get_next_page(PLDAP, PLDAPSearch, ULONG, ULONG*); ULONG ldap_get_next_page_s(PLDAP, PLDAPSearch, LDAP_TIMEVAL*, ULONG, ULONG*, LDAPMessage**); ULONG ldap_get_paged_count(PLDAP, PLDAPSearch, ULONG*, PLDAPMessage); ULONG ldap_parse_page_controlA(PLDAP, PLDAPControlA*, ULONG*, BerValue**); ULONG ldap_parse_page_controlW(PLDAP, PLDAPControlW*, ULONG*, BerValue**); ULONG ldap_parse_sort_controlA(PLDAP, PLDAPControlA*, ULONG*, PCHAR*); ULONG ldap_parse_sort_controlW(PLDAP, PLDAPControlW*, ULONG*, PWCHAR*); INT ldap_parse_vlv_controlA(LDAP*, LDAPControlA**, uint*, uint*, BerValue**, int*); INT ldap_parse_vlv_controlW(LDAP*, LDAPControlW**, uint*, uint*, BerValue**, int*); PLDAPSearch ldap_search_init_pageA(PLDAP, PCHAR, ULONG, PCHAR, PCHAR[], ULONG, PLDAPControlA*, PLDAPControlA*, ULONG, ULONG, PLDAPSortKeyA*); PLDAPSearch ldap_search_init_pageW(PLDAP, PWCHAR, ULONG, PWCHAR, PWCHAR[], ULONG, PLDAPControlW*, PLDAPControlW*, ULONG, ULONG, PLDAPSortKeyW*); ULONG ldap_search_abandon_page(PLDAP, PLDAPSearch); LDAP ldap_conn_from_msg(LDAP*, LDAPMessage*); INT LdapUnicodeToUTF8(LPCWSTR, int, LPSTR, int); INT LdapUTF8ToUnicode(LPCSTR, int, LPWSTR, int); deprecated { ULONG ldap_bindA(LDAP*, PCHAR, PCHAR, ULONG); ULONG ldap_bindW(LDAP*, PWCHAR, PWCHAR, ULONG); ULONG ldap_bind_sA(LDAP*, PCHAR, PCHAR, ULONG); ULONG ldap_bind_sW(LDAP*, PWCHAR, PWCHAR, ULONG); ULONG ldap_modrdnA(LDAP*, PCHAR, PCHAR); ULONG ldap_modrdnW(LDAP*, PWCHAR, PWCHAR); ULONG ldap_modrdn_sA(LDAP*, PCHAR, PCHAR); ULONG ldap_modrdn_sW(LDAP*, PWCHAR, PWCHAR); ULONG ldap_modrdn2A(LDAP*, PCHAR, PCHAR, INT); ULONG ldap_modrdn2W(LDAP*, PWCHAR, PWCHAR, INT); ULONG ldap_modrdn2_sA(LDAP*, PCHAR, PCHAR, INT); ULONG ldap_modrdn2_sW(LDAP*, PWCHAR, PWCHAR, INT); } } version (Unicode) { alias LDAPControlW LDAPControl; alias PLDAPControlW PLDAPControl; alias LDAPModW LDAPMod; alias LDAPModW PLDAPMod; alias LDAPSortKeyW LDAPSortKey; alias PLDAPSortKeyW PLDAPSortKey; alias LDAPAPIInfoW LDAPAPIInfo; alias PLDAPAPIInfoW PLDAPAPIInfo; alias LDAPAPIFeatureInfoW LDAPAPIFeatureInfo; alias PLDAPAPIFeatureInfoW PLDAPAPIFeatureInfo; alias cldap_openW cldap_open; alias ldap_openW ldap_open; alias ldap_simple_bindW ldap_simple_bind; alias ldap_simple_bind_sW ldap_simple_bind_s; alias ldap_sasl_bindW ldap_sasl_bind; alias ldap_sasl_bind_sW ldap_sasl_bind_s; alias ldap_initW ldap_init; alias ldap_sslinitW ldap_sslinit; alias ldap_get_optionW ldap_get_option; alias ldap_set_optionW ldap_set_option; alias ldap_start_tls_sW ldap_start_tls_s; alias ldap_addW ldap_add; alias ldap_add_extW ldap_add_ext; alias ldap_add_sW ldap_add_s; alias ldap_add_ext_sW ldap_add_ext_s; alias ldap_compareW ldap_compare; alias ldap_compare_extW ldap_compare_ext; alias ldap_compare_sW ldap_compare_s; alias ldap_compare_ext_sW ldap_compare_ext_s; alias ldap_deleteW ldap_delete; alias ldap_delete_extW ldap_delete_ext; alias ldap_delete_sW ldap_delete_s; alias ldap_delete_ext_sW ldap_delete_ext_s; alias ldap_extended_operation_sW ldap_extended_operation_s; alias ldap_extended_operationW ldap_extended_operation; alias ldap_modifyW ldap_modify; alias ldap_modify_extW ldap_modify_ext; alias ldap_modify_sW ldap_modify_s; alias ldap_modify_ext_sW ldap_modify_ext_s; alias ldap_check_filterW ldap_check_filter; alias ldap_count_valuesW ldap_count_values; alias ldap_create_page_controlW ldap_create_page_control; alias ldap_create_sort_controlW ldap_create_sort_control; alias ldap_create_vlv_controlW ldap_create_vlv_control; alias ldap_encode_sort_controlW ldap_encode_sort_control; alias ldap_escape_filter_elementW ldap_escape_filter_element; alias ldap_first_attributeW ldap_first_attribute; alias ldap_next_attributeW ldap_next_attribute; alias ldap_get_valuesW ldap_get_values; alias ldap_get_values_lenW ldap_get_values_len; alias ldap_parse_extended_resultW ldap_parse_extended_result; alias ldap_parse_page_controlW ldap_parse_page_control; alias ldap_parse_referenceW ldap_parse_reference; alias ldap_parse_resultW ldap_parse_result; alias ldap_parse_sort_controlW ldap_parse_sort_control; alias ldap_parse_vlv_controlW ldap_parse_vlv_control; alias ldap_searchW ldap_search; alias ldap_search_sW ldap_search_s; alias ldap_search_stW ldap_search_st; alias ldap_search_extW ldap_search_ext; alias ldap_search_ext_sW ldap_search_ext_s; alias ldap_search_init_pageW ldap_search_init_page; alias ldap_err2stringW ldap_err2string; alias ldap_control_freeW ldap_control_free; alias ldap_controls_freeW ldap_controls_free; alias ldap_free_controlsW ldap_free_controls; alias ldap_memfreeW ldap_memfree; alias ldap_value_freeW ldap_value_free; alias ldap_dn2ufnW ldap_dn2ufn; alias ldap_ufn2dnW ldap_ufn2dn; alias ldap_explode_dnW ldap_explode_dn; alias ldap_get_dnW ldap_get_dn; alias ldap_rename_extW ldap_rename; alias ldap_rename_ext_sW ldap_rename_s; alias ldap_rename_extW ldap_rename_ext; alias ldap_rename_ext_sW ldap_rename_ext_s; deprecated { alias ldap_bindW ldap_bind; alias ldap_bind_sW ldap_bind_s; alias ldap_modrdnW ldap_modrdn; alias ldap_modrdn_sW ldap_modrdn_s; alias ldap_modrdn2W ldap_modrdn2; alias ldap_modrdn2_sW ldap_modrdn2_s; } } else { alias LDAPControlA LDAPControl; alias PLDAPControlA PLDAPControl; alias LDAPModA LDAPMod; alias LDAPModA PLDAPMod; alias LDAPSortKeyA LDAPSortKey; alias PLDAPSortKeyA PLDAPSortKey; alias LDAPAPIInfoA LDAPAPIInfo; alias PLDAPAPIInfoA PLDAPAPIInfo; alias LDAPAPIFeatureInfoA LDAPAPIFeatureInfo; alias PLDAPAPIFeatureInfoA PLDAPAPIFeatureInfo; alias cldap_openA cldap_open; alias ldap_openA ldap_open; alias ldap_simple_bindA ldap_simple_bind; alias ldap_simple_bind_sA ldap_simple_bind_s; alias ldap_sasl_bindA ldap_sasl_bind; alias ldap_sasl_bind_sA ldap_sasl_bind_s; alias ldap_initA ldap_init; alias ldap_sslinitA ldap_sslinit; alias ldap_get_optionA ldap_get_option; alias ldap_set_optionA ldap_set_option; alias ldap_start_tls_sA ldap_start_tls_s; alias ldap_addA ldap_add; alias ldap_add_extA ldap_add_ext; alias ldap_add_sA ldap_add_s; alias ldap_add_ext_sA ldap_add_ext_s; alias ldap_compareA ldap_compare; alias ldap_compare_extA ldap_compare_ext; alias ldap_compare_sA ldap_compare_s; alias ldap_compare_ext_sA ldap_compare_ext_s; alias ldap_deleteA ldap_delete; alias ldap_delete_extA ldap_delete_ext; alias ldap_delete_sA ldap_delete_s; alias ldap_delete_ext_sA ldap_delete_ext_s; alias ldap_extended_operation_sA ldap_extended_operation_s; alias ldap_extended_operationA ldap_extended_operation; alias ldap_modifyA ldap_modify; alias ldap_modify_extA ldap_modify_ext; alias ldap_modify_sA ldap_modify_s; alias ldap_modify_ext_sA ldap_modify_ext_s; alias ldap_check_filterA ldap_check_filter; alias ldap_count_valuesA ldap_count_values; alias ldap_create_page_controlA ldap_create_page_control; alias ldap_create_sort_controlA ldap_create_sort_control; alias ldap_create_vlv_controlA ldap_create_vlv_control; alias ldap_encode_sort_controlA ldap_encode_sort_control; alias ldap_escape_filter_elementA ldap_escape_filter_element; alias ldap_first_attributeA ldap_first_attribute; alias ldap_next_attributeA ldap_next_attribute; alias ldap_get_valuesA ldap_get_values; alias ldap_get_values_lenA ldap_get_values_len; alias ldap_parse_extended_resultA ldap_parse_extended_result; alias ldap_parse_page_controlA ldap_parse_page_control; alias ldap_parse_referenceA ldap_parse_reference; alias ldap_parse_resultA ldap_parse_result; alias ldap_parse_sort_controlA ldap_parse_sort_control; alias ldap_parse_vlv_controlA ldap_parse_vlv_control; alias ldap_searchA ldap_search; alias ldap_search_sA ldap_search_s; alias ldap_search_stA ldap_search_st; alias ldap_search_extA ldap_search_ext; alias ldap_search_ext_sA ldap_search_ext_s; alias ldap_search_init_pageA ldap_search_init_page; alias ldap_err2stringA ldap_err2string; alias ldap_control_freeA ldap_control_free; alias ldap_controls_freeA ldap_controls_free; alias ldap_free_controlsA ldap_free_controls; alias ldap_memfreeA ldap_memfree; alias ldap_value_freeA ldap_value_free; alias ldap_dn2ufnA ldap_dn2ufn; alias ldap_ufn2dnA ldap_ufn2dn; alias ldap_explode_dnA ldap_explode_dn; alias ldap_get_dnA ldap_get_dn; alias ldap_rename_extA ldap_rename; alias ldap_rename_ext_sA ldap_rename_s; alias ldap_rename_extA ldap_rename_ext; alias ldap_rename_ext_sA ldap_rename_ext_s; deprecated { alias ldap_bindA ldap_bind; alias ldap_bind_sA ldap_bind_s; alias ldap_modrdnA ldap_modrdn; alias ldap_modrdn_sA ldap_modrdn_s; alias ldap_modrdn2A ldap_modrdn2; alias ldap_modrdn2_sA ldap_modrdn2_s; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/olectl.d0000664000175000017500000003212412776214756023143 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_olectl.d) */ module core.sys.windows.olectl; version (Windows): // In conversion from MinGW, the following was deleted: //#define FONTSIZE(n) {n##0000, 0} import core.sys.windows.ocidl, core.sys.windows.olectlid; private import core.sys.windows.basetyps, core.sys.windows.oaidl, core.sys.windows.oleauto, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.wingdi, core.sys.windows.winuser, core.sys.windows.wtypes; private import core.sys.windows.ntdef; // for NTSTATUS private import core.sys.windows.objfwd; // for LPSTREAM private import core.sys.windows.winerror; // for SCODE private { // These replace C macros. template ITF_ERROR_SCODE_FOR_D(int c) { enum SCODE ITF_ERROR_SCODE_FOR_D = (SEVERITY_ERROR << 31) | (FACILITY_ITF << 16) | c; } template ITF_SUCCESS_SCODE_FOR_D(int c) { enum SCODE ITF_SUCCESS_SCODE_FOR_D = (SEVERITY_SUCCESS << 31) | (FACILITY_ITF << 16) | c; } template STD_CTL_SCODE(int c) { enum SCODE STD_CTL_SCODE = (SEVERITY_ERROR << 31) | (FACILITY_CONTROL << 16) | c; } } enum : SCODE { CTL_E_ILLEGALFUNCTIONCALL = STD_CTL_SCODE!(5), CTL_E_OVERFLOW = STD_CTL_SCODE!(6), CTL_E_OUTOFMEMORY = STD_CTL_SCODE!(7), CTL_E_DIVISIONBYZERO = STD_CTL_SCODE!(11), CTL_E_OUTOFSTRINGSPACE = STD_CTL_SCODE!(14), CTL_E_OUTOFSTACKSPACE = STD_CTL_SCODE!(28), CTL_E_BADFILENAMEORNUMBER = STD_CTL_SCODE!(52), CTL_E_FILENOTFOUND = STD_CTL_SCODE!(53), CTL_E_BADFILEMODE = STD_CTL_SCODE!(54), CTL_E_FILEALREADYOPEN = STD_CTL_SCODE!(55), CTL_E_DEVICEIOERROR = STD_CTL_SCODE!(57), CTL_E_FILEALREADYEXISTS = STD_CTL_SCODE!(58), CTL_E_BADRECORDLENGTH = STD_CTL_SCODE!(59), CTL_E_DISKFULL = STD_CTL_SCODE!(61), CTL_E_BADRECORDNUMBER = STD_CTL_SCODE!(63), CTL_E_BADFILENAME = STD_CTL_SCODE!(64), CTL_E_TOOMANYFILES = STD_CTL_SCODE!(67), CTL_E_DEVICEUNAVAILABLE = STD_CTL_SCODE!(68), CTL_E_PERMISSIONDENIED = STD_CTL_SCODE!(70), CTL_E_DISKNOTREADY = STD_CTL_SCODE!(71), CTL_E_PATHFILEACCESSERROR = STD_CTL_SCODE!(75), CTL_E_PATHNOTFOUND = STD_CTL_SCODE!(76), CTL_E_INVALIDPATTERNSTRING = STD_CTL_SCODE!(93), CTL_E_INVALIDUSEOFNULL = STD_CTL_SCODE!(94), CTL_E_INVALIDFILEFORMAT = STD_CTL_SCODE!(321), CTL_E_INVALIDPROPERTYVALUE = STD_CTL_SCODE!(380), CTL_E_INVALIDPROPERTYARRAYINDEX = STD_CTL_SCODE!(381), CTL_E_SETNOTSUPPORTEDATRUNTIME = STD_CTL_SCODE!(382), CTL_E_SETNOTSUPPORTED = STD_CTL_SCODE!(383), CTL_E_NEEDPROPERTYARRAYINDEX = STD_CTL_SCODE!(385), CTL_E_SETNOTPERMITTED = STD_CTL_SCODE!(387), CTL_E_GETNOTSUPPORTEDATRUNTIME = STD_CTL_SCODE!(393), CTL_E_GETNOTSUPPORTED = STD_CTL_SCODE!(394), CTL_E_PROPERTYNOTFOUND = STD_CTL_SCODE!(422), CTL_E_INVALIDCLIPBOARDFORMAT = STD_CTL_SCODE!(460), CTL_E_INVALIDPICTURE = STD_CTL_SCODE!(481), CTL_E_PRINTERERROR = STD_CTL_SCODE!(482), CTL_E_CANTSAVEFILETOTEMP = STD_CTL_SCODE!(735), CTL_E_SEARCHTEXTNOTFOUND = STD_CTL_SCODE!(744), CTL_E_REPLACEMENTSTOOLONG = STD_CTL_SCODE!(746), CTL_E_CUSTOM_FIRST = STD_CTL_SCODE!(600) } enum SCODE CLASS_E_NOTLICENSED = CLASSFACTORY_E_FIRST+2; enum : SCODE { CONNECT_E_FIRST = ITF_ERROR_SCODE_FOR_D!(0x200), CONNECT_E_LAST = ITF_ERROR_SCODE_FOR_D!(0x20F), CONNECT_S_FIRST = ITF_SUCCESS_SCODE_FOR_D!(0x200), CONNECT_S_LAST = ITF_SUCCESS_SCODE_FOR_D!(0x20F), CONNECT_E_NOCONNECTION = CONNECT_E_FIRST + 0, CONNECT_E_ADVISELIMIT = CONNECT_E_FIRST + 1, CONNECT_E_CANNOTCONNECT = CONNECT_E_FIRST + 2, CONNECT_E_OVERRIDDEN = CONNECT_E_FIRST + 3, SELFREG_E_FIRST = ITF_ERROR_SCODE_FOR_D!(0x200), SELFREG_E_LAST = ITF_ERROR_SCODE_FOR_D!(0x20F), SELFREG_S_FIRST = ITF_SUCCESS_SCODE_FOR_D!(0x200), SELFREG_S_LAST = ITF_SUCCESS_SCODE_FOR_D!(0x20F), SELFREG_E_TYPELIB = SELFREG_E_FIRST + 0, SELFREG_E_CLASS = SELFREG_E_FIRST + 1, PERPROP_E_FIRST = ITF_ERROR_SCODE_FOR_D!(0x200), PERPROP_E_LAST = ITF_ERROR_SCODE_FOR_D!(0x20F), PERPROP_S_FIRST = ITF_SUCCESS_SCODE_FOR_D!(0x200), PERPROP_S_LAST = ITF_SUCCESS_SCODE_FOR_D!(0x20F), PERPROP_E_NOPAGEAVAILABLE = PERPROP_E_FIRST } enum { OLEMISC_RECOMPOSEONRESIZE = 0x1, OLEMISC_ONLYICONIC = 0x2, OLEMISC_INSERTNOTREPLACE = 0x4, OLEMISC_STATIC = 0x8, OLEMISC_CANTLINKINSIDE = 0x10, OLEMISC_CANLINKBYOLE1 = 0x20, OLEMISC_ISLINKOBJECT = 0x40, OLEMISC_INSIDEOUT = 0x80, OLEMISC_ACTIVATEWHENVISIBLE = 0x100, OLEMISC_RENDERINGISDEVICEINDEPENDENT = 0x200, OLEMISC_INVISIBLEATRUNTIME = 0x400, OLEMISC_ALWAYSRUN = 0x800, OLEMISC_ACTSLIKEBUTTON = 0x1000, OLEMISC_ACTSLIKELABEL = 0x2000, OLEMISC_NOUIACTIVATE = 0x4000, OLEMISC_ALIGNABLE = 0x8000, OLEMISC_SIMPLEFRAME = 0x10000, OLEMISC_SETCLIENTSITEFIRST = 0x20000, OLEMISC_IMEMODE = 0x40000, OLEMISC_IGNOREACTIVATEWHENVISIBLE = 0x80000, OLEMISC_WANTSTOMENUMERGE = 0x100000, OLEMISC_SUPPORTSMULTILEVELUNDO = 0x200000 } enum OLEIVERB_PROPERTIES = -7; enum VT_STREAMED_PROPSET = 73; enum VT_STORED_PROPSET = 74; enum VT_BLOB_PROPSET = 75; enum VT_VERBOSE_ENUM = 76; enum VT_COLOR = VARENUM.VT_I4; enum VT_XPOS_PIXELS = VARENUM.VT_I4; enum VT_YPOS_PIXELS = VARENUM.VT_I4; enum VT_XSIZE_PIXELS = VARENUM.VT_I4; enum VT_YSIZE_PIXELS = VARENUM.VT_I4; enum VT_XPOS_HIMETRIC = VARENUM.VT_I4; enum VT_YPOS_HIMETRIC = VARENUM.VT_I4; enum VT_XSIZE_HIMETRIC = VARENUM.VT_I4; enum VT_YSIZE_HIMETRIC = VARENUM.VT_I4; enum VT_TRISTATE = VARENUM.VT_I2; enum VT_OPTEXCLUSIVE = VARENUM.VT_BOOL; enum VT_FONT = VARENUM.VT_DISPATCH; enum VT_PICTURE = VARENUM.VT_DISPATCH; enum VT_HANDLE = VARENUM.VT_I4; enum { OCM__BASE = WM_USER + 0x1c00, OCM_COMMAND = OCM__BASE + WM_COMMAND, OCM_CTLCOLORBTN = OCM__BASE + WM_CTLCOLORBTN, OCM_CTLCOLOREDIT = OCM__BASE + WM_CTLCOLOREDIT, OCM_CTLCOLORDLG = OCM__BASE + WM_CTLCOLORDLG, OCM_CTLCOLORLISTBOX = OCM__BASE + WM_CTLCOLORLISTBOX, OCM_CTLCOLORMSGBOX = OCM__BASE + WM_CTLCOLORMSGBOX, OCM_CTLCOLORSCROLLBAR = OCM__BASE + WM_CTLCOLORSCROLLBAR, OCM_CTLCOLORSTATIC = OCM__BASE + WM_CTLCOLORSTATIC, OCM_DRAWITEM = OCM__BASE + WM_DRAWITEM, OCM_MEASUREITEM = OCM__BASE + WM_MEASUREITEM, OCM_DELETEITEM = OCM__BASE + WM_DELETEITEM, OCM_VKEYTOITEM = OCM__BASE + WM_VKEYTOITEM, OCM_CHARTOITEM = OCM__BASE + WM_CHARTOITEM, OCM_COMPAREITEM = OCM__BASE + WM_COMPAREITEM, OCM_HSCROLL = OCM__BASE + WM_HSCROLL, OCM_VSCROLL = OCM__BASE + WM_VSCROLL, OCM_PARENTNOTIFY = OCM__BASE + WM_PARENTNOTIFY, OCM_NOTIFY = OCM__BASE + WM_NOTIFY } enum { CTRLINFO_EATS_RETURN = 1, CTRLINFO_EATS_ESCAPE } enum { XFORMCOORDS_POSITION = 1, XFORMCOORDS_SIZE = 2, XFORMCOORDS_HIMETRICTOCONTAINER = 4, XFORMCOORDS_CONTAINERTOHIMETRIC = 8 } enum GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1; enum { PROPPAGESTATUS_DIRTY = 1, PROPPAGESTATUS_VALIDATE = 2 } enum { PICTURE_SCALABLE = 1, PICTURE_TRANSPARENT = 2 } enum { PICTYPE_UNINITIALIZED = -1, PICTYPE_NONE, // = 0 PICTYPE_BITMAP, PICTYPE_METAFILE, PICTYPE_ICON, PICTYPE_ENHMETAFILE // = 4 } enum { DISPID_AUTOSIZE = -500, DISPID_BACKCOLOR = -501, DISPID_BACKSTYLE = -502, DISPID_BORDERCOLOR = -503, DISPID_BORDERSTYLE = -504, DISPID_BORDERWIDTH = -505, DISPID_DRAWMODE = -507, DISPID_DRAWSTYLE = -508, DISPID_DRAWWIDTH = -509, DISPID_FILLCOLOR = -510, DISPID_FILLSTYLE = -511, DISPID_FONT = -512, DISPID_FORECOLOR = -513, DISPID_ENABLED = -514, DISPID_HWND = -515, DISPID_TABSTOP = -516, DISPID_TEXT = -517, DISPID_CAPTION = -518, DISPID_BORDERVISIBLE = -519, DISPID_APPEARANCE = -520, DISPID_MOUSEPOINTER = -521, DISPID_MOUSEICON = -522, DISPID_PICTURE = -523, DISPID_VALID = -524, DISPID_REFRESH = -550, DISPID_DOCLICK = -551, DISPID_ABOUTBOX = -552, DISPID_CLICK = -600, DISPID_DBLCLICK = -601, DISPID_KEYDOWN = -602, DISPID_KEYPRESS = -603, DISPID_KEYUP = -604, DISPID_MOUSEDOWN = -605, DISPID_MOUSEMOVE = -606, DISPID_MOUSEUP = -607, DISPID_ERROREVENT = -608, DISPID_AMBIENT_BACKCOLOR = -701, DISPID_AMBIENT_DISPLAYNAME = -702, DISPID_AMBIENT_FONT = -703, DISPID_AMBIENT_FORECOLOR = -704, DISPID_AMBIENT_LOCALEID = -705, DISPID_AMBIENT_MESSAGEREFLECT = -706, DISPID_AMBIENT_SCALEUNITS = -707, DISPID_AMBIENT_TEXTALIGN = -708, DISPID_AMBIENT_USERMODE = -709, DISPID_AMBIENT_UIDEAD = -710, DISPID_AMBIENT_SHOWGRABHANDLES = -711, DISPID_AMBIENT_SHOWHATCHING = -712, DISPID_AMBIENT_DISPLAYASDEFAULT = -713, DISPID_AMBIENT_SUPPORTSMNEMONICS = -714, DISPID_AMBIENT_AUTOCLIP = -715, DISPID_AMBIENT_APPEARANCE = -716, DISPID_AMBIENT_CODEPAGE = -725, DISPID_AMBIENT_PALETTE = -726, DISPID_AMBIENT_CHARSET = -727, DISPID_AMBIENT_RIGHTTOLEFT = -732, DISPID_AMBIENT_TOPTOBOTTOM = -733 } enum { DISPID_FONT_NAME = 0, DISPID_FONT_SIZE = 2, DISPID_FONT_BOLD, DISPID_FONT_ITALIC, DISPID_FONT_UNDER, DISPID_FONT_STRIKE, DISPID_FONT_WEIGHT, DISPID_FONT_CHARSET // = 8 } enum { DISPID_PICT_HANDLE = 0, DISPID_PICT_HPAL = 2, DISPID_PICT_TYPE, DISPID_PICT_WIDTH, DISPID_PICT_HEIGHT, DISPID_PICT_RENDER // = 6 } alias IOleControl LPOLECONTROL; alias IOleControlSite LPOLECONTROLSITE; alias ISimpleFrameSite LPSIMPLEFRAMESITE; alias IPersistPropertyBag LPPERSISTPROPERTYBAG; alias IPersistStreamInit LPPERSISTSTREAMINIT; alias IPersistMemory LPPERSISTMEMORY; alias IPropertyNotifySink LPPROPERTYNOTIFYSINK; alias IProvideClassInfo LPPROVIDECLASSINFO; alias IProvideClassInfo2 LPPROVIDECLASSINFO2; alias IConnectionPointContainer LPCONNECTIONPOINTCONTAINER; alias IClassFactory2 LPCLASSFACTORY2; alias ISpecifyPropertyPages LPSPECIFYPROPERTYPAGES; alias IPerPropertyBrowsing LPPERPROPERTYBROWSING; alias IPropertyPage LPPROPERTYPAGE; alias IPropertyPage2 LPPROPERTYPAGE2; alias IPicture LPPICTURE; alias IPictureDisp LPPICTUREDISP; alias int OLE_XPOS_PIXELS; alias int OLE_YPOS_PIXELS; alias int OLE_XSIZE_PIXELS; alias int OLE_YSIZE_PIXELS; alias float OLE_XPOS_CONTAINER; alias float OLE_YPOS_CONTAINER; alias float OLE_XSIZE_CONTAINER; alias VARIANT_BOOL OLE_OPTEXCLUSIVE; alias VARIANT_BOOL OLE_CANCELBOOL; alias VARIANT_BOOL OLE_ENABLEDEFAULTBOOL; align(8): enum OLE_TRISTATE { triUnchecked, triChecked1, triGray } struct OCPFIPARAMS { ULONG cbStructSize; HWND hWndOwner; int x; int y; LPCOLESTR lpszCaption; ULONG cObjects; LPUNKNOWN *lplpUnk; ULONG cPages; CLSID *lpPages; LCID lcid; DISPID dispidInitialProperty; } alias OCPFIPARAMS* LPOCPFIPARAMS; struct FONTDESC { UINT cbSizeofstruct; LPOLESTR lpstrName; CY cySize; SHORT sWeight; SHORT sCharset; BOOL fItalic; BOOL fUnderline; BOOL fStrikethrough; } alias FONTDESC* LPFONTDESC; struct PICTDESC { UINT cbSizeofstruct; UINT picType; union { struct bmp { HBITMAP hbitmap; HPALETTE hpal; } struct wmf { HMETAFILE hmeta; int xExt; int yExt; } struct icon { HICON hicon; } struct emf { HENHMETAFILE hemf; } } } alias PICTDESC* LPPICTDESC; extern(Windows) { HRESULT DllRegisterServer(); HRESULT DllUnregisterServer(); HRESULT OleCreateFontIndirect(LPFONTDESC, REFIID, PVOID*); HRESULT OleCreatePictureIndirect(LPPICTDESC, REFIID, BOOL, PVOID*); HRESULT OleCreatePropertyFrame(HWND, UINT, UINT, LPCOLESTR, ULONG, LPUNKNOWN*, ULONG, LPCLSID, LCID, DWORD, PVOID); HRESULT OleCreatePropertyFrameIndirect(LPOCPFIPARAMS); HCURSOR OleIconToCursor(HINSTANCE, HICON); HRESULT OleLoadPicture(LPSTREAM, LONG, BOOL, REFIID, PVOID*); HRESULT OleLoadPictureEx(LPSTREAM, LONG, BOOL, REFIID, DWORD, DWORD, DWORD, LPVOID*); HRESULT OleLoadPicturePath(LPOLESTR, LPUNKNOWN, DWORD, OLE_COLOR, REFIID, LPVOID*); HRESULT OleLoadPictureFile(VARIANT, LPDISPATCH*); HRESULT OleLoadPictureFileEx(VARIANT, DWORD, DWORD, DWORD, LPDISPATCH*); HRESULT OleSavePictureFile(LPDISPATCH, BSTR); HRESULT OleTranslateColor(OLE_COLOR, HPALETTE, COLORREF*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winsock2.d0000664000175000017500000004017312776214756023423 0ustar kaikai/* Written by Christopher E. Miller $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0). */ module core.sys.windows.winsock2; version (Windows): extern(Windows): nothrow: alias SOCKET = size_t; alias socklen_t = int; enum SOCKET INVALID_SOCKET = cast(SOCKET)~0; enum int SOCKET_ERROR = -1; enum WSADESCRIPTION_LEN = 256; enum WSASYS_STATUS_LEN = 128; struct WSADATA { ushort wVersion; ushort wHighVersion; char[WSADESCRIPTION_LEN + 1] szDescription; char[WSASYS_STATUS_LEN + 1] szSystemStatus; ushort iMaxSockets; ushort iMaxUdpDg; char* lpVendorInfo; } alias LPWSADATA = WSADATA*; enum int IOCPARM_MASK = 0x7F; enum int IOC_IN = cast(int)0x80000000; enum int FIONBIO = cast(int)(IOC_IN | ((uint.sizeof & IOCPARM_MASK) << 16) | (102 << 8) | 126); enum NI_MAXHOST = 1025; enum NI_MAXSERV = 32; @nogc { int WSAStartup(ushort wVersionRequested, LPWSADATA lpWSAData); int WSACleanup(); SOCKET socket(int af, int type, int protocol); int ioctlsocket(SOCKET s, int cmd, uint* argp); int bind(SOCKET s, const(sockaddr)* name, socklen_t namelen); int connect(SOCKET s, const(sockaddr)* name, socklen_t namelen); int listen(SOCKET s, int backlog); SOCKET accept(SOCKET s, sockaddr* addr, socklen_t* addrlen); int closesocket(SOCKET s); int shutdown(SOCKET s, int how); int getpeername(SOCKET s, sockaddr* name, socklen_t* namelen); int getsockname(SOCKET s, sockaddr* name, socklen_t* namelen); int send(SOCKET s, const(void)* buf, int len, int flags); int sendto(SOCKET s, const(void)* buf, int len, int flags, const(sockaddr)* to, socklen_t tolen); int recv(SOCKET s, void* buf, int len, int flags); int recvfrom(SOCKET s, void* buf, int len, int flags, sockaddr* from, socklen_t* fromlen); int getsockopt(SOCKET s, int level, int optname, void* optval, socklen_t* optlen); int setsockopt(SOCKET s, int level, int optname, const(void)* optval, socklen_t optlen); uint inet_addr(const char* cp); int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, const(timeval)* timeout); char* inet_ntoa(in_addr ina); hostent* gethostbyname(const char* name); hostent* gethostbyaddr(const(void)* addr, int len, int type); protoent* getprotobyname(const char* name); protoent* getprotobynumber(int number); servent* getservbyname(const char* name, const char* proto); servent* getservbyport(int port, const char* proto); } enum: int { NI_NOFQDN = 0x01, NI_NUMERICHOST = 0x02, NI_NAMEREQD = 0x04, NI_NUMERICSERV = 0x08, NI_DGRAM = 0x10, } @nogc { int gethostname(const char* name, int namelen); int getaddrinfo(const(char)* nodename, const(char)* servname, const(addrinfo)* hints, addrinfo** res); void freeaddrinfo(addrinfo* ai); int getnameinfo(const(sockaddr)* sa, socklen_t salen, char* host, uint hostlen, char* serv, uint servlen, int flags); } enum WSABASEERR = 10000; enum: int { /* * Windows Sockets definitions of regular Microsoft C error constants */ WSAEINTR = (WSABASEERR+4), WSAEBADF = (WSABASEERR+9), WSAEACCES = (WSABASEERR+13), WSAEFAULT = (WSABASEERR+14), WSAEINVAL = (WSABASEERR+22), WSAEMFILE = (WSABASEERR+24), /* * Windows Sockets definitions of regular Berkeley error constants */ WSAEWOULDBLOCK = (WSABASEERR+35), WSAEINPROGRESS = (WSABASEERR+36), WSAEALREADY = (WSABASEERR+37), WSAENOTSOCK = (WSABASEERR+38), WSAEDESTADDRREQ = (WSABASEERR+39), WSAEMSGSIZE = (WSABASEERR+40), WSAEPROTOTYPE = (WSABASEERR+41), WSAENOPROTOOPT = (WSABASEERR+42), WSAEPROTONOSUPPORT = (WSABASEERR+43), WSAESOCKTNOSUPPORT = (WSABASEERR+44), WSAEOPNOTSUPP = (WSABASEERR+45), WSAEPFNOSUPPORT = (WSABASEERR+46), WSAEAFNOSUPPORT = (WSABASEERR+47), WSAEADDRINUSE = (WSABASEERR+48), WSAEADDRNOTAVAIL = (WSABASEERR+49), WSAENETDOWN = (WSABASEERR+50), WSAENETUNREACH = (WSABASEERR+51), WSAENETRESET = (WSABASEERR+52), WSAECONNABORTED = (WSABASEERR+53), WSAECONNRESET = (WSABASEERR+54), WSAENOBUFS = (WSABASEERR+55), WSAEISCONN = (WSABASEERR+56), WSAENOTCONN = (WSABASEERR+57), WSAESHUTDOWN = (WSABASEERR+58), WSAETOOMANYREFS = (WSABASEERR+59), WSAETIMEDOUT = (WSABASEERR+60), WSAECONNREFUSED = (WSABASEERR+61), WSAELOOP = (WSABASEERR+62), WSAENAMETOOLONG = (WSABASEERR+63), WSAEHOSTDOWN = (WSABASEERR+64), WSAEHOSTUNREACH = (WSABASEERR+65), WSAENOTEMPTY = (WSABASEERR+66), WSAEPROCLIM = (WSABASEERR+67), WSAEUSERS = (WSABASEERR+68), WSAEDQUOT = (WSABASEERR+69), WSAESTALE = (WSABASEERR+70), WSAEREMOTE = (WSABASEERR+71), /* * Extended Windows Sockets error constant definitions */ WSASYSNOTREADY = (WSABASEERR+91), WSAVERNOTSUPPORTED = (WSABASEERR+92), WSANOTINITIALISED = (WSABASEERR+93), /* Authoritative Answer: Host not found */ WSAHOST_NOT_FOUND = (WSABASEERR+1001), HOST_NOT_FOUND = WSAHOST_NOT_FOUND, /* Non-Authoritative: Host not found, or SERVERFAIL */ WSATRY_AGAIN = (WSABASEERR+1002), TRY_AGAIN = WSATRY_AGAIN, /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ WSANO_RECOVERY = (WSABASEERR+1003), NO_RECOVERY = WSANO_RECOVERY, /* Valid name, no data record of requested type */ WSANO_DATA = (WSABASEERR+1004), NO_DATA = WSANO_DATA, /* no address, look for MX record */ WSANO_ADDRESS = WSANO_DATA, NO_ADDRESS = WSANO_ADDRESS } /* * Windows Sockets errors redefined as regular Berkeley error constants */ enum: int { EWOULDBLOCK = WSAEWOULDBLOCK, EINPROGRESS = WSAEINPROGRESS, EALREADY = WSAEALREADY, ENOTSOCK = WSAENOTSOCK, EDESTADDRREQ = WSAEDESTADDRREQ, EMSGSIZE = WSAEMSGSIZE, EPROTOTYPE = WSAEPROTOTYPE, ENOPROTOOPT = WSAENOPROTOOPT, EPROTONOSUPPORT = WSAEPROTONOSUPPORT, ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT, EOPNOTSUPP = WSAEOPNOTSUPP, EPFNOSUPPORT = WSAEPFNOSUPPORT, EAFNOSUPPORT = WSAEAFNOSUPPORT, EADDRINUSE = WSAEADDRINUSE, EADDRNOTAVAIL = WSAEADDRNOTAVAIL, ENETDOWN = WSAENETDOWN, ENETUNREACH = WSAENETUNREACH, ENETRESET = WSAENETRESET, ECONNABORTED = WSAECONNABORTED, ECONNRESET = WSAECONNRESET, ENOBUFS = WSAENOBUFS, EISCONN = WSAEISCONN, ENOTCONN = WSAENOTCONN, ESHUTDOWN = WSAESHUTDOWN, ETOOMANYREFS = WSAETOOMANYREFS, ETIMEDOUT = WSAETIMEDOUT, ECONNREFUSED = WSAECONNREFUSED, ELOOP = WSAELOOP, ENAMETOOLONG = WSAENAMETOOLONG, EHOSTDOWN = WSAEHOSTDOWN, EHOSTUNREACH = WSAEHOSTUNREACH, ENOTEMPTY = WSAENOTEMPTY, EPROCLIM = WSAEPROCLIM, EUSERS = WSAEUSERS, EDQUOT = WSAEDQUOT, ESTALE = WSAESTALE, EREMOTE = WSAEREMOTE } enum: int { EAI_NONAME = WSAHOST_NOT_FOUND, } int WSAGetLastError() @trusted @nogc; enum: int { AF_UNSPEC = 0, AF_UNIX = 1, AF_INET = 2, AF_IMPLINK = 3, AF_PUP = 4, AF_CHAOS = 5, AF_NS = 6, AF_IPX = AF_NS, AF_ISO = 7, AF_OSI = AF_ISO, AF_ECMA = 8, AF_DATAKIT = 9, AF_CCITT = 10, AF_SNA = 11, AF_DECnet = 12, AF_DLI = 13, AF_LAT = 14, AF_HYLINK = 15, AF_APPLETALK = 16, AF_NETBIOS = 17, AF_VOICEVIEW = 18, AF_FIREFOX = 19, AF_UNKNOWN1 = 20, AF_BAN = 21, AF_ATM = 22, AF_INET6 = 23, AF_CLUSTER = 24, AF_12844 = 25, AF_IRDA = 26, AF_NETDES = 28, AF_MAX = 29, PF_UNSPEC = AF_UNSPEC, PF_UNIX = AF_UNIX, PF_INET = AF_INET, PF_IMPLINK = AF_IMPLINK, PF_PUP = AF_PUP, PF_CHAOS = AF_CHAOS, PF_NS = AF_NS, PF_IPX = AF_IPX, PF_ISO = AF_ISO, PF_OSI = AF_OSI, PF_ECMA = AF_ECMA, PF_DATAKIT = AF_DATAKIT, PF_CCITT = AF_CCITT, PF_SNA = AF_SNA, PF_DECnet = AF_DECnet, PF_DLI = AF_DLI, PF_LAT = AF_LAT, PF_HYLINK = AF_HYLINK, PF_APPLETALK = AF_APPLETALK, PF_VOICEVIEW = AF_VOICEVIEW, PF_FIREFOX = AF_FIREFOX, PF_UNKNOWN1 = AF_UNKNOWN1, PF_BAN = AF_BAN, PF_INET6 = AF_INET6, PF_MAX = AF_MAX, } enum: int { SOL_SOCKET = 0xFFFF, } enum: int { SO_DEBUG = 0x0001, SO_ACCEPTCONN = 0x0002, SO_REUSEADDR = 0x0004, SO_KEEPALIVE = 0x0008, SO_DONTROUTE = 0x0010, SO_BROADCAST = 0x0020, SO_USELOOPBACK = 0x0040, SO_LINGER = 0x0080, SO_DONTLINGER = ~SO_LINGER, SO_OOBINLINE = 0x0100, SO_SNDBUF = 0x1001, SO_RCVBUF = 0x1002, SO_SNDLOWAT = 0x1003, SO_RCVLOWAT = 0x1004, SO_SNDTIMEO = 0x1005, SO_RCVTIMEO = 0x1006, SO_ERROR = 0x1007, SO_TYPE = 0x1008, SO_EXCLUSIVEADDRUSE = ~SO_REUSEADDR, TCP_NODELAY = 1, IP_OPTIONS = 1, IP_HDRINCL = 2, IP_TOS = 3, IP_TTL = 4, IP_MULTICAST_IF = 9, IP_MULTICAST_TTL = 10, IP_MULTICAST_LOOP = 11, IP_ADD_MEMBERSHIP = 12, IP_DROP_MEMBERSHIP = 13, IP_DONTFRAGMENT = 14, IP_ADD_SOURCE_MEMBERSHIP = 15, IP_DROP_SOURCE_MEMBERSHIP = 16, IP_BLOCK_SOURCE = 17, IP_UNBLOCK_SOURCE = 18, IP_PKTINFO = 19, IPV6_UNICAST_HOPS = 4, IPV6_MULTICAST_IF = 9, IPV6_MULTICAST_HOPS = 10, IPV6_MULTICAST_LOOP = 11, IPV6_ADD_MEMBERSHIP = 12, IPV6_DROP_MEMBERSHIP = 13, IPV6_JOIN_GROUP = IPV6_ADD_MEMBERSHIP, IPV6_LEAVE_GROUP = IPV6_DROP_MEMBERSHIP, IPV6_V6ONLY = 27, } /// Default FD_SETSIZE value. /// In C/C++, it is redefinable by #define-ing the macro before #include-ing /// winsock.h. In D, use the $(D FD_CREATE) function to allocate a $(D fd_set) /// of an arbitrary size. enum int FD_SETSIZE = 64; struct fd_set_custom(uint SETSIZE) { uint fd_count; SOCKET[SETSIZE] fd_array; } alias fd_set = fd_set_custom!FD_SETSIZE; // Removes. void FD_CLR(SOCKET fd, fd_set* set) pure @nogc { uint c = set.fd_count; SOCKET* start = set.fd_array.ptr; SOCKET* stop = start + c; for(; start != stop; start++) { if(*start == fd) goto found; } return; //not found found: for(++start; start != stop; start++) { *(start - 1) = *start; } set.fd_count = c - 1; } // Tests. int FD_ISSET(SOCKET fd, const(fd_set)* set) pure @nogc { const(SOCKET)* start = set.fd_array.ptr; const(SOCKET)* stop = start + set.fd_count; for(; start != stop; start++) { if(*start == fd) return true; } return false; } // Adds. void FD_SET(SOCKET fd, fd_set* set) pure @nogc { uint c = set.fd_count; set.fd_array.ptr[c] = fd; set.fd_count = c + 1; } // Resets to zero. void FD_ZERO(fd_set* set) pure @nogc { set.fd_count = 0; } /// Creates a new $(D fd_set) with the specified capacity. fd_set* FD_CREATE(uint capacity) pure { // Take into account alignment (SOCKET may be 64-bit and require 64-bit alignment on 64-bit systems) size_t size = (fd_set_custom!1).sizeof - SOCKET.sizeof + (SOCKET.sizeof * capacity); auto data = new ubyte[size]; auto set = cast(fd_set*)data.ptr; FD_ZERO(set); return set; } struct linger { ushort l_onoff; ushort l_linger; } struct protoent { char* p_name; char** p_aliases; short p_proto; } struct servent { char* s_name; char** s_aliases; version (Win64) { char* s_proto; short s_port; } else version (Win32) { short s_port; char* s_proto; } } /+ union in6_addr { private union _u_t { ubyte[16] Byte; ushort[8] Word; } _u_t u; } struct in_addr6 { ubyte[16] s6_addr; } +/ @safe pure @nogc { version(BigEndian) { ushort htons(ushort x) { return x; } uint htonl(uint x) { return x; } } else version(LittleEndian) { private import core.bitop; ushort htons(ushort x) { return cast(ushort)((x >> 8) | (x << 8)); } uint htonl(uint x) { return bswap(x); } } else { static assert(0); } ushort ntohs(ushort x) { return htons(x); } uint ntohl(uint x) { return htonl(x); } } // @safe pure @nogc enum: int { SOCK_STREAM = 1, SOCK_DGRAM = 2, SOCK_RAW = 3, SOCK_RDM = 4, SOCK_SEQPACKET = 5, } enum: int { IPPROTO_IP = 0, IPPROTO_ICMP = 1, IPPROTO_IGMP = 2, IPPROTO_GGP = 3, IPPROTO_TCP = 6, IPPROTO_PUP = 12, IPPROTO_UDP = 17, IPPROTO_IDP = 22, IPPROTO_IPV6 = 41, IPPROTO_ND = 77, IPPROTO_RAW = 255, IPPROTO_MAX = 256, } enum: int { MSG_OOB = 0x1, MSG_PEEK = 0x2, MSG_DONTROUTE = 0x4 } enum: int { SD_RECEIVE = 0, SD_SEND = 1, SD_BOTH = 2, } enum: uint { INADDR_ANY = 0, INADDR_LOOPBACK = 0x7F000001, INADDR_BROADCAST = 0xFFFFFFFF, INADDR_NONE = 0xFFFFFFFF, ADDR_ANY = INADDR_ANY, } enum: int { AI_PASSIVE = 0x1, AI_CANONNAME = 0x2, AI_NUMERICHOST = 0x4, AI_ADDRCONFIG = 0x0400, AI_NON_AUTHORITATIVE = 0x04000, AI_SECURE = 0x08000, AI_RETURN_PREFERRED_NAMES = 0x010000, } struct timeval { int tv_sec; int tv_usec; } union in_addr { private union _S_un_t { private struct _S_un_b_t { ubyte s_b1, s_b2, s_b3, s_b4; } _S_un_b_t S_un_b; private struct _S_un_w_t { ushort s_w1, s_w2; } _S_un_w_t S_un_w; uint S_addr; } _S_un_t S_un; uint s_addr; struct { ubyte s_net, s_host; union { ushort s_imp; struct { ubyte s_lh, s_impno; } } } } union in6_addr { private union _in6_u_t { ubyte[16] u6_addr8; ushort[8] u6_addr16; uint[4] u6_addr32; } _in6_u_t in6_u; ubyte[16] s6_addr8; ushort[8] s6_addr16; uint[4] s6_addr32; alias s6_addr = s6_addr8; } enum in6_addr IN6ADDR_ANY = { s6_addr8: [0] }; enum in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] }; //alias IN6ADDR_ANY_INIT = IN6ADDR_ANY; //alias IN6ADDR_LOOPBACK_INIT = IN6ADDR_LOOPBACK; enum int INET_ADDRSTRLEN = 16; enum int INET6_ADDRSTRLEN = 46; struct sockaddr { short sa_family; ubyte[14] sa_data; } alias sockaddr SOCKADDR; alias SOCKADDR* PSOCKADDR, LPSOCKADDR; struct SOCKADDR_STORAGE { short ss_family; char[6] __ss_pad1; long __ss_align; char[112] __ss_pad2; } alias SOCKADDR_STORAGE* PSOCKADDR_STORAGE; struct sockaddr_in { short sin_family = AF_INET; ushort sin_port; in_addr sin_addr; ubyte[8] sin_zero; } alias sockaddr_in SOCKADDR_IN; alias SOCKADDR_IN* PSOCKADDR_IN, LPSOCKADDR_IN; struct sockaddr_in6 { short sin6_family = AF_INET6; ushort sin6_port; uint sin6_flowinfo; in6_addr sin6_addr; uint sin6_scope_id; } struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char* ai_canonname; sockaddr* ai_addr; addrinfo* ai_next; } struct hostent { char* h_name; char** h_aliases; short h_addrtype; short h_length; char** h_addr_list; char* h_addr() @safe pure nothrow @nogc { return h_addr_list[0]; } } // Note: These are Winsock2!! struct WSAOVERLAPPED; alias LPWSAOVERLAPPED = WSAOVERLAPPED*; alias LPWSAOVERLAPPED_COMPLETION_ROUTINE = void function(uint, uint, LPWSAOVERLAPPED, uint); int WSAIoctl(SOCKET s, uint dwIoControlCode, void* lpvInBuffer, uint cbInBuffer, void* lpvOutBuffer, uint cbOutBuffer, uint* lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); enum IOC_VENDOR = 0x18000000; enum SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4; /* Argument structure for SIO_KEEPALIVE_VALS */ struct tcp_keepalive { uint onoff; uint keepalivetime; uint keepaliveinterval; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/tlhelp32.d0000664000175000017500000001056412776214756023322 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_tlhelp32.d) */ module core.sys.windows.tlhelp32; version (Windows): pragma(lib, "kernel32"); version (ANSI) {} else version = Unicode; private import core.sys.windows.windef; enum : uint { HF32_DEFAULT = 1, HF32_SHARED } enum : uint { LF32_FIXED = 0x1, LF32_FREE = 0x2, LF32_MOVEABLE = 0x4 } enum MAX_MODULE_NAME32 = 255; enum : uint { TH32CS_SNAPHEAPLIST = 0x1, TH32CS_SNAPPROCESS = 0x2, TH32CS_SNAPTHREAD = 0x4, TH32CS_SNAPMODULE = 0x8, TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST|TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE), TH32CS_INHERIT = 0x80000000 } struct HEAPLIST32 { SIZE_T dwSize; DWORD th32ProcessID; ULONG_PTR th32HeapID; DWORD dwFlags; } alias HEAPLIST32* PHEAPLIST32; alias HEAPLIST32* LPHEAPLIST32; struct HEAPENTRY32 { SIZE_T dwSize; HANDLE hHandle; ULONG_PTR dwAddress; SIZE_T dwBlockSize; DWORD dwFlags; DWORD dwLockCount; DWORD dwResvd; DWORD th32ProcessID; ULONG_PTR th32HeapID; } alias HEAPENTRY32* PHEAPENTRY32; alias HEAPENTRY32* LPHEAPENTRY32; struct PROCESSENTRY32W { DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; DWORD cntThreads; DWORD th32ParentProcessID; LONG pcPriClassBase; DWORD dwFlags; WCHAR[MAX_PATH] szExeFile; } alias PROCESSENTRY32W* PPROCESSENTRY32W; alias PROCESSENTRY32W* LPPROCESSENTRY32W; struct THREADENTRY32 { DWORD dwSize; DWORD cntUsage; DWORD th32ThreadID; DWORD th32OwnerProcessID; LONG tpBasePri; LONG tpDeltaPri; DWORD dwFlags; } alias THREADENTRY32* PTHREADENTRY32; alias THREADENTRY32* LPTHREADENTRY32; struct MODULEENTRY32W { DWORD dwSize; DWORD th32ModuleID; DWORD th32ProcessID; DWORD GlblcntUsage; DWORD ProccntUsage; BYTE *modBaseAddr; DWORD modBaseSize; HMODULE hModule; WCHAR[MAX_MODULE_NAME32 + 1] szModule; WCHAR[MAX_PATH] szExePath; } alias MODULEENTRY32W* PMODULEENTRY32W; alias MODULEENTRY32W* LPMODULEENTRY32W; version(Unicode) { alias PROCESSENTRY32W PROCESSENTRY32; alias PPROCESSENTRY32W PPROCESSENTRY32; alias LPPROCESSENTRY32W LPPROCESSENTRY32; alias MODULEENTRY32W MODULEENTRY32; alias PMODULEENTRY32W PMODULEENTRY32; alias LPMODULEENTRY32W LPMODULEENTRY32; } else { struct PROCESSENTRY32 { DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; DWORD cntThreads; DWORD th32ParentProcessID; LONG pcPriClassBase; DWORD dwFlags; CHAR[MAX_PATH] szExeFile; } alias PROCESSENTRY32* PPROCESSENTRY32; alias PROCESSENTRY32* LPPROCESSENTRY32; struct MODULEENTRY32 { DWORD dwSize; DWORD th32ModuleID; DWORD th32ProcessID; DWORD GlblcntUsage; DWORD ProccntUsage; BYTE *modBaseAddr; DWORD modBaseSize; HMODULE hModule; char[MAX_MODULE_NAME32 + 1] szModule; char[MAX_PATH] szExePath; } alias MODULEENTRY32* PMODULEENTRY32; alias MODULEENTRY32* LPMODULEENTRY32; } extern(Windows) nothrow @nogc { BOOL Heap32First(LPHEAPENTRY32,DWORD,DWORD); BOOL Heap32ListFirst(HANDLE,LPHEAPLIST32); BOOL Heap32ListNext(HANDLE,LPHEAPLIST32); BOOL Heap32Next(LPHEAPENTRY32); BOOL Thread32First(HANDLE,LPTHREADENTRY32); BOOL Thread32Next(HANDLE,LPTHREADENTRY32); BOOL Toolhelp32ReadProcessMemory(DWORD,LPCVOID,LPVOID,DWORD,LPDWORD); HANDLE CreateToolhelp32Snapshot(DWORD,DWORD); BOOL Module32FirstW(HANDLE,LPMODULEENTRY32W); BOOL Module32NextW(HANDLE,LPMODULEENTRY32W); BOOL Process32FirstW(HANDLE,LPPROCESSENTRY32W); BOOL Process32NextW(HANDLE,LPPROCESSENTRY32W); } version(Unicode) { alias Module32FirstW Module32First; alias Module32NextW Module32Next; alias Process32FirstW Process32First; alias Process32NextW Process32Next; } else { extern(Windows) nothrow @nogc { BOOL Module32First(HANDLE,LPMODULEENTRY32); BOOL Module32Next(HANDLE,LPMODULEENTRY32); BOOL Process32First(HANDLE,LPPROCESSENTRY32); BOOL Process32Next(HANDLE,LPPROCESSENTRY32); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/uuid.d0000664000175000017500000160154412776214756022640 0ustar kaikaimodule core.sys.windows.uuid; version (Windows): import core.sys.windows.basetyps; export extern(C) { enum IID _DBBMKGUID = {0xF6304BB0, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID _DBCIDGUID = {0xFE284700, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID _GUID_NAMEONLY = {0xE8BF1170, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID ARRAYID_PathProperties = {0x7ECBBA04, 0x2D97, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID BFID_GRAY_16 = {0xF9D6BC00, 0x449C, 0x11D0, [0x91, 0x8C, 0x00, 0xAA, 0x00, 0x6C, 0x1A, 0x01]}; enum IID BFID_GRAY_8 = {0xD93DE910, 0x449C, 0x11D0, [0x91, 0x8C, 0x00, 0xAA, 0x00, 0x6C, 0x1A, 0x01]}; enum IID BFID_MONOCHROME = {0xE436EB78, 0x524F, 0x11CE, [0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70]}; enum IID BFID_RGB_24 = {0xE436EB7D, 0x524F, 0x11CE, [0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70]}; enum IID BFID_RGB_32 = {0xE436EB7E, 0x524F, 0x11CE, [0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70]}; enum IID BFID_RGB_4 = {0xE436EB79, 0x524F, 0x11CE, [0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70]}; enum IID BFID_RGB_555 = {0xE436EB7C, 0x524F, 0x11CE, [0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70]}; enum IID BFID_RGB_565 = {0xE436EB7B, 0x524F, 0x11CE, [0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70]}; enum IID BFID_RGB_8 = {0xE436EB7A, 0x524F, 0x11CE, [0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70]}; enum IID BFID_RGBA_32 = {0x773C9AC0, 0x3274, 0x11D0, [0xB7, 0x24, 0x00, 0xAA, 0x00, 0x6C, 0x1A, 0x01]}; enum IID BHID_LinkTargetItem = {0x3981E228, 0xF559, 0x11D3, [0x8E, 0x3A, 0x00, 0xC0, 0x4F, 0x68, 0x37, 0xD5]}; enum IID BHID_SFObject = {0x3981E224, 0xF559, 0x11D3, [0x8E, 0x3A, 0x00, 0xC0, 0x4F, 0x68, 0x37, 0xD5]}; enum IID BHID_SFUIObject = {0x3981E225, 0xF559, 0x11D3, [0x8E, 0x3A, 0x00, 0xC0, 0x4F, 0x68, 0x37, 0xD5]}; enum IID BHID_SFViewObject = {0x3981E226, 0xF559, 0x11D3, [0x8E, 0x3A, 0x00, 0xC0, 0x4F, 0x68, 0x37, 0xD5]}; enum IID BHID_Storage = {0x3981E227, 0xF559, 0x11D3, [0x8E, 0x3A, 0x00, 0xC0, 0x4F, 0x68, 0x37, 0xD5]}; enum IID BHID_StorageEnum = {0x4621A4E3, 0xF0D6, 0x4773, [0x8A, 0x9C, 0x46, 0xE7, 0x7B, 0x17, 0x48, 0x40]}; enum IID BHID_Stream = {0x1CEBB3AB, 0x7C10, 0x499A, [0xA4, 0x17, 0x92, 0xCA, 0x16, 0xC4, 0xCB, 0x83]}; enum IID CATID_BrowsableShellExt = {0x00021490, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CATID_BrowseInPlace = {0x00021491, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CATID_ClusCfgCapabilities = {0x4653EEC4, 0x2788, 0x4EBD, [0xA8, 0x31, 0x7E, 0x0D, 0x9F, 0x82, 0xD6, 0xE7]}; enum IID CATID_ClusCfgMemberSetChangeListener = {0x8A43EAD4, 0x10F1, 0x440D, [0x8D, 0xAA, 0x1F, 0xE3, 0x8D, 0x16, 0x98, 0xCD]}; enum IID CATID_ClusCfgResourceTypes = {0x7C4CAE52, 0xCAC9, 0x499D, [0x82, 0xC6, 0xBC, 0x6A, 0x21, 0x77, 0xE5, 0x56]}; enum IID CATID_ClusCfgStartupListeners = {0xDF406DB4, 0x7872, 0x4A99, [0xBB, 0x3C, 0x14, 0xA9, 0xC3, 0x39, 0x33, 0xD1]}; enum IID CATID_CommBand = {0x00021494, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CATID_Control = {0x40FC6ED4, 0x2438, 0x11CF, [0xA3, 0xDB, 0x08, 0x00, 0x36, 0xF1, 0x25, 0x02]}; enum IID CATID_DesignTimeUIActivatableControl = {0xF2BB56D1, 0xDB07, 0x11D1, [0xAA, 0x6B, 0x00, 0x60, 0x97, 0xDB, 0x95, 0x39]}; enum IID CATID_DeskBand = {0x00021492, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CATID_DocObject = {0x40FC6ED8, 0x2438, 0x11CF, [0xA3, 0xDB, 0x08, 0x00, 0x36, 0xF1, 0x25, 0x02]}; enum IID CATID_EnumClusCfgManagedResources = {0x02A34F88, 0xD31A, 0x4688, [0xBD, 0xDD, 0x38, 0xA7, 0x39, 0xE4, 0xF8, 0x9B]}; enum IID CATID_InfoBand = {0x00021493, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CATID_Insertable = {0x40FC6ED3, 0x2438, 0x11CF, [0xA3, 0xDB, 0x08, 0x00, 0x36, 0xF1, 0x25, 0x02]}; enum IID CATID_InternetAware = {0x0DE86A58, 0x2BAA, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID CATID_IsShortcut = {0x40FC6ED6, 0x2438, 0x11CF, [0xA3, 0xDB, 0x08, 0x00, 0x36, 0xF1, 0x25, 0x02]}; enum IID CATID_MARSHALER = {0x00000003, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CATID_NeverShowExt = {0x40FC6ED7, 0x2438, 0x11CF, [0xA3, 0xDB, 0x08, 0x00, 0x36, 0xF1, 0x25, 0x02]}; enum IID CATID_PersistsToFile = {0x0DE86A56, 0x2BAA, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID CATID_PersistsToMemory = {0x0DE86A55, 0x2BAA, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID CATID_PersistsToMoniker = {0x0DE86A51, 0x2BAA, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID CATID_PersistsToPropertyBag = {0x0DE86A57, 0x2BAA, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID CATID_PersistsToStorage = {0x0DE86A52, 0x2BAA, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID CATID_PersistsToStream = {0x0DE86A54, 0x2BAA, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID CATID_PersistsToStreamInit = {0x0DE86A53, 0x2BAA, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID CATID_Printable = {0x40FC6ED9, 0x2438, 0x11CF, [0xA3, 0xDB, 0x08, 0x00, 0x36, 0xF1, 0x25, 0x02]}; enum IID CATID_Programmable = {0x40FC6ED5, 0x2438, 0x11CF, [0xA3, 0xDB, 0x08, 0x00, 0x36, 0xF1, 0x25, 0x02]}; enum IID CATID_RequiresDataPathHost = {0x0DE86A50, 0x2BAA, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID CATID_SafeForInitializing = {0x7DD95802, 0x9882, 0x11CF, [0x9F, 0xA9, 0x00, 0xAA, 0x00, 0x6C, 0x42, 0xC4]}; enum IID CATID_SafeForScripting = {0x7DD95801, 0x9882, 0x11CF, [0x9F, 0xA9, 0x00, 0xAA, 0x00, 0x6C, 0x42, 0xC4]}; enum IID CGID_DocHostCommandHandler = {0xF38BC242, 0xB950, 0x11D1, [0x89, 0x18, 0x00, 0xC0, 0x4F, 0xC2, 0xC8, 0x36]}; enum IID CGID_DownloadHost = {0xE0608728, 0xAE4C, 0x11D1, [0xBA, 0x40, 0x00, 0xC0, 0x4F, 0xB9, 0x2D, 0x79]}; enum IID CGID_Explorer = {0x000214D0, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CGID_ExplorerBarDoc = {0x000214D3, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CGID_InternetExplorer = {0xEB7EED00, 0xF74D, 0x11D2, [0xBB, 0x7F, 0x00, 0x10, 0x4B, 0x35, 0xE7, 0xF9]}; enum IID CGID_MSHTML = {0xDE4BA900, 0x59CA, 0x11CF, [0x95, 0x92, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID CGID_ShellDocView = {0x000214D1, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CGID_ShellServiceObject = {0x000214D2, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CGID_ShortCut = {0x93A68750, 0x951A, 0x11D1, [0x94, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]}; enum IID CLSID_1 = {0xD34F1813, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_2 = {0xD34F1814, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_3 = {0xD34F1815, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_4 = {0xD34F1816, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_5 = {0xD34F1817, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_6 = {0xD34F1818, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_7 = {0xD34F1819, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_8 = {0xD34F181A, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_9 = {0xD34F181B, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_a = {0xD34F181C, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_AboutProtocol = {0x3050F406, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_AccessControlEntry = {0xB75AC000, 0x9BDD, 0x11D0, [0x85, 0x2C, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID CLSID_AccessControlList = {0xB85EA052, 0x9BDD, 0x11D0, [0x85, 0x2C, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID CLSID_AccountDiscovery = {0x3DAB30ED, 0x8132, 0x40BF, [0xA8, 0xBA, 0x7B, 0x50, 0x57, 0xF0, 0xCD, 0x10]}; enum IID CLSID_ACLCustomMRU = {0x6935DB93, 0x21E8, 0x4CCC, [0xBE, 0xB9, 0x9F, 0xE3, 0xC7, 0x7A, 0x29, 0x7A]}; enum IID CLSID_ACLHistory = {0x00BB2764, 0x6A77, 0x11D0, [0xA5, 0x35, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62]}; enum IID CLSID_ACListISF = {0x03C036F1, 0xA186, 0x11D0, [0x82, 0x4A, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83]}; enum IID CLSID_ACLMRU = {0x6756A641, 0xDE71, 0x11D0, [0x83, 0x1B, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83]}; enum IID CLSID_ACLMulti = {0x00BB2765, 0x6A77, 0x11D0, [0xA5, 0x35, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62]}; enum IID CLSID_ActiveDesktop = {0x75048700, 0xEF1F, 0x11D0, [0x98, 0x88, 0x00, 0x60, 0x97, 0xDE, 0xAC, 0xF9]}; enum IID CLSID_AdapterInfo = {0x6F9942C9, 0xC1B1, 0x4AB5, [0x93, 0xDA, 0x60, 0x58, 0x99, 0x1D, 0xC8, 0xF3]}; enum IID CLSID_AddrControl = {0x00000348, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_AddressBarParser = {0xE0E11A09, 0x5CB8, 0x4B6C, [0x83, 0x32, 0xE0, 0x07, 0x20, 0xA1, 0x68, 0xF2]}; enum IID CLSID_ADsDSOObject = {0x549365D0, 0xEC26, 0x11CF, [0x83, 0x10, 0x00, 0xAA, 0x00, 0xB5, 0x05, 0xDB]}; enum IID CLSID_ADsSecurityUtility = {0xF270C64A, 0xFFB8, 0x4AE4, [0x85, 0xFE, 0x3A, 0x75, 0xE5, 0x34, 0x79, 0x66]}; enum IID CLSID_ADSystemInfo = {0x50B6327F, 0xAFD1, 0x11D2, [0x9C, 0xB9, 0x00, 0x00, 0xF8, 0x7A, 0x36, 0x9E]}; enum IID CLSID_AlgSetup = {0x27D0BCCC, 0x344D, 0x4287, [0xAF, 0x37, 0x0C, 0x72, 0xC1, 0x61, 0xC1, 0x4C]}; enum IID CLSID_AllClasses = {0x00000330, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_AlphabeticalCategorizer = {0x3C2654C6, 0x7372, 0x4F6B, [0xB3, 0x10, 0x55, 0xD6, 0x12, 0x8F, 0x49, 0xD2]}; enum IID CLSID_AnchorClick = {0x13D5413C, 0x33B9, 0x11D2, [0x95, 0xA7, 0x00, 0xC0, 0x4F, 0x8E, 0xCB, 0x02]}; enum IID CLSID_AnimationComposerFactory = {0x332B2A56, 0xF86C, 0x47E7, [0x86, 0x02, 0xFC, 0x42, 0xAC, 0x8B, 0x99, 0x20]}; enum IID CLSID_AnimationComposerSiteFactory = {0x16911A65, 0xD41D, 0x4431, [0x87, 0xF7, 0xE7, 0x57, 0xF4, 0xD0, 0x3B, 0xD8]}; enum IID CLSID_ApplicationGatewayServices = {0xF8ADE1D3, 0x49DF, 0x4B75, [0x90, 0x05, 0xEF, 0x95, 0x08, 0xE6, 0xA3, 0x37]}; enum IID CLSID_AutoComplete = {0x00BB2763, 0x6A77, 0x11D0, [0xA5, 0x35, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62]}; enum IID CLSID_AutoDiscoveryProvider = {0xC4F3D5BF, 0x4809, 0x44E3, [0x84, 0xA4, 0x36, 0x8B, 0x6B, 0x33, 0xB0, 0xB4]}; enum IID CLSID_AutoplayForSlideShow = {0x00E7B358, 0xF65B, 0x4DCF, [0x83, 0xDF, 0xCD, 0x02, 0x6B, 0x94, 0xBF, 0xD4]}; enum IID CLSID_b = {0xD34F181D, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_BackgroundCopyManager = {0x4991D34B, 0x80A1, 0x4291, [0x83, 0xB6, 0x33, 0x28, 0x36, 0x6B, 0x90, 0x97]}; enum IID CLSID_BackgroundCopyManager1_5 = {0xF087771F, 0xD74F, 0x4C1A, [0xBB, 0x8A, 0xE1, 0x6A, 0xCA, 0x91, 0x24, 0xEA]}; enum IID CLSID_BackgroundCopyQMgr = {0x69AD4AEE, 0x51BE, 0x439B, [0xA9, 0x2C, 0x86, 0xAE, 0x49, 0x0E, 0x8B, 0x30]}; enum IID CLSID_BackLink = {0xFCBF906F, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_BasicImageEffects = {0x16B280C8, 0xEE70, 0x11D1, [0x90, 0x66, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_BasicImageEffectsPP = {0x16B280C9, 0xEE70, 0x11D1, [0x90, 0x66, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_BlockFormats = {0x3050F831, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_BridgeTerminal = {0x8EBAE7A3, 0x8943, 0x11D1, [0x96, 0xB8, 0x00, 0xC0, 0x4F, 0xB6, 0xE8, 0x66]}; enum IID CLSID_c = {0xD34F181E, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_CAccPropServices = {0xB5F8350B, 0x0548, 0x48B1, [0xA6, 0xEE, 0x88, 0xBD, 0x00, 0xB4, 0xA5, 0xE7]}; enum IID CLSID_CActiveIMM = {0x4955DD33, 0xB159, 0x11D0, [0x8F, 0xCF, 0x00, 0xAA, 0x00, 0x6B, 0xCC, 0x59]}; enum IID CLSID_CAnchorBrowsePropertyPage = {0x3050F3BB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CaseIgnoreList = {0x15F88A55, 0x4680, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_CCheckBox = {0x3050F686, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CColorPropPage = {0x0BE35201, 0x8F91, 0x11CE, [0x9D, 0xE3, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51]}; enum IID CLSID_CCombobox = {0x3050F678, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CDBurn = {0xFBEB8A05, 0xBEEE, 0x4442, [0x80, 0x4E, 0x40, 0x9D, 0x6C, 0x45, 0x15, 0xE9]}; enum IID CLSID_CDebugDocumentHelper = {0x83B8BCA6, 0x687C, 0x11D0, [0xA4, 0x05, 0x00, 0xAA, 0x00, 0x60, 0x27, 0x5C]}; enum IID CLSID_CDeviceRect = {0x3050F6D4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CDirect3DRM = {0x4516EC41, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID CLSID_CDirect3DRMAnimation = {0x4FA35698, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMAnimationSet = {0x4FA35699, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMClippedVisual = {0x5434E72D, 0x6D66, 0x11D1, [0xBB, 0x0B, 0x00, 0x00, 0xF8, 0x75, 0x86, 0x5A]}; enum IID CLSID_CDirect3DRMDevice = {0x4FA3568E, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMFace = {0x4FA35693, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMFrame = {0x4FA35690, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMFrameInterpolator = {0x0DE9EAA2, 0x3B84, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID CLSID_CDirect3DRMLight = {0x4FA35694, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMLightInterpolator = {0x0DE9EAA6, 0x3B84, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID CLSID_CDirect3DRMMaterial = {0x4FA35697, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMMaterialInterpolato = {0x0DE9EAA7, 0x3B84, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID CLSID_CDirect3DRMMesh = {0x4FA35691, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMMeshBuilder = {0x4FA35692, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMMeshInterpolator = {0x0DE9EAA3, 0x3B84, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID CLSID_CDirect3DRMProgressiveMesh = {0x4516EC40, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID CLSID_CDirect3DRMShadow = {0x4FA3569B, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMTexture = {0x4FA35695, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMTextureInterpolator = {0x0DE9EAA8, 0x3B84, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID CLSID_CDirect3DRMUserVisual = {0x4FA3569A, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMViewport = {0x4FA3568F, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirect3DRMViewportInterpolato = {0x0DE9EAA1, 0x3B84, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID CLSID_CDirect3DRMWrap = {0x4FA35696, 0x623F, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID CLSID_CDirectXFile = {0x4516EC43, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID CLSID_CDLAgent = {0x7D559C10, 0x9FE9, 0x11D0, [0x93, 0xF7, 0x00, 0xAA, 0x00, 0x59, 0xCE, 0x02]}; enum IID CLSID_CdlProtocol = {0x3DD53D40, 0x7B8B, 0x11D0, [0xB0, 0x13, 0x00, 0xAA, 0x00, 0x59, 0xCE, 0x02]}; enum IID CLSID_CDocBrowsePropertyPage = {0x3050F3B4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CDownloadBehavior = {0x3050F5BE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CEnroll = {0x43F8F289, 0x7A20, 0x11D0, [0x8F, 0x06, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1]}; enum IID CLSID_CEventObj = {0x3050F48A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CFontPropPage = {0x0BE35200, 0x8F91, 0x11CE, [0x9D, 0xE3, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51]}; enum IID CLSID_CFSIconOverlayManager = {0x63B51F81, 0xC868, 0x11D0, [0x99, 0x9C, 0x00, 0xC0, 0x4F, 0xD6, 0x55, 0xE1]}; enum IID CLSID_ChannelAgent = {0xE3A8BDE6, 0xABCE, 0x11D0, [0xBC, 0x4B, 0x00, 0xC0, 0x4F, 0xD9, 0x29, 0xDB]}; enum IID CLSID_ChannelMgr = {0xB3CDAE90, 0xD170, 0x11D0, [0x80, 0x2B, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13]}; enum IID CLSID_CHeaderFooter = {0x3050F6CD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CHtmlArea = {0x3050F64F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CIEOptionElement = {0x3050F698, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CIESelectElement = {0x3050F688, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CImageBrowsePropertyPage = {0x3050F3B3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_ClassInstallFilter = {0x32B533BB, 0xEDAE, 0x11D0, [0xBD, 0x5A, 0x00, 0xAA, 0x00, 0xB9, 0x2A, 0xF1]}; enum IID CLSID_CLayoutRect = {0x3050F664, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_ClientCaps = {0x7E8BC44E, 0xAEFF, 0x11D1, [0x89, 0xC2, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4]}; enum IID CLSID_ClusAppWiz = {0x24F97150, 0x6689, 0x11D1, [0x9A, 0xA7, 0x00, 0xC0, 0x4F, 0xB9, 0x3A, 0x80]}; enum IID CLSID_ClusCfgAsyncEvictCleanup = {0x08F35A72, 0xD7C4, 0x42F4, [0xBC, 0x81, 0x51, 0x88, 0xE1, 0x9D, 0xFA, 0x39]}; enum IID CLSID_ClusCfgEvictCleanup = {0x32152BE9, 0xDE8C, 0x4D0F, [0x81, 0xB0, 0xBC, 0xE5, 0xD1, 0x1E, 0xCB, 0x00]}; enum IID CLSID_ClusCfgResTypeGenScript = {0xD513C4F4, 0x1D34, 0x44A3, [0x83, 0xD4, 0x81, 0x26, 0x51, 0xDB, 0x89, 0x18]}; enum IID CLSID_ClusCfgResTypeMajorityNodeSet = {0xB6870B44, 0x0BDF, 0x4B46, [0xAC, 0x1F, 0x6C, 0x69, 0x1B, 0x62, 0x2E, 0xDF]}; enum IID CLSID_ClusCfgResTypeServices = {0x6A370489, 0xBB52, 0x4727, [0xB7, 0x40, 0x08, 0xF4, 0x94, 0x16, 0x34, 0x78]}; enum IID CLSID_ClusCfgStartupNotify = {0x105EEEB6, 0x32FD, 0x4EA9, [0x89, 0x12, 0x84, 0x3A, 0x7F, 0xF3, 0xCA, 0x2D]}; enum IID CLSID_ClusCfgWizard = {0x1919C4FE, 0x6F46, 0x4027, [0x97, 0x7D, 0x0E, 0xF1, 0xC8, 0xF2, 0x63, 0x72]}; enum IID CLSID_ClusterConfigurationType = {0xBF3768C2, 0xE0E5, 0x448F, [0x95, 0x2B, 0x25, 0xD4, 0x33, 0x2D, 0xEF, 0xA3]}; enum IID CLSID_CMimeTypes = {0x3050F3FE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CMLangConvertCharset = {0xD66D6F99, 0xCDAA, 0x11D0, [0xB8, 0x22, 0x00, 0xC0, 0x4F, 0xC9, 0xB3, 0x1F]}; enum IID CLSID_CMLangString = {0xC04D65CF, 0xB70D, 0x11D0, [0xB1, 0x88, 0x00, 0xAA, 0x00, 0x38, 0xC9, 0x69]}; enum IID CLSID_CMultiLanguage = {0x275C23E2, 0x3747, 0x11D0, [0x9F, 0xEA, 0x00, 0xAA, 0x00, 0x3F, 0x86, 0x46]}; enum IID CLSID_CNetCfg = {0x5B035261, 0x40F9, 0x11D1, [0xAA, 0xEC, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID CLSID_CoDitherToRGB8 = {0xA860CE50, 0x3910, 0x11D0, [0x86, 0xFC, 0x00, 0xA0, 0xC9, 0x13, 0xF7, 0x50]}; enum IID CLSID_CoMapMIMEToCLSID = {0x30C3B080, 0x30FB, 0x11D0, [0xB7, 0x24, 0x00, 0xAA, 0x00, 0x6C, 0x1A, 0x01]}; enum IID CLSID_ComBinding = {0x00000328, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_CommonQuery = {0x83BC5EC0, 0x6F2A, 0x11D0, [0xA1, 0xC4, 0x00, 0xAA, 0x00, 0xC1, 0x6E, 0x65]}; enum IID CLSID_CompositePP = {0x25B33660, 0xFD83, 0x11D1, [0x8A, 0xDE, 0x44, 0x45, 0x53, 0x54, 0x00, 0x01]}; enum IID CLSID_ConnectionCommonUi = {0x7007ACD1, 0x3202, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID CLSID_ConnectionManager = {0xBA126AD1, 0x2166, 0x11D1, [0xB1, 0xD0, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID CLSID_ConnectionManager2 = {0xBA126AE5, 0x2166, 0x11D1, [0xB1, 0xD0, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID CLSID_ControlPanel = {0x21EC2020, 0x3AEA, 0x1069, [0xA2, 0xDD, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D]}; enum IID CLSID_ConvertVBX = {0xFB8F0822, 0x0164, 0x101B, [0x84, 0xED, 0x08, 0x00, 0x2B, 0x2E, 0xC7, 0x13]}; enum IID CLSID_ConvolvePP = {0x25B33661, 0xFD83, 0x11D1, [0x8A, 0xDE, 0x44, 0x45, 0x53, 0x54, 0x00, 0x01]}; enum IID CLSID_COpsProfile = {0x3050F402, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CoSniffStream = {0x6A01FDA0, 0x30DF, 0x11D0, [0xB7, 0x24, 0x00, 0xAA, 0x00, 0x6C, 0x1A, 0x01]}; enum IID CLSID_CPersistDataPeer = {0x3050F487, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CPersistHistory = {0x3050F4C8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CPersistShortcut = {0x3050F4C6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CPersistSnapshot = {0x3050F4C9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CPersistUserData = {0x3050F48E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CPicturePropPage = {0x0BE35202, 0x8F91, 0x11CE, [0x9D, 0xE3, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51]}; enum IID CLSID_CPlugins = {0x3050F3FF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CRadioButton = {0x3050F69C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CrBarn = {0xC3BDF740, 0x0B58, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrBarnPP = {0xFCAD7436, 0xF151, 0x4110, [0xB9, 0x7E, 0x32, 0xBD, 0x60, 0x7F, 0xBD, 0xB8]}; enum IID CLSID_CrBlindPP = {0x213052C1, 0x100D, 0x11D2, [0x8B, 0x82, 0x00, 0xA0, 0xC9, 0x3C, 0x09, 0xB2]}; enum IID CLSID_CrBlinds = {0x00C429C0, 0x0BA9, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrBlur = {0x7312498D, 0xE87A, 0x11D1, [0x81, 0xE0, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID CLSID_CrBlurPP = {0x623E287E, 0xFC0E, 0x11D1, [0x9A, 0x77, 0x00, 0x00, 0xF8, 0x75, 0x6A, 0x10]}; enum IID CLSID_CrEmboss = {0xF515306D, 0x0156, 0x11D2, [0x81, 0xEA, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID CLSID_CrEngrave = {0xF515306E, 0x0156, 0x11D2, [0x81, 0xEA, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID CLSID_CrInset = {0x93073C40, 0x0BA5, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrIris = {0x3F69F351, 0x0379, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrIrisPP = {0x80DE22C4, 0x0F44, 0x11D2, [0x8B, 0x82, 0x00, 0xA0, 0xC9, 0x3C, 0x09, 0xB2]}; enum IID CLSID_CrRadialWipe = {0x424B71AF, 0x0695, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrRadialWipePP = {0x33D932E0, 0x0F48, 0x11D2, [0x8B, 0x82, 0x00, 0xA0, 0xC9, 0x3C, 0x09, 0xB2]}; enum IID CLSID_CrSlide = {0x810E402F, 0x056B, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrSlidePP = {0xCC8CEDE1, 0x1003, 0x11D2, [0x8B, 0x82, 0x00, 0xA0, 0xC9, 0x3C, 0x09, 0xB2]}; enum IID CLSID_CrSpiral = {0xACA97E00, 0x0C7D, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrSpiralPP = {0xC6A4FE81, 0x1022, 0x11D2, [0x8B, 0x82, 0x00, 0xA0, 0xC9, 0x3C, 0x09, 0xB2]}; enum IID CLSID_CrStretch = {0x7658F2A2, 0x0A83, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrStretchPP = {0x15FB95E0, 0x0F77, 0x11D2, [0x8B, 0x82, 0x00, 0xA0, 0xC9, 0x3C, 0x09, 0xB2]}; enum IID CLSID_CrWheel = {0x5AE1DAE0, 0x1461, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrWheelPP = {0xFA9F6180, 0x1464, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrZigzag = {0xE6E73D20, 0x0C8A, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_CrZigzagPP = {0x1559A3C1, 0x102B, 0x11D2, [0x8B, 0x82, 0x00, 0xA0, 0xC9, 0x3C, 0x09, 0xB2]}; enum IID CLSID_CScriptErrorList = {0xEFD01300, 0x160F, 0x11D2, [0xBB, 0x2E, 0x00, 0x80, 0x5F, 0xF7, 0xEF, 0xCA]}; enum IID CLSID_CScrollBar = {0x3050F68A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CSliderBar = {0x3050F68E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CSpinButton = {0x3050F68C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CTemplatePrinter = {0x3050F6B3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_CUrlHistory = {0x3C374A40, 0xBAE4, 0x11CF, [0xBF, 0x7D, 0x00, 0xAA, 0x00, 0x69, 0x46, 0xEE]}; enum IID CLSID_CURLSearchHook = {0xCFBFAE00, 0x17A6, 0x11D0, [0x99, 0xCB, 0x00, 0xC0, 0x4F, 0xD6, 0x44, 0x97]}; enum IID CLSID_CurrentUserClasses = {0x00000332, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_CUtilityButton = {0x3050F6B0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_d = {0xD34F181F, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_DAArray = {0x9CDE7340, 0x3C20, 0x11D0, [0xA3, 0x30, 0x00, 0xAA, 0x00, 0xB9, 0x2C, 0x03]}; enum IID CLSID_DABbox2 = {0x50B4791E, 0x4731, 0x11D0, [0x89, 0x12, 0x00, 0xC0, 0x4F, 0xC2, 0xA0, 0xCA]}; enum IID CLSID_DABbox3 = {0x4A933703, 0xE36F, 0x11D0, [0x9B, 0x99, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID CLSID_DABehavior = {0xC46C1BF2, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DABoolean = {0x25B0F91D, 0xD23D, 0x11D0, [0x9B, 0x85, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID CLSID_DACamera = {0xC46C1BD9, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAColor = {0xC46C1BC9, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DADashStyle = {0x9CADDC0C, 0xAD56, 0x11D1, [0x9F, 0xF8, 0x00, 0xC0, 0x4F, 0xA3, 0x21, 0x95]}; enum IID CLSID_DAEndStyle = {0xFC54BEAB, 0x5B12, 0x11D1, [0x8E, 0x7B, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID CLSID_DAEvent = {0x3E2487C4, 0x8709, 0x11D0, [0xB1, 0x77, 0x00, 0xC0, 0x4F, 0xC2, 0xA0, 0xCA]}; enum IID CLSID_DAFontStyle = {0x3F3DA01A, 0x4705, 0x11D0, [0x87, 0x10, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID CLSID_DAGeometry = {0xC46C1BDB, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAImage = {0xC46C1BCB, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAImportationResult = {0x283807B3, 0x2C60, 0x11D0, [0xA3, 0x1D, 0x00, 0xAA, 0x00, 0xB9, 0x2C, 0x03]}; enum IID CLSID_DAJoinStyle = {0xFC54BEAA, 0x5B12, 0x11D1, [0x8E, 0x7B, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID CLSID_DALineStyle = {0x283807B8, 0x2C60, 0x11D0, [0xA3, 0x1D, 0x00, 0xAA, 0x00, 0xB9, 0x2C, 0x03]}; enum IID CLSID_DAMatte = {0xC46C1BC3, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAMicrophone = {0xC46C1BE3, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAMontage = {0xC46C1BD7, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DANumber = {0xC46C1BC7, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAPair = {0xBC0BFD34, 0xD21D, 0x11D0, [0x93, 0x85, 0x00, 0xC0, 0x4F, 0xB6, 0xBD, 0x36]}; enum IID CLSID_DAPath2 = {0xC46C1BCF, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAPickableResult = {0x34F681D0, 0x3640, 0x11CF, [0x92, 0x94, 0x00, 0xAA, 0x00, 0xB8, 0xA7, 0x33]}; enum IID CLSID_DAPoint2 = {0xC46C1BD5, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAPoint3 = {0xC46C1BE5, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DarwinAppPublisher = {0xCFCCC7A0, 0xA282, 0x11D1, [0x90, 0x82, 0x00, 0x60, 0x08, 0x05, 0x93, 0x82]}; enum IID CLSID_DASound = {0xC46C1BD1, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAStatics = {0xC46C1BF3, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAString = {0xC46C1BD3, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DataChannel = {0xBBB36F15, 0x408D, 0x4056, [0x8C, 0x27, 0x92, 0x08, 0x43, 0xD4, 0x0B, 0xE5]}; enum IID CLSID_DATransform2 = {0xC46C1BDF, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DATransform3 = {0xC46C1BC5, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DATuple = {0x283807B7, 0x2C60, 0x11D0, [0xA3, 0x1D, 0x00, 0xAA, 0x00, 0xB9, 0x2C, 0x03]}; enum IID CLSID_DAUserData = {0x283807B4, 0x2C60, 0x11D0, [0xA3, 0x1D, 0x00, 0xAA, 0x00, 0xB9, 0x2C, 0x03]}; enum IID CLSID_DAVector2 = {0xC46C1BE1, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAVector3 = {0xC46C1BC0, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAView = {0x960D8EFF, 0xE494, 0x11D1, [0xAB, 0x75, 0x00, 0xC0, 0x4F, 0xD9, 0x2B, 0x6B]}; enum IID CLSID_DAViewerControl = {0xC46C1BEB, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DAViewerControlWindowed = {0xC46C1BF1, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID CLSID_DCOMAccessControl = {0x0000031D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_DebugHelper = {0x0BFCC060, 0x8C1D, 0x11D0, [0xAC, 0xCD, 0x00, 0xAA, 0x00, 0x60, 0x27, 0x5C]}; enum IID CLSID_DeCompMimeFilter = {0x8F6B0360, 0xB80D, 0x11D0, [0xA9, 0xB3, 0x00, 0x60, 0x97, 0x94, 0x23, 0x11]}; enum IID CLSID_DefaultDebugSessionProvider = {0x834128A2, 0x51F4, 0x11D0, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID CLSID_DirectDraw = {0xD7B70EE0, 0x4340, 0x11CF, [0xB0, 0x63, 0x00, 0x20, 0xAF, 0xC2, 0xCD, 0x35]}; enum IID CLSID_DirectDrawClipper = {0x593817A0, 0x7DB3, 0x11CF, [0xA2, 0xDE, 0x00, 0xAA, 0x00, 0xB9, 0x33, 0x56]}; enum IID CLSID_DirectDrawFactory2 = {0xB9DC4790, 0x4AF1, 0x11D1, [0x8C, 0x4C, 0x00, 0xC0, 0x4F, 0xD9, 0x30, 0xC5]}; enum IID CLSID_DirectInput = {0x25E609E0, 0xB259, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID CLSID_DirectInputDevice = {0x25E609E1, 0xB259, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID CLSID_DirectMusic = {0x636B9F10, 0x0C7D, 0x11D1, [0x95, 0xB2, 0x00, 0x20, 0xAF, 0xDC, 0x74, 0x21]}; enum IID CLSID_DirectMusicBand = {0x79BA9E00, 0xB6EE, 0x11D1, [0x86, 0xBE, 0x00, 0xC0, 0x4F, 0xBF, 0x8F, 0xEF]}; enum IID CLSID_DirectMusicBandTrack = {0xD2AC2894, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicChordMap = {0xD2AC288F, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicChordMapTrack = {0xD2AC2896, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicChordTrack = {0xD2AC288B, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicCollection = {0x480FF4B0, 0x28B2, 0x11D1, [0xBE, 0xF7, 0x00, 0xC0, 0x4F, 0xBF, 0x8F, 0xEF]}; enum IID CLSID_DirectMusicCommandTrack = {0xD2AC288C, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicComposer = {0xD2AC2890, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicGraph = {0xD2AC2884, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicLoader = {0xD2AC2892, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicMotifTrack = {0xD2AC288E, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicMuteTrack = {0xD2AC2898, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicPerformance = {0xD2AC2881, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicSegment = {0xD2AC2882, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicSegmentState = {0xD2AC2883, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicSeqTrack = {0xD2AC2886, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicSignPostTrack = {0xF17E8672, 0xC3B4, 0x11D1, [0x87, 0x0B, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicStyle = {0xD2AC288A, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicStyleTrack = {0xD2AC288D, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicSynth = {0x58C2B4D0, 0x46E7, 0x11D1, [0x89, 0xAC, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29]}; enum IID CLSID_DirectMusicSysExTrack = {0xD2AC2887, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicTempoTrack = {0xD2AC2885, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectMusicTimeSigTrack = {0xD2AC2888, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID CLSID_DirectPlay = {0xD1EB6D20, 0x8923, 0x11D0, [0x9D, 0x97, 0x00, 0xA0, 0xC9, 0x0A, 0x43, 0xCB]}; enum IID CLSID_DirectPlayLobby = {0x2FE8F810, 0xB2A5, 0x11D0, [0xA7, 0x87, 0x00, 0x00, 0xF8, 0x03, 0xAB, 0xFC]}; enum IID CLSID_DirectSound = {0x47D4D946, 0x62E8, 0x11CF, [0x93, 0xBC, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID CLSID_DirectSoundCapture = {0xB0210780, 0x89CD, 0x11D0, [0xAF, 0x08, 0x00, 0xA0, 0xC9, 0x25, 0xCD, 0x16]}; enum IID CLSID_DispatchMapper = {0xE9225296, 0xC759, 0x11D1, [0xA0, 0x2B, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID CLSID_DNWithBinary = {0x7E99C0A3, 0xF935, 0x11D2, [0xBA, 0x96, 0x00, 0xC0, 0x4F, 0xB6, 0xD0, 0xD1]}; enum IID CLSID_DNWithString = {0x334857CC, 0xF934, 0x11D2, [0xBA, 0x96, 0x00, 0xC0, 0x4F, 0xB6, 0xD0, 0xD1]}; enum IID CLSID_DocFileColumnProvider = {0x24F14F01, 0x7B1C, 0x11D1, [0x83, 0x8F, 0x00, 0x00, 0xF8, 0x04, 0x61, 0xCF]}; enum IID CLSID_DocHostUIHandler = {0x7057E952, 0xBD1B, 0x11D1, [0x89, 0x19, 0x00, 0xC0, 0x4F, 0xC2, 0xC8, 0x36]}; enum IID CLSID_DOMChildrenCollection = {0x3050F5AA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_DOMDocument = {0x2933BF90, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID CLSID_DOMFreeThreadedDocument = {0x2933BF91, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID CLSID_DragDropHelper = {0x4657278A, 0x411B, 0x11D2, [0x83, 0x9A, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0]}; enum IID CLSID_DriveSizeCategorizer = {0x94357B53, 0xCA29, 0x4B78, [0x83, 0xAE, 0xE8, 0xFE, 0x74, 0x09, 0x13, 0x4F]}; enum IID CLSID_DriveTypeCategorizer = {0xB0A8F3CF, 0x4333, 0x4BAB, [0x88, 0x73, 0x1C, 0xCB, 0x1C, 0xAD, 0xA4, 0x8B]}; enum IID CLSID_DsDisplaySpecifier = {0x1AB4A8C0, 0x6A0B, 0x11D2, [0xAD, 0x49, 0x00, 0xC0, 0x4F, 0xA3, 0x1A, 0x86]}; enum IID CLSID_DsDomainTreeBrowser = {0x1698790A, 0xE2B4, 0x11D0, [0xB0, 0xB1, 0x00, 0xC0, 0x4F, 0xD8, 0xDC, 0xA6]}; enum IID CLSID_DsFindAdvanced = {0x83EE3FE3, 0x57D9, 0x11D0, [0xB9, 0x32, 0x00, 0xA0, 0x24, 0xAB, 0x2D, 0xBB]}; enum IID CLSID_DsFindComputer = {0x16006700, 0x87AD, 0x11D0, [0x91, 0x40, 0x00, 0xAA, 0x00, 0xC1, 0x6E, 0x65]}; enum IID CLSID_DsFindContainer = {0xC1B3CBF2, 0x886A, 0x11D0, [0x91, 0x40, 0x00, 0xAA, 0x00, 0xC1, 0x6E, 0x65]}; enum IID CLSID_DsFindDomainController = {0x538C7B7E, 0xD25E, 0x11D0, [0x97, 0x42, 0x00, 0xA0, 0xC9, 0x06, 0xAF, 0x45]}; enum IID CLSID_DsFindFrsMembers = {0x94CE4B18, 0xB3D3, 0x11D1, [0xB9, 0xB4, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0xB0]}; enum IID CLSID_DsFindObjects = {0x83EE3FE1, 0x57D9, 0x11D0, [0xB9, 0x32, 0x00, 0xA0, 0x24, 0xAB, 0x2D, 0xBB]}; enum IID CLSID_DsFindPeople = {0x83EE3FE2, 0x57D9, 0x11D0, [0xB9, 0x32, 0x00, 0xA0, 0x24, 0xAB, 0x2D, 0xBB]}; enum IID CLSID_DsFindPrinter = {0xB577F070, 0x7EE2, 0x11D0, [0x91, 0x3F, 0x00, 0xAA, 0x00, 0xC1, 0x6E, 0x65]}; enum IID CLSID_DsFindVolume = {0xC1B3CBF1, 0x886A, 0x11D0, [0x91, 0x40, 0x00, 0xAA, 0x00, 0xC1, 0x6E, 0x65]}; enum IID CLSID_DsFolderProperties = {0x9E51E0D0, 0x6E0F, 0x11D2, [0x96, 0x01, 0x00, 0xC0, 0x4F, 0xA3, 0x1A, 0x86]}; enum IID CLSID_DsPropertyPages = {0x0D45D530, 0x764B, 0x11D0, [0xA1, 0xCA, 0x00, 0xAA, 0x00, 0xC1, 0x6E, 0x65]}; enum IID CLSID_DsQuery = {0x8A23E65E, 0x31C2, 0x11D0, [0x89, 0x1C, 0x00, 0xA0, 0x24, 0xAB, 0x2D, 0xBB]}; enum IID CLSID_DWbemClassObject = {0x64AB3751, 0x12BC, 0x11D1, [0x9E, 0x61, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID CLSID_DWbemContext = {0x752FF212, 0xF7B7, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID CLSID_DWbemLocator = {0xCB7CA032, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID CLSID_DX2D = {0x473AA80B, 0x4577, 0x11D1, [0x81, 0xA8, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID CLSID_DXFade = {0x16B280C5, 0xEE70, 0x11D1, [0x90, 0x66, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_DXGradient = {0xC6365470, 0xF667, 0x11D1, [0x90, 0x67, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_DXLUTBuilder = {0x1E54333B, 0x2A00, 0x11D1, [0x81, 0x98, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID CLSID_DXRasterizer = {0x8652CE55, 0x9E80, 0x11D1, [0x90, 0x53, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_DXSurface = {0x0E890F83, 0x5F79, 0x11D1, [0x90, 0x43, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_DXSurfaceModifier = {0x3E669F1D, 0x9C23, 0x11D1, [0x90, 0x53, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_DXTAlpha = {0xADC6CB82, 0x424C, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID CLSID_DXTAlphaImageLoader = {0x0C7EFBDE, 0x0303, 0x4C6F, [0xA4, 0xF7, 0x31, 0xFA, 0x2B, 0xE5, 0xE3, 0x97]}; enum IID CLSID_DXTAlphaImageLoaderPP = {0x8C80CE2D, 0x850D, 0x47DA, [0x8E, 0xCD, 0x55, 0x02, 0x35, 0x62, 0xD1, 0x67]}; enum IID CLSID_DXTAlphaPP = {0xD687A7E0, 0x4BA4, 0x11D2, [0x8A, 0xDE, 0x00, 0xA0, 0xC9, 0x8E, 0x65, 0x27]}; enum IID CLSID_DXTaskManager = {0x4CB26C03, 0xFF93, 0x11D0, [0x81, 0x7E, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID CLSID_DXTBarn = {0xEC9BA17D, 0x60B5, 0x462B, [0xA6, 0xD8, 0x14, 0xB8, 0x90, 0x57, 0xE2, 0x2A]}; enum IID CLSID_DXTBlinds = {0x9A4A4A51, 0xFB3A, 0x4F4B, [0x9B, 0x57, 0xA2, 0x91, 0x2A, 0x28, 0x97, 0x69]}; enum IID CLSID_DXTCheckerBoard = {0xB3EE7802, 0x8224, 0x4787, [0xA1, 0xEA, 0xF0, 0xDE, 0x16, 0xDE, 0xAB, 0xD3]}; enum IID CLSID_DXTCheckerBoardPP = {0xCBF47525, 0x98D2, 0x45EA, [0xB8, 0x43, 0xFD, 0x21, 0x3D, 0x93, 0x2B, 0x10]}; enum IID CLSID_DXTChroma = {0x421516C1, 0x3CF8, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID CLSID_DXTChromaPP = {0xEC7E0760, 0x4C76, 0x11D2, [0x8A, 0xDE, 0x00, 0xA0, 0xC9, 0x8E, 0x65, 0x27]}; enum IID CLSID_DXTComposite = {0x9A43A844, 0x0831, 0x11D1, [0x81, 0x7F, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID CLSID_DXTConvolution = {0x2BC0EF29, 0xE6BA, 0x11D1, [0x81, 0xDD, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID CLSID_DXTDropShadow = {0xADC6CB86, 0x424C, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID CLSID_DXTDropShadowPP = {0xEC7E0761, 0x4C76, 0x11D2, [0x8A, 0xDE, 0x00, 0xA0, 0xC9, 0x8E, 0x65, 0x27]}; enum IID CLSID_DXTFilter = {0x385A91BC, 0x1E8A, 0x4E4A, [0xA7, 0xA6, 0xF4, 0xFC, 0x1E, 0x6C, 0xA1, 0xBD]}; enum IID CLSID_DXTFilterBehavior = {0x649EEC1E, 0xB579, 0x4E8C, [0xBB, 0x3B, 0x49, 0x97, 0xF8, 0x42, 0x65, 0x36]}; enum IID CLSID_DXTFilterCollection = {0xA7EE7F34, 0x3BD1, 0x427F, [0x92, 0x31, 0xF9, 0x41, 0xE9, 0xB7, 0xE1, 0xFE]}; enum IID CLSID_DXTFilterFactory = {0x81397204, 0xF51A, 0x4571, [0x8D, 0x7B, 0xDC, 0x03, 0x05, 0x21, 0xAA, 0xBD]}; enum IID CLSID_DXTGlow = {0x9F8E6421, 0x3D9B, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID CLSID_DXTGlowPP = {0xEC7E0764, 0x4C76, 0x11D2, [0x8A, 0xDE, 0x00, 0xA0, 0xC9, 0x8E, 0x65, 0x27]}; enum IID CLSID_DXTGradientD = {0x623E2882, 0xFC0E, 0x11D1, [0x9A, 0x77, 0x00, 0x00, 0xF8, 0x75, 0x6A, 0x10]}; enum IID CLSID_DXTGradientWipe = {0xB96F67A2, 0x30C2, 0x47E8, [0xBD, 0x85, 0x70, 0xA2, 0xC9, 0x48, 0xB5, 0x0F]}; enum IID CLSID_DXTICMFilter = {0xA1BFB370, 0x5A9F, 0x4429, [0xBB, 0x72, 0xB1, 0x3E, 0x2F, 0xEA, 0xED, 0xEF]}; enum IID CLSID_DXTICMFilterPP = {0x1958FB12, 0x31E6, 0x47E5, [0xAA, 0x49, 0xB2, 0x3D, 0x12, 0xC8, 0x53, 0xE6]}; enum IID CLSID_DXTInset = {0x76F363F2, 0x7E9F, 0x4ED7, [0xA6, 0xA7, 0xEE, 0x30, 0x35, 0x1B, 0x66, 0x28]}; enum IID CLSID_DXTIris = {0x049F2CE6, 0xD996, 0x4721, [0x89, 0x7A, 0xDB, 0x15, 0xCE, 0x9E, 0xB7, 0x3D]}; enum IID CLSID_DXTLabel = {0x54702535, 0x2606, 0x11D1, [0x99, 0x9C, 0x00, 0x00, 0xF8, 0x75, 0x6A, 0x10]}; enum IID CLSID_DXTLight = {0xF9EFBEC2, 0x4302, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID CLSID_DXTLightPP = {0x694AF25F, 0x124D, 0x11D3, [0x91, 0xD5, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID CLSID_DXTMaskFilter = {0x3A04D93B, 0x1EDD, 0x4F3F, [0xA3, 0x75, 0xA0, 0x3E, 0xC1, 0x95, 0x72, 0xC4]}; enum IID CLSID_DXTMatrix = {0x4ABF5A06, 0x5568, 0x4834, [0xBE, 0xE3, 0x32, 0x7A, 0x6D, 0x95, 0xA6, 0x85]}; enum IID CLSID_DXTMatrixPP = {0xC591103A, 0xB3A8, 0x4D47, [0xA3, 0xF7, 0x2A, 0xEE, 0xE4, 0xB8, 0x01, 0x3F]}; enum IID CLSID_DXTMetaBurnFilm = {0x107045D1, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaCenterPeel = {0xAA0D4D0C, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID CLSID_DXTMetaColorFade = {0x2A54C908, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaFlowMotion = {0x2A54C90B, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaGriddler = {0x2A54C911, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaGriddler2 = {0x2A54C913, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaJaws = {0x2A54C904, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaLightWipe = {0x107045C8, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaLiquid = {0xAA0D4D0A, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID CLSID_DXTMetaPageTurn = {0xAA0D4D08, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID CLSID_DXTMetaPeelPiece = {0xAA0D4D10, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID CLSID_DXTMetaPeelSmall = {0xAA0D4D0E, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID CLSID_DXTMetaPeelSplit = {0xAA0D4D12, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID CLSID_DXTMetaRadialScaleWipe = {0x107045CA, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaRipple = {0xAA0D4D03, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID CLSID_DXTMetaRoll = {0x9C61F46E, 0x0530, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID CLSID_DXTMetaThreshold = {0x2A54C915, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaTwister = {0x107045CF, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaVacuum = {0x2A54C90D, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaWater = {0x107045C5, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaWhiteOut = {0x107045CC, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID CLSID_DXTMetaWormHole = {0x0E6AE022, 0x0C83, 0x11D2, [0x8C, 0xD4, 0x00, 0x10, 0x4B, 0xC7, 0x5D, 0x9A]}; enum IID CLSID_DXTMotionBlur = {0xDD13DE77, 0xD3BA, 0x42D4, [0xB5, 0xC6, 0x77, 0x45, 0xFA, 0x4E, 0x2D, 0x4B]}; enum IID CLSID_DXTMotionBlurPP = {0x926433E1, 0x7F8F, 0x4BC6, [0xBE, 0xC4, 0x8C, 0x12, 0x6C, 0x6B, 0x7D, 0xC4]}; enum IID CLSID_DXTRadialWipe = {0x164484A9, 0x35D9, 0x4FB7, [0x9F, 0xAB, 0x48, 0x27, 0x3B, 0x96, 0xAA, 0x1D]}; enum IID CLSID_DXTRandomBars = {0x2E7700B7, 0x27C4, 0x437F, [0x9F, 0xBF, 0x1E, 0x8B, 0xE2, 0x81, 0x75, 0x66]}; enum IID CLSID_DXTRandomBarsPP = {0xE3E6AE11, 0x7FDC, 0x40C4, [0xAF, 0xBF, 0x1D, 0xCE, 0xA8, 0x28, 0x62, 0xCC]}; enum IID CLSID_DXTRandomDissolve = {0xF7F4A1B6, 0x8E87, 0x452F, [0xA2, 0xD7, 0x30, 0x77, 0xF5, 0x08, 0xDB, 0xC0]}; enum IID CLSID_DXTransformFactory = {0xD1FE6762, 0xFC48, 0x11D0, [0x88, 0x3A, 0x3C, 0x8B, 0x00, 0xC1, 0x00, 0x00]}; enum IID CLSID_DXTRedirect = {0x42B07B28, 0x2280, 0x4937, [0xB0, 0x35, 0x02, 0x93, 0xFB, 0x81, 0x27, 0x81]}; enum IID CLSID_DXTRevealTrans = {0xE31E87C4, 0x86EA, 0x4940, [0x9B, 0x8A, 0x5B, 0xD5, 0xD1, 0x79, 0xA7, 0x37]}; enum IID CLSID_DXTScale = {0x555278E2, 0x05DB, 0x11D1, [0x88, 0x3A, 0x3C, 0x8B, 0x00, 0xC1, 0x00, 0x00]}; enum IID CLSID_DXTShadow = {0xE71B4063, 0x3E59, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID CLSID_DXTShadowPP = {0xEC7E0765, 0x4C76, 0x11D2, [0x8A, 0xDE, 0x00, 0xA0, 0xC9, 0x8E, 0x65, 0x27]}; enum IID CLSID_DXTSlide = {0xD1C5A1E7, 0xCC47, 0x4E32, [0xBD, 0xD2, 0x4B, 0x3C, 0x5F, 0xC5, 0x0A, 0xF5]}; enum IID CLSID_DXTSpiral = {0x4A03DCB9, 0x6E17, 0x4A39, [0x88, 0x45, 0x4E, 0xE7, 0xDC, 0x53, 0x31, 0xA5]}; enum IID CLSID_DXTStretch = {0xF088DE73, 0xBDD0, 0x4E3C, [0x81, 0xF8, 0x6D, 0x32, 0xF4, 0xFE, 0x9D, 0x28]}; enum IID CLSID_DXTStrips = {0x63A4B1FC, 0x259A, 0x4A5B, [0x81, 0x29, 0xA8, 0x3B, 0x8C, 0x9E, 0x6F, 0x4F]}; enum IID CLSID_DXTStripsPP = {0xFEC0B7EE, 0x7AEC, 0x4067, [0x9E, 0xE1, 0xFA, 0xCF, 0xB7, 0xCE, 0x9A, 0xF9]}; enum IID CLSID_DXTWave = {0xADC6CB88, 0x424C, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID CLSID_DXTWavePP = {0xF12456C0, 0x4C9E, 0x11D2, [0x8A, 0xDE, 0x00, 0xA0, 0xC9, 0x8E, 0x65, 0x27]}; enum IID CLSID_DXTWipe = {0xAF279B30, 0x86EB, 0x11D1, [0x81, 0xBF, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID CLSID_DXTWipePP = {0x7FFE4D08, 0xFBFD, 0x11D1, [0x9A, 0x77, 0x00, 0x00, 0xF8, 0x75, 0x6A, 0x10]}; enum IID CLSID_DXTZigzag = {0x23E26328, 0x3928, 0x40F2, [0x95, 0xE5, 0x93, 0xCA, 0xD6, 0x90, 0x16, 0xEB]}; enum IID CLSID_EAPOLManager = {0xBA126AE4, 0x2166, 0x11D1, [0xB1, 0xD0, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID CLSID_Email = {0x8F92A857, 0x478E, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_EnumAdapterInfo = {0x6F9942CA, 0xC1B1, 0x4AB5, [0x93, 0xDA, 0x60, 0x58, 0x99, 0x1D, 0xC8, 0xF3]}; enum IID CLSID_EVENTQUEUE = {0x6E0FF466, 0x339E, 0x11D1, [0xBE, 0x5B, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0xBB]}; enum IID CLSID_EXTENDEDERRORINFO = {0xC8B522CF, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID CLSID_FadePP = {0x16B280C6, 0xEE70, 0x11D1, [0x90, 0x66, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_FaxNumber = {0xA5062215, 0x4681, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_FilePlaybackTerminal = {0x0CB9914C, 0x79CD, 0x47DC, [0xAD, 0xB0, 0x32, 0x7F, 0x47, 0xCE, 0xFB, 0x20]}; enum IID CLSID_FileProtocol = {0x79EAC9E7, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_FileRecordingTerminal = {0x521F3D06, 0xC3D0, 0x4511, [0x86, 0x17, 0x86, 0xB9, 0xA7, 0x83, 0xDA, 0x77]}; enum IID CLSID_FileRecordingTrack = {0xBF14A2E4, 0xE88B, 0x4EF5, [0x97, 0x40, 0x5A, 0xC5, 0xD0, 0x22, 0xF8, 0xC9]}; enum IID CLSID_FileSearchBand = {0xC4EE31F3, 0x4768, 0x11D2, [0xBE, 0x5C, 0x00, 0xA0, 0xC9, 0xA8, 0x3D, 0xA1]}; enum IID CLSID_FileSysColumnProvider = {0x0D2E74C4, 0x3C34, 0x11D2, [0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71]}; enum IID CLSID_FileTerminal = {0xAAF578F1, 0xDC70, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID CLSID_FolderShortcut = {0x0AFACED1, 0xE828, 0x11D1, [0x91, 0x87, 0xB5, 0x32, 0xF1, 0xE9, 0x57, 0x5D]}; enum IID CLSID_FolderViewHost = {0x20B1CB23, 0x6968, 0x4EB9, [0xB7, 0xD4, 0xA6, 0x6D, 0x00, 0xD0, 0x7C, 0xEE]}; enum IID CLSID_FontNames = {0x3050F83A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_FramesCollection = {0x3050F7F6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_FreeSpaceCategorizer = {0xB5607793, 0x24AC, 0x44C7, [0x82, 0xE2, 0x83, 0x17, 0x26, 0xAA, 0x6C, 0xB7]}; enum IID CLSID_FtpProtocol = {0x79EAC9E3, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_GblComponentCategoriesMgr = {0x0002E006, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_GLOBAL_BROADCAST = {0xD34F1810, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_GopherProtocol = {0x79EAC9E4, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_GradientPP = {0x623E2880, 0xFC0E, 0x11D1, [0x9A, 0x77, 0x00, 0x00, 0xF8, 0x75, 0x6A, 0x10]}; enum IID CLSID_HandsetTerminal = {0xAAF578EB, 0xDC70, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID CLSID_HeadsetTerminal = {0xAAF578ED, 0xDC70, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID CLSID_HNetCfgMgr = {0x46C166AA, 0x3108, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID CLSID_Hold = {0xB3AD3E13, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_HomeNetAutoConfigService = {0x9A8EA3B5, 0x572E, 0x4CB3, [0x9E, 0xB9, 0xEC, 0x68, 0x9A, 0xC5, 0x75, 0xAE]}; enum IID CLSID_HomePage = {0x766BF2AE, 0xD650, 0x11D1, [0x98, 0x11, 0x00, 0xC0, 0x4F, 0xC3, 0x1D, 0x2E]}; enum IID CLSID_HostDialogHelper = {0x429AF92C, 0xA51F, 0x11D2, [0x86, 0x1E, 0x00, 0xC0, 0x4F, 0xA3, 0x5C, 0x89]}; enum IID CLSID_HTADocument = {0x3050F5C8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTCAttachBehavior = {0x3050F5F5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTCDefaultDispatch = {0x3050F4FC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTCDescBehavior = {0x3050F5DD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTCEventBehavior = {0x3050F4FE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTCMethodBehavior = {0x3050F630, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTCPropertyBehavior = {0x3050F5DE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLAnchorElement = {0x3050F248, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLAppBehavior = {0x3050F5CB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLApplication = {0x3050F4D8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLAreaElement = {0x3050F283, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLAreasCollection = {0x3050F4CA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLAttributeCollection = {0x3050F4CC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLBaseElement = {0x3050F276, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLBaseFontElement = {0x3050F282, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLBGsound = {0x3050F370, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLBlockElement = {0x3050F281, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLBody = {0x3050F24A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLBRElement = {0x3050F280, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLButtonElement = {0x3050F2C6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLCommentElement = {0x3050F317, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLCurrentStyle = {0x3050F3DC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDDElement = {0x3050F27F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDefaults = {0x3050F6C8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDialog = {0x3050F28A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDivElement = {0x3050F27E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDivPosition = {0x3050F249, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HtmlDlgSafeHelper = {0x3050F819, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDListElement = {0x3050F27D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDocument = {0x25336920, 0x03F9, 0x11CF, [0x8F, 0xD0, 0x00, 0xAA, 0x00, 0x68, 0x6F, 0x13]}; enum IID CLSID_HTMLDOMAttribute = {0x3050F4B2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDOMImplementation = {0x3050F80E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDOMTextNode = {0x3050F4BA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLDTElement = {0x3050F27C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLElementCollection = {0x3050F4CB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLEmbed = {0x3050F25D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLFieldSetElement = {0x3050F3E8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLFontElement = {0x3050F27B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLFormElement = {0x3050F251, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLFrameBase = {0x3050F312, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLFrameElement = {0x3050F314, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLFrameSetSite = {0x3050F31A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLGenericElement = {0x3050F4B8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLHeadElement = {0x3050F493, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLHeaderElement = {0x3050F27A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLHistory = {0xFECEAAA3, 0x8405, 0x11CF, [0x8B, 0xA1, 0x00, 0xAA, 0x00, 0x47, 0x6D, 0xA6]}; enum IID CLSID_HTMLHRElement = {0x3050F252, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLHtmlElement = {0x3050F491, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLIFrame = {0x3050F316, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLImageElementFactory = {0x3050F38F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLImg = {0x3050F241, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLInputButtonElement = {0x3050F2B4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLInputElement = {0x3050F5D8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLInputFileElement = {0x3050F2AE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLInputImage = {0x3050F2C4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLInputTextElement = {0x3050F2AB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLIsIndexElement = {0x3050F278, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLLabelElement = {0x3050F32B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLLegendElement = {0x3050F3E9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLLIElement = {0x3050F273, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLLinkElement = {0x3050F277, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLListElement = {0x3050F272, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLLoadOptions = {0x18845040, 0x0FA5, 0x11D1, [0xBA, 0x19, 0x00, 0xC0, 0x4F, 0xD9, 0x12, 0xD0]}; enum IID CLSID_HTMLLocation = {0x163BB1E1, 0x6E00, 0x11CF, [0x83, 0x7A, 0x48, 0xDC, 0x04, 0xC1, 0x00, 0x00]}; enum IID CLSID_HTMLMapElement = {0x3050F271, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLMarqueeElement = {0x3050F2B9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLMetaElement = {0x3050F275, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLNamespace = {0x3050F6BC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLNamespaceCollection = {0x3050F6B9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLNavigator = {0xFECEAAA6, 0x8405, 0x11CF, [0x8B, 0xA1, 0x00, 0xAA, 0x00, 0x47, 0x6D, 0xA6]}; enum IID CLSID_HTMLNextIdElement = {0x3050F279, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLNoShowElement = {0x3050F38B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLObjectElement = {0x3050F24E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLOListElement = {0x3050F270, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLOptionButtonElement = {0x3050F2BE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLOptionElement = {0x3050F24D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLOptionElementFactory = {0x3050F38D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLParaElement = {0x3050F26F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLParamElement = {0x3050F83E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLPhraseElement = {0x3050F26E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLPluginDocument = {0x25336921, 0x03F9, 0x11CF, [0x8F, 0xD0, 0x00, 0xAA, 0x00, 0x68, 0x6F, 0x13]}; enum IID CLSID_HTMLPopup = {0x3050F667, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLRenderStyle = {0x3050F6AA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLRichtextElement = {0x3050F2DF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLRuleStyle = {0x3050F3D0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLScreen = {0x3050F35D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLScriptElement = {0x3050F28C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLSelectElement = {0x3050F245, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLSpanElement = {0x3050F3F5, 0x98B4, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLSpanFlow = {0x3050F3E6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLStyle = {0x3050F285, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLStyleElement = {0x3050F37D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLStyleFontFace = {0x3050F3D4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLStyleSheet = {0x3050F2E4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLStyleSheetPage = {0x3050F7EF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLStyleSheetPagesCollection = {0x3050F7F1, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLStyleSheetRule = {0x3050F3CE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLStyleSheetRulesCollection = {0x3050F3CD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLStyleSheetsCollection = {0x3050F37F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLTable = {0x3050F26B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLTableCaption = {0x3050F2EC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLTableCell = {0x3050F246, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLTableCol = {0x3050F26C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLTableRow = {0x3050F26D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLTableSection = {0x3050F2E9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLTextAreaElement = {0x3050F2AC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLTextElement = {0x3050F26A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLTitleElement = {0x3050F284, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLUListElement = {0x3050F269, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLUnknownElement = {0x3050F268, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLUrnCollection = {0x3050F580, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HTMLWindow2 = {0xD48A6EC6, 0x6A4A, 0x11CF, [0x94, 0xA7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID CLSID_HTMLWindowProxy = {0x3050F391, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_HttpProtocol = {0x79EAC9E2, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_HttpSProtocol = {0x79EAC9E5, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_HWShellExecute = {0xFFB8655F, 0x81B9, 0x4FCE, [0xB8, 0x9C, 0x9A, 0x6B, 0xA7, 0x6D, 0x13, 0xE7]}; enum IID CLSID_IActiveXSafetyProvider = {0xAAF8C6CE, 0xF972, 0x11D0, [0x97, 0xEB, 0x00, 0xAA, 0x00, 0x61, 0x53, 0x33]}; enum IID CLSID_IImageDecodeFilter = {0x607FD4E8, 0x0A03, 0x11D1, [0xAB, 0x1D, 0x00, 0xC0, 0x4F, 0xC9, 0xB3, 0x04]}; enum IID CLSID_IImgCtx = {0x3050F3D6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_ImageList = {0x7C476BA2, 0x02B1, 0x48F4, [0x80, 0x48, 0xB2, 0x46, 0x19, 0xDD, 0xC0, 0x58]}; enum IID CLSID_ImageProperties = {0x7AB770C7, 0x0E23, 0x4D7A, [0x8A, 0xA2, 0x19, 0xBF, 0xAD, 0x47, 0x98, 0x29]}; enum IID CLSID_InProcFreeMarshaler = {0x0000033A, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_IntDitherer = {0x05F6FE1A, 0xECEF, 0x11D0, [0xAA, 0xE7, 0x00, 0xC0, 0x4F, 0xC9, 0xB3, 0x04]}; enum IID CLSID_IntelliForms = {0x613AB92E, 0x16BF, 0x11D2, [0xBC, 0xA5, 0x00, 0xC0, 0x4F, 0xD9, 0x29, 0xDB]}; enum IID CLSID_Internet = {0x871C5380, 0x42A0, 0x1069, [0xA2, 0xEA, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D]}; enum IID CLSID_InternetButtons = {0x1E796980, 0x9CC5, 0x11D1, [0xA8, 0x3F, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0x61]}; enum IID CLSID_InternetConnectionBeaconServic = {0x04DF613A, 0x5610, 0x11D4, [0x9E, 0xC8, 0x00, 0xB0, 0xD0, 0x22, 0xDD, 0x1F]}; enum IID CLSID_InternetExplorer = {0x0002DF01, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_InternetPrintOrdering = {0xADD36AA8, 0x751A, 0x4579, [0xA2, 0x66, 0xD6, 0x6F, 0x52, 0x02, 0xCC, 0xBB]}; enum IID CLSID_InternetSecurityManager = {0x7B8A2D94, 0x0AC9, 0x11D1, [0x89, 0x6C, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4]}; enum IID CLSID_InternetShortcut = {0xFBF23B40, 0xE3F0, 0x101B, [0x84, 0x88, 0x00, 0xAA, 0x00, 0x3E, 0x56, 0xF8]}; enum IID CLSID_InternetZoneManager = {0x7B8A2D95, 0x0AC9, 0x11D1, [0x89, 0x6C, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4]}; enum IID CLSID_LanConnectionManager = {0xBA126AD3, 0x2166, 0x11D1, [0xB1, 0xD0, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID CLSID_LargeInteger = {0x927971F5, 0x0939, 0x11D1, [0x8B, 0xE1, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID CLSID_LDAPConnectionObject = {0x7DA2A9C4, 0x0C46, 0x43BD, [0xB0, 0x4E, 0xD9, 0x2B, 0x1B, 0xE2, 0x7C, 0x45]}; enum IID CLSID_LDAPObject = {0x05709878, 0x5195, 0x466C, [0x9E, 0x64, 0x48, 0x7C, 0xE3, 0xCA, 0x20, 0xBF]}; enum IID CLSID_LinkColumnProvider = {0x24F14F02, 0x7B1C, 0x11D1, [0x83, 0x8F, 0x00, 0x00, 0xF8, 0x04, 0x61, 0xCF]}; enum IID CLSID_LocalMachineClasses = {0x00000331, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_LogManager = {0x8FDA8FA4, 0x8763, 0x479F, [0xB9, 0xB1, 0x22, 0x02, 0xB2, 0x80, 0xD2, 0x93]}; enum IID CLSID_LUTBuilderPP = {0x25B33662, 0xFD83, 0x11D1, [0x8A, 0xDE, 0x44, 0x45, 0x53, 0x54, 0x00, 0x01]}; enum IID CLSID_MachineDebugManager = {0x0C0A3666, 0x30C9, 0x11D0, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID CLSID_MailAutoDiscovery = {0x008FD5DD, 0x6DBB, 0x48E3, [0x99, 0x1B, 0x2D, 0x3E, 0xD6, 0x58, 0x51, 0x6A]}; enum IID CLSID_MailProtocolADEntry = {0x61A5D6F3, 0xC131, 0x4C35, [0xBF, 0x40, 0x90, 0xA5, 0x0F, 0x21, 0x41, 0x22]}; enum IID CLSID_ManualResetEvent = {0x0000032C, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_McastAddressAllocation = {0xDF0DAEF2, 0xA289, 0x11D1, [0x86, 0x97, 0x00, 0x60, 0x08, 0xB0, 0xE5, 0xD2]}; enum IID CLSID_MediaStreamTerminal = {0xE2F7AEF7, 0x4971, 0x11D1, [0xA6, 0x71, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xE8]}; enum IID CLSID_MergedCategorizer = {0x8E827C11, 0x33E7, 0x4BC1, [0xB2, 0x42, 0x8C, 0xD9, 0xA1, 0xC2, 0xB3, 0x04]}; enum IID CLSID_MHTMLDocument = {0x3050F3D9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_MicrophoneTerminal = {0xAAF578EF, 0xDC70, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID CLSID_MicrosoftDS = {0xFE1290F0, 0xCFBD, 0x11CF, [0xA3, 0x30, 0x00, 0xAA, 0x00, 0xC1, 0x6E, 0x65]}; enum IID CLSID_MigrationWizardAuto = {0x67331D85, 0xBE17, 0x42F6, [0x8D, 0x3F, 0x47, 0xB8, 0xE8, 0xB2, 0x66, 0x37]}; enum IID CLSID_MkProtocol = {0x79EAC9E6, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_MofCompiler = {0x6DAF9757, 0x2E37, 0x11D2, [0xAE, 0xC9, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID CLSID_MountedVolume = {0x12518493, 0x00B2, 0x11D2, [0x9F, 0xA5, 0x9E, 0x34, 0x20, 0x52, 0x41, 0x53]}; enum IID CLSID_MSBurnEngineObj = {0x520CCA67, 0x51A5, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID CLSID_MSDATT = {0xC8B522CE, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID CLSID_MSDAVTM = {0x0C733A8E, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID CLSID_MSDiscMasterObj = {0x520CCA63, 0x51A5, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID CLSID_MSDiscRecorderObj = {0x520CCA61, 0x51A5, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID CLSID_MSDiscStashObj = {0x520CCA65, 0x51A5, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID CLSID_MSEnumDiscRecordersObj = {0x8A03567A, 0x63CB, 0x4BA8, [0xBA, 0xF6, 0x52, 0x11, 0x98, 0x16, 0xD1, 0xEF]}; enum IID CLSID_MSOButtons = {0x178F34B8, 0xA282, 0x11D2, [0x86, 0xC5, 0x00, 0xC0, 0x4F, 0x8E, 0xEA, 0x99]}; enum IID CLSID_MyComputer = {0x20D04FE0, 0x3AEA, 0x1069, [0xA2, 0xD8, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D]}; enum IID CLSID_MyDocuments = {0x450D8FBA, 0xAD25, 0x11D0, [0x98, 0xA8, 0x08, 0x00, 0x36, 0x1B, 0x11, 0x03]}; enum IID CLSID_NameTranslate = {0x274FAE1F, 0x3626, 0x11D1, [0xA3, 0xA4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_NetAddress = {0xB0B71247, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_NetConnectionHNetUtil = {0xBA126AE3, 0x2166, 0x11D1, [0xB1, 0xD0, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID CLSID_NetConnectionUiUtilities = {0x7007ACD3, 0x3202, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID CLSID_NetCrawler = {0x601AC3DC, 0x786A, 0x4EB0, [0xBF, 0x40, 0xEE, 0x35, 0x21, 0xE7, 0x0B, 0xFB]}; enum IID CLSID_NetSharingManager = {0x5C63C1AD, 0x3956, 0x4FF8, [0x84, 0x86, 0x40, 0x03, 0x47, 0x58, 0x31, 0x5B]}; enum IID CLSID_NetworkDomain = {0x46E06680, 0x4BF0, 0x11D1, [0x83, 0xEE, 0x00, 0xA0, 0xC9, 0x0D, 0xC8, 0x49]}; enum IID CLSID_NetworkPlaces = {0x208D2C60, 0x3AEA, 0x1069, [0xA2, 0xD7, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D]}; enum IID CLSID_NetworkServer = {0xC0542A90, 0x4BF0, 0x11D1, [0x83, 0xEE, 0x00, 0xA0, 0xC9, 0x0D, 0xC8, 0x49]}; enum IID CLSID_NetworkShare = {0x54A754C0, 0x4BF0, 0x11D1, [0x83, 0xEE, 0x00, 0xA0, 0xC9, 0x0D, 0xC8, 0x49]}; enum IID CLSID_NetworkType = {0xD4F3D51B, 0x1755, 0x4953, [0x9C, 0x8B, 0x24, 0x95, 0xAB, 0xE5, 0xE0, 0x7E]}; enum IID CLSID_NodeType = {0x1AAA3D11, 0x4792, 0x44E4, [0x9D, 0x49, 0x78, 0xFE, 0xD3, 0x69, 0x1A, 0x14]}; enum IID CLSID_NotificaitonTest1 = {0xC733E501, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_NotificaitonTest2 = {0xC733E502, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_NotificaitonTest3 = {0xC733E503, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_NotificaitonTest4 = {0xC733E504, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_NotificationManager = {0xE1813DD0, 0xAADA, 0x4738, [0xB5, 0xFF, 0x96, 0xB4, 0x18, 0x9C, 0x50, 0x19]}; enum IID CLSID_ObjectManager = {0x955661BD, 0xCCA2, 0x4EAC, [0x91, 0xD0, 0xA0, 0x39, 0x6A, 0x28, 0xAE, 0xFD]}; enum IID CLSID_OctetList = {0x1241400F, 0x4680, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_OldHTMLDocument = {0xD48A6EC9, 0x6A4A, 0x11CF, [0x94, 0xA7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID CLSID_OldHTMLFormElement = {0x0D04D285, 0x6BEC, 0x11CF, [0x8B, 0x97, 0x00, 0xAA, 0x00, 0x47, 0x6D, 0xA6]}; enum IID CLSID_OLEDB_CONVERSIONLIBRARY = {0xC8B522D1, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID CLSID_OLEDB_ENUMERATOR = {0xC8B522D0, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID CLSID_OLEDB_ROWPOSITIONLIBRARY = {0x2048EEE6, 0x7FA2, 0x11D0, [0x9E, 0x6A, 0x00, 0xA0, 0xC9, 0x13, 0x8C, 0x29]}; enum IID CLSID_PassportClientServices = {0x2D2307C8, 0x7DB4, 0x40D6, [0x91, 0x00, 0xD5, 0x2A, 0xF4, 0xF9, 0x7A, 0x5B]}; enum IID CLSID_Path = {0xB2538919, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_Pathname = {0x080D0D78, 0xF421, 0x11D0, [0xA3, 0x6E, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_PeerFactory = {0x3050F4CF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_PendingProxyConnection = {0xD8A68E5E, 0x2B37, 0x426C, [0xA3, 0x29, 0xC1, 0x17, 0xC1, 0x4C, 0x42, 0x9E]}; enum IID CLSID_PersistentDataChannel = {0xBC9B54AB, 0x7883, 0x4C13, [0x90, 0x9F, 0x03, 0x3D, 0x03, 0x26, 0x79, 0x90]}; enum IID CLSID_PersistPropset = {0xFB8F0821, 0x0164, 0x101B, [0x84, 0xED, 0x08, 0x00, 0x2B, 0x2E, 0xC7, 0x13]}; enum IID CLSID_Picture_Dib = {0x00000316, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_Picture_EnhMetafile = {0x00000319, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_Picture_Metafile = {0x00000315, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_Pixelate = {0x4CCEA634, 0xFBE0, 0x11D1, [0x90, 0x6A, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_PixelatePP = {0x4CCEA635, 0xFBE0, 0x11D1, [0x90, 0x6A, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID CLSID_PluggableSuperclassRegistratio = {0xBB918E32, 0x2A5C, 0x4986, [0xAB, 0x40, 0x16, 0x86, 0xA0, 0x34, 0x39, 0x0A]}; enum IID CLSID_PluggableTerminalRegistration = {0x45234E3E, 0x61CC, 0x4311, [0xA3, 0xAB, 0x24, 0x80, 0x82, 0x55, 0x44, 0x82]}; enum IID CLSID_PostAgent = {0xD8BD2030, 0x6FC9, 0x11D0, [0x86, 0x4F, 0x00, 0xAA, 0x00, 0x68, 0x09, 0xD9]}; enum IID CLSID_PostalAddress = {0x0A75AFCD, 0x4680, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_PrimaryControlChannel = {0x3CEB5509, 0xC1CD, 0x432F, [0x9D, 0x8F, 0x65, 0xD1, 0xE2, 0x86, 0xAA, 0x80]}; enum IID CLSID_Printers = {0x2227A280, 0x3AEA, 0x1069, [0xA2, 0xDE, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D]}; enum IID CLSID_PROCESS_BROADCAST = {0xD34F1811, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_ProcessDebugManager = {0x78A51822, 0x51F4, 0x11D0, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID CLSID_ProgressDialog = {0xF8383852, 0xFCD3, 0x11D1, [0xA6, 0xB9, 0x00, 0x60, 0x97, 0xDF, 0x5B, 0xD4]}; enum IID CLSID_PropertiesUI = {0xD912F8CF, 0x0396, 0x4915, [0x88, 0x4E, 0xFB, 0x42, 0x5D, 0x32, 0x94, 0x3B]}; enum IID CLSID_PropertyEntry = {0x72D3EDC2, 0xA4C4, 0x11D0, [0x85, 0x33, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID CLSID_PropertyValue = {0x7B9E38B0, 0xA97C, 0x11D0, [0x85, 0x34, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID CLSID_PSBindCtx = {0x00000312, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_PSClassObject = {0x0000030E, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_PSClientSite = {0x0000030D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_PSDragDrop = {0x00000311, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_PSEnumerators = {0x00000313, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_PseudoSink = {0xE002E4F0, 0xE6EA, 0x11D2, [0x9C, 0xB3, 0x00, 0x10, 0x5A, 0x1F, 0x48, 0x01]}; enum IID CLSID_PSGenObject = {0x0000030C, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_PSInPlaceActive = {0x0000030F, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_PSInPlaceFrame = {0x00000310, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_PSUrlMonProxy = {0x79EAC9F1, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_PublishDropTarget = {0xCC6EEFFB, 0x43F6, 0x46C5, [0x96, 0x19, 0x51, 0xD5, 0x71, 0x96, 0x7F, 0x7D]}; enum IID CLSID_PublishingWizard = {0x6B33163C, 0x76A5, 0x4B6C, [0xBF, 0x21, 0x45, 0xDE, 0x9C, 0xD5, 0x03, 0xA1]}; enum IID CLSID_QueryAssociations = {0xA07034FD, 0x6CAA, 0x4954, [0xAC, 0x3F, 0x97, 0xA2, 0x72, 0x16, 0xF9, 0x8A]}; enum IID CLSID_QueryCancelAutoPlay = {0x331F1768, 0x05A9, 0x4DDD, [0xB8, 0x6E, 0xDA, 0xE3, 0x4D, 0xDC, 0x99, 0x8A]}; enum IID CLSID_RecycleBin = {0x645FF040, 0x5081, 0x101B, [0x9F, 0x08, 0x00, 0xAA, 0x00, 0x2F, 0x95, 0x4E]}; enum IID CLSID_RemoteUnknownPSFactory = {0x00000340, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_Rendezvous = {0xF1029E5B, 0xCB5B, 0x11D0, [0x8D, 0x59, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID CLSID_ReplicaPointer = {0xF5D1BADF, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_Request = {0x6BC096B1, 0x0CE6, 0x11D1, [0xBA, 0xAE, 0x00, 0xC0, 0x4F, 0xC2, 0xE2, 0x0D]}; enum IID CLSID_RequestMakeCall = {0xAC48FFE0, 0xF8C4, 0x11D1, [0xA0, 0x30, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID CLSID_ResProtocol = {0x3050F3BC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_RTCClient = {0x7A42EA29, 0xA2B7, 0x40C4, [0xB0, 0x91, 0xF6, 0xF0, 0x24, 0xAA, 0x89, 0xBE]}; enum IID CLSID_Scriptlet = {0xAE24FDAE, 0x03C6, 0x11D1, [0x8B, 0x76, 0x00, 0x80, 0xC7, 0x44, 0xF3, 0x89]}; enum IID CLSID_SdoMachine = {0xE9218AE7, 0x9E91, 0x11D1, [0xBF, 0x60, 0x00, 0x80, 0xC7, 0x84, 0x6B, 0xC0]}; enum IID CLSID_SdpConferenceBlob = {0x9B2719DD, 0xB696, 0x11D0, [0xA4, 0x89, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID CLSID_SearchAssistantOC = {0xB45FF030, 0x4447, 0x11D2, [0x85, 0xDE, 0x00, 0xC0, 0x4F, 0xA3, 0x5C, 0x89]}; enum IID CLSID_SearchCommand = {0xB005E690, 0x678D, 0x11D1, [0xB7, 0x58, 0x00, 0xA0, 0xC9, 0x05, 0x64, 0xFE]}; enum IID CLSID_SecondaryControlChannel = {0x7B3181A0, 0xC92F, 0x4567, [0xB0, 0xFA, 0xCD, 0x9A, 0x10, 0xEC, 0xD7, 0xD1]}; enum IID CLSID_SecurityDescriptor = {0xB958F73C, 0x9BDD, 0x11D0, [0x85, 0x2C, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID CLSID_SENS = {0xD597CAFE, 0x5B9F, 0x11D1, [0x8D, 0xD2, 0x00, 0xAA, 0x00, 0x4A, 0xBD, 0x5E]}; enum IID CLSID_ServiceManager = {0xABD0388A, 0xDEC1, 0x44F3, [0x98, 0xE1, 0x8D, 0x5C, 0xC8, 0x0B, 0x97, 0xEB]}; enum IID CLSID_SharingApplicationDefinition = {0x46C166B0, 0x3108, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID CLSID_SharingConfiguration = {0x46C166B1, 0x3108, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID CLSID_SharingManagerEnumApplicationDe = {0x46C166AE, 0x3108, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID CLSID_SharingManagerEnumPortMapping = {0x46C166AF, 0x3108, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID CLSID_SharingManagerEnumPrivateConnec = {0x46C166AD, 0x3108, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID CLSID_SharingManagerEnumPublicConnect = {0x46C166AC, 0x3108, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID CLSID_Shell = {0x13709620, 0xC279, 0x11CE, [0xA4, 0x9E, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID CLSID_ShellBrowserWindow = {0xC08AFD90, 0xF2A1, 0x11D1, [0x84, 0x55, 0x00, 0xA0, 0xC9, 0x1F, 0x38, 0x80]}; enum IID CLSID_ShellDesktop = {0x00021400, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_ShellDispatchInproc = {0x0A89A860, 0xD7B1, 0x11CE, [0x83, 0x50, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID CLSID_ShellFolderItem = {0x2FE352EA, 0xFD1F, 0x11D2, [0xB1, 0xF4, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x3E]}; enum IID CLSID_ShellFolderView = {0x62112AA1, 0xEBE4, 0x11CF, [0xA5, 0xFB, 0x00, 0x20, 0xAF, 0xE7, 0x29, 0x2D]}; enum IID CLSID_ShellFolderViewOC = {0x9BA05971, 0xF6A8, 0x11CF, [0xA4, 0x42, 0x00, 0xA0, 0xC9, 0x0A, 0x8F, 0x39]}; enum IID CLSID_ShellFSFolder = {0xF3364BA0, 0x65B9, 0x11CE, [0xA9, 0xBA, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37]}; enum IID CLSID_ShellImageDataFactory = {0x66E4E4FB, 0xF385, 0x4DD0, [0x8D, 0x74, 0xA2, 0xEF, 0xD1, 0xBC, 0x61, 0x78]}; enum IID CLSID_ShellLink = {0x00021401, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_ShellLinkObject = {0x11219420, 0x1768, 0x11D1, [0x95, 0xBE, 0x00, 0x60, 0x97, 0x97, 0xEA, 0x4F]}; enum IID CLSID_ShellLocalMachine = {0x60664CAF, 0xAF0D, 0x0005, [0xA3, 0x00, 0x5C, 0x7D, 0x25, 0xFF, 0x22, 0xA0]}; enum IID CLSID_ShellLogonEnumUsers = {0x60664CAF, 0xAF0D, 0x0004, [0xA3, 0x00, 0x5C, 0x7D, 0x25, 0xFF, 0x22, 0xA0]}; enum IID CLSID_ShellLogonStatusHost = {0x60664CAF, 0xAF0D, 0x0007, [0xA3, 0x00, 0x5C, 0x7D, 0x25, 0xFF, 0x22, 0xA0]}; enum IID CLSID_ShellLogonUser = {0x60664CAF, 0xAF0D, 0x0003, [0xA3, 0x00, 0x5C, 0x7D, 0x25, 0xFF, 0x22, 0xA0]}; enum IID CLSID_ShellNameSpace = {0x55136805, 0xB2DE, 0x11D1, [0xB9, 0xF2, 0x00, 0xA0, 0xC9, 0x8B, 0xC5, 0x47]}; enum IID CLSID_ShellUIHelper = {0x64AB4BB7, 0x111E, 0x11D1, [0x8F, 0x79, 0x00, 0xC0, 0x4F, 0xC2, 0xFB, 0xE1]}; enum IID CLSID_ShellWindows = {0x9BA05972, 0xF6A8, 0x11CF, [0xA4, 0x42, 0x00, 0xA0, 0xC9, 0x0A, 0x8F, 0x39]}; enum IID CLSID_SizeCategorizer = {0x55D7B852, 0xF6D1, 0x42F2, [0xAA, 0x75, 0x87, 0x28, 0xA1, 0xB2, 0xD2, 0x64]}; enum IID CLSID_SoftDistExt = {0xB15B8DC0, 0xC7E1, 0x11D0, [0x86, 0x80, 0x00, 0xAA, 0x00, 0xBD, 0xCB, 0x71]}; enum IID CLSID_SpeakerphoneTerminal = {0xAAF578EE, 0xDC70, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID CLSID_SpeakersTerminal = {0xAAF578F0, 0xDC70, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID CLSID_SpeechUIServer = {0x1443904B, 0x34E4, 0x40F6, [0xB3, 0x0F, 0x6B, 0xEB, 0x81, 0x26, 0x7B, 0x80]}; enum IID CLSID_StaticDib = {0x00000316, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_StaticMetafile = {0x00000315, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_StdAsyncActManager = {0x00000329, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_StdComponentCategoriesMgr = {0x0002E005, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_StdEncodingFilterFac = {0x54C37CD0, 0xD944, 0x11D0, [0xA9, 0xF4, 0x00, 0x60, 0x97, 0x94, 0x23, 0x11]}; enum IID CLSID_StdEvent = {0x0000032B, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_StdFont = {0x0BE35203, 0x8F91, 0x11CE, [0x9D, 0xE3, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51]}; enum IID CLSID_StdGlobalInterfaceTable = {0x00000323, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_StdHlink = {0x79EAC9D0, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_StdHlinkBrowseContext = {0x79EAC9D1, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_StdMarshal = {0x00000017, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_StdNotificationMgr = {0xC733E4AF, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_StdPicture = {0x0BE35204, 0x8F91, 0x11CE, [0x9D, 0xE3, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51]}; enum IID CLSID_StdURLMoniker = {0x79EAC9E0, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_StdURLProtocol = {0x79EAC9E1, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_StgFolder = {0xE773F1AF, 0x3A65, 0x4866, [0x85, 0x7D, 0x84, 0x6F, 0xC9, 0xC4, 0x59, 0x8A]}; enum IID CLSID_StockColorPage = {0x7EBDAAE1, 0x8120, 0x11CF, [0x89, 0x9F, 0x00, 0xAA, 0x00, 0x68, 0x8B, 0x10]}; enum IID CLSID_StockFontPage = {0x7EBDAAE0, 0x8120, 0x11CF, [0x89, 0x9F, 0x00, 0xAA, 0x00, 0x68, 0x8B, 0x10]}; enum IID CLSID_StockPicturePage = {0x7EBDAAE2, 0x8120, 0x11CF, [0x89, 0x9F, 0x00, 0xAA, 0x00, 0x68, 0x8B, 0x10]}; enum IID CLSID_SubscriptionMgr = {0xABBE31D0, 0x6DAE, 0x11D0, [0xBE, 0xCA, 0x00, 0xC0, 0x4F, 0xD9, 0x40, 0xBE]}; enum IID CLSID_SubscriptionThrottler = {0x1E9B00E5, 0x9846, 0x11D1, [0xA1, 0xEE, 0x00, 0xC0, 0x4F, 0xC2, 0xFB, 0xE1]}; enum IID CLSID_SWbemDateTime = {0x47DFBE54, 0xCF76, 0x11D3, [0xB3, 0x8F, 0x00, 0x10, 0x5A, 0x1F, 0x47, 0x3A]}; enum IID CLSID_SWbemEventSource = {0x04B83D58, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemLastError = {0xC2FEEEAC, 0xCFCD, 0x11D1, [0x8B, 0x05, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemLocator = {0x76A64158, 0xCB41, 0x11D1, [0x8B, 0x02, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemMethod = {0x04B83D5B, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemMethodSet = {0x04B83D5A, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemNamedValue = {0x04B83D60, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemNamedValueSet = {0x9AED384E, 0xCE8B, 0x11D1, [0x8B, 0x05, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemObject = {0x04B83D62, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemObjectEx = {0xD6BDAFB2, 0x9435, 0x491F, [0xBB, 0x87, 0x6A, 0xA0, 0xF0, 0xBC, 0x31, 0xA2]}; enum IID CLSID_SWbemObjectPath = {0x5791BC26, 0xCE9C, 0x11D1, [0x97, 0xBF, 0x00, 0x00, 0xF8, 0x1E, 0x84, 0x9C]}; enum IID CLSID_SWbemObjectSet = {0x04B83D61, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemPrivilege = {0x26EE67BC, 0x5804, 0x11D2, [0x8B, 0x4A, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemPrivilegeSet = {0x26EE67BE, 0x5804, 0x11D2, [0x8B, 0x4A, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemProperty = {0x04B83D5D, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemPropertySet = {0x04B83D5C, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemQualifier = {0x04B83D5F, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemQualifierSet = {0x04B83D5E, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemRefreshableItem = {0x8C6854BC, 0xDE4B, 0x11D3, [0xB3, 0x90, 0x00, 0x10, 0x5A, 0x1F, 0x47, 0x3A]}; enum IID CLSID_SWbemRefresher = {0xD269BF5C, 0xD9C1, 0x11D3, [0xB3, 0x8F, 0x00, 0x10, 0x5A, 0x1F, 0x47, 0x3A]}; enum IID CLSID_SWbemSecurity = {0xB54D66E9, 0x2287, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemServices = {0x04B83D63, 0x21AE, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID CLSID_SWbemServicesEx = {0x62E522DC, 0x8CF3, 0x40A8, [0x8B, 0x2E, 0x37, 0xD5, 0x95, 0x65, 0x1E, 0x40]}; enum IID CLSID_SWbemSink = {0x75718C9A, 0xF029, 0x11D1, [0xA1, 0xAC, 0x00, 0xC0, 0x4F, 0xB6, 0xC2, 0x23]}; enum IID CLSID_SynchronizeContainer = {0x0000032D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID CLSID_SyncMgr = {0x6295DF27, 0x35EE, 0x11D1, [0x87, 0x07, 0x00, 0xC0, 0x4F, 0xD9, 0x33, 0x27]}; enum IID CLSID_TAPI = {0x21D6D48E, 0xA88B, 0x11D0, [0x83, 0xDD, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID CLSID_TaskbarList = {0x56FDF344, 0xFD6D, 0x11D0, [0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90]}; enum IID CLSID_TaskManager = {0xC0F615A7, 0xF874, 0x4521, [0x87, 0x91, 0xED, 0x3B, 0x84, 0x01, 0x7E, 0xF7]}; enum IID CLSID_TerminalManager = {0x7170F2E0, 0x9BE3, 0x11D0, [0xA0, 0x09, 0x00, 0xAA, 0x00, 0xB6, 0x05, 0xA4]}; enum IID CLSID_THREAD_BROADCAST = {0xD34F1812, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_ThreadDialogProcParam = {0x3050F5EB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID CLSID_ThumbnailFCNHandler = {0xCEFC65D8, 0x66D8, 0x11D1, [0x8D, 0x8C, 0x00, 0x00, 0xF8, 0x04, 0xB0, 0x57]}; enum IID CLSID_ThumbnailUpdater = {0xA3C63918, 0x889D, 0x11D1, [0x83, 0xE9, 0x00, 0xC0, 0x4F, 0xC2, 0xC6, 0xD4]}; enum IID CLSID_TIME = {0xE32EF57B, 0x7FDE, 0x4765, [0x9B, 0xC5, 0xA1, 0xBA, 0x97, 0x05, 0xC4, 0x4E]}; enum IID CLSID_TIMEAnimation = {0xF99D135A, 0xC07C, 0x449E, [0x96, 0x5C, 0x7D, 0xBB, 0x7C, 0x55, 0x4A, 0x51]}; enum IID CLSID_TimeCategorizer = {0x3BB4118F, 0xDDFD, 0x4D30, [0xA3, 0x48, 0x9F, 0xB5, 0xD6, 0xBF, 0x1A, 0xFE]}; enum IID CLSID_TIMEColorAnimation = {0x62F75052, 0xF3EC, 0x4A64, [0x84, 0xFB, 0xAB, 0x18, 0xE0, 0x74, 0x6E, 0xD8]}; enum IID CLSID_TIMEFactory = {0x17237A20, 0x3ADB, 0x48EC, [0xB1, 0x82, 0x35, 0x29, 0x1F, 0x11, 0x57, 0x90]}; enum IID CLSID_TIMEFilterAnimation = {0xC54515D0, 0xF2E5, 0x4BDD, [0xAA, 0x86, 0x1E, 0x4F, 0x23, 0xE4, 0x80, 0xE7]}; enum IID CLSID_TIMEMotionAnimation = {0x0019A09D, 0x1A81, 0x41C5, [0x89, 0xEC, 0xD9, 0xE7, 0x37, 0x81, 0x13, 0x03]}; enum IID CLSID_TIMESetAnimation = {0xBA91CE53, 0xBAEB, 0x4F05, [0x86, 0x1C, 0x0A, 0x2A, 0x09, 0x34, 0xF8, 0x2E]}; enum IID CLSID_Timestamp = {0xB2BED2EB, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_ToolbarExtButtons = {0x2CE4B5D8, 0xA28F, 0x11D2, [0x86, 0xC5, 0x00, 0xC0, 0x4F, 0x8E, 0xEA, 0x99]}; enum IID CLSID_TrackFile = {0x8790C947, 0xA30B, 0x11D0, [0x8C, 0xAB, 0x00, 0xC0, 0x4F, 0xD9, 0x0F, 0x85]}; enum IID CLSID_TrkForceOwnership = {0xA2531F45, 0xC67D, 0x11D0, [0x8C, 0xB1, 0x00, 0xC0, 0x4F, 0xD9, 0x0F, 0x85]}; enum IID CLSID_TrkRestoreNotify = {0xD0056F6C, 0xE2A0, 0x11D0, [0xB1, 0xC2, 0x00, 0xC0, 0x4F, 0xB9, 0x38, 0x6D]}; enum IID CLSID_TrkRestoreParser = {0x755939E4, 0xE381, 0x11D0, [0xB1, 0xC5, 0x00, 0xC0, 0x4F, 0xB9, 0x38, 0x6D]}; enum IID CLSID_TypedName = {0xB33143CB, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID CLSID_UmiLDAPQueryObject = {0xCD5D4D76, 0xA818, 0x4F95, [0xB9, 0x58, 0x79, 0x70, 0xFD, 0x94, 0x12, 0xCA]}; enum IID CLSID_UnsecuredApartment = {0x49BD2028, 0x1523, 0x11D1, [0xAD, 0x79, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID CLSID_UPnPDescriptionDocument = {0x1D8A9B47, 0x3A28, 0x4CE2, [0x8A, 0x4B, 0xBD, 0x34, 0xE4, 0x5B, 0xCE, 0xEB]}; enum IID CLSID_UPnPDevice = {0xA32552C5, 0xBA61, 0x457A, [0xB5, 0x9A, 0xA2, 0x56, 0x1E, 0x12, 0x5E, 0x33]}; enum IID CLSID_UPnPDeviceFinder = {0xE2085F28, 0xFEB7, 0x404A, [0xB8, 0xE7, 0xE6, 0x59, 0xBD, 0xEA, 0xAA, 0x02]}; enum IID CLSID_UPnPDeviceHostICSSupport = {0x797A9BB1, 0x9E49, 0x4E63, [0xAF, 0xE1, 0x1B, 0x45, 0xB9, 0xDC, 0x81, 0x62]}; enum IID CLSID_UPnPDeviceHostSetup = {0xB4609411, 0xC81C, 0x4CCE, [0x8C, 0x76, 0xC6, 0xB5, 0x0C, 0x94, 0x02, 0xC6]}; enum IID CLSID_UPnPDevices = {0xB9E84FFD, 0xAD3C, 0x40A4, [0xB8, 0x35, 0x08, 0x82, 0xEB, 0xCB, 0xAA, 0xA8]}; enum IID CLSID_UPnPNAT = {0xAE1E00AA, 0x3FD5, 0x403C, [0x8A, 0x27, 0x2B, 0xBD, 0xC3, 0x0C, 0xD0, 0xE1]}; enum IID CLSID_UPnPRegistrar = {0x204810B9, 0x73B2, 0x11D4, [0xBF, 0x42, 0x00, 0xB0, 0xD0, 0x11, 0x8B, 0x56]}; enum IID CLSID_UPnPService = {0xC624BA95, 0xFBCB, 0x4409, [0x8C, 0x03, 0x8C, 0xCE, 0xEC, 0x53, 0x3E, 0xF1]}; enum IID CLSID_UPnPServices = {0xC0BC4B4A, 0xA406, 0x4EFC, [0x93, 0x2F, 0xB8, 0x54, 0x6B, 0x81, 0x00, 0xCC]}; enum IID CLSID_UrlMkBindCtx = {0x79EAC9F2, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID CLSID_UserEventTimer = {0x864A1288, 0x354C, 0x4D19, [0x9D, 0x68, 0xC2, 0x74, 0x2B, 0xB1, 0x49, 0x97]}; enum IID CLSID_UserEventTimerCallback = {0x15FFFD13, 0x5140, 0x41B8, [0xB8, 0x9A, 0xC8, 0xD5, 0x75, 0x9C, 0xD2, 0xB2]}; enum IID CLSID_UserNotification = {0x0010890E, 0x8789, 0x413C, [0xAD, 0xBC, 0x48, 0xF5, 0xB5, 0x11, 0xB3, 0xAF]}; enum IID CLSID_VideoInputTerminal = {0xAAF578EC, 0xDC70, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID CLSID_VideoWindowTerm = {0xF7438990, 0xD6EB, 0x11D0, [0x82, 0xA6, 0x00, 0xAA, 0x00, 0xB5, 0xCA, 0x1B]}; enum IID CLSID_VirusScan = {0xE88E5DE0, 0xBD3E, 0x11CF, [0xAA, 0xFA, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x5C]}; enum IID CLSID_WbemAdministrativeLocator = {0xCB8555CC, 0x9128, 0x11D1, [0xAD, 0x9B, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID CLSID_WbemAuthenticatedLocator = {0xCD184336, 0x9128, 0x11D1, [0xAD, 0x9B, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID CLSID_WbemBackupRestore = {0xC49E32C6, 0xBC8B, 0x11D2, [0x85, 0xD4, 0x00, 0x10, 0x5A, 0x1F, 0x83, 0x04]}; enum IID CLSID_WbemClassObject = {0x9A653086, 0x174F, 0x11D2, [0xB5, 0xF9, 0x00, 0x10, 0x4B, 0x70, 0x3E, 0xFD]}; enum IID CLSID_WbemContext = {0x674B6698, 0xEE92, 0x11D0, [0xAD, 0x71, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID CLSID_WbemDCOMTransport = {0xF7CE2E13, 0x8C90, 0x11D1, [0x9E, 0x7B, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID CLSID_WbemDecoupledBasicEventProvide = {0xF5F75737, 0x2843, 0x4F22, [0x93, 0x3D, 0xC7, 0x6A, 0x97, 0xCD, 0xA6, 0x2F]}; enum IID CLSID_WbemDecoupledRegistrar = {0x4CFC7932, 0x0F9D, 0x4BEF, [0x9C, 0x32, 0x8E, 0xA2, 0xA6, 0xB5, 0x6F, 0xCB]}; enum IID CLSID_WbemDefPath = {0xCF4CC405, 0xE2C5, 0x4DDD, [0xB3, 0xCE, 0x5E, 0x75, 0x82, 0xD8, 0xC9, 0xFA]}; enum IID CLSID_WbemLevel1Login = {0x8BC3F05E, 0xD86B, 0x11D0, [0xA0, 0x75, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID CLSID_WbemLocalAddrRes = {0xA1044801, 0x8F7E, 0x11D1, [0x9E, 0x7C, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID CLSID_WbemLocator = {0x4590F811, 0x1D3A, 0x11D0, [0x89, 0x1F, 0x00, 0xAA, 0x00, 0x4B, 0x2E, 0x24]}; enum IID CLSID_WbemObjectTextSrc = {0x8D1C559D, 0x84F0, 0x4BB3, [0xA7, 0xD5, 0x56, 0xA7, 0x43, 0x5A, 0x9B, 0xA6]}; enum IID CLSID_WbemQuery = {0xEAC8A024, 0x21E2, 0x4523, [0xAD, 0x73, 0xA7, 0x1A, 0x0A, 0xA2, 0xF5, 0x6A]}; enum IID CLSID_WbemRefresher = {0xC71566F2, 0x561E, 0x11D1, [0xAD, 0x87, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID CLSID_WbemStatusCodeText = {0xEB87E1BD, 0x3233, 0x11D2, [0xAE, 0xC9, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID CLSID_WbemUnauthenticatedLocator = {0x443E7B79, 0xDE31, 0x11D2, [0xB3, 0x40, 0x00, 0x10, 0x4B, 0xCC, 0x4B, 0x4A]}; enum IID CLSID_WbemUninitializedClassObject = {0x7A0227F6, 0x7108, 0x11D1, [0xAD, 0x90, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID CLSID_WebBrowser = {0x8856F961, 0x340A, 0x11D0, [0xA9, 0x6B, 0x00, 0xC0, 0x4F, 0xD7, 0x05, 0xA2]}; enum IID CLSID_WebBrowser_V1 = {0xEAB22AC3, 0x30C1, 0x11CF, [0xA7, 0xEB, 0x00, 0x00, 0xC0, 0x5B, 0xAE, 0x0B]}; enum IID CLSID_WebCheck = {0xE6FB5E20, 0xDE35, 0x11CF, [0x9C, 0x87, 0x00, 0xAA, 0x00, 0x51, 0x27, 0xED]}; enum IID CLSID_WebCheckDefaultProcess = {0xC733E4B0, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID CLSID_WebCheckOfflineSync = {0x7FC0B86E, 0x5FA7, 0x11D1, [0xBC, 0x7C, 0x00, 0xC0, 0x4F, 0xD9, 0x29, 0xDB]}; enum IID CLSID_WebCrawlerAgent = {0x08165EA0, 0xE946, 0x11CF, [0x9C, 0x87, 0x00, 0xAA, 0x00, 0x51, 0x27, 0xED]}; enum IID CLSID_WebViewFolderContents = {0x1820FED0, 0x473E, 0x11D0, [0xA9, 0x6C, 0x00, 0xC0, 0x4F, 0xD7, 0x05, 0xA2]}; enum IID CLSID_WebWizardHost = {0xC827F149, 0x55C1, 0x4D28, [0x93, 0x5E, 0x57, 0xE4, 0x7C, 0xAE, 0xD9, 0x73]}; enum IID CLSID_wfolders = {0xBAE31F9A, 0x1B81, 0x11D2, [0xA9, 0x7A, 0x00, 0xC0, 0x4F, 0x8E, 0xCB, 0x02]}; enum IID CLSID_WinNTConnectionObject = {0x7992C6EB, 0xD142, 0x4332, [0x83, 0x1E, 0x31, 0x54, 0xC5, 0x0A, 0x83, 0x16]}; enum IID CLSID_WinNTObject = {0xB8324185, 0x4050, 0x4220, [0x98, 0x0A, 0xAB, 0x14, 0x62, 0x3E, 0x06, 0x3A]}; enum IID CLSID_WinNTSystemInfo = {0x66182EC4, 0xAFD1, 0x11D2, [0x9C, 0xB9, 0x00, 0x00, 0xF8, 0x7A, 0x36, 0x9E]}; enum IID CLSID_WMIExtension = {0xF0975AFE, 0x5C7F, 0x11D2, [0x8B, 0x74, 0x00, 0x10, 0x4B, 0x2A, 0xFB, 0x41]}; enum IID CLSID_XMLDocument = {0xCFC399AF, 0xD876, 0x11D0, [0x9C, 0x10, 0x00, 0xC0, 0x4F, 0xC9, 0x9C, 0x8E]}; enum IID CLSID_XMLDSOControl = {0x550DDA30, 0x0541, 0x11D2, [0x9C, 0xA9, 0x00, 0x60, 0xB0, 0xEC, 0x3D, 0x39]}; enum IID CLSID_XMLHTTPRequest = {0xED8C108E, 0x4349, 0x11D2, [0x91, 0xA4, 0x00, 0xC0, 0x4F, 0x79, 0x69, 0xE8]}; enum IID CLSID_XMLParser = {0xD2423620, 0x51A0, 0x11D2, [0x9C, 0xAF, 0x00, 0x60, 0xB0, 0xEC, 0x3D, 0x39]}; enum IID DB_PROPERTY_AUTOMATICUPDATE = {0xC8B52209, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_BTREE = {0xC8B52201, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_CHECK_OPTION = {0xC8B5220B, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_CLUSTERED = {0xC8B521FF, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_CONSTRAINT_CHECK_DEFERRE = {0xC8B521F0, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_DISALLOWNULL = {0xC8B52205, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_DROP_CASCADE = {0xC8B521F3, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_EXPLICITUPDATE = {0xC8B5220A, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_FILLFACTOR = {0xC8B52203, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_HASH = {0xC8B52202, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_IGNOREANYNULL = {0xC8B52207, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_IGNORENULL = {0xC8B52206, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_INITIALSIZE = {0xC8B52204, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_NONCLUSTERED = {0xC8B52200, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_ON_COMMIT_PRESERVE_ROWS = {0xC8B52230, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_PRIMARY = {0xC8B521FC, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_SORTBOOKMARKS = {0xC8B52208, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DB_PROPERTY_UNIQUE = {0xC8B521F5, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBCOL_SELFCOLUMNS = {0xC8B52231, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBCOL_SPECIALCOL = {0xC8B52232, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_COMMAND = {0xC8B522F8, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_CONTAINEROBJECT = {0xC8B522FB, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_DBSQL = {0xC8B521FB, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_DEFAULT = {0xC8B521FB, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_DSO = {0xC8B522F4, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_HISTOGRAM_ROWSET = {0xC8B52300, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_LDAPDialect = {0xEFF65380, 0x9C98, 0x11CF, [0xB9, 0x63, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_LIKE_DOS = {0xC8B521F7, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_LIKE_MAPI = {0xC8B521F9, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_LIKE_OFS = {0xC8B521F8, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_LIKE_SQL = {0xC8B521F6, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_MDX = {0xA07CCCD0, 0x8148, 0x11D0, [0x87, 0xBB, 0x00, 0xC0, 0x4F, 0xC3, 0x39, 0x42]}; enum IID DBGUID_ROW = {0xC8B522F7, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_ROWSET = {0xC8B522F6, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_SESSION = {0xC8B522F5, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_SQL = {0xC8B522D7, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBGUID_STREAM = {0xC8B522F9, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_CHARACTERSET = {0xC8B522ED, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_COLLATION = {0xC8B522EA, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_COLUMN = {0xC8B522E4, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_DATABASE = {0xC8B522E5, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_DOMAIN = {0xC8B522E9, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_PROCEDURE = {0xC8B522E6, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_SCHEMA = {0xC8B522E8, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_SCHEMAROWSET = {0xC8B522EC, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_TABLE = {0xC8B522E2, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_TRANSLATION = {0xC8B522EE, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_TRUSTEE = {0xC8B522EB, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBOBJECT_VIEW = {0xC8B522E7, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_ADSIBIND = {0x6DA66DC8, 0xB7E8, 0x11D2, [0x9D, 0x60, 0x00, 0xC0, 0x4F, 0x68, 0x93, 0x45]}; enum IID DBPROPSET_ADSISEARCH = {0xCFCFC928, 0x9AA2, 0x11D0, [0xA7, 0x9A, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0xA8]}; enum IID DBPROPSET_COLUMN = {0xC8B522B9, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_COLUMNALL = {0xC8B522F0, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_CONSTRAINTALL = {0xC8B522FA, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_DATASOURCE = {0xC8B522BA, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_DATASOURCEALL = {0xC8B522C0, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_DATASOURCEINFO = {0xC8B522BB, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_DATASOURCEINFOALL = {0xC8B522C1, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_DBINIT = {0xC8B522BC, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_DBINITALL = {0xC8B522CA, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_INDEX = {0xC8B522BD, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_INDEXALL = {0xC8B522F1, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_PROPERTIESINERROR = {0xC8B522D4, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_ROWSET = {0xC8B522BE, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_ROWSETALL = {0xC8B522C2, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_SESSION = {0xC8B522C6, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_SESSIONALL = {0xC8B522C7, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_STREAM = {0xC8B522FD, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_STREAMALL = {0xC8B522FE, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_TABLE = {0xC8B522BF, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_TABLEALL = {0xC8B522F2, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_TRUSTEE = {0xC8B522E1, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_TRUSTEEALL = {0xC8B522F3, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_VIEW = {0xC8B522DF, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBPROPSET_VIEWALL = {0xC8B522FC, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_ASSERTIONS = {0xC8B52210, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_CATALOGS = {0xC8B52211, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_CHARACTER_SETS = {0xC8B52212, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_CHECK_CONSTRAINTS = {0xC8B52215, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_CHECK_CONSTRAINTS_BY_TABLE = {0xC8B52301, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_COLLATIONS = {0xC8B52213, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_COLUMN_DOMAIN_USAGE = {0xC8B5221B, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_COLUMN_PRIVILEGES = {0xC8B52221, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_COLUMNS = {0xC8B52214, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_CONSTRAINT_COLUMN_USAGE = {0xC8B52216, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_CONSTRAINT_TABLE_USAGE = {0xC8B52217, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_FOREIGN_KEYS = {0xC8B522C4, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_INDEXES = {0xC8B5221E, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_KEY_COLUMN_USAGE = {0xC8B52218, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_PRIMARY_KEYS = {0xC8B522C5, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_PROCEDURE_COLUMNS = {0xC8B522C9, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_PROCEDURE_PARAMETERS = {0xC8B522B8, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_PROCEDURES = {0xC8B52224, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_PROVIDER_TYPES = {0xC8B5222C, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_REFERENTIAL_CONSTRAINTS = {0xC8B52219, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_SCHEMATA = {0xC8B52225, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_SQL_LANGUAGES = {0xC8B52226, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_STATISTICS = {0xC8B52227, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_TABLE_CONSTRAINTS = {0xC8B5221A, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_TABLE_PRIVILEGES = {0xC8B52222, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_TABLE_STATISTICS = {0xC8B522FF, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_TABLES = {0xC8B52229, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_TABLES_INFO = {0xC8B522E0, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_TRANSLATIONS = {0xC8B5222A, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_TRUSTEE = {0xC8B522EF, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_USAGE_PRIVILEGES = {0xC8B52223, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_VIEW_COLUMN_USAGE = {0xC8B5222E, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_VIEW_TABLE_USAGE = {0xC8B5222F, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DBSCHEMA_VIEWS = {0xC8B5222D, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID DDVPTYPE_BROOKTREE = {0x1352A560, 0xDA61, 0x11CF, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID DDVPTYPE_CCIR656 = {0xFCA326A0, 0xDA60, 0x11CF, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID DDVPTYPE_E_HREFH_VREFL = {0x92783220, 0xDA60, 0x11CF, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID DDVPTYPE_E_HREFL_VREFL = {0xE09C77E0, 0xDA60, 0x11CF, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID DDVPTYPE_PHILIPS = {0x332CF160, 0xDA61, 0x11CF, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID DIID__SearchAssistantEvents = {0x1611FDDA, 0x445B, 0x11D2, [0x85, 0xDE, 0x00, 0xC0, 0x4F, 0xA3, 0x5C, 0x89]}; enum IID DIID_DispCEventObj = {0x3050F558, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispDOMChildrenCollection = {0x3050F577, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTCAttachBehavior = {0x3050F583, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTCDefaultDispatch = {0x3050F573, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTCDescBehavior = {0x3050F57E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTCEventBehavior = {0x3050F574, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTCMethodBehavior = {0x3050F587, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTCPropertyBehavior = {0x3050F57F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLAnchorElement = {0x3050F502, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLAppBehavior = {0x3050F57C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLAreaElement = {0x3050F503, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLAreasCollection = {0x3050F56A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLAttributeCollection = {0x3050F56C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLBaseElement = {0x3050F518, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLBaseFontElement = {0x3050F504, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLBGsound = {0x3050F53C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLBlockElement = {0x3050F506, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLBody = {0x3050F507, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLBRElement = {0x3050F53A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLButtonElement = {0x3050F51F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLCommentElement = {0x3050F50A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLCurrentStyle = {0x3050F557, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDDElement = {0x3050F50B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDefaults = {0x3050F58C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDivElement = {0x3050F50C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDivPosition = {0x3050F50F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDListElement = {0x3050F53B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDocument = {0x3050F55F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDOMAttribute = {0x3050F564, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDOMImplementation = {0x3050F58F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDOMTextNode = {0x3050F565, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLDTElement = {0x3050F50D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLElementCollection = {0x3050F56B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLEmbed = {0x3050F52E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLFieldSetElement = {0x3050F545, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLFontElement = {0x3050F512, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLFormElement = {0x3050F510, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLFrameBase = {0x3050F541, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLFrameElement = {0x3050F513, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLFrameSetSite = {0x3050F514, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLGenericElement = {0x3050F563, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLHeadElement = {0x3050F561, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLHeaderElement = {0x3050F515, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLHRElement = {0x3050F53D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLHtmlElement = {0x3050F560, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLIFrame = {0x3050F51B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLImg = {0x3050F51C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLInputElement = {0x3050F57D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLIsIndexElement = {0x3050F519, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLLabelElement = {0x3050F522, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLLegendElement = {0x3050F546, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLLIElement = {0x3050F523, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLLinkElement = {0x3050F524, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLListElement = {0x3050F525, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLMapElement = {0x3050F526, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLMarqueeElement = {0x3050F527, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLMetaElement = {0x3050F517, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLNextIdElement = {0x3050F51A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLNoShowElement = {0x3050F528, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLObjectElement = {0x3050F529, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLOListElement = {0x3050F52A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLOptionElement = {0x3050F52B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLParaElement = {0x3050F52C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLParamElement = {0x3050F590, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLPhraseElement = {0x3050F52D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLPopup = {0x3050F589, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLRenderStyle = {0x3050F58B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLRichtextElement = {0x3050F54D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLRuleStyle = {0x3050F55C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLScreen = {0x3050F591, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLScriptElement = {0x3050F530, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLSelectElement = {0x3050F531, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLSpanElement = {0x3050F548, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLSpanFlow = {0x3050F544, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLStyle = {0x3050F55A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLStyleElement = {0x3050F511, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLStyleSheet = {0x3050F58D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLTable = {0x3050F532, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLTableCaption = {0x3050F508, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLTableCell = {0x3050F536, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLTableCol = {0x3050F533, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLTableRow = {0x3050F535, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLTableSection = {0x3050F534, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLTextAreaElement = {0x3050F521, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLTextElement = {0x3050F537, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLTitleElement = {0x3050F516, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLUListElement = {0x3050F538, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLUnknownElement = {0x3050F539, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLWindow2 = {0x3050F55D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispHTMLWindowProxy = {0x3050F55E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispIHTMLInputButtonElement = {0x3050F51E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispIHTMLInputFileElement = {0x3050F542, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispIHTMLInputImage = {0x3050F51D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispIHTMLInputTextElement = {0x3050F520, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DispIHTMLOptionButtonElement = {0x3050F509, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_DMigrationWizardAutoEvents = {0xD2AC137D, 0xA6D8, 0x43B6, [0x98, 0x79, 0xEA, 0x34, 0xB6, 0x7E, 0x18, 0x80]}; enum IID DIID_DSearchCommandEvents = {0x60890160, 0x69F0, 0x11D1, [0xB7, 0x58, 0x00, 0xA0, 0xC9, 0x05, 0x64, 0xFE]}; enum IID DIID_DShellFolderViewEvents = {0x62112AA2, 0xEBE4, 0x11CF, [0xA5, 0xFB, 0x00, 0x20, 0xAF, 0xE7, 0x29, 0x2D]}; enum IID DIID_DShellNameSpaceEvents = {0x55136806, 0xB2DE, 0x11D1, [0xB9, 0xF2, 0x00, 0xA0, 0xC9, 0x8B, 0xC5, 0x47]}; enum IID DIID_DShellWindowsEvents = {0xFE4106E0, 0x399A, 0x11D0, [0xA4, 0x8C, 0x00, 0xA0, 0xC9, 0x0A, 0x8F, 0x39]}; enum IID DIID_DWebBridgeEvents = {0xA6D897FF, 0x0A95, 0x11D1, [0xB0, 0xBA, 0x00, 0x60, 0x08, 0x16, 0x6E, 0x11]}; enum IID DIID_DWebBrowserEvents = {0xEAB22AC2, 0x30C1, 0x11CF, [0xA7, 0xEB, 0x00, 0x00, 0xC0, 0x5B, 0xAE, 0x0B]}; enum IID DIID_DWebBrowserEvents2 = {0x34A715A0, 0x6587, 0x11D0, [0x92, 0x4A, 0x00, 0x20, 0xAF, 0xC7, 0xAC, 0x4D]}; enum IID DIID_HTMLAnchorEvents = {0x3050F29D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLAnchorEvents2 = {0x3050F610, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLAreaEvents = {0x3050F366, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLAreaEvents2 = {0x3050F611, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLButtonElementEvents = {0x3050F2B3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLButtonElementEvents2 = {0x3050F617, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLControlElementEvents = {0x3050F4EA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLControlElementEvents2 = {0x3050F612, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLDocumentEvents = {0x3050F260, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLDocumentEvents2 = {0x3050F613, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLElementEvents = {0x3050F33C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLElementEvents2 = {0x3050F60F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLFormElementEvents = {0x3050F364, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLFormElementEvents2 = {0x3050F614, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLFrameSiteEvents = {0x3050F800, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLFrameSiteEvents2 = {0x3050F7FF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLImgEvents = {0x3050F25B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLImgEvents2 = {0x3050F616, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLInputFileElementEvents = {0x3050F2AF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLInputFileElementEvents2 = {0x3050F61A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLInputImageEvents = {0x3050F2C3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLInputImageEvents2 = {0x3050F61B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLInputTextElementEvents = {0x3050F2A7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLInputTextElementEvents2 = {0x3050F618, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLLabelEvents = {0x3050F329, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLLabelEvents2 = {0x3050F61C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLLinkElementEvents = {0x3050F3CC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLLinkElementEvents2 = {0x3050F61D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLMapEvents = {0x3050F3BA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLMapEvents2 = {0x3050F61E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLMarqueeElementEvents = {0x3050F2B8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLMarqueeElementEvents2 = {0x3050F61F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLNamespaceEvents = {0x3050F6BD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLObjectElementEvents = {0x3050F3C4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLObjectElementEvents2 = {0x3050F620, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLOptionButtonElementEvents = {0x3050F2BD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLOptionButtonElementEvents2 = {0x3050F619, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLPersistEvents = {0x3050F4C7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLScriptEvents = {0x3050F3E2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLScriptEvents2 = {0x3050F621, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLSelectElementEvents = {0x3050F302, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLSelectElementEvents2 = {0x3050F622, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLStyleElementEvents = {0x3050F3CB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLStyleElementEvents2 = {0x3050F615, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLTableEvents = {0x3050F407, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLTableEvents2 = {0x3050F623, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLTextContainerEvents = {0x1FF6AA72, 0x5842, 0x11CF, [0xA7, 0x07, 0x00, 0xAA, 0x00, 0xC0, 0x09, 0x8D]}; enum IID DIID_HTMLTextContainerEvents2 = {0x3050F624, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_HTMLWindowEvents = {0x96A0A4E0, 0xD062, 0x11CF, [0x94, 0xB6, 0x00, 0xAA, 0x00, 0x60, 0x27, 0x5C]}; enum IID DIID_HTMLWindowEvents2 = {0x3050F625, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_IRTCDispatchEventNotification = {0x176DDFBE, 0xFEC0, 0x4D55, [0xBC, 0x87, 0x84, 0xCF, 0xF1, 0xEF, 0x7F, 0x91]}; enum IID DIID_ISWbemSinkEvents = {0x75718CA0, 0xF029, 0x11D1, [0xA1, 0xAC, 0x00, 0xC0, 0x4F, 0xB6, 0xC2, 0x23]}; enum IID DIID_ITTAPIDispatchEventNotification = {0x9F34325B, 0x7E62, 0x11D2, [0x94, 0x57, 0x00, 0xC0, 0x4F, 0x8E, 0xC8, 0x88]}; enum IID DIID_LayoutRectEvents = {0x3050F674, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID DIID_XMLDOMDocumentEvents = {0x3EFAA427, 0x272F, 0x11D2, [0x83, 0x6F, 0x00, 0x00, 0xF8, 0x7A, 0x77, 0x82]}; enum IID DPAID_ComPort = {0xF2F0CE00, 0xE0AF, 0x11CF, [0x9C, 0x4E, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPAID_INet = {0xC4A54DA0, 0xE0AF, 0x11CF, [0x9C, 0x4E, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPAID_INetPort = {0xE4524541, 0x8EA5, 0x11D1, [0x8A, 0x96, 0x00, 0x60, 0x97, 0xB0, 0x14, 0x11]}; enum IID DPAID_INetW = {0xE63232A0, 0x9DBF, 0x11D0, [0x9C, 0xC1, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPAID_LobbyProvider = {0x59B95640, 0x9667, 0x11D0, [0xA7, 0x7D, 0x00, 0x00, 0xF8, 0x03, 0xAB, 0xFC]}; enum IID DPAID_Modem = {0xF6DCC200, 0xA2FE, 0x11D0, [0x9C, 0x4F, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPAID_ModemW = {0x01FD92E0, 0xA2FF, 0x11D0, [0x9C, 0x4F, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPAID_Phone = {0x78EC89A0, 0xE0AF, 0x11CF, [0x9C, 0x4E, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPAID_PhoneW = {0xBA5A7A70, 0x9DBF, 0x11D0, [0x9C, 0xC1, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPAID_ServiceProvider = {0x07D916C0, 0xE0AF, 0x11CF, [0x9C, 0x4E, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPAID_TotalSize = {0x1318F560, 0x912C, 0x11D0, [0x9D, 0xAA, 0x00, 0xA0, 0xC9, 0x0A, 0x43, 0xCB]}; enum IID DPLPROPERTY_LobbyGuid = {0xF56920A0, 0xD218, 0x11D0, [0xBA, 0x39, 0x00, 0xC0, 0x4F, 0xD7, 0xED, 0x67]}; enum IID DPLPROPERTY_MessagesSupported = {0x762CCDA1, 0xD916, 0x11D0, [0xBA, 0x39, 0x00, 0xC0, 0x4F, 0xD7, 0xED, 0x67]}; enum IID DPLPROPERTY_PlayerGuid = {0xB4319322, 0xD20D, 0x11D0, [0xBA, 0x39, 0x00, 0xC0, 0x4F, 0xD7, 0xED, 0x67]}; enum IID DPLPROPERTY_PlayerScore = {0x48784000, 0xD219, 0x11D0, [0xBA, 0x39, 0x00, 0xC0, 0x4F, 0xD7, 0xED, 0x67]}; enum IID DPSPGUID_IPX = {0x685BC400, 0x9D2C, 0x11CF, [0xA9, 0xCD, 0x00, 0xAA, 0x00, 0x68, 0x86, 0xE3]}; enum IID DPSPGUID_MODEM = {0x44EAA760, 0xCB68, 0x11CF, [0x9C, 0x4E, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPSPGUID_SERIAL = {0x0F1D6860, 0x88D9, 0x11CF, [0x9C, 0x4E, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID DPSPGUID_TCPIP = {0x36E95EE0, 0x8577, 0x11CF, [0x96, 0x0C, 0x00, 0x80, 0xC7, 0x53, 0x4E, 0x82]}; enum IID DS3DALG_HRTF_FULL = {0xC2413340, 0x1C1B, 0x11D2, [0x94, 0xF5, 0x00, 0xC0, 0x4F, 0xC2, 0x8A, 0xCA]}; enum IID DS3DALG_HRTF_LIGHT = {0xC2413342, 0x1C1B, 0x11D2, [0x94, 0xF5, 0x00, 0xC0, 0x4F, 0xC2, 0x8A, 0xCA]}; enum IID DS3DALG_NO_VIRTUALIZATION = {0xC241333F, 0x1C1B, 0x11D2, [0x94, 0xF5, 0x00, 0xC0, 0x4F, 0xC2, 0x8A, 0xCA]}; enum IID FLAGID_Internet = {0x96300DA0, 0x2BAB, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID FMTID_AudioSummaryInformation = {0x64440490, 0x4C8B, 0x11D1, [0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03]}; enum IID FMTID_Briefcase = {0x328D8B21, 0x7729, 0x4BFC, [0x95, 0x4C, 0x90, 0x2B, 0x32, 0x9D, 0x56, 0xB0]}; enum IID FMTID_DiscardableInformation = {0xD725EBB0, 0xC9B8, 0x11D1, [0x89, 0xBC, 0x00, 0x00, 0xF8, 0x04, 0xB0, 0x57]}; enum IID FMTID_Displaced = {0x9B174B33, 0x40FF, 0x11D2, [0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71]}; enum IID FMTID_DocSummaryInformation = {0xD5CDD502, 0x2E9C, 0x101B, [0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE]}; enum IID FMTID_DRM = {0xAEAC19E4, 0x89AE, 0x4508, [0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED]}; enum IID FMTID_ImageProperties = {0x14B81DA1, 0x0135, 0x4D31, [0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99]}; enum IID FMTID_ImageSummaryInformation = {0x6444048F, 0x4C8B, 0x11D1, [0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03]}; enum IID FMTID_InternetSite = {0x000214A1, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID FMTID_Intshcut = {0x000214A0, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID FMTID_MediaFileSummaryInformation = {0x64440492, 0x4C8B, 0x11D1, [0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03]}; enum IID FMTID_Misc = {0x9B174B34, 0x40FF, 0x11D2, [0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71]}; enum IID FMTID_MUSIC = {0x56A3372E, 0xCE9C, 0x11D2, [0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6]}; enum IID FMTID_PropertyBag = {0x20001801, 0x5DE6, 0x11D1, [0x8E, 0x38, 0x00, 0xC0, 0x4F, 0xB9, 0x38, 0x6D]}; enum IID FMTID_Query = {0x49691C90, 0x7E17, 0x101A, [0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9]}; enum IID FMTID_ShellDetails = {0x28636AA6, 0x953D, 0x11D2, [0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0]}; enum IID FMTID_Storage = {0xB725F130, 0x47EF, 0x101A, [0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC]}; enum IID FMTID_SummaryInformation = {0xF29F85E0, 0x4FF9, 0x1068, [0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9]}; enum IID FMTID_UserDefinedProperties = {0xD5CDD505, 0x2E9C, 0x101B, [0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE]}; enum IID FMTID_VideoSummaryInformation = {0x64440491, 0x4C8B, 0x11D1, [0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03]}; enum IID FMTID_Volume = {0x9B174B35, 0x40FF, 0x11D2, [0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71]}; enum IID FMTID_WebView = {0xF2275480, 0xF782, 0x4291, [0xBD, 0x94, 0xF1, 0x36, 0x93, 0x51, 0x3A, 0xEC]}; enum IID GUID_ACPI_CMOS_INTERFACE_STANDARD = {0x3A8D0384, 0x6505, 0x40CA, [0xBC, 0x39, 0x56, 0xC1, 0x5F, 0x8C, 0x5F, 0xED]}; enum IID GUID_ACPI_INTERFACE_STANDARD = {0xB091A08A, 0xBA97, 0x11D0, [0xBD, 0x14, 0x00, 0xAA, 0x00, 0xB7, 0xB3, 0x2A]}; enum IID GUID_ACPI_PORT_RANGES_INTERFACE_STAND = {0xF14F609B, 0xCBBD, 0x4957, [0xA6, 0x74, 0xBC, 0x00, 0x21, 0x3F, 0x1C, 0x97]}; enum IID GUID_ACPI_REGS_INTERFACE_STANDARD = {0x06141966, 0x7245, 0x6369, [0x46, 0x2E, 0x4E, 0x65, 0x6C, 0x73, 0x6F, 0x6E]}; enum IID GUID_ARBITER_INTERFACE_STANDARD = {0xE644F185, 0x8C0E, 0x11D0, [0xBE, 0xCF, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F]}; enum IID GUID_BUS_INTERFACE_STANDARD = {0x496B8280, 0x6F25, 0x11D0, [0xBE, 0xAF, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F]}; enum IID GUID_BUS_TYPE_1394 = {0xF74E73EB, 0x9AC5, 0x45EB, [0xBE, 0x4D, 0x77, 0x2C, 0xC7, 0x1D, 0xDF, 0xB3]}; enum IID GUID_BUS_TYPE_AVC = {0xC06FF265, 0xAE09, 0x48F0, [0x81, 0x2C, 0x16, 0x75, 0x3D, 0x7C, 0xBA, 0x83]}; enum IID GUID_BUS_TYPE_DOT4PRT = {0x441EE001, 0x4342, 0x11D5, [0xA1, 0x84, 0x00, 0xC0, 0x4F, 0x60, 0x52, 0x4D]}; enum IID GUID_BUS_TYPE_EISA = {0xDDC35509, 0xF3FC, 0x11D0, [0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1]}; enum IID GUID_BUS_TYPE_HID = {0xEEAF37D0, 0x1963, 0x47C4, [0xAA, 0x48, 0x72, 0x47, 0x6D, 0xB7, 0xCF, 0x49]}; enum IID GUID_BUS_TYPE_INTERNAL = {0x1530EA73, 0x086B, 0x11D1, [0xA0, 0x9F, 0x00, 0xC0, 0x4F, 0xC3, 0x40, 0xB1]}; enum IID GUID_BUS_TYPE_IRDA = {0x7AE17DC1, 0xC944, 0x44D6, [0x88, 0x1F, 0x4C, 0x2E, 0x61, 0x05, 0x3B, 0xC1]}; enum IID GUID_BUS_TYPE_ISAPNP = {0xE676F854, 0xD87D, 0x11D0, [0x92, 0xB2, 0x00, 0xA0, 0xC9, 0x05, 0x5F, 0xC5]}; enum IID GUID_BUS_TYPE_LPTENUM = {0xC4CA1000, 0x2DDC, 0x11D5, [0xA1, 0x7A, 0x00, 0xC0, 0x4F, 0x60, 0x52, 0x4D]}; enum IID GUID_BUS_TYPE_MCA = {0x1C75997A, 0xDC33, 0x11D0, [0x92, 0xB2, 0x00, 0xA0, 0xC9, 0x05, 0x5F, 0xC5]}; enum IID GUID_BUS_TYPE_PCI = {0xC8EBDFB0, 0xB510, 0x11D0, [0x80, 0xE5, 0x00, 0xA0, 0xC9, 0x25, 0x42, 0xE3]}; enum IID GUID_BUS_TYPE_PCMCIA = {0x09343630, 0xAF9F, 0x11D0, [0x92, 0xE9, 0x00, 0x00, 0xF8, 0x1E, 0x1B, 0x30]}; enum IID GUID_BUS_TYPE_SERENUM = {0x77114A87, 0x8944, 0x11D1, [0xBD, 0x90, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0x2D]}; enum IID GUID_BUS_TYPE_USB = {0x9D7DEBBC, 0xC85D, 0x11D1, [0x9E, 0xB4, 0x00, 0x60, 0x08, 0xC3, 0xA1, 0x9A]}; enum IID GUID_BUS_TYPE_USBPRINT = {0x441EE000, 0x4342, 0x11D5, [0xA1, 0x84, 0x00, 0xC0, 0x4F, 0x60, 0x52, 0x4D]}; enum IID GUID_Button = {0xA36D02F0, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_CHECKVALUEEXCLUSIVE = {0x6650430C, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_ChordParam = {0xD2AC289E, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_Clear_All_Bands = {0xD2AC28AB, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_COLOR = {0x66504301, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_ColorControlCallbacks = {0xEFD60CC2, 0x49E7, 0x11D0, [0x88, 0x9D, 0x00, 0xAA, 0x00, 0xBB, 0xB7, 0x6A]}; enum IID GUID_CommandParam = {0xD2AC289D, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_CommandParam2 = {0x28F97EF7, 0x9538, 0x11D2, [0x97, 0xA9, 0x00, 0xC0, 0x4F, 0xA3, 0x6E, 0x58]}; enum IID GUID_ConnectToDLSCollection = {0x1DB1AE6B, 0xE92E, 0x11D1, [0xA8, 0xC5, 0x00, 0xC0, 0x4F, 0xA3, 0x72, 0x6E]}; enum IID GUID_ConstantForce = {0x13541C20, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_CustomForce = {0x13541C2B, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_D3DCallbacks2 = {0x0BA584E1, 0x70B6, 0x11D0, [0x88, 0x9D, 0x00, 0xAA, 0x00, 0xBB, 0xB7, 0x6A]}; enum IID GUID_D3DCallbacks3 = {0xDDF41230, 0xEC0A, 0x11D0, [0xA9, 0xB6, 0x00, 0xAA, 0x00, 0xC0, 0x99, 0x3E]}; enum IID GUID_D3DExtendedCaps = {0x7DE41F80, 0x9D93, 0x11D0, [0x89, 0xAB, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29]}; enum IID GUID_D3DParseUnknownCommandCallback = {0x2E04FFA0, 0x98E4, 0x11D1, [0x8C, 0xE1, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID GUID_Damper = {0x13541C28, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_DDMoreCaps = {0x880BAF30, 0xB030, 0x11D0, [0x8E, 0xA7, 0x00, 0x60, 0x97, 0x97, 0xEA, 0x5B]}; enum IID GUID_DDMoreSurfaceCaps = {0x3B8A0466, 0xF269, 0x11D1, [0x88, 0x0B, 0x00, 0xC0, 0x4F, 0xD9, 0x30, 0xC5]}; enum IID GUID_DDStereoMode = {0xF828169C, 0xA8E8, 0x11D2, [0xA1, 0xF2, 0x00, 0xA0, 0xC9, 0x83, 0xEA, 0xF6]}; enum IID GUID_DefaultGMCollection = {0xF17E8673, 0xC3B4, 0x11D1, [0x87, 0x0B, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_DEVCLASS_1394 = {0x6BDD1FC1, 0x810F, 0x11D0, [0xBE, 0xC7, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F]}; enum IID GUID_DEVCLASS_1394DEBUG = {0x66F250D6, 0x7801, 0x4A64, [0xB1, 0x39, 0xEE, 0xA8, 0x0A, 0x45, 0x0B, 0x24]}; enum IID GUID_DEVCLASS_61883 = {0x7EBEFBC0, 0x3200, 0x11D2, [0xB4, 0xC2, 0x00, 0xA0, 0xC9, 0x69, 0x7D, 0x07]}; enum IID GUID_DEVCLASS_ADAPTER = {0x4D36E964, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_APMSUPPORT = {0xD45B1C18, 0xC8FA, 0x11D1, [0x9F, 0x77, 0x00, 0x00, 0xF8, 0x05, 0xF5, 0x30]}; enum IID GUID_DEVCLASS_AVC = {0xC06FF265, 0xAE09, 0x48F0, [0x81, 0x2C, 0x16, 0x75, 0x3D, 0x7C, 0xBA, 0x83]}; enum IID GUID_DEVCLASS_BATTERY = {0x72631E54, 0x78A4, 0x11D0, [0xBC, 0xF7, 0x00, 0xAA, 0x00, 0xB7, 0xB3, 0x2A]}; enum IID GUID_DEVCLASS_BLUETOOTH = {0xE0CBF06C, 0xCD8B, 0x4647, [0xBB, 0x8A, 0x26, 0x3B, 0x43, 0xF0, 0xF9, 0x74]}; enum IID GUID_DEVCLASS_CDROM = {0x4D36E965, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_COMPUTER = {0x4D36E966, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_DECODER = {0x6BDD1FC2, 0x810F, 0x11D0, [0xBE, 0xC7, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F]}; enum IID GUID_DEVCLASS_DISKDRIVE = {0x4D36E967, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_DISPLAY = {0x4D36E968, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_DOT4 = {0x48721B56, 0x6795, 0x11D2, [0xB1, 0xA8, 0x00, 0x80, 0xC7, 0x2E, 0x74, 0xA2]}; enum IID GUID_DEVCLASS_DOT4PRINT = {0x49CE6AC8, 0x6F86, 0x11D2, [0xB1, 0xE5, 0x00, 0x80, 0xC7, 0x2E, 0x74, 0xA2]}; enum IID GUID_DEVCLASS_ENUM1394 = {0xC459DF55, 0xDB08, 0x11D1, [0xB0, 0x09, 0x00, 0xA0, 0xC9, 0x08, 0x1F, 0xF6]}; enum IID GUID_DEVCLASS_FDC = {0x4D36E969, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_FLOPPYDISK = {0x4D36E980, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_FSFILTER_ACTIVITYMONIT = {0xB86DFF51, 0xA31E, 0x4BAC, [0xB3, 0xCF, 0xE8, 0xCF, 0xE7, 0x5C, 0x9F, 0xC2]}; enum IID GUID_DEVCLASS_FSFILTER_ANTIVIRUS = {0xB1D1A169, 0xC54F, 0x4379, [0x81, 0xDB, 0xBE, 0xE7, 0xD8, 0x8D, 0x74, 0x54]}; enum IID GUID_DEVCLASS_FSFILTER_CFSMETADATASER = {0xCDCF0939, 0xB75B, 0x4630, [0xBF, 0x76, 0x80, 0xF7, 0xBA, 0x65, 0x58, 0x84]}; enum IID GUID_DEVCLASS_FSFILTER_COMPRESSION = {0xF3586BAF, 0xB5AA, 0x49B5, [0x8D, 0x6C, 0x05, 0x69, 0x28, 0x4C, 0x63, 0x9F]}; enum IID GUID_DEVCLASS_FSFILTER_CONTENTSCREEN = {0x3E3F0674, 0xC83C, 0x4558, [0xBB, 0x26, 0x98, 0x20, 0xE1, 0xEB, 0xA5, 0xC5]}; enum IID GUID_DEVCLASS_FSFILTER_CONTINUOUSBACK = {0x71AA14F8, 0x6FAD, 0x4622, [0xAD, 0x77, 0x92, 0xBB, 0x9D, 0x7E, 0x69, 0x47]}; enum IID GUID_DEVCLASS_FSFILTER_COPYPROTECTIO = {0x89786FF1, 0x9C12, 0x402F, [0x9C, 0x9E, 0x17, 0x75, 0x3C, 0x7F, 0x43, 0x75]}; enum IID GUID_DEVCLASS_FSFILTER_ENCRYPTION = {0xA0A701C0, 0xA511, 0x42FF, [0xAA, 0x6C, 0x06, 0xDC, 0x03, 0x95, 0x57, 0x6F]}; enum IID GUID_DEVCLASS_FSFILTER_HSM = {0xD546500A, 0x2AEB, 0x45F6, [0x94, 0x82, 0xF4, 0xB1, 0x79, 0x9C, 0x31, 0x77]}; enum IID GUID_DEVCLASS_FSFILTER_INFRASTRUCTUR = {0xE55FA6F9, 0x128C, 0x4D04, [0xAB, 0xAB, 0x63, 0x0C, 0x74, 0xB1, 0x45, 0x3A]}; enum IID GUID_DEVCLASS_FSFILTER_OPENFILEBACKU = {0xF8ECAFA6, 0x66D1, 0x41A5, [0x89, 0x9B, 0x66, 0x58, 0x5D, 0x72, 0x16, 0xB7]}; enum IID GUID_DEVCLASS_FSFILTER_PHYSICALQUOTAM = {0x6A0A8E78, 0xBBA6, 0x4FC4, [0xA7, 0x09, 0x1E, 0x33, 0xCD, 0x09, 0xD6, 0x7E]}; enum IID GUID_DEVCLASS_FSFILTER_QUOTAMANAGEME = {0x8503C911, 0xA6C7, 0x4919, [0x8F, 0x79, 0x50, 0x28, 0xF5, 0x86, 0x6B, 0x0C]}; enum IID GUID_DEVCLASS_FSFILTER_REPLICATION = {0x48D3EBC4, 0x4CF8, 0x48FF, [0xB8, 0x69, 0x9C, 0x68, 0xAD, 0x42, 0xEB, 0x9F]}; enum IID GUID_DEVCLASS_FSFILTER_SECURITYENHANC = {0xD02BC3DA, 0x0C8E, 0x4945, [0x9B, 0xD5, 0xF1, 0x88, 0x3C, 0x22, 0x6C, 0x8C]}; enum IID GUID_DEVCLASS_FSFILTER_SYSTEM = {0x5D1B9AAA, 0x01E2, 0x46AF, [0x84, 0x9F, 0x27, 0x2B, 0x3F, 0x32, 0x4C, 0x46]}; enum IID GUID_DEVCLASS_FSFILTER_SYSTEMRECOVER = {0x2DB15374, 0x706E, 0x4131, [0xA0, 0xC7, 0xD7, 0xC7, 0x8E, 0xB0, 0x28, 0x9A]}; enum IID GUID_DEVCLASS_FSFILTER_UNDELETE = {0xFE8F1572, 0xC67A, 0x48C0, [0xBB, 0xAC, 0x0B, 0x5C, 0x6D, 0x66, 0xCA, 0xFB]}; enum IID GUID_DEVCLASS_GPS = {0x6BDD1FC3, 0x810F, 0x11D0, [0xBE, 0xC7, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F]}; enum IID GUID_DEVCLASS_HDC = {0x4D36E96A, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_HIDCLASS = {0x745A17A0, 0x74D3, 0x11D0, [0xB6, 0xFE, 0x00, 0xA0, 0xC9, 0x0F, 0x57, 0xDA]}; enum IID GUID_DEVCLASS_IMAGE = {0x6BDD1FC6, 0x810F, 0x11D0, [0xBE, 0xC7, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F]}; enum IID GUID_DEVCLASS_INFRARED = {0x6BDD1FC5, 0x810F, 0x11D0, [0xBE, 0xC7, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F]}; enum IID GUID_DEVCLASS_KEYBOARD = {0x4D36E96B, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_LEGACYDRIVER = {0x8ECC055D, 0x047F, 0x11D1, [0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1]}; enum IID GUID_DEVCLASS_MEDIA = {0x4D36E96C, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_MEDIUM_CHANGER = {0xCE5939AE, 0xEBDE, 0x11D0, [0xB1, 0x81, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xC4]}; enum IID GUID_DEVCLASS_MODEM = {0x4D36E96D, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_MONITOR = {0x4D36E96E, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_MOUSE = {0x4D36E96F, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_MTD = {0x4D36E970, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_MULTIFUNCTION = {0x4D36E971, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_MULTIPORTSERIAL = {0x50906CB8, 0xBA12, 0x11D1, [0xBF, 0x5D, 0x00, 0x00, 0xF8, 0x05, 0xF5, 0x30]}; enum IID GUID_DEVCLASS_NET = {0x4D36E972, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_NETCLIENT = {0x4D36E973, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_NETSERVICE = {0x4D36E974, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_NETTRANS = {0x4D36E975, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_NODRIVER = {0x4D36E976, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_PCMCIA = {0x4D36E977, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_PNPPRINTERS = {0x4658EE7E, 0xF050, 0x11D1, [0xB6, 0xBD, 0x00, 0xC0, 0x4F, 0xA3, 0x72, 0xA7]}; enum IID GUID_DEVCLASS_PORTS = {0x4D36E978, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_PRINTER = {0x4D36E979, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_PRINTERUPGRADE = {0x4D36E97A, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_PROCESSOR = {0x50127DC3, 0x0F36, 0x415E, [0xA6, 0xCC, 0x4C, 0xB3, 0xBE, 0x91, 0x0B, 0x65]}; enum IID GUID_DEVCLASS_SBP2 = {0xD48179BE, 0xEC20, 0x11D1, [0xB6, 0xB8, 0x00, 0xC0, 0x4F, 0xA3, 0x72, 0xA7]}; enum IID GUID_DEVCLASS_SCSIADAPTER = {0x4D36E97B, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_SMARTCARDREADER = {0x50DD5230, 0xBA8A, 0x11D1, [0xBF, 0x5D, 0x00, 0x00, 0xF8, 0x05, 0xF5, 0x30]}; enum IID GUID_DEVCLASS_SOUND = {0x4D36E97C, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_SYSTEM = {0x4D36E97D, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_TAPEDRIVE = {0x6D807884, 0x7D21, 0x11CF, [0x80, 0x1C, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_UNKNOWN = {0x4D36E97E, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVCLASS_USB = {0x36FC9E60, 0xC465, 0x11CF, [0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_DEVCLASS_VOLUME = {0x71A27CDD, 0x812A, 0x11D0, [0xBE, 0xC7, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F]}; enum IID GUID_DEVCLASS_VOLUMESNAPSHOT = {0x533C5B84, 0xEC70, 0x11D2, [0x95, 0x05, 0x00, 0xC0, 0x4F, 0x79, 0xDE, 0xAF]}; enum IID GUID_DEVCLASS_WCEUSBS = {0x25DBCE51, 0x6C8F, 0x4A72, [0x8A, 0x6D, 0xB5, 0x4C, 0x2B, 0x4F, 0xC8, 0x35]}; enum IID GUID_DEVICE_INTERFACE_ARRIVAL = {0xCB3A4004, 0x46F0, 0x11D0, [0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F]}; enum IID GUID_DEVICE_INTERFACE_REMOVAL = {0xCB3A4005, 0x46F0, 0x11D0, [0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F]}; enum IID GUID_DEVINTERFACE_CDCHANGER = {0x53F56312, 0xB6BF, 0x11D0, [0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DEVINTERFACE_CDROM = {0x53F56308, 0xB6BF, 0x11D0, [0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DEVINTERFACE_COMPORT = {0x86E0D1E0, 0x8089, 0x11D0, [0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73]}; enum IID GUID_DEVINTERFACE_DISK = {0x53F56307, 0xB6BF, 0x11D0, [0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DEVINTERFACE_FLOPPY = {0x53F56311, 0xB6BF, 0x11D0, [0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DEVINTERFACE_MEDIUMCHANGER = {0x53F56310, 0xB6BF, 0x11D0, [0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DEVINTERFACE_PARTITION = {0x53F5630A, 0xB6BF, 0x11D0, [0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DEVINTERFACE_SERENUM_BUS_ENUMERA = {0x4D36E978, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_DEVINTERFACE_STORAGEPORT = {0x2ACCFE60, 0xC130, 0x11D2, [0xB0, 0x82, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DEVINTERFACE_TAPE = {0x53F5630B, 0xB6BF, 0x11D0, [0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DEVINTERFACE_VOLUME = {0x53F5630D, 0xB6BF, 0x11D0, [0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DEVINTERFACE_WRITEONCEDISK = {0x53F5630C, 0xB6BF, 0x11D0, [0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B]}; enum IID GUID_DirectDrawPaletteStream = {0x730C7FFC, 0x5347, 0x11D1, [0x8C, 0x4D, 0x00, 0xC0, 0x4F, 0xD9, 0x30, 0xC5]}; enum IID GUID_DirectDrawSurfaceStream = {0xE043BC46, 0x5317, 0x11D1, [0x8C, 0x4D, 0x00, 0xC0, 0x4F, 0xD9, 0x30, 0xC5]}; enum IID GUID_DirectMusicAllTypes = {0xD2AC2893, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_Disable_Auto_Download = {0xD2AC28AA, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_DisableTempo = {0x45FC707D, 0x1DB4, 0x11D2, [0xBC, 0xAC, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEB]}; enum IID GUID_DisableTimeSig = {0x45FC707B, 0x1DB4, 0x11D2, [0xBC, 0xAC, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEB]}; enum IID GUID_DMUS_PROP_DLS1 = {0x178F2F27, 0xC364, 0x11D1, [0xA7, 0x60, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID GUID_DMUS_PROP_DLS2 = {0xF14599E5, 0x4689, 0x11D2, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID GUID_DMUS_PROP_Effects = {0xCDA8D611, 0x684A, 0x11D2, [0x87, 0x1E, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_DMUS_PROP_GM_Hardware = {0x178F2F24, 0xC364, 0x11D1, [0xA7, 0x60, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID GUID_DMUS_PROP_GS_Capable = {0x6496ABA2, 0x61B0, 0x11D2, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID GUID_DMUS_PROP_GS_Hardware = {0x178F2F25, 0xC364, 0x11D1, [0xA7, 0x60, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID GUID_DMUS_PROP_INSTRUMENT2 = {0x865FD372, 0x9F67, 0x11D2, [0x87, 0x2A, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_DMUS_PROP_LegacyCaps = {0xCFA7CDC2, 0x00A1, 0x11D2, [0xAA, 0xD5, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID GUID_DMUS_PROP_MemorySize = {0x178F2F28, 0xC364, 0x11D1, [0xA7, 0x60, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID GUID_DMUS_PROP_SampleMemorySize = {0x178F2F28, 0xC364, 0x11D1, [0xA7, 0x60, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID GUID_DMUS_PROP_SamplePlaybackRate = {0x2A91F713, 0xA4BF, 0x11D2, [0xBB, 0xDF, 0x00, 0x60, 0x08, 0x33, 0xDB, 0xD8]}; enum IID GUID_DMUS_PROP_SynthSink_DSOUND = {0x0AA97844, 0xC877, 0x11D1, [0x87, 0x0C, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_DMUS_PROP_SynthSink_WAVE = {0x0AA97845, 0xC877, 0x11D1, [0x87, 0x0C, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_DMUS_PROP_Volume = {0xFEDFAE25, 0xE46E, 0x11D1, [0xAA, 0xCE, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID GUID_DMUS_PROP_WavesReverb = {0x04CB5622, 0x32E5, 0x11D2, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID GUID_DMUS_PROP_WriteLatency = {0x268A0FA0, 0x60F2, 0x11D2, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID GUID_DMUS_PROP_WritePeriod = {0x268A0FA1, 0x60F2, 0x11D2, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID GUID_DMUS_PROP_XG_Capable = {0x6496ABA1, 0x61B0, 0x11D2, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID GUID_DMUS_PROP_XG_Hardware = {0x178F2F26, 0xC364, 0x11D1, [0xA7, 0x60, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID GUID_Download = {0xD2AC28A7, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_Enable_Auto_Download = {0xD2AC28A9, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_EnableTempo = {0x45FC707E, 0x1DB4, 0x11D2, [0xBC, 0xAC, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEB]}; enum IID GUID_EnableTimeSig = {0x45FC707C, 0x1DB4, 0x11D2, [0xBC, 0xAC, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEB]}; enum IID GUID_FONTBOLD = {0x6650430F, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_FONTITALIC = {0x66504310, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_FONTNAME = {0x6650430D, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_FONTSIZE = {0x6650430E, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_FONTSTRIKETHROUGH = {0x66504312, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_FONTUNDERSCORE = {0x66504311, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_Friction = {0x13541C2A, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_HANDLE = {0x66504313, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_HasPathProperties = {0x0002DE81, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID GUID_HIDClass = {0x745A17A0, 0x74D3, 0x11D0, [0xB6, 0xFE, 0x00, 0xA0, 0xC9, 0x0F, 0x57, 0xDA]}; enum IID GUID_HIMETRIC = {0x66504300, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_HWPROFILE_CHANGE_CANCELLED = {0xCB3A4002, 0x46F0, 0x11D0, [0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F]}; enum IID GUID_HWPROFILE_CHANGE_COMPLETE = {0xCB3A4003, 0x46F0, 0x11D0, [0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F]}; enum IID GUID_HWPROFILE_QUERY_CHANGE = {0xCB3A4001, 0x46F0, 0x11D0, [0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F]}; enum IID GUID_IDirectMusicBand = {0xD2AC28AC, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_IDirectMusicChordMap = {0xD2AC28AD, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_IDirectMusicStyle = {0xD2AC28A1, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_Inertia = {0x13541C29, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_INT_ROUTE_INTERFACE_STANDARD = {0x70941BF4, 0x0073, 0x11D1, [0xA0, 0x9E, 0x00, 0xC0, 0x4F, 0xC3, 0x40, 0xB1]}; enum IID GUID_Joystick = {0x6F1D2B70, 0xD5A0, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_KernelCallbacks = {0x80863800, 0x6B06, 0x11D0, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID GUID_KernelCaps = {0xFFAA7540, 0x7AA8, 0x11D0, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID GUID_Key = {0x55728220, 0xD33C, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_KeyboardClass = {0x4D36E96B, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_LEGACY_DEVICE_DETECTION_STANDAR = {0x50FEB0DE, 0x596A, 0x11D2, [0xA5, 0xB8, 0x00, 0x00, 0xF8, 0x1A, 0x46, 0x19]}; enum IID GUID_MediaClass = {0x4D36E96C, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_MF_ENUMERATION_INTERFACE = {0xAEB895F0, 0x5586, 0x11D1, [0x8D, 0x84, 0x00, 0xA0, 0xC9, 0x06, 0xB2, 0x44]}; enum IID GUID_Miscellaneous2Callbacks = {0x406B2F00, 0x3E5A, 0x11D1, [0xB6, 0x40, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x6A]}; enum IID GUID_MiscellaneousCallbacks = {0xEFD60CC0, 0x49E7, 0x11D0, [0x88, 0x9D, 0x00, 0xAA, 0x00, 0xBB, 0xB7, 0x6A]}; enum IID GUID_MotionCompCallbacks = {0xB1122B40, 0x5DA5, 0x11D1, [0x8F, 0xCF, 0x00, 0xC0, 0x4F, 0xC2, 0x9B, 0x4E]}; enum IID GUID_MouseClass = {0x4D36E96F, 0xE325, 0x11CE, [0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18]}; enum IID GUID_MuteParam = {0xD2AC28AF, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_NDIS_802_11_ADD_WEP = {0x4307BFF0, 0x2129, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_AUTHENTICATION_MODE = {0x43920A24, 0x2129, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_BASIC_RATES = {0x4A198516, 0x2068, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_BSSID = {0x2504B6C2, 0x1FA5, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_BSSID_LIST = {0x69526F9A, 0x2062, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_BSSID_LIST_SCAN = {0x0D9E01E1, 0xBA70, 0x11D4, [0xB6, 0x75, 0x00, 0x20, 0x48, 0x57, 0x03, 0x37]}; enum IID GUID_NDIS_802_11_CONFIGURATION = {0x4A4DF982, 0x2068, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_DESIRED_RATES = {0x452EE08E, 0x2536, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_DISASSOCIATE = {0x43671F40, 0x2129, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_FRAGMENTATION_THRESH = {0x69AAA7C4, 0x2062, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_INFRASTRUCTURE_MODE = {0x697D5A7E, 0x2062, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_NETWORK_TYPE_IN_USE = {0x857E2326, 0x2041, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_NETWORK_TYPES_SUPPOR = {0x8531D6E6, 0x2041, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_NUMBER_OF_ANTENNAS = {0x01779336, 0x2064, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_POWER_MODE = {0x85BE837C, 0x2041, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_PRIVACY_FILTER = {0x6733C4E9, 0x4792, 0x11D4, [0x97, 0xF1, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_REMOVE_WEP = {0x433C345C, 0x2129, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_RSSI = {0x1507DB16, 0x2053, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_RSSI_TRIGGER = {0x155689B8, 0x2053, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_RTS_THRESHOLD = {0x0134D07E, 0x2064, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_RX_ANTENNA_SELECTED = {0x01AC07A2, 0x2064, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_SSID = {0x7D2A90EA, 0x2041, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_STATISTICS = {0x42BB73B0, 0x2129, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_SUPPORTED_RATES = {0x49DB8722, 0x2068, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_TX_ANTENNA_SELECTED = {0x01DBB74A, 0x2064, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_TX_POWER_LEVEL = {0x11E6BA76, 0x2053, 0x11D4, [0x97, 0xEB, 0x00, 0xC0, 0x4F, 0x79, 0xC4, 0x03]}; enum IID GUID_NDIS_802_11_WEP_STATUS = {0xB027A21F, 0x3CFA, 0x4125, [0x80, 0x0B, 0x3F, 0x7A, 0x18, 0xFD, 0xDC, 0xDC]}; enum IID GUID_NDIS_802_3_CURRENT_ADDRESS = {0x44795700, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_3_MAC_OPTIONS = {0x44795703, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_3_MAXIMUM_LIST_SIZE = {0x44795702, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_3_MULTICAST_LIST = {0x44795701, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_3_PERMANENT_ADDRESS = {0x447956FF, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_3_RCV_ERROR_ALIGNMENT = {0x44795704, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_3_XMIT_MORE_COLLISIONS = {0x44795706, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_3_XMIT_ONE_COLLISION = {0x44795705, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_5_CURRENT_ADDRESS = {0x44795708, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_5_CURRENT_FUNCTIONAL = {0x44795709, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_5_CURRENT_GROUP = {0x4479570A, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_5_CURRENT_RING_STATE = {0xACF14032, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_5_CURRENT_RING_STATUS = {0x890A36EC, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_5_LAST_OPEN_STATUS = {0x4479570B, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_5_LINE_ERRORS = {0xACF14033, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_5_LOST_FRAMES = {0xACF14034, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_802_5_PERMANENT_ADDRESS = {0x44795707, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_HW_CURRENT_ADDRESS = {0x791AD1A1, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_MAX_AAL0_PACKET_SIZE = {0x791AD1A5, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_MAX_AAL1_PACKET_SIZE = {0x791AD1A6, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_MAX_AAL34_PACKET_SIZE = {0x791AD1A7, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_MAX_AAL5_PACKET_SIZE = {0x791AD191, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_MAX_ACTIVE_VCI_BITS = {0x791AD1A3, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_MAX_ACTIVE_VCS = {0x791AD1A2, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_MAX_ACTIVE_VPI_BITS = {0x791AD1A4, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_RCV_CELLS_DROPPED = {0x0A21480C, 0xE35F, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_RCV_CELLS_OK = {0x0A21480A, 0xE35F, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_SUPPORTED_AAL_TYPES = {0x791AD1A0, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_SUPPORTED_SERVICE_CATEG = {0x791AD19F, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_SUPPORTED_VC_RATES = {0x791AD19E, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ATM_XMIT_CELLS_OK = {0x0A21480B, 0xE35F, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ENUMERATE_ADAPTER = {0x981F2D7F, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_ENUMERATE_VC = {0x981F2D82, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_ATTACHMENT_TYPE = {0xACF1403D, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_DOWNSTREAM_NODE_LONG = {0xACF1403F, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_FRAME_ERRORS = {0xACF14040, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_FRAMES_LOST = {0xACF14041, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_LCONNECTION_STATE = {0xACF14045, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_LCT_FAILURES = {0xACF14043, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_LEM_REJECTS = {0xACF14044, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_LONG_CURRENT_ADDR = {0xACF14036, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_LONG_MAX_LIST_SIZE = {0xACF14038, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_LONG_MULTICAST_LIST = {0xACF14037, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_LONG_PERMANENT_ADDR = {0xACF14035, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_RING_MGT_STATE = {0xACF14042, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_SHORT_CURRENT_ADDR = {0xACF1403A, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_SHORT_MAX_LIST_SIZE = {0xACF1403C, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_SHORT_MULTICAST_LIST = {0xACF1403B, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_SHORT_PERMANENT_ADDR = {0xACF14039, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_FDDI_UPSTREAM_NODE_LONG = {0xACF1403E, 0xA61C, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_DRIVER_VERSION = {0x791AD198, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_HARDWARE_STATUS = {0x791AD192, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_LINK_SPEED = {0x791AD195, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_MAC_OPTIONS = {0x791AD19A, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_MEDIA_CONNECT_STATU = {0x791AD19B, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_MEDIA_IN_USE = {0x791AD194, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_MEDIA_SUPPORTED = {0x791AD193, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_MINIMUM_LINK_SPEED = {0x791AD19D, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_RCV_PDUS_ERROR = {0x0A214808, 0xE35F, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_RCV_PDUS_NO_BUFFER = {0x0A214809, 0xE35F, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_RCV_PDUS_OK = {0x0A214806, 0xE35F, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_VENDOR_DESCRIPTION = {0x791AD197, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_VENDOR_DRIVER_VERSI = {0x791AD19C, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_VENDOR_ID = {0x791AD196, 0xE35C, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_XMIT_PDUS_ERROR = {0x0A214807, 0xE35F, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CO_XMIT_PDUS_OK = {0x0A214805, 0xE35F, 0x11D0, [0x96, 0x92, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CURRENT_LOOKAHEAD = {0x5EC10361, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_CURRENT_PACKET_FILTER = {0x5EC10360, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_DRIVER_VERSION = {0x5EC10362, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_HARDWARE_STATUS = {0x5EC10354, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_LINK_SPEED = {0x5EC10359, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_MAC_OPTIONS = {0x5EC10365, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_MAXIMUM_FRAME_SIZE = {0x5EC10358, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_MAXIMUM_LOOKAHEAD = {0x5EC10357, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_MAXIMUM_SEND_PACKETS = {0x5EC10367, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_MAXIMUM_TOTAL_SIZE = {0x5EC10363, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_MEDIA_CONNECT_STATUS = {0x5EC10366, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_MEDIA_IN_USE = {0x5EC10356, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_MEDIA_SUPPORTED = {0x5EC10355, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_PHYSICAL_MEDIUM = {0x418CA16D, 0x3937, 0x4208, [0x94, 0x0A, 0xEC, 0x61, 0x96, 0x27, 0x80, 0x85]}; enum IID GUID_NDIS_GEN_RCV_ERROR = {0x447956FD, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_RCV_NO_BUFFER = {0x447956FE, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_RCV_OK = {0x447956FB, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_RECEIVE_BLOCK_SIZE = {0x5EC1035D, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_RECEIVE_BUFFER_SPACE = {0x5EC1035B, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_TRANSMIT_BLOCK_SIZE = {0x5EC1035C, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_TRANSMIT_BUFFER_SPACE = {0x5EC1035A, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_VENDOR_DESCRIPTION = {0x5EC1035F, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_VENDOR_DRIVER_VERSION = {0x447956F9, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_VENDOR_ID = {0x5EC1035E, 0xA61A, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_VLAN_ID = {0x765DC702, 0xC5E8, 0x4B67, [0x84, 0x3B, 0x3F, 0x5A, 0x4F, 0xF2, 0x64, 0x8B]}; enum IID GUID_NDIS_GEN_XMIT_ERROR = {0x447956FC, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_GEN_XMIT_OK = {0x447956FA, 0xA61B, 0x11D0, [0x8D, 0xD4, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_LAN_CLASS = {0xAD498944, 0x762F, 0x11D0, [0x8D, 0xCB, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL = {0x981F2D81, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_NOTIFY_ADAPTER_REMOVAL = {0x981F2D80, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_NOTIFY_BIND = {0x5413531C, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_NOTIFY_UNBIND = {0x6E3CE1EC, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_NOTIFY_VC_ARRIVAL = {0x182F9E0C, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_NOTIFY_VC_REMOVAL = {0x981F2D79, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_STATUS_LINK_SPEED_CHANGE = {0x981F2D85, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_STATUS_MEDIA_CONNECT = {0x981F2D7D, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_STATUS_MEDIA_DISCONNECT = {0x981F2D7E, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_STATUS_MEDIA_SPECIFIC_INDIC = {0x981F2D84, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_STATUS_RESET_END = {0x981F2D77, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_STATUS_RESET_START = {0x981F2D76, 0xB1F3, 0x11D0, [0x8D, 0xD7, 0x00, 0xC0, 0x4F, 0xC3, 0x35, 0x8C]}; enum IID GUID_NDIS_WAKE_ON_MAGIC_PACKET_ONLY = {0xA14F1C97, 0x8839, 0x4F8A, [0x99, 0x96, 0xA2, 0x89, 0x96, 0xEB, 0xBF, 0x1D]}; enum IID GUID_NETSHELL_PROPS = {0x2D15A9A1, 0xA556, 0x4189, [0x91, 0xAD, 0x02, 0x74, 0x58, 0xF1, 0x1A, 0x07]}; enum IID GUID_NonLocalVidMemCaps = {0x86C4FA80, 0x8D84, 0x11D0, [0x94, 0xE8, 0x00, 0xC0, 0x4F, 0xC3, 0x41, 0x37]}; enum IID GUID_NOTIFICATION_CHORD = {0xD2AC289B, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_NOTIFICATION_COMMAND = {0xD2AC289C, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_NOTIFICATION_MEASUREANDBEAT = {0xD2AC289A, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_NOTIFICATION_PERFORMANCE = {0x81F75BC5, 0x4E5D, 0x11D2, [0xBC, 0xC7, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEB]}; enum IID GUID_NOTIFICATION_SEGMENT = {0xD2AC2899, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_NULL = {0x00000000, 0x0000, 0x0000, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]}; enum IID GUID_OPTIONVALUEEXCLUSIVE = {0x6650430B, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_OptSurfaceKmodeInfo = {0xE05C8472, 0x51D4, 0x11D1, [0x8C, 0xCE, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID GUID_OptSurfaceUmodeInfo = {0x9D792804, 0x5FA8, 0x11D1, [0x8C, 0xD0, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID GUID_PathProperty = {0x0002DE80, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID GUID_PCI_BUS_INTERFACE_STANDARD = {0x496B8281, 0x6F25, 0x11D0, [0xBE, 0xAF, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F]}; enum IID GUID_PCI_DEVICE_PRESENT_INTERFACE = {0xD1B82C26, 0xBF49, 0x45EF, [0xB2, 0x16, 0x71, 0xCB, 0xD7, 0x88, 0x9B, 0x57]}; enum IID GUID_PCMCIA_BUS_INTERFACE_STANDARD = {0x76173AF0, 0xC504, 0x11D1, [0x94, 0x7F, 0x00, 0xC0, 0x4F, 0xB9, 0x60, 0xEE]}; enum IID GUID_PerfAutoDownload = {0xFB09565B, 0x3631, 0x11D2, [0xBC, 0xB8, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEB]}; enum IID GUID_PerfMasterGrooveLevel = {0xD2AC28B2, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_PerfMasterTempo = {0xD2AC28B0, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_PerfMasterVolume = {0xD2AC28B1, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_PNP_CUSTOM_NOTIFICATION = {0xACA73F8E, 0x8D23, 0x11D1, [0xAC, 0x7D, 0x00, 0x00, 0xF8, 0x75, 0x71, 0xD0]}; enum IID GUID_PNP_POWER_NOTIFICATION = {0xC2CF0660, 0xEB7A, 0x11D1, [0xBD, 0x7F, 0x00, 0x00, 0xF8, 0x75, 0x71, 0xD0]}; enum IID GUID_POV = {0xA36D02F2, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_POWER_DEVICE_ENABLE = {0x827C0A6F, 0xFEB0, 0x11D0, [0xBD, 0x26, 0x00, 0xAA, 0x00, 0xB7, 0xB3, 0x2A]}; enum IID GUID_POWER_DEVICE_TIMEOUTS = {0xA45DA735, 0xFEB0, 0x11D0, [0xBD, 0x26, 0x00, 0xAA, 0x00, 0xB7, 0xB3, 0x2A]}; enum IID GUID_POWER_DEVICE_WAKE_ENABLE = {0xA9546A82, 0xFEB0, 0x11D0, [0xBD, 0x26, 0x00, 0xAA, 0x00, 0xB7, 0xB3, 0x2A]}; enum IID GUID_QOS_BESTEFFORT_BANDWIDTH = {0xED885290, 0x40EC, 0x11D1, [0x2C, 0x91, 0x00, 0xAA, 0x00, 0x57, 0x49, 0x15]}; enum IID GUID_QOS_ENABLE_AVG_STATS = {0xBAFB6D11, 0x27C4, 0x4801, [0xA4, 0x6F, 0xEF, 0x80, 0x80, 0xC1, 0x88, 0xC8]}; enum IID GUID_QOS_ENABLE_WINDOW_ADJUSTMENT = {0xAA966725, 0xD3E9, 0x4C55, [0xB3, 0x35, 0x2A, 0x00, 0x27, 0x9A, 0x1E, 0x64]}; enum IID GUID_QOS_FLOW_8021P_CONFORMING = {0x08C1E013, 0xFCD2, 0x11D2, [0xBE, 0x1E, 0x00, 0xA0, 0xC9, 0x9E, 0xE6, 0x3B]}; enum IID GUID_QOS_FLOW_8021P_NONCONFORMING = {0x09023F91, 0xFCD2, 0x11D2, [0xBE, 0x1E, 0x00, 0xA0, 0xC9, 0x9E, 0xE6, 0x3B]}; enum IID GUID_QOS_FLOW_COUNT = {0x1147F880, 0x40ED, 0x11D1, [0x2C, 0x91, 0x00, 0xAA, 0x00, 0x57, 0x49, 0x15]}; enum IID GUID_QOS_FLOW_IP_CONFORMING = {0x07F99A8B, 0xFCD2, 0x11D2, [0xBE, 0x1E, 0x00, 0xA0, 0xC9, 0x9E, 0xE6, 0x3B]}; enum IID GUID_QOS_FLOW_IP_NONCONFORMING = {0x087A5987, 0xFCD2, 0x11D2, [0xBE, 0x1E, 0x00, 0xA0, 0xC9, 0x9E, 0xE6, 0x3B]}; enum IID GUID_QOS_FLOW_MODE = {0x5C82290A, 0x515A, 0x11D2, [0x8E, 0x58, 0x00, 0xC0, 0x4F, 0xC9, 0xBF, 0xCB]}; enum IID GUID_QOS_ISSLOW_FLOW = {0xABF273A4, 0xEE07, 0x11D2, [0xBE, 0x1B, 0x00, 0xA0, 0xC9, 0x9E, 0xE6, 0x3B]}; enum IID GUID_QOS_LATENCY = {0xFC408EF0, 0x40EC, 0x11D1, [0x2C, 0x91, 0x00, 0xAA, 0x00, 0x57, 0x49, 0x15]}; enum IID GUID_QOS_MAX_OUTSTANDING_SENDS = {0x161FFA86, 0x6120, 0x11D1, [0x2C, 0x91, 0x00, 0xAA, 0x00, 0x57, 0x49, 0x15]}; enum IID GUID_QOS_NON_BESTEFFORT_LIMIT = {0x185C44E0, 0x40ED, 0x11D1, [0x2C, 0x91, 0x00, 0xAA, 0x00, 0x57, 0x49, 0x15]}; enum IID GUID_QOS_REMAINING_BANDWIDTH = {0xC4C51720, 0x40EC, 0x11D1, [0x2C, 0x91, 0x00, 0xAA, 0x00, 0x57, 0x49, 0x15]}; enum IID GUID_QOS_STATISTICS_BUFFER = {0xBB2C0980, 0xE900, 0x11D1, [0xB0, 0x7E, 0x00, 0x80, 0xC7, 0x13, 0x82, 0xBF]}; enum IID GUID_QOS_TIMER_RESOLUTION = {0xBA10CC88, 0xF13E, 0x11D2, [0xBE, 0x1B, 0x00, 0xA0, 0xC9, 0x9E, 0xE6, 0x3B]}; enum IID GUID_RampForce = {0x13541C21, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_RhythmParam = {0xD2AC289F, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_RxAxis = {0xA36D02F4, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_RyAxis = {0xA36D02F5, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_RzAxis = {0xA36D02E3, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_SawtoothDown = {0x13541C26, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_SawtoothUp = {0x13541C25, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_SeedVariations = {0x65B76FA5, 0xFF37, 0x11D2, [0x81, 0x4E, 0x00, 0xC0, 0x4F, 0xA3, 0x6E, 0x58]}; enum IID GUID_Sine = {0x13541C23, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_Slider = {0xA36D02E4, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_Spring = {0x13541C27, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_Square = {0x13541C22, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_StandardMIDIFile = {0x06621075, 0xE92E, 0x11D1, [0xA8, 0xC5, 0x00, 0xC0, 0x4F, 0xA3, 0x72, 0x6E]}; enum IID GUID_SysKeyboard = {0x6F1D2B61, 0xD5A0, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_SysKeyboardEm = {0x6F1D2B82, 0xD5A0, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_SysKeyboardEm2 = {0x6F1D2B83, 0xD5A0, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_SysMouse = {0x6F1D2B60, 0xD5A0, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_SysMouseEm = {0x6F1D2B80, 0xD5A0, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_SysMouseEm2 = {0x6F1D2B81, 0xD5A0, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_TARGET_DEVICE_QUERY_REMOVE = {0xCB3A4006, 0x46F0, 0x11D0, [0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F]}; enum IID GUID_TARGET_DEVICE_REMOVE_CANCELLED = {0xCB3A4007, 0x46F0, 0x11D0, [0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F]}; enum IID GUID_TARGET_DEVICE_REMOVE_COMPLETE = {0xCB3A4008, 0x46F0, 0x11D0, [0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F]}; enum IID GUID_TempoParam = {0xD2AC28A5, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_TimeSignature = {0xD2AC28A4, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_TRANSLATOR_INTERFACE_STANDARD = {0x6C154A92, 0xAACF, 0x11D0, [0x8D, 0x2A, 0x00, 0xA0, 0xC9, 0x06, 0xB2, 0x44]}; enum IID GUID_Triangle = {0x13541C24, 0x8E33, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID GUID_TRISTATE = {0x6650430A, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_Unknown = {0xA36D02F3, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_Unload = {0xD2AC28A8, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID GUID_UserModeDriverInfo = {0xF0B0E8E2, 0x5F97, 0x11D1, [0x8C, 0xD0, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID GUID_UserModeDriverPassword = {0x97F861B6, 0x60A1, 0x11D1, [0x8C, 0xD0, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID GUID_VideoPortCallbacks = {0xEFD60CC1, 0x49E7, 0x11D0, [0x88, 0x9D, 0x00, 0xAA, 0x00, 0xBB, 0xB7, 0x6A]}; enum IID GUID_VideoPortCaps = {0xEFD60CC3, 0x49E7, 0x11D0, [0x88, 0x9D, 0x00, 0xAA, 0x00, 0xBB, 0xB7, 0x6A]}; enum IID GUID_XAxis = {0xA36D02E0, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_XPOS = {0x66504306, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_XPOSPIXEL = {0x66504302, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_XSIZE = {0x66504308, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_XSIZEPIXEL = {0x66504304, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_YAxis = {0xA36D02E1, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_YPOS = {0x66504307, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_YPOSPIXEL = {0x66504303, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_YSIZE = {0x66504309, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_YSIZEPIXEL = {0x66504305, 0xBE0F, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID GUID_ZAxis = {0xA36D02E2, 0xC9F3, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID GUID_ZPixelFormats = {0x93869880, 0x36CF, 0x11D1, [0x9B, 0x1B, 0x00, 0xAA, 0x00, 0xBB, 0xB8, 0xAE]}; enum IID IID_AsyncIAdviseSink = {0x00000150, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_AsyncIAdviseSink2 = {0x00000151, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_AsyncIBackgroundCopyCallback = {0xCA29D251, 0xB4BB, 0x4679, [0xA3, 0xD9, 0xAE, 0x80, 0x06, 0x11, 0x9D, 0x54]}; enum IID IID_AsyncIClusCfgBaseCluster = {0xA8A5C614, 0x2518, 0x47F5, [0x96, 0xCA, 0xCA, 0xFA, 0x7F, 0xFB, 0xAF, 0x68]}; enum IID IID_AsyncIClusCfgCallback = {0xEBCE8945, 0xAC69, 0x4B3A, [0x86, 0x5D, 0xE2, 0xD4, 0xEB, 0x33, 0xE4, 0x1B]}; enum IID IID_AsyncIClusCfgClusterInfo = {0x8BDBA247, 0x04F5, 0x4114, [0x83, 0x7E, 0xB2, 0x63, 0x41, 0x2A, 0x4B, 0x64]}; enum IID IID_AsyncIClusCfgCredentials = {0x54AA9406, 0xA409, 0x4B49, [0xB3, 0x14, 0x5F, 0x0A, 0x0C, 0xE4, 0xC8, 0x8F]}; enum IID IID_AsyncIClusCfgEvictCleanup = {0x6FE3E362, 0xD373, 0x4C5F, [0xA0, 0xAF, 0x1D, 0xFE, 0x84, 0x93, 0xC6, 0x55]}; enum IID IID_AsyncIClusCfgInitialize = {0x2A0EB82E, 0xF878, 0x492A, [0x95, 0x1E, 0xAE, 0x00, 0x09, 0x18, 0xC4, 0xA6]}; enum IID IID_AsyncIClusCfgIPAddressInfo = {0xAAEAF0A5, 0xE310, 0x4604, [0xA5, 0x5E, 0x2F, 0x9D, 0xDC, 0x41, 0x57, 0xA9]}; enum IID IID_AsyncIClusCfgManagedResourceInfo = {0x73616028, 0x1243, 0x4749, [0xAD, 0x84, 0x0B, 0x5E, 0xB3, 0x58, 0xFF, 0xA0]}; enum IID IID_AsyncIClusCfgMemberSetChangeListe = {0x2B645350, 0x2643, 0x4ABC, [0xA4, 0xE5, 0x82, 0x4D, 0x88, 0x1B, 0x75, 0x82]}; enum IID IID_AsyncIClusCfgNetworkInfo = {0xED71FD2D, 0xAD02, 0x4DFC, [0xB3, 0x76, 0x5F, 0xFA, 0x5F, 0x5A, 0x7C, 0x2C]}; enum IID IID_AsyncIClusCfgNodeInfo = {0x4F3BB40B, 0xDF27, 0x40A0, [0xB3, 0x1A, 0xBA, 0x18, 0x32, 0x4C, 0xEB, 0x9D]}; enum IID IID_AsyncIClusCfgPartitionInfo = {0xEC1EBD9F, 0x5866, 0x4846, [0x89, 0x52, 0xEC, 0x36, 0xC3, 0x96, 0x1E, 0xEF]}; enum IID IID_AsyncIClusCfgResourceTypeCreate = {0x3AFCE3B9, 0x5F3E, 0x4DDF, [0xA8, 0xF4, 0x4B, 0x4F, 0xCB, 0xF2, 0x8F, 0x8F]}; enum IID IID_AsyncIClusCfgResourceTypeInfo = {0xC649A282, 0xC847, 0x4F5C, [0x98, 0x41, 0xD2, 0xF7, 0x3B, 0x5A, 0xA7, 0x1D]}; enum IID IID_AsyncIClusCfgServer = {0x2A1640AA, 0x4561, 0x4A08, [0xB5, 0xD9, 0x0A, 0xA3, 0x8C, 0x6B, 0xE6, 0x28]}; enum IID IID_AsyncIClusCfgStartupListener = {0xD282CAF0, 0x2EDE, 0x4AB9, [0xA5, 0xD5, 0xF7, 0xBD, 0xE3, 0xD2, 0x3F, 0x10]}; enum IID IID_AsyncIClusCfgStartupNotify = {0xC2B0D06A, 0x6353, 0x4EE1, [0xB2, 0x53, 0x6B, 0x0D, 0x75, 0xDB, 0x2C, 0xD3]}; enum IID IID_AsyncIEnumClusCfgIPAddresses = {0xBD5F35BA, 0x0BC0, 0x455F, [0x92, 0x6D, 0xC3, 0xD3, 0x56, 0x41, 0x94, 0x87]}; enum IID IID_AsyncIEnumClusCfgManagedResource = {0xB138483F, 0x9695, 0x4FA6, [0xA9, 0x8F, 0x0D, 0xE2, 0xFB, 0x35, 0x54, 0x49]}; enum IID IID_AsyncIEnumClusCfgNetworks = {0xF56B9B0D, 0xE7B8, 0x49EC, [0xA8, 0x43, 0x54, 0x75, 0x07, 0x6B, 0x94, 0x7D]}; enum IID IID_AsyncIEnumClusCfgPartitions = {0x4440BB6A, 0xB0AC, 0x479D, [0xB5, 0x34, 0x72, 0x65, 0xA3, 0x1D, 0x6C, 0x56]}; enum IID IID_AsyncIMultiQI = {0x000E0020, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_AsyncIPipeByte = {0xDB2F3ACB, 0x2F86, 0x11D1, [0x8E, 0x04, 0x00, 0xC0, 0x4F, 0xB9, 0x98, 0x9A]}; enum IID IID_AsyncIPipeDouble = {0xDB2F3ACF, 0x2F86, 0x11D1, [0x8E, 0x04, 0x00, 0xC0, 0x4F, 0xB9, 0x98, 0x9A]}; enum IID IID_AsyncIPipeLong = {0xDB2F3ACD, 0x2F86, 0x11D1, [0x8E, 0x04, 0x00, 0xC0, 0x4F, 0xB9, 0x98, 0x9A]}; enum IID IID_AsyncIUnknown = {0x000E0000, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_DFConstraint = {0x4A3DF050, 0x23BD, 0x11D2, [0x93, 0x9F, 0x00, 0xA0, 0xC9, 0x1E, 0xED, 0xBA]}; enum IID IID_DIEnumWbemClassObject = {0xCB7CA037, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_DIWbemCallResult = {0xCB7CA039, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_DIWbemClassObject = {0xCB7CA033, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_DIWbemContext = {0xCB7CA038, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_DIWbemLocator = {0xCB7CA035, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_DIWbemObjectSink = {0xCB7CA036, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_DIWbemQualifierSet = {0xCB7CA034, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_DIWbemServices = {0xCB7CA03A, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_Folder = {0xBBCBDE60, 0xC3FF, 0x11CE, [0x83, 0x50, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_Folder2 = {0xF0D2D8EF, 0x3890, 0x11D2, [0xBF, 0x8B, 0x00, 0xC0, 0x4F, 0xB9, 0x36, 0x61]}; enum IID IID_Folder3 = {0xA7AE5F64, 0xC4D7, 0x4D7F, [0x93, 0x07, 0x4D, 0x24, 0xEE, 0x54, 0xB8, 0x41]}; enum IID IID_FolderItem = {0xFAC32C80, 0xCBE4, 0x11CE, [0x83, 0x50, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_FolderItem2 = {0xEDC817AA, 0x92B8, 0x11D1, [0xB0, 0x75, 0x00, 0xC0, 0x4F, 0xC3, 0x3A, 0xA5]}; enum IID IID_FolderItems = {0x744129E0, 0xCBE5, 0x11CE, [0x83, 0x50, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_FolderItems2 = {0xC94F0AD0, 0xF363, 0x11D2, [0xA3, 0x27, 0x00, 0xC0, 0x4F, 0x8E, 0xEC, 0x7F]}; enum IID IID_FolderItems3 = {0xEAA7C309, 0xBBEC, 0x49D5, [0x82, 0x1D, 0x64, 0xD9, 0x66, 0xCB, 0x66, 0x7F]}; enum IID IID_FolderItemVerb = {0x08EC3E00, 0x50B0, 0x11CF, [0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85]}; enum IID IID_FolderItemVerbs = {0x1F8352C0, 0x50B0, 0x11CF, [0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85]}; enum IID IID_IAccessControl = {0xEEDD23E0, 0x8410, 0x11CE, [0xA1, 0xC3, 0x08, 0x00, 0x2B, 0x2B, 0x8D, 0x8F]}; enum IID IID_IAccessible = {0x618736E0, 0x3C3D, 0x11CF, [0x81, 0x0C, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71]}; enum IID IID_IAccessibleHandler = {0x03022430, 0xABC4, 0x11D0, [0xBD, 0xE2, 0x00, 0xAA, 0x00, 0x1A, 0x19, 0x53]}; enum IID IID_IAccessor = {0x0C733A8C, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IAccIdentity = {0x7852B78D, 0x1CFD, 0x41C1, [0xA6, 0x15, 0x9C, 0x0C, 0x85, 0x96, 0x0B, 0x5F]}; enum IID IID_IAccountDiscovery = {0xFA202BBC, 0x6ABE, 0x4C17, [0xB1, 0x84, 0x57, 0x0B, 0x6C, 0xF2, 0x56, 0xA6]}; enum IID IID_IAccPropServer = {0x76C0DBBB, 0x15E0, 0x4E7B, [0xB6, 0x1B, 0x20, 0xEE, 0xEA, 0x20, 0x01, 0xE0]}; enum IID IID_IAccPropServices = {0x6E26E776, 0x04F0, 0x495D, [0x80, 0xE4, 0x33, 0x30, 0x35, 0x2E, 0x31, 0x69]}; enum IID IID_IACList = {0x77A130B0, 0x94FD, 0x11D0, [0xA5, 0x44, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62]}; enum IID IID_IACList2 = {0x470141A0, 0x5186, 0x11D2, [0xBB, 0xB6, 0x00, 0x60, 0x97, 0x7B, 0x46, 0x4C]}; enum IID IID_IActionProgress = {0x49FF1173, 0xEADC, 0x446D, [0x92, 0x85, 0x15, 0x64, 0x53, 0xA6, 0x43, 0x1C]}; enum IID IID_IActionProgressDialog = {0x49FF1172, 0xEADC, 0x446D, [0x92, 0x85, 0x15, 0x64, 0x53, 0xA6, 0x43, 0x1C]}; enum IID IID_IActiveDesktop = {0xF490EB00, 0x1240, 0x11D1, [0x98, 0x88, 0x00, 0x60, 0x97, 0xDE, 0xAC, 0xF9]}; enum IID IID_IActiveIME = {0x6FE20962, 0xD077, 0x11D0, [0x8F, 0xE7, 0x00, 0xAA, 0x00, 0x6B, 0xCC, 0x59]}; enum IID IID_IActiveIME2 = {0xE1C4BF0E, 0x2D53, 0x11D2, [0x93, 0xE1, 0x00, 0x60, 0xB0, 0x67, 0xB8, 0x6E]}; enum IID IID_IActiveIMMApp = {0x08C0E040, 0x62D1, 0x11D1, [0x93, 0x26, 0x00, 0x60, 0xB0, 0x67, 0xB8, 0x6E]}; enum IID IID_IActiveIMMIME = {0x08C03411, 0xF96B, 0x11D0, [0xA4, 0x75, 0x00, 0xAA, 0x00, 0x6B, 0xCC, 0x59]}; enum IID IID_IActiveIMMMessagePumpOwner = {0xB5CF2CFA, 0x8AEB, 0x11D1, [0x93, 0x64, 0x00, 0x60, 0xB0, 0x67, 0xB8, 0x6E]}; enum IID IID_IActiveIMMRegistrar = {0xB3458082, 0xBD00, 0x11D1, [0x93, 0x9B, 0x00, 0x60, 0xB0, 0x67, 0xB8, 0x6E]}; enum IID IID_IActiveScript = {0xBB1A2AE1, 0xA4F9, 0x11CF, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID IID_IActiveScriptAuthor = {0x9C109DA0, 0x7006, 0x11D1, [0xB3, 0x6C, 0x00, 0xA0, 0xC9, 0x11, 0xE8, 0xB2]}; enum IID IID_IActiveScriptAuthorProcedure = {0x7E2D4B70, 0xBD9A, 0x11D0, [0x93, 0x36, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IActiveScriptDebug = {0x51973C10, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IActiveScriptDebug32 = {0x51973C10, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IActiveScriptDebug64 = {0xBC437E23, 0xF5B8, 0x47F4, [0xBB, 0x79, 0x7D, 0x1C, 0xE5, 0x48, 0x3B, 0x86]}; enum IID IID_IActiveScriptEncode = {0xBB1A2AE3, 0xA4F9, 0x11CF, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID IID_IActiveScriptError = {0xEAE1BA61, 0xA4ED, 0x11CF, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID IID_IActiveScriptError64 = {0xB21FB2A1, 0x5B8F, 0x4963, [0x8C, 0x21, 0x21, 0x45, 0x0F, 0x84, 0xED, 0x7F]}; enum IID IID_IActiveScriptErrorDebug = {0x51973C12, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IActiveScriptGarbageCollector = {0x6AA2C4A0, 0x2B53, 0x11D4, [0xA2, 0xA0, 0x00, 0x10, 0x4B, 0xD3, 0x50, 0x90]}; enum IID IID_IActiveScriptHostEncode = {0xBEE9B76E, 0xCFE3, 0x11D1, [0xB7, 0x47, 0x00, 0xC0, 0x4F, 0xC2, 0xB0, 0x85]}; enum IID IID_IActiveScriptParse = {0xBB1A2AE2, 0xA4F9, 0x11CF, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID IID_IActiveScriptParse32 = {0xBB1A2AE2, 0xA4F9, 0x11CF, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID IID_IActiveScriptParse64 = {0xC7EF7658, 0xE1EE, 0x480E, [0x97, 0xEA, 0xD5, 0x2C, 0xB4, 0xD7, 0x6D, 0x17]}; enum IID IID_IActiveScriptParseProcedure = {0xAA5B6A80, 0xB834, 0x11D0, [0x93, 0x2F, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IActiveScriptParseProcedure2_32 = {0x71EE5B20, 0xFB04, 0x11D1, [0xB3, 0xA8, 0x00, 0xA0, 0xC9, 0x11, 0xE8, 0xB2]}; enum IID IID_IActiveScriptParseProcedure2_64 = {0xFE7C4271, 0x210C, 0x448D, [0x9F, 0x54, 0x76, 0xDA, 0xB7, 0x04, 0x7B, 0x28]}; enum IID IID_IActiveScriptParseProcedure32 = {0xAA5B6A80, 0xB834, 0x11D0, [0x93, 0x2F, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IActiveScriptParseProcedure64 = {0xC64713B6, 0xE029, 0x4CC5, [0x92, 0x00, 0x43, 0x8B, 0x72, 0x89, 0x0B, 0x6A]}; enum IID IID_IActiveScriptParseProcedureOld = {0x1CFF0050, 0x6FDD, 0x11D0, [0x93, 0x28, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IActiveScriptParseProcedureOld32 = {0x1CFF0050, 0x6FDD, 0x11D0, [0x93, 0x28, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IActiveScriptParseProcedureOld64 = {0x21F57128, 0x08C9, 0x4638, [0xBA, 0x12, 0x22, 0xD1, 0x5D, 0x88, 0xDC, 0x5C]}; enum IID IID_IActiveScriptProperty = {0x4954E0D0, 0xFBC7, 0x11D1, [0x84, 0x10, 0x00, 0x60, 0x08, 0xC3, 0xFB, 0xFC]}; enum IID IID_IActiveScriptSIPInfo = {0x764651D0, 0x38DE, 0x11D4, [0xA2, 0xA3, 0x00, 0x10, 0x4B, 0xD3, 0x50, 0x90]}; enum IID IID_IActiveScriptSite = {0xDB01A1E3, 0xA42B, 0x11CF, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID IID_IActiveScriptSiteDebug32 = {0x51973C11, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IActiveScriptSiteDebug64 = {0xD6B96B0A, 0x7463, 0x402C, [0x92, 0xAC, 0x89, 0x98, 0x42, 0x26, 0x94, 0x2F]}; enum IID IID_IActiveScriptSiteInterruptPoll = {0x539698A0, 0xCDCA, 0x11CF, [0xA5, 0xEB, 0x00, 0xAA, 0x00, 0x47, 0xA0, 0x63]}; enum IID IID_IActiveScriptSiteWindow = {0xD10F6761, 0x83E9, 0x11CF, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID IID_IActiveScriptStats = {0xB8DA6310, 0xE19B, 0x11D0, [0x93, 0x3C, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IActiveXSafetyProvider = {0x69FF5101, 0xFC63, 0x11D0, [0x97, 0xEB, 0x00, 0xAA, 0x00, 0x61, 0x53, 0x33]}; enum IID IID_IAdapterInfo = {0x480BF94A, 0x09FD, 0x4F8A, [0xA3, 0xE0, 0xB0, 0x70, 0x02, 0x82, 0xD8, 0x4D]}; enum IID IID_IAdapterNotificationSink = {0x44AB2DC3, 0x23B2, 0x47DE, [0x82, 0x28, 0x2E, 0x1C, 0xCE, 0xEB, 0x99, 0x11]}; enum IID IID_IAddEvents = {0xD710A6AE, 0x3371, 0x11D1, [0xBE, 0x5B, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0xBB]}; enum IID IID_IAddressBarParser = {0xC9D81948, 0x443A, 0x40C7, [0x94, 0x5C, 0x5E, 0x17, 0x1B, 0x8C, 0x66, 0xB4]}; enum IID IID_IAddrExclusionControl = {0x00000148, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IAddrTrackingControl = {0x00000147, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IADs = {0xFD8256D0, 0xFD15, 0x11CE, [0xAB, 0xC4, 0x02, 0x60, 0x8C, 0x9E, 0x75, 0x53]}; enum IID IID_IADsAccessControlEntry = {0xB4F3A14C, 0x9BDD, 0x11D0, [0x85, 0x2C, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsAccessControlList = {0xB7EE91CC, 0x9BDD, 0x11D0, [0x85, 0x2C, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsAcePrivate = {0xFD145DF2, 0xFD96, 0x4135, [0x9B, 0x22, 0x68, 0xFF, 0x0F, 0x6B, 0xF5, 0xBB]}; enum IID IID_IADsAcl = {0x8452D3AB, 0x0869, 0x11D1, [0xA3, 0x77, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsADSystemInfo = {0x5BB11929, 0xAFD1, 0x11D2, [0x9C, 0xB9, 0x00, 0x00, 0xF8, 0x7A, 0x36, 0x9E]}; enum IID IID_IADsBackLink = {0xFD1302BD, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsCaseIgnoreList = {0x7B66B533, 0x4680, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsClass = {0xC8F93DD0, 0x4AE0, 0x11CF, [0x9E, 0x73, 0x00, 0xAA, 0x00, 0x4A, 0x56, 0x91]}; enum IID IID_IADsCollection = {0x72B945E0, 0x253B, 0x11CF, [0xA9, 0x88, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsComputer = {0xEFE3CC70, 0x1D9F, 0x11CF, [0xB1, 0xF3, 0x02, 0x60, 0x8C, 0x9E, 0x75, 0x53]}; enum IID IID_IADsComputerOperations = {0xEF497680, 0x1D9F, 0x11CF, [0xB1, 0xF3, 0x02, 0x60, 0x8C, 0x9E, 0x75, 0x53]}; enum IID IID_IADsContainer = {0x001677D0, 0xFD16, 0x11CE, [0xAB, 0xC4, 0x02, 0x60, 0x8C, 0x9E, 0x75, 0x53]}; enum IID IID_IADsDeleteOps = {0xB2BD0902, 0x8878, 0x11D1, [0x8C, 0x21, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsDNWithBinary = {0x7E99C0A2, 0xF935, 0x11D2, [0xBA, 0x96, 0x00, 0xC0, 0x4F, 0xB6, 0xD0, 0xD1]}; enum IID IID_IADsDNWithString = {0x370DF02E, 0xF934, 0x11D2, [0xBA, 0x96, 0x00, 0xC0, 0x4F, 0xB6, 0xD0, 0xD1]}; enum IID IID_IADsDomain = {0x00E4C220, 0xFD16, 0x11CE, [0xAB, 0xC4, 0x02, 0x60, 0x8C, 0x9E, 0x75, 0x53]}; enum IID IID_IADsEmail = {0x97AF011A, 0x478E, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsExtension = {0x3D35553C, 0xD2B0, 0x11D1, [0xB1, 0x7B, 0x00, 0x00, 0xF8, 0x75, 0x93, 0xA0]}; enum IID IID_IADsFaxNumber = {0xA910DEA9, 0x4680, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsFileService = {0xA89D1900, 0x31CA, 0x11CF, [0xA9, 0x8A, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsFileServiceOperations = {0xA02DED10, 0x31CA, 0x11CF, [0xA9, 0x8A, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsFileShare = {0xEB6DCAF0, 0x4B83, 0x11CF, [0xA9, 0x95, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsGroup = {0x27636B00, 0x410F, 0x11CF, [0xB1, 0xFF, 0x02, 0x60, 0x8C, 0x9E, 0x75, 0x53]}; enum IID IID_IADsHold = {0xB3EB3B37, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsLargeInteger = {0x9068270B, 0x0939, 0x11D1, [0x8B, 0xE1, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsLocality = {0xA05E03A2, 0xEFFE, 0x11CF, [0x8A, 0xBC, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsMembers = {0x451A0030, 0x72EC, 0x11CF, [0xB0, 0x3B, 0x00, 0xAA, 0x00, 0x6E, 0x09, 0x75]}; enum IID IID_IADsNamespaces = {0x28B96BA0, 0xB330, 0x11CF, [0xA9, 0xAD, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsNameTranslate = {0xB1B272A3, 0x3625, 0x11D1, [0xA3, 0xA4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsNetAddress = {0xB21A50A9, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsO = {0xA1CD2DC6, 0xEFFE, 0x11CF, [0x8A, 0xBC, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsObjectOptions = {0x46F14FDA, 0x232B, 0x11D1, [0xA8, 0x08, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0xA8]}; enum IID IID_IADsObjOptPrivate = {0x81CBB829, 0x1867, 0x11D2, [0x92, 0x20, 0x00, 0xC0, 0x4F, 0xB6, 0xD0, 0xD1]}; enum IID IID_IADsOctetList = {0x7B28B80F, 0x4680, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsOpenDSObject = {0xDDF2891E, 0x0F9C, 0x11D0, [0x8A, 0xD4, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsOU = {0xA2F733B8, 0xEFFE, 0x11CF, [0x8A, 0xBC, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsPath = {0xB287FCD5, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsPathname = {0xD592AED4, 0xF420, 0x11D0, [0xA3, 0x6E, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsPathnameProvider = {0xAACD1D30, 0x8BD0, 0x11D2, [0x92, 0xA9, 0x00, 0xC0, 0x4F, 0x79, 0xF8, 0x34]}; enum IID IID_IADsPostalAddress = {0x7ADECF29, 0x4680, 0x11D1, [0xA3, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsPrintJob = {0x32FB6780, 0x1ED0, 0x11CF, [0xA9, 0x88, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsPrintJobOperations = {0x9A52DB30, 0x1ECF, 0x11CF, [0xA9, 0x88, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsPrintQueue = {0xB15160D0, 0x1226, 0x11CF, [0xA9, 0x85, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsPrintQueueOperations = {0x124BE5C0, 0x156E, 0x11CF, [0xA9, 0x86, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsProperty = {0xC8F93DD3, 0x4AE0, 0x11CF, [0x9E, 0x73, 0x00, 0xAA, 0x00, 0x4A, 0x56, 0x91]}; enum IID IID_IADsPropertyEntry = {0x05792C8E, 0x941F, 0x11D0, [0x85, 0x29, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsPropertyList = {0xC6F602B6, 0x8F69, 0x11D0, [0x85, 0x28, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsPropertyValue = {0x79FA9AD0, 0xA97C, 0x11D0, [0x85, 0x34, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsPropertyValue2 = {0x306E831C, 0x5BC7, 0x11D1, [0xA3, 0xB8, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsReplicaPointer = {0xF60FB803, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsResource = {0x34A05B20, 0x4AAB, 0x11CF, [0xAE, 0x2C, 0x00, 0xAA, 0x00, 0x6E, 0xBF, 0xB9]}; enum IID IID_IADsSearch = {0xC69F7780, 0x4008, 0x11D0, [0xB9, 0x4C, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0xA8]}; enum IID IID_IADsSecurityDescriptor = {0xB8C787CA, 0x9BDD, 0x11D0, [0x85, 0x2C, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsSecurityUtility = {0xA63251B2, 0x5F21, 0x474B, [0xAB, 0x52, 0x4A, 0x8E, 0xFA, 0xD1, 0x08, 0x95]}; enum IID IID_IADsService = {0x68AF66E0, 0x31CA, 0x11CF, [0xA9, 0x8A, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsServiceOperations = {0x5D7B33F0, 0x31CA, 0x11CF, [0xA9, 0x8A, 0x00, 0xAA, 0x00, 0x6B, 0xC1, 0x49]}; enum IID IID_IADsSession = {0x398B7DA0, 0x4AAB, 0x11CF, [0xAE, 0x2C, 0x00, 0xAA, 0x00, 0x6E, 0xBF, 0xB9]}; enum IID IID_IADsSyntax = {0xC8F93DD2, 0x4AE0, 0x11CF, [0x9E, 0x73, 0x00, 0xAA, 0x00, 0x4A, 0x56, 0x91]}; enum IID IID_IADsTimestamp = {0xB2F5A901, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsTypedName = {0xB371A349, 0x4080, 0x11D1, [0xA3, 0xAC, 0x00, 0xC0, 0x4F, 0xB9, 0x50, 0xDC]}; enum IID IID_IADsUmiHelperPrivate = {0x4FE243F0, 0xAD89, 0x4CBC, [0x9B, 0x14, 0x48, 0x61, 0x26, 0x44, 0x6A, 0xE0]}; enum IID IID_IADsUser = {0x3E37E320, 0x17E2, 0x11CF, [0xAB, 0xC4, 0x02, 0x60, 0x8C, 0x9E, 0x75, 0x53]}; enum IID IID_IADsValue = {0x1E3EF0AA, 0xAEF5, 0x11D0, [0x85, 0x37, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IADsWinNTSystemInfo = {0x6C6D65DC, 0xAFD1, 0x11D2, [0x9C, 0xB9, 0x00, 0x00, 0xF8, 0x7A, 0x36, 0x9E]}; enum IID IID_IAdviseSink = {0x0000010F, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IAdviseSink2 = {0x00000125, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IAdviseSinkEx = {0x3AF24290, 0x0C96, 0x11CE, [0xA0, 0xCF, 0x00, 0xAA, 0x00, 0x60, 0x0A, 0xB8]}; enum IID IID_IAlertReport = {0x4E81DFE8, 0x4CA0, 0x101A, [0x82, 0x06, 0x08, 0x00, 0x2B, 0x2F, 0xC0, 0x9B]}; enum IID IID_IAlertTarget = {0x589B61C0, 0x54E6, 0x11CE, [0x94, 0xDD, 0x00, 0xAA, 0x00, 0x51, 0xE4, 0x0F]}; enum IID IID_IAlgSetup = {0xA779AF1A, 0x009A, 0x4C44, [0xB9, 0xF0, 0x8F, 0x0F, 0x4C, 0xF2, 0xAE, 0x49]}; enum IID IID_IAlterIndex = {0x0C733AA6, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IAlterTable = {0x0C733AA5, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IAnchorClick = {0x13D5413B, 0x33B9, 0x11D2, [0x95, 0xA7, 0x00, 0xC0, 0x4F, 0x8E, 0xCB, 0x02]}; enum IID IID_IAnimationComposer = {0x5459C83D, 0x322B, 0x44B3, [0x8D, 0xAA, 0x24, 0xC9, 0x47, 0xE7, 0xB2, 0x75]}; enum IID IID_IAnimationComposer2 = {0x1A4F0E79, 0x09CD, 0x47F3, [0xAF, 0xF1, 0x48, 0x3B, 0xF3, 0xA2, 0x22, 0xDC]}; enum IID IID_IAnimationComposerFactory = {0xBEEB3233, 0xF71F, 0x4683, [0x8B, 0x05, 0x9A, 0x53, 0x14, 0xC9, 0x7D, 0xBC]}; enum IID IID_IAnimationComposerSite = {0x488FCB56, 0x8FD6, 0x4CDA, [0xA0, 0x6A, 0x5B, 0xB2, 0x32, 0x93, 0x0E, 0xCA]}; enum IID IID_IAnimationComposerSiteFactory = {0xB4EA5681, 0xED72, 0x4EFE, [0xBB, 0xD7, 0x7C, 0x47, 0xD1, 0x32, 0x56, 0x96]}; enum IID IID_IAnimationComposerSiteSink = {0x8EF76C64, 0x71CD, 0x480F, [0x96, 0xFC, 0xBA, 0x26, 0x96, 0xE6, 0x59, 0xBE]}; enum IID IID_IAnimationFragment = {0x319DFD88, 0x0AC6, 0x4AB1, [0xA1, 0x9F, 0x90, 0x22, 0x3B, 0xA2, 0xDA, 0x16]}; enum IID IID_IAnimationRoot = {0x29DF6387, 0x30B4, 0x4A62, [0x89, 0x1B, 0xA9, 0xC5, 0xBE, 0x37, 0xBE, 0x88]}; enum IID IID_IApplicationDebugger = {0x51973C2A, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IApplicationDebuggerUI = {0x51973C2B, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IApplicationGateway = {0x5134842B, 0xFDCE, 0x485D, [0x93, 0xCD, 0xDE, 0x16, 0x40, 0x64, 0x3B, 0xBE]}; enum IID IID_IApplicationGatewayServices = {0x5134842A, 0xFDCE, 0x485D, [0x93, 0xCD, 0xDE, 0x16, 0x40, 0x64, 0x3B, 0xBE]}; enum IID IID_IAppPublisher = {0x07250A10, 0x9CF9, 0x11D1, [0x90, 0x76, 0x00, 0x60, 0x08, 0x05, 0x93, 0x82]}; enum IID IID_IAsyncBindCtx = {0x79EAC9D4, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IAsyncManager = {0x0000002A, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IAsyncMoniker = {0x79EAC9D3, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IAsyncOperation = {0x3D8B0590, 0xF691, 0x11D2, [0x8E, 0xA9, 0x00, 0x60, 0x97, 0xDF, 0x5B, 0xD4]}; enum IID IID_IAsyncRpcChannelBuffer = {0xA5029FB6, 0x3C34, 0x11D1, [0x9C, 0x99, 0x00, 0xC0, 0x4F, 0xB9, 0x98, 0xAA]}; enum IID IID_IAttributesRaw = {0x6BC096A8, 0x0CE6, 0x11D1, [0xBA, 0xAE, 0x00, 0xC0, 0x4F, 0xC2, 0xE2, 0x0D]}; enum IID IID_IAuditControl = {0x1DA6292F, 0xBC66, 0x11CE, [0xAA, 0xE3, 0x00, 0xAA, 0x00, 0x4C, 0x27, 0x37]}; enum IID IID_IAuthenticate = {0x79EAC9D0, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IAutoComplete = {0x00BB2762, 0x6A77, 0x11D0, [0xA5, 0x35, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62]}; enum IID IID_IAutoComplete2 = {0xEAC04BC0, 0x3791, 0x11D2, [0xBB, 0x95, 0x00, 0x60, 0x97, 0x7B, 0x46, 0x4C]}; enum IID IID_IAutoCompleteDropDown = {0x3CD141F4, 0x3C6A, 0x11D2, [0xBC, 0xAA, 0x00, 0xC0, 0x4F, 0xD9, 0x29, 0xDB]}; enum IID IID_IAutoCompList = {0x00BB2760, 0x6A77, 0x11D0, [0xA5, 0x35, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62]}; enum IID IID_IAutoDiscoveryProvider = {0x9DCF4A37, 0x01DE, 0x4549, [0xA9, 0xCB, 0x3A, 0xC3, 0x1E, 0xC2, 0x3C, 0x4F]}; enum IID IID_IBackgroundCopyCallback = {0x97EA99C7, 0x0186, 0x4AD4, [0x8D, 0xF9, 0xC5, 0xB4, 0xE0, 0xED, 0x6B, 0x22]}; enum IID IID_IBackgroundCopyCallback1 = {0x084F6593, 0x3800, 0x4E08, [0x9B, 0x59, 0x99, 0xFA, 0x59, 0xAD, 0xDF, 0x82]}; enum IID IID_IBackgroundCopyError = {0x19C613A0, 0xFCB8, 0x4F28, [0x81, 0xAE, 0x89, 0x7C, 0x3D, 0x07, 0x8F, 0x81]}; enum IID IID_IBackgroundCopyFile = {0x01B7BD23, 0xFB88, 0x4A77, [0x84, 0x90, 0x58, 0x91, 0xD3, 0xE4, 0x65, 0x3A]}; enum IID IID_IBackgroundCopyGroup = {0x1DED80A7, 0x53EA, 0x424F, [0x8A, 0x04, 0x17, 0xFE, 0xA9, 0xAD, 0xC4, 0xF5]}; enum IID IID_IBackgroundCopyJob = {0x37668D37, 0x507E, 0x4160, [0x93, 0x16, 0x26, 0x30, 0x6D, 0x15, 0x0B, 0x12]}; enum IID IID_IBackgroundCopyJob1 = {0x59F5553C, 0x2031, 0x4629, [0xBB, 0x18, 0x26, 0x45, 0xA6, 0x97, 0x09, 0x47]}; enum IID IID_IBackgroundCopyJob2 = {0x54B50739, 0x686F, 0x45EB, [0x9D, 0xFF, 0xD6, 0xA9, 0xA0, 0xFA, 0xA9, 0xAF]}; enum IID IID_IBackgroundCopyManager = {0x5CE34C0D, 0x0DC9, 0x4C1F, [0x89, 0x7C, 0xDA, 0xA1, 0xB7, 0x8C, 0xEE, 0x7C]}; enum IID IID_IBackgroundCopyQMgr = {0x16F41C69, 0x09F5, 0x41D2, [0x8C, 0xD8, 0x3C, 0x08, 0xC4, 0x7B, 0xC8, 0xA8]}; enum IID IID_IBidiRequestSpl = {0x9C007000, 0xFFA8, 0x44FF, [0xB2, 0xB3, 0xAE, 0x91, 0x02, 0xC7, 0x4D, 0x4C]}; enum IID IID_IBindCtx = {0x0000000E, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IBindEventHandler = {0x63CDBCB0, 0xC1B1, 0x11D0, [0x93, 0x36, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IBindHost = {0xFC4801A1, 0x2BA9, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID IID_IBinding = {0x79EAC9C0, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IBindProtocol = {0x79EAC9CD, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IBindResource = {0x0C733AB1, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IBindStatusCallback = {0x79EAC9C1, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IBindStatusCallbackHolder = {0x79EAC9CC, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IBindStatusCallbackMsg = {0x79EAC9D5, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IBitsTest1 = {0x51A183DB, 0x67E0, 0x4472, [0x86, 0x02, 0x3D, 0xBC, 0x73, 0x0B, 0x7E, 0xF5]}; enum IID IID_IBlockFormats = {0x3050F830, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IBlockingLock = {0x30F3D47A, 0x6447, 0x11D1, [0x8E, 0x3C, 0x00, 0xC0, 0x4F, 0xB9, 0x38, 0x6D]}; enum IID IID_IBoundObject = {0x9BFBBC00, 0xEFF1, 0x101A, [0x84, 0xED, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IBoundObjectSite = {0x9BFBBC01, 0xEFF1, 0x101A, [0x84, 0xED, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IBriefcaseStg = {0x8BCE1FA1, 0x0921, 0x101B, [0xB1, 0xFF, 0x00, 0xDD, 0x01, 0x0C, 0xCC, 0x48]}; enum IID IID_IBurnEngine = {0x520CCA66, 0x51A5, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID IID_ICallFactory = {0x1C733A30, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICallFrame = {0xD573B4B0, 0x894E, 0x11D2, [0xB8, 0xB6, 0x00, 0xC0, 0x4F, 0xB9, 0x61, 0x8A]}; enum IID IID_ICallFrameEvents = {0xFD5E0843, 0xFC91, 0x11D0, [0x97, 0xD7, 0x00, 0xC0, 0x4F, 0xB9, 0x61, 0x8A]}; enum IID IID_ICallFrameWalker = {0x08B23919, 0x392D, 0x11D2, [0xB8, 0xA4, 0x00, 0xC0, 0x4F, 0xB9, 0x61, 0x8A]}; enum IID IID_ICallIndirect = {0xD573B4B1, 0x894E, 0x11D2, [0xB8, 0xB6, 0x00, 0xC0, 0x4F, 0xB9, 0x61, 0x8A]}; enum IID IID_ICallInterceptor = {0x60C7CA75, 0x896D, 0x11D2, [0xB8, 0xB6, 0x00, 0xC0, 0x4F, 0xB9, 0x61, 0x8A]}; enum IID IID_ICallUnmarshal = {0x5333B003, 0x2E42, 0x11D2, [0xB8, 0x9D, 0x00, 0xC0, 0x4F, 0xB9, 0x61, 0x8A]}; enum IID IID_ICancelMethodCalls = {0x00000029, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ICatalogFileInfo = {0x711C7600, 0x6B48, 0x11D1, [0xB4, 0x03, 0x00, 0xAA, 0x00, 0xB9, 0x2A, 0xF1]}; enum IID IID_ICategorizer = {0xA3B14589, 0x9174, 0x49A8, [0x89, 0xA3, 0x06, 0xA1, 0xAE, 0x2B, 0x9B, 0xA7]}; enum IID IID_ICategoryProvider = {0x9AF64809, 0x5864, 0x4C26, [0xA7, 0x20, 0xC1, 0xF7, 0x8C, 0x08, 0x6E, 0xE3]}; enum IID IID_ICatInformation = {0x0002E013, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ICatRegister = {0x0002E012, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ICDBurn = {0x3D73A659, 0xE5D0, 0x4D42, [0xAF, 0xC0, 0x51, 0x21, 0xBA, 0x42, 0x5C, 0x8D]}; enum IID IID_ICEnroll = {0x43F8F288, 0x7A20, 0x11D0, [0x8F, 0x06, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1]}; enum IID IID_ICEnroll2 = {0x704CA730, 0xC90B, 0x11D1, [0x9B, 0xEC, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1]}; enum IID IID_ICEnroll3 = {0xC28C2D95, 0xB7DE, 0x11D2, [0xA4, 0x21, 0x00, 0xC0, 0x4F, 0x79, 0xFE, 0x8E]}; enum IID IID_ICEnroll4 = {0xC1F1188A, 0x2EB5, 0x4A80, [0x84, 0x1B, 0x7E, 0x72, 0x9A, 0x35, 0x6D, 0x90]}; enum IID IID_IChannelHook = {0x1008C4A0, 0x7613, 0x11CF, [0x9A, 0xF1, 0x00, 0x20, 0xAF, 0x6E, 0x72, 0xF4]}; enum IID IID_IChannelMgr = {0x85BD8E82, 0x0FBA, 0x11D1, [0x90, 0xC3, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x68]}; enum IID IID_IChapteredRowset = {0x0C733A93, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICheckBox = {0x3050F685, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ICiAdmin = {0xAE67C7D8, 0x85D3, 0x11D0, [0x8C, 0x45, 0x00, 0xC0, 0x4F, 0xC2, 0xDB, 0x8D]}; enum IID IID_ICiAdminParams = {0xA82D48C6, 0x3F0F, 0x11D0, [0x8C, 0x91, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCAdviseStatus = {0xCA05734A, 0x1218, 0x11D3, [0xAE, 0x7A, 0x00, 0xC0, 0x4F, 0x72, 0xF8, 0x31]}; enum IID IID_ICiCDeferredPropRetriever = {0xC273AF70, 0x6D72, 0x11D0, [0x8D, 0x64, 0x00, 0xA0, 0xC9, 0x08, 0xDB, 0xF1]}; enum IID IID_ICiCDocName = {0x76615076, 0x3C2B, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCDocNameToWorkidTranslator = {0x25FC3F54, 0x3CB4, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCDocNameToWorkidTranslatorEx = {0x7BBA76E6, 0xA0E3, 0x11D2, [0xBC, 0x5D, 0x00, 0xC0, 0x4F, 0xA3, 0x54, 0xBA]}; enum IID IID_ICiCDocStore = {0x46625468, 0x3C32, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCDocStoreEx = {0xF98282A7, 0xFA72, 0x11D1, [0x97, 0x98, 0x00, 0xC0, 0x4F, 0xC2, 0xF4, 0x10]}; enum IID IID_ICiCDocStoreLocator = {0x97EE7C06, 0x5908, 0x11D0, [0x8C, 0x9B, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCEventLogItem = {0x44CC886A, 0x4314, 0x11D0, [0x8C, 0x91, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCFilterClient = {0xA1E0BCB6, 0x3C24, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCFilterStatus = {0xBC5F3D60, 0x8BBC, 0x11D1, [0x8F, 0x73, 0x00, 0xA0, 0xC9, 0x19, 0x17, 0xF5]}; enum IID IID_ICiCIndexNotificationStatus = {0x5FFF3840, 0x8E76, 0x11D0, [0x8D, 0x69, 0x00, 0xA0, 0xC9, 0x08, 0xDB, 0xF1]}; enum IID IID_ICiCLangRes = {0x914C2E6C, 0x43FE, 0x11D0, [0x8C, 0x91, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiControl = {0x63DEB7F4, 0x3CCB, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCOpenedDoc = {0x151EDFBE, 0x3C2F, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCPropertyStorage = {0x4C46225A, 0x3CB5, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCPropRetriever = {0x77D9B2DA, 0x4401, 0x11D0, [0x8C, 0x91, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCQueryNotification = {0x0A9E9F6C, 0x3CE2, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCQuerySession = {0xAE461FD6, 0x4E1D, 0x11D0, [0x8C, 0x94, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCResourceMonitor = {0xF700FF8E, 0x20EE, 0x11D2, [0x80, 0xF7, 0x00, 0xC0, 0x4F, 0xA3, 0x54, 0xBA]}; enum IID IID_ICiCScope = {0x1021C882, 0x3CC0, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCScopeChecker = {0x7D820C9C, 0x3CBC, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCScopeEnumerator = {0xCF8505EA, 0x3CCA, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCSecurityChecker = {0xCA130CF4, 0x3CC2, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiCUserSecurity = {0x5D01D9CE, 0x3CC2, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiDocChangeNotifySink = {0x8BFA1386, 0x3CE5, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiEnumWorkids = {0x77900150, 0xA09C, 0x11D0, [0xA8, 0x0D, 0x00, 0xA0, 0xC9, 0x06, 0x24, 0x1A]}; enum IID IID_ICiFrameworkQuery = {0xAE67C7D9, 0x85D3, 0x11D0, [0x8C, 0x45, 0x00, 0xC0, 0x4F, 0xC2, 0xDB, 0x8D]}; enum IID IID_ICiIndexNotification = {0x4F2CD6E0, 0x8E74, 0x11D0, [0x8D, 0x69, 0x00, 0xA0, 0xC9, 0x08, 0xDB, 0xF1]}; enum IID IID_ICiIndexNotificationEntry = {0x210769D0, 0x8E75, 0x11D0, [0x8D, 0x69, 0x00, 0xA0, 0xC9, 0x08, 0xDB, 0xF1]}; enum IID IID_ICiISearchCreator = {0x7DC07FA0, 0x902E, 0x11D0, [0xA8, 0x0C, 0x00, 0xA0, 0xC9, 0x06, 0x24, 0x1A]}; enum IID IID_ICiManager = {0xCF0FCF56, 0x3CCE, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiPersistIncrFile = {0x31B311E2, 0x4498, 0x11D0, [0x8C, 0x91, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_ICiQueryPropertyMapper = {0xD2333EB0, 0x756B, 0x11D0, [0x8D, 0x66, 0x00, 0xA0, 0xC9, 0x08, 0xDB, 0xF1]}; enum IID IID_ICiStartup = {0x68232CB8, 0x3CCC, 0x11D0, [0x8C, 0x90, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_IClassActivator = {0x00000140, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IClassFactory = {0x00000001, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IClassFactory2 = {0xB196B28F, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IClassFactoryEx = {0x342D1EA0, 0xAE25, 0x11D1, [0x89, 0xC5, 0x00, 0x60, 0x08, 0xC3, 0xFB, 0xFC]}; enum IID IID_IClientCaps = {0x7E8BC44D, 0xAEFF, 0x11D1, [0x89, 0xC2, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4]}; enum IID IID_IClientSecurity = {0x0000013D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IClusCfgAsyncEvictCleanup = {0x52C80B95, 0xC1AD, 0x4240, [0x8D, 0x89, 0x72, 0xE9, 0xFA, 0x84, 0x02, 0x5E]}; enum IID IID_IClusCfgBaseCluster = {0xA8A5C613, 0x2518, 0x47F5, [0x96, 0xCA, 0xCA, 0xFA, 0x7F, 0xFB, 0xAF, 0x68]}; enum IID IID_IClusCfgCallback = {0x238DCA63, 0xE2EF, 0x4F32, [0xA2, 0x4D, 0xAC, 0xBF, 0x97, 0x5B, 0xE8, 0x42]}; enum IID IID_IClusCfgCapabilities = {0xD94AB253, 0x36C7, 0x41C1, [0xB5, 0x2E, 0x26, 0xB4, 0x51, 0x97, 0x5C, 0x8D]}; enum IID IID_IClusCfgClusterConnection = {0xCE6EF90C, 0x3602, 0x41E7, [0x95, 0xBD, 0xAA, 0xFD, 0x37, 0xA6, 0x76, 0xDF]}; enum IID IID_IClusCfgClusterInfo = {0x85B4BBC0, 0xDDC4, 0x4AE7, [0x82, 0x68, 0xF4, 0x85, 0x0B, 0xB2, 0xA6, 0xEE]}; enum IID IID_IClusCfgCredentials = {0x54AA9406, 0xA409, 0x4B49, [0xB3, 0x14, 0x5F, 0x0A, 0x0C, 0xE4, 0xC8, 0x8E]}; enum IID IID_IClusCfgEvictCleanup = {0x6FE3E361, 0xD373, 0x4C5F, [0xA0, 0xAF, 0x1D, 0xFE, 0x84, 0x93, 0xC6, 0x55]}; enum IID IID_IClusCfgGroupCfg = {0xDCB6D3D2, 0xA55F, 0x49E5, [0xA6, 0x4A, 0x0C, 0xCF, 0xEB, 0x01, 0xED, 0x3A]}; enum IID IID_IClusCfgInitialize = {0x2A0EB82D, 0xF878, 0x492A, [0x95, 0x1E, 0xAE, 0x00, 0x09, 0x18, 0xC4, 0xA6]}; enum IID IID_IClusCfgIPAddressInfo = {0xAAEAF0A5, 0xE310, 0x4604, [0xA5, 0x5E, 0x2F, 0x9D, 0xDC, 0x41, 0x57, 0xA8]}; enum IID IID_IClusCfgManagedResourceCfg = {0x60300A0F, 0x77E1, 0x440C, [0xBD, 0x94, 0x6B, 0xFB, 0x0D, 0xBF, 0xDB, 0x3A]}; enum IID IID_IClusCfgManagedResourceInfo = {0xE0324847, 0x1520, 0x41B0, [0xB9, 0x60, 0x54, 0x19, 0x8D, 0xA5, 0xF8, 0xAF]}; enum IID IID_IClusCfgMemberSetChangeListener = {0x2B64534F, 0x2643, 0x4ABC, [0xA4, 0xE5, 0x82, 0x4D, 0x88, 0x1B, 0x75, 0x82]}; enum IID IID_IClusCfgNetworkInfo = {0x19FC7580, 0x950A, 0x44A6, [0x96, 0x6E, 0x74, 0xB1, 0x4B, 0x20, 0x91, 0x8F]}; enum IID IID_IClusCfgNodeInfo = {0xE4B5FA15, 0xDD07, 0x439E, [0xA6, 0x23, 0x88, 0x23, 0x52, 0x4E, 0x3D, 0x19]}; enum IID IID_IClusCfgPartitionInfo = {0xEC1EBD9F, 0x5866, 0x4846, [0x89, 0x52, 0xEC, 0x36, 0xC3, 0x96, 0x1E, 0xEE]}; enum IID IID_IClusCfgPollingCallback = {0xC72DB1FD, 0x51A2, 0x43E6, [0xB7, 0x08, 0xD9, 0xDB, 0x7D, 0xA7, 0x96, 0x30]}; enum IID IID_IClusCfgPollingCallbackInfo = {0x2AF55DA7, 0xCB6F, 0x40DE, [0xBB, 0x11, 0x66, 0x73, 0x46, 0x4B, 0x2C, 0x54]}; enum IID IID_IClusCfgResourceCreate = {0x0647B41A, 0xC777, 0x443C, [0x94, 0x32, 0x02, 0xCC, 0xCF, 0x4F, 0xF4, 0x43]}; enum IID IID_IClusCfgResourcePostCreate = {0x72A9BF54, 0x13B6, 0x451F, [0x91, 0x0D, 0x69, 0x13, 0xEB, 0xF0, 0x25, 0xAB]}; enum IID IID_IClusCfgResourcePreCreate = {0x4240F6A1, 0x9D49, 0x427E, [0x8F, 0x3D, 0x09, 0x38, 0x4E, 0x1F, 0x59, 0xE4]}; enum IID IID_IClusCfgResourceTypeCreate = {0x3AFCE3B8, 0x5F3E, 0x4DDF, [0xA8, 0xF4, 0x4B, 0x4F, 0xCB, 0xF2, 0x8F, 0x8F]}; enum IID IID_IClusCfgResourceTypeInfo = {0xC649A281, 0xC847, 0x4F5C, [0x98, 0x41, 0xD2, 0xF7, 0x3B, 0x5A, 0xA7, 0x1D]}; enum IID IID_IClusCfgResTypeServicesInitializ = {0x6E109698, 0xDFC4, 0x4471, [0xAC, 0xE1, 0x04, 0x14, 0x93, 0x1B, 0x3B, 0xB3]}; enum IID IID_IClusCfgServer = {0x4C06EAE6, 0x990E, 0x4051, [0x8A, 0xA1, 0xAD, 0x4B, 0x4E, 0xAE, 0x9C, 0xAF]}; enum IID IID_IClusCfgSetCredentials = {0x58E6E5B9, 0x4788, 0x4D9A, [0x82, 0x55, 0x1E, 0x27, 0x4E, 0x5D, 0xCC, 0xB0]}; enum IID IID_IClusCfgStartupListener = {0xD282CAEF, 0x2EDE, 0x4AB9, [0xA5, 0xD5, 0xF7, 0xBD, 0xE3, 0xD2, 0x3F, 0x0F]}; enum IID IID_IClusCfgStartupNotify = {0xC2B0D069, 0x6353, 0x4EE1, [0xB2, 0x53, 0x6B, 0x0D, 0x75, 0xDB, 0x2C, 0xD3]}; enum IID IID_IClusCfgVerify = {0xD47BBEEC, 0x2286, 0x4514, [0xAA, 0x90, 0x7E, 0x88, 0xBD, 0x0F, 0xE5, 0x43]}; enum IID IID_IClusCfgWizard = {0x2EB57A3B, 0xDA8D, 0x4B56, [0x97, 0xCF, 0xA3, 0x19, 0x1B, 0xF8, 0xFD, 0x5B]}; enum IID IID_IClusterApplicationWizard = {0x24F97151, 0x6689, 0x11D1, [0x9A, 0xA7, 0x00, 0xC0, 0x4F, 0xB9, 0x3A, 0x80]}; enum IID IID_ICodeInstall = {0x79EAC9D1, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IColumnMapper = {0x0B63E37A, 0x9CCC, 0x11D0, [0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04]}; enum IID IID_IColumnMapperCreator = {0x0B63E37B, 0x9CCC, 0x11D0, [0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04]}; enum IID IID_IColumnProvider = {0xE8025004, 0x1C42, 0x11D2, [0xBE, 0x2C, 0x00, 0xA0, 0xC9, 0xA8, 0x3D, 0xA1]}; enum IID IID_IColumnsInfo = {0x0C733A11, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IColumnsInfo2 = {0x0C733AB8, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IColumnsRowset = {0x0C733A10, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICombobox = {0x3050F677, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ICommand = {0x0C733A63, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommandCost = {0x0C733A4E, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommandPersist = {0x0C733AA7, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommandPrepare = {0x0C733A26, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommandProperties = {0x0C733A79, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommandStream = {0x0C733ABF, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommandText = {0x0C733A27, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommandTree = {0x0C733A87, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommandValidate = {0x0C733A18, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommandWithParameters = {0x0C733A64, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICommDlgBrowser = {0x000214F1, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ICommDlgBrowser2 = {0x10339516, 0x2894, 0x11D2, [0x90, 0x39, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x3E]}; enum IID IID_ICommonQuery = {0xAB50DEC0, 0x6F1D, 0x11D0, [0xA1, 0xC4, 0x00, 0xAA, 0x00, 0xC1, 0x6E, 0x65]}; enum IID IID_IComThreadingInfo = {0x000001CE, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IConfigurationConnection = {0xDDAD8191, 0x66C5, 0x4A30, [0xA4, 0xDF, 0xCB, 0x6C, 0x21, 0x67, 0x04, 0xCA]}; enum IID IID_IConnectionInfo = {0x15182CE3, 0x82D7, 0x473F, [0x92, 0xDE, 0x70, 0x6E, 0x2B, 0xCE, 0xA9, 0x02]}; enum IID IID_IConnectionManager = {0xC0017768, 0x1BF3, 0x4352, [0x8D, 0x6C, 0x3A, 0x8C, 0x1D, 0x0F, 0xB4, 0x77]}; enum IID IID_IConnectionPoint = {0xB196B286, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IConnectionPointContainer = {0xB196B284, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IContextCallback = {0x000001DA, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IContextMenu = {0x000214E4, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IContextMenu2 = {0x000214F4, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IContextMenu3 = {0xBCFCE0A0, 0xEC17, 0x11D0, [0x8D, 0x10, 0x00, 0xA0, 0xC9, 0x0F, 0x27, 0x19]}; enum IID IID_IContinue = {0x0000012A, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IContinueCallback = {0xB722BCCA, 0x4E68, 0x101B, [0xA2, 0xBC, 0x00, 0xAA, 0x00, 0x40, 0x47, 0x70]}; enum IID IID_IConvertType = {0x0C733A88, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICrBarn = {0x276A2EE0, 0x0B5D, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICrBarn2 = {0xB66A7A1B, 0x8FC6, 0x448C, [0xA2, 0xEB, 0x3C, 0x55, 0x95, 0x74, 0x78, 0xA1]}; enum IID IID_ICrBlinds = {0x5AF5C340, 0x0BA9, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICrBlinds2 = {0x7059D403, 0x599A, 0x4264, [0x81, 0x40, 0x64, 0x1E, 0xB8, 0xAE, 0x1F, 0x64]}; enum IID IID_ICrBlur = {0x9F7C7827, 0xE87A, 0x11D1, [0x81, 0xE0, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_ICreateErrorInfo = {0x22F03340, 0x547D, 0x101B, [0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19]}; enum IID IID_ICreateRow = {0x0C733AB2, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ICreateTypeInfo = {0x00020405, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ICreateTypeInfo2 = {0x0002040E, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ICreateTypeLib = {0x00020406, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ICreateTypeLib2 = {0x0002040F, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ICrEmboss = {0xE4ACFB80, 0x053E, 0x11D2, [0x81, 0xEA, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_ICrEngrave = {0xE4ACFB7F, 0x053E, 0x11D2, [0x81, 0xEA, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_ICrInset = {0x05C5EE20, 0x0BA6, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICrIris = {0x3F69F350, 0x0379, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICrIris2 = {0xF7B06961, 0xBA8C, 0x4970, [0x91, 0x8B, 0x1C, 0x60, 0xCB, 0x9F, 0xF1, 0x80]}; enum IID IID_ICrRadialWipe = {0x424B71AE, 0x0695, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICrSlide = {0x810E402E, 0x056B, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICrSpiral = {0x0DE527A0, 0x0C7E, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICrStretch = {0x6684AF00, 0x0A87, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICrWheel = {0x3943DE80, 0x1464, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICrZigzag = {0x4E5A64A0, 0x0C8B, 0x11D2, [0xA4, 0x84, 0x00, 0xC0, 0x4F, 0x8E, 0xFB, 0x69]}; enum IID IID_ICSSFilter = {0x3050F3EC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ICSSFilterDispatch = {0x9519152B, 0x9484, 0x4A6C, [0xB6, 0xA7, 0x4F, 0x25, 0xE9, 0x2D, 0x6C, 0x6B]}; enum IID IID_ICSSFilterSite = {0x3050F3ED, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ICurrentWorkingDirectory = {0x91956D21, 0x9276, 0x11D1, [0x92, 0x1A, 0x00, 0x60, 0x97, 0xDF, 0x5B, 0xD4]}; enum IID IID_ICursor = {0x9F6AA700, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID IID_ICursorFind = {0xE01D7850, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID IID_ICursorMove = {0xACFF0690, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID IID_ICursorScroll = {0xBB87E420, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID IID_ICursorUpdateARow = {0xD14216A0, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID IID_ICustomDoc = {0x3050F3F0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ICustomRatingHelper = {0xD0D9842D, 0xE211, 0x4B2C, [0x88, 0xDC, 0xBC, 0x72, 0x93, 0x42, 0xDF, 0xCB]}; enum IID IID_IDA2Array = {0x2A8F0B06, 0xBE2B, 0x11D1, [0xB2, 0x19, 0x00, 0xC0, 0x4F, 0xC2, 0xA0, 0xCA]}; enum IID IID_IDA2Behavior = {0xC46C1BF0, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDA2Event = {0x69B5BC70, 0x9B19, 0x11D0, [0x9B, 0x60, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDA2FontStyle = {0x283807B5, 0x2C60, 0x11D0, [0xA3, 0x1D, 0x00, 0xAA, 0x00, 0xB9, 0x2C, 0x03]}; enum IID IID_IDA2Geometry = {0x4A933702, 0xE36F, 0x11D0, [0x9B, 0x99, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDA2Image = {0x45393DF0, 0x54B9, 0x11CF, [0x92, 0xA2, 0x00, 0xAA, 0x00, 0xB8, 0xA7, 0x33]}; enum IID IID_IDA2LineStyle = {0x2AE71568, 0x4B34, 0x11D1, [0xB1, 0xE3, 0x00, 0xC0, 0x4F, 0xC2, 0xA0, 0xCA]}; enum IID IID_IDA2Statics = {0xD17506C2, 0x6B26, 0x11D0, [0x89, 0x14, 0x00, 0xC0, 0x4F, 0xC2, 0xA0, 0xCA]}; enum IID IID_IDA2View = {0x5F00F545, 0xDF18, 0x11D1, [0xAB, 0x6F, 0x00, 0xC0, 0x4F, 0xD9, 0x2B, 0x6B]}; enum IID IID_IDA2ViewerControl = {0xC46C1BEF, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDA2ViewerControlWindowed = {0xC46C1BED, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAArray = {0xFA261CF0, 0xC44E, 0x11D1, [0x9B, 0xE4, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDABbox2 = {0xBA8B033E, 0x1E91, 0x11D1, [0x88, 0x09, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID IID_IDABbox3 = {0x0E41257B, 0x812D, 0x11D0, [0x9B, 0x4A, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDABehavior = {0x5DFB2651, 0x9668, 0x11D0, [0xB1, 0x7B, 0x00, 0xC0, 0x4F, 0xC2, 0xA0, 0xCA]}; enum IID IID_IDABoolean = {0xC46C1BDA, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDABvrHook = {0x50B4791F, 0x4731, 0x11D0, [0x89, 0x12, 0x00, 0xC0, 0x4F, 0xC2, 0xA0, 0xCA]}; enum IID IID_IDACamera = {0xC46C1BCA, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAColor = {0xC46C1BDC, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDADashStyle = {0xF3E1B522, 0xD8A6, 0x11D1, [0x9B, 0xE5, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDADrawingSurface = {0xC46C1BF4, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDADXTransformResult = {0xAF868305, 0xAB0B, 0x11D0, [0x87, 0x6A, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID IID_IDAEndStyle = {0xB6FFC24C, 0x7E13, 0x11D0, [0x9B, 0x47, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDAEvent = {0xC46C1BCE, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAFontStyle = {0xC46C1BC1, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAGeometry = {0xC46C1BCC, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAImage = {0xC46C1BC4, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAImport = {0xC46C1BEE, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAImportationResult = {0xB90E5258, 0x574A, 0x11D1, [0x8E, 0x7B, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID IID_IDAJoinStyle = {0xA3034056, 0xEC1C, 0x11D1, [0x9B, 0xE8, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDALineStyle = {0x69AD90EF, 0x1C20, 0x11D1, [0x88, 0x01, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID IID_IDAMatte = {0xC46C1BE4, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAMicrophone = {0xC46C1BD8, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAModifiableBehavior = {0xC46C1BEC, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAMontage = {0xC46C1BC8, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDANumber = {0xD17506C3, 0x6B26, 0x11D0, [0x89, 0x14, 0x00, 0xC0, 0x4F, 0xC2, 0xA0, 0xCA]}; enum IID IID_IDAPair = {0x542FB453, 0x5003, 0x11CF, [0x92, 0xA2, 0x00, 0xAA, 0x00, 0xB8, 0xA7, 0x33]}; enum IID IID_IDAPath2 = {0xC46C1BD0, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAPickableResult = {0xC46C1BDE, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAPoint2 = {0x9CDE7341, 0x3C20, 0x11D0, [0xA3, 0x30, 0x00, 0xAA, 0x00, 0xB9, 0x2C, 0x03]}; enum IID IID_IDAPoint3 = {0xC46C1BD6, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAPreferences = {0xB90E525A, 0x574A, 0x11D1, [0x8E, 0x7B, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID IID_IDASite = {0xB90E5259, 0x574A, 0x11D1, [0x8E, 0x7B, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID IID_IDASound = {0xC46C1BE6, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAStatics = {0x5DFB2650, 0x9668, 0x11D0, [0xB1, 0x7B, 0x00, 0xC0, 0x4F, 0xC2, 0xA0, 0xCA]}; enum IID IID_IDAString = {0xC46C1BD2, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDataAdviseHolder = {0x00000110, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDataChannel = {0xAD42D12A, 0x4AD0, 0x4856, [0x91, 0x9E, 0xE8, 0x54, 0xC9, 0x1D, 0x18, 0x56]}; enum IID IID_IDataConvert = {0x0C733A8D, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDataFilter = {0x69D14C80, 0xC18E, 0x11D0, [0xA9, 0xCE, 0x00, 0x60, 0x97, 0x94, 0x23, 0x11]}; enum IID IID_IDataObject = {0x0000010E, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDATransform2 = {0xC46C1BD4, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDATransform3 = {0xC46C1BE0, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDATuple = {0x542FB452, 0x5003, 0x11CF, [0x92, 0xA2, 0x00, 0xAA, 0x00, 0xB8, 0xA7, 0x33]}; enum IID IID_IDAUntilNotifier = {0x25B0F91C, 0xD23D, 0x11D0, [0x9B, 0x85, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDAUserData = {0xBACD4D86, 0x4A4F, 0x11D1, [0x9B, 0xC8, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDAVector2 = {0xC46C1BC6, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAVector3 = {0xC46C1BE2, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAView = {0xAF868304, 0xAB0B, 0x11D0, [0x87, 0x6A, 0x00, 0xC0, 0x4F, 0xC2, 0x9D, 0x46]}; enum IID IID_IDAViewerControl = {0xC46C1BDD, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAViewerControlWindowed = {0xC46C1BCD, 0x3C52, 0x11D0, [0x92, 0x00, 0x84, 0x8C, 0x1D, 0x00, 0x00, 0x00]}; enum IID IID_IDAViewSite = {0xBCBB1F75, 0xE384, 0x11D0, [0x9B, 0x99, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID IID_IDBAsynchNotify = {0x0C733A96, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBAsynchStatus = {0x0C733A95, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBBinderProperties = {0x0C733AB3, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBCreateCommand = {0x0C733A1D, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBCreateSession = {0x0C733A5D, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBDataSourceAdmin = {0x0C733A7A, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBInfo = {0x0C733A89, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBInitialize = {0x0C733A8B, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBProperties = {0x0C733A8A, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBSchemaCommand = {0x0C733A50, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDBSchemaRowset = {0x0C733A7B, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDCInfo = {0x0C733A9C, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IDDVideoAcceleratorContainer = {0xACA12120, 0x3356, 0x11D1, [0x8F, 0xCF, 0x00, 0xC0, 0x4F, 0xC2, 0x9B, 0x4E]}; enum IID IID_IDDVideoPortContainer = {0x6C142760, 0xA733, 0x11CE, [0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60]}; enum IID IID_IDebug = {0x00000123, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDebugApplication = {0x51973C32, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugApplication32 = {0x51973C32, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugApplication64 = {0x4DEDC754, 0x04C7, 0x4F10, [0x9E, 0x60, 0x16, 0xA3, 0x90, 0xFE, 0x6E, 0x62]}; enum IID IID_IDebugApplicationEx = {0x51973C00, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugApplicationNode = {0x51973C34, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugApplicationNodeEvents = {0x51973C35, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugApplicationThread = {0x51973C38, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugApplicationThread64 = {0x9DAC5886, 0xDBAD, 0x456D, [0x9D, 0xEE, 0x5D, 0xEC, 0x39, 0xAB, 0x3D, 0xDA]}; enum IID IID_IDebugAsyncOperation = {0x51973C1B, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugAsyncOperationCallBack = {0x51973C1C, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugCodeContext = {0x51973C13, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugCookie = {0x51973C39, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocument = {0x51973C21, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentContext = {0x51973C28, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentHelper32 = {0x51973C26, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentHelper64 = {0xC4C7363C, 0x20FD, 0x47F9, [0xBD, 0x82, 0x48, 0x55, 0xE0, 0x15, 0x08, 0x71]}; enum IID IID_IDebugDocumentHelperEx = {0x51973C02, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentHost = {0x51973C27, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentInfo = {0x51973C1F, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentProvider = {0x51973C20, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentText = {0x51973C22, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentTextAuthor = {0x51973C24, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentTextEvents = {0x51973C23, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugDocumentTextExternalAuthor = {0x51973C25, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugExpression = {0x51973C14, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugExpressionCallBack = {0x51973C16, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugExpressionContext = {0x51973C15, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugExtendedProperty = {0x51973C52, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugFormatter = {0x51973C05, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugHelper = {0x51973C3F, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugHelperEx = {0x51973C08, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugOut = {0xC733E4F1, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_IDebugProperty = {0x51973C50, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugPropertyEnumType_All = {0x51973C55, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugPropertyEnumType_Arguments = {0x51973C57, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugPropertyEnumType_Locals = {0x51973C56, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugPropertyEnumType_LocalsPlus = {0x51973C58, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugPropertyEnumType_Registers = {0x51973C59, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugRegister = {0xC733E4F0, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_IDebugSessionProvider = {0x51973C29, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugSessionProviderEx = {0x51973C09, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugSetValueCallback = {0x51973C06, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugStackFrame = {0x51973C17, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugStackFrameSniffer = {0x51973C18, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugStackFrameSnifferEx = {0x51973C19, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugStackFrameSnifferEx32 = {0x51973C19, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugStackFrameSnifferEx64 = {0x8CD12AF4, 0x49C1, 0x4D52, [0x8D, 0x8A, 0xC1, 0x46, 0xF4, 0x75, 0x81, 0xAA]}; enum IID IID_IDebugStream = {0x00000124, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDebugSyncOperation = {0x51973C1A, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugThreadCall = {0x51973C36, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugThreadCall32 = {0x51973C36, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IDebugThreadCall64 = {0xCB3FA335, 0xE979, 0x42FD, [0x9F, 0xCF, 0xA7, 0x54, 0x6A, 0x0F, 0x39, 0x05]}; enum IID IID_IDelaydC = {0xBFF9C030, 0xB58F, 0x11CE, [0xB5, 0xB0, 0x00, 0xAA, 0x00, 0x6C, 0xB3, 0x7D]}; enum IID IID_IDelayedRelease = {0x000214ED, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDelegateFolder = {0xADD8BA80, 0x002B, 0x11D0, [0x8F, 0x0F, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62]}; enum IID IID_IDeskBand = {0xEB0FE172, 0x1A3A, 0x11D0, [0x89, 0xB3, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xAC]}; enum IID IID_IDeviceRect = {0x3050F6D5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IDfReserved1 = {0x00000013, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDfReserved2 = {0x00000014, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDfReserved3 = {0x00000015, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDialBranding = {0x8AECAFA9, 0x4306, 0x43CC, [0x8C, 0x5A, 0x76, 0x5F, 0x29, 0x79, 0xCC, 0x16]}; enum IID IID_IDialEngine = {0x39FD782B, 0x7905, 0x40D5, [0x91, 0x48, 0x3C, 0x9B, 0x19, 0x04, 0x23, 0xD5]}; enum IID IID_IDialEventSink = {0x2D86F4FF, 0x6E2D, 0x4488, [0xB2, 0xE9, 0x69, 0x34, 0xAF, 0xD4, 0x1B, 0xEA]}; enum IID IID_IDifferencing = {0x994F0AF0, 0x2977, 0x11CE, [0xBB, 0x80, 0x08, 0x00, 0x2B, 0x36, 0xB2, 0xB0]}; enum IID IID_IDirect3D = {0x3BBA0080, 0x2421, 0x11CF, [0xA3, 0x1A, 0x00, 0xAA, 0x00, 0xB9, 0x33, 0x56]}; enum IID IID_IDirect3D2 = {0x6AAE1EC1, 0x662A, 0x11D0, [0x88, 0x9D, 0x00, 0xAA, 0x00, 0xBB, 0xB7, 0x6A]}; enum IID IID_IDirect3D3 = {0xBB223240, 0xE72B, 0x11D0, [0xA9, 0xB4, 0x00, 0xAA, 0x00, 0xC0, 0x99, 0x3E]}; enum IID IID_IDirect3D7 = {0xF5049E77, 0x4861, 0x11D2, [0xA4, 0x07, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID IID_IDirect3DDevice = {0x64108800, 0x957D, 0x11D0, [0x89, 0xAB, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29]}; enum IID IID_IDirect3DDevice2 = {0x93281501, 0x8CF8, 0x11D0, [0x89, 0xAB, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29]}; enum IID IID_IDirect3DDevice3 = {0xB0AB3B60, 0x33D7, 0x11D1, [0xA9, 0x81, 0x00, 0xC0, 0x4F, 0xD7, 0xB1, 0x74]}; enum IID IID_IDirect3DDevice7 = {0xF5049E79, 0x4861, 0x11D2, [0xA4, 0x07, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID IID_IDirect3DExecuteBuffer = {0x4417C145, 0x33AD, 0x11CF, [0x81, 0x6F, 0x00, 0x00, 0xC0, 0x20, 0x15, 0x6E]}; enum IID IID_IDirect3DHALDevice = {0x84E63DE0, 0x46AA, 0x11CF, [0x81, 0x6F, 0x00, 0x00, 0xC0, 0x20, 0x15, 0x6E]}; enum IID IID_IDirect3DLight = {0x4417C142, 0x33AD, 0x11CF, [0x81, 0x6F, 0x00, 0x00, 0xC0, 0x20, 0x15, 0x6E]}; enum IID IID_IDirect3DMaterial = {0x4417C144, 0x33AD, 0x11CF, [0x81, 0x6F, 0x00, 0x00, 0xC0, 0x20, 0x15, 0x6E]}; enum IID IID_IDirect3DMaterial2 = {0x93281503, 0x8CF8, 0x11D0, [0x89, 0xAB, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29]}; enum IID IID_IDirect3DMaterial3 = {0xCA9C46F4, 0xD3C5, 0x11D1, [0xB7, 0x5A, 0x00, 0x60, 0x08, 0x52, 0xB3, 0x12]}; enum IID IID_IDirect3DMMXDevice = {0x881949A1, 0xD6F3, 0x11D0, [0x89, 0xAB, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29]}; enum IID IID_IDirect3DNullDevice = {0x8767DF22, 0xBACC, 0x11D1, [0x89, 0x69, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID IID_IDirect3DRampDevice = {0xF2086B20, 0x259F, 0x11CF, [0xA3, 0x1A, 0x00, 0xAA, 0x00, 0xB9, 0x33, 0x56]}; enum IID IID_IDirect3DRefDevice = {0x50936643, 0x13E9, 0x11D1, [0x89, 0xAA, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29]}; enum IID IID_IDirect3DRGBDevice = {0xA4665C60, 0x2673, 0x11CF, [0xA3, 0x1A, 0x00, 0xAA, 0x00, 0xB9, 0x33, 0x56]}; enum IID IID_IDirect3DRM = {0x2BC49361, 0x8327, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRM2 = {0x4516ECC8, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRM3 = {0x4516EC83, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMAnimation = {0xEB16CB0D, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMAnimation2 = {0xFF6B7F77, 0xA40E, 0x11D1, [0x91, 0xF9, 0x00, 0x00, 0xF8, 0x75, 0x8E, 0x66]}; enum IID IID_IDirect3DRMAnimationArray = {0xD5F1CAE0, 0x4BD7, 0x11D1, [0xB9, 0x74, 0x00, 0x60, 0x08, 0x3E, 0x45, 0xF3]}; enum IID IID_IDirect3DRMAnimationSet = {0xEB16CB0E, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMAnimationSet2 = {0xFF6B7F79, 0xA40E, 0x11D1, [0x91, 0xF9, 0x00, 0x00, 0xF8, 0x75, 0x8E, 0x66]}; enum IID IID_IDirect3DRMClippedVisual = {0x5434E733, 0x6D66, 0x11D1, [0xBB, 0x0B, 0x00, 0x00, 0xF8, 0x75, 0x86, 0x5A]}; enum IID IID_IDirect3DRMDevice = {0xE9E19280, 0x6E05, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMDevice2 = {0x4516EC78, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMDevice3 = {0x549F498B, 0xBFEB, 0x11D1, [0x8E, 0xD8, 0x00, 0xA0, 0xC9, 0x67, 0xA4, 0x82]}; enum IID IID_IDirect3DRMDeviceArray = {0xEB16CB10, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMFace = {0xEB16CB07, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMFace2 = {0x4516EC81, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMFaceArray = {0xEB16CB17, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMFrame = {0xEB16CB03, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMFrame2 = {0xC3DFBD60, 0x3988, 0x11D0, [0x9E, 0xC2, 0x00, 0x00, 0xC0, 0x29, 0x1A, 0xC3]}; enum IID IID_IDirect3DRMFrame3 = {0xFF6B7F70, 0xA40E, 0x11D1, [0x91, 0xF9, 0x00, 0x00, 0xF8, 0x75, 0x8E, 0x66]}; enum IID IID_IDirect3DRMFrameArray = {0xEB16CB12, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMInterpolator = {0x242F6BC1, 0x3849, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMLight = {0xEB16CB08, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMLightArray = {0xEB16CB14, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMMaterial = {0xEB16CB0B, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMMaterial2 = {0xFF6B7F75, 0xA40E, 0x11D1, [0x91, 0xF9, 0x00, 0x00, 0xF8, 0x75, 0x8E, 0x66]}; enum IID IID_IDirect3DRMMesh = {0xA3A80D01, 0x6E12, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMMeshBuilder = {0xA3A80D02, 0x6E12, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMMeshBuilder2 = {0x4516EC77, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMMeshBuilder3 = {0x4516EC82, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMObject = {0xEB16CB00, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMObject2 = {0x4516EC7C, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMObjectArray = {0x242F6BC2, 0x3849, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMPicked2Array = {0x4516EC7B, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMPickedArray = {0xEB16CB16, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMProgressiveMesh = {0x4516EC79, 0x8F20, 0x11D0, [0x9B, 0x6D, 0x00, 0x00, 0xC0, 0x78, 0x1B, 0xC3]}; enum IID IID_IDirect3DRMShadow = {0xAF359780, 0x6BA3, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMShadow2 = {0x86B44E25, 0x9C82, 0x11D1, [0xBB, 0x0B, 0x00, 0xA0, 0xC9, 0x81, 0xA0, 0xA6]}; enum IID IID_IDirect3DRMTexture = {0xEB16CB09, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMTexture2 = {0x120F30C0, 0x1629, 0x11D0, [0x94, 0x1C, 0x00, 0x80, 0xC8, 0x0C, 0xFA, 0x7B]}; enum IID IID_IDirect3DRMTexture3 = {0xFF6B7F73, 0xA40E, 0x11D1, [0x91, 0xF9, 0x00, 0x00, 0xF8, 0x75, 0x8E, 0x66]}; enum IID IID_IDirect3DRMUserVisual = {0x59163DE0, 0x6D43, 0x11CF, [0xAC, 0x4A, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMViewport = {0xEB16CB02, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMViewport2 = {0x4A1B1BE6, 0xBFED, 0x11D1, [0x8E, 0xD8, 0x00, 0xA0, 0xC9, 0x67, 0xA4, 0x82]}; enum IID IID_IDirect3DRMViewportArray = {0xEB16CB11, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMVisual = {0xEB16CB04, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMVisualArray = {0xEB16CB13, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMWinDevice = {0xC5016CC0, 0xD273, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DRMWrap = {0xEB16CB0A, 0xD271, 0x11CE, [0xAC, 0x48, 0x00, 0x00, 0xC0, 0x38, 0x25, 0xA1]}; enum IID IID_IDirect3DTexture = {0x2CDCD9E0, 0x25A0, 0x11CF, [0xA3, 0x1A, 0x00, 0xAA, 0x00, 0xB9, 0x33, 0x56]}; enum IID IID_IDirect3DTexture2 = {0x93281502, 0x8CF8, 0x11D0, [0x89, 0xAB, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29]}; enum IID IID_IDirect3DTnLHalDevice = {0xF5049E78, 0x4861, 0x11D2, [0xA4, 0x07, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID IID_IDirect3DVertexBuffer = {0x7A503555, 0x4A83, 0x11D1, [0xA5, 0xDB, 0x00, 0xA0, 0xC9, 0x03, 0x67, 0xF8]}; enum IID IID_IDirect3DVertexBuffer7 = {0xF5049E7D, 0x4861, 0x11D2, [0xA4, 0x07, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID IID_IDirect3DViewport = {0x4417C146, 0x33AD, 0x11CF, [0x81, 0x6F, 0x00, 0x00, 0xC0, 0x20, 0x15, 0x6E]}; enum IID IID_IDirect3DViewport2 = {0x93281500, 0x8CF8, 0x11D0, [0x89, 0xAB, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29]}; enum IID IID_IDirect3DViewport3 = {0xB0AB3B61, 0x33D7, 0x11D1, [0xA9, 0x81, 0x00, 0xC0, 0x4F, 0xD7, 0xB1, 0x74]}; enum IID IID_IDirectDraw = {0x6C14DB80, 0xA733, 0x11CE, [0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60]}; enum IID IID_IDirectDraw2 = {0xB3A6F3E0, 0x2B43, 0x11CF, [0xA2, 0xDE, 0x00, 0xAA, 0x00, 0xB9, 0x33, 0x56]}; enum IID IID_IDirectDraw4 = {0x9C59509A, 0x39BD, 0x11D1, [0x8C, 0x4A, 0x00, 0xC0, 0x4F, 0xD9, 0x30, 0xC5]}; enum IID IID_IDirectDraw7 = {0x15E65EC0, 0x3B9C, 0x11D2, [0xB9, 0x2F, 0x00, 0x60, 0x97, 0x97, 0xEA, 0x5B]}; enum IID IID_IDirectDrawClipper = {0x6C14DB85, 0xA733, 0x11CE, [0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60]}; enum IID IID_IDirectDrawColorControl = {0x4B9F0EE0, 0x0D7E, 0x11D0, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID IID_IDirectDrawFactory2 = {0x89B2C488, 0x4AF4, 0x11D1, [0x8C, 0x4C, 0x00, 0xC0, 0x4F, 0xD9, 0x30, 0xC5]}; enum IID IID_IDirectDrawGammaControl = {0x69C11C3E, 0xB46B, 0x11D1, [0xAD, 0x7A, 0x00, 0xC0, 0x4F, 0xC2, 0x9B, 0x4E]}; enum IID IID_IDirectDrawKernel = {0x8D56C120, 0x6A08, 0x11D0, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID IID_IDirectDrawOptSurface = {0x51191F1E, 0x4F2B, 0x11D1, [0x8C, 0xC3, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0xA8]}; enum IID IID_IDirectDrawPalette = {0x6C14DB84, 0xA733, 0x11CE, [0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60]}; enum IID IID_IDirectDrawPalette2 = {0xC03C477E, 0x6519, 0x11D1, [0x8C, 0x52, 0x00, 0xC0, 0x4F, 0xD9, 0x30, 0xC5]}; enum IID IID_IDirectDrawSurface = {0x6C14DB81, 0xA733, 0x11CE, [0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60]}; enum IID IID_IDirectDrawSurface2 = {0x57805885, 0x6EEC, 0x11CF, [0x94, 0x41, 0xA8, 0x23, 0x03, 0xC1, 0x0E, 0x27]}; enum IID IID_IDirectDrawSurface3 = {0xDA044E00, 0x69B2, 0x11D0, [0xA1, 0xD5, 0x00, 0xAA, 0x00, 0xB8, 0xDF, 0xBB]}; enum IID IID_IDirectDrawSurface4 = {0x0B2B8630, 0xAD35, 0x11D0, [0x8E, 0xA6, 0x00, 0x60, 0x97, 0x97, 0xEA, 0x5B]}; enum IID IID_IDirectDrawSurface7 = {0x06675A80, 0x3B9B, 0x11D2, [0xB9, 0x2F, 0x00, 0x60, 0x97, 0x97, 0xEA, 0x5B]}; enum IID IID_IDirectDrawSurfaceKernel = {0x60755DA0, 0x6A40, 0x11D0, [0x9B, 0x06, 0x00, 0xA0, 0xC9, 0x03, 0xA3, 0xB8]}; enum IID IID_IDirectDrawVideoAccelerator = {0xC9B2D740, 0x3356, 0x11D1, [0x8F, 0xCF, 0x00, 0xC0, 0x4F, 0xC2, 0x9B, 0x4E]}; enum IID IID_IDirectDrawVideoPort = {0xB36D93E0, 0x2B43, 0x11CF, [0xA2, 0xDE, 0x00, 0xAA, 0x00, 0xB9, 0x33, 0x56]}; enum IID IID_IDirectInput2A = {0x5944E662, 0xAA8A, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IDirectInput2W = {0x5944E663, 0xAA8A, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IDirectInput7A = {0x9A4CB684, 0x236D, 0x11D3, [0x8E, 0x9D, 0x00, 0xC0, 0x4F, 0x68, 0x44, 0xAE]}; enum IID IID_IDirectInput7W = {0x9A4CB685, 0x236D, 0x11D3, [0x8E, 0x9D, 0x00, 0xC0, 0x4F, 0x68, 0x44, 0xAE]}; enum IID IID_IDirectInputA = {0x89521360, 0xAA8A, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IDirectInputDevice2A = {0x5944E682, 0xC92E, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IDirectInputDevice2W = {0x5944E683, 0xC92E, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IDirectInputDevice7A = {0x57D7C6BC, 0x2356, 0x11D3, [0x8E, 0x9D, 0x00, 0xC0, 0x4F, 0x68, 0x44, 0xAE]}; enum IID IID_IDirectInputDevice7W = {0x57D7C6BD, 0x2356, 0x11D3, [0x8E, 0x9D, 0x00, 0xC0, 0x4F, 0x68, 0x44, 0xAE]}; enum IID IID_IDirectInputDeviceA = {0x5944E680, 0xC92E, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IDirectInputDeviceW = {0x5944E681, 0xC92E, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IDirectInputEffect = {0xE7E1F7C0, 0x88D2, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID IID_IDirectInputEffectDriver = {0x02538130, 0x898F, 0x11D0, [0x9A, 0xD0, 0x00, 0xA0, 0xC9, 0xA0, 0x6E, 0x35]}; enum IID IID_IDirectInputJoyConfig = {0x1DE12AB1, 0xC9F5, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IDirectInputPIDDriver = {0xEEC6993A, 0xB3FD, 0x11D2, [0xA9, 0x16, 0x00, 0xC0, 0x4F, 0xB9, 0x86, 0x38]}; enum IID IID_IDirectInputW = {0x89521361, 0xAA8A, 0x11CF, [0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IDirectMusic = {0x6536115A, 0x7B2D, 0x11D2, [0xBA, 0x18, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID IID_IDirectMusic2 = {0x6FC2CAE1, 0xBC78, 0x11D2, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID IID_IDirectMusicBand = {0xD2AC28C0, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicBuffer = {0xD2AC2878, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicChordMap = {0xD2AC28BE, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicCollection = {0xD2AC287C, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicComposer = {0xD2AC28BF, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicDownload = {0xD2AC287B, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicDownloadedInstrument = {0xD2AC287E, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicGetLoader = {0x68A04844, 0xD13D, 0x11D1, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID IID_IDirectMusicGraph = {0x2BEFC277, 0x5497, 0x11D2, [0xBC, 0xCB, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEB]}; enum IID IID_IDirectMusicInstrument = {0xD2AC287D, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicLoader = {0x2FFAACA2, 0x5DCA, 0x11D2, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID IID_IDirectMusicObject = {0xD2AC28B5, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicPerformance = {0x07D43D03, 0x6523, 0x11D2, [0x87, 0x1D, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicPerformance2 = {0x6FC2CAE0, 0xBC78, 0x11D2, [0xAF, 0xA6, 0x00, 0xAA, 0x00, 0x24, 0xD8, 0xB6]}; enum IID IID_IDirectMusicPort = {0x08F2D8C9, 0x37C2, 0x11D2, [0xB9, 0xF9, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID IID_IDirectMusicPortDownload = {0xD2AC287A, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicSegment = {0xF96029A2, 0x4282, 0x11D2, [0x87, 0x17, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicSegment2 = {0xD38894D1, 0xC052, 0x11D2, [0x87, 0x2F, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicSegmentState = {0xA3AFDCC7, 0xD3EE, 0x11D1, [0xBC, 0x8D, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEB]}; enum IID IID_IDirectMusicStyle = {0xD2AC28BD, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicThru = {0xCED153E7, 0x3606, 0x11D2, [0xB9, 0xF9, 0x00, 0x00, 0xF8, 0x75, 0xAC, 0x12]}; enum IID IID_IDirectMusicTool = {0xD2AC28BA, 0xB39B, 0x11D1, [0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectMusicTrack = {0xF96029A1, 0x4282, 0x11D2, [0x87, 0x17, 0x00, 0x60, 0x08, 0x93, 0xB1, 0xBD]}; enum IID IID_IDirectoryObject = {0xE798DE2C, 0x22E4, 0x11D0, [0x84, 0xFE, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IDirectorySchemaMgmt = {0x75DB3B9C, 0xA4D8, 0x11D0, [0xA7, 0x9C, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0xA8]}; enum IID IID_IDirectorySearch = {0x109BA8EC, 0x92F0, 0x11D0, [0xA7, 0x90, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0xA8]}; enum IID IID_IDirectPlay = {0x5454E9A0, 0xDB65, 0x11CE, [0x92, 0x1C, 0x00, 0xAA, 0x00, 0x6C, 0x49, 0x72]}; enum IID IID_IDirectPlay2 = {0x2B74F7C0, 0x9154, 0x11CF, [0xA9, 0xCD, 0x00, 0xAA, 0x00, 0x68, 0x86, 0xE3]}; enum IID IID_IDirectPlay2A = {0x9D460580, 0xA822, 0x11CF, [0x96, 0x0C, 0x00, 0x80, 0xC7, 0x53, 0x4E, 0x82]}; enum IID IID_IDirectPlay3 = {0x133EFE40, 0x32DC, 0x11D0, [0x9C, 0xFB, 0x00, 0xA0, 0xC9, 0x0A, 0x43, 0xCB]}; enum IID IID_IDirectPlay3A = {0x133EFE41, 0x32DC, 0x11D0, [0x9C, 0xFB, 0x00, 0xA0, 0xC9, 0x0A, 0x43, 0xCB]}; enum IID IID_IDirectPlay4 = {0x0AB1C530, 0x4745, 0x11D1, [0xA7, 0xA1, 0x00, 0x00, 0xF8, 0x03, 0xAB, 0xFC]}; enum IID IID_IDirectPlay4A = {0x0AB1C531, 0x4745, 0x11D1, [0xA7, 0xA1, 0x00, 0x00, 0xF8, 0x03, 0xAB, 0xFC]}; enum IID IID_IDirectPlayLobby = {0xAF465C71, 0x9588, 0x11CF, [0xA0, 0x20, 0x00, 0xAA, 0x00, 0x61, 0x57, 0xAC]}; enum IID IID_IDirectPlayLobby2 = {0x0194C220, 0xA303, 0x11D0, [0x9C, 0x4F, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID IID_IDirectPlayLobby2A = {0x1BB4AF80, 0xA303, 0x11D0, [0x9C, 0x4F, 0x00, 0xA0, 0xC9, 0x05, 0x42, 0x5E]}; enum IID IID_IDirectPlayLobby3 = {0x2DB72490, 0x652C, 0x11D1, [0xA7, 0xA8, 0x00, 0x00, 0xF8, 0x03, 0xAB, 0xFC]}; enum IID IID_IDirectPlayLobby3A = {0x2DB72491, 0x652C, 0x11D1, [0xA7, 0xA8, 0x00, 0x00, 0xF8, 0x03, 0xAB, 0xFC]}; enum IID IID_IDirectPlayLobbyA = {0x26C66A70, 0xB367, 0x11CF, [0xA0, 0x24, 0x00, 0xAA, 0x00, 0x61, 0x57, 0xAC]}; enum IID IID_IDirectSound = {0x279AFA83, 0x4981, 0x11CE, [0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60]}; enum IID IID_IDirectSound3DBuffer = {0x279AFA86, 0x4981, 0x11CE, [0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60]}; enum IID IID_IDirectSound3DListener = {0x279AFA84, 0x4981, 0x11CE, [0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60]}; enum IID IID_IDirectSoundBuffer = {0x279AFA85, 0x4981, 0x11CE, [0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60]}; enum IID IID_IDirectSoundCapture = {0xB0210781, 0x89CD, 0x11D0, [0xAF, 0x08, 0x00, 0xA0, 0xC9, 0x25, 0xCD, 0x16]}; enum IID IID_IDirectSoundCaptureBuffer = {0xB0210782, 0x89CD, 0x11D0, [0xAF, 0x08, 0x00, 0xA0, 0xC9, 0x25, 0xCD, 0x16]}; enum IID IID_IDirectSoundNotify = {0xB0210783, 0x89CD, 0x11D0, [0xAF, 0x08, 0x00, 0xA0, 0xC9, 0x25, 0xCD, 0x16]}; enum IID IID_IDirectWriterLock = {0x0E6D4D92, 0x6738, 0x11CF, [0x96, 0x08, 0x00, 0xAA, 0x00, 0x68, 0x0D, 0xB4]}; enum IID IID_IDirectXFile = {0x3D82AB40, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID IID_IDirectXFileBinary = {0x3D82AB46, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID IID_IDirectXFileData = {0x3D82AB44, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID IID_IDirectXFileDataReference = {0x3D82AB45, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID IID_IDirectXFileEnumObject = {0x3D82AB41, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID IID_IDirectXFileObject = {0x3D82AB43, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID IID_IDirectXFileSaveObject = {0x3D82AB42, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID IID_IDiscardableBrowserProperty = {0x49C3DE7C, 0xD329, 0x11D0, [0xAB, 0x73, 0x00, 0xC0, 0x4F, 0xC3, 0x3E, 0x80]}; enum IID IID_IDiscMaster = {0x520CCA62, 0x51A5, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID IID_IDiscMasterProgressEvents = {0xEC9E51C1, 0x4E5D, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID IID_IDiscRecorder = {0x85AC9776, 0xCA88, 0x4CF2, [0x89, 0x4E, 0x09, 0x59, 0x8C, 0x07, 0x8A, 0x41]}; enum IID IID_IDiscStash = {0x520CCA64, 0x51A5, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID IID_IDispatch = {0x00020400, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDispatchEx = {0xA6EF9860, 0xC720, 0x11D0, [0x93, 0x37, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IDispError = {0xA6EF9861, 0xC720, 0x11D0, [0x93, 0x37, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IDisplayPointer = {0x3050F69E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IDisplayServices = {0x3050F69D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IDithererImpl = {0x7C48E840, 0x3910, 0x11D0, [0x86, 0xFC, 0x00, 0xA0, 0xC9, 0x13, 0xF7, 0x50]}; enum IID IID_IDocHostShowUI = {0xC4D244B0, 0xD43E, 0x11CF, [0x89, 0x3B, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x1A]}; enum IID IID_IDocHostUIHandler = {0xBD3F23C0, 0xD43E, 0x11CF, [0x89, 0x3B, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x1A]}; enum IID IID_IDocHostUIHandler2 = {0x3050F6D0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IDockingWindow = {0x012DD920, 0x7B26, 0x11D0, [0x8C, 0xA9, 0x00, 0xA0, 0xC9, 0x2D, 0xBF, 0xE8]}; enum IID IID_IDockingWindowFrame = {0x47D2657A, 0x7B27, 0x11D0, [0x8C, 0xA9, 0x00, 0xA0, 0xC9, 0x2D, 0xBF, 0xE8]}; enum IID IID_IDockingWindowSite = {0x2A342FC2, 0x7B26, 0x11D0, [0x8C, 0xA9, 0x00, 0xA0, 0xC9, 0x2D, 0xBF, 0xE8]}; enum IID IID_IDoTask = {0x0230C9F8, 0xEE7F, 0x4307, [0x98, 0xDB, 0x72, 0x6E, 0xBC, 0xAE, 0x55, 0xD6]}; enum IID IID_IDownloadBehavior = {0x3050F5BD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IDownloadManager = {0x988934A4, 0x064B, 0x11D3, [0xBB, 0x80, 0x00, 0x10, 0x4B, 0x35, 0xE7, 0xF9]}; enum IID IID_IDownloadNotify = {0xCAEB5D28, 0xAE4C, 0x11D1, [0xBA, 0x40, 0x00, 0xC0, 0x4F, 0xB9, 0x2D, 0x79]}; enum IID IID_IDragSourceHelper = {0xDE5BF786, 0x477A, 0x11D2, [0x83, 0x9D, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0]}; enum IID IID_IDropSource = {0x00000121, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDropTarget = {0x00000122, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IDropTargetHelper = {0x4657278B, 0x411B, 0x11D2, [0x83, 0x9A, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0]}; enum IID IID_IDsBrowseDomainTree = {0x7CABCF1E, 0x78F5, 0x11D2, [0x96, 0x0C, 0x00, 0xC0, 0x4F, 0xA3, 0x1A, 0x86]}; enum IID IID_IDsQueryColumnHandler = {0xC072999E, 0xFA49, 0x11D1, [0xA0, 0xAF, 0x00, 0xC0, 0x4F, 0xA3, 0x1A, 0x86]}; enum IID IID_IDummy = {0x0D7CA54A, 0xD252, 0x4FCB, [0x91, 0x04, 0xF6, 0xDD, 0xD3, 0x10, 0xB3, 0xF9]}; enum IID IID_IDummyHICONIncluder = {0x947990DE, 0xCC28, 0x11D2, [0xA0, 0xF7, 0x00, 0x80, 0x5F, 0x85, 0x8F, 0xB1]}; enum IID IID_IDX2D = {0x9EFD02A9, 0xA996, 0x11D1, [0x81, 0xC9, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDX2DDebug = {0x03BB2457, 0xA279, 0x11D1, [0x81, 0xC6, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDXARGBReadPtr = {0xEAAAC2D6, 0xC290, 0x11D1, [0x90, 0x5D, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXARGBReadWritePtr = {0xEAAAC2D7, 0xC290, 0x11D1, [0x90, 0x5D, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXARGBSurfaceInit = {0x9EA3B63A, 0xC37D, 0x11D1, [0x90, 0x5E, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXBaseObject = {0x17B59B2B, 0x9CC8, 0x11D1, [0x90, 0x53, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXBasicImage = {0x16B280C7, 0xEE70, 0x11D1, [0x90, 0x66, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXDCLock = {0x0F619456, 0xCF39, 0x11D1, [0x90, 0x5E, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXDLUTBuilder = {0x73068231, 0x35EE, 0x11D1, [0x81, 0xA1, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDXDMapper = {0x7FD9088B, 0x35ED, 0x11D1, [0x81, 0xA1, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDXEffect = {0xE31FB81B, 0x1335, 0x11D1, [0x81, 0x89, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDXGradient = {0xB2024B51, 0xEE77, 0x11D1, [0x90, 0x66, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXGradient2 = {0xD0EF2A80, 0x61DC, 0x11D2, [0xB2, 0xEB, 0x00, 0xA0, 0xC9, 0x36, 0xB2, 0x12]}; enum IID IID_IDXLookupTable = {0x01BAFC7F, 0x9E63, 0x11D1, [0x90, 0x53, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXLUTBuilder = {0xF4370FC1, 0xCADB, 0x11D0, [0xB5, 0x2C, 0x00, 0xA0, 0xC9, 0x05, 0x43, 0x73]}; enum IID IID_IDXMapper = {0x555278E5, 0x05DB, 0x11D1, [0x88, 0x3A, 0x3C, 0x8B, 0x00, 0xC1, 0x00, 0x00]}; enum IID IID_IDXPixelate = {0xD33E180F, 0xFBE9, 0x11D1, [0x90, 0x6A, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXRasterizer = {0x9EA3B635, 0xC37D, 0x11D1, [0x90, 0x5E, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXRawSurface = {0x09756C8A, 0xD96A, 0x11D1, [0x90, 0x62, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXSurface = {0xB39FD73F, 0xE139, 0x11D1, [0x90, 0x65, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXSurfaceFactory = {0x144946F5, 0xC4D4, 0x11D1, [0x81, 0xD1, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDXSurfaceInit = {0x9EA3B639, 0xC37D, 0x11D1, [0x90, 0x5E, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXSurfaceModifier = {0x9EA3B637, 0xC37D, 0x11D1, [0x90, 0x5E, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXSurfacePick = {0x30A5FB79, 0xE11F, 0x11D1, [0x90, 0x64, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXTAlpha = {0x1D4637E0, 0x383C, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID IID_IDXTAlphaImageLoader = {0xA5F2D3E8, 0x7A7E, 0x48E5, [0xBC, 0x75, 0x40, 0x79, 0x0B, 0xE4, 0xA9, 0x41]}; enum IID IID_IDXTaskManager = {0x254DBBC1, 0xF922, 0x11D0, [0x88, 0x3A, 0x3C, 0x8B, 0x00, 0xC1, 0x00, 0x00]}; enum IID IID_IDXTBindHost = {0xD26BCE55, 0xE9DC, 0x11D1, [0x90, 0x66, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXTCheckerBoard = {0xAD3C2576, 0x117C, 0x4510, [0x84, 0xDD, 0xB6, 0x68, 0x97, 0x1D, 0xCF, 0xD1]}; enum IID IID_IDXTChroma = {0x1D4637E2, 0x383C, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID IID_IDXTClipOrigin = {0xEE1663D8, 0x0988, 0x4C48, [0x9F, 0xD6, 0xDB, 0x44, 0x50, 0x88, 0x56, 0x68]}; enum IID IID_IDXTComposite = {0x9A43A843, 0x0831, 0x11D1, [0x81, 0x7F, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDXTConvolution = {0x7BA7F8AF, 0xE5EA, 0x11D1, [0x81, 0xDD, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDXTDropShadow = {0x1D4637E3, 0x383C, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID IID_IDXTFade = {0x16B280C4, 0xEE70, 0x11D1, [0x90, 0x66, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXTFilter = {0x6187E5A2, 0xA445, 0x4608, [0x8F, 0xC0, 0xBE, 0x7A, 0x6C, 0x8D, 0xB3, 0x86]}; enum IID IID_IDXTFilterBehavior = {0x14D7DDDD, 0xACA2, 0x4E45, [0x95, 0x04, 0x38, 0x08, 0xAB, 0xEB, 0x4F, 0x92]}; enum IID IID_IDXTFilterBehaviorSite = {0x909B23C2, 0x9018, 0x499F, [0xA8, 0x6D, 0x4E, 0x7D, 0xA9, 0x37, 0xE9, 0x31]}; enum IID IID_IDXTFilterCollection = {0x22B07B33, 0x8BFB, 0x49D4, [0x9B, 0x90, 0x09, 0x38, 0x37, 0x0C, 0x90, 0x19]}; enum IID IID_IDXTFilterController = {0x5CF315F2, 0x273D, 0x47B6, [0xB9, 0xED, 0xF7, 0x5D, 0xC3, 0xB0, 0x15, 0x0B]}; enum IID IID_IDXTGlow = {0x1D4637E4, 0x383C, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID IID_IDXTGradientD = {0x623E2881, 0xFC0E, 0x11D1, [0x9A, 0x77, 0x00, 0x00, 0xF8, 0x75, 0x6A, 0x10]}; enum IID IID_IDXTGridSize = {0xD6BBE91E, 0xFF60, 0x11D2, [0x8F, 0x6E, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x74]}; enum IID IID_IDXTICMFilter = {0x734321ED, 0x1E7B, 0x4E1C, [0xBB, 0xFA, 0x89, 0xC8, 0x19, 0x80, 0x0E, 0x2F]}; enum IID IID_IDXTLabel = {0xC0C17F0E, 0xAE41, 0x11D1, [0x9A, 0x3B, 0x00, 0x00, 0xF8, 0x75, 0x6A, 0x10]}; enum IID IID_IDXTLight = {0xF9EFBEC1, 0x4302, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID IID_IDXTMask = {0xA1067146, 0xB063, 0x47D7, [0xA5, 0x4A, 0x2C, 0x23, 0x09, 0xE9, 0x88, 0x9D]}; enum IID IID_IDXTMatrix = {0xAC66A493, 0x0F0C, 0x4C76, [0x82, 0x5C, 0x9D, 0x68, 0xBE, 0xDE, 0x91, 0x88]}; enum IID IID_IDXTMetaBurnFilm = {0x107045D0, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaCenterPeel = {0xAA0D4D0B, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID IID_IDXTMetaColorFade = {0x2A54C907, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaFlowMotion = {0x2A54C90A, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaGriddler = {0x2A54C910, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaGriddler2 = {0x2A54C912, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaJaws = {0x2A54C903, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaLightWipe = {0x107045C7, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaLiquid = {0xAA0D4D09, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID IID_IDXTMetaPageTurn = {0xAA0D4D07, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID IID_IDXTMetaPeelPiece = {0xAA0D4D0F, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID IID_IDXTMetaPeelSmall = {0xAA0D4D0D, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID IID_IDXTMetaPeelSplit = {0xAA0D4D11, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID IID_IDXTMetaRadialScaleWipe = {0x107045C9, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaRipple = {0xAA0D4D02, 0x06A3, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID IID_IDXTMetaRoll = {0x9C61F46D, 0x0530, 0x11D2, [0x8F, 0x98, 0x00, 0xC0, 0x4F, 0xB9, 0x2E, 0xB7]}; enum IID IID_IDXTMetaThreshold = {0x2A54C914, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaTwister = {0x107045CE, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaVacuum = {0x2A54C90C, 0x07AA, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaWater = {0x107045C4, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaWhiteOut = {0x107045CB, 0x06E0, 0x11D2, [0x8D, 0x6D, 0x00, 0xC0, 0x4F, 0x8E, 0xF8, 0xE0]}; enum IID IID_IDXTMetaWormHole = {0x0E6AE021, 0x0C83, 0x11D2, [0x8C, 0xD4, 0x00, 0x10, 0x4B, 0xC7, 0x5D, 0x9A]}; enum IID IID_IDXTMotionBlur = {0x089057BE, 0xD3F5, 0x4A2C, [0xB1, 0x0A, 0xA5, 0x13, 0x01, 0x84, 0xA0, 0xF7]}; enum IID IID_IDXTRandomBars = {0x8A6D2022, 0x4A8F, 0x4EB9, [0xBB, 0x25, 0xAA, 0x05, 0x20, 0x1F, 0x9C, 0x84]}; enum IID IID_IDXTransform = {0x30A5FB78, 0xE11F, 0x11D1, [0x90, 0x64, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXTransformFactory = {0x6A950B2B, 0xA971, 0x11D1, [0x81, 0xC8, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDXTRedirect = {0x02F5140B, 0x626F, 0x4019, [0x9C, 0x9E, 0x2D, 0xAA, 0x1E, 0x93, 0xE8, 0xFC]}; enum IID IID_IDXTRedirectFilterInit = {0xD1A57094, 0x21F7, 0x4E6C, [0x93, 0xE5, 0xF5, 0xF7, 0x7F, 0x74, 0x82, 0x93]}; enum IID IID_IDXTRevealTrans = {0xB8095006, 0xA128, 0x464B, [0x8B, 0x2D, 0x90, 0x58, 0x0A, 0xEE, 0x2B, 0x05]}; enum IID IID_IDXTScale = {0xB39FD742, 0xE139, 0x11D1, [0x90, 0x65, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXTScaleOutput = {0xB2024B50, 0xEE77, 0x11D1, [0x90, 0x66, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D]}; enum IID IID_IDXTShadow = {0x1D4637E6, 0x383C, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID IID_IDXTStrips = {0xA83C9B5C, 0xFB11, 0x4AF5, [0x8F, 0x65, 0xD0, 0x3F, 0x15, 0x1D, 0x3E, 0xD5]}; enum IID IID_IDXTWave = {0x1D4637E7, 0x383C, 0x11D2, [0x95, 0x2A, 0x00, 0xC0, 0x4F, 0xA3, 0x4F, 0x05]}; enum IID IID_IDXTWipe = {0xAF279B2F, 0x86EB, 0x11D1, [0x81, 0xBF, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID IID_IDXTWipe2 = {0xE1FF8091, 0x442B, 0x4801, [0x88, 0xB6, 0x2B, 0x47, 0xB1, 0x61, 0x1F, 0xD2]}; enum IID IID_IDynamicPortMapping = {0x4FC80282, 0x23B6, 0x4378, [0x9A, 0x27, 0xCD, 0x8F, 0x17, 0xC9, 0x40, 0x0C]}; enum IID IID_IDynamicPortMappingCollection = {0xB60DE00F, 0x156E, 0x4E8D, [0x9E, 0xC1, 0x3A, 0x23, 0x42, 0xC1, 0x08, 0x99]}; enum IID IID_IEditDebugServices = {0x3050F60B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementAdorner = {0x3050F607, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehavior = {0x3050F425, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorCategory = {0x3050F4ED, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorFactory = {0x3050F429, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorFocus = {0x3050F6B6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorLayout = {0x3050F6BA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorLayout2 = {0x3050F846, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorRender = {0x3050F4AA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorSite = {0x3050F427, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorSiteCategory = {0x3050F4EE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorSiteLayout = {0x3050F6B7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorSiteLayout2 = {0x3050F847, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorSiteOM = {0x3050F489, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorSiteOM2 = {0x3050F659, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorSiteRender = {0x3050F4A7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorSubmit = {0x3050F646, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementBehaviorUI = {0x3050F4BF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementNamespace = {0x3050F671, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementNamespaceFactory = {0x3050F672, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementNamespaceFactory2 = {0x3050F805, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementNamespaceFactoryCallback = {0x3050F7FD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementNamespacePrivate = {0x3050F7FF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementNamespaceTable = {0x3050F670, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IElementSegment = {0x3050F68F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IEmptyVolumeCache = {0x8FCE5227, 0x04DA, 0x11D1, [0xA0, 0x04, 0x00, 0x80, 0x5F, 0x8A, 0xBE, 0x06]}; enum IID IID_IEmptyVolumeCache2 = {0x02B7E3BA, 0x4DB3, 0x11D2, [0xB2, 0xD9, 0x00, 0xC0, 0x4F, 0x8E, 0xEC, 0x8C]}; enum IID IID_IEmptyVolumeCacheCallBack = {0x6E793361, 0x73C6, 0x11D0, [0x84, 0x69, 0x00, 0xAA, 0x00, 0x44, 0x29, 0x01]}; enum IID IID_IEncodingFilterFactory = {0x70BDDE00, 0xC18E, 0x11D0, [0xA9, 0xCE, 0x00, 0x60, 0x97, 0x94, 0x23, 0x11]}; enum IID IID_IEnroll = {0xACAA7838, 0x4585, 0x11D1, [0xAB, 0x57, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1]}; enum IID IID_IEnroll2 = {0xC080E199, 0xB7DF, 0x11D2, [0xA4, 0x21, 0x00, 0xC0, 0x4F, 0x79, 0xFE, 0x8E]}; enum IID IID_IEnroll4 = {0xF8053FE5, 0x78F4, 0x448F, [0xA0, 0xDB, 0x41, 0xD6, 0x1B, 0x73, 0x44, 0x6B]}; enum IID IID_IEntryID = {0xE4D19810, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID IID_IEnumACDGroup = {0x5AFC3157, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_IEnumACString = {0x8E74C210, 0xCF9D, 0x4EAF, [0xA4, 0x03, 0x73, 0x56, 0x42, 0x8F, 0x0A, 0x5A]}; enum IID IID_IEnumAdapterInfo = {0xA23F9D11, 0x714C, 0x41FE, [0x84, 0x71, 0xFF, 0xB1, 0x9B, 0xC2, 0x84, 0x54]}; enum IID IID_IEnumAddress = {0x1666FCA1, 0x9363, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_IEnumAgent = {0x5AFC314D, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_IEnumAgentHandler = {0x587E8C28, 0x9802, 0x11D1, [0xA0, 0xA4, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_IEnumAgentSession = {0x5AFC314E, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_IEnumBackgroundCopyFiles = {0xCA51E165, 0xC365, 0x424C, [0x8D, 0x41, 0x24, 0xAA, 0xA4, 0xFF, 0x3C, 0x40]}; enum IID IID_IEnumBackgroundCopyGroups = {0xD993E603, 0x4AA4, 0x47C5, [0x86, 0x65, 0xC2, 0x0D, 0x39, 0xC2, 0xBA, 0x4F]}; enum IID IID_IEnumBackgroundCopyJobs = {0x1AF4F612, 0x3B71, 0x466F, [0x8F, 0x58, 0x7B, 0x6F, 0x73, 0xAC, 0x57, 0xAD]}; enum IID IID_IEnumBackgroundCopyJobs1 = {0x8BAEBA9D, 0x8F1C, 0x42C4, [0xB8, 0x2C, 0x09, 0xAE, 0x79, 0x98, 0x0D, 0x25]}; enum IID IID_IEnumBstr = {0x35372049, 0x0BC6, 0x11D2, [0xA0, 0x33, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_IEnumCall = {0xAE269CF6, 0x935E, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_IEnumCallback = {0x00000108, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumCallHub = {0xA3C15450, 0x5B92, 0x11D1, [0x8F, 0x4E, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_IEnumCallingCard = {0x0C4D8F02, 0x8DDB, 0x11D1, [0xA0, 0x9E, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_IEnumCATEGORYINFO = {0x0002E011, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumChannels = {0xA4C65425, 0x0F82, 0x11D1, [0x90, 0xC3, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x68]}; enum IID IID_IEnumClusCfgIPAddresses = {0xBD5F35BA, 0x0BC0, 0x455F, [0x92, 0x6D, 0xC3, 0xD3, 0x56, 0x41, 0x94, 0x86]}; enum IID IID_IEnumClusCfgManagedResources = {0x7DBE11EB, 0xA5DF, 0x4534, [0xAB, 0xF6, 0x8B, 0xAC, 0x7B, 0x53, 0xFC, 0x95]}; enum IID IID_IEnumClusCfgNetworks = {0xCF3FAED8, 0x1322, 0x4BCB, [0x99, 0x23, 0xB5, 0xB7, 0x45, 0xA6, 0x9E, 0x36]}; enum IID IID_IEnumClusCfgPartitions = {0x4440BB6A, 0xB0AC, 0x479D, [0xB5, 0x34, 0x72, 0x65, 0xA3, 0x1D, 0x6C, 0x55]}; enum IID IID_IEnumCodePage = {0x275C23E3, 0x3747, 0x11D0, [0x9F, 0xEA, 0x00, 0xAA, 0x00, 0x3F, 0x86, 0x46]}; enum IID IID_IEnumConnectionPoints = {0xB196B285, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IEnumConnections = {0xB196B287, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IEnumCookies = {0x5E3E482E, 0x3C22, 0x482C, [0xB6, 0x64, 0x69, 0x30, 0x51, 0xAD, 0x0A, 0x5D]}; enum IID IID_IEnumDebugApplicationNodes = {0x51973C3A, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IEnumDebugCodeContexts = {0x51973C1D, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IEnumDebugExpressionContexts = {0x51973C40, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IEnumDebugExtendedPropertyInfo = {0x51973C53, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IEnumDebugPropertyInfo = {0x51973C51, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IEnumDebugStackFrames = {0x51973C1E, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IEnumDebugStackFrames64 = {0x0DC38853, 0xC1B0, 0x4176, [0xA9, 0x84, 0xB2, 0x98, 0x36, 0x10, 0x27, 0xAF]}; enum IID IID_IEnumDialableAddrs = {0x34621D70, 0x6CFF, 0x11D1, [0xAF, 0xF7, 0x00, 0xC0, 0x4F, 0xC3, 0x1F, 0xEE]}; enum IID IID_IEnumDirectory = {0x34621D6D, 0x6CFF, 0x11D1, [0xAF, 0xF7, 0x00, 0xC0, 0x4F, 0xC3, 0x1F, 0xEE]}; enum IID IID_IEnumDirectoryObject = {0x06C9B64A, 0x306D, 0x11D1, [0x97, 0x74, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_IEnumDiscMasterFormats = {0xDDF445E1, 0x54BA, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID IID_IEnumDiscRecorders = {0x9B1921E1, 0x54AC, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID IID_IEnumExtraSearch = {0x0E700BE1, 0x9DB6, 0x11D1, [0xA1, 0xCE, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13]}; enum IID IID_IEnumFORMATETC = {0x00000103, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumGeneric = {0x00000106, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumGUID = {0x0002E000, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumHLITEM = {0x79EAC9C6, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IEnumHNetApplicationProtocols = {0x85D18B7B, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IEnumHNetBridgedConnections = {0x85D18B7D, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IEnumHNetBridges = {0x85D18B77, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IEnumHNetFirewalledConnections = {0x85D18B78, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IEnumHNetIcsPrivateConnections = {0x85D18B7A, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IEnumHNetIcsPublicConnections = {0x85D18B79, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IEnumHNetPortMappingBindings = {0x85D18B81, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IEnumHNetPortMappingProtocols = {0x85D18B7C, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IEnumHolder = {0x00000107, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumIDList = {0x000214F2, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumInputContext = {0x09B5EAB0, 0xF997, 0x11D1, [0x93, 0xD4, 0x00, 0x60, 0xB0, 0x67, 0xB8, 0x6E]}; enum IID IID_IEnumItemProperties = {0xF72C8D96, 0x6DBD, 0x11D1, [0xA1, 0xE8, 0x00, 0xC0, 0x4F, 0xC2, 0xFB, 0xE1]}; enum IID IID_IEnumLocation = {0x0C4D8F01, 0x8DDB, 0x11D1, [0xA0, 0x9E, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_IEnumMcastScope = {0xDF0DAF09, 0xA289, 0x11D1, [0x86, 0x97, 0x00, 0x60, 0x08, 0xB0, 0xE5, 0xD2]}; enum IID IID_IEnumMedia = {0xCA8397BE, 0x2FA4, 0x11D1, [0x97, 0x74, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_IEnumMoniker = {0x00000102, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumNetCfgBindingInterface = {0xC0E8AE90, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IEnumNetCfgBindingPath = {0xC0E8AE91, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IEnumNetCfgComponent = {0xC0E8AE92, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IEnumNetConnection = {0xC08956A0, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IEnumNetSharingEveryConnection = {0xC08956B8, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IEnumNetSharingPortMapping = {0xC08956B0, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IEnumNetSharingPrivateConnection = {0xC08956B5, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IEnumNetSharingPublicConnection = {0xC08956B4, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IEnumNodes = {0xC477E363, 0xAF0A, 0x4203, [0xA6, 0x04, 0x45, 0xCD, 0x60, 0x7D, 0xD7, 0x10]}; enum IID IID_IEnumNotification = {0xC733E4A8, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_IEnumNotificationSinkItem = {0xC733E4AA, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_IEnumOleDocumentViews = {0xB722BCC8, 0x4E68, 0x101B, [0xA2, 0xBC, 0x00, 0xAA, 0x00, 0x40, 0x47, 0x70]}; enum IID IID_IEnumOleUndoUnits = {0xB3E7C340, 0xEF97, 0x11CE, [0x9B, 0xC9, 0x00, 0xAA, 0x00, 0x60, 0x8E, 0x01]}; enum IID IID_IEnumOLEVERB = {0x00000104, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumParticipant = {0x0A91B56C, 0x5A35, 0x11D2, [0x95, 0xA0, 0x00, 0xA0, 0x24, 0x4D, 0x22, 0x98]}; enum IID IID_IEnumPhone = {0xF15B7669, 0x4780, 0x4595, [0x8C, 0x89, 0xFB, 0x36, 0x9C, 0x8C, 0xF7, 0xAA]}; enum IID IID_IEnumPluggableSuperclassInfo = {0xE9586A80, 0x89E6, 0x4CFF, [0x93, 0x1D, 0x47, 0x8D, 0x57, 0x51, 0xF4, 0xC0]}; enum IID IID_IEnumPluggableTerminalClassInfo = {0x4567450C, 0xDBEE, 0x4E3F, [0xAA, 0xF5, 0x37, 0xBF, 0x9E, 0xBF, 0x5E, 0x29]}; enum IID IID_IEnumPrivacyRecords = {0x3050F844, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IEnumPropertyMap = {0xC733E4A1, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_IEnumPublishedApps = {0x0B124F8C, 0x91F0, 0x11D1, [0xB8, 0xB5, 0x00, 0x60, 0x08, 0x05, 0x93, 0x82]}; enum IID IID_IEnumQueue = {0x5AFC3158, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_IEnumRegisterWordA = {0x08C03412, 0xF96B, 0x11D0, [0xA4, 0x75, 0x00, 0xAA, 0x00, 0x6B, 0xCC, 0x59]}; enum IID IID_IEnumRegisterWordW = {0x4955DD31, 0xB159, 0x11D0, [0x8F, 0xCF, 0x00, 0xAA, 0x00, 0x6B, 0xCC, 0x59]}; enum IID IID_IEnumRemoteDebugApplications = {0x51973C3B, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IEnumRemoteDebugApplicationThrea = {0x51973C3C, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IEnumRfc1766 = {0x3DC39D1D, 0xC030, 0x11D0, [0xB8, 0x1B, 0x00, 0xC0, 0x4F, 0xC9, 0xB3, 0x1F]}; enum IID IID_IEnumScheduleGroup = {0xC733E4A9, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_IEnumScript = {0xAE5F1430, 0x388B, 0x11D2, [0x83, 0x80, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0xA1]}; enum IID IID_IEnumSTATDATA = {0x00000105, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumSTATPROPBAG = {0x20021801, 0x5DE6, 0x11D1, [0x8E, 0x38, 0x00, 0xC0, 0x4F, 0xB9, 0x38, 0x6D]}; enum IID IID_IEnumSTATPROPSETSTG = {0x0000013B, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumSTATPROPSTG = {0x00000139, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumSTATSTG = {0x0000000D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumSTATURL = {0x3C374A42, 0xBAE4, 0x11CF, [0xBF, 0x7D, 0x00, 0xAA, 0x00, 0x69, 0x46, 0xEE]}; enum IID IID_IEnumStream = {0xEE3BD606, 0x3868, 0x11D2, [0xA0, 0x45, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_IEnumString = {0x00000101, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumSubscription = {0xF72C8D97, 0x6DBD, 0x11D1, [0xA1, 0xE8, 0x00, 0xC0, 0x4F, 0xC2, 0xFB, 0xE1]}; enum IID IID_IEnumSubStream = {0xEE3BD609, 0x3868, 0x11D2, [0xA0, 0x45, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_IEnumSyncItems = {0xF0E1589A, 0xA700, 0x11D1, [0x98, 0x31, 0x00, 0xC0, 0x4F, 0xD9, 0x10, 0xDD]}; enum IID IID_IEnumSyncSchedules = {0xF0E15898, 0xA700, 0x11D1, [0x98, 0x31, 0x00, 0xC0, 0x4F, 0xD9, 0x10, 0xDD]}; enum IID IID_IEnumTerminal = {0xAE269CF4, 0x935E, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_IEnumTerminalClass = {0xAE269CF5, 0x935E, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_IEnumTime = {0x9055322E, 0x2FA8, 0x11D1, [0x97, 0x74, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_IEnumTravelLogEntry = {0x7EBFDD85, 0xAD18, 0x11D3, [0xA4, 0xC5, 0x00, 0xC0, 0x4F, 0x72, 0xD6, 0xB8]}; enum IID IID_IEnumUnknown = {0x00000100, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumVARIANT = {0x00020404, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IEnumWbemClassObject = {0x027947E1, 0xD731, 0x11CE, [0xA3, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]}; enum IID IID_IErrorInfo = {0x1CF2B120, 0x547D, 0x101B, [0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19]}; enum IID IID_IErrorLog = {0x3127CA40, 0x446E, 0x11CE, [0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51]}; enum IID IID_IErrorLookup = {0x0C733A66, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IErrorRecords = {0x0C733A67, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IESP = {0xE99A04AA, 0xAB95, 0x11D0, [0xBE, 0x96, 0x00, 0xA0, 0xC9, 0x49, 0x89, 0xDE]}; enum IID IID_IExtendObjectManager = {0xCA7BB0B9, 0x700C, 0x4DC5, [0x99, 0x1E, 0x75, 0xF9, 0xE6, 0x5E, 0xE9, 0x75]}; enum IID IID_IExtensionServices = {0x79EAC9CB, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IExternalConnection = {0x00000019, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IExtractIconA = {0x000214EB, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IExtractIconW = {0x000214FA, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IExtractImage = {0xBB2E617C, 0x0920, 0x11D1, [0x9A, 0x0B, 0x00, 0xC0, 0x4F, 0xC2, 0xD6, 0xC1]}; enum IID IID_IExtractImage2 = {0x953BB1EE, 0x93B4, 0x11D1, [0x98, 0xA3, 0x00, 0xC0, 0x4F, 0xB6, 0x87, 0xDA]}; enum IID IID_IFileSearchBand = {0x2D91EEA1, 0x9932, 0x11D2, [0xBE, 0x86, 0x00, 0xA0, 0xC9, 0xA8, 0x3D, 0xA1]}; enum IID IID_IFileSystemBindData = {0x01E18D10, 0x4D8B, 0x11D2, [0x85, 0x5D, 0x00, 0x60, 0x08, 0x05, 0x93, 0x67]}; enum IID IID_IFileViewerA = {0x000214F0, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IFileViewerSite = {0x000214F3, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IFileViewerW = {0x000214F8, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IFillLockBytes = {0x99CAF010, 0x415E, 0x11CF, [0x88, 0x14, 0x00, 0xAA, 0x00, 0xB5, 0x69, 0xF5]}; enum IID IID_IFilter = {0x89BCB740, 0x6119, 0x101A, [0xBC, 0xB7, 0x00, 0xDD, 0x01, 0x06, 0x55, 0xAF]}; enum IID IID_IFilterAnimationInfo = {0x02E29300, 0xC758, 0x49B4, [0x9E, 0x11, 0xC5, 0x8B, 0xFE, 0x90, 0x55, 0x8B]}; enum IID IID_IFilterStatus = {0xF4EB8260, 0x8DDA, 0x11D1, [0xB3, 0xAA, 0x00, 0xA0, 0xC9, 0x06, 0x37, 0x96]}; enum IID IID_IFolderFilter = {0x9CC22886, 0xDC8E, 0x11D2, [0xB1, 0xD0, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x3E]}; enum IID IID_IFolderFilterSite = {0xC0A651F5, 0xB48B, 0x11D2, [0xB5, 0xED, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6]}; enum IID IID_IFolderView = {0xCDE725B0, 0xCCC9, 0x4519, [0x91, 0x7E, 0x32, 0x5D, 0x72, 0xFA, 0xB4, 0xCE]}; enum IID IID_IFolderViewHost = {0x1EA58F02, 0xD55A, 0x411D, [0xB0, 0x9E, 0x9E, 0x65, 0xAC, 0x21, 0x60, 0x5B]}; enum IID IID_IFolderViewOC = {0x9BA05970, 0xF6A8, 0x11CF, [0xA4, 0x42, 0x00, 0xA0, 0xC9, 0x0A, 0x8F, 0x39]}; enum IID IID_IFont = {0xBEF6E002, 0xA874, 0x101A, [0x8B, 0xBA, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID IID_IFontDisp = {0xBEF6E003, 0xA874, 0x101A, [0x8B, 0xBA, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID IID_IFontEventsDisp = {0x4EF6100A, 0xAF88, 0x11D0, [0x98, 0x46, 0x00, 0xC0, 0x4F, 0xC2, 0x99, 0x93]}; enum IID IID_IFontNames = {0x3050F839, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IForegroundTransfer = {0x00000145, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IFsCiAdmin = {0x75398C30, 0x7A26, 0x11D0, [0xA8, 0x0A, 0x00, 0xA0, 0xC9, 0x06, 0x24, 0x1A]}; enum IID IID_IGatherData = {0x65318F4A, 0xB63C, 0x4E21, [0xAD, 0xDC, 0xBD, 0xCF, 0xB9, 0x69, 0xE1, 0x81]}; enum IID IID_IGetClusterDataInfo = {0x97DEDE51, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IGetClusterGroupInfo = {0x97DEDE54, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IGetClusterNetInterfaceInfo = {0x97DEDE57, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IGetClusterNetworkInfo = {0x97DEDE56, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IGetClusterNodeInfo = {0x97DEDE53, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IGetClusterObjectInfo = {0x97DEDE52, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IGetClusterResourceInfo = {0x97DEDE55, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IGetClusterUIInfo = {0x97DEDE50, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IGetDataSource = {0x0C733A75, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IGetRow = {0x0C733AAF, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IGetSession = {0x0C733ABA, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IGetSourceRow = {0x0C733ABB, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IGlobalInterfaceTable = {0x00000146, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IH26XEncodeOptions = {0x65698D40, 0x282D, 0x11D0, [0x88, 0x00, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IH26XEncoderControl = {0xF9B78AA1, 0xEA12, 0x11CF, [0x9F, 0xEC, 0x00, 0xAA, 0x00, 0xA5, 0x9F, 0x69]}; enum IID IID_IH26XRTPControl = {0x1FC3F2C0, 0x2BFD, 0x11D0, [0x88, 0x00, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IH26XSnapshot = {0x3CB194A0, 0x10AA, 0x11D0, [0x88, 0x00, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IH26XVideoEffects = {0x21555140, 0x9C2B, 0x11CF, [0x90, 0xFA, 0x00, 0xAA, 0x00, 0xA7, 0x29, 0xEA]}; enum IID IID_IH323LineEx = {0x44CF6A9D, 0xCB40, 0x4BBC, [0xB2, 0xD3, 0xB6, 0xAA, 0x93, 0x32, 0x2C, 0x71]}; enum IID IID_IHeaderFooter = {0x3050F6CE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHighlightRenderingServices = {0x3050F606, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHighlightSegment = {0x3050F690, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHlink = {0x79EAC9C3, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IHlinkBrowseContext = {0x79EAC9C7, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IHlinkFrame = {0x79EAC9C5, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IHlinkSite = {0x79EAC9C2, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IHlinkTarget = {0x79EAC9C4, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IHNetApplicationProtocol = {0x85D18B7F, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetBridge = {0x85D18B75, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetBridgedConnection = {0x85D18B76, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetBridgeSettings = {0x85D18B6D, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetCfgMgr = {0x85D18B6C, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetConnection = {0x85D18B71, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetFirewalledConnection = {0x85D18B72, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetFirewallSettings = {0x85D18B6E, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetIcsPrivateConnection = {0x85D18B74, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetIcsPublicConnection = {0x85D18B73, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetIcsSettings = {0x85D18B6F, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetPortMappingBinding = {0x85D18B80, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetPortMappingProtocol = {0x85D18B7E, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHNetProtocolSettings = {0x85D18B70, 0x3032, 0x11D4, [0x93, 0x48, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x71]}; enum IID IID_IHomePage = {0x766BF2AF, 0xD650, 0x11D1, [0x98, 0x11, 0x00, 0xC0, 0x4F, 0xC3, 0x1D, 0x2E]}; enum IID IID_IHostBehaviorInit = {0x3050F842, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHostDialogHelper = {0x53DEC138, 0xA51E, 0x11D2, [0x86, 0x1E, 0x00, 0xC0, 0x4F, 0xA3, 0x5C, 0x89]}; enum IID IID_IHTCAttachBehavior = {0x3050F5F4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTCAttachBehavior2 = {0x3050F7EB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTCDefaultDispatch = {0x3050F4FD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTCDescBehavior = {0x3050F5DC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTCEventBehavior = {0x3050F4FF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTCMethodBehavior = {0x3050F631, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTCPropertyBehavior = {0x3050F5DF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAnchorElement = {0x3050F1DA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAnchorElement2 = {0x3050F825, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAppBehavior = {0x3050F5CA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAppBehavior2 = {0x3050F5C9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAppBehavior3 = {0x3050F5CD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHtmlArea = {0x3050F64E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAreaElement = {0x3050F265, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAreasCollection = {0x3050F383, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAreasCollection2 = {0x3050F5EC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAreasCollection3 = {0x3050F837, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAttributeCollection = {0x3050F4C3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLAttributeCollection2 = {0x3050F80A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLBaseElement = {0x3050F204, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLBaseFontElement = {0x3050F202, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLBGsound = {0x3050F369, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLBlockElement = {0x3050F208, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLBlockElement2 = {0x3050F823, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLBodyElement = {0x3050F1D8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLBodyElement2 = {0x3050F5C5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLBookmarkCollection = {0x3050F4CE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLBRElement = {0x3050F1F0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLButtonElement = {0x3050F2BB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLCaret = {0x3050F604, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLChangeLog = {0x3050F649, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLChangePlayback = {0x3050F6E0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLChangeSink = {0x3050F64A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLCommentElement = {0x3050F20C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLCommentElement2 = {0x3050F813, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLComputedStyle = {0x3050F6C3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLControlElement = {0x3050F4E9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLControlRange = {0x3050F29C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLControlRange2 = {0x3050F65E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLCurrentStyle = {0x3050F3DB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLCurrentStyle2 = {0x3050F658, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLCurrentStyle3 = {0x3050F818, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDatabinding = {0x3050F3F2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDataTransfer = {0x3050F4B3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDDElement = {0x3050F1F2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDialog = {0x3050F216, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDialog2 = {0x3050F5E0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDialog3 = {0x3050F388, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDivElement = {0x3050F200, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDivPosition = {0x3050F212, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHtmlDlgSafeHelper = {0x3050F81A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDListElement = {0x3050F1F1, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDocument = {0x626FC520, 0xA41E, 0x11CF, [0xA7, 0x31, 0x00, 0xA0, 0xC9, 0x08, 0x26, 0x37]}; enum IID IID_IHTMLDocument2 = {0x332C4425, 0x26CB, 0x11D0, [0xB4, 0x83, 0x00, 0xC0, 0x4F, 0xD9, 0x01, 0x19]}; enum IID IID_IHTMLDocument3 = {0x3050F485, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDocument4 = {0x3050F69A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDocument5 = {0x3050F80C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDOMAttribute = {0x3050F4B0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDOMAttribute2 = {0x3050F810, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDOMChildrenCollection = {0x3050F5AB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDOMImplementation = {0x3050F80D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDOMNode = {0x3050F5DA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDOMNode2 = {0x3050F80B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDOMTextNode = {0x3050F4B1, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDOMTextNode2 = {0x3050F809, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDTElement = {0x3050F1F3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLDXTransform = {0x30E2AB7D, 0x4FDD, 0x4159, [0xB7, 0xEA, 0xDC, 0x72, 0x2B, 0xF4, 0xAD, 0xE5]}; enum IID IID_IHTMLEditDesigner = {0x3050F662, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEditHost = {0x3050F6A0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEditHost2 = {0x3050F848, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0D]}; enum IID IID_IHTMLEditingServices = {0x3050F7FB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEditor = {0x3050F7FA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEditServices = {0x3050F663, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEditServices2 = {0x3050F812, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLElement = {0x3050F1FF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLElement2 = {0x3050F434, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLElement3 = {0x3050F673, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLElement4 = {0x3050F80F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLElementCollection = {0x3050F21F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLElementCollection2 = {0x3050F5EE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLElementCollection3 = {0x3050F835, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLElementDefaults = {0x3050F6C9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLElementRender = {0x3050F669, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEmbedElement = {0x3050F25F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEventObj = {0x3050F32D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEventObj2 = {0x3050F48B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEventObj3 = {0x3050F680, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLEventObj4 = {0x3050F814, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFieldSetElement = {0x3050F3E7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFieldSetElement2 = {0x3050F833, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFilterPainter = {0x3050F6DE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFilterPaintSite = {0x3050F6D3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFiltersCollection = {0x3050F3EE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFontElement = {0x3050F1D9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFontNamesCollection = {0x3050F376, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFontSizesCollection = {0x3050F377, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFormElement = {0x3050F1F7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFormElement2 = {0x3050F4F6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFormElement3 = {0x3050F836, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFrameBase = {0x3050F311, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFrameBase2 = {0x3050F6DB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFrameBase3 = {0x3050F82E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFrameElement = {0x3050F313, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFrameElement2 = {0x3050F7F5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFramesCollection2 = {0x332C4426, 0x26CB, 0x11D0, [0xB4, 0x83, 0x00, 0xC0, 0x4F, 0xD9, 0x01, 0x19]}; enum IID IID_IHTMLFrameSetElement = {0x3050F319, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLFrameSetElement2 = {0x3050F5C6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLGenericElement = {0x3050F4B7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLHeadElement = {0x3050F81D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLHeaderElement = {0x3050F1F6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLHRElement = {0x3050F1F4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLHtmlElement = {0x3050F81C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLIFrameElement = {0x3050F315, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLIFrameElement2 = {0x3050F4E6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLImageElementFactory = {0x3050F38E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLImgElement = {0x3050F240, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLImgElement2 = {0x3050F826, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLInputButtonElement = {0x3050F2B2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLInputElement = {0x3050F5D2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLInputElement2 = {0x3050F821, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLInputFileElement = {0x3050F2AD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLInputHiddenElement = {0x3050F2A4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLInputImage = {0x3050F2C2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLInputTextElement = {0x3050F2A6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLIPrintCollection = {0x3050F6B5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLIsIndexElement = {0x3050F206, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLIsIndexElement2 = {0x3050F82F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLLabelElement = {0x3050F32A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLLabelElement2 = {0x3050F832, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLLegendElement = {0x3050F3EA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLLegendElement2 = {0x3050F834, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLLIElement = {0x3050F1E0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLLinkElement = {0x3050F205, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLLinkElement2 = {0x3050F4E5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLLinkElement3 = {0x3050F81E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLListElement = {0x3050F20E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLListElement2 = {0x3050F822, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHtmlLoadOptions = {0xA71A0808, 0x0F88, 0x11D1, [0xBA, 0x19, 0x00, 0xC0, 0x4F, 0xD9, 0x12, 0xD0]}; enum IID IID_IHTMLLocation = {0x163BB1E0, 0x6E00, 0x11CF, [0x83, 0x7A, 0x48, 0xDC, 0x04, 0xC1, 0x00, 0x00]}; enum IID IID_IHTMLMapElement = {0x3050F266, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLMarqueeElement = {0x3050F2B5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLMetaElement = {0x3050F203, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLMetaElement2 = {0x3050F81F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLMimeTypesCollection = {0x3050F3FC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLModelessInit = {0x3050F5E4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLNamespace = {0x3050F6BB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLNamespaceCollection = {0x3050F6B8, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLNextIdElement = {0x3050F207, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLNoShowElement = {0x3050F38A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLObjectElement = {0x3050F24F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLObjectElement2 = {0x3050F4CD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLObjectElement3 = {0x3050F827, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLOListElement = {0x3050F1DE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLOMWindowServices = {0x3050F5FC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLOpsProfile = {0x3050F401, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLOptionButtonElement = {0x3050F2BC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLOptionElement = {0x3050F211, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLOptionElement2 = {0x3050F697, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLOptionElement3 = {0x3050F820, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLOptionElementFactory = {0x3050F38C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLOptionsHolder = {0x3050F378, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPainter = {0x3050F6A6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPainterEventInfo = {0x3050F6DF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPainterOverlay = {0x3050F7E3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPaintSite = {0x3050F6A7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLParaElement = {0x3050F1F5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLParamElement = {0x3050F83D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPersistData = {0x3050F4C5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPersistDataOM = {0x3050F4C0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPhraseElement = {0x3050F20A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPhraseElement2 = {0x3050F824, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPluginsCollection = {0x3050F3FD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPopup = {0x3050F666, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPrivateWindow = {0x3050F6DC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPrivateWindow2 = {0x3050F7E5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLPrivateWindow3 = {0x3050F840, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLRect = {0x3050F4A3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLRectCollection = {0x3050F4A4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLRenderStyle = {0x3050F6AE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLRuleStyle = {0x3050F3CF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLRuleStyle2 = {0x3050F4AC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLRuleStyle3 = {0x3050F657, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLRuleStyle4 = {0x3050F817, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLScreen = {0x3050F35C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLScreen2 = {0x3050F84A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLScriptElement = {0x3050F28B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLScriptElement2 = {0x3050F828, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLSelectElement = {0x3050F244, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLSelectElement2 = {0x3050F5ED, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLSelectElement3 = {0x3050F687, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLSelectElement4 = {0x3050F838, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLSelectionObject = {0x3050F25A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLSelectionObject2 = {0x3050F7EC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLSpanElement = {0x3050F3F3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLSpanFlow = {0x3050F3E5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyle = {0x3050F25E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyle2 = {0x3050F4A2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyle3 = {0x3050F656, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyle4 = {0x3050F816, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyleElement = {0x3050F375, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyleFontFace = {0x3050F3D5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyleSheet = {0x3050F2E3, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyleSheet2 = {0x3050F3D1, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyleSheetPage = {0x3050F7EE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyleSheetPagesCollection = {0x3050F7F0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyleSheetRule = {0x3050F357, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyleSheetRulesCollection = {0x3050F2E5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLStyleSheetsCollection = {0x3050F37E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLSubmitData = {0x3050F645, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTable = {0x3050F21E, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTable2 = {0x3050F4AD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTable3 = {0x3050F829, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableCaption = {0x3050F2EB, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableCell = {0x3050F23D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableCell2 = {0x3050F82D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableCol = {0x3050F23A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableCol2 = {0x3050F82A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableRow = {0x3050F23C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableRow2 = {0x3050F4A1, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableRow3 = {0x3050F82C, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableRowMetrics = {0x3050F413, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableSection = {0x3050F23B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableSection2 = {0x3050F5C7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTableSection3 = {0x3050F82B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTextAreaElement = {0x3050F2AA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTextContainer = {0x3050F230, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTextElement = {0x3050F218, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTextRangeMetrics = {0x3050F40B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTextRangeMetrics2 = {0x3050F4A6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTitleElement = {0x3050F322, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTxtRange = {0x3050F220, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLTxtRangeCollection = {0x3050F7ED, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLUListElement = {0x3050F1DD, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLUniqueName = {0x3050F4D0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLUnknownElement = {0x3050F209, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLUrnCollection = {0x3050F5E2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLUserDataOM = {0x3050F48F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLViewFilter = {0x3050F2F1, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLViewFilterSite = {0x3050F2F4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLWindow2 = {0x332C4427, 0x26CB, 0x11D0, [0xB4, 0x83, 0x00, 0xC0, 0x4F, 0xD9, 0x01, 0x19]}; enum IID IID_IHTMLWindow3 = {0x3050F4AE, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHTMLWindow4 = {0x3050F6CF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IHttpNegotiate = {0x79EAC9D2, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IHttpNegotiate2 = {0x4F9F9FCB, 0xE0F4, 0x48EB, [0xB7, 0xAB, 0xFA, 0x2E, 0xA9, 0x36, 0x5C, 0xB4]}; enum IID IID_IHttpSecurity = {0x79EAC9D7, 0xBAFA, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IHWEventHandler = {0xC1FB73D0, 0xEC3A, 0x4BA2, [0xB5, 0x12, 0x8C, 0xDB, 0x91, 0x87, 0xB6, 0xD1]}; enum IID IID_IImageDecodeEventSink = {0xBAA342A0, 0x2DED, 0x11D0, [0x86, 0xF4, 0x00, 0xA0, 0xC9, 0x13, 0xF7, 0x50]}; enum IID IID_IImageDecodeFilter = {0xA3CCEDF3, 0x2DE2, 0x11D0, [0x86, 0xF4, 0x00, 0xA0, 0xC9, 0x13, 0xF7, 0x50]}; enum IID IID_IImageList = {0x46EB5926, 0x582E, 0x4017, [0x9F, 0xDF, 0xE8, 0x99, 0x8D, 0xAA, 0x09, 0x50]}; enum IID IID_IIMEServices = {0x3050F6CA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IImgCtx = {0x3050F3D7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IIndexDefinition = {0x0C733A68, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IInputObject = {0x68284FAA, 0x6A48, 0x11D0, [0x8C, 0x78, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xB4]}; enum IID IID_IInputObjectSite = {0xF1DB8392, 0x7331, 0x11D0, [0x8C, 0x99, 0x00, 0xA0, 0xC9, 0x2D, 0xBF, 0xE8]}; enum IID IID_IIntDitherer = {0x06670CA0, 0xECEF, 0x11D0, [0xAA, 0xE7, 0x00, 0xC0, 0x4F, 0xC9, 0xB3, 0x04]}; enum IID IID_IIntelliForms = {0x9B9F68E6, 0x1AAA, 0x11D2, [0xBC, 0xA5, 0x00, 0xC0, 0x4F, 0xD9, 0x29, 0xDB]}; enum IID IID_IInterfaceRelated = {0xD1FB5A79, 0x7706, 0x11D1, [0xAD, 0xBA, 0x00, 0xC0, 0x4F, 0xC2, 0xAD, 0xC0]}; enum IID IID_IInternalMoniker = {0x00000011, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IInternalUnknown = {0x00000021, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IInternet = {0x79EAC9E0, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetBindInfo = {0x79EAC9E1, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetConnectionDevice = {0x04DF6137, 0x5610, 0x11D4, [0x9E, 0xC8, 0x00, 0xB0, 0xD0, 0x22, 0xDD, 0x1F]}; enum IID IID_IInternetConnectionDeviceClient = {0x04DF6139, 0x5610, 0x11D4, [0x9E, 0xC8, 0x00, 0xB0, 0xD0, 0x22, 0xDD, 0x1F]}; enum IID IID_IInternetConnectionDeviceSharedCo = {0x04DF6138, 0x5610, 0x11D4, [0x9E, 0xC8, 0x00, 0xB0, 0xD0, 0x22, 0xDD, 0x1F]}; enum IID IID_IInternetHostSecurityManager = {0x3AF280B6, 0xCB3F, 0x11D0, [0x89, 0x1E, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4]}; enum IID IID_IInternetPriority = {0x79EAC9EB, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetProtocol = {0x79EAC9E4, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetProtocolInfo = {0x79EAC9EC, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetProtocolRoot = {0x79EAC9E3, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetProtocolSink = {0x79EAC9E5, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetProtocolSinkStackable = {0x79EAC9F0, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetSecurityManager = {0x79EAC9EE, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetSecurityMgrSite = {0x79EAC9ED, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetSession = {0x79EAC9E7, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetThreadSwitch = {0x79EAC9E8, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IInternetZoneManager = {0x79EAC9EF, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IIpxAdapterInfo = {0x98133270, 0x4B20, 0x11D1, [0xAB, 0x01, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IItemNameLimits = {0x1DF0D7F1, 0xB267, 0x4D28, [0x8B, 0x10, 0x12, 0xE2, 0x32, 0x02, 0xA5, 0xC4]}; enum IID IID_IJolietDiscMaster = {0xE3BC42CE, 0x4E5C, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID IID_IKeyFrameControl = {0xC3341386, 0xAF91, 0x4EF9, [0x83, 0xB6, 0xBE, 0x37, 0x62, 0xE4, 0x2E, 0xCB]}; enum IID IID_IKsControl = {0x28F54685, 0x06FD, 0x11D2, [0xB2, 0x7A, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96]}; enum IID IID_IKsPropertySet = {0x31EFAC30, 0x515C, 0x11D0, [0xA9, 0xAA, 0x00, 0xAA, 0x00, 0x61, 0xBE, 0x93]}; enum IID IID_ILayoutRect = {0x3050F665, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ILayoutStorage = {0x0E6D4D90, 0x6738, 0x11CF, [0x96, 0x08, 0x00, 0xAA, 0x00, 0x68, 0x0D, 0xB4]}; enum IID IID_ILineInfo = {0x3050F7E2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ILocalMachine = {0x60664CAF, 0xAF0D, 0x1005, [0xA3, 0x00, 0x5C, 0x7D, 0x25, 0xFF, 0x22, 0xA0]}; enum IID IID_ILockBytes = {0x0000000A, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ILogger = {0xD9598418, 0x304E, 0x4F94, [0xB6, 0xA1, 0xE6, 0x42, 0xFE, 0x95, 0xED, 0x57]}; enum IID IID_ILogManager = {0x4759DC11, 0x8DA0, 0x4261, [0xBB, 0xFB, 0xEC, 0x32, 0x19, 0x11, 0xD1, 0xC9]}; enum IID IID_ILogonEnumUsers = {0x60664CAF, 0xAF0D, 0x1004, [0xA3, 0x00, 0x5C, 0x7D, 0x25, 0xFF, 0x22, 0xA0]}; enum IID IID_ILogonStatusHost = {0x60664CAF, 0xAF0D, 0x1007, [0xA3, 0x00, 0x5C, 0x7D, 0x25, 0xFF, 0x22, 0xA0]}; enum IID IID_ILogonUser = {0x60664CAF, 0xAF0D, 0x1003, [0xA3, 0x00, 0x5C, 0x7D, 0x25, 0xFF, 0x22, 0xA0]}; enum IID IID_IMachineDebugManager = {0x51973C2C, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IMachineDebugManagerCookie = {0x51973C2D, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IMachineDebugManagerEvents = {0x51973C2E, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IMailAutoDiscovery = {0x80402DEE, 0xB114, 0x4D32, [0xB4, 0x4E, 0x82, 0xFD, 0x82, 0x34, 0xC9, 0x2A]}; enum IID IID_IMailProtocolADEntry = {0x40EF8C68, 0xD554, 0x47ED, [0xAA, 0x37, 0xE5, 0xFB, 0x6B, 0xC9, 0x10, 0x75]}; enum IID IID_IMalloc = {0x00000002, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IMallocSpy = {0x0000001D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IMapMIMEToCLSID = {0xD9E89500, 0x30FA, 0x11D0, [0xB7, 0x24, 0x00, 0xAA, 0x00, 0x6C, 0x1A, 0x01]}; enum IID IID_IMarkupContainer = {0x3050F5F9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IMarkupContainer2 = {0x3050F648, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IMarkupPointer = {0x3050F49F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IMarkupPointer2 = {0x3050F675, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IMarkupServices = {0x3050F4A0, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IMarkupServices2 = {0x3050F682, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IMarkupTextFrags = {0x3050F5FA, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IMarshal = {0x00000003, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IMarshal2 = {0x000001CF, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IMcastAddressAllocation = {0xDF0DAEF1, 0xA289, 0x11D1, [0x86, 0x97, 0x00, 0x60, 0x08, 0xB0, 0xE5, 0xD2]}; enum IID IID_IMcastLeaseInfo = {0xDF0DAEFD, 0xA289, 0x11D1, [0x86, 0x97, 0x00, 0x60, 0x08, 0xB0, 0xE5, 0xD2]}; enum IID IID_IMcastScope = {0xDF0DAEF4, 0xA289, 0x11D1, [0x86, 0x97, 0x00, 0x60, 0x08, 0xB0, 0xE5, 0xD2]}; enum IID IID_IMDDataset = {0xA07CCCD1, 0x8148, 0x11D0, [0x87, 0xBB, 0x00, 0xC0, 0x4F, 0xC3, 0x39, 0x42]}; enum IID IID_IMDFind = {0xA07CCCD2, 0x8148, 0x11D0, [0x87, 0xBB, 0x00, 0xC0, 0x4F, 0xC3, 0x39, 0x42]}; enum IID IID_IMDRangeRowset = {0x0C733AA0, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IMessageFilter = {0x00000016, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IMigrationWizardAuto = {0xCE20DAB9, 0xB353, 0x469B, [0x8B, 0x4D, 0x6D, 0xBB, 0x3A, 0x7B, 0xA0, 0x16]}; enum IID IID_IMimeInfo = {0xF77459A0, 0xBF9A, 0x11CF, [0xBA, 0x4E, 0x00, 0xC0, 0x4F, 0xD7, 0x08, 0x16]}; enum IID IID_IMLangCodePages = {0x359F3443, 0xBD4A, 0x11D0, [0xB1, 0x88, 0x00, 0xAA, 0x00, 0x38, 0xC9, 0x69]}; enum IID IID_IMLangConvertCharset = {0xD66D6F98, 0xCDAA, 0x11D0, [0xB8, 0x22, 0x00, 0xC0, 0x4F, 0xC9, 0xB3, 0x1F]}; enum IID IID_IMLangFontLink = {0x359F3441, 0xBD4A, 0x11D0, [0xB1, 0x88, 0x00, 0xAA, 0x00, 0x38, 0xC9, 0x69]}; enum IID IID_IMLangFontLink2 = {0xDCCFC162, 0x2B38, 0x11D2, [0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A]}; enum IID IID_IMLangLineBreakConsole = {0xF5BE2EE1, 0xBFD7, 0x11D0, [0xB1, 0x88, 0x00, 0xAA, 0x00, 0x38, 0xC9, 0x69]}; enum IID IID_IMLangString = {0xC04D65CE, 0xB70D, 0x11D0, [0xB1, 0x88, 0x00, 0xAA, 0x00, 0x38, 0xC9, 0x69]}; enum IID IID_IMLangStringAStr = {0xC04D65D2, 0xB70D, 0x11D0, [0xB1, 0x88, 0x00, 0xAA, 0x00, 0x38, 0xC9, 0x69]}; enum IID IID_IMLangStringBufA = {0xD24ACD23, 0xBA72, 0x11D0, [0xB1, 0x88, 0x00, 0xAA, 0x00, 0x38, 0xC9, 0x69]}; enum IID IID_IMLangStringBufW = {0xD24ACD21, 0xBA72, 0x11D0, [0xB1, 0x88, 0x00, 0xAA, 0x00, 0x38, 0xC9, 0x69]}; enum IID IID_IMLangStringWStr = {0xC04D65D0, 0xB70D, 0x11D0, [0xB1, 0x88, 0x00, 0xAA, 0x00, 0x38, 0xC9, 0x69]}; enum IID IID_IMofCompiler = {0x6DAF974E, 0x2E37, 0x11D2, [0xAE, 0xC9, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IMoniker = {0x0000000F, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IMonikerProp = {0xA5CA5F7F, 0x1847, 0x4D87, [0x9C, 0x5B, 0x91, 0x85, 0x09, 0xF7, 0x51, 0x1D]}; enum IID IID_IMountedVolume = {0x12518492, 0x00B2, 0x11D2, [0x9F, 0xA5, 0x9E, 0x34, 0x20, 0x52, 0x41, 0x53]}; enum IID IID_IMulticastControl = {0x410FA507, 0x4DC6, 0x415A, [0x90, 0x14, 0x63, 0x38, 0x75, 0xD5, 0x40, 0x6E]}; enum IID IID_IMultiLanguage = {0x275C23E1, 0x3747, 0x11D0, [0x9F, 0xEA, 0x00, 0xAA, 0x00, 0x3F, 0x86, 0x46]}; enum IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11D2, [0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A]}; enum IID IID_IMultiLanguage3 = {0x4E5868AB, 0xB157, 0x4623, [0x9A, 0xCC, 0x6A, 0x1D, 0x9C, 0xAE, 0xBE, 0x04]}; enum IID IID_IMultiplePropertyAccess = {0xEC81FEDE, 0xD432, 0x11CE, [0x92, 0x44, 0x00, 0x20, 0xAF, 0x6E, 0x72, 0xDB]}; enum IID IID_IMultipleResults = {0x0C733A90, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IMultiQI = {0x00000020, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_INamedPropertyBag = {0xFB700430, 0x952C, 0x11D1, [0x94, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]}; enum IID IID_INATEventManager = {0x624BD588, 0x9060, 0x4109, [0xB0, 0xB0, 0x1A, 0xDB, 0xBC, 0xAC, 0x32, 0xDF]}; enum IID IID_INATExternalIPAddressCallback = {0x9C416740, 0xA34E, 0x446F, [0xBA, 0x06, 0xAB, 0xD0, 0x4C, 0x31, 0x49, 0xAE]}; enum IID IID_INATNumberOfEntriesCallback = {0xC83A0A74, 0x91EE, 0x41B6, [0xB6, 0x7A, 0x67, 0xE0, 0xF0, 0x0B, 0xBD, 0x78]}; enum IID IID_INetCfg = {0xC0E8AE93, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgBindingInterface = {0xC0E8AE94, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgBindingPath = {0xC0E8AE96, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgClass = {0xC0E8AE97, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgClassSetup = {0xC0E8AE9D, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgComponent = {0xC0E8AE99, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgComponentBindings = {0xC0E8AE9E, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgComponentControl = {0x932238DF, 0xBEA1, 0x11D0, [0x92, 0x98, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0xCF]}; enum IID IID_INetCfgComponentNotifyBinding = {0x932238E1, 0xBEA1, 0x11D0, [0x92, 0x98, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0xCF]}; enum IID IID_INetCfgComponentNotifyGlobal = {0x932238E2, 0xBEA1, 0x11D0, [0x92, 0x98, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0xCF]}; enum IID IID_INetCfgComponentPrivate = {0x98133273, 0x4B20, 0x11D1, [0xAB, 0x01, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgComponentPropertyUi = {0x932238E0, 0xBEA1, 0x11D0, [0x92, 0x98, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0xCF]}; enum IID IID_INetCfgComponentSetup = {0x932238E3, 0xBEA1, 0x11D0, [0x92, 0x98, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0xCF]}; enum IID IID_INetCfgComponentSysPrep = {0xC0E8AE9A, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgComponentUpperEdge = {0x932238E4, 0xBEA1, 0x11D0, [0x92, 0x98, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0xCF]}; enum IID IID_INetCfgInternalSetup = {0x98133276, 0x4B20, 0x11D1, [0xAB, 0x01, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgLock = {0xC0E8AE9F, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgPnpReconfigCallback = {0x8D84BD35, 0xE227, 0x11D2, [0xB7, 0x00, 0x00, 0xA0, 0xC9, 0x8A, 0x6A, 0x85]}; enum IID IID_INetCfgSpecialCase = {0xC0E8AE95, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCfgSysPrep = {0xC0E8AE98, 0x306E, 0x11D1, [0xAA, 0xCF, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnection = {0xC08956A1, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnection2 = {0xFAEDCF6A, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionBrandingInfo = {0xFAEDCF5B, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionCMUtil = {0xFAEDCF60, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionCommonUi = {0xC08956A5, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionConnectUi = {0xC08956A3, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionHNetUtil = {0xFAEDCF64, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionManager = {0xC08956A2, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionManager2 = {0xFAEDCF69, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionManagerDebug = {0xFAEDCF5D, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionManagerEvents = {0xC08956BA, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionNotifySink = {0xFAEDCF5C, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionPropertyUi = {0xC08956A4, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionPropertyUi2 = {0xC08956B9, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionProps = {0xF4277C95, 0xCE5B, 0x463D, [0x81, 0x67, 0x56, 0x62, 0xD9, 0xBC, 0xAA, 0x72]}; enum IID IID_INetConnectionRefresh = {0xFAEDCF5F, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionSysTray = {0xFAEDCF65, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionUiLock = {0xFAEDCF50, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionUiUtilities = {0xFAEDCF5E, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionWizardUi = {0xFAEDCF51, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetConnectionWizardUiContext = {0xFAEDCF52, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetCrawler = {0x49C929EE, 0xA1B7, 0x4C58, [0xB5, 0x39, 0xE6, 0x3B, 0xE3, 0x92, 0xB6, 0xF3]}; enum IID IID_INetDefaultConnection = {0xFAEDCF66, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetInboundConnection = {0xFAEDCF53, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetInstallQueue = {0x98133274, 0x4B20, 0x11D1, [0xAB, 0x01, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetLanConnection = {0xFAEDCF54, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetLanConnectionUiInfo = {0xC08956A6, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetLanConnectionWizardUi = {0xFAEDCF56, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetMachinePolicies = {0xFAEDCF68, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetRasConnection = {0xFAEDCF57, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetRasConnectionIpUiInfo = {0xFAEDCF58, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetSharedAccessConnection = {0xFAEDCF55, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetSharingConfiguration = {0xC08956B6, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetSharingEveryConnectionCollect = {0x33C4643C, 0x7811, 0x46FA, [0xA8, 0x9A, 0x76, 0x85, 0x97, 0xBD, 0x72, 0x23]}; enum IID IID_INetSharingManager = {0xC08956B7, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetSharingPortMapping = {0xC08956B1, 0x1CD3, 0x11D1, [0xB1, 0xC5, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_INetSharingPortMappingCollection = {0x02E4A2DE, 0xDA20, 0x4E34, [0x89, 0xC8, 0xAC, 0x22, 0x27, 0x5A, 0x01, 0x0B]}; enum IID IID_INetSharingPortMappingProps = {0x24B7E9B5, 0xE38F, 0x4685, [0x85, 0x1B, 0x00, 0x89, 0x2C, 0xF5, 0xF9, 0x40]}; enum IID IID_INetSharingPrivateConnectionColle = {0x38AE69E0, 0x4409, 0x402A, [0xA2, 0xCB, 0xE9, 0x65, 0xC7, 0x27, 0xF8, 0x40]}; enum IID IID_INetSharingPublicConnectionCollec = {0x7D7A6355, 0xF372, 0x4971, [0xA1, 0x49, 0xBF, 0xC9, 0x27, 0xBE, 0x76, 0x2A]}; enum IID IID_INewShortcutHookA = {0x000214E1, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_INewShortcutHookW = {0x000214F7, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_INewWDEvents = {0x0751C551, 0x7568, 0x41C9, [0x8E, 0x5B, 0xE2, 0x2E, 0x38, 0x91, 0x92, 0x36]}; enum IID IID_INotification = {0xC733E4A3, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_INotificationHelper = {0xC733E4AB, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_INotificationManager = {0x95531501, 0x8782, 0x4845, [0x90, 0x1D, 0x31, 0x2F, 0x36, 0xBA, 0x6C, 0x6E]}; enum IID IID_INotificationMgr = {0xC733E4A4, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_INotificationPing = {0xC733E4AC, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_INotificationProcessMgr0 = {0xC733E4AE, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_INotificationReport = {0xC733E4A7, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_INotificationRunning = {0xC733E4AD, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_INotificationSink = {0xC733E4A5, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_INotifyDBEvents = {0xDB526CC0, 0xD188, 0x11CD, [0xAD, 0x48, 0x00, 0xAA, 0x00, 0x3C, 0x9C, 0xB6]}; enum IID IID_INotifyReplica = {0x99180163, 0xDA16, 0x101A, [0x93, 0x5C, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_INotifyUI = {0xE5E8D401, 0x1A37, 0x4FBF, [0x88, 0x0C, 0x82, 0x6C, 0xC8, 0x95, 0x16, 0xFD]}; enum IID IID_IObjectAccessControl = {0x0C733AA3, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IObjectIdentity = {0xCA04B7E6, 0x0D21, 0x11D1, [0x8C, 0xC5, 0x00, 0xC0, 0x4F, 0xC2, 0xB0, 0x85]}; enum IID IID_IObjectManager = {0xD51351DF, 0x6394, 0x4236, [0x97, 0x83, 0x65, 0xED, 0x05, 0x63, 0x10, 0x68]}; enum IID IID_IObjectSafety = {0xCB5BDC81, 0x93C1, 0x11CF, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID IID_IObjectWithSite = {0xFC4801A3, 0x2BA9, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID IID_IObjMgr = {0x00BB2761, 0x6A77, 0x11D0, [0xA5, 0x35, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62]}; enum IID IID_IOInet = {0x79EAC9E0, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetBindClient = {0x79EAC9E2, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetBindInfo = {0x79EAC9E1, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetCache = {0x79EAC9EA, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetPriority = {0x79EAC9EB, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetProtocol = {0x79EAC9E4, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetProtocolInfo = {0x79EAC9EC, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetProtocolRoot = {0x79EAC9E3, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetProtocolSink = {0x79EAC9E5, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetSession = {0x79EAC967, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOInetThreadSwitch = {0x79EAC968, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IOldSyncMgrRegister = {0x894D8C55, 0xBDDF, 0x11D1, [0xB8, 0x5D, 0x00, 0xC0, 0x4F, 0xB9, 0x39, 0x81]}; enum IID IID_IOldSyncMgrSynchronize = {0x6295DF28, 0x35EE, 0x11D1, [0x87, 0x07, 0x00, 0xC0, 0x4F, 0xD9, 0x33, 0x27]}; enum IID IID_IOldSyncMgrSynchronizeCallback = {0x6295DF29, 0x35EE, 0x11D1, [0x87, 0x07, 0x00, 0xC0, 0x4F, 0xD9, 0x33, 0x27]}; enum IID IID_IOleAdviseHolder = {0x00000111, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleCache = {0x0000011E, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleCache2 = {0x00000128, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleCacheControl = {0x00000129, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleClientSite = {0x00000118, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleCommandTarget = {0xB722BCCB, 0x4E68, 0x101B, [0xA2, 0xBC, 0x00, 0xAA, 0x00, 0x40, 0x47, 0x70]}; enum IID IID_IOleContainer = {0x0000011B, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleControl = {0xB196B288, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IOleControlSite = {0xB196B289, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IOleDocument = {0xB722BCC5, 0x4E68, 0x101B, [0xA2, 0xBC, 0x00, 0xAA, 0x00, 0x40, 0x47, 0x70]}; enum IID IID_IOleDocumentSite = {0xB722BCC7, 0x4E68, 0x101B, [0xA2, 0xBC, 0x00, 0xAA, 0x00, 0x40, 0x47, 0x70]}; enum IID IID_IOleDocumentView = {0xB722BCC6, 0x4E68, 0x101B, [0xA2, 0xBC, 0x00, 0xAA, 0x00, 0x40, 0x47, 0x70]}; enum IID IID_IOleInPlaceActiveObject = {0x00000117, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleInPlaceFrame = {0x00000116, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleInPlaceObject = {0x00000113, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleInPlaceObjectWindowless = {0x1C2056CC, 0x5EF4, 0x101B, [0x8B, 0xC8, 0x00, 0xAA, 0x00, 0x3E, 0x3B, 0x29]}; enum IID IID_IOleInPlaceSite = {0x00000119, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleInPlaceSiteEx = {0x9C2CAD80, 0x3424, 0x11CF, [0xB6, 0x70, 0x00, 0xAA, 0x00, 0x4C, 0xD6, 0xD8]}; enum IID IID_IOleInPlaceSiteWindowless = {0x922EADA0, 0x3424, 0x11CF, [0xB6, 0x70, 0x00, 0xAA, 0x00, 0x4C, 0xD6, 0xD8]}; enum IID IID_IOleInPlaceUIWindow = {0x00000115, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleItemContainer = {0x0000011C, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleLink = {0x0000011D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleManager = {0x0000011F, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleObject = {0x00000112, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleParentUndoUnit = {0xA1FAF330, 0xEF97, 0x11CE, [0x9B, 0xC9, 0x00, 0xAA, 0x00, 0x60, 0x8E, 0x01]}; enum IID IID_IOlePresObj = {0x00000120, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOleUndoManager = {0xD001F200, 0xEF97, 0x11CE, [0x9B, 0xC9, 0x00, 0xAA, 0x00, 0x60, 0x8E, 0x01]}; enum IID IID_IOleUndoUnit = {0x894AD3B0, 0xEF97, 0x11CE, [0x9B, 0xC9, 0x00, 0xAA, 0x00, 0x60, 0x8E, 0x01]}; enum IID IID_IOleWindow = {0x00000114, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOmHistory = {0xFECEAAA2, 0x8405, 0x11CF, [0x8B, 0xA1, 0x00, 0xAA, 0x00, 0x47, 0x6D, 0xA6]}; enum IID IID_IOmNavigator = {0xFECEAAA5, 0x8405, 0x11CF, [0x8B, 0xA1, 0x00, 0xAA, 0x00, 0x47, 0x6D, 0xA6]}; enum IID IID_IOpaqueDataInfo = {0x000001A9, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IOpenRowset = {0x0C733A69, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IOplockStorage = {0x8D19C834, 0x8879, 0x11D1, [0x83, 0xE9, 0x00, 0xC0, 0x4F, 0xC2, 0xC6, 0xD4]}; enum IID IID_IOpsProfileSimple = {0x7DD1362C, 0x28B6, 0x11D2, [0xBC, 0xA7, 0x00, 0xC0, 0x4F, 0xD9, 0x29, 0xDB]}; enum IID IID_IOptionArray = {0x22B6D492, 0x0F88, 0x11D1, [0xBA, 0x19, 0x00, 0xC0, 0x4F, 0xD9, 0x12, 0xD0]}; enum IID IID_IOverlappedCompletion = {0x521A28F0, 0xE40B, 0x11CE, [0xB2, 0xC9, 0x00, 0xAA, 0x00, 0x68, 0x09, 0x37]}; enum IID IID_IOverlappedStream = {0x49384070, 0xE40A, 0x11CE, [0xB2, 0xC9, 0x00, 0xAA, 0x00, 0x68, 0x09, 0x37]}; enum IID IID_IParentRowset = {0x0C733AAA, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IParseDisplayName = {0x0000011A, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IParser = {0x186442B0, 0x472E, 0x11D1, [0x89, 0x52, 0x00, 0xC0, 0x4F, 0xD6, 0x11, 0xD7]}; enum IID IID_IParserSession = {0x186442B1, 0x472E, 0x11D1, [0x89, 0x52, 0x00, 0xC0, 0x4F, 0xD6, 0x11, 0xD7]}; enum IID IID_IParserTreeProperties = {0x186442B2, 0x472E, 0x11D1, [0x89, 0x52, 0x00, 0xC0, 0x4F, 0xD6, 0x11, 0xD7]}; enum IID IID_IParserVerify = {0x186442B3, 0x472E, 0x11D1, [0x89, 0x52, 0x00, 0xC0, 0x4F, 0xD6, 0x11, 0xD7]}; enum IID IID_IPassportClientServices = {0xB30F7305, 0x5967, 0x45D1, [0xB7, 0xBC, 0xD6, 0xEB, 0x71, 0x63, 0xD7, 0x70]}; enum IID IID_IPeerFactory = {0x6663F9D3, 0xB482, 0x11D1, [0x89, 0xC6, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4]}; enum IID IID_IPendingProxyConnection = {0xB68E5043, 0x3E3D, 0x4CC2, [0xB9, 0xC1, 0x5F, 0x8F, 0x88, 0xFE, 0xE8, 0x1C]}; enum IID IID_IPerPropertyBrowsing = {0x376BD3AA, 0x3845, 0x101B, [0x84, 0xED, 0x08, 0x00, 0x2B, 0x2E, 0xC7, 0x13]}; enum IID IID_IPerPropertyBrowsing2 = {0x51973C54, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IPersist = {0x0000010C, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IPersistentDataChannel = {0xA180E934, 0xD92A, 0x415D, [0x91, 0x44, 0x75, 0x9F, 0x80, 0x54, 0xE8, 0xF6]}; enum IID IID_IPersistFile = {0x0000010B, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IPersistFolder = {0x000214EA, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IPersistFolder2 = {0x1AC3D9F0, 0x175C, 0x11D1, [0x95, 0xBE, 0x00, 0x60, 0x97, 0x97, 0xEA, 0x4F]}; enum IID IID_IPersistFolder3 = {0xCEF04FDF, 0xFE72, 0x11D2, [0x87, 0xA5, 0x00, 0xC0, 0x4F, 0x68, 0x37, 0xCF]}; enum IID IID_IPersistHistory = {0x91A565C1, 0xE38F, 0x11D0, [0x94, 0xBF, 0x00, 0xA0, 0xC9, 0x05, 0x5C, 0xBF]}; enum IID IID_IPersistIDList = {0x1079ACFC, 0x29BD, 0x11D3, [0x8E, 0x0D, 0x00, 0xC0, 0x4F, 0x68, 0x37, 0xD5]}; enum IID IID_IPersistMemory = {0xBD1AE5E0, 0xA6AE, 0x11CE, [0xBD, 0x37, 0x50, 0x42, 0x00, 0xC1, 0x00, 0x00]}; enum IID IID_IPersistMoniker = {0x79EAC9C9, 0xBAF9, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IPersistNetConnection = {0xFAEDCF59, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IPersistPropertyBag = {0x37D84F60, 0x42CB, 0x11CE, [0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51]}; enum IID IID_IPersistPropertyBag2 = {0x22F55881, 0x280B, 0x11D0, [0xA8, 0xA9, 0x00, 0xA0, 0xC9, 0x0C, 0x20, 0x04]}; enum IID IID_IPersistQuery = {0x1A3114B8, 0xA62E, 0x11D0, [0xA6, 0xC5, 0x00, 0xA0, 0xC9, 0x06, 0xAF, 0x45]}; enum IID IID_IPersistStorage = {0x0000010A, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IPersistStream = {0x00000109, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IPersistStreamInit = {0x7FD52380, 0x4E07, 0x101B, [0xAE, 0x2D, 0x08, 0x00, 0x2B, 0x2E, 0xC7, 0x13]}; enum IID IID_IPhraseSink = {0xCC906FF0, 0xC058, 0x101A, [0xB5, 0x54, 0x08, 0x00, 0x2B, 0x33, 0xB0, 0xE6]}; enum IID IID_IPicture = {0x7BF80980, 0xBF32, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID IID_IPictureDisp = {0x7BF80981, 0xBF32, 0x101A, [0x8B, 0xBB, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID IID_IPipeByte = {0xDB2F3ACA, 0x2F86, 0x11D1, [0x8E, 0x04, 0x00, 0xC0, 0x4F, 0xB9, 0x98, 0x9A]}; enum IID IID_IPipeDouble = {0xDB2F3ACE, 0x2F86, 0x11D1, [0x8E, 0x04, 0x00, 0xC0, 0x4F, 0xB9, 0x98, 0x9A]}; enum IID IID_IPipeLong = {0xDB2F3ACC, 0x2F86, 0x11D1, [0x8E, 0x04, 0x00, 0xC0, 0x4F, 0xB9, 0x98, 0x9A]}; enum IID IID_IPointerInactive = {0x55980BA0, 0x35AA, 0x11CF, [0xB6, 0x71, 0x00, 0xAA, 0x00, 0x4C, 0xD6, 0xD8]}; enum IID IID_IPrimaryControlChannel = {0x1A2E8B62, 0x9012, 0x4BE6, [0x84, 0xAE, 0x32, 0xBD, 0x66, 0xBA, 0x65, 0x7A]}; enum IID IID_IPrint = {0xB722BCC9, 0x4E68, 0x101B, [0xA2, 0xBC, 0x00, 0xAA, 0x00, 0x40, 0x47, 0x70]}; enum IID IID_IPrintDialogCallback = {0x5852A2C3, 0x6530, 0x11D1, [0xB6, 0xA3, 0x00, 0x00, 0xF8, 0x75, 0x7B, 0xF9]}; enum IID IID_IPrintDialogServices = {0x509AAEDA, 0x5639, 0x11D1, [0xB6, 0xA1, 0x00, 0x00, 0xF8, 0x75, 0x7B, 0xF9]}; enum IID IID_IPrivacyServices = {0x3050F84B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IPrivateDispatch = {0x86AB4BBE, 0x65F6, 0x11D1, [0x8C, 0x13, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IPrivateUnknown = {0x89126BAB, 0x6EAD, 0x11D1, [0x8C, 0x18, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0x03]}; enum IID IID_IPrivSyncMgrSynchronizeInvoke = {0x6295DF2E, 0x35EE, 0x11D1, [0x87, 0x07, 0x00, 0xC0, 0x4F, 0xD9, 0x33, 0x27]}; enum IID IID_IProcessDebugManager = {0x51973C2F, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IProcessDebugManager32 = {0x51973C2F, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IProcessDebugManager64 = {0x56B9FC1C, 0x63A9, 0x4CC1, [0xAC, 0x21, 0x08, 0x7D, 0x69, 0xA1, 0x7F, 0xAB]}; enum IID IID_IProcessInitControl = {0x72380D55, 0x8D2B, 0x43A3, [0x85, 0x13, 0x2B, 0x6E, 0xF3, 0x14, 0x34, 0xE9]}; enum IID IID_IProfferService = {0xCB728B20, 0xF786, 0x11CE, [0x92, 0xAD, 0x00, 0xAA, 0x00, 0xA7, 0x4C, 0xD0]}; enum IID IID_IProgressDialog = {0xEBBC7C04, 0x315E, 0x11D2, [0xB6, 0x2F, 0x00, 0x60, 0x97, 0xDF, 0x5B, 0xD4]}; enum IID IID_IProgressNotify = {0xA9D758A0, 0x4617, 0x11CF, [0x95, 0xFC, 0x00, 0xAA, 0x00, 0x68, 0x0D, 0xB4]}; enum IID IID_IProgSink = {0x3050F371, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, [0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51]}; enum IID IID_IPropertyBag2 = {0x22F55882, 0x280B, 0x11D0, [0xA8, 0xA9, 0x00, 0xA0, 0xC9, 0x0C, 0x20, 0x04]}; enum IID IID_IPropertyBagEx = {0x20011801, 0x5DE6, 0x11D1, [0x8E, 0x38, 0x00, 0xC0, 0x4F, 0xB9, 0x38, 0x6D]}; enum IID IID_IPropertyFrame = {0xB196B28A, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IPropertyMap = {0xC733E4A2, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_IPropertyMapper = {0xB324B226, 0x41A0, 0x11D0, [0x8C, 0x91, 0x00, 0x20, 0xAF, 0x1D, 0x74, 0x0E]}; enum IID IID_IPropertyNotifySink = {0x9BFBBC02, 0xEFF1, 0x101A, [0x84, 0xED, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IPropertyPage = {0xB196B28D, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IPropertyPage2 = {0x01E44665, 0x24AC, 0x101B, [0x84, 0xED, 0x08, 0x00, 0x2B, 0x2E, 0xC7, 0x13]}; enum IID IID_IPropertyPageSite = {0xB196B28C, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IPropertySetContainer = {0xB4FFAE60, 0xA7CA, 0x11CD, [0xB5, 0x8B, 0x00, 0x00, 0x6B, 0x82, 0x91, 0x56]}; enum IID IID_IPropertySetStorage = {0x0000013A, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IPropertyStorage = {0x00000138, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IPropertyUI = {0x757A7D9F, 0x919A, 0x4118, [0x99, 0xD7, 0xDB, 0xB2, 0x08, 0xC8, 0xCC, 0x66]}; enum IID IID_IPropSheetPage = {0x000214F6, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IProvideClassInfo = {0xB196B283, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_IProvideClassInfo2 = {0xA6BC3AC0, 0xDBAA, 0x11CE, [0x9D, 0xE3, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51]}; enum IID IID_IProvideExpressionContexts = {0x51973C41, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IProvideMoniker = {0x0C733A4D, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IProvideMultipleClassInfo = {0xA7ABA9C1, 0x8983, 0x11CF, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID IID_IProxy = {0x00000027, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IProxyManager = {0x00000008, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IPSFactory = {0x00000009, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IPSFactoryBuffer = {0xD5F569D0, 0x593B, 0x101A, [0xB5, 0x69, 0x08, 0x00, 0x2B, 0x2D, 0xBF, 0x7A]}; enum IID IID_IPublishedApp = {0x1BC752E0, 0x9046, 0x11D1, [0xB8, 0xB3, 0x00, 0x60, 0x08, 0x05, 0x93, 0x82]}; enum IID IID_IPublishingWizard = {0xAA9198BB, 0xCCEC, 0x472D, [0xBE, 0xED, 0x19, 0xA4, 0xF6, 0x73, 0x3F, 0x7A]}; enum IID IID_IQualityControl = {0x6BC096AB, 0x0CE6, 0x11D1, [0xBA, 0xAE, 0x00, 0xC0, 0x4F, 0xC2, 0xE2, 0x0D]}; enum IID IID_IQuery = {0x0C733A51, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IQueryAssociations = {0xC46CA590, 0x3C3F, 0x11D2, [0xBE, 0xE6, 0x00, 0x00, 0xF8, 0x05, 0xCA, 0x57]}; enum IID IID_IQueryCancelAutoPlay = {0xDDEFE873, 0x6997, 0x4E68, [0xBE, 0x26, 0x39, 0xB6, 0x33, 0xAD, 0xBE, 0x12]}; enum IID IID_IQueryContinue = {0x7307055C, 0xB24A, 0x486B, [0x9F, 0x25, 0x16, 0x3E, 0x59, 0x7A, 0x28, 0xA9]}; enum IID IID_IQueryForm = {0x8CFCEE30, 0x39BD, 0x11D0, [0xB8, 0xD1, 0x00, 0xA0, 0x24, 0xAB, 0x2D, 0xBB]}; enum IID IID_IQueryFrame = {0x7E8C7C20, 0x7C9D, 0x11D0, [0x91, 0x3F, 0x00, 0xAA, 0x00, 0xC1, 0x6E, 0x65]}; enum IID IID_IQueryHandler = {0xA60CC73F, 0xE0FC, 0x11D0, [0x97, 0x50, 0x00, 0xA0, 0xC9, 0x06, 0xAF, 0x45]}; enum IID IID_IQueryInfo = {0x00021500, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IQuickActivate = {0xCF51ED10, 0x62FE, 0x11CF, [0xBF, 0x86, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0x36]}; enum IID IID_IRadioButton = {0x3050F69B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IRatingNotification = {0x639447BD, 0xB2D3, 0x44B9, [0x9F, 0xB0, 0x51, 0x0F, 0x23, 0xCB, 0x45, 0xE4]}; enum IID IID_IReadData = {0x0C733A6A, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IReadEvents = {0xF64AEFDE, 0x3376, 0x11D1, [0xBE, 0x5B, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0xBB]}; enum IID IID_IRecalcEngine = {0x3050F496, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IRecalcHost = {0x3050F497, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IRecalcHostDebug = {0x3050F5F7, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IRecalcProperty = {0x3050F5D6, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IReconcilableObject = {0x99180162, 0xDA16, 0x101A, [0x93, 0x5C, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IReconcileInitiator = {0x99180161, 0xDA16, 0x101A, [0x93, 0x5C, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IRecordInfo = {0x0000002F, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRedbookDiscMaster = {0xE3BC42CD, 0x4E5C, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID IID_IReferenceClock = {0x56A86897, 0x0AD4, 0x11CE, [0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70]}; enum IID IID_IRegisterProvider = {0x0C733AB9, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRegisterVirusScanEngine = {0x0825E060, 0xB961, 0x11CF, [0xAA, 0xFA, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x5C]}; enum IID IID_IReleaseMarshalBuffers = {0xEB0CB9E8, 0x7996, 0x11D2, [0x87, 0x2E, 0x00, 0x00, 0xF8, 0x08, 0x08, 0x59]}; enum IID IID_IRemoteCallBack = {0x8947C648, 0x3833, 0x11D1, [0x86, 0x82, 0x00, 0xC0, 0x4F, 0xBF, 0xE1, 0x71]}; enum IID IID_IRemoteComputer = {0x000214FE, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRemoteDebugApplication = {0x51973C30, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IRemoteDebugApplicationEvents = {0x51973C33, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IRemoteDebugApplicationEx = {0x51973C01, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IRemoteDebugApplicationThread = {0x51973C37, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_IRemoteDebugApplicationThreadEx = {0xB9B32B0C, 0x9147, 0x11D1, [0x94, 0xEA, 0x00, 0xC0, 0x4F, 0xA3, 0x02, 0xA1]}; enum IID IID_IRemoteDelaydC = {0x394540A0, 0x6FCF, 0x11D0, [0xAC, 0xE0, 0x00, 0x00, 0xF8, 0x01, 0x14, 0xD3]}; enum IID IID_IRemoteESP = {0xE99A04AB, 0xAB95, 0x11D0, [0xBE, 0x96, 0x00, 0xA0, 0xC9, 0x49, 0x89, 0xDE]}; enum IID IID_IRemoteFinder = {0x944AD532, 0xB09D, 0x11CE, [0xB5, 0x9C, 0x00, 0xAA, 0x00, 0x6C, 0xB3, 0x7D]}; enum IID IID_IRemoteStats = {0x944AD531, 0xB09D, 0x11CE, [0xB5, 0x9C, 0x00, 0xAA, 0x00, 0x6C, 0xB3, 0x7D]}; enum IID IID_IRequest = {0x6BC096A7, 0x0CE6, 0x11D1, [0xBA, 0xAE, 0x00, 0xC0, 0x4F, 0xC2, 0xE2, 0x0D]}; enum IID IID_IRequestHandler = {0x6BC096AA, 0x0CE6, 0x11D1, [0xBA, 0xAE, 0x00, 0xC0, 0x4F, 0xC2, 0xE2, 0x0D]}; enum IID IID_IRequestSource = {0x6BC096A9, 0x0CE6, 0x11D1, [0xBA, 0xAE, 0x00, 0xC0, 0x4F, 0xC2, 0xE2, 0x0D]}; enum IID IID_IRequestState = {0x6BC096BA, 0x0CE6, 0x11D1, [0xBA, 0xAE, 0x00, 0xC0, 0x4F, 0xC2, 0xE2, 0x0D]}; enum IID IID_IResolveShellLink = {0x5CD52983, 0x9449, 0x11D2, [0x96, 0x3A, 0x00, 0xC0, 0x4F, 0x79, 0xAD, 0xF0]}; enum IID IID_IRichEditOle = {0x00020D00, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRichEditOleCallback = {0x00020D03, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRootStorage = {0x00000012, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IROTData = {0xF29F6BC0, 0x5021, 0x11CE, [0xAA, 0x15, 0x00, 0x00, 0x69, 0x01, 0x29, 0x3F]}; enum IID IID_IRow = {0x0C733AB4, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowChange = {0x0C733AB5, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowInfo = {0x0C733AC1, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowPosition = {0x0C733A94, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowPositionChange = {0x0997A571, 0x126E, 0x11D0, [0x9F, 0x8A, 0x00, 0xA0, 0xC9, 0xA0, 0x63, 0x1E]}; enum IID IID_IRowSchemaChange = {0x0C733AAE, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowset = {0x0C733A7C, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetAsynch = {0x0C733A0F, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetBookmark = {0x0C733AC2, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetChange = {0x0C733A05, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetChapterMember = {0x0C733AA8, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetCopyRows = {0x0C733A6B, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetCurrentIndex = {0x0C733ABD, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetExactScroll = {0x0C733A7F, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetFind = {0x0C733A9D, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetIdentity = {0x0C733A09, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetIndex = {0x0C733A82, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetInfo = {0x0C733A55, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetKeys = {0x0C733A12, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetLocate = {0x0C733A7D, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetNewRowAfter = {0x0C733A71, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetNextRowset = {0x0C733A72, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetNotify = {0x0C733A83, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetQueryStatus = {0xA7AC77ED, 0xF8D7, 0x11CE, [0xA7, 0x98, 0x00, 0x20, 0xF8, 0x00, 0x80, 0x24]}; enum IID IID_IRowsetRefresh = {0x0C733AA9, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetResynch = {0x0C733A84, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetScroll = {0x0C733A7E, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetUpdate = {0x0C733A6D, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetView = {0x0C733A99, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetWatchAll = {0x0C733A73, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetWatchNotify = {0x0C733A44, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetWatchRegion = {0x0C733A45, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRowsetWithParameters = {0x0C733A6E, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IRpcChannel = {0x00000004, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRpcChannelBuffer = {0xD5F56B60, 0x593B, 0x101A, [0xB5, 0x69, 0x08, 0x00, 0x2B, 0x2D, 0xBF, 0x7A]}; enum IID IID_IRpcChannelBuffer2 = {0x594F31D0, 0x7F19, 0x11D0, [0xB1, 0x94, 0x00, 0xA0, 0xC9, 0x0D, 0xC8, 0xBF]}; enum IID IID_IRpcChannelBuffer3 = {0x25B15600, 0x0115, 0x11D0, [0xBF, 0x0D, 0x00, 0xAA, 0x00, 0xB8, 0xDF, 0xD2]}; enum IID IID_IRpcHelper = {0x00000149, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRpcOptions = {0x00000144, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRpcProxy = {0x00000007, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRpcProxyBuffer = {0xD5F56A34, 0x593B, 0x101A, [0xB5, 0x69, 0x08, 0x00, 0x2B, 0x2D, 0xBF, 0x7A]}; enum IID IID_IRpcStub = {0x00000005, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRpcStubBuffer = {0xD5F56AFC, 0x593B, 0x101A, [0xB5, 0x69, 0x08, 0x00, 0x2B, 0x2D, 0xBF, 0x7A]}; enum IID IID_IRpcSyntaxNegotiate = {0x58A08519, 0x24C8, 0x4935, [0xB4, 0x82, 0x3F, 0xD8, 0x23, 0x33, 0x3A, 0x4F]}; enum IID IID_IRTC = {0x4811EA40, 0xB582, 0x11CE, [0xB5, 0xAF, 0x00, 0xAA, 0x00, 0x6C, 0xB3, 0x7D]}; enum IID IID_IRTCBuddy = {0xFCB136C8, 0x7B90, 0x4E0C, [0xBE, 0xFE, 0x56, 0xED, 0xF0, 0xBA, 0x6F, 0x1C]}; enum IID IID_IRTCBuddyEvent = {0xF36D755D, 0x17E6, 0x404E, [0x95, 0x4F, 0x0F, 0xC0, 0x75, 0x74, 0xC7, 0x8D]}; enum IID IID_IRTCClient = {0x07829E45, 0x9A34, 0x408E, [0xA0, 0x11, 0xBD, 0xDF, 0x13, 0x48, 0x7C, 0xD1]}; enum IID IID_IRTCClientEvent = {0x2B493B7A, 0x3CBA, 0x4170, [0x9C, 0x8B, 0x76, 0xA9, 0xDA, 0xCD, 0xD6, 0x44]}; enum IID IID_IRTCClientPresence = {0x11C3CBCC, 0x0744, 0x42D1, [0x96, 0x8A, 0x51, 0xAA, 0x1B, 0xB2, 0x74, 0xC6]}; enum IID IID_IRTCClientProvisioning = {0xB9F5CF06, 0x65B9, 0x4A80, [0xA0, 0xE6, 0x73, 0xCA, 0xE3, 0xEF, 0x38, 0x22]}; enum IID IID_IRTCCollection = {0xEC7C8096, 0xB918, 0x4044, [0x94, 0xF1, 0xE4, 0xFB, 0xA0, 0x36, 0x1D, 0x5C]}; enum IID IID_IRTCEnumBuddies = {0xF7296917, 0x5569, 0x4B3B, [0xB3, 0xAF, 0x98, 0xD1, 0x14, 0x4B, 0x2B, 0x87]}; enum IID IID_IRTCEnumParticipants = {0xFCD56F29, 0x4A4F, 0x41B2, [0xBA, 0x5C, 0xF5, 0xBC, 0xCC, 0x06, 0x0B, 0xF6]}; enum IID IID_IRTCEnumProfiles = {0x29B7C41C, 0xED82, 0x4BCA, [0x84, 0xAD, 0x39, 0xD5, 0x10, 0x1B, 0x58, 0xE3]}; enum IID IID_IRTCEnumWatchers = {0xA87D55D7, 0xDB74, 0x4ED1, [0x9C, 0xA4, 0x77, 0xA0, 0xE4, 0x1B, 0x41, 0x3E]}; enum IID IID_IRTCEventNotification = {0x13FA24C7, 0x5748, 0x4B21, [0x91, 0xF5, 0x73, 0x97, 0x60, 0x9C, 0xE7, 0x47]}; enum IID IID_IRTCIntensityEvent = {0x4C23BF51, 0x390C, 0x4992, [0xA4, 0x1D, 0x41, 0xEE, 0xC0, 0x5B, 0x2A, 0x4B]}; enum IID IID_IRTCMediaEvent = {0x099944FB, 0xBCDA, 0x453E, [0x8C, 0x41, 0xE1, 0x3D, 0xA2, 0xAD, 0xF7, 0xF3]}; enum IID IID_IRTCMessagingEvent = {0xD3609541, 0x1B29, 0x4DE5, [0xA4, 0xAD, 0x5A, 0xEB, 0xAF, 0x31, 0x95, 0x12]}; enum IID IID_IRTCParticipant = {0xAE86ADD5, 0x26B1, 0x4414, [0xAF, 0x1D, 0xB9, 0x4C, 0xD9, 0x38, 0xD7, 0x39]}; enum IID IID_IRTCParticipantStateChangeEvent = {0x09BCB597, 0xF0FA, 0x48F9, [0xB4, 0x20, 0x46, 0x8C, 0xEA, 0x7F, 0xDE, 0x04]}; enum IID IID_IRTCPresenceContact = {0x8B22F92C, 0xCD90, 0x42DB, [0xA7, 0x33, 0x21, 0x22, 0x05, 0xC3, 0xE3, 0xDF]}; enum IID IID_IRTCProfile = {0xD07ECA9E, 0x4062, 0x4DD4, [0x9E, 0x7D, 0x72, 0x2A, 0x49, 0xBA, 0x73, 0x03]}; enum IID IID_IRTCProfileEvent = {0xD6D5AB3B, 0x770E, 0x43E8, [0x80, 0x0A, 0x79, 0xB0, 0x62, 0x39, 0x5F, 0xCA]}; enum IID IID_IRTCRegistrationStateChangeEvent = {0x62D0991B, 0x50AB, 0x4F02, [0xB9, 0x48, 0xCA, 0x94, 0xF2, 0x6F, 0x8F, 0x95]}; enum IID IID_IRTCSession = {0x387C8086, 0x99BE, 0x42FB, [0x99, 0x73, 0x7C, 0x0F, 0xC0, 0xCA, 0x9F, 0xA8]}; enum IID IID_IRTCSessionOperationCompleteEven = {0xA6BFF4C0, 0xF7C8, 0x4D3C, [0x9A, 0x41, 0x35, 0x50, 0xF7, 0x8A, 0x95, 0xB0]}; enum IID IID_IRTCSessionStateChangeEvent = {0xB5BAD703, 0x5952, 0x48B3, [0x93, 0x21, 0x7F, 0x45, 0x00, 0x52, 0x15, 0x06]}; enum IID IID_IRTCWatcher = {0xC7CEDAD8, 0x346B, 0x4D1B, [0xAC, 0x02, 0xA2, 0x08, 0x8D, 0xF9, 0xBE, 0x4F]}; enum IID IID_IRTCWatcherEvent = {0xF30D7261, 0x587A, 0x424F, [0x82, 0x2C, 0x31, 0x27, 0x88, 0xF4, 0x35, 0x48]}; enum IID IID_IRunnableObject = {0x00000126, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IRunnableTask = {0x85788D00, 0x6807, 0x11D0, [0xB8, 0x10, 0x00, 0xC0, 0x4F, 0xD7, 0x06, 0xEC]}; enum IID IID_IRunningObjectTable = {0x00000010, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IScheduleGroup = {0xC733E4A6, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID IID_IScopedOperations = {0x0C733AB0, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IScriptEntry = {0x0AEE2A95, 0xBCBB, 0x11D0, [0x8C, 0x72, 0x00, 0xC0, 0x4F, 0xC2, 0xB0, 0x85]}; enum IID IID_IScriptErrorList = {0xF3470F24, 0x15FD, 0x11D2, [0xBB, 0x2E, 0x00, 0x80, 0x5F, 0xF7, 0xEF, 0xCA]}; enum IID IID_IScriptNode = {0x0AEE2A94, 0xBCBB, 0x11D0, [0x8C, 0x72, 0x00, 0xC0, 0x4F, 0xC2, 0xB0, 0x85]}; enum IID IID_IScriptScriptlet = {0x0AEE2A96, 0xBCBB, 0x11D0, [0x8C, 0x72, 0x00, 0xC0, 0x4F, 0xC2, 0xB0, 0x85]}; enum IID IID_IScrollBar = {0x3050F689, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISdo = {0x56BC53DE, 0x96DB, 0x11D1, [0xBF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]}; enum IID IID_ISdoCollection = {0x56BC53E2, 0x96DB, 0x11D1, [0xBF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]}; enum IID IID_ISdoDictionaryOld = {0xD432E5F4, 0x53D8, 0x11D2, [0x9A, 0x3A, 0x00, 0xC0, 0x4F, 0xB9, 0x98, 0xAC]}; enum IID IID_ISdoMachine = {0x479F6E75, 0x49A2, 0x11D2, [0x8E, 0xCA, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x19]}; enum IID IID_ISdoServiceControl = {0x479F6E74, 0x49A2, 0x11D2, [0x8E, 0xCA, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x19]}; enum IID IID_ISearch = {0xBA9239A4, 0x3DD5, 0x11D2, [0xBF, 0x8B, 0x00, 0xC0, 0x4F, 0xB9, 0x36, 0x61]}; enum IID IID_ISearchAssistantOC = {0x72423E8F, 0x8011, 0x11D2, [0xBE, 0x79, 0x00, 0xA0, 0xC9, 0xA8, 0x3D, 0xA1]}; enum IID IID_ISearchAssistantOC2 = {0x72423E8F, 0x8011, 0x11D2, [0xBE, 0x79, 0x00, 0xA0, 0xC9, 0xA8, 0x3D, 0xA2]}; enum IID IID_ISearchAssistantOC3 = {0x72423E8F, 0x8011, 0x11D2, [0xBE, 0x79, 0x00, 0xA0, 0xC9, 0xA8, 0x3D, 0xA3]}; enum IID IID_ISearchCommandExt = {0x1D2EFD50, 0x75CE, 0x11D1, [0xB7, 0x5A, 0x00, 0xA0, 0xC9, 0x05, 0x64, 0xFE]}; enum IID IID_ISearchContext = {0x09F656A2, 0x41AF, 0x480C, [0x88, 0xF7, 0x16, 0xCC, 0x0D, 0x16, 0x46, 0x15]}; enum IID IID_ISearches = {0x47C922A2, 0x3DD5, 0x11D2, [0xBF, 0x8B, 0x00, 0xC0, 0x4F, 0xB9, 0x36, 0x61]}; enum IID IID_ISearchQueryHits = {0xED8CE7E0, 0x106C, 0x11CE, [0x84, 0xE2, 0x00, 0xAA, 0x00, 0x4B, 0x99, 0x86]}; enum IID IID_ISecondaryControlChannel = {0xA23F9D10, 0x714C, 0x41FE, [0x84, 0x71, 0xFF, 0xB1, 0x9B, 0xC2, 0x84, 0x54]}; enum IID IID_ISecureUrlHost = {0xC81984C4, 0x74C8, 0x11D2, [0xBA, 0xA9, 0x00, 0xC0, 0x4F, 0xC2, 0x04, 0x0E]}; enum IID IID_ISecurityInfo = {0x0C733AA4, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ISegment = {0x3050F683, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISegmentList = {0x3050F605, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISegmentListIterator = {0x3050F692, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISelectionObject2 = {0x3050F7FC, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISelectionServices = {0x3050F684, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISelectionServicesListener = {0x3050F699, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISensLogon = {0xD597BAB3, 0x5B9F, 0x11D1, [0x8D, 0xD2, 0x00, 0xAA, 0x00, 0x4A, 0xBD, 0x5E]}; enum IID IID_ISensLogon2 = {0xD597BAB4, 0x5B9F, 0x11D1, [0x8D, 0xD2, 0x00, 0xAA, 0x00, 0x4A, 0xBD, 0x5E]}; enum IID IID_ISensNetwork = {0xD597BAB1, 0x5B9F, 0x11D1, [0x8D, 0xD2, 0x00, 0xAA, 0x00, 0x4A, 0xBD, 0x5E]}; enum IID IID_ISensOnNow = {0xD597BAB2, 0x5B9F, 0x11D1, [0x8D, 0xD2, 0x00, 0xAA, 0x00, 0x4A, 0xBD, 0x5E]}; enum IID IID_ISequenceNumber = {0x3050F6C1, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISequentialStream = {0x0C733A30, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IServerSecurity = {0x0000013E, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IServiceProvider = {0x6D5140C1, 0x7436, 0x11CE, [0x80, 0x34, 0x00, 0xAA, 0x00, 0x60, 0x09, 0xFA]}; enum IID IID_ISessionProperties = {0x0C733A85, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ISetNextStatement = {0x51973C03, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_ISharedAccessBeacon = {0xFAEDCF6B, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_ISharedAccessBeaconFinder = {0xFAEDCF67, 0x31FE, 0x11D1, [0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_IShellApp = {0xA3E14960, 0x935F, 0x11D1, [0xB8, 0xB8, 0x00, 0x60, 0x08, 0x05, 0x93, 0x82]}; enum IID IID_IShellBrowser = {0x000214E2, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellChangeNotify = {0xD82BE2B1, 0x5764, 0x11D0, [0xA9, 0x6E, 0x00, 0xC0, 0x4F, 0xD7, 0x05, 0xA2]}; enum IID IID_IShellCopyHookA = {0x000214EF, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellCopyHookW = {0x000214FC, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellDetails = {0x000214EC, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellDetails3 = {0xD2A105C0, 0x87D5, 0x11D1, [0x83, 0x91, 0x00, 0x00, 0xF8, 0x04, 0x61, 0xCF]}; enum IID IID_IShellDispatch = {0xD8F015C0, 0xC278, 0x11CE, [0xA4, 0x9E, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IShellDispatch2 = {0xA4C6892C, 0x3BA9, 0x11D2, [0x9D, 0xEA, 0x00, 0xC0, 0x4F, 0xB1, 0x61, 0x62]}; enum IID IID_IShellDispatch3 = {0x177160CA, 0xBB5A, 0x411C, [0x84, 0x1D, 0xBD, 0x38, 0xFA, 0xCD, 0xEA, 0xA0]}; enum IID IID_IShellDispatch4 = {0xEFD84B2D, 0x4BCF, 0x4298, [0xBE, 0x25, 0xEB, 0x54, 0x2A, 0x59, 0xFB, 0xDA]}; enum IID IID_IShellExecuteHookA = {0x000214F5, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellExecuteHookW = {0x000214FB, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellExtInit = {0x000214E8, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellFavoritesNameSpace = {0x55136804, 0xB2DE, 0x11D1, [0xB9, 0xF2, 0x00, 0xA0, 0xC9, 0x8B, 0xC5, 0x47]}; enum IID IID_IShellFolder = {0x000214E6, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellFolder2 = {0x93F2F68C, 0x1D1B, 0x11D3, [0xA3, 0x0E, 0x00, 0xC0, 0x4F, 0x79, 0xAB, 0xD1]}; enum IID IID_IShellFolderViewCB = {0x2047E320, 0xF2A9, 0x11CE, [0xAE, 0x65, 0x08, 0x00, 0x2B, 0x2E, 0x12, 0x62]}; enum IID IID_IShellFolderViewDual = {0xE7A1AF80, 0x4D96, 0x11CF, [0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85]}; enum IID IID_IShellFolderViewDual2 = {0x31C147B6, 0x0ADE, 0x4A3C, [0xB5, 0x14, 0xDD, 0xF9, 0x32, 0xEF, 0x6D, 0x17]}; enum IID IID_IShellIcon = {0x000214E5, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellIconOverlay = {0x7D688A70, 0xC613, 0x11D0, [0x99, 0x9B, 0x00, 0xC0, 0x4F, 0xD6, 0x55, 0xE1]}; enum IID IID_IShellIconOverlayIdentifier = {0x0C6C4200, 0xC589, 0x11D0, [0x99, 0x9A, 0x00, 0xC0, 0x4F, 0xD6, 0x55, 0xE1]}; enum IID IID_IShellImageData = {0xBFDEEC12, 0x8040, 0x4403, [0xA5, 0xEA, 0x9E, 0x07, 0xDA, 0xFC, 0xF5, 0x30]}; enum IID IID_IShellImageDataAbort = {0x53FB8E58, 0x50C0, 0x4003, [0xB4, 0xAA, 0x0C, 0x8D, 0xF2, 0x8E, 0x7F, 0x3A]}; enum IID IID_IShellImageDataFactory = {0x9BE8ED5C, 0xEDAB, 0x4D75, [0x90, 0xF3, 0xBD, 0x5B, 0xDB, 0xB2, 0x1C, 0x82]}; enum IID IID_IShellLinkA = {0x000214EE, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellLinkDataList = {0x45E2B4AE, 0xB1C3, 0x11D0, [0xB9, 0x2F, 0x00, 0xA0, 0xC9, 0x03, 0x12, 0xE1]}; enum IID IID_IShellLinkDual = {0x88A05C00, 0xF000, 0x11CE, [0x83, 0x50, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00]}; enum IID IID_IShellLinkDual2 = {0x317EE249, 0xF12E, 0x11D2, [0xB1, 0xE4, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x3E]}; enum IID IID_IShellLinkW = {0x000214F9, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellNameSpace = {0xE572D3C9, 0x37BE, 0x4AE2, [0x82, 0x5D, 0xD5, 0x21, 0x76, 0x3E, 0x31, 0x08]}; enum IID IID_IShellPropSheetExt = {0x000214E9, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellUIHelper = {0x729FE2F8, 0x1EA8, 0x11D1, [0x8F, 0x85, 0x00, 0xC0, 0x4F, 0xC2, 0xFB, 0xE1]}; enum IID IID_IShellView = {0x000214E3, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IShellView2 = {0x88E39E80, 0x3578, 0x11CF, [0xAE, 0x69, 0x08, 0x00, 0x2B, 0x2E, 0x12, 0x62]}; enum IID IID_IShellWindows = {0x85CB6900, 0x4D95, 0x11CF, [0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85]}; enum IID IID_ISimpleCommandCreator = {0x5E341AB7, 0x02D0, 0x11D1, [0x90, 0x0C, 0x00, 0xA0, 0xC9, 0x06, 0x37, 0x96]}; enum IID IID_ISimpleConnectionPoint = {0x51973C3E, 0xCB0C, 0x11D0, [0xB5, 0xC9, 0x00, 0xA0, 0x24, 0x4A, 0x0E, 0x7A]}; enum IID IID_ISimpleFrameSite = {0x742B0E01, 0x14E6, 0x101B, [0x91, 0x4E, 0x00, 0xAA, 0x00, 0x30, 0x0C, 0xAB]}; enum IID IID_ISliderBar = {0x3050F68D, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISniffStream = {0x4EF17940, 0x30E0, 0x11D0, [0xB7, 0x24, 0x00, 0xAA, 0x00, 0x6C, 0x1A, 0x01]}; enum IID IID_ISOAPRequest = {0xAD194525, 0x6E01, 0x4BCA, [0x92, 0x9C, 0x23, 0xC7, 0x38, 0x33, 0x36, 0xAF]}; enum IID IID_ISoftDistExt = {0xB15B8DC1, 0xC7E1, 0x11D0, [0x86, 0x80, 0x00, 0xAA, 0x00, 0xBD, 0xCB, 0x71]}; enum IID IID_ISourcesRowset = {0x0C733A1E, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ISpecialSystemProperties = {0x000001B9, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ISpecifyPropertyPages = {0xB196B28B, 0xBAB4, 0x101A, [0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07]}; enum IID IID_ISpinButton = {0x3050F68B, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISQLErrorInfo = {0x0C733A74, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IStandardActivator = {0x000001B8, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IStandardInfo = {0xF1D9C1A5, 0x9589, 0x40DD, [0xB6, 0x3D, 0x9B, 0xB0, 0xB3, 0x8A, 0x10, 0x22]}; enum IID IID_IStaticPortMapping = {0x6F10711F, 0x729B, 0x41E5, [0x93, 0xB8, 0xF2, 0x1D, 0x0F, 0x81, 0x8D, 0xF1]}; enum IID IID_IStaticPortMappingCollection = {0xCD1F3E77, 0x66D6, 0x4664, [0x82, 0xC7, 0x36, 0xDB, 0xB6, 0x41, 0xD0, 0xF1]}; enum IID IID_IStats = {0x944AD530, 0xB09D, 0x11CE, [0xB5, 0x9C, 0x00, 0xAA, 0x00, 0x6C, 0xB3, 0x7D]}; enum IID IID_IStdMarshalInfo = {0x00000018, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IStemmer = {0xEFBAF140, 0x7F42, 0x11CE, [0xBE, 0x57, 0x00, 0xAA, 0x00, 0x51, 0xFE, 0x20]}; enum IID IID_IStemSink = {0xFE77C330, 0x7F42, 0x11CE, [0xBE, 0x57, 0x00, 0xAA, 0x00, 0x51, 0xFE, 0x20]}; enum IID IID_IStorage = {0x0000000B, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IStream = {0x0000000C, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IStub = {0x00000026, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IStubManager = {0x00000006, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ISubDivisionProvider = {0x3050F4D2, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ISubscriptionAgentControl = {0xA89E8FF0, 0x70F4, 0x11D1, [0xBC, 0x7F, 0x00, 0xC0, 0x4F, 0xD9, 0x29, 0xDB]}; enum IID IID_ISubscriptionAgentEvents = {0xA89E8FF1, 0x70F4, 0x11D1, [0xBC, 0x7F, 0x00, 0xC0, 0x4F, 0xD9, 0x29, 0xDB]}; enum IID IID_ISubscriptionAgentShellExt = {0x81B184BA, 0xB302, 0x11D1, [0x85, 0x52, 0x00, 0xC0, 0x4F, 0xA3, 0x5C, 0x89]}; enum IID IID_ISubscriptionItem = {0xA97559F8, 0x6C4A, 0x11D1, [0xA1, 0xE8, 0x00, 0xC0, 0x4F, 0xC2, 0xFB, 0xE1]}; enum IID IID_ISubscriptionMgr = {0x085FB2C0, 0x0DF8, 0x11D1, [0x8F, 0x4B, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x3F]}; enum IID IID_ISubscriptionMgr2 = {0x614BC270, 0xAEDF, 0x11D1, [0xA1, 0xF9, 0x00, 0xC0, 0x4F, 0xC2, 0xFB, 0xE1]}; enum IID IID_ISubscriptionMgrPriv = {0xD66B399E, 0xAF1D, 0x11D1, [0xA1, 0xF9, 0x00, 0xC0, 0x4F, 0xC2, 0xFB, 0xE1]}; enum IID IID_ISubscriptionThrottler = {0x1E9B00E4, 0x9846, 0x11D1, [0xA1, 0xEE, 0x00, 0xC0, 0x4F, 0xC2, 0xFB, 0xE1]}; enum IID IID_ISupportErrorInfo = {0xDF0B3D60, 0x548F, 0x101B, [0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19]}; enum IID IID_ISurrogate = {0x00000022, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ISWbemDateTime = {0x5E97458A, 0xCF77, 0x11D3, [0xB3, 0x8F, 0x00, 0x10, 0x5A, 0x1F, 0x47, 0x3A]}; enum IID IID_ISWbemEventSource = {0x27D54D92, 0x0EBE, 0x11D2, [0x8B, 0x22, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemLastError = {0xD962DB84, 0xD4BB, 0x11D1, [0x8B, 0x09, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemLocator = {0x76A6415B, 0xCB41, 0x11D1, [0x8B, 0x02, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemMethod = {0x422E8E90, 0xD955, 0x11D1, [0x8B, 0x09, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemMethodSet = {0xC93BA292, 0xD955, 0x11D1, [0x8B, 0x09, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemNamedValue = {0x76A64164, 0xCB41, 0x11D1, [0x8B, 0x02, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemNamedValueSet = {0xCF2376EA, 0xCE8C, 0x11D1, [0x8B, 0x05, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemObject = {0x76A6415A, 0xCB41, 0x11D1, [0x8B, 0x02, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemObjectEx = {0x269AD56A, 0x8A67, 0x4129, [0xBC, 0x8C, 0x05, 0x06, 0xDC, 0xFE, 0x98, 0x80]}; enum IID IID_ISWbemObjectPath = {0x5791BC27, 0xCE9C, 0x11D1, [0x97, 0xBF, 0x00, 0x00, 0xF8, 0x1E, 0x84, 0x9C]}; enum IID IID_ISWbemObjectSet = {0x76A6415F, 0xCB41, 0x11D1, [0x8B, 0x02, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemPrivilege = {0x26EE67BD, 0x5804, 0x11D2, [0x8B, 0x4A, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemPrivilegeSet = {0x26EE67BF, 0x5804, 0x11D2, [0x8B, 0x4A, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemProperty = {0x1A388F98, 0xD4BA, 0x11D1, [0x8B, 0x09, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemPropertySet = {0xDEA0A7B2, 0xD4BA, 0x11D1, [0x8B, 0x09, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemQualifier = {0x79B05932, 0xD3B7, 0x11D1, [0x8B, 0x06, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemQualifierSet = {0x9B16ED16, 0xD3DF, 0x11D1, [0x8B, 0x08, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemRefreshableItem = {0x5AD4BF92, 0xDAAB, 0x11D3, [0xB3, 0x8F, 0x00, 0x10, 0x5A, 0x1F, 0x47, 0x3A]}; enum IID IID_ISWbemRefresher = {0x14D8250E, 0xD9C2, 0x11D3, [0xB3, 0x8F, 0x00, 0x10, 0x5A, 0x1F, 0x47, 0x3A]}; enum IID IID_ISWbemSecurity = {0xB54D66E6, 0x2287, 0x11D2, [0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemServices = {0x76A6415C, 0xCB41, 0x11D1, [0x8B, 0x02, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID IID_ISWbemServicesEx = {0xD2F68443, 0x85DC, 0x427E, [0x91, 0xD8, 0x36, 0x65, 0x54, 0xCC, 0x75, 0x4C]}; enum IID IID_ISWbemSink = {0x75718C9F, 0xF029, 0x11D1, [0xA1, 0xAC, 0x00, 0xC0, 0x4F, 0xB6, 0xC2, 0x23]}; enum IID IID_ISynchronize = {0x00000030, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ISynchronizeContainer = {0x00000033, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ISynchronizedCallBack = {0x74C26041, 0x70D1, 0x11D1, [0xB7, 0x5A, 0x00, 0xA0, 0xC9, 0x05, 0x64, 0xFE]}; enum IID IID_ISynchronizeEvent = {0x00000032, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ISynchronizeHandle = {0x00000031, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ISynchronizeMutex = {0x00000025, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ISyncMgrEnumItems = {0x6295DF2A, 0x35EE, 0x11D1, [0x87, 0x07, 0x00, 0xC0, 0x4F, 0xD9, 0x33, 0x27]}; enum IID IID_ISyncMgrRegisterCSC = {0x47681A61, 0xBC74, 0x11D2, [0xB5, 0xC5, 0x00, 0xC0, 0x4F, 0xB9, 0x39, 0x81]}; enum IID IID_ISyncMgrSynchronizeInvoke = {0x6295DF2C, 0x35EE, 0x11D1, [0x87, 0x07, 0x00, 0xC0, 0x4F, 0xD9, 0x33, 0x27]}; enum IID IID_ISyncSchedule = {0xF0E15899, 0xA700, 0x11D1, [0x98, 0x31, 0x00, 0xC0, 0x4F, 0xD9, 0x10, 0xDD]}; enum IID IID_ISyncScheduleMgr = {0xF0E15897, 0xA700, 0x11D1, [0x98, 0x31, 0x00, 0xC0, 0x4F, 0xD9, 0x10, 0xDD]}; enum IID IID_ISyncSchedulep = {0xF0E1589B, 0xA700, 0x11D1, [0x98, 0x31, 0x00, 0xC0, 0x4F, 0xD9, 0x10, 0xDD]}; enum IID IID_ITableCreation = {0x0C733ABC, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ITableDefinition = {0x0C733A86, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ITableDefinitionWithConstraints = {0x0C733AAB, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ITableRename = {0x0C733A77, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ITACDGroup = {0x5AFC3148, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITACDGroupEvent = {0x297F3032, 0xBD11, 0x11D1, [0xA0, 0xA7, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITAddress = {0xB1EFC386, 0x9355, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_ITAddress2 = {0xB0AE5D9B, 0xBE51, 0x46C9, [0xB0, 0xF7, 0xDF, 0xA8, 0xA2, 0x2A, 0x8B, 0xC4]}; enum IID IID_ITAddressCapabilities = {0x8DF232F5, 0x821B, 0x11D1, [0xBB, 0x5C, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITAddressDeviceSpecificEvent = {0x3ACB216B, 0x40BD, 0x487A, [0x86, 0x72, 0x5C, 0xE7, 0x7B, 0xD7, 0xE3, 0xA3]}; enum IID IID_ITAddressEvent = {0x831CE2D1, 0x83B5, 0x11D1, [0xBB, 0x5C, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITAddressTranslation = {0x0C4D8F03, 0x8DDB, 0x11D1, [0xA0, 0x9E, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITAddressTranslationInfo = {0xAFC15945, 0x8D40, 0x11D1, [0xA0, 0x9E, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITAgent = {0x5770ECE5, 0x4B27, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITAgentEvent = {0x5AFC314A, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITAgentHandler = {0x587E8C22, 0x9802, 0x11D1, [0xA0, 0xA4, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITAgentHandlerEvent = {0x297F3034, 0xBD11, 0x11D1, [0xA0, 0xA7, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITAgentSession = {0x5AFC3147, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITAgentSessionEvent = {0x5AFC314B, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITAllocatorProperties = {0xC1BC3C90, 0xBCFE, 0x11D1, [0x97, 0x45, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITAMMediaFormat = {0x0364EB00, 0x4A77, 0x11D1, [0xA6, 0x71, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xE8]}; enum IID IID_ITargetContainer = {0x7847EC01, 0x2BEC, 0x11D0, [0x82, 0xB4, 0x00, 0xA0, 0xC9, 0x0C, 0x29, 0xC5]}; enum IID IID_ITargetEmbedding = {0x548793C0, 0x9E74, 0x11CF, [0x96, 0x55, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0x23]}; enum IID IID_ITargetFrame = {0xD5F78C80, 0x5252, 0x11CF, [0x90, 0xFA, 0x00, 0xAA, 0x00, 0x42, 0x10, 0x6E]}; enum IID IID_ITargetFrame2 = {0x86D52E11, 0x94A8, 0x11D0, [0x82, 0xAF, 0x00, 0xC0, 0x4F, 0xD5, 0xAE, 0x38]}; enum IID IID_ITargetFramePriv = {0x9216E421, 0x2BF5, 0x11D0, [0x82, 0xB4, 0x00, 0xA0, 0xC9, 0x0C, 0x29, 0xC5]}; enum IID IID_ITargetNotify = {0x863A99A0, 0x21BC, 0x11D0, [0x82, 0xB4, 0x00, 0xA0, 0xC9, 0x0C, 0x29, 0xC5]}; enum IID IID_ITargetNotify2 = {0x3050F6B1, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ITaskAnalyzeCluster = {0x795737A1, 0xE13A, 0x45EB, [0x8D, 0xFD, 0x81, 0x85, 0xC4, 0xB7, 0xAD, 0x4E]}; enum IID IID_ITaskbarList = {0x56FDF342, 0xFD6D, 0x11D0, [0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90]}; enum IID IID_ITaskbarList2 = {0x602D4995, 0xB13A, 0x429B, [0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17]}; enum IID IID_ITaskCommitClusterChanges = {0x1BF12DDE, 0xF8B0, 0x49B1, [0xA4, 0x58, 0x67, 0x47, 0xDB, 0x78, 0x8A, 0x47]}; enum IID IID_ITaskCompareAndPushInformation = {0xD4F1C2AF, 0xB370, 0x49DE, [0x87, 0x68, 0x40, 0x10, 0xB5, 0x68, 0x63, 0x6C]}; enum IID IID_ITaskGatherClusterInfo = {0xE167965C, 0xC5D6, 0x493C, [0xA3, 0x43, 0x4C, 0x10, 0x5C, 0x01, 0xDD, 0xE7]}; enum IID IID_ITaskGatherInformation = {0xB9AAF3F8, 0x238E, 0x4993, [0xBA, 0x31, 0x14, 0x85, 0x98, 0x04, 0xF9, 0x2C]}; enum IID IID_ITaskGatherNodeInfo = {0xF19A2E01, 0x2CB3, 0x47B4, [0x8F, 0x5D, 0xB9, 0x77, 0x17, 0x6B, 0x45, 0xC8]}; enum IID IID_ITaskGetDomains = {0xDFCB4ACD, 0xC4DB, 0x4DB4, [0x8E, 0xBB, 0x1D, 0xD0, 0x7A, 0x9D, 0x5B, 0x82]}; enum IID IID_ITaskGetDomainsCallback = {0x85402E44, 0x6834, 0x41DF, [0x85, 0x90, 0x01, 0x82, 0x7D, 0x12, 0x4E, 0x1B]}; enum IID IID_ITaskLoginDomain = {0x76AD8E51, 0x53C3, 0x4347, [0x89, 0x5D, 0x6C, 0x30, 0xF4, 0x13, 0x93, 0x74]}; enum IID IID_ITaskLoginDomainCallback = {0xEFAF3C43, 0x7A8F, 0x469B, [0xB8, 0xBB, 0xC8, 0x0C, 0x57, 0x47, 0xCE, 0x05]}; enum IID IID_ITaskManager = {0x16116694, 0xDFC5, 0x470B, [0xAC, 0x12, 0x46, 0xFB, 0xB0, 0x1C, 0xEF, 0x10]}; enum IID IID_ITaskPollingCallback = {0x49E92395, 0x66AF, 0x4ADD, [0xA4, 0x1E, 0x43, 0x51, 0x2C, 0xB5, 0x19, 0xB3]}; enum IID IID_ITaskVerifyIPAddress = {0x0C95E1B1, 0x0CFF, 0x4740, [0x8A, 0xBD, 0x69, 0x91, 0x2D, 0x10, 0x5B, 0xD1]}; enum IID IID_ITASRTerminalEvent = {0xEE016A02, 0x4FA9, 0x467C, [0x93, 0x3F, 0x5A, 0x15, 0xB1, 0x23, 0x77, 0xD7]}; enum IID IID_ITAttributeList = {0x5037FB82, 0xCAE9, 0x11D0, [0x8D, 0x58, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITAudioDeviceControl = {0x6C0AB6C5, 0x21E3, 0x11D3, [0xA5, 0x77, 0x00, 0xC0, 0x4F, 0x8E, 0xF6, 0xE3]}; enum IID IID_ITAudioSettings = {0x6C0AB6C6, 0x21E3, 0x11D3, [0xA5, 0x77, 0x00, 0xC0, 0x4F, 0x8E, 0xF6, 0xE3]}; enum IID IID_ITAutomatedPhoneControl = {0x1EE1AF0E, 0x6159, 0x4A61, [0xB7, 0x9B, 0x6A, 0x4B, 0xA3, 0xFC, 0x9D, 0xFC]}; enum IID IID_ITBasicAudioTerminal = {0xB1EFC38D, 0x9355, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_ITBasicCallControl = {0xB1EFC389, 0x9355, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_ITBasicCallControl2 = {0x161A4A56, 0x1E99, 0x4B3F, [0xA4, 0x6A, 0x16, 0x8F, 0x38, 0xA5, 0xEE, 0x4C]}; enum IID IID_ITCallHub = {0xA3C1544E, 0x5B92, 0x11D1, [0x8F, 0x4E, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITCallHubEvent = {0xA3C15451, 0x5B92, 0x11D1, [0x8F, 0x4E, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITCallInfo = {0x350F85D1, 0x1227, 0x11D3, [0x83, 0xD4, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITCallInfo2 = {0x94D70CA6, 0x7AB0, 0x4DAA, [0x81, 0xCA, 0xB8, 0xF8, 0x64, 0x3F, 0xAE, 0xC1]}; enum IID IID_ITCallInfoChangeEvent = {0x5D4B65F9, 0xE51C, 0x11D1, [0xA0, 0x2F, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITCallingCard = {0x0C4D8F00, 0x8DDB, 0x11D1, [0xA0, 0x9E, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITCallMediaEvent = {0xFF36B87F, 0xEC3A, 0x11D0, [0x8E, 0xE4, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITCallNotificationEvent = {0x895801DF, 0x3DD6, 0x11D1, [0x8F, 0x30, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITCallQualityControl = {0xFE1D8AE0, 0xEDC4, 0x49B5, [0x8F, 0x8C, 0x4D, 0xE4, 0x0F, 0x9C, 0xDF, 0xAF]}; enum IID IID_ITCallStateEvent = {0x62F47097, 0x95C9, 0x11D0, [0x83, 0x5D, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_ITCollection = {0x5EC5ACF2, 0x9C02, 0x11D0, [0x83, 0x62, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_ITCollection2 = {0xE6DDDDA5, 0xA6D3, 0x48FF, [0x87, 0x37, 0xD3, 0x2F, 0xC4, 0xD9, 0x54, 0x77]}; enum IID IID_ITConferenceBlob = {0xC259D7AA, 0xC8AB, 0x11D0, [0x8D, 0x58, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITConnection = {0x8FA381D4, 0xC8C2, 0x11D0, [0x8D, 0x58, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITcpipProperties = {0x98133271, 0x4B20, 0x11D1, [0xAB, 0x01, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E]}; enum IID IID_ITCustomTone = {0x357AD764, 0xB3C6, 0x4B2A, [0x8F, 0xA5, 0x07, 0x22, 0x82, 0x7A, 0x92, 0x54]}; enum IID IID_ITDetectTone = {0x961F79BD, 0x3097, 0x49DF, [0xA1, 0xD6, 0x90, 0x9B, 0x77, 0xE8, 0x9C, 0xA0]}; enum IID IID_ITDigitDetectionEvent = {0x80D3BFAC, 0x57D9, 0x11D2, [0xA0, 0x4A, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITDigitGenerationEvent = {0x80D3BFAD, 0x57D9, 0x11D2, [0xA0, 0x4A, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITDigitsGatheredEvent = {0xE52EC4C1, 0xCBA3, 0x441A, [0x9E, 0x6A, 0x93, 0xCB, 0x90, 0x9E, 0x97, 0x24]}; enum IID IID_ITDirectory = {0x34621D6C, 0x6CFF, 0x11D1, [0xAF, 0xF7, 0x00, 0xC0, 0x4F, 0xC3, 0x1F, 0xEE]}; enum IID IID_ITDirectoryObject = {0x34621D6E, 0x6CFF, 0x11D1, [0xAF, 0xF7, 0x00, 0xC0, 0x4F, 0xC3, 0x1F, 0xEE]}; enum IID IID_ITDirectoryObjectConference = {0xF1029E5D, 0xCB5B, 0x11D0, [0x8D, 0x59, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITDirectoryObjectUser = {0x34621D6F, 0x6CFF, 0x11D1, [0xAF, 0xF7, 0x00, 0xC0, 0x4F, 0xC3, 0x1F, 0xEE]}; enum IID IID_ITDispatchMapper = {0xE9225295, 0xC759, 0x11D1, [0xA0, 0x2B, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITemplatePrinter = {0x3050F6B4, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ITemplatePrinter2 = {0x3050F83F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ITFileTerminalEvent = {0xE4A7FBAC, 0x8C17, 0x4427, [0x9F, 0x55, 0x9F, 0x58, 0x9A, 0xC8, 0xAF, 0x00]}; enum IID IID_ITFileTrack = {0x31CA6EA9, 0xC08A, 0x4BEA, [0x88, 0x11, 0x8E, 0x9C, 0x1B, 0xA3, 0xEA, 0x3A]}; enum IID IID_ITfLangBarAddIn = {0xC9ADDAC3, 0x15CB, 0x4957, [0xB9, 0x3C, 0xDB, 0x08, 0x73, 0xFF, 0x98, 0xBB]}; enum IID IID_ITFormatControl = {0x6C0AB6C1, 0x21E3, 0x11D3, [0xA5, 0x77, 0x00, 0xC0, 0x4F, 0x8E, 0xF6, 0xE3]}; enum IID IID_ITForwardInformation = {0x449F659E, 0x88A3, 0x11D1, [0xBB, 0x5D, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITForwardInformation2 = {0x5229B4ED, 0xB260, 0x4382, [0x8E, 0x1A, 0x5D, 0xF3, 0xA8, 0xA4, 0xCC, 0xC0]}; enum IID IID_ITfSpeechUIServer = {0x90E9A944, 0x9244, 0x489F, [0xA7, 0x8F, 0xDE, 0x67, 0xAF, 0xC0, 0x13, 0xA7]}; enum IID IID_IThumbnailCapture = {0x4EA39266, 0x7211, 0x409F, [0xB6, 0x22, 0xF6, 0x3D, 0xBD, 0x16, 0xC5, 0x33]}; enum IID IID_IThumbnailExtractor = {0x969DC708, 0x5C76, 0x11D1, [0x8D, 0x86, 0x00, 0x00, 0xF8, 0x04, 0xB0, 0x57]}; enum IID IID_ITILSConfig = {0x34621D72, 0x6CFF, 0x11D1, [0xAF, 0xF7, 0x00, 0xC0, 0x4F, 0xC3, 0x1F, 0xEE]}; enum IID IID_ITIMEActiveElementCollection = {0x403E2540, 0x4520, 0x11D3, [0x93, 0xAB, 0x00, 0xA0, 0xC9, 0x67, 0xA4, 0x38]}; enum IID IID_ITimeAndNoticeControl = {0xBC0BF6AE, 0x8878, 0x11D1, [0x83, 0xE9, 0x00, 0xC0, 0x4F, 0xC2, 0xC6, 0xD4]}; enum IID IID_ITIMEAnimationElement = {0xA74F14B1, 0xB6A2, 0x430A, [0xA5, 0xE8, 0x1F, 0x4E, 0x53, 0xF7, 0x10, 0xFE]}; enum IID IID_ITIMEAnimationElement2 = {0x29CE8661, 0xBD43, 0x421A, [0xB6, 0x16, 0xE9, 0xB3, 0x1F, 0x33, 0xA5, 0x72]}; enum IID IID_ITIMEBodyElement = {0x8C90E348, 0xEC0A, 0x4229, [0x90, 0xB0, 0xE5, 0x7D, 0x2C, 0xA4, 0x5C, 0xCB]}; enum IID IID_ITIMEDMusicPlayerObject = {0x407954F5, 0x2BAB, 0x4CFA, [0x95, 0x4D, 0x24, 0x9F, 0x9F, 0xCE, 0x43, 0xA1]}; enum IID IID_ITIMEDVDPlayerObject = {0x3AF7AB68, 0x4F29, 0x462C, [0xAA, 0x6E, 0x58, 0x72, 0x44, 0x88, 0x99, 0xE3]}; enum IID IID_ITIMEElement = {0x1C2EF64E, 0xF07D, 0x4338, [0x97, 0x71, 0x91, 0x54, 0x49, 0x1C, 0xD8, 0xB9]}; enum IID IID_ITIMEElementCollection = {0x50ABC224, 0x6D53, 0x4F83, [0x91, 0x35, 0x24, 0x40, 0xA4, 0x1B, 0x7B, 0xC8]}; enum IID IID_ITIMEFactory = {0xCD51E446, 0x3006, 0x434F, [0x90, 0xE2, 0xE3, 0x7E, 0x8F, 0xB8, 0xCA, 0x8F]}; enum IID IID_ITIMEMediaElement = {0x47A6972F, 0xAE65, 0x4A6B, [0xAE, 0x63, 0xD0, 0xC1, 0xD5, 0x30, 0x7B, 0x58]}; enum IID IID_ITIMEMediaElement2 = {0x9EE29400, 0x7EE6, 0x453A, [0x85, 0xB3, 0x4E, 0xC2, 0x8E, 0x03, 0x05, 0xB4]}; enum IID IID_ITIMEMediaPlayer = {0xEA4A95BE, 0xACC9, 0x4BF0, [0x85, 0xA4, 0x1B, 0xF3, 0xC5, 0x1E, 0x43, 0x1C]}; enum IID IID_ITIMEMediaPlayerAudio = {0xFFAACFDA, 0xB374, 0x4F22, [0xAC, 0x9A, 0xC5, 0xBB, 0x94, 0x37, 0xCB, 0x56]}; enum IID IID_ITIMEMediaPlayerControl = {0x897A99E7, 0xF386, 0x45C8, [0xB5, 0x1B, 0x3A, 0x25, 0xBB, 0xCB, 0xBA, 0x69]}; enum IID IID_ITIMEMediaPlayerNetwork = {0xB9987FCA, 0x7FBB, 0x4015, [0xBD, 0x3D, 0x74, 0x18, 0x60, 0x55, 0x14, 0xDA]}; enum IID IID_ITIMEMediaPlayerSite = {0xBF0571ED, 0x344F, 0x4F58, [0x82, 0xC7, 0x74, 0x31, 0xED, 0x0F, 0xD8, 0x34]}; enum IID IID_ITIMEPlayItem = {0x2A6096D9, 0x2CE0, 0x47DC, [0xA8, 0x13, 0x90, 0x99, 0xA2, 0x46, 0x63, 0x09]}; enum IID IID_ITIMEPlayItem2 = {0x4262CD38, 0x6BDC, 0x40A4, [0xBC, 0x50, 0x4C, 0xC5, 0x03, 0x66, 0xE7, 0x02]}; enum IID IID_ITIMEPlayList = {0xE9B75B62, 0xDD97, 0x4B19, [0x8F, 0xD9, 0x96, 0x46, 0x29, 0x29, 0x52, 0xE0]}; enum IID IID_ITimer = {0x3050F360, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ITimerService = {0x3050F35F, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ITimerSink = {0x3050F361, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ITIMEState = {0xDD5EC62A, 0x9D77, 0x4573, [0x80, 0xA8, 0x75, 0x85, 0x94, 0xE6, 0x9C, 0xEA]}; enum IID IID_ITIMETransitionElement = {0xF383D66F, 0x5E68, 0x4FC2, [0xB6, 0x41, 0x03, 0x67, 0x2B, 0x54, 0x3A, 0x49]}; enum IID IID_ITLegacyAddressMediaControl = {0xAB493640, 0x4C0B, 0x11D2, [0xA0, 0x46, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITLegacyAddressMediaControl2 = {0xB0EE512B, 0xA531, 0x409E, [0x9D, 0xD9, 0x40, 0x99, 0xFE, 0x86, 0xC7, 0x38]}; enum IID IID_ITLegacyCallMediaControl = {0xD624582F, 0xCC23, 0x4436, [0xB8, 0xA5, 0x47, 0xC6, 0x25, 0xC8, 0x04, 0x5D]}; enum IID IID_ITLegacyCallMediaControl2 = {0x57CA332D, 0x7BC2, 0x44F1, [0xA6, 0x0C, 0x93, 0x6F, 0xE8, 0xD7, 0xCE, 0x73]}; enum IID IID_ITLegacyWaveSupport = {0x207823EA, 0xE252, 0x11D2, [0xB7, 0x7E, 0x00, 0x80, 0xC7, 0x13, 0x53, 0x81]}; enum IID IID_ITLocalParticipant = {0x39CBF055, 0xF77A, 0x11D2, [0xA8, 0x24, 0x00, 0xC0, 0x4F, 0x8E, 0xF6, 0xE3]}; enum IID IID_ITLocationInfo = {0x0C4D8EFF, 0x8DDB, 0x11D1, [0xA0, 0x9E, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITMedia = {0x0CC1F053, 0xCAEB, 0x11D0, [0x8D, 0x58, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITMediaCollection = {0x6A8E16A2, 0x0ABC, 0x11D1, [0x97, 0x6D, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITMediaControl = {0xC445DDE8, 0x5199, 0x4BC7, [0x98, 0x07, 0x5F, 0xFB, 0x92, 0xE4, 0x2E, 0x09]}; enum IID IID_ITMediaPlayback = {0x627E8AE6, 0xAE4C, 0x4A69, [0xBB, 0x63, 0x2A, 0xD6, 0x25, 0x40, 0x4B, 0x77]}; enum IID IID_ITMediaRecord = {0xF5DD4592, 0x5476, 0x4CC1, [0x9D, 0x4D, 0xFA, 0xD3, 0xEE, 0xFE, 0x7D, 0xB2]}; enum IID IID_ITMediaSupport = {0xB1EFC384, 0x9355, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_ITMSPAddress = {0xEE3BD600, 0x3868, 0x11D2, [0xA0, 0x45, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITMultiTrackTerminal = {0xFE040091, 0xADE8, 0x4072, [0x95, 0xC9, 0xBF, 0x7D, 0xE8, 0xC5, 0x4B, 0x44]}; enum IID IID_ITParticipant = {0x5899B820, 0x5A34, 0x11D2, [0x95, 0xA0, 0x00, 0xA0, 0x24, 0x4D, 0x22, 0x98]}; enum IID IID_ITParticipantControl = {0xD2EE6684, 0x5A34, 0x11D2, [0x95, 0xA0, 0x00, 0xA0, 0x24, 0x4D, 0x22, 0x98]}; enum IID IID_ITParticipantEvent = {0x8BB35070, 0x2DAD, 0x11D3, [0xA5, 0x80, 0x00, 0xC0, 0x4F, 0x8E, 0xF6, 0xE3]}; enum IID IID_ITParticipantSubStreamControl = {0x2C679108, 0x5A35, 0x11D2, [0x95, 0xA0, 0x00, 0xA0, 0x24, 0x4D, 0x22, 0x98]}; enum IID IID_ITPhone = {0x09D48DB4, 0x10CC, 0x4388, [0x9D, 0xE7, 0xA8, 0x46, 0x56, 0x18, 0x97, 0x5A]}; enum IID IID_ITPhoneDeviceSpecificEvent = {0x63FFB2A6, 0x872B, 0x4CD3, [0xA5, 0x01, 0x32, 0x6E, 0x8F, 0xB4, 0x0A, 0xF7]}; enum IID IID_ITPhoneEvent = {0x8F942DD8, 0x64ED, 0x4AAF, [0xA7, 0x7D, 0xB2, 0x3D, 0xB0, 0x83, 0x7E, 0xAD]}; enum IID IID_ITPluggableTerminalClassInfo = {0x41757F4A, 0xCF09, 0x4B34, [0xBC, 0x96, 0x0A, 0x79, 0xD2, 0x39, 0x00, 0x76]}; enum IID IID_ITPluggableTerminalClassRegistrat = {0x924A3723, 0xA00B, 0x4F5F, [0x9F, 0xEE, 0x8E, 0x9A, 0xEB, 0x9E, 0x82, 0xAA]}; enum IID IID_ITPluggableTerminalEventSink = {0x6E0887BE, 0xBA1A, 0x492E, [0xBD, 0x10, 0x40, 0x20, 0xEC, 0x5E, 0x33, 0xE0]}; enum IID IID_ITPluggableTerminalEventSinkRegis = {0xF7115709, 0xA216, 0x4957, [0xA7, 0x59, 0x06, 0x0A, 0xB3, 0x2A, 0x90, 0xD1]}; enum IID IID_ITPluggableTerminalInitializatio = {0xAED6483C, 0x3304, 0x11D2, [0x86, 0xF1, 0x00, 0x60, 0x08, 0xB0, 0xE5, 0xD2]}; enum IID IID_ITPluggableTerminalSuperclassInf = {0x6D54E42C, 0x4625, 0x4359, [0xA6, 0xF7, 0x63, 0x19, 0x99, 0x10, 0x7E, 0x05]}; enum IID IID_ITPluggableTerminalSuperclassRegi = {0x60D3C08A, 0xC13E, 0x4195, [0x9A, 0xB0, 0x8D, 0xE7, 0x68, 0x09, 0x0F, 0x25]}; enum IID IID_ITPrivateEvent = {0x0E269CD0, 0x10D4, 0x4121, [0x9C, 0x22, 0x9C, 0x85, 0xD6, 0x25, 0x65, 0x0D]}; enum IID IID_ITQOSApplicationID = {0xE8C89D27, 0xA3BD, 0x47D5, [0xA6, 0xFC, 0xD2, 0xAE, 0x40, 0xCD, 0xBC, 0x6E]}; enum IID IID_ITQOSEvent = {0xCFA3357C, 0xAD77, 0x11D1, [0xBB, 0x68, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITQueue = {0x5AFC3149, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITQueueEvent = {0x297F3033, 0xBD11, 0x11D1, [0xA0, 0xA7, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITrackFile = {0x8790C948, 0xA30B, 0x11D0, [0x8C, 0xAB, 0x00, 0xC0, 0x4F, 0xD9, 0x0F, 0x85]}; enum IID IID_ITransaction = {0x0FB15084, 0xAF41, 0x11CE, [0xBD, 0x2B, 0x20, 0x4C, 0x4F, 0x4F, 0x50, 0x20]}; enum IID IID_ITransaction2 = {0x34021548, 0x0065, 0x11D3, [0xBA, 0xC1, 0x00, 0xC0, 0x4F, 0x79, 0x7B, 0xE2]}; enum IID IID_ITransactionCloner = {0x02656950, 0x2152, 0x11D0, [0x94, 0x4C, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x6E]}; enum IID IID_ITransactionDispenser = {0x3A6AD9E1, 0x23B9, 0x11CF, [0xAD, 0x60, 0x00, 0xAA, 0x00, 0xA7, 0x4C, 0xCD]}; enum IID IID_ITransactionJoin = {0x0C733A5E, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ITransactionLocal = {0x0C733A5F, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ITransactionObject = {0x0C733A60, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ITransactionOptions = {0x3A6AD9E0, 0x23B9, 0x11CF, [0xAD, 0x60, 0x00, 0xAA, 0x00, 0xA7, 0x4C, 0xCD]}; enum IID IID_ITransactionOutcomeEvents = {0x3A6AD9E2, 0x23B9, 0x11CF, [0xAD, 0x60, 0x00, 0xAA, 0x00, 0xA7, 0x4C, 0xCD]}; enum IID IID_ITransmt = {0xB3C9F150, 0xB593, 0x11CE, [0xB5, 0xB0, 0x00, 0xAA, 0x00, 0x6C, 0xB3, 0x7D]}; enum IID IID_ITravelEntry = {0xF46EDB3B, 0xBC2F, 0x11D0, [0x94, 0x12, 0x00, 0xAA, 0x00, 0xA3, 0xEB, 0xD3]}; enum IID IID_ITravelLog = {0x66A9CB08, 0x4802, 0x11D2, [0xA5, 0x61, 0x00, 0xA0, 0xC9, 0x2D, 0xBF, 0xE8]}; enum IID IID_ITravelLogClient = {0x3050F67A, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ITravelLogClient2 = {0x0AD364CE, 0xADCB, 0x11D3, [0x82, 0x69, 0x00, 0x80, 0x5F, 0xC7, 0x32, 0xC0]}; enum IID IID_ITravelLogEntry = {0x7EBFDD87, 0xAD18, 0x11D3, [0xA4, 0xC5, 0x00, 0xC0, 0x4F, 0x72, 0xD6, 0xB8]}; enum IID IID_ITravelLogEx = {0x3050F679, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_ITravelLogStg = {0x7EBFDD80, 0xAD18, 0x11D3, [0xA4, 0xC5, 0x00, 0xC0, 0x4F, 0x72, 0xD6, 0xB8]}; enum IID IID_ITRendezvous = {0x34621D6B, 0x6CFF, 0x11D1, [0xAF, 0xF7, 0x00, 0xC0, 0x4F, 0xC3, 0x1F, 0xEE]}; enum IID IID_ITRequest = {0xAC48FFDF, 0xF8C4, 0x11D1, [0xA0, 0x30, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITRequestEvent = {0xAC48FFDE, 0xF8C4, 0x11D1, [0xA0, 0x30, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITridentEventSink = {0x1DC9CA50, 0x06EF, 0x11D2, [0x84, 0x15, 0x00, 0x60, 0x08, 0xC3, 0xFB, 0xFC]}; enum IID IID_ITrkForceOwnership = {0xA2531F44, 0xC67D, 0x11D0, [0x8C, 0xB1, 0x00, 0xC0, 0x4F, 0xD9, 0x0F, 0x85]}; enum IID IID_ITrkRestoreNotify = {0xD0056F6B, 0xE2A0, 0x11D0, [0xB1, 0xC2, 0x00, 0xC0, 0x4F, 0xB9, 0x38, 0x6D]}; enum IID IID_ITrkRestoreParser = {0x755939E3, 0xE381, 0x11D0, [0xB1, 0xC5, 0x00, 0xC0, 0x4F, 0xB9, 0x38, 0x6D]}; enum IID IID_ITrusteeAdmin = {0x0C733AA1, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ITrusteeGroupAdmin = {0x0C733AA2, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_ITScriptableAudioFormat = {0xB87658BD, 0x3C59, 0x4F64, [0xBE, 0x74, 0xAE, 0xDE, 0x3E, 0x86, 0xA8, 0x1E]}; enum IID IID_ITSdp = {0x9B2719D8, 0xB696, 0x11D0, [0xA4, 0x89, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITStaticAudioTerminal = {0xA86B7871, 0xD14C, 0x48E6, [0x92, 0x2E, 0xA8, 0xD1, 0x5F, 0x98, 0x48, 0x00]}; enum IID IID_ITStream = {0xEE3BD605, 0x3868, 0x11D2, [0xA0, 0x45, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITStreamControl = {0xEE3BD604, 0x3868, 0x11D2, [0xA0, 0x45, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITStreamQualityControl = {0x6C0AB6C2, 0x21E3, 0x11D3, [0xA5, 0x77, 0x00, 0xC0, 0x4F, 0x8E, 0xF6, 0xE3]}; enum IID IID_ITSubStream = {0xEE3BD608, 0x3868, 0x11D2, [0xA0, 0x45, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITSubStreamControl = {0xEE3BD607, 0x3868, 0x11D2, [0xA0, 0x45, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITTAPI = {0xB1EFC382, 0x9355, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_ITTAPI2 = {0x54FBDC8C, 0xD90F, 0x4DAD, [0x96, 0x95, 0xB3, 0x73, 0x09, 0x7F, 0x09, 0x4B]}; enum IID IID_ITTAPICallCenter = {0x5AFC3154, 0x4BCC, 0x11D1, [0xBF, 0x80, 0x00, 0x80, 0x5F, 0xC1, 0x47, 0xD3]}; enum IID IID_ITTAPIEventNotification = {0xEDDB9426, 0x3B91, 0x11D1, [0x8F, 0x30, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITTAPIObjectEvent = {0xF4854D48, 0x937A, 0x11D1, [0xBB, 0x58, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID IID_ITTAPIObjectEvent2 = {0x359DDA6E, 0x68CE, 0x4383, [0xBF, 0x0B, 0x16, 0x91, 0x33, 0xC4, 0x1B, 0x46]}; enum IID IID_ITTerminal = {0xB1EFC38A, 0x9355, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_ITTerminalControl = {0xAED6483B, 0x3304, 0x11D2, [0x86, 0xF1, 0x00, 0x60, 0x08, 0xB0, 0xE5, 0xD2]}; enum IID IID_ITTerminalManager = {0x7170F2DE, 0x9BE3, 0x11D0, [0xA0, 0x09, 0x00, 0xAA, 0x00, 0xB6, 0x05, 0xA4]}; enum IID IID_ITTerminalManager2 = {0xBB33DEC6, 0xB2C7, 0x46E6, [0x9E, 0xD1, 0x49, 0x8B, 0x91, 0xFA, 0x85, 0xAC]}; enum IID IID_ITTerminalSupport = {0xB1EFC385, 0x9355, 0x11D0, [0x83, 0x5C, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID IID_ITTerminalSupport2 = {0xF3EB39BC, 0x1B1F, 0x4E99, [0xA0, 0xC0, 0x56, 0x30, 0x5C, 0x4D, 0xD5, 0x91]}; enum IID IID_ITTime = {0x2652BB78, 0x1516, 0x11D1, [0x97, 0x71, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITTimeCollection = {0x0CC1F04F, 0xCAEB, 0x11D0, [0x8D, 0x58, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID IID_ITToneDetectionEvent = {0x407E0FAF, 0xD047, 0x4753, [0xB0, 0xC6, 0x8E, 0x06, 0x03, 0x73, 0xFE, 0xCD]}; enum IID IID_ITToneTerminalEvent = {0xE6F56009, 0x611F, 0x4945, [0xBB, 0xD2, 0x2D, 0x0C, 0xE5, 0x61, 0x20, 0x56]}; enum IID IID_ITTTSTerminalEvent = {0xD964788F, 0x95A5, 0x461D, [0xAB, 0x0C, 0xB9, 0x90, 0x0A, 0x6C, 0x27, 0x13]}; enum IID IID_ITypeChangeEvents = {0x00020410, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ITypeComp = {0x00020403, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ITypeFactory = {0x0000002E, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ITypeInfo = {0x00020401, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ITypeInfo2 = {0x00020412, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ITypeLib = {0x00020402, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ITypeLib2 = {0x00020411, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_ITypeMarshal = {0x0000002D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IUmiADSIPrivate = {0xCFCECB01, 0x3123, 0x4926, [0xB5, 0xE3, 0x62, 0x78, 0x08, 0x27, 0x26, 0x43]}; enum IID IID_IUniformResourceLocatorA = {0xFBF23B80, 0xE3F0, 0x101B, [0x84, 0x88, 0x00, 0xAA, 0x00, 0x3E, 0x56, 0xF8]}; enum IID IID_IUniformResourceLocatorW = {0xCABB0DA0, 0xDA57, 0x11CF, [0x99, 0x74, 0x00, 0x20, 0xAF, 0xD7, 0x97, 0x62]}; enum IID IID_IUnknown = {0x00000000, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IUnsecuredApartment = {0x1CFABA8C, 0x1523, 0x11D1, [0xAD, 0x79, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID IID_IUPnPDescriptionDocument = {0x11D1C1B2, 0x7DAA, 0x4C9E, [0x95, 0x95, 0x7F, 0x82, 0xED, 0x20, 0x6D, 0x1E]}; enum IID IID_IUPnPDescriptionDocumentCallback = {0x77394C69, 0x5486, 0x40D6, [0x9B, 0xC3, 0x49, 0x91, 0x98, 0x3E, 0x02, 0xDA]}; enum IID IID_IUPnPDevice = {0x3D44D0D1, 0x98C9, 0x4889, [0xAC, 0xD1, 0xF9, 0xD6, 0x74, 0xBF, 0x22, 0x21]}; enum IID IID_IUPnPDeviceControl = {0x204810BA, 0x73B2, 0x11D4, [0xBF, 0x42, 0x00, 0xB0, 0xD0, 0x11, 0x8B, 0x56]}; enum IID IID_IUPnPDeviceDocumentAccess = {0xE7772804, 0x3287, 0x418E, [0x90, 0x72, 0xCF, 0x2B, 0x47, 0x23, 0x89, 0x81]}; enum IID IID_IUPnPDeviceFinder = {0xADDA3D55, 0x6F72, 0x4319, [0xBF, 0xF9, 0x18, 0x60, 0x0A, 0x53, 0x9B, 0x10]}; enum IID IID_IUPnPDeviceFinderAddCallbackWithI = {0x983DFC0B, 0x1796, 0x44DF, [0x89, 0x75, 0xCA, 0x54, 0x5B, 0x62, 0x0E, 0xE5]}; enum IID IID_IUPnPDeviceFinderCallback = {0x415A984A, 0x88B3, 0x49F3, [0x92, 0xAF, 0x05, 0x08, 0xBE, 0xDF, 0x0D, 0x6C]}; enum IID IID_IUPnPDeviceHostICSSupport = {0x3FFC5AE5, 0xA66B, 0x499C, [0xA1, 0x80, 0xC7, 0x39, 0x3D, 0xB6, 0xBA, 0x8D]}; enum IID IID_IUPnPDeviceHostSetup = {0x6BD34909, 0x54E7, 0x4FBF, [0x85, 0x62, 0x7B, 0x89, 0x70, 0x9A, 0x58, 0x9A]}; enum IID IID_IUPnPDeviceProvider = {0x204810B8, 0x73B2, 0x11D4, [0xBF, 0x42, 0x00, 0xB0, 0xD0, 0x11, 0x8B, 0x56]}; enum IID IID_IUPnPDevices = {0xFDBC0C73, 0xBDA3, 0x4C66, [0xAC, 0x4F, 0xF2, 0xD9, 0x6F, 0xDA, 0xD6, 0x8C]}; enum IID IID_IUPnPEventSink = {0x204810B4, 0x73B2, 0x11D4, [0xBF, 0x42, 0x00, 0xB0, 0xD0, 0x11, 0x8B, 0x56]}; enum IID IID_IUPnPEventSource = {0x204810B5, 0x73B2, 0x11D4, [0xBF, 0x42, 0x00, 0xB0, 0xD0, 0x11, 0x8B, 0x56]}; enum IID IID_IUPnPNAT = {0xB171C812, 0xCC76, 0x485A, [0x94, 0xD8, 0xB6, 0xB3, 0xA2, 0x79, 0x4E, 0x99]}; enum IID IID_IUPnPPrivateCallbackHelper = {0x8DCC8327, 0xDBE9, 0x48E6, [0x84, 0x6C, 0x33, 0x72, 0x58, 0x65, 0xD5, 0x0C]}; enum IID IID_IUPnPPrivateDocumentCallbackHelp = {0x19432A8E, 0x4A32, 0x4860, [0xB8, 0xFB, 0x95, 0xB1, 0x11, 0x7C, 0xD4, 0xE5]}; enum IID IID_IUPnPPrivateServiceHelper2 = {0x340F4076, 0x6856, 0x48F9, [0xB3, 0xC4, 0x97, 0xB9, 0x1B, 0x68, 0xD7, 0x7E]}; enum IID IID_IUPnPRegistrar = {0x204810B6, 0x73B2, 0x11D4, [0xBF, 0x42, 0x00, 0xB0, 0xD0, 0x11, 0x8B, 0x56]}; enum IID IID_IUPnPReregistrar = {0x204810B7, 0x73B2, 0x11D4, [0xBF, 0x42, 0x00, 0xB0, 0xD0, 0x11, 0x8B, 0x56]}; enum IID IID_IUPnPService = {0xA295019C, 0xDC65, 0x47DD, [0x90, 0xDC, 0x7F, 0xE9, 0x18, 0xA1, 0xAB, 0x44]}; enum IID IID_IUPnPServiceCallback = {0x31FADCA9, 0xAB73, 0x464B, [0xB6, 0x7D, 0x5C, 0x1D, 0x0F, 0x83, 0xC8, 0xB8]}; enum IID IID_IUPnPServiceCallbackPrivate = {0x24EA2515, 0xF612, 0x4528, [0xBA, 0x82, 0x7B, 0xD3, 0xDB, 0xBA, 0xD3, 0x03]}; enum IID IID_IUPnPServices = {0x3F8C8E9E, 0x9A7A, 0x4DC8, [0xBC, 0x41, 0xFF, 0x31, 0xFA, 0x37, 0x49, 0x56]}; enum IID IID_IUrlHistoryNotify = {0xBC40BEC1, 0xC493, 0x11D0, [0x83, 0x1B, 0x00, 0xC0, 0x4F, 0xD5, 0xAE, 0x38]}; enum IID IID_IUrlHistoryStg = {0x3C374A41, 0xBAE4, 0x11CF, [0xBF, 0x7D, 0x00, 0xAA, 0x00, 0x69, 0x46, 0xEE]}; enum IID IID_IUrlHistoryStg2 = {0xAFA0DC11, 0xC313, 0x11D0, [0x83, 0x1A, 0x00, 0xC0, 0x4F, 0xD5, 0xAE, 0x38]}; enum IID IID_IUrlMon = {0x00000026, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IURLSearchHook = {0xAC60F6A0, 0x0FD9, 0x11D0, [0x99, 0xCB, 0x00, 0xC0, 0x4F, 0xD6, 0x44, 0x97]}; enum IID IID_IURLSearchHook2 = {0x5EE44DA4, 0x6D32, 0x46E3, [0x86, 0xBC, 0x07, 0x54, 0x0D, 0xED, 0xD0, 0xE0]}; enum IID IID_IUrlTrackingStg = {0xF2F8CBB3, 0xB040, 0x11D0, [0xBB, 0x16, 0x00, 0xC0, 0x4F, 0xB6, 0x6F, 0x63]}; enum IID IID_IUserEventTimer = {0x0F504B94, 0x6E42, 0x42E6, [0x99, 0xE0, 0xE2, 0x0F, 0xAF, 0xE5, 0x2A, 0xB4]}; enum IID IID_IUserEventTimerCallback = {0xE9EAD8E6, 0x2A25, 0x410E, [0x9B, 0x58, 0xA9, 0xFB, 0xEF, 0x1D, 0xD1, 0xA2]}; enum IID IID_IUserNotification = {0xBA9711BA, 0x5893, 0x4787, [0xA7, 0xE1, 0x41, 0x27, 0x71, 0x51, 0x55, 0x0B]}; enum IID IID_IUtilityButton = {0x3050F6AF, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID IID_IVariantChangeType = {0xA6EF9862, 0xC720, 0x11D0, [0x93, 0x37, 0x00, 0xA0, 0xC9, 0x0D, 0xCA, 0xA9]}; enum IID IID_IVersionHost = {0x667115AC, 0xDC02, 0x11D1, [0xBA, 0x57, 0x00, 0xC0, 0x4F, 0xC2, 0x04, 0x0E]}; enum IID IID_IVersionVector = {0x4EB01410, 0xDB1A, 0x11D1, [0xBA, 0x53, 0x00, 0xC0, 0x4F, 0xC2, 0x04, 0x0E]}; enum IID IID_IViewChapter = {0x0C733A98, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IViewFilter = {0x0C733A9B, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IViewObject = {0x0000010D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IViewObject2 = {0x00000127, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IViewObjectEx = {0x3AF24292, 0x0C96, 0x11CE, [0xA0, 0xCF, 0x00, 0xAA, 0x00, 0x60, 0x0A, 0xB8]}; enum IID IID_IViewRowset = {0x0C733A97, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IViewSort = {0x0C733A9A, 0x2A1C, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID IID_IVirusScanEngine = {0x083DB180, 0xB4A8, 0x11CF, [0xAA, 0xFA, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x5C]}; enum IID IID_IVirusScanner = {0x4589BEE0, 0xB4B1, 0x11CF, [0xAA, 0xFA, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x5C]}; enum IID IID_IWaitMultiple = {0x0000002B, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IWbemAddressResolution = {0xF7CE2E12, 0x8C90, 0x11D1, [0x9E, 0x7B, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_IWbemBackupRestore = {0xC49E32C7, 0xBC8B, 0x11D2, [0x85, 0xD4, 0x00, 0x10, 0x5A, 0x1F, 0x83, 0x04]}; enum IID IID_IWbemBackupRestoreEx = {0xA359DEC5, 0xE813, 0x4834, [0x8A, 0x2A, 0xBA, 0x7F, 0x1D, 0x77, 0x7D, 0x76]}; enum IID IID_IWbemCallResult = {0x44ACA675, 0xE8FC, 0x11D0, [0xA0, 0x7C, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemCallStatus = {0x4212DC47, 0x142E, 0x4C6C, [0xBC, 0x49, 0x6C, 0xA2, 0x32, 0xDD, 0x09, 0x59]}; enum IID IID_IWbemClassObject = {0xDC12A681, 0x737F, 0x11CF, [0x88, 0x4D, 0x00, 0xAA, 0x00, 0x4B, 0x2E, 0x24]}; enum IID IID_IWbemClientConnectionTransport = {0xA889C72A, 0xFCC1, 0x4A9E, [0xAF, 0x61, 0xED, 0x07, 0x13, 0x33, 0xFB, 0x5B]}; enum IID IID_IWbemClientTransport = {0xF7CE2E11, 0x8C90, 0x11D1, [0x9E, 0x7B, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID IID_IWbemConfigure = {0x9A368276, 0x26CF, 0x11D0, [0xAD, 0x3C, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID IID_IWbemConfigureRefresher = {0x49353C92, 0x516B, 0x11D1, [0xAE, 0xA6, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemConnectorLogin = {0xD8EC9CB1, 0xB135, 0x4F10, [0x8B, 0x1B, 0xC7, 0x18, 0x8B, 0xB0, 0xD1, 0x86]}; enum IID IID_IWbemConstructClassObject = {0x9EF76194, 0x70D5, 0x11D1, [0xAD, 0x90, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID IID_IWbemContext = {0x44ACA674, 0xE8FC, 0x11D0, [0xA0, 0x7C, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemDecoupledBasicEventProvider = {0x86336D20, 0xCA11, 0x4786, [0x9E, 0xF1, 0xBC, 0x8A, 0x94, 0x6B, 0x42, 0xFC]}; enum IID IID_IWbemDecoupledEventSink = {0xCD94EBF2, 0xE622, 0x11D2, [0x9C, 0xB3, 0x00, 0x10, 0x5A, 0x1F, 0x48, 0x01]}; enum IID IID_IWbemDecoupledRegistrar = {0x1005CBCF, 0xE64F, 0x4646, [0xBC, 0xD3, 0x3A, 0x08, 0x9D, 0x8A, 0x84, 0xB4]}; enum IID IID_IWbemEventConsumerProvider = {0xE246107A, 0xB06E, 0x11D0, [0xAD, 0x61, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID IID_IWbemEventConsumerProviderEx = {0x17CF534A, 0xD8A3, 0x4AD0, [0xAC, 0x92, 0x5E, 0x3D, 0x01, 0x71, 0x71, 0x51]}; enum IID IID_IWbemEventProvider = {0xE245105B, 0xB06E, 0x11D0, [0xAD, 0x61, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID IID_IWbemEventProviderQuerySink = {0x580ACAF8, 0xFA1C, 0x11D0, [0xAD, 0x72, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID IID_IWbemEventProviderSecurity = {0x631F7D96, 0xD993, 0x11D2, [0xB3, 0x39, 0x00, 0x10, 0x5A, 0x1F, 0x4A, 0xAF]}; enum IID IID_IWbemEventSink = {0x3AE0080A, 0x7E3A, 0x4366, [0xBF, 0x89, 0x0F, 0xEE, 0xDC, 0x93, 0x16, 0x59]}; enum IID IID_IWbemHiPerfEnum = {0x2705C288, 0x79AE, 0x11D2, [0xB3, 0x48, 0x00, 0x10, 0x5A, 0x1F, 0x81, 0x77]}; enum IID IID_IWbemHiPerfProvider = {0x49353C93, 0x516B, 0x11D1, [0xAE, 0xA6, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemLevel1Login = {0xF309AD18, 0xD86A, 0x11D0, [0xA0, 0x75, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemLocator = {0xDC12A687, 0x737F, 0x11CF, [0x88, 0x4D, 0x00, 0xAA, 0x00, 0x4B, 0x2E, 0x24]}; enum IID IID_IWbemObjectAccess = {0x49353C9A, 0x516B, 0x11D1, [0xAE, 0xA6, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemObjectSink = {0x7C857801, 0x7381, 0x11CF, [0x88, 0x4D, 0x00, 0xAA, 0x00, 0x4B, 0x2E, 0x24]}; enum IID IID_IWbemObjectTextSrc = {0xBFBF883A, 0xCAD7, 0x11D3, [0xA1, 0x1B, 0x00, 0x10, 0x5A, 0x1F, 0x51, 0x5A]}; enum IID IID_IWbemPath = {0x3BC15AF2, 0x736C, 0x477E, [0x9E, 0x51, 0x23, 0x8A, 0xF8, 0x66, 0x7D, 0xCC]}; enum IID IID_IWbemPathKeyList = {0x9AE62877, 0x7544, 0x4BB0, [0xAA, 0x26, 0xA1, 0x38, 0x24, 0x65, 0x9E, 0xD6]}; enum IID IID_IWbemPropertyProvider = {0xCE61E841, 0x65BC, 0x11D0, [0xB6, 0xBD, 0x00, 0xAA, 0x00, 0x32, 0x40, 0xC7]}; enum IID IID_IWbemProviderIdentity = {0x631F7D97, 0xD993, 0x11D2, [0xB3, 0x39, 0x00, 0x10, 0x5A, 0x1F, 0x4A, 0xAF]}; enum IID IID_IWbemProviderInit = {0x1BE41572, 0x91DD, 0x11D1, [0xAE, 0xB2, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemProviderInitSink = {0x1BE41571, 0x91DD, 0x11D1, [0xAE, 0xB2, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemQualifierSet = {0xDC12A680, 0x737F, 0x11CF, [0x88, 0x4D, 0x00, 0xAA, 0x00, 0x4B, 0x2E, 0x24]}; enum IID IID_IWbemQuery = {0x81166F58, 0xDD98, 0x11D3, [0xA1, 0x20, 0x00, 0x10, 0x5A, 0x1F, 0x51, 0x5A]}; enum IID IID_IWbemRawSdAccessor = {0xC1E2D759, 0xCABD, 0x11D3, [0xA1, 0x1B, 0x00, 0x10, 0x5A, 0x1F, 0x51, 0x5A]}; enum IID IID_IWbemRefresher = {0x49353C99, 0x516B, 0x11D1, [0xAE, 0xA6, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemServices = {0x9556DC99, 0x828C, 0x11CF, [0xA3, 0x7E, 0x00, 0xAA, 0x00, 0x32, 0x40, 0xC7]}; enum IID IID_IWbemShutdown = {0xB7B31DF9, 0xD515, 0x11D3, [0xA1, 0x1C, 0x00, 0x10, 0x5A, 0x1F, 0x51, 0x5A]}; enum IID IID_IWbemStatusCodeText = {0xEB87E1BC, 0x3233, 0x11D2, [0xAE, 0xC9, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20]}; enum IID IID_IWbemTransport = {0x553FE584, 0x2156, 0x11D0, [0xB6, 0xAE, 0x00, 0xAA, 0x00, 0x32, 0x40, 0xC7]}; enum IID IID_IWbemUnboundObjectSink = {0xE246107B, 0xB06E, 0x11D0, [0xAD, 0x61, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID IID_IWBScriptControl = {0xA5170870, 0x0CF8, 0x11D1, [0x8B, 0x91, 0x00, 0x80, 0xC7, 0x44, 0xF3, 0x89]}; enum IID IID_IWCContextMenuCallback = {0x97DEDE64, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IWCPropertySheetCallback = {0x97DEDE60, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IWCWizard97Callback = {0x97DEDE67, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IWCWizardCallback = {0x97DEDE62, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IWebBridge = {0xAE24FDAD, 0x03C6, 0x11D1, [0x8B, 0x76, 0x00, 0x80, 0xC7, 0x44, 0xF3, 0x89]}; enum IID IID_IWebBrowser = {0xEAB22AC1, 0x30C1, 0x11CF, [0xA7, 0xEB, 0x00, 0x00, 0xC0, 0x5B, 0xAE, 0x0B]}; enum IID IID_IWebBrowser2 = {0xD30C1661, 0xCDAF, 0x11D0, [0x8A, 0x3E, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E]}; enum IID IID_IWebBrowserApp = {0x0002DF05, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID IID_IWebWizardExtension = {0x0E6B3F66, 0x98D1, 0x48C0, [0xA2, 0x22, 0xFB, 0xDE, 0x74, 0xE2, 0xFB, 0xC5]}; enum IID IID_IWebWizardHost = {0x18BCC359, 0x4990, 0x4BFB, [0xB9, 0x51, 0x3C, 0x83, 0x70, 0x2B, 0xE5, 0xF9]}; enum IID IID_IWEExtendContextMenu = {0x97DEDE65, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IWEExtendPropertySheet = {0x97DEDE61, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IWEExtendWizard = {0x97DEDE63, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IWEExtendWizard97 = {0x97DEDE68, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_IWEInvokeCommand = {0x97DEDE66, 0xFC6B, 0x11CF, [0xB5, 0xF5, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x05]}; enum IID IID_Iwfolders = {0xBAE31F98, 0x1B81, 0x11D2, [0xA9, 0x7A, 0x00, 0xC0, 0x4F, 0x8E, 0xCB, 0x02]}; enum IID IID_IWindowForBindingUI = {0x79EAC9D5, 0xBAFA, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IWinInetHttpInfo = {0x79EAC9D8, 0xBAFA, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IWinInetInfo = {0x79EAC9D6, 0xBAFA, 0x11CE, [0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B]}; enum IID IID_IWizardExtension = {0xC02EA696, 0x86CC, 0x491E, [0x9B, 0x23, 0x74, 0x39, 0x4A, 0x04, 0x44, 0xA8]}; enum IID IID_IWizardSite = {0x88960F5B, 0x422F, 0x4E7B, [0x80, 0x13, 0x73, 0x41, 0x53, 0x81, 0xC3, 0xC3]}; enum IID IID_IWMIExtension = {0xADC1F06E, 0x5C7E, 0x11D2, [0x8B, 0x74, 0x00, 0x10, 0x4B, 0x2A, 0xFB, 0x41]}; enum IID IID_IWordBreaker = {0xD53552C8, 0x77E3, 0x101A, [0xB5, 0x52, 0x08, 0x00, 0x2B, 0x33, 0xB0, 0xE6]}; enum IID IID_IWordSink = {0xCC907054, 0xC058, 0x101A, [0xB5, 0x54, 0x08, 0x00, 0x2B, 0x33, 0xB0, 0xE6]}; enum IID IID_IWrappedProtocol = {0x53C84785, 0x8425, 0x4DC5, [0x97, 0x1B, 0xE5, 0x8D, 0x9C, 0x19, 0xF9, 0xB6]}; enum IID IID_IXMLAttribute = {0xD4D4A0FC, 0x3B73, 0x11D1, [0xB2, 0xB4, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0x96]}; enum IID IID_IXMLDocument = {0xF52E2B61, 0x18A1, 0x11D1, [0xB1, 0x05, 0x00, 0x80, 0x5F, 0x49, 0x91, 0x6B]}; enum IID IID_IXMLDocument2 = {0x2B8DE2FE, 0x8D2D, 0x11D1, [0xB2, 0xFC, 0x00, 0xC0, 0x4F, 0xD9, 0x15, 0xA9]}; enum IID IID_IXMLDOMAttribute = {0x2933BF85, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMCDATASection = {0x2933BF8A, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMCharacterData = {0x2933BF84, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMComment = {0x2933BF88, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMDocument = {0x2933BF81, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMDocumentFragment = {0x3EFAA413, 0x272F, 0x11D2, [0x83, 0x6F, 0x00, 0x00, 0xF8, 0x7A, 0x77, 0x82]}; enum IID IID_IXMLDOMDocumentType = {0x2933BF8B, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMElement = {0x2933BF86, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMEntity = {0x2933BF8D, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMEntityReference = {0x2933BF8E, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMImplementation = {0x2933BF8F, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMNamedNodeMap = {0x2933BF83, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMNode = {0x2933BF80, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMNodeList = {0x2933BF82, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMNotation = {0x2933BF8C, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMParseError = {0x3EFAA426, 0x272F, 0x11D2, [0x83, 0x6F, 0x00, 0x00, 0xF8, 0x7A, 0x77, 0x82]}; enum IID IID_IXMLDOMProcessingInstruction = {0x2933BF89, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDOMText = {0x2933BF87, 0x7B36, 0x11D2, [0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60]}; enum IID IID_IXMLDSOControl = {0x310AFA62, 0x0575, 0x11D2, [0x9C, 0xA9, 0x00, 0x60, 0xB0, 0xEC, 0x3D, 0x39]}; enum IID IID_IXMLElement = {0x3F7F31AC, 0xE15F, 0x11D0, [0x9C, 0x25, 0x00, 0xC0, 0x4F, 0xC9, 0x9C, 0x8E]}; enum IID IID_IXMLElement2 = {0x2B8DE2FF, 0x8D2D, 0x11D1, [0xB2, 0xFC, 0x00, 0xC0, 0x4F, 0xD9, 0x15, 0xA9]}; enum IID IID_IXMLElementCollection = {0x65725580, 0x9B5D, 0x11D0, [0x9B, 0xFE, 0x00, 0xC0, 0x4F, 0xC9, 0x9C, 0x8E]}; enum IID IID_IXMLError = {0x948C5AD3, 0xC58D, 0x11D0, [0x9C, 0x0B, 0x00, 0xC0, 0x4F, 0xC9, 0x9C, 0x8E]}; enum IID IID_IXMLGenericParse = {0xE4E23071, 0x4D07, 0x11D2, [0xAE, 0x76, 0x00, 0x80, 0xC7, 0x3B, 0xC1, 0x99]}; enum IID IID_IXMLHttpRequest = {0xED8C108D, 0x4349, 0x11D2, [0x91, 0xA4, 0x00, 0xC0, 0x4F, 0x79, 0x69, 0xE8]}; enum IID IID_IXMLNodeFactory = {0xD242361F, 0x51A0, 0x11D2, [0x9C, 0xAF, 0x00, 0x60, 0xB0, 0xEC, 0x3D, 0x39]}; enum IID IID_IXMLNodeSource = {0xD242361D, 0x51A0, 0x11D2, [0x9C, 0xAF, 0x00, 0x60, 0xB0, 0xEC, 0x3D, 0x39]}; enum IID IID_IXMLParser = {0xD242361E, 0x51A0, 0x11D2, [0x9C, 0xAF, 0x00, 0x60, 0xB0, 0xEC, 0x3D, 0x39]}; enum IID IID_IXTLRuntime = {0x3EFAA425, 0x272F, 0x11D2, [0x83, 0x6F, 0x00, 0x00, 0xF8, 0x7A, 0x77, 0x82]}; enum IID IID_StdOle = {0x00020430, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID KSDATAFORMAT_SUBTYPE_DIRECTMUSIC = {0x1A82F8BC, 0x3F8B, 0x11D2, [0xB7, 0x74, 0x00, 0x60, 0x08, 0x33, 0x16, 0xC1]}; enum IID KSDATAFORMAT_SUBTYPE_MIDI = {0x1D262760, 0xE957, 0x11CF, [0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00]}; enum IID LIBID_Accessibility = {0x1EA4DBF0, 0x3C3B, 0x11CF, [0x81, 0x0C, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71]}; enum IID LIBID_ActiveIMM = {0x4955DD30, 0xB159, 0x11D0, [0x8F, 0xCF, 0x00, 0xAA, 0x00, 0x6B, 0xCC, 0x59]}; enum IID LIBID_ADs = {0x97D25DB0, 0x0363, 0x11CF, [0xAB, 0xC4, 0x02, 0x60, 0x8C, 0x9E, 0x75, 0x53]}; enum IID LIBID_ALGLib = {0xB6D1D098, 0xE235, 0x4B99, [0xBA, 0x98, 0x7C, 0x62, 0x4F, 0xD8, 0x75, 0xDB]}; enum IID LIBID_AutoDiscovery = {0x4EAFB888, 0x81CB, 0x4EBA, [0xBA, 0xC9, 0xDA, 0x25, 0x4E, 0x57, 0x21, 0xF1]}; enum IID LIBID_BackgroundCopyManager = {0x1DEEB74F, 0x7915, 0x4560, [0xB5, 0x58, 0x91, 0x8C, 0x83, 0xF1, 0x76, 0xA6]}; enum IID LIBID_BackgroundCopyManager1_5 = {0xEA9319EA, 0xC628, 0x480F, [0x83, 0x31, 0x76, 0x8F, 0xAC, 0x39, 0x7E, 0x4E]}; enum IID LIBID_BackgroundCopyQMgr = {0xF5B26DCB, 0xB37E, 0x4D7C, [0xAE, 0x7A, 0x1C, 0xB3, 0xFB, 0xEB, 0x18, 0x3E]}; enum IID LIBID_CHANNELMGR = {0x4804F2E0, 0xD16E, 0x11D0, [0x80, 0x2B, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13]}; enum IID LIBID_CLADMWIZLib = {0x24F97140, 0x6689, 0x11D1, [0x9A, 0xA7, 0x00, 0xC0, 0x4F, 0xB9, 0x3A, 0x80]}; enum IID LIBID_ClusCfgWizard = {0x6D01FEDC, 0x8D34, 0x4728, [0xAD, 0x0B, 0xB3, 0xA2, 0x1A, 0x10, 0x3B, 0x42]}; enum IID LIBID_CommonControlObjects = {0xBCADA15B, 0xB428, 0x420C, [0x8D, 0x28, 0x02, 0x35, 0x90, 0x92, 0x4C, 0x9F]}; enum IID LIBID_DirectAnimation = {0xBCBB1F74, 0xE384, 0x11D0, [0x9B, 0x99, 0x00, 0xC0, 0x4F, 0xC2, 0xF5, 0x1D]}; enum IID LIBID_DWbemServices_v3 = {0xCB7CA031, 0xF729, 0x11D0, [0x9E, 0x4D, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8]}; enum IID LIBID_DXTMSFTLib = {0x5E77EB03, 0x937C, 0x11D1, [0xB0, 0x47, 0x00, 0xAA, 0x00, 0x3B, 0x60, 0x61]}; enum IID LIBID_DXTRANSLib = {0x54314D1D, 0x35FE, 0x11D1, [0x81, 0xA1, 0x00, 0x00, 0xF8, 0x75, 0x57, 0xDB]}; enum IID LIBID_DXTRANSPLib = {0x527A4DA4, 0x7F2C, 0x11D2, [0xB1, 0x2D, 0x00, 0x00, 0xF8, 0x1F, 0x59, 0x95]}; enum IID LIBID_EventQLib = {0xA70080F2, 0x403B, 0x11D1, [0x88, 0x36, 0x00, 0xA0, 0xC9, 0x49, 0xAC, 0x67]}; enum IID LIBID_IASPolicyLib = {0x6BC096A5, 0x0CE6, 0x11D1, [0xBA, 0xAE, 0x00, 0xC0, 0x4F, 0xC2, 0xE2, 0x0D]}; enum IID LIBID_IEXTagLib = {0x7E8BC440, 0xAEFF, 0x11D1, [0x89, 0xC2, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4]}; enum IID LIBID_IMAPILib = {0xC49F2184, 0x50A7, 0x11D3, [0x91, 0x44, 0x00, 0x10, 0x4B, 0xA1, 0x1C, 0x5E]}; enum IID LIBID_ImgUtilLib = {0xCF790840, 0x2DC4, 0x11D0, [0xB7, 0x24, 0x00, 0xAA, 0x00, 0x6C, 0x1A, 0x01]}; enum IID LIBID_ITRKADMNLib = {0xA2531F35, 0xC67D, 0x11D0, [0x8C, 0xB1, 0x00, 0xC0, 0x4F, 0xD9, 0x0F, 0x85]}; enum IID LIBID_McastLib = {0x64217CC0, 0xA285, 0x11D1, [0x86, 0x97, 0x00, 0x60, 0x08, 0xB0, 0xE5, 0xD2]}; enum IID LIBID_MSHTML = {0x3050F1C5, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID LIBID_MSHTMLINTERNAL = {0x3050F7E1, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID LIBID_MSTIME = {0x87C96271, 0xADDB, 0x4745, [0xB2, 0xE8, 0xDF, 0x88, 0xA8, 0x47, 0x2F, 0xD1]}; enum IID LIBID_MSXML = {0xD63E0CE2, 0xA0A2, 0x11D0, [0x9C, 0x02, 0x00, 0xC0, 0x4F, 0xC9, 0x9C, 0x8E]}; enum IID LIBID_MultiLanguage = {0x275C23E0, 0x3747, 0x11D0, [0x9F, 0xEA, 0x00, 0xAA, 0x00, 0x3F, 0x86, 0x46]}; enum IID LIBID_NATUPNPLib = {0x1C565858, 0xF302, 0x471E, [0xB4, 0x09, 0xF1, 0x80, 0xAA, 0x4A, 0xBE, 0xC6]}; enum IID LIBID_NETCONLib = {0x43E734CA, 0x043D, 0x4A70, [0x9A, 0x2C, 0xA8, 0xF2, 0x54, 0x06, 0x3D, 0x91]}; enum IID LIBID_PassiveSink = {0xE002EEEF, 0xE6EA, 0x11D2, [0x9C, 0xB3, 0x00, 0x10, 0x5A, 0x1F, 0x48, 0x01]}; enum IID LIBID_ProcessDebugManagerLib = {0x78A51821, 0x51F4, 0x11D0, [0x8F, 0x20, 0x00, 0x80, 0x5F, 0x2C, 0xD0, 0x64]}; enum IID LIBID_RENDLib = {0xF1029E4D, 0xCB5B, 0x11D0, [0x8D, 0x59, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID LIBID_RTCCORELib = {0xCD260094, 0xDE10, 0x4AEE, [0xAC, 0x73, 0xEF, 0x87, 0xF6, 0xE1, 0x26, 0x83]}; enum IID LIBID_SDOIASLib = {0x81DDF732, 0x4AA8, 0x4A35, [0xBD, 0xFF, 0x8B, 0x42, 0xEF, 0xE7, 0xC6, 0x24]}; enum IID LIBID_SDPBLBLib = {0xC259D79A, 0xC8AB, 0x11D0, [0x8D, 0x58, 0x00, 0xC0, 0x4F, 0xD9, 0x1A, 0xC0]}; enum IID LIBID_SensEvents = {0xD597DEED, 0x5B9F, 0x11D1, [0x8D, 0xD2, 0x00, 0xAA, 0x00, 0x4A, 0xBD, 0x5E]}; enum IID LIBID_SHDocVw = {0xEAB22AC0, 0x30C1, 0x11CF, [0xA7, 0xEB, 0x00, 0x00, 0xC0, 0x5B, 0xAE, 0x0B]}; enum IID LIBID_Shell32 = {0x50A7E9B0, 0x70EF, 0x11D1, [0xB7, 0x5A, 0x00, 0xA0, 0xC9, 0x05, 0x64, 0xFE]}; enum IID LIBID_ShellImageData = {0x0B8AFF06, 0x8DF0, 0x4F13, [0x8E, 0x25, 0x25, 0xB2, 0x31, 0x9C, 0x43, 0x6A]}; enum IID LIBID_ShellObjects = {0x50A7E9B1, 0x70EF, 0x11D1, [0xB7, 0x5A, 0x00, 0xA0, 0xC9, 0x05, 0x64, 0xFE]}; enum IID LIBID_SHGINALib = {0x0A055C02, 0xBABE, 0x4480, [0xBB, 0x7B, 0xA8, 0xEC, 0x72, 0x3C, 0xE9, 0xC0]}; enum IID LIBID_SubscriptionMgr = {0xC54FD88A, 0xFFA1, 0x11D0, [0xBC, 0x5E, 0x00, 0xC0, 0x4F, 0xD9, 0x29, 0xDB]}; enum IID LIBID_TAPI3Lib = {0x21D6D480, 0xA88B, 0x11D0, [0x83, 0xDD, 0x00, 0xAA, 0x00, 0x3C, 0xCA, 0xBD]}; enum IID LIBID_TERMMGRLib = {0x28DCD85B, 0xACA4, 0x11D0, [0xA0, 0x28, 0x00, 0xAA, 0x00, 0xB6, 0x05, 0xA4]}; enum IID LIBID_UPnPHostLib = {0x204810B3, 0x73B2, 0x11D4, [0xBF, 0x42, 0x00, 0xB0, 0xD0, 0x11, 0x8B, 0x56]}; enum IID LIBID_UPNPLib = {0xDB3442A7, 0xA2E9, 0x4A59, [0x9C, 0xB5, 0xF5, 0xC1, 0xA5, 0xD9, 0x01, 0xE5]}; enum IID LIBID_VIRUSSCAN = {0x5F47DB70, 0xD9FE, 0x11D0, [0x95, 0x64, 0x00, 0x60, 0x97, 0x97, 0xEA, 0x4F]}; enum IID LIBID_WbemClient_v1 = {0x7EC196FE, 0x7005, 0x11D1, [0xAD, 0x90, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID LIBID_WbemProviders_v1 = {0x092DF710, 0x7010, 0x11D1, [0xAD, 0x90, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF]}; enum IID LIBID_WbemScripting = {0x565783C6, 0xCB41, 0x11D1, [0x8B, 0x02, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6]}; enum IID LIBID_WbemTransports_v1 = {0x027947F3, 0xD731, 0x11CE, [0xA3, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]}; enum IID LIBID_WbemUtilities_v1 = {0x226C9290, 0xDD96, 0x11D3, [0xA1, 0x20, 0x00, 0x10, 0x5A, 0x1F, 0x51, 0x5A]}; enum IID LIBID_WebCheck = {0x10BD2E25, 0xF235, 0x11CF, [0xB5, 0xDD, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xEC]}; enum IID LIBID_WMIEXTENSIONLib = {0xE503D000, 0x5C7F, 0x11D2, [0x8B, 0x74, 0x00, 0x10, 0x4B, 0x2A, 0xFB, 0x41]}; enum IID LIBID_XENROLLLib = {0x43F8F27B, 0x7A20, 0x11D0, [0x8F, 0x06, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1]}; enum IID LIBID_XMLPSR = {0xD242361C, 0x51A0, 0x11D2, [0x9C, 0xAF, 0x00, 0x60, 0xB0, 0xEC, 0x3D, 0x39]}; enum IID MDGUID_MDX = {0xA07CCCD0, 0x8148, 0x11D0, [0x87, 0xBB, 0x00, 0xC0, 0x4F, 0xC3, 0x39, 0x42]}; enum IID MDSCHEMA_ACTIONS = {0xA07CCD08, 0x8148, 0x11D0, [0x87, 0xBB, 0x00, 0xC0, 0x4F, 0xC3, 0x39, 0x42]}; enum IID MDSCHEMA_COMMANDS = {0xA07CCD09, 0x8148, 0x11D0, [0x87, 0xBB, 0x00, 0xC0, 0x4F, 0xC3, 0x39, 0x42]}; enum IID MDSCHEMA_CUBES = {0xC8B522D8, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID MDSCHEMA_DIMENSIONS = {0xC8B522D9, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID MDSCHEMA_FUNCTIONS = {0xA07CCD07, 0x8148, 0x11D0, [0x87, 0xBB, 0x00, 0xC0, 0x4F, 0xC3, 0x39, 0x42]}; enum IID MDSCHEMA_HIERARCHIES = {0xC8B522DA, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID MDSCHEMA_LEVELS = {0xC8B522DB, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID MDSCHEMA_MEASURES = {0xC8B522DC, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID MDSCHEMA_MEMBERS = {0xC8B522DE, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID MDSCHEMA_PROPERTIES = {0xC8B522DD, 0x5CF3, 0x11CE, [0xAD, 0xE5, 0x00, 0xAA, 0x00, 0x44, 0x77, 0x3D]}; enum IID MDSCHEMA_SETS = {0xA07CCD0B, 0x8148, 0x11D0, [0x87, 0xBB, 0x00, 0xC0, 0x4F, 0xC3, 0x39, 0x42]}; enum IID NAMEDTIMER_DRAW = {0x3050F362, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID NOTFCOOKIE_SCHEDULE_GROUP_DAILY = {0xD34F18B0, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTFCOOKIE_SCHEDULE_GROUP_MANUAL = {0xD34F18B3, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTFCOOKIE_SCHEDULE_GROUP_MONTHLY = {0xD34F18B2, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTFCOOKIE_SCHEDULE_GROUP_WEEKLY = {0xD34F18B1, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_11 = {0xD34F17FB, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_12 = {0xD34F17FC, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_13 = {0xD34F17FD, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_14 = {0xD34F17FE, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_15 = {0xD34F17FF, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_AGENT_INIT = {0x1E4A7390, 0xC70B, 0x11D0, [0x95, 0xF8, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xEC]}; enum IID NOTIFICATIONTYPE_AGENT_START = {0xD34F17EC, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_ALERT = {0xD34F17E3, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_ANOUNCMENT = {0xD34F17E1, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_BEGIN_REPORT = {0xD34F17EE, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_CONFIG_CHANGED = {0xD34F17F2, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_CONNECT_TO_INTERNET = {0xD34F17F0, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_d = {0xD34F17F8, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_DISCONNECT_FROM_INTE = {0xD34F17F1, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_e = {0xD34F17F9, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_END_REPORT = {0xD34F17EF, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_f = {0xD34F17FA, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_GROUP_DONE = {0xD34F1885, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_GROUP_RESTART = {0xD34F1884, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_GROUP_START = {0xD34F1883, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_i6 = {0xD34F1886, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_i7 = {0xD34F1887, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_i8 = {0xD34F1888, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_i9 = {0xD34F1889, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_iA = {0xD34F188A, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_iB = {0xD34F188B, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_iC = {0xD34F188C, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_iD = {0xD34F188D, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_iE = {0xD34F188E, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_iF = {0xD34F188F, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_INET_IDLE = {0xD34F17E4, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_INET_OFFLINE = {0xD34F17E5, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_INET_ONLINE = {0xD34F17E6, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_ITEM_DONE = {0xD34F1882, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_ITEM_RESTART = {0xD34F1881, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_ITEM_START = {0xD34F1880, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_NULL = {0xD34F17E0, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_PROGRESS_REPORT = {0xD34F17F3, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_0 = {0xD34F1800, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_1 = {0xD34F1801, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_2 = {0xD34F1802, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_3 = {0xD34F1803, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_4 = {0xD34F1804, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_5 = {0xD34F1805, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_6 = {0xD34F1806, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_7 = {0xD34F1807, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_8 = {0xD34F1808, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_9 = {0xD34F1809, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_A = {0xD34F180A, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_B = {0xD34F180B, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_C = {0xD34F180C, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_D = {0xD34F180D, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_E = {0xD34F180E, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_START_F = {0xD34F180F, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_TASK = {0xD34F17E2, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_TASKS_ABORT = {0xD34F17E9, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_TASKS_COMPLETED = {0xD34F17EA, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_TASKS_ERROR = {0xD34F17F7, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_TASKS_PROGRESS = {0xD34F17EB, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_TASKS_RESUME = {0xD34F17E8, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_TASKS_STARTED = {0xD34F17F6, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_TASKS_SUSPEND = {0xD34F17E7, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_USER_IDLE_BEGIN = {0xD34F17F4, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID NOTIFICATIONTYPE_USER_IDLE_END = {0xD34F17F5, 0x576E, 0x11D0, [0xB2, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0xCD, 0x22]}; enum IID OLE_DATAPATH_ALLIMAGE = {0x0002DE0E, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_ALLMM = {0x0002DE18, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_ALLTEXT = {0x0002DE1E, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_ANSITEXT = {0x0002DE19, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_AVI = {0x0002DE0F, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_BASICAUDIO = {0x0002DE12, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_BIFF = {0x0002DE21, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_BMP = {0x0002DE01, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_CGM = {0x0002DE0B, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_COMMONIMAGE = {0x0002DE0D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_DIB = {0x0002DE02, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_DIF = {0x0002DE1F, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_ENHMF = {0x0002DE04, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_EPS = {0x0002DE0C, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_GIF = {0x0002DE05, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_HTML = {0x0002DE1C, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_JPEG = {0x0002DE06, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_MIDI = {0x0002DE13, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_MPEG = {0x0002DE10, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_PALETTE = {0x0002DE22, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_PCX = {0x0002DE09, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_PENDATA = {0x0002DE23, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_PICT = {0x0002DE0A, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_POSTSCRIPT = {0x0002DE1D, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_QUICKTIME = {0x0002DE11, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_RIFF = {0x0002DE15, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_RTF = {0x0002DE1B, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_SOUND = {0x0002DE16, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_SYLK = {0x0002DE20, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_TIFF = {0x0002DE07, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_UNICODE = {0x0002DE1A, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_VIDEO = {0x0002DE17, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_WAV = {0x0002DE14, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_WMF = {0x0002DE03, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLE_DATAPATH_XBM = {0x0002DE08, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]}; enum IID OLEDB_SVC_DSLPropertyPages = {0x51740C02, 0x7E8E, 0x11D2, [0xA0, 0x2D, 0x00, 0xC0, 0x4F, 0xA3, 0x73, 0x48]}; enum IID PSGUID_QUERY = {0x49691C90, 0x7E17, 0x101A, [0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9]}; enum IID RESCLASSTYPE_IPAddress = {0x57A80E0F, 0x6F18, 0x458B, [0xA7, 0x2A, 0xD1, 0x17, 0x0C, 0x47, 0x93, 0x90]}; enum IID RESCLASSTYPE_NetworkName = {0xBBA69EB9, 0xF5D0, 0x487B, [0x92, 0xAE, 0x1B, 0xA1, 0x0F, 0x39, 0x21, 0x58]}; enum IID RESCLASSTYPE_StorageDevice = {0x12453A47, 0x8C5E, 0x4837, [0xBA, 0xC6, 0xB2, 0x54, 0xB8, 0xF2, 0x64, 0xCC]}; enum IID RESTYPE_ClusterIPAddress = {0xE50DF832, 0x477C, 0x440C, [0xB7, 0xA3, 0x38, 0x23, 0xA6, 0xEF, 0x6C, 0xCB]}; enum IID RESTYPE_ClusterNetName = {0xB2897CCF, 0x8D2C, 0x4BC1, [0xB4, 0x96, 0x6E, 0x2B, 0xC7, 0xA0, 0xBB, 0x38]}; enum IID RESTYPE_ClusterQuorumDisk = {0xD9DDFB80, 0x0BDC, 0x40D4, [0xB3, 0x96, 0x1A, 0xFD, 0x77, 0xDD, 0xD1, 0x9C]}; enum IID RESTYPE_GenericScript = {0xF372184D, 0xDFDB, 0x4370, [0xA0, 0x05, 0xE1, 0xEF, 0x30, 0x1B, 0x23, 0xA4]}; enum IID RESTYPE_IPAddress = {0xE61ADE71, 0xC79A, 0x4FDA, [0xB1, 0xDB, 0xA9, 0xB8, 0xD2, 0x0C, 0x8B, 0x14]}; enum IID RESTYPE_LocalQuorum = {0xF004656D, 0x5B48, 0x4580, [0xA1, 0xF4, 0xC3, 0xEC, 0x14, 0x98, 0x3D, 0x1E]}; enum IID RESTYPE_MajorityNodeSet = {0x56BFAE11, 0xD2F7, 0x4F4F, [0x99, 0x52, 0x55, 0xAF, 0x19, 0xBA, 0xC3, 0xE9]}; enum IID RESTYPE_NetworkName = {0xC1D2FE1E, 0xD332, 0x445F, [0x8D, 0xA1, 0x12, 0xE5, 0xE2, 0xD3, 0x7C, 0xBF]}; enum IID RESTYPE_PhysicalDisk = {0xCC558763, 0x3386, 0x42EF, [0xB1, 0x50, 0xBE, 0x79, 0x33, 0x44, 0xD4, 0x5F]}; enum IID SID_CtxQueryAssociations = {0xFAADFC40, 0xB777, 0x4B69, [0xAA, 0x81, 0x77, 0x03, 0x5E, 0xF0, 0xE6, 0xE8]}; enum IID SID_SContainerDispatch = {0xB722BE00, 0x4E68, 0x101B, [0xA2, 0xBC, 0x00, 0xAA, 0x00, 0x40, 0x47, 0x70]}; enum IID SID_SDataPathBrowser = {0xFC4801A5, 0x2BA9, 0x11CF, [0xA2, 0x29, 0x00, 0xAA, 0x00, 0x3D, 0x73, 0x52]}; enum IID SID_SGetViewFromViewDual = {0x889A935D, 0x971E, 0x4B12, [0xB9, 0x0C, 0x24, 0xDF, 0xC9, 0xE1, 0xE5, 0xE8]}; enum IID SID_SHTMLEditServices = {0x3050F7F9, 0x98B5, 0x11CF, [0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B]}; enum IID SID_STopLevelBrowser = {0x4C96BE40, 0x915C, 0x11CF, [0x99, 0xD3, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37]}; enum IID SID_STopWindow = {0x49E1B500, 0x4636, 0x11D3, [0x97, 0xF7, 0x00, 0xC0, 0x4F, 0x45, 0xD0, 0xB3]}; enum IID SID_SVersionHost = {0x371EA634, 0xDC5C, 0x11D1, [0xBA, 0x57, 0x00, 0xC0, 0x4F, 0xC2, 0x04, 0x0E]}; enum IID TAPIMEDIATYPE_Audio = {0x028ED8C2, 0xDC7A, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID TAPIMEDIATYPE_DataModem = {0x028ED8C6, 0xDC7A, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID TAPIMEDIATYPE_G3Fax = {0x028ED8C7, 0xDC7A, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID TAPIMEDIATYPE_Video = {0x028ED8C4, 0xDC7A, 0x11D0, [0x8E, 0xD3, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID TAPIPROTOCOL_H323 = {0x831CE2D7, 0x83B5, 0x11D1, [0xBB, 0x5C, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID TAPIPROTOCOL_Multicast = {0x831CE2D8, 0x83B5, 0x11D1, [0xBB, 0x5C, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID TAPIPROTOCOL_PSTN = {0x831CE2D6, 0x83B5, 0x11D1, [0xBB, 0x5C, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F]}; enum IID TASK_AnalyzeCluster = {0x3140B5A6, 0x9AFA, 0x4588, [0x8C, 0xA0, 0x9B, 0xE8, 0xF8, 0xB6, 0x15, 0x06]}; enum IID TASK_CommitClusterChanges = {0x2D03030B, 0xF084, 0x4807, [0xBB, 0xAC, 0x94, 0x26, 0x9E, 0x50, 0xB5, 0x6F]}; enum IID TASKID_Major_Check_Cluster_Feasibili = {0xEBC8AEFF, 0x10C3, 0x4D5B, [0xAC, 0x17, 0xFC, 0x0F, 0x4C, 0x38, 0x71, 0xB7]}; enum IID TASKID_Major_Check_Node_Feasibility = {0xCC5E57B1, 0x4520, 0x4672, [0xB4, 0xBA, 0xA2, 0x88, 0xEC, 0x42, 0x94, 0x6E]}; enum IID TASKID_Major_Checking_For_Existing_Cl = {0xB8453B8F, 0x92FD, 0x4350, [0xA6, 0xD9, 0x55, 0x1F, 0xD0, 0x18, 0xB7, 0x91]}; enum IID TASKID_Major_Client_And_Server_Log = {0xCD36919C, 0x9F31, 0x46B4, [0xA2, 0x9D, 0xAC, 0x87, 0xF4, 0xE6, 0xCC, 0x93]}; enum IID TASKID_Major_Client_Log = {0x64ECA0EA, 0x9CB6, 0x4324, [0x97, 0x02, 0xDF, 0x15, 0xC6, 0x96, 0xC3, 0x0A]}; enum IID TASKID_Major_Configure_Cluster_Servic = {0x7C5F0774, 0x1611, 0x42B5, [0xAF, 0x3C, 0x6E, 0x12, 0x4A, 0xC4, 0xD3, 0x6B]}; enum IID TASKID_Major_Configure_Resource_Type = {0x6D47AF1F, 0x7F17, 0x4B80, [0x8F, 0xAB, 0x3A, 0x2D, 0x19, 0xB1, 0x23, 0x3D]}; enum IID TASKID_Major_Configure_Resources = {0x411BCDEC, 0x69D3, 0x4485, [0x8D, 0x5D, 0xE1, 0x9E, 0xE7, 0x7A, 0x6D, 0xD4]}; enum IID TASKID_Major_Establish_Connection = {0x93C32F99, 0x39CA, 0x4D38, [0x9D, 0x7F, 0x27, 0x07, 0xCA, 0x0E, 0xAF, 0x46]}; enum IID TASKID_Major_Find_Devices = {0x036BF567, 0x2377, 0x4BB3, [0x8A, 0xE1, 0xE4, 0x10, 0x4E, 0x2E, 0xB3, 0xC5]}; enum IID TASKID_Major_Reanalyze = {0xE25968DA, 0x9C7B, 0x42DB, [0xAD, 0xA9, 0xBC, 0x4E, 0x34, 0xF1, 0x7E, 0x6E]}; enum IID TASKID_Major_Server_Log = {0x05AA0768, 0x5F49, 0x49CD, [0xAF, 0xDC, 0x96, 0xF9, 0xD5, 0x18, 0x02, 0xD4]}; enum IID TASKID_Minor_Update_Progress = {0x2362D3DA, 0xA6A4, 0x4551, [0xB8, 0x46, 0x7B, 0xB3, 0xA1, 0x36, 0x5F, 0x56]}; enum IID TID_D3DRMAnimation = {0x3D82AB4F, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMAnimationKey = {0x10DD46A8, 0x775B, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMAnimationOptions = {0xE2BF56C0, 0x840F, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMAnimationSet = {0x3D82AB50, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMAppData = {0xE5745280, 0xB24F, 0x11CF, [0x9D, 0xD5, 0x00, 0xAA, 0x00, 0xA7, 0x1A, 0x2F]}; enum IID TID_D3DRMBoolean = {0x537DA6A0, 0xCA37, 0x11D0, [0x94, 0x1C, 0x00, 0x80, 0xC8, 0x0C, 0xFA, 0x7B]}; enum IID TID_D3DRMBoolean2d = {0x4885AE63, 0x78E8, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMCamera = {0x3D82AB51, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMColorRGB = {0xD3E16E81, 0x7835, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMColorRGBA = {0x35FF44E0, 0x6C7C, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMCoords2d = {0xF6F23F44, 0x7686, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMExternalVisual = {0x98116AA0, 0xBDBA, 0x11D1, [0x82, 0xC0, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x71]}; enum IID TID_D3DRMFloatKeys = {0x10DD46A9, 0x775B, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMFrame = {0x3D82AB46, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMFramePosition = {0xE2BF56C1, 0x840F, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMFrameRotation = {0xE2BF56C3, 0x840F, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMFrameTransformMatrix = {0xF6F23F41, 0x7686, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMFrameVelocity = {0xE2BF56C2, 0x840F, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMGuid = {0xA42790E0, 0x7810, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMIndexedColor = {0x1630B820, 0x7842, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMInfo = {0x2B957100, 0x9E9A, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMInlineData = {0x3A23EEA0, 0x94B1, 0x11D0, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMLight = {0x3D82AB4A, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMLightAttenuation = {0xA8A98BA0, 0xC5E5, 0x11CF, [0xB9, 0x41, 0x00, 0x80, 0xC8, 0x0C, 0xFA, 0x7B]}; enum IID TID_D3DRMLightPenumbra = {0xAED22741, 0xB31F, 0x11CF, [0x9D, 0xD5, 0x00, 0xAA, 0x00, 0xA7, 0x1A, 0x2F]}; enum IID TID_D3DRMLightRange = {0xAED22742, 0xB31F, 0x11CF, [0x9D, 0xD5, 0x00, 0xAA, 0x00, 0xA7, 0x1A, 0x2F]}; enum IID TID_D3DRMLightUmbra = {0xAED22740, 0xB31F, 0x11CF, [0x9D, 0xD5, 0x00, 0xAA, 0x00, 0xA7, 0x1A, 0x2F]}; enum IID TID_D3DRMMaterial = {0x3D82AB4D, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMMaterialAmbientColor = {0x01411840, 0x7786, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMaterialArray = {0x35FF44E1, 0x6C7C, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMaterialDiffuseColor = {0x01411841, 0x7786, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMaterialEmissiveColor = {0xD3E16E80, 0x7835, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMaterialPower = {0x01411843, 0x7786, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMaterialSpecularColor = {0x01411842, 0x7786, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMaterialWrap = {0x4885AE60, 0x78E8, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMatrix4x4 = {0xF6F23F45, 0x7686, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMesh = {0x3D82AB44, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMMeshFace = {0x3D82AB5F, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMMeshFaceWraps = {0xED1EC5C0, 0xC0A8, 0x11D0, [0x94, 0x1C, 0x00, 0x80, 0xC8, 0x0C, 0xFA, 0x7B]}; enum IID TID_D3DRMMeshMaterialList = {0xF6F23F42, 0x7686, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMeshNormals = {0xF6F23F43, 0x7686, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMeshTextureCoords = {0xF6F23F40, 0x7686, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMMeshVertexColors = {0x1630B821, 0x7842, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMProgressiveMesh = {0x8A63C360, 0x997D, 0x11D0, [0x94, 0x1C, 0x00, 0x80, 0xC8, 0x0C, 0xFA, 0x7B]}; enum IID TID_D3DRMPropertyBag = {0x7F0F21E1, 0xBFE1, 0x11D1, [0x82, 0xC0, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x71]}; enum IID TID_D3DRMRightHanded = {0x7F5D5EA0, 0xD53A, 0x11D1, [0x82, 0xC0, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x71]}; enum IID TID_D3DRMStringProperty = {0x7F0F21E0, 0xBFE1, 0x11D1, [0x82, 0xC0, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x71]}; enum IID TID_D3DRMTextureFilename = {0xA42790E1, 0x7810, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMTextureReference = {0xA42790E2, 0x7810, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMTimedFloatKeys = {0xF406B180, 0x7B3B, 0x11CF, [0x8F, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xA3]}; enum IID TID_D3DRMUrl = {0x3A23EEA1, 0x94B1, 0x11D0, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_D3DRMVector = {0x3D82AB5E, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; enum IID TID_DXFILEHeader = {0x3D82AB43, 0x62DA, 0x11CF, [0xAB, 0x39, 0x00, 0x20, 0xAF, 0x71, 0xE4, 0x33]}; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmuseflg.d0000664000175000017500000000055312776214756023500 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmuseflg.d) */ module core.sys.windows.lmuseflg; version (Windows): enum : uint { USE_NOFORCE = 0, USE_FORCE, USE_LOTS_OF_FORCE // = 2 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/richole.d0000664000175000017500000000601412776214756023305 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_richole.d) */ module core.sys.windows.richole; version (Windows): private import core.sys.windows.objfwd, core.sys.windows.objidl, core.sys.windows.ole2, core.sys.windows.unknwn, core.sys.windows.windef; private import core.sys.windows.richedit; // for CHARRANGE align(4): enum ULONG REO_GETOBJ_NO_INTERFACES = 0, REO_GETOBJ_POLEOBJ = 1, REO_GETOBJ_PSTG = 2, REO_GETOBJ_POLESITE = 4, REO_GETOBJ_ALL_INTERFACES = 7, REO_CP_SELECTION = -1, REO_IOB_SELECTION = -1, REO_IOB_USE_CP = -2, REO_NULL = 0, REO_READWRITEMASK = 0x3F, REO_DONTNEEDPALETTE = 32, REO_BLANK = 16, REO_DYNAMICSIZE = 8, REO_INVERTEDSELECT = 4, REO_BELOWBASELINE = 2, REO_RESIZABLE = 1, REO_LINK = 0x80000000, REO_STATIC = 0x40000000, REO_SELECTED = 0x08000000, REO_OPEN = 0x4000000, REO_INPLACEACTIVE = 0x2000000, REO_HILITED = 0x1000000, REO_LINKAVAILABLE = 0x800000, REO_GETMETAFILE = 0x400000; enum { RECO_PASTE = 0, RECO_DROP, RECO_COPY, RECO_CUT, RECO_DRAG // = 4 } extern (C) extern const GUID IID_IRichEditOle, IID_IRichEditOleCallback; struct REOBJECT { DWORD cbStruct = REOBJECT.sizeof; LONG cp; CLSID clsid; LPOLEOBJECT poleobj; LPSTORAGE pstg; LPOLECLIENTSITE polesite; SIZEL sizel; DWORD dvaspect; DWORD dwFlags; DWORD dwUser; } interface IRichEditOle : IUnknown { HRESULT GetClientSite(LPOLECLIENTSITE*); LONG GetObjectCount(); LONG GetLinkCount(); HRESULT GetObject(LONG, REOBJECT*, DWORD); HRESULT InsertObject(REOBJECT*); HRESULT ConvertObject(LONG, REFCLSID, LPCSTR); HRESULT ActivateAs(REFCLSID, REFCLSID); HRESULT SetHostNames(LPCSTR, LPCSTR); HRESULT SetLinkAvailable(LONG, BOOL); HRESULT SetDvaspect(LONG, DWORD); HRESULT HandsOffStorage(LONG); HRESULT SaveCompleted(LONG, LPSTORAGE); HRESULT InPlaceDeactivate(); HRESULT ContextSensitiveHelp(BOOL); HRESULT GetClipboardData(CHARRANGE*, DWORD, LPDATAOBJECT*); HRESULT ImportDataObject(LPDATAOBJECT, CLIPFORMAT, HGLOBAL); }; alias IRichEditOle LPRICHEDITOLE; interface IRichEditOleCallback : IUnknown { HRESULT GetNewStorage(LPSTORAGE*); HRESULT GetInPlaceContext(LPOLEINPLACEFRAME*, LPOLEINPLACEUIWINDOW*, LPOLEINPLACEFRAMEINFO); HRESULT ShowContainerUI(BOOL); HRESULT QueryInsertObject(LPCLSID, LPSTORAGE, LONG); HRESULT DeleteObject(LPOLEOBJECT); HRESULT QueryAcceptData(LPDATAOBJECT, CLIPFORMAT*, DWORD, BOOL, HGLOBAL); HRESULT ContextSensitiveHelp(BOOL); HRESULT GetClipboardData(CHARRANGE*, DWORD, LPDATAOBJECT*); HRESULT GetDragDropEffect(BOOL, DWORD, PDWORD); HRESULT GetContextMenu(WORD, LPOLEOBJECT, CHARRANGE*, HMENU*); }; alias IRichEditOleCallback LPRICHEDITOLECALLBACK; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/core.d0000664000175000017500000000141112776214756022604 0ustar kaikai/** * Helper module for the Windows API * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_core.d) */ module core.sys.windows.core; version (Windows): /** The core Windows API functions. Importing this file is equivalent to the C code: --- #define WIN32_LEAN_AND_MEAN #include "windows.h" --- */ public import core.sys.windows.windef; public import core.sys.windows.winnt; public import core.sys.windows.wincon; public import core.sys.windows.winbase; public import core.sys.windows.wingdi; public import core.sys.windows.winuser; public import core.sys.windows.winnls; public import core.sys.windows.winver; public import core.sys.windows.winnetwk; public import core.sys.windows.winsvc; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winhttp.d0000664000175000017500000011163212776214756023360 0ustar kaikai/** * Windows API header module * * Translated from Windows SDK Headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winhttp.d) */ module core.sys.windows.winhttp; version (Windows): pragma(lib, "winhttp"); // FIXME: Grouping of constants. Windows SDK doesn't make this entirely clear // FIXME: Verify WINHTTP_STATUS_CALLBACK function declaration works correctly import core.sys.windows.w32api; import core.sys.windows.winbase; import core.sys.windows.windef; import core.sys.windows.winsock2; // Selective Imports BUG (: SOCKADDR_STORAGE;) alias HINTERNET = void*; alias LPHINTERNET = HINTERNET*; alias INTERNET_PORT = WORD; alias LPINTERNET_PORT = INTERNET_PORT*; alias INTERNET_SCHEME = int; alias LPINTERNET_SCHEME = INTERNET_SCHEME*; // Protocol 'Manifests' enum : DWORD { INTERNET_DEFAULT_PORT = 0, INTERNET_DEFAULT_HTTP_PORT = 80, INTERNET_DEFAULT_HTTPS_PORT = 443 } // WinHttpOpen() Flags: enum DWORD WINHTTP_FLAG_ASYNC = 0x10000000; // WinHttpOpenRequest() Flags: enum : DWORD { WINHTTP_FLAG_SECURE = 0x00800000, WINHTTP_FLAG_ESCAPE_PERCENT = 0x00000004, WINHTTP_FLAG_NULL_CODEPAGE = 0x00000008, WINHTTP_FLAG_BYPASS_PROXY_CACHE = 0x00000100, WINHTTP_FLAG_REFRESH = WINHTTP_FLAG_BYPASS_PROXY_CACHE, WINHTTP_FLAG_ESCAPE_DISABLE = 0x00000040, WINHTTP_FLAG_ESCAPE_DISABLE_QUERY = 0x00000080, SECURITY_FLAG_IGNORE_UNKNOWN_CA = 0x00000100, SECURITY_FLAG_IGNORE_CERT_DATE_INVALID = 0x00002000, SECURITY_FLAG_IGNORE_CERT_CN_INVALID = 0x00001000, SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE = 0x00000200 } struct WINHTTP_ASYNC_RESULT { DWORD_PTR dwResult; DWORD dwError; } alias LPWINHTTP_ASYNC_RESULT = WINHTTP_ASYNC_RESULT*; struct HTTP_VERSION_INFO { DWORD dwMajorVersion; DWORD dwMinorVersion; } alias LPHTTP_VERSION_INFO = HTTP_VERSION_INFO*; // URL Scheme enum : DWORD { INTERNET_SCHEME_HTTP = 1, INTERNET_SCHEME_HTTPS = 2, INTERNET_SCHEME_FTP = 3, INTERNET_SCHEME_SOCKS = 4 } struct URL_COMPONENTS { DWORD dwStructSize; LPWSTR lpszScheme; DWORD dwSchemeLength; INTERNET_SCHEME nScheme; LPWSTR lpszHostName; DWORD dwHostNameLength; INTERNET_PORT nPort; LPWSTR lpszUserName; DWORD dwUserNameLength; LPWSTR lpszPassword; DWORD dwPasswordLength; LPWSTR lpszUrlPath; DWORD dwUrlPathLength; LPWSTR lpszExtraInfo; DWORD dwExtraInfoLength; } alias LPURL_COMPONENTS = URL_COMPONENTS*; alias URL_COMPONENTSW = URL_COMPONENTS; alias LPURL_COMPONENTSW = URL_COMPONENTS*; struct WINHTTP_PROXY_INFO { DWORD dwAccessType; LPWSTR lpszProxy; LPWSTR lpszProxyBypass; } alias LPWINHTTP_PROXY_INFO = WINHTTP_PROXY_INFO*; alias WINHTTP_PROXY_INFOW = WINHTTP_PROXY_INFO; alias LPWINHTTP_PROXY_INFOW = WINHTTP_PROXY_INFO*; struct WINHTTP_AUTOPROXY_OPTIONS { DWORD dwFlags; DWORD dwAutoDetectFlags; LPCWSTR lpszAutoConfigUrl; LPVOID lpvReserved; DWORD dwReserved; BOOL fAutoLogonIfChallenged; } enum : DWORD { WINHTTP_AUTOPROXY_AUTO_DETECT = 0x00000001, WINHTTP_AUTOPROXY_CONFIG_URL = 0x00000002, WINHTTP_AUTOPROXY_HOST_KEEPCASE = 0x00000004, WINHTTP_AUTOPROXY_HOST_LOWERCASE = 0x00000008, WINHTTP_AUTOPROXY_RUN_INPROCESS = 0x00010000, WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY = 0x00020000, WINHTTP_AUTOPROXY_NO_DIRECTACCESS = 0x00040000, WINHTTP_AUTOPROXY_NO_CACHE_CLIENT = 0x00080000, WINHTTP_AUTOPROXY_NO_CACHE_SVC = 0x00100000, WINHTTP_AUTOPROXY_SORT_RESULTS = 0x00400000 } // dwAutoDetectFlags enum : DWORD { WINHTTP_AUTO_DETECT_TYPE_DHCP = 0x00000001, WINHTTP_AUTO_DETECT_TYPE_DNS_A = 0x00000002 } struct WINHTTP_CERTIFICATE_INFO { FILETIME ftExpiry; FILETIME ftStart; LPWSTR lpszSubjectInfo; LPWSTR lpszIssuerInfo; LPWSTR lpszProtocolName; LPWSTR lpszSignatureAlgName; LPWSTR lpszEncryptionAlgName; DWORD dwKeySize; } // This structure is only defined #if _WS2DEF_ defined (from ) - per Windows SDK struct WINHTTP_CONNECTION_INFO { DWORD cbSize; SOCKADDR_STORAGE LocalAddress; SOCKADDR_STORAGE RemoteAddress; } // WinHttpTimeFromSystemTime enum DWORD WINHTTP_TIME_FORMAT_BUFSIZE = 62; // CrackUrl, CombineUrl enum : DWORD { ICU_NO_ENCODE = 0x20000000, ICU_DECODE = 0x10000000, ICU_NO_META = 0x08000000, ICU_ENCODE_SPACES_ONLY = 0x04000000, ICU_BROWSER_MODE = 0x02000000, ICU_ENCODE_PERCENT = 0x00001000 } // WinHttpCrackUrl, WinHttpCreateUrl enum : DWORD { ICU_ESCAPE = 0x80000000, ICU_ESCAPE_AUTHORITY = 0x00002000, ICU_REJECT_USERPWD = 0x00004000 } enum : DWORD { WINHTTP_ACCESS_TYPE_DEFAULT_PROXY = 0, WINHTTP_ACCESS_TYPE_NO_PROXY = 1, WINHTTP_ACCESS_TYPE_NAMED_PROXY = 3, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY = 4 } // WinHttpOpen 'prettifiers' enum LPCWSTR WINHTTP_NO_PROXY_NAME = null; enum LPCWSTR WINHTTP_NO_PROXY_BYPASS = null; enum LPVOID WINHTTP_NO_CLIENT_CERT_CONTEXT = null; // WinHttp{Query|Set}Option enum : DWORD { WINHTTP_FIRST_OPTION = WINHTTP_OPTION_CALLBACK, WINHTTP_OPTION_CALLBACK = 1, WINHTTP_OPTION_RESOLVE_TIMEOUT = 2, WINHTTP_OPTION_CONNECT_TIMEOUT = 3, WINHTTP_OPTION_CONNECT_RETRIES = 4, WINHTTP_OPTION_SEND_TIMEOUT = 5, WINHTTP_OPTION_RECEIVE_TIMEOUT = 6, WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT = 7, WINHTTP_OPTION_HANDLE_TYPE = 9, WINHTTP_OPTION_READ_BUFFER_SIZE = 12, WINHTTP_OPTION_WRITE_BUFFER_SIZE = 13, WINHTTP_OPTION_PARENT_HANDLE = 21, WINHTTP_OPTION_EXTENDED_ERROR = 24, WINHTTP_OPTION_SECURITY_FLAGS = 31, WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT = 32, WINHTTP_OPTION_URL = 34, WINHTTP_OPTION_SECURITY_KEY_BITNESS = 36, WINHTTP_OPTION_PROXY = 38, WINHTTP_OPTION_PROXY_RESULT_ENTRY = 39, WINHTTP_OPTION_USER_AGENT = 41, WINHTTP_OPTION_CONTEXT_VALUE = 45, WINHTTP_OPTION_CLIENT_CERT_CONTEXT = 47, WINHTTP_OPTION_REQUEST_PRIORITY = 58, WINHTTP_OPTION_HTTP_VERSION = 59, WINHTTP_OPTION_DISABLE_FEATURE = 63, WINHTTP_OPTION_CODEPAGE = 68, WINHTTP_OPTION_MAX_CONNS_PER_SERVER = 73, WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER = 74, WINHTTP_OPTION_AUTOLOGON_POLICY = 77, WINHTTP_OPTION_SERVER_CERT_CONTEXT = 78, WINHTTP_OPTION_ENABLE_FEATURE = 79, WINHTTP_OPTION_WORKER_THREAD_COUNT = 80, WINHTTP_OPTION_PASSPORT_COBRANDING_TEXT = 81, WINHTTP_OPTION_PASSPORT_COBRANDING_URL = 82, WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH = 83, WINHTTP_OPTION_SECURE_PROTOCOLS = 84, WINHTTP_OPTION_ENABLETRACING = 85, WINHTTP_OPTION_PASSPORT_SIGN_OUT = 86, WINHTTP_OPTION_PASSPORT_RETURN_URL = 87, WINHTTP_OPTION_REDIRECT_POLICY = 88, WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS = 89, WINHTTP_OPTION_MAX_HTTP_STATUS_CONTINUE = 90, WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE = 91, WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE = 92, WINHTTP_OPTION_CONNECTION_INFO = 93, WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST = 94, WINHTTP_OPTION_SPN = 96, WINHTTP_OPTION_GLOBAL_PROXY_CREDS = 97, WINHTTP_OPTION_GLOBAL_SERVER_CREDS = 98, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT = 99, WINHTTP_OPTION_REJECT_USERPWD_IN_URL = 100, WINHTTP_OPTION_USE_GLOBAL_SERVER_CREDENTIALS = 101, WINHTTP_OPTION_RECEIVE_PROXY_CONNECT_RESPONSE = 103, WINHTTP_OPTION_IS_PROXY_CONNECT_RESPONSE = 104, WINHTTP_OPTION_SERVER_SPN_USED = 106, WINHTTP_OPTION_PROXY_SPN_USED = 107, WINHTTP_OPTION_SERVER_CBT = 108, WINHTTP_OPTION_UNSAFE_HEADER_PARSING = 110, WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS = 111, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET = 114, WINHTTP_OPTION_WEB_SOCKET_CLOSE_TIMEOUT = 115, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL = 116, WINHTTP_OPTION_DECOMPRESSION = 118, WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE = 122, WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE = 123, //WINHTTP_LAST_OPTION => Moved outside of enum - static if() constraints within enums WINHTTP_OPTION_USERNAME = 0x1000, WINHTTP_OPTION_PASSWORD = 0x1001, WINHTTP_OPTION_PROXY_USERNAME = 0x1002, WINHTTP_OPTION_PROXY_PASSWORD = 0x1003, WINHTTP_CONNS_PER_SERVER_UNLIMITED = 0xFFFFFFFF, WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM = 0, WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW = 1, WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH = 2, WINHTTP_AUTOLOGON_SECURITY_LEVEL_DEFAULT = WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM, WINHTTP_OPTION_REDIRECT_POLICY_NEVER = 0, WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP = 1, WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS = 2, WINHTTP_OPTION_REDIRECT_POLICY_LAST = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS, WINHTTP_OPTION_REDIRECT_POLICY_DEFAULT = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP, WINHTTP_DISABLE_PASSPORT_AUTH = 0x00000000, WINHTTP_ENABLE_PASSPORT_AUTH = 0x10000000, WINHTTP_DISABLE_PASSPORT_KEYRING = 0x20000000, WINHTTP_ENABLE_PASSPORT_KEYRING = 0x40000000, WINHTTP_DISABLE_COOKIES = 0x00000001, WINHTTP_DISABLE_REDIRECTS = 0x00000002, WINHTTP_DISABLE_AUTHENTICATION = 0x00000004, WINHTTP_DISABLE_KEEP_ALIVE = 0x00000008, WINHTTP_ENABLE_SSL_REVOCATION = 0x00000001, WINHTTP_ENABLE_SSL_REVERT_IMPERSONATION = 0x00000002, WINHTTP_DISABLE_SPN_SERVER_PORT = 0x00000000, WINHTTP_ENABLE_SPN_SERVER_PORT = 0x00000001, WINHTTP_OPTION_SPN_MASK = WINHTTP_ENABLE_SPN_SERVER_PORT } // Windows 8.1 SDK: static if (_WIN32_WINNT >= 0x602) { enum DWORD WINHTTP_LAST_OPTION = WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE; } else { // Windows 7.0A SDK: enum DWORD WINHTTP_LAST_OPTION = WINHTTP_OPTION_SERVER_CBT; } enum : DWORD { WINHTTP_DECOMPRESSION_FLAG_GZIP = 0x00000001, WINHTTP_DECOMPRESSION_FLAG_DEFLATE = 0x00000002, WINHTTP_DECOMPRESSION_FLAG_ALL = (WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE) } struct WINHTTP_CREDS { LPSTR lpszUserName; LPSTR lpszPassword; LPSTR lpszRealm; DWORD dwAuthScheme; LPSTR lpszHostName; DWORD dwPort; } alias PWINHTTP_CREDS = WINHTTP_CREDS*; struct WINHTTP_CREDS_EX { LPSTR lpszUserName; LPSTR lpszPassword; LPSTR lpszRealm; DWORD dwAuthScheme; LPSTR lpszHostName; DWORD dwPort; LPSTR lpszUrl; } alias PWINHTTP_CREDS_EX = WINHTTP_CREDS_EX*; enum : DWORD { WINHTTP_HANDLE_TYPE_SESSION = 1, WINHTTP_HANDLE_TYPE_CONNECT = 2, WINHTTP_HANDLE_TYPE_REQUEST = 3, WINHTTP_AUTH_SCHEME_BASIC = 0x00000001, WINHTTP_AUTH_SCHEME_NTLM = 0x00000002, WINHTTP_AUTH_SCHEME_PASSPORT = 0x00000004, WINHTTP_AUTH_SCHEME_DIGEST = 0x00000008, WINHTTP_AUTH_SCHEME_NEGOTIATE = 0x00000010, WINHTTP_AUTH_TARGET_SERVER = 0x00000000, WINHTTP_AUTH_TARGET_PROXY = 0x00000001, SECURITY_FLAG_SECURE = 0x00000001, SECURITY_FLAG_STRENGTH_WEAK = 0x10000000, SECURITY_FLAG_STRENGTH_MEDIUM = 0x40000000, SECURITY_FLAG_STRENGTH_STRONG = 0x20000000, WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED = 0x00000001, WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT = 0x00000002, WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED = 0x00000004, WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA = 0x00000008, WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID = 0x00000010, WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID = 0x00000020, WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE = 0x00000040, WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR = 0x80000000, WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 = 0x00000008, WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 = 0x00000020, WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 = 0x00000080, WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 = 0x00000200, WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 = 0x00000800, WINHTTP_FLAG_SECURE_PROTOCOL_ALL = (WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 | WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1) } alias extern(Windows) int fnWINHTTP_STATUS_CALLBACK(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation,DWORD dwStatusInformationLength); alias WINHTTP_STATUS_CALLBACK = fnWINHTTP_STATUS_CALLBACK*; alias LPWINHTTP_STATUS_CALLBACK = WINHTTP_STATUS_CALLBACK*; enum : DWORD { WINHTTP_CALLBACK_STATUS_RESOLVING_NAME = 0x00000001, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED = 0x00000002, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER = 0x00000004, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER = 0x00000008, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST = 0x00000010, WINHTTP_CALLBACK_STATUS_REQUEST_SENT = 0x00000020, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE = 0x00000040, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED = 0x00000080, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION = 0x00000100, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED = 0x00000200, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED = 0x00000400, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING = 0x00000800, WINHTTP_CALLBACK_STATUS_DETECTING_PROXY = 0x00001000, WINHTTP_CALLBACK_STATUS_REDIRECT = 0x00004000, WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE = 0x00008000, WINHTTP_CALLBACK_STATUS_SECURE_FAILURE = 0x00010000, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE = 0x00020000, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE = 0x00040000, WINHTTP_CALLBACK_STATUS_READ_COMPLETE = 0x00080000, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE = 0x00100000, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR = 0x00200000, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE = 0x00400000 } enum : DWORD { WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE = 0x01000000, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE = 0x02000000, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE = 0x04000000 } enum : DWORD { API_RECEIVE_RESPONSE = 1, API_QUERY_DATA_AVAILABLE = 2, API_READ_DATA = 3, API_WRITE_DATA = 4, API_SEND_REQUEST = 5 } enum : DWORD { WINHTTP_CALLBACK_FLAG_RESOLVE_NAME = (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED), WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER = (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER), WINHTTP_CALLBACK_FLAG_SEND_REQUEST = (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT), WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE = (WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED), WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION = (WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED), WINHTTP_CALLBACK_FLAG_HANDLES = (WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING), WINHTTP_CALLBACK_FLAG_DETECTING_PROXY = WINHTTP_CALLBACK_STATUS_DETECTING_PROXY, WINHTTP_CALLBACK_FLAG_REDIRECT = WINHTTP_CALLBACK_STATUS_REDIRECT, WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE = WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE = WINHTTP_CALLBACK_STATUS_SECURE_FAILURE, WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE = WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE = WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE = WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, WINHTTP_CALLBACK_FLAG_READ_COMPLETE = WINHTTP_CALLBACK_STATUS_READ_COMPLETE, WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE = WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, WINHTTP_CALLBACK_FLAG_REQUEST_ERROR = WINHTTP_CALLBACK_STATUS_REQUEST_ERROR } enum DWORD WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE = WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE; // Windows 8+/2012+ static if (_WIN32_WINNT >= 0x602) { enum DWORD WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS = (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE | WINHTTP_CALLBACK_STATUS_READ_COMPLETE | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR); } else { enum DWORD WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS = (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE | WINHTTP_CALLBACK_STATUS_READ_COMPLETE | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE); } enum DWORD WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS = 0xffffffff; enum WINHTTP_INVALID_STATUS_CALLBACK = (cast(WINHTTP_STATUS_CALLBACK)(-1L)); enum : DWORD { WINHTTP_QUERY_MIME_VERSION = 0, WINHTTP_QUERY_CONTENT_TYPE = 1, WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2, WINHTTP_QUERY_CONTENT_ID = 3, WINHTTP_QUERY_CONTENT_DESCRIPTION = 4, WINHTTP_QUERY_CONTENT_LENGTH = 5, WINHTTP_QUERY_CONTENT_LANGUAGE = 6, WINHTTP_QUERY_ALLOW = 7, WINHTTP_QUERY_PUBLIC = 8, WINHTTP_QUERY_DATE = 9, WINHTTP_QUERY_EXPIRES = 10, WINHTTP_QUERY_LAST_MODIFIED = 11, WINHTTP_QUERY_MESSAGE_ID = 12, WINHTTP_QUERY_URI = 13, WINHTTP_QUERY_DERIVED_FROM = 14, WINHTTP_QUERY_COST = 15, WINHTTP_QUERY_LINK = 16, WINHTTP_QUERY_PRAGMA = 17, WINHTTP_QUERY_VERSION = 18, WINHTTP_QUERY_STATUS_CODE = 19, WINHTTP_QUERY_STATUS_TEXT = 20, WINHTTP_QUERY_RAW_HEADERS = 21, WINHTTP_QUERY_RAW_HEADERS_CRLF = 22, WINHTTP_QUERY_CONNECTION = 23, WINHTTP_QUERY_ACCEPT = 24, WINHTTP_QUERY_ACCEPT_CHARSET = 25, WINHTTP_QUERY_ACCEPT_ENCODING = 26, WINHTTP_QUERY_ACCEPT_LANGUAGE = 27, WINHTTP_QUERY_AUTHORIZATION = 28, WINHTTP_QUERY_CONTENT_ENCODING = 29, WINHTTP_QUERY_FORWARDED = 30, WINHTTP_QUERY_FROM = 31, WINHTTP_QUERY_IF_MODIFIED_SINCE = 32, WINHTTP_QUERY_LOCATION = 33, WINHTTP_QUERY_ORIG_URI = 34, WINHTTP_QUERY_REFERER = 35, WINHTTP_QUERY_RETRY_AFTER = 36, WINHTTP_QUERY_SERVER = 37, WINHTTP_QUERY_TITLE = 38, WINHTTP_QUERY_USER_AGENT = 39, WINHTTP_QUERY_WWW_AUTHENTICATE = 40, WINHTTP_QUERY_PROXY_AUTHENTICATE = 41, WINHTTP_QUERY_ACCEPT_RANGES = 42, WINHTTP_QUERY_SET_COOKIE = 43, WINHTTP_QUERY_COOKIE = 44, WINHTTP_QUERY_REQUEST_METHOD = 45, WINHTTP_QUERY_REFRESH = 46, WINHTTP_QUERY_CONTENT_DISPOSITION = 47, // HTTP 1.1 defined headers WINHTTP_QUERY_AGE = 48, WINHTTP_QUERY_CACHE_CONTROL = 49, WINHTTP_QUERY_CONTENT_BASE = 50, WINHTTP_QUERY_CONTENT_LOCATION = 51, WINHTTP_QUERY_CONTENT_MD5 = 52, WINHTTP_QUERY_CONTENT_RANGE = 53, WINHTTP_QUERY_ETAG = 54, WINHTTP_QUERY_HOST = 55, WINHTTP_QUERY_IF_MATCH = 56, WINHTTP_QUERY_IF_NONE_MATCH = 57, WINHTTP_QUERY_IF_RANGE = 58, WINHTTP_QUERY_IF_UNMODIFIED_SINCE = 59, WINHTTP_QUERY_MAX_FORWARDS = 60, WINHTTP_QUERY_PROXY_AUTHORIZATION = 61, WINHTTP_QUERY_RANGE = 62, WINHTTP_QUERY_TRANSFER_ENCODING = 63, WINHTTP_QUERY_UPGRADE = 64, WINHTTP_QUERY_VARY = 65, WINHTTP_QUERY_VIA = 66, WINHTTP_QUERY_WARNING = 67, WINHTTP_QUERY_EXPECT = 68, WINHTTP_QUERY_PROXY_CONNECTION = 69, WINHTTP_QUERY_UNLESS_MODIFIED_SINCE = 70, WINHTTP_QUERY_PROXY_SUPPORT = 75, WINHTTP_QUERY_AUTHENTICATION_INFO = 76, WINHTTP_QUERY_PASSPORT_URLS = 77, WINHTTP_QUERY_PASSPORT_CONFIG = 78, WINHTTP_QUERY_MAX = 78, WINHTTP_QUERY_CUSTOM = 65535, WINHTTP_QUERY_FLAG_REQUEST_HEADERS = 0x80000000, WINHTTP_QUERY_FLAG_SYSTEMTIME = 0x40000000, WINHTTP_QUERY_FLAG_NUMBER = 0x20000000 } enum : DWORD { HTTP_STATUS_CONTINUE = 100, HTTP_STATUS_SWITCH_PROTOCOLS = 101, HTTP_STATUS_OK = 200, HTTP_STATUS_CREATED = 201, HTTP_STATUS_ACCEPTED = 202, HTTP_STATUS_PARTIAL = 203, HTTP_STATUS_NO_CONTENT = 204, HTTP_STATUS_RESET_CONTENT = 205, HTTP_STATUS_PARTIAL_CONTENT = 206, HTTP_STATUS_WEBDAV_MULTI_STATUS = 207, HTTP_STATUS_AMBIGUOUS = 300, HTTP_STATUS_MOVED = 301, HTTP_STATUS_REDIRECT = 302, HTTP_STATUS_REDIRECT_METHOD = 303, HTTP_STATUS_NOT_MODIFIED = 304, HTTP_STATUS_USE_PROXY = 305, HTTP_STATUS_REDIRECT_KEEP_VERB = 307, HTTP_STATUS_BAD_REQUEST = 400, HTTP_STATUS_DENIED = 401, HTTP_STATUS_PAYMENT_REQ = 402, HTTP_STATUS_FORBIDDEN = 403, HTTP_STATUS_NOT_FOUND = 404, HTTP_STATUS_BAD_METHOD = 405, HTTP_STATUS_NONE_ACCEPTABLE = 406, HTTP_STATUS_PROXY_AUTH_REQ = 407, HTTP_STATUS_REQUEST_TIMEOUT = 408, HTTP_STATUS_CONFLICT = 409, HTTP_STATUS_GONE = 410, HTTP_STATUS_LENGTH_REQUIRED = 411, HTTP_STATUS_PRECOND_FAILED = 412, HTTP_STATUS_REQUEST_TOO_LARGE = 413, HTTP_STATUS_URI_TOO_LONG = 414, HTTP_STATUS_UNSUPPORTED_MEDIA = 415, HTTP_STATUS_RETRY_WITH = 449, HTTP_STATUS_SERVER_ERROR = 500, HTTP_STATUS_NOT_SUPPORTED = 501, HTTP_STATUS_BAD_GATEWAY = 502, HTTP_STATUS_SERVICE_UNAVAIL = 503, HTTP_STATUS_GATEWAY_TIMEOUT = 504, HTTP_STATUS_VERSION_NOT_SUP = 505, HTTP_STATUS_FIRST = HTTP_STATUS_CONTINUE, HTTP_STATUS_LAST = HTTP_STATUS_VERSION_NOT_SUP } enum LPCWSTR WINHTTP_NO_REFERER = null; enum LPCWSTR * WINHTTP_DEFAULT_ACCEPT_TYPES = null; enum : DWORD { WINHTTP_ADDREQ_INDEX_MASK = 0x0000FFFF, WINHTTP_ADDREQ_FLAGS_MASK = 0xFFFF0000, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW = 0x10000000, WINHTTP_ADDREQ_FLAG_ADD = 0x20000000, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA = 0x40000000, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON = 0x01000000, WINHTTP_ADDREQ_FLAG_COALESCE = WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA, WINHTTP_ADDREQ_FLAG_REPLACE = 0x80000000, WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH = 0 } enum LPCWSTR WINHTTP_NO_ADDITIONAL_HEADERS = null; enum LPVOID WINHTTP_NO_REQUEST_DATA = null; enum LPCWSTR WINHTTP_HEADER_NAME_BY_INDEX = null; enum LPVOID WINHTTP_NO_OUTPUT_BUFFER = null; enum LPDWORD WINHTTP_NO_HEADER_INDEX = null; struct WINHTTP_CURRENT_USER_IE_PROXY_CONFIG { BOOL fAutoDetect; LPWSTR lpszAutoConfigUrl; LPWSTR lpszProxy; LPWSTR lpszProxyBypass; } // WinHttp API error returns enum : DWORD { WINHTTP_ERROR_BASE = 12000, ERROR_WINHTTP_OUT_OF_HANDLES = (WINHTTP_ERROR_BASE + 1), ERROR_WINHTTP_TIMEOUT = (WINHTTP_ERROR_BASE + 2), ERROR_WINHTTP_INTERNAL_ERROR = (WINHTTP_ERROR_BASE + 4), ERROR_WINHTTP_INVALID_URL = (WINHTTP_ERROR_BASE + 5), ERROR_WINHTTP_UNRECOGNIZED_SCHEME = (WINHTTP_ERROR_BASE + 6), ERROR_WINHTTP_NAME_NOT_RESOLVED = (WINHTTP_ERROR_BASE + 7), ERROR_WINHTTP_INVALID_OPTION = (WINHTTP_ERROR_BASE + 9), ERROR_WINHTTP_OPTION_NOT_SETTABLE = (WINHTTP_ERROR_BASE + 11), ERROR_WINHTTP_SHUTDOWN = (WINHTTP_ERROR_BASE + 12), ERROR_WINHTTP_LOGIN_FAILURE = (WINHTTP_ERROR_BASE + 15), ERROR_WINHTTP_OPERATION_CANCELLED = (WINHTTP_ERROR_BASE + 17), ERROR_WINHTTP_INCORRECT_HANDLE_TYPE = (WINHTTP_ERROR_BASE + 18), ERROR_WINHTTP_INCORRECT_HANDLE_STATE = (WINHTTP_ERROR_BASE + 19), ERROR_WINHTTP_CANNOT_CONNECT = (WINHTTP_ERROR_BASE + 29), ERROR_WINHTTP_CONNECTION_ERROR = (WINHTTP_ERROR_BASE + 30), ERROR_WINHTTP_RESEND_REQUEST = (WINHTTP_ERROR_BASE + 32), ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED = (WINHTTP_ERROR_BASE, + 44), ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN = (WINHTTP_ERROR_BASE + 100), ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND = (WINHTTP_ERROR_BASE + 101), ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND = (WINHTTP_ERROR_BASE + 102), ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN = (WINHTTP_ERROR_BASE + 103), ERROR_WINHTTP_HEADER_NOT_FOUND = (WINHTTP_ERROR_BASE + 150), ERROR_WINHTTP_INVALID_SERVER_RESPONSE = (WINHTTP_ERROR_BASE + 152), ERROR_WINHTTP_INVALID_HEADER = (WINHTTP_ERROR_BASE + 153), ERROR_WINHTTP_INVALID_QUERY_REQUEST = (WINHTTP_ERROR_BASE + 154), ERROR_WINHTTP_HEADER_ALREADY_EXISTS = (WINHTTP_ERROR_BASE + 155), ERROR_WINHTTP_REDIRECT_FAILED = (WINHTTP_ERROR_BASE + 156), ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR = (WINHTTP_ERROR_BASE + 178), ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT = (WINHTTP_ERROR_BASE + 166), ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT = (WINHTTP_ERROR_BASE + 167), ERROR_WINHTTP_UNHANDLED_SCRIPT_TYPE = (WINHTTP_ERROR_BASE + 176), ERROR_WINHTTP_SCRIPT_EXECUTION_ERROR = (WINHTTP_ERROR_BASE + 177), ERROR_WINHTTP_NOT_INITIALIZED = (WINHTTP_ERROR_BASE + 172), ERROR_WINHTTP_SECURE_FAILURE = (WINHTTP_ERROR_BASE + 175), ERROR_WINHTTP_SECURE_CERT_DATE_INVALID = (WINHTTP_ERROR_BASE + 37), ERROR_WINHTTP_SECURE_CERT_CN_INVALID = (WINHTTP_ERROR_BASE + 38), ERROR_WINHTTP_SECURE_INVALID_CA = (WINHTTP_ERROR_BASE + 45), ERROR_WINHTTP_SECURE_CERT_REV_FAILED = (WINHTTP_ERROR_BASE + 57), ERROR_WINHTTP_SECURE_CHANNEL_ERROR = (WINHTTP_ERROR_BASE + 157), ERROR_WINHTTP_SECURE_INVALID_CERT = (WINHTTP_ERROR_BASE + 169), ERROR_WINHTTP_SECURE_CERT_REVOKED = (WINHTTP_ERROR_BASE + 170), ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE = (WINHTTP_ERROR_BASE + 179), ERROR_WINHTTP_AUTODETECTION_FAILED = (WINHTTP_ERROR_BASE + 180), ERROR_WINHTTP_HEADER_COUNT_EXCEEDED = (WINHTTP_ERROR_BASE + 181), ERROR_WINHTTP_HEADER_SIZE_OVERFLOW = (WINHTTP_ERROR_BASE + 182), ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW = (WINHTTP_ERROR_BASE + 183), ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW = (WINHTTP_ERROR_BASE + 184), ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY = (WINHTTP_ERROR_BASE + 185), ERROR_WINHTTP_CLIENT_CERT_NO_ACCESS_PRIVATE_KEY = (WINHTTP_ERROR_BASE + 186), WINHTTP_ERROR_LAST = (WINHTTP_ERROR_BASE + 186) } enum : DWORD { WINHTTP_RESET_STATE = 0x00000001, WINHTTP_RESET_SWPAD_CURRENT_NETWORK = 0x00000002, WINHTTP_RESET_SWPAD_ALL = 0x00000004, WINHTTP_RESET_SCRIPT_CACHE = 0x00000008, WINHTTP_RESET_ALL = 0x0000FFFF, WINHTTP_RESET_NOTIFY_NETWORK_CHANGED = 0x00010000, WINHTTP_RESET_OUT_OF_PROC = 0x00020000 } enum : DWORD { WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH = 123, WINHTTP_WEB_SOCKET_MIN_KEEPALIVE_VALUE = 15000 } // Version(Windows8) || Version(Windows2012): static if (_WIN32_WINNT >= 0x602) { enum WINHTTP_WEB_SOCKET_OPERATION : DWORD { WINHTTP_WEB_SOCKET_SEND_OPERATION = 0, WINHTTP_WEB_SOCKET_RECEIVE_OPERATION = 1, WINHTTP_WEB_SOCKET_CLOSE_OPERATION = 2, WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION = 3 } enum WINHTTP_WEB_SOCKET_BUFFER_TYPE : DWORD { WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE = 0, WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE = 1, WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE = 2, WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE = 3, WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE = 4 } enum WINHTTP_WEB_SOCKET_CLOSE_STATUS : DWORD { WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS = 1000, WINHTTP_WEB_SOCKET_ENDPOINT_TERMINATED_CLOSE_STATUS = 1001, WINHTTP_WEB_SOCKET_PROTOCOL_ERROR_CLOSE_STATUS = 1002, WINHTTP_WEB_SOCKET_INVALID_DATA_TYPE_CLOSE_STATUS = 1003, WINHTTP_WEB_SOCKET_EMPTY_CLOSE_STATUS = 1005, WINHTTP_WEB_SOCKET_ABORTED_CLOSE_STATUS = 1006, WINHTTP_WEB_SOCKET_INVALID_PAYLOAD_CLOSE_STATUS = 1007, WINHTTP_WEB_SOCKET_POLICY_VIOLATION_CLOSE_STATUS = 1008, WINHTTP_WEB_SOCKET_MESSAGE_TOO_BIG_CLOSE_STATUS = 1009, WINHTTP_WEB_SOCKET_UNSUPPORTED_EXTENSIONS_CLOSE_STATUS = 1010, WINHTTP_WEB_SOCKET_SERVER_ERROR_CLOSE_STATUS = 1011, WINHTTP_WEB_SOCKET_SECURE_HANDSHAKE_ERROR_CLOSE_STATUS = 1015 } struct WINHTTP_PROXY_RESULT_ENTRY { BOOL fProxy; BOOL fBypass; INTERNET_SCHEME ProxyScheme; PWSTR pwszProxy; INTERNET_PORT ProxyPort; } struct WINHTTP_PROXY_RESULT { DWORD cEntries; WINHTTP_PROXY_RESULT_ENTRY *pEntries; } struct WINHTTP_WEB_SOCKET_ASYNC_RESULT { WINHTTP_ASYNC_RESULT AsyncResult; WINHTTP_WEB_SOCKET_OPERATION Operation; } struct WINHTTP_WEB_SOCKET_STATUS { DWORD dwBytesTransferred; WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType; } } extern (Windows) { BOOL WinHttpAddRequestHeaders(HINTERNET hRequest, LPCWSTR pwszHeaders, DWORD dwHeadersLength, DWORD dwModifiers); BOOL WinHttpCheckPlatform(); BOOL WinHttpCloseHandle(HINTERNET hInternet); HINTERNET WinHttpConnect(HINTERNET hSession, LPCWSTR pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); BOOL WinHttpCrackUrl(LPCWSTR pwszUrl, DWORD dwUrlLength, DWORD dwFlags, LPURL_COMPONENTS lpUrlComponents); BOOL WinHttpCreateUrl(LPURL_COMPONENTS lpUrlComponents, DWORD dwFlags, LPWSTR pwszUrl, LPDWORD lpdwUrlLength); BOOL WinHttpDetectAutoProxyConfigUrl(DWORD dwAutoDetectFlags, LPWSTR *ppwszAutoConfigUrl); BOOL WinHttpGetDefaultProxyConfiguration(WINHTTP_PROXY_INFO *pProxyInfo); BOOL WinHttpGetIEProxyConfigForCurrentUser(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *pProxyConfig); BOOL WinHttpGetProxyForUrl(HINTERNET hSession, LPCWSTR lpcwszUrl, WINHTTP_AUTOPROXY_OPTIONS *pAutoProxyOptions, WINHTTP_PROXY_INFO *pProxyInfo); HINTERNET WinHttpOpen(LPCWSTR pwszUserAgent, DWORD dwAccessType, LPCWSTR pwszProxyName, LPCWSTR pwszProxyBypass, DWORD dwFlags); HINTERNET WinHttpOpenRequest(HINTERNET hConnect, LPCWSTR pwszVerb, LPCWSTR pwszObjectName, LPCWSTR pwszVersion, LPCWSTR pwszReferrer, LPCWSTR *ppwszAcceptTypes, DWORD dwFlags); BOOL WinHttpQueryAuthSchemes(HINTERNET hRequest, LPDWORD lpdwSupportedSchemes, LPDWORD lpdwFirstScheme, LPDWORD pdwAuthTarget); BOOL WinHttpQueryDataAvailable(HINTERNET hRequest, LPDWORD lpdwNumberOfBytesAvailable); BOOL WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR pwszName, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex); BOOL WinHttpQueryOption(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength); BOOL WinHttpReadData(HINTERNET hRequest, LPVOID lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD lpdwNumberOfBytesRead); BOOL WinHttpReceiveResponse(HINTERNET hRequest, LPVOID lpReserved); BOOL WinHttpSendRequest(HINTERNET hRequest, LPCWSTR pwszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); BOOL WinHttpSetCredentials(HINTERNET hRequest, DWORD AuthTargets, DWORD AuthScheme, LPCWSTR pwszUserName, LPCWSTR pwszPassword, LPVOID pAuthParams); BOOL WinHttpSetDefaultProxyConfiguration(WINHTTP_PROXY_INFO *pProxyInfo); BOOL WinHttpSetOption(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength); WINHTTP_STATUS_CALLBACK WinHttpSetStatusCallback(HINTERNET hInternet, WINHTTP_STATUS_CALLBACK lpfnInternetCallback, DWORD dwNotificationFlags, DWORD_PTR dwReserved); BOOL WinHttpSetTimeouts(HINTERNET hInternet, int dwResolveTimeout, int dwConnectTimeout, int dwSendTimeout, int dwReceiveTimeout); BOOL WinHttpTimeFromSystemTime(const SYSTEMTIME *pst, LPWSTR pwszTime); BOOL WinHttpTimeToSystemTime(LPCWSTR pwszTime, SYSTEMTIME *pst); BOOL WinHttpWriteData(HINTERNET hRequest, LPCVOID lpBuffer, DWORD dwNumberOfBytesToWrite, LPDWORD lpdwNumberOfBytesWritten); // Version(Windows8) || Version(Windows2012): static if (_WIN32_WINNT >= 0x602) { DWORD WinHttpCreateProxyResolver(HINTERNET hSession, HINTERNET *phResolver); void WinHttpFreeProxyResult(WINHTTP_PROXY_RESULT *pProxyResult); DWORD WinHttpGetProxyForUrlEx(HINTERNET hResolver, PCWSTR pcwszUrl, WINHTTP_AUTOPROXY_OPTIONS *pAutoProxyOptions, DWORD_PTR pContext); DWORD WinHttpGetProxyResult(HINTERNET hResolver, WINHTTP_PROXY_RESULT *pProxyResult); DWORD WinHttpResetAutoProxy(HINTERNET hSession, DWORD dwFlags); DWORD WinHttpWebSocketClose(HINTERNET hWebSocket, USHORT usStatus, PVOID pvReason, DWORD dwReasonLength); HINTERNET WinHttpWebSocketCompleteUpgrade(HINTERNET hRequest, DWORD_PTR pContext); DWORD WinHttpWebSocketQueryCloseStatus(HINTERNET hWebSocket, USHORT *pusStatus, PVOID pvReason, DWORD dwReasonLength, DWORD *pdwReasonLengthConsumed); DWORD WinHttpWebSocketReceive(HINTERNET hWebSocket, PVOID pvBuffer, DWORD dwBufferLength, DWORD *pdwBytesRead, WINHTTP_WEB_SOCKET_BUFFER_TYPE *peBufferType); DWORD WinHttpWebSocketSend(HINTERNET hWebSocket, WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType, PVOID pvBuffer, DWORD dwBufferLength); DWORD WinHttpWebSocketShutdown(HINTERNET hWebSocket, USHORT usStatus, PVOID pvReason, DWORD dwReasonLength); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ole2ver.d0000664000175000017500000000055712776214756023244 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ole2ver.d) */ module core.sys.windows.ole2ver; version (Windows): // These are apparently not documented on the MSDN site enum rmm = 23; enum rup = 639; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ocidl.d0000664000175000017500000003055612776214756022762 0ustar kaikai/** * Windows API header module * * Part of the Internet Development SDK * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ocidl.d) */ module core.sys.windows.ocidl; version (Windows): private import core.sys.windows.ole2, core.sys.windows.oleidl, core.sys.windows.oaidl, core.sys.windows.objfwd, core.sys.windows.windef, core.sys.windows.wtypes; private import core.sys.windows.objidl; // for CLIPFORMAT private import core.sys.windows.wingdi; // for TEXTMETRICW private import core.sys.windows.winuser; // for LPMSG interface IBindHost : IUnknown {} interface IServiceProvider : IUnknown{ HRESULT QueryService(REFGUID,REFIID,void**); } /* // TODO: //private import core.sys.windows.servprov; // for IServiceProvider // private import core.sys.windows.urlmon; // for IBindHost. This is not included in MinGW. // core.sys.windows.urlmon should contain: interface IBindHost : IUnknown { HRESULT CreateMoniker(LPOLESTR szName, IBindCtx pBC, IMoniker* ppmk, DWORD); HRESULT MonikerBindToObject(IMoniker pMk, IBindCtx pBC, IBindStatusCallback pBSC, REFIID, void** ); HRESULT MonikerBindToStorage(IMoniker pMk, IBindCtx pBC, IBindStatusCallback pBSC, REFIID, void** ); } */ //[Yes] #ifndef OLE2ANSI alias TEXTMETRICW TEXTMETRICOLE; //} else { //alias TEXTMETRIC TEXTMETRICOLE; //} alias TEXTMETRICOLE* LPTEXTMETRICOLE; alias DWORD OLE_COLOR; alias UINT OLE_HANDLE; alias int OLE_XPOS_HIMETRIC; alias int OLE_YPOS_HIMETRIC; alias int OLE_XSIZE_HIMETRIC; alias int OLE_YSIZE_HIMETRIC; enum READYSTATE { READYSTATE_UNINITIALIZED = 0, READYSTATE_LOADING = 1, READYSTATE_LOADED = 2, READYSTATE_INTERACTIVE = 3, READYSTATE_COMPLETE = 4 } enum PROPBAG2_TYPE { PROPBAG2_TYPE_UNDEFINED, PROPBAG2_TYPE_DATA, PROPBAG2_TYPE_URL, PROPBAG2_TYPE_OBJECT, PROPBAG2_TYPE_STREAM, PROPBAG2_TYPE_STORAGE, PROPBAG2_TYPE_MONIKER // = 6 } struct PROPBAG2 { DWORD dwType; VARTYPE vt; CLIPFORMAT cfType; DWORD dwHint; LPOLESTR pstrName; CLSID clsid; } enum QACONTAINERFLAGS { QACONTAINER_SHOWHATCHING = 1, QACONTAINER_SHOWGRABHANDLES = 2, QACONTAINER_USERMODE = 4, QACONTAINER_DISPLAYASDEFAULT = 8, QACONTAINER_UIDEAD = 16, QACONTAINER_AUTOCLIP = 32, QACONTAINER_MESSAGEREFLECT = 64, QACONTAINER_SUPPORTSMNEMONICS = 128 } struct QACONTAINER { ULONG cbSize = this.sizeof; IOleClientSite pClientSite; IAdviseSinkEx pAdviseSink; IPropertyNotifySink pPropertyNotifySink; IUnknown pUnkEventSink; DWORD dwAmbientFlags; OLE_COLOR colorFore; OLE_COLOR colorBack; IFont pFont; IOleUndoManager pUndoMgr; DWORD dwAppearance; LONG lcid; HPALETTE hpal; IBindHost pBindHost; IOleControlSite pOleControlSite; IServiceProvider pServiceProvider; } struct QACONTROL { ULONG cbSize = this.sizeof; DWORD dwMiscStatus; DWORD dwViewStatus; DWORD dwEventCookie; DWORD dwPropNotifyCookie; DWORD dwPointerActivationPolicy; } struct POINTF { float x; float y; } alias POINTF* LPPOINTF; struct CONTROLINFO { ULONG cb; HACCEL hAccel; USHORT cAccel; DWORD dwFlags; } alias CONTROLINFO* LPCONTROLINFO; struct CONNECTDATA { LPUNKNOWN pUnk; DWORD dwCookie; } alias CONNECTDATA* LPCONNECTDATA; struct LICINFO { int cbLicInfo; BOOL fRuntimeKeyAvail; BOOL fLicVerified; } alias LICINFO* LPLICINFO; struct CAUUID { ULONG cElems; GUID* pElems; } alias CAUUID* LPCAUUID; struct CALPOLESTR { ULONG cElems; LPOLESTR* pElems; } alias CALPOLESTR* LPCALPOLESTR; struct CADWORD { ULONG cElems; DWORD* pElems; } alias CADWORD* LPCADWORD; struct PROPPAGEINFO { ULONG cb; LPOLESTR pszTitle; SIZE size; LPOLESTR pszDocString; LPOLESTR pszHelpFile; DWORD dwHelpContext; } alias PROPPAGEINFO* LPPROPPAGEINFO; interface IOleControl : IUnknown { HRESULT GetControlInfo(LPCONTROLINFO); HRESULT OnMnemonic(LPMSG); HRESULT OnAmbientPropertyChange(DISPID); HRESULT FreezeEvents(BOOL); } interface IOleControlSite : IUnknown { HRESULT OnControlInfoChanged(); HRESULT LockInPlaceActive(BOOL); HRESULT GetExtendedControl(LPDISPATCH*); HRESULT TransformCoords(POINTL*, POINTF*, DWORD); HRESULT TranslateAccelerator(LPMSG, DWORD); HRESULT OnFocus(BOOL); HRESULT ShowPropertyFrame(); } interface ISimpleFrameSite : IUnknown { HRESULT PreMessageFilter(HWND, UINT, WPARAM, LPARAM, LRESULT*, PDWORD); HRESULT PostMessageFilter(HWND, UINT, WPARAM, LPARAM, LRESULT*, DWORD); } interface IErrorLog : IUnknown { HRESULT AddError(LPCOLESTR, LPEXCEPINFO); } alias IErrorLog LPERRORLOG; interface IPropertyBag : IUnknown { HRESULT Read(LPCOLESTR, LPVARIANT, LPERRORLOG); HRESULT Write(LPCOLESTR, LPVARIANT); } alias IPropertyBag LPPROPERTYBAG; interface IPropertyBag2 : IUnknown { HRESULT Read(ULONG, PROPBAG2*, LPERRORLOG, VARIANT*, HRESULT*); HRESULT Write(ULONG, PROPBAG2*, VARIANT*); HRESULT CountProperties(ULONG*); HRESULT GetPropertyInfo(ULONG, ULONG, PROPBAG2*, ULONG*); HRESULT LoadObject(LPCOLESTR, DWORD, IUnknown, LPERRORLOG); } alias IPropertyBag2 LPPROPERTYBAG2; interface IPersistPropertyBag : IPersist { HRESULT InitNew(); HRESULT Load(LPPROPERTYBAG, LPERRORLOG); HRESULT Save(LPPROPERTYBAG, BOOL, BOOL); } interface IPersistPropertyBag2 : IPersist { HRESULT InitNew(); HRESULT Load(LPPROPERTYBAG2, LPERRORLOG); HRESULT Save(LPPROPERTYBAG2, BOOL, BOOL); HRESULT IsDirty(); } interface IPersistStreamInit : IPersist { HRESULT IsDirty(); HRESULT Load(LPSTREAM); HRESULT Save(LPSTREAM, BOOL); HRESULT GetSizeMax(PULARGE_INTEGER); HRESULT InitNew(); } interface IPersistMemory : IPersist { HRESULT IsDirty(); HRESULT Load(PVOID, ULONG); HRESULT Save(PVOID, BOOL, ULONG); HRESULT GetSizeMax(PULONG); HRESULT InitNew(); } interface IPropertyNotifySink : IUnknown { HRESULT OnChanged(DISPID); HRESULT OnRequestEdit(DISPID); } interface IProvideClassInfo : IUnknown { HRESULT GetClassInfo(LPTYPEINFO*); } interface IProvideClassInfo2 : IProvideClassInfo { HRESULT GetGUID(DWORD, GUID*); } interface IConnectionPointContainer : IUnknown { HRESULT EnumConnectionPoints(LPENUMCONNECTIONPOINTS*); HRESULT FindConnectionPoint(REFIID, LPCONNECTIONPOINT*); } interface IEnumConnectionPoints : IUnknown { HRESULT Next(ULONG, LPCONNECTIONPOINT*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(LPENUMCONNECTIONPOINTS*); } alias IEnumConnectionPoints LPENUMCONNECTIONPOINTS; interface IConnectionPoint : IUnknown { HRESULT GetConnectionInterface(IID*); HRESULT GetConnectionPointContainer(IConnectionPointContainer*); HRESULT Advise(LPUNKNOWN, PDWORD); HRESULT Unadvise(DWORD); HRESULT EnumConnections(LPENUMCONNECTIONS*); } alias IConnectionPoint LPCONNECTIONPOINT; interface IEnumConnections : IUnknown { HRESULT Next(ULONG, LPCONNECTDATA, PULONG); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(LPENUMCONNECTIONS*); } alias IEnumConnections LPENUMCONNECTIONS; interface IClassFactory2 : IClassFactory { HRESULT GetLicInfo(LPLICINFO); HRESULT RequestLicKey(DWORD, BSTR*); HRESULT CreateInstanceLic(LPUNKNOWN, LPUNKNOWN, REFIID, BSTR, PVOID*); } interface ISpecifyPropertyPages : IUnknown { HRESULT GetPages(CAUUID*); } interface IPerPropertyBrowsing : IUnknown { HRESULT GetDisplayString(DISPID, BSTR*); HRESULT MapPropertyToPage(DISPID, LPCLSID); HRESULT GetPredefinedStrings(DISPID, CALPOLESTR*, CADWORD*); HRESULT GetPredefinedValue(DISPID, DWORD, VARIANT*); } interface IPropertyPageSite : IUnknown { HRESULT OnStatusChange(DWORD); HRESULT GetLocaleID(LCID*); HRESULT GetPageContainer(LPUNKNOWN*); HRESULT TranslateAccelerator(LPMSG); } alias IPropertyPageSite LPPROPERTYPAGESITE; interface IPropertyPage : IUnknown { HRESULT SetPageSite(LPPROPERTYPAGESITE); HRESULT Activate(HWND, LPCRECT, BOOL); HRESULT Deactivate(); HRESULT GetPageInfo(LPPROPPAGEINFO); HRESULT SetObjects(ULONG, LPUNKNOWN*); HRESULT Show(UINT); HRESULT Move(LPCRECT); HRESULT IsPageDirty(); HRESULT Apply(); HRESULT Help(LPCOLESTR); HRESULT TranslateAccelerator(LPMSG); } interface IPropertyPage2 : IPropertyPage { HRESULT EditProperty(DISPID); } interface IFont : IUnknown { HRESULT get_Name(BSTR*); HRESULT put_Name(BSTR); HRESULT get_Size(CY*); HRESULT put_Size(CY); HRESULT get_Bold(BOOL*); HRESULT put_Bold(BOOL); HRESULT get_Italic(BOOL*); HRESULT put_Italic(BOOL); HRESULT get_Underline(BOOL*); HRESULT put_Underline(BOOL); HRESULT get_Strikethrough(BOOL*); HRESULT put_Strikethrough(BOOL); HRESULT get_Weight(short*); HRESULT put_Weight(short); HRESULT get_Charset(short*); HRESULT put_Charset(short); HRESULT get_hFont(HFONT*); HRESULT Clone(IFont*); HRESULT IsEqual(IFont); HRESULT SetRatio(int, int); HRESULT QueryTextMetrics(LPTEXTMETRICOLE); HRESULT AddRefHfont(HFONT); HRESULT ReleaseHfont(HFONT); HRESULT SetHdc(HDC); } alias IFont LPFONT; interface IFontDisp : IDispatch { } alias IFontDisp LPFONTDISP; interface IPicture : IUnknown { HRESULT get_Handle(OLE_HANDLE*); HRESULT get_hPal(OLE_HANDLE*); HRESULT get_Type(short*); HRESULT get_Width(OLE_XSIZE_HIMETRIC*); HRESULT get_Height(OLE_YSIZE_HIMETRIC*); HRESULT Render(HDC, int, int, int, int, OLE_XPOS_HIMETRIC, OLE_YPOS_HIMETRIC, OLE_XSIZE_HIMETRIC, OLE_YSIZE_HIMETRIC, LPCRECT); HRESULT set_hPal(OLE_HANDLE); HRESULT get_CurDC(HDC*); HRESULT SelectPicture(HDC, HDC*, OLE_HANDLE*); HRESULT get_KeepOriginalFormat(BOOL*); HRESULT put_KeepOriginalFormat(BOOL); HRESULT PictureChanged(); HRESULT SaveAsFile(LPSTREAM, BOOL, LONG*); HRESULT get_Attributes(PDWORD); } interface IPictureDisp : IDispatch { } interface IOleInPlaceSiteEx : IOleInPlaceSite { HRESULT OnInPlaceActivateEx(BOOL*, DWORD); HRESULT OnInPlaceDeactivateEx(BOOL); HRESULT RequestUIActivate(); } interface IObjectWithSite : IUnknown { HRESULT SetSite(IUnknown); HRESULT GetSite(REFIID, void**); } interface IOleInPlaceSiteWindowless : IOleInPlaceSiteEx { HRESULT CanWindowlessActivate(); HRESULT GetCapture(); HRESULT SetCapture(BOOL); HRESULT GetFocus(); HRESULT SetFocus(BOOL); HRESULT GetDC(LPCRECT, DWORD, HDC*); HRESULT ReleaseDC(HDC); HRESULT InvalidateRect(LPCRECT, BOOL); HRESULT InvalidateRgn(HRGN, BOOL); HRESULT ScrollRect(INT, INT, LPCRECT, LPCRECT); HRESULT AdjustRect(LPCRECT); HRESULT OnDefWindowMessage(UINT, WPARAM, LPARAM, LRESULT*); } interface IAdviseSinkEx : IUnknown { void OnDataChange(FORMATETC*, STGMEDIUM*); void OnViewChange(DWORD, LONG); void OnRename(IMoniker); void OnSave(); void OnClose(); HRESULT OnViewStatusChange(DWORD); } interface IPointerInactive : IUnknown { HRESULT GetActivationPolicy(DWORD*); HRESULT OnInactiveMouseMove(LPCRECT, LONG, LONG, DWORD); HRESULT OnInactiveSetCursor(LPCRECT, LONG, LONG, DWORD, BOOL); } interface IOleUndoUnit : IUnknown { HRESULT Do(LPOLEUNDOMANAGER); HRESULT GetDescription(BSTR*); HRESULT GetUnitType(CLSID*, LONG*); HRESULT OnNextAdd(); } interface IOleParentUndoUnit : IOleUndoUnit { HRESULT Open(IOleParentUndoUnit); HRESULT Close(IOleParentUndoUnit, BOOL); HRESULT Add(IOleUndoUnit); HRESULT FindUnit(IOleUndoUnit); HRESULT GetParentState(DWORD*); } interface IEnumOleUndoUnits : IUnknown { HRESULT Next(ULONG, IOleUndoUnit*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumOleUndoUnits*); } interface IOleUndoManager : IUnknown { HRESULT Open(IOleParentUndoUnit); HRESULT Close(IOleParentUndoUnit, BOOL); HRESULT Add(IOleUndoUnit); HRESULT GetOpenParentState(DWORD*); HRESULT DiscardFrom(IOleUndoUnit); HRESULT UndoTo(IOleUndoUnit); HRESULT RedoTo(IOleUndoUnit); HRESULT EnumUndoable(IEnumOleUndoUnits*); HRESULT EnumRedoable(IEnumOleUndoUnits*); HRESULT GetLastUndoDescription(BSTR*); HRESULT GetLastRedoDescription(BSTR*); HRESULT Enable(BOOL); } alias IOleUndoManager LPOLEUNDOMANAGER; interface IQuickActivate : IUnknown { HRESULT QuickActivate(QACONTAINER*, QACONTROL*); HRESULT SetContentExtent(LPSIZEL); HRESULT GetContentExtent(LPSIZEL); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmsvc.d0000664000175000017500000001327712776214756023015 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmsvc.d) */ module core.sys.windows.lmsvc; version (Windows): // FIXME: Is this file deprecated? All of the functions are only for Win16. /** Changes relative to MinGW: lmsname is not imported publicly (instead, core.sys.windows.lm imports it directly). */ // TODO: 5 macros private import core.sys.windows.lmcons, core.sys.windows.lmsname, core.sys.windows.windef; const TCHAR[] SERVICE_DOS_ENCRYPTION = "ENCRYPT"; enum SERVICE_UNINSTALLED=0; enum SERVICE_INSTALL_PENDING=1; enum SERVICE_UNINSTALL_PENDING=2; enum SERVICE_INSTALLED=3; enum SERVICE_INSTALL_STATE=3; enum SERVICE_PAUSE_STATE=18; enum LM20_SERVICE_ACTIVE=0; enum LM20_SERVICE_CONTINUE_PENDING=4; enum LM20_SERVICE_PAUSE_PENDING=8; enum LM20_SERVICE_PAUSED=18; enum SERVICE_NOT_UNINSTALLABLE=0; enum SERVICE_UNINSTALLABLE=16; enum SERVICE_NOT_PAUSABLE=0; enum SERVICE_PAUSABLE=32; enum SERVICE_REDIR_PAUSED=0x700; enum SERVICE_REDIR_DISK_PAUSED=256; enum SERVICE_REDIR_PRINT_PAUSED=512; enum SERVICE_REDIR_COMM_PAUSED=1024; enum SERVICE_CTRL_INTERROGATE=0; enum SERVICE_CTRL_PAUSE=1; enum SERVICE_CTRL_CONTINUE=2; enum SERVICE_CTRL_UNINSTALL=3; enum SERVICE_CTRL_REDIR_DISK=1; enum SERVICE_CTRL_REDIR_PRINT=2; enum SERVICE_CTRL_REDIR_COMM=4; enum SERVICE_IP_NO_HINT=0; enum SERVICE_CCP_NO_HINT=0; enum SERVICE_IP_QUERY_HINT=0x10000; enum SERVICE_CCP_QUERY_HINT=0x10000; enum SERVICE_IP_CHKPT_NUM=255; enum SERVICE_CCP_CHKPT_NUM=255; enum SERVICE_IP_WAIT_TIME=0xFF00; enum SERVICE_CCP_WAIT_TIME=0xFF00; enum SERVICE_IP_WAITTIME_SHIFT=8; enum SERVICE_NTIP_WAITTIME_SHIFT=12; enum UPPER_HINT_MASK=0xFF00; enum LOWER_HINT_MASK=255; enum UPPER_GET_HINT_MASK=0xFF00000; enum LOWER_GET_HINT_MASK=0xFF00; enum SERVICE_NT_MAXTIME=0xFFFF; enum SERVICE_RESRV_MASK=0x1FFFF; enum SERVICE_MAXTIME=255; enum SERVICE_BASE=3050; enum SERVICE_UIC_NORMAL=0; enum SERVICE_UIC_BADPARMVAL = SERVICE_BASE+1; enum SERVICE_UIC_MISSPARM = SERVICE_BASE+2; enum SERVICE_UIC_UNKPARM = SERVICE_BASE+3; enum SERVICE_UIC_RESOURCE = SERVICE_BASE+4; enum SERVICE_UIC_CONFIG = SERVICE_BASE+5; enum SERVICE_UIC_SYSTEM = SERVICE_BASE+6; enum SERVICE_UIC_INTERNAL = SERVICE_BASE+7; enum SERVICE_UIC_AMBIGPARM = SERVICE_BASE+8; enum SERVICE_UIC_DUPPARM = SERVICE_BASE+9; enum SERVICE_UIC_KILL = SERVICE_BASE+10; enum SERVICE_UIC_EXEC = SERVICE_BASE+11; enum SERVICE_UIC_SUBSERV = SERVICE_BASE+12; enum SERVICE_UIC_CONFLPARM = SERVICE_BASE+13; enum SERVICE_UIC_FILE = SERVICE_BASE+14; enum SERVICE_UIC_M_NULL=0; enum SERVICE_UIC_M_MEMORY = SERVICE_BASE+20; enum SERVICE_UIC_M_DISK = SERVICE_BASE+21; enum SERVICE_UIC_M_THREADS = SERVICE_BASE+22; enum SERVICE_UIC_M_PROCESSES = SERVICE_BASE+23; enum SERVICE_UIC_M_SECURITY = SERVICE_BASE+24; enum SERVICE_UIC_M_LANROOT = SERVICE_BASE+25; enum SERVICE_UIC_M_REDIR = SERVICE_BASE+26; enum SERVICE_UIC_M_SERVER = SERVICE_BASE+27; enum SERVICE_UIC_M_SEC_FILE_ERR = SERVICE_BASE+28; enum SERVICE_UIC_M_FILES = SERVICE_BASE+29; enum SERVICE_UIC_M_LOGS = SERVICE_BASE+30; enum SERVICE_UIC_M_LANGROUP = SERVICE_BASE+31; enum SERVICE_UIC_M_MSGNAME = SERVICE_BASE+32; enum SERVICE_UIC_M_ANNOUNCE = SERVICE_BASE+33; enum SERVICE_UIC_M_UAS = SERVICE_BASE+34; enum SERVICE_UIC_M_SERVER_SEC_ERR = SERVICE_BASE+35; enum SERVICE_UIC_M_WKSTA = SERVICE_BASE+37; enum SERVICE_UIC_M_ERRLOG = SERVICE_BASE+38; enum SERVICE_UIC_M_FILE_UW = SERVICE_BASE+39; enum SERVICE_UIC_M_ADDPAK = SERVICE_BASE+40; enum SERVICE_UIC_M_LAZY = SERVICE_BASE+41; enum SERVICE_UIC_M_UAS_MACHINE_ACCT = SERVICE_BASE+42; enum SERVICE_UIC_M_UAS_SERVERS_NMEMB = SERVICE_BASE+43; enum SERVICE_UIC_M_UAS_SERVERS_NOGRP = SERVICE_BASE+44; enum SERVICE_UIC_M_UAS_INVALID_ROLE = SERVICE_BASE+45; enum SERVICE_UIC_M_NETLOGON_NO_DC = SERVICE_BASE+46; enum SERVICE_UIC_M_NETLOGON_DC_CFLCT = SERVICE_BASE+47; enum SERVICE_UIC_M_NETLOGON_AUTH = SERVICE_BASE+48; enum SERVICE_UIC_M_UAS_PROLOG = SERVICE_BASE+49; enum SERVICE2_BASE=5600; enum SERVICE_UIC_M_NETLOGON_MPATH = SERVICE2_BASE+0; enum SERVICE_UIC_M_LSA_MACHINE_ACCT = SERVICE2_BASE+1; enum SERVICE_UIC_M_DATABASE_ERROR = SERVICE2_BASE+2; struct SERVICE_INFO_0 { LPWSTR svci0_name; } alias SERVICE_INFO_0* PSERVICE_INFO_0, LPSERVICE_INFO_0; struct SERVICE_INFO_1 { LPWSTR svci1_name; DWORD svci1_status; DWORD svci1_code; DWORD svci1_pid; } alias SERVICE_INFO_1* PSERVICE_INFO_1, LPSERVICE_INFO_1; struct SERVICE_INFO_2 { LPWSTR svci2_name; DWORD svci2_status; DWORD svci2_code; DWORD svci2_pid; LPWSTR svci2_text; DWORD svci2_specific_error; LPWSTR svci2_display_name; } alias SERVICE_INFO_2* PSERVICE_INFO_2, LPSERVICE_INFO_2; extern (Windows) { deprecated { NET_API_STATUS NetServiceControl(LPCWSTR, LPCWSTR, DWORD, DWORD, PBYTE*); NET_API_STATUS NetServiceEnum(LPCWSTR, DWORD, PBYTE*, DWORD, PDWORD, PDWORD, PDWORD); NET_API_STATUS NetServiceGetInfo(LPCWSTR, LPCWSTR, DWORD, PBYTE*); NET_API_STATUS NetServiceInstall(LPCWSTR, LPCWSTR, DWORD, LPCWSTR*, PBYTE*); } } //MACRO #define SERVICE_IP_CODE(t, n) ((long)SERVICE_IP_QUERY_HINT|(long)(n|(t<>SERVICE_NTIP_WAITTIME_SHIFT)|(((c)&LOWER_GET_HINT_MASK)>>SERVICE_IP_WAITTIME_SHIFT)) ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/powrprof.d0000664000175000017500000001144112776214756023536 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_powrprof.d) */ module core.sys.windows.powrprof; version (Windows): pragma(lib, "powrprof"); private import core.sys.windows.windef; private import core.sys.windows.ntdef; // FIXME: look up Windows version support enum ULONG EnableSysTrayBatteryMeter = 1, EnableMultiBatteryDisplay = 2, EnablePasswordLogon = 4, EnableWakeOnRing = 8, EnableVideoDimDisplay = 16; enum UINT NEWSCHEME = -1; struct GLOBAL_MACHINE_POWER_POLICY { ULONG Revision; SYSTEM_POWER_STATE LidOpenWakeAc; SYSTEM_POWER_STATE LidOpenWakeDc; ULONG BroadcastCapacityResolution; } alias GLOBAL_MACHINE_POWER_POLICY* PGLOBAL_MACHINE_POWER_POLICY; struct GLOBAL_USER_POWER_POLICY { ULONG Revision; POWER_ACTION_POLICY PowerButtonAc; POWER_ACTION_POLICY PowerButtonDc; POWER_ACTION_POLICY SleepButtonAc; POWER_ACTION_POLICY SleepButtonDc; POWER_ACTION_POLICY LidCloseAc; POWER_ACTION_POLICY LidCloseDc; SYSTEM_POWER_LEVEL[NUM_DISCHARGE_POLICIES] DischargePolicy; ULONG GlobalFlags; } alias GLOBAL_USER_POWER_POLICY* PGLOBAL_USER_POWER_POLICY; struct GLOBAL_POWER_POLICY { GLOBAL_USER_POWER_POLICY user; GLOBAL_MACHINE_POWER_POLICY mach; } alias GLOBAL_POWER_POLICY* PGLOBAL_POWER_POLICY; struct MACHINE_POWER_POLICY { ULONG Revision; SYSTEM_POWER_STATE MinSleepAc; SYSTEM_POWER_STATE MinSleepDc; SYSTEM_POWER_STATE ReducedLatencySleepAc; SYSTEM_POWER_STATE ReducedLatencySleepDc; ULONG DozeTimeoutAc; ULONG DozeTimeoutDc; ULONG DozeS4TimeoutAc; ULONG DozeS4TimeoutDc; UCHAR MinThrottleAc; UCHAR MinThrottleDc; UCHAR[2] pad1; POWER_ACTION_POLICY OverThrottledAc; POWER_ACTION_POLICY OverThrottledDc; } alias MACHINE_POWER_POLICY* PMACHINE_POWER_POLICY; struct MACHINE_PROCESSOR_POWER_POLICY { ULONG Revision; PROCESSOR_POWER_POLICY ProcessorPolicyAc; PROCESSOR_POWER_POLICY ProcessorPolicyDc; } alias MACHINE_PROCESSOR_POWER_POLICY* PMACHINE_PROCESSOR_POWER_POLICY; struct USER_POWER_POLICY { ULONG Revision; POWER_ACTION_POLICY IdleAc; POWER_ACTION_POLICY IdleDc; ULONG IdleTimeoutAc; ULONG IdleTimeoutDc; UCHAR IdleSensitivityAc; UCHAR IdleSensitivityDc; UCHAR ThrottlePolicyAc; UCHAR ThrottlePolicyDc; SYSTEM_POWER_STATE MaxSleepAc; SYSTEM_POWER_STATE MaxSleepDc; ULONG[2] Reserved; ULONG VideoTimeoutAc; ULONG VideoTimeoutDc; ULONG SpindownTimeoutAc; ULONG SpindownTimeoutDc; BOOLEAN OptimizeForPowerAc; BOOLEAN OptimizeForPowerDc; UCHAR FanThrottleToleranceAc; UCHAR FanThrottleToleranceDc; UCHAR ForcedThrottleAc; UCHAR ForcedThrottleDc; } alias USER_POWER_POLICY* PUSER_POWER_POLICY; struct POWER_POLICY { USER_POWER_POLICY user; MACHINE_POWER_POLICY mach; } alias POWER_POLICY* PPOWER_POLICY; extern (Windows) { alias BOOLEAN function(UINT, DWORD, LPTSTR, DWORD, LPTSTR, PPOWER_POLICY, LPARAM) PWRSCHEMESENUMPROC; alias BOOLEAN function(POWER_ACTION, SYSTEM_POWER_STATE, ULONG, BOOLEAN) PFNNTINITIATEPWRACTION; NTSTATUS CallNtPowerInformation(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG); BOOLEAN CanUserWritePwrScheme(); BOOLEAN DeletePwrScheme(UINT); BOOLEAN EnumPwrSchemes(PWRSCHEMESENUMPROC, LPARAM); BOOLEAN GetActivePwrScheme(PUINT); BOOLEAN GetCurrentPowerPolicies(PGLOBAL_POWER_POLICY, PPOWER_POLICY); BOOLEAN GetPwrCapabilities(PSYSTEM_POWER_CAPABILITIES); BOOLEAN GetPwrDiskSpindownRange(PUINT, PUINT); BOOLEAN IsAdminOverrideActive(PADMINISTRATOR_POWER_POLICY); BOOLEAN IsPwrHibernateAllowed(); BOOLEAN IsPwrShutdownAllowed(); BOOLEAN IsPwrSuspendAllowed(); BOOLEAN ReadGlobalPwrPolicy(PGLOBAL_POWER_POLICY); BOOLEAN ReadProcessorPwrScheme(UINT, PMACHINE_PROCESSOR_POWER_POLICY); BOOLEAN ReadPwrScheme(UINT, PPOWER_POLICY); BOOLEAN SetActivePwrScheme(UINT, PGLOBAL_POWER_POLICY, PPOWER_POLICY); BOOLEAN SetSuspendState(BOOLEAN, BOOLEAN, BOOLEAN); BOOLEAN WriteGlobalPwrPolicy(PGLOBAL_POWER_POLICY); BOOLEAN WriteProcessorPwrScheme(UINT, PMACHINE_PROCESSOR_POWER_POLICY); BOOLEAN ValidatePowerPolicies(PGLOBAL_POWER_POLICY, PPOWER_POLICY); BOOLEAN WritePwrScheme(PUINT, LPTSTR, LPTSTR, PPOWER_POLICY); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/stacktrace.d0000664000175000017500000003103612776214756024006 0ustar kaikai/** * ... * * Copyright: Copyright Benjamin Thaut 2010 - 2013. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Benjamin Thaut, Sean Kelly * Source: $(DRUNTIMESRC core/sys/windows/_stacktrace.d) */ module core.sys.windows.stacktrace; version (Windows): import core.demangle; import core.runtime; import core.stdc.stdlib; import core.stdc.string; import core.sys.windows.dbghelp; import core.sys.windows.windows; //debug=PRINTF; debug(PRINTF) import core.stdc.stdio; extern(Windows) void RtlCaptureContext(CONTEXT* ContextRecord); extern(Windows) DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR pBuffer, DWORD nSize); extern(Windows) alias USHORT function(ULONG FramesToSkip, ULONG FramesToCapture, PVOID *BackTrace, PULONG BackTraceHash) RtlCaptureStackBackTraceFunc; private __gshared RtlCaptureStackBackTraceFunc RtlCaptureStackBackTrace; private __gshared immutable bool initialized; class StackTrace : Throwable.TraceInfo { public: /** * Constructor * Params: * skip = The number of stack frames to skip. * context = The context to receive the stack trace from. Can be null. */ this(size_t skip, CONTEXT* context) { if(context is null) { version(Win64) static enum INTERNALFRAMES = 3; else version(Win32) static enum INTERNALFRAMES = 2; skip += INTERNALFRAMES; //skip the stack frames within the StackTrace class } else { //When a exception context is given the first stack frame is repeated for some reason version(Win64) static enum INTERNALFRAMES = 1; else version(Win32) static enum INTERNALFRAMES = 1; skip += INTERNALFRAMES; } if( initialized ) m_trace = trace(skip, context); } int opApply( scope int delegate(ref const(char[])) dg ) const { return opApply( (ref size_t, ref const(char[]) buf) { return dg( buf ); }); } int opApply( scope int delegate(ref size_t, ref const(char[])) dg ) const { int result; foreach( i, e; resolve(m_trace) ) { if( (result = dg( i, e )) != 0 ) break; } return result; } override string toString() const { string result; foreach( e; this ) { result ~= e ~ "\n"; } return result; } /** * Receive a stack trace in the form of an address list. * Params: * skip = How many stack frames should be skipped. * context = The context that should be used. If null the current context is used. * Returns: * A list of addresses that can be passed to resolve at a later point in time. */ static ulong[] trace(size_t skip = 0, CONTEXT* context = null) { synchronized( typeid(StackTrace) ) { return traceNoSync(skip, context); } } /** * Resolve a stack trace. * Params: * addresses = A list of addresses to resolve. * Returns: * An array of strings with the results. */ static char[][] resolve(const(ulong)[] addresses) { synchronized( typeid(StackTrace) ) { return resolveNoSync(addresses); } } private: ulong[] m_trace; static ulong[] traceNoSync(size_t skip, CONTEXT* context) { auto dbghelp = DbgHelp.get(); if(dbghelp is null) return []; // dbghelp.dll not available if(RtlCaptureStackBackTrace !is null && context is null) { size_t[63] buffer = void; // On windows xp the sum of "frames to skip" and "frames to capture" can't be greater then 63 auto backtraceLength = RtlCaptureStackBackTrace(cast(ULONG)skip, cast(ULONG)(buffer.length - skip), cast(void**)buffer.ptr, null); // If we get a backtrace and it does not have the maximum length use it. // Otherwise rely on tracing through StackWalk64 which is slower but works when no frame pointers are available. if(backtraceLength > 1 && backtraceLength < buffer.length - skip) { debug(PRINTF) printf("Using result from RtlCaptureStackBackTrace\n"); version(Win64) { return buffer[0..backtraceLength].dup; } else version(Win32) { auto result = new ulong[backtraceLength]; foreach(i, ref e; result) { e = buffer[i]; } return result; } } } HANDLE hThread = GetCurrentThread(); HANDLE hProcess = GetCurrentProcess(); CONTEXT ctxt; if(context is null) { ctxt.ContextFlags = CONTEXT_FULL; RtlCaptureContext(&ctxt); } else { ctxt = *context; } //x86 STACKFRAME64 stackframe; with (stackframe) { version(X86) { enum Flat = ADDRESS_MODE.AddrModeFlat; AddrPC.Offset = ctxt.Eip; AddrPC.Mode = Flat; AddrFrame.Offset = ctxt.Ebp; AddrFrame.Mode = Flat; AddrStack.Offset = ctxt.Esp; AddrStack.Mode = Flat; } else version(X86_64) { enum Flat = ADDRESS_MODE.AddrModeFlat; AddrPC.Offset = ctxt.Rip; AddrPC.Mode = Flat; AddrFrame.Offset = ctxt.Rbp; AddrFrame.Mode = Flat; AddrStack.Offset = ctxt.Rsp; AddrStack.Mode = Flat; } } version (X86) enum imageType = IMAGE_FILE_MACHINE_I386; else version (X86_64) enum imageType = IMAGE_FILE_MACHINE_AMD64; else static assert(0, "unimplemented"); ulong[] result; size_t frameNum = 0; // do ... while so that we don't skip the first stackframe do { if( stackframe.AddrPC.Offset == stackframe.AddrReturn.Offset ) { debug(PRINTF) printf("Endless callstack\n"); break; } if(frameNum >= skip) { result ~= stackframe.AddrPC.Offset; } frameNum++; } while (dbghelp.StackWalk64(imageType, hProcess, hThread, &stackframe, &ctxt, null, null, null, null)); return result; } static char[][] resolveNoSync(const(ulong)[] addresses) { auto dbghelp = DbgHelp.get(); if(dbghelp is null) return []; // dbghelp.dll not available HANDLE hProcess = GetCurrentProcess(); static struct BufSymbol { align(1): IMAGEHLP_SYMBOLA64 _base; TCHAR[1024] _buf; } BufSymbol bufSymbol=void; IMAGEHLP_SYMBOLA64* symbol = &bufSymbol._base; symbol.SizeOfStruct = IMAGEHLP_SYMBOLA64.sizeof; symbol.MaxNameLength = bufSymbol._buf.length; char[][] trace; foreach(pc; addresses) { if( pc != 0 ) { char[] res; if (dbghelp.SymGetSymFromAddr64(hProcess, pc, null, symbol) && *symbol.Name.ptr) { DWORD disp; IMAGEHLP_LINEA64 line=void; line.SizeOfStruct = IMAGEHLP_LINEA64.sizeof; if (dbghelp.SymGetLineFromAddr64(hProcess, pc, &disp, &line)) res = formatStackFrame(cast(void*)pc, symbol.Name.ptr, line.FileName, line.LineNumber); else res = formatStackFrame(cast(void*)pc, symbol.Name.ptr); } else res = formatStackFrame(cast(void*)pc); trace ~= res; } } return trace; } static char[] formatStackFrame(void* pc) { import core.stdc.stdio : snprintf; char[2+2*size_t.sizeof+1] buf=void; immutable len = snprintf(buf.ptr, buf.length, "0x%p", pc); cast(uint)len < buf.length || assert(0); return buf[0 .. len].dup; } static char[] formatStackFrame(void* pc, char* symName) { char[2048] demangleBuf=void; auto res = formatStackFrame(pc); res ~= " in "; const(char)[] tempSymName = symName[0 .. strlen(symName)]; //Deal with dmd mangling of long names version(DigitalMars) version(Win32) { size_t decodeIndex = 0; tempSymName = decodeDmdString(tempSymName, decodeIndex); } res ~= demangle(tempSymName, demangleBuf); return res; } static char[] formatStackFrame(void* pc, char* symName, in char* fileName, uint lineNum) { import core.stdc.stdio : snprintf; char[11] buf=void; auto res = formatStackFrame(pc, symName); res ~= " at "; res ~= fileName[0 .. strlen(fileName)]; res ~= "("; immutable len = snprintf(buf.ptr, buf.length, "%u", lineNum); cast(uint)len < buf.length || assert(0); res ~= buf[0 .. len]; res ~= ")"; return res; } } // Workaround OPTLINK bug (Bugzilla 8263) extern(Windows) BOOL FixupDebugHeader(HANDLE hProcess, ULONG ActionCode, ulong CallbackContext, ulong UserContext) { if (ActionCode == CBA_READ_MEMORY) { auto p = cast(IMAGEHLP_CBA_READ_MEMORY*)CallbackContext; if (!(p.addr & 0xFF) && p.bytes == 0x1C && // IMAGE_DEBUG_DIRECTORY.PointerToRawData (*cast(DWORD*)(p.addr + 24) & 0xFF) == 0x20) { immutable base = DbgHelp.get().SymGetModuleBase64(hProcess, p.addr); // IMAGE_DEBUG_DIRECTORY.AddressOfRawData if (base + *cast(DWORD*)(p.addr + 20) == p.addr + 0x1C && *cast(DWORD*)(p.addr + 0x1C) == 0 && *cast(DWORD*)(p.addr + 0x20) == ('N'|'B'<<8|'0'<<16|'9'<<24)) { debug(PRINTF) printf("fixup IMAGE_DEBUG_DIRECTORY.AddressOfRawData\n"); memcpy(p.buf, cast(void*)p.addr, 0x1C); *cast(DWORD*)(p.buf + 20) = cast(DWORD)(p.addr - base) + 0x20; *p.bytesread = 0x1C; return TRUE; } } } return FALSE; } private string generateSearchPath() { __gshared string[3] defaultPathList = ["_NT_SYMBOL_PATH", "_NT_ALTERNATE_SYMBOL_PATH", "SYSTEMROOT"]; string path; char[2048] temp; DWORD len; foreach( e; defaultPathList ) { if( (len = GetEnvironmentVariableA( e.ptr, temp.ptr, temp.length )) > 0 ) { path ~= temp[0 .. len]; path ~= ";"; } } path ~= "\0"; return path; } shared static this() { auto dbghelp = DbgHelp.get(); if( dbghelp is null ) return; // dbghelp.dll not available auto kernel32Handle = LoadLibraryA( "kernel32.dll" ); if(kernel32Handle !is null) { RtlCaptureStackBackTrace = cast(RtlCaptureStackBackTraceFunc) GetProcAddress(kernel32Handle, "RtlCaptureStackBackTrace"); debug(PRINTF) { if(RtlCaptureStackBackTrace !is null) printf("Found RtlCaptureStackBackTrace\n"); } } debug(PRINTF) { API_VERSION* dbghelpVersion = dbghelp.ImagehlpApiVersion(); printf("DbgHelp Version %d.%d.%d\n", dbghelpVersion.MajorVersion, dbghelpVersion.MinorVersion, dbghelpVersion.Revision); } HANDLE hProcess = GetCurrentProcess(); DWORD symOptions = dbghelp.SymGetOptions(); symOptions |= SYMOPT_LOAD_LINES; symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; symOptions |= SYMOPT_DEFERRED_LOAD; symOptions = dbghelp.SymSetOptions( symOptions ); debug(PRINTF) printf("Search paths: %s\n", generateSearchPath().ptr); if (!dbghelp.SymInitialize(hProcess, generateSearchPath().ptr, TRUE)) return; dbghelp.SymRegisterCallback64(hProcess, &FixupDebugHeader, 0); initialized = true; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/imagehlp.d0000664000175000017500000003065212776214756023453 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_imagehlp.d) */ module core.sys.windows.imagehlp; version (Windows): version (ANSI) {} else version = Unicode; /* Comment from MinGW NOTE: This strictly does not belong in the Win32 API since it's really part of Platform SDK. However, GDB needs it and we might as well provide it here. */ private import core.sys.windows.winbase, core.sys.windows.windef; // FIXME: check types of constants enum API_VERSION_NUMBER = 7; enum BIND_NO_BOUND_IMPORTS = 1; enum BIND_NO_UPDATE = 2; enum BIND_ALL_IMAGES = 4; enum BIND_CACHE_IMPORT_DLLS = 8; enum { CBA_DEFERRED_SYMBOL_LOAD_START = 1, CBA_DEFERRED_SYMBOL_LOAD_COMPLETE, CBA_DEFERRED_SYMBOL_LOAD_FAILURE, CBA_SYMBOLS_UNLOADED, CBA_DUPLICATE_SYMBOL } enum CERT_PE_IMAGE_DIGEST_DEBUG_INFO = 1; enum CERT_PE_IMAGE_DIGEST_RESOURCES = 2; enum CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO = 4; enum CERT_PE_IMAGE_DIGEST_NON_PE_INFO = 8; enum CERT_SECTION_TYPE_ANY = 255; enum { CHECKSUM_SUCCESS = 0, CHECKSUM_OPEN_FAILURE, CHECKSUM_MAP_FAILURE, CHECKSUM_MAPVIEW_FAILURE, CHECKSUM_UNICODE_FAILURE } enum IMAGE_SEPARATION = 65536; enum SPLITSYM_REMOVE_PRIVATE = 1; enum SPLITSYM_EXTRACT_ALL = 2; enum SPLITSYM_SYMBOLPATH_IS_SRC = 4; enum SYMF_OMAP_GENERATED = 1; enum SYMF_OMAP_MODIFIED = 2; enum SYMOPT_CASE_INSENSITIVE = 1; enum SYMOPT_UNDNAME = 2; enum SYMOPT_DEFERRED_LOADS = 4; enum SYMOPT_NO_CPP = 8; //const SYMOPT_LOAD_LINES = 16; //const SYMOPT_OMAP_FIND_NEAREST = 32; public import core.sys.windows.dbghelp_types : SYMOPT_DEFERRED_LOAD, SYMOPT_FAIL_CRITICAL_ERRORS, SYMOPT_LOAD_LINES, SYMOPT_DEBUG; enum UNDNAME_COMPLETE = 0; enum UNDNAME_NO_LEADING_UNDERSCORES = 1; enum UNDNAME_NO_MS_KEYWORDS = 2; enum UNDNAME_NO_FUNCTION_RETURNS = 4; enum UNDNAME_NO_ALLOCATION_MODEL = 8; enum UNDNAME_NO_ALLOCATION_LANGUAGE = 16; enum UNDNAME_NO_MS_THISTYPE = 32; enum UNDNAME_NO_CV_THISTYPE = 64; enum UNDNAME_NO_THISTYPE = 96; enum UNDNAME_NO_ACCESS_SPECIFIERS = 128; enum UNDNAME_NO_THROW_SIGNATURES = 256; enum UNDNAME_NO_MEMBER_TYPE = 512; enum UNDNAME_NO_RETURN_UDT_MODEL = 1024; enum UNDNAME_32_BIT_DECODE = 2048; enum UNDNAME_NAME_ONLY = 4096; enum UNDNAME_NO_ARGUMENTS = 8192; enum UNDNAME_NO_SPECIAL_SYMS = 16384; enum IMAGEHLP_STATUS_REASON { BindOutOfMemory, BindRvaToVaFailed, BindNoRoomInImage, BindImportModuleFailed, BindImportProcedureFailed, BindImportModule, BindImportProcedure, BindForwarder, BindForwarderNOT, BindImageModified, BindExpandFileHeaders, BindImageComplete, BindMismatchedSymbols, BindSymbolsNotUpdated } struct LOADED_IMAGE { LPSTR ModuleName; HANDLE hFile; PUCHAR MappedAddress; PIMAGE_NT_HEADERS FileHeader; PIMAGE_SECTION_HEADER LastRvaSection; ULONG NumberOfSections; PIMAGE_SECTION_HEADER Sections; ULONG Characteristics; BOOLEAN fSystemImage; BOOLEAN fDOSImage; LIST_ENTRY Links; ULONG SizeOfImage; } alias LOADED_IMAGE* PLOADED_IMAGE; struct IMAGE_DEBUG_INFORMATION { LIST_ENTRY List; DWORD Size; PVOID MappedBase; USHORT Machine; USHORT Characteristics; DWORD CheckSum; DWORD ImageBase; DWORD SizeOfImage; DWORD NumberOfSections; PIMAGE_SECTION_HEADER Sections; DWORD ExportedNamesSize; LPSTR ExportedNames; DWORD NumberOfFunctionTableEntries; PIMAGE_FUNCTION_ENTRY FunctionTableEntries; DWORD LowestFunctionStartingAddress; DWORD HighestFunctionEndingAddress; DWORD NumberOfFpoTableEntries; PFPO_DATA FpoTableEntries; DWORD SizeOfCoffSymbols; PIMAGE_COFF_SYMBOLS_HEADER CoffSymbols; DWORD SizeOfCodeViewSymbols; PVOID CodeViewSymbols; LPSTR ImageFilePath; LPSTR ImageFileName; LPSTR DebugFilePath; DWORD TimeDateStamp; BOOL RomImage; PIMAGE_DEBUG_DIRECTORY DebugDirectory; DWORD NumberOfDebugDirectories; DWORD[3] Reserved; } alias IMAGE_DEBUG_INFORMATION* PIMAGE_DEBUG_INFORMATION; enum ADDRESS_MODE { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat } struct ADDRESS { DWORD Offset; WORD Segment; ADDRESS_MODE Mode; } alias ADDRESS* LPADDRESS; struct KDHELP { DWORD Thread; DWORD ThCallbackStack; DWORD NextCallback; DWORD FramePointer; DWORD KiCallUserMode; DWORD KeUserCallbackDispatcher; DWORD SystemRangeStart; DWORD ThCallbackBStore; DWORD KiUserExceptionDispatcher; DWORD StackBase; DWORD StackLimit; DWORD[5] Reserved; } alias KDHELP* PKDHELP; struct STACKFRAME { ADDRESS AddrPC; ADDRESS AddrReturn; ADDRESS AddrFrame; ADDRESS AddrStack; LPVOID FuncTableEntry; DWORD[4] Params; BOOL Far; BOOL Virtual; DWORD[3] Reserved; KDHELP KdHelp; ADDRESS AddrBStore; } alias STACKFRAME* LPSTACKFRAME; /* struct API_VERSION { USHORT MajorVersion; USHORT MinorVersion; USHORT Revision; USHORT Reserved; } */ public import core.sys.windows.dbghelp_types : API_VERSION; alias API_VERSION* LPAPI_VERSION; enum SYM_TYPE { SymNone, SymCoff, SymCv, SymPdb, SymExport, SymDeferred, SymSym } struct IMAGEHLP_SYMBOL { DWORD SizeOfStruct; DWORD Address; DWORD Size; DWORD Flags; DWORD MaxNameLength; CHAR[1] Name; } alias IMAGEHLP_SYMBOL* PIMAGEHLP_SYMBOL; struct IMAGEHLP_MODULE { DWORD SizeOfStruct; DWORD BaseOfImage; DWORD ImageSize; DWORD TimeDateStamp; DWORD CheckSum; DWORD NumSyms; SYM_TYPE SymType; CHAR[32] ModuleName; CHAR[256] ImageName; CHAR[256] LoadedImageName; } alias IMAGEHLP_MODULE* PIMAGEHLP_MODULE; struct IMAGEHLP_LINE { DWORD SizeOfStruct; DWORD Key; DWORD LineNumber; PCHAR FileName; DWORD Address; } alias IMAGEHLP_LINE* PIMAGEHLP_LINE; struct IMAGEHLP_DEFERRED_SYMBOL_LOAD { DWORD SizeOfStruct; DWORD BaseOfImage; DWORD CheckSum; DWORD TimeDateStamp; CHAR[MAX_PATH] FileName; BOOLEAN Reparse; } alias IMAGEHLP_DEFERRED_SYMBOL_LOAD* PIMAGEHLP_DEFERRED_SYMBOL_LOAD; struct IMAGEHLP_DUPLICATE_SYMBOL { DWORD SizeOfStruct; DWORD NumberOfDups; PIMAGEHLP_SYMBOL Symbol; ULONG SelectedSymbol; } alias IMAGEHLP_DUPLICATE_SYMBOL* PIMAGEHLP_DUPLICATE_SYMBOL; mixin DECLARE_HANDLE!("DIGEST_HANDLE"); extern (Windows) { alias BOOL function(IMAGEHLP_STATUS_REASON, LPSTR, LPSTR, ULONG, ULONG) PIMAGEHLP_STATUS_ROUTINE; alias BOOL function(HANDLE , LPCVOID, LPVOID, DWORD, LPDWORD) PREAD_PROCESS_MEMORY_ROUTINE; alias LPVOID function(HANDLE, DWORD) PFUNCTION_TABLE_ACCESS_ROUTINE; alias DWORD function(HANDLE, DWORD) PGET_MODULE_BASE_ROUTINE; alias DWORD function(HANDLE, HANDLE, LPADDRESS) PTRANSLATE_ADDRESS_ROUTINE; alias BOOL function(LPSTR, ULONG, PVOID) PSYM_ENUMMODULES_CALLBACK; alias BOOL function(LPSTR, ULONG, ULONG, PVOID) PSYM_ENUMSYMBOLS_CALLBACK; alias BOOL function(LPSTR, ULONG, ULONG, PVOID) PENUMLOADED_MODULES_CALLBACK; alias BOOL function(HANDLE, ULONG, PVOID, PVOID) PSYMBOL_REGISTERED_CALLBACK; alias BOOL function(DIGEST_HANDLE refdata, PBYTE pData, DWORD dwLength) DIGEST_FUNCTION; PIMAGE_NT_HEADERS CheckSumMappedFile(LPVOID, DWORD, LPDWORD, LPDWORD); DWORD MapFileAndCheckSumA(LPSTR, LPDWORD, LPDWORD); DWORD MapFileAndCheckSumW(PWSTR, LPDWORD, LPDWORD); BOOL TouchFileTimes(HANDLE, LPSYSTEMTIME); BOOL SplitSymbols(LPSTR, LPSTR, LPSTR, DWORD); HANDLE FindDebugInfoFile(LPSTR, LPSTR, LPSTR); HANDLE FindExecutableImage(LPSTR, LPSTR, LPSTR); BOOL UpdateDebugInfoFile(LPSTR, LPSTR, LPSTR, PIMAGE_NT_HEADERS); BOOL UpdateDebugInfoFileEx(LPSTR, LPSTR, LPSTR, PIMAGE_NT_HEADERS, DWORD); BOOL BindImage(LPSTR, LPSTR, LPSTR); BOOL BindImageEx(DWORD, LPSTR, LPSTR, LPSTR, PIMAGEHLP_STATUS_ROUTINE); BOOL ReBaseImage(LPSTR, LPSTR, BOOL, BOOL, BOOL, ULONG, ULONG*, ULONG*, ULONG*, ULONG*, ULONG); PLOADED_IMAGE ImageLoad(LPSTR, LPSTR); BOOL ImageUnload(PLOADED_IMAGE); PIMAGE_NT_HEADERS ImageNtHeader(PVOID); PVOID ImageDirectoryEntryToData(PVOID, BOOLEAN, USHORT, PULONG); PIMAGE_SECTION_HEADER ImageRvaToSection(PIMAGE_NT_HEADERS, PVOID, ULONG); PVOID ImageRvaToVa(PIMAGE_NT_HEADERS, PVOID, ULONG, PIMAGE_SECTION_HEADER*); BOOL MapAndLoad(LPSTR, LPSTR, PLOADED_IMAGE, BOOL, BOOL); BOOL GetImageConfigInformation(PLOADED_IMAGE, PIMAGE_LOAD_CONFIG_DIRECTORY); DWORD GetImageUnusedHeaderBytes(PLOADED_IMAGE, LPDWORD); BOOL SetImageConfigInformation(PLOADED_IMAGE, PIMAGE_LOAD_CONFIG_DIRECTORY); BOOL UnMapAndLoad(PLOADED_IMAGE); PIMAGE_DEBUG_INFORMATION MapDebugInformation(HANDLE, LPSTR, LPSTR, DWORD); BOOL UnmapDebugInformation(PIMAGE_DEBUG_INFORMATION); HANDLE FindExecutableImage(LPSTR, LPSTR, LPSTR); BOOL SearchTreeForFile(LPSTR, LPSTR, LPSTR); BOOL MakeSureDirectoryPathExists(LPCSTR); DWORD UnDecorateSymbolName(LPCSTR, LPSTR, DWORD, DWORD); BOOL StackWalk(DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID, PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE); LPAPI_VERSION ImagehlpApiVersion(); LPAPI_VERSION ImagehlpApiVersionEx(LPAPI_VERSION); DWORD GetTimestampForLoadedLibrary(HMODULE); BOOL RemovePrivateCvSymbolic(PCHAR, PCHAR*, ULONG*); VOID RemoveRelocations(PCHAR); DWORD SymSetOptions(DWORD); DWORD SymGetOptions(); BOOL SymCleanup(HANDLE); BOOL SymEnumerateModules(HANDLE, PSYM_ENUMMODULES_CALLBACK, PVOID); BOOL SymEnumerateSymbols(HANDLE, DWORD, PSYM_ENUMSYMBOLS_CALLBACK, PVOID); BOOL EnumerateLoadedModules(HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID); LPVOID SymFunctionTableAccess(HANDLE, DWORD); BOOL SymGetModuleInfo(HANDLE, DWORD, PIMAGEHLP_MODULE); DWORD SymGetModuleBase(HANDLE, DWORD); BOOL SymGetSymFromAddr(HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL); BOOL SymGetSymFromName(HANDLE, LPSTR, PIMAGEHLP_SYMBOL); BOOL SymGetSymNext(HANDLE, PIMAGEHLP_SYMBOL); BOOL SymGetSymPrev(HANDLE, PIMAGEHLP_SYMBOL); BOOL SymGetLineFromAddr(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE); BOOL SymGetLineFromName(HANDLE, LPSTR, LPSTR, DWORD, PLONG, PIMAGEHLP_LINE); BOOL SymGetLineNext(HANDLE, PIMAGEHLP_LINE); BOOL SymGetLinePrev(HANDLE, PIMAGEHLP_LINE); BOOL SymMatchFileName(LPSTR, LPSTR, LPSTR*, LPSTR*); BOOL SymInitialize(HANDLE, LPSTR, BOOL); BOOL SymGetSearchPath(HANDLE, LPSTR, DWORD); BOOL SymSetSearchPath(HANDLE, LPSTR); BOOL SymLoadModule(HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD); BOOL SymUnloadModule(HANDLE, DWORD); BOOL SymUnDName(PIMAGEHLP_SYMBOL, LPSTR, DWORD); BOOL SymRegisterCallback(HANDLE, PSYMBOL_REGISTERED_CALLBACK, PVOID); BOOL ImageGetDigestStream(HANDLE, DWORD, DIGEST_FUNCTION, DIGEST_HANDLE); BOOL ImageAddCertificate(HANDLE, LPWIN_CERTIFICATE, PDWORD); BOOL ImageRemoveCertificate(HANDLE, DWORD); BOOL ImageEnumerateCertificates(HANDLE, WORD, PDWORD, PDWORD, DWORD); BOOL ImageGetCertificateData(HANDLE, DWORD, LPWIN_CERTIFICATE, PDWORD); BOOL ImageGetCertificateHeader(HANDLE, DWORD, LPWIN_CERTIFICATE); BOOL CopyPdb(CHAR*, CHAR*, BOOL); BOOL RemovePrivateCvSymbolicEx(PCHAR, ULONG, PCHAR*, ULONG*); } version (Unicode) { alias MapFileAndCheckSumW MapFileAndCheckSum; } else { alias MapFileAndCheckSumA MapFileAndCheckSum; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/nspapi.d0000664000175000017500000000660012776214756023153 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_nspapi.d) */ module core.sys.windows.nspapi; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.basetyps, core.sys.windows.windef; // FIXME: check types of constants enum { NS_ALL = 0, NS_SAP, NS_NDS, NS_PEER_BROWSE, NS_TCPIP_LOCAL = 10, NS_TCPIP_HOSTS, NS_DNS, NS_NETBT, NS_WINS, NS_NBP = 20, NS_MS = 30, NS_STDA, NS_NTDS, NS_X500 = 40, NS_NIS, NS_NISPLUS, NS_WRQ = 50 } enum { SERVICE_REGISTER = 1, SERVICE_DEREGISTER = 2, SERVICE_FLUSH = 3, SERVICE_FLAG_HARD = 2 } /* MinGW makes the next section conditional on winsock.h or winsock2.h * being included. But that doesn't translate well into D. */ version (Win32_Winsock1) { import core.sys.windows.winsock; } else { import core.sys.windows.winsock2; } struct SOCKET_ADDRESS { LPSOCKADDR lpSockaddr; INT iSockaddrLength; } alias SOCKET_ADDRESS* PSOCKET_ADDRESS, LPSOCKET_ADDRESS; struct CSADDR_INFO { SOCKET_ADDRESS LocalAddr; SOCKET_ADDRESS RemoteAddr; INT iSocketType; INT iProtocol; } alias CSADDR_INFO* PCSADDR_INFO, LPCSADDR_INFO; struct BLOB { ULONG cbSize; BYTE* pBlobData; } alias BLOB* PBLOB, LPBLOB; struct SERVICE_ADDRESS { DWORD dwAddressType; DWORD dwAddressFlags; DWORD dwAddressLength; DWORD dwPrincipalLength; BYTE* lpAddress; BYTE* lpPrincipal; } struct SERVICE_ADDRESSES { DWORD dwAddressCount; SERVICE_ADDRESS _Addresses; SERVICE_ADDRESS* Addresses() return { return &_Addresses; } } alias SERVICE_ADDRESSES* PSERVICE_ADDRESSES, LPSERVICE_ADDRESSES; struct SERVICE_INFOA { LPGUID lpServiceType; LPSTR lpServiceName; LPSTR lpComment; LPSTR lpLocale; DWORD dwDisplayHint; DWORD dwVersion; DWORD dwTime; LPSTR lpMachineName; LPSERVICE_ADDRESSES lpServiceAddress; BLOB ServiceSpecificInfo; } alias SERVICE_INFOA* LPSERVICE_INFOA; struct SERVICE_INFOW { LPGUID lpServiceType; LPWSTR lpServiceName; LPWSTR lpComment; LPWSTR lpLocale; DWORD dwDisplayHint; DWORD dwVersion; DWORD dwTime; LPWSTR lpMachineName; LPSERVICE_ADDRESSES lpServiceAddress; BLOB ServiceSpecificInfo; } alias SERVICE_INFOW* LPSERVICE_INFOW; alias void* LPSERVICE_ASYNC_INFO; extern (Windows) { INT SetServiceA(DWORD, DWORD, DWORD, LPSERVICE_INFOA, LPSERVICE_ASYNC_INFO, LPDWORD); INT SetServiceW(DWORD, DWORD, DWORD, LPSERVICE_INFOW, LPSERVICE_ASYNC_INFO, LPDWORD); INT GetAddressByNameA(DWORD, LPGUID, LPSTR, LPINT, DWORD, LPSERVICE_ASYNC_INFO, LPVOID, LPDWORD, LPSTR, LPDWORD); INT GetAddressByNameW(DWORD, LPGUID, LPWSTR, LPINT, DWORD, LPSERVICE_ASYNC_INFO, LPVOID, LPDWORD, LPWSTR, LPDWORD); } version (Unicode) { alias SERVICE_INFOW SERVICE_INFO; alias SetServiceW SetService; alias GetAddressByNameW GetAddressByName; } else { alias SERVICE_INFOA SERVICE_INFO; alias SetServiceA SetService; alias GetAddressByNameA GetAddressByName; } alias SERVICE_INFO _SERVICE_INFO; alias SERVICE_INFO* LPSERVICE_INFO; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rpcnsip.d0000664000175000017500000000162112776214756023335 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rpcnsip.d) */ module core.sys.windows.rpcnsip; version (Windows): private import core.sys.windows.rpcdce, core.sys.windows.rpcdcep, core.sys.windows.rpcnsi; struct RPC_IMPORT_CONTEXT_P { RPC_NS_HANDLE LookupContext; RPC_BINDING_HANDLE ProposedHandle; RPC_BINDING_VECTOR* Bindings; } alias RPC_IMPORT_CONTEXT_P* PRPC_IMPORT_CONTEXT_P; extern(Windows) { RPC_STATUS I_RpcNsGetBuffer(PRPC_MESSAGE); RPC_STATUS I_RpcNsSendReceive(PRPC_MESSAGE, RPC_BINDING_HANDLE*); void I_RpcNsRaiseException(PRPC_MESSAGE, RPC_STATUS); RPC_STATUS I_RpcReBindBuffer(PRPC_MESSAGE); RPC_STATUS I_NsServerBindSearch(); RPC_STATUS I_NsClientBindSearch(); void I_NsClientBindDone(); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ntdll.d0000664000175000017500000000076212776214756023001 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ntdll.d) */ module core.sys.windows.ntdll; version (Windows): private import core.sys.windows.w32api; enum SHUTDOWN_ACTION { ShutdownNoReboot, ShutdownReboot, ShutdownPowerOff } extern (Windows) uint NtShutdownSystem(SHUTDOWN_ACTION Action); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/olectlid.d0000664000175000017500000000047512776214756023464 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_olectlid.d) */ module core.sys.windows.olectlid; version (Windows): private import core.sys.windows.basetyps; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/sqltypes.d0000664000175000017500000000604612776214756023551 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_sqltypes.d) */ module core.sys.windows.sqltypes; version (Windows): version (ANSI) {} else version = Unicode; /* Conversion notes: It's assumed that ODBC >= 0x0300. */ private import core.sys.windows.windef; private import core.sys.windows.basetyps; // for GUID alias byte SCHAR, SQLSCHAR; alias int SDWORD, SLONG, SQLINTEGER; alias short SWORD, SSHORT, RETCODE, SQLSMALLINT; alias ULONG UDWORD; alias USHORT UWORD, SQLUSMALLINT; alias double SDOUBLE, LDOUBLE; alias float SFLOAT; alias PVOID PTR, HENV, HDBC, HSTMT, SQLPOINTER; alias UCHAR SQLCHAR; // #ifndef _WIN64 alias UDWORD SQLUINTEGER; // #endif //static if (ODBCVER >= 0x0300) { alias TypeDef!(HANDLE) SQLHANDLE; alias SQLHANDLE SQLHENV, SQLHDBC, SQLHSTMT, SQLHDESC; /* } else { alias void* SQLHENV; alias void* SQLHDBC; alias void* SQLHSTMT; } */ alias SQLSMALLINT SQLRETURN; alias HWND SQLHWND; alias ULONG BOOKMARK; alias SQLINTEGER SQLLEN, SQLROWOFFSET; alias SQLUINTEGER SQLROWCOUNT, SQLULEN; alias DWORD SQLTRANSID; alias SQLUSMALLINT SQLSETPOSIROW; alias wchar SQLWCHAR; version(Unicode) { alias SQLWCHAR SQLTCHAR; } else { alias SQLCHAR SQLTCHAR; } //static if (ODBCVER >= 0x0300) { alias ubyte SQLDATE, SQLDECIMAL; alias double SQLDOUBLE, SQLFLOAT; alias ubyte SQLNUMERIC; alias float SQLREAL; alias ubyte SQLTIME, SQLTIMESTAMP, SQLVARCHAR; alias long ODBCINT64, SQLBIGINT; alias ulong SQLUBIGINT; //} struct DATE_STRUCT { SQLSMALLINT year; SQLUSMALLINT month; SQLUSMALLINT day; } struct TIME_STRUCT { SQLUSMALLINT hour; SQLUSMALLINT minute; SQLUSMALLINT second; } struct TIMESTAMP_STRUCT { SQLSMALLINT year; SQLUSMALLINT month; SQLUSMALLINT day; SQLUSMALLINT hour; SQLUSMALLINT minute; SQLUSMALLINT second; SQLUINTEGER fraction; } //static if (ODBCVER >= 0x0300) { alias DATE_STRUCT SQL_DATE_STRUCT; alias TIME_STRUCT SQL_TIME_STRUCT; alias TIMESTAMP_STRUCT SQL_TIMESTAMP_STRUCT; enum SQLINTERVAL { SQL_IS_YEAR = 1, SQL_IS_MONTH, SQL_IS_DAY, SQL_IS_HOUR, SQL_IS_MINUTE, SQL_IS_SECOND, SQL_IS_YEAR_TO_MONTH, SQL_IS_DAY_TO_HOUR, SQL_IS_DAY_TO_MINUTE, SQL_IS_DAY_TO_SECOND, SQL_IS_HOUR_TO_MINUTE, SQL_IS_HOUR_TO_SECOND, SQL_IS_MINUTE_TO_SECOND } struct SQL_YEAR_MONTH_STRUCT { SQLUINTEGER year; SQLUINTEGER month; } struct SQL_DAY_SECOND_STRUCT { SQLUINTEGER day; SQLUINTEGER hour; SQLUINTEGER minute; SQLUINTEGER second; SQLUINTEGER fraction; } struct SQL_INTERVAL_STRUCT { SQLINTERVAL interval_type; SQLSMALLINT interval_sign; union _intval { SQL_YEAR_MONTH_STRUCT year_month; SQL_DAY_SECOND_STRUCT day_second; } _intval intval; } enum SQL_MAX_NUMERIC_LEN = 16; struct SQL_NUMERIC_STRUCT { SQLCHAR precision; SQLSCHAR scale; SQLCHAR sign; SQLCHAR[SQL_MAX_NUMERIC_LEN] val; } // } ODBCVER >= 0x0300 alias GUID SQLGUID; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmserver.d0000664000175000017500000007624512776214756023534 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmserver.d) */ module core.sys.windows.lmserver; version (Windows): import core.sys.windows.winsvc; private import core.sys.windows.lmcons, core.sys.windows.windef; struct SERVER_INFO_100 { DWORD sv100_platform_id; LPWSTR sv100_name; } alias SERVER_INFO_100* PSERVER_INFO_100, LPSERVER_INFO_100; struct SERVER_INFO_101 { DWORD sv101_platform_id; LPWSTR sv101_name; DWORD sv101_version_major; DWORD sv101_version_minor; DWORD sv101_type; LPWSTR sv101_comment; } alias SERVER_INFO_101* PSERVER_INFO_101, LPSERVER_INFO_101; struct SERVER_INFO_102 { DWORD sv102_platform_id; LPWSTR sv102_name; DWORD sv102_version_major; DWORD sv102_version_minor; DWORD sv102_type; LPWSTR sv102_comment; DWORD sv102_users; LONG sv102_disc; BOOL sv102_hidden; DWORD sv102_announce; DWORD sv102_anndelta; DWORD sv102_licenses; LPWSTR sv102_userpath; } alias SERVER_INFO_102* PSERVER_INFO_102, LPSERVER_INFO_102; struct SERVER_INFO_402 { DWORD sv402_ulist_mtime; DWORD sv402_glist_mtime; DWORD sv402_alist_mtime; LPWSTR sv402_alerts; DWORD sv402_security; DWORD sv402_numadmin; DWORD sv402_lanmask; LPWSTR sv402_guestacct; DWORD sv402_chdevs; DWORD sv402_chdevq; DWORD sv402_chdevjobs; DWORD sv402_connections; DWORD sv402_shares; DWORD sv402_openfiles; DWORD sv402_sessopens; DWORD sv402_sessvcs; DWORD sv402_sessreqs; DWORD sv402_opensearch; DWORD sv402_activelocks; DWORD sv402_numreqbuf; DWORD sv402_sizreqbuf; DWORD sv402_numbigbuf; DWORD sv402_numfiletasks; DWORD sv402_alertsched; DWORD sv402_erroralert; DWORD sv402_logonalert; DWORD sv402_accessalert; DWORD sv402_diskalert; DWORD sv402_netioalert; DWORD sv402_maxauditsz; LPWSTR sv402_srvheuristics; } alias SERVER_INFO_402* PSERVER_INFO_402, LPSERVER_INFO_402; struct SERVER_INFO_403 { DWORD sv403_ulist_mtime; DWORD sv403_glist_mtime; DWORD sv403_alist_mtime; LPWSTR sv403_alerts; DWORD sv403_security; DWORD sv403_numadmin; DWORD sv403_lanmask; LPWSTR sv403_guestacct; DWORD sv403_chdevs; DWORD sv403_chdevq; DWORD sv403_chdevjobs; DWORD sv403_connections; DWORD sv403_shares; DWORD sv403_openfiles; DWORD sv403_sessopens; DWORD sv403_sessvcs; DWORD sv403_sessreqs; DWORD sv403_opensearch; DWORD sv403_activelocks; DWORD sv403_numreqbuf; DWORD sv403_sizreqbuf; DWORD sv403_numbigbuf; DWORD sv403_numfiletasks; DWORD sv403_alertsched; DWORD sv403_erroralert; DWORD sv403_logonalert; DWORD sv403_accessalert; DWORD sv403_diskalert; DWORD sv403_netioalert; DWORD sv403_maxauditsz; LPWSTR sv403_srvheuristics; DWORD sv403_auditedevents; DWORD sv403_autoprofile; LPWSTR sv403_autopath; } alias SERVER_INFO_403* PSERVER_INFO_403, LPSERVER_INFO_403; struct SERVER_INFO_502 { DWORD sv502_sessopens; DWORD sv502_sessvcs; DWORD sv502_opensearch; DWORD sv502_sizreqbuf; DWORD sv502_initworkitems; DWORD sv502_maxworkitems; DWORD sv502_rawworkitems; DWORD sv502_irpstacksize; DWORD sv502_maxrawbuflen; DWORD sv502_sessusers; DWORD sv502_sessconns; DWORD sv502_maxpagedmemoryusage; DWORD sv502_maxnonpagedmemoryusage; BOOL sv502_enablesoftcompat; BOOL sv502_enableforcedlogoff; BOOL sv502_timesource; BOOL sv502_acceptdownlevelapis; BOOL sv502_lmannounce; } alias SERVER_INFO_502* PSERVER_INFO_502, LPSERVER_INFO_502; struct SERVER_INFO_503 { DWORD sv503_sessopens; DWORD sv503_sessvcs; DWORD sv503_opensearch; DWORD sv503_sizreqbuf; DWORD sv503_initworkitems; DWORD sv503_maxworkitems; DWORD sv503_rawworkitems; DWORD sv503_irpstacksize; DWORD sv503_maxrawbuflen; DWORD sv503_sessusers; DWORD sv503_sessconns; DWORD sv503_maxpagedmemoryusage; DWORD sv503_maxnonpagedmemoryusage; BOOL sv503_enablesoftcompat; BOOL sv503_enableforcedlogoff; BOOL sv503_timesource; BOOL sv503_acceptdownlevelapis; BOOL sv503_lmannounce; LPWSTR sv503_domain; DWORD sv503_maxcopyreadlen; DWORD sv503_maxcopywritelen; DWORD sv503_minkeepsearch; DWORD sv503_maxkeepsearch; DWORD sv503_minkeepcomplsearch; DWORD sv503_maxkeepcomplsearch; DWORD sv503_threadcountadd; DWORD sv503_numblockthreads; DWORD sv503_scavtimeout; DWORD sv503_minrcvqueue; DWORD sv503_minfreeworkitems; DWORD sv503_xactmemsize; DWORD sv503_threadpriority; DWORD sv503_maxmpxct; DWORD sv503_oplockbreakwait; DWORD sv503_oplockbreakresponsewait; BOOL sv503_enableoplocks; BOOL sv503_enableoplockforceclose; BOOL sv503_enablefcbopens; BOOL sv503_enableraw; BOOL sv503_enablesharednetdrives; DWORD sv503_minfreeconnections; DWORD sv503_maxfreeconnections; } alias SERVER_INFO_503* PSERVER_INFO_503, LPSERVER_INFO_503; struct SERVER_INFO_599 { DWORD sv599_sessopens; DWORD sv599_sessvcs; DWORD sv599_opensearch; DWORD sv599_sizreqbuf; DWORD sv599_initworkitems; DWORD sv599_maxworkitems; DWORD sv599_rawworkitems; DWORD sv599_irpstacksize; DWORD sv599_maxrawbuflen; DWORD sv599_sessusers; DWORD sv599_sessconns; DWORD sv599_maxpagedmemoryusage; DWORD sv599_maxnonpagedmemoryusage; BOOL sv599_enablesoftcompat; BOOL sv599_enableforcedlogoff; BOOL sv599_timesource; BOOL sv599_acceptdownlevelapis; BOOL sv599_lmannounce; LPWSTR sv599_domain; DWORD sv599_maxcopyreadlen; DWORD sv599_maxcopywritelen; DWORD sv599_minkeepsearch; DWORD sv599_maxkeepsearch; DWORD sv599_minkeepcomplsearch; DWORD sv599_maxkeepcomplsearch; DWORD sv599_threadcountadd; DWORD sv599_numblockthreads; DWORD sv599_scavtimeout; DWORD sv599_minrcvqueue; DWORD sv599_minfreeworkitems; DWORD sv599_xactmemsize; DWORD sv599_threadpriority; DWORD sv599_maxmpxct; DWORD sv599_oplockbreakwait; DWORD sv599_oplockbreakresponsewait; BOOL sv599_enableoplocks; BOOL sv599_enableoplockforceclose; BOOL sv599_enablefcbopens; BOOL sv599_enableraw; BOOL sv599_enablesharednetdrives; DWORD sv599_minfreeconnections; DWORD sv599_maxfreeconnections; DWORD sv599_initsesstable; DWORD sv599_initconntable; DWORD sv599_initfiletable; DWORD sv599_initsearchtable; DWORD sv599_alertschedule; DWORD sv599_errorthreshold; DWORD sv599_networkerrorthreshold; DWORD sv599_diskspacethreshold; DWORD sv599_reserved; DWORD sv599_maxlinkdelay; DWORD sv599_minlinkthroughput; DWORD sv599_linkinfovalidtime; DWORD sv599_scavqosinfoupdatetime; DWORD sv599_maxworkitemidletime; } alias SERVER_INFO_599* PSERVER_INFO_599, LPSERVER_INFO_599; struct SERVER_INFO_598 { DWORD sv598_maxrawworkitems; DWORD sv598_maxthreadsperqueue; DWORD sv598_producttype; DWORD sv598_serversize; DWORD sv598_connectionlessautodisc; DWORD sv598_sharingviolationretries; DWORD sv598_sharingviolationdelay; DWORD sv598_maxglobalopensearch; DWORD sv598_removeduplicatesearches; DWORD sv598_lockviolationoffset; DWORD sv598_lockviolationdelay; DWORD sv598_mdlreadswitchover; DWORD sv598_cachedopenlimit; DWORD sv598_otherqueueaffinity; BOOL sv598_restrictnullsessaccess; BOOL sv598_enablewfw311directipx; DWORD sv598_queuesamplesecs; DWORD sv598_balancecount; DWORD sv598_preferredaffinity; DWORD sv598_maxfreerfcbs; DWORD sv598_maxfreemfcbs; DWORD sv598_maxfreelfcbs; DWORD sv598_maxfreepagedpoolchunks; DWORD sv598_minpagedpoolchunksize; DWORD sv598_maxpagedpoolchunksize; BOOL sv598_sendsfrompreferredprocessor; } alias SERVER_INFO_598* PSERVER_INFO_598, LPSERVER_INFO_598; struct SERVER_INFO_1005 { LPWSTR sv1005_comment; } alias SERVER_INFO_1005* PSERVER_INFO_1005, LPSERVER_INFO_1005; struct SERVER_INFO_1107 { DWORD sv1107_users; } alias SERVER_INFO_1107* PSERVER_INFO_1107, LPSERVER_INFO_1107; struct SERVER_INFO_1010 { LONG sv1010_disc; } alias SERVER_INFO_1010* PSERVER_INFO_1010, LPSERVER_INFO_1010; struct SERVER_INFO_1016 { BOOL sv1016_hidden; } alias SERVER_INFO_1016* PSERVER_INFO_1016, LPSERVER_INFO_1016; struct SERVER_INFO_1017 { DWORD sv1017_announce; } alias SERVER_INFO_1017* PSERVER_INFO_1017, LPSERVER_INFO_1017; struct SERVER_INFO_1018 { DWORD sv1018_anndelta; } alias SERVER_INFO_1018* PSERVER_INFO_1018, LPSERVER_INFO_1018; struct SERVER_INFO_1501 { DWORD sv1501_sessopens; } alias SERVER_INFO_1501* PSERVER_INFO_1501, LPSERVER_INFO_1501; struct SERVER_INFO_1502 { DWORD sv1502_sessvcs; } alias SERVER_INFO_1502* PSERVER_INFO_1502, LPSERVER_INFO_1502; struct SERVER_INFO_1503 { DWORD sv1503_opensearch; } alias SERVER_INFO_1503* PSERVER_INFO_1503, LPSERVER_INFO_1503; struct SERVER_INFO_1506 { DWORD sv1506_maxworkitems; } alias SERVER_INFO_1506* PSERVER_INFO_1506, LPSERVER_INFO_1506; struct SERVER_INFO_1509 { DWORD sv1509_maxrawbuflen; } alias SERVER_INFO_1509* PSERVER_INFO_1509, LPSERVER_INFO_1509; struct SERVER_INFO_1510 { DWORD sv1510_sessusers; } alias SERVER_INFO_1510* PSERVER_INFO_1510, LPSERVER_INFO_1510; struct SERVER_INFO_1511 { DWORD sv1511_sessconns; } alias SERVER_INFO_1511* PSERVER_INFO_1511, LPSERVER_INFO_1511; struct SERVER_INFO_1512 { DWORD sv1512_maxnonpagedmemoryusage; } alias SERVER_INFO_1512* PSERVER_INFO_1512, LPSERVER_INFO_1512; struct SERVER_INFO_1513 { DWORD sv1513_maxpagedmemoryusage; } alias SERVER_INFO_1513* PSERVER_INFO_1513, LPSERVER_INFO_1513; struct SERVER_INFO_1514 { BOOL sv1514_enablesoftcompat; } alias SERVER_INFO_1514* PSERVER_INFO_1514, LPSERVER_INFO_1514; struct SERVER_INFO_1515 { BOOL sv1515_enableforcedlogoff; } alias SERVER_INFO_1515* PSERVER_INFO_1515, LPSERVER_INFO_1515; struct SERVER_INFO_1516 { BOOL sv1516_timesource; } alias SERVER_INFO_1516* PSERVER_INFO_1516, LPSERVER_INFO_1516; struct SERVER_INFO_1518 { BOOL sv1518_lmannounce; } alias SERVER_INFO_1518* PSERVER_INFO_1518, LPSERVER_INFO_1518; struct SERVER_INFO_1520 { DWORD sv1520_maxcopyreadlen; } alias SERVER_INFO_1520* PSERVER_INFO_1520, LPSERVER_INFO_1520; struct SERVER_INFO_1521 { DWORD sv1521_maxcopywritelen; } alias SERVER_INFO_1521* PSERVER_INFO_1521, LPSERVER_INFO_1521; struct SERVER_INFO_1522 { DWORD sv1522_minkeepsearch; } alias SERVER_INFO_1522* PSERVER_INFO_1522, LPSERVER_INFO_1522; struct SERVER_INFO_1523 { DWORD sv1523_maxkeepsearch; } alias SERVER_INFO_1523* PSERVER_INFO_1523, LPSERVER_INFO_1523; struct SERVER_INFO_1524 { DWORD sv1524_minkeepcomplsearch; } alias SERVER_INFO_1524* PSERVER_INFO_1524, LPSERVER_INFO_1524; struct SERVER_INFO_1525 { DWORD sv1525_maxkeepcomplsearch; } alias SERVER_INFO_1525* PSERVER_INFO_1525, LPSERVER_INFO_1525; struct SERVER_INFO_1528 { DWORD sv1528_scavtimeout; } alias SERVER_INFO_1528* PSERVER_INFO_1528, LPSERVER_INFO_1528; struct SERVER_INFO_1529 { DWORD sv1529_minrcvqueue; } alias SERVER_INFO_1529* PSERVER_INFO_1529, LPSERVER_INFO_1529; struct SERVER_INFO_1530 { DWORD sv1530_minfreeworkitems; } alias SERVER_INFO_1530* PSERVER_INFO_1530, LPSERVER_INFO_1530; struct SERVER_INFO_1533 { DWORD sv1533_maxmpxct; } alias SERVER_INFO_1533* PSERVER_INFO_1533, LPSERVER_INFO_1533; struct SERVER_INFO_1534 { DWORD sv1534_oplockbreakwait; } alias SERVER_INFO_1534* PSERVER_INFO_1534, LPSERVER_INFO_1534; struct SERVER_INFO_1535 { DWORD sv1535_oplockbreakresponsewait; } alias SERVER_INFO_1535* PSERVER_INFO_1535, LPSERVER_INFO_1535; struct SERVER_INFO_1536 { BOOL sv1536_enableoplocks; } alias SERVER_INFO_1536* PSERVER_INFO_1536, LPSERVER_INFO_1536; struct SERVER_INFO_1537 { BOOL sv1537_enableoplockforceclose; } alias SERVER_INFO_1537* PSERVER_INFO_1537, LPSERVER_INFO_1537; struct SERVER_INFO_1538 { BOOL sv1538_enablefcbopens; } alias SERVER_INFO_1538* PSERVER_INFO_1538, LPSERVER_INFO_1538; struct SERVER_INFO_1539 { BOOL sv1539_enableraw; } alias SERVER_INFO_1539* PSERVER_INFO_1539, LPSERVER_INFO_1539; struct SERVER_INFO_1540 { BOOL sv1540_enablesharednetdrives; } alias SERVER_INFO_1540* PSERVER_INFO_1540, LPSERVER_INFO_1540; struct SERVER_INFO_1541 { BOOL sv1541_minfreeconnections; } alias SERVER_INFO_1541* PSERVER_INFO_1541, LPSERVER_INFO_1541; struct SERVER_INFO_1542 { BOOL sv1542_maxfreeconnections; } alias SERVER_INFO_1542* PSERVER_INFO_1542, LPSERVER_INFO_1542; struct SERVER_INFO_1543 { DWORD sv1543_initsesstable; } alias SERVER_INFO_1543* PSERVER_INFO_1543, LPSERVER_INFO_1543; struct SERVER_INFO_1544 { DWORD sv1544_initconntable; } alias SERVER_INFO_1544* PSERVER_INFO_1544, LPSERVER_INFO_1544; struct SERVER_INFO_1545 { DWORD sv1545_initfiletable; } alias SERVER_INFO_1545* PSERVER_INFO_1545, LPSERVER_INFO_1545; struct SERVER_INFO_1546 { DWORD sv1546_initsearchtable; } alias SERVER_INFO_1546* PSERVER_INFO_1546, LPSERVER_INFO_1546; struct SERVER_INFO_1547 { DWORD sv1547_alertschedule; } alias SERVER_INFO_1547* PSERVER_INFO_1547, LPSERVER_INFO_1547; struct SERVER_INFO_1548 { DWORD sv1548_errorthreshold; } alias SERVER_INFO_1548* PSERVER_INFO_1548, LPSERVER_INFO_1548; struct SERVER_INFO_1549 { DWORD sv1549_networkerrorthreshold; } alias SERVER_INFO_1549* PSERVER_INFO_1549, LPSERVER_INFO_1549; struct SERVER_INFO_1550 { DWORD sv1550_diskspacethreshold; } alias SERVER_INFO_1550* PSERVER_INFO_1550, LPSERVER_INFO_1550; struct SERVER_INFO_1552 { DWORD sv1552_maxlinkdelay; } alias SERVER_INFO_1552* PSERVER_INFO_1552, LPSERVER_INFO_1552; struct SERVER_INFO_1553 { DWORD sv1553_minlinkthroughput; } alias SERVER_INFO_1553* PSERVER_INFO_1553, LPSERVER_INFO_1553; struct SERVER_INFO_1554 { DWORD sv1554_linkinfovalidtime; } alias SERVER_INFO_1554* PSERVER_INFO_1554, LPSERVER_INFO_1554; struct SERVER_INFO_1555 { DWORD sv1555_scavqosinfoupdatetime; } alias SERVER_INFO_1555* PSERVER_INFO_1555, LPSERVER_INFO_1555; struct SERVER_INFO_1556 { DWORD sv1556_maxworkitemidletime; } alias SERVER_INFO_1556* PSERVER_INFO_1556, LPSERVER_INFO_1556; struct SERVER_INFO_1557 { DWORD sv1557_maxrawworkitems; } alias SERVER_INFO_1557* PSERVER_INFO_1557, LPSERVER_INFO_1557; struct SERVER_INFO_1560 { DWORD sv1560_producttype; } alias SERVER_INFO_1560* PSERVER_INFO_1560, LPSERVER_INFO_1560; struct SERVER_INFO_1561 { DWORD sv1561_serversize; } alias SERVER_INFO_1561* PSERVER_INFO_1561, LPSERVER_INFO_1561; struct SERVER_INFO_1562 { DWORD sv1562_connectionlessautodisc; } alias SERVER_INFO_1562* PSERVER_INFO_1562, LPSERVER_INFO_1562; struct SERVER_INFO_1563 { DWORD sv1563_sharingviolationretries; } alias SERVER_INFO_1563* PSERVER_INFO_1563, LPSERVER_INFO_1563; struct SERVER_INFO_1564 { DWORD sv1564_sharingviolationdelay; } alias SERVER_INFO_1564* PSERVER_INFO_1564, LPSERVER_INFO_1564; struct SERVER_INFO_1565 { DWORD sv1565_maxglobalopensearch; } alias SERVER_INFO_1565* PSERVER_INFO_1565, LPSERVER_INFO_1565; struct SERVER_INFO_1566 { BOOL sv1566_removeduplicatesearches; } alias SERVER_INFO_1566* PSERVER_INFO_1566, LPSERVER_INFO_1566; struct SERVER_INFO_1567 { DWORD sv1567_lockviolationretries; } alias SERVER_INFO_1567* PSERVER_INFO_1567, LPSERVER_INFO_1567; struct SERVER_INFO_1568 { DWORD sv1568_lockviolationoffset; } alias SERVER_INFO_1568* PSERVER_INFO_1568, LPSERVER_INFO_1568; struct SERVER_INFO_1569 { DWORD sv1569_lockviolationdelay; } alias SERVER_INFO_1569* PSERVER_INFO_1569, LPSERVER_INFO_1569; struct SERVER_INFO_1570 { DWORD sv1570_mdlreadswitchover; } alias SERVER_INFO_1570* PSERVER_INFO_1570, LPSERVER_INFO_1570; struct SERVER_INFO_1571 { DWORD sv1571_cachedopenlimit; } alias SERVER_INFO_1571* PSERVER_INFO_1571, LPSERVER_INFO_1571; struct SERVER_INFO_1572 { DWORD sv1572_criticalthreads; } alias SERVER_INFO_1572* PSERVER_INFO_1572, LPSERVER_INFO_1572; struct SERVER_INFO_1573 { DWORD sv1573_restrictnullsessaccess; } alias SERVER_INFO_1573* PSERVER_INFO_1573, LPSERVER_INFO_1573; struct SERVER_INFO_1574 { DWORD sv1574_enablewfw311directipx; } alias SERVER_INFO_1574* PSERVER_INFO_1574, LPSERVER_INFO_1574; struct SERVER_INFO_1575 { DWORD sv1575_otherqueueaffinity; } alias SERVER_INFO_1575* PSERVER_INFO_1575, LPSERVER_INFO_1575; struct SERVER_INFO_1576 { DWORD sv1576_queuesamplesecs; } alias SERVER_INFO_1576* PSERVER_INFO_1576, LPSERVER_INFO_1576; struct SERVER_INFO_1577 { DWORD sv1577_balancecount; } alias SERVER_INFO_1577* PSERVER_INFO_1577, LPSERVER_INFO_1577; struct SERVER_INFO_1578 { DWORD sv1578_preferredaffinity; } alias SERVER_INFO_1578* PSERVER_INFO_1578, LPSERVER_INFO_1578; struct SERVER_INFO_1579 { DWORD sv1579_maxfreerfcbs; } alias SERVER_INFO_1579* PSERVER_INFO_1579, LPSERVER_INFO_1579; struct SERVER_INFO_1580 { DWORD sv1580_maxfreemfcbs; } alias SERVER_INFO_1580* PSERVER_INFO_1580, LPSERVER_INFO_1580; struct SERVER_INFO_1581 { DWORD sv1581_maxfreemlcbs; } alias SERVER_INFO_1581* PSERVER_INFO_1581, LPSERVER_INFO_1581; struct SERVER_INFO_1582 { DWORD sv1582_maxfreepagedpoolchunks; } alias SERVER_INFO_1582* PSERVER_INFO_1582, LPSERVER_INFO_1582; struct SERVER_INFO_1583 { DWORD sv1583_minpagedpoolchunksize; } alias SERVER_INFO_1583* PSERVER_INFO_1583, LPSERVER_INFO_1583; struct SERVER_INFO_1584 { DWORD sv1584_maxpagedpoolchunksize; } alias SERVER_INFO_1584* PSERVER_INFO_1584, LPSERVER_INFO_1584; struct SERVER_INFO_1585 { BOOL sv1585_sendsfrompreferredprocessor; } alias SERVER_INFO_1585* PSERVER_INFO_1585, LPSERVER_INFO_1585; struct SERVER_INFO_1586 { BOOL sv1586_maxthreadsperqueue; } alias SERVER_INFO_1586* PSERVER_INFO_1586, LPSERVER_INFO_1586; struct SERVER_TRANSPORT_INFO_0 { DWORD svti0_numberofvcs; LPWSTR svti0_transportname; PBYTE svti0_transportaddress; DWORD svti0_transportaddresslength; LPWSTR svti0_networkaddress; } alias SERVER_TRANSPORT_INFO_0* PSERVER_TRANSPORT_INFO_0, LPSERVER_TRANSPORT_INFO_0; extern (Windows): NET_API_STATUS NetServerEnum(LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,DWORD,LPCWSTR,PDWORD); NET_API_STATUS NetServerEnumEx(LPCWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,DWORD,LPCWSTR,LPCWSTR); NET_API_STATUS NetServerGetInfo(LPWSTR,DWORD,PBYTE*); NET_API_STATUS NetServerSetInfo(LPWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetServerSetInfoCommandLine(WORD,LPWSTR*); NET_API_STATUS NetServerDiskEnum(LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetServerComputerNameAdd(LPWSTR,LPWSTR,LPWSTR); NET_API_STATUS NetServerComputerNameDel(LPWSTR,LPWSTR); NET_API_STATUS NetServerTransportAdd(LPWSTR,DWORD,PBYTE); NET_API_STATUS NetServerTransportAddEx(LPWSTR,DWORD,PBYTE); NET_API_STATUS NetServerTransportDel(LPWSTR,DWORD,PBYTE); NET_API_STATUS NetServerTransportEnum(LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); BOOL SetServiceBits(SERVICE_STATUS_HANDLE,DWORD,BOOL,BOOL); enum SVI1_NUM_ELEMENTS=5; enum SVI2_NUM_ELEMENTS=40; enum SVI3_NUM_ELEMENTS=44; enum SV_MAX_CMD_LEN=PATHLEN; enum SW_AUTOPROF_LOAD_MASK=1; enum SW_AUTOPROF_SAVE_MASK=2; enum SV_MAX_SRV_HEUR_LEN=32; enum SV_USERS_PER_LICENSE=5; enum SV_PLATFORM_ID_OS2=400; enum SV_PLATFORM_ID_NT=500; enum MAJOR_VERSION_MASK=15; enum SV_TYPE_WORKSTATION=1; enum SV_TYPE_SERVER=2; enum SV_TYPE_SQLSERVER=4; enum SV_TYPE_DOMAIN_CTRL=8; enum SV_TYPE_DOMAIN_BAKCTRL=16; enum SV_TYPE_TIME_SOURCE=32; enum SV_TYPE_AFP=64; enum SV_TYPE_NOVELL=128; enum SV_TYPE_DOMAIN_MEMBER=256; enum SV_TYPE_PRINTQ_SERVER=512; enum SV_TYPE_DIALIN_SERVER=1024; enum SV_TYPE_XENIX_SERVER=2048; enum SV_TYPE_SERVER_UNIX=SV_TYPE_XENIX_SERVER; enum SV_TYPE_NT=4096; enum SV_TYPE_WFW=8192; enum SV_TYPE_SERVER_MFPN=16384; enum SV_TYPE_SERVER_NT=32768; enum SV_TYPE_POTENTIAL_BROWSER=65536; enum SV_TYPE_BACKUP_BROWSER=0x20000; enum SV_TYPE_MASTER_BROWSER=0x40000; enum SV_TYPE_DOMAIN_MASTER=0x80000; enum SV_TYPE_SERVER_OSF=0x100000; enum SV_TYPE_SERVER_VMS=0x200000; enum SV_TYPE_WINDOWS=0x400000; enum SV_TYPE_ALTERNATE_XPORT=0x20000000; enum SV_TYPE_LOCAL_LIST_ONLY=0x40000000; enum SV_TYPE_DOMAIN_ENUM=0x80000000; enum SV_TYPE_ALL=0xFFFFFFFF; enum SV_NODISC=(-1); enum SV_USERSECURITY=1; enum SV_SHARESECURITY=0; enum SV_HIDDEN=1; enum SV_VISIBLE=0; enum SV_PLATFORM_ID_PARMNUM=101; enum SV_NAME_PARMNUM=102; enum SV_VERSION_MAJOR_PARMNUM=103; enum SV_VERSION_MINOR_PARMNUM=104; enum SV_TYPE_PARMNUM=105; enum SV_COMMENT_PARMNUM=5; enum SV_USERS_PARMNUM=107; enum SV_DISC_PARMNUM=10; enum SV_HIDDEN_PARMNUM=16; enum SV_ANNOUNCE_PARMNUM=17; enum SV_ANNDELTA_PARMNUM=18; enum SV_USERPATH_PARMNUM=112; enum SV_ULIST_MTIME_PARMNUM=401; enum SV_GLIST_MTIME_PARMNUM=402; enum SV_ALIST_MTIME_PARMNUM=403; enum SV_ALERTS_PARMNUM=11; enum SV_SECURITY_PARMNUM=405; enum SV_NUMADMIN_PARMNUM=406; enum SV_LANMASK_PARMNUM=407; enum SV_GUESTACC_PARMNUM=408; enum SV_CHDEVQ_PARMNUM=410; enum SV_CHDEVJOBS_PARMNUM=411; enum SV_CONNECTIONS_PARMNUM=412; enum SV_SHARES_PARMNUM=413; enum SV_OPENFILES_PARMNUM=414; enum SV_SESSREQS_PARMNUM=417; enum SV_ACTIVELOCKS_PARMNUM=419; enum SV_NUMREQBUF_PARMNUM=420; enum SV_NUMBIGBUF_PARMNUM=422; enum SV_NUMFILETASKS_PARMNUM=423; enum SV_ALERTSCHED_PARMNUM=37; enum SV_ERRORALERT_PARMNUM=38; enum SV_LOGONALERT_PARMNUM=39; enum SV_ACCESSALERT_PARMNUM=40; enum SV_DISKALERT_PARMNUM=41; enum SV_NETIOALERT_PARMNUM=42; enum SV_MAXAUDITSZ_PARMNUM=43; enum SV_SRVHEURISTICS_PARMNUM=431; enum SV_SESSOPENS_PARMNUM=501; enum SV_SESSVCS_PARMNUM=502; enum SV_OPENSEARCH_PARMNUM=503; enum SV_SIZREQBUF_PARMNUM=504; enum SV_INITWORKITEMS_PARMNUM=505; enum SV_MAXWORKITEMS_PARMNUM=506; enum SV_RAWWORKITEMS_PARMNUM=507; enum SV_IRPSTACKSIZE_PARMNUM=508; enum SV_MAXRAWBUFLEN_PARMNUM=509; enum SV_SESSUSERS_PARMNUM=510; enum SV_SESSCONNS_PARMNUM=511; enum SV_MAXNONPAGEDMEMORYUSAGE_PARMNUM=512; enum SV_MAXPAGEDMEMORYUSAGE_PARMNUM=513; enum SV_ENABLESOFTCOMPAT_PARMNUM=514; enum SV_ENABLEFORCEDLOGOFF_PARMNUM=515; enum SV_TIMESOURCE_PARMNUM=516; enum SV_ACCEPTDOWNLEVELAPIS_PARMNUM=517; enum SV_LMANNOUNCE_PARMNUM=518; enum SV_DOMAIN_PARMNUM=519; enum SV_MAXCOPYREADLEN_PARMNUM=520; enum SV_MAXCOPYWRITELEN_PARMNUM=521; enum SV_MINKEEPSEARCH_PARMNUM=522; enum SV_MAXKEEPSEARCH_PARMNUM=523; enum SV_MINKEEPCOMPLSEARCH_PARMNUM=524; enum SV_MAXKEEPCOMPLSEARCH_PARMNUM=525; enum SV_THREADCOUNTADD_PARMNUM=526; enum SV_NUMBLOCKTHREADS_PARMNUM=527; enum SV_SCAVTIMEOUT_PARMNUM=528; enum SV_MINRCVQUEUE_PARMNUM=529; enum SV_MINFREEWORKITEMS_PARMNUM=530; enum SV_XACTMEMSIZE_PARMNUM=531; enum SV_THREADPRIORITY_PARMNUM=532; enum SV_MAXMPXCT_PARMNUM=533; enum SV_OPLOCKBREAKWAIT_PARMNUM=534; enum SV_OPLOCKBREAKRESPONSEWAIT_PARMNUM=535; enum SV_ENABLEOPLOCKS_PARMNUM=536; enum SV_ENABLEOPLOCKFORCECLOSE_PARMNUM=537; enum SV_ENABLEFCBOPENS_PARMNUM=538; enum SV_ENABLERAW_PARMNUM=539; enum SV_ENABLESHAREDNETDRIVES_PARMNUM=540; enum SV_MINFREECONNECTIONS_PARMNUM=541; enum SV_MAXFREECONNECTIONS_PARMNUM=542; enum SV_INITSESSTABLE_PARMNUM=543; enum SV_INITCONNTABLE_PARMNUM=544; enum SV_INITFILETABLE_PARMNUM=545; enum SV_INITSEARCHTABLE_PARMNUM=546; enum SV_ALERTSCHEDULE_PARMNUM=547; enum SV_ERRORTHRESHOLD_PARMNUM=548; enum SV_NETWORKERRORTHRESHOLD_PARMNUM=549; enum SV_DISKSPACETHRESHOLD_PARMNUM=550; enum SV_MAXLINKDELAY_PARMNUM=552; enum SV_MINLINKTHROUGHPUT_PARMNUM=553; enum SV_LINKINFOVALIDTIME_PARMNUM=554; enum SV_SCAVQOSINFOUPDATETIME_PARMNUM=555; enum SV_MAXWORKITEMIDLETIME_PARMNUM=556; enum SV_MAXRAWWORKITEMS_PARMNUM=557; enum SV_PRODUCTTYPE_PARMNUM=560; enum SV_SERVERSIZE_PARMNUM=561; enum SV_CONNECTIONLESSAUTODISC_PARMNUM=562; enum SV_SHARINGVIOLATIONRETRIES_PARMNUM=563; enum SV_SHARINGVIOLATIONDELAY_PARMNUM=564; enum SV_MAXGLOBALOPENSEARCH_PARMNUM=565; enum SV_REMOVEDUPLICATESEARCHES_PARMNUM=566; enum SV_LOCKVIOLATIONRETRIES_PARMNUM=567; enum SV_LOCKVIOLATIONOFFSET_PARMNUM=568; enum SV_LOCKVIOLATIONDELAY_PARMNUM=569; enum SV_MDLREADSWITCHOVER_PARMNUM=570; enum SV_CACHEDOPENLIMIT_PARMNUM=571; enum SV_CRITICALTHREADS_PARMNUM=572; enum SV_RESTRICTNULLSESSACCESS_PARMNUM=573; enum SV_ENABLEWFW311DIRECTIPX_PARMNUM=574; enum SV_OTHERQUEUEAFFINITY_PARMNUM=575; enum SV_QUEUESAMPLESECS_PARMNUM=576; enum SV_BALANCECOUNT_PARMNUM=577; enum SV_PREFERREDAFFINITY_PARMNUM=578; enum SV_MAXFREERFCBS_PARMNUM=579; enum SV_MAXFREEMFCBS_PARMNUM=580; enum SV_MAXFREELFCBS_PARMNUM=581; enum SV_MAXFREEPAGEDPOOLCHUNKS_PARMNUM=582; enum SV_MINPAGEDPOOLCHUNKSIZE_PARMNUM=583; enum SV_MAXPAGEDPOOLCHUNKSIZE_PARMNUM=584; enum SV_SENDSFROMPREFERREDPROCESSOR_PARMNUM=585; enum SV_MAXTHREADSPERQUEUE_PARMNUM=586; enum SV_COMMENT_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_COMMENT_PARMNUM); enum SV_USERS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_USERS_PARMNUM); enum SV_DISC_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_DISC_PARMNUM); enum SV_HIDDEN_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_HIDDEN_PARMNUM); enum SV_ANNOUNCE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ANNOUNCE_PARMNUM); enum SV_ANNDELTA_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ANNDELTA_PARMNUM); enum SV_SESSOPENS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SESSOPENS_PARMNUM); enum SV_SESSVCS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SESSVCS_PARMNUM); enum SV_OPENSEARCH_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_OPENSEARCH_PARMNUM); enum SV_MAXWORKITEMS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXWORKITEMS_PARMNUM); enum SV_MAXRAWBUFLEN_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXRAWBUFLEN_PARMNUM); enum SV_SESSUSERS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SESSUSERS_PARMNUM); enum SV_SESSCONNS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SESSCONNS_PARMNUM); enum SV_MAXNONPAGEDMEMORYUSAGE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXNONPAGEDMEMORYUSAGE_PARMNUM); enum SV_MAXPAGEDMEMORYUSAGE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXPAGEDMEMORYUSAGE_PARMNUM); enum SV_ENABLESOFTCOMPAT_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ENABLESOFTCOMPAT_PARMNUM); enum SV_ENABLEFORCEDLOGOFF_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ENABLEFORCEDLOGOFF_PARMNUM); enum SV_TIMESOURCE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_TIMESOURCE_PARMNUM); enum SV_LMANNOUNCE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_LMANNOUNCE_PARMNUM); enum SV_MAXCOPYREADLEN_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXCOPYREADLEN_PARMNUM); enum SV_MAXCOPYWRITELEN_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXCOPYWRITELEN_PARMNUM); enum SV_MINKEEPSEARCH_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MINKEEPSEARCH_PARMNUM); enum SV_MAXKEEPSEARCH_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXKEEPSEARCH_PARMNUM); enum SV_MINKEEPCOMPLSEARCH_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MINKEEPCOMPLSEARCH_PARMNUM); enum SV_MAXKEEPCOMPLSEARCH_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXKEEPCOMPLSEARCH_PARMNUM); enum SV_SCAVTIMEOUT_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SCAVTIMEOUT_PARMNUM); enum SV_MINRCVQUEUE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MINRCVQUEUE_PARMNUM); enum SV_MINFREEWORKITEMS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MINFREEWORKITEMS_PARMNUM); enum SV_MAXMPXCT_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXMPXCT_PARMNUM); enum SV_OPLOCKBREAKWAIT_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_OPLOCKBREAKWAIT_PARMNUM); enum SV_OPLOCKBREAKRESPONSEWAIT_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_OPLOCKBREAKRESPONSEWAIT_PARMNUM); enum SV_ENABLEOPLOCKS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ENABLEOPLOCKS_PARMNUM); enum SV_ENABLEOPLOCKFORCECLOSE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ENABLEOPLOCKFORCECLOSE_PARMNUM); enum SV_ENABLEFCBOPENS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ENABLEFCBOPENS_PARMNUM); enum SV_ENABLERAW_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ENABLERAW_PARMNUM); enum SV_ENABLESHAREDNETDRIVES_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ENABLESHAREDNETDRIVES_PARMNUM); enum SV_MINFREECONNECTIONS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MINFREECONNECTIONS_PARMNUM); enum SV_MAXFREECONNECTIONS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXFREECONNECTIONS_PARMNUM); enum SV_INITSESSTABLE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_INITSESSTABLE_PARMNUM); enum SV_INITCONNTABLE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_INITCONNTABLE_PARMNUM); enum SV_INITFILETABLE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_INITFILETABLE_PARMNUM); enum SV_INITSEARCHTABLE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_INITSEARCHTABLE_PARMNUM); enum SV_ALERTSCHEDULE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ALERTSCHEDULE_PARMNUM); enum SV_ERRORTHRESHOLD_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ERRORTHRESHOLD_PARMNUM); enum SV_NETWORKERRORTHRESHOLD_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_NETWORKERRORTHRESHOLD_PARMNUM); enum SV_DISKSPACETHRESHOLD_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_DISKSPACETHRESHOLD_PARMNUM); enum SV_MAXLINKDELAY_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXLINKDELAY_PARMNUM); enum SV_MINLINKTHROUGHPUT_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MINLINKTHROUGHPUT_PARMNUM); enum SV_LINKINFOVALIDTIME_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_LINKINFOVALIDTIME_PARMNUM); enum SV_SCAVQOSINFOUPDATETIME_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SCAVQOSINFOUPDATETIME_PARMNUM); enum SV_MAXWORKITEMIDLETIME_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXWORKITEMIDLETIME_PARMNUM); enum SV_MAXRAWWORKITEMS_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXRAWWORKITEMS_PARMNUM); enum SV_PRODUCTTYPE_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_PRODUCTTYPE_PARMNUM); enum SV_SERVERSIZE_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SERVERSIZE_PARMNUM); enum SV_CONNECTIONLESSAUTODISC_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_CONNECTIONLESSAUTODISC_PARMNUM); enum SV_SHARINGVIOLATIONRETRIES_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SHARINGVIOLATIONRETRIES_PARMNUM); enum SV_SHARINGVIOLATIONDELAY_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SHARINGVIOLATIONDELAY_PARMNUM); enum SV_MAXGLOBALOPENSEARCH_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXGLOBALOPENSEARCH_PARMNUM); enum SV_REMOVEDUPLICATESEARCHES_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_REMOVEDUPLICATESEARCHES_PARMNUM); enum SV_LOCKVIOLATIONRETRIES_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_LOCKVIOLATIONRETRIES_PARMNUM); enum SV_LOCKVIOLATIONOFFSET_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_LOCKVIOLATIONOFFSET_PARMNUM); enum SV_LOCKVIOLATIONDELAY_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_LOCKVIOLATIONDELAY_PARMNUM); enum SV_MDLREADSWITCHOVER_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MDLREADSWITCHOVER_PARMNUM); enum SV_CACHEDOPENLIMIT_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_CACHEDOPENLIMIT_PARMNUM); enum SV_CRITICALTHREADS_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_CRITICALTHREADS_PARMNUM); enum SV_RESTRICTNULLSESSACCESS_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_RESTRICTNULLSESSACCESS_PARMNUM); enum SV_ENABLEWFW311DIRECTIPX_INFOLOEVEL=(PARMNUM_BASE_INFOLEVEL+SV_ENABLEWFW311DIRECTIPX_PARMNUM); enum SV_OTHERQUEUEAFFINITY_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_OTHERQUEUEAFFINITY_PARMNUM); enum SV_QUEUESAMPLESECS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_QUEUESAMPLESECS_PARMNUM); enum SV_BALANCECOUNT_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_BALANCECOUNT_PARMNUM); enum SV_PREFERREDAFFINITY_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_PREFERREDAFFINITY_PARMNUM); enum SV_MAXFREERFCBS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXFREERFCBS_PARMNUM); enum SV_MAXFREEMFCBS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXFREEMFCBS_PARMNUM); enum SV_MAXFREELFCBS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXFREELFCBS_PARMNUM); enum SV_MAXFREEPAGEDPOOLCHUNKS_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXFREEPAGEDPOOLCHUNKS_PARMNUM); enum SV_MINPAGEDPOOLCHUNKSIZE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MINPAGEDPOOLCHUNKSIZE_PARMNUM); enum SV_MAXPAGEDPOOLCHUNKSIZE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXPAGEDPOOLCHUNKSIZE_PARMNUM); enum SV_SENDSFROMPREFERREDPROCESSOR_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_SENDSFROMPREFERREDPROCESSOR_PARMNUM); enum SV_MAXTHREADSPERQUEUE_INFOLEVEL=(PARMNUM_BASE_INFOLEVEL+SV_MAXTHREADSPERQUEUE_PARMNUM); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/schannel.d0000664000175000017500000000642112776214756023455 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_schannel.d) */ module core.sys.windows.schannel; version (Windows): import core.sys.windows.wincrypt; private import core.sys.windows.windef; enum DWORD SCHANNEL_CRED_VERSION = 4; enum SCHANNEL_SHUTDOWN = 1; /* Comment from MinGW ? Do these belong here or in wincrypt.h */ enum : DWORD { AUTHTYPE_CLIENT = 1, AUTHTYPE_SERVER = 2 } enum DWORD SP_PROT_PCT1_SERVER = 0x01, SP_PROT_PCT1_CLIENT = 0x02, SP_PROT_SSL2_SERVER = 0x04, SP_PROT_SSL2_CLIENT = 0x08, SP_PROT_SSL3_SERVER = 0x10, SP_PROT_SSL3_CLIENT = 0x20, SP_PROT_TLS1_SERVER = 0x40, SP_PROT_TLS1_CLIENT = 0x80, SP_PROT_PCT1 = SP_PROT_PCT1_CLIENT | SP_PROT_PCT1_SERVER, SP_PROT_TLS1 = SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_SERVER, SP_PROT_SSL2 = SP_PROT_SSL2_CLIENT | SP_PROT_SSL2_SERVER, SP_PROT_SSL3 = SP_PROT_SSL3_CLIENT | SP_PROT_SSL3_SERVER; enum DWORD SCH_CRED_NO_SYSTEM_MAPPER = 0x0002, SCH_CRED_NO_SERVERNAME_CHECK = 0x0004, SCH_CRED_MANUAL_CRED_VALIDATION = 0x0008, SCH_CRED_NO_DEFAULT_CREDS = 0x0010, SCH_CRED_AUTO_CRED_VALIDATION = 0x0020, SCH_CRED_USE_DEFAULT_CREDS = 0x0040, SCH_CRED_REVOCATION_CHECK_END_CERT = 0x0100, SCH_CRED_REVOCATION_CHECK_CHAIN = 0x0200, SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x0400, SCH_CRED_IGNORE_NO_REVOCATION_CHECK = 0x0800, SCH_CRED_IGNORE_REVOCATION_OFFLINE = 0x1000; // No definition - presumably an opaque structure struct _HMAPPER; struct SCHANNEL_CRED { DWORD dwVersion = SCHANNEL_CRED_VERSION; DWORD cCreds; PCCERT_CONTEXT* paCred; HCERTSTORE hRootStore; DWORD cMappers; _HMAPPER** aphMappers; DWORD cSupportedAlgs; ALG_ID* palgSupportedAlgs; DWORD grbitEnabledProtocols; DWORD dwMinimumCypherStrength; DWORD dwMaximumCypherStrength; DWORD dwSessionLifespan; DWORD dwFlags; DWORD reserved; } alias SCHANNEL_CRED* PSCHANNEL_CRED; struct SecPkgCred_SupportedAlgs { DWORD cSupportedAlgs; ALG_ID* palgSupportedAlgs; } alias SecPkgCred_SupportedAlgs* PSecPkgCred_SupportedAlgs; struct SecPkgCred_CypherStrengths { DWORD dwMinimumCypherStrength; DWORD dwMaximumCypherStrength; } alias SecPkgCred_CypherStrengths* PSecPkgCred_CypherStrengths; struct SecPkgCred_SupportedProtocols { DWORD grbitProtocol; } alias SecPkgCred_SupportedProtocols* PSecPkgCred_SupportedProtocols; struct SecPkgContext_IssuerListInfoEx { PCERT_NAME_BLOB aIssuers; DWORD cIssuers; } alias SecPkgContext_IssuerListInfoEx* PSecPkgContext_IssuerListInfoEx; struct SecPkgContext_ConnectionInfo { DWORD dwProtocol; ALG_ID aiCipher; DWORD dwCipherStrength; ALG_ID aiHash; DWORD dwHashStrength; ALG_ID aiExch; DWORD dwExchStrength; } alias SecPkgContext_ConnectionInfo* PSecPkgContext_ConnectionInfo; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ntsecapi.d0000664000175000017500000006446312776214756023502 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ntsecapi.d) */ module core.sys.windows.ntsecapi; version (Windows): pragma(lib, "advapi32"); version (ANSI) {} else version = Unicode; private import core.sys.windows.basetyps, core.sys.windows.ntdef, core.sys.windows.windef, core.sys.windows.winnt, core.sys.windows.w32api; // FIXME: check types and grouping of constants // FIXME: check Windows version support enum KERB_WRAP_NO_ENCRYPT = 0x80000001; enum LOGON_GUEST = 0x00000001; enum LOGON_NOENCRYPTION = 0x00000002; enum LOGON_CACHED_ACCOUNT = 0x00000004; enum LOGON_USED_LM_PASSWORD = 0x00000008; enum LOGON_EXTRA_SIDS = 0x00000020; enum LOGON_SUBAUTH_SESSION_KEY = 0x00000040; enum LOGON_SERVER_TRUST_ACCOUNT = 0x00000080; enum LOGON_NTLMV2_ENABLED = 0x00000100; enum LOGON_RESOURCE_GROUPS = 0x00000200; enum LOGON_PROFILE_PATH_RETURNED = 0x00000400; enum LOGON_GRACE_LOGON = 0x01000000; enum { LSA_MODE_PASSWORD_PROTECTED = 1, LSA_MODE_INDIVIDUAL_ACCOUNTS, LSA_MODE_MANDATORY_ACCESS, LSA_MODE_LOG_FULL } bool LSA_SUCCESS(int x) { return x >= 0; } /* TOTHINKABOUT: These constants don't have ANSI/Unicode versioned * aliases. Should we merge them anyway? */ const char[] MICROSOFT_KERBEROS_NAME_A = "Kerberos"; const wchar[] MICROSOFT_KERBEROS_NAME_W = "Kerberos"; const char[] MSV1_0_PACKAGE_NAME = "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0"; const wchar[] MSV1_0_PACKAGE_NAMEW = "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0"; enum MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT = 32; enum MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT = 2048; enum MSV1_0_CLEARTEXT_PASSWORD_ALLOWED = 2; enum MSV1_0_CRED_LM_PRESENT = 1; enum MSV1_0_CRED_NT_PRESENT = 2; enum MSV1_0_CRED_VERSION = 0; enum MSV1_0_DONT_TRY_GUEST_ACCOUNT = 16; enum MSV1_0_MAX_NTLM3_LIFE = 1800; enum MSV1_0_MAX_AVL_SIZE = 64000; enum MSV1_0_MNS_LOGON = 16777216; enum size_t MSV1_0_CHALLENGE_LENGTH = 8, MSV1_0_LANMAN_SESSION_KEY_LENGTH = 8, MSV1_0_NTLM3_RESPONSE_LENGTH = 16, MSV1_0_NTLM3_OWF_LENGTH = 16, MSV1_0_NTLM3_INPUT_LENGTH = MSV1_0_NTLM3_RESPONSE.sizeof - MSV1_0_NTLM3_RESPONSE_LENGTH, MSV1_0_OWF_PASSWORD_LENGTH = 16, MSV1_0_PACKAGE_NAMEW_LENGTH = MSV1_0_PACKAGE_NAMEW.sizeof - WCHAR.sizeof; enum MSV1_0_RETURN_USER_PARAMETERS = 8; enum MSV1_0_RETURN_PASSWORD_EXPIRY = 64; enum MSV1_0_RETURN_PROFILE_PATH = 512; enum MSV1_0_SUBAUTHENTICATION_DLL_EX = 1048576; enum MSV1_0_SUBAUTHENTICATION_DLL = 0xff000000; enum MSV1_0_SUBAUTHENTICATION_DLL_SHIFT = 24; enum MSV1_0_SUBAUTHENTICATION_DLL_RAS = 2; enum MSV1_0_SUBAUTHENTICATION_DLL_IIS = 132; enum MSV1_0_SUBAUTHENTICATION_FLAGS = 0xff000000; enum MSV1_0_TRY_GUEST_ACCOUNT_ONLY = 256; enum MSV1_0_TRY_SPECIFIED_DOMAIN_ONLY = 1024; enum MSV1_0_UPDATE_LOGON_STATISTICS = 4; enum MSV1_0_USE_CLIENT_CHALLENGE = 128; enum MSV1_0_USER_SESSION_KEY_LENGTH = 16; const char[] MSV1_0_SUBAUTHENTICATION_KEY = `System\CurrentControlSet\Control\Lsa\MSV1_0`, MSV1_0_SUBAUTHENTICATION_VALUE = "Auth"; enum ACCESS_MASK POLICY_VIEW_LOCAL_INFORMATION = 0x0001, POLICY_VIEW_AUDIT_INFORMATION = 0x0002, POLICY_GET_PRIVATE_INFORMATION = 0x0004, POLICY_TRUST_ADMIN = 0x0008, POLICY_CREATE_ACCOUNT = 0x0010, POLICY_CREATE_SECRET = 0x0020, POLICY_CREATE_PRIVILEGE = 0x0040, POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x0080, POLICY_SET_AUDIT_REQUIREMENTS = 0x0100, POLICY_AUDIT_LOG_ADMIN = 0x0200, POLICY_SERVER_ADMIN = 0x0400, POLICY_LOOKUP_NAMES = 0x0800, POLICY_READ = STANDARD_RIGHTS_READ | 0x0006, POLICY_WRITE = STANDARD_RIGHTS_WRITE | 0x07F8, POLICY_EXECUTE = STANDARD_RIGHTS_EXECUTE | 0x0801, POLICY_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | 0x0FFF; enum POLICY_AUDIT_EVENT_UNCHANGED = 0; enum POLICY_AUDIT_EVENT_SUCCESS = 1; enum POLICY_AUDIT_EVENT_FAILURE = 2; enum POLICY_AUDIT_EVENT_NONE = 4; enum POLICY_AUDIT_EVENT_MASK = 7; enum { POLICY_LOCATION_LOCAL = 1, POLICY_LOCATION_DS } enum : uint { POLICY_MACHINE_POLICY_LOCAL = 0, POLICY_MACHINE_POLICY_DEFAULTED, POLICY_MACHINE_POLICY_EXPLICIT, POLICY_MACHINE_POLICY_UNKNOWN = 0xFFFFFFFF } enum POLICY_QOS_SCHANEL_REQUIRED = 0x0001; enum POLICY_QOS_OUTBOUND_INTEGRITY = 0x0002; enum POLICY_QOS_OUTBOUND_CONFIDENTIALITY = 0x0004; enum POLICY_QOS_INBOUND_INTEGREITY = 0x0008; enum POLICY_QOS_INBOUND_CONFIDENTIALITY = 0x0010; enum POLICY_QOS_ALLOW_LOCAL_ROOT_CERT_STORE = 0x0020; enum POLICY_QOS_RAS_SERVER_ALLOWED = 0x0040; enum POLICY_QOS_DHCP_SERVER_ALLOWD = 0x0080; enum POLICY_KERBEROS_FORWARDABLE = 1; enum POLICY_KERBEROS_PROXYABLE = 2; enum POLICY_KERBEROS_RENEWABLE = 4; enum POLICY_KERBEROS_POSTDATEABLE = 8; const char[] SAM_PASSWORD_CHANGE_NOTIFY_ROUTINE = "PasswordChangeNotify", SAM_INIT_NOTIFICATION_ROUTINE = "InitializeChangeNotify", SAM_PASSWORD_FILTER_ROUTINE = "PasswordFilter"; const TCHAR[] SE_INTERACTIVE_LOGON_NAME = "SeInteractiveLogonRight", SE_NETWORK_LOGON_NAME = "SeNetworkLogonRight", SE_BATCH_LOGON_NAME = "SeBatchLogonRight", SE_SERVICE_LOGON_NAME = "SeServiceLogonRight"; enum { TRUST_ATTRIBUTE_NON_TRANSITIVE = 1, TRUST_ATTRIBUTE_UPLEVEL_ONLY = 2, TRUST_ATTRIBUTE_TREE_PARENT = 4194304, TRUST_ATTRIBUTES_VALID = -16580609 } enum { TRUST_AUTH_TYPE_NONE, TRUST_AUTH_TYPE_NT4OWF, TRUST_AUTH_TYPE_CLEAR } enum { TRUST_DIRECTION_DISABLED, TRUST_DIRECTION_INBOUND, TRUST_DIRECTION_OUTBOUND, TRUST_DIRECTION_BIDIRECTIONAL } enum { TRUST_TYPE_DOWNLEVEL = 1, TRUST_TYPE_UPLEVEL, TRUST_TYPE_MIT, TRUST_TYPE_DCE } alias UNICODE_STRING LSA_UNICODE_STRING; alias UNICODE_STRING* PLSA_UNICODE_STRING; alias STRING LSA_STRING; alias STRING* PLSA_STRING; enum MSV1_0_LOGON_SUBMIT_TYPE { MsV1_0InteractiveLogon = 2, MsV1_0Lm20Logon, MsV1_0NetworkLogon, MsV1_0SubAuthLogon, MsV1_0WorkstationUnlockLogon = 7 } alias MSV1_0_LOGON_SUBMIT_TYPE* PMSV1_0_LOGON_SUBMIT_TYPE; enum MSV1_0_PROFILE_BUFFER_TYPE { MsV1_0InteractiveProfile = 2, MsV1_0Lm20LogonProfile, MsV1_0SmartCardProfile } alias MSV1_0_PROFILE_BUFFER_TYPE* PMSV1_0_PROFILE_BUFFER_TYPE; enum MSV1_0_AVID { MsvAvEOL, MsvAvNbComputerName, MsvAvNbDomainName, MsvAvDnsComputerName, MsvAvDnsDomainName } enum MSV1_0_PROTOCOL_MESSAGE_TYPE { MsV1_0Lm20ChallengeRequest = 0, MsV1_0Lm20GetChallengeResponse, MsV1_0EnumerateUsers, MsV1_0GetUserInfo, MsV1_0ReLogonUsers, MsV1_0ChangePassword, MsV1_0ChangeCachedPassword, MsV1_0GenericPassthrough, MsV1_0CacheLogon, MsV1_0SubAuth, MsV1_0DeriveCredential, MsV1_0CacheLookup } alias MSV1_0_PROTOCOL_MESSAGE_TYPE* PMSV1_0_PROTOCOL_MESSAGE_TYPE; enum POLICY_LSA_SERVER_ROLE { PolicyServerRoleBackup = 2, PolicyServerRolePrimary } alias POLICY_LSA_SERVER_ROLE* PPOLICY_LSA_SERVER_ROLE; enum POLICY_SERVER_ENABLE_STATE { PolicyServerEnabled = 2, PolicyServerDisabled } alias POLICY_SERVER_ENABLE_STATE* PPOLICY_SERVER_ENABLE_STATE; enum POLICY_INFORMATION_CLASS { PolicyAuditLogInformation = 1, PolicyAuditEventsInformation, PolicyPrimaryDomainInformation, PolicyPdAccountInformation, PolicyAccountDomainInformation, PolicyLsaServerRoleInformation, PolicyReplicaSourceInformation, PolicyDefaultQuotaInformation, PolicyModificationInformation, PolicyAuditFullSetInformation, PolicyAuditFullQueryInformation, PolicyDnsDomainInformation, PolicyEfsInformation } alias POLICY_INFORMATION_CLASS* PPOLICY_INFORMATION_CLASS; enum POLICY_AUDIT_EVENT_TYPE { AuditCategorySystem, AuditCategoryLogon, AuditCategoryObjectAccess, AuditCategoryPrivilegeUse, AuditCategoryDetailedTracking, AuditCategoryPolicyChange, AuditCategoryAccountManagement, AuditCategoryDirectoryServiceAccess, AuditCategoryAccountLogon } alias POLICY_AUDIT_EVENT_TYPE* PPOLICY_AUDIT_EVENT_TYPE; enum POLICY_LOCAL_INFORMATION_CLASS { PolicyLocalAuditEventsInformation = 1, PolicyLocalPdAccountInformation, PolicyLocalAccountDomainInformation, PolicyLocalLsaServerRoleInformation, PolicyLocalReplicaSourceInformation, PolicyLocalModificationInformation, PolicyLocalAuditFullSetInformation, PolicyLocalAuditFullQueryInformation, PolicyLocalDnsDomainInformation, PolicyLocalIPSecReferenceInformation, PolicyLocalMachinePasswordInformation, PolicyLocalQualityOfServiceInformation, PolicyLocalPolicyLocationInformation } alias POLICY_LOCAL_INFORMATION_CLASS* PPOLICY_LOCAL_INFORMATION_CLASS; enum POLICY_DOMAIN_INFORMATION_CLASS { PolicyDomainIPSecReferenceInformation = 1, PolicyDomainQualityOfServiceInformation, PolicyDomainEfsInformation, PolicyDomainPublicKeyInformation, PolicyDomainPasswordPolicyInformation, PolicyDomainLockoutInformation, PolicyDomainKerberosTicketInformation } alias POLICY_DOMAIN_INFORMATION_CLASS* PPOLICY_DOMAIN_INFORMATION_CLASS; enum SECURITY_LOGON_TYPE { Interactive = 2, Network, Batch, Service, Proxy, Unlock } alias SECURITY_LOGON_TYPE* PSECURITY_LOGON_TYPE; enum TRUSTED_INFORMATION_CLASS { TrustedDomainNameInformation = 1, TrustedControllersInformation, TrustedPosixOffsetInformation, TrustedPasswordInformation, TrustedDomainInformationBasic, TrustedDomainInformationEx, TrustedDomainAuthInformation, TrustedDomainFullInformation } alias TRUSTED_INFORMATION_CLASS* PTRUSTED_INFORMATION_CLASS; struct DOMAIN_PASSWORD_INFORMATION { USHORT MinPasswordLength; USHORT PasswordHistoryLength; ULONG PasswordProperties; LARGE_INTEGER MaxPasswordAge; LARGE_INTEGER MinPasswordAge; } alias DOMAIN_PASSWORD_INFORMATION* PDOMAIN_PASSWORD_INFORMATION; struct LSA_ENUMERATION_INFORMATION { PSID Sid; } alias LSA_ENUMERATION_INFORMATION* PLSA_ENUMERATION_INFORMATION; alias OBJECT_ATTRIBUTES LSA_OBJECT_ATTRIBUTES; alias OBJECT_ATTRIBUTES* PLSA_OBJECT_ATTRIBUTES; struct LSA_TRUST_INFORMATION { LSA_UNICODE_STRING Name; PSID Sid; } alias LSA_TRUST_INFORMATION TRUSTED_DOMAIN_INFORMATION_BASIC; alias LSA_TRUST_INFORMATION* PLSA_TRUST_INFORMATION; /* in MinGW (further down the code): * typedef PLSA_TRUST_INFORMATION *PTRUSTED_DOMAIN_INFORMATION_BASIC; * but it doesn't look right.... */ alias LSA_TRUST_INFORMATION** PTRUSTED_DOMAIN_INFORMATION_BASIC; struct LSA_REFERENCED_DOMAIN_LIST { ULONG Entries; PLSA_TRUST_INFORMATION Domains; } alias LSA_REFERENCED_DOMAIN_LIST* PLSA_REFERENCED_DOMAIN_LIST; struct LSA_TRANSLATED_SID { SID_NAME_USE Use; ULONG RelativeId; LONG DomainIndex; } alias LSA_TRANSLATED_SID* PLSA_TRANSLATED_SID; struct LSA_TRANSLATED_NAME { SID_NAME_USE Use; LSA_UNICODE_STRING Name; LONG DomainIndex; } alias LSA_TRANSLATED_NAME* PLSA_TRANSLATED_NAME; struct MSV1_0_INTERACTIVE_LOGON { MSV1_0_LOGON_SUBMIT_TYPE MessageType; UNICODE_STRING LogonDomainName; UNICODE_STRING UserName; UNICODE_STRING Password; } alias MSV1_0_INTERACTIVE_LOGON* PMSV1_0_INTERACTIVE_LOGON; struct MSV1_0_INTERACTIVE_PROFILE { MSV1_0_PROFILE_BUFFER_TYPE MessageType; USHORT LogonCount; USHORT BadPasswordCount; LARGE_INTEGER LogonTime; LARGE_INTEGER LogoffTime; LARGE_INTEGER KickOffTime; LARGE_INTEGER PasswordLastSet; LARGE_INTEGER PasswordCanChange; LARGE_INTEGER PasswordMustChange; UNICODE_STRING LogonScript; UNICODE_STRING HomeDirectory; UNICODE_STRING FullName; UNICODE_STRING ProfilePath; UNICODE_STRING HomeDirectoryDrive; UNICODE_STRING LogonServer; ULONG UserFlags; } alias MSV1_0_INTERACTIVE_PROFILE* PMSV1_0_INTERACTIVE_PROFILE; struct MSV1_0_LM20_LOGON { MSV1_0_LOGON_SUBMIT_TYPE MessageType; UNICODE_STRING LogonDomainName; UNICODE_STRING UserName; UNICODE_STRING Workstation; UCHAR[MSV1_0_CHALLENGE_LENGTH] ChallengeToClient; STRING CaseSensitiveChallengeResponse; STRING CaseInsensitiveChallengeResponse; ULONG ParameterControl; } alias MSV1_0_LM20_LOGON* PMSV1_0_LM20_LOGON; //static if (_WIN32_WINNT >= 0x500) { struct MSV1_0_SUBAUTH_LOGON { MSV1_0_LOGON_SUBMIT_TYPE MessageType; UNICODE_STRING LogonDomainName; UNICODE_STRING UserName; UNICODE_STRING Workstation; UCHAR[MSV1_0_CHALLENGE_LENGTH] ChallengeToClient; STRING AuthenticationInfo1; STRING AuthenticationInfo2; ULONG ParameterControl; ULONG SubAuthPackageId; } alias MSV1_0_SUBAUTH_LOGON* PMSV1_0_SUBAUTH_LOGON; //} struct MSV1_0_LM20_LOGON_PROFILE { MSV1_0_PROFILE_BUFFER_TYPE MessageType; LARGE_INTEGER KickOffTime; LARGE_INTEGER LogoffTime; ULONG UserFlags; UCHAR[MSV1_0_USER_SESSION_KEY_LENGTH] UserSessionKey; UNICODE_STRING LogonDomainName; UCHAR[MSV1_0_LANMAN_SESSION_KEY_LENGTH] LanmanSessionKey; UNICODE_STRING LogonServer; UNICODE_STRING UserParameters; } alias MSV1_0_LM20_LOGON_PROFILE* PMSV1_0_LM20_LOGON_PROFILE; struct MSV1_0_SUPPLEMENTAL_CREDENTIAL { ULONG Version; ULONG Flags; UCHAR[MSV1_0_OWF_PASSWORD_LENGTH] LmPassword; UCHAR[MSV1_0_OWF_PASSWORD_LENGTH] NtPassword; } alias MSV1_0_SUPPLEMENTAL_CREDENTIAL* PMSV1_0_SUPPLEMENTAL_CREDENTIAL; struct MSV1_0_NTLM3_RESPONSE { UCHAR[MSV1_0_NTLM3_RESPONSE_LENGTH] Response; UCHAR RespType; UCHAR HiRespType; USHORT Flags; ULONG MsgWord; ULONGLONG TimeStamp; UCHAR[MSV1_0_CHALLENGE_LENGTH] ChallengeFromClient; ULONG AvPairsOff; UCHAR _Buffer; UCHAR* Buffer() return { return &_Buffer; } } alias MSV1_0_NTLM3_RESPONSE* PMSV1_0_NTLM3_RESPONSE; struct MSV1_0_AV_PAIR { USHORT AvId; USHORT AvLen; } alias MSV1_0_AV_PAIR* PMSV1_0_AV_PAIR; struct MSV1_0_CHANGEPASSWORD_REQUEST { MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType; UNICODE_STRING DomainName; UNICODE_STRING AccountName; UNICODE_STRING OldPassword; UNICODE_STRING NewPassword; BOOLEAN Impersonating; } alias MSV1_0_CHANGEPASSWORD_REQUEST* PMSV1_0_CHANGEPASSWORD_REQUEST; struct MSV1_0_CHANGEPASSWORD_RESPONSE { MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType; BOOLEAN PasswordInfoValid; DOMAIN_PASSWORD_INFORMATION DomainPasswordInfo; } alias MSV1_0_CHANGEPASSWORD_RESPONSE* PMSV1_0_CHANGEPASSWORD_RESPONSE; struct MSV1_0_SUBAUTH_REQUEST { MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType; ULONG SubAuthPackageId; ULONG SubAuthInfoLength; PUCHAR SubAuthSubmitBuffer; } alias MSV1_0_SUBAUTH_REQUEST* PMSV1_0_SUBAUTH_REQUEST; struct MSV1_0_SUBAUTH_RESPONSE { MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType; ULONG SubAuthInfoLength; PUCHAR SubAuthReturnBuffer; } alias MSV1_0_SUBAUTH_RESPONSE* PMSV1_0_SUBAUTH_RESPONSE; enum MSV1_0_DERIVECRED_TYPE_SHA1 = 0; struct MSV1_0_DERIVECRED_REQUEST { MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType; LUID LogonId; ULONG DeriveCredType; ULONG DeriveCredInfoLength; UCHAR _DeriveCredSubmitBuffer; UCHAR* DeriveCredSubmitBuffer() return { return &_DeriveCredSubmitBuffer; } } alias MSV1_0_DERIVECRED_REQUEST* PMSV1_0_DERIVECRED_REQUEST; struct MSV1_0_DERIVECRED_RESPONSE { MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType; ULONG DeriveCredInfoLength; UCHAR _DeriveCredReturnBuffer; UCHAR* DeriveCredReturnBuffer() return { return &_DeriveCredReturnBuffer; } } alias MSV1_0_DERIVECRED_RESPONSE* PMSV1_0_DERIVECRED_RESPONSE; alias uint LSA_ENUMERATION_HANDLE, LSA_OPERATIONAL_MODE, POLICY_AUDIT_EVENT_OPTIONS; alias uint* PLSA_ENUMERATION_HANDLE, PLSA_OPERATIONAL_MODE, PPOLICY_AUDIT_EVENT_OPTIONS; struct POLICY_PRIVILEGE_DEFINITION { LSA_UNICODE_STRING Name; LUID LocalValue; } alias POLICY_PRIVILEGE_DEFINITION* PPOLICY_PRIVILEGE_DEFINITION; struct POLICY_AUDIT_LOG_INFO { ULONG AuditLogPercentFull; ULONG MaximumLogSize; LARGE_INTEGER AuditRetentionPeriod; BOOLEAN AuditLogFullShutdownInProgress; LARGE_INTEGER TimeToShutdown; ULONG NextAuditRecordId; } alias POLICY_AUDIT_LOG_INFO* PPOLICY_AUDIT_LOG_INFO; struct POLICY_AUDIT_EVENTS_INFO { BOOLEAN AuditingMode; PPOLICY_AUDIT_EVENT_OPTIONS EventAuditingOptions; ULONG MaximumAuditEventCount; } alias POLICY_AUDIT_EVENTS_INFO* PPOLICY_AUDIT_EVENTS_INFO; struct POLICY_ACCOUNT_DOMAIN_INFO { LSA_UNICODE_STRING DomainName; PSID DomainSid; } alias POLICY_ACCOUNT_DOMAIN_INFO* PPOLICY_ACCOUNT_DOMAIN_INFO; struct POLICY_PRIMARY_DOMAIN_INFO { LSA_UNICODE_STRING Name; PSID Sid; } alias POLICY_PRIMARY_DOMAIN_INFO* PPOLICY_PRIMARY_DOMAIN_INFO; struct POLICY_DNS_DOMAIN_INFO { LSA_UNICODE_STRING Name; LSA_UNICODE_STRING DnsDomainName; LSA_UNICODE_STRING DnsTreeName; GUID DomainGuid; PSID Sid; } alias POLICY_DNS_DOMAIN_INFO* PPOLICY_DNS_DOMAIN_INFO; struct POLICY_PD_ACCOUNT_INFO { LSA_UNICODE_STRING Name; } alias POLICY_PD_ACCOUNT_INFO* PPOLICY_PD_ACCOUNT_INFO; struct POLICY_LSA_SERVER_ROLE_INFO { POLICY_LSA_SERVER_ROLE LsaServerRole; } alias POLICY_LSA_SERVER_ROLE_INFO* PPOLICY_LSA_SERVER_ROLE_INFO; struct POLICY_REPLICA_SOURCE_INFO { LSA_UNICODE_STRING ReplicaSource; LSA_UNICODE_STRING ReplicaAccountName; } alias POLICY_REPLICA_SOURCE_INFO* PPOLICY_REPLICA_SOURCE_INFO; struct POLICY_DEFAULT_QUOTA_INFO { QUOTA_LIMITS QuotaLimits; } alias POLICY_DEFAULT_QUOTA_INFO* PPOLICY_DEFAULT_QUOTA_INFO; struct POLICY_MODIFICATION_INFO { LARGE_INTEGER ModifiedId; LARGE_INTEGER DatabaseCreationTime; } alias POLICY_MODIFICATION_INFO* PPOLICY_MODIFICATION_INFO; struct POLICY_AUDIT_FULL_SET_INFO { BOOLEAN ShutDownOnFull; } alias POLICY_AUDIT_FULL_SET_INFO* PPOLICY_AUDIT_FULL_SET_INFO; struct POLICY_AUDIT_FULL_QUERY_INFO { BOOLEAN ShutDownOnFull; BOOLEAN LogIsFull; } alias POLICY_AUDIT_FULL_QUERY_INFO* PPOLICY_AUDIT_FULL_QUERY_INFO; struct POLICY_EFS_INFO { ULONG InfoLength; PUCHAR EfsBlob; } alias POLICY_EFS_INFO* PPOLICY_EFS_INFO; struct POLICY_LOCAL_IPSEC_REFERENCE_INFO { LSA_UNICODE_STRING ObjectPath; } alias POLICY_LOCAL_IPSEC_REFERENCE_INFO* PPOLICY_LOCAL_IPSEC_REFERENCE_INFO; struct POLICY_LOCAL_MACHINE_PASSWORD_INFO { LARGE_INTEGER PasswordChangeInterval; } alias POLICY_LOCAL_MACHINE_PASSWORD_INFO* PPOLICY_LOCAL_MACHINE_PASSWORD_INFO; struct POLICY_LOCAL_POLICY_LOCATION_INFO { ULONG PolicyLocation; } alias POLICY_LOCAL_POLICY_LOCATION_INFO* PPOLICY_LOCAL_POLICY_LOCATION_INFO; struct POLICY_LOCAL_QUALITY_OF_SERVICE_INFO{ ULONG QualityOfService; } alias POLICY_LOCAL_QUALITY_OF_SERVICE_INFO POLICY_DOMAIN_QUALITY_OF_SERVICE_INFO; alias POLICY_LOCAL_QUALITY_OF_SERVICE_INFO* PPOLICY_LOCAL_QUALITY_OF_SERVICE_INFO, PPOLICY_DOMAIN_QUALITY_OF_SERVICE_INFO; struct POLICY_DOMAIN_PUBLIC_KEY_INFO { ULONG InfoLength; PUCHAR PublicKeyInfo; } alias POLICY_DOMAIN_PUBLIC_KEY_INFO* PPOLICY_DOMAIN_PUBLIC_KEY_INFO; struct POLICY_DOMAIN_LOCKOUT_INFO { LARGE_INTEGER LockoutDuration; LARGE_INTEGER LockoutObservationWindow; USHORT LockoutThreshold; } alias POLICY_DOMAIN_LOCKOUT_INFO* PPOLICY_DOMAIN_LOCKOUT_INFO; struct POLICY_DOMAIN_PASSWORD_INFO { USHORT MinPasswordLength; USHORT PasswordHistoryLength; ULONG PasswordProperties; LARGE_INTEGER MaxPasswordAge; LARGE_INTEGER MinPasswordAge; } alias POLICY_DOMAIN_PASSWORD_INFO* PPOLICY_DOMAIN_PASSWORD_INFO; struct POLICY_DOMAIN_KERBEROS_TICKET_INFO { ULONG AuthenticationOptions; LARGE_INTEGER MinTicketAge; LARGE_INTEGER MaxTicketAge; LARGE_INTEGER MaxRenewAge; LARGE_INTEGER ProxyLifetime; LARGE_INTEGER ForceLogoff; } alias POLICY_DOMAIN_KERBEROS_TICKET_INFO* PPOLICY_DOMAIN_KERBEROS_TICKET_INFO; mixin DECLARE_HANDLE!("LSA_HANDLE"); alias LSA_HANDLE* PLSA_HANDLE; struct TRUSTED_DOMAIN_NAME_INFO { LSA_UNICODE_STRING Name; } alias TRUSTED_DOMAIN_NAME_INFO* PTRUSTED_DOMAIN_NAME_INFO; struct TRUSTED_CONTROLLERS_INFO { ULONG Entries; PLSA_UNICODE_STRING Names; } alias TRUSTED_CONTROLLERS_INFO* PTRUSTED_CONTROLLERS_INFO; struct TRUSTED_POSIX_OFFSET_INFO { ULONG Offset; } alias TRUSTED_POSIX_OFFSET_INFO* PTRUSTED_POSIX_OFFSET_INFO; struct TRUSTED_PASSWORD_INFO { LSA_UNICODE_STRING Password; LSA_UNICODE_STRING OldPassword; } alias TRUSTED_PASSWORD_INFO* PTRUSTED_PASSWORD_INFO; struct TRUSTED_DOMAIN_INFORMATION_EX { LSA_UNICODE_STRING Name; LSA_UNICODE_STRING FlatName; PSID Sid; ULONG TrustDirection; ULONG TrustType; ULONG TrustAttributes; } alias TRUSTED_DOMAIN_INFORMATION_EX* PTRUSTED_DOMAIN_INFORMATION_EX; struct LSA_AUTH_INFORMATION { LARGE_INTEGER LastUpdateTime; ULONG AuthType; ULONG AuthInfoLength; PUCHAR AuthInfo; } alias LSA_AUTH_INFORMATION* PLSA_AUTH_INFORMATION; struct TRUSTED_DOMAIN_AUTH_INFORMATION { ULONG IncomingAuthInfos; PLSA_AUTH_INFORMATION IncomingAuthenticationInformation; PLSA_AUTH_INFORMATION IncomingPreviousAuthenticationInformation; ULONG OutgoingAuthInfos; PLSA_AUTH_INFORMATION OutgoingAuthenticationInformation; PLSA_AUTH_INFORMATION OutgoingPreviousAuthenticationInformation; } alias TRUSTED_DOMAIN_AUTH_INFORMATION* PTRUSTED_DOMAIN_AUTH_INFORMATION; struct TRUSTED_DOMAIN_FULL_INFORMATION { TRUSTED_DOMAIN_INFORMATION_EX Information; TRUSTED_POSIX_OFFSET_INFO PosixOffset; TRUSTED_DOMAIN_AUTH_INFORMATION AuthInformation; } alias TRUSTED_DOMAIN_FULL_INFORMATION* PTRUSTED_DOMAIN_FULL_INFORMATION; extern (Windows) { NTSTATUS LsaAddAccountRights(LSA_HANDLE, PSID, PLSA_UNICODE_STRING, ULONG); NTSTATUS LsaCallAuthenticationPackage(HANDLE, ULONG, PVOID, ULONG, PVOID*, PULONG, PNTSTATUS); NTSTATUS LsaClose(LSA_HANDLE); NTSTATUS LsaConnectUntrusted(PHANDLE); NTSTATUS LsaCreateTrustedDomainEx(LSA_HANDLE, PTRUSTED_DOMAIN_INFORMATION_EX, PTRUSTED_DOMAIN_AUTH_INFORMATION, ACCESS_MASK, PLSA_HANDLE); NTSTATUS LsaDeleteTrustedDomain(LSA_HANDLE, PSID); NTSTATUS LsaDeregisterLogonProcess(HANDLE); NTSTATUS LsaEnumerateAccountRights(LSA_HANDLE, PSID, PLSA_UNICODE_STRING*, PULONG); NTSTATUS LsaEnumerateAccountsWithUserRight(LSA_HANDLE, PLSA_UNICODE_STRING, PVOID*, PULONG); NTSTATUS LsaEnumerateTrustedDomains(LSA_HANDLE, PLSA_ENUMERATION_HANDLE, PVOID*, ULONG, PULONG); NTSTATUS LsaEnumerateTrustedDomainsEx(LSA_HANDLE, PLSA_ENUMERATION_HANDLE, TRUSTED_INFORMATION_CLASS, PVOID*, ULONG, PULONG); NTSTATUS LsaFreeMemory(PVOID); NTSTATUS LsaFreeReturnBuffer(PVOID); NTSTATUS LsaLogonUser(HANDLE, PLSA_STRING, SECURITY_LOGON_TYPE, ULONG, PVOID, ULONG, PTOKEN_GROUPS, PTOKEN_SOURCE, PVOID*, PULONG, PLUID, PHANDLE, PQUOTA_LIMITS, PNTSTATUS); NTSTATUS LsaLookupAuthenticationPackage(HANDLE, PLSA_STRING, PULONG); NTSTATUS LsaLookupNames(LSA_HANDLE, ULONG, PLSA_UNICODE_STRING, PLSA_REFERENCED_DOMAIN_LIST*, PLSA_TRANSLATED_SID*); NTSTATUS LsaLookupSids(LSA_HANDLE, ULONG, PSID*, PLSA_REFERENCED_DOMAIN_LIST*, PLSA_TRANSLATED_NAME*); ULONG LsaNtStatusToWinError(NTSTATUS); NTSTATUS LsaOpenPolicy(PLSA_UNICODE_STRING, PLSA_OBJECT_ATTRIBUTES, ACCESS_MASK, PLSA_HANDLE); NTSTATUS LsaQueryDomainInformationPolicy(LSA_HANDLE, POLICY_DOMAIN_INFORMATION_CLASS, PVOID*); NTSTATUS LsaQueryInformationPolicy(LSA_HANDLE, POLICY_INFORMATION_CLASS, PVOID*); NTSTATUS LsaQueryLocalInformationPolicy(LSA_HANDLE, POLICY_LOCAL_INFORMATION_CLASS, PVOID*); NTSTATUS LsaQueryTrustedDomainInfo(LSA_HANDLE, PSID, TRUSTED_INFORMATION_CLASS, PVOID*); NTSTATUS LsaQueryTrustedDomainInfoByName(LSA_HANDLE, PLSA_UNICODE_STRING, TRUSTED_INFORMATION_CLASS, PVOID*); NTSTATUS LsaRegisterLogonProcess(PLSA_STRING, PHANDLE, PLSA_OPERATIONAL_MODE); NTSTATUS LsaRemoveAccountRights(LSA_HANDLE, PSID, BOOLEAN, PLSA_UNICODE_STRING, ULONG); NTSTATUS LsaRetrievePrivateData(LSA_HANDLE, PLSA_UNICODE_STRING, PLSA_UNICODE_STRING*); NTSTATUS LsaSetDomainInformationPolicy(LSA_HANDLE, POLICY_DOMAIN_INFORMATION_CLASS, PVOID); NTSTATUS LsaSetInformationPolicy(LSA_HANDLE, POLICY_INFORMATION_CLASS, PVOID); NTSTATUS LsaSetLocalInformationPolicy(LSA_HANDLE, POLICY_LOCAL_INFORMATION_CLASS, PVOID); NTSTATUS LsaSetTrustedDomainInformation(LSA_HANDLE, PSID, TRUSTED_INFORMATION_CLASS, PVOID); NTSTATUS LsaSetTrustedDomainInfoByName(LSA_HANDLE, PLSA_UNICODE_STRING, TRUSTED_INFORMATION_CLASS, PVOID); NTSTATUS LsaStorePrivateData(LSA_HANDLE, PLSA_UNICODE_STRING, PLSA_UNICODE_STRING); } alias NTSTATUS function(PUNICODE_STRING, ULONG, PUNICODE_STRING) PSAM_PASSWORD_NOTIFICATION_ROUTINE; alias BOOLEAN function() PSAM_INIT_NOTIFICATION_ROUTINE; alias BOOLEAN function(PUNICODE_STRING, PUNICODE_STRING, PUNICODE_STRING, BOOLEAN) PSAM_PASSWORD_FILTER_ROUTINE; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/errorrep.d0000664000175000017500000000205512776214756023521 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_errorrep.d) */ module core.sys.windows.errorrep; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.w32api, core.sys.windows.windef; static assert (_WIN32_WINNT >= 0x501, "core.sys.windows.errorrep is available only if version WindowsXP, Windows2003 " "or WindowsVista is set"); enum EFaultRepRetVal { frrvOk, frrvOkManifest, frrvOkQueued, frrvErr, frrvErrNoDW, frrvErrTimeout, frrvLaunchDebugger, frrvOkHeadless // = 7 } extern (Windows) { BOOL AddERExcludedApplicationA(LPCSTR); BOOL AddERExcludedApplicationW(LPCWSTR); EFaultRepRetVal ReportFault(LPEXCEPTION_POINTERS, DWORD); } version (Unicode) { alias AddERExcludedApplicationW AddERExcludedApplication; } else { alias AddERExcludedApplicationA AddERExcludedApplication; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/basetyps.d0000664000175000017500000000131412776214756023510 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_basetyps.d) */ module core.sys.windows.basetyps; version (Windows): private import core.sys.windows.windef, core.sys.windows.basetsd; align(1) struct GUID { // size is 16 align(1): DWORD Data1; WORD Data2; WORD Data3; BYTE[8] Data4; } alias GUID UUID, /*IID, CLSID, */FMTID, uuid_t; alias IID = const(GUID); alias CLSID = const(GUID); alias GUID* LPGUID, LPCLSID, LPIID; alias const(GUID)* LPCGUID, REFGUID, REFIID, REFCLSID, REFFMTID; alias uint error_status_t, PROPID; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/nddeapi.d0000664000175000017500000001251612776214756023270 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_nddeapi.d) */ module core.sys.windows.nddeapi; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.windef; // FIXME: check types and grouping of constants /+ #ifndef CNLEN /* also in lmcons.h */ #define CNLEN 15 #define UNCLEN (CNLEN + 2) #endif +/ enum char SEP_CHAR = ','; const char[] BAR_CHAR = "|"; enum wchar SEP_WCHAR = ','; const wchar[] BAR_WCHAR = "|"; enum { NDDE_NO_ERROR, NDDE_ACCESS_DENIED, NDDE_BUF_TOO_SMALL, NDDE_ERROR_MORE_DATA, NDDE_INVALID_SERVER, NDDE_INVALID_SHARE, NDDE_INVALID_PARAMETER, NDDE_INVALID_LEVEL, NDDE_INVALID_PASSWORD, NDDE_INVALID_ITEMNAME, NDDE_INVALID_TOPIC, NDDE_INTERNAL_ERROR, NDDE_OUT_OF_MEMORY, NDDE_INVALID_APPNAME, NDDE_NOT_IMPLEMENTED, NDDE_SHARE_ALREADY_EXIST, NDDE_SHARE_NOT_EXIST, NDDE_INVALID_FILENAME, NDDE_NOT_RUNNING, NDDE_INVALID_WINDOW, NDDE_INVALID_SESSION, NDDE_INVALID_ITEM_LIST, NDDE_SHARE_DATA_CORRUPTED, NDDE_REGISTRY_ERROR, NDDE_CANT_ACCESS_SERVER, NDDE_INVALID_SPECIAL_COMMAND, NDDE_INVALID_SECURITY_DESC, NDDE_TRUST_SHARE_FAIL } enum size_t MAX_NDDESHARENAME = 256, MAX_DOMAINNAME = 15, MAX_USERNAME = 15, MAX_APPNAME = 255, MAX_TOPICNAME = 255, MAX_ITEMNAME = 255; enum NDDEF_NOPASSWORDPROMPT = 1; enum NDDEF_NOCACHELOOKUP = 2; enum NDDEF_STRIP_NDDE = 4; enum SHARE_TYPE_OLD = 1; enum SHARE_TYPE_NEW = 2; enum SHARE_TYPE_STATIC = 4; enum uint NDDE_CMD_SHOW_MASK = 0x0000FFFF, NDDE_TRUST_CMD_SHOW = 0x10000000, NDDE_TRUST_SHARE_DEL = 0x20000000, NDDE_TRUST_SHARE_INIT = 0x40000000, NDDE_TRUST_SHARE_START = 0x80000000; struct NDdeShareInfo_tag { LONG lRevision; LPTSTR lpszShareName; LONG lShareType; LPTSTR lpszAppTopicList; LONG fSharedFlag; LONG fService; LONG fStartAppFlag; LONG nCmdShow; LONG[2] qModifyId; LONG cNumItems; LPTSTR lpszItemList; } extern (C) { // huh? NDdeShareInfo_tag NDDESHAREINFO; NDdeShareInfo_tag* PNDDESHAREINFO; } extern (Windows) { UINT NDdeGetErrorStringA(UINT, LPSTR, DWORD); UINT NDdeGetErrorStringW(UINT, LPWSTR, DWORD); UINT NDdeGetShareSecurityA(LPSTR, LPSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, PDWORD); UINT NDdeGetShareSecurityW(LPWSTR, LPWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, PDWORD); UINT NDdeGetTrustedShareA(LPSTR, LPSTR, PDWORD, PDWORD, PDWORD); UINT NDdeGetTrustedShareW(LPWSTR, LPWSTR, PDWORD, PDWORD, PDWORD); BOOL NDdeIsValidShareNameA(LPSTR); BOOL NDdeIsValidShareNameW(LPWSTR); BOOL NDdeIsValidAppTopicListA(LPSTR); BOOL NDdeIsValidAppTopicListW(LPWSTR); UINT NDdeSetShareSecurityA(LPSTR, LPSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); UINT NDdeSetShareSecurityW(LPWSTR, LPWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); UINT NDdeSetTrustedShareA(LPSTR, LPSTR, DWORD); UINT NDdeSetTrustedShareW(LPWSTR, LPWSTR, DWORD); UINT NDdeShareAddA(LPSTR, UINT, PSECURITY_DESCRIPTOR, PBYTE, DWORD); UINT NDdeShareAddW(LPWSTR, UINT, PSECURITY_DESCRIPTOR, PBYTE, DWORD); UINT NDdeShareDelA(LPSTR, LPSTR, UINT); UINT NDdeShareDelW(LPWSTR, LPWSTR, UINT); UINT NDdeShareEnumA(LPSTR, UINT, PBYTE, DWORD, PDWORD, PDWORD); UINT NDdeShareEnumW(LPWSTR, UINT, PBYTE, DWORD, PDWORD, PDWORD); UINT NDdeShareGetInfoA(LPSTR, LPSTR, UINT, PBYTE, DWORD, PDWORD, PWORD); UINT NDdeShareGetInfoW(LPWSTR, LPWSTR, UINT, PBYTE, DWORD, PDWORD, PWORD); UINT NDdeShareSetInfoA(LPSTR, LPSTR, UINT, PBYTE, DWORD, WORD); UINT NDdeShareSetInfoW(LPWSTR, LPWSTR, UINT, PBYTE, DWORD, WORD); UINT NDdeTrustedShareEnumA(LPSTR, UINT, PBYTE, DWORD, PDWORD, PDWORD); UINT NDdeTrustedShareEnumW(LPWSTR, UINT, PBYTE, DWORD, PDWORD, PDWORD); } version (Unicode) { alias NDdeShareAddW NDdeShareAdd; alias NDdeShareDelW NDdeShareDel; alias NDdeSetShareSecurityW NDdeSetShareSecurity; alias NDdeGetShareSecurityW NDdeGetShareSecurity; alias NDdeShareEnumW NDdeShareEnum; alias NDdeShareGetInfoW NDdeShareGetInfo; alias NDdeShareSetInfoW NDdeShareSetInfo; alias NDdeGetErrorStringW NDdeGetErrorString; alias NDdeIsValidShareNameW NDdeIsValidShareName; alias NDdeIsValidAppTopicListW NDdeIsValidAppTopicList; alias NDdeSetTrustedShareW NDdeSetTrustedShare; alias NDdeGetTrustedShareW NDdeGetTrustedShare; alias NDdeTrustedShareEnumW NDdeTrustedShareEnum; } else { alias NDdeShareAddA NDdeShareAdd; alias NDdeShareDelA NDdeShareDel; alias NDdeSetShareSecurityA NDdeSetShareSecurity; alias NDdeGetShareSecurityA NDdeGetShareSecurity; alias NDdeShareEnumA NDdeShareEnum; alias NDdeShareGetInfoA NDdeShareGetInfo; alias NDdeShareSetInfoA NDdeShareSetInfo; alias NDdeGetErrorStringA NDdeGetErrorString; alias NDdeIsValidShareNameA NDdeIsValidShareName; alias NDdeIsValidAppTopicListA NDdeIsValidAppTopicList; alias NDdeSetTrustedShareA NDdeSetTrustedShare; alias NDdeGetTrustedShareA NDdeGetTrustedShare; alias NDdeTrustedShareEnumA NDdeTrustedShareEnum; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/intshcut.d0000664000175000017500000000547612776214756023534 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_intshcut.d) */ module core.sys.windows.intshcut; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.unknwn, core.sys.windows.windef; enum : SCODE { E_FLAGS = 0x80041000, // = MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x1000) URL_E_INVALID_SYNTAX = 0x80041001, // = MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x1001) URL_E_UNREGISTERED_PROTOCOL = 0x80041002, // etc. IS_E_EXEC_FAILED = 0x80042002 } enum IURL_SETURL_FLAGS { IURL_SETURL_FL_GUESS_PROTOCOL = 1, IURL_SETURL_FL_USE_DEFAULT_PROTOCOL, ALL_IURL_SETURL_FLAGS } enum IURL_INVOKECOMMAND_FLAGS { IURL_INVOKECOMMAND_FL_ALLOW_UI = 1, IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB, ALL_IURL_INVOKECOMMAND_FLAGS } enum TRANSLATEURL_IN_FLAGS { TRANSLATEURL_FL_GUESS_PROTOCOL = 1, TRANSLATEURL_FL_USE_DEFAULT_PROTOCOL, ALL_TRANSLATEURL_FLAGS } enum URLASSOCIATIONDIALOG_IN_FLAGS { URLASSOCDLG_FL_USE_DEFAULT_NAME = 1, URLASSOCDLG_FL_REGISTER_ASSOC, ALL_URLASSOCDLG_FLAGS } enum MIMEASSOCIATIONDIALOG_IN_FLAGS { MIMEASSOCDLG_FL_REGISTER_ASSOC = 1, ALL_MIMEASSOCDLG_FLAGS = MIMEASSOCDLG_FL_REGISTER_ASSOC } struct URLINVOKECOMMANDINFO { DWORD dwcbSize = URLINVOKECOMMANDINFO.sizeof; DWORD dwFlags; HWND hwndParent; PCSTR pcszVerb; } alias URLINVOKECOMMANDINFO CURLINVOKECOMMANDINFO; alias URLINVOKECOMMANDINFO* PURLINVOKECOMMANDINFO, PCURLINVOKECOMMANDINFO; interface IUniformResourceLocator : IUnknown { HRESULT SetURL(PCSTR, DWORD); HRESULT GetURL(PSTR*); HRESULT InvokeCommand(PURLINVOKECOMMANDINFO); } //alias typeof(*(IUniformResourceLocator.init)) CIUniformResourceLocator; // value-type of interface not representable in D alias IUniformResourceLocator PIUniformResourceLocator, PCIUniformResourceLocator; extern (Windows) { BOOL InetIsOffline(DWORD); HRESULT MIMEAssociationDialogA(HWND, DWORD, PCSTR, PCSTR, PSTR, UINT); HRESULT MIMEAssociationDialogW(HWND, DWORD, PCWSTR, PCWSTR, PWSTR, UINT); HRESULT TranslateURLA(PCSTR, DWORD, PSTR*); HRESULT TranslateURLW(PCWSTR, DWORD, PWSTR*); HRESULT URLAssociationDialogA(HWND, DWORD, PCSTR, PCSTR, PSTR, UINT); HRESULT URLAssociationDialogW(HWND, DWORD, PCWSTR, PCWSTR, PWSTR, UINT); } version (Unicode) { alias TranslateURLW TranslateURL; alias MIMEAssociationDialogW MIMEAssociationDialog; alias URLAssociationDialogW URLAssociationDialog; } else { alias TranslateURLA TranslateURL; alias MIMEAssociationDialogA MIMEAssociationDialog; alias URLAssociationDialogA URLAssociationDialog; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ipifcons.d0000664000175000017500000000161412776214756023473 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ipifcons.d) */ module core.sys.windows.ipifcons; version (Windows): // FIXME: check types of constants enum { MIB_IF_ADMIN_STATUS_UP = 1, MIB_IF_ADMIN_STATUS_DOWN, MIB_IF_ADMIN_STATUS_TESTING, } enum { MIB_IF_OPER_STATUS_NON_OPERATIONAL, MIB_IF_OPER_STATUS_UNREACHABLE, MIB_IF_OPER_STATUS_DISCONNECTED, MIB_IF_OPER_STATUS_CONNECTING, MIB_IF_OPER_STATUS_CONNECTED, MIB_IF_OPER_STATUS_OPERATIONAL // = 5 } enum { MIB_IF_TYPE_OTHER = 1, MIB_IF_TYPE_ETHERNET = 6, MIB_IF_TYPE_TOKENRING = 9, MIB_IF_TYPE_FDDI = 15, MIB_IF_TYPE_PPP = 23, MIB_IF_TYPE_LOOPBACK = 24, MIB_IF_TYPE_SLIP = 28 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/com.d0000664000175000017500000000555312776214756022445 0ustar kaikaimodule core.sys.windows.com; version (Windows): pragma(lib,"uuid"); import core.atomic; import core.sys.windows.windows; //import std.string; public import core.sys.windows.basetyps : GUID, IID, CLSID; public import core.sys.windows.objbase : CLSCTX_INPROC, CLSCTX_ALL, CLSCTX_SERVER, COINIT, CoBuildVersion, StringFromGUID2, CoInitialize, CoInitializeEx, CoUninitialize, CoGetCurrentProcess, CoCreateInstance, CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries; public import core.sys.windows.ole2ver : rmm, rup; public import core.sys.windows.unknwn : IUnknown, IClassFactory; public import core.sys.windows.winerror : S_OK, S_FALSE, NOERROR, E_NOTIMPL, E_NOINTERFACE, E_POINTER, E_ABORT, E_FAIL, E_HANDLE, CLASS_E_NOAGGREGATION, E_OUTOFMEMORY, E_INVALIDARG, E_UNEXPECTED, RPC_E_CHANGED_MODE; public import core.sys.windows.wtypes : OLECHAR, LPOLESTR, LPCOLESTR; alias CLSCTX_INPROC_SERVER = core.sys.windows.wtypes.CLSCTX.CLSCTX_INPROC_SERVER ; alias CLSCTX_INPROC_HANDLER = core.sys.windows.wtypes.CLSCTX.CLSCTX_INPROC_HANDLER ; alias CLSCTX_LOCAL_SERVER = core.sys.windows.wtypes.CLSCTX.CLSCTX_LOCAL_SERVER ; alias CLSCTX_INPROC_SERVER16 = core.sys.windows.wtypes.CLSCTX.CLSCTX_INPROC_SERVER16 ; alias CLSCTX_REMOTE_SERVER = core.sys.windows.wtypes.CLSCTX.CLSCTX_REMOTE_SERVER ; alias CLSCTX_INPROC_HANDLER16 = core.sys.windows.wtypes.CLSCTX.CLSCTX_INPROC_HANDLER16 ; alias CLSCTX_INPROC_SERVERX86 = core.sys.windows.wtypes.CLSCTX.CLSCTX_INPROC_SERVERX86 ; alias CLSCTX_INPROC_HANDLERX86 = core.sys.windows.wtypes.CLSCTX.CLSCTX_INPROC_HANDLERX86; alias COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED; alias COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED ; alias COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE ; alias COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY; public import core.sys.windows.uuid; extern (System) { class ComObject : IUnknown { extern (System): HRESULT QueryInterface(const(IID)* riid, void** ppv) { if (*riid == IID_IUnknown) { *ppv = cast(void*)cast(IUnknown)this; AddRef(); return S_OK; } else { *ppv = null; return E_NOINTERFACE; } } ULONG AddRef() { return atomicOp!"+="(*cast(shared)&count, 1); } ULONG Release() { LONG lRef = atomicOp!"-="(*cast(shared)&count, 1); if (lRef == 0) { // free object // If we delete this object, then the postinvariant called upon // return from Release() will fail. // Just let the GC reap it. //delete this; return 0; } return cast(ULONG)lRef; } LONG count = 0; // object reference count } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winnt.d0000664000175000017500000036531512776214756023033 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.12 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winnt.d) */ module core.sys.windows.winnt; version (Windows): version (ANSI) {} else version = Unicode; public import core.sys.windows.basetsd, core.sys.windows.windef, core.sys.windows.winerror; private import core.sys.windows.w32api; /* Translation Notes: The following macros are unneeded for D: FIELD_OFFSET(t,f), CONTAINING_RECORD(address, type, field) */ alias void VOID; alias char CHAR, CCHAR; alias wchar WCHAR; alias bool BOOLEAN; alias byte FCHAR; alias ubyte UCHAR; alias short SHORT; alias ushort LANGID, FSHORT; alias uint LCID, FLONG, ACCESS_MASK; alias long LONGLONG, USN; alias ulong DWORDLONG, ULONGLONG; alias void* PVOID, LPVOID; alias char* PSZ, PCHAR, PCCHAR, LPCH, PCH, LPSTR, PSTR; alias wchar* PWCHAR, LPWCH, PWCH, LPWSTR, PWSTR; alias bool* PBOOLEAN; alias ubyte* PUCHAR; alias short* PSHORT; alias int* PLONG; alias uint* PLCID, PACCESS_MASK; alias long* PLONGLONG; alias ulong* PDWORDLONG, PULONGLONG; // FIXME(MinGW) for __WIN64 alias void* PVOID64; // const versions alias const(char)* PCCH, LPCCH, PCSTR, LPCSTR; alias const(wchar)* LPCWCH, PCWCH, LPCWSTR, PCWSTR; version (Unicode) { alias WCHAR TCHAR, _TCHAR; } else { alias CHAR TCHAR, _TCHAR; } alias TCHAR TBYTE; alias TCHAR* PTCH , PTBYTE, LPTCH , PTSTR , LPTSTR , LP, PTCHAR; alias const(TCHAR)* PCTCH, LPCTCH, PCTSTR, LPCTSTR ; enum char ANSI_NULL = '\0'; enum wchar UNICODE_NULL = '\0'; enum APPLICATION_ERROR_MASK = 0x20000000; enum ERROR_SEVERITY_SUCCESS = 0x00000000; enum ERROR_SEVERITY_INFORMATIONAL = 0x40000000; enum ERROR_SEVERITY_WARNING = 0x80000000; enum ERROR_SEVERITY_ERROR = 0xC0000000; // MinGW: also in ddk/ntifs.h enum : USHORT { COMPRESSION_FORMAT_NONE = 0x0000, COMPRESSION_FORMAT_DEFAULT = 0x0001, COMPRESSION_FORMAT_LZNT1 = 0x0002, COMPRESSION_ENGINE_STANDARD = 0x0000, COMPRESSION_ENGINE_MAXIMUM = 0x0100, COMPRESSION_ENGINE_HIBER = 0x0200 } // ACCESS_DENIED_OBJECT_ACE, etc enum DWORD ACE_OBJECT_TYPE_PRESENT = 0x00000001, ACE_INHERITED_OBJECT_TYPE_PRESENT = 0x00000002; // ACE_HEADER.AceType // also in ddk/ntifs.h enum : BYTE { ACCESS_ALLOWED_ACE_TYPE, ACCESS_DENIED_ACE_TYPE, SYSTEM_AUDIT_ACE_TYPE, SYSTEM_ALARM_ACE_TYPE } // ACE_HEADER.AceFlags enum BYTE OBJECT_INHERIT_ACE = 0x01, CONTAINER_INHERIT_ACE = 0x02, NO_PROPAGATE_INHERIT_ACE = 0x04, INHERIT_ONLY_ACE = 0x08, INHERITED_ACE = 0x10, VALID_INHERIT_FLAGS = 0x1F, SUCCESSFUL_ACCESS_ACE_FLAG = 0x40, FAILED_ACCESS_ACE_FLAG = 0x80; // Access Mask Format enum ACCESS_MASK DELETE = 0x00010000, READ_CONTROL = 0x00020000, WRITE_DAC = 0x00040000, WRITE_OWNER = 0x00080000, SYNCHRONIZE = 0x00100000, ACCESS_SYSTEM_SECURITY = 0x01000000, MAXIMUM_ALLOWED = 0x02000000, GENERIC_READ = 0x80000000, GENERIC_WRITE = 0x40000000, GENERIC_EXECUTE = 0x20000000, GENERIC_ALL = 0x10000000, STANDARD_RIGHTS_REQUIRED = 0x000F0000, STANDARD_RIGHTS_READ = 0x00020000, STANDARD_RIGHTS_WRITE = 0x00020000, STANDARD_RIGHTS_EXECUTE = 0x00020000, STANDARD_RIGHTS_ALL = 0x001F0000, SPECIFIC_RIGHTS_ALL = 0x0000FFFF; enum DWORD INVALID_FILE_ATTRIBUTES = -1; // MinGW: Also in ddk/winddk.h enum DWORD FILE_LIST_DIRECTORY = 0x00000001, FILE_READ_DATA = 0x00000001, FILE_ADD_FILE = 0x00000002, FILE_WRITE_DATA = 0x00000002, FILE_ADD_SUBDIRECTORY = 0x00000004, FILE_APPEND_DATA = 0x00000004, FILE_CREATE_PIPE_INSTANCE = 0x00000004, FILE_READ_EA = 0x00000008, FILE_READ_PROPERTIES = 0x00000008, FILE_WRITE_EA = 0x00000010, FILE_WRITE_PROPERTIES = 0x00000010, FILE_EXECUTE = 0x00000020, FILE_TRAVERSE = 0x00000020, FILE_DELETE_CHILD = 0x00000040, FILE_READ_ATTRIBUTES = 0x00000080, FILE_WRITE_ATTRIBUTES = 0x00000100; enum DWORD FILE_SHARE_READ = 0x00000001, FILE_SHARE_WRITE = 0x00000002, FILE_SHARE_DELETE = 0x00000004, FILE_SHARE_VALID_FLAGS = 0x00000007; enum DWORD FILE_ATTRIBUTE_READONLY = 0x00000001, FILE_ATTRIBUTE_HIDDEN = 0x00000002, FILE_ATTRIBUTE_SYSTEM = 0x00000004, FILE_ATTRIBUTE_DIRECTORY = 0x00000010, FILE_ATTRIBUTE_ARCHIVE = 0x00000020, FILE_ATTRIBUTE_DEVICE = 0x00000040, FILE_ATTRIBUTE_NORMAL = 0x00000080, FILE_ATTRIBUTE_TEMPORARY = 0x00000100, FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200, FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400, FILE_ATTRIBUTE_COMPRESSED = 0x00000800, FILE_ATTRIBUTE_OFFLINE = 0x00001000, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000, FILE_ATTRIBUTE_ENCRYPTED = 0x00004000, FILE_ATTRIBUTE_VALID_FLAGS = 0x00007fb7, FILE_ATTRIBUTE_VALID_SET_FLAGS = 0x000031a7; // These are not documented on MSDN enum FILE_COPY_STRUCTURED_STORAGE = 0x00000041; enum FILE_STRUCTURED_STORAGE = 0x00000441; // Nor are these enum FILE_VALID_OPTION_FLAGS = 0x00ffffff; enum FILE_VALID_PIPE_OPTION_FLAGS = 0x00000032; enum FILE_VALID_MAILSLOT_OPTION_FLAGS = 0x00000032; enum FILE_VALID_SET_FLAGS = 0x00000036; enum ULONG FILE_SUPERSEDE = 0x00000000, FILE_OPEN = 0x00000001, FILE_CREATE = 0x00000002, FILE_OPEN_IF = 0x00000003, FILE_OVERWRITE = 0x00000004, FILE_OVERWRITE_IF = 0x00000005, FILE_MAXIMUM_DISPOSITION = 0x00000005; enum ULONG FILE_DIRECTORY_FILE = 0x00000001, FILE_WRITE_THROUGH = 0x00000002, FILE_SEQUENTIAL_ONLY = 0x00000004, FILE_NO_INTERMEDIATE_BUFFERING = 0x00000008, FILE_SYNCHRONOUS_IO_ALERT = 0x00000010, FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020, FILE_NON_DIRECTORY_FILE = 0x00000040, FILE_CREATE_TREE_CONNECTION = 0x00000080, FILE_COMPLETE_IF_OPLOCKED = 0x00000100, FILE_NO_EA_KNOWLEDGE = 0x00000200, FILE_OPEN_FOR_RECOVERY = 0x00000400, FILE_RANDOM_ACCESS = 0x00000800, FILE_DELETE_ON_CLOSE = 0x00001000, FILE_OPEN_BY_FILE_ID = 0x00002000, FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000, FILE_NO_COMPRESSION = 0x00008000, FILE_RESERVE_OPFILTER = 0x00100000, FILE_OPEN_REPARSE_POINT = 0x00200000, FILE_OPEN_NO_RECALL = 0x00400000, FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000; enum ACCESS_MASK FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x01FF, FILE_GENERIC_EXECUTE = STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE, FILE_GENERIC_READ = STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE, FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE; // MinGW: end winddk.h // MinGW: also in ddk/ntifs.h enum DWORD FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001, FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002, FILE_NOTIFY_CHANGE_NAME = 0x00000003, FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004, FILE_NOTIFY_CHANGE_SIZE = 0x00000008, FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010, FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020, FILE_NOTIFY_CHANGE_CREATION = 0x00000040, FILE_NOTIFY_CHANGE_EA = 0x00000080, FILE_NOTIFY_CHANGE_SECURITY = 0x00000100, FILE_NOTIFY_CHANGE_STREAM_NAME = 0x00000200, FILE_NOTIFY_CHANGE_STREAM_SIZE = 0x00000400, FILE_NOTIFY_CHANGE_STREAM_WRITE = 0x00000800, FILE_NOTIFY_VALID_MASK = 0x00000fff; enum DWORD FILE_CASE_SENSITIVE_SEARCH = 0x00000001, FILE_CASE_PRESERVED_NAMES = 0x00000002, FILE_UNICODE_ON_DISK = 0x00000004, FILE_PERSISTENT_ACLS = 0x00000008, FILE_FILE_COMPRESSION = 0x00000010, FILE_VOLUME_QUOTAS = 0x00000020, FILE_SUPPORTS_SPARSE_FILES = 0x00000040, FILE_SUPPORTS_REPARSE_POINTS = 0x00000080, FILE_SUPPORTS_REMOTE_STORAGE = 0x00000100, FS_LFN_APIS = 0x00004000, FILE_VOLUME_IS_COMPRESSED = 0x00008000, FILE_SUPPORTS_OBJECT_IDS = 0x00010000, FILE_SUPPORTS_ENCRYPTION = 0x00020000, FILE_NAMED_STREAMS = 0x00040000, FILE_READ_ONLY_VOLUME = 0x00080000, FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000, FILE_SUPPORTS_TRANSACTIONS = 0x00200000; // These are not documented on MSDN enum ACCESS_MASK IO_COMPLETION_QUERY_STATE = 1, IO_COMPLETION_MODIFY_STATE = 2, IO_COMPLETION_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 3; // MinGW: end ntifs.h // MinGW: also in ddk/winddk.h enum DWORD DUPLICATE_CLOSE_SOURCE = 1, DUPLICATE_SAME_ACCESS = 2, DUPLICATE_SAME_ATTRIBUTES = 4; // MinGW: end winddk.k enum DWORD MAILSLOT_NO_MESSAGE = -1, MAILSLOT_WAIT_FOREVER = -1; enum ACCESS_MASK PROCESS_TERMINATE = 0x0001, PROCESS_CREATE_THREAD = 0x0002, PROCESS_SET_SESSIONID = 0x0004, PROCESS_VM_OPERATION = 0x0008, PROCESS_VM_READ = 0x0010, PROCESS_VM_WRITE = 0x0020, PROCESS_DUP_HANDLE = 0x0040, PROCESS_CREATE_PROCESS = 0x0080, PROCESS_SET_QUOTA = 0x0100, PROCESS_SET_INFORMATION = 0x0200, PROCESS_QUERY_INFORMATION = 0x0400, PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x0FFF; enum ACCESS_MASK THREAD_TERMINATE = 0x0001, THREAD_SUSPEND_RESUME = 0x0002, THREAD_GET_CONTEXT = 0x0008, THREAD_SET_CONTEXT = 0x0010, THREAD_SET_INFORMATION = 0x0020, THREAD_QUERY_INFORMATION = 0x0040, THREAD_SET_THREAD_TOKEN = 0x0080, THREAD_IMPERSONATE = 0x0100, THREAD_DIRECT_IMPERSONATION = 0x0200, THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3FF; // These are not documented on MSDN enum THREAD_BASE_PRIORITY_LOWRT = 15; enum THREAD_BASE_PRIORITY_MAX = 2; enum THREAD_BASE_PRIORITY_MIN = -2; enum THREAD_BASE_PRIORITY_IDLE = -15; enum DWORD EXCEPTION_NONCONTINUABLE = 1; enum size_t EXCEPTION_MAXIMUM_PARAMETERS = 15; // These are not documented on MSDN enum ACCESS_MASK MUTANT_QUERY_STATE = 1, MUTANT_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | MUTANT_QUERY_STATE; enum ACCESS_MASK TIMER_QUERY_STATE = 1, TIMER_MODIFY_STATE = 2, TIMER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | TIMER_QUERY_STATE | TIMER_MODIFY_STATE; enum SID_IDENTIFIER_AUTHORITY SECURITY_NULL_SID_AUTHORITY = {[5: 0]}, SECURITY_WORLD_SID_AUTHORITY = {[5: 1]}, SECURITY_LOCAL_SID_AUTHORITY = {[5: 2]}, SECURITY_CREATOR_SID_AUTHORITY = {[5: 3]}, SECURITY_NON_UNIQUE_AUTHORITY = {[5: 4]}, SECURITY_NT_AUTHORITY = {[5: 5]}, SECURITY_MANDATORY_LABEL_AUTHORITY = {[5: 6]}; enum DWORD SECURITY_NULL_RID = 0, SECURITY_WORLD_RID = 0, SECURITY_LOCAL_RID = 0, SECURITY_CREATOR_OWNER_RID = 0, SECURITY_CREATOR_GROUP_RID = 1, SECURITY_DIALUP_RID = 1, SECURITY_NETWORK_RID = 2, SECURITY_BATCH_RID = 3, SECURITY_INTERACTIVE_RID = 4, SECURITY_LOGON_IDS_RID = 5, SECURITY_SERVICE_RID = 6, SECURITY_LOCAL_SYSTEM_RID = 18, SECURITY_BUILTIN_DOMAIN_RID = 32, SECURITY_PRINCIPAL_SELF_RID = 10, SECURITY_CREATOR_OWNER_SERVER_RID = 2, SECURITY_CREATOR_GROUP_SERVER_RID = 3, SECURITY_LOGON_IDS_RID_COUNT = 3, SECURITY_ANONYMOUS_LOGON_RID = 7, SECURITY_PROXY_RID = 8, SECURITY_ENTERPRISE_CONTROLLERS_RID = 9, SECURITY_SERVER_LOGON_RID = SECURITY_ENTERPRISE_CONTROLLERS_RID, SECURITY_AUTHENTICATED_USER_RID = 11, SECURITY_RESTRICTED_CODE_RID = 12, SECURITY_NT_NON_UNIQUE_RID = 21, SID_REVISION = 1; enum : DWORD { DOMAIN_USER_RID_ADMIN = 0x01F4, DOMAIN_USER_RID_GUEST = 0x01F5, DOMAIN_GROUP_RID_ADMINS = 0x0200, DOMAIN_GROUP_RID_USERS = 0x0201, DOMAIN_ALIAS_RID_ADMINS = 0x0220, DOMAIN_ALIAS_RID_USERS = 0x0221, DOMAIN_ALIAS_RID_GUESTS = 0x0222, DOMAIN_ALIAS_RID_POWER_USERS = 0x0223, DOMAIN_ALIAS_RID_ACCOUNT_OPS = 0x0224, DOMAIN_ALIAS_RID_SYSTEM_OPS = 0x0225, DOMAIN_ALIAS_RID_PRINT_OPS = 0x0226, DOMAIN_ALIAS_RID_BACKUP_OPS = 0x0227, DOMAIN_ALIAS_RID_REPLICATOR = 0x0228 } enum : WORD { SECURITY_MANDATORY_UNTRUSTED_RID = 0, SECURITY_MANDATORY_LOW_RID = 0x1000, SECURITY_MANDATORY_MEDIUM_RID = 0x2000, SECURITY_MANDATORY_HIGH_RID = 0x3000, SECURITY_MANDATORY_SYSTEM_RID = 0x4000, SECURITY_MANDATORY_PROTECTED_PROCESS_RID = 0x5000, SECURITY_MANDATORY_MAXIMUM_USER_RID = SECURITY_MANDATORY_SYSTEM_RID } const TCHAR[] SE_CREATE_TOKEN_NAME = "SeCreateTokenPrivilege", SE_ASSIGNPRIMARYTOKEN_NAME = "SeAssignPrimaryTokenPrivilege", SE_LOCK_MEMORY_NAME = "SeLockMemoryPrivilege", SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege", SE_UNSOLICITED_INPUT_NAME = "SeUnsolicitedInputPrivilege", SE_MACHINE_ACCOUNT_NAME = "SeMachineAccountPrivilege", SE_TCB_NAME = "SeTcbPrivilege", SE_SECURITY_NAME = "SeSecurityPrivilege", SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege", SE_LOAD_DRIVER_NAME = "SeLoadDriverPrivilege", SE_SYSTEM_PROFILE_NAME = "SeSystemProfilePrivilege", SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege", SE_PROF_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege", SE_INC_BASE_PRIORITY_NAME = "SeIncreaseBasePriorityPrivilege", SE_CREATE_PAGEFILE_NAME = "SeCreatePagefilePrivilege", SE_CREATE_PERMANENT_NAME = "SeCreatePermanentPrivilege", SE_BACKUP_NAME = "SeBackupPrivilege", SE_RESTORE_NAME = "SeRestorePrivilege", SE_SHUTDOWN_NAME = "SeShutdownPrivilege", SE_DEBUG_NAME = "SeDebugPrivilege", SE_AUDIT_NAME = "SeAuditPrivilege", SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege", SE_CHANGE_NOTIFY_NAME = "SeChangeNotifyPrivilege", SE_REMOTE_SHUTDOWN_NAME = "SeRemoteShutdownPrivilege", SE_CREATE_GLOBAL_NAME = "SeCreateGlobalPrivilege", SE_UNDOCK_NAME = "SeUndockPrivilege", SE_MANAGE_VOLUME_NAME = "SeManageVolumePrivilege", SE_IMPERSONATE_NAME = "SeImpersonatePrivilege", SE_ENABLE_DELEGATION_NAME = "SeEnableDelegationPrivilege", SE_SYNC_AGENT_NAME = "SeSyncAgentPrivilege", SE_TRUSTED_CREDMAN_ACCESS_NAME = "SeTrustedCredManAccessPrivilege", SE_RELABEL_NAME = "SeRelabelPrivilege", SE_INCREASE_WORKING_SET_NAME = "SeIncreaseWorkingSetPrivilege", SE_TIME_ZONE_NAME = "SeTimeZonePrivilege", SE_CREATE_SYMBOLIC_LINK_NAME = "SeCreateSymbolicLinkPrivilege"; enum DWORD SE_GROUP_MANDATORY = 0x00000001, SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002, SE_GROUP_ENABLED = 0x00000004, SE_GROUP_OWNER = 0x00000008, SE_GROUP_USE_FOR_DENY_ONLY = 0x00000010, SE_GROUP_INTEGRITY = 0x00000020, SE_GROUP_INTEGRITY_ENABLED = 0x00000040, SE_GROUP_RESOURCE = 0x20000000, SE_GROUP_LOGON_ID = 0xC0000000; // Primary language identifiers enum : USHORT { LANG_NEUTRAL, LANG_ARABIC, LANG_BULGARIAN, LANG_CATALAN, LANG_CHINESE, LANG_CZECH, LANG_DANISH, LANG_GERMAN, LANG_GREEK, LANG_ENGLISH, LANG_SPANISH, LANG_FINNISH, LANG_FRENCH, LANG_HEBREW, LANG_HUNGARIAN, LANG_ICELANDIC, LANG_ITALIAN, LANG_JAPANESE, LANG_KOREAN, LANG_DUTCH, LANG_NORWEGIAN, LANG_POLISH, LANG_PORTUGUESE, // = 0x16 LANG_ROMANIAN = 0x18, LANG_RUSSIAN, LANG_CROATIAN, // = 0x1A LANG_SERBIAN = 0x1A, LANG_BOSNIAN = 0x1A, LANG_SLOVAK, LANG_ALBANIAN, LANG_SWEDISH, LANG_THAI, LANG_TURKISH, LANG_URDU, LANG_INDONESIAN, LANG_UKRAINIAN, LANG_BELARUSIAN, LANG_SLOVENIAN, LANG_ESTONIAN, LANG_LATVIAN, LANG_LITHUANIAN, // = 0x27 LANG_FARSI = 0x29, LANG_PERSIAN = 0x29, LANG_VIETNAMESE, LANG_ARMENIAN, LANG_AZERI, LANG_BASQUE, LANG_LOWER_SORBIAN, // = 0x2E LANG_UPPER_SORBIAN = 0x2E, LANG_MACEDONIAN, // = 0x2F LANG_TSWANA = 0x32, LANG_XHOSA = 0x34, LANG_ZULU, LANG_AFRIKAANS, LANG_GEORGIAN, LANG_FAEROESE, LANG_HINDI, LANG_MALTESE, LANG_SAMI, LANG_IRISH, // = 0x3C LANG_MALAY = 0x3E, LANG_KAZAK, LANG_KYRGYZ, LANG_SWAHILI, // = 0x41 LANG_UZBEK = 0x43, LANG_TATAR, LANG_BENGALI, LANG_PUNJABI, LANG_GUJARATI, LANG_ORIYA, LANG_TAMIL, LANG_TELUGU, LANG_KANNADA, LANG_MALAYALAM, LANG_ASSAMESE, LANG_MARATHI, LANG_SANSKRIT, LANG_MONGOLIAN, LANG_TIBETAN, LANG_WELSH, LANG_KHMER, LANG_LAO, // = 0x54 LANG_GALICIAN = 0x56, LANG_KONKANI, LANG_MANIPURI, LANG_SINDHI, LANG_SYRIAC, LANG_SINHALESE, // = 0x5B LANG_INUKTITUT = 0x5D, LANG_AMHARIC, LANG_TAMAZIGHT, LANG_KASHMIRI, LANG_NEPALI, LANG_FRISIAN, LANG_PASHTO, LANG_FILIPINO, LANG_DIVEHI, // = 0x65 LANG_HAUSA = 0x68, LANG_YORUBA = 0x6A, LANG_QUECHUA, LANG_SOTHO, LANG_BASHKIR, LANG_LUXEMBOURGISH, LANG_GREENLANDIC, LANG_IGBO, // = 0x70 LANG_TIGRIGNA = 0x73, LANG_YI = 0x78, LANG_MAPUDUNGUN = 0x7A, LANG_MOHAWK = 0x7C, LANG_BRETON = 0x7E, LANG_UIGHUR = 0x80, LANG_MAORI, LANG_OCCITAN, LANG_CORSICAN, LANG_ALSATIAN, LANG_YAKUT, LANG_KICHE, LANG_KINYARWANDA, LANG_WOLOF, // = 0x88 LANG_DARI = 0x8C, LANG_MALAGASY, // = 0x8D LANG_SERBIAN_NEUTRAL = 0x7C1A, LANG_BOSNIAN_NEUTRAL = 0x781A, LANG_INVARIANT = 0x7F } // Sublanguage identifiers enum : USHORT { SUBLANG_NEUTRAL, SUBLANG_DEFAULT, SUBLANG_SYS_DEFAULT, SUBLANG_CUSTOM_DEFAULT, // = 3 SUBLANG_UI_CUSTOM_DEFAULT = 3, SUBLANG_CUSTOM_UNSPECIFIED, // = 4 SUBLANG_AFRIKAANS_SOUTH_AFRICA = 1, SUBLANG_ALBANIAN_ALBANIA = 1, SUBLANG_ALSATIAN_FRANCE = 1, SUBLANG_AMHARIC_ETHIOPIA = 1, SUBLANG_ARABIC_SAUDI_ARABIA = 1, SUBLANG_ARABIC_IRAQ, SUBLANG_ARABIC_EGYPT, SUBLANG_ARABIC_LIBYA, SUBLANG_ARABIC_ALGERIA, SUBLANG_ARABIC_MOROCCO, SUBLANG_ARABIC_TUNISIA, SUBLANG_ARABIC_OMAN, SUBLANG_ARABIC_YEMEN, SUBLANG_ARABIC_SYRIA, SUBLANG_ARABIC_JORDAN, SUBLANG_ARABIC_LEBANON, SUBLANG_ARABIC_KUWAIT, SUBLANG_ARABIC_UAE, SUBLANG_ARABIC_BAHRAIN, SUBLANG_ARABIC_QATAR, // = 16 SUBLANG_ARMENIAN_ARMENIA = 1, SUBLANG_ASSAMESE_INDIA = 1, SUBLANG_AZERI_LATIN = 1, SUBLANG_AZERI_CYRILLIC, // = 2 SUBLANG_BASHKIR_RUSSIA = 1, SUBLANG_BASQUE_BASQUE = 1, SUBLANG_BELARUSIAN_BELARUS = 1, SUBLANG_BENGALI_INDIA = 1, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN = 5, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC = 8, SUBLANG_BRETON_FRANCE = 1, SUBLANG_BULGARIAN_BULGARIA = 1, SUBLANG_CATALAN_CATALAN = 1, SUBLANG_CHINESE_TRADITIONAL = 1, SUBLANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_HONGKONG, SUBLANG_CHINESE_SINGAPORE, SUBLANG_CHINESE_MACAU, // = 5 SUBLANG_CORSICAN_FRANCE = 1, SUBLANG_CROATIAN_CROATIA = 1, SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN = 4, SUBLANG_CZECH_CZECH_REPUBLIC = 1, SUBLANG_DANISH_DENMARK = 1, SUBLANG_DIVEHI_MALDIVES = 1, SUBLANG_DUTCH = 1, SUBLANG_DUTCH_BELGIAN, // = 2 SUBLANG_ENGLISH_US = 1, SUBLANG_ENGLISH_UK, SUBLANG_ENGLISH_AUS, SUBLANG_ENGLISH_CAN, SUBLANG_ENGLISH_NZ, SUBLANG_ENGLISH_EIRE, // = 6 SUBLANG_ENGLISH_IRELAND = 6, SUBLANG_ENGLISH_SOUTH_AFRICA, SUBLANG_ENGLISH_JAMAICA, SUBLANG_ENGLISH_CARIBBEAN, SUBLANG_ENGLISH_BELIZE, SUBLANG_ENGLISH_TRINIDAD, SUBLANG_ENGLISH_ZIMBABWE, SUBLANG_ENGLISH_PHILIPPINES, // = 13 SUBLANG_ENGLISH_INDIA = 16, SUBLANG_ENGLISH_MALAYSIA, SUBLANG_ENGLISH_SINGAPORE, // = 18 SUBLANG_ESTONIAN_ESTONIA = 1, SUBLANG_FAEROESE_FAROE_ISLANDS = 1, SUBLANG_FILIPINO_PHILIPPINES = 1, SUBLANG_FINNISH_FINLAND = 1, SUBLANG_FRENCH = 1, SUBLANG_FRENCH_BELGIAN, SUBLANG_FRENCH_CANADIAN, SUBLANG_FRENCH_SWISS, SUBLANG_FRENCH_LUXEMBOURG, SUBLANG_FRENCH_MONACO, // = 6 SUBLANG_FRISIAN_NETHERLANDS = 1, SUBLANG_GALICIAN_GALICIAN = 1, SUBLANG_GEORGIAN_GEORGIA = 1, SUBLANG_GERMAN = 1, SUBLANG_GERMAN_SWISS, SUBLANG_GERMAN_AUSTRIAN, SUBLANG_GERMAN_LUXEMBOURG, SUBLANG_GERMAN_LIECHTENSTEIN, // = 5 SUBLANG_GREEK_GREECE = 1, SUBLANG_GREENLANDIC_GREENLAND = 1, SUBLANG_GUJARATI_INDIA = 1, SUBLANG_HAUSA_NIGERIA = 1, SUBLANG_HEBREW_ISRAEL = 1, SUBLANG_HINDI_INDIA = 1, SUBLANG_HUNGARIAN_HUNGARY = 1, SUBLANG_ICELANDIC_ICELAND = 1, SUBLANG_IGBO_NIGERIA = 1, SUBLANG_INDONESIAN_INDONESIA = 1, SUBLANG_INUKTITUT_CANADA = 1, SUBLANG_INUKTITUT_CANADA_LATIN = 1, SUBLANG_IRISH_IRELAND = 1, SUBLANG_ITALIAN = 1, SUBLANG_ITALIAN_SWISS, // = 2 SUBLANG_JAPANESE_JAPAN = 1, SUBLANG_KASHMIRI_INDIA = 2, SUBLANG_KASHMIRI_SASIA = 2, SUBLANG_KAZAK_KAZAKHSTAN = 1, SUBLANG_KHMER_CAMBODIA = 1, SUBLANG_KICHE_GUATEMALA = 1, SUBLANG_KINYARWANDA_RWANDA = 1, SUBLANG_KONKANI_INDIA = 1, SUBLANG_KOREAN = 1, SUBLANG_KOREAN_JOHAB = 2, SUBLANG_KYRGYZ_KYRGYZSTAN = 1, SUBLANG_LAO_LAO_PDR = 1, SUBLANG_LATVIAN_LATVIA = 1, SUBLANG_LITHUANIAN = 1, SUBLANG_LITHUANIAN_LITHUANIA = 1, SUBLANG_LOWER_SORBIAN_GERMANY = 1, SUBLANG_LUXEMBOURGISH_LUXEMBOURG = 1, SUBLANG_MACEDONIAN_MACEDONIA = 1, SUBLANG_MALAYALAM_INDIA = 1, SUBLANG_MALTESE_MALTA = 1, SUBLANG_MAORI_NEW_ZEALAND = 1, SUBLANG_MAPUDUNGUN_CHILE = 1, SUBLANG_MARATHI_INDIA = 1, SUBLANG_MOHAWK_MOHAWK = 1, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA = 1, SUBLANG_MONGOLIAN_PRC, // = 2 SUBLANG_MALAY_MALAYSIA = 1, SUBLANG_MALAY_BRUNEI_DARUSSALAM, // = 2 SUBLANG_NEPALI_NEPAL = 1, SUBLANG_NEPALI_INDIA, // = 2 SUBLANG_NORWEGIAN_BOKMAL = 1, SUBLANG_NORWEGIAN_NYNORSK, // = 2 SUBLANG_OCCITAN_FRANCE = 1, SUBLANG_ORIYA_INDIA = 1, SUBLANG_PASHTO_AFGHANISTAN = 1, SUBLANG_PERSIAN_IRAN = 1, SUBLANG_POLISH_POLAND = 1, SUBLANG_PORTUGUESE_BRAZILIAN = 1, SUBLANG_PORTUGUESE = 2, SUBLANG_PORTUGUESE_PORTUGAL, // = 2 SUBLANG_PUNJABI_INDIA = 1, SUBLANG_QUECHUA_BOLIVIA = 1, SUBLANG_QUECHUA_ECUADOR, SUBLANG_QUECHUA_PERU, // = 3 SUBLANG_ROMANIAN_ROMANIA = 1, SUBLANG_ROMANSH_SWITZERLAND = 1, SUBLANG_RUSSIAN_RUSSIA = 1, SUBLANG_SAMI_NORTHERN_NORWAY = 1, SUBLANG_SAMI_NORTHERN_SWEDEN, SUBLANG_SAMI_NORTHERN_FINLAND, // = 3 SUBLANG_SAMI_SKOLT_FINLAND = 3, SUBLANG_SAMI_INARI_FINLAND = 3, SUBLANG_SAMI_LULE_NORWAY, SUBLANG_SAMI_LULE_SWEDEN, SUBLANG_SAMI_SOUTHERN_NORWAY, SUBLANG_SAMI_SOUTHERN_SWEDEN, // = 7 SUBLANG_SANSKRIT_INDIA = 1, SUBLANG_SERBIAN_LATIN = 2, SUBLANG_SERBIAN_CYRILLIC, // = 3 SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN = 6, SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC = 7, SUBLANG_SINDHI_AFGHANISTAN = 2, SUBLANG_SINHALESE_SRI_LANKA = 1, SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA = 1, SUBLANG_SLOVAK_SLOVAKIA = 1, SUBLANG_SLOVENIAN_SLOVENIA = 1, SUBLANG_SPANISH = 1, SUBLANG_SPANISH_MEXICAN, SUBLANG_SPANISH_MODERN, SUBLANG_SPANISH_GUATEMALA, SUBLANG_SPANISH_COSTA_RICA, SUBLANG_SPANISH_PANAMA, SUBLANG_SPANISH_DOMINICAN_REPUBLIC, SUBLANG_SPANISH_VENEZUELA, SUBLANG_SPANISH_COLOMBIA, SUBLANG_SPANISH_PERU, SUBLANG_SPANISH_ARGENTINA, SUBLANG_SPANISH_ECUADOR, SUBLANG_SPANISH_CHILE, SUBLANG_SPANISH_URUGUAY, SUBLANG_SPANISH_PARAGUAY, SUBLANG_SPANISH_BOLIVIA, SUBLANG_SPANISH_EL_SALVADOR, SUBLANG_SPANISH_HONDURAS, SUBLANG_SPANISH_NICARAGUA, SUBLANG_SPANISH_PUERTO_RICO, SUBLANG_SPANISH_US, // = 21 SUBLANG_SWEDISH = 1, SUBLANG_SWEDISH_SWEDEN = 1, SUBLANG_SWEDISH_FINLAND, // = 2 SUBLANG_SYRIAC = 1, SUBLANG_TAJIK_TAJIKISTAN = 1, SUBLANG_TAMAZIGHT_ALGERIA_LATIN = 2, SUBLANG_TAMIL_INDIA = 1, SUBLANG_TATAR_RUSSIA = 1, SUBLANG_TELUGU_INDIA = 1, SUBLANG_THAI_THAILAND = 1, SUBLANG_TIBETAN_PRC = 1, SUBLANG_TIBETAN_BHUTAN = 2, SUBLANG_TIGRIGNA_ERITREA = 1, SUBLANG_TSWANA_SOUTH_AFRICA = 1, SUBLANG_TURKISH_TURKEY = 1, SUBLANG_TURKMEN_TURKMENISTAN = 1, SUBLANG_UIGHUR_PRC = 1, SUBLANG_UKRAINIAN_UKRAINE = 1, SUBLANG_UPPER_SORBIAN_GERMANY = 1, SUBLANG_URDU_PAKISTAN = 1, SUBLANG_URDU_INDIA, // = 2 SUBLANG_UZBEK_LATIN = 1, SUBLANG_UZBEK_CYRILLIC, // = 2 SUBLANG_VIETNAMESE_VIETNAM = 1, SUBLANG_WELSH_UNITED_KINGDOM = 1, SUBLANG_WOLOF_SENEGAL = 1, SUBLANG_YORUBA_NIGERIA = 1, SUBLANG_XHOSA_SOUTH_AFRICA = 1, SUBLANG_YAKUT_RUSSIA = 1, SUBLANG_YI_PRC = 1, SUBLANG_ZULU_SOUTH_AFRICA = 1 } // This is not documented on MSDN enum NLS_VALID_LOCALE_MASK = 1048575; // Sorting identifiers enum : WORD { SORT_DEFAULT = 0, SORT_JAPANESE_XJIS = 0, SORT_JAPANESE_UNICODE = 1, SORT_CHINESE_BIG5 = 0, SORT_CHINESE_PRCP = 0, SORT_CHINESE_UNICODE = 1, SORT_CHINESE_PRC = 2, SORT_CHINESE_BOPOMOFO = 3, SORT_KOREAN_KSC = 0, SORT_KOREAN_UNICODE = 1, SORT_GERMAN_PHONE_BOOK = 1, SORT_HUNGARIAN_DEFAULT = 0, SORT_HUNGARIAN_TECHNICAL = 1, SORT_GEORGIAN_TRADITIONAL = 0, SORT_GEORGIAN_MODERN = 1 } pure nothrow @nogc { WORD MAKELANGID(/*USHORT*/uint p, /*USHORT*/ uint s) { return cast(WORD)((s << 10) | p); } WORD PRIMARYLANGID(/*WORD*/uint lgid) { return cast(WORD)(lgid & 0x3FF); } WORD SUBLANGID(/*WORD*/uint lgid) { return cast(WORD)(lgid >>> 10); } DWORD MAKELCID(/*WORD*/uint lgid, /*WORD*/uint srtid) { return (cast(DWORD) srtid << 16) | cast(DWORD) lgid; } // ??? //DWORD MAKESORTLCID(WORD lgid, WORD srtid, WORD ver) { return (MAKELCID(lgid, srtid)) | ((cast(DWORD)ver) << 20); } WORD LANGIDFROMLCID(LCID lcid) { return cast(WORD) lcid; } WORD SORTIDFROMLCID(LCID lcid) { return cast(WORD) ((lcid >>> 16) & 0x0F); } WORD SORTVERSIONFROMLCID(LCID lcid) { return cast(WORD) ((lcid >>> 20) & 0x0F); } } enum WORD LANG_SYSTEM_DEFAULT = (SUBLANG_SYS_DEFAULT << 10) | LANG_NEUTRAL; enum WORD LANG_USER_DEFAULT = (SUBLANG_DEFAULT << 10) | LANG_NEUTRAL; enum DWORD LOCALE_NEUTRAL = (SORT_DEFAULT << 16) | (SUBLANG_NEUTRAL << 10) | LANG_NEUTRAL; // --- enum : BYTE { ACL_REVISION = 2, ACL_REVISION_DS = 4 } // These are not documented on MSDN enum : BYTE { ACL_REVISION1 = 1, ACL_REVISION2, ACL_REVISION3, ACL_REVISION4 // = 4 } enum BYTE MIN_ACL_REVISION = 2, MAX_ACL_REVISION = 4; /+ // These aren't necessary for D. enum MINCHAR=0x80; enum MAXCHAR=0x7f; enum MINSHORT=0x8000; enum MAXSHORT=0x7fff; enum MINLONG=0x80000000; enum MAXLONG=0x7fffffff; enum MAXBYTE=0xff; enum MAXWORD=0xffff; enum MAXDWORD=0xffffffff; +/ // SYSTEM_INFO.dwProcessorType enum : DWORD { PROCESSOR_INTEL_386 = 386, PROCESSOR_INTEL_486 = 486, PROCESSOR_INTEL_PENTIUM = 586, PROCESSOR_MIPS_R4000 = 4000, PROCESSOR_ALPHA_21064 = 21064, PROCESSOR_INTEL_IA64 = 2200 } // SYSTEM_INFO.wProcessorArchitecture enum : WORD { PROCESSOR_ARCHITECTURE_INTEL, PROCESSOR_ARCHITECTURE_MIPS, PROCESSOR_ARCHITECTURE_ALPHA, PROCESSOR_ARCHITECTURE_PPC, PROCESSOR_ARCHITECTURE_SHX, PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARCHITECTURE_IA64, PROCESSOR_ARCHITECTURE_ALPHA64, PROCESSOR_ARCHITECTURE_MSIL, PROCESSOR_ARCHITECTURE_AMD64, PROCESSOR_ARCHITECTURE_IA32_ON_WIN64, // = 10 PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF } // IsProcessorFeaturePresent() enum : DWORD { PF_FLOATING_POINT_PRECISION_ERRATA, PF_FLOATING_POINT_EMULATED, PF_COMPARE_EXCHANGE_DOUBLE, PF_MMX_INSTRUCTIONS_AVAILABLE, PF_PPC_MOVEMEM_64BIT_OK, PF_ALPHA_BYTE_INSTRUCTIONS, PF_XMMI_INSTRUCTIONS_AVAILABLE, PF_3DNOW_INSTRUCTIONS_AVAILABLE, PF_RDTSC_INSTRUCTION_AVAILABLE, PF_PAE_ENABLED, PF_XMMI64_INSTRUCTIONS_AVAILABLE } // MinGW: also in ddk/ntifs.h enum : DWORD { FILE_ACTION_ADDED = 1, FILE_ACTION_REMOVED, FILE_ACTION_MODIFIED, FILE_ACTION_RENAMED_OLD_NAME, FILE_ACTION_RENAMED_NEW_NAME, FILE_ACTION_ADDED_STREAM, FILE_ACTION_REMOVED_STREAM, FILE_ACTION_MODIFIED_STREAM, FILE_ACTION_REMOVED_BY_DELETE, FILE_ACTION_ID_NOT_TUNNELLED, FILE_ACTION_TUNNELLED_ID_COLLISION // = 11 } // MinGW: end ntifs.h enum DWORD HEAP_NO_SERIALIZE = 0x01, HEAP_GROWABLE = 0x02, HEAP_GENERATE_EXCEPTIONS = 0x04, HEAP_ZERO_MEMORY = 0x08, HEAP_REALLOC_IN_PLACE_ONLY = 0x10, HEAP_TAIL_CHECKING_ENABLED = 0x20, HEAP_FREE_CHECKING_ENABLED = 0x40, HEAP_DISABLE_COALESCE_ON_FREE = 0x80; // These are not documented on MSDN enum HEAP_CREATE_ALIGN_16 = 0; enum HEAP_CREATE_ENABLE_TRACING = 0x020000; enum HEAP_MAXIMUM_TAG = 0x000FFF; enum HEAP_PSEUDO_TAG_FLAG = 0x008000; enum HEAP_TAG_SHIFT = 16; // ??? //MACRO #define HEAP_MAKE_TAG_FLAGS(b,o) ((DWORD)((b)+(o)<<16))) enum ACCESS_MASK KEY_QUERY_VALUE = 0x000001, KEY_SET_VALUE = 0x000002, KEY_CREATE_SUB_KEY = 0x000004, KEY_ENUMERATE_SUB_KEYS = 0x000008, KEY_NOTIFY = 0x000010, KEY_CREATE_LINK = 0x000020, KEY_WRITE = 0x020006, KEY_EXECUTE = 0x020019, KEY_READ = 0x020019, KEY_ALL_ACCESS = 0x0F003F; static if (_WIN32_WINNT >= 0x502) { enum ACCESS_MASK KEY_WOW64_64KEY = 0x000100, KEY_WOW64_32KEY = 0x000200; } enum DWORD REG_WHOLE_HIVE_VOLATILE = 1, REG_REFRESH_HIVE = 2, REG_NO_LAZY_FLUSH = 4; enum DWORD REG_OPTION_RESERVED = 0, REG_OPTION_NON_VOLATILE = 0, REG_OPTION_VOLATILE = 1, REG_OPTION_CREATE_LINK = 2, REG_OPTION_BACKUP_RESTORE = 4, REG_OPTION_OPEN_LINK = 8, REG_LEGAL_OPTION = 15; enum SECURITY_INFORMATION OWNER_SECURITY_INFORMATION = 0x00000001, GROUP_SECURITY_INFORMATION = 0x00000002, DACL_SECURITY_INFORMATION = 0x00000004, SACL_SECURITY_INFORMATION = 0x00000008, LABEL_SECURITY_INFORMATION = 0x00000010, UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000, UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000, PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000, PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000; enum DWORD MAXIMUM_PROCESSORS = 32; // VirtualAlloc(), etc // ------------------- enum : DWORD { PAGE_NOACCESS = 0x0001, PAGE_READONLY = 0x0002, PAGE_READWRITE = 0x0004, PAGE_WRITECOPY = 0x0008, PAGE_EXECUTE = 0x0010, PAGE_EXECUTE_READ = 0x0020, PAGE_EXECUTE_READWRITE = 0x0040, PAGE_EXECUTE_WRITECOPY = 0x0080, PAGE_GUARD = 0x0100, PAGE_NOCACHE = 0x0200 } enum : DWORD { MEM_COMMIT = 0x00001000, MEM_RESERVE = 0x00002000, MEM_DECOMMIT = 0x00004000, MEM_RELEASE = 0x00008000, MEM_FREE = 0x00010000, MEM_PRIVATE = 0x00020000, MEM_MAPPED = 0x00040000, MEM_RESET = 0x00080000, MEM_TOP_DOWN = 0x00100000, MEM_WRITE_WATCH = 0x00200000, // MinGW (???): 98/Me MEM_PHYSICAL = 0x00400000, MEM_4MB_PAGES = 0x80000000 } // MinGW: also in ddk/ntifs.h // CreateFileMapping() enum DWORD SEC_BASED = 0x00200000, SEC_NO_CHANGE = 0x00400000, SEC_FILE = 0x00800000, SEC_IMAGE = 0x01000000, SEC_VLM = 0x02000000, SEC_RESERVE = 0x04000000, SEC_COMMIT = 0x08000000, SEC_NOCACHE = 0x10000000, MEM_IMAGE = SEC_IMAGE; // MinGW: end ntifs.h // ??? enum ACCESS_MASK SECTION_QUERY = 0x000001, SECTION_MAP_WRITE = 0x000002, SECTION_MAP_READ = 0x000004, SECTION_MAP_EXECUTE = 0x000008, SECTION_EXTEND_SIZE = 0x000010, SECTION_ALL_ACCESS = 0x0F001F; // These are not documented on MSDN enum MESSAGE_RESOURCE_UNICODE = 1; enum RTL_CRITSECT_TYPE = 0; enum RTL_RESOURCE_TYPE = 1; // COFF file format // ---------------- // IMAGE_FILE_HEADER.Characteristics enum WORD IMAGE_FILE_RELOCS_STRIPPED = 0x0001, IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002, IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004, IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008, IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010, IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020, IMAGE_FILE_BYTES_REVERSED_LO = 0x0080, IMAGE_FILE_32BIT_MACHINE = 0x0100, IMAGE_FILE_DEBUG_STRIPPED = 0x0200, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400, IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800, IMAGE_FILE_SYSTEM = 0x1000, IMAGE_FILE_DLL = 0x2000, IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000, IMAGE_FILE_BYTES_REVERSED_HI = 0x8000; // IMAGE_FILE_HEADER.Machine enum : WORD { IMAGE_FILE_MACHINE_UNKNOWN = 0x0000, IMAGE_FILE_MACHINE_I386 = 0x014C, IMAGE_FILE_MACHINE_R3000 = 0x0162, IMAGE_FILE_MACHINE_R4000 = 0x0166, IMAGE_FILE_MACHINE_R10000 = 0x0168, IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x0169, IMAGE_FILE_MACHINE_ALPHA = 0x0184, IMAGE_FILE_MACHINE_SH3 = 0x01A2, IMAGE_FILE_MACHINE_SH3DSP = 0x01A3, IMAGE_FILE_MACHINE_SH4 = 0x01A6, IMAGE_FILE_MACHINE_SH5 = 0x01A8, IMAGE_FILE_MACHINE_ARM = 0x01C0, IMAGE_FILE_MACHINE_THUMB = 0x01C2, IMAGE_FILE_MACHINE_AM33 = 0x01D3, IMAGE_FILE_MACHINE_POWERPC = 0x01F0, IMAGE_FILE_MACHINE_POWERPCFP = 0x01F1, IMAGE_FILE_MACHINE_IA64 = 0x0200, IMAGE_FILE_MACHINE_MIPS16 = 0x0266, IMAGE_FILE_MACHINE_MIPSFPU = 0x0366, IMAGE_FILE_MACHINE_MIPSFPU16 = 0x0466, IMAGE_FILE_MACHINE_EBC = 0x0EBC, IMAGE_FILE_MACHINE_AMD64 = 0x8664, IMAGE_FILE_MACHINE_M32R = 0x9041 } // ??? enum { IMAGE_DOS_SIGNATURE = 0x5A4D, IMAGE_OS2_SIGNATURE = 0x454E, IMAGE_OS2_SIGNATURE_LE = 0x454C, IMAGE_VXD_SIGNATURE = 0x454C, IMAGE_NT_SIGNATURE = 0x4550 } // IMAGE_OPTIONAL_HEADER.Magic enum : WORD { IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x010B, IMAGE_ROM_OPTIONAL_HDR_MAGIC = 0x0107, IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x020B } // IMAGE_OPTIONAL_HEADER.Subsystem enum : WORD { IMAGE_SUBSYSTEM_UNKNOWN = 0, IMAGE_SUBSYSTEM_NATIVE, IMAGE_SUBSYSTEM_WINDOWS_GUI, IMAGE_SUBSYSTEM_WINDOWS_CUI, // = 3 IMAGE_SUBSYSTEM_OS2_CUI = 5, IMAGE_SUBSYSTEM_POSIX_CUI = 7, IMAGE_SUBSYSTEM_NATIVE_WINDOWS, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, IMAGE_SUBSYSTEM_EFI_APPLICATION, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, IMAGE_SUBSYSTEM_EFI_ROM, IMAGE_SUBSYSTEM_XBOX, // = 14 IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16 } // IMAGE_OPTIONAL_HEADER.DllCharacteristics enum WORD IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = 0x0080, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100, IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200, IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400, IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800, IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000, IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000; // ??? enum IMAGE_SEPARATE_DEBUG_SIGNATURE = 0x4944; enum size_t IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16, IMAGE_SIZEOF_ROM_OPTIONAL_HEADER = 56, IMAGE_SIZEOF_STD_OPTIONAL_HEADER = 28, IMAGE_SIZEOF_NT_OPTIONAL_HEADER = 224, IMAGE_SIZEOF_SHORT_NAME = 8, IMAGE_SIZEOF_SECTION_HEADER = 40, IMAGE_SIZEOF_SYMBOL = 18, IMAGE_SIZEOF_AUX_SYMBOL = 18, IMAGE_SIZEOF_RELOCATION = 10, IMAGE_SIZEOF_BASE_RELOCATION = 8, IMAGE_SIZEOF_LINENUMBER = 6, IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR = 60, SIZEOF_RFPO_DATA = 16; PIMAGE_SECTION_HEADER IMAGE_FIRST_SECTION(PIMAGE_NT_HEADERS h) { return cast(PIMAGE_SECTION_HEADER) (&h.OptionalHeader + h.FileHeader.SizeOfOptionalHeader); } // ImageDirectoryEntryToDataEx() enum : USHORT { IMAGE_DIRECTORY_ENTRY_EXPORT = 0, IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_DIRECTORY_ENTRY_RESOURCE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, IMAGE_DIRECTORY_ENTRY_SECURITY, IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_DIRECTORY_ENTRY_DEBUG, IMAGE_DIRECTORY_ENTRY_COPYRIGHT, // = 7 IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7, IMAGE_DIRECTORY_ENTRY_GLOBALPTR, IMAGE_DIRECTORY_ENTRY_TLS, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, IMAGE_DIRECTORY_ENTRY_IAT, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, // = 14 } // IMAGE_SECTION_HEADER.Characteristics enum DWORD IMAGE_SCN_TYPE_REG = 0x00000000, IMAGE_SCN_TYPE_DSECT = 0x00000001, IMAGE_SCN_TYPE_NOLOAD = 0x00000002, IMAGE_SCN_TYPE_GROUP = 0x00000004, IMAGE_SCN_TYPE_NO_PAD = 0x00000008, IMAGE_SCN_TYPE_COPY = 0x00000010, IMAGE_SCN_CNT_CODE = 0x00000020, IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040, IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080, IMAGE_SCN_LNK_OTHER = 0x00000100, IMAGE_SCN_LNK_INFO = 0x00000200, IMAGE_SCN_TYPE_OVER = 0x00000400, IMAGE_SCN_LNK_REMOVE = 0x00000800, IMAGE_SCN_LNK_COMDAT = 0x00001000, IMAGE_SCN_MEM_FARDATA = 0x00008000, IMAGE_SCN_GPREL = 0x00008000, IMAGE_SCN_MEM_PURGEABLE = 0x00020000, IMAGE_SCN_MEM_16BIT = 0x00020000, IMAGE_SCN_MEM_LOCKED = 0x00040000, IMAGE_SCN_MEM_PRELOAD = 0x00080000, IMAGE_SCN_ALIGN_1BYTES = 0x00100000, IMAGE_SCN_ALIGN_2BYTES = 0x00200000, IMAGE_SCN_ALIGN_4BYTES = 0x00300000, IMAGE_SCN_ALIGN_8BYTES = 0x00400000, IMAGE_SCN_ALIGN_16BYTES = 0x00500000, IMAGE_SCN_ALIGN_32BYTES = 0x00600000, IMAGE_SCN_ALIGN_64BYTES = 0x00700000, IMAGE_SCN_ALIGN_128BYTES = 0x00800000, IMAGE_SCN_ALIGN_256BYTES = 0x00900000, IMAGE_SCN_ALIGN_512BYTES = 0x00A00000, IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000, IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000, IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000, IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000, IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000, IMAGE_SCN_MEM_DISCARDABLE = 0x02000000, IMAGE_SCN_MEM_NOT_CACHED = 0x04000000, IMAGE_SCN_MEM_NOT_PAGED = 0x08000000, IMAGE_SCN_MEM_SHARED = 0x10000000, IMAGE_SCN_MEM_EXECUTE = 0x20000000, IMAGE_SCN_MEM_READ = 0x40000000, IMAGE_SCN_MEM_WRITE = 0x80000000; /* The following constants are mostlydocumented at * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/pecoff.doc * but don't seem to be defined in the HTML docs. */ enum : SHORT { IMAGE_SYM_UNDEFINED = 0, IMAGE_SYM_ABSOLUTE = -1, IMAGE_SYM_DEBUG = -2 } enum : ubyte { IMAGE_SYM_TYPE_NULL, IMAGE_SYM_TYPE_VOID, IMAGE_SYM_TYPE_CHAR, IMAGE_SYM_TYPE_SHORT, IMAGE_SYM_TYPE_INT, IMAGE_SYM_TYPE_LONG, IMAGE_SYM_TYPE_FLOAT, IMAGE_SYM_TYPE_DOUBLE, IMAGE_SYM_TYPE_STRUCT, IMAGE_SYM_TYPE_UNION, IMAGE_SYM_TYPE_ENUM, IMAGE_SYM_TYPE_MOE, IMAGE_SYM_TYPE_BYTE, IMAGE_SYM_TYPE_WORD, IMAGE_SYM_TYPE_UINT, IMAGE_SYM_TYPE_DWORD // = 15 } enum IMAGE_SYM_TYPE_PCODE = 32768; // ??? enum : ubyte { IMAGE_SYM_DTYPE_NULL, IMAGE_SYM_DTYPE_POINTER, IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_ARRAY } enum : BYTE { IMAGE_SYM_CLASS_END_OF_FUNCTION = 0xFF, IMAGE_SYM_CLASS_NULL = 0, IMAGE_SYM_CLASS_AUTOMATIC, IMAGE_SYM_CLASS_EXTERNAL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_REGISTER, IMAGE_SYM_CLASS_EXTERNAL_DEF, IMAGE_SYM_CLASS_LABEL, IMAGE_SYM_CLASS_UNDEFINED_LABEL, IMAGE_SYM_CLASS_MEMBER_OF_STRUCT, IMAGE_SYM_CLASS_ARGUMENT, IMAGE_SYM_CLASS_STRUCT_TAG, IMAGE_SYM_CLASS_MEMBER_OF_UNION, IMAGE_SYM_CLASS_UNION_TAG, IMAGE_SYM_CLASS_TYPE_DEFINITION, IMAGE_SYM_CLASS_UNDEFINED_STATIC, IMAGE_SYM_CLASS_ENUM_TAG, IMAGE_SYM_CLASS_MEMBER_OF_ENUM, IMAGE_SYM_CLASS_REGISTER_PARAM, IMAGE_SYM_CLASS_BIT_FIELD, // = 18 IMAGE_SYM_CLASS_FAR_EXTERNAL = 68, IMAGE_SYM_CLASS_BLOCK = 100, IMAGE_SYM_CLASS_FUNCTION, IMAGE_SYM_CLASS_END_OF_STRUCT, IMAGE_SYM_CLASS_FILE, IMAGE_SYM_CLASS_SECTION, IMAGE_SYM_CLASS_WEAK_EXTERNAL,// = 105 IMAGE_SYM_CLASS_CLR_TOKEN = 107 } enum : BYTE { IMAGE_COMDAT_SELECT_NODUPLICATES = 1, IMAGE_COMDAT_SELECT_ANY, IMAGE_COMDAT_SELECT_SAME_SIZE, IMAGE_COMDAT_SELECT_EXACT_MATCH, IMAGE_COMDAT_SELECT_ASSOCIATIVE, IMAGE_COMDAT_SELECT_LARGEST, IMAGE_COMDAT_SELECT_NEWEST // = 7 } enum : DWORD { IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY = 1, IMAGE_WEAK_EXTERN_SEARCH_LIBRARY, IMAGE_WEAK_EXTERN_SEARCH_ALIAS } enum : WORD { IMAGE_REL_I386_ABSOLUTE = 0x0000, IMAGE_REL_I386_DIR16 = 0x0001, IMAGE_REL_I386_REL16 = 0x0002, IMAGE_REL_I386_DIR32 = 0x0006, IMAGE_REL_I386_DIR32NB = 0x0007, IMAGE_REL_I386_SEG12 = 0x0009, IMAGE_REL_I386_SECTION = 0x000A, IMAGE_REL_I386_SECREL = 0x000B, IMAGE_REL_I386_TOKEN = 0x000C, IMAGE_REL_I386_SECREL7 = 0x000D, IMAGE_REL_I386_REL32 = 0x0014 } enum : WORD { IMAGE_REL_AMD64_ABSOLUTE = 0x0000, IMAGE_REL_AMD64_ADDR64 = 0x0001, IMAGE_REL_AMD64_ADDR32 = 0x0002, IMAGE_REL_AMD64_ADDR32NB = 0x0003, IMAGE_REL_AMD64_REL32 = 0x0004, IMAGE_REL_AMD64_REL32_1 = 0x0005, IMAGE_REL_AMD64_REL32_2 = 0x0006, IMAGE_REL_AMD64_REL32_3 = 0x0007, IMAGE_REL_AMD64_REL32_4 = 0x0008, IMAGE_REL_AMD64_REL32_5 = 0x0009, IMAGE_REL_AMD64_SECTION = 0x000A, IMAGE_REL_AMD64_SECREL = 0x000B, IMAGE_REL_AMD64_SECREL7 = 0x000C, IMAGE_REL_AMD64_TOKEN = 0x000D, IMAGE_REL_AMD64_SREL32 = 0x000E, IMAGE_REL_AMD64_PAIR = 0x000F, IMAGE_REL_AMD64_SSPAN32 = 0x0010 } enum : WORD { IMAGE_REL_IA64_ABSOLUTE = 0x0000, IMAGE_REL_IA64_IMM14 = 0x0001, IMAGE_REL_IA64_IMM22 = 0x0002, IMAGE_REL_IA64_IMM64 = 0x0003, IMAGE_REL_IA64_DIR32 = 0x0004, IMAGE_REL_IA64_DIR64 = 0x0005, IMAGE_REL_IA64_PCREL21B = 0x0006, IMAGE_REL_IA64_PCREL21M = 0x0007, IMAGE_REL_IA64_PCREL21F = 0x0008, IMAGE_REL_IA64_GPREL22 = 0x0009, IMAGE_REL_IA64_LTOFF22 = 0x000A, IMAGE_REL_IA64_SECTION = 0x000B, IMAGE_REL_IA64_SECREL22 = 0x000C, IMAGE_REL_IA64_SECREL64I = 0x000D, IMAGE_REL_IA64_SECREL32 = 0x000E, IMAGE_REL_IA64_DIR32NB = 0x0010, IMAGE_REL_IA64_SREL14 = 0x0011, IMAGE_REL_IA64_SREL22 = 0x0012, IMAGE_REL_IA64_SREL32 = 0x0013, IMAGE_REL_IA64_UREL32 = 0x0014, IMAGE_REL_IA64_PCREL60X = 0x0015, IMAGE_REL_IA64_PCREL60B = 0x0016, IMAGE_REL_IA64_PCREL60F = 0x0017, IMAGE_REL_IA64_PCREL60I = 0x0018, IMAGE_REL_IA64_PCREL60M = 0x0019, IMAGE_REL_IA64_IMMGPREL64 = 0x001A, IMAGE_REL_IA64_TOKEN = 0x001B, IMAGE_REL_IA64_GPREL32 = 0x001C, IMAGE_REL_IA64_ADDEND = 0x001F } enum : WORD { IMAGE_REL_SH3_ABSOLUTE = 0x0000, IMAGE_REL_SH3_DIRECT16 = 0x0001, IMAGE_REL_SH3_DIRECT32 = 0x0002, IMAGE_REL_SH3_DIRECT8 = 0x0003, IMAGE_REL_SH3_DIRECT8_WORD = 0x0004, IMAGE_REL_SH3_DIRECT8_LONG = 0x0005, IMAGE_REL_SH3_DIRECT4 = 0x0006, IMAGE_REL_SH3_DIRECT4_WORD = 0x0007, IMAGE_REL_SH3_DIRECT4_LONG = 0x0008, IMAGE_REL_SH3_PCREL8_WORD = 0x0009, IMAGE_REL_SH3_PCREL8_LONG = 0x000A, IMAGE_REL_SH3_PCREL12_WORD = 0x000B, IMAGE_REL_SH3_STARTOF_SECTION = 0x000C, IMAGE_REL_SH3_SIZEOF_SECTION = 0x000D, IMAGE_REL_SH3_SECTION = 0x000E, IMAGE_REL_SH3_SECREL = 0x000F, IMAGE_REL_SH3_DIRECT32_NB = 0x0010, IMAGE_REL_SH3_GPREL4_LONG = 0x0011, IMAGE_REL_SH3_TOKEN = 0x0012, IMAGE_REL_SHM_PCRELPT = 0x0013, IMAGE_REL_SHM_REFLO = 0x0014, IMAGE_REL_SHM_REFHALF = 0x0015, IMAGE_REL_SHM_RELLO = 0x0016, IMAGE_REL_SHM_RELHALF = 0x0017, IMAGE_REL_SHM_PAIR = 0x0018, IMAGE_REL_SHM_NOMODE = 0x8000 } enum : WORD { IMAGE_REL_M32R_ABSOLUTE = 0x0000, IMAGE_REL_M32R_ADDR32 = 0x0001, IMAGE_REL_M32R_ADDR32NB = 0x0002, IMAGE_REL_M32R_ADDR24 = 0x0003, IMAGE_REL_M32R_GPREL16 = 0x0004, IMAGE_REL_M32R_PCREL24 = 0x0005, IMAGE_REL_M32R_PCREL16 = 0x0006, IMAGE_REL_M32R_PCREL8 = 0x0007, IMAGE_REL_M32R_REFHALF = 0x0008, IMAGE_REL_M32R_REFHI = 0x0009, IMAGE_REL_M32R_REFLO = 0x000A, IMAGE_REL_M32R_PAIR = 0x000B, IMAGE_REL_M32R_SECTION = 0x000C, IMAGE_REL_M32R_SECREL = 0x000D, IMAGE_REL_M32R_TOKEN = 0x000E } enum : WORD { IMAGE_REL_MIPS_ABSOLUTE = 0x0000, IMAGE_REL_MIPS_REFHALF = 0x0001, IMAGE_REL_MIPS_REFWORD = 0x0002, IMAGE_REL_MIPS_JMPADDR = 0x0003, IMAGE_REL_MIPS_REFHI = 0x0004, IMAGE_REL_MIPS_REFLO = 0x0005, IMAGE_REL_MIPS_GPREL = 0x0006, IMAGE_REL_MIPS_LITERAL = 0x0007, IMAGE_REL_MIPS_SECTION = 0x000A, IMAGE_REL_MIPS_SECREL = 0x000B, IMAGE_REL_MIPS_SECRELLO = 0x000C, IMAGE_REL_MIPS_SECRELHI = 0x000D, IMAGE_REL_MIPS_JMPADDR16 = 0x0010, IMAGE_REL_MIPS_REFWORDNB = 0x0022, IMAGE_REL_MIPS_PAIR = 0x0025 } enum : WORD { IMAGE_REL_ALPHA_ABSOLUTE, IMAGE_REL_ALPHA_REFLONG, IMAGE_REL_ALPHA_REFQUAD, IMAGE_REL_ALPHA_GPREL32, IMAGE_REL_ALPHA_LITERAL, IMAGE_REL_ALPHA_LITUSE, IMAGE_REL_ALPHA_GPDISP, IMAGE_REL_ALPHA_BRADDR, IMAGE_REL_ALPHA_HINT, IMAGE_REL_ALPHA_INLINE_REFLONG, IMAGE_REL_ALPHA_REFHI, IMAGE_REL_ALPHA_REFLO, IMAGE_REL_ALPHA_PAIR, IMAGE_REL_ALPHA_MATCH, IMAGE_REL_ALPHA_SECTION, IMAGE_REL_ALPHA_SECREL, IMAGE_REL_ALPHA_REFLONGNB, IMAGE_REL_ALPHA_SECRELLO, IMAGE_REL_ALPHA_SECRELHI // = 18 } enum : WORD { IMAGE_REL_PPC_ABSOLUTE, IMAGE_REL_PPC_ADDR64, IMAGE_REL_PPC_ADDR32, IMAGE_REL_PPC_ADDR24, IMAGE_REL_PPC_ADDR16, IMAGE_REL_PPC_ADDR14, IMAGE_REL_PPC_REL24, IMAGE_REL_PPC_REL14, IMAGE_REL_PPC_TOCREL16, IMAGE_REL_PPC_TOCREL14, IMAGE_REL_PPC_ADDR32NB, IMAGE_REL_PPC_SECREL, IMAGE_REL_PPC_SECTION, IMAGE_REL_PPC_IFGLUE, IMAGE_REL_PPC_IMGLUE, IMAGE_REL_PPC_SECREL16, IMAGE_REL_PPC_REFHI, IMAGE_REL_PPC_REFLO, IMAGE_REL_PPC_PAIR // = 18 } // ??? enum IMAGE_REL_PPC_TYPEMASK = 0x00FF; enum IMAGE_REL_PPC_NEG = 0x0100; enum IMAGE_REL_PPC_BRTAKEN = 0x0200; enum IMAGE_REL_PPC_BRNTAKEN = 0x0400; enum IMAGE_REL_PPC_TOCDEFN = 0x0800; enum { IMAGE_REL_BASED_ABSOLUTE, IMAGE_REL_BASED_HIGH, IMAGE_REL_BASED_LOW, IMAGE_REL_BASED_HIGHLOW, IMAGE_REL_BASED_HIGHADJ, IMAGE_REL_BASED_MIPS_JMPADDR } // End of constants documented in pecoff.doc enum size_t IMAGE_ARCHIVE_START_SIZE = 8; const TCHAR[] IMAGE_ARCHIVE_START = "!\n", IMAGE_ARCHIVE_END = "`\n", IMAGE_ARCHIVE_PAD = "\n", IMAGE_ARCHIVE_LINKER_MEMBER = "/ ", IMAGE_ARCHIVE_LONGNAMES_MEMBER = "// "; enum IMAGE_ORDINAL_FLAG32 = 0x80000000; ulong IMAGE_ORDINAL64(ulong Ordinal) { return Ordinal & 0xFFFF; } uint IMAGE_ORDINAL32(uint Ordinal) { return Ordinal & 0xFFFF; } bool IMAGE_SNAP_BY_ORDINAL32(uint Ordinal) { return (Ordinal & IMAGE_ORDINAL_FLAG32) != 0; } enum ulong IMAGE_ORDINAL_FLAG64 = 0x8000000000000000; bool IMAGE_SNAP_BY_ORDINAL64(ulong Ordinal) { return (Ordinal & IMAGE_ORDINAL_FLAG64) != 0; } // ??? enum IMAGE_RESOURCE_NAME_IS_STRING = 0x80000000; enum IMAGE_RESOURCE_DATA_IS_DIRECTORY = 0x80000000; enum : DWORD { IMAGE_DEBUG_TYPE_UNKNOWN, IMAGE_DEBUG_TYPE_COFF, IMAGE_DEBUG_TYPE_CODEVIEW, IMAGE_DEBUG_TYPE_FPO, IMAGE_DEBUG_TYPE_MISC, IMAGE_DEBUG_TYPE_EXCEPTION, IMAGE_DEBUG_TYPE_FIXUP, IMAGE_DEBUG_TYPE_OMAP_TO_SRC, IMAGE_DEBUG_TYPE_OMAP_FROM_SRC, IMAGE_DEBUG_TYPE_BORLAND // = 9 } enum : ubyte { FRAME_FPO, FRAME_TRAP, FRAME_TSS, FRAME_NONFPO } // ??? enum IMAGE_DEBUG_MISC_EXENAME = 1; // ??? enum N_BTMASK = 0x000F; enum N_TMASK = 0x0030; enum N_TMASK1 = 0x00C0; enum N_TMASK2 = 0x00F0; enum N_BTSHFT = 4; enum N_TSHIFT = 2; enum int IS_TEXT_UNICODE_ASCII16 = 0x0001, IS_TEXT_UNICODE_STATISTICS = 0x0002, IS_TEXT_UNICODE_CONTROLS = 0x0004, IS_TEXT_UNICODE_SIGNATURE = 0x0008, IS_TEXT_UNICODE_REVERSE_ASCII16 = 0x0010, IS_TEXT_UNICODE_REVERSE_STATISTICS = 0x0020, IS_TEXT_UNICODE_REVERSE_CONTROLS = 0x0040, IS_TEXT_UNICODE_REVERSE_SIGNATURE = 0x0080, IS_TEXT_UNICODE_ILLEGAL_CHARS = 0x0100, IS_TEXT_UNICODE_ODD_LENGTH = 0x0200, IS_TEXT_UNICODE_NULL_BYTES = 0x1000, IS_TEXT_UNICODE_UNICODE_MASK = 0x000F, IS_TEXT_UNICODE_REVERSE_MASK = 0x00F0, IS_TEXT_UNICODE_NOT_UNICODE_MASK = 0x0F00, IS_TEXT_UNICODE_NOT_ASCII_MASK = 0xF000; enum DWORD SERVICE_KERNEL_DRIVER = 0x0001, SERVICE_FILE_SYSTEM_DRIVER = 0x0002, SERVICE_ADAPTER = 0x0004, SERVICE_RECOGNIZER_DRIVER = 0x0008, SERVICE_WIN32_OWN_PROCESS = 0x0010, SERVICE_WIN32_SHARE_PROCESS = 0x0020, SERVICE_INTERACTIVE_PROCESS = 0x0100, SERVICE_DRIVER = 0x000B, SERVICE_WIN32 = 0x0030, SERVICE_TYPE_ALL = 0x013F; enum : DWORD { SERVICE_BOOT_START = 0, SERVICE_SYSTEM_START = 1, SERVICE_AUTO_START = 2, SERVICE_DEMAND_START = 3, SERVICE_DISABLED = 4 } enum : DWORD { SERVICE_ERROR_IGNORE = 0, SERVICE_ERROR_NORMAL = 1, SERVICE_ERROR_SEVERE = 2, SERVICE_ERROR_CRITICAL = 3 } enum uint SE_OWNER_DEFAULTED = 0x0001, SE_GROUP_DEFAULTED = 0x0002, SE_DACL_PRESENT = 0x0004, SE_DACL_DEFAULTED = 0x0008, SE_SACL_PRESENT = 0x0010, SE_SACL_DEFAULTED = 0x0020, SE_DACL_AUTO_INHERIT_REQ = 0x0100, SE_SACL_AUTO_INHERIT_REQ = 0x0200, SE_DACL_AUTO_INHERITED = 0x0400, SE_SACL_AUTO_INHERITED = 0x0800, SE_DACL_PROTECTED = 0x1000, SE_SACL_PROTECTED = 0x2000, SE_SELF_RELATIVE = 0x8000; enum SECURITY_IMPERSONATION_LEVEL { SecurityAnonymous, SecurityIdentification, SecurityImpersonation, SecurityDelegation } alias SECURITY_IMPERSONATION_LEVEL* PSECURITY_IMPERSONATION_LEVEL; alias BOOLEAN SECURITY_CONTEXT_TRACKING_MODE; alias BOOLEAN* PSECURITY_CONTEXT_TRACKING_MODE; enum size_t SECURITY_DESCRIPTOR_MIN_LENGTH = 20; enum DWORD SECURITY_DESCRIPTOR_REVISION = 1, SECURITY_DESCRIPTOR_REVISION1 = 1; enum DWORD SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001, SE_PRIVILEGE_ENABLED = 0x00000002, SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000; enum DWORD PRIVILEGE_SET_ALL_NECESSARY = 1; enum SECURITY_IMPERSONATION_LEVEL SECURITY_MAX_IMPERSONATION_LEVEL = SECURITY_IMPERSONATION_LEVEL.SecurityDelegation, DEFAULT_IMPERSONATION_LEVEL = SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation; enum BOOLEAN SECURITY_DYNAMIC_TRACKING = true, SECURITY_STATIC_TRACKING = false; // also in ddk/ntifs.h enum DWORD TOKEN_ASSIGN_PRIMARY = 0x0001, TOKEN_DUPLICATE = 0x0002, TOKEN_IMPERSONATE = 0x0004, TOKEN_QUERY = 0x0008, TOKEN_QUERY_SOURCE = 0x0010, TOKEN_ADJUST_PRIVILEGES = 0x0020, TOKEN_ADJUST_GROUPS = 0x0040, TOKEN_ADJUST_DEFAULT = 0x0080, TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT, TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY, TOKEN_WRITE = STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT, TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE; enum size_t TOKEN_SOURCE_LENGTH = 8; // end ddk/ntifs.h enum : DWORD { DLL_PROCESS_DETACH, DLL_PROCESS_ATTACH, DLL_THREAD_ATTACH, DLL_THREAD_DETACH } enum : DWORD { DBG_CONTINUE = 0x00010002, DBG_TERMINATE_THREAD = 0x40010003, DBG_TERMINATE_PROCESS = 0x40010004, DBG_CONTROL_C = 0x40010005, DBG_CONTROL_BREAK = 0x40010008, DBG_EXCEPTION_NOT_HANDLED = 0x80010001 } enum : DWORD { TAPE_ABSOLUTE_POSITION, TAPE_LOGICAL_POSITION, TAPE_PSEUDO_LOGICAL_POSITION } enum : DWORD { TAPE_REWIND, TAPE_ABSOLUTE_BLOCK, TAPE_LOGICAL_BLOCK, TAPE_PSEUDO_LOGICAL_BLOCK, TAPE_SPACE_END_OF_DATA, TAPE_SPACE_RELATIVE_BLOCKS, TAPE_SPACE_FILEMARKS, TAPE_SPACE_SEQUENTIAL_FMKS, TAPE_SPACE_SETMARKS, TAPE_SPACE_SEQUENTIAL_SMKS } enum DWORD TAPE_DRIVE_FIXED = 0x00000001, TAPE_DRIVE_SELECT = 0x00000002, TAPE_DRIVE_INITIATOR = 0x00000004, TAPE_DRIVE_ERASE_SHORT = 0x00000010, TAPE_DRIVE_ERASE_LONG = 0x00000020, TAPE_DRIVE_ERASE_BOP_ONLY = 0x00000040, TAPE_DRIVE_ERASE_IMMEDIATE = 0x00000080, TAPE_DRIVE_TAPE_CAPACITY = 0x00000100, TAPE_DRIVE_TAPE_REMAINING = 0x00000200, TAPE_DRIVE_FIXED_BLOCK = 0x00000400, TAPE_DRIVE_VARIABLE_BLOCK = 0x00000800, TAPE_DRIVE_WRITE_PROTECT = 0x00001000, TAPE_DRIVE_EOT_WZ_SIZE = 0x00002000, TAPE_DRIVE_ECC = 0x00010000, TAPE_DRIVE_COMPRESSION = 0x00020000, TAPE_DRIVE_PADDING = 0x00040000, TAPE_DRIVE_REPORT_SMKS = 0x00080000, TAPE_DRIVE_GET_ABSOLUTE_BLK = 0x00100000, TAPE_DRIVE_GET_LOGICAL_BLK = 0x00200000, TAPE_DRIVE_SET_EOT_WZ_SIZE = 0x00400000, TAPE_DRIVE_EJECT_MEDIA = 0x01000000, TAPE_DRIVE_CLEAN_REQUESTS = 0x02000000, TAPE_DRIVE_SET_CMP_BOP_ONLY = 0x04000000, TAPE_DRIVE_RESERVED_BIT = 0x80000000; enum DWORD TAPE_DRIVE_LOAD_UNLOAD = 0x80000001, TAPE_DRIVE_TENSION = 0x80000002, TAPE_DRIVE_LOCK_UNLOCK = 0x80000004, TAPE_DRIVE_REWIND_IMMEDIATE = 0x80000008, TAPE_DRIVE_SET_BLOCK_SIZE = 0x80000010, TAPE_DRIVE_LOAD_UNLD_IMMED = 0x80000020, TAPE_DRIVE_TENSION_IMMED = 0x80000040, TAPE_DRIVE_LOCK_UNLK_IMMED = 0x80000080, TAPE_DRIVE_SET_ECC = 0x80000100, TAPE_DRIVE_SET_COMPRESSION = 0x80000200, TAPE_DRIVE_SET_PADDING = 0x80000400, TAPE_DRIVE_SET_REPORT_SMKS = 0x80000800, TAPE_DRIVE_ABSOLUTE_BLK = 0x80001000, TAPE_DRIVE_ABS_BLK_IMMED = 0x80002000, TAPE_DRIVE_LOGICAL_BLK = 0x80004000, TAPE_DRIVE_LOG_BLK_IMMED = 0x80008000, TAPE_DRIVE_END_OF_DATA = 0x80010000, TAPE_DRIVE_RELATIVE_BLKS = 0x80020000, TAPE_DRIVE_FILEMARKS = 0x80040000, TAPE_DRIVE_SEQUENTIAL_FMKS = 0x80080000, TAPE_DRIVE_SETMARKS = 0x80100000, TAPE_DRIVE_SEQUENTIAL_SMKS = 0x80200000, TAPE_DRIVE_REVERSE_POSITION = 0x80400000, TAPE_DRIVE_SPACE_IMMEDIATE = 0x80800000, TAPE_DRIVE_WRITE_SETMARKS = 0x81000000, TAPE_DRIVE_WRITE_FILEMARKS = 0x82000000, TAPE_DRIVE_WRITE_SHORT_FMKS = 0x84000000, TAPE_DRIVE_WRITE_LONG_FMKS = 0x88000000, TAPE_DRIVE_WRITE_MARK_IMMED = 0x90000000, TAPE_DRIVE_FORMAT = 0xA0000000, TAPE_DRIVE_FORMAT_IMMEDIATE = 0xC0000000, TAPE_DRIVE_HIGH_FEATURES = 0x80000000; enum : DWORD { TAPE_FIXED_PARTITIONS = 0, TAPE_SELECT_PARTITIONS = 1, TAPE_INITIATOR_PARTITIONS = 2 } enum : DWORD { TAPE_SETMARKS, TAPE_FILEMARKS, TAPE_SHORT_FILEMARKS, TAPE_LONG_FILEMARKS } enum : DWORD { TAPE_ERASE_SHORT, TAPE_ERASE_LONG } enum : DWORD { TAPE_LOAD, TAPE_UNLOAD, TAPE_TENSION, TAPE_LOCK, TAPE_UNLOCK, TAPE_FORMAT } enum : ULONG32 { VER_PLATFORM_WIN32s, VER_PLATFORM_WIN32_WINDOWS, VER_PLATFORM_WIN32_NT } enum : UCHAR { VER_NT_WORKSTATION = 1, VER_NT_DOMAIN_CONTROLLER, VER_NT_SERVER } enum USHORT VER_SUITE_SMALLBUSINESS = 0x0001, VER_SUITE_ENTERPRISE = 0x0002, VER_SUITE_BACKOFFICE = 0x0004, VER_SUITE_TERMINAL = 0x0010, VER_SUITE_SMALLBUSINESS_RESTRICTED = 0x0020, VER_SUITE_EMBEDDEDNT = 0x0040, VER_SUITE_DATACENTER = 0x0080, VER_SUITE_SINGLEUSERTS = 0x0100, VER_SUITE_PERSONAL = 0x0200, VER_SUITE_BLADE = 0x0400, VER_SUITE_STORAGE_SERVER = 0x2000, VER_SUITE_COMPUTE_SERVER = 0x4000; enum ULONG WT_EXECUTEDEFAULT = 0x00000000, WT_EXECUTEINIOTHREAD = 0x00000001, WT_EXECUTEINWAITTHREAD = 0x00000004, WT_EXECUTEONLYONCE = 0x00000008, WT_EXECUTELONGFUNCTION = 0x00000010, WT_EXECUTEINTIMERTHREAD = 0x00000020, WT_EXECUTEINPERSISTENTTHREAD = 0x00000080, WT_TRANSFER_IMPERSONATION = 0x00000100; static if (_WIN32_WINNT >= 0x500) { enum DWORD VER_MINORVERSION = 0x01, VER_MAJORVERSION = 0x02, VER_BUILDNUMBER = 0x04, VER_PLATFORMID = 0x08, VER_SERVICEPACKMINOR = 0x10, VER_SERVICEPACKMAJOR = 0x20, VER_SUITENAME = 0x40, VER_PRODUCT_TYPE = 0x80; enum : DWORD { VER_EQUAL = 1, VER_GREATER, VER_GREATER_EQUAL, VER_LESS, VER_LESS_EQUAL, VER_AND, VER_OR // = 7 } } static if (_WIN32_WINNT >= 0x501) { enum : ULONG { ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION = 1, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION, // = 7 ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES = 9 } } // Macros BYTE BTYPE(BYTE x) { return cast(BYTE) (x & N_BTMASK); } bool ISPTR(uint x) { return (x & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT); } bool ISFCN(uint x) { return (x & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT); } bool ISARY(uint x) { return (x & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT); } bool ISTAG(uint x) { return x == IMAGE_SYM_CLASS_STRUCT_TAG || x == IMAGE_SYM_CLASS_UNION_TAG || x == IMAGE_SYM_CLASS_ENUM_TAG; } uint INCREF(uint x) { return ((x & ~N_BTMASK) << N_TSHIFT) | (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT) | (x & N_BTMASK); } uint DECREF(uint x) { return ((x >>> N_TSHIFT) & ~N_BTMASK) | (x & N_BTMASK); } enum DWORD TLS_MINIMUM_AVAILABLE = 64; enum ULONG IO_REPARSE_TAG_RESERVED_ZERO = 0, IO_REPARSE_TAG_RESERVED_ONE = 1, IO_REPARSE_TAG_RESERVED_RANGE = IO_REPARSE_TAG_RESERVED_ONE, IO_REPARSE_TAG_SYMBOLIC_LINK = IO_REPARSE_TAG_RESERVED_ZERO, IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003, IO_REPARSE_TAG_SYMLINK = 0xA000000C, IO_REPARSE_TAG_VALID_VALUES = 0xE000FFFF; /* Although these are semantically boolean, they are documented and * implemented to return ULONG; this behaviour is preserved for compatibility */ ULONG IsReparseTagMicrosoft(ULONG x) { return x & 0x80000000; } ULONG IsReparseTagHighLatency(ULONG x) { return x & 0x40000000; } ULONG IsReparseTagNameSurrogate(ULONG x) { return x & 0x20000000; } bool IsReparseTagValid(ULONG x) { return !(x & ~IO_REPARSE_TAG_VALID_VALUES) && (x > IO_REPARSE_TAG_RESERVED_RANGE); } // Doesn't seem to make sense, but anyway.... ULONG WT_SET_MAX_THREADPOOL_THREADS(ref ULONG Flags, ushort Limit) { return Flags |= Limit << 16; } import core.sys.windows.basetyps; /* also in core.sys.windows.basetyps struct GUID { uint Data1; ushort Data2; ushort Data3; ubyte Data4[8]; } alias GUID* REFGUID, LPGUID; */ struct GENERIC_MAPPING { ACCESS_MASK GenericRead; ACCESS_MASK GenericWrite; ACCESS_MASK GenericExecute; ACCESS_MASK GenericAll; } alias GENERIC_MAPPING* PGENERIC_MAPPING; struct ACE_HEADER { BYTE AceType; BYTE AceFlags; WORD AceSize; } alias ACE_HEADER* PACE_HEADER; struct ACCESS_ALLOWED_ACE { ACE_HEADER Header; ACCESS_MASK Mask; DWORD SidStart; } alias ACCESS_ALLOWED_ACE* PACCESS_ALLOWED_ACE; struct ACCESS_DENIED_ACE { ACE_HEADER Header; ACCESS_MASK Mask; DWORD SidStart; } alias ACCESS_DENIED_ACE* PACCESS_DENIED_ACE; struct SYSTEM_AUDIT_ACE { ACE_HEADER Header; ACCESS_MASK Mask; DWORD SidStart; } alias SYSTEM_AUDIT_ACE *PSYSTEM_AUDIT_ACE; struct SYSTEM_ALARM_ACE { ACE_HEADER Header; ACCESS_MASK Mask; DWORD SidStart; } alias SYSTEM_ALARM_ACE* PSYSTEM_ALARM_ACE; struct ACCESS_ALLOWED_OBJECT_ACE { ACE_HEADER Header; ACCESS_MASK Mask; DWORD Flags; GUID ObjectType; GUID InheritedObjectType; DWORD SidStart; } alias ACCESS_ALLOWED_OBJECT_ACE* PACCESS_ALLOWED_OBJECT_ACE; struct ACCESS_DENIED_OBJECT_ACE { ACE_HEADER Header; ACCESS_MASK Mask; DWORD Flags; GUID ObjectType; GUID InheritedObjectType; DWORD SidStart; } alias ACCESS_DENIED_OBJECT_ACE* PACCESS_DENIED_OBJECT_ACE; struct SYSTEM_AUDIT_OBJECT_ACE { ACE_HEADER Header; ACCESS_MASK Mask; DWORD Flags; GUID ObjectType; GUID InheritedObjectType; DWORD SidStart; } alias SYSTEM_AUDIT_OBJECT_ACE* PSYSTEM_AUDIT_OBJECT_ACE; struct SYSTEM_ALARM_OBJECT_ACE { ACE_HEADER Header; ACCESS_MASK Mask; DWORD Flags; GUID ObjectType; GUID InheritedObjectType; DWORD SidStart; } alias SYSTEM_ALARM_OBJECT_ACE* PSYSTEM_ALARM_OBJECT_ACE; struct ACL { BYTE AclRevision; BYTE Sbz1; WORD AclSize; WORD AceCount; WORD Sbz2; } alias ACL* PACL; struct ACL_REVISION_INFORMATION { DWORD AclRevision; } struct ACL_SIZE_INFORMATION { DWORD AceCount; DWORD AclBytesInUse; DWORD AclBytesFree; } version (X86) { // ??? enum SIZE_OF_80387_REGISTERS = 80; enum CONTEXT_i386 = 0x010000; enum CONTEXT_i486 = 0x010000; enum CONTEXT_CONTROL = CONTEXT_i386 | 0x01; enum CONTEXT_INTEGER = CONTEXT_i386 | 0x02; enum CONTEXT_SEGMENTS = CONTEXT_i386 | 0x04; enum CONTEXT_FLOATING_POINT = CONTEXT_i386 | 0x08; enum CONTEXT_DEBUG_REGISTERS = CONTEXT_i386 | 0x10; enum CONTEXT_EXTENDED_REGISTERS = CONTEXT_i386 | 0x20; enum CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; enum CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS; enum MAXIMUM_SUPPORTED_EXTENSION = 512; struct FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE[80] RegisterArea; DWORD Cr0NpxState; } struct CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE[MAXIMUM_SUPPORTED_EXTENSION] ExtendedRegisters; } } else version(X86_64) { enum CONTEXT_AMD64 = 0x100000; enum CONTEXT_CONTROL = (CONTEXT_AMD64 | 0x1L); enum CONTEXT_INTEGER = (CONTEXT_AMD64 | 0x2L); enum CONTEXT_SEGMENTS = (CONTEXT_AMD64 | 0x4L); enum CONTEXT_FLOATING_POINT = (CONTEXT_AMD64 | 0x8L); enum CONTEXT_DEBUG_REGISTERS = (CONTEXT_AMD64 | 0x10L); enum CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT); enum CONTEXT_ALL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS); enum CONTEXT_EXCEPTION_ACTIVE = 0x8000000; enum CONTEXT_SERVICE_ACTIVE = 0x10000000; enum CONTEXT_EXCEPTION_REQUEST = 0x40000000; enum CONTEXT_EXCEPTION_REPORTING = 0x80000000; enum INITIAL_MXCSR = 0x1f80; enum INITIAL_FPCSR = 0x027f; align(16) struct M128A { ULONGLONG Low; LONGLONG High; } alias M128A* PM128A; struct XMM_SAVE_AREA32 { WORD ControlWord; WORD StatusWord; BYTE TagWord; BYTE Reserved1; WORD ErrorOpcode; DWORD ErrorOffset; WORD ErrorSelector; WORD Reserved2; DWORD DataOffset; WORD DataSelector; WORD Reserved3; DWORD MxCsr; DWORD MxCsr_Mask; M128A[8] FloatRegisters; M128A[16] XmmRegisters; BYTE[96] Reserved4; } alias XMM_SAVE_AREA32 PXMM_SAVE_AREA32; enum LEGACY_SAVE_AREA_LENGTH = XMM_SAVE_AREA32.sizeof; align(16) struct CONTEXT { DWORD64 P1Home; DWORD64 P2Home; DWORD64 P3Home; DWORD64 P4Home; DWORD64 P5Home; DWORD64 P6Home; DWORD ContextFlags; DWORD MxCsr; WORD SegCs; WORD SegDs; WORD SegEs; WORD SegFs; WORD SegGs; WORD SegSs; DWORD EFlags; DWORD64 Dr0; DWORD64 Dr1; DWORD64 Dr2; DWORD64 Dr3; DWORD64 Dr6; DWORD64 Dr7; DWORD64 Rax; DWORD64 Rcx; DWORD64 Rdx; DWORD64 Rbx; DWORD64 Rsp; DWORD64 Rbp; DWORD64 Rsi; DWORD64 Rdi; DWORD64 R8; DWORD64 R9; DWORD64 R10; DWORD64 R11; DWORD64 R12; DWORD64 R13; DWORD64 R14; DWORD64 R15; DWORD64 Rip; union { XMM_SAVE_AREA32 FltSave; XMM_SAVE_AREA32 FloatSave; struct { M128A[2] Header; M128A[8] Legacy; M128A Xmm0; M128A Xmm1; M128A Xmm2; M128A Xmm3; M128A Xmm4; M128A Xmm5; M128A Xmm6; M128A Xmm7; M128A Xmm8; M128A Xmm9; M128A Xmm10; M128A Xmm11; M128A Xmm12; M128A Xmm13; M128A Xmm14; M128A Xmm15; }; }; M128A[26] VectorRegister; DWORD64 VectorControl; DWORD64 DebugControl; DWORD64 LastBranchToRip; DWORD64 LastBranchFromRip; DWORD64 LastExceptionToRip; DWORD64 LastExceptionFromRip; } } else { static assert(false, "Unsupported CPU"); // Versions for PowerPC, Alpha, SHX, and MIPS removed. } alias CONTEXT* PCONTEXT, LPCONTEXT; struct EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; EXCEPTION_RECORD* ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; DWORD[EXCEPTION_MAXIMUM_PARAMETERS] ExceptionInformation; } alias EXCEPTION_RECORD* PEXCEPTION_RECORD, LPEXCEPTION_RECORD; struct EXCEPTION_POINTERS { PEXCEPTION_RECORD ExceptionRecord; PCONTEXT ContextRecord; } alias EXCEPTION_POINTERS* PEXCEPTION_POINTERS, LPEXCEPTION_POINTERS; union LARGE_INTEGER { struct { uint LowPart; int HighPart; } long QuadPart; } alias LARGE_INTEGER* PLARGE_INTEGER; union ULARGE_INTEGER { struct { uint LowPart; uint HighPart; } ulong QuadPart; } alias ULARGE_INTEGER* PULARGE_INTEGER; alias LARGE_INTEGER LUID; alias LUID* PLUID; enum LUID SYSTEM_LUID = { QuadPart:999 }; align(4) struct LUID_AND_ATTRIBUTES { LUID Luid; DWORD Attributes; } alias LUID_AND_ATTRIBUTES* PLUID_AND_ATTRIBUTES; struct PRIVILEGE_SET { DWORD PrivilegeCount; DWORD Control; LUID_AND_ATTRIBUTES _Privilege; LUID_AND_ATTRIBUTES* Privilege() return { return &_Privilege; } } alias PRIVILEGE_SET* PPRIVILEGE_SET; struct SECURITY_ATTRIBUTES { DWORD nLength; LPVOID lpSecurityDescriptor; BOOL bInheritHandle; } alias SECURITY_ATTRIBUTES* PSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES; struct SECURITY_QUALITY_OF_SERVICE { DWORD Length; SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; BOOLEAN EffectiveOnly; } alias SECURITY_QUALITY_OF_SERVICE* PSECURITY_QUALITY_OF_SERVICE; alias PVOID PACCESS_TOKEN; struct SE_IMPERSONATION_STATE { PACCESS_TOKEN Token; BOOLEAN CopyOnOpen; BOOLEAN EffectiveOnly; SECURITY_IMPERSONATION_LEVEL Level; } alias SE_IMPERSONATION_STATE* PSE_IMPERSONATION_STATE; struct SID_IDENTIFIER_AUTHORITY { BYTE[6] Value; } alias SID_IDENTIFIER_AUTHORITY* PSID_IDENTIFIER_AUTHORITY, LPSID_IDENTIFIER_AUTHORITY; alias PVOID PSID; struct SID { BYTE Revision; BYTE SubAuthorityCount; SID_IDENTIFIER_AUTHORITY IdentifierAuthority; DWORD _SubAuthority; DWORD* SubAuthority() return { return &_SubAuthority; } } alias SID* PISID; struct SID_AND_ATTRIBUTES { PSID Sid; DWORD Attributes; } alias SID_AND_ATTRIBUTES* PSID_AND_ATTRIBUTES; struct TOKEN_SOURCE { CHAR[TOKEN_SOURCE_LENGTH] SourceName; LUID SourceIdentifier; } alias TOKEN_SOURCE* PTOKEN_SOURCE; struct TOKEN_CONTROL { LUID TokenId; LUID AuthenticationId; LUID ModifiedId; TOKEN_SOURCE TokenSource; } alias TOKEN_CONTROL* PTOKEN_CONTROL; struct TOKEN_DEFAULT_DACL { PACL DefaultDacl; } alias TOKEN_DEFAULT_DACL* PTOKEN_DEFAULT_DACL; struct TOKEN_GROUPS { DWORD GroupCount; SID_AND_ATTRIBUTES _Groups; SID_AND_ATTRIBUTES* Groups() return { return &_Groups; } } alias TOKEN_GROUPS* PTOKEN_GROUPS, LPTOKEN_GROUPS; struct TOKEN_OWNER { PSID Owner; } alias TOKEN_OWNER* PTOKEN_OWNER; struct TOKEN_PRIMARY_GROUP { PSID PrimaryGroup; } alias TOKEN_PRIMARY_GROUP* PTOKEN_PRIMARY_GROUP; struct TOKEN_PRIVILEGES { DWORD PrivilegeCount; LUID_AND_ATTRIBUTES _Privileges; LUID_AND_ATTRIBUTES* Privileges() return { return &_Privileges; } } alias TOKEN_PRIVILEGES* PTOKEN_PRIVILEGES, LPTOKEN_PRIVILEGES; enum TOKEN_TYPE { TokenPrimary = 1, TokenImpersonation } alias TOKEN_TYPE* PTOKEN_TYPE; struct TOKEN_STATISTICS { LUID TokenId; LUID AuthenticationId; LARGE_INTEGER ExpirationTime; TOKEN_TYPE TokenType; SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; DWORD DynamicCharged; DWORD DynamicAvailable; DWORD GroupCount; DWORD PrivilegeCount; LUID ModifiedId; } alias TOKEN_STATISTICS* PTOKEN_STATISTICS; struct TOKEN_USER { SID_AND_ATTRIBUTES User; } alias TOKEN_USER* PTOKEN_USER; alias DWORD SECURITY_INFORMATION; alias SECURITY_INFORMATION* PSECURITY_INFORMATION; alias WORD SECURITY_DESCRIPTOR_CONTROL; alias SECURITY_DESCRIPTOR_CONTROL* PSECURITY_DESCRIPTOR_CONTROL; struct SECURITY_DESCRIPTOR { BYTE Revision; BYTE Sbz1; SECURITY_DESCRIPTOR_CONTROL Control; PSID Owner; PSID Group; PACL Sacl; PACL Dacl; } alias SECURITY_DESCRIPTOR* PSECURITY_DESCRIPTOR, PISECURITY_DESCRIPTOR; enum TOKEN_INFORMATION_CLASS { TokenUser = 1, TokenGroups, TokenPrivileges, TokenOwner, TokenPrimaryGroup, TokenDefaultDacl, TokenSource, TokenType, TokenImpersonationLevel, TokenStatistics, TokenRestrictedSids, TokenSessionId, TokenGroupsAndPrivileges, TokenSessionReference, TokenSandBoxInert, TokenAuditPolicy, TokenOrigin } enum SID_NAME_USE { SidTypeUser = 1, SidTypeGroup, SidTypeDomain, SidTypeAlias, SidTypeWellKnownGroup, SidTypeDeletedAccount, SidTypeInvalid, SidTypeUnknown, SidTypeComputer } alias SID_NAME_USE* PSID_NAME_USE; struct QUOTA_LIMITS { SIZE_T PagedPoolLimit; SIZE_T NonPagedPoolLimit; SIZE_T MinimumWorkingSetSize; SIZE_T MaximumWorkingSetSize; SIZE_T PagefileLimit; LARGE_INTEGER TimeLimit; } alias QUOTA_LIMITS* PQUOTA_LIMITS; struct IO_COUNTERS { ULONGLONG ReadOperationCount; ULONGLONG WriteOperationCount; ULONGLONG OtherOperationCount; ULONGLONG ReadTransferCount; ULONGLONG WriteTransferCount; ULONGLONG OtherTransferCount; } alias IO_COUNTERS* PIO_COUNTERS; struct FILE_NOTIFY_INFORMATION { DWORD NextEntryOffset; DWORD Action; DWORD FileNameLength; WCHAR _FileName; WCHAR* FileName() return { return &_FileName; } } alias FILE_NOTIFY_INFORMATION* PFILE_NOTIFY_INFORMATION; struct TAPE_ERASE { DWORD Type; BOOLEAN Immediate; } alias TAPE_ERASE* PTAPE_ERASE; struct TAPE_GET_DRIVE_PARAMETERS { BOOLEAN ECC; BOOLEAN Compression; BOOLEAN DataPadding; BOOLEAN ReportSetmarks; DWORD DefaultBlockSize; DWORD MaximumBlockSize; DWORD MinimumBlockSize; DWORD MaximumPartitionCount; DWORD FeaturesLow; DWORD FeaturesHigh; DWORD EOTWarningZoneSize; } alias TAPE_GET_DRIVE_PARAMETERS* PTAPE_GET_DRIVE_PARAMETERS; struct TAPE_GET_MEDIA_PARAMETERS { LARGE_INTEGER Capacity; LARGE_INTEGER Remaining; DWORD BlockSize; DWORD PartitionCount; BOOLEAN WriteProtected; } alias TAPE_GET_MEDIA_PARAMETERS* PTAPE_GET_MEDIA_PARAMETERS; struct TAPE_GET_POSITION { ULONG Type; ULONG Partition; ULONG OffsetLow; ULONG OffsetHigh; } alias TAPE_GET_POSITION* PTAPE_GET_POSITION; struct TAPE_PREPARE { DWORD Operation; BOOLEAN Immediate; } alias TAPE_PREPARE* PTAPE_PREPARE; struct TAPE_SET_DRIVE_PARAMETERS { BOOLEAN ECC; BOOLEAN Compression; BOOLEAN DataPadding; BOOLEAN ReportSetmarks; ULONG EOTWarningZoneSize; } alias TAPE_SET_DRIVE_PARAMETERS* PTAPE_SET_DRIVE_PARAMETERS; struct TAPE_SET_MEDIA_PARAMETERS { ULONG BlockSize; } alias TAPE_SET_MEDIA_PARAMETERS* PTAPE_SET_MEDIA_PARAMETERS; struct TAPE_SET_POSITION { DWORD Method; DWORD Partition; LARGE_INTEGER Offset; BOOLEAN Immediate; } alias TAPE_SET_POSITION* PTAPE_SET_POSITION; struct TAPE_WRITE_MARKS { DWORD Type; DWORD Count; BOOLEAN Immediate; } alias TAPE_WRITE_MARKS* PTAPE_WRITE_MARKS; struct TAPE_CREATE_PARTITION { DWORD Method; DWORD Count; DWORD Size; } alias TAPE_CREATE_PARTITION* PTAPE_CREATE_PARTITION; struct MEMORY_BASIC_INFORMATION { PVOID BaseAddress; PVOID AllocationBase; DWORD AllocationProtect; DWORD RegionSize; DWORD State; DWORD Protect; DWORD Type; } alias MEMORY_BASIC_INFORMATION* PMEMORY_BASIC_INFORMATION; struct MESSAGE_RESOURCE_ENTRY { WORD Length; WORD Flags; BYTE _Text; BYTE* Text() return { return &_Text; } } alias MESSAGE_RESOURCE_ENTRY* PMESSAGE_RESOURCE_ENTRY; struct MESSAGE_RESOURCE_BLOCK { DWORD LowId; DWORD HighId; DWORD OffsetToEntries; } alias MESSAGE_RESOURCE_BLOCK* PMESSAGE_RESOURCE_BLOCK; struct MESSAGE_RESOURCE_DATA { DWORD NumberOfBlocks; MESSAGE_RESOURCE_BLOCK _Blocks; MESSAGE_RESOURCE_BLOCK* Blocks() return { return &_Blocks; } } alias MESSAGE_RESOURCE_DATA* PMESSAGE_RESOURCE_DATA; struct LIST_ENTRY { LIST_ENTRY* Flink; LIST_ENTRY* Blink; } alias LIST_ENTRY* PLIST_ENTRY; alias LIST_ENTRY _LIST_ENTRY; struct SINGLE_LIST_ENTRY { SINGLE_LIST_ENTRY* Next; } alias SINGLE_LIST_ENTRY SLIST_ENTRY; alias SINGLE_LIST_ENTRY* PSINGLE_LIST_ENTRY, PSLIST_ENTRY; union SLIST_HEADER { ULONGLONG Alignment; struct { SLIST_ENTRY Next; WORD Depth; WORD Sequence; } } alias SLIST_HEADER* PSLIST_HEADER; struct RTL_CRITICAL_SECTION_DEBUG { WORD Type; WORD CreatorBackTraceIndex; RTL_CRITICAL_SECTION* CriticalSection; LIST_ENTRY ProcessLocksList; DWORD EntryCount; DWORD ContentionCount; DWORD[2] Spare; } alias RTL_CRITICAL_SECTION_DEBUG* PRTL_CRITICAL_SECTION_DEBUG; alias RTL_CRITICAL_SECTION_DEBUG _RTL_CRITICAL_SECTION_DEBUG; struct RTL_CRITICAL_SECTION { PRTL_CRITICAL_SECTION_DEBUG DebugInfo; LONG LockCount; LONG RecursionCount; HANDLE OwningThread; HANDLE LockSemaphore; ULONG_PTR SpinCount; alias Reserved = SpinCount; } alias RTL_CRITICAL_SECTION* PRTL_CRITICAL_SECTION; alias RTL_CRITICAL_SECTION _RTL_CRITICAL_SECTION; struct EVENTLOGRECORD { DWORD Length; DWORD Reserved; DWORD RecordNumber; DWORD TimeGenerated; DWORD TimeWritten; DWORD EventID; WORD EventType; WORD NumStrings; WORD EventCategory; WORD ReservedFlags; DWORD ClosingRecordNumber; DWORD StringOffset; DWORD UserSidLength; DWORD UserSidOffset; DWORD DataLength; DWORD DataOffset; } alias EVENTLOGRECORD* PEVENTLOGRECORD; struct OSVERSIONINFOA { DWORD dwOSVersionInfoSize = OSVERSIONINFOA.sizeof; DWORD dwMajorVersion; DWORD dwMinorVersion; DWORD dwBuildNumber; DWORD dwPlatformId; CHAR[128] szCSDVersion; } alias OSVERSIONINFOA* POSVERSIONINFOA, LPOSVERSIONINFOA; struct OSVERSIONINFOW { DWORD dwOSVersionInfoSize = OSVERSIONINFOW.sizeof; DWORD dwMajorVersion; DWORD dwMinorVersion; DWORD dwBuildNumber; DWORD dwPlatformId; WCHAR[128] szCSDVersion; } alias OSVERSIONINFOW* POSVERSIONINFOW, LPOSVERSIONINFOW; struct OSVERSIONINFOEXA { DWORD dwOSVersionInfoSize; DWORD dwMajorVersion; DWORD dwMinorVersion; DWORD dwBuildNumber; DWORD dwPlatformId; CHAR[128] szCSDVersion; WORD wServicePackMajor; WORD wServicePackMinor; WORD wSuiteMask; BYTE wProductType; BYTE wReserved; } alias OSVERSIONINFOEXA* POSVERSIONINFOEXA, LPOSVERSIONINFOEXA; struct OSVERSIONINFOEXW { DWORD dwOSVersionInfoSize; DWORD dwMajorVersion; DWORD dwMinorVersion; DWORD dwBuildNumber; DWORD dwPlatformId; WCHAR[128] szCSDVersion; WORD wServicePackMajor; WORD wServicePackMinor; WORD wSuiteMask; BYTE wProductType; BYTE wReserved; } alias OSVERSIONINFOEXW* POSVERSIONINFOEXW, LPOSVERSIONINFOEXW; align(2) struct IMAGE_VXD_HEADER { WORD e32_magic; BYTE e32_border; BYTE e32_worder; DWORD e32_level; WORD e32_cpu; WORD e32_os; DWORD e32_ver; DWORD e32_mflags; DWORD e32_mpages; DWORD e32_startobj; DWORD e32_eip; DWORD e32_stackobj; DWORD e32_esp; DWORD e32_pagesize; DWORD e32_lastpagesize; DWORD e32_fixupsize; DWORD e32_fixupsum; DWORD e32_ldrsize; DWORD e32_ldrsum; DWORD e32_objtab; DWORD e32_objcnt; DWORD e32_objmap; DWORD e32_itermap; DWORD e32_rsrctab; DWORD e32_rsrccnt; DWORD e32_restab; DWORD e32_enttab; DWORD e32_dirtab; DWORD e32_dircnt; DWORD e32_fpagetab; DWORD e32_frectab; DWORD e32_impmod; DWORD e32_impmodcnt; DWORD e32_impproc; DWORD e32_pagesum; DWORD e32_datapage; DWORD e32_preload; DWORD e32_nrestab; DWORD e32_cbnrestab; DWORD e32_nressum; DWORD e32_autodata; DWORD e32_debuginfo; DWORD e32_debuglen; DWORD e32_instpreload; DWORD e32_instdemand; DWORD e32_heapsize; BYTE[12] e32_res3; DWORD e32_winresoff; DWORD e32_winreslen; WORD e32_devid; WORD e32_ddkver; } alias IMAGE_VXD_HEADER* PIMAGE_VXD_HEADER; align(4): struct IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } alias IMAGE_FILE_HEADER* PIMAGE_FILE_HEADER; // const IMAGE_SIZEOF_FILE_HEADER = IMAGE_FILE_HEADER.sizeof; struct IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } alias IMAGE_DATA_DIRECTORY* PIMAGE_DATA_DIRECTORY; struct IMAGE_OPTIONAL_HEADER32 { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] DataDirectory; } alias IMAGE_OPTIONAL_HEADER32* PIMAGE_OPTIONAL_HEADER32; struct IMAGE_OPTIONAL_HEADER64 { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; ULONGLONG ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; ULONGLONG SizeOfStackReserve; ULONGLONG SizeOfStackCommit; ULONGLONG SizeOfHeapReserve; ULONGLONG SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] DataDirectory; } alias IMAGE_OPTIONAL_HEADER64* PIMAGE_OPTIONAL_HEADER64; struct IMAGE_ROM_OPTIONAL_HEADER { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; DWORD BaseOfBss; DWORD GprMask; DWORD[4] CprMask; DWORD GpValue; } alias IMAGE_ROM_OPTIONAL_HEADER* PIMAGE_ROM_OPTIONAL_HEADER; align(2): struct IMAGE_DOS_HEADER { WORD e_magic; WORD e_cblp; WORD e_cp; WORD e_crlc; WORD e_cparhdr; WORD e_minalloc; WORD e_maxalloc; WORD e_ss; WORD e_sp; WORD e_csum; WORD e_ip; WORD e_cs; WORD e_lfarlc; WORD e_ovno; WORD[4] e_res; WORD e_oemid; WORD e_oeminfo; WORD[10] e_res2; LONG e_lfanew; } alias IMAGE_DOS_HEADER* PIMAGE_DOS_HEADER; struct IMAGE_OS2_HEADER { WORD ne_magic; CHAR ne_ver; CHAR ne_rev; WORD ne_enttab; WORD ne_cbenttab; LONG ne_crc; WORD ne_flags; WORD ne_autodata; WORD ne_heap; WORD ne_stack; LONG ne_csip; LONG ne_sssp; WORD ne_cseg; WORD ne_cmod; WORD ne_cbnrestab; WORD ne_segtab; WORD ne_rsrctab; WORD ne_restab; WORD ne_modtab; WORD ne_imptab; LONG ne_nrestab; WORD ne_cmovent; WORD ne_align; WORD ne_cres; BYTE ne_exetyp; BYTE ne_flagsothers; WORD ne_pretthunks; WORD ne_psegrefbytes; WORD ne_swaparea; WORD ne_expver; } alias IMAGE_OS2_HEADER* PIMAGE_OS2_HEADER; align(4) struct IMAGE_NT_HEADERS32 { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER OptionalHeader; } alias IMAGE_NT_HEADERS32* PIMAGE_NT_HEADERS32; align(4) struct IMAGE_NT_HEADERS64 { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER OptionalHeader; } alias IMAGE_NT_HEADERS64* PIMAGE_NT_HEADERS64; struct IMAGE_ROM_HEADERS { IMAGE_FILE_HEADER FileHeader; IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; } alias IMAGE_ROM_HEADERS* PIMAGE_ROM_HEADERS; struct IMAGE_SECTION_HEADER { BYTE[IMAGE_SIZEOF_SHORT_NAME] Name; union _Misc { DWORD PhysicalAddress; DWORD VirtualSize; } _Misc Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } alias IMAGE_SECTION_HEADER* PIMAGE_SECTION_HEADER; struct IMAGE_SYMBOL { union _N { BYTE[8] ShortName; struct Name { DWORD Short; DWORD Long; } PBYTE[2] LongName; } _N N; DWORD Value; SHORT SectionNumber; WORD Type; BYTE StorageClass; BYTE NumberOfAuxSymbols; } alias IMAGE_SYMBOL* PIMAGE_SYMBOL; union IMAGE_AUX_SYMBOL { struct _Sym { DWORD TagIndex; union _Misc { struct _LnSz { WORD Linenumber; WORD Size; } _LnSz LnSz; DWORD TotalSize; } _Misc Misc; union _FcnAry { struct _Function { DWORD PointerToLinenumber; DWORD PointerToNextFunction; } _Function Function; struct _Array { WORD[4] Dimension; } _Array Array; } _FcnAry FcnAry; WORD TvIndex; } _Sym Sym; struct _File { BYTE[IMAGE_SIZEOF_SYMBOL] Name; } _File File; struct _Section { DWORD Length; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD CheckSum; SHORT Number; BYTE Selection; } _Section Section; } alias IMAGE_AUX_SYMBOL* PIMAGE_AUX_SYMBOL; struct IMAGE_COFF_SYMBOLS_HEADER { DWORD NumberOfSymbols; DWORD LvaToFirstSymbol; DWORD NumberOfLinenumbers; DWORD LvaToFirstLinenumber; DWORD RvaToFirstByteOfCode; DWORD RvaToLastByteOfCode; DWORD RvaToFirstByteOfData; DWORD RvaToLastByteOfData; } alias IMAGE_COFF_SYMBOLS_HEADER* PIMAGE_COFF_SYMBOLS_HEADER; struct IMAGE_RELOCATION { union { DWORD VirtualAddress; DWORD RelocCount; } DWORD SymbolTableIndex; WORD Type; } alias IMAGE_RELOCATION* PIMAGE_RELOCATION; align(4) struct IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; } alias IMAGE_BASE_RELOCATION* PIMAGE_BASE_RELOCATION; align(2) struct IMAGE_LINENUMBER { union _Type { DWORD SymbolTableIndex; DWORD VirtualAddress; } _Type Type; WORD Linenumber; } alias IMAGE_LINENUMBER* PIMAGE_LINENUMBER; align(4): struct IMAGE_ARCHIVE_MEMBER_HEADER { BYTE[16] Name; BYTE[12] Date; BYTE[6] UserID; BYTE[6] GroupID; BYTE[8] Mode; BYTE[10] Size; BYTE[2] EndHeader; } alias IMAGE_ARCHIVE_MEMBER_HEADER* PIMAGE_ARCHIVE_MEMBER_HEADER; struct IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; DWORD Base; DWORD NumberOfFunctions; DWORD NumberOfNames; DWORD AddressOfFunctions; DWORD AddressOfNames; DWORD AddressOfNameOrdinals; } alias IMAGE_EXPORT_DIRECTORY* PIMAGE_EXPORT_DIRECTORY; struct IMAGE_IMPORT_BY_NAME { WORD Hint; BYTE _Name; BYTE* Name() return { return &_Name; } } alias IMAGE_IMPORT_BY_NAME* PIMAGE_IMPORT_BY_NAME; struct IMAGE_THUNK_DATA32 { union _u1 { DWORD ForwarderString; DWORD Function; DWORD Ordinal; DWORD AddressOfData; } _u1 u1; } alias IMAGE_THUNK_DATA32* PIMAGE_THUNK_DATA32; struct IMAGE_THUNK_DATA64 { union _u1 { ULONGLONG ForwarderString; ULONGLONG Function; ULONGLONG Ordinal; ULONGLONG AddressOfData; } _u1 u1; } alias IMAGE_THUNK_DATA64* PIMAGE_THUNK_DATA64; struct IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; DWORD OriginalFirstThunk; } DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; DWORD FirstThunk; } alias IMAGE_IMPORT_DESCRIPTOR* PIMAGE_IMPORT_DESCRIPTOR; struct IMAGE_BOUND_IMPORT_DESCRIPTOR { DWORD TimeDateStamp; WORD OffsetModuleName; WORD NumberOfModuleForwarderRefs; } alias IMAGE_BOUND_IMPORT_DESCRIPTOR* PIMAGE_BOUND_IMPORT_DESCRIPTOR; struct IMAGE_BOUND_FORWARDER_REF { DWORD TimeDateStamp; WORD OffsetModuleName; WORD Reserved; } alias IMAGE_BOUND_FORWARDER_REF* PIMAGE_BOUND_FORWARDER_REF; struct IMAGE_TLS_DIRECTORY32 { DWORD StartAddressOfRawData; DWORD EndAddressOfRawData; DWORD AddressOfIndex; DWORD AddressOfCallBacks; DWORD SizeOfZeroFill; DWORD Characteristics; } alias IMAGE_TLS_DIRECTORY32* PIMAGE_TLS_DIRECTORY32; struct IMAGE_TLS_DIRECTORY64 { ULONGLONG StartAddressOfRawData; ULONGLONG EndAddressOfRawData; ULONGLONG AddressOfIndex; ULONGLONG AddressOfCallBacks; DWORD SizeOfZeroFill; DWORD Characteristics; } alias IMAGE_TLS_DIRECTORY64* PIMAGE_TLS_DIRECTORY64; struct IMAGE_RESOURCE_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; WORD NumberOfNamedEntries; WORD NumberOfIdEntries; } alias IMAGE_RESOURCE_DIRECTORY* PIMAGE_RESOURCE_DIRECTORY; struct IMAGE_RESOURCE_DIRECTORY_ENTRY { union { /+struct { DWORD NameOffset:31; DWORD NameIsString:1; }+/ DWORD Name; WORD Id; } DWORD OffsetToData; /+struct { DWORD OffsetToDirectory:31; DWORD DataIsDirectory:1; }+/ uint NameOffset() { return Name & 0x7FFFFFFF; } bool NameIsString() { return cast(bool)(Name & 0x80000000); } uint OffsetToDirectory() { return OffsetToData & 0x7FFFFFFF; } bool DataIsDirectory() { return cast(bool)(OffsetToData & 0x80000000); } uint NameOffset(uint n) { Name = (Name & 0x80000000) | (n & 0x7FFFFFFF); return n & 0x7FFFFFFF; } bool NameIsString(bool n) { Name = (Name & 0x7FFFFFFF) | (n << 31); return n; } uint OffsetToDirectory(uint o) { OffsetToData = (OffsetToData & 0x80000000) | (o & 0x7FFFFFFF); return o & 0x7FFFFFFF; } bool DataIsDirectory(bool d) { OffsetToData = (OffsetToData & 0x7FFFFFFF) | (d << 31); return d; } } alias IMAGE_RESOURCE_DIRECTORY_ENTRY* PIMAGE_RESOURCE_DIRECTORY_ENTRY; struct IMAGE_RESOURCE_DIRECTORY_STRING { WORD Length; CHAR _NameString; CHAR* NameString() return { return &_NameString; } } alias IMAGE_RESOURCE_DIRECTORY_STRING* PIMAGE_RESOURCE_DIRECTORY_STRING; struct IMAGE_RESOURCE_DIR_STRING_U { WORD Length; WCHAR _NameString; WCHAR* NameString() return { return &_NameString; } } alias IMAGE_RESOURCE_DIR_STRING_U* PIMAGE_RESOURCE_DIR_STRING_U; struct IMAGE_RESOURCE_DATA_ENTRY { DWORD OffsetToData; DWORD Size; DWORD CodePage; DWORD Reserved; } alias IMAGE_RESOURCE_DATA_ENTRY* PIMAGE_RESOURCE_DATA_ENTRY; struct IMAGE_LOAD_CONFIG_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD GlobalFlagsClear; DWORD GlobalFlagsSet; DWORD CriticalSectionDefaultTimeout; DWORD DeCommitFreeBlockThreshold; DWORD DeCommitTotalFreeThreshold; PVOID LockPrefixTable; DWORD MaximumAllocationSize; DWORD VirtualMemoryThreshold; DWORD ProcessHeapFlags; DWORD[4] Reserved; } alias IMAGE_LOAD_CONFIG_DIRECTORY* PIMAGE_LOAD_CONFIG_DIRECTORY; struct IMAGE_LOAD_CONFIG_DIRECTORY64 { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD GlobalFlagsClear; DWORD GlobalFlagsSet; DWORD CriticalSectionDefaultTimeout; ULONGLONG DeCommitFreeBlockThreshold; ULONGLONG DeCommitTotalFreeThreshold; ULONGLONG LockPrefixTable; ULONGLONG MaximumAllocationSize; ULONGLONG VirtualMemoryThreshold; ULONGLONG ProcessAffinityMask; DWORD ProcessHeapFlags; WORD CSDFlags; WORD Reserved1; ULONGLONG EditList; DWORD[2] Reserved; } alias IMAGE_LOAD_CONFIG_DIRECTORY64* PIMAGE_LOAD_CONFIG_DIRECTORY64; struct IMAGE_RUNTIME_FUNCTION_ENTRY { DWORD BeginAddress; DWORD EndAddress; PVOID ExceptionHandler; PVOID HandlerData; DWORD PrologEndAddress; } alias IMAGE_RUNTIME_FUNCTION_ENTRY* PIMAGE_RUNTIME_FUNCTION_ENTRY; struct IMAGE_CE_RUNTIME_FUNCTION_ENTRY { uint FuncStart; union { ubyte PrologLen; uint _bf; } /+ unsigned int FuncLen:22; unsigned int ThirtyTwoBit:1; unsigned int ExceptionFlag:1; +/ uint FuncLen() { return (_bf >> 8) & 0x3FFFFF; } bool ThirtyTwoBit() { return cast(bool)(_bf & 0x40000000); } bool ExceptionFlag() { return cast(bool)(_bf & 0x80000000); } uint FuncLen(uint f) { _bf = (_bf & ~0x3FFFFF00) | ((f & 0x3FFFFF) << 8); return f & 0x3FFFFF; } bool ThirtyTwoBit(bool t) { _bf = (_bf & ~0x40000000) | (t << 30); return t; } bool ExceptionFlag(bool e) { _bf = (_bf & ~0x80000000) | (e << 31); return e; } } alias IMAGE_CE_RUNTIME_FUNCTION_ENTRY* PIMAGE_CE_RUNTIME_FUNCTION_ENTRY; struct IMAGE_DEBUG_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Type; DWORD SizeOfData; DWORD AddressOfRawData; DWORD PointerToRawData; } alias IMAGE_DEBUG_DIRECTORY* PIMAGE_DEBUG_DIRECTORY; struct FPO_DATA { DWORD ulOffStart; DWORD cbProcSize; DWORD cdwLocals; WORD cdwParams; ubyte cbProlog; ubyte _bf; /+ WORD cbRegs:3; WORD fHasSEH:1; WORD fUseBP:1; WORD reserved:1; WORD cbFrame:2; +/ ubyte cbRegs() { return cast(ubyte)(_bf & 0x07); } bool fHasSEH() { return cast(bool)(_bf & 0x08); } bool fUseBP() { return cast(bool)(_bf & 0x10); } bool reserved() { return cast(bool)(_bf & 0x20); } ubyte cbFrame() { return cast(ubyte)(_bf >> 6); } ubyte cbRegs(ubyte c) { _bf = cast(ubyte) ((_bf & ~0x07) | (c & 0x07)); return cast(ubyte)(c & 0x07); } bool fHasSEH(bool f) { _bf = cast(ubyte)((_bf & ~0x08) | (f << 3)); return f; } bool fUseBP(bool f) { _bf = cast(ubyte)((_bf & ~0x10) | (f << 4)); return f; } bool reserved(bool r) { _bf = cast(ubyte)((_bf & ~0x20) | (r << 5)); return r; } ubyte cbFrame(ubyte c) { _bf = cast(ubyte) ((_bf & ~0xC0) | ((c & 0x03) << 6)); return cast(ubyte)(c & 0x03); } } alias FPO_DATA* PFPO_DATA; struct IMAGE_DEBUG_MISC { DWORD DataType; DWORD Length; BOOLEAN Unicode; BYTE[3] Reserved; BYTE _Data; BYTE* Data() return { return &_Data; } } alias IMAGE_DEBUG_MISC* PIMAGE_DEBUG_MISC; struct IMAGE_FUNCTION_ENTRY { DWORD StartingAddress; DWORD EndingAddress; DWORD EndOfPrologue; } alias IMAGE_FUNCTION_ENTRY* PIMAGE_FUNCTION_ENTRY; struct IMAGE_FUNCTION_ENTRY64 { ULONGLONG StartingAddress; ULONGLONG EndingAddress; union { ULONGLONG EndOfPrologue; ULONGLONG UnwindInfoAddress; } } alias IMAGE_FUNCTION_ENTRY64* PIMAGE_FUNCTION_ENTRY64; struct IMAGE_SEPARATE_DEBUG_HEADER { WORD Signature; WORD Flags; WORD Machine; WORD Characteristics; DWORD TimeDateStamp; DWORD CheckSum; DWORD ImageBase; DWORD SizeOfImage; DWORD NumberOfSections; DWORD ExportedNamesSize; DWORD DebugDirectorySize; DWORD SectionAlignment; DWORD[2] Reserved; } alias IMAGE_SEPARATE_DEBUG_HEADER* PIMAGE_SEPARATE_DEBUG_HEADER; enum SERVICE_NODE_TYPE { DriverType = SERVICE_KERNEL_DRIVER, FileSystemType = SERVICE_FILE_SYSTEM_DRIVER, Win32ServiceOwnProcess = SERVICE_WIN32_OWN_PROCESS, Win32ServiceShareProcess = SERVICE_WIN32_SHARE_PROCESS, AdapterType = SERVICE_ADAPTER, RecognizerType = SERVICE_RECOGNIZER_DRIVER } enum SERVICE_LOAD_TYPE { BootLoad = SERVICE_BOOT_START, SystemLoad = SERVICE_SYSTEM_START, AutoLoad = SERVICE_AUTO_START, DemandLoad = SERVICE_DEMAND_START, DisableLoad = SERVICE_DISABLED } enum SERVICE_ERROR_TYPE { IgnoreError = SERVICE_ERROR_IGNORE, NormalError = SERVICE_ERROR_NORMAL, SevereError = SERVICE_ERROR_SEVERE, CriticalError = SERVICE_ERROR_CRITICAL } alias SERVICE_ERROR_TYPE _CM_ERROR_CONTROL_TYPE; //DAC: According to MSJ, 'UnderTheHood', May 1996, this // structure is not documented in any official Microsoft header file. alias void EXCEPTION_REGISTRATION_RECORD; align: struct NT_TIB { EXCEPTION_REGISTRATION_RECORD *ExceptionList; PVOID StackBase; PVOID StackLimit; PVOID SubSystemTib; union { PVOID FiberData; DWORD Version; } PVOID ArbitraryUserPointer; NT_TIB *Self; } alias NT_TIB* PNT_TIB; struct REPARSE_DATA_BUFFER { DWORD ReparseTag; WORD ReparseDataLength; WORD Reserved; union { struct _GenericReparseBuffer { BYTE _DataBuffer; BYTE* DataBuffer() return { return &_DataBuffer; } } _GenericReparseBuffer GenericReparseBuffer; struct _SymbolicLinkReparseBuffer { WORD SubstituteNameOffset; WORD SubstituteNameLength; WORD PrintNameOffset; WORD PrintNameLength; // ??? This is in MinGW, but absent in MSDN docs ULONG Flags; WCHAR _PathBuffer; WCHAR* PathBuffer() return { return &_PathBuffer; } } _SymbolicLinkReparseBuffer SymbolicLinkReparseBuffer; struct _MountPointReparseBuffer { WORD SubstituteNameOffset; WORD SubstituteNameLength; WORD PrintNameOffset; WORD PrintNameLength; WCHAR _PathBuffer; WCHAR* PathBuffer() return { return &_PathBuffer; } } _MountPointReparseBuffer MountPointReparseBuffer; } } alias REPARSE_DATA_BUFFER *PREPARSE_DATA_BUFFER; struct REPARSE_GUID_DATA_BUFFER { DWORD ReparseTag; WORD ReparseDataLength; WORD Reserved; GUID ReparseGuid; struct _GenericReparseBuffer { BYTE _DataBuffer; BYTE* DataBuffer() return { return &_DataBuffer; } } _GenericReparseBuffer GenericReparseBuffer; } alias REPARSE_GUID_DATA_BUFFER* PREPARSE_GUID_DATA_BUFFER; enum size_t REPARSE_DATA_BUFFER_HEADER_SIZE = REPARSE_DATA_BUFFER.GenericReparseBuffer.offsetof, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE = REPARSE_GUID_DATA_BUFFER.GenericReparseBuffer.offsetof, MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384; struct REPARSE_POINT_INFORMATION { WORD ReparseDataLength; WORD UnparsedNameLength; } alias REPARSE_POINT_INFORMATION* PREPARSE_POINT_INFORMATION; union FILE_SEGMENT_ELEMENT { PVOID64 Buffer; ULONGLONG Alignment; } alias FILE_SEGMENT_ELEMENT* PFILE_SEGMENT_ELEMENT; // JOBOBJECT_BASIC_LIMIT_INFORMATION.LimitFlags constants enum DWORD JOB_OBJECT_LIMIT_WORKINGSET = 0x0001, JOB_OBJECT_LIMIT_PROCESS_TIME = 0x0002, JOB_OBJECT_LIMIT_JOB_TIME = 0x0004, JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x0008, JOB_OBJECT_LIMIT_AFFINITY = 0x0010, JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x0020, JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x0040, JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x0080, JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x0100, JOB_OBJECT_LIMIT_JOB_MEMORY = 0x0200, JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x0400, JOB_OBJECT_BREAKAWAY_OK = 0x0800, JOB_OBJECT_SILENT_BREAKAWAY = 0x1000; // JOBOBJECT_BASIC_UI_RESTRICTIONS.UIRestrictionsClass constants enum DWORD JOB_OBJECT_UILIMIT_HANDLES = 0x0001, JOB_OBJECT_UILIMIT_READCLIPBOARD = 0x0002, JOB_OBJECT_UILIMIT_WRITECLIPBOARD = 0x0004, JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS = 0x0008, JOB_OBJECT_UILIMIT_DISPLAYSETTINGS = 0x0010, JOB_OBJECT_UILIMIT_GLOBALATOMS = 0x0020, JOB_OBJECT_UILIMIT_DESKTOP = 0x0040, JOB_OBJECT_UILIMIT_EXITWINDOWS = 0x0080; // JOBOBJECT_SECURITY_LIMIT_INFORMATION.SecurityLimitFlags constants enum DWORD JOB_OBJECT_SECURITY_NO_ADMIN = 0x0001, JOB_OBJECT_SECURITY_RESTRICTED_TOKEN = 0x0002, JOB_OBJECT_SECURITY_ONLY_TOKEN = 0x0004, JOB_OBJECT_SECURITY_FILTER_TOKENS = 0x0008; // JOBOBJECT_END_OF_JOB_TIME_INFORMATION.EndOfJobTimeAction constants enum : DWORD { JOB_OBJECT_TERMINATE_AT_END_OF_JOB, JOB_OBJECT_POST_AT_END_OF_JOB } enum : DWORD { JOB_OBJECT_MSG_END_OF_JOB_TIME = 1, JOB_OBJECT_MSG_END_OF_PROCESS_TIME, JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, JOB_OBJECT_MSG_NEW_PROCESS, JOB_OBJECT_MSG_EXIT_PROCESS, JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS, JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT, JOB_OBJECT_MSG_JOB_MEMORY_LIMIT } enum JOBOBJECTINFOCLASS { JobObjectBasicAccountingInformation = 1, JobObjectBasicLimitInformation, JobObjectBasicProcessIdList, JobObjectBasicUIRestrictions, JobObjectSecurityLimitInformation, JobObjectEndOfJobTimeInformation, JobObjectAssociateCompletionPortInformation, JobObjectBasicAndIoAccountingInformation, JobObjectExtendedLimitInformation, JobObjectJobSetInformation, MaxJobObjectInfoClass } struct JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { LARGE_INTEGER TotalUserTime; LARGE_INTEGER TotalKernelTime; LARGE_INTEGER ThisPeriodTotalUserTime; LARGE_INTEGER ThisPeriodTotalKernelTime; DWORD TotalPageFaultCount; DWORD TotalProcesses; DWORD ActiveProcesses; DWORD TotalTerminatedProcesses; } alias JOBOBJECT_BASIC_ACCOUNTING_INFORMATION* PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION; struct JOBOBJECT_BASIC_LIMIT_INFORMATION { LARGE_INTEGER PerProcessUserTimeLimit; LARGE_INTEGER PerJobUserTimeLimit; DWORD LimitFlags; SIZE_T MinimumWorkingSetSize; SIZE_T MaximumWorkingSetSize; DWORD ActiveProcessLimit; ULONG_PTR Affinity; DWORD PriorityClass; DWORD SchedulingClass; } alias JOBOBJECT_BASIC_LIMIT_INFORMATION* PJOBOBJECT_BASIC_LIMIT_INFORMATION; struct JOBOBJECT_BASIC_PROCESS_ID_LIST { DWORD NumberOfAssignedProcesses; DWORD NumberOfProcessIdsInList; ULONG_PTR _ProcessIdList; ULONG_PTR* ProcessIdList() return { return &_ProcessIdList; } } alias JOBOBJECT_BASIC_PROCESS_ID_LIST* PJOBOBJECT_BASIC_PROCESS_ID_LIST; struct JOBOBJECT_BASIC_UI_RESTRICTIONS { DWORD UIRestrictionsClass; } alias JOBOBJECT_BASIC_UI_RESTRICTIONS* PJOBOBJECT_BASIC_UI_RESTRICTIONS; struct JOBOBJECT_SECURITY_LIMIT_INFORMATION { DWORD SecurityLimitFlags; HANDLE JobToken; PTOKEN_GROUPS SidsToDisable; PTOKEN_PRIVILEGES PrivilegesToDelete; PTOKEN_GROUPS RestrictedSids; } alias JOBOBJECT_SECURITY_LIMIT_INFORMATION* PJOBOBJECT_SECURITY_LIMIT_INFORMATION; struct JOBOBJECT_END_OF_JOB_TIME_INFORMATION { DWORD EndOfJobTimeAction; } alias JOBOBJECT_END_OF_JOB_TIME_INFORMATION* PJOBOBJECT_END_OF_JOB_TIME_INFORMATION; struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT { PVOID CompletionKey; HANDLE CompletionPort; } alias JOBOBJECT_ASSOCIATE_COMPLETION_PORT* PJOBOBJECT_ASSOCIATE_COMPLETION_PORT; struct JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION { JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; IO_COUNTERS IoInfo; } alias JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION *PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION; struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; IO_COUNTERS IoInfo; SIZE_T ProcessMemoryLimit; SIZE_T JobMemoryLimit; SIZE_T PeakProcessMemoryUsed; SIZE_T PeakJobMemoryUsed; } alias JOBOBJECT_EXTENDED_LIMIT_INFORMATION* PJOBOBJECT_EXTENDED_LIMIT_INFORMATION; struct JOBOBJECT_JOBSET_INFORMATION { DWORD MemberLevel; } alias JOBOBJECT_JOBSET_INFORMATION* PJOBOBJECT_JOBSET_INFORMATION; // MinGW: Making these defines conditional on _WIN32_WINNT will break ddk includes //static if (_WIN32_WINNT >= 0x500) { enum DWORD ES_SYSTEM_REQUIRED = 0x00000001, ES_DISPLAY_REQUIRED = 0x00000002, ES_USER_PRESENT = 0x00000004, ES_CONTINUOUS = 0x80000000; enum LATENCY_TIME { LT_DONT_CARE, LT_LOWEST_LATENCY } alias LATENCY_TIME* PLATENCY_TIME; enum SYSTEM_POWER_STATE { PowerSystemUnspecified, PowerSystemWorking, PowerSystemSleeping1, PowerSystemSleeping2, PowerSystemSleeping3, PowerSystemHibernate, PowerSystemShutdown, PowerSystemMaximum } alias SYSTEM_POWER_STATE* PSYSTEM_POWER_STATE; enum POWER_SYSTEM_MAXIMUM = SYSTEM_POWER_STATE.PowerSystemMaximum; enum POWER_ACTION { PowerActionNone, PowerActionReserved, PowerActionSleep, PowerActionHibernate, PowerActionShutdown, PowerActionShutdownReset, PowerActionShutdownOff, PowerActionWarmEject } alias POWER_ACTION* PPOWER_ACTION; static if (_WIN32_WINNT >= 0x600) { enum SYSTEM_POWER_CONDITION { PoAc, PoDc, PoHot, PoConditionMaximum } alias SYSTEM_POWER_CONDITION* PSYSTEM_POWER_CONDITION; } enum DEVICE_POWER_STATE { PowerDeviceUnspecified, PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, PowerDeviceD3, PowerDeviceMaximum } alias DEVICE_POWER_STATE* PDEVICE_POWER_STATE; align(4): struct BATTERY_REPORTING_SCALE { DWORD Granularity; DWORD Capacity; } alias BATTERY_REPORTING_SCALE* PBATTERY_REPORTING_SCALE; struct POWER_ACTION_POLICY { POWER_ACTION Action; ULONG Flags; ULONG EventCode; } alias POWER_ACTION_POLICY* PPOWER_ACTION_POLICY; // POWER_ACTION_POLICY.Flags constants enum ULONG POWER_ACTION_QUERY_ALLOWED = 0x00000001, POWER_ACTION_UI_ALLOWED = 0x00000002, POWER_ACTION_OVERRIDE_APPS = 0x00000004, POWER_ACTION_LIGHTEST_FIRST = 0x10000000, POWER_ACTION_LOCK_CONSOLE = 0x20000000, POWER_ACTION_DISABLE_WAKES = 0x40000000, POWER_ACTION_CRITICAL = 0x80000000; // POWER_ACTION_POLICY.EventCode constants enum ULONG POWER_LEVEL_USER_NOTIFY_TEXT = 0x00000001, POWER_LEVEL_USER_NOTIFY_SOUND = 0x00000002, POWER_LEVEL_USER_NOTIFY_EXEC = 0x00000004, POWER_USER_NOTIFY_BUTTON = 0x00000008, POWER_USER_NOTIFY_SHUTDOWN = 0x00000010, POWER_FORCE_TRIGGER_RESET = 0x80000000; enum size_t DISCHARGE_POLICY_CRITICAL = 0, DISCHARGE_POLICY_LOW = 1, NUM_DISCHARGE_POLICIES = 4; enum : BYTE { PO_THROTTLE_NONE, PO_THROTTLE_CONSTANT, PO_THROTTLE_DEGRADE, PO_THROTTLE_ADAPTIVE, PO_THROTTLE_MAXIMUM } struct SYSTEM_POWER_LEVEL { BOOLEAN Enable; UCHAR[3] Spare; ULONG BatteryLevel; POWER_ACTION_POLICY PowerPolicy; SYSTEM_POWER_STATE MinSystemState; } alias SYSTEM_POWER_LEVEL* PSYSTEM_POWER_LEVEL; struct SYSTEM_POWER_POLICY { ULONG Revision; POWER_ACTION_POLICY PowerButton; POWER_ACTION_POLICY SleepButton; POWER_ACTION_POLICY LidClose; SYSTEM_POWER_STATE LidOpenWake; ULONG Reserved; POWER_ACTION_POLICY Idle; ULONG IdleTimeout; UCHAR IdleSensitivity; UCHAR DynamicThrottle; UCHAR[2] Spare2; SYSTEM_POWER_STATE MinSleep; SYSTEM_POWER_STATE MaxSleep; SYSTEM_POWER_STATE ReducedLatencySleep; ULONG WinLogonFlags; ULONG Spare3; ULONG DozeS4Timeout; ULONG BroadcastCapacityResolution; SYSTEM_POWER_LEVEL[NUM_DISCHARGE_POLICIES] DischargePolicy; ULONG VideoTimeout; BOOLEAN VideoDimDisplay; ULONG[3] VideoReserved; ULONG SpindownTimeout; BOOLEAN OptimizeForPower; UCHAR FanThrottleTolerance; UCHAR ForcedThrottle; UCHAR MinThrottle; POWER_ACTION_POLICY OverThrottled; } alias SYSTEM_POWER_POLICY* PSYSTEM_POWER_POLICY; struct SYSTEM_POWER_CAPABILITIES { BOOLEAN PowerButtonPresent; BOOLEAN SleepButtonPresent; BOOLEAN LidPresent; BOOLEAN SystemS1; BOOLEAN SystemS2; BOOLEAN SystemS3; BOOLEAN SystemS4; BOOLEAN SystemS5; BOOLEAN HiberFilePresent; BOOLEAN FullWake; BOOLEAN VideoDimPresent; BOOLEAN ApmPresent; BOOLEAN UpsPresent; BOOLEAN ThermalControl; BOOLEAN ProcessorThrottle; UCHAR ProcessorMinThrottle; UCHAR ProcessorMaxThrottle; UCHAR[4] spare2; BOOLEAN DiskSpinDown; UCHAR[8] spare3; BOOLEAN SystemBatteriesPresent; BOOLEAN BatteriesAreShortTerm; BATTERY_REPORTING_SCALE[3] BatteryScale; SYSTEM_POWER_STATE AcOnLineWake; SYSTEM_POWER_STATE SoftLidWake; SYSTEM_POWER_STATE RtcWake; SYSTEM_POWER_STATE MinDeviceWakeState; SYSTEM_POWER_STATE DefaultLowLatencyWake; } alias SYSTEM_POWER_CAPABILITIES* PSYSTEM_POWER_CAPABILITIES; struct SYSTEM_BATTERY_STATE { BOOLEAN AcOnLine; BOOLEAN BatteryPresent; BOOLEAN Charging; BOOLEAN Discharging; BOOLEAN[4] Spare1; ULONG MaxCapacity; ULONG RemainingCapacity; ULONG Rate; ULONG EstimatedTime; ULONG DefaultAlert1; ULONG DefaultAlert2; } alias SYSTEM_BATTERY_STATE* PSYSTEM_BATTERY_STATE; enum POWER_INFORMATION_LEVEL { SystemPowerPolicyAc, SystemPowerPolicyDc, VerifySystemPolicyAc, VerifySystemPolicyDc, SystemPowerCapabilities, SystemBatteryState, SystemPowerStateHandler, ProcessorStateHandler, SystemPowerPolicyCurrent, AdministratorPowerPolicy, SystemReserveHiberFile, ProcessorInformation, SystemPowerInformation, ProcessorStateHandler2, LastWakeTime, LastSleepTime, SystemExecutionState, SystemPowerStateNotifyHandler, ProcessorPowerPolicyAc, ProcessorPowerPolicyDc, VerifyProcessorPowerPolicyAc, VerifyProcessorPowerPolicyDc, ProcessorPowerPolicyCurrent } //#if 1 /* (WIN32_WINNT >= 0x0500) */ struct SYSTEM_POWER_INFORMATION { ULONG MaxIdlenessAllowed; ULONG Idleness; ULONG TimeRemaining; UCHAR CoolingMode; } alias SYSTEM_POWER_INFORMATION* PSYSTEM_POWER_INFORMATION; //#endif struct PROCESSOR_POWER_POLICY_INFO { ULONG TimeCheck; ULONG DemoteLimit; ULONG PromoteLimit; UCHAR DemotePercent; UCHAR PromotePercent; UCHAR[2] Spare; uint _bf; bool AllowDemotion() { return cast(bool)(_bf & 1); } bool AllowPromotion() { return cast(bool)(_bf & 2); } bool AllowDemotion(bool a) { _bf = (_bf & ~1) | a; return a; } bool AllowPromotion(bool a) { _bf = (_bf & ~2) | (a << 1); return a; } /+ ULONG AllowDemotion : 1; ULONG AllowPromotion : 1; ULONG Reserved : 30; +/ } alias PROCESSOR_POWER_POLICY_INFO* PPROCESSOR_POWER_POLICY_INFO; struct PROCESSOR_POWER_POLICY { ULONG Revision; UCHAR DynamicThrottle; UCHAR[3] Spare; ULONG Reserved; ULONG PolicyCount; PROCESSOR_POWER_POLICY_INFO[3] Policy; } alias PROCESSOR_POWER_POLICY* PPROCESSOR_POWER_POLICY; struct ADMINISTRATOR_POWER_POLICY { SYSTEM_POWER_STATE MinSleep; SYSTEM_POWER_STATE MaxSleep; ULONG MinVideoTimeout; ULONG MaxVideoTimeout; ULONG MinSpindownTimeout; ULONG MaxSpindownTimeout; } alias ADMINISTRATOR_POWER_POLICY* PADMINISTRATOR_POWER_POLICY; //}//#endif /* _WIN32_WINNT >= 0x500 */ extern (Windows) { alias void function(PVOID, DWORD, PVOID) PIMAGE_TLS_CALLBACK; static if (_WIN32_WINNT >= 0x500) { alias LONG function(PEXCEPTION_POINTERS) PVECTORED_EXCEPTION_HANDLER; alias void function(PVOID, BOOLEAN) WAITORTIMERCALLBACKFUNC; } } static if (_WIN32_WINNT >= 0x501) { enum HEAP_INFORMATION_CLASS { HeapCompatibilityInformation } enum ACTIVATION_CONTEXT_INFO_CLASS { ActivationContextBasicInformation = 1, ActivationContextDetailedInformation, AssemblyDetailedInformationInActivationContext, FileInformationInAssemblyOfAssemblyInActivationContext } struct ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION { DWORD ulFlags; DWORD ulEncodedAssemblyIdentityLength; DWORD ulManifestPathType; DWORD ulManifestPathLength; LARGE_INTEGER liManifestLastWriteTime; DWORD ulPolicyPathType; DWORD ulPolicyPathLength; LARGE_INTEGER liPolicyLastWriteTime; DWORD ulMetadataSatelliteRosterIndex; DWORD ulManifestVersionMajor; DWORD ulManifestVersionMinor; DWORD ulPolicyVersionMajor; DWORD ulPolicyVersionMinor; DWORD ulAssemblyDirectoryNameLength; PCWSTR lpAssemblyEncodedAssemblyIdentity; PCWSTR lpAssemblyManifestPath; PCWSTR lpAssemblyPolicyPath; PCWSTR lpAssemblyDirectoryName; } alias ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION* PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; alias const(ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION)* PCACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; struct ACTIVATION_CONTEXT_DETAILED_INFORMATION { DWORD dwFlags; DWORD ulFormatVersion; DWORD ulAssemblyCount; DWORD ulRootManifestPathType; DWORD ulRootManifestPathChars; DWORD ulRootConfigurationPathType; DWORD ulRootConfigurationPathChars; DWORD ulAppDirPathType; DWORD ulAppDirPathChars; PCWSTR lpRootManifestPath; PCWSTR lpRootConfigurationPath; PCWSTR lpAppDirPath; } alias ACTIVATION_CONTEXT_DETAILED_INFORMATION* PACTIVATION_CONTEXT_DETAILED_INFORMATION; alias const(ACTIVATION_CONTEXT_DETAILED_INFORMATION)* PCACTIVATION_CONTEXT_DETAILED_INFORMATION; struct ACTIVATION_CONTEXT_QUERY_INDEX { ULONG ulAssemblyIndex; ULONG ulFileIndexInAssembly; } alias ACTIVATION_CONTEXT_QUERY_INDEX* PACTIVATION_CONTEXT_QUERY_INDEX; alias const(ACTIVATION_CONTEXT_QUERY_INDEX)* PCACTIVATION_CONTEXT_QUERY_INDEX; struct ASSEMBLY_FILE_DETAILED_INFORMATION { DWORD ulFlags; DWORD ulFilenameLength; DWORD ulPathLength; PCWSTR lpFileName; PCWSTR lpFilePath; } alias ASSEMBLY_FILE_DETAILED_INFORMATION* PASSEMBLY_FILE_DETAILED_INFORMATION; alias const(ASSEMBLY_FILE_DETAILED_INFORMATION)* PCASSEMBLY_FILE_DETAILED_INFORMATION; } version (Unicode) { alias OSVERSIONINFOW OSVERSIONINFO; alias OSVERSIONINFOEXW OSVERSIONINFOEX; } else { alias OSVERSIONINFOA OSVERSIONINFO; alias OSVERSIONINFOEXA OSVERSIONINFOEX; } alias OSVERSIONINFO* POSVERSIONINFO, LPOSVERSIONINFO; alias OSVERSIONINFOEX* POSVERSIONINFOEX, LPOSVERSIONINFOEX; static if (_WIN32_WINNT >= 0x500) { extern (Windows) ULONGLONG VerSetConditionMask(ULONGLONG, DWORD, BYTE); } version (Win64) { enum WORD IMAGE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR64_MAGIC; alias IMAGE_ORDINAL_FLAG64 IMAGE_ORDINAL_FLAG; alias IMAGE_SNAP_BY_ORDINAL64 IMAGE_SNAP_BY_ORDINAL; alias IMAGE_ORDINAL64 IMAGE_ORDINAL; alias IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; alias IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; alias IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; alias IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY; } else { enum WORD IMAGE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR32_MAGIC; alias IMAGE_ORDINAL_FLAG32 IMAGE_ORDINAL_FLAG; alias IMAGE_ORDINAL32 IMAGE_ORDINAL; alias IMAGE_SNAP_BY_ORDINAL32 IMAGE_SNAP_BY_ORDINAL; alias IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; alias IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; alias IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; alias IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY; } alias IMAGE_OPTIONAL_HEADER* PIMAGE_OPTIONAL_HEADER; alias IMAGE_NT_HEADERS* PIMAGE_NT_HEADERS; alias IMAGE_THUNK_DATA* PIMAGE_THUNK_DATA; alias IMAGE_TLS_DIRECTORY* PIMAGE_TLS_DIRECTORY; // TODO: MinGW implements these in assembly. How to translate? PVOID GetCurrentFiber(); PVOID GetFiberData(); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rpcdce2.d0000664000175000017500000000435012776214756023203 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rpcdce2.d) */ module core.sys.windows.rpcdce2; version (Windows): version (ANSI) {} else version = Unicode; import core.sys.windows.rpcdce; private import core.sys.windows.basetyps; // FIXME: deal with RPC_UNICODE_SUPPORTED // FIXME: check types of constants enum { RPC_C_EP_ALL_ELTS, RPC_C_EP_MATCH_BY_IF, RPC_C_EP_MATCH_BY_OBJ, RPC_C_EP_MATCH_BY_BOTH } enum { RPC_C_VERS_ALL = 1, RPC_C_VERS_COMPATIBLE, RPC_C_VERS_EXACT, RPC_C_VERS_MAJOR_ONLY, RPC_C_VERS_UPTO } enum size_t DCE_C_ERROR_STRING_LEN = 256; enum { RPC_C_MGMT_INQ_IF_IDS, RPC_C_MGMT_INQ_PRINC_NAME, RPC_C_MGMT_INQ_STATS, RPC_C_MGMT_IS_SERVER_LISTEN, RPC_C_MGMT_STOP_SERVER_LISTEN } extern (Windows) { int UuidCompare(UUID*, UUID*, RPC_STATUS*); RPC_STATUS UuidCreateNil(UUID*); int UuidEqual(UUID*, UUID*, RPC_STATUS*); ushort UuidHash(UUID*, RPC_STATUS*); int UuidIsNil(UUID*, RPC_STATUS*); RPC_STATUS RpcMgmtEpEltInqBegin(RPC_BINDING_HANDLE, uint, RPC_IF_ID*, uint, UUID*, RPC_EP_INQ_HANDLE*); RPC_STATUS RpcMgmtEpEltInqDone(RPC_EP_INQ_HANDLE*); RPC_STATUS RpcMgmtEpUnregister(RPC_BINDING_HANDLE, RPC_IF_ID*, RPC_BINDING_HANDLE, UUID*); RPC_STATUS RpcMgmtSetAuthorizationFn(RPC_MGMT_AUTHORIZATION_FN); } //#ifdef RPC_UNICODE_SUPPORTED RPC_STATUS DceErrorInqTextA(RPC_STATUS, char*); RPC_STATUS DceErrorInqTextW(RPC_STATUS, wchar*); RPC_STATUS RpcMgmtEpEltInqNextA(RPC_EP_INQ_HANDLE, RPC_IF_ID*, RPC_BINDING_HANDLE*, UUID*, char**); RPC_STATUS RpcMgmtEpEltInqNextW(RPC_EP_INQ_HANDLE, RPC_IF_ID*, RPC_BINDING_HANDLE*, UUID*, wchar**); version (Unicode) { alias RpcMgmtEpEltInqNextW RpcMgmtEpEltInqNext; alias DceErrorInqTextW DceErrorInqText; } else { alias RpcMgmtEpEltInqNextA RpcMgmtEpEltInqNext; alias DceErrorInqTextA DceErrorInqText; } /+ #else /* RPC_UNICODE_SUPPORTED */ RPC_STATUS RPC_ENTRY DceErrorInqText(RPC_STATUS,unsigned char*); RPC_STATUS RPC_ENTRY RpcMgmtEpEltInqNext(RPC_EP_INQ_HANDLE,RPC_IF_ID*,RPC_BINDING_HANDLE*,UUID*,unsigned char**); #endif +/ ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/vfw.d0000664000175000017500000025346112776214756022474 0ustar kaikai/** * Windows API header module * * written in the D programming language * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_vfw.d) */ module core.sys.windows.vfw; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "vfw32"); private import core.sys.windows.commdlg, core.sys.windows.wingdi, core.sys.windows.mmsystem, core.sys.windows.unknwn, core.sys.windows.w32api, core.sys.windows.windef, core.sys.windows.winuser; extern(Windows) { DWORD VideoForWindowsVersion(); LONG InitVFW(); LONG TermVFW(); } DWORD MKFOURCC(char ch0, char ch1, char ch2, char ch3) { return (cast(DWORD)ch0) | ((cast(DWORD)ch1) << 8) | ((cast(DWORD)ch2) << 16) | ((cast(DWORD)ch3) << 24); } /** * COMPMAN - Installable Compression Manager. */ enum ICVERSION = 0x0104; alias TypeDef!(HANDLE) HIC; enum BI_1632 = 0x32333631; template aviTWOCC(char c0, char c1) { enum WORD aviTWOCC = c0 | (c1 << 8); } enum ICTYPE_VIDEO = mmioFOURCC!('v', 'i', 'd', 'c'); enum ICTYPE_AUDIO = mmioFOURCC!('a', 'u', 'd', 'c'); enum { ICERR_OK = 0, ICERR_DONTDRAW = 1, ICERR_NEWPALETTE = 2, ICERR_GOTOKEYFRAME = 3, ICERR_STOPDRAWING = 4, } enum ICERR_UNSUPPORTED = -1; enum ICERR_BADFORMAT = -2; enum ICERR_MEMORY = -3; enum ICERR_INTERNAL = -4; enum ICERR_BADFLAGS = -5; enum ICERR_BADPARAM = -6; enum ICERR_BADSIZE = -7; enum ICERR_BADHANDLE = -8; enum ICERR_CANTUPDATE = -9; enum ICERR_ABORT = -10; enum ICERR_ERROR = -100; enum ICERR_BADBITDEPTH = -200; enum ICERR_BADIMAGESIZE = -201; enum ICERR_CUSTOM = -400; enum { ICMODE_COMPRESS = 1, ICMODE_DECOMPRESS, ICMODE_FASTDECOMPRESS, ICMODE_QUERY, ICMODE_FASTCOMPRESS, ICMODE_DRAW = 8, } enum ICMODE_INTERNALF_FUNCTION32 = 0x8000; enum ICMODE_INTERNALF_MASK = 0x8000; enum { AVIIF_LIST = 0x00000001, AVIIF_TWOCC = 0x00000002, AVIIF_KEYFRAME = 0x00000010, } enum ICQUALITY_LOW = 0; enum ICQUALITY_HIGH = 10000; enum ICQUALITY_DEFAULT = -1; enum { ICM_USER = DRV_USER + 0x0000, ICM_RESERVED_LOW = DRV_USER + 0x1000, ICM_RESERVED_HIGH = DRV_USER + 0x2000, ICM_RESERVED = ICM_RESERVED_LOW, } // messages enum { ICM_GETSTATE = ICM_RESERVED + 0, ICM_SETSTATE = ICM_RESERVED + 1, ICM_GETINFO = ICM_RESERVED + 2, ICM_CONFIGURE = ICM_RESERVED + 10, ICM_ABOUT = ICM_RESERVED + 11, ICM_GETERRORTEXT = ICM_RESERVED + 12, ICM_GETFORMATNAME = ICM_RESERVED + 20, ICM_ENUMFORMATS = ICM_RESERVED + 21, ICM_GETDEFAULTQUALITY = ICM_RESERVED + 30, ICM_GETQUALITY = ICM_RESERVED + 31, ICM_SETQUALITY = ICM_RESERVED + 32, ICM_SET = ICM_RESERVED + 40, ICM_GET = ICM_RESERVED + 41, } enum ICM_FRAMERATE = mmioFOURCC!('F','r','m','R'); enum ICM_KEYFRAMERATE = mmioFOURCC!('K','e','y','R'); // ICM specific messages. enum { ICM_COMPRESS_GET_FORMAT = ICM_USER + 4, ICM_COMPRESS_GET_SIZE = ICM_USER + 5, ICM_COMPRESS_QUERY = ICM_USER + 6, ICM_COMPRESS_BEGIN = ICM_USER + 7, ICM_COMPRESS = ICM_USER + 8, ICM_COMPRESS_END = ICM_USER + 9, ICM_DECOMPRESS_GET_FORMAT = ICM_USER + 10, ICM_DECOMPRESS_QUERY = ICM_USER + 11, ICM_DECOMPRESS_BEGIN = ICM_USER + 12, ICM_DECOMPRESS = ICM_USER + 13, ICM_DECOMPRESS_END = ICM_USER + 14, ICM_DECOMPRESS_SET_PALETTE = ICM_USER + 29, ICM_DECOMPRESS_GET_PALETTE = ICM_USER + 30, ICM_DRAW_QUERY = ICM_USER + 31, ICM_DRAW_BEGIN = ICM_USER + 15, ICM_DRAW_GET_PALETTE = ICM_USER + 16, ICM_DRAW_UPDATE = ICM_USER + 17, ICM_DRAW_START = ICM_USER + 18, ICM_DRAW_STOP = ICM_USER + 19, ICM_DRAW_BITS = ICM_USER + 20, ICM_DRAW_END = ICM_USER + 21, ICM_DRAW_GETTIME = ICM_USER + 32, ICM_DRAW = ICM_USER + 33, ICM_DRAW_WINDOW = ICM_USER + 34, ICM_DRAW_SETTIME = ICM_USER + 35, ICM_DRAW_REALIZE = ICM_USER + 36, ICM_DRAW_FLUSH = ICM_USER + 37, ICM_DRAW_RENDERBUFFER = ICM_USER + 38, ICM_DRAW_START_PLAY = ICM_USER + 39, ICM_DRAW_STOP_PLAY = ICM_USER + 40, ICM_DRAW_SUGGESTFORMAT = ICM_USER + 50, ICM_DRAW_CHANGEPALETTE = ICM_USER + 51, ICM_DRAW_IDLE = ICM_USER + 52, ICM_GETBUFFERSWANTED = ICM_USER + 41, ICM_GETDEFAULTKEYFRAMERATE = ICM_USER + 42, ICM_DECOMPRESSEX_BEGIN = ICM_USER + 60, ICM_DECOMPRESSEX_QUERY = ICM_USER + 61, ICM_DECOMPRESSEX = ICM_USER + 62, ICM_DECOMPRESSEX_END = ICM_USER + 63, ICM_COMPRESS_FRAMES_INFO = ICM_USER + 70, ICM_COMPRESS_FRAMES = ICM_USER + 71, ICM_SET_STATUS_PROC = ICM_USER + 72, } struct ICOPEN { DWORD dwSize; DWORD fccType; DWORD fccHandler; DWORD dwVersion; DWORD dwFlags; LRESULT dwError; LPVOID pV1Reserved; LPVOID pV2Reserved; DWORD dnDevNode; } struct ICINFO { DWORD dwSize; DWORD fccType; DWORD fccHandler; DWORD dwFlags; DWORD dwVersion; DWORD dwVersionICM; WCHAR[16] szName; WCHAR[128] szDescription; WCHAR[128] szDriver; } enum { VIDCF_QUALITY = 0x0001, VIDCF_CRUNCH = 0x0002, VIDCF_TEMPORAL = 0x0004, VIDCF_COMPRESSFRAMES = 0x0008, VIDCF_DRAW = 0x0010, VIDCF_FASTTEMPORALC = 0x0020, VIDCF_FASTTEMPORALD = 0x0080, } enum ICCOMPRESS_KEYFRAME = 0x00000001L; struct ICCOMPRESS { DWORD dwFlags; LPBITMAPINFOHEADER lpbiOutput; LPVOID lpOutput; LPBITMAPINFOHEADER lpbiInput; LPVOID lpInput; LPDWORD lpckid; LPDWORD lpdwFlags; LONG lFrameNum; DWORD dwFrameSize; DWORD dwQuality; LPBITMAPINFOHEADER lpbiPrev; LPVOID lpPrev; } enum ICCOMPRESSFRAMES_PADDING = 0x00000001; struct ICCOMPRESSFRAMES { DWORD dwFlags; LPBITMAPINFOHEADER lpbiOutput; LPARAM lOutput; LPBITMAPINFOHEADER lpbiInput; LPARAM lInput; LONG lStartFrame; LONG lFrameCount; LONG lQuality; LONG lDataRate; LONG lKeyRate; DWORD dwRate; DWORD dwScale; DWORD dwOverheadPerFrame; DWORD dwReserved2; LONG function(LPARAM lInput, LONG lFrame, LPVOID lpBits, LONG len) GetData; LONG function(LPARAM lOutput, LONG lFrame, LPVOID lpBits, LONG len) PutData; } enum { ICSTATUS_START = 0, ICSTATUS_STATUS = 1, ICSTATUS_END = 2, ICSTATUS_ERROR = 3, ICSTATUS_YIELD = 4, } struct ICSETSTATUSPROC { DWORD dwFlags; LPARAM lParam; LONG function(LPARAM lParam, UINT message, LONG l) Status; } enum { ICDECOMPRESS_NOTKEYFRAME = 0x08000000, ICDECOMPRESS_NULLFRAME = 0x10000000, ICDECOMPRESS_PREROLL = 0x20000000, ICDECOMPRESS_UPDATE = 0x40000000, ICDECOMPRESS_HURRYUP = 0x80000000, } struct ICDECOMPRESS { DWORD dwFlags; LPBITMAPINFOHEADER lpbiInput; LPVOID lpInput; LPBITMAPINFOHEADER lpbiOutput; LPVOID lpOutput; DWORD ckid; } struct ICDECOMPRESSEX { DWORD dwFlags; LPBITMAPINFOHEADER lpbiSrc; LPVOID lpSrc; LPBITMAPINFOHEADER lpbiDst; LPVOID lpDst; int xDst; int yDst; int dxDst; int dyDst; int xSrc; int ySrc; int dxSrc; int dySrc; } enum { ICDRAW_QUERY = 0x00000001, ICDRAW_FULLSCREEN = 0x00000002, ICDRAW_HDC = 0x00000004, ICDRAW_ANIMATE = 0x00000008, ICDRAW_CONTINUE = 0x00000010, ICDRAW_MEMORYDC = 0x00000020, ICDRAW_UPDATING = 0x00000040, ICDRAW_RENDER = 0x00000080, ICDRAW_BUFFER = 0x00000100, } struct ICDRAWBEGIN { DWORD dwFlags; HPALETTE hpal; HWND hwnd; HDC hdc; int xDst; int yDst; int dxDst; int dyDst; LPBITMAPINFOHEADER lpbi; int xSrc; int ySrc; int dxSrc; int dySrc; DWORD dwRate; DWORD dwScale; } enum { ICDRAW_NOTKEYFRAME = 0x08000000, ICDRAW_NULLFRAME = 0x10000000, ICDRAW_PREROLL = 0x20000000, ICDRAW_UPDATE = 0x40000000, ICDRAW_HURRYUP = 0x80000000, } struct ICDRAW { DWORD dwFlags; LPVOID lpFormat; LPVOID lpData; DWORD cbData; LONG lTime; } struct ICDRAWSUGGEST { LPBITMAPINFOHEADER lpbiIn; LPBITMAPINFOHEADER lpbiSuggest; int dxSrc; int dySrc; int dxDst; int dyDst; HIC hicDecompressor; } struct ICPALETTE { DWORD dwFlags; int iStart; int iLen; LPPALETTEENTRY lppe; } /** * ICM function declarations */ extern (Windows) { BOOL ICInfo(DWORD fccType, DWORD fccHandler, ICINFO *lpicinfo); BOOL ICInstall(DWORD fccType, DWORD fccHandler, LPARAM lParam, LPSTR szDesc, UINT wFlags); BOOL ICRemove(DWORD fccType, DWORD fccHandler, UINT wFlags); LRESULT ICGetInfo(HIC hic, ICINFO *picinfo, DWORD cb); HIC ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode); HIC ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, FARPROC lpfnHandler); LRESULT ICClose(HIC hic); LRESULT ICSendMessage(HIC hic, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2); } enum { ICINSTALL_FUNCTION = 0x0001, ICINSTALL_DRIVER = 0x0002, ICINSTALL_HDRV = 0x0004, ICINSTALL_UNICODE = 0x8000, ICINSTALL_DRIVERW = 0x8002, } // query macros enum ICMF_CONFIGURE_QUERY = 0x00000001; enum ICMF_ABOUT_QUERY = 0x00000001; DWORD ICQueryAbout(HIC hic) { return ICSendMessage(hic, ICM_ABOUT, -1, ICMF_ABOUT_QUERY) == ICERR_OK; } DWORD ICAbout(HIC hic, HWND hwnd) { return cast(DWORD) ICSendMessage(hic, ICM_ABOUT, cast(DWORD_PTR) cast(UINT_PTR) hwnd, 0); } DWORD ICQueryConfigure(HIC hic) { return (ICSendMessage(hic, ICM_CONFIGURE, -1, ICMF_CONFIGURE_QUERY) == ICERR_OK); } DWORD ICConfigure(HIC hic, HWND hwnd) { return cast(DWORD) ICSendMessage(hic, ICM_CONFIGURE, cast(DWORD_PTR) cast(UINT_PTR) hwnd, 0); } DWORD ICGetState(HIC hic, LPVOID pv, DWORD_PTR cb) { return cast(DWORD) ICSendMessage(hic, ICM_GETSTATE, cast(DWORD_PTR) pv, cb); } DWORD ICSetState(HIC hic, LPVOID pv, DWORD_PTR cb) { return cast(DWORD) ICSendMessage(hic, ICM_SETSTATE, cast(DWORD_PTR) pv, cb); } DWORD ICGetStateSize(HIC hic) { return ICGetState(hic, null, 0); } DWORD dwICValue; DWORD ICGetDefaultQuality(HIC hic) { ICSendMessage(hic, ICM_GETDEFAULTQUALITY, cast(DWORD_PTR)&dwICValue, DWORD.sizeof); return dwICValue; } DWORD ICGetDefaultKeyFrameRate(HIC hic) { ICSendMessage(hic, ICM_GETDEFAULTKEYFRAMERATE, cast(DWORD_PTR)&dwICValue, DWORD.sizeof); return dwICValue; } DWORD ICDrawWindow(HIC hic, LPVOID prc) { return cast(DWORD) ICSendMessage(hic, ICM_DRAW_WINDOW, cast(DWORD_PTR) prc, RECT.sizeof); } extern (Windows) { DWORD ICCompress(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiOutput, LPVOID lpData, LPBITMAPINFOHEADER lpbiInput, LPVOID lpBits, LPDWORD lpckid, LPDWORD lpdwFlags, LONG lFrameNum, DWORD dwFrameSize, DWORD dwQuality, LPBITMAPINFOHEADER lpbiPrev, LPVOID lpPrev); } LRESULT ICCompressBegin(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) { return ICSendMessage(hic, ICM_COMPRESS_BEGIN, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput); } LRESULT ICCompressQuery(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) { return ICSendMessage(hic, ICM_COMPRESS_QUERY, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput); } LRESULT ICCompressGetFormat(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) { return ICSendMessage(hic, ICM_COMPRESS_GET_FORMAT, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput); } DWORD ICCompressGetFormatSize(HIC hic, LPVOID lpbi) { return cast(DWORD)ICCompressGetFormat(hic, lpbi, null); } DWORD ICCompressGetSize(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) { return cast(DWORD)ICSendMessage(hic, ICM_COMPRESS_GET_SIZE, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput); } LRESULT ICCompressEnd(HIC hic) { return ICSendMessage(hic, ICM_COMPRESS_END, 0, 0); } extern (Windows) { DWORD ICDecompress(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiFormat, LPVOID lpData, LPBITMAPINFOHEADER lpbi, LPVOID lpBits); } LRESULT ICDecompressBegin(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) { return ICSendMessage(hic, ICM_DECOMPRESS_BEGIN, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput); } LRESULT ICDecompressQuery(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) { return ICSendMessage(hic, ICM_DECOMPRESS_QUERY, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput); } LONG ICDecompressGetFormat(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) { return cast(LONG)ICSendMessage(hic, ICM_DECOMPRESS_GET_FORMAT, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput); } LONG ICDecompressGetFormatSize(HIC hic, LPVOID lpbi) { return ICDecompressGetFormat(hic, lpbi, null); } LRESULT ICDecompressGetPalette(HIC hic, LPVOID lpbiInput, LPVOID lpbiOutput) { return ICSendMessage(hic, ICM_DECOMPRESS_GET_PALETTE, cast(DWORD_PTR)lpbiInput, cast(DWORD_PTR)lpbiOutput); } LRESULT ICDecompressSetPalette(HIC hic, LPVOID lpbiPalette) { return ICSendMessage(hic, ICM_DECOMPRESS_SET_PALETTE, cast(DWORD_PTR)lpbiPalette, 0); } LRESULT ICDecompressEnd(HIC hic) { return ICSendMessage(hic, ICM_DECOMPRESS_END, 0, 0); } LRESULT ICDecompressEx(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiSrc, LPVOID lpSrc, int xSrc, int ySrc, int dxSrc, int dySrc, LPBITMAPINFOHEADER lpbiDst, LPVOID lpDst, int xDst, int yDst, int dxDst, int dyDst) { ICDECOMPRESSEX ic; ic.dwFlags = dwFlags; ic.lpbiSrc = lpbiSrc; ic.lpSrc = lpSrc; ic.xSrc = xSrc; ic.ySrc = ySrc; ic.dxSrc = dxSrc; ic.dySrc = dySrc; ic.lpbiDst = lpbiDst; ic.lpDst = lpDst; ic.xDst = xDst; ic.yDst = yDst; ic.dxDst = dxDst; ic.dyDst = dyDst; return ICSendMessage(hic, ICM_DECOMPRESSEX, cast(DWORD_PTR)&ic, ic.sizeof); } LRESULT ICDecompressExBegin(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiSrc, LPVOID lpSrc, int xSrc, int ySrc, int dxSrc, int dySrc, LPBITMAPINFOHEADER lpbiDst, LPVOID lpDst, int xDst, int yDst, int dxDst, int dyDst) { ICDECOMPRESSEX ic; ic.dwFlags = dwFlags; ic.lpbiSrc = lpbiSrc; ic.lpSrc = lpSrc; ic.xSrc = xSrc; ic.ySrc = ySrc; ic.dxSrc = dxSrc; ic.dySrc = dySrc; ic.lpbiDst = lpbiDst; ic.lpDst = lpDst; ic.xDst = xDst; ic.yDst = yDst; ic.dxDst = dxDst; ic.dyDst = dyDst; return ICSendMessage(hic, ICM_DECOMPRESSEX_BEGIN, cast(DWORD_PTR)&ic, ic.sizeof); } LRESULT ICDecompressExQuery(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiSrc, LPVOID lpSrc, int xSrc, int ySrc, int dxSrc, int dySrc, LPBITMAPINFOHEADER lpbiDst, LPVOID lpDst, int xDst, int yDst, int dxDst, int dyDst) { ICDECOMPRESSEX ic; ic.dwFlags = dwFlags; ic.lpbiSrc = lpbiSrc; ic.lpSrc = lpSrc; ic.xSrc = xSrc; ic.ySrc = ySrc; ic.dxSrc = dxSrc; ic.dySrc = dySrc; ic.lpbiDst = lpbiDst; ic.lpDst = lpDst; ic.xDst = xDst; ic.yDst = yDst; ic.dxDst = dxDst; ic.dyDst = dyDst; return ICSendMessage(hic, ICM_DECOMPRESSEX_QUERY, cast(DWORD_PTR)&ic, ic.sizeof); } LRESULT ICDecompressExEnd(HIC hic) { return ICSendMessage(hic, ICM_DECOMPRESSEX_END, 0, 0); } extern (Windows) { DWORD ICDrawBegin(HIC hic, DWORD dwFlags, HPALETTE hpal, HWND hwnd, HDC hdc, int xDst, int yDst, int dxDst, int dyDst, LPBITMAPINFOHEADER lpbi, int xSrc, int ySrc, int dxSrc, int dySrc, DWORD dwRate, DWORD dwScale); } extern (Windows) { DWORD ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime); } LRESULT ICDrawSuggestFormat(HIC hic, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, int dxSrc, int dySrc, int dxDst, int dyDst, HIC hicDecomp) { ICDRAWSUGGEST ic; ic.lpbiIn = lpbiIn; ic.lpbiSuggest = lpbiOut; ic.dxSrc = dxSrc; ic.dySrc = dySrc; ic.dxDst = dxDst; ic.dyDst = dyDst; ic.hicDecompressor = hicDecomp; return ICSendMessage(hic, ICM_DRAW_SUGGESTFORMAT, cast(DWORD_PTR)&ic, ic.sizeof); } LRESULT ICDrawQuery(HIC hic, LPVOID lpbiInput) { return ICSendMessage(hic, ICM_DRAW_QUERY, cast(DWORD_PTR)lpbiInput, 0L); } LRESULT ICDrawChangePalette(HIC hic, LPVOID lpbiInput) { return ICSendMessage(hic, ICM_DRAW_CHANGEPALETTE, cast(DWORD_PTR)lpbiInput, 0L); } LRESULT ICGetBuffersWanted(HIC hic, LPVOID lpdwBuffers) { return ICSendMessage(hic, ICM_GETBUFFERSWANTED, cast(DWORD_PTR)lpdwBuffers, 0); } LRESULT ICDrawEnd(HIC hic) { return ICSendMessage(hic, ICM_DRAW_END, 0, 0); } LRESULT ICDrawStart(HIC hic) { return ICSendMessage(hic, ICM_DRAW_START, 0, 0); } LRESULT ICDrawStartPlay(HIC hic, DWORD lFrom, DWORD lTo) { return ICSendMessage(hic, ICM_DRAW_START_PLAY, cast(DWORD_PTR)lFrom, cast(DWORD_PTR)lTo); } LRESULT ICDrawStop(HIC hic) { return ICSendMessage(hic, ICM_DRAW_STOP, 0, 0); } LRESULT ICDrawStopPlay(HIC hic) { return ICSendMessage(hic, ICM_DRAW_STOP_PLAY, 0, 0); } LRESULT ICDrawGetTime(HIC hic, LPVOID lplTime) { return ICSendMessage(hic, ICM_DRAW_GETTIME, cast(DWORD_PTR)lplTime, 0); } LRESULT ICDrawSetTime(HIC hic, DWORD lTime) { return ICSendMessage(hic, ICM_DRAW_SETTIME, cast(DWORD_PTR)lTime, 0); } LRESULT ICDrawRealize(HIC hic, HDC hdc, BOOL fBackground) { return ICSendMessage(hic, ICM_DRAW_REALIZE, cast(DWORD_PTR)hdc, cast(DWORD_PTR)fBackground); } LRESULT ICDrawFlush(HIC hic) { return ICSendMessage(hic, ICM_DRAW_FLUSH, 0, 0); } LRESULT ICDrawRenderBuffer(HIC hic) { return ICSendMessage(hic, ICM_DRAW_RENDERBUFFER, 0, 0); } LRESULT ICSetStatusProc(HIC hic, DWORD dwFlags, LRESULT lParam, LONG function(LPARAM, UINT, LONG) fpfnStatus) { ICSETSTATUSPROC ic; ic.dwFlags = dwFlags; ic.lParam = lParam; ic.Status = fpfnStatus; return ICSendMessage(hic, ICM_SET_STATUS_PROC, cast(DWORD_PTR)&ic, ic.sizeof); } HIC ICDecompressOpen(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { return ICLocate(fccType, fccHandler, lpbiIn, lpbiOut, ICMODE_DECOMPRESS); } HIC ICDrawOpen(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn) { return ICLocate(fccType, fccHandler, lpbiIn, null, ICMODE_DRAW); } extern (Windows) { HIC ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, WORD wFlags); HIC ICGetDisplayFormat(HIC hic, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, int BitDepth, int dx, int dy); HANDLE ICImageCompress(HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn, LPVOID lpBits, LPBITMAPINFO lpbiOut, LONG lQuality, LONG* plSize); HANDLE ICImageDecompress(HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn, LPVOID lpBits, LPBITMAPINFO lpbiOut); } struct COMPVARS { LONG cbSize = this.sizeof; DWORD dwFlags; HIC hic; DWORD fccType; DWORD fccHandler; LPBITMAPINFO lpbiIn; LPBITMAPINFO lpbiOut; LPVOID lpBitsOut; LPVOID lpBitsPrev; LONG lFrame; LONG lKey; LONG lDataRate; LONG lQ; LONG lKeyCount; LPVOID lpState; LONG cbState; } alias COMPVARS* PCOMPVARS; enum ICMF_COMPVARS_VALID = 0x00000001; extern (Windows) { BOOL ICCompressorChoose(HWND hwnd, UINT uiFlags, LPVOID pvIn, LPVOID lpData, PCOMPVARS pc, LPSTR lpszTitle); } enum { ICMF_CHOOSE_KEYFRAME = 0x0001, ICMF_CHOOSE_DATARATE = 0x0002, ICMF_CHOOSE_PREVIEW = 0x0004, ICMF_CHOOSE_ALLCOMPRESSORS = 0x0008, } extern (Windows) { BOOL ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn); void ICSeqCompressFrameEnd(PCOMPVARS pc); LPVOID ICSeqCompressFrame(PCOMPVARS pc, UINT uiFlags, LPVOID lpBits, BOOL* pfKey, LONG* plSize); void ICCompressorFree(PCOMPVARS pc); } mixin DECLARE_HANDLE!("HDRAWDIB"); enum { DDF_0001 = 0x0001, DDF_UPDATE = 0x0002, DDF_SAME_HDC = 0x0004, DDF_SAME_DRAW = 0x0008, DDF_DONTDRAW = 0x0010, DDF_ANIMATE = 0x0020, DDF_BUFFER = 0x0040, DDF_JUSTDRAWIT = 0x0080, DDF_FULLSCREEN = 0x0100, DDF_BACKGROUNDPAL = 0x0200, DDF_NOTKEYFRAME = 0x0400, DDF_HURRYUP = 0x0800, DDF_HALFTONE = 0x1000, DDF_2000 = 0x2000, DDF_PREROLL = DDF_DONTDRAW, DDF_SAME_DIB = DDF_SAME_DRAW, DDF_SAME_SIZE = DDF_SAME_DRAW, } extern (Windows) { BOOL DrawDibInit(); HDRAWDIB DrawDibOpen(); BOOL DrawDibClose(HDRAWDIB hdd); LPVOID DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags); UINT DrawDibError(HDRAWDIB hdd); HPALETTE DrawDibGetPalette(HDRAWDIB hdd); BOOL DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal); BOOL DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe); UINT DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground); BOOL DrawDibStart(HDRAWDIB hdd, DWORD rate); BOOL DrawDibStop(HDRAWDIB hdd); BOOL DrawDibBegin(HDRAWDIB hdd, HDC hdc, int dxDst, int dyDst, LPBITMAPINFOHEADER lpbi, int dxSrc, int dySrc, UINT wFlags); BOOL DrawDibDraw(HDRAWDIB hdd, HDC hdc, int xDst, int yDst, int dxDst, int dyDst, LPBITMAPINFOHEADER lpbi, LPVOID lpBits, int xSrc, int ySrc, int dxSrc, int dySrc, UINT wFlags); } BOOL DrawDibUpdate(HDRAWDIB hdd, HDC hdc, int x, int y) { return DrawDibDraw(hdd, hdc, x, y, 0, 0, null, null, 0, 0, 0, 0, DDF_UPDATE); } extern (Windows) { BOOL DrawDibEnd(HDRAWDIB hdd); } struct DRAWDIBTIME { LONG timeCount; LONG timeDraw; LONG timeDecompress; LONG timeDither; LONG timeStretch; LONG timeBlt; LONG timeSetDIBits; } alias DRAWDIBTIME* LPDRAWDIBTIME; extern (Windows) { BOOL DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime); } enum { PD_CAN_DRAW_DIB = 0x0001, PD_CAN_STRETCHDIB = 0x0002, PD_STRETCHDIB_1_1_OK = 0x0004, PD_STRETCHDIB_1_2_OK = 0x0008, PD_STRETCHDIB_1_N_OK = 0x0010, } extern (Windows) { LRESULT DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi); void StretchDIB(LPBITMAPINFOHEADER biDst, LPVOID lpDst, int DstX, int DstY, int DstXE, int DstYE, LPBITMAPINFOHEADER biSrc, LPVOID lpSrc, int SrcX, int SrcY, int SrcXE, int SrcYE); } alias DWORD FOURCC; alias WORD TWOCC; enum formtypeAVI = mmioFOURCC!('A', 'V', 'I', ' '); enum listtypeAVIHEADER = mmioFOURCC!('h', 'd', 'r', 'l'); enum ckidAVIMAINHDR = mmioFOURCC!('a', 'v', 'i', 'h'); enum listtypeSTREAMHEADER = mmioFOURCC!('s', 't', 'r', 'l'); enum ckidSTREAMHEADER = mmioFOURCC!('s', 't', 'r', 'h'); enum ckidSTREAMFORMAT = mmioFOURCC!('s', 't', 'r', 'f'); enum ckidSTREAMHANDLERDATA = mmioFOURCC!('s', 't', 'r', 'd'); enum ckidSTREAMNAME = mmioFOURCC!('s', 't', 'r', 'n'); enum listtypeAVIMOVIE = mmioFOURCC!('m', 'o', 'v', 'i'); enum listtypeAVIRECORD = mmioFOURCC!('r', 'e', 'c', ' '); enum ckidAVINEWINDEX = mmioFOURCC!('i', 'd', 'x', '1'); enum streamtypeVIDEO = mmioFOURCC!('v', 'i', 'd', 's'); enum streamtypeAUDIO = mmioFOURCC!('a', 'u', 'd', 's'); enum streamtypeMIDI = mmioFOURCC!('m', 'i', 'd', 's'); enum streamtypeTEXT = mmioFOURCC!('t', 'x', 't', 's'); enum cktypeDIBbits = aviTWOCC!('d', 'b'); enum cktypeDIBcompressed = aviTWOCC!('d', 'c'); enum cktypePALchange = aviTWOCC!('p', 'c'); enum cktypeWAVEbytes = aviTWOCC!('w', 'b'); enum ckidAVIPADDING = mmioFOURCC!('J', 'U', 'N', 'K'); DWORD FromHex(char n) { return (n >= 'A') ? n + 10 - 'A' : n - '0'; } WORD StreamFromFOURCC(DWORD fcc) { return cast(WORD)((FromHex(LOBYTE(LOWORD(fcc))) << 4) + (FromHex(HIBYTE(LOWORD(fcc))))); } WORD TWOCCFromFOURCC(DWORD fcc) { return HIWORD(fcc); } BYTE ToHex(DWORD n) { return cast(BYTE)((n > 9) ? n - 10 + 'A' : n + '0'); } DWORD MAKEAVICKID(WORD tcc, WORD stream) { return MAKELONG(cast(WORD)((ToHex(stream & 0x0f) << 8) | (ToHex((stream & 0xf0) >> 4))), tcc); } enum { AVIF_HASINDEX = 0x00000010, AVIF_MUSTUSEINDEX = 0x00000020, AVIF_ISINTERLEAVED = 0x00000100, AVIF_WASCAPTUREFILE = 0x00010000, AVIF_COPYRIGHTED = 0x00020000, } enum AVI_HEADERSIZE = 2048; struct MainAVIHeader { DWORD dwMicroSecPerFrame; DWORD dwMaxBytesPerSec; DWORD dwPaddingGranularity; DWORD dwFlags; DWORD dwTotalFrames; DWORD dwInitialFrames; DWORD dwStreams; DWORD dwSuggestedBufferSize; DWORD dwWidth; DWORD dwHeight; DWORD[4] dwReserved; } enum AVISF_DISABLED = 0x00000001; enum AVISF_VIDEO_PALCHANGES = 0x00010000; struct AVIStreamHeader { FOURCC fccType; FOURCC fccHandler; DWORD dwFlags; WORD wPriority; WORD wLanguage; DWORD dwInitialFrames; DWORD dwScale; DWORD dwRate; DWORD dwStart; DWORD dwLength; DWORD dwSuggestedBufferSize; DWORD dwQuality; DWORD dwSampleSize; RECT rcFrame; } enum { AVIIF_FIRSTPART = 0x00000020L, AVIIF_LASTPART = 0x00000040L, AVIIF_MIDPART = (AVIIF_LASTPART|AVIIF_FIRSTPART), AVIIF_NOTIME = 0x00000100L, AVIIF_COMPUSE = 0x0FFF0000L, } struct AVIINDEXENTRY { DWORD ckid; DWORD dwFlags; DWORD dwChunkOffset; DWORD dwChunkLength; } struct AVIPALCHANGE { BYTE bFirstEntry; BYTE bNumEntries; WORD wFlags; PALETTEENTRY[1] _peNew; PALETTEENTRY* peNew() return { return _peNew.ptr; } } enum AVIGETFRAMEF_BESTDISPLAYFMT = 1; struct AVISTREAMINFOW { DWORD fccType; DWORD fccHandler; DWORD dwFlags; DWORD dwCaps; WORD wPriority; WORD wLanguage; DWORD dwScale; DWORD dwRate; DWORD dwStart; DWORD dwLength; DWORD dwInitialFrames; DWORD dwSuggestedBufferSize; DWORD dwQuality; DWORD dwSampleSize; RECT rcFrame; DWORD dwEditCount; DWORD dwFormatChangeCount; WCHAR[64] szName; } alias AVISTREAMINFOW* LPAVISTREAMINFOW; struct AVISTREAMINFOA { DWORD fccType; DWORD fccHandler; DWORD dwFlags; DWORD dwCaps; WORD wPriority; WORD wLanguage; DWORD dwScale; DWORD dwRate; DWORD dwStart; DWORD dwLength; DWORD dwInitialFrames; DWORD dwSuggestedBufferSize; DWORD dwQuality; DWORD dwSampleSize; RECT rcFrame; DWORD dwEditCount; DWORD dwFormatChangeCount; char[64] szName; } alias AVISTREAMINFOA* LPAVISTREAMINFOA; version(Unicode) { alias AVISTREAMINFOW AVISTREAMINFO; alias LPAVISTREAMINFOW LPAVISTREAMINFO; } else { // Unicode alias AVISTREAMINFOA AVISTREAMINFO; alias LPAVISTREAMINFOA LPAVISTREAMINFO; } enum AVISTREAMINFO_DISABLED = 0x00000001; enum AVISTREAMINFO_FORMATCHANGES = 0x00010000; struct AVIFILEINFOW { DWORD dwMaxBytesPerSec; DWORD dwFlags; DWORD dwCaps; DWORD dwStreams; DWORD dwSuggestedBufferSize; DWORD dwWidth; DWORD dwHeight; DWORD dwScale; DWORD dwRate; DWORD dwLength; DWORD dwEditCount; WCHAR[64] szFileType; } alias AVIFILEINFOW* LPAVIFILEINFOW; struct AVIFILEINFOA { DWORD dwMaxBytesPerSec; DWORD dwFlags; DWORD dwCaps; DWORD dwStreams; DWORD dwSuggestedBufferSize; DWORD dwWidth; DWORD dwHeight; DWORD dwScale; DWORD dwRate; DWORD dwLength; DWORD dwEditCount; char[64] szFileType; } alias AVIFILEINFOA* LPAVIFILEINFOA; version(Unicode) { alias AVIFILEINFOW AVIFILEINFO; alias LPAVIFILEINFOW LPAVIFILEINFO; } else { // Unicode alias AVIFILEINFOA AVIFILEINFO; alias LPAVIFILEINFOA LPAVIFILEINFO; } enum { AVIFILEINFO_HASINDEX = 0x00000010, AVIFILEINFO_MUSTUSEINDEX = 0x00000020, AVIFILEINFO_ISINTERLEAVED = 0x00000100, AVIFILEINFO_WASCAPTUREFILE = 0x00010000, AVIFILEINFO_COPYRIGHTED = 0x00020000, } enum { AVIFILECAPS_CANREAD = 0x00000001, AVIFILECAPS_CANWRITE = 0x00000002, AVIFILECAPS_ALLKEYFRAMES = 0x00000010, AVIFILECAPS_NOCOMPRESSION = 0x00000020, } extern (Windows) { alias BOOL function(int) AVISAVECALLBACK; } struct AVICOMPRESSOPTIONS { DWORD fccType; DWORD fccHandler; DWORD dwKeyFrameEvery; DWORD dwQuality; DWORD dwBytesPerSecond; DWORD dwFlags; LPVOID lpFormat; DWORD cbFormat; LPVOID lpParms; DWORD cbParms; DWORD dwInterleaveEvery; } alias AVICOMPRESSOPTIONS* LPAVICOMPRESSOPTIONS; enum { AVICOMPRESSF_INTERLEAVE = 0x00000001, AVICOMPRESSF_DATARATE = 0x00000002, AVICOMPRESSF_KEYFRAMES = 0x00000004, AVICOMPRESSF_VALID = 0x00000008, } /+ TODO: DECLARE_INTERFACE_(IAVIStream, IUnknown) { STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; STDMETHOD(Create) (THIS_ LPARAM lParam1, LPARAM lParam2) PURE ; STDMETHOD(Info) (THIS_ AVISTREAMINFOW FAR * psi, LONG lSize) PURE ; STDMETHOD_(LONG, FindSample)(THIS_ LONG lPos, LONG lFlags) PURE ; STDMETHOD(ReadFormat) (THIS_ LONG lPos, LPVOID lpFormat, LONG FAR *lpcbFormat) PURE ; STDMETHOD(SetFormat) (THIS_ LONG lPos, LPVOID lpFormat, LONG cbFormat) PURE ; STDMETHOD(Read) (THIS_ LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG FAR * plBytes, LONG FAR * plSamples) PURE ; STDMETHOD(Write) (THIS_ LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG FAR *plSampWritten, LONG FAR *plBytesWritten) PURE ; STDMETHOD(Delete) (THIS_ LONG lStart, LONG lSamples) PURE; STDMETHOD(ReadData) (THIS_ DWORD fcc, LPVOID lp, LONG FAR *lpcb) PURE ; STDMETHOD(WriteData) (THIS_ DWORD fcc, LPVOID lp, LONG cb) PURE ; #ifdef _WIN32 STDMETHOD(SetInfo) (THIS_ AVISTREAMINFOW FAR * lpInfo, LONG cbInfo) PURE; #else STDMETHOD(Reserved1) (THIS) PURE; STDMETHOD(Reserved2) (THIS) PURE; STDMETHOD(Reserved3) (THIS) PURE; STDMETHOD(Reserved4) (THIS) PURE; STDMETHOD(Reserved5) (THIS) PURE; #endif }; alias TypeDef!(IAVIStream FAR*) PAVISTREAM; #undef INTERFACE #define INTERFACE IAVIStreaming DECLARE_INTERFACE_(IAVIStreaming, IUnknown) { STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; STDMETHOD(Begin) (THIS_ LONG lStart, LONG lEnd, LONG lRate) PURE; STDMETHOD(End) (THIS) PURE; }; alias TypeDef!(IAVIStreaming FAR*) PAVISTREAMING; #undef INTERFACE #define INTERFACE IAVIEditStream DECLARE_INTERFACE_(IAVIEditStream, IUnknown) { STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; STDMETHOD(Cut) (THIS_ LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult) PURE; STDMETHOD(Copy) (THIS_ LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult) PURE; STDMETHOD(Paste) (THIS_ LONG FAR *plPos, LONG FAR *plLength, PAVISTREAM pstream, LONG lStart, LONG lEnd) PURE; STDMETHOD(Clone) (THIS_ PAVISTREAM FAR *ppResult) PURE; STDMETHOD(SetInfo) (THIS_ AVISTREAMINFOW FAR * lpInfo, LONG cbInfo) PURE; }; alias TypeDef!(IAVIEditStream FAR*) PAVIEDITSTREAM; #undef INTERFACE #define INTERFACE IAVIPersistFile DECLARE_INTERFACE_(IAVIPersistFile, IPersistFile) { STDMETHOD(Reserved1)(THIS) PURE; }; alias TypeDef!(IAVIPersistFile FAR*) PAVIPERSISTFILE; #undef INTERFACE #define INTERFACE IAVIFile #define PAVIFILE IAVIFile FAR* DECLARE_INTERFACE_(IAVIFile, IUnknown) { STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; STDMETHOD(Info) (THIS_ AVIFILEINFOW FAR * pfi, LONG lSize) PURE; STDMETHOD(GetStream) (THIS_ PAVISTREAM FAR * ppStream, DWORD fccType, LONG lParam) PURE; STDMETHOD(CreateStream) (THIS_ PAVISTREAM FAR * ppStream, AVISTREAMINFOW FAR * psi) PURE; STDMETHOD(WriteData) (THIS_ DWORD ckid, LPVOID lpData, LONG cbData) PURE; STDMETHOD(ReadData) (THIS_ DWORD ckid, LPVOID lpData, LONG FAR *lpcbData) PURE; STDMETHOD(EndRecord) (THIS) PURE; STDMETHOD(DeleteStream) (THIS_ DWORD fccType, LONG lParam) PURE; }; #undef PAVIFILE alias TypeDef!(IAVIFile FAR*) PAVIFILE; #undef INTERFACE #define INTERFACE IGetFrame #define PGETFRAME IGetFrame FAR* DECLARE_INTERFACE_(IGetFrame, IUnknown) { STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; STDMETHOD_(LPVOID,GetFrame) (THIS_ LONG lPos) PURE; STDMETHOD(Begin) (THIS_ LONG lStart, LONG lEnd, LONG lRate) PURE; STDMETHOD(End) (THIS) PURE; STDMETHOD(SetFormat) (THIS_ LPBITMAPINFOHEADER lpbi, LPVOID lpBits, int x, int y, int dx, int dy) PURE; }; #undef PGETFRAME alias TypeDef!(IGetFrame FAR*) PGETFRAME; #define DEFINE_AVIGUID(name, l, w1, w2) DEFINE_GUID(name, l, w1, w2, 0xC0,0,0,0,0,0,0,0x46) DEFINE_AVIGUID(IID_IAVIFile, 0x00020020, 0, 0); DEFINE_AVIGUID(IID_IAVIStream, 0x00020021, 0, 0); DEFINE_AVIGUID(IID_IAVIStreaming, 0x00020022, 0, 0); DEFINE_AVIGUID(IID_IGetFrame, 0x00020023, 0, 0); DEFINE_AVIGUID(IID_IAVIEditStream, 0x00020024, 0, 0); DEFINE_AVIGUID(IID_IAVIPersistFile, 0x00020025, 0, 0); #ifndef UNICODE DEFINE_AVIGUID(CLSID_AVISimpleUnMarshal, 0x00020009, 0, 0); #endif DEFINE_AVIGUID(CLSID_AVIFile, 0x00020000, 0, 0); #define AVIFILEHANDLER_CANREAD 0x0001 #define AVIFILEHANDLER_CANWRITE 0x0002 #define AVIFILEHANDLER_CANACCEPTNONRGB 0x0004 STDAPI_(void) AVIFileInit(void); STDAPI_(void) AVIFileExit(void); STDAPI_(ULONG) AVIFileAddRef (PAVIFILE pfile); STDAPI_(ULONG) AVIFileRelease (PAVIFILE pfile); #ifdef _WIN32 STDAPI AVIFileOpenA (PAVIFILE FAR * ppfile, LPCSTR szFile, UINT uMode, LPCLSID lpHandler); STDAPI AVIFileOpenW (PAVIFILE FAR * ppfile, LPCWSTR szFile, UINT uMode, LPCLSID lpHandler); #ifdef UNICODE #define AVIFileOpen AVIFileOpenW #else #define AVIFileOpen AVIFileOpenA #endif #else STDAPI AVIFileOpen (PAVIFILE FAR * ppfile, LPCSTR szFile, UINT uMode, LPCLSID lpHandler); #define AVIFileOpenW AVIFileOpen #endif #ifdef _WIN32 STDAPI AVIFileInfoW (PAVIFILE pfile, LPAVIFILEINFOW pfi, LONG lSize); STDAPI AVIFileInfoA (PAVIFILE pfile, LPAVIFILEINFOA pfi, LONG lSize); #ifdef UNICODE #define AVIFileInfo AVIFileInfoW #else #define AVIFileInfo AVIFileInfoA #endif #else STDAPI AVIFileInfo (PAVIFILE pfile, LPAVIFILEINFO pfi, LONG lSize); #define AVIFileInfoW AVIFileInfo #endif STDAPI AVIFileGetStream (PAVIFILE pfile, PAVISTREAM FAR * ppavi, DWORD fccType, LONG lParam); #ifdef _WIN32 STDAPI AVIFileCreateStreamW (PAVIFILE pfile, PAVISTREAM FAR *ppavi, AVISTREAMINFOW FAR * psi); STDAPI AVIFileCreateStreamA (PAVIFILE pfile, PAVISTREAM FAR *ppavi, AVISTREAMINFOA FAR * psi); #ifdef UNICODE #define AVIFileCreateStream AVIFileCreateStreamW #else #define AVIFileCreateStream AVIFileCreateStreamA #endif #else STDAPI AVIFileCreateStream(PAVIFILE pfile, PAVISTREAM FAR *ppavi, AVISTREAMINFO FAR * psi); #define AVIFileCreateStreamW AVIFileCreateStream #endif STDAPI AVIFileWriteData (PAVIFILE pfile, DWORD ckid, LPVOID lpData, LONG cbData); STDAPI AVIFileReadData (PAVIFILE pfile, DWORD ckid, LPVOID lpData, LONG FAR *lpcbData); STDAPI AVIFileEndRecord (PAVIFILE pfile); STDAPI_(ULONG) AVIStreamAddRef (PAVISTREAM pavi); STDAPI_(ULONG) AVIStreamRelease (PAVISTREAM pavi); STDAPI AVIStreamInfoW (PAVISTREAM pavi, LPAVISTREAMINFOW psi, LONG lSize); STDAPI AVIStreamInfoA (PAVISTREAM pavi, LPAVISTREAMINFOA psi, LONG lSize); #ifdef UNICODE #define AVIStreamInfo AVIStreamInfoW #else #define AVIStreamInfo AVIStreamInfoA #endif STDAPI_(LONG) AVIStreamFindSample(PAVISTREAM pavi, LONG lPos, LONG lFlags); STDAPI AVIStreamReadFormat (PAVISTREAM pavi, LONG lPos,LPVOID lpFormat,LONG FAR *lpcbFormat); STDAPI AVIStreamSetFormat (PAVISTREAM pavi, LONG lPos,LPVOID lpFormat,LONG cbFormat); STDAPI AVIStreamReadData (PAVISTREAM pavi, DWORD fcc, LPVOID lp, LONG FAR *lpcb); STDAPI AVIStreamWriteData (PAVISTREAM pavi, DWORD fcc, LPVOID lp, LONG cb); STDAPI AVIStreamRead (PAVISTREAM pavi, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG FAR * plBytes, LONG FAR * plSamples); #define AVISTREAMREAD_CONVENIENT (-1L) STDAPI AVIStreamWrite (PAVISTREAM pavi, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG FAR *plSampWritten, LONG FAR *plBytesWritten); STDAPI_(LONG) AVIStreamStart (PAVISTREAM pavi); STDAPI_(LONG) AVIStreamLength (PAVISTREAM pavi); STDAPI_(LONG) AVIStreamTimeToSample (PAVISTREAM pavi, LONG lTime); STDAPI_(LONG) AVIStreamSampleToTime (PAVISTREAM pavi, LONG lSample); STDAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate); STDAPI AVIStreamEndStreaming(PAVISTREAM pavi); STDAPI_(PGETFRAME) AVIStreamGetFrameOpen(PAVISTREAM pavi, LPBITMAPINFOHEADER lpbiWanted); STDAPI_(LPVOID) AVIStreamGetFrame(PGETFRAME pg, LONG lPos); STDAPI AVIStreamGetFrameClose(PGETFRAME pg); STDAPI AVIStreamOpenFromFileA(PAVISTREAM FAR *ppavi, LPCSTR szFile, DWORD fccType, LONG lParam, UINT mode, CLSID FAR *pclsidHandler); STDAPI AVIStreamOpenFromFileW(PAVISTREAM FAR *ppavi, LPCWSTR szFile, DWORD fccType, LONG lParam, UINT mode, CLSID FAR *pclsidHandler); #ifdef UNICODE #define AVIStreamOpenFromFile AVIStreamOpenFromFileW #else #define AVIStreamOpenFromFile AVIStreamOpenFromFileA #endif STDAPI AVIStreamCreate(PAVISTREAM FAR *ppavi, LONG lParam1, LONG lParam2, CLSID FAR *pclsidHandler); #define FIND_DIR 0x0000000FL #define FIND_NEXT 0x00000001L #define FIND_PREV 0x00000004L #define FIND_FROM_START 0x00000008L #define FIND_TYPE 0x000000F0L #define FIND_KEY 0x00000010L #define FIND_ANY 0x00000020L #define FIND_FORMAT 0x00000040L #define FIND_RET 0x0000F000L #define FIND_POS 0x00000000L #define FIND_LENGTH 0x00001000L #define FIND_OFFSET 0x00002000L #define FIND_SIZE 0x00003000L #define FIND_INDEX 0x00004000L #define AVIStreamFindKeyFrame AVIStreamFindSample #define FindKeyFrame FindSample #define AVIStreamClose AVIStreamRelease #define AVIFileClose AVIFileRelease #define AVIStreamInit AVIFileInit #define AVIStreamExit AVIFileExit #define SEARCH_NEAREST FIND_PREV #define SEARCH_BACKWARD FIND_PREV #define SEARCH_FORWARD FIND_NEXT #define SEARCH_KEY FIND_KEY #define SEARCH_ANY FIND_ANY #define AVIStreamSampleToSample(pavi1, pavi2, l) AVIStreamTimeToSample(pavi1,AVIStreamSampleToTime(pavi2, l)) #define AVIStreamNextSample(pavi, l) AVIStreamFindSample(pavi,l+1,FIND_NEXT|FIND_ANY) #define AVIStreamPrevSample(pavi, l) AVIStreamFindSample(pavi,l-1,FIND_PREV|FIND_ANY) #define AVIStreamNearestSample(pavi, l) AVIStreamFindSample(pavi,l,FIND_PREV|FIND_ANY) #define AVIStreamNextKeyFrame(pavi,l) AVIStreamFindSample(pavi,l+1,FIND_NEXT|FIND_KEY) #define AVIStreamPrevKeyFrame(pavi, l) AVIStreamFindSample(pavi,l-1,FIND_PREV|FIND_KEY) #define AVIStreamNearestKeyFrame(pavi, l) AVIStreamFindSample(pavi,l,FIND_PREV|FIND_KEY) #define AVIStreamIsKeyFrame(pavi, l) (AVIStreamNearestKeyFrame(pavi,l) == l) #define AVIStreamPrevSampleTime(pavi, t) AVIStreamSampleToTime(pavi, AVIStreamPrevSample(pavi,AVIStreamTimeToSample(pavi,t))) #define AVIStreamNextSampleTime(pavi, t) AVIStreamSampleToTime(pavi, AVIStreamNextSample(pavi,AVIStreamTimeToSample(pavi,t))) #define AVIStreamNearestSampleTime(pavi, t) AVIStreamSampleToTime(pavi, AVIStreamNearestSample(pavi,AVIStreamTimeToSample(pavi,t))) #define AVIStreamNextKeyFrameTime(pavi, t) AVIStreamSampleToTime(pavi, AVIStreamNextKeyFrame(pavi,AVIStreamTimeToSample(pavi, t))) #define AVIStreamPrevKeyFrameTime(pavi, t) AVIStreamSampleToTime(pavi, AVIStreamPrevKeyFrame(pavi,AVIStreamTimeToSample(pavi, t))) #define AVIStreamNearestKeyFrameTime(pavi, t) AVIStreamSampleToTime(pavi, AVIStreamNearestKeyFrame(pavi,AVIStreamTimeToSample(pavi, t))) #define AVIStreamStartTime(pavi) AVIStreamSampleToTime(pavi, AVIStreamStart(pavi)) #define AVIStreamLengthTime(pavi) AVIStreamSampleToTime(pavi, AVIStreamLength(pavi)) #define AVIStreamEnd(pavi) (AVIStreamStart(pavi) + AVIStreamLength(pavi)) #define AVIStreamEndTime(pavi) AVIStreamSampleToTime(pavi, AVIStreamEnd(pavi)) #define AVIStreamSampleSize(pavi, lPos, plSize) AVIStreamRead(pavi,lPos,1,NULL,0,plSize,NULL) #define AVIStreamFormatSize(pavi, lPos, plSize) AVIStreamReadFormat(pavi,lPos,NULL,plSize) #define AVIStreamDataSize(pavi, fcc, plSize) AVIStreamReadData(pavi,fcc,NULL,plSize) #ifndef comptypeDIB #define comptypeDIB mmioFOURCC('D', 'I', 'B', ' ') #endif STDAPI AVIMakeCompressedStream( PAVISTREAM FAR * ppsCompressed, PAVISTREAM ppsSource, AVICOMPRESSOPTIONS FAR * lpOptions, CLSID FAR *pclsidHandler); EXTERN_C HRESULT CDECL AVISaveA (LPCSTR szFile, CLSID FAR *pclsidHandler, AVISAVECALLBACK lpfnCallback, int nStreams, PAVISTREAM pfile, LPAVICOMPRESSOPTIONS lpOptions, ...); STDAPI AVISaveVA(LPCSTR szFile, CLSID FAR *pclsidHandler, AVISAVECALLBACK lpfnCallback, int nStreams, PAVISTREAM FAR * ppavi, LPAVICOMPRESSOPTIONS FAR *plpOptions); EXTERN_C HRESULT CDECL AVISaveW (LPCWSTR szFile, CLSID FAR *pclsidHandler, AVISAVECALLBACK lpfnCallback, int nStreams, PAVISTREAM pfile, LPAVICOMPRESSOPTIONS lpOptions, ...); STDAPI AVISaveVW(LPCWSTR szFile, CLSID FAR *pclsidHandler, AVISAVECALLBACK lpfnCallback, int nStreams, PAVISTREAM FAR * ppavi, LPAVICOMPRESSOPTIONS FAR *plpOptions); #ifdef UNICODE #define AVISave AVISaveW #define AVISaveV AVISaveVW #else #define AVISave AVISaveA #define AVISaveV AVISaveVA #endif STDAPI_(INT_PTR) AVISaveOptions(HWND hwnd, UINT uiFlags, int nStreams, PAVISTREAM FAR *ppavi, LPAVICOMPRESSOPTIONS FAR *plpOptions); STDAPI AVISaveOptionsFree(int nStreams, LPAVICOMPRESSOPTIONS FAR *plpOptions); STDAPI AVIBuildFilterW(LPWSTR lpszFilter, LONG cbFilter, BOOL fSaving); STDAPI AVIBuildFilterA(LPSTR lpszFilter, LONG cbFilter, BOOL fSaving); #ifdef UNICODE #define AVIBuildFilter AVIBuildFilterW #else #define AVIBuildFilter AVIBuildFilterA #endif STDAPI AVIMakeFileFromStreams(PAVIFILE FAR * ppfile, int nStreams, PAVISTREAM FAR * papStreams); STDAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal, PAVISTREAM FAR *ppstream); STDAPI AVIPutFileOnClipboard(PAVIFILE pf); STDAPI AVIGetFromClipboard(PAVIFILE FAR * lppf); STDAPI AVIClearClipboard(void); STDAPI CreateEditableStream( PAVISTREAM FAR * ppsEditable, PAVISTREAM psSource); STDAPI EditStreamCut(PAVISTREAM pavi, LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult); STDAPI EditStreamCopy(PAVISTREAM pavi, LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult); STDAPI EditStreamPaste(PAVISTREAM pavi, LONG FAR *plPos, LONG FAR *plLength, PAVISTREAM pstream, LONG lStart, LONG lEnd); STDAPI EditStreamClone(PAVISTREAM pavi, PAVISTREAM FAR *ppResult); STDAPI EditStreamSetNameA(PAVISTREAM pavi, LPCSTR lpszName); STDAPI EditStreamSetNameW(PAVISTREAM pavi, LPCWSTR lpszName); STDAPI EditStreamSetInfoW(PAVISTREAM pavi, LPAVISTREAMINFOW lpInfo, LONG cbInfo); STDAPI EditStreamSetInfoA(PAVISTREAM pavi, LPAVISTREAMINFOA lpInfo, LONG cbInfo); #ifdef UNICODE #define EditStreamSetInfo EditStreamSetInfoW #define EditStreamSetName EditStreamSetNameW #else #define EditStreamSetInfo EditStreamSetInfoA #define EditStreamSetName EditStreamSetNameA #endif +/ enum AVIERR_OK = 0L; SCODE MAKE_AVIERR(DWORD error) { return MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x4000 + error); } enum AVIERR_UNSUPPORTED = MAKE_AVIERR(101); enum AVIERR_BADFORMAT = MAKE_AVIERR(102); enum AVIERR_MEMORY = MAKE_AVIERR(103); enum AVIERR_INTERNAL = MAKE_AVIERR(104); enum AVIERR_BADFLAGS = MAKE_AVIERR(105); enum AVIERR_BADPARAM = MAKE_AVIERR(106); enum AVIERR_BADSIZE = MAKE_AVIERR(107); enum AVIERR_BADHANDLE = MAKE_AVIERR(108); enum AVIERR_FILEREAD = MAKE_AVIERR(109); enum AVIERR_FILEWRITE = MAKE_AVIERR(110); enum AVIERR_FILEOPEN = MAKE_AVIERR(111); enum AVIERR_COMPRESSOR = MAKE_AVIERR(112); enum AVIERR_NOCOMPRESSOR = MAKE_AVIERR(113); enum AVIERR_READONLY = MAKE_AVIERR(114); enum AVIERR_NODATA = MAKE_AVIERR(115); enum AVIERR_BUFFERTOOSMALL = MAKE_AVIERR(116); enum AVIERR_CANTCOMPRESS = MAKE_AVIERR(117); enum AVIERR_USERABORT = MAKE_AVIERR(198); enum AVIERR_ERROR = MAKE_AVIERR(199); const TCHAR[] MCIWND_WINDOW_CLASS = "MCIWndClass"; extern (Windows) { HWND MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance, DWORD dwStyle, LPCSTR szFile); HWND MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance, DWORD dwStyle, LPCWSTR szFile); } version(Unicode) { alias MCIWndCreateW MCIWndCreate; } else { // Unicode alias MCIWndCreateA MCIWndCreate; } extern(Windows) { BOOL MCIWndRegisterClass(); } enum { MCIWNDOPENF_NEW = 0x0001, MCIWNDF_NOAUTOSIZEWINDOW = 0x0001, MCIWNDF_NOPLAYBAR = 0x0002, MCIWNDF_NOAUTOSIZEMOVIE = 0x0004, MCIWNDF_NOMENU = 0x0008, MCIWNDF_SHOWNAME = 0x0010, MCIWNDF_SHOWPOS = 0x0020, MCIWNDF_SHOWMODE = 0x0040, MCIWNDF_SHOWALL = 0x0070, MCIWNDF_NOTIFYMODE = 0x0100, MCIWNDF_NOTIFYPOS = 0x0200, MCIWNDF_NOTIFYSIZE = 0x0400, MCIWNDF_NOTIFYERROR = 0x1000, MCIWNDF_NOTIFYALL = 0x1F00, MCIWNDF_NOTIFYANSI = 0x0080, MCIWNDF_NOTIFYMEDIAA = 0x0880, MCIWNDF_NOTIFYMEDIAW = 0x0800, } version(Unicode) { alias MCIWNDF_NOTIFYMEDIAW MCIWNDF_NOTIFYMEDIA; } else { // Unicode alias MCIWNDF_NOTIFYMEDIAA MCIWNDF_NOTIFYMEDIA; } enum { MCIWNDF_RECORD = 0x2000, MCIWNDF_NOERRORDLG = 0x4000, MCIWNDF_NOOPEN = 0x8000, } // can macros BOOL MCIWndCanPlay(HWND hwnd) { return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_PLAY, 0, 0); } BOOL MCIWndCanRecord(HWND hwnd) { return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_RECORD, 0, 0); } BOOL MCIWndCanSave(HWND hwnd) { return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_SAVE, 0, 0); } BOOL MCIWndCanWindow(HWND hwnd) { return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_WINDOW, 0, 0); } BOOL MCIWndCanEject(HWND hwnd) { return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_EJECT, 0, 0); } BOOL MCIWndCanConfig(HWND hwnd) { return cast(BOOL)SendMessage(hwnd, MCIWNDM_CAN_CONFIG, 0, 0); } BOOL MCIWndPaletteKick(HWND hwnd) { return cast(BOOL)SendMessage(hwnd, MCIWNDM_PALETTEKICK, 0, 0); } LONG MCIWndSave(HWND hwnd, LPVOID szFile) { return cast(LONG)SendMessage(hwnd, MCI_SAVE, 0, cast(LPARAM)szFile); } LONG MCIWndSaveDialog(HWND hwnd) { return MCIWndSave(hwnd, cast(LPVOID)-1); } LONG MCIWndNew(HWND hwnd, LPVOID lp) { return cast(LONG)SendMessage(hwnd, MCIWNDM_NEW, 0, cast(LPARAM)lp); } LONG MCIWndRecord(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCI_RECORD, 0, 0); } LONG MCIWndOpen(HWND hwnd, LPVOID sz, UINT f) { return cast(LONG)SendMessage(hwnd, MCIWNDM_OPEN, cast(WPARAM)f, cast(LPARAM)sz); } LONG MCIWndOpenDialog(HWND hwnd) { return MCIWndOpen(hwnd, cast(LPVOID)-1, 0); } LONG MCIWndClose(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCI_CLOSE, 0, 0); } LONG MCIWndPlay(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCI_PLAY, 0, 0); } LONG MCIWndStop(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCI_STOP, 0, 0); } LONG MCIWndPause(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCI_PAUSE, 0, 0); } LONG MCIWndResume(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCI_RESUME, 0, 0); } LONG MCIWndSeek(HWND hwnd, LONG lPos) { return cast(LONG)SendMessage(hwnd, MCI_SEEK, 0, cast(LPARAM)lPos); } LONG MCIWndHome(HWND hwnd) { return MCIWndSeek(hwnd, MCIWND_START); } LONG MCIWndEnd(HWND hwnd) { return MCIWndSeek(hwnd, MCIWND_END); } LONG MCIWndEject(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCIWNDM_EJECT, 0, 0); } LONG MCIWndGetSource(HWND hwnd, LPRECT prc) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GET_SOURCE, 0, cast(LPARAM)prc); } LONG MCIWndPutSource(HWND hwnd, LPRECT prc) { return cast(LONG)SendMessage(hwnd, MCIWNDM_PUT_SOURCE, 0, cast(LPARAM)prc); } LONG MCIWndGetDest(HWND hwnd, LPRECT prc) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GET_DEST, 0, cast(LPARAM)prc); } LONG MCIWndPutDest(HWND hwnd, LPRECT prc) { return cast(LONG)SendMessage(hwnd, MCIWNDM_PUT_DEST, 0, cast(LPARAM)prc); } LONG MCIWndPlayReverse(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCIWNDM_PLAYREVERSE, 0, 0); } LONG MCIWndPlayFrom(HWND hwnd, LONG lPos) { return cast(LONG)SendMessage(hwnd, MCIWNDM_PLAYFROM, 0, cast(LPARAM)lPos); } LONG MCIWndPlayTo(HWND hwnd, LONG lPos) { return cast(LONG)SendMessage(hwnd, MCIWNDM_PLAYTO, 0, cast(LPARAM)lPos); } LONG MCIWndPlayFromTo(HWND hwnd, LONG lStart, LONG lEnd) { MCIWndSeek(hwnd, lStart); return MCIWndPlayTo(hwnd, lEnd); } UINT MCIWndGetDeviceID(HWND hwnd) { return cast(UINT)SendMessage(hwnd, MCIWNDM_GETDEVICEID, 0, 0); } UINT MCIWndGetAlias(HWND hwnd) { return cast(UINT)SendMessage(hwnd, MCIWNDM_GETALIAS, 0, 0); } LONG MCIWndGetMode(HWND hwnd, LPTSTR lp, UINT len) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GETMODE, cast(WPARAM)len, cast(LPARAM)lp); } LONG MCIWndGetPosition(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GETPOSITION, 0, 0); } LONG MCIWndGetPositionString(HWND hwnd, LPTSTR lp, UINT len) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GETPOSITION, cast(WPARAM)len, cast(LPARAM)lp); } LONG MCIWndGetStart(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GETSTART, 0, 0); } LONG MCIWndGetLength(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GETLENGTH, 0, 0); } LONG MCIWndGetEnd(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GETEND, 0, 0); } LONG MCIWndStep(HWND hwnd, LONG n) { return cast(LONG)SendMessage(hwnd, MCI_STEP, 0, cast(LPARAM)n); } void MCIWndDestroy(HWND hwnd) { SendMessage(hwnd, WM_CLOSE, 0, 0); } void MCIWndSetZoom(HWND hwnd, UINT iZoom) { SendMessage(hwnd, MCIWNDM_SETZOOM, 0, cast(LPARAM)iZoom); } UINT MCIWndGetZoom(HWND hwnd) { return cast(UINT)SendMessage(hwnd, MCIWNDM_GETZOOM, 0, 0); } LONG MCIWndSetVolume(HWND hwnd, UINT iVol) { return cast(LONG)SendMessage(hwnd, MCIWNDM_SETVOLUME, 0, cast(LPARAM)iVol); } LONG MCIWndGetVolume(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GETVOLUME, 0, 0); } LONG MCIWndSetSpeed(HWND hwnd, UINT iSpeed) { return cast(LONG)SendMessage(hwnd, MCIWNDM_SETSPEED, 0, cast(LPARAM)iSpeed); } LONG MCIWndGetSpeed(HWND hwnd) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GETSPEED, 0, 0); } LONG MCIWndSetTimeFormat(HWND hwnd, LPTSTR lp) { return cast(LONG)SendMessage(hwnd, MCIWNDM_SETTIMEFORMAT, 0, cast(LPARAM)lp); } LONG MCIWndUseFrames(HWND hwnd) { return MCIWndSetTimeFormat(hwnd, (cast(TCHAR[])"frames").ptr); } LONG MCIWndUseTime(HWND hwnd) { return MCIWndSetTimeFormat(hwnd, (cast(TCHAR[])"ms").ptr); } LONG MCIWndGetTimeFormat(HWND hwnd, LPTSTR lp, UINT len) { return cast(LONG)SendMessage(hwnd, MCIWNDM_GETTIMEFORMAT, cast(WPARAM)len, cast(LPARAM)lp); } void MCIWndValidateMedia(HWND hwnd) { SendMessage(hwnd, MCIWNDM_VALIDATEMEDIA, 0, 0); } void MCIWndSetRepeat(HWND hwnd, BOOL f) { SendMessage(hwnd, MCIWNDM_SETREPEAT, 0, cast(LPARAM)f); } BOOL MCIWndGetRepeat(HWND hwnd) { return cast(BOOL)SendMessage(hwnd, MCIWNDM_GETREPEAT, 0, 0); } void MCIWndSetActiveTimer(HWND hwnd, UINT active) { SendMessage(hwnd, MCIWNDM_SETACTIVETIMER, cast(WPARAM)active, 0); } void MCIWndSetInactiveTimer(HWND hwnd, UINT inactive) { SendMessage(hwnd, MCIWNDM_SETINACTIVETIMER, cast(WPARAM)inactive, 0); } void MCIWndSetTimers(HWND hwnd, UINT active, UINT inactive) { SendMessage(hwnd, MCIWNDM_SETTIMERS, cast(WPARAM)active, cast(LPARAM)inactive); } UINT MCIWndGetActiveTimer(HWND hwnd) { return cast(UINT)SendMessage(hwnd, MCIWNDM_GETACTIVETIMER, 0, 0); } UINT MCIWndGetInactiveTimer(HWND hwnd) { return cast(UINT)SendMessage(hwnd, MCIWNDM_GETINACTIVETIMER, 0, 0); } LONG MCIWndRealize(HWND hwnd, BOOL fBkgnd) { return cast(LONG) SendMessage(hwnd, MCIWNDM_REALIZE, cast(WPARAM)fBkgnd, 0); } LONG MCIWndSendString(HWND hwnd, LPTSTR sz) { return cast(LONG) SendMessage(hwnd, MCIWNDM_SENDSTRING, 0, cast(LPARAM)sz); } LONG MCIWndReturnString(HWND hwnd, LPVOID lp, UINT len) { return cast(LONG) SendMessage(hwnd, MCIWNDM_RETURNSTRING, cast(WPARAM)len, cast(LPARAM)lp); } LONG MCIWndGetError(HWND hwnd, LPVOID lp, UINT len) { return cast(LONG) SendMessage(hwnd, MCIWNDM_GETERROR, cast(WPARAM)len, cast(LPARAM)lp); } HPALETTE MCIWndGetPalette(HWND hwnd) { return cast(HPALETTE)SendMessage(hwnd, MCIWNDM_GETPALETTE, 0, 0); } LONG MCIWndSetPalette(HWND hwnd, HPALETTE hpal) { return cast(LONG) SendMessage(hwnd, MCIWNDM_SETPALETTE, cast(WPARAM)hpal, 0); } LONG MCIWndGetFileName(HWND hwnd, LPVOID lp, UINT len) { return cast(LONG) SendMessage(hwnd, MCIWNDM_GETFILENAME, cast(WPARAM)len, cast(LPARAM)lp); } LONG MCIWndGetDevice(HWND hwnd, LPVOID lp, UINT len) { return cast(LONG) SendMessage(hwnd, MCIWNDM_GETDEVICE, cast(WPARAM)len, cast(LPARAM)lp); } UINT MCIWndGetStyles(HWND hwnd) { return cast(UINT) SendMessage(hwnd, MCIWNDM_GETSTYLES, 0, 0); } LONG MCIWndChangeStyles(HWND hwnd, UINT mask, LONG value) { return cast(LONG) SendMessage(hwnd, MCIWNDM_CHANGESTYLES, cast(WPARAM)mask, cast(LPARAM)value); } LONG MCIWndOpenInterface(HWND hwnd, LPUNKNOWN pUnk) { return cast(LONG) SendMessage(hwnd, MCIWNDM_OPENINTERFACE, 0, cast(LPARAM)cast(void*)pUnk); } LONG MCIWndSetOwner(HWND hwnd, HWND hwndP) { return cast(LONG) SendMessage(hwnd, MCIWNDM_SETOWNER, cast(WPARAM)hwndP, 0); } enum { MCIWNDM_GETDEVICEID = WM_USER + 100, MCIWNDM_SENDSTRINGA = WM_USER + 101, MCIWNDM_GETPOSITIONA = WM_USER + 102, MCIWNDM_GETSTART = WM_USER + 103, MCIWNDM_GETLENGTH = WM_USER + 104, MCIWNDM_GETEND = WM_USER + 105, MCIWNDM_GETMODEA = WM_USER + 106, MCIWNDM_EJECT = WM_USER + 107, MCIWNDM_SETZOOM = WM_USER + 108, MCIWNDM_GETZOOM = WM_USER + 109, MCIWNDM_SETVOLUME = WM_USER + 110, MCIWNDM_GETVOLUME = WM_USER + 111, MCIWNDM_SETSPEED = WM_USER + 112, MCIWNDM_GETSPEED = WM_USER + 113, MCIWNDM_SETREPEAT = WM_USER + 114, MCIWNDM_GETREPEAT = WM_USER + 115, MCIWNDM_REALIZE = WM_USER + 118, MCIWNDM_SETTIMEFORMATA = WM_USER + 119, MCIWNDM_GETTIMEFORMATA = WM_USER + 120, MCIWNDM_VALIDATEMEDIA = WM_USER + 121, MCIWNDM_PLAYFROM = WM_USER + 122, MCIWNDM_PLAYTO = WM_USER + 123, MCIWNDM_GETFILENAMEA = WM_USER + 124, MCIWNDM_GETDEVICEA = WM_USER + 125, MCIWNDM_GETPALETTE = WM_USER + 126, MCIWNDM_SETPALETTE = WM_USER + 127, MCIWNDM_GETERRORA = WM_USER + 128, MCIWNDM_SETTIMERS = WM_USER + 129, MCIWNDM_SETACTIVETIMER = WM_USER + 130, MCIWNDM_SETINACTIVETIMER = WM_USER + 131, MCIWNDM_GETACTIVETIMER = WM_USER + 132, MCIWNDM_GETINACTIVETIMER = WM_USER + 133, MCIWNDM_NEWA = WM_USER + 134, MCIWNDM_CHANGESTYLES = WM_USER + 135, MCIWNDM_GETSTYLES = WM_USER + 136, MCIWNDM_GETALIAS = WM_USER + 137, MCIWNDM_RETURNSTRINGA = WM_USER + 138, MCIWNDM_PLAYREVERSE = WM_USER + 139, MCIWNDM_GET_SOURCE = WM_USER + 140, MCIWNDM_PUT_SOURCE = WM_USER + 141, MCIWNDM_GET_DEST = WM_USER + 142, MCIWNDM_PUT_DEST = WM_USER + 143, MCIWNDM_CAN_PLAY = WM_USER + 144, MCIWNDM_CAN_WINDOW = WM_USER + 145, MCIWNDM_CAN_RECORD = WM_USER + 146, MCIWNDM_CAN_SAVE = WM_USER + 147, MCIWNDM_CAN_EJECT = WM_USER + 148, MCIWNDM_CAN_CONFIG = WM_USER + 149, MCIWNDM_PALETTEKICK = WM_USER + 150, MCIWNDM_OPENINTERFACE = WM_USER + 151, MCIWNDM_SETOWNER = WM_USER + 152, MCIWNDM_OPENA = WM_USER + 153, MCIWNDM_SENDSTRINGW = WM_USER + 201, MCIWNDM_GETPOSITIONW = WM_USER + 202, MCIWNDM_GETMODEW = WM_USER + 206, MCIWNDM_SETTIMEFORMATW = WM_USER + 219, MCIWNDM_GETTIMEFORMATW = WM_USER + 220, MCIWNDM_GETFILENAMEW = WM_USER + 224, MCIWNDM_GETDEVICEW = WM_USER + 225, MCIWNDM_GETERRORW = WM_USER + 228, MCIWNDM_NEWW = WM_USER + 234, MCIWNDM_RETURNSTRINGW = WM_USER + 238, MCIWNDM_OPENW = WM_USER + 252, } version(Unicode) { alias MCIWNDM_SENDSTRINGW MCIWNDM_SENDSTRING; alias MCIWNDM_GETPOSITIONW MCIWNDM_GETPOSITION; alias MCIWNDM_GETMODEW MCIWNDM_GETMODE; alias MCIWNDM_SETTIMEFORMATW MCIWNDM_SETTIMEFORMAT; alias MCIWNDM_GETTIMEFORMATW MCIWNDM_GETTIMEFORMAT; alias MCIWNDM_GETFILENAMEW MCIWNDM_GETFILENAME; alias MCIWNDM_GETDEVICEW MCIWNDM_GETDEVICE; alias MCIWNDM_GETERRORW MCIWNDM_GETERROR; alias MCIWNDM_NEWW MCIWNDM_NEW; alias MCIWNDM_RETURNSTRINGW MCIWNDM_RETURNSTRING; alias MCIWNDM_OPENW MCIWNDM_OPEN; } else { // Unicode alias MCIWNDM_SENDSTRINGA MCIWNDM_SENDSTRING; alias MCIWNDM_GETPOSITIONA MCIWNDM_GETPOSITION; alias MCIWNDM_GETMODEA MCIWNDM_GETMODE; alias MCIWNDM_SETTIMEFORMATA MCIWNDM_SETTIMEFORMAT; alias MCIWNDM_GETTIMEFORMATA MCIWNDM_GETTIMEFORMAT; alias MCIWNDM_GETFILENAMEA MCIWNDM_GETFILENAME; alias MCIWNDM_GETDEVICEA MCIWNDM_GETDEVICE; alias MCIWNDM_GETERRORA MCIWNDM_GETERROR; alias MCIWNDM_NEWA MCIWNDM_NEW; alias MCIWNDM_RETURNSTRINGA MCIWNDM_RETURNSTRING; alias MCIWNDM_OPENA MCIWNDM_OPEN; } enum { MCIWNDM_NOTIFYMODE = WM_USER + 200, MCIWNDM_NOTIFYPOS = WM_USER + 201, MCIWNDM_NOTIFYSIZE = WM_USER + 202, MCIWNDM_NOTIFYMEDIA = WM_USER + 203, MCIWNDM_NOTIFYERROR = WM_USER + 205, } enum MCIWND_START = -1; enum MCIWND_END = -2; enum { MCI_CLOSE = 0x0804, MCI_PLAY = 0x0806, MCI_SEEK = 0x0807, MCI_STOP = 0x0808, MCI_PAUSE = 0x0809, MCI_STEP = 0x080E, MCI_RECORD = 0x080F, MCI_SAVE = 0x0813, MCI_CUT = 0x0851, MCI_COPY = 0x0852, MCI_PASTE = 0x0853, MCI_RESUME = 0x0855, MCI_DELETE = 0x0856, } enum { MCI_MODE_NOT_READY = 524, MCI_MODE_STOP, MCI_MODE_PLAY, MCI_MODE_RECORD, MCI_MODE_SEEK, MCI_MODE_PAUSE, MCI_MODE_OPEN, } alias TypeDef!(HANDLE) HVIDEO; alias HVIDEO* LPHVIDEO; // Error Return Values enum { DV_ERR_OK = 0, DV_ERR_BASE = 1, DV_ERR_NONSPECIFIC = DV_ERR_BASE, DV_ERR_BADFORMAT = DV_ERR_BASE + 1, DV_ERR_STILLPLAYING = DV_ERR_BASE + 2, DV_ERR_UNPREPARED = DV_ERR_BASE + 3, DV_ERR_SYNC = DV_ERR_BASE + 4, DV_ERR_TOOMANYCHANNELS = DV_ERR_BASE + 5, DV_ERR_NOTDETECTED = DV_ERR_BASE + 6, DV_ERR_BADINSTALL = DV_ERR_BASE + 7, DV_ERR_CREATEPALETTE = DV_ERR_BASE + 8, DV_ERR_SIZEFIELD = DV_ERR_BASE + 9, DV_ERR_PARAM1 = DV_ERR_BASE + 10, DV_ERR_PARAM2 = DV_ERR_BASE + 11, DV_ERR_CONFIG1 = DV_ERR_BASE + 12, DV_ERR_CONFIG2 = DV_ERR_BASE + 13, DV_ERR_FLAGS = DV_ERR_BASE + 14, DV_ERR_13 = DV_ERR_BASE + 15, DV_ERR_NOTSUPPORTED = DV_ERR_BASE + 16, DV_ERR_NOMEM = DV_ERR_BASE + 17, DV_ERR_ALLOCATED = DV_ERR_BASE + 18, DV_ERR_BADDEVICEID = DV_ERR_BASE + 19, DV_ERR_INVALHANDLE = DV_ERR_BASE + 20, DV_ERR_BADERRNUM = DV_ERR_BASE + 21, DV_ERR_NO_BUFFERS = DV_ERR_BASE + 22, DV_ERR_MEM_CONFLICT = DV_ERR_BASE + 23, DV_ERR_IO_CONFLICT = DV_ERR_BASE + 24, DV_ERR_DMA_CONFLICT = DV_ERR_BASE + 25, DV_ERR_INT_CONFLICT = DV_ERR_BASE + 26, DV_ERR_PROTECT_ONLY = DV_ERR_BASE + 27, DV_ERR_LASTERROR = DV_ERR_BASE + 27, DV_ERR_USER_MSG = DV_ERR_BASE + 1000, } // Callback Messages enum { MM_DRVM_OPEN = 0x3D0, MM_DRVM_CLOSE, MM_DRVM_DATA, MM_DRVM_ERROR, } enum { DV_VM_OPEN = MM_DRVM_OPEN, DV_VM_CLOSE = MM_DRVM_CLOSE, DV_VM_DATA = MM_DRVM_DATA, DV_VM_ERROR = MM_DRVM_ERROR, } /** * Structures */ struct VIDEOHDR { LPBYTE lpData; DWORD dwBufferLength; DWORD dwBytesUsed; DWORD dwTimeCaptured; DWORD_PTR dwUser; DWORD dwFlags; DWORD_PTR[4]dwReserved; } alias VIDEOHDR* PVIDEOHDR, LPVIDEOHDR; enum { VHDR_DONE = 0x00000001, VHDR_PREPARED = 0x00000002, VHDR_INQUEUE = 0x00000004, VHDR_KEYFRAME = 0x00000008, VHDR_VALID = 0x0000000F, } struct CHANNEL_CAPS { DWORD dwFlags; DWORD dwSrcRectXMod; DWORD dwSrcRectYMod; DWORD dwSrcRectWidthMod; DWORD dwSrcRectHeightMod; DWORD dwDstRectXMod; DWORD dwDstRectYMod; DWORD dwDstRectWidthMod; DWORD dwDstRectHeightMod; } alias CHANNEL_CAPS* PCHANNEL_CAPS, LPCHANNEL_CAPS; enum { VCAPS_OVERLAY = 0x00000001, VCAPS_SRC_CAN_CLIP = 0x00000002, VCAPS_DST_CAN_CLIP = 0x00000004, VCAPS_CAN_SCALE = 0x00000008, } /** * API Flags */ enum { VIDEO_EXTERNALIN = 0x0001, VIDEO_EXTERNALOUT = 0x0002, VIDEO_IN = 0x0004, VIDEO_OUT = 0x0008, VIDEO_DLG_QUERY = 0x0010, } enum { VIDEO_CONFIGURE_QUERYSIZE = 0x0001, VIDEO_CONFIGURE_CURRENT = 0x0010, VIDEO_CONFIGURE_NOMINAL = 0x0020, VIDEO_CONFIGURE_MIN = 0x0040, VIDEO_CONFIGURE_MAX = 0x0080, VIDEO_CONFIGURE_SET = 0x1000, VIDEO_CONFIGURE_GET = 0x2000, VIDEO_CONFIGURE_QUERY = 0x8000, } /** * CONFIGURE MESSAGES */ enum { DVM_USER = 0x4000, DVM_CONFIGURE_START = 0x1000, DVM_CONFIGURE_END = 0x1FFF, DVM_PALETTE = DVM_CONFIGURE_START + 1, DVM_FORMAT = DVM_CONFIGURE_START + 2, DVM_PALETTERGB555 = DVM_CONFIGURE_START + 3, DVM_SRC_RECT = DVM_CONFIGURE_START + 4, DVM_DST_RECT = DVM_CONFIGURE_START + 5, } /** * AVICap window class */ LRESULT AVICapSM(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (IsWindow(hWnd)) { return SendMessage(hWnd, msg, wParam, lParam); } return 0; } enum { WM_CAP_START = WM_USER, WM_CAP_UNICODE_START = WM_USER + 100, WM_CAP_GET_CAPSTREAMPTR = WM_CAP_START + 1, WM_CAP_SET_CALLBACK_ERRORA = WM_CAP_START + 2, WM_CAP_SET_CALLBACK_STATUSA = WM_CAP_START + 3, WM_CAP_SET_CALLBACK_ERRORW = WM_CAP_UNICODE_START + 2, WM_CAP_SET_CALLBACK_STATUSW = WM_CAP_UNICODE_START + 3, } version(Unicode) { alias WM_CAP_SET_CALLBACK_ERRORW WM_CAP_SET_CALLBACK_ERROR; alias WM_CAP_SET_CALLBACK_STATUSW WM_CAP_SET_CALLBACK_STATUS; } else { // Unicode alias WM_CAP_SET_CALLBACK_ERRORA WM_CAP_SET_CALLBACK_ERROR; alias WM_CAP_SET_CALLBACK_STATUSA WM_CAP_SET_CALLBACK_STATUS; } enum { WM_CAP_SET_CALLBACK_YIELD = WM_CAP_START + 4, WM_CAP_SET_CALLBACK_FRAME = WM_CAP_START + 5, WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_CAP_START + 6, WM_CAP_SET_CALLBACK_WAVESTREAM = WM_CAP_START + 7, WM_CAP_GET_USER_DATA = WM_CAP_START + 8, WM_CAP_SET_USER_DATA = WM_CAP_START + 9, WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10, WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11, WM_CAP_DRIVER_GET_NAMEA = WM_CAP_START + 12, WM_CAP_DRIVER_GET_VERSIONA = WM_CAP_START + 13, WM_CAP_DRIVER_GET_NAMEW = WM_CAP_UNICODE_START + 12, WM_CAP_DRIVER_GET_VERSIONW = WM_CAP_UNICODE_START + 13, } version(Unicode) { alias WM_CAP_DRIVER_GET_NAMEW WM_CAP_DRIVER_GET_NAME; alias WM_CAP_DRIVER_GET_VERSIONW WM_CAP_DRIVER_GET_VERSION; } else { // Unicode alias WM_CAP_DRIVER_GET_NAMEA WM_CAP_DRIVER_GET_NAME; alias WM_CAP_DRIVER_GET_VERSIONA WM_CAP_DRIVER_GET_VERSION; } enum { WM_CAP_DRIVER_GET_CAPS = WM_CAP_START + 14, WM_CAP_FILE_SET_CAPTURE_FILEA = WM_CAP_START + 20, WM_CAP_FILE_GET_CAPTURE_FILEA = WM_CAP_START + 21, WM_CAP_FILE_SAVEASA = WM_CAP_START + 23, WM_CAP_FILE_SAVEDIBA = WM_CAP_START + 25, WM_CAP_FILE_SET_CAPTURE_FILEW = WM_CAP_UNICODE_START + 20, WM_CAP_FILE_GET_CAPTURE_FILEW = WM_CAP_UNICODE_START + 21, WM_CAP_FILE_SAVEASW = WM_CAP_UNICODE_START + 23, WM_CAP_FILE_SAVEDIBW = WM_CAP_UNICODE_START + 25, } version(Unicode) { alias WM_CAP_FILE_SET_CAPTURE_FILEW WM_CAP_FILE_SET_CAPTURE_FILE; alias WM_CAP_FILE_GET_CAPTURE_FILEW WM_CAP_FILE_GET_CAPTURE_FILE; alias WM_CAP_FILE_SAVEASW WM_CAP_FILE_SAVEAS; alias WM_CAP_FILE_SAVEDIBW WM_CAP_FILE_SAVEDIB; } else { // Unicode alias WM_CAP_FILE_SET_CAPTURE_FILEA WM_CAP_FILE_SET_CAPTURE_FILE; alias WM_CAP_FILE_GET_CAPTURE_FILEA WM_CAP_FILE_GET_CAPTURE_FILE; alias WM_CAP_FILE_SAVEASA WM_CAP_FILE_SAVEAS; alias WM_CAP_FILE_SAVEDIBA WM_CAP_FILE_SAVEDIB; } enum { WM_CAP_FILE_ALLOCATE = WM_CAP_START + 22, WM_CAP_FILE_SET_INFOCHUNK = WM_CAP_START + 24, WM_CAP_EDIT_COPY = WM_CAP_START + 30, WM_CAP_SET_AUDIOFORMAT = WM_CAP_START + 35, WM_CAP_GET_AUDIOFORMAT = WM_CAP_START + 36, WM_CAP_DLG_VIDEOFORMAT = WM_CAP_START + 41, WM_CAP_DLG_VIDEOSOURCE = WM_CAP_START + 42, WM_CAP_DLG_VIDEODISPLAY = WM_CAP_START + 43, WM_CAP_GET_VIDEOFORMAT = WM_CAP_START + 44, WM_CAP_SET_VIDEOFORMAT = WM_CAP_START + 45, WM_CAP_DLG_VIDEOCOMPRESSION = WM_CAP_START + 46, WM_CAP_SET_PREVIEW = WM_CAP_START + 50, WM_CAP_SET_OVERLAY = WM_CAP_START + 51, WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52, WM_CAP_SET_SCALE = WM_CAP_START + 53, WM_CAP_GET_STATUS = WM_CAP_START + 54, WM_CAP_SET_SCROLL = WM_CAP_START + 55, WM_CAP_GRAB_FRAME = WM_CAP_START + 60, WM_CAP_GRAB_FRAME_NOSTOP = WM_CAP_START + 61, WM_CAP_SEQUENCE = WM_CAP_START + 62, WM_CAP_SEQUENCE_NOFILE = WM_CAP_START + 63, WM_CAP_SET_SEQUENCE_SETUP = WM_CAP_START + 64, WM_CAP_GET_SEQUENCE_SETUP = WM_CAP_START + 65, WM_CAP_SET_MCI_DEVICEA = WM_CAP_START + 66, WM_CAP_GET_MCI_DEVICEA = WM_CAP_START + 67, WM_CAP_SET_MCI_DEVICEW = WM_CAP_UNICODE_START + 66, WM_CAP_GET_MCI_DEVICEW = WM_CAP_UNICODE_START + 67, } version(Unicode) { alias WM_CAP_SET_MCI_DEVICEW WM_CAP_SET_MCI_DEVICE; alias WM_CAP_GET_MCI_DEVICEW WM_CAP_GET_MCI_DEVICE; } else { // Unicode alias WM_CAP_SET_MCI_DEVICEA WM_CAP_SET_MCI_DEVICE; alias WM_CAP_GET_MCI_DEVICEA WM_CAP_GET_MCI_DEVICE; } enum { WM_CAP_STOP = WM_CAP_START + 68, WM_CAP_ABORT = WM_CAP_START + 69, WM_CAP_SINGLE_FRAME_OPEN = WM_CAP_START + 70, WM_CAP_SINGLE_FRAME_CLOSE = WM_CAP_START + 71, WM_CAP_SINGLE_FRAME = WM_CAP_START + 72, WM_CAP_PAL_OPENA = WM_CAP_START + 80, WM_CAP_PAL_SAVEA = WM_CAP_START + 81, WM_CAP_PAL_OPENW = WM_CAP_UNICODE_START + 80, WM_CAP_PAL_SAVEW = WM_CAP_UNICODE_START + 81, } version(Unicode) { alias WM_CAP_PAL_OPENW WM_CAP_PAL_OPEN; alias WM_CAP_PAL_SAVEW WM_CAP_PAL_SAVE; } else { // Unicode alias WM_CAP_PAL_OPENA WM_CAP_PAL_OPEN; alias WM_CAP_PAL_SAVEA WM_CAP_PAL_SAVE; } enum { WM_CAP_PAL_PASTE = WM_CAP_START + 82, WM_CAP_PAL_AUTOCREATE = WM_CAP_START + 83, WM_CAP_PAL_MANUALCREATE = WM_CAP_START + 84, WM_CAP_SET_CALLBACK_CAPCONTROL = WM_CAP_START + 85, WM_CAP_UNICODE_END = WM_CAP_PAL_SAVEW, WM_CAP_END = WM_CAP_UNICODE_END, } /** * message wrapper */ BOOL capSetCallbackOnError(HWND hWnd, LPVOID fpProc) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_ERROR, 0, cast(LPARAM)fpProc); } BOOL capSetCallbackOnStatus(HWND hWnd, LPVOID fpProc) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_STATUS, 0, cast(LPARAM)fpProc); } BOOL capSetCallbackOnYield(HWND hWnd, LPVOID fpProc) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_YIELD, 0, cast(LPARAM)fpProc); } BOOL capSetCallbackOnFrame(HWND hWnd, LPVOID fpProc) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_FRAME, 0, cast(LPARAM)fpProc); } BOOL capSetCallbackOnVideoStream(HWND hWnd, LPVOID fpProc) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, cast(LPARAM)fpProc); } BOOL capSetCallbackOnWaveStream(HWND hWnd, LPVOID fpProc) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_WAVESTREAM, 0, cast(LPARAM)fpProc); } BOOL capSetCallbackOnCapControl(HWND hWnd, LPVOID fpProc) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_CALLBACK_CAPCONTROL, 0, cast(LPARAM)fpProc); } BOOL capSetUserData(HWND hWnd, LPARAM lUser) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_USER_DATA, 0, lUser); } BOOL capGetUserData(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_GET_USER_DATA, 0, 0); } BOOL capDriverConnect(HWND hWnd, WPARAM i) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_CONNECT, i, 0); } BOOL capDriverDisconnect(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_DISCONNECT, 0, 0); } BOOL capDriverGetName(HWND hWnd, LPTSTR szName, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_GET_NAME, wSize, cast(LPARAM)szName); } BOOL capDriverGetVersion(HWND hWnd, LPTSTR szVer, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_GET_VERSION, wSize, cast(LPARAM)szVer); } BOOL capDriverGetCaps(HWND hWnd, LPCAPDRIVERCAPS s, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_DRIVER_GET_CAPS, wSize, cast(LPARAM)s); } BOOL capFileSetCaptureFile(HWND hWnd, LPTSTR szName) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_SET_CAPTURE_FILE, 0, cast(LPARAM)szName); } BOOL capFileGetCaptureFile(HWND hWnd, LPTSTR szName, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_GET_CAPTURE_FILE, wSize, cast(LPARAM)szName); } BOOL capFileAlloc(HWND hWnd, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_ALLOCATE, wSize, 0); } BOOL capFileSaveAs(HWND hWnd, LPTSTR szName) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_SAVEAS, 0, cast(LPARAM)szName); } BOOL capFileSetInfoChunk(HWND hWnd, LPCAPINFOCHUNK lpInfoChunk) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_SET_INFOCHUNK, 0, cast(LPARAM)lpInfoChunk); } BOOL capFileSaveDIB(HWND hWnd, LPTSTR szName) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_FILE_SAVEDIB, 0, cast(LPARAM)szName); } BOOL capEditCopy(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_EDIT_COPY, 0, 0); } BOOL capSetAudioFormat(HWND hWnd, LPWAVEFORMATEX s, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_AUDIOFORMAT, wSize, cast(LPARAM)s); } DWORD capGetAudioFormat(HWND hWnd, LPWAVEFORMATEX s, WPARAM wSize) { return cast(DWORD)AVICapSM(hWnd, WM_CAP_GET_AUDIOFORMAT, wSize, cast(LPARAM)s); } DWORD capGetAudioFormatSize(HWND hWnd) { return cast(DWORD)AVICapSM(hWnd, WM_CAP_GET_AUDIOFORMAT, 0, 0); } BOOL capDlgVideoFormat(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_DLG_VIDEOFORMAT, 0, 0); } BOOL capDlgVideoSource(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_DLG_VIDEOSOURCE, 0, 0); } BOOL capDlgVideoDisplay(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_DLG_VIDEODISPLAY, 0, 0); } BOOL capDlgVideoCompression(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_DLG_VIDEOCOMPRESSION, 0, 0); } DWORD capGetVideoFormat(HWND hWnd, void* s, WPARAM wSize) { return cast(DWORD)AVICapSM(hWnd, WM_CAP_GET_VIDEOFORMAT, wSize, cast(LPARAM)s); } DWORD capGetVideoFormatSize(HWND hWnd) { return cast(DWORD)AVICapSM(hWnd, WM_CAP_GET_VIDEOFORMAT, 0, 0); } BOOL capSetVideoFormat(HWND hWnd, void* s, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_VIDEOFORMAT, wSize, cast(LPARAM)s); } BOOL capPreview(HWND hWnd, BOOL f) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_PREVIEW, cast(WPARAM)f, 0); } BOOL capPreviewRate(HWND hWnd, WPARAM wMS) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_PREVIEWRATE, wMS, 0); } BOOL capOverlay(HWND hWnd, BOOL f) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_OVERLAY, cast(WPARAM)f, 0); } BOOL capPreviewScale(HWND hWnd, BOOL f) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_SCALE, cast(WPARAM)f, 0); } BOOL capGetStatus(HWND hWnd, LPCAPSTATUS s, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_GET_STATUS, wSize, cast(LPARAM)s); } BOOL capSetScrollPos(HWND hWnd, LPPOINT lpP) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_SCROLL, 0, cast(LPARAM)lpP); } BOOL capGrabFrame(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_GRAB_FRAME, 0, 0); } BOOL capGrabFrameNoStop(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0); } BOOL capCaptureSequence(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SEQUENCE, 0, 0); } BOOL capCaptureSequenceNoFile(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SEQUENCE_NOFILE, 0, 0); } BOOL capCaptureStop(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_STOP, 0, 0); } BOOL capCaptureAbort(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_ABORT, 0, 0); } BOOL capCaptureSingleFrameOpen(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SINGLE_FRAME_OPEN, 0, 0); } BOOL capCaptureSingleFrameClose(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SINGLE_FRAME_CLOSE, 0, 0); } BOOL capCaptureSingleFrame(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SINGLE_FRAME, 0, 0); } BOOL capCaptureGetSetup(HWND hWnd, LPCAPTUREPARMS s, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_GET_SEQUENCE_SETUP, wSize, cast(LPARAM)s); } BOOL capCaptureSetSetup(HWND hWnd, LPCAPTUREPARMS s, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_SEQUENCE_SETUP, wSize, cast(LPARAM)s); } BOOL capSetMCIDeviceName(HWND hWnd, LPTSTR szName) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_SET_MCI_DEVICE, 0, cast(LPARAM)szName); } BOOL capGetMCIDeviceName(HWND hWnd, LPTSTR szName, WPARAM wSize) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_GET_MCI_DEVICE, wSize, cast(LPARAM)szName); } BOOL capPaletteOpen(HWND hWnd, LPTSTR szName) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_OPEN, 0, cast(LPARAM)szName); } BOOL capPaletteSave(HWND hWnd, LPTSTR szName) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_SAVE, 0, cast(LPARAM)szName); } BOOL capPalettePaste(HWND hWnd) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_PASTE, 0, 0); } BOOL capPaletteAuto(HWND hWnd, WPARAM iFrames, LPARAM iColors) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_AUTOCREATE, iFrames, iColors); } BOOL capPaletteManual(HWND hWnd, WPARAM fGrab, LPARAM iColors) { return cast(BOOL)AVICapSM(hWnd, WM_CAP_PAL_MANUALCREATE, fGrab, iColors); } /** * structs */ struct CAPDRIVERCAPS { UINT wDeviceIndex; BOOL fHasOverlay; BOOL fHasDlgVideoSource; BOOL fHasDlgVideoFormat; BOOL fHasDlgVideoDisplay; BOOL fCaptureInitialized; BOOL fDriverSuppliesPalettes; HANDLE hVideoIn; HANDLE hVideoOut; HANDLE hVideoExtIn; HANDLE hVideoExtOut; } alias CAPDRIVERCAPS* PCAPDRIVERCAPS, LPCAPDRIVERCAPS; struct CAPSTATUS { UINT uiImageWidth; UINT uiImageHeight; BOOL fLiveWindow; BOOL fOverlayWindow; BOOL fScale; POINT ptScroll; BOOL fUsingDefaultPalette; BOOL fAudioHardware; BOOL fCapFileExists; DWORD dwCurrentVideoFrame; DWORD dwCurrentVideoFramesDropped; DWORD dwCurrentWaveSamples; DWORD dwCurrentTimeElapsedMS; HPALETTE hPalCurrent; BOOL fCapturingNow; DWORD dwReturn; UINT wNumVideoAllocated; UINT wNumAudioAllocated; } alias CAPSTATUS* PCAPSTATUS, LPCAPSTATUS; struct CAPTUREPARMS { DWORD dwRequestMicroSecPerFrame; BOOL fMakeUserHitOKToCapture; UINT wPercentDropForError; BOOL fYield; DWORD dwIndexSize; UINT wChunkGranularity; BOOL fUsingDOSMemory; UINT wNumVideoRequested; BOOL fCaptureAudio; UINT wNumAudioRequested; UINT vKeyAbort; BOOL fAbortLeftMouse; BOOL fAbortRightMouse; BOOL fLimitEnabled; UINT wTimeLimit; BOOL fMCIControl; BOOL fStepMCIDevice; DWORD dwMCIStartTime; DWORD dwMCIStopTime; BOOL fStepCaptureAt2x; UINT wStepCaptureAverageFrames; DWORD dwAudioBufferSize; BOOL fDisableWriteCache; UINT AVStreamMaster; } alias CAPTUREPARMS* PCAPTUREPARMS, LPCAPTUREPARMS; enum AVSTREAMMASTER_AUDIO = 0; enum AVSTREAMMASTER_NONE = 1; struct CAPINFOCHUNK { FOURCC fccInfoID; LPVOID lpData; LONG cbData; } alias CAPINFOCHUNK* PCAPINFOCHUNK, LPCAPINFOCHUNK; // Callback Definitions extern (Windows) { alias LRESULT function(HWND hWnd) CAPYIELDCALLBACK; alias LRESULT function(HWND hWnd, int nID, LPCWSTR lpsz) CAPSTATUSCALLBACKW; alias LRESULT function(HWND hWnd, int nID, LPCWSTR lpsz) CAPERRORCALLBACKW; alias LRESULT function(HWND hWnd, int nID, LPCSTR lpsz) CAPSTATUSCALLBACKA; alias LRESULT function(HWND hWnd, int nID, LPCSTR lpsz) CAPERRORCALLBACKA; } version(Unicode) { alias CAPSTATUSCALLBACKW CAPSTATUSCALLBACK; alias CAPERRORCALLBACKW CAPERRORCALLBACK; } else { // Unicode alias CAPSTATUSCALLBACKA CAPSTATUSCALLBACK; alias CAPERRORCALLBACKA CAPERRORCALLBACK; } extern (Windows) { alias LRESULT function(HWND hWnd, LPVIDEOHDR lpVHdr) CAPVIDEOCALLBACK; alias LRESULT function(HWND hWnd, LPWAVEHDR lpWHdr) CAPWAVECALLBACK; alias LRESULT function(HWND hWnd, int nState) CAPCONTROLCALLBACK; } // CapControlCallback states enum CONTROLCALLBACK_PREROLL = 1; enum CONTROLCALLBACK_CAPTURING = 2; extern (Windows) { HWND capCreateCaptureWindowA(LPCSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, int nID); BOOL capGetDriverDescriptionA(UINT wDriverIndex, LPSTR lpszName, int cbName, LPSTR lpszVer, int cbVer); HWND capCreateCaptureWindowW(LPCWSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, int nID); BOOL capGetDriverDescriptionW(UINT wDriverIndex, LPWSTR lpszName, int cbName, LPWSTR lpszVer, int cbVer); } version(Unicode) { alias capCreateCaptureWindowW capCreateCaptureWindow; alias capGetDriverDescriptionW capGetDriverDescription; } else { // Unicode alias capCreateCaptureWindowA capCreateCaptureWindow; alias capGetDriverDescriptionA capGetDriverDescription; } // New Information chunk IDs enum infotypeDIGITIZATION_TIME = mmioFOURCC!('I', 'D', 'I', 'T'); enum infotypeSMPTE_TIME = mmioFOURCC!('I', 'S', 'M', 'P'); // status and error callbacks enum { IDS_CAP_BEGIN = 300, IDS_CAP_END = 301, IDS_CAP_INFO = 401, IDS_CAP_OUTOFMEM = 402, IDS_CAP_FILEEXISTS = 403, IDS_CAP_ERRORPALOPEN = 404, IDS_CAP_ERRORPALSAVE = 405, IDS_CAP_ERRORDIBSAVE = 406, IDS_CAP_DEFAVIEXT = 407, IDS_CAP_DEFPALEXT = 408, IDS_CAP_CANTOPEN = 409, IDS_CAP_SEQ_MSGSTART = 410, IDS_CAP_SEQ_MSGSTOP = 411, IDS_CAP_VIDEDITERR = 412, IDS_CAP_READONLYFILE = 413, IDS_CAP_WRITEERROR = 414, IDS_CAP_NODISKSPACE = 415, IDS_CAP_SETFILESIZE = 416, IDS_CAP_SAVEASPERCENT = 417, IDS_CAP_DRIVER_ERROR = 418, IDS_CAP_WAVE_OPEN_ERROR = 419, IDS_CAP_WAVE_ALLOC_ERROR = 420, IDS_CAP_WAVE_PREPARE_ERROR = 421, IDS_CAP_WAVE_ADD_ERROR = 422, IDS_CAP_WAVE_SIZE_ERROR = 423, IDS_CAP_VIDEO_OPEN_ERROR = 424, IDS_CAP_VIDEO_ALLOC_ERROR = 425, IDS_CAP_VIDEO_PREPARE_ERROR = 426, IDS_CAP_VIDEO_ADD_ERROR = 427, IDS_CAP_VIDEO_SIZE_ERROR = 428, IDS_CAP_FILE_OPEN_ERROR = 429, IDS_CAP_FILE_WRITE_ERROR = 430, IDS_CAP_RECORDING_ERROR = 431, IDS_CAP_RECORDING_ERROR2 = 432, IDS_CAP_AVI_INIT_ERROR = 433, IDS_CAP_NO_FRAME_CAP_ERROR = 434, IDS_CAP_NO_PALETTE_WARN = 435, IDS_CAP_MCI_CONTROL_ERROR = 436, IDS_CAP_MCI_CANT_STEP_ERROR = 437, IDS_CAP_NO_AUDIO_CAP_ERROR = 438, IDS_CAP_AVI_DRAWDIB_ERROR = 439, IDS_CAP_COMPRESSOR_ERROR = 440, IDS_CAP_AUDIO_DROP_ERROR = 441, IDS_CAP_AUDIO_DROP_COMPERROR = 442, IDS_CAP_STAT_LIVE_MODE = 500, IDS_CAP_STAT_OVERLAY_MODE = 501, IDS_CAP_STAT_CAP_INIT = 502, IDS_CAP_STAT_CAP_FINI = 503, IDS_CAP_STAT_PALETTE_BUILD = 504, IDS_CAP_STAT_OPTPAL_BUILD = 505, IDS_CAP_STAT_I_FRAMES = 506, IDS_CAP_STAT_L_FRAMES = 507, IDS_CAP_STAT_CAP_L_FRAMES = 508, IDS_CAP_STAT_CAP_AUDIO = 509, IDS_CAP_STAT_VIDEOCURRENT = 510, IDS_CAP_STAT_VIDEOAUDIO = 511, IDS_CAP_STAT_VIDEOONLY = 512, IDS_CAP_STAT_FRAMESDROPPED = 513, } /** * FilePreview dialog. */ extern (Windows) { BOOL GetOpenFileNamePreviewA(LPOPENFILENAMEA lpofn); BOOL GetSaveFileNamePreviewA(LPOPENFILENAMEA lpofn); BOOL GetOpenFileNamePreviewW(LPOPENFILENAMEW lpofn); BOOL GetSaveFileNamePreviewW(LPOPENFILENAMEW lpofn); } version(Unicode) { alias GetOpenFileNamePreviewW GetOpenFileNamePreview; alias GetSaveFileNamePreviewW GetSaveFileNamePreview; } else { // Unicode alias GetOpenFileNamePreviewA GetOpenFileNamePreview; alias GetSaveFileNamePreviewA GetSaveFileNamePreview; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ras.d0000664000175000017500000007702712776214756022461 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ras.d) */ module core.sys.windows.ras; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "rasapi32"); private import core.sys.windows.basetyps, core.sys.windows.lmcons, core.sys.windows.w32api, core.sys.windows.windef; align(4): enum RAS_MaxDeviceType = 16; enum RAS_MaxPhoneNumber = 128; enum RAS_MaxIpAddress = 15; enum RAS_MaxIpxAddress = 21; enum RAS_MaxEntryName = 256; enum RAS_MaxDeviceName = 128; enum RAS_MaxCallbackNumber = RAS_MaxPhoneNumber; enum RAS_MaxAreaCode = 10; enum RAS_MaxPadType = 32; enum RAS_MaxX25Address = 200; enum RAS_MaxFacilities = 200; enum RAS_MaxUserData = 200; enum RAS_MaxReplyMessage = 1024; enum RDEOPT_UsePrefixSuffix = 0x00000001; enum RDEOPT_PausedStates = 0x00000002; enum RDEOPT_IgnoreModemSpeaker = 0x00000004; enum RDEOPT_SetModemSpeaker = 0x00000008; enum RDEOPT_IgnoreSoftwareCompression = 0x00000010; enum RDEOPT_SetSoftwareCompression = 0x00000020; enum RDEOPT_DisableConnectedUI = 0x00000040; enum RDEOPT_DisableReconnectUI = 0x00000080; enum RDEOPT_DisableReconnect = 0x00000100; enum RDEOPT_NoUser = 0x00000200; enum RDEOPT_PauseOnScript = 0x00000400; enum RDEOPT_Router = 0x00000800; enum REN_User = 0x00000000; enum REN_AllUsers = 0x00000001; enum VS_Default = 0; enum VS_PptpOnly = 1; enum VS_PptpFirst = 2; enum VS_L2tpOnly = 3; enum VS_L2tpFirst = 4; enum RASDIALEVENT = "RasDialEvent"; enum WM_RASDIALEVENT = 0xCCCD; enum RASEO_UseCountryAndAreaCodes = 0x00000001; enum RASEO_SpecificIpAddr = 0x00000002; enum RASEO_SpecificNameServers = 0x00000004; enum RASEO_IpHeaderCompression = 0x00000008; enum RASEO_RemoteDefaultGateway = 0x00000010; enum RASEO_DisableLcpExtensions = 0x00000020; enum RASEO_TerminalBeforeDial = 0x00000040; enum RASEO_TerminalAfterDial = 0x00000080; enum RASEO_ModemLights = 0x00000100; enum RASEO_SwCompression = 0x00000200; enum RASEO_RequireEncryptedPw = 0x00000400; enum RASEO_RequireMsEncryptedPw = 0x00000800; enum RASEO_RequireDataEncryption = 0x00001000; enum RASEO_NetworkLogon = 0x00002000; enum RASEO_UseLogonCredentials = 0x00004000; enum RASEO_PromoteAlternates = 0x00008000; enum RASNP_NetBEUI = 0x00000001; enum RASNP_Ipx = 0x00000002; enum RASNP_Ip = 0x00000004; enum RASFP_Ppp = 0x00000001; enum RASFP_Slip = 0x00000002; enum RASFP_Ras = 0x00000004; const TCHAR[] RASDT_Modem = "modem", RASDT_Isdn = "isdn", RASDT_X25 = "x25", RASDT_Vpn = "vpn", RASDT_Pad = "pad", RASDT_Generic = "GENERIC", RASDT_Serial = "SERIAL", RASDT_FrameRelay = "FRAMERELAY", RASDT_Atm = "ATM", RASDT_Sonet = "SONET", RASDT_SW56 = "SW56", RASDT_Irda = "IRDA", RASDT_Parallel = "PARALLEL"; enum RASET_Phone = 1; enum RASET_Vpn = 2; enum RASET_Direct = 3; enum RASET_Internet = 4; static if (_WIN32_WINNT >= 0x401) { enum RASEO_SecureLocalFiles = 0x00010000; enum RASCN_Connection = 0x00000001; enum RASCN_Disconnection = 0x00000002; enum RASCN_BandwidthAdded = 0x00000004; enum RASCN_BandwidthRemoved = 0x00000008; enum RASEDM_DialAll = 1; enum RASEDM_DialAsNeeded = 2; enum RASIDS_Disabled = 0xffffffff; enum RASIDS_UseGlobalValue = 0; enum RASADFLG_PositionDlg = 0x00000001; enum RASCM_UserName = 0x00000001; enum RASCM_Password = 0x00000002; enum RASCM_Domain = 0x00000004; enum RASADP_DisableConnectionQuery = 0; enum RASADP_LoginSessionDisable = 1; enum RASADP_SavedAddressesLimit = 2; enum RASADP_FailedConnectionTimeout = 3; enum RASADP_ConnectionQueryTimeout = 4; } //static if (_WIN32_WINNT >= 0x500) { enum RDEOPT_CustomDial = 0x00001000; enum RASLCPAP_PAP = 0xC023; enum RASLCPAP_SPAP = 0xC027; enum RASLCPAP_CHAP = 0xC223; enum RASLCPAP_EAP = 0xC227; enum RASLCPAD_CHAP_MD5 = 0x05; enum RASLCPAD_CHAP_MS = 0x80; enum RASLCPAD_CHAP_MSV2 = 0x81; enum RASLCPO_PFC = 0x00000001; enum RASLCPO_ACFC = 0x00000002; enum RASLCPO_SSHF = 0x00000004; enum RASLCPO_DES_56 = 0x00000008; enum RASLCPO_3_DES = 0x00000010; enum RASCCPCA_MPPC = 0x00000006; enum RASCCPCA_STAC = 0x00000005; enum RASCCPO_Compression = 0x00000001; enum RASCCPO_HistoryLess = 0x00000002; enum RASCCPO_Encryption56bit = 0x00000010; enum RASCCPO_Encryption40bit = 0x00000020; enum RASCCPO_Encryption128bit = 0x00000040; enum RASEO_RequireEAP = 0x00020000; enum RASEO_RequirePAP = 0x00040000; enum RASEO_RequireSPAP = 0x00080000; enum RASEO_Custom = 0x00100000; enum RASEO_PreviewPhoneNumber = 0x00200000; enum RASEO_SharedPhoneNumbers = 0x00800000; enum RASEO_PreviewUserPw = 0x01000000; enum RASEO_PreviewDomain = 0x02000000; enum RASEO_ShowDialingProgress = 0x04000000; enum RASEO_RequireCHAP = 0x08000000; enum RASEO_RequireMsCHAP = 0x10000000; enum RASEO_RequireMsCHAP2 = 0x20000000; enum RASEO_RequireW95MSCHAP = 0x40000000; enum RASEO_CustomScript = 0x80000000; enum RASIPO_VJ = 0x00000001; enum RCD_SingleUser = 0; enum RCD_AllUsers = 0x00000001; enum RCD_Eap = 0x00000002; enum RASEAPF_NonInteractive = 0x00000002; enum RASEAPF_Logon = 0x00000004; enum RASEAPF_Preview = 0x00000008; enum ET_40Bit = 1; enum ET_128Bit = 2; enum ET_None = 0; enum ET_Require = 1; enum ET_RequireMax = 2; enum ET_Optional = 3; //} enum RASCS_PAUSED = 0x1000; enum RASCS_DONE = 0x2000; enum RASCONNSTATE { RASCS_OpenPort = 0, RASCS_PortOpened, RASCS_ConnectDevice, RASCS_DeviceConnected, RASCS_AllDevicesConnected, RASCS_Authenticate, RASCS_AuthNotify, RASCS_AuthRetry, RASCS_AuthCallback, RASCS_AuthChangePassword, RASCS_AuthProject, RASCS_AuthLinkSpeed, RASCS_AuthAck, RASCS_ReAuthenticate, RASCS_Authenticated, RASCS_PrepareForCallback, RASCS_WaitForModemReset, RASCS_WaitForCallback, RASCS_Projected, RASCS_StartAuthentication, RASCS_CallbackComplete, RASCS_LogonNetwork, RASCS_SubEntryConnected, RASCS_SubEntryDisconnected, RASCS_Interactive = RASCS_PAUSED, RASCS_RetryAuthentication, RASCS_CallbackSetByCaller, RASCS_PasswordExpired, // static if (_WIN32_WINNT >= 0x500) { RASCS_InvokeEapUI, // } RASCS_Connected = RASCS_DONE, RASCS_Disconnected } alias RASCONNSTATE* LPRASCONNSTATE; enum RASPROJECTION { RASP_Amb = 0x10000, RASP_PppNbf = 0x803F, RASP_PppIpx = 0x802B, RASP_PppIp = 0x8021, // static if (_WIN32_WINNT >= 0x500) { RASP_PppCcp = 0x80FD, // } RASP_PppLcp = 0xC021, RASP_Slip = 0x20000 } alias RASPROJECTION* LPRASPROJECTION; alias TypeDef!(HANDLE) HRASCONN; alias HRASCONN* LPHRASCONN; struct RASCONNW { DWORD dwSize; HRASCONN hrasconn; WCHAR[RAS_MaxEntryName + 1] szEntryName; WCHAR[RAS_MaxDeviceType + 1] szDeviceType; WCHAR[RAS_MaxDeviceName + 1] szDeviceName; //static if (_WIN32_WINNT >= 0x401) { WCHAR[MAX_PATH] szPhonebook; DWORD dwSubEntry; //} //static if (_WIN32_WINNT >= 0x500) { GUID guidEntry; //} static if (_WIN32_WINNT >= 0x501) { DWORD dwFlags; LUID luid; } } alias RASCONNW* LPRASCONNW; struct RASCONNA { DWORD dwSize; HRASCONN hrasconn; CHAR[RAS_MaxEntryName + 1] szEntryName; CHAR[RAS_MaxDeviceType + 1] szDeviceType; CHAR[RAS_MaxDeviceName + 1] szDeviceName; //static if (_WIN32_WINNT >= 0x401) { CHAR[MAX_PATH] szPhonebook; DWORD dwSubEntry; //} //static if (_WIN32_WINNT >= 0x500) { GUID guidEntry; //} static if (_WIN32_WINNT >= 0x501) { DWORD dwFlags; LUID luid; } } alias RASCONNA* LPRASCONNA; struct RASCONNSTATUSW { DWORD dwSize; RASCONNSTATE rasconnstate; DWORD dwError; WCHAR[RAS_MaxDeviceType + 1] szDeviceType; WCHAR[RAS_MaxDeviceName + 1] szDeviceName; static if (_WIN32_WINNT >= 0x401) { WCHAR[RAS_MaxPhoneNumber + 1] szPhoneNumber; } } alias RASCONNSTATUSW* LPRASCONNSTATUSW; struct RASCONNSTATUSA { DWORD dwSize; RASCONNSTATE rasconnstate; DWORD dwError; CHAR[RAS_MaxDeviceType + 1] szDeviceType; CHAR[RAS_MaxDeviceName + 1] szDeviceName; static if (_WIN32_WINNT >= 0x401) { CHAR[RAS_MaxPhoneNumber + 1] szPhoneNumber; } } alias RASCONNSTATUSA* LPRASCONNSTATUSA; struct RASDIALPARAMSW { DWORD dwSize; WCHAR[RAS_MaxEntryName + 1] szEntryName; WCHAR[RAS_MaxPhoneNumber + 1] szPhoneNumber; WCHAR[RAS_MaxCallbackNumber + 1] szCallbackNumber; WCHAR[UNLEN + 1] szUserName; WCHAR[PWLEN + 1] szPassword; WCHAR[DNLEN + 1] szDomain; static if (_WIN32_WINNT >= 0x401) { DWORD dwSubEntry; ULONG_PTR dwCallbackId; } } alias RASDIALPARAMSW* LPRASDIALPARAMSW; struct RASDIALPARAMSA{ DWORD dwSize; CHAR[RAS_MaxEntryName + 1] szEntryName; CHAR[RAS_MaxPhoneNumber + 1] szPhoneNumber; CHAR[RAS_MaxCallbackNumber + 1] szCallbackNumber; CHAR[UNLEN + 1] szUserName; CHAR[PWLEN + 1] szPassword; CHAR[DNLEN + 1] szDomain; static if (_WIN32_WINNT >= 0x401) { DWORD dwSubEntry; ULONG_PTR dwCallbackId; } } alias RASDIALPARAMSA* LPRASDIALPARAMSA; //static if (_WIN32_WINNT >= 0x500) { struct RASEAPINFO { DWORD dwSizeofEapInfo; BYTE *pbEapInfo; } //} struct RASDIALEXTENSIONS { DWORD dwSize; DWORD dwfOptions; HWND hwndParent; ULONG_PTR reserved; //static if (_WIN32_WINNT >= 0x500) { ULONG_PTR reserved1; RASEAPINFO RasEapInfo; //} } alias RASDIALEXTENSIONS* LPRASDIALEXTENSIONS; struct RASENTRYNAMEW { DWORD dwSize; WCHAR[RAS_MaxEntryName + 1] szEntryName; //static if (_WIN32_WINNT >= 0x500) { DWORD dwFlags; WCHAR[MAX_PATH + 1] szPhonebookPath; //} } alias RASENTRYNAMEW* LPRASENTRYNAMEW; struct RASENTRYNAMEA{ DWORD dwSize; CHAR[RAS_MaxEntryName + 1] szEntryName; //static if (_WIN32_WINNT >= 0x500) { DWORD dwFlags; CHAR[MAX_PATH + 1] szPhonebookPath; //} } alias RASENTRYNAMEA* LPRASENTRYNAMEA; struct RASAMBW{ DWORD dwSize; DWORD dwError; WCHAR[NETBIOS_NAME_LEN + 1] szNetBiosError; BYTE bLana; } alias RASAMBW* LPRASAMBW; struct RASAMBA{ DWORD dwSize; DWORD dwError; CHAR[NETBIOS_NAME_LEN + 1] szNetBiosError; BYTE bLana; } alias RASAMBA* LPRASAMBA; struct RASPPPNBFW{ DWORD dwSize; DWORD dwError; DWORD dwNetBiosError; WCHAR[NETBIOS_NAME_LEN + 1] szNetBiosError; WCHAR[NETBIOS_NAME_LEN + 1] szWorkstationName; BYTE bLana; } alias RASPPPNBFW* LPRASPPPNBFW; struct RASPPPNBFA{ DWORD dwSize; DWORD dwError; DWORD dwNetBiosError; CHAR[NETBIOS_NAME_LEN + 1] szNetBiosError; CHAR[NETBIOS_NAME_LEN + 1] szWorkstationName; BYTE bLana; } alias RASPPPNBFA* LPRASPPPNBFA; struct RASPPPIPXW { DWORD dwSize; DWORD dwError; WCHAR[RAS_MaxIpxAddress + 1] szIpxAddress; } alias RASPPPIPXW* LPRASPPPIPXW; struct RASPPPIPXA { DWORD dwSize; DWORD dwError; CHAR[RAS_MaxIpxAddress + 1] szIpxAddress; } alias RASPPPIPXA* LPRASPPPIPXA; struct RASPPPIPW{ DWORD dwSize; DWORD dwError; WCHAR[RAS_MaxIpAddress + 1] szIpAddress; //#ifndef WINNT35COMPATIBLE WCHAR[RAS_MaxIpAddress + 1] szServerIpAddress; //#endif //static if (_WIN32_WINNT >= 0x500) { DWORD dwOptions; DWORD dwServerOptions; //} } alias RASPPPIPW* LPRASPPPIPW; struct RASPPPIPA{ DWORD dwSize; DWORD dwError; CHAR[RAS_MaxIpAddress + 1] szIpAddress; //#ifndef WINNT35COMPATIBLE CHAR[RAS_MaxIpAddress + 1] szServerIpAddress; //#endif //static if (_WIN32_WINNT >= 0x500) { DWORD dwOptions; DWORD dwServerOptions; //} } alias RASPPPIPA* LPRASPPPIPA; struct RASPPPLCPW{ DWORD dwSize; BOOL fBundled; //static if (_WIN32_WINNT >= 0x500) { DWORD dwError; DWORD dwAuthenticationProtocol; DWORD dwAuthenticationData; DWORD dwEapTypeId; DWORD dwServerAuthenticationProtocol; DWORD dwServerAuthenticationData; DWORD dwServerEapTypeId; BOOL fMultilink; DWORD dwTerminateReason; DWORD dwServerTerminateReason; WCHAR[RAS_MaxReplyMessage] szReplyMessage; DWORD dwOptions; DWORD dwServerOptions; //} } alias RASPPPLCPW* LPRASPPPLCPW; struct RASPPPLCPA{ DWORD dwSize; BOOL fBundled; //static if (_WIN32_WINNT >= 0x500) { DWORD dwError; DWORD dwAuthenticationProtocol; DWORD dwAuthenticationData; DWORD dwEapTypeId; DWORD dwServerAuthenticationProtocol; DWORD dwServerAuthenticationData; DWORD dwServerEapTypeId; BOOL fMultilink; DWORD dwTerminateReason; DWORD dwServerTerminateReason; CHAR[RAS_MaxReplyMessage] szReplyMessage; DWORD dwOptions; DWORD dwServerOptions; //} } alias RASPPPLCPA* LPRASPPPLCPA; struct RASSLIPW{ DWORD dwSize; DWORD dwError; WCHAR[RAS_MaxIpAddress + 1] szIpAddress; } alias RASSLIPW* LPRASSLIPW; struct RASSLIPA{ DWORD dwSize; DWORD dwError; CHAR[RAS_MaxIpAddress + 1] szIpAddress; } alias RASSLIPA* LPRASSLIPA; struct RASDEVINFOW{ DWORD dwSize; WCHAR[RAS_MaxDeviceType + 1] szDeviceType; WCHAR[RAS_MaxDeviceName + 1] szDeviceName; } alias RASDEVINFOW* LPRASDEVINFOW; struct RASDEVINFOA{ DWORD dwSize; CHAR[RAS_MaxDeviceType + 1] szDeviceType; CHAR[RAS_MaxDeviceName + 1] szDeviceName; } alias RASDEVINFOA* LPRASDEVINFOA; struct RASCTRYINFO { DWORD dwSize; DWORD dwCountryID; DWORD dwNextCountryID; DWORD dwCountryCode; DWORD dwCountryNameOffset; } alias RASCTRYINFO* LPRASCTRYINFO; alias RASCTRYINFO RASCTRYINFOW, RASCTRYINFOA; alias RASCTRYINFOW* LPRASCTRYINFOW; alias RASCTRYINFOA* LPRASCTRYINFOA; struct RASIPADDR { BYTE a; BYTE b; BYTE c; BYTE d; } struct RASENTRYW { DWORD dwSize; DWORD dwfOptions; DWORD dwCountryID; DWORD dwCountryCode; WCHAR[RAS_MaxAreaCode + 1] szAreaCode; WCHAR[RAS_MaxPhoneNumber + 1] szLocalPhoneNumber; DWORD dwAlternateOffset; RASIPADDR ipaddr; RASIPADDR ipaddrDns; RASIPADDR ipaddrDnsAlt; RASIPADDR ipaddrWins; RASIPADDR ipaddrWinsAlt; DWORD dwFrameSize; DWORD dwfNetProtocols; DWORD dwFramingProtocol; WCHAR[MAX_PATH] szScript; WCHAR[MAX_PATH] szAutodialDll; WCHAR[MAX_PATH] szAutodialFunc; WCHAR[RAS_MaxDeviceType + 1] szDeviceType; WCHAR[RAS_MaxDeviceName + 1] szDeviceName; WCHAR[RAS_MaxPadType + 1] szX25PadType; WCHAR[RAS_MaxX25Address + 1] szX25Address; WCHAR[RAS_MaxFacilities + 1] szX25Facilities; WCHAR[RAS_MaxUserData + 1] szX25UserData; DWORD dwChannels; DWORD dwReserved1; DWORD dwReserved2; //static if (_WIN32_WINNT >= 0x401) { DWORD dwSubEntries; DWORD dwDialMode; DWORD dwDialExtraPercent; DWORD dwDialExtraSampleSeconds; DWORD dwHangUpExtraPercent; DWORD dwHangUpExtraSampleSeconds; DWORD dwIdleDisconnectSeconds; //} //static if (_WIN32_WINNT >= 0x500) { DWORD dwType; DWORD dwEncryptionType; DWORD dwCustomAuthKey; GUID guidId; WCHAR[MAX_PATH] szCustomDialDll; DWORD dwVpnStrategy; //} } alias RASENTRYW* LPRASENTRYW; struct RASENTRYA { DWORD dwSize; DWORD dwfOptions; DWORD dwCountryID; DWORD dwCountryCode; CHAR[RAS_MaxAreaCode + 1] szAreaCode; CHAR[RAS_MaxPhoneNumber + 1] szLocalPhoneNumber; DWORD dwAlternateOffset; RASIPADDR ipaddr; RASIPADDR ipaddrDns; RASIPADDR ipaddrDnsAlt; RASIPADDR ipaddrWins; RASIPADDR ipaddrWinsAlt; DWORD dwFrameSize; DWORD dwfNetProtocols; DWORD dwFramingProtocol; CHAR[MAX_PATH] szScript; CHAR[MAX_PATH] szAutodialDll; CHAR[MAX_PATH] szAutodialFunc; CHAR[RAS_MaxDeviceType + 1] szDeviceType; CHAR[RAS_MaxDeviceName + 1] szDeviceName; CHAR[RAS_MaxPadType + 1] szX25PadType; CHAR[RAS_MaxX25Address + 1] szX25Address; CHAR[RAS_MaxFacilities + 1] szX25Facilities; CHAR[RAS_MaxUserData + 1] szX25UserData; DWORD dwChannels; DWORD dwReserved1; DWORD dwReserved2; //static if (_WIN32_WINNT >= 0x401) { DWORD dwSubEntries; DWORD dwDialMode; DWORD dwDialExtraPercent; DWORD dwDialExtraSampleSeconds; DWORD dwHangUpExtraPercent; DWORD dwHangUpExtraSampleSeconds; DWORD dwIdleDisconnectSeconds; //} //static if (_WIN32_WINNT >= 0x500) { DWORD dwType; DWORD dwEncryptionType; DWORD dwCustomAuthKey; GUID guidId; CHAR[MAX_PATH] szCustomDialDll; DWORD dwVpnStrategy; //} } alias RASENTRYA* LPRASENTRYA; //static if (_WIN32_WINNT >= 0x401) { struct RASADPARAMS { DWORD dwSize; HWND hwndOwner; DWORD dwFlags; LONG xDlg; LONG yDlg; } alias RASADPARAMS* LPRASADPARAMS; struct RASSUBENTRYW{ DWORD dwSize; DWORD dwfFlags; WCHAR[RAS_MaxDeviceType + 1] szDeviceType; WCHAR[RAS_MaxDeviceName + 1] szDeviceName; WCHAR[RAS_MaxPhoneNumber + 1] szLocalPhoneNumber; DWORD dwAlternateOffset; } alias RASSUBENTRYW* LPRASSUBENTRYW; struct RASSUBENTRYA{ DWORD dwSize; DWORD dwfFlags; CHAR[RAS_MaxDeviceType + 1] szDeviceType; CHAR[RAS_MaxDeviceName + 1] szDeviceName; CHAR[RAS_MaxPhoneNumber + 1] szLocalPhoneNumber; DWORD dwAlternateOffset; } alias RASSUBENTRYA* LPRASSUBENTRYA; struct RASCREDENTIALSW{ DWORD dwSize; DWORD dwMask; WCHAR[UNLEN + 1] szUserName; WCHAR[PWLEN + 1] szPassword; WCHAR[DNLEN + 1] szDomain; } alias RASCREDENTIALSW* LPRASCREDENTIALSW; struct RASCREDENTIALSA{ DWORD dwSize; DWORD dwMask; CHAR[UNLEN + 1] szUserName; CHAR[PWLEN + 1] szPassword; CHAR[DNLEN + 1] szDomain; } alias RASCREDENTIALSA* LPRASCREDENTIALSA; struct RASAUTODIALENTRYW{ DWORD dwSize; DWORD dwFlags; DWORD dwDialingLocation; WCHAR[RAS_MaxEntryName + 1] szEntry; } alias RASAUTODIALENTRYW* LPRASAUTODIALENTRYW; struct RASAUTODIALENTRYA{ DWORD dwSize; DWORD dwFlags; DWORD dwDialingLocation; CHAR[RAS_MaxEntryName + 1] szEntry; } alias RASAUTODIALENTRYA* LPRASAUTODIALENTRYA; //} //static if (_WIN32_WINNT >= 0x500) { struct RASPPPCCP{ DWORD dwSize; DWORD dwError; DWORD dwCompressionAlgorithm; DWORD dwOptions; DWORD dwServerCompressionAlgorithm; DWORD dwServerOptions; } alias RASPPPCCP* LPRASPPPCCP; struct RASEAPUSERIDENTITYW{ WCHAR[UNLEN + 1] szUserName; DWORD dwSizeofEapInfo; BYTE[1] pbEapInfo; } alias RASEAPUSERIDENTITYW* LPRASEAPUSERIDENTITYW; struct RASEAPUSERIDENTITYA{ CHAR[UNLEN + 1] szUserName; DWORD dwSizeofEapInfo; BYTE[1] pbEapInfo; } alias RASEAPUSERIDENTITYA* LPRASEAPUSERIDENTITYA; struct RAS_STATS{ DWORD dwSize; DWORD dwBytesXmited; DWORD dwBytesRcved; DWORD dwFramesXmited; DWORD dwFramesRcved; DWORD dwCrcErr; DWORD dwTimeoutErr; DWORD dwAlignmentErr; DWORD dwHardwareOverrunErr; DWORD dwFramingErr; DWORD dwBufferOverrunErr; DWORD dwCompressionRatioIn; DWORD dwCompressionRatioOut; DWORD dwBps; DWORD dwConnectDuration; } alias RAS_STATS* PRAS_STATS; //} /* UNICODE typedefs for structures*/ version (Unicode) { alias RASCONNW RASCONN; alias RASENTRYW RASENTRY; alias RASCONNSTATUSW RASCONNSTATUS; alias RASDIALPARAMSW RASDIALPARAMS; alias RASAMBW RASAMB; alias RASPPPNBFW RASPPPNBF; alias RASPPPIPXW RASPPPIPX; alias RASPPPIPW RASPPPIP; alias RASPPPLCPW RASPPPLCP; alias RASSLIPW RASSLIP; alias RASDEVINFOW RASDEVINFO; alias RASENTRYNAMEW RASENTRYNAME; //static if (_WIN32_WINNT >= 0x401) { alias RASSUBENTRYW RASSUBENTRY; alias RASCREDENTIALSW RASCREDENTIALS; alias RASAUTODIALENTRYW RASAUTODIALENTRY; //} //static if (_WIN32_WINNT >= 0x500) { alias RASEAPUSERIDENTITYW RASEAPUSERIDENTITY; //} } else { // ! defined UNICODE alias RASCONNA RASCONN; alias RASENTRYA RASENTRY; alias RASCONNSTATUSA RASCONNSTATUS; alias RASDIALPARAMSA RASDIALPARAMS; alias RASAMBA RASAMB; alias RASPPPNBFA RASPPPNBF; alias RASPPPIPXA RASPPPIPX; alias RASPPPIPA RASPPPIP; alias RASPPPLCPA RASPPPLCP; alias RASSLIPA RASSLIP; alias RASDEVINFOA RASDEVINFO; alias RASENTRYNAMEA RASENTRYNAME; //static if (_WIN32_WINNT >= 0x401) { alias RASSUBENTRYA RASSUBENTRY; alias RASCREDENTIALSA RASCREDENTIALS; alias RASAUTODIALENTRYA RASAUTODIALENTRY; //} //static if (_WIN32_WINNT >= 0x500) { alias RASEAPUSERIDENTITYA RASEAPUSERIDENTITY; //} }// ! UNICODE alias RASCONN* LPRASCONN; alias RASENTRY* LPRASENTRY; alias RASCONNSTATUS* LPRASCONNSTATUS; alias RASDIALPARAMS* LPRASDIALPARAMS; alias RASAMB* LPRASAM; alias RASPPPNBF* LPRASPPPNBF; alias RASPPPIPX* LPRASPPPIPX; alias RASPPPIP* LPRASPPPIP; alias RASPPPLCP* LPRASPPPLCP; alias RASSLIP* LPRASSLIP; alias RASDEVINFO* LPRASDEVINFO; alias RASENTRYNAME* LPRASENTRYNAME; //static if (_WIN32_WINNT >= 0x401) { alias RASSUBENTRY* LPRASSUBENTRY; alias RASCREDENTIALS* LPRASCREDENTIALS; alias RASAUTODIALENTRY* LPRASAUTODIALENTRY; //} //static if (_WIN32_WINNT >= 0x500) { alias RASEAPUSERIDENTITY* LPRASEAPUSERIDENTITY; //} /* Callback prototypes */ deprecated { alias BOOL function (HWND, LPSTR, DWORD, LPDWORD) ORASADFUNC; } alias void function (UINT, RASCONNSTATE, DWORD) RASDIALFUNC; alias void function(HRASCONN, UINT, RASCONNSTATE, DWORD, DWORD) RASDIALFUNC1; alias DWORD function (ULONG_PTR, DWORD, HRASCONN, UINT, RASCONNSTATE, DWORD, DWORD) RASDIALFUNC2; /* External functions */ DWORD RasDialA(LPRASDIALEXTENSIONS, LPCSTR, LPRASDIALPARAMSA, DWORD, LPVOID, LPHRASCONN); DWORD RasDialW(LPRASDIALEXTENSIONS, LPCWSTR, LPRASDIALPARAMSW, DWORD, LPVOID, LPHRASCONN); DWORD RasEnumConnectionsA(LPRASCONNA, LPDWORD, LPDWORD); DWORD RasEnumConnectionsW(LPRASCONNW, LPDWORD, LPDWORD); DWORD RasEnumEntriesA(LPCSTR, LPCSTR, LPRASENTRYNAMEA, LPDWORD, LPDWORD); DWORD RasEnumEntriesW(LPCWSTR, LPCWSTR, LPRASENTRYNAMEW, LPDWORD, LPDWORD); DWORD RasGetConnectStatusA(HRASCONN, LPRASCONNSTATUSA); DWORD RasGetConnectStatusW(HRASCONN, LPRASCONNSTATUSW); DWORD RasGetErrorStringA(UINT, LPSTR, DWORD); DWORD RasGetErrorStringW(UINT, LPWSTR, DWORD); DWORD RasHangUpA(HRASCONN); DWORD RasHangUpW(HRASCONN); DWORD RasGetProjectionInfoA(HRASCONN, RASPROJECTION, LPVOID, LPDWORD); DWORD RasGetProjectionInfoW(HRASCONN, RASPROJECTION, LPVOID, LPDWORD); DWORD RasCreatePhonebookEntryA(HWND, LPCSTR); DWORD RasCreatePhonebookEntryW(HWND, LPCWSTR); DWORD RasEditPhonebookEntryA(HWND, LPCSTR, LPCSTR); DWORD RasEditPhonebookEntryW(HWND, LPCWSTR, LPCWSTR); DWORD RasSetEntryDialParamsA(LPCSTR, LPRASDIALPARAMSA, BOOL); DWORD RasSetEntryDialParamsW(LPCWSTR, LPRASDIALPARAMSW, BOOL); DWORD RasGetEntryDialParamsA(LPCSTR, LPRASDIALPARAMSA, LPBOOL); DWORD RasGetEntryDialParamsW(LPCWSTR, LPRASDIALPARAMSW, LPBOOL); DWORD RasEnumDevicesA(LPRASDEVINFOA, LPDWORD, LPDWORD); DWORD RasEnumDevicesW(LPRASDEVINFOW, LPDWORD, LPDWORD); DWORD RasGetCountryInfoA(LPRASCTRYINFOA, LPDWORD); DWORD RasGetCountryInfoW(LPRASCTRYINFOW, LPDWORD); DWORD RasGetEntryPropertiesA(LPCSTR, LPCSTR, LPRASENTRYA, LPDWORD, LPBYTE, LPDWORD); DWORD RasGetEntryPropertiesW(LPCWSTR, LPCWSTR, LPRASENTRYW, LPDWORD, LPBYTE, LPDWORD); DWORD RasSetEntryPropertiesA(LPCSTR, LPCSTR, LPRASENTRYA, DWORD, LPBYTE, DWORD); DWORD RasSetEntryPropertiesW(LPCWSTR, LPCWSTR, LPRASENTRYW, DWORD, LPBYTE, DWORD); DWORD RasRenameEntryA(LPCSTR, LPCSTR, LPCSTR); DWORD RasRenameEntryW(LPCWSTR, LPCWSTR, LPCWSTR); DWORD RasDeleteEntryA(LPCSTR, LPCSTR); DWORD RasDeleteEntryW(LPCWSTR, LPCWSTR); DWORD RasValidateEntryNameA(LPCSTR, LPCSTR); DWORD RasValidateEntryNameW(LPCWSTR, LPCWSTR); //static if(_WIN32_WINNT >= 0x401) { alias BOOL function(LPSTR, LPSTR, LPRASADPARAMS, LPDWORD) RASADFUNCA; alias BOOL function(LPWSTR, LPWSTR, LPRASADPARAMS, LPDWORD) RASADFUNCW; DWORD RasGetSubEntryHandleA(HRASCONN, DWORD, LPHRASCONN); DWORD RasGetSubEntryHandleW(HRASCONN, DWORD, LPHRASCONN); DWORD RasGetCredentialsA(LPCSTR, LPCSTR, LPRASCREDENTIALSA); DWORD RasGetCredentialsW(LPCWSTR, LPCWSTR, LPRASCREDENTIALSW); DWORD RasSetCredentialsA(LPCSTR, LPCSTR, LPRASCREDENTIALSA, BOOL); DWORD RasSetCredentialsW(LPCWSTR, LPCWSTR, LPRASCREDENTIALSW, BOOL); DWORD RasConnectionNotificationA(HRASCONN, HANDLE, DWORD); DWORD RasConnectionNotificationW(HRASCONN, HANDLE, DWORD); DWORD RasGetSubEntryPropertiesA(LPCSTR, LPCSTR, DWORD, LPRASSUBENTRYA, LPDWORD, LPBYTE, LPDWORD); DWORD RasGetSubEntryPropertiesW(LPCWSTR, LPCWSTR, DWORD, LPRASSUBENTRYW, LPDWORD, LPBYTE, LPDWORD); DWORD RasSetSubEntryPropertiesA(LPCSTR, LPCSTR, DWORD, LPRASSUBENTRYA, DWORD, LPBYTE, DWORD); DWORD RasSetSubEntryPropertiesW(LPCWSTR, LPCWSTR, DWORD, LPRASSUBENTRYW, DWORD, LPBYTE, DWORD); DWORD RasGetAutodialAddressA(LPCSTR, LPDWORD, LPRASAUTODIALENTRYA, LPDWORD, LPDWORD); DWORD RasGetAutodialAddressW(LPCWSTR, LPDWORD, LPRASAUTODIALENTRYW, LPDWORD, LPDWORD); DWORD RasSetAutodialAddressA(LPCSTR, DWORD, LPRASAUTODIALENTRYA, DWORD, DWORD); DWORD RasSetAutodialAddressW(LPCWSTR, DWORD, LPRASAUTODIALENTRYW, DWORD, DWORD); DWORD RasEnumAutodialAddressesA(LPSTR*, LPDWORD, LPDWORD); DWORD RasEnumAutodialAddressesW(LPWSTR*, LPDWORD, LPDWORD); DWORD RasGetAutodialEnableA(DWORD, LPBOOL); DWORD RasGetAutodialEnableW(DWORD, LPBOOL); DWORD RasSetAutodialEnableA(DWORD, BOOL); DWORD RasSetAutodialEnableW(DWORD, BOOL); DWORD RasGetAutodialParamA(DWORD, LPVOID, LPDWORD); DWORD RasGetAutodialParamW(DWORD, LPVOID, LPDWORD); DWORD RasSetAutodialParamA(DWORD, LPVOID, DWORD); DWORD RasSetAutodialParamW(DWORD, LPVOID, DWORD); //} static if (_WIN32_WINNT >= 0x500) { alias DWORD function(HRASCONN) RasCustomHangUpFn; alias DWORD function(LPCTSTR, LPCTSTR, DWORD) RasCustomDeleteEntryNotifyFn; alias DWORD function(HINSTANCE, LPRASDIALEXTENSIONS, LPCTSTR, LPRASDIALPARAMS, DWORD, LPVOID, LPHRASCONN, DWORD) RasCustomDialFn; DWORD RasInvokeEapUI(HRASCONN, DWORD, LPRASDIALEXTENSIONS, HWND); DWORD RasGetLinkStatistics(HRASCONN, DWORD, RAS_STATS*); DWORD RasGetConnectionStatistics(HRASCONN, RAS_STATS*); DWORD RasClearLinkStatistics(HRASCONN, DWORD); DWORD RasClearConnectionStatistics(HRASCONN); DWORD RasGetEapUserDataA(HANDLE, LPCSTR, LPCSTR, BYTE*, DWORD*); DWORD RasGetEapUserDataW(HANDLE, LPCWSTR, LPCWSTR, BYTE*, DWORD*); DWORD RasSetEapUserDataA(HANDLE, LPCSTR, LPCSTR, BYTE*, DWORD); DWORD RasSetEapUserDataW(HANDLE, LPCWSTR, LPCWSTR, BYTE*, DWORD); DWORD RasGetCustomAuthDataA(LPCSTR, LPCSTR, BYTE*, DWORD*); DWORD RasGetCustomAuthDataW(LPCWSTR, LPCWSTR, BYTE*, DWORD*); DWORD RasSetCustomAuthDataA(LPCSTR, LPCSTR, BYTE*, DWORD); DWORD RasSetCustomAuthDataW(LPCWSTR, LPCWSTR, BYTE*, DWORD); DWORD RasGetEapUserIdentityW(LPCWSTR, LPCWSTR, DWORD, HWND, LPRASEAPUSERIDENTITYW*); DWORD RasGetEapUserIdentityA(LPCSTR, LPCSTR, DWORD, HWND, LPRASEAPUSERIDENTITYA*); void RasFreeEapUserIdentityW(LPRASEAPUSERIDENTITYW); void RasFreeEapUserIdentityA(LPRASEAPUSERIDENTITYA); } /* UNICODE defines for functions */ version(Unicode) { alias RasDialW RasDial; alias RasEnumConnectionsW RasEnumConnections; alias RasEnumEntriesW RasEnumEntries; alias RasGetConnectStatusW RasGetConnectStatus; alias RasGetErrorStringW RasGetErrorString; alias RasHangUpW RasHangUp; alias RasGetProjectionInfoW RasGetProjectionInfo; alias RasCreatePhonebookEntryW RasCreatePhonebookEntry; alias RasEditPhonebookEntryW RasEditPhonebookEntry; alias RasSetEntryDialParamsW RasSetEntryDialParams; alias RasGetEntryDialParamsW RasGetEntryDialParams; alias RasEnumDevicesW RasEnumDevices; alias RasGetCountryInfoW RasGetCountryInfo; alias RasGetEntryPropertiesW RasGetEntryProperties; alias RasSetEntryPropertiesW RasSetEntryProperties; alias RasRenameEntryW RasRenameEntry; alias RasDeleteEntryW RasDeleteEntry; alias RasValidateEntryNameW RasValidateEntryName; //static if (_WIN32_WINNT >= 0x401) { alias RASADFUNCW RASADFUNC; alias RasGetSubEntryHandleW RasGetSubEntryHandle; alias RasConnectionNotificationW RasConnectionNotification; alias RasGetSubEntryPropertiesW RasGetSubEntryProperties; alias RasSetSubEntryPropertiesW RasSetSubEntryProperties; alias RasGetCredentialsW RasGetCredentials; alias RasSetCredentialsW RasSetCredentials; alias RasGetAutodialAddressW RasGetAutodialAddress; alias RasSetAutodialAddressW RasSetAutodialAddress; alias RasEnumAutodialAddressesW RasEnumAutodialAddresses; alias RasGetAutodialEnableW RasGetAutodialEnable; alias RasSetAutodialEnableW RasSetAutodialEnable; alias RasGetAutodialParamW RasGetAutodialParam; alias RasSetAutodialParamW RasSetAutodialParam; //} //static if (_WIN32_WINNT >= 0x500) { alias RasGetEapUserDataW RasGetEapUserData; alias RasSetEapUserDataW RasSetEapUserData; alias RasGetCustomAuthDataW RasGetCustomAuthData; alias RasSetCustomAuthDataW RasSetCustomAuthData; alias RasGetEapUserIdentityW RasGetEapUserIdentity; alias RasFreeEapUserIdentityW RasFreeEapUserIdentity; //} } else { // !Unicode alias RasDialA RasDial; alias RasEnumConnectionsA RasEnumConnections; alias RasEnumEntriesA RasEnumEntries; alias RasGetConnectStatusA RasGetConnectStatus; alias RasGetErrorStringA RasGetErrorString; alias RasHangUpA RasHangUp; alias RasGetProjectionInfoA RasGetProjectionInfo; alias RasCreatePhonebookEntryA RasCreatePhonebookEntry; alias RasEditPhonebookEntryA RasEditPhonebookEntry; alias RasSetEntryDialParamsA RasSetEntryDialParams; alias RasGetEntryDialParamsA RasGetEntryDialParams; alias RasEnumDevicesA RasEnumDevices; alias RasGetCountryInfoA RasGetCountryInfo; alias RasGetEntryPropertiesA RasGetEntryProperties; alias RasSetEntryPropertiesA RasSetEntryProperties; alias RasRenameEntryA RasRenameEntry; alias RasDeleteEntryA RasDeleteEntry; alias RasValidateEntryNameA RasValidateEntryName; //static if (_WIN32_WINNT >= 0x401) { alias RASADFUNCA RASADFUNC; alias RasGetSubEntryHandleA RasGetSubEntryHandle; alias RasConnectionNotificationA RasConnectionNotification; alias RasGetSubEntryPropertiesA RasGetSubEntryProperties; alias RasSetSubEntryPropertiesA RasSetSubEntryProperties; alias RasGetCredentialsA RasGetCredentials; alias RasSetCredentialsA RasSetCredentials; alias RasGetAutodialAddressA RasGetAutodialAddress; alias RasSetAutodialAddressA RasSetAutodialAddress; alias RasEnumAutodialAddressesA RasEnumAutodialAddresses; alias RasGetAutodialEnableA RasGetAutodialEnable; alias RasSetAutodialEnableA RasSetAutodialEnable; alias RasGetAutodialParamA RasGetAutodialParam; alias RasSetAutodialParamA RasSetAutodialParam; //} //static if (_WIN32_WINNT >= 0x500) { alias RasGetEapUserDataA RasGetEapUserData; alias RasSetEapUserDataA RasSetEapUserData; alias RasGetCustomAuthDataA RasGetCustomAuthData; alias RasSetCustomAuthDataA RasSetCustomAuthData; alias RasGetEapUserIdentityA RasGetEapUserIdentity; alias RasFreeEapUserIdentityA RasFreeEapUserIdentity; //} } //#endif // !Unicode ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winbase.d0000664000175000017500000031555412776214756023324 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winbase.d) */ module core.sys.windows.winbase; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "kernel32"); /** Translation Notes: The following macros are obsolete, and have no effect. LockSegment(w), MakeProcInstance(p, i), UnlockResource(h), UnlockSegment(w) FreeModule(m), FreeProcInstance(p), GetFreeSpace(w), DefineHandleTable(w) SetSwapAreaSize(w), LimitEmsPages(n), Yield() // These are not required for DMD. //FIXME: // #ifndef UNDER_CE int WinMain(HINSTANCE, HINSTANCE, LPSTR, int); #else int WinMain(HINSTANCE, HINSTANCE, LPWSTR, int); #endif int wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int); */ import core.sys.windows.windef, core.sys.windows.winver; private import core.sys.windows.basetyps, core.sys.windows.w32api, core.sys.windows.winnt; // FIXME: //alias void va_list; import core.stdc.stdarg : va_list; // COMMPROP structure, used by GetCommProperties() // ----------------------------------------------- // Communications provider type enum : DWORD { PST_UNSPECIFIED, PST_RS232, PST_PARALLELPORT, PST_RS422, PST_RS423, PST_RS449, PST_MODEM, // = 6 PST_FAX = 0x0021, PST_SCANNER = 0x0022, PST_NETWORK_BRIDGE = 0x0100, PST_LAT = 0x0101, PST_TCPIP_TELNET = 0x0102, PST_X25 = 0x0103 } // Max baud rate enum : DWORD { BAUD_075 = 0x00000001, BAUD_110 = 0x00000002, BAUD_134_5 = 0x00000004, BAUD_150 = 0x00000008, BAUD_300 = 0x00000010, BAUD_600 = 0x00000020, BAUD_1200 = 0x00000040, BAUD_1800 = 0x00000080, BAUD_2400 = 0x00000100, BAUD_4800 = 0x00000200, BAUD_7200 = 0x00000400, BAUD_9600 = 0x00000800, BAUD_14400 = 0x00001000, BAUD_19200 = 0x00002000, BAUD_38400 = 0x00004000, BAUD_56K = 0x00008000, BAUD_128K = 0x00010000, BAUD_115200 = 0x00020000, BAUD_57600 = 0x00040000, BAUD_USER = 0x10000000 } // Comm capabilities enum : DWORD { PCF_DTRDSR = 0x0001, PCF_RTSCTS = 0x0002, PCF_RLSD = 0x0004, PCF_PARITY_CHECK = 0x0008, PCF_XONXOFF = 0x0010, PCF_SETXCHAR = 0x0020, PCF_TOTALTIMEOUTS = 0x0040, PCF_INTTIMEOUTS = 0x0080, PCF_SPECIALCHARS = 0x0100, PCF_16BITMODE = 0x0200 } enum : DWORD { SP_PARITY = 1, SP_BAUD = 2, SP_DATABITS = 4, SP_STOPBITS = 8, SP_HANDSHAKING = 16, SP_PARITY_CHECK = 32, SP_RLSD = 64 } enum : DWORD { DATABITS_5 = 1, DATABITS_6 = 2, DATABITS_7 = 4, DATABITS_8 = 8, DATABITS_16 = 16, DATABITS_16X = 32 } enum : WORD { STOPBITS_10 = 0x0001, STOPBITS_15 = 0x0002, STOPBITS_20 = 0x0004, PARITY_NONE = 0x0100, PARITY_ODD = 0x0200, PARITY_EVEN = 0x0400, PARITY_MARK = 0x0800, PARITY_SPACE = 0x1000 } // used by dwServiceMask enum SP_SERIALCOMM = 1; struct COMMPROP { WORD wPacketLength; WORD wPacketVersion; DWORD dwServiceMask; DWORD dwReserved1; DWORD dwMaxTxQueue; DWORD dwMaxRxQueue; DWORD dwMaxBaud; DWORD dwProvSubType; DWORD dwProvCapabilities; DWORD dwSettableParams; DWORD dwSettableBaud; WORD wSettableData; WORD wSettableStopParity; DWORD dwCurrentTxQueue; DWORD dwCurrentRxQueue; DWORD dwProvSpec1; DWORD dwProvSpec2; WCHAR _wcProvChar; WCHAR* wcProvChar() return { return &_wcProvChar; } } alias COMMPROP* LPCOMMPROP; // ---------- // for DEBUG_EVENT enum : DWORD { EXCEPTION_DEBUG_EVENT = 1, CREATE_THREAD_DEBUG_EVENT, CREATE_PROCESS_DEBUG_EVENT, EXIT_THREAD_DEBUG_EVENT, EXIT_PROCESS_DEBUG_EVENT, LOAD_DLL_DEBUG_EVENT, UNLOAD_DLL_DEBUG_EVENT, OUTPUT_DEBUG_STRING_EVENT, RIP_EVENT } enum HFILE HFILE_ERROR = cast(HFILE) (-1); // for SetFilePointer() enum : DWORD { FILE_BEGIN = 0, FILE_CURRENT = 1, FILE_END = 2 } enum DWORD INVALID_SET_FILE_POINTER = -1; // for OpenFile() deprecated enum : UINT { OF_READ = 0, OF_WRITE = 0x0001, OF_READWRITE = 0x0002, OF_SHARE_COMPAT = 0, OF_SHARE_EXCLUSIVE = 0x0010, OF_SHARE_DENY_WRITE = 0x0020, OF_SHARE_DENY_READ = 0x0030, OF_SHARE_DENY_NONE = 0x0040, OF_PARSE = 0x0100, OF_DELETE = 0x0200, OF_VERIFY = 0x0400, OF_CANCEL = 0x0800, OF_CREATE = 0x1000, OF_PROMPT = 0x2000, OF_EXIST = 0x4000, OF_REOPEN = 0x8000 } enum : DWORD { NMPWAIT_NOWAIT = 1, NMPWAIT_WAIT_FOREVER = -1, NMPWAIT_USE_DEFAULT_WAIT = 0 } // for ClearCommError() enum DWORD CE_RXOVER = 0x0001, CE_OVERRUN = 0x0002, CE_RXPARITY = 0x0004, CE_FRAME = 0x0008, CE_BREAK = 0x0010, CE_TXFULL = 0x0100, CE_PTO = 0x0200, CE_IOE = 0x0400, CE_DNS = 0x0800, CE_OOP = 0x1000, CE_MODE = 0x8000; // for CopyProgressRoutine callback. enum : DWORD { PROGRESS_CONTINUE = 0, PROGRESS_CANCEL = 1, PROGRESS_STOP = 2, PROGRESS_QUIET = 3 } enum : DWORD { CALLBACK_CHUNK_FINISHED = 0, CALLBACK_STREAM_SWITCH = 1 } // CopyFileEx() enum : DWORD { COPY_FILE_FAIL_IF_EXISTS = 1, COPY_FILE_RESTARTABLE = 2 } enum : DWORD { FILE_MAP_COPY = 1, FILE_MAP_WRITE = 2, FILE_MAP_READ = 4, FILE_MAP_ALL_ACCESS = 0x000F001F } enum : DWORD { MUTEX_ALL_ACCESS = 0x001f0001, MUTEX_MODIFY_STATE = 0x00000001, SEMAPHORE_ALL_ACCESS = 0x001f0003, SEMAPHORE_MODIFY_STATE = 0x00000002, EVENT_ALL_ACCESS = 0x001f0003, EVENT_MODIFY_STATE = 0x00000002 } // CreateNamedPipe() enum : DWORD { PIPE_ACCESS_INBOUND = 1, PIPE_ACCESS_OUTBOUND = 2, PIPE_ACCESS_DUPLEX = 3 } enum DWORD PIPE_TYPE_BYTE = 0, PIPE_TYPE_MESSAGE = 4, PIPE_READMODE_BYTE = 0, PIPE_READMODE_MESSAGE = 2, PIPE_WAIT = 0, PIPE_NOWAIT = 1; // GetNamedPipeInfo() enum DWORD PIPE_CLIENT_END = 0, PIPE_SERVER_END = 1; enum DWORD PIPE_UNLIMITED_INSTANCES = 255; // dwCreationFlags for CreateProcess() and CreateProcessAsUser() enum : DWORD { DEBUG_PROCESS = 0x00000001, DEBUG_ONLY_THIS_PROCESS = 0x00000002, CREATE_SUSPENDED = 0x00000004, DETACHED_PROCESS = 0x00000008, CREATE_NEW_CONSOLE = 0x00000010, NORMAL_PRIORITY_CLASS = 0x00000020, IDLE_PRIORITY_CLASS = 0x00000040, HIGH_PRIORITY_CLASS = 0x00000080, REALTIME_PRIORITY_CLASS = 0x00000100, CREATE_NEW_PROCESS_GROUP = 0x00000200, CREATE_UNICODE_ENVIRONMENT = 0x00000400, CREATE_SEPARATE_WOW_VDM = 0x00000800, CREATE_SHARED_WOW_VDM = 0x00001000, CREATE_FORCEDOS = 0x00002000, BELOW_NORMAL_PRIORITY_CLASS = 0x00004000, ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000, CREATE_BREAKAWAY_FROM_JOB = 0x01000000, CREATE_WITH_USERPROFILE = 0x02000000, CREATE_DEFAULT_ERROR_MODE = 0x04000000, CREATE_NO_WINDOW = 0x08000000, PROFILE_USER = 0x10000000, PROFILE_KERNEL = 0x20000000, PROFILE_SERVER = 0x40000000 } enum DWORD CONSOLE_TEXTMODE_BUFFER = 1; // CreateFile() enum : DWORD { CREATE_NEW = 1, CREATE_ALWAYS, OPEN_EXISTING, OPEN_ALWAYS, TRUNCATE_EXISTING } // CreateFile() enum DWORD FILE_FLAG_WRITE_THROUGH = 0x80000000, FILE_FLAG_OVERLAPPED = 0x40000000, FILE_FLAG_NO_BUFFERING = 0x20000000, FILE_FLAG_RANDOM_ACCESS = 0x10000000, FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000, FILE_FLAG_DELETE_ON_CLOSE = 0x04000000, FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, FILE_FLAG_POSIX_SEMANTICS = 0x01000000, FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000, FILE_FLAG_OPEN_NO_RECALL = 0x00100000; static if (_WIN32_WINNT >= 0x500) { enum DWORD FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000; } // for CreateFile() enum DWORD SECURITY_ANONYMOUS = SECURITY_IMPERSONATION_LEVEL.SecurityAnonymous<<16, SECURITY_IDENTIFICATION = SECURITY_IMPERSONATION_LEVEL.SecurityIdentification<<16, SECURITY_IMPERSONATION = SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation<<16, SECURITY_DELEGATION = SECURITY_IMPERSONATION_LEVEL.SecurityDelegation<<16, SECURITY_CONTEXT_TRACKING = 0x00040000, SECURITY_EFFECTIVE_ONLY = 0x00080000, SECURITY_SQOS_PRESENT = 0x00100000, SECURITY_VALID_SQOS_FLAGS = 0x001F0000; // Thread exit code enum DWORD STILL_ACTIVE = 0x103; /* ??? The only documentation of this seems to be about Windows CE and to * state what _doesn't_ support it. */ enum DWORD FIND_FIRST_EX_CASE_SENSITIVE = 1; // GetBinaryType() enum : DWORD { SCS_32BIT_BINARY = 0, SCS_DOS_BINARY, SCS_WOW_BINARY, SCS_PIF_BINARY, SCS_POSIX_BINARY, SCS_OS216_BINARY } enum size_t MAX_COMPUTERNAME_LENGTH = 15, HW_PROFILE_GUIDLEN = 39, MAX_PROFILE_LEN = 80; // HW_PROFILE_INFO enum DWORD DOCKINFO_UNDOCKED = 1, DOCKINFO_DOCKED = 2, DOCKINFO_USER_SUPPLIED = 4, DOCKINFO_USER_UNDOCKED = DOCKINFO_USER_SUPPLIED | DOCKINFO_UNDOCKED, DOCKINFO_USER_DOCKED = DOCKINFO_USER_SUPPLIED | DOCKINFO_DOCKED; // DriveType(), RealDriveType() enum : int { DRIVE_UNKNOWN = 0, DRIVE_NO_ROOT_DIR, DRIVE_REMOVABLE, DRIVE_FIXED, DRIVE_REMOTE, DRIVE_CDROM, DRIVE_RAMDISK } // GetFileType() enum : DWORD { FILE_TYPE_UNKNOWN = 0, FILE_TYPE_DISK, FILE_TYPE_CHAR, FILE_TYPE_PIPE, FILE_TYPE_REMOTE = 0x8000 } // Get/SetHandleInformation() enum DWORD HANDLE_FLAG_INHERIT = 0x01, HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x02; enum : DWORD { STD_INPUT_HANDLE = 0xFFFFFFF6, STD_OUTPUT_HANDLE = 0xFFFFFFF5, STD_ERROR_HANDLE = 0xFFFFFFF4 } enum HANDLE INVALID_HANDLE_VALUE = cast(HANDLE) (-1); enum : DWORD { GET_TAPE_MEDIA_INFORMATION = 0, GET_TAPE_DRIVE_INFORMATION = 1 } enum : DWORD { SET_TAPE_MEDIA_INFORMATION = 0, SET_TAPE_DRIVE_INFORMATION = 1 } // SetThreadPriority()/GetThreadPriority() enum : int { THREAD_PRIORITY_IDLE = -15, THREAD_PRIORITY_LOWEST = -2, THREAD_PRIORITY_BELOW_NORMAL = -1, THREAD_PRIORITY_NORMAL = 0, THREAD_PRIORITY_ABOVE_NORMAL = 1, THREAD_PRIORITY_HIGHEST = 2, THREAD_PRIORITY_TIME_CRITICAL = 15, THREAD_PRIORITY_ERROR_RETURN = 2147483647 } enum : DWORD { TIME_ZONE_ID_UNKNOWN, TIME_ZONE_ID_STANDARD, TIME_ZONE_ID_DAYLIGHT, TIME_ZONE_ID_INVALID = 0xFFFFFFFF } enum DWORD FS_CASE_SENSITIVE = 1, FS_CASE_IS_PRESERVED = 2, FS_UNICODE_STORED_ON_DISK = 4, FS_PERSISTENT_ACLS = 8, FS_FILE_COMPRESSION = 16, FS_VOL_IS_COMPRESSED = 32768; // Flags for GlobalAlloc enum UINT GMEM_FIXED = 0, GMEM_MOVEABLE = 0x0002, GMEM_ZEROINIT = 0x0040, GPTR = 0x0040, GHND = 0x0042, GMEM_MODIFY = 0x0080, // used only for GlobalRealloc GMEM_VALID_FLAGS = 0x7F72; /+ // Obselete flags (Win16 only) GMEM_NOCOMPACT=16; GMEM_NODISCARD=32; GMEM_DISCARDABLE=256; GMEM_NOT_BANKED=4096; GMEM_LOWER=4096; GMEM_SHARE=8192; GMEM_DDESHARE=8192; GMEM_LOCKCOUNT=255; // for GlobalFlags() GMEM_DISCARDED = 16384; GMEM_INVALID_HANDLE = 32768; GMEM_NOTIFY = 16384; +/ enum UINT LMEM_FIXED = 0, LMEM_MOVEABLE = 0x0002, LMEM_NONZEROLPTR = 0, NONZEROLPTR = 0, LMEM_NONZEROLHND = 0x0002, NONZEROLHND = 0x0002, LMEM_DISCARDABLE = 0x0F00, LMEM_NOCOMPACT = 0x0010, LMEM_NODISCARD = 0x0020, LMEM_ZEROINIT = 0x0040, LPTR = 0x0040, LHND = 0x0042, LMEM_MODIFY = 0x0080, LMEM_LOCKCOUNT = 0x00FF, LMEM_DISCARDED = 0x4000, LMEM_INVALID_HANDLE = 0x8000; // used in EXCEPTION_RECORD enum : DWORD { STATUS_WAIT_0 = 0, STATUS_ABANDONED_WAIT_0 = 0x00000080, STATUS_USER_APC = 0x000000C0, STATUS_TIMEOUT = 0x00000102, STATUS_PENDING = 0x00000103, STATUS_SEGMENT_NOTIFICATION = 0x40000005, STATUS_GUARD_PAGE_VIOLATION = 0x80000001, STATUS_DATATYPE_MISALIGNMENT = 0x80000002, STATUS_BREAKPOINT = 0x80000003, STATUS_SINGLE_STEP = 0x80000004, STATUS_ACCESS_VIOLATION = 0xC0000005, STATUS_IN_PAGE_ERROR = 0xC0000006, STATUS_INVALID_HANDLE = 0xC0000008, STATUS_NO_MEMORY = 0xC0000017, STATUS_ILLEGAL_INSTRUCTION = 0xC000001D, STATUS_NONCONTINUABLE_EXCEPTION = 0xC0000025, STATUS_INVALID_DISPOSITION = 0xC0000026, STATUS_ARRAY_BOUNDS_EXCEEDED = 0xC000008C, STATUS_FLOAT_DENORMAL_OPERAND = 0xC000008D, STATUS_FLOAT_DIVIDE_BY_ZERO = 0xC000008E, STATUS_FLOAT_INEXACT_RESULT = 0xC000008F, STATUS_FLOAT_INVALID_OPERATION = 0xC0000090, STATUS_FLOAT_OVERFLOW = 0xC0000091, STATUS_FLOAT_STACK_CHECK = 0xC0000092, STATUS_FLOAT_UNDERFLOW = 0xC0000093, STATUS_INTEGER_DIVIDE_BY_ZERO = 0xC0000094, STATUS_INTEGER_OVERFLOW = 0xC0000095, STATUS_PRIVILEGED_INSTRUCTION = 0xC0000096, STATUS_STACK_OVERFLOW = 0xC00000FD, STATUS_CONTROL_C_EXIT = 0xC000013A, STATUS_DLL_INIT_FAILED = 0xC0000142, STATUS_DLL_INIT_FAILED_LOGOFF = 0xC000026B, CONTROL_C_EXIT = STATUS_CONTROL_C_EXIT, EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION, EXCEPTION_DATATYPE_MISALIGNMENT = STATUS_DATATYPE_MISALIGNMENT, EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT, EXCEPTION_SINGLE_STEP = STATUS_SINGLE_STEP, EXCEPTION_ARRAY_BOUNDS_EXCEEDED = STATUS_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO = STATUS_FLOAT_DIVIDE_BY_ZERO, EXCEPTION_FLT_INEXACT_RESULT = STATUS_FLOAT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION = STATUS_FLOAT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW = STATUS_FLOAT_OVERFLOW, EXCEPTION_FLT_STACK_CHECK = STATUS_FLOAT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW = STATUS_FLOAT_UNDERFLOW, EXCEPTION_INT_DIVIDE_BY_ZERO = STATUS_INTEGER_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW = STATUS_INTEGER_OVERFLOW, EXCEPTION_PRIV_INSTRUCTION = STATUS_PRIVILEGED_INSTRUCTION, EXCEPTION_IN_PAGE_ERROR = STATUS_IN_PAGE_ERROR, EXCEPTION_ILLEGAL_INSTRUCTION = STATUS_ILLEGAL_INSTRUCTION, EXCEPTION_NONCONTINUABLE_EXCEPTION = STATUS_NONCONTINUABLE_EXCEPTION, EXCEPTION_STACK_OVERFLOW = STATUS_STACK_OVERFLOW, EXCEPTION_INVALID_DISPOSITION = STATUS_INVALID_DISPOSITION, EXCEPTION_GUARD_PAGE = STATUS_GUARD_PAGE_VIOLATION, EXCEPTION_INVALID_HANDLE = STATUS_INVALID_HANDLE } // for PROCESS_HEAP_ENTRY enum WORD PROCESS_HEAP_REGION = 1, PROCESS_HEAP_UNCOMMITTED_RANGE = 2, PROCESS_HEAP_ENTRY_BUSY = 4, PROCESS_HEAP_ENTRY_MOVEABLE = 16, PROCESS_HEAP_ENTRY_DDESHARE = 32; // for LoadLibraryEx() enum DWORD DONT_RESOLVE_DLL_REFERENCES = 0x01, // not for WinME and earlier LOAD_LIBRARY_AS_DATAFILE = 0x02, LOAD_WITH_ALTERED_SEARCH_PATH = 0x08, LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x10; // only for XP and later // for LockFile() enum DWORD LOCKFILE_FAIL_IMMEDIATELY = 1, LOCKFILE_EXCLUSIVE_LOCK = 2; enum MAXIMUM_WAIT_OBJECTS = 64; enum MAXIMUM_SUSPEND_COUNT = 0x7F; enum WAIT_OBJECT_0 = 0; enum WAIT_ABANDONED_0 = 128; //const WAIT_TIMEOUT=258; // also in winerror.h enum : DWORD { WAIT_IO_COMPLETION = 0x000000C0, WAIT_ABANDONED = 0x00000080, WAIT_FAILED = 0xFFFFFFFF } // PurgeComm() enum DWORD PURGE_TXABORT = 1, PURGE_RXABORT = 2, PURGE_TXCLEAR = 4, PURGE_RXCLEAR = 8; // ReadEventLog() enum DWORD EVENTLOG_SEQUENTIAL_READ = 1, EVENTLOG_SEEK_READ = 2, EVENTLOG_FORWARDS_READ = 4, EVENTLOG_BACKWARDS_READ = 8; // ReportEvent() enum : WORD { EVENTLOG_SUCCESS = 0, EVENTLOG_ERROR_TYPE = 1, EVENTLOG_WARNING_TYPE = 2, EVENTLOG_INFORMATION_TYPE = 4, EVENTLOG_AUDIT_SUCCESS = 8, EVENTLOG_AUDIT_FAILURE = 16 } // FormatMessage() enum DWORD FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x0100, FORMAT_MESSAGE_IGNORE_INSERTS = 0x0200, FORMAT_MESSAGE_FROM_STRING = 0x0400, FORMAT_MESSAGE_FROM_HMODULE = 0x0800, FORMAT_MESSAGE_FROM_SYSTEM = 0x1000, FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x2000; enum DWORD FORMAT_MESSAGE_MAX_WIDTH_MASK = 255; // also in ddk/ntapi.h // To restore default error mode, call SetErrorMode(0) enum { SEM_FAILCRITICALERRORS = 0x0001, SEM_NOGPFAULTERRORBOX = 0x0002, SEM_NOALIGNMENTFAULTEXCEPT = 0x0004, SEM_NOOPENFILEERRORBOX = 0x8000 } // end ntapi.h enum { SLE_ERROR = 1, SLE_MINORERROR, SLE_WARNING } enum SHUTDOWN_NORETRY = 1; // Return type for exception filters. enum : LONG { EXCEPTION_EXECUTE_HANDLER = 1, EXCEPTION_CONTINUE_EXECUTION = -1, EXCEPTION_CONTINUE_SEARCH = 0 } enum : ATOM { MAXINTATOM = 0xC000, INVALID_ATOM = 0 } enum IGNORE = 0; enum INFINITE = 0xFFFFFFFF; // EscapeCommFunction() enum { SETXOFF = 1, SETXON, SETRTS, CLRRTS, SETDTR, CLRDTR, // = 6 SETBREAK = 8, CLRBREAK = 9 } // for SetCommMask() enum DWORD EV_RXCHAR = 0x0001, EV_RXFLAG = 0x0002, EV_TXEMPTY = 0x0004, EV_CTS = 0x0008, EV_DSR = 0x0010, EV_RLSD = 0x0020, EV_BREAK = 0x0040, EV_ERR = 0x0080, EV_RING = 0x0100, EV_PERR = 0x0200, EV_RX80FULL = 0x0400, EV_EVENT1 = 0x0800, EV_EVENT2 = 0x1000; // GetCommModemStatus() enum DWORD MS_CTS_ON = 0x0010, MS_DSR_ON = 0x0020, MS_RING_ON = 0x0040, MS_RLSD_ON = 0x0080; // DCB enum : BYTE { NOPARITY = 0, ODDPARITY, EVENPARITY, MARKPARITY, SPACEPARITY } // DCB enum : BYTE { ONESTOPBIT = 0, ONE5STOPBITS, TWOSTOPBITS } // DCB enum : DWORD { CBR_110 = 110, CBR_300 = 300, CBR_600 = 600, CBR_1200 = 1200, CBR_2400 = 2400, CBR_4800 = 4800, CBR_9600 = 9600, CBR_14400 = 14400, CBR_19200 = 19200, CBR_38400 = 38400, CBR_56000 = 56000, CBR_57600 = 57600, CBR_115200 = 115200, CBR_128000 = 128000, CBR_256000 = 256000 } // DCB, 2-bit bitfield enum { DTR_CONTROL_DISABLE = 0, DTR_CONTROL_ENABLE, DTR_CONTROL_HANDSHAKE } // DCB, 2-bit bitfield enum { RTS_CONTROL_DISABLE = 0, RTS_CONTROL_ENABLE, RTS_CONTROL_HANDSHAKE, RTS_CONTROL_TOGGLE, } // WIN32_STREAM_ID enum : DWORD { BACKUP_INVALID = 0, BACKUP_DATA, BACKUP_EA_DATA, BACKUP_SECURITY_DATA, BACKUP_ALTERNATE_DATA, BACKUP_LINK, BACKUP_PROPERTY_DATA, BACKUP_OBJECT_ID, BACKUP_REPARSE_DATA, BACKUP_SPARSE_BLOCK } // WIN32_STREAM_ID enum : DWORD { STREAM_NORMAL_ATTRIBUTE = 0, STREAM_MODIFIED_WHEN_READ = 1, STREAM_CONTAINS_SECURITY = 2, STREAM_CONTAINS_PROPERTIES = 4 } // STARTUPINFO enum DWORD STARTF_USESHOWWINDOW = 0x0001, STARTF_USESIZE = 0x0002, STARTF_USEPOSITION = 0x0004, STARTF_USECOUNTCHARS = 0x0008, STARTF_USEFILLATTRIBUTE = 0x0010, STARTF_RUNFULLSCREEN = 0x0020, STARTF_FORCEONFEEDBACK = 0x0040, STARTF_FORCEOFFFEEDBACK = 0x0080, STARTF_USESTDHANDLES = 0x0100, STARTF_USEHOTKEY = 0x0200; // ??? enum { TC_NORMAL = 0, TC_HARDERR = 1, TC_GP_TRAP = 2, TC_SIGNAL = 3 } /+ These seem to be Windows CE-specific enum { AC_LINE_OFFLINE = 0, AC_LINE_ONLINE = 1, AC_LINE_BACKUP_POWER = 2, AC_LINE_UNKNOWN = 255 } enum { BATTERY_FLAG_HIGH = 1, BATTERY_FLAG_LOW = 2, BATTERY_FLAG_CRITICAL = 4, BATTERY_FLAG_CHARGING = 8, BATTERY_FLAG_NO_BATTERY = 128, BATTERY_FLAG_UNKNOWN = 255, BATTERY_PERCENTAGE_UNKNOWN = 255, BATTERY_LIFE_UNKNOWN = 0xFFFFFFFF } +/ // ??? enum HINSTANCE_ERROR = 32; // returned from GetFileSize() enum DWORD INVALID_FILE_SIZE = 0xFFFFFFFF; enum DWORD TLS_OUT_OF_INDEXES = 0xFFFFFFFF; // GetWriteWatch() enum DWORD WRITE_WATCH_FLAG_RESET = 1; // for LogonUser() enum : DWORD { LOGON32_LOGON_INTERACTIVE = 2, LOGON32_LOGON_NETWORK = 3, LOGON32_LOGON_BATCH = 4, LOGON32_LOGON_SERVICE = 5, LOGON32_LOGON_UNLOCK = 7 } // for LogonUser() enum : DWORD { LOGON32_PROVIDER_DEFAULT, LOGON32_PROVIDER_WINNT35, LOGON32_PROVIDER_WINNT40, LOGON32_PROVIDER_WINNT50 } // for MoveFileEx() enum DWORD MOVEFILE_REPLACE_EXISTING = 1, MOVEFILE_COPY_ALLOWED = 2, MOVEFILE_DELAY_UNTIL_REBOOT = 4, MOVEFILE_WRITE_THROUGH = 8; // DefineDosDevice() enum DWORD DDD_RAW_TARGET_PATH = 1, DDD_REMOVE_DEFINITION = 2, DDD_EXACT_MATCH_ON_REMOVE = 4; static if (_WIN32_WINNT >= 0x500) { enum : DWORD { LOGON32_LOGON_NETWORK_CLEARTEXT = 8, LOGON32_LOGON_NEW_CREDENTIALS = 9 } // ReplaceFile() enum DWORD REPLACEFILE_WRITE_THROUGH = 1, REPLACEFILE_IGNORE_MERGE_ERRORS = 2; } static if (_WIN32_WINNT >= 0x501) { enum DWORD GET_MODULE_HANDLE_EX_FLAG_PIN = 1, GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 2, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 4; // for ACTCTX enum DWORD ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID = 0x01, ACTCTX_FLAG_LANGID_VALID = 0x02, ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x04, ACTCTX_FLAG_RESOURCE_NAME_VALID = 0x08, ACTCTX_FLAG_SET_PROCESS_DEFAULT = 0x10, ACTCTX_FLAG_APPLICATION_NAME_VALID = 0x20, ACTCTX_FLAG_HMODULE_VALID = 0x80; // DeactivateActCtx() enum DWORD DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION = 1; // FindActCtxSectionString() enum DWORD FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX = 1; // QueryActCtxW() enum DWORD QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX = 0x04, QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE = 0x08, QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS = 0x10; enum { LOGON_WITH_PROFILE = 1, LOGON_NETCREDENTIALS_ONLY } } // ---- struct FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } alias FILETIME* PFILETIME, LPFILETIME; struct BY_HANDLE_FILE_INFORMATION { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD dwVolumeSerialNumber; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD nNumberOfLinks; DWORD nFileIndexHigh; DWORD nFileIndexLow; } alias BY_HANDLE_FILE_INFORMATION* LPBY_HANDLE_FILE_INFORMATION; struct DCB { DWORD DCBlength = DCB.sizeof; DWORD BaudRate; /+ DWORD fBinary:1; // Binary Mode (skip EOF check) DWORD fParity:1; // Enable parity checking DWORD fOutxCtsFlow:1; // CTS handshaking on output DWORD fOutxDsrFlow:1; // DSR handshaking on output DWORD fDtrControl:2; // DTR Flow control DWORD fDsrSensitivity:1; // DSR Sensitivity DWORD fTXContinueOnXoff:1; // Continue TX when Xoff sent DWORD fOutX:1; // Enable output X-ON/X-OFF DWORD fInX:1; // Enable input X-ON/X-OFF DWORD fErrorChar:1; // Enable Err Replacement DWORD fNull:1; // Enable Null stripping DWORD fRtsControl:2; // Rts Flow control DWORD fAbortOnError:1; // Abort all reads and writes on Error DWORD fDummy2:17; // Reserved +/ uint _bf; bool fBinary(bool f) { _bf = (_bf & ~0x0001) | f; return f; } bool fParity(bool f) { _bf = (_bf & ~0x0002) | (f<<1); return f; } bool fOutxCtsFlow(bool f) { _bf = (_bf & ~0x0004) | (f<<2); return f; } bool fOutxDsrFlow(bool f) { _bf = (_bf & ~0x0008) | (f<<3); return f; } byte fDtrControl(byte x) { _bf = (_bf & ~0x0030) | (x<<4); return cast(byte)(x & 3); } bool fDsrSensitivity(bool f) { _bf = (_bf & ~0x0040) | (f<<6); return f; } bool fTXContinueOnXoff(bool f) { _bf = (_bf & ~0x0080) | (f<<7); return f; } bool fOutX(bool f) { _bf = (_bf & ~0x0100) | (f<<8); return f; } bool fInX(bool f) { _bf = (_bf & ~0x0200) | (f<<9); return f; } bool fErrorChar(bool f) { _bf = (_bf & ~0x0400) | (f<<10); return f; } bool fNull(bool f) { _bf = (_bf & ~0x0800) | (f<<11); return f; } byte fRtsControl(byte x) { _bf = (_bf & ~0x3000) | (x<<12); return cast(byte)(x & 3); } bool fAbortOnError(bool f) { _bf = (_bf & ~0x4000) | (f<<14); return f; } bool fBinary() { return cast(bool) (_bf & 1); } bool fParity() { return cast(bool) (_bf & 2); } bool fOutxCtsFlow() { return cast(bool) (_bf & 4); } bool fOutxDsrFlow() { return cast(bool) (_bf & 8); } byte fDtrControl() { return cast(byte) ((_bf & (32+16))>>4); } bool fDsrSensitivity() { return cast(bool) (_bf & 64); } bool fTXContinueOnXoff() { return cast(bool) (_bf & 128); } bool fOutX() { return cast(bool) (_bf & 256); } bool fInX() { return cast(bool) (_bf & 512); } bool fErrorChar() { return cast(bool) (_bf & 1024); } bool fNull() { return cast(bool) (_bf & 2048); } byte fRtsControl() { return cast(byte) ((_bf & (4096+8192))>>12); } bool fAbortOnError() { return cast(bool) (_bf & 16384); } WORD wReserved; WORD XonLim; WORD XoffLim; BYTE ByteSize; BYTE Parity; BYTE StopBits; char XonChar; char XoffChar; char ErrorChar; char EofChar; char EvtChar; WORD wReserved1; } alias DCB* LPDCB; struct COMMCONFIG { DWORD dwSize = COMMCONFIG.sizeof; WORD wVersion; WORD wReserved; DCB dcb; DWORD dwProviderSubType; DWORD dwProviderOffset; DWORD dwProviderSize; WCHAR _wcProviderData; WCHAR* wcProviderData() return { return &_wcProviderData; } } alias COMMCONFIG* LPCOMMCONFIG; struct COMMTIMEOUTS { DWORD ReadIntervalTimeout; DWORD ReadTotalTimeoutMultiplier; DWORD ReadTotalTimeoutConstant; DWORD WriteTotalTimeoutMultiplier; DWORD WriteTotalTimeoutConstant; } alias COMMTIMEOUTS* LPCOMMTIMEOUTS; struct COMSTAT { /+ DWORD fCtsHold:1; DWORD fDsrHold:1; DWORD fRlsdHold:1; DWORD fXoffHold:1; DWORD fXoffSent:1; DWORD fEof:1; DWORD fTxim:1; DWORD fReserved:25; +/ DWORD _bf; bool fCtsHold(bool f) { _bf = (_bf & ~1) | f; return f; } bool fDsrHold(bool f) { _bf = (_bf & ~2) | (f<<1); return f; } bool fRlsdHold(bool f) { _bf = (_bf & ~4) | (f<<2); return f; } bool fXoffHold(bool f) { _bf = (_bf & ~8) | (f<<3); return f; } bool fXoffSent(bool f) { _bf = (_bf & ~16) | (f<<4); return f; } bool fEof(bool f) { _bf = (_bf & ~32) | (f<<5); return f; } bool fTxim(bool f) { _bf = (_bf & ~64) | (f<<6); return f; } bool fCtsHold() { return cast(bool) (_bf & 1); } bool fDsrHold() { return cast(bool) (_bf & 2); } bool fRlsdHold() { return cast(bool) (_bf & 4); } bool fXoffHold() { return cast(bool) (_bf & 8); } bool fXoffSent() { return cast(bool) (_bf & 16); } bool fEof() { return cast(bool) (_bf & 32); } bool fTxim() { return cast(bool) (_bf & 64); } DWORD cbInQue; DWORD cbOutQue; } alias COMSTAT* LPCOMSTAT; struct CREATE_PROCESS_DEBUG_INFO { HANDLE hFile; HANDLE hProcess; HANDLE hThread; LPVOID lpBaseOfImage; DWORD dwDebugInfoFileOffset; DWORD nDebugInfoSize; LPVOID lpThreadLocalBase; LPTHREAD_START_ROUTINE lpStartAddress; LPVOID lpImageName; WORD fUnicode; } alias CREATE_PROCESS_DEBUG_INFO* LPCREATE_PROCESS_DEBUG_INFO; struct CREATE_THREAD_DEBUG_INFO { HANDLE hThread; LPVOID lpThreadLocalBase; LPTHREAD_START_ROUTINE lpStartAddress; } alias CREATE_THREAD_DEBUG_INFO* LPCREATE_THREAD_DEBUG_INFO; struct EXCEPTION_DEBUG_INFO { EXCEPTION_RECORD ExceptionRecord; DWORD dwFirstChance; } alias EXCEPTION_DEBUG_INFO* LPEXCEPTION_DEBUG_INFO; struct EXIT_THREAD_DEBUG_INFO { DWORD dwExitCode; } alias EXIT_THREAD_DEBUG_INFO* LPEXIT_THREAD_DEBUG_INFO; struct EXIT_PROCESS_DEBUG_INFO { DWORD dwExitCode; } alias EXIT_PROCESS_DEBUG_INFO* LPEXIT_PROCESS_DEBUG_INFO; struct LOAD_DLL_DEBUG_INFO { HANDLE hFile; LPVOID lpBaseOfDll; DWORD dwDebugInfoFileOffset; DWORD nDebugInfoSize; LPVOID lpImageName; WORD fUnicode; } alias LOAD_DLL_DEBUG_INFO* LPLOAD_DLL_DEBUG_INFO; struct UNLOAD_DLL_DEBUG_INFO { LPVOID lpBaseOfDll; } alias UNLOAD_DLL_DEBUG_INFO* LPUNLOAD_DLL_DEBUG_INFO; struct OUTPUT_DEBUG_STRING_INFO { LPSTR lpDebugStringData; WORD fUnicode; WORD nDebugStringLength; } alias OUTPUT_DEBUG_STRING_INFO* LPOUTPUT_DEBUG_STRING_INFO; struct RIP_INFO { DWORD dwError; DWORD dwType; } alias RIP_INFO* LPRIP_INFO; struct DEBUG_EVENT { DWORD dwDebugEventCode; DWORD dwProcessId; DWORD dwThreadId; union { EXCEPTION_DEBUG_INFO Exception; CREATE_THREAD_DEBUG_INFO CreateThread; CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; EXIT_THREAD_DEBUG_INFO ExitThread; EXIT_PROCESS_DEBUG_INFO ExitProcess; LOAD_DLL_DEBUG_INFO LoadDll; UNLOAD_DLL_DEBUG_INFO UnloadDll; OUTPUT_DEBUG_STRING_INFO DebugString; RIP_INFO RipInfo; } } alias DEBUG_EVENT* LPDEBUG_EVENT; struct OVERLAPPED { ULONG_PTR Internal; ULONG_PTR InternalHigh; union { struct { DWORD Offset; DWORD OffsetHigh; } PVOID Pointer; } HANDLE hEvent; } alias OVERLAPPED* POVERLAPPED, LPOVERLAPPED; struct STARTUPINFOA { DWORD cb = STARTUPINFOA.sizeof; LPSTR lpReserved; LPSTR lpDesktop; LPSTR lpTitle; DWORD dwX; DWORD dwY; DWORD dwXSize; DWORD dwYSize; DWORD dwXCountChars; DWORD dwYCountChars; DWORD dwFillAttribute; DWORD dwFlags; WORD wShowWindow; WORD cbReserved2; PBYTE lpReserved2; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; } alias STARTUPINFOA* LPSTARTUPINFOA; struct STARTUPINFOW { DWORD cb = STARTUPINFOW.sizeof; LPWSTR lpReserved; LPWSTR lpDesktop; LPWSTR lpTitle; DWORD dwX; DWORD dwY; DWORD dwXSize; DWORD dwYSize; DWORD dwXCountChars; DWORD dwYCountChars; DWORD dwFillAttribute; DWORD dwFlags; WORD wShowWindow; WORD cbReserved2; PBYTE lpReserved2; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; } alias STARTUPINFOW STARTUPINFO_W; alias STARTUPINFOW* LPSTARTUPINFOW, LPSTARTUPINFO_W; struct PROCESS_INFORMATION { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } alias PROCESS_INFORMATION* PPROCESS_INFORMATION, LPPROCESS_INFORMATION; /* struct CRITICAL_SECTION_DEBUG { WORD Type; WORD CreatorBackTraceIndex; CRITICAL_SECTION* CriticalSection; LIST_ENTRY ProcessLocksList; DWORD EntryCount; DWORD ContentionCount; DWORD[2] Spare; } alias CRITICAL_SECTION_DEBUG* PCRITICAL_SECTION_DEBUG; struct CRITICAL_SECTION { PCRITICAL_SECTION_DEBUG DebugInfo; LONG LockCount; LONG RecursionCount; HANDLE OwningThread; HANDLE LockSemaphore; DWORD SpinCount; } alias CRITICAL_SECTION* PCRITICAL_SECTION, LPCRITICAL_SECTION; */ alias CRITICAL_SECTION_DEBUG = RTL_CRITICAL_SECTION_DEBUG; alias CRITICAL_SECTION_DEBUG* PCRITICAL_SECTION_DEBUG; alias CRITICAL_SECTION = RTL_CRITICAL_SECTION; alias CRITICAL_SECTION* PCRITICAL_SECTION, LPCRITICAL_SECTION; struct SYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; } alias SYSTEMTIME* LPSYSTEMTIME; struct WIN32_FILE_ATTRIBUTE_DATA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; } alias WIN32_FILE_ATTRIBUTE_DATA* LPWIN32_FILE_ATTRIBUTE_DATA; struct WIN32_FIND_DATAA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; // #ifdef _WIN32_WCE // DWORD dwOID; // #else DWORD dwReserved0; DWORD dwReserved1; // #endif CHAR[MAX_PATH] cFileName; // #ifndef _WIN32_WCE CHAR[14] cAlternateFileName; // #endif } alias WIN32_FIND_DATAA* PWIN32_FIND_DATAA, LPWIN32_FIND_DATAA; struct WIN32_FIND_DATAW { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; // #ifdef _WIN32_WCE // DWORD dwOID; // #else DWORD dwReserved0; DWORD dwReserved1; // #endif WCHAR[MAX_PATH] cFileName; // #ifndef _WIN32_WCE WCHAR[14] cAlternateFileName; // #endif } alias WIN32_FIND_DATAW* PWIN32_FIND_DATAW, LPWIN32_FIND_DATAW; struct WIN32_STREAM_ID { DWORD dwStreamId; DWORD dwStreamAttributes; LARGE_INTEGER Size; DWORD dwStreamNameSize; WCHAR _cStreamName; WCHAR* cStreamName() return { return &_cStreamName; } } alias WIN32_STREAM_ID* LPWIN32_STREAM_ID; enum FINDEX_INFO_LEVELS { FindExInfoStandard, FindExInfoMaxInfoLevel } enum FINDEX_SEARCH_OPS { FindExSearchNameMatch, FindExSearchLimitToDirectories, FindExSearchLimitToDevices, FindExSearchMaxSearchOp } enum ACL_INFORMATION_CLASS { AclRevisionInformation = 1, AclSizeInformation } struct HW_PROFILE_INFOA { DWORD dwDockInfo; CHAR[HW_PROFILE_GUIDLEN] szHwProfileGuid; CHAR[MAX_PROFILE_LEN] szHwProfileName; } alias HW_PROFILE_INFOA* LPHW_PROFILE_INFOA; struct HW_PROFILE_INFOW { DWORD dwDockInfo; WCHAR[HW_PROFILE_GUIDLEN] szHwProfileGuid; WCHAR[MAX_PROFILE_LEN] szHwProfileName; } alias HW_PROFILE_INFOW* LPHW_PROFILE_INFOW; /* ??? MSDN documents this only for Windows CE/Mobile, but it's used by * GetFileAttributesEx, which is in desktop Windows. */ enum GET_FILEEX_INFO_LEVELS { GetFileExInfoStandard, GetFileExMaxInfoLevel } struct SYSTEM_INFO { union { DWORD dwOemId; struct { WORD wProcessorArchitecture; WORD wReserved; } } DWORD dwPageSize; PVOID lpMinimumApplicationAddress; PVOID lpMaximumApplicationAddress; DWORD_PTR dwActiveProcessorMask; DWORD dwNumberOfProcessors; DWORD dwProcessorType; DWORD dwAllocationGranularity; WORD wProcessorLevel; WORD wProcessorRevision; } alias SYSTEM_INFO* LPSYSTEM_INFO; static if (_WIN32_WINNT >= 0x500) { struct SYSTEM_POWER_STATUS { BYTE ACLineStatus; BYTE BatteryFlag; BYTE BatteryLifePercent; BYTE Reserved1; DWORD BatteryLifeTime; DWORD BatteryFullLifeTime; } alias SYSTEM_POWER_STATUS* LPSYSTEM_POWER_STATUS; } struct TIME_ZONE_INFORMATION { LONG Bias; WCHAR[32] StandardName; SYSTEMTIME StandardDate; LONG StandardBias; WCHAR[32] DaylightName; SYSTEMTIME DaylightDate; LONG DaylightBias; } alias TIME_ZONE_INFORMATION* LPTIME_ZONE_INFORMATION; // Does not exist in Windows headers, only MSDN // documentation (for TIME_ZONE_INFORMATION). // Provided solely for compatibility with the old // core.sys.windows.windows struct REG_TZI_FORMAT { LONG Bias; LONG StandardBias; LONG DaylightBias; SYSTEMTIME StandardDate; SYSTEMTIME DaylightDate; } // MSDN documents this, possibly erroneously, as Win2000+. struct MEMORYSTATUS { DWORD dwLength; DWORD dwMemoryLoad; DWORD dwTotalPhys; DWORD dwAvailPhys; DWORD dwTotalPageFile; DWORD dwAvailPageFile; DWORD dwTotalVirtual; DWORD dwAvailVirtual; } alias MEMORYSTATUS* LPMEMORYSTATUS; static if (_WIN32_WINNT >= 0x500) { struct MEMORYSTATUSEX { DWORD dwLength; DWORD dwMemoryLoad; DWORDLONG ullTotalPhys; DWORDLONG ullAvailPhys; DWORDLONG ullTotalPageFile; DWORDLONG ullAvailPageFile; DWORDLONG ullTotalVirtual; DWORDLONG ullAvailVirtual; DWORDLONG ullAvailExtendedVirtual; } alias MEMORYSTATUSEX* LPMEMORYSTATUSEX; } struct LDT_ENTRY { WORD LimitLow; WORD BaseLow; struct { BYTE BaseMid; BYTE Flags1; BYTE Flags2; BYTE BaseHi; byte Type(byte f) { Flags1 = cast(BYTE) ((Flags1 & 0xE0) | f); return cast(byte)(f & 0x1F); } byte Dpl(byte f) { Flags1 = cast(BYTE) ((Flags1 & 0x9F) | (f<<5)); return cast(byte)(f & 3); } bool Pres(bool f) { Flags1 = cast(BYTE) ((Flags1 & 0x7F) | (f<<7)); return f; } byte LimitHi(byte f) { Flags2 = cast(BYTE) ((Flags2 & 0xF0) | (f&0x0F)); return cast(byte)(f & 0x0F); } bool Sys(bool f) { Flags2 = cast(BYTE) ((Flags2 & 0xEF) | (f<<4)); return f; } // Next bit is reserved bool Default_Big(bool f) { Flags2 = cast(BYTE) ((Flags2 & 0xBF) | (f<<6)); return f; } bool Granularity(bool f) { Flags2 = cast(BYTE) ((Flags2 & 0x7F) | (f<<7)); return f; } byte Type() { return cast(byte) (Flags1 & 0x1F); } byte Dpl() { return cast(byte) ((Flags1 & 0x60)>>5); } bool Pres() { return cast(bool) (Flags1 & 0x80); } byte LimitHi() { return cast(byte) (Flags2 & 0x0F); } bool Sys() { return cast(bool) (Flags2 & 0x10); } bool Default_Big() { return cast(bool) (Flags2 & 0x40); } bool Granularity() { return cast(bool) (Flags2 & 0x80); } } /+ union HighWord { struct Bytes { BYTE BaseMid; BYTE Flags1; BYTE Flags2; BYTE BaseHi; } struct Bits { DWORD BaseMid:8; DWORD Type:5; DWORD Dpl:2; DWORD Pres:1; DWORD LimitHi:4; DWORD Sys:1; DWORD Reserved_0:1; DWORD Default_Big:1; DWORD Granularity:1; DWORD BaseHi:8; } } +/ } alias LDT_ENTRY* PLDT_ENTRY, LPLDT_ENTRY; /* As with the other memory management functions and structures, MSDN's * Windows version info shall be taken with a cup of salt. */ struct PROCESS_HEAP_ENTRY { PVOID lpData; DWORD cbData; BYTE cbOverhead; BYTE iRegionIndex; WORD wFlags; union { struct Block { HANDLE hMem; DWORD[3] dwReserved; } struct Region { DWORD dwCommittedSize; DWORD dwUnCommittedSize; LPVOID lpFirstBlock; LPVOID lpLastBlock; } } } alias PROCESS_HEAP_ENTRY* LPPROCESS_HEAP_ENTRY; struct OFSTRUCT { BYTE cBytes = OFSTRUCT.sizeof; BYTE fFixedDisk; WORD nErrCode; WORD Reserved1; WORD Reserved2; CHAR[128] szPathName; // const OFS_MAXPATHNAME = 128; } alias OFSTRUCT* LPOFSTRUCT, POFSTRUCT; /* ??? MSDN documents this only for Windows CE, but it's used by * ImageGetCertificateData, which is in desktop Windows. */ struct WIN_CERTIFICATE { DWORD dwLength; WORD wRevision; WORD wCertificateType; BYTE _bCertificate; BYTE* bCertificate() return { return &_bCertificate; } } alias WIN_CERTIFICATE* LPWIN_CERTIFICATE; static if (_WIN32_WINNT >= 0x500) { enum COMPUTER_NAME_FORMAT { ComputerNameNetBIOS, ComputerNameDnsHostname, ComputerNameDnsDomain, ComputerNameDnsFullyQualified, ComputerNamePhysicalNetBIOS, ComputerNamePhysicalDnsHostname, ComputerNamePhysicalDnsDomain, ComputerNamePhysicalDnsFullyQualified, ComputerNameMax } } static if (_WIN32_WINNT >= 0x501) { struct ACTCTXA { ULONG cbSize = this.sizeof; DWORD dwFlags; LPCSTR lpSource; USHORT wProcessorArchitecture; LANGID wLangId; LPCSTR lpAssemblyDirectory; LPCSTR lpResourceName; LPCSTR lpApplicationName; HMODULE hModule; } alias ACTCTXA* PACTCTXA; alias const(ACTCTXA)* PCACTCTXA; struct ACTCTXW { ULONG cbSize = this.sizeof; DWORD dwFlags; LPCWSTR lpSource; USHORT wProcessorArchitecture; LANGID wLangId; LPCWSTR lpAssemblyDirectory; LPCWSTR lpResourceName; LPCWSTR lpApplicationName; HMODULE hModule; } alias ACTCTXW* PACTCTXW; alias const(ACTCTXW)* PCACTCTXW; struct ACTCTX_SECTION_KEYED_DATA { ULONG cbSize = this.sizeof; ULONG ulDataFormatVersion; PVOID lpData; ULONG ulLength; PVOID lpSectionGlobalData; ULONG ulSectionGlobalDataLength; PVOID lpSectionBase; ULONG ulSectionTotalLength; HANDLE hActCtx; HANDLE ulAssemblyRosterIndex; } alias ACTCTX_SECTION_KEYED_DATA* PACTCTX_SECTION_KEYED_DATA; alias const(ACTCTX_SECTION_KEYED_DATA)* PCACTCTX_SECTION_KEYED_DATA; enum MEMORY_RESOURCE_NOTIFICATION_TYPE { LowMemoryResourceNotification, HighMemoryResourceNotification } } // (_WIN32_WINNT >= 0x501) static if (_WIN32_WINNT >= 0x410) { /* apparently used only by SetThreadExecutionState (Win2000+) * and DDK functions (version compatibility not established) */ alias DWORD EXECUTION_STATE; } // Callbacks extern (Windows) { alias DWORD function(LPVOID) LPTHREAD_START_ROUTINE; alias DWORD function(LARGE_INTEGER, LARGE_INTEGER, LARGE_INTEGER, LARGE_INTEGER, DWORD, DWORD, HANDLE, HANDLE, LPVOID) LPPROGRESS_ROUTINE; alias void function(PVOID) LPFIBER_START_ROUTINE; alias BOOL function(HMODULE, LPCSTR, LPCSTR, WORD, LONG) ENUMRESLANGPROCA; alias BOOL function(HMODULE, LPCWSTR, LPCWSTR, WORD, LONG) ENUMRESLANGPROCW; alias BOOL function(HMODULE, LPCSTR, LPSTR, LONG) ENUMRESNAMEPROCA; alias BOOL function(HMODULE, LPCWSTR, LPWSTR, LONG) ENUMRESNAMEPROCW; alias BOOL function(HMODULE, LPSTR, LONG) ENUMRESTYPEPROCA; alias BOOL function(HMODULE, LPWSTR, LONG) ENUMRESTYPEPROCW; alias void function(DWORD, DWORD, LPOVERLAPPED) LPOVERLAPPED_COMPLETION_ROUTINE; alias LONG function(LPEXCEPTION_POINTERS) PTOP_LEVEL_EXCEPTION_FILTER; alias PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; alias void function(ULONG_PTR) PAPCFUNC; alias void function(PVOID, DWORD, DWORD) PTIMERAPCROUTINE; static if (_WIN32_WINNT >= 0x500) { alias void function(PVOID, BOOLEAN) WAITORTIMERCALLBACK; } } LPTSTR MAKEINTATOM()(ushort i) { return cast(LPTSTR) cast(size_t) i; } extern (Windows) nothrow @nogc { // The following Win16 functions are obselete in Win32. int _hread(HFILE, LPVOID, int); int _hwrite(HFILE, LPCSTR, int); HFILE _lclose(HFILE); HFILE _lcreat(LPCSTR, int); LONG _llseek(HFILE, LONG, int); HFILE _lopen(LPCSTR, int); UINT _lread(HFILE, LPVOID, UINT); UINT _lwrite(HFILE, LPCSTR, UINT); SIZE_T GlobalCompact(DWORD); VOID GlobalFix(HGLOBAL); // MSDN contradicts itself on GlobalFlags: // "This function is provided only for compatibility with 16-bit versions of Windows." // but also requires Windows 2000 or above UINT GlobalFlags(HGLOBAL); VOID GlobalUnfix(HGLOBAL); BOOL GlobalUnWire(HGLOBAL); PVOID GlobalWire(HGLOBAL); SIZE_T LocalCompact(UINT); UINT LocalFlags(HLOCAL); SIZE_T LocalShrink(HLOCAL, UINT); /+ //-------------------------------------- // These functions are problematic version(UseNtoSKernel) {}else { /* CAREFUL: These are exported from ntoskrnl.exe and declared in winddk.h as __fastcall functions, but are exported from kernel32.dll as __stdcall */ static if (_WIN32_WINNT >= 0x501) { VOID InitializeSListHead(PSLIST_HEADER); } LONG InterlockedCompareExchange(LPLONG, LONG, LONG); // PVOID WINAPI InterlockedCompareExchangePointer(PVOID*, PVOID, PVOID); (PVOID)InterlockedCompareExchange((LPLONG)(d) (PVOID)InterlockedCompareExchange((LPLONG)(d), (LONG)(e), (LONG)(c)) LONG InterlockedDecrement(LPLONG); LONG InterlockedExchange(LPLONG, LONG); // PVOID WINAPI InterlockedExchangePointer(PVOID*, PVOID); (PVOID)InterlockedExchange((LPLONG)((PVOID)InterlockedExchange((LPLONG)(t), (LONG)(v)) LONG InterlockedExchangeAdd(LPLONG, LONG); static if (_WIN32_WINNT >= 0x501) { PSLIST_ENTRY InterlockedFlushSList(PSLIST_HEADER); } LONG InterlockedIncrement(LPLONG); static if (_WIN32_WINNT >= 0x501) { PSLIST_ENTRY InterlockedPopEntrySList(PSLIST_HEADER); PSLIST_ENTRY InterlockedPushEntrySList(PSLIST_HEADER, PSLIST_ENTRY); } } // #endif // __USE_NTOSKRNL__ //-------------------------------------- +/ LONG InterlockedIncrement(LPLONG lpAddend); LONG InterlockedDecrement(LPLONG lpAddend); LONG InterlockedExchange(LPLONG Target, LONG Value); LONG InterlockedExchangeAdd(LPLONG Addend, LONG Value); LONG InterlockedCompareExchange(LONG *Destination, LONG Exchange, LONG Comperand); ATOM AddAtomA(LPCSTR); ATOM AddAtomW(LPCWSTR); BOOL AreFileApisANSI(); BOOL Beep(DWORD, DWORD); HANDLE BeginUpdateResourceA(LPCSTR, BOOL); HANDLE BeginUpdateResourceW(LPCWSTR, BOOL); BOOL BuildCommDCBA(LPCSTR, LPDCB); BOOL BuildCommDCBW(LPCWSTR, LPDCB); BOOL BuildCommDCBAndTimeoutsA(LPCSTR, LPDCB, LPCOMMTIMEOUTS); BOOL BuildCommDCBAndTimeoutsW(LPCWSTR, LPDCB, LPCOMMTIMEOUTS); BOOL CallNamedPipeA(LPCSTR, PVOID, DWORD, PVOID, DWORD, PDWORD, DWORD); BOOL CallNamedPipeW(LPCWSTR, PVOID, DWORD, PVOID, DWORD, PDWORD, DWORD); BOOL CancelDeviceWakeupRequest(HANDLE); BOOL CheckTokenMembership(HANDLE, PSID, PBOOL); BOOL ClearCommBreak(HANDLE); BOOL ClearCommError(HANDLE, PDWORD, LPCOMSTAT); BOOL CloseHandle(HANDLE) @trusted; BOOL CommConfigDialogA(LPCSTR, HWND, LPCOMMCONFIG); BOOL CommConfigDialogW(LPCWSTR, HWND, LPCOMMCONFIG); LONG CompareFileTime(const(FILETIME)*, const(FILETIME)*); BOOL ContinueDebugEvent(DWORD, DWORD, DWORD); BOOL CopyFileA(LPCSTR, LPCSTR, BOOL); BOOL CopyFileW(LPCWSTR, LPCWSTR, BOOL); BOOL CopyFileExA(LPCSTR, LPCSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD); BOOL CopyFileExW(LPCWSTR, LPCWSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD); /+ FIXME alias memmove RtlMoveMemory; alias memcpy RtlCopyMemory; void RtlFillMemory(PVOID dest, SIZE_T len, BYTE fill) { memset(dest, fill, len); } void RtlZeroMemory(PVOID dest, SIZE_T len) { RtlFillMemory(dest, len, 0); } alias RtlMoveMemory MoveMemory; alias RtlCopyMemory CopyMemory; alias RtlFillMemory FillMemory; alias RtlZeroMemory ZeroMemory; +/ BOOL CreateDirectoryA(LPCSTR, LPSECURITY_ATTRIBUTES); BOOL CreateDirectoryW(LPCWSTR, LPSECURITY_ATTRIBUTES); BOOL CreateDirectoryExA(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); BOOL CreateDirectoryExW(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); HANDLE CreateEventA(LPSECURITY_ATTRIBUTES, BOOL, BOOL, LPCSTR); HANDLE CreateEventW(LPSECURITY_ATTRIBUTES, BOOL, BOOL, LPCWSTR); HANDLE CreateFileA(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); HANDLE CreateFileW(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); HANDLE CreateIoCompletionPort(HANDLE, HANDLE, ULONG_PTR, DWORD); HANDLE CreateMailslotA(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES); HANDLE CreateMailslotW(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES); HANDLE CreateMutexA(LPSECURITY_ATTRIBUTES, BOOL, LPCSTR); HANDLE CreateMutexW(LPSECURITY_ATTRIBUTES, BOOL, LPCWSTR); BOOL CreatePipe(PHANDLE, PHANDLE, LPSECURITY_ATTRIBUTES, DWORD); BOOL CreateProcessA(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, PVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION); BOOL CreateProcessW(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, PVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION); HANDLE CreateSemaphoreA(LPSECURITY_ATTRIBUTES, LONG, LONG, LPCSTR) @trusted; HANDLE CreateSemaphoreW(LPSECURITY_ATTRIBUTES, LONG, LONG, LPCWSTR) @trusted; HANDLE CreateThread(LPSECURITY_ATTRIBUTES, DWORD, LPTHREAD_START_ROUTINE, PVOID, DWORD, PDWORD); BOOL DebugActiveProcess(DWORD); void DebugBreak(); ATOM DeleteAtom(ATOM); void DeleteCriticalSection(PCRITICAL_SECTION); BOOL DeleteFileA(LPCSTR); BOOL DeleteFileW(LPCWSTR); BOOL DisableThreadLibraryCalls(HMODULE); BOOL DosDateTimeToFileTime(WORD, WORD, LPFILETIME); BOOL DuplicateHandle(HANDLE, HANDLE, HANDLE, PHANDLE, DWORD, BOOL, DWORD); BOOL EndUpdateResourceA(HANDLE, BOOL); BOOL EndUpdateResourceW(HANDLE, BOOL); void EnterCriticalSection(LPCRITICAL_SECTION); BOOL EnumResourceLanguagesA(HMODULE, LPCSTR, LPCSTR, ENUMRESLANGPROC, LONG_PTR); BOOL EnumResourceLanguagesW(HMODULE, LPCWSTR, LPCWSTR, ENUMRESLANGPROC, LONG_PTR); BOOL EnumResourceNamesA(HMODULE, LPCSTR, ENUMRESNAMEPROC, LONG_PTR); BOOL EnumResourceNamesW(HMODULE, LPCWSTR, ENUMRESNAMEPROC, LONG_PTR); BOOL EnumResourceTypesA(HMODULE, ENUMRESTYPEPROC, LONG_PTR); BOOL EnumResourceTypesW(HMODULE, ENUMRESTYPEPROC, LONG_PTR); BOOL EscapeCommFunction(HANDLE, DWORD); void ExitProcess(UINT); // Never returns void ExitThread(DWORD); // Never returns DWORD ExpandEnvironmentStringsA(LPCSTR, LPSTR, DWORD); DWORD ExpandEnvironmentStringsW(LPCWSTR, LPWSTR, DWORD); void FatalAppExitA(UINT, LPCSTR); void FatalAppExitW(UINT, LPCWSTR); void FatalExit(int); BOOL FileTimeToDosDateTime(const(FILETIME)*, LPWORD, LPWORD); BOOL FileTimeToLocalFileTime(const(FILETIME)*, LPFILETIME); BOOL FileTimeToSystemTime(const(FILETIME)*, LPSYSTEMTIME); ATOM FindAtomA(LPCSTR); ATOM FindAtomW(LPCWSTR); BOOL FindClose(HANDLE); BOOL FindCloseChangeNotification(HANDLE); HANDLE FindFirstChangeNotificationA(LPCSTR, BOOL, DWORD); HANDLE FindFirstChangeNotificationW(LPCWSTR, BOOL, DWORD); HANDLE FindFirstFileA(LPCSTR, LPWIN32_FIND_DATAA); HANDLE FindFirstFileW(LPCWSTR, LPWIN32_FIND_DATAW); BOOL FindNextChangeNotification(HANDLE); BOOL FindNextFileA(HANDLE, LPWIN32_FIND_DATAA); BOOL FindNextFileW(HANDLE, LPWIN32_FIND_DATAW); HRSRC FindResourceA(HMODULE, LPCSTR, LPCSTR); HRSRC FindResourceW(HINSTANCE, LPCWSTR, LPCWSTR); HRSRC FindResourceExA(HINSTANCE, LPCSTR, LPCSTR, WORD); HRSRC FindResourceExW(HINSTANCE, LPCWSTR, LPCWSTR, WORD); BOOL FlushFileBuffers(HANDLE); BOOL FlushInstructionCache(HANDLE, PCVOID, DWORD); DWORD FormatMessageA(DWORD, PCVOID, DWORD, DWORD, LPSTR, DWORD, va_list*); DWORD FormatMessageW(DWORD, PCVOID, DWORD, DWORD, LPWSTR, DWORD, va_list*); BOOL FreeEnvironmentStringsA(LPSTR); BOOL FreeEnvironmentStringsW(LPWSTR); BOOL FreeLibrary(HMODULE); void FreeLibraryAndExitThread(HMODULE, DWORD); // never returns BOOL FreeResource(HGLOBAL); UINT GetAtomNameA(ATOM, LPSTR, int); UINT GetAtomNameW(ATOM, LPWSTR, int); LPSTR GetCommandLineA(); LPWSTR GetCommandLineW(); BOOL GetCommConfig(HANDLE, LPCOMMCONFIG, PDWORD); BOOL GetCommMask(HANDLE, PDWORD); BOOL GetCommModemStatus(HANDLE, PDWORD); BOOL GetCommProperties(HANDLE, LPCOMMPROP); BOOL GetCommState(HANDLE, LPDCB); BOOL GetCommTimeouts(HANDLE, LPCOMMTIMEOUTS); BOOL GetComputerNameA(LPSTR, PDWORD); BOOL GetComputerNameW(LPWSTR, PDWORD); DWORD GetCurrentDirectoryA(DWORD, LPSTR); DWORD GetCurrentDirectoryW(DWORD, LPWSTR); HANDLE GetCurrentProcess(); DWORD GetCurrentProcessId(); HANDLE GetCurrentThread(); /* In MinGW: #ifdef _WIN32_WCE extern DWORD GetCurrentThreadId(void); #else WINBASEAPI DWORD WINAPI GetCurrentThreadId(void); #endif */ DWORD GetCurrentThreadId(); alias GetTickCount GetCurrentTime; BOOL GetDefaultCommConfigA(LPCSTR, LPCOMMCONFIG, PDWORD); BOOL GetDefaultCommConfigW(LPCWSTR, LPCOMMCONFIG, PDWORD); BOOL GetDiskFreeSpaceA(LPCSTR, PDWORD, PDWORD, PDWORD, PDWORD); BOOL GetDiskFreeSpaceW(LPCWSTR, PDWORD, PDWORD, PDWORD, PDWORD); BOOL GetDiskFreeSpaceExA(LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER); BOOL GetDiskFreeSpaceExW(LPCWSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER); UINT GetDriveTypeA(LPCSTR); UINT GetDriveTypeW(LPCWSTR); LPSTR GetEnvironmentStrings(); // ??? LPSTR GetEnvironmentStringsA(); LPWSTR GetEnvironmentStringsW(); DWORD GetEnvironmentVariableA(LPCSTR, LPSTR, DWORD); DWORD GetEnvironmentVariableW(LPCWSTR, LPWSTR, DWORD); BOOL GetExitCodeProcess(HANDLE, PDWORD); BOOL GetExitCodeThread(HANDLE, PDWORD); DWORD GetFileAttributesA(LPCSTR); DWORD GetFileAttributesW(LPCWSTR); BOOL GetFileInformationByHandle(HANDLE, LPBY_HANDLE_FILE_INFORMATION); DWORD GetFileSize(HANDLE, PDWORD); BOOL GetFileTime(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME); DWORD GetFileType(HANDLE); DWORD GetFullPathNameA(LPCSTR, DWORD, LPSTR, LPSTR*); DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*); DWORD GetLastError() @trusted; void GetLocalTime(LPSYSTEMTIME); DWORD GetLogicalDrives(); DWORD GetLogicalDriveStringsA(DWORD, LPSTR); DWORD GetLogicalDriveStringsW(DWORD, LPWSTR); BOOL GetMailslotInfo(HANDLE, PDWORD, PDWORD, PDWORD, PDWORD); DWORD GetModuleFileNameA(HINSTANCE, LPSTR, DWORD); DWORD GetModuleFileNameW(HINSTANCE, LPWSTR, DWORD); HMODULE GetModuleHandleA(LPCSTR); HMODULE GetModuleHandleW(LPCWSTR); BOOL GetNamedPipeHandleStateA(HANDLE, PDWORD, PDWORD, PDWORD, PDWORD, LPSTR, DWORD); BOOL GetNamedPipeHandleStateW(HANDLE, PDWORD, PDWORD, PDWORD, PDWORD, LPWSTR, DWORD); BOOL GetNamedPipeInfo(HANDLE, PDWORD, PDWORD, PDWORD, PDWORD); BOOL GetOverlappedResult(HANDLE, LPOVERLAPPED, PDWORD, BOOL); DWORD GetPriorityClass(HANDLE); UINT GetPrivateProfileIntA(LPCSTR, LPCSTR, INT, LPCSTR); UINT GetPrivateProfileIntW(LPCWSTR, LPCWSTR, INT, LPCWSTR); DWORD GetPrivateProfileSectionA(LPCSTR, LPSTR, DWORD, LPCSTR); DWORD GetPrivateProfileSectionW(LPCWSTR, LPWSTR, DWORD, LPCWSTR); DWORD GetPrivateProfileSectionNamesA(LPSTR, DWORD, LPCSTR); DWORD GetPrivateProfileSectionNamesW(LPWSTR, DWORD, LPCWSTR); DWORD GetPrivateProfileStringA(LPCSTR, LPCSTR, LPCSTR, LPSTR, DWORD, LPCSTR); DWORD GetPrivateProfileStringW(LPCWSTR, LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR); BOOL GetPrivateProfileStructA(LPCSTR, LPCSTR, LPVOID, UINT, LPCSTR); BOOL GetPrivateProfileStructW(LPCWSTR, LPCWSTR, LPVOID, UINT, LPCWSTR); FARPROC GetProcAddress(HMODULE, LPCSTR); // 1st param wrongly HINSTANCE in MinGW BOOL GetProcessAffinityMask(HANDLE, PDWORD, PDWORD); DWORD GetProcessVersion(DWORD); UINT GetProfileIntA(LPCSTR, LPCSTR, INT); UINT GetProfileIntW(LPCWSTR, LPCWSTR, INT); DWORD GetProfileSectionA(LPCSTR, LPSTR, DWORD); DWORD GetProfileSectionW(LPCWSTR, LPWSTR, DWORD); DWORD GetProfileStringA(LPCSTR, LPCSTR, LPCSTR, LPSTR, DWORD); DWORD GetProfileStringW(LPCWSTR, LPCWSTR, LPCWSTR, LPWSTR, DWORD); DWORD GetShortPathNameA(LPCSTR, LPSTR, DWORD); DWORD GetShortPathNameW(LPCWSTR, LPWSTR, DWORD); VOID GetStartupInfoA(LPSTARTUPINFOA); VOID GetStartupInfoW(LPSTARTUPINFOW); HANDLE GetStdHandle(DWORD); UINT GetSystemDirectoryA(LPSTR, UINT); UINT GetSystemDirectoryW(LPWSTR, UINT); VOID GetSystemInfo(LPSYSTEM_INFO); VOID GetSystemTime(LPSYSTEMTIME); BOOL GetSystemTimeAdjustment(PDWORD, PDWORD, PBOOL); void GetSystemTimeAsFileTime(LPFILETIME); UINT GetTempFileNameA(LPCSTR, LPCSTR, UINT, LPSTR); UINT GetTempFileNameW(LPCWSTR, LPCWSTR, UINT, LPWSTR); DWORD GetTempPathA(DWORD, LPSTR); DWORD GetTempPathW(DWORD, LPWSTR); BOOL GetThreadContext(HANDLE, LPCONTEXT); int GetThreadPriority(HANDLE); BOOL GetThreadSelectorEntry(HANDLE, DWORD, LPLDT_ENTRY); DWORD GetTickCount(); DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION); BOOL GetUserNameA (LPSTR, PDWORD); BOOL GetUserNameW(LPWSTR, PDWORD); DWORD GetVersion(); BOOL GetVersionExA(LPOSVERSIONINFOA); BOOL GetVersionExW(LPOSVERSIONINFOW); BOOL GetVolumeInformationA(LPCSTR, LPSTR, DWORD, PDWORD, PDWORD, PDWORD, LPSTR, DWORD); BOOL GetVolumeInformationW(LPCWSTR, LPWSTR, DWORD, PDWORD, PDWORD, PDWORD, LPWSTR, DWORD); UINT GetWindowsDirectoryA(LPSTR, UINT); UINT GetWindowsDirectoryW(LPWSTR, UINT); DWORD GetWindowThreadProcessId(HWND, PDWORD); ATOM GlobalAddAtomA(LPCSTR); ATOM GlobalAddAtomW(LPCWSTR); ATOM GlobalDeleteAtom(ATOM); ATOM GlobalFindAtomA(LPCSTR); ATOM GlobalFindAtomW(LPCWSTR); UINT GlobalGetAtomNameA(ATOM, LPSTR, int); UINT GlobalGetAtomNameW(ATOM, LPWSTR, int); bool HasOverlappedIoCompleted(LPOVERLAPPED lpOverlapped) { return lpOverlapped.Internal != STATUS_PENDING; } BOOL InitAtomTable(DWORD); VOID InitializeCriticalSection(LPCRITICAL_SECTION) @trusted; /* ??? The next two are allegedly obsolete and "supported only for * backward compatibility with the 16-bit Windows API". Yet the * replacements IsBadReadPtr and IsBadWritePtr are apparently Win2000+ * only. Where's the mistake? */ BOOL IsBadHugeReadPtr(PCVOID, UINT_PTR); BOOL IsBadHugeWritePtr(PVOID, UINT_PTR); BOOL IsBadReadPtr(PCVOID, UINT_PTR); BOOL IsBadStringPtrA(LPCSTR, UINT_PTR); BOOL IsBadStringPtrW(LPCWSTR, UINT_PTR); BOOL IsBadWritePtr(PVOID, UINT_PTR); void LeaveCriticalSection(LPCRITICAL_SECTION); HINSTANCE LoadLibraryA(LPCSTR); HINSTANCE LoadLibraryW(LPCWSTR); HINSTANCE LoadLibraryExA(LPCSTR, HANDLE, DWORD); HINSTANCE LoadLibraryExW(LPCWSTR, HANDLE, DWORD); DWORD LoadModule(LPCSTR, PVOID); HGLOBAL LoadResource(HINSTANCE, HRSRC); BOOL LocalFileTimeToFileTime(const(FILETIME)*, LPFILETIME); BOOL LockFile(HANDLE, DWORD, DWORD, DWORD, DWORD); PVOID LockResource(HGLOBAL); LPSTR lstrcatA(LPSTR, LPCSTR); LPWSTR lstrcatW(LPWSTR, LPCWSTR); int lstrcmpA(LPCSTR, LPCSTR); int lstrcmpiA(LPCSTR, LPCSTR); int lstrcmpiW(LPCWSTR, LPCWSTR); int lstrcmpW(LPCWSTR, LPCWSTR); LPSTR lstrcpyA(LPSTR, LPCSTR); LPSTR lstrcpynA(LPSTR, LPCSTR, int); LPWSTR lstrcpynW(LPWSTR, LPCWSTR, int); LPWSTR lstrcpyW(LPWSTR, LPCWSTR); int lstrlenA(LPCSTR); int lstrlenW(LPCWSTR); BOOL MoveFileA(LPCSTR, LPCSTR); BOOL MoveFileW(LPCWSTR, LPCWSTR); int MulDiv(int, int, int); HANDLE OpenEventA(DWORD, BOOL, LPCSTR); HANDLE OpenEventW(DWORD, BOOL, LPCWSTR); deprecated HFILE OpenFile(LPCSTR, LPOFSTRUCT, UINT); HANDLE OpenMutexA(DWORD, BOOL, LPCSTR); HANDLE OpenMutexW(DWORD, BOOL, LPCWSTR); HANDLE OpenProcess(DWORD, BOOL, DWORD); HANDLE OpenSemaphoreA(DWORD, BOOL, LPCSTR); HANDLE OpenSemaphoreW(DWORD, BOOL, LPCWSTR); void OutputDebugStringA(LPCSTR); void OutputDebugStringW(LPCWSTR); BOOL PeekNamedPipe(HANDLE, PVOID, DWORD, PDWORD, PDWORD, PDWORD); BOOL PulseEvent(HANDLE); BOOL PurgeComm(HANDLE, DWORD); BOOL QueryPerformanceCounter(PLARGE_INTEGER); BOOL QueryPerformanceFrequency(PLARGE_INTEGER); DWORD QueueUserAPC(PAPCFUNC, HANDLE, ULONG_PTR); void RaiseException(DWORD, DWORD, DWORD, const(DWORD)*); BOOL ReadFile(HANDLE, PVOID, DWORD, PDWORD, LPOVERLAPPED); BOOL ReadFileEx(HANDLE, PVOID, DWORD, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE); BOOL ReadProcessMemory(HANDLE, PCVOID, PVOID, SIZE_T, SIZE_T*); BOOL ReleaseMutex(HANDLE); BOOL ReleaseSemaphore(HANDLE, LONG, LPLONG); BOOL RemoveDirectoryA(LPCSTR); BOOL RemoveDirectoryW(LPCWSTR); /* In MinGW: #ifdef _WIN32_WCE extern BOOL ResetEvent(HANDLE); #else WINBASEAPI BOOL WINAPI ResetEvent(HANDLE); #endif */ BOOL ResetEvent(HANDLE); DWORD ResumeThread(HANDLE); DWORD SearchPathA(LPCSTR, LPCSTR, LPCSTR, DWORD, LPSTR, LPSTR*); DWORD SearchPathW(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPWSTR, LPWSTR*); BOOL SetCommBreak(HANDLE); BOOL SetCommConfig(HANDLE, LPCOMMCONFIG, DWORD); BOOL SetCommMask(HANDLE, DWORD); BOOL SetCommState(HANDLE, LPDCB); BOOL SetCommTimeouts(HANDLE, LPCOMMTIMEOUTS); BOOL SetComputerNameA(LPCSTR); BOOL SetComputerNameW(LPCWSTR); BOOL SetCurrentDirectoryA(LPCSTR); BOOL SetCurrentDirectoryW(LPCWSTR); BOOL SetDefaultCommConfigA(LPCSTR, LPCOMMCONFIG, DWORD); BOOL SetDefaultCommConfigW(LPCWSTR, LPCOMMCONFIG, DWORD); BOOL SetEndOfFile(HANDLE); BOOL SetEnvironmentVariableA(LPCSTR, LPCSTR); BOOL SetEnvironmentVariableW(LPCWSTR, LPCWSTR); UINT SetErrorMode(UINT); /* In MinGW: #ifdef _WIN32_WCE extern BOOL SetEvent(HANDLE); #else WINBASEAPI BOOL WINAPI SetEvent(HANDLE); #endif */ BOOL SetEvent(HANDLE); VOID SetFileApisToANSI(); VOID SetFileApisToOEM(); BOOL SetFileAttributesA(LPCSTR, DWORD); BOOL SetFileAttributesW(LPCWSTR, DWORD); DWORD SetFilePointer(HANDLE, LONG, PLONG, DWORD); BOOL SetFileTime(HANDLE, const(FILETIME)*, const(FILETIME)*, const(FILETIME)*); deprecated UINT SetHandleCount(UINT); void SetLastError(DWORD); void SetLastErrorEx(DWORD, DWORD); BOOL SetLocalTime(const(SYSTEMTIME)*); BOOL SetMailslotInfo(HANDLE, DWORD); BOOL SetNamedPipeHandleState(HANDLE, PDWORD, PDWORD, PDWORD); BOOL SetPriorityClass(HANDLE, DWORD); BOOL SetStdHandle(DWORD, HANDLE); BOOL SetSystemTime(const(SYSTEMTIME)*); DWORD SetThreadAffinityMask(HANDLE, DWORD); BOOL SetThreadContext(HANDLE, const(CONTEXT)*); BOOL SetThreadPriority(HANDLE, int); BOOL SetTimeZoneInformation(const(TIME_ZONE_INFORMATION)*); LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER); BOOL SetupComm(HANDLE, DWORD, DWORD); BOOL SetVolumeLabelA(LPCSTR, LPCSTR); BOOL SetVolumeLabelW(LPCWSTR, LPCWSTR); DWORD SizeofResource(HINSTANCE, HRSRC); void Sleep(DWORD); DWORD SleepEx(DWORD, BOOL); DWORD SuspendThread(HANDLE); BOOL SystemTimeToFileTime(const(SYSTEMTIME)*, LPFILETIME); BOOL TerminateProcess(HANDLE, UINT); BOOL TerminateThread(HANDLE, DWORD); DWORD TlsAlloc(); BOOL TlsFree(DWORD); PVOID TlsGetValue(DWORD); BOOL TlsSetValue(DWORD, PVOID); BOOL TransactNamedPipe(HANDLE, PVOID, DWORD, PVOID, DWORD, PDWORD, LPOVERLAPPED); BOOL TransmitCommChar(HANDLE, char); LONG UnhandledExceptionFilter(LPEXCEPTION_POINTERS); BOOL UnlockFile(HANDLE, DWORD, DWORD, DWORD, DWORD); BOOL WaitCommEvent(HANDLE, PDWORD, LPOVERLAPPED); BOOL WaitForDebugEvent(LPDEBUG_EVENT, DWORD); DWORD WaitForMultipleObjects(DWORD, const(HANDLE)*, BOOL, DWORD); DWORD WaitForMultipleObjectsEx(DWORD, const(HANDLE)*, BOOL, DWORD, BOOL); DWORD WaitForSingleObject(HANDLE, DWORD); DWORD WaitForSingleObjectEx(HANDLE, DWORD, BOOL); BOOL WaitNamedPipeA(LPCSTR, DWORD); BOOL WaitNamedPipeW(LPCWSTR, DWORD); // undocumented on MSDN BOOL WinLoadTrustProvider(GUID*); BOOL WriteFile(HANDLE, PCVOID, DWORD, PDWORD, LPOVERLAPPED); BOOL WriteFileEx(HANDLE, PCVOID, DWORD, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE); BOOL WritePrivateProfileSectionA(LPCSTR, LPCSTR, LPCSTR); BOOL WritePrivateProfileSectionW(LPCWSTR, LPCWSTR, LPCWSTR); BOOL WritePrivateProfileStringA(LPCSTR, LPCSTR, LPCSTR, LPCSTR); BOOL WritePrivateProfileStringW(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR); BOOL WritePrivateProfileStructA(LPCSTR, LPCSTR, LPVOID, UINT, LPCSTR); BOOL WritePrivateProfileStructW(LPCWSTR, LPCWSTR, LPVOID, UINT, LPCWSTR); BOOL WriteProcessMemory(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*); BOOL WriteProfileSectionA(LPCSTR, LPCSTR); BOOL WriteProfileSectionW(LPCWSTR, LPCWSTR); BOOL WriteProfileStringA(LPCSTR, LPCSTR, LPCSTR); BOOL WriteProfileStringW(LPCWSTR, LPCWSTR, LPCWSTR); /* Memory allocation functions. * MSDN documents these erroneously as Win2000+; thus it is uncertain what * version compatibility they really have. */ HGLOBAL GlobalAlloc(UINT, SIZE_T); HGLOBAL GlobalDiscard(HGLOBAL); HGLOBAL GlobalFree(HGLOBAL); HGLOBAL GlobalHandle(PCVOID); LPVOID GlobalLock(HGLOBAL); VOID GlobalMemoryStatus(LPMEMORYSTATUS); HGLOBAL GlobalReAlloc(HGLOBAL, SIZE_T, UINT); SIZE_T GlobalSize(HGLOBAL); BOOL GlobalUnlock(HGLOBAL); PVOID HeapAlloc(HANDLE, DWORD, SIZE_T); SIZE_T HeapCompact(HANDLE, DWORD); HANDLE HeapCreate(DWORD, SIZE_T, SIZE_T); BOOL HeapDestroy(HANDLE); BOOL HeapFree(HANDLE, DWORD, PVOID); BOOL HeapLock(HANDLE); PVOID HeapReAlloc(HANDLE, DWORD, PVOID, SIZE_T); SIZE_T HeapSize(HANDLE, DWORD, PCVOID); BOOL HeapUnlock(HANDLE); BOOL HeapValidate(HANDLE, DWORD, PCVOID); BOOL HeapWalk(HANDLE, LPPROCESS_HEAP_ENTRY); HLOCAL LocalAlloc(UINT, SIZE_T); HLOCAL LocalDiscard(HLOCAL); HLOCAL LocalFree(HLOCAL); HLOCAL LocalHandle(LPCVOID); PVOID LocalLock(HLOCAL); HLOCAL LocalReAlloc(HLOCAL, SIZE_T, UINT); UINT LocalSize(HLOCAL); BOOL LocalUnlock(HLOCAL); PVOID VirtualAlloc(PVOID, SIZE_T, DWORD, DWORD); PVOID VirtualAllocEx(HANDLE, PVOID, SIZE_T, DWORD, DWORD); BOOL VirtualFree(PVOID, SIZE_T, DWORD); BOOL VirtualFreeEx(HANDLE, PVOID, SIZE_T, DWORD); BOOL VirtualLock(PVOID, SIZE_T); BOOL VirtualProtect(PVOID, SIZE_T, DWORD, PDWORD); BOOL VirtualProtectEx(HANDLE, PVOID, SIZE_T, DWORD, PDWORD); SIZE_T VirtualQuery(LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T); SIZE_T VirtualQueryEx(HANDLE, LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T); BOOL VirtualUnlock(PVOID, SIZE_T); // not in MinGW 4.0 - ??? static if (_WIN32_WINNT >= 0x600) { BOOL CancelIoEx(HANDLE, LPOVERLAPPED); } BOOL CancelIo(HANDLE); BOOL CancelWaitableTimer(HANDLE); PVOID ConvertThreadToFiber(PVOID); LPVOID CreateFiber(SIZE_T, LPFIBER_START_ROUTINE, LPVOID); HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES, BOOL, LPCSTR); HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES, BOOL, LPCWSTR); void DeleteFiber(PVOID); BOOL GetFileAttributesExA(LPCSTR, GET_FILEEX_INFO_LEVELS, PVOID); BOOL GetFileAttributesExW(LPCWSTR, GET_FILEEX_INFO_LEVELS, PVOID); DWORD GetLongPathNameA(LPCSTR, LPSTR, DWORD); DWORD GetLongPathNameW(LPCWSTR, LPWSTR, DWORD); BOOL InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION, DWORD); BOOL IsDebuggerPresent(); HANDLE OpenWaitableTimerA(DWORD, BOOL, LPCSTR); HANDLE OpenWaitableTimerW(DWORD, BOOL, LPCWSTR); DWORD QueryDosDeviceA(LPCSTR, LPSTR, DWORD); DWORD QueryDosDeviceW(LPCWSTR, LPWSTR, DWORD); BOOL SetWaitableTimer(HANDLE, const(LARGE_INTEGER)*, LONG, PTIMERAPCROUTINE, PVOID, BOOL); void SwitchToFiber(PVOID); static if (_WIN32_WINNT >= 0x500) { HANDLE OpenThread(DWORD, BOOL, DWORD); } BOOL AccessCheck(PSECURITY_DESCRIPTOR, HANDLE, DWORD, PGENERIC_MAPPING, PPRIVILEGE_SET, PDWORD, PDWORD, PBOOL); BOOL AccessCheckAndAuditAlarmA(LPCSTR, LPVOID, LPSTR, LPSTR, PSECURITY_DESCRIPTOR, DWORD, PGENERIC_MAPPING, BOOL, PDWORD, PBOOL, PBOOL); BOOL AccessCheckAndAuditAlarmW(LPCWSTR, LPVOID, LPWSTR, LPWSTR, PSECURITY_DESCRIPTOR, DWORD, PGENERIC_MAPPING, BOOL, PDWORD, PBOOL, PBOOL); BOOL AddAccessAllowedAce(PACL, DWORD, DWORD, PSID); BOOL AddAccessDeniedAce(PACL, DWORD, DWORD, PSID); BOOL AddAce(PACL, DWORD, DWORD, PVOID, DWORD); BOOL AddAuditAccessAce(PACL, DWORD, DWORD, PSID, BOOL, BOOL); BOOL AdjustTokenGroups(HANDLE, BOOL, PTOKEN_GROUPS, DWORD, PTOKEN_GROUPS, PDWORD); BOOL AdjustTokenPrivileges(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); BOOL AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*); BOOL AllocateLocallyUniqueId(PLUID); BOOL AreAllAccessesGranted(DWORD, DWORD); BOOL AreAnyAccessesGranted(DWORD, DWORD); BOOL BackupEventLogA(HANDLE, LPCSTR); BOOL BackupEventLogW(HANDLE, LPCWSTR); BOOL BackupRead(HANDLE, LPBYTE, DWORD, LPDWORD, BOOL, BOOL, LPVOID*); BOOL BackupSeek(HANDLE, DWORD, DWORD, LPDWORD, LPDWORD, LPVOID*); BOOL BackupWrite(HANDLE, LPBYTE, DWORD, LPDWORD, BOOL, BOOL, LPVOID*); BOOL ClearEventLogA(HANDLE, LPCSTR); BOOL ClearEventLogW(HANDLE, LPCWSTR); BOOL CloseEventLog(HANDLE); BOOL ConnectNamedPipe(HANDLE, LPOVERLAPPED); BOOL CopySid(DWORD, PSID, PSID); HANDLE CreateNamedPipeA(LPCSTR, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPSECURITY_ATTRIBUTES); HANDLE CreateNamedPipeW(LPCWSTR, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPSECURITY_ATTRIBUTES); BOOL CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR*, BOOL, HANDLE, PGENERIC_MAPPING); BOOL CreateProcessAsUserA(HANDLE, LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, PVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION); BOOL CreateProcessAsUserW(HANDLE, LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, PVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION); HANDLE CreateRemoteThread(HANDLE, LPSECURITY_ATTRIBUTES, DWORD, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); DWORD CreateTapePartition(HANDLE, DWORD, DWORD, DWORD); BOOL DefineDosDeviceA(DWORD, LPCSTR, LPCSTR); BOOL DefineDosDeviceW(DWORD, LPCWSTR, LPCWSTR); BOOL DeleteAce(PACL, DWORD); BOOL DeregisterEventSource(HANDLE); BOOL DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR*); BOOL DeviceIoControl(HANDLE, DWORD, PVOID, DWORD, PVOID, DWORD, PDWORD, POVERLAPPED); BOOL DisconnectNamedPipe(HANDLE); BOOL DuplicateToken(HANDLE, SECURITY_IMPERSONATION_LEVEL, PHANDLE); BOOL DuplicateTokenEx(HANDLE, DWORD, LPSECURITY_ATTRIBUTES, SECURITY_IMPERSONATION_LEVEL, TOKEN_TYPE, PHANDLE); BOOL EqualPrefixSid(PSID, PSID); BOOL EqualSid(PSID, PSID); DWORD EraseTape(HANDLE, DWORD, BOOL); HANDLE FindFirstFileExA(LPCSTR, FINDEX_INFO_LEVELS, PVOID, FINDEX_SEARCH_OPS, PVOID, DWORD); HANDLE FindFirstFileExW(LPCWSTR, FINDEX_INFO_LEVELS, PVOID, FINDEX_SEARCH_OPS, PVOID, DWORD); BOOL FindFirstFreeAce(PACL, PVOID*); PVOID FreeSid(PSID); BOOL GetAce(PACL, DWORD, LPVOID*); BOOL GetAclInformation(PACL, PVOID, DWORD, ACL_INFORMATION_CLASS); BOOL GetBinaryTypeA(LPCSTR, PDWORD); BOOL GetBinaryTypeW(LPCWSTR, PDWORD); DWORD GetCompressedFileSizeA(LPCSTR, PDWORD); DWORD GetCompressedFileSizeW(LPCWSTR, PDWORD); BOOL GetCurrentHwProfileA(LPHW_PROFILE_INFOA); BOOL GetCurrentHwProfileW(LPHW_PROFILE_INFOW); BOOL GetFileSecurityA(LPCSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, PDWORD); BOOL GetFileSecurityW(LPCWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, PDWORD); BOOL GetHandleInformation(HANDLE, PDWORD); BOOL GetKernelObjectSecurity(HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, PDWORD); DWORD GetLengthSid(PSID); BOOL GetNumberOfEventLogRecords(HANDLE, PDWORD); BOOL GetOldestEventLogRecord(HANDLE, PDWORD); BOOL GetPrivateObjectSecurity(PSECURITY_DESCRIPTOR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, PDWORD); BOOL GetProcessPriorityBoost(HANDLE, PBOOL); BOOL GetProcessShutdownParameters(PDWORD, PDWORD); BOOL GetProcessTimes(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); HWINSTA GetProcessWindowStation(); BOOL GetProcessWorkingSetSize(HANDLE, PSIZE_T, PSIZE_T); BOOL GetQueuedCompletionStatus(HANDLE, PDWORD, PULONG_PTR, LPOVERLAPPED*, DWORD); BOOL GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR_CONTROL, PDWORD); BOOL GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR, LPBOOL, PACL*, LPBOOL); BOOL GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR, PSID*, LPBOOL); DWORD GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR); BOOL GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR, PSID*, LPBOOL); BOOL GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR, LPBOOL, PACL*, LPBOOL); PSID_IDENTIFIER_AUTHORITY GetSidIdentifierAuthority(PSID); DWORD GetSidLengthRequired(UCHAR); PDWORD GetSidSubAuthority(PSID, DWORD); PUCHAR GetSidSubAuthorityCount(PSID); DWORD GetTapeParameters(HANDLE, DWORD, PDWORD, PVOID); DWORD GetTapePosition(HANDLE, DWORD, PDWORD, PDWORD, PDWORD); DWORD GetTapeStatus(HANDLE); BOOL GetThreadPriorityBoost(HANDLE, PBOOL); BOOL GetThreadTimes(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); BOOL GetTokenInformation(HANDLE, TOKEN_INFORMATION_CLASS, PVOID, DWORD, PDWORD); BOOL ImpersonateLoggedOnUser(HANDLE); BOOL ImpersonateNamedPipeClient(HANDLE); BOOL ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL); BOOL InitializeAcl(PACL, DWORD, DWORD); DWORD SetCriticalSectionSpinCount(LPCRITICAL_SECTION, DWORD); BOOL InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR, DWORD); BOOL InitializeSid(PSID, PSID_IDENTIFIER_AUTHORITY, BYTE); BOOL IsProcessorFeaturePresent(DWORD); BOOL IsTextUnicode(PCVOID, int, LPINT); BOOL IsValidAcl(PACL); BOOL IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR); BOOL IsValidSid(PSID); BOOL LockFileEx(HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED); BOOL LogonUserA(LPSTR, LPSTR, LPSTR, DWORD, DWORD, PHANDLE); BOOL LogonUserW(LPWSTR, LPWSTR, LPWSTR, DWORD, DWORD, PHANDLE); BOOL LookupAccountNameA(LPCSTR, LPCSTR, PSID, PDWORD, LPSTR, PDWORD, PSID_NAME_USE); BOOL LookupAccountNameW(LPCWSTR, LPCWSTR, PSID, PDWORD, LPWSTR, PDWORD, PSID_NAME_USE); BOOL LookupAccountSidA(LPCSTR, PSID, LPSTR, PDWORD, LPSTR, PDWORD, PSID_NAME_USE); BOOL LookupAccountSidW(LPCWSTR, PSID, LPWSTR, PDWORD, LPWSTR, PDWORD, PSID_NAME_USE); BOOL LookupPrivilegeDisplayNameA(LPCSTR, LPCSTR, LPSTR, PDWORD, PDWORD); BOOL LookupPrivilegeDisplayNameW(LPCWSTR, LPCWSTR, LPWSTR, PDWORD, PDWORD); BOOL LookupPrivilegeNameA(LPCSTR, PLUID, LPSTR, PDWORD); BOOL LookupPrivilegeNameW(LPCWSTR, PLUID, LPWSTR, PDWORD); BOOL LookupPrivilegeValueA(LPCSTR, LPCSTR, PLUID); BOOL LookupPrivilegeValueW(LPCWSTR, LPCWSTR, PLUID); BOOL MakeAbsoluteSD(PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR, PDWORD, PACL, PDWORD, PACL, PDWORD, PSID, PDWORD, PSID, PDWORD); BOOL MakeSelfRelativeSD(PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR, PDWORD); VOID MapGenericMask(PDWORD, PGENERIC_MAPPING); BOOL MoveFileExA(LPCSTR, LPCSTR, DWORD); BOOL MoveFileExW(LPCWSTR, LPCWSTR, DWORD); BOOL NotifyChangeEventLog(HANDLE, HANDLE); BOOL ObjectCloseAuditAlarmA(LPCSTR, PVOID, BOOL); BOOL ObjectCloseAuditAlarmW(LPCWSTR, PVOID, BOOL); BOOL ObjectDeleteAuditAlarmA(LPCSTR, PVOID, BOOL); BOOL ObjectDeleteAuditAlarmW(LPCWSTR, PVOID, BOOL); BOOL ObjectOpenAuditAlarmA(LPCSTR, PVOID, LPSTR, LPSTR, PSECURITY_DESCRIPTOR, HANDLE, DWORD, DWORD, PPRIVILEGE_SET, BOOL, BOOL, PBOOL); BOOL ObjectOpenAuditAlarmW(LPCWSTR, PVOID, LPWSTR, LPWSTR, PSECURITY_DESCRIPTOR, HANDLE, DWORD, DWORD, PPRIVILEGE_SET, BOOL, BOOL, PBOOL); BOOL ObjectPrivilegeAuditAlarmA(LPCSTR, PVOID, HANDLE, DWORD, PPRIVILEGE_SET, BOOL); BOOL ObjectPrivilegeAuditAlarmW(LPCWSTR, PVOID, HANDLE, DWORD, PPRIVILEGE_SET, BOOL); HANDLE OpenBackupEventLogA(LPCSTR, LPCSTR); HANDLE OpenBackupEventLogW(LPCWSTR, LPCWSTR); HANDLE OpenEventLogA(LPCSTR, LPCSTR); HANDLE OpenEventLogW(LPCWSTR, LPCWSTR); BOOL OpenProcessToken(HANDLE, DWORD, PHANDLE); BOOL OpenThreadToken(HANDLE, DWORD, BOOL, PHANDLE); BOOL PostQueuedCompletionStatus(HANDLE, DWORD, ULONG_PTR, LPOVERLAPPED); DWORD PrepareTape(HANDLE, DWORD, BOOL); BOOL PrivilegeCheck(HANDLE, PPRIVILEGE_SET, PBOOL); BOOL PrivilegedServiceAuditAlarmA(LPCSTR, LPCSTR, HANDLE, PPRIVILEGE_SET, BOOL); BOOL PrivilegedServiceAuditAlarmW(LPCWSTR, LPCWSTR, HANDLE, PPRIVILEGE_SET, BOOL); BOOL ReadDirectoryChangesW(HANDLE, PVOID, DWORD, BOOL, DWORD, PDWORD, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE); BOOL ReadEventLogA(HANDLE, DWORD, DWORD, PVOID, DWORD, DWORD*, DWORD*); BOOL ReadEventLogW(HANDLE, DWORD, DWORD, PVOID, DWORD, DWORD*, DWORD*); BOOL ReadFileScatter(HANDLE, FILE_SEGMENT_ELEMENT*, DWORD, LPDWORD, LPOVERLAPPED); HANDLE RegisterEventSourceA (LPCSTR, LPCSTR); HANDLE RegisterEventSourceW(LPCWSTR, LPCWSTR); BOOL ReportEventA(HANDLE, WORD, WORD, DWORD, PSID, WORD, DWORD, LPCSTR*, PVOID); BOOL ReportEventW(HANDLE, WORD, WORD, DWORD, PSID, WORD, DWORD, LPCWSTR*, PVOID); BOOL RevertToSelf(); BOOL SetAclInformation(PACL, PVOID, DWORD, ACL_INFORMATION_CLASS); BOOL SetFileSecurityA(LPCSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); BOOL SetFileSecurityW(LPCWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); BOOL SetHandleInformation(HANDLE, DWORD, DWORD); BOOL SetKernelObjectSecurity(HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); BOOL SetPrivateObjectSecurity(SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR*, PGENERIC_MAPPING, HANDLE); BOOL SetProcessAffinityMask(HANDLE, DWORD); BOOL SetProcessPriorityBoost(HANDLE, BOOL); BOOL SetProcessShutdownParameters(DWORD, DWORD); BOOL SetProcessWorkingSetSize(HANDLE, SIZE_T, SIZE_T); BOOL SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR, BOOL, PACL, BOOL); BOOL SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR, PSID, BOOL); BOOL SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR, PSID, BOOL); BOOL SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR, BOOL, PACL, BOOL); BOOL SetSystemTimeAdjustment(DWORD, BOOL); DWORD SetTapeParameters(HANDLE, DWORD, PVOID); DWORD SetTapePosition(HANDLE, DWORD, DWORD, DWORD, DWORD, BOOL); BOOL SetThreadPriorityBoost(HANDLE, BOOL); BOOL SetThreadToken(PHANDLE, HANDLE); BOOL SetTokenInformation(HANDLE, TOKEN_INFORMATION_CLASS, PVOID, DWORD); DWORD SignalObjectAndWait(HANDLE, HANDLE, DWORD, BOOL); BOOL SwitchToThread(); BOOL SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME); BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME); BOOL TryEnterCriticalSection(LPCRITICAL_SECTION); BOOL UnlockFileEx(HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED); BOOL UpdateResourceA(HANDLE, LPCSTR, LPCSTR, WORD, PVOID, DWORD); BOOL UpdateResourceW(HANDLE, LPCWSTR, LPCWSTR, WORD, PVOID, DWORD); BOOL WriteFileGather(HANDLE, FILE_SEGMENT_ELEMENT*, DWORD, LPDWORD, LPOVERLAPPED); DWORD WriteTapemark(HANDLE, DWORD, DWORD, BOOL); static if (_WIN32_WINNT >= 0x500) { BOOL AddAccessAllowedAceEx(PACL, DWORD, DWORD, DWORD, PSID); BOOL AddAccessDeniedAceEx(PACL, DWORD, DWORD, DWORD, PSID); PVOID AddVectoredExceptionHandler(ULONG, PVECTORED_EXCEPTION_HANDLER); BOOL AllocateUserPhysicalPages(HANDLE, PULONG_PTR, PULONG_PTR); BOOL AssignProcessToJobObject(HANDLE, HANDLE); BOOL ChangeTimerQueueTimer(HANDLE,HANDLE,ULONG,ULONG); LPVOID CreateFiberEx(SIZE_T, SIZE_T, DWORD, LPFIBER_START_ROUTINE, LPVOID); HANDLE CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR); HANDLE CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCWSTR); BOOL CreateHardLinkA(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); BOOL CreateHardLinkW(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); HANDLE CreateJobObjectA(LPSECURITY_ATTRIBUTES, LPCSTR); HANDLE CreateJobObjectW(LPSECURITY_ATTRIBUTES, LPCWSTR); BOOL CreateProcessWithLogonW(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPCWSTR, LPWSTR, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION); HANDLE CreateTimerQueue(); BOOL CreateTimerQueueTimer(PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG); BOOL DeleteTimerQueue(HANDLE); BOOL DeleteTimerQueueEx(HANDLE, HANDLE); BOOL DeleteTimerQueueTimer(HANDLE, HANDLE, HANDLE); BOOL DeleteVolumeMountPointA(LPCSTR); BOOL DeleteVolumeMountPointW(LPCWSTR); BOOL DnsHostnameToComputerNameA(LPCSTR, LPSTR, LPDWORD); BOOL DnsHostnameToComputerNameW(LPCWSTR, LPWSTR, LPDWORD); BOOL EncryptFileA(LPCSTR); BOOL EncryptFileW(LPCWSTR); BOOL FileEncryptionStatusA(LPCSTR, LPDWORD); BOOL FileEncryptionStatusW(LPCWSTR, LPDWORD); HANDLE FindFirstVolumeA(LPCSTR, DWORD); HANDLE FindFirstVolumeMountPointA(LPSTR, LPSTR, DWORD); HANDLE FindFirstVolumeMountPointW(LPWSTR, LPWSTR, DWORD); HANDLE FindFirstVolumeW(LPCWSTR, DWORD); BOOL FindNextVolumeA(HANDLE, LPCSTR, DWORD); BOOL FindNextVolumeW(HANDLE, LPWSTR, DWORD); BOOL FindNextVolumeMountPointA(HANDLE, LPSTR, DWORD); BOOL FindNextVolumeMountPointW(HANDLE, LPWSTR, DWORD); BOOL FindVolumeClose(HANDLE); BOOL FindVolumeMountPointClose(HANDLE); BOOL FlushViewOfFile(PCVOID, SIZE_T); BOOL FreeUserPhysicalPages(HANDLE, PULONG_PTR, PULONG_PTR); BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT, LPSTR, LPDWORD); BOOL GetComputerNameExW(COMPUTER_NAME_FORMAT, LPWSTR, LPDWORD); BOOL GetFileSizeEx(HANDLE, PLARGE_INTEGER); BOOL GetModuleHandleExA(DWORD, LPCSTR, HMODULE*); BOOL GetModuleHandleExW(DWORD, LPCWSTR, HMODULE*); HANDLE GetProcessHeap(); DWORD GetProcessHeaps(DWORD, PHANDLE); BOOL GetProcessIoCounters(HANDLE, PIO_COUNTERS); BOOL GetSystemPowerStatus(LPSYSTEM_POWER_STATUS); UINT GetSystemWindowsDirectoryA(LPSTR, UINT); UINT GetSystemWindowsDirectoryW(LPWSTR, UINT); BOOL GetVolumeNameForVolumeMountPointA(LPCSTR, LPSTR, DWORD); BOOL GetVolumeNameForVolumeMountPointW(LPCWSTR, LPWSTR, DWORD); BOOL GetVolumePathNameA(LPCSTR, LPSTR, DWORD); BOOL GetVolumePathNameW(LPCWSTR, LPWSTR, DWORD); BOOL GlobalMemoryStatusEx(LPMEMORYSTATUSEX); BOOL IsBadCodePtr(FARPROC); BOOL IsSystemResumeAutomatic(); BOOL MapUserPhysicalPages(PVOID, ULONG_PTR, PULONG_PTR); BOOL MapUserPhysicalPagesScatter(PVOID*, ULONG_PTR, PULONG_PTR); PVOID MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); PVOID MapViewOfFileEx(HANDLE, DWORD, DWORD, DWORD, SIZE_T, PVOID); HANDLE OpenFileMappingA(DWORD, BOOL, LPCSTR); HANDLE OpenFileMappingW(DWORD, BOOL, LPCWSTR); BOOL ProcessIdToSessionId(DWORD, DWORD*); BOOL QueryInformationJobObject(HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD, LPDWORD); ULONG RemoveVectoredExceptionHandler(PVOID); BOOL ReplaceFileA(LPCSTR, LPCSTR, LPCSTR, DWORD, LPVOID, LPVOID); BOOL ReplaceFileW(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPVOID, LPVOID); BOOL SetComputerNameExA(COMPUTER_NAME_FORMAT, LPCSTR); BOOL SetComputerNameExW(COMPUTER_NAME_FORMAT, LPCWSTR); BOOL SetFilePointerEx(HANDLE, LARGE_INTEGER, PLARGE_INTEGER, DWORD); BOOL SetInformationJobObject(HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD); BOOL SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SECURITY_DESCRIPTOR_CONTROL); BOOL SetSystemPowerState(BOOL, BOOL); EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE); DWORD SetThreadIdealProcessor(HANDLE, DWORD); BOOL SetVolumeMountPointA(LPCSTR, LPCSTR); BOOL SetVolumeMountPointW(LPCWSTR, LPCWSTR); BOOL TerminateJobObject(HANDLE, UINT); BOOL UnmapViewOfFile(PCVOID); BOOL UnregisterWait(HANDLE); BOOL UnregisterWaitEx(HANDLE, HANDLE); BOOL VerifyVersionInfoA(LPOSVERSIONINFOEXA, DWORD, DWORDLONG); BOOL VerifyVersionInfoW(LPOSVERSIONINFOEXW, DWORD, DWORDLONG); } static if (_WIN32_WINNT >= 0x501) { BOOL ActivateActCtx(HANDLE, ULONG_PTR*); void AddRefActCtx(HANDLE); BOOL CheckNameLegalDOS8Dot3A(LPCSTR, LPSTR, DWORD, PBOOL, PBOOL); BOOL CheckNameLegalDOS8Dot3W(LPCWSTR, LPSTR, DWORD, PBOOL, PBOOL); BOOL CheckRemoteDebuggerPresent(HANDLE, PBOOL); BOOL ConvertFiberToThread(); HANDLE CreateActCtxA(PCACTCTXA); HANDLE CreateActCtxW(PCACTCTXW); HANDLE CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE); BOOL DeactivateActCtx(DWORD, ULONG_PTR); BOOL DebugActiveProcessStop(DWORD); BOOL DebugBreakProcess(HANDLE); BOOL DebugSetProcessKillOnExit(BOOL); BOOL FindActCtxSectionGuid(DWORD, const(GUID)*, ULONG, const(GUID)*, PACTCTX_SECTION_KEYED_DATA); BOOL FindActCtxSectionStringA(DWORD, const(GUID)*, ULONG, LPCSTR, PACTCTX_SECTION_KEYED_DATA); BOOL FindActCtxSectionStringW(DWORD, const(GUID)*, ULONG, LPCWSTR, PACTCTX_SECTION_KEYED_DATA); BOOL GetCurrentActCtx(HANDLE*); VOID GetNativeSystemInfo(LPSYSTEM_INFO); BOOL GetProcessHandleCount(HANDLE, PDWORD); BOOL GetSystemRegistryQuota(PDWORD, PDWORD); BOOL GetSystemTimes(LPFILETIME, LPFILETIME, LPFILETIME); UINT GetSystemWow64DirectoryA(LPSTR, UINT); UINT GetSystemWow64DirectoryW(LPWSTR, UINT); BOOL GetThreadIOPendingFlag(HANDLE, PBOOL); BOOL GetVolumePathNamesForVolumeNameA(LPCSTR, LPSTR, DWORD, PDWORD); BOOL GetVolumePathNamesForVolumeNameW(LPCWSTR, LPWSTR, DWORD, PDWORD); UINT GetWriteWatch(DWORD, PVOID, SIZE_T, PVOID*, PULONG_PTR, PULONG); BOOL HeapQueryInformation(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); BOOL HeapSetInformation(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T); BOOL IsProcessInJob(HANDLE, HANDLE, PBOOL); BOOL IsWow64Process(HANDLE, PBOOL); BOOL QueryActCtxW(DWORD, HANDLE, PVOID, ULONG, PVOID, SIZE_T, SIZE_T*); BOOL QueryMemoryResourceNotification(HANDLE, PBOOL); void ReleaseActCtx(HANDLE); UINT ResetWriteWatch(LPVOID, SIZE_T); BOOL SetFileShortNameA(HANDLE, LPCSTR); BOOL SetFileShortNameW(HANDLE, LPCWSTR); BOOL SetFileValidData(HANDLE, LONGLONG); BOOL ZombifyActCtx(HANDLE); } static if (_WIN32_WINNT >= 0x502) { DWORD GetFirmwareEnvironmentVariableA(LPCSTR, LPCSTR, PVOID, DWORD); DWORD GetFirmwareEnvironmentVariableW(LPCWSTR, LPCWSTR, PVOID, DWORD); DWORD GetDllDirectoryA(DWORD, LPSTR); DWORD GetDllDirectoryW(DWORD, LPWSTR); DWORD GetThreadId(HANDLE); DWORD GetProcessId(HANDLE); HANDLE ReOpenFile(HANDLE, DWORD, DWORD, DWORD); BOOL SetDllDirectoryA(LPCSTR); BOOL SetDllDirectoryW(LPCWSTR); BOOL SetFirmwareEnvironmentVariableA(LPCSTR, LPCSTR, PVOID, DWORD); BOOL SetFirmwareEnvironmentVariableW(LPCWSTR, LPCWSTR, PVOID, DWORD); } // ??? static if (_WIN32_WINNT >= 0x510) { VOID RestoreLastError(DWORD); } } // For compatibility with old core.sys.windows.windows: version (LittleEndian) nothrow @nogc { BOOL QueryPerformanceCounter(long* lpPerformanceCount) { return QueryPerformanceCounter(cast(PLARGE_INTEGER)lpPerformanceCount); } BOOL QueryPerformanceFrequency(long* lpFrequency) { return QueryPerformanceFrequency(cast(PLARGE_INTEGER)lpFrequency); } } mixin DECLARE_AW!("STARTUPINFO"); version (Unicode) { //alias STARTUPINFOW STARTUPINFO; alias WIN32_FIND_DATAW WIN32_FIND_DATA; alias ENUMRESLANGPROCW ENUMRESLANGPROC; alias ENUMRESNAMEPROCW ENUMRESNAMEPROC; alias ENUMRESTYPEPROCW ENUMRESTYPEPROC; alias AddAtomW AddAtom; alias BeginUpdateResourceW BeginUpdateResource; alias BuildCommDCBW BuildCommDCB; alias BuildCommDCBAndTimeoutsW BuildCommDCBAndTimeouts; alias CallNamedPipeW CallNamedPipe; alias CommConfigDialogW CommConfigDialog; alias CopyFileW CopyFile; alias CopyFileExW CopyFileEx; alias CreateDirectoryW CreateDirectory; alias CreateDirectoryExW CreateDirectoryEx; alias CreateEventW CreateEvent; alias CreateFileW CreateFile; alias CreateMailslotW CreateMailslot; alias CreateMutexW CreateMutex; alias CreateProcessW CreateProcess; alias CreateSemaphoreW CreateSemaphore; alias DeleteFileW DeleteFile; alias EndUpdateResourceW EndUpdateResource; alias EnumResourceLanguagesW EnumResourceLanguages; alias EnumResourceNamesW EnumResourceNames; alias EnumResourceTypesW EnumResourceTypes; alias ExpandEnvironmentStringsW ExpandEnvironmentStrings; alias FatalAppExitW FatalAppExit; alias FindAtomW FindAtom; alias FindFirstChangeNotificationW FindFirstChangeNotification; alias FindFirstFileW FindFirstFile; alias FindNextFileW FindNextFile; alias FindResourceW FindResource; alias FindResourceExW FindResourceEx; alias FormatMessageW FormatMessage; alias FreeEnvironmentStringsW FreeEnvironmentStrings; alias GetAtomNameW GetAtomName; alias GetCommandLineW GetCommandLine; alias GetComputerNameW GetComputerName; alias GetCurrentDirectoryW GetCurrentDirectory; alias GetDefaultCommConfigW GetDefaultCommConfig; alias GetDiskFreeSpaceW GetDiskFreeSpace; alias GetDiskFreeSpaceExW GetDiskFreeSpaceEx; alias GetDriveTypeW GetDriveType; alias GetEnvironmentStringsW GetEnvironmentStrings; alias GetEnvironmentVariableW GetEnvironmentVariable; alias GetFileAttributesW GetFileAttributes; alias GetFullPathNameW GetFullPathName; alias GetLogicalDriveStringsW GetLogicalDriveStrings; alias GetModuleFileNameW GetModuleFileName; alias GetModuleHandleW GetModuleHandle; alias GetNamedPipeHandleStateW GetNamedPipeHandleState; alias GetPrivateProfileIntW GetPrivateProfileInt; alias GetPrivateProfileSectionW GetPrivateProfileSection; alias GetPrivateProfileSectionNamesW GetPrivateProfileSectionNames; alias GetPrivateProfileStringW GetPrivateProfileString; alias GetPrivateProfileStructW GetPrivateProfileStruct; alias GetProfileIntW GetProfileInt; alias GetProfileSectionW GetProfileSection; alias GetProfileStringW GetProfileString; alias GetShortPathNameW GetShortPathName; alias GetStartupInfoW GetStartupInfo; alias GetSystemDirectoryW GetSystemDirectory; alias GetTempFileNameW GetTempFileName; alias GetTempPathW GetTempPath; alias GetUserNameW GetUserName; alias GetVersionExW GetVersionEx; alias GetVolumeInformationW GetVolumeInformation; alias GetWindowsDirectoryW GetWindowsDirectory; alias GlobalAddAtomW GlobalAddAtom; alias GlobalFindAtomW GlobalFindAtom; alias GlobalGetAtomNameW GlobalGetAtomName; alias IsBadStringPtrW IsBadStringPtr; alias LoadLibraryW LoadLibrary; alias LoadLibraryExW LoadLibraryEx; alias lstrcatW lstrcat; alias lstrcmpW lstrcmp; alias lstrcmpiW lstrcmpi; alias lstrcpyW lstrcpy; alias lstrcpynW lstrcpyn; alias lstrlenW lstrlen; alias MoveFileW MoveFile; alias OpenEventW OpenEvent; alias OpenMutexW OpenMutex; alias OpenSemaphoreW OpenSemaphore; alias OutputDebugStringW OutputDebugString; alias RemoveDirectoryW RemoveDirectory; alias SearchPathW SearchPath; alias SetComputerNameW SetComputerName; alias SetCurrentDirectoryW SetCurrentDirectory; alias SetDefaultCommConfigW SetDefaultCommConfig; alias SetEnvironmentVariableW SetEnvironmentVariable; alias SetFileAttributesW SetFileAttributes; alias SetVolumeLabelW SetVolumeLabel; alias WaitNamedPipeW WaitNamedPipe; alias WritePrivateProfileSectionW WritePrivateProfileSection; alias WritePrivateProfileStringW WritePrivateProfileString; alias WritePrivateProfileStructW WritePrivateProfileStruct; alias WriteProfileSectionW WriteProfileSection; alias WriteProfileStringW WriteProfileString; alias CreateWaitableTimerW CreateWaitableTimer; alias GetFileAttributesExW GetFileAttributesEx; alias GetLongPathNameW GetLongPathName; alias QueryDosDeviceW QueryDosDevice; alias HW_PROFILE_INFOW HW_PROFILE_INFO; alias AccessCheckAndAuditAlarmW AccessCheckAndAuditAlarm; alias BackupEventLogW BackupEventLog; alias ClearEventLogW ClearEventLog; alias CreateNamedPipeW CreateNamedPipe; alias CreateProcessAsUserW CreateProcessAsUser; alias DefineDosDeviceW DefineDosDevice; alias FindFirstFileExW FindFirstFileEx; alias GetBinaryTypeW GetBinaryType; alias GetCompressedFileSizeW GetCompressedFileSize; alias GetFileSecurityW GetFileSecurity; alias LogonUserW LogonUser; alias LookupAccountNameW LookupAccountName; alias LookupAccountSidW LookupAccountSid; alias LookupPrivilegeDisplayNameW LookupPrivilegeDisplayName; alias LookupPrivilegeNameW LookupPrivilegeName; alias LookupPrivilegeValueW LookupPrivilegeValue; alias MoveFileExW MoveFileEx; alias ObjectCloseAuditAlarmW ObjectCloseAuditAlarm; alias ObjectDeleteAuditAlarmW ObjectDeleteAuditAlarm; alias ObjectOpenAuditAlarmW ObjectOpenAuditAlarm; alias ObjectPrivilegeAuditAlarmW ObjectPrivilegeAuditAlarm; alias OpenBackupEventLogW OpenBackupEventLog; alias OpenEventLogW OpenEventLog; alias PrivilegedServiceAuditAlarmW PrivilegedServiceAuditAlarm; alias ReadEventLogW ReadEventLog; alias RegisterEventSourceW RegisterEventSource; alias ReportEventW ReportEvent; alias SetFileSecurityW SetFileSecurity; alias UpdateResourceW UpdateResource; static if (_WIN32_WINNT >= 0x500) { alias CreateFileMappingW CreateFileMapping; alias CreateHardLinkW CreateHardLink; alias CreateJobObjectW CreateJobObject; alias DeleteVolumeMountPointW DeleteVolumeMountPoint; alias DnsHostnameToComputerNameW DnsHostnameToComputerName; alias EncryptFileW EncryptFile; alias FileEncryptionStatusW FileEncryptionStatus; alias FindFirstVolumeW FindFirstVolume; alias FindFirstVolumeMountPointW FindFirstVolumeMountPoint; alias FindNextVolumeW FindNextVolume; alias FindNextVolumeMountPointW FindNextVolumeMountPoint; alias GetModuleHandleExW GetModuleHandleEx; alias GetSystemWindowsDirectoryW GetSystemWindowsDirectory; alias GetVolumeNameForVolumeMountPointW GetVolumeNameForVolumeMountPoint; alias GetVolumePathNameW GetVolumePathName; alias OpenFileMappingW OpenFileMapping; alias ReplaceFileW ReplaceFile; alias SetVolumeMountPointW SetVolumeMountPoint; alias VerifyVersionInfoW VerifyVersionInfo; } static if (_WIN32_WINNT >= 0x501) { alias ACTCTXW ACTCTX; alias CheckNameLegalDOS8Dot3W CheckNameLegalDOS8Dot3; alias CreateActCtxW CreateActCtx; alias FindActCtxSectionStringW FindActCtxSectionString; alias GetSystemWow64DirectoryW GetSystemWow64Directory; alias GetVolumePathNamesForVolumeNameW GetVolumePathNamesForVolumeName; alias SetFileShortNameW SetFileShortName; } static if (_WIN32_WINNT >= 0x502) { alias SetFirmwareEnvironmentVariableW SetFirmwareEnvironmentVariable; alias SetDllDirectoryW SetDllDirectory; alias GetDllDirectoryW GetDllDirectory; } } else { //alias STARTUPINFOA STARTUPINFO; alias WIN32_FIND_DATAA WIN32_FIND_DATA; alias ENUMRESLANGPROCW ENUMRESLANGPROC; alias ENUMRESNAMEPROCW ENUMRESNAMEPROC; alias ENUMRESTYPEPROCW ENUMRESTYPEPROC; alias AddAtomA AddAtom; alias BeginUpdateResourceA BeginUpdateResource; alias BuildCommDCBA BuildCommDCB; alias BuildCommDCBAndTimeoutsA BuildCommDCBAndTimeouts; alias CallNamedPipeA CallNamedPipe; alias CommConfigDialogA CommConfigDialog; alias CopyFileA CopyFile; alias CopyFileExA CopyFileEx; alias CreateDirectoryA CreateDirectory; alias CreateDirectoryExA CreateDirectoryEx; alias CreateEventA CreateEvent; alias CreateFileA CreateFile; alias CreateMailslotA CreateMailslot; alias CreateMutexA CreateMutex; alias CreateProcessA CreateProcess; alias CreateSemaphoreA CreateSemaphore; alias DeleteFileA DeleteFile; alias EndUpdateResourceA EndUpdateResource; alias EnumResourceLanguagesA EnumResourceLanguages; alias EnumResourceNamesA EnumResourceNames; alias EnumResourceTypesA EnumResourceTypes; alias ExpandEnvironmentStringsA ExpandEnvironmentStrings; alias FatalAppExitA FatalAppExit; alias FindAtomA FindAtom; alias FindFirstChangeNotificationA FindFirstChangeNotification; alias FindFirstFileA FindFirstFile; alias FindNextFileA FindNextFile; alias FindResourceA FindResource; alias FindResourceExA FindResourceEx; alias FormatMessageA FormatMessage; alias FreeEnvironmentStringsA FreeEnvironmentStrings; alias GetAtomNameA GetAtomName; alias GetCommandLineA GetCommandLine; alias GetComputerNameA GetComputerName; alias GetCurrentDirectoryA GetCurrentDirectory; alias GetDefaultCommConfigA GetDefaultCommConfig; alias GetDiskFreeSpaceA GetDiskFreeSpace; alias GetDiskFreeSpaceExA GetDiskFreeSpaceEx; alias GetDriveTypeA GetDriveType; alias GetEnvironmentVariableA GetEnvironmentVariable; alias GetFileAttributesA GetFileAttributes; alias GetFullPathNameA GetFullPathName; alias GetLogicalDriveStringsA GetLogicalDriveStrings; alias GetNamedPipeHandleStateA GetNamedPipeHandleState; alias GetModuleHandleA GetModuleHandle; alias GetModuleFileNameA GetModuleFileName; alias GetPrivateProfileIntA GetPrivateProfileInt; alias GetPrivateProfileSectionA GetPrivateProfileSection; alias GetPrivateProfileSectionNamesA GetPrivateProfileSectionNames; alias GetPrivateProfileStringA GetPrivateProfileString; alias GetPrivateProfileStructA GetPrivateProfileStruct; alias GetProfileIntA GetProfileInt; alias GetProfileSectionA GetProfileSection; alias GetProfileStringA GetProfileString; alias GetShortPathNameA GetShortPathName; alias GetStartupInfoA GetStartupInfo; alias GetSystemDirectoryA GetSystemDirectory; alias GetTempFileNameA GetTempFileName; alias GetTempPathA GetTempPath; alias GetUserNameA GetUserName; alias GetVersionExA GetVersionEx; alias GetVolumeInformationA GetVolumeInformation; alias GetWindowsDirectoryA GetWindowsDirectory; alias GlobalAddAtomA GlobalAddAtom; alias GlobalFindAtomA GlobalFindAtom; alias GlobalGetAtomNameA GlobalGetAtomName; alias IsBadStringPtrA IsBadStringPtr; alias LoadLibraryA LoadLibrary; alias LoadLibraryExA LoadLibraryEx; alias lstrcatA lstrcat; alias lstrcmpA lstrcmp; alias lstrcmpiA lstrcmpi; alias lstrcpyA lstrcpy; alias lstrcpynA lstrcpyn; alias lstrlenA lstrlen; alias MoveFileA MoveFile; alias OpenEventA OpenEvent; alias OpenMutexA OpenMutex; alias OpenSemaphoreA OpenSemaphore; alias OutputDebugStringA OutputDebugString; alias RemoveDirectoryA RemoveDirectory; alias SearchPathA SearchPath; alias SetComputerNameA SetComputerName; alias SetCurrentDirectoryA SetCurrentDirectory; alias SetDefaultCommConfigA SetDefaultCommConfig; alias SetEnvironmentVariableA SetEnvironmentVariable; alias SetFileAttributesA SetFileAttributes; alias SetVolumeLabelA SetVolumeLabel; alias WaitNamedPipeA WaitNamedPipe; alias WritePrivateProfileSectionA WritePrivateProfileSection; alias WritePrivateProfileStringA WritePrivateProfileString; alias WritePrivateProfileStructA WritePrivateProfileStruct; alias WriteProfileSectionA WriteProfileSection; alias WriteProfileStringA WriteProfileString; alias CreateWaitableTimerA CreateWaitableTimer; alias GetFileAttributesExA GetFileAttributesEx; alias GetLongPathNameA GetLongPathName; alias QueryDosDeviceA QueryDosDevice; alias HW_PROFILE_INFOA HW_PROFILE_INFO; alias AccessCheckAndAuditAlarmA AccessCheckAndAuditAlarm; alias BackupEventLogA BackupEventLog; alias ClearEventLogA ClearEventLog; alias CreateNamedPipeA CreateNamedPipe; alias CreateProcessAsUserA CreateProcessAsUser; alias DefineDosDeviceA DefineDosDevice; alias FindFirstFileExA FindFirstFileEx; alias GetBinaryTypeA GetBinaryType; alias GetCompressedFileSizeA GetCompressedFileSize; alias GetFileSecurityA GetFileSecurity; alias LogonUserA LogonUser; alias LookupAccountNameA LookupAccountName; alias LookupAccountSidA LookupAccountSid; alias LookupPrivilegeDisplayNameA LookupPrivilegeDisplayName; alias LookupPrivilegeNameA LookupPrivilegeName; alias LookupPrivilegeValueA LookupPrivilegeValue; alias MoveFileExA MoveFileEx; alias ObjectCloseAuditAlarmA ObjectCloseAuditAlarm; alias ObjectDeleteAuditAlarmA ObjectDeleteAuditAlarm; alias ObjectOpenAuditAlarmA ObjectOpenAuditAlarm; alias ObjectPrivilegeAuditAlarmA ObjectPrivilegeAuditAlarm; alias OpenBackupEventLogA OpenBackupEventLog; alias OpenEventLogA OpenEventLog; alias PrivilegedServiceAuditAlarmA PrivilegedServiceAuditAlarm; alias ReadEventLogA ReadEventLog; alias RegisterEventSourceA RegisterEventSource; alias ReportEventA ReportEvent; alias SetFileSecurityA SetFileSecurity; alias UpdateResourceA UpdateResource; static if (_WIN32_WINNT >= 0x500) { alias CreateFileMappingA CreateFileMapping; alias CreateHardLinkA CreateHardLink; alias CreateJobObjectA CreateJobObject; alias DeleteVolumeMountPointA DeleteVolumeMountPoint; alias DnsHostnameToComputerNameA DnsHostnameToComputerName; alias EncryptFileA EncryptFile; alias FileEncryptionStatusA FileEncryptionStatus; alias FindFirstVolumeA FindFirstVolume; alias FindFirstVolumeMountPointA FindFirstVolumeMountPoint; alias FindNextVolumeA FindNextVolume; alias FindNextVolumeMountPointA FindNextVolumeMountPoint; alias GetModuleHandleExA GetModuleHandleEx; alias GetSystemWindowsDirectoryA GetSystemWindowsDirectory; alias GetVolumeNameForVolumeMountPointA GetVolumeNameForVolumeMountPoint; alias GetVolumePathNameA GetVolumePathName; alias OpenFileMappingA OpenFileMapping; alias ReplaceFileA ReplaceFile; alias SetVolumeMountPointA SetVolumeMountPoint; alias VerifyVersionInfoA VerifyVersionInfo; } static if (_WIN32_WINNT >= 0x501) { alias ACTCTXA ACTCTX; alias CheckNameLegalDOS8Dot3A CheckNameLegalDOS8Dot3; alias CreateActCtxA CreateActCtx; alias FindActCtxSectionStringA FindActCtxSectionString; alias GetSystemWow64DirectoryA GetSystemWow64Directory; alias GetVolumePathNamesForVolumeNameA GetVolumePathNamesForVolumeName; alias SetFileShortNameA SetFileShortName; } static if (_WIN32_WINNT >= 0x502) { alias GetDllDirectoryA GetDllDirectory; alias SetDllDirectoryA SetDllDirectory; alias SetFirmwareEnvironmentVariableA SetFirmwareEnvironmentVariable; } } alias STARTUPINFO* LPSTARTUPINFO; alias WIN32_FIND_DATA* LPWIN32_FIND_DATA; alias HW_PROFILE_INFO* LPHW_PROFILE_INFO; static if (_WIN32_WINNT >= 0x501) { alias ACTCTX* PACTCTX, PCACTCTX; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/cplext.d0000664000175000017500000000076412776214756023165 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_cplext.d) */ module core.sys.windows.cplext; version (Windows): enum : uint { CPLPAGE_MOUSE_BUTTONS = 1, CPLPAGE_MOUSE_PTRMOTION = 2, CPLPAGE_MOUSE_WHEEL = 3, CPLPAGE_KEYBOARD_SPEED = 1, CPLPAGE_DISPLAY_BACKGROUND = 1 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/commctrl.d0000664000175000017500000047276712776214756023526 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.12 * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_commctrl.d) */ module core.sys.windows.commctrl; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "comctl32"); private import core.sys.windows.w32api, core.sys.windows.windef, core.sys.windows.winuser; private import core.sys.windows.winbase; // for SYSTEMTIME private import core.sys.windows.objfwd; // for LPSTREAM import core.sys.windows.prsht; enum COMCTL32_VERSION = 6; const TCHAR[] DRAGLISTMSGSTRING = "commctrl_DragListMsg", HOTKEY_CLASS = "msctls_hotkey32", PROGRESS_CLASS = "msctls_progress32", STATUSCLASSNAME = "msctls_statusbar32", TOOLBARCLASSNAME = "ToolbarWindow32", TOOLTIPS_CLASS = "tooltips_class32", TRACKBAR_CLASS = "msctls_trackbar32", UPDOWN_CLASS = "msctls_updown32", ANIMATE_CLASS = "SysAnimate32", DATETIMEPICK_CLASS = "SysDateTimePick32", MONTHCAL_CLASS = "SysMonthCal32", REBARCLASSNAME = "ReBarWindow32", WC_COMBOBOXEX = "ComboBoxEx32", WC_IPADDRESS = "SysIPAddress32", WC_LISTVIEW = "SysListView32", WC_TABCONTROL = "SysTabControl32", WC_TREEVIEW = "SysTreeView32", WC_HEADER = "SysHeader32", WC_PAGESCROLLER = "SysPager", WC_NATIVEFONTCTL = "NativeFontCtl", WC_BUTTON = "Button", WC_STATIC = "Static", WC_EDIT = "Edit", WC_LISTBOX = "ListBox", WC_COMBOBOX = "ComboBox", WC_SCROLLBAR = "ScrollBar", WC_LINKA = "SysLink"; enum { LVM_FIRST = 0x1000, TV_FIRST = 0x1100, HDM_FIRST = 0x1200 } enum { ACM_OPENA = WM_USER + 100, ACM_PLAY = WM_USER + 101, ACM_STOP = WM_USER + 102, ACM_OPENW = WM_USER + 103, ACM_ISPLAYING = WM_USER + 104 } enum { ACN_START = 1, ACN_STOP } enum { CBEIF_TEXT = 0x00000001, CBEIF_IMAGE = 0x00000002, CBEIF_SELECTEDIMAGE = 0x00000004, CBEIF_OVERLAY = 0x00000008, CBEIF_INDENT = 0x00000010, CBEIF_LPARAM = 0x00000020, CBEIF_DI_SETITEM = 0x10000000 } enum { RBN_FIRST = -831U, RBN_LAST = -859U, MCN_FIRST = -750U, MCN_LAST = -759U, DTN_FIRST = -760U, DTN_LAST = -799U, CBEN_FIRST = -800U, CBEN_LAST = -830U } enum { CBEN_INSERTITEM = CBEN_FIRST - 1, CBEN_DELETEITEM = CBEN_FIRST - 2, CBEN_BEGINEDIT = CBEN_FIRST - 4, CBEN_ENDEDITA = CBEN_FIRST - 5, CBEN_ENDEDITW = CBEN_FIRST - 6 } enum { CBENF_KILLFOCUS = 1, CBENF_RETURN, CBENF_ESCAPE, CBENF_DROPDOWN // = 4 } enum CBEMAXSTRLEN = 260; enum { DL_BEGINDRAG = 1157, DL_CANCELDRAG = 1160, DL_DRAGGING = 1158, DL_DROPPED = 1159, DL_CURSORSET = 0, DL_STOPCURSOR = 1, DL_COPYCURSOR = 2, DL_MOVECURSOR = 3 } enum { CCS_TOP = 1, CCS_NOMOVEY = 2, CCS_BOTTOM = 3, CCS_NORESIZE = 4, CCS_NOPARENTALIGN = 8, CCS_ADJUSTABLE = 32, CCS_NODIVIDER = 64 } static if (_WIN32_IE >= 0x300) { enum { CCS_VERT = 128, CCS_LEFT = 129, CCS_NOMOVEX = 130, CCS_RIGHT = 131 } } enum { ACS_CENTER = 0x0001, ACS_TRANSPARENT = 0x0002, ACS_AUTOPLAY = 0x0004, ACS_TIMER = 0x0008 } enum { PGS_VERT = 0x00000000, PGS_HORZ = 0x00000001, PGS_AUTOSCROLL = 0x00000002, PGS_DRAGNDROP = 0x00000004 } enum CMB_MASKED = 2; enum MINSYSCOMMAND = SC_SIZE; enum { SBT_OWNERDRAW = 0x1000, SBT_NOBORDERS = 256, SBT_POPOUT = 512, SBT_RTLREADING = 1024 } enum { SB_SETTEXTA = WM_USER + 1, SB_SETTEXTW = WM_USER + 11, SB_GETTEXTA = WM_USER + 2, SB_GETTEXTW = WM_USER + 13, SB_GETTEXTLENGTHA = WM_USER + 3, SB_GETTEXTLENGTHW = WM_USER + 12, SB_SETPARTS = WM_USER + 4, SB_GETPARTS = WM_USER + 6, SB_GETBORDERS = WM_USER + 7, SB_SETMINHEIGHT = WM_USER + 8, SB_SIMPLE = WM_USER + 9, SB_GETRECT = WM_USER + 10 } enum { MSGF_COMMCTRL_BEGINDRAG = 0x4200, MSGF_COMMCTRL_SIZEHEADER = 0x4201, MSGF_COMMCTRL_DRAGSELECT = 0x4202, MSGF_COMMCTRL_TOOLBARCUST = 0x4203 } enum { ILC_COLOR = 0, ILC_COLOR4 = 4, ILC_COLOR8 = 8, ILC_COLOR16 = 16, ILC_COLOR24 = 24, ILC_COLOR32 = 32, ILC_COLORDDB = 254, ILC_MASK = 1, ILC_PALETTE = 2048 } enum { ILCF_MOVE, ILCF_SWAP } enum { ILS_NORMAL = 0, ILS_GLOW = 1, ILS_SHADOW = 2, ILS_SATURATE = 4, ILS_ALPHA = 8, ILD_BLEND25 = 2, ILD_BLEND50 = 4, ILD_SELECTED = 4, ILD_BLEND = 4, ILD_FOCUS = 2, ILD_MASK = 16, ILD_NORMAL = 0, ILD_TRANSPARENT = 1, ILD_IMAGE = 0x0020, ILD_ROP = 0x0040, ILD_OVERLAYMASK = 0x0F00, ILD_PRESERVEALPHA = 0x1000, ILD_SCALE = 0x2000, ILD_DPISCALE = 0x4000 } enum { HDS_HORZ = 0, HDS_BUTTONS = 2, HDS_HIDDEN = 8 } static if (_WIN32_IE >= 0x400) { enum { HDS_HOTTRACK = 4, HDS_DRAGDROP = 0x0040, HDS_FULLDRAG = 0x0080 } } static if (_WIN32_IE >= 0x500) { enum { HDS_FILTERBAR = 0x0100 } } enum { NM_FIRST = 0, NM_LAST = -99U, LVN_FIRST = -100U, LVN_LAST = -199U, HDN_FIRST = -300U, HDN_LAST = -399U, TVN_FIRST = -400U, TVN_LAST = -499U, TTN_FIRST = -520U, TTN_LAST = -549U, TCN_FIRST = -550U, TCN_LAST = -580U, CDN_FIRST = -601U, /* also in commdlg.h */ CDN_LAST = -699U, TBN_FIRST = -700U, TBN_LAST = -720U, UDN_FIRST = -721U, UDN_LAST = -740U } /*static if (_WIN32_IE >= 0x300) { enum { RBN_FIRST = -831U, RBN_LAST = -859U, MCN_FIRST = -750U, MCN_LAST = -759U, DTN_FIRST = -760U, DTN_LAST = -799U, CBEN_FIRST = -800U, CBEN_LAST = -830U } }*/ static if (_WIN32_IE >= 0x400) { enum { IPN_FIRST = -860U, IPN_LAST = -879U, IPN_FIELDCHANGED = IPN_FIRST, SBN_FIRST = -880U, SBN_LAST = -899U, PGN_FIRST = -900U, PGN_LAST = -950U, PGN_SCROLL = PGN_FIRST-1, PGN_CALCSIZE = PGN_FIRST-2 } } static if (_WIN32_IE >= 0x500) { enum { WMN_FIRST = -1000U, WMN_LAST = -1200U, } } static if (_WIN32_WINNT >= 0x501) { enum { BCN_FIRST = -1250U, BCN_LAST = -1350U, } } static if (_WIN32_WINNT >= 0x600) { enum { TRBN_FIRST = -1501U, TRBN_LAST = -1519U, } } enum { HDI_WIDTH = 1, HDI_HEIGHT = 1, HDI_TEXT = 2, HDI_FORMAT = 4, HDI_LPARAM = 8, HDI_BITMAP = 16 } static if (_WIN32_IE >= 0x300) { enum { HDI_IMAGE = 32, HDI_DI_SETITEM = 64, HDI_ORDER = 128 } } static if (_WIN32_IE >= 0x500) { enum { HDI_FILTER = 256 } } enum { CBES_EX_NOEDITIMAGE = 0x00000001, CBES_EX_NOEDITIMAGEINDENT = 0x00000002, CBES_EX_PATHWORDBREAKPROC = 0x00000004 } static if (_WIN32_IE >= 0x400) { enum { CBES_EX_NOSIZELIMIT = 0x00000008, CBES_EX_CASESENSITIVE = 0x00000010, CBEN_GETDISPINFOA = CBEN_FIRST - 0, CBEN_GETDISPINFOW = CBEN_FIRST - 7, CBEN_DRAGBEGINA = CBEN_FIRST - 8, CBEN_DRAGBEGINW = CBEN_FIRST - 9 } } enum { HDF_LEFT, HDF_RIGHT, HDF_CENTER, HDF_JUSTIFYMASK, HDF_RTLREADING, // = 4 HDF_OWNERDRAW = 0x8000, HDF_STRING = 0x4000, HDF_BITMAP = 0x2000 } static if (_WIN32_IE >= 0x300) { enum { HDF_BITMAP_ON_RIGHT = 0x1000, HDF_IMAGE = 0x0800 } } enum { CCM_FIRST = 0x2000, CCM_LAST = CCM_FIRST + 0x200, CCM_SETBKCOLOR = 8193, CCM_SETCOLORSCHEME = 8194, CCM_GETCOLORSCHEME = 8195, CCM_GETDROPTARGET = 8196, CCM_SETUNICODEFORMAT = 8197, CCM_GETUNICODEFORMAT = 8198, CCM_SETVERSION = 0x2007, CCM_GETVERSION = 0x2008, CCM_SETNOTIFYWINDOW = 0x2009 } enum { HDM_GETITEMCOUNT = HDM_FIRST, HDM_INSERTITEMA = HDM_FIRST + 1, HDM_INSERTITEMW = HDM_FIRST + 10, HDM_DELETEITEM = HDM_FIRST + 2, HDM_GETITEMA = HDM_FIRST + 3, HDM_GETITEMW = HDM_FIRST + 11, HDM_SETITEMA = HDM_FIRST + 4, HDM_SETITEMW = HDM_FIRST + 12, HDM_LAYOUT = HDM_FIRST + 5 } static if (_WIN32_IE >= 0x300) { enum { HDM_GETITEMRECT = HDM_FIRST + 7, HDM_SETIMAGELIST = HDM_FIRST + 8, HDM_GETIMAGELIST = HDM_FIRST + 9, HDM_ORDERTOINDEX = HDM_FIRST + 15, HDM_CREATEDRAGIMAGE = HDM_FIRST + 16, HDM_GETORDERARRAY = HDM_FIRST + 17, HDM_SETORDERARRAY = HDM_FIRST + 18, HDM_SETHOTDIVIDER = HDM_FIRST + 19 } } static if (_WIN32_IE >= 0x400) { enum { HDM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT, HDM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT } } static if (_WIN32_IE >= 0x500) { enum { HDM_SETBITMAPMARGIN = HDM_FIRST + 20, HDM_GETBITMAPMARGIN = HDM_FIRST + 21, HDM_SETFILTERCHANGETIMEOUT = HDM_FIRST + 22, HDM_EDITFILTER = HDM_FIRST + 23, HDM_CLEARFILTER = HDM_FIRST + 24, } } static if (_WIN32_IE >= 0x600) { enum { HDM_GETITEMDROPDOWNRECT = HDM_FIRST + 25, HDM_GETOVERFLOWRECT = HDM_FIRST + 26, HDM_GETFOCUSEDITEM = HDM_FIRST + 27, HDM_SETFOCUSEDITEM = HDM_FIRST + 28, } } enum { HHT_NOWHERE = 1, HHT_ONHEADER = 2, HHT_ONDIVIDER = 4, HHT_ONDIVOPEN = 8, HHT_ABOVE = 256, HHT_BELOW = 512, HHT_TORIGHT = 1024, HHT_TOLEFT = 2048 } enum { HDM_HITTEST = HDM_FIRST + 6 } enum { HDN_ITEMCHANGINGA = HDN_FIRST -0, HDN_ITEMCHANGINGW = HDN_FIRST -20, HDN_ITEMCHANGEDA = HDN_FIRST -1, HDN_ITEMCHANGEDW = HDN_FIRST -21, HDN_ITEMCLICKA = HDN_FIRST -2, HDN_ITEMCLICKW = HDN_FIRST -22, HDN_ITEMDBLCLICKA = HDN_FIRST -3, HDN_ITEMDBLCLICKW = HDN_FIRST -23, HDN_DIVIDERDBLCLICKA = HDN_FIRST -5, HDN_DIVIDERDBLCLICKW = HDN_FIRST -25, HDN_BEGINTRACKA = HDN_FIRST -6, HDN_BEGINTRACKW = HDN_FIRST -26, HDN_ENDTRACKA = HDN_FIRST -7, HDN_ENDTRACKW = HDN_FIRST -27, HDN_TRACKA = HDN_FIRST -8, HDN_TRACKW = HDN_FIRST -28 } static if (_WIN32_IE >= 0x300) { enum { HDN_ENDDRAG = (HDN_FIRST-11), HDN_BEGINDRAG = (HDN_FIRST-10), HDN_GETDISPINFOA = (HDN_FIRST-9), HDN_GETDISPINFOW = (HDN_FIRST-29) } } static if (_WIN32_IE >= 0x400) { enum { HICF_OTHER = 0x00, HICF_MOUSE = 0x01, HICF_ARROWKEYS = 0x02, HICF_ACCELERATOR = 0x04, HICF_DUPACCEL = 0x08, HICF_ENTERING = 0x10, HICF_LEAVING = 0x20, HICF_RESELECT = 0x40, HICF_LMOUSE = 0x80, HICF_TOGGLEDROPDOWN = 0x100 } } enum { IPM_CLEARADDRESS = WM_USER + 100, IPM_SETADDRESS = WM_USER + 101, IPM_GETADDRESS = WM_USER + 102, IPM_SETRANGE = WM_USER + 103, IPM_SETFOCUS = WM_USER + 104, IPM_ISBLANK = WM_USER + 105 } static if (_WIN32_IE >= 0x500) { enum { I_INDENTCALLBACK = -1, I_IMAGENONE = -2 } } enum { TBSTATE_CHECKED = 1, TBSTATE_PRESSED = 2, TBSTATE_ENABLED = 4, TBSTATE_HIDDEN = 8, TBSTATE_INDETERMINATE = 16, TBSTATE_WRAP = 32 } static if (_WIN32_IE >= 0x300) { enum { TBSTATE_ELLIPSES = 0x40 } } static if (_WIN32_IE >= 0x400) { enum { TBSTATE_MARKED = 0x0080 } } enum { TBSTYLE_BUTTON = 0, TBSTYLE_SEP = 1, TBSTYLE_CHECK = 2, TBSTYLE_GROUP = 4, TBSTYLE_CHECKGROUP = TBSTYLE_GROUP | TBSTYLE_CHECK } static if (_WIN32_IE >= 0x300) { enum { TBSTYLE_DROPDOWN = 8 } } static if (_WIN32_IE >= 0x400) { enum { TBSTYLE_AUTOSIZE = 16, TBSTYLE_NOPREFIX = 32 } } enum { TBSTYLE_TOOLTIPS = 256, TBSTYLE_WRAPABLE = 512, TBSTYLE_ALTDRAG = 1024 } static if (_WIN32_IE >= 0x300) { enum { TBSTYLE_FLAT = 2048, TBSTYLE_LIST = 4096, TBSTYLE_CUSTOMERASE = 8192 } } static if (_WIN32_IE >= 0x400) { enum { TBSTYLE_REGISTERDROP = 0x4000, TBSTYLE_TRANSPARENT = 0x8000, TBSTYLE_EX_DRAWDDARROWS = 0x00000001 } } static if (_WIN32_IE >= 0x501) { enum { TBSTYLE_EX_MIXEDBUTTONS = 8, TBSTYLE_EX_HIDECLIPPEDBUTTONS = 16 } } static if (_WIN32_WINNT >= 0x501) { enum { TBSTYLE_EX_DOUBLEBUFFER = 0x80 } } static if (_WIN32_IE >= 0x500) { enum { BTNS_BUTTON = TBSTYLE_BUTTON, BTNS_SEP = TBSTYLE_SEP, BTNS_CHECK = TBSTYLE_CHECK, BTNS_GROUP = TBSTYLE_GROUP, BTNS_CHECKGROUP = TBSTYLE_CHECKGROUP, BTNS_DROPDOWN = TBSTYLE_DROPDOWN, BTNS_AUTOSIZE = TBSTYLE_AUTOSIZE, BTNS_NOPREFIX = TBSTYLE_NOPREFIX, BTNS_WHOLEDROPDOWN = 0x0080 } } static if (_WIN32_IE >= 0x501) { enum { BTNS_SHOWTEXT = 0x0040 } } static if (_WIN32_IE >= 0x400) { enum { TBCDRF_NOEDGES = 0x10000, TBCDRF_HILITEHOTTRACK = 0x20000, TBCDRF_NOOFFSET = 0x40000, TBCDRF_NOMARK = 0x80000, TBCDRF_NOETCHEDEFFECT = 0x100000 } } enum HINST_COMMCTRL = cast(HINSTANCE) (-1); enum { IDB_STD_SMALL_COLOR, IDB_STD_LARGE_COLOR, IDB_VIEW_SMALL_COLOR = 4, IDB_VIEW_LARGE_COLOR = 5 } static if (_WIN32_IE >= 0x300) { enum { IDB_HIST_SMALL_COLOR = 8, IDB_HIST_LARGE_COLOR = 9 } } enum { STD_CUT, STD_COPY, STD_PASTE, STD_UNDO, STD_REDOW, STD_DELETE, STD_FILENEW, STD_FILEOPEN, STD_FILESAVE, STD_PRINTPRE, STD_PROPERTIES, STD_HELP, STD_FIND, STD_REPLACE, STD_PRINT // = 14 } enum { VIEW_LARGEICONS, VIEW_SMALLICONS, VIEW_LIST, VIEW_DETAILS, VIEW_SORTNAME, VIEW_SORTSIZE, VIEW_SORTDATE, VIEW_SORTTYPE, VIEW_PARENTFOLDER, VIEW_NETCONNECT, VIEW_NETDISCONNECT, VIEW_NEWFOLDER // = 11 } enum { TB_ENABLEBUTTON = WM_USER + 1, TB_CHECKBUTTON, TB_PRESSBUTTON, TB_HIDEBUTTON, TB_INDETERMINATE, // = WM_USER + 5, TB_ISBUTTONENABLED = WM_USER + 9, TB_ISBUTTONCHECKED, TB_ISBUTTONPRESSED, TB_ISBUTTONHIDDEN, TB_ISBUTTONINDETERMINATE, // = WM_USER + 13, TB_SETSTATE = WM_USER + 17, TB_GETSTATE = WM_USER + 18, TB_ADDBITMAP = WM_USER + 19, TB_DELETEBUTTON = WM_USER + 22, TB_GETBUTTON, TB_BUTTONCOUNT, TB_COMMANDTOINDEX, TB_SAVERESTOREA, TB_CUSTOMIZE, TB_ADDSTRINGA, TB_GETITEMRECT, TB_BUTTONSTRUCTSIZE, TB_SETBUTTONSIZE, TB_SETBITMAPSIZE, TB_AUTOSIZE, // = WM_USER + 33, TB_GETTOOLTIPS = WM_USER + 35, TB_SETTOOLTIPS = WM_USER + 36, TB_SETPARENT = WM_USER + 37, TB_SETROWS = WM_USER + 39, TB_GETROWS, TB_GETBITMAPFLAGS, TB_SETCMDID, TB_CHANGEBITMAP, TB_GETBITMAP, TB_GETBUTTONTEXTA, TB_REPLACEBITMAP, // = WM_USER + 46, TB_GETBUTTONSIZE = WM_USER + 58, TB_SETBUTTONWIDTH = WM_USER + 59, TB_GETBUTTONTEXTW = WM_USER + 75, TB_SAVERESTOREW = WM_USER + 76, TB_ADDSTRINGW = WM_USER + 77, } static if (_WIN32_IE >= 0x400) { enum { TB_MARKBUTTON = WM_USER + 6 } } static if (_WIN32_IE >= 0x400) { enum { TB_ISBUTTONHIGHLIGHTED = WM_USER + 14 } } static if (_WIN32_IE >= 0x400) { enum { TB_ADDBUTTONSA = WM_USER + 20, TB_INSERTBUTTONA = WM_USER + 21 } } else { enum { TB_ADDBUTTONS = WM_USER + 20, TB_INSERTBUTTON = WM_USER + 21 } } static if (_WIN32_IE >= 0x300) { enum { TB_SETINDENT = WM_USER + 47, TB_SETIMAGELIST, TB_GETIMAGELIST, TB_LOADIMAGES, TB_GETRECT, TB_SETHOTIMAGELIST, TB_GETHOTIMAGELIST, TB_SETDISABLEDIMAGELIST, TB_GETDISABLEDIMAGELIST, TB_SETSTYLE, TB_GETSTYLE, //TB_GETBUTTONSIZE, //TB_SETBUTTONWIDTH, TB_SETMAXTEXTROWS, TB_GETTEXTROWS // = WM_USER + 61 } } static if (_WIN32_IE >= 0x400) { enum { TB_GETOBJECT = WM_USER + 62, TB_GETBUTTONINFOW, TB_SETBUTTONINFOW, TB_GETBUTTONINFOA, TB_SETBUTTONINFOA, TB_INSERTBUTTONW, TB_ADDBUTTONSW, TB_HITTEST, // = WM_USER + 69 TB_SETEXTENDEDSTYLE = WM_USER + 84, TB_GETEXTENDEDSTYLE = WM_USER + 85, TB_SETDRAWTEXTFLAGS = WM_USER + 70, TB_GETHOTITEM, TB_SETHOTITEM, TB_SETANCHORHIGHLIGHT, TB_GETANCHORHIGHLIGHT, // = WM_USER + 74 TB_MAPACCELERATORA = WM_USER + 78, TB_GETINSERTMARK, TB_SETINSERTMARK, TB_INSERTMARKHITTEST, TB_MOVEBUTTON, TB_GETMAXSIZE, //TB_SETEXTENDEDSTYLE, //TB_GETEXTENDEDSTYLE, TB_GETPADDING, TB_SETPADDING, TB_SETINSERTMARKCOLOR, TB_GETINSERTMARKCOLOR, TB_MAPACCELERATORW, TB_GETSTRINGW, TB_GETSTRINGA, // = WM_USER + 92 TB_SETHOTITEM2 = WM_USER + 94, TB_SETLISTGAP = WM_USER + 96, TB_GETIMAGELISTCOUNT = WM_USER + 98, TB_GETIDEALSIZE = WM_USER + 99, //TB_TRANSLATEACCELERATOR = CCM_TRANSLATEACCELERATOR, TB_SETCOLORSCHEME = CCM_SETCOLORSCHEME, TB_GETCOLORSCHEME = CCM_GETCOLORSCHEME, TB_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT, TB_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT } } static if (_WIN32_WINNT >= 0x501) { enum { TB_GETMETRICS = WM_USER + 101, TB_SETMETRICS = WM_USER + 102, } } static if (_WIN32_WINNT >= 0x600) { enum { TB_GETITEMDROPDOWNRECT = WM_USER + 103, TB_SETPRESSEDIMAGELIST = WM_USER + 104, TB_GETPRESSEDIMAGELIST = WM_USER + 105, } } enum TBBF_LARGE = 1; enum { TBN_GETBUTTONINFOA = TBN_FIRST -0, TBN_BEGINDRAG = TBN_FIRST -1, TBN_ENDDRAG = TBN_FIRST -2, TBN_BEGINADJUST = TBN_FIRST -3, TBN_ENDADJUST = TBN_FIRST -4, TBN_RESET = TBN_FIRST -5, TBN_QUERYINSERT = TBN_FIRST -6, TBN_QUERYDELETE = TBN_FIRST -7, TBN_TOOLBARCHANGE = TBN_FIRST -8, TBN_CUSTHELP = TBN_FIRST -9 } static if (_WIN32_IE >= 0x300) { enum { TBN_DROPDOWN = TBN_FIRST - 10 } } static if (_WIN32_IE >= 0x400) { enum { TBN_HOTITEMCHANGE = TBN_FIRST - 13, TBN_DRAGOUT = TBN_FIRST - 14, TBN_DELETINGBUTTON = TBN_FIRST - 15, TBN_GETDISPINFOA = TBN_FIRST - 16, TBN_GETDISPINFOW = TBN_FIRST - 17, TBN_GETINFOTIPA = TBN_FIRST - 18, TBN_GETINFOTIPW = TBN_FIRST - 19, TBN_GETBUTTONINFOW = TBN_FIRST - 20 } } static if (_WIN32_IE >= 0x500) { enum { TBN_RESTORE = TBN_FIRST - 21, TBN_SAVE = TBN_FIRST - 22, TBN_INITCUSTOMIZE = TBN_FIRST - 23 } enum { TBNRF_HIDEHELP = 1, TBNRF_ENDCUSTOMIZE } enum { TBNF_IMAGE = 1, TBNF_TEXT = 2, TBNF_DI_SETITEM = 0x10000000 } } enum { TTS_ALWAYSTIP = 1, TTS_NOPREFIX } static if(_WIN32_IE >= 0x500) { enum { TTS_NOANIMATE = 0x10, TTS_NOFADE = 0x20, TTS_BALLOON = 0x40, TTS_CLOSE = 0x80 } } enum { TTF_IDISHWND = 1, TTF_CENTERTIP = 2, TTF_RTLREADING = 4, TTF_SUBCLASS = 16 } static if (_WIN32_IE >= 0x300) { enum { TTF_TRACK = 0x0020, TTF_ABSOLUTE = 0x0080, TTF_TRANSPARENT = 0x0100, TTF_DI_SETITEM = 0x8000 } static if (_WIN32_IE >= 0x501) { enum { TTF_PARSELINKS = 0x1000 } } enum { TBCD_TICS = 1, TBCD_THUMB, TBCD_CHANNEL // = 3 } } static if (_WIN32_IE >= 0x400) { enum { TBDDRET_DEFAULT, TBDDRET_NODEFAULT, TBDDRET_TREATPRESSED } enum { TBIMHT_AFTER = 1, TBIMHT_BACKGROUND } } enum { TTDT_AUTOMATIC, TTDT_RESHOW, TTDT_AUTOPOP, TTDT_INITIAL } enum { TTM_ACTIVATE = WM_USER + 1, TTM_SETDELAYTIME = WM_USER + 3, TTM_ADDTOOLA, TTM_DELTOOLA, TTM_NEWTOOLRECTA, TTM_RELAYEVENT, TTM_GETTOOLINFOA, TTM_SETTOOLINFOA, TTM_HITTESTA, TTM_GETTEXTA, TTM_UPDATETIPTEXTA, TTM_GETTOOLCOUNT, TTM_ENUMTOOLSA, TTM_GETCURRENTTOOLA, TTM_WINDOWFROMPOINT, // = WM_USER + 16 TTM_ADDTOOLW = WM_USER + 50, TTM_DELTOOLW, TTM_NEWTOOLRECTW, TTM_GETTOOLINFOW, TTM_SETTOOLINFOW, TTM_HITTESTW, TTM_GETTEXTW, TTM_UPDATETIPTEXTW, TTM_ENUMTOOLSW, TTM_GETCURRENTTOOLW // = WM_USER + 59 } static if (_WIN32_IE >= 0x300) { enum { TTM_TRACKACTIVATE = WM_USER + 17, TTM_TRACKPOSITION, TTM_SETTIPBKCOLOR, TTM_SETTIPTEXTCOLOR, TTM_GETDELAYTIME, TTM_GETTIPBKCOLOR, TTM_GETTIPTEXTCOLOR, TTM_SETMAXTIPWIDTH, TTM_GETMAXTIPWIDTH, TTM_SETMARGIN, TTM_GETMARGIN, TTM_POP // = WM_USER + 28 } } static if (_WIN32_IE >= 0x400) { // IE4.0 ??? enum { TTM_UPDATE = WM_USER + 29, TTM_GETBUBBLESIZE, TTM_ADJUSTRECT, TTM_SETTITLEA, TTM_SETTITLEW // = WM_USER + 33 } static if (_WIN32_IE >= 0x500) { alias TTM_SETTITLEW TTM_SETTITLE; } else { alias TTM_SETTITLEA TTM_SETTITLE; } } static if (_WIN32_WINNT >= 0x501) { enum { TTM_POPUP = (WM_USER + 34), TTM_GETTITLE = (WM_USER + 35), } } enum { TTN_GETDISPINFOA = TTN_FIRST - 0, TTN_GETDISPINFOW = TTN_FIRST - 10, TTN_NEEDTEXTA = TTN_GETDISPINFOA, TTN_NEEDTEXTW = TTN_GETDISPINFOW, TTN_SHOW = TTN_FIRST-1, TTN_POP = TTN_FIRST-2 } enum UD_MAXVAL = 0x7fff; enum UD_MINVAL = -UD_MAXVAL; enum { UDN_DELTAPOS = UDN_FIRST-1, UDS_WRAP = 1, UDS_SETBUDDYINT = 2, UDS_ALIGNRIGHT = 4, UDS_ALIGNLEFT = 8, UDS_AUTOBUDDY = 16, UDS_ARROWKEYS = 32, UDS_HORZ = 64, UDS_NOTHOUSANDS = 128 } static if (_WIN32_IE >= 0x300) { enum { UDS_HOTTRACK = 0x0100 } } enum { UDM_SETRANGE = WM_USER + 101, UDM_GETRANGE, UDM_SETPOS, UDM_GETPOS, UDM_SETBUDDY, UDM_GETBUDDY, UDM_SETACCEL, UDM_GETACCEL, UDM_SETBASE, UDM_GETBASE // = WM_USER + 110 } static if (_WIN32_IE >= 0x400) { enum { UDM_SETRANGE32 = WM_USER + 111, UDM_GETRANGE32, UDM_SETPOS32, UDM_GETPOS32 // = WM_USER + 114 } } static if (_WIN32_IE >= 0x500) { enum { UDM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT, UDM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT } } /*enum { SB_SETTEXTA = WM_USER + 1, SB_GETTEXTA, SB_GETTEXTLENGTHA, SB_SETPARTS, // = WM_USER + 4 SB_GETPARTS = WM_USER + 6, SB_GETBORDERS, SB_SETMINHEIGHT, SB_SIMPLE, SB_GETRECT, SB_SETTEXTW, SB_GETTEXTLENGTHW, SB_GETTEXTW // = WM_USER + 13 }*/ /*enum { SBT_OWNERDRAW = 0x1000, SBT_NOBORDERS = 256, SBT_POPOUT = 512, SBT_RTLREADING = 1024 }*/ static if(_WIN32_IE >= 0x400) { enum { SBT_TOOLTIPS = 0x0800, SBN_SIMPLEMODECHANGE = SBN_FIRST } } enum { TBS_AUTOTICKS = 1, TBS_VERT = 2, TBS_HORZ = 0, TBS_TOP = 4, TBS_BOTTOM = 0, TBS_LEFT = 4, TBS_RIGHT = 0, TBS_BOTH = 8, TBS_NOTICKS = 16, TBS_ENABLESELRANGE = 32, TBS_FIXEDLENGTH = 64, TBS_NOTHUMB = 128 } static if (_WIN32_IE >= 0x300) { enum { TBS_TOOLTIPS = 0x0100, TBTS_TOP = 0, TBTS_LEFT, TBTS_BOTTOM, TBTS_RIGHT // = 3 } } static if (_WIN32_IE >= 0x500) { enum { TBS_REVERSED = 0x0200 } } static if (_WIN32_IE >= 0x501) { enum { TBS_DOWNISLEFT = 0x0400 } } static if (_WIN32_IE >= 0x400) { enum { TBIF_BYINDEX = 0x80000000, TBIF_COMMAND = 32, TBIF_IMAGE = 1, TBIF_LPARAM = 16, TBIF_SIZE = 64, TBIF_STATE = 4, TBIF_STYLE = 8, TBIF_TEXT = 2 } } enum { TBM_GETPOS = WM_USER, TBM_GETRANGEMIN, TBM_GETRANGEMAX, TBM_GETTIC, TBM_SETTIC, TBM_SETPOS, TBM_SETRANGE, TBM_SETRANGEMIN, TBM_SETRANGEMAX, TBM_CLEARTICS, TBM_SETSEL, TBM_SETSELSTART, TBM_SETSELEND, // = WM_USER+12, TBM_GETPTICS = WM_USER+14, TBM_GETTICPOS, TBM_GETNUMTICS, TBM_GETSELSTART, TBM_GETSELEND, TBM_CLEARSEL, TBM_SETTICFREQ, TBM_SETPAGESIZE, TBM_GETPAGESIZE, TBM_SETLINESIZE, TBM_GETLINESIZE, TBM_GETTHUMBRECT, TBM_GETCHANNELRECT, TBM_SETTHUMBLENGTH, TBM_GETTHUMBLENGTH, TBM_SETTOOLTIPS, TBM_GETTOOLTIPS, TBM_SETTIPSIDE, TBM_SETBUDDY, TBM_GETBUDDY, // = WM_USER+33, TBM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT, TBM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT } enum { TB_LINEUP, TB_LINEDOWN, TB_PAGEUP, TB_PAGEDOWN, TB_THUMBPOSITION, TB_THUMBTRACK, TB_TOP, TB_BOTTOM, TB_ENDTRACK // = 8 } enum { HOTKEYF_SHIFT = 1, HOTKEYF_CONTROL = 2, HOTKEYF_ALT = 4, HOTKEYF_EXT = 8 } enum { HKCOMB_NONE = 1, HKCOMB_S = 2, HKCOMB_C = 4, HKCOMB_A = 8, HKCOMB_SC = 16, HKCOMB_SA = 32, HKCOMB_CA = 64, HKCOMB_SCA = 128 } enum { HKM_SETHOTKEY = WM_USER + 1, HKM_GETHOTKEY = WM_USER + 2, HKM_SETRULES = WM_USER + 3 } enum { PBM_SETRANGE = WM_USER + 1, PBM_SETPOS, PBM_DELTAPOS, PBM_SETSTEP, PBM_STEPIT, // = WM_USER + 5 PBM_SETRANGE32 = 1030, PBM_GETRANGE, PBM_GETPOS, PBM_SETBARCOLOR, // = 1033 PBM_SETBKCOLOR = CCM_SETBKCOLOR } static if (_WIN32_WINNT >= 0x501) { enum { PBM_SETMARQUEE = WM_USER + 10, } } static if (_WIN32_WINNT >= 0x600) { enum { PBM_GETSTEP = WM_USER + 13, PBM_GETBKCOLOR, PBM_GETBARCOLOR, PBM_SETSTATE, PBM_GETSTATE, } } enum { PBS_SMOOTH = 1, PBS_VERTICAL = 4 } static if (_WIN32_WINNT >= 0x501) { enum { PBS_MARQUEE = 8, } } static if (_WIN32_WINNT >= 0x600) { enum { PBS_SMOOTHREVERSE = 16, } } enum { LVS_ICON, LVS_REPORT, LVS_SMALLICON, LVS_LIST, // = 3 LVS_TYPEMASK = 3, LVS_SINGLESEL = 4, LVS_SHOWSELALWAYS = 8, LVS_SORTASCENDING = 16, LVS_SORTDESCENDING = 32, LVS_SHAREIMAGELISTS = 64, LVS_NOLABELWRAP = 128, LVS_AUTOARRANGE = 256, LVS_EDITLABELS = 512, LVS_NOSCROLL = 0x2000, LVS_TYPESTYLEMASK = 0xFC00, LVS_ALIGNTOP = 0, LVS_ALIGNLEFT = 0x800, LVS_ALIGNMASK = 0xC00, LVS_OWNERDRAWFIXED = 0x400, LVS_NOCOLUMNHEADER = 0x4000, LVS_NOSORTHEADER = 0x8000 } static if (_WIN32_IE >= 0x300) { enum { CDIS_CHECKED = 8, CDIS_DEFAULT = 32, CDIS_DISABLED = 4, CDIS_FOCUS = 16, CDIS_GRAYED = 2, CDIS_HOT = 64, CDIS_SELECTED = 1, CDIS_MARKED = 128, CDIS_INDETERMINATE = 256 } static if (_WIN32_WINNT >= 0x501) { enum { CDIS_SHOWKEYBOARDCUES = 512 } } enum { CDDS_POSTERASE = 4, CDDS_POSTPAINT = 2, CDDS_PREERASE = 3, CDDS_PREPAINT = 1, CDDS_ITEM = 65536, CDDS_ITEMPOSTERASE = 65540, CDDS_ITEMPOSTPAINT = 65538, CDDS_ITEMPREERASE = 65539, CDDS_ITEMPREPAINT = 65537 } static if (_WIN32_IE >= 0x400) { enum { CDDS_SUBITEM = 0x20000 } } enum { CDRF_DODEFAULT = 0x00, CDRF_NOTIFYITEMDRAW = 0x20, CDRF_NOTIFYSUBITEMDRAW = 0x20, CDRF_NOTIFYITEMERASE = 0x80, CDRF_NOTIFYPOSTERASE = 0x40, CDRF_NOTIFYPOSTPAINT = 0x10, CDRF_NEWFONT = 0x02, CDRF_SKIPDEFAULT = 0x04 } static if (_WIN32_IE >= 0x400) { enum { LVBKIF_SOURCE_NONE = 0x00000000, LVBKIF_SOURCE_HBITMAP = 0x00000001, LVBKIF_SOURCE_URL = 0x00000002, LVBKIF_SOURCE_MASK = 0x00000003, LVBKIF_STYLE_NORMAL = 0x00000000, LVBKIF_STYLE_TILE = 0x00000010, LVBKIF_STYLE_MASK = 0x00000010 } } static if (_WIN32_WINNT >= 0x501) { enum { LVBKIF_FLAG_TILEOFFSET = 0x00000100, LVBKIF_TYPE_WATERMARK = 0x10000000 } } enum { LVS_OWNERDATA = 4096 } enum { LVS_EX_CHECKBOXES = 4, LVS_EX_FULLROWSELECT = 32, LVS_EX_GRIDLINES = 1, LVS_EX_HEADERDRAGDROP = 16, LVS_EX_ONECLICKACTIVATE = 64, LVS_EX_SUBITEMIMAGES = 2, LVS_EX_TRACKSELECT = 8, LVS_EX_TWOCLICKACTIVATE = 128 } enum { LVSICF_NOINVALIDATEALL = 0x00000001, LVSICF_NOSCROLL = 0x00000002 } static if(_WIN32_IE >= 0x400) { enum { LVS_EX_FLATSB = 0x00000100, LVS_EX_REGIONAL = 0x00000200, LVS_EX_INFOTIP = 0x00000400, LVS_EX_UNDERLINEHOT = 0x00000800, LVS_EX_UNDERLINECOLD = 0x00001000, LVS_EX_MULTIWORKAREAS = 0x00002000 } } static if(_WIN32_IE >= 0x500) { enum { LVS_EX_LABELTIP = 0x00004000, LVS_EX_BORDERSELECT = 0x00008000 } } } enum { LVSIL_NORMAL, LVSIL_SMALL, LVSIL_STATE } enum { LVM_GETBKCOLOR = LVM_FIRST, LVM_SETBKCOLOR, LVM_GETIMAGELIST, LVM_SETIMAGELIST, LVM_GETITEMCOUNT, // = LVM_FIRST + 4 LVM_SORTITEMSEX = LVM_FIRST + 81, LVM_GETGROUPSTATE = LVM_FIRST + 92, LVM_GETFOCUSEDGROUP, LVM_GETGROUPRECT = LVM_FIRST + 98, LVM_SETVIEW = LVM_FIRST + 142, LVM_GETVIEW, // = LVM_FIRST + 143 LVM_INSERTGROUP = LVM_FIRST + 145, LVM_SETGROUPINFO = LVM_FIRST + 147, LVM_GETGROUPINFO = LVM_FIRST + 149, LVM_REMOVEGROUP, LVM_MOVEGROUP, // = LVM_FIRST + 151 LVM_GETGROUPCOUNT, LVM_GETGROUPINFOBYINDEX, LVM_MOVEITEMTOGROUP, LVM_SETGROUPMETRICS = LVM_FIRST + 155, LVM_GETGROUPMETRICS, LVM_ENABLEGROUPVIEW, LVM_SORTGROUPS, LVM_INSERTGROUPSORTED, LVM_REMOVEALLGROUPS, LVM_HASGROUP, LVM_SETTILEVIEWINFO, LVM_GETTILEVIEWINFO, LVM_SETTILEINFO, LVM_GETTILEINFO, LVM_SETINSERTMARK, LVM_GETINSERTMARK, LVM_INSERTMARKHITTEST, LVM_GETINSERTMARKRECT, LVM_SETINSERTMARKCOLOR, LVM_GETINSERTMARKCOLOR, // = LVM_FIRST + 171 LVM_SETINFOTIP = LVM_FIRST + 173, LVM_GETSELECTEDCOLUMN, LVM_ISGROUPVIEWENABLED, LVM_GETOUTLINECOLOR, LVM_SETOUTLINECOLOR, // = LVM_FIRST + 177 LVM_CANCELEDITLABEL = LVM_FIRST + 179, LVM_MAPINDEXTOID = LVM_FIRST + 180, LVM_MAPIDTOINDEX = LVM_FIRST + 181, LVM_ISITEMVISIBLE = LVM_FIRST + 182, } static if (_WIN32_WINNT >= 0x501) { enum { LVM_SETSELECTEDCOLUMN = LVM_FIRST + 140 } } static if (_WIN32_WINNT >= 0x600) { enum { LVM_GETEMPTYTEXT = LVM_FIRST + 204, LVM_GETFOOTERRECT = LVM_FIRST + 205, LVM_GETFOOTERINFO = LVM_FIRST + 206, LVM_GETFOOTERITEMRECT = LVM_FIRST + 207, LVM_GETFOOTERITEM = (LVM_FIRST + 208), LVM_GETITEMINDEXRECT = (LVM_FIRST + 209), LVM_SETITEMINDEXSTATE = (LVM_FIRST + 210), LVM_GETNEXTITEMINDEX = (LVM_FIRST + 211), } } enum { LVIF_TEXT = 1, LVIF_IMAGE = 2, LVIF_PARAM = 4, LVIF_STATE = 8 } static if (_WIN32_IE >= 0x300) { enum { LVIF_INDENT = 16, LVIF_NORECOMPUTE = 2048 } } static if (_WIN32_WINNT >= 0x501) { enum { LVIF_GROUPID = 128, LVIF_COLUMNS = 256 } } enum { LVIS_FOCUSED = 1, LVIS_SELECTED = 2, LVIS_CUT = 4, LVIS_DROPHILITED = 8, LVIS_OVERLAYMASK = 0xF00, LVIS_STATEIMAGEMASK = 0xF000 } enum LPWSTR LPSTR_TEXTCALLBACKW = cast(LPWSTR) -1; enum LPSTR LPSTR_TEXTCALLBACKA = cast(LPSTR) -1; enum I_IMAGECALLBACK = -1; static if(_WIN32_IE >= 0x400) { enum { LVM_SETBKIMAGEA = LVM_FIRST + 68, LVM_SETBKIMAGEW = LVM_FIRST + 138, LVM_GETBKIMAGEA = LVM_FIRST + 69, LVM_GETBKIMAGEW = LVM_FIRST + 139, LV_MAX_WORKAREAS = 16, LVM_SETWORKAREAS = LVM_FIRST + 65, LVM_GETWORKAREAS = LVM_FIRST + 70, LVM_GETNUMBEROFWORKAREAS = LVM_FIRST + 73, LVM_GETSELECTIONMARK = LVM_FIRST + 66, LVM_SETSELECTIONMARK = LVM_FIRST + 67, LVM_SETHOVERTIME = LVM_FIRST + 71, LVM_GETHOVERTIME = LVM_FIRST + 72, LVM_SETTOOLTIPS = LVM_FIRST + 74, LVM_GETTOOLTIPS = LVM_FIRST + 78, LVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT, LVM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT } } enum { LVNI_ALL, LVNI_FOCUSED = 1, LVNI_SELECTED = 2, LVNI_CUT = 4, LVNI_DROPHILITED = 8, LVNI_ABOVE = 256, LVNI_BELOW = 512, LVNI_TOLEFT = 1024, LVNI_TORIGHT = 2048 } enum { LVM_GETITEMA = LVM_FIRST + 5, LVM_SETITEMA, LVM_INSERTITEMA, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETCALLBACKMASK, LVM_SETCALLBACKMASK, LVM_GETNEXTITEM, LVM_FINDITEMA, LVM_GETITEMRECT, LVM_SETITEMPOSITION, LVM_GETITEMPOSITION, LVM_GETSTRINGWIDTHA, LVM_HITTEST, LVM_ENSUREVISIBLE, LVM_SCROLL, LVM_REDRAWITEMS, LVM_ARRANGE, LVM_EDITLABELA, LVM_GETEDITCONTROL, LVM_GETCOLUMNA, LVM_SETCOLUMNA, LVM_INSERTCOLUMNA, LVM_DELETECOLUMN, LVM_GETCOLUMNWIDTH, LVM_SETCOLUMNWIDTH, // = LVM_FIRST + 30, LVM_CREATEDRAGIMAGE = LVM_FIRST + 33, LVM_GETVIEWRECT, LVM_GETTEXTCOLOR, LVM_SETTEXTCOLOR, LVM_GETTEXTBKCOLOR, LVM_SETTEXTBKCOLOR, LVM_GETTOPINDEX, LVM_GETCOUNTPERPAGE, LVM_GETORIGIN, LVM_UPDATE, LVM_SETITEMSTATE, LVM_GETITEMSTATE, LVM_GETITEMTEXTA, LVM_SETITEMTEXTA, LVM_SETITEMCOUNT, LVM_SORTITEMS, LVM_SETITEMPOSITION32, LVM_GETSELECTEDCOUNT, LVM_GETITEMSPACING, LVM_GETISEARCHSTRINGA, // = LVM_FIRST + 52, LVM_GETITEMW = LVM_FIRST + 75, LVM_SETITEMW = LVM_FIRST + 76, LVM_INSERTITEMW = LVM_FIRST + 77, LVM_FINDITEMW = LVM_FIRST + 83, LVM_GETSTRINGWIDTHW = LVM_FIRST + 87, LVM_GETCOLUMNW = LVM_FIRST + 95, LVM_SETCOLUMNW = LVM_FIRST + 96, LVM_INSERTCOLUMNW = LVM_FIRST + 97, LVM_GETITEMTEXTW = LVM_FIRST + 115, LVM_SETITEMTEXTW, LVM_GETISEARCHSTRINGW, LVM_EDITLABELW // = LVM_FIRST + 118, } static if (_WIN32_IE >= 0x300) { enum { LVM_GETHEADER = LVM_FIRST + 31, LVM_SETICONSPACING = LVM_FIRST + 53, LVM_SETEXTENDEDLISTVIEWSTYLE, LVM_GETEXTENDEDLISTVIEWSTYLE, LVM_GETSUBITEMRECT, LVM_SUBITEMHITTEST, LVM_SETCOLUMNORDERARRAY, LVM_GETCOLUMNORDERARRAY, LVM_SETHOTITEM, LVM_GETHOTITEM, LVM_SETHOTCURSOR, LVM_GETHOTCURSOR, LVM_APPROXIMATEVIEWRECT // = LVM_FIRST + 64, } } enum { LVFI_PARAM = 1, LVFI_STRING = 2, LVFI_PARTIAL = 8, LVFI_WRAP = 32, LVFI_NEARESTXY = 64 } enum { LVIF_DI_SETITEM = 0x1000 } enum { LVIR_BOUNDS, LVIR_ICON, LVIR_LABEL, LVIR_SELECTBOUNDS // = 3 } enum { LVHT_NOWHERE = 1, LVHT_ONITEMICON = 2, LVHT_ONITEMLABEL = 4, LVHT_ONITEMSTATEICON = 8, LVHT_ONITEM = LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON, LVHT_ABOVE = 8, LVHT_BELOW = 16, LVHT_TORIGHT = 32, LVHT_TOLEFT = 64 } enum { LVA_DEFAULT = 0, LVA_ALIGNLEFT = 1, LVA_ALIGNTOP = 2, LVA_SNAPTOGRID = 5 } enum { LVCF_FMT = 1, LVCF_WIDTH = 2, LVCF_TEXT = 4, LVCF_SUBITEM = 8 } static if (_WIN32_IE >= 0x300) { enum { LVCF_IMAGE = 16, LVCF_ORDER = 32 } } enum { LVCFMT_LEFT, LVCFMT_RIGHT, LVCFMT_CENTER, LVCFMT_JUSTIFYMASK // = 3 } static if (_WIN32_IE >= 0x300) { enum { LVCFMT_IMAGE = 2048, LVCFMT_BITMAP_ON_RIGHT = 4096, LVCFMT_COL_HAS_IMAGES = 32768 } } enum { LVSCW_AUTOSIZE = -1, LVSCW_AUTOSIZE_USEHEADER = -2 } enum { LVN_ITEMCHANGING = LVN_FIRST, LVN_ITEMCHANGED = LVN_FIRST - 1, LVN_INSERTITEM = LVN_FIRST - 2, LVN_DELETEITEM = LVN_FIRST - 3, LVN_DELETEALLITEMS = LVN_FIRST - 4, LVN_BEGINLABELEDITA = LVN_FIRST - 5, LVN_ENDLABELEDITA = LVN_FIRST - 6, LVN_COLUMNCLICK = LVN_FIRST - 8, LVN_BEGINDRAG = LVN_FIRST - 9, LVN_BEGINRDRAG = LVN_FIRST - 11, LVN_GETDISPINFOA = LVN_FIRST - 50, LVN_SETDISPINFOA = LVN_FIRST - 51, LVN_KEYDOWN = LVN_FIRST - 55, LVN_BEGINLABELEDITW = LVN_FIRST - 75, LVN_ENDLABELEDITW = LVN_FIRST - 76, LVN_GETDISPINFOW = LVN_FIRST - 77, LVN_SETDISPINFOW = LVN_FIRST - 78 } static if (_WIN32_IE >= 0x400) { enum { LVN_MARQUEEBEGIN = LVN_FIRST - 56, LVN_GETINFOTIPA = LVN_FIRST - 57, LVN_GETINFOTIPW = LVN_FIRST - 58, LVKF_ALT = 1, LVKF_CONTROL = 2, LVKF_SHIFT = 4, LVGIT_UNFOLDED = 1 } } enum { TVS_HASBUTTONS = 1, TVS_HASLINES = 2, TVS_LINESATROOT = 4, TVS_EDITLABELS = 8, TVS_DISABLEDRAGDROP = 16, TVS_SHOWSELALWAYS = 32 } static if (_WIN32_IE >= 0x300) { enum { TVS_RTLREADING = 64, TVS_NOTOOLTIPS = 128, TVS_CHECKBOXES = 256, TVS_TRACKSELECT = 512 } } static if (_WIN32_IE >= 0x400) { enum { TVS_SINGLEEXPAND = 1024, TVS_INFOTIP = 2048, TVS_FULLROWSELECT = 4096, TVS_NOSCROLL = 8192, TVS_NONEVENHEIGHT = 16384 } } static if (_WIN32_IE >= 0x500) { enum { TVS_NOHSCROLL = 0x8000 } } enum { TVIF_TEXT = 1, TVIF_IMAGE = 2, TVIF_PARAM = 4, TVIF_STATE = 8, TVIF_HANDLE = 16, TVIF_SELECTEDIMAGE = 32, TVIF_CHILDREN = 64 } static if (_WIN32_IE >= 0x400) { enum { TVIF_INTEGRAL = 0x0080 } } enum { TVIS_FOCUSED = 1, TVIS_SELECTED = 2, TVIS_CUT = 4, TVIS_DROPHILITED = 8, TVIS_BOLD = 16, TVIS_EXPANDED = 32, TVIS_EXPANDEDONCE = 64, TVIS_OVERLAYMASK = 0xF00, TVIS_STATEIMAGEMASK = 0xF000, TVIS_USERMASK = 0xF000 } enum { I_CHILDRENCALLBACK = -1 } mixin DECLARE_HANDLE!("HTREEITEM"); mixin DECLARE_HANDLE!("HIMAGELIST"); version(Win64) { enum HTREEITEM TVI_ROOT = cast(HTREEITEM) cast(ULONG_PTR)-0x10000, TVI_FIRST = cast(HTREEITEM) cast(ULONG_PTR)-0xffff, TVI_LAST = cast(HTREEITEM) cast(ULONG_PTR)-0xfffe, TVI_SORT = cast(HTREEITEM) cast(ULONG_PTR)-0xfffd; } else { enum HTREEITEM TVI_ROOT = cast(HTREEITEM) 0xFFFF0000, TVI_FIRST = cast(HTREEITEM) 0xFFFF0001, TVI_LAST = cast(HTREEITEM) 0xFFFF0002, TVI_SORT = cast(HTREEITEM) 0xFFFF0003; } enum { TVSIL_NORMAL = 0, TVSIL_STATE = 2 } enum { TVM_INSERTITEMA = TV_FIRST, TVM_DELETEITEM = TV_FIRST + 1, TVM_EXPAND = TV_FIRST + 2, TVM_GETITEMRECT = TV_FIRST + 4, TVM_GETCOUNT, TVM_GETINDENT, TVM_SETINDENT, TVM_GETIMAGELIST, TVM_SETIMAGELIST, TVM_GETNEXTITEM, TVM_SELECTITEM, TVM_GETITEMA, TVM_SETITEMA, TVM_EDITLABELA, TVM_GETEDITCONTROL, TVM_GETVISIBLECOUNT, TVM_HITTEST, TVM_CREATEDRAGIMAGE, TVM_SORTCHILDREN, TVM_ENSUREVISIBLE, TVM_SORTCHILDRENCB, TVM_ENDEDITLABELNOW, TVM_GETISEARCHSTRINGA, // = TV_FIRST + 23 TVM_INSERTITEMW = TV_FIRST + 50, TVM_GETITEMW = TV_FIRST + 62, TVM_SETITEMW = TV_FIRST + 63, TVM_GETISEARCHSTRINGW = TV_FIRST + 64, TVM_EDITLABELW = TV_FIRST + 65 } static if (_WIN32_IE >= 0x300) { enum { TVM_GETTOOLTIPS = TV_FIRST + 25, TVM_SETTOOLTIPS = TV_FIRST + 24 } } static if (_WIN32_IE >= 0x400) { enum { TVM_SETINSERTMARK = TV_FIRST + 26, TVM_SETITEMHEIGHT, TVM_GETITEMHEIGHT, TVM_SETBKCOLOR, TVM_SETTEXTCOLOR, TVM_GETBKCOLOR, TVM_GETTEXTCOLOR, TVM_SETSCROLLTIME, TVM_GETSCROLLTIME, // = TV_FIRST + 34 TVM_SETINSERTMARKCOLOR = TV_FIRST + 37, TVM_GETINSERTMARKCOLOR = TV_FIRST + 38, TVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT, TVM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT } } static if (_WIN32_IE >= 0x500) { enum { TVM_GETITEMSTATE = TV_FIRST + 39, TVM_SETLINECOLOR = TV_FIRST + 40, TVM_GETLINECOLOR = TV_FIRST + 41 } } static if (_WIN32_IE >= 0x501) { enum { TVM_MAPACCIDTOHTREEITEM = TV_FIRST + 42, TVM_MAPHTREEITEMTOACCID = TV_FIRST + 43, TVM_SETEXTENDEDSTYLE = TV_FIRST + 44, TVM_GETEXTENDEDSTYLE = TV_FIRST + 45, TVM_SETAUTOSCROLLINFO = TV_FIRST + 59 } } static if (_WIN32_IE >= 0x600) { enum { TVM_GETSELECTEDCOUNT = TV_FIRST + 70, TVM_SHOWINFOTIP = TV_FIRST + 71, TVM_GETITEMPARTRECT = TV_FIRST + 72, } } enum { TVE_COLLAPSE = 1, TVE_EXPAND = 2, TVE_TOGGLE = 3, TVE_COLLAPSERESET = 0x8000 } static if (_WIN32_IE >= 0x300) { enum { TVE_EXPANDPARTIAL = 0x4000 } } enum { TVC_UNKNOWN, TVC_BYMOUSE, TVC_BYKEYBOARD // = 2 } enum { TVGN_ROOT, TVGN_NEXT, TVGN_PREVIOUS, TVGN_PARENT, TVGN_CHILD, TVGN_FIRSTVISIBLE, TVGN_NEXTVISIBLE, TVGN_PREVIOUSVISIBLE, TVGN_DROPHILITE, TVGN_CARET // = 9 } static if (_WIN32_IE >= 0x400) { enum { TVGN_LASTVISIBLE = 10 } } static if (_WIN32_IE >= 0x600) { enum { TVGN_NEXTSELECTED = 11 } } enum { TVN_SELCHANGINGA = TVN_FIRST - 1, TVN_SELCHANGEDA = TVN_FIRST - 2, TVN_GETDISPINFOA = TVN_FIRST - 3, TVN_SETDISPINFOA = TVN_FIRST - 4, TVN_ITEMEXPANDINGA = TVN_FIRST - 5, TVN_ITEMEXPANDEDA = TVN_FIRST - 6, TVN_BEGINDRAGA = TVN_FIRST - 7, TVN_BEGINRDRAGA = TVN_FIRST - 8, TVN_DELETEITEMA = TVN_FIRST - 9, TVN_BEGINLABELEDITA = TVN_FIRST - 10, TVN_ENDLABELEDITA = TVN_FIRST - 11, TVN_KEYDOWN = TVN_FIRST - 12, TVN_SELCHANGINGW = TVN_FIRST - 50, TVN_SELCHANGEDW = TVN_FIRST - 51, TVN_GETDISPINFOW = TVN_FIRST - 52, TVN_SETDISPINFOW = TVN_FIRST - 53, TVN_ITEMEXPANDINGW = TVN_FIRST - 54, TVN_ITEMEXPANDEDW = TVN_FIRST - 55, TVN_BEGINDRAGW = TVN_FIRST - 56, TVN_BEGINRDRAGW = TVN_FIRST - 57, TVN_DELETEITEMW = TVN_FIRST - 58, TVN_BEGINLABELEDITW = TVN_FIRST - 59, TVN_ENDLABELEDITW = TVN_FIRST - 60 } static if (_WIN32_IE >= 0x400) { enum { TVNRET_DEFAULT = 0, TVNRET_SKIPOLD = 1, TVNRET_SKIPNEW = 2, TVN_GETINFOTIPA = TVN_FIRST - 13, TVN_GETINFOTIPW = TVN_FIRST - 14, TVN_SINGLEEXPAND = TVN_FIRST - 15 } } enum { TVIF_DI_SETITEM = 0x1000 } enum { TVHT_NOWHERE = 1, TVHT_ONITEMICON = 2, TVHT_ONITEMLABEL = 4, TVHT_ONITEMINDENT = 8, TVHT_ONITEMBUTTON = 16, TVHT_ONITEMRIGHT = 32, TVHT_ONITEMSTATEICON = 64, TVHT_ABOVE = 256, TVHT_BELOW = 512, TVHT_TORIGHT = 1024, TVHT_TOLEFT = 2048, TCHT_NOWHERE = 1, TCHT_ONITEMICON = 2, TCHT_ONITEMLABEL = 4, TVHT_ONITEM = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON, TCHT_ONITEM = TCHT_ONITEMICON | TCHT_ONITEMLABEL } enum { TCS_TABS = 0, TCS_RIGHTJUSTIFY = 0, TCS_SINGLELINE = 0, TCS_FORCEICONLEFT = 16, TCS_FORCELABELLEFT = 32, TCS_BUTTONS = 256, TCS_MULTILINE = 512, TCS_FIXEDWIDTH = 1024, TCS_RAGGEDRIGHT = 2048, TCS_FOCUSONBUTTONDOWN = 0x1000, TCS_OWNERDRAWFIXED = 0x2000, TCS_TOOLTIPS = 0x4000, TCS_FOCUSNEVER = 0x8000 } static if (_WIN32_IE >= 0x300) { enum { TCS_BOTTOM = 2, TCS_RIGHT = 2, TCS_VERTICAL = 128, TCS_SCROLLOPPOSITE = 0x0001, TCS_HOTTRACK = 0x0040, TCS_MULTISELECT = 0x0004 } } static if(_WIN32_IE >= 0x400) { enum { TCS_FLATBUTTONS = 0x0008, TCS_EX_FLATSEPARATORS = 0x00000001, TCS_EX_REGISTERDROP = 0x00000002 } } enum { TCIF_TEXT = 1, TCIF_IMAGE = 2, TCIF_RTLREADING = 4, TCIF_PARAM = 8 } static if (_WIN32_IE >= 0x400) { enum { TCIF_STATE = 16 } } enum { TCIS_BUTTONPRESSED = 1 } static if (_WIN32_IE >= 0x400) { enum { TCIS_HIGHLIGHTED = 2 } } enum { TCM_FIRST = 0x1300, TCM_GETIMAGELIST = TCM_FIRST + 2, TCM_SETIMAGELIST, TCM_GETITEMCOUNT, TCM_GETITEMA, TCM_SETITEMA, TCM_INSERTITEMA, TCM_DELETEITEM, TCM_DELETEALLITEMS, TCM_GETITEMRECT, TCM_GETCURSEL, TCM_SETCURSEL, TCM_HITTEST, TCM_SETITEMEXTRA, // = TCM_FIRST + 14 TCM_ADJUSTRECT = TCM_FIRST + 40, TCM_SETITEMSIZE, TCM_REMOVEIMAGE, TCM_SETPADDING, TCM_GETROWCOUNT, TCM_GETTOOLTIPS, TCM_SETTOOLTIPS, TCM_GETCURFOCUS, TCM_SETCURFOCUS, TCM_SETMINTABWIDTH, TCM_DESELECTALL, // = TCM_FIRST + 50 TCM_GETITEMW = TCM_FIRST + 60, TCM_SETITEMW = TCM_FIRST + 61, TCM_INSERTITEMW = TCM_FIRST + 62 } static if (_WIN32_IE >=0x0400) { enum { TCM_HIGHLIGHTITEM = TCM_FIRST + 51, TCM_SETEXTENDEDSTYLE = TCM_FIRST + 52, TCM_GETEXTENDEDSTYLE = TCM_FIRST + 53, TCM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT, TCM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT } } enum { TCN_KEYDOWN = TCN_FIRST, TCN_SELCHANGE = TCN_FIRST - 1, TCN_SELCHANGING = TCN_FIRST - 2 } enum { NM_OUTOFMEMORY = NM_FIRST - 1, NM_CLICK = NM_FIRST - 2, NM_DBLCLK = NM_FIRST - 3, NM_RETURN = NM_FIRST - 4, NM_RCLICK = NM_FIRST - 5, NM_RDBLCLK = NM_FIRST - 6, NM_SETFOCUS = NM_FIRST - 7, NM_KILLFOCUS = NM_FIRST - 8, NM_CUSTOMDRAW = NM_FIRST - 12, NM_HOVER = NM_FIRST - 13, NM_NCHITTEST = NM_FIRST - 14, NM_KEYDOWN = NM_FIRST - 15, NM_RELEASEDCAPTURE = NM_FIRST - 16, NM_SETCURSOR = NM_FIRST - 17, NM_CHAR = NM_FIRST - 18, NM_TOOLTIPSCREATED = NM_FIRST - 19 } enum { SBARS_SIZEGRIP = 256 } /*enum { CCM_FIRST = 0x2000, CCM_LAST = CCM_FIRST + 0x200, CCM_SETBKCOLOR = 8193, CCM_SETCOLORSCHEME = 8194, CCM_GETCOLORSCHEME = 8195, CCM_GETDROPTARGET = 8196, CCM_SETUNICODEFORMAT = 8197, CCM_GETUNICODEFORMAT = 8198, CCM_SETVERSION = 0x2007, CCM_GETVERSION = 0x2008, CCM_SETNOTIFYWINDOW = 0x2009 }*/ static if (_WIN32_WINNT >= 0x501) { enum { CCM_SETWINDOWTHEME = 0x200b, CCM_DPISCALE = 0x200c, RB_GETBANDMARGINS = WM_USER + 40, RB_SETWINDOWTHEME = CCM_SETWINDOWTHEME, TB_SETWINDOWTHEME = CCM_SETWINDOWTHEME, TTM_SETWINDOWTHEME = CCM_SETWINDOWTHEME, } } enum { ICC_LISTVIEW_CLASSES = 1, ICC_TREEVIEW_CLASSES = 2, ICC_BAR_CLASSES = 4, ICC_TAB_CLASSES = 8, ICC_UPDOWN_CLASS = 16, ICC_PROGRESS_CLASS = 32, ICC_HOTKEY_CLASS = 64, ICC_ANIMATE_CLASS = 128, ICC_WIN95_CLASSES = 255, ICC_DATE_CLASSES = 256, ICC_USEREX_CLASSES = 512, ICC_COOL_CLASSES = 1024 } static if (_WIN32_IE >= 0x400) { enum { INFOTIPSIZE = 1024, ICC_INTERNET_CLASSES = 2048, ICC_PAGESCROLLER_CLASS = 4096, ICC_NATIVEFNTCTL_CLASS = 8192 } } static if (_WIN32_WINNT >= 0x501) { enum { ICC_STANDARD_CLASSES = 0x00004000, ICC_LINK_CLASS = 0x00008000 } } enum { GDTR_MIN = 1, GDTR_MAX = 2 } enum { GMR_VISIBLE, GMR_DAYSTATE } enum { GDT_ERROR = -1, GDT_VALID = 0, GDT_NONE = 1 } enum { DTS_SHORTDATEFORMAT = 0, DTS_UPDOWN = 1, DTS_SHOWNONE = 2, DTS_LONGDATEFORMAT = 4, DTS_TIMEFORMAT = 9, DTS_APPCANPARSE = 16, DTS_RIGHTALIGN = 32 } static if (_WIN32_IE >= 0x500) { enum { DTS_SHORTDATECENTURYFORMAT = 0x000C } } enum { MCS_DAYSTATE = 1, MCS_MULTISELECT = 2, MCS_WEEKNUMBERS = 4 } static if (_WIN32_IE >= 0x400) { enum { MCS_NOTODAYCIRCLE = 0x0008, MCS_NOTODAY = 0x0010 } } else { enum { MCS_NOTODAY = 0x0008 } } enum { DTM_FIRST = 0x10000, DTM_GETSYSTEMTIME = 0x1001, DTM_SETSYSTEMTIME = 0x1002, DTM_GETRANGE = 0x1003, DTM_SETRANGE = 0x1004, DTM_SETFORMATA = 0x1005, DTM_SETMCCOLOR = 0x1006, DTM_GETMCCOLOR = 0x1007, DTM_GETMONTHCAL = 0x1008, DTM_SETMCFONT = 0x1009, DTM_GETMCFONT = 0x100a, DTM_SETFORMATW = 0x1050 } static if (_WIN32_WINNT >= 0x600) { enum { DTM_SETMCSTYLE = DTM_FIRST + 11, DTM_GETMCSTYLE, DTM_CLOSEMONTHCAL, DTM_GETDATETIMEPICKERINFO, DTM_GETIDEALSIZE, } } enum { DTN_USERSTRINGA = -758U, DTN_USERSTRINGW = -745U, DTN_WMKEYDOWNA = -757U, DTN_WMKEYDOWNW = -744U, DTN_FORMATA = -756U, DTN_FORMATW = -743U, DTN_FORMATQUERYA = -755U, DTN_FORMATQUERYW = -742U, DTN_DROPDOWN = -754U, DTN_CLOSEUP = -753U, DTN_DATETIMECHANGE = -759U, } enum { MCM_FIRST = 0x1000, MCM_GETCURSEL = 0x1001, MCM_SETCURSEL = 0x1002, MCM_GETMAXSELCOUNT = 0x1003, MCM_SETMAXSELCOUNT = 0x1004, MCM_GETSELRANGE = 0x1005, MCM_SETSELRANGE = 0x1006, MCM_GETMONTHRANGE = 0x1007, MCM_SETDAYSTATE = 0x1008, MCM_GETMINREQRECT = 0x1009, MCM_SETCOLOR = 0x100a, MCM_GETCOLOR = 0x100b, MCM_SETTODAY = 0x100c, MCM_GETTODAY = 0x100d, MCM_HITTEST = 0x100e, MCM_SETFIRSTDAYOFWEEK = 0x100f, MCM_GETFIRSTDAYOFWEEK = 0x1010, MCM_GETRANGE = 0x1011, MCM_SETRANGE = 0x1012, MCM_GETMONTHDELTA = 0x1013, MCM_SETMONTHDELTA = 0x1014, MCM_GETMAXTODAYWIDTH = 0x1015, MCM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT, MCM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT } static if (_WIN32_WINNT >= 0x600) { enum { MCM_GETCURRENTVIEW = MCM_FIRST + 22, MCM_GETCALENDARCOUNT, MCM_GETCALENDARGRIDINFO, MCM_GETCALID = MCM_FIRST + 27, MCM_SETCALID, MCM_SIZERECTTOMIN, MCM_SETCALENDARBORDER, MCM_GETCALENDARBORDER, MCM_SETCURRENTVIEW, } } enum { MCN_SELCHANGE = -749U, MCN_GETDAYSTATE = -747U, MCN_SELECT = -746U } enum { ODT_HEADER = 100, ODT_TAB, ODT_LISTVIEW // = 102 } enum { SB_SETBKCOLOR = 0x2001 } static if (_WIN32_IE >= 0x300) { enum { SB_ISSIMPLE = 1038 } enum { MCSC_BACKGROUND, MCSC_TEXT, MCSC_TITLEBK, MCSC_TITLETEXT, MCSC_MONTHBK, MCSC_TRAILINGTEXT // = 5 } } static if (_WIN32_IE >= 0x400) { enum { MCHT_TITLE = 0x10000, MCHT_CALENDAR = 0x20000, MCHT_TODAYLINK = 0x30000, MCHT_NEXT = 0x1000000, MCHT_PREV = 0x2000000, MCHT_NOWHERE = 0x00, MCHT_TITLEBK = MCHT_TITLE, MCHT_TITLEMONTH = MCHT_TITLE | 0x0001, MCHT_TITLEYEAR = MCHT_TITLE | 0x0002, MCHT_TITLEBTNNEXT = MCHT_TITLE | MCHT_NEXT | 0x0003, MCHT_TITLEBTNPREV = MCHT_TITLE | MCHT_PREV | 0x0003, MCHT_CALENDARBK = MCHT_CALENDAR, MCHT_CALENDARDATE = MCHT_CALENDAR | 0x0001, MCHT_CALENDARDATENEXT = MCHT_CALENDARDATE | MCHT_NEXT, MCHT_CALENDARDATEPREV = MCHT_CALENDARDATE | MCHT_PREV, MCHT_CALENDARDAY = MCHT_CALENDAR | 0x0002, MCHT_CALENDARWEEKNUM = MCHT_CALENDAR | 0x0003 } } enum { RBS_TOOLTIPS = 256, RBS_VARHEIGHT = 512, RBS_BANDBORDERS = 1024, RBS_FIXEDORDER = 2048 } enum { RBIM_IMAGELIST = 1 } enum { RB_SETCOLORSCHEME = CCM_SETCOLORSCHEME, RB_GETCOLORSCHEME = CCM_GETCOLORSCHEME } enum { RBBS_BREAK = 0x0001, RBBS_FIXEDSIZE = 0x0002, RBBS_CHILDEDGE = 0x0004, RBBS_HIDDEN = 0x0008, RBBS_NOVERT = 0x0010, RBBS_FIXEDBMP = 0x0020, RBBS_VARIABLEHEIGHT = 0x0040, RBBS_GRIPPERALWAYS = 0x0080, RBBS_NOGRIPPER = 0x0100 } static if (_WIN32_IE >= 0x500) { enum { RBBS_USECHEVRON = 0x0200 } } static if (_WIN32_IE >= 0x501) { enum { RBBS_HIDETITLE = 0x0400, RBBS_TOPALIGN = 0x0800 } } enum { RBBIM_STYLE = 1, RBBIM_COLORS = 2, RBBIM_TEXT = 4, RBBIM_IMAGE = 8, RBBIM_CHILD = 16, RBBIM_CHILDSIZE = 32, RBBIM_SIZE = 64, RBBIM_BACKGROUND = 128, RBBIM_ID = 256 } enum { RB_INSERTBANDA = WM_USER + 1, RB_DELETEBAND, RB_GETBARINFO, RB_SETBARINFO, // = WM_USER + 4 RB_SETBANDINFOA = WM_USER + 6, RB_SETPARENT = WM_USER + 7, RB_INSERTBANDW = WM_USER + 10, RB_SETBANDINFOW, RB_GETBANDCOUNT, RB_GETROWCOUNT, RB_GETROWHEIGHT // = WM_USER + 14, } enum { RBN_HEIGHTCHANGE = RBN_FIRST } static if (_WIN32_IE >= 0x300) { enum { LVN_ODCACHEHINT = LVN_FIRST - 13, LVN_ODFINDITEMA = LVN_FIRST - 52, LVN_ODFINDITEMW = LVN_FIRST - 79, LVN_ITEMACTIVATE = LVN_FIRST - 14, LVN_ODSTATECHANGED = LVN_FIRST - 15 } version (Unicode) { enum { LVN_ODFINDITEM = LVN_ODFINDITEMW } } else { enum { LVN_ODFINDITEM = LVN_ODFINDITEMA } } } static if (_WIN32_IE >= 0x400) { enum { SB_SETICON = 1039, SB_SETTIPTEXTA, SB_SETTIPTEXTW, SB_GETTIPTEXTA, SB_GETTIPTEXTW, SB_GETICON, // = 1044 SB_SETUNICODEFORMAT = 0x2005, SB_GETUNICODEFORMAT = 0x2006 } enum { PGF_INVISIBLE = 0, PGF_NORMAL = 1, PGF_GRAYED = 2, PGF_DEPRESSED = 4, PGF_HOT = 8 } enum { PGB_TOPORLEFT, PGB_BOTTOMORRIGHT } enum { PGF_SCROLLUP = 1, PGF_SCROLLDOWN = 2, PGF_SCROLLLEFT = 4, PGF_SCROLLRIGHT = 8 } enum { PGK_SHIFT = 1, PGK_CONTROL = 2, PGK_MENU = 4 } enum { PGF_CALCWIDTH = 1, PGF_CALCHEIGHT = 2 } enum { PGM_FIRST = 0x1400, PGM_SETCHILD = PGM_FIRST + 1, PGM_RECALCSIZE, PGM_FORWARDMOUSE, PGM_SETBKCOLOR, PGM_GETBKCOLOR, PGM_SETBORDER, PGM_GETBORDER, PGM_SETPOS, PGM_GETPOS, PGM_SETBUTTONSIZE, PGM_GETBUTTONSIZE, PGM_GETBUTTONSTATE, // = PGM_FIRST + 12 PGM_GETDROPTARGET = CCM_GETDROPTARGET } enum { RBS_REGISTERDROP = 4096, RBS_AUTOSIZE = 8192, RBS_VERTICALGRIPPER = 16384, RBS_DBLCLKTOGGLE = 32768 } enum { RBBIM_IDEALSIZE = 512, RBBIM_LPARAM = 1024, RBBIM_HEADERSIZE = 2048 } enum { RB_HITTEST = WM_USER + 8, RB_GETRECT = WM_USER + 9, RB_IDTOINDEX = WM_USER + 16, RB_GETTOOLTIPS, RB_SETTOOLTIPS, RB_SETBKCOLOR, RB_GETBKCOLOR, RB_SETTEXTCOLOR, RB_GETTEXTCOLOR, RB_SIZETORECT, RB_BEGINDRAG, RB_ENDDRAG, RB_DRAGMOVE, RB_GETBARHEIGHT, RB_GETBANDINFOW, RB_GETBANDINFOA, RB_MINIMIZEBAND, RB_MAXIMIZEBAND, // = WM_USER + 31 RB_GETDROPTARGET = CCM_GETDROPTARGET, RB_GETBANDBORDERS = WM_USER + 34, RB_SHOWBAND = WM_USER + 35, RB_SETPALETTE = WM_USER + 37, RB_GETPALETTE = WM_USER + 38, RB_MOVEBAND = WM_USER + 39, RB_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT, RB_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT } enum { RBN_GETOBJECT = RBN_FIRST - 1, RBN_LAYOUTCHANGED = RBN_FIRST - 2, RBN_AUTOSIZE = RBN_FIRST - 3, RBN_BEGINDRAG = RBN_FIRST - 4, RBN_ENDDRAG = RBN_FIRST - 5, RBN_DELETINGBAND = RBN_FIRST - 6, RBN_DELETEDBAND = RBN_FIRST - 7, RBN_CHILDSIZE = RBN_FIRST - 8 } enum { RBNM_ID = 1, RBNM_STYLE = 2, RBNM_LPARAM = 4 } enum { RBHT_NOWHERE = 1, RBHT_CAPTION, RBHT_CLIENT, RBHT_GRABBER } version (Unicode) { alias SB_SETTIPTEXTW SB_SETTIPTEXT; alias SB_GETTIPTEXTW SB_GETTIPTEXT; alias RB_GETBANDINFOW RB_GETBANDINFO; } else { alias SB_SETTIPTEXTA SB_SETTIPTEXT; alias SB_GETTIPTEXTA SB_GETTIPTEXT; alias RB_GETBANDINFOA RB_GETBANDINFO; } } else { enum { RB_GETBANDINFO = WM_USER + 5 } } static if (_WIN32_IE >= 0x500) { enum { RB_PUSHCHEVRON = WM_USER + 43, } } static if (_WIN32_IE >= 0x600) { enum { RB_SETEXTENDEDSTYLE = WM_USER + 41, RB_GETEXTENDEDSTYLE = WM_USER + 42, } } static if (_WIN32_WINNT >= 0x500) { enum { RB_SETBANDWIDTH = WM_USER + 44, } } static if (_WIN32_WINNT >= 0x501) { enum { ECM_FIRST = 0x1500, BCM_FIRST = 0x1600, BCM_GETIDEALSIZE = BCM_FIRST + 0x0001, BCM_SETIMAGELIST = BCM_FIRST + 0x0002, BCM_GETIMAGELIST = BCM_FIRST + 0x0003, BCM_SETTEXTMARGIN = BCM_FIRST + 0x0004, BCM_GETTEXTMARGIN = BCM_FIRST + 0x0005, BCN_HOTITEMCHANGE = BCN_FIRST + 0x0001, } struct NMBCHOTITEM { NMHDR hdr; DWORD dwFlags; } alias NMBCHOTITEM* LPNMBCHOTITEM; } static if(_WIN32_WINNT >= 0x600) { enum { BST_DROPDOWNPUSHED = 0x0400, BS_SPLITBUTTON = 0x0000_000C, BS_DEFSPLITBUTTON = 0x0000_000D, BS_COMMANDLINK = 0x0000_000E, BS_DEFCOMMANDLINK = 0x0000_000F, BCSIF_GLYPH = 0x0001, BCSIF_IMAGE = 0x0002, BCSIF_STYLE = 0x0004, BCSIF_SIZE = 0x0008, BCSS_NOSPLIT = 0x0001, BCSS_STRETCH = 0x0002, BCSS_ALIGNLEFT = 0x0004, BCSS_IMAGE = 0x0008, BCM_SETDROPDOWNSTATE = BCM_FIRST + 0x0006, BCM_SETSPLITINFO = BCM_FIRST + 0x0007, BCM_GETSPLITINFO = BCM_FIRST + 0x0008, BCM_SETNOTE = BCM_FIRST + 0x0009, BCM_GETNOTE = BCM_FIRST + 0x000A, BCM_GETNOTELENGTH = BCM_FIRST + 0x000B, BCM_SETSHIELD = BCM_FIRST + 0x000C, BCN_DROPDOWN = BCN_FIRST + 0x0002, } enum HIMAGELIST BCCL_NOGLYPH = cast(HIMAGELIST)-1; struct BUTTON_SPLITINFO { UINT mask; HIMAGELIST himlGlyph; UINT uSplitStyle; SIZE size; } alias BUTTON_SPLITINFO* PBUTTON_SPLITINFO; } enum { CBEM_INSERTITEMA = WM_USER + 1, CBEM_SETIMAGELIST, CBEM_GETIMAGELIST, CBEM_GETITEMA, CBEM_SETITEMA, CBEM_GETCOMBOCONTROL, CBEM_GETEDITCONTROL, CBEM_SETEXSTYLE, CBEM_GETEXSTYLE, // = WM_USER + 9) CBEM_DELETEITEM = CB_DELETESTRING } static if (_WIN32_IE >= 0x400) { enum { CBEM_SETEXTENDEDSTYLE = WM_USER + 14, CBEM_GETEXTENDEDSTYLE = WM_USER + 9, CBEM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT, CBEM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT } } enum { CBEM_HASEDITCHANGED = WM_USER + 10, CBEM_INSERTITEMW = WM_USER + 11, CBEM_SETITEMW = WM_USER + 12, CBEM_GETITEMW = WM_USER + 13 } static if (_WIN32_WINNT >= 0x501) { enum { CBEM_SETWINDOWTHEME = CCM_SETWINDOWTHEME } } enum { DA_LAST = 0x7fffffff } enum { DPA_APPEND = 0x7fffffff, DPA_ERR = -1 } enum { DSA_APPEND = 0x7fffffff, DSA_ERR = -1 } enum { DPAS_SORTED = 1, DPAS_INSERTBEFORE = 2, DPAS_INSERTAFTER = 4 } static if (_WIN32_IE >= 0x400) { enum { WSB_PROP_CYVSCROLL = 1, WSB_PROP_CXHSCROLL = 2, WSB_PROP_CYHSCROLL = 4, WSB_PROP_CXVSCROLL = 8, WSB_PROP_CXHTHUMB = 16, WSB_PROP_CYVTHUMB = 32, WSB_PROP_VBKGCOLOR = 64, WSB_PROP_HBKGCOLOR = 128, WSB_PROP_VSTYLE = 256, WSB_PROP_HSTYLE = 512, WSB_PROP_WINSTYLE = 1024, WSB_PROP_PALETTE = 2048, WSB_PROP_MASK = 0xfff, FSB_FLAT_MODE = 2, FSB_ENCARTA_MODE = 1, FSB_REGULAR_MODE = 0 } } static if (_WIN32_WINNT >= 0x501) { enum { LIF_ITEMINDEX = 1, LIF_STATE = 2, LIF_ITEMID = 4, LIF_URL = 8 } enum { LIS_FOCUSED = 1, LIS_ENABLED = 2, LIS_VISITED = 4 } enum { LM_HITTEST = WM_USER + 768, LM_GETIDEALHEIGHT, LM_SETITEM, LM_GETITEM, // = WM_USER + 771 LM_GETIDEALSIZE = LM_GETIDEALHEIGHT, } enum size_t MAX_LINKID_TEXT = 48; enum size_t L_MAX_URL_LENGTH = 2084; } struct TBMETRICS { UINT cbSize = TBMETRICS.sizeof; DWORD dwMask; int cxPad; int cyPad; int cxBarPad; int cyBarPad; int cxButtonSpacing; int cyButtonSpacing; } alias TBMETRICS* LPTBMETRICS; static if (_WIN32_WINNT >= 0x501) { struct TTGETTITLE { DWORD dwSize = TTGETTITLE.sizeof; UINT uTitleBitmap; UINT cch; WCHAR* pszTitle; } alias TTGETTITLE* PTTGETTITLE; } static if (_WIN32_WINNT >= 0x600) { struct MCGRIDINFO { UINT cbSize; DWORD dwPart; DWORD dwFlags; int iCalendar; int iRow; int iCol; BOOL bSelected; SYSTEMTIME stStart; SYSTEMTIME stEnd; RECT rc; PWSTR pszName; size_t cchName; } alias MCGRIDINFO* PMCGRIDINFO; struct DATETIMEPICKERINFO { DWORD cbSize; RECT rcCheck; DWORD stateCheck; RECT rcButton; DWORD stateButton; HWND hwndEdit; HWND hwndUD; HWND hwndDropDown; } alias DATETIMEPICKERINFO* LPDATETIMEPICKERINFO; } struct COMBOBOXEXITEMA { UINT mask; INT_PTR iItem; LPSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int iOverlay; int iIndent; LPARAM lParam; } alias COMBOBOXEXITEMA* PCOMBOBOXEXITEMA; alias const(COMBOBOXEXITEMA)* PCCOMBOEXITEMA; struct COMBOBOXEXITEMW { UINT mask; INT_PTR iItem; LPWSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int iOverlay; int iIndent; LPARAM lParam; } alias COMBOBOXEXITEMW* PCOMBOBOXEXITEMW; alias const(COMBOBOXEXITEMW)* PCCOMBOEXITEMW; static if (_WIN32_IE >= 0x400) { struct NMCOMBOBOXEXA { NMHDR hdr; COMBOBOXEXITEMA ceItem; } alias NMCOMBOBOXEXA* PNMCOMBOBOXEXA; struct NMCOMBOBOXEXW { NMHDR hdr; COMBOBOXEXITEMW ceItem; } alias NMCOMBOBOXEXW* PNMCOMBOBOXEXW; struct NMCBEDRAGBEGINW { NMHDR hdr; int iItemid; WCHAR[CBEMAXSTRLEN] szText; } alias NMCBEDRAGBEGINW* LPNMCBEDRAGBEGINW, PNMCBEDRAGBEGINW; struct NMCBEDRAGBEGINA { NMHDR hdr; int iItemid; char[CBEMAXSTRLEN] szText; } alias NMCBEDRAGBEGINA* LPNMCBEDRAGBEGINA, PNMCBEDRAGBEGINA; struct NMIPADDRESS { NMHDR hdr; int iField; int iValue; } alias NMIPADDRESS* LPNMIPADDRESS; struct NMLVKEYDOWN { NMHDR hdr; WORD wVKey; UINT flags; } alias NMLVKEYDOWN* LPNMLVKEYDOWN; struct NMPGCALCSIZE { NMHDR hdr; DWORD dwFlag; int iWidth; int iHeight; } alias NMPGCALCSIZE* LPNMPGCALCSIZE; struct NMPGSCROLL { NMHDR hdr; BOOL fwKeys; RECT rcParent; int iDir; int iXpos; int iYpos; int iScroll; } alias NMPGSCROLL* LPNMPGSCROLL; struct NMSELCHANGE { NMHDR nmhdr; SYSTEMTIME stSelStart; SYSTEMTIME stSelEnd; } alias NMSELCHANGE* LPNMSELCHANGE; struct NMTBHOTITEM { NMHDR hdr; int idOld; int idNew; DWORD dwFlags; } alias NMTBHOTITEM* LPNMTBHOTITEM; struct NMTBDISPINFOA { NMHDR hdr; DWORD dwMask; int idCommand; DWORD_PTR lParam; int iImage; LPSTR pszText; int cchText; } alias NMTBDISPINFOA* LPNMTBDISPINFOA; struct NMTBDISPINFOW { NMHDR hdr; DWORD dwMask; int idCommand; DWORD_PTR lParam; int iImage; LPWSTR pszText; int cchText; } alias NMTBDISPINFOW* LPNMTBDISPINFOW; struct NMTBGETINFOTIPA { NMHDR hdr; LPSTR pszText; int cchTextMax; int iItem; LPARAM lParam; } alias NMTBGETINFOTIPA* LPNMTBGETINFOTIPA; struct NMTBGETINFOTIPW { NMHDR hdr; LPWSTR pszText; int cchTextMax; int iItem; LPARAM lParam; } alias NMTBGETINFOTIPW* LPNMTBGETINFOTIPW; struct NMMOUSE { NMHDR hdr; DWORD_PTR dwItemSpec; DWORD_PTR dwItemData; POINT pt; LPARAM dwHitInfo; } alias NMMOUSE* LPNMMOUSE; } static if (_WIN32_IE >= 0x401) { struct NMTOOLTIPSCREATED { NMHDR hdr; HWND hwndToolTips; } alias NMTOOLTIPSCREATED* LPNMTOOLTIPSCREATED; } struct NMDATETIMECHANGE { NMHDR nmhdr; DWORD dwFlags; SYSTEMTIME st; } alias NMDATETIMECHANGE* LPNMDATETIMECHANGE; struct NMCBEENDEDITW { NMHDR hdr; BOOL fChanged; int iNewSelection; WCHAR[CBEMAXSTRLEN] szText; int iWhy; } alias NMCBEENDEDITW* LPNMCBEENDEDITW, PNMCBEENDEDITW; struct NMCBEENDEDITA { NMHDR hdr; BOOL fChanged; int iNewSelection; char[CBEMAXSTRLEN] szText; int iWhy; } alias NMCBEENDEDITA* LPNMCBEENDEDITA, PNMCBEENDEDITA; struct COLORMAP { COLORREF from; COLORREF to; } alias COLORMAP* LPCOLORMAP; struct DRAGLISTINFO { UINT uNotification; HWND hWnd; POINT ptCursor; } alias DRAGLISTINFO* LPDRAGLISTINFO; struct TBBUTTON { int iBitmap; int idCommand; BYTE fsState; BYTE fsStyle; version(Win64){ BYTE[6] bReserved; } else { BYTE[2] bReserved; } DWORD_PTR dwData; INT_PTR iString; } alias TBBUTTON* PTBBUTTON, LPTBBUTTON; alias const(TBBUTTON)* LPCTBBUTTON; static if (_WIN32_IE >= 0x400) { struct TBBUTTONINFOA { UINT cbSize = TBBUTTONINFOA.sizeof; DWORD dwMask; int idCommand; int iImage; BYTE fsState; BYTE fsStyle; WORD cx; DWORD_PTR lParam; LPSTR pszText; int cchText; } alias TBBUTTONINFOA* LPTBBUTTONINFOA; struct TBBUTTONINFOW { UINT cbSize = TBBUTTONINFOW.sizeof; DWORD dwMask; int idCommand; int iImage; BYTE fsState; BYTE fsStyle; WORD cx; DWORD_PTR lParam; LPWSTR pszText; int cchText; } alias TBBUTTONINFOW* LPTBBUTTONINFOW; struct TBINSERTMARK { int iButton; DWORD dwFlags; } alias TBINSERTMARK* LPTBINSERTMARK; struct LVBKIMAGEA { ULONG ulFlags; HBITMAP hbm; LPSTR pszImage; UINT cchImageMax; int xOffsetPercent; int yOffsetPercent; } alias LVBKIMAGEA* LPLVBKIMAGEA; struct LVBKIMAGEW { ULONG ulFlags; HBITMAP hbm; LPWSTR pszImage; UINT cchImageMax; int xOffsetPercent; int yOffsetPercent; } alias LVBKIMAGEW* LPLVBKIMAGEW; } /*struct TBNOTIFY { NMHDR hdr; int iItem; TBBUTTON tbButton; int cchText; LPTSTR pszText; } alias TBNOTIFY* LPTBNOTIFY; */ /*struct TBSAVEPARAMS { HKEY hkr; LPCTSTR pszSubKey; LPCTSTR pszValueName; }*/ struct IMAGEINFO { HBITMAP hbmImage; HBITMAP hbmMask; int Unused1; int Unused2; RECT rcImage; } alias IMAGEINFO* LPIMAGEINFO; static if (_WIN32_IE >= 0x500) { struct HDITEMA { UINT mask; int cxy; LPSTR pszText; HBITMAP hbm; int cchTextMax; int fmt; LPARAM lParam; int iImage; int iOrder; UINT type; LPVOID pvFilter; } struct HDITEMW { UINT mask; int cxy; LPWSTR pszText; HBITMAP hbm; int cchTextMax; int fmt; LPARAM lParam; int iImage; int iOrder; UINT type; LPVOID pvFilter; } } else static if (_WIN32_IE >= 0x300) { struct HDITEMA { UINT mask; int cxy; LPSTR pszText; HBITMAP hbm; int cchTextMax; int fmt; LPARAM lParam; int iImage; int iOrder; } struct HDITEMW { UINT mask; int cxy; LPWSTR pszText; HBITMAP hbm; int cchTextMax; int fmt; LPARAM lParam; int iImage; int iOrder; } } else { struct HDITEMA { UINT mask; int cxy; LPSTR pszText; HBITMAP hbm; int cchTextMax; int fmt; LPARAM lParam; } struct HDITEMW { UINT mask; int cxy; LPWSTR pszText; HBITMAP hbm; int cchTextMax; int fmt; LPARAM lParam; } } alias HDITEMA* LPHDITEMA; alias HDITEMW* LPHDITEMW; deprecated { alias HDITEMA HD_ITEMA; alias HDITEMW HD_ITEMW; //alias HDITEM HD_ITEM; fixme } struct HD_LAYOUT { RECT* prc; WINDOWPOS* pwpos; } alias HD_LAYOUT* LPHDLAYOUT; deprecated alias HD_LAYOUT HDLAYOUT; struct HD_HITTESTINFO { POINT pt; UINT flags; int iItem; } alias HD_HITTESTINFO* LPHDHITTESTINFO; struct HD_NOTIFYA { NMHDR hdr; int iItem; int iButton; HDITEMA* pitem; } struct HD_NOTIFYW { NMHDR hdr; int iItem; int iButton; HDITEMW* pitem; } /* FIXME: NMHEADER structure (base for all events of the comctl controls) is the same as HD_NOTIFY depending on the value of _WIN32_IE macro. I'm defining both for now. */ struct NMHEADERA { NMHDR hdr; int iItem; int iButton; HDITEMA* pitem; } alias NMHEADERA* LPNMHEADERA; struct NMHEADERW { NMHDR hdr; int iItem; int iButton; HDITEMW* pitem; } alias NMHEADERW* LPNMHEADERW; version (Unicode) { alias NMHEADERW NMHEADER; alias LPNMHEADERW LPNMHEADER; } else { alias NMHEADERA NMHEADER; alias LPNMHEADERA LPNMHEADER; } // End FIXME struct NMHDDISPINFOA { NMHDR hdr; int iItem; UINT mask; LPSTR pszText; int cchTextMax; int iImage; LPARAM lParam; } alias NMHDDISPINFOA* LPNMHDDISPINFOA; struct NMHDDISPINFOW { NMHDR hdr; int iItem; UINT mask; LPWSTR pszText; int cchTextMax; int iImage; LPARAM lParam; } alias NMHDDISPINFOW* LPNMHDDISPINFOW; struct NMCUSTOMDRAW { NMHDR hdr; DWORD dwDrawStage; HDC hdc; RECT rc; DWORD dwItemSpec; UINT uItemState; LPARAM lItemlParam; } alias NMCUSTOMDRAW* LPNMCUSTOMDRAW; static if (_WIN32_IE >= 0x400) { struct NMLVCUSTOMDRAW { NMCUSTOMDRAW nmcd; COLORREF clrText; COLORREF clrTextBk; int iSubItem; } } else { struct NMLVCUSTOMDRAW { NMCUSTOMDRAW nmcd; COLORREF clrText; COLORREF clrTextBk; } } alias NMLVCUSTOMDRAW* LPNMLVCUSTOMDRAW; static if (_WIN32_IE >= 0x400) { struct NMLVGETINFOTIPA { NMHDR hdr; DWORD dwFlags; LPSTR pszText; int cchTextMax; int iItem; int iSubItem; LPARAM lParam; } alias NMLVGETINFOTIPA* LPNMLVGETINFOTIPA; struct NMLVGETINFOTIPW { NMHDR hdr; DWORD dwFlags; LPWSTR pszText; int cchTextMax; int iItem; int iSubItem; LPARAM lParam; } alias NMLVGETINFOTIPW* LPNMLVGETINFOTIPW; } static if (_WIN32_IE >= 0x400) { struct NMTVCUSTOMDRAW { NMCUSTOMDRAW nmcd; COLORREF clrText; COLORREF clrTextBk; int iLevel; } } else { struct NMTVCUSTOMDRAW { NMCUSTOMDRAW nmcd; COLORREF clrText; COLORREF clrTextBk; } } alias NMTVCUSTOMDRAW* LPNMTVCUSTOMDRAW; static if (_WIN32_IE >= 0x400) { static if (_WIN32_WINNT >= 0x501) { struct NMTBCUSTOMDRAW { NMCUSTOMDRAW nmcd; HBRUSH hbrMonoDither; HBRUSH hbrLines; HPEN hpenLines; COLORREF clrText; COLORREF clrMark; COLORREF clrTextHighlight; COLORREF clrBtnFace; COLORREF clrBtnHighlight; COLORREF clrHighlightHotTrack; RECT rcText; int nStringBkMode; int nHLStringBkMode; int iListGap; } } else { struct NMTBCUSTOMDRAW { NMCUSTOMDRAW nmcd; HBRUSH hbrMonoDither; HBRUSH hbrLines; HPEN hpenLines; COLORREF clrText; COLORREF clrMark; COLORREF clrTextHighlight; COLORREF clrBtnFace; COLORREF clrBtnHighlight; COLORREF clrHighlightHotTrack; RECT rcText; int nStringBkMode; int nHLStringBkMode; } } alias NMTBCUSTOMDRAW* LPNMTBCUSTOMDRAW; struct NMITEMACTIVATE { NMHDR hdr; int iItem; int iSubItem; UINT uNewState; UINT uOldState; UINT uChanged; POINT ptAction; LPARAM lParam; UINT uKeyFlags; } alias NMITEMACTIVATE* LPNMITEMACTIVATE; } struct TBADDBITMAP { HINSTANCE hInst; UINT_PTR nID; } alias TBADDBITMAP* LPTBADDBITMAP; struct TBSAVEPARAMSA { HKEY hkr; LPCSTR pszSubKey; LPCSTR pszValueName; } struct TBSAVEPARAMSW { HKEY hkr; LPCWSTR pszSubKey; LPCWSTR pszValueName; } struct TBREPLACEBITMAP { HINSTANCE hInstOld; UINT_PTR nIDOld; HINSTANCE hInstNew; UINT_PTR nIDNew; int nButtons; } alias TBREPLACEBITMAP* LPTBREPLACEBITMAP; static if (_WIN32_IE >= 0x500) { struct NMTOOLBARA { NMHDR hdr; int iItem; TBBUTTON tbButton; int cchText; LPSTR pszText; RECT rcButton; } struct NMTOOLBARW { NMHDR hdr; int iItem; TBBUTTON tbButton; int cchText; LPWSTR pszText; RECT rcButton; } } else { struct NMTOOLBARA { NMHDR hdr; int iItem; TBBUTTON tbButton; int cchText; LPSTR pszText; } struct NMTOOLBARW { NMHDR hdr; int iItem; TBBUTTON tbButton; int cchText; LPWSTR pszText; } } alias NMTOOLBARA* LPNMTOOLBARA; alias NMTOOLBARW* LPNMTOOLBARW; alias NMTOOLBARA TBNOTIFYA; alias LPNMTOOLBARA LPTBNOTIFYA; alias NMTOOLBARW TBNOTIFYW; alias LPNMTOOLBARW LPTBNOTIFYW; static if (_WIN32_WINNT >= 0x501) { struct TOOLINFOA { UINT cbSize = TOOLINFOA.sizeof; UINT uFlags; HWND hwnd; UINT_PTR uId; RECT rect; HINSTANCE hinst; LPSTR lpszText; LPARAM lParam; void* lpReserved; } struct TOOLINFOW { UINT cbSize = TOOLINFOW.sizeof; UINT uFlags; HWND hwnd; UINT_PTR uId; RECT rect; HINSTANCE hinst; LPWSTR lpszText; LPARAM lParam; void* lpReserved; } enum size_t TTTOOLINFOA_V1_SIZE = TOOLINFOA.lParam.offsetof, TTTOOLINFOW_V1_SIZE = TOOLINFOW.lParam.offsetof, TTTOOLINFOA_V2_SIZE = TOOLINFOA.lpReserved.offsetof, TTTOOLINFOW_V2_SIZE = TOOLINFOW.lpReserved.offsetof, TTTOOLINFOA_V3_SIZE = TOOLINFOA.sizeof, TTTOOLINFOW_V3_SIZE = TOOLINFOW.sizeof; } else static if (_WIN32_IE >= 0x300) { struct TOOLINFOA { UINT cbSize = TOOLINFOA.sizeof; UINT uFlags; HWND hwnd; UINT uId; RECT rect; HINSTANCE hinst; LPSTR lpszText; LPARAM lParam; } struct TOOLINFOW { UINT cbSize = TOOLINFOW.sizeof; UINT uFlags; HWND hwnd; UINT uId; RECT rect; HINSTANCE hinst; LPWSTR lpszText; LPARAM lParam; } enum size_t TTTOOLINFOA_V1_SIZE = TOOLINFOA.lParam.offsetof, TTTOOLINFOW_V1_SIZE = TOOLINFOW.lParam.offsetof, TTTOOLINFOA_V2_SIZE = TOOLINFOA.sizeof, TTTOOLINFOW_V2_SIZE = TOOLINFOW.sizeof; } else { struct TOOLINFOA { UINT cbSize = TOOLINFOA.sizeof; UINT uFlags; HWND hwnd; UINT uId; RECT rect; HINSTANCE hinst; LPSTR lpszText; } struct TOOLINFOW { UINT cbSize = TOOLINFOW.sizeof; UINT uFlags; HWND hwnd; UINT uId; RECT rect; HINSTANCE hinst; LPWSTR lpszText; } enum size_t TTTOOLINFOA_V1_SIZE = TOOLINFOA.sizeof, TTTOOLINFOW_V1_SIZE = TOOLINFOW.sizeof; } alias TOOLINFOA TTTOOLINFOA; alias TOOLINFOW TTTOOLINFOW; alias TTTOOLINFOA* LPTTTOOLINFOA, PTOOLINFOA, LPTOOLINFOA; alias TTTOOLINFOW* LPTTTOOLINFOW, PTOOLINFOW, LPTOOLINFOW; struct TTHITTESTINFOA { HWND hwnd; POINT pt; TOOLINFOA ti; } alias TTHITTESTINFOA* LPTTHITTESTINFOA, LPHITTESTINFOA; struct TTHITTESTINFOW { HWND hwnd; POINT pt; TOOLINFOW ti; } alias TTHITTESTINFOW* LPTTHITTESTINFOW, LPHITTESTINFOW; static if (_WIN32_IE >= 0x300) { struct NMTTDISPINFOA { NMHDR hdr; LPSTR lpszText; char[80] szText; HINSTANCE hinst; UINT uFlags; LPARAM lParam; } struct NMTTDISPINFOW { NMHDR hdr; LPWSTR lpszText; WCHAR[80] szText; HINSTANCE hinst; UINT uFlags; LPARAM lParam; } } else { struct NMTTDISPINFOA { NMHDR hdr; LPSTR lpszText; char[80] szText; HINSTANCE hinst; UINT uFlags; } struct NMTTDISPINFOW { NMHDR hdr; LPWSTR lpszText; WCHAR[80] szText; HINSTANCE hinst; UINT uFlags; } } alias NMTTDISPINFOA* LPNMTTDISPINFOA; alias NMTTDISPINFOW* LPNMTTDISPINFOW; alias NMTTDISPINFOA TOOLTIPTEXTA; alias LPNMTTDISPINFOA LPTOOLTIPTEXTA; alias NMTTDISPINFOW TOOLTIPTEXTW; alias LPNMTTDISPINFOW LPTOOLTIPTEXTW; struct UDACCEL { UINT nSec; UINT nInc; } alias UDACCEL* LPUDACCEL; struct NMUPDOWN { NMHDR hdr; int iPos; int iDelta; } alias NMUPDOWN* LPNMUPDOWN; deprecated { alias NMUPDOWN NM_UPDOWN; alias LPNMUPDOWN LPNM_UPDOWN; } static if (_WIN32_WINNT >= 0x501) { struct LVITEMA { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPSTR pszText; int cchTextMax; int iImage; LPARAM lParam; int iIndent; int iGroupId; UINT cColumns; PUINT puColumns; } struct LVITEMW { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPWSTR pszText; int cchTextMax; int iImage; LPARAM lParam; int iIndent; int iGroupId; UINT cColumns; PUINT puColumns; } } else static if (_WIN32_IE >= 0x300) { struct LVITEMA { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPSTR pszText; int cchTextMax; int iImage; LPARAM lParam; int iIndent; } struct LVITEMW { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPWSTR pszText; int cchTextMax; int iImage; LPARAM lParam; int iIndent; } } else { struct LVITEMA { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPSTR pszText; int cchTextMax; int iImage; LPARAM lParam; } struct LVITEMW { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPWSTR pszText; int cchTextMax; int iImage; LPARAM lParam; } } alias LVITEMA* LPLVITEMA; alias LVITEMW* LPLVITEMW; alias LVITEMA LV_ITEMA; alias LVITEMW LV_ITEMW; struct LVFINDINFOA { UINT flags; LPCSTR psz; LPARAM lParam; POINT pt; UINT vkDirection; } struct LVFINDINFOW { UINT flags; LPCWSTR psz; LPARAM lParam; POINT pt; UINT vkDirection; } alias LVFINDINFOA* LPFINDINFOA; alias LVFINDINFOA LV_FINDINFOA; alias LVFINDINFOW* LPFINDINFOW; alias LVFINDINFOW LV_FINDINFOW; struct NMLVFINDITEMA { NMHDR hdr; int iStart; LVFINDINFOA lvfi; } struct NMLVFINDITEMW { NMHDR hdr; int iStart; LVFINDINFOW lvfi; } alias NMLVFINDITEMA* PNMLVFINDITEMA, LPNMLVFINDITEMA; alias NMLVFINDITEMW* PNMLVFINDITEMW, LPNMLVFINDITEMW; static if (_WIN32_IE >= 0x300) { struct LVHITTESTINFO { POINT pt; UINT flags; int iItem; int iSubItem; } } else { struct LVHITTESTINFO { POINT pt; UINT flags; int iItem; } } alias LVHITTESTINFO* LPLVHITTESTINFO; alias LVHITTESTINFO LV_HITTESTINFO; static if (_WIN32_IE >= 0x300) { struct LVCOLUMNA { UINT mask; int fmt; int cx; LPSTR pszText; int cchTextMax; int iSubItem; int iImage; int iOrder; } struct LVCOLUMNW { UINT mask; int fmt; int cx; LPWSTR pszText; int cchTextMax; int iSubItem; int iImage; int iOrder; } } else { struct LVCOLUMNA { UINT mask; int fmt; int cx; LPSTR pszText; int cchTextMax; int iSubItem; } struct LVCOLUMNW { UINT mask; int fmt; int cx; LPWSTR pszText; int cchTextMax; int iSubItem; } } alias LVCOLUMNA* LPLVCOLUMNA; alias LVCOLUMNW* LPLVCOLUMNW; alias LVCOLUMNA LV_COLUMNA; alias LVCOLUMNW LV_COLUMNW; static if (_WIN32_WINNT >= 0x501) { /* SG: The definitions in this static if block are from the MSDN docs. * They are not in MinGW, but nonetheless required for macros that are. */ struct LVGROUP { UINT cbSize = LVGROUP.sizeof; UINT mask; LPWSTR pszHeader; int cchHeader; LPWSTR pszFooter; int cchFooter; int iGroupId; UINT stateMask; UINT state; UINT uAlign; static if (_WIN32_WINNT >= 0x600) { LPWSTR pszSubtitle; UINT cchSubtitle; LPWSTR pszTask; UINT cchTask; LPWSTR pszDescriptionTop; UINT cchDescriptionTop; LPWSTR pszDescriptionBottom; UINT cchDescriptionBottom; int iTitleImage; int iExtendedImage; int iFirstItem; // Read only UINT cItems; // Read only LPWSTR pszSubsetTitle; // NULL if group is not subset UINT cchSubsetTitle; } } alias LVGROUP* PLVGROUP; struct LVGROUPMETRICS { UINT cbSize = LVGROUPMETRICS.sizeof; UINT mask; UINT Left; UINT Top; UINT Right; UINT Bottom; COLORREF crLeft; COLORREF crTop; COLORREF crRight; COLORREF crBottom; COLORREF crHeader; COLORREF crFooter; } alias LVGROUPMETRICS* PLVGROUPMETRICS; struct LVINSERTMARK { UINT cbSize = LVINSERTMARK.sizeof; DWORD dwFlags; int iItem; DWORD dwReserved; } alias LVINSERTMARK* PLVINSERTMARK; alias LVINSERTMARK* LPLVINSERTMARK; struct LVTILEINFO { UINT cbSize = LVTILEINFO.sizeof; int iItem; UINT cColumns; PUINT puColumns; static if (_WIN32_WINNT >= 0x600) { int* piColFmt; } } alias LVTILEINFO* PLVTILEINFO; struct LVTILEVIEWINFO { UINT cbSize = LVTILEVIEWINFO.sizeof; DWORD dwMask; DWORD dwFlags; SIZE sizeTile; int cLines; RECT rcLabelMargin; } alias LVTILEVIEWINFO* PLVTILEVIEWINFO; struct LVINSERTGROUPSORTED { PFNLVGROUPCOMPARE pfnGroupCompare; LPVOID* pvData; LVGROUP lvGroup; } alias LVINSERTGROUPSORTED* PLVINSERTGROUPSORTED; alias int function(INT, INT, VOID*) PFNLVGROUPCOMPARE; struct LVSETINFOTIP { UINT cbSize = LVSETINFOTIP.sizeof; DWORD dwFlags; LPWSTR pszText; int iItem; int iSubItem; HBITMAP hbmp; } alias LVSETINFOTIP* PLVSETINFOTIP; struct BUTTON_IMAGELIST { HIMAGELIST himl; RECT margin; UINT uAlign; } alias BUTTON_IMAGELIST* PBUTTON_IMAGELIST; } static if (_WIN32_WINNT >= 0x600) { struct LVITEMINDEX { int iItem; int iGroup; }; alias LVITEMINDEX* PLVITEMINDEX; struct LVFOOTERINFO { UINT mask; LPWSTR pszText; int cchTextMax; UINT cItems; } alias LVFOOTERINFO* LPLVFOOTERINFO; struct LVFOOTERITEM { UINT mask; int iItem; LPWSTR pszText; int cchTextMax; UINT state; UINT stateMask; } alias LVFOOTERITEM *LPLVFOOTERITEM; alias UINT TVITEMPART; enum { TVGIPR_BUTTON = 0x0001, } } alias int function(LPARAM, LPARAM, LPARAM) PFNLVCOMPARE; struct NMLISTVIEW { NMHDR hdr; int iItem; int iSubItem; UINT uNewState; UINT uOldState; UINT uChanged; POINT ptAction; LPARAM lParam; } alias NMLISTVIEW* LPNMLISTVIEW; deprecated { alias NMLISTVIEW NM_LISTVIEW; alias LPNMLISTVIEW LPNM_LISTVIEW; } struct NMLVDISPINFOA { NMHDR hdr; LV_ITEMA item; } alias NMLVDISPINFOA* LPNMLVDISPINFOA; alias NMLVDISPINFOA LV_DISPINFOA; struct NMLVDISPINFOW { NMHDR hdr; LV_ITEMW item; } alias NMLVDISPINFOW* LPNMLVDISPINFOW; alias NMLVDISPINFOW LV_DISPINFOW; struct LV_KEYDOWN { NMHDR hdr; WORD wVKey; UINT flags; } struct NMLVCACHEHINT { NMHDR hdr; int iFrom; int iTo; } alias NMLVCACHEHINT* LPNMLVCACHEHINT, PNM_CACHEHINT, LPNM_CACHEHINT; alias NMLVCACHEHINT NM_CACHEHINT; struct TVITEMA { UINT mask; HTREEITEM hItem; UINT state; UINT stateMask; LPSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int cChildren; LPARAM lParam; } alias TVITEMA* LPTVITEMA, LPTV_ITEMA; alias TVITEMA TV_ITEMA; struct TVITEMW { UINT mask; HTREEITEM hItem; UINT state; UINT stateMask; LPWSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int cChildren; LPARAM lParam; } alias TVITEMW* LPTVITEMW, LPTV_ITEMW; alias TVITEMW TV_ITEMW; static if (_WIN32_IE >= 0x400) { struct TVITEMEXA { UINT mask; HTREEITEM hItem; UINT state; UINT stateMask; LPSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int cChildren; LPARAM lParam; int iIntegral; } alias TVITEMEXA* LPTVITEMEXA; struct TVITEMEXW { UINT mask; HTREEITEM hItem; UINT state; UINT stateMask; LPWSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int cChildren; LPARAM lParam; int iIntegral; } alias TVITEMEXW* LPTVITEMEXW; } static if (_WIN32_IE >= 0x400) { struct TVINSERTSTRUCTA { HTREEITEM hParent; HTREEITEM hInsertAfter; union { TVITEMEXA itemex; TV_ITEMA item; } } struct TVINSERTSTRUCTW { HTREEITEM hParent; HTREEITEM hInsertAfter; union { TVITEMEXW itemex; TV_ITEMW item; } } } else { struct TVINSERTSTRUCTA { HTREEITEM hParent; HTREEITEM hInsertAfter; TV_ITEMA item; } struct TVINSERTSTRUCTW { HTREEITEM hParent; HTREEITEM hInsertAfter; TV_ITEMW item; } } alias TVINSERTSTRUCTA* LPTVINSERTSTRUCTA, LPTV_INSERTSTRUCTA; alias TVINSERTSTRUCTA TV_INSERTSTRUCTA; alias TVINSERTSTRUCTW* LPTVINSERTSTRUCTW, LPTV_INSERTSTRUCTW; alias TVINSERTSTRUCTW TV_INSERTSTRUCTW; struct TVHITTESTINFO { POINT pt; UINT flags; HTREEITEM hItem; } alias TVHITTESTINFO* LPTVHITTESTINFO, LPTV_HITTESTINFO; alias TVHITTESTINFO TV_HITTESTINFO; static if (_WIN32_WINNT >= 0x600) { struct TVGETITEMPARTRECTINFO { HTREEITEM hti; RECT* prc; TVITEMPART partID; } } alias int function(LPARAM, LPARAM, LPARAM) PFNTVCOMPARE; struct TVSORTCB { HTREEITEM hParent; PFNTVCOMPARE lpfnCompare; LPARAM lParam; } alias TVSORTCB* LPTVSORTCB, LPTV_SORTCB; alias TVSORTCB TV_SORTCB; struct NMTREEVIEWA { NMHDR hdr; UINT action; TV_ITEMA itemOld; TV_ITEMA itemNew; POINT ptDrag; } alias NMTREEVIEWA* LPNMTREEVIEWA, LPNM_TREEVIEWA; alias NMTREEVIEWA NM_TREEVIEWA; struct NMTREEVIEWW { NMHDR hdr; UINT action; TV_ITEMW itemOld; TV_ITEMW itemNew; POINT ptDrag; } alias NMTREEVIEWW* LPNMTREEVIEWW, LPNM_TREEVIEWW; alias NMTREEVIEWW NM_TREEVIEWW; struct NMTVDISPINFOA { NMHDR hdr; TVITEMA item; } alias NMTVDISPINFOA* LPNMTVDISPINFOA; alias NMTVDISPINFOA TV_DISPINFOA; struct NMTVDISPINFOW { NMHDR hdr; TVITEMW item; } alias NMTVDISPINFOW* LPNMTVDISPINFOW; alias NMTVDISPINFOW TV_DISPINFOW; static if (_WIN32_IE >= 0x400) { struct NMTVGETINFOTIPA { NMHDR hdr; LPSTR pszText; int cchTextMax; HTREEITEM hItem; LPARAM lParam; } alias NMTVGETINFOTIPA* LPNMTVGETINFOTIPA; struct NMTVGETINFOTIPW { NMHDR hdr; LPWSTR pszText; int cchTextMax; HTREEITEM hItem; LPARAM lParam; } alias NMTVGETINFOTIPW* LPNMTVGETINFOTIPW; } struct TV_KEYDOWN { NMHDR hdr; WORD wVKey; UINT flags; } struct TC_ITEMHEADERA { UINT mask; UINT lpReserved1; UINT lpReserved2; LPSTR pszText; int cchTextMax; int iImage; } struct TC_ITEMHEADERW { UINT mask; UINT lpReserved1; UINT lpReserved2; LPWSTR pszText; int cchTextMax; int iImage; } static if (_WIN32_IE >= 0x300) { struct TCITEMA { UINT mask; DWORD dwState; DWORD dwStateMask; LPSTR pszText; int cchTextMax; int iImage; LPARAM lParam; } struct TCITEMW { UINT mask; DWORD dwState; DWORD dwStateMask; LPWSTR pszText; int cchTextMax; int iImage; LPARAM lParam; } } else { struct TCITEMA { UINT mask; UINT lpReserved1; UINT lpReserved2; LPSTR pszText; int cchTextMax; int iImage; LPARAM lParam; } struct TCITEMW { UINT mask; UINT lpReserved1; UINT lpReserved2; LPWSTR pszText; int cchTextMax; int iImage; LPARAM lParam; } } alias TCITEMA* LPTCITEMA; alias TCITEMA TC_ITEMA; alias TCITEMW* LPTCITEMW; alias TCITEMW TC_ITEMW; struct TCHITTESTINFO { POINT pt; UINT flags; } alias TCHITTESTINFO* LPTCHITTESTINFO, LPTC_HITTESTINFO; alias TCHITTESTINFO TC_HITTESTINFO; struct TC_KEYDOWN { NMHDR hdr; WORD wVKey; UINT flags; } static if (_WIN32_IE >= 0x300) { struct INITCOMMONCONTROLSEX { DWORD dwSize = INITCOMMONCONTROLSEX.sizeof; DWORD dwICC; } alias INITCOMMONCONTROLSEX* LPINITCOMMONCONTROLSEX; } struct PBRANGE { int iLow; int iHigh; } alias PBRANGE* PPBRANGE; struct COLORSCHEME { DWORD dwSize = COLORSCHEME.sizeof; COLORREF clrBtnHighlight; COLORREF clrBtnShadow; } alias COLORSCHEME* LPCOLORSCHEME; struct MCHITTESTINFO { UINT cbSize = MCHITTESTINFO.sizeof; POINT pt; UINT uHit; SYSTEMTIME st; } alias MCHITTESTINFO* PMCHITTESTINFO; alias DWORD MONTHDAYSTATE; alias MONTHDAYSTATE* LPMONTHDAYSTATE; struct NMDAYSTATE { NMHDR nmhdr; SYSTEMTIME stStart; int cDayState; LPMONTHDAYSTATE prgDayState; } alias NMDAYSTATE* LPNMDAYSTATE; struct REBARINFO { UINT cbSize = REBARINFO.sizeof; UINT fMask; HIMAGELIST himl; } alias REBARINFO* LPREBARINFO; static if (_WIN32_IE >= 0x400) { struct REBARBANDINFOA { UINT cbSize = REBARBANDINFOA.sizeof; UINT fMask; UINT fStyle; COLORREF clrFore; COLORREF clrBack; LPSTR lpText; UINT cch; int iImage; HWND hwndChild; UINT cxMinChild; UINT cyMinChild; UINT cx; HBITMAP hbmBack; UINT wID; UINT cyChild; UINT cyMaxChild; UINT cyIntegral; UINT cxIdeal; LPARAM lParam; UINT cxHeader; } struct REBARBANDINFOW { UINT cbSize = REBARBANDINFOW.sizeof; UINT fMask; UINT fStyle; COLORREF clrFore; COLORREF clrBack; LPWSTR lpText; UINT cch; int iImage; HWND hwndChild; UINT cxMinChild; UINT cyMinChild; UINT cx; HBITMAP hbmBack; UINT wID; UINT cyChild; UINT cyMaxChild; UINT cyIntegral; UINT cxIdeal; LPARAM lParam; UINT cxHeader; } enum : size_t { REBARBANDINFOA_V3_SIZE = REBARBANDINFOA.cyChild.offsetof, REBARBANDINFOW_V3_SIZE = REBARBANDINFOW.cyChild.offsetof } } else { struct REBARBANDINFOA { UINT cbSize = REBARBANDINFOA.sizeof; UINT fMask; UINT fStyle; COLORREF clrFore; COLORREF clrBack; LPSTR lpText; UINT cch; int iImage; HWND hwndChild; UINT cxMinChild; UINT cyMinChild; UINT cx; HBITMAP hbmBack; UINT wID; } struct REBARBANDINFOW { UINT cbSize = REBARBANDINFOW.sizeof; UINT fMask; UINT fStyle; COLORREF clrFore; COLORREF clrBack; LPWSTR lpText; UINT cch; int iImage; HWND hwndChild; UINT cxMinChild; UINT cyMinChild; UINT cx; HBITMAP hbmBack; UINT wID; } enum : size_t { REBARBANDINFOA_V3_SIZE = REBARBANDINFOA.sizeof, REBARBANDINFOW_V3_SIZE = REBARBANDINFOW.sizeof } } alias REBARBANDINFOA* LPREBARBANDINFOA; alias const(REBARBANDINFOA)* LPCREBARBANDINFOA; alias REBARBANDINFOW* LPREBARBANDINFOW; alias const(REBARBANDINFOW)* LPCREBARBANDINFOW; static if (_WIN32_IE >= 0x300) { struct NMLVODSTATECHANGE { NMHDR hdr; int iFrom; int iTo; UINT uNewState; UINT uOldState; } alias NMLVODSTATECHANGE* LPNMLVODSTATECHANGE; static if (_WIN32_WINNT >= 0x501) { struct IMAGELISTDRAWPARAMS { DWORD cbSize = IMAGELISTDRAWPARAMS.sizeof; HIMAGELIST himl; int i; HDC hdcDst; int x; int y; int cx; int cy; int xBitmap; int yBitmap; COLORREF rgbBk; COLORREF rgbFg; UINT fStyle; DWORD dwRop; DWORD fState; DWORD Frame; COLORREF crEffect; } } else { struct IMAGELISTDRAWPARAMS { DWORD cbSize = IMAGELISTDRAWPARAMS.sizeof; HIMAGELIST himl; int i; HDC hdcDst; int x; int y; int cx; int cy; int xBitmap; int yBitmap; COLORREF rgbBk; COLORREF rgbFg; UINT fStyle; DWORD dwRop; } } alias IMAGELISTDRAWPARAMS* LPIMAGELISTDRAWPARAMS; } static if (_WIN32_IE >= 0x400) { struct NMREBARCHILDSIZE { NMHDR hdr; UINT uBand; UINT wID; RECT rcChild; RECT rcBand; } alias NMREBARCHILDSIZE* LPNMREBARCHILDSIZE; struct NMREBAR { NMHDR hdr; DWORD dwMask; UINT uBand; UINT fStyle; UINT wID; LPARAM lParam; } alias NMREBAR* LPNMREBAR; struct NMRBAUTOSIZE { NMHDR hdr; BOOL fChanged; RECT rcTarget; RECT rcActual; } alias NMRBAUTOSIZE* LPNMRBAUTOSIZE; static if (_WIN32_IE >= 0x500) { struct NMREBARCHEVRON { NMHDR hdr; UINT uBand; UINT wID; LPARAM lParam; RECT rc; LPARAM lParamNM; } alias NMREBARCHEVRON* LPNMREBARCHEVRON; } struct RBHITTESTINFO { POINT pt; UINT flags; int iBand; } alias RBHITTESTINFO* LPRBHITTESTINFO; } mixin DECLARE_HANDLE!("HDSA"); mixin DECLARE_HANDLE!("HDPA"); version (Unicode) { alias HDITEMW HDITEM; alias LPHDITEMW LPHDITEM; alias TOOLINFOW TOOLINFO; alias TOOLINFOW* PTOOLINFO, LPTOOLINFO; alias TTHITTESTINFOW TTHITTESTINFO; alias TTHITTESTINFOW* LPHITTESTINFO, LPTTHITTESTINFO; alias TOOLTIPTEXTW TOOLTIPTEXT; alias TOOLTIPTEXTW* LPTOOLTIPTEXT; alias NMTTDISPINFOW NMTTDISPINFO; alias NMTTDISPINFOW* LPNMTTDISPINFO; alias TV_ITEMW TV_ITEM; alias TV_ITEMW* LPTV_ITEM; alias TVITEMW TVITEM; alias TVITEMW* LPTVITEM; static if (_WIN32_IE >= 0x400) { alias TVITEMEXW TVITEMEX; alias TVITEMEXW* LPTVITEMEX; } alias TV_INSERTSTRUCTW TV_INSERTSTRUCT; alias TV_INSERTSTRUCTW* LPTV_INSERTSTRUCT; alias TVINSERTSTRUCTW TVINSERTSTRUCT; alias TVINSERTSTRUCTW* LPTVINSERTSTRUCT; alias NM_TREEVIEWW NM_TREEVIEW; alias NM_TREEVIEWW* LPNM_TREEVIEW; alias NMTREEVIEWW NMTREEVIEW; alias NMTREEVIEWW* LPNMTREEVIEW; alias NMHDDISPINFOW NMHDDISPINFO; alias NMHDDISPINFOW* LPNMHDDISPINFO; alias ACM_OPENW ACM_OPEN; alias COMBOBOXEXITEMW COMBOBOXEXITEM; alias PCOMBOBOXEXITEMW PCOMBOBOXEXITEM; //alias PCCOMBOBOXEXITEMW PCCOMBOBOXEXITEM; fixme alias CBEM_INSERTITEMW CBEM_INSERTITEM; alias CBEM_SETITEMW CBEM_SETITEM; alias CBEM_GETITEMW CBEM_GETITEM; alias CBEN_ENDEDITW CBEN_ENDEDIT; alias NMCBEENDEDITW NMCBEENDEDIT; alias LPNMCBEENDEDITW LPNMCBEENDEDIT; alias PNMCBEENDEDITW PNMCBEENDEDIT; static if (_WIN32_IE >= 0x400) { alias NMCOMBOBOXEXW NMCOMBOBOXEX; alias PNMCOMBOBOXEXW PNMCOMBOBOXEX; alias CBEN_GETDISPINFOW CBEN_GETDISPINFO; alias CBEN_DRAGBEGINW CBEN_DRAGBEGIN; alias NMCBEDRAGBEGINW NMCBEDRAGBEGIN; alias LPNMCBEDRAGBEGINW LPNMCBEDRAGBEGIN; alias PNMCBEDRAGBEGINW PNMCBEDRAGBEGIN; } alias SB_GETTEXTW SB_GETTEXT; alias SB_SETTEXTW SB_SETTEXT; alias SB_GETTEXTLENGTHW SB_GETTEXTLENGTH; alias HDM_INSERTITEMW HDM_INSERTITEM; alias HDM_GETITEMW HDM_GETITEM; alias HDM_SETITEMW HDM_SETITEM; alias HDN_ITEMCHANGINGW HDN_ITEMCHANGING; alias HDN_ITEMCHANGEDW HDN_ITEMCHANGED; alias HDN_ITEMCLICKW HDN_ITEMCLICK; alias HDN_ITEMDBLCLICKW HDN_ITEMDBLCLICK; alias HDN_DIVIDERDBLCLICKW HDN_DIVIDERDBLCLICK; alias HDN_BEGINTRACKW HDN_BEGINTRACK; alias HDN_ENDTRACKW HDN_ENDTRACK; alias HDN_TRACKW HDN_TRACK; static if (_WIN32_IE >= 0x300) { alias HDN_GETDISPINFOW HDN_GETDISPINFO; } alias HD_NOTIFYW HD_NOTIFY; alias TBSAVEPARAMSW TBSAVEPARAMS; alias TB_GETBUTTONTEXTW TB_GETBUTTONTEXT; alias TB_SAVERESTOREW TB_SAVERESTORE; alias TB_ADDSTRINGW TB_ADDSTRING; static if (_WIN32_IE >= 0x400) { alias TBN_GETBUTTONINFOW TBN_GETBUTTONINFO; // fixme alias TB_GETBUTTONINFOW TB_GETBUTTONINFO; alias TB_SETBUTTONINFOW TB_SETBUTTONINFO; alias TB_INSERTBUTTONW TB_INSERTBUTTON; alias TB_ADDBUTTONSW TB_ADDBUTTONS; alias TB_MAPACCELERATORW TB_MAPACCELERATOR; alias TB_GETSTRINGW TB_GETSTRING; alias TBBUTTONINFOW TBBUTTONINFO; alias LPTBBUTTONINFOW LPTBBUTTONINFO; alias TBN_GETDISPINFOW TBN_GETDISPINFO; alias NMTBDISPINFOW NMTBDISPINFO; alias LPNMTBDISPINFOW LPNMTBDISPINFO; alias NMTBGETINFOTIPW NMTBGETINFOTIP; alias LPNMTBGETINFOTIPW LPNMTBGETINFOTIP; } alias TBNOTIFYW TBNOTIFY; alias LPTBNOTIFYW LPTBNOTIFY; alias NMTOOLBARW NMTOOLBAR; alias LPNMTOOLBARW LPNMTOOLBAR; alias TTM_ADDTOOLW TTM_ADDTOOL; alias TTM_DELTOOLW TTM_DELTOOL; alias TTM_NEWTOOLRECTW TTM_NEWTOOLRECT; alias TTM_GETTOOLINFOW TTM_GETTOOLINFO; alias TTM_SETTOOLINFOW TTM_SETTOOLINFO; alias TTM_HITTESTW TTM_HITTEST; alias TTM_GETTEXTW TTM_GETTEXT; alias TTM_UPDATETIPTEXTW TTM_UPDATETIPTEXT; alias TTM_ENUMTOOLSW TTM_ENUMTOOLS; alias TTM_GETCURRENTTOOLW TTM_GETCURRENTTOOL; alias TTN_NEEDTEXTW TTN_NEEDTEXT; alias TTN_GETDISPINFOW TTN_GETDISPINFO; //alias SB_GETTEXTW SB_GETTEXT; //alias SB_SETTEXTW SB_SETTEXT; //alias SB_GETTEXTLENGTHW SB_GETTEXTLENGTH; alias LV_ITEMW LV_ITEM; alias LVITEMW LVITEM; alias LVITEM* LPLVITEM; alias LPSTR_TEXTCALLBACKW LPSTR_TEXTCALLBACK; static if (_WIN32_IE >= 0x400) { alias LVBKIMAGEW LVBKIMAGE; alias LPLVBKIMAGEW LPLVBKIMAGE; alias LVM_SETBKIMAGEW LVM_SETBKIMAGE; alias LVM_GETBKIMAGEW LVM_GETBKIMAGE; } alias LVM_GETITEMW LVM_GETITEM; alias LVM_SETITEMW LVM_SETITEM; alias LVM_INSERTITEMW LVM_INSERTITEM; alias LV_FINDINFOW LV_FINDINFO; alias LVFINDINFOW LVFINDINFO; alias LPFINDINFOW LPFINDINFO; alias NMLVFINDITEMW NMLVFINDITEM; alias PNMLVFINDITEMW PNMLVFINDITEM; alias LPNMLVFINDITEMW LPNMLVFINDITEM; alias LVM_FINDITEMW LVM_FINDITEM; alias LVM_GETSTRINGWIDTHW LVM_GETSTRINGWIDTH; alias LVM_EDITLABELW LVM_EDITLABEL; alias LV_COLUMNW LV_COLUMN; alias LVCOLUMNW LVCOLUMN; alias LVCOLUMNW* LPLVCOLUMN; alias LVM_GETCOLUMNW LVM_GETCOLUMN; alias LVM_SETCOLUMNW LVM_SETCOLUMN; alias LVM_INSERTCOLUMNW LVM_INSERTCOLUMN; alias LVM_GETITEMTEXTW LVM_GETITEMTEXT; alias LVM_SETITEMTEXTW LVM_SETITEMTEXT; alias LVM_GETISEARCHSTRINGW LVM_GETISEARCHSTRING; alias LVN_BEGINLABELEDITW LVN_BEGINLABELEDIT; alias LVN_ENDLABELEDITW LVN_ENDLABELEDIT; alias LVN_GETDISPINFOW LVN_GETDISPINFO; alias LVN_SETDISPINFOW LVN_SETDISPINFO; static if (_WIN32_IE >= 0x400) { alias LVN_GETINFOTIPW LVN_GETINFOTIP; alias NMLVGETINFOTIPW NMLVGETINFOTIP; alias LPNMLVGETINFOTIPW LPNMLVGETINFOTIP; } alias LV_DISPINFOW LV_DISPINFO; alias NMLVDISPINFOW NMLVDISPINFO; alias LPNMLVDISPINFOW LPNMLVDISPINFO; alias TVM_INSERTITEMW TVM_INSERTITEM; alias TVM_GETITEMW TVM_GETITEM; alias TVM_SETITEMW TVM_SETITEM; alias TVM_EDITLABELW TVM_EDITLABEL; alias TVM_GETISEARCHSTRINGW TVM_GETISEARCHSTRING; alias NMTVDISPINFOW TV_DISPINFO; alias NMTVDISPINFOW NMTVDISPINFO; alias LPNMTVDISPINFOW LPNMTVDISPINFO; static if (_WIN32_IE >= 0x400) { alias NMTVGETINFOTIPW NMTVGETINFOTIP; alias LPNMTVGETINFOTIPW LPNMTVGETINFOTIP; alias TVN_GETINFOTIPW TVN_GETINFOTIP; } alias TVN_SELCHANGINGW TVN_SELCHANGING; alias TVN_SELCHANGEDW TVN_SELCHANGED; alias TVN_GETDISPINFOW TVN_GETDISPINFO; alias TVN_SETDISPINFOW TVN_SETDISPINFO; alias TVN_ITEMEXPANDINGW TVN_ITEMEXPANDING; alias TVN_ITEMEXPANDEDW TVN_ITEMEXPANDED; alias TVN_BEGINDRAGW TVN_BEGINDRAG; alias TVN_BEGINRDRAGW TVN_BEGINRDRAG; alias TVN_DELETEITEMW TVN_DELETEITEM; alias TVN_BEGINLABELEDITW TVN_BEGINLABELEDIT; alias TVN_ENDLABELEDITW TVN_ENDLABELEDIT; alias TC_ITEMHEADERW TC_ITEMHEADER; alias TC_ITEMW TC_ITEM; alias TCITEMW TCITEM; alias LPTCITEMW LPTCITEM; alias TCM_GETITEMW TCM_GETITEM; alias TCM_SETITEMW TCM_SETITEM; alias TCM_INSERTITEMW TCM_INSERTITEM; alias CreateStatusWindowW CreateStatusWindow; alias DrawStatusTextW DrawStatusText; alias ImageList_LoadImageW ImageList_LoadImage; alias DTM_SETFORMATW DTM_SETFORMAT; alias DTN_USERSTRINGW DTN_USERSTRING; alias DTN_WMKEYDOWNW DTN_WMKEYDOWN; alias DTN_FORMATW DTN_FORMAT; alias DTN_FORMATQUERYW DTN_FORMATQUERY; alias REBARBANDINFOW REBARBANDINFO; alias REBARBANDINFO* LPREBARBANDINFO; alias LPCREBARBANDINFOW LPCREBARBANDINFO; alias REBARBANDINFOW_V3_SIZE REBARBANDINFO_V3_SIZE; alias RB_INSERTBANDW RB_INSERTBAND; alias RB_SETBANDINFOW RB_SETBANDINFO; } else { alias HDITEMA HDITEM; alias LPHDITEMA LPHDITEM; alias TOOLINFOA TOOLINFO; alias TOOLINFOA* PTOOLINFO, LPTOOLINFO; alias TTHITTESTINFOA TTHITTESTINFO; alias TTHITTESTINFOA* LPHITTESTINFO, LPTTHITTESTINFO; alias TOOLTIPTEXTA TOOLTIPTEXT; alias TOOLTIPTEXTA* LPTOOLTIPTEXT; alias NMTTDISPINFOA NMTTDISPINFO; alias NMTTDISPINFOA* LPNMTTDISPINFO; alias TV_ITEMA TV_ITEM; alias TV_ITEMA* LPTV_ITEM; alias TVITEMA TVITEM; alias TVITEMA* LPTVITEM; static if (_WIN32_IE >= 0x400) { alias TVITEMEXA TVITEMEX; alias TVITEMEXA* LPTVITEMEX; } alias TV_INSERTSTRUCTA TV_INSERTSTRUCT; alias TV_INSERTSTRUCTA* LPTV_INSERTSTRUCT; alias TVINSERTSTRUCTA TVINSERTSTRUCT; alias TVINSERTSTRUCTA* LPTVINSERTSTRUCT; alias NM_TREEVIEWA NM_TREEVIEW; alias NM_TREEVIEWA* LPNM_TREEVIEW; alias NMTREEVIEWA NMTREEVIEW; alias NMTREEVIEWA* LPNMTREEVIEW; alias NMHDDISPINFOW NMHDDISPINFO; alias NMHDDISPINFOW* LPNMHDDISPINFO; alias ACM_OPENA ACM_OPEN; alias COMBOBOXEXITEMA COMBOBOXEXITEM; alias PCOMBOBOXEXITEMA PCOMBOBOXEXITEM; //alias PCCOMBOBOXEXITEMA PCCOMBOBOXEXITEM; fixme alias CBEM_INSERTITEMA CBEM_INSERTITEM; alias CBEM_SETITEMA CBEM_SETITEM; alias CBEM_GETITEMA CBEM_GETITEM; alias CBEN_ENDEDITA CBEN_ENDEDIT; alias NMCBEENDEDITA NMCBEENDEDIT; alias LPNMCBEENDEDITA LPNMCBEENDEDIT; alias PNMCBEENDEDITA PNMCBEENDEDIT; static if (_WIN32_IE >= 0x400) { alias TB_GETBUTTONINFOA TB_GETBUTTONINFO; alias TB_SETBUTTONINFOA TB_SETBUTTONINFO; alias TB_INSERTBUTTONA TB_INSERTBUTTON; alias TB_ADDBUTTONSA TB_ADDBUTTONS; alias TB_MAPACCELERATORA TB_MAPACCELERATOR; alias TB_GETSTRINGA TB_GETSTRING; alias NMCOMBOBOXEXA NMCOMBOBOXEX; alias PNMCOMBOBOXEXA PNMCOMBOBOXEX; alias CBEN_DRAGBEGINA CBEN_DRAGBEGIN; alias CBEN_GETDISPINFOA CBEN_GETDISPINFO; alias NMCBEDRAGBEGINA NMCBEDRAGBEGIN; alias LPNMCBEDRAGBEGINA LPNMCBEDRAGBEGIN; alias PNMCBEDRAGBEGINA PNMCBEDRAGBEGIN; alias TBN_GETDISPINFOA TBN_GETDISPINFO; alias NMTBDISPINFOA NMTBDISPINFO; alias LPNMTBDISPINFOA LPNMTBDISPINFO; alias NMTBGETINFOTIPA NMTBGETINFOTIP; alias LPNMTBGETINFOTIPA LPNMTBGETINFOTIP; } alias SB_GETTEXTA SB_GETTEXT; alias SB_SETTEXTA SB_SETTEXT; alias SB_GETTEXTLENGTHA SB_GETTEXTLENGTH; alias HDM_INSERTITEMA HDM_INSERTITEM; alias HDM_GETITEMA HDM_GETITEM; alias HDM_SETITEMA HDM_SETITEM; alias HDN_ITEMCHANGINGA HDN_ITEMCHANGING; alias HDN_ITEMCHANGEDA HDN_ITEMCHANGED; alias HDN_ITEMCLICKA HDN_ITEMCLICK; alias HDN_ITEMDBLCLICKA HDN_ITEMDBLCLICK; alias HDN_DIVIDERDBLCLICKA HDN_DIVIDERDBLCLICK; alias HDN_BEGINTRACKA HDN_BEGINTRACK; alias HDN_ENDTRACKA HDN_ENDTRACK; alias HDN_TRACKA HDN_TRACK; static if (_WIN32_IE >= 0x300) { alias HDN_GETDISPINFOA HDN_GETDISPINFO; } alias HD_NOTIFYA HD_NOTIFY; alias TBSAVEPARAMSA TBSAVEPARAMS; alias TB_GETBUTTONTEXTA TB_GETBUTTONTEXT; alias TB_SAVERESTOREA TB_SAVERESTORE; alias TB_ADDSTRINGA TB_ADDSTRING; alias TBN_GETBUTTONINFOA TBN_GETBUTTONINFO; static if (_WIN32_IE >= 0x400) { alias TBBUTTONINFOA TBBUTTONINFO; alias LPTBBUTTONINFOA LPTBBUTTONINFO; } alias TBNOTIFYA TBNOTIFY; alias LPTBNOTIFYA LPTBNOTIFY; alias NMTOOLBARA NMTOOLBAR; alias LPNMTOOLBARA LPNMTOOLBAR; alias TTM_ADDTOOLA TTM_ADDTOOL; alias TTM_DELTOOLA TTM_DELTOOL; alias TTM_NEWTOOLRECTA TTM_NEWTOOLRECT; alias TTM_GETTOOLINFOA TTM_GETTOOLINFO; alias TTM_SETTOOLINFOA TTM_SETTOOLINFO; alias TTM_HITTESTA TTM_HITTEST; alias TTM_GETTEXTA TTM_GETTEXT; alias TTM_UPDATETIPTEXTA TTM_UPDATETIPTEXT; alias TTM_ENUMTOOLSA TTM_ENUMTOOLS; alias TTM_GETCURRENTTOOLA TTM_GETCURRENTTOOL; alias TTN_NEEDTEXTA TTN_NEEDTEXT; alias TTN_GETDISPINFOA TTN_GETDISPINFO; alias LV_ITEMA LV_ITEM; alias LVITEMA LVITEM; alias LVITEM* LPLVITEM; alias LPSTR_TEXTCALLBACKA LPSTR_TEXTCALLBACK; static if (_WIN32_IE >= 0x400) { alias LVBKIMAGEA LVBKIMAGE; alias LPLVBKIMAGEA LPLVBKIMAGE; alias LVM_SETBKIMAGEA LVM_SETBKIMAGE; alias LVM_GETBKIMAGEA LVM_GETBKIMAGE; } alias LVM_GETITEMA LVM_GETITEM; alias LVM_SETITEMA LVM_SETITEM; alias LVM_INSERTITEMA LVM_INSERTITEM; alias LV_FINDINFOA LV_FINDINFO; alias LVFINDINFOA LVFINDINFO; alias LPFINDINFOA LPFINDINFO; alias NMLVFINDITEMA NMLVFINDITEM; alias PNMLVFINDITEMA PNMLVFINDITEM; alias LPNMLVFINDITEMA LPNMLVFINDITEM; alias LVM_FINDITEMA LVM_FINDITEM; alias LVM_GETSTRINGWIDTHA LVM_GETSTRINGWIDTH; alias LVM_EDITLABELA LVM_EDITLABEL; alias LV_COLUMNA LV_COLUMN; alias LVCOLUMNA LVCOLUMN; alias LVCOLUMNA* LPLVCOLUMN; alias LVM_GETCOLUMNA LVM_GETCOLUMN; alias LVM_SETCOLUMNA LVM_SETCOLUMN; alias LVM_INSERTCOLUMNA LVM_INSERTCOLUMN; alias LVM_GETITEMTEXTA LVM_GETITEMTEXT; alias LVM_SETITEMTEXTA LVM_SETITEMTEXT; alias LVM_GETISEARCHSTRINGA LVM_GETISEARCHSTRING; alias LVN_BEGINLABELEDITA LVN_BEGINLABELEDIT; alias LVN_ENDLABELEDITA LVN_ENDLABELEDIT; alias LVN_GETDISPINFOA LVN_GETDISPINFO; alias LVN_SETDISPINFOA LVN_SETDISPINFO; static if (_WIN32_IE >= 0x400) { alias LVN_GETINFOTIPA LVN_GETINFOTIP; alias NMLVGETINFOTIPA NMLVGETINFOTIP; alias LPNMLVGETINFOTIPA LPNMLVGETINFOTIP; } alias LV_DISPINFOA LV_DISPINFO; alias NMLVDISPINFOA NMLVDISPINFO; alias LPNMLVDISPINFOA LPNMLVDISPINFO; alias TVM_INSERTITEMA TVM_INSERTITEM; alias TVM_GETITEMA TVM_GETITEM; alias TVM_SETITEMA TVM_SETITEM; alias TVM_EDITLABELA TVM_EDITLABEL; alias TVM_GETISEARCHSTRINGA TVM_GETISEARCHSTRING; alias NMTVDISPINFOA TV_DISPINFO; alias NMTVDISPINFOA NMTVDISPINFO; alias LPNMTVDISPINFOA LPNMTVDISPINFO; static if (_WIN32_IE >= 0x400) { alias NMTVGETINFOTIPA NMTVGETINFOTIP; alias LPNMTVGETINFOTIPA LPNMTVGETINFOTIP; alias TVN_GETINFOTIPA TVN_GETINFOTIP; } alias TVN_SELCHANGINGA TVN_SELCHANGING; alias TVN_SELCHANGEDA TVN_SELCHANGED; alias TVN_GETDISPINFOA TVN_GETDISPINFO; alias TVN_SETDISPINFOA TVN_SETDISPINFO; alias TVN_ITEMEXPANDINGA TVN_ITEMEXPANDING; alias TVN_ITEMEXPANDEDA TVN_ITEMEXPANDED; alias TVN_BEGINDRAGA TVN_BEGINDRAG; alias TVN_BEGINRDRAGA TVN_BEGINRDRAG; alias TVN_DELETEITEMA TVN_DELETEITEM; alias TVN_BEGINLABELEDITA TVN_BEGINLABELEDIT; alias TVN_ENDLABELEDITA TVN_ENDLABELEDIT; alias TC_ITEMHEADERA TC_ITEMHEADER; alias TC_ITEMA TC_ITEM; alias TCITEMA TCITEM; alias LPTCITEMA LPTCITEM; alias TCM_GETITEMA TCM_GETITEM; alias TCM_SETITEMA TCM_SETITEM; alias TCM_INSERTITEMA TCM_INSERTITEM; alias CreateStatusWindowA CreateStatusWindow; alias DrawStatusTextA DrawStatusText; alias ImageList_LoadImageA ImageList_LoadImage; alias DTM_SETFORMATA DTM_SETFORMAT; alias DTN_USERSTRINGA DTN_USERSTRING; alias DTN_WMKEYDOWNA DTN_WMKEYDOWN; alias DTN_FORMATA DTN_FORMAT; alias DTN_FORMATQUERYA DTN_FORMATQUERY; alias REBARBANDINFOA REBARBANDINFO; alias REBARBANDINFOA* LPREBARBANDINFO; alias LPCREBARBANDINFOA LPCREBARBANDINFO; alias REBARBANDINFOA_V3_SIZE REBARBANDINFO_V3_SIZE; alias RB_INSERTBANDA RB_INSERTBAND; alias RB_SETBANDINFOA RB_SETBANDINFO; } alias INT function(PVOID, PVOID) PFNDPAENUMCALLBACK; alias INT function(PVOID, PVOID) PFNDSAENUMCALLBACK; alias INT function(PVOID, PVOID, LPARAM) PFNDPACOMPARE; static if (_WIN32_WINNT >= 0x501) { extern (Windows) alias LRESULT function(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR) SUBCLASSPROC; struct LITEM { UINT mask; int iLink; UINT state; UINT stateMask; WCHAR[MAX_LINKID_TEXT] szID; WCHAR[L_MAX_URL_LENGTH] szUrl; } alias LITEM* PLITEM; struct LHITTESTINFO { POINT pt; LITEM item; } alias LHITTESTINFO* PLHITTESTINFO; struct NMLINK { NMHDR hdr; LITEM item; } alias NMLINK* PNMLINK; } uint INDEXTOOVERLAYMASK(uint i) { return i << 8; } uint INDEXTOSTATEIMAGEMASK(uint i) { return i << 12; } template HANDLE_WM_NOTIFY(R) { R HANDLE_WM_NOTIFY(HWND hwnd, WPARAM wParam, LPARAM lParam, R function(HWND, int, NMHDR*) fn) { return fn(hwnd, wParam, cast(NMHDR*) lParam); } } int FORWARD_WM_NOTIFY(HWND hwnd, int idFrom, NMHDR* pnmhdr, int function(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) fn) { return fn(hwnd, WM_NOTIFY, idFrom, cast(LPARAM) pnmhdr); } //#define CCSIZEOF_STRUCT(s, m) (((int)((PBYTE)(&((s*)0)->m)-((PBYTE)((s*)0))))+sizeof(((s*)0)->m)) LPARAM MAKEIPADDRESS(ubyte b1, ubyte b2, ubyte b3, ubyte b4) { return (cast(DWORD) b1 << 24) | (cast(DWORD) b2 << 16) | (cast(DWORD) b3 << 8) | (cast(DWORD) b4); } LPARAM MAKEIPRANGE(ubyte low, ubyte high) { return (cast(int) high << 8) | low; } ubyte FIRST_IPADDRESS(LPARAM x) { return cast(ubyte) (x >> 24); } ubyte SECOND_IPADDRESS(LPARAM x) { return cast(ubyte) (x >> 16); } ubyte THIRD_IPADDRESS(LPARAM x) { return cast(ubyte) (x >> 8); } ubyte FOURTH_IPADDRESS(LPARAM x) { return cast(ubyte) x; } HWND Animate_Create(HWND hwndP, UINT id, DWORD dwStyle, HINSTANCE hInstance) { return CreateWindow(cast(TCHAR*)ANIMATE_CLASS.ptr, null, dwStyle, 0, 0, 0, 0, hwndP, cast(HMENU) id, hInstance, null); } BOOL Animate_Open(HWND hwnd, LPTSTR szName) { return cast(BOOL) SendMessage(hwnd, ACM_OPEN, 0, cast(LPARAM) szName); } BOOL Animate_OpenEx(HWND hwnd, HINSTANCE hInst, LPTSTR szName) { return cast(BOOL) SendMessage(hwnd, ACM_OPEN, cast(WPARAM) hInst, cast(LPARAM) szName); } BOOL Animate_Play(HWND hwnd, int from, int to, int rep) { return cast(BOOL) SendMessage(hwnd, ACM_PLAY, rep, MAKELONG(cast(ushort) from, cast(ushort) to)); } BOOL Animate_Stop(HWND hwnd) { return cast(BOOL) SendMessage(hwnd, ACM_STOP, 0, 0); } BOOL Animate_Close(HWND hwnd) { return Animate_Open(hwnd, null); } BOOL Animate_Seek(HWND hwnd, int frame) { return Animate_Play(hwnd, frame, frame, 1); } extern (Windows) { HBITMAP CreateMappedBitmap(HINSTANCE, INT_PTR, UINT, LPCOLORMAP, int); HWND CreateStatusWindowA(LONG, LPCSTR, HWND, UINT); HWND CreateStatusWindowW(LONG, LPCWSTR, HWND, UINT); HWND CreateToolbarEx(HWND, DWORD, UINT, int, HINSTANCE, UINT_PTR, LPCTBBUTTON, int, int, int, int, int, UINT); HWND CreateUpDownControl(DWORD, int, int, int, int, HWND, int, HINSTANCE, HWND, int, int, int); } HWND DateTime_GetMonthCal(HWND hwnd) { return cast(HWND) SendMessage(hwnd, DTM_GETMONTHCAL, 0, 0); } COLORREF DateTime_GetMonthCalColor(HWND hwnd, int iColor) { return cast(COLORREF) SendMessage(hwnd, DTM_GETMCCOLOR, iColor, 0); } HFONT DateTime_GetMonthCalFont(HWND hwnd) { return cast(HFONT) SendMessage(hwnd, DTM_GETMCFONT, 0, 0); } DWORD DateTime_GetRange(HWND hwnd, LPSYSTEMTIME lpSysTimeArray) { return cast(DWORD) SendMessage(hwnd, DTM_GETRANGE, 0, cast(LPARAM) lpSysTimeArray); } DWORD DateTime_GetSystemtime(HWND hwnd, LPSYSTEMTIME lpSysTime) { return cast(DWORD) SendMessage(hwnd, DTM_GETSYSTEMTIME, 0, cast(LPARAM) lpSysTime); } BOOL DateTime_SetFormat(HWND hwnd, LPCTSTR lpszFormat) { return cast(BOOL) SendMessage(hwnd, DTM_SETFORMAT, 0, cast(LPARAM) lpszFormat); } LRESULT DateTime_SetMonthCalColor(HWND hwnd, int iColor, COLORREF clr) { return SendMessage(hwnd, DTM_SETMCCOLOR, cast(WPARAM) iColor, cast(LPARAM) clr); } void DateTime_SetMonthCalFont(HWND hwnd, HFONT hfont, BOOL fRedraw) { SendMessage(hwnd, DTM_SETMCFONT, cast(WPARAM) hfont, fRedraw); } BOOL DateTime_SetRange(HWND hwnd, WPARAM flags, LPSYSTEMTIME lpSysTimeArray) { return cast(BOOL) SendMessage(hwnd, DTM_SETRANGE, flags, cast(LPARAM) lpSysTimeArray); } BOOL DateTime_SetSystemtime(HWND hwnd, WPARAM flag, LPSYSTEMTIME lpSysTime) { return cast(BOOL) SendMessage(hwnd, DTM_SETSYSTEMTIME, flag, cast(LPARAM) lpSysTime); } extern (Windows) { void DrawInsert(HWND, HWND, int); void DrawStatusTextA(HDC, LPRECT, LPCSTR, UINT); void DrawStatusTextW(HDC, LPRECT, LPCWSTR, UINT); void GetEffectiveClientRect(HWND, LPRECT, LPINT); } int Header_GetItemCount(HWND w) { return cast(int) SendMessage(w, HDM_GETITEMCOUNT, 0, 0); } int Header_InsertItem(HWND w, int i, const(HDITEM)* phdi) { return cast(int) SendMessage(w, HDM_INSERTITEM, i, cast(LPARAM) phdi); } BOOL Header_DeleteItem(HWND w, int i) { return cast(BOOL) SendMessage(w, HDM_DELETEITEM, i, 0); } BOOL Header_GetItem(HWND w, int i, LPHDITEM phdi) { return cast(BOOL) SendMessage(w, HDM_GETITEM, i, cast(LPARAM) phdi); } BOOL Header_SetItem(HWND w, int i, const(HDITEM)* phdi) { return cast(BOOL) SendMessage(w, HDM_SETITEM, i, cast(LPARAM) phdi); } BOOL Header_Layout(HWND w, LPHDLAYOUT playout) { return cast(BOOL) SendMessage(w, HDM_LAYOUT, 0, cast(LPARAM) playout); } static if (_WIN32_IE >= 0x300) { int Header_OrderToIndex(HWND w, int i) { return cast(int) SendMessage(w, HDM_ORDERTOINDEX, i, 0); } BOOL Header_GetItemRect(HWND w, int i, RECT* r) { return cast(BOOL) SendMessage(w, HDM_GETITEMRECT, i, cast(LPARAM) r); } BOOL Header_GetOrderArray(HWND w, int iSize, LPINT lpiArray) { return cast(BOOL) SendMessage(w, HDM_GETORDERARRAY, iSize, cast(LPARAM) lpiArray); } BOOL Header_SetOrderArray(HWND w, int iSize, LPINT lpiArray) { return cast(BOOL) SendMessage(w, HDM_SETORDERARRAY, iSize, cast(LPARAM) lpiArray); } HIMAGELIST Header_CreateDragImage(HWND w, int i) { return cast(HIMAGELIST) SendMessage(w, HDM_CREATEDRAGIMAGE, i, 0); } HIMAGELIST Header_SetImageList(HWND w, HIMAGELIST himl) { return cast(HIMAGELIST) SendMessage(w, HDM_SETIMAGELIST, 0, cast(LPARAM) himl); } HIMAGELIST Header_GetImageList(HWND w) { return cast(HIMAGELIST) SendMessage(w, HDM_GETIMAGELIST, 0, 0); } } static if (_WIN32_IE >= 0x400) { BOOL Header_GetUnicodeFormat(HWND w) { return cast(BOOL) SendMessage(w, HDM_GETUNICODEFORMAT, 0, 0); } BOOL Header_SetUnicodeFormat(HWND w, BOOL fUnicode) { return cast(BOOL) SendMessage(w, HDM_SETUNICODEFORMAT, fUnicode, 0); } } extern (Windows) { HDSA DSA_Create(INT, INT); BOOL DSA_Destroy(HDSA); VOID DSA_DestroyCallback(HDSA, PFNDSAENUMCALLBACK, PVOID); PVOID DSA_GetItemPtr(HDSA, INT); INT DSA_InsertItem(HDSA, INT, PVOID); HDPA DPA_Create(INT); BOOL DPA_Destroy(HDPA); PVOID DPA_DeletePtr(HDPA, INT); BOOL DPA_DeleteAllPtrs(HDPA); VOID DPA_EnumCallback(HDPA, PFNDPAENUMCALLBACK, PVOID); VOID DPA_DestroyCallback(HDPA, PFNDPAENUMCALLBACK, PVOID); BOOL DPA_SetPtr(HDPA, INT, PVOID); INT DPA_InsertPtr(HDPA, INT, PVOID); PVOID DPA_GetPtr(HDPA, INT_PTR); BOOL DPA_Sort(HDPA, PFNDPACOMPARE, LPARAM); INT DPA_Search(HDPA, PVOID, INT, PFNDPACOMPARE, LPARAM, UINT); BOOL Str_SetPtrW(LPWSTR*, LPCWSTR); static if (_WIN32_IE >= 0x400) { BOOL FlatSB_EnableScrollBar(HWND, INT, UINT); BOOL FlatSB_ShowScrollBar(HWND, INT, BOOL); BOOL FlatSB_GetScrollRange(HWND, INT, LPINT, LPINT); BOOL FlatSB_GetScrollInfo(HWND, INT, LPSCROLLINFO); INT FlatSB_GetScrollPos(HWND, INT); BOOL FlatSB_GetScrollProp(HWND, INT, LPINT); version (Win64) { BOOL FlatSB_GetScrollPropPtr(HWND, INT, PINT_PTR); } else { alias FlatSB_GetScrollProp FlatSB_GetScrollPropPtr; } INT FlatSB_SetScrollPos(HWND, INT, INT, BOOL); INT FlatSB_SetScrollInfo(HWND, INT, LPSCROLLINFO, BOOL); INT FlatSB_SetScrollRange(HWND, INT, INT, INT, BOOL); BOOL FlatSB_SetScrollProp(HWND, UINT, INT_PTR, BOOL); alias FlatSB_SetScrollProp FlatSB_SetScrollPropPtr; BOOL InitializeFlatSB(HWND); HRESULT UninitializeFlatSB(HWND); } static if (_WIN32_WINNT >= 0x501) { BOOL SetWindowSubclass(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); BOOL GetWindowSubclass(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR*); BOOL RemoveWindowSubclass(HWND, SUBCLASSPROC, UINT_PTR); LRESULT DefSubclassProc(HWND, UINT, WPARAM, LPARAM); INT DrawShadowText(HDC, LPCWSTR, UINT, RECT*, DWORD, COLORREF, COLORREF, INT, INT); } int ImageList_Add(HIMAGELIST, HBITMAP, HBITMAP); int ImageList_AddMasked(HIMAGELIST, HBITMAP, COLORREF); BOOL ImageList_BeginDrag(HIMAGELIST, int, int, int); HIMAGELIST ImageList_Create(int, int, UINT, int, int); BOOL ImageList_Destroy(HIMAGELIST); BOOL ImageList_DragEnter(HWND, int, int); BOOL ImageList_DragLeave(HWND); BOOL ImageList_DragMove(int, int); BOOL ImageList_DragShowNolock(BOOL); BOOL ImageList_Draw(HIMAGELIST, int, HDC, int, int, UINT); BOOL ImageList_DrawEx(HIMAGELIST, int, HDC, int, int, int, int, COLORREF, COLORREF, UINT); void ImageList_EndDrag(); COLORREF ImageList_GetBkColor(HIMAGELIST); HIMAGELIST ImageList_GetDragImage(LPPOINT, LPPOINT); HICON ImageList_GetIcon(HIMAGELIST, int, UINT); BOOL ImageList_GetIconSize(HIMAGELIST, int*, int*); int ImageList_GetImageCount(HIMAGELIST); BOOL ImageList_GetImageInfo(HIMAGELIST, int, IMAGEINFO*); HIMAGELIST ImageList_LoadImageA(HINSTANCE, LPCSTR, int, int, COLORREF, UINT, UINT); HIMAGELIST ImageList_LoadImageW(HINSTANCE, LPCWSTR, int, int, COLORREF, UINT, UINT); HIMAGELIST ImageList_Merge(HIMAGELIST, int, HIMAGELIST, int, int, int); BOOL ImageList_Remove(HIMAGELIST, int); BOOL ImageList_Replace(HIMAGELIST, int, HBITMAP, HBITMAP); int ImageList_ReplaceIcon(HIMAGELIST, int, HICON); COLORREF ImageList_SetBkColor(HIMAGELIST, COLORREF); BOOL ImageList_SetDragCursorImage(HIMAGELIST, int, int, int); BOOL ImageList_SetIconSize(HIMAGELIST, int, int); BOOL ImageList_SetOverlayImage(HIMAGELIST, int, int); //#ifdef _OBJIDL_H HIMAGELIST ImageList_Read(LPSTREAM); BOOL ImageList_Write(HIMAGELIST, LPSTREAM); //#endif static if (_WIN32_IE >= 0x400) { HIMAGELIST ImageList_Duplicate(HIMAGELIST himl); } void InitCommonControls(); static if (_WIN32_IE >= 0x300) { BOOL InitCommonControlsEx(LPINITCOMMONCONTROLSEX); } int LBItemFromPt(HWND, POINT, BOOL); } int ImageList_AddIcon(HIMAGELIST himl, HICON hicon) { return ImageList_ReplaceIcon(himl, -1, hicon); } HICON ImageList_ExtractIcon(HINSTANCE hi, HIMAGELIST himl, int i) { return ImageList_GetIcon(himl, i, 0); } HIMAGELIST ImageList_LoadBitmap(HINSTANCE hi, LPCTSTR lpbmp, int cx, int cGrow, COLORREF crMask) { return ImageList_LoadImage(hi, lpbmp, cx, cGrow, crMask, IMAGE_BITMAP, 0); } BOOL ImageList_RemoveAll(HIMAGELIST himl) { return ImageList_Remove(himl, -1); } COLORREF ListView_GetBkColor(HWND w) { return cast(COLORREF) SendMessage(w, LVM_GETBKCOLOR, 0, 0); } HIMAGELIST ListView_GetImageList(HWND w, int i) { return cast(HIMAGELIST) SendMessage(w, LVM_GETIMAGELIST, i, 0); } int ListView_GetItemCount(HWND w) { return cast(int) SendMessage(w, LVM_GETITEMCOUNT, 0, 0); } BOOL ListView_GetItem(HWND w, LPLVITEM pitem) { return cast(BOOL) SendMessage(w, LVM_GETITEM, 0, cast(LPARAM) pitem); } BOOL ListView_SetBkColor(HWND w, COLORREF c) { return cast(BOOL) SendMessage(w, LVM_SETBKCOLOR, 0, cast(LPARAM) c); } HIMAGELIST ListView_SetImageList(HWND w, HIMAGELIST h, int i) { return cast(HIMAGELIST) SendMessage(w, LVM_SETIMAGELIST, i, cast(LPARAM) h); } BOOL ListView_SetItem(HWND w, const(LV_ITEM)* i) { return cast(BOOL) SendMessage(w, LVM_SETITEM, 0, cast(LPARAM) i); } int ListView_InsertItem(HWND w, const(LV_ITEM)* i) { return cast(int) SendMessage(w, LVM_INSERTITEM, 0, cast(LPARAM) i); } BOOL ListView_DeleteItem(HWND w, int i) { return cast(BOOL) SendMessage(w, LVM_DELETEITEM, i, 0); } BOOL ListView_DeleteAllItems(HWND w) { return cast(BOOL) SendMessage(w, LVM_DELETEALLITEMS, 0, 0); } UINT ListView_GetCallbackMask(HWND w) { return cast(UINT) SendMessage(w, LVM_GETCALLBACKMASK, 0, 0); } BOOL ListView_SetCallbackMask(HWND w, UINT m) { return cast(BOOL) SendMessage(w, LVM_SETCALLBACKMASK, m, 0); } int ListView_GetNextItem(HWND w, int i, UINT f) { return cast(int) SendMessage(w, LVM_GETNEXTITEM, i, MAKELPARAM(cast(ushort)f, 0)); } int ListView_FindItem(HWND w, int i, const(LV_FINDINFO)* p) { return cast(int) SendMessage(w, LVM_FINDITEM, i, cast(LPARAM) p); } BOOL ListView_GetItemRect(HWND w, int i, LPRECT p, int c) { return cast(BOOL) SendMessage(w, LVM_GETITEMRECT, i, p ? (p.left = c, cast(LPARAM) p) : 0); } BOOL ListView_SetItemPosition(HWND w, int i, int x, int y) { return cast(BOOL) SendMessage(w, LVM_SETITEMPOSITION, i, MAKELPARAM(cast(ushort)x, cast(ushort)y)); } BOOL ListView_GetItemPosition(HWND w, int i, POINT* p) { return cast(BOOL) SendMessage(w, LVM_GETITEMPOSITION, i, cast(LPARAM) p); } DWORD ListView_GetItemSpacing(HWND w, BOOL f) { return cast(DWORD) SendMessage(w, LVM_GETITEMSPACING, f, 0); } int ListView_GetStringWidth(HWND w, LPCSTR s) { return cast(int) SendMessage(w, LVM_GETSTRINGWIDTH, 0, cast(LPARAM) s); } int ListView_HitTest(HWND w, LPLVHITTESTINFO p) { return cast(int) SendMessage(w, LVM_HITTEST, 0, cast(LPARAM) p); } BOOL ListView_EnsureVisible(HWND w, int i, BOOL f) { return cast(BOOL) SendMessage(w, LVM_ENSUREVISIBLE, i, MAKELPARAM(cast(ushort)f, 0)); } BOOL ListView_Scroll(HWND w, int dx, int dy) { return cast(BOOL) SendMessage(w, LVM_SCROLL, dx, dy); } BOOL ListView_RedrawItems(HWND w, int f, int l) { return cast(BOOL) SendMessage(w, LVM_REDRAWITEMS, f, l); } BOOL ListView_Arrange(HWND w, UINT c) { return cast(BOOL) SendMessage(w, LVM_ARRANGE, c, 0); } HWND ListView_EditLabel(HWND w, int i) { return cast(HWND) SendMessage(w, LVM_EDITLABEL, i, 0); } HWND ListView_GetEditControl(HWND w) { return cast(HWND) SendMessage(w, LVM_GETEDITCONTROL, 0, 0); } BOOL ListView_GetColumn(HWND w, int i, LPLVCOLUMN p) { return cast(BOOL) SendMessage(w, LVM_GETCOLUMN, i, cast(LPARAM) p); } BOOL ListView_SetColumn(HWND w, int i, const(LV_COLUMN)* p) { return cast(BOOL) SendMessage(w, LVM_SETCOLUMN, i, cast(LPARAM) p); } int ListView_InsertColumn(HWND w, int i, const(LV_COLUMN)* p) { return cast(int) SendMessage(w, LVM_INSERTCOLUMN, i, cast(LPARAM) p); } BOOL ListView_DeleteColumn(HWND w, int i) { return cast(BOOL) SendMessage(w, LVM_DELETECOLUMN, i, 0); } int ListView_GetColumnWidth(HWND w, int i) { return cast(int) SendMessage(w, LVM_GETCOLUMNWIDTH, i, 0); } BOOL ListView_SetColumnWidth(HWND w, int i, int x) { return cast(BOOL) SendMessage(w, LVM_SETCOLUMNWIDTH, i, MAKELPARAM(cast(ushort)x, 0)); } HIMAGELIST ListView_CreateDragImage(HWND w, int i, LPPOINT p) { return cast(HIMAGELIST) SendMessage(w, LVM_CREATEDRAGIMAGE, i, cast(LPARAM) p); } BOOL ListView_GetViewRect(HWND w, RECT* p) { return cast(BOOL) SendMessage(w, LVM_GETVIEWRECT, 0, cast(LPARAM) p); } COLORREF ListView_GetTextColor(HWND w) { return cast(COLORREF) SendMessage(w, LVM_GETTEXTCOLOR, 0, 0); } BOOL ListView_SetTextColor(HWND w, COLORREF c) { return cast(BOOL) SendMessage(w, LVM_SETTEXTCOLOR, 0, cast(LPARAM) c); } COLORREF ListView_GetTextBkColor(HWND w) { return cast(COLORREF) SendMessage(w, LVM_GETTEXTBKCOLOR, 0, 0); } BOOL ListView_SetTextBkColor(HWND w, COLORREF c) { return cast(BOOL) SendMessage(w, LVM_SETTEXTBKCOLOR, 0, cast(LPARAM) c); } int ListView_GetTopIndex(HWND w) { return cast(int) SendMessage(w, LVM_GETTOPINDEX, 0, 0); } int ListView_GetCountPerPage(HWND w) { return cast(int) SendMessage(w, LVM_GETCOUNTPERPAGE, 0, 0); } BOOL ListView_GetOrigin(HWND w, LPPOINT p) { return cast(BOOL) SendMessage(w, LVM_GETORIGIN, 0, cast(LPARAM) p); } BOOL ListView_Update(HWND w, WPARAM i) { return cast(BOOL) SendMessage(w, LVM_UPDATE, i, 0); } void ListView_SetItemState(HWND w, int i, UINT d, UINT m) { LV_ITEM _lvi; _lvi.stateMask = m; _lvi.state = d; SendMessage(w, LVM_SETITEMSTATE, i, cast(LPARAM) &_lvi); } UINT ListView_GetItemState(HWND w, int i, UINT m) { return cast(UINT) SendMessage(w, LVM_GETITEMSTATE, i, m); } void ListView_GetItemText(HWND w, int i, int iS, LPTSTR s, int n) { LV_ITEM _lvi; _lvi.iSubItem = iS; _lvi.cchTextMax = n; _lvi.pszText = s; SendMessage(w, LVM_GETITEMTEXT, i, cast(LPARAM) &_lvi); } void ListView_SetItemText(HWND w, int i, int iS, LPTSTR s) { LV_ITEM _lvi; _lvi.iSubItem = iS; _lvi.pszText = s; SendMessage(w, LVM_SETITEMTEXT, i, cast(LPARAM) &_lvi); } void ListView_SetItemCount(HWND w, int n) { SendMessage(w, LVM_SETITEMCOUNT, n, 0); } BOOL ListView_SortItems(HWND w, PFNLVCOMPARE f, LPARAM l) { return cast(BOOL) SendMessage(w, LVM_SORTITEMS, l, cast(LPARAM) f); } void ListView_SetItemPosition32(HWND w, int i, int x, int y) { POINT p; p.x = x; p.y = y; SendMessage(w, LVM_SETITEMPOSITION32, i, cast(LPARAM) &p); } UINT ListView_GetSelectedCount(HWND w) { return cast(UINT) SendMessage(w, LVM_GETSELECTEDCOUNT, 0, 0); } UINT ListView_GetCheckState(HWND w, UINT i) { return ((cast(UINT) SendMessage(w, LVM_GETITEMSTATE, i, LVIS_STATEIMAGEMASK)) >> 12) - 1; } void ListView_SetCheckState(HWND w, UINT i, BOOL f) { ListView_SetItemState(w, i, INDEXTOSTATEIMAGEMASK(f ? 2 : 1), LVIS_STATEIMAGEMASK); } BOOL ListView_GetISearchString(HWND w, LPSTR lpsz) { return cast(BOOL) SendMessage(w, LVM_GETISEARCHSTRING, 0, cast(LPARAM) lpsz); } void ListView_CancelEditLabel(HWND w) { SendMessage(w, LVM_CANCELEDITLABEL, 0, 0); } int ListView_EnableGroupView(HWND w, BOOL i) { return cast(int) SendMessage(w, LVM_ENABLEGROUPVIEW, i, 0); } //static if (_WIN32_WINNT >= 0x500 || _WIN32_IE >= 0x500) { BOOL ListView_SortItemsEx(HWND w, PFNLVCOMPARE c, LPARAM p) { return cast(BOOL) SendMessage(w, LVM_SORTITEMSEX, cast(WPARAM) p, cast(LPARAM)c); } //} static if (_WIN32_WINNT >= 0x501) { int ListView_GetGroupInfo(HWND w, int i, PLVGROUP p) { return cast(int) SendMessage(w, LVM_GETGROUPINFO, i, cast(LPARAM) p); } void ListView_GetGroupMetrics(HWND w, PLVGROUPMETRICS p) { SendMessage(w, LVM_GETGROUPMETRICS, 0, cast(LPARAM) p); } BOOL ListView_GetInsertMark(HWND w, PLVINSERTMARK p) { return cast(BOOL) SendMessage(w, LVM_GETINSERTMARK, 0, cast(LPARAM) p); } COLORREF ListView_GetInsertMarkColor(HWND w) { return cast(COLORREF) SendMessage(w, LVM_GETINSERTMARKCOLOR, 0, 0); } int ListView_GetInsertMarkRect(HWND w, LPRECT p) { return cast(int) SendMessage(w, LVM_GETINSERTMARKRECT, 0, cast(LPARAM) p); } COLORREF ListView_GetOutlineColor(HWND w) { return cast(COLORREF) SendMessage(w, LVM_GETOUTLINECOLOR, 0, 0); } UINT ListView_GetSelectedColumn(HWND w) { return cast(UINT) SendMessage(w, LVM_GETSELECTEDCOLUMN, 0, 0); } void ListView_GetTileInfo(HWND w, PLVTILEINFO p) { SendMessage(w, LVM_GETTILEINFO, 0, cast(LPARAM) p); } void ListView_GetTileViewInfo(HWND w, PLVTILEVIEWINFO p) { SendMessage(w, LVM_GETTILEVIEWINFO, 0, cast(LPARAM) p); } DWORD ListView_GetView(HWND w) { return cast(DWORD) SendMessage(w, LVM_GETVIEW, 0, 0); } BOOL ListView_HasGroup(HWND w, int i) { return cast(BOOL) SendMessage(w, LVM_HASGROUP, i, 0); } int ListView_InsertGroup(HWND w, int i, PLVGROUP p) { return cast(int) SendMessage(w, LVM_INSERTGROUP, i, cast(LPARAM) p); } void ListView_InsertGroupSorted(HWND w, PLVINSERTGROUPSORTED p) { SendMessage(w, LVM_INSERTGROUPSORTED, cast(WPARAM) p, 0); } BOOL ListView_InsertMarkHitTest(HWND w, LPPOINT p, PLVINSERTMARK t) { return cast(BOOL) SendMessage(w, LVM_INSERTMARKHITTEST, cast(WPARAM) p, cast(LPARAM) t); } BOOL ListView_IsGroupViewEnabled(HWND w) { return cast(BOOL) SendMessage(w, LVM_ISGROUPVIEWENABLED, 0, 0); } UINT ListView_MapIDToIndex(HWND w, UINT i) { return cast(UINT) SendMessage(w, LVM_MAPIDTOINDEX, i, 0); } /* ??? MSDN documents this as "Not implemented", except in relation to * Windows CE/Mobile. */ void ListView_MoveGroup(HWND w, int i, int t) { SendMessage(w, LVM_MOVEGROUP, i, t); } void ListView_RemoveAllGroups(HWND w) { SendMessage(w, LVM_REMOVEALLGROUPS, 0, 0); } int ListView_RemoveGroup(HWND w, int i) { return cast(int) SendMessage(w, LVM_REMOVEGROUP, i, 0); } int ListView_SetGroupInfo(HWND w, int i, PLVGROUP p) { return cast(int) SendMessage(w, LVM_SETGROUPINFO, i, cast(LPARAM) p); } void ListView_SetGroupMetrics(HWND w, PLVGROUPMETRICS p) { SendMessage(w, LVM_SETGROUPMETRICS, 0, cast(LPARAM) p); } BOOL ListView_SetInfoTip(HWND w, PLVSETINFOTIP p) { return cast(BOOL) SendMessage(w, LVM_SETINFOTIP, 0, cast(LPARAM) p); } BOOL ListView_SetInsertMark(HWND w, PLVINSERTMARK p) { return cast(BOOL) SendMessage(w, LVM_SETINSERTMARK, 0, cast(LPARAM) p); } COLORREF ListView_SetInsertMarkColor(HWND w, COLORREF c) { return cast(COLORREF) SendMessage(w, LVM_SETINSERTMARKCOLOR, 0, c); } COLORREF ListView_SetOutlineColor(HWND w, COLORREF c) { return cast(COLORREF) SendMessage(w, LVM_SETOUTLINECOLOR, 0, c); } void ListView_SetSelectedColumn(HWND w, int i) { SendMessage(w, LVM_SETSELECTEDCOLUMN, i, 0); } BOOL ListView_SetTileInfo(HWND w, PLVTILEINFO p) { return cast(BOOL) SendMessage(w, LVM_SETTILEINFO, 0, cast(LPARAM) p); } BOOL ListView_SetTileViewInfo(HWND w, PLVTILEVIEWINFO p) { return cast(BOOL) SendMessage(w, LVM_SETTILEVIEWINFO, 0, cast(LPARAM) p); } int ListView_SetView(HWND w, DWORD i) { return cast(int) SendMessage(w, LVM_SETVIEW, i, 0); } int ListView_SortGroups(HWND w, PFNLVGROUPCOMPARE c, LPVOID p) { return cast(int) SendMessage(w, LVM_SORTGROUPS, cast(WPARAM) c, cast(LPARAM) p); } } static if (_WIN32_WINNT >= 0x501) { enum { CBM_FIRST = 0x1700, CB_SETMINVISIBLE = CBM_FIRST + 1, CB_GETMINVISIBLE = CBM_FIRST + 2, CB_SETCUEBANNER = CBM_FIRST + 3, CB_GETCUEBANNER = CBM_FIRST + 4, } BOOL ComboBox_SetMinVisible(HWND w, INT i) { return cast(BOOL) SendMessage(w, CB_SETMINVISIBLE, cast(WPARAM) i, 0); } int ComboBox_GetMinVisible(HWND w) { return cast(int) SendMessage(w, CB_GETMINVISIBLE, 0, 0); } } extern (Windows) BOOL MakeDragList(HWND); extern (Windows) void MenuHelp(UINT, WPARAM, LPARAM, HMENU, HINSTANCE, HWND, PUINT); COLORREF MonthCal_GetColor(HWND hwnd, INT icolor) { return cast(COLORREF) SendMessage(hwnd, MCM_GETCOLOR, cast(WPARAM) icolor, 0); } BOOL MonthCal_GetCurSel(HWND hwnd, LPSYSTEMTIME lpsystime) { return cast(BOOL) SendMessage(hwnd, MCM_GETCURSEL, 0, cast(LPARAM) lpsystime); } DWORD MonthCal_GetFirstDayOfWeek(HWND hwnd) { return cast(DWORD) SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0); } DWORD MonthCal_GetMaxSelCount(HWND hwnd) { return cast(DWORD) SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0); } DWORD MonthCal_GetMaxTodayWidth(HWND hwnd) { return cast(DWORD) SendMessage(hwnd, MCM_GETMAXTODAYWIDTH, 0, 0); } BOOL MonthCal_GetMinReqRect(HWND hwnd, LPRECT lpRectInfo) { return cast(BOOL) SendMessage(hwnd, MCM_GETMINREQRECT, 0, cast(LPARAM) lpRectInfo); } INT MonthCal_GetMonthDelta(HWND hwnd) { return cast(INT) SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0); } INT MonthCal_GetMonthRange(HWND hwnd, DWORD flag, LPSYSTEMTIME systimearray) { return cast(INT) SendMessage(hwnd, MCM_GETMONTHRANGE, cast(WPARAM) flag, cast(LPARAM) systimearray); } DWORD MonthCal_GetRange(HWND hwnd, LPSYSTEMTIME systimearray) { return cast(DWORD) SendMessage(hwnd, MCM_GETRANGE, 0, cast(LPARAM) systimearray); } BOOL MonthCal_GetSelRange(HWND hwnd, LPSYSTEMTIME systimearray) { return cast(BOOL) SendMessage(hwnd, MCM_GETSELRANGE, 0, cast(LPARAM) systimearray); } BOOL MonthCal_GetToday(HWND hwnd, LPSYSTEMTIME systime) { return cast(BOOL) SendMessage(hwnd, MCM_GETTODAY, 0, cast(LPARAM) systime); } BOOL MonthCal_GetUnicodeFormat(HWND hwnd) { return cast(BOOL) SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0); } DWORD MonthCal_HitTest(HWND hwnd, PMCHITTESTINFO pmchittest) { return cast(DWORD) SendMessage(hwnd, MCM_HITTEST, 0, cast(LPARAM) pmchittest); } COLORREF MonthCal_SetColor(HWND hwnd, INT icolor, COLORREF clr) { return cast(COLORREF) SendMessage(hwnd, MCM_SETCOLOR, cast(WPARAM) icolor, cast(LPARAM) clr); } BOOL MonthCal_SetCurSel(HWND hwnd, LPSYSTEMTIME lpsystime) { return cast(BOOL) SendMessage(hwnd, MCM_SETCURSEL, 0, cast(LPARAM) lpsystime); } BOOL MonthCal_SetDayState(HWND hwnd, INT imonths, LPMONTHDAYSTATE lpdatestatearray) { return cast(BOOL) SendMessage(hwnd, MCM_SETDAYSTATE, cast(WPARAM) imonths, cast(LPARAM) lpdatestatearray); } DWORD MonthCal_SetFirstDayOfWeek(HWND hwnd, INT iday) { return cast(DWORD) SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, cast(LPARAM) iday); } BOOL MonthCal_SetMaxSelCount(HWND hwnd, UINT imax) { return cast(BOOL) SendMessage(hwnd, MCM_SETMAXSELCOUNT, cast(WPARAM) imax, 0); } INT MonthCal_SetMonthDelta(HWND hwnd, INT idelta) { return cast(INT) SendMessage(hwnd, MCM_SETMONTHDELTA, cast(WPARAM) idelta, 0); } BOOL MonthCal_SetSelRange(HWND hwnd, LPSYSTEMTIME systimearray) { return cast(BOOL) SendMessage(hwnd, MCM_SETSELRANGE, 0, cast(LPARAM) systimearray); } void MonthCal_SetToday(HWND hwnd, LPSYSTEMTIME systime) { SendMessage(hwnd, MCM_SETTODAY, 0, cast(LPARAM) systime); } BOOL MonthCal_SetUnicodeFormat(HWND hwnd, BOOL unicode) { return cast(BOOL) SendMessage(hwnd, MCM_SETUNICODEFORMAT, cast(WPARAM) unicode, 0); } BOOL MonthCal_SetRange(HWND w, DWORD f, LPSYSTEMTIME st) { return cast(BOOL) SendMessage(w, MCM_SETRANGE, cast(WPARAM) f, cast(LPARAM) st); } extern (Windows) BOOL ShowHideMenuCtl(HWND, UINT_PTR, PINT); BOOL TabCtrl_GetItem(HWND w, int i, LPTCITEM p) { return cast(BOOL) SendMessage(w, TCM_GETITEM, i, cast(LPARAM) p); } BOOL TabCtrl_SetItem(HWND w, int i, LPTCITEM p) { return cast(BOOL) SendMessage(w, TCM_SETITEM, i, cast(LPARAM) p); } int TabCtrl_InsertItem(HWND w, int i, const(TC_ITEM)* p) { return cast(int) SendMessage(w, TCM_INSERTITEM, i, cast(LPARAM) p); } BOOL TabCtrl_DeleteItem(HWND w, int i) { return cast(BOOL) SendMessage(w, TCM_DELETEITEM, i, 0); } BOOL TabCtrl_DeleteAllItems(HWND w) { return cast(BOOL) SendMessage(w, TCM_DELETEALLITEMS, 0, 0); } BOOL TabCtrl_GetItemRect(HWND w, int i, LPRECT p) { return cast(BOOL) SendMessage(w, TCM_GETITEMRECT, i, cast(LPARAM) p); } int TabCtrl_GetCurSel(HWND w) { return cast(int) SendMessage(w, TCM_GETCURSEL, 0, 0); } int TabCtrl_SetCurSel(HWND w, int i) { return cast(int) SendMessage(w, TCM_SETCURSEL, i, 0); } int TabCtrl_HitTest(HWND w, LPTCHITTESTINFO p) { return cast(int) SendMessage(w, TCM_HITTEST, 0, cast(LPARAM) p); } BOOL TabCtrl_SetItemExtra(HWND w, int c) { return cast(BOOL) SendMessage(w, TCM_SETITEMEXTRA, c, 0); } int TabCtrl_AdjustRect(HWND w, BOOL b, LPRECT p) { return cast(int) SendMessage(w, TCM_ADJUSTRECT, b, cast(LPARAM) p); } DWORD TabCtrl_SetItemSize(HWND w, int x, int y) { return cast(DWORD) SendMessage(w, TCM_SETITEMSIZE, 0, MAKELPARAM(cast(ushort)x, cast(ushort)y)); } void TabCtrl_RemoveImage(HWND w, int i) { SendMessage(w, TCM_REMOVEIMAGE, i, 0); } void TabCtrl_SetPadding(HWND w, int x, int y) { SendMessage(w, TCM_SETPADDING, 0, MAKELPARAM(cast(ushort)x, cast(ushort)y)); } int TabCtrl_GetRowCount(HWND w) { return cast(int) SendMessage(w, TCM_GETROWCOUNT, 0, 0); } HWND TabCtrl_GetToolTips(HWND w) { return cast(HWND) SendMessage(w, TCM_GETTOOLTIPS, 0, 0); } void TabCtrl_SetToolTips(HWND w, HWND t) { SendMessage(w, TCM_SETTOOLTIPS, cast(WPARAM) t, 0); } int TabCtrl_GetCurFocus(HWND w) { return cast(int) SendMessage(w, TCM_GETCURFOCUS, 0, 0); } void TabCtrl_SetCurFocus(HWND w, int i) { SendMessage(w, TCM_SETCURFOCUS, i, 0); } HIMAGELIST TabCtrl_GetImageList(HWND w) { return cast(HIMAGELIST) SendMessage(w, TCM_GETIMAGELIST, 0, 0); } HIMAGELIST TabCtrl_SetImageList(HWND w, HIMAGELIST h) { return cast(HIMAGELIST) SendMessage(w, TCM_SETIMAGELIST, 0, cast(LPARAM) h); } int TabCtrl_GetItemCount(HWND w) { return cast(int) SendMessage(w, TCM_GETITEMCOUNT, 0, 0); } extern (Windows) BOOL _TrackMouseEvent(LPTRACKMOUSEEVENT); HTREEITEM TreeView_InsertItem(HWND w, LPTVINSERTSTRUCT i) { return cast(HTREEITEM) SendMessage(w, TVM_INSERTITEM, 0, cast(LPARAM) i); } BOOL TreeView_DeleteItem(HWND w, HTREEITEM i) { return cast(BOOL) SendMessage(w, TVM_DELETEITEM, 0, cast(LPARAM) i); } BOOL TreeView_DeleteAllItems(HWND w) { return cast(BOOL) SendMessage(w, TVM_DELETEITEM, 0, cast(LPARAM) TVI_ROOT); } BOOL TreeView_Expand(HWND w, HTREEITEM i, UINT c) { return cast(BOOL) SendMessage(w, TVM_EXPAND, c, cast(LPARAM) i); } BOOL TreeView_GetItemRect(HWND w, HTREEITEM i, LPRECT p, BOOL c) { *cast(HTREEITEM*) p = i; return cast(BOOL) SendMessage(w, TVM_GETITEMRECT, c, cast(LPARAM) p); } UINT TreeView_GetCount(HWND w) { return cast(UINT) SendMessage(w, TVM_GETCOUNT, 0, 0); } UINT TreeView_GetIndent(HWND w) { return cast(UINT) SendMessage(w, TVM_GETINDENT, 0, 0); } BOOL TreeView_SetIndent(HWND w, INT i) { return cast(BOOL) SendMessage(w, TVM_SETINDENT, i, 0); } HIMAGELIST TreeView_GetImageList(HWND w, INT i) { return cast(HIMAGELIST) SendMessage(w, TVM_GETIMAGELIST, i, 0); } HIMAGELIST TreeView_SetImageList(HWND w, HIMAGELIST h, INT i) { return cast(HIMAGELIST) SendMessage(w, TVM_SETIMAGELIST, i, cast(LPARAM) h); } HTREEITEM TreeView_GetNextItem(HWND w, HTREEITEM i, UINT c) { return cast(HTREEITEM) SendMessage(w, TVM_GETNEXTITEM, c, cast(LPARAM) i); } HTREEITEM TreeView_GetChild(HWND w, HTREEITEM i) { return TreeView_GetNextItem(w, i, TVGN_CHILD); } HTREEITEM TreeView_GetNextSibling(HWND w, HTREEITEM i) { return TreeView_GetNextItem(w, i, TVGN_NEXT); } HTREEITEM TreeView_GetPrevSibling(HWND w, HTREEITEM i) { return TreeView_GetNextItem(w, i, TVGN_PREVIOUS); } HTREEITEM TreeView_GetParent(HWND w, HTREEITEM i) { return TreeView_GetNextItem(w, i, TVGN_PARENT); } HTREEITEM TreeView_GetFirstVisible(HWND w) { return TreeView_GetNextItem(w, null, TVGN_FIRSTVISIBLE); } HTREEITEM TreeView_GetNextVisible(HWND w, HTREEITEM i) { return TreeView_GetNextItem(w, i, TVGN_NEXTVISIBLE); } HTREEITEM TreeView_GetPrevVisible(HWND w, HTREEITEM i) { return TreeView_GetNextItem(w, i, TVGN_PREVIOUSVISIBLE); } HTREEITEM TreeView_GetSelection(HWND w) { return TreeView_GetNextItem(w, null, TVGN_CARET); } HTREEITEM TreeView_GetDropHilight(HTREEITEM w) { return TreeView_GetNextItem(w, null, TVGN_DROPHILITE); } HTREEITEM TreeView_GetRoot(HWND w) { return TreeView_GetNextItem(w, null, TVGN_ROOT); } BOOL TreeView_Select(HWND w, HTREEITEM i, UINT c) { return cast(BOOL) SendMessage(w, TVM_SELECTITEM, c, cast(LPARAM) i); } BOOL TreeView_SelectItem(HWND w, HTREEITEM i) { return TreeView_Select(w, i, TVGN_CARET); } BOOL TreeView_SelectDropTarget(HWND w, HTREEITEM i) { return TreeView_Select(w, i, TVGN_DROPHILITE); } BOOL TreeView_SelectSetFirstVisible(HWND w, HTREEITEM i) { return TreeView_Select(w, i, TVGN_FIRSTVISIBLE); } BOOL TreeView_GetItem(HWND w, LPTVITEM i) { return cast(BOOL) SendMessage(w, TVM_GETITEM, 0, cast(LPARAM) i); } BOOL TreeView_SetItem(HWND w, const(TV_ITEM)* i) { return cast(BOOL) SendMessage(w, TVM_SETITEM, 0, cast(LPARAM) i); } HWND TreeView_EditLabel(HWND w, HTREEITEM i) { return cast(HWND) SendMessage(w, TVM_EDITLABEL, 0, cast(LPARAM) i); } HWND TreeView_GetEditControl(HWND w) { return cast(HWND) SendMessage(w, TVM_GETEDITCONTROL, 0, 0); } UINT TreeView_GetVisibleCount(HWND w) { return cast(UINT) SendMessage(w, TVM_GETVISIBLECOUNT, 0, 0); } HTREEITEM TreeView_HitTest(HWND w, LPTVHITTESTINFO p) { return cast(HTREEITEM) SendMessage(w, TVM_HITTEST, 0, cast(LPARAM) p); } HIMAGELIST TreeView_CreateDragImage(HWND w, HTREEITEM i) { return cast(HIMAGELIST) SendMessage(w, TVM_CREATEDRAGIMAGE, 0, cast(LPARAM) i); } BOOL TreeView_SortChildren(HWND w, HTREEITEM i, BOOL r) { return cast(BOOL) SendMessage(w, TVM_SORTCHILDREN, r, cast(LPARAM) i); } BOOL TreeView_EnsureVisible(HWND w, HTREEITEM i) { return cast(BOOL) SendMessage(w, TVM_ENSUREVISIBLE, 0, cast(LPARAM) i); } BOOL TreeView_SortChildrenCB(HWND w, LPTVSORTCB s, BOOL r) { return cast(BOOL) SendMessage(w, TVM_SORTCHILDRENCB, r, cast(LPARAM) s); } BOOL TreeView_EndEditLabelNow(HWND w, BOOL f) { return cast(BOOL) SendMessage(w, TVM_ENDEDITLABELNOW, f, 0); } BOOL TreeView_GetISearchString(HWND w, LPTSTR s) { return cast(BOOL) SendMessage(w, TVM_GETISEARCHSTRING, 0, cast(LPARAM) s); } static if (_WIN32_IE >= 0x300) { DWORD ListView_ApproximateViewRect(HWND w, int iw, int ih, int i) { return cast(DWORD) SendMessage(w, LVM_APPROXIMATEVIEWRECT, i, MAKELPARAM(cast(ushort)iw, cast(ushort)ih)); } DWORD ListView_SetExtendedListViewStyle(HWND w, DWORD s) { return cast(DWORD) SendMessage(w, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, s); } DWORD ListView_GetExtendedListViewStyle(HWND w) { return cast(DWORD) SendMessage(w, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); } BOOL ListView_SetColumnOrderArray(HWND w, int i, int* a) { return cast(BOOL) SendMessage(w, LVM_SETCOLUMNORDERARRAY, cast(WPARAM) i, cast(LPARAM) a); } BOOL ListView_GetColumnOrderArray(HWND w, int i, int* a) { return cast(BOOL) SendMessage(w, LVM_GETCOLUMNORDERARRAY, cast(WPARAM) i, cast(LPARAM) a); } HWND ListView_GetHeader(HWND w) { return cast(HWND) SendMessage(w, LVM_GETHEADER, 0, 0); } HCURSOR ListView_GetHotCursor(HWND w) { return cast(HCURSOR) SendMessage(w, LVM_GETHOTCURSOR, 0, 0); } INT ListView_GetHotItem(HWND w) { return cast(INT) SendMessage(w, LVM_GETHOTITEM, 0, 0); } BOOL ListView_GetSubItemRect(HWND w, int i, int isi, int c, LPRECT p) { return cast(BOOL) SendMessage(w, LVM_GETSUBITEMRECT, i, p ? (p.left = c, p.top = isi, cast(LPARAM) p) : 0); } HCURSOR ListView_SetHotCursor(HWND w, HCURSOR c) { return cast(HCURSOR) SendMessage(w, LVM_SETHOTCURSOR, 0, cast(LPARAM) c); } INT ListView_SetHotItem(HWND w, INT i) { return cast(INT) SendMessage(w, LVM_SETHOTITEM, cast(WPARAM) i, 0); } DWORD ListView_SetIconSpacing(HWND w, int x, int y) { return cast(DWORD) SendMessage(w, LVM_SETICONSPACING, 0, MAKELONG(cast(ushort)x, cast(ushort)y)); } INT ListView_SubItemHitTest(HWND w, LPLVHITTESTINFO p) { return cast(INT) SendMessage(w, LVM_SUBITEMHITTEST, 0, cast(LPARAM) p); } BOOL ListView_SetItemCountEx(HWND w, int i, DWORD f) { return cast(BOOL) SendMessage(w, LVM_SETITEMCOUNT, i, cast(LPARAM) f); } extern (Windows) { WINBOOL ImageList_SetImageCount(HIMAGELIST, UINT); WINBOOL ImageList_Copy(HIMAGELIST, int, HIMAGELIST, int, UINT); WINBOOL ImageList_DrawIndirect(IMAGELISTDRAWPARAMS*); } int TabCtrl_SetMinTabWidth(HWND hwnd, int x) { return cast(int) SendMessage(hwnd, TCM_SETMINTABWIDTH, 0, x); } VOID TabCtrl_DeselectAll(HWND hwnd, UINT fExcludeFocus) { SendMessage(hwnd, TCM_DESELECTALL, fExcludeFocus, 0); } HWND TreeView_GetToolTips(HWND w) { return cast(HWND) SendMessage(w, TVM_GETTOOLTIPS, 0, 0); } HWND TreeView_SetToolTips(HWND w, HWND wt) { return cast(HWND) SendMessage(w, TVM_SETTOOLTIPS, cast(WPARAM) wt, 0); } } static if (_WIN32_IE >= 0x400) { BOOL ListView_GetBkImage(HWND h, LPLVBKIMAGE plvbki) { return cast(BOOL) SendMessage(h, LVM_GETBKIMAGE, 0, cast(LPARAM) plvbki); } BOOL ListView_SetBkImage(HWND h, LPLVBKIMAGE plvbki) { return cast(BOOL) SendMessage(h, LVM_SETBKIMAGE, 0, cast(LPARAM) plvbki); } DWORD ListView_SetExtendedListViewStyleEx(HWND w, DWORD m, DWORD s) { return cast(DWORD) SendMessage(w, LVM_SETEXTENDEDLISTVIEWSTYLE, m, s); } VOID ListView_SetWorkAreas(HWND w, INT n, LPRECT r) { SendMessage(w, LVM_SETWORKAREAS, cast(WPARAM) n, cast(LPARAM) r); } VOID ListView_GetWorkAreas(HWND w, INT n, LPRECT r) { SendMessage(w, LVM_GETWORKAREAS, cast(WPARAM) n, cast(LPARAM) r); } BOOL ListView_GetNumberOfWorkAreas(HWND w, LPUINT n) { return cast(BOOL) SendMessage(w, LVM_GETNUMBEROFWORKAREAS, 0, cast(LPARAM) n); } DWORD ListView_SetHoverTime(HWND w, DWORD t) { return cast(DWORD) SendMessage(w, LVM_SETHOVERTIME, 0, cast(LPARAM) t); } DWORD ListView_GetHoverTime(HWND w) { return cast(DWORD) SendMessage(w, LVM_GETHOVERTIME, 0, 0); } INT ListView_GetSelectionMark(HWND w) { return cast(INT) SendMessage(w, LVM_GETSELECTIONMARK, 0, 0); } INT ListView_SetSelectionMark(HWND w, INT i) { return cast(INT) SendMessage(w, LVM_SETSELECTIONMARK, 0, cast(LPARAM) i); } HWND ListView_SetToolTips(HWND w, HWND n) { return cast(HWND) SendMessage(w, LVM_SETTOOLTIPS, cast(WPARAM) n, 0); } HWND ListView_GetToolTips(HWND w) { return cast(HWND) SendMessage(w, LVM_GETTOOLTIPS, 0, 0); } BOOL ListView_SetUnicodeFormat(HWND w, BOOL f) { return cast(BOOL) SendMessage(w, LVM_SETUNICODEFORMAT, cast(WPARAM) f, 0); } BOOL ListView_GetUnicodeFormat(HWND w) { return cast(BOOL) SendMessage(w, LVM_GETUNICODEFORMAT, 0, 0); } BOOL TabCtrl_HighlightItem(HWND hwnd, INT i, WORD fHighlight) { return cast(BOOL) SendMessage(hwnd, TCM_HIGHLIGHTITEM, cast(WPARAM) i, cast(LPARAM) MAKELONG(fHighlight, 0)); } DWORD TabCtrl_SetExtendedStyle(HWND hwnd, DWORD dw) { return cast(DWORD) SendMessage(hwnd, TCM_SETEXTENDEDSTYLE, 0, dw); } DWORD TabCtrl_GetExtendedStyle(HWND hwnd) { return cast(DWORD) SendMessage(hwnd, TCM_GETEXTENDEDSTYLE, 0, 0); } BOOL TabCtrl_SetUnicodeFormat(HWND hwnd, HWND fUnicode) { return cast(BOOL) SendMessage(hwnd, TCM_SETUNICODEFORMAT, cast(WPARAM) fUnicode, 0); } BOOL TabCtrl_GetUnicodeFormat(HWND hwnd) { return cast(BOOL) SendMessage(hwnd, TCM_GETUNICODEFORMAT, 0, 0); } COLORREF TreeView_GetBkColor(HWND w) { return cast(COLORREF) SendMessage(w, TVM_GETBKCOLOR, 0, 0); } COLORREF TreeView_GetInsertMarkColor(HWND w) { return cast(COLORREF) SendMessage(w, TVM_GETINSERTMARKCOLOR, 0, 0); } int TreeView_GetItemHeight(HWND w) { return cast(int) SendMessage(w, TVM_GETITEMHEIGHT, 0, 0); } UINT TreeView_GetScrollTime(HWND w) { return cast(UINT) SendMessage(w, TVM_GETSCROLLTIME, 0, 0); } COLORREF TreeView_GetTextColor(HWND w) { return cast(COLORREF) SendMessage(w, TVM_GETTEXTCOLOR, 0, 0); } COLORREF TreeView_SetBkColor(HWND w, COLORREF c) { return cast(COLORREF) SendMessage(w, TVM_SETBKCOLOR, 0, cast(LPARAM) c); } COLORREF TreeView_SetInsertMarkColor(HWND w, COLORREF c) { return cast(COLORREF) SendMessage(w, TVM_SETINSERTMARKCOLOR, 0, cast(LPARAM) c); } int TreeView_SetItemHeight(HWND w, SHORT h) { return cast(int) SendMessage(w, TVM_SETITEMHEIGHT, cast(WPARAM) h, 0); } UINT TreeView_SetScrollTime(HWND w, UINT t) { return cast(UINT) SendMessage(w, TVM_SETSCROLLTIME, cast(WPARAM) t, 0); } COLORREF TreeView_SetTextColor(HWND w, COLORREF c) { return cast(COLORREF) SendMessage(w, TVM_SETTEXTCOLOR, 0, cast(LPARAM) c); } BOOL TreeView_SetInsertMark(HWND w, HTREEITEM i, BOOL a) { return cast(BOOL) SendMessage(w, TVM_SETINSERTMARK, cast(WPARAM) a, cast(LPARAM) i); } BOOL TreeView_SetUnicodeFormat(HWND w, BOOL u) { return cast(BOOL) SendMessage(w, TVM_SETUNICODEFORMAT, cast(WPARAM) u, 0); } BOOL TreeView_GetUnicodeFormat(HWND w) { return cast(BOOL) SendMessage(w, TVM_GETUNICODEFORMAT, 0, 0); } HTREEITEM TreeView_GetLastVisible(HWND w) { return TreeView_GetNextItem(w, null, TVGN_LASTVISIBLE); } } static if (_WIN32_IE >= 0x500) { UINT TreeView_GetItemState(HWND w, HTREEITEM i, UINT m) { return cast(UINT) SendMessage(w, TVM_GETITEMSTATE, cast(WPARAM) i, cast(LPARAM) m); } BOOL TreeView_SetItemState(HWND w, HTREEITEM i, UINT d, UINT m) { TVITEM _tvi; _tvi.mask = TVIF_STATE; _tvi.hItem = i; _tvi.stateMask = m; _tvi.state = d; return cast(BOOL) SendMessage(w, TVM_SETITEM, 0, cast(LPARAM) &_tvi); } } //#ifdef _WIN32_WCE // these are PPC only /+ extern (Windows) { HWND CommandBar_Create(HINSTANCE, HWND, int); BOOL CommandBar_Show(HWND, BOOL); int CommandBar_AddBitmap(HWND, HINSTANCE, int, int, int, int); HWND CommandBar_InsertComboBox(HWND, HINSTANCE, int, UINT, WORD, WORD); BOOL CommandBar_InsertMenubar(HWND, HINSTANCE, WORD, WORD ); BOOL CommandBar_InsertMenubarEx(HWND, HINSTANCE, LPTSTR, WORD); BOOL CommandBar_DrawMenuBar(HWND, WORD); HMENU CommandBar_GetMenu(HWND, WORD); BOOL CommandBar_AddAdornments(HWND, DWORD, DWORD); int CommandBar_Height(HWND hwndCB); } // MinGW: These two are not in the DLL void CommandBar_InsertButton(HWND hwnd, int i, LPTBBUTTON lptbbutton) { SendMessage(hwnd, TB_INSERTBUTTON, i, lptbbutton); } alias DestroyWindow CommandBar_Destroy; +/ //#endif // _WIN32_WCE static if (_WIN32_WINNT >= 0x501) { struct EDITBALLOONTIP { DWORD cbStruct; LPCWSTR pszTitle; LPCWSTR pszText; INT ttiIcon; } alias EDITBALLOONTIP* PEDITBALLOONTIP; enum EM_SETCUEBANNER = ECM_FIRST + 1; enum EM_GETCUEBANNER = ECM_FIRST + 2; enum EM_SHOWBALLOONTIP = ECM_FIRST + 3; enum EM_HIDEBALLOONTIP = ECM_FIRST + 4; } static if (_WIN32_WINNT >= 0x600) { enum EM_SETHILITE = ECM_FIRST + 5; enum EM_GETHILITE = ECM_FIRST + 6; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rapi.d0000664000175000017500000000261112776214756022612 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rapi.d) */ module core.sys.windows.rapi; version (Windows): /* Comment from MinGW NOTE: This strictly does not belong in the Win32 API since it's really part of Platform SDK. */ private import core.sys.windows.winbase, core.sys.windows.windef; extern (Windows): enum RAPISTREAMFLAG { STREAM_TIMEOUT_READ } interface IRAPIStream { HRESULT SetRapiStat(RAPISTREAMFLAG, DWORD); HRESULT GetRapiStat(RAPISTREAMFLAG, DWORD*); } alias HRESULT function(DWORD, BYTE, DWORD, BYTE, IRAPIStream) RAPIEXT; struct RAPIINIT { DWORD cbSize = this.sizeof; HANDLE heRapiInit; HRESULT hrRapiInit; } HRESULT CeRapiInit(); HRESULT CeRapiInitEx(RAPIINIT*); BOOL CeCreateProcess(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPWSTR, LPSTARTUPINFO, LPPROCESS_INFORMATION); HRESULT CeRapiUninit(); BOOL CeWriteFile(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED); HANDLE CeCreateFile(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); BOOL CeCreateDirectory(LPCWSTR, LPSECURITY_ATTRIBUTES); DWORD CeGetLastError(); BOOL CeGetFileTime(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME); BOOL CeCloseHandle(HANDLE); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/sql.d0000664000175000017500000003557612776214756022476 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_sql.d) */ module core.sys.windows.sql; version (Windows): public import core.sys.windows.sqltypes; private import core.sys.windows.windef; enum ODBCVER = 0x0351; enum SQL_ACCESSIBLE_PROCEDURES=20; enum SQL_ACCESSIBLE_TABLES=19; enum SQL_ALL_TYPES=0; enum SQL_ALTER_TABLE=86; enum SQL_API_SQLALLOCCONNECT=1; enum SQL_API_SQLALLOCENV=2; enum SQL_API_SQLALLOCSTMT=3; enum SQL_API_SQLBINDCOL=4; enum SQL_API_SQLCANCEL=5; enum SQL_API_SQLCOLUMNS=40; enum SQL_API_SQLCONNECT=7; enum SQL_API_SQLDATASOURCES=57; enum SQL_API_SQLDESCRIBECOL=8; enum SQL_API_SQLDISCONNECT=9; enum SQL_API_SQLERROR=10; enum SQL_API_SQLEXECDIRECT=11; enum SQL_API_SQLEXECUTE=12; enum SQL_API_SQLFETCH=13; enum SQL_API_SQLFREECONNECT=14; enum SQL_API_SQLFREEENV=15; enum SQL_API_SQLFREESTMT=16; enum SQL_API_SQLGETCONNECTOPTION=42; enum SQL_API_SQLGETCURSORNAME=17; enum SQL_API_SQLGETDATA=43; enum SQL_API_SQLGETFUNCTIONS=44; enum SQL_API_SQLGETINFO=45; enum SQL_API_SQLGETSTMTOPTION=46; enum SQL_API_SQLGETTYPEINFO=47; enum SQL_API_SQLNUMRESULTCOLS=18; enum SQL_API_SQLPARAMDATA=48; enum SQL_API_SQLPREPARE=19; enum SQL_API_SQLPUTDATA=49; enum SQL_API_SQLROWCOUNT=20; enum SQL_API_SQLSETCONNECTOPTION=50; enum SQL_API_SQLSETCURSORNAME=21; enum SQL_API_SQLSETPARAM=22; enum SQL_API_SQLSETSTMTOPTION=51; enum SQL_API_SQLSPECIALCOLUMNS=52; enum SQL_API_SQLSTATISTICS=53; enum SQL_API_SQLTABLES=54; enum SQL_API_SQLTRANSACT=23; enum SQL_CB_DELETE=0; enum SQL_CB_CLOSE=1; enum SQL_CB_PRESERVE=2; enum SQL_CHAR=1; enum SQL_CLOSE=0; enum SQL_COMMIT=0; enum SQL_CURSOR_COMMIT_BEHAVIOR=23; enum SQL_DATA_AT_EXEC=-2; enum SQL_DATA_SOURCE_NAME=2; enum SQL_DATA_SOURCE_READ_ONLY=25; enum SQL_DBMS_NAME=17; enum SQL_DBMS_VER=18; enum SQL_DECIMAL=3; enum SQL_DEFAULT_TXN_ISOLATION=26; enum SQL_DOUBLE=8; enum SQL_DROP=1; enum SQL_ERROR=-1; enum SQL_FD_FETCH_NEXT=1; enum SQL_FD_FETCH_FIRST=2; enum SQL_FD_FETCH_LAST=4; enum SQL_FD_FETCH_PRIOR=8; enum SQL_FD_FETCH_ABSOLUTE=16; enum SQL_FD_FETCH_RELATIVE=32; enum SQL_FETCH_ABSOLUTE=5; enum SQL_FETCH_DIRECTION=8; enum SQL_FETCH_FIRST=2; enum SQL_FETCH_LAST=3; enum SQL_FETCH_NEXT=1; enum SQL_FETCH_PRIOR=4; enum SQL_FETCH_RELATIVE=6; enum SQL_FLOAT=6; enum SQL_GD_ANY_COLUMN=1; enum SQL_GD_ANY_ORDER=2; enum SQL_GETDATA_EXTENSIONS=81; enum SQL_IC_LOWER=2; enum SQL_IC_MIXED=4; enum SQL_IC_SENSITIVE=3; enum SQL_IC_UPPER=1; enum SQL_IDENTIFIER_CASE=28; enum SQL_IDENTIFIER_QUOTE_CHAR=29; enum SQL_INDEX_ALL=1; enum SQL_INDEX_CLUSTERED=1; enum SQL_INDEX_HASHED=2; enum SQL_INDEX_OTHER=3; enum SQL_INDEX_UNIQUE=0; enum SQL_INTEGER=4; enum SQL_INTEGRITY=73; enum SQL_INVALID_HANDLE=-2; enum SQL_MAX_CATALOG_NAME_LEN=34; enum SQL_MAX_COLUMN_NAME_LEN=30; enum SQL_MAX_COLUMNS_IN_GROUP_BY=97; enum SQL_MAX_COLUMNS_IN_INDEX=98; enum SQL_MAX_COLUMNS_IN_ORDER_BY=99; enum SQL_MAX_COLUMNS_IN_SELECT=100; enum SQL_MAX_COLUMNS_IN_TABLE=101; enum SQL_MAX_CURSOR_NAME_LEN=31; enum SQL_MAX_INDEX_SIZE=102; enum SQL_MAX_MESSAGE_LENGTH=512; enum SQL_MAX_ROW_SIZE=104; enum SQL_MAX_SCHEMA_NAME_LEN=32; enum SQL_MAX_STATEMENT_LEN=105; enum SQL_MAX_TABLE_NAME_LEN=35; enum SQL_MAX_TABLES_IN_SELECT=106; enum SQL_MAX_USER_NAME_LEN=107; enum SQL_MAXIMUM_CATALOG_NAME_LENGTH=SQL_MAX_CATALOG_NAME_LEN; enum SQL_MAXIMUM_COLUMN_NAME_LENGTH=SQL_MAX_COLUMN_NAME_LEN; enum SQL_MAXIMUM_COLUMNS_IN_GROUP_BY=SQL_MAX_COLUMNS_IN_GROUP_BY; enum SQL_MAXIMUM_COLUMNS_IN_INDEX=SQL_MAX_COLUMNS_IN_INDEX; enum SQL_MAXIMUM_COLUMNS_IN_ORDER_BY=SQL_MAX_COLUMNS_IN_ORDER_BY; enum SQL_MAXIMUM_COLUMNS_IN_SELECT=SQL_MAX_COLUMNS_IN_SELECT; enum SQL_MAXIMUM_CURSOR_NAME_LENGTH=SQL_MAX_CURSOR_NAME_LEN; enum SQL_MAXIMUM_INDEX_SIZE=SQL_MAX_INDEX_SIZE; enum SQL_MAXIMUM_ROW_SIZE=SQL_MAX_ROW_SIZE; enum SQL_MAXIMUM_SCHEMA_NAME_LENGTH=SQL_MAX_SCHEMA_NAME_LEN; enum SQL_MAXIMUM_STATEMENT_LENGTH=SQL_MAX_STATEMENT_LEN; enum SQL_MAXIMUM_TABLES_IN_SELECT=SQL_MAX_TABLES_IN_SELECT; enum SQL_MAXIMUM_USER_NAME_LENGTH=SQL_MAX_USER_NAME_LEN; enum SQL_NC_HIGH=0; enum SQL_NC_LOW=1; enum SQL_NEED_DATA=99; enum SQL_NO_NULLS=0; enum SQL_NTS=-3; enum LONG SQL_NTSL=-3; enum SQL_NULL_COLLATION=85; enum SQL_NULL_DATA=-1; enum SQL_NULL_HDBC=0; enum SQL_NULL_HENV=0; enum SQL_NULL_HSTMT=0; enum SQL_NULLABLE=1; enum SQL_NULLABLE_UNKNOWN=2; enum SQL_NUMERIC=2; enum SQL_ORDER_BY_COLUMNS_IN_SELECT=90; enum SQL_PC_PSEUDO=2; enum SQL_PC_UNKNOWN=0; enum SQL_REAL=7; enum SQL_RESET_PARAMS=3; enum SQL_ROLLBACK=1; enum SQL_SCCO_LOCK=2; enum SQL_SCCO_OPT_ROWVER=4; enum SQL_SCCO_OPT_VALUES=8; enum SQL_SCCO_READ_ONLY=1; enum SQL_SCOPE_CURROW=0; enum SQL_SCOPE_SESSION=2; enum SQL_SCOPE_TRANSACTION=1; enum SQL_SCROLL_CONCURRENCY=43; enum SQL_SEARCH_PATTERN_ESCAPE=14; enum SQL_SERVER_NAME=13; enum SQL_SMALLINT=5; enum SQL_SPECIAL_CHARACTERS=94; enum SQL_STILL_EXECUTING=2; //MACRO #define SQL_SUCCEEDED(rc) (((rc)&(~1))==0) enum SQL_SUCCESS=0; enum SQL_SUCCESS_WITH_INFO=1; enum SQL_TC_ALL=2; enum SQL_TC_DDL_COMMIT=3; enum SQL_TC_DDL_IGNORE=4; enum SQL_TC_DML=1; enum SQL_TC_NONE=0; enum SQL_TXN_CAPABLE=46; enum SQL_TXN_ISOLATION_OPTION=72; enum SQL_TXN_READ_COMMITTED=2; enum SQL_TXN_READ_UNCOMMITTED=1; enum SQL_TXN_REPEATABLE_READ=4; enum SQL_TXN_SERIALIZABLE=8; enum SQL_TRANSACTION_CAPABLE=SQL_TXN_CAPABLE; enum SQL_TRANSACTION_ISOLATION_OPTION=SQL_TXN_ISOLATION_OPTION; enum SQL_TRANSACTION_READ_COMMITTED=SQL_TXN_READ_COMMITTED; enum SQL_TRANSACTION_READ_UNCOMMITTED=SQL_TXN_READ_UNCOMMITTED; enum SQL_TRANSACTION_REPEATABLE_READ=SQL_TXN_REPEATABLE_READ; enum SQL_TRANSACTION_SERIALIZABLE=SQL_TXN_SERIALIZABLE; enum SQL_UNBIND=2; enum SQL_UNKNOWN_TYPE=0; enum SQL_USER_NAME=47; enum SQL_VARCHAR=12; static if (ODBCVER >= 0x0200) { enum SQL_AT_ADD_COLUMN = 1; enum SQL_AT_DROP_COLUMN = 2; } static if (ODBCVER >= 0x0201) { enum SQL_OJ_LEFT = 1; enum SQL_OJ_RIGHT = 2; enum SQL_OJ_FULL = 4; enum SQL_OJ_NESTED = 8; enum SQL_OJ_NOT_ORDERED = 16; enum SQL_OJ_INNER = 32; enum SQL_OJ_ALL_COMPARISON_OPS = 64; } static if (ODBCVER >= 0x0300) { enum SQL_AM_CONNECTION=1; enum SQL_AM_NONE=0; enum SQL_AM_STATEMENT=2; enum SQL_API_SQLALLOCHANDLE=1001; enum SQL_API_SQLBINDPARAM=1002; enum SQL_API_SQLCLOSECURSOR=1003; enum SQL_API_SQLCOLATTRIBUTE=6; enum SQL_API_SQLCOPYDESC=1004; enum SQL_API_SQLENDTRAN=1005; enum SQL_API_SQLFETCHSCROLL=1021; enum SQL_API_SQLFREEHANDLE=1006; enum SQL_API_SQLGETCONNECTATTR=1007; enum SQL_API_SQLGETDESCFIELD=1008; enum SQL_API_SQLGETDESCREC=1009; enum SQL_API_SQLGETDIAGFIELD=1010; enum SQL_API_SQLGETDIAGREC=1011; enum SQL_API_SQLGETENVATTR=1012; enum SQL_API_SQLGETSTMTATTR=1014; enum SQL_API_SQLSETCONNECTATTR=1016; enum SQL_API_SQLSETDESCFIELD=1017; enum SQL_API_SQLSETDESCREC=1018; enum SQL_API_SQLSETENVATTR=1019; enum SQL_API_SQLSETSTMTATTR=1020; enum SQL_ARD_TYPE=-99; enum SQL_AT_ADD_CONSTRAINT=8; enum SQL_ATTR_APP_PARAM_DESC=10011; enum SQL_ATTR_APP_ROW_DESC=10010; enum SQL_ATTR_AUTO_IPD=10001; enum SQL_ATTR_CURSOR_SCROLLABLE=-1; enum SQL_ATTR_CURSOR_SENSITIVITY=-2; enum SQL_ATTR_IMP_PARAM_DESC=10013; enum SQL_ATTR_IMP_ROW_DESC=10012; enum SQL_ATTR_METADATA_ID=10014; enum SQL_ATTR_OUTPUT_NTS=10001; enum SQL_CATALOG_NAME=10003; enum SQL_CODE_DATE=1; enum SQL_CODE_TIME=2; enum SQL_CODE_TIMESTAMP=3; enum SQL_COLLATION_SEQ=10004; enum SQL_CURSOR_SENSITIVITY=10001; enum SQL_DATE_LEN=10; enum SQL_DATETIME=9; enum SQL_DEFAULT=99; enum SQL_DESC_ALLOC_AUTO=1; enum SQL_DESC_ALLOC_USER=2; enum SQL_DESC_ALLOC_TYPE=1099; enum SQL_DESC_COUNT=1001; enum SQL_DESC_TYPE=1002; enum SQL_DESC_LENGTH=1003; enum SQL_DESC_OCTET_LENGTH_PTR=1004; enum SQL_DESC_PRECISION=1005; enum SQL_DESC_SCALE=1006; enum SQL_DESC_DATETIME_INTERVAL_CODE=1007; enum SQL_DESC_NULLABLE=1008; enum SQL_DESC_INDICATOR_PTR=1009; enum SQL_DESC_DATA_PTR=1010; enum SQL_DESC_NAME=1011; enum SQL_DESC_UNNAMED=1012; enum SQL_DESC_OCTET_LENGTH=1013; enum SQL_DESCRIBE_PARAMETER=10002; enum SQL_DIAG_ALTER_DOMAIN=3; enum SQL_DIAG_ALTER_TABLE=4; enum SQL_DIAG_CALL=7; enum SQL_DIAG_CLASS_ORIGIN=8; enum SQL_DIAG_CONNECTION_NAME=10; enum SQL_DIAG_CREATE_ASSERTION=6; enum SQL_DIAG_CREATE_CHARACTER_SET=8; enum SQL_DIAG_CREATE_COLLATION=10; enum SQL_DIAG_CREATE_DOMAIN=23; enum SQL_DIAG_CREATE_INDEX=-1; enum SQL_DIAG_CREATE_SCHEMA=64; enum SQL_DIAG_CREATE_TABLE=77; enum SQL_DIAG_CREATE_TRANSLATION=79; enum SQL_DIAG_CREATE_VIEW=84; enum SQL_DIAG_DELETE_WHERE=19; enum SQL_DIAG_DROP_ASSERTION=24; enum SQL_DIAG_DROP_CHARACTER_SET=25; enum SQL_DIAG_DROP_COLLATION=26; enum SQL_DIAG_DROP_DOMAIN=27; enum SQL_DIAG_DROP_INDEX=(-2); enum SQL_DIAG_DROP_SCHEMA=31; enum SQL_DIAG_DROP_TABLE=32; enum SQL_DIAG_DROP_TRANSLATION=33; enum SQL_DIAG_DROP_VIEW=36; enum SQL_DIAG_DYNAMIC_DELETE_CURSOR=38; enum SQL_DIAG_DYNAMIC_FUNCTION=7; enum SQL_DIAG_DYNAMIC_FUNCTION_CODE=12; enum SQL_DIAG_DYNAMIC_UPDATE_CURSOR=81; enum SQL_DIAG_GRANT=48; enum SQL_DIAG_INSERT=50; enum SQL_DIAG_MESSAGE_TEXT=6; enum SQL_DIAG_NATIVE=5; enum SQL_DIAG_NUMBER=2; enum SQL_DIAG_RETURNCODE=1; enum SQL_DIAG_REVOKE=59; enum SQL_DIAG_ROW_COUNT=3; enum SQL_DIAG_SELECT_CURSOR=85; enum SQL_DIAG_SERVER_NAME=11; enum SQL_DIAG_SQLSTATE=4; enum SQL_DIAG_SUBCLASS_ORIGIN=9; enum SQL_DIAG_UNKNOWN_STATEMENT=0; enum SQL_DIAG_UPDATE_WHERE=82; enum SQL_FALSE=0; enum SQL_HANDLE_DBC=2; enum SQL_HANDLE_DESC=4; enum SQL_HANDLE_ENV=1; enum SQL_HANDLE_STMT=3; enum SQL_INSENSITIVE=1; enum SQL_MAX_CONCURRENT_ACTIVITIES=1; enum SQL_MAX_DRIVER_CONNECTIONS=0; enum SQL_MAX_IDENTIFIER_LEN=10005; enum SQL_MAXIMUM_CONCURRENT_ACTIVITIES=SQL_MAX_CONCURRENT_ACTIVITIES; enum SQL_MAXIMUM_DRIVER_CONNECTIONS=SQL_MAX_DRIVER_CONNECTIONS; enum SQL_MAXIMUM_IDENTIFIER_LENGTH=SQL_MAX_IDENTIFIER_LEN; enum SQL_NAMED=0; enum SQL_NO_DATA=100; enum SQL_NONSCROLLABLE=0; enum SQL_NULL_HANDLE=0L; enum SQL_NULL_HDESC=0; enum SQL_OJ_CAPABILITIES=115; enum SQL_OUTER_JOIN_CAPABILITIES=SQL_OJ_CAPABILITIES; enum SQL_PC_NON_PSEUDO=1; enum SQL_PRED_NONE=0; enum SQL_PRED_CHAR=1; enum SQL_PRED_BASIC=2; enum SQL_ROW_IDENTIFIER=1; enum SQL_SCROLLABLE=1; enum SQL_SENSITIVE=2; enum SQL_TIME_LEN=8; enum SQL_TIMESTAMP_LEN=19; enum SQL_TRUE=1; enum SQL_TYPE_DATE=91; enum SQL_TYPE_TIME=92; enum SQL_TYPE_TIMESTAMP=93; enum SQL_UNNAMED=1; enum SQL_UNSPECIFIED=0; enum SQL_XOPEN_CLI_YEAR=10000; }//#endif /* ODBCVER >= 0x0300 */ extern (Windows) { deprecated { SQLRETURN SQLAllocConnect(SQLHENV, SQLHDBC*); SQLRETURN SQLAllocEnv(SQLHENV*); SQLRETURN SQLAllocStmt(SQLHDBC, SQLHSTMT*); SQLRETURN SQLError(SQLHENV, SQLHDBC, SQLHSTMT, SQLCHAR*, SQLINTEGER*, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLFreeConnect(SQLHDBC); SQLRETURN SQLFreeEnv(SQLHENV); SQLRETURN SQLSetParam(SQLHSTMT, SQLUSMALLINT, SQLSMALLINT, SQLSMALLINT, SQLULEN, SQLSMALLINT, SQLPOINTER, SQLLEN*); SQLRETURN SQLGetConnectOption(SQLHDBC, SQLUSMALLINT, SQLPOINTER); SQLRETURN SQLGetStmtOption(SQLHSTMT, SQLUSMALLINT, SQLPOINTER); SQLRETURN SQLSetConnectOption(SQLHDBC, SQLUSMALLINT, SQLULEN); SQLRETURN SQLSetStmtOption(SQLHSTMT, SQLUSMALLINT, SQLROWCOUNT); } SQLRETURN SQLBindCol(SQLHSTMT, SQLUSMALLINT, SQLSMALLINT, SQLPOINTER, SQLLEN, SQLLEN*); SQLRETURN SQLCancel(SQLHSTMT); SQLRETURN SQLConnect(SQLHDBC, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLDescribeCol(SQLHSTMT, SQLUSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLSMALLINT*, SQLULEN*, SQLSMALLINT*, SQLSMALLINT*); SQLRETURN SQLDisconnect(SQLHDBC); SQLRETURN SQLExecDirect(SQLHSTMT, SQLCHAR*, SQLINTEGER); SQLRETURN SQLExecute(SQLHSTMT); SQLRETURN SQLFetch(SQLHSTMT); SQLRETURN SQLFreeStmt(SQLHSTMT, SQLUSMALLINT); SQLRETURN SQLGetCursorName(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLNumResultCols(SQLHSTMT, SQLSMALLINT*); SQLRETURN SQLPrepare(SQLHSTMT, SQLCHAR*, SQLINTEGER); SQLRETURN SQLRowCount(SQLHSTMT, SQLLEN*); SQLRETURN SQLSetCursorName(SQLHSTMT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLTransact(SQLHENV, SQLHDBC, SQLUSMALLINT); SQLRETURN SQLColumns(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLGetData(SQLHSTMT, SQLUSMALLINT, SQLSMALLINT, SQLPOINTER, SQLLEN, SQLLEN*); SQLRETURN SQLGetFunctions(SQLHDBC, SQLUSMALLINT, SQLUSMALLINT*); SQLRETURN SQLGetInfo(SQLHDBC, SQLUSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetTypeInfo(SQLHSTMT, SQLSMALLINT); SQLRETURN SQLParamData(SQLHSTMT, SQLPOINTER*); SQLRETURN SQLPutData(SQLHSTMT, SQLPOINTER, SQLLEN); SQLRETURN SQLSpecialColumns(SQLHSTMT, SQLUSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLUSMALLINT, SQLUSMALLINT); SQLRETURN SQLStatistics(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLUSMALLINT, SQLUSMALLINT); SQLRETURN SQLTables(SQLHSTMT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLCHAR*, SQLSMALLINT); SQLRETURN SQLDataSources(SQLHENV, SQLUSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); static if (ODBCVER >= 0x0300) { SQLRETURN SQLAllocHandle(SQLSMALLINT, SQLHANDLE, SQLHANDLE*); SQLRETURN SQLBindParam(SQLHSTMT, SQLUSMALLINT, SQLSMALLINT, SQLSMALLINT, SQLULEN, SQLSMALLINT, SQLPOINTER, SQLLEN*); SQLRETURN SQLCloseCursor(SQLHSTMT); SQLRETURN SQLColAttribute(SQLHSTMT, SQLUSMALLINT, SQLUSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*, SQLPOINTER); SQLRETURN SQLCopyDesc(SQLHDESC, SQLHDESC); SQLRETURN SQLEndTran(SQLSMALLINT, SQLHANDLE, SQLSMALLINT); SQLRETURN SQLFetchScroll(SQLHSTMT, SQLSMALLINT, SQLROWOFFSET); SQLRETURN SQLFreeHandle(SQLSMALLINT, SQLHANDLE); SQLRETURN SQLGetConnectAttr(SQLHDBC, SQLINTEGER, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLGetDescField(SQLHDESC, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLGetDescRec(SQLHDESC, SQLSMALLINT, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*, SQLSMALLINT*, SQLSMALLINT*, SQLLEN*, SQLSMALLINT*, SQLSMALLINT*, SQLSMALLINT*); SQLRETURN SQLGetDiagField(SQLSMALLINT, SQLHANDLE, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetDiagRec(SQLSMALLINT, SQLHANDLE, SQLSMALLINT, SQLCHAR*, SQLINTEGER*, SQLCHAR*, SQLSMALLINT, SQLSMALLINT*); SQLRETURN SQLGetEnvAttr(SQLHENV, SQLINTEGER, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLGetStmtAttr(SQLHSTMT, SQLINTEGER, SQLPOINTER, SQLINTEGER, SQLINTEGER*); SQLRETURN SQLSetConnectAttr(SQLHDBC, SQLINTEGER, SQLPOINTER, SQLINTEGER); SQLRETURN SQLSetDescField(SQLHDESC, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLINTEGER); SQLRETURN SQLSetDescRec(SQLHDESC, SQLSMALLINT, SQLSMALLINT, SQLSMALLINT, SQLLEN, SQLSMALLINT, SQLSMALLINT, SQLPOINTER, SQLLEN*, SQLLEN*); SQLRETURN SQLSetEnvAttr(SQLHENV, SQLINTEGER, SQLPOINTER, SQLINTEGER); SQLRETURN SQLSetStmtAttr(SQLHSTMT, SQLINTEGER, SQLPOINTER, SQLINTEGER); }/* (ODBCVER >= 0x0300) */ } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/windef.d0000664000175000017500000000725112776214756023140 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_windef.d) */ module core.sys.windows.windef; version (Windows): public import core.sys.windows.winnt; private import core.sys.windows.w32api; enum size_t MAX_PATH = 260; pure nothrow @nogc { ushort MAKEWORD(ubyte a, ubyte b) { return cast(ushort) ((b << 8) | a); } ushort MAKEWORD(ushort a, ushort b) { assert((a & 0xFF00) == 0); assert((b & 0xFF00) == 0); return MAKEWORD(cast(ubyte)a, cast(ubyte)b); } uint MAKELONG(ushort a, ushort b) { return cast(uint) ((b << 16) | a); } uint MAKELONG(uint a, uint b) { assert((a & 0xFFFF0000) == 0); assert((b & 0xFFFF0000) == 0); return MAKELONG(cast(ushort)a, cast(ushort)b); } ushort LOWORD(ulong l) { return cast(ushort) l; } ushort HIWORD(ulong l) { return cast(ushort) (l >>> 16); } ubyte LOBYTE(ushort w) { return cast(ubyte) w; } ubyte HIBYTE(ushort w) { return cast(ubyte) (w >>> 8); } } enum NULL = null; static assert (is(typeof({ void test(int* p) {} test(NULL); }))); alias ubyte BYTE; alias ubyte* PBYTE, LPBYTE; alias ushort USHORT, WORD, ATOM; alias ushort* PUSHORT, PWORD, LPWORD; alias uint ULONG, DWORD, UINT, COLORREF; alias uint* PULONG, PDWORD, LPDWORD, PUINT, LPUINT, LPCOLORREF; alias int WINBOOL, BOOL, INT, LONG, HFILE, HRESULT; alias int* PWINBOOL, LPWINBOOL, PBOOL, LPBOOL, PINT, LPINT, LPLONG; alias float FLOAT; alias float* PFLOAT; alias const(void)* PCVOID, LPCVOID; alias UINT_PTR WPARAM; alias LONG_PTR LPARAM, LRESULT; mixin DECLARE_HANDLE!("HHOOK"); mixin DECLARE_HANDLE!("HGLOBAL"); mixin DECLARE_HANDLE!("HLOCAL"); mixin DECLARE_HANDLE!("GLOBALHANDLE"); mixin DECLARE_HANDLE!("LOCALHANDLE"); mixin DECLARE_HANDLE!("HGDIOBJ"); mixin DECLARE_HANDLE!("HACCEL"); mixin DECLARE_HANDLE!("HBITMAP", HGDIOBJ); mixin DECLARE_HANDLE!("HBRUSH", HGDIOBJ); mixin DECLARE_HANDLE!("HCOLORSPACE"); mixin DECLARE_HANDLE!("HDC"); mixin DECLARE_HANDLE!("HGLRC"); mixin DECLARE_HANDLE!("HDESK"); mixin DECLARE_HANDLE!("HENHMETAFILE"); mixin DECLARE_HANDLE!("HFONT", HGDIOBJ); mixin DECLARE_HANDLE!("HICON"); mixin DECLARE_HANDLE!("HINSTANCE"); mixin DECLARE_HANDLE!("HKEY"); mixin DECLARE_HANDLE!("HMENU"); mixin DECLARE_HANDLE!("HMETAFILE"); mixin DECLARE_HANDLE!("HMODULE"); mixin DECLARE_HANDLE!("HMONITOR"); mixin DECLARE_HANDLE!("HPALETTE"); mixin DECLARE_HANDLE!("HPEN", HGDIOBJ); mixin DECLARE_HANDLE!("HRGN", HGDIOBJ); mixin DECLARE_HANDLE!("HRSRC"); mixin DECLARE_HANDLE!("HSTR"); mixin DECLARE_HANDLE!("HTASK"); mixin DECLARE_HANDLE!("HWND"); mixin DECLARE_HANDLE!("HWINSTA"); mixin DECLARE_HANDLE!("HKL"); mixin DECLARE_HANDLE!("HCURSOR"); alias HKEY* PHKEY; static if (_WIN32_WINNT >= 0x500) { mixin DECLARE_HANDLE!("HTERMINAL"); mixin DECLARE_HANDLE!("HWINEVENTHOOK"); } alias extern (Windows) INT_PTR function() nothrow FARPROC, NEARPROC, PROC; struct RECT { LONG left; LONG top; LONG right; LONG bottom; } alias RECT RECTL; alias RECT* PRECT, NPRECT, LPRECT, PRECTL, LPRECTL; alias const(RECT)* LPCRECT, LPCRECTL; struct POINT { LONG x; LONG y; } alias POINT POINTL; alias POINT* PPOINT, NPPOINT, LPPOINT, PPOINTL, LPPOINTL; struct SIZE { LONG cx; LONG cy; } alias SIZE SIZEL; alias SIZE* PSIZE, LPSIZE, PSIZEL, LPSIZEL; struct POINTS { SHORT x; SHORT y; } alias POINTS* PPOINTS, LPPOINTS; enum : BOOL { FALSE = 0, TRUE = 1 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rpcdcep.d0000664000175000017500000001122012776214756023273 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rpcdcep.d) */ module core.sys.windows.rpcdcep; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.basetyps; private import core.sys.windows.w32api; private import core.sys.windows.windef; mixin DECLARE_HANDLE!("I_RPC_HANDLE"); alias long RPC_STATUS; enum RPC_NCA_FLAGS_DEFAULT=0; enum RPC_NCA_FLAGS_IDEMPOTENT=1; enum RPC_NCA_FLAGS_BROADCAST=2; enum RPC_NCA_FLAGS_MAYBE=4; enum RPCFLG_ASYNCHRONOUS=0x40000000; enum RPCFLG_INPUT_SYNCHRONOUS=0x20000000; enum RPC_FLAGS_VALID_BIT=0x8000; enum TRANSPORT_TYPE_CN=1; enum TRANSPORT_TYPE_DG=2; enum TRANSPORT_TYPE_LPC=4; enum TRANSPORT_TYPE_WMSG=8; struct RPC_VERSION { ushort MajorVersion; ushort MinorVersion; } struct RPC_SYNTAX_IDENTIFIER { GUID SyntaxGUID; RPC_VERSION SyntaxVersion; } alias RPC_SYNTAX_IDENTIFIER* PRPC_SYNTAX_IDENTIFIER; struct RPC_MESSAGE { HANDLE Handle; uint DataRepresentation; void* Buffer; uint BufferLength; uint ProcNum; PRPC_SYNTAX_IDENTIFIER TransferSyntax; void* RpcInterfaceInformation; void* ReservedForRuntime; void* ManagerEpv; void* ImportContext; uint RpcFlags; } alias RPC_MESSAGE* PRPC_MESSAGE; extern (Windows) { alias void function (PRPC_MESSAGE Message) RPC_DISPATCH_FUNCTION; } struct RPC_DISPATCH_TABLE { uint DispatchTableCount; RPC_DISPATCH_FUNCTION* DispatchTable; int Reserved; } alias RPC_DISPATCH_TABLE* PRPC_DISPATCH_TABLE; struct RPC_PROTSEQ_ENDPOINT { ubyte* RpcProtocolSequence; ubyte* Endpoint; } alias RPC_PROTSEQ_ENDPOINT* PRPC_PROTSEQ_ENDPOINT; struct RPC_SERVER_INTERFACE { uint Length; RPC_SYNTAX_IDENTIFIER InterfaceId; RPC_SYNTAX_IDENTIFIER TransferSyntax; PRPC_DISPATCH_TABLE DispatchTable; uint RpcProtseqEndpointCount; PRPC_PROTSEQ_ENDPOINT RpcProtseqEndpoint; void* DefaultManagerEpv; const(void)* InterpreterInfo; } alias RPC_SERVER_INTERFACE* PRPC_SERVER_INTERFACE; struct RPC_CLIENT_INTERFACE { uint Length; RPC_SYNTAX_IDENTIFIER InterfaceId; RPC_SYNTAX_IDENTIFIER TransferSyntax; PRPC_DISPATCH_TABLE DispatchTable; uint RpcProtseqEndpointCount; PRPC_PROTSEQ_ENDPOINT RpcProtseqEndpoint; uint Reserved; const(void)* InterpreterInfo; } alias RPC_CLIENT_INTERFACE* PRPC_CLIENT_INTERFACE; alias TypeDef!(void*) I_RPC_MUTEX; struct RPC_TRANSFER_SYNTAX { GUID Uuid; ushort VersMajor; ushort VersMinor; } alias RPC_STATUS function(void*, void*, void*) RPC_BLOCKING_FN; extern (Windows) { alias void function(void*) PRPC_RUNDOWN; int I_RpcGetBuffer(RPC_MESSAGE*); int I_RpcSendReceive(RPC_MESSAGE*); int I_RpcSend(RPC_MESSAGE*); int I_RpcFreeBuffer(RPC_MESSAGE*); void I_RpcRequestMutex(I_RPC_MUTEX*); void I_RpcClearMutex(I_RPC_MUTEX); void I_RpcDeleteMutex(I_RPC_MUTEX); void* I_RpcAllocate(uint); void I_RpcFree(void*); void I_RpcPauseExecution(uint); int I_RpcMonitorAssociation(HANDLE, PRPC_RUNDOWN, void*); int I_RpcStopMonitorAssociation(HANDLE); HANDLE I_RpcGetCurrentCallHandle(); int I_RpcGetAssociationContext(void**); int I_RpcSetAssociationContext(void*); int I_RpcNsBindingSetEntryName(HANDLE, uint, wchar*); int I_RpcBindingInqDynamicEndpoint(HANDLE, wchar**); int I_RpcBindingInqTransportType(HANDLE, uint*); int I_RpcIfInqTransferSyntaxes(HANDLE, RPC_TRANSFER_SYNTAX*, uint, uint*); int I_UuidCreate(GUID*); int I_RpcBindingCopy(HANDLE, HANDLE*); int I_RpcBindingIsClientLocal(HANDLE, uint*); void I_RpcSsDontSerializeContext(); int I_RpcServerRegisterForwardFunction(int function (GUID*, RPC_VERSION*, GUID*, ubyte*, void**)); int I_RpcConnectionInqSockBuffSize(uint*, uint*); int I_RpcConnectionSetSockBuffSize(uint, uint); int I_RpcBindingSetAsync(HANDLE, RPC_BLOCKING_FN); int I_RpcAsyncSendReceive(RPC_MESSAGE*, void*); int I_RpcGetThreadWindowHandle(void**); int I_RpcServerThreadPauseListening(); int I_RpcServerThreadContinueListening(); int I_RpcServerUnregisterEndpointA(ubyte*, ubyte*); int I_RpcServerUnregisterEndpointW(ushort*, ushort*); } version(Unicode) { alias I_RpcServerUnregisterEndpointW I_RpcServerUnregisterEndpoint; } else { alias I_RpcServerUnregisterEndpointA I_RpcServerUnregisterEndpoint; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lm.d0000664000175000017500000000275512776214756022300 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lm.d) */ module core.sys.windows.lm; version (Windows): /* removed - now supporting only Win2k up version (WindowsVista) { version = WIN32_WINNT_ONLY; } else version (Windows2003) { version = WIN32_WINNT_ONLY; } else version (WindowsXP) { version = WIN32_WINNT_ONLY; } else version (WindowsNTonly) { version = WIN32_WINNT_ONLY; } */ public import core.sys.windows.lmcons; public import core.sys.windows.lmaccess; public import core.sys.windows.lmalert; public import core.sys.windows.lmat; public import core.sys.windows.lmerr; public import core.sys.windows.lmshare; public import core.sys.windows.lmapibuf; public import core.sys.windows.lmremutl; public import core.sys.windows.lmrepl; public import core.sys.windows.lmuse; public import core.sys.windows.lmstats; public import core.sys.windows.lmwksta; public import core.sys.windows.lmserver; version (Windows2000) { } else { public import core.sys.windows.lmmsg; } // FIXME: Everything in these next files seems to be deprecated! import core.sys.windows.lmaudit; import core.sys.windows.lmchdev; // can't find many docs for functions from this file. import core.sys.windows.lmconfig; import core.sys.windows.lmerrlog; import core.sys.windows.lmsvc; import core.sys.windows.lmsname; // in MinGW, this was publicly included by lm.lmsvc ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/prsht.d0000664000175000017500000002674312776214756023033 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Vladimir Vlasov * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_prsht.d) */ module core.sys.windows.prsht; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "comctl32"); private import core.sys.windows.w32api, core.sys.windows.windef, core.sys.windows.winuser; enum MAXPROPPAGES = 100; enum { PSP_DEFAULT = 0x00000000, PSP_DLGINDIRECT = 0x00000001, PSP_USEHICON = 0x00000002, PSP_USEICONID = 0x00000004, PSP_USETITLE = 0x00000008, PSP_RTLREADING = 0x00000010, PSP_HASHELP = 0x00000020, PSP_USEREFPARENT = 0x00000040, PSP_USECALLBACK = 0x00000080, PSP_PREMATURE = 0x00000400 } static if (_WIN32_IE >= 0x400) { enum { PSP_HIDEHEADER = 0x00000800, PSP_USEHEADERTITLE = 0x00001000, PSP_USEHEADERSUBTITLE = 0x00002000 } } enum { PSPCB_RELEASE = 1, PSPCB_CREATE } enum { PSH_DEFAULT = 0x00000000, PSH_PROPTITLE = 0x00000001, PSH_USEHICON = 0x00000002, PSH_USEICONID = 0x00000004, PSH_PROPSHEETPAGE = 0x00000008, PSH_WIZARDHASFINISH = 0x00000010, PSH_WIZARD = 0x00000020, PSH_USEPSTARTPAGE = 0x00000040, PSH_NOAPPLYNOW = 0x00000080, PSH_USECALLBACK = 0x00000100, PSH_HASHELP = 0x00000200, PSH_MODELESS = 0x00000400, PSH_RTLREADING = 0x00000800, PSH_WIZARDCONTEXTHELP = 0x00001000 } static if (_WIN32_IE >= 0x400) { enum { PSH_WATERMARK = 0x00008000, PSH_USEHBMWATERMARK = 0x00010000, PSH_USEHPLWATERMARK = 0x00020000, PSH_STRETCHWATERMARK = 0x00040000, PSH_HEADER = 0x00080000, PSH_USEHBMHEADER = 0x00100000, PSH_USEPAGELANG = 0x00200000 } static if (_WIN32_IE < 0x0500) { enum { PSH_WIZARD97 = 0x00002000 } } else { enum { PSH_WIZARD97 = 0x01000000 } } } static if (_WIN32_IE >= 0x500) { enum { PSH_WIZARD_LITE = 0x00400000, PSH_NOCONTEXTHELP = 0x02000000 } } enum { PSCB_INITIALIZED = 1, PSCB_PRECREATE } enum { PSN_FIRST = (-200), PSN_LAST = (-299), PSN_SETACTIVE = (-200), PSN_KILLACTIVE = (-201), PSN_APPLY = (-202), PSN_RESET = (-203), PSN_HELP = (-205), PSN_WIZBACK = (-206), PSN_WIZNEXT = (-207), PSN_WIZFINISH = (-208), PSN_QUERYCANCEL = (-209) } static if (_WIN32_IE >= 0x400) { enum { PSN_GETOBJECT = (-210) } } static if (_WIN32_IE >= 0x500) { enum { PSN_TRANSLATEACCELERATOR = (-212), PSN_QUERYINITIALFOCUS = (-213) } } enum { PSNRET_NOERROR, PSNRET_INVALID, PSNRET_INVALID_NOCHANGEPAGE, PSNRET_MESSAGEHANDLED } enum { ID_PSRESTARTWINDOWS = 0x2, ID_PSREBOOTSYSTEM = ID_PSRESTARTWINDOWS | 0x1 } enum { WIZ_CXDLG = 276, WIZ_CYDLG = 140, WIZ_CXBMP = 80, WIZ_BODYX = 92, WIZ_BODYCX = 184 } enum { PROP_SM_CXDLG = 212, PROP_SM_CYDLG = 188, PROP_MED_CXDLG = 227, PROP_MED_CYDLG = 215, PROP_LG_CXDLG = 252, PROP_LG_CYDLG = 218 } enum { PSBTN_BACK, PSBTN_NEXT, PSBTN_FINISH, PSBTN_OK, PSBTN_APPLYNOW, PSBTN_CANCEL, PSBTN_HELP, PSBTN_MAX = 6 } enum { PSWIZB_BACK = 1, PSWIZB_NEXT = 2, PSWIZB_FINISH = 4, PSWIZB_DISABLEDFINISH = 8 } enum { PSM_SETCURSEL = WM_USER + 101, PSM_REMOVEPAGE, PSM_ADDPAGE, PSM_CHANGED, PSM_RESTARTWINDOWS, PSM_REBOOTSYSTEM, PSM_CANCELTOCLOSE, PSM_QUERYSIBLINGS, PSM_UNCHANGED, PSM_APPLY, PSM_SETTITLEA, PSM_SETWIZBUTTONS, PSM_PRESSBUTTON, PSM_SETCURSELID, PSM_SETFINISHTEXTA, PSM_GETTABCONTROL, PSM_ISDIALOGMESSAGE, PSM_GETCURRENTPAGEHWND, PSM_INSERTPAGE, PSM_SETTITLEW, PSM_SETFINISHTEXTW // = WM_USER + 121, } alias UINT function(HWND, UINT, LPPROPSHEETPAGEA) LPFNPSPCALLBACKA; alias UINT function(HWND, UINT, LPPROPSHEETPAGEW) LPFNPSPCALLBACKW; alias int function(HWND, UINT, LPARAM) PFNPROPSHEETCALLBACK; align(4): struct PROPSHEETPAGEA { DWORD dwSize = PROPSHEETPAGEA.sizeof; DWORD dwFlags; HINSTANCE hInstance; union { LPCSTR pszTemplate; LPCDLGTEMPLATE pResource; } union { HICON hIcon; LPCSTR pszIcon; } LPCSTR pszTitle; DLGPROC pfnDlgProc; LPARAM lParam; LPFNPSPCALLBACKA pfnCallback; UINT* pcRefParent; static if (_WIN32_IE >= 0x400) { LPCSTR pszHeaderTitle; LPCSTR pszHeaderSubTitle; } } alias PROPSHEETPAGEA* LPPROPSHEETPAGEA; alias const(PROPSHEETPAGEA)* LPCPROPSHEETPAGEA; struct PROPSHEETPAGEW { DWORD dwSize = PROPSHEETPAGEW.sizeof; DWORD dwFlags; HINSTANCE hInstance; union { LPCWSTR pszTemplate; LPCDLGTEMPLATE pResource; } union { HICON hIcon; LPCWSTR pszIcon; } LPCWSTR pszTitle; DLGPROC pfnDlgProc; LPARAM lParam; LPFNPSPCALLBACKW pfnCallback; UINT* pcRefParent; static if (_WIN32_IE >= 0x400) { LPCWSTR pszHeaderTitle; LPCWSTR pszHeaderSubTitle; } } alias PROPSHEETPAGEW* LPPROPSHEETPAGEW; alias const(PROPSHEETPAGEW)* LPCPROPSHEETPAGEW; mixin DECLARE_HANDLE!("HPROPSHEETPAGE"); struct PROPSHEETHEADERA { DWORD dwSize = PROPSHEETHEADERA.sizeof; DWORD dwFlags; HWND hwndParent; HINSTANCE hInstance; union { HICON hIcon; LPCSTR pszIcon; } LPCSTR pszCaption; UINT nPages; union { UINT nStartPage; LPCSTR pStartPage; } union { LPCPROPSHEETPAGEA ppsp; HPROPSHEETPAGE* phpage; } PFNPROPSHEETCALLBACK pfnCallback; static if (_WIN32_IE >= 0x400) { union { HBITMAP hbmWatermark; LPCSTR pszbmWatermark; } HPALETTE hplWatermark; union { HBITMAP hbmHeader; LPCSTR pszbmHeader; } } } alias PROPSHEETHEADERA* LPPROPSHEETHEADERA; alias const(PROPSHEETHEADERA)* LPCPROPSHEETHEADERA; struct PROPSHEETHEADERW { DWORD dwSize = PROPSHEETHEADERW.sizeof; DWORD dwFlags; HWND hwndParent; HINSTANCE hInstance; union { HICON hIcon; LPCWSTR pszIcon; } LPCWSTR pszCaption; UINT nPages; union { UINT nStartPage; LPCWSTR pStartPage; } union { LPCPROPSHEETPAGEW ppsp; HPROPSHEETPAGE* phpage; } PFNPROPSHEETCALLBACK pfnCallback; static if (_WIN32_IE >= 0x400) { union { HBITMAP hbmWatermark; LPCWSTR pszbmWatermark; } HPALETTE hplWatermark; union { HBITMAP hbmHeader; LPCWSTR pszbmHeader; } } } alias PROPSHEETHEADERW* LPPROPSHEETHEADERW; alias const(PROPSHEETHEADERW)* LPCPROPSHEETHEADERW; alias BOOL function(HPROPSHEETPAGE, LPARAM) LPFNADDPROPSHEETPAGE; alias BOOL function(LPVOID, LPFNADDPROPSHEETPAGE, LPARAM) LPFNADDPROPSHEETPAGES; struct PSHNOTIFY { NMHDR hdr; LPARAM lParam; } alias PSHNOTIFY* LPPSHNOTIFY; extern (Windows) { HPROPSHEETPAGE CreatePropertySheetPageA(LPCPROPSHEETPAGEA); HPROPSHEETPAGE CreatePropertySheetPageW(LPCPROPSHEETPAGEW); BOOL DestroyPropertySheetPage(HPROPSHEETPAGE); int PropertySheetA(LPCPROPSHEETHEADERA); int PropertySheetW(LPCPROPSHEETHEADERW); } version (Unicode) { alias LPFNPSPCALLBACKW LPFNPSPCALLBACK; alias PROPSHEETPAGEW PROPSHEETPAGE; alias LPPROPSHEETPAGEW LPPROPSHEETPAGE; alias LPCPROPSHEETPAGEW LPCPROPSHEETPAGE; alias PROPSHEETHEADERW PROPSHEETHEADER; alias LPPROPSHEETHEADERW LPPROPSHEETHEADER; alias LPCPROPSHEETHEADERW LPCPROPSHEETHEADER; alias PSM_SETTITLEW PSM_SETTITLE; alias PSM_SETFINISHTEXTW PSM_SETFINISHTEXT; alias CreatePropertySheetPageW CreatePropertySheetPage; alias PropertySheetW PropertySheet; } else { alias LPFNPSPCALLBACKA LPFNPSPCALLBACK; alias PROPSHEETPAGEA PROPSHEETPAGE; alias LPPROPSHEETPAGEA LPPROPSHEETPAGE; alias LPCPROPSHEETPAGEA LPCPROPSHEETPAGE; alias PROPSHEETHEADERA PROPSHEETHEADER; alias LPPROPSHEETHEADERA LPPROPSHEETHEADER; alias LPCPROPSHEETHEADERA LPCPROPSHEETHEADER; alias PSM_SETTITLEA PSM_SETTITLE; alias PSM_SETFINISHTEXTA PSM_SETFINISHTEXT; alias CreatePropertySheetPageA CreatePropertySheetPage; alias PropertySheetA PropertySheet; } BOOL PropSheet_SetCurSel(HWND hPropSheetDlg, HPROPSHEETPAGE hpage, HPROPSHEETPAGE index) { return cast(BOOL) SendMessage(hPropSheetDlg, PSM_SETCURSEL, cast(WPARAM) index, cast(LPARAM) hpage); } VOID PropSheet_RemovePage(HWND hPropSheetDlg, int index, HPROPSHEETPAGE hpage) { SendMessage(hPropSheetDlg, PSM_REMOVEPAGE, index, cast(LPARAM) hpage); } BOOL PropSheet_AddPage(HWND hPropSheetDlg, HPROPSHEETPAGE hpage) { return cast(BOOL) SendMessage(hPropSheetDlg, PSM_ADDPAGE, 0, cast(LPARAM) hpage); } VOID PropSheet_Changed(HWND hPropSheetDlg, HWND hwndPage) { SendMessage(hPropSheetDlg, PSM_CHANGED, cast(WPARAM) hwndPage, 0); } VOID PropSheet_RestartWindows(HWND hPropSheetDlg) { SendMessage(hPropSheetDlg, PSM_RESTARTWINDOWS, 0, 0); } VOID PropSheet_RebootSystem(HWND hPropSheetDlg) { SendMessage(hPropSheetDlg, PSM_REBOOTSYSTEM, 0, 0); } VOID PropSheet_CancelToClose(HWND hPropSheetDlg) { SendMessage(hPropSheetDlg, PSM_CANCELTOCLOSE, 0, 0); } int PropSheet_QuerySiblings(HWND hPropSheetDlg, WPARAM param1, LPARAM param2) { return cast(int) SendMessage(hPropSheetDlg, PSM_QUERYSIBLINGS, param1, param2); } VOID PropSheet_UnChanged(HWND hPropSheetDlg, HWND hwndPage) { SendMessage(hPropSheetDlg, PSM_UNCHANGED, cast(WPARAM) hwndPage, 0); } BOOL PropSheet_Apply(HWND hPropSheetDlg) { return cast(BOOL) SendMessage(hPropSheetDlg, PSM_APPLY, 0, 0); } VOID PropSheet_SetTitle(HWND hPropSheetDlg, DWORD wStyle, LPTSTR lpszText) { SendMessage(hPropSheetDlg, PSM_SETTITLE, wStyle, cast(LPARAM) lpszText); } VOID PropSheet_SetWizButtons(HWND hPropSheetDlg, DWORD dwFlags) { PostMessage(hPropSheetDlg, PSM_SETWIZBUTTONS, 0, cast(LPARAM) dwFlags); } BOOL PropSheet_PressButton(HWND hPropSheetDlg, int iButton) { return cast(BOOL) SendMessage(hPropSheetDlg, PSM_PRESSBUTTON, iButton, 0); } BOOL PropSheet_SetCurSelByID(HWND hPropSheetDlg, int id) { return cast(BOOL) SendMessage(hPropSheetDlg, PSM_SETCURSELID, 0, id); } VOID PropSheet_SetFinishText(HWND hPropSheetDlg, LPTSTR lpszText) { SendMessage(hPropSheetDlg, PSM_SETFINISHTEXT, 0, cast(LPARAM) lpszText); } HWND PropSheet_GetTabControl(HWND hPropSheetDlg) { return cast(HWND) SendMessage(hPropSheetDlg, PSM_GETTABCONTROL, 0, 0); } BOOL PropSheet_IsDialogMessage(HWND hDlg, LPMSG pMsg) { return cast(BOOL) SendMessage(hDlg, PSM_ISDIALOGMESSAGE, 0, cast(LPARAM) pMsg); } HWND PropSheet_GetCurrentPageHwnd(HWND hDlg) { return cast(HWND) SendMessage(hDlg, PSM_GETCURRENTPAGEHWND, 0, 0); } BOOL PropSheet_InsertPage(HWND hPropSheetDlg, WPARAM wInsertAfter, HPROPSHEETPAGE hpage) { return cast(BOOL) SendMessage(hPropSheetDlg, PSM_INSERTPAGE, wInsertAfter, cast(LPARAM) hpage); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/cguid.d0000664000175000017500000000046712776214756022761 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_cguid.d) */ module core.sys.windows.cguid; version (Windows): private import core.sys.windows.basetyps; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/raserror.d0000664000175000017500000001440012776214756023515 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_raserror.d) */ module core.sys.windows.raserror; version (Windows): enum { SUCCESS = 0, RASBASE = 600, PENDING = RASBASE, ERROR_INVALID_PORT_HANDLE, ERROR_PORT_ALREADY_OPEN, ERROR_BUFFER_TOO_SMALL, ERROR_WRONG_INFO_SPECIFIED, ERROR_CANNOT_SET_PORT_INFO, ERROR_PORT_NOT_CONNECTED, ERROR_EVENT_INVALID, ERROR_DEVICE_DOES_NOT_EXIST, ERROR_DEVICETYPE_DOES_NOT_EXIST, ERROR_BUFFER_INVALID, ERROR_ROUTE_NOT_AVAILABLE, ERROR_ROUTE_NOT_ALLOCATED, ERROR_INVALID_COMPRESSION_SPECIFIED, ERROR_OUT_OF_BUFFERS, ERROR_PORT_NOT_FOUND, ERROR_ASYNC_REQUEST_PENDING, ERROR_ALREADY_DISCONNECTING, ERROR_PORT_NOT_OPEN, ERROR_PORT_DISCONNECTED, ERROR_NO_ENDPOINTS, ERROR_CANNOT_OPEN_PHONEBOOK, ERROR_CANNOT_LOAD_PHONEBOOK, ERROR_CANNOT_FIND_PHONEBOOK_ENTRY, ERROR_CANNOT_WRITE_PHONEBOOK, ERROR_CORRUPT_PHONEBOOK, ERROR_CANNOT_LOAD_STRING, ERROR_KEY_NOT_FOUND, ERROR_DISCONNECTION, ERROR_REMOTE_DISCONNECTION, ERROR_HARDWARE_FAILURE, ERROR_USER_DISCONNECTION, ERROR_INVALID_SIZE, ERROR_PORT_NOT_AVAILABLE, ERROR_CANNOT_PROJECT_CLIENT, ERROR_UNKNOWN, ERROR_WRONG_DEVICE_ATTACHED, ERROR_BAD_STRING, ERROR_REQUEST_TIMEOUT, ERROR_CANNOT_GET_LANA, ERROR_NETBIOS_ERROR, ERROR_SERVER_OUT_OF_RESOURCES, ERROR_NAME_EXISTS_ON_NET, ERROR_SERVER_GENERAL_NET_FAILURE, WARNING_MSG_ALIAS_NOT_ADDED, ERROR_AUTH_INTERNAL, ERROR_RESTRICTED_LOGON_HOURS, ERROR_ACCT_DISABLED, ERROR_PASSWD_EXPIRED, ERROR_NO_DIALIN_PERMISSION, ERROR_SERVER_NOT_RESPONDING, ERROR_FROM_DEVICE, ERROR_UNRECOGNIZED_RESPONSE, ERROR_MACRO_NOT_FOUND, ERROR_MACRO_NOT_DEFINED, ERROR_MESSAGE_MACRO_NOT_FOUND, ERROR_DEFAULTOFF_MACRO_NOT_FOUND, ERROR_FILE_COULD_NOT_BE_OPENED, ERROR_DEVICENAME_TOO_LONG, ERROR_DEVICENAME_NOT_FOUND, ERROR_NO_RESPONSES, ERROR_NO_COMMAND_FOUND, ERROR_WRONG_KEY_SPECIFIED, ERROR_UNKNOWN_DEVICE_TYPE, ERROR_ALLOCATING_MEMORY, ERROR_PORT_NOT_CONFIGURED, ERROR_DEVICE_NOT_READY, ERROR_READING_INI_FILE, ERROR_NO_CONNECTION, ERROR_BAD_USAGE_IN_INI_FILE, ERROR_READING_SECTIONNAME, ERROR_READING_DEVICETYPE, ERROR_READING_DEVICENAME, ERROR_READING_USAGE, ERROR_READING_MAXCONNECTBPS, ERROR_READING_MAXCARRIERBPS, ERROR_LINE_BUSY, ERROR_VOICE_ANSWER, ERROR_NO_ANSWER, ERROR_NO_CARRIER, ERROR_NO_DIALTONE, ERROR_IN_COMMAND, ERROR_WRITING_SECTIONNAME, ERROR_WRITING_DEVICETYPE, ERROR_WRITING_DEVICENAME, ERROR_WRITING_MAXCONNECTBPS, ERROR_WRITING_MAXCARRIERBPS, ERROR_WRITING_USAGE, ERROR_WRITING_DEFAULTOFF, ERROR_READING_DEFAULTOFF, ERROR_EMPTY_INI_FILE, ERROR_AUTHENTICATION_FAILURE, ERROR_PORT_OR_DEVICE, ERROR_NOT_BINARY_MACRO, ERROR_DCB_NOT_FOUND, ERROR_STATE_MACHINES_NOT_STARTED, ERROR_STATE_MACHINES_ALREADY_STARTED, ERROR_PARTIAL_RESPONSE_LOOPING, ERROR_UNKNOWN_RESPONSE_KEY, ERROR_RECV_BUF_FULL, ERROR_CMD_TOO_LONG, ERROR_UNSUPPORTED_BPS, ERROR_UNEXPECTED_RESPONSE, ERROR_INTERACTIVE_MODE, ERROR_BAD_CALLBACK_NUMBER, ERROR_INVALID_AUTH_STATE, ERROR_WRITING_INITBPS, ERROR_X25_DIAGNOSTIC, ERROR_ACCT_EXPIRED, ERROR_CHANGING_PASSWORD, ERROR_OVERRUN, ERROR_RASMAN_CANNOT_INITIALIZE, ERROR_BIPLEX_PORT_NOT_AVAILABLE, ERROR_NO_ACTIVE_ISDN_LINES, ERROR_NO_ISDN_CHANNELS_AVAILABLE, ERROR_TOO_MANY_LINE_ERRORS, ERROR_IP_CONFIGURATION, ERROR_NO_IP_ADDRESSES, ERROR_PPP_TIMEOUT, ERROR_PPP_REMOTE_TERMINATED, ERROR_PPP_NO_PROTOCOLS_CONFIGURED, ERROR_PPP_NO_RESPONSE, ERROR_PPP_INVALID_PACKET, ERROR_PHONE_NUMBER_TOO_LONG, ERROR_IPXCP_NO_DIALOUT_CONFIGURED, ERROR_IPXCP_NO_DIALIN_CONFIGURED, ERROR_IPXCP_DIALOUT_ALREADY_ACTIVE, ERROR_ACCESSING_TCPCFGDLL, ERROR_NO_IP_RAS_ADAPTER, ERROR_SLIP_REQUIRES_IP, ERROR_PROJECTION_NOT_COMPLETE, ERROR_PROTOCOL_NOT_CONFIGURED, ERROR_PPP_NOT_CONVERGING, ERROR_PPP_CP_REJECTED, ERROR_PPP_LCP_TERMINATED, ERROR_PPP_REQUIRED_ADDRESS_REJECTED, ERROR_PPP_NCP_TERMINATED, ERROR_PPP_LOOPBACK_DETECTED, ERROR_PPP_NO_ADDRESS_ASSIGNED, ERROR_CANNOT_USE_LOGON_CREDENTIALS, ERROR_TAPI_CONFIGURATION, ERROR_NO_LOCAL_ENCRYPTION, ERROR_NO_REMOTE_ENCRYPTION, ERROR_REMOTE_REQUIRES_ENCRYPTION, ERROR_IPXCP_NET_NUMBER_CONFLICT, ERROR_INVALID_SMM, ERROR_SMM_UNINITIALIZED, ERROR_NO_MAC_FOR_PORT, ERROR_SMM_TIMEOUT, ERROR_BAD_PHONE_NUMBER, ERROR_WRONG_MODULE, ERROR_INVALID_CALLBACK_NUMBER, ERROR_SCRIPT_SYNTAX, ERROR_HANGUP_FAILED, ERROR_BUNDLE_NOT_FOUND, ERROR_CANNOT_DO_CUSTOMDIAL, ERROR_DIAL_ALREADY_IN_PROGRESS, ERROR_RASAUTO_CANNOT_INITIALIZE, ERROR_CONNECTION_ALREADY_SHARED, ERROR_SHARING_CHANGE_FAILED, ERROR_SHARING_ROUTER_INSTALL, ERROR_SHARE_CONNECTION_FAILED, ERROR_SHARING_PRIVATE_INSTALL, ERROR_CANNOT_SHARE_CONNECTION, ERROR_NO_SMART_CARD_READER, ERROR_SHARING_ADDRESS_EXISTS, ERROR_NO_CERTIFICATE, ERROR_SHARING_MULTIPLE_ADDRESSES, ERROR_FAILED_TO_ENCRYPT, ERROR_BAD_ADDRESS_SPECIFIED, ERROR_CONNECTION_REJECT, ERROR_CONGESTION, ERROR_INCOMPATIBLE, ERROR_NUMBERCHANGED, ERROR_TEMPFAILURE, ERROR_BLOCKED, ERROR_DONOTDISTURB, ERROR_OUTOFORDER, ERROR_UNABLE_TO_AUTHENTICATE_SERVER, ERROR_SMART_CARD_REQUIRED, ERROR_INVALID_FUNCTION_FOR_ENTRY, ERROR_CERT_FOR_ENCRYPTION_NOT_FOUND, ERROR_SHARING_RRAS_CONFLICT, ERROR_SHARING_NO_PRIVATE_LAN, ERROR_NO_DIFF_USER_AT_LOGON, ERROR_NO_REG_CERT_AT_LOGON, ERROR_OAKLEY_NO_CERT, ERROR_OAKLEY_AUTH_FAIL, ERROR_OAKLEY_ATTRIB_FAIL, ERROR_OAKLEY_GENERAL_PROCESSING, ERROR_OAKLEY_NO_PEER_CERT, ERROR_OAKLEY_NO_POLICY, ERROR_OAKLEY_TIMED_OUT, ERROR_OAKLEY_ERROR, ERROR_UNKNOWN_FRAMED_PROTOCOL, ERROR_WRONG_TUNNEL_TYPE, ERROR_UNKNOWN_SERVICE_TYPE, ERROR_CONNECTING_DEVICE_NOT_FOUND, ERROR_NO_EAPTLS_CERTIFICATE, // = RASBASE+198 RASBASEEND = ERROR_NO_EAPTLS_CERTIFICATE } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/shlguid.d0000664000175000017500000000103012776214756023310 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_shlguid.d) */ module core.sys.windows.shlguid; version (Windows): private import core.sys.windows.basetyps, core.sys.windows.w32api; // FIXME: clean up Windows version support // I think this is just a helper macro for other win32 headers? //MACRO #define DEFINE_SHLGUID(n,l,w1,w2) DEFINE_GUID(n,l,w1,w2,0xC0,0,0,0,0,0,0,0x46) ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winuser.d0000664000175000017500000041370712776214756023367 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winuser.d) */ module core.sys.windows.winuser; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "user32"); // Conversion Notes: // The following macros were for win16 only, and are not included in this file: //#define EnumTaskWindows(h, f, p) EnumThreadWindows((DWORD)h, f, p) //#define PostAppMessageA(t, m, w, l) PostThreadMessageA((DWORD)t, m, w, l) //#define PostAppMessageW(t, m, w, l) PostThreadMessageW((DWORD)t, m, w, l) //#define GetSysModalWindow() (NULL) //#define SetSysModalWindow(h) (NULL) //#define GetWindowTask(hWnd) ((HANDLE)GetWindowThreadProcessId(hWnd, NULL)) //#define DefHookProc(c, p, lp, h) CallNextHookEx((HHOOK)*h, c, p, lp) private import core.sys.windows.w32api, core.sys.windows.winbase, core.sys.windows.wingdi; private import core.sys.windows.windef; // for HMONITOR // FIXME: clean up Windows version support LPTSTR MAKEINTATOM_T()(int i) { return cast(LPTSTR) i; } enum LPTSTR WC_DIALOG = MAKEINTATOM_T(0x8002); enum { FAPPCOMMAND_MOUSE = 0x8000, FAPPCOMMAND_KEY = 0, FAPPCOMMAND_OEM = 0x1000, FAPPCOMMAND_MASK = 0xF000 } enum { MNGO_NOINTERFACE = 0, MNGO_NOERROR, MNGOF_TOPGAP = 1, MNGOF_BOTTOMGAP } enum { FVIRTKEY = 1, FNOINVERT = 2, FSHIFT = 4, FCONTROL = 8, FALT = 16 } enum { ATF_TIMEOUTON = 1, ATF_ONOFFFEEDBACK = 2, ATF_AVAILABLE = 4 // May be obsolete. Not in recent MS docs. } enum { WH_MIN = -1, WH_MSGFILTER = -1, WH_JOURNALRECORD, WH_JOURNALPLAYBACK, WH_KEYBOARD, WH_GETMESSAGE, WH_CALLWNDPROC, WH_CBT, WH_SYSMSGFILTER, WH_MOUSE, WH_HARDWARE, WH_DEBUG, WH_SHELL, WH_FOREGROUNDIDLE, WH_CALLWNDPROCRET, WH_KEYBOARD_LL, WH_MOUSE_LL, // = 14 WH_MAX = 14, WH_MINHOOK = WH_MIN, WH_MAXHOOK = WH_MAX } enum { HC_ACTION = 0, HC_GETNEXT, HC_SKIP, HC_NOREMOVE, // = 3 HC_NOREM = HC_NOREMOVE, HC_SYSMODALON, HC_SYSMODALOFF } enum { HCBT_MOVESIZE = 0, HCBT_MINMAX, HCBT_QS, HCBT_CREATEWND, HCBT_DESTROYWND, HCBT_ACTIVATE, HCBT_CLICKSKIPPED, HCBT_KEYSKIPPED, HCBT_SYSCOMMAND, HCBT_SETFOCUS // = 9 } enum { CF_TEXT = 0x0001, CF_BITMAP, CF_METAFILEPICT, CF_SYLK, CF_DIF, CF_TIFF, CF_OEMTEXT, CF_DIB, CF_PALETTE, CF_PENDATA, CF_RIFF, CF_WAVE, CF_UNICODETEXT, CF_ENHMETAFILE, CF_HDROP, CF_LOCALE, CF_DIBV5, CF_MAX, // = 0x0012 CF_OWNERDISPLAY = 0x0080, CF_DSPTEXT, CF_DSPBITMAP, CF_DSPMETAFILEPICT, // = 0x0083 CF_DSPENHMETAFILE = 0x008E, CF_PRIVATEFIRST = 0x0200, CF_PRIVATELAST = 0x02FF, CF_GDIOBJFIRST = 0x0300, CF_GDIOBJLAST = 0x03FF } enum HKL_PREV = 0; enum HKL_NEXT = 1; enum KLF_ACTIVATE = 1; enum KLF_SUBSTITUTE_OK = 2; enum KLF_UNLOADPREVIOUS = 4; enum KLF_REORDER = 8; enum KLF_REPLACELANG = 16; enum KLF_NOTELLSHELL = 128; enum KLF_SETFORPROCESS = 256; enum KL_NAMELENGTH = 9; enum MF_ENABLED = 0; enum MF_GRAYED = 1; enum MF_DISABLED = 2; enum MF_BITMAP = 4; enum MF_CHECKED = 8; enum MF_MENUBARBREAK = 32; enum MF_MENUBREAK = 64; enum MF_OWNERDRAW = 256; enum MF_POPUP = 16; enum MF_SEPARATOR = 0x800; enum MF_STRING = 0; enum MF_UNCHECKED = 0; enum MF_DEFAULT = 4096; enum MF_SYSMENU = 0x2000; enum MF_HELP = 0x4000; enum MF_END = 128; enum MF_RIGHTJUSTIFY = 0x4000; enum MF_MOUSESELECT = 0x8000; enum MF_INSERT = 0; enum MF_CHANGE = 128; enum MF_APPEND = 256; enum MF_DELETE = 512; enum MF_REMOVE = 4096; enum MF_USECHECKBITMAPS = 512; enum MF_UNHILITE = 0; enum MF_HILITE = 128; // Also defined in dbt.h enum BSM_ALLCOMPONENTS = 0; enum BSM_VXDS = 1; enum BSM_NETDRIVER = 2; enum BSM_INSTALLABLEDRIVERS = 4; enum BSM_APPLICATIONS = 8; enum BSM_ALLDESKTOPS = 16; enum { BSF_QUERY = 0x0001, BSF_IGNORECURRENTTASK = 0x0002, BSF_FLUSHDISK = 0x0004, BSF_NOHANG = 0x0008, BSF_POSTMESSAGE = 0x0010, BSF_FORCEIFHUNG = 0x0020, BSF_NOTIMEOUTIFNOTHUNG = 0x0040, BSF_ALLOWSFW = 0x0080, BSF_SENDNOTIFYMESSAGE = 0x0100 } static if (_WIN32_WINNT >= 0x501) { enum { BSF_RETURNHDESK = 0x0200, BSF_LUID = 0x0400 } } enum BROADCAST_QUERY_DENY = 1112363332; enum DWORD ENUM_CURRENT_SETTINGS = -1; enum DWORD ENUM_REGISTRY_SETTINGS = -2; enum CDS_UPDATEREGISTRY = 1; enum CDS_TEST = 2; enum CDS_FULLSCREEN = 4; enum CDS_GLOBAL = 8; enum CDS_SET_PRIMARY = 16; enum CDS_NORESET = 0x10000000; enum CDS_SETRECT = 0x20000000; enum CDS_RESET = 0x40000000; enum { DISP_CHANGE_BADPARAM = -5, DISP_CHANGE_BADFLAGS, DISP_CHANGE_NOTUPDATED, DISP_CHANGE_BADMODE, DISP_CHANGE_FAILED, DISP_CHANGE_SUCCESSFUL, DISP_CHANGE_RESTART // = 1 } enum BST_UNCHECKED = 0; enum BST_CHECKED = 1; enum BST_INDETERMINATE = 2; enum BST_PUSHED = 4; enum BST_FOCUS = 8; enum MF_BYCOMMAND = 0; enum MF_BYPOSITION = 1024; // [Redefined] MF_UNCHECKED = 0 // [Redefined] MF_HILITE = 128 // [Redefined] MF_UNHILITE = 0 enum CWP_ALL = 0; enum CWP_SKIPINVISIBLE = 1; enum CWP_SKIPDISABLED = 2; enum CWP_SKIPTRANSPARENT = 4; enum IMAGE_BITMAP = 0; enum IMAGE_ICON = 1; enum IMAGE_CURSOR = 2; enum IMAGE_ENHMETAFILE = 3; enum DF_ALLOWOTHERACCOUNTHOOK = 1; enum DESKTOP_READOBJECTS = 1; enum DESKTOP_CREATEWINDOW = 2; enum DESKTOP_CREATEMENU = 4; enum DESKTOP_HOOKCONTROL = 8; enum DESKTOP_JOURNALRECORD = 16; enum DESKTOP_JOURNALPLAYBACK = 32; enum DESKTOP_ENUMERATE = 64; enum DESKTOP_WRITEOBJECTS = 128; enum DESKTOP_SWITCHDESKTOP = 256; enum int CW_USEDEFAULT = 0x80000000; enum { WS_OVERLAPPED = 0, WS_TILED = WS_OVERLAPPED, WS_MAXIMIZEBOX = 0x00010000, WS_MINIMIZEBOX = 0x00020000, WS_TABSTOP = 0x00010000, WS_GROUP = 0x00020000, WS_THICKFRAME = 0x00040000, WS_SIZEBOX = WS_THICKFRAME, WS_SYSMENU = 0x00080000, WS_HSCROLL = 0x00100000, WS_VSCROLL = 0x00200000, WS_DLGFRAME = 0x00400000, WS_BORDER = 0x00800000, WS_CAPTION = 0x00c00000, WS_OVERLAPPEDWINDOW = WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW, WS_MAXIMIZE = 0x01000000, WS_CLIPCHILDREN = 0x02000000, WS_CLIPSIBLINGS = 0x04000000, WS_DISABLED = 0x08000000, WS_VISIBLE = 0x10000000, WS_MINIMIZE = 0x20000000, WS_ICONIC = WS_MINIMIZE, WS_CHILD = 0x40000000, WS_CHILDWINDOW = 0x40000000, WS_POPUP = 0x80000000, WS_POPUPWINDOW = WS_POPUP|WS_BORDER|WS_SYSMENU, } enum MDIS_ALLCHILDSTYLES = 1; enum BS_3STATE = 5; enum BS_AUTO3STATE = 6; enum BS_AUTOCHECKBOX = 3; enum BS_AUTORADIOBUTTON = 9; enum BS_BITMAP = 128; enum BS_BOTTOM = 0x800; enum BS_CENTER = 0x300; enum BS_CHECKBOX = 2; enum BS_DEFPUSHBUTTON = 1; enum BS_GROUPBOX = 7; enum BS_ICON = 64; enum BS_LEFT = 256; enum BS_LEFTTEXT = 32; enum BS_MULTILINE = 0x2000; enum BS_NOTIFY = 0x4000; enum BS_OWNERDRAW = 0xb; enum BS_PUSHBUTTON = 0; enum BS_PUSHLIKE = 4096; enum BS_RADIOBUTTON = 4; enum BS_RIGHT = 512; enum BS_RIGHTBUTTON = 32; enum BS_TEXT = 0; enum BS_TOP = 0x400; enum BS_USERBUTTON = 8; enum BS_VCENTER = 0xc00; enum BS_FLAT = 0x8000; enum CBS_AUTOHSCROLL = 64; enum CBS_DISABLENOSCROLL = 0x800; enum CBS_DROPDOWN = 2; enum CBS_DROPDOWNLIST = 3; enum CBS_HASSTRINGS = 512; enum CBS_LOWERCASE = 0x4000; enum CBS_NOINTEGRALHEIGHT = 0x400; enum CBS_OEMCONVERT = 128; enum CBS_OWNERDRAWFIXED = 16; enum CBS_OWNERDRAWVARIABLE = 32; enum CBS_SIMPLE = 1; enum CBS_SORT = 256; enum CBS_UPPERCASE = 0x2000; enum ES_AUTOHSCROLL = 128; enum ES_AUTOVSCROLL = 64; enum ES_CENTER = 1; enum ES_LEFT = 0; enum ES_LOWERCASE = 16; enum ES_MULTILINE = 4; enum ES_NOHIDESEL = 256; enum ES_NUMBER = 0x2000; enum ES_OEMCONVERT = 0x400; enum ES_PASSWORD = 32; enum ES_READONLY = 0x800; enum ES_RIGHT = 2; enum ES_UPPERCASE = 8; enum ES_WANTRETURN = 4096; enum LBS_DISABLENOSCROLL = 4096; enum LBS_EXTENDEDSEL = 0x800; enum LBS_HASSTRINGS = 64; enum LBS_MULTICOLUMN = 512; enum LBS_MULTIPLESEL = 8; enum LBS_NODATA = 0x2000; enum LBS_NOINTEGRALHEIGHT = 256; enum LBS_NOREDRAW = 4; enum LBS_NOSEL = 0x4000; enum LBS_NOTIFY = 1; enum LBS_OWNERDRAWFIXED = 16; enum LBS_OWNERDRAWVARIABLE = 32; enum LBS_SORT = 2; enum LBS_STANDARD = 0xa00003; enum LBS_USETABSTOPS = 128; enum LBS_WANTKEYBOARDINPUT = 0x400; enum SBS_BOTTOMALIGN = 4; enum SBS_HORZ = 0; enum SBS_LEFTALIGN = 2; enum SBS_RIGHTALIGN = 4; enum SBS_SIZEBOX = 8; enum SBS_SIZEBOXBOTTOMRIGHTALIGN = 4; enum SBS_SIZEBOXTOPLEFTALIGN = 2; enum SBS_SIZEGRIP = 16; enum SBS_TOPALIGN = 2; enum SBS_VERT = 1; enum SS_BITMAP = 14; enum SS_BLACKFRAME = 7; enum SS_BLACKRECT = 4; enum SS_CENTER = 1; enum SS_CENTERIMAGE = 512; enum SS_ENHMETAFILE = 15; enum SS_ETCHEDFRAME = 18; enum SS_ETCHEDHORZ = 16; enum SS_ETCHEDVERT = 17; enum SS_GRAYFRAME = 8; enum SS_GRAYRECT = 5; enum SS_ICON = 3; enum SS_LEFT = 0; enum SS_LEFTNOWORDWRAP = 0xc; enum SS_NOPREFIX = 128; enum SS_NOTIFY = 256; enum SS_OWNERDRAW = 0xd; enum SS_REALSIZEIMAGE = 0x800; enum SS_RIGHT = 2; enum SS_RIGHTJUST = 0x400; enum SS_SIMPLE = 11; enum SS_SUNKEN = 4096; enum SS_WHITEFRAME = 9; enum SS_WHITERECT = 6; enum SS_USERITEM = 10; enum SS_TYPEMASK = 0x0000001FL; enum SS_ENDELLIPSIS = 0x00004000L; enum SS_PATHELLIPSIS = 0x00008000L; enum SS_WORDELLIPSIS = 0x0000C000L; enum SS_ELLIPSISMASK = 0x0000C000L; enum DS_ABSALIGN = 0x0001; enum DS_3DLOOK = 0x0004; enum DS_SYSMODAL = 0x0002; enum DS_FIXEDSYS = 0x0008; enum DS_NOFAILCREATE = 0x0010; enum DS_LOCALEDIT = 0x0020; enum DS_SETFONT = 0x0040; enum DS_MODALFRAME = 0x0080; enum DS_NOIDLEMSG = 0x0100; enum DS_SETFOREGROUND = 0x0200; enum DS_CONTROL = 0x0400; enum DS_CENTER = 0x0800; enum DS_CENTERMOUSE = 0x1000; enum DS_CONTEXTHELP = 0x2000; enum DS_SHELLFONT = DS_SETFONT | DS_FIXEDSYS; enum WS_EX_ACCEPTFILES = 16; enum WS_EX_APPWINDOW = 0x40000; enum WS_EX_CLIENTEDGE = 512; enum WS_EX_COMPOSITED = 0x2000000; // XP enum WS_EX_CONTEXTHELP = 0x400; enum WS_EX_CONTROLPARENT = 0x10000; enum WS_EX_DLGMODALFRAME = 1; enum WS_EX_LAYERED = 0x80000; // w2k enum WS_EX_LAYOUTRTL = 0x400000; // w98, w2k enum WS_EX_LEFT = 0; enum WS_EX_LEFTSCROLLBAR = 0x4000; enum WS_EX_LTRREADING = 0; enum WS_EX_MDICHILD = 64; enum WS_EX_NOACTIVATE = 0x8000000; // w2k enum WS_EX_NOINHERITLAYOUT = 0x100000; // w2k enum WS_EX_NOPARENTNOTIFY = 4; enum WS_EX_OVERLAPPEDWINDOW = 0x300; enum WS_EX_PALETTEWINDOW = 0x188; enum WS_EX_RIGHT = 0x1000; enum WS_EX_RIGHTSCROLLBAR = 0; enum WS_EX_RTLREADING = 0x2000; enum WS_EX_STATICEDGE = 0x20000; enum WS_EX_TOOLWINDOW = 128; enum WS_EX_TOPMOST = 8; enum WS_EX_TRANSPARENT = 32; enum WS_EX_WINDOWEDGE = 256; enum WINSTA_ENUMDESKTOPS = 1; enum WINSTA_READATTRIBUTES = 2; enum WINSTA_ACCESSCLIPBOARD = 4; enum WINSTA_CREATEDESKTOP = 8; enum WINSTA_WRITEATTRIBUTES = 16; enum WINSTA_ACCESSGLOBALATOMS = 32; enum WINSTA_EXITWINDOWS = 64; enum WINSTA_ENUMERATE = 256; enum WINSTA_READSCREEN = 512; enum DDL_READWRITE = 0; enum DDL_READONLY = 1; enum DDL_HIDDEN = 2; enum DDL_SYSTEM = 4; enum DDL_DIRECTORY = 16; enum DDL_ARCHIVE = 32; enum DDL_POSTMSGS = 8192; enum DDL_DRIVES = 16384; enum DDL_EXCLUSIVE = 32768; enum { DC_ACTIVE = 0x0001, DC_SMALLCAP = 0x0002, DC_ICON = 0x0004, DC_TEXT = 0x0008, DC_INBUTTON = 0x0010, DC_GRADIENT = 0x0020 } static if (_WIN32_WINNT >= 0x501) { enum DC_BUTTONS = 0x1000; } // Where are these documented? //enum DC_CAPTION = DC_ICON|DC_TEXT|DC_BUTTONS; //enum DC_NC = DC_CAPTION|DC_FRAME; enum BDR_RAISEDOUTER = 1; enum BDR_SUNKENOUTER = 2; enum BDR_RAISEDINNER = 4; enum BDR_SUNKENINNER = 8; enum BDR_OUTER = 3; enum BDR_INNER = 0xc; enum BDR_RAISED = 5; enum BDR_SUNKEN = 10; enum EDGE_RAISED = BDR_RAISEDOUTER|BDR_RAISEDINNER; enum EDGE_SUNKEN = BDR_SUNKENOUTER|BDR_SUNKENINNER; enum EDGE_ETCHED = BDR_SUNKENOUTER|BDR_RAISEDINNER; enum EDGE_BUMP = BDR_RAISEDOUTER|BDR_SUNKENINNER; enum BF_LEFT = 1; enum BF_TOP = 2; enum BF_RIGHT = 4; enum BF_BOTTOM = 8; enum BF_TOPLEFT = BF_TOP|BF_LEFT; enum BF_TOPRIGHT = BF_TOP|BF_RIGHT; enum BF_BOTTOMLEFT = BF_BOTTOM|BF_LEFT; enum BF_BOTTOMRIGHT = BF_BOTTOM|BF_RIGHT; enum BF_RECT = BF_LEFT|BF_TOP|BF_RIGHT|BF_BOTTOM ; enum BF_DIAGONAL = 16; enum BF_DIAGONAL_ENDTOPRIGHT = BF_DIAGONAL|BF_TOP|BF_RIGHT; enum BF_DIAGONAL_ENDTOPLEFT = BF_DIAGONAL|BF_TOP|BF_LEFT; enum BF_DIAGONAL_ENDBOTTOMLEFT = BF_DIAGONAL|BF_BOTTOM|BF_LEFT; enum BF_DIAGONAL_ENDBOTTOMRIGHT = BF_DIAGONAL|BF_BOTTOM|BF_RIGHT; enum BF_MIDDLE = 0x800; enum BF_SOFT = 0x1000; enum BF_ADJUST = 0x2000; enum BF_FLAT = 0x4000; enum BF_MONO = 0x8000; enum { DFC_CAPTION = 1, DFC_MENU, DFC_SCROLL, DFC_BUTTON, DFC_POPUPMENU // = 5 } enum { DFCS_CAPTIONCLOSE, DFCS_CAPTIONMIN, DFCS_CAPTIONMAX, DFCS_CAPTIONRESTORE, DFCS_CAPTIONHELP // = 4 } enum { DFCS_MENUARROW = 0, DFCS_MENUCHECK = 1, DFCS_MENUBULLET = 2, DFCS_MENUARROWRIGHT = 4 } enum { DFCS_SCROLLUP = 0, DFCS_SCROLLDOWN = 1, DFCS_SCROLLLEFT = 2, DFCS_SCROLLRIGHT = 3, DFCS_SCROLLCOMBOBOX = 5, DFCS_SCROLLSIZEGRIP = 8, DFCS_SCROLLSIZEGRIPRIGHT = 16 } enum { DFCS_BUTTONCHECK = 0, DFCS_BUTTONRADIOIMAGE = 0x0001, DFCS_BUTTONRADIOMASK = 0x0002, DFCS_BUTTONRADIO = 0x0004, DFCS_BUTTON3STATE = 0x0008, DFCS_BUTTONPUSH = 0x0010, DFCS_INACTIVE = 0x0100, DFCS_PUSHED = 0x0200, DFCS_CHECKED = 0x0400, DFCS_TRANSPARENT = 0x0800, DFCS_HOT = 0x1000, DFCS_ADJUSTRECT = 0x2000, DFCS_FLAT = 0x4000, DFCS_MONO = 0x8000 } enum { DST_COMPLEX = 0, DST_TEXT, DST_PREFIXTEXT, DST_ICON, DST_BITMAP // = 4 } enum DSS_NORMAL = 0; enum DSS_UNION = 16; enum DSS_DISABLED = 32; enum DSS_MONO = 128; enum DSS_RIGHT = 0x8000; enum DT_BOTTOM = 8; enum DT_CALCRECT = 1024; enum DT_CENTER = 1; enum DT_EDITCONTROL = 8192; enum DT_END_ELLIPSIS = 32768; enum DT_PATH_ELLIPSIS = 16384; enum DT_WORD_ELLIPSIS = 0x40000; enum DT_EXPANDTABS = 64; enum DT_EXTERNALLEADING = 512; enum DT_LEFT = 0; enum DT_MODIFYSTRING = 65536; enum DT_NOCLIP = 256; enum DT_NOPREFIX = 2048; enum DT_RIGHT = 2; enum DT_RTLREADING = 131072; enum DT_SINGLELINE = 32; enum DT_TABSTOP = 128; enum DT_TOP = 0; enum DT_VCENTER = 4; enum DT_WORDBREAK = 16; enum DT_INTERNAL = 4096; enum WB_ISDELIMITER = 2; enum WB_LEFT = 0; enum WB_RIGHT = 1; enum SB_HORZ = 0; enum SB_VERT = 1; enum SB_CTL = 2; enum SB_BOTH = 3; enum ESB_DISABLE_BOTH = 3; enum ESB_DISABLE_DOWN = 2; enum ESB_DISABLE_LEFT = 1; enum ESB_DISABLE_LTUP = 1; enum ESB_DISABLE_RIGHT = 2; enum ESB_DISABLE_RTDN = 2; enum ESB_DISABLE_UP = 1; enum ESB_ENABLE_BOTH = 0; enum SB_LINEUP = 0; enum SB_LINEDOWN = 1; enum SB_LINELEFT = 0; enum SB_LINERIGHT = 1; enum SB_PAGEUP = 2; enum SB_PAGEDOWN = 3; enum SB_PAGELEFT = 2; enum SB_PAGERIGHT = 3; enum SB_THUMBPOSITION = 4; enum SB_THUMBTRACK = 5; enum SB_ENDSCROLL = 8; enum SB_LEFT = 6; enum SB_RIGHT = 7; enum SB_BOTTOM = 7; enum SB_TOP = 6; //MACRO #define IS_INTRESOURCE(i) (((ULONG_PTR)(i) >> 16) == 0) template MAKEINTRESOURCE_T(WORD i) { enum LPTSTR MAKEINTRESOURCE_T = cast(LPTSTR)(i); } nothrow @nogc { LPSTR MAKEINTRESOURCEA(/*WORD*/uint i) { return cast(LPSTR) i; } LPWSTR MAKEINTRESOURCEW(/*WORD*/uint i) { return cast(LPWSTR) i; } } enum RT_CURSOR = MAKEINTRESOURCE_T!(1); enum RT_BITMAP = MAKEINTRESOURCE_T!(2); enum RT_ICON = MAKEINTRESOURCE_T!(3); enum RT_MENU = MAKEINTRESOURCE_T!(4); enum RT_DIALOG = MAKEINTRESOURCE_T!(5); enum RT_STRING = MAKEINTRESOURCE_T!(6); enum RT_FONTDIR = MAKEINTRESOURCE_T!(7); enum RT_FONT = MAKEINTRESOURCE_T!(8); enum RT_ACCELERATOR = MAKEINTRESOURCE_T!(9); enum RT_RCDATA = MAKEINTRESOURCE_T!(10); enum RT_MESSAGETABLE = MAKEINTRESOURCE_T!(11); enum RT_GROUP_CURSOR = MAKEINTRESOURCE_T!(12); enum RT_GROUP_ICON = MAKEINTRESOURCE_T!(14); enum RT_VERSION = MAKEINTRESOURCE_T!(16); enum RT_DLGINCLUDE = MAKEINTRESOURCE_T!(17); enum RT_PLUGPLAY = MAKEINTRESOURCE_T!(19); enum RT_VXD = MAKEINTRESOURCE_T!(20); enum RT_ANICURSOR = MAKEINTRESOURCE_T!(21); enum RT_ANIICON = MAKEINTRESOURCE_T!(22); enum RT_HTML = MAKEINTRESOURCE_T!(23); enum RT_MANIFEST = MAKEINTRESOURCE_T!(24); enum CREATEPROCESS_MANIFEST_RESOURCE_ID = MAKEINTRESOURCE_T!(1); enum ISOLATIONAWARE_MANIFEST_RESOURCE_ID = MAKEINTRESOURCE_T!(2); enum ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID = MAKEINTRESOURCE_T!(3); enum { EWX_LOGOFF = 0, EWX_SHUTDOWN = 1, EWX_REBOOT = 2, EWX_FORCE = 4, EWX_POWEROFF = 8, EWX_FORCEIFHUNG = 16 } enum CS_BYTEALIGNCLIENT = 4096; enum CS_BYTEALIGNWINDOW = 8192; enum CS_KEYCVTWINDOW = 4; enum CS_NOKEYCVT = 256; enum CS_CLASSDC = 64; enum CS_DBLCLKS = 8; enum CS_GLOBALCLASS = 16384; enum CS_HREDRAW = 2; enum CS_NOCLOSE = 512; enum CS_OWNDC = 32; enum CS_PARENTDC = 128; enum CS_SAVEBITS = 2048; enum CS_VREDRAW = 1; enum CS_IME = 0x10000; enum GCW_ATOM = -32; enum GCL_CBCLSEXTRA = -20; enum GCL_CBWNDEXTRA = -18; enum GCL_HBRBACKGROUND = -10; enum GCL_HCURSOR = -12; enum GCL_HICON = -14; enum GCL_HICONSM = -34; enum GCL_HMODULE = -16; enum GCL_MENUNAME = -8; enum GCL_STYLE = -26; enum GCL_WNDPROC = -24; alias GCL_HICONSM GCLP_HICONSM; alias GCL_HICON GCLP_HICON; alias GCL_HCURSOR GCLP_HCURSOR; alias GCL_HBRBACKGROUND GCLP_HBRBACKGROUND; alias GCL_HMODULE GCLP_HMODULE; alias GCL_MENUNAME GCLP_MENUNAME; alias GCL_WNDPROC GCLP_WNDPROC; enum { IDC_ARROW = MAKEINTRESOURCE_T!(32512), IDC_IBEAM = MAKEINTRESOURCE_T!(32513), IDC_WAIT = MAKEINTRESOURCE_T!(32514), IDC_CROSS = MAKEINTRESOURCE_T!(32515), IDC_UPARROW = MAKEINTRESOURCE_T!(32516), IDC_SIZE = MAKEINTRESOURCE_T!(32640), IDC_ICON = MAKEINTRESOURCE_T!(32641), IDC_SIZENWSE = MAKEINTRESOURCE_T!(32642), IDC_SIZENESW = MAKEINTRESOURCE_T!(32643), IDC_SIZEWE = MAKEINTRESOURCE_T!(32644), IDC_SIZENS = MAKEINTRESOURCE_T!(32645), IDC_SIZEALL = MAKEINTRESOURCE_T!(32646), IDC_NO = MAKEINTRESOURCE_T!(32648), IDC_HAND = MAKEINTRESOURCE_T!(32649), IDC_APPSTARTING = MAKEINTRESOURCE_T!(32650), IDC_HELP = MAKEINTRESOURCE_T!(32651), IDI_APPLICATION = MAKEINTRESOURCE_T!(32512), IDI_HAND = MAKEINTRESOURCE_T!(32513), IDI_QUESTION = MAKEINTRESOURCE_T!(32514), IDI_EXCLAMATION = MAKEINTRESOURCE_T!(32515), IDI_ASTERISK = MAKEINTRESOURCE_T!(32516), IDI_WINLOGO = MAKEINTRESOURCE_T!(32517), IDI_WARNING = IDI_EXCLAMATION, IDI_ERROR = IDI_HAND, IDI_INFORMATION = IDI_ASTERISK } static if (_WIN32_WINNT >= 0x600) { enum IDI_SHIELD = MAKEINTRESOURCE_T!(32518); } enum { MIIM_STATE = 0x0001, MIIM_ID = 0x0002, MIIM_SUBMENU = 0x0004, MIIM_CHECKMARKS = 0x0008, MIIM_TYPE = 0x0010, MIIM_DATA = 0x0020, MIIM_STRING = 0x0040, MIIM_BITMAP = 0x0080, MIIM_FTYPE = 0x0100 } enum { MFT_BITMAP = 0x0004, MFT_MENUBARBREAK = 0x0020, MFT_MENUBREAK = 0x0040, MFT_OWNERDRAW = 0x0100, MFT_RADIOCHECK = 0x0200, MFT_RIGHTJUSTIFY = 0x4000, MFT_SEPARATOR = 0x0800, MFT_RIGHTORDER = 0x2000, MFT_STRING = 0 } enum { MFS_CHECKED = 8, MFS_DEFAULT = 4096, MFS_DISABLED = 3, MFS_ENABLED = 0, MFS_GRAYED = 3, MFS_HILITE = 128, MFS_UNCHECKED = 0, MFS_UNHILITE = 0 } enum { GW_HWNDFIRST = 0, GW_HWNDLAST, GW_HWNDNEXT, GW_HWNDPREV, GW_OWNER, GW_CHILD // = 5 } enum { SW_HIDE = 0, SW_NORMAL = 1, SW_SHOWNORMAL = 1, SW_SHOWMINIMIZED = 2, SW_MAXIMIZE = 3, SW_SHOWMAXIMIZED = 3, SW_SHOWNOACTIVATE = 4, SW_SHOW = 5, SW_MINIMIZE = 6, SW_SHOWMINNOACTIVE = 7, SW_SHOWNA = 8, SW_RESTORE = 9, SW_SHOWDEFAULT = 10, SW_FORCEMINIMIZE = 11, SW_MAX = 11 } enum { SW_PARENTCLOSING = 1, SW_OTHERZOOM, SW_PARENTOPENING, SW_OTHERUNZOOM // = 4 } enum { // is this a different SW from the previous? SW_SCROLLCHILDREN = 0x01, SW_INVALIDATE = 0x02, SW_ERASE = 0x04, SW_SMOOTHSCROLL = 0x10 } enum { MB_OK = 0, MB_OKCANCEL, MB_ABORTRETRYIGNORE, MB_YESNOCANCEL, MB_YESNO, MB_RETRYCANCEL, MB_CANCELTRYCONTINUE, // = 6 MB_TYPEMASK = 0x0000000F, MB_ICONHAND = 0x00000010, MB_ICONSTOP = MB_ICONHAND, MB_ICONERROR = MB_ICONHAND, MB_ICONQUESTION = 0x00000020, MB_ICONEXCLAMATION = 0x00000030, MB_ICONWARNING = MB_ICONEXCLAMATION, MB_ICONASTERISK = 0x00000040, MB_ICONINFORMATION = MB_ICONASTERISK, MB_USERICON = 0x00000080, MB_ICONMASK = 0x000000F0, MB_DEFBUTTON1 = 0, MB_DEFBUTTON2 = 0x00000100, MB_DEFBUTTON3 = 0x00000200, MB_DEFBUTTON4 = 0x00000300, MB_DEFMASK = 0x00000F00, MB_APPLMODAL = 0, MB_SYSTEMMODAL = 0x00001000, MB_TASKMODAL = 0x00002000, MB_MODEMASK = 0x00003000, MB_HELP = 0x00004000, MB_NOFOCUS = 0x00008000, MB_MISCMASK = 0x0000C000, MB_SETFOREGROUND = 0x00010000, MB_DEFAULT_DESKTOP_ONLY = 0x00020000, MB_TOPMOST = 0x00040000, MB_SERVICE_NOTIFICATION_NT3X = 0x00040000, MB_RIGHT = 0x00080000, MB_RTLREADING = 0x00100000, MB_SERVICE_NOTIFICATION = 0x00200000 } enum { IDOK = 1, IDCANCEL, IDABORT, IDRETRY, IDIGNORE, IDYES, IDNO, IDCLOSE, IDHELP, IDTRYAGAIN, IDCONTINUE // = 11 } enum GWL_EXSTYLE = -20; enum GWL_STYLE = -16; enum GWL_WNDPROC = -4; enum GWLP_WNDPROC = -4; enum GWL_HINSTANCE = -6; enum GWLP_HINSTANCE = -6; enum GWL_HWNDPARENT = -8; enum GWLP_HWNDPARENT = -8; enum GWL_ID = -12; enum GWLP_ID = -12; enum GWL_USERDATA = -21; enum GWLP_USERDATA = -21; enum DWL_DLGPROC = 4; enum DWLP_DLGPROC = 4; enum DWL_MSGRESULT = 0; enum DWLP_MSGRESULT = 0; enum DWL_USER = 8; enum DWLP_USER = 8; enum QS_KEY = 1; enum QS_MOUSEMOVE = 2; enum QS_MOUSEBUTTON = 4; enum QS_MOUSE = 6; enum QS_POSTMESSAGE = 8; enum QS_TIMER = 16; enum QS_PAINT = 32; enum QS_SENDMESSAGE = 64; enum QS_HOTKEY = 128; enum QS_ALLPOSTMESSAGE = 256; static if (_WIN32_WINNT >= 0x501) { enum QS_RAWINPUT = 1024; enum QS_INPUT = 1031; enum QS_ALLEVENTS = 1215; enum QS_ALLINPUT = 1279; } else { enum QS_INPUT = 7; enum QS_ALLEVENTS = 191; enum QS_ALLINPUT = 255; } enum MWMO_WAITALL = 1; enum MWMO_ALERTABLE = 2; enum MWMO_INPUTAVAILABLE = 4; enum COLOR_3DDKSHADOW = 21; enum COLOR_3DFACE = 15; enum COLOR_3DHILIGHT = 20; enum COLOR_3DHIGHLIGHT = 20; enum COLOR_3DLIGHT = 22; enum COLOR_BTNHILIGHT = 20; enum COLOR_3DSHADOW = 16; enum COLOR_ACTIVEBORDER = 10; enum COLOR_ACTIVECAPTION = 2; enum COLOR_APPWORKSPACE = 12; enum COLOR_BACKGROUND = 1; enum COLOR_DESKTOP = 1; enum COLOR_BTNFACE = 15; enum COLOR_BTNHIGHLIGHT = 20; enum COLOR_BTNSHADOW = 16; enum COLOR_BTNTEXT = 18; enum COLOR_CAPTIONTEXT = 9; enum COLOR_GRAYTEXT = 17; enum COLOR_HIGHLIGHT = 13; enum COLOR_HIGHLIGHTTEXT = 14; enum COLOR_INACTIVEBORDER = 11; enum COLOR_INACTIVECAPTION = 3; enum COLOR_INACTIVECAPTIONTEXT = 19; enum COLOR_INFOBK = 24; enum COLOR_INFOTEXT = 23; enum COLOR_MENU = 4; enum COLOR_MENUTEXT = 7; enum COLOR_SCROLLBAR = 0; enum COLOR_WINDOW = 5; enum COLOR_WINDOWFRAME = 6; enum COLOR_WINDOWTEXT = 8; enum COLOR_HOTLIGHT = 26; enum COLOR_GRADIENTACTIVECAPTION = 27; enum COLOR_GRADIENTINACTIVECAPTION = 28; enum CTLCOLOR_MSGBOX = 0; enum CTLCOLOR_EDIT = 1; enum CTLCOLOR_LISTBOX = 2; enum CTLCOLOR_BTN = 3; enum CTLCOLOR_DLG = 4; enum CTLCOLOR_SCROLLBAR = 5; enum CTLCOLOR_STATIC = 6; enum CTLCOLOR_MAX = 7; // For GetSystemMetrics() enum : int { SM_CXSCREEN = 0, SM_CYSCREEN, SM_CXVSCROLL, SM_CYHSCROLL, SM_CYCAPTION, SM_CXBORDER, SM_CYBORDER, SM_CXDLGFRAME, // = 7 SM_CXFIXEDFRAME = SM_CXDLGFRAME, SM_CYDLGFRAME, // = 8 SM_CYFIXEDFRAME = SM_CYDLGFRAME, SM_CYVTHUMB, // = 9 SM_CXHTHUMB, SM_CXICON, SM_CYICON, SM_CXCURSOR, SM_CYCURSOR, SM_CYMENU, SM_CXFULLSCREEN, SM_CYFULLSCREEN, SM_CYKANJIWINDOW, SM_MOUSEPRESENT, SM_CYVSCROLL, SM_CXHSCROLL, SM_DEBUG, SM_SWAPBUTTON, SM_RESERVED1, SM_RESERVED2, SM_RESERVED3, SM_RESERVED4, SM_CXMIN, SM_CYMIN, SM_CXSIZE, SM_CYSIZE, SM_CXSIZEFRAME, // = 32, SM_CXFRAME = SM_CXSIZEFRAME, SM_CYSIZEFRAME, // = 33 SM_CYFRAME = SM_CYSIZEFRAME, SM_CXMINTRACK, SM_CYMINTRACK, SM_CXDOUBLECLK, SM_CYDOUBLECLK, SM_CXICONSPACING, SM_CYICONSPACING, SM_MENUDROPALIGNMENT, SM_PENWINDOWS, SM_DBCSENABLED, SM_CMOUSEBUTTONS, SM_SECURE, SM_CXEDGE, SM_CYEDGE, SM_CXMINSPACING, SM_CYMINSPACING, SM_CXSMICON, SM_CYSMICON, SM_CYSMCAPTION, SM_CXSMSIZE, SM_CYSMSIZE, SM_CXMENUSIZE, SM_CYMENUSIZE, SM_ARRANGE, SM_CXMINIMIZED, SM_CYMINIMIZED, SM_CXMAXTRACK, SM_CYMAXTRACK, SM_CXMAXIMIZED, SM_CYMAXIMIZED, SM_NETWORK, // = 63 SM_CLEANBOOT = 67, SM_CXDRAG, SM_CYDRAG, SM_SHOWSOUNDS, SM_CXMENUCHECK, SM_CYMENUCHECK, SM_SLOWMACHINE, SM_MIDEASTENABLED, SM_MOUSEWHEELPRESENT, SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_CMONITORS, SM_SAMEDISPLAYFORMAT, SM_IMMENABLED, SM_CXFOCUSBORDER, SM_CYFOCUSBORDER, // = 84 SM_TABLETPC = 86, SM_MEDIACENTER, SM_STARTER, // = 88 SM_CMETRICS = 88, SM_SERVERR2, SM_REMOTESESSION = 0x1000, } static if (_WIN32_WINNT >= 0x501) { enum { // These are only for WinXP and later SM_SHUTTINGDOWN = 0x2000, SM_REMOTECONTROL = 0x2001 } } enum ARW_BOTTOMLEFT = 0; enum ARW_BOTTOMRIGHT = 1; enum ARW_HIDE = 8; enum ARW_TOPLEFT = 2; enum ARW_TOPRIGHT = 3; enum ARW_DOWN = 4; enum ARW_LEFT = 0; enum ARW_RIGHT = 0; enum ARW_UP = 4; enum UOI_FLAGS = 1; enum UOI_NAME = 2; enum UOI_TYPE = 3; enum UOI_USER_SID = 4; // For the fuLoad parameter of LoadImage() enum : UINT { LR_DEFAULTCOLOR = 0, LR_MONOCHROME = 0x0001, LR_COLOR = 0x0002, LR_COPYRETURNORG = 0x0004, LR_COPYDELETEORG = 0x0008, LR_LOADFROMFILE = 0x0010, LR_LOADTRANSPARENT = 0x0020, LR_DEFAULTSIZE = 0x0040, LR_VGACOLOR = 0x0080, LR_LOADREALSIZE = 0x0080, LR_LOADMAP3DCOLORS = 0x1000, LR_CREATEDIBSECTION = 0x2000, LR_COPYFROMRESOURCE = 0x4000, LR_SHARED = 0x8000 } enum { KEYEVENTF_EXTENDEDKEY = 1, KEYEVENTF_KEYUP = 2, KEYEVENTF_UNICODE = 4, KEYEVENTF_SCANCODE = 8 } enum OBM_BTNCORNERS = 32758; enum OBM_BTSIZE = 32761; enum OBM_CHECK = 32760; enum OBM_CHECKBOXES = 32759; enum OBM_CLOSE = 32754; enum OBM_COMBO = 32738; enum OBM_DNARROW = 32752; enum OBM_DNARROWD = 32742; enum OBM_DNARROWI = 32736; enum OBM_LFARROW = 32750; enum OBM_LFARROWI = 32734; enum OBM_LFARROWD = 32740; enum OBM_MNARROW = 32739; enum OBM_OLD_CLOSE = 32767; enum OBM_OLD_DNARROW = 32764; enum OBM_OLD_LFARROW = 32762; enum OBM_OLD_REDUCE = 32757; enum OBM_OLD_RESTORE = 32755; enum OBM_OLD_RGARROW = 32763; enum OBM_OLD_UPARROW = 32765; enum OBM_OLD_ZOOM = 32756; enum OBM_REDUCE = 32749; enum OBM_REDUCED = 32746; enum OBM_RESTORE = 32747; enum OBM_RESTORED = 32744; enum OBM_RGARROW = 32751; enum OBM_RGARROWD = 32741; enum OBM_RGARROWI = 32735; enum OBM_SIZE = 32766; enum OBM_UPARROW = 32753; enum OBM_UPARROWD = 32743; enum OBM_UPARROWI = 32737; enum OBM_ZOOM = 32748; enum OBM_ZOOMD = 32745; enum OCR_NORMAL = 32512; enum OCR_IBEAM = 32513; enum OCR_WAIT = 32514; enum OCR_CROSS = 32515; enum OCR_UP = 32516; enum OCR_SIZE = 32640; enum OCR_ICON = 32641; enum OCR_SIZENWSE = 32642; enum OCR_SIZENESW = 32643; enum OCR_SIZEWE = 32644; enum OCR_SIZENS = 32645; enum OCR_SIZEALL = 32646; enum OCR_NO = 32648; enum OCR_APPSTARTING = 32650; enum OIC_SAMPLE = 32512; enum OIC_HAND = 32513; enum OIC_QUES = 32514; enum OIC_BANG = 32515; enum OIC_NOTE = 32516; enum OIC_WINLOGO = 32517; enum OIC_WARNING = OIC_BANG; enum OIC_ERROR = OIC_HAND; enum OIC_INFORMATION = OIC_NOTE; enum HELPINFO_MENUITEM = 2; enum HELPINFO_WINDOW = 1; static if (_WIN32_WINNT >= 0x501) { enum { WTS_CONSOLE_CONNECT = 1, WTS_CONSOLE_DISCONNECT, WTS_REMOTE_CONNECT, WTS_REMOTE_DISCONNECT, WTS_SESSION_LOGON, WTS_SESSION_LOGOFF, WTS_SESSION_LOCK, WTS_SESSION_UNLOCK, WTS_SESSION_REMOTE_CONTROL // = 9 } } enum MSGF_DIALOGBOX = 0; enum MSGF_MESSAGEBOX = 1; enum MSGF_MENU = 2; enum MSGF_MOVE = 3; enum MSGF_SIZE = 4; enum MSGF_SCROLLBAR = 5; enum MSGF_NEXTWINDOW = 6; enum MSGF_MAINLOOP = 8; enum MSGF_USER = 4096; enum { MOUSEEVENTF_MOVE = 0x0001, MOUSEEVENTF_LEFTDOWN = 0x0002, MOUSEEVENTF_LEFTUP = 0x0004, MOUSEEVENTF_RIGHTDOWN = 0x0008, MOUSEEVENTF_RIGHTUP = 0x0010, MOUSEEVENTF_MIDDLEDOWN = 0x0020, MOUSEEVENTF_MIDDLEUP = 0x0040, MOUSEEVENTF_XDOWN = 0x0080, MOUSEEVENTF_XUP = 0x0100, MOUSEEVENTF_WHEEL = 0x0800, MOUSEEVENTF_ABSOLUTE = 0x8000 } enum PM_NOREMOVE = 0; enum PM_REMOVE = 1; enum PM_NOYIELD = 2; enum : HWND { HWND_BROADCAST = cast(HWND) 0xFFFF, HWND_MESSAGE = cast(HWND) -3, HWND_NOTOPMOST = cast(HWND) -2, HWND_TOPMOST = cast(HWND) -1, HWND_TOP = cast(HWND) 0, HWND_DESKTOP = cast(HWND) 0, HWND_BOTTOM = cast(HWND) 1 } enum RDW_INVALIDATE = 1; enum RDW_INTERNALPAINT = 2; enum RDW_ERASE = 4; enum RDW_VALIDATE = 8; enum RDW_NOINTERNALPAINT = 16; enum RDW_NOERASE = 32; enum RDW_NOCHILDREN = 64; enum RDW_ALLCHILDREN = 128; enum RDW_UPDATENOW = 256; enum RDW_ERASENOW = 512; enum RDW_FRAME = 1024; enum RDW_NOFRAME = 2048; enum { SMTO_NORMAL = 0, SMTO_BLOCK = 1, SMTO_ABORTIFHUNG = 2, SMTO_NOTIMEOUTIFNOTHUNG = 8 } enum SIF_ALL = 23; enum SIF_PAGE = 2; enum SIF_POS = 4; enum SIF_RANGE = 1; enum SIF_DISABLENOSCROLL = 8; enum SIF_TRACKPOS = 16; enum SWP_DRAWFRAME = 32; enum SWP_FRAMECHANGED = 32; enum SWP_HIDEWINDOW = 128; enum SWP_NOACTIVATE = 16; enum SWP_NOCOPYBITS = 256; enum SWP_NOMOVE = 2; enum SWP_NOSIZE = 1; enum SWP_NOREDRAW = 8; enum SWP_NOZORDER = 4; enum SWP_SHOWWINDOW = 64; enum SWP_NOOWNERZORDER = 512; enum SWP_NOREPOSITION = 512; enum SWP_NOSENDCHANGING = 1024; enum SWP_DEFERERASE = 8192; enum SWP_ASYNCWINDOWPOS = 16384; enum { // passed variously as int or WPARAM HSHELL_WINDOWCREATED = 1, HSHELL_WINDOWDESTROYED, HSHELL_ACTIVATESHELLWINDOW, HSHELL_WINDOWACTIVATED, HSHELL_GETMINRECT, HSHELL_REDRAW, HSHELL_TASKMAN, HSHELL_LANGUAGE, // = 8 HSHELL_ENDTASK = 10, HSHELL_ACCESSIBILITYSTATE, HSHELL_APPCOMMAND, // = 12 HSHELL_RUDEAPPACTIVATED = 32772, HSHELL_FLASH = 32774 } static if (_WIN32_WINNT >= 0x501) { enum { HSHELL_WINDOWREPLACED = 13, HSHELL_WINDOWREPLACING } } enum { SPI_GETBEEP = 0x0001, SPI_SETBEEP = 0x0002, SPI_GETMOUSE = 0x0003, SPI_SETMOUSE = 0x0004, SPI_GETBORDER = 0x0005, SPI_SETBORDER = 0x0006, SPI_GETKEYBOARDSPEED = 0x000A, SPI_SETKEYBOARDSPEED = 0x000B, SPI_LANGDRIVER = 0x000C, SPI_ICONHORIZONTALSPACING = 0x000D, SPI_GETSCREENSAVETIMEOUT = 0x000E, SPI_SETSCREENSAVETIMEOUT = 0x000F, SPI_GETSCREENSAVEACTIVE = 0x0010, SPI_SETSCREENSAVEACTIVE = 0x0011, SPI_GETGRIDGRANULARITY = 0x0012, SPI_SETGRIDGRANULARITY = 0x0013, SPI_SETDESKWALLPAPER = 0x0014, SPI_SETDESKPATTERN = 0x0015, SPI_GETKEYBOARDDELAY = 0x0016, SPI_SETKEYBOARDDELAY = 0x0017, SPI_ICONVERTICALSPACING = 0x0018, SPI_GETICONTITLEWRAP = 0x0019, SPI_SETICONTITLEWRAP = 0x001A, SPI_GETMENUDROPALIGNMENT = 0x001B, SPI_SETMENUDROPALIGNMENT = 0x001C, SPI_SETDOUBLECLKWIDTH = 0x001D, SPI_SETDOUBLECLKHEIGHT = 0x001E, SPI_GETICONTITLELOGFONT = 0x001F, SPI_SETDOUBLECLICKTIME = 0x0020, SPI_SETMOUSEBUTTONSWAP = 0x0021, SPI_SETICONTITLELOGFONT = 0x0022, SPI_GETFASTTASKSWITCH = 0x0023, SPI_SETFASTTASKSWITCH = 0x0024, SPI_SETDRAGFULLWINDOWS = 0x0025, SPI_GETDRAGFULLWINDOWS = 0x0026, SPI_GETNONCLIENTMETRICS = 0x0029, SPI_SETNONCLIENTMETRICS = 0x002A, SPI_GETMINIMIZEDMETRICS = 0x002B, SPI_SETMINIMIZEDMETRICS = 0x002C, SPI_GETICONMETRICS = 0x002D, SPI_SETICONMETRICS = 0x002E, SPI_SETWORKAREA = 0x002F, SPI_GETWORKAREA = 0x0030, SPI_SETPENWINDOWS = 0x0031, SPI_GETFILTERKEYS = 0x0032, SPI_SETFILTERKEYS = 0x0033, SPI_GETTOGGLEKEYS = 0x0034, SPI_SETTOGGLEKEYS = 0x0035, SPI_GETMOUSEKEYS = 0x0036, SPI_SETMOUSEKEYS = 0x0037, SPI_GETSHOWSOUNDS = 0x0038, SPI_SETSHOWSOUNDS = 0x0039, SPI_GETSTICKYKEYS = 0x003A, SPI_SETSTICKYKEYS = 0x003B, SPI_GETACCESSTIMEOUT = 0x003C, SPI_SETACCESSTIMEOUT = 0x003D, SPI_GETSERIALKEYS = 0x003E, SPI_SETSERIALKEYS = 0x003F, SPI_GETSOUNDSENTRY = 0x0040, SPI_SETSOUNDSENTRY = 0x0041, SPI_GETHIGHCONTRAST = 0x0042, SPI_SETHIGHCONTRAST = 0x0043, SPI_GETKEYBOARDPREF = 0x0044, SPI_SETKEYBOARDPREF = 0x0045, SPI_GETSCREENREADER = 0x0046, SPI_SETSCREENREADER = 0x0047, SPI_GETANIMATION = 0x0048, SPI_SETANIMATION = 0x0049, SPI_GETFONTSMOOTHING = 0x004A, SPI_SETFONTSMOOTHING = 0x004B, SPI_SETDRAGWIDTH = 0x004C, SPI_SETDRAGHEIGHT = 0x004D, SPI_SETHANDHELD = 0x004E, SPI_GETLOWPOWERTIMEOUT = 0x004F, SPI_GETPOWEROFFTIMEOUT = 0x0050, SPI_SETLOWPOWERTIMEOUT = 0x0051, SPI_SETPOWEROFFTIMEOUT = 0x0052, SPI_GETLOWPOWERACTIVE = 0x0053, SPI_GETPOWEROFFACTIVE = 0x0054, SPI_SETLOWPOWERACTIVE = 0x0055, SPI_SETPOWEROFFACTIVE = 0x0056, SPI_SETCURSORS = 0x0057, SPI_SETICONS = 0x0058, SPI_GETDEFAULTINPUTLANG = 0x0059, SPI_SETDEFAULTINPUTLANG = 0x005A, SPI_SETLANGTOGGLE = 0x005B, SPI_GETWINDOWSEXTENSION = 0x005C, SPI_SETMOUSETRAILS = 0x005D, SPI_GETMOUSETRAILS = 0x005E, SPI_GETSNAPTODEFBUTTON = 0x005F, SPI_SETSNAPTODEFBUTTON = 0x0060, //SPI_SCREENSAVERRUNNING = 0x0061, // mistake in older MinGW? SPI_SETSCREENSAVERRUNNING = 0x0061, SPI_GETMOUSEHOVERWIDTH = 0x0062, SPI_SETMOUSEHOVERWIDTH = 0x0063, SPI_GETMOUSEHOVERHEIGHT = 0x0064, SPI_SETMOUSEHOVERHEIGHT = 0x0065, SPI_GETMOUSEHOVERTIME = 0x0066, SPI_SETMOUSEHOVERTIME = 0x0067, SPI_GETWHEELSCROLLLINES = 0x0068, SPI_SETWHEELSCROLLLINES = 0x0069, SPI_GETMENUSHOWDELAY = 0x006A, SPI_SETMENUSHOWDELAY = 0x006B, SPI_GETSHOWIMEUI = 0x006E, SPI_SETSHOWIMEUI = 0x006F, SPI_GETMOUSESPEED = 0x0070, SPI_SETMOUSESPEED = 0x0071, SPI_GETSCREENSAVERRUNNING = 0x0072, SPI_GETDESKWALLPAPER = 0x0073, SPI_GETACTIVEWINDOWTRACKING = 0x1000, SPI_SETACTIVEWINDOWTRACKING = 0x1001, SPI_GETMENUANIMATION = 0x1002, SPI_SETMENUANIMATION = 0x1003, SPI_GETCOMBOBOXANIMATION = 0x1004, SPI_SETCOMBOBOXANIMATION = 0x1005, SPI_GETLISTBOXSMOOTHSCROLLING = 0x1006, SPI_SETLISTBOXSMOOTHSCROLLING = 0x1007, SPI_GETGRADIENTCAPTIONS = 0x1008, SPI_SETGRADIENTCAPTIONS = 0x1009, SPI_GETKEYBOARDCUES = 0x100A, SPI_GETMENUUNDERLINES = SPI_GETKEYBOARDCUES, SPI_SETKEYBOARDCUES = 0x100B, SPI_SETMENUUNDERLINES = SPI_SETKEYBOARDCUES, SPI_GETACTIVEWNDTRKZORDER = 0x100C, SPI_SETACTIVEWNDTRKZORDER = 0x100D, SPI_GETHOTTRACKING = 0x100E, SPI_SETHOTTRACKING = 0x100F, SPI_GETMENUFADE = 0x1012, SPI_SETMENUFADE = 0x1013, SPI_GETSELECTIONFADE = 0x1014, SPI_SETSELECTIONFADE = 0x1015, SPI_GETTOOLTIPANIMATION = 0x1016, SPI_SETTOOLTIPANIMATION = 0x1017, SPI_GETTOOLTIPFADE = 0x1018, SPI_SETTOOLTIPFADE = 0x1019, SPI_GETCURSORSHADOW = 0x101A, SPI_SETCURSORSHADOW = 0x101B, SPI_GETBLOCKSENDINPUTRESETS = 0x1026, SPI_SETBLOCKSENDINPUTRESETS = 0x1027, SPI_GETUIEFFECTS = 0x103E, SPI_SETUIEFFECTS = 0x103F, SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000, SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001, SPI_GETACTIVEWNDTRKTIMEOUT = 0x2002, SPI_SETACTIVEWNDTRKTIMEOUT = 0x2003, SPI_GETFOREGROUNDFLASHCOUNT = 0x2004, SPI_SETFOREGROUNDFLASHCOUNT = 0x2005, SPI_GETCARETWIDTH = 0x2006, SPI_SETCARETWIDTH = 0x2007 } enum { SPIF_UPDATEINIFILE = 1, SPIF_SENDWININICHANGE = 2, SPIF_SENDCHANGE = SPIF_SENDWININICHANGE } // [Redefined] ATF_ONOFFFEEDBACK = 2 // [Redefined] ATF_TIMEOUTON = 1 enum WM_APP = 32768; enum WM_ACTIVATE = 6; enum WM_ACTIVATEAPP = 28; enum WM_AFXFIRST = 864; enum WM_AFXLAST = 895; enum WM_ASKCBFORMATNAME = 780; enum WM_CANCELJOURNAL = 75; enum WM_CANCELMODE = 31; enum WM_CAPTURECHANGED = 533; enum WM_CHANGECBCHAIN = 781; enum WM_CHAR = 258; enum WM_CHARTOITEM = 47; enum WM_CHILDACTIVATE = 34; enum WM_CLEAR = 771; enum WM_CLOSE = 16; enum WM_COMMAND = 273; enum WM_COMMNOTIFY = 68; // obsolete enum WM_COMPACTING = 65; enum WM_COMPAREITEM = 57; enum WM_CONTEXTMENU = 123; enum WM_COPY = 769; enum WM_COPYDATA = 74; enum WM_CREATE = 1; enum WM_CTLCOLORBTN = 309; enum WM_CTLCOLORDLG = 310; enum WM_CTLCOLOREDIT = 307; enum WM_CTLCOLORLISTBOX = 308; enum WM_CTLCOLORMSGBOX = 306; enum WM_CTLCOLORSCROLLBAR = 311; enum WM_CTLCOLORSTATIC = 312; enum WM_CUT = 768; enum WM_DEADCHAR = 259; enum WM_DELETEITEM = 45; enum WM_DESTROY = 2; enum WM_DESTROYCLIPBOARD = 775; enum WM_DEVICECHANGE = 537; enum WM_DEVMODECHANGE = 27; enum WM_DISPLAYCHANGE = 126; enum WM_DRAWCLIPBOARD = 776; enum WM_DRAWITEM = 43; enum WM_DROPFILES = 563; enum WM_ENABLE = 10; enum WM_ENDSESSION = 22; enum WM_ENTERIDLE = 289; enum WM_ENTERMENULOOP = 529; enum WM_ENTERSIZEMOVE = 561; enum WM_ERASEBKGND = 20; enum WM_EXITMENULOOP = 530; enum WM_EXITSIZEMOVE = 562; enum WM_FONTCHANGE = 29; enum WM_GETDLGCODE = 135; enum WM_GETFONT = 49; enum WM_GETHOTKEY = 51; enum WM_GETICON = 127; enum WM_GETMINMAXINFO = 36; enum WM_GETTEXT = 13; enum WM_GETTEXTLENGTH = 14; enum WM_HANDHELDFIRST = 856; enum WM_HANDHELDLAST = 863; enum WM_HELP = 83; enum WM_HOTKEY = 786; enum WM_HSCROLL = 276; enum WM_HSCROLLCLIPBOARD = 782; enum WM_ICONERASEBKGND = 39; enum WM_INITDIALOG = 272; enum WM_INITMENU = 278; enum WM_INITMENUPOPUP = 279; enum WM_INPUTLANGCHANGE = 81; enum WM_INPUTLANGCHANGEREQUEST = 80; enum WM_KEYDOWN = 256; enum WM_KEYUP = 257; enum WM_KILLFOCUS = 8; enum WM_MDIACTIVATE = 546; enum WM_MDICASCADE = 551; enum WM_MDICREATE = 544; enum WM_MDIDESTROY = 545; enum WM_MDIGETACTIVE = 553; enum WM_MDIICONARRANGE = 552; enum WM_MDIMAXIMIZE = 549; enum WM_MDINEXT = 548; enum WM_MDIREFRESHMENU = 564; enum WM_MDIRESTORE = 547; enum WM_MDISETMENU = 560; enum WM_MDITILE = 550; enum WM_MEASUREITEM = 44; enum WM_UNINITMENUPOPUP = 0x0125; enum WM_MENURBUTTONUP = 290; enum WM_MENUCOMMAND = 0x0126; enum WM_MENUGETOBJECT = 0x0124; enum WM_MENUDRAG = 0x0123; enum WM_CHANGEUISTATE = 0x0127; enum WM_UPDATEUISTATE = 0x0128; enum WM_QUERYUISTATE = 0x0129; // LOWORD(wParam) values in WM_*UISTATE* enum { UIS_SET = 1, UIS_CLEAR = 2, UIS_INITIALIZE = 3 } // HIWORD(wParam) values in WM_*UISTATE* enum { UISF_HIDEFOCUS = 0x1, UISF_HIDEACCEL = 0x2 } static if (_WIN32_WINNT >= 0x501) { // HIWORD(wParam) values in WM_*UISTATE* enum { UISF_ACTIVE = 0x4 } } enum WM_MENUCHAR = 288; enum WM_MENUSELECT = 287; enum WM_MOVE = 3; enum WM_MOVING = 534; enum WM_NCACTIVATE = 134; enum WM_NCCALCSIZE = 131; enum WM_NCCREATE = 129; enum WM_NCDESTROY = 130; enum WM_NCHITTEST = 132; enum WM_NCLBUTTONDBLCLK = 163; enum WM_NCLBUTTONDOWN = 161; enum WM_NCLBUTTONUP = 162; enum WM_NCMBUTTONDBLCLK = 169; enum WM_NCMBUTTONDOWN = 167; enum WM_NCMBUTTONUP = 168; enum WM_NCXBUTTONDOWN = 171; enum WM_NCXBUTTONUP = 172; enum WM_NCXBUTTONDBLCLK = 173; enum WM_NCMOUSEHOVER = 0x02A0; enum WM_NCMOUSELEAVE = 0x02A2; enum WM_NCMOUSEMOVE = 160; enum WM_NCPAINT = 133; enum WM_NCRBUTTONDBLCLK = 166; enum WM_NCRBUTTONDOWN = 164; enum WM_NCRBUTTONUP = 165; enum WM_NEXTDLGCTL = 40; enum WM_NEXTMENU = 531; enum WM_NOTIFY = 78; enum WM_NOTIFYFORMAT = 85; enum WM_NULL = 0; enum WM_PAINT = 15; enum WM_PAINTCLIPBOARD = 777; enum WM_PAINTICON = 38; enum WM_PALETTECHANGED = 785; enum WM_PALETTEISCHANGING = 784; enum WM_PARENTNOTIFY = 528; enum WM_PASTE = 770; enum WM_PENWINFIRST = 896; enum WM_PENWINLAST = 911; enum WM_POWER = 72; enum WM_POWERBROADCAST = 536; enum WM_PRINT = 791; enum WM_PRINTCLIENT = 792; enum WM_APPCOMMAND = 0x0319; enum WM_QUERYDRAGICON = 55; enum WM_QUERYENDSESSION = 17; enum WM_QUERYNEWPALETTE = 783; enum WM_QUERYOPEN = 19; enum WM_QUEUESYNC = 35; enum WM_QUIT = 18; enum WM_RENDERALLFORMATS = 774; enum WM_RENDERFORMAT = 773; enum WM_SETCURSOR = 32; enum WM_SETFOCUS = 7; enum WM_SETFONT = 48; enum WM_SETHOTKEY = 50; enum WM_SETICON = 128; enum WM_SETREDRAW = 11; enum WM_SETTEXT = 12; enum WM_SETTINGCHANGE = 26; enum WM_SHOWWINDOW = 24; enum WM_SIZE = 5; enum WM_SIZECLIPBOARD = 779; enum WM_SIZING = 532; enum WM_SPOOLERSTATUS = 42; enum WM_STYLECHANGED = 125; enum WM_STYLECHANGING = 124; enum WM_SYSCHAR = 262; enum WM_SYSCOLORCHANGE = 21; enum WM_SYSCOMMAND = 274; enum WM_SYSDEADCHAR = 263; enum WM_SYSKEYDOWN = 260; enum WM_SYSKEYUP = 261; static if (_WIN32_WINNT >= 0x501) { enum WM_TABLET_FIRST = 704; enum WM_TABLET_LAST = 735; } enum WM_TCARD = 82; enum WM_THEMECHANGED = 794; enum WM_TIMECHANGE = 30; enum WM_TIMER = 275; enum WM_UNDO = 772; enum WM_USER = 1024; enum WM_USERCHANGED = 84; enum WM_VKEYTOITEM = 46; enum WM_VSCROLL = 277; enum WM_VSCROLLCLIPBOARD = 778; enum WM_WINDOWPOSCHANGED = 71; enum WM_WINDOWPOSCHANGING = 70; enum WM_WININICHANGE = 26; static if(_WIN32_WINNT >= 0x501) { enum WM_WTSSESSION_CHANGE = 689; } enum WM_INPUT = 255; enum WM_KEYFIRST = 256; static if(_WIN32_WINNT >= 0x501) { enum WM_UNICHAR = 265; enum WM_KEYLAST = 265; enum UNICODE_NOCHAR = 0xFFFF; } else { enum WM_KEYLAST = 264; } enum WM_SYNCPAINT = 136; enum WM_MOUSEACTIVATE = 33; enum WM_MOUSEMOVE = 512; enum WM_LBUTTONDOWN = 513; enum WM_LBUTTONUP = 514; enum WM_LBUTTONDBLCLK = 515; enum WM_RBUTTONDOWN = 516; enum WM_RBUTTONUP = 517; enum WM_RBUTTONDBLCLK = 518; enum WM_MBUTTONDOWN = 519; enum WM_MBUTTONUP = 520; enum WM_MBUTTONDBLCLK = 521; enum WM_MOUSEWHEEL = 522; enum WM_MOUSEFIRST = 512; static if (_WIN32_WINNT >= 0x501) { enum WM_XBUTTONDOWN = 523; enum WM_XBUTTONUP = 524; enum WM_XBUTTONDBLCLK = 525; } static if (_WIN32_WINNT >= 0x600) { // FIXME: where did this come from? what version is it? enum WM_MOUSEHWHEEL = 526; } static if (_WIN32_WINNT >= 0x600) { enum WM_MOUSELAST = WM_MOUSEHWHEEL; } else static if (_WIN32_WINNT >= 0x501) { enum WM_MOUSELAST = WM_XBUTTONDBLCLK; } else { enum WM_MOUSELAST = WM_MOUSEWHEEL; } enum WM_MOUSEHOVER = 0x2A1; enum WM_MOUSELEAVE = 0x2A3; enum WHEEL_DELTA = 120; SHORT GET_WHEEL_DELTA_WPARAM()(WPARAM wparam) { return cast(SHORT) HIWORD(wparam); } enum WHEEL_PAGESCROLL = uint.max; enum BM_CLICK = 245; enum BM_GETCHECK = 240; enum BM_GETIMAGE = 246; enum BM_GETSTATE = 242; enum BM_SETCHECK = 241; enum BM_SETIMAGE = 247; static if(_WIN32_WINNT >= 0x600) { enum BM_SETDONTCLICK = 248; } enum BM_SETSTATE = 243; enum BM_SETSTYLE = 244; enum BN_CLICKED = 0; enum BN_DBLCLK = 5; enum BN_DISABLE = 4; enum BN_DOUBLECLICKED = 5; enum BN_HILITE = 2; enum BN_KILLFOCUS = 7; enum BN_PAINT = 1; enum BN_PUSHED = 2; enum BN_SETFOCUS = 6; enum BN_UNHILITE = 3; enum BN_UNPUSHED = 3; enum CB_ADDSTRING = 323; enum CB_DELETESTRING = 324; enum CB_DIR = 325; enum CB_FINDSTRING = 332; enum CB_FINDSTRINGEXACT = 344; enum CB_GETCOUNT = 326; enum CB_GETCURSEL = 327; enum CB_GETDROPPEDCONTROLRECT = 338; enum CB_GETDROPPEDSTATE = 343; enum CB_GETDROPPEDWIDTH = 351; enum CB_GETEDITSEL = 320; enum CB_GETEXTENDEDUI = 342; enum CB_GETHORIZONTALEXTENT = 349; enum CB_GETITEMDATA = 336; enum CB_GETITEMHEIGHT = 340; enum CB_GETLBTEXT = 328; enum CB_GETLBTEXTLEN = 329; enum CB_GETLOCALE = 346; enum CB_GETTOPINDEX = 347; enum CB_INITSTORAGE = 353; enum CB_INSERTSTRING = 330; enum CB_LIMITTEXT = 321; enum CB_RESETCONTENT = 331; enum CB_SELECTSTRING = 333; enum CB_SETCURSEL = 334; enum CB_SETDROPPEDWIDTH = 352; enum CB_SETEDITSEL = 322; enum CB_SETEXTENDEDUI = 341; enum CB_SETHORIZONTALEXTENT = 350; enum CB_SETITEMDATA = 337; enum CB_SETITEMHEIGHT = 339; enum CB_SETLOCALE = 345; enum CB_SETTOPINDEX = 348; enum CB_SHOWDROPDOWN = 335; static if(_WIN32_WINNT >= 0x501) { enum CB_GETCOMBOBOXINFO = 356; } enum CBN_CLOSEUP = 8; enum CBN_DBLCLK = 2; enum CBN_DROPDOWN = 7; enum CBN_EDITCHANGE = 5; enum CBN_EDITUPDATE = 6; enum CBN_ERRSPACE = (-1); enum CBN_KILLFOCUS = 4; enum CBN_SELCHANGE = 1; enum CBN_SELENDCANCEL = 10; enum CBN_SELENDOK = 9; enum CBN_SETFOCUS = 3; enum EM_CANUNDO = 198; enum EM_CHARFROMPOS = 215; enum EM_EMPTYUNDOBUFFER = 205; enum EM_FMTLINES = 200; enum EM_GETFIRSTVISIBLELINE = 206; enum EM_GETHANDLE = 189; enum EM_GETLIMITTEXT = 213; enum EM_GETLINE = 196; enum EM_GETLINECOUNT = 186; enum EM_GETMARGINS = 212; enum EM_GETMODIFY = 184; enum EM_GETPASSWORDCHAR = 210; enum EM_GETRECT = 178; enum EM_GETSEL = 176; enum EM_GETTHUMB = 190; enum EM_GETWORDBREAKPROC = 209; enum EM_LIMITTEXT = 197; enum EM_LINEFROMCHAR = 201; enum EM_LINEINDEX = 187; enum EM_LINELENGTH = 193; enum EM_LINESCROLL = 182; enum EM_POSFROMCHAR = 214; enum EM_REPLACESEL = 194; enum EM_SCROLL = 181; enum EM_SCROLLCARET = 183; enum EM_SETHANDLE = 188; enum EM_SETLIMITTEXT = 197; enum EM_SETMARGINS = 211; enum EM_SETMODIFY = 185; enum EM_SETPASSWORDCHAR = 204; enum EM_SETREADONLY = 207; enum EM_SETRECT = 179; enum EM_SETRECTNP = 180; enum EM_SETSEL = 177; enum EM_SETTABSTOPS = 203; enum EM_SETWORDBREAKPROC = 208; enum EM_UNDO = 199; enum EM_SETIMESTATUS = 216; enum EM_GETIMESTATUS = 217; enum EN_CHANGE = 768; enum EN_ERRSPACE = 1280; enum EN_HSCROLL = 1537; enum EN_KILLFOCUS = 512; enum EN_MAXTEXT = 1281; enum EN_SETFOCUS = 256; enum EN_UPDATE = 1024; enum EN_VSCROLL = 1538; enum LB_ADDFILE = 406; enum LB_ADDSTRING = 384; enum LB_DELETESTRING = 386; enum LB_DIR = 397; enum LB_FINDSTRING = 399; enum LB_FINDSTRINGEXACT = 418; enum LB_GETANCHORINDEX = 413; enum LB_GETCARETINDEX = 415; enum LB_GETCOUNT = 395; enum LB_GETCURSEL = 392; enum LB_GETHORIZONTALEXTENT = 403; enum LB_GETITEMDATA = 409; enum LB_GETITEMHEIGHT = 417; enum LB_GETITEMRECT = 408; enum LB_GETLOCALE = 422; enum LB_GETSEL = 391; enum LB_GETSELCOUNT = 400; enum LB_GETSELITEMS = 401; enum LB_GETTEXT = 393; enum LB_GETTEXTLEN = 394; enum LB_GETTOPINDEX = 398; enum LB_INITSTORAGE = 424; enum LB_INSERTSTRING = 385; enum LB_ITEMFROMPOINT = 425; enum LB_RESETCONTENT = 388; enum LB_SELECTSTRING = 396; enum LB_SELITEMRANGE = 411; enum LB_SELITEMRANGEEX = 387; enum LB_SETANCHORINDEX = 412; enum LB_SETCARETINDEX = 414; enum LB_SETCOLUMNWIDTH = 405; enum LB_SETCOUNT = 423; enum LB_SETCURSEL = 390; enum LB_SETHORIZONTALEXTENT = 404; enum LB_SETITEMDATA = 410; enum LB_SETITEMHEIGHT = 416; enum LB_SETLOCALE = 421; enum LB_SETSEL = 389; enum LB_SETTABSTOPS = 402; enum LB_SETTOPINDEX = 407; static if(_WIN32_WINNT >= 0x501) { enum LB_GETLISTBOXINFO = 434; } enum LBN_DBLCLK = 2; enum LBN_ERRSPACE = -2; enum LBN_KILLFOCUS = 5; enum LBN_SELCANCEL = 3; enum LBN_SELCHANGE = 1; enum LBN_SETFOCUS = 4; enum SBM_ENABLE_ARROWS = 228; enum SBM_GETPOS = 225; enum SBM_GETRANGE = 227; enum SBM_GETSCROLLINFO = 234; enum SBM_SETPOS = 224; enum SBM_SETRANGE = 226; enum SBM_SETRANGEREDRAW = 230; enum SBM_SETSCROLLINFO = 233; static if(_WIN32_WINNT >= 0x501) { enum SBM_GETSCROLLBARINFO = 235; } enum STM_GETICON = 369; enum STM_GETIMAGE = 371; enum STM_SETICON = 368; enum STM_SETIMAGE = 370; enum STN_CLICKED = 0; enum STN_DBLCLK = 1; enum STN_DISABLE = 3; enum STN_ENABLE = 2; enum STM_MSGMAX = 372; enum DM_GETDEFID = WM_USER; enum DM_SETDEFID = WM_USER+1; enum DM_REPOSITION = WM_USER+2; enum PSM_PAGEINFO = WM_USER+100; enum PSM_SHEETINFO = WM_USER+101; enum PSI_SETACTIVE = 1; enum PSI_KILLACTIVE = 2; enum PSI_APPLY = 3; enum PSI_RESET = 4; enum PSI_HASHELP = 5; enum PSI_HELP = 6; enum PSI_CHANGED = 1; enum PSI_GUISTART = 2; enum PSI_REBOOT = 3; enum PSI_GETSIBLINGS = 4; enum DCX_WINDOW = 1; enum DCX_CACHE = 2; enum DCX_PARENTCLIP = 32; enum DCX_CLIPSIBLINGS = 16; enum DCX_CLIPCHILDREN = 8; enum DCX_NORESETATTRS = 4; enum DCX_INTERSECTUPDATE = 0x200; enum DCX_LOCKWINDOWUPDATE = 0x400; enum DCX_EXCLUDERGN = 64; enum DCX_INTERSECTRGN = 128; enum DCX_EXCLUDEUPDATE = 256; enum DCX_VALIDATE = 0x200000; enum GMDI_GOINTOPOPUPS = 2; enum GMDI_USEDISABLED = 1; enum FKF_AVAILABLE = 2; enum FKF_CLICKON = 64; enum FKF_FILTERKEYSON = 1; enum FKF_HOTKEYACTIVE = 4; enum FKF_HOTKEYSOUND = 16; enum FKF_CONFIRMHOTKEY = 8; enum FKF_INDICATOR = 32; enum HCF_HIGHCONTRASTON = 1; enum HCF_AVAILABLE = 2; enum HCF_HOTKEYACTIVE = 4; enum HCF_CONFIRMHOTKEY = 8; enum HCF_HOTKEYSOUND = 16; enum HCF_INDICATOR = 32; enum HCF_HOTKEYAVAILABLE = 64; enum MKF_AVAILABLE = 2; enum MKF_CONFIRMHOTKEY = 8; enum MKF_HOTKEYACTIVE = 4; enum MKF_HOTKEYSOUND = 16; enum MKF_INDICATOR = 32; enum MKF_MOUSEKEYSON = 1; enum MKF_MODIFIERS = 64; enum MKF_REPLACENUMBERS = 128; enum SERKF_ACTIVE = 8; // May be obsolete. Not in recent MS docs. enum SERKF_AVAILABLE = 2; enum SERKF_INDICATOR = 4; enum SERKF_SERIALKEYSON = 1; enum SSF_AVAILABLE = 2; enum SSF_SOUNDSENTRYON = 1; enum SSTF_BORDER = 2; enum SSTF_CHARS = 1; enum SSTF_DISPLAY = 3; enum SSTF_NONE = 0; enum SSGF_DISPLAY = 3; enum SSGF_NONE = 0; enum SSWF_CUSTOM = 4; enum SSWF_DISPLAY = 3; enum SSWF_NONE = 0; enum SSWF_TITLE = 1; enum SSWF_WINDOW = 2; enum SKF_AUDIBLEFEEDBACK = 64; enum SKF_AVAILABLE = 2; enum SKF_CONFIRMHOTKEY = 8; enum SKF_HOTKEYACTIVE = 4; enum SKF_HOTKEYSOUND = 16; enum SKF_INDICATOR = 32; enum SKF_STICKYKEYSON = 1; enum SKF_TRISTATE = 128; enum SKF_TWOKEYSOFF = 256; enum TKF_AVAILABLE = 2; enum TKF_CONFIRMHOTKEY = 8; enum TKF_HOTKEYACTIVE = 4; enum TKF_HOTKEYSOUND = 16; enum TKF_TOGGLEKEYSON = 1; enum MDITILE_SKIPDISABLED = 2; enum MDITILE_HORIZONTAL = 1; enum MDITILE_VERTICAL = 0; enum { VK_LBUTTON = 0x01, VK_RBUTTON = 0x02, VK_CANCEL = 0x03, VK_MBUTTON = 0x04, VK_XBUTTON1 = 0x05, VK_XBUTTON2 = 0x06, VK_BACK = 0x08, VK_TAB = 0x09, VK_CLEAR = 0x0C, VK_RETURN = 0x0D, VK_SHIFT = 0x10, VK_CONTROL = 0x11, VK_MENU = 0x12, VK_PAUSE = 0x13, VK_CAPITAL = 0x14, VK_KANA = 0x15, VK_HANGEUL = 0x15, VK_HANGUL = 0x15, VK_JUNJA = 0x17, VK_FINAL = 0x18, VK_HANJA = 0x19, VK_KANJI = 0x19, VK_ESCAPE = 0x1B, VK_CONVERT = 0x1C, VK_NONCONVERT = 0x1D, VK_ACCEPT = 0x1E, VK_MODECHANGE = 0x1F, VK_SPACE = 0x20, VK_PRIOR = 0x21, VK_NEXT = 0x22, VK_END = 0x23, VK_HOME = 0x24, VK_LEFT = 0x25, VK_UP = 0x26, VK_RIGHT = 0x27, VK_DOWN = 0x28, VK_SELECT = 0x29, VK_PRINT = 0x2A, VK_EXECUTE = 0x2B, VK_SNAPSHOT = 0x2C, VK_INSERT = 0x2D, VK_DELETE = 0x2E, VK_HELP = 0x2F, VK_LWIN = 0x5B, VK_RWIN = 0x5C, VK_APPS = 0x5D, VK_SLEEP = 0x5F, VK_NUMPAD0 = 0x60, VK_NUMPAD1 = 0x61, VK_NUMPAD2 = 0x62, VK_NUMPAD3 = 0x63, VK_NUMPAD4 = 0x64, VK_NUMPAD5 = 0x65, VK_NUMPAD6 = 0x66, VK_NUMPAD7 = 0x67, VK_NUMPAD8 = 0x68, VK_NUMPAD9 = 0x69, VK_MULTIPLY = 0x6A, VK_ADD = 0x6B, VK_SEPARATOR = 0x6C, VK_SUBTRACT = 0x6D, VK_DECIMAL = 0x6E, VK_DIVIDE = 0x6F, VK_F1 = 0x70, VK_F2 = 0x71, VK_F3 = 0x72, VK_F4 = 0x73, VK_F5 = 0x74, VK_F6 = 0x75, VK_F7 = 0x76, VK_F8 = 0x77, VK_F9 = 0x78, VK_F10 = 0x79, VK_F11 = 0x7A, VK_F12 = 0x7B, VK_F13 = 0x7C, VK_F14 = 0x7D, VK_F15 = 0x7E, VK_F16 = 0x7F, VK_F17 = 0x80, VK_F18 = 0x81, VK_F19 = 0x82, VK_F20 = 0x83, VK_F21 = 0x84, VK_F22 = 0x85, VK_F23 = 0x86, VK_F24 = 0x87, VK_NUMLOCK = 0x90, VK_SCROLL = 0x91, VK_LSHIFT = 0xA0, VK_RSHIFT = 0xA1, VK_LCONTROL = 0xA2, VK_RCONTROL = 0xA3, VK_LMENU = 0xA4, VK_RMENU = 0xA5, VK_BROWSER_BACK = 0xA6, VK_BROWSER_FORWARD = 0xA7, VK_BROWSER_REFRESH = 0xA8, VK_BROWSER_STOP = 0xA9, VK_BROWSER_SEARCH = 0xAA, VK_BROWSER_FAVORITES = 0xAB, VK_BROWSER_HOME = 0xAC, VK_VOLUME_MUTE = 0xAD, VK_VOLUME_DOWN = 0xAE, VK_VOLUME_UP = 0xAF, VK_MEDIA_NEXT_TRACK = 0xB0, VK_MEDIA_PREV_TRACK = 0xB1, VK_MEDIA_STOP = 0xB2, VK_MEDIA_PLAY_PAUSE = 0xB3, VK_LAUNCH_MAIL = 0xB4, VK_LAUNCH_MEDIA_SELECT = 0xB5, VK_LAUNCH_APP1 = 0xB6, VK_LAUNCH_APP2 = 0xB7, VK_OEM_1 = 0xBA, VK_OEM_PLUS = 0xBB, VK_OEM_COMMA = 0xBC, VK_OEM_MINUS = 0xBD, VK_OEM_PERIOD = 0xBE, VK_OEM_2 = 0xBF, VK_OEM_3 = 0xC0, VK_OEM_4 = 0xDB, VK_OEM_5 = 0xDC, VK_OEM_6 = 0xDD, VK_OEM_7 = 0xDE, VK_OEM_8 = 0xDF, VK_OEM_102 = 0xE2, VK_PROCESSKEY = 0xE5, VK_PACKET = 0xE7, VK_ATTN = 0xF6, VK_CRSEL = 0xF7, VK_EXSEL = 0xF8, VK_EREOF = 0xF9, VK_PLAY = 0xFA, VK_ZOOM = 0xFB, VK_NONAME = 0xFC, VK_PA1 = 0xFD, VK_OEM_CLEAR = 0xFE, } enum TME_HOVER = 1; enum TME_LEAVE = 2; enum TME_QUERY = 0x40000000; enum TME_CANCEL = 0x80000000; enum HOVER_DEFAULT = 0xFFFFFFFF; enum MK_LBUTTON = 1; enum MK_RBUTTON = 2; enum MK_SHIFT = 4; enum MK_CONTROL = 8; enum MK_MBUTTON = 16; enum MK_XBUTTON1 = 32; enum MK_XBUTTON2 = 64; enum { TPM_RECURSE = 0x0001, TPM_LEFTBUTTON = 0, TPM_RIGHTBUTTON = 0x0002, TPM_LEFTALIGN = 0, TPM_CENTERALIGN = 0x0004, TPM_RIGHTALIGN = 0x0008, TPM_TOPALIGN = 0, TPM_VCENTERALIGN = 0x0010, TPM_BOTTOMALIGN = 0x0020, TPM_HORIZONTAL = 0, TPM_VERTICAL = 0x0040, TPM_NONOTIFY = 0x0080, TPM_RETURNCMD = 0x0100 } enum HELP_COMMAND = 0x102; enum HELP_CONTENTS = 3; enum HELP_CONTEXT = 1; enum HELP_CONTEXTPOPUP = 8; enum HELP_FORCEFILE = 9; enum HELP_HELPONHELP = 4; enum HELP_INDEX = 3; enum HELP_KEY = 0x101; enum HELP_MULTIKEY = 0x201; enum HELP_PARTIALKEY = 0x105; enum HELP_QUIT = 2; enum HELP_SETCONTENTS = 5; enum HELP_SETINDEX = 5; enum HELP_SETWINPOS = 0x203; enum HELP_CONTEXTMENU = 0xa; enum HELP_FINDER = 0xb; enum HELP_WM_HELP = 0xc; enum HELP_TCARD = 0x8000; enum HELP_TCARD_DATA = 16; enum HELP_TCARD_OTHER_CALLER = 0x11; enum IDH_NO_HELP = 28440; enum IDH_MISSING_CONTEXT = 28441; enum IDH_GENERIC_HELP_BUTTON = 28442; enum IDH_OK = 28443; enum IDH_CANCEL = 28444; enum IDH_HELP = 28445; enum LB_CTLCODE = 0; enum LB_OKAY = 0; enum LB_ERR = -1; enum LB_ERRSPACE = -2; enum CB_OKAY = 0; enum CB_ERR = -1; enum CB_ERRSPACE = -2; enum HIDE_WINDOW = 0; enum SHOW_OPENWINDOW = 1; enum SHOW_ICONWINDOW = 2; enum SHOW_FULLSCREEN = 3; enum SHOW_OPENNOACTIVATE = 4; enum KF_EXTENDED = 256; enum KF_DLGMODE = 2048; enum KF_MENUMODE = 4096; enum KF_ALTDOWN = 8192; enum KF_REPEAT = 16384; enum KF_UP = 32768; enum WSF_VISIBLE = 1; enum PWR_OK = 1; enum PWR_FAIL = -1; enum PWR_SUSPENDREQUEST = 1; enum PWR_SUSPENDRESUME = 2; enum PWR_CRITICALRESUME = 3; enum NFR_ANSI = 1; enum NFR_UNICODE = 2; enum NF_QUERY = 3; enum NF_REQUERY = 4; enum MENULOOP_WINDOW = 0; enum MENULOOP_POPUP = 1; enum WMSZ_LEFT = 1; enum WMSZ_RIGHT = 2; enum WMSZ_TOP = 3; enum WMSZ_TOPLEFT = 4; enum WMSZ_TOPRIGHT = 5; enum WMSZ_BOTTOM = 6; enum WMSZ_BOTTOMLEFT = 7; enum WMSZ_BOTTOMRIGHT = 8; enum HTERROR = -2; enum HTTRANSPARENT = -1; enum HTNOWHERE = 0; enum HTCLIENT = 1; enum HTCAPTION = 2; enum HTSYSMENU = 3; enum HTGROWBOX = 4; enum HTSIZE = 4; enum HTMENU = 5; enum HTHSCROLL = 6; enum HTVSCROLL = 7; enum HTMINBUTTON = 8; enum HTMAXBUTTON = 9; enum HTREDUCE = 8; enum HTZOOM = 9; enum HTLEFT = 10; enum HTSIZEFIRST = 10; enum HTRIGHT = 11; enum HTTOP = 12; enum HTTOPLEFT = 13; enum HTTOPRIGHT = 14; enum HTBOTTOM = 15; enum HTBOTTOMLEFT = 16; enum HTBOTTOMRIGHT = 17; enum HTSIZELAST = 17; enum HTBORDER = 18; enum HTOBJECT = 19; enum HTCLOSE = 20; enum HTHELP = 21; enum MA_ACTIVATE = 1; enum MA_ACTIVATEANDEAT = 2; enum MA_NOACTIVATE = 3; enum MA_NOACTIVATEANDEAT = 4; enum SIZE_RESTORED = 0; enum SIZE_MINIMIZED = 1; enum SIZE_MAXIMIZED = 2; enum SIZE_MAXSHOW = 3; enum SIZE_MAXHIDE = 4; enum SIZENORMAL = 0; enum SIZEICONIC = 1; enum SIZEFULLSCREEN = 2; enum SIZEZOOMSHOW = 3; enum SIZEZOOMHIDE = 4; enum WVR_ALIGNTOP = 16; enum WVR_ALIGNLEFT = 32; enum WVR_ALIGNBOTTOM = 64; enum WVR_ALIGNRIGHT = 128; enum WVR_HREDRAW = 256; enum WVR_VREDRAW = 512; enum WVR_REDRAW = (WVR_HREDRAW|WVR_VREDRAW); enum WVR_VALIDRECTS = 1024; enum PRF_CHECKVISIBLE = 1; enum PRF_NONCLIENT = 2; enum PRF_CLIENT = 4; enum PRF_ERASEBKGND = 8; enum PRF_CHILDREN = 16; enum PRF_OWNED = 32; enum IDANI_OPEN = 1; enum IDANI_CLOSE = 2; enum IDANI_CAPTION = 3; enum WPF_RESTORETOMAXIMIZED = 2; enum WPF_SETMINPOSITION = 1; enum ODT_MENU = 1; enum ODT_LISTBOX = 2; enum ODT_COMBOBOX = 3; enum ODT_BUTTON = 4; enum ODT_STATIC = 5; enum ODA_DRAWENTIRE = 1; enum ODA_SELECT = 2; enum ODA_FOCUS = 4; enum ODS_SELECTED = 1; enum ODS_GRAYED = 2; enum ODS_DISABLED = 4; enum ODS_CHECKED = 8; enum ODS_FOCUS = 16; enum ODS_DEFAULT = 32; enum ODS_COMBOBOXEDIT = 4096; enum IDHOT_SNAPWINDOW = -1; enum IDHOT_SNAPDESKTOP = -2; enum DBWF_LPARAMPOINTER = 0x8000; enum DLGWINDOWEXTRA = 30; enum MNC_IGNORE = 0; enum MNC_CLOSE = 1; enum MNC_EXECUTE = 2; enum MNC_SELECT = 3; enum DOF_EXECUTABLE = 0x8001; enum DOF_DOCUMENT = 0x8002; enum DOF_DIRECTORY = 0x8003; enum DOF_MULTIPLE = 0x8004; enum DOF_PROGMAN = 1; enum DOF_SHELLDATA = 2; enum DO_DROPFILE = 0x454C4946; enum DO_PRINTFILE = 0x544E5250; enum SC_SIZE = 0xF000; enum SC_MOVE = 0xF010; enum SC_MINIMIZE = 0xF020; enum SC_ICON = 0xf020; enum SC_MAXIMIZE = 0xF030; enum SC_ZOOM = 0xF030; enum SC_NEXTWINDOW = 0xF040; enum SC_PREVWINDOW = 0xF050; enum SC_CLOSE = 0xF060; enum SC_VSCROLL = 0xF070; enum SC_HSCROLL = 0xF080; enum SC_MOUSEMENU = 0xF090; enum SC_KEYMENU = 0xF100; enum SC_ARRANGE = 0xF110; enum SC_RESTORE = 0xF120; enum SC_TASKLIST = 0xF130; enum SC_SCREENSAVE = 0xF140; enum SC_HOTKEY = 0xF150; enum SC_DEFAULT = 0xF160; enum SC_MONITORPOWER = 0xF170; enum SC_CONTEXTHELP = 0xF180; enum SC_SEPARATOR = 0xF00F; enum EC_LEFTMARGIN = 1; enum EC_RIGHTMARGIN = 2; enum EC_USEFONTINFO = 0xffff; enum DC_HASDEFID = 0x534B; enum DLGC_WANTARROWS = 1; enum DLGC_WANTTAB = 2; enum DLGC_WANTALLKEYS = 4; enum DLGC_WANTMESSAGE = 4; enum DLGC_HASSETSEL = 8; enum DLGC_DEFPUSHBUTTON = 16; enum DLGC_UNDEFPUSHBUTTON = 32; enum DLGC_RADIOBUTTON = 64; enum DLGC_WANTCHARS = 128; enum DLGC_STATIC = 256; enum DLGC_BUTTON = 0x2000; enum WA_INACTIVE = 0; enum WA_ACTIVE = 1; enum WA_CLICKACTIVE = 2; enum ICON_SMALL = 0; enum ICON_BIG = 1; static if (_WIN32_WINNT >= 0x501) { enum ICON_SMALL2 = 2; } enum HBITMAP HBMMENU_CALLBACK = cast(HBITMAP)-1, HBMMENU_SYSTEM = cast(HBITMAP)1, HBMMENU_MBAR_RESTORE = cast(HBITMAP)2, HBMMENU_MBAR_MINIMIZE = cast(HBITMAP)3, HBMMENU_MBAR_CLOSE = cast(HBITMAP)5, HBMMENU_MBAR_CLOSE_D = cast(HBITMAP)6, HBMMENU_MBAR_MINIMIZE_D = cast(HBITMAP)7, HBMMENU_POPUP_CLOSE = cast(HBITMAP)8, HBMMENU_POPUP_RESTORE = cast(HBITMAP)9, HBMMENU_POPUP_MAXIMIZE = cast(HBITMAP)10, HBMMENU_POPUP_MINIMIZE = cast(HBITMAP)11; enum MOD_ALT = 1; enum MOD_CONTROL = 2; enum MOD_SHIFT = 4; enum MOD_WIN = 8; enum MOD_IGNORE_ALL_MODIFIER = 1024; enum MOD_ON_KEYUP = 2048; enum MOD_RIGHT = 16384; enum MOD_LEFT = 32768; enum LLKHF_EXTENDED = (KF_EXTENDED >> 8); enum LLKHF_INJECTED = 0x00000010; enum LLKHF_ALTDOWN = (KF_ALTDOWN >> 8); enum LLKHF_UP = (KF_UP >> 8); enum CURSOR_SHOWING = 0x00000001; enum WS_ACTIVECAPTION = 0x00000001; enum ENDSESSION_LOGOFF = 0x80000000; enum GA_PARENT = 1; enum GA_ROOT = 2; enum GA_ROOTOWNER = 3; enum { MAPVK_VK_TO_VSC, MAPVK_VSC_TO_VK, MAPVK_VK_TO_CHAR, MAPVK_VSC_TO_VK_EX, MAPVK_VK_TO_VSC_EX // = 4 } enum { INPUT_MOUSE, INPUT_KEYBOARD, INPUT_HARDWARE // = 2 } // Callbacks // --------- extern (Windows) nothrow { alias INT_PTR function(HWND, UINT, WPARAM, LPARAM) DLGPROC; alias void function(HWND, UINT, UINT_PTR, DWORD) TIMERPROC; alias BOOL function(HDC, LPARAM, int) GRAYSTRINGPROC; alias LRESULT function(int, WPARAM, LPARAM) HOOKPROC; alias BOOL function(HWND, LPCSTR, HANDLE) PROPENUMPROCA; alias BOOL function(HWND, LPCWSTR, HANDLE) PROPENUMPROCW; alias BOOL function(HWND, LPSTR, HANDLE, ULONG_PTR) PROPENUMPROCEXA; alias BOOL function(HWND, LPWSTR, HANDLE, ULONG_PTR) PROPENUMPROCEXW; alias int function(LPSTR, int, int, int) EDITWORDBREAKPROCA; alias int function(LPWSTR, int, int, int) EDITWORDBREAKPROCW; alias LRESULT function(HWND, UINT, WPARAM, LPARAM) WNDPROC; alias BOOL function(HDC, LPARAM, WPARAM, int, int) DRAWSTATEPROC; alias BOOL function(HWND, LPARAM) WNDENUMPROC; alias BOOL function(HWND, LPARAM) ENUMWINDOWSPROC; alias void function(LPHELPINFO) MSGBOXCALLBACK; alias BOOL function(HMONITOR, HDC, LPRECT, LPARAM) MONITORENUMPROC; alias BOOL function(LPSTR, LPARAM) NAMEENUMPROCA; alias BOOL function(LPWSTR, LPARAM) NAMEENUMPROCW; alias void function(HWND, UINT, ULONG_PTR, LRESULT) SENDASYNCPROC; alias NAMEENUMPROCA DESKTOPENUMPROCA; alias NAMEENUMPROCW DESKTOPENUMPROCW; alias NAMEENUMPROCA WINSTAENUMPROCA; alias NAMEENUMPROCW WINSTAENUMPROCW; } mixin DECLARE_HANDLE!("HDWP"); mixin DECLARE_HANDLE!("HDEVNOTIFY"); struct MENUGETOBJECTINFO { DWORD dwFlags; UINT uPos; HMENU hmenu; PVOID riid; PVOID pvObj; } alias MENUGETOBJECTINFO* PMENUGETOBJECTINFO; struct ACCEL { BYTE fVirt; WORD key; WORD cmd; } alias ACCEL* LPACCEL; struct ACCESSTIMEOUT { UINT cbSize = ACCESSTIMEOUT.sizeof; DWORD dwFlags; DWORD iTimeOutMSec; } alias ACCESSTIMEOUT* LPACCESSTIMEOUT; struct ANIMATIONINFO { UINT cbSize = ANIMATIONINFO.sizeof; int iMinAnimate; } alias ANIMATIONINFO* LPANIMATIONINFO; struct CREATESTRUCTA { LPVOID lpCreateParams; HINSTANCE hInstance; HMENU hMenu; HWND hwndParent; int cy; int cx; int y; int x; LONG style; LPCSTR lpszName; LPCSTR lpszClass; DWORD dwExStyle; } alias CREATESTRUCTA* LPCREATESTRUCTA; struct CREATESTRUCTW { LPVOID lpCreateParams; HINSTANCE hInstance; HMENU hMenu; HWND hwndParent; int cy; int cx; int y; int x; LONG style; LPCWSTR lpszName; LPCWSTR lpszClass; DWORD dwExStyle; } alias CREATESTRUCTW* LPCREATESTRUCTW; struct CBT_CREATEWNDA { LPCREATESTRUCTA lpcs; HWND hwndInsertAfter; } alias CBT_CREATEWNDA* LPCBT_CREATEWNDA; struct CBT_CREATEWNDW { LPCREATESTRUCTW lpcs; HWND hwndInsertAfter; } alias CBT_CREATEWNDW* LPCBT_CREATEWNDW; struct CBTACTIVATESTRUCT { BOOL fMouse; HWND hWndActive; } alias CBTACTIVATESTRUCT* LPCBTACTIVATESTRUCT; static if (_WIN32_WINNT >= 0x501) { struct WTSSESSION_NOTIFICATION { DWORD cbSize; DWORD dwSessionId; } alias WTSSESSION_NOTIFICATION* PWTSSESSION_NOTIFICATION; } struct CLIENTCREATESTRUCT { HANDLE hWindowMenu; UINT idFirstChild; } alias CLIENTCREATESTRUCT* LPCLIENTCREATESTRUCT; struct COMPAREITEMSTRUCT { UINT CtlType; UINT CtlID; HWND hwndItem; UINT itemID1; DWORD itemData1; UINT itemID2; DWORD itemData2; DWORD dwLocaleId; } alias COMPAREITEMSTRUCT* LPCOMPAREITEMSTRUCT; struct COPYDATASTRUCT { DWORD dwData; DWORD cbData; PVOID lpData; } alias COPYDATASTRUCT* PCOPYDATASTRUCT; struct CURSORSHAPE { int xHotSpot; int yHotSpot; int cx; int cy; int cbWidth; BYTE Planes; BYTE BitsPixel; } alias CURSORSHAPE* LPCURSORSHAPE; struct CWPRETSTRUCT { LRESULT lResult; LPARAM lParam; WPARAM wParam; DWORD message; HWND hwnd; } struct CWPSTRUCT { LPARAM lParam; WPARAM wParam; UINT message; HWND hwnd; } alias CWPSTRUCT* PCWPSTRUCT; struct DEBUGHOOKINFO { DWORD idThread; DWORD idThreadInstaller; LPARAM lParam; WPARAM wParam; int code; } alias DEBUGHOOKINFO* PDEBUGHOOKINFO, LPDEBUGHOOKINFO; struct DELETEITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; HWND hwndItem; UINT itemData; } alias DELETEITEMSTRUCT* PDELETEITEMSTRUCT, LPDELETEITEMSTRUCT; align(2): struct DLGITEMTEMPLATE { DWORD style; DWORD dwExtendedStyle; short x; short y; short cx; short cy; WORD id; } alias DLGITEMTEMPLATE* LPDLGITEMTEMPLATE; struct DLGTEMPLATE { DWORD style; DWORD dwExtendedStyle; WORD cdit; short x; short y; short cx; short cy; } alias DLGTEMPLATE* LPDLGTEMPLATE, LPDLGTEMPLATEA, LPDLGTEMPLATEW; alias const(DLGTEMPLATE)* LPCDLGTEMPLATE, LPCDLGTEMPLATEA, LPCDLGTEMPLATEW; align: struct DRAWITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; DWORD itemData; } alias DRAWITEMSTRUCT* LPDRAWITEMSTRUCT, PDRAWITEMSTRUCT; struct DRAWTEXTPARAMS { UINT cbSize = DRAWTEXTPARAMS.sizeof; int iTabLength; int iLeftMargin; int iRightMargin; UINT uiLengthDrawn; } alias DRAWTEXTPARAMS* LPDRAWTEXTPARAMS; struct PAINTSTRUCT { HDC hdc; BOOL fErase; RECT rcPaint; BOOL fRestore; BOOL fIncUpdate; BYTE[32] rgbReserved; } alias PAINTSTRUCT* PPAINTSTRUCT, NPPAINTSTRUCT, LPPAINTSTRUCT; struct MSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } alias MSG* NPMSG, LPMSG, PMSG; struct ICONINFO { BOOL fIcon; DWORD xHotspot; DWORD yHotspot; HBITMAP hbmMask; HBITMAP hbmColor; } alias ICONINFO* PICONINFO; struct NMHDR { HWND hwndFrom; UINT_PTR idFrom; UINT code; } alias NMHDR* LPNMHDR; struct WNDCLASSA { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCSTR lpszMenuName; LPCSTR lpszClassName; } alias WNDCLASSA* NPWNDCLASSA, LPWNDCLASSA, PWNDCLASSA; struct WNDCLASSW { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCWSTR lpszMenuName; LPCWSTR lpszClassName; } alias WNDCLASSW* NPWNDCLASSW, LPWNDCLASSW, PWNDCLASSW; struct WNDCLASSEXA { UINT cbSize = WNDCLASSEXA.sizeof; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCSTR lpszMenuName; LPCSTR lpszClassName; HICON hIconSm; } alias WNDCLASSEXA* NPWNDCLASSEXA, LPWNDCLASSEXA, PWNDCLASSEXA; struct WNDCLASSEXW { UINT cbSize = WNDCLASSEXW.sizeof; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCWSTR lpszMenuName; LPCWSTR lpszClassName; HICON hIconSm; } alias WNDCLASSEXW* LPWNDCLASSEXW, PWNDCLASSEXW; struct MENUITEMINFOA { UINT cbSize = MENUITEMINFOA.sizeof; UINT fMask; UINT fType; UINT fState; UINT wID; HMENU hSubMenu; HBITMAP hbmpChecked; HBITMAP hbmpUnchecked; ULONG_PTR dwItemData; LPSTR dwTypeData; UINT cch; HBITMAP hbmpItem; } alias MENUITEMINFOA* LPMENUITEMINFOA; alias const(MENUITEMINFOA)* LPCMENUITEMINFOA; struct MENUITEMINFOW { UINT cbSize = MENUITEMINFOW.sizeof; UINT fMask; UINT fType; UINT fState; UINT wID; HMENU hSubMenu; HBITMAP hbmpChecked; HBITMAP hbmpUnchecked; ULONG_PTR dwItemData; LPWSTR dwTypeData; UINT cch; HBITMAP hbmpItem; } alias MENUITEMINFOW* LPMENUITEMINFOW; alias const(MENUITEMINFOW)* LPCMENUITEMINFOW; struct SCROLLINFO { UINT cbSize = this.sizeof; UINT fMask; int nMin; int nMax; UINT nPage; int nPos; int nTrackPos; } alias SCROLLINFO* LPSCROLLINFO; alias const(SCROLLINFO)* LPCSCROLLINFO; struct WINDOWPLACEMENT { UINT length; UINT flags; UINT showCmd; POINT ptMinPosition; POINT ptMaxPosition; RECT rcNormalPosition; } alias WINDOWPLACEMENT* LPWINDOWPLACEMENT, PWINDOWPLACEMENT; struct MENUITEMTEMPLATEHEADER { WORD versionNumber; WORD offset; } struct MENUITEMTEMPLATE { WORD mtOption; WORD mtID; WCHAR[1] mtString; } alias void MENUTEMPLATE, MENUTEMPLATEA, MENUTEMPLATEW; alias MENUTEMPLATE* LPMENUTEMPLATEA, LPMENUTEMPLATEW, LPMENUTEMPLATE; struct HELPINFO { UINT cbSize = this.sizeof; int iContextType; int iCtrlId; HANDLE hItemHandle; DWORD dwContextId; POINT MousePos; } alias HELPINFO* LPHELPINFO; struct MSGBOXPARAMSA { UINT cbSize = this.sizeof; HWND hwndOwner; HINSTANCE hInstance; LPCSTR lpszText; LPCSTR lpszCaption; DWORD dwStyle; LPCSTR lpszIcon; DWORD dwContextHelpId; MSGBOXCALLBACK lpfnMsgBoxCallback; DWORD dwLanguageId; } alias MSGBOXPARAMSA* PMSGBOXPARAMSA, LPMSGBOXPARAMSA; struct MSGBOXPARAMSW { UINT cbSize = this.sizeof; HWND hwndOwner; HINSTANCE hInstance; LPCWSTR lpszText; LPCWSTR lpszCaption; DWORD dwStyle; LPCWSTR lpszIcon; DWORD dwContextHelpId; MSGBOXCALLBACK lpfnMsgBoxCallback; DWORD dwLanguageId; } alias MSGBOXPARAMSW* PMSGBOXPARAMSW, LPMSGBOXPARAMSW; struct USEROBJECTFLAGS { BOOL fInherit; BOOL fReserved; DWORD dwFlags; } struct FILTERKEYS { UINT cbSize = this.sizeof; DWORD dwFlags; DWORD iWaitMSec; DWORD iDelayMSec; DWORD iRepeatMSec; DWORD iBounceMSec; } struct HIGHCONTRASTA { UINT cbSize = this.sizeof; DWORD dwFlags; LPSTR lpszDefaultScheme; } alias HIGHCONTRASTA* LPHIGHCONTRASTA; struct HIGHCONTRASTW { UINT cbSize = this.sizeof; DWORD dwFlags; LPWSTR lpszDefaultScheme; } alias HIGHCONTRASTW* LPHIGHCONTRASTW; struct ICONMETRICSA { UINT cbSize = this.sizeof; int iHorzSpacing; int iVertSpacing; int iTitleWrap; LOGFONTA lfFont; } alias ICONMETRICSA* LPICONMETRICSA; struct ICONMETRICSW { UINT cbSize = this.sizeof; int iHorzSpacing; int iVertSpacing; int iTitleWrap; LOGFONTW lfFont; } alias ICONMETRICSW* LPICONMETRICSW; struct MINIMIZEDMETRICS { UINT cbSize = this.sizeof; int iWidth; int iHorzGap; int iVertGap; int iArrange; } alias MINIMIZEDMETRICS* LPMINIMIZEDMETRICS; struct MOUSEKEYS { UINT cbSize = this.sizeof; DWORD dwFlags; DWORD iMaxSpeed; DWORD iTimeToMaxSpeed; DWORD iCtrlSpeed; DWORD dwReserved1; DWORD dwReserved2; } alias MOUSEKEYS* LPMOUSEKEYS; struct NONCLIENTMETRICSA { UINT cbSize = this.sizeof; int iBorderWidth; int iScrollWidth; int iScrollHeight; int iCaptionWidth; int iCaptionHeight; LOGFONTA lfCaptionFont; int iSmCaptionWidth; int iSmCaptionHeight; LOGFONTA lfSmCaptionFont; int iMenuWidth; int iMenuHeight; LOGFONTA lfMenuFont; LOGFONTA lfStatusFont; LOGFONTA lfMessageFont; } alias NONCLIENTMETRICSA* LPNONCLIENTMETRICSA; struct NONCLIENTMETRICSW { UINT cbSize = this.sizeof; int iBorderWidth; int iScrollWidth; int iScrollHeight; int iCaptionWidth; int iCaptionHeight; LOGFONTW lfCaptionFont; int iSmCaptionWidth; int iSmCaptionHeight; LOGFONTW lfSmCaptionFont; int iMenuWidth; int iMenuHeight; LOGFONTW lfMenuFont; LOGFONTW lfStatusFont; LOGFONTW lfMessageFont; } alias NONCLIENTMETRICSW* LPNONCLIENTMETRICSW; struct SERIALKEYSA { UINT cbSize = this.sizeof; DWORD dwFlags; LPSTR lpszActivePort; LPSTR lpszPort; UINT iBaudRate; UINT iPortState; UINT iActive; } alias SERIALKEYSA* LPSERIALKEYSA; struct SERIALKEYSW { UINT cbSize = this.sizeof; DWORD dwFlags; LPWSTR lpszActivePort; LPWSTR lpszPort; UINT iBaudRate; UINT iPortState; UINT iActive; } alias SERIALKEYSW* LPSERIALKEYSW; struct SOUNDSENTRYA { UINT cbSize = this.sizeof; DWORD dwFlags; DWORD iFSTextEffect; DWORD iFSTextEffectMSec; DWORD iFSTextEffectColorBits; DWORD iFSGrafEffect; DWORD iFSGrafEffectMSec; DWORD iFSGrafEffectColor; DWORD iWindowsEffect; DWORD iWindowsEffectMSec; LPSTR lpszWindowsEffectDLL; DWORD iWindowsEffectOrdinal; } alias SOUNDSENTRYA* LPSOUNDSENTRYA; struct SOUNDSENTRYW { UINT cbSize = this.sizeof; DWORD dwFlags; DWORD iFSTextEffect; DWORD iFSTextEffectMSec; DWORD iFSTextEffectColorBits; DWORD iFSGrafEffect; DWORD iFSGrafEffectMSec; DWORD iFSGrafEffectColor; DWORD iWindowsEffect; DWORD iWindowsEffectMSec; LPWSTR lpszWindowsEffectDLL; DWORD iWindowsEffectOrdinal; } alias SOUNDSENTRYW* LPSOUNDSENTRYW; struct STICKYKEYS { DWORD cbSize = this.sizeof; DWORD dwFlags; } alias STICKYKEYS* LPSTICKYKEYS; struct TOGGLEKEYS { DWORD cbSize = this.sizeof; DWORD dwFlags; } struct MOUSEHOOKSTRUCT { POINT pt; HWND hwnd; UINT wHitTestCode; DWORD dwExtraInfo; } alias MOUSEHOOKSTRUCT* LPMOUSEHOOKSTRUCT, PMOUSEHOOKSTRUCT; struct TRACKMOUSEEVENT { DWORD cbSize = this.sizeof; DWORD dwFlags; HWND hwndTrack; DWORD dwHoverTime; } alias TRACKMOUSEEVENT* LPTRACKMOUSEEVENT; struct TPMPARAMS { UINT cbSize = this.sizeof; RECT rcExclude; } alias TPMPARAMS* LPTPMPARAMS; struct EVENTMSG { UINT message; UINT paramL; UINT paramH; DWORD time; HWND hwnd; } alias EVENTMSG* PEVENTMSGMSG, LPEVENTMSGMSG, PEVENTMSG, LPEVENTMSG; struct WINDOWPOS { HWND hwnd; HWND hwndInsertAfter; int x; int y; int cx; int cy; UINT flags; } alias WINDOWPOS* PWINDOWPOS, LPWINDOWPOS; struct NCCALCSIZE_PARAMS { RECT[3] rgrc; PWINDOWPOS lppos; } alias NCCALCSIZE_PARAMS* LPNCCALCSIZE_PARAMS; struct MDICREATESTRUCTA { LPCSTR szClass; LPCSTR szTitle; HANDLE hOwner; int x; int y; int cx; int cy; DWORD style; LPARAM lParam; } alias MDICREATESTRUCTA* LPMDICREATESTRUCTA; struct MDICREATESTRUCTW { LPCWSTR szClass; LPCWSTR szTitle; HANDLE hOwner; int x; int y; int cx; int cy; DWORD style; LPARAM lParam; } alias MDICREATESTRUCTW* LPMDICREATESTRUCTW; struct MINMAXINFO { POINT ptReserved; POINT ptMaxSize; POINT ptMaxPosition; POINT ptMinTrackSize; POINT ptMaxTrackSize; } alias MINMAXINFO* PMINMAXINFO, LPMINMAXINFO; struct MDINEXTMENU { HMENU hmenuIn; HMENU hmenuNext; HWND hwndNext; } alias MDINEXTMENU* PMDINEXTMENU, LPMDINEXTMENU; struct MEASUREITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemWidth; UINT itemHeight; DWORD itemData; } alias MEASUREITEMSTRUCT* PMEASUREITEMSTRUCT, LPMEASUREITEMSTRUCT; struct DROPSTRUCT { HWND hwndSource; HWND hwndSink; DWORD wFmt; DWORD dwData; POINT ptDrop; DWORD dwControlData; } alias DROPSTRUCT* PDROPSTRUCT, LPDROPSTRUCT; alias DWORD HELPPOLY; struct MULTIKEYHELPA { DWORD mkSize; CHAR mkKeylist; CHAR[1] szKeyphrase; } alias MULTIKEYHELPA* PMULTIKEYHELPA, LPMULTIKEYHELPA; struct MULTIKEYHELPW { DWORD mkSize; WCHAR mkKeylist; WCHAR[1] szKeyphrase; } alias MULTIKEYHELPW* PMULTIKEYHELPW, LPMULTIKEYHELPW; struct HELPWININFOA { int wStructSize; int x; int y; int dx; int dy; int wMax; CHAR[2] rgchMember; } alias HELPWININFOA* PHELPWININFOA, LPHELPWININFOA; struct HELPWININFOW { int wStructSize; int x; int y; int dx; int dy; int wMax; WCHAR[2] rgchMember; } alias HELPWININFOW* PHELPWININFOW, LPHELPWININFOW; struct STYLESTRUCT { DWORD styleOld; DWORD styleNew; } alias STYLESTRUCT* LPSTYLESTRUCT; struct ALTTABINFO { DWORD cbSize = this.sizeof; int cItems; int cColumns; int cRows; int iColFocus; int iRowFocus; int cxItem; int cyItem; POINT ptStart; } alias ALTTABINFO* PALTTABINFO, LPALTTABINFO; struct COMBOBOXINFO { DWORD cbSize = this.sizeof; RECT rcItem; RECT rcButton; DWORD stateButton; HWND hwndCombo; HWND hwndItem; HWND hwndList; } alias COMBOBOXINFO* PCOMBOBOXINFO, LPCOMBOBOXINFO; struct CURSORINFO { DWORD cbSize = this.sizeof; DWORD flags; HCURSOR hCursor; POINT ptScreenPos; } alias CURSORINFO* PCURSORINFO, LPCURSORINFO; struct MENUBARINFO { DWORD cbSize = this.sizeof; RECT rcBar; HMENU hMenu; HWND hwndMenu; byte bf_; // Simulated bitfield // BOOL fBarFocused:1; // BOOL fFocused:1; bool fBarFocused() { return (bf_ & 1) == 1; } bool fFocused() { return (bf_ & 2) == 2; } bool fBarFocused(bool b) { bf_ = cast(byte) ((bf_ & 0xFE) | b); return b; } bool fFocused(bool b) { bf_ = cast(byte) (b ? (bf_ | 2) : bf_ & 0xFD); return b; } } alias MENUBARINFO* PMENUBARINFO; struct MENUINFO { DWORD cbSize = this.sizeof; DWORD fMask; DWORD dwStyle; UINT cyMax; HBRUSH hbrBack; DWORD dwContextHelpID; ULONG_PTR dwMenuData; } alias MENUINFO* LPMENUINFO; alias const(MENUINFO)* LPCMENUINFO; enum CCHILDREN_SCROLLBAR = 5; struct SCROLLBARINFO { DWORD cbSize = this.sizeof; RECT rcScrollBar; int dxyLineButton; int xyThumbTop; int xyThumbBottom; int reserved; DWORD[CCHILDREN_SCROLLBAR+1] rgstate; } alias SCROLLBARINFO* PSCROLLBARINFO, LPSCROLLBARINFO; enum CCHILDREN_TITLEBAR = 5; struct WINDOWINFO { DWORD cbSize = WINDOWINFO.sizeof; RECT rcWindow; RECT rcClient; DWORD dwStyle; DWORD dwExStyle; DWORD dwWindowStatus; UINT cxWindowBorders; UINT cyWindowBorders; ATOM atomWindowType; WORD wCreatorVersion; } alias WINDOWINFO* PWINDOWINFO, LPWINDOWINFO; struct LASTINPUTINFO { UINT cbSize = this.sizeof; DWORD dwTime; } alias LASTINPUTINFO* PLASTINPUTINFO; struct MONITORINFO { DWORD cbSize = this.sizeof; RECT rcMonitor; RECT rcWork; DWORD dwFlags; } alias MONITORINFO* LPMONITORINFO; enum CCHDEVICENAME = 32; struct MONITORINFOEXA { DWORD cbSize = MONITORINFOEXA.sizeof; RECT rcMonitor; RECT rcWork; DWORD dwFlags; CHAR[CCHDEVICENAME] szDevice; } alias MONITORINFOEXA* LPMONITORINFOEXA; struct MONITORINFOEXW { DWORD cbSize = MONITORINFOEXW.sizeof; RECT rcMonitor; RECT rcWork; DWORD dwFlags; WCHAR[CCHDEVICENAME] szDevice; } alias MONITORINFOEXW* LPMONITORINFOEXW; struct KBDLLHOOKSTRUCT { DWORD vkCode; DWORD scanCode; DWORD flags; DWORD time; DWORD dwExtraInfo; } alias KBDLLHOOKSTRUCT* LPKBDLLHOOKSTRUCT, PKBDLLHOOKSTRUCT; struct MSLLHOOKSTRUCT { POINT pt; DWORD mouseData; DWORD flags; DWORD time; ULONG_PTR dwExtraInfo; } alias MSLLHOOKSTRUCT* PMSLLHOOKSTRUCT; struct MOUSEINPUT { LONG dx; LONG dy; DWORD mouseData; DWORD dwFlags; DWORD time; ULONG_PTR dwExtraInfo; } alias MOUSEINPUT* PMOUSEINPUT; struct KEYBDINPUT { WORD wVk; WORD wScan; DWORD dwFlags; DWORD time; ULONG_PTR dwExtraInfo; } alias KEYBDINPUT* PKEYBDINPUT; struct HARDWAREINPUT { DWORD uMsg; WORD wParamL; WORD wParamH; } alias HARDWAREINPUT* PHARDWAREINPUT; struct INPUT { DWORD type; union { MOUSEINPUT mi; KEYBDINPUT ki; HARDWAREINPUT hi; } } alias INPUT* PINPUT, LPINPUT; static if (_WIN32_WINNT >= 0x501) { struct BSMINFO { UINT cbSize = this.sizeof; HDESK hdesk; HWND hwnd; LUID luid; } alias BSMINFO* PBSMINFO; alias TypeDef!(HANDLE) HRAWINPUT; struct RAWINPUTHEADER { DWORD dwType; DWORD dwSize; HANDLE hDevice; WPARAM wParam; } alias RAWINPUTHEADER* PRAWINPUTHEADER; struct RAWMOUSE { USHORT usFlags; union { ULONG ulButtons; struct { USHORT usButtonFlags; USHORT usButtonData; } } ULONG ulRawButtons; LONG lLastX; LONG lLastY; ULONG ulExtraInformation; } alias RAWMOUSE* PRAWMOUSE, LPRAWMOUSE; struct RAWKEYBOARD { USHORT MakeCode; USHORT Flags; USHORT Reserved; USHORT VKey; UINT Message; ULONG ExtraInformation; } alias RAWKEYBOARD* PRAWKEYBOARD, LPRAWKEYBOARD; struct RAWHID { DWORD dwSizeHid; DWORD dwCount; BYTE bRawData; } alias RAWHID* PRAWHID, LPRAWHID; struct RAWINPUT { RAWINPUTHEADER header; union _data { RAWMOUSE mouse; RAWKEYBOARD keyboard; RAWHID hid; } _data data; } alias RAWINPUT* PRAWINPUT, LPRAWINPUT; struct RAWINPUTDEVICE { USHORT usUsagePage; USHORT usUsage; DWORD dwFlags; HWND hwndTarget; } alias RAWINPUTDEVICE* PRAWINPUTDEVICE, LPRAWINPUTDEVICE; alias const(RAWINPUTDEVICE)* PCRAWINPUTDEVICE; struct RAWINPUTDEVICELIST { HANDLE hDevice; DWORD dwType; } alias RAWINPUTDEVICELIST* PRAWINPUTDEVICELIST; struct RID_DEVICE_INFO_MOUSE { DWORD dwId; DWORD dwNumberOfButtons; DWORD dwSampleRate; BOOL fHasHorizontalWheel; } struct RID_DEVICE_INFO_KEYBOARD { DWORD dwType; DWORD dwSubType; DWORD dwKeyboardMode; DWORD dwNumberOfFunctionKeys; DWORD dwNumberOfIndicators; DWORD dwNumberOfKeysTotal; } struct RID_DEVICE_INFO_HID { DWORD dwVendorId; DWORD dwProductId; DWORD dwVersionNumber; USHORT usUsagePage; USHORT usUsage; } struct RID_DEVICE_INFO { DWORD cbSize = this.sizeof; DWORD dwType; union { RID_DEVICE_INFO_MOUSE mouse; RID_DEVICE_INFO_KEYBOARD keyboard; RID_DEVICE_INFO_HID hid; } } }// (_WIN32_WINNT >= 0x501) alias CharToOemA AnsiToOem; alias OemToCharA OemToAnsi; alias CharToOemBuffA AnsiToOemBuff; alias OemToCharBuffA OemToAnsiBuff; alias CharUpperA AnsiUpper; alias CharUpperBuffA AnsiUpperBuff; alias CharLowerA AnsiLower; alias CharLowerBuffA AnsiLowerBuff; alias CharNextA AnsiNext; alias CharPrevA AnsiPrev; alias MAKELONG MAKEWPARAM; alias MAKELONG MAKELPARAM; alias MAKELONG MAKELRESULT; void POINTSTOPOINT()(out POINT p, LONG ps) { p.x = LOWORD(ps); p.y = HIWORD(ps); } POINTS POINTTOPOINTS()(in POINT p) { return MAKELONG(p.x, p.y); } extern (Windows) nothrow @nogc { HKL ActivateKeyboardLayout(HKL, UINT); BOOL AdjustWindowRect(LPRECT, DWORD, BOOL); BOOL AdjustWindowRectEx(LPRECT, DWORD, BOOL, DWORD); BOOL AnyPopup(); BOOL AppendMenuA(HMENU, UINT, UINT_PTR, LPCSTR); BOOL AppendMenuW(HMENU, UINT, UINT_PTR, LPCWSTR); UINT ArrangeIconicWindows(HWND); BOOL AttachThreadInput(DWORD, DWORD, BOOL); HDWP BeginDeferWindowPos(int); HDC BeginPaint(HWND, LPPAINTSTRUCT); BOOL BringWindowToTop(HWND); BOOL CallMsgFilterA(LPMSG, INT); BOOL CallMsgFilterW(LPMSG, INT); LRESULT CallNextHookEx(HHOOK, int, WPARAM, LPARAM); LRESULT CallWindowProcA(WNDPROC, HWND, UINT, WPARAM, LPARAM); LRESULT CallWindowProcW(WNDPROC, HWND, UINT, WPARAM, LPARAM); WORD CascadeWindows(HWND, UINT, LPCRECT, UINT, const(HWND)*); BOOL ChangeClipboardChain(HWND, HWND); LONG ChangeDisplaySettingsA(PDEVMODEA, DWORD); LONG ChangeDisplaySettingsW(PDEVMODEW, DWORD); LONG ChangeDisplaySettingsExA(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID); LONG ChangeDisplaySettingsExW(LPCWSTR, LPDEVMODEW, HWND, DWORD, LPVOID); BOOL ChangeMenuA(HMENU, UINT, LPCSTR, UINT, UINT); BOOL ChangeMenuW(HMENU, UINT, LPCWSTR, UINT, UINT); LPSTR CharLowerA(LPSTR); LPWSTR CharLowerW(LPWSTR); DWORD CharLowerBuffA(LPSTR, DWORD); DWORD CharLowerBuffW(LPWSTR, DWORD); LPSTR CharNextA(LPCSTR); LPWSTR CharNextW(LPCWSTR); LPSTR CharNextExA(WORD, LPCSTR, DWORD); LPWSTR CharNextExW(WORD, LPCWSTR, DWORD); LPSTR CharPrevA(LPCSTR, LPCSTR); LPWSTR CharPrevW(LPCWSTR, LPCWSTR); LPSTR CharPrevExA(WORD, LPCSTR, LPCSTR, DWORD); LPWSTR CharPrevExW(WORD, LPCWSTR, LPCWSTR, DWORD); BOOL CharToOemA(LPCSTR, LPSTR); BOOL CharToOemW(LPCWSTR, LPSTR); BOOL CharToOemBuffA(LPCSTR, LPSTR, DWORD); BOOL CharToOemBuffW(LPCWSTR, LPSTR, DWORD); LPSTR CharUpperA(LPSTR); LPWSTR CharUpperW(LPWSTR); DWORD CharUpperBuffA(LPSTR, DWORD); DWORD CharUpperBuffW(LPWSTR, DWORD); BOOL CheckDlgButton(HWND, int, UINT); DWORD CheckMenuItem(HMENU, UINT, UINT); BOOL CheckMenuRadioItem(HMENU, UINT, UINT, UINT, UINT); BOOL CheckRadioButton(HWND, int, int, int); HWND ChildWindowFromPoint(HWND, POINT); HWND ChildWindowFromPointEx(HWND, POINT, UINT); BOOL ClientToScreen(HWND, LPPOINT); BOOL ClipCursor(LPCRECT); BOOL CloseClipboard(); BOOL CloseDesktop(HDESK); BOOL CloseWindow(HWND); BOOL CloseWindowStation(HWINSTA); int CopyAcceleratorTableA(HACCEL, LPACCEL, int); int CopyAcceleratorTableW(HACCEL, LPACCEL, int); HICON CopyIcon(HICON); HANDLE CopyImage(HANDLE, UINT, int, int, UINT); BOOL CopyRect(LPRECT, LPCRECT); int CountClipboardFormats(); HACCEL CreateAcceleratorTableA(LPACCEL, int); HACCEL CreateAcceleratorTableW(LPACCEL, int); BOOL CreateCaret(HWND, HBITMAP, int, int); HCURSOR CreateCursor(HINSTANCE, int, int, int, int, PCVOID, PCVOID); HDESK CreateDesktopA(LPCSTR, LPCSTR, LPDEVMODEA, DWORD, ACCESS_MASK, LPSECURITY_ATTRIBUTES); HDESK CreateDesktopW(LPCWSTR, LPCWSTR, LPDEVMODEW, DWORD, ACCESS_MASK, LPSECURITY_ATTRIBUTES); HWND CreateDialogParamA(HINSTANCE, LPCSTR, HWND, DLGPROC, LPARAM); HWND CreateDialogParamW(HINSTANCE, LPCWSTR, HWND, DLGPROC, LPARAM); HWND CreateDialogIndirectParamA(HINSTANCE, LPCDLGTEMPLATE, HWND, DLGPROC, LPARAM); HWND CreateDialogIndirectParamW(HINSTANCE, LPCDLGTEMPLATE, HWND, DLGPROC, LPARAM); HICON CreateIcon(HINSTANCE, int, int, BYTE, BYTE, const(BYTE)*, BYTE*); HICON CreateIconFromResource(PBYTE, DWORD, BOOL, DWORD); HICON CreateIconFromResourceEx(PBYTE, DWORD, BOOL, DWORD, int, int, UINT); HICON CreateIconIndirect(PICONINFO); HWND CreateMDIWindowA(LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HINSTANCE, LPARAM); HWND CreateMDIWindowW(LPCWSTR, LPCWSTR, DWORD, int, int, int, int, HWND, HINSTANCE, LPARAM); HMENU CreateMenu(); HMENU CreatePopupMenu(); HWND CreateWindowExA(DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID); HWND CreateWindowExW(DWORD, LPCWSTR, LPCWSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID); HWINSTA CreateWindowStationA(LPSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES); HWINSTA CreateWindowStationW(LPWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES); LRESULT DefDlgProcA(HWND, UINT, WPARAM, LPARAM); LRESULT DefDlgProcW(HWND, UINT, WPARAM, LPARAM); HDWP DeferWindowPos(HDWP, HWND, HWND, int, int, int, int, UINT); LRESULT DefFrameProcA(HWND, HWND, UINT, WPARAM, LPARAM); LRESULT DefFrameProcW(HWND, HWND, UINT, WPARAM, LPARAM); LRESULT DefMDIChildProcA(HWND, UINT, WPARAM, LPARAM); LRESULT DefMDIChildProcW(HWND, UINT, WPARAM, LPARAM); LRESULT DefWindowProcA(HWND, UINT, WPARAM, LPARAM); LRESULT DefWindowProcW(HWND, UINT, WPARAM, LPARAM); BOOL DeleteMenu(HMENU, UINT, UINT); BOOL DeregisterShellHookWindow(HWND); BOOL DestroyAcceleratorTable(HACCEL); BOOL DestroyCaret(); BOOL DestroyCursor(HCURSOR); BOOL DestroyIcon(HICON); BOOL DestroyMenu(HMENU); BOOL DestroyWindow(HWND); INT_PTR DialogBoxParamA(HINSTANCE, LPCSTR, HWND, DLGPROC, LPARAM); INT_PTR DialogBoxParamW(HINSTANCE, LPCWSTR, HWND, DLGPROC, LPARAM); INT_PTR DialogBoxIndirectParamA(HINSTANCE, LPCDLGTEMPLATE, HWND, DLGPROC, LPARAM); INT_PTR DialogBoxIndirectParamW(HINSTANCE, LPCDLGTEMPLATE, HWND, DLGPROC, LPARAM); } // extern (Windows) nothrow @nogc { HCURSOR CopyCursor(HCURSOR c) { return cast(HCURSOR)CopyIcon(cast(HICON)c); } HWND CreateDialogA(HINSTANCE h, LPCSTR n, HWND w, DLGPROC f) { return CreateDialogParamA(h, n, w, f, 0); } HWND CreateDialogW(HINSTANCE h, LPCWSTR n, HWND w, DLGPROC f) { return CreateDialogParamW(h, n, w, f, 0); } HWND CreateDialogIndirectA(HINSTANCE h, LPCDLGTEMPLATE t, HWND w, DLGPROC f) { return CreateDialogIndirectParamA(h, t, w, f, 0); } HWND CreateDialogIndirectW(HINSTANCE h, LPCDLGTEMPLATE t, HWND w, DLGPROC f) { return CreateDialogIndirectParamW(h, t, w, f, 0); } HWND CreateWindowA(LPCSTR a, LPCSTR b, DWORD c, int d, int e, int f, int g, HWND h, HMENU i, HINSTANCE j, LPVOID k) { return CreateWindowExA(0, a, b, c, d, e, f, g, h, i, j, k); } HWND CreateWindowW(LPCWSTR a, LPCWSTR b, DWORD c, int d, int e, int f, int g, HWND h, HMENU i, HINSTANCE j, LPVOID k) { return CreateWindowExW(0, a, b, c, d, e, f, g, h, i, j, k); } INT_PTR DialogBoxA(HINSTANCE i, LPCSTR t, HWND p, DLGPROC f) { return DialogBoxParamA(i, t, p, f, 0); } INT_PTR DialogBoxW(HINSTANCE i, LPCWSTR t, HWND p, DLGPROC f) { return DialogBoxParamW(i, t, p, f, 0); } INT_PTR DialogBoxIndirectA(HINSTANCE i, LPCDLGTEMPLATE t, HWND p, DLGPROC f) { return DialogBoxIndirectParamA(i, t, p, f, 0); } INT_PTR DialogBoxIndirectW(HINSTANCE i, LPCDLGTEMPLATE t, HWND p, DLGPROC f) { return DialogBoxIndirectParamW(i, t, p, f, 0); } BOOL ExitWindows(UINT r, DWORD c) { return ExitWindowsEx(EWX_LOGOFF, 0); } } alias GetWindow GetNextWindow; extern (Windows) nothrow @nogc: LONG DispatchMessageA(const(MSG)*); LONG DispatchMessageW(const(MSG)*); int DlgDirListA(HWND, LPSTR, int, int, UINT); int DlgDirListW(HWND, LPWSTR, int, int, UINT); int DlgDirListComboBoxA(HWND, LPSTR, int, int, UINT); int DlgDirListComboBoxW(HWND, LPWSTR, int, int, UINT); BOOL DlgDirSelectComboBoxExA(HWND, LPSTR, int, int); BOOL DlgDirSelectComboBoxExW(HWND, LPWSTR, int, int); BOOL DlgDirSelectExA(HWND, LPSTR, int, int); BOOL DlgDirSelectExW(HWND, LPWSTR, int, int); BOOL DragDetect(HWND, POINT); DWORD DragObject(HWND, HWND, UINT, DWORD, HCURSOR); BOOL DrawAnimatedRects(HWND, int, LPCRECT, LPCRECT); BOOL DrawCaption(HWND, HDC, LPCRECT, UINT); BOOL DrawEdge(HDC, LPRECT, UINT, UINT); BOOL DrawFocusRect(HDC, LPCRECT); BOOL DrawFrameControl(HDC, LPRECT, UINT, UINT); BOOL DrawIcon(HDC, int, int, HICON); BOOL DrawIconEx(HDC, int, int, HICON, int, int, UINT, HBRUSH, UINT); BOOL DrawMenuBar(HWND); BOOL DrawStateA(HDC, HBRUSH, DRAWSTATEPROC, LPARAM, WPARAM, int, int, int, int, UINT); BOOL DrawStateW(HDC, HBRUSH, DRAWSTATEPROC, LPARAM, WPARAM, int, int, int, int, UINT); int DrawTextA(HDC, LPCSTR, int, LPRECT, UINT); int DrawTextW(HDC, LPCWSTR, int, LPRECT, UINT); int DrawTextExA(HDC, LPSTR, int, LPRECT, UINT, LPDRAWTEXTPARAMS); int DrawTextExW(HDC, LPWSTR, int, LPRECT, UINT, LPDRAWTEXTPARAMS); BOOL EmptyClipboard(); BOOL EnableMenuItem(HMENU, UINT, UINT); BOOL EnableScrollBar(HWND, UINT, UINT); BOOL EnableWindow(HWND, BOOL); BOOL EndDeferWindowPos(HDWP); BOOL EndDialog(HWND, INT_PTR); BOOL EndMenu(); BOOL EndPaint(HWND, const(PAINTSTRUCT)*); BOOL EnumChildWindows(HWND, ENUMWINDOWSPROC, LPARAM); UINT EnumClipboardFormats(UINT); BOOL EnumDesktopsA(HWINSTA, DESKTOPENUMPROCA, LPARAM); BOOL EnumDesktopsW(HWINSTA, DESKTOPENUMPROCW, LPARAM); BOOL EnumDesktopWindows(HDESK, ENUMWINDOWSPROC, LPARAM); BOOL EnumDisplaySettingsA(LPCSTR, DWORD, PDEVMODEA); BOOL EnumDisplaySettingsW(LPCWSTR, DWORD, PDEVMODEW); BOOL EnumDisplayDevicesA(LPCSTR, DWORD, PDISPLAY_DEVICEA, DWORD); BOOL EnumDisplayDevicesW(LPCWSTR, DWORD, PDISPLAY_DEVICEW, DWORD); int EnumPropsA(HWND, PROPENUMPROCA); int EnumPropsW(HWND, PROPENUMPROCW); int EnumPropsExA(HWND, PROPENUMPROCEXA, LPARAM); int EnumPropsExW(HWND, PROPENUMPROCEXW, LPARAM); BOOL EnumThreadWindows(DWORD, WNDENUMPROC, LPARAM); BOOL EnumWindows(WNDENUMPROC, LPARAM); BOOL EnumWindowStationsA(WINSTAENUMPROCA, LPARAM); BOOL EnumWindowStationsW(WINSTAENUMPROCW, LPARAM); BOOL EqualRect(LPCRECT, LPCRECT); BOOL ExitWindowsEx(UINT, DWORD); HWND FindWindowA(LPCSTR, LPCSTR); HWND FindWindowExA(HWND, HWND, LPCSTR, LPCSTR); HWND FindWindowExW(HWND, HWND, LPCWSTR, LPCWSTR); HWND FindWindowW(LPCWSTR, LPCWSTR); BOOL FlashWindow(HWND, BOOL); int FrameRect(HDC, LPCRECT, HBRUSH); BOOL FrameRgn(HDC, HRGN, HBRUSH, int, int); HWND GetActiveWindow(); HWND GetAncestor(HWND, UINT); SHORT GetAsyncKeyState(int); HWND GetCapture(); UINT GetCaretBlinkTime(); BOOL GetCaretPos(LPPOINT); BOOL GetClassInfoA(HINSTANCE, LPCSTR, LPWNDCLASSA); BOOL GetClassInfoExA(HINSTANCE, LPCSTR, LPWNDCLASSEXA); BOOL GetClassInfoW(HINSTANCE, LPCWSTR, LPWNDCLASSW); BOOL GetClassInfoExW(HINSTANCE, LPCWSTR, LPWNDCLASSEXW); DWORD GetClassLongA(HWND, int); DWORD GetClassLongW(HWND, int); int GetClassNameA(HWND, LPSTR, int); int GetClassNameW(HWND, LPWSTR, int); WORD GetClassWord(HWND, int); BOOL GetClientRect(HWND, LPRECT); HANDLE GetClipboardData(UINT); int GetClipboardFormatNameA(UINT, LPSTR, int); int GetClipboardFormatNameW(UINT, LPWSTR, int); HWND GetClipboardOwner(); HWND GetClipboardViewer(); BOOL GetClipCursor(LPRECT); BOOL GetCursorPos(LPPOINT); HDC GetDC(HWND); HDC GetDCEx(HWND, HRGN, DWORD); HWND GetDesktopWindow(); int GetDialogBaseUnits(); int GetDlgCtrlID(HWND); HWND GetDlgItem(HWND, int); UINT GetDlgItemInt(HWND, int, PBOOL, BOOL); UINT GetDlgItemTextA(HWND, int, LPSTR, int); UINT GetDlgItemTextW(HWND, int, LPWSTR, int); UINT GetDoubleClickTime(); HWND GetFocus(); HWND GetForegroundWindow(); BOOL GetIconInfo(HICON, PICONINFO); BOOL GetInputState(); UINT GetKBCodePage(); HKL GetKeyboardLayout(DWORD); UINT GetKeyboardLayoutList(int, HKL*); BOOL GetKeyboardLayoutNameA(LPSTR); BOOL GetKeyboardLayoutNameW(LPWSTR); BOOL GetKeyboardState(PBYTE); int GetKeyboardType(int); int GetKeyNameTextA(LONG, LPSTR, int); int GetKeyNameTextW(LONG, LPWSTR, int); SHORT GetKeyState(int); HWND GetLastActivePopup(HWND); HMENU GetMenu(HWND); LONG GetMenuCheckMarkDimensions(); DWORD GetMenuContextHelpId(HMENU); UINT GetMenuDefaultItem(HMENU, UINT, UINT); int GetMenuItemCount(HMENU); UINT GetMenuItemID(HMENU, int); BOOL GetMenuItemInfoA(HMENU, UINT, BOOL, LPMENUITEMINFOA); BOOL GetMenuItemInfoW(HMENU, UINT, BOOL, LPMENUITEMINFOW); BOOL GetMenuItemRect(HWND, HMENU, UINT, LPRECT); UINT GetMenuState(HMENU, UINT, UINT); int GetMenuStringA(HMENU, UINT, LPSTR, int, UINT); int GetMenuStringW(HMENU, UINT, LPWSTR, int, UINT); BOOL GetMessageA(LPMSG, HWND, UINT, UINT); BOOL GetMessageW(LPMSG, HWND, UINT, UINT); LONG GetMessageExtraInfo(); DWORD GetMessagePos(); LONG GetMessageTime(); HWND GetNextDlgGroupItem(HWND, HWND, BOOL); HWND GetNextDlgTabItem(HWND, HWND, BOOL); HWND GetOpenClipboardWindow(); HWND GetParent(HWND); int GetPriorityClipboardFormat(UINT*, int); HANDLE GetPropA(HWND, LPCSTR); HANDLE GetPropW(HWND, LPCWSTR); DWORD GetQueueStatus(UINT); BOOL GetScrollInfo(HWND, int, LPSCROLLINFO); int GetScrollPos(HWND, int); BOOL GetScrollRange(HWND, int, LPINT, LPINT); HMENU GetSubMenu(HMENU, int); DWORD GetSysColor(int); HBRUSH GetSysColorBrush(int); HMENU GetSystemMenu(HWND, BOOL); int GetSystemMetrics(int); DWORD GetTabbedTextExtentA(HDC, LPCSTR, int, int, LPINT); DWORD GetTabbedTextExtentW(HDC, LPCWSTR, int, int, LPINT); LONG GetWindowLongA(HWND, int); LONG GetWindowLongW(HWND, int); HDESK GetThreadDesktop(DWORD); HWND GetTopWindow(HWND); BOOL GetUpdateRect(HWND, LPRECT, BOOL); int GetUpdateRgn(HWND, HRGN, BOOL); BOOL GetUserObjectInformationA(HANDLE, int, PVOID, DWORD, PDWORD); BOOL GetUserObjectInformationW(HANDLE, int, PVOID, DWORD, PDWORD); BOOL GetUserObjectSecurity(HANDLE, PSECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, PDWORD); HWND GetWindow(HWND, UINT); DWORD GetWindowContextHelpId(HWND); HDC GetWindowDC(HWND); BOOL GetWindowPlacement(HWND, WINDOWPLACEMENT*); BOOL GetWindowRect(HWND, LPRECT); int GetWindowRgn(HWND, HRGN); int GetWindowTextA(HWND, LPSTR, int); int GetWindowTextLengthA(HWND); int GetWindowTextLengthW(HWND); int GetWindowTextW(HWND, LPWSTR, int); WORD GetWindowWord(HWND, int); BOOL GetAltTabInfoA(HWND, int, PALTTABINFO, LPSTR, UINT); BOOL GetAltTabInfoW(HWND, int, PALTTABINFO, LPWSTR, UINT); BOOL GetComboBoxInfo(HWND, PCOMBOBOXINFO); BOOL GetCursorInfo(PCURSORINFO); BOOL GetLastInputInfo(PLASTINPUTINFO); DWORD GetListBoxInfo(HWND); BOOL GetMenuBarInfo(HWND, LONG, LONG, PMENUBARINFO); BOOL GetMenuInfo(HMENU, LPMENUINFO); BOOL GetScrollBarInfo(HWND, LONG, PSCROLLBARINFO); BOOL GetTitleBarInfo(HWND, PTITLEBARINFO); BOOL GetWindowInfo(HWND, PWINDOWINFO); UINT GetWindowModuleFileNameA(HWND, LPSTR, UINT); UINT GetWindowModuleFileNameW(HWND, LPWSTR, UINT); BOOL GrayStringA(HDC, HBRUSH, GRAYSTRINGPROC, LPARAM, int, int, int, int, int); BOOL GrayStringW(HDC, HBRUSH, GRAYSTRINGPROC, LPARAM, int, int, int, int, int); BOOL HideCaret(HWND); BOOL HiliteMenuItem(HWND, HMENU, UINT, UINT); BOOL InflateRect(LPRECT, int, int); BOOL InSendMessage(); BOOL InsertMenuA(HMENU, UINT, UINT, UINT_PTR, LPCSTR); BOOL InsertMenuW(HMENU, UINT, UINT, UINT_PTR, LPCWSTR); BOOL InsertMenuItemA(HMENU, UINT, BOOL, LPCMENUITEMINFOA); BOOL InsertMenuItemW(HMENU, UINT, BOOL, LPCMENUITEMINFOW); INT InternalGetWindowText(HWND, LPWSTR, INT); BOOL IntersectRect(LPRECT, LPCRECT, LPCRECT); BOOL InvalidateRect(HWND, LPCRECT, BOOL); BOOL InvalidateRgn(HWND, HRGN, BOOL); BOOL InvertRect(HDC, LPCRECT); BOOL IsCharAlphaA(CHAR ch); BOOL IsCharAlphaNumericA(CHAR); BOOL IsCharAlphaNumericW(WCHAR); BOOL IsCharAlphaW(WCHAR); BOOL IsCharLowerA(CHAR); BOOL IsCharLowerW(WCHAR); BOOL IsCharUpperA(CHAR); BOOL IsCharUpperW(WCHAR); BOOL IsChild(HWND, HWND); BOOL IsClipboardFormatAvailable(UINT); BOOL IsDialogMessageA(HWND, LPMSG); BOOL IsDialogMessageW(HWND, LPMSG); UINT IsDlgButtonChecked(HWND, int); BOOL IsIconic(HWND); BOOL IsMenu(HMENU); BOOL IsRectEmpty(LPCRECT); BOOL IsWindow(HWND); BOOL IsWindowEnabled(HWND); BOOL IsWindowUnicode(HWND); BOOL IsWindowVisible(HWND); BOOL IsZoomed(HWND); void keybd_event(BYTE, BYTE, DWORD, DWORD); BOOL KillTimer(HWND, UINT_PTR); HACCEL LoadAcceleratorsA(HINSTANCE, LPCSTR); HACCEL LoadAcceleratorsW(HINSTANCE, LPCWSTR); HBITMAP LoadBitmapA(HINSTANCE, LPCSTR); HBITMAP LoadBitmapW(HINSTANCE, LPCWSTR); HCURSOR LoadCursorA(HINSTANCE, LPCSTR); HCURSOR LoadCursorFromFileA(LPCSTR); HCURSOR LoadCursorFromFileW(LPCWSTR); HCURSOR LoadCursorW(HINSTANCE, LPCWSTR); HICON LoadIconA(HINSTANCE, LPCSTR); HICON LoadIconW(HINSTANCE, LPCWSTR); HANDLE LoadImageA(HINSTANCE, LPCSTR, UINT, int, int, UINT); HANDLE LoadImageW(HINSTANCE, LPCWSTR, UINT, int, int, UINT); HKL LoadKeyboardLayoutA(LPCSTR, UINT); HKL LoadKeyboardLayoutW(LPCWSTR, UINT); HMENU LoadMenuA(HINSTANCE, LPCSTR); HMENU LoadMenuIndirectA(const(MENUTEMPLATE)*); HMENU LoadMenuIndirectW(const(MENUTEMPLATE)*); HMENU LoadMenuW(HINSTANCE, LPCWSTR); int LoadStringA(HINSTANCE, UINT, LPSTR, int); int LoadStringW(HINSTANCE, UINT, LPWSTR, int); BOOL LockWindowUpdate(HWND); int LookupIconIdFromDirectory(PBYTE, BOOL); int LookupIconIdFromDirectoryEx(PBYTE, BOOL, int, int, UINT); BOOL MapDialogRect(HWND, LPRECT); UINT MapVirtualKeyA(UINT, UINT); UINT MapVirtualKeyExA(UINT, UINT, HKL); UINT MapVirtualKeyExW(UINT, UINT, HKL); UINT MapVirtualKeyW(UINT, UINT); int MapWindowPoints(HWND, HWND, LPPOINT, UINT); int MenuItemFromPoint(HWND, HMENU, POINT); BOOL MessageBeep(UINT); int MessageBoxA(HWND, LPCSTR, LPCSTR, UINT); int MessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT); int MessageBoxExA(HWND, LPCSTR, LPCSTR, UINT, WORD); int MessageBoxExW(HWND, LPCWSTR, LPCWSTR, UINT, WORD); int MessageBoxIndirectA(const(MSGBOXPARAMSA)*); int MessageBoxIndirectW(const(MSGBOXPARAMSW)*); BOOL ModifyMenuA(HMENU, UINT, UINT, UINT_PTR, LPCSTR); BOOL ModifyMenuW(HMENU, UINT, UINT, UINT_PTR, LPCWSTR); void mouse_event(DWORD, DWORD, DWORD, DWORD, ULONG_PTR); BOOL MoveWindow(HWND, int, int, int, int, BOOL); DWORD MsgWaitForMultipleObjects(DWORD, const(HANDLE)*, BOOL, DWORD, DWORD); DWORD MsgWaitForMultipleObjectsEx(DWORD, const(HANDLE)*, DWORD, DWORD, DWORD); DWORD OemKeyScan(WORD); BOOL OemToCharA(LPCSTR, LPSTR); BOOL OemToCharBuffA(LPCSTR, LPSTR, DWORD); BOOL OemToCharBuffW(LPCSTR, LPWSTR, DWORD); BOOL OemToCharW(LPCSTR, LPWSTR); BOOL OffsetRect(LPRECT, int, int); BOOL OpenClipboard(HWND); HDESK OpenDesktopA(LPSTR, DWORD, BOOL, DWORD); HDESK OpenDesktopW(LPWSTR, DWORD, BOOL, DWORD); BOOL OpenIcon(HWND); HDESK OpenInputDesktop(DWORD, BOOL, DWORD); HWINSTA OpenWindowStationA(LPSTR, BOOL, DWORD); HWINSTA OpenWindowStationW(LPWSTR, BOOL, DWORD); BOOL PaintDesktop(HDC); BOOL PeekMessageA(LPMSG, HWND, UINT, UINT, UINT); BOOL PeekMessageW(LPMSG, HWND, UINT, UINT, UINT); BOOL PostMessageA(HWND, UINT, WPARAM, LPARAM); BOOL PostMessageW(HWND, UINT, WPARAM, LPARAM); void PostQuitMessage(int); BOOL PostThreadMessageA(DWORD, UINT, WPARAM, LPARAM); BOOL PostThreadMessageW(DWORD, UINT, WPARAM, LPARAM); BOOL PtInRect(LPCRECT, POINT); HWND RealChildWindowFromPoint(HWND, POINT); UINT RealGetWindowClassA(HWND, LPSTR, UINT); UINT RealGetWindowClassW(HWND, LPWSTR, UINT); BOOL RedrawWindow(HWND, LPCRECT, HRGN, UINT); ATOM RegisterClassA(const(WNDCLASSA)*); ATOM RegisterClassW(const(WNDCLASSW)*); ATOM RegisterClassExA(const(WNDCLASSEXA)*); ATOM RegisterClassExW(const(WNDCLASSEXW)*); UINT RegisterClipboardFormatA(LPCSTR); UINT RegisterClipboardFormatW(LPCWSTR); BOOL RegisterHotKey(HWND, int, UINT, UINT); UINT RegisterWindowMessageA(LPCSTR); UINT RegisterWindowMessageW(LPCWSTR); BOOL ReleaseCapture(); int ReleaseDC(HWND, HDC); BOOL RemoveMenu(HMENU, UINT, UINT); HANDLE RemovePropA(HWND, LPCSTR); HANDLE RemovePropW(HWND, LPCWSTR); BOOL ReplyMessage(LRESULT); BOOL ScreenToClient(HWND, LPPOINT); BOOL ScrollDC(HDC, int, int, LPCRECT, LPCRECT, HRGN, LPRECT); BOOL ScrollWindow(HWND, int, int, LPCRECT, LPCRECT); int ScrollWindowEx(HWND, int, int, LPCRECT, LPCRECT, HRGN, LPRECT, UINT); LONG SendDlgItemMessageA(HWND, int, UINT, WPARAM, LPARAM); LONG SendDlgItemMessageW(HWND, int, UINT, WPARAM, LPARAM); LRESULT SendMessageA(HWND, UINT, WPARAM, LPARAM); BOOL SendMessageCallbackA(HWND, UINT, WPARAM, LPARAM, SENDASYNCPROC, DWORD); BOOL SendMessageCallbackW(HWND, UINT, WPARAM, LPARAM, SENDASYNCPROC, DWORD); LRESULT SendMessageTimeoutA(HWND, UINT, WPARAM, LPARAM, UINT, UINT, PDWORD); LRESULT SendMessageTimeoutW(HWND, UINT, WPARAM, LPARAM, UINT, UINT, PDWORD); LRESULT SendMessageW(HWND, UINT, WPARAM, LPARAM); BOOL SendNotifyMessageA(HWND, UINT, WPARAM, LPARAM); BOOL SendNotifyMessageW(HWND, UINT, WPARAM, LPARAM); HWND SetActiveWindow(HWND); HWND SetCapture(HWND hWnd); BOOL SetCaretBlinkTime(UINT); BOOL SetCaretPos(int, int); DWORD SetClassLongA(HWND, int, LONG); DWORD SetClassLongW(HWND, int, LONG); WORD SetClassWord(HWND, int, WORD); HANDLE SetClipboardData(UINT, HANDLE); HWND SetClipboardViewer(HWND); HCURSOR SetCursor(HCURSOR); BOOL SetCursorPos(int, int); void SetDebugErrorLevel(DWORD); BOOL SetDlgItemInt(HWND, int, UINT, BOOL); BOOL SetDlgItemTextA(HWND, int, LPCSTR); BOOL SetDlgItemTextW(HWND, int, LPCWSTR); BOOL SetDoubleClickTime(UINT); HWND SetFocus(HWND); BOOL SetForegroundWindow(HWND); BOOL SetKeyboardState(PBYTE); BOOL SetMenu(HWND, HMENU); BOOL SetMenuContextHelpId(HMENU, DWORD); BOOL SetMenuDefaultItem(HMENU, UINT, UINT); BOOL SetMenuInfo(HMENU, LPCMENUINFO); BOOL SetMenuItemBitmaps(HMENU, UINT, UINT, HBITMAP, HBITMAP); BOOL SetMenuItemInfoA(HMENU, UINT, BOOL, LPCMENUITEMINFOA); BOOL SetMenuItemInfoW(HMENU, UINT, BOOL, LPCMENUITEMINFOW); LPARAM SetMessageExtraInfo(LPARAM); BOOL SetMessageQueue(int); HWND SetParent(HWND, HWND); BOOL SetProcessWindowStation(HWINSTA); BOOL SetPropA(HWND, LPCSTR, HANDLE); BOOL SetPropW(HWND, LPCWSTR, HANDLE); BOOL SetRect(LPRECT, int, int, int, int); BOOL SetRectEmpty(LPRECT); int SetScrollInfo(HWND, int, LPCSCROLLINFO, BOOL); int SetScrollPos(HWND, int, int, BOOL); BOOL SetScrollRange(HWND, int, int, int, BOOL); BOOL SetSysColors(int, const(INT)*, const(COLORREF)*); BOOL SetSystemCursor(HCURSOR, DWORD); BOOL SetThreadDesktop(HDESK); UINT_PTR SetTimer(HWND, UINT_PTR, UINT, TIMERPROC); BOOL SetUserObjectInformationA(HANDLE, int, PVOID, DWORD); BOOL SetUserObjectInformationW(HANDLE, int, PVOID, DWORD); BOOL SetUserObjectSecurity(HANDLE, PSECURITY_INFORMATION, PSECURITY_DESCRIPTOR); BOOL SetWindowContextHelpId(HWND, DWORD); LONG SetWindowLongA(HWND, int, LONG); LONG SetWindowLongW(HWND, int, LONG); BOOL SetWindowPlacement(HWND hWnd, const(WINDOWPLACEMENT)*); BOOL SetWindowPos(HWND, HWND, int, int, int, int, UINT); int SetWindowRgn(HWND, HRGN, BOOL); HHOOK SetWindowsHookA(int, HOOKPROC); HHOOK SetWindowsHookW(int, HOOKPROC); HHOOK SetWindowsHookExA(int, HOOKPROC, HINSTANCE, DWORD); HHOOK SetWindowsHookExW(int, HOOKPROC, HINSTANCE, DWORD); BOOL SetWindowTextA(HWND, LPCSTR); BOOL SetWindowTextW(HWND, LPCWSTR); WORD SetWindowWord(HWND, int, WORD); BOOL ShowCaret(HWND); int ShowCursor(BOOL); BOOL ShowOwnedPopups(HWND, BOOL); BOOL ShowScrollBar(HWND, int, BOOL); BOOL ShowWindow(HWND, int); BOOL ShowWindowAsync(HWND, int); BOOL SubtractRect(LPRECT, LPCRECT, LPCRECT); BOOL SwapMouseButton(BOOL); BOOL SwitchDesktop(HDESK); BOOL SystemParametersInfoA(UINT, UINT, PVOID, UINT); BOOL SystemParametersInfoW(UINT, UINT, PVOID, UINT); LONG TabbedTextOutA(HDC, int, int, LPCSTR, int, int, LPINT, int); LONG TabbedTextOutW(HDC, int, int, LPCWSTR, int, int, LPINT, int); WORD TileWindows(HWND, UINT, LPCRECT, UINT, const(HWND)*); int ToAscii(UINT, UINT, PBYTE, LPWORD, UINT); int ToAsciiEx(UINT, UINT, PBYTE, LPWORD, UINT, HKL); int ToUnicode(UINT, UINT, PBYTE, LPWSTR, int, UINT); int ToUnicodeEx(UINT, UINT, PBYTE, LPWSTR, int, UINT, HKL); BOOL TrackMouseEvent(LPTRACKMOUSEEVENT); BOOL TrackPopupMenu(HMENU, UINT, int, int, int, HWND, LPCRECT); BOOL TrackPopupMenuEx(HMENU, UINT, int, int, HWND, LPTPMPARAMS); int TranslateAcceleratorA(HWND, HACCEL, LPMSG); int TranslateAcceleratorW(HWND, HACCEL, LPMSG); BOOL TranslateMDISysAccel(HWND, LPMSG); BOOL TranslateMessage(const(MSG)*); BOOL UnhookWindowsHook(int, HOOKPROC); BOOL UnhookWindowsHookEx(HHOOK); BOOL UnionRect(LPRECT, LPCRECT, LPCRECT); BOOL UnloadKeyboardLayout(HKL); BOOL UnregisterClassA(LPCSTR, HINSTANCE); BOOL UnregisterClassW(LPCWSTR, HINSTANCE); BOOL UnregisterHotKey(HWND, int); BOOL UpdateWindow(HWND); BOOL ValidateRect(HWND, LPCRECT); BOOL ValidateRgn(HWND, HRGN); SHORT VkKeyScanA(CHAR); SHORT VkKeyScanExA(CHAR, HKL); SHORT VkKeyScanExW(WCHAR, HKL); SHORT VkKeyScanW(WCHAR); DWORD WaitForInputIdle(HANDLE, DWORD); BOOL WaitMessage(); HWND WindowFromDC(HDC hDC); HWND WindowFromPoint(POINT); UINT WinExec(LPCSTR, UINT); BOOL WinHelpA(HWND, LPCSTR, UINT, DWORD); BOOL WinHelpW(HWND, LPCWSTR, UINT, DWORD); extern (C) { int wsprintfA(LPSTR, LPCSTR, ...); int wsprintfW(LPWSTR, LPCWSTR, ...); } // These shouldn't be necessary for D. alias TypeDef!(char*) va_list_; int wvsprintfA(LPSTR, LPCSTR, va_list_ arglist); int wvsprintfW(LPWSTR, LPCWSTR, va_list_ arglist); enum : DWORD { MONITOR_DEFAULTTONULL, MONITOR_DEFAULTTOPRIMARY, MONITOR_DEFAULTTONEAREST // = 2 } enum MONITORINFOF_PRIMARY = 1; enum EDS_RAWMODE = 0x00000002; enum { ISMEX_NOSEND = 0, ISMEX_SEND = 1, ISMEX_NOTIFY = 2, ISMEX_CALLBACK = 4, ISMEX_REPLIED = 8 } struct TITLEBARINFO { DWORD cbSize = TITLEBARINFO.sizeof; RECT rcTitleBar; DWORD[CCHILDREN_TITLEBAR+1] rgstate; } alias TITLEBARINFO* PTITLEBARINFO, LPTITLEBARINFO; static if (_WIN32_WINNT >= 0x501) { // *** correct? struct FLASHWINFO { UINT cbSize = this.sizeof; HWND hwnd; DWORD dwFlags; UINT uCount; DWORD dwTimeout; } alias FLASHWINFO* PFLASHWINFO; } enum DWORD ASFW_ANY = -1; enum : UINT { LSFW_LOCK = 1, LSFW_UNLOCK } enum { GMMP_USE_DISPLAY_POINTS = 1, GMMP_USE_HIGH_RESOLUTION_POINTS } struct MOUSEMOVEPOINT { int x; int y; DWORD time; ULONG_PTR dwExtraInfo; } alias MOUSEMOVEPOINT* PMOUSEMOVEPOINT, LPMOUSEMOVEPOINT; enum { MIM_MAXHEIGHT = 1, MIM_BACKGROUND = 2, MIM_HELPID = 4, MIM_MENUDATA = 8, MIM_STYLE = 16, MIM_APPLYTOSUBMENUS = 0x80000000L } enum { MNS_NOCHECK = 0x80000000, MNS_MODELESS = 0x40000000, MNS_DRAGDROP = 0x20000000, MNS_AUTODISMISS = 0x10000000, MNS_NOTIFYBYPOS = 0x08000000, MNS_CHECKORBMP = 0x04000000 } enum { PM_QS_INPUT = (QS_INPUT << 16), PM_QS_POSTMESSAGE = ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16), PM_QS_PAINT = (QS_PAINT << 16), PM_QS_SENDMESSAGE = (QS_SENDMESSAGE << 16) } /* #define WM_GETOBJECT 0x003D #define WM_CHANGEUISTATE 0x0127 #define WM_UPDATEUISTATE 0x0128 #define WM_QUERYUISTATE 0x0129 #define WM_UNINITMENUPOPUP 0x0125 #define WM_MENURBUTTONUP 290 #define WM_MENUCOMMAND 0x0126 #define WM_MENUGETOBJECT 0x0124 #define WM_MENUDRAG 0x0123 #define WM_APPCOMMAND 0x0319 #define WM_NCXBUTTONDOWN 171 #define WM_NCXBUTTONUP 172 #define WM_NCXBUTTONDBLCLK 173 #define WM_NCMOUSEHOVER 0x02A0 #define WM_NCMOUSELEAVE 0x02A2*/ enum { FLASHW_STOP = 0, FLASHW_CAPTION = 0x01, FLASHW_TRAY = 0x02, FLASHW_ALL = 0x03, FLASHW_TIMER = 0x04, FLASHW_TIMERNOFG = 0x0C } enum CHILDID_SELF = 0; enum { OBJID_WINDOW = 0x00000000, OBJID_SOUND = 0xFFFFFFF5, OBJID_ALERT = 0xFFFFFFF6, OBJID_CURSOR = 0xFFFFFFF7, OBJID_CARET = 0xFFFFFFF8, OBJID_SIZEGRIP = 0xFFFFFFF9, OBJID_HSCROLL = 0xFFFFFFFA, OBJID_VSCROLL = 0xFFFFFFFB, OBJID_CLIENT = 0xFFFFFFFC, OBJID_MENU = 0xFFFFFFFD, OBJID_TITLEBAR = 0xFFFFFFFE, OBJID_SYSMENU = 0xFFFFFFFF } enum { GUI_CARETBLINKING = 0x0001, GUI_INMOVESIZE = 0x0002, GUI_INMENUMODE = 0x0004, GUI_SYSTEMMENUMODE = 0x0008, GUI_POPUPMENUMODE = 0x0010 } static if (_WIN32_WINNT >= 0x501) { enum GUI_16BITTASK = 0x0020; } enum { WINEVENT_OUTOFCONTEXT = 0x00, WINEVENT_SKIPOWNTHREAD = 0x01, WINEVENT_SKIPOWNPROCESS = 0x02, WINEVENT_INCONTEXT = 0x04 } enum { AW_HOR_POSITIVE = 0x00000001, AW_HOR_NEGATIVE = 0x00000002, AW_VER_POSITIVE = 0x00000004, AW_VER_NEGATIVE = 0x00000008, AW_CENTER = 0x00000010, AW_HIDE = 0x00010000, AW_ACTIVATE = 0x00020000, AW_SLIDE = 0x00040000, AW_BLEND = 0x00080000 } enum { DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000, DEVICE_NOTIFY_SERVICE_HANDLE = 0x00000001 } static if (_WIN32_WINNT >= 0x501) { enum DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004; } enum : DWORD { EVENT_MIN = 0x00000001, EVENT_SYSTEM_SOUND = 0x00000001, EVENT_SYSTEM_ALERT, EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_MENUSTART, EVENT_SYSTEM_MENUEND, EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPEND, EVENT_SYSTEM_CAPTURESTART, EVENT_SYSTEM_CAPTUREEND, EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, EVENT_SYSTEM_CONTEXTHELPSTART, EVENT_SYSTEM_CONTEXTHELPEND, EVENT_SYSTEM_DRAGDROPSTART, EVENT_SYSTEM_DRAGDROPEND, EVENT_SYSTEM_DIALOGSTART, EVENT_SYSTEM_DIALOGEND, EVENT_SYSTEM_SCROLLINGSTART, EVENT_SYSTEM_SCROLLINGEND, EVENT_SYSTEM_SWITCHSTART, EVENT_SYSTEM_SWITCHEND, EVENT_SYSTEM_MINIMIZESTART, EVENT_SYSTEM_MINIMIZEEND, // = 0x00000017 EVENT_OBJECT_CREATE = 0x00008000, EVENT_OBJECT_DESTROY, EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE, EVENT_OBJECT_REORDER, EVENT_OBJECT_FOCUS, EVENT_OBJECT_SELECTION, EVENT_OBJECT_SELECTIONADD, EVENT_OBJECT_SELECTIONREMOVE, EVENT_OBJECT_SELECTIONWITHIN, EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_DESCRIPTIONCHANGE, EVENT_OBJECT_VALUECHANGE, EVENT_OBJECT_PARENTCHANGE, EVENT_OBJECT_HELPCHANGE, EVENT_OBJECT_DEFACTIONCHANGE, EVENT_OBJECT_ACCELERATORCHANGE, // = 0x00008012 EVENT_MAX = 0x7FFFFFFF } static if (_WIN32_WINNT >= 0x501) { enum : DWORD { EVENT_CONSOLE_CARET = 0x00004000, EVENT_CONSOLE_UPDATE_REGION, EVENT_CONSOLE_UPDATE_SIMPLE, EVENT_CONSOLE_UPDATE_SCROLL, EVENT_CONSOLE_LAYOUT, EVENT_CONSOLE_START_APPLICATION, EVENT_CONSOLE_END_APPLICATION, // = 0x00004007 } enum : LONG { CONSOLE_CARET_SELECTION = 1, CONSOLE_CARET_VISIBLE // = 2 } enum LONG CONSOLE_APPLICATION_16BIT = 1; } enum { LWA_COLORKEY = 1, LWA_ALPHA } enum { ULW_COLORKEY = 1, ULW_ALPHA = 2, ULW_OPAQUE = 4 } enum { GR_GDIOBJECTS, GR_USEROBJECTS } enum { XBUTTON1 = 1, XBUTTON2 } struct GUITHREADINFO { DWORD cbSize = this.sizeof; DWORD flags; HWND hwndActive; HWND hwndFocus; HWND hwndCapture; HWND hwndMenuOwner; HWND hwndMoveSize; HWND hwndCaret; RECT rcCaret; } alias GUITHREADINFO* PGUITHREADINFO, LPGUITHREADINFO; extern (Windows) { alias void function(HWINEVENTHOOK, DWORD, HWND, LONG, LONG, DWORD, DWORD) WINEVENTPROC; } // *** line 4680 of MinGW 4.0 int BroadcastSystemMessageA(DWORD, LPDWORD, UINT, WPARAM, LPARAM); int BroadcastSystemMessageW(DWORD, LPDWORD, UINT, WPARAM, LPARAM); UINT SendInput(UINT, LPINPUT, int); BOOL EnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM); BOOL GetMonitorInfoA(HMONITOR, LPMONITORINFO); BOOL GetMonitorInfoW(HMONITOR, LPMONITORINFO); HMONITOR MonitorFromPoint(POINT, DWORD); HMONITOR MonitorFromRect(LPCRECT, DWORD); HMONITOR MonitorFromWindow(HWND, DWORD); BOOL AllowSetForegroundWindow(DWORD); BOOL AnimateWindow(HWND, DWORD, DWORD); BOOL EndTask(HWND, BOOL, BOOL); BOOL EnumDisplaySettingsExA(LPCSTR, DWORD, LPDEVMODEA, DWORD); BOOL EnumDisplaySettingsExW(LPCWSTR, DWORD, LPDEVMODEW, DWORD); DWORD GetClipboardSequenceNumber(); DWORD GetGuiResources(HANDLE, DWORD); BOOL GetGUIThreadInfo(DWORD, LPGUITHREADINFO); int GetMouseMovePointsEx(UINT, LPMOUSEMOVEPOINT, LPMOUSEMOVEPOINT, int, DWORD); BOOL GetProcessDefaultLayout(DWORD*); HWND GetShellWindow(); BOOL IsHungAppWindow(HWND); DWORD InSendMessageEx(LPVOID); BOOL LockSetForegroundWindow(UINT); BOOL LockWorkStation(); void NotifyWinEvent(DWORD, HWND, LONG, LONG); HDEVNOTIFY RegisterDeviceNotificationA(HANDLE, LPVOID, DWORD); HDEVNOTIFY RegisterDeviceNotificationW(HANDLE, LPVOID, DWORD); BOOL SetProcessDefaultLayout(DWORD); HWINEVENTHOOK SetWinEventHook(UINT, UINT, HMODULE, WINEVENTPROC, DWORD, DWORD, UINT); void SwitchToThisWindow(HWND, BOOL); BOOL SetLayeredWindowAttributes(HWND, COLORREF, BYTE, DWORD); BOOL UpdateLayeredWindow(HWND, HDC, POINT*, SIZE*, HDC, POINT*, COLORREF, BLENDFUNCTION*, DWORD); BOOL UserHandleGrantAccess(HANDLE, HANDLE, BOOL); BOOL UnhookWinEvent(HWINEVENTHOOK); BOOL UnregisterDeviceNotification(HANDLE); static if (_WIN32_WINNT >= 0x501) { int BroadcastSystemMessageExA(DWORD, LPDWORD, UINT, WPARAM, LPARAM, PBSMINFO); int BroadcastSystemMessageExW(DWORD, LPDWORD, UINT, WPARAM, LPARAM, PBSMINFO); LRESULT DefRawInputProc(PRAWINPUT*, INT, UINT); BOOL FlashWindowEx(PFLASHWINFO); BOOL GetLayeredWindowAttributes(HWND, COLORREF*, BYTE*, DWORD*); UINT GetRawInputBuffer(PRAWINPUT, PUINT, UINT); UINT GetRawInputData(HRAWINPUT, UINT, LPVOID, PUINT, UINT); UINT GetRawInputDeviceInfoA(HANDLE, UINT, LPVOID, PUINT); UINT GetRawInputDeviceInfoW(HANDLE, UINT, LPVOID, PUINT); UINT GetRawInputDeviceList(PRAWINPUTDEVICELIST, PUINT, UINT); UINT GetRegisteredRawInputDevices(PRAWINPUTDEVICE, PUINT, UINT); BOOL IsGUIThread(BOOL); BOOL IsWinEventHookInstalled(DWORD); BOOL PrintWindow(HWND, HDC, UINT); BOOL RegisterRawInputDevices(PCRAWINPUTDEVICE, UINT, UINT); } version (Win64) { LONG_PTR GetWindowLongPtrA(HWND, int); LONG_PTR GetWindowLongPtrW(HWND, int); LONG_PTR SetWindowLongPtrA(HWND, int, LONG_PTR); LONG_PTR SetWindowLongPtrW(HWND, int, LONG_PTR); } else { alias GetWindowLongA GetWindowLongPtrA; alias GetWindowLongW GetWindowLongPtrW; alias SetWindowLongA SetWindowLongPtrA; alias SetWindowLongW SetWindowLongPtrW; } // ----- // Aliases for Unicode or Ansi version(Unicode) { alias EDITWORDBREAKPROCW EDITWORDBREAKPROC; alias PROPENUMPROCW PROPENUMPROC; alias PROPENUMPROCEXW PROPENUMPROCEX; alias DESKTOPENUMPROCW DESKTOPENUMPROC; alias WINSTAENUMPROCW WINSTAENUMPROC; alias MAKEINTRESOURCEW MAKEINTRESOURCE; alias WNDCLASSW WNDCLASS; alias WNDCLASSEXW WNDCLASSEX; alias MENUITEMINFOW MENUITEMINFO; alias LPCMENUITEMINFOW LPCMENUITEMINFO; alias MSGBOXPARAMSW MSGBOXPARAMS; alias HIGHCONTRASTW HIGHCONTRAST; alias SERIALKEYSW SERIALKEYS; alias SOUNDSENTRYW SOUNDSENTRY; alias CREATESTRUCTW CREATESTRUCT; alias CBT_CREATEWNDW CBT_CREATEWND; alias MDICREATESTRUCTW MDICREATESTRUCT; alias MULTIKEYHELPW MULTIKEYHELP; alias MONITORINFOEXW MONITORINFOEX; alias ICONMETRICSW ICONMETRICS; alias NONCLIENTMETRICSW NONCLIENTMETRICS; alias AppendMenuW AppendMenu; alias BroadcastSystemMessageW BroadcastSystemMessage; static if (_WIN32_WINNT >= 0x501) { alias BroadcastSystemMessageExW BroadcastSystemMessageEx; } alias CallMsgFilterW CallMsgFilter; alias CallWindowProcW CallWindowProc; alias ChangeMenuW ChangeMenu; alias CharLowerW CharLower; alias CharLowerBuffW CharLowerBuff; alias CharNextW CharNext; alias CharNextExW CharNextEx; alias CharPrevW CharPrev; alias CharPrevExW CharPrevEx; alias CharToOemW CharToOem; alias CharToOemBuffW CharToOemBuff; alias CharUpperW CharUpper; alias CharUpperBuffW CharUpperBuff; alias CopyAcceleratorTableW CopyAcceleratorTable; alias CreateAcceleratorTableW CreateAcceleratorTable; alias CreateDialogW CreateDialog; alias CreateDialogIndirectW CreateDialogIndirect; alias CreateDialogIndirectParamW CreateDialogIndirectParam; alias CreateDialogParamW CreateDialogParam; alias CreateMDIWindowW CreateMDIWindow; alias CreateWindowW CreateWindow; alias CreateWindowExW CreateWindowEx; alias CreateWindowStationW CreateWindowStation; alias DefDlgProcW DefDlgProc; alias DefFrameProcW DefFrameProc; alias DefMDIChildProcW DefMDIChildProc; alias DefWindowProcW DefWindowProc; alias DialogBoxW DialogBox; alias DialogBoxIndirectW DialogBoxIndirect; alias DialogBoxIndirectParamW DialogBoxIndirectParam; alias DialogBoxParamW DialogBoxParam; alias DispatchMessageW DispatchMessage; alias DlgDirListW DlgDirList; alias DlgDirListComboBoxW DlgDirListComboBox; alias DlgDirSelectComboBoxExW DlgDirSelectComboBoxEx; alias DlgDirSelectExW DlgDirSelectEx; alias DrawStateW DrawState; alias DrawTextW DrawText; alias DrawTextExW DrawTextEx; alias EnumDesktopsW EnumDesktops; alias EnumPropsW EnumProps; alias EnumPropsExW EnumPropsEx; alias EnumWindowStationsW EnumWindowStations; alias FindWindowW FindWindow; alias FindWindowExW FindWindowEx; alias GetClassInfoW GetClassInfo; alias GetClassInfoExW GetClassInfoEx; alias GetClassLongW GetClassLong; alias GetClassNameW GetClassName; alias GetClipboardFormatNameW GetClipboardFormatName; alias GetDlgItemTextW GetDlgItemText; alias GetKeyboardLayoutNameW GetKeyboardLayoutName; alias GetKeyNameTextW GetKeyNameText; alias GetMenuItemInfoW GetMenuItemInfo; alias GetMenuStringW GetMenuString; alias GetMessageW GetMessage; alias GetMonitorInfoW GetMonitorInfo; alias GetPropW GetProp; static if (_WIN32_WINNT >= 0x501) { alias GetRawInputDeviceInfoW GetRawInputDeviceInfo; } alias GetTabbedTextExtentW GetTabbedTextExtent; alias GetUserObjectInformationW GetUserObjectInformation; alias GetWindowLongW GetWindowLong; alias GetWindowLongPtrW GetWindowLongPtr; alias GetWindowTextW GetWindowText; alias GetWindowTextLengthW GetWindowTextLength; alias GetAltTabInfoW GetAltTabInfo; alias GetWindowModuleFileNameW GetWindowModuleFileName; alias GrayStringW GrayString; alias InsertMenuW InsertMenu; alias InsertMenuItemW InsertMenuItem; alias IsCharAlphaW IsCharAlpha; alias IsCharAlphaNumericW IsCharAlphaNumeric; alias IsCharLowerW IsCharLower; alias IsCharUpperW IsCharUpper; alias IsDialogMessageW IsDialogMessage; alias LoadAcceleratorsW LoadAccelerators; alias LoadBitmapW LoadBitmap; alias LoadCursorW LoadCursor; alias LoadCursorFromFileW LoadCursorFromFile; alias LoadIconW LoadIcon; alias LoadImageW LoadImage; alias LoadKeyboardLayoutW LoadKeyboardLayout; alias LoadMenuW LoadMenu; alias LoadMenuIndirectW LoadMenuIndirect; alias LoadStringW LoadString; alias MapVirtualKeyW MapVirtualKey; alias MapVirtualKeyExW MapVirtualKeyEx; alias MessageBoxW MessageBox; alias MessageBoxExW MessageBoxEx; alias MessageBoxIndirectW MessageBoxIndirect; alias ModifyMenuW ModifyMenu; alias OemToCharW OemToChar; alias OemToCharBuffW OemToCharBuff; alias OpenDesktopW OpenDesktop; alias OpenWindowStationW OpenWindowStation; alias PeekMessageW PeekMessage; alias PostMessageW PostMessage; alias PostThreadMessageW PostThreadMessage; alias RealGetWindowClassW RealGetWindowClass; alias RegisterClassW RegisterClass; alias RegisterClassExW RegisterClassEx; alias RegisterClipboardFormatW RegisterClipboardFormat; alias RegisterDeviceNotificationW RegisterDeviceNotification; alias RegisterWindowMessageW RegisterWindowMessage; alias RemovePropW RemoveProp; alias SendDlgItemMessageW SendDlgItemMessage; alias SendMessageW SendMessage; alias SendMessageCallbackW SendMessageCallback; alias SendMessageTimeoutW SendMessageTimeout; alias SendNotifyMessageW SendNotifyMessage; alias SetClassLongW SetClassLong; alias SetDlgItemTextW SetDlgItemText; alias SetMenuItemInfoW SetMenuItemInfo; alias SetPropW SetProp; alias SetUserObjectInformationW SetUserObjectInformation; alias SetWindowLongW SetWindowLong; alias SetWindowLongPtrW SetWindowLongPtr; alias SetWindowsHookW SetWindowsHook; alias SetWindowsHookExW SetWindowsHookEx; alias SetWindowTextW SetWindowText; alias SystemParametersInfoW SystemParametersInfo; alias TabbedTextOutW TabbedTextOut; alias TranslateAcceleratorW TranslateAccelerator; alias UnregisterClassW UnregisterClass; alias VkKeyScanW VkKeyScan; alias VkKeyScanExW VkKeyScanEx; alias WinHelpW WinHelp; alias wsprintfW wsprintf; alias wvsprintfW wvsprintf; alias ChangeDisplaySettingsW ChangeDisplaySettings; alias ChangeDisplaySettingsExW ChangeDisplaySettingsEx; alias CreateDesktopW CreateDesktop; alias EnumDisplaySettingsW EnumDisplaySettings; alias EnumDisplaySettingsExW EnumDisplaySettingsEx; alias EnumDisplayDevicesW EnumDisplayDevices; } else { // ANSI alias EDITWORDBREAKPROCA EDITWORDBREAKPROC; alias PROPENUMPROCA PROPENUMPROC; alias PROPENUMPROCEXA PROPENUMPROCEX; alias DESKTOPENUMPROCA DESKTOPENUMPROC; alias WINSTAENUMPROCA WINSTAENUMPROC; alias MAKEINTRESOURCEA MAKEINTRESOURCE; alias WNDCLASSA WNDCLASS; alias WNDCLASSEXA WNDCLASSEX; alias MENUITEMINFOA MENUITEMINFO; alias LPCMENUITEMINFOA LPCMENUITEMINFO; alias MSGBOXPARAMSA MSGBOXPARAMS; alias HIGHCONTRASTA HIGHCONTRAST; alias SERIALKEYSA SERIALKEYS; alias SOUNDSENTRYA SOUNDSENTRY; alias CREATESTRUCTA CREATESTRUCT; alias CBT_CREATEWNDA CBT_CREATEWND; alias MDICREATESTRUCTA MDICREATESTRUCT; alias MULTIKEYHELPA MULTIKEYHELP; alias MONITORINFOEXA MONITORINFOEX; alias ICONMETRICSA ICONMETRICS; alias NONCLIENTMETRICSA NONCLIENTMETRICS; alias AppendMenuA AppendMenu; alias BroadcastSystemMessageA BroadcastSystemMessage; static if (_WIN32_WINNT >= 0x501) { alias BroadcastSystemMessageExA BroadcastSystemMessageEx; } alias CallMsgFilterA CallMsgFilter; alias CallWindowProcA CallWindowProc; alias ChangeMenuA ChangeMenu; alias CharLowerA CharLower; alias CharLowerBuffA CharLowerBuff; alias CharNextA CharNext; alias CharNextExA CharNextEx; alias CharPrevA CharPrev; alias CharPrevExA CharPrevEx; alias CharToOemA CharToOem; alias CharToOemBuffA CharToOemBuff; alias CharUpperA CharUpper; alias CharUpperBuffA CharUpperBuff; alias CopyAcceleratorTableA CopyAcceleratorTable; alias CreateAcceleratorTableA CreateAcceleratorTable; alias CreateDialogA CreateDialog; alias CreateDialogIndirectA CreateDialogIndirect; alias CreateDialogIndirectParamA CreateDialogIndirectParam; alias CreateDialogParamA CreateDialogParam; alias CreateMDIWindowA CreateMDIWindow; alias CreateWindowA CreateWindow; alias CreateWindowExA CreateWindowEx; alias CreateWindowStationA CreateWindowStation; alias DefDlgProcA DefDlgProc; alias DefFrameProcA DefFrameProc; alias DefMDIChildProcA DefMDIChildProc; alias DefWindowProcA DefWindowProc; alias DialogBoxA DialogBox; alias DialogBoxIndirectA DialogBoxIndirect; alias DialogBoxIndirectParamA DialogBoxIndirectParam; alias DialogBoxParamA DialogBoxParam; alias DispatchMessageA DispatchMessage; alias DlgDirListA DlgDirList; alias DlgDirListComboBoxA DlgDirListComboBox; alias DlgDirSelectComboBoxExA DlgDirSelectComboBoxEx; alias DlgDirSelectExA DlgDirSelectEx; alias DrawStateA DrawState; alias DrawTextA DrawText; alias DrawTextExA DrawTextEx; alias EnumDesktopsA EnumDesktops; alias EnumPropsA EnumProps; alias EnumPropsExA EnumPropsEx; alias EnumWindowStationsA EnumWindowStations; alias FindWindowA FindWindow; alias FindWindowExA FindWindowEx; alias GetClassInfoA GetClassInfo; alias GetClassInfoExA GetClassInfoEx; alias GetClassLongA GetClassLong; alias GetClassNameA GetClassName; alias GetClipboardFormatNameA GetClipboardFormatName; alias GetDlgItemTextA GetDlgItemText; alias GetKeyboardLayoutNameA GetKeyboardLayoutName; alias GetKeyNameTextA GetKeyNameText; alias GetMenuItemInfoA GetMenuItemInfo; alias GetMenuStringA GetMenuString; alias GetMessageA GetMessage; alias GetMonitorInfoA GetMonitorInfo; alias GetPropA GetProp; static if (_WIN32_WINNT >= 0x501) { alias GetRawInputDeviceInfoA GetRawInputDeviceInfo; } alias GetTabbedTextExtentA GetTabbedTextExtent; alias GetUserObjectInformationA GetUserObjectInformation; alias GetWindowLongA GetWindowLong; alias GetWindowLongPtrA GetWindowLongPtr; alias GetWindowTextA GetWindowText; alias GetWindowTextLengthA GetWindowTextLength; alias GetAltTabInfoA GetAltTabInfo; alias GetWindowModuleFileNameA GetWindowModuleFileName; alias GrayStringA GrayString; alias InsertMenuA InsertMenu; alias InsertMenuItemA InsertMenuItem; alias IsCharAlphaA IsCharAlpha; alias IsCharAlphaNumericA IsCharAlphaNumeric; alias IsCharLowerA IsCharLower; alias IsCharUpperA IsCharUpper; alias IsDialogMessageA IsDialogMessage; alias LoadAcceleratorsA LoadAccelerators; alias LoadBitmapA LoadBitmap; alias LoadCursorA LoadCursor; alias LoadIconA LoadIcon; alias LoadCursorFromFileA LoadCursorFromFile; alias LoadImageA LoadImage; alias LoadKeyboardLayoutA LoadKeyboardLayout; alias LoadMenuA LoadMenu; alias LoadMenuIndirectA LoadMenuIndirect; alias LoadStringA LoadString; alias MapVirtualKeyA MapVirtualKey; alias MapVirtualKeyExA MapVirtualKeyEx; alias MessageBoxA MessageBox; alias MessageBoxExA MessageBoxEx; alias MessageBoxIndirectA MessageBoxIndirect; alias ModifyMenuA ModifyMenu; alias OemToCharA OemToChar; alias OemToCharBuffA OemToCharBuff; alias OpenDesktopA OpenDesktop; alias OpenWindowStationA OpenWindowStation; alias PeekMessageA PeekMessage; alias PostMessageA PostMessage; alias PostThreadMessageA PostThreadMessage; alias RealGetWindowClassA RealGetWindowClass; alias RegisterClassA RegisterClass; alias RegisterClassExA RegisterClassEx; alias RegisterClipboardFormatA RegisterClipboardFormat; alias RegisterDeviceNotificationA RegisterDeviceNotification; alias RegisterWindowMessageA RegisterWindowMessage; alias RemovePropA RemoveProp; alias SendDlgItemMessageA SendDlgItemMessage; alias SendMessageA SendMessage; alias SendMessageCallbackA SendMessageCallback; alias SendMessageTimeoutA SendMessageTimeout; alias SendNotifyMessageA SendNotifyMessage; alias SetClassLongA SetClassLong; alias SetDlgItemTextA SetDlgItemText; alias SetMenuItemInfoA SetMenuItemInfo; alias SetPropA SetProp; alias SetUserObjectInformationA SetUserObjectInformation; alias SetWindowLongA SetWindowLong; alias SetWindowLongPtrA SetWindowLongPtr; alias SetWindowsHookA SetWindowsHook; alias SetWindowsHookExA SetWindowsHookEx; alias SetWindowTextA SetWindowText; alias SystemParametersInfoA SystemParametersInfo; alias TabbedTextOutA TabbedTextOut; alias TranslateAcceleratorA TranslateAccelerator; alias UnregisterClassA UnregisterClass; alias VkKeyScanA VkKeyScan; alias VkKeyScanExA VkKeyScanEx; alias WinHelpA WinHelp; alias wsprintfA wsprintf; alias wvsprintfA wvsprintf; alias ChangeDisplaySettingsA ChangeDisplaySettings; alias ChangeDisplaySettingsExA ChangeDisplaySettingsEx; alias CreateDesktopA CreateDesktop; alias EnumDisplaySettingsA EnumDisplaySettings; alias EnumDisplaySettingsExA EnumDisplaySettingsEx; alias EnumDisplayDevicesA EnumDisplayDevices; } alias WNDCLASS* LPWNDCLASS, PWNDCLASS; alias WNDCLASSEX* LPWNDCLASSEX, PWNDCLASSEX; alias MENUITEMINFO* LPMENUITEMINFO; alias MSGBOXPARAMS* PMSGBOXPARAMS, LPMSGBOXPARAMS; alias HIGHCONTRAST* LPHIGHCONTRAST; alias SERIALKEYS* LPSERIALKEYS; alias SOUNDSENTRY* LPSOUNDSENTRY; alias CREATESTRUCT* LPCREATESTRUCT; alias CBT_CREATEWND* LPCBT_CREATEWND; alias MDICREATESTRUCT* LPMDICREATESTRUCT; alias MULTIKEYHELP* PMULTIKEYHELP, LPMULTIKEYHELP; alias MONITORINFOEX* LPMONITORINFOEX; alias ICONMETRICS* LPICONMETRICS; alias NONCLIENTMETRICS* LPNONCLIENTMETRICS; static if (_WIN32_WINNT >= 0x501) { enum PW_CLIENTONLY = 0x00000001; enum RIM_INPUT = 0x00000000; enum RIM_INPUTSINK = 0x00000001; enum RIM_TYPEMOUSE = 0x00000000; enum RIM_TYPEKEYBOARD = 0x00000001; enum RIM_TYPEHID = 0x00000002; enum MOUSE_MOVE_RELATIVE = 0x00000000; enum MOUSE_MOVE_ABSOLUTE = 0x00000001; enum MOUSE_VIRTUAL_DESKTOP = 0x00000002; enum MOUSE_ATTRIBUTES_CHANGED = 0x00000004; enum RI_MOUSE_LEFT_BUTTON_DOWN = 0x0001; enum RI_MOUSE_LEFT_BUTTON_UP = 0x0002; enum RI_MOUSE_RIGHT_BUTTON_DOWN = 0x0004; enum RI_MOUSE_RIGHT_BUTTON_UP = 0x0008; enum RI_MOUSE_MIDDLE_BUTTON_DOWN = 0x0010; enum RI_MOUSE_MIDDLE_BUTTON_UP = 0x0020; enum RI_MOUSE_BUTTON_1_DOWN = RI_MOUSE_LEFT_BUTTON_DOWN; enum RI_MOUSE_BUTTON_1_UP = RI_MOUSE_LEFT_BUTTON_UP; enum RI_MOUSE_BUTTON_2_DOWN = RI_MOUSE_RIGHT_BUTTON_DOWN; enum RI_MOUSE_BUTTON_2_UP = RI_MOUSE_RIGHT_BUTTON_UP; enum RI_MOUSE_BUTTON_3_DOWN = RI_MOUSE_MIDDLE_BUTTON_DOWN; enum RI_MOUSE_BUTTON_3_UP = RI_MOUSE_MIDDLE_BUTTON_UP; enum RI_MOUSE_BUTTON_4_DOWN = 0x0040; enum RI_MOUSE_BUTTON_4_UP = 0x0080; enum RI_MOUSE_BUTTON_5_DOWN = 0x0100; enum RI_MOUSE_BUTTON_5_UP = 0x0200; enum RI_MOUSE_WHEEL = 0x0400; enum KEYBOARD_OVERRUN_MAKE_CODE = 0x00ff; enum RI_KEY_MAKE = 0x0000; enum RI_KEY_BREAK = 0x0001; enum RI_KEY_E0 = 0x0002; enum RI_KEY_E1 = 0x0004; enum RI_KEY_TERMSRV_SET_LED = 0x0008; enum RI_KEY_TERMSRV_SHADOW = 0x0010; enum RID_INPUT = 0x10000003; enum RID_HEADER = 0x10000005; enum RIDI_PREPARSEDDATA = 0x20000005; enum RIDI_DEVICENAME = 0x20000007; enum RIDI_DEVICEINFO = 0x2000000b; enum RIDEV_REMOVE = 0x00000001; enum RIDEV_EXCLUDE = 0x00000010; enum RIDEV_PAGEONLY = 0x00000020; enum RIDEV_NOLEGACY = 0x00000030; enum RIDEV_INPUTSINK = 0x00000100; enum RIDEV_CAPTUREMOUSE = 0x00000200; enum RIDEV_NOHOTKEYS = 0x00000200; enum RIDEV_APPKEYS = 0x00000400; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/tmschema.d0000664000175000017500000002714212776214756023466 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_tmschema.d) */ module core.sys.windows.tmschema; version (Windows): /* BUTTON parts */ enum { BP_PUSHBUTTON = 1, BP_RADIOBUTTON = 2, BP_CHECKBOX = 3, BP_GROUPBOX = 4, BP_USERBUTTON = 5 } enum { CBS_UNCHECKEDNORMAL = 1, CBS_UNCHECKEDHOT = 2, CBS_UNCHECKEDPRESSED = 3, CBS_UNCHECKEDDISABLED = 4, CBS_CHECKEDNORMAL = 5, CBS_CHECKEDHOT = 6, CBS_CHECKEDPRESSED = 7, CBS_CHECKEDDISABLED = 8, CBS_MIXEDNORMAL = 9, CBS_MIXEDHOT = 10, CBS_MIXEDPRESSED = 11, CBS_MIXEDDISABLED = 12 } enum { GBS_NORMAL = 1, GBS_DISABLED = 2 } enum { PBS_NORMAL = 1, PBS_HOT = 2, PBS_PRESSED = 3, PBS_DISABLED = 4, PBS_DEFAULTED = 5 } enum { RBS_UNCHECKEDNORMAL = 1, RBS_UNCHECKEDHOT = 2, RBS_UNCHECKEDPRESSED = 3, RBS_UNCHECKEDDISABLED = 4, RBS_CHECKEDNORMAL = 5, RBS_CHECKEDHOT = 6, RBS_CHECKEDPRESSED = 7, RBS_CHECKEDDISABLED = 8 } /* CLOCK parts */ enum { CLP_TIME = 1 } enum { CLS_NORMAL = 1 } /* COMBOBOX parts */ enum { CP_DROPDOWNBUTTON = 1 } enum { CBXS_NORMAL = 1, CBXS_HOT = 2, CBXS_PRESSED = 3, CBXS_DISABLED = 4 } /* EDIT parts */ enum { EP_EDITTEXT = 1, EP_CARET = 2 } enum { ETS_NORMAL = 1, ETS_HOT = 2, ETS_SELECTED = 3, ETS_DISABLED = 4, ETS_FOCUSED = 5, ETS_READONLY = 6, ETS_ASSIST = 7 } /* EXPLORERBAR parts */ enum { EBP_HEADERBACKGROUND = 1, EBP_HEADERCLOSE = 2, EBP_HEADERPIN = 3, EBP_IEBARMENU = 4, EBP_NORMALGROUPBACKGROUND = 5, EBP_NORMALGROUPCOLLAPSE = 6, EBP_NORMALGROUPEXPAND = 7, EBP_NORMALGROUPHEAD = 8, EBP_SPECIALGROUPBACKGROUND = 9, EBP_SPECIALGROUPCOLLAPSE = 10, EBP_SPECIALGROUPEXPAND = 11, EBP_SPECIALGROUPHEAD = 12 } enum { EBHC_NORMAL = 1, EBHC_HOT = 2, EBHC_PRESSED = 3 } enum { EBHP_NORMAL = 1, EBHP_HOT = 2, EBHP_PRESSED = 3, EBHP_SELECTEDNORMAL = 4, EBHP_SELECTEDHOT = 5, EBHP_SELECTEDPRESSED = 6 } enum { EBM_NORMAL = 1, EBM_HOT = 2, EBM_PRESSED = 3 } enum { EBNGC_NORMAL = 1, EBNGC_HOT = 2, EBNGC_PRESSED = 3 } enum { EBNGE_NORMAL = 1, EBNGE_HOT = 2, EBNGE_PRESSED = 3 } enum { EBSGC_NORMAL = 1, EBSGC_HOT = 2, EBSGC_PRESSED = 3 } enum { EBSGE_NORMAL = 1, EBSGE_HOT = 2, EBSGE_PRESSED = 3 } /* HEADER parts */ enum { HP_HEADERITEM = 1, HP_HEADERITEMLEFT = 2, HP_HEADERITEMRIGHT = 3, HP_HEADERSORTARROW = 4 } enum { HIS_NORMAL = 1, HIS_HOT = 2, HIS_PRESSED = 3 } enum { HILS_NORMAL = 1, HILS_HOT = 2, HILS_PRESSED = 3 } enum { HIRS_NORMAL = 1, HIRS_HOT = 2, HIRS_PRESSED = 3 } enum { HSAS_SORTEDUP = 1, HSAS_SORTEDDOWN = 2 } /* LISTVIEW parts */ enum { LVP_LISTITEM = 1, LVP_LISTGROUP = 2, LVP_LISTDETAIL = 3, LVP_LISTSORTEDDETAIL = 4, LVP_EMPTYTEXT = 5 } enum { LIS_NORMAL = 1, LIS_HOT = 2, LIS_SELECTED = 3, LIS_DISABLED = 4, LIS_SELECTEDNOTFOCUS = 5 } /* MENU parts */ enum { MP_MENUITEM = 1, MP_MENUDROPDOWN = 2, MP_MENUBARITEM = 3, MP_MENUBARDROPDOWN = 4, MP_CHEVRON = 5, MP_SEPARATOR = 6 } enum { MS_NORMAL = 1, MS_SELECTED = 2, MS_DEMOTED = 3 } /* MENUBAND parts */ enum { MDP_NEWAPPBUTTON = 1, MDP_SEPERATOR = 2 } enum { MDS_NORMAL = 1, MDS_HOT = 2, MDS_PRESSED = 3, MDS_DISABLED = 4, MDS_CHECKED = 5, MDS_HOTCHECKED = 6 } /* PAGE parts */ enum { PGRP_UP = 1, PGRP_DOWN = 2, PGRP_UPHORZ = 3, PGRP_DOWNHORZ = 4 } enum { DNS_NORMAL = 1, DNS_HOT = 2, DNS_PRESSED = 3, DNS_DISABLED = 4 } enum { DNHZS_NORMAL = 1, DNHZS_HOT = 2, DNHZS_PRESSED = 3, DNHZS_DISABLED = 4 } enum { UPS_NORMAL = 1, UPS_HOT = 2, UPS_PRESSED = 3, UPS_DISABLED = 4 } enum { UPHZS_NORMAL = 1, UPHZS_HOT = 2, UPHZS_PRESSED = 3, UPHZS_DISABLED = 4 } /* PROGRESS parts */ enum { PP_BAR = 1, PP_BARVERT = 2, PP_CHUNK = 3, PP_CHUNKVERT = 4 } /* REBAR parts */ enum { RP_GRIPPER = 1, RP_GRIPPERVERT = 2, RP_BAND = 3, RP_CHEVRON = 4, RP_CHEVRONVERT = 5 } enum { CHEVS_NORMAL = 1, CHEVS_HOT = 2, CHEVS_PRESSED = 3 } /* SCROLLBAR parts */ enum { SBP_ARROWBTN = 1, SBP_THUMBBTNHORZ = 2, SBP_THUMBBTNVERT = 3, SBP_LOWERTRACKHORZ = 4, SBP_UPPERTRACKHORZ = 5, SBP_LOWERTRACKVERT = 6, SBP_UPPERTRACKVERT = 7, SBP_GRIPPERHORZ = 8, SBP_GRIPPERVERT = 9, SBP_SIZEBOX = 10 } enum { ABS_UPNORMAL = 1, ABS_UPHOT = 2, ABS_UPPRESSED = 3, ABS_UPDISABLED = 4, ABS_DOWNNORMAL = 5, ABS_DOWNHOT = 6, ABS_DOWNPRESSED = 7, ABS_DOWNDISABLED = 8, ABS_LEFTNORMAL = 9, ABS_LEFTHOT = 10, ABS_LEFTPRESSED = 11, ABS_LEFTDISABLED = 12, ABS_RIGHTNORMAL = 13, ABS_RIGHTHOT = 14, ABS_RIGHTPRESSED = 15, ABS_RIGHTDISABLED = 16 } enum { SCRBS_NORMAL = 1, SCRBS_HOT = 2, SCRBS_PRESSED = 3, SCRBS_DISABLED = 4 } enum { SZB_RIGHTALIGN = 1, SZB_LEFTALIGN = 2 } /* SPIN parts */ enum { SPNP_UP = 1, SPNP_DOWN = 2, SPNP_UPHORZ = 3, SPNP_DOWNHORZ = 4 } /* STARTPANEL parts */ enum { SPP_USERPANE = 1, SPP_MOREPROGRAMS = 2, SPP_MOREPROGRAMSARROW = 3, SPP_PROGLIST = 4, SPP_PROGLISTSEPARATOR = 5, SPP_PLACESLIST = 6, SPP_PLACESLISTSEPARATOR = 7, SPP_LOGOFF = 8, SPP_LOGOFFBUTTONS = 9, SPP_USERPICTURE = 10, SPP_PREVIEW = 11 } enum { SPLS_NORMAL = 1, SPLS_HOT = 2, SPLS_PRESSED = 3 } enum { SPS_NORMAL = 1, SPS_HOT = 2, SPS_PRESSED = 3 } /* STATUS parts */ enum { SP_PANE = 1, SP_GRIPPERPANE = 2, SP_GRIPPER = 3 } /* TAB parts */ enum { TABP_TABITEM = 1, TABP_TABITEMLEFTEDGE = 2, TABP_TABITEMRIGHTEDGE = 3, TABP_TABITEMBOTHEDGE = 4, TABP_TOPTABITEM = 5, TABP_TOPTABITEMLEFTEDGE = 6, TABP_TOPTABITEMRIGHTEDGE = 7, TABP_TOPTABITEMBOTHEDGE = 8, TABP_PANE = 9, TABP_BODY = 10 } enum { TIS_NORMAL = 1, TIS_HOT = 2, TIS_SELECTED = 3, TIS_DISABLED = 4, TIS_FOCUSED = 5 } enum { TIBES_NORMAL = 1, TIBES_HOT = 2, TIBES_SELECTED = 3, TIBES_DISABLED = 4, TIBES_FOCUSED = 5 } enum { TILES_NORMAL = 1, TILES_HOT = 2, TILES_SELECTED = 3, TILES_DISABLED = 4, TILES_FOCUSED = 5 } enum { TIRES_NORMAL = 1, TIRES_HOT = 2, TIRES_SELECTED = 3, TIRES_DISABLED = 4, TIRES_FOCUSED = 5 } enum { TTIS_NORMAL = 1, TTIS_HOT = 2, TTIS_SELECTED = 3, TTIS_DISABLED = 4, TTIS_FOCUSED = 5 } enum { TTIBES_NORMAL = 1, TTIBES_HOT = 2, TTIBES_SELECTED = 3, TTIBES_DISABLED = 4, TTIBES_FOCUSED = 5 } enum { TTILES_NORMAL = 1, TTILES_HOT = 2, TTILES_SELECTED = 3, TTILES_DISABLED = 4, TTILES_FOCUSED = 5 } enum { TTIRES_NORMAL = 1, TTIRES_HOT = 2, TTIRES_SELECTED = 3, TTIRES_DISABLED = 4, TTIRES_FOCUSED = 5 } /* TASKBAND parts */ enum { TDP_GROUPCOUNT = 1, TDP_FLASHBUTTON = 2, TDP_FLASHBUTTONGROUPMENU = 3 } /* TASKBAR parts */ enum { TBP_BACKGROUNDBOTTOM = 1, TBP_BACKGROUNDRIGHT = 2, TBP_BACKGROUNDTOP = 3, TBP_BACKGROUNDLEFT = 4, TBP_SIZINGBARBOTTOM = 5, TBP_SIZINGBARRIGHT = 6, TBP_SIZINGBARTOP = 7, TBP_SIZINGBARLEFT = 8 } /* TOOLBAR parts */ enum { TP_BUTTON = 1, TP_DROPDOWNBUTTON = 2, TP_SPLITBUTTON = 3, TP_SPLITBUTTONDROPDOWN = 4, TP_SEPARATOR = 5, TP_SEPARATORVERT = 6 } enum { TS_NORMAL = 1, TS_HOT = 2, TS_PRESSED = 3, TS_DISABLED = 4, TS_CHECKED = 5, TS_HOTCHECKED = 6 } /* TOOLTIP parts */ enum { TTP_STANDARD = 1, TTP_STANDARDTITLE = 2, TTP_BALLOON = 3, TTP_BALLOONTITLE = 4, TTP_CLOSE = 5 } enum { TTBS_NORMAL = 1, TTBS_LINK = 2 } enum { TTCS_NORMAL = 1, TTCS_HOT = 2, TTCS_PRESSED = 3 } enum { TTSS_NORMAL = 1, TTSS_LINK = 2 } /* TRACKBAR parts */ enum { TKP_TRACK = 1, TKP_TRACKVERT = 2, TKP_THUMB = 3, TKP_THUMBBOTTOM = 4, TKP_THUMBTOP = 5, TKP_THUMBVERT = 6, TKP_THUMBLEFT = 7, TKP_THUMBRIGHT = 8, TKP_TICS = 9, TKP_TICSVERT = 10 } enum { TUS_NORMAL = 1, TUS_HOT = 2, TUS_PRESSED = 3, TUS_FOCUSED = 4, TUS_DISABLED = 5 } enum { TUBS_NORMAL = 1, TUBS_HOT = 2, TUBS_PRESSED = 3, TUBS_FOCUSED = 4, TUBS_DISABLED = 5 } enum { TUVLS_NORMAL = 1, TUVLS_HOT = 2, TUVLS_PRESSED = 3, TUVLS_FOCUSED = 4, TUVLS_DISABLED = 5 } enum { TUVRS_NORMAL = 1, TUVRS_HOT = 2, TUVRS_PRESSED = 3, TUVRS_FOCUSED = 4, TUVRS_DISABLED = 5 } enum { TUTS_NORMAL = 1, TUTS_HOT = 2, TUTS_PRESSED = 3, TUTS_FOCUSED = 4, TUTS_DISABLED = 5 } enum { TUVS_NORMAL = 1, TUVS_HOT = 2, TUVS_PRESSED = 3, TUVS_FOCUSED = 4, TUVS_DISABLED = 5 } enum { TSS_NORMAL = 1 } enum { TSVS_NORMAL = 1 } enum { TRS_NORMAL = 1 } enum { TRVS_NORMAL = 1 } /* TRAYNOTIFY parts */ enum { TNP_BACKGROUND = 1, TNP_ANIMBACKGROUND = 2 } /* TREEVIEW parts */ enum { TVP_TREEITEM = 1, TVP_GLYPH = 2, TVP_BRANCH = 3 } enum { GLPS_CLOSED = 1, GLPS_OPENED = 2 } enum { TREIS_NORMAL = 1, TREIS_HOT = 2, TREIS_SELECTED = 3, TREIS_DISABLED = 4, TREIS_SELECTEDNOTFOCUS = 5 } /* WINDOW parts */ enum { WP_CAPTION = 1, WP_SMALLCAPTION = 2, WP_MINCAPTION = 3, WP_SMALLMINCAPTION = 4, WP_MAXCAPTION = 5, WP_SMALLMAXCAPTION = 6, WP_FRAMELEFT = 7, WP_FRAMERIGHT = 8, WP_FRAMEBOTTOM = 9, WP_SMALLFRAMELEFT = 10, WP_SMALLFRAMERIGHT = 11, WP_SMALLFRAMEBOTTOM = 12, WP_SYSBUTTON = 13, WP_MDISYSBUTTON = 14, WP_MINBUTTON = 15, WP_MDIMINBUTTON = 16, WP_MAXBUTTON = 17, WP_CLOSEBUTTON = 18, WP_SMALLCLOSEBUTTON = 19, WP_MDICLOSEBUTTON = 20, WP_RESTOREBUTTON = 21, WP_MDIRESTOREBUTTON = 22, WP_HELPBUTTON = 23, WP_MDIHELPBUTTON = 24, WP_HORZSCROLL = 25, WP_HORZTHUMB = 26, WP_VERTSCROLL = 27, WP_VERTTHUMB = 28, WP_DIALOG = 29, WP_CAPTIONSIZINGTEMPLATE = 30, WP_SMALLCAPTIONSIZINGTEMPLATE = 31, WP_FRAMELEFTSIZINGTEMPLATE = 32, WP_SMALLFRAMELEFTSIZINGTEMPLATE = 33, WP_FRAMERIGHTSIZINGTEMPLATE = 34, WP_SMALLFRAMERIGHTSIZINGTEMPLATE = 35, WP_FRAMEBOTTOMSIZINGTEMPLATE = 36, WP_SMALLFRAMEBOTTOMSIZINGTEMPLATE = 37 } enum { CS_ACTIVE = 1, CS_INACTIVE = 2, CS_DISABLED = 3 } enum { CBS_NORMAL = 1, CBS_HOT = 2, CBS_PUSHED = 3, CBS_DISABLED = 4 } enum { FS_ACTIVE = 1, FS_INACTIVE = 2 } enum { HBS_NORMAL = 1, HBS_HOT = 2, HBS_PUSHED = 3, HBS_DISABLED = 4 } enum { HSS_NORMAL = 1, HSS_HOT = 2, HSS_PUSHED = 3, HSS_DISABLED = 4 } enum { HTS_NORMAL = 1, HTS_HOT = 2, HTS_PUSHED = 3, HTS_DISABLED = 4 } enum { MAXBS_NORMAL = 1, MAXBS_HOT = 2, MAXBS_PUSHED = 3, MAXBS_DISABLED = 4 } enum { MXCS_ACTIVE = 1, MXCS_INACTIVE = 2, MXCS_DISABLED = 3 } enum { MINBS_NORMAL = 1, MINBS_HOT = 2, MINBS_PUSHED = 3, MINBS_DISABLED = 4 } enum { RBS_NORMAL = 1, RBS_HOT = 2, RBS_PUSHED = 3, RBS_DISABLED = 4 } enum { SBS_NORMAL = 1, SBS_HOT = 2, SBS_PUSHED = 3, SBS_DISABLED = 4 } enum { MNCS_ACTIVE = 1, MNCS_INACTIVE = 2, MNCS_DISABLED = 3 } enum { VSS_NORMAL = 1, VSS_HOT = 2, VSS_PUSHED = 3, VSS_DISABLED = 4 } enum { VTS_NORMAL = 1, VTS_HOT = 2, VTS_PUSHED = 3, VTS_DISABLED = 4 } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/comcat.d0000664000175000017500000000434612776214756023134 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_comcat.d) */ module core.sys.windows.comcat; version (Windows): import core.sys.windows.windows, core.sys.windows.ole2; private import core.sys.windows.basetyps, core.sys.windows.cguid, core.sys.windows.objbase, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.wtypes; alias IEnumGUID LPENUMGUID; interface IEnumGUID : IUnknown { HRESULT Next(ULONG, GUID*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(LPENUMGUID*); } alias GUID CATID; alias REFGUID REFCATID; alias GUID_NULL CATID_NULL; alias IsEqualGUID IsEqualCATID; struct CATEGORYINFO { CATID catid; LCID lcid; OLECHAR[128] szDescription; } alias CATEGORYINFO* LPCATEGORYINFO; alias IEnumGUID IEnumCATID; alias LPENUMGUID LPENUMCATID; alias IID_IEnumGUID IID_IEnumCATID; alias IEnumGUID IEnumCLSID; alias LPENUMGUID LPENUMCLSID; alias IID_IEnumGUID IID_IEnumCLSID; interface ICatInformation : IUnknown { HRESULT EnumCategories(LCID, LPENUMCATEGORYINFO*); HRESULT GetCategoryDesc(REFCATID, LCID, PWCHAR*); HRESULT EnumClassesOfCategories(ULONG, CATID*, ULONG, CATID*, LPENUMCLSID*); HRESULT IsClassOfCategories(REFCLSID, ULONG, CATID*, ULONG, CATID*); HRESULT EnumImplCategoriesOfClass(REFCLSID, LPENUMCATID*); HRESULT EnumReqCategoriesOfClass(REFCLSID, LPENUMCATID*); } alias ICatInformation LPCATINFORMATION; interface ICatRegister : IUnknown { HRESULT RegisterCategories(ULONG, CATEGORYINFO*); HRESULT UnRegisterCategories(ULONG, CATID*); HRESULT RegisterClassImplCategories(REFCLSID, ULONG, CATID*); HRESULT UnRegisterClassImplCategories(REFCLSID, ULONG, CATID*); HRESULT RegisterClassReqCategories(REFCLSID, ULONG, CATID*); HRESULT UnRegisterClassReqCategories(REFCLSID, ULONG, CATID*); } alias ICatRegister LPCATREGISTER; interface IEnumCATEGORYINFO : IUnknown { HRESULT Next(ULONG, CATEGORYINFO*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(LPENUMCATEGORYINFO*); } alias IEnumCATEGORYINFO LPENUMCATEGORYINFO; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmbrowsr.d0000664000175000017500000000646312776214756023537 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmbrowsr.d) */ module core.sys.windows.lmbrowsr; version (Windows): private import core.sys.windows.lmcons, core.sys.windows.windef; enum BROWSER_ROLE_PDC = 1; enum BROWSER_ROLE_BDC = 2; struct BROWSER_STATISTICS { LARGE_INTEGER StatisticsStartTime; LARGE_INTEGER NumberOfServerAnnouncements; LARGE_INTEGER NumberOfDomainAnnouncements; ULONG NumberOfElectionPackets; ULONG NumberOfMailslotWrites; ULONG NumberOfGetBrowserServerListRequests; ULONG NumberOfServerEnumerations; ULONG NumberOfDomainEnumerations; ULONG NumberOfOtherEnumerations; ULONG NumberOfMissedServerAnnouncements; ULONG NumberOfMissedMailslotDatagrams; ULONG NumberOfMissedGetBrowserServerListRequests; ULONG NumberOfFailedServerAnnounceAllocations; ULONG NumberOfFailedMailslotAllocations; ULONG NumberOfFailedMailslotReceives; ULONG NumberOfFailedMailslotWrites; ULONG NumberOfFailedMailslotOpens; ULONG NumberOfDuplicateMasterAnnouncements; LARGE_INTEGER NumberOfIllegalDatagrams; } alias BROWSER_STATISTICS* PBROWSER_STATISTICS, LPBROWSER_STATISTICS; struct BROWSER_STATISTICS_100 { LARGE_INTEGER StartTime; LARGE_INTEGER NumberOfServerAnnouncements; LARGE_INTEGER NumberOfDomainAnnouncements; ULONG NumberOfElectionPackets; ULONG NumberOfMailslotWrites; ULONG NumberOfGetBrowserServerListRequests; LARGE_INTEGER NumberOfIllegalDatagrams; } alias BROWSER_STATISTICS_100* PBROWSER_STATISTICS_100; struct BROWSER_STATISTICS_101 { LARGE_INTEGER StartTime; LARGE_INTEGER NumberOfServerAnnouncements; LARGE_INTEGER NumberOfDomainAnnouncements; ULONG NumberOfElectionPackets; ULONG NumberOfMailslotWrites; ULONG NumberOfGetBrowserServerListRequests; LARGE_INTEGER NumberOfIllegalDatagrams; ULONG NumberOfMissedServerAnnouncements; ULONG NumberOfMissedMailslotDatagrams; ULONG NumberOfMissedGetBrowserServerListRequests; ULONG NumberOfFailedServerAnnounceAllocations; ULONG NumberOfFailedMailslotAllocations; ULONG NumberOfFailedMailslotReceives; ULONG NumberOfFailedMailslotWrites; ULONG NumberOfFailedMailslotOpens; ULONG NumberOfDuplicateMasterAnnouncements; } alias BROWSER_STATISTICS_101* PBROWSER_STATISTICS_101; extern (Windows) { NET_API_STATUS I_BrowserServerEnum(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, PBYTE*, DWORD, PDWORD, PDWORD, DWORD, LPCWSTR, PDWORD); NET_API_STATUS I_BrowserServerEnumEx(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, PBYTE*, DWORD, PDWORD, PDWORD, DWORD, LPCWSTR, LPCWSTR); NET_API_STATUS I_BrowserQueryEmulatedDomains(LPWSTR, PBYTE*, PDWORD); NET_API_STATUS I_BrowserQueryOtherDomains(LPCWSTR, PBYTE*, PDWORD, PDWORD); NET_API_STATUS I_BrowserResetNetlogonState(LPCWSTR); NET_API_STATUS I_BrowserSetNetlogonState(LPWSTR, LPWSTR, LPWSTR, DWORD); NET_API_STATUS I_BrowserQueryStatistics(LPCWSTR, LPBROWSER_STATISTICS*); NET_API_STATUS I_BrowserResetStatistics(LPCWSTR); WORD I_BrowserServerEnumForXactsrv(LPCWSTR, LPCWSTR, ULONG, USHORT, PVOID, WORD, DWORD, PDWORD, PDWORD, DWORD, LPCWSTR, LPCWSTR, PWORD); NET_API_STATUS I_BrowserDebugTrace(PWCHAR, PCHAR); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/ntdef.d0000664000175000017500000000426612776214756022767 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_ntdef.d) */ module core.sys.windows.ntdef; version (Windows): private import core.sys.windows.basetsd, core.sys.windows.subauth, core.sys.windows.windef, core.sys.windows.winnt; enum uint OBJ_INHERIT = 0x0002, OBJ_PERMANENT = 0x0010, OBJ_EXCLUSIVE = 0x0020, OBJ_CASE_INSENSITIVE = 0x0040, OBJ_OPENIF = 0x0080, OBJ_OPENLINK = 0x0100, OBJ_VALID_ATTRIBUTES = 0x01F2; void InitializeObjectAttributes(OBJECT_ATTRIBUTES* p, UNICODE_STRING* n, uint a, HANDLE r, void* s) { with (*p) { Length = OBJECT_ATTRIBUTES.sizeof; RootDirectory = r; Attributes = a; ObjectName = n; SecurityDescriptor = s; SecurityQualityOfService = null; } } bool NT_SUCCESS(int x) { return x >= 0; } /* In MinGW, NTSTATUS, UNICODE_STRING, STRING and their associated pointer * type aliases are defined in ntdef.h, ntsecapi.h and subauth.h, each of * which checks that none of the others is already included. */ alias int NTSTATUS; alias int* PNTSTATUS; struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } alias UNICODE_STRING* PUNICODE_STRING; alias const(UNICODE_STRING)* PCUNICODE_STRING; struct STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } alias STRING ANSI_STRING, OEM_STRING; alias STRING* PSTRING, PANSI_STRING, POEM_STRING; alias LARGE_INTEGER PHYSICAL_ADDRESS; alias LARGE_INTEGER* PPHYSICAL_ADDRESS; enum SECTION_INHERIT { ViewShare = 1, ViewUnmap } /* In MinGW, this is defined in ntdef.h and ntsecapi.h, each of which checks * that the other isn't already included. */ struct OBJECT_ATTRIBUTES { ULONG Length = OBJECT_ATTRIBUTES.sizeof; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } alias OBJECT_ATTRIBUTES* POBJECT_ATTRIBUTES; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/custcntl.d0000664000175000017500000000632412776214756023523 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_custcntl.d) */ module core.sys.windows.custcntl; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.windef; // FIXME: check type enum CCF_NOTEXT = 1; enum size_t CCHCCCLASS = 32, CCHCCDESC = 32, CCHCCTEXT = 256; struct CCSTYLEA { DWORD flStyle; DWORD flExtStyle; CHAR[CCHCCTEXT] szText; LANGID lgid; WORD wReserved1; } alias CCSTYLEA* LPCCSTYLEA; struct CCSTYLEW { DWORD flStyle; DWORD flExtStyle; WCHAR[CCHCCTEXT] szText; LANGID lgid; WORD wReserved1; } alias CCSTYLEW* LPCCSTYLEW; struct CCSTYLEFLAGA { DWORD flStyle; DWORD flStyleMask; LPSTR pszStyle; } alias CCSTYLEFLAGA* LPCCSTYLEFLAGA; struct CCSTYLEFLAGW { DWORD flStyle; DWORD flStyleMask; LPWSTR pszStyle; } alias CCSTYLEFLAGW* LPCCSTYLEFLAGW; struct CCINFOA { CHAR[CCHCCCLASS] szClass; DWORD flOptions; CHAR[CCHCCDESC] szDesc; UINT cxDefault; UINT cyDefault; DWORD flStyleDefault; DWORD flExtStyleDefault; DWORD flCtrlTypeMask; CHAR[CCHCCTEXT] szTextDefault; INT cStyleFlags; LPCCSTYLEFLAGA aStyleFlags; LPFNCCSTYLEA lpfnStyle; LPFNCCSIZETOTEXTA lpfnSizeToText; DWORD dwReserved1; DWORD dwReserved2; } alias CCINFOA* LPCCINFOA; struct CCINFOW { WCHAR[CCHCCCLASS] szClass; DWORD flOptions; WCHAR[CCHCCDESC] szDesc; UINT cxDefault; UINT cyDefault; DWORD flStyleDefault; DWORD flExtStyleDefault; DWORD flCtrlTypeMask; WCHAR[CCHCCTEXT] szTextDefault; INT cStyleFlags; LPCCSTYLEFLAGW aStyleFlags; LPFNCCSTYLEW lpfnStyle; LPFNCCSIZETOTEXTW lpfnSizeToText; DWORD dwReserved1; DWORD dwReserved2; } alias CCINFOW* LPCCINFOW; extern (Windows) { alias BOOL function(HWND, LPCCSTYLEA) LPFNCCSTYLEA; alias BOOL function(HWND, LPCCSTYLEW) LPFNCCSTYLEW; alias INT function(DWORD, DWORD, HFONT, LPSTR) LPFNCCSIZETOTEXTA; alias INT function(DWORD, DWORD, HFONT, LPWSTR) LPFNCCSIZETOTEXTW; alias UINT function(LPCCINFOA) LPFNCCINFOA; alias UINT function(LPCCINFOW) LPFNCCINFOW; UINT CustomControlInfoA(LPCCINFOA acci); UINT CustomControlInfoW(LPCCINFOW acci); } version (Unicode) { alias CCSTYLEW CCSTYLE; alias CCSTYLEFLAGW CCSTYLEFLAG; alias CCINFOW CCINFO; alias LPFNCCSTYLEW LPFNCCSTYLE; alias LPFNCCSIZETOTEXTW LPFNCCSIZETOTEXT; alias LPFNCCINFOW LPFNCCINFO; } else { alias CCSTYLEA CCSTYLE; alias CCSTYLEFLAGA CCSTYLEFLAG; alias CCINFOA CCINFO; alias LPFNCCSTYLEA LPFNCCSTYLE; alias LPFNCCSIZETOTEXTA LPFNCCSIZETOTEXT; alias LPFNCCINFOA LPFNCCINFO; } alias CCSTYLE* LPCCSTYLE; alias CCSTYLEFLAG* LPCCSTYLEFLAG; alias CCINFO* LPCCINFO; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/nb30.d0000664000175000017500000001247112776214756022426 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_nb30.d) */ module core.sys.windows.nb30; version (Windows): private import core.sys.windows.windef; enum size_t NCBNAMSZ = 16, MAX_LANA = 254; // FIXME: are these really two sets of constants? enum : UCHAR { REGISTERING = 0, REGISTERED = 4, DEREGISTERED, DUPLICATE, DUPLICATE_DEREG, // = 7 UNIQUE_NAME = 0, GROUP_NAME = 0x80, NAME_FLAGS_MASK = 0x87 } enum : UCHAR { LISTEN_OUTSTANDING = 1, CALL_PENDING, SESSION_ESTABLISHED, HANGUP_PENDING, HANGUP_COMPLETE, SESSION_ABORTED // = 6 } enum char[4] ALL_TRANSPORTS = "M\0\0\0", MS_NBF = "MNBF"; enum : UCHAR { NCBCALL = 0x10, NCBLISTEN, NCBHANGUP, // = 0x12 NCBSEND = 0x14, NCBRECV, NCBRECVANY, NCBCHAINSEND, // = 0x17 NCBDGSEND = 0x20, NCBDGRECV, NCBDGSENDBC, NCBDGRECVBC, // = 0x23, NCBADDNAME = 0x30, NCBDELNAME, NCBRESET, NCBASTAT, NCBSSTAT, NCBCANCEL, NCBADDGRNAME, NCBENUM, // = 0x37 NCBUNLINK = 0x70, NCBSENDNA, NCBCHAINSENDNA, NCBLANSTALERT, // = 0x73 NCBACTION = 0x77, NCBFINDNAME, NCBTRACE // = 0x79 } enum UCHAR ASYNCH = 0x80; enum : UCHAR { NRC_GOODRET = 0x00, NRC_BUFLEN = 0x01, NRC_ILLCMD = 0x03, NRC_CMDTMO = 0x05, NRC_INCOMP, NRC_BADDR, NRC_SNUMOUT, NRC_NORES, NRC_SCLOSED, NRC_CMDCAN, // = 0x0b NRC_DUPNAME = 0x0d, NRC_NAMTFUL, NRC_ACTSES, // = 0x0f, NRC_LOCTFUL = 0x11, NRC_REMTFUL, NRC_ILLNN, NRC_NOCALL, NRC_NOWILD, NRC_INUSE, NRC_NAMERR, NRC_SABORT, NRC_NAMCONF, // = 0x19 NRC_IFBUSY = 0x21, NRC_TOOMANY, NRC_BRIDGE, NRC_CANOCCR, // = 0x24 NRC_CANCEL = 0x26, NRC_DUPENV = 0x30, NRC_ENVNOTDEF = 0x34, NRC_OSRESNOTAV, NRC_MAXAPPS, NRC_NOSAPS, NRC_NORESOURCES, NRC_INVADDRESS, // = 0x39 NRC_INVDDID = 0x3B, NRC_LOCKFAIL = 0x3C, NRC_OPENERR = 0x3f, NRC_SYSTEM = 0x40, NRC_PENDING = 0xff } struct ACTION_HEADER { union { /* transport_id is defined as a ULONG, but both the above constants * and the documented description suggest it should be a char[4] */ ULONG transport_id; char[4] c_transport_id; } USHORT action_code; USHORT reserved; } alias ACTION_HEADER* PACTION_HEADER; struct ADAPTER_STATUS { UCHAR[6] adapter_address; UCHAR rev_major; UCHAR reserved0; UCHAR adapter_type; UCHAR rev_minor; WORD duration; WORD frmr_recv; WORD frmr_xmit; WORD iframe_recv_err; WORD xmit_aborts; DWORD xmit_success; DWORD recv_success; WORD iframe_xmit_err; WORD recv_buff_unavail; WORD t1_timeouts; WORD ti_timeouts; DWORD reserved1; WORD free_ncbs; WORD max_cfg_ncbs; WORD max_ncbs; WORD xmit_buf_unavail; WORD max_dgram_size; WORD pending_sess; WORD max_cfg_sess; WORD max_sess; WORD max_sess_pkt_size; WORD name_count; } alias ADAPTER_STATUS* PADAPTER_STATUS; struct FIND_NAME_BUFFER { /* From Win32 API docs * * length * Specifies the length, in bytes, of the FIND_NAME_BUFFER * structure. Although this structure always occupies 33 bytes, * not all of the structure is necessarily valid. * * On this basis, should length be initialised? */ UCHAR length; UCHAR access_control; UCHAR frame_control; UCHAR[6] destination_addr; UCHAR[6] source_addr; UCHAR[18] routing_info; } alias FIND_NAME_BUFFER* PFIND_NAME_BUFFER; struct FIND_NAME_HEADER { WORD node_count; UCHAR reserved; UCHAR unique_group; } alias FIND_NAME_HEADER* PFIND_NAME_HEADER; struct LANA_ENUM { UCHAR length; UCHAR[MAX_LANA+1] lana; } alias LANA_ENUM* PLANA_ENUM; struct NAME_BUFFER { UCHAR[NCBNAMSZ] name; UCHAR name_num; UCHAR name_flags; } alias NAME_BUFFER* PNAME_BUFFER; struct NCB { UCHAR ncb_command; UCHAR ncb_retcode; UCHAR ncb_lsn; UCHAR ncb_num; PUCHAR ncb_buffer; WORD ncb_length; UCHAR[NCBNAMSZ] ncb_callname; UCHAR[NCBNAMSZ] ncb_name; UCHAR ncb_rto; UCHAR ncb_sto; extern (Windows) void function(NCB*) ncb_post; UCHAR ncb_lana_num; UCHAR ncb_cmd_cplt; UCHAR[10] ncb_reserve; HANDLE ncb_event; } alias NCB* PNCB; struct SESSION_BUFFER { UCHAR lsn; UCHAR state; UCHAR[NCBNAMSZ] local_name; UCHAR[NCBNAMSZ] remote_name; UCHAR rcvs_outstanding; UCHAR sends_outstanding; } alias SESSION_BUFFER* PSESSION_BUFFER; struct SESSION_HEADER { UCHAR sess_name; UCHAR num_sess; UCHAR rcv_dg_outstanding; UCHAR rcv_any_outstanding; } alias SESSION_HEADER* PSESSION_HEADER; extern (Windows) UCHAR Netbios(PNCB); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmmsg.d0000664000175000017500000000236712776214756023006 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmmsg.d) */ module core.sys.windows.lmmsg; version (Windows): pragma(lib, "netapi32"); private import core.sys.windows.lmcons, core.sys.windows.windef, core.sys.windows.w32api; static assert (_WIN32_WINNT >= 0x501, "core.sys.windows.lmmsg is available only if version WindowsXP, Windows2003 " "or WindowsVista is set"); enum MSGNAME_NOT_FORWARDED = 0; enum MSGNAME_FORWARDED_TO = 4; enum MSGNAME_FORWARDED_FROM = 16; struct MSG_INFO_0 { LPWSTR msgi0_name; } alias MSG_INFO_0* PMSG_INFO_0, LPMSG_INFO_0; struct MSG_INFO_1 { LPWSTR msgi1_name; DWORD msgi1_forward_flag; LPWSTR msgi1_forward; } alias MSG_INFO_1* PMSG_INFO_1, LPMSG_INFO_1; extern (Windows) { NET_API_STATUS NetMessageBufferSend(LPCWSTR, LPCWSTR, LPCWSTR, PBYTE, DWORD); NET_API_STATUS NetMessageNameAdd(LPCWSTR, LPCWSTR); NET_API_STATUS NetMessageNameDel(LPCWSTR, LPCWSTR); NET_API_STATUS NetMessageNameEnum(LPCWSTR, DWORD, PBYTE*, DWORD, PDWORD, PDWORD, PDWORD); NET_API_STATUS NetMessageNameGetInfo(LPCWSTR, LPCWSTR, DWORD, PBYTE*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmconfig.d0000664000175000017500000000146112776214756023457 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmconfig.d) */ module core.sys.windows.lmconfig; version (Windows): // All functions in this file are deprecated! private import core.sys.windows.lmcons, core.sys.windows.windef; deprecated { struct CONFIG_INFO_0 { LPWSTR cfgi0_key; LPWSTR cfgi0_data; } alias CONFIG_INFO_0* PCONFIG_INFO_0, LPCONFIG_INFO_0; extern (Windows) { NET_API_STATUS NetConfigGet(LPCWSTR, LPCWSTR, LPCWSTR, PBYTE*); NET_API_STATUS NetConfigGetAll(LPCWSTR, LPCWSTR, PBYTE*); NET_API_STATUS NetConfigSet(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, DWORD, PBYTE, DWORD); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/oleauto.d0000664000175000017500000006537612776214756023350 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_oleauto.d) */ module core.sys.windows.oleauto; version (Windows): pragma(lib, "oleaut32"); import core.sys.windows.oaidl; private import core.sys.windows.basetyps, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.wtypes; private import core.sys.windows.winbase; // for SYSTEMTIME align(8): enum STDOLE_MAJORVERNUM = 1; enum STDOLE_MINORVERNUM = 0; enum STDOLE_LCID = 0; enum VARIANT_NOVALUEPROP = 0x01; enum VARIANT_ALPHABOOL = 0x02; enum VARIANT_NOUSEOVERRIDE = 0x04; enum VARIANT_LOCALBOOL = 0x08; enum VAR_TIMEVALUEONLY = 0x0001; enum VAR_DATEVALUEONLY = 0x0002; enum VAR_VALIDDATE = 0x0004; enum VAR_CALENDAR_HIJRI = 0x0008; enum VAR_LOCALBOOL = 0x0010; enum VAR_FORMAT_NOSUBSTITUTE = 0x0020; enum VAR_FOURDIGITYEARS = 0x0040; enum VAR_CALENDAR_THAI = 0x0080; enum VAR_CALENDAR_GREGORIAN = 0x0100; enum MEMBERID_NIL = DISPID_UNKNOWN; enum ID_DEFAULTINST = -2; enum DISPATCH_METHOD = 1; enum DISPATCH_PROPERTYGET = 2; enum DISPATCH_PROPERTYPUT = 4; enum DISPATCH_PROPERTYPUTREF = 8; //ULONG LHashValOfName(LCID l, OLECHAR* n) { return LHashValOfNameSys(SYSKIND.SYS_WIN32, l, n); } // DAC: These aren't in the 2003 SDK. //MACRO #define WHashValOfLHashVal(h) ((unsigned short)(0x0000ffff&(h))) //MACRO #define IsHashValCompatible(h1, h2) ((BOOL)((0x00ff0000&(h1))==(0x00ff0000&(h2)))) enum { ACTIVEOBJECT_STRONG = 0, ACTIVEOBJECT_WEAK = 1 } // DAC: These seem to be irrelevant for D. //#define V_UNION(X, Y) ((X)->Y) //#define V_VT(X) ((X)->vt) //#define V_BOOL(X) V_UNION(X, boolVal) //#define V_ISBYREF(X) (V_VT(X)&VT_BYREF) //#define V_ISARRAY(X) (V_VT(X)&VT_ARRAY) //#define V_ISVECTOR(X) (V_VT(X)&VT_VECTOR) //#define V_NONE(X) V_I2(X) //#define V_UI1(X) V_UNION(X, bVal) //#define V_UI1REF(X) V_UNION(X, pbVal) //#define V_I2(X) V_UNION(X, iVal) //#define V_UI2(X) V_UNION(X, uiVal) //#define V_I2REF(X) V_UNION(X, piVal) //#define V_I4(X) V_UNION(X, lVal) //#define V_UI4(X) V_UNION(X, ulVal) //#define V_I4REF(X) V_UNION(X, plVal) //#define V_UI4REF(X) V_UNION(X, pulVal) //#define V_I8(X) V_UNION(X, llVal) //#define V_UI8(X) V_UNION(X, ullVal) //#define V_I8REF(X) V_UNION(X, pllVal) //#define V_UI8REF(X) V_UNION(X, pullVal) //#define V_R4(X) V_UNION(X, fltVal) //#define V_R4REF(X) V_UNION(X, pfltVal) //#define V_R8(X) V_UNION(X, dblVal) //#define V_R8REF(X) V_UNION(X, pdblVal) //#define V_CY(X) V_UNION(X, cyVal) //#define V_CYREF(X) V_UNION(X, pcyVal) //#define V_DATE(X) V_UNION(X, date) //#define V_DATEREF(X) V_UNION(X, pdate) //#define V_BSTR(X) V_UNION(X, bstrVal) //#define V_BSTRREF(X) V_UNION(X, pbstrVal) //#define V_DISPATCH(X) V_UNION(X, pdispVal) //#define V_DISPATCHREF(X) V_UNION(X, ppdispVal) //#define V_ERROR(X) V_UNION(X, scode) //#define V_ERRORREF(X) V_UNION(X, pscode) //#define V_BOOLREF(X) V_UNION(X, pboolVal) //#define V_UNKNOWN(X) V_UNION(X, punkVal) //#define V_UNKNOWNREF(X) V_UNION(X, ppunkVal) //#define V_VARIANTREF(X) V_UNION(X, pvarVal) //#define V_LPSTR(X) V_UNION(X, pszVal) //#define V_LPSTRREF(X) V_UNION(X, ppszVal) //#define V_LPWSTR(X) V_UNION(X, pwszVal) //#define V_LPWSTRREF(X) V_UNION(X, ppwszVal) //#define V_FILETIME(X) V_UNION(X, filetime) //#define V_FILETIMEREF(X) V_UNION(X, pfiletime) //#define V_BLOB(X) V_UNION(X, blob) //#define V_UUID(X) V_UNION(X, puuid) //#define V_CLSID(X) V_UNION(X, puuid) //#define V_ARRAY(X) V_UNION(X, parray) //#define V_ARRAYREF(X) V_UNION(X, pparray) //#define V_BYREF(X) V_UNION(X, byref) //#define V_DECIMAL(X) ((X)->decVal) //#define V_DECIMALREF(X) V_UNION(X, pdecVal) //#define V_I1(X) V_UNION(X, cVal) //#ifdef _WIN64 //#define V_INT_PTR(X) V_I8(X) //#define V_UINT_PTR(X) V_UI8(X) //#define V_INT_PTRREF(X) V_I8REF(X) //#define V_UINT_PTRREF(X) V_UI8REF(X) //#else //#define V_INT_PTR(X) V_I4(X) //#define V_UINT_PTR(X) V_UI4(X) //#define V_INT_PTRREF(X) V_I4REF(X) //#define V_UINT_PTRREF(X) V_UI4REF(X) //#endif enum { VARCMP_LT = 0, VARCMP_EQ, VARCMP_GT, VARCMP_NULL // = 3 } enum LOCALE_USE_NLS = 0x10000000; enum VARIANT_NOUSEROVERRIDE = 0x04; enum VARIANT_CALENDAR_HIJRI = 0x08; enum VARIANT_CALENDAR_THAI = 0x20; enum VARIANT_CALENDAR_GREGORIAN = 0x40; enum VARIANT_USE_NLS = 0x80; enum NUMPRS_LEADING_WHITE = 0x00001; enum NUMPRS_TRAILING_WHITE = 0x00002; enum NUMPRS_LEADING_PLUS = 0x00004; enum NUMPRS_TRAILING_PLUS = 0x00008; enum NUMPRS_LEADING_MINUS = 0x00010; enum NUMPRS_TRAILING_MINUS = 0x00020; enum NUMPRS_HEX_OCT = 0x00040; enum NUMPRS_PARENS = 0x00080; enum NUMPRS_DECIMAL = 0x00100; enum NUMPRS_THOUSANDS = 0x00200; enum NUMPRS_CURRENCY = 0x00400; enum NUMPRS_EXPONENT = 0x00800; enum NUMPRS_USE_ALL = 0x01000; enum NUMPRS_STD = 0x01FFF; enum NUMPRS_NEG = 0x10000; enum NUMPRS_INEXACT = 0x20000; enum VTBIT_I1 = 1 << VARENUM.VT_I1; enum VTBIT_UI1 = 1 << VARENUM.VT_UI1; enum VTBIT_I2 = 1 << VARENUM.VT_I2; enum VTBIT_UI2 = 1 << VARENUM.VT_UI2; enum VTBIT_I4 = 1 << VARENUM.VT_I4; enum VTBIT_UI4 = 1 << VARENUM.VT_UI4; enum VTBIT_I8 = 1 << VARENUM.VT_I8; enum VTBIT_UI8 = 1 << VARENUM.VT_UI8; enum VTBIT_R4 = 1 << VARENUM.VT_R4; enum VTBIT_R8 = 1 << VARENUM.VT_R8; enum VTBIT_CY = 1 << VARENUM.VT_CY; enum VTBIT_DECIMAL = 1 << VARENUM.VT_DECIMAL; enum REGKIND{ REGKIND_DEFAULT, REGKIND_REGISTER, REGKIND_NONE } struct PARAMDATA{ OLECHAR* szName; VARTYPE vt; } alias PARAMDATA* LPPARAMDATA; struct METHODDATA{ OLECHAR* szName; PARAMDATA* ppdata; DISPID dispid; UINT iMeth; CALLCONV cc; UINT cArgs; WORD wFlags; VARTYPE vtReturn; } alias METHODDATA* LPMETHODDATA; struct INTERFACEDATA{ METHODDATA* pmethdata; UINT cMembers; } alias INTERFACEDATA* LPINTERFACEDATA; struct UDATE { SYSTEMTIME st; USHORT wDayOfYear; } struct NUMPARSE { int cDig; uint dwInFlags; uint dwOutFlags; int cchUsed; int nBaseShift; int nPwr10; } // DAC: In MinGW, these were declared but not defined in oaidl. // The SDK docs suggest they belong in this file instead. deprecated { // not actually deprecated, but they aren't converted yet. // (will need to reinstate CreateTypeLib as well) interface ICreateTypeInfo {}; interface ICreateTypeInfo2 {}; interface ICreateTypeLib {}; interface ICreateTypeLib2 {}; alias ICreateTypeInfo LPCREATETYPEINFO; alias ICreateTypeInfo2 LPCREATETYPEINFO2; alias ICreateTypeLib LPCREATETYPELIB; alias ICreateTypeLib2 LPCREATETYPELIB2; } extern (Windows) { BSTR SysAllocString(const(OLECHAR)*); int SysReAllocString(BSTR*, const(OLECHAR)*); BSTR SysAllocStringLen(const(OLECHAR)*, uint); int SysReAllocStringLen(BSTR*, const(OLECHAR)*, uint); void SysFreeString(BSTR); uint SysStringLen(BSTR); uint SysStringByteLen(BSTR); BSTR SysAllocStringByteLen(const(char)*, uint); int DosDateTimeToVariantTime(ushort, ushort, double*); int VariantTimeToDosDateTime(double, ushort*, ushort*); int VariantTimeToSystemTime(double, LPSYSTEMTIME); int SystemTimeToVariantTime(LPSYSTEMTIME, double*); HRESULT VarDateFromUdate(UDATE*, ULONG, DATE*); HRESULT VarDateFromUdateEx(UDATE*, LCID, ULONG, DATE*); HRESULT VarUdateFromDate(DATE, ULONG, UDATE*); HRESULT SafeArrayAllocDescriptor(uint, SAFEARRAY**); HRESULT SafeArrayAllocData(SAFEARRAY*); SAFEARRAY* SafeArrayCreate(VARTYPE, uint, SAFEARRAYBOUND*); HRESULT SafeArrayDestroyDescriptor(SAFEARRAY*); HRESULT SafeArrayDestroyData(SAFEARRAY*); HRESULT SafeArrayDestroy(SAFEARRAY*); HRESULT SafeArrayRedim(SAFEARRAY*, SAFEARRAYBOUND*); uint SafeArrayGetDim(SAFEARRAY*); uint SafeArrayGetElemsize(SAFEARRAY*); HRESULT SafeArrayGetUBound(SAFEARRAY*, uint, int*); HRESULT SafeArrayGetLBound(SAFEARRAY*, uint, int*); HRESULT SafeArrayLock(SAFEARRAY*); HRESULT SafeArrayUnlock(SAFEARRAY*); HRESULT SafeArrayAccessData(SAFEARRAY*, void**); HRESULT SafeArrayUnaccessData(SAFEARRAY*); HRESULT SafeArrayGetElement(SAFEARRAY*, int*, void*); HRESULT SafeArrayPutElement(SAFEARRAY*, int*, void*); HRESULT SafeArrayCopy(SAFEARRAY*, SAFEARRAY**); HRESULT SafeArrayPtrOfIndex(SAFEARRAY*, int*, void**); SAFEARRAY* SafeArrayCreateVector(VARTYPE, LONG, ULONG); SAFEARRAY* SafeArrayCreateVectorEx(VARTYPE, LONG, ULONG, LPVOID); HRESULT SafeArrayAllocDescriptorEx(VARTYPE, UINT, SAFEARRAY**); HRESULT SafeArrayGetVartype(SAFEARRAY*, VARTYPE*); HRESULT SafeArraySetRecordInfo(SAFEARRAY*, IRecordInfo); HRESULT SafeArrayGetRecordInfo(SAFEARRAY*, IRecordInfo*); HRESULT SafeArraySetIID(SAFEARRAY*, REFGUID); HRESULT SafeArrayGetIID(SAFEARRAY*, GUID*); void VariantInit(VARIANTARG*); HRESULT VariantClear(VARIANTARG*); HRESULT VariantCopy(VARIANTARG*, VARIANTARG*); HRESULT VariantCopyInd(VARIANT*, VARIANTARG*); HRESULT VariantChangeType(VARIANTARG*, VARIANTARG*, ushort, VARTYPE); HRESULT VariantChangeTypeEx(VARIANTARG*, VARIANTARG*, LCID, ushort, VARTYPE); HRESULT VarUI1FromI2(short, ubyte*); HRESULT VarUI1FromI4(int, ubyte*); HRESULT VarUI1FromR4(float, ubyte*); HRESULT VarUI1FromR8(double, ubyte*); HRESULT VarUI1FromCy(CY, ubyte*); HRESULT VarUI1FromDate(DATE, ubyte*); HRESULT VarUI1FromStr(OLECHAR*, LCID, uint, ubyte*); HRESULT VarUI1FromDisp(LPDISPATCH, LCID, ubyte*); HRESULT VarUI1FromBool(VARIANT_BOOL, ubyte*); HRESULT VarI2FromUI1(ubyte, short*); HRESULT VarI2FromI4(int, short*); HRESULT VarI2FromR4(float, short*); HRESULT VarI2FromR8(double, short*); HRESULT VarI2FromCy(CY cyIn, short*); HRESULT VarI2FromDate(DATE, short*); HRESULT VarI2FromStr(OLECHAR*, LCID, uint, short*); HRESULT VarI2FromDisp(LPDISPATCH, LCID, short*); HRESULT VarI2FromBool(VARIANT_BOOL, short*); HRESULT VarI4FromUI1(ubyte, int*); HRESULT VarI4FromI2(short, int*); HRESULT VarI4FromR4(float, int*); HRESULT VarI4FromR8(double, int*); HRESULT VarI4FromCy(CY, int*); HRESULT VarI4FromDate(DATE, int*); HRESULT VarI4FromStr(OLECHAR*, LCID, uint, int*); HRESULT VarI4FromDisp(LPDISPATCH, LCID, int*); HRESULT VarI4FromBool(VARIANT_BOOL, int*); HRESULT VarR4FromUI1(ubyte, float*); HRESULT VarR4FromI2(short, float*); HRESULT VarR4FromI4(int, float*); HRESULT VarR4FromR8(double, float*); HRESULT VarR4FromCy(CY, float*); HRESULT VarR4FromDate(DATE, float*); HRESULT VarR4FromStr(OLECHAR*, LCID, uint, float*); HRESULT VarR4FromDisp(LPDISPATCH, LCID, float*); HRESULT VarR4FromBool(VARIANT_BOOL, float*); HRESULT VarR8FromUI1(ubyte, double*); HRESULT VarR8FromI2(short, double*); HRESULT VarR8FromI4(int, double*); HRESULT VarR8FromR4(float, double*); HRESULT VarR8FromCy(CY, double*); HRESULT VarR8FromDate(DATE, double*); HRESULT VarR8FromStr(OLECHAR*, LCID, uint, double*); HRESULT VarR8FromDisp(LPDISPATCH, LCID, double*); HRESULT VarR8FromBool(VARIANT_BOOL, double*); HRESULT VarR8FromDec(DECIMAL*, double*); HRESULT VarDateFromUI1(ubyte, DATE*); HRESULT VarDateFromI2(short, DATE*); HRESULT VarDateFromI4(int, DATE*); HRESULT VarDateFromR4(float, DATE*); HRESULT VarDateFromR8(double, DATE*); HRESULT VarDateFromCy(CY, DATE*); HRESULT VarDateFromStr(OLECHAR*, LCID, uint, DATE*); HRESULT VarDateFromDisp(LPDISPATCH, LCID, DATE*); HRESULT VarDateFromBool(VARIANT_BOOL, DATE*); HRESULT VarCyFromUI1(ubyte, CY*); HRESULT VarCyFromI2(short, CY*); HRESULT VarCyFromI4(int, CY*); HRESULT VarCyFromR4(float, CY*); HRESULT VarCyFromR8(double, CY*); HRESULT VarCyFromDate(DATE, CY*); HRESULT VarCyFromStr(OLECHAR*, LCID, uint, CY*); HRESULT VarCyFromDisp(LPDISPATCH, LCID, CY*); HRESULT VarCyFromBool(VARIANT_BOOL, CY*); HRESULT VarBstrFromUI1(ubyte, LCID, uint, BSTR*); HRESULT VarBstrFromI2(short, LCID, uint, BSTR*); HRESULT VarBstrFromI4(int, LCID, uint, BSTR*); HRESULT VarBstrFromR4(float, LCID, uint, BSTR*); HRESULT VarBstrFromR8(double, LCID, uint, BSTR*); HRESULT VarBstrFromCy(CY, LCID, uint, BSTR*); HRESULT VarBstrFromDate(DATE, LCID, uint, BSTR*); HRESULT VarBstrFromDisp(LPDISPATCH, LCID, uint, BSTR*); HRESULT VarBstrFromBool(VARIANT_BOOL, LCID, uint, BSTR*); HRESULT VarBoolFromUI1(ubyte, VARIANT_BOOL*); HRESULT VarBoolFromI2(short, VARIANT_BOOL*); HRESULT VarBoolFromI4(int, VARIANT_BOOL*); HRESULT VarBoolFromR4(float, VARIANT_BOOL*); HRESULT VarBoolFromR8(double, VARIANT_BOOL*); HRESULT VarBoolFromDate(DATE, VARIANT_BOOL*); HRESULT VarBoolFromCy(CY, VARIANT_BOOL*); HRESULT VarBoolFromStr(OLECHAR*, LCID, uint, VARIANT_BOOL*); HRESULT VarBoolFromDisp(LPDISPATCH, LCID, VARIANT_BOOL*); HRESULT VarDecFromR8(double, DECIMAL*); ULONG LHashValOfNameSysA(SYSKIND, LCID, const(char)*); ULONG LHashValOfNameSys(SYSKIND, LCID, const(OLECHAR)*); HRESULT LoadTypeLib(const(OLECHAR)*, LPTYPELIB*); HRESULT LoadTypeLibEx(LPCOLESTR, REGKIND, LPTYPELIB*); HRESULT LoadRegTypeLib(REFGUID, WORD, WORD, LCID, LPTYPELIB*); HRESULT QueryPathOfRegTypeLib(REFGUID, ushort, ushort, LCID, LPBSTR); HRESULT RegisterTypeLib(LPTYPELIB, OLECHAR*, OLECHAR*); HRESULT UnRegisterTypeLib(REFGUID, WORD, WORD, LCID, SYSKIND); // not actually deprecated, but depends on unconverted ICreateTypeLib deprecated HRESULT CreateTypeLib(SYSKIND, const(OLECHAR)*, LPCREATETYPELIB*); HRESULT DispGetParam(DISPPARAMS*, UINT, VARTYPE, VARIANT*, UINT*); HRESULT DispGetIDsOfNames(LPTYPEINFO, OLECHAR**, UINT, DISPID*); HRESULT DispInvoke(void*, LPTYPEINFO, DISPID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*); HRESULT CreateDispTypeInfo(INTERFACEDATA*, LCID, LPTYPEINFO*); HRESULT CreateStdDispatch(IUnknown, void*, LPTYPEINFO, IUnknown*); HRESULT RegisterActiveObject(IUnknown, REFCLSID, DWORD, DWORD*); HRESULT RevokeActiveObject(DWORD, void*); HRESULT GetActiveObject(REFCLSID, void*, IUnknown*); HRESULT SetErrorInfo(uint, LPERRORINFO); HRESULT GetErrorInfo(uint, LPERRORINFO*); HRESULT CreateErrorInfo(LPCREATEERRORINFO*); uint OaBuildVersion(); HRESULT VectorFromBstr (BSTR, SAFEARRAY**); HRESULT BstrFromVector (SAFEARRAY*, BSTR*); HRESULT VarParseNumFromStr(OLECHAR*, LCID, ULONG, NUMPARSE*, BYTE*); HRESULT VarNumFromParseNum(NUMPARSE*, BYTE*, ULONG, VARIANT*); HRESULT VarAdd(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarSub(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarMul(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarDiv(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarUI1FromI2(SHORT, BYTE*); HRESULT VarUI1FromI4(LONG, BYTE*); HRESULT VarUI1FromI8(LONG64, BYTE*); HRESULT VarUI1FromR4(FLOAT, BYTE*); HRESULT VarUI1FromR8(DOUBLE, BYTE*); HRESULT VarUI1FromDate(DATE, BYTE*); HRESULT VarUI1FromBool(VARIANT_BOOL, BYTE*); HRESULT VarUI1FromI1(byte, BYTE*); HRESULT VarUI1FromUI2(USHORT, BYTE*); HRESULT VarUI1FromUI4(ULONG, BYTE*); HRESULT VarUI1FromUI8(ULONG64, BYTE*); HRESULT VarUI1FromStr(OLECHAR*, LCID, ULONG, BYTE*); HRESULT VarUI1FromCy(CY, BYTE*); HRESULT VarUI1FromDec(DECIMAL*, BYTE*); HRESULT VarUI1FromDisp(IDispatch, LCID, BYTE*); HRESULT VarI2FromUI1(BYTE, SHORT*); HRESULT VarI2FromI4(LONG, SHORT*); HRESULT VarI2FromI8(LONG64, SHORT*); HRESULT VarI2FromR4(FLOAT, SHORT*); HRESULT VarI2FromR8(DOUBLE, SHORT*); HRESULT VarI2FromDate(DATE, SHORT*); HRESULT VarI2FromBool(VARIANT_BOOL, SHORT*); HRESULT VarI2FromI1(byte, SHORT*); HRESULT VarI2FromUI2(USHORT, SHORT*); HRESULT VarI2FromUI4(ULONG, SHORT*); HRESULT VarI2FromUI8(ULONG64, SHORT*); HRESULT VarI2FromStr(OLECHAR*, LCID, ULONG, SHORT*); HRESULT VarI2FromCy(CY, SHORT*); HRESULT VarI2FromDec(DECIMAL*, SHORT*); HRESULT VarI2FromDisp(IDispatch, LCID, SHORT*); HRESULT VarI4FromUI1(BYTE, LONG*); HRESULT VarI4FromI2(SHORT, LONG*); HRESULT VarI4FromI8(LONG64, LONG*); HRESULT VarI4FromR4(FLOAT, LONG*); HRESULT VarI4FromR8(DOUBLE, LONG*); HRESULT VarI4FromDate(DATE, LONG*); HRESULT VarI4FromBool(VARIANT_BOOL, LONG*); HRESULT VarI4FromI1(byte, LONG*); HRESULT VarI4FromUI2(USHORT, LONG*); HRESULT VarI4FromUI4(ULONG, LONG*); HRESULT VarI4FromUI8(ULONG64, LONG*); HRESULT VarI4FromStr(OLECHAR*, LCID, ULONG, LONG*); HRESULT VarI4FromCy(CY, LONG*); HRESULT VarI4FromDec(DECIMAL*, LONG*); HRESULT VarI4FromDisp(IDispatch, LCID, LONG*); HRESULT VarI8FromUI1(BYTE, LONG64*); HRESULT VarI8FromI2(SHORT, LONG64*); HRESULT VarI8FromI4(LONG, LONG64*); HRESULT VarI8FromR4(FLOAT, LONG64*); HRESULT VarI8FromR8(DOUBLE, LONG64*); HRESULT VarI8FromDate(DATE, LONG64*); HRESULT VarI8FromStr(OLECHAR*, LCID, ULONG, LONG64*); HRESULT VarI8FromBool(VARIANT_BOOL, LONG64*); HRESULT VarI8FromI1(byte, LONG64*); HRESULT VarI8FromUI2(USHORT, LONG64*); HRESULT VarI8FromUI4(ULONG, LONG64*); HRESULT VarI8FromUI8(ULONG64, LONG64*); HRESULT VarI8FromDec(DECIMAL* pdecIn, LONG64*); HRESULT VarI8FromInt(INT intIn, LONG64*); HRESULT VarI8FromCy(CY, LONG64*); HRESULT VarI8FromDisp(IDispatch, LCID, LONG64*); HRESULT VarR4FromUI1(BYTE, FLOAT*); HRESULT VarR4FromI2(SHORT, FLOAT*); HRESULT VarR4FromI4(LONG, FLOAT*); HRESULT VarR4FromI8(LONG64, FLOAT*); HRESULT VarR4FromR8(DOUBLE, FLOAT*); HRESULT VarR4FromDate(DATE, FLOAT*); HRESULT VarR4FromBool(VARIANT_BOOL, FLOAT*); HRESULT VarR4FromI1(byte, FLOAT*); HRESULT VarR4FromUI2(USHORT, FLOAT*); HRESULT VarR4FromUI4(ULONG, FLOAT*); HRESULT VarR4FromUI8(ULONG64, FLOAT*); HRESULT VarR4FromStr(OLECHAR*, LCID, ULONG, FLOAT*); HRESULT VarR4FromCy(CY, FLOAT*); HRESULT VarR4FromDec(DECIMAL*, FLOAT*); HRESULT VarR4FromDisp(IDispatch, LCID, FLOAT*); HRESULT VarR8FromUI1(BYTE, double*); HRESULT VarR8FromI2(SHORT, double*); HRESULT VarR8FromI4(LONG, double*); HRESULT VarR8FromI8(LONG64, double*); HRESULT VarR8FromR4(FLOAT, double*); HRESULT VarR8FromDate(DATE, double*); HRESULT VarR8FromBool(VARIANT_BOOL, double*); HRESULT VarR8FromI1(byte, double*); HRESULT VarR8FromUI2(USHORT, double*); HRESULT VarR8FromUI4(ULONG, double*); HRESULT VarR8FromUI8(ULONG64, double*); HRESULT VarR8FromStr(OLECHAR*, LCID, ULONG, double*); HRESULT VarR8FromCy(CY, double*); HRESULT VarR8FromDec(DECIMAL*, double*); HRESULT VarR8FromDisp(IDispatch, LCID, double*); HRESULT VarDateFromUI1(BYTE, DATE*); HRESULT VarDateFromI2(SHORT, DATE*); HRESULT VarDateFromI4(LONG, DATE*); HRESULT VarDateFromI8(LONG64, DATE*); HRESULT VarDateFromR4(FLOAT, DATE*); HRESULT VarDateFromR8(DOUBLE, DATE*); HRESULT VarDateFromStr(OLECHAR*, LCID, ULONG, DATE*); HRESULT VarDateFromI1(byte, DATE*); HRESULT VarDateFromUI2(USHORT, DATE*); HRESULT VarDateFromUI4(ULONG, DATE*); HRESULT VarDateFromUI8(ULONG64, DATE*); HRESULT VarDateFromBool(VARIANT_BOOL, DATE*); HRESULT VarDateFromCy(CY, DATE*); HRESULT VarDateFromDec(DECIMAL*, DATE*); HRESULT VarDateFromDisp(IDispatch, LCID, DATE*); HRESULT VarCyFromUI1(BYTE, CY*); HRESULT VarCyFromI2(SHORT sIn, CY*); HRESULT VarCyFromI4(LONG, CY*); HRESULT VarCyFromI8(LONG64, CY*); HRESULT VarCyFromR4(FLOAT, CY*); HRESULT VarCyFromR8(DOUBLE, CY*); HRESULT VarCyFromDate(DATE, CY*); HRESULT VarCyFromStr(OLECHAR*, LCID, ULONG, CY*); HRESULT VarCyFromBool(VARIANT_BOOL, CY*); HRESULT VarCyFromI1(byte, CY*); HRESULT VarCyFromUI2(USHORT, CY*); HRESULT VarCyFromUI4(ULONG, CY*); HRESULT VarCyFromUI8(ULONG64, CY*); HRESULT VarCyFromDec(DECIMAL*, CY*); HRESULT VarCyFromStr(OLECHAR*, LCID, ULONG, CY*); HRESULT VarCyFromDisp(IDispatch, LCID, CY*); HRESULT VarBstrFromUI1(BYTE, LCID, ULONG, BSTR*); HRESULT VarBstrFromI2(SHORT, LCID, ULONG, BSTR*); HRESULT VarBstrFromI4(LONG, LCID, ULONG, BSTR*); HRESULT VarBstrFromI8(LONG64, LCID, ULONG, BSTR*); HRESULT VarBstrFromR4(FLOAT, LCID, ULONG, BSTR*); HRESULT VarBstrFromR8(DOUBLE, LCID, ULONG, BSTR*); HRESULT VarBstrFromDate(DATE, LCID, ULONG, BSTR*); HRESULT VarBstrFromBool(VARIANT_BOOL, LCID, ULONG, BSTR*); HRESULT VarBstrFromI1(byte, LCID, ULONG, BSTR*); HRESULT VarBstrFromUI2(USHORT, LCID, ULONG, BSTR*); HRESULT VarBstrFromUI8(ULONG64, LCID, ULONG, BSTR*); HRESULT VarBstrFromUI4(ULONG, LCID, ULONG, BSTR*); HRESULT VarBstrFromCy(CY, LCID, ULONG, BSTR*); HRESULT VarBstrFromDec(DECIMAL*, LCID, ULONG, BSTR*); HRESULT VarBstrFromDisp(IDispatch, LCID, ULONG, BSTR*); HRESULT VarBoolFromUI1(BYTE, VARIANT_BOOL*); HRESULT VarBoolFromI2(SHORT, VARIANT_BOOL*); HRESULT VarBoolFromI4(LONG, VARIANT_BOOL*); HRESULT VarBoolFromI8(LONG64, VARIANT_BOOL*); HRESULT VarBoolFromR4(FLOAT, VARIANT_BOOL*); HRESULT VarBoolFromR8(DOUBLE, VARIANT_BOOL*); HRESULT VarBoolFromDate(DATE, VARIANT_BOOL*); HRESULT VarBoolFromStr(OLECHAR*, LCID, ULONG, VARIANT_BOOL*); HRESULT VarBoolFromI1(byte, VARIANT_BOOL*); HRESULT VarBoolFromUI2(USHORT, VARIANT_BOOL*); HRESULT VarBoolFromUI4(ULONG, VARIANT_BOOL*); HRESULT VarBoolFromUI8(ULONG64, VARIANT_BOOL*); HRESULT VarBoolFromCy(CY, VARIANT_BOOL*); HRESULT VarBoolFromDec(DECIMAL*, VARIANT_BOOL*); HRESULT VarBoolFromDisp(IDispatch, LCID, VARIANT_BOOL*); HRESULT VarI1FromUI1(BYTE, byte*); HRESULT VarI1FromI2(SHORT, byte*); HRESULT VarI1FromI4(LONG, byte*); HRESULT VarI1FromI8(LONG64, byte*); HRESULT VarI1FromR4(FLOAT, byte*); HRESULT VarI1FromR8(DOUBLE, byte*); HRESULT VarI1FromDate(DATE, byte*); HRESULT VarI1FromStr(OLECHAR*, LCID, ULONG, byte*); HRESULT VarI1FromBool(VARIANT_BOOL, byte*); HRESULT VarI1FromUI2(USHORT, byte*); HRESULT VarI1FromUI4(ULONG, byte*); HRESULT VarI1FromUI8(ULONG64, byte*); HRESULT VarI1FromCy(CY, byte*); HRESULT VarI1FromDec(DECIMAL*, byte*); HRESULT VarI1FromDisp(IDispatch, LCID, byte*); HRESULT VarUI2FromUI1(BYTE, USHORT*); HRESULT VarUI2FromI2(SHORT, USHORT*); HRESULT VarUI2FromI4(LONG, USHORT*); HRESULT VarUI2FromI8(LONG64, USHORT*); HRESULT VarUI2FromR4(FLOAT, USHORT*); HRESULT VarUI2FromR8(DOUBLE, USHORT*); HRESULT VarUI2FromDate(DATE, USHORT*); HRESULT VarUI2FromStr(OLECHAR*, LCID, ULONG, USHORT*); HRESULT VarUI2FromBool(VARIANT_BOOL, USHORT*); HRESULT VarUI2FromI1(byte, USHORT*); HRESULT VarUI2FromUI4(ULONG, USHORT*); HRESULT VarUI2FromUI8(ULONG64, USHORT*); HRESULT VarUI2FromCy(CY, USHORT*); HRESULT VarUI2FromDec(DECIMAL*, USHORT*); HRESULT VarUI2FromDisp(IDispatch, LCID, USHORT*); HRESULT VarUI4FromStr(OLECHAR*, LCID, ULONG, ULONG*); HRESULT VarUI4FromUI1(BYTE, ULONG*); HRESULT VarUI4FromI2(SHORT, ULONG*); HRESULT VarUI4FromI4(LONG, ULONG*); HRESULT VarUI4FromI8(LONG64, ULONG*); HRESULT VarUI4FromR4(FLOAT, ULONG*); HRESULT VarUI4FromR8(DOUBLE, ULONG*); HRESULT VarUI4FromDate(DATE, ULONG*); HRESULT VarUI4FromBool(VARIANT_BOOL, ULONG*); HRESULT VarUI4FromI1(byte, ULONG*); HRESULT VarUI4FromUI2(USHORT, ULONG*); HRESULT VarUI4FromUI8(ULONG64, ULONG*); HRESULT VarUI4FromCy(CY, ULONG*); HRESULT VarUI4FromDec(DECIMAL*, ULONG*); HRESULT VarUI4FromDisp(IDispatch, LCID, ULONG*); HRESULT VarUI8FromUI1(BYTE, ULONG64*); HRESULT VarUI8FromI2(SHORT, ULONG64*); HRESULT VarUI8FromI4(LONG, ULONG64*); HRESULT VarUI8FromI8(LONG64, ULONG64*); HRESULT VarUI8FromR4(FLOAT, ULONG64*); HRESULT VarUI8FromR8(DOUBLE, ULONG64*); HRESULT VarUI8FromDate(DATE, ULONG64*); HRESULT VarUI8FromStr(OLECHAR*, LCID, ULONG, ULONG64*); HRESULT VarUI8FromBool(VARIANT_BOOL, ULONG64*); HRESULT VarUI8FromI1(byte, ULONG64*); HRESULT VarUI8FromUI2(USHORT, ULONG64*); HRESULT VarUI8FromUI4(ULONG, ULONG64*); HRESULT VarUI8FromDec(DECIMAL*, ULONG64*); HRESULT VarUI8FromInt(INT, ULONG64*); HRESULT VarUI8FromCy(CY, ULONG64*); HRESULT VarUI8FromDisp(IDispatch, LCID, ULONG64*); HRESULT VarDecFromUI1(BYTE, DECIMAL*); HRESULT VarDecFromI2(SHORT, DECIMAL*); HRESULT VarDecFromI4(LONG, DECIMAL*); HRESULT VarDecFromI8(LONG64, DECIMAL*); HRESULT VarDecFromR4(FLOAT, DECIMAL*); HRESULT VarDecFromR8(DOUBLE, DECIMAL*); HRESULT VarDecFromDate(DATE, DECIMAL*); HRESULT VarDecFromStr(OLECHAR*, LCID, ULONG, DECIMAL*); HRESULT VarDecFromBool(VARIANT_BOOL, DECIMAL*); HRESULT VarDecFromI1(byte, DECIMAL*); HRESULT VarDecFromUI2(USHORT, DECIMAL*); HRESULT VarDecFromUI4(ULONG, DECIMAL*); HRESULT VarDecFromUI8(ULONG64, DECIMAL*); HRESULT VarDecFromCy(CY, DECIMAL*); HRESULT VarDecFromDisp(IDispatch, LCID, DECIMAL*); HRESULT VarDecNeg(const(DECIMAL)*, DECIMAL*); HRESULT VarR4CmpR8(float, double); HRESULT VarR8Pow(double, double, double*); HRESULT VarR8Round(double, int, double*); HRESULT VarDecAbs(const(DECIMAL)*, DECIMAL*); HRESULT VarDecAdd(const(DECIMAL)*, const(DECIMAL)*, DECIMAL*); HRESULT VarDecCmp(const(DECIMAL)*, const(DECIMAL)*); HRESULT VarDecCmpR8(const(DECIMAL)*, DOUBLE); HRESULT VarDecDiv(const(DECIMAL)*, const(DECIMAL)*, DECIMAL*); HRESULT VarDecFix(const(DECIMAL)*, DECIMAL*); HRESULT VarDecInt(const(DECIMAL)*, DECIMAL*); HRESULT VarDecMul(const(DECIMAL)*, const(DECIMAL)*, DECIMAL*); HRESULT VarDecRound(const(DECIMAL)*, int, DECIMAL*); HRESULT VarDecSub(const(DECIMAL)*, const(DECIMAL)*, DECIMAL*); HRESULT VarCyAbs(CY, CY*); HRESULT VarCyAdd(CY, CY, CY*); HRESULT VarCyCmp(CY, CY); HRESULT VarCyCmpR8(CY, DOUBLE); HRESULT VarCyFix(CY, CY*); HRESULT VarCyInt(CY, CY*); HRESULT VarCyMul(CY, CY, CY*); HRESULT VarCyMulI4(CY, LONG, CY*); HRESULT VarCyMulI8(CY, LONG64, CY*); HRESULT VarCyNeg(CY, CY*); HRESULT VarCyRound(CY, INT, CY*); HRESULT VarCySub(CY, CY, CY*); HRESULT VarAdd(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarAnd(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarCat(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarDiv(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarEqv(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarIdiv(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarImp(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarMod(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarMul(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarOr(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarPow(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarSub(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarXor(LPVARIANT, LPVARIANT, LPVARIANT); HRESULT VarAbs(LPVARIANT, LPVARIANT); HRESULT VarFix(LPVARIANT, LPVARIANT); HRESULT VarInt(LPVARIANT, LPVARIANT); HRESULT VarNeg(LPVARIANT, LPVARIANT); HRESULT VarNot(LPVARIANT, LPVARIANT); HRESULT VarRound(LPVARIANT, int, LPVARIANT); HRESULT VarCmp(LPVARIANT, LPVARIANT, LCID, ULONG); HRESULT VarBstrCmp(BSTR, BSTR, LCID, ULONG); HRESULT VarBstrCat(BSTR, BSTR, BSTR*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/docobj.d0000664000175000017500000000674012776214756023126 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_docobj.d) */ module core.sys.windows.docobj; version (Windows): private import core.sys.windows.basetyps, core.sys.windows.oaidl, core.sys.windows.objidl, core.sys.windows.oleidl, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.wtypes; // FIXME: remove inherited methods from interface definitions enum { OLECMDERR_E_UNKNOWNGROUP = -2147221244, OLECMDERR_E_CANCELED = -2147221245, OLECMDERR_E_NOHELP = -2147221246, OLECMDERR_E_DISABLED = -2147221247, OLECMDERR_E_NOTSUPPORTED = -2147221248 } enum OLECMDID { OLECMDID_OPEN = 1, OLECMDID_NEW = 2, OLECMDID_SAVE = 3, OLECMDID_SAVEAS = 4, OLECMDID_SAVECOPYAS = 5, OLECMDID_PRINT = 6, OLECMDID_PRINTPREVIEW = 7, OLECMDID_PAGESETUP = 8, OLECMDID_SPELL = 9, OLECMDID_PROPERTIES = 10, OLECMDID_CUT = 11, OLECMDID_COPY = 12, OLECMDID_PASTE = 13, OLECMDID_PASTESPECIAL = 14, OLECMDID_UNDO = 15, OLECMDID_REDO = 16, OLECMDID_SELECTALL = 17, OLECMDID_CLEARSELECTION = 18, OLECMDID_ZOOM = 19, OLECMDID_GETZOOMRANGE = 20, OLECMDID_UPDATECOMMANDS = 21, OLECMDID_REFRESH = 22, OLECMDID_STOP = 23, OLECMDID_HIDETOOLBARS = 24, OLECMDID_SETPROGRESSMAX = 25, OLECMDID_SETPROGRESSPOS = 26, OLECMDID_SETPROGRESSTEXT = 27, OLECMDID_SETTITLE = 28, OLECMDID_SETDOWNLOADSTATE = 29, OLECMDID_STOPDOWNLOAD = 30 } enum OLECMDF { OLECMDF_SUPPORTED = 1, OLECMDF_ENABLED = 2, OLECMDF_LATCHED = 4, OLECMDF_NINCHED = 8 } enum OLECMDEXECOPT { OLECMDEXECOPT_DODEFAULT = 0, OLECMDEXECOPT_PROMPTUSER = 1, OLECMDEXECOPT_DONTPROMPTUSER = 2, OLECMDEXECOPT_SHOWHELP = 3 } struct OLECMDTEXT { DWORD cmdtextf; ULONG cwActual; ULONG cwBuf; wchar[1] rgwz; } struct OLECMD { ULONG cmdID; DWORD cmdf; } alias IOleInPlaceSite LPOLEINPLACESITE; alias IEnumOleDocumentViews LPENUMOLEDOCUMENTVIEWS; extern (C) extern const IID IID_IContinueCallback, IID_IEnumOleDocumentViews, IID_IPrint, IID_IOleDocumentView, IID_IOleDocument, IID_IOleCommandTarget, IID_IOleDocumentSite; interface IOleDocumentView : IUnknown { HRESULT SetInPlaceSite(LPOLEINPLACESITE); HRESULT GetInPlaceSite(LPOLEINPLACESITE*); HRESULT GetDocument(IUnknown*); HRESULT SetRect(LPRECT); HRESULT GetRect(LPRECT); HRESULT SetRectComplex(LPRECT, LPRECT, LPRECT, LPRECT); HRESULT Show(BOOL); HRESULT UIActivate(BOOL); HRESULT Open(); HRESULT Close(DWORD); HRESULT SaveViewState(IStream); HRESULT ApplyViewState(IStream); HRESULT Clone(LPOLEINPLACESITE, IOleDocumentView*); } interface IEnumOleDocumentViews : IUnknown { HRESULT Next(ULONG, IOleDocumentView, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumOleDocumentViews*); } interface IOleDocument : IUnknown { HRESULT CreateView(LPOLEINPLACESITE, IStream, DWORD, IOleDocumentView*); HRESULT GetDocMiscStatus(DWORD*); HRESULT EnumViews(LPENUMOLEDOCUMENTVIEWS*, IOleDocumentView*); } interface IOleCommandTarget : IUnknown { HRESULT QueryStatus(const(GUID)*, ULONG, OLECMD*, OLECMDTEXT*); HRESULT Exec(const(GUID)*, DWORD, DWORD, VARIANTARG*, VARIANTARG*); } interface IOleDocumentSite : IUnknown { HRESULT ActivateMe(IOleDocumentView); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/sspi.d0000664000175000017500000003747112776214756022651 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Ellery Newcomer * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_sspi.d) */ module core.sys.windows.sspi; version (Windows): version (ANSI) {} else version = Unicode; import core.sys.windows.windef; import core.sys.windows.ntdef; import core.sys.windows.w32api; import core.sys.windows.security; import core.sys.windows.ntsecapi; import core.sys.windows.subauth; enum :ULONG{ SECPKG_CRED_INBOUND = 1, SECPKG_CRED_OUTBOUND = 2, SECPKG_CRED_BOTH = (SECPKG_CRED_OUTBOUND|SECPKG_CRED_INBOUND), SECPKG_CRED_ATTR_NAMES = 1, } enum :ULONG{ SECPKG_FLAG_INTEGRITY = 1, SECPKG_FLAG_PRIVACY = 2, SECPKG_FLAG_TOKEN_ONLY = 4, SECPKG_FLAG_DATAGRAM = 8, SECPKG_FLAG_CONNECTION = 16, SECPKG_FLAG_MULTI_REQUIRED = 32, SECPKG_FLAG_CLIENT_ONLY = 64, SECPKG_FLAG_EXTENDED_ERROR = 128, SECPKG_FLAG_IMPERSONATION = 256, SECPKG_FLAG_ACCEPT_WIN32_NAME = 512, SECPKG_FLAG_STREAM = 1024, } enum :ULONG{ SECPKG_ATTR_AUTHORITY = 6, SECPKG_ATTR_CONNECTION_INFO = 90, SECPKG_ATTR_ISSUER_LIST = 80, SECPKG_ATTR_ISSUER_LIST_EX = 89, SECPKG_ATTR_KEY_INFO = 5, SECPKG_ATTR_LIFESPAN = 2, SECPKG_ATTR_LOCAL_CERT_CONTEXT = 84, SECPKG_ATTR_LOCAL_CRED = 82, SECPKG_ATTR_NAMES = 1, SECPKG_ATTR_PROTO_INFO = 7, SECPKG_ATTR_REMOTE_CERT_CONTEXT = 83, SECPKG_ATTR_REMOTE_CRED = 81, SECPKG_ATTR_SIZES = 0, SECPKG_ATTR_STREAM_SIZES = 4, } enum :ULONG{ SECBUFFER_EMPTY = 0, SECBUFFER_DATA = 1, SECBUFFER_TOKEN = 2, SECBUFFER_PKG_PARAMS = 3, SECBUFFER_MISSING = 4, SECBUFFER_EXTRA = 5, SECBUFFER_STREAM_TRAILER = 6, SECBUFFER_STREAM_HEADER = 7, SECBUFFER_PADDING = 9, SECBUFFER_STREAM = 10, SECBUFFER_READONLY = 0x80000000, SECBUFFER_ATTRMASK = 0xf0000000, } enum UNISP_NAME_A = "Microsoft Unified Security Protocol Provider"; enum UNISP_NAME_W = "Microsoft Unified Security Protocol Provider"w; enum SECBUFFER_VERSION = 0; alias UNICODE_STRING SECURITY_STRING; alias UNICODE_STRING* PSECURITY_STRING; extern(Windows): struct SecHandle { ULONG_PTR dwLower; ULONG_PTR dwUpper; } alias SecHandle* PSecHandle; struct SecBuffer { ULONG cbBuffer; ULONG BufferType; PVOID pvBuffer; } alias SecBuffer* PSecBuffer; alias SecHandle CredHandle; alias PSecHandle PCredHandle; alias SecHandle CtxtHandle; alias PSecHandle PCtxtHandle; struct SECURITY_INTEGER { uint LowPart; int HighPart; } alias SECURITY_INTEGER TimeStamp; alias SECURITY_INTEGER* PTimeStamp; struct SecBufferDesc { ULONG ulVersion; ULONG cBuffers; PSecBuffer pBuffers; } alias SecBufferDesc* PSecBufferDesc; struct SecPkgContext_StreamSizes { ULONG cbHeader; ULONG cbTrailer; ULONG cbMaximumMessage; ULONG cBuffers; ULONG cbBlockSize; } alias SecPkgContext_StreamSizes* PSecPkgContext_StreamSizes; struct SecPkgContext_Sizes { ULONG cbMaxToken; ULONG cbMaxSignature; ULONG cbBlockSize; ULONG cbSecurityTrailer; } alias SecPkgContext_Sizes* PSecPkgContext_Sizes; struct SecPkgContext_AuthorityW { SEC_WCHAR* sAuthorityName; } alias SecPkgContext_AuthorityW* PSecPkgContext_AuthorityW; struct SecPkgContext_AuthorityA { SEC_CHAR* sAuthorityName; } alias SecPkgContext_AuthorityA* PSecPkgContext_AuthorityA; struct SecPkgContext_KeyInfoW { SEC_WCHAR* sSignatureAlgorithmName; SEC_WCHAR* sEncryptAlgorithmName; ULONG KeySize; ULONG SignatureAlgorithm; ULONG EncryptAlgorithm; } alias SecPkgContext_KeyInfoW* PSecPkgContext_KeyInfoW; struct SecPkgContext_KeyInfoA { SEC_CHAR* sSignatureAlgorithmName; SEC_CHAR* sEncryptAlgorithmName; ULONG KeySize; ULONG SignatureAlgorithm; ULONG EncryptAlgorithm; } alias SecPkgContext_KeyInfoA* PSecPkgContext_KeyInfoA; struct SecPkgContext_LifeSpan { TimeStamp tsStart; TimeStamp tsExpiry; } alias SecPkgContext_LifeSpan* PSecPkgContext_LifeSpan; struct SecPkgContext_NamesW { SEC_WCHAR* sUserName; } alias SecPkgContext_NamesW* PSecPkgContext_NamesW; struct SecPkgContext_NamesA { SEC_CHAR* sUserName; } alias SecPkgContext_NamesA* PSecPkgContext_NamesA; struct SecPkgInfoW { ULONG fCapabilities; USHORT wVersion; USHORT wRPCID; ULONG cbMaxToken; SEC_WCHAR* Name; SEC_WCHAR* Comment; } alias SecPkgInfoW* PSecPkgInfoW; struct SecPkgInfoA { ULONG fCapabilities; USHORT wVersion; USHORT wRPCID; ULONG cbMaxToken; SEC_CHAR* Name; SEC_CHAR* Comment; } alias SecPkgInfoA* PSecPkgInfoA; /* supported only in win2k+, so it should be a PSecPkgInfoW */ /* PSDK does not say it has ANSI/Unicode versions */ struct SecPkgContext_PackageInfo { PSecPkgInfoW PackageInfo; } alias SecPkgContext_PackageInfo* PSecPkgContext_PackageInfo; struct SecPkgCredentials_NamesW { SEC_WCHAR* sUserName; } alias SecPkgCredentials_NamesW* PSecPkgCredentials_NamesW; struct SecPkgCredentials_NamesA { SEC_CHAR* sUserName; } alias SecPkgCredentials_NamesA* PSecPkgCredentials_NamesA; /* TODO: missing type in SDK */ alias void function() SEC_GET_KEY_FN; alias SECURITY_STATUS function(PULONG,PSecPkgInfoW*) ENUMERATE_SECURITY_PACKAGES_FN_W; alias SECURITY_STATUS function(PULONG,PSecPkgInfoA*) ENUMERATE_SECURITY_PACKAGES_FN_A; alias SECURITY_STATUS function(PCredHandle,ULONG,PVOID) QUERY_CREDENTIALS_ATTRIBUTES_FN_W; alias SECURITY_STATUS function(PCredHandle,ULONG,PVOID) QUERY_CREDENTIALS_ATTRIBUTES_FN_A; alias SECURITY_STATUS function(SEC_WCHAR*,SEC_WCHAR*,ULONG,PLUID,PVOID,SEC_GET_KEY_FN,PVOID,PCredHandle,PTimeStamp) ACQUIRE_CREDENTIALS_HANDLE_FN_W; alias SECURITY_STATUS function(SEC_CHAR*,SEC_CHAR*,ULONG,PLUID,PVOID,SEC_GET_KEY_FN,PVOID,PCredHandle,PTimeStamp) ACQUIRE_CREDENTIALS_HANDLE_FN_A; alias SECURITY_STATUS function(PCredHandle) FREE_CREDENTIALS_HANDLE_FN; alias SECURITY_STATUS function(PCredHandle,PCtxtHandle,SEC_WCHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp) INITIALIZE_SECURITY_CONTEXT_FN_W; alias SECURITY_STATUS function(PCredHandle,PCtxtHandle,SEC_CHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp) INITIALIZE_SECURITY_CONTEXT_FN_A; alias SECURITY_STATUS function(PCredHandle,PCtxtHandle,PSecBufferDesc,ULONG,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp) ACCEPT_SECURITY_CONTEXT_FN; alias SECURITY_STATUS function(PCtxtHandle,PSecBufferDesc) COMPLETE_AUTH_TOKEN_FN; alias SECURITY_STATUS function(PCtxtHandle) DELETE_SECURITY_CONTEXT_FN; alias SECURITY_STATUS function(PCtxtHandle,PSecBufferDesc) APPLY_CONTROL_TOKEN_FN_W; alias SECURITY_STATUS function(PCtxtHandle,PSecBufferDesc) APPLY_CONTROL_TOKEN_FN_A; alias SECURITY_STATUS function(PCtxtHandle,ULONG,PVOID) QUERY_CONTEXT_ATTRIBUTES_FN_A; alias SECURITY_STATUS function(PCtxtHandle,ULONG,PVOID) QUERY_CONTEXT_ATTRIBUTES_FN_W; alias SECURITY_STATUS function(PCtxtHandle) IMPERSONATE_SECURITY_CONTEXT_FN; alias SECURITY_STATUS function(PCtxtHandle) REVERT_SECURITY_CONTEXT_FN; alias SECURITY_STATUS function(PCtxtHandle,ULONG,PSecBufferDesc,ULONG) MAKE_SIGNATURE_FN; alias SECURITY_STATUS function(PCtxtHandle,PSecBufferDesc,ULONG,PULONG) VERIFY_SIGNATURE_FN; alias SECURITY_STATUS function(PVOID) FREE_CONTEXT_BUFFER_FN; alias SECURITY_STATUS function(SEC_CHAR*,PSecPkgInfoA*) QUERY_SECURITY_PACKAGE_INFO_FN_A; alias SECURITY_STATUS function(PCtxtHandle,HANDLE*) QUERY_SECURITY_CONTEXT_TOKEN_FN; alias SECURITY_STATUS function(SEC_WCHAR*,PSecPkgInfoW*) QUERY_SECURITY_PACKAGE_INFO_FN_W; alias SECURITY_STATUS function(PCtxtHandle,ULONG,PSecBufferDesc,ULONG) ENCRYPT_MESSAGE_FN; alias SECURITY_STATUS function(PCtxtHandle,PSecBufferDesc,ULONG,PULONG) DECRYPT_MESSAGE_FN; /* No, it really is FreeCredentialsHandle, see the thread beginning * http://sourceforge.net/mailarchive/message.php?msg_id=4321080 for a * discovery discussion. */ struct SecurityFunctionTableW{ uint dwVersion; ENUMERATE_SECURITY_PACKAGES_FN_W EnumerateSecurityPackagesW; QUERY_CREDENTIALS_ATTRIBUTES_FN_W QueryCredentialsAttributesW; ACQUIRE_CREDENTIALS_HANDLE_FN_W AcquireCredentialsHandleW; FREE_CREDENTIALS_HANDLE_FN FreeCredentialsHandle; void* Reserved2; INITIALIZE_SECURITY_CONTEXT_FN_W InitializeSecurityContextW; ACCEPT_SECURITY_CONTEXT_FN AcceptSecurityContext; COMPLETE_AUTH_TOKEN_FN CompleteAuthToken; DELETE_SECURITY_CONTEXT_FN DeleteSecurityContext; APPLY_CONTROL_TOKEN_FN_W ApplyControlTokenW; QUERY_CONTEXT_ATTRIBUTES_FN_W QueryContextAttributesW; IMPERSONATE_SECURITY_CONTEXT_FN ImpersonateSecurityContext; REVERT_SECURITY_CONTEXT_FN RevertSecurityContext; MAKE_SIGNATURE_FN MakeSignature; VERIFY_SIGNATURE_FN VerifySignature; FREE_CONTEXT_BUFFER_FN FreeContextBuffer; QUERY_SECURITY_PACKAGE_INFO_FN_W QuerySecurityPackageInfoW; void* Reserved3; void* Reserved4; void* Reserved5; void* Reserved6; void* Reserved7; void* Reserved8; QUERY_SECURITY_CONTEXT_TOKEN_FN QuerySecurityContextToken; ENCRYPT_MESSAGE_FN EncryptMessage; DECRYPT_MESSAGE_FN DecryptMessage; } alias SecurityFunctionTableW* PSecurityFunctionTableW; struct SecurityFunctionTableA{ uint dwVersion; ENUMERATE_SECURITY_PACKAGES_FN_A EnumerateSecurityPackagesA; QUERY_CREDENTIALS_ATTRIBUTES_FN_A QueryCredentialsAttributesA; ACQUIRE_CREDENTIALS_HANDLE_FN_A AcquireCredentialsHandleA; FREE_CREDENTIALS_HANDLE_FN FreeCredentialsHandle; void* Reserved2; INITIALIZE_SECURITY_CONTEXT_FN_A InitializeSecurityContextA; ACCEPT_SECURITY_CONTEXT_FN AcceptSecurityContext; COMPLETE_AUTH_TOKEN_FN CompleteAuthToken; DELETE_SECURITY_CONTEXT_FN DeleteSecurityContext; APPLY_CONTROL_TOKEN_FN_A ApplyControlTokenA; QUERY_CONTEXT_ATTRIBUTES_FN_A QueryContextAttributesA; IMPERSONATE_SECURITY_CONTEXT_FN ImpersonateSecurityContext; REVERT_SECURITY_CONTEXT_FN RevertSecurityContext; MAKE_SIGNATURE_FN MakeSignature; VERIFY_SIGNATURE_FN VerifySignature; FREE_CONTEXT_BUFFER_FN FreeContextBuffer; QUERY_SECURITY_PACKAGE_INFO_FN_A QuerySecurityPackageInfoA; void* Reserved3; void* Reserved4; void* Unknown1; void* Unknown2; void* Unknown3; void* Unknown4; void* Unknown5; ENCRYPT_MESSAGE_FN EncryptMessage; DECRYPT_MESSAGE_FN DecryptMessage; } alias SecurityFunctionTableA* PSecurityFunctionTableA; alias PSecurityFunctionTableA function() INIT_SECURITY_INTERFACE_A; alias PSecurityFunctionTableW function() INIT_SECURITY_INTERFACE_W; SECURITY_STATUS FreeCredentialsHandle(PCredHandle); SECURITY_STATUS EnumerateSecurityPackagesA(PULONG,PSecPkgInfoA*); SECURITY_STATUS EnumerateSecurityPackagesW(PULONG,PSecPkgInfoW*); SECURITY_STATUS AcquireCredentialsHandleA(SEC_CHAR*,SEC_CHAR*,ULONG,PLUID,PVOID,SEC_GET_KEY_FN,PVOID,PCredHandle,PTimeStamp); SECURITY_STATUS AcquireCredentialsHandleW(SEC_WCHAR*,SEC_WCHAR*,ULONG,PLUID,PVOID,SEC_GET_KEY_FN,PVOID,PCredHandle,PTimeStamp); SECURITY_STATUS AcceptSecurityContext(PCredHandle,PCtxtHandle,PSecBufferDesc,ULONG,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp); SECURITY_STATUS InitializeSecurityContextA(PCredHandle,PCtxtHandle,SEC_CHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp); SECURITY_STATUS InitializeSecurityContextW(PCredHandle,PCtxtHandle,SEC_WCHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp); SECURITY_STATUS FreeContextBuffer(PVOID); SECURITY_STATUS QueryContextAttributesA(PCtxtHandle,ULONG,PVOID); SECURITY_STATUS QueryContextAttributesW(PCtxtHandle,ULONG,PVOID); SECURITY_STATUS QueryCredentialsAttributesA(PCredHandle,ULONG,PVOID); SECURITY_STATUS QueryCredentialsAttributesW(PCredHandle,ULONG,PVOID); static if(_WIN32_WINNT >= 0x500){ SECURITY_STATUS QuerySecurityContextToken(PCtxtHandle,HANDLE*); } SECURITY_STATUS DecryptMessage(PCtxtHandle,PSecBufferDesc,ULONG,PULONG); SECURITY_STATUS EncryptMessage(PCtxtHandle,ULONG,PSecBufferDesc,ULONG); SECURITY_STATUS DeleteSecurityContext(PCtxtHandle); SECURITY_STATUS CompleteAuthToken(PCtxtHandle,PSecBufferDesc); SECURITY_STATUS ApplyControlTokenA(PCtxtHandle,PSecBufferDesc); SECURITY_STATUS ApplyControlTokenW(PCtxtHandle,PSecBufferDesc); SECURITY_STATUS ImpersonateSecurityContext(PCtxtHandle); SECURITY_STATUS RevertSecurityContext(PCtxtHandle); SECURITY_STATUS MakeSignature(PCtxtHandle,ULONG,PSecBufferDesc,ULONG); SECURITY_STATUS VerifySignature(PCtxtHandle,PSecBufferDesc,ULONG,PULONG); SECURITY_STATUS QuerySecurityPackageInfoA(SEC_CHAR*,PSecPkgInfoA*); SECURITY_STATUS QuerySecurityPackageInfoW(SEC_WCHAR*,PSecPkgInfoW*); PSecurityFunctionTableA InitSecurityInterfaceA(); PSecurityFunctionTableW InitSecurityInterfaceW(); version(Unicode) { alias UNISP_NAME_W UNISP_NAME; alias SecPkgInfoW SecPkgInfo; alias PSecPkgInfoW PSecPkgInfo; alias SecPkgCredentials_NamesW SecPkgCredentials_Names; alias PSecPkgCredentials_NamesW PSecPkgCredentials_Names; alias SecPkgContext_AuthorityW SecPkgContext_Authority; alias PSecPkgContext_AuthorityW PSecPkgContext_Authority; alias SecPkgContext_KeyInfoW SecPkgContext_KeyInfo; alias PSecPkgContext_KeyInfoW PSecPkgContext_KeyInfo; alias SecPkgContext_NamesW SecPkgContext_Names; alias PSecPkgContext_NamesW PSecPkgContext_Names; alias SecurityFunctionTableW SecurityFunctionTable; alias PSecurityFunctionTableW PSecurityFunctionTable; alias AcquireCredentialsHandleW AcquireCredentialsHandle; alias EnumerateSecurityPackagesW EnumerateSecurityPackages; alias InitializeSecurityContextW InitializeSecurityContext; alias QueryContextAttributesW QueryContextAttributes; alias QueryCredentialsAttributesW QueryCredentialsAttributes; alias QuerySecurityPackageInfoW QuerySecurityPackageInfo; alias ApplyControlTokenW ApplyControlToken; alias ENUMERATE_SECURITY_PACKAGES_FN_W ENUMERATE_SECURITY_PACKAGES_FN; alias QUERY_CREDENTIALS_ATTRIBUTES_FN_W QUERY_CREDENTIALS_ATTRIBUTES_FN; alias ACQUIRE_CREDENTIALS_HANDLE_FN_W ACQUIRE_CREDENTIALS_HANDLE_FN; alias INITIALIZE_SECURITY_CONTEXT_FN_W INITIALIZE_SECURITY_CONTEXT_FN; alias APPLY_CONTROL_TOKEN_FN_W APPLY_CONTROL_TOKEN_FN; alias QUERY_CONTEXT_ATTRIBUTES_FN_W QUERY_CONTEXT_ATTRIBUTES_FN; alias QUERY_SECURITY_PACKAGE_INFO_FN_W QUERY_SECURITY_PACKAGE_INFO_FN; alias INIT_SECURITY_INTERFACE_W INIT_SECURITY_INTERFACE; }else{ alias UNISP_NAME_A UNISP_NAME; alias SecPkgInfoA SecPkgInfo; alias PSecPkgInfoA PSecPkgInfo; alias SecPkgCredentials_NamesA SecPkgCredentials_Names; alias PSecPkgCredentials_NamesA PSecPkgCredentials_Names; alias SecPkgContext_AuthorityA SecPkgContext_Authority; alias PSecPkgContext_AuthorityA PSecPkgContext_Authority; alias SecPkgContext_KeyInfoA SecPkgContext_KeyInfo; alias PSecPkgContext_KeyInfoA PSecPkgContext_KeyInfo; alias SecPkgContext_NamesA SecPkgContext_Names; alias PSecPkgContext_NamesA PSecPkgContext_Names; alias SecurityFunctionTableA SecurityFunctionTable; alias PSecurityFunctionTableA PSecurityFunctionTable; alias AcquireCredentialsHandleA AcquireCredentialsHandle; alias EnumerateSecurityPackagesA EnumerateSecurityPackages; alias InitializeSecurityContextA InitializeSecurityContext; alias QueryContextAttributesA QueryContextAttributes; alias QueryCredentialsAttributesA QueryCredentialsAttributes; alias QuerySecurityPackageInfoA QuerySecurityPackageInfo; alias ApplyControlTokenA ApplyControlToken; alias ENUMERATE_SECURITY_PACKAGES_FN_A ENUMERATE_SECURITY_PACKAGES_FN; alias QUERY_CREDENTIALS_ATTRIBUTES_FN_A QUERY_CREDENTIALS_ATTRIBUTES_FN; alias ACQUIRE_CREDENTIALS_HANDLE_FN_A ACQUIRE_CREDENTIALS_HANDLE_FN; alias INITIALIZE_SECURITY_CONTEXT_FN_A INITIALIZE_SECURITY_CONTEXT_FN; alias APPLY_CONTROL_TOKEN_FN_A APPLY_CONTROL_TOKEN_FN; alias QUERY_CONTEXT_ATTRIBUTES_FN_A QUERY_CONTEXT_ATTRIBUTES_FN; alias QUERY_SECURITY_PACKAGE_INFO_FN_A QUERY_SECURITY_PACKAGE_INFO_FN; alias INIT_SECURITY_INTERFACE_A INIT_SECURITY_INTERFACE; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmat.d0000664000175000017500000000257212776214756022622 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmat.d) */ module core.sys.windows.lmat; version (Windows): pragma(lib, "netapi32"); private import core.sys.windows.lmcons, core.sys.windows.windef; enum JOB_RUN_PERIODICALLY = 1; enum JOB_EXEC_ERROR = 2; enum JOB_RUNS_TODAY = 4; enum JOB_ADD_CURRENT_DATE = 8; enum JOB_NONINTERACTIVE = 16; enum JOB_INPUT_FLAGS = JOB_RUN_PERIODICALLY | JOB_ADD_CURRENT_DATE | JOB_NONINTERACTIVE; enum JOB_OUTPUT_FLAGS = JOB_RUN_PERIODICALLY | JOB_EXEC_ERROR | JOB_RUNS_TODAY | JOB_NONINTERACTIVE; struct AT_ENUM { DWORD JobId; DWORD JobTime; DWORD DaysOfMonth; UCHAR DaysOfWeek; UCHAR Flags; LPWSTR Command; } alias AT_ENUM* PAT_ENUM, LPAT_ENUM; struct AT_INFO { DWORD JobTime; DWORD DaysOfMonth; UCHAR DaysOfWeek; UCHAR Flags; LPWSTR Command; } alias AT_INFO* PAT_INFO, LPAT_INFO; extern (Windows) { NET_API_STATUS NetScheduleJobAdd(LPWSTR, PBYTE, LPDWORD); NET_API_STATUS NetScheduleJobDel(LPWSTR, DWORD, DWORD); NET_API_STATUS NetScheduleJobEnum(LPWSTR, PBYTE*, DWORD, PDWORD, PDWORD, PDWORD); NET_API_STATUS NetScheduleJobGetInfo(LPWSTR, DWORD, PBYTE*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmremutl.d0000664000175000017500000000310712776214756023521 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmremutl.d) */ module core.sys.windows.lmremutl; version (Windows): pragma(lib, "netapi32"); // D Conversion Note: DESC_CHAR is defined as TCHAR. private import core.sys.windows.lmcons, core.sys.windows.windef; enum SUPPORTS_REMOTE_ADMIN_PROTOCOL = 2; enum SUPPORTS_RPC = 4; enum SUPPORTS_SAM_PROTOCOL = 8; enum SUPPORTS_UNICODE = 16; enum SUPPORTS_LOCAL = 32; enum SUPPORTS_ANY = 0xFFFFFFFF; enum NO_PERMISSION_REQUIRED = 1; enum ALLOCATE_RESPONSE = 2; enum USE_SPECIFIC_TRANSPORT = 0x80000000; //[Yes] #ifndef DESC_CHAR_UNICODE //alias CHAR DESC_CHAR; //} else { //[No] #else //[No] typedef WCHAR DESC_CHAR; //[No] #endif // FIXME (D): Is this OK? alias TCHAR DESC_CHAR; alias DESC_CHAR* LPDESC; struct TIME_OF_DAY_INFO { DWORD tod_elapsedt; DWORD tod_msecs; DWORD tod_hours; DWORD tod_mins; DWORD tod_secs; DWORD tod_hunds; LONG tod_timezone; DWORD tod_tinterval; DWORD tod_day; DWORD tod_month; DWORD tod_year; DWORD tod_weekday; } alias TIME_OF_DAY_INFO* PTIME_OF_DAY_INFO, LPTIME_OF_DAY_INFO; extern (Windows) { NET_API_STATUS NetRemoteTOD(LPCWSTR, PBYTE*); NET_API_STATUS NetRemoteComputerSupports(LPCWSTR, DWORD, PDWORD); NET_API_STATUS RxRemoteApi(DWORD, LPCWSTR, LPDESC, LPDESC, LPDESC, LPDESC, LPDESC, LPDESC, LPDESC, DWORD, ...); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/w32api.d0000664000175000017500000000563312776214756022773 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 4.0 * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_w32api.d) */ module core.sys.windows.w32api; version (Windows): version (ANSI) {} else version = Unicode; enum __W32API_VERSION = 3.17; enum __W32API_MAJOR_VERSION = 3; enum __W32API_MINOR_VERSION = 17; /* These version identifiers are used to specify the minimum version of Windows that an * application will support. * * Previously the minimum Windows 9x and Windows NT versions could be specified. However, since * Windows 9x is no longer supported, either by Microsoft or by DMD, this distinction has been * removed in order to simplify the bindings. */ version (Windows10) { enum uint _WIN32_WINNT = 0x604; } else version (Windows8_1) { // also Windows2012R2 enum uint _WIN32_WINNT = 0x603; } else version (Windows8) { // also Windows2012 enum uint _WIN32_WINNT = 0x602; } else version (Windows7) { // also Windows2008R2 enum uint _WIN32_WINNT = 0x601; } else version (WindowsVista) { // also Windows2008 enum uint _WIN32_WINNT = 0x600; } else version (Windows2003) { // also WindowsHomeServer, WindowsXP64 enum uint _WIN32_WINNT = 0x502; } else version (WindowsXP) { enum uint _WIN32_WINNT = 0x501; } else version (Windows2000) { // Current DMD doesn't support any version of Windows older than XP, // but third-party compilers could use this enum uint _WIN32_WINNT = 0x500; } else { enum uint _WIN32_WINNT = 0x501; } version (IE10) { enum uint _WIN32_IE = 0xA00; } else version (IE9) { enum uint _WIN32_IE = 0x900; } else version (IE8) { enum uint _WIN32_IE = 0x800; } else version (IE7) { enum uint _WIN32_IE = 0x700; } else version (IE602) { enum uint _WIN32_IE = 0x603; } else version (IE601) { enum uint _WIN32_IE = 0x601; } else version (IE6) { enum uint _WIN32_IE = 0x600; } else version (IE56) { enum uint _WIN32_IE = 0x560; } else version (IE501) { enum uint _WIN32_IE = 0x501; } else version (IE5) { enum uint _WIN32_IE = 0x500; } else version (IE401) { enum uint _WIN32_IE = 0x401; } else version (IE4) { enum uint _WIN32_IE = 0x400; } else version (IE3) { enum uint _WIN32_IE = 0x300; } else static if (_WIN32_WINNT >= 0x410) { enum uint _WIN32_IE = 0x400; } else { enum uint _WIN32_IE = 0; } debug (WindowsUnitTest) { unittest { printf("Windows NT version: %03x\n", _WIN32_WINNT); printf("IE version: %03x\n", _WIN32_IE); } } version (Unicode) { enum bool _WIN32_UNICODE = true; package template DECLARE_AW(string name) { mixin("alias " ~ name ~ "W " ~ name ~ ";"); } } else { enum bool _WIN32_UNICODE = false; package template DECLARE_AW(string name) { mixin("alias " ~ name ~ "A " ~ name ~ ";"); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/wincon.d0000664000175000017500000002141512776214756023157 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_wincon.d) */ module core.sys.windows.wincon; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "kernel32"); private import core.sys.windows.w32api, core.sys.windows.windef; // FIXME: clean up Windows version support enum { FOREGROUND_BLUE = 1, FOREGROUND_GREEN = 2, FOREGROUND_RED = 4, FOREGROUND_INTENSITY = 8, BACKGROUND_BLUE = 16, BACKGROUND_GREEN = 32, BACKGROUND_RED = 64, BACKGROUND_INTENSITY = 128 } static if (_WIN32_WINNT >= 0x501) { enum { CONSOLE_FULLSCREEN_MODE = 1, CONSOLE_WINDOWED_MODE = 0 } } enum { CTRL_C_EVENT = 0, CTRL_BREAK_EVENT = 1, CTRL_CLOSE_EVENT = 2, CTRL_LOGOFF_EVENT = 5, CTRL_SHUTDOWN_EVENT = 6 } enum { ENABLE_PROCESSED_INPUT = 1, ENABLE_LINE_INPUT = 2, ENABLE_ECHO_INPUT = 4, ENABLE_WINDOW_INPUT = 8, ENABLE_MOUSE_INPUT = 16 } enum { ENABLE_PROCESSED_OUTPUT = 1, ENABLE_WRAP_AT_EOL_OUTPUT = 2 } enum { KEY_EVENT = 1, MOUSE_EVENT = 2, WINDOW_BUFFER_SIZE_EVENT = 4, MENU_EVENT = 8, FOCUS_EVENT = 16 } enum { RIGHT_ALT_PRESSED = 1, LEFT_ALT_PRESSED = 2, RIGHT_CTRL_PRESSED = 4, LEFT_CTRL_PRESSED = 8, SHIFT_PRESSED = 16, NUMLOCK_ON = 32, SCROLLLOCK_ON = 64, CAPSLOCK_ON = 128, ENHANCED_KEY = 256 } enum { FROM_LEFT_1ST_BUTTON_PRESSED = 1, RIGHTMOST_BUTTON_PRESSED = 2, FROM_LEFT_2ND_BUTTON_PRESSED = 4, FROM_LEFT_3RD_BUTTON_PRESSED = 8, FROM_LEFT_4TH_BUTTON_PRESSED = 16 } enum { MOUSE_MOVED = 1, DOUBLE_CLICK = 2, MOUSE_WHEELED = 4 } struct CHAR_INFO { union _Char { WCHAR UnicodeChar; CHAR AsciiChar; } union { _Char Char; WCHAR UnicodeChar; CHAR AsciiChar; } WORD Attributes; } alias CHAR_INFO* PCHAR_INFO; struct SMALL_RECT { SHORT Left; SHORT Top; SHORT Right; SHORT Bottom; } alias SMALL_RECT* PSMALL_RECT; struct CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; } alias CONSOLE_CURSOR_INFO* PCONSOLE_CURSOR_INFO; struct COORD { SHORT X; SHORT Y; } alias COORD* PCOORD; struct CONSOLE_FONT_INFO { DWORD nFont; COORD dwFontSize; } alias CONSOLE_FONT_INFO* PCONSOLE_FONT_INFO; struct CONSOLE_SCREEN_BUFFER_INFO { COORD dwSize; COORD dwCursorPosition; WORD wAttributes; SMALL_RECT srWindow; COORD dwMaximumWindowSize; } alias CONSOLE_SCREEN_BUFFER_INFO* PCONSOLE_SCREEN_BUFFER_INFO; alias extern(Windows) BOOL function(DWORD) nothrow PHANDLER_ROUTINE; struct KEY_EVENT_RECORD { BOOL bKeyDown; WORD wRepeatCount; WORD wVirtualKeyCode; WORD wVirtualScanCode; union _uChar { WCHAR UnicodeChar; CHAR AsciiChar; } union { WCHAR UnicodeChar; CHAR AsciiChar; _uChar uChar; } DWORD dwControlKeyState; } alias KEY_EVENT_RECORD* PKEY_EVENT_RECORD; struct MOUSE_EVENT_RECORD { COORD dwMousePosition; DWORD dwButtonState; DWORD dwControlKeyState; DWORD dwEventFlags; } alias MOUSE_EVENT_RECORD* PMOUSE_EVENT_RECORD; struct WINDOW_BUFFER_SIZE_RECORD { COORD dwSize; } alias WINDOW_BUFFER_SIZE_RECORD* PWINDOW_BUFFER_SIZE_RECORD; struct MENU_EVENT_RECORD { UINT dwCommandId; } alias MENU_EVENT_RECORD* PMENU_EVENT_RECORD; struct FOCUS_EVENT_RECORD { BOOL bSetFocus; } alias FOCUS_EVENT_RECORD* PFOCUS_EVENT_RECORD; struct INPUT_RECORD { WORD EventType; union _Event { KEY_EVENT_RECORD KeyEvent; MOUSE_EVENT_RECORD MouseEvent; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; MENU_EVENT_RECORD MenuEvent; FOCUS_EVENT_RECORD FocusEvent; } union { KEY_EVENT_RECORD KeyEvent; MOUSE_EVENT_RECORD MouseEvent; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; MENU_EVENT_RECORD MenuEvent; FOCUS_EVENT_RECORD FocusEvent; _Event Event; } } alias INPUT_RECORD* PINPUT_RECORD; extern (Windows) nothrow @nogc: BOOL AllocConsole(); HANDLE CreateConsoleScreenBuffer(DWORD, DWORD, const(SECURITY_ATTRIBUTES)*, DWORD, LPVOID); BOOL FillConsoleOutputAttribute(HANDLE, WORD, DWORD, COORD, PDWORD); BOOL FillConsoleOutputCharacterA(HANDLE, CHAR, DWORD, COORD, PDWORD); BOOL FillConsoleOutputCharacterW(HANDLE, WCHAR, DWORD, COORD, PDWORD); BOOL FlushConsoleInputBuffer(HANDLE); BOOL FreeConsole(); BOOL GenerateConsoleCtrlEvent(DWORD, DWORD); UINT GetConsoleCP(); BOOL GetConsoleCursorInfo(HANDLE, PCONSOLE_CURSOR_INFO); BOOL GetConsoleMode(HANDLE,PDWORD); UINT GetConsoleOutputCP(); BOOL GetConsoleScreenBufferInfo(HANDLE, PCONSOLE_SCREEN_BUFFER_INFO); DWORD GetConsoleTitleA(LPSTR, DWORD); DWORD GetConsoleTitleW(LPWSTR, DWORD); COORD GetLargestConsoleWindowSize(HANDLE); BOOL GetNumberOfConsoleInputEvents(HANDLE, PDWORD); BOOL GetNumberOfConsoleMouseButtons(PDWORD); BOOL PeekConsoleInputA(HANDLE, PINPUT_RECORD, DWORD, PDWORD); BOOL PeekConsoleInputW(HANDLE, PINPUT_RECORD, DWORD, PDWORD); BOOL ReadConsoleA(HANDLE, PVOID, DWORD, PDWORD, PVOID); BOOL ReadConsoleW(HANDLE, PVOID, DWORD, PDWORD, PVOID); BOOL ReadConsoleInputA(HANDLE, PINPUT_RECORD, DWORD, PDWORD); BOOL ReadConsoleInputW(HANDLE, PINPUT_RECORD, DWORD, PDWORD); BOOL ReadConsoleOutputAttribute(HANDLE, LPWORD, DWORD, COORD, LPDWORD); BOOL ReadConsoleOutputCharacterA(HANDLE, LPSTR, DWORD, COORD, PDWORD); BOOL ReadConsoleOutputCharacterW(HANDLE, LPWSTR, DWORD, COORD, PDWORD); BOOL ReadConsoleOutputA(HANDLE, PCHAR_INFO, COORD, COORD, PSMALL_RECT); BOOL ReadConsoleOutputW(HANDLE, PCHAR_INFO, COORD, COORD, PSMALL_RECT); BOOL ScrollConsoleScreenBufferA(HANDLE, const(SMALL_RECT)*, const(SMALL_RECT)*, COORD, const(CHAR_INFO)*); BOOL ScrollConsoleScreenBufferW(HANDLE, const(SMALL_RECT)*, const(SMALL_RECT)*, COORD, const(CHAR_INFO)*); BOOL SetConsoleActiveScreenBuffer(HANDLE); BOOL SetConsoleCP(UINT); BOOL SetConsoleCtrlHandler(PHANDLER_ROUTINE, BOOL); BOOL SetConsoleCursorInfo(HANDLE, const(CONSOLE_CURSOR_INFO)*); BOOL SetConsoleCursorPosition(HANDLE, COORD); static if (_WIN32_WINNT >= 0x500) { BOOL GetConsoleDisplayMode(LPDWORD); HWND GetConsoleWindow(); } static if (_WIN32_WINNT >= 0x501) { BOOL AttachConsole(DWORD); BOOL SetConsoleDisplayMode(HANDLE, DWORD, PCOORD); enum DWORD ATTACH_PARENT_PROCESS = cast(DWORD)-1; } BOOL SetConsoleMode(HANDLE, DWORD); BOOL SetConsoleOutputCP(UINT); BOOL SetConsoleScreenBufferSize(HANDLE, COORD); BOOL SetConsoleTextAttribute(HANDLE, WORD); BOOL SetConsoleTitleA(LPCSTR); BOOL SetConsoleTitleW(LPCWSTR); BOOL SetConsoleWindowInfo(HANDLE, BOOL, const(SMALL_RECT)*); BOOL WriteConsoleA(HANDLE, PCVOID, DWORD, PDWORD, PVOID); BOOL WriteConsoleW(HANDLE, PCVOID, DWORD, PDWORD, PVOID); BOOL WriteConsoleInputA(HANDLE, const(INPUT_RECORD)*, DWORD, PDWORD); BOOL WriteConsoleInputW(HANDLE, const(INPUT_RECORD)*, DWORD, PDWORD); BOOL WriteConsoleOutputA(HANDLE, const(CHAR_INFO)*, COORD, COORD, PSMALL_RECT); BOOL WriteConsoleOutputW(HANDLE, const(CHAR_INFO)*, COORD, COORD, PSMALL_RECT); BOOL WriteConsoleOutputAttribute(HANDLE, const(WORD)*, DWORD, COORD, PDWORD); BOOL WriteConsoleOutputCharacterA(HANDLE, LPCSTR, DWORD, COORD, PDWORD); BOOL WriteConsoleOutputCharacterW(HANDLE, LPCWSTR, DWORD, COORD, PDWORD); version (Unicode) { alias FillConsoleOutputCharacterW FillConsoleOutputCharacter; alias GetConsoleTitleW GetConsoleTitle; alias PeekConsoleInputW PeekConsoleInput; alias ReadConsoleW ReadConsole; alias ReadConsoleInputW ReadConsoleInput; alias ReadConsoleOutputW ReadConsoleOutput; alias ReadConsoleOutputCharacterW ReadConsoleOutputCharacter; alias ScrollConsoleScreenBufferW ScrollConsoleScreenBuffer; alias SetConsoleTitleW SetConsoleTitle; alias WriteConsoleW WriteConsole; alias WriteConsoleInputW WriteConsoleInput; alias WriteConsoleOutputW WriteConsoleOutput; alias WriteConsoleOutputCharacterW WriteConsoleOutputCharacter; } else { alias FillConsoleOutputCharacterA FillConsoleOutputCharacter; alias GetConsoleTitleA GetConsoleTitle; alias PeekConsoleInputA PeekConsoleInput; alias ReadConsoleA ReadConsole; alias ReadConsoleInputA ReadConsoleInput; alias ReadConsoleOutputA ReadConsoleOutput; alias ReadConsoleOutputCharacterA ReadConsoleOutputCharacter; alias ScrollConsoleScreenBufferA ScrollConsoleScreenBuffer; alias SetConsoleTitleA SetConsoleTitle; alias WriteConsoleA WriteConsole; alias WriteConsoleInputA WriteConsoleInput; alias WriteConsoleOutputA WriteConsoleOutput; alias WriteConsoleOutputCharacterA WriteConsoleOutputCharacter; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmstats.d0000664000175000017500000000647512776214756023362 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmstats.d) */ module core.sys.windows.lmstats; version (Windows): pragma(lib, "netapi32"); private import core.sys.windows.lmcons, core.sys.windows.windef; enum ULONG STATSOPT_CLR = 1, STATS_NO_VALUE = -1, STATS_OVERFLOW = -2; struct STAT_SERVER_0{ DWORD sts0_start; DWORD sts0_fopens; DWORD sts0_devopens; DWORD sts0_jobsqueued; DWORD sts0_sopens; DWORD sts0_stimedout; DWORD sts0_serrorout; DWORD sts0_pwerrors; DWORD sts0_permerrors; DWORD sts0_syserrors; DWORD sts0_bytessent_low; DWORD sts0_bytessent_high; DWORD sts0_bytesrcvd_low; DWORD sts0_bytesrcvd_high; DWORD sts0_avresponse; DWORD sts0_reqbufneed; DWORD sts0_bigbufneed; } alias STAT_SERVER_0* PSTAT_SERVER_0, LPSTAT_SERVER_0; // #ifdef LM20_WORKSTATION_STATISTICS // typedef struct _STAT_WORKSTATION_0 { // DWORD stw0_start; // DWORD stw0_numNCB_r; // DWORD stw0_numNCB_s; // DWORD stw0_numNCB_a; // DWORD stw0_fiNCB_r; // DWORD stw0_fiNCB_s; // DWORD stw0_fiNCB_a; // DWORD stw0_fcNCB_r; // DWORD stw0_fcNCB_s; // DWORD stw0_fcNCB_a; // DWORD stw0_sesstart; // DWORD stw0_sessfailcon; // DWORD stw0_sessbroke; // DWORD stw0_uses; // DWORD stw0_usefail; // DWORD stw0_autorec; // DWORD stw0_bytessent_r_lo; // DWORD stw0_bytessent_r_hi; // DWORD stw0_bytesrcvd_r_lo; // DWORD stw0_bytesrcvd_r_hi; // DWORD stw0_bytessent_s_lo; // DWORD stw0_bytessent_s_hi; // DWORD stw0_bytesrcvd_s_lo; // DWORD stw0_bytesrcvd_s_hi; // DWORD stw0_bytessent_a_lo; // DWORD stw0_bytessent_a_hi; // DWORD stw0_bytesrcvd_a_lo; // DWORD stw0_bytesrcvd_a_hi; // DWORD stw0_reqbufneed; // DWORD stw0_bigbufneed; // } STAT_WORKSTATION_0,*PSTAT_WORKSTATION_0,*LPSTAT_WORKSTATION_0; // #else struct STAT_WORKSTATION_0{ LARGE_INTEGER StatisticsStartTime; LARGE_INTEGER BytesReceived; LARGE_INTEGER SmbsReceived; LARGE_INTEGER PagingReadBytesRequested; LARGE_INTEGER NonPagingReadBytesRequested; LARGE_INTEGER CacheReadBytesRequested; LARGE_INTEGER NetworkReadBytesRequested; LARGE_INTEGER BytesTransmitted; LARGE_INTEGER SmbsTransmitted; LARGE_INTEGER PagingWriteBytesRequested; LARGE_INTEGER NonPagingWriteBytesRequested; LARGE_INTEGER CacheWriteBytesRequested; LARGE_INTEGER NetworkWriteBytesRequested; DWORD InitiallyFailedOperations; DWORD FailedCompletionOperations; DWORD ReadOperations; DWORD RandomReadOperations; DWORD ReadSmbs; DWORD LargeReadSmbs; DWORD SmallReadSmbs; DWORD WriteOperations; DWORD RandomWriteOperations; DWORD WriteSmbs; DWORD LargeWriteSmbs; DWORD SmallWriteSmbs; DWORD RawReadsDenied; DWORD RawWritesDenied; DWORD NetworkErrors; DWORD Sessions; DWORD FailedSessions; DWORD Reconnects; DWORD CoreConnects; DWORD Lanman20Connects; DWORD Lanman21Connects; DWORD LanmanNtConnects; DWORD ServerDisconnects; DWORD HungSessions; DWORD UseCount; DWORD FailedUseCount; DWORD CurrentCommands; } alias STAT_WORKSTATION_0* PSTAT_WORKSTATION_0, LPSTAT_WORKSTATION_0; extern (Windows): NET_API_STATUS NetStatisticsGet(LPWSTR,LPWSTR,DWORD,DWORD,PBYTE*); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/winber.d0000664000175000017500000000402312776214756023144 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_winber.d) */ module core.sys.windows.winber; version (Windows): /* Comment from MinGW winber.h - Header file for the Windows LDAP Basic Encoding Rules API Written by Filip Navara References: The C LDAP Application Program Interface http://www.watersprings.org/pub/id/draft-ietf-ldapext-ldap-c-api-05.txt Lightweight Directory Access Protocol Reference http://msdn.microsoft.com/library/en-us/netdir/ldap/ldap_reference.asp This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ import core.sys.windows.basetsd; /* Opaque structure * http://msdn.microsoft.com/library/en-us/ldap/ldap/berelement.asp */ struct BerElement; alias int ber_int_t, ber_slen_t; alias uint ber_uint_t, ber_len_t, ber_tag_t; align(4): struct BerValue { ber_len_t bv_len; char* bv_val; } alias BerValue LDAP_BERVAL, BERVAL; alias BerValue* PLDAP_BERVAL, PBERVAL; enum ber_tag_t LBER_ERROR = -1, LBER_DEFAULT = -1, LBER_USE_DER = 1; /* FIXME: In MinGW, these are WINBERAPI == DECLSPEC_IMPORT. Linkage * attribute? */ extern (C) { BerElement* ber_init(const(BerValue)*); int ber_printf(BerElement*, const(char)*, ...); int ber_flatten(BerElement*, BerValue**); ber_tag_t ber_scanf(BerElement*, const(char)*, ...); ber_tag_t ber_peek_tag(BerElement*, ber_len_t*); ber_tag_t ber_skip_tag(BerElement*, ber_len_t*); ber_tag_t ber_first_element(BerElement*, ber_len_t*, char**); ber_tag_t ber_next_element(BerElement*, ber_len_t*, char*); void ber_bvfree(BerValue*); void ber_bvecfree(BerValue**); void ber_free(BerElement*, int); BerValue* ber_bvdup(BerValue*); BerElement* ber_alloc_t(int); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmapibuf.d0000664000175000017500000000122412776214756023455 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmapibuf.d) */ module core.sys.windows.lmapibuf; version (Windows): pragma(lib, "netapi32"); private import core.sys.windows.lmcons, core.sys.windows.windef; extern (Windows) { NET_API_STATUS NetApiBufferAllocate(DWORD, PVOID*); NET_API_STATUS NetApiBufferFree(PVOID); NET_API_STATUS NetApiBufferReallocate(PVOID, DWORD, PVOID*); NET_API_STATUS NetApiBufferSize(PVOID, PDWORD); NET_API_STATUS NetapipBufferAllocate(DWORD, PVOID*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/iprtrmib.d0000664000175000017500000001330012776214756023504 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_iprtrmib.d) */ module core.sys.windows.iprtrmib; version (Windows): import core.sys.windows.ipifcons; private import core.sys.windows.windef; // FIXME: check types of constants enum size_t MAXLEN_PHYSADDR = 8, MAXLEN_IFDESCR = 256, MAX_INTERFACE_NAME_LEN = 256; enum { MIB_IPNET_TYPE_OTHER = 1, MIB_IPNET_TYPE_INVALID, MIB_IPNET_TYPE_DYNAMIC, MIB_IPNET_TYPE_STATIC } enum { MIB_TCP_RTO_OTHER = 1, MIB_TCP_RTO_CONSTANT, MIB_TCP_RTO_RSRE, MIB_TCP_RTO_VANJ } enum { MIB_TCP_STATE_CLOSED = 1, MIB_TCP_STATE_LISTEN, MIB_TCP_STATE_SYN_SENT, MIB_TCP_STATE_SYN_RCVD, MIB_TCP_STATE_ESTAB, MIB_TCP_STATE_FIN_WAIT1, MIB_TCP_STATE_FIN_WAIT2, MIB_TCP_STATE_CLOSE_WAIT, MIB_TCP_STATE_CLOSING, MIB_TCP_STATE_LAST_ACK, MIB_TCP_STATE_TIME_WAIT, MIB_TCP_STATE_DELETE_TCB // = 12 } enum DWORD MIB_USE_CURRENT_TTL = -1, MIB_USE_CURRENT_FORWARDING = -1, MIB_TCP_MAXCONN_DYNAMIC = -1; struct MIB_IPADDRROW { DWORD dwAddr; DWORD dwIndex; DWORD dwMask; DWORD dwBCastAddr; DWORD dwReasmSize; ushort unused1; ushort unused2; } alias MIB_IPADDRROW* PMIB_IPADDRROW; struct MIB_IPADDRTABLE { DWORD dwNumEntries; MIB_IPADDRROW[1] _table; MIB_IPADDRROW* table() return { return _table.ptr; } } alias MIB_IPADDRTABLE* PMIB_IPADDRTABLE; struct MIB_IPFORWARDROW { DWORD dwForwardDest; DWORD dwForwardMask; DWORD dwForwardPolicy; DWORD dwForwardNextHop; DWORD dwForwardIfIndex; DWORD dwForwardType; DWORD dwForwardProto; DWORD dwForwardAge; DWORD dwForwardNextHopAS; DWORD dwForwardMetric1; DWORD dwForwardMetric2; DWORD dwForwardMetric3; DWORD dwForwardMetric4; DWORD dwForwardMetric5; } alias MIB_IPFORWARDROW* PMIB_IPFORWARDROW; struct MIB_IPFORWARDTABLE { DWORD dwNumEntries; MIB_IPFORWARDROW[1] _table; MIB_IPFORWARDROW* table() return { return _table.ptr; } } alias MIB_IPFORWARDTABLE* PMIB_IPFORWARDTABLE; struct MIB_IPNETROW { DWORD dwIndex; DWORD dwPhysAddrLen; BYTE[MAXLEN_PHYSADDR] bPhysAddr; DWORD dwAddr; DWORD dwType; } alias MIB_IPNETROW* PMIB_IPNETROW; struct MIB_IPNETTABLE { DWORD dwNumEntries; MIB_IPNETROW[1] _table; MIB_IPNETROW* table() return { return _table.ptr; } } alias MIB_IPNETTABLE* PMIB_IPNETTABLE; struct MIBICMPSTATS { DWORD dwMsgs; DWORD dwErrors; DWORD dwDestUnreachs; DWORD dwTimeExcds; DWORD dwParmProbs; DWORD dwSrcQuenchs; DWORD dwRedirects; DWORD dwEchos; DWORD dwEchoReps; DWORD dwTimestamps; DWORD dwTimestampReps; DWORD dwAddrMasks; DWORD dwAddrMaskReps; } alias MIBICMPSTATS* PMIBICMPSTATS; struct MIBICMPINFO { MIBICMPSTATS icmpInStats; MIBICMPSTATS icmpOutStats; } alias MIBICMPINFO* PMIBICMPINFO; struct MIB_ICMP { MIBICMPINFO stats; } alias MIB_ICMP* PMIB_ICMP; struct MIB_IFROW { WCHAR[MAX_INTERFACE_NAME_LEN] wszName; DWORD dwIndex; DWORD dwType; DWORD dwMtu; DWORD dwSpeed; DWORD dwPhysAddrLen; BYTE[MAXLEN_PHYSADDR] bPhysAddr; DWORD dwAdminStatus; DWORD dwOperStatus; DWORD dwLastChange; DWORD dwInOctets; DWORD dwInUcastPkts; DWORD dwInNUcastPkts; DWORD dwInDiscards; DWORD dwInErrors; DWORD dwInUnknownProtos; DWORD dwOutOctets; DWORD dwOutUcastPkts; DWORD dwOutNUcastPkts; DWORD dwOutDiscards; DWORD dwOutErrors; DWORD dwOutQLen; DWORD dwDescrLen; BYTE[MAXLEN_IFDESCR] bDescr; } alias MIB_IFROW* PMIB_IFROW; struct MIB_IFTABLE { DWORD dwNumEntries; MIB_IFROW[1] _table; MIB_IFROW* table() return { return _table.ptr; } } alias MIB_IFTABLE* PMIB_IFTABLE; struct MIB_IPSTATS { DWORD dwForwarding; DWORD dwDefaultTTL; DWORD dwInReceives; DWORD dwInHdrErrors; DWORD dwInAddrErrors; DWORD dwForwDatagrams; DWORD dwInUnknownProtos; DWORD dwInDiscards; DWORD dwInDelivers; DWORD dwOutRequests; DWORD dwRoutingDiscards; DWORD dwOutDiscards; DWORD dwOutNoRoutes; DWORD dwReasmTimeout; DWORD dwReasmReqds; DWORD dwReasmOks; DWORD dwReasmFails; DWORD dwFragOks; DWORD dwFragFails; DWORD dwFragCreates; DWORD dwNumIf; DWORD dwNumAddr; DWORD dwNumRoutes; } alias MIB_IPSTATS* PMIB_IPSTATS; struct MIB_TCPSTATS { DWORD dwRtoAlgorithm; DWORD dwRtoMin; DWORD dwRtoMax; DWORD dwMaxConn; DWORD dwActiveOpens; DWORD dwPassiveOpens; DWORD dwAttemptFails; DWORD dwEstabResets; DWORD dwCurrEstab; DWORD dwInSegs; DWORD dwOutSegs; DWORD dwRetransSegs; DWORD dwInErrs; DWORD dwOutRsts; DWORD dwNumConns; } alias MIB_TCPSTATS* PMIB_TCPSTATS; struct MIB_TCPROW { DWORD dwState; DWORD dwLocalAddr; DWORD dwLocalPort; DWORD dwRemoteAddr; DWORD dwRemotePort; } alias MIB_TCPROW* PMIB_TCPROW; struct MIB_TCPTABLE { DWORD dwNumEntries; MIB_TCPROW[1] _table; MIB_TCPROW* table() return { return _table.ptr; } } alias MIB_TCPTABLE* PMIB_TCPTABLE; struct MIB_UDPSTATS { DWORD dwInDatagrams; DWORD dwNoPorts; DWORD dwInErrors; DWORD dwOutDatagrams; DWORD dwNumAddrs; } alias MIB_UDPSTATS* PMIB_UDPSTATS; struct MIB_UDPROW { DWORD dwLocalAddr; DWORD dwLocalPort; } alias MIB_UDPROW* PMIB_UDPROW; struct MIB_UDPTABLE { DWORD dwNumEntries; MIB_UDPROW[1] _table; MIB_UDPROW* table() return { return _table.ptr; } } alias MIB_UDPTABLE* PMIB_UDPTABLE; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/wtypes.d0000664000175000017500000001047212776214756023216 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_wtypes.d) */ module core.sys.windows.wtypes; version (Windows): import core.sys.windows.rpc, core.sys.windows.rpcndr; private import core.sys.windows.windef; private import core.sys.windows.uuid; // for GUID_NULL alias GUID_NULL IID_NULL, CLSID_NULL; enum ROTFLAGS_REGISTRATIONKEEPSALIVE = 0x01; enum ROTFLAGS_ALLOWANYCLIENT = 0x02; // also in winsock2.h struct BLOB { ULONG cbSize; BYTE* pBlobData; } alias BLOB* PBLOB, LPBLOB; enum DVASPECT { DVASPECT_CONTENT = 1, DVASPECT_THUMBNAIL = 2, DVASPECT_ICON = 4, DVASPECT_DOCPRINT = 8 } enum DVASPECT2 { DVASPECT_OPAQUE = 16, DVASPECT_TRANSPARENT = 32 } enum STATFLAG { STATFLAG_DEFAULT = 0, STATFLAG_NONAME = 1 } enum MEMCTX { MEMCTX_LOCAL = 0, MEMCTX_TASK, MEMCTX_SHARED, MEMCTX_MACSYSTEM, MEMCTX_UNKNOWN = -1, MEMCTX_SAME = -2 } enum MSHCTX { MSHCTX_LOCAL = 0, MSHCTX_NOSHAREDMEM, MSHCTX_DIFFERENTMACHINE, MSHCTX_INPROC, MSHCTX_CROSSCTX } enum CLSCTX { CLSCTX_INPROC_SERVER = 0x1, CLSCTX_INPROC_HANDLER = 0x2, CLSCTX_LOCAL_SERVER = 0x4, CLSCTX_INPROC_SERVER16 = 0x8, CLSCTX_REMOTE_SERVER = 0x10, CLSCTX_INPROC_HANDLER16 = 0x20, CLSCTX_INPROC_SERVERX86 = 0x40, CLSCTX_INPROC_HANDLERX86 = 0x80, } enum MSHLFLAGS { MSHLFLAGS_NORMAL, MSHLFLAGS_TABLESTRONG, MSHLFLAGS_TABLEWEAK } struct FLAGGED_WORD_BLOB { uint fFlags; uint clSize; ushort[1] asData; } alias WCHAR OLECHAR; alias LPWSTR LPOLESTR; alias LPCWSTR LPCOLESTR; alias ushort VARTYPE; alias short VARIANT_BOOL; alias VARIANT_BOOL _VARIANT_BOOL; enum VARIANT_BOOL VARIANT_TRUE = -1; // 0xffff; enum VARIANT_BOOL VARIANT_FALSE = 0; alias OLECHAR* BSTR; alias FLAGGED_WORD_BLOB* wireBSTR; alias BSTR* LPBSTR; //alias LONG SCODE; // also in winerror mixin DECLARE_HANDLE!("HCONTEXT"); mixin DECLARE_HANDLE!("HMETAFILEPICT"); union CY { struct { uint Lo; int Hi; } LONGLONG int64; } alias double DATE; struct BSTRBLOB { ULONG cbSize; PBYTE pData; } alias BSTRBLOB* LPBSTRBLOB; // Used only in the PROPVARIANT structure // According to the 2003 SDK, this should be in propidl.h, not here. struct CLIPDATA { ULONG cbSize; int ulClipFmt; PBYTE pClipData; } enum STGC { STGC_DEFAULT, STGC_OVERWRITE, STGC_ONLYIFCURRENT, STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE } enum STGMOVE { STGMOVE_MOVE, STGMOVE_COPY, STGMOVE_SHALLOWCOPY } enum VARENUM { VT_EMPTY, VT_NULL, VT_I2, VT_I4, VT_R4, VT_R8, VT_CY, VT_DATE, VT_BSTR, VT_DISPATCH, VT_ERROR, VT_BOOL, VT_VARIANT, VT_UNKNOWN, VT_DECIMAL, VT_I1 = 16, VT_UI1, VT_UI2, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT, VT_VOID, VT_HRESULT, VT_PTR, VT_SAFEARRAY, VT_CARRAY, VT_USERDEFINED, VT_LPSTR, VT_LPWSTR, VT_RECORD = 36, VT_INT_PTR = 37, VT_UINT_PTR = 38, VT_FILETIME = 64, VT_BLOB, VT_STREAM, VT_STORAGE, VT_STREAMED_OBJECT, VT_STORED_OBJECT, VT_BLOB_OBJECT, VT_CF, VT_CLSID, VT_BSTR_BLOB = 0xfff, VT_VECTOR = 0x1000, VT_ARRAY = 0x2000, VT_BYREF = 0x4000, VT_RESERVED = 0x8000, VT_ILLEGAL = 0xffff, VT_ILLEGALMASKED = 0xfff, VT_TYPEMASK = 0xfff }; struct BYTE_SIZEDARR { uint clSize; byte* pData; } struct WORD_SIZEDARR { uint clSize; ushort* pData; } struct DWORD_SIZEDARR { uint clSize; uint* pData; } struct HYPER_SIZEDARR { uint clSize; hyper* pData; } alias double DOUBLE; struct DECIMAL { USHORT wReserved; union { struct { ubyte scale; // valid values are 0 to 28 ubyte sign; // 0 for positive, DECIMAL_NEG for negatives. enum ubyte DECIMAL_NEG = 0x80; } USHORT signscale; } ULONG Hi32; union { struct { ULONG Lo32; ULONG Mid32; } ULONGLONG Lo64; } // #define DECIMAL_SETZERO(d) {(d).Lo64=(d).Hi32=(d).signscale=0;} void setZero() { Lo64 = 0; Hi32 = 0; signscale = 0; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmwksta.d0000664000175000017500000002563012776214756023347 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmwksta.d) */ module core.sys.windows.lmwksta; version (Windows): pragma(lib, "netapi32"); import core.sys.windows.lmuseflg; private import core.sys.windows.lmcons, core.sys.windows.windef; pragma(lib, "Netapi32"); enum { WKSTA_COMPUTERNAME_PARMNUM = 1, WKSTA_LANGROUP_PARMNUM, // = 2 WKSTA_VER_MAJOR_PARMNUM = 4, WKSTA_VER_MINOR_PARMNUM, WKSTA_LOGGED_ON_USERS_PARMNUM, WKSTA_LANROOT_PARMNUM, WKSTA_LOGON_DOMAIN_PARMNUM, WKSTA_LOGON_SERVER_PARMNUM, WKSTA_CHARWAIT_PARMNUM, WKSTA_CHARTIME_PARMNUM, WKSTA_CHARCOUNT_PARMNUM, WKSTA_KEEPCONN_PARMNUM, WKSTA_KEEPSEARCH_PARMNUM, WKSTA_MAXCMDS_PARMNUM, WKSTA_NUMWORKBUF_PARMNUM, WKSTA_MAXWRKCACHE_PARMNUM, WKSTA_SESSTIMEOUT_PARMNUM, WKSTA_SIZERROR_PARMNUM, WKSTA_NUMALERTS_PARMNUM, WKSTA_NUMSERVICES_PARMNUM, WKSTA_NUMCHARBUF_PARMNUM, WKSTA_SIZCHARBUF_PARMNUM, // = 23 WKSTA_ERRLOGSZ_PARMNUM = 27, WKSTA_PRINTBUFTIME_PARMNUM, WKSTA_SIZWORKBUF_PARMNUM, WKSTA_MAILSLOTS_PARMNUM, WKSTA_NUMDGRAMBUF_PARMNUM, WKSTA_WRKHEURISTICS_PARMNUM, WKSTA_MAXTHREADS_PARMNUM, // = 33 WKSTA_LOCKQUOTA_PARMNUM = 41, WKSTA_LOCKINCREMENT_PARMNUM, WKSTA_LOCKMAXIMUM_PARMNUM, WKSTA_PIPEINCREMENT_PARMNUM, WKSTA_PIPEMAXIMUM_PARMNUM, WKSTA_DORMANTFILELIMIT_PARMNUM, WKSTA_CACHEFILETIMEOUT_PARMNUM, WKSTA_USEOPPORTUNISTICLOCKING_PARMNUM, WKSTA_USEUNLOCKBEHIND_PARMNUM, WKSTA_USECLOSEBEHIND_PARMNUM, WKSTA_BUFFERNAMEDPIPES_PARMNUM, WKSTA_USELOCKANDREADANDUNLOCK_PARMNUM, WKSTA_UTILIZENTCACHING_PARMNUM, WKSTA_USERAWREAD_PARMNUM, WKSTA_USERAWWRITE_PARMNUM, WKSTA_USEWRITERAWWITHDATA_PARMNUM, WKSTA_USEENCRYPTION_PARMNUM, WKSTA_BUFFILESWITHDENYWRITE_PARMNUM, WKSTA_BUFFERREADONLYFILES_PARMNUM, WKSTA_FORCECORECREATEMODE_PARMNUM, WKSTA_USE512BYTESMAXTRANSFER_PARMNUM, WKSTA_READAHEADTHRUPUT_PARMNUM, // = 62 WKSTA_PLATFORM_ID_PARMNUM = 100, WKSTA_OTH_DOMAINS_PARMNUM = 101, TRANSPORT_QUALITYOFSERVICE_PARMNUM = 201, TRANSPORT_NAME_PARMNUM = 202 } struct WKSTA_INFO_100{ DWORD wki100_platform_id; LPWSTR wki100_computername; LPWSTR wki100_langroup; DWORD wki100_ver_major; DWORD wki100_ver_minor; } alias WKSTA_INFO_100* PWKSTA_INFO_100, LPWKSTA_INFO_100; struct WKSTA_INFO_101{ DWORD wki101_platform_id; LPWSTR wki101_computername; LPWSTR wki101_langroup; DWORD wki101_ver_major; DWORD wki101_ver_minor; LPWSTR wki101_lanroot; } alias WKSTA_INFO_101* PWKSTA_INFO_101, LPWKSTA_INFO_101; struct WKSTA_INFO_102{ DWORD wki102_platform_id; LPWSTR wki102_computername; LPWSTR wki102_langroup; DWORD wki102_ver_major; DWORD wki102_ver_minor; LPWSTR wki102_lanroot; DWORD wki102_logged_on_users; } alias WKSTA_INFO_102* PWKSTA_INFO_102, LPWKSTA_INFO_102; struct WKSTA_INFO_302{ DWORD wki302_char_wait; DWORD wki302_collection_time; DWORD wki302_maximum_collection_count; DWORD wki302_keep_conn; DWORD wki302_keep_search; DWORD wki302_max_cmds; DWORD wki302_num_work_buf; DWORD wki302_siz_work_buf; DWORD wki302_max_wrk_cache; DWORD wki302_sess_timeout; DWORD wki302_siz_error; DWORD wki302_num_alerts; DWORD wki302_num_services; DWORD wki302_errlog_sz; DWORD wki302_print_buf_time; DWORD wki302_num_char_buf; DWORD wki302_siz_char_buf; LPWSTR wki302_wrk_heuristics; DWORD wki302_mailslots; DWORD wki302_num_dgram_buf; } alias WKSTA_INFO_302* PWKSTA_INFO_302, LPWKSTA_INFO_302; struct WKSTA_INFO_402{ DWORD wki402_char_wait; DWORD wki402_collection_time; DWORD wki402_maximum_collection_count; DWORD wki402_keep_conn; DWORD wki402_keep_search; DWORD wki402_max_cmds; DWORD wki402_num_work_buf; DWORD wki402_siz_work_buf; DWORD wki402_max_wrk_cache; DWORD wki402_sess_timeout; DWORD wki402_siz_error; DWORD wki402_num_alerts; DWORD wki402_num_services; DWORD wki402_errlog_sz; DWORD wki402_print_buf_time; DWORD wki402_num_char_buf; DWORD wki402_siz_char_buf; LPWSTR wki402_wrk_heuristics; DWORD wki402_mailslots; DWORD wki402_num_dgram_buf; DWORD wki402_max_threads; } alias WKSTA_INFO_402* PWKSTA_INFO_402, LPWKSTA_INFO_402; struct WKSTA_INFO_502{ DWORD wki502_char_wait; DWORD wki502_collection_time; DWORD wki502_maximum_collection_count; DWORD wki502_keep_conn; DWORD wki502_max_cmds; DWORD wki502_sess_timeout; DWORD wki502_siz_char_buf; DWORD wki502_max_threads; DWORD wki502_lock_quota; DWORD wki502_lock_increment; DWORD wki502_lock_maximum; DWORD wki502_pipe_increment; DWORD wki502_pipe_maximum; DWORD wki502_cache_file_timeout; DWORD wki502_dormant_file_limit; DWORD wki502_read_ahead_throughput; DWORD wki502_num_mailslot_buffers; DWORD wki502_num_srv_announce_buffers; DWORD wki502_max_illegal_datagram_events; DWORD wki502_illegal_datagram_event_reset_frequency; BOOL wki502_log_election_packets; BOOL wki502_use_opportunistic_locking; BOOL wki502_use_unlock_behind; BOOL wki502_use_close_behind; BOOL wki502_buf_named_pipes; BOOL wki502_use_lock_read_unlock; BOOL wki502_utilize_nt_caching; BOOL wki502_use_raw_read; BOOL wki502_use_raw_write; BOOL wki502_use_write_raw_data; BOOL wki502_use_encryption; BOOL wki502_buf_files_deny_write; BOOL wki502_buf_read_only_files; BOOL wki502_force_core_create_mode; BOOL wki502_use_512_byte_max_transfer; } alias WKSTA_INFO_502* PWKSTA_INFO_502, LPWKSTA_INFO_502; struct WKSTA_INFO_1010 { DWORD wki1010_char_wait; } alias WKSTA_INFO_1010* PWKSTA_INFO_1010, LPWKSTA_INFO_1010; struct WKSTA_INFO_1011 { DWORD wki1011_collection_time; } alias WKSTA_INFO_1011* PWKSTA_INFO_1011, LPWKSTA_INFO_1011; struct WKSTA_INFO_1012 { DWORD wki1012_maximum_collection_count; } alias WKSTA_INFO_1012* PWKSTA_INFO_1012, LPWKSTA_INFO_1012; struct WKSTA_INFO_1027 { DWORD wki1027_errlog_sz; } alias WKSTA_INFO_1027* PWKSTA_INFO_1027, LPWKSTA_INFO_1027; struct WKSTA_INFO_1028 { DWORD wki1028_print_buf_time; } alias WKSTA_INFO_1028* PWKSTA_INFO_1028, LPWKSTA_INFO_1028; struct WKSTA_INFO_1032 { DWORD wki1032_wrk_heuristics; } alias WKSTA_INFO_1032* PWKSTA_INFO_1032, LPWKSTA_INFO_1032; struct WKSTA_INFO_1013 { DWORD wki1013_keep_conn; } alias WKSTA_INFO_1013* PWKSTA_INFO_1013, LPWKSTA_INFO_1013; struct WKSTA_INFO_1018 { DWORD wki1018_sess_timeout; } alias WKSTA_INFO_1018* PWKSTA_INFO_1018, LPWKSTA_INFO_1018; struct WKSTA_INFO_1023 { DWORD wki1023_siz_char_buf; } alias WKSTA_INFO_1023* PWKSTA_INFO_1023, LPWKSTA_INFO_1023; struct WKSTA_INFO_1033 { DWORD wki1033_max_threads; } alias WKSTA_INFO_1033* PWKSTA_INFO_1033, LPWKSTA_INFO_1033; struct WKSTA_INFO_1041 { DWORD wki1041_lock_quota; } alias WKSTA_INFO_1041* PWKSTA_INFO_1041, LPWKSTA_INFO_1041; struct WKSTA_INFO_1042 { DWORD wki1042_lock_increment; } alias WKSTA_INFO_1042* PWKSTA_INFO_1042, LPWKSTA_INFO_1042; struct WKSTA_INFO_1043 { DWORD wki1043_lock_maximum; } alias WKSTA_INFO_1043* PWKSTA_INFO_1043, LPWKSTA_INFO_1043; struct WKSTA_INFO_1044 { DWORD wki1044_pipe_increment; } alias WKSTA_INFO_1044* PWKSTA_INFO_1044, LPWKSTA_INFO_1044; struct WKSTA_INFO_1045 { DWORD wki1045_pipe_maximum; } alias WKSTA_INFO_1045* PWKSTA_INFO_1045, LPWKSTA_INFO_1045; struct WKSTA_INFO_1046 { DWORD wki1046_dormant_file_limit; } alias WKSTA_INFO_1046* PWKSTA_INFO_1046, LPWKSTA_INFO_1046; struct WKSTA_INFO_1047 { DWORD wki1047_cache_file_timeout; } alias WKSTA_INFO_1047* PWKSTA_INFO_1047, LPWKSTA_INFO_1047; struct WKSTA_INFO_1048 { BOOL wki1048_use_opportunistic_locking; } alias WKSTA_INFO_1048* PWKSTA_INFO_1048, LPWKSTA_INFO_1048; struct WKSTA_INFO_1049 { BOOL wki1049_use_unlock_behind; } alias WKSTA_INFO_1049* PWKSTA_INFO_1049, LPWKSTA_INFO_1049; struct WKSTA_INFO_1050 { BOOL wki1050_use_close_behind; } alias WKSTA_INFO_1050* PWKSTA_INFO_1050, LPWKSTA_INFO_1050; struct WKSTA_INFO_1051 { BOOL wki1051_buf_named_pipes; } alias WKSTA_INFO_1051* PWKSTA_INFO_1051, LPWKSTA_INFO_1051; struct WKSTA_INFO_1052 { BOOL wki1052_use_lock_read_unlock; } alias WKSTA_INFO_1052* PWKSTA_INFO_1052, LPWKSTA_INFO_1052; struct WKSTA_INFO_1053 { BOOL wki1053_utilize_nt_caching; } alias WKSTA_INFO_1053* PWKSTA_INFO_1053, LPWKSTA_INFO_1053; struct WKSTA_INFO_1054 { BOOL wki1054_use_raw_read; } alias WKSTA_INFO_1054* PWKSTA_INFO_1054, LPWKSTA_INFO_1054; struct WKSTA_INFO_1055 { BOOL wki1055_use_raw_write; } alias WKSTA_INFO_1055* PWKSTA_INFO_1055, LPWKSTA_INFO_1055; struct WKSTA_INFO_1056 { BOOL wki1056_use_write_raw_data; } alias WKSTA_INFO_1056* PWKSTA_INFO_1056, LPWKSTA_INFO_1056; struct WKSTA_INFO_1057 { BOOL wki1057_use_encryption; } alias WKSTA_INFO_1057* PWKSTA_INFO_1057, LPWKSTA_INFO_1057; struct WKSTA_INFO_1058 { BOOL wki1058_buf_files_deny_write; } alias WKSTA_INFO_1058* PWKSTA_INFO_1058, LPWKSTA_INFO_1058; struct WKSTA_INFO_1059 { BOOL wki1059_buf_read_only_files; } alias WKSTA_INFO_1059* PWKSTA_INFO_1059, LPWKSTA_INFO_1059; struct WKSTA_INFO_1060 { BOOL wki1060_force_core_create_mode; } alias WKSTA_INFO_1060* PWKSTA_INFO_1060, LPWKSTA_INFO_1060; struct WKSTA_INFO_1061 { BOOL wki1061_use_512_byte_max_transfer; } alias WKSTA_INFO_1061* PWKSTA_INFO_1061, LPWKSTA_INFO_1061; struct WKSTA_INFO_1062 { DWORD wki1062_read_ahead_throughput; } alias WKSTA_INFO_1062* PWKSTA_INFO_1062, LPWKSTA_INFO_1062; struct WKSTA_USER_INFO_0 { LPWSTR wkui0_username; } alias WKSTA_USER_INFO_0* PWKSTA_USER_INFO_0, LPWKSTA_USER_INFO_0; struct WKSTA_USER_INFO_1{ LPWSTR wkui1_username; LPWSTR wkui1_logon_domain; LPWSTR wkui1_oth_domains; LPWSTR wkui1_logon_server; } alias WKSTA_USER_INFO_1* PWKSTA_USER_INFO_1, LPWKSTA_USER_INFO_1; struct WKSTA_USER_INFO_1101 { LPWSTR wkui1101_oth_domains; } alias WKSTA_USER_INFO_1101* PWKSTA_USER_INFO_1101, LPWKSTA_USER_INFO_1101; struct WKSTA_TRANSPORT_INFO_0{ DWORD wkti0_quality_of_service; DWORD wkti0_number_of_vcs; LPWSTR wkti0_transport_name; LPWSTR wkti0_transport_address; BOOL wkti0_wan_ish; } alias WKSTA_TRANSPORT_INFO_0* PWKSTA_TRANSPORT_INFO_0, LPWKSTA_TRANSPORT_INFO_0; extern (Windows) { NET_API_STATUS NetWkstaGetInfo(LPWSTR,DWORD,PBYTE*); NET_API_STATUS NetWkstaSetInfo(LPWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetWkstaUserGetInfo(LPWSTR,DWORD,PBYTE*); NET_API_STATUS NetWkstaUserSetInfo(LPWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetWkstaUserEnum(LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); NET_API_STATUS NetWkstaTransportAdd(LPWSTR,DWORD,PBYTE,PDWORD); NET_API_STATUS NetWkstaTransportDel(LPWSTR,LPWSTR,DWORD); NET_API_STATUS NetWkstaTransportEnum(LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmalert.d0000664000175000017500000000402312776214756023316 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmalert.d) */ module core.sys.windows.lmalert; version (Windows): pragma(lib, "netapi32"); private import core.sys.windows.lmcons, core.sys.windows.windef; const TCHAR[] ALERTER_MAILSLOT = `\\.\MAILSLOT\Alerter`, ALERT_PRINT_EVENT = "PRINTING", ALERT_MESSAGE_EVENT = "MESSAGE", ALERT_ERRORLOG_EVENT = "ERRORLOG", ALERT_ADMIN_EVENT = "ADMIN", ALERT_USER_EVENT = "USER"; //MACRO #define ALERT_OTHER_INFO(x) ((PBYTE)(x)+sizeof(STD_ALERT)) //MACRO #define ALERT_VAR_DATA(p) ((PBYTE)(p)+sizeof(*p)) enum PRJOB_QSTATUS = 3; enum PRJOB_DEVSTATUS = 508; enum PRJOB_COMPLETE = 4; enum PRJOB_INTERV = 8; enum PRJOB_ = 16; enum PRJOB_DESTOFFLINE = 32; enum PRJOB_DESTPAUSED = 64; enum PRJOB_NOTIFY = 128; enum PRJOB_DESTNOPAPER = 256; enum PRJOB_DELETED = 32768; enum PRJOB_QS_QUEUED = 0; enum PRJOB_QS_PAUSED = 1; enum PRJOB_QS_SPOOLING = 2; enum PRJOB_QS_PRINTING = 3; struct ADMIN_OTHER_INFO{ DWORD alrtad_errcode; DWORD alrtad_numstrings; } alias ADMIN_OTHER_INFO* PADMIN_OTHER_INFO, LPADMIN_OTHER_INFO; struct STD_ALERT{ DWORD alrt_timestamp; TCHAR[EVLEN+1] alrt_eventname; TCHAR[SNLEN+1] alrt_servicename; } alias STD_ALERT* PSTD_ALERT, LPSTD_ALERT; struct ERRLOG_OTHER_INFO{ DWORD alrter_errcode; DWORD alrter_offset; } alias ERRLOG_OTHER_INFO* PERRLOG_OTHER_INFO, LPERRLOG_OTHER_INFO; struct PRINT_OTHER_INFO{ DWORD alrtpr_jobid; DWORD alrtpr_status; DWORD alrtpr_submitted; DWORD alrtpr_size; } alias PRINT_OTHER_INFO* PPRINT_OTHER_INFO, LPPRINT_OTHER_INFO; struct USER_OTHER_INFO{ DWORD alrtus_errcode; DWORD alrtus_numstrings; } alias USER_OTHER_INFO* PUSER_OTHER_INFO, LPUSER_OTHER_INFO; extern (Windows) { NET_API_STATUS NetAlertRaise(LPCWSTR,PVOID,DWORD); NET_API_STATUS NetAlertRaiseEx(LPCWSTR,PVOID,DWORD,LPCWSTR); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/dbghelp_types.d0000664000175000017500000001135212776214756024512 0ustar kaikai/** * ... * * Copyright: Copyright Benjamin Thaut 2010 - 2011. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Benjamin Thaut, Sean Kelly * Source: $(DRUNTIMESRC core/sys/windows/_dbghelp_types.d) */ module core.sys.windows.dbghelp_types; version (Windows): version (ANSI) {} else version = Unicode; import core.sys.windows.windows; public import core.sys.windows.winnt : TCHAR; /* enum ADDRESS_MODE : DWORD { AddrMode1616 = 0, AddrMode1632 = 1, AddrModeReal = 2, AddrModeFlat = 3, } */ enum : DWORD { SYMOPT_DEFERRED_LOAD = 0x00000004, SYMOPT_FAIL_CRITICAL_ERRORS = 0x00000200, SYMOPT_LOAD_LINES = 0x00000010, SYMOPT_DEBUG = 0x80000000, } enum : ULONG { CBA_READ_MEMORY = 0x00000006, CBA_DEBUG_INFO = 0x10000000, } public import core.sys.windows.basetyps : GUID; struct ADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; } struct KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64[5] Reserved; } struct STACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; PVOID FuncTableEntry; DWORD64[4] Params; BOOL Far; BOOL Virtual; DWORD64[3] Reserved; KDHELP64 KdHelp; } public import core.sys.windows.winnt : IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_IA64, IMAGE_FILE_MACHINE_AMD64; struct IMAGEHLP_LINEA64 { DWORD SizeOfStruct; PVOID Key; DWORD LineNumber; PCSTR FileName; DWORD64 Address; } struct IMAGEHLP_LINEW64 { DWORD SizeOfStruct; PVOID Key; DWORD LineNumber; PWSTR FileName; DWORD64 Address; } enum SYM_TYPE : int { SymNone = 0, SymCoff, SymCv, SymPdb, SymExport, SymDeferred, SymSym, SymDia, SymVirtual, NumSymTypes, } struct IMAGEHLP_MODULEA64 { DWORD SizeOfStruct; DWORD64 BaseOfImage; DWORD ImageSize; DWORD TimeDateStamp; DWORD CheckSum; DWORD NumSyms; SYM_TYPE SymType; CHAR[32] ModuleName; CHAR[256] ImageName; CHAR[256] LoadedImageName; // new elements: 07-Jun-2002 version (none) { CHAR[256] LoadedPdbName; DWORD CVSig; CHAR[MAX_PATH*3] CVData; DWORD PdbSig; GUID PdbSig70; DWORD PdbAge; BOOL PdbUnmatched; BOOL DbgUnmachted; BOOL LineNumbers; BOOL GlobalSymbols; BOOL TypeInfo; } // new elements: 17-Dec-2003 version (none) { BOOL SourceIndexed; BOOL Publics; } } struct IMAGEHLP_MODULEW64 { DWORD SizeOfStruct; DWORD64 BaseOfImage; DWORD ImageSize; DWORD TimeDateStamp; DWORD CheckSum; DWORD NumSyms; SYM_TYPE SymType; WCHAR[32] ModuleName; WCHAR[256] ImageName; WCHAR[256] LoadedImageName; // new elements: 07-Jun-2002 version (none) { WCHAR[256] LoadedPdbName; DWORD CVSig; WCHAR[MAX_PATH*3] CVData; DWORD PdbSig; GUID PdbSig70; DWORD PdbAge; BOOL PdbUnmatched; BOOL DbgUnmachted; BOOL LineNumbers; BOOL GlobalSymbols; BOOL TypeInfo; } // new elements: 17-Dec-2003 version (none) { BOOL SourceIndexed; BOOL Publics; } } struct IMAGEHLP_SYMBOLA64 { DWORD SizeOfStruct; DWORD64 Address; DWORD Size; DWORD Flags; DWORD MaxNameLength; CHAR[1] Name; } struct IMAGEHLP_SYMBOLW64 { DWORD SizeOfStruct; DWORD64 Address; DWORD Size; DWORD Flags; DWORD MaxNameLength; WCHAR[1] Name; } struct IMAGEHLP_CBA_READ_MEMORY { DWORD64 addr; PVOID buf; DWORD bytes; DWORD *bytesread; } struct API_VERSION { USHORT MajorVersion; USHORT MinorVersion; USHORT Revision; USHORT Reserved; } version (Unicode) { alias IMAGEHLP_LINEW64 IMAGEHLP_LINE64; alias IMAGEHLP_MODULEW64 IMAGEHLP_MODULE64; alias IMAGEHLP_SYMBOLW64 IMAGEHLP_SYMBOL64; } else { alias IMAGEHLP_LINEA64 IMAGEHLP_LINE64; alias IMAGEHLP_MODULEA64 IMAGEHLP_MODULE64; alias IMAGEHLP_SYMBOLA64 IMAGEHLP_SYMBOL64; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/oaidl.d0000664000175000017500000004012012776214756022744 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_oaidl.d) */ module core.sys.windows.oaidl; version (Windows): private import core.sys.windows.basetyps, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.wtypes; enum DISPID_UNKNOWN = -1; enum DISPID_VALUE = 0; enum DISPID_PROPERTYPUT = -3; enum DISPID_NEWENUM = -4; enum DISPID_EVALUATE = -5; enum DISPID_CONSTRUCTOR = -6; enum DISPID_DESTRUCTOR = -7; enum DISPID_COLLECT = -8; enum FADF_AUTO = 1; enum FADF_STATIC = 2; enum FADF_EMBEDDED = 4; enum FADF_FIXEDSIZE = 16; enum FADF_RECORD = 32; enum FADF_HAVEIID = 64; enum FADF_HAVEVARTYPE = 128; enum FADF_BSTR = 256; enum FADF_UNKNOWN = 512; enum FADF_DISPATCH = 1024; enum FADF_VARIANT = 2048; enum FADF_RESERVED = 0xf0e8; enum FADF_DATADELETED = 0x1000; enum FADF_CREATEVECTOR = 0x2000; enum PARAMFLAG_NONE = 0; enum PARAMFLAG_FIN = 1; enum PARAMFLAG_FOUT = 2; enum PARAMFLAG_FLCID = 4; enum PARAMFLAG_FRETVAL = 8; enum PARAMFLAG_FOPT = 16; enum PARAMFLAG_FHASDEFAULT = 32; enum IDLFLAG_NONE = PARAMFLAG_NONE; enum IDLFLAG_FIN = PARAMFLAG_FIN; enum IDLFLAG_FOUT = PARAMFLAG_FOUT; enum IDLFLAG_FLCID = PARAMFLAG_FLCID; enum IDLFLAG_FRETVAL = PARAMFLAG_FRETVAL; enum IMPLTYPEFLAG_FDEFAULT = 1; enum IMPLTYPEFLAG_FSOURCE = 2; enum IMPLTYPEFLAG_FRESTRICTED = 4; enum IMPLTYPEFLAG_FDEFAULTVTABLE = 8; enum SYSKIND { SYS_WIN16, SYS_WIN32, SYS_MAC } enum LIBFLAGS { LIBFLAG_FRESTRICTED = 1, LIBFLAG_FCONTROL = 2, LIBFLAG_FHIDDEN = 4, LIBFLAG_FHASDISKIMAGE = 8 } struct TLIBATTR { GUID guid; LCID lcid; SYSKIND syskind; WORD wMajorVerNum; WORD wMinorVerNum; WORD wLibFlags; } alias TLIBATTR* LPTLIBATTR; alias CY CURRENCY; struct SAFEARRAYBOUND { ULONG cElements; LONG lLbound; } alias SAFEARRAYBOUND* LPSAFEARRAYBOUND; struct SAFEARR_BSTR { ULONG Size; wireBSTR* aBstr; } struct SAFEARR_UNKNOWN { ULONG Size; IUnknown* apUnknown; } struct SAFEARR_DISPATCH { ULONG Size; LPDISPATCH* apDispatch; } struct SAFEARR_VARIANT { ULONG Size; _wireVARIANT* aVariant; } enum SF_TYPE { SF_ERROR=VARENUM.VT_ERROR, SF_I1=VARENUM.VT_I1, SF_I2=VARENUM.VT_I2, SF_I4=VARENUM.VT_I4, SF_I8=VARENUM.VT_I8, SF_BSTR=VARENUM.VT_BSTR, SF_UNKNOWN=VARENUM.VT_UNKNOWN, SF_DISPATCH=VARENUM.VT_DISPATCH, SF_VARIANT=VARENUM.VT_VARIANT } struct _wireBRECORD { ULONG fFlags; ULONG clSize; LPRECORDINFO* pRecInfo; byte* pRecord; } alias _wireBRECORD* wireBRECORD; struct SAFEARR_BRECORD { ULONG Size; wireBRECORD* aRecord; } struct SAFEARR_HAVEIID { ULONG Size; IUnknown* apUnknown; IID iid; } struct SAFEARRAYUNION { ULONG sfType; union _u { SAFEARR_BSTR BstrStr; SAFEARR_UNKNOWN UnknownStr; SAFEARR_DISPATCH DispatchStr; SAFEARR_VARIANT VariantStr; SAFEARR_BRECORD RecordStr; SAFEARR_HAVEIID HaveIidStr; BYTE_SIZEDARR ByteStr; WORD_SIZEDARR WordStr; DWORD_SIZEDARR LongStr; HYPER_SIZEDARR HyperStr; } _u u; } struct _wireSAFEARRAY { USHORT cDims; USHORT fFeatures; ULONG cbElements; ULONG cLocks; SAFEARRAYUNION uArrayStructs; SAFEARRAYBOUND[1] rgsabound; } alias _wireSAFEARRAY* wireSAFEARRAY; alias wireSAFEARRAY* wirePSAFEARRAY; struct SAFEARRAY { USHORT cDims; USHORT fFeatures; ULONG cbElements; ULONG cLocks; PVOID pvData; SAFEARRAYBOUND[1] rgsabound; } alias SAFEARRAY* LPSAFEARRAY; struct VARIANT { union { struct { VARTYPE vt; WORD wReserved1; WORD wReserved2; WORD wReserved3; union { int lVal; LONGLONG llVal; ubyte bVal; short iVal; float fltVal; double dblVal; VARIANT_BOOL boolVal; SCODE scode; CY cyVal; DATE date; BSTR bstrVal; IUnknown punkVal; IDispatch pdispVal; SAFEARRAY* parray; ubyte* pbVal; short* piVal; int* plVal; float* pfltVal; double* pdblVal; VARIANT_BOOL* pboolVal; _VARIANT_BOOL* pbool; SCODE* pscode; CY* pcyVal; DATE* pdate; BSTR* pbstrVal; IUnknown* ppunkVal; IDispatch* ppdispVal; SAFEARRAY** pparray; VARIANT* pvarVal; void* byref; CHAR cVal; USHORT uiVal; ULONG ulVal; ULONGLONG ullVal; INT intVal; UINT uintVal; DECIMAL* pdecVal; CHAR* pcVal; USHORT* puiVal; ULONG* pulVal; INT* pintVal; UINT* puintVal; struct { PVOID pvRecord; IRecordInfo pRecInfo; } } } DECIMAL decVal; } } alias VARIANT* LPVARIANT; alias VARIANT VARIANTARG; alias VARIANT* LPVARIANTARG; struct _wireVARIANT { DWORD clSize; DWORD rpcReserved; USHORT vt; USHORT wReserved1; USHORT wReserved2; USHORT wReserved3; union { LONG lVal; LONGLONG llVal; BYTE bVal; SHORT iVal; FLOAT fltVal; DOUBLE dblVal; VARIANT_BOOL boolVal; SCODE scode; CY cyVal; DATE date; wireBSTR bstrVal; IUnknown punkVal; LPDISPATCH pdispVal; wirePSAFEARRAY parray; wireBRECORD brecVal; BYTE* pbVal; SHORT* piVal; LONG* plVal; FLOAT* pfltVal; DOUBLE* pdblVal; VARIANT_BOOL* pboolVal; SCODE* pscode; CY* pcyVal; DATE* pdate; wireBSTR* pbstrVal; IUnknown* ppunkVal; LPDISPATCH* ppdispVal; wirePSAFEARRAY* pparray; wireVARIANT* pvarVal; CHAR cVal; USHORT uiVal; ULONG ulVal; ULONGLONG ullVal; INT intVal; UINT uintVal; DECIMAL decVal; DECIMAL* pdecVal; CHAR* pcVal; USHORT* puiVal; ULONG* pulVal; INT* pintVal; UINT* puintVal; } } alias _wireVARIANT* wireVARIANT; alias LONG DISPID; alias DISPID MEMBERID; alias DWORD HREFTYPE; enum TYPEKIND { TKIND_ENUM, TKIND_RECORD, TKIND_MODULE, TKIND_INTERFACE, TKIND_DISPATCH, TKIND_COCLASS, TKIND_ALIAS, TKIND_UNION, TKIND_MAX } struct TYPEDESC { union { TYPEDESC* lptdesc; ARRAYDESC* lpadesc; HREFTYPE hreftype; } VARTYPE vt; } struct ARRAYDESC { TYPEDESC tdescElem; USHORT cDims; SAFEARRAYBOUND[1] rgbounds; } struct PARAMDESCEX { ULONG cBytes; VARIANTARG varDefaultValue; } alias PARAMDESCEX* LPPARAMDESCEX; struct PARAMDESC { LPPARAMDESCEX pparamdescex; USHORT wParamFlags; } alias PARAMDESC* LPPARAMDESC; struct IDLDESC { ULONG dwReserved; USHORT wIDLFlags; } alias IDLDESC* LPIDLDESC; struct ELEMDESC { TYPEDESC tdesc; union { IDLDESC idldesc; PARAMDESC paramdesc; } } alias ELEMDESC* LPELEMDESC; struct TYPEATTR { GUID guid; LCID lcid; DWORD dwReserved; MEMBERID memidConstructor; MEMBERID memidDestructor; LPOLESTR lpstrSchema; ULONG cbSizeInstance; TYPEKIND typekind; WORD cFuncs; WORD cVars; WORD cImplTypes; WORD cbSizeVft; WORD cbAlignment; WORD wTypeFlags; WORD wMajorVerNum; WORD wMinorVerNum; TYPEDESC tdescAlias; IDLDESC idldescType; } alias TYPEATTR* LPTYPEATTR; struct DISPPARAMS { VARIANTARG* rgvarg; DISPID* rgdispidNamedArgs; UINT cArgs; UINT cNamedArgs; } struct EXCEPINFO { WORD wCode; WORD wReserved; BSTR bstrSource; BSTR bstrDescription; BSTR bstrHelpFile; DWORD dwHelpContext; PVOID pvReserved; extern (Windows) { HRESULT function (EXCEPINFO* ) pfnDeferredFillIn; } SCODE scode; } alias EXCEPINFO* LPEXCEPINFO; enum CALLCONV { CC_FASTCALL, CC_CDECL, CC_MSCPASCAL, CC_PASCAL=CC_MSCPASCAL, CC_MACPASCAL, CC_STDCALL, CC_FPFASTCALL, CC_SYSCALL, CC_MPWCDECL, CC_MPWPASCAL, CC_MAX=CC_MPWPASCAL } enum FUNCKIND { FUNC_VIRTUAL, FUNC_PUREVIRTUAL, FUNC_NONVIRTUAL, FUNC_STATIC, FUNC_DISPATCH } enum INVOKEKIND { INVOKE_FUNC = 1, INVOKE_PROPERTYGET = 2, INVOKE_PROPERTYPUT = 4, INVOKE_PROPERTYPUTREF = 8 } struct FUNCDESC { MEMBERID memid; SCODE* lprgscode; ELEMDESC* lprgelemdescParam; FUNCKIND funckind; INVOKEKIND invkind; CALLCONV callconv; SHORT cParams; SHORT cParamsOpt; SHORT oVft; SHORT cScodes; ELEMDESC elemdescFunc; WORD wFuncFlags; } alias FUNCDESC* LPFUNCDESC; enum VARKIND { VAR_PERINSTANCE, VAR_STATIC, VAR_CONST, VAR_DISPATCH } struct VARDESC { MEMBERID memid; LPOLESTR lpstrSchema; union { ULONG oInst; VARIANT* lpvarValue; } ELEMDESC elemdescVar; WORD wVarFlags; VARKIND varkind; } alias VARDESC* LPVARDESC; enum TYPEFLAGS { TYPEFLAG_FAPPOBJECT = 1, TYPEFLAG_FCANCREATE = 2, TYPEFLAG_FLICENSED = 4, TYPEFLAG_FPREDECLID = 8, TYPEFLAG_FHIDDEN = 16, TYPEFLAG_FCONTROL = 32, TYPEFLAG_FDUAL = 64, TYPEFLAG_FNONEXTENSIBLE = 128, TYPEFLAG_FOLEAUTOMATION = 256, TYPEFLAG_FRESTRICTED = 512, TYPEFLAG_FAGGREGATABLE = 1024, TYPEFLAG_FREPLACEABLE = 2048, TYPEFLAG_FDISPATCHABLE = 4096, TYPEFLAG_FREVERSEBIND = 8192 } enum FUNCFLAGS { FUNCFLAG_FRESTRICTED = 1, FUNCFLAG_FSOURCE = 2, FUNCFLAG_FBINDABLE = 4, FUNCFLAG_FREQUESTEDIT = 8, FUNCFLAG_FDISPLAYBIND = 16, FUNCFLAG_FDEFAULTBIND = 32, FUNCFLAG_FHIDDEN = 64, FUNCFLAG_FUSESGETLASTERROR = 128, FUNCFLAG_FDEFAULTCOLLELEM = 256, FUNCFLAG_FUIDEFAULT = 512, FUNCFLAG_FNONBROWSABLE = 1024, FUNCFLAG_FREPLACEABLE = 2048, FUNCFLAG_FIMMEDIATEBIND = 4096 } enum VARFLAGS { VARFLAG_FREADONLY = 1, VARFLAG_FSOURCE = 2, VARFLAG_FBINDABLE = 4, VARFLAG_FREQUESTEDIT = 8, VARFLAG_FDISPLAYBIND = 16, VARFLAG_FDEFAULTBIND = 32, VARFLAG_FHIDDEN = 64, VARFLAG_FRESTRICTED = 128, VARFLAG_FDEFAULTCOLLELEM = 256, VARFLAG_FUIDEFAULT = 512, VARFLAG_FNONBROWSABLE = 1024, VARFLAG_FREPLACEABLE = 2048, VARFLAG_FIMMEDIATEBIND = 4096 } struct CLEANLOCALSTORAGE { IUnknown pInterface; PVOID pStorage; DWORD flags; } struct CUSTDATAITEM { GUID guid; VARIANTARG varValue; } alias CUSTDATAITEM* LPCUSTDATAITEM; struct CUSTDATA { DWORD cCustData; LPCUSTDATAITEM prgCustData; } alias CUSTDATA* LPCUSTDATA; enum DESCKIND { DESCKIND_NONE = 0, DESCKIND_FUNCDESC = DESCKIND_NONE+1, DESCKIND_VARDESC = DESCKIND_FUNCDESC+1, DESCKIND_TYPECOMP = DESCKIND_VARDESC+1, DESCKIND_IMPLICITAPPOBJ = DESCKIND_TYPECOMP+1, DESCKIND_MAX = DESCKIND_IMPLICITAPPOBJ+1 } union BINDPTR { LPFUNCDESC lpfuncdesc; LPVARDESC lpvardesc; LPTYPECOMP lptcomp; } alias BINDPTR* LPBINDPTR; interface IDispatch : IUnknown { HRESULT GetTypeInfoCount(UINT*); HRESULT GetTypeInfo(UINT, LCID, LPTYPEINFO*); HRESULT GetIDsOfNames(REFIID, LPOLESTR*, UINT, LCID, DISPID*); HRESULT Invoke(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*); } alias IDispatch LPDISPATCH; interface IEnumVARIANT : IUnknown { HRESULT Next(ULONG, VARIANT*, ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumVARIANT*); } alias IEnumVARIANT LPENUMVARIANT; interface ITypeComp : IUnknown { HRESULT Bind(LPOLESTR, ULONG, WORD, LPTYPEINFO*, DESCKIND*, LPBINDPTR); HRESULT BindType(LPOLESTR, ULONG, LPTYPEINFO*, LPTYPECOMP*); } alias ITypeComp LPTYPECOMP; interface ITypeInfo : IUnknown { HRESULT GetTypeAttr(LPTYPEATTR*); HRESULT GetTypeComp(LPTYPECOMP*); HRESULT GetFuncDesc(UINT, LPFUNCDESC*); HRESULT GetVarDesc(UINT, LPVARDESC*); HRESULT GetNames(MEMBERID, BSTR*, UINT, UINT*); HRESULT GetRefTypeOfImplType(UINT, HREFTYPE*); HRESULT GetImplTypeFlags(UINT, INT*); HRESULT GetIDsOfNames(LPOLESTR*, UINT, MEMBERID*); HRESULT Invoke(PVOID, MEMBERID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*); HRESULT GetDocumentation(MEMBERID, BSTR*, BSTR*, DWORD*, BSTR*); HRESULT GetDllEntry(MEMBERID, INVOKEKIND, BSTR*, BSTR*, WORD*); HRESULT GetRefTypeInfo(HREFTYPE, LPTYPEINFO*); HRESULT AddressOfMember(MEMBERID, INVOKEKIND, PVOID*); HRESULT CreateInstance(LPUNKNOWN, REFIID, PVOID*); HRESULT GetMops(MEMBERID, BSTR*); HRESULT GetContainingTypeLib(LPTYPELIB*, UINT*); void ReleaseTypeAttr(LPTYPEATTR); void ReleaseFuncDesc(LPFUNCDESC); void ReleaseVarDesc(LPVARDESC); } alias ITypeInfo LPTYPEINFO; interface ITypeInfo2 : ITypeInfo { HRESULT GetTypeKind(TYPEKIND*); HRESULT GetTypeFlags(ULONG*); HRESULT GetFuncIndexOfMemId(MEMBERID, INVOKEKIND, UINT*); HRESULT GetVarIndexOfMemId(MEMBERID, UINT*); HRESULT GetCustData(REFGUID, VARIANT*); HRESULT GetFuncCustData(UINT, REFGUID, VARIANT*); HRESULT GetParamCustData(UINT, UINT, REFGUID, VARIANT*); HRESULT GetVarCustData(UINT, REFGUID, VARIANT*); HRESULT GetImplTypeCustData(UINT, REFGUID, VARIANT*); HRESULT GetDocumentation2(MEMBERID, LCID, BSTR*, DWORD*, BSTR*); HRESULT GetAllCustData(CUSTDATA*); HRESULT GetAllFuncCustData(UINT, CUSTDATA*); HRESULT GetAllParamCustData(UINT, UINT, CUSTDATA*); HRESULT GetAllVarCustData(UINT, CUSTDATA*); HRESULT GetAllImplTypeCustData(UINT, CUSTDATA*); } alias ITypeInfo2 LPTYPEINFO2; interface ITypeLib : IUnknown { UINT GetTypeInfoCount(); HRESULT GetTypeInfo(UINT, ITypeInfo*); HRESULT GetTypeInfoType(UINT, TYPEKIND*); HRESULT GetTypeInfoOfGuid(REFGUID, ITypeInfo*); HRESULT GetLibAttr(TLIBATTR**); HRESULT GetTypeComp(ITypeComp); HRESULT GetDocumentation(INT, BSTR*, BSTR*, DWORD*, BSTR*); HRESULT IsName(LPOLESTR, ULONG, BOOL*); HRESULT FindName(LPOLESTR, ULONG, ITypeInfo*, MEMBERID*, USHORT*); void ReleaseTLibAttr(TLIBATTR*); } alias ITypeLib LPTYPELIB; interface ITypeLib2 : ITypeLib { HRESULT GetCustData(REFGUID, VARIANT*); HRESULT GetLibStatistics(ULONG*, ULONG*); HRESULT GetDocumentation2(INT, LCID, BSTR*, DWORD*, BSTR*); HRESULT GetAllCustData(CUSTDATA*); } alias ITypeLib2 LPTYPELIB2; interface IErrorInfo : IUnknown { HRESULT GetGUID(GUID*); HRESULT GetSource(BSTR*); HRESULT GetDescription(BSTR*); HRESULT GetHelpFile(BSTR*); HRESULT GetHelpContext(DWORD*); } alias IErrorInfo LPERRORINFO; interface ICreateErrorInfo : IUnknown { HRESULT SetGUID(REFGUID); HRESULT SetSource(LPOLESTR); HRESULT SetDescription(LPOLESTR); HRESULT SetHelpFile(LPOLESTR); HRESULT SetHelpContext(DWORD); } alias ICreateErrorInfo LPCREATEERRORINFO; interface ISupportErrorInfo : IUnknown { HRESULT InterfaceSupportsErrorInfo(REFIID); } alias ISupportErrorInfo LPSUPPORTERRORINFO; interface IRecordInfo : IUnknown { HRESULT RecordInit(PVOID); HRESULT RecordClear(PVOID); HRESULT RecordCopy(PVOID, PVOID); HRESULT GetGuid(GUID*); HRESULT GetName(BSTR*); HRESULT GetSize(ULONG*); HRESULT GetTypeInfo(ITypeInfo*); HRESULT GetField(PVOID, LPCOLESTR, VARIANT*); HRESULT GetFieldNoCopy(PVOID, LPCOLESTR, VARIANT*, PVOID*); HRESULT PutField (ULONG, PVOID, LPCOLESTR, VARIANT*); HRESULT PutFieldNoCopy(ULONG, PVOID, LPCOLESTR, VARIANT*); HRESULT GetFieldNames(ULONG*, BSTR*); BOOL IsMatchingType(); PVOID RecordCreate(); HRESULT RecordCreateCopy(PVOID, PVOID*); HRESULT RecordDestroy (PVOID); } alias IRecordInfo LPRECORDINFO; interface ITypeMarshal : IUnknown { HRESULT Size(PVOID, DWORD, PVOID, ULONG*); HRESULT Marshal(PVOID, DWORD, PVOID, ULONG, BYTE*, ULONG*); HRESULT Unmarshal(PVOID, DWORD, ULONG, BYTE*, ULONG*); HRESULT Free(PVOID); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/mcx.d0000664000175000017500000000465012776214756022453 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_mcx.d) */ module core.sys.windows.mcx; version (Windows): private import core.sys.windows.windef; enum DWORD DIALOPTION_BILLING = 64, DIALOPTION_QUIET = 128, DIALOPTION_DIALTONE = 256; enum DWORD MDMVOLFLAG_LOW = 1, MDMVOLFLAG_MEDIUM = 2, MDMVOLFLAG_HIGH = 4; enum : DWORD { MDMVOL_LOW = 0, MDMVOL_MEDIUM = 1, MDMVOL_HIGH = 2 } enum DWORD MDMSPKRFLAG_OFF = 1, MDMSPKRFLAG_DIAL = 2, MDMSPKRFLAG_ON = 4, MDMSPKRFLAG_CALLSETUP = 8; enum : DWORD { MDMSPKR_OFF, MDMSPKR_DIAL, MDMSPKR_ON, MDMSPKR_CALLSETUP } enum DWORD MDM_COMPRESSION = 0x0001, MDM_ERROR_CONTROL = 0x0002, MDM_FORCED_EC = 0x0004, MDM_CELLULAR = 0x0008, MDM_FLOWCONTROL_HARD = 0x0010, MDM_FLOWCONTROL_SOFT = 0x0020, MDM_CCITT_OVERRIDE = 0x0040, MDM_SPEED_ADJUST = 0x0080, MDM_TONE_DIAL = 0x0100, MDM_BLIND_DIAL = 0x0200, MDM_V23_OVERRIDE = 0x0400; struct MODEMDEVCAPS { DWORD dwActualSize; DWORD dwRequiredSize; DWORD dwDevSpecificOffset; DWORD dwDevSpecificSize; DWORD dwModemProviderVersion; DWORD dwModemManufacturerOffset; DWORD dwModemManufacturerSize; DWORD dwModemModelOffset; DWORD dwModemModelSize; DWORD dwModemVersionOffset; DWORD dwModemVersionSize; DWORD dwDialOptions; DWORD dwCallSetupFailTimer; DWORD dwInactivityTimeout; DWORD dwSpeakerVolume; DWORD dwSpeakerMode; DWORD dwModemOptions; DWORD dwMaxDTERate; DWORD dwMaxDCERate; BYTE _abVariablePortion; BYTE* abVariablePortion() return { return &_abVariablePortion; } } alias MODEMDEVCAPS* PMODEMDEVCAPS, LPMODEMDEVCAPS; struct MODEMSETTINGS { DWORD dwActualSize; DWORD dwRequiredSize; DWORD dwDevSpecificOffset; DWORD dwDevSpecificSize; DWORD dwCallSetupFailTimer; DWORD dwInactivityTimeout; DWORD dwSpeakerVolume; DWORD dwSpeakerMode; DWORD dwPreferredModemOptions; DWORD dwNegotiatedModemOptions; DWORD dwNegotiatedDCERate; BYTE _abVariablePortion; BYTE* abVariablePortion() return { return &_abVariablePortion; } } alias MODEMSETTINGS* PMODEMSETTINGS, LPMODEMSETTINGS; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/msacm.d0000664000175000017500000001405212776214756022761 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_msacm.d) */ module core.sys.windows.msacm; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.basetsd, core.sys.windows.mmsystem, core.sys.windows.windef; mixin DECLARE_HANDLE!("HACMDRIVERID"); mixin DECLARE_HANDLE!("HACMDRIVER"); alias HACMDRIVER* LPHACMDRIVER; /* Comment from MinGW found through experimentation */ enum size_t ACMDRIVERDETAILS_SHORTNAME_CHARS = 32, ACMDRIVERDETAILS_LONGNAME_CHARS = 128, ACMDRIVERDETAILS_COPYRIGHT_CHARS = 80, ACMDRIVERDETAILS_LICENSING_CHARS = 128; /* Comment from MinGW I don't know the right values for these macros */ enum size_t ACMFORMATDETAILS_FORMAT_CHARS = 256, ACMFORMATTAGDETAILS_FORMATTAG_CHARS = 256, ACMDRIVERDETAILS_FEATURES_CHARS = 256; struct ACMFORMATDETAILSA { DWORD cbStruct = ACMFORMATDETAILSA.sizeof; // are they? DWORD dwFormatIndex; DWORD dwFormatTag; DWORD fdwSupport; LPWAVEFORMATEX pwfx; DWORD cbwfx; char[ACMFORMATDETAILS_FORMAT_CHARS] szFormat; } alias ACMFORMATDETAILSA* LPACMFORMATDETAILSA; struct ACMFORMATDETAILSW { DWORD cbStruct = ACMFORMATDETAILSW.sizeof; DWORD dwFormatIndex; DWORD dwFormatTag; DWORD fdwSupport; LPWAVEFORMATEX pwfx; DWORD cbwfx; WCHAR[ACMFORMATDETAILS_FORMAT_CHARS] szFormat; } alias ACMFORMATDETAILSW* LPACMFORMATDETAILSW; struct ACMFORMATTAGDETAILSA { DWORD cbStruct = ACMFORMATTAGDETAILSA.sizeof; DWORD dwFormatTagIndex; DWORD dwFormatTag; DWORD cbFormatSize; DWORD fdwSupport; DWORD cStandardFormats; char[ACMFORMATTAGDETAILS_FORMATTAG_CHARS] szFormatTag; } alias ACMFORMATTAGDETAILSA* LPACMFORMATTAGDETAILSA; struct ACMFORMATTAGDETAILSW { DWORD cbStruct = ACMFORMATTAGDETAILSW.sizeof; DWORD dwFormatTagIndex; DWORD dwFormatTag; DWORD cbFormatSize; DWORD fdwSupport; DWORD cStandardFormats; WCHAR[ACMFORMATTAGDETAILS_FORMATTAG_CHARS] szFormatTag; } alias ACMFORMATTAGDETAILSW* LPACMFORMATTAGDETAILSW; struct ACMDRIVERDETAILSA { DWORD cbStruct = ACMDRIVERDETAILSA.sizeof; FOURCC fccType; FOURCC fccComp; WORD wMid; WORD wPid; DWORD vdwACM; DWORD vdwDriver; DWORD fdwSupport; DWORD cFormatTags; DWORD cFilterTags; HICON hicon; char[ACMDRIVERDETAILS_SHORTNAME_CHARS] szShortName; char[ACMDRIVERDETAILS_LONGNAME_CHARS] szLongName; char[ACMDRIVERDETAILS_COPYRIGHT_CHARS] szCopyright; char[ACMDRIVERDETAILS_LICENSING_CHARS] szLicensing; char[ACMDRIVERDETAILS_FEATURES_CHARS] szFeatures; } alias ACMDRIVERDETAILSA* LPACMDRIVERDETAILSA; struct ACMDRIVERDETAILSW { DWORD cbStruct = ACMDRIVERDETAILSW.sizeof; FOURCC fccType; FOURCC fccComp; WORD wMid; WORD wPid; DWORD vdwACM; DWORD vdwDriver; DWORD fdwSupport; DWORD cFormatTags; DWORD cFilterTags; HICON hicon; WCHAR[ACMDRIVERDETAILS_SHORTNAME_CHARS] szShortName; WCHAR[ACMDRIVERDETAILS_LONGNAME_CHARS] szLongName; WCHAR[ACMDRIVERDETAILS_COPYRIGHT_CHARS] szCopyright; WCHAR[ACMDRIVERDETAILS_LICENSING_CHARS] szLicensing; WCHAR[ACMDRIVERDETAILS_FEATURES_CHARS] szFeatures; } alias ACMDRIVERDETAILSW* LPACMDRIVERDETAILSW; extern (Windows) { alias BOOL function(HACMDRIVERID hadid, LPACMFORMATDETAILSA pafd, DWORD_PTR dwInstance, DWORD fdwSupport) ACMFORMATENUMCBA; alias BOOL function(HACMDRIVERID hadid, LPACMFORMATDETAILSW pafd, DWORD_PTR dwInstance, DWORD fdwSupport) ACMFORMATENUMCBW; alias BOOL function(HACMDRIVERID hadid, LPACMFORMATTAGDETAILSA paftd, DWORD_PTR dwInstance, DWORD fdwSupport) ACMFORMATTAGENUMCBA; alias BOOL function(HACMDRIVERID hadid, LPACMFORMATTAGDETAILSW paftd, DWORD_PTR dwInstance, DWORD fdwSupport) ACMFORMATTAGENUMCBW; alias BOOL function(HACMDRIVERID hadid, DWORD_PTR dwInstance, DWORD fdwSupport) ACMDRIVERENUMCB; MMRESULT acmDriverOpen(LPHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen); MMRESULT acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD_PTR dwInstance, DWORD fdwEnum); MMRESULT acmFormatEnumA(HACMDRIVER had, LPACMFORMATDETAILSA pafd, ACMFORMATENUMCBA fnCallback, DWORD_PTR dwInstance, DWORD fdwEnum); MMRESULT acmFormatEnumW(HACMDRIVER had, LPACMFORMATDETAILSW pafd, ACMFORMATENUMCBW fnCallback, DWORD_PTR dwInstance, DWORD fdwEnum); MMRESULT acmDriverClose(HACMDRIVER had, DWORD fdwClose); MMRESULT acmDriverDetailsA(HACMDRIVERID hadid, LPACMDRIVERDETAILSA padd, DWORD fdwDetails); MMRESULT acmDriverDetailsW(HACMDRIVERID hadid, LPACMDRIVERDETAILSW padd, DWORD fdwDetails); MMRESULT acmFormatTagEnumA(HACMDRIVER had, LPACMFORMATTAGDETAILSA paftd, ACMFORMATTAGENUMCBA fnCallback, DWORD_PTR dwInstance, DWORD fdwEnum); MMRESULT acmFormatTagEnumW(HACMDRIVER had, LPACMFORMATTAGDETAILSW paftd, ACMFORMATTAGENUMCBW fnCallback, DWORD_PTR dwInstance, DWORD fdwEnum); } version (Unicode) { alias ACMFORMATDETAILSW ACMFORMATDETAILS; alias ACMFORMATTAGDETAILSW ACMFORMATTAGDETAILS; alias ACMDRIVERDETAILSW ACMDRIVERDETAILS; alias ACMFORMATENUMCBW ACMFORMATENUMCB; alias ACMFORMATTAGENUMCBW ACMFORMATTAGENUMCB; alias acmFormatEnumW acmFormatEnum; alias acmDriverDetailsW acmDriverDetails; alias acmFormatTagEnumW acmFormatTagEnum; } else { alias ACMFORMATDETAILSA ACMFORMATDETAILS; alias ACMFORMATTAGDETAILSA ACMFORMATTAGDETAILS; alias ACMDRIVERDETAILSA ACMDRIVERDETAILS; alias ACMFORMATENUMCBA ACMFORMATENUMCB; alias ACMFORMATTAGENUMCBA ACMFORMATTAGENUMCB; alias acmFormatEnumA acmFormatEnum; alias acmDriverDetailsA acmDriverDetails; alias acmFormatTagEnumA acmFormatTagEnum; } alias ACMFORMATDETAILS* LPACMFORMATDETAILS; alias ACMFORMATTAGDETAILS* LPACMFORMATTAGDETAILS; alias ACMDRIVERDETAILS* LPACMDRIVERDETAILS; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/aclapi.d0000664000175000017500000001550712776214756023120 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_aclapi.d) */ module core.sys.windows.aclapi; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "advapi32"); import core.sys.windows.windows, core.sys.windows.accctrl; extern (Windows) { VOID BuildExplicitAccessWithNameA(PEXPLICIT_ACCESS_A, LPSTR, DWORD, ACCESS_MODE, DWORD); VOID BuildExplicitAccessWithNameW(PEXPLICIT_ACCESS_W, LPWSTR, DWORD, ACCESS_MODE, DWORD); DWORD BuildSecurityDescriptorA(PTRUSTEE_A, PTRUSTEE_A , ULONG, PEXPLICIT_ACCESS_A, ULONG, PEXPLICIT_ACCESS_A, PSECURITY_DESCRIPTOR, PULONG, PSECURITY_DESCRIPTOR*); DWORD BuildSecurityDescriptorW(PTRUSTEE_W, PTRUSTEE_W , ULONG, PEXPLICIT_ACCESS_W, ULONG, PEXPLICIT_ACCESS_W, PSECURITY_DESCRIPTOR, PULONG, PSECURITY_DESCRIPTOR*); VOID BuildTrusteeWithNameA(PTRUSTEE_A, LPSTR); VOID BuildTrusteeWithNameW(PTRUSTEE_W, LPWSTR); VOID BuildTrusteeWithObjectsAndNameA(PTRUSTEE_A, POBJECTS_AND_NAME_A, SE_OBJECT_TYPE, LPSTR, LPSTR, LPSTR); VOID BuildTrusteeWithObjectsAndNameW(PTRUSTEE_W, POBJECTS_AND_NAME_W, SE_OBJECT_TYPE, LPWSTR, LPWSTR, LPWSTR); VOID BuildTrusteeWithObjectsAndSidA(PTRUSTEE_A, POBJECTS_AND_SID, GUID*, GUID*, PSID); VOID BuildTrusteeWithObjectsAndSidW(PTRUSTEE_W, POBJECTS_AND_SID, GUID*, GUID*, PSID); VOID BuildTrusteeWithSidA(PTRUSTEE_A, PSID); VOID BuildTrusteeWithSidW(PTRUSTEE_W, PSID); DWORD GetAuditedPermissionsFromAclA(PACL, PTRUSTEE_A, PACCESS_MASK, PACCESS_MASK); DWORD GetAuditedPermissionsFromAclW(PACL, PTRUSTEE_W, PACCESS_MASK, PACCESS_MASK); DWORD GetEffectiveRightsFromAclA(PACL, PTRUSTEE_A, PACCESS_MASK); DWORD GetEffectiveRightsFromAclW(PACL, PTRUSTEE_W, PACCESS_MASK); DWORD GetExplicitEntriesFromAclA(PACL, PULONG, PEXPLICIT_ACCESS_A*); DWORD GetExplicitEntriesFromAclW(PACL, PULONG, PEXPLICIT_ACCESS_W*); static if (_WIN32_WINNT >= 0x501) { DWORD GetInheritanceSourceA(LPSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, BOOL, GUID**, DWORD, PACL, void*, PGENERIC_MAPPING, PINHERITED_FROMA); DWORD GetInheritanceSourceW(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, BOOL, GUID**, DWORD, PACL, void*, PGENERIC_MAPPING, PINHERITED_FROMW); } DWORD GetNamedSecurityInfoA(LPSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); DWORD GetNamedSecurityInfoW(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); DWORD GetSecurityInfo(HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); TRUSTEE_FORM GetTrusteeFormA(PTRUSTEE_A); TRUSTEE_FORM GetTrusteeFormW(PTRUSTEE_W); LPSTR GetTrusteeNameA(PTRUSTEE_A); LPWSTR GetTrusteeNameW(PTRUSTEE_W); TRUSTEE_TYPE GetTrusteeTypeA(PTRUSTEE_A); TRUSTEE_TYPE GetTrusteeTypeW(PTRUSTEE_W); DWORD LookupSecurityDescriptorPartsA(PTRUSTEE_A*, PTRUSTEE_A*, PULONG, PEXPLICIT_ACCESS_A*, PULONG, PEXPLICIT_ACCESS_A*, PSECURITY_DESCRIPTOR); DWORD LookupSecurityDescriptorPartsW(PTRUSTEE_W*, PTRUSTEE_W*, PULONG, PEXPLICIT_ACCESS_W*, PULONG, PEXPLICIT_ACCESS_W*, PSECURITY_DESCRIPTOR); DWORD SetEntriesInAclA(ULONG, PEXPLICIT_ACCESS_A, PACL, PACL*); DWORD SetEntriesInAclW(ULONG, PEXPLICIT_ACCESS_W, PACL, PACL*); DWORD SetNamedSecurityInfoA(LPSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID, PSID, PACL, PACL); DWORD SetNamedSecurityInfoW(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID, PSID, PACL, PACL); DWORD SetSecurityInfo(HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID, PSID, PACL, PACL); VOID BuildImpersonateExplicitAccessWithNameA(PEXPLICIT_ACCESS_A, LPSTR, PTRUSTEE_A, DWORD, ACCESS_MODE, DWORD); VOID BuildImpersonateExplicitAccessWithNameW(PEXPLICIT_ACCESS_W, LPWSTR, PTRUSTEE_W, DWORD, ACCESS_MODE, DWORD); VOID BuildImpersonateTrusteeA(PTRUSTEE_A, PTRUSTEE_A); VOID BuildImpersonateTrusteeW(PTRUSTEE_W, PTRUSTEE_W); PTRUSTEE_A GetMultipleTrusteeA(PTRUSTEE_A); PTRUSTEE_W GetMultipleTrusteeW(PTRUSTEE_W); MULTIPLE_TRUSTEE_OPERATION GetMultipleTrusteeOperationA(PTRUSTEE_A); MULTIPLE_TRUSTEE_OPERATION GetMultipleTrusteeOperationW(PTRUSTEE_W); } version (Unicode) { alias BuildExplicitAccessWithNameW BuildExplicitAccessWithName; alias BuildSecurityDescriptorW BuildSecurityDescriptor; alias BuildTrusteeWithNameW BuildTrusteeWithName; alias BuildTrusteeWithObjectsAndNameW BuildTrusteeWithObjectsAndName; alias BuildTrusteeWithObjectsAndSidW BuildTrusteeWithObjectsAndSid; alias BuildTrusteeWithSidW BuildTrusteeWithSid; alias GetAuditedPermissionsFromAclW GetAuditedPermissionsFromAcl; alias GetEffectiveRightsFromAclW GetEffectiveRightsFromAcl; alias GetExplicitEntriesFromAclW GetExplicitEntriesFromAcl; alias GetNamedSecurityInfoW GetNamedSecurityInfo; alias GetTrusteeFormW GetTrusteeForm; alias GetTrusteeNameW GetTrusteeName; alias GetTrusteeTypeW GetTrusteeType; alias LookupSecurityDescriptorPartsW LookupSecurityDescriptorParts; alias SetEntriesInAclW SetEntriesInAcl; alias SetNamedSecurityInfoW SetNamedSecurityInfo; alias BuildImpersonateExplicitAccessWithNameW BuildImpersonateExplicitAccessWithName; alias BuildImpersonateTrusteeW BuildImpersonateTrustee; alias GetMultipleTrusteeW GetMultipleTrustee; alias GetMultipleTrusteeOperationW GetMultipleTrusteeOperation; } else { alias BuildExplicitAccessWithNameA BuildExplicitAccessWithName; alias BuildSecurityDescriptorA BuildSecurityDescriptor; alias BuildTrusteeWithNameA BuildTrusteeWithName; alias BuildTrusteeWithObjectsAndNameA BuildTrusteeWithObjectsAndName; alias BuildTrusteeWithObjectsAndSidA BuildTrusteeWithObjectsAndSid; alias BuildTrusteeWithSidA BuildTrusteeWithSid; alias GetAuditedPermissionsFromAclA GetAuditedPermissionsFromAcl; alias GetEffectiveRightsFromAclA GetEffectiveRightsFromAcl; alias GetExplicitEntriesFromAclA GetExplicitEntriesFromAcl; alias GetNamedSecurityInfoA GetNamedSecurityInfo; alias GetTrusteeFormA GetTrusteeForm; alias GetTrusteeNameA GetTrusteeName; alias GetTrusteeTypeA GetTrusteeType; alias LookupSecurityDescriptorPartsA LookupSecurityDescriptorParts; alias SetEntriesInAclA SetEntriesInAcl; alias SetNamedSecurityInfoA SetNamedSecurityInfo; alias BuildImpersonateExplicitAccessWithNameA BuildImpersonateExplicitAccessWithName; alias BuildImpersonateTrusteeA BuildImpersonateTrustee; alias GetMultipleTrusteeA GetMultipleTrustee; alias GetMultipleTrusteeOperationA GetMultipleTrusteeOperation; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/lmsname.d0000664000175000017500000000506312776214756023317 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_lmsname.d) */ module core.sys.windows.lmsname; version (Windows): private import core.sys.windows.windef; const TCHAR[] SERVICE_WORKSTATION = "LanmanWorkstation", SERVICE_LM20_WORKSTATION = "WORKSTATION", WORKSTATION_DISPLAY_NAME = "Workstation", SERVICE_SERVER = "LanmanServer", SERVICE_LM20_SERVER = "SERVER", SERVER_DISPLAY_NAME = "Server", SERVICE_BROWSER = "BROWSER", SERVICE_LM20_BROWSER = SERVICE_BROWSER, SERVICE_MESSENGER = "MESSENGER", SERVICE_LM20_MESSENGER = SERVICE_MESSENGER, SERVICE_NETRUN = "NETRUN", SERVICE_LM20_NETRUN = SERVICE_NETRUN, SERVICE_SPOOLER = "SPOOLER", SERVICE_LM20_SPOOLER = SERVICE_SPOOLER, SERVICE_ALERTER = "ALERTER", SERVICE_LM20_ALERTER = SERVICE_ALERTER, SERVICE_NETLOGON = "NETLOGON", SERVICE_LM20_NETLOGON = SERVICE_NETLOGON, SERVICE_NETPOPUP = "NETPOPUP", SERVICE_LM20_NETPOPUP = SERVICE_NETPOPUP, SERVICE_SQLSERVER = "SQLSERVER", SERVICE_LM20_SQLSERVER = SERVICE_SQLSERVER, SERVICE_REPL = "REPLICATOR", SERVICE_LM20_REPL = SERVICE_REPL, SERVICE_RIPL = "REMOTEBOOT", SERVICE_LM20_RIPL = SERVICE_RIPL, SERVICE_TIMESOURCE = "TIMESOURCE", SERVICE_LM20_TIMESOURCE = SERVICE_TIMESOURCE, SERVICE_AFP = "AFP", SERVICE_LM20_AFP = SERVICE_AFP, SERVICE_UPS = "UPS", SERVICE_LM20_UPS = SERVICE_UPS, SERVICE_XACTSRV = "XACTSRV", SERVICE_LM20_XACTSRV = SERVICE_XACTSRV, SERVICE_TCPIP = "TCPIP", SERVICE_LM20_TCPIP = SERVICE_TCPIP, SERVICE_NBT = "NBT", SERVICE_LM20_NBT = SERVICE_NBT, SERVICE_LMHOSTS = "LMHOSTS", SERVICE_LM20_LMHOSTS = SERVICE_LMHOSTS, SERVICE_TELNET = "Telnet", SERVICE_LM20_TELNET = SERVICE_TELNET, SERVICE_SCHEDULE = "Schedule", SERVICE_LM20_SCHEDULE = SERVICE_SCHEDULE, SERVICE_NTLMSSP = "NtLmSsp", SERVICE_DHCP = "DHCP", SERVICE_LM20_DHCP = SERVICE_DHCP, SERVICE_NWSAP = "NwSapAgent", SERVICE_LM20_NWSAP = SERVICE_NWSAP, NWSAP_DISPLAY_NAME = "NW Sap Agent", SERVICE_NWCS = "NWCWorkstation"; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rpc.d0000664000175000017500000000145312776214756022446 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rpc.d) */ module core.sys.windows.rpc; version (Windows): /* Moved to rpcdecp (duplicate definition). typedef void *I_RPC_HANDLE; alias long RPC_STATUS; // Moved to rpcdce: RpcImpersonateClient RpcRevertToSelf */ public import core.sys.windows.unknwn; public import core.sys.windows.rpcdce; // also pulls in rpcdcep public import core.sys.windows.rpcnsi; public import core.sys.windows.rpcnterr; public import core.sys.windows.winerror; alias MIDL_user_allocate midl_user_allocate; alias MIDL_user_free midl_user_free; extern (Windows) { int I_RpcMapWin32Status(RPC_STATUS); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/isguids.d0000664000175000017500000000067012776214756023331 0ustar kaikai/** * Windows API header module * * Translated from MinGW API for MS-Windows 3.10 * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_isguids.d) */ module core.sys.windows.isguids; version (Windows): private import core.sys.windows.basetyps; extern (C) extern const GUID CLSID_InternetShortcut, IID_IUniformResourceLocator; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/wtsapi32.d0000664000175000017500000003533112776214756023340 0ustar kaikai/** * Windows API header module * * Translated from MinGW-w64 API * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_wtsapi32.d) */ module core.sys.windows.wtsapi32; version (Windows): version (ANSI) {} else version = Unicode; pragma(lib, "wtsapi32"); private import core.sys.windows.w32api; import core.sys.windows.windef; enum { WTS_CURRENT_SERVER = null, WTS_CURRENT_SERVER_HANDLE = null, WTS_CURRENT_SERVER_NAME = null } enum DWORD WTS_CURRENT_SESSION = cast(DWORD) -1; enum { IDTIMEOUT = 32000, IDASYNC = 32001 } enum { WTS_WSD_LOGOFF = 0x01, WTS_WSD_SHUTDOWN = 0x02, WTS_WSD_REBOOT = 0x04, WTS_WSD_POWEROFF = 0x08, WTS_WSD_FASTREBOOT = 0x10 } enum WTS_CONNECTSTATE_CLASS { WTSActive, WTSConnected, WTSConnectQuery, WTSShadow, WTSDisconnected, WTSIdle, WTSListen, WTSReset, WTSDown, WTSInit } struct WTS_SERVER_INFOW { LPWSTR pServerName; } alias WTS_SERVER_INFOW* PWTS_SERVER_INFOW; struct WTS_SERVER_INFOA { LPSTR pServerName; } alias WTS_SERVER_INFOA* PWTS_SERVER_INFOA; version(Unicode) { alias WTS_SERVER_INFOW WTS_SERVER_INFO; alias PWTS_SERVER_INFOW PWTS_SERVER_INFO; } else { alias WTS_SERVER_INFOA WTS_SERVER_INFO; alias PWTS_SERVER_INFOA PWTS_SERVER_INFO; } struct WTS_SESSION_INFOW { DWORD SessionId; LPWSTR pWinStationName; WTS_CONNECTSTATE_CLASS State; } alias WTS_SESSION_INFOW* PWTS_SESSION_INFOW; struct WTS_SESSION_INFOA { DWORD SessionId; LPSTR pWinStationName; WTS_CONNECTSTATE_CLASS State; } alias WTS_SESSION_INFOA* PWTS_SESSION_INFOA; version(Unicode) { alias WTS_SESSION_INFOW WTS_SESSION_INFO; alias PWTS_SESSION_INFOW PWTS_SESSION_INFO; } else { alias WTS_SESSION_INFOA WTS_SESSION_INFO; alias PWTS_SESSION_INFOA PWTS_SESSION_INFO; } struct WTS_PROCESS_INFOW { DWORD SessionId; DWORD ProcessId; LPWSTR pProcessName; PSID pUserSid; } alias WTS_PROCESS_INFOW* PWTS_PROCESS_INFOW; struct WTS_PROCESS_INFOA { DWORD SessionId; DWORD ProcessId; LPSTR pProcessName; PSID pUserSid; } alias WTS_PROCESS_INFOA* PWTS_PROCESS_INFOA; version(Unicode) { alias WTS_PROCESS_INFOW WTS_PROCESS_INFO; alias PWTS_PROCESS_INFOW PWTS_PROCESS_INFO; } else { alias WTS_PROCESS_INFOA WTS_PROCESS_INFO; alias PWTS_PROCESS_INFOA PWTS_PROCESS_INFO; } enum { WTS_PROTOCOL_TYPE_CONSOLE, WTS_PROTOCOL_TYPE_ICA, WTS_PROTOCOL_TYPE_RDP } enum WTS_INFO_CLASS { WTSInitialProgram, WTSApplicationName, WTSWorkingDirectory, WTSOEMId, WTSSessionId, WTSUserName, WTSWinStationName, WTSDomainName, WTSConnectState, WTSClientBuildNumber, WTSClientName, WTSClientDirectory, WTSClientProductId, WTSClientHardwareId, WTSClientAddress, WTSClientDisplay, WTSClientProtocolType, WTSIdleTime, WTSLogonTime, WTSIncomingBytes, WTSOutgoingBytes, WTSIncomingFrames, WTSOutgoingFrames, WTSClientInfo, WTSSessionInfo, // = 24 } struct WTS_CLIENT_ADDRESS { DWORD AddressFamily; BYTE[20] Address; } alias WTS_CLIENT_ADDRESS* PWTS_CLIENT_ADDRESS; struct WTS_CLIENT_DISPLAY { DWORD HorizontalResolution; DWORD VerticalResolution; DWORD ColorDepth; } alias WTS_CLIENT_DISPLAY* PWTS_CLIENT_DISPLAY; enum WTS_CONFIG_CLASS { WTSUserConfigInitialProgram, WTSUserConfigWorkingDirectory, WTSUserConfigfInheritInitialProgram, WTSUserConfigfAllowLogonTerminalServer, WTSUserConfigTimeoutSettingsConnections, WTSUserConfigTimeoutSettingsDisconnections, WTSUserConfigTimeoutSettingsIdle, WTSUserConfigfDeviceClientDrives, WTSUserConfigfDeviceClientPrinters, WTSUserConfigfDeviceClientDefaultPrinter, WTSUserConfigBrokenTimeoutSettings, WTSUserConfigReconnectSettings, WTSUserConfigModemCallbackSettings, WTSUserConfigModemCallbackPhoneNumber, WTSUserConfigShadowingSettings, WTSUserConfigTerminalServerProfilePath, WTSUserConfigTerminalServerHomeDir, WTSUserConfigTerminalServerHomeDirDrive, WTSUserConfigfTerminalServerRemoteHomeDir } enum { WTS_EVENT_NONE = 0x0, WTS_EVENT_CREATE = 0x1, WTS_EVENT_DELETE = 0x2, WTS_EVENT_RENAME = 0x4, WTS_EVENT_CONNECT = 0x8, WTS_EVENT_DISCONNECT = 0x10, WTS_EVENT_LOGON = 0x20, WTS_EVENT_LOGOFF = 0x40, WTS_EVENT_STATECHANGE = 0x80, WTS_EVENT_LICENSE = 0x100, WTS_EVENT_ALL = 0x7fffffff, WTS_EVENT_FLUSH = 0x80000000 } enum WTS_VIRTUAL_CLASS { WTSVirtualClientData, WTSVirtualFileHandle } version(Unicode) { alias WTSEnumerateServersW WTSEnumerateServers; alias WTSOpenServerW WTSOpenServer; alias WTSEnumerateSessionsW WTSEnumerateSessions; alias WTSEnumerateProcessesW WTSEnumerateProcesses; alias WTSQuerySessionInformationW WTSQuerySessionInformation; alias WTSQueryUserConfigW WTSQueryUserConfig; alias WTSSetUserConfigW WTSSetUserConfig; alias WTSSendMessageW WTSSendMessage; } else { alias WTSEnumerateServersA WTSEnumerateServers; alias WTSOpenServerA WTSOpenServer; alias WTSEnumerateSessionsA WTSEnumerateSessions; alias WTSEnumerateProcessesA WTSEnumerateProcesses; alias WTSQuerySessionInformationA WTSQuerySessionInformation; alias WTSQueryUserConfigA WTSQueryUserConfig; alias WTSSetUserConfigA WTSSetUserConfig; alias WTSSendMessageA WTSSendMessage; } extern(Windows) { WINBOOL WTSEnumerateServersW(LPWSTR pDomainName, DWORD Reserved, DWORD Version, PWTS_SERVER_INFOW* ppServerInfo, DWORD* pCount); WINBOOL WTSEnumerateServersA(LPSTR pDomainName, DWORD Reserved, DWORD Version, PWTS_SERVER_INFOA* ppServerInfo, DWORD* pCount); HANDLE WTSOpenServerW(LPWSTR pServerName); HANDLE WTSOpenServerA(LPSTR pServerName); VOID WTSCloseServer(HANDLE hServer); WINBOOL WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version, PWTS_SESSION_INFOW* ppSessionInfo, DWORD* pCount); WINBOOL WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version, PWTS_SESSION_INFOA* ppSessionInfo, DWORD* pCount); WINBOOL WTSEnumerateProcessesW(HANDLE hServer, DWORD Reserved, DWORD Version, PWTS_PROCESS_INFOW* ppProcessInfo, DWORD* pCount); WINBOOL WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved, DWORD Version, PWTS_PROCESS_INFOA* ppProcessInfo, DWORD* pCount); WINBOOL WTSTerminateProcess(HANDLE hServer, DWORD ProcessId, DWORD ExitCode); WINBOOL WTSQuerySessionInformationW(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPWSTR* ppBuffer, DWORD* pBytesReturned); WINBOOL WTSQuerySessionInformationA(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPSTR* ppBuffer, DWORD* pBytesReturned); WINBOOL WTSQueryUserConfigW(LPWSTR pServerName, LPWSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass, LPWSTR* ppBuffer, DWORD* pBytesReturned); WINBOOL WTSQueryUserConfigA(LPSTR pServerName, LPSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass, LPSTR* ppBuffer, DWORD* pBytesReturned); WINBOOL WTSSetUserConfigW(LPWSTR pServerName, LPWSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass, LPWSTR pBuffer, DWORD DataLength); WINBOOL WTSSetUserConfigA(LPSTR pServerName, LPSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass, LPSTR pBuffer, DWORD DataLength); WINBOOL WTSSendMessageW(HANDLE hServer, DWORD SessionId, LPWSTR pTitle, DWORD TitleLength, LPWSTR pMessage, DWORD MessageLength, DWORD Style, DWORD Timeout, DWORD* pResponse, WINBOOL bWait); WINBOOL WTSSendMessageA(HANDLE hServer, DWORD SessionId, LPSTR pTitle, DWORD TitleLength, LPSTR pMessage, DWORD MessageLength, DWORD Style, DWORD Timeout, DWORD* pResponse, WINBOOL bWait); WINBOOL WTSDisconnectSession(HANDLE hServer, DWORD SessionId, WINBOOL bWait); WINBOOL WTSLogoffSession(HANDLE hServer, DWORD SessionId, WINBOOL bWait); WINBOOL WTSShutdownSystem(HANDLE hServer, DWORD ShutdownFlag); WINBOOL WTSWaitSystemEvent(HANDLE hServer, DWORD EventMask, DWORD* pEventFlags); HANDLE WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName); WINBOOL WTSVirtualChannelClose(HANDLE hChannelHandle); WINBOOL WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut, PCHAR Buffer, ULONG BufferSize, PULONG pBytesRead); WINBOOL WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length, PULONG pBytesWritten); WINBOOL WTSVirtualChannelPurgeInput(HANDLE hChannelHandle); WINBOOL WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle); WINBOOL WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS, PVOID* ppBuffer, DWORD* pBytesReturned); VOID WTSFreeMemory(PVOID pMemory); WINBOOL WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags); WINBOOL WTSUnRegisterSessionNotification(HWND hWnd); WINBOOL WTSQueryUserToken(ULONG SessionId, PHANDLE phToken); } enum { NOTIFY_FOR_ALL_SESSIONS = 1, NOTIFY_FOR_THIS_SESSION = 0 } enum { USERNAME_LENGTH = 20, CLIENTNAME_LENGTH = 20, CLIENTADDRESS_LENGTH = 30, WINSTATIONNAME_LENGTH = 32, DOMAIN_LENGTH = 17 } static if (_WIN32_WINNT >= 0x600) { struct WTSCLIENTW { WCHAR[CLIENTNAME_LENGTH + 1] ClientName; WCHAR[DOMAIN_LENGTH + 1] Domain; WCHAR[USERNAME_LENGTH + 1] UserName; WCHAR[MAX_PATH + 1] WorkDirectory; WCHAR[MAX_PATH + 1] InitialProgram; BYTE EncryptionLevel; ULONG ClientAddressFamily; USHORT[CLIENTADDRESS_LENGTH + 1] ClientAddress; USHORT HRes; USHORT VRes; USHORT ColorDepth; WCHAR[MAX_PATH + 1] ClientDirectory; ULONG ClientBuildNumber; ULONG ClientHardwareId; USHORT ClientProductId; USHORT OutBufCountHost; USHORT OutBufCountClient; USHORT OutBufLength; WCHAR[MAX_PATH + 1] DeviceId; } alias WTSCLIENTW* PWTSCLIENTW; struct WTSCLIENTA { CHAR[CLIENTNAME_LENGTH + 1] ClientName; CHAR[DOMAIN_LENGTH + 1 ] Domain; CHAR[USERNAME_LENGTH + 1] UserName; CHAR[MAX_PATH + 1] WorkDirectory; CHAR[MAX_PATH + 1] InitialProgram; BYTE EncryptionLevel; ULONG ClientAddressFamily; USHORT[CLIENTADDRESS_LENGTH + 1] ClientAddress; USHORT HRes; USHORT VRes; USHORT ColorDepth; CHAR[MAX_PATH + 1] ClientDirectory; ULONG ClientBuildNumber; ULONG ClientHardwareId; USHORT ClientProductId; USHORT OutBufCountHost; USHORT OutBufCountClient; USHORT OutBufLength; CHAR[MAX_PATH + 1] DeviceId; } alias WTSCLIENTA* PWTSCLIENTA; version(Unicode) { alias WTSCLIENTW WTSCLIENT; alias PWTSCLIENTW PWTSCLIENT; } else { alias WTSCLIENTA WTSCLIENT; alias PWTSCLIENTA PWTSCLIENT; } struct WTSINFOW { WTS_CONNECTSTATE_CLASS State; DWORD SessionId; DWORD IncomingBytes; DWORD OutgoingBytes; DWORD IncomingCompressedBytes; DWORD OutgoingCompressedBytes; WCHAR[WINSTATIONNAME_LENGTH] WinStationName; WCHAR[DOMAIN_LENGTH] Domain; WCHAR[USERNAME_LENGTH+1] UserName; LARGE_INTEGER ConnectTime; LARGE_INTEGER DisconnectTime; LARGE_INTEGER LastInputTime; LARGE_INTEGER LogonTime; LARGE_INTEGER CurrentTime; } alias WTSINFOW* PWTSINFOW; struct WTSINFOA { WTS_CONNECTSTATE_CLASS State; DWORD SessionId; DWORD IncomingBytes; DWORD OutgoingBytes; DWORD IncomingCompressedBytes; DWORD OutgoingCompressedBytes; CHAR[WINSTATIONNAME_LENGTH] WinStationName; CHAR[DOMAIN_LENGTH] Domain; CHAR[USERNAME_LENGTH+1] UserName; LARGE_INTEGER ConnectTime; LARGE_INTEGER DisconnectTime; LARGE_INTEGER LastInputTime; LARGE_INTEGER LogonTime; LARGE_INTEGER CurrentTime; } alias WTSINFOA* PWTSINFOA; version(Unicode) { alias WTSINFOW WTSINFO; alias PWTSINFOW PWTSINFO; } else { alias WTSINFOA WTSINFO; alias PWTSINFOA PWTSINFO; } extern(Windows) { WINBOOL WTSConnectSessionA( ULONG LogonId, ULONG TargetLogonId, PSTR pPassword, WINBOOL bWait ); WINBOOL WTSConnectSessionW( ULONG LogonId, ULONG TargetLogonId, PWSTR pPassword, WINBOOL bWait ); WINBOOL WTSRegisterSessionNotificationEx( HANDLE hServer, HWND hWnd, DWORD dwFlags ); WINBOOL WTSStartRemoteControlSessionA( LPSTR pTargetServerName, ULONG TargetLogonId, BYTE HotkeyVk, USHORT HotkeyModifiers ); WINBOOL WTSStartRemoteControlSessionW( LPWSTR pTargetServerName, ULONG TargetLogonId, BYTE HotkeyVk, USHORT HotkeyModifiers ); version(Unicode) { alias WTSStartRemoteControlSessionW WTSStartRemoteControlSession; alias WTSConnectSessionW WTSConnectSession; } else { alias WTSStartRemoteControlSessionA WTSStartRemoteControlSession; alias WTSConnectSessionA WTSConnectSession; } WINBOOL WTSStopRemoteControlSession( ULONG LogonId ); WINBOOL WTSUnRegisterSessionNotificationEx( HANDLE hServer, HWND hWnd ); HANDLE WTSVirtualChannelOpenEx( DWORD SessionId, LPSTR pVirtualName, DWORD flags ); } /* extern(Windows) */ } /* static if (_WIN32_WINNT >= 0x600) */ ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/pbt.d0000664000175000017500000000130212776214756022440 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_pbt.d) */ module core.sys.windows.pbt; version (Windows): private import core.sys.windows.windef; enum : WPARAM { PBT_APMQUERYSUSPEND, PBT_APMQUERYSTANDBY, PBT_APMQUERYSUSPENDFAILED, PBT_APMQUERYSTANDBYFAILED, PBT_APMSUSPEND, PBT_APMSTANDBY, PBT_APMRESUMECRITICAL, PBT_APMRESUMESUSPEND, PBT_APMRESUMESTANDBY, PBT_APMBATTERYLOW, PBT_APMPOWERSTATUSCHANGE, PBT_APMOEMEVENT // = 11 } enum LPARAM PBTF_APMRESUMEFROMFAILURE = 1; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/objfwd.d0000664000175000017500000000606212776214756023136 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_objfwd.d) */ module core.sys.windows.objfwd; version (Windows): private import core.sys.windows.objidl; /+ // Forward declararions are not necessary in D. extern(Windows) { interface IMoniker; interface IStream; interface IMarshal; interface IMalloc; interface IMallocSpy; interface IMessageFilter; interface IPersist; interface IPersistStream; interface IRunningObjectTable; interface IBindCtx; interface IAdviseSink; interface IAdviseSink2; interface IDataObject; interface IDataAdviseHolder; interface IEnumMoniker; interface IEnumFORMATETC; interface IEnumSTATDATA; interface IEnumSTATSTG; interface IEnumSTATPROPSTG; interface IEnumString; interface IEnumUnknown; interface IStorage; interface IPersistStorage; interface ILockBytes; interface IStdMarshalInfo; interface IExternalConnection; interface IRunnableObject; interface IROTData; interface IPersistFile; interface IRootStorage; interface IPropertyStorage; interface IEnumSTATPROPSETSTG; interface IPropertySetStorage; interface IClientSecurity; interface IServerSecurity; interface IClassActivator; interface IFillLockBytes; interface IProgressNotify; interface ILayoutStorage; interface IRpcProxyBuffer; interface IRpcChannelBuffer; interface IRpcStubBuffer; } +/ alias IMoniker LPMONIKER; alias IStream LPSTREAM; alias IMarshal LPMARSHAL; alias IMalloc LPMALLOC; alias IMallocSpy LPMALLOCSPY; alias IMessageFilter LPMESSAGEFILTER; alias IPersist LPPERSIST; alias IPersistStream LPPERSISTSTREAM; alias IRunningObjectTable LPRUNNINGOBJECTTABLE; alias IBindCtx LPBINDCTX, LPBC; alias IAdviseSink LPADVISESINK; alias IAdviseSink2 LPADVISESINK2; alias IDataObject LPDATAOBJECT; alias IDataAdviseHolder LPDATAADVISEHOLDER; alias IEnumMoniker LPENUMMONIKER; alias IEnumFORMATETC LPENUMFORMATETC; alias IEnumSTATDATA LPENUMSTATDATA; alias IEnumSTATSTG LPENUMSTATSTG; alias IEnumSTATPROPSTG LPENUMSTATPROPSTG; alias IEnumString LPENUMSTRING; alias IEnumUnknown LPENUMUNKNOWN; alias IStorage LPSTORAGE; alias IPersistStorage LPPERSISTSTORAGE; alias ILockBytes LPLOCKBYTES; alias IStdMarshalInfo LPSTDMARSHALINFO; alias IExternalConnection LPEXTERNALCONNECTION; alias IRunnableObject LPRUNNABLEOBJECT; alias IROTData LPROTDATA; alias IPersistFile LPPERSISTFILE; alias IRootStorage LPROOTSTORAGE; alias IRpcChannelBuffer LPRPCCHANNELBUFFER; alias IRpcProxyBuffer LPRPCPROXYBUFFER; alias IRpcStubBuffer LPRPCSTUBBUFFER; alias IPropertyStorage LPPROPERTYSTORAGE; alias IEnumSTATPROPSETSTG LPENUMSTATPROPSETSTG; alias IPropertySetStorage LPPROPERTYSETSTORAGE; alias IClientSecurity LPCLIENTSECURITY; alias IServerSecurity LPSERVERSECURITY; alias IClassActivator LPCLASSACTIVATOR; alias IFillLockBytes LPFILLLOCKBYTES; alias IProgressNotify LPPROGRESSNOTIFY; alias ILayoutStorage LPLAYOUTSTORAGE; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/rasdlg.d0000664000175000017500000000777512776214756023153 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_rasdlg.d) */ module core.sys.windows.rasdlg; version (Windows): version (ANSI) {} else version = Unicode; import core.sys.windows.ras; private import core.sys.windows.lmcons, core.sys.windows.windef; enum { RASPBDEVENT_AddEntry = 1, RASPBDEVENT_EditEntry, RASPBDEVENT_RemoveEntry, RASPBDEVENT_DialEntry, RASPBDEVENT_EditGlobals, RASPBDEVENT_NoUser, RASPBDEVENT_NoUserEdit } enum RASPBDFLAG_PositionDlg = 1; enum RASPBDFLAG_ForceCloseOnDial = 2; enum RASPBDFLAG_NoUser = 16; enum RASEDFLAG_PositionDlg = 1; enum RASEDFLAG_NewEntry = 2; enum RASEDFLAG_CloneEntry = 4; enum RASDDFLAG_PositionDlg = 1; align(4): struct RASENTRYDLGA { DWORD dwSize = RASENTRYDLGA.sizeof; HWND hwndOwner; DWORD dwFlags; LONG xDlg; LONG yDlg; CHAR[RAS_MaxEntryName + 1] szEntry; DWORD dwError; ULONG_PTR reserved; ULONG_PTR reserved2; } alias RASENTRYDLGA* LPRASENTRYDLGA; struct RASENTRYDLGW { DWORD dwSize = RASENTRYDLGW.sizeof; HWND hwndOwner; DWORD dwFlags; LONG xDlg; LONG yDlg; WCHAR[RAS_MaxEntryName + 1] szEntry; DWORD dwError; ULONG_PTR reserved; ULONG_PTR reserved2; } alias RASENTRYDLGW* LPRASENTRYDLGW; struct RASDIALDLG { DWORD dwSize; HWND hwndOwner; DWORD dwFlags; LONG xDlg; LONG yDlg; DWORD dwSubEntry; DWORD dwError; ULONG_PTR reserved; ULONG_PTR reserved2; } alias RASDIALDLG* LPRASDIALDLG; // Application-defined callback functions extern (Windows) { alias VOID function(DWORD, DWORD, LPWSTR, LPVOID) RASPBDLGFUNCW; alias VOID function(DWORD, DWORD, LPSTR, LPVOID) RASPBDLGFUNCA; } struct RASPBDLGA { DWORD dwSize = RASPBDLGA.sizeof; HWND hwndOwner; DWORD dwFlags; LONG xDlg; LONG yDlg; ULONG_PTR dwCallbackId; RASPBDLGFUNCA pCallback; DWORD dwError; ULONG_PTR reserved; ULONG_PTR reserved2; } alias RASPBDLGA* LPRASPBDLGA; struct RASPBDLGW { DWORD dwSize = RASPBDLGW.sizeof; HWND hwndOwner; DWORD dwFlags; LONG xDlg; LONG yDlg; ULONG_PTR dwCallbackId; RASPBDLGFUNCW pCallback; DWORD dwError; ULONG_PTR reserved; ULONG_PTR reserved2; } alias RASPBDLGW* LPRASPBDLGW; struct RASNOUSERA { DWORD dwSize = RASNOUSERA.sizeof; DWORD dwFlags; DWORD dwTimeoutMs; CHAR[UNLEN + 1] szUserName; CHAR[PWLEN + 1] szPassword; CHAR[DNLEN + 1] szDomain; } alias RASNOUSERA* LPRASNOUSERA; struct RASNOUSERW { DWORD dwSize = RASNOUSERW.sizeof; DWORD dwFlags; DWORD dwTimeoutMs; WCHAR[UNLEN + 1] szUserName; WCHAR[PWLEN + 1] szPassword; WCHAR[DNLEN + 1] szDomain; } alias RASNOUSERW* LPRASNOUSERW; extern (Windows) { BOOL RasDialDlgA(LPSTR, LPSTR, LPSTR, LPRASDIALDLG); BOOL RasDialDlgW(LPWSTR, LPWSTR, LPWSTR, LPRASDIALDLG); BOOL RasEntryDlgA(LPSTR, LPSTR, LPRASENTRYDLGA); BOOL RasEntryDlgW(LPWSTR, LPWSTR, LPRASENTRYDLGW); BOOL RasPhonebookDlgA(LPSTR, LPSTR, LPRASPBDLGA); BOOL RasPhonebookDlgW(LPWSTR, LPWSTR, LPRASPBDLGW); } version (Unicode) { alias RASENTRYDLGW RASENTRYDLG; alias RASPBDLGW RASPBDLG; alias RASNOUSERW RASNOUSER; alias RasDialDlgW RasDialDlg; alias RasEntryDlgW RasEntryDlg; alias RasPhonebookDlgW RasPhonebookDlg; } else { alias RASENTRYDLGA RASENTRYDLG; alias RASPBDLGA RASPBDLG; alias RASNOUSERA RASNOUSER; alias RasDialDlgA RasDialDlg; alias RasEntryDlgA RasEntryDlg; alias RasPhonebookDlgA RasPhonebookDlg; } alias RASENTRYDLG* LPRASENTRYDLG; alias RASPBDLG* LPRASPBDLG; alias RASNOUSER* LPRASNOUSER; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/httpext.d0000664000175000017500000000653312776214756023366 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_httpext.d) */ module core.sys.windows.httpext; version (Windows): /* Comment from MinGW httpext.h - Header for ISAPI extensions. This file is part of a free library for the Win32 API. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ private import core.sys.windows.windows; enum { HSE_VERSION_MAJOR = 2, HSE_VERSION_MINOR = 0, HSE_LOG_BUFFER_LEN = 80, HSE_MAX_EXT_DLL_NAME_LEN = 256, HSE_STATUS_SUCCESS = 1, HSE_STATUS_SUCCESS_AND_KEEP_CONN, HSE_STATUS_PENDING, HSE_STATUS_ERROR, HSE_REQ_BASE = 0, HSE_REQ_SEND_URL_REDIRECT_RESP, HSE_REQ_SEND_URL, HSE_REQ_SEND_RESPONSE_HEADER, HSE_REQ_DONE_WITH_SESSION, HSE_REQ_SEND_RESPONSE_HEADER_EX = 1016, HSE_REQ_END_RESERVED = 1000, HSE_TERM_ADVISORY_UNLOAD = 0x00000001, HSE_TERM_MUST_UNLOAD, HSE_IO_SYNC = 0x00000001, HSE_IO_ASYNC, HSE_IO_DISCONNECT_AFTER_SEND = 0x00000004, HSE_IO_SEND_HEADERS = 0x00000008 } mixin DECLARE_HANDLE!("HCONN"); struct HSE_VERSION_INFO { DWORD dwExtensionVersion; CHAR[HSE_MAX_EXT_DLL_NAME_LEN] lpszExtensionDesc; } alias HSE_VERSION_INFO* LPHSE_VERSION_INFO; struct EXTENSION_CONTROL_BLOCK { DWORD cbSize = EXTENSION_CONTROL_BLOCK.sizeof; DWORD dwVersion; HCONN ConnID; DWORD dwHttpStatusCode; CHAR[HSE_LOG_BUFFER_LEN] lpszLogData; LPSTR lpszMethod; LPSTR lpszQueryString; LPSTR lpszPathInfo; LPSTR lpszPathTranslated; DWORD cbTotalBytes; DWORD cbAvailable; LPBYTE lpbData; LPSTR lpszContentType; extern(Pascal) BOOL function(HCONN, LPSTR, LPVOID, LPDWORD) GetServerVariable; extern(Pascal) BOOL function(HCONN, LPVOID, LPDWORD, DWORD) WriteClient; extern(Pascal) BOOL function(HCONN, LPVOID, LPDWORD) ReadClient; extern(Pascal) BOOL function(HCONN, DWORD, LPVOID, LPDWORD, LPDWORD) ServerSupportFunction; } alias EXTENSION_CONTROL_BLOCK* LPEXTENSION_CONTROL_BLOCK; extern (Pascal) { alias BOOL function(HSE_VERSION_INFO*) PFN_GETEXTENSIONVERSION; alias DWORD function(EXTENSION_CONTROL_BLOCK*) PFN_HTTPEXTENSIONPROC; alias BOOL function(DWORD) PFN_TERMINATEEXTENSION; alias VOID function(EXTENSION_CONTROL_BLOCK*, PVOID, DWORD, DWORD) PFN_HSE_IO_COMPLETION; } struct HSE_TF_INFO { PFN_HSE_IO_COMPLETION pfnHseIO; PVOID pContext; HANDLE hFile; LPCSTR pszStatusCode; DWORD BytesToWrite; DWORD Offset; PVOID pHead; DWORD HeadLength; PVOID pTail; DWORD TailLength; DWORD dwFlags; } alias HSE_TF_INFO* LPHSE_TF_INFO; struct HSE_SEND_HEADER_EX_INFO { LPCSTR pszStatus; LPCSTR pszHeader; DWORD cchStatus; DWORD cchHeader; BOOL fKeepConn; } alias HSE_SEND_HEADER_EX_INFO* LPHSE_SEND_HEADER_EX_INF; extern (Pascal) { BOOL GetExtensionVersion(HSE_VERSION_INFO*); DWORD HttpExtensionProc(EXTENSION_CONTROL_BLOCK*); BOOL TerminateExtension(DWORD); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/oleidl.d0000664000175000017500000001644712776214756023143 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_oleidl.d) */ module core.sys.windows.oleidl; version (Windows): // DAC: This is defined in ocidl !! // what is it doing in here? //alias IEnumOleUndoUnits LPENUMOLEUNDOUNITS; private import core.sys.windows.basetyps, core.sys.windows.objidl, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.winuser, core.sys.windows.wtypes; private import core.sys.windows.objfwd; // for LPMONIKER private import core.sys.windows.wingdi; // for LPLOGPALETTE enum MK_ALT = 32; enum BINDSPEED { BINDSPEED_INDEFINITE = 1, BINDSPEED_MODERATE, BINDSPEED_IMMEDIATE } enum OLEWHICHMK { OLEWHICHMK_CONTAINER = 1, OLEWHICHMK_OBJREL, OLEWHICHMK_OBJFULL } enum OLEGETMONIKER { OLEGETMONIKER_ONLYIFTHERE = 1, OLEGETMONIKER_FORCEASSIGN, OLEGETMONIKER_UNASSIGN, OLEGETMONIKER_TEMPFORUSER } enum USERCLASSTYPE { USERCLASSTYPE_FULL = 1, USERCLASSTYPE_SHORT, USERCLASSTYPE_APPNAME } enum DROPEFFECT { DROPEFFECT_NONE = 0, DROPEFFECT_COPY = 1, DROPEFFECT_MOVE = 2, DROPEFFECT_LINK = 4, DROPEFFECT_SCROLL = 0x80000000 } struct OLEMENUGROUPWIDTHS { LONG[6] width; } alias OLEMENUGROUPWIDTHS* LPOLEMENUGROUPWIDTHS; alias HGLOBAL HOLEMENU; enum OLECLOSE { OLECLOSE_SAVEIFDIRTY, OLECLOSE_NOSAVE, OLECLOSE_PROMPTSAVE } struct OLEVERB { LONG lVerb; LPWSTR lpszVerbName; DWORD fuFlags; DWORD grfAttribs; } alias OLEVERB* LPOLEVERB; alias RECT BORDERWIDTHS; alias LPRECT LPBORDERWIDTHS; alias LPCRECT LPCBORDERWIDTHS; struct OLEINPLACEFRAMEINFO { UINT cb; BOOL fMDIApp; HWND hwndFrame; HACCEL haccel; UINT cAccelEntries; } alias OLEINPLACEFRAMEINFO* LPOLEINPLACEFRAMEINFO; interface IEnumOLEVERB : IUnknown { HRESULT Next(ULONG,OLEVERB*,ULONG*); HRESULT Skip(ULONG); HRESULT Reset(); HRESULT Clone(IEnumOLEVERB*); } //alias IEnumOLEVERB IEnumOleVerb; alias IEnumOLEVERB LPENUMOLEVERB; interface IParseDisplayName : IUnknown { HRESULT ParseDisplayName(IBindCtx,LPOLESTR,ULONG*,IMoniker*); } alias IParseDisplayName LPPARSEDISPLAYNAME; interface IOleContainer : IParseDisplayName { HRESULT EnumObjects(DWORD,IEnumUnknown*); HRESULT LockContainer(BOOL); } alias IOleContainer LPOLECONTAINER; interface IOleItemContainer : IOleContainer { HRESULT GetObject(LPOLESTR,DWORD,IBindCtx,REFIID,void**); HRESULT GetObjectStorage(LPOLESTR,IBindCtx,REFIID,void**); HRESULT IsRunning(LPOLESTR); } interface IOleClientSite : IUnknown { HRESULT SaveObject(); HRESULT GetMoniker(DWORD,DWORD,LPMONIKER*); HRESULT GetContainer(LPOLECONTAINER*); HRESULT ShowObject(); HRESULT OnShowWindow(BOOL); HRESULT RequestNewObjectLayout(); } alias IOleClientSite LPOLECLIENTSITE; interface IOleObject : IUnknown { HRESULT SetClientSite(LPOLECLIENTSITE); HRESULT GetClientSite(LPOLECLIENTSITE*); HRESULT SetHostNames(LPCOLESTR,LPCOLESTR); HRESULT Close(DWORD); HRESULT SetMoniker(DWORD,LPMONIKER); HRESULT GetMoniker(DWORD,DWORD,LPMONIKER*); HRESULT InitFromData(LPDATAOBJECT,BOOL,DWORD); HRESULT GetClipboardData(DWORD,LPDATAOBJECT*); HRESULT DoVerb(LONG,LPMSG,LPOLECLIENTSITE,LONG,HWND,LPCRECT); HRESULT EnumVerbs(LPENUMOLEVERB*); HRESULT Update(); HRESULT IsUpToDate(); HRESULT GetUserClassID(LPCLSID); HRESULT GetUserType(DWORD,LPOLESTR*); HRESULT SetExtent(DWORD,SIZEL*); HRESULT GetExtent(DWORD,SIZEL*); HRESULT Advise(LPADVISESINK,PDWORD); HRESULT Unadvise(DWORD); HRESULT EnumAdvise(LPENUMSTATDATA*); HRESULT GetMiscStatus(DWORD,PDWORD); HRESULT SetColorScheme(LPLOGPALETTE); } alias IOleObject LPOLEOBJECT; interface IOleWindow : IUnknown { HRESULT GetWindow(HWND*); HRESULT ContextSensitiveHelp(BOOL); } alias IOleWindow LPOLEWINDOW; interface IOleInPlaceUIWindow : IOleWindow { HRESULT GetBorder(LPRECT); HRESULT RequestBorderSpace(LPCBORDERWIDTHS); HRESULT SetBorderSpace(LPCBORDERWIDTHS); HRESULT SetActiveObject(LPOLEINPLACEACTIVEOBJECT,LPCOLESTR); } alias IOleInPlaceUIWindow LPOLEINPLACEUIWINDOW; interface IOleInPlaceObject : IOleWindow { HRESULT InPlaceDeactivate(); HRESULT UIDeactivate(); HRESULT SetObjectRects(LPCRECT,LPCRECT); HRESULT ReactivateAndUndo(); } interface IOleInPlaceActiveObject : IOleWindow { HRESULT TranslateAccelerator(LPMSG); HRESULT OnFrameWindowActivate(BOOL); HRESULT OnDocWindowActivate(BOOL); HRESULT ResizeBorder(LPCRECT,LPOLEINPLACEUIWINDOW,BOOL); HRESULT EnableModeless(BOOL); } alias IOleInPlaceActiveObject LPOLEINPLACEACTIVEOBJECT; interface IOleInPlaceFrame : IOleInPlaceUIWindow { HRESULT InsertMenus(HMENU,LPOLEMENUGROUPWIDTHS); HRESULT SetMenu(HMENU,HOLEMENU,HWND); HRESULT RemoveMenus(HMENU); HRESULT SetStatusText(LPCOLESTR); HRESULT EnableModeless(BOOL); HRESULT TranslateAccelerator(LPMSG,WORD); } alias IOleInPlaceFrame LPOLEINPLACEFRAME; interface IOleInPlaceSite : IOleWindow { HRESULT CanInPlaceActivate(); HRESULT OnInPlaceActivate(); HRESULT OnUIActivate(); HRESULT GetWindowContext(IOleInPlaceFrame,IOleInPlaceUIWindow,LPRECT,LPRECT,LPOLEINPLACEFRAMEINFO); HRESULT Scroll(SIZE); HRESULT OnUIDeactivate(BOOL); HRESULT OnInPlaceDeactivate(); HRESULT DiscardUndoState(); HRESULT DeactivateAndUndo(); HRESULT OnPosRectChange(LPCRECT); } interface IOleAdviseHolder : IUnknown { HRESULT Advise(LPADVISESINK,PDWORD); HRESULT Unadvise(DWORD); HRESULT EnumAdvise(LPENUMSTATDATA*); HRESULT SendOnRename(LPMONIKER); HRESULT SendOnSave(); HRESULT SendOnClose(); } alias IOleAdviseHolder LPOLEADVISEHOLDER; interface IDropSource : IUnknown { HRESULT QueryContinueDrag(BOOL,DWORD); HRESULT GiveFeedback(DWORD); } alias IDropSource LPDROPSOURCE; interface IDropTarget : IUnknown { HRESULT DragEnter(LPDATAOBJECT,DWORD,POINTL,PDWORD); HRESULT DragOver(DWORD,POINTL,PDWORD); HRESULT DragLeave(); HRESULT Drop(LPDATAOBJECT,DWORD,POINTL,PDWORD); } alias IDropTarget LPDROPTARGET; extern (Windows) { alias BOOL function(DWORD) __IView_pfncont; } interface IViewObject : IUnknown { HRESULT Draw(DWORD,LONG,PVOID,DVTARGETDEVICE*,HDC,HDC,LPCRECTL,LPCRECTL,__IView_pfncont pfnContinue,DWORD); HRESULT GetColorSet(DWORD,LONG,PVOID,DVTARGETDEVICE*,HDC,LPLOGPALETTE*); HRESULT Freeze(DWORD,LONG,PVOID,PDWORD); HRESULT Unfreeze(DWORD); HRESULT SetAdvise(DWORD,DWORD,IAdviseSink); HRESULT GetAdvise(PDWORD,PDWORD,IAdviseSink*); } alias IViewObject LPVIEWOBJECT; interface IViewObject2 : IViewObject { HRESULT GetExtent(DWORD,LONG,DVTARGETDEVICE*,LPSIZEL); } alias IViewObject2 LPVIEWOBJECT2; interface IOleCache : IUnknown { HRESULT Cache(FORMATETC*,DWORD,DWORD*); HRESULT Uncache(DWORD); HRESULT EnumCache(IEnumSTATDATA*); HRESULT InitCache(LPDATAOBJECT); HRESULT SetData(FORMATETC*,STGMEDIUM*,BOOL); } alias IOleCache LPOLECACHE; interface IOleCache2 : IOleCache { HRESULT UpdateCache(LPDATAOBJECT,DWORD,LPVOID); HRESULT DiscardCache(DWORD); } alias IOleCache2 LPOLECACHE2; interface IOleCacheControl : IUnknown { HRESULT OnRun(LPDATAOBJECT); HRESULT OnStop(); } alias IOleCacheControl LPOLECACHECONTROL; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/mshtml.d0000664000175000017500000004471612776214756023177 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_mshtml.d) */ module core.sys.windows.mshtml; version (Windows): private import core.sys.windows.basetyps, core.sys.windows.oaidl, core.sys.windows.unknwn, core.sys.windows.windef, core.sys.windows.wtypes; // These are used in this file, but not defined in MinGW. interface IHTMLStyleSheet {}; alias IHTMLStyle LPHTMLSTYLE; alias IHTMLStyleSheet LPHTMLSTYLESHEET; interface IHTMLLocation {}; alias IHTMLLocation LPHTMLLOCATION; interface IHTMLFramesCollection {}; alias IHTMLFramesCollection LPHTMLFRAMESCOLLECTION; interface IHTMLStyleSheetsCollection {}; alias IHTMLStyleSheetsCollection LPHTMLSTYLESHEETSCOLLECTION; interface IHTMLStyle {}; interface IHTMLFiltersCollection {}; alias IHTMLFiltersCollection LPHTMLFILTERSCOLLECTION; interface IOmHistory : IDispatch { HRESULT get_length(short* p); HRESULT back(VARIANT*); HRESULT forward(VARIANT*); HRESULT go(VARIANT*); }; alias IOmHistory LPOMHISTORY; interface IOmNavigator {}; alias IOmNavigator LPOMNAVIGATOR; interface IHTMLImageElementFactory {}; alias IHTMLImageElementFactory LPHTMLIMAGEELEMENTFACTORY; interface IHTMLEventObj {}; alias IHTMLEventObj LPHTMLEVENTOBJ; interface IHTMLScreen {}; alias IHTMLScreen LPHTMLSCREEN; interface IHTMLOptionElementFactory {}; alias IHTMLOptionElementFactory LPHTMLOPTIONELEMENTFACTORY; interface IHTMLLinkElement : IDispatch { HRESULT put_href(BSTR); HRESULT get_href(BSTR*); HRESULT put_rel(BSTR); HRESULT get_rel(BSTR*); HRESULT put_rev(BSTR); HRESULT get_rev(BSTR*); HRESULT put_type(BSTR); HRESULT get_type(BSTR*); HRESULT get_readyState(BSTR*); HRESULT put_onreadystatechange(VARIANT); HRESULT get_onreadystatechange(VARIANT*); HRESULT put_onload(VARIANT); HRESULT get_onload(VARIANT*); HRESULT put_onerror(VARIANT); HRESULT get_onerror(VARIANT*); HRESULT get_styleSheet(LPHTMLSTYLESHEET*); HRESULT put_disabled(VARIANT_BOOL); HRESULT get_disabled(VARIANT_BOOL*); HRESULT put_media(BSTR); HRESULT get_media(BSTR*); } alias IHTMLLinkElement LPHTMLLINKELEMENT; interface IHTMLImgElement : IDispatch { HRESULT put_isMap(VARIANT_BOOL); HRESULT get_isMap(VARIANT_BOOL*); HRESULT put_useMap(BSTR); HRESULT get_useMap(BSTR*); HRESULT get_mimeType(BSTR*); HRESULT get_fileSize(BSTR*); HRESULT get_fileCreatedDate(BSTR*); HRESULT get_fileModifiedDate(BSTR*); HRESULT get_fileUpdatedDate(BSTR*); HRESULT get_protocol(BSTR*); HRESULT get_href(BSTR*); HRESULT get_nameProp(BSTR*); HRESULT put_border(VARIANT); HRESULT get_border(VARIANT*); HRESULT put_vspace(LONG); HRESULT get_vspace(LONG*); HRESULT put_hspace(LONG); HRESULT get_hspace(LONG*); HRESULT put_alt(BSTR); HRESULT get_alt(BSTR*); HRESULT put_src(BSTR); HRESULT get_src(BSTR*); HRESULT put_lowsrc(BSTR); HRESULT get_lowsrc(BSTR*); HRESULT put_vrml(BSTR); HRESULT get_vrml(BSTR*); HRESULT put_dynsrc(BSTR); HRESULT get_dynsrc(BSTR*); HRESULT get_readyState(BSTR*); HRESULT get_complete(VARIANT_BOOL*); HRESULT put_loop(VARIANT); HRESULT get_loop(VARIANT*); HRESULT put_align(BSTR); HRESULT get_align(BSTR*); HRESULT put_onload(VARIANT); HRESULT get_onload(VARIANT*); HRESULT put_onerror(VARIANT); HRESULT get_onerror(VARIANT*); HRESULT put_onabort(VARIANT); HRESULT get_onabort(VARIANT*); HRESULT put_name(BSTR); HRESULT get_name(BSTR*); HRESULT put_width(LONG); HRESULT get_width(LONG*); HRESULT put_height(LONG); HRESULT get_height(LONG*); HRESULT put_start(BSTR); HRESULT get_start(BSTR*); } alias IHTMLImgElement LPHTMLIMGELEMENT; interface IHTMLElementCollection : IDispatch { HRESULT toString(BSTR*); HRESULT put_length(LONG); HRESULT get_length(LONG*); HRESULT get__newEnum(IUnknown*); HRESULT item(VARIANT,VARIANT,IDispatch* pDisp); HRESULT tags(VARIANT,IDispatch* pdisp); } alias IHTMLElementCollection LPHTMLELEMENTCOLLECTION; interface IHTMLDocument : IDispatch { HRESULT get_Script(IDispatch*); } interface IHTMLDocument2 : IHTMLDocument { HRESULT get_all(LPHTMLELEMENTCOLLECTION*); HRESULT get_body(LPHTMLELEMENT*); HRESULT get_activeElement(LPHTMLELEMENT*); HRESULT get_images(LPHTMLELEMENTCOLLECTION*); HRESULT get_applets(LPHTMLELEMENTCOLLECTION*); HRESULT get_links(LPHTMLELEMENTCOLLECTION*); HRESULT get_forms(LPHTMLELEMENTCOLLECTION*); HRESULT get_anchors(LPHTMLELEMENTCOLLECTION*); HRESULT put_title(BSTR); HRESULT get_title(BSTR*); HRESULT get_scripts(LPHTMLELEMENTCOLLECTION*); HRESULT put_designMode(BSTR); HRESULT get_designMode(BSTR*); HRESULT get_selection(LPHTMLSELECTIONOBJECT*); HRESULT get_readyState(BSTR*); HRESULT get_frames(IHTMLFramesCollection2*); HRESULT get_embeds(LPHTMLELEMENTCOLLECTION*); HRESULT get_plugins(LPHTMLELEMENTCOLLECTION*); HRESULT put_alinkColor(VARIANT); HRESULT get_alinkColor(VARIANT*); HRESULT put_bgColor(VARIANT); HRESULT get_bgColor(VARIANT*); HRESULT put_fgColor(VARIANT); HRESULT get_fgColor(VARIANT*); HRESULT put_linkColor(VARIANT); HRESULT get_linkColor(VARIANT*); HRESULT put_vlinkColor(VARIANT); HRESULT get_vlinkColor(VARIANT*); HRESULT get_referrer(BSTR*); HRESULT get_location(LPHTMLLOCATION*); HRESULT get_lastModified(BSTR*); HRESULT put_url(BSTR); HRESULT get_url(BSTR*); HRESULT put_domain(BSTR); HRESULT get_domain(BSTR*); HRESULT put_cookie(BSTR); HRESULT get_cookie(BSTR*); HRESULT put_expands(VARIANT_BOOL); HRESULT get_expands(VARIANT_BOOL*); HRESULT put_charset(BSTR); HRESULT get_charset(BSTR*); HRESULT put_defaultCharset(BSTR); HRESULT get_defaultCharset(BSTR*); HRESULT get_mimeType(BSTR*); HRESULT get_fileSize(BSTR*); HRESULT get_fileCreatedDate(BSTR*); HRESULT get_fileModifiedDate(BSTR*); HRESULT get_fileUpdatedDate(BSTR*); HRESULT get_security(BSTR*); HRESULT get_protocol(BSTR*); HRESULT get_nameProp(BSTR*); HRESULT write(SAFEARRAY*); HRESULT writeln(SAFEARRAY*); HRESULT open(BSTR,VARIANT,VARIANT,VARIANT,IDispatch*); HRESULT close(); HRESULT clear(); HRESULT queryCommandSupported(BSTR,VARIANT_BOOL*); HRESULT queryCommandEnabled(BSTR,VARIANT_BOOL*); HRESULT queryCommandState(BSTR,VARIANT_BOOL*); HRESULT queryCommandIndeterm(BSTR,VARIANT_BOOL*); HRESULT queryCommandText(BSTR,BSTR*); HRESULT queryCommandValue(BSTR,VARIANT*); HRESULT execCommand(BSTR,VARIANT_BOOL,VARIANT,VARIANT_BOOL*); HRESULT execCommandShowHelp(BSTR,VARIANT_BOOL*); HRESULT createElement(BSTR,LPHTMLELEMENT*); HRESULT put_onhelp(VARIANT); HRESULT get_onhelp(VARIANT*); HRESULT put_onclick(VARIANT); HRESULT get_onclick(VARIANT*); HRESULT put_ondblclick(VARIANT); HRESULT get_ondblclick(VARIANT*); HRESULT put_onkeyup(VARIANT); HRESULT get_onkeyup(VARIANT*); HRESULT put_onkeydown(VARIANT); HRESULT get_onkeydown(VARIANT*); HRESULT put_onkeypress(VARIANT); HRESULT get_onkeypress(VARIANT*); HRESULT put_onmouseup(VARIANT); HRESULT get_onmouseup(VARIANT*); HRESULT put_onmousedown(VARIANT); HRESULT get_onmousedown(VARIANT*); HRESULT put_onmousemove(VARIANT); HRESULT get_onmousemove(VARIANT*); HRESULT put_onmouseout(VARIANT); HRESULT get_onmouseout(VARIANT*); HRESULT put_onmouseover(VARIANT); HRESULT get_onmouseover(VARIANT*); HRESULT put_onreadystatechange(VARIANT); HRESULT get_onreadystatechange(VARIANT*); HRESULT put_onafterupdate(VARIANT); HRESULT get_onafterupdate(VARIANT*); HRESULT put_onrowexit(VARIANT); HRESULT get_onrowexit(VARIANT*); HRESULT put_onrowenter(VARIANT); HRESULT get_onrowenter(VARIANT*); HRESULT put_ondragstart(VARIANT); HRESULT get_ondragstart(VARIANT*); HRESULT put_onselectstart(VARIANT); HRESULT get_onselectstart(VARIANT*); HRESULT elementFromPoint(LONG,LONG,LPHTMLELEMENT*); HRESULT get_parentWindow(LPHTMLWINDOW2*); HRESULT get_styleSheets(LPHTMLSTYLESHEETSCOLLECTION*); HRESULT put_onbeforeupdate(VARIANT); HRESULT get_onbeforeupdate(VARIANT*); HRESULT put_onerrorupdate(VARIANT); HRESULT get_onerrorupdate(VARIANT*); HRESULT toString(BSTR*); HRESULT createStyleSheet(BSTR,LONG,LPHTMLSTYLESHEET*); } interface IHTMLSelectionObject : IDispatch { HRESULT createRange(IDispatch*); HRESULT empty(); HRESULT clear(); HRESULT get_type(BSTR*); } alias IHTMLSelectionObject LPHTMLSELECTIONOBJECT; interface IHTMLTxtRange : IDispatch { HRESULT get_htmlText(BSTR*); HRESULT put_text(BSTR); HRESULT get_text(BSTR*); HRESULT parentElement(LPHTMLELEMENT*); HRESULT duplicate(IHTMLTxtRange*); HRESULT inRange(IHTMLTxtRange,VARIANT_BOOL*); HRESULT isEqual(IHTMLTxtRange,VARIANT_BOOL*); HRESULT scrollIntoView(VARIANT_BOOL); HRESULT collapse(VARIANT_BOOL); HRESULT expand(BSTR,VARIANT_BOOL*); HRESULT move(BSTR,LONG,LONG*); HRESULT moveStart(BSTR,LONG,LONG*); HRESULT moveEnd(BSTR,LONG,LONG*); HRESULT select(); HRESULT pasteHTML(BSTR); HRESULT moveToElementText(LPHTMLELEMENT); HRESULT setEndPoint(BSTR,IHTMLTxtRange); HRESULT compareEndPoints(BSTR,IHTMLTxtRange,LONG*); HRESULT findText(BSTR,LONG,LONG,VARIANT_BOOL*); HRESULT moveToPoint(LONG,LONG); HRESULT getBookmark(BSTR*); HRESULT moveToBookbark(BSTR,VARIANT_BOOL*); HRESULT queryCommandSupported(BSTR,VARIANT_BOOL*); HRESULT queryCommandEnabled(BSTR,VARIANT_BOOL*); HRESULT queryCommandState(BSTR,VARIANT_BOOL*); HRESULT queryCommandIndeterm(BSTR,VARIANT_BOOL*); HRESULT queryCommandText(BSTR,BSTR*); HRESULT queryCommandValue(BSTR,VARIANT*); HRESULT execCommand(BSTR,VARIANT_BOOL,VARIANT,VARIANT_BOOL*); HRESULT execCommandShowHelp(BSTR,VARIANT_BOOL*); } interface IHTMLElement : IDispatch { HRESULT setAttribute(BSTR,VARIANT,LONG); HRESULT getAttribute(BSTR,LONG,VARIANT*); HRESULT removeAttribute(BSTR,LONG,VARIANT_BOOL*); HRESULT put_className(BSTR); HRESULT get_className(BSTR*); HRESULT put_id(BSTR); HRESULT get_id(BSTR*); HRESULT get_tagName(BSTR*); HRESULT get_parentElement(LPHTMLELEMENT*); HRESULT get_style(LPHTMLSTYLE*); HRESULT put_onhelp(VARIANT); HRESULT get_onhelp(VARIANT*); HRESULT put_onclick(VARIANT); HRESULT get_onclick(VARIANT*); HRESULT put_ondblclick(VARIANT); HRESULT get_ondblclick(VARIANT*); HRESULT put_onkeydown(VARIANT); HRESULT get_onkeydown(VARIANT*); HRESULT put_onkeyup(VARIANT); HRESULT get_onkeyup(VARIANT*); HRESULT put_onkeypress(VARIANT); HRESULT get_onkeypress(VARIANT*); HRESULT put_onmouseout(VARIANT); HRESULT get_onmouseout(VARIANT*); HRESULT put_onmouseover(VARIANT); HRESULT get_onmouseover(VARIANT*); HRESULT put_onmousemove(VARIANT); HRESULT get_onmousemove(VARIANT*); HRESULT put_onmousedown(VARIANT); HRESULT get_onmousedown(VARIANT*); HRESULT put_onmouseup(VARIANT); HRESULT get_onmouseup(VARIANT*); HRESULT get_document(IDispatch*); HRESULT put_title(BSTR); HRESULT get_title(BSTR*); HRESULT put_language(BSTR); HRESULT get_language(BSTR*); HRESULT put_onselectstart(VARIANT); HRESULT get_onselectstart(VARIANT*); HRESULT scrollIntoView(VARIANT); HRESULT contains(LPHTMLELEMENT,VARIANT_BOOL*); HRESULT get_source3Index(LONG*); HRESULT get_recordNumber(VARIANT*); HRESULT put_lang(BSTR); HRESULT get_lang(BSTR*); HRESULT get_offsetLeft(LONG*); HRESULT get_offsetTop(LONG*); HRESULT get_offsetWidth(LONG*); HRESULT get_offsetHeight(LONG*); HRESULT get_offsetParent(LPHTMLELEMENT*); HRESULT put_innerHTML(BSTR); HRESULT get_innerHTML(BSTR*); HRESULT put_innerText(BSTR); HRESULT get_innerText(BSTR*); HRESULT put_outerHTML(BSTR); HRESULT get_outerHTML(BSTR*); HRESULT put_outerText(BSTR); HRESULT get_outerText(BSTR*); HRESULT insertAdjacentHTML(BSTR,BSTR); HRESULT insertAdjacentText(BSTR,BSTR); HRESULT get_parentTextEdit(LPHTMLELEMENT*); HRESULT isTextEdit(VARIANT_BOOL*); HRESULT click(); HRESULT get_filters(LPHTMLFILTERSCOLLECTION*); HRESULT put_ondragstart(VARIANT); HRESULT get_ondragstart(VARIANT*); HRESULT toString(BSTR*); HRESULT put_onbeforeupdate(VARIANT); HRESULT get_onbeforeupdate(VARIANT*); HRESULT put_onafterupdate(VARIANT); HRESULT get_onafterupdate(VARIANT*); HRESULT put_onerrorupdate(VARIANT); HRESULT get_onerrorupdate(VARIANT*); HRESULT put_onrowexit(VARIANT); HRESULT get_onrowexit(VARIANT*); HRESULT put_onrowenter(VARIANT); HRESULT get_onrowenter(VARIANT*); HRESULT put_ondatasetchanged(VARIANT); HRESULT get_ondatasetchanged(VARIANT*); HRESULT put_ondataavailable(VARIANT); HRESULT get_ondataavailable(VARIANT*); HRESULT put_ondatasetcomplete(VARIANT); HRESULT get_ondatasetcomplete(VARIANT*); HRESULT put_onfilterchange(VARIANT); HRESULT get_onfilterchange(VARIANT*); HRESULT get_children(IDispatch*); HRESULT get_all(IDispatch*); } alias IHTMLElement LPHTMLELEMENT; interface IHTMLFramesCollection2 : IDispatch { HRESULT item(VARIANT*,VARIANT*); HRESULT get_length(LONG*); } interface IHTMLWindow2 : IHTMLFramesCollection2 { HRESULT get_frames(IHTMLFramesCollection2*); HRESULT put_defaultStatus(BSTR); HRESULT get_defaultStatus(BSTR*); HRESULT put_status(BSTR); HRESULT get_status(BSTR*); HRESULT setTimeout(BSTR,LONG,VARIANT*,LONG*); HRESULT clearTimeout(LONG); HRESULT alert(BSTR); HRESULT confirm(BSTR,VARIANT_BOOL*); HRESULT prompt(BSTR,BSTR,VARIANT*); HRESULT get_Image(LPHTMLIMAGEELEMENTFACTORY*); HRESULT get_location(LPHTMLLOCATION*); HRESULT get_history(LPOMHISTORY*); HRESULT close(); HRESULT put_opener(VARIANT); HRESULT get_opener(VARIANT*); HRESULT get_navigator(LPOMNAVIGATOR*); HRESULT put_name(BSTR); HRESULT get_name(BSTR*); HRESULT get_parent(LPHTMLWINDOW2*); HRESULT open(BSTR,BSTR,BSTR,VARIANT_BOOL,LPHTMLWINDOW2*); HRESULT get_self(LPHTMLWINDOW2*); HRESULT get_top(LPHTMLWINDOW2*); HRESULT get_window(LPHTMLWINDOW2*); HRESULT navigate(BSTR); HRESULT put_onfocus(VARIANT); HRESULT get_onfocus(VARIANT*); HRESULT put_onblur(VARIANT); HRESULT get_onblur(VARIANT*); HRESULT put_onload(VARIANT); HRESULT get_onload(VARIANT*); HRESULT put_onbeforeunload(VARIANT); HRESULT get_onbeforeunload(VARIANT*); HRESULT put_onunload(VARIANT); HRESULT get_onunload(VARIANT*); HRESULT put_onhelp(VARIANT); HRESULT get_onhelp(VARIANT*); HRESULT put_onerror(VARIANT); HRESULT get_onerror(VARIANT*); HRESULT put_onresize(VARIANT); HRESULT get_onresize(VARIANT*); HRESULT put_onscroll(VARIANT); HRESULT get_onscroll(VARIANT*); HRESULT get_document(IHTMLDocument2*); HRESULT get_event(LPHTMLEVENTOBJ*); HRESULT get__newEnum(IUnknown*); HRESULT showModalDialog(BSTR,VARIANT*,VARIANT*,VARIANT*); HRESULT showHelp(BSTR,VARIANT,BSTR); HRESULT get_screen(LPHTMLSCREEN*); HRESULT get_Option(LPHTMLOPTIONELEMENTFACTORY*); HRESULT focus(); HRESULT get_closed(VARIANT_BOOL*); HRESULT blur(); HRESULT scroll(long,long); HRESULT get_clientInformation(LPOMNAVIGATOR*); HRESULT setInterval(BSTR,long,VARIANT*,long*); HRESULT clearInterval(long); HRESULT put_offscreenBuffering(VARIANT); HRESULT get_offscreenBuffering(VARIANT*); HRESULT execScript(BSTR,BSTR,VARIANT*); HRESULT toString(BSTR*); HRESULT scrollBy(LONG,LONG); HRESULT scrollTo(LONG,LONG); HRESULT moveTo(LONG,LONG); HRESULT moveBy(LONG,LONG); HRESULT resizeTo(LONG,LONG); HRESULT resizeBy(LONG,LONG); HRESULT get_external(IDispatch*); } alias IHTMLWindow2 LPHTMLWINDOW2; interface IHTMLFrameBase : IDispatch { HRESULT put_src(BSTR); HRESULT get_src(BSTR*); HRESULT put_name(BSTR); HRESULT get_name(BSTR*); HRESULT put_border(VARIANT); HRESULT get_border(VARIANT*); HRESULT put_frameBorder(BSTR); HRESULT get_frameBorder(BSTR*); HRESULT put_frameSpacing(VARIANT); HRESULT get_frameSpacing(VARIANT*); HRESULT put_marginWidth(VARIANT); HRESULT get_marginWidth(VARIANT*); HRESULT put_marginHeight(VARIANT); HRESULT get_marginHeight(VARIANT*); HRESULT put_noResize(VARIANT_BOOL); HRESULT get_noResize(VARIANT_BOOL*); HRESULT put_scrolling(BSTR); HRESULT get_scrolling(BSTR*); } interface IHTMLFrameBase2 : IDispatch { HRESULT get_contentWindow(IHTMLWindow2*); HRESULT put_onload(VARIANT); HRESULT get_onload(VARIANT*); HRESULT put_onreadystatechange(VARIANT); HRESULT get_onreadystatechange(VARIANT*); HRESULT get_readyState(BSTR*); HRESULT put_allowTransparency(VARIANT_BOOL); HRESULT get_allowTransparency(VARIANT_BOOL*); } interface IHTMLFrameBase3 : IDispatch { HRESULT put_longDesc(BSTR); HRESULT get_longDesc(BSTR*); } interface IHTMLBodyElement : IDispatch { HRESULT put_background(BSTR); HRESULT get_background(BSTR*); HRESULT put_bgProperties(BSTR); HRESULT get_bgProperties(BSTR*); HRESULT put_leftMargin(VARIANT); HRESULT get_leftMargin(VARIANT*); HRESULT put_topMargin(VARIANT); HRESULT get_topMargin(VARIANT*); HRESULT put_rightMargin(VARIANT); HRESULT get_rightMargin(VARIANT*); HRESULT put_bottomMargin(VARIANT); HRESULT get_bottomMargin(VARIANT*); HRESULT put_noWrap(VARIANT_BOOL); HRESULT get_noWrap(VARIANT_BOOL*); HRESULT put_bgColor(VARIANT); HRESULT get_bgColor(VARIANT*); HRESULT put_text(VARIANT); HRESULT get_text(VARIANT*); HRESULT put_link(VARIANT); HRESULT get_link(VARIANT*); HRESULT put_vLink(VARIANT); HRESULT get_vLink(VARIANT*); HRESULT put_aLink(VARIANT); HRESULT get_aLink(VARIANT*); HRESULT put_onload(VARIANT); HRESULT get_onload(VARIANT*); HRESULT put_onunload(VARIANT); HRESULT get_onunload(VARIANT*); HRESULT put_scroll(BSTR); HRESULT get_scroll(BSTR*); HRESULT put_onselect(VARIANT); HRESULT get_onselect(VARIANT*); HRESULT put_onbeforeunload(VARIANT); HRESULT get_onbeforeunload(VARIANT*); HRESULT createTextRange(IHTMLTxtRange*); } interface IHTMLBodyElement2 : IDispatch { HRESULT put_onbeforeprint(VARIANT); HRESULT get_onbeforeprint(VARIANT*); HRESULT put_onafterprint(VARIANT); HRESULT get_onafterprint(VARIANT*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/richedit.d0000664000175000017500000003174712776214756023466 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_richedit.d) */ module core.sys.windows.richedit; version (Windows): version (ANSI) {} else version = Unicode; private import core.sys.windows.windef, core.sys.windows.winuser; private import core.sys.windows.wingdi; // for LF_FACESIZE align(4): version(Unicode) { const wchar[] RICHEDIT_CLASS = "RichEdit20W"; } else { const char[] RICHEDIT_CLASS = "RichEdit20A"; } enum RICHEDIT_CLASS10A = "RICHEDIT"; const TCHAR[] CF_RTF = "Rich Text Format", CF_RTFNOOBJS = "Rich Text Format Without Objects", CF_RETEXTOBJ = "RichEdit Text and Objects"; enum DWORD CFM_BOLD = 1, CFM_ITALIC = 2, CFM_UNDERLINE = 4, CFM_STRIKEOUT = 8, CFM_PROTECTED = 16, CFM_LINK = 32, CFM_SIZE = 0x80000000, CFM_COLOR = 0x40000000, CFM_FACE = 0x20000000, CFM_OFFSET = 0x10000000, CFM_CHARSET = 0x08000000, CFM_SUBSCRIPT = 0x00030000, CFM_SUPERSCRIPT = 0x00030000; enum DWORD CFE_BOLD = 1, CFE_ITALIC = 2, CFE_UNDERLINE = 4, CFE_STRIKEOUT = 8, CFE_PROTECTED = 16, CFE_SUBSCRIPT = 0x00010000, CFE_SUPERSCRIPT = 0x00020000, CFE_AUTOCOLOR = 0x40000000; enum CFM_EFFECTS = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_COLOR | CFM_STRIKEOUT | CFE_PROTECTED | CFM_LINK; // flags for EM_SETIMEOPTIONS enum LPARAM IMF_FORCENONE = 1, IMF_FORCEENABLE = 2, IMF_FORCEDISABLE = 4, IMF_CLOSESTATUSWINDOW = 8, IMF_VERTICAL = 32, IMF_FORCEACTIVE = 64, IMF_FORCEINACTIVE = 128, IMF_FORCEREMEMBER = 256; enum SEL_EMPTY=0; enum SEL_TEXT=1; enum SEL_OBJECT=2; enum SEL_MULTICHAR=4; enum SEL_MULTIOBJECT=8; enum MAX_TAB_STOPS=32; enum PFM_ALIGNMENT=8; enum PFM_NUMBERING=32; enum PFM_OFFSET=4; enum PFM_OFFSETINDENT=0x80000000; enum PFM_RIGHTINDENT=2; enum PFM_STARTINDENT=1; enum PFM_TABSTOPS=16; enum PFM_BORDER=2048; enum PFM_LINESPACING=256; enum PFM_NUMBERINGSTART=32768; enum PFM_NUMBERINGSTYLE=8192; enum PFM_NUMBERINGTAB=16384; enum PFM_SHADING=4096; enum PFM_SPACEAFTER=128; enum PFM_SPACEBEFORE=64; enum PFM_STYLE=1024; enum PFM_DONOTHYPHEN=4194304; enum PFM_KEEP=131072; enum PFM_KEEPNEXT=262144; enum PFM_NOLINENUMBER=1048576; enum PFM_NOWIDOWCONTROL=2097152; enum PFM_PAGEBREAKBEFORE=524288; enum PFM_RTLPARA=65536; enum PFM_SIDEBYSIDE=8388608; enum PFM_TABLE=1073741824; enum PFN_BULLET=1; enum PFE_DONOTHYPHEN=64; enum PFE_KEEP=2; enum PFE_KEEPNEXT=4; enum PFE_NOLINENUMBER=16; enum PFE_NOWIDOWCONTROL=32; enum PFE_PAGEBREAKBEFORE=8; enum PFE_RTLPARA=1; enum PFE_SIDEBYSIDE=128; enum PFE_TABLE=16384; enum PFA_LEFT=1; enum PFA_RIGHT=2; enum PFA_CENTER=3; enum PFA_JUSTIFY=4; enum PFA_FULL_INTERWORD=4; enum SF_TEXT=1; enum SF_RTF=2; enum SF_RTFNOOBJS=3; enum SF_TEXTIZED=4; enum SF_UNICODE=16; enum SF_USECODEPAGE=32; enum SF_NCRFORNONASCII=64; enum SF_RTFVAL=0x0700; enum SFF_PWD=0x0800; enum SFF_KEEPDOCINFO=0x1000; enum SFF_PERSISTVIEWSCALE=0x2000; enum SFF_PLAINRTF=0x4000; enum SFF_SELECTION=0x8000; enum WB_CLASSIFY = 3; enum WB_MOVEWORDLEFT = 4; enum WB_MOVEWORDRIGHT = 5; enum WB_LEFTBREAK = 6; enum WB_RIGHTBREAK = 7; enum WB_MOVEWORDPREV = 4; enum WB_MOVEWORDNEXT = 5; enum WB_PREVBREAK = 6; enum WB_NEXTBREAK = 7; enum WBF_WORDWRAP = 16; enum WBF_WORDBREAK = 32; enum WBF_OVERFLOW = 64; enum WBF_LEVEL1 = 128; enum WBF_LEVEL2 = 256; enum WBF_CUSTOM = 512; enum ES_DISABLENOSCROLL = 8192; enum ES_SUNKEN = 16384; enum ES_SAVESEL = 32768; enum ES_EX_NOCALLOLEINIT = 16777216; enum ES_NOIME = 524288; enum ES_NOOLEDRAGDROP = 8; enum ES_SELECTIONBAR = 16777216; enum ES_SELFIME = 262144; enum ES_VERTICAL = 4194304; enum EM_CANPASTE = WM_USER+50; enum EM_DISPLAYBAND = WM_USER+51; enum EM_EXGETSEL = WM_USER+52; enum EM_EXLIMITTEXT = WM_USER+53; enum EM_EXLINEFROMCHAR = WM_USER+54; enum EM_EXSETSEL = WM_USER+55; enum EM_FINDTEXT = WM_USER+56; enum EM_FORMATRANGE = WM_USER+57; enum EM_GETCHARFORMAT = WM_USER+58; enum EM_GETEVENTMASK = WM_USER+59; enum EM_GETOLEINTERFACE = WM_USER+60; enum EM_GETPARAFORMAT = WM_USER+61; enum EM_GETSELTEXT = WM_USER+62; enum EM_HIDESELECTION = WM_USER+63; enum EM_PASTESPECIAL = WM_USER+64; enum EM_REQUESTRESIZE = WM_USER+65; enum EM_SELECTIONTYPE = WM_USER+66; enum EM_SETBKGNDCOLOR = WM_USER+67; enum EM_SETCHARFORMAT = WM_USER+68; enum EM_SETEVENTMASK = WM_USER+69; enum EM_SETOLECALLBACK = WM_USER+70; enum EM_SETPARAFORMAT = WM_USER+71; enum EM_SETTARGETDEVICE = WM_USER+72; enum EM_STREAMIN = WM_USER+73; enum EM_STREAMOUT = WM_USER+74; enum EM_GETTEXTRANGE = WM_USER+75; enum EM_FINDWORDBREAK = WM_USER+76; enum EM_SETOPTIONS = WM_USER+77; enum EM_GETOPTIONS = WM_USER+78; enum EM_FINDTEXTEX = WM_USER+79; enum EM_GETWORDBREAKPROCEX = WM_USER+80; enum EM_SETWORDBREAKPROCEX = WM_USER+81; /* RichEdit 2.0 messages */ enum EM_SETUNDOLIMIT = WM_USER+82; enum EM_REDO = WM_USER+84; enum EM_CANREDO = WM_USER+85; enum EM_GETUNDONAME = WM_USER+86; enum EM_GETREDONAME = WM_USER+87; enum EM_STOPGROUPTYPING = WM_USER+88; enum EM_SETTEXTMODE = WM_USER+89; enum EM_GETTEXTMODE = WM_USER+90; enum EM_AUTOURLDETECT = WM_USER+91; enum EM_GETAUTOURLDETECT = WM_USER + 92; enum EM_SETPALETTE = WM_USER + 93; enum EM_GETTEXTEX = WM_USER+94; enum EM_GETTEXTLENGTHEX = WM_USER+95; enum EM_SHOWSCROLLBAR = WM_USER+96; enum EM_SETTEXTEX = WM_USER + 97; enum EM_SETPUNCTUATION = WM_USER + 100; enum EM_GETPUNCTUATION = WM_USER + 101; enum EM_SETWORDWRAPMODE = WM_USER + 102; enum EM_GETWORDWRAPMODE = WM_USER + 103; enum EM_SETIMECOLOR = WM_USER + 104; enum EM_GETIMECOLOR = WM_USER + 105; enum EM_SETIMEOPTIONS = WM_USER + 106; enum EM_GETIMEOPTIONS = WM_USER + 107; enum EM_SETLANGOPTIONS = WM_USER+120; enum EM_GETLANGOPTIONS = WM_USER+121; enum EM_GETIMECOMPMODE = WM_USER+122; enum EM_FINDTEXTW = WM_USER + 123; enum EM_FINDTEXTEXW = WM_USER + 124; enum EM_RECONVERSION = WM_USER + 125; enum EM_SETBIDIOPTIONS = WM_USER + 200; enum EM_GETBIDIOPTIONS = WM_USER + 201; enum EM_SETTYPOGRAPHYOPTIONS = WM_USER+202; enum EM_GETTYPOGRAPHYOPTIONS = WM_USER+203; enum EM_SETEDITSTYLE = WM_USER + 204; enum EM_GETEDITSTYLE = WM_USER + 205; enum EM_GETSCROLLPOS = WM_USER+221; enum EM_SETSCROLLPOS = WM_USER+222; enum EM_SETFONTSIZE = WM_USER+223; enum EM_GETZOOM = WM_USER+224; enum EM_SETZOOM = WM_USER+225; enum EN_MSGFILTER = 1792; enum EN_REQUESTRESIZE = 1793; enum EN_SELCHANGE = 1794; enum EN_DROPFILES = 1795; enum EN_PROTECTED = 1796; enum EN_CORRECTTEXT = 1797; enum EN_STOPNOUNDO = 1798; enum EN_IMECHANGE = 1799; enum EN_SAVECLIPBOARD = 1800; enum EN_OLEOPFAILED = 1801; enum EN_LINK = 1803; enum ENM_NONE = 0; enum ENM_CHANGE = 1; enum ENM_UPDATE = 2; enum ENM_SCROLL = 4; enum ENM_SCROLLEVENTS = 8; enum ENM_DRAGDROPDONE = 16; enum ENM_KEYEVENTS = 65536; enum ENM_MOUSEEVENTS = 131072; enum ENM_REQUESTRESIZE = 262144; enum ENM_SELCHANGE = 524288; enum ENM_DROPFILES = 1048576; enum ENM_PROTECTED = 2097152; enum ENM_CORRECTTEXT = 4194304; enum ENM_IMECHANGE = 8388608; enum ENM_LANGCHANGE = 16777216; enum ENM_OBJECTPOSITIONS = 33554432; enum ENM_LINK = 67108864; enum ECO_AUTOWORDSELECTION=1; enum ECO_AUTOVSCROLL=64; enum ECO_AUTOHSCROLL=128; enum ECO_NOHIDESEL=256; enum ECO_READONLY=2048; enum ECO_WANTRETURN=4096; enum ECO_SAVESEL=0x8000; enum ECO_SELECTIONBAR=0x1000000; enum ECO_VERTICAL=0x400000; enum { ECOOP_SET = 1, ECOOP_OR, ECOOP_AND, ECOOP_XOR } enum SCF_DEFAULT = 0; enum SCF_SELECTION = 1; enum SCF_WORD = 2; enum SCF_ALL = 4; enum SCF_USEUIRULES = 8; alias DWORD TEXTMODE; enum TM_PLAINTEXT=1; enum TM_RICHTEXT=2; enum TM_SINGLELEVELUNDO=4; enum TM_MULTILEVELUNDO=8; enum TM_SINGLECODEPAGE=16; enum TM_MULTICODEPAGE=32; enum GT_DEFAULT=0; enum GT_USECRLF=1; enum yHeightCharPtsMost=1638; enum lDefaultTab=720; alias DWORD UNDONAMEID; enum UID_UNKNOWN = 0; enum UID_TYPING = 1; enum UID_DELETE = 2; enum UID_DRAGDROP = 3; enum UID_CUT = 4; enum UID_PASTE = 5; struct CHARFORMATA { UINT cbSize = this.sizeof; DWORD dwMask; DWORD dwEffects; LONG yHeight; LONG yOffset; COLORREF crTextColor; BYTE bCharSet; BYTE bPitchAndFamily; char[LF_FACESIZE] szFaceName; } struct CHARFORMATW { UINT cbSize = this.sizeof; DWORD dwMask; DWORD dwEffects; LONG yHeight; LONG yOffset; COLORREF crTextColor; BYTE bCharSet; BYTE bPitchAndFamily; WCHAR[LF_FACESIZE] szFaceName; } struct CHARFORMAT2A { UINT cbSize = this.sizeof; DWORD dwMask; DWORD dwEffects; LONG yHeight; LONG yOffset; COLORREF crTextColor; BYTE bCharSet; BYTE bPitchAndFamily; char[LF_FACESIZE] szFaceName; WORD wWeight; SHORT sSpacing; COLORREF crBackColor; LCID lcid; DWORD dwReserved; SHORT sStyle; WORD wKerning; BYTE bUnderlineType; BYTE bAnimation; BYTE bRevAuthor; } struct CHARFORMAT2W { UINT cbSize = this.sizeof; DWORD dwMask; DWORD dwEffects; LONG yHeight; LONG yOffset; COLORREF crTextColor; BYTE bCharSet; BYTE bPitchAndFamily; WCHAR[LF_FACESIZE] szFaceName; WORD wWeight; SHORT sSpacing; COLORREF crBackColor; LCID lcid; DWORD dwReserved; SHORT sStyle; WORD wKerning; BYTE bUnderlineType; BYTE bAnimation; BYTE bRevAuthor; } struct CHARRANGE { LONG cpMin; LONG cpMax; } struct COMPCOLOR { COLORREF crText; COLORREF crBackground; DWORD dwEffects; } extern (Windows) { alias DWORD function(DWORD,PBYTE,LONG,LONG*) EDITSTREAMCALLBACK; } struct EDITSTREAM { DWORD dwCookie; DWORD dwError; EDITSTREAMCALLBACK pfnCallback; } struct ENCORRECTTEXT { NMHDR nmhdr; CHARRANGE chrg; WORD seltyp; } struct ENDROPFILES { NMHDR nmhdr; HANDLE hDrop; LONG cp; BOOL fProtected; } struct ENLINK { NMHDR nmhdr; UINT msg; WPARAM wParam; LPARAM lParam; CHARRANGE chrg; } struct ENOLEOPFAILED { NMHDR nmhdr; LONG iob; LONG lOper; HRESULT hr; } struct ENPROTECTED { NMHDR nmhdr; UINT msg; WPARAM wParam; LPARAM lParam; CHARRANGE chrg; } alias ENPROTECTED* LPENPROTECTED; struct ENSAVECLIPBOARD { NMHDR nmhdr; LONG cObjectCount; LONG cch; } struct FINDTEXTA { CHARRANGE chrg; LPSTR lpstrText; } struct FINDTEXTW { CHARRANGE chrg; LPWSTR lpstrText; } struct FINDTEXTEXA { CHARRANGE chrg; LPSTR lpstrText; CHARRANGE chrgText; } struct FINDTEXTEXW { CHARRANGE chrg; LPWSTR lpstrText; CHARRANGE chrgText; } struct FORMATRANGE { HDC hdc; HDC hdcTarget; RECT rc; RECT rcPage; CHARRANGE chrg; } struct MSGFILTER { NMHDR nmhdr; UINT msg; WPARAM wParam; LPARAM lParam; } struct PARAFORMAT { UINT cbSize = this.sizeof; DWORD dwMask; WORD wNumbering; WORD wReserved; LONG dxStartIndent; LONG dxRightIndent; LONG dxOffset; WORD wAlignment; SHORT cTabCount; LONG[MAX_TAB_STOPS] rgxTabs; } struct PARAFORMAT2 { UINT cbSize = this.sizeof; DWORD dwMask; WORD wNumbering; WORD wEffects; LONG dxStartIndent; LONG dxRightIndent; LONG dxOffset; WORD wAlignment; SHORT cTabCount; LONG[MAX_TAB_STOPS] rgxTabs; LONG dySpaceBefore; LONG dySpaceAfter; LONG dyLineSpacing; SHORT sStype; BYTE bLineSpacingRule; BYTE bOutlineLevel; WORD wShadingWeight; WORD wShadingStyle; WORD wNumberingStart; WORD wNumberingStyle; WORD wNumberingTab; WORD wBorderSpace; WORD wBorderWidth; WORD wBorders; } struct SELCHANGE { NMHDR nmhdr; CHARRANGE chrg; WORD seltyp; } struct TEXTRANGEA { CHARRANGE chrg; LPSTR lpstrText; } struct TEXTRANGEW { CHARRANGE chrg; LPWSTR lpstrText; } struct REQRESIZE { NMHDR nmhdr; RECT rc; } struct REPASTESPECIAL { DWORD dwAspect; DWORD dwParam; } struct PUNCTUATION { UINT iSize; LPSTR szPunctuation; } struct GETTEXTEX { DWORD cb; DWORD flags; UINT codepage; LPCSTR lpDefaultChar; LPBOOL lpUsedDefChar; } extern (Windows) { alias LONG function(char*,LONG,BYTE,INT) EDITWORDBREAKPROCEX; } /* Defines for EM_SETTYPOGRAPHYOPTIONS */ enum TO_ADVANCEDTYPOGRAPHY = 1; enum TO_SIMPLELINEBREAK = 2; /* Defines for GETTEXTLENGTHEX */ enum GTL_DEFAULT = 0; enum GTL_USECRLF = 1; enum GTL_PRECISE = 2; enum GTL_CLOSE = 4; enum GTL_NUMCHARS = 8; enum GTL_NUMBYTES = 16; struct GETTEXTLENGTHEX { DWORD flags; UINT codepage; } version(Unicode) { alias CHARFORMATW CHARFORMAT; alias CHARFORMAT2W CHARFORMAT2; alias FINDTEXTW FINDTEXT; alias FINDTEXTEXW FINDTEXTEX; alias TEXTRANGEW TEXTRANGE; } else { alias CHARFORMATA CHARFORMAT; alias CHARFORMAT2A CHARFORMAT2; alias FINDTEXTA FINDTEXT; alias FINDTEXTEXA FINDTEXTEX; alias TEXTRANGEA TEXTRANGE; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/windows/wincrypt.d0000664000175000017500000006444612776214756023554 0ustar kaikai/** * Windows API header module * * Translated from MinGW Windows headers * * Authors: Stewart Gordon * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(DRUNTIMESRC src/core/sys/windows/_wincrypt.d) */ module core.sys.windows.wincrypt; version (Windows): pragma(lib, "advapi32"); version (ANSI) {} else version = Unicode; private import core.sys.windows.w32api, core.sys.windows.winbase, core.sys.windows.windef; /* FIXME: * Types of some constants * Types of macros * Inits of various "size" and "version" members * Why are some #ifdefs commented out? */ const TCHAR[] MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0", MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0", MS_STRONG_PROV = "Microsoft Strong Cryptographic Provider", MS_DEF_RSA_SIG_PROV = "Microsoft RSA Signature Cryptographic Provider", MS_DEF_RSA_SCHANNEL_PROV = "Microsoft RSA SChannel Cryptographic Provider", MS_DEF_DSS_PROV = "Microsoft Base DSS Cryptographic Provider", MS_DEF_DSS_DH_PROV = "Microsoft Base DSS and Diffie-Hellman Cryptographic Provider", MS_ENH_DSS_DH_PROV = "Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider", MS_DEF_DH_SCHANNEL_PROV = "Microsoft DH SChannel Cryptographic Provider", MS_SCARD_PROV = "Microsoft Base Smart Card Crypto Provider"; static if (_WIN32_WINNT > 0x501) { const TCHAR[] MS_ENH_RSA_AES_PROV = "Microsoft Enhanced RSA and AES Cryptographic Provider"; } else static if (_WIN32_WINNT == 0x501) { const TCHAR[] MS_ENH_RSA_AES_PROV = "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"; } ALG_ID GET_ALG_CLASS(ALG_ID x) { return x & 0xE000; } ALG_ID GET_ALG_TYPE (ALG_ID x) { return x & 0x1E00; } ALG_ID GET_ALG_SID (ALG_ID x) { return x & 0x01FF; } enum : ALG_ID { ALG_CLASS_ANY = 0, ALG_CLASS_SIGNATURE = 0x2000, ALG_CLASS_MSG_ENCRYPT = 0x4000, ALG_CLASS_DATA_ENCRYPT = 0x6000, ALG_CLASS_HASH = 0x8000, ALG_CLASS_KEY_EXCHANGE = 0xA000, ALG_CLASS_ALL = 0xE000 } enum : ALG_ID { ALG_TYPE_ANY = 0, ALG_TYPE_DSS = 0x0200, ALG_TYPE_RSA = 0x0400, ALG_TYPE_BLOCK = 0x0600, ALG_TYPE_STREAM = 0x0800, ALG_TYPE_DH = 0x0A00, ALG_TYPE_SECURECHANNEL = 0x0C00 } enum : ALG_ID { ALG_SID_ANY = 0, ALG_SID_RSA_ANY = 0, ALG_SID_RSA_PKCS, ALG_SID_RSA_MSATWORK, ALG_SID_RSA_ENTRUST, ALG_SID_RSA_PGP, // = 4 ALG_SID_DSS_ANY = 0, ALG_SID_DSS_PKCS, ALG_SID_DSS_DMS, // = 2 ALG_SID_DES = 1, ALG_SID_3DES = 3, ALG_SID_DESX, ALG_SID_IDEA, ALG_SID_CAST, ALG_SID_SAFERSK64, ALG_SID_SAFERSK128, ALG_SID_3DES_112, ALG_SID_SKIPJACK, ALG_SID_TEK, ALG_SID_CYLINK_MEK, ALG_SID_RC5, // = 13 ALG_SID_RC2 = 2, ALG_SID_RC4 = 1, ALG_SID_SEAL = 2, ALG_SID_MD2 = 1, ALG_SID_MD4, ALG_SID_MD5, ALG_SID_SHA, ALG_SID_MAC, ALG_SID_RIPEMD, ALG_SID_RIPEMD160, ALG_SID_SSL3SHAMD5, ALG_SID_HMAC, ALG_SID_TLS1PRF, // = 10 ALG_SID_AES_128 = 14, ALG_SID_AES_192, ALG_SID_AES_256, ALG_SID_AES, // = 17 ALG_SID_EXAMPLE = 80 } enum : ALG_ID { CALG_MD2 = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD2, CALG_MD4 = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD4, CALG_MD5 = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5, CALG_SHA = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA, CALG_SHA1 = CALG_SHA, CALG_MAC = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MAC, CALG_3DES = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 3, CALG_CYLINK_MEK = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 12, CALG_SKIPJACK = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 10, CALG_KEA_KEYX = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_STREAM | ALG_TYPE_DSS | 4, CALG_RSA_SIGN = ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY, CALG_DSS_SIGN = ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY, CALG_RSA_KEYX = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RSA | ALG_SID_RSA_ANY, CALG_DES = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_DES, CALG_RC2 = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_RC2, CALG_RC4 = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | ALG_SID_RC4, CALG_SEAL = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | ALG_SID_SEAL, CALG_DH_EPHEM = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_STREAM | ALG_TYPE_DSS | ALG_SID_DSS_DMS, CALG_DESX = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_DESX, // is undefined ALG_CLASS_DHASH in MinGW - presuming typo CALG_TLS1PRF = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_TLS1PRF, CALG_AES_128 = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_128, CALG_AES_192 = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_192, CALG_AES_256 = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256, CALG_AES = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES, } enum { CRYPT_VERIFYCONTEXT = 0xF0000000, } enum { CRYPT_NEWKEYSET = 8, CRYPT_DELETEKEYSET = 16, CRYPT_MACHINE_KEYSET = 32, CRYPT_SILENT = 64, } enum { CRYPT_EXPORTABLE = 1, CRYPT_USER_PROTECTED = 2, CRYPT_CREATE_SALT = 4, CRYPT_UPDATE_KEY = 8, } enum { SIMPLEBLOB = 1, PUBLICKEYBLOB = 6, PRIVATEKEYBLOB = 7, PLAINTEXTKEYBLOB = 8, OPAQUEKEYBLOB = 9, PUBLICKEYBLOBEX = 10, SYMMETRICWRAPKEYBLOB = 11, } enum { AT_KEYEXCHANGE = 1, AT_SIGNATURE = 2, } enum { CRYPT_USERDATA = 1, } enum { PKCS5_PADDING = 1, } enum { CRYPT_MODE_CBC = 1, CRYPT_MODE_ECB = 2, CRYPT_MODE_OFB = 3, CRYPT_MODE_CFB = 4, CRYPT_MODE_CTS = 5, CRYPT_MODE_CBCI = 6, CRYPT_MODE_CFBP = 7, CRYPT_MODE_OFBP = 8, CRYPT_MODE_CBCOFM = 9, CRYPT_MODE_CBCOFMI = 10, } enum { CRYPT_ENCRYPT = 1, CRYPT_DECRYPT = 2, CRYPT_EXPORT = 4, CRYPT_READ = 8, CRYPT_WRITE = 16, CRYPT_MAC = 32, } enum { HP_ALGID = 1, HP_HASHVAL = 2, HP_HASHSIZE = 4, HP_HMAC_INFO = 5, } enum { CRYPT_FAILED = FALSE, CRYPT_SUCCEED = TRUE, } bool RCRYPT_SUCCEEDED(BOOL r) { return r==CRYPT_SUCCEED; } bool RCRYPT_FAILED(BOOL r) { return r==CRYPT_FAILED; } enum { PP_ENUMALGS = 1, PP_ENUMCONTAINERS = 2, PP_IMPTYPE = 3, PP_NAME = 4, PP_VERSION = 5, PP_CONTAINER = 6, PP_CHANGE_PASSWORD = 7, PP_KEYSET_SEC_DESCR = 8, PP_CERTCHAIN = 9, PP_KEY_TYPE_SUBTYPE = 10, PP_PROVTYPE = 16, PP_KEYSTORAGE = 17, PP_APPLI_CERT = 18, PP_SYM_KEYSIZE = 19, PP_SESSION_KEYSIZE = 20, PP_UI_PROMPT = 21, PP_ENUMALGS_EX = 22, PP_ENUMMANDROOTS = 25, PP_ENUMELECTROOTS = 26, PP_KEYSET_TYPE = 27, PP_ADMIN_PIN = 31, PP_KEYEXCHANGE_PIN = 32, PP_SIGNATURE_PIN = 33, PP_SIG_KEYSIZE_INC = 34, PP_KEYX_KEYSIZE_INC = 35, PP_UNIQUE_CONTAINER = 36, PP_SGC_INFO = 37, PP_USE_HARDWARE_RNG = 38, PP_KEYSPEC = 39, PP_ENUMEX_SIGNING_PROT = 40, } enum { CRYPT_FIRST = 1, CRYPT_NEXT = 2, } enum { CRYPT_IMPL_HARDWARE = 1, CRYPT_IMPL_SOFTWARE = 2, CRYPT_IMPL_MIXED = 3, CRYPT_IMPL_UNKNOWN = 4, } enum { PROV_RSA_FULL = 1, PROV_RSA_SIG = 2, PROV_DSS = 3, PROV_FORTEZZA = 4, PROV_MS_MAIL = 5, PROV_SSL = 6, PROV_STT_MER = 7, PROV_STT_ACQ = 8, PROV_STT_BRND = 9, PROV_STT_ROOT = 10, PROV_STT_ISS = 11, PROV_RSA_SCHANNEL = 12, PROV_DSS_DH = 13, PROV_EC_ECDSA_SIG = 14, PROV_EC_ECNRA_SIG = 15, PROV_EC_ECDSA_FULL = 16, PROV_EC_ECNRA_FULL = 17, PROV_DH_SCHANNEL = 18, PROV_SPYRUS_LYNKS = 20, PROV_RNG = 21, PROV_INTEL_SEC = 22, PROV_RSA_AES = 24, MAXUIDLEN = 64, } enum { CUR_BLOB_VERSION = 2, } enum { X509_ASN_ENCODING = 1, PKCS_7_ASN_ENCODING = 65536, } enum { CERT_V1 = 0, CERT_V2 = 1, CERT_V3 = 2, } enum { CERT_E_CHAINING = (-2146762486), CERT_E_CN_NO_MATCH = (-2146762481), CERT_E_EXPIRED = (-2146762495), CERT_E_PURPOSE = (-2146762490), CERT_E_REVOCATION_FAILURE = (-2146762482), CERT_E_REVOKED = (-2146762484), CERT_E_ROLE = (-2146762493), CERT_E_UNTRUSTEDROOT = (-2146762487), CERT_E_UNTRUSTEDTESTROOT = (-2146762483), CERT_E_VALIDITYPERIODNESTING = (-2146762494), CERT_E_WRONG_USAGE = (-2146762480), CERT_E_PATHLENCONST = (-2146762492), CERT_E_CRITICAL = (-2146762491), CERT_E_ISSUERCHAINING = (-2146762489), CERT_E_MALFORMED = (-2146762488), CRYPT_E_REVOCATION_OFFLINE = (-2146885613), CRYPT_E_REVOKED = (-2146885616), TRUST_E_BASIC_CONSTRAINTS = (-2146869223), TRUST_E_CERT_SIGNATURE = (-2146869244), TRUST_E_FAIL = (-2146762485), } enum { CERT_TRUST_NO_ERROR = 0, CERT_TRUST_IS_NOT_TIME_VALID = 1, CERT_TRUST_IS_NOT_TIME_NESTED = 2, CERT_TRUST_IS_REVOKED = 4, CERT_TRUST_IS_NOT_SIGNATURE_VALID = 8, CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 16, CERT_TRUST_IS_UNTRUSTED_ROOT = 32, CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 64, CERT_TRUST_IS_CYCLIC = 128, CERT_TRUST_IS_PARTIAL_CHAIN = 65536, CERT_TRUST_CTL_IS_NOT_TIME_VALID = 131072, CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID = 262144, CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE = 524288, } enum { CERT_TRUST_HAS_EXACT_MATCH_ISSUER = 1, CERT_TRUST_HAS_KEY_MATCH_ISSUER = 2, CERT_TRUST_HAS_NAME_MATCH_ISSUER = 4, CERT_TRUST_IS_SELF_SIGNED = 8, CERT_TRUST_IS_COMPLEX_CHAIN = 65536, } enum { CERT_CHAIN_POLICY_BASE = cast(LPCSTR) 1, CERT_CHAIN_POLICY_AUTHENTICODE = cast(LPCSTR) 2, CERT_CHAIN_POLICY_AUTHENTICODE_TS = cast(LPCSTR) 3, CERT_CHAIN_POLICY_SSL = cast(LPCSTR) 4, CERT_CHAIN_POLICY_BASIC_CONSTRAINTS = cast(LPCSTR) 5, CERT_CHAIN_POLICY_NT_AUTH = cast(LPCSTR) 6, } enum { USAGE_MATCH_TYPE_AND = 0, USAGE_MATCH_TYPE_OR = 1, } enum { CERT_SIMPLE_NAME_STR = 1, CERT_OID_NAME_STR = 2, CERT_X500_NAME_STR = 3, } enum { CERT_NAME_STR_SEMICOLON_FLAG = 1073741824, CERT_NAME_STR_CRLF_FLAG = 134217728, CERT_NAME_STR_NO_PLUS_FLAG = 536870912, CERT_NAME_STR_NO_QUOTING_FLAG = 268435456, CERT_NAME_STR_REVERSE_FLAG = 33554432, CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG = 131072, } enum { CERT_FIND_ANY = 0, CERT_FIND_CERT_ID = 1048576, CERT_FIND_CTL_USAGE = 655360, CERT_FIND_ENHKEY_USAGE = 655360, CERT_FIND_EXISTING = 851968, CERT_FIND_HASH = 65536, CERT_FIND_ISSUER_ATTR = 196612, CERT_FIND_ISSUER_NAME = 131076, CERT_FIND_ISSUER_OF = 786432, CERT_FIND_KEY_IDENTIFIER = 983040, CERT_FIND_KEY_SPEC = 589824, CERT_FIND_MD5_HASH = 262144, CERT_FIND_PROPERTY = 327680, CERT_FIND_PUBLIC_KEY = 393216, CERT_FIND_SHA1_HASH = 65536, CERT_FIND_SIGNATURE_HASH = 917504, CERT_FIND_SUBJECT_ATTR = 196615, CERT_FIND_SUBJECT_CERT = 720896, CERT_FIND_SUBJECT_NAME = 131079, CERT_FIND_SUBJECT_STR_A = 458759, CERT_FIND_SUBJECT_STR_W = 524295, CERT_FIND_ISSUER_STR_A = 458756, CERT_FIND_ISSUER_STR_W = 524292, } enum { CERT_FIND_OR_ENHKEY_USAGE_FLAG = 16, CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG = 1, CERT_FIND_NO_ENHKEY_USAGE_FLAG = 8, CERT_FIND_VALID_ENHKEY_USAGE_FLAG = 32, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG = 2, } enum { CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG = 2, CERT_UNICODE_IS_RDN_ATTRS_FLAG = 1, CERT_CHAIN_FIND_BY_ISSUER = 1, } enum { CERT_CHAIN_FIND_BY_ISSUER_COMPARE_KEY_FLAG = 1, CERT_CHAIN_FIND_BY_ISSUER_COMPLEX_CHAIN_FLAG = 2, CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG = 4, CERT_CHAIN_FIND_BY_ISSUER_LOCAL_MACHINE_FLAG = 8, CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG = 16384, CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG = 32768, } enum { CERT_STORE_PROV_SYSTEM = 10, CERT_SYSTEM_STORE_LOCAL_MACHINE = 131072, } enum { szOID_PKIX_KP_SERVER_AUTH = "4235600", szOID_SERVER_GATED_CRYPTO = "4235658", szOID_SGC_NETSCAPE = "2.16.840.1.113730.4.1", szOID_PKIX_KP_CLIENT_AUTH = "1.3.6.1.5.5.7.3.2", } enum { CRYPT_NOHASHOID = 0x00000001, CRYPT_NO_SALT = 0x10, CRYPT_PREGEN = 0x40, } enum { CRYPT_RECIPIENT = 0x10, CRYPT_INITIATOR = 0x40, CRYPT_ONLINE = 0x80, CRYPT_SF = 0x100, CRYPT_CREATE_IV = 0x200, CRYPT_KEK = 0x400, CRYPT_DATA_KEY = 0x800, CRYPT_VOLATILE = 0x1000, CRYPT_SGCKEY = 0x2000, } enum { KP_IV = 0x00000001, KP_SALT = 0x00000002, KP_PADDING = 0x00000003, KP_MODE = 0x00000004, KP_MODE_BITS = 0x00000005, KP_PERMISSIONS = 0x00000006, KP_ALGID = 0x00000007, KP_BLOCKLEN = 0x00000008, KP_KEYLEN = 0x00000009, KP_SALT_EX = 0x0000000a, KP_P = 0x0000000b, KP_G = 0x0000000c, KP_Q = 0x0000000d, KP_X = 0x0000000e, KP_Y = 0x0000000f, KP_RA = 0x00000010, KP_RB = 0x00000011, KP_INFO = 0x00000012, KP_EFFECTIVE_KEYLEN = 0x00000013, KP_SCHANNEL_ALG = 0x00000014, KP_PUB_PARAMS = 0x00000027, } enum { CRYPT_FLAG_PCT1 = 0x0001, CRYPT_FLAG_SSL2 = 0x0002, CRYPT_FLAG_SSL3 = 0x0004, CRYPT_FLAG_TLS1 = 0x0008, CRYPT_FLAG_IPSEC = 0x0010, CRYPT_FLAG_SIGNING = 0x0020, } enum { SCHANNEL_MAC_KEY = 0x00000000, SCHANNEL_ENC_KEY = 0x00000001, } enum { INTERNATIONAL_USAGE = 0x00000001, } alias UINT ALG_ID; alias ULONG HCRYPTPROV, HCRYPTKEY, HCRYPTHASH; alias PVOID HCERTSTORE, HCRYPTMSG, HCERTCHAINENGINE; struct VTableProvStruc { FARPROC FuncVerifyImage; } alias VTableProvStruc* PVTableProvStruc; struct _CRYPTOAPI_BLOB { DWORD cbData; BYTE* pbData; } alias _CRYPTOAPI_BLOB CRYPT_INTEGER_BLOB, CRYPT_UINT_BLOB, CRYPT_OBJID_BLOB, CERT_NAME_BLOB, CERT_RDN_VALUE_BLOB, CERT_BLOB, CRL_BLOB, DATA_BLOB, CRYPT_DATA_BLOB, CRYPT_HASH_BLOB, CRYPT_DIGEST_BLOB, CRYPT_DER_BLOB, CRYPT_ATTR_BLOB; alias _CRYPTOAPI_BLOB* PCRYPT_INTEGER_BLOB, PCRYPT_UINT_BLOB, PCRYPT_OBJID_BLOB, PCERT_NAME_BLOB, PCERT_RDN_VALUE_BLOB, PCERT_BLOB, PCRL_BLOB, PDATA_BLOB, PCRYPT_DATA_BLOB, PCRYPT_HASH_BLOB, PCRYPT_DIGEST_BLOB, PCRYPT_DER_BLOB, PCRYPT_ATTR_BLOB; // not described in SDK; has the same layout as HTTPSPolicyCallbackData struct SSL_EXTRA_CERT_CHAIN_POLICY_PARA { DWORD cbStruct; DWORD dwAuthType; DWORD fdwChecks; LPWSTR pwszServerName; } alias SSL_EXTRA_CERT_CHAIN_POLICY_PARA HTTPSPolicyCallbackData; alias SSL_EXTRA_CERT_CHAIN_POLICY_PARA* PSSL_EXTRA_CERT_CHAIN_POLICY_PARA, PHTTPSPolicyCallbackData; /* #if (_WIN32_WINNT>=0x500) */ struct CERT_CHAIN_POLICY_PARA { DWORD cbSize = CERT_CHAIN_POLICY_PARA.sizeof; DWORD dwFlags; void* pvExtraPolicyPara; } alias CERT_CHAIN_POLICY_PARA* PCERT_CHAIN_POLICY_PARA; struct CERT_CHAIN_POLICY_STATUS { DWORD cbSize = CERT_CHAIN_POLICY_STATUS.sizeof; DWORD dwError; LONG lChainIndex; LONG lElementIndex; void* pvExtraPolicyStatus; } alias CERT_CHAIN_POLICY_STATUS* PCERT_CHAIN_POLICY_STATUS; /* #endif */ struct CRYPT_ALGORITHM_IDENTIFIER { LPSTR pszObjId; CRYPT_OBJID_BLOB Parameters; } alias CRYPT_ALGORITHM_IDENTIFIER* PCRYPT_ALGORITHM_IDENTIFIER; struct CRYPT_BIT_BLOB { DWORD cbData; BYTE* pbData; DWORD cUnusedBits; } alias CRYPT_BIT_BLOB* PCRYPT_BIT_BLOB; struct CERT_PUBLIC_KEY_INFO { CRYPT_ALGORITHM_IDENTIFIER Algorithm; CRYPT_BIT_BLOB PublicKey; } alias CERT_PUBLIC_KEY_INFO* PCERT_PUBLIC_KEY_INFO; struct CERT_EXTENSION { LPSTR pszObjId; BOOL fCritical; CRYPT_OBJID_BLOB Value; } alias CERT_EXTENSION* PCERT_EXTENSION; struct CERT_INFO { DWORD dwVersion; CRYPT_INTEGER_BLOB SerialNumber; CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; CERT_NAME_BLOB Issuer; FILETIME NotBefore; FILETIME NotAfter; CERT_NAME_BLOB Subject; CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo; CRYPT_BIT_BLOB IssuerUniqueId; CRYPT_BIT_BLOB SubjectUniqueId; DWORD cExtension; PCERT_EXTENSION rgExtension; } alias CERT_INFO* PCERT_INFO; struct CERT_CONTEXT { DWORD dwCertEncodingType; BYTE* pbCertEncoded; DWORD cbCertEncoded; PCERT_INFO pCertInfo; HCERTSTORE hCertStore; } alias CERT_CONTEXT* PCERT_CONTEXT; alias const(CERT_CONTEXT)* PCCERT_CONTEXT; struct CTL_USAGE { DWORD cUsageIdentifier; LPSTR* rgpszUsageIdentifier; } alias CTL_USAGE CERT_ENHKEY_USAGE; alias CTL_USAGE* PCTRL_USAGE, PCERT_ENHKEY_USAGE; struct CERT_USAGE_MATCH { DWORD dwType; CERT_ENHKEY_USAGE Usage; } alias CERT_USAGE_MATCH* PCERT_USAGE_MATCH; /* #if (_WIN32_WINNT>=0x500) */ struct CERT_CHAIN_PARA { DWORD cbSize = CERT_CHAIN_PARA.sizeof; CERT_USAGE_MATCH RequestedUsage; //#if CERT_CHAIN_PARA_HAS_EXTRA_FIELDS CERT_USAGE_MATCH RequestedIssuancePolicy; DWORD dwUrlRetrievalTimeout; BOOL fCheckRevocationFreshnessTime; DWORD dwRevocationFreshnessTime; //#endif } alias CERT_CHAIN_PARA* PCERT_CHAIN_PARA; extern (Windows) alias BOOL function(PCCERT_CONTEXT, void*) PFN_CERT_CHAIN_FIND_BY_ISSUER_CALLBACK; struct CERT_CHAIN_FIND_BY_ISSUER_PARA { DWORD cbSize = CERT_CHAIN_FIND_BY_ISSUER_PARA.sizeof; LPCSTR pszUsageIdentifier; DWORD dwKeySpec; DWORD dwAcquirePrivateKeyFlags; DWORD cIssuer; CERT_NAME_BLOB* rgIssuer; PFN_CERT_CHAIN_FIND_BY_ISSUER_CALLBACK pfnFIndCallback; void* pvFindArg; DWORD* pdwIssuerChainIndex; DWORD* pdwIssuerElementIndex; } alias CERT_CHAIN_FIND_BY_ISSUER_PARA* PCERT_CHAIN_FIND_BY_ISSUER_PARA; /* #endif */ struct CERT_TRUST_STATUS { DWORD dwErrorStatus; DWORD dwInfoStatus; } alias CERT_TRUST_STATUS* PCERT_TRUST_STATUS; struct CRL_ENTRY { CRYPT_INTEGER_BLOB SerialNumber; FILETIME RevocationDate; DWORD cExtension; PCERT_EXTENSION rgExtension; } alias CRL_ENTRY* PCRL_ENTRY; struct CRL_INFO { DWORD dwVersion; CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; CERT_NAME_BLOB Issuer; FILETIME ThisUpdate; FILETIME NextUpdate; DWORD cCRLEntry; PCRL_ENTRY rgCRLEntry; DWORD cExtension; PCERT_EXTENSION rgExtension; } alias CRL_INFO* PCRL_INFO; struct CRL_CONTEXT { DWORD dwCertEncodingType; BYTE* pbCrlEncoded; DWORD cbCrlEncoded; PCRL_INFO pCrlInfo; HCERTSTORE hCertStore; } alias CRL_CONTEXT* PCRL_CONTEXT; alias const(CRL_CONTEXT)* PCCRL_CONTEXT; struct CERT_REVOCATION_CRL_INFO { DWORD cbSize = CERT_REVOCATION_CRL_INFO.sizeof; PCCRL_CONTEXT pBaseCRLContext; PCCRL_CONTEXT pDeltaCRLContext; PCRL_ENTRY pCrlEntry; BOOL fDeltaCrlEntry; } alias CERT_REVOCATION_CRL_INFO* PCERT_REVOCATION_CRL_INFO; struct CERT_REVOCATION_INFO { DWORD cbSize = CERT_REVOCATION_INFO.sizeof; DWORD dwRevocationResult; LPCSTR pszRevocationOid; LPVOID pvOidSpecificInfo; BOOL fHasFreshnessTime; DWORD dwFreshnessTime; PCERT_REVOCATION_CRL_INFO pCrlInfo; } alias CERT_REVOCATION_INFO* PCERT_REVOCATION_INFO; /* #if (_WIN32_WINNT>=0x500) */ struct CERT_CHAIN_ELEMENT { DWORD cbSize = CERT_CHAIN_ELEMENT.sizeof; PCCERT_CONTEXT pCertContext; CERT_TRUST_STATUS TrustStatus; PCERT_REVOCATION_INFO pRevocationInfo; PCERT_ENHKEY_USAGE pIssuanceUsage; PCERT_ENHKEY_USAGE pApplicationUsage; } alias CERT_CHAIN_ELEMENT* PCERT_CHAIN_ELEMENT; /* #endif */ struct CRYPT_ATTRIBUTE { LPSTR pszObjId; DWORD cValue; PCRYPT_ATTR_BLOB rgValue; } alias CRYPT_ATTRIBUTE* PCRYPT_ATTRIBUTE; struct CTL_ENTRY { CRYPT_DATA_BLOB SubjectIdentifier; DWORD cAttribute; PCRYPT_ATTRIBUTE rgAttribute; } alias CTL_ENTRY* PCTL_ENTRY; struct CTL_INFO { DWORD dwVersion; CTL_USAGE SubjectUsage; CRYPT_DATA_BLOB ListIdentifier; CRYPT_INTEGER_BLOB SequenceNumber; FILETIME ThisUpdate; FILETIME NextUpdate; CRYPT_ALGORITHM_IDENTIFIER SubjectAlgorithm; DWORD cCTLEntry; PCTL_ENTRY rgCTLEntry; DWORD cExtension; PCERT_EXTENSION rgExtension; } alias CTL_INFO* PCTL_INFO; struct CTL_CONTEXT { DWORD dwMsgAndCertEncodingType; BYTE* pbCtlEncoded; DWORD cbCtlEncoded; PCTL_INFO pCtlInfo; HCERTSTORE hCertStore; HCRYPTMSG hCryptMsg; BYTE* pbCtlContent; DWORD cbCtlContent; } alias CTL_CONTEXT* PCTL_CONTEXT; alias const(CTL_CONTEXT)* PCCTL_CONTEXT; struct CERT_TRUST_LIST_INFO { DWORD cbSize = CERT_TRUST_LIST_INFO.sizeof; PCTL_ENTRY pCtlEntry; PCCTL_CONTEXT pCtlContext; } alias CERT_TRUST_LIST_INFO* PCERT_TRUST_LIST_INFO; struct CERT_SIMPLE_CHAIN { DWORD cbSize = CERT_SIMPLE_CHAIN.sizeof; CERT_TRUST_STATUS TrustStatus; DWORD cElement; PCERT_CHAIN_ELEMENT* rgpElement; PCERT_TRUST_LIST_INFO pTrustListInfo; BOOL fHasRevocationFreshnessTime; DWORD dwRevocationFreshnessTime; } alias CERT_SIMPLE_CHAIN* PCERT_SIMPLE_CHAIN; /* #if (_WIN32_WINNT>=0x500) */ alias const(CERT_CHAIN_CONTEXT)* PCCERT_CHAIN_CONTEXT; struct CERT_CHAIN_CONTEXT { DWORD cbSize = CERT_CHAIN_CONTEXT.sizeof; CERT_TRUST_STATUS TrustStatus; DWORD cChain; PCERT_SIMPLE_CHAIN* rgpChain; DWORD cLowerQualityChainContext; PCCERT_CHAIN_CONTEXT* rgpLowerQualityChainContext; BOOL fHasRevocationFreshnessTime; DWORD dwRevocationFreshnessTime; } alias CERT_CHAIN_CONTEXT* PCERT_CHAIN_CONTEXT; /* #endif */ struct PROV_ENUMALGS { ALG_ID aiAlgid; DWORD dwBitLen; DWORD dwNameLen; CHAR[20] szName; } struct PUBLICKEYSTRUC { BYTE bType; BYTE bVersion; WORD reserved; ALG_ID aiKeyAlg; } alias PUBLICKEYSTRUC BLOBHEADER; struct RSAPUBKEY { DWORD magic; DWORD bitlen; DWORD pubexp; } struct HMAC_INFO { ALG_ID HashAlgid; BYTE* pbInnerString; DWORD cbInnerString; BYTE* pbOuterString; DWORD cbOuterString; } alias HMAC_INFO* PHMAC_INFO; extern (Windows) { BOOL CertCloseStore(HCERTSTORE, DWORD); BOOL CertGetCertificateChain(HCERTCHAINENGINE, PCCERT_CONTEXT, LPFILETIME, HCERTSTORE, PCERT_CHAIN_PARA, DWORD, LPVOID, PCCERT_CHAIN_CONTEXT*); BOOL CertVerifyCertificateChainPolicy(LPCSTR, PCCERT_CHAIN_CONTEXT, PCERT_CHAIN_POLICY_PARA, PCERT_CHAIN_POLICY_STATUS); void CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT); DWORD CertNameToStrA(DWORD, PCERT_NAME_BLOB, DWORD, LPSTR, DWORD); DWORD CertNameToStrW(DWORD, PCERT_NAME_BLOB, DWORD, LPWSTR, DWORD); HCERTSTORE CertOpenSystemStoreA(HCRYPTPROV, LPCSTR); HCERTSTORE CertOpenSystemStoreW(HCRYPTPROV, LPCWSTR); HCERTSTORE CertOpenStore(LPCSTR, DWORD, HCRYPTPROV, DWORD, const(void)*); PCCERT_CONTEXT CertFindCertificateInStore(HCERTSTORE, DWORD, DWORD, DWORD, const(void)*, PCCERT_CONTEXT); BOOL CertFreeCertificateContext(PCCERT_CONTEXT); PCCERT_CONTEXT CertGetIssuerCertificateFromStore(HCERTSTORE, PCCERT_CONTEXT, PCCERT_CONTEXT, DWORD*); PCCERT_CHAIN_CONTEXT CertFindChainInStore(HCERTSTORE, DWORD, DWORD, DWORD, const(void)*, PCCERT_CHAIN_CONTEXT); BOOL CryptAcquireContextA(HCRYPTPROV*, LPCSTR, LPCSTR, DWORD, DWORD); BOOL CryptAcquireContextW(HCRYPTPROV*, LPCWSTR, LPCWSTR, DWORD, DWORD); BOOL CryptContextAddRef(HCRYPTPROV, DWORD*, DWORD); BOOL CryptReleaseContext(HCRYPTPROV, DWORD); BOOL CryptGenKey(HCRYPTPROV, ALG_ID, DWORD, HCRYPTKEY*); BOOL CryptDeriveKey(HCRYPTPROV, ALG_ID, HCRYPTHASH, DWORD, HCRYPTKEY*); BOOL CryptDestroyKey(HCRYPTKEY); static if (_WIN32_WINNT >= 0x500) { BOOL CryptDuplicateHash(HCRYPTHASH, DWORD*, DWORD, HCRYPTHASH*); BOOL CryptDuplicateKey(HCRYPTKEY, DWORD*, DWORD, HCRYPTKEY*); } BOOL CryptSetKeyParam(HCRYPTKEY, DWORD, PBYTE, DWORD); BOOL CryptGetKeyParam(HCRYPTKEY, DWORD, PBYTE, PDWORD, DWORD); BOOL CryptSetHashParam(HCRYPTHASH, DWORD, PBYTE, DWORD); BOOL CryptGetHashParam(HCRYPTHASH, DWORD, PBYTE, PDWORD, DWORD); BOOL CryptSetProvParam(HCRYPTPROV, DWORD, PBYTE, DWORD); BOOL CryptGetProvParam(HCRYPTPROV, DWORD, PBYTE, PDWORD, DWORD); BOOL CryptGenRandom(HCRYPTPROV, DWORD, PBYTE); BOOL CryptGetUserKey(HCRYPTPROV, DWORD, HCRYPTKEY*); BOOL CryptExportKey(HCRYPTKEY, HCRYPTKEY, DWORD, DWORD, PBYTE, PDWORD); BOOL CryptImportKey(HCRYPTPROV, PBYTE, DWORD, HCRYPTKEY, DWORD, HCRYPTKEY*); BOOL CryptEncrypt(HCRYPTKEY, HCRYPTHASH, BOOL, DWORD, PBYTE, PDWORD, DWORD); BOOL CryptDecrypt(HCRYPTKEY, HCRYPTHASH, BOOL, DWORD, PBYTE, PDWORD); BOOL CryptCreateHash(HCRYPTPROV, ALG_ID, HCRYPTKEY, DWORD, HCRYPTHASH*); BOOL CryptHashData(HCRYPTHASH, PBYTE, DWORD, DWORD); BOOL CryptHashSessionKey(HCRYPTHASH, HCRYPTKEY, DWORD); BOOL CryptGetHashValue(HCRYPTHASH, DWORD, PBYTE, PDWORD); BOOL CryptDestroyHash(HCRYPTHASH); BOOL CryptSignHashA(HCRYPTHASH, DWORD, LPCSTR, DWORD, PBYTE, PDWORD); BOOL CryptSignHashW(HCRYPTHASH, DWORD, LPCWSTR, DWORD, PBYTE, PDWORD); BOOL CryptVerifySignatureA(HCRYPTHASH, PBYTE, DWORD, HCRYPTKEY, LPCSTR, DWORD); BOOL CryptVerifySignatureW(HCRYPTHASH, PBYTE, DWORD, HCRYPTKEY, LPCWSTR, DWORD); BOOL CryptSetProviderA(LPCSTR, DWORD); BOOL CryptSetProviderW(LPCWSTR, DWORD); } version (Unicode) { alias CertNameToStrW CertNameToStr; alias CryptAcquireContextW CryptAcquireContext; alias CryptSignHashW CryptSignHash; alias CryptVerifySignatureW CryptVerifySignature; alias CryptSetProviderW CryptSetProvider; alias CertOpenSystemStoreW CertOpenSystemStore; /+alias CERT_FIND_SUBJECT_STR_W CERT_FIND_SUBJECT_STR; alias CERT_FIND_ISSUER_STR_W CERT_FIND_ISSUER_STR;+/ } else { alias CertNameToStrA CertNameToStr; alias CryptAcquireContextA CryptAcquireContext; alias CryptSignHashA CryptSignHash; alias CryptVerifySignatureA CryptVerifySignature; alias CryptSetProviderA CryptSetProvider; alias CertOpenSystemStoreA CertOpenSystemStore; /+alias CERT_FIND_SUBJECT_STR_A CERT_FIND_SUBJECT_STR; alias CERT_FIND_ISSUER_STR_A CERT_FIND_ISSUER_STR;+/ } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/0000775000175000017500000000000012776214756021432 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/dlfcn.d0000664000175000017500000000732212776214756022671 0ustar kaikai/** * D header file for FreeBSD. * * Copyright: Copyright Martin Nowak 2012. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak */ module core.sys.freebsd.dlfcn; public import core.sys.posix.dlfcn; version (FreeBSD): extern (C): nothrow: enum __BSD_VISIBLE = true; /* * Modes and flags for dlopen(). */ static assert(RTLD_LAZY == 1); static assert(RTLD_NOW == 2); enum RTLD_MODEMASK = 0x3; static assert(RTLD_GLOBAL == 0x100); static assert(RTLD_LOCAL == 0); enum RTLD_TRACE = 0x200; enum RTLD_NODELETE = 0x01000; enum RTLD_NOLOAD = 0x02000; /* * Request arguments for dlinfo(). */ enum RTLD_DI_LINKMAP = 2; /* Obtain link map. */ enum RTLD_DI_SERINFO = 4; /* Obtain search path info. */ enum RTLD_DI_SERINFOSIZE = 5; /* ... query for required space. */ enum RTLD_DI_ORIGIN = 6; /* Obtain object origin */ enum RTLD_DI_MAX = RTLD_DI_ORIGIN; /* * Special handle arguments for dlsym()/dlinfo(). */ enum RTLD_NEXT = cast(void *)-1; /* Search subsequent objects. */ enum RTLD_DEFAULT = cast(void *)-2; /* Use default search algorithm. */ enum RTLD_SELF = cast(void *)-3; /* Search the caller itself. */ static if (__BSD_VISIBLE) { /* * Structure filled in by dladdr(). */ struct Dl_info { const(char) *dli_fname; /* Pathname of shared object. */ void *dli_fbase; /* Base address of shared object. */ const(char) *dli_sname; /* Name of nearest symbol. */ void *dli_saddr; /* Address of nearest symbol. */ }; /*- * The actual type declared by this typedef is immaterial, provided that * it is a function pointer. Its purpose is to provide a return type for * dlfunc() which can be cast to a function pointer type without depending * on behavior undefined by the C standard, which might trigger a compiler * diagnostic. We intentionally declare a unique type signature to force * a diagnostic should the application not cast the return value of dlfunc() * appropriately. */ struct __dlfunc_arg { int __dlfunc_dummy; }; alias void function(__dlfunc_arg) dlfunc_t; /* * Structures, returned by the RTLD_DI_SERINFO dlinfo() request. */ struct Dl_serpath { char * dls_name; /* single search path entry */ uint dls_flags; /* path information */ }; struct Dl_serinfo { size_t dls_size; /* total buffer size */ uint dls_cnt; /* number of path entries */ Dl_serpath[1] dls_serpath; /* there may be more than one */ }; } private template __externC(RT, P...) { alias extern(C) RT function(P) nothrow @nogc __externC; } /* XSI functions first. */ static assert(is(typeof(&dlclose) == __externC!(int, void*))); static assert(is(typeof(&dlerror) == __externC!(char*))); static assert(is(typeof(&dlopen) == __externC!(void*, const char*, int))); static assert(is(typeof(&dlsym) == __externC!(void*, void*, const char*))); static if (__BSD_VISIBLE) { void* fdlopen(int, int); int dladdr(const(void)*, Dl_info*); dlfunc_t dlfunc(void*, const(char)*); int dlinfo(void*, int, void*); void dllockinit(void* _context, void* function(void* _context) _lock_create, void function(void* _lock) _rlock_acquire, void function(void* _lock) _wlock_acquire, void function(void* _lock) _lock_release, void function(void* _lock) _lock_destroy, void function(void* _context) _context_destroy); void* dlvsym(void*, const(char)*, const(char)*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/execinfo.d0000664000175000017500000000710312776214756023400 0ustar kaikai/** * FreeBSD implementation of glibc's $(LINK2 http://www.gnu.org/software/libc/manual/html_node/Backtraces.html backtrace) facility. * * Copyright: Copyright Martin Nowak 2012. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak * Source: $(DRUNTIMESRC core/sys/freebsd/_execinfo.d) */ module core.sys.freebsd.execinfo; version (FreeBSD): extern (C): nothrow: import core.sys.freebsd.dlfcn; // Use extern (D) so that these functions don't collide with libexecinfo. extern (D) int backtrace(void** buffer, int size) { import core.thread : thread_stackBottom; void** p, pend=cast(void**)thread_stackBottom(); version (D_InlineAsm_X86) asm nothrow @trusted { mov p[EBP], EBP; } else version (D_InlineAsm_X86_64) asm nothrow @trusted { mov p[RBP], RBP; } else static assert(false, "Architecture not supported."); int i; for (; i < size && p < pend; ++i) { buffer[i] = *(p + 1); auto pnext = cast(void**)*p; if (pnext <= p) break; p = pnext; } return i; } extern (D) char** backtrace_symbols(const(void*)* buffer, int size) { static void* realloc(void* p, size_t len) nothrow { static import cstdlib=core.stdc.stdlib; auto res = cstdlib.realloc(p, len); if (res is null) cstdlib.free(p); return res; } if (size <= 0) return null; size_t pos = size * (char*).sizeof; char** p = cast(char**)realloc(null, pos); if (p is null) return null; Dl_info info; foreach (i, addr; buffer[0 .. size]) { if (dladdr(addr, &info) == 0) (cast(ubyte*)&info)[0 .. info.sizeof] = 0; fixupDLInfo(addr, info); immutable len = formatStackFrame(null, 0, addr, info); assert(len > 0); p = cast(char**)realloc(p, pos + len); if (p is null) return null; formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0); p[i] = cast(char*)pos; pos += len; } foreach (i; 0 .. size) { pos = cast(size_t)p[i]; p[i] = cast(char*)p + pos; } return p; } extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd) { import core.sys.posix.unistd : write; import core.stdc.stdlib : alloca; if (size <= 0) return; Dl_info info; foreach (i, addr; buffer[0 .. size]) { if (dladdr(addr, &info) == 0) (cast(ubyte*)&info)[0 .. info.sizeof] = 0; fixupDLInfo(addr, info); enum maxAlloca = 1024; enum min = (size_t a, size_t b) => a <= b ? a : b; immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca); assert(len > 0); auto p = cast(char*)alloca(len); if (p is null) return; formatStackFrame(p, len, addr, info) >= len || assert(0); p[len - 1] = '\n'; write(fd, p, len); } } private void fixupDLInfo(const(void)* addr, ref Dl_info info) { if (info.dli_fname is null) info.dli_fname = "???"; if (info.dli_fbase is null) info.dli_fbase = null; if (info.dli_sname is null) info.dli_sname = "???"; if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr; } private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info) { import core.stdc.stdio : snprintf; immutable off = addr - info.dli_saddr; immutable len = snprintf(p, plen, "%p <%s+%zd> at %s", addr, info.dli_sname, off, info.dli_fname); assert(len > 0); return cast(size_t)len + 1; // + '\0' } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/time.d0000664000175000017500000000124412776214756022536 0ustar kaikai//Written in the D programming language /++ D header file for FreeBSD's extensions to POSIX's time.h. Copyright: Copyright 2014 License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jonathan M Davis +/ module core.sys.freebsd.time; public import core.sys.posix.time; version(FreeBSD): enum CLOCK_VIRTUAL = 1; enum CLOCK_PROF = 2; enum CLOCK_UPTIME = 5; enum CLOCK_UPTIME_PRECISE = 7; enum CLOCK_UPTIME_FAST = 8; enum CLOCK_REALTIME_PRECISE = 9; enum CLOCK_REALTIME_FAST = 10; enum CLOCK_MONOTONIC_PRECISE = 11; enum CLOCK_MONOTONIC_FAST = 12; enum CLOCK_SECOND = 13; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/sys/0000775000175000017500000000000012776214756022250 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/sys/elf.d0000664000175000017500000000041012776214756023156 0ustar kaikai/** * D header file for FreeBSD. * * $(LINK2 http://svnweb.freebsd.org/base/head/sys/sys/elf.h?view=markup, sys/elf.h) */ module core.sys.freebsd.sys.elf; version (FreeBSD): public import core.sys.freebsd.sys.elf32; public import core.sys.freebsd.sys.elf64; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/sys/link_elf.d0000664000175000017500000000345012776214756024202 0ustar kaikai/** * D header file for FreeBSD. * * $(LINK2 http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?view=markup, sys/link_elf.h) */ module core.sys.freebsd.sys.link_elf; version (FreeBSD): extern (C): nothrow: import core.stdc.stdint : uint64_t; import core.sys.freebsd.sys.elf; version(D_LP64) enum __ELF_NATIVE_CLASS = 64; else enum __ELF_NATIVE_CLASS = 32; template ElfW(string type) { mixin("alias Elf"~__ELF_NATIVE_CLASS.stringof~"_"~type~" ElfW;"); } enum LA_SER_ORIG = 0x01; enum LA_SER_LIBPATH = 0x02; enum LA_SER_RUNPATH = 0x04; enum LA_SER_CONFIG = 0x08; enum LA_SER_DEFAULT = 0x40; enum LA_SER_SECURE = 0x80; struct link_map { char* l_addr; version (MIPS32) char* l_offs; version (MIPS64) char* l_offs; char* l_name; void* l_ld; link_map* l_next, l_prev; } alias link_map Link_map; enum { RT_CONSISTENT, RT_ADD, RT_DELETE, } struct r_debug { int r_version; link_map* r_map; void function(r_debug*, link_map*) r_brk; }; struct dl_phdr_info { ElfW!"Addr" dlpi_addr; char* dlpi_name; ElfW!"Phdr"* dlpi_phdr; ElfW!"Half" dlpi_phnum; uint64_t dlpi_adds; uint64_t dlpi_subs; size_t dlpi_tls_modid; void* dlpi_tls_data; }; private alias extern(C) int function(dl_phdr_info*, size_t, void *) dl_iterate_phdr_cb; private alias extern(C) int function(dl_phdr_info*, size_t, void *) @nogc dl_iterate_phdr_cb_ngc; extern int dl_iterate_phdr(dl_iterate_phdr_cb __callback, void*__data); extern int dl_iterate_phdr(dl_iterate_phdr_cb_ngc __callback, void*__data) @nogc; extern int _rtld_addr_phdr(const void*, dl_phdr_info*) @nogc; extern int _rtld_get_stack_prot() @nogc; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/sys/elf_common.d0000664000175000017500000006374012776214756024545 0ustar kaikai/** * D header file for FreeBSD. * * $(LINK2 http://svnweb.freebsd.org/base/head/sys/sys/elf_common.h?view=markup, sys/elf_common.h) */ module core.sys.freebsd.sys.elf_common; version (FreeBSD): extern (C): pure: nothrow: import core.stdc.stdint; struct Elf_Note { uint32_t n_namesz; uint32_t n_descsz; uint32_t n_type; } struct Elf_GNU_Hash_Header { uint32_t gh_nbuckets; uint32_t gh_symndx; uint32_t gh_maskwords; uint32_t gh_shift2; } enum EI_MAG0 = 0; enum EI_MAG1 = 1; enum EI_MAG2 = 2; enum EI_MAG3 = 3; enum EI_CLASS = 4; enum EI_DATA = 5; enum EI_VERSION = 6; enum EI_OSABI = 7; enum EI_ABIVERSION = 8; enum OLD_EI_BRAND = 8; enum EI_PAD = 9; enum EI_NIDENT = 16; enum ELFMAG0 = 0x7f; enum ELFMAG1 = 'E'; enum ELFMAG2 = 'L'; enum ELFMAG3 = 'F'; enum ELFMAG = "\177ELF"; enum SELFMAG = 4; enum EV_NONE = 0; enum EV_CURRENT = 1; enum ELFCLASSNONE = 0; enum ELFCLASS32 = 1; enum ELFCLASS64 = 2; enum ELFDATANONE = 0; enum ELFDATA2LSB = 1; enum ELFDATA2MSB = 2; enum ELFOSABI_NONE = 0; enum ELFOSABI_SYSV = 0; enum ELFOSABI_HPUX = 1; enum ELFOSABI_NETBSD = 2; enum ELFOSABI_LINUX = 3; enum ELFOSABI_HURD = 4; enum ELFOSABI_86OPEN = 5; enum ELFOSABI_SOLARIS = 6; enum ELFOSABI_AIX = 7; enum ELFOSABI_MONTEREY = 7; enum ELFOSABI_IRIX = 8; enum ELFOSABI_FREEBSD = 9; enum ELFOSABI_TRU64 = 10; enum ELFOSABI_MODESTO = 11; enum ELFOSABI_OPENBSD = 12; enum ELFOSABI_OPENVMS = 13; enum ELFOSABI_NSK = 14; enum ELFOSABI_AROS = 15; enum ELFOSABI_ARM = 97; enum ELFOSABI_STANDALONE = 255; extern (D) { auto IS_ELF(T)(T ehdr) { return ehdr.e_ident[EI_MAG0] == ELFMAG0 && ehdr.e_ident[EI_MAG1] == ELFMAG1 && ehdr.e_ident[EI_MAG2] == ELFMAG2 && ehdr.e_ident[EI_MAG3] == ELFMAG3; } } enum ET_NONE = 0; enum ET_REL = 1; enum ET_EXEC = 2; enum ET_DYN = 3; enum ET_CORE = 4; enum ET_LOOS = 0xfe00; enum ET_HIOS = 0xfeff; enum ET_LOPROC = 0xff00; enum ET_HIPROC = 0xffff; enum EM_NONE = 0; enum EM_M32 = 1; enum EM_SPARC = 2; enum EM_386 = 3; enum EM_68K = 4; enum EM_88K = 5; enum EM_860 = 7; enum EM_MIPS = 8; enum EM_S370 = 9; enum EM_MIPS_RS3_LE = 10; enum EM_PARISC = 15; enum EM_VPP500 = 17; enum EM_SPARC32PLUS = 18; enum EM_960 = 19; enum EM_PPC = 20; enum EM_PPC64 = 21; enum EM_S390 = 22; enum EM_V800 = 36; enum EM_FR20 = 37; enum EM_RH32 = 38; enum EM_RCE = 39; enum EM_ARM = 40; enum EM_SH = 42; enum EM_SPARCV9 = 43; enum EM_TRICORE = 44; enum EM_ARC = 45; enum EM_H8_300 = 46; enum EM_H8_300H = 47; enum EM_H8S = 48; enum EM_H8_500 = 49; enum EM_IA_64 = 50; enum EM_MIPS_X = 51; enum EM_COLDFIRE = 52; enum EM_68HC12 = 53; enum EM_MMA = 54; enum EM_PCP = 55; enum EM_NCPU = 56; enum EM_NDR1 = 57; enum EM_STARCORE = 58; enum EM_ME16 = 59; enum EM_ST100 = 60; enum EM_TINYJ = 61; enum EM_X86_64 = 62; enum EM_AMD64 = 62; enum EM_PDSP = 63; enum EM_FX66 = 66; enum EM_ST9PLUS = 67; enum EM_ST7 = 68; enum EM_68HC16 = 69; enum EM_68HC11 = 70; enum EM_68HC08 = 71; enum EM_68HC05 = 72; enum EM_SVX = 73; enum EM_ST19 = 74; enum EM_VAX = 75; enum EM_CRIS = 76; enum EM_JAVELIN = 77; enum EM_FIREPATH = 78; enum EM_ZSP = 79; enum EM_MMIX = 80; enum EM_HUANY = 81; enum EM_PRISM = 82; enum EM_AVR = 83; enum EM_FR30 = 84; enum EM_D10V = 85; enum EM_D30V = 86; enum EM_V850 = 87; enum EM_M32R = 88; enum EM_MN10300 = 89; enum EM_MN10200 = 90; enum EM_PJ = 91; enum EM_OPENRISC = 92; enum EM_ARC_A5 = 93; enum EM_XTENSA = 94; enum EM_VIDEOCORE = 95; enum EM_TMM_GPP = 96; enum EM_NS32K = 97; enum EM_TPC = 98; enum EM_SNP1K = 99; enum EM_ST200 = 100; enum EM_IP2K = 101; enum EM_MAX = 102; enum EM_CR = 103; enum EM_F2MC16 = 104; enum EM_MSP430 = 105; enum EM_BLACKFIN = 106; enum EM_SE_C33 = 107; enum EM_SEP = 108; enum EM_ARCA = 109; enum EM_UNICORE = 110; enum EM_486 = 6; enum EM_MIPS_RS4_BE = 10; enum EM_ALPHA_STD = 41; enum EM_ALPHA = 0x9026; enum SHN_UNDEF = 0; enum SHN_LORESERVE = 0xff00; enum SHN_LOPROC = 0xff00; enum SHN_HIPROC = 0xff1f; enum SHN_LOOS = 0xff20; enum SHN_HIOS = 0xff3f; enum SHN_ABS = 0xfff1; enum SHN_COMMON = 0xfff2; enum SHN_XINDEX = 0xffff; enum SHN_HIRESERVE = 0xffff; enum SHT_NULL = 0; enum SHT_PROGBITS = 1; enum SHT_SYMTAB = 2; enum SHT_STRTAB = 3; enum SHT_RELA = 4; enum SHT_HASH = 5; enum SHT_DYNAMIC = 6; enum SHT_NOTE = 7; enum SHT_NOBITS = 8; enum SHT_REL = 9; enum SHT_SHLIB = 10; enum SHT_DYNSYM = 11; enum SHT_INIT_ARRAY = 14; enum SHT_FINI_ARRAY = 15; enum SHT_PREINIT_ARRAY = 16; enum SHT_GROUP = 17; enum SHT_SYMTAB_SHNDX = 18; enum SHT_LOOS = 0x60000000; enum SHT_LOSUNW = 0x6ffffff4; enum SHT_SUNW_dof = 0x6ffffff4; enum SHT_SUNW_cap = 0x6ffffff5; enum SHT_SUNW_SIGNATURE = 0x6ffffff6; enum SHT_GNU_HASH = 0x6ffffff6; enum SHT_SUNW_ANNOTATE = 0x6ffffff7; enum SHT_SUNW_DEBUGSTR = 0x6ffffff8; enum SHT_SUNW_DEBUG = 0x6ffffff9; enum SHT_SUNW_move = 0x6ffffffa; enum SHT_SUNW_COMDAT = 0x6ffffffb; enum SHT_SUNW_syminfo = 0x6ffffffc; enum SHT_SUNW_verdef = 0x6ffffffd; enum SHT_GNU_verdef = 0x6ffffffd; enum SHT_SUNW_verneed = 0x6ffffffe; enum SHT_GNU_verneed = 0x6ffffffe; enum SHT_SUNW_versym = 0x6fffffff; enum SHT_GNU_versym = 0x6fffffff; enum SHT_HISUNW = 0x6fffffff; enum SHT_HIOS = 0x6fffffff; enum SHT_LOPROC = 0x70000000; enum SHT_AMD64_UNWIND = 0x70000001; enum SHT_ARM_EXIDX = 0x70000001; enum SHT_ARM_PREEMPTMAP = 0x70000002; enum SHT_ARM_ATTRIBUTES = 0x70000003; enum SHT_ARM_DEBUGOVERLAY = 0x70000004; enum SHT_ARM_OVERLAYSECTION = 0x70000005; enum SHT_MIPS_REGINFO = 0x70000006; enum SHT_MIPS_OPTIONS = 0x7000000d; enum SHT_MIPS_DWARF = 0x7000001e; enum SHT_HIPROC = 0x7fffffff; enum SHT_LOUSER = 0x80000000; enum SHT_HIUSER = 0x8fffffff; enum SHF_WRITE = (1 << 0); enum SHF_ALLOC = (1 << 1); enum SHF_EXECINSTR = (1 << 2); enum SHF_MERGE = (1 << 4); enum SHF_STRINGS = (1 << 5); enum SHF_INFO_LINK = (1 << 6); enum SHF_LINK_ORDER = (1 << 7); enum SHF_OS_NONCONFORMING = (1 << 8); enum SHF_GROUP = (1 << 9); enum SHF_TLS = (1 << 10); enum SHF_MASKOS = 0x0ff00000; enum SHF_MASKPROC = 0xf0000000; enum PT_NULL = 0; enum PT_LOAD = 1; enum PT_DYNAMIC = 2; enum PT_INTERP = 3; enum PT_NOTE = 4; enum PT_SHLIB = 5; enum PT_PHDR = 6; enum PT_TLS = 7; enum PT_LOOS = 0x60000000; enum PT_SUNW_UNWIND = 0x6464e550; enum PT_GNU_EH_FRAME = 0x6474e550; enum PT_GNU_STACK = 0x6474e551; enum PT_GNU_RELRO = 0x6474e552; enum PT_LOSUNW = 0x6ffffffa; enum PT_SUNWBSS = 0x6ffffffa; enum PT_SUNWSTACK = 0x6ffffffb; enum PT_SUNWDTRACE = 0x6ffffffc; enum PT_SUNWCAP = 0x6ffffffd; enum PT_HISUNW = 0x6fffffff; enum PT_HIOS = 0x6fffffff; enum PT_LOPROC = 0x70000000; enum PT_HIPROC = 0x7fffffff; enum PF_X = (1 << 0); enum PF_W = (1 << 1); enum PF_R = (1 << 2); enum PF_MASKOS = 0x0ff00000; enum PF_MASKPROC = 0xf0000000; enum PN_XNUM = 0xffff; enum DT_NULL = 0; enum DT_NEEDED = 1; enum DT_PLTRELSZ = 2; enum DT_PLTGOT = 3; enum DT_HASH = 4; enum DT_STRTAB = 5; enum DT_SYMTAB = 6; enum DT_RELA = 7; enum DT_RELASZ = 8; enum DT_RELAENT = 9; enum DT_STRSZ = 10; enum DT_SYMENT = 11; enum DT_INIT = 12; enum DT_FINI = 13; enum DT_SONAME = 14; enum DT_RPATH = 15; enum DT_SYMBOLIC = 16; enum DT_REL = 17; enum DT_RELSZ = 18; enum DT_RELENT = 19; enum DT_PLTREL = 20; enum DT_DEBUG = 21; enum DT_TEXTREL = 22; enum DT_JMPREL = 23; enum DT_BIND_NOW = 24; enum DT_INIT_ARRAY = 25; enum DT_FINI_ARRAY = 26; enum DT_INIT_ARRAYSZ = 27; enum DT_FINI_ARRAYSZ = 28; enum DT_RUNPATH = 29; enum DT_FLAGS = 30; enum DT_ENCODING = 32; enum DT_PREINIT_ARRAY = 32; enum DT_PREINIT_ARRAYSZ = 33; enum DT_MAXPOSTAGS = 34; enum DT_LOOS = 0x6000000d; enum DT_SUNW_AUXILIARY = 0x6000000d; enum DT_SUNW_RTLDINF = 0x6000000e; enum DT_SUNW_FILTER = 0x6000000f; enum DT_SUNW_CAP = 0x60000010; enum DT_HIOS = 0x6ffff000; enum DT_VALRNGLO = 0x6ffffd00; enum DT_CHECKSUM = 0x6ffffdf8; enum DT_PLTPADSZ = 0x6ffffdf9; enum DT_MOVEENT = 0x6ffffdfa; enum DT_MOVESZ = 0x6ffffdfb; enum DT_FEATURE_1 = 0x6ffffdfc; enum DT_POSFLAG_1 = 0x6ffffdfd; enum DT_SYMINSZ = 0x6ffffdfe; enum DT_SYMINENT = 0x6ffffdff; enum DT_VALRNGHI = 0x6ffffdff; enum DT_ADDRRNGLO = 0x6ffffe00; enum DT_GNU_HASH = 0x6ffffef5; enum DT_CONFIG = 0x6ffffefa; enum DT_DEPAUDIT = 0x6ffffefb; enum DT_AUDIT = 0x6ffffefc; enum DT_PLTPAD = 0x6ffffefd; enum DT_MOVETAB = 0x6ffffefe; enum DT_SYMINFO = 0x6ffffeff; enum DT_ADDRRNGHI = 0x6ffffeff; enum DT_VERSYM = 0x6ffffff0; enum DT_RELACOUNT = 0x6ffffff9; enum DT_RELCOUNT = 0x6ffffffa; enum DT_FLAGS_1 = 0x6ffffffb; enum DT_VERDEF = 0x6ffffffc; enum DT_VERDEFNUM = 0x6ffffffd; enum DT_VERNEED = 0x6ffffffe; enum DT_VERNEEDNUM = 0x6fffffff; enum DT_LOPROC = 0x70000000; enum DT_DEPRECATED_SPARC_REGISTER = 0x7000001; enum DT_AUXILIARY = 0x7ffffffd; enum DT_USED = 0x7ffffffe; enum DT_FILTER = 0x7fffffff; enum DT_HIPROC = 0x7fffffff; enum DF_ORIGIN = 0x00000001; enum DF_SYMBOLIC = 0x00000002; enum DF_TEXTREL = 0x00000004; enum DF_BIND_NOW = 0x00000008; enum DF_STATIC_TLS = 0x00000010; enum DF_1_BIND_NOW = 0x00000001; enum DF_1_GLOBAL = 0x00000002; enum DF_1_NODELETE = 0x00000008; enum DF_1_LOADFLTR = 0x00000010; enum DF_1_NOOPEN = 0x00000040; enum DF_1_NODEFLIB = 0x00000800; enum NT_PRSTATUS = 1; enum NT_FPREGSET = 2; enum NT_PRPSINFO = 3; enum NT_THRMISC = 7; enum NT_PROCSTAT_PROC = 8; enum NT_PROCSTAT_FILES = 9; enum NT_PROCSTAT_VMMAP = 10; enum NT_PROCSTAT_GROUPS = 11; enum NT_PROCSTAT_UMASK = 12; enum NT_PROCSTAT_RLIMIT = 13; enum NT_PROCSTAT_OSREL = 14; enum NT_PROCSTAT_PSSTRINGS = 15; enum NT_PROCSTAT_AUXV = 16; enum STB_LOCAL = 0; enum STB_GLOBAL = 1; enum STB_WEAK = 2; enum STB_NUM = 3; enum STB_LOOS = 10; enum STB_HIOS = 12; enum STB_LOPROC = 13; enum STB_HIPROC = 15; enum STT_NOTYPE = 0; enum STT_OBJECT = 1; enum STT_FUNC = 2; enum STT_SECTION = 3; enum STT_FILE = 4; enum STT_COMMON = 5; enum STT_TLS = 6; enum STT_NUM = 7; enum STT_LOOS = 10; enum STT_GNU_IFUNC = 10; enum STT_HIOS = 12; enum STT_LOPROC = 13; enum STT_HIPROC = 15; enum STV_DEFAULT = 0; enum STV_INTERNAL = 1; enum STV_HIDDEN = 2; enum STV_PROTECTED = 3; enum STV_EXPORTED = 4; enum STV_SINGLETON = 5; enum STV_ELIMINATE = 6; enum STN_UNDEF = 0; enum VER_DEF_CURRENT = 1; alias VER_NDX VER_DEF_IDX; enum VER_FLG_BASE = 0x1; enum VER_FLG_WEAK = 0x2; enum VER_NEED_CURRENT = 1; enum VER_NEED_WEAK = 32768; enum VER_NEED_HIDDEN = VER_NDX_HIDDEN; alias VER_NDX VER_NEED_IDX; enum VER_NDX_LOCAL = 0; enum VER_NDX_GLOBAL = 1; enum VER_NDX_GIVEN = 2; enum VER_NDX_HIDDEN = 32768; extern (D) { auto VER_NDX(V)(V v) { return v & ~(1u << 15); } } enum CA_SUNW_NULL = 0; enum CA_SUNW_HW_1 = 1; enum CA_SUNW_SF_1 = 2; enum SYMINFO_FLG_DIRECT = 0x0001; enum SYMINFO_FLG_PASSTHRU = 0x0002; enum SYMINFO_FLG_COPY = 0x0004; enum SYMINFO_FLG_LAZYLOAD = 0x0008; enum SYMINFO_FLG_DIRECTBIND = 0x0010; enum SYMINFO_FLG_NOEXTDIRECT = 0x0020; enum SYMINFO_FLG_FILTER = 0x0002; enum SYMINFO_FLG_AUXILIARY = 0x0040; enum SYMINFO_BT_SELF = 0xffff; enum SYMINFO_BT_PARENT = 0xfffe; enum SYMINFO_BT_NONE = 0xfffd; enum SYMINFO_BT_EXTERN = 0xfffc; enum SYMINFO_BT_LOWRESERVE = 0xff00; enum SYMINFO_NONE = 0; enum SYMINFO_CURRENT = 1; enum SYMINFO_NUM = 2; enum R_386_NONE = 0; enum R_386_32 = 1; enum R_386_PC32 = 2; enum R_386_GOT32 = 3; enum R_386_PLT32 = 4; enum R_386_COPY = 5; enum R_386_GLOB_DAT = 6; enum R_386_JMP_SLOT = 7; enum R_386_RELATIVE = 8; enum R_386_GOTOFF = 9; enum R_386_GOTPC = 10; enum R_386_TLS_TPOFF = 14; enum R_386_TLS_IE = 15; enum R_386_TLS_GOTIE = 16; enum R_386_TLS_LE = 17; enum R_386_TLS_GD = 18; enum R_386_TLS_LDM = 19; enum R_386_TLS_GD_32 = 24; enum R_386_TLS_GD_PUSH = 25; enum R_386_TLS_GD_CALL = 26; enum R_386_TLS_GD_POP = 27; enum R_386_TLS_LDM_32 = 28; enum R_386_TLS_LDM_PUSH = 29; enum R_386_TLS_LDM_CALL = 30; enum R_386_TLS_LDM_POP = 31; enum R_386_TLS_LDO_32 = 32; enum R_386_TLS_IE_32 = 33; enum R_386_TLS_LE_32 = 34; enum R_386_TLS_DTPMOD32 = 35; enum R_386_TLS_DTPOFF32 = 36; enum R_386_TLS_TPOFF32 = 37; enum R_386_IRELATIVE = 42; enum R_ARM_NONE = 0; enum R_ARM_PC24 = 1; enum R_ARM_ABS32 = 2; enum R_ARM_REL32 = 3; enum R_ARM_PC13 = 4; enum R_ARM_ABS16 = 5; enum R_ARM_ABS12 = 6; enum R_ARM_THM_ABS5 = 7; enum R_ARM_ABS8 = 8; enum R_ARM_SBREL32 = 9; enum R_ARM_THM_PC22 = 10; enum R_ARM_THM_PC8 = 11; enum R_ARM_AMP_VCALL9 = 12; enum R_ARM_SWI24 = 13; enum R_ARM_THM_SWI8 = 14; enum R_ARM_XPC25 = 15; enum R_ARM_THM_XPC22 = 16; enum R_ARM_TLS_DTPMOD32 = 17; enum R_ARM_TLS_DTPOFF32 = 18; enum R_ARM_TLS_TPOFF32 = 19; enum R_ARM_COPY = 20; enum R_ARM_GLOB_DAT = 21; enum R_ARM_JUMP_SLOT = 22; enum R_ARM_RELATIVE = 23; enum R_ARM_GOTOFF = 24; enum R_ARM_GOTPC = 25; enum R_ARM_GOT32 = 26; enum R_ARM_PLT32 = 27; enum R_ARM_GNU_VTENTRY = 100; enum R_ARM_GNU_VTINHERIT = 101; enum R_ARM_RSBREL32 = 250; enum R_ARM_THM_RPC22 = 251; enum R_ARM_RREL32 = 252; enum R_ARM_RABS32 = 253; enum R_ARM_RPC24 = 254; enum R_ARM_RBASE = 255; enum R_IA_64_NONE = 0; enum R_IA_64_IMM14 = 0x21; enum R_IA_64_IMM22 = 0x22; enum R_IA_64_IMM64 = 0x23; enum R_IA_64_DIR32MSB = 0x24; enum R_IA_64_DIR32LSB = 0x25; enum R_IA_64_DIR64MSB = 0x26; enum R_IA_64_DIR64LSB = 0x27; enum R_IA_64_GPREL22 = 0x2a; enum R_IA_64_GPREL64I = 0x2b; enum R_IA_64_GPREL32MSB = 0x2c; enum R_IA_64_GPREL32LSB = 0x2d; enum R_IA_64_GPREL64MSB = 0x2e; enum R_IA_64_GPREL64LSB = 0x2f; enum R_IA_64_LTOFF22 = 0x32; enum R_IA_64_LTOFF64I = 0x33; enum R_IA_64_PLTOFF22 = 0x3a; enum R_IA_64_PLTOFF64I = 0x3b; enum R_IA_64_PLTOFF64MSB = 0x3e; enum R_IA_64_PLTOFF64LSB = 0x3f; enum R_IA_64_FPTR64I = 0x43; enum R_IA_64_FPTR32MSB = 0x44; enum R_IA_64_FPTR32LSB = 0x45; enum R_IA_64_FPTR64MSB = 0x46; enum R_IA_64_FPTR64LSB = 0x47; enum R_IA_64_PCREL60B = 0x48; enum R_IA_64_PCREL21B = 0x49; enum R_IA_64_PCREL21M = 0x4a; enum R_IA_64_PCREL21F = 0x4b; enum R_IA_64_PCREL32MSB = 0x4c; enum R_IA_64_PCREL32LSB = 0x4d; enum R_IA_64_PCREL64MSB = 0x4e; enum R_IA_64_PCREL64LSB = 0x4f; enum R_IA_64_LTOFF_FPTR22 = 0x52; enum R_IA_64_LTOFF_FPTR64I = 0x53; enum R_IA_64_LTOFF_FPTR32MSB = 0x54; enum R_IA_64_LTOFF_FPTR32LSB = 0x55; enum R_IA_64_LTOFF_FPTR64MSB = 0x56; enum R_IA_64_LTOFF_FPTR64LSB = 0x57; enum R_IA_64_SEGREL32MSB = 0x5c; enum R_IA_64_SEGREL32LSB = 0x5d; enum R_IA_64_SEGREL64MSB = 0x5e; enum R_IA_64_SEGREL64LSB = 0x5f; enum R_IA_64_SECREL32MSB = 0x64; enum R_IA_64_SECREL32LSB = 0x65; enum R_IA_64_SECREL64MSB = 0x66; enum R_IA_64_SECREL64LSB = 0x67; enum R_IA_64_REL32MSB = 0x6c; enum R_IA_64_REL32LSB = 0x6d; enum R_IA_64_REL64MSB = 0x6e; enum R_IA_64_REL64LSB = 0x6f; enum R_IA_64_LTV32MSB = 0x74; enum R_IA_64_LTV32LSB = 0x75; enum R_IA_64_LTV64MSB = 0x76; enum R_IA_64_LTV64LSB = 0x77; enum R_IA_64_PCREL21BI = 0x79; enum R_IA_64_PCREL22 = 0x7a; enum R_IA_64_PCREL64I = 0x7b; enum R_IA_64_IPLTMSB = 0x80; enum R_IA_64_IPLTLSB = 0x81; enum R_IA_64_SUB = 0x85; enum R_IA_64_LTOFF22X = 0x86; enum R_IA_64_LDXMOV = 0x87; enum R_IA_64_TPREL14 = 0x91; enum R_IA_64_TPREL22 = 0x92; enum R_IA_64_TPREL64I = 0x93; enum R_IA_64_TPREL64MSB = 0x96; enum R_IA_64_TPREL64LSB = 0x97; enum R_IA_64_LTOFF_TPREL22 = 0x9a; enum R_IA_64_DTPMOD64MSB = 0xa6; enum R_IA_64_DTPMOD64LSB = 0xa7; enum R_IA_64_LTOFF_DTPMOD22 = 0xaa; enum R_IA_64_DTPREL14 = 0xb1; enum R_IA_64_DTPREL22 = 0xb2; enum R_IA_64_DTPREL64I = 0xb3; enum R_IA_64_DTPREL32MSB = 0xb4; enum R_IA_64_DTPREL32LSB = 0xb5; enum R_IA_64_DTPREL64MSB = 0xb6; enum R_IA_64_DTPREL64LSB = 0xb7; enum R_IA_64_LTOFF_DTPREL22 = 0xba; enum R_MIPS_NONE = 0; enum R_MIPS_16 = 1; enum R_MIPS_32 = 2; enum R_MIPS_REL32 = 3; enum R_MIPS_26 = 4; enum R_MIPS_HI16 = 5; enum R_MIPS_LO16 = 6; enum R_MIPS_GPREL16 = 7; enum R_MIPS_LITERAL = 8; enum R_MIPS_GOT16 = 9; enum R_MIPS_PC16 = 10; enum R_MIPS_CALL16 = 11; enum R_MIPS_GPREL32 = 12; enum R_MIPS_GOTHI16 = 21; enum R_MIPS_GOTLO16 = 22; enum R_MIPS_CALLHI16 = 30; enum R_MIPS_CALLLO16 = 31; enum R_PPC_NONE = 0; enum R_PPC_ADDR32 = 1; enum R_PPC_ADDR24 = 2; enum R_PPC_ADDR16 = 3; enum R_PPC_ADDR16_LO = 4; enum R_PPC_ADDR16_HI = 5; enum R_PPC_ADDR16_HA = 6; enum R_PPC_ADDR14 = 7; enum R_PPC_ADDR14_BRTAKEN = 8; enum R_PPC_ADDR14_BRNTAKEN = 9; enum R_PPC_REL24 = 10; enum R_PPC_REL14 = 11; enum R_PPC_REL14_BRTAKEN = 12; enum R_PPC_REL14_BRNTAKEN = 13; enum R_PPC_GOT16 = 14; enum R_PPC_GOT16_LO = 15; enum R_PPC_GOT16_HI = 16; enum R_PPC_GOT16_HA = 17; enum R_PPC_PLTREL24 = 18; enum R_PPC_COPY = 19; enum R_PPC_GLOB_DAT = 20; enum R_PPC_JMP_SLOT = 21; enum R_PPC_RELATIVE = 22; enum R_PPC_LOCAL24PC = 23; enum R_PPC_UADDR32 = 24; enum R_PPC_UADDR16 = 25; enum R_PPC_REL32 = 26; enum R_PPC_PLT32 = 27; enum R_PPC_PLTREL32 = 28; enum R_PPC_PLT16_LO = 29; enum R_PPC_PLT16_HI = 30; enum R_PPC_PLT16_HA = 31; enum R_PPC_SDAREL16 = 32; enum R_PPC_SECTOFF = 33; enum R_PPC_SECTOFF_LO = 34; enum R_PPC_SECTOFF_HI = 35; enum R_PPC_SECTOFF_HA = 36; enum R_PPC64_ADDR64 = 38; enum R_PPC64_ADDR16_HIGHER = 39; enum R_PPC64_ADDR16_HIGHERA = 40; enum R_PPC64_ADDR16_HIGHEST = 41; enum R_PPC64_ADDR16_HIGHESTA = 42; enum R_PPC64_UADDR64 = 43; enum R_PPC64_REL64 = 44; enum R_PPC64_PLT64 = 45; enum R_PPC64_PLTREL64 = 46; enum R_PPC64_TOC16 = 47; enum R_PPC64_TOC16_LO = 48; enum R_PPC64_TOC16_HI = 49; enum R_PPC64_TOC16_HA = 50; enum R_PPC64_TOC = 51; enum R_PPC64_DTPMOD64 = 68; enum R_PPC64_TPREL64 = 73; enum R_PPC64_DTPREL64 = 78; enum R_PPC_TLS = 67; enum R_PPC_DTPMOD32 = 68; enum R_PPC_TPREL16 = 69; enum R_PPC_TPREL16_LO = 70; enum R_PPC_TPREL16_HI = 71; enum R_PPC_TPREL16_HA = 72; enum R_PPC_TPREL32 = 73; enum R_PPC_DTPREL16 = 74; enum R_PPC_DTPREL16_LO = 75; enum R_PPC_DTPREL16_HI = 76; enum R_PPC_DTPREL16_HA = 77; enum R_PPC_DTPREL32 = 78; enum R_PPC_GOT_TLSGD16 = 79; enum R_PPC_GOT_TLSGD16_LO = 80; enum R_PPC_GOT_TLSGD16_HI = 81; enum R_PPC_GOT_TLSGD16_HA = 82; enum R_PPC_GOT_TLSLD16 = 83; enum R_PPC_GOT_TLSLD16_LO = 84; enum R_PPC_GOT_TLSLD16_HI = 85; enum R_PPC_GOT_TLSLD16_HA = 86; enum R_PPC_GOT_TPREL16 = 87; enum R_PPC_GOT_TPREL16_LO = 88; enum R_PPC_GOT_TPREL16_HI = 89; enum R_PPC_GOT_TPREL16_HA = 90; enum R_PPC_EMB_NADDR32 = 101; enum R_PPC_EMB_NADDR16 = 102; enum R_PPC_EMB_NADDR16_LO = 103; enum R_PPC_EMB_NADDR16_HI = 104; enum R_PPC_EMB_NADDR16_HA = 105; enum R_PPC_EMB_SDAI16 = 106; enum R_PPC_EMB_SDA2I16 = 107; enum R_PPC_EMB_SDA2REL = 108; enum R_PPC_EMB_SDA21 = 109; enum R_PPC_EMB_MRKREF = 110; enum R_PPC_EMB_RELSEC16 = 111; enum R_PPC_EMB_RELST_LO = 112; enum R_PPC_EMB_RELST_HI = 113; enum R_PPC_EMB_RELST_HA = 114; enum R_PPC_EMB_BIT_FLD = 115; enum R_PPC_EMB_RELSDA = 116; enum R_SPARC_NONE = 0; enum R_SPARC_8 = 1; enum R_SPARC_16 = 2; enum R_SPARC_32 = 3; enum R_SPARC_DISP8 = 4; enum R_SPARC_DISP16 = 5; enum R_SPARC_DISP32 = 6; enum R_SPARC_WDISP30 = 7; enum R_SPARC_WDISP22 = 8; enum R_SPARC_HI22 = 9; enum R_SPARC_22 = 10; enum R_SPARC_13 = 11; enum R_SPARC_LO10 = 12; enum R_SPARC_GOT10 = 13; enum R_SPARC_GOT13 = 14; enum R_SPARC_GOT22 = 15; enum R_SPARC_PC10 = 16; enum R_SPARC_PC22 = 17; enum R_SPARC_WPLT30 = 18; enum R_SPARC_COPY = 19; enum R_SPARC_GLOB_DAT = 20; enum R_SPARC_JMP_SLOT = 21; enum R_SPARC_RELATIVE = 22; enum R_SPARC_UA32 = 23; enum R_SPARC_PLT32 = 24; enum R_SPARC_HIPLT22 = 25; enum R_SPARC_LOPLT10 = 26; enum R_SPARC_PCPLT32 = 27; enum R_SPARC_PCPLT22 = 28; enum R_SPARC_PCPLT10 = 29; enum R_SPARC_10 = 30; enum R_SPARC_11 = 31; enum R_SPARC_64 = 32; enum R_SPARC_OLO10 = 33; enum R_SPARC_HH22 = 34; enum R_SPARC_HM10 = 35; enum R_SPARC_LM22 = 36; enum R_SPARC_PC_HH22 = 37; enum R_SPARC_PC_HM10 = 38; enum R_SPARC_PC_LM22 = 39; enum R_SPARC_WDISP16 = 40; enum R_SPARC_WDISP19 = 41; enum R_SPARC_GLOB_JMP = 42; enum R_SPARC_7 = 43; enum R_SPARC_5 = 44; enum R_SPARC_6 = 45; enum R_SPARC_DISP64 = 46; enum R_SPARC_PLT64 = 47; enum R_SPARC_HIX22 = 48; enum R_SPARC_LOX10 = 49; enum R_SPARC_H44 = 50; enum R_SPARC_M44 = 51; enum R_SPARC_L44 = 52; enum R_SPARC_REGISTER = 53; enum R_SPARC_UA64 = 54; enum R_SPARC_UA16 = 55; enum R_SPARC_TLS_GD_HI22 = 56; enum R_SPARC_TLS_GD_LO10 = 57; enum R_SPARC_TLS_GD_ADD = 58; enum R_SPARC_TLS_GD_CALL = 59; enum R_SPARC_TLS_LDM_HI22 = 60; enum R_SPARC_TLS_LDM_LO10 = 61; enum R_SPARC_TLS_LDM_ADD = 62; enum R_SPARC_TLS_LDM_CALL = 63; enum R_SPARC_TLS_LDO_HIX22 = 64; enum R_SPARC_TLS_LDO_LOX10 = 65; enum R_SPARC_TLS_LDO_ADD = 66; enum R_SPARC_TLS_IE_HI22 = 67; enum R_SPARC_TLS_IE_LO10 = 68; enum R_SPARC_TLS_IE_LD = 69; enum R_SPARC_TLS_IE_LDX = 70; enum R_SPARC_TLS_IE_ADD = 71; enum R_SPARC_TLS_LE_HIX22 = 72; enum R_SPARC_TLS_LE_LOX10 = 73; enum R_SPARC_TLS_DTPMOD32 = 74; enum R_SPARC_TLS_DTPMOD64 = 75; enum R_SPARC_TLS_DTPOFF32 = 76; enum R_SPARC_TLS_DTPOFF64 = 77; enum R_SPARC_TLS_TPOFF32 = 78; enum R_SPARC_TLS_TPOFF64 = 79; enum R_X86_64_NONE = 0; enum R_X86_64_64 = 1; enum R_X86_64_PC32 = 2; enum R_X86_64_GOT32 = 3; enum R_X86_64_PLT32 = 4; enum R_X86_64_COPY = 5; enum R_X86_64_GLOB_DAT = 6; enum R_X86_64_JMP_SLOT = 7; enum R_X86_64_RELATIVE = 8; enum R_X86_64_GOTPCREL = 9; enum R_X86_64_32 = 10; enum R_X86_64_32S = 11; enum R_X86_64_16 = 12; enum R_X86_64_PC16 = 13; enum R_X86_64_8 = 14; enum R_X86_64_PC8 = 15; enum R_X86_64_DTPMOD64 = 16; enum R_X86_64_DTPOFF64 = 17; enum R_X86_64_TPOFF64 = 18; enum R_X86_64_TLSGD = 19; enum R_X86_64_TLSLD = 20; enum R_X86_64_DTPOFF32 = 21; enum R_X86_64_GOTTPOFF = 22; enum R_X86_64_TPOFF32 = 23; enum R_X86_64_IRELATIVE = 37; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/sys/mman.d0000664000175000017500000000724112776214756023351 0ustar kaikai/** * D header file for FreeBSD * * Authors: Martin Nowak */ module core.sys.freebsd.sys.mman; version (FreeBSD): extern (C): nothrow: public import core.sys.posix.sys.mman; import core.sys.freebsd.sys.cdefs; import core.sys.posix.sys.types; // https://svnweb.freebsd.org/base/head/sys/sys/mman.h?revision=270825&view=markup static if (__BSD_VISIBLE) { enum INHERIT_SHARE = 0; enum INHERIT_COPY = 1; enum INHERIT_NONE = 2; } // already in core.sys.posix.sys.mman // enum PROT_NONE = 0x00; // enum PROT_READ = 0x01; // enum PROT_WRITE = 0x02; // enum PROT_EXEC = 0x04; // enum MAP_SHARED = 0x0001; // enum MAP_PRIVATE = 0x0002; static if (__BSD_VISIBLE) alias MAP_COPY = MAP_PRIVATE; // enum MAP_FIXED = 0x0010; static if (__BSD_VISIBLE) { enum MAP_RENAME = 0x0020; enum MAP_NORESERVE = 0x0040; enum MAP_RESERVED0080 = 0x0080; enum MAP_RESERVED0100 = 0x0100; enum MAP_HASSEMAPHORE = 0x0200; enum MAP_STACK = 0x0400; enum MAP_NOSYNC = 0x0800; enum MAP_FILE = 0x0000; // already in core.sys.posix.sys.mman // enum MAP_ANON = 0x1000; //#ifndef _KERNEL alias MAP_ANONYMOUS = MAP_ANON; //#endif /* !_KERNEL */ enum MAP_EXCL = 0x00004000; enum MAP_NOCORE = 0x00020000; enum MAP_PREFAULT_READ = 0x00040000; version (LP64) enum MAP_32BIT = 0x00080000; extern(D) int MAP_ALIGNED(int n) { return n << MAP_ALIGNMENT_SHIFT; } enum MAP_ALIGNMENT_SHIFT = 24; enum MAP_ALIGNMENT_MASK = MAP_ALIGNED(0xff); enum MAP_ALIGNED_SUPER = MAP_ALIGNED(1); } static if (__POSIX_VISIBLE >= 199309) { // already in core.sys.posix.sys.mman // enum MCL_CURRENT = 0x0001; // enum MCL_FUTURE = 0x0002; } // already in core.sys.posix.sys.mman enum MAP_FAILED = cast(void*)-1; // already in core.sys.posix.sys.mman // enum MS_SYNC = 0x0000; // enum MS_ASYNC = 0x0001; // enum MS_INVALIDATE = 0x0002; enum _MADV_NORMAL = 0; enum _MADV_RANDOM = 1; enum _MADV_SEQUENTIAL = 2; enum _MADV_WILLNEED = 3; enum _MADV_DONTNEED = 4; static if (__BSD_VISIBLE) { alias MADV_NORMAL = _MADV_NORMAL; alias MADV_RANDOM = _MADV_RANDOM; alias MADV_SEQUENTIAL = _MADV_SEQUENTIAL; alias MADV_WILLNEED = _MADV_WILLNEED; alias MADV_DONTNEED = _MADV_DONTNEED; enum MADV_FREE = 5; enum MADV_NOSYNC = 6; enum MADV_AUTOSYNC = 7; enum MADV_NOCORE = 8; enum MADV_CORE = 9; enum MADV_PROTECT = 10; enum MINCORE_INCORE = 0x1; enum MINCORE_REFERENCED = 0x2; enum MINCORE_MODIFIED = 0x4; enum MINCORE_REFERENCED_OTHER = 0x8; enum MINCORE_MODIFIED_OTHER = 0x10; enum MINCORE_SUPER = 0x20; enum SHM_ANON = cast(const(char) *)1; } static if (__POSIX_VISIBLE >= 200112) { // already in core.sys.posix.sys.mman // alias POSIX_MADV_NORMAL = _MADV_NORMAL; // alias POSIX_MADV_RANDOM = _MADV_RANDOM; // alias POSIX_MADV_SEQUENTIAL = _MADV_SEQUENTIAL; // alias POSIX_MADV_WILLNEED = _MADV_WILLNEED; // alias POSIX_MADV_DONTNEED = _MADV_DONTNEED; } static if (__BSD_VISIBLE) { int getpagesizes(size_t *, int); int madvise(void *, size_t, int); int mincore(const(void) *, size_t, char *); int minherit(void *, size_t, int); } // already in core.sys.posix.sys.mman // int mlock(const void *, size_t); // void * mmap(void *, size_t, int, int, int, off_t); // int mprotect(const void *, size_t, int); // int msync(void *, size_t, int); // int munlock(const void *, size_t); // int munmap(void *, size_t); static if (__POSIX_VISIBLE >= 200112) // int posix_madvise(void *, size_t, int); static if (__POSIX_VISIBLE >= 199309) { // int mlockall(int); // int munlockall(); // int shm_open(const(char) *, int, mode_t); // int shm_unlink(const(char) *); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/sys/elf32.d0000664000175000017500000000725112776214756023335 0ustar kaikai/** * D header file for FreeBSD. * * $(LINK2 http://svnweb.freebsd.org/base/head/sys/sys/elf32.h?view=markup, sys/elf32.h) */ module core.sys.freebsd.sys.elf32; version (FreeBSD): extern (C): pure: nothrow: import core.stdc.stdint; public import core.sys.freebsd.sys.elf_common; alias uint16_t Elf32_Half; alias uint32_t Elf32_Word; alias int32_t Elf32_Sword; alias uint64_t Elf32_Lword; alias uint32_t Elf32_Addr; alias uint32_t Elf32_Off; alias Elf32_Word Elf32_Hashelt; alias Elf32_Word Elf32_Size; alias Elf32_Sword Elf32_Ssize; struct Elf32_Ehdr { char[EI_NIDENT] e_ident; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } struct Elf32_Shdr { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } struct Elf32_Phdr { Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; } struct Elf32_Dyn { Elf32_Sword d_tag; union _d_un { Elf32_Word d_val; Elf32_Addr d_ptr; } _d_un d_un; } struct Elf32_Rel { Elf32_Addr r_offset; Elf32_Word r_info; } struct Elf32_Rela { Elf32_Addr r_offset; Elf32_Word r_info; Elf32_Sword r_addend; } extern (D) { auto ELF32_R_SYM(V)(V val) { return val >> 8; } auto ELF32_R_TYPE(V)(V val) { return val & 0xff; } auto ELF32_R_INFO(S, T)(S sym, T type) { return (sym << 8) + (type & 0xff); } } alias Elf_Note Elf32_Nhdr; struct Elf32_Move { Elf32_Lword m_value; Elf32_Word m_info; Elf32_Word m_poffset; Elf32_Half m_repeat; Elf32_Half m_stride; } extern (D) { auto ELF32_M_SYM(I)(I info) { return info >> 8; } auto ELF32_M_SIZE(I)(I info) { return cast(ubyte)info; } auto ELF32_M_INFO(S, SZ)(S sym, SZ size) { return (sym << 8) + cast(ubye)size; } } struct Elf32_Cap { Elf32_Word c_tag; union _c_un { Elf32_Word c_val; Elf32_Addr c_ptr; } _c_un c_un; } struct Elf32_Sym { Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; ubyte st_info; ubyte st_other; Elf32_Half st_shndx; } extern (D) { auto ELF32_ST_BIND(T)(T val) { return cast(ubyte)val >> 4; } auto ELF32_ST_TYPE(T)(T val) { return val & 0xf; } auto ELF32_ST_INFO(B, T)(B bind, T type) { return (bind << 4) + (type & 0xf); } auto ELF32_ST_VISIBILITY(O)(O o) { return o & 0x03; } } struct Elf32_Verdef { Elf32_Half vd_version; Elf32_Half vd_flags; Elf32_Half vd_ndx; Elf32_Half vd_cnt; Elf32_Word vd_hash; Elf32_Word vd_aux; Elf32_Word vd_next; } struct Elf32_Verdaux { Elf32_Word vda_name; Elf32_Word vda_next; } struct Elf32_Verneed { Elf32_Half vn_version; Elf32_Half vn_cnt; Elf32_Word vn_file; Elf32_Word vn_aux; Elf32_Word vn_next; } struct Elf32_Vernaux { Elf32_Word vna_hash; Elf32_Half vna_flags; Elf32_Half vna_other; Elf32_Word vna_name; Elf32_Word vna_next; } alias Elf32_Half Elf32_Versym; struct Elf32_Syminfo { Elf32_Half si_boundto; Elf32_Half si_flags; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/sys/elf64.d0000664000175000017500000000776312776214756023352 0ustar kaikai/** * D header file for FreeBSD. * * $(LINK2 http://svnweb.freebsd.org/base/head/sys/sys/elf64.h?view=markup, sys/elf64.h) */ module core.sys.freebsd.sys.elf64; version (FreeBSD): extern (C): pure: nothrow: import core.stdc.stdint; public import core.sys.freebsd.sys.elf_common; alias uint16_t Elf64_Half; alias uint32_t Elf64_Word; alias int32_t Elf64_Sword; alias uint64_t Elf64_Lword; alias uint64_t Elf64_Xword; alias int64_t Elf64_Sxword; alias uint64_t Elf64_Addr; alias uint64_t Elf64_Off; alias Elf64_Word Elf64_Hashelt; alias Elf64_Xword Elf64_Size; alias Elf64_Sxword Elf64_Ssize; struct Elf64_Ehdr { char[EI_NIDENT] e_ident; Elf64_Half e_type; Elf64_Half e_machine; Elf64_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf64_Word e_flags; Elf64_Half e_ehsize; Elf64_Half e_phentsize; Elf64_Half e_phnum; Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx; } struct Elf64_Shdr { Elf64_Word sh_name; Elf64_Word sh_type; Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; Elf64_Xword sh_addralign; Elf64_Xword sh_entsize; } struct Elf64_Phdr { Elf64_Word p_type; Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align; } struct Elf64_Dyn { Elf64_Sxword d_tag; union _d_un { Elf64_Xword d_val; Elf64_Addr d_ptr; } _d_un d_un; } struct Elf64_Rel { Elf64_Addr r_offset; Elf64_Xword r_info; } struct Elf64_Rela { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } extern (D) { auto ELF64_R_SYM(I)(I i) { return i >> 32; } auto ELF64_R_TYPE(I)(I i) { return i & 0xffffffff; } auto ELF64_R_INFO(S, T)(S sym, T type) { return (sym << 32) + (type & 0xffffffff); } auto ELF64_R_TYPE_DATA(I)(I i) { return (cast(Elf64_Xword) i << 32) >> 40; } auto ELF64_R_TYPE_ID(I)(I i) { return (cast(Elf64_Xword) i << 56 ) >> 56; } auto ELF64_R_TYPE_INFO(D, T)(D d, T t) { return cast(Elf64_Xword) d << 8 + cast(Elf64_Xword) t; } } alias Elf_Note Elf64_Nhdr; struct Elf64_Move { Elf64_Lword m_value; Elf64_Xword m_info; Elf64_Xword m_poffset; Elf64_Half m_repeat; Elf64_Half m_stride; } extern (D) { auto ELF64_M_SYM(I)(I info) { return info >> 8; } auto ELF64_M_SIZE(I)(I info) { return cast(ubyte)info; } auto ELF64_M_INFO(S, SZ)(S sym, SZ size) { return (sym << 8) + cast(ubye)size; } } struct Elf64_Cap { Elf64_Xword c_tag; union _c_un { Elf64_Xword c_val; Elf64_Addr c_ptr; } _c_un c_un; } struct Elf64_Sym { Elf64_Word st_name; ubyte st_info; ubyte st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } extern (D) { auto ELF64_ST_BIND(T)(T val) { return cast(ubyte)val >> 4; } auto ELF64_ST_TYPE(T)(T val) { return val & 0xf; } auto ELF64_ST_INFO(B, T)(B bind, T type) { return (bind << 4) + (type & 0xf); } auto ELF64_ST_VISIBILITY(O)(O o) { return o & 0x03; } } struct Elf64_Verdef { Elf64_Half vd_version; Elf64_Half vd_flags; Elf64_Half vd_ndx; Elf64_Half vd_cnt; Elf64_Word vd_hash; Elf64_Word vd_aux; Elf64_Word vd_next; } struct Elf64_Verdaux { Elf64_Word vda_name; Elf64_Word vda_next; } struct Elf64_Verneed { Elf64_Half vn_version; Elf64_Half vn_cnt; Elf64_Word vn_file; Elf64_Word vn_aux; Elf64_Word vn_next; } struct Elf64_Vernaux { Elf64_Word vna_hash; Elf64_Half vna_flags; Elf64_Half vna_other; Elf64_Word vna_name; Elf64_Word vna_next; } alias Elf64_Half Elf64_Versym; struct Elf64_Syminfo { Elf64_Half si_boundto; Elf64_Half si_flags; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/sys/event.d0000664000175000017500000001044712776214756023544 0ustar kaikai/** * D header file for FreeBSD. * * Copyright: Copyright Martin Nowak 2012. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak */ /* Copyright Martin Nowak 2012. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.freebsd.sys.event; version (FreeBSD): extern (C): import core.stdc.stdint; // intptr_t, uintptr_t import core.sys.posix.time; // timespec enum { EVFILT_READ = -1, EVFILT_WRITE = -2, EVFILT_AIO = -3, /* attached to aio requests */ EVFILT_VNODE = -4, /* attached to vnodes */ EVFILT_PROC = -5, /* attached to struct proc */ EVFILT_SIGNAL = -6, /* attached to struct proc */ EVFILT_TIMER = -7, /* timers */ // EVFILT_NETDEV = -8, /* no longer supported */ EVFILT_FS = -9, /* filesystem events */ EVFILT_LIO = -10, /* attached to lio requests */ EVFILT_USER = -11, /* User events */ EVFILT_SYSCOUNT = 11, } extern(D) void EV_SET(kevent_t* kevp, typeof(kevent_t.tupleof) args) { *kevp = kevent_t(args); } struct kevent_t { uintptr_t ident; /* identifier for this event */ short filter; /* filter for event */ ushort flags; uint fflags; intptr_t data; void *udata; /* opaque user data identifier */ } enum { /* actions */ EV_ADD = 0x0001, /* add event to kq (implies enable) */ EV_DELETE = 0x0002, /* delete event from kq */ EV_ENABLE = 0x0004, /* enable event */ EV_DISABLE = 0x0008, /* disable event (not reported) */ /* flags */ EV_ONESHOT = 0x0010, /* only report one occurrence */ EV_CLEAR = 0x0020, /* clear event state after reporting */ EV_RECEIPT = 0x0040, /* force EV_ERROR on success, data=0 */ EV_DISPATCH = 0x0080, /* disable event after reporting */ EV_SYSFLAGS = 0xF000, /* reserved by system */ EV_FLAG1 = 0x2000, /* filter-specific flag */ /* returned values */ EV_EOF = 0x8000, /* EOF detected */ EV_ERROR = 0x4000, /* error, data contains errno */ } enum { /* * data/hint flags/masks for EVFILT_USER, shared with userspace * * On input, the top two bits of fflags specifies how the lower twenty four * bits should be applied to the stored value of fflags. * * On output, the top two bits will always be set to NOTE_FFNOP and the * remaining twenty four bits will contain the stored fflags value. */ NOTE_FFNOP = 0x00000000, /* ignore input fflags */ NOTE_FFAND = 0x40000000, /* AND fflags */ NOTE_FFOR = 0x80000000, /* OR fflags */ NOTE_FFCOPY = 0xc0000000, /* copy fflags */ NOTE_FFCTRLMASK = 0xc0000000, /* masks for operations */ NOTE_FFLAGSMASK = 0x00ffffff, NOTE_TRIGGER = 0x01000000, /* Cause the event to be triggered for output. */ /* * data/hint flags for EVFILT_{READ|WRITE}, shared with userspace */ NOTE_LOWAT = 0x0001, /* low water mark */ /* * data/hint flags for EVFILT_VNODE, shared with userspace */ NOTE_DELETE = 0x0001, /* vnode was removed */ NOTE_WRITE = 0x0002, /* data contents changed */ NOTE_EXTEND = 0x0004, /* size increased */ NOTE_ATTRIB = 0x0008, /* attributes changed */ NOTE_LINK = 0x0010, /* link count changed */ NOTE_RENAME = 0x0020, /* vnode was renamed */ NOTE_REVOKE = 0x0040, /* vnode access was revoked */ /* * data/hint flags for EVFILT_PROC, shared with userspace */ NOTE_EXIT = 0x80000000, /* process exited */ NOTE_FORK = 0x40000000, /* process forked */ NOTE_EXEC = 0x20000000, /* process exec'd */ NOTE_PCTRLMASK = 0xf0000000, /* mask for hint bits */ NOTE_PDATAMASK = 0x000fffff, /* mask for pid */ /* additional flags for EVFILT_PROC */ NOTE_TRACK = 0x00000001, /* follow across forks */ NOTE_TRACKERR = 0x00000002, /* could not track child */ NOTE_CHILD = 0x00000004, /* am a child process */ } int kqueue(); int kevent(int kq, const kevent_t *changelist, int nchanges, kevent_t *eventlist, int nevents, const timespec *timeout); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/freebsd/sys/cdefs.d0000664000175000017500000000054412776214756023504 0ustar kaikai/** * D header file for FreeBSD * * Authors: Martin Nowak */ module core.sys.freebsd.sys.cdefs; version (FreeBSD): public import core.sys.posix.config; // https://svnweb.freebsd.org/base/head/sys/sys/cdefs.h?revision=271155&view=markup enum __POSIX_VISIBLE = 200112; enum __XSI_VISIBLE = 700; enum __BSD_VISIBLE = true; enum __ISO_C_VISIBLE = 1999; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/0000775000175000017500000000000012776214756021157 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/dlfcn.d0000664000175000017500000001742412776214756022422 0ustar kaikai/** * D header file for GNU/Linux * * $(LINK2 http://sourceware.org/git/?p=glibc.git;a=blob;f=dlfcn/dlfcn.h, glibc dlfcn/dlfcn.h) */ module core.sys.linux.dlfcn; version (linux): extern (C): nothrow: public import core.sys.posix.dlfcn; import core.sys.linux.config; // version (X86) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h // enum RTLD_LAZY = 0x00001; // POSIX // enum RTLD_NOW = 0x00002; // POSIX enum RTLD_BINDING_MASK = 0x3; enum RTLD_NOLOAD = 0x00004; enum RTLD_DEEPBIND = 0x00008; // enum RTLD_GLOBAL = 0x00100; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_NODELETE = 0x01000; static if (__USE_GNU) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { _dl_mcount_wrapper_check(cast(void*)fctp); return fctp(args); } void _dl_mcount_wrapper_check(void* __selfpc); } } else version (X86_64) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h // enum RTLD_LAZY = 0x00001; // POSIX // enum RTLD_NOW = 0x00002; // POSIX enum RTLD_BINDING_MASK = 0x3; enum RTLD_NOLOAD = 0x00004; enum RTLD_DEEPBIND = 0x00008; // enum RTLD_GLOBAL = 0x00100; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_NODELETE = 0x01000; static if (__USE_GNU) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { _dl_mcount_wrapper_check(cast(void*)fctp); return fctp(args); } void _dl_mcount_wrapper_check(void* __selfpc); } } else version (MIPS32) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/mips/bits/dlfcn.h // enum RTLD_LAZY = 0x0001; // POSIX // enum RTLD_NOW = 0x0002; // POSIX enum RTLD_BINDING_MASK = 0x3; enum RTLD_NOLOAD = 0x00008; enum RTLD_DEEPBIND = 0x00010; // enum RTLD_GLOBAL = 0x0004; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_NODELETE = 0x01000; static if (__USE_GNU) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { _dl_mcount_wrapper_check(cast(void*)fctp); return fctp(args); } void _dl_mcount_wrapper_check(void* __selfpc); } } else version (MIPS64) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/mips/bits/dlfcn.h // enum RTLD_LAZY = 0x0001; // POSIX // enum RTLD_NOW = 0x0002; // POSIX enum RTLD_BINDING_MASK = 0x3; enum RTLD_NOLOAD = 0x00008; enum RTLD_DEEPBIND = 0x00010; // enum RTLD_GLOBAL = 0x0004; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_NODELETE = 0x01000; static if (__USE_GNU) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { _dl_mcount_wrapper_check(cast(void*)fctp); return fctp(args); } void _dl_mcount_wrapper_check(void* __selfpc); } } else version (PPC) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h // enum RTLD_LAZY = 0x0001; // POSIX // enum RTLD_NOW = 0x0002; // POSIX enum RTLD_BINDING_MASK = 0x3; enum RTLD_NOLOAD = 0x00004; enum RTLD_DEEPBIND = 0x00008; // enum RTLD_GLOBAL = 0x00100; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_NODELETE = 0x01000; static if (__USE_GNU) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { _dl_mcount_wrapper_check(cast(void*)fctp); return fctp(args); } void _dl_mcount_wrapper_check(void* __selfpc); } } else version (PPC64) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h // enum RTLD_LAZY = 0x0001; // POSIX // enum RTLD_NOW = 0x0002; // POSIX enum RTLD_BINDING_MASK = 0x3; enum RTLD_NOLOAD = 0x00004; enum RTLD_DEEPBIND = 0x00008; // enum RTLD_GLOBAL = 0x00100; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_NODELETE = 0x01000; static if (__USE_GNU) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { _dl_mcount_wrapper_check(cast(void*)fctp); return fctp(args); } void _dl_mcount_wrapper_check(void* __selfpc); } } else version (ARM) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h // enum RTLD_LAZY = 0x0001; // POSIX // enum RTLD_NOW = 0x0002; // POSIX enum RTLD_BINDING_MASK = 0x3; enum RTLD_NOLOAD = 0x00004; enum RTLD_DEEPBIND = 0x00008; // enum RTLD_GLOBAL = 0x00100; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_NODELETE = 0x01000; static if (__USE_GNU) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { _dl_mcount_wrapper_check(cast(void*)fctp); return fctp(args); } void _dl_mcount_wrapper_check(void* __selfpc); } } else version (AArch64) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h // enum RTLD_LAZY = 0x0001; // POSIX // enum RTLD_NOW = 0x0002; // POSIX enum RTLD_BINDING_MASK = 0x3; enum RTLD_NOLOAD = 0x00004; enum RTLD_DEEPBIND = 0x00008; // enum RTLD_GLOBAL = 0x00100; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_NODELETE = 0x01000; static if (__USE_GNU) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { _dl_mcount_wrapper_check(cast(void*)fctp); return fctp(args); } void _dl_mcount_wrapper_check(void* __selfpc); } } else version (SystemZ) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h // enum RTLD_LAZY = 0x0001; // POSIX // enum RTLD_NOW = 0x0002; // POSIX enum RTLD_BINDING_MASK = 0x3; enum RTLD_NOLOAD = 0x00004; enum RTLD_DEEPBIND = 0x00008; // enum RTLD_GLOBAL = 0x00100; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_NODELETE = 0x01000; static if (__USE_GNU) { RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args) { _dl_mcount_wrapper_check(cast(void*)fctp); return fctp(args); } void _dl_mcount_wrapper_check(void* __selfpc); } } else static assert(0, "unimplemented"); // static if (__USE_GNU) { enum RTLD_NEXT = cast(void *)-1L; enum RTLD_DEFAULT = cast(void *)0; alias c_long Lmid_t; enum LM_ID_BASE = 0; enum LM_ID_NEWLM = -1; } // void* dlopen(in char* __file, int __mode); // POSIX // int dlclose(void* __handle); // POSIX // void* dlsym(void* __handle, in char* __name); // POSIX static if (__USE_GNU) { void* dlmopen(Lmid_t __nsid, in char* __file, int __mode); void* dlvsym(void* __handle, in char* __name, in char* __version); } // char* dlerror(); // POSIX static if (__USE_GNU) { struct Dl_info { const(char)* dli_fname; void* dli_fbase; const(char)* dli_sname; void* dli_saddr; } int dladdr(void* __address, Dl_info* __info); int dladdr1(void* __address, Dl_info* __info, void** __extra_info, int __flags); enum { RTLD_DL_SYMENT = 1, RTLD_DL_LINKMAP = 2, } int dlinfo(void* __handle, int __request, void* __arg); enum { RTLD_DI_LMID = 1, RTLD_DI_LINKMAP = 2, RTLD_DI_CONFIGADDR = 3, RTLD_DI_SERINFO = 4, RTLD_DI_SERINFOSIZE = 5, RTLD_DI_ORIGIN = 6, RTLD_DI_PROFILENAME = 7, RTLD_DI_PROFILEOUT = 8, RTLD_DI_TLS_MODID = 9, RTLD_DI_TLS_DATA = 10, RTLD_DI_MAX = 10, } struct Dl_serpath { char* dls_name; uint dls_flags; } struct Dl_serinfo { size_t dls_size; uint dls_cnt; Dl_serpath[1] dls_serpath; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/execinfo.d0000664000175000017500000000065512776214756023132 0ustar kaikai/** * D header file for GNU/Linux. * * Copyright: Copyright Martin Nowak 2012. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ module core.sys.linux.execinfo; version (linux): extern (C): nothrow: int backtrace(void** buffer, int size); char** backtrace_symbols(const(void*)* buffer, int size); void backtrace_symbols_fd(const(void*)* buffer, int size, int fd); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/timerfd.d0000664000175000017500000000121012776214756022750 0ustar kaikai/** * D header file to interface with the Linux timefd API * Available since Linux 2.6 * * License : $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) */ module core.sys.linux.timerfd; version (linux): public import core.sys.posix.time; extern (C): @system: @nogc: nothrow: int timerfd_create(int clockid, int flags); int timerfd_settime(int fd, int flags, const itimerspec* new_value, itimerspec* old_value); int timerfd_gettime(int fd, itimerspec* curr_value); enum TFD_TIMER_ABSTIME = 1 << 0; enum TFD_CLOEXEC = 0x80000; enum TFD_NONBLOCK = 0x800; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/stdio.d0000664000175000017500000000615312776214756022453 0ustar kaikai/** * D header file for GNU stdio. * * Copyright: Danny Milosavljevic 2014 * License: Boost License 1.0. * Authors: Danny Milosavljevic */ module core.sys.linux.stdio; version (CRuntime_Glibc): public import core.sys.posix.stdio; import core.sys.posix.sys.types : ssize_t, off64_t = off_t; import core.sys.linux.config : __USE_FILE_OFFSET64; import core.stdc.stdio : FILE; import core.stdc.stddef : wchar_t; extern(C) nothrow { alias ssize_t function(void *cookie, char *buf, size_t size) cookie_read_function_t; alias ssize_t function(void *cookie, const(char) *buf, size_t size) cookie_write_function_t; alias int function(void *cookie, off64_t *offset, int whence) cookie_seek_function_t; alias int function(void *cookie) cookie_close_function_t; struct cookie_io_functions_t { cookie_read_function_t read; cookie_write_function_t write; cookie_seek_function_t seek; cookie_close_function_t close; } FILE* fopencookie(in void* cookie, in char* mode, cookie_io_functions_t io_funcs); void setbuffer(FILE *stream, char *buf, size_t size); // note: _BSD_SOURCE } unittest { static int flag = 0; static int written = 0; static int closed = 0; // Note: this test needs to run on both a 32 and a 64 bit machine, both have to pass. import core.stdc.errno : errno, EBADF; //import core.sys.posix.sys.stat : off64_t; import core.stdc.stdio : FILE, fflush, fileno, fprintf, fgetc, EOF, fclose; import core.stdc.string : memcpy, memset; extern (C) ssize_t specialRead(void *cookie, char *buf, size_t size) nothrow { memset(buf, 'a', size); return size; } extern (C) int specialClose(void* cookie) nothrow { ++closed; return 0; } extern (C) ssize_t specialWrite(void *cookie, const(char) *buf, size_t size) nothrow { int* c = cast(int*) cookie; flag = *c; written += size; return size; } int dummy = 42; cookie_io_functions_t fns = { read: &specialRead, write: &specialWrite, close: &specialClose, }; FILE* f = fopencookie(&dummy, "r+", fns); assert(f !is null); //File.open(); //auto g = File(f); assert(fileno(f) == -1 && errno == EBADF); assert(fprintf(f, "hello") == "hello".length); //assert(errno == EBADF); assert(fflush(f) == 0); assert(written == "hello".length); // Note: do not swap reading and writing here. int c = 0; while((c = fgetc(f)) != EOF) { assert(c == 'a'); break; // endless otherwise } assert(c == 'a'); assert(fclose(f) == 0); assert(closed == 1); assert(flag == dummy); //stdin.getFP(); //assert(stdin.fileno() == 0); } unittest { /* setbuffer */ char buf; int c; byte[10] dummy = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; FILE* f = fmemopen(dummy.ptr, 10, "r"); assert(f !is null); setbuffer(f, &buf, 1); assert(fgetc(f) == 1); assert(fgetc(f) == 2); assert(fgetc(f) == 3); assert(fgetc(f) == 4); assert(fclose(f) == 0); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/elf.d0000664000175000017500000023151012776214756022074 0ustar kaikai/** * D header file for GNU/Linux * * $(LINK2 http://sourceware.org/git/?p=glibc.git;a=blob;f=elf/elf.h, glibc elf/elf.h) */ module core.sys.linux.elf; version (linux): extern (C): pure: nothrow: import core.stdc.stdint; alias uint16_t Elf32_Half; alias uint16_t Elf64_Half; alias uint32_t Elf32_Word; alias int32_t Elf32_Sword; alias uint32_t Elf64_Word; alias int32_t Elf64_Sword; alias uint64_t Elf32_Xword; alias int64_t Elf32_Sxword; alias uint64_t Elf64_Xword; alias int64_t Elf64_Sxword; alias uint32_t Elf32_Addr; alias uint64_t Elf64_Addr; alias uint32_t Elf32_Off; alias uint64_t Elf64_Off; alias uint16_t Elf32_Section; alias uint16_t Elf64_Section; alias Elf32_Half Elf32_Versym; alias Elf64_Half Elf64_Versym; enum EI_NIDENT = 16; struct Elf32_Ehdr { char[EI_NIDENT] e_ident; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } struct Elf64_Ehdr { char[EI_NIDENT] e_ident; Elf64_Half e_type; Elf64_Half e_machine; Elf64_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf64_Word e_flags; Elf64_Half e_ehsize; Elf64_Half e_phentsize; Elf64_Half e_phnum; Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx; } enum EI_MAG0 = 0; enum ELFMAG0 = 0x7f; enum EI_MAG1 = 1; enum ELFMAG1 = 'E'; enum EI_MAG2 = 2; enum ELFMAG2 = 'L'; enum EI_MAG3 = 3; enum ELFMAG3 = 'F'; enum ELFMAG = "\177ELF"; enum SELFMAG = 4; enum EI_CLASS = 4; enum ELFCLASSNONE = 0; enum ELFCLASS32 = 1; enum ELFCLASS64 = 2; enum ELFCLASSNUM = 3; enum EI_DATA = 5; enum ELFDATANONE = 0; enum ELFDATA2LSB = 1; enum ELFDATA2MSB = 2; enum ELFDATANUM = 3; enum EI_VERSION = 6; enum EI_OSABI = 7; enum ELFOSABI_NONE = 0; enum ELFOSABI_SYSV = 0; enum ELFOSABI_HPUX = 1; enum ELFOSABI_NETBSD = 2; enum ELFOSABI_GNU = 3; enum ELFOSABI_LINUX = ELFOSABI_GNU; enum ELFOSABI_SOLARIS = 6; enum ELFOSABI_AIX = 7; enum ELFOSABI_IRIX = 8; enum ELFOSABI_FREEBSD = 9; enum ELFOSABI_TRU64 = 10; enum ELFOSABI_MODESTO = 11; enum ELFOSABI_OPENBSD = 12; enum ELFOSABI_ARM_AEABI = 64; enum ELFOSABI_ARM = 97; enum ELFOSABI_STANDALONE = 255; enum EI_ABIVERSION = 8; enum EI_PAD = 9; enum ET_NONE = 0; enum ET_REL = 1; enum ET_EXEC = 2; enum ET_DYN = 3; enum ET_CORE = 4; enum ET_NUM = 5; enum ET_LOOS = 0xfe00; enum ET_HIOS = 0xfeff; enum ET_LOPROC = 0xff00; enum ET_HIPROC = 0xffff; enum EM_NONE = 0; enum EM_M32 = 1; enum EM_SPARC = 2; enum EM_386 = 3; enum EM_68K = 4; enum EM_88K = 5; enum EM_860 = 7; enum EM_MIPS = 8; enum EM_S370 = 9; enum EM_MIPS_RS3_LE = 10; enum EM_PARISC = 15; enum EM_VPP500 = 17; enum EM_SPARC32PLUS = 18; enum EM_960 = 19; enum EM_PPC = 20; enum EM_PPC64 = 21; enum EM_S390 = 22; enum EM_V800 = 36; enum EM_FR20 = 37; enum EM_RH32 = 38; enum EM_RCE = 39; enum EM_ARM = 40; enum EM_FAKE_ALPHA = 41; enum EM_SH = 42; enum EM_SPARCV9 = 43; enum EM_TRICORE = 44; enum EM_ARC = 45; enum EM_H8_300 = 46; enum EM_H8_300H = 47; enum EM_H8S = 48; enum EM_H8_500 = 49; enum EM_IA_64 = 50; enum EM_MIPS_X = 51; enum EM_COLDFIRE = 52; enum EM_68HC12 = 53; enum EM_MMA = 54; enum EM_PCP = 55; enum EM_NCPU = 56; enum EM_NDR1 = 57; enum EM_STARCORE = 58; enum EM_ME16 = 59; enum EM_ST100 = 60; enum EM_TINYJ = 61; enum EM_X86_64 = 62; enum EM_PDSP = 63; enum EM_FX66 = 66; enum EM_ST9PLUS = 67; enum EM_ST7 = 68; enum EM_68HC16 = 69; enum EM_68HC11 = 70; enum EM_68HC08 = 71; enum EM_68HC05 = 72; enum EM_SVX = 73; enum EM_ST19 = 74; enum EM_VAX = 75; enum EM_CRIS = 76; enum EM_JAVELIN = 77; enum EM_FIREPATH = 78; enum EM_ZSP = 79; enum EM_MMIX = 80; enum EM_HUANY = 81; enum EM_PRISM = 82; enum EM_AVR = 83; enum EM_FR30 = 84; enum EM_D10V = 85; enum EM_D30V = 86; enum EM_V850 = 87; enum EM_M32R = 88; enum EM_MN10300 = 89; enum EM_MN10200 = 90; enum EM_PJ = 91; enum EM_OPENRISC = 92; enum EM_ARC_A5 = 93; enum EM_XTENSA = 94; enum EM_AARCH64 = 183; enum EM_TILEPRO = 188; enum EM_TILEGX = 191; enum EM_NUM = 192; enum EM_ALPHA = 0x9026; enum EV_NONE = 0; enum EV_CURRENT = 1; enum EV_NUM = 2; struct Elf32_Shdr { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } struct Elf64_Shdr { Elf64_Word sh_name; Elf64_Word sh_type; Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; Elf64_Xword sh_addralign; Elf64_Xword sh_entsize; } enum SHN_UNDEF = 0; enum SHN_LORESERVE = 0xff00; enum SHN_LOPROC = 0xff00; enum SHN_BEFORE = 0xff00; enum SHN_AFTER = 0xff01; enum SHN_HIPROC = 0xff1f; enum SHN_LOOS = 0xff20; enum SHN_HIOS = 0xff3f; enum SHN_ABS = 0xfff1; enum SHN_COMMON = 0xfff2; enum SHN_XINDEX = 0xffff; enum SHN_HIRESERVE = 0xffff; enum SHT_NULL = 0; enum SHT_PROGBITS = 1; enum SHT_SYMTAB = 2; enum SHT_STRTAB = 3; enum SHT_RELA = 4; enum SHT_HASH = 5; enum SHT_DYNAMIC = 6; enum SHT_NOTE = 7; enum SHT_NOBITS = 8; enum SHT_REL = 9; enum SHT_SHLIB = 10; enum SHT_DYNSYM = 11; enum SHT_INIT_ARRAY = 14; enum SHT_FINI_ARRAY = 15; enum SHT_PREINIT_ARRAY = 16; enum SHT_GROUP = 17; enum SHT_SYMTAB_SHNDX = 18; enum SHT_NUM = 19; enum SHT_LOOS = 0x60000000; enum SHT_GNU_ATTRIBUTES = 0x6ffffff5; enum SHT_GNU_HASH = 0x6ffffff6; enum SHT_GNU_LIBLIST = 0x6ffffff7; enum SHT_CHECKSUM = 0x6ffffff8; enum SHT_LOSUNW = 0x6ffffffa; enum SHT_SUNW_move = 0x6ffffffa; enum SHT_SUNW_COMDAT = 0x6ffffffb; enum SHT_SUNW_syminfo = 0x6ffffffc; enum SHT_GNU_verdef = 0x6ffffffd; enum SHT_GNU_verneed = 0x6ffffffe; enum SHT_GNU_versym = 0x6fffffff; enum SHT_HISUNW = 0x6fffffff; enum SHT_HIOS = 0x6fffffff; enum SHT_LOPROC = 0x70000000; enum SHT_HIPROC = 0x7fffffff; enum SHT_LOUSER = 0x80000000; enum SHT_HIUSER = 0x8fffffff; enum SHF_WRITE = (1 << 0); enum SHF_ALLOC = (1 << 1); enum SHF_EXECINSTR = (1 << 2); enum SHF_MERGE = (1 << 4); enum SHF_STRINGS = (1 << 5); enum SHF_INFO_LINK = (1 << 6); enum SHF_LINK_ORDER = (1 << 7); enum SHF_OS_NONCONFORMING = (1 << 8); enum SHF_GROUP = (1 << 9); enum SHF_TLS = (1 << 10); enum SHF_MASKOS = 0x0ff00000; enum SHF_MASKPROC = 0xf0000000; enum SHF_ORDERED = (1 << 30); enum SHF_EXCLUDE = (1 << 31); enum GRP_COMDAT = 0x1; struct Elf32_Sym { Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; ubyte st_info; ubyte st_other; Elf32_Section st_shndx; } struct Elf64_Sym { Elf64_Word st_name; ubyte st_info; ubyte st_other; Elf64_Section st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } struct Elf32_Syminfo { Elf32_Half si_boundto; Elf32_Half si_flags; } struct Elf64_Syminfo { Elf64_Half si_boundto; Elf64_Half si_flags; } enum SYMINFO_BT_SELF = 0xffff; enum SYMINFO_BT_PARENT = 0xfffe; enum SYMINFO_BT_LOWRESERVE = 0xff00; enum SYMINFO_FLG_DIRECT = 0x0001; enum SYMINFO_FLG_PASSTHRU = 0x0002; enum SYMINFO_FLG_COPY = 0x0004; enum SYMINFO_FLG_LAZYLOAD = 0x0008; enum SYMINFO_NONE = 0; enum SYMINFO_CURRENT = 1; enum SYMINFO_NUM = 2; extern (D) { auto ELF32_ST_BIND(T)(T val) { return cast(ubyte)val >> 4; } auto ELF32_ST_TYPE(T)(T val) { return val & 0xf; } auto ELF32_ST_INFO(B, T)(B bind, T type) { return (bind << 4) + (type & 0xf); } alias ELF32_ST_BIND ELF64_ST_BIND; alias ELF32_ST_TYPE ELF64_ST_TYPE; alias ELF32_ST_INFO ELF64_ST_INFO; } enum STB_LOCAL = 0; enum STB_GLOBAL = 1; enum STB_WEAK = 2; enum STB_NUM = 3; enum STB_LOOS = 10; enum STB_GNU_UNIQUE = 10; enum STB_HIOS = 12; enum STB_LOPROC = 13; enum STB_HIPROC = 15; enum STT_NOTYPE = 0; enum STT_OBJECT = 1; enum STT_FUNC = 2; enum STT_SECTION = 3; enum STT_FILE = 4; enum STT_COMMON = 5; enum STT_TLS = 6; enum STT_NUM = 7; enum STT_LOOS = 10; enum STT_GNU_IFUNC = 10; enum STT_HIOS = 12; enum STT_LOPROC = 13; enum STT_HIPROC = 15; enum STN_UNDEF = 0; extern (D) { auto ELF32_ST_VISIBILITY(O)(O o) { return o & 0x03; } alias ELF32_ST_VISIBILITY ELF64_ST_VISIBILITY; } enum STV_DEFAULT = 0; enum STV_INTERNAL = 1; enum STV_HIDDEN = 2; enum STV_PROTECTED = 3; struct Elf32_Rel { Elf32_Addr r_offset; Elf32_Word r_info; } struct Elf64_Rel { Elf64_Addr r_offset; Elf64_Xword r_info; } struct Elf32_Rela { Elf32_Addr r_offset; Elf32_Word r_info; Elf32_Sword r_addend; } struct Elf64_Rela { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } extern (D) { auto ELF32_R_SYM(V)(V val) { return val >> 8; } auto ELF32_R_TYPE(V)(V val) { return val & 0xff; } auto ELF32_R_INFO(S, T)(S sym, T type) { return (sym << 8) + (type & 0xff); } auto ELF64_R_SYM(I)(I i) { return i >> 32; } auto ELF64_R_TYPE(I)(I i) { return i & 0xffffffff; } auto ELF64_R_INFO(S, T)(S sym, T type) { return (sym << 32) + (type); } } struct Elf32_Phdr { Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; } struct Elf64_Phdr { Elf64_Word p_type; Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align; } enum PN_XNUM = 0xffff; enum PT_NULL = 0; enum PT_LOAD = 1; enum PT_DYNAMIC = 2; enum PT_INTERP = 3; enum PT_NOTE = 4; enum PT_SHLIB = 5; enum PT_PHDR = 6; enum PT_TLS = 7; enum PT_NUM = 8; enum PT_LOOS = 0x60000000; enum PT_GNU_EH_FRAME = 0x6474e550; enum PT_GNU_STACK = 0x6474e551; enum PT_GNU_RELRO = 0x6474e552; enum PT_LOSUNW = 0x6ffffffa; enum PT_SUNWBSS = 0x6ffffffa; enum PT_SUNWSTACK = 0x6ffffffb; enum PT_HISUNW = 0x6fffffff; enum PT_HIOS = 0x6fffffff; enum PT_LOPROC = 0x70000000; enum PT_HIPROC = 0x7fffffff; enum PF_X = (1 << 0); enum PF_W = (1 << 1); enum PF_R = (1 << 2); enum PF_MASKOS = 0x0ff00000; enum PF_MASKPROC = 0xf0000000; enum NT_PRSTATUS = 1; enum NT_FPREGSET = 2; enum NT_PRPSINFO = 3; enum NT_PRXREG = 4; enum NT_TASKSTRUCT = 4; enum NT_PLATFORM = 5; enum NT_AUXV = 6; enum NT_GWINDOWS = 7; enum NT_ASRS = 8; enum NT_PSTATUS = 10; enum NT_PSINFO = 13; enum NT_PRCRED = 14; enum NT_UTSNAME = 15; enum NT_LWPSTATUS = 16; enum NT_LWPSINFO = 17; enum NT_PRFPXREG = 20; enum NT_SIGINFO = 0x53494749; enum NT_FILE = 0x46494c45; enum NT_PRXFPREG = 0x46e62b7f; enum NT_PPC_VMX = 0x100; enum NT_PPC_SPE = 0x101; enum NT_PPC_VSX = 0x102; enum NT_386_TLS = 0x200; enum NT_386_IOPERM = 0x201; enum NT_X86_XSTATE = 0x202; enum NT_S390_HIGH_GPRS = 0x300; enum NT_S390_TIMER = 0x301; enum NT_S390_TODCMP = 0x302; enum NT_S390_TODPREG = 0x303; enum NT_S390_CTRS = 0x304; enum NT_S390_PREFIX = 0x305; enum NT_S390_LAST_BREAK = 0x306; enum NT_S390_SYSTEM_CALL = 0x307; enum NT_S390_TDB = 0x308; enum NT_ARM_VFP = 0x400; enum NT_ARM_TLS = 0x401; enum NT_ARM_HW_BREAK = 0x402; enum NT_ARM_HW_WATCH = 0x403; enum NT_VERSION = 1; struct Elf32_Dyn { Elf32_Sword d_tag; union _d_un { Elf32_Word d_val; Elf32_Addr d_ptr; } _d_un d_un; } struct Elf64_Dyn { Elf64_Sxword d_tag; union _d_un { Elf64_Xword d_val; Elf64_Addr d_ptr; } _d_un d_un; } enum DT_NULL = 0; enum DT_NEEDED = 1; enum DT_PLTRELSZ = 2; enum DT_PLTGOT = 3; enum DT_HASH = 4; enum DT_STRTAB = 5; enum DT_SYMTAB = 6; enum DT_RELA = 7; enum DT_RELASZ = 8; enum DT_RELAENT = 9; enum DT_STRSZ = 10; enum DT_SYMENT = 11; enum DT_INIT = 12; enum DT_FINI = 13; enum DT_SONAME = 14; enum DT_RPATH = 15; enum DT_SYMBOLIC = 16; enum DT_REL = 17; enum DT_RELSZ = 18; enum DT_RELENT = 19; enum DT_PLTREL = 20; enum DT_DEBUG = 21; enum DT_TEXTREL = 22; enum DT_JMPREL = 23; enum DT_BIND_NOW = 24; enum DT_INIT_ARRAY = 25; enum DT_FINI_ARRAY = 26; enum DT_INIT_ARRAYSZ = 27; enum DT_FINI_ARRAYSZ = 28; enum DT_RUNPATH = 29; enum DT_FLAGS = 30; enum DT_ENCODING = 32; enum DT_PREINIT_ARRAY = 32; enum DT_PREINIT_ARRAYSZ = 33; enum DT_NUM = 34; enum DT_LOOS = 0x6000000d; enum DT_HIOS = 0x6ffff000; enum DT_LOPROC = 0x70000000; enum DT_HIPROC = 0x7fffffff; enum DT_PROCNUM = DT_MIPS_NUM; enum DT_VALRNGLO = 0x6ffffd00; enum DT_GNU_PRELINKED = 0x6ffffdf5; enum DT_GNU_CONFLICTSZ = 0x6ffffdf6; enum DT_GNU_LIBLISTSZ = 0x6ffffdf7; enum DT_CHECKSUM = 0x6ffffdf8; enum DT_PLTPADSZ = 0x6ffffdf9; enum DT_MOVEENT = 0x6ffffdfa; enum DT_MOVESZ = 0x6ffffdfb; enum DT_FEATURE_1 = 0x6ffffdfc; enum DT_POSFLAG_1 = 0x6ffffdfd; enum DT_SYMINSZ = 0x6ffffdfe; enum DT_SYMINENT = 0x6ffffdff; enum DT_VALRNGHI = 0x6ffffdff; extern (D) auto DT_VALTAGIDX(T)(T tag) { return DT_VALRNGHI - tag; } enum DT_VALNUM = 12; enum DT_ADDRRNGLO = 0x6ffffe00; enum DT_GNU_HASH = 0x6ffffef5; enum DT_TLSDESC_PLT = 0x6ffffef6; enum DT_TLSDESC_GOT = 0x6ffffef7; enum DT_GNU_CONFLICT = 0x6ffffef8; enum DT_GNU_LIBLIST = 0x6ffffef9; enum DT_CONFIG = 0x6ffffefa; enum DT_DEPAUDIT = 0x6ffffefb; enum DT_AUDIT = 0x6ffffefc; enum DT_PLTPAD = 0x6ffffefd; enum DT_MOVETAB = 0x6ffffefe; enum DT_SYMINFO = 0x6ffffeff; enum DT_ADDRRNGHI = 0x6ffffeff; extern (D) auto DT_ADDRTAGIDX(T)(T tag) { return DT_ADDRRNGHI - tag; } enum DT_ADDRNUM = 11; enum DT_VERSYM = 0x6ffffff0; enum DT_RELACOUNT = 0x6ffffff9; enum DT_RELCOUNT = 0x6ffffffa; enum DT_FLAGS_1 = 0x6ffffffb; enum DT_VERDEF = 0x6ffffffc; enum DT_VERDEFNUM = 0x6ffffffd; enum DT_VERNEED = 0x6ffffffe; enum DT_VERNEEDNUM = 0x6fffffff; extern (D) auto DT_VERSIONTAGIDX(T)(T tag) { return DT_VERNEEDNUM - tag; } enum DT_VERSIONTAGNUM = 16; enum DT_AUXILIARY = 0x7ffffffd; enum DT_FILTER = 0x7fffffff; extern (D) auto DT_EXTRATAGIDX(T)(T tag) { return cast(Elf32_Word)(-(cast(Elf32_Sword)(tag) <<1>>1)-1); } enum DT_EXTRANUM = 3; enum DF_ORIGIN = 0x00000001; enum DF_SYMBOLIC = 0x00000002; enum DF_TEXTREL = 0x00000004; enum DF_BIND_NOW = 0x00000008; enum DF_STATIC_TLS = 0x00000010; enum DF_1_NOW = 0x00000001; enum DF_1_GLOBAL = 0x00000002; enum DF_1_GROUP = 0x00000004; enum DF_1_NODELETE = 0x00000008; enum DF_1_LOADFLTR = 0x00000010; enum DF_1_INITFIRST = 0x00000020; enum DF_1_NOOPEN = 0x00000040; enum DF_1_ORIGIN = 0x00000080; enum DF_1_DIRECT = 0x00000100; enum DF_1_TRANS = 0x00000200; enum DF_1_INTERPOSE = 0x00000400; enum DF_1_NODEFLIB = 0x00000800; enum DF_1_NODUMP = 0x00001000; enum DF_1_CONFALT = 0x00002000; enum DF_1_ENDFILTEE = 0x00004000; enum DF_1_DISPRELDNE = 0x00008000; enum DF_1_DISPRELPND = 0x00010000; enum DF_1_NODIRECT = 0x00020000; enum DF_1_IGNMULDEF = 0x00040000; enum DF_1_NOKSYMS = 0x00080000; enum DF_1_NOHDR = 0x00100000; enum DF_1_EDITED = 0x00200000; enum DF_1_NORELOC = 0x00400000; enum DF_1_SYMINTPOSE = 0x00800000; enum DF_1_GLOBAUDIT = 0x01000000; enum DF_1_SINGLETON = 0x02000000; enum DTF_1_PARINIT = 0x00000001; enum DTF_1_CONFEXP = 0x00000002; enum DF_P1_LAZYLOAD = 0x00000001; enum DF_P1_GROUPPERM = 0x00000002; struct Elf32_Verdef { Elf32_Half vd_version; Elf32_Half vd_flags; Elf32_Half vd_ndx; Elf32_Half vd_cnt; Elf32_Word vd_hash; Elf32_Word vd_aux; Elf32_Word vd_next; } struct Elf64_Verdef { Elf64_Half vd_version; Elf64_Half vd_flags; Elf64_Half vd_ndx; Elf64_Half vd_cnt; Elf64_Word vd_hash; Elf64_Word vd_aux; Elf64_Word vd_next; } enum VER_DEF_NONE = 0; enum VER_DEF_CURRENT = 1; enum VER_DEF_NUM = 2; enum VER_FLG_BASE = 0x1; enum VER_FLG_WEAK = 0x2; enum VER_NDX_LOCAL = 0; enum VER_NDX_GLOBAL = 1; enum VER_NDX_LORESERVE = 0xff00; enum VER_NDX_ELIMINATE = 0xff01; struct Elf32_Verdaux { Elf32_Word vda_name; Elf32_Word vda_next; } struct Elf64_Verdaux { Elf64_Word vda_name; Elf64_Word vda_next; } struct Elf32_Verneed { Elf32_Half vn_version; Elf32_Half vn_cnt; Elf32_Word vn_file; Elf32_Word vn_aux; Elf32_Word vn_next; } struct Elf64_Verneed { Elf64_Half vn_version; Elf64_Half vn_cnt; Elf64_Word vn_file; Elf64_Word vn_aux; Elf64_Word vn_next; } enum VER_NEED_NONE = 0; enum VER_NEED_CURRENT = 1; enum VER_NEED_NUM = 2; struct Elf32_Vernaux { Elf32_Word vna_hash; Elf32_Half vna_flags; Elf32_Half vna_other; Elf32_Word vna_name; Elf32_Word vna_next; } struct Elf64_Vernaux { Elf64_Word vna_hash; Elf64_Half vna_flags; Elf64_Half vna_other; Elf64_Word vna_name; Elf64_Word vna_next; } // duplicate // enum VER_FLG_WEAK = 0x2; struct Elf32_auxv_t { uint32_t a_type; union _a_un { uint32_t a_val; } _a_un a_un; } struct Elf64_auxv_t { uint64_t a_type; union _a_un { uint64_t a_val; } _a_un a_un; } enum AT_NULL = 0; enum AT_IGNORE = 1; enum AT_EXECFD = 2; enum AT_PHDR = 3; enum AT_PHENT = 4; enum AT_PHNUM = 5; enum AT_PAGESZ = 6; enum AT_BASE = 7; enum AT_FLAGS = 8; enum AT_ENTRY = 9; enum AT_NOTELF = 10; enum AT_UID = 11; enum AT_EUID = 12; enum AT_GID = 13; enum AT_EGID = 14; enum AT_CLKTCK = 17; enum AT_PLATFORM = 15; enum AT_HWCAP = 16; enum AT_FPUCW = 18; enum AT_DCACHEBSIZE = 19; enum AT_ICACHEBSIZE = 20; enum AT_UCACHEBSIZE = 21; enum AT_IGNOREPPC = 22; enum AT_SECURE = 23; enum AT_BASE_PLATFORM = 24; enum AT_RANDOM = 25; enum AT_HWCAP2 = 26; enum AT_EXECFN = 31; enum AT_SYSINFO = 32; enum AT_SYSINFO_EHDR = 33; ; enum AT_L1I_CACHESHAPE = 34; enum AT_L1D_CACHESHAPE = 35; enum AT_L2_CACHESHAPE = 36; enum AT_L3_CACHESHAPE = 37; struct Elf32_Nhdr { Elf32_Word n_namesz; Elf32_Word n_descsz; Elf32_Word n_type; } struct Elf64_Nhdr { Elf64_Word n_namesz; Elf64_Word n_descsz; Elf64_Word n_type; } enum ELF_NOTE_SOLARIS = "SUNW Solaris"; enum ELF_NOTE_GNU = "GNU"; enum ELF_NOTE_PAGESIZE_HINT = 1; enum NT_GNU_ABI_TAG = 1; enum ELF_NOTE_ABI = NT_GNU_ABI_TAG; enum ELF_NOTE_OS_LINUX = 0; enum ELF_NOTE_OS_GNU = 1; enum ELF_NOTE_OS_SOLARIS2 = 2; enum ELF_NOTE_OS_FREEBSD = 3; enum NT_GNU_HWCAP = 2; enum NT_GNU_BUILD_ID = 3; enum NT_GNU_GOLD_VERSION = 4; struct Elf32_Move { Elf32_Xword m_value; Elf32_Word m_info; Elf32_Word m_poffset; Elf32_Half m_repeat; Elf32_Half m_stride; } struct Elf64_Move { Elf64_Xword m_value; Elf64_Xword m_info; Elf64_Xword m_poffset; Elf64_Half m_repeat; Elf64_Half m_stride; } extern (D) { auto ELF32_M_SYM(I)(I info) { return info >> 8; } auto ELF32_M_SIZE(I)(I info) { return cast(ubyte)info; } auto ELF32_M_INFO(S, SZ)(S sym, SZ size) { return (sym << 8) + cast(ubyte)size; } } alias ELF32_M_SYM ELF64_M_SYM; alias ELF32_M_SIZE ELF64_M_SIZE; alias ELF32_M_INFO ELF64_M_INFO; enum EF_CPU32 = 0x00810000; enum R_68K_NONE = 0; enum R_68K_32 = 1; enum R_68K_16 = 2; enum R_68K_8 = 3; enum R_68K_PC32 = 4; enum R_68K_PC16 = 5; enum R_68K_PC8 = 6; enum R_68K_GOT32 = 7; enum R_68K_GOT16 = 8; enum R_68K_GOT8 = 9; enum R_68K_GOT32O = 10; enum R_68K_GOT16O = 11; enum R_68K_GOT8O = 12; enum R_68K_PLT32 = 13; enum R_68K_PLT16 = 14; enum R_68K_PLT8 = 15; enum R_68K_PLT32O = 16; enum R_68K_PLT16O = 17; enum R_68K_PLT8O = 18; enum R_68K_COPY = 19; enum R_68K_GLOB_DAT = 20; enum R_68K_JMP_SLOT = 21; enum R_68K_RELATIVE = 22; enum R_68K_TLS_GD32 = 25; enum R_68K_TLS_GD16 = 26; enum R_68K_TLS_GD8 = 27; enum R_68K_TLS_LDM32 = 28; enum R_68K_TLS_LDM16 = 29; enum R_68K_TLS_LDM8 = 30; enum R_68K_TLS_LDO32 = 31; enum R_68K_TLS_LDO16 = 32; enum R_68K_TLS_LDO8 = 33; enum R_68K_TLS_IE32 = 34; enum R_68K_TLS_IE16 = 35; enum R_68K_TLS_IE8 = 36; enum R_68K_TLS_LE32 = 37; enum R_68K_TLS_LE16 = 38; enum R_68K_TLS_LE8 = 39; enum R_68K_TLS_DTPMOD32 = 40; enum R_68K_TLS_DTPREL32 = 41; enum R_68K_TLS_TPREL32 = 42; enum R_68K_NUM = 43; enum R_386_NONE = 0; enum R_386_32 = 1; enum R_386_PC32 = 2; enum R_386_GOT32 = 3; enum R_386_PLT32 = 4; enum R_386_COPY = 5; enum R_386_GLOB_DAT = 6; enum R_386_JMP_SLOT = 7; enum R_386_RELATIVE = 8; enum R_386_GOTOFF = 9; enum R_386_GOTPC = 10; enum R_386_32PLT = 11; enum R_386_TLS_TPOFF = 14; enum R_386_TLS_IE = 15; enum R_386_TLS_GOTIE = 16; enum R_386_TLS_LE = 17; enum R_386_TLS_GD = 18; enum R_386_TLS_LDM = 19; enum R_386_16 = 20; enum R_386_PC16 = 21; enum R_386_8 = 22; enum R_386_PC8 = 23; enum R_386_TLS_GD_32 = 24; enum R_386_TLS_GD_PUSH = 25; enum R_386_TLS_GD_CALL = 26; enum R_386_TLS_GD_POP = 27; enum R_386_TLS_LDM_32 = 28; enum R_386_TLS_LDM_PUSH = 29; enum R_386_TLS_LDM_CALL = 30; enum R_386_TLS_LDM_POP = 31; enum R_386_TLS_LDO_32 = 32; enum R_386_TLS_IE_32 = 33; enum R_386_TLS_LE_32 = 34; enum R_386_TLS_DTPMOD32 = 35; enum R_386_TLS_DTPOFF32 = 36; enum R_386_TLS_TPOFF32 = 37; enum R_386_SIZE32 = 38; enum R_386_TLS_GOTDESC = 39; enum R_386_TLS_DESC_CALL = 40; enum R_386_TLS_DESC = 41; enum R_386_IRELATIVE = 42; enum R_386_NUM = 43; enum STT_SPARC_REGISTER = 13; enum EF_SPARCV9_MM = 3; enum EF_SPARCV9_TSO = 0; enum EF_SPARCV9_PSO = 1; enum EF_SPARCV9_RMO = 2; enum EF_SPARC_LEDATA = 0x800000; enum EF_SPARC_EXT_MASK = 0xFFFF00; enum EF_SPARC_32PLUS = 0x000100; enum EF_SPARC_SUN_US1 = 0x000200; enum EF_SPARC_HAL_R1 = 0x000400; enum EF_SPARC_SUN_US3 = 0x000800; enum R_SPARC_NONE = 0; enum R_SPARC_8 = 1; enum R_SPARC_16 = 2; enum R_SPARC_32 = 3; enum R_SPARC_DISP8 = 4; enum R_SPARC_DISP16 = 5; enum R_SPARC_DISP32 = 6; enum R_SPARC_WDISP30 = 7; enum R_SPARC_WDISP22 = 8; enum R_SPARC_HI22 = 9; enum R_SPARC_22 = 10; enum R_SPARC_13 = 11; enum R_SPARC_LO10 = 12; enum R_SPARC_GOT10 = 13; enum R_SPARC_GOT13 = 14; enum R_SPARC_GOT22 = 15; enum R_SPARC_PC10 = 16; enum R_SPARC_PC22 = 17; enum R_SPARC_WPLT30 = 18; enum R_SPARC_COPY = 19; enum R_SPARC_GLOB_DAT = 20; enum R_SPARC_JMP_SLOT = 21; enum R_SPARC_RELATIVE = 22; enum R_SPARC_UA32 = 23; enum R_SPARC_PLT32 = 24; enum R_SPARC_HIPLT22 = 25; enum R_SPARC_LOPLT10 = 26; enum R_SPARC_PCPLT32 = 27; enum R_SPARC_PCPLT22 = 28; enum R_SPARC_PCPLT10 = 29; enum R_SPARC_10 = 30; enum R_SPARC_11 = 31; enum R_SPARC_64 = 32; enum R_SPARC_OLO10 = 33; enum R_SPARC_HH22 = 34; enum R_SPARC_HM10 = 35; enum R_SPARC_LM22 = 36; enum R_SPARC_PC_HH22 = 37; enum R_SPARC_PC_HM10 = 38; enum R_SPARC_PC_LM22 = 39; enum R_SPARC_WDISP16 = 40; enum R_SPARC_WDISP19 = 41; enum R_SPARC_GLOB_JMP = 42; enum R_SPARC_7 = 43; enum R_SPARC_5 = 44; enum R_SPARC_6 = 45; enum R_SPARC_DISP64 = 46; enum R_SPARC_PLT64 = 47; enum R_SPARC_HIX22 = 48; enum R_SPARC_LOX10 = 49; enum R_SPARC_H44 = 50; enum R_SPARC_M44 = 51; enum R_SPARC_L44 = 52; enum R_SPARC_REGISTER = 53; enum R_SPARC_UA64 = 54; enum R_SPARC_UA16 = 55; enum R_SPARC_TLS_GD_HI22 = 56; enum R_SPARC_TLS_GD_LO10 = 57; enum R_SPARC_TLS_GD_ADD = 58; enum R_SPARC_TLS_GD_CALL = 59; enum R_SPARC_TLS_LDM_HI22 = 60; enum R_SPARC_TLS_LDM_LO10 = 61; enum R_SPARC_TLS_LDM_ADD = 62; enum R_SPARC_TLS_LDM_CALL = 63; enum R_SPARC_TLS_LDO_HIX22 = 64; enum R_SPARC_TLS_LDO_LOX10 = 65; enum R_SPARC_TLS_LDO_ADD = 66; enum R_SPARC_TLS_IE_HI22 = 67; enum R_SPARC_TLS_IE_LO10 = 68; enum R_SPARC_TLS_IE_LD = 69; enum R_SPARC_TLS_IE_LDX = 70; enum R_SPARC_TLS_IE_ADD = 71; enum R_SPARC_TLS_LE_HIX22 = 72; enum R_SPARC_TLS_LE_LOX10 = 73; enum R_SPARC_TLS_DTPMOD32 = 74; enum R_SPARC_TLS_DTPMOD64 = 75; enum R_SPARC_TLS_DTPOFF32 = 76; enum R_SPARC_TLS_DTPOFF64 = 77; enum R_SPARC_TLS_TPOFF32 = 78; enum R_SPARC_TLS_TPOFF64 = 79; enum R_SPARC_GOTDATA_HIX22 = 80; enum R_SPARC_GOTDATA_LOX10 = 81; enum R_SPARC_GOTDATA_OP_HIX22 = 82; enum R_SPARC_GOTDATA_OP_LOX10 = 83; enum R_SPARC_GOTDATA_OP = 84; enum R_SPARC_H34 = 85; enum R_SPARC_SIZE32 = 86; enum R_SPARC_SIZE64 = 87; enum R_SPARC_WDISP10 = 88; enum R_SPARC_JMP_IREL = 248; enum R_SPARC_IRELATIVE = 249; enum R_SPARC_GNU_VTINHERIT = 250; enum R_SPARC_GNU_VTENTRY = 251; enum R_SPARC_REV32 = 252; enum R_SPARC_NUM = 253; enum DT_SPARC_REGISTER = 0x70000001; enum DT_SPARC_NUM = 2; enum EF_MIPS_NOREORDER = 1; enum EF_MIPS_PIC = 2; enum EF_MIPS_CPIC = 4; enum EF_MIPS_XGOT = 8; enum EF_MIPS_64BIT_WHIRL = 16; enum EF_MIPS_ABI2 = 32; enum EF_MIPS_ABI_ON32 = 64; enum EF_MIPS_ARCH = 0xf0000000; enum EF_MIPS_ARCH_1 = 0x00000000; enum EF_MIPS_ARCH_2 = 0x10000000; enum EF_MIPS_ARCH_3 = 0x20000000; enum EF_MIPS_ARCH_4 = 0x30000000; enum EF_MIPS_ARCH_5 = 0x40000000; enum EF_MIPS_ARCH_32 = 0x50000000; enum EF_MIPS_ARCH_64 = 0x60000000; enum EF_MIPS_ARCH_32R2 = 0x70000000; enum EF_MIPS_ARCH_64R2 = 0x80000000; enum E_MIPS_ARCH_1 = EF_MIPS_ARCH_1; enum E_MIPS_ARCH_2 = EF_MIPS_ARCH_2; enum E_MIPS_ARCH_3 = EF_MIPS_ARCH_3; enum E_MIPS_ARCH_4 = EF_MIPS_ARCH_4; enum E_MIPS_ARCH_5 = EF_MIPS_ARCH_5; enum E_MIPS_ARCH_32 = EF_MIPS_ARCH_32; enum E_MIPS_ARCH_64 = EF_MIPS_ARCH_64; enum SHN_MIPS_ACOMMON = 0xff00; enum SHN_MIPS_TEXT = 0xff01; enum SHN_MIPS_DATA = 0xff02; enum SHN_MIPS_SCOMMON = 0xff03; enum SHN_MIPS_SUNDEFINED = 0xff04; enum SHT_MIPS_LIBLIST = 0x70000000; enum SHT_MIPS_MSYM = 0x70000001; enum SHT_MIPS_CONFLICT = 0x70000002; enum SHT_MIPS_GPTAB = 0x70000003; enum SHT_MIPS_UCODE = 0x70000004; enum SHT_MIPS_DEBUG = 0x70000005; enum SHT_MIPS_REGINFO = 0x70000006; enum SHT_MIPS_PACKAGE = 0x70000007; enum SHT_MIPS_PACKSYM = 0x70000008; enum SHT_MIPS_RELD = 0x70000009; enum SHT_MIPS_IFACE = 0x7000000b; enum SHT_MIPS_CONTENT = 0x7000000c; enum SHT_MIPS_OPTIONS = 0x7000000d; enum SHT_MIPS_SHDR = 0x70000010; enum SHT_MIPS_FDESC = 0x70000011; enum SHT_MIPS_EXTSYM = 0x70000012; enum SHT_MIPS_DENSE = 0x70000013; enum SHT_MIPS_PDESC = 0x70000014; enum SHT_MIPS_LOCSYM = 0x70000015; enum SHT_MIPS_AUXSYM = 0x70000016; enum SHT_MIPS_OPTSYM = 0x70000017; enum SHT_MIPS_LOCSTR = 0x70000018; enum SHT_MIPS_LINE = 0x70000019; enum SHT_MIPS_RFDESC = 0x7000001a; enum SHT_MIPS_DELTASYM = 0x7000001b; enum SHT_MIPS_DELTAINST = 0x7000001c; enum SHT_MIPS_DELTACLASS = 0x7000001d; enum SHT_MIPS_DWARF = 0x7000001e; enum SHT_MIPS_DELTADECL = 0x7000001f; enum SHT_MIPS_SYMBOL_LIB = 0x70000020; enum SHT_MIPS_EVENTS = 0x70000021; enum SHT_MIPS_TRANSLATE = 0x70000022; enum SHT_MIPS_PIXIE = 0x70000023; enum SHT_MIPS_XLATE = 0x70000024; enum SHT_MIPS_XLATE_DEBUG = 0x70000025; enum SHT_MIPS_WHIRL = 0x70000026; enum SHT_MIPS_EH_REGION = 0x70000027; enum SHT_MIPS_XLATE_OLD = 0x70000028; enum SHT_MIPS_PDR_EXCEPTION = 0x70000029; enum SHF_MIPS_GPREL = 0x10000000; enum SHF_MIPS_MERGE = 0x20000000; enum SHF_MIPS_ADDR = 0x40000000; enum SHF_MIPS_STRINGS = 0x80000000; enum SHF_MIPS_NOSTRIP = 0x08000000; enum SHF_MIPS_LOCAL = 0x04000000; enum SHF_MIPS_NAMES = 0x02000000; enum SHF_MIPS_NODUPE = 0x01000000; enum STO_MIPS_DEFAULT = 0x0; enum STO_MIPS_INTERNAL = 0x1; enum STO_MIPS_HIDDEN = 0x2; enum STO_MIPS_PROTECTED = 0x3; enum STO_MIPS_PLT = 0x8; enum STO_MIPS_SC_ALIGN_UNUSED = 0xff; enum STB_MIPS_SPLIT_COMMON = 13; union Elf32_gptab { struct _gt_header { Elf32_Word gt_current_g_value; Elf32_Word gt_unused; } _gt_header gt_header; struct _gt_entry { Elf32_Word gt_g_value; Elf32_Word gt_bytes; } _gt_entry gt_entry; } struct Elf32_RegInfo { Elf32_Word ri_gprmask; Elf32_Word[4] ri_cprmask; Elf32_Sword ri_gp_value; } struct Elf_Options { ubyte kind; ubyte size; Elf32_Section section; Elf32_Word info; } enum ODK_NULL = 0; enum ODK_REGINFO = 1; enum ODK_EXCEPTIONS = 2; enum ODK_PAD = 3; enum ODK_HWPATCH = 4; enum ODK_FILL = 5; enum ODK_TAGS = 6; enum ODK_HWAND = 7; enum ODK_HWOR = 8; enum OEX_FPU_MIN = 0x1f; enum OEX_FPU_MAX = 0x1f00; enum OEX_PAGE0 = 0x10000; enum OEX_SMM = 0x20000; enum OEX_FPDBUG = 0x40000; enum OEX_PRECISEFP = OEX_FPDBUG; enum OEX_DISMISS = 0x80000; enum OEX_FPU_INVAL = 0x10; enum OEX_FPU_DIV0 = 0x08; enum OEX_FPU_OFLO = 0x04; enum OEX_FPU_UFLO = 0x02; enum OEX_FPU_INEX = 0x01; enum OHW_R4KEOP = 0x1; enum OHW_R8KPFETCH = 0x2; enum OHW_R5KEOP = 0x4; enum OHW_R5KCVTL = 0x8; enum OPAD_PREFIX = 0x1; enum OPAD_POSTFIX = 0x2; enum OPAD_SYMBOL = 0x4; struct Elf_Options_Hw { Elf32_Word hwp_flags1; Elf32_Word hwp_flags2; } enum OHWA0_R4KEOP_CHECKED = 0x00000001; enum OHWA1_R4KEOP_CLEAN = 0x00000002; enum R_MIPS_NONE = 0; enum R_MIPS_16 = 1; enum R_MIPS_32 = 2; enum R_MIPS_REL32 = 3; enum R_MIPS_26 = 4; enum R_MIPS_HI16 = 5; enum R_MIPS_LO16 = 6; enum R_MIPS_GPREL16 = 7; enum R_MIPS_LITERAL = 8; enum R_MIPS_GOT16 = 9; enum R_MIPS_PC16 = 10; enum R_MIPS_CALL16 = 11; enum R_MIPS_GPREL32 = 12; enum R_MIPS_SHIFT5 = 16; enum R_MIPS_SHIFT6 = 17; enum R_MIPS_64 = 18; enum R_MIPS_GOT_DISP = 19; enum R_MIPS_GOT_PAGE = 20; enum R_MIPS_GOT_OFST = 21; enum R_MIPS_GOT_HI16 = 22; enum R_MIPS_GOT_LO16 = 23; enum R_MIPS_SUB = 24; enum R_MIPS_INSERT_A = 25; enum R_MIPS_INSERT_B = 26; enum R_MIPS_DELETE = 27; enum R_MIPS_HIGHER = 28; enum R_MIPS_HIGHEST = 29; enum R_MIPS_CALL_HI16 = 30; enum R_MIPS_CALL_LO16 = 31; enum R_MIPS_SCN_DISP = 32; enum R_MIPS_REL16 = 33; enum R_MIPS_ADD_IMMEDIATE = 34; enum R_MIPS_PJUMP = 35; enum R_MIPS_RELGOT = 36; enum R_MIPS_JALR = 37; enum R_MIPS_TLS_DTPMOD32 = 38; enum R_MIPS_TLS_DTPREL32 = 39; enum R_MIPS_TLS_DTPMOD64 = 40; enum R_MIPS_TLS_DTPREL64 = 41; enum R_MIPS_TLS_GD = 42; enum R_MIPS_TLS_LDM = 43; enum R_MIPS_TLS_DTPREL_HI16 = 44; enum R_MIPS_TLS_DTPREL_LO16 = 45; enum R_MIPS_TLS_GOTTPREL = 46; enum R_MIPS_TLS_TPREL32 = 47; enum R_MIPS_TLS_TPREL64 = 48; enum R_MIPS_TLS_TPREL_HI16 = 49; enum R_MIPS_TLS_TPREL_LO16 = 50; enum R_MIPS_GLOB_DAT = 51; enum R_MIPS_COPY = 126; enum R_MIPS_JUMP_SLOT = 127; enum R_MIPS_NUM = 128; enum PT_MIPS_REGINFO = 0x70000000; enum PT_MIPS_RTPROC = 0x70000001; enum PT_MIPS_OPTIONS = 0x70000002; enum PF_MIPS_LOCAL = 0x10000000; enum DT_MIPS_RLD_VERSION = 0x70000001; enum DT_MIPS_TIME_STAMP = 0x70000002; enum DT_MIPS_ICHECKSUM = 0x70000003; enum DT_MIPS_IVERSION = 0x70000004; enum DT_MIPS_FLAGS = 0x70000005; enum DT_MIPS_BASE_ADDRESS = 0x70000006; enum DT_MIPS_MSYM = 0x70000007; enum DT_MIPS_CONFLICT = 0x70000008; enum DT_MIPS_LIBLIST = 0x70000009; enum DT_MIPS_LOCAL_GOTNO = 0x7000000a; enum DT_MIPS_CONFLICTNO = 0x7000000b; enum DT_MIPS_LIBLISTNO = 0x70000010; enum DT_MIPS_SYMTABNO = 0x70000011; enum DT_MIPS_UNREFEXTNO = 0x70000012; enum DT_MIPS_GOTSYM = 0x70000013; enum DT_MIPS_HIPAGENO = 0x70000014; enum DT_MIPS_RLD_MAP = 0x70000016; enum DT_MIPS_DELTA_CLASS = 0x70000017; enum DT_MIPS_DELTA_CLASS_NO = 0x70000018; enum DT_MIPS_DELTA_INSTANCE = 0x70000019; enum DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a; enum DT_MIPS_DELTA_RELOC = 0x7000001b; enum DT_MIPS_DELTA_RELOC_NO = 0x7000001c; enum DT_MIPS_DELTA_SYM = 0x7000001d; enum DT_MIPS_DELTA_SYM_NO = 0x7000001e; enum DT_MIPS_DELTA_CLASSSYM = 0x70000020; enum DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021; enum DT_MIPS_CXX_FLAGS = 0x70000022; enum DT_MIPS_PIXIE_INIT = 0x70000023; enum DT_MIPS_SYMBOL_LIB = 0x70000024; enum DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025; enum DT_MIPS_LOCAL_GOTIDX = 0x70000026; enum DT_MIPS_HIDDEN_GOTIDX = 0x70000027; enum DT_MIPS_PROTECTED_GOTIDX = 0x70000028; enum DT_MIPS_OPTIONS = 0x70000029; enum DT_MIPS_INTERFACE = 0x7000002a; enum DT_MIPS_DYNSTR_ALIGN = 0x7000002b; enum DT_MIPS_INTERFACE_SIZE = 0x7000002c; enum DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002d; enum DT_MIPS_PERF_SUFFIX = 0x7000002e; enum DT_MIPS_COMPACT_SIZE = 0x7000002f; enum DT_MIPS_GP_VALUE = 0x70000030; enum DT_MIPS_AUX_DYNAMIC = 0x70000031; enum DT_MIPS_PLTGOT = 0x70000032; enum DT_MIPS_RWPLT = 0x70000034; enum DT_MIPS_NUM = 0x35; enum RHF_NONE = 0; enum RHF_QUICKSTART = (1 << 0); enum RHF_NOTPOT = (1 << 1); enum RHF_NO_LIBRARY_REPLACEMENT = (1 << 2); enum RHF_NO_MOVE = (1 << 3); enum RHF_SGI_ONLY = (1 << 4); enum RHF_GUARANTEE_INIT = (1 << 5); enum RHF_DELTA_C_PLUS_PLUS = (1 << 6); enum RHF_GUARANTEE_START_INIT = (1 << 7); enum RHF_PIXIE = (1 << 8); enum RHF_DEFAULT_DELAY_LOAD = (1 << 9); enum RHF_REQUICKSTART = (1 << 10); enum RHF_REQUICKSTARTED = (1 << 11); enum RHF_CORD = (1 << 12); enum RHF_NO_UNRES_UNDEF = (1 << 13); enum RHF_RLD_ORDER_SAFE = (1 << 14); struct Elf32_Lib { Elf32_Word l_name; Elf32_Word l_time_stamp; Elf32_Word l_checksum; Elf32_Word l_version; Elf32_Word l_flags; } struct Elf64_Lib { Elf64_Word l_name; Elf64_Word l_time_stamp; Elf64_Word l_checksum; Elf64_Word l_version; Elf64_Word l_flags; } enum LL_NONE = 0; enum LL_EXACT_MATCH = (1 << 0); enum LL_IGNORE_INT_VER = (1 << 1); enum LL_REQUIRE_MINOR = (1 << 2); enum LL_EXPORTS = (1 << 3); enum LL_DELAY_LOAD = (1 << 4); enum LL_DELTA = (1 << 5); alias Elf32_Addr Elf32_Conflict; enum EF_PARISC_TRAPNIL = 0x00010000; enum EF_PARISC_EXT = 0x00020000; enum EF_PARISC_LSB = 0x00040000; enum EF_PARISC_WIDE = 0x00080000; enum EF_PARISC_NO_KABP = 0x00100000; enum EF_PARISC_LAZYSWAP = 0x00400000; enum EF_PARISC_ARCH = 0x0000ffff; enum EFA_PARISC_1_0 = 0x020b; enum EFA_PARISC_1_1 = 0x0210; enum EFA_PARISC_2_0 = 0x0214; enum SHN_PARISC_ANSI_COMMON = 0xff00; enum SHN_PARISC_HUGE_COMMON = 0xff01; enum SHT_PARISC_EXT = 0x70000000; enum SHT_PARISC_UNWIND = 0x70000001; enum SHT_PARISC_DOC = 0x70000002; enum SHF_PARISC_SHORT = 0x20000000; enum SHF_PARISC_HUGE = 0x40000000; enum SHF_PARISC_SBP = 0x80000000; enum STT_PARISC_MILLICODE = 13; enum STT_HP_OPAQUE = (STT_LOOS + 0x1); enum STT_HP_STUB = (STT_LOOS + 0x2); enum R_PARISC_NONE = 0; enum R_PARISC_DIR32 = 1; enum R_PARISC_DIR21L = 2; enum R_PARISC_DIR17R = 3; enum R_PARISC_DIR17F = 4; enum R_PARISC_DIR14R = 6; enum R_PARISC_PCREL32 = 9; enum R_PARISC_PCREL21L = 10; enum R_PARISC_PCREL17R = 11; enum R_PARISC_PCREL17F = 12; enum R_PARISC_PCREL14R = 14; enum R_PARISC_DPREL21L = 18; enum R_PARISC_DPREL14R = 22; enum R_PARISC_GPREL21L = 26; enum R_PARISC_GPREL14R = 30; enum R_PARISC_LTOFF21L = 34; enum R_PARISC_LTOFF14R = 38; enum R_PARISC_SECREL32 = 41; enum R_PARISC_SEGBASE = 48; enum R_PARISC_SEGREL32 = 49; enum R_PARISC_PLTOFF21L = 50; enum R_PARISC_PLTOFF14R = 54; enum R_PARISC_LTOFF_FPTR32 = 57; enum R_PARISC_LTOFF_FPTR21L = 58; enum R_PARISC_LTOFF_FPTR14R = 62; enum R_PARISC_FPTR64 = 64; enum R_PARISC_PLABEL32 = 65; enum R_PARISC_PLABEL21L = 66; enum R_PARISC_PLABEL14R = 70; enum R_PARISC_PCREL64 = 72; enum R_PARISC_PCREL22F = 74; enum R_PARISC_PCREL14WR = 75; enum R_PARISC_PCREL14DR = 76; enum R_PARISC_PCREL16F = 77; enum R_PARISC_PCREL16WF = 78; enum R_PARISC_PCREL16DF = 79; enum R_PARISC_DIR64 = 80; enum R_PARISC_DIR14WR = 83; enum R_PARISC_DIR14DR = 84; enum R_PARISC_DIR16F = 85; enum R_PARISC_DIR16WF = 86; enum R_PARISC_DIR16DF = 87; enum R_PARISC_GPREL64 = 88; enum R_PARISC_GPREL14WR = 91; enum R_PARISC_GPREL14DR = 92; enum R_PARISC_GPREL16F = 93; enum R_PARISC_GPREL16WF = 94; enum R_PARISC_GPREL16DF = 95; enum R_PARISC_LTOFF64 = 96; enum R_PARISC_LTOFF14WR = 99; enum R_PARISC_LTOFF14DR = 100; enum R_PARISC_LTOFF16F = 101; enum R_PARISC_LTOFF16WF = 102; enum R_PARISC_LTOFF16DF = 103; enum R_PARISC_SECREL64 = 104; enum R_PARISC_SEGREL64 = 112; enum R_PARISC_PLTOFF14WR = 115; enum R_PARISC_PLTOFF14DR = 116; enum R_PARISC_PLTOFF16F = 117; enum R_PARISC_PLTOFF16WF = 118; enum R_PARISC_PLTOFF16DF = 119; enum R_PARISC_LTOFF_FPTR64 = 120; enum R_PARISC_LTOFF_FPTR14WR = 123; enum R_PARISC_LTOFF_FPTR14DR = 124; enum R_PARISC_LTOFF_FPTR16F = 125; enum R_PARISC_LTOFF_FPTR16WF = 126; enum R_PARISC_LTOFF_FPTR16DF = 127; enum R_PARISC_LORESERVE = 128; enum R_PARISC_COPY = 128; enum R_PARISC_IPLT = 129; enum R_PARISC_EPLT = 130; enum R_PARISC_TPREL32 = 153; enum R_PARISC_TPREL21L = 154; enum R_PARISC_TPREL14R = 158; enum R_PARISC_LTOFF_TP21L = 162; enum R_PARISC_LTOFF_TP14R = 166; enum R_PARISC_LTOFF_TP14F = 167; enum R_PARISC_TPREL64 = 216; enum R_PARISC_TPREL14WR = 219; enum R_PARISC_TPREL14DR = 220; enum R_PARISC_TPREL16F = 221; enum R_PARISC_TPREL16WF = 222; enum R_PARISC_TPREL16DF = 223; enum R_PARISC_LTOFF_TP64 = 224; enum R_PARISC_LTOFF_TP14WR = 227; enum R_PARISC_LTOFF_TP14DR = 228; enum R_PARISC_LTOFF_TP16F = 229; enum R_PARISC_LTOFF_TP16WF = 230; enum R_PARISC_LTOFF_TP16DF = 231; enum R_PARISC_GNU_VTENTRY = 232; enum R_PARISC_GNU_VTINHERIT = 233; enum R_PARISC_TLS_GD21L = 234; enum R_PARISC_TLS_GD14R = 235; enum R_PARISC_TLS_GDCALL = 236; enum R_PARISC_TLS_LDM21L = 237; enum R_PARISC_TLS_LDM14R = 238; enum R_PARISC_TLS_LDMCALL = 239; enum R_PARISC_TLS_LDO21L = 240; enum R_PARISC_TLS_LDO14R = 241; enum R_PARISC_TLS_DTPMOD32 = 242; enum R_PARISC_TLS_DTPMOD64 = 243; enum R_PARISC_TLS_DTPOFF32 = 244; enum R_PARISC_TLS_DTPOFF64 = 245; enum R_PARISC_TLS_LE21L = R_PARISC_TPREL21L; enum R_PARISC_TLS_LE14R = R_PARISC_TPREL14R; enum R_PARISC_TLS_IE21L = R_PARISC_LTOFF_TP21L; enum R_PARISC_TLS_IE14R = R_PARISC_LTOFF_TP14R; enum R_PARISC_TLS_TPREL32 = R_PARISC_TPREL32; enum R_PARISC_TLS_TPREL64 = R_PARISC_TPREL64; enum R_PARISC_HIRESERVE = 255; enum PT_HP_TLS = (PT_LOOS + 0x0); enum PT_HP_CORE_NONE = (PT_LOOS + 0x1); enum PT_HP_CORE_VERSION = (PT_LOOS + 0x2); enum PT_HP_CORE_KERNEL = (PT_LOOS + 0x3); enum PT_HP_CORE_COMM = (PT_LOOS + 0x4); enum PT_HP_CORE_PROC = (PT_LOOS + 0x5); enum PT_HP_CORE_LOADABLE = (PT_LOOS + 0x6); enum PT_HP_CORE_STACK = (PT_LOOS + 0x7); enum PT_HP_CORE_SHM = (PT_LOOS + 0x8); enum PT_HP_CORE_MMF = (PT_LOOS + 0x9); enum PT_HP_PARALLEL = (PT_LOOS + 0x10); enum PT_HP_FASTBIND = (PT_LOOS + 0x11); enum PT_HP_OPT_ANNOT = (PT_LOOS + 0x12); enum PT_HP_HSL_ANNOT = (PT_LOOS + 0x13); enum PT_HP_STACK = (PT_LOOS + 0x14); enum PT_PARISC_ARCHEXT = 0x70000000; enum PT_PARISC_UNWIND = 0x70000001; enum PF_PARISC_SBP = 0x08000000; enum PF_HP_PAGE_SIZE = 0x00100000; enum PF_HP_FAR_SHARED = 0x00200000; enum PF_HP_NEAR_SHARED = 0x00400000; enum PF_HP_CODE = 0x01000000; enum PF_HP_MODIFY = 0x02000000; enum PF_HP_LAZYSWAP = 0x04000000; enum PF_HP_SBP = 0x08000000; enum EF_ALPHA_32BIT = 1; enum EF_ALPHA_CANRELAX = 2; enum SHT_ALPHA_DEBUG = 0x70000001; enum SHT_ALPHA_REGINFO = 0x70000002; enum SHF_ALPHA_GPREL = 0x10000000; enum STO_ALPHA_NOPV = 0x80; enum STO_ALPHA_STD_GPLOAD = 0x88; enum R_ALPHA_NONE = 0; enum R_ALPHA_REFLONG = 1; enum R_ALPHA_REFQUAD = 2; enum R_ALPHA_GPREL32 = 3; enum R_ALPHA_LITERAL = 4; enum R_ALPHA_LITUSE = 5; enum R_ALPHA_GPDISP = 6; enum R_ALPHA_BRADDR = 7; enum R_ALPHA_HINT = 8; enum R_ALPHA_SREL16 = 9; enum R_ALPHA_SREL32 = 10; enum R_ALPHA_SREL64 = 11; enum R_ALPHA_GPRELHIGH = 17; enum R_ALPHA_GPRELLOW = 18; enum R_ALPHA_GPREL16 = 19; enum R_ALPHA_COPY = 24; enum R_ALPHA_GLOB_DAT = 25; enum R_ALPHA_JMP_SLOT = 26; enum R_ALPHA_RELATIVE = 27; enum R_ALPHA_TLS_GD_HI = 28; enum R_ALPHA_TLSGD = 29; enum R_ALPHA_TLS_LDM = 30; enum R_ALPHA_DTPMOD64 = 31; enum R_ALPHA_GOTDTPREL = 32; enum R_ALPHA_DTPREL64 = 33; enum R_ALPHA_DTPRELHI = 34; enum R_ALPHA_DTPRELLO = 35; enum R_ALPHA_DTPREL16 = 36; enum R_ALPHA_GOTTPREL = 37; enum R_ALPHA_TPREL64 = 38; enum R_ALPHA_TPRELHI = 39; enum R_ALPHA_TPRELLO = 40; enum R_ALPHA_TPREL16 = 41; enum R_ALPHA_NUM = 46; enum LITUSE_ALPHA_ADDR = 0; enum LITUSE_ALPHA_BASE = 1; enum LITUSE_ALPHA_BYTOFF = 2; enum LITUSE_ALPHA_JSR = 3; enum LITUSE_ALPHA_TLS_GD = 4; enum LITUSE_ALPHA_TLS_LDM = 5; enum DT_ALPHA_PLTRO = (DT_LOPROC + 0); enum DT_ALPHA_NUM = 1; enum EF_PPC_EMB = 0x80000000; enum EF_PPC_RELOCATABLE = 0x00010000; enum EF_PPC_RELOCATABLE_LIB = 0x00008000; enum R_PPC_NONE = 0; enum R_PPC_ADDR32 = 1; enum R_PPC_ADDR24 = 2; enum R_PPC_ADDR16 = 3; enum R_PPC_ADDR16_LO = 4; enum R_PPC_ADDR16_HI = 5; enum R_PPC_ADDR16_HA = 6; enum R_PPC_ADDR14 = 7; enum R_PPC_ADDR14_BRTAKEN = 8; enum R_PPC_ADDR14_BRNTAKEN = 9; enum R_PPC_REL24 = 10; enum R_PPC_REL14 = 11; enum R_PPC_REL14_BRTAKEN = 12; enum R_PPC_REL14_BRNTAKEN = 13; enum R_PPC_GOT16 = 14; enum R_PPC_GOT16_LO = 15; enum R_PPC_GOT16_HI = 16; enum R_PPC_GOT16_HA = 17; enum R_PPC_PLTREL24 = 18; enum R_PPC_COPY = 19; enum R_PPC_GLOB_DAT = 20; enum R_PPC_JMP_SLOT = 21; enum R_PPC_RELATIVE = 22; enum R_PPC_LOCAL24PC = 23; enum R_PPC_UADDR32 = 24; enum R_PPC_UADDR16 = 25; enum R_PPC_REL32 = 26; enum R_PPC_PLT32 = 27; enum R_PPC_PLTREL32 = 28; enum R_PPC_PLT16_LO = 29; enum R_PPC_PLT16_HI = 30; enum R_PPC_PLT16_HA = 31; enum R_PPC_SDAREL16 = 32; enum R_PPC_SECTOFF = 33; enum R_PPC_SECTOFF_LO = 34; enum R_PPC_SECTOFF_HI = 35; enum R_PPC_SECTOFF_HA = 36; enum R_PPC_TLS = 67; enum R_PPC_DTPMOD32 = 68; enum R_PPC_TPREL16 = 69; enum R_PPC_TPREL16_LO = 70; enum R_PPC_TPREL16_HI = 71; enum R_PPC_TPREL16_HA = 72; enum R_PPC_TPREL32 = 73; enum R_PPC_DTPREL16 = 74; enum R_PPC_DTPREL16_LO = 75; enum R_PPC_DTPREL16_HI = 76; enum R_PPC_DTPREL16_HA = 77; enum R_PPC_DTPREL32 = 78; enum R_PPC_GOT_TLSGD16 = 79; enum R_PPC_GOT_TLSGD16_LO = 80; enum R_PPC_GOT_TLSGD16_HI = 81; enum R_PPC_GOT_TLSGD16_HA = 82; enum R_PPC_GOT_TLSLD16 = 83; enum R_PPC_GOT_TLSLD16_LO = 84; enum R_PPC_GOT_TLSLD16_HI = 85; enum R_PPC_GOT_TLSLD16_HA = 86; enum R_PPC_GOT_TPREL16 = 87; enum R_PPC_GOT_TPREL16_LO = 88; enum R_PPC_GOT_TPREL16_HI = 89; enum R_PPC_GOT_TPREL16_HA = 90; enum R_PPC_GOT_DTPREL16 = 91; enum R_PPC_GOT_DTPREL16_LO = 92; enum R_PPC_GOT_DTPREL16_HI = 93; enum R_PPC_GOT_DTPREL16_HA = 94; enum R_PPC_EMB_NADDR32 = 101; enum R_PPC_EMB_NADDR16 = 102; enum R_PPC_EMB_NADDR16_LO = 103; enum R_PPC_EMB_NADDR16_HI = 104; enum R_PPC_EMB_NADDR16_HA = 105; enum R_PPC_EMB_SDAI16 = 106; enum R_PPC_EMB_SDA2I16 = 107; enum R_PPC_EMB_SDA2REL = 108; enum R_PPC_EMB_SDA21 = 109; enum R_PPC_EMB_MRKREF = 110; enum R_PPC_EMB_RELSEC16 = 111; enum R_PPC_EMB_RELST_LO = 112; enum R_PPC_EMB_RELST_HI = 113; enum R_PPC_EMB_RELST_HA = 114; enum R_PPC_EMB_BIT_FLD = 115; enum R_PPC_EMB_RELSDA = 116; enum R_PPC_DIAB_SDA21_LO = 180; enum R_PPC_DIAB_SDA21_HI = 181; enum R_PPC_DIAB_SDA21_HA = 182; enum R_PPC_DIAB_RELSDA_LO = 183; enum R_PPC_DIAB_RELSDA_HI = 184; enum R_PPC_DIAB_RELSDA_HA = 185; enum R_PPC_IRELATIVE = 248; enum R_PPC_REL16 = 249; enum R_PPC_REL16_LO = 250; enum R_PPC_REL16_HI = 251; enum R_PPC_REL16_HA = 252; enum R_PPC_TOC16 = 255; enum DT_PPC_GOT = (DT_LOPROC + 0); enum DT_PPC_NUM = 1; enum R_PPC64_NONE = R_PPC_NONE; enum R_PPC64_ADDR32 = R_PPC_ADDR32; enum R_PPC64_ADDR24 = R_PPC_ADDR24; enum R_PPC64_ADDR16 = R_PPC_ADDR16; enum R_PPC64_ADDR16_LO = R_PPC_ADDR16_LO; enum R_PPC64_ADDR16_HI = R_PPC_ADDR16_HI; enum R_PPC64_ADDR16_HA = R_PPC_ADDR16_HA; enum R_PPC64_ADDR14 = R_PPC_ADDR14; enum R_PPC64_ADDR14_BRTAKEN = R_PPC_ADDR14_BRTAKEN; enum R_PPC64_ADDR14_BRNTAKEN = R_PPC_ADDR14_BRNTAKEN; enum R_PPC64_REL24 = R_PPC_REL24; enum R_PPC64_REL14 = R_PPC_REL14; enum R_PPC64_REL14_BRTAKEN = R_PPC_REL14_BRTAKEN; enum R_PPC64_REL14_BRNTAKEN = R_PPC_REL14_BRNTAKEN; enum R_PPC64_GOT16 = R_PPC_GOT16; enum R_PPC64_GOT16_LO = R_PPC_GOT16_LO; enum R_PPC64_GOT16_HI = R_PPC_GOT16_HI; enum R_PPC64_GOT16_HA = R_PPC_GOT16_HA; enum R_PPC64_COPY = R_PPC_COPY; enum R_PPC64_GLOB_DAT = R_PPC_GLOB_DAT; enum R_PPC64_JMP_SLOT = R_PPC_JMP_SLOT; enum R_PPC64_RELATIVE = R_PPC_RELATIVE; enum R_PPC64_UADDR32 = R_PPC_UADDR32; enum R_PPC64_UADDR16 = R_PPC_UADDR16; enum R_PPC64_REL32 = R_PPC_REL32; enum R_PPC64_PLT32 = R_PPC_PLT32; enum R_PPC64_PLTREL32 = R_PPC_PLTREL32; enum R_PPC64_PLT16_LO = R_PPC_PLT16_LO; enum R_PPC64_PLT16_HI = R_PPC_PLT16_HI; enum R_PPC64_PLT16_HA = R_PPC_PLT16_HA; enum R_PPC64_SECTOFF = R_PPC_SECTOFF; enum R_PPC64_SECTOFF_LO = R_PPC_SECTOFF_LO; enum R_PPC64_SECTOFF_HI = R_PPC_SECTOFF_HI; enum R_PPC64_SECTOFF_HA = R_PPC_SECTOFF_HA; enum R_PPC64_ADDR30 = 37; enum R_PPC64_ADDR64 = 38; enum R_PPC64_ADDR16_HIGHER = 39; enum R_PPC64_ADDR16_HIGHERA = 40; enum R_PPC64_ADDR16_HIGHEST = 41; enum R_PPC64_ADDR16_HIGHESTA = 42; enum R_PPC64_UADDR64 = 43; enum R_PPC64_REL64 = 44; enum R_PPC64_PLT64 = 45; enum R_PPC64_PLTREL64 = 46; enum R_PPC64_TOC16 = 47; enum R_PPC64_TOC16_LO = 48; enum R_PPC64_TOC16_HI = 49; enum R_PPC64_TOC16_HA = 50; enum R_PPC64_TOC = 51; enum R_PPC64_PLTGOT16 = 52; enum R_PPC64_PLTGOT16_LO = 53; enum R_PPC64_PLTGOT16_HI = 54; enum R_PPC64_PLTGOT16_HA = 55; enum R_PPC64_ADDR16_DS = 56; enum R_PPC64_ADDR16_LO_DS = 57; enum R_PPC64_GOT16_DS = 58; enum R_PPC64_GOT16_LO_DS = 59; enum R_PPC64_PLT16_LO_DS = 60; enum R_PPC64_SECTOFF_DS = 61; enum R_PPC64_SECTOFF_LO_DS = 62; enum R_PPC64_TOC16_DS = 63; enum R_PPC64_TOC16_LO_DS = 64; enum R_PPC64_PLTGOT16_DS = 65; enum R_PPC64_PLTGOT16_LO_DS = 66; enum R_PPC64_TLS = 67; enum R_PPC64_DTPMOD64 = 68; enum R_PPC64_TPREL16 = 69; enum R_PPC64_TPREL16_LO = 70; enum R_PPC64_TPREL16_HI = 71; enum R_PPC64_TPREL16_HA = 72; enum R_PPC64_TPREL64 = 73; enum R_PPC64_DTPREL16 = 74; enum R_PPC64_DTPREL16_LO = 75; enum R_PPC64_DTPREL16_HI = 76; enum R_PPC64_DTPREL16_HA = 77; enum R_PPC64_DTPREL64 = 78; enum R_PPC64_GOT_TLSGD16 = 79; enum R_PPC64_GOT_TLSGD16_LO = 80; enum R_PPC64_GOT_TLSGD16_HI = 81; enum R_PPC64_GOT_TLSGD16_HA = 82; enum R_PPC64_GOT_TLSLD16 = 83; enum R_PPC64_GOT_TLSLD16_LO = 84; enum R_PPC64_GOT_TLSLD16_HI = 85; enum R_PPC64_GOT_TLSLD16_HA = 86; enum R_PPC64_GOT_TPREL16_DS = 87; enum R_PPC64_GOT_TPREL16_LO_DS = 88; enum R_PPC64_GOT_TPREL16_HI = 89; enum R_PPC64_GOT_TPREL16_HA = 90; enum R_PPC64_GOT_DTPREL16_DS = 91; enum R_PPC64_GOT_DTPREL16_LO_DS = 92; enum R_PPC64_GOT_DTPREL16_HI = 93; enum R_PPC64_GOT_DTPREL16_HA = 94; enum R_PPC64_TPREL16_DS = 95; enum R_PPC64_TPREL16_LO_DS = 96; enum R_PPC64_TPREL16_HIGHER = 97; enum R_PPC64_TPREL16_HIGHERA = 98; enum R_PPC64_TPREL16_HIGHEST = 99; enum R_PPC64_TPREL16_HIGHESTA = 100; enum R_PPC64_DTPREL16_DS = 101; enum R_PPC64_DTPREL16_LO_DS = 102; enum R_PPC64_DTPREL16_HIGHER = 103; enum R_PPC64_DTPREL16_HIGHERA = 104; enum R_PPC64_DTPREL16_HIGHEST = 105; enum R_PPC64_DTPREL16_HIGHESTA = 106; enum R_PPC64_JMP_IREL = 247; enum R_PPC64_IRELATIVE = 248; enum R_PPC64_REL16 = 249; enum R_PPC64_REL16_LO = 250; enum R_PPC64_REL16_HI = 251; enum R_PPC64_REL16_HA = 252; enum DT_PPC64_GLINK = (DT_LOPROC + 0); enum DT_PPC64_OPD = (DT_LOPROC + 1); enum DT_PPC64_OPDSZ = (DT_LOPROC + 2); enum DT_PPC64_NUM = 3; enum EF_ARM_RELEXEC = 0x01; enum EF_ARM_HASENTRY = 0x02; enum EF_ARM_INTERWORK = 0x04; enum EF_ARM_APCS_26 = 0x08; enum EF_ARM_APCS_FLOAT = 0x10; enum EF_ARM_PIC = 0x20; enum EF_ARM_ALIGN8 = 0x40; enum EF_ARM_NEW_ABI = 0x80; enum EF_ARM_OLD_ABI = 0x100; enum EF_ARM_SOFT_FLOAT = 0x200; enum EF_ARM_VFP_FLOAT = 0x400; enum EF_ARM_MAVERICK_FLOAT = 0x800; enum EF_ARM_ABI_FLOAT_SOFT = 0x200; enum EF_ARM_ABI_FLOAT_HARD = 0x400; enum EF_ARM_SYMSARESORTED = 0x04; enum EF_ARM_DYNSYMSUSESEGIDX = 0x08; enum EF_ARM_MAPSYMSFIRST = 0x10; enum EF_ARM_EABIMASK = 0XFF000000; enum EF_ARM_BE8 = 0x00800000; enum EF_ARM_LE8 = 0x00400000; extern (D) auto EF_ARM_EABI_VERSION(F)(F flags) { return flags & EF_ARM_EABIMASK; } enum EF_ARM_EABI_UNKNOWN = 0x00000000; enum EF_ARM_EABI_VER1 = 0x01000000; enum EF_ARM_EABI_VER2 = 0x02000000; enum EF_ARM_EABI_VER3 = 0x03000000; enum EF_ARM_EABI_VER4 = 0x04000000; enum EF_ARM_EABI_VER5 = 0x05000000; enum STT_ARM_TFUNC = STT_LOPROC; enum STT_ARM_16BIT = STT_HIPROC; enum SHF_ARM_ENTRYSECT = 0x10000000; enum SHF_ARM_COMDEF = 0x80000000; enum PF_ARM_SB = 0x10000000; enum PF_ARM_PI = 0x20000000; enum PF_ARM_ABS = 0x40000000; enum PT_ARM_EXIDX = (PT_LOPROC + 1); enum SHT_ARM_EXIDX = (SHT_LOPROC + 1); enum SHT_ARM_PREEMPTMAP = (SHT_LOPROC + 2); enum SHT_ARM_ATTRIBUTES = (SHT_LOPROC + 3); enum R_AARCH64_NONE = 0; enum R_AARCH64_ABS64 = 257; enum R_AARCH64_ABS32 = 258; enum R_AARCH64_COPY = 1024; enum R_AARCH64_GLOB_DAT = 1025; enum R_AARCH64_JUMP_SLOT = 1026; enum R_AARCH64_RELATIVE = 1027; enum R_AARCH64_TLS_DTPMOD64 = 1028; enum R_AARCH64_TLS_DTPREL64 = 1029; enum R_AARCH64_TLS_TPREL64 = 1030; enum R_AARCH64_TLSDESC = 1031; enum R_ARM_NONE = 0; enum R_ARM_PC24 = 1; enum R_ARM_ABS32 = 2; enum R_ARM_REL32 = 3; enum R_ARM_PC13 = 4; enum R_ARM_ABS16 = 5; enum R_ARM_ABS12 = 6; enum R_ARM_THM_ABS5 = 7; enum R_ARM_ABS8 = 8; enum R_ARM_SBREL32 = 9; enum R_ARM_THM_PC22 = 10; enum R_ARM_THM_PC8 = 11; enum R_ARM_AMP_VCALL9 = 12; enum R_ARM_SWI24 = 13; enum R_ARM_TLS_DESC = 13; enum R_ARM_THM_SWI8 = 14; enum R_ARM_XPC25 = 15; enum R_ARM_THM_XPC22 = 16; enum R_ARM_TLS_DTPMOD32 = 17; enum R_ARM_TLS_DTPOFF32 = 18; enum R_ARM_TLS_TPOFF32 = 19; enum R_ARM_COPY = 20; enum R_ARM_GLOB_DAT = 21; enum R_ARM_JUMP_SLOT = 22; enum R_ARM_RELATIVE = 23; enum R_ARM_GOTOFF = 24; enum R_ARM_GOTPC = 25; enum R_ARM_GOT32 = 26; enum R_ARM_PLT32 = 27; enum R_ARM_ALU_PCREL_7_0 = 32; enum R_ARM_ALU_PCREL_15_8 = 33; enum R_ARM_ALU_PCREL_23_15 = 34; enum R_ARM_LDR_SBREL_11_0 = 35; enum R_ARM_ALU_SBREL_19_12 = 36; enum R_ARM_ALU_SBREL_27_20 = 37; enum R_ARM_TLS_GOTDESC = 90; enum R_ARM_TLS_CALL = 91; enum R_ARM_TLS_DESCSEQ = 92; enum R_ARM_THM_TLS_CALL = 93; enum R_ARM_GNU_VTENTRY = 100; enum R_ARM_GNU_VTINHERIT = 101; enum R_ARM_THM_PC11 = 102; enum R_ARM_THM_PC9 = 103; enum R_ARM_TLS_GD32 = 104; enum R_ARM_TLS_LDM32 = 105; enum R_ARM_TLS_LDO32 = 106; enum R_ARM_TLS_IE32 = 107; enum R_ARM_TLS_LE32 = 108; enum R_ARM_THM_TLS_DESCSEQ = 129; enum R_ARM_IRELATIVE = 160; enum R_ARM_RXPC25 = 249; enum R_ARM_RSBREL32 = 250; enum R_ARM_THM_RPC22 = 251; enum R_ARM_RREL32 = 252; enum R_ARM_RABS22 = 253; enum R_ARM_RPC24 = 254; enum R_ARM_RBASE = 255; enum R_ARM_NUM = 256; enum EF_IA_64_MASKOS = 0x0000000f; enum EF_IA_64_ABI64 = 0x00000010; enum EF_IA_64_ARCH = 0xff000000; enum PT_IA_64_ARCHEXT = (PT_LOPROC + 0); enum PT_IA_64_UNWIND = (PT_LOPROC + 1); enum PT_IA_64_HP_OPT_ANOT = (PT_LOOS + 0x12); enum PT_IA_64_HP_HSL_ANOT = (PT_LOOS + 0x13); enum PT_IA_64_HP_STACK = (PT_LOOS + 0x14); enum PF_IA_64_NORECOV = 0x80000000; enum SHT_IA_64_EXT = (SHT_LOPROC + 0); enum SHT_IA_64_UNWIND = (SHT_LOPROC + 1); enum SHF_IA_64_SHORT = 0x10000000; enum SHF_IA_64_NORECOV = 0x20000000; enum DT_IA_64_PLT_RESERVE = (DT_LOPROC + 0); enum DT_IA_64_NUM = 1; enum R_IA64_NONE = 0x00; enum R_IA64_IMM14 = 0x21; enum R_IA64_IMM22 = 0x22; enum R_IA64_IMM64 = 0x23; enum R_IA64_DIR32MSB = 0x24; enum R_IA64_DIR32LSB = 0x25; enum R_IA64_DIR64MSB = 0x26; enum R_IA64_DIR64LSB = 0x27; enum R_IA64_GPREL22 = 0x2a; enum R_IA64_GPREL64I = 0x2b; enum R_IA64_GPREL32MSB = 0x2c; enum R_IA64_GPREL32LSB = 0x2d; enum R_IA64_GPREL64MSB = 0x2e; enum R_IA64_GPREL64LSB = 0x2f; enum R_IA64_LTOFF22 = 0x32; enum R_IA64_LTOFF64I = 0x33; enum R_IA64_PLTOFF22 = 0x3a; enum R_IA64_PLTOFF64I = 0x3b; enum R_IA64_PLTOFF64MSB = 0x3e; enum R_IA64_PLTOFF64LSB = 0x3f; enum R_IA64_FPTR64I = 0x43; enum R_IA64_FPTR32MSB = 0x44; enum R_IA64_FPTR32LSB = 0x45; enum R_IA64_FPTR64MSB = 0x46; enum R_IA64_FPTR64LSB = 0x47; enum R_IA64_PCREL60B = 0x48; enum R_IA64_PCREL21B = 0x49; enum R_IA64_PCREL21M = 0x4a; enum R_IA64_PCREL21F = 0x4b; enum R_IA64_PCREL32MSB = 0x4c; enum R_IA64_PCREL32LSB = 0x4d; enum R_IA64_PCREL64MSB = 0x4e; enum R_IA64_PCREL64LSB = 0x4f; enum R_IA64_LTOFF_FPTR22 = 0x52; enum R_IA64_LTOFF_FPTR64I = 0x53; enum R_IA64_LTOFF_FPTR32MSB = 0x54; enum R_IA64_LTOFF_FPTR32LSB = 0x55; enum R_IA64_LTOFF_FPTR64MSB = 0x56; enum R_IA64_LTOFF_FPTR64LSB = 0x57; enum R_IA64_SEGREL32MSB = 0x5c; enum R_IA64_SEGREL32LSB = 0x5d; enum R_IA64_SEGREL64MSB = 0x5e; enum R_IA64_SEGREL64LSB = 0x5f; enum R_IA64_SECREL32MSB = 0x64; enum R_IA64_SECREL32LSB = 0x65; enum R_IA64_SECREL64MSB = 0x66; enum R_IA64_SECREL64LSB = 0x67; enum R_IA64_REL32MSB = 0x6c; enum R_IA64_REL32LSB = 0x6d; enum R_IA64_REL64MSB = 0x6e; enum R_IA64_REL64LSB = 0x6f; enum R_IA64_LTV32MSB = 0x74; enum R_IA64_LTV32LSB = 0x75; enum R_IA64_LTV64MSB = 0x76; enum R_IA64_LTV64LSB = 0x77; enum R_IA64_PCREL21BI = 0x79; enum R_IA64_PCREL22 = 0x7a; enum R_IA64_PCREL64I = 0x7b; enum R_IA64_IPLTMSB = 0x80; enum R_IA64_IPLTLSB = 0x81; enum R_IA64_COPY = 0x84; enum R_IA64_SUB = 0x85; enum R_IA64_LTOFF22X = 0x86; enum R_IA64_LDXMOV = 0x87; enum R_IA64_TPREL14 = 0x91; enum R_IA64_TPREL22 = 0x92; enum R_IA64_TPREL64I = 0x93; enum R_IA64_TPREL64MSB = 0x96; enum R_IA64_TPREL64LSB = 0x97; enum R_IA64_LTOFF_TPREL22 = 0x9a; enum R_IA64_DTPMOD64MSB = 0xa6; enum R_IA64_DTPMOD64LSB = 0xa7; enum R_IA64_LTOFF_DTPMOD22 = 0xaa; enum R_IA64_DTPREL14 = 0xb1; enum R_IA64_DTPREL22 = 0xb2; enum R_IA64_DTPREL64I = 0xb3; enum R_IA64_DTPREL32MSB = 0xb4; enum R_IA64_DTPREL32LSB = 0xb5; enum R_IA64_DTPREL64MSB = 0xb6; enum R_IA64_DTPREL64LSB = 0xb7; enum R_IA64_LTOFF_DTPREL22 = 0xba; enum EF_SH_MACH_MASK = 0x1f; enum EF_SH_UNKNOWN = 0x0; enum EF_SH1 = 0x1; enum EF_SH2 = 0x2; enum EF_SH3 = 0x3; enum EF_SH_DSP = 0x4; enum EF_SH3_DSP = 0x5; enum EF_SH4AL_DSP = 0x6; enum EF_SH3E = 0x8; enum EF_SH4 = 0x9; enum EF_SH2E = 0xb; enum EF_SH4A = 0xc; enum EF_SH2A = 0xd; enum EF_SH4_NOFPU = 0x10; enum EF_SH4A_NOFPU = 0x11; enum EF_SH4_NOMMU_NOFPU = 0x12; enum EF_SH2A_NOFPU = 0x13; enum EF_SH3_NOMMU = 0x14; enum EF_SH2A_SH4_NOFPU = 0x15; enum EF_SH2A_SH3_NOFPU = 0x16; enum EF_SH2A_SH4 = 0x17; enum EF_SH2A_SH3E = 0x18; enum R_SH_NONE = 0; enum R_SH_DIR32 = 1; enum R_SH_REL32 = 2; enum R_SH_DIR8WPN = 3; enum R_SH_IND12W = 4; enum R_SH_DIR8WPL = 5; enum R_SH_DIR8WPZ = 6; enum R_SH_DIR8BP = 7; enum R_SH_DIR8W = 8; enum R_SH_DIR8L = 9; enum R_SH_SWITCH16 = 25; enum R_SH_SWITCH32 = 26; enum R_SH_USES = 27; enum R_SH_COUNT = 28; enum R_SH_ALIGN = 29; enum R_SH_CODE = 30; enum R_SH_DATA = 31; enum R_SH_LABEL = 32; enum R_SH_SWITCH8 = 33; enum R_SH_GNU_VTINHERIT = 34; enum R_SH_GNU_VTENTRY = 35; enum R_SH_TLS_GD_32 = 144; enum R_SH_TLS_LD_32 = 145; enum R_SH_TLS_LDO_32 = 146; enum R_SH_TLS_IE_32 = 147; enum R_SH_TLS_LE_32 = 148; enum R_SH_TLS_DTPMOD32 = 149; enum R_SH_TLS_DTPOFF32 = 150; enum R_SH_TLS_TPOFF32 = 151; enum R_SH_GOT32 = 160; enum R_SH_PLT32 = 161; enum R_SH_COPY = 162; enum R_SH_GLOB_DAT = 163; enum R_SH_JMP_SLOT = 164; enum R_SH_RELATIVE = 165; enum R_SH_GOTOFF = 166; enum R_SH_GOTPC = 167; enum R_SH_NUM = 256; enum EF_S390_HIGH_GPRS = 0x00000001; enum R_390_NONE = 0; enum R_390_8 = 1; enum R_390_12 = 2; enum R_390_16 = 3; enum R_390_32 = 4; enum R_390_PC32 = 5; enum R_390_GOT12 = 6; enum R_390_GOT32 = 7; enum R_390_PLT32 = 8; enum R_390_COPY = 9; enum R_390_GLOB_DAT = 10; enum R_390_JMP_SLOT = 11; enum R_390_RELATIVE = 12; enum R_390_GOTOFF32 = 13; enum R_390_GOTPC = 14; enum R_390_GOT16 = 15; enum R_390_PC16 = 16; enum R_390_PC16DBL = 17; enum R_390_PLT16DBL = 18; enum R_390_PC32DBL = 19; enum R_390_PLT32DBL = 20; enum R_390_GOTPCDBL = 21; enum R_390_64 = 22; enum R_390_PC64 = 23; enum R_390_GOT64 = 24; enum R_390_PLT64 = 25; enum R_390_GOTENT = 26; enum R_390_GOTOFF16 = 27; enum R_390_GOTOFF64 = 28; enum R_390_GOTPLT12 = 29; enum R_390_GOTPLT16 = 30; enum R_390_GOTPLT32 = 31; enum R_390_GOTPLT64 = 32; enum R_390_GOTPLTENT = 33; enum R_390_PLTOFF16 = 34; enum R_390_PLTOFF32 = 35; enum R_390_PLTOFF64 = 36; enum R_390_TLS_LOAD = 37; enum R_390_TLS_GDCALL = 38; enum R_390_TLS_LDCALL = 39; enum R_390_TLS_GD32 = 40; enum R_390_TLS_GD64 = 41; enum R_390_TLS_GOTIE12 = 42; enum R_390_TLS_GOTIE32 = 43; enum R_390_TLS_GOTIE64 = 44; enum R_390_TLS_LDM32 = 45; enum R_390_TLS_LDM64 = 46; enum R_390_TLS_IE32 = 47; enum R_390_TLS_IE64 = 48; enum R_390_TLS_IEENT = 49; enum R_390_TLS_LE32 = 50; enum R_390_TLS_LE64 = 51; enum R_390_TLS_LDO32 = 52; enum R_390_TLS_LDO64 = 53; enum R_390_TLS_DTPMOD = 54; enum R_390_TLS_DTPOFF = 55; enum R_390_TLS_TPOFF = 56; enum R_390_20 = 57; enum R_390_GOT20 = 58; enum R_390_GOTPLT20 = 59; enum R_390_TLS_GOTIE20 = 60; enum R_390_IRELATIVE = 61; enum R_390_NUM = 62; enum R_CRIS_NONE = 0; enum R_CRIS_8 = 1; enum R_CRIS_16 = 2; enum R_CRIS_32 = 3; enum R_CRIS_8_PCREL = 4; enum R_CRIS_16_PCREL = 5; enum R_CRIS_32_PCREL = 6; enum R_CRIS_GNU_VTINHERIT = 7; enum R_CRIS_GNU_VTENTRY = 8; enum R_CRIS_COPY = 9; enum R_CRIS_GLOB_DAT = 10; enum R_CRIS_JUMP_SLOT = 11; enum R_CRIS_RELATIVE = 12; enum R_CRIS_16_GOT = 13; enum R_CRIS_32_GOT = 14; enum R_CRIS_16_GOTPLT = 15; enum R_CRIS_32_GOTPLT = 16; enum R_CRIS_32_GOTREL = 17; enum R_CRIS_32_PLT_GOTREL = 18; enum R_CRIS_32_PLT_PCREL = 19; enum R_CRIS_NUM = 20; enum R_X86_64_NONE = 0; enum R_X86_64_64 = 1; enum R_X86_64_PC32 = 2; enum R_X86_64_GOT32 = 3; enum R_X86_64_PLT32 = 4; enum R_X86_64_COPY = 5; enum R_X86_64_GLOB_DAT = 6; enum R_X86_64_JUMP_SLOT = 7; enum R_X86_64_RELATIVE = 8; enum R_X86_64_GOTPCREL = 9; enum R_X86_64_32 = 10; enum R_X86_64_32S = 11; enum R_X86_64_16 = 12; enum R_X86_64_PC16 = 13; enum R_X86_64_8 = 14; enum R_X86_64_PC8 = 15; enum R_X86_64_DTPMOD64 = 16; enum R_X86_64_DTPOFF64 = 17; enum R_X86_64_TPOFF64 = 18; enum R_X86_64_TLSGD = 19; enum R_X86_64_TLSLD = 20; enum R_X86_64_DTPOFF32 = 21; enum R_X86_64_GOTTPOFF = 22; enum R_X86_64_TPOFF32 = 23; enum R_X86_64_PC64 = 24; enum R_X86_64_GOTOFF64 = 25; enum R_X86_64_GOTPC32 = 26; enum R_X86_64_GOT64 = 27; enum R_X86_64_GOTPCREL64 = 28; enum R_X86_64_GOTPC64 = 29; enum R_X86_64_GOTPLT64 = 30; enum R_X86_64_PLTOFF64 = 31; enum R_X86_64_SIZE32 = 32; enum R_X86_64_SIZE64 = 33; enum R_X86_64_GOTPC32_TLSDESC = 34; enum R_X86_64_TLSDESC_CALL = 35; enum R_X86_64_TLSDESC = 36; enum R_X86_64_IRELATIVE = 37; enum R_X86_64_RELATIVE64 = 38; enum R_X86_64_NUM = 39; enum R_MN10300_NONE = 0; enum R_MN10300_32 = 1; enum R_MN10300_16 = 2; enum R_MN10300_8 = 3; enum R_MN10300_PCREL32 = 4; enum R_MN10300_PCREL16 = 5; enum R_MN10300_PCREL8 = 6; enum R_MN10300_GNU_VTINHERIT = 7; enum R_MN10300_GNU_VTENTRY = 8; enum R_MN10300_24 = 9; enum R_MN10300_GOTPC32 = 10; enum R_MN10300_GOTPC16 = 11; enum R_MN10300_GOTOFF32 = 12; enum R_MN10300_GOTOFF24 = 13; enum R_MN10300_GOTOFF16 = 14; enum R_MN10300_PLT32 = 15; enum R_MN10300_PLT16 = 16; enum R_MN10300_GOT32 = 17; enum R_MN10300_GOT24 = 18; enum R_MN10300_GOT16 = 19; enum R_MN10300_COPY = 20; enum R_MN10300_GLOB_DAT = 21; enum R_MN10300_JMP_SLOT = 22; enum R_MN10300_RELATIVE = 23; enum R_MN10300_TLS_GD = 24; enum R_MN10300_TLS_LD = 25; enum R_MN10300_TLS_LDO = 26; enum R_MN10300_TLS_GOTIE = 27; enum R_MN10300_TLS_IE = 28; enum R_MN10300_TLS_LE = 29; enum R_MN10300_TLS_DTPMOD = 30; enum R_MN10300_TLS_DTPOFF = 31; enum R_MN10300_TLS_TPOFF = 32; enum R_MN10300_SYM_DIFF = 33; enum R_MN10300_ALIGN = 34; enum R_MN10300_NUM = 35; enum R_M32R_NONE = 0; enum R_M32R_16 = 1; enum R_M32R_32 = 2; enum R_M32R_24 = 3; enum R_M32R_10_PCREL = 4; enum R_M32R_18_PCREL = 5; enum R_M32R_26_PCREL = 6; enum R_M32R_HI16_ULO = 7; enum R_M32R_HI16_SLO = 8; enum R_M32R_LO16 = 9; enum R_M32R_SDA16 = 10; enum R_M32R_GNU_VTINHERIT = 11; enum R_M32R_GNU_VTENTRY = 12; enum R_M32R_16_RELA = 33; enum R_M32R_32_RELA = 34; enum R_M32R_24_RELA = 35; enum R_M32R_10_PCREL_RELA = 36; enum R_M32R_18_PCREL_RELA = 37; enum R_M32R_26_PCREL_RELA = 38; enum R_M32R_HI16_ULO_RELA = 39; enum R_M32R_HI16_SLO_RELA = 40; enum R_M32R_LO16_RELA = 41; enum R_M32R_SDA16_RELA = 42; enum R_M32R_RELA_GNU_VTINHERIT = 43; enum R_M32R_RELA_GNU_VTENTRY = 44; enum R_M32R_REL32 = 45; enum R_M32R_GOT24 = 48; enum R_M32R_26_PLTREL = 49; enum R_M32R_COPY = 50; enum R_M32R_GLOB_DAT = 51; enum R_M32R_JMP_SLOT = 52; enum R_M32R_RELATIVE = 53; enum R_M32R_GOTOFF = 54; enum R_M32R_GOTPC24 = 55; enum R_M32R_GOT16_HI_ULO = 56; enum R_M32R_GOT16_HI_SLO = 57; enum R_M32R_GOT16_LO = 58; enum R_M32R_GOTPC_HI_ULO = 59; enum R_M32R_GOTPC_HI_SLO = 60; enum R_M32R_GOTPC_LO = 61; enum R_M32R_GOTOFF_HI_ULO = 62; enum R_M32R_GOTOFF_HI_SLO = 63; enum R_M32R_GOTOFF_LO = 64; enum R_M32R_NUM = 256; enum R_TILEPRO_NONE = 0; enum R_TILEPRO_32 = 1; enum R_TILEPRO_16 = 2; enum R_TILEPRO_8 = 3; enum R_TILEPRO_32_PCREL = 4; enum R_TILEPRO_16_PCREL = 5; enum R_TILEPRO_8_PCREL = 6; enum R_TILEPRO_LO16 = 7; enum R_TILEPRO_HI16 = 8; enum R_TILEPRO_HA16 = 9; enum R_TILEPRO_COPY = 10; enum R_TILEPRO_GLOB_DAT = 11; enum R_TILEPRO_JMP_SLOT = 12; enum R_TILEPRO_RELATIVE = 13; enum R_TILEPRO_BROFF_X1 = 14; enum R_TILEPRO_JOFFLONG_X1 = 15; enum R_TILEPRO_JOFFLONG_X1_PLT = 16; enum R_TILEPRO_IMM8_X0 = 17; enum R_TILEPRO_IMM8_Y0 = 18; enum R_TILEPRO_IMM8_X1 = 19; enum R_TILEPRO_IMM8_Y1 = 20; enum R_TILEPRO_MT_IMM15_X1 = 21; enum R_TILEPRO_MF_IMM15_X1 = 22; enum R_TILEPRO_IMM16_X0 = 23; enum R_TILEPRO_IMM16_X1 = 24; enum R_TILEPRO_IMM16_X0_LO = 25; enum R_TILEPRO_IMM16_X1_LO = 26; enum R_TILEPRO_IMM16_X0_HI = 27; enum R_TILEPRO_IMM16_X1_HI = 28; enum R_TILEPRO_IMM16_X0_HA = 29; enum R_TILEPRO_IMM16_X1_HA = 30; enum R_TILEPRO_IMM16_X0_PCREL = 31; enum R_TILEPRO_IMM16_X1_PCREL = 32; enum R_TILEPRO_IMM16_X0_LO_PCREL = 33; enum R_TILEPRO_IMM16_X1_LO_PCREL = 34; enum R_TILEPRO_IMM16_X0_HI_PCREL = 35; enum R_TILEPRO_IMM16_X1_HI_PCREL = 36; enum R_TILEPRO_IMM16_X0_HA_PCREL = 37; enum R_TILEPRO_IMM16_X1_HA_PCREL = 38; enum R_TILEPRO_IMM16_X0_GOT = 39; enum R_TILEPRO_IMM16_X1_GOT = 40; enum R_TILEPRO_IMM16_X0_GOT_LO = 41; enum R_TILEPRO_IMM16_X1_GOT_LO = 42; enum R_TILEPRO_IMM16_X0_GOT_HI = 43; enum R_TILEPRO_IMM16_X1_GOT_HI = 44; enum R_TILEPRO_IMM16_X0_GOT_HA = 45; enum R_TILEPRO_IMM16_X1_GOT_HA = 46; enum R_TILEPRO_MMSTART_X0 = 47; enum R_TILEPRO_MMEND_X0 = 48; enum R_TILEPRO_MMSTART_X1 = 49; enum R_TILEPRO_MMEND_X1 = 50; enum R_TILEPRO_SHAMT_X0 = 51; enum R_TILEPRO_SHAMT_X1 = 52; enum R_TILEPRO_SHAMT_Y0 = 53; enum R_TILEPRO_SHAMT_Y1 = 54; enum R_TILEPRO_DEST_IMM8_X1 = 55; enum R_TILEPRO_TLS_GD_CALL = 60; enum R_TILEPRO_IMM8_X0_TLS_GD_ADD = 61; enum R_TILEPRO_IMM8_X1_TLS_GD_ADD = 62; enum R_TILEPRO_IMM8_Y0_TLS_GD_ADD = 63; enum R_TILEPRO_IMM8_Y1_TLS_GD_ADD = 64; enum R_TILEPRO_TLS_IE_LOAD = 65; enum R_TILEPRO_IMM16_X0_TLS_GD = 66; enum R_TILEPRO_IMM16_X1_TLS_GD = 67; enum R_TILEPRO_IMM16_X0_TLS_GD_LO = 68; enum R_TILEPRO_IMM16_X1_TLS_GD_LO = 69; enum R_TILEPRO_IMM16_X0_TLS_GD_HI = 70; enum R_TILEPRO_IMM16_X1_TLS_GD_HI = 71; enum R_TILEPRO_IMM16_X0_TLS_GD_HA = 72; enum R_TILEPRO_IMM16_X1_TLS_GD_HA = 73; enum R_TILEPRO_IMM16_X0_TLS_IE = 74; enum R_TILEPRO_IMM16_X1_TLS_IE = 75; enum R_TILEPRO_IMM16_X0_TLS_IE_LO = 76; enum R_TILEPRO_IMM16_X1_TLS_IE_LO = 77; enum R_TILEPRO_IMM16_X0_TLS_IE_HI = 78; enum R_TILEPRO_IMM16_X1_TLS_IE_HI = 79; enum R_TILEPRO_IMM16_X0_TLS_IE_HA = 80; enum R_TILEPRO_IMM16_X1_TLS_IE_HA = 81; enum R_TILEPRO_TLS_DTPMOD32 = 82; enum R_TILEPRO_TLS_DTPOFF32 = 83; enum R_TILEPRO_TLS_TPOFF32 = 84; enum R_TILEPRO_IMM16_X0_TLS_LE = 85; enum R_TILEPRO_IMM16_X1_TLS_LE = 86; enum R_TILEPRO_IMM16_X0_TLS_LE_LO = 87; enum R_TILEPRO_IMM16_X1_TLS_LE_LO = 88; enum R_TILEPRO_IMM16_X0_TLS_LE_HI = 89; enum R_TILEPRO_IMM16_X1_TLS_LE_HI = 90; enum R_TILEPRO_IMM16_X0_TLS_LE_HA = 91; enum R_TILEPRO_IMM16_X1_TLS_LE_HA = 92; enum R_TILEPRO_GNU_VTINHERIT = 128; enum R_TILEPRO_GNU_VTENTRY = 129; enum R_TILEPRO_NUM = 130; enum R_TILEGX_NONE = 0; enum R_TILEGX_64 = 1; enum R_TILEGX_32 = 2; enum R_TILEGX_16 = 3; enum R_TILEGX_8 = 4; enum R_TILEGX_64_PCREL = 5; enum R_TILEGX_32_PCREL = 6; enum R_TILEGX_16_PCREL = 7; enum R_TILEGX_8_PCREL = 8; enum R_TILEGX_HW0 = 9; enum R_TILEGX_HW1 = 10; enum R_TILEGX_HW2 = 11; enum R_TILEGX_HW3 = 12; enum R_TILEGX_HW0_LAST = 13; enum R_TILEGX_HW1_LAST = 14; enum R_TILEGX_HW2_LAST = 15; enum R_TILEGX_COPY = 16; enum R_TILEGX_GLOB_DAT = 17; enum R_TILEGX_JMP_SLOT = 18; enum R_TILEGX_RELATIVE = 19; enum R_TILEGX_BROFF_X1 = 20; enum R_TILEGX_JUMPOFF_X1 = 21; enum R_TILEGX_JUMPOFF_X1_PLT = 22; enum R_TILEGX_IMM8_X0 = 23; enum R_TILEGX_IMM8_Y0 = 24; enum R_TILEGX_IMM8_X1 = 25; enum R_TILEGX_IMM8_Y1 = 26; enum R_TILEGX_DEST_IMM8_X1 = 27; enum R_TILEGX_MT_IMM14_X1 = 28; enum R_TILEGX_MF_IMM14_X1 = 29; enum R_TILEGX_MMSTART_X0 = 30; enum R_TILEGX_MMEND_X0 = 31; enum R_TILEGX_SHAMT_X0 = 32; enum R_TILEGX_SHAMT_X1 = 33; enum R_TILEGX_SHAMT_Y0 = 34; enum R_TILEGX_SHAMT_Y1 = 35; enum R_TILEGX_IMM16_X0_HW0 = 36; enum R_TILEGX_IMM16_X1_HW0 = 37; enum R_TILEGX_IMM16_X0_HW1 = 38; enum R_TILEGX_IMM16_X1_HW1 = 39; enum R_TILEGX_IMM16_X0_HW2 = 40; enum R_TILEGX_IMM16_X1_HW2 = 41; enum R_TILEGX_IMM16_X0_HW3 = 42; enum R_TILEGX_IMM16_X1_HW3 = 43; enum R_TILEGX_IMM16_X0_HW0_LAST = 44; enum R_TILEGX_IMM16_X1_HW0_LAST = 45; enum R_TILEGX_IMM16_X0_HW1_LAST = 46; enum R_TILEGX_IMM16_X1_HW1_LAST = 47; enum R_TILEGX_IMM16_X0_HW2_LAST = 48; enum R_TILEGX_IMM16_X1_HW2_LAST = 49; enum R_TILEGX_IMM16_X0_HW0_PCREL = 50; enum R_TILEGX_IMM16_X1_HW0_PCREL = 51; enum R_TILEGX_IMM16_X0_HW1_PCREL = 52; enum R_TILEGX_IMM16_X1_HW1_PCREL = 53; enum R_TILEGX_IMM16_X0_HW2_PCREL = 54; enum R_TILEGX_IMM16_X1_HW2_PCREL = 55; enum R_TILEGX_IMM16_X0_HW3_PCREL = 56; enum R_TILEGX_IMM16_X1_HW3_PCREL = 57; enum R_TILEGX_IMM16_X0_HW0_LAST_PCREL = 58; enum R_TILEGX_IMM16_X1_HW0_LAST_PCREL = 59; enum R_TILEGX_IMM16_X0_HW1_LAST_PCREL = 60; enum R_TILEGX_IMM16_X1_HW1_LAST_PCREL = 61; enum R_TILEGX_IMM16_X0_HW2_LAST_PCREL = 62; enum R_TILEGX_IMM16_X1_HW2_LAST_PCREL = 63; enum R_TILEGX_IMM16_X0_HW0_GOT = 64; enum R_TILEGX_IMM16_X1_HW0_GOT = 65; enum R_TILEGX_IMM16_X0_HW0_PLT_PCREL = 66; enum R_TILEGX_IMM16_X1_HW0_PLT_PCREL = 67; enum R_TILEGX_IMM16_X0_HW1_PLT_PCREL = 68; enum R_TILEGX_IMM16_X1_HW1_PLT_PCREL = 69; enum R_TILEGX_IMM16_X0_HW2_PLT_PCREL = 70; enum R_TILEGX_IMM16_X1_HW2_PLT_PCREL = 71; enum R_TILEGX_IMM16_X0_HW0_LAST_GOT = 72; enum R_TILEGX_IMM16_X1_HW0_LAST_GOT = 73; enum R_TILEGX_IMM16_X0_HW1_LAST_GOT = 74; enum R_TILEGX_IMM16_X1_HW1_LAST_GOT = 75; enum R_TILEGX_IMM16_X0_HW3_PLT_PCREL = 76; enum R_TILEGX_IMM16_X1_HW3_PLT_PCREL = 77; enum R_TILEGX_IMM16_X0_HW0_TLS_GD = 78; enum R_TILEGX_IMM16_X1_HW0_TLS_GD = 79; enum R_TILEGX_IMM16_X0_HW0_TLS_LE = 80; enum R_TILEGX_IMM16_X1_HW0_TLS_LE = 81; enum R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE = 82; enum R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE = 83; enum R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE = 84; enum R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE = 85; enum R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD = 86; enum R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD = 87; enum R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD = 88; enum R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD = 89; enum R_TILEGX_IMM16_X0_HW0_TLS_IE = 92; enum R_TILEGX_IMM16_X1_HW0_TLS_IE = 93; enum R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL = 94; enum R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL = 95; enum R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL = 96; enum R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL = 97; enum R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL = 98; enum R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL = 99; enum R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE = 100; enum R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE = 101; enum R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE = 102; enum R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE = 103; enum R_TILEGX_TLS_DTPMOD64 = 106; enum R_TILEGX_TLS_DTPOFF64 = 107; enum R_TILEGX_TLS_TPOFF64 = 108; enum R_TILEGX_TLS_DTPMOD32 = 109; enum R_TILEGX_TLS_DTPOFF32 = 110; enum R_TILEGX_TLS_TPOFF32 = 111; enum R_TILEGX_TLS_GD_CALL = 112; enum R_TILEGX_IMM8_X0_TLS_GD_ADD = 113; enum R_TILEGX_IMM8_X1_TLS_GD_ADD = 114; enum R_TILEGX_IMM8_Y0_TLS_GD_ADD = 115; enum R_TILEGX_IMM8_Y1_TLS_GD_ADD = 116; enum R_TILEGX_TLS_IE_LOAD = 117; enum R_TILEGX_IMM8_X0_TLS_ADD = 118; enum R_TILEGX_IMM8_X1_TLS_ADD = 119; enum R_TILEGX_IMM8_Y0_TLS_ADD = 120; enum R_TILEGX_IMM8_Y1_TLS_ADD = 121; enum R_TILEGX_GNU_VTINHERIT = 128; enum R_TILEGX_GNU_VTENTRY = 129; enum R_TILEGX_NUM = 130; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/config.d0000664000175000017500000000131612776214756022572 0ustar kaikai/** * D header file for GNU/Linux * * Authors: Martin Nowak */ module core.sys.linux.config; version (linux): public import core.sys.posix.config; // man 7 feature_test_macros // http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html enum _GNU_SOURCE = true; // deduced // http://sourceware.org/git/?p=glibc.git;a=blob;f=include/features.h enum _BSD_SOURCE = true; enum _SVID_SOURCE = true; enum _ATFILE_SOURCE = true; enum __USE_MISC = _BSD_SOURCE || _SVID_SOURCE; enum __USE_BSD = _BSD_SOURCE; enum __USE_SVID = _SVID_SOURCE; enum __USE_ATFILE = _ATFILE_SOURCE; enum __USE_GNU = _GNU_SOURCE; // Available in bionic from API 21 version(CRuntime_Bionic) enum __WORDSIZE = 32; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/tipc.d0000664000175000017500000000721112776214756022264 0ustar kaikai/** * Interface for Linux TIPC sockets, /usr/include/linux/tipc.h * * Copyright: Public Domain * License: Public Domain * Authors: Leandro Lucarella */ module core.sys.linux.tipc; version (linux): extern (C) nothrow @nogc: struct tipc_portid { uint ref_; uint node; } struct tipc_name { uint type; uint instance; } struct tipc_name_seq { uint type; uint lower; uint upper; } struct tipc_subscr { tipc_name_seq seq; uint timeout; uint filter; ubyte[8] usr_handle; } struct tipc_event { uint event; uint found_lower; uint found_upper; tipc_portid port; tipc_subscr s; } struct sockaddr_tipc { ushort family; ubyte addrtype; byte scope_; union Addr { tipc_portid id; tipc_name_seq nameseq; static struct Name { tipc_name name; uint domain; } Name name; } Addr addr; } uint tipc_addr(uint zone, uint cluster, uint node) { return (zone << 24) | (cluster << 12) | node; } unittest { assert (tipc_addr(0, 0, 0) == 0); assert (tipc_addr(1, 1, 1) == 16781313); assert (tipc_addr(2, 1, 27) == 33558555); assert (tipc_addr(3, 1, 63) == 50335807); } uint tipc_zone(uint addr) { return addr >> 24; } unittest { assert (tipc_zone(0u) == 0); assert (tipc_zone(16781313u) == 1); assert (tipc_zone(33558555u) == 2); assert (tipc_zone(50335807u) == 3); } uint tipc_cluster(uint addr) { return (addr >> 12) & 0xfff; } unittest { assert (tipc_cluster(0u) == 0); assert (tipc_cluster(16781313u) == 1); assert (tipc_cluster(33558555u) == 1); assert (tipc_cluster(50335807u) == 1); } uint tipc_node(uint addr) { return addr & 0xfff; } unittest { assert (tipc_node(0u) == 0); assert (tipc_node(16781313u) == 1); assert (tipc_node(33558555u) == 27); assert (tipc_node(50335807u) == 63); } enum: int { TIPC_CFG_SRV = 0, TIPC_TOP_SRV = 1, TIPC_RESERVED_TYPES = 64, } enum: int { TIPC_ZONE_SCOPE = 1, TIPC_CLUSTER_SCOPE = 2, TIPC_NODE_SCOPE = 3, } enum: int { TIPC_MAX_USER_MSG_SIZE = 66000, } enum: int { TIPC_LOW_IMPORTANCE = 0, TIPC_MEDIUM_IMPORTANCE = 1, TIPC_HIGH_IMPORTANCE = 2, TIPC_CRITICAL_IMPORTANCE = 3, } enum: int { TIPC_OK = 0, TIPC_ERR_NO_NAME = 1, TIPC_ERR_NO_PORT = 2, TIPC_ERR_NO_NODE = 3, TIPC_ERR_OVERLOAD = 4, TIPC_CONN_SHUTDOWN = 5, } enum: int { TIPC_SUB_PORTS = 0x01, TIPC_SUB_SERVICE = 0x02, TIPC_SUB_CANCEL = 0x04, } version (none) enum: int { TIPC_SUB_NO_BIND_EVTS = 0x04, TIPC_SUB_NO_UNBIND_EVTS = 0x08, TIPC_SUB_SINGLE_EVT = 0x10, } enum: int { TIPC_WAIT_FOREVER = ~0, } enum: int { TIPC_PUBLISHED = 1, TIPC_WITHDRAWN = 2, TIPC_SUBSCR_TIMEOUT = 3, } enum: int { AF_TIPC = 30, PF_TIPC = 30, SOL_TIPC = 271, TIPC_ADDR_NAMESEQ = 1, TIPC_ADDR_MCAST = 1, TIPC_ADDR_NAME = 2, TIPC_ADDR_ID = 3, } enum: int { TIPC_ERRINFO = 1, TIPC_RETDATA = 2, TIPC_DESTNAME = 3, } enum: int { TIPC_IMPORTANCE = 127, TIPC_SRC_DROPPABLE = 128, TIPC_DEST_DROPPABLE = 129, TIPC_CONN_TIMEOUT = 130, } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/fcntl.d0000664000175000017500000000057712776214756022443 0ustar kaikaimodule core.sys.linux.fcntl; public import core.sys.posix.fcntl; version (linux): extern(C): nothrow: // From linux/falloc.h enum { FALLOC_FL_KEEP_SIZE = 0x01, FALLOC_FL_PUNCH_HOLE = 0x02, FALLOC_FL_NO_HIDE_STALE = 0x04 } // Linux-specific fallocate // (http://man7.org/linux/man-pages/man2/fallocate.2.html) int fallocate(int fd, int mode, off_t offset, off_t len); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/time.d0000664000175000017500000000113612776214756022263 0ustar kaikai//Written in the D programming language /++ D header file for Linux extensions to POSIX's time.h. Copyright: Copyright 2014 License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Jonathan M Davis +/ module core.sys.linux.time; public import core.sys.posix.time; version(linux): enum CLOCK_MONOTONIC_RAW = 4; enum CLOCK_REALTIME_COARSE = 5; enum CLOCK_MONOTONIC_COARSE = 6; enum CLOCK_BOOTTIME = 7; enum CLOCK_REALTIME_ALARM = 8; enum CLOCK_BOOTTIME_ALARM = 9; enum CLOCK_SGI_CYCLE = 10; enum CLOCK_TAI = 11; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/link.d0000664000175000017500000001056612776214756022271 0ustar kaikai/** * D header file for GNU/Linux * * $(LINK2 http://sourceware.org/git/?p=glibc.git;a=blob;f=elf/link.h, glibc elf/link.h) */ module core.sys.linux.link; version (linux): extern (C): nothrow: import core.stdc.stdint : uintptr_t, uint32_t, uint64_t; import core.sys.linux.config : __WORDSIZE; import core.sys.linux.dlfcn : Lmid_t; import core.sys.linux.elf; // version (X86) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/elfclass.h alias __WORDSIZE __ELF_NATIVE_CLASS; alias uint32_t Elf_Symndx; } else version (X86_64) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/elfclass.h alias __WORDSIZE __ELF_NATIVE_CLASS; alias uint32_t Elf_Symndx; } else version (MIPS32) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/elfclass.h alias __WORDSIZE __ELF_NATIVE_CLASS; alias uint32_t Elf_Symndx; } else version (MIPS64) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/elfclass.h alias __WORDSIZE __ELF_NATIVE_CLASS; alias uint32_t Elf_Symndx; } else version (PPC) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/elfclass.h alias __WORDSIZE __ELF_NATIVE_CLASS; alias uint32_t Elf_Symndx; } else version (PPC64) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/elfclass.h alias __WORDSIZE __ELF_NATIVE_CLASS; alias uint32_t Elf_Symndx; } else version (ARM) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/elfclass.h alias __WORDSIZE __ELF_NATIVE_CLASS; alias uint32_t Elf_Symndx; } else version (AArch64) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/elfclass.h alias __WORDSIZE __ELF_NATIVE_CLASS; alias uint32_t Elf_Symndx; } else version (SystemZ) { // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/elfclass.h alias __WORDSIZE __ELF_NATIVE_CLASS; alias uint64_t Elf_Symndx; } else static assert(0, "unimplemented"); // template ElfW(string type) { mixin("alias Elf"~__ELF_NATIVE_CLASS.stringof~"_"~type~" ElfW;"); } enum { RT_CONSISTENT, RT_ADD, RT_DELETE, } struct r_debug { int r_version; link_map* r_map; ElfW!"Addr" r_brk; typeof(RT_CONSISTENT) r_state; ElfW!"Addr" r_ldbase; } extern r_debug _r_debug; extern ElfW!"Dyn"* _DYNAMIC; struct link_map { ElfW!"Addr" l_addr; char* l_name; ElfW!"Dyn"* l_ld; link_map* l_next, l_prev; } enum { LA_ACT_CONSISTENT, LA_ACT_ADD, LA_ACT_DELETE, } enum { LA_SER_ORIG = 0x01, LA_SER_LIBPATH = 0x02, LA_SER_RUNPATH = 0x04, LA_SER_CONFIG = 0x08, LA_SER_DEFAULT = 0x40, LA_SER_SECURE = 0x80, } enum { LA_FLG_BINDTO = 0x01, LA_FLG_BINDFROM = 0x02, } enum { LA_SYMB_NOPLTENTER = 0x01, LA_SYMB_NOPLTEXIT = 0x02, LA_SYMB_STRUCTCALL = 0x04, LA_SYMB_DLSYM = 0x08, LA_SYMB_ALTVALUE = 0x10, } struct dl_phdr_info { ElfW!"Addr" dlpi_addr; const(char)* dlpi_name; const(ElfW!"Phdr")* dlpi_phdr; ElfW!"Half" dlpi_phnum; // check the SIZE argument of the dl_iterate_phdr callback whether // the following members are available ulong dlpi_adds; ulong dlpi_subs; size_t dlpi_tls_modid; void *dlpi_tls_data; } private alias extern(C) int function(dl_phdr_info*, size_t, void *) dl_iterate_phdr_cb; private alias extern(C) int function(dl_phdr_info*, size_t, void *) @nogc dl_iterate_phdr_cb_ngc; extern int dl_iterate_phdr(dl_iterate_phdr_cb __callback, void*__data); extern int dl_iterate_phdr(dl_iterate_phdr_cb_ngc __callback, void*__data) @nogc; // ld.so auditing interfaces prototypes have to be defined by the auditing DSO. extern uint la_version(uint __version); extern void la_activity(uintptr_t *__cookie, uint __flag); extern char* la_objsearch(const(char)* __name, uintptr_t* __cookie, uint __flag); extern uint la_objopen(link_map* __map, Lmid_t __lmid, uintptr_t* __cookie); extern void la_preinit(uintptr_t* __cookie); extern uintptr_t la_symbind32(Elf32_Sym* __sym, uint __ndx, uintptr_t* __refcook, uintptr_t* __defcook, uint *__flags, const(char)* __symname); extern uintptr_t la_symbind64(Elf64_Sym* __sym, uint __ndx, uintptr_t* __refcook, uintptr_t* __defcook, uint* __flags, const(char)* __symname); extern uint la_objclose(uintptr_t *__cookie); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/termios.d0000664000175000017500000000163012776214756023006 0ustar kaikai/** * D header file for GNU/Linux */ /* Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.linux.termios; version(linux): public import core.sys.posix.termios; enum B57600 = 0x1001; // 0010001 enum B115200 = 0x1002; // 0010002 enum B230400 = 0x1003; // 0010003 enum B460800 = 0x1004; // 0010004 enum B500000 = 0x1005; // 0010005 enum B576000 = 0x1006; // 0010006 enum B921600 = 0x1007; // 0010007 enum B1000000 = 0x1008; // 0010010 enum B1152000 = 0x1009; // 0010011 enum B1500000 = 0x100A; // 0010012 enum B2000000 = 0x100B; // 0010013 enum B2500000 = 0x100C; // 0010014 enum B3000000 = 0x100D; // 0010015 enum B3500000 = 0x100E; // 0010016 enum B4000000 = 0x100F; // 0010017 enum CRTSCTS = 0x80000000; // 020000000000 ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/unistd.d0000664000175000017500000000103112776214756022625 0ustar kaikaimodule core.sys.linux.unistd; public import core.sys.posix.unistd; version(linux): extern(C): nothrow: // Additional seek constants for sparse file handling // from Linux's unistd.h, stdio.h, and linux/fs.h // (see http://man7.org/linux/man-pages/man2/lseek.2.html) enum { /// Offset is relative to the next location containing data SEEK_DATA = 3, /// Offset is relative to the next hole (or EOF if file is not sparse) SEEK_HOLE = 4 } /// Prompt for a password without echoing it. char* getpass(const(char)* prompt); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/errno.d0000664000175000017500000000062412776214756022453 0ustar kaikai/** * D header file for GNU/Linux * * $(LINK2 http://sourceware.org/git/?p=glibc.git;a=blob;f=stdlib/errno.h, glibc stdlib/errno.h) */ module core.sys.linux.errno; version (linux): extern (C): nothrow: public import core.stdc.errno; import core.sys.linux.config; static if (__USE_GNU) { extern __gshared char* program_invocation_name, program_invocation_short_name; alias error_t = int; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/sys/0000775000175000017500000000000012776214756021775 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/sys/sysinfo.d0000664000175000017500000000232612776214756023637 0ustar kaikai/** * D header file for GNU/Linux. * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ module core.sys.linux.sys.sysinfo; version(linux) extern(C) @nogc nothrow: import core.sys.linux.config; // linux/sysinfo.h enum SI_LOAD_SHIFT = 16; struct sysinfo_ { c_long uptime; /* Seconds since boot */ c_ulong[3] loads; /* 1, 5, and 15 minute load averages */ c_ulong totalram; /* Total usable main memory size */ c_ulong freeram; /* Available memory size */ c_ulong sharedram; /* Amount of shared memory */ c_ulong bufferram; /* Memory used by buffers */ c_ulong totalswap; /* Total swap space size */ c_ulong freeswap; /* swap space still available */ ushort procs; /* Number of current processes */ ushort pad; /* Explicit padding for m68k */ c_ulong totalhigh; /* Total high memory size */ c_ulong freehigh; /* Available high memory size */ uint mem_unit; /* Memory unit size in bytes */ ubyte[20-2 * c_ulong.sizeof - uint.sizeof] _f; /* Padding: libc5 uses this.. */ } int sysinfo(sysinfo_ *info); int get_nprocs_conf(); int get_nprocs(); c_long get_phys_pages(); c_long get_avphys_pages(); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/sys/signalfd.d0000664000175000017500000000146212776214756023734 0ustar kaikai/** * D header file for Linux. * * Copyright: Copyright Alex Rønne Petersen 2012. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Alex Rønne Petersen */ module core.sys.linux.sys.signalfd; import core.sys.posix.signal; version (linux): extern (C): @system: nothrow: struct signalfd_siginfo { uint ssi_signo; int ssi_errno; int ssi_code; uint ssi_pid; uint ssi_uid; int ssi_fd; uint ssi_tid; uint ssi_band; uint ssi_overrun; uint ssi_trapno; int ssi_status; int ssi_int; ulong ssi_ptr; ulong ssi_utime; ulong ssi_stime; ulong ssi_addr; ubyte[48] __pad; } enum SFD_CLOEXEC = 0x80000; // 02000000 enum SFD_NONBLOCK = 0x800; // 04000 int signalfd (int __fd, const(sigset_t)* __mask, int __flags); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/sys/auxv.d0000664000175000017500000001700312776214756023126 0ustar kaikai/** * D header file for GNU/Linux. * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Kai Nacke */ module core.sys.linux.sys.auxv; import core.stdc.config; version (linux): extern (C): c_ulong getauxval(c_ulong type) nothrow pure @nogc @system; version(PPC) { // See https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/powerpc/bits/hwcap.h enum PPC_FEATURE_32 = 0x80000000; enum PPC_FEATURE_64 = 0x40000000; enum PPC_FEATURE_601_INSTR = 0x20000000; enum PPC_FEATURE_HAS_ALTIVEC = 0x10000000; enum PPC_FEATURE_HAS_FPU = 0x08000000; enum PPC_FEATURE_HAS_MMU = 0x04000000; enum PPC_FEATURE_HAS_4xxMAC = 0x02000000; enum PPC_FEATURE_UNIFIED_CACHE = 0x01000000; enum PPC_FEATURE_HAS_SPE = 0x00800000; enum PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000; enum PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000; enum PPC_FEATURE_NO_TB = 0x00100000; enum PPC_FEATURE_POWER4 = 0x00080000; enum PPC_FEATURE_POWER5 = 0x00040000; enum PPC_FEATURE_POWER5_PLUS = 0x00020000; enum PPC_FEATURE_CELL_BE = 0x00010000; enum PPC_FEATURE_BOOKE = 0x00008000; enum PPC_FEATURE_SMT = 0x00004000; enum PPC_FEATURE_ICACHE_SNOOP = 0x00002000; enum PPC_FEATURE_ARCH_2_05 = 0x00001000; enum PPC_FEATURE_PA6T = 0x00000800; enum PPC_FEATURE_HAS_DFP = 0x00000400; enum PPC_FEATURE_POWER6_EXT = 0x00000200; enum PPC_FEATURE_ARCH_2_06 = 0x00000100; enum PPC_FEATURE_HAS_VSX = 0x00000080; enum PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040; enum PPC_FEATURE_TRUE_LE = 0x00000002; enum PPC_FEATURE_PPC_LE = 0x00000001; enum PPC_FEATURE2_ARCH_2_07 = 0x80000000; enum PPC_FEATURE2_HAS_HTM = 0x40000000; enum PPC_FEATURE2_HAS_DSCR = 0x20000000; enum PPC_FEATURE2_HAS_EBB = 0x10000000; enum PPC_FEATURE2_HAS_ISEL = 0x08000000; enum PPC_FEATURE2_HAS_TAR = 0x04000000; enum PPC_FEATURE2_HAS_VEC_CRYPTO = 0x02000000; } else version(PPC64) { // See https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/powerpc/bits/hwcap.h enum PPC_FEATURE_32 = 0x80000000; enum PPC_FEATURE_64 = 0x40000000; enum PPC_FEATURE_601_INSTR = 0x20000000; enum PPC_FEATURE_HAS_ALTIVEC = 0x10000000; enum PPC_FEATURE_HAS_FPU = 0x08000000; enum PPC_FEATURE_HAS_MMU = 0x04000000; enum PPC_FEATURE_HAS_4xxMAC = 0x02000000; enum PPC_FEATURE_UNIFIED_CACHE = 0x01000000; enum PPC_FEATURE_HAS_SPE = 0x00800000; enum PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000; enum PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000; enum PPC_FEATURE_NO_TB = 0x00100000; enum PPC_FEATURE_POWER4 = 0x00080000; enum PPC_FEATURE_POWER5 = 0x00040000; enum PPC_FEATURE_POWER5_PLUS = 0x00020000; enum PPC_FEATURE_CELL_BE = 0x00010000; enum PPC_FEATURE_BOOKE = 0x00008000; enum PPC_FEATURE_SMT = 0x00004000; enum PPC_FEATURE_ICACHE_SNOOP = 0x00002000; enum PPC_FEATURE_ARCH_2_05 = 0x00001000; enum PPC_FEATURE_PA6T = 0x00000800; enum PPC_FEATURE_HAS_DFP = 0x00000400; enum PPC_FEATURE_POWER6_EXT = 0x00000200; enum PPC_FEATURE_ARCH_2_06 = 0x00000100; enum PPC_FEATURE_HAS_VSX = 0x00000080; enum PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040; enum PPC_FEATURE_TRUE_LE = 0x00000002; enum PPC_FEATURE_PPC_LE = 0x00000001; enum PPC_FEATURE2_ARCH_2_07 = 0x80000000; enum PPC_FEATURE2_HAS_HTM = 0x40000000; enum PPC_FEATURE2_HAS_DSCR = 0x20000000; enum PPC_FEATURE2_HAS_EBB = 0x10000000; enum PPC_FEATURE2_HAS_ISEL = 0x08000000; enum PPC_FEATURE2_HAS_TAR = 0x04000000; enum PPC_FEATURE2_HAS_VEC_CRYPTO = 0x02000000; } else version(SPARC) { // See https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/sparc/bits/hwcap.h enum HWCAP_SPARC_FLUSH = 0x00000001; enum HWCAP_SPARC_STBAR = 0x00000002; enum HWCAP_SPARC_SWAP = 0x00000004; enum HWCAP_SPARC_MULDIV = 0x00000008; enum HWCAP_SPARC_V9 = 0x00000010; enum HWCAP_SPARC_ULTRA3 = 0x00000020; enum HWCAP_SPARC_BLKINIT = 0x00000040; enum HWCAP_SPARC_N2 = 0x00000080; enum HWCAP_SPARC_MUL32 = 0x00000100; enum HWCAP_SPARC_DIV32 = 0x00000200; enum HWCAP_SPARC_FSMULD = 0x00000400; enum HWCAP_SPARC_V8PLUS = 0x00000800; enum HWCAP_SPARC_POPC = 0x00001000; enum HWCAP_SPARC_VIS = 0x00002000; enum HWCAP_SPARC_VIS2 = 0x00004000; enum HWCAP_SPARC_ASI_BLK_INIT = 0x00008000; enum HWCAP_SPARC_FMAF = 0x00010000; enum HWCAP_SPARC_VIS3 = 0x00020000; enum HWCAP_SPARC_HPC = 0x00040000; enum HWCAP_SPARC_RANDOM = 0x00080000; enum HWCAP_SPARC_TRANS = 0x00100000; enum HWCAP_SPARC_FJFMAU = 0x00200000; enum HWCAP_SPARC_IMA = 0x00400000; enum HWCAP_SPARC_ASI_CACHE_SPARING = 0x00800000; enum HWCAP_SPARC_PAUSE = 0x01000000; enum HWCAP_SPARC_CBCOND = 0x02000000; enum HWCAP_SPARC_CRYPTO = 0x04000000; } else version(SPARC64) { // See https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/sparc/bits/hwcap.h enum HWCAP_SPARC_FLUSH = 0x00000001; enum HWCAP_SPARC_STBAR = 0x00000002; enum HWCAP_SPARC_SWAP = 0x00000004; enum HWCAP_SPARC_MULDIV = 0x00000008; enum HWCAP_SPARC_V9 = 0x00000010; enum HWCAP_SPARC_ULTRA3 = 0x00000020; enum HWCAP_SPARC_BLKINIT = 0x00000040; enum HWCAP_SPARC_N2 = 0x00000080; enum HWCAP_SPARC_MUL32 = 0x00000100; enum HWCAP_SPARC_DIV32 = 0x00000200; enum HWCAP_SPARC_FSMULD = 0x00000400; enum HWCAP_SPARC_V8PLUS = 0x00000800; enum HWCAP_SPARC_POPC = 0x00001000; enum HWCAP_SPARC_VIS = 0x00002000; enum HWCAP_SPARC_VIS2 = 0x00004000; enum HWCAP_SPARC_ASI_BLK_INIT = 0x00008000; enum HWCAP_SPARC_FMAF = 0x00010000; enum HWCAP_SPARC_VIS3 = 0x00020000; enum HWCAP_SPARC_HPC = 0x00040000; enum HWCAP_SPARC_RANDOM = 0x00080000; enum HWCAP_SPARC_TRANS = 0x00100000; enum HWCAP_SPARC_FJFMAU = 0x00200000; enum HWCAP_SPARC_IMA = 0x00400000; enum HWCAP_SPARC_ASI_CACHE_SPARING = 0x00800000; enum HWCAP_SPARC_PAUSE = 0x01000000; enum HWCAP_SPARC_CBCOND = 0x02000000; enum HWCAP_SPARC_CRYPTO = 0x04000000; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/sys/mman.d0000664000175000017500000004320312776214756023074 0ustar kaikai/** * D header file for GNU/Linux * * Authors: Martin Nowak */ module core.sys.linux.sys.mman; version (linux): extern (C): nothrow: public import core.sys.posix.sys.mman; import core.sys.linux.config; // // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/powerpc/bits/mman.h version (PPC) { enum PROT_SAO = 0x10; static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x00080, MAP_NORESERVE = 0x00040, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } // in core.sys.posix.sys.mman // enum // { // MCL_CURRENT = 0x2000, // MCL_FUTURE = 0x4000, // } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/powerpc/bits/mman.h else version (PPC64) { enum PROT_SAO = 0x10; static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x00080, MAP_NORESERVE = 0x00040, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } // in core.sys.posix.sys.mman // enum // { // MCL_CURRENT = 0x2000, // MCL_FUTURE = 0x4000, // } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/s390/bits/mman.h else version (S390) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x02000, MAP_NORESERVE = 0x04000, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/s390/bits/mman.h else version (SystemZ) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x02000, MAP_NORESERVE = 0x04000, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sh/bits/mman.h else version (SH) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x0100, MAP_DENYWRITE = 0x0800, MAP_EXECUTABLE = 0x1000, MAP_LOCKED = 0x2000, MAP_NORESERVE = 0x4000, MAP_POPULATE = 0x8000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sh/bits/mman.h else version (SH64) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x0100, MAP_DENYWRITE = 0x0800, MAP_EXECUTABLE = 0x1000, MAP_LOCKED = 0x2000, MAP_NORESERVE = 0x4000, MAP_POPULATE = 0x8000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sparc/bits/mman.h else version (SPARC) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x0200, MAP_DENYWRITE = 0x0800, MAP_EXECUTABLE = 0x1000, MAP_LOCKED = 0x0100, MAP_NORESERVE = 0x0040, _MAP_NEW = 0x80000000, MAP_POPULATE = 0x8000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } // in core.sys.posix.sys.mman // enum // { // MCL_CURRENT = 0x2000, // MCL_FUTURE = 0x4000, // } static if (__USE_MISC) enum MAP_RENAME MAP_ANONYMOUS; } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sparc/bits/mman.h else version (SPARC64) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x0200, MAP_DENYWRITE = 0x0800, MAP_EXECUTABLE = 0x1000, MAP_LOCKED = 0x0100, MAP_NORESERVE = 0x0040, _MAP_NEW = 0x80000000, MAP_POPULATE = 0x8000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } // in core.sys.posix.sys.mman // enum // { // MCL_CURRENT = 0x2000, // MCL_FUTURE = 0x4000, // } static if (__USE_MISC) enum MAP_RENAME MAP_ANONYMOUS; } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86/bits/mman.h else version (X86) { static if (__USE_MISC) enum MAP_32BIT = 0x40; static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x02000, MAP_NORESERVE = 0x04000, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86/bits/mman.h else version (X86_64) { static if (__USE_MISC) enum MAP_32BIT = 0x40; static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x02000, MAP_NORESERVE = 0x04000, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/unix/sysv/linux/aarch64/bits/mman.h else version (AArch64) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x02000, MAP_NORESERVE = 0x04000, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/unix/sysv/linux/alpha/bits/mman.h else version (Alpha) { enum { PROT_READ = 0x1, PROT_WRITE = 0x2, PROT_EXEC = 0x4, PROT_NONE = 0x0, PROT_GROWSDOWN = 0x01000000, PROT_GROWSUP = 0x02000000, } enum MAP_SHARED = 0x01; enum MAP_PRIVATE = 0x02; static if (__USE_MISC) enum MAP_TYPE = 0x0f; enum MAP_FIXED = 0x10; static if (__USE_MISC) enum { MAP_FILE = 0, MAP_ANONYMOUS = MAP_ANON, // in core.sys.posix.sys.mman // MAP_ANON = MAP_ANONYMOUS, MAP_HUGE_SHIFT = 26, MAP_HUGE_MASK = 0x3f, } static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x01000, MAP_DENYWRITE = 0x02000, MAP_EXECUTABLE = 0x04000, MAP_LOCKED = 0x08000, MAP_NORESERVE = 0x10000, MAP_POPULATE = 0x20000, MAP_NONBLOCK = 0x40000, MAP_STACK = 0x80000, MAP_HUGETLB = 0x100000, } // in core.sys.posix.sys.mman // enum // { // MS_ASYNC = 1, // MS_SYNC = 2, // MS_INVALIDATE = 4, // } // in core.sys.posix.sys.mman // enum // { // MCL_CURRENT = 8192, // MCL_FUTURE = 16384, // } static if (__USE_GNU) enum { MREMAP_MAYMOVE = 1, MREMAP_FIXED = 2, } static if (__USE_BSD) enum { MADV_NORMAL = 0, MADV_RANDOM = 1, MADV_SEQUENTIAL = 2, MADV_WILLNEED = 3, MADV_DONTNEED = 6, MADV_REMOVE = 9, MADV_DONTFORK = 10, MADV_DOFORK = 11, MADV_MERGEABLE = 12, MADV_UNMERGEABLE = 13, MADV_HUGEPAGE = 14, MADV_NOHUGEPAGE = 15, MADV_DONTDUMP = 16, MADV_DODUMP = 17, MADV_HWPOISON = 100, } // in core.sys.posix.sys.mman // static if (__USE_XOPEN2K) enum // { // POSIX_MADV_NORMAL = 0, // POSIX_MADV_RANDOM = 1, // POSIX_MADV_SEQUENTIAL = 2, // POSIX_MADV_WILLNEED = 3, // POSIX_MADV_DONTNEED = 6, // } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/unix/sysv/linux/arm/bits/mman.h else version (ARM) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x02000, MAP_NORESERVE = 0x04000, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/unix/sysv/linux/hppa/bits/mman.h else version (HPPA) { enum { PROT_READ = 0x1, PROT_WRITE = 0x2, PROT_EXEC = 0x4, PROT_NONE = 0x0, PROT_GROWSDOWN = 0x01000000, PROT_GROWSUP = 0x02000000, } enum MAP_SHARED = 0x01; enum MAP_PRIVATE = 0x02; static if (__USE_MISC) enum MAP_TYPE = 0x0f; enum MAP_FIXED = 0x04; static if (__USE_MISC) enum { MAP_FILE = 0, MAP_ANONYMOUS = MAP_ANON, // in core.sys.posix.sys.mman // MAP_ANON = MAP_ANONYMOUS, MAP_VARIABLE = 0, MAP_HUGE_SHIFT = 26, MAP_HUGE_MASK = 0x3f, } static if (__USE_MISC) enum { MAP_DENYWRITE = 0x0800, MAP_EXECUTABLE = 0x1000, MAP_LOCKED = 0x2000, MAP_NORESERVE = 0x4000, MAP_GROWSDOWN = 0x8000, MAP_POPULATE = 0x10000, MAP_NONBLOCK = 0x20000, } // in core.sys.posix.sys.mman // enum // { // MS_ASYNC = 1, // MS_SYNC = 2, // MS_INVALIDATE = 4, // } // in core.sys.posix.sys.mman // enum // { // MCL_CURRENT = 1, // MCL_FUTURE = 2, // } static if (__USE_GNU) enum { MREMAP_MAYMOVE = 1, MREMAP_FIXED = 2, } static if (__USE_BSD) enum { MADV_NORMAL = 0, MADV_RANDOM = 1, MADV_SEQUENTIAL = 2, MADV_WILLNEED = 3, MADV_DONTNEED = 4, MADV_SPACEAVAIL = 5, MADV_VPS_PURGE = 6, MADV_VPS_INHERIT = 7, MADV_REMOVE = 9, MADV_DONTFORK = 10, MADV_DOFORK = 11, MADV_MERGEABLE = 65, MADV_UNMERGEABLE = 66, } enum { MADV_4K_PAGES = 12, MADV_16K_PAGES = 14, MADV_64K_PAGES = 16, MADV_256K_PAGES = 18, MADV_1M_PAGES = 20, MADV_4M_PAGES = 22, MADV_16M_PAGES = 24, MADV_64M_PAGES = 26, } // in core.sys.posix.sys.mman // static if (__USE_XOPEN2K) enum // { // POSIX_MADV_NORMAL = 0, // POSIX_MADV_RANDOM = 1, // POSIX_MADV_SEQUENTIAL = 2, // POSIX_MADV_WILLNEED = 3, // POSIX_MADV_DONTNEED = 4, // } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/unix/sysv/linux/hppa/bits/mman.h else version (HPPA64) { enum { PROT_READ = 0x1, PROT_WRITE = 0x2, PROT_EXEC = 0x4, PROT_NONE = 0x0, PROT_GROWSDOWN = 0x01000000, PROT_GROWSUP = 0x02000000, } enum MAP_SHARED = 0x01; enum MAP_PRIVATE = 0x02; static if (__USE_MISC) enum MAP_TYPE = 0x0f; enum MAP_FIXED = 0x04; static if (__USE_MISC) enum { MAP_FILE = 0, MAP_ANONYMOUS = MAP_ANON, // in core.sys.posix.sys.mman // MAP_ANON = MAP_ANONYMOUS, MAP_VARIABLE = 0, MAP_HUGE_SHIFT = 26, MAP_HUGE_MASK = 0x3f, } static if (__USE_MISC) enum { MAP_DENYWRITE = 0x0800, MAP_EXECUTABLE = 0x1000, MAP_LOCKED = 0x2000, MAP_NORESERVE = 0x4000, MAP_GROWSDOWN = 0x8000, MAP_POPULATE = 0x10000, MAP_NONBLOCK = 0x20000, } // in core.sys.posix.sys.mman // enum // { // MS_ASYNC = 1, // MS_SYNC = 2, // MS_INVALIDATE = 4, // } // in core.sys.posix.sys.mman // enum // { // MCL_CURRENT = 1, // MCL_FUTURE = 2, // } static if (__USE_GNU) enum { MREMAP_MAYMOVE = 1, MREMAP_FIXED = 2, } static if (__USE_BSD) enum { MADV_NORMAL = 0, MADV_RANDOM = 1, MADV_SEQUENTIAL = 2, MADV_WILLNEED = 3, MADV_DONTNEED = 4, MADV_SPACEAVAIL = 5, MADV_VPS_PURGE = 6, MADV_VPS_INHERIT = 7, MADV_REMOVE = 9, MADV_DONTFORK = 10, MADV_DOFORK = 11, MADV_MERGEABLE = 65, MADV_UNMERGEABLE = 66, } enum { MADV_4K_PAGES = 12, MADV_16K_PAGES = 14, MADV_64K_PAGES = 16, MADV_256K_PAGES = 18, MADV_1M_PAGES = 20, MADV_4M_PAGES = 22, MADV_16M_PAGES = 24, MADV_64M_PAGES = 26, } // in core.sys.posix.sys.mman // static if (__USE_XOPEN2K) enum // { // POSIX_MADV_NORMAL = 0, // POSIX_MADV_RANDOM = 1, // POSIX_MADV_SEQUENTIAL = 2, // POSIX_MADV_WILLNEED = 3, // POSIX_MADV_DONTNEED = 4, // } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/unix/sysv/linux/ia64/bits/mman.h else version (IA64) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_GROWSUP = 0x00200, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x02000, MAP_NORESERVE = 0x04000, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/unix/sysv/linux/m68k/bits/mman.h else version (M68K) { static if (__USE_MISC) enum { MAP_GROWSDOWN = 0x00100, MAP_DENYWRITE = 0x00800, MAP_EXECUTABLE = 0x01000, MAP_LOCKED = 0x02000, MAP_NORESERVE = 0x04000, MAP_POPULATE = 0x08000, MAP_NONBLOCK = 0x10000, MAP_STACK = 0x20000, MAP_HUGETLB = 0x40000, } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/unix/sysv/linux/mips/bits/mman.h else version (MIPS32) { static if (__USE_MISC) enum { MAP_NORESERVE = 0x0400, MAP_GROWSDOWN = 0x1000, MAP_DENYWRITE = 0x2000, MAP_EXECUTABLE = 0x4000, MAP_LOCKED = 0x8000, MAP_POPULATE = 0x10000, MAP_NONBLOCK = 0x20000, MAP_STACK = 0x40000, MAP_HUGETLB = 0x80000, } static if (__USE_MISC) enum MAP_RENAME = MAP_ANONYMOUS; } // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/unix/sysv/linux/mips/bits/mman.h else version (MIPS64) { static if (__USE_MISC) enum { MAP_NORESERVE = 0x0400, MAP_GROWSDOWN = 0x1000, MAP_DENYWRITE = 0x2000, MAP_EXECUTABLE = 0x4000, MAP_LOCKED = 0x8000, MAP_POPULATE = 0x10000, MAP_NONBLOCK = 0x20000, MAP_STACK = 0x40000, MAP_HUGETLB = 0x80000, } static if (__USE_MISC) enum MAP_RENAME = MAP_ANONYMOUS; } else { static assert(0, "unimplemented"); } // http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/bits/mman-linux.h version (Alpha) { } else version (HPPA) { } else version (HPPA64) { } else { // in core.sys.posix.sys.mman // enum PROT_READ = 0x1; // enum PROT_WRITE = 0x2; // enum PROT_EXEC = 0x4; // enum PROT_NONE = 0x0; enum PROT_GROWSDOWN = 0x01000000; enum PROT_GROWSUP = 0x02000000; enum MAP_SHARED = 0x01; enum MAP_PRIVATE = 0x02; static if (__USE_MISC) enum MAP_TYPE = 0x0f; enum MAP_FIXED = 0x10; static if (__USE_MISC) enum { MAP_FILE = 0, MAP_ANONYMOUS = MAP_ANON, // in core.sys.posix.sys.mman // MAP_ANON = 0xXX, MAP_HUGE_SHIFT = 26, MAP_HUGE_MASK = 0x3f, } // in core.sys.posix.sys.mman // enum // { // MS_ASYNC = 1, // MS_SYNC = 4, // MS_INVALIDATE = 2, // } static if (__USE_GNU) enum { MREMAP_MAYMOVE = 1, MREMAP_FIXED = 2, } static if (__USE_BSD) enum { MADV_NORMAL = 0, MADV_RANDOM = 1, MADV_SEQUENTIAL = 2, MADV_WILLNEED = 3, MADV_DONTNEED = 4, MADV_REMOVE = 9, MADV_DONTFORK = 10, MADV_DOFORK = 11, MADV_MERGEABLE = 12, MADV_UNMERGEABLE = 13, MADV_HWPOISON = 100, } // in core.sys.posix.sys.mman // static if (__USE_XOPEN2K) enum // { // POSIX_MADV_NORMAL = 0, // POSIX_MADV_RANDOM = 1, // POSIX_MADV_SEQUENTIAL = 2, // POSIX_MADV_WILLNEED = 3, // POSIX_MADV_DONTNEED = 4, // } // in core.sys.posix.sys.mman // enum // { // // MCL_CURRENT = 1, // MCL_FUTURE = 2, // } } // http://sourceware.org/git/?p=glibc.git;a=blob;f=misc/sys/mman.h // in core.sys.posix.sys.mman // static if (__USE_LARGEFILE64) void* mmap64(void*, size_t, int, int, int, off_t); // static if (__USE_FILE_OFFSET64) // alias mmap64 mmap; // else // void* mmap(void*, size_t, int, int, int, off_t); // int munmap(void*, size_t); // int mprotect(void *__addr, size_t __len, int __prot); // int msync(void *__addr, size_t __len, int __flags); static if (__USE_BSD) int madvise(void *__addr, size_t __len, int __advice); // static if (__USE_XOPEN2K) int posix_madvise(void *__addr, size_t __len, int __advice); // int mlock(const(void) *__addr, size_t __len); // int munlock(const(void) *__addr, size_t __len); // int mlockall(int __flags); // int munlockall(); static if (__USE_MISC) int mincore(void *__start, size_t __len, ubyte *__vec); static if (__USE_GNU) void *mremap(void *__addr, size_t __old_len, size_t __new_len, int __flags, ...); static if (__USE_GNU) int remap_file_pages(void *__start, size_t __size, int __prot, size_t __pgoff, int __flags); // int shm_open(in char *__name, int __oflag, mode_t __mode); // int shm_unlink(in char *__name); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/sys/inotify.d0000664000175000017500000000460212776214756023625 0ustar kaikai/** * D header file for GNU/Linux. * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Gary Willoughby */ module core.sys.linux.sys.inotify; version (linux): extern (C): @system: nothrow: struct inotify_event { int wd; uint mask; uint cookie; uint len; char[0] name; } enum: uint { IN_ACCESS = 0x00000000, IN_MODIFY = 0x00000002, IN_ATTRIB = 0x00000004, IN_CLOSE_WRITE = 0x00000008, IN_CLOSE_NOWRITE = 0x00000010, IN_OPEN = 0x00000020, IN_MOVED_FROM = 0x00000040, IN_MOVED_TO = 0x00000080, IN_CREATE = 0x00000100, IN_DELETE = 0x00000200, IN_DELETE_SELF = 0x00000400, IN_MOVE_SELF = 0x00000800, IN_UMOUNT = 0x00002000, IN_Q_OVERFLOW = 0x00004000, IN_IGNORED = 0x00008000, IN_CLOSE = 0x00000018, IN_MOVE = 0x000000C0, IN_ONLYDIR = 0x01000000, IN_DONT_FOLLOW = 0x02000000, IN_EXCL_UNLINK = 0x04000000, IN_MASK_ADD = 0x20000000, IN_ISDIR = 0x40000000, IN_ONESHOT = 0x80000000, IN_ALL_EVENTS = 0x80000FFF, } version (X86) { enum IN_CLOEXEC = 0x80000; // octal!2000000 enum IN_NONBLOCK = 0x800; // octal!4000 } else version (X86_64) { enum IN_CLOEXEC = 0x80000; // octal!2000000 enum IN_NONBLOCK = 0x800; // octal!4000 } else version (MIPS32) { enum IN_CLOEXEC = 0x80000; // octal!2000000 enum IN_NONBLOCK = 0x80; // octal!200 } else version (MIPS64) { enum IN_CLOEXEC = 0x80000; // octal!2000000 enum IN_NONBLOCK = 0x80; // octal!200 } else version (PPC) { enum IN_CLOEXEC = 0x80000; // octal!2000000 enum IN_NONBLOCK = 0x800; // octal!4000 } else version (PPC64) { enum IN_CLOEXEC = 0x80000; // octal!2000000 enum IN_NONBLOCK = 0x800; // octal!4000 } else version (ARM) { enum IN_CLOEXEC = 0x80000; // octal!2000000 enum IN_NONBLOCK = 0x800; // octal!4000 } else version (AArch64) { enum IN_CLOEXEC = 0x80000; // octal!2000000 enum IN_NONBLOCK = 0x800; // octal!4000 } else version (SystemZ) { enum IN_CLOEXEC = 0x80000; // octal!2000000 enum IN_NONBLOCK = 0x800; // octal!4000 } else static assert(0, "unimplemented"); int inotify_init(); int inotify_init1(int flags); int inotify_add_watch(int fd, const(char)* name, uint mask); int inotify_rm_watch(int fd, uint wd); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/sys/socket.d0000664000175000017500000000051012776214756023426 0ustar kaikai/** * D header file for GNU/Linux. * * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Paul O'Neil */ module core.sys.linux.sys.socket; public import core.sys.posix.sys.socket; version(linux): extern(C): @nogc: nothrow: enum { AF_RXRPC = 33, PF_RXRPC = AF_RXRPC, } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/sys/xattr.d0000664000175000017500000000512112776214756023303 0ustar kaikai/** * D header file for GNU/Linux. * * Copyright: Copyright Robert Klotzner 2012. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Robert Klotzner */ module core.sys.linux.sys.xattr; import core.sys.posix.sys.types; version (linux): extern (C): @system: nothrow: enum { XATTR_CREATE = 1, /* set value, fail if attr already exists. */ XATTR_REPLACE = 2 /* set value, fail if attr does not exist. */ } enum XATTR_OS2_PREFIX = "os2."; enum XATTR_OS2_PREFIX_LEN = XATTR_OS2_PREFIX.length; enum XATTR_SECURITY_PREFIX = "security."; enum XATTR_SECURITY_PREFIX_LEN = XATTR_SECURITY_PREFIX.length; enum XATTR_SYSTEM_PREFIX = "system."; enum XATTR_SYSTEM_PREFIX_LEN = XATTR_SYSTEM_PREFIX.length; enum XATTR_TRUSTED_PREFIX = "trusted."; enum XATTR_TRUSTED_PREFIX_LEN = XATTR_TRUSTED_PREFIX.length; enum XATTR_USER_PREFIX = "user."; enum XATTR_USER_PREFIX_LEN = XATTR_USER_PREFIX.length; /* Security namespace */ enum XATTR_SELINUX_SUFFIX = "selinux."; enum XATTR_NAME_SELINUX = XATTR_SECURITY_PREFIX ~ XATTR_SELINUX_SUFFIX; enum XATTR_SMACK_SUFFIX = "SMACK64"; enum XATTR_SMACK_IPIN = "SMACK64IPIN"; enum XATTR_SMACK_IPOUT = "SMACK64IPOUT"; enum XATTR_SMACK_EXEC = "SMACK64EXEC"; enum XATTR_SMACK_TRANSMUTE = "SMACK64TRANSMUTE"; enum XATTR_SMACK_MMAP = "SMACK64MMAP"; enum XATTR_NAME_SMACK = XATTR_SECURITY_PREFIX ~ XATTR_SMACK_SUFFIX; enum XATTR_NAME_SMACKIPIN = XATTR_SECURITY_PREFIX ~ XATTR_SMACK_IPIN; enum XATTR_NAME_SMACKIPOUT = XATTR_SECURITY_PREFIX ~ XATTR_SMACK_IPOUT; enum XATTR_NAME_SMACKEXEC = XATTR_SECURITY_PREFIX ~ XATTR_SMACK_EXEC; enum XATTR_NAME_SMACKTRANSMUTE = XATTR_SECURITY_PREFIX ~ XATTR_SMACK_TRANSMUTE; enum XATTR_NAME_SMACKMMAP = XATTR_SECURITY_PREFIX ~ XATTR_SMACK_MMAP; enum XATTR_CAPS_SUFFIX = "capability"; enum XATTR_NAME_CAPS = XATTR_SECURITY_PREFIX ~ XATTR_CAPS_SUFFIX; int setxattr(in char* path, in char* name, in void* value, size_t size, int flags); int lsetxattr(in char* path, in char* name, in void* value, size_t size, int flags); int fsetxattr(int fd, in char* name, in void* value, size_t size, int flags); ssize_t getxattr(in char* path, in char* name, void* value, size_t size); ssize_t lgetxattr(in char* path, in char* name, void* value, size_t size); ssize_t fgetxattr(int fd, in char* name, void* value, size_t size); ssize_t listxattr(in char* path, char* list, size_t size); ssize_t llistxattr(in char* path, char* list, size_t size); ssize_t flistxattr (int __fd, char *list, size_t size); int removexattr (in char *path, in char *name); int lremovexattr (in char *path, in char *name); int fremovexattr (int fd, in char *name); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/linux/epoll.d0000664000175000017500000000445712776214756022451 0ustar kaikai/** * D header file to interface with the Linux epoll API (http://man7.org/linux/man-pages/man7/epoll.7.html). * Available since Linux 2.6 * * Copyright: Copyright Adil Baig 2012. * License : $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors : Adil Baig (github.com/adilbaig) */ module core.sys.linux.epoll; version (linux): extern (C): @system: nothrow: enum { EPOLL_CLOEXEC = 0x80000, EPOLL_NONBLOCK = 0x800 } enum { EPOLLIN = 0x001, EPOLLPRI = 0x002, EPOLLOUT = 0x004, EPOLLRDNORM = 0x040, EPOLLRDBAND = 0x080, EPOLLWRNORM = 0x100, EPOLLWRBAND = 0x200, EPOLLMSG = 0x400, EPOLLERR = 0x008, EPOLLHUP = 0x010, EPOLLRDHUP = 0x2000, // since Linux 2.6.17 EPOLLONESHOT = 1u << 30, EPOLLET = 1u << 31 } /* Valid opcodes ( "op" parameter ) to issue to epoll_ctl(). */ enum { EPOLL_CTL_ADD = 1, // Add a file descriptor to the interface. EPOLL_CTL_DEL = 2, // Remove a file descriptor from the interface. EPOLL_CTL_MOD = 3, // Change file descriptor epoll_event structure. } version (X86) { align(1) struct epoll_event { align(1): uint events; epoll_data_t data; } } else version (X86_64) { align(1) struct epoll_event { align(1): uint events; epoll_data_t data; } } else version (ARM) { struct epoll_event { uint events; epoll_data_t data; } } else version (AArch64) { struct epoll_event { uint events; epoll_data_t data; } } else version (PPC) { struct epoll_event { uint events; epoll_data_t data; } } else version (PPC64) { struct epoll_event { uint events; epoll_data_t data; } } else version (MIPS64) { struct epoll_event { uint events; epoll_data_t data; } } else version (SystemZ) { struct epoll_event { uint events; epoll_data_t data; } } else { static assert(false, "Platform not supported"); } union epoll_data_t { void *ptr; int fd; uint u32; ulong u64; } int epoll_create (int size); int epoll_create1 (int flags); int epoll_ctl (int epfd, int op, int fd, epoll_event *event); int epoll_wait (int epfd, epoll_event *events, int maxevents, int timeout); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/bionic/0000775000175000017500000000000012776214756021263 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/bionic/fcntl.d0000664000175000017500000000014412776214756022535 0ustar kaikaimodule core.sys.bionic.fcntl; version(CRuntime_Bionic) extern(C) nothrow @nogc: enum LOCK_EX = 2; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/bionic/unistd.d0000664000175000017500000000016112776214756022734 0ustar kaikaimodule core.sys.bionic.unistd; version(CRuntime_Bionic) extern(C) nothrow @nogc: int flock(int, int) @trusted; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/0000775000175000017500000000000012776214756020631 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/execinfo.d0000664000175000017500000000064312776214756022601 0ustar kaikai/** * D header file for OSX. * * Copyright: Copyright Martin Nowak 2012. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ module core.sys.osx.execinfo; version (OSX): extern (C): nothrow: int backtrace(void** buffer, int size); char** backtrace_symbols(const(void*)* buffer, int size); void backtrace_symbols_fd(const(void*)* buffer, int size, int fd); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/mach/0000775000175000017500000000000012776214756021541 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/mach/semaphore.d0000664000175000017500000000316012776214756023671 0ustar kaikai/** * D header file for OSX. * * Copyright: Copyright Sean Kelly 2008 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly */ /* Copyright Sean Kelly 2008 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.osx.mach.semaphore; version (OSX): extern (C): nothrow: public import core.sys.osx.mach.kern_return; public import core.sys.osx.mach.port; alias mach_port_t task_t; alias mach_port_t thread_t; alias mach_port_t semaphore_t; alias int sync_policy_t; alias int clock_res_t; struct mach_timespec_t { uint tv_sec; clock_res_t tv_nsec; } enum { SYNC_POLICY_FIFO = 0x0, SYNC_POLICY_FIXED_PRIORITY = 0x1, SYNC_POLICY_REVERSED = 0x2, SYNC_POLICY_ORDER_MASK = 0x3, SYNC_POLICY_LIFO = (SYNC_POLICY_FIFO | SYNC_POLICY_REVERSED), SYNC_POLICY_MAX = 0x7, } task_t mach_task_self(); kern_return_t semaphore_create(task_t, semaphore_t*, int, int); kern_return_t semaphore_destroy(task_t, semaphore_t); kern_return_t semaphore_signal(semaphore_t); kern_return_t semaphore_signal_all(semaphore_t); kern_return_t semaphore_signal_thread(semaphore_t, thread_t); kern_return_t semaphore_wait(semaphore_t); kern_return_t semaphore_wait_signal(semaphore_t, semaphore_t); kern_return_t semaphore_timedwait(semaphore_t, mach_timespec_t); kern_return_t semaphore_timedwait_signal(semaphore_t, semaphore_t, mach_timespec_t); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/mach/loader.d0000664000175000017500000000432712776214756023162 0ustar kaikai/** * Copyright: Copyright Digital Mars 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Jacob Carlborg * Version: Initial created: Feb 20, 2010 */ /* Copyright Digital Mars 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.osx.mach.loader; version (OSX): extern (C): struct mach_header { uint magic; int cputype; int cpusubtype; uint filetype; uint ncmds; uint sizeofcmds; uint flags; } struct mach_header_64 { uint magic; int cputype; int cpusubtype; uint filetype; uint ncmds; uint sizeofcmds; uint flags; uint reserved; } enum uint MH_MAGIC = 0xfeedface; enum uint MH_CIGAM = 0xcefaedfe; enum uint MH_MAGIC_64 = 0xfeedfacf; enum uint MH_CIGAM_64 = 0xcffaedfe; enum SEG_PAGEZERO = "__PAGEZERO"; enum SEG_TEXT = "__TEXT"; enum SECT_TEXT = "__text"; enum SECT_FVMLIB_INIT0 = "__fvmlib_init0"; enum SECT_FVMLIB_INIT1 = "__fvmlib_init1"; enum SEG_DATA = "__DATA"; enum SECT_DATA = "__data"; enum SECT_BSS = "__bss"; enum SECT_COMMON = "__common"; enum SEG_OBJC = "__OBJC"; enum SECT_OBJC_SYMBOLS = "__symbol_table"; enum SECT_OBJC_MODULES = "__module_info"; enum SECT_OBJC_STRINGS = "__selector_strs"; enum SECT_OBJC_REFS = "__selector_refs"; enum SEG_ICON = "__ICON"; enum SECT_ICON_HEADER = "__header"; enum SECT_ICON_TIFF = "__tiff"; enum SEG_LINKEDIT = "__LINKEDIT"; enum SEG_UNIXSTACK = "__UNIXSTACK"; enum SEG_IMPORT = "__IMPORT"; struct section { char[16] sectname; char[16] segname; uint addr; uint size; uint offset; uint align_; uint reloff; uint nreloc; uint flags; uint reserved1; uint reserved2; } struct section_64 { char[16] sectname; char[16] segname; ulong addr; ulong size; uint offset; uint align_; uint reloff; uint nreloc; uint flags; uint reserved1; uint reserved2; uint reserved3; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/mach/dyld.d0000664000175000017500000000161312776214756022643 0ustar kaikai/** * Copyright: Copyright Digital Mars 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Jacob Carlborg * Version: Initial created: Feb 20, 2010 */ /* Copyright Digital Mars 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.osx.mach.dyld; version (OSX): extern (C): public import core.stdc.stdint; // for intptr_t public import core.sys.osx.mach.loader; uint _dyld_image_count(); const(char)* _dyld_get_image_name(uint image_index); mach_header* _dyld_get_image_header(uint image_index); void _dyld_register_func_for_add_image(void function(in mach_header* mh, intptr_t vmaddr_slide)); void _dyld_register_func_for_remove_image(void function(in mach_header* mh, intptr_t vmaddr_slide)); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/mach/kern_return.d0000664000175000017500000000454312776214756024252 0ustar kaikai/** * D header file for OSX. * * Copyright: Copyright Sean Kelly 2008 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly */ /* Copyright Sean Kelly 2008 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.osx.mach.kern_return; version (OSX): extern (C): alias int kern_return_t; enum : kern_return_t { KERN_SUCCESS = 0, KERN_INVALID_ADDRESS = 1, KERN_PROTECTION_FAILURE = 2, KERN_NO_SPACE = 3, KERN_INVALID_ARGUMENT = 4, KERN_FAILURE = 5, KERN_RESOURCE_SHORTAGE = 6, KERN_NOT_RECEIVER = 7, KERN_NO_ACCESS = 8, KERN_MEMORY_FAILURE = 9, KERN_MEMORY_ERROR = 10, KERN_ALREADY_IN_SET = 11, KERN_NOT_IN_SET = 12, KERN_NAME_EXISTS = 13, KERN_ABORTED = 14, KERN_INVALID_NAME = 15, KERN_INVALID_TASK = 16, KERN_INVALID_RIGHT = 17, KERN_INVALID_VALUE = 18, KERN_UREFS_OVERFLOW = 19, KERN_INVALID_CAPABILITY = 20, KERN_RIGHT_EXISTS = 21, KERN_INVALID_HOST = 22, KERN_MEMORY_PRESENT = 23, KERN_MEMORY_DATA_MOVED = 24, KERN_MEMORY_RESTART_COPY = 25, KERN_INVALID_PROCESSOR_SET = 26, KERN_POLICY_LIMIT = 27, KERN_INVALID_POLICY = 28, KERN_INVALID_OBJECT = 29, KERN_ALREADY_WAITING = 30, KERN_DEFAULT_SET = 31, KERN_EXCEPTION_PROTECTED = 32, KERN_INVALID_LEDGER = 33, KERN_INVALID_MEMORY_CONTROL = 34, KERN_INVALID_SECURITY = 35, KERN_NOT_DEPRESSED = 36, KERN_TERMINATED = 37, KERN_LOCK_SET_DESTROYED = 38, KERN_LOCK_UNSTABLE = 39, KERN_LOCK_OWNED = 40, KERN_LOCK_OWNED_SELF = 41, KERN_SEMAPHORE_DESTROYED = 42, KERN_RPC_SERVER_TERMINATED = 43, KERN_RPC_TERMINATE_ORPHAN = 44, KERN_RPC_CONTINUE_ORPHAN = 45, KERN_NOT_SUPPORTED = 46, KERN_NODE_DOWN = 47, KERN_OPERATION_TIMED_OUT = 49, KERN_RETURN_MAX = 0x100, } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/mach/getsect.d0000664000175000017500000000131212776214756023341 0ustar kaikai/** * Copyright: Copyright Digital Mars 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Jacob Carlborg * Version: Initial created: Mar 16, 2010 */ /* Copyright Digital Mars 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.osx.mach.getsect; version (OSX): extern (C): public import core.sys.osx.mach.loader; const(section)* getsectbynamefromheader(in mach_header* mhp, in char* segname, in char* sectname); const(section_64)* getsectbynamefromheader_64(in mach_header_64* mhp, in char* segname, in char* sectname); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/mach/port.d0000664000175000017500000000114512776214756022673 0ustar kaikai/** * D header file for OSX. * * Copyright: Copyright Sean Kelly 2008 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly */ /* Copyright Sean Kelly 2008 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.osx.mach.port; version (OSX): extern (C): version( X86 ) version = i386; version( X86_64 ) version = i386; version( i386 ) { alias uint natural_t; alias natural_t mach_port_t; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/mach/thread_act.d0000664000175000017500000000627112776214756024012 0ustar kaikai/** * D header file for OSX. * * Copyright: Copyright Sean Kelly 2008 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly */ /* Copyright Sean Kelly 2008 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.osx.mach.thread_act; version (OSX): extern (C): nothrow: public import core.sys.osx.mach.kern_return; public import core.sys.osx.mach.port; version( X86 ) version = i386; version( X86_64 ) version = i386; version( i386 ) { alias mach_port_t thread_act_t; alias void thread_state_t; alias int thread_state_flavor_t; alias natural_t mach_msg_type_number_t; enum { x86_THREAD_STATE32 = 1, x86_FLOAT_STATE32 = 2, x86_EXCEPTION_STATE32 = 3, x86_THREAD_STATE64 = 4, x86_FLOAT_STATE64 = 5, x86_EXCEPTION_STATE64 = 6, x86_THREAD_STATE = 7, x86_FLOAT_STATE = 8, x86_EXCEPTION_STATE = 9, x86_DEBUG_STATE32 = 10, x86_DEBUG_STATE64 = 11, x86_DEBUG_STATE = 12, THREAD_STATE_NONE = 13, } struct x86_thread_state32_t { uint eax; uint ebx; uint ecx; uint edx; uint edi; uint esi; uint ebp; uint esp; uint ss; uint eflags; uint eip; uint cs; uint ds; uint es; uint fs; uint gs; } struct x86_thread_state64_t { ulong rax; ulong rbx; ulong rcx; ulong rdx; ulong rdi; ulong rsi; ulong rbp; ulong rsp; ulong r8; ulong r9; ulong r10; ulong r11; ulong r12; ulong r13; ulong r14; ulong r15; ulong rip; ulong rflags; ulong cs; ulong fs; ulong gs; } struct x86_state_hdr_t { int flavor; int count; } struct x86_thread_state_t { x86_state_hdr_t tsh; union _uts { x86_thread_state32_t ts32; x86_thread_state64_t ts64; } _uts uts; } enum : mach_msg_type_number_t { x86_THREAD_STATE32_COUNT = cast(mach_msg_type_number_t)( x86_thread_state32_t.sizeof / int.sizeof ), x86_THREAD_STATE64_COUNT = cast(mach_msg_type_number_t)( x86_thread_state64_t.sizeof / int.sizeof ), x86_THREAD_STATE_COUNT = cast(mach_msg_type_number_t)( x86_thread_state_t.sizeof / int.sizeof ), } alias x86_THREAD_STATE MACHINE_THREAD_STATE; alias x86_THREAD_STATE_COUNT MACHINE_THREAD_STATE_COUNT; mach_port_t mach_thread_self(); kern_return_t thread_suspend(thread_act_t); kern_return_t thread_resume(thread_act_t); kern_return_t thread_get_state(thread_act_t, thread_state_flavor_t, thread_state_t*, mach_msg_type_number_t*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/pthread.d0000664000175000017500000000361012776214756022425 0ustar kaikai/** * D header file for OSX. * * Copyright: Copyright Sean Kelly 2008 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly */ /* Copyright Sean Kelly 2008 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.osx.pthread; version (OSX): extern (C): nothrow: public import core.sys.posix.pthread; public import core.sys.osx.mach.port; int pthread_is_threaded_np(); int pthread_threadid_np(pthread_t, ulong*); // ^ __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2) int pthread_rwlock_longrdlock_np(pthread_rwlock_t*); int pthread_rwlock_yieldwrlock_np(pthread_rwlock_t*); // ^ __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); int pthread_rwlock_downgrade_np(pthread_rwlock_t*); int pthread_rwlock_upgrade_np(pthread_rwlock_t*); int pthread_rwlock_tryupgrade_np(pthread_rwlock_t*); int pthread_rwlock_held_np(pthread_rwlock_t*); int pthread_rwlock_rdheld_np(pthread_rwlock_t*); int pthread_rwlock_wrheld_np(pthread_rwlock_t*); int pthread_getname_np(pthread_t, char*, size_t); int pthread_setname_np(in char*); // ^ __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2) int pthread_main_np(); mach_port_t pthread_mach_thread_np(pthread_t); size_t pthread_get_stacksize_np(pthread_t); void* pthread_get_stackaddr_np(pthread_t); int pthread_cond_signal_thread_np(pthread_cond_t*, pthread_t); int pthread_cond_timedwait_relative_np(pthread_cond_t*, pthread_mutex_t*, in timespec*); int pthread_create_suspended_np(pthread_t*, in pthread_attr_t*, void* function(void*), void*); int pthread_kill(pthread_t, int); pthread_t pthread_from_mach_thread_np(mach_port_t); // ^ __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0) int pthread_sigmask(int, in sigset_t*, sigset_t*); // ^ __DARWIN_ALIAS(pthread_sigmask) void pthread_yield_np(); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/sys/0000775000175000017500000000000012776214756021447 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/sys/mman.d0000664000175000017500000000501512776214756022545 0ustar kaikai/** * D header file for FreeBSD * * Authors: Martin Nowak */ module core.sys.osx.sys.mman; version (OSX): extern (C): nothrow: public import core.sys.posix.sys.mman; import core.sys.osx.sys.cdefs; import core.sys.posix.sys.types; // already in core.sys.posix.sys.mman // enum PROT_NONE = 0x00; // enum PROT_READ = 0x01; // enum PROT_WRITE = 0x02; // enum PROT_EXEC = 0x04; // already in core.sys.posix.sys.mman // enum MAP_SHARED = 0x0001; // enum MAP_PRIVATE = 0x0002; static if (_DARWIN_C_SOURCE) alias MAP_COPY = MAP_PRIVATE; // enum MAP_FIXED = 0x0010; static if (_DARWIN_C_SOURCE) { enum MAP_RENAME = 0x0020; enum MAP_NORESERVE = 0x0040; enum MAP_RESERVED0080 = 0x0080; enum MAP_NOEXTEND = 0x0100; enum MAP_HASSEMAPHORE = 0x0200; enum MAP_NOCACHE = 0x0400; enum MAP_JIT = 0x0800; } // already in core.sys.posix.sys.mman // enum MCL_CURRENT = 0x0001; // enum MCL_FUTURE = 0x0002; // enum MAP_FAILED = cast(void*)-1; // enum MS_ASYNC = 0x0001; // enum MS_INVALIDATE = 0x0002; // enum MS_SYNC = 0x0010; static if (_DARWIN_C_SOURCE) { enum MS_KILLPAGES = 0x0004; enum MS_DEACTIVATE = 0x0008; enum MAP_FILE = 0x0000; // already in core.sys.posix.sys.mman // enum MAP_ANON = 0x1000; // enum POSIX_MADV_NORMAL = 0; // enum POSIX_MADV_RANDOM = 1; // enum POSIX_MADV_SEQUENTIAL = 2; // enum POSIX_MADV_WILLNEED = 3; // enum POSIX_MADV_DONTNEED = 4; alias MADV_NORMAL = POSIX_MADV_NORMAL; alias MADV_RANDOM = POSIX_MADV_RANDOM; alias MADV_SEQUENTIAL = POSIX_MADV_SEQUENTIAL; alias MADV_WILLNEED = POSIX_MADV_WILLNEED; alias MADV_DONTNEED = POSIX_MADV_DONTNEED; enum MADV_FREE = 5; enum MADV_ZERO_WIRED_PAGES = 6; enum MADV_FREE_REUSABLE = 7; enum MADV_FREE_REUSE = 8; enum MADV_CAN_REUSE = 9; enum MINCORE_INCORE = 0x1; enum MINCORE_REFERENCED = 0x2; enum MINCORE_MODIFIED = 0x4; enum MINCORE_REFERENCED_OTHER = 0x8; enum MINCORE_MODIFIED_OTHER = 0x10; } // already in core.sys.posix.sys.mman // int mlockall(int); // int munlockall(void); // int mlock(const void *, size_t); // void * mmap(void *, size_t, int, int, int, off_t); // int mprotect(void *, size_t, int); // int msync(void *, size_t, int); // int munlock(const void *, size_t); // int munmap(void *, size_t); // int shm_open(const char *, int, ...); // int shm_unlink(const char *); // int posix_madvise(void *, size_t, int); static if (_DARWIN_C_SOURCE) { int madvise(void *, size_t, int); int mincore(const(void)*, size_t, char *); int minherit(void *, size_t, int); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/sys/event.d0000664000175000017500000001047612776214756022745 0ustar kaikai/** * D header file for OSX. * * Copyright: Copyright Martin Nowak 2012. Etienne Cimon 2015. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak */ /* Copyright Martin Nowak 2012. Etienne Cimon 2015. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.osx.sys.event; version (OSX): extern (C): import core.stdc.stdint; // intptr_t, uintptr_t import core.sys.posix.time; // timespec enum : short { EVFILT_READ = -1, EVFILT_WRITE = -2, EVFILT_AIO = -3, /* attached to aio requests */ EVFILT_VNODE = -4, /* attached to vnodes */ EVFILT_PROC = -5, /* attached to struct proc */ EVFILT_SIGNAL = -6, /* attached to struct proc */ EVFILT_TIMER = -7, /* timers */ EVFILT_MACHPORT = -8, /* Mach portsets */ EVFILT_FS = -9, /* filesystem events */ EVFILT_USER = -10, /* User events */ EVFILT_VM = -12, /* virtual memory events */ EVFILT_SYSCOUNT = 11 } extern(D) void EV_SET(kevent_t* kevp, typeof(kevent_t.tupleof) args) { *kevp = kevent_t(args); } struct kevent_t { uintptr_t ident; /* identifier for this event */ short filter; /* filter for event */ ushort flags; uint fflags; intptr_t data; void *udata; /* opaque user data identifier */ } enum { /* actions */ EV_ADD = 0x0001, /* add event to kq (implies enable) */ EV_DELETE = 0x0002, /* delete event from kq */ EV_ENABLE = 0x0004, /* enable event */ EV_DISABLE = 0x0008, /* disable event (not reported) */ /* flags */ EV_ONESHOT = 0x0010, /* only report one occurrence */ EV_CLEAR = 0x0020, /* clear event state after reporting */ EV_RECEIPT = 0x0040, /* force EV_ERROR on success, data=0 */ EV_DISPATCH = 0x0080, /* disable event after reporting */ EV_SYSFLAGS = 0xF000, /* reserved by system */ EV_FLAG1 = 0x2000, /* filter-specific flag */ /* returned values */ EV_EOF = 0x8000, /* EOF detected */ EV_ERROR = 0x4000, /* error, data contains errno */ } enum { /* * data/hint flags/masks for EVFILT_USER, shared with userspace * * On input, the top two bits of fflags specifies how the lower twenty four * bits should be applied to the stored value of fflags. * * On output, the top two bits will always be set to NOTE_FFNOP and the * remaining twenty four bits will contain the stored fflags value. */ NOTE_FFNOP = 0x00000000, /* ignore input fflags */ NOTE_FFAND = 0x40000000, /* AND fflags */ NOTE_FFOR = 0x80000000, /* OR fflags */ NOTE_FFCOPY = 0xc0000000, /* copy fflags */ NOTE_FFCTRLMASK = 0xc0000000, /* masks for operations */ NOTE_FFLAGSMASK = 0x00ffffff, NOTE_TRIGGER = 0x01000000, /* Cause the event to be triggered for output. */ /* * data/hint flags for EVFILT_{READ|WRITE}, shared with userspace */ NOTE_LOWAT = 0x0001, /* low water mark */ /* * data/hint flags for EVFILT_VNODE, shared with userspace */ NOTE_DELETE = 0x0001, /* vnode was removed */ NOTE_WRITE = 0x0002, /* data contents changed */ NOTE_EXTEND = 0x0004, /* size increased */ NOTE_ATTRIB = 0x0008, /* attributes changed */ NOTE_LINK = 0x0010, /* link count changed */ NOTE_RENAME = 0x0020, /* vnode was renamed */ NOTE_REVOKE = 0x0040, /* vnode access was revoked */ /* * data/hint flags for EVFILT_PROC, shared with userspace */ NOTE_EXIT = 0x80000000, /* process exited */ NOTE_FORK = 0x40000000, /* process forked */ NOTE_EXEC = 0x20000000, /* process exec'd */ NOTE_PCTRLMASK = 0xf0000000, /* mask for hint bits */ NOTE_PDATAMASK = 0x000fffff, /* mask for pid */ /* additional flags for EVFILT_PROC */ NOTE_TRACK = 0x00000001, /* follow across forks */ NOTE_TRACKERR = 0x00000002, /* could not track child */ NOTE_CHILD = 0x00000004, /* am a child process */ } int kqueue(); int kevent(int kq, const kevent_t *changelist, int nchanges, kevent_t *eventlist, int nevents, const timespec *timeout); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/osx/sys/cdefs.d0000664000175000017500000000051012776214756022674 0ustar kaikai/** * D header file for OSX * * Authors: Martin Nowak */ module core.sys.osx.sys.cdefs; version (OSX): public import core.sys.posix.config; // http://www.opensource.apple.com/source/xnu/xnu-2422.115.4/bsd/sys/cdefs.h enum _DARWIN_C_SOURCE = true; enum __DARWIN_C_FULL = 900000L; enum __DARWIN_C_LEVEL = __DARWIN_C_FULL; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/0000775000175000017500000000000012776214756021474 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/dlfcn.d0000664000175000017500000000443212776214756022732 0ustar kaikai/** * D header file for Solaris * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/head/dlfcn.h, illumos dlfcn.h) */ module core.sys.solaris.dlfcn; version (Solaris): extern (C): nothrow: public import core.sys.posix.dlfcn; import core.stdc.config; // enum RTLD_LAZY = 0x00001; // POSIX // enum RTLD_NOW = 0x00002; // POSIX enum RTLD_NOLOAD = 0x00004; enum RTLD_DEEPBIND = 0x00008; // enum RTLD_GLOBAL = 0x00100; // POSIX // enum RTLD_LOCAL = 0; // POSIX enum RTLD_PARENT = 0x00200; enum RTLD_GROUP = 0x00400; enum RTLD_WORLD = 0x00800; enum RTLD_NODELETE = 0x01000; enum RTLD_FIRST = 0x02000; enum RTLD_CONFGEN = 0x10000; enum { RTLD_NEXT = cast(void *)-1, RTLD_DEFAULT = cast(void *)-2, RTLD_SELF = cast(void *)-3, RTLD_PROBE = cast(void *)-4, } alias c_ulong Lmid_t; void* dlmopen(Lmid_t, in char*, int); enum { RTLD_REL_RELATIVE = 0x00001, RTLD_REL_EXEC = 0x00002, RTLD_REL_DEPENDS = 0x00004, RTLD_REL_PRELOAD = 0x00008, RTLD_REL_SELF = 0x00010, RTLD_REL_WEAK = 0x00020, RTLD_REL_ALL = 0x00fff, RTLD_MEMORY = 0x01000, RTLD_STRIP = 0x02000, RTLD_NOHEAP = 0x04000, RTLD_CONFSET = 0x10000, } int dldump(in char*, in char*, int); struct Dl_info { const(char)* dli_fname; void* dli_fbase; const(char)* dli_sname; void* dli_saddr; } enum { RTLD_DL_SYMENT = 1, RTLD_DL_LINKMAP = 2, } int dladdr(const(void)*, Dl_info*); int dladdr1(void*, Dl_info*, void**, int); enum { RTLD_DI_LMID = 1, RTLD_DI_LINKMAP = 2, RTLD_DI_CONFIGADDR = 3, RTLD_DI_SERINFO = 4, RTLD_DI_SERINFOSIZE = 5, RTLD_DI_ORIGIN = 6, RTLD_DI_PROFILENAME = 7, RTLD_DI_PROFILEOUT = 8, RTLD_DI_GETSIGNAL = 9, RTLD_DI_SETSIGNAL = 10, RTLD_DI_ARGSINFO = 11, RTLD_DI_MMAPS = 12, RTLD_DI_MMAPCNT = 13, RTLD_DI_DEFERRED = 14, RTLD_DI_DEFERRED_SYM = 15, RTLD_DI_MAX = 15, } int dlinfo(void*, int, void*); struct Dl_serpath { char* dls_name; uint dls_flags; } struct Dl_serinfo { size_t dls_size; uint dls_cnt; Dl_serpath[1] dls_serpath; } // FIXME: Dl_argsinfo, Dl_mapinfo, Dl_amd64_unwindinfo are missingldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/execinfo.d0000664000175000017500000000100112776214756023431 0ustar kaikai/** * D header file for Solaris. * * Copyright: Copyright Martin Nowak 2012. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Martin Nowak */ module core.sys.solaris.execinfo; // The interface is exactly the same as linux, so copied from linux's execinfo.d version (Solaris): extern (C): nothrow: int backtrace(void** buffer, int size); char** backtrace_symbols(const(void*)* buffer, int size); void backtrace_symbols_fd(const(void*)* buffer, int size, int fd); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/elf.d0000664000175000017500000000036612776214756022414 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/head/elf.h, illumos elf.h) */ module core.sys.solaris.elf; version (Solaris): extern (C): nothrow: public import core.sys.solaris.sys.elf; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/libelf.d0000664000175000017500000000670212776214756023103 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/head/libelf.h, illumos libelf.h) */ module core.sys.solaris.libelf; version (Solaris): extern (C): nothrow: import core.stdc.config; import core.sys.posix.sys.types; import core.sys.solaris.sys.elf; enum Elf_Cmd { ELF_C_NULL = 0, ELF_C_READ, ELF_C_WRITE, ELF_C_CLR, ELF_C_SET, ELF_C_FDDONE, ELF_C_FDREAD, ELF_C_RDWR, ELF_C_WRIMAGE, ELF_C_IMAGE, ELF_C_NUM } enum ELF_F_DIRTY = 0x1; enum ELF_F_LAYOUT = 0x4; enum Elf_Kind { ELF_K_NONE = 0, ELF_K_AR, ELF_K_COFF, ELF_K_ELF, ELF_K_NUM } enum Elf_Type { ELF_T_BYTE = 0, ELF_T_ADDR, ELF_T_DYN, ELF_T_EHDR, ELF_T_HALF, ELF_T_OFF, ELF_T_PHDR, ELF_T_RELA, ELF_T_REL, ELF_T_SHDR, ELF_T_SWORD, ELF_T_SYM, ELF_T_WORD, ELF_T_VDEF, ELF_T_VNEED, ELF_T_SXWORD, ELF_T_XWORD, ELF_T_SYMINFO, ELF_T_NOTE, ELF_T_MOVE, ELF_T_MOVEP, ELF_T_CAP, ELF_T_NUM } struct Elf { } struct Elf_Scn { } struct Elf_Arhdr { char* ar_name; time_t ar_date; uid_t ar_uid; gid_t ar_gid; mode_t ar_mode; off_t ar_size; char* ar_rawname; } struct Elf_Arsym { char* as_name; size_t as_off; c_ulong as_hash; } struct Elf_Data { void* d_buf; Elf_Type d_type; size_t d_size; off_t d_off; size_t d_align; uint d_version; } Elf* elf_begin(int, Elf_Cmd, Elf*); int elf_cntl(Elf*, Elf_Cmd); int elf_end(Elf*); const(char)* elf_errmsg(int); int elf_errno(); void elf_fill(int); uint elf_flagdata(Elf_Data*, Elf_Cmd, uint); uint elf_flagehdr(Elf*, Elf_Cmd, uint); uint elf_flagelf(Elf*, Elf_Cmd, uint); uint elf_flagphdr(Elf*, Elf_Cmd, uint); uint elf_flagscn(Elf_Scn*, Elf_Cmd, uint); uint elf_flagshdr(Elf_Scn*, Elf_Cmd, uint); size_t elf32_fsize(Elf_Type, size_t, uint); Elf_Arhdr* elf_getarhdr(Elf*); Elf_Arsym* elf_getarsym(Elf*, size_t*); off_t elf_getbase(Elf*); Elf_Data* elf_getdata(Elf_Scn*, Elf_Data*); Elf32_Ehdr* elf32_getehdr(Elf*); char* elf_getident(Elf*, size_t*); Elf32_Phdr* elf32_getphdr(Elf*); Elf_Scn* elf_getscn(Elf*, size_t); Elf32_Shdr* elf32_getshdr(Elf_Scn*); int elf_getphnum(Elf*, size_t*); int elf_getphdrnum(Elf*, size_t*); int elf_getshnum(Elf*, size_t*); int elf_getshdrnum(Elf*, size_t*); int elf_getshstrndx(Elf*, size_t*); int elf_getshdrstrndx(Elf*, size_t*); c_ulong elf_hash(in char*); uint elf_sys_encoding(); long elf32_checksum(Elf*); Elf_Kind elf_kind(Elf*); Elf* elf_memory(char*, size_t); size_t elf_ndxscn(Elf_Scn*); Elf_Data* elf_newdata(Elf_Scn*); Elf32_Ehdr* elf32_newehdr(Elf*); Elf32_Phdr* elf32_newphdr(Elf*, size_t); Elf_Scn* elf_newscn(Elf*); Elf_Scn* elf_nextscn(Elf*, Elf_Scn*); Elf_Cmd elf_next(Elf*); size_t elf_rand(Elf*, size_t); Elf_Data* elf_rawdata(Elf_Scn*, Elf_Data*); char* elf_rawfile(Elf*, size_t*); char* elf_strptr(Elf*, size_t, size_t); off_t elf_update(Elf*, Elf_Cmd); uint elf_version(uint); Elf_Data* elf32_xlatetof(Elf_Data*, in Elf_Data*, uint); Elf_Data* elf32_xlatetom(Elf_Data*, in Elf_Data*, uint); version(D_LP64) { size_t elf64_fsize(Elf_Type, size_t, uint); Elf64_Ehdr* elf64_getehdr(Elf*); Elf64_Phdr* elf64_getphdr(Elf*); Elf64_Shdr* elf64_getshdr(Elf_Scn*); long elf64_checksum(Elf*); Elf64_Ehdr* elf64_newehdr(Elf*); Elf64_Phdr* elf64_newphdr(Elf*, size_t); Elf_Data* elf64_xlatetof(Elf_Data*, in Elf_Data*, uint); Elf_Data* elf64_xlatetom(Elf_Data*, in Elf_Data*, uint); }ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/time.d0000664000175000017500000000071712776214756022604 0ustar kaikai//Written in the D programming language /++ D header file for Solaris's extensions to POSIX's time.h. Copyright: Copyright 2014 License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Kai Nacke +/ module core.sys.solaris.time; public import core.sys.posix.time; version(Solaris): enum CLOCK_VIRTUAL = 1; enum CLOCK_HIGHRES = CLOCK_MONOTONIC; enum CLOCK_PROF = CLOCK_THREAD_CPUTIME_ID; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/link.d0000664000175000017500000001124312776214756022577 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/head/link.h, illumos link.h) */ module core.sys.solaris.link; version (Solaris): extern (C): nothrow: import core.stdc.stdint; import core.sys.solaris.dlfcn; import core.sys.solaris.libelf; import core.sys.solaris.sys.elf; import core.sys.solaris.sys.link; uint ld_version(uint); void ld_input_done(uint*); void ld_start(in char*, in Elf32_Half, in char*); void ld_atexit(int); void ld_open(in char**, in char**, int*, int, Elf**, Elf*, size_t, in Elf_Kind); void ld_file(in char*, in Elf_Kind, int, Elf*); void ld_input_section(in char*, Elf32_Shdr**, Elf32_Word, Elf_Data*, Elf*, uint*); void ld_section(in char*, Elf32_Shdr*, Elf32_Word, Elf_Data*, Elf*); version(D_LP64) { void ld_start64(in char*, in Elf64_Half, in char*); void ld_atexit64(int); void ld_open64(in char**, in char**, int*, int, Elf**, Elf*, size_t, in Elf_Kind); void ld_file64(in char*, in Elf_Kind, int, Elf*); void ld_input_section64(in char*, Elf64_Shdr**, Elf64_Word, Elf_Data*, Elf*, uint*); void ld_section64(in char*, Elf64_Shdr*, Elf64_Word, Elf_Data*, Elf*); } enum LD_SUP_VNONE = 0; enum LD_SUP_VERSION1 = 1; enum LD_SUP_VERSION2 = 2; enum LD_SUP_VERSION3 = 3; enum LD_SUP_VCURRENT = LD_SUP_VERSION3; enum LD_SUP_DERIVED = 0x1; enum LD_SUP_INHERITED = 0x2; enum LD_SUP_EXTRACTED = 0x4; enum LM_ID_BASE = 0x00; enum LM_ID_LDSO = 0x01; enum LM_ID_NUM = 2; enum LM_ID_BRAND = 0xfd; enum LM_ID_NONE = 0xfe; enum LM_ID_NEWLM = 0xff; enum LAV_NONE = 0; enum LAV_VERSION1 = 1; enum LAV_VERSION2 = 2; enum LAV_VERSION3 = 3; enum LAV_VERSION4 = 4; enum LAV_VERSION5 = 5; enum LAV_CURRENT = LAV_VERSION5; enum LAV_NUM = 6; enum LA_FLG_BINDTO = 0x0001; enum LA_FLG_BINDFROM = 0x0002; enum LA_SYMB_NOPLTENTER = 0x0001; enum LA_SYMB_NOPLTEXIT = 0x0002; enum LA_SYMB_STRUCTCALL = 0x0004; enum LA_SYMB_DLSYM = 0x0008; enum LA_SYMB_ALTVALUE = 0x0010; enum LA_SER_ORIG = 0x001; enum LA_SER_LIBPATH = 0x002; enum LA_SER_RUNPATH = 0x004; enum LA_SER_CONFIG = 0x008; enum LA_SER_DEFAULT = 0x040; enum LA_SER_SECURE = 0x080; enum LA_SER_MASK = 0xfff; enum LA_ACT_CONSISTENT = 0x00; enum LA_ACT_ADD = 0x01; enum LA_ACT_DELETE = 0x02; enum LA_ACT_MAX = 3; version(D_LP64) alias long lagreg_t; else alias int lagreg_t; struct _la_sparc_regs { lagreg_t lr_rego0; lagreg_t lr_rego1; lagreg_t lr_rego2; lagreg_t lr_rego3; lagreg_t lr_rego4; lagreg_t lr_rego5; lagreg_t lr_rego6; lagreg_t lr_rego7; } version(D_LP64) { alias _la_sparc_regs La_sparcv9_regs; struct La_amd64_regs { lagreg_t lr_rsp; lagreg_t lr_rbp; lagreg_t lr_rdi; lagreg_t lr_rsi; lagreg_t lr_rdx; lagreg_t lr_rcx; lagreg_t lr_r8; lagreg_t lr_r9; } } else { alias _la_sparc_regs La_sparcv8_regs; struct La_i86_regs { lagreg_t lr_esp; lagreg_t lr_ebp; } } uint la_version(uint); void la_activity(uintptr_t*, uint); void la_preinit(uintptr_t*); char* la_objsearch(in char*, uintptr_t*, uint); uint la_objopen(Link_map*, Lmid_t, uintptr_t*); uint la_objclose(uintptr_t*); int la_objfilter(uintptr_t*, in char*, uintptr_t*, uint); version(D_LP64) { uintptr_t la_amd64_pltenter(Elf64_Sym*, uint, uintptr_t*, uintptr_t*, La_amd64_regs*, uint*, in char*); uintptr_t la_symbind64(Elf64_Sym*, uint, uintptr_t*, uintptr_t*, uint*, in char*); uintptr_t la_sparcv9_pltenter(Elf64_Sym*, uint, uintptr_t*, uintptr_t*, La_sparcv9_regs*, uint*, in char*); uintptr_t la_pltexit64(Elf64_Sym*, uint, uintptr_t*, uintptr_t*, uintptr_t, in char*); } else { uintptr_t la_symbind32(Elf32_Sym*, uint, uintptr_t*, uintptr_t*, uint*); uintptr_t la_sparcv8_pltenter(Elf32_Sym*, uint, uintptr_t*, uintptr_t*, La_sparcv8_regs*, uint*); uintptr_t la_i86_pltenter(Elf32_Sym*, uint, uintptr_t*, uintptr_t*, La_i86_regs*, uint*); uintptr_t la_pltexit(Elf32_Sym*, uint, uintptr_t*, uintptr_t*, uintptr_t); } template ElfW(string type) { version (D_LP64) mixin("alias Elf64_"~type~" ElfW;"); else mixin("alias Elf32_"~type~" ElfW;"); } struct dl_phdr_info { ElfW!"Addr" dlpi_addr; char* dlpi_name; ElfW!"Phdr"* dlpi_phdr; ElfW!"Half" dlpi_phnum; uint64_t dlpi_adds; uint64_t dlpi_subs; }; private alias extern(C) int function(dl_phdr_info*, size_t, void *) dl_iterate_phdr_cb; private alias extern(C) int function(dl_phdr_info*, size_t, void *) @nogc dl_iterate_phdr_cb_ngc; extern int dl_iterate_phdr(dl_iterate_phdr_cb __callback, void*__data); extern int dl_iterate_phdr(dl_iterate_phdr_cb_ngc __callback, void*__data) @nogc; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/0000775000175000017500000000000012776214756022312 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/elf_386.d0000664000175000017500000000414612776214756023632 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/sys/elf_386.h, illumos sys/elf_386.h) */ module core.sys.solaris.sys.elf_386; version (Solaris): extern (C): nothrow: enum R_386_NONE = 0; enum R_386_32 = 1; enum R_386_PC32 = 2; enum R_386_GOT32 = 3; enum R_386_PLT32 = 4; enum R_386_COPY = 5; enum R_386_GLOB_DAT = 6; enum R_386_JMP_SLOT = 7; enum R_386_RELATIVE = 8; enum R_386_GOTOFF = 9; enum R_386_GOTPC = 10; enum R_386_32PLT = 11; enum R_386_TLS_GD_PLT = 12; enum R_386_TLS_LDM_PLT = 13; enum R_386_TLS_TPOFF = 14; enum R_386_TLS_IE = 15; enum R_386_TLS_GOTIE = 16; enum R_386_TLS_LE = 17; enum R_386_TLS_GD = 18; enum R_386_TLS_LDM = 19; enum R_386_16 = 20; enum R_386_PC16 = 21; enum R_386_8 = 22; enum R_386_PC8 = 23; enum R_386_UNKNOWN24 = 24; enum R_386_UNKNOWN25 = 25; enum R_386_UNKNOWN26 = 26; enum R_386_UNKNOWN27 = 27; enum R_386_UNKNOWN28 = 28; enum R_386_UNKNOWN29 = 29; enum R_386_UNKNOWN30 = 30; enum R_386_UNKNOWN31 = 31; enum R_386_TLS_LDO_32 = 32; enum R_386_UNKNOWN33 = 33; enum R_386_UNKNOWN34 = 34; enum R_386_TLS_DTPMOD32 = 35; enum R_386_TLS_DTPOFF32 = 36; enum R_386_UNKNOWN37 = 37; enum R_386_SIZE32 = 38; enum R_386_NUM = 39; enum ELF_386_MAXPGSZ = 0x10000; enum SHF_ORDERED = 0x40000000; enum SHF_EXCLUDE = 0x80000000; enum SHN_BEFORE = 0xff00; enum SHN_AFTER = 0xff01; enum M_PLT_INSSIZE = 6; enum M_PLT_XNumber = 1; enum M_GOT_XDYNAMIC = 0; enum M_GOT_XLINKMAP = 1; enum M_GOT_XRTLD = 2; enum M_GOT_XNumber = 3; enum M32_WORD_ALIGN = 4; enum M32_PLT_ENTSIZE = 16; enum M32_PLT_ALIGN = M32_WORD_ALIGN; enum M32_GOT_ENTSIZE = 4; enum M32_PLT_RESERVSZ = (M_PLT_XNumber * M32_PLT_ENTSIZE); version(_ELF64) {} else { enum M_WORD_ALIGN = M32_WORD_ALIGN; enum M_PLT_ENTSIZE = M32_PLT_ENTSIZE; enum M_PLT_ALIGN = M32_PLT_ALIGN; enum M_PLT_RESERVSZ = M32_PLT_RESERVSZ; enum M_GOT_ENTSIZE = M32_GOT_ENTSIZE; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/elf.d0000664000175000017500000003617012776214756023234 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/sys/elf_386.h, illumos sys/elf_386.h) */ module core.sys.solaris.sys.elf; version (Solaris): extern (C): nothrow: public import core.sys.solaris.sys.elftypes; enum ELF32_FSZ_ADDR = 4; enum ELF32_FSZ_HALF = 2; enum ELF32_FSZ_OFF = 4; enum ELF32_FSZ_SWORD = 4; enum ELF32_FSZ_WORD = 4; enum ELF64_FSZ_ADDR = 8; enum ELF64_FSZ_HALF = 2; enum ELF64_FSZ_OFF = 8; enum ELF64_FSZ_SWORD = 4; enum ELF64_FSZ_WORD = 4; enum ELF64_FSZ_SXWORD = 8; enum ELF64_FSZ_XWORD = 8; enum EI_NIDENT = 16; struct Elf32_Ehdr { char[EI_NIDENT] e_ident; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } struct Elf64_Ehdr { char[EI_NIDENT] e_ident; Elf64_Half e_type; Elf64_Half e_machine; Elf64_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf64_Word e_flags; Elf64_Half e_ehsize; Elf64_Half e_phentsize; Elf64_Half e_phnum; Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx; } enum EI_MAG0 = 0; enum EI_MAG1 = 1; enum EI_MAG2 = 2; enum EI_MAG3 = 3; enum EI_CLASS = 4; enum EI_DATA = 5; enum EI_VERSION = 6; enum EI_OSABI = 7; enum EI_ABIVERSION = 8; enum EI_PAD = 9; enum ELFMAG0 = 0x7f; enum ELFMAG1 = 'E'; enum ELFMAG2 = 'L'; enum ELFMAG3 = 'F'; enum ELFMAG = "\177ELF"; enum SELFMAG = 4; enum ELFCLASSNONE = 0; enum ELFCLASS32 = 1; enum ELFCLASS64 = 2; enum ELFCLASSNUM = 3; enum ELFDATANONE = 0; enum ELFDATA2LSB = 1; enum ELFDATA2MSB = 2; enum ELFDATANUM = 3; enum ET_NONE = 0; enum ET_REL = 1; enum ET_EXEC = 2; enum ET_DYN = 3; enum ET_CORE = 4; enum ET_NUM = 5; enum ET_LOOS = 0xfe00; enum ET_LOSUNW = 0xfeff; enum ET_SUNWPSEUDO = 0xfeff; enum ET_HISUNW = 0xfeff; enum ET_HIOS = 0xfeff; enum ET_LOPROC = 0xff00; enum ET_HIPROC = 0xffff; enum EM_NONE = 0; enum EM_M32 = 1; enum EM_SPARC = 2; enum EM_386 = 3; enum EM_68K = 4; enum EM_88K = 5; enum EM_486 = 6; enum EM_860 = 7; enum EM_MIPS = 8; enum EM_S370 = 9; enum EM_MIPS_RS3_LE = 10; enum EM_RS6000 = 11; enum EM_UNKNOWN12 = 12; enum EM_UNKNOWN13 = 13; enum EM_UNKNOWN14 = 14; enum EM_PA_RISC = 15; enum EM_PARISC = EM_PA_RISC; enum EM_nCUBE = 16; enum EM_VPP500 = 17; enum EM_SPARC32PLUS = 18; enum EM_960 = 19; enum EM_PPC = 20; enum EM_PPC64 = 21; enum EM_S390 = 22; enum EM_UNKNOWN22 = EM_S390; enum EM_UNKNOWN23 = 23; enum EM_UNKNOWN24 = 24; enum EM_UNKNOWN25 = 25; enum EM_UNKNOWN26 = 26; enum EM_UNKNOWN27 = 27; enum EM_UNKNOWN28 = 28; enum EM_UNKNOWN29 = 29; enum EM_UNKNOWN30 = 30; enum EM_UNKNOWN31 = 31; enum EM_UNKNOWN32 = 32; enum EM_UNKNOWN33 = 33; enum EM_UNKNOWN34 = 34; enum EM_UNKNOWN35 = 35; enum EM_V800 = 36; enum EM_FR20 = 37; enum EM_RH32 = 38; enum EM_RCE = 39; enum EM_ARM = 40; enum EM_ALPHA = 41; enum EM_SH = 42; enum EM_SPARCV9 = 43; enum EM_TRICORE = 44; enum EM_ARC = 45; enum EM_H8_300 = 46; enum EM_H8_300H = 47; enum EM_H8S = 48; enum EM_H8_500 = 49; enum EM_IA_64 = 50; enum EM_MIPS_X = 51; enum EM_COLDFIRE = 52; enum EM_68HC12 = 53; enum EM_MMA = 54; enum EM_PCP = 55; enum EM_NCPU = 56; enum EM_NDR1 = 57; enum EM_STARCORE = 58; enum EM_ME16 = 59; enum EM_ST100 = 60; enum EM_TINYJ = 61; enum EM_AMD64 = 62; enum EM_X86_64 = EM_AMD64; enum EM_PDSP = 63; enum EM_UNKNOWN64 = 64; enum EM_UNKNOWN65 = 65; enum EM_FX66 = 66; enum EM_ST9PLUS = 67; enum EM_ST7 = 68; enum EM_68HC16 = 69; enum EM_68HC11 = 70; enum EM_68HC08 = 71; enum EM_68HC05 = 72; enum EM_SVX = 73; enum EM_ST19 = 74; enum EM_VAX = 75; enum EM_CRIS = 76; enum EM_JAVELIN = 77; enum EM_FIREPATH = 78; enum EM_ZSP = 79; enum EM_MMIX = 80; enum EM_HUANY = 81; enum EM_PRISM = 82; enum EM_AVR = 83; enum EM_FR30 = 84; enum EM_D10V = 85; enum EM_D30V = 86; enum EM_V850 = 87; enum EM_M32R = 88; enum EM_MN10300 = 89; enum EM_MN10200 = 90; enum EM_PJ = 91; enum EM_OPENRISC = 92; enum EM_ARC_A5 = 93; enum EM_XTENSA = 94; enum EM_NUM = 95; enum EV_NONE = 0; enum EV_CURRENT = 1; enum EV_NUM = 2; enum ELFOSABI_NONE = 0; enum ELFOSABI_SYSV = ELFOSABI_NONE; enum ELFOSABI_HPUX = 1; enum ELFOSABI_NETBSD = 2; enum ELFOSABI_LINUX = 3; enum ELFOSABI_UNKNOWN4 = 4; enum ELFOSABI_UNKNOWN5 = 5; enum ELFOSABI_SOLARIS = 6; enum ELFOSABI_AIX = 7; enum ELFOSABI_IRIX = 8; enum ELFOSABI_FREEBSD = 9; enum ELFOSABI_TRU64 = 10; enum ELFOSABI_MODESTO = 11; enum ELFOSABI_OPENBSD = 12; enum ELFOSABI_OPENVMS = 13; enum ELFOSABI_NSK = 14; enum ELFOSABI_AROS = 15; enum ELFOSABI_ARM = 97; enum ELFOSABI_STANDALONE = 255; enum EAV_SUNW_NONE = 0; enum EAV_SUNW_CURRENT = 1; enum EAV_SUNW_NUM = 2; struct Elf32_Phdr { Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; } struct Elf64_Phdr { Elf64_Word p_type; Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align; } enum PT_NULL = 0; enum PT_LOAD = 1; enum PT_DYNAMIC = 2; enum PT_INTERP = 3; enum PT_NOTE = 4; enum PT_SHLIB = 5; enum PT_PHDR = 6; enum PT_TLS = 7; enum PT_NUM = 8; enum PT_LOOS = 0x60000000; enum PT_SUNW_UNWIND = 0x6464e550; enum PT_SUNW_EH_FRAME = 0x6474e550; enum PT_GNU_EH_FRAME = PT_SUNW_EH_FRAME; enum PT_GNU_STACK = 0x6474e551; enum PT_GNU_RELRO = 0x6474e552; enum PT_LOSUNW = 0x6ffffffa; enum PT_SUNWBSS = 0x6ffffffa; enum PT_SUNWSTACK = 0x6ffffffb; enum PT_SUNWDTRACE = 0x6ffffffc; enum PT_SUNWCAP = 0x6ffffffd; enum PT_HISUNW = 0x6fffffff; enum PT_HIOS = 0x6fffffff; enum PT_LOPROC = 0x70000000; enum PT_HIPROC = 0x7fffffff; enum PF_R = 0x4; enum PF_W = 0x2; enum PF_X = 0x1; enum PF_MASKOS = 0x0ff00000; enum PF_MASKPROC = 0xf0000000; enum PF_SUNW_FAILURE = 0x00100000; enum PF_SUNW_KILLED = 0x00200000; enum PF_SUNW_SIGINFO = 0x00400000; enum PN_XNUM = 0xffff; struct Elf32_Shdr { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } struct Elf64_Shdr { Elf64_Word sh_name; Elf64_Word sh_type; Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; Elf64_Xword sh_addralign; Elf64_Xword sh_entsize; } enum SHT_NULL = 0; enum SHT_PROGBITS = 1; enum SHT_SYMTAB = 2; enum SHT_STRTAB = 3; enum SHT_RELA = 4; enum SHT_HASH = 5; enum SHT_DYNAMIC = 6; enum SHT_NOTE = 7; enum SHT_NOBITS = 8; enum SHT_REL = 9; enum SHT_SHLIB = 10; enum SHT_DYNSYM = 11; enum SHT_UNKNOWN12 = 12; enum SHT_UNKNOWN13 = 13; enum SHT_INIT_ARRAY = 14; enum SHT_FINI_ARRAY = 15; enum SHT_PREINIT_ARRAY = 16; enum SHT_GROUP = 17; enum SHT_SYMTAB_SHNDX = 18; enum SHT_NUM = 19; enum SHT_LOOS = 0x60000000; enum SHT_LOSUNW = 0x6fffffef; enum SHT_SUNW_capchain = 0x6fffffef; enum SHT_SUNW_capinfo = 0x6ffffff0; enum SHT_SUNW_symsort = 0x6ffffff1; enum SHT_SUNW_tlssort = 0x6ffffff2; enum SHT_SUNW_LDYNSYM = 0x6ffffff3; enum SHT_SUNW_dof = 0x6ffffff4; enum SHT_SUNW_cap = 0x6ffffff5; enum SHT_SUNW_SIGNATURE = 0x6ffffff6; enum SHT_SUNW_ANNOTATE = 0x6ffffff7; enum SHT_SUNW_DEBUGSTR = 0x6ffffff8; enum SHT_SUNW_DEBUG = 0x6ffffff9; enum SHT_SUNW_move = 0x6ffffffa; enum SHT_SUNW_COMDAT = 0x6ffffffb; enum SHT_SUNW_syminfo = 0x6ffffffc; enum SHT_SUNW_verdef = 0x6ffffffd; enum SHT_GNU_verdef = SHT_SUNW_verdef; enum SHT_SUNW_verneed = 0x6ffffffe; enum SHT_GNU_verneed = SHT_SUNW_verneed; enum SHT_SUNW_versym = 0x6fffffff; enum SHT_GNU_versym = SHT_SUNW_versym; enum SHT_HISUNW = 0x6fffffff; enum SHT_HIOS = 0x6fffffff; enum SHT_GNU_ATTRIBUTES = 0x6ffffff5; enum SHT_GNU_HASH = 0x6ffffff6; enum SHT_GNU_LIBLIST = 0x6ffffff7; enum SHT_CHECKSUM = 0x6ffffff8; enum SHT_LOPROC = 0x70000000; enum SHT_HIPROC = 0x7fffffff; enum SHT_LOUSER = 0x80000000; enum SHT_HIUSER = 0xffffffff; enum SHF_WRITE = 0x01; enum SHF_ALLOC = 0x02; enum SHF_EXECINSTR = 0x04; enum SHF_MERGE = 0x10; enum SHF_STRINGS = 0x20; enum SHF_INFO_LINK = 0x40; enum SHF_LINK_ORDER = 0x80; enum SHF_OS_NONCONFORMING = 0x100; enum SHF_GROUP = 0x200; enum SHF_TLS = 0x400; enum SHF_MASKOS = 0x0ff00000; enum SHF_MASKPROC = 0xf0000000; enum SHN_UNDEF = 0; enum SHN_LORESERVE = 0xff00; enum SHN_LOPROC = 0xff00; enum SHN_HIPROC = 0xff1f; enum SHN_LOOS = 0xff20; enum SHN_LOSUNW = 0xff3f; enum SHN_SUNW_IGNORE = 0xff3f; enum SHN_HISUNW = 0xff3f; enum SHN_HIOS = 0xff3f; enum SHN_ABS = 0xfff1; enum SHN_COMMON = 0xfff2; enum SHN_XINDEX = 0xffff; enum SHN_HIRESERVE = 0xffff; struct Elf32_Sym { Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; ubyte st_info; ubyte st_other; Elf32_Half st_shndx; } struct Elf64_Sym { Elf64_Word st_name; ubyte st_info; ubyte st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } enum STN_UNDEF = 0; extern (D) { auto ELF32_ST_BIND(T)(T val) { return cast(ubyte)val >> 4; } auto ELF32_ST_TYPE(T)(T val) { return val & 0xf; } auto ELF32_ST_INFO(B, T)(B bind, T type) { return (bind << 4) + (type & 0xf); } alias ELF32_ST_BIND ELF64_ST_BIND; alias ELF32_ST_TYPE ELF64_ST_TYPE; alias ELF32_ST_INFO ELF64_ST_INFO; } enum STB_LOCAL = 0; enum STB_GLOBAL = 1; enum STB_WEAK = 2; enum STB_NUM = 3; enum STB_LOPROC = 13; enum STB_HIPROC = 15; enum STT_NOTYPE = 0; enum STT_OBJECT = 1; enum STT_FUNC = 2; enum STT_SECTION = 3; enum STT_FILE = 4; enum STT_COMMON = 5; enum STT_TLS = 6; enum STT_NUM = 7; enum STT_LOOS = 10; enum STT_HIOS = 12; enum STT_LOPROC = 13; enum STT_HIPROC = 15; extern (D) { auto ELF32_ST_VISIBILITY(O)(O o) { return o & 0x07; } alias ELF32_ST_VISIBILITY ELF64_ST_VISIBILITY; } enum STV_DEFAULT = 0; enum STV_INTERNAL = 1; enum STV_HIDDEN = 2; enum STV_PROTECTED = 3; enum STV_EXPORTED = 4; enum STV_SINGLETON = 5; enum STV_ELIMINATE = 6; enum STV_NUM = 7; struct Elf32_Rel { Elf32_Addr r_offset; Elf32_Word r_info; } struct Elf32_Rela { Elf32_Addr r_offset; Elf32_Word r_info; Elf32_Sword r_addend; } struct Elf64_Rel { Elf64_Addr r_offset; Elf64_Xword r_info; } struct Elf64_Rela { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } extern (D) { auto ELF32_R_SYM(V)(V val) { return val >> 8; } auto ELF32_R_TYPE(V)(V val) { return val & 0xff; } auto ELF32_R_INFO(S, T)(S sym, T type) { return (sym << 8) + (type & 0xff); } auto ELF64_R_SYM(I)(I i) { return i >> 32; } auto ELF64_R_TYPE(I)(I i) { return i & 0xffffffff; } auto ELF64_R_INFO(S, T)(S sym, T type) { return (sym << 32) + (type); } auto ELF64_R_TYPE_DATA(I)(I i) { return (i << 32) >> 40; } auto ELF64_R_TYPE_ID(I)(I i) { return (i << 56) >> 56; } auto ELF64_R_TYPE_INFO(S, T)(S sym, T type) { return (sym <<8) + (type); } } enum GRP_COMDAT = 0x01; struct Elf32_Nhdr { Elf32_Word n_namesz; Elf32_Word n_descsz; Elf32_Word n_type; } struct Elf64_Nhdr { Elf64_Word n_namesz; Elf64_Word n_descsz; Elf64_Word n_type; } struct Elf32_Move { Elf32_Lword m_value; Elf32_Word m_info; Elf32_Word m_poffset; Elf32_Half m_repeat; Elf32_Half m_stride; } extern (D) { auto ELF32_M_SYM(I)(I info) { return info >> 8; } auto ELF32_M_SIZE(I)(I info) { return cast(ubyte)info; } auto ELF32_M_INFO(S, SZ)(S sym, SZ size) { return (sym << 8) + cast(ubyte)size; } } struct Elf64_Move { Elf64_Lword m_value; Elf64_Xword m_info; Elf64_Xword m_poffset; Elf64_Half m_repeat; Elf64_Half m_stride; } alias ELF32_M_SYM ELF64_M_SYM; alias ELF32_M_SIZE ELF64_M_SIZE; alias ELF32_M_INFO ELF64_M_INFO; struct Elf32_Cap { Elf32_Word c_tag; union c_un { Elf32_Word c_val; Elf32_Addr c_ptr; } } alias Elf32_Word Elf32_Capinfo; alias Elf32_Word Elf32_Capchain; alias ELF32_M_SYM ELF32_C_SYM; alias ELF32_M_SIZE ELF32_C_GROUP; alias ELF32_M_INFO ELF32_C_INFO; struct Elf64_Cap { Elf64_Xword c_tag; union c_un { Elf64_Xword c_val; Elf64_Addr c_ptr; } } alias Elf64_Xword Elf64_Capinfo; alias Elf64_Word Elf64_Capchain; /* * Macros to compose and decompose values for capabilities info. * * sym = ELF64_C_SYM(info) * grp = ELF64_C_GROUP(info) * info = ELF64_C_INFO(sym, grp) */ extern (D) { auto ELF64_C_SYM(I)(I info) { return info >> 32; } auto ELF64_C_GROUP(I)(I info) { return cast(Elf64_Word)info; } auto ELF64_C_INFO(S, G)(S sym, G grp) { return (sym << 32) + grp; } } enum CAPINFO_NONE = 0; enum CAPINFO_CURRENT = 1; enum CAPINFO_NUM = 2; enum CAPCHAIN_NONE = 0; enum CAPCHAIN_CURRENT = 1; enum CAPCHAIN_NUM = 2; enum CAPINFO_SUNW_GLOB = 0xff; enum CA_SUNW_NULL = 0; enum CA_SUNW_HW_1 = 1; enum CA_SUNW_SF_1 = 2; enum CA_SUNW_HW_2 = 3; enum CA_SUNW_PLAT = 4; enum CA_SUNW_MACH = 5; enum CA_SUNW_ID = 6; enum CA_SUNW_NUM = 7; enum SF1_SUNW_FPKNWN = 0x001; enum SF1_SUNW_FPUSED = 0x002; enum SF1_SUNW_ADDR32 = 0x004; enum SF1_SUNW_MASK = 0x007; enum NT_PRSTATUS = 1; enum NT_PRFPREG = 2; enum NT_PRPSINFO = 3; enum NT_PRXREG = 4; enum NT_PLATFORM = 5; enum NT_AUXV = 6; enum NT_GWINDOWS = 7; enum NT_ASRS = 8; enum NT_LDT = 9; enum NT_PSTATUS = 10; enum NT_PSINFO = 13; enum NT_PRCRED = 14; enum NT_UTSNAME = 15; enum NT_LWPSTATUS = 16; enum NT_LWPSINFO = 17; enum NT_PRPRIV = 18; enum NT_PRPRIVINFO = 19; enum NT_CONTENT = 20; enum NT_ZONENAME = 21; enum NT_FDINFO = 22; enum NT_SPYMASTER = 23; enum NT_NUM = 23; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/procset.d0000664000175000017500000000201012776214756024127 0ustar kaikai/** * D header file defining a process set. * * Copyright: Copyright 2014 Jason King. * License: $(WEB www.boost.org/LICENSE_1.0.txt, Boost License 1.0). * Authors: Jason King */ /* * Copyright 2014 Jason King. * Distributed under the Boost Software License, Version 1.0. * See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt */ module core.sys.solaris.sys.procset; version (Solaris): nothrow: @nogc: import core.sys.posix.sys.types : id_t; import core.sys.posix.sys.wait : idtype_t; enum P_INITPID = 1; enum P_INITUID = 0; enum P_INITPGID = 0; enum idop_t { POP_DIFF, POP_AND, POP_OR, POP_XOR } struct procset_t { idop_t p_op; idtype_t p_lidtype; id_t p_lid; idtype_t p_ridtype; id_t p_rid; } void setprocset(ref procset_t psp, idop_t op, idtype_t ltype, id_t lid, idtype_t rtype, id_t rid) { psp.p_op = op; psp.p_lidtype = ltype; psp.p_lid = lid; psp.p_ridtype = rtype; psp.p_rid = rid; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/types.d0000664000175000017500000000077012776214756023627 0ustar kaikai/** * D header file that defines Solaris-specific types. * * Copyright: Copyright 2014 Jason King. * License: $(WEB www.boost.org/LICENSE_1.0.txt, Boost License 1.0). * Authors: Jason King */ /* * Copyright 2014 Jason King. * Distributed under the Boost Software License, Version 1.0. * See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt */ module core.sys.solaris.sys.types; version (Solaris): nothrow: @nogc: alias short pri_t; enum P_MYID = -1; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/elftypes.d0000664000175000017500000000121112776214756024305 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/sys/elftypes.h, illumos sys/elftypes.h) */ module core.sys.solaris.sys.elftypes; version (Solaris): extern (C): nothrow: import core.stdc.stdint; alias uint32_t Elf32_Addr; alias uint16_t Elf32_Half; alias uint32_t Elf32_Off; alias int32_t Elf32_Sword; alias uint32_t Elf32_Word; alias uint64_t Elf64_Addr; alias uint16_t Elf64_Half; alias uint64_t Elf64_Off; alias int32_t Elf64_Sword; alias int64_t Elf64_Sxword; alias uint32_t Elf64_Word; alias uint64_t Elf64_Xword; alias uint64_t Elf64_Lword; alias uint64_t Elf32_Lword; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/elf_amd64.d0000664000175000017500000000667112776214756024232 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/sys/elf_amd64.h, illumos sys/elf_amd64.h) */ module core.sys.solaris.sys.elf_amd64; version (Solaris): extern (C): nothrow: public import core.sys.solaris.sys.elf_386; enum R_AMD64_NONE = 0; enum R_AMD64_64 = 1; enum R_AMD64_PC32 = 2; enum R_AMD64_GOT32 = 3; enum R_AMD64_PLT32 = 4; enum R_AMD64_COPY = 5; enum R_AMD64_GLOB_DAT = 6; enum R_AMD64_JUMP_SLOT = 7; enum R_AMD64_RELATIVE = 8; enum R_AMD64_GOTPCREL = 9; enum R_AMD64_32 = 10; enum R_AMD64_32S = 11; enum R_AMD64_16 = 12; enum R_AMD64_PC16 = 13; enum R_AMD64_8 = 14; enum R_AMD64_PC8 = 15; enum R_AMD64_DTPMOD64 = 16; enum R_AMD64_DTPOFF64 = 17; enum R_AMD64_TPOFF64 = 18; enum R_AMD64_TLSGD = 19; enum R_AMD64_TLSLD = 20; enum R_AMD64_DTPOFF32 = 21; enum R_AMD64_GOTTPOFF = 22; enum R_AMD64_TPOFF32 = 23; enum R_AMD64_PC64 = 24; enum R_AMD64_GOTOFF64 = 25; enum R_AMD64_GOTPC32 = 26; enum R_AMD64_GOT64 = 27; enum R_AMD64_GOTPCREL64 = 28; enum R_AMD64_GOTPC64 = 29; enum R_AMD64_GOTPLT64 = 30; enum R_AMD64_PLTOFF64 = 31; enum R_AMD64_SIZE32 = 32; enum R_AMD64_SIZE64 = 33; enum R_AMD64_NUM = 34; enum R_X86_64_NONE = R_AMD64_NONE; enum R_X86_64_64 = R_AMD64_64; enum R_X86_64_PC32 = R_AMD64_PC32; enum R_X86_64_GOT32 = R_AMD64_GOT32; enum R_X86_64_PLT32 = R_AMD64_PLT32; enum R_X86_64_COPY = R_AMD64_COPY; enum R_X86_64_GLOB_DAT = R_AMD64_GLOB_DAT; enum R_X86_64_JUMP_SLOT = R_AMD64_JUMP_SLOT; enum R_X86_64_RELATIVE = R_AMD64_RELATIVE; enum R_X86_64_GOTPCREL = R_AMD64_GOTPCREL; enum R_X86_64_32 = R_AMD64_32; enum R_X86_64_32S = R_AMD64_32S; enum R_X86_64_16 = R_AMD64_16; enum R_X86_64_PC16 = R_AMD64_PC16; enum R_X86_64_8 = R_AMD64_8; enum R_X86_64_PC8 = R_AMD64_PC8; enum R_X86_64_DTPMOD64 = R_AMD64_DTPMOD64; enum R_X86_64_DTPOFF64 = R_AMD64_DTPOFF64; enum R_X86_64_TPOFF64 = R_AMD64_TPOFF64; enum R_X86_64_TLSGD = R_AMD64_TLSGD; enum R_X86_64_TLSLD = R_AMD64_TLSLD; enum R_X86_64_DTPOFF32 = R_AMD64_DTPOFF32; enum R_X86_64_GOTTPOFF = R_AMD64_GOTTPOFF; enum R_X86_64_TPOFF32 = R_AMD64_TPOFF32; enum R_X86_64_PC64 = R_AMD64_PC64; enum R_X86_64_GOTPC32 = R_AMD64_GOTPC32; enum R_X86_64_GOTOFF64 = R_AMD64_GOTOFF64; enum R_X86_64_GOT64 = R_AMD64_GOT64; enum R_X86_64_GOTPCREL64 = R_AMD64_GOTPCREL64; enum R_X86_64_GOTPC64 = R_AMD64_GOTPC64; enum R_X86_64_GOTPLT64 = R_AMD64_GOTPLT64; enum R_X86_64_PLTOFF64 = R_AMD64_PLTOFF64; enum R_X86_64_SIZE32 = R_AMD64_SIZE32; enum R_X86_64_SIZE64 = R_AMD64_SIZE64; enum R_X86_64_NUM = R_AMD64_NUM; enum ELF_AMD64_MAXPGSZ = 0x100000; enum SHT_AMD64_UNWIND = 0x70000001; enum SHT_X86_64_UNWIND = SHT_AMD64_UNWIND; enum SHF_AMD64_LARGE = 0x10000000; enum SHF_X86_64_LARGE = SHF_AMD64_LARGE; enum SHN_AMD64_LCOMMON = 0xff02; enum SHN_X86_64_LCOMMON = SHN_AMD64_LCOMMON; enum M64_WORD_ALIGN = 8; enum M64_PLT_ENTSIZE = M32_PLT_ENTSIZE; enum M64_PLT_ALIGN = M64_WORD_ALIGN; enum M64_GOT_ENTSIZE = 8; enum M64_PLT_RESERVSZ = M32_PLT_RESERVSZ; version(_ELF64) { enum M_WORD_ALIGN = M64_WORD_ALIGN; enum M_PLT_ENTSIZE = M64_PLT_ENTSIZE; enum M_PLT_ALIGN = M64_PLT_ALIGN; enum M_PLT_RESERVSZ = M64_PLT_RESERVSZ; enum M_GOT_ENTSIZE = M64_GOT_ENTSIZE; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/elf_SPARC.d0000664000175000017500000001271212776214756024160 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/sys/elf_SPARC.h, illumos sys/elf_SPARC.h) */ module core.sys.solaris.sys.elf_SPARC; version (Solaris): extern (C): nothrow: enum EF_SPARC_32PLUS_MASK = 0xffff00; enum EF_SPARC_32PLUS = 0x000100; enum EF_SPARC_EXT_MASK = 0xffff00; enum EF_SPARC_SUN_US1 = 0x000200; enum EF_SPARC_HAL_R1 = 0x000400; enum EF_SPARC_SUN_US3 = 0x000800; enum EF_SPARCV9_MM = 0x3; enum EF_SPARCV9_TSO = 0x0; enum EF_SPARCV9_PSO = 0x1; enum EF_SPARCV9_RMO = 0x2; enum R_SPARC_NONE = 0; enum R_SPARC_8 = 1; enum R_SPARC_16 = 2; enum R_SPARC_32 = 3; enum R_SPARC_DISP8 = 4; enum R_SPARC_DISP16 = 5; enum R_SPARC_DISP32 = 6; enum R_SPARC_WDISP30 = 7; enum R_SPARC_WDISP22 = 8; enum R_SPARC_HI22 = 9; enum R_SPARC_22 = 10; enum R_SPARC_13 = 11; enum R_SPARC_LO10 = 12; enum R_SPARC_GOT10 = 13; enum R_SPARC_GOT13 = 14; enum R_SPARC_GOT22 = 15; enum R_SPARC_PC10 = 16; enum R_SPARC_PC22 = 17; enum R_SPARC_WPLT30 = 18; enum R_SPARC_COPY = 19; enum R_SPARC_GLOB_DAT = 20; enum R_SPARC_JMP_SLOT = 21; enum R_SPARC_RELATIVE = 22; enum R_SPARC_UA32 = 23; enum R_SPARC_PLT32 = 24; enum R_SPARC_HIPLT22 = 25; enum R_SPARC_LOPLT10 = 26; enum R_SPARC_PCPLT32 = 27; enum R_SPARC_PCPLT22 = 28; enum R_SPARC_PCPLT10 = 29; enum R_SPARC_10 = 30; enum R_SPARC_11 = 31; enum R_SPARC_64 = 32; enum R_SPARC_OLO10 = 33; enum R_SPARC_HH22 = 34; enum R_SPARC_HM10 = 35; enum R_SPARC_LM22 = 36; enum R_SPARC_PC_HH22 = 37; enum R_SPARC_PC_HM10 = 38; enum R_SPARC_PC_LM22 = 39; enum R_SPARC_WDISP16 = 40; enum R_SPARC_WDISP19 = 41; enum R_SPARC_GLOB_JMP = 42; enum R_SPARC_7 = 43; enum R_SPARC_5 = 44; enum R_SPARC_6 = 45; enum R_SPARC_DISP64 = 46; enum R_SPARC_PLT64 = 47; enum R_SPARC_HIX22 = 48; enum R_SPARC_LOX10 = 49; enum R_SPARC_H44 = 50; enum R_SPARC_M44 = 51; enum R_SPARC_L44 = 52; enum R_SPARC_REGISTER = 53; enum R_SPARC_UA64 = 54; enum R_SPARC_UA16 = 55; enum R_SPARC_TLS_GD_HI22 = 56; enum R_SPARC_TLS_GD_LO10 = 57; enum R_SPARC_TLS_GD_ADD = 58; enum R_SPARC_TLS_GD_CALL = 59; enum R_SPARC_TLS_LDM_HI22 = 60; enum R_SPARC_TLS_LDM_LO10 = 61; enum R_SPARC_TLS_LDM_ADD = 62; enum R_SPARC_TLS_LDM_CALL = 63; enum R_SPARC_TLS_LDO_HIX22 = 64; enum R_SPARC_TLS_LDO_LOX10 = 65; enum R_SPARC_TLS_LDO_ADD = 66; enum R_SPARC_TLS_IE_HI22 = 67; enum R_SPARC_TLS_IE_LO10 = 68; enum R_SPARC_TLS_IE_LD = 69; enum R_SPARC_TLS_IE_LDX = 70; enum R_SPARC_TLS_IE_ADD = 71; enum R_SPARC_TLS_LE_HIX22 = 72; enum R_SPARC_TLS_LE_LOX10 = 73; enum R_SPARC_TLS_DTPMOD32 = 74; enum R_SPARC_TLS_DTPMOD64 = 75; enum R_SPARC_TLS_DTPOFF32 = 76; enum R_SPARC_TLS_DTPOFF64 = 77; enum R_SPARC_TLS_TPOFF32 = 78; enum R_SPARC_TLS_TPOFF64 = 79; enum R_SPARC_GOTDATA_HIX22 = 80; enum R_SPARC_GOTDATA_LOX10 = 81; enum R_SPARC_GOTDATA_OP_HIX22 = 82; enum R_SPARC_GOTDATA_OP_LOX10 = 83; enum R_SPARC_GOTDATA_OP = 84; enum R_SPARC_H34 = 85; enum R_SPARC_SIZE32 = 86; enum R_SPARC_SIZE64 = 87; enum R_SPARC_NUM = 88; enum R_SPARC_L34 = R_SPARC_L44; enum ELF_SPARC_MAXPGSZ = 0x10000; enum ELF_SPARCV9_MAXPGSZ = 0x100000; enum SHT_SPARC_GOTDATA = 0x70000000; enum SHF_ORDERED = 0x40000000; enum SHF_EXCLUDE = 0x80000000; enum SHN_BEFORE = 0xff00; enum SHN_AFTER = 0xff01; enum STT_SPARC_REGISTER = 13; enum DT_SPARC_REGISTER = 0x70000001; enum STO_SPARC_REGISTER_G1 = 0x1; enum STO_SPARC_REGISTER_G2 = 0x2; enum STO_SPARC_REGISTER_G3 = 0x3; enum STO_SPARC_REGISTER_G4 = 0x4; enum STO_SPARC_REGISTER_G5 = 0x5; enum STO_SPARC_REGISTER_G6 = 0x6; enum STO_SPARC_REGISTER_G7 = 0x7; enum M_PLT_INSSIZE = 4; enum M_PLT_XNumber = 4; enum M_GOT_XDYNAMIC = 0; enum M_GOT_XNumber = 1; enum M32_WORD_ALIGN = 4; enum M32_PLT_ENTSIZE = 12; enum M32_PLT_ALIGN = M_WORD_ALIGN; enum M32_GOT_ENTSIZE = 4; enum M32_GOT_MAXSMALL = 2048; enum M32_PLT_RESERVSZ = (M_PLT_XNumber * M32_PLT_ENTSIZE); enum M64_WORD_ALIGN = 8; enum M64_PLT_ENTSIZE = 32; enum M64_PLT_ALIGN = 256; enum M64_GOT_ENTSIZE = 8; enum M64_GOT_MAXSMALL = 1024; enum M64_PLT_RESERVSZ = (M_PLT_XNumber * M64_PLT_ENTSIZE); enum M64_PLT_NEARPLTS = 0x8000; enum M64_PLT_FENTSIZE = 24; enum M64_PLT_PSIZE = 8; enum M64_PLT_FBLKCNTS = 160; enum M64_PLT_FBLOCKSZ = (M64_PLT_FBLKCNTS * M64_PLT_ENTSIZE); version(_ELF64) { enum M_WORD_ALIGN = M64_WORD_ALIGN; enum M_PLT_ENTSIZE = M64_PLT_ENTSIZE; enum M_PLT_ALIGN = M64_PLT_ALIGN; enum M_PLT_RESERVSZ = M64_PLT_RESERVSZ; enum M_GOT_ENTSIZE = M64_GOT_ENTSIZE; enum M_GOT_MAXSMALL = M64_GOT_MAXSMALL; } else { enum M_WORD_ALIGN = M32_WORD_ALIGN; enum M_PLT_ENTSIZE = M32_PLT_ENTSIZE; enum M_PLT_ALIGN = M32_PLT_ALIGN; enum M_PLT_RESERVSZ = M32_PLT_RESERVSZ; enum M_GOT_ENTSIZE = M32_GOT_ENTSIZE; enum M_GOT_MAXSMALL = M32_GOT_MAXSMALL; }ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/elf_notes.d0000664000175000017500000000047412776214756024442 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/sys/elf_notes.h, illumos sys/elf_notes.h) */ module core.sys.solaris.sys.elf_notes; version (Solaris): extern (C): nothrow: enum ELF_NOTE_SOLARIS = "SUNW Solaris"; enum ELF_NOTE_PAGESIZE_HINT = 1; ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/link.d0000664000175000017500000002174512776214756023425 0ustar kaikai/** * D header file for Solaris. * * $(LINK2 http://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/sys/link.h, illumos sys/link.h) */ module core.sys.solaris.sys.link; version (Solaris): extern (C): nothrow: public import core.sys.solaris.sys.elftypes; import core.stdc.config; struct Elf32_Dyn { Elf32_Sword d_tag; union d_un { Elf32_Word d_val; Elf32_Addr d_ptr; Elf32_Off d_off; } } struct Elf64_Dyn { Elf64_Xword d_tag; union d_un { Elf64_Xword d_val; Elf64_Addr d_ptr; } } enum DT_NULL = 0; enum DT_NEEDED = 1; enum DT_PLTRELSZ = 2; enum DT_PLTGOT = 3; enum DT_HASH = 4; enum DT_STRTAB = 5; enum DT_SYMTAB = 6; enum DT_RELA = 7; enum DT_RELASZ = 8; enum DT_RELAENT = 9; enum DT_STRSZ = 10; enum DT_SYMENT = 11; enum DT_INIT = 12; enum DT_FINI = 13; enum DT_SONAME = 14; enum DT_RPATH = 15; enum DT_SYMBOLIC = 16; enum DT_REL = 17; enum DT_RELSZ = 18; enum DT_RELENT = 19; enum DT_PLTREL = 20; enum DT_DEBUG = 21; enum DT_TEXTREL = 22; enum DT_JMPREL = 23; enum DT_BIND_NOW = 24; enum DT_INIT_ARRAY = 25; enum DT_FINI_ARRAY = 26; enum DT_INIT_ARRAYSZ = 27; enum DT_FINI_ARRAYSZ = 28; enum DT_RUNPATH = 29; enum DT_FLAGS = 30; enum DT_ENCODING = 32; enum DT_PREINIT_ARRAY = 32; enum DT_PREINIT_ARRAYSZ = 33; enum DT_MAXPOSTAGS = 34; enum DT_LOOS = 0x6000000d; enum DT_SUNW_AUXILIARY = 0x6000000d; enum DT_SUNW_RTLDINF = 0x6000000e; enum DT_SUNW_FILTER = 0x6000000f; enum DT_SUNW_CAP = 0x60000010; enum DT_SUNW_SYMTAB = 0x60000011; enum DT_SUNW_SYMSZ = 0x60000012; enum DT_SUNW_ENCODING = 0x60000013; enum DT_SUNW_SORTENT = 0x60000013; enum DT_SUNW_SYMSORT = 0x60000014; enum DT_SUNW_SYMSORTSZ = 0x60000015; enum DT_SUNW_TLSSORT = 0x60000016; enum DT_SUNW_TLSSORTSZ = 0x60000017; enum DT_SUNW_CAPINFO = 0x60000018; enum DT_SUNW_STRPAD = 0x60000019; enum DT_SUNW_CAPCHAIN = 0x6000001a; enum DT_SUNW_LDMACH = 0x6000001b; enum DT_SUNW_CAPCHAINENT = 0x6000001d; enum DT_SUNW_CAPCHAINSZ = 0x6000001f; enum DT_HIOS = 0x6ffff000; enum DT_DEPRECATED_SPARC_REGISTER = 0x7000001; enum DT_VALRNGLO = 0x6ffffd00; enum DT_GNU_PRELINKED = 0x6ffffdf5; enum DT_GNU_CONFLICTSZ = 0x6ffffdf6; enum DT_GNU_LIBLISTSZ = 0x6ffffdf7; enum DT_CHECKSUM = 0x6ffffdf8; enum DT_PLTPADSZ = 0x6ffffdf9; enum DT_MOVEENT = 0x6ffffdfa; enum DT_MOVESZ = 0x6ffffdfb; enum DT_FEATURE_1 = 0x6ffffdfc; enum DT_POSFLAG_1 = 0x6ffffdfd; enum DT_SYMINSZ = 0x6ffffdfe; enum DT_SYMINENT = 0x6ffffdff; enum DT_VALRNGHI = 0x6ffffdff; enum DT_ADDRRNGLO = 0x6ffffe00; enum DT_GNU_HASH = 0x6ffffef5; enum DT_TLSDESC_PLT = 0x6ffffef6; enum DT_TLSDESC_GOT = 0x6ffffef7; enum DT_GNU_CONFLICT = 0x6ffffef8; enum DT_GNU_LIBLIST = 0x6ffffef9; enum DT_CONFIG = 0x6ffffefa; enum DT_DEPAUDIT = 0x6ffffefb; enum DT_AUDIT = 0x6ffffefc; enum DT_PLTPAD = 0x6ffffefd; enum DT_MOVETAB = 0x6ffffefe; enum DT_SYMINFO = 0x6ffffeff; enum DT_ADDRRNGHI = 0x6ffffeff; enum DT_VERSYM = 0x6ffffff0; enum DT_RELACOUNT = 0x6ffffff9; enum DT_RELCOUNT = 0x6ffffffa; enum DT_FLAGS_1 = 0x6ffffffb; enum DT_VERDEF = 0x6ffffffc; enum DT_VERDEFNUM = 0x6ffffffd; enum DT_VERNEED = 0x6ffffffe; enum DT_VERNEEDNUM = 0x6fffffff; enum DT_LOPROC = 0x70000000; enum DT_AUXILIARY = 0x7ffffffd; enum DT_USED = 0x7ffffffe; enum DT_FILTER = 0x7fffffff; enum DT_HIPROC = 0x7fffffff; enum DF_ORIGIN = 0x00000001; enum DF_SYMBOLIC = 0x00000002; enum DF_TEXTREL = 0x00000004; enum DF_BIND_NOW = 0x00000008; enum DF_STATIC_TLS = 0x00000010; enum DF_P1_LAZYLOAD = 0x00000001; enum DF_P1_GROUPPERM = 0x00000002; enum DF_P1_DEFERRED = 0x00000004; enum DF_1_NOW = 0x00000001; enum DF_1_GLOBAL = 0x00000002; enum DF_1_GROUP = 0x00000004; enum DF_1_NODELETE = 0x00000008; enum DF_1_LOADFLTR = 0x00000010; enum DF_1_INITFIRST = 0x00000020; enum DF_1_NOOPEN = 0x00000040; enum DF_1_ORIGIN = 0x00000080; enum DF_1_DIRECT = 0x00000100; enum DF_1_TRANS = 0x00000200; enum DF_1_INTERPOSE = 0x00000400; enum DF_1_NODEFLIB = 0x00000800; enum DF_1_NODUMP = 0x00001000; enum DF_1_CONFALT = 0x00002000; enum DF_1_ENDFILTEE = 0x00004000; enum DF_1_DISPRELDNE = 0x00008000; enum DF_1_DISPRELPND = 0x00010000; enum DF_1_NODIRECT = 0x00020000; enum DF_1_IGNMULDEF = 0x00040000; enum DF_1_NOKSYMS = 0x00080000; enum DF_1_NOHDR = 0x00100000; enum DF_1_EDITED = 0x00200000; enum DF_1_NORELOC = 0x00400000; enum DF_1_SYMINTPOSE = 0x00800000; enum DF_1_GLOBAUDIT = 0x01000000; enum DF_1_SINGLETON = 0x02000000; enum DTF_1_PARINIT = 0x00000001; enum DTF_1_CONFEXP = 0x00000002; struct Elf32_Verdef { Elf32_Half vd_version; Elf32_Half vd_flags; Elf32_Half vd_ndx; Elf32_Half vd_cnt; Elf32_Word vd_hash; Elf32_Word vd_aux; Elf32_Word vd_next; } struct Elf32_Verdaux { Elf32_Word vda_name; Elf32_Word vda_next; } struct Elf32_Verneed { Elf32_Half vn_version; Elf32_Half vn_cnt; Elf32_Word vn_file; Elf32_Word vn_aux; Elf32_Word vn_next; } struct Elf32_Vernaux { Elf32_Word vna_hash; Elf32_Half vna_flags; Elf32_Half vna_other; Elf32_Word vna_name; Elf32_Word vna_next; } alias Elf32_Half Elf32_Versym; struct Elf32_Syminfo { Elf32_Half si_boundto; Elf32_Half si_flags; } struct Elf64_Verdef { Elf64_Half vd_version; Elf64_Half vd_flags; Elf64_Half vd_ndx; Elf64_Half vd_cnt; Elf64_Word vd_hash; Elf64_Word vd_aux; Elf64_Word vd_next; } struct Elf64_Verdaux { Elf64_Word vda_name; Elf64_Word vda_next; } struct Elf64_Verneed { Elf64_Half vn_version; Elf64_Half vn_cnt; Elf64_Word vn_file; Elf64_Word vn_aux; Elf64_Word vn_next; } struct Elf64_Vernaux { Elf64_Word vna_hash; Elf64_Half vna_flags; Elf64_Half vna_other; Elf64_Word vna_name; Elf64_Word vna_next; } alias Elf64_Half Elf64_Versym; struct Elf64_Syminfo { Elf64_Half si_boundto; Elf64_Half si_flags; } enum VER_NDX_LOCAL = 0; enum VER_NDX_GLOBAL = 1; enum VER_NDX_LORESERVE = 0xff00; enum VER_NDX_ELIMINATE = 0xff01; enum VER_FLG_BASE = 0x1; enum VER_FLG_WEAK = 0x2; enum VER_FLG_INFO = 0x4; enum VER_DEF_NONE = 0; enum VER_DEF_CURRENT = 1; enum VER_DEF_NUM = 2; enum VER_NEED_NONE = 0; enum VER_NEED_CURRENT = 1; enum VER_NEED_NUM = 2; enum SYMINFO_FLG_DIRECT = 0x0001; enum SYMINFO_FLG_FILTER = 0x0002; enum SYMINFO_FLG_PASSTHRU = SYMINFO_FLG_FILTER; enum SYMINFO_FLG_COPY = 0x0004; enum SYMINFO_FLG_LAZYLOAD = 0x0008; enum SYMINFO_FLG_DIRECTBIND = 0x0010; enum SYMINFO_FLG_NOEXTDIRECT = 0x0020; enum SYMINFO_FLG_AUXILIARY = 0x0040; enum SYMINFO_FLG_INTERPOSE = 0x0080; enum SYMINFO_FLG_CAP = 0x0100; enum SYMINFO_FLG_DEFERRED = 0x0200; enum SYMINFO_BT_SELF = 0xffff; enum SYMINFO_BT_PARENT = 0xfffe; enum SYMINFO_BT_NONE = 0xfffd; enum SYMINFO_BT_EXTERN = 0xfffc; enum SYMINFO_BT_LOWRESERVE = 0xff00; enum SYMINFO_NONE = 0; enum SYMINFO_CURRENT = 1; enum SYMINFO_NUM = 2; alias link_map Link_map; struct link_map { c_ulong l_addr; char* l_name; version(D_LP64) Elf64_Dyn* l_ld; else Elf32_Dyn* l_ld; Link_map* l_next; Link_map* l_prev; char* l_refname; } version(_SYSCALL32) { alias link_map32 Link_map32; struct link_map32 { Elf32_Word l_addr; Elf32_Addr l_name; Elf32_Addr l_ld; Elf32_Addr l_next; Elf32_Addr l_prev; Elf32_Addr l_refname; } } enum r_state_e { RT_CONSISTENT, RT_ADD, RT_DELETE } enum rd_flags_e { RD_FL_NONE = 0, RD_FL_ODBG = (1<<0), RD_FL_DBG = (1<<1) } enum rd_event_e { RD_NONE = 0, RD_PREINIT, RD_POSTINIT, RD_DLACTIVITY } struct r_debug { int r_version; Link_map* r_map; c_ulong r_brk; r_state_e r_state; c_ulong r_ldbase; Link_map* r_ldsomap; rd_event_e r_rdevent; rd_flags_e r_flags; } version(_SYSCALL32) { struct r_debug32 { Elf32_Word r_version; Elf32_Addr r_map; Elf32_Word r_brk; r_state_e r_state; Elf32_Word r_ldbase; Elf32_Addr r_ldsomap; rd_event_e r_rdevent; rd_flags_e r_flags; } } enum R_DEBUG_VERSION = 2; struct Elf32_Boot { Elf32_Sword eb_tag; union eb_un { Elf32_Word eb_val; Elf32_Addr eb_ptr; Elf32_Off eb_off; } } struct Elf64_Boot { Elf64_Xword eb_tag; union eb_un { Elf64_Xword eb_val; Elf64_Addr eb_ptr; Elf64_Off eb_off; } } enum EB_NULL = 0; enum EB_DYNAMIC = 1; enum EB_LDSO_BASE = 2; enum EB_ARGV = 3; enum EB_ENVP = 4; enum EB_AUXV = 5; enum EB_DEVZERO = 6; enum EB_PAGESIZE = 7; enum EB_MAX = 8; enum EB_MAX_SIZE32 = 64; enum EB_MAX_SIZE64 = 128; void _ld_libc(void *); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/solaris/sys/priocntl.d0000664000175000017500000000610012776214756024306 0ustar kaikai/** * D header file for the Solaris priocntl(2) and priocntlset(2) functions. * * Copyright: Copyright 2014 Jason King. * License: $(WEB www.boost.org/LICENSE_1.0.txt, Boost License 1.0). * Authors: Jason King */ /* * Copyright 2014 Jason King. * Distributed under the Boost Software License, Version 1.0. * See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt */ module core.sys.solaris.sys.priocntl; version (Solaris): nothrow: @nogc: extern (C): import core.sys.posix.sys.types : caddr_t, id_t; import core.stdc.config : c_long; import core.sys.solaris.sys.procset; import core.sys.solaris.sys.types : pri_t; c_long priocntl(idtype_t, id_t, int, ...); c_long priocntlset(procset_t*, int, ...); enum PC_GETCID = 0; /* Get class ID */ enum PC_GETCLINFO = 1; /* Get info about a configured class */ enum PC_SETPARMS = 2; /* Set scheduling parameters */ enum PC_GETPARMS = 3; /* Get scheduling parameters */ enum PC_ADMIN = 4; /* Scheduler administration (used by */ /* dispadmin(1M), not for general use) */ enum PC_GETPRIRANGE = 5; /* Get priority range for a class */ /* posix.4; scheduling, not for general use */ enum PC_DONICE = 6; /* Set or get nice value */ enum PC_SETXPARMS = 7; /* Set extended scheduling parameters */ enum PC_GETXPARMS = 8; /* Get extended scheduling parameters */ enum PC_SETDFLCL = 9; /* Set default class, not for general use */ enum PC_GETDFLCL = 10; /* Get default class, not for general use */ enum PC_DOPRIO = 11; /* Set or get priority, not for general use */ enum PC_CLNULL = -1; enum PC_CLNMSZ = 16; enum PC_CLINFOSZ = (32 / int.sizeof); enum PC_CLPARMSZ = (32 / int.sizeof); enum PC_GETNICE = 0; enum PC_SETNICE = 1; enum PC_GETPRIO = 0; enum PC_SETPRIO = 1; struct pcinfo_t { id_t pc_cid; // class id char[PC_CLNMSZ] pc_clname; // class name int[PC_CLINFOSZ] pc_clinfo; // class information } struct pcparms_t { id_t pc_cid; // process class int[PC_CLPARMSZ] pc_clparms; //class specific parameters } struct pcnice_t { int pc_val; // nice value int pc_op; // type of operation, set or get } struct pcprio_t { int pc_op; // type of operation, set or get id_t pc_cid; // class id int pc_val; // priority value } // Used by the priocntl varargs interface // PC_SETXPARMS and PC_GETXPARMS enum PC_VAPARMCNT = 8; // max # of kv pairs enum PC_KY_NULL = 0; // kv chain terminator enum PC_KY_CLNAME = 1; // get the class name of a process or LWP struct pc_vaparm_t { int pc_key; ulong pc_parm; } struct pc_vaparms_t { int pc_vaparmscnt; // # of kv pairs pc_vaparm_t[PC_VAPARMCNT] pc_parm; } // Not for general use struct pcpri_t { id_t pc_cid; pri_t pc_clpmax; pri_t pc_clpmin; } struct pcadmin_t { id_t pc_cid; caddr_t pc_cladmin; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/0000775000175000017500000000000012776214756021162 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/dlfcn.d0000664000175000017500000001161512776214756022421 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.dlfcn; private import core.sys.posix.config; version (Posix): extern (C): nothrow: @nogc: // // XOpen (XSI) // /* RTLD_LAZY RTLD_NOW RTLD_GLOBAL RTLD_LOCAL int dlclose(void*); char* dlerror(); void* dlopen(in char*, int); void* dlsym(void*, in char*); */ version( CRuntime_Glibc ) { version (X86) { enum RTLD_LAZY = 0x00001; enum RTLD_NOW = 0x00002; enum RTLD_GLOBAL = 0x00100; enum RTLD_LOCAL = 0x00000; } else version (X86_64) { enum RTLD_LAZY = 0x00001; enum RTLD_NOW = 0x00002; enum RTLD_GLOBAL = 0x00100; enum RTLD_LOCAL = 0x00000; } else version (MIPS32) { enum RTLD_LAZY = 0x0001; enum RTLD_NOW = 0x0002; enum RTLD_GLOBAL = 0x0004; enum RTLD_LOCAL = 0; } else version (MIPS64) { enum RTLD_LAZY = 0x0001; enum RTLD_NOW = 0x0002; enum RTLD_GLOBAL = 0x0004; enum RTLD_LOCAL = 0; } else version (PPC) { enum RTLD_LAZY = 0x00001; enum RTLD_NOW = 0x00002; enum RTLD_GLOBAL = 0x00100; enum RTLD_LOCAL = 0; } else version (PPC64) { enum RTLD_LAZY = 0x00001; enum RTLD_NOW = 0x00002; enum RTLD_GLOBAL = 0x00100; enum RTLD_LOCAL = 0; } else version (ARM) { enum RTLD_LAZY = 0x00001; enum RTLD_NOW = 0x00002; enum RTLD_GLOBAL = 0x00100; enum RTLD_LOCAL = 0; } else version (AArch64) { enum RTLD_LAZY = 0x00001; enum RTLD_NOW = 0x00002; enum RTLD_GLOBAL = 0x00100; enum RTLD_LOCAL = 0; } else version (SystemZ) { enum RTLD_LAZY = 0x00001; enum RTLD_NOW = 0x00002; enum RTLD_GLOBAL = 0x00100; enum RTLD_LOCAL = 0; } else static assert(0, "unimplemented"); int dlclose(void*); char* dlerror(); void* dlopen(in char*, int); void* dlsym(void*, in char*); deprecated("Please use core.sys.linux.dlfcn for non-POSIX extensions") { int dladdr(void* addr, Dl_info* info); void* dlvsym(void* handle, in char* symbol, in char* version_); struct Dl_info { const(char)* dli_fname; void* dli_fbase; const(char)* dli_sname; void* dli_saddr; } } } else version( OSX ) { enum RTLD_LAZY = 0x00001; enum RTLD_NOW = 0x00002; enum RTLD_GLOBAL = 0x00100; enum RTLD_LOCAL = 0x00000; int dlclose(void*); char* dlerror(); void* dlopen(in char*, int); void* dlsym(void*, in char*); int dladdr(void* addr, Dl_info* info); struct Dl_info { const(char)* dli_fname; void* dli_fbase; const(char)* dli_sname; void* dli_saddr; } } else version( FreeBSD ) { enum RTLD_LAZY = 1; enum RTLD_NOW = 2; enum RTLD_GLOBAL = 0x100; enum RTLD_LOCAL = 0; int dlclose(void*); char* dlerror(); void* dlopen(in char*, int); void* dlsym(void*, in char*); int dladdr(const(void)* addr, Dl_info* info); struct Dl_info { const(char)* dli_fname; void* dli_fbase; const(char)* dli_sname; void* dli_saddr; } } else version( Solaris ) { enum RTLD_LAZY = 1; enum RTLD_NOW = 2; enum RTLD_GLOBAL = 0x100; enum RTLD_LOCAL = 0; int dlclose(void*); char* dlerror(); void* dlopen(in char*, int); void* dlsym(void*, in char*); int dladdr(const(void)* addr, Dl_info* info); struct Dl_info { const(char)* dli_fname; void* dli_fbase; const(char)* dli_sname; void* dli_saddr; } } else version( CRuntime_Bionic ) { enum { RTLD_NOW = 0, RTLD_LAZY = 1, RTLD_LOCAL = 0, RTLD_GLOBAL = 2 } int dladdr(in void*, Dl_info*); int dlclose(void*); const(char)* dlerror(); void* dlopen(in char*, int); void* dlsym(void*, in char*); struct Dl_info { const(char)* dli_fname; void* dli_fbase; const(char)* dli_sname; void* dli_saddr; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sched.d0000664000175000017500000001045312776214756022420 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sched; private import core.sys.posix.config; public import core.sys.posix.time; public import core.sys.posix.sys.types; version (Posix): extern (C): nothrow: @nogc: // // Required // /* struct sched_param { int sched_priority (THR) int sched_ss_low_priority (SS|TSP) struct timespec sched_ss_repl_period (SS|TSP) struct timespec sched_ss_init_budget (SS|TSP) int sched_ss_max_repl (SS|TSP) } SCHED_FIFO SCHED_RR SCHED_SPORADIC (SS|TSP) SCHED_OTHER int sched_getparam(pid_t, sched_param*); int sched_getscheduler(pid_t); int sched_setparam(pid_t, in sched_param*); int sched_setscheduler(pid_t, int, in sched_param*); */ version( CRuntime_Glibc ) { struct sched_param { int sched_priority; } enum SCHED_OTHER = 0; enum SCHED_FIFO = 1; enum SCHED_RR = 2; //SCHED_SPORADIC (SS|TSP) } else version( OSX ) { enum SCHED_OTHER = 1; enum SCHED_FIFO = 4; enum SCHED_RR = 2; //SCHED_SPORADIC (SS|TSP) private enum __SCHED_PARAM_SIZE__ = 4; struct sched_param { int sched_priority; byte[__PTHREAD_MUTEX_SIZE__] __opaque; } } else version( FreeBSD ) { struct sched_param { int sched_priority; } enum SCHED_FIFO = 1; enum SCHED_OTHER = 2; enum SCHED_RR = 3; } else version( OpenBSD ) { struct sched_param { int sched_priority; } enum SCHED_FIFO = 1; enum SCHED_OTHER = 2; enum SCHED_RR = 3; } else version (Solaris) { struct sched_param { int sched_priority; int[8] sched_pad; } enum SCHED_OTHER = 0; enum SCHED_FIFO = 1; enum SCHED_RR = 2; enum SCHED_SYS = 3; enum SCHED_IA = 4; enum SCHED_FSS = 5; enum SCHED_FX = 6; enum _SCHED_NEXT = 7; } else version( CRuntime_Bionic ) { struct sched_param { int sched_priority; } enum SCHED_NORMAL = 0; enum SCHED_OTHER = 0; enum SCHED_FIFO = 1; enum SCHED_RR = 2; } else { static assert(false, "Unsupported platform"); } int sched_getparam(pid_t, sched_param*); int sched_getscheduler(pid_t); int sched_setparam(pid_t, in sched_param*); int sched_setscheduler(pid_t, int, in sched_param*); // // Thread (THR) // /* int sched_yield(); */ version( CRuntime_Glibc ) { int sched_yield(); } else version( OSX ) { int sched_yield(); } else version( FreeBSD ) { int sched_yield(); } else version( OpenBSD ) { int sched_yield(); } else version (Solaris) { int sched_yield(); } else version (CRuntime_Bionic) { int sched_yield(); } else { static assert(false, "Unsupported platform"); } // // Scheduling (TPS) // /* int sched_get_priority_max(int); int sched_get_priority_min(int); int sched_rr_get_interval(pid_t, timespec*); */ version( CRuntime_Glibc ) { int sched_get_priority_max(int); int sched_get_priority_min(int); int sched_rr_get_interval(pid_t, timespec*); } else version( OSX ) { int sched_get_priority_min(int); int sched_get_priority_max(int); //int sched_rr_get_interval(pid_t, timespec*); // FIXME: unavailable? } else version( FreeBSD ) { int sched_get_priority_min(int); int sched_get_priority_max(int); int sched_rr_get_interval(pid_t, timespec*); } else version( OpenBSD ) { int sched_get_priority_min(int); int sched_get_priority_max(int); int sched_rr_get_interval(pid_t, timespec*); } else version (Solaris) { int sched_get_priority_max(int); int sched_get_priority_min(int); int sched_rr_get_interval(pid_t, timespec*); } else version (CRuntime_Bionic) { int sched_get_priority_max(int); int sched_get_priority_min(int); int sched_rr_get_interval(pid_t, timespec*); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/stdio.d0000664000175000017500000001722112776214756022454 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.stdio; private import core.sys.posix.config; public import core.stdc.stdio; public import core.sys.posix.sys.types; // for off_t version (Posix): extern (C): nothrow: @nogc: // // Required (defined in core.stdc.stdio) // /* BUFSIZ _IOFBF _IOLBF _IONBF L_tmpnam SEEK_CUR SEEK_END SEEK_SET FILENAME_MAX FOPEN_MAX TMP_MAX EOF NULL stderr stdin stdout FILE fpos_t size_t void clearerr(FILE*); int fclose(FILE*); int feof(FILE*); int ferror(FILE*); int fflush(FILE*); int fgetc(FILE*); int fgetpos(FILE*, fpos_t *); char* fgets(char*, int, FILE*); FILE* fopen(in char*, in char*); int fprintf(FILE*, in char*, ...); int fputc(int, FILE*); int fputs(in char*, FILE*); size_t fread(void *, size_t, size_t, FILE*); FILE* freopen(in char*, in char*, FILE*); int fscanf(FILE*, in char*, ...); int fseek(FILE*, c_long, int); int fsetpos(FILE*, in fpos_t*); c_long ftell(FILE*); size_t fwrite(in void *, size_t, size_t, FILE*); int getc(FILE*); int getchar(); char* gets(char*); void perror(in char*); int printf(in char*, ...); int putc(int, FILE*); int putchar(int); int puts(in char*); int remove(in char*); int rename(in char*, in char*); void rewind(FILE*); int scanf(in char*, ...); void setbuf(FILE*, char*); int setvbuf(FILE*, char*, int, size_t); int snprintf(char*, size_t, in char*, ...); int sprintf(char*, in char*, ...); int sscanf(in char*, in char*, int ...); FILE* tmpfile(); char* tmpnam(char*); int ungetc(int, FILE*); int vfprintf(FILE*, in char*, va_list); int vfscanf(FILE*, in char*, va_list); int vprintf(in char*, va_list); int vscanf(in char*, va_list); int vsnprintf(char*, size_t, in char*, va_list); int vsprintf(char*, in char*, va_list); int vsscanf(in char*, in char*, va_list arg); */ version( CRuntime_Glibc ) { /* * actually, if __USE_FILE_OFFSET64 && !_LARGEFILE64_SOURCE * the *64 functions shouldn't be visible, but the aliases should * still be supported */ static if( __USE_FILE_OFFSET64 ) { int fgetpos64(FILE*, fpos_t *); alias fgetpos64 fgetpos; FILE* fopen64(in char*, in char*); alias fopen64 fopen; FILE* freopen64(in char*, in char*, FILE*); alias freopen64 freopen; int fseek(FILE*, c_long, int); int fsetpos64(FILE*, in fpos_t*); alias fsetpos64 fsetpos; FILE* tmpfile64(); alias tmpfile64 tmpfile; } else { int fgetpos(FILE*, fpos_t *); FILE* fopen(in char*, in char*); FILE* freopen(in char*, in char*, FILE*); int fseek(FILE*, c_long, int); int fsetpos(FILE*, in fpos_t*); FILE* tmpfile(); } } else version( CRuntime_Bionic ) { int fgetpos(FILE*, fpos_t *); FILE* fopen(in char*, in char*); FILE* freopen(in char*, in char*, FILE*); int fseek(FILE*, c_long, int); int fsetpos(FILE*, in fpos_t*); } // // C Extension (CX) // /* L_ctermid char* ctermid(char*); FILE* fdopen(int, in char*); int fileno(FILE*); int fseeko(FILE*, off_t, int); off_t ftello(FILE*); char* gets(char*); int pclose(FILE*); FILE* popen(in char*, in char*); */ version( CRuntime_Glibc ) { enum L_ctermid = 9; static if( __USE_FILE_OFFSET64 ) { int fseeko64(FILE*, off_t, int); alias fseeko64 fseeko; } else { int fseeko(FILE*, off_t, int); } static if( __USE_FILE_OFFSET64 ) { off_t ftello64(FILE*); alias ftello64 ftello; } else { off_t ftello(FILE*); } } else version( Posix ) { int fseeko(FILE*, off_t, int); off_t ftello(FILE*); } char* ctermid(char*); FILE* fdopen(int, in char*); int fileno(FILE*); //int fseeko(FILE*, off_t, int); //off_t ftello(FILE*); char* gets(char*); int pclose(FILE*); FILE* popen(in char*, in char*); // memstream functions are conforming to POSIX.1-2008. These functions are // not specified in POSIX.1-2001 and are not widely available on other // systems. version( CRuntime_Glibc ) // as of glibc 1.0x version = HaveMemstream; else version( FreeBSD ) // as of FreeBSD 9.2 version = HaveMemstream; else version( OpenBSD ) // as of OpenBSD 5.4 version = HaveMemstream; version( HaveMemstream ) { FILE* fmemopen(in void* buf, in size_t size, in char* mode); FILE* open_memstream(char** ptr, size_t* sizeloc); FILE* open_wmemstream(wchar_t** ptr, size_t* sizeloc); } // // Thread-Safe Functions (TSF) // /* void flockfile(FILE*); int ftrylockfile(FILE*); void funlockfile(FILE*); int getc_unlocked(FILE*); int getchar_unlocked(); int putc_unlocked(int, FILE*); int putchar_unlocked(int); */ version( CRuntime_Glibc ) { void flockfile(FILE*); int ftrylockfile(FILE*); void funlockfile(FILE*); int getc_unlocked(FILE*); int getchar_unlocked(); int putc_unlocked(int, FILE*); int putchar_unlocked(int); } else version( OpenBSD ) { void flockfile(FILE*); int ftrylockfile(FILE*); void funlockfile(FILE*); int getc_unlocked(FILE*); int getchar_unlocked(); int putc_unlocked(int, FILE*); int putchar_unlocked(int); } else version( Solaris ) { void flockfile(FILE*); int ftrylockfile(FILE*); void funlockfile(FILE*); int getc_unlocked(FILE*); int getchar_unlocked(); int putc_unlocked(int, FILE*); int putchar_unlocked(int); } // // XOpen (XSI) // /* P_tmpdir va_list (defined in core.stdc.stdarg) char* tempnam(in char*, in char*); */ char* tempnam(in char*, in char*); version( CRuntime_Glibc ) { enum P_tmpdir = "/tmp"; } version( OSX ) { enum P_tmpdir = "/var/tmp"; } version( FreeBSD ) { enum P_tmpdir = "/var/tmp/"; } version( OpenBSD ) { enum P_tmpdir = "/tmp/"; } version( Solaris ) { enum P_tmpdir = "/var/tmp/"; } version( HaveMemstream ) unittest { /* fmemopen */ import core.stdc.string : memcmp; byte[10] buf; auto f = fmemopen(buf.ptr, 10, "w"); assert(f !is null); assert(fprintf(f, "hello") == "hello".length); assert(fflush(f) == 0); assert(memcmp(buf.ptr, "hello".ptr, "hello".length) == 0); //assert(buf assert(fclose(f) == 0); } version( HaveMemstream ) unittest { /* Note: open_memstream is only useful for writing */ import core.stdc.string : memcmp; char* ptr = null; char[6] testdata = ['h', 'e', 'l', 'l', 'o', 0]; size_t sz = 0; auto f = open_memstream(&ptr, &sz); assert(f !is null); assert(fprintf(f, "%s", testdata.ptr) == 5); assert(fflush(f) == 0); assert(memcmp(ptr, testdata.ptr, testdata.length) == 0); assert(fclose(f) == 0); } version( HaveMemstream ) unittest { /* Note: open_wmemstream is only useful for writing */ import core.stdc.string : memcmp; import core.stdc.wchar_ : fwprintf; wchar_t* ptr = null; wchar_t[6] testdata = ['h', 'e', 'l', 'l', 'o', 0]; size_t sz = 0; auto f = open_wmemstream(&ptr, &sz); assert(f !is null); assert(fwprintf(f, testdata.ptr) == 5); assert(fflush(f) == 0); assert(memcmp(ptr, testdata.ptr, testdata.length*wchar_t.sizeof) == 0); assert(fclose(f) == 0); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/semaphore.d0000664000175000017500000000575112776214756023322 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.semaphore; private import core.sys.posix.config; private import core.sys.posix.time; version (Posix): extern (C): nothrow: @nogc: // // Required // /* sem_t SEM_FAILED int sem_close(sem_t*); int sem_destroy(sem_t*); int sem_getvalue(sem_t*, int*); int sem_init(sem_t*, int, uint); sem_t* sem_open(in char*, int, ...); int sem_post(sem_t*); int sem_trywait(sem_t*); int sem_unlink(in char*); int sem_wait(sem_t*); */ version( CRuntime_Glibc ) { private alias int __atomic_lock_t; private struct _pthread_fastlock { c_long __status; __atomic_lock_t __spinlock; } struct sem_t { _pthread_fastlock __sem_lock; int __sem_value; void* __sem_waiting; } enum SEM_FAILED = cast(sem_t*) null; } else version( OSX ) { alias int sem_t; enum SEM_FAILED = cast(sem_t*) null; } else version( FreeBSD ) { // FBSD-9.0 definition struct sem_t { uint _magic; struct _usem { shared uint _has_waiters; shared uint _count; uint _flags; } _usem _kern; } enum SEM_FAILED = cast(sem_t*) null; } else version( OpenBSD ) { struct __sem { } alias sem_t = __sem*; enum SEM_FAILED = cast(sem_t*) null; } else version (Solaris) { struct sem_t { uint sem_count; ushort sem_type; ushort sem_magic; ulong[3] sem_pad1; ulong[2] sem_pad2; } enum SEM_FAILED = cast(sem_t*)-1; } else version( CRuntime_Bionic ) { struct sem_t { uint count; //volatile } enum SEM_FAILED = null; } else { static assert(false, "Unsupported platform"); } int sem_close(sem_t*); int sem_destroy(sem_t*); int sem_getvalue(sem_t*, int*); int sem_init(sem_t*, int, uint); sem_t* sem_open(in char*, int, ...); int sem_post(sem_t*); int sem_trywait(sem_t*); int sem_unlink(in char*); int sem_wait(sem_t*); // // Timeouts (TMO) // /* int sem_timedwait(sem_t*, in timespec*); */ version( CRuntime_Glibc ) { int sem_timedwait(sem_t*, in timespec*); } else version( OSX ) { int sem_timedwait(sem_t*, in timespec*); } else version( FreeBSD ) { int sem_timedwait(sem_t*, in timespec*); } else version( OpenBSD ) { int sem_timedwait(sem_t*, in timespec*); } else version (Solaris) { int sem_timedwait(sem_t*, in timespec*); } else version( CRuntime_Bionic ) { int sem_timedwait(sem_t*, in timespec*); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/config.d0000664000175000017500000000477412776214756022610 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.config; public import core.stdc.config; version (Posix): extern (C) nothrow @nogc: enum _XOPEN_SOURCE = 600; enum _POSIX_SOURCE = true; enum _POSIX_C_SOURCE = 200112L; version (CRuntime_Glibc) { // man 7 feature_test_macros // http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html enum _GNU_SOURCE = false; enum _BSD_SOURCE = false; enum _SVID_SOURCE = false; enum _ATFILE_SOURCE = false; enum _FILE_OFFSET_BITS = 64; // enum __REDIRECT = false; enum _REENTRANT = true; // set by compiler when linking -pthread // deduced enum __USE_FILE_OFFSET64 = _FILE_OFFSET_BITS == 64; enum __USE_LARGEFILE = __USE_FILE_OFFSET64 && !__REDIRECT; enum __USE_LARGEFILE64 = __USE_FILE_OFFSET64 && !__REDIRECT; enum __USE_XOPEN2K = _XOPEN_SOURCE >= 600; enum __USE_XOPEN2KXSI = _XOPEN_SOURCE >= 600; enum __USE_XOPEN2K8 = _XOPEN_SOURCE >= 700; enum __USE_XOPEN2K8XSI = _XOPEN_SOURCE >= 700; enum __USE_MISC = _BSD_SOURCE || _SVID_SOURCE; enum __USE_BSD = _BSD_SOURCE; enum __USE_SVID = _SVID_SOURCE; enum __USE_ATFILE = _ATFILE_SOURCE; enum __USE_GNU = _GNU_SOURCE; enum __USE_REENTRANT = _REENTRANT; version(D_LP64) enum __WORDSIZE=64; else enum __WORDSIZE=32; } else version (Solaris) { enum _FILE_OFFSET_BITS = 64; enum __REDIRECT = false; enum __USE_FILE_OFFSET64 = _FILE_OFFSET_BITS == 64; enum __USE_LARGEFILE = __USE_FILE_OFFSET64 && !__REDIRECT; enum __USE_LARGEFILE64 = __USE_FILE_OFFSET64 && !__REDIRECT; enum __USE_XOPEN2K = _XOPEN_SOURCE >= 600; enum __USE_XOPEN2KXSI = _XOPEN_SOURCE >= 600; enum __USE_XOPEN2K8 = _XOPEN_SOURCE >= 700; enum __USE_XOPEN2K8XSI = _XOPEN_SOURCE >= 700; version (D_LP64) enum __WORDSIZE = 64; else enum __WORDSIZE = 32; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/fcntl.d0000664000175000017500000003341012776214756022436 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.fcntl; private import core.sys.posix.config; private import core.stdc.stdint; public import core.sys.posix.sys.types; // for off_t, mode_t public import core.sys.posix.sys.stat; // for S_IFMT, etc. version (Posix): extern (C): nothrow: @nogc: // // Required // /* F_DUPFD F_GETFD F_SETFD F_GETFL F_SETFL F_GETLK F_SETLK F_SETLKW F_GETOWN F_SETOWN FD_CLOEXEC F_RDLCK F_UNLCK F_WRLCK O_CREAT O_EXCL O_NOCTTY O_TRUNC O_APPEND O_DSYNC O_NONBLOCK O_RSYNC O_SYNC O_ACCMODE O_RDONLY O_RDWR O_WRONLY struct flock { short l_type; short l_whence; off_t l_start; off_t l_len; pid_t l_pid; } int creat(in char*, mode_t); int fcntl(int, int, ...); int open(in char*, int, ...); */ version( CRuntime_Glibc ) { enum F_DUPFD = 0; enum F_GETFD = 1; enum F_SETFD = 2; enum F_GETFL = 3; enum F_SETFL = 4; version(X86_64) { static assert(off_t.sizeof == 8); enum F_GETLK = 5; enum F_SETLK = 6; enum F_SETLKW = 7; } else static if( __USE_FILE_OFFSET64 ) { enum F_GETLK = 12; enum F_SETLK = 13; enum F_SETLKW = 14; } else { enum F_GETLK = 5; enum F_SETLK = 6; enum F_SETLKW = 7; } enum F_GETOWN = 9; enum F_SETOWN = 8; enum FD_CLOEXEC = 1; enum F_RDLCK = 0; enum F_UNLCK = 2; enum F_WRLCK = 1; version (X86) { enum O_CREAT = 0x40; // octal 0100 enum O_EXCL = 0x80; // octal 0200 enum O_NOCTTY = 0x100; // octal 0400 enum O_TRUNC = 0x200; // octal 01000 enum O_APPEND = 0x400; // octal 02000 enum O_NONBLOCK = 0x800; // octal 04000 enum O_SYNC = 0x101000; // octal 04010000 enum O_DSYNC = 0x1000; // octal 010000 enum O_RSYNC = O_SYNC; } else version (X86_64) { enum O_CREAT = 0x40; // octal 0100 enum O_EXCL = 0x80; // octal 0200 enum O_NOCTTY = 0x100; // octal 0400 enum O_TRUNC = 0x200; // octal 01000 enum O_APPEND = 0x400; // octal 02000 enum O_NONBLOCK = 0x800; // octal 04000 enum O_SYNC = 0x101000; // octal 04010000 enum O_DSYNC = 0x1000; // octal 010000 enum O_RSYNC = O_SYNC; } else version (MIPS32) { enum O_CREAT = 0x0100; enum O_EXCL = 0x0400; enum O_NOCTTY = 0x0800; enum O_TRUNC = 0x0200; enum O_APPEND = 0x0008; enum O_DSYNC = O_SYNC; enum O_NONBLOCK = 0x0080; enum O_RSYNC = O_SYNC; enum O_SYNC = 0x0010; } else version (MIPS64) { enum O_CREAT = 0x0100; enum O_EXCL = 0x0400; enum O_NOCTTY = 0x0800; enum O_TRUNC = 0x0200; enum O_APPEND = 0x0008; enum O_DSYNC = 0x0010; enum O_NONBLOCK = 0x0080; enum O_RSYNC = O_SYNC; enum O_SYNC = 0x4010; } else version (PPC) { enum O_CREAT = 0x40; // octal 0100 enum O_EXCL = 0x80; // octal 0200 enum O_NOCTTY = 0x100; // octal 0400 enum O_TRUNC = 0x200; // octal 01000 enum O_APPEND = 0x400; // octal 02000 enum O_NONBLOCK = 0x800; // octal 04000 enum O_SYNC = 0x101000; // octal 04010000 enum O_DSYNC = 0x1000; // octal 010000 enum O_RSYNC = O_SYNC; } else version (PPC64) { enum O_CREAT = 0x40; // octal 0100 enum O_EXCL = 0x80; // octal 0200 enum O_NOCTTY = 0x100; // octal 0400 enum O_TRUNC = 0x200; // octal 01000 enum O_APPEND = 0x400; // octal 02000 enum O_NONBLOCK = 0x800; // octal 04000 enum O_SYNC = 0x101000; // octal 04010000 enum O_DSYNC = 0x1000; // octal 010000 enum O_RSYNC = O_SYNC; } else version (ARM) { enum O_CREAT = 0x40; // octal 0100 enum O_EXCL = 0x80; // octal 0200 enum O_NOCTTY = 0x100; // octal 0400 enum O_TRUNC = 0x200; // octal 01000 enum O_APPEND = 0x400; // octal 02000 enum O_NONBLOCK = 0x800; // octal 04000 enum O_SYNC = 0x101000; // octal 04010000 enum O_DSYNC = 0x1000; // octal 010000 enum O_RSYNC = O_SYNC; } else version (AArch64) { enum O_CREAT = 0x40; // octal 0100 enum O_EXCL = 0x80; // octal 0200 enum O_NOCTTY = 0x100; // octal 0400 enum O_TRUNC = 0x200; // octal 01000 enum O_APPEND = 0x400; // octal 02000 enum O_NONBLOCK = 0x800; // octal 04000 enum O_SYNC = 0x101000; // octal 04010000 enum O_DSYNC = 0x1000; // octal 010000 enum O_RSYNC = O_SYNC; } else version (SystemZ) { enum O_CREAT = 0x40; // octal 0100 enum O_EXCL = 0x80; // octal 0200 enum O_NOCTTY = 0x100; // octal 0400 enum O_TRUNC = 0x200; // octal 01000 enum O_APPEND = 0x400; // octal 02000 enum O_NONBLOCK = 0x800; // octal 04000 enum O_SYNC = 0x101000; // octal 04010000 enum O_DSYNC = 0x1000; // octal 010000 enum O_RSYNC = O_SYNC; } else static assert(0, "unimplemented"); enum O_ACCMODE = 0x3; enum O_RDONLY = 0x0; enum O_WRONLY = 0x1; enum O_RDWR = 0x2; struct flock { short l_type; short l_whence; off_t l_start; off_t l_len; pid_t l_pid; } static if( __USE_FILE_OFFSET64 ) { int creat64(in char*, mode_t); alias creat64 creat; int open64(in char*, int, ...); alias open64 open; } else { int creat(in char*, mode_t); int open(in char*, int, ...); } } else version( OSX ) { enum F_DUPFD = 0; enum F_GETFD = 1; enum F_SETFD = 2; enum F_GETFL = 3; enum F_SETFL = 4; enum F_GETOWN = 5; enum F_SETOWN = 6; enum F_GETLK = 7; enum F_SETLK = 8; enum F_SETLKW = 9; enum FD_CLOEXEC = 1; enum F_RDLCK = 1; enum F_UNLCK = 2; enum F_WRLCK = 3; enum O_CREAT = 0x0200; enum O_EXCL = 0x0800; enum O_NOCTTY = 0; enum O_TRUNC = 0x0400; enum O_RDONLY = 0x0000; enum O_WRONLY = 0x0001; enum O_RDWR = 0x0002; enum O_ACCMODE = 0x0003; enum O_NONBLOCK = 0x0004; enum O_APPEND = 0x0008; enum O_SYNC = 0x0080; //enum O_DSYNC //enum O_RSYNC struct flock { off_t l_start; off_t l_len; pid_t l_pid; short l_type; short l_whence; } int creat(in char*, mode_t); int open(in char*, int, ...); } else version( FreeBSD ) { enum F_DUPFD = 0; enum F_GETFD = 1; enum F_SETFD = 2; enum F_GETFL = 3; enum F_SETFL = 4; enum F_GETOWN = 5; enum F_SETOWN = 6; enum F_GETLK = 11; enum F_SETLK = 12; enum F_SETLKW = 13; enum F_OGETLK = 7; enum F_OSETLK = 8; enum F_OSETLKW = 9; enum F_DUP2FD = 10; enum FD_CLOEXEC = 1; enum F_RDLCK = 1; enum F_UNLCK = 2; enum F_WRLCK = 3; enum O_CREAT = 0x0200; enum O_EXCL = 0x0800; enum O_NOCTTY = 0x8000; enum O_TRUNC = 0x0400; enum O_RDONLY = 0x0000; enum O_WRONLY = 0x0001; enum O_RDWR = 0x0002; enum O_ACCMODE = 0x0003; enum O_NONBLOCK = 0x0004; enum O_APPEND = 0x0008; enum O_SYNC = 0x0080; //enum O_DSYNC //enum O_RSYNC struct flock { off_t l_start; off_t l_len; pid_t l_pid; short l_type; short l_whence; int l_sysid; } struct oflock { off_t l_start; off_t l_len; pid_t l_pid; short l_type; short l_whence; } int creat(in char*, mode_t); int open(in char*, int, ...); } else version (Solaris) { enum F_DUPFD = 0; enum F_GETFD = 1; enum F_SETFD = 2; enum F_GETFL = 3; enum F_SETFL = 4; version (D_LP64) { enum F_GETLK = 14; enum F_SETLK = 6; enum F_SETLKW = 7; } else { static if (__USE_FILE_OFFSET64) { enum F_GETLK = 14; enum F_SETLK = 6; enum F_SETLKW = 7; } else { enum F_GETLK = 33; enum F_SETLK = 34; enum F_SETLKW = 35; } } enum F_GETOWN = 23; enum F_SETOWN = 24; enum FD_CLOEXEC = 1; enum F_RDLCK = 1; enum F_UNLCK = 3; enum F_WRLCK = 2; enum F_UNCKSYS = 4; enum O_CREAT = 0x0100; enum O_EXCL = 0x0400; enum O_NOCTTY = 0x0800; enum O_TRUNC = 0x0200; enum O_APPEND = 0x0008; enum O_NONBLOCK = 0x0080; enum O_SYNC = 0x0010; enum O_DSYNC = 0x0040; enum O_RSYNC = 0x8000; enum O_ACCMODE = (O_SEARCH | O_EXEC | 0x3); enum O_RDONLY = 0; enum O_WRONLY = 1; enum O_RDWR = 2; enum O_SEARCH = 0x200000; enum O_EXEC = 0x400000; struct flock { short l_type; short l_whence; off_t l_start; off_t l_len; int l_sysid; pid_t l_pid; c_long[4] l_pad; } static if (__USE_LARGEFILE64) { struct flock64 { short l_type; short l_whence; off64_t l_start; off64_t l_len; int l_sysid; pid_t l_pid; c_long[4] l_pad; } } version (D_LP64) { int creat(in char*, mode_t); int open(in char*, int, ...); static if (__USE_LARGEFILE64) { alias creat creat64; alias open open64; } } else { static if (__USE_LARGEFILE64) { int creat64(in char*, mode_t); alias creat64 creat; int open64(in char*, int, ...); alias open64 open; } else { int creat(in char*, mode_t); int open(in char*, int, ...); } } } else version( CRuntime_Bionic ) { // All these except for the two functions open and creat really come from // the linux kernel and can probably be merged. enum F_DUPFD = 0; enum F_GETFD = 1; enum F_SETFD = 2; enum F_GETFL = 3; enum F_SETFL = 4; enum F_GETLK = 5; enum F_SETLK = 6; enum F_SETLKW = 7; enum F_SETOWN = 8; enum F_GETOWN = 9; enum FD_CLOEXEC = 1; enum F_RDLCK = 0; enum F_WRLCK = 1; enum F_UNLCK = 2; version (X86) { enum O_CREAT = 0x40; // octal 0100 enum O_EXCL = 0x80; // octal 0200 enum O_NOCTTY = 0x100; // octal 0400 enum O_TRUNC = 0x200; // octal 01000 enum O_APPEND = 0x400; // octal 02000 enum O_NONBLOCK = 0x800; // octal 04000 enum O_SYNC = 0x1000; // octal 010000 } else version (ARM) { enum O_CREAT = 0x40; // octal 0100 enum O_EXCL = 0x80; // octal 0200 enum O_NOCTTY = 0x100; // octal 0400 enum O_TRUNC = 0x200; // octal 01000 enum O_APPEND = 0x400; // octal 02000 enum O_NONBLOCK = 0x800; // octal 04000 enum O_SYNC = 0x1000; // octal 010000 } else { static assert(false, "Architecture not supported."); } enum O_ACCMODE = 0x3; enum O_RDONLY = 0x0; enum O_WRONLY = 0x1; enum O_RDWR = 0x2; struct flock { short l_type; short l_whence; off_t l_start; off_t l_len; pid_t l_pid; } int creat(in char*, mode_t); int open(in char*, int, ...); } else { static assert(false, "Unsupported platform"); } //int creat(in char*, mode_t); int fcntl(int, int, ...); //int open(in char*, int, ...); // Generic Posix fallocate int posix_fallocate(int, off_t, off_t); // // Advisory Information (ADV) // /* POSIX_FADV_NORMAL POSIX_FADV_SEQUENTIAL POSIX_FADV_RANDOM POSIX_FADV_WILLNEED POSIX_FADV_DONTNEED POSIX_FADV_NOREUSE int posix_fadvise(int, off_t, off_t, int); */ ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/grp.d0000664000175000017500000000633412776214756022125 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009, Sönke Ludwig 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen, Sönke Ludwig * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.grp; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for gid_t, uid_t version (Posix): extern (C): nothrow: @nogc: // // Required // /* struct group { char* gr_name; char* gr_passwd; gid_t gr_gid; char** gr_mem; } group* getgrnam(in char*); group* getgrgid(gid_t); */ version( CRuntime_Glibc ) { struct group { char* gr_name; char* gr_passwd; gid_t gr_gid; char** gr_mem; } } else version( OSX ) { struct group { char* gr_name; char* gr_passwd; gid_t gr_gid; char** gr_mem; } } else version( FreeBSD ) { struct group { char* gr_name; char* gr_passwd; gid_t gr_gid; char** gr_mem; } } else version( Solaris ) { struct group { char* gr_name; char* gr_passwd; gid_t gr_gid; char** gr_mem; } } else version( CRuntime_Bionic ) { struct group { char* gr_name; char* gr_passwd; gid_t gr_gid; char** gr_mem; } } else { static assert(false, "Unsupported platform"); } group* getgrnam(in char*); group* getgrgid(gid_t); // // Thread-Safe Functions (TSF) // /* int getgrnam_r(in char*, group*, char*, size_t, group**); int getgrgid_r(gid_t, group*, char*, size_t, group**); */ version( CRuntime_Glibc ) { int getgrnam_r(in char*, group*, char*, size_t, group**); int getgrgid_r(gid_t, group*, char*, size_t, group**); } else version( OSX ) { int getgrnam_r(in char*, group*, char*, size_t, group**); int getgrgid_r(gid_t, group*, char*, size_t, group**); } else version( FreeBSD ) { int getgrnam_r(in char*, group*, char*, size_t, group**); int getgrgid_r(gid_t, group*, char*, size_t, group**); } else version( Solaris ) { int getgrnam_r(in char*, group*, char*, int, group**); int getgrgid_r(gid_t, group*, char*, int, group**); } else version( CRuntime_Bionic ) { } else { static assert(false, "Unsupported platform"); } // // XOpen (XSI) // /* struct group *getgrent(void); void endgrent(void); void setgrent(void); */ version( CRuntime_Glibc ) { group* getgrent(); @trusted void endgrent(); @trusted void setgrent(); } else version( OSX ) { group* getgrent(); @trusted void endgrent(); @trusted void setgrent(); } else version( FreeBSD ) { group* getgrent(); @trusted void endgrent(); @trusted void setgrent(); } else version( Solaris ) { group* getgrent(); @trusted void endgrent(); @trusted void setgrent(); } else version( CRuntime_Bionic ) { } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/poll.d0000664000175000017500000000745012776214756022303 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.poll; private import core.sys.posix.config; version (Posix): extern (C): nothrow: @nogc: // // XOpen (XSI) // /* struct pollfd { int fd; short events; short revents; } nfds_t POLLIN POLLRDNORM POLLRDBAND POLLPRI POLLOUT POLLWRNORM POLLWRBAND POLLERR POLLHUP POLLNVAL int poll(pollfd[], nfds_t, int); */ version( CRuntime_Glibc ) { struct pollfd { int fd; short events; short revents; } alias c_ulong nfds_t; enum { POLLIN = 0x001, POLLRDNORM = 0x040, POLLRDBAND = 0x080, POLLPRI = 0x002, POLLOUT = 0x004, POLLWRNORM = 0x100, POLLWRBAND = 0x200, POLLERR = 0x008, POLLHUP = 0x010, POLLNVAL = 0x020, } int poll(pollfd*, nfds_t, int); } else version( OSX ) { struct pollfd { int fd; short events; short revents; }; alias uint nfds_t; enum { POLLIN = 0x0001, POLLPRI = 0x0002, POLLOUT = 0x0004, POLLRDNORM = 0x0040, POLLWRNORM = POLLOUT, POLLRDBAND = 0x0080, POLLWRBAND = 0x0100, POLLEXTEND = 0x0200, POLLATTRIB = 0x0400, POLLNLINK = 0x0800, POLLWRITE = 0x1000, POLLERR = 0x0008, POLLHUP = 0x0010, POLLNVAL = 0x0020, POLLSTANDARD = (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND| POLLWRBAND|POLLERR|POLLHUP|POLLNVAL) } int poll(pollfd*, nfds_t, int); } else version( FreeBSD ) { alias uint nfds_t; struct pollfd { int fd; short events; short revents; }; enum { POLLIN = 0x0001, POLLPRI = 0x0002, POLLOUT = 0x0004, POLLRDNORM = 0x0040, POLLWRNORM = POLLOUT, POLLRDBAND = 0x0080, POLLWRBAND = 0x0100, //POLLEXTEND = 0x0200, //POLLATTRIB = 0x0400, //POLLNLINK = 0x0800, //POLLWRITE = 0x1000, POLLERR = 0x0008, POLLHUP = 0x0010, POLLNVAL = 0x0020, POLLSTANDARD = (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND| POLLWRBAND|POLLERR|POLLHUP|POLLNVAL) } int poll(pollfd*, nfds_t, int); } else version( Solaris ) { alias c_ulong nfds_t; struct pollfd { int fd; short events; short revents; } enum { POLLIN = 0x0001, POLLPRI = 0x0002, POLLOUT = 0x0004, POLLRDNORM = 0x0040, POLLWRNORM = POLLOUT, POLLRDBAND = 0x0080, POLLWRBAND = 0x0100, POLLERR = 0x0008, POLLHUP = 0x0010, POLLNVAL = 0x0020, } int poll(pollfd*, nfds_t, int); } else version( CRuntime_Bionic ) { struct pollfd { int fd; short events; short revents; } alias uint nfds_t; enum { POLLIN = 0x001, POLLRDNORM = 0x040, POLLRDBAND = 0x080, POLLPRI = 0x002, POLLOUT = 0x004, POLLWRNORM = 0x100, POLLWRBAND = 0x200, POLLERR = 0x008, POLLHUP = 0x010, POLLNVAL = 0x020, } int poll(pollfd*, nfds_t, c_long); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/setjmp.d0000664000175000017500000001455112776214756022637 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.setjmp; private import core.sys.posix.config; private import core.sys.posix.signal; // for sigset_t version (Posix): extern (C) nothrow @nogc: // // Required // /* jmp_buf int setjmp(ref jmp_buf); void longjmp(ref jmp_buf, int); */ version( CRuntime_Glibc ) { version( X86_64 ) { //enum JB_BX = 0; //enum JB_BP = 1; //enum JB_12 = 2; //enum JB_13 = 3; //enum JB_14 = 4; //enum JB_15 = 5; //enum JB_SP = 6; //enum JB_PC = 7; //enum JB_SIZE = 64; alias long[8] __jmp_buf; } else version( X86 ) { //enum JB_BX = 0; //enum JB_SI = 1; //enum JB_DI = 2; //enum JB_BP = 3; //enum JB_SP = 4; //enum JB_PC = 5; //enum JB_SIZE = 24; alias int[6] __jmp_buf; } else version ( SPARC ) { alias int[3] __jmp_buf; } else version (AArch64) { alias long[22] __jmp_buf; } else version (ARM) { alias int[64] __jmp_buf; } else version (PPC) { alias int[64 + (12*4)] __jmp_buf; } else version (PPC64) { alias long[64] __jmp_buf; } else version (MIPS) { struct __jmp_buf { version (MIPS_O32) { void * __pc; void * __sp; int[8] __regs; void * __fp; void * __gp; } else { long __pc; long __sp; long[8] __regs; long __fp; long __gp; } int __fpc_csr; version (MIPS_N64) double[8] __fpregs; else double[6] __fpregs; } } else version (MIPS64) { struct __jmp_buf { long __pc; long __sp; long[8] __regs; long __fp; long __gp; int __fpc_csr; version (MIPS_N64) double[8] __fpregs; else double[6] __fpregs; } } else version (SystemZ) { struct __s390_jmp_buf { c_long[10] __gregs; c_long[8] __fpregs; } alias __jmp_buf = __s390_jmp_buf[1]; } else static assert(0, "unimplemented"); struct __jmp_buf_tag { __jmp_buf __jmpbuf; int __mask_was_saved; sigset_t __saved_mask; } alias __jmp_buf_tag[1] jmp_buf; alias _setjmp setjmp; // see XOpen block void longjmp(ref jmp_buf, int); } else version( FreeBSD ) { // version( X86 ) { enum _JBLEN = 11; struct _jmp_buf { int[_JBLEN + 1] _jb; } } else version( X86_64) { enum _JBLEN = 12; struct _jmp_buf { c_long[_JBLEN] _jb; } } else version( SPARC ) { enum _JBLEN = 5; struct _jmp_buf { c_long[_JBLEN + 1] _jb; } } else static assert(0); alias _jmp_buf[1] jmp_buf; int setjmp(ref jmp_buf); void longjmp(ref jmp_buf, int); } else version( OpenBSD ) { // version( X86 ) { enum _JBLEN = 10; } else version( X86_64) { enum _JBLEN = 11; } else version( ARM ) { enum _JBLEN = 64; } else version( PPC ) { enum _JBLEN = 100; } else version( MIPS64 ) { enum _JBLEN = 83; } else version( SPARC ) { enum _JBLEN = 10; } else version( SPARC64 ) { enum _JBLEN = 14; } else static assert(0); alias jmp_buf = c_long[_JBLEN]; int setjmp(ref jmp_buf); void longjmp(ref jmp_buf, int); } else version( CRuntime_Bionic ) { // version( X86 ) { enum _JBLEN = 10; } else version( ARM ) { enum _JBLEN = 64; } else { static assert(false, "Architecture not supported."); } alias c_long[_JBLEN] jmp_buf; int setjmp(ref jmp_buf); void longjmp(ref jmp_buf, int); } // // C Extension (CX) // /* sigjmp_buf int sigsetjmp(sigjmp_buf, int); void siglongjmp(sigjmp_buf, int); */ version( CRuntime_Glibc ) { alias jmp_buf sigjmp_buf; int __sigsetjmp(sigjmp_buf, int); alias __sigsetjmp sigsetjmp; void siglongjmp(sigjmp_buf, int); } else version( FreeBSD ) { // version( X86 ) { struct _sigjmp_buf { int[_JBLEN + 1] _ssjb; } } else version( X86_64) { struct _sigjmp_buf { c_long[_JBLEN] _sjb; } } else version( SPARC ) { enum _JBLEN = 5; enum _JB_FP = 0; enum _JB_PC = 1; enum _JB_SP = 2; enum _JB_SIGMASK = 3; enum _JB_SIGFLAG = 5; struct _sigjmp_buf { c_long[_JBLEN + 1] _sjb; } } else static assert(0); alias _sigjmp_buf[1] sigjmp_buf; int sigsetjmp(ref sigjmp_buf); void siglongjmp(ref sigjmp_buf, int); } else version( OpenBSD ) { alias sigjmp_buf = c_long[_JBLEN + 1]; int sigsetjmp(ref sigjmp_buf); void siglongjmp(ref sigjmp_buf, int); } else version( CRuntime_Bionic ) { alias c_long[_JBLEN + 1] sigjmp_buf; int sigsetjmp(ref sigjmp_buf, int); void siglongjmp(ref sigjmp_buf, int); } // // XOpen (XSI) // /* int _setjmp(jmp_buf); void _longjmp(jmp_buf, int); */ version( CRuntime_Glibc ) { int _setjmp(ref jmp_buf); void _longjmp(ref jmp_buf, int); } else version( FreeBSD ) { int _setjmp(ref jmp_buf); void _longjmp(ref jmp_buf, int); } else version( OpenBSD ) { int _setjmp(ref jmp_buf); void _longjmp(ref jmp_buf, int); } else version( CRuntime_Bionic ) { int _setjmp(ref jmp_buf); void _longjmp(ref jmp_buf, int); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/inttypes.d0000664000175000017500000000222312776214756023205 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.inttypes; private import core.sys.posix.config; public import core.stdc.inttypes; version (Posix): extern (C) nothrow @nogc: // // Required // /* intmax_t imaxabs(intmax_t); imaxdiv_t imaxdiv(intmax_t, intmax_t); intmax_t strtoimax(in char*, char**, int); uintmax_t strtoumax(in char *, char**, int); intmax_t wcstoimax(in wchar_t*, wchar_t**, int); uintmax_t wcstoumax(in wchar_t*, wchar_t**, int); */ intmax_t imaxabs(intmax_t); imaxdiv_t imaxdiv(intmax_t, intmax_t); intmax_t strtoimax(in char*, char**, int); uintmax_t strtoumax(in char *, char**, int); intmax_t wcstoimax(in wchar_t*, wchar_t**, int); uintmax_t wcstoumax(in wchar_t*, wchar_t**, int); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/mqueue.d0000664000175000017500000001525512776214756022640 0ustar kaikai/** * D header file for Posix Message Queues * * Defines external functions required to manage Posix Message Queues * * mq_open(3) open a message queue * mq_close(3) close a message queue * mq_unlink(3) remove a message queue * mq_send(3) send a message * mq_receive(3) receive a message * mq_timedsend(3) send a message with a timeout (linux specific) * mq_timedreceive(3) receive a message with a timeout (linux specific) * mq_getattr(3) get message queue attributes * mq_setattr(3) set message queue attributes * mq_notify(3) register asynchronous notify * * Copyright: Copyright (c) 2016 sociomantic labs. All rights reserved * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Andreas Bok Andersen, Mathias Lang * Standards: POSIX.1-2001. * See_Also: $(WEB pubs.opengroup.org/onlinepubs/9699919799/basedefs/mqueue.h.html, Standard) */ module core.sys.posix.mqueue; import core.sys.posix.config; import core.sys.posix.signal; import core.sys.posix.time; version (Posix): version (CRuntime_Glibc): extern (C): @nogc nothrow: /// Message queue descriptor. alias int mqd_t; /** * Used in getting and setting the attributes of a message queue. */ struct mq_attr { /// Message queue flags. c_long mq_flags; /// Maximum number of messages. c_long mq_maxmsg; /// Maximum message size. c_long mq_msgsize; /// Number of messages currently queued. c_long mq_curmsgs; } /** * Establish connection between a process and a message queue `name`. * * Note: * Linux prototypes are: * mqd_t mq_open (const(char)* name, int oflag); * mqd_t mq_open(const(char)* name, int oflag, mode_t mode, mq_attr* attr); * * Params: * name = Name of the message queue to open. * oflags = determines the type of access used. * If `O_CREAT` is on `oflag`, the third argument is taken as a * `mode_t`, the mode of the created message queue. * If `O_CREAT` is on `oflag`, the fourth argument is taken as * a pointer to a `mq_attr' (message queue attributes). * If the fourth argument is `null`, default attributes are used. * * Returns: * Message queue descriptor or (mqd_t) -1 on error. */ mqd_t mq_open(const(char)* name, int oflag, ...); /** * Closes the message queue descriptor mqdes. * * Params: * mqdes = Message queue descriptor to close. * * Returns: * On success mq_close() returns 0; on error, -1 is returned, with errno * set to indicate the error. */ int mq_close (mqd_t mqdes); /** * Query status and attributes of message queue `mqdes`. * * Params: * mqdes = Message queue descriptor. * mqstat = Buffer to fill with the message queue's attributes. * * Returns: * On success mq_getattr() return 0; on error, -1 is returned, with errno * set to indicate the error. */ int mq_getattr (mqd_t mqdes, mq_attr* mqstat); /* * Set attributes associated with message queue `mqdes` * * Params: * mqdes = Message queue descriptor. * newstat = non-null pointer to fill with attributes for `mqdes`. * oldstat = if not `null` it is filled with the old attributes. * * Returns: * On success mq_setattr() return 0; on error, -1 is returned, with errno * set to indicate the error. */ int mq_setattr (mqd_t mqdes, const(mq_attr)* newstat, mq_attr* oldstat); /** * Remove the specified message queue `name`. * * Params: * name = Name of the queue to remove. * * Returns: * On success mq_unlink() returns 0; on error, -1 is returned, with errno * set to indicate the error. */ int mq_unlink (const(char)* name); /** * Register for notification when a message is available * * Params: * mqdes = Message queue descriptor. * notification = See `man 3 mq_notify` for details. * * Returns: * On success mq_notify() returns 0; on error, -1 is returned, with errno * set to indicate the error. */ int mq_notify (mqd_t mqdes, const(sigevent)* notification); /** * Receive the oldest message with the highest priority the the message queue * * Params: * mqdes = Message queue descriptor. * msg_ptr = Buffer to write the message to * msg_len = Size of the buffer provided as `msg_ptr`. Must be greater * than the mq_msgsize attribute of the queue. * msg_prio = If not `null`, set to the priority of this message. * * Returns: * On success, mq_receive() returns the number of bytes in the received * message; on error, -1 is returned, with errno set to indicate the error */ ssize_t mq_receive (mqd_t mqdes, char* msg_ptr, size_t msg_len, uint* msg_prio); /** * Receive the oldest message with the highest priority the the message queue, * wait up to a certain timeout. * * Params: * mqdes = Message queue descriptor. * msg_ptr = Buffer to write the message to * msg_len = Size of the buffer provided as `msg_ptr`. Must be greater * than the mq_msgsize attribute of the queue. * msg_prio = If not `null`, set to the priority of this message. * abs_timeout = Specify a ceiling on the time to block if the queue is empty. * * Returns: * On success, mq_receive() returns the number of bytes in the received * message; on error, -1 is returned, with errno set to indicate the error */ ssize_t mq_timedreceive (mqd_t mqdes, char* msg_ptr, size_t msg_len, uint* msg_prio, const(timespec)* abs_timeout); /** * Add a message to a message queue. * * Params: * mqdes = Message queue descriptor. * msg_ptr = Buffer to read the message from * msg_len = Size of the message provided via `msg_ptr`. Must be lower * or equal to the mq_msgsize attribute of the queue. * msg_prio = Priority of this message. * * Returns: * On success, mq_send() return zero; on error, -1 is returned, with errno * set to indicate the error. */ int mq_send (mqd_t mqdes, const(char)* msg_ptr, size_t msg_len, uint msg_prio); /** * Add a message to a message queue, block up to a certain time if the queue * is full. * * Params: * mqdes = Message queue descriptor. * msg_ptr = Buffer to read the message from * msg_len = Size of the message provided via `msg_ptr`. Must be lower * or equal to the mq_msgsize attribute of the queue. * msg_prio = Priority of this message. * abs_timeout = Specify a ceiling on the time to block if the queue is empty. * * Returns: * On success, mq_timedsend() return zero; on error, -1 is returned, * with errno set to indicate the error. * */ int mq_timedsend (mqd_t mqdes, const(char)* msg_ptr, size_t msg_len, uint msg_prio, const(timespec)* abs_timeout); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/stdlib.d0000664000175000017500000003210012776214756022604 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.stdlib; private import core.sys.posix.config; public import core.stdc.stdlib; public import core.sys.posix.sys.wait; version (Posix): extern (C): nothrow: @nogc: // // Required (defined in core.stdc.stdlib) // /* EXIT_FAILURE EXIT_SUCCESS NULL RAND_MAX MB_CUR_MAX div_t ldiv_t lldiv_t size_t wchar_t void _Exit(int); void abort(); int abs(int); int atexit(void function()); double atof(in char*); int atoi(in char*); c_long atol(in char*); long atoll(in char*); void* bsearch(in void*, in void*, size_t, size_t, int function(in void*, in void*)); void* calloc(size_t, size_t); div_t div(int, int); void exit(int); void free(void*); char* getenv(in char*); c_long labs(c_long); ldiv_t ldiv(c_long, c_long); long llabs(long); lldiv_t lldiv(long, long); void* malloc(size_t); int mblen(in char*, size_t); size_t mbstowcs(wchar_t*, in char*, size_t); int mbtowc(wchar_t*, in char*, size_t); void qsort(void*, size_t, size_t, int function(in void*, in void*)); int rand(); void* realloc(void*, size_t); void srand(uint); double strtod(in char*, char**); float strtof(in char*, char**); c_long strtol(in char*, char**, int); real strtold(in char*, char**); long strtoll(in char*, char**, int); c_ulong strtoul(in char*, char**, int); ulong strtoull(in char*, char**, int); int system(in char*); size_t wcstombs(char*, in wchar_t*, size_t); int wctomb(char*, wchar_t); */ // // Advisory Information (ADV) // /* int posix_memalign(void**, size_t, size_t); */ version( CRuntime_Glibc ) { int posix_memalign(void**, size_t, size_t); } else version( FreeBSD ) { int posix_memalign(void**, size_t, size_t); } else version( OpenBSD ) { int posix_memalign(void**, size_t, size_t); } else version( Solaris ) { int posix_memalign(void**, size_t, size_t); } // // C Extension (CX) // /* int setenv(in char*, in char*, int); int unsetenv(in char*); */ version( CRuntime_Glibc ) { int setenv(in char*, in char*, int); int unsetenv(in char*); void* valloc(size_t); // LEGACY non-standard } else version( OSX ) { int setenv(in char*, in char*, int); int unsetenv(in char*); void* valloc(size_t); // LEGACY non-standard } else version( FreeBSD ) { int setenv(in char*, in char*, int); int unsetenv(in char*); void* valloc(size_t); // LEGACY non-standard } else version( OpenBSD ) { int setenv(in char*, in char*, int); int unsetenv(in char*); void* valloc(size_t); // LEGACY non-standard } else version( CRuntime_Bionic ) { int setenv(in char*, in char*, int); int unsetenv(in char*); void* valloc(size_t); } else version( Solaris ) { int setenv(in char*, in char*, int); int unsetenv(in char*); void* valloc(size_t); // LEGACY non-standard } // // Thread-Safe Functions (TSF) // /* int rand_r(uint*); */ version( CRuntime_Glibc ) { int rand_r(uint*); } else version( OSX ) { int rand_r(uint*); } else version( FreeBSD ) { int rand_r(uint*); } else version( OpenBSD ) { int rand_r(uint*); } else version( Solaris ) { int rand_r(uint*); } // // XOpen (XSI) // /* WNOHANG (defined in core.sys.posix.sys.wait) WUNTRACED (defined in core.sys.posix.sys.wait) WEXITSTATUS (defined in core.sys.posix.sys.wait) WIFEXITED (defined in core.sys.posix.sys.wait) WIFSIGNALED (defined in core.sys.posix.sys.wait) WIFSTOPPED (defined in core.sys.posix.sys.wait) WSTOPSIG (defined in core.sys.posix.sys.wait) WTERMSIG (defined in core.sys.posix.sys.wait) c_long a64l(in char*); double drand48(); char* ecvt(double, int, int *, int *); // LEGACY double erand48(ref ushort[3]); char* fcvt(double, int, int *, int *); // LEGACY char* gcvt(double, int, char*); // LEGACY // per spec: int getsubopt(char** char* const*, char**); int getsubopt(char**, in char**, char**); int grantpt(int); char* initstate(uint, char*, size_t); c_long jrand48(ref ushort[3]); char* l64a(c_long); void lcong48(ref ushort[7]); c_long lrand48(); char* mktemp(char*); // LEGACY int mkstemp(char*); int mkdtemp(char*); // Defined in IEEE 1003.1, 2008 Edition c_long mrand48(); c_long nrand48(ref ushort[3]); int posix_openpt(int); char* ptsname(int); int putenv(char*); c_long random(); char* realpath(in char*, char*); ushort *seed48(ref ushort[3]); void setkey(in char*); char* setstate(in char*); void srand48(c_long); void srandom(uint); int unlockpt(int); */ version( CRuntime_Glibc ) { //WNOHANG (defined in core.sys.posix.sys.wait) //WUNTRACED (defined in core.sys.posix.sys.wait) //WEXITSTATUS (defined in core.sys.posix.sys.wait) //WIFEXITED (defined in core.sys.posix.sys.wait) //WIFSIGNALED (defined in core.sys.posix.sys.wait) //WIFSTOPPED (defined in core.sys.posix.sys.wait) //WSTOPSIG (defined in core.sys.posix.sys.wait) //WTERMSIG (defined in core.sys.posix.sys.wait) c_long a64l(in char*); double drand48(); char* ecvt(double, int, int *, int *); // LEGACY double erand48(ref ushort[3]); char* fcvt(double, int, int *, int *); // LEGACY char* gcvt(double, int, char*); // LEGACY int getsubopt(char**, in char**, char**); int grantpt(int); char* initstate(uint, char*, size_t); c_long jrand48(ref ushort[3]); char* l64a(c_long); void lcong48(ref ushort[7]); c_long lrand48(); char* mktemp(char*); // LEGACY //int mkstemp(char*); char* mkdtemp(char*); // Defined in IEEE 1003.1, 2008 Edition c_long mrand48(); c_long nrand48(ref ushort[3]); int posix_openpt(int); char* ptsname(int); int putenv(char*); c_long random(); char* realpath(in char*, char*); ushort *seed48(ref ushort[3]); void setkey(in char*); char* setstate(in char*); void srand48(c_long); void srandom(uint); int unlockpt(int); static if( __USE_LARGEFILE64 ) { int mkstemp64(char*); alias mkstemp64 mkstemp; } else { int mkstemp(char*); } } else version( OSX ) { //WNOHANG (defined in core.sys.posix.sys.wait) //WUNTRACED (defined in core.sys.posix.sys.wait) //WEXITSTATUS (defined in core.sys.posix.sys.wait) //WIFEXITED (defined in core.sys.posix.sys.wait) //WIFSIGNALED (defined in core.sys.posix.sys.wait) //WIFSTOPPED (defined in core.sys.posix.sys.wait) //WSTOPSIG (defined in core.sys.posix.sys.wait) //WTERMSIG (defined in core.sys.posix.sys.wait) c_long a64l(in char*); double drand48(); char* ecvt(double, int, int *, int *); // LEGACY double erand48(ref ushort[3]); char* fcvt(double, int, int *, int *); // LEGACY char* gcvt(double, int, char*); // LEGACY int getsubopt(char**, in char**, char**); int grantpt(int); char* initstate(uint, char*, size_t); c_long jrand48(ref ushort[3]); char* l64a(c_long); void lcong48(ref ushort[7]); c_long lrand48(); char* mktemp(char*); // LEGACY int mkstemp(char*); char* mkdtemp(char*); // Defined in IEEE 1003.1, 2008 Edition c_long mrand48(); c_long nrand48(ref ushort[3]); int posix_openpt(int); char* ptsname(int); int putenv(char*); c_long random(); char* realpath(in char*, char*); ushort *seed48(ref ushort[3]); void setkey(in char*); char* setstate(in char*); void srand48(c_long); void srandom(uint); int unlockpt(int); } else version( FreeBSD ) { //WNOHANG (defined in core.sys.posix.sys.wait) //WUNTRACED (defined in core.sys.posix.sys.wait) //WEXITSTATUS (defined in core.sys.posix.sys.wait) //WIFEXITED (defined in core.sys.posix.sys.wait) //WIFSIGNALED (defined in core.sys.posix.sys.wait) //WIFSTOPPED (defined in core.sys.posix.sys.wait) //WSTOPSIG (defined in core.sys.posix.sys.wait) //WTERMSIG (defined in core.sys.posix.sys.wait) c_long a64l(in char*); double drand48(); //char* ecvt(double, int, int *, int *); // LEGACY double erand48(ref ushort[3]); //char* fcvt(double, int, int *, int *); // LEGACY //char* gcvt(double, int, char*); // LEGACY int getsubopt(char**, in char**, char**); int grantpt(int); char* initstate(uint, char*, size_t); c_long jrand48(ref ushort[3]); char* l64a(c_long); void lcong48(ref ushort[7]); c_long lrand48(); char* mktemp(char*); // LEGACY int mkstemp(char*); char* mkdtemp(char*); // Defined in IEEE 1003.1, 2008 Edition c_long mrand48(); c_long nrand48(ref ushort[3]); int posix_openpt(int); char* ptsname(int); int putenv(char*); c_long random(); char* realpath(in char*, char*); ushort *seed48(ref ushort[3]); void setkey(in char*); char* setstate(in char*); void srand48(c_long); void srandom(uint); int unlockpt(int); } else version( OpenBSD ) { //WNOHANG (defined in core.sys.posix.sys.wait) //WUNTRACED (defined in core.sys.posix.sys.wait) //WEXITSTATUS (defined in core.sys.posix.sys.wait) //WIFEXITED (defined in core.sys.posix.sys.wait) //WIFSIGNALED (defined in core.sys.posix.sys.wait) //WIFSTOPPED (defined in core.sys.posix.sys.wait) //WSTOPSIG (defined in core.sys.posix.sys.wait) //WTERMSIG (defined in core.sys.posix.sys.wait) c_long a64l(in char*); double drand48(); //char* ecvt(double, int, int *, int *); // LEGACY double erand48(ref ushort[3]); //char* fcvt(double, int, int *, int *); // LEGACY //char* gcvt(double, int, char*); // LEGACY int getsubopt(char**, in char**, char**); int grantpt(int); char* initstate(uint, char*, size_t); c_long jrand48(ref ushort[3]); char* l64a(c_long); void lcong48(ref ushort[7]); c_long lrand48(); char* mktemp(char*); // LEGACY int mkstemp(char*); char* mkdtemp(char*); // Defined in IEEE 1003.1, 2008 Edition c_long mrand48(); c_long nrand48(ref ushort[3]); int posix_openpt(int); char* ptsname(int); int putenv(char*); c_long random(); char* realpath(in char*, char*); ushort *seed48(ref ushort[3]); // void setkey(in char*); // not implemented char* setstate(in char*); void srand48(c_long); void srandom(uint); int unlockpt(int); } else version( CRuntime_Bionic ) { double drand48(); double erand48(ref ushort[3]); //int grantpt(int); defined inline, but seems to do nothing in bionic c_long jrand48(ref ushort[3]); c_long lrand48(); char* mktemp(char*); // LEGACY int mkstemp(char*); char* mkdtemp(char*); // Defined in IEEE 1003.1, 2008 Edition c_long mrand48(); c_long nrand48(ref ushort[3]); char* ptsname(int); int putenv(in char*); c_long random() { return lrand48(); } char* realpath(in char*, char*); ushort* seed48(ref ushort[3]); void srand48(c_long); void srandom(uint s) { srand48(s); } int unlockpt(int); } else version( Solaris ) { //WNOHANG (defined in core.sys.posix.sys.wait) //WUNTRACED (defined in core.sys.posix.sys.wait) //WEXITSTATUS (defined in core.sys.posix.sys.wait) //WIFEXITED (defined in core.sys.posix.sys.wait) //WIFSIGNALED (defined in core.sys.posix.sys.wait) //WIFSTOPPED (defined in core.sys.posix.sys.wait) //WSTOPSIG (defined in core.sys.posix.sys.wait) //WTERMSIG (defined in core.sys.posix.sys.wait) c_long a64l(in char*); double drand48(); char* ecvt(double, int, int *, int *); // LEGACY double erand48(ref ushort[3]); char* fcvt(double, int, int *, int *); // LEGACY char* gcvt(double, int, char*); // LEGACY int getsubopt(char**, in char**, char**); int grantpt(int); char* initstate(uint, char*, size_t); c_long jrand48(ref ushort[3]); char* l64a(c_long); void lcong48(ref ushort[7]); c_long lrand48(); char* mktemp(char*); // LEGACY //int mkstemp(char*); char* mkdtemp(char*); // Defined in IEEE 1003.1, 2008 Edition c_long mrand48(); c_long nrand48(ref ushort[3]); int posix_openpt(int); char* ptsname(int); int putenv(char*); c_long random(); char* realpath(in char*, char*); ushort *seed48(ref ushort[3]); void setkey(in char*); char* setstate(in char*); void srand48(c_long); void srandom(uint); int unlockpt(int); version (D_LP64) { int mkstemp(char*); static if ( __USE_LARGEFILE64 ) alias mkstemp mkstemp64; } else { int mkstemp64(char*); static if ( __USE_LARGEFILE64 ) alias mkstemp64 mkstemp; else int mkstemp(char*); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/time.d0000664000175000017500000002243412776214756022272 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.time; private import core.sys.posix.config; public import core.stdc.time; public import core.sys.posix.sys.types; public import core.sys.posix.signal; // for sigevent version (Posix): extern (C): nothrow: @nogc: // // Required (defined in core.stdc.time) // /* char* asctime(in tm*); clock_t clock(); char* ctime(in time_t*); double difftime(time_t, time_t); tm* gmtime(in time_t*); tm* localtime(in time_t*); time_t mktime(tm*); size_t strftime(char*, size_t, in char*, in tm*); time_t time(time_t*); */ version( CRuntime_Glibc ) { time_t timegm(tm*); // non-standard } else version( OSX ) { time_t timegm(tm*); // non-standard } else version( FreeBSD ) { time_t timegm(tm*); // non-standard } else version (Solaris) { time_t timegm(tm*); // non-standard } else version (CRuntime_Bionic) { // Not supported. } else { static assert(false, "Unsupported platform"); } // // C Extension (CX) // (defined in core.stdc.time) // /* char* tzname[]; void tzset(); */ // // Process CPU-Time Clocks (CPT) // /* int clock_getcpuclockid(pid_t, clockid_t*); */ // // Clock Selection (CS) // /* int clock_nanosleep(clockid_t, int, in timespec*, timespec*); */ // // Monotonic Clock (MON) // /* CLOCK_MONOTONIC */ version( linux ) { enum CLOCK_MONOTONIC = 1; // To be removed in December 2015. static import core.sys.linux.time; deprecated("Please import it from core.sys.linux.time instead.") alias CLOCK_MONOTONIC_RAW = core.sys.linux.time.CLOCK_MONOTONIC_RAW; // non-standard deprecated("Please import it from core.sys.linux.time instead.") alias CLOCK_MONOTONIC_COARSE = core.sys.linux.time.CLOCK_MONOTONIC_COARSE; // non-standard } else version (FreeBSD) { // time.h enum CLOCK_MONOTONIC = 4; // To be removed in December 2015. static import core.sys.freebsd.time; deprecated("Please import it from core.sys.freebsd.time instead.") alias CLOCK_MONOTONIC_PRECISE = core.sys.freebsd.time.CLOCK_MONOTONIC_PRECISE; deprecated("Please import it from core.sys.freebsd.time instead.") alias CLOCK_MONOTONIC_FAST = core.sys.freebsd.time.CLOCK_MONOTONIC_FAST; } else version (OSX) { // No CLOCK_MONOTONIC defined } else version (Solaris) { enum CLOCK_MONOTONIC = 4; } else { static assert(0); } // // Timer (TMR) // /* CLOCK_PROCESS_CPUTIME_ID (TMR|CPT) CLOCK_THREAD_CPUTIME_ID (TMR|TCT) NOTE: timespec must be defined in core.sys.posix.signal to break a circular import. struct timespec { time_t tv_sec; int tv_nsec; } struct itimerspec { timespec it_interval; timespec it_value; } CLOCK_REALTIME TIMER_ABSTIME clockid_t timer_t int clock_getres(clockid_t, timespec*); int clock_gettime(clockid_t, timespec*); int clock_settime(clockid_t, in timespec*); int nanosleep(in timespec*, timespec*); int timer_create(clockid_t, sigevent*, timer_t*); int timer_delete(timer_t); int timer_gettime(timer_t, itimerspec*); int timer_getoverrun(timer_t); int timer_settime(timer_t, int, in itimerspec*, itimerspec*); */ version( CRuntime_Glibc ) { enum CLOCK_PROCESS_CPUTIME_ID = 2; enum CLOCK_THREAD_CPUTIME_ID = 3; // NOTE: See above for why this is commented out. // //struct timespec //{ // time_t tv_sec; // c_long tv_nsec; //} struct itimerspec { timespec it_interval; timespec it_value; } enum CLOCK_REALTIME = 0; // To be removed in December 2015. static import core.sys.linux.time; deprecated("Please import it from core.sys.linux.time instead.") alias CLOCK_REALTIME_COARSE = core.sys.linux.time.CLOCK_REALTIME_COARSE; // non-standard enum TIMER_ABSTIME = 0x01; alias int clockid_t; alias int timer_t; int clock_getres(clockid_t, timespec*); int clock_gettime(clockid_t, timespec*); int clock_settime(clockid_t, in timespec*); int nanosleep(in timespec*, timespec*); int timer_create(clockid_t, sigevent*, timer_t*); int timer_delete(timer_t); int timer_gettime(timer_t, itimerspec*); int timer_getoverrun(timer_t); int timer_settime(timer_t, int, in itimerspec*, itimerspec*); } else version( OSX ) { int nanosleep(in timespec*, timespec*); } else version( FreeBSD ) { //enum CLOCK_PROCESS_CPUTIME_ID = ??; enum CLOCK_THREAD_CPUTIME_ID = 15; // NOTE: See above for why this is commented out. // //struct timespec //{ // time_t tv_sec; // c_long tv_nsec; //} struct itimerspec { timespec it_interval; timespec it_value; } enum CLOCK_REALTIME = 0; enum TIMER_ABSTIME = 0x01; alias int clockid_t; // alias int timer_t; int clock_getres(clockid_t, timespec*); int clock_gettime(clockid_t, timespec*); int clock_settime(clockid_t, in timespec*); int nanosleep(in timespec*, timespec*); int timer_create(clockid_t, sigevent*, timer_t*); int timer_delete(timer_t); int timer_gettime(timer_t, itimerspec*); int timer_getoverrun(timer_t); int timer_settime(timer_t, int, in itimerspec*, itimerspec*); } else version (Solaris) { enum CLOCK_PROCESS_CPUTIME_ID = 5; // enum CLOCK_THREAD_CPUTIME_ID = 2; // struct itimerspec { timespec it_interval; timespec it_value; } enum CLOCK_REALTIME = 3; // enum TIMER_ABSOLUTE = 0x1; alias int clockid_t; alias int timer_t; int clock_getres(clockid_t, timespec*); int clock_gettime(clockid_t, timespec*); int clock_settime(clockid_t, in timespec*); int clock_nanosleep(clockid_t, int, in timespec*, timespec*); int nanosleep(in timespec*, timespec*); int timer_create(clockid_t, sigevent*, timer_t*); int timer_delete(timer_t); int timer_getoverrun(timer_t); int timer_gettime(timer_t, itimerspec*); int timer_settime(timer_t, int, in itimerspec*, itimerspec*); } else version( CRuntime_Bionic ) { enum CLOCK_PROCESS_CPUTIME_ID = 2; enum CLOCK_THREAD_CPUTIME_ID = 3; struct itimerspec { timespec it_interval; timespec it_value; } enum CLOCK_REALTIME = 0; enum CLOCK_REALTIME_HR = 4; enum TIMER_ABSTIME = 0x01; alias int clockid_t; alias int timer_t; int clock_getres(int, timespec*); int clock_gettime(int, timespec*); int nanosleep(in timespec*, timespec*); int timer_create(int, sigevent*, timer_t*); int timer_delete(timer_t); int timer_gettime(timer_t, itimerspec*); int timer_getoverrun(timer_t); int timer_settime(timer_t, int, in itimerspec*, itimerspec*); } else { static assert(false, "Unsupported platform"); } // // Thread-Safe Functions (TSF) // /* char* asctime_r(in tm*, char*); char* ctime_r(in time_t*, char*); tm* gmtime_r(in time_t*, tm*); tm* localtime_r(in time_t*, tm*); */ version( CRuntime_Glibc ) { char* asctime_r(in tm*, char*); char* ctime_r(in time_t*, char*); tm* gmtime_r(in time_t*, tm*); tm* localtime_r(in time_t*, tm*); } else version( OSX ) { char* asctime_r(in tm*, char*); char* ctime_r(in time_t*, char*); tm* gmtime_r(in time_t*, tm*); tm* localtime_r(in time_t*, tm*); } else version( FreeBSD ) { char* asctime_r(in tm*, char*); char* ctime_r(in time_t*, char*); tm* gmtime_r(in time_t*, tm*); tm* localtime_r(in time_t*, tm*); } else version (Solaris) { char* asctime_r(in tm*, char*); char* ctime_r(in time_t*, char*); tm* gmtime_r(in time_t*, tm*); tm* localtime_r(in time_t*, tm*); } else version (CRuntime_Bionic) { char* asctime_r(in tm*, char*); char* ctime_r(in time_t*, char*); tm* gmtime_r(in time_t*, tm*); tm* localtime_r(in time_t*, tm*); } else { static assert(false, "Unsupported platform"); } // // XOpen (XSI) // /* getdate_err int daylight; int timezone; tm* getdate(in char*); char* strptime(in char*, in char*, tm*); */ version( CRuntime_Glibc ) { extern __gshared int daylight; extern __gshared c_long timezone; tm* getdate(in char*); char* strptime(in char*, in char*, tm*); } else version( OSX ) { extern __gshared c_long timezone; extern __gshared int daylight; tm* getdate(in char*); char* strptime(in char*, in char*, tm*); } else version( FreeBSD ) { //tm* getdate(in char*); char* strptime(in char*, in char*, tm*); } else version (Solaris) { extern __gshared c_long timezone, altzone; extern __gshared int daylight; tm* getdate(in char*); char* __strptime_dontzero(in char*, in char*, tm*); alias __strptime_dontzero strptime; } else version( CRuntime_Bionic ) { extern __gshared int daylight; extern __gshared c_long timezone; char* strptime(in char*, in char*, tm*); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/dirent.d0000664000175000017500000001524012776214756022616 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersn * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.dirent; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for ino_t version (Posix): extern (C): nothrow: @nogc: // // Required // /* DIR struct dirent { char[] d_name; } int closedir(DIR*); DIR* opendir(in char*); dirent* readdir(DIR*); void rewinddir(DIR*); */ version( CRuntime_Glibc ) { // NOTE: The following constants are non-standard Linux definitions // for dirent.d_type. enum { DT_UNKNOWN = 0, DT_FIFO = 1, DT_CHR = 2, DT_DIR = 4, DT_BLK = 6, DT_REG = 8, DT_LNK = 10, DT_SOCK = 12, DT_WHT = 14 } struct dirent { ino_t d_ino; off_t d_off; ushort d_reclen; ubyte d_type; char[256] d_name; } struct DIR { // Managed by OS } static if( __USE_FILE_OFFSET64 ) { dirent* readdir64(DIR*); alias readdir64 readdir; } else { dirent* readdir(DIR*); } } else version( OSX ) { enum { DT_UNKNOWN = 0, DT_FIFO = 1, DT_CHR = 2, DT_DIR = 4, DT_BLK = 6, DT_REG = 8, DT_LNK = 10, DT_SOCK = 12, DT_WHT = 14 } // _DARWIN_FEATURE_64_BIT_INODE dirent is default for Mac OSX >10.5 and is // only meaningful type for other OS X/Darwin variants (e.g. iOS). // man dir(5) has some info, man stat(2) gives details. struct dirent { ino_t d_ino; alias d_fileno = d_ino; ulong d_seekoff; ushort d_reclen; ushort d_namlen; ubyte d_type; char[1024] d_name; } struct DIR { // Managed by OS } // OS X maintains backwards compatibility with older binaries using 32-bit // inode functions by appending $INODE64 to newer 64-bit inode functions. pragma(mangle, "readdir$INODE64") dirent* readdir(DIR*); } else version( FreeBSD ) { enum { DT_UNKNOWN = 0, DT_FIFO = 1, DT_CHR = 2, DT_DIR = 4, DT_BLK = 6, DT_REG = 8, DT_LNK = 10, DT_SOCK = 12, DT_WHT = 14 } align(4) struct dirent { uint d_fileno; ushort d_reclen; ubyte d_type; ubyte d_namlen; char[256] d_name; } alias void* DIR; dirent* readdir(DIR*); } else version (Solaris) { struct dirent { ino_t d_ino; off_t d_off; ushort d_reclen; char[1] d_name; } struct DIR { int dd_fd; int dd_loc; int dd_size; char* dd_buf; } version (D_LP64) { dirent* readdir(DIR*); alias readdir64 = readdir; } else { static if (__USE_LARGEFILE64) { dirent* readdir64(DIR*); alias readdir64 readdir; } else { dirent* readdir(DIR*); } } } else version( CRuntime_Bionic ) { enum { DT_UNKNOWN = 0, DT_FIFO = 1, DT_CHR = 2, DT_DIR = 4, DT_BLK = 6, DT_REG = 8, DT_LNK = 10, DT_SOCK = 12, DT_WHT = 14 } struct dirent { ulong d_ino; long d_off; ushort d_reclen; ubyte d_type; char[256] d_name; } struct DIR { } dirent* readdir(DIR*); } else { static assert(false, "Unsupported platform"); } version( OSX ) { version( D_LP64 ) { int closedir(DIR*); pragma(mangle, "opendir$INODE64") DIR* opendir(in char*); pragma(mangle, "rewinddir$INODE64") void rewinddir(DIR*); } else { // 32-bit mangles __DARWIN_UNIX03 specific functions with $UNIX2003 to // maintain backward compatibility with binaries build pre 10.5 pragma(mangle, "closedir$UNIX2003") int closedir(DIR*); pragma(mangle, "opendir$INODE64$UNIX2003") DIR* opendir(in char*); pragma(mangle, "rewinddir$INODE64$UNIX2003") void rewinddir(DIR*); } } else { int closedir(DIR*); DIR* opendir(in char*); //dirent* readdir(DIR*); void rewinddir(DIR*); } // // Thread-Safe Functions (TSF) // /* int readdir_r(DIR*, dirent*, dirent**); */ version( CRuntime_Glibc ) { static if( __USE_LARGEFILE64 ) { int readdir64_r(DIR*, dirent*, dirent**); alias readdir64_r readdir_r; } else { int readdir_r(DIR*, dirent*, dirent**); } } else version( OSX ) { pragma(mangle, "readdir_r$INODE64") int readdir_r(DIR*, dirent*, dirent**); } else version( FreeBSD ) { int readdir_r(DIR*, dirent*, dirent**); } else version (Solaris) { static if (__USE_LARGEFILE64) { int readdir64_r(DIR*, dirent*, dirent**); alias readdir64_r readdir_r; } else { int readdir_r(DIR*, dirent*, dirent**); } } else version( CRuntime_Bionic ) { int readdir_r(DIR*, dirent*, dirent**); } else { static assert(false, "Unsupported platform"); } // // XOpen (XSI) // /* void seekdir(DIR*, c_long); c_long telldir(DIR*); */ version( CRuntime_Glibc ) { void seekdir(DIR*, c_long); c_long telldir(DIR*); } else version( FreeBSD ) { void seekdir(DIR*, c_long); c_long telldir(DIR*); } else version ( OSX ) { version ( D_LP64 ) { pragma(mangle, "seekdir$INODE64") void seekdir(DIR*, c_long); pragma(mangle, "telldir$INODE64") c_long telldir(DIR*); } else { // 32-bit mangles __DARWIN_UNIX03 specific functions with $UNIX2003 to // maintain backward compatibility with binaries build pre 10.5 pragma(mangle, "seekdir$INODE64$UNIX2003") void seekdir(DIR*, c_long); pragma(mangle, "telldir$INODE64$UNIX2003") c_long telldir(DIR*); } } else version (Solaris) { c_long telldir(DIR*); void seekdir(DIR*, c_long); } else version (CRuntime_Bionic) { } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/pthread.d0000664000175000017500000011030212776214756022753 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.pthread; private import core.sys.posix.config; public import core.sys.posix.sys.types; public import core.sys.posix.sched; public import core.sys.posix.time; import core.stdc.stdint; version (OSX) version = Darwin; else version (iOS) version = Darwin; else version (TVOS) version = Darwin; else version (WatchOS) version = Darwin; version (Posix): extern (C) nothrow: // // Required // /* PTHREAD_CANCEL_ASYNCHRONOUS PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_DEFERRED PTHREAD_CANCEL_DISABLE PTHREAD_CANCELED PTHREAD_COND_INITIALIZER PTHREAD_CREATE_DETACHED PTHREAD_CREATE_JOINABLE PTHREAD_EXPLICIT_SCHED PTHREAD_INHERIT_SCHED PTHREAD_MUTEX_INITIALIZER PTHREAD_ONCE_INIT PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_PRIVATE int pthread_atfork(void function(), void function(), void function()); int pthread_attr_destroy(pthread_attr_t*); int pthread_attr_getdetachstate(in pthread_attr_t*, int*); int pthread_attr_getschedparam(in pthread_attr_t*, sched_param*); int pthread_attr_init(pthread_attr_t*); int pthread_attr_setdetachstate(pthread_attr_t*, int); int pthread_attr_setschedparam(in pthread_attr_t*, sched_param*); int pthread_cancel(pthread_t); void pthread_cleanup_push(void function(void*), void*); void pthread_cleanup_pop(int); int pthread_cond_broadcast(pthread_cond_t*); int pthread_cond_destroy(pthread_cond_t*); int pthread_cond_init(in pthread_cond_t*, pthread_condattr_t*); int pthread_cond_signal(pthread_cond_t*); int pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, in timespec*); int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*); int pthread_condattr_destroy(pthread_condattr_t*); int pthread_condattr_init(pthread_condattr_t*); int pthread_create(pthread_t*, in pthread_attr_t*, void* function(void*), void*); int pthread_detach(pthread_t); int pthread_equal(pthread_t, pthread_t); void pthread_exit(void*); void* pthread_getspecific(pthread_key_t); int pthread_join(pthread_t, void**); int pthread_key_create(pthread_key_t*, void function(void*)); int pthread_key_delete(pthread_key_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_mutexattr_destroy(pthread_mutexattr_t*); int pthread_mutexattr_init(pthread_mutexattr_t*); int pthread_once(pthread_once_t*, void function()); int pthread_rwlock_destroy(pthread_rwlock_t*); int pthread_rwlock_init(pthread_rwlock_t*, in 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*); int pthread_rwlockattr_destroy(pthread_rwlockattr_t*); int pthread_rwlockattr_init(pthread_rwlockattr_t*); pthread_t pthread_self(); int pthread_setcancelstate(int, int*); int pthread_setcanceltype(int, int*); int pthread_setspecific(pthread_key_t, in void*); void pthread_testcancel(); */ version( CRuntime_Glibc ) { enum { PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE } enum { PTHREAD_CANCEL_DEFERRED, PTHREAD_CANCEL_ASYNCHRONOUS } enum PTHREAD_CANCELED = cast(void*) -1; //enum pthread_mutex_t PTHREAD_COND_INITIALIZER = { __LOCK_ALT_INITIALIZER, 0, "", 0 }; enum { PTHREAD_CREATE_JOINABLE, PTHREAD_CREATE_DETACHED } enum { PTHREAD_INHERIT_SCHED, PTHREAD_EXPLICIT_SCHED } enum PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t.init; enum PTHREAD_ONCE_INIT = pthread_once_t.init; enum { PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED } } else version( Darwin ) { enum { PTHREAD_CANCEL_ENABLE = 1, PTHREAD_CANCEL_DISABLE = 0 } enum { PTHREAD_CANCEL_DEFERRED = 2, PTHREAD_CANCEL_ASYNCHRONOUS = 0 } enum PTHREAD_CANCELED = cast(void*) -1; //enum pthread_mutex_t PTHREAD_COND_INITIALIZER = { __LOCK_ALT_INITIALIZER, 0, "", 0 }; enum { PTHREAD_CREATE_JOINABLE = 1, PTHREAD_CREATE_DETACHED = 2 } enum { PTHREAD_INHERIT_SCHED = 1, PTHREAD_EXPLICIT_SCHED = 2 } enum PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0x32AAABA7); enum PTHREAD_ONCE_INIT = pthread_once_t(0x30b1bcba); enum { PTHREAD_PROCESS_PRIVATE = 2, PTHREAD_PROCESS_SHARED = 1 } } else version( FreeBSD ) { enum { PTHREAD_DETACHED = 0x1, PTHREAD_INHERIT_SCHED = 0x4, PTHREAD_NOFLOAT = 0x8, PTHREAD_CREATE_DETACHED = PTHREAD_DETACHED, PTHREAD_CREATE_JOINABLE = 0, PTHREAD_EXPLICIT_SCHED = 0, } enum { PTHREAD_PROCESS_PRIVATE = 0, PTHREAD_PROCESS_SHARED = 1, } enum { PTHREAD_CANCEL_ENABLE = 0, PTHREAD_CANCEL_DISABLE = 1, PTHREAD_CANCEL_DEFERRED = 0, PTHREAD_CANCEL_ASYNCHRONOUS = 2, } enum PTHREAD_CANCELED = cast(void*) -1; enum PTHREAD_NEEDS_INIT = 0; enum PTHREAD_DONE_INIT = 1; enum PTHREAD_MUTEX_INITIALIZER = null; enum PTHREAD_ONCE_INIT = null; enum PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP = null; enum PTHREAD_COND_INITIALIZER = null; enum PTHREAD_RWLOCK_INITIALIZER = null; } else version( OpenBSD ) { enum { PTHREAD_DETACHED = 0x1, PTHREAD_INHERIT_SCHED = 0x4, PTHREAD_NOFLOAT = 0x8, PTHREAD_CREATE_DETACHED = PTHREAD_DETACHED, PTHREAD_CREATE_JOINABLE = 0, PTHREAD_EXPLICIT_SCHED = 0, } enum { PTHREAD_PROCESS_PRIVATE = 0, PTHREAD_PROCESS_SHARED = 1, } enum { PTHREAD_CANCEL_ENABLE = 0, PTHREAD_CANCEL_DISABLE = 1, PTHREAD_CANCEL_DEFERRED = 0, PTHREAD_CANCEL_ASYNCHRONOUS = 2, } enum PTHREAD_CANCELED = cast(void*) 1; enum { PTHREAD_NEEDS_INIT = 0, PTHREAD_DONE_INIT = 1, } enum PTHREAD_MUTEX_INITIALIZER = null; //enum PTHREAD_ONCE_INIT = { PTHREAD_NEEDS_INIT, PTHREAD_MUTEX_INITIALIZER }; enum PTHREAD_COND_INITIALIZER = null; enum PTHREAD_RWLOCK_INITIALIZER = null; } else version (Solaris) { enum { PTHREAD_INHERIT_SCHED = 0x01, PTHREAD_NOFLOAT = 0x08, PTHREAD_CREATE_DETACHED = 0x40, PTHREAD_CREATE_JOINABLE = 0x00, PTHREAD_EXPLICIT_SCHED = 0x00, } enum { PTHREAD_PROCESS_PRIVATE = 0, PTHREAD_PROCESS_SHARED = 1, } enum { PTHREAD_CANCEL_ENABLE = 0, PTHREAD_CANCEL_DISABLE = 1, PTHREAD_CANCEL_DEFERRED = 0, PTHREAD_CANCEL_ASYNCHRONOUS = 2, } enum PTHREAD_CANCELED = cast(void*)-19; enum PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t.init; enum PTHREAD_ONCE_INIT = pthread_once_t.init; } else version( CRuntime_Bionic ) { enum { PTHREAD_CREATE_JOINABLE, PTHREAD_CREATE_DETACHED } enum PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t.init; enum PTHREAD_ONCE_INIT = pthread_once_t.init; enum { PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED } } else { static assert(false, "Unsupported platform"); } int pthread_atfork(void function(), void function(), void function()); int pthread_attr_destroy(pthread_attr_t*); int pthread_attr_getdetachstate(in pthread_attr_t*, int*); int pthread_attr_getschedparam(in pthread_attr_t*, sched_param*); int pthread_attr_init(pthread_attr_t*); int pthread_attr_setdetachstate(pthread_attr_t*, int); int pthread_attr_setschedparam(in pthread_attr_t*, sched_param*); int pthread_cancel(pthread_t); version( CRuntime_Glibc ) { alias void function(void*) _pthread_cleanup_routine; struct _pthread_cleanup_buffer { _pthread_cleanup_routine __routine; void* __arg; int __canceltype; _pthread_cleanup_buffer* __prev; } void _pthread_cleanup_push(_pthread_cleanup_buffer*, _pthread_cleanup_routine, void*); void _pthread_cleanup_pop(_pthread_cleanup_buffer*, int); struct pthread_cleanup { _pthread_cleanup_buffer buffer = void; extern (D) void push()( _pthread_cleanup_routine routine, void* arg ) { _pthread_cleanup_push( &buffer, routine, arg ); } extern (D) void pop()( int execute ) { _pthread_cleanup_pop( &buffer, execute ); } } } else version( Darwin ) { alias void function(void*) _pthread_cleanup_routine; struct _pthread_cleanup_buffer { _pthread_cleanup_routine __routine; void* __arg; _pthread_cleanup_buffer* __next; } struct pthread_cleanup { _pthread_cleanup_buffer buffer = void; extern (D) void push()( _pthread_cleanup_routine routine, void* arg ) { pthread_t self = pthread_self(); buffer.__routine = routine; buffer.__arg = arg; buffer.__next = cast(_pthread_cleanup_buffer*) self.__cleanup_stack; self.__cleanup_stack = cast(pthread_handler_rec*) &buffer; } extern (D) void pop()( int execute ) { pthread_t self = pthread_self(); self.__cleanup_stack = cast(pthread_handler_rec*) buffer.__next; if( execute ) { buffer.__routine( buffer.__arg ); } } } } else version( FreeBSD ) { alias void function(void*) _pthread_cleanup_routine; struct _pthread_cleanup_info { uintptr_t[8] pthread_cleanup_pad; } struct pthread_cleanup { _pthread_cleanup_info __cleanup_info__ = void; extern (D) void push()( _pthread_cleanup_routine cleanup_routine, void* cleanup_arg ) { __pthread_cleanup_push_imp( cleanup_routine, cleanup_arg, &__cleanup_info__ ); } extern (D) void pop()( int execute ) { __pthread_cleanup_pop_imp( execute ); } } void __pthread_cleanup_push_imp(_pthread_cleanup_routine, void*, _pthread_cleanup_info*); void __pthread_cleanup_pop_imp(int); } else version ( OpenBSD ) { void pthread_cleanup_push(void function(void*), void*); void pthread_cleanup_pop(int); } else version (Solaris) { alias void function(void*) _pthread_cleanup_routine; caddr_t _getfp(); struct _pthread_cleanup_info { uintptr_t[4] pthread_cleanup_pad; } struct pthread_cleanup { _pthread_cleanup_info __cleanup_info__ = void; extern (D) void push()(_pthread_cleanup_routine cleanup_routine, void* cleanup_arg) { __pthread_cleanup_push(cleanup_routine, cleanup_arg, _getfp(), &__cleanup_info__); } extern (D) void pop()(int execute) { __pthread_cleanup_pop(execute, &__cleanup_info__); } } void __pthread_cleanup_push(_pthread_cleanup_routine, void*, caddr_t, _pthread_cleanup_info*); void __pthread_cleanup_pop(int, _pthread_cleanup_info*); } else version( CRuntime_Bionic ) { alias void function(void*) __pthread_cleanup_func_t; struct __pthread_cleanup_t { __pthread_cleanup_t* __cleanup_prev; __pthread_cleanup_func_t __cleanup_routine; void* __cleanup_arg; } void __pthread_cleanup_push(__pthread_cleanup_t*, __pthread_cleanup_func_t, void*); void __pthread_cleanup_pop(__pthread_cleanup_t*, int); struct pthread_cleanup { __pthread_cleanup_t __cleanup = void; extern (D) void push()( __pthread_cleanup_func_t routine, void* arg ) { __pthread_cleanup_push( &__cleanup, routine, arg ); } extern (D) void pop()( int execute ) { __pthread_cleanup_pop( &__cleanup, execute ); } } } else { static assert(false, "Unsupported platform"); } @nogc { int pthread_cond_broadcast(pthread_cond_t*); int pthread_cond_destroy(pthread_cond_t*); int pthread_cond_init(in pthread_cond_t*, pthread_condattr_t*) @trusted; int pthread_cond_signal(pthread_cond_t*); int pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, in timespec*); int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*); int pthread_condattr_destroy(pthread_condattr_t*); int pthread_condattr_init(pthread_condattr_t*); int pthread_create(pthread_t*, in pthread_attr_t*, void* function(void*), void*); int pthread_detach(pthread_t); int pthread_equal(pthread_t, pthread_t); void pthread_exit(void*); void* pthread_getspecific(pthread_key_t); int pthread_join(pthread_t, void**); int pthread_key_create(pthread_key_t*, void function(void*)); int pthread_key_delete(pthread_key_t); int pthread_mutex_destroy(pthread_mutex_t*); int pthread_mutex_init(pthread_mutex_t*, pthread_mutexattr_t*) @trusted; int pthread_mutex_lock(pthread_mutex_t*); int pthread_mutex_trylock(pthread_mutex_t*); int pthread_mutex_unlock(pthread_mutex_t*); int pthread_mutexattr_destroy(pthread_mutexattr_t*); int pthread_mutexattr_init(pthread_mutexattr_t*) @trusted; int pthread_once(pthread_once_t*, void function()); int pthread_rwlock_destroy(pthread_rwlock_t*); int pthread_rwlock_init(pthread_rwlock_t*, in 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*); int pthread_rwlockattr_destroy(pthread_rwlockattr_t*); int pthread_rwlockattr_init(pthread_rwlockattr_t*); pthread_t pthread_self(); int pthread_setcancelstate(int, int*); int pthread_setcanceltype(int, int*); int pthread_setspecific(pthread_key_t, in void*); void pthread_testcancel(); } // // Barrier (BAR) // /* PTHREAD_BARRIER_SERIAL_THREAD int pthread_barrier_destroy(pthread_barrier_t*); int pthread_barrier_init(pthread_barrier_t*, in pthread_barrierattr_t*, uint); int pthread_barrier_wait(pthread_barrier_t*); int pthread_barrierattr_destroy(pthread_barrierattr_t*); int pthread_barrierattr_getpshared(in pthread_barrierattr_t*, int*); (BAR|TSH) int pthread_barrierattr_init(pthread_barrierattr_t*); int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); (BAR|TSH) */ version( CRuntime_Glibc ) { enum PTHREAD_BARRIER_SERIAL_THREAD = -1; int pthread_barrier_destroy(pthread_barrier_t*); int pthread_barrier_init(pthread_barrier_t*, in pthread_barrierattr_t*, uint); int pthread_barrier_wait(pthread_barrier_t*); int pthread_barrierattr_destroy(pthread_barrierattr_t*); int pthread_barrierattr_getpshared(in pthread_barrierattr_t*, int*); int pthread_barrierattr_init(pthread_barrierattr_t*); int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); } else version( FreeBSD ) { enum PTHREAD_BARRIER_SERIAL_THREAD = -1; int pthread_barrier_destroy(pthread_barrier_t*); int pthread_barrier_init(pthread_barrier_t*, in pthread_barrierattr_t*, uint); int pthread_barrier_wait(pthread_barrier_t*); int pthread_barrierattr_destroy(pthread_barrierattr_t*); int pthread_barrierattr_getpshared(in pthread_barrierattr_t*, int*); int pthread_barrierattr_init(pthread_barrierattr_t*); int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); } else version( OpenBSD ) { enum PTHREAD_BARRIER_SERIAL_THREAD = -1; int pthread_barrier_destroy(pthread_barrier_t*); int pthread_barrier_init(pthread_barrier_t*, in pthread_barrierattr_t*, uint); int pthread_barrier_wait(pthread_barrier_t*); int pthread_barrierattr_destroy(pthread_barrierattr_t*); int pthread_barrierattr_getpshared(in pthread_barrierattr_t*, int*); int pthread_barrierattr_init(pthread_barrierattr_t*); int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); } else version (Darwin) { } else version (Solaris) { enum PTHREAD_BARRIER_SERIAL_THREAD = -2; int pthread_barrier_destroy(pthread_barrier_t*); int pthread_barrier_init(pthread_barrier_t*, in pthread_barrierattr_t*, uint); int pthread_barrier_wait(pthread_barrier_t*); int pthread_barrierattr_destroy(pthread_barrierattr_t*); int pthread_barrierattr_getpshared(in pthread_barrierattr_t*, int*); int pthread_barrierattr_init(pthread_barrierattr_t*); int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); } else version (CRuntime_Bionic) { } else { static assert(false, "Unsupported platform"); } // // Clock (CS) // /* int pthread_condattr_getclock(in pthread_condattr_t*, clockid_t*); int pthread_condattr_setclock(pthread_condattr_t*, clockid_t); */ // // Spinlock (SPI) // /* int pthread_spin_destroy(pthread_spinlock_t*); int pthread_spin_init(pthread_spinlock_t*, int); int pthread_spin_lock(pthread_spinlock_t*); int pthread_spin_trylock(pthread_spinlock_t*); int pthread_spin_unlock(pthread_spinlock_t*); */ version( CRuntime_Glibc ) { int pthread_spin_destroy(pthread_spinlock_t*); int pthread_spin_init(pthread_spinlock_t*, int); int pthread_spin_lock(pthread_spinlock_t*); int pthread_spin_trylock(pthread_spinlock_t*); int pthread_spin_unlock(pthread_spinlock_t*); } else version( FreeBSD ) { int pthread_spin_init(pthread_spinlock_t*, int); int pthread_spin_destroy(pthread_spinlock_t*); int pthread_spin_lock(pthread_spinlock_t*); int pthread_spin_trylock(pthread_spinlock_t*); int pthread_spin_unlock(pthread_spinlock_t*); } else version( OpenBSD ) { int pthread_spin_init(pthread_spinlock_t*, int); int pthread_spin_destroy(pthread_spinlock_t*); int pthread_spin_lock(pthread_spinlock_t*); int pthread_spin_trylock(pthread_spinlock_t*); int pthread_spin_unlock(pthread_spinlock_t*); } else version (Darwin) { } else version (Solaris) { int pthread_spin_init(pthread_spinlock_t*, int); int pthread_spin_destroy(pthread_spinlock_t*); int pthread_spin_lock(pthread_spinlock_t*); int pthread_spin_trylock(pthread_spinlock_t*); int pthread_spin_unlock(pthread_spinlock_t*); } else version (CRuntime_Bionic) { } else { static assert(false, "Unsupported platform"); } // // XOpen (XSI) // /* PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_RECURSIVE int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); int pthread_attr_setguardsize(pthread_attr_t*, size_t); int pthread_getconcurrency(); int pthread_mutexattr_gettype(in pthread_mutexattr_t*, int*); int pthread_mutexattr_settype(pthread_mutexattr_t*, int); int pthread_setconcurrency(int); */ version( CRuntime_Glibc ) { enum PTHREAD_MUTEX_NORMAL = 0; enum PTHREAD_MUTEX_RECURSIVE = 1; enum PTHREAD_MUTEX_ERRORCHECK = 2; enum PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL; int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); int pthread_attr_setguardsize(pthread_attr_t*, size_t); int pthread_getconcurrency(); int pthread_mutexattr_gettype(in pthread_mutexattr_t*, int*); int pthread_mutexattr_settype(pthread_mutexattr_t*, int) @trusted; int pthread_setconcurrency(int); } else version( Darwin ) { enum PTHREAD_MUTEX_NORMAL = 0; enum PTHREAD_MUTEX_ERRORCHECK = 1; enum PTHREAD_MUTEX_RECURSIVE = 2; enum PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL; int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); int pthread_attr_setguardsize(pthread_attr_t*, size_t); int pthread_getconcurrency(); int pthread_mutexattr_gettype(in pthread_mutexattr_t*, int*); int pthread_mutexattr_settype(pthread_mutexattr_t*, int) @trusted; int pthread_setconcurrency(int); } else version( FreeBSD ) { enum { PTHREAD_MUTEX_ERRORCHECK = 1, PTHREAD_MUTEX_RECURSIVE = 2, PTHREAD_MUTEX_NORMAL = 3, PTHREAD_MUTEX_ADAPTIVE_NP = 4, PTHREAD_MUTEX_TYPE_MAX } enum PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_ERRORCHECK; int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); int pthread_attr_setguardsize(pthread_attr_t*, size_t); int pthread_getconcurrency(); int pthread_mutexattr_gettype(pthread_mutexattr_t*, int*); int pthread_mutexattr_settype(pthread_mutexattr_t*, int) @trusted; int pthread_setconcurrency(int); } else version( OpenBSD ) { enum { PTHREAD_MUTEX_ERRORCHECK = 1, PTHREAD_MUTEX_RECURSIVE = 2, PTHREAD_MUTEX_NORMAL = 3, PTHREAD_MUTEX_ADAPTIVE_NP = 4, PTHREAD_MUTEX_TYPE_MAX } enum PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_ERRORCHECK; int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); int pthread_attr_setguardsize(pthread_attr_t*, size_t); int pthread_getconcurrency(); int pthread_mutexattr_gettype(pthread_mutexattr_t*, int*); int pthread_mutexattr_settype(pthread_mutexattr_t*, int) @trusted; int pthread_setconcurrency(int); } else version (Solaris) { enum { PTHREAD_MUTEX_ERRORCHECK = 2, PTHREAD_MUTEX_RECURSIVE = 4, PTHREAD_MUTEX_NORMAL = 0, } enum PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL; int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); int pthread_attr_setguardsize(pthread_attr_t*, size_t); int pthread_getconcurrency(); int pthread_mutexattr_gettype(pthread_mutexattr_t*, int*); int pthread_mutexattr_settype(pthread_mutexattr_t*, int) @trusted; int pthread_setconcurrency(int); } else version (CRuntime_Bionic) { enum PTHREAD_MUTEX_NORMAL = 0; enum PTHREAD_MUTEX_RECURSIVE = 1; enum PTHREAD_MUTEX_ERRORCHECK = 2; enum PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL; int pthread_attr_getguardsize(in pthread_attr_t*, size_t*); int pthread_attr_setguardsize(pthread_attr_t*, size_t); int pthread_mutexattr_gettype(in pthread_mutexattr_t*, int*); int pthread_mutexattr_settype(pthread_mutexattr_t*, int) @trusted; } else { static assert(false, "Unsupported platform"); } // // CPU Time (TCT) // /* int pthread_getcpuclockid(pthread_t, clockid_t*); */ version( CRuntime_Glibc ) { int pthread_getcpuclockid(pthread_t, clockid_t*); } else version( FreeBSD ) { int pthread_getcpuclockid(pthread_t, clockid_t*); } else version( OpenBSD ) { int pthread_getcpuclockid(pthread_t, clockid_t*); } else version (Darwin) { } else version (Solaris) { } else version( CRuntime_Bionic ) { int pthread_getcpuclockid(pthread_t, clockid_t*); } else { static assert(false, "Unsupported platform"); } // // Timeouts (TMO) // /* int pthread_mutex_timedlock(pthread_mutex_t*, in timespec*); int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); */ version( CRuntime_Glibc ) { int pthread_mutex_timedlock(pthread_mutex_t*, in timespec*); int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); } else version( Darwin ) { int pthread_mutex_timedlock(pthread_mutex_t*, in timespec*); int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); } else version( FreeBSD ) { int pthread_mutex_timedlock(pthread_mutex_t*, in timespec*); int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); } else version( OpenBSD ) { int pthread_mutex_timedlock(pthread_mutex_t*, in timespec*); int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); } else version (Solaris) { int pthread_mutex_timedlock(pthread_mutex_t*, in timespec*); int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); } else version( CRuntime_Bionic ) { int pthread_rwlock_timedrdlock(pthread_rwlock_t*, in timespec*); int pthread_rwlock_timedwrlock(pthread_rwlock_t*, in timespec*); } else { static assert(false, "Unsupported platform"); } // // Priority (TPI|TPP) // /* PTHREAD_PRIO_INHERIT (TPI) PTHREAD_PRIO_NONE (TPP|TPI) PTHREAD_PRIO_PROTECT (TPI) int pthread_mutex_getprioceiling(in pthread_mutex_t*, int*); (TPP) int pthread_mutex_setprioceiling(pthread_mutex_t*, int, int*); (TPP) int pthread_mutexattr_getprioceiling(pthread_mutexattr_t*, int*); (TPP) int pthread_mutexattr_getprotocol(in pthread_mutexattr_t*, int*); (TPI|TPP) int pthread_mutexattr_setprioceiling(pthread_mutexattr_t*, int); (TPP) int pthread_mutexattr_setprotocol(pthread_mutexattr_t*, int); (TPI|TPP) */ version( Darwin ) { enum { PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT, PTHREAD_PRIO_PROTECT } int pthread_mutex_getprioceiling(in pthread_mutex_t*, int*); int pthread_mutex_setprioceiling(pthread_mutex_t*, int, int*); int pthread_mutexattr_getprioceiling(in pthread_mutexattr_t*, int*); int pthread_mutexattr_getprotocol(in pthread_mutexattr_t*, int*); int pthread_mutexattr_setprioceiling(pthread_mutexattr_t*, int); int pthread_mutexattr_setprotocol(pthread_mutexattr_t*, int); } else version( Solaris ) { enum { PTHREAD_PRIO_NONE = 0x00, PTHREAD_PRIO_INHERIT = 0x10, PTHREAD_PRIO_PROTECT = 0x20, } int pthread_mutex_getprioceiling(in pthread_mutex_t*, int*); int pthread_mutex_setprioceiling(pthread_mutex_t*, int, int*); int pthread_mutexattr_getprioceiling(in pthread_mutexattr_t*, int*); int pthread_mutexattr_getprotocol(in pthread_mutexattr_t*, int*); int pthread_mutexattr_setprioceiling(pthread_mutexattr_t*, int); int pthread_mutexattr_setprotocol(pthread_mutexattr_t*, int); } // // Scheduling (TPS) // /* PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_SYSTEM int pthread_attr_getinheritsched(in pthread_attr_t*, int*); int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); int pthread_attr_getscope(in pthread_attr_t*, int*); int pthread_attr_setinheritsched(pthread_attr_t*, int); int pthread_attr_setschedpolicy(pthread_attr_t*, int); int pthread_attr_setscope(pthread_attr_t*, int); int pthread_getschedparam(pthread_t, int*, sched_param*); int pthread_setschedparam(pthread_t, int, in sched_param*); int pthread_setschedprio(pthread_t, int); */ version( CRuntime_Glibc ) { enum { PTHREAD_SCOPE_SYSTEM, PTHREAD_SCOPE_PROCESS } int pthread_attr_getinheritsched(in pthread_attr_t*, int*); int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); int pthread_attr_getscope(in pthread_attr_t*, int*); int pthread_attr_setinheritsched(pthread_attr_t*, int); int pthread_attr_setschedpolicy(pthread_attr_t*, int); int pthread_attr_setscope(pthread_attr_t*, int); int pthread_getschedparam(pthread_t, int*, sched_param*); int pthread_setschedparam(pthread_t, int, in sched_param*); int pthread_setschedprio(pthread_t, int); } else version( Darwin ) { enum { PTHREAD_SCOPE_SYSTEM = 1, PTHREAD_SCOPE_PROCESS = 2 } int pthread_attr_getinheritsched(in pthread_attr_t*, int*); int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); int pthread_attr_getscope(in pthread_attr_t*, int*); int pthread_attr_setinheritsched(pthread_attr_t*, int); int pthread_attr_setschedpolicy(pthread_attr_t*, int); int pthread_attr_setscope(pthread_attr_t*, int); int pthread_getschedparam(pthread_t, int*, sched_param*); int pthread_setschedparam(pthread_t, int, in sched_param*); // int pthread_setschedprio(pthread_t, int); // not implemented } else version( FreeBSD ) { enum { PTHREAD_SCOPE_PROCESS = 0, PTHREAD_SCOPE_SYSTEM = 0x2 } int pthread_attr_getinheritsched(in pthread_attr_t*, int*); int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); int pthread_attr_getscope(in pthread_attr_t*, int*); int pthread_attr_setinheritsched(pthread_attr_t*, int); int pthread_attr_setschedpolicy(pthread_attr_t*, int); int pthread_attr_setscope(in pthread_attr_t*, int); int pthread_getschedparam(pthread_t, int*, sched_param*); int pthread_setschedparam(pthread_t, int, sched_param*); // int pthread_setschedprio(pthread_t, int); // not implemented } else version( OpenBSD ) { enum { PTHREAD_SCOPE_PROCESS = 0, PTHREAD_SCOPE_SYSTEM = 0x2 } int pthread_attr_getinheritsched(in pthread_attr_t*, int*); int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); int pthread_attr_getscope(in pthread_attr_t*, int*); int pthread_attr_setinheritsched(pthread_attr_t*, int); int pthread_attr_setschedpolicy(pthread_attr_t*, int); int pthread_attr_setscope(in pthread_attr_t*, int); int pthread_getschedparam(pthread_t, int*, sched_param*); int pthread_setschedparam(pthread_t, int, sched_param*); // int pthread_setschedprio(pthread_t, int); // not implemented } else version (Solaris) { enum { PTHREAD_SCOPE_PROCESS = 0, PTHREAD_SCOPE_SYSTEM = 1, } int pthread_attr_getinheritsched(in pthread_attr_t*, int*); int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); int pthread_attr_getscope(in pthread_attr_t*, int*); int pthread_attr_setinheritsched(pthread_attr_t*, int); int pthread_attr_setschedpolicy(pthread_attr_t*, int); int pthread_attr_setscope(in pthread_attr_t*, int); int pthread_getschedparam(pthread_t, int*, sched_param*); int pthread_setschedparam(pthread_t, int, sched_param*); int pthread_setschedprio(pthread_t, int); } else version (CRuntime_Bionic) { enum { PTHREAD_SCOPE_SYSTEM, PTHREAD_SCOPE_PROCESS } int pthread_attr_getschedpolicy(in pthread_attr_t*, int*); int pthread_attr_getscope(in pthread_attr_t*); int pthread_attr_setschedpolicy(pthread_attr_t*, int); int pthread_attr_setscope(pthread_attr_t*, int); int pthread_getschedparam(pthread_t, int*, sched_param*); int pthread_setschedparam(pthread_t, int, in sched_param*); } else { static assert(false, "Unsupported platform"); } // // Stack (TSA|TSS) // /* int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); (TSA|TSS) int pthread_attr_getstackaddr(in pthread_attr_t*, void**); (TSA) int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); (TSS) int pthread_attr_setstack(pthread_attr_t*, void*, size_t); (TSA|TSS) int pthread_attr_setstackaddr(pthread_attr_t*, void*); (TSA) int pthread_attr_setstacksize(pthread_attr_t*, size_t); (TSS) */ version( CRuntime_Glibc ) { int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); int pthread_attr_getstackaddr(in pthread_attr_t*, void**); int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); int pthread_attr_setstack(pthread_attr_t*, void*, size_t); int pthread_attr_setstackaddr(pthread_attr_t*, void*); int pthread_attr_setstacksize(pthread_attr_t*, size_t); } else version( Darwin ) { int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); int pthread_attr_getstackaddr(in pthread_attr_t*, void**); int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); int pthread_attr_setstack(pthread_attr_t*, void*, size_t); int pthread_attr_setstackaddr(pthread_attr_t*, void*); int pthread_attr_setstacksize(pthread_attr_t*, size_t); } else version( FreeBSD ) { int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); int pthread_attr_getstackaddr(in pthread_attr_t*, void**); int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); int pthread_attr_setstack(pthread_attr_t*, void*, size_t); int pthread_attr_setstackaddr(pthread_attr_t*, void*); int pthread_attr_setstacksize(pthread_attr_t*, size_t); } else version( OpenBSD ) { int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); int pthread_attr_getstackaddr(in pthread_attr_t*, void**); int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); int pthread_attr_setstack(pthread_attr_t*, void*, size_t); int pthread_attr_setstackaddr(pthread_attr_t*, void*); int pthread_attr_setstacksize(pthread_attr_t*, size_t); } else version (Solaris) { int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); int pthread_attr_getstackaddr(in pthread_attr_t*, void**); int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); int pthread_attr_setstack(pthread_attr_t*, void*, size_t); int pthread_attr_setstackaddr(pthread_attr_t*, void*); int pthread_attr_setstacksize(pthread_attr_t*, size_t); } else version (CRuntime_Bionic) { int pthread_attr_getstack(in pthread_attr_t*, void**, size_t*); int pthread_attr_getstackaddr(in pthread_attr_t*, void**); int pthread_attr_getstacksize(in pthread_attr_t*, size_t*); int pthread_attr_setstack(pthread_attr_t*, void*, size_t); int pthread_attr_setstackaddr(pthread_attr_t*, void*); int pthread_attr_setstacksize(pthread_attr_t*, size_t); } else { static assert(false, "Unsupported platform"); } // // Shared Synchronization (TSH) // /* int pthread_condattr_getpshared(in pthread_condattr_t*, int*); int pthread_condattr_setpshared(pthread_condattr_t*, int); int pthread_mutexattr_getpshared(in pthread_mutexattr_t*, int*); int pthread_mutexattr_setpshared(pthread_mutexattr_t*, int); int pthread_rwlockattr_getpshared(in pthread_rwlockattr_t*, int*); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int); */ version (CRuntime_Glibc) { int pthread_condattr_getpshared(in pthread_condattr_t*, int*); int pthread_condattr_setpshared(pthread_condattr_t*, int); int pthread_mutexattr_getpshared(in pthread_mutexattr_t*, int*); int pthread_mutexattr_setpshared(pthread_mutexattr_t*, int); int pthread_rwlockattr_getpshared(in pthread_rwlockattr_t*, int*); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int); } else version( FreeBSD ) { int pthread_condattr_getpshared(in pthread_condattr_t*, int*); int pthread_condattr_setpshared(pthread_condattr_t*, int); int pthread_mutexattr_getpshared(in pthread_mutexattr_t*, int*); int pthread_mutexattr_setpshared(pthread_mutexattr_t*, int); int pthread_rwlockattr_getpshared(in pthread_rwlockattr_t*, int*); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int); } else version( OpenBSD ) { } else version( Darwin ) { int pthread_condattr_getpshared(in pthread_condattr_t*, int*); int pthread_condattr_setpshared(pthread_condattr_t*, int); int pthread_mutexattr_getpshared(in pthread_mutexattr_t*, int*); int pthread_mutexattr_setpshared(pthread_mutexattr_t*, int); int pthread_rwlockattr_getpshared(in pthread_rwlockattr_t*, int*); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int); } else version (Solaris) { int pthread_condattr_getpshared(in pthread_condattr_t*, int*); int pthread_condattr_setpshared(pthread_condattr_t*, int); int pthread_mutexattr_getpshared(in pthread_mutexattr_t*, int*); int pthread_mutexattr_setpshared(pthread_mutexattr_t*, int); int pthread_rwlockattr_getpshared(in pthread_rwlockattr_t*, int*); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int); } else version (CRuntime_Bionic) { int pthread_condattr_getpshared(pthread_condattr_t*, int*); int pthread_condattr_setpshared(pthread_condattr_t*, int); int pthread_mutexattr_getpshared(pthread_mutexattr_t*, int*); int pthread_mutexattr_setpshared(pthread_mutexattr_t*, int); int pthread_rwlockattr_getpshared(pthread_rwlockattr_t*, int*); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/termios.d0000664000175000017500000004364312776214756023023 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.termios; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for pid_t version (Posix): extern (C): nothrow: @nogc: // // Required // /* cc_t speed_t tcflag_t NCCS struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t[NCCS] c_cc; } VEOF VEOL VERASE VINTR VKILL VMIN VQUIT VSTART VSTOP VSUSP VTIME BRKINT ICRNL IGNBRK IGNCR IGNPAR INLCR INPCK ISTRIP IXOFF IXON PARMRK OPOST B0 B50 B75 B110 B134 B150 B200 B300 B600 B1200 B1800 B2400 B4800 B9600 B19200 B38400 CSIZE CS5 CS6 CS7 CS8 CSTOPB CREAD PARENB PARODD HUPCL CLOCAL ECHO ECHOE ECHOK ECHONL ICANON IEXTEN ISIG NOFLSH TOSTOP TCSANOW TCSADRAIN TCSAFLUSH TCIFLUSH TCIOFLUSH TCOFLUSH TCIOFF TCION TCOOFF TCOON speed_t cfgetispeed(in termios*); speed_t cfgetospeed(in termios*); int cfsetispeed(termios*, speed_t); int cfsetospeed(termios*, speed_t); int tcdrain(int); int tcflow(int, int); int tcflush(int, int); int tcgetattr(int, termios*); int tcsendbreak(int, int); int tcsetattr(int, int, in termios*); */ version( CRuntime_Glibc ) { alias ubyte cc_t; alias uint speed_t; alias uint tcflag_t; enum NCCS = 32; struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t c_line; cc_t[NCCS] c_cc; speed_t c_ispeed; speed_t c_ospeed; } enum VEOF = 4; enum VEOL = 11; enum VERASE = 2; enum VINTR = 0; enum VKILL = 3; enum VMIN = 6; enum VQUIT = 1; enum VSTART = 8; enum VSTOP = 9; enum VSUSP = 10; enum VTIME = 5; enum BRKINT = 0x0000002; // 0000002 enum ICRNL = 0x0000100; // 0000400 enum IGNBRK = 0x0000001; // 0000001 enum IGNCR = 0x0000080; // 0000200 enum IGNPAR = 0x0000004; // 0000004 enum INLCR = 0x0000040; // 0000100 enum INPCK = 0x0000010; // 0000020 enum ISTRIP = 0x0000020; // 0000040 enum IXOFF = 0x0001000; // 0010000 enum IXON = 0x0000400; // 0002000 enum PARMRK = 0x0000008; // 0000010 enum OPOST = 0x0000001; // 0000001 enum B0 = 0x0000000; // 0000000 enum B50 = 0x0000001; // 0000001 enum B75 = 0x0000002; // 0000002 enum B110 = 0x0000003; // 0000003 enum B134 = 0x0000004; // 0000004 enum B150 = 0x0000005; // 0000005 enum B200 = 0x0000006; // 0000006 enum B300 = 0x0000007; // 0000007 enum B600 = 0x0000008; // 0000010 enum B1200 = 0x0000009; // 0000011 enum B1800 = 0x000000A; // 0000012 enum B2400 = 0x000000B; // 0000013 enum B4800 = 0x000000C; // 0000014 enum B9600 = 0x000000D; // 0000015 enum B19200 = 0x000000E; // 0000016 enum B38400 = 0x000000F; // 0000017 enum CSIZE = 0x0000030; // 0000060 enum CS5 = 0x0000000; // 0000000 enum CS6 = 0x0000010; // 0000020 enum CS7 = 0x0000020; // 0000040 enum CS8 = 0x0000030; // 0000060 enum CSTOPB = 0x0000040; // 0000100 enum CREAD = 0x0000080; // 0000200 enum PARENB = 0x0000100; // 0000400 enum PARODD = 0x0000200; // 0001000 enum HUPCL = 0x0000400; // 0002000 enum CLOCAL = 0x0000800; // 0004000 enum ECHO = 0x0000008; // 0000010 enum ECHOE = 0x0000010; // 0000020 enum ECHOK = 0x0000020; // 0000040 enum ECHONL = 0x0000040; // 0000100 enum ICANON = 0x0000002; // 0000002 enum IEXTEN = 0x0008000; // 0100000 enum ISIG = 0x0000001; // 0000001 enum NOFLSH = 0x0000080; // 0000200 enum TOSTOP = 0x0000100; // 0000400 enum TCSANOW = 0; enum TCSADRAIN = 1; enum TCSAFLUSH = 2; enum TCIFLUSH = 0; enum TCOFLUSH = 1; enum TCIOFLUSH = 2; enum TCIOFF = 2; enum TCION = 3; enum TCOOFF = 0; enum TCOON = 1; speed_t cfgetispeed(in termios*); speed_t cfgetospeed(in termios*); int cfsetispeed(termios*, speed_t); int cfsetospeed(termios*, speed_t); int tcdrain(int); int tcflow(int, int); int tcflush(int, int); int tcgetattr(int, termios*); int tcsendbreak(int, int); int tcsetattr(int, int, in termios*); } else version( OSX ) { alias ubyte cc_t; alias c_ulong speed_t; alias c_ulong tcflag_t; enum NCCS = 20; struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t[NCCS] c_cc; speed_t c_ispeed; speed_t c_ospeed; } enum VEOF = 0; enum VEOL = 1; enum VERASE = 3; enum VINTR = 8; enum VKILL = 5; enum VMIN = 16; enum VQUIT = 9; enum VSTART = 12; enum VSTOP = 13; enum VSUSP = 10; enum VTIME = 17; enum BRKINT = 0x0000002; enum ICRNL = 0x0000100; enum IGNBRK = 0x0000001; enum IGNCR = 0x0000080; enum IGNPAR = 0x0000004; enum INLCR = 0x0000040; enum INPCK = 0x0000010; enum ISTRIP = 0x0000020; enum IXOFF = 0x0000400; enum IXON = 0x0000200; enum PARMRK = 0x0000008; enum OPOST = 0x0000001; enum B0 = 0; enum B50 = 50; enum B75 = 75; enum B110 = 110; enum B134 = 134; enum B150 = 150; enum B200 = 200; enum B300 = 300; enum B600 = 600; enum B1200 = 1200; enum B1800 = 1800; enum B2400 = 2400; enum B4800 = 4800; enum B9600 = 9600; enum B19200 = 19200; enum B38400 = 38400; enum CSIZE = 0x0000300; enum CS5 = 0x0000000; enum CS6 = 0x0000100; enum CS7 = 0x0000200; enum CS8 = 0x0000300; enum CSTOPB = 0x0000400; enum CREAD = 0x0000800; enum PARENB = 0x0001000; enum PARODD = 0x0002000; enum HUPCL = 0x0004000; enum CLOCAL = 0x0008000; enum ECHO = 0x00000008; enum ECHOE = 0x00000002; enum ECHOK = 0x00000004; enum ECHONL = 0x00000010; enum ICANON = 0x00000100; enum IEXTEN = 0x00000400; enum ISIG = 0x00000080; enum NOFLSH = 0x80000000; enum TOSTOP = 0x00400000; enum TCSANOW = 0; enum TCSADRAIN = 1; enum TCSAFLUSH = 2; enum TCIFLUSH = 1; enum TCOFLUSH = 2; enum TCIOFLUSH = 3; enum TCIOFF = 3; enum TCION = 4; enum TCOOFF = 1; enum TCOON = 2; speed_t cfgetispeed(in termios*); speed_t cfgetospeed(in termios*); int cfsetispeed(termios*, speed_t); int cfsetospeed(termios*, speed_t); int tcdrain(int); int tcflow(int, int); int tcflush(int, int); int tcgetattr(int, termios*); int tcsendbreak(int, int); int tcsetattr(int, int, in termios*); } else version ( FreeBSD ) { alias ubyte cc_t; alias uint speed_t; alias uint tcflag_t; enum NCCS = 20; struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t[NCCS] c_cc; speed_t c_ispeed; speed_t c_ospeed; } enum VEOF = 0; enum VEOL = 1; enum VERASE = 3; enum VINTR = 8; enum VKILL = 5; enum VMIN = 16; enum VQUIT = 9; enum VSTART = 12; enum VSTOP = 13; enum VSUSP = 10; enum VTIME = 17; enum BRKINT = 0x0000002; enum ICRNL = 0x0000100; enum IGNBRK = 0x0000001; enum IGNCR = 0x0000080; enum IGNPAR = 0x0000004; enum INLCR = 0x0000040; enum INPCK = 0x0000010; enum ISTRIP = 0x0000020; enum IXOFF = 0x0000400; enum IXON = 0x0000200; enum PARMRK = 0x0000008; enum OPOST = 0x0000001; enum B0 = 0; enum B50 = 50; enum B75 = 75; enum B110 = 110; enum B134 = 134; enum B150 = 150; enum B200 = 200; enum B300 = 300; enum B600 = 600; enum B1200 = 1200; enum B1800 = 1800; enum B2400 = 2400; enum B4800 = 4800; enum B9600 = 9600; enum B19200 = 19200; enum B38400 = 38400; enum CSIZE = 0x0000300; enum CS5 = 0x0000000; enum CS6 = 0x0000100; enum CS7 = 0x0000200; enum CS8 = 0x0000300; enum CSTOPB = 0x0000400; enum CREAD = 0x0000800; enum PARENB = 0x0001000; enum PARODD = 0x0002000; enum HUPCL = 0x0004000; enum CLOCAL = 0x0008000; enum ECHO = 0x00000008; enum ECHOE = 0x00000002; enum ECHOK = 0x00000004; enum ECHONL = 0x00000010; enum ICANON = 0x00000100; enum IEXTEN = 0x00000400; enum ISIG = 0x00000080; enum NOFLSH = 0x80000000; enum TOSTOP = 0x00400000; enum TCSANOW = 0; enum TCSADRAIN = 1; enum TCSAFLUSH = 2; enum TCIFLUSH = 1; enum TCOFLUSH = 2; enum TCIOFLUSH = 3; enum TCIOFF = 3; enum TCION = 4; enum TCOOFF = 1; enum TCOON = 2; speed_t cfgetispeed(in termios*); speed_t cfgetospeed(in termios*); int cfsetispeed(termios*, speed_t); int cfsetospeed(termios*, speed_t); int tcdrain(int); int tcflow(int, int); int tcflush(int, int); int tcgetattr(int, termios*); int tcsendbreak(int, int); int tcsetattr(int, int, in termios*); } else version (Solaris) { alias tcflag_t = uint; alias cc_t = ubyte; alias speed_t = uint; enum NCCS = 19; struct termios { tcflag_t c_iflag; /* input modes */ tcflag_t c_oflag; /* output modes */ tcflag_t c_cflag; /* control modes */ tcflag_t c_lflag; /* line discipline modes */ cc_t[NCCS] c_cc; /* control chars */ } /* control characters */ enum VINTR = 0; enum VQUIT = 1; enum VERASE = 2; enum VKILL = 3; enum VEOF = 4; enum VEOL = 5; enum VMIN = 4; enum VTIME = 5; enum VSTART = 8; enum VSTOP = 9; enum VSUSP = 10; /* input modes */ enum IGNBRK = 0x000001; enum BRKINT = 0x000002; enum IGNPAR = 0x000004; enum PARMRK = 0x000008; enum INPCK = 0x000010; enum ISTRIP = 0x000020; enum INLCR = 0x000040; enum IGNCR = 0x000080; enum ICRNL = 0x000100; enum IXON = 0x000400; enum IXOFF = 0x001000; /* output modes */ enum OPOST = 0x000001; /* control modes */ enum CSIZE = 0x000030; enum CS5 = 0x000000; enum CS6 = 0x000010; enum CS7 = 0x000020; enum CS8 = 0x000030; enum CSTOPB = 0x000040; enum CREAD = 0x000080; enum PARENB = 0x000100; enum PARODD = 0x000200; enum HUPCL = 0x000400; enum CLOCAL = 0x000800; enum CRTSCTS = 0x10000000; /* line discipline 0 modes */ enum ISIG = 0x000001; enum ICANON = 0x000002; enum ECHO = 0x000008; enum ECHOE = 0x000010; enum ECHOK = 0x000020; enum ECHONL = 0x000040; enum NOFLSH = 0x000080; enum TOSTOP = 0x000100; enum ECHOCTL = 0x000200; enum ECHOPRT = 0x000400; enum ECHOKE = 0x000800; enum IEXTEN = 0x008000; /* POSIX flag - enable POSIX extensions */ enum _TIOC = ('T'<<8); enum TCSANOW = (_TIOC|14); enum TCSADRAIN = (_TIOC|15); enum TCSAFLUSH = (_TIOC|16); /* termios option flags */ enum TCIFLUSH = 0; /* flush data received but not read */ enum TCOFLUSH = 1; /* flush data written but not transmitted */ enum TCIOFLUSH = 2; /* flush both data both input and output queues */ enum TCOOFF = 0; /* suspend output */ enum TCOON = 1; /* restart suspended output */ enum TCIOFF = 2; /* suspend input */ enum TCION = 3; /* restart suspended input */ /* Speeds */ enum B0 = 0; enum B50 = 1; enum B75 = 2; enum B110 = 3; enum B134 = 4; enum B150 = 5; enum B200 = 6; enum B300 = 7; enum B600 = 8; enum B1200 = 9; enum B1800 = 10; enum B2400 = 11; enum B4800 = 12; enum B9600 = 13; enum B19200 = 14; enum B38400 = 15; enum B57600 = 16; enum B76800 = 17; enum B115200 = 18; enum B153600 = 19; enum B230400 = 20; enum B307200 = 21; enum B460800 = 22; enum B921600 = 23; /* * POSIX termios functions * These functions get mapped into ioctls. */ speed_t cfgetospeed(in termios*); int cfsetospeed(termios*, speed_t); speed_t cfgetispeed(in termios*); int cfsetispeed(termios*, speed_t); int tcgetattr(int, termios*); int tcsetattr(int, int, in termios*); int tcsendbreak(int, int); int tcdrain(int); int tcflush(int, int); int tcflow(int, int); } // // XOpen (XSI) // /* IXANY ONLCR OCRNL ONOCR ONLRET OFILL NLDLY NL0 NL1 CRDLY CR0 CR1 CR2 CR3 TABDLY TAB0 TAB1 TAB2 TAB3 BSDLY BS0 BS1 VTDLY VT0 VT1 FFDLY FF0 FF1 pid_t tcgetsid(int); */ version( CRuntime_Glibc ) { enum IXANY = 0x0000800; // 0004000 enum ONLCR = 0x0000004; // 0000004 enum OCRNL = 0x0000008; // 0000010 enum ONOCR = 0x0000010; // 0000020 enum ONLRET = 0x0000020; // 0000040 enum OFILL = 0x0000040; // 0000100 enum NLDLY = 0x0000100; // 0000400 enum NL0 = 0x0000000; // 0000000 enum NL1 = 0x0000100; // 0000400 enum CRDLY = 0x0000600; // 0003000 enum CR0 = 0x0000000; // 0000000 enum CR1 = 0x0000200; // 0001000 enum CR2 = 0x0000400; // 0002000 enum CR3 = 0x0000600; // 0003000 enum TABDLY = 0x0001800; // 0014000 enum TAB0 = 0x0000000; // 0000000 enum TAB1 = 0x0000800; // 0004000 enum TAB2 = 0x0001000; // 0010000 enum TAB3 = 0x0001800; // 0014000 enum BSDLY = 0x0002000; // 0020000 enum BS0 = 0x0000000; // 0000000 enum BS1 = 0x0002000; // 0020000 enum VTDLY = 0x0004000; // 0040000 enum VT0 = 0x0000000; // 0000000 enum VT1 = 0x0004000; // 0040000 enum FFDLY = 0x0008000; // 0100000 enum FF0 = 0x0000000; // 0000000 enum FF1 = 0x0008000; // 0100000 pid_t tcgetsid(int); } else version (OSX) { enum IXANY = 0x00000800; enum ONLCR = 0x00000002; enum OCRNL = 0x00000010; enum ONOCR = 0x00000020; enum ONLRET = 0x00000040; enum OFILL = 0x00000080; enum NLDLY = 0x00000300; enum NL0 = 0x00000000; enum NL1 = 0x00000100; enum CRDLY = 0x00003000; enum CR0 = 0x00000000; enum CR1 = 0x00001000; enum CR2 = 0x00002000; enum CR3 = 0x00003000; enum TABDLY = 0x00000c04; enum TAB0 = 0x00000000; enum TAB1 = 0x00000400; enum TAB2 = 0x00000800; enum TAB3 = 0x00000004; enum BSDLY = 0x00008000; enum BS0 = 0x00000000; enum BS1 = 0x00008000; enum VTDLY = 0x00010000; enum VT0 = 0x00000000; enum VT1 = 0x00010000; enum FFDLY = 0x00004000; enum FF0 = 0x00000000; enum FF1 = 0x00004000; pid_t tcgetsid (int); } else version( FreeBSD ) { enum IXANY = 0x00000800; enum ONLCR = 0x00000002; enum OCRNL = 0x00000010; enum ONOCR = 0x00000020; enum ONLRET = 0x00000040; //enum OFILL //enum NLDLY //enum NL0 //enum NL1 //enum CRDLY //enum CR0 //enum CR1 //enum CR2 //enum CR3 enum TABDLY = 0x00000004; enum TAB0 = 0x00000000; //enum TAB1 //enum TAB2 enum TAB3 = 0x00000004; //enum BSDLY //enum BS0 //enum BS1 //enum VTDLY //enum VT0 //enum VT1 //enum FFDLY //enum FF0 //enum FF1 pid_t tcgetsid(int); } else version (Solaris) { enum IXANY = 0x0000800; enum ONLCR = 0x0000004; enum OCRNL = 0x0000008; enum ONOCR = 0x0000010; enum ONLRET = 0x0000020; enum OFILL = 0x0000040; enum OFDEL = 0x0000080; enum NLDLY = 0x0000100; enum NL0 = 0x0000000; enum NL1 = 0x0000100; enum CRDLY = 0x0000600; enum CR0 = 0x0000000; enum CR1 = 0x0000200; enum CR2 = 0x0000400; enum CR3 = 0x0000600; enum TABDLY = 0x0001800; enum TAB0 = 0x0000000; enum TAB1 = 0x0000800; enum TAB2 = 0x0001000; enum TAB3 = 0x0001800; enum BSDLY = 0x0002000; enum BS0 = 0x0000000; enum BS1 = 0x0002000; enum VTDLY = 0x0004000; enum VT0 = 0x0000000; enum VT1 = 0x0004000; enum FFDLY = 0x0008000; enum FF0 = 0x0000000; enum FF1 = 0x0008000; enum XCASE = 0x0000004; pid_t tcgetsid(int); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/signal.d0000664000175000017500000014651512776214756022620 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition * Source: $(DRUNTIMESRC core/sys/posix/_signal.d) */ module core.sys.posix.signal; private import core.sys.posix.config; public import core.stdc.signal; public import core.sys.posix.sys.types; // for pid_t //public import core.sys.posix.time; // for timespec, now defined here version (OSX) version = Darwin; else version (iOS) version = Darwin; else version (TVOS) version = Darwin; else version (WatchOS) version = Darwin; version (Posix): extern (C): //nothrow: // this causes Issue 12738 // // Required // /* SIG_DFL (defined in core.stdc.signal) SIG_ERR (defined in core.stdc.signal) SIG_IGN (defined in core.stdc.signal) sig_atomic_t (defined in core.stdc.signal) SIGEV_NONE SIGEV_SIGNAL SIGEV_THREAD union sigval { int sival_int; void* sival_ptr; } SIGRTMIN SIGRTMAX SIGABRT (defined in core.stdc.signal) SIGALRM SIGBUS SIGCHLD SIGCONT SIGFPE (defined in core.stdc.signal) SIGHUP SIGILL (defined in core.stdc.signal) SIGINT (defined in core.stdc.signal) SIGKILL SIGPIPE SIGQUIT SIGSEGV (defined in core.stdc.signal) SIGSTOP SIGTERM (defined in core.stdc.signal) SIGTSTP SIGTTIN SIGTTOU SIGUSR1 SIGUSR2 SIGURG struct sigaction_t { sigfn_t sa_handler; sigset_t sa_mask; sigactfn_t sa_sigaction; } sigfn_t signal(int sig, sigfn_t func); (defined in core.stdc.signal) int raise(int sig); (defined in core.stdc.signal) */ //SIG_DFL (defined in core.stdc.signal) //SIG_ERR (defined in core.stdc.signal) //SIG_IGN (defined in core.stdc.signal) //sig_atomic_t (defined in core.stdc.signal) private alias void function(int) sigfn_t; private alias void function(int, siginfo_t*, void*) sigactfn_t; // nothrow versions nothrow @nogc { private alias void function(int) sigfn_t2; private alias void function(int, siginfo_t*, void*) sigactfn_t2; } enum { SIGEV_SIGNAL, SIGEV_NONE, SIGEV_THREAD } union sigval { int sival_int; void* sival_ptr; } version( Solaris ) { import core.sys.posix.unistd; @property int SIGRTMIN() nothrow @nogc { __gshared static int sig = -1; if (sig == -1) { sig = cast(int)sysconf(_SC_SIGRT_MIN); } return sig; } @property int SIGRTMAX() nothrow @nogc { __gshared static int sig = -1; if (sig == -1) { sig = cast(int)sysconf(_SC_SIGRT_MAX); } return sig; } } else version( CRuntime_Glibc ) { private extern (C) nothrow @nogc { int __libc_current_sigrtmin(); int __libc_current_sigrtmax(); } @property int SIGRTMIN() nothrow @nogc { __gshared static int sig = -1; if (sig == -1) { sig = __libc_current_sigrtmin(); } return sig; } @property int SIGRTMAX() nothrow @nogc { __gshared static int sig = -1; if (sig == -1) { sig = __libc_current_sigrtmax(); } return sig; } } else version (FreeBSD) { // https://github.com/freebsd/freebsd/blob/e79c62ff68fc74d88cb6f479859f6fae9baa5101/sys/sys/signal.h#L117 enum SIGRTMIN = 65; enum SIGRTMAX = 126; } // Note: it appears that FreeBSD (prior to 7) and OSX do not support realtime signals version( linux ) { version (X86) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 7; enum SIGCHLD = 17; enum SIGCONT = 18; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 19; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 20; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 10; enum SIGUSR2 = 12; enum SIGURG = 23; } else version (X86_64) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 7; enum SIGCHLD = 17; enum SIGCONT = 18; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 19; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 20; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 10; enum SIGUSR2 = 12; enum SIGURG = 23; } else version (MIPS32) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 10; enum SIGCHLD = 18; enum SIGCONT = 25; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 23; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 24; enum SIGTTIN = 26; enum SIGTTOU = 27; enum SIGUSR1 = 16; enum SIGUSR2 = 17; enum SIGURG = 21; } else version (MIPS64) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 10; enum SIGCHLD = 18; enum SIGCONT = 25; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 23; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 24; enum SIGTTIN = 26; enum SIGTTOU = 27; enum SIGUSR1 = 16; enum SIGUSR2 = 17; enum SIGURG = 21; } else version (PPC) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 7; enum SIGCHLD = 17; enum SIGCONT = 18; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 19; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 20; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 10; enum SIGUSR2 = 12; enum SIGURG = 23; } else version (PPC64) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 7; enum SIGCHLD = 17; enum SIGCONT = 18; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 19; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 20; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 10; enum SIGUSR2 = 12; enum SIGURG = 23; } else version (ARM) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 7; enum SIGCHLD = 17; enum SIGCONT = 18; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 19; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 20; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 10; enum SIGUSR2 = 12; enum SIGURG = 23; } else version (AArch64) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 7; enum SIGCHLD = 17; enum SIGCONT = 18; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 19; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 20; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 10; enum SIGUSR2 = 12; enum SIGURG = 23; } else version (SystemZ) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 7; enum SIGCHLD = 17; enum SIGCONT = 18; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 19; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 20; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 10; enum SIGUSR2 = 12; enum SIGURG = 23; } else static assert(0, "unimplemented"); } else version( Darwin ) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 10; enum SIGCHLD = 20; enum SIGCONT = 19; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 17; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 18; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 30; enum SIGUSR2 = 31; enum SIGURG = 16; } else version( FreeBSD ) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 10; enum SIGCHLD = 20; enum SIGCONT = 19; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 17; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 18; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 30; enum SIGUSR2 = 31; enum SIGURG = 16; } else version( OpenBSD ) { //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 10; enum SIGCHLD = 20; enum SIGCONT = 19; //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 17; //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 18; enum SIGTTIN = 21; enum SIGTTOU = 22; enum SIGUSR1 = 30; enum SIGUSR2 = 31; enum SIGURG = 16; } else version (Solaris) { enum SIGALRM = 14; enum SIGBUS = 10; enum SIGCHLD = 18; enum SIGCONT = 25; enum SIGHUP = 1; enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; enum SIGSTOP = 23; enum SIGTSTP = 24; enum SIGTTIN = 26; enum SIGTTOU = 27; enum SIGUSR1 = 16; enum SIGUSR2 = 17; enum SIGURG = 21; } else { static assert(false, "Unsupported platform"); } version( CRuntime_Glibc ) { struct sigaction_t { static if( true /* __USE_POSIX199309 */ ) { union { sigfn_t sa_handler; sigactfn_t sa_sigaction; } } else { sigfn_t sa_handler; } sigset_t sa_mask; int sa_flags; void function() sa_restorer; } } else version( FreeBSD ) { struct sigaction_t { union { sigfn_t sa_handler; sigactfn_t sa_sigaction; } int sa_flags; sigset_t sa_mask; } } else version( OpenBSD ) { struct sigaction_t { union { sigfn_t __sa_handler; alias sa_handler = __sa_handler; sigactfn_t __sa_sigaction; alias sa_sigaction = __sa_sigaction; } sigset_t sa_mask; int sa_flags; } } else version (Solaris) { struct sigaction_t { int sa_flags; union { sigfn_t sa_handler; sigactfn_t sa_sigaction; } sigset_t sa_mask; version (D_LP64) {} else int[2] sa_resv; } } else version (linux) { version (X86) { struct sigaction_t { union { sigfn_t sa_handler; sigactfn_t sa_sigaction; } sigset_t sa_mask; c_ulong sa_flags; void function() sa_restorer; } } else version (ARM) { struct sigaction_t { union { sigfn_t sa_handler; sigactfn_t sa_sigaction; } sigset_t sa_mask; c_ulong sa_flags; void function() sa_restorer; } } else { static assert(false, "Architecture not supported."); } } else version( Darwin ) { struct sigaction_t { static if( true /* __USE_POSIX199309 */ ) { union { sigfn_t sa_handler; sigactfn_t sa_sigaction; } } else { sigfn_t sa_handler; } sigset_t sa_mask; int sa_flags; } } else { static assert(false, "Unsupported platform"); } // // C Extension (CX) // /* SIG_HOLD sigset_t pid_t (defined in core.sys.types) SIGABRT (defined in core.stdc.signal) SIGFPE (defined in core.stdc.signal) SIGILL (defined in core.stdc.signal) SIGINT (defined in core.stdc.signal) SIGSEGV (defined in core.stdc.signal) SIGTERM (defined in core.stdc.signal) SA_NOCLDSTOP (CX|XSI) SIG_BLOCK SIG_UNBLOCK SIG_SETMASK struct siginfo_t { int si_signo; int si_code; version( XSI ) { int si_errno; pid_t si_pid; uid_t si_uid; void* si_addr; int si_status; c_long si_band; } version( RTS ) { sigval si_value; } } SI_USER SI_QUEUE SI_TIMER SI_ASYNCIO SI_MESGQ int kill(pid_t, int); int sigaction(int, in sigaction_t*, sigaction_t*); int sigaddset(sigset_t*, int); int sigdelset(sigset_t*, int); int sigemptyset(sigset_t*); int sigfillset(sigset_t*); int sigismember(in sigset_t*, int); int sigpending(sigset_t*); int sigprocmask(int, in sigset_t*, sigset_t*); int sigsuspend(in sigset_t*); int sigwait(in sigset_t*, int*); */ nothrow @nogc { version( CRuntime_Glibc ) { enum SIG_HOLD = cast(sigfn_t2) 1; private enum _SIGSET_NWORDS = 1024 / (8 * c_ulong.sizeof); struct sigset_t { c_ulong[_SIGSET_NWORDS] __val; } // pid_t (defined in core.sys.types) //SIGABRT (defined in core.stdc.signal) //SIGFPE (defined in core.stdc.signal) //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) //SIGSEGV (defined in core.stdc.signal) //SIGTERM (defined in core.stdc.signal) enum SA_NOCLDSTOP = 1; // (CX|XSI) enum SIG_BLOCK = 0; enum SIG_UNBLOCK = 1; enum SIG_SETMASK = 2; private enum __SI_MAX_SIZE = 128; static if( false /* __WORDSIZE == 64 */ ) { private enum __SI_PAD_SIZE = ((__SI_MAX_SIZE / int.sizeof) - 4); } else { private enum __SI_PAD_SIZE = ((__SI_MAX_SIZE / int.sizeof) - 3); } struct siginfo_t { int si_signo; // Signal number int si_errno; // If non-zero, an errno value associated with // this signal, as defined in int si_code; // Signal code union _sifields_t { int[__SI_PAD_SIZE] _pad; // kill() struct _kill_t { pid_t si_pid; // Sending process ID uid_t si_uid; // Real user ID of sending process } _kill_t _kill; // POSIX.1b timers. struct _timer_t { int si_tid; // Timer ID int si_overrun; // Overrun count sigval si_sigval; // Signal value } _timer_t _timer; // POSIX.1b signals struct _rt_t { pid_t si_pid; // Sending process ID uid_t si_uid; // Real user ID of sending process sigval si_sigval; // Signal value } _rt_t _rt; // SIGCHLD struct _sigchild_t { pid_t si_pid; // Which child uid_t si_uid; // Real user ID of sending process int si_status; // Exit value or signal clock_t si_utime; clock_t si_stime; } _sigchild_t _sigchld; // SIGILL, SIGFPE, SIGSEGV, SIGBUS struct _sigfault_t { void* si_addr; // Faulting insn/memory ref } _sigfault_t _sigfault; // SIGPOLL struct _sigpoll_t { c_long si_band; // Band event for SIGPOLL int si_fd; } _sigpoll_t _sigpoll; } _sifields_t _sifields; nothrow @nogc: @property ref pid_t si_pid() return { return _sifields._kill.si_pid; } @property ref uid_t si_uid() return { return _sifields._kill.si_uid; } @property ref void* si_addr() return { return _sifields._sigfault.si_addr; } @property ref int si_status() return { return _sifields._sigchld.si_status; } @property ref c_long si_band() return { return _sifields._sigpoll.si_band; } @property ref sigval si_value() return { return _sifields._rt.si_sigval; } } enum { SI_ASYNCNL = -60, SI_TKILL = -6, SI_SIGIO, SI_ASYNCIO, SI_MESGQ, SI_TIMER, SI_QUEUE, SI_USER, SI_KERNEL = 0x80 } int kill(pid_t, int); int sigaction(int, in sigaction_t*, sigaction_t*); int sigaddset(sigset_t*, int); int sigdelset(sigset_t*, int); int sigemptyset(sigset_t*); int sigfillset(sigset_t*); int sigismember(in sigset_t*, int); int sigpending(sigset_t*); int sigprocmask(int, in sigset_t*, sigset_t*); int sigsuspend(in sigset_t*); int sigwait(in sigset_t*, int*); } else version( Darwin ) { enum SIG_HOLD = cast(sigfn_t2) 5; alias uint sigset_t; // pid_t (defined in core.sys.types) //SIGABRT (defined in core.stdc.signal) //SIGFPE (defined in core.stdc.signal) //SIGILL (defined in core.stdc.signal) //SIGINT (defined in core.stdc.signal) //SIGSEGV (defined in core.stdc.signal) //SIGTERM (defined in core.stdc.signal) enum SA_NOCLDSTOP = 8; // (CX|XSI) enum SIG_BLOCK = 1; enum SIG_UNBLOCK = 2; enum SIG_SETMASK = 3; struct siginfo_t { int si_signo; int si_errno; int si_code; pid_t si_pid; uid_t si_uid; int si_status; void* si_addr; sigval si_value; int si_band; uint[7] pad; } enum SI_USER = 0x10001; enum SI_QUEUE = 0x10002; enum SI_TIMER = 0x10003; enum SI_ASYNCIO = 0x10004; enum SI_MESGQ = 0x10005; int kill(pid_t, int); int sigaction(int, in sigaction_t*, sigaction_t*); int sigaddset(sigset_t*, int); int sigdelset(sigset_t*, int); int sigemptyset(sigset_t*); int sigfillset(sigset_t*); int sigismember(in sigset_t*, int); int sigpending(sigset_t*); int sigprocmask(int, in sigset_t*, sigset_t*); int sigsuspend(in sigset_t*); int sigwait(in sigset_t*, int*); } else version( FreeBSD ) { enum SIG_HOLD = cast(sigfn_t2) 3; struct sigset_t { uint[4] __bits; } enum SA_NOCLDSTOP = 8; enum SIG_BLOCK = 1; enum SIG_UNBLOCK = 2; enum SIG_SETMASK = 3; struct siginfo_t { int si_signo; int si_errno; int si_code; pid_t si_pid; uid_t si_uid; int si_status; void* si_addr; sigval si_value; union __reason { struct __fault { int _trapno; } __fault _fault; struct __timer { int _timerid; int _overrun; } __timer _timer; struct __mesgq { int _mqd; } __mesgq _mesgq; struct __poll { c_long _band; } __poll _poll; struct ___spare___ { c_long __spare1__; int[7] __spare2__; } ___spare___ __spare__; } __reason _reason; @property ref c_long si_band() return { return _reason._poll._band; } } enum SI_USER = 0x10001; enum SI_QUEUE = 0x10002; enum SI_TIMER = 0x10003; enum SI_ASYNCIO = 0x10004; enum SI_MESGQ = 0x10005; int kill(pid_t, int); int sigaction(int, in sigaction_t*, sigaction_t*); int sigaddset(sigset_t*, int); int sigdelset(sigset_t*, int); int sigemptyset(sigset_t *); int sigfillset(sigset_t *); int sigismember(in sigset_t *, int); int sigpending(sigset_t *); int sigprocmask(int, in sigset_t*, sigset_t*); int sigsuspend(in sigset_t *); int sigwait(in sigset_t*, int*); } else version( OpenBSD ) { enum SIG_CATCH = cast(sigfn_t2) 2; enum SIG_HOLD = cast(sigfn_t2) 3; alias sigset_t = uint; enum SA_NOCLDSTOP = 0x0008; enum SIG_BLOCK = 1; enum SIG_UNBLOCK = 2; enum SIG_SETMASK = 3; private enum SI_MAXSZ = 128; private enum SI_PAD = (SI_MAXSZ / int.sizeof) - 3; struct siginfo_t { int si_signo; int si_errno; int si_code; union _data { int[SI_PAD] _pad; struct _proc { pid_t _pid; union _pdata { struct _kill { uid_t _uid; sigval _value; } struct _cld { clock_t _utime; clock_t _stime; int _status; } } } struct _fault { caddr_t _addr; int _trapno; } } alias si_pid = _data._proc._pid; alias si_status = _data._proc._pdata._cld._status; alias si_stime = _data._proc._pdata._cld._stime; alias si_utime = _data._proc._pdata._cld._utime; alias si_uid = _data._proc._pdata._kill._uid; alias si_value = _data._proc._pdata._kill._value; alias si_addr = _data._fault._addr; alias si_trapno = _data._fault._trapno; } enum SI_NOINFO = 32767; enum SI_USER = 0; enum SI_LWP = -1; enum SI_QUEUE = -2; enum SI_TIMER = -3; int kill(pid_t, int); int sigaction(int, in sigaction_t*, sigaction_t*); int sigaddset(sigset_t*, int); int sigdelset(sigset_t*, int); int sigemptyset(sigset_t *); int sigfillset(sigset_t *); int sigismember(in sigset_t *, int); int sigpending(sigset_t *); int sigprocmask(int, in sigset_t*, sigset_t*); int sigsuspend(in sigset_t *); int sigwait(in sigset_t*, int*); } else version (Solaris) { enum SIG_HOLD = cast(sigfn_t2)2; struct sigset_t { uint[4] __bits; } struct siginfo_t { int si_signo; int si_code; int si_errno; version (D_LP64) int si_pad; union ___data { version (D_LP64) int[(256 / int.sizeof) - 4] si_pad; else int[(128 / int.sizeof) - 3] si_pad; struct ___proc { pid_t __pid; union ___pdata { struct ___kill { uid_t __uid; sigval __value; } ___kill __kill; struct ___cld { clock_t __utime; int __status; clock_t __stime; } ___cld __cld; } ___pdata __pdata; ctid_t __ctid; zoneid_t __zoneid; } ___proc __proc; struct ___fault { void* __addr; int __trapno; caddr_t __pc; } ___fault __fault; struct ___file { int __fd; c_long __band; } ___file __file; struct ___prof { caddr_t __faddr; timestruc_t __tstamp; short __syscall; char __nsysarg; char __fault; c_long[8] __sysarg; int[10] __mstate; } ___prof __prof; struct ___rctl { int __entity; } ___rctl __rctl; } ___data __data; } int kill(pid_t, int); int sigaction(int, in sigaction_t*, sigaction_t*); int sigaddset(sigset_t*, int); int sigdelset(sigset_t*, int); int sigemptyset(sigset_t*); int sigfillset(sigset_t*); int sigismember(in sigset_t*, int); int sigpending(sigset_t*); int sigprocmask(int, in sigset_t*, sigset_t*); int sigsuspend(in sigset_t*); int sigwait(in sigset_t*, int*); } else version( CRuntime_Bionic ) { public import core.sys.posix.time: timer_t; private import core.stdc.string : memset; version (X86) { alias c_ulong sigset_t; enum int LONG_BIT = 32; } else version (ARM) { alias c_ulong sigset_t; enum int LONG_BIT = 32; } else { static assert(false, "Architecture not supported."); } enum SIG_BLOCK = 0; enum SIG_UNBLOCK = 1; enum SIG_SETMASK = 2; private enum SI_MAX_SIZE = 128; private enum SI_PAD_SIZE = ((SI_MAX_SIZE / int.sizeof) - 3); struct siginfo_t { int si_signo; int si_errno; int si_code; union _sifields_t { int[SI_PAD_SIZE] _pad; struct _kill_t { pid_t _pid; uid_t _uid; } _kill_t _kill; struct _timer_t { timer_t _tid; int _overrun; sigval _sigval; int _sys_private; } _timer_t _timer; struct _rt_t { pid_t _pid; uid_t _uid; sigval _sigval; } _rt_t _rt; struct _sigchild_t { pid_t _pid; uid_t _uid; int _status; clock_t _utime; clock_t _stime; } _sigchild_t _sigchld; struct _sigfault_t { void* _addr; } _sigfault_t _sigfault; struct _sigpoll_t { c_long _band; int _fd; } _sigpoll_t _sigpoll; } _sifields_t _sifields; } enum { SI_TKILL = -6, SI_SIGIO, SI_ASYNCIO, SI_MESGQ, SI_TIMER, SI_QUEUE, SI_USER, SI_KERNEL = 0x80 } int kill(pid_t, int); int sigaction(int, in sigaction_t*, sigaction_t*); // These functions are defined inline in bionic. int sigaddset(sigset_t* set, int signum) { c_ulong* local_set = cast(c_ulong*) set; signum--; local_set[signum/LONG_BIT] |= 1UL << (signum%LONG_BIT); return 0; } int sigdelset(sigset_t* set, int signum) { c_ulong* local_set = cast(c_ulong*) set; signum--; local_set[signum/LONG_BIT] &= ~(1UL << (signum%LONG_BIT)); return 0; } int sigemptyset(sigset_t* set) { memset(set, 0, (*set).sizeof); return 0; } int sigfillset(sigset_t* set) { memset(set, ~0, (*set).sizeof); return 0; } int sigismember(sigset_t* set, int signum) { c_ulong* local_set = cast(c_ulong*) set; signum--; return cast(int) ((local_set[signum/LONG_BIT] >> (signum%LONG_BIT)) & 1); } int sigpending(sigset_t*); int sigprocmask(int, in sigset_t*, sigset_t*); int sigsuspend(in sigset_t*); int sigwait(in sigset_t*, int*); } else { static assert(false, "Unsupported platform"); } } // // XOpen (XSI) // /* SIGPOLL SIGPROF SIGSYS SIGTRAP SIGVTALRM SIGXCPU SIGXFSZ SA_ONSTACK SA_RESETHAND SA_RESTART SA_SIGINFO SA_NOCLDWAIT SA_NODEFER SS_ONSTACK SS_DISABLE MINSIGSTKSZ SIGSTKSZ ucontext_t // from ucontext mcontext_t // from ucontext struct stack_t { void* ss_sp; size_t ss_size; int ss_flags; } struct sigstack { int ss_onstack; void* ss_sp; } ILL_ILLOPC ILL_ILLOPN ILL_ILLADR ILL_ILLTRP ILL_PRVOPC ILL_PRVREG ILL_COPROC ILL_BADSTK FPE_INTDIV FPE_INTOVF FPE_FLTDIV FPE_FLTOVF FPE_FLTUND FPE_FLTRES FPE_FLTINV FPE_FLTSUB SEGV_MAPERR SEGV_ACCERR BUS_ADRALN BUS_ADRERR BUS_OBJERR TRAP_BRKPT TRAP_TRACE CLD_EXITED CLD_KILLED CLD_DUMPED CLD_TRAPPED CLD_STOPPED CLD_CONTINUED POLL_IN POLL_OUT POLL_MSG POLL_ERR POLL_PRI POLL_HUP sigfn_t bsd_signal(int sig, sigfn_t func); sigfn_t sigset(int sig, sigfn_t func); int killpg(pid_t, int); int sigaltstack(in stack_t*, stack_t*); int sighold(int); int sigignore(int); int siginterrupt(int, int); int sigpause(int); int sigrelse(int); */ version( CRuntime_Glibc ) { version (X86) { enum SIGPOLL = 29; enum SIGPROF = 27; enum SIGSYS = 31; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; } else version (X86_64) { enum SIGPOLL = 29; enum SIGPROF = 27; enum SIGSYS = 31; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; } else version (MIPS32) { enum SIGPOLL = 22; enum SIGPROF = 29; enum SIGSYS = 12; enum SIGTRAP = 5; enum SIGVTALRM = 28; enum SIGXCPU = 30; enum SIGXFSZ = 31; } else version (MIPS64) { enum SIGPOLL = 22; enum SIGPROF = 29; enum SIGSYS = 12; enum SIGTRAP = 5; enum SIGVTALRM = 28; enum SIGXCPU = 30; enum SIGXFSZ = 31; } else version (PPC) { enum SIGPOLL = 29; enum SIGPROF = 27; enum SIGSYS = 31; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; } else version (PPC64) { enum SIGPOLL = 29; enum SIGPROF = 27; enum SIGSYS = 31; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; } else version (ARM) { enum SIGPOLL = 29; enum SIGPROF = 27; enum SIGSYS = 31; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; } else version (AArch64) { enum SIGPOLL = 29; enum SIGPROF = 27; enum SIGSYS = 31; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; } else version (SystemZ) { enum SIGPOLL = 29; enum SIGPROF = 27; enum SIGSYS = 31; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; } else static assert(0, "unimplemented"); enum SA_ONSTACK = 0x08000000; enum SA_RESETHAND = 0x80000000; enum SA_RESTART = 0x10000000; enum SA_SIGINFO = 4; enum SA_NOCLDWAIT = 2; enum SA_NODEFER = 0x40000000; enum SS_ONSTACK = 1; enum SS_DISABLE = 2; enum MINSIGSTKSZ = 2048; enum SIGSTKSZ = 8192; //ucontext_t (defined in core.sys.posix.ucontext) //mcontext_t (defined in core.sys.posix.ucontext) struct stack_t { void* ss_sp; int ss_flags; size_t ss_size; } struct sigstack { void* ss_sp; int ss_onstack; } enum { ILL_ILLOPC = 1, ILL_ILLOPN, ILL_ILLADR, ILL_ILLTRP, ILL_PRVOPC, ILL_PRVREG, ILL_COPROC, ILL_BADSTK } enum { FPE_INTDIV = 1, FPE_INTOVF, FPE_FLTDIV, FPE_FLTOVF, FPE_FLTUND, FPE_FLTRES, FPE_FLTINV, FPE_FLTSUB } enum { SEGV_MAPERR = 1, SEGV_ACCERR } enum { BUS_ADRALN = 1, BUS_ADRERR, BUS_OBJERR } enum { TRAP_BRKPT = 1, TRAP_TRACE } enum { CLD_EXITED = 1, CLD_KILLED, CLD_DUMPED, CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED } enum { POLL_IN = 1, POLL_OUT, POLL_MSG, POLL_ERR, POLL_PRI, POLL_HUP } sigfn_t bsd_signal(int sig, sigfn_t func); sigfn_t sigset(int sig, sigfn_t func); nothrow: @nogc: sigfn_t2 bsd_signal(int sig, sigfn_t2 func); sigfn_t2 sigset(int sig, sigfn_t2 func); int killpg(pid_t, int); int sigaltstack(in stack_t*, stack_t*); int sighold(int); int sigignore(int); int siginterrupt(int, int); int sigpause(int); int sigrelse(int); } else version( Darwin ) { enum SIGPOLL = 7; enum SIGPROF = 27; enum SIGSYS = 12; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; enum SA_ONSTACK = 0x0001; enum SA_RESETHAND = 0x0004; enum SA_RESTART = 0x0002; enum SA_SIGINFO = 0x0040; enum SA_NOCLDWAIT = 0x0020; enum SA_NODEFER = 0x0010; enum SS_ONSTACK = 0x0001; enum SS_DISABLE = 0x0004; enum MINSIGSTKSZ = 32768; enum SIGSTKSZ = 131072; //ucontext_t (defined in core.sys.posix.ucontext) //mcontext_t (defined in core.sys.posix.ucontext) struct stack_t { void* ss_sp; size_t ss_size; int ss_flags; } struct sigstack { void* ss_sp; int ss_onstack; } enum ILL_ILLOPC = 1; enum ILL_ILLOPN = 4; enum ILL_ILLADR = 5; enum ILL_ILLTRP = 2; enum ILL_PRVOPC = 3; enum ILL_PRVREG = 6; enum ILL_COPROC = 7; enum ILL_BADSTK = 8; enum FPE_INTDIV = 7; enum FPE_INTOVF = 8; enum FPE_FLTDIV = 1; enum FPE_FLTOVF = 2; enum FPE_FLTUND = 3; enum FPE_FLTRES = 4; enum FPE_FLTINV = 5; enum FPE_FLTSUB = 6; enum { SEGV_MAPERR = 1, SEGV_ACCERR } enum { BUS_ADRALN = 1, BUS_ADRERR, BUS_OBJERR } enum { TRAP_BRKPT = 1, TRAP_TRACE } enum { CLD_EXITED = 1, CLD_KILLED, CLD_DUMPED, CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED } enum { POLL_IN = 1, POLL_OUT, POLL_MSG, POLL_ERR, POLL_PRI, POLL_HUP } sigfn_t bsd_signal(int sig, sigfn_t func); sigfn_t sigset(int sig, sigfn_t func); nothrow: @nogc: sigfn_t2 bsd_signal(int sig, sigfn_t2 func); sigfn_t2 sigset(int sig, sigfn_t2 func); int killpg(pid_t, int); int sigaltstack(in stack_t*, stack_t*); int sighold(int); int sigignore(int); int siginterrupt(int, int); int sigpause(int); int sigrelse(int); } else version( FreeBSD ) { // No SIGPOLL on *BSD enum SIGPROF = 27; enum SIGSYS = 12; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; enum { SA_ONSTACK = 0x0001, SA_RESTART = 0x0002, SA_RESETHAND = 0x0004, SA_NODEFER = 0x0010, SA_NOCLDWAIT = 0x0020, SA_SIGINFO = 0x0040, } enum { SS_ONSTACK = 0x0001, SS_DISABLE = 0x0004, } enum MINSIGSTKSZ = 512 * 4; enum SIGSTKSZ = (MINSIGSTKSZ + 32768); ; //ucontext_t (defined in core.sys.posix.ucontext) //mcontext_t (defined in core.sys.posix.ucontext) struct stack_t { void* ss_sp; size_t ss_size; int ss_flags; } struct sigstack { void* ss_sp; int ss_onstack; } enum { ILL_ILLOPC = 1, ILL_ILLOPN, ILL_ILLADR, ILL_ILLTRP, ILL_PRVOPC, ILL_PRVREG, ILL_COPROC, ILL_BADSTK, } enum { BUS_ADRALN = 1, BUS_ADRERR, BUS_OBJERR, } enum { SEGV_MAPERR = 1, SEGV_ACCERR, } enum { FPE_INTOVF = 1, FPE_INTDIV, FPE_FLTDIV, FPE_FLTOVF, FPE_FLTUND, FPE_FLTRES, FPE_FLTINV, FPE_FLTSUB, } enum { TRAP_BRKPT = 1, TRAP_TRACE, } enum { CLD_EXITED = 1, CLD_KILLED, CLD_DUMPED, CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED, } enum { POLL_IN = 1, POLL_OUT, POLL_MSG, POLL_ERR, POLL_PRI, POLL_HUP, } //sigfn_t bsd_signal(int sig, sigfn_t func); sigfn_t sigset(int sig, sigfn_t func); nothrow: @nogc: //sigfn_t2 bsd_signal(int sig, sigfn_t2 func); sigfn_t2 sigset(int sig, sigfn_t2 func); int killpg(pid_t, int); int sigaltstack(in stack_t*, stack_t*); int sighold(int); int sigignore(int); int siginterrupt(int, int); int sigpause(int); int sigrelse(int); } else version (OpenBSD) { // No SIGPOLL on *BSD enum SIGPROF = 27; enum SIGSYS = 12; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; enum { SA_ONSTACK = 0x0001, SA_RESTART = 0x0002, SA_RESETHAND = 0x0004, SA_NODEFER = 0x0010, SA_NOCLDWAIT = 0x0020, SA_SIGINFO = 0x0040, } enum { SS_ONSTACK = 0x0001, SS_DISABLE = 0x0004, } enum MINSIGSTKSZ = 8192; enum SIGSTKSZ = (MINSIGSTKSZ + 32768); //ucontext_t (defined in core.sys.posix.ucontext) //mcontext_t (defined in core.sys.posix.ucontext) struct stack_t { void* ss_sp; size_t ss_size; int ss_flags; } enum { ILL_ILLOPC = 1, ILL_ILLOPN, ILL_ILLADR, ILL_ILLTRP, ILL_PRVOPC, ILL_PRVREG, ILL_COPROC, ILL_BADSTK, NSIGILL = ILL_BADSTK, } enum { BUS_ADRALN = 1, BUS_ADRERR, BUS_OBJERR, NSIGBUS = BUS_OBJERR, } enum { SEGV_MAPERR = 1, SEGV_ACCERR, NSIGSEGV = SEGV_ACCERR, } enum { FPE_INTDIV = 1, FPE_INTOVF, FPE_FLTDIV, FPE_FLTOVF, FPE_FLTUND, FPE_FLTRES, FPE_FLTINV, FPE_FLTSUB, NSIGFPE = FPE_FLTSUB, } enum { TRAP_BRKPT = 1, TRAP_TRACE, NSIGTRAP = TRAP_TRACE, } enum { CLD_EXITED = 1, CLD_KILLED, CLD_DUMPED, CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED, NSIGCLD = CLD_CONTINUED, } enum { POLL_IN = 1, POLL_OUT, POLL_MSG, POLL_ERR, POLL_PRI, POLL_HUP, NSIGPOLL = POLL_HUP, } nothrow: @nogc: int killpg(pid_t, int); int sigaltstack(in stack_t*, stack_t*); int siginterrupt(int, int); int sigpause(int); } else version (Solaris) { enum SIGPOLL = 22; enum SIGPROF = 29; enum SIGSYS = 12; enum SIGTRAP = 5; enum SIGVTALRM = 31; enum SIGXCPU = 30; enum SIGXFSZ = 25; enum { SA_ONSTACK = 0x00001, SA_RESTART = 0x00004, SA_RESETHAND = 0x00002, SA_NODEFER = 0x00010, SA_NOCLDWAIT = 0x10000, SA_SIGINFO = 0x00008, } enum { SS_ONSTACK = 0x0001, SS_DISABLE = 0x0002, } enum MINSIGSTKSZ = 2048; enum SIGSTKSZ = 8192; struct stack_t { void* ss_sp; size_t ss_size; int ss_flags; } struct sigstack { void* ss_sp; int ss_onstack; } enum { ILL_ILLOPC = 1, ILL_ILLOPN, ILL_ILLADR, ILL_ILLTRP, ILL_PRVOPC, ILL_PRVREG, ILL_COPROC, ILL_BADSTK, } enum { BUS_ADRALN = 1, BUS_ADRERR, BUS_OBJERR, } enum { SEGV_MAPERR = 1, SEGV_ACCERR, } enum { FPE_INTDIV = 1, FPE_INTOVF, FPE_FLTDIV, FPE_FLTOVF, FPE_FLTUND, FPE_FLTRES, FPE_FLTINV, FPE_FLTSUB, FPE_FLTDEN, } enum { TRAP_BRKPT = 1, TRAP_TRACE, TRAP_RWATCH, TRAP_WWATCH, TRAP_XWATCH, TRAP_DTRACE, } enum { CLD_EXITED = 1, CLD_KILLED, CLD_DUMPED, CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED, } enum { POLL_IN = 1, POLL_OUT, POLL_MSG, POLL_ERR, POLL_PRI, POLL_HUP, } sigfn_t sigset(int sig, sigfn_t func); nothrow: @nogc: sigfn_t2 sigset(int sig, sigfn_t2 func); int killpg(pid_t, int); int sigaltstack(in stack_t*, stack_t*); int sighold(int); int sigignore(int); int siginterrupt(int, int); int sigpause(int); int sigrelse(int); } else version (CRuntime_Bionic) { version (X86) { enum SIGPOLL = 29; enum SIGPROF = 27; enum SIGSYS = 31; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; enum SA_ONSTACK = 0x08000000; enum SA_RESETHAND = 0x80000000; enum SA_RESTART = 0x10000000; enum SA_SIGINFO = 4; enum SA_NOCLDWAIT = 2; enum SA_NODEFER = 0x40000000; enum SS_ONSTACK = 1; enum SS_DISABLE = 2; enum MINSIGSTKSZ = 2048; enum SIGSTKSZ = 8192; struct stack_t { void* ss_sp; int ss_flags; size_t ss_size; } } else version (ARM) { enum SIGPOLL = 29; enum SIGPROF = 27; enum SIGSYS = 31; enum SIGTRAP = 5; enum SIGVTALRM = 26; enum SIGXCPU = 24; enum SIGXFSZ = 25; enum SA_ONSTACK = 0x08000000; enum SA_RESETHAND = 0x80000000; enum SA_RESTART = 0x10000000; enum SA_SIGINFO = 4; enum SA_NOCLDWAIT = 2; enum SA_NODEFER = 0x40000000; enum SS_ONSTACK = 1; enum SS_DISABLE = 2; enum MINSIGSTKSZ = 2048; enum SIGSTKSZ = 8192; struct stack_t { void* ss_sp; int ss_flags; size_t ss_size; } } else { static assert(false, "Architecture not supported."); } enum { ILL_ILLOPC = 1, ILL_ILLOPN, ILL_ILLADR, ILL_ILLTRP, ILL_PRVOPC, ILL_PRVREG, ILL_COPROC, ILL_BADSTK } enum { FPE_INTDIV = 1, FPE_INTOVF, FPE_FLTDIV, FPE_FLTOVF, FPE_FLTUND, FPE_FLTRES, FPE_FLTINV, FPE_FLTSUB } enum { SEGV_MAPERR = 1, SEGV_ACCERR } enum { BUS_ADRALN = 1, BUS_ADRERR, BUS_OBJERR } enum { TRAP_BRKPT = 1, TRAP_TRACE } enum { CLD_EXITED = 1, CLD_KILLED, CLD_DUMPED, CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED } enum { POLL_IN = 1, POLL_OUT, POLL_MSG, POLL_ERR, POLL_PRI, POLL_HUP } sigfn_t bsd_signal(int, sigfn_t); nothrow: @nogc: sigfn_t2 bsd_signal(int, sigfn_t2); int killpg(int, int); int sigaltstack(in stack_t*, stack_t*); int siginterrupt(int, int); } else { static assert(false, "Unsupported platform"); } // // Timer (TMR) // /* NOTE: This should actually be defined in core.sys.posix.time. It is defined here instead to break a circular import. struct timespec { time_t tv_sec; int tv_nsec; } */ version( linux ) { struct timespec { time_t tv_sec; c_long tv_nsec; } } else version( Darwin ) { struct timespec { time_t tv_sec; c_long tv_nsec; } } else version( FreeBSD ) { struct timespec { time_t tv_sec; c_long tv_nsec; } } else version( OpenBSD ) { struct timespec { time_t tv_sec; c_long tv_nsec; } } else version (Solaris) { struct timespec { time_t tv_sec; c_long tv_nsec; } alias timespec timestruc_t; } else { static assert(false, "Unsupported platform"); } // // Realtime Signals (RTS) // /* struct sigevent { int sigev_notify; int sigev_signo; sigval sigev_value; void(*)(sigval) sigev_notify_function; pthread_attr_t* sigev_notify_attributes; } int sigqueue(pid_t, int, in sigval); int sigtimedwait(in sigset_t*, siginfo_t*, in timespec*); int sigwaitinfo(in sigset_t*, siginfo_t*); */ nothrow: @nogc: version( CRuntime_Glibc ) { private enum __SIGEV_MAX_SIZE = 64; static if( false /* __WORDSIZE == 64 */ ) { private enum __SIGEV_PAD_SIZE = ((__SIGEV_MAX_SIZE / int.sizeof) - 4); } else { private enum __SIGEV_PAD_SIZE = ((__SIGEV_MAX_SIZE / int.sizeof) - 3); } struct sigevent { sigval sigev_value; int sigev_signo; int sigev_notify; union _sigev_un_t { int[__SIGEV_PAD_SIZE] _pad; pid_t _tid; struct _sigev_thread_t { void function(sigval) _function; void* _attribute; } _sigev_thread_t _sigev_thread; } _sigev_un_t _sigev_un; } int sigqueue(pid_t, int, in sigval); int sigtimedwait(in sigset_t*, siginfo_t*, in timespec*); int sigwaitinfo(in sigset_t*, siginfo_t*); } else version( FreeBSD ) { struct sigevent { int sigev_notify; int sigev_signo; sigval sigev_value; union _sigev_un { lwpid_t _threadid; struct _sigev_thread { void function(sigval) _function; void* _attribute; } c_long[8] __spare__; } } int sigqueue(pid_t, int, in sigval); int sigtimedwait(in sigset_t*, siginfo_t*, in timespec*); int sigwaitinfo(in sigset_t*, siginfo_t*); } else version (OpenBSD) { } else version (Darwin) { } else version (Solaris) { struct sigevent { int sigev_notify; int sigev_signo; sigval sigev_value; void function(sigval) sigev_notify_function; pthread_attr_t* sigev_notify_attributes; int __sigev_pad2; } int sigqueue(pid_t, int, in sigval); int sigtimedwait(in sigset_t*, siginfo_t*, in timespec*); int sigwaitinfo(in sigset_t*, siginfo_t*); } else version( CRuntime_Bionic ) { private enum __ARCH_SIGEV_PREAMBLE_SIZE = (int.sizeof * 2) + sigval.sizeof; private enum SIGEV_MAX_SIZE = 64; private enum SIGEV_PAD_SIZE = (SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE) / int.sizeof; struct sigevent { sigval sigev_value; int sigev_signo; int sigev_notify; union _sigev_un_t { int[SIGEV_PAD_SIZE] _pad; int _tid; struct _sigev_thread_t { void function(sigval) _function; void* _attribute; } _sigev_thread_t _sigev_thread; } _sigev_un_t _sigev_un; } } else { static assert(false, "Unsupported platform"); } // // Threads (THR) // /* int pthread_kill(pthread_t, int); int pthread_sigmask(int, in sigset_t*, sigset_t*); */ version( CRuntime_Glibc ) { int pthread_kill(pthread_t, int); int pthread_sigmask(int, in sigset_t*, sigset_t*); } else version( Darwin ) { int pthread_kill(pthread_t, int); int pthread_sigmask(int, in sigset_t*, sigset_t*); } else version( FreeBSD ) { int pthread_kill(pthread_t, int); int pthread_sigmask(int, in sigset_t*, sigset_t*); } else version( OpenBSD ) { int pthread_kill(pthread_t, int); int pthread_sigmask(int, in sigset_t*, sigset_t*); } else version (Solaris) { int pthread_kill(pthread_t, int); int pthread_sigmask(int, in sigset_t*, sigset_t*); } else version( CRuntime_Bionic ) { int pthread_kill(pthread_t, int); int pthread_sigmask(int, in sigset_t*, sigset_t*); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/unistd.d0000664000175000017500000013027512776214756022645 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.unistd; private import core.sys.posix.config; private import core.stdc.stddef; public import core.sys.posix.inttypes; // for intptr_t public import core.sys.posix.sys.types; // for ssize_t, uid_t, gid_t, off_t, pid_t, useconds_t version (Posix): extern (C): nothrow: @nogc: enum STDIN_FILENO = 0; enum STDOUT_FILENO = 1; enum STDERR_FILENO = 2; extern __gshared char* optarg; extern __gshared int optind; extern __gshared int opterr; extern __gshared int optopt; int access(in char*, int); uint alarm(uint) @trusted; int chdir(in char*); int chown(in char*, uid_t, gid_t); int close(int) @trusted; size_t confstr(int, char*, size_t); int dup(int) @trusted; int dup2(int, int) @trusted; int execl(in char*, in char*, ...); int execle(in char*, in char*, ...); int execlp(in char*, in char*, ...); int execv(in char*, in char**); int execve(in char*, in char**, in char**); int execvp(in char*, in char**); void _exit(int) @trusted; int fchown(int, uid_t, gid_t) @trusted; pid_t fork() @trusted; c_long fpathconf(int, int) @trusted; //int ftruncate(int, off_t); char* getcwd(char*, size_t); gid_t getegid() @trusted; uid_t geteuid() @trusted; gid_t getgid() @trusted; int getgroups(int, gid_t *); int gethostname(char*, size_t); char* getlogin() @trusted; int getlogin_r(char*, size_t); int getopt(int, in char**, in char*); pid_t getpgrp() @trusted; pid_t getpid() @trusted; pid_t getppid() @trusted; uid_t getuid() @trusted; int isatty(int) @trusted; int link(in char*, in char*); //off_t lseek(int, off_t, int); c_long pathconf(in char*, int); int pause() @trusted; int pipe(ref int[2]) @trusted; ssize_t read(int, void*, size_t); ssize_t readlink(in char*, char*, size_t); int rmdir(in char*); int setegid(gid_t) @trusted; int seteuid(uid_t) @trusted; int setgid(gid_t) @trusted; int setpgid(pid_t, pid_t) @trusted; pid_t setsid() @trusted; int setuid(uid_t) @trusted; uint sleep(uint) @trusted; int symlink(in char*, in char*); c_long sysconf(int) @trusted; pid_t tcgetpgrp(int) @trusted; int tcsetpgrp(int, pid_t) @trusted; char* ttyname(int) @trusted; int ttyname_r(int, char*, size_t); int unlink(in char*); ssize_t write(int, in void*, size_t); version( CRuntime_Glibc ) { static if( __USE_FILE_OFFSET64 ) { off_t lseek64(int, off_t, int) @trusted; alias lseek64 lseek; } else { off_t lseek(int, off_t, int) @trusted; } static if( __USE_LARGEFILE64 ) { int ftruncate64(int, off_t) @trusted; alias ftruncate64 ftruncate; } else { int ftruncate(int, off_t) @trusted; } } else version( FreeBSD ) { off_t lseek(int, off_t, int) @trusted; int ftruncate(int, off_t) @trusted; } else version( Solaris ) { version ( D_LP64 ) { off_t lseek(int, off_t, int) @trusted; alias lseek lseek64; int ftruncate(int, off_t) @trusted; alias ftruncate ftruncate64; } else { static if( __USE_LARGEFILE64 ) { off64_t lseek64(int, off64_t, int) @trusted; alias lseek64 lseek; int ftruncate64(int, off64_t) @trusted; alias ftruncate64 ftruncate; } else { off_t lseek(int, off_t, int) @trusted; int ftruncate(int, off_t) @trusted; } } } else version( OSX ) { off_t lseek(int, off_t, int) @trusted; int ftruncate(int, off_t) @trusted; } else version( CRuntime_Bionic ) { off_t lseek(int, off_t, int) @trusted; int ftruncate(int, off_t) @trusted; } version( CRuntime_Glibc ) { enum F_OK = 0; enum R_OK = 4; enum W_OK = 2; enum X_OK = 1; enum F_ULOCK = 0; enum F_LOCK = 1; enum F_TLOCK = 2; enum F_TEST = 3; enum { _CS_PATH, _CS_V6_WIDTH_RESTRICTED_ENVS, _CS_GNU_LIBC_VERSION, _CS_GNU_LIBPTHREAD_VERSION, _CS_LFS_CFLAGS = 1000, _CS_LFS_LDFLAGS, _CS_LFS_LIBS, _CS_LFS_LINTFLAGS, _CS_LFS64_CFLAGS, _CS_LFS64_LDFLAGS, _CS_LFS64_LIBS, _CS_LFS64_LINTFLAGS, _CS_XBS5_ILP32_OFF32_CFLAGS = 1100, _CS_XBS5_ILP32_OFF32_LDFLAGS, _CS_XBS5_ILP32_OFF32_LIBS, _CS_XBS5_ILP32_OFF32_LINTFLAGS, _CS_XBS5_ILP32_OFFBIG_CFLAGS, _CS_XBS5_ILP32_OFFBIG_LDFLAGS, _CS_XBS5_ILP32_OFFBIG_LIBS, _CS_XBS5_ILP32_OFFBIG_LINTFLAGS, _CS_XBS5_LP64_OFF64_CFLAGS, _CS_XBS5_LP64_OFF64_LDFLAGS, _CS_XBS5_LP64_OFF64_LIBS, _CS_XBS5_LP64_OFF64_LINTFLAGS, _CS_XBS5_LPBIG_OFFBIG_CFLAGS, _CS_XBS5_LPBIG_OFFBIG_LDFLAGS, _CS_XBS5_LPBIG_OFFBIG_LIBS, _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS, _CS_POSIX_V6_ILP32_OFF32_CFLAGS, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS, _CS_POSIX_V6_ILP32_OFF32_LIBS, _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_LIBS, _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS, _CS_POSIX_V6_LP64_OFF64_CFLAGS, _CS_POSIX_V6_LP64_OFF64_LDFLAGS, _CS_POSIX_V6_LP64_OFF64_LIBS, _CS_POSIX_V6_LP64_OFF64_LINTFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS, _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS } enum { _PC_LINK_MAX, _PC_MAX_CANON, _PC_MAX_INPUT, _PC_NAME_MAX, _PC_PATH_MAX, _PC_PIPE_BUF, _PC_CHOWN_RESTRICTED, _PC_NO_TRUNC, _PC_VDISABLE, _PC_SYNC_IO, _PC_ASYNC_IO, _PC_PRIO_IO, _PC_SOCK_MAXBUF, _PC_FILESIZEBITS, _PC_REC_INCR_XFER_SIZE, _PC_REC_MAX_XFER_SIZE, _PC_REC_MIN_XFER_SIZE, _PC_REC_XFER_ALIGN, _PC_ALLOC_SIZE_MIN, _PC_SYMLINK_MAX, _PC_2_SYMLINKS } enum { _SC_ARG_MAX, _SC_CHILD_MAX, _SC_CLK_TCK, _SC_NGROUPS_MAX, _SC_OPEN_MAX, _SC_STREAM_MAX, _SC_TZNAME_MAX, _SC_JOB_CONTROL, _SC_SAVED_IDS, _SC_REALTIME_SIGNALS, _SC_PRIORITY_SCHEDULING, _SC_TIMERS, _SC_ASYNCHRONOUS_IO, _SC_PRIORITIZED_IO, _SC_SYNCHRONIZED_IO, _SC_FSYNC, _SC_MAPPED_FILES, _SC_MEMLOCK, _SC_MEMLOCK_RANGE, _SC_MEMORY_PROTECTION, _SC_MESSAGE_PASSING, _SC_SEMAPHORES, _SC_SHARED_MEMORY_OBJECTS, _SC_AIO_LISTIO_MAX, _SC_AIO_MAX, _SC_AIO_PRIO_DELTA_MAX, _SC_DELAYTIMER_MAX, _SC_MQ_OPEN_MAX, _SC_MQ_PRIO_MAX, _SC_VERSION, _SC_PAGESIZE, _SC_PAGE_SIZE = _SC_PAGESIZE, _SC_RTSIG_MAX, _SC_SEM_NSEMS_MAX, _SC_SEM_VALUE_MAX, _SC_SIGQUEUE_MAX, _SC_TIMER_MAX, _SC_BC_BASE_MAX, _SC_BC_DIM_MAX, _SC_BC_SCALE_MAX, _SC_BC_STRING_MAX, _SC_COLL_WEIGHTS_MAX, _SC_EQUIV_CLASS_MAX, _SC_EXPR_NEST_MAX, _SC_LINE_MAX, _SC_RE_DUP_MAX, _SC_CHARCLASS_NAME_MAX, _SC_2_VERSION, _SC_2_C_BIND, _SC_2_C_DEV, _SC_2_FORT_DEV, _SC_2_FORT_RUN, _SC_2_SW_DEV, _SC_2_LOCALEDEF, _SC_PII, _SC_PII_XTI, _SC_PII_SOCKET, _SC_PII_INTERNET, _SC_PII_OSI, _SC_POLL, _SC_SELECT, _SC_UIO_MAXIOV, _SC_IOV_MAX = _SC_UIO_MAXIOV, _SC_PII_INTERNET_STREAM, _SC_PII_INTERNET_DGRAM, _SC_PII_OSI_COTS, _SC_PII_OSI_CLTS, _SC_PII_OSI_M, _SC_T_IOV_MAX, _SC_THREADS, _SC_THREAD_SAFE_FUNCTIONS, _SC_GETGR_R_SIZE_MAX, _SC_GETPW_R_SIZE_MAX, _SC_LOGIN_NAME_MAX, _SC_TTY_NAME_MAX, _SC_THREAD_DESTRUCTOR_ITERATIONS, _SC_THREAD_KEYS_MAX, _SC_THREAD_STACK_MIN, _SC_THREAD_THREADS_MAX, _SC_THREAD_ATTR_STACKADDR, _SC_THREAD_ATTR_STACKSIZE, _SC_THREAD_PRIORITY_SCHEDULING, _SC_THREAD_PRIO_INHERIT, _SC_THREAD_PRIO_PROTECT, _SC_THREAD_PROCESS_SHARED, _SC_NPROCESSORS_CONF, _SC_NPROCESSORS_ONLN, _SC_PHYS_PAGES, _SC_AVPHYS_PAGES, _SC_ATEXIT_MAX, _SC_PASS_MAX, _SC_XOPEN_VERSION, _SC_XOPEN_XCU_VERSION, _SC_XOPEN_UNIX, _SC_XOPEN_CRYPT, _SC_XOPEN_ENH_I18N, _SC_XOPEN_SHM, _SC_2_CHAR_TERM, _SC_2_C_VERSION, _SC_2_UPE, _SC_XOPEN_XPG2, _SC_XOPEN_XPG3, _SC_XOPEN_XPG4, _SC_CHAR_BIT, _SC_CHAR_MAX, _SC_CHAR_MIN, _SC_INT_MAX, _SC_INT_MIN, _SC_LONG_BIT, _SC_WORD_BIT, _SC_MB_LEN_MAX, _SC_NZERO, _SC_SSIZE_MAX, _SC_SCHAR_MAX, _SC_SCHAR_MIN, _SC_SHRT_MAX, _SC_SHRT_MIN, _SC_UCHAR_MAX, _SC_UINT_MAX, _SC_ULONG_MAX, _SC_USHRT_MAX, _SC_NL_ARGMAX, _SC_NL_LANGMAX, _SC_NL_MSGMAX, _SC_NL_NMAX, _SC_NL_SETMAX, _SC_NL_TEXTMAX, _SC_XBS5_ILP32_OFF32, _SC_XBS5_ILP32_OFFBIG, _SC_XBS5_LP64_OFF64, _SC_XBS5_LPBIG_OFFBIG, _SC_XOPEN_LEGACY, _SC_XOPEN_REALTIME, _SC_XOPEN_REALTIME_THREADS, _SC_ADVISORY_INFO, _SC_BARRIERS, _SC_BASE, _SC_C_LANG_SUPPORT, _SC_C_LANG_SUPPORT_R, _SC_CLOCK_SELECTION, _SC_CPUTIME, _SC_THREAD_CPUTIME, _SC_DEVICE_IO, _SC_DEVICE_SPECIFIC, _SC_DEVICE_SPECIFIC_R, _SC_FD_MGMT, _SC_FIFO, _SC_PIPE, _SC_FILE_ATTRIBUTES, _SC_FILE_LOCKING, _SC_FILE_SYSTEM, _SC_MONOTONIC_CLOCK, _SC_MULTI_PROCESS, _SC_SINGLE_PROCESS, _SC_NETWORKING, _SC_READER_WRITER_LOCKS, _SC_SPIN_LOCKS, _SC_REGEXP, _SC_REGEX_VERSION, _SC_SHELL, _SC_SIGNALS, _SC_SPAWN, _SC_SPORADIC_SERVER, _SC_THREAD_SPORADIC_SERVER, _SC_SYSTEM_DATABASE, _SC_SYSTEM_DATABASE_R, _SC_TIMEOUTS, _SC_TYPED_MEMORY_OBJECTS, _SC_USER_GROUPS, _SC_USER_GROUPS_R, _SC_2_PBS, _SC_2_PBS_ACCOUNTING, _SC_2_PBS_LOCATE, _SC_2_PBS_MESSAGE, _SC_2_PBS_TRACK, _SC_SYMLOOP_MAX, _SC_STREAMS, _SC_2_PBS_CHECKPOINT, _SC_V6_ILP32_OFF32, _SC_V6_ILP32_OFFBIG, _SC_V6_LP64_OFF64, _SC_V6_LPBIG_OFFBIG, _SC_HOST_NAME_MAX, _SC_TRACE, _SC_TRACE_EVENT_FILTER, _SC_TRACE_INHERIT, _SC_TRACE_LOG, _SC_LEVEL1_ICACHE_SIZE, _SC_LEVEL1_ICACHE_ASSOC, _SC_LEVEL1_ICACHE_LINESIZE, _SC_LEVEL1_DCACHE_SIZE, _SC_LEVEL1_DCACHE_ASSOC, _SC_LEVEL1_DCACHE_LINESIZE, _SC_LEVEL2_CACHE_SIZE, _SC_LEVEL2_CACHE_ASSOC, _SC_LEVEL2_CACHE_LINESIZE, _SC_LEVEL3_CACHE_SIZE, _SC_LEVEL3_CACHE_ASSOC, _SC_LEVEL3_CACHE_LINESIZE, _SC_LEVEL4_CACHE_SIZE, _SC_LEVEL4_CACHE_ASSOC, _SC_LEVEL4_CACHE_LINESIZE, _SC_IPV6 = _SC_LEVEL1_ICACHE_SIZE + 50, _SC_RAW_SOCKETS } } else version( OSX ) { enum F_OK = 0; enum R_OK = 4; enum W_OK = 2; enum X_OK = 1; enum F_ULOCK = 0; enum F_LOCK = 1; enum F_TLOCK = 2; enum F_TEST = 3; enum { _SC_ARG_MAX = 1, _SC_CHILD_MAX = 2, _SC_CLK_TCK = 3, _SC_NGROUPS_MAX = 4, _SC_OPEN_MAX = 5, _SC_JOB_CONTROL = 6, _SC_SAVED_IDS = 7, _SC_VERSION = 8, _SC_BC_BASE_MAX = 9, _SC_BC_DIM_MAX = 10, _SC_BC_SCALE_MAX = 11, _SC_BC_STRING_MAX = 12, _SC_COLL_WEIGHTS_MAX = 13, _SC_EXPR_NEST_MAX = 14, _SC_LINE_MAX = 15, _SC_RE_DUP_MAX = 16, _SC_2_VERSION = 17, _SC_2_C_BIND = 18, _SC_2_C_DEV = 19, _SC_2_CHAR_TERM = 20, _SC_2_FORT_DEV = 21, _SC_2_FORT_RUN = 22, _SC_2_LOCALEDEF = 23, _SC_2_SW_DEV = 24, _SC_2_UPE = 25, _SC_STREAM_MAX = 26, _SC_TZNAME_MAX = 27, _SC_ASYNCHRONOUS_IO = 28, _SC_PAGESIZE = 29, _SC_MEMLOCK = 30, _SC_MEMLOCK_RANGE = 31, _SC_MEMORY_PROTECTION = 32, _SC_MESSAGE_PASSING = 33, _SC_PRIORITIZED_IO = 34, _SC_PRIORITY_SCHEDULING = 35, _SC_REALTIME_SIGNALS = 36, _SC_SEMAPHORES = 37, _SC_FSYNC = 38, _SC_SHARED_MEMORY_OBJECTS = 39, _SC_SYNCHRONIZED_IO = 40, _SC_TIMERS = 41, _SC_AIO_LISTIO_MAX = 42, _SC_AIO_MAX = 43, _SC_AIO_PRIO_DELTA_MAX = 44, _SC_DELAYTIMER_MAX = 45, _SC_MQ_OPEN_MAX = 46, _SC_MAPPED_FILES = 47, _SC_RTSIG_MAX = 48, _SC_SEM_NSEMS_MAX = 49, _SC_SEM_VALUE_MAX = 50, _SC_SIGQUEUE_MAX = 51, _SC_TIMER_MAX = 52, _SC_IOV_MAX = 56, _SC_NPROCESSORS_CONF = 57, _SC_NPROCESSORS_ONLN = 58, _SC_2_PBS = 59, _SC_2_PBS_ACCOUNTING = 60, _SC_2_PBS_CHECKPOINT = 61, _SC_2_PBS_LOCATE = 62, _SC_2_PBS_MESSAGE = 63, _SC_2_PBS_TRACK = 64, _SC_ADVISORY_INFO = 65, _SC_BARRIERS = 66, _SC_CLOCK_SELECTION = 67, _SC_CPUTIME = 68, _SC_FILE_LOCKING = 69, _SC_GETGR_R_SIZE_MAX = 70, _SC_GETPW_R_SIZE_MAX = 71, _SC_HOST_NAME_MAX = 72, _SC_LOGIN_NAME_MAX = 73, _SC_MONOTONIC_CLOCK = 74, _SC_MQ_PRIO_MAX = 75, _SC_READER_WRITER_LOCKS = 76, _SC_REGEXP = 77, _SC_SHELL = 78, _SC_SPAWN = 79, _SC_SPIN_LOCKS = 80, _SC_SPORADIC_SERVER = 81, _SC_THREAD_ATTR_STACKADDR = 82, _SC_THREAD_ATTR_STACKSIZE = 83, _SC_THREAD_CPUTIME = 84, _SC_THREAD_DESTRUCTOR_ITERATIONS = 85, _SC_THREAD_KEYS_MAX = 86, _SC_THREAD_PRIO_INHERIT = 87, _SC_THREAD_PRIO_PROTECT = 88, _SC_THREAD_PRIORITY_SCHEDULING = 89, _SC_THREAD_PROCESS_SHARED = 90, _SC_THREAD_SAFE_FUNCTIONS = 91, _SC_THREAD_SPORADIC_SERVER = 92, _SC_THREAD_STACK_MIN = 93, _SC_THREAD_THREADS_MAX = 94, _SC_TIMEOUTS = 95, _SC_THREADS = 96, _SC_TRACE = 97, _SC_TRACE_EVENT_FILTER = 98, _SC_TRACE_INHERIT = 99, _SC_TRACE_LOG = 100, _SC_TTY_NAME_MAX = 101, _SC_TYPED_MEMORY_OBJECTS = 102, _SC_V6_ILP32_OFF32 = 103, _SC_V6_ILP32_OFFBIG = 104, _SC_V6_LP64_OFF64 = 105, _SC_V6_LPBIG_OFFBIG = 106, _SC_ATEXIT_MAX = 107, _SC_XOPEN_CRYPT = 108, _SC_XOPEN_ENH_I18N = 109, _SC_XOPEN_LEGACY = 110, _SC_XOPEN_REALTIME = 111, _SC_XOPEN_REALTIME_THREADS = 112, _SC_XOPEN_SHM = 113, _SC_XOPEN_STREAMS = 114, _SC_XOPEN_UNIX = 115, _SC_XOPEN_VERSION = 116, _SC_IPV6 = 118, _SC_RAW_SOCKETS = 119, _SC_SYMLOOP_MAX = 120, _SC_XOPEN_XCU_VERSION = 121, _SC_XBS5_ILP32_OFF32 = 122, _SC_XBS5_ILP32_OFFBIG = 123, _SC_XBS5_LP64_OFF64 = 124, _SC_XBS5_LPBIG_OFFBIG = 125, _SC_SS_REPL_MAX = 126, _SC_TRACE_EVENT_NAME_MAX = 127, _SC_TRACE_NAME_MAX = 128, _SC_TRACE_SYS_MAX = 129, _SC_TRACE_USER_EVENT_MAX = 130, _SC_PASS_MAX = 131, } enum _SC_PAGE_SIZE = _SC_PAGESIZE; enum { _CS_PATH = 1, _CS_POSIX_V6_ILP32_OFF32_CFLAGS = 2, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS = 3, _CS_POSIX_V6_ILP32_OFF32_LIBS = 4, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS = 5, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS = 6, _CS_POSIX_V6_ILP32_OFFBIG_LIBS = 7, _CS_POSIX_V6_LP64_OFF64_CFLAGS = 8, _CS_POSIX_V6_LP64_OFF64_LDFLAGS = 9, _CS_POSIX_V6_LP64_OFF64_LIBS = 10, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS = 11, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS = 12, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS = 13, _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS = 14, _CS_XBS5_ILP32_OFF32_CFLAGS = 20, _CS_XBS5_ILP32_OFF32_LDFLAGS = 21, _CS_XBS5_ILP32_OFF32_LIBS = 22, _CS_XBS5_ILP32_OFF32_LINTFLAGS = 23, _CS_XBS5_ILP32_OFFBIG_CFLAGS = 24, _CS_XBS5_ILP32_OFFBIG_LDFLAGS = 25, _CS_XBS5_ILP32_OFFBIG_LIBS = 26, _CS_XBS5_ILP32_OFFBIG_LINTFLAGS = 27, _CS_XBS5_LP64_OFF64_CFLAGS = 28, _CS_XBS5_LP64_OFF64_LDFLAGS = 29, _CS_XBS5_LP64_OFF64_LIBS = 30, _CS_XBS5_LP64_OFF64_LINTFLAGS = 31, _CS_XBS5_LPBIG_OFFBIG_CFLAGS = 32, _CS_XBS5_LPBIG_OFFBIG_LDFLAGS = 33, _CS_XBS5_LPBIG_OFFBIG_LIBS = 34, _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS = 35, _CS_DARWIN_USER_DIR = 65536, _CS_DARWIN_USER_TEMP_DIR = 65537, _CS_DARWIN_USER_CACHE_DIR = 65538, } } else version( FreeBSD ) { enum F_OK = 0; enum R_OK = 0x04; enum W_OK = 0x02; enum X_OK = 0x01; enum F_ULOCK = 0; enum F_LOCK = 1; enum F_TLOCK = 2; enum F_TEST = 3; enum { _SC_ARG_MAX = 1, _SC_CHILD_MAX = 2, _SC_CLK_TCK = 3, _SC_NGROUPS_MAX = 4, _SC_OPEN_MAX = 5, _SC_JOB_CONTROL = 6, _SC_SAVED_IDS = 7, _SC_VERSION = 8, _SC_BC_BASE_MAX = 9, _SC_BC_DIM_MAX = 10, _SC_BC_SCALE_MAX = 11, _SC_BC_STRING_MAX = 12, _SC_COLL_WEIGHTS_MAX = 13, _SC_EXPR_NEST_MAX = 14, _SC_LINE_MAX = 15, _SC_RE_DUP_MAX = 16, _SC_2_VERSION = 17, _SC_2_C_BIND = 18, _SC_2_C_DEV = 19, _SC_2_CHAR_TERM = 20, _SC_2_FORT_DEV = 21, _SC_2_FORT_RUN = 22, _SC_2_LOCALEDEF = 23, _SC_2_SW_DEV = 24, _SC_2_UPE = 25, _SC_STREAM_MAX = 26, _SC_TZNAME_MAX = 27, _SC_ASYNCHRONOUS_IO = 28, _SC_MAPPED_FILES = 29, _SC_MEMLOCK = 30, _SC_MEMLOCK_RANGE = 31, _SC_MEMORY_PROTECTION = 32, _SC_MESSAGE_PASSING = 33, _SC_PRIORITIZED_IO = 34, _SC_PRIORITY_SCHEDULING = 35, _SC_REALTIME_SIGNALS = 36, _SC_SEMAPHORES = 37, _SC_FSYNC = 38, _SC_SHARED_MEMORY_OBJECTS = 39, _SC_SYNCHRONIZED_IO = 40, _SC_TIMERS = 41, _SC_AIO_LISTIO_MAX = 42, _SC_AIO_MAX = 43, _SC_AIO_PRIO_DELTA_MAX = 44, _SC_DELAYTIMER_MAX = 45, _SC_MQ_OPEN_MAX = 46, _SC_PAGESIZE = 47, _SC_RTSIG_MAX = 48, _SC_SEM_NSEMS_MAX = 49, _SC_SEM_VALUE_MAX = 50, _SC_SIGQUEUE_MAX = 51, _SC_TIMER_MAX = 52, _SC_IOV_MAX = 56, _SC_NPROCESSORS_CONF = 57, _SC_NPROCESSORS_ONLN = 58, _SC_2_PBS = 59, _SC_2_PBS_ACCOUNTING = 60, _SC_2_PBS_CHECKPOINT = 61, _SC_2_PBS_LOCATE = 62, _SC_2_PBS_MESSAGE = 63, _SC_2_PBS_TRACK = 64, _SC_ADVISORY_INFO = 65, _SC_BARRIERS = 66, _SC_CLOCK_SELECTION = 67, _SC_CPUTIME = 68, _SC_FILE_LOCKING = 69, _SC_GETGR_R_SIZE_MAX = 70, _SC_GETPW_R_SIZE_MAX = 71, _SC_HOST_NAME_MAX = 72, _SC_LOGIN_NAME_MAX = 73, _SC_MONOTONIC_CLOCK = 74, _SC_MQ_PRIO_MAX = 75, _SC_READER_WRITER_LOCKS = 76, _SC_REGEXP = 77, _SC_SHELL = 78, _SC_SPAWN = 79, _SC_SPIN_LOCKS = 80, _SC_SPORADIC_SERVER = 81, _SC_THREAD_ATTR_STACKADDR = 82, _SC_THREAD_ATTR_STACKSIZE = 83, _SC_THREAD_CPUTIME = 84, _SC_THREAD_DESTRUCTOR_ITERATIONS = 85, _SC_THREAD_KEYS_MAX = 86, _SC_THREAD_PRIO_INHERIT = 87, _SC_THREAD_PRIO_PROTECT = 88, _SC_THREAD_PRIORITY_SCHEDULING = 89, _SC_THREAD_PROCESS_SHARED = 90, _SC_THREAD_SAFE_FUNCTIONS = 91, _SC_THREAD_SPORADIC_SERVER = 92, _SC_THREAD_STACK_MIN = 93, _SC_THREAD_THREADS_MAX = 94, _SC_TIMEOUTS = 95, _SC_THREADS = 96, _SC_TRACE = 97, _SC_TRACE_EVENT_FILTER = 98, _SC_TRACE_INHERIT = 99, _SC_TRACE_LOG = 100, _SC_TTY_NAME_MAX = 101, _SC_TYPED_MEMORY_OBJECTS = 102, _SC_V6_ILP32_OFF32 = 103, _SC_V6_ILP32_OFFBIG = 104, _SC_V6_LP64_OFF64 = 105, _SC_V6_LPBIG_OFFBIG = 106, _SC_IPV6 = 118, _SC_RAW_SOCKETS = 119, _SC_SYMLOOP_MAX = 120, _SC_ATEXIT_MAX = 107, _SC_XOPEN_CRYPT = 108, _SC_XOPEN_ENH_I18N = 109, _SC_XOPEN_LEGACY = 110, _SC_XOPEN_REALTIME = 111, _SC_XOPEN_REALTIME_THREADS = 112, _SC_XOPEN_SHM = 113, _SC_XOPEN_STREAMS = 114, _SC_XOPEN_UNIX = 115, _SC_XOPEN_VERSION = 116, _SC_XOPEN_XCU_VERSION = 117, _SC_CPUSET_SIZE = 122, _SC_PHYS_PAGES = 121, } enum _SC_PAGE_SIZE = _SC_PAGESIZE; enum { _CS_PATH = 1, _CS_POSIX_V6_ILP32_OFF32_CFLAGS = 2, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS = 3, _CS_POSIX_V6_ILP32_OFF32_LIBS = 4, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS = 5, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS = 6, _CS_POSIX_V6_ILP32_OFFBIG_LIBS = 7, _CS_POSIX_V6_LP64_OFF64_CFLAGS = 8, _CS_POSIX_V6_LP64_OFF64_LDFLAGS = 9, _CS_POSIX_V6_LP64_OFF64_LIBS = 10, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS = 11, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS = 12, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS = 13, _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS = 14, } } else version( CRuntime_Bionic ) { enum F_OK = 0; enum R_OK = 4; enum W_OK = 2; enum X_OK = 1; enum _SC_PAGESIZE = 0x0027; enum _SC_NPROCESSORS_ONLN = 0x0061; enum _SC_THREAD_STACK_MIN = 0x004c; } else version( Solaris ) { enum F_OK = 0; enum R_OK = 4; enum W_OK = 2; enum X_OK = 1; enum F_ULOCK = 0; enum F_LOCK = 1; enum F_TLOCK = 2; enum F_TEST = 3; enum { // large file compilation environment configuration _CS_LFS_CFLAGS = 68, _CS_LFS_LDFLAGS = 69, _CS_LFS_LIBS = 70, _CS_LFS_LINTFLAGS = 71, // transitional large file interface configuration _CS_LFS64_CFLAGS = 72, _CS_LFS64_LDFLAGS = 73, _CS_LFS64_LIBS = 74, _CS_LFS64_LINTFLAGS = 75, // UNIX 98 _CS_XBS5_ILP32_OFF32_CFLAGS = 700, _CS_XBS5_ILP32_OFF32_LDFLAGS = 701, _CS_XBS5_ILP32_OFF32_LIBS = 702, _CS_XBS5_ILP32_OFF32_LINTFLAGS = 703, _CS_XBS5_ILP32_OFFBIG_CFLAGS = 705, _CS_XBS5_ILP32_OFFBIG_LDFLAGS = 706, _CS_XBS5_ILP32_OFFBIG_LIBS = 707, _CS_XBS5_ILP32_OFFBIG_LINTFLAGS = 708, _CS_XBS5_LP64_OFF64_CFLAGS = 709, _CS_XBS5_LP64_OFF64_LDFLAGS = 710, _CS_XBS5_LP64_OFF64_LIBS = 711, _CS_XBS5_LP64_OFF64_LINTFLAGS = 712, _CS_XBS5_LPBIG_OFFBIG_CFLAGS = 713, _CS_XBS5_LPBIG_OFFBIG_LDFLAGS = 714, _CS_XBS5_LPBIG_OFFBIG_LIBS = 715, _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS = 716, // UNIX 03 _CS_POSIX_V6_ILP32_OFF32_CFLAGS = 800, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS = 801, _CS_POSIX_V6_ILP32_OFF32_LIBS = 802, _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS = 803, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS = 804, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS = 805, _CS_POSIX_V6_ILP32_OFFBIG_LIBS = 806, _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS = 807, _CS_POSIX_V6_LP64_OFF64_CFLAGS = 808, _CS_POSIX_V6_LP64_OFF64_LDFLAGS = 809, _CS_POSIX_V6_LP64_OFF64_LIBS = 810, _CS_POSIX_V6_LP64_OFF64_LINTFLAGS = 811, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS = 812, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS = 813, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS = 814, _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS = 815, _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS = 816 } enum { _SC_ARG_MAX = 1, _SC_CHILD_MAX = 2, _SC_CLK_TCK = 3, _SC_NGROUPS_MAX = 4, _SC_OPEN_MAX = 5, _SC_JOB_CONTROL = 6, _SC_SAVED_IDS = 7, _SC_VERSION = 8, _SC_PASS_MAX = 9, _SC_LOGNAME_MAX = 10, _SC_PAGESIZE = 11, _SC_XOPEN_VERSION = 12, // 13 reserved for SVr4-ES/MP _SC_NACLS_MAX _SC_NPROCESSORS_CONF = 14, _SC_NPROCESSORS_ONLN = 15, _SC_STREAM_MAX = 16, _SC_TZNAME_MAX = 17, _SC_AIO_LISTIO_MAX = 18, _SC_AIO_MAX = 19, _SC_AIO_PRIO_DELTA_MAX = 20, _SC_ASYNCHRONOUS_IO = 21, _SC_DELAYTIMER_MAX = 22, _SC_FSYNC = 23, _SC_MAPPED_FILES = 24, _SC_MEMLOCK = 25, _SC_MEMLOCK_RANGE = 26, _SC_MEMORY_PROTECTION = 27, _SC_MESSAGE_PASSING = 28, _SC_MQ_OPEN_MAX = 29, _SC_MQ_PRIO_MAX = 30, _SC_PRIORITIZED_IO = 31, _SC_PRIORITY_SCHEDULING = 32, _SC_REALTIME_SIGNALS = 33, _SC_RTSIG_MAX = 34, _SC_SEMAPHORES = 35, _SC_SEM_NSEMS_MAX = 36, _SC_SEM_VALUE_MAX = 37, _SC_SHARED_MEMORY_OBJECTS = 38, _SC_SIGQUEUE_MAX = 39, _SC_SIGRT_MIN = 40, _SC_SIGRT_MAX = 41, _SC_SYNCHRONIZED_IO = 42, _SC_TIMERS = 43, _SC_TIMER_MAX = 44, _SC_2_C_BIND = 45, _SC_2_C_DEV = 46, _SC_2_C_VERSION = 47, _SC_2_FORT_DEV = 48, _SC_2_FORT_RUN = 49, _SC_2_LOCALEDEF = 50, _SC_2_SW_DEV = 51, _SC_2_UPE = 52, _SC_2_VERSION = 53, _SC_BC_BASE_MAX = 54, _SC_BC_DIM_MAX = 55, _SC_BC_SCALE_MAX = 56, _SC_BC_STRING_MAX = 57, _SC_COLL_WEIGHTS_MAX = 58, _SC_EXPR_NEST_MAX = 59, _SC_LINE_MAX = 60, _SC_RE_DUP_MAX = 61, _SC_XOPEN_CRYPT = 62, _SC_XOPEN_ENH_I18N = 63, _SC_XOPEN_SHM = 64, _SC_2_CHAR_TERM = 66, _SC_XOPEN_XCU_VERSION = 67, _SC_ATEXIT_MAX = 76, _SC_IOV_MAX = 77, _SC_XOPEN_UNIX = 78, _SC_T_IOV_MAX = 79, _SC_PHYS_PAGES = 500, _SC_AVPHYS_PAGES = 501, _SC_COHER_BLKSZ = 503, _SC_SPLIT_CACHE = 504, _SC_ICACHE_SZ = 505, _SC_DCACHE_SZ = 506, _SC_ICACHE_LINESZ = 507, _SC_DCACHE_LINESZ = 508, _SC_ICACHE_BLKSZ = 509, _SC_DCACHE_BLKSZ = 510, _SC_DCACHE_TBLKSZ = 511, _SC_ICACHE_ASSOC = 512, _SC_DCACHE_ASSOC = 513, _SC_MAXPID = 514, _SC_STACK_PROT = 515, _SC_NPROCESSORS_MAX = 516, _SC_CPUID_MAX = 517, _SC_EPHID_MAX = 518, _SC_THREAD_DESTRUCTOR_ITERATIONS = 568, _SC_GETGR_R_SIZE_MAX = 569, _SC_GETPW_R_SIZE_MAX = 570, _SC_LOGIN_NAME_MAX = 571, _SC_THREAD_KEYS_MAX = 572, _SC_THREAD_STACK_MIN = 573, _SC_THREAD_THREADS_MAX = 574, _SC_TTY_NAME_MAX = 575, _SC_THREADS = 576, _SC_THREAD_ATTR_STACKADDR = 577, _SC_THREAD_ATTR_STACKSIZE = 578, _SC_THREAD_PRIORITY_SCHEDULING = 579, _SC_THREAD_PRIO_INHERIT = 580, _SC_THREAD_PRIO_PROTECT = 581, _SC_THREAD_PROCESS_SHARED = 582, _SC_THREAD_SAFE_FUNCTIONS = 583, _SC_XOPEN_LEGACY = 717, _SC_XOPEN_REALTIME = 718, _SC_XOPEN_REALTIME_THREADS = 719, _SC_XBS5_ILP32_OFF32 = 720, _SC_XBS5_ILP32_OFFBIG = 721, _SC_XBS5_LP64_OFF64 = 722, _SC_XBS5_LPBIG_OFFBIG = 723, _SC_2_PBS = 724, _SC_2_PBS_ACCOUNTING = 725, _SC_2_PBS_CHECKPOINT = 726, _SC_2_PBS_LOCATE = 728, _SC_2_PBS_MESSAGE = 729, _SC_2_PBS_TRACK = 730, _SC_ADVISORY_INFO = 731, _SC_BARRIERS = 732, _SC_CLOCK_SELECTION = 733, _SC_CPUTIME = 734, _SC_HOST_NAME_MAX = 735, _SC_MONOTONIC_CLOCK = 736, _SC_READER_WRITER_LOCKS = 737, _SC_REGEXP = 738, _SC_SHELL = 739, _SC_SPAWN = 740, _SC_SPIN_LOCKS = 741, _SC_SPORADIC_SERVER = 742, _SC_SS_REPL_MAX = 743, _SC_SYMLOOP_MAX = 744, _SC_THREAD_CPUTIME = 745, _SC_THREAD_SPORADIC_SERVER = 746, _SC_TIMEOUTS = 747, _SC_TRACE = 748, _SC_TRACE_EVENT_FILTER = 749, _SC_TRACE_EVENT_NAME_MAX = 750, _SC_TRACE_INHERIT = 751, _SC_TRACE_LOG = 752, _SC_TRACE_NAME_MAX = 753, _SC_TRACE_SYS_MAX = 754, _SC_TRACE_USER_EVENT_MAX = 755, _SC_TYPED_MEMORY_OBJECTS = 756, _SC_V6_ILP32_OFF32 = 757, _SC_V6_ILP32_OFFBIG = 758, _SC_V6_LP64_OFF64 = 759, _SC_V6_LPBIG_OFFBIG = 760, _SC_XOPEN_STREAMS = 761, _SC_IPV6 = 762, _SC_RAW_SOCKETS = 763, } enum _SC_PAGE_SIZE = _SC_PAGESIZE; enum { _PC_LINK_MAX = 1, _PC_MAX_CANON = 2, _PC_MAX_INPUT = 3, _PC_NAME_MAX = 4, _PC_PATH_MAX = 5, _PC_PIPE_BUF = 6, _PC_NO_TRUNC = 7, _PC_VDISABLE = 8, _PC_CHOWN_RESTRICTED = 9, _PC_ASYNC_IO = 10, _PC_PRIO_IO = 11, _PC_SYNC_IO = 12, _PC_ALLOC_SIZE_MIN = 13, _PC_REC_INCR_XFER_SIZE = 14, _PC_REC_MAX_XFER_SIZE = 15, _PC_REC_MIN_XFER_SIZE = 16, _PC_REC_XFER_ALIGN = 17, _PC_SYMLINK_MAX = 18, _PC_2_SYMLINKS = 19, _PC_ACL_ENABLED = 20, _PC_MIN_HOLE_SIZE = 21, _PC_CASE_BEHAVIOR = 22, _PC_SATTR_ENABLED = 23, _PC_SATTR_EXISTS = 24, _PC_ACCESS_FILTERING = 25, _PC_TIMESTAMP_RESOLUTION = 26, _PC_FILESIZEBITS = 67, _PC_XATTR_ENABLED = 100, _PC_XATTR_EXISTS = 101 } enum _PC_LAST = 101; } // // File Synchronization (FSC) // /* int fsync(int); */ version( CRuntime_Glibc ) { int fsync(int) @trusted; } else version( OSX ) { int fsync(int) @trusted; } else version( FreeBSD ) { int fsync(int) @trusted; } else version( CRuntime_Bionic ) { int fsync(int) @trusted; } else version( Solaris ) { int fsync(int) @trusted; } // // Synchronized I/O (SIO) // /* int fdatasync(int); */ version( CRuntime_Glibc ) { int fdatasync(int) @trusted; } else version( Solaris ) { int fdatasync(int) @trusted; } else version( CRuntime_Bionic ) { int fdatasync(int) @trusted; } // // XOpen (XSI) // /* char* crypt(in char*, in char*); char* ctermid(char*); void encrypt(ref char[64], int); int fchdir(int); c_long gethostid(); pid_t getpgid(pid_t); pid_t getsid(pid_t); char* getwd(char*); // LEGACY int lchown(in char*, uid_t, gid_t); int lockf(int, int, off_t); int nice(int); ssize_t pread(int, void*, size_t, off_t); ssize_t pwrite(int, in void*, size_t, off_t); pid_t setpgrp(); int setregid(gid_t, gid_t); int setreuid(uid_t, uid_t); void swab(in void*, void*, ssize_t); void sync(); int truncate(in char*, off_t); useconds_t ualarm(useconds_t, useconds_t); int usleep(useconds_t); pid_t vfork(); */ version( CRuntime_Glibc ) { char* crypt(in char*, in char*); char* ctermid(char*); void encrypt(ref char[64], int) @trusted; int fchdir(int) @trusted; c_long gethostid() @trusted; pid_t getpgid(pid_t) @trusted; pid_t getsid(pid_t) @trusted; char* getwd(char*); // LEGACY int lchown(in char*, uid_t, gid_t); //int lockf(int, int, off_t); int nice(int) @trusted; //ssize_t pread(int, void*, size_t, off_t); //ssize_t pwrite(int, in void*, size_t, off_t); pid_t setpgrp() @trusted; int setregid(gid_t, gid_t) @trusted; int setreuid(uid_t, uid_t) @trusted; void swab(in void*, void*, ssize_t); void sync() @trusted; //int truncate(in char*, off_t); useconds_t ualarm(useconds_t, useconds_t) @trusted; int usleep(useconds_t) @trusted; pid_t vfork(); static if( __USE_FILE_OFFSET64 ) { int lockf64(int, int, off_t) @trusted; alias lockf64 lockf; ssize_t pread64(int, void*, size_t, off_t); alias pread64 pread; ssize_t pwrite64(int, in void*, size_t, off_t); alias pwrite64 pwrite; int truncate64(in char*, off_t); alias truncate64 truncate; } else { int lockf(int, int, off_t) @trusted; ssize_t pread(int, void*, size_t, off_t); ssize_t pwrite(int, in void*, size_t, off_t); int truncate(in char*, off_t); } } else version( OSX ) { char* crypt(in char*, in char*); char* ctermid(char*); void encrypt(ref char[64], int) @trusted; int fchdir(int) @trusted; c_long gethostid() @trusted; pid_t getpgid(pid_t) @trusted; pid_t getsid(pid_t) @trusted; char* getwd(char*); // LEGACY int lchown(in char*, uid_t, gid_t); int lockf(int, int, off_t) @trusted; int nice(int) @trusted; ssize_t pread(int, void*, size_t, off_t); ssize_t pwrite(int, in void*, size_t, off_t); pid_t setpgrp() @trusted; int setregid(gid_t, gid_t) @trusted; int setreuid(uid_t, uid_t) @trusted; void swab(in void*, void*, ssize_t); void sync() @trusted; int truncate(in char*, off_t); useconds_t ualarm(useconds_t, useconds_t) @trusted; int usleep(useconds_t) @trusted; pid_t vfork(); } else version( FreeBSD ) { char* crypt(in char*, in char*); //char* ctermid(char*); void encrypt(ref char[64], int) @trusted; int fchdir(int) @trusted; c_long gethostid() @trusted; int getpgid(pid_t) @trusted; int getsid(pid_t) @trusted; char* getwd(char*); // LEGACY int lchown(in char*, uid_t, gid_t); int lockf(int, int, off_t) @trusted; int nice(int) @trusted; ssize_t pread(int, void*, size_t, off_t); ssize_t pwrite(int, in void*, size_t, off_t); int setpgrp(pid_t, pid_t) @trusted; int setregid(gid_t, gid_t) @trusted; int setreuid(uid_t, uid_t) @trusted; void swab(in void*, void*, ssize_t); void sync() @trusted; int truncate(in char*, off_t); useconds_t ualarm(useconds_t, useconds_t) @trusted; int usleep(useconds_t) @trusted; pid_t vfork(); } else version( CRuntime_Bionic ) { int fchdir(int) @trusted; pid_t getpgid(pid_t) @trusted; int lchown(in char*, uid_t, gid_t); int nice(int) @trusted; ssize_t pread(int, void*, size_t, off_t); ssize_t pwrite(int, in void*, size_t, off_t); int setpgrp() @trusted; int setregid(gid_t, gid_t) @trusted; int setreuid(uid_t, uid_t) @trusted; int sync() @trusted; int truncate(in char*, off_t); int usleep(c_ulong) @trusted; pid_t vfork(); } else version( Solaris ) { char* crypt(in char*, in char*); char* ctermid(char*); void encrypt(ref char[64], int); int fchdir(int); c_long gethostid(); pid_t getpgid(pid_t); pid_t getsid(pid_t); char* getwd(char*); // LEGACY int lchown(in char*, uid_t, gid_t); int nice(int); pid_t setpgrp(); int setregid(gid_t, gid_t); int setreuid(uid_t, uid_t); void swab(in void*, void*, ssize_t); void sync(); useconds_t ualarm(useconds_t, useconds_t); int usleep(useconds_t); pid_t vfork(); version (D_LP64) { int lockf(int, int, off_t); alias lockf lockf64; ssize_t pread(int, void*, size_t, off_t); alias pread pread64; ssize_t pwrite(int, in void*, size_t, off_t); alias pwrite pwrite64; int truncate(in char*, off_t); alias truncate truncate64; } else { static if( __USE_FILE_OFFSET64 ) { int lockf64(int, int, off64_t); alias lockf64 lockf; ssize_t pread64(int, void*, size_t, off64_t); alias pread64 pread; ssize_t pwrite64(int, in void*, size_t, off_t); alias pwrite64 pwrite; int truncate64(in char*, off_t); alias truncate64 truncate; } else { int lockf(int, int, off_t); ssize_t pread(int, void*, size_t, off_t); ssize_t pwrite(int, in void*, size_t, off_t); int truncate(in char*, off_t); } } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/arpa/0000775000175000017500000000000012776214756022105 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/arpa/inet.d0000664000175000017500000001320412776214756023211 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.arpa.inet; private import core.sys.posix.config; public import core.stdc.inttypes; // for uint32_t, uint16_t public import core.sys.posix.sys.socket; // for socklen_t version (Posix): extern (C) nothrow @nogc: // // Required // /* NOTE: The following must must be defined in core.sys.posix.arpa.inet to break a circular import: in_port_t, in_addr_t, struct in_addr, INET_ADDRSTRLEN. in_port_t // from core.sys.posix.netinet.in_ in_addr_t // from core.sys.posix.netinet.in_ struct in_addr // from core.sys.posix.netinet.in_ INET_ADDRSTRLEN // from core.sys.posix.netinet.in_ uint32_t // from core.stdc.inttypes uint16_t // from core.stdc.inttypes uint32_t htonl(uint32_t); uint16_t htons(uint16_t); uint32_t ntohl(uint32_t); uint16_t ntohs(uint16_t); in_addr_t inet_addr(in char*); char* inet_ntoa(in_addr); // per spec: const char* inet_ntop(int, const void*, char*, socklen_t); char* inet_ntop(int, in void*, char*, socklen_t); int inet_pton(int, in char*, void*); */ version( CRuntime_Glibc ) { alias uint16_t in_port_t; alias uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; } enum INET_ADDRSTRLEN = 16; @trusted pure { uint32_t htonl(uint32_t); uint16_t htons(uint16_t); uint32_t ntohl(uint32_t); uint16_t ntohs(uint16_t); } in_addr_t inet_addr(in char*); char* inet_ntoa(in_addr); const(char)* inet_ntop(int, in void*, char*, socklen_t); int inet_pton(int, in char*, void*); } else version( OSX ) { alias uint16_t in_port_t; alias uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; } enum INET_ADDRSTRLEN = 16; @trusted pure { uint32_t htonl(uint32_t); uint16_t htons(uint16_t); uint32_t ntohl(uint32_t); uint16_t ntohs(uint16_t); } in_addr_t inet_addr(in char*); char* inet_ntoa(in_addr); const(char)* inet_ntop(int, in void*, char*, socklen_t); int inet_pton(int, in char*, void*); } else version( FreeBSD ) { alias uint16_t in_port_t; alias uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; } enum INET_ADDRSTRLEN = 16; @trusted pure { uint32_t htonl(uint32_t); uint16_t htons(uint16_t); uint32_t ntohl(uint32_t); uint16_t ntohs(uint16_t); } in_addr_t inet_addr(in char*); char* inet_ntoa(in_addr); const(char)* inet_ntop(int, in void*, char*, socklen_t); int inet_pton(int, in char*, void*); } else version( Solaris ) { alias uint16_t in_port_t; alias uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; } enum INET_ADDRSTRLEN = 16; @trusted pure { uint32_t htonl(uint32_t); uint16_t htons(uint16_t); uint32_t ntohl(uint32_t); uint16_t ntohs(uint16_t); } in_addr_t inet_addr(in char*); char* inet_ntoa(in_addr); const(char)* inet_ntop(int, in void*, char*, socklen_t); int inet_pton(int, in char*, void*); } else version( Solaris ) { alias uint16_t in_port_t; alias uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; } enum INET_ADDRSTRLEN = 16; @trusted pure { uint32_t htonl(uint32_t); uint16_t htons(uint16_t); uint32_t ntohl(uint32_t); uint16_t ntohs(uint16_t); } in_addr_t inet_addr(in char*); char* inet_ntoa(in_addr); const(char)* inet_ntop(int, in void*, char*, socklen_t); int inet_pton(int, in char*, void*); } else version( CRuntime_Bionic ) { alias uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; } enum INET_ADDRSTRLEN = 16; @safe pure extern (D) { private { uint32_t __swap32( uint32_t x ) { uint32_t byte32_swap = (x & 0xff) << 24 | (x &0xff00) << 8 | (x & 0xff0000) >> 8 | (x & 0xff000000) >> 24; return byte32_swap; } uint16_t __swap16( uint16_t x ) { uint16_t byte16_swap = (x & 0xff) << 8 | (x & 0xff00) >> 8; return byte16_swap; } } uint32_t htonl(uint32_t x) { return __swap32(x); } uint16_t htons(uint16_t x) { return __swap16(x); } uint32_t ntohl(uint32_t x) { return __swap32(x); } uint16_t ntohs(uint16_t x) { return __swap16(x); } } in_addr_t inet_addr(in char*); char* inet_ntoa(in_addr); const(char)* inet_ntop(int, in void*, char*, size_t); int inet_pton(int, in char*, void*); } // // IPV6 (IP6) // /* NOTE: The following must must be defined in core.sys.posix.arpa.inet to break a circular import: INET6_ADDRSTRLEN. INET6_ADDRSTRLEN // from core.sys.posix.netinet.in_ */ version( CRuntime_Glibc ) { enum INET6_ADDRSTRLEN = 46; } else version( OSX ) { enum INET6_ADDRSTRLEN = 46; } else version( FreeBSD ) { enum INET6_ADDRSTRLEN = 46; } else version( Solaris ) { enum INET6_ADDRSTRLEN = 46; } else version( CRuntime_Bionic ) { enum INET6_ADDRSTRLEN = 46; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/netinet/0000775000175000017500000000000012776214756022630 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/netinet/in_.d0000664000175000017500000006322312776214756023550 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.netinet.in_; private import core.sys.posix.config; public import core.stdc.inttypes; // for uint32_t, uint16_t, uint8_t public import core.sys.posix.arpa.inet; public import core.sys.posix.sys.socket; // for sa_family_t version (Posix): extern (C) nothrow @nogc: // // Required // /* NOTE: The following must must be defined in core.sys.posix.arpa.inet to break a circular import: in_port_t, in_addr_t, struct in_addr, INET_ADDRSTRLEN. in_port_t in_addr_t sa_family_t // from core.sys.posix.sys.socket uint8_t // from core.stdc.inttypes uint32_t // from core.stdc.inttypes struct in_addr { in_addr_t s_addr; } struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; in_addr sin_addr; } IPPROTO_IP IPPROTO_ICMP IPPROTO_TCP IPPROTO_UDP INADDR_ANY INADDR_BROADCAST INET_ADDRSTRLEN htonl() // from core.sys.posix.arpa.inet htons() // from core.sys.posix.arpa.inet ntohl() // from core.sys.posix.arpa.inet ntohs() // from core.sys.posix.arpa.inet */ version( CRuntime_Glibc ) { // Some networking constants are subtly different for glibc, linux kernel // constants are also provided below. //alias uint16_t in_port_t; //alias uint32_t in_addr_t; //struct in_addr //{ // in_addr_t s_addr; //} private enum __SOCK_SIZE__ = 16; struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; in_addr sin_addr; /* Pad to size of `struct sockaddr'. */ ubyte[__SOCK_SIZE__ - sa_family_t.sizeof - in_port_t.sizeof - in_addr.sizeof] __pad; } enum { IPPROTO_IP = 0, IPPROTO_ICMP = 1, IPPROTO_IGMP = 2, IPPROTO_GGP = 3, IPPROTO_TCP = 6, IPPROTO_PUP = 12, IPPROTO_UDP = 17, IPPROTO_IDP = 22, IPPROTO_ND = 77, IPPROTO_MAX = 256 } enum : uint { INADDR_ANY = 0x00000000, INADDR_BROADCAST = 0xffffffff, INADDR_LOOPBACK = 0x7F000001, INADDR_NONE = 0xFFFFFFFF } //enum INET_ADDRSTRLEN = 16; } else version( OSX ) { //alias uint16_t in_port_t; //alias uint32_t in_addr_t; //struct in_addr //{ // in_addr_t s_addr; //} private enum __SOCK_SIZE__ = 16; struct sockaddr_in { ubyte sin_len; sa_family_t sin_family; in_port_t sin_port; in_addr sin_addr; ubyte[8] sin_zero; } enum { IPPROTO_IP = 0, IPPROTO_ICMP = 1, IPPROTO_IGMP = 2, IPPROTO_GGP = 3, IPPROTO_TCP = 6, IPPROTO_PUP = 12, IPPROTO_UDP = 17, IPPROTO_IDP = 22, IPPROTO_ND = 77, IPPROTO_MAX = 256 } enum : uint { INADDR_ANY = 0x00000000, INADDR_BROADCAST = 0xffffffff, INADDR_LOOPBACK = 0x7F000001, INADDR_NONE = 0xFFFFFFFF } //enum INET_ADDRSTRLEN = 16; } else version( FreeBSD ) { //alias uint16_t in_port_t; //alias uint32_t in_addr_t; //struct in_addr //{ // in_addr_t s_addr; //} struct sockaddr_in { ubyte sin_len; sa_family_t sin_family; in_port_t sin_port; in_addr sin_addr; ubyte[8] sin_zero; } enum { IPPROTO_IP = 0, IPPROTO_ICMP = 1, IPPROTO_IGMP = 2, IPPROTO_GGP = 3, IPPROTO_TCP = 6, IPPROTO_PUP = 12, IPPROTO_UDP = 17, IPPROTO_IDP = 22, IPPROTO_ND = 77, IPPROTO_MAX = 256 } enum : uint { INADDR_ANY = 0x00000000, INADDR_BROADCAST = 0xffffffff, INADDR_LOOPBACK = 0x7f000001, INADDR_NONE = 0xffffffff } //enum INET_ADDRSTRLEN = 16; } else version( Solaris ) { struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; in_addr sin_addr; ubyte[8] sin_zero; } enum { IPPROTO_IP = 0, IPPROTO_ICMP = 1, IPPROTO_IGMP = 2, IPPROTO_GGP = 3, IPPROTO_TCP = 6, IPPROTO_PUP = 12, IPPROTO_UDP = 17, IPPROTO_IDP = 22, IPPROTO_ND = 77, IPPROTO_MAX = 256 } enum : uint { INADDR_ANY = 0x00000000, INADDR_BROADCAST = 0xffffffff, INADDR_LOOPBACK = 0x7f000001, INADDR_NONE = 0xffffffff } } else version( linux ) { private enum __SOCK_SIZE__ = 16; struct sockaddr_in { sa_family_t sin_family; ushort sin_port; in_addr sin_addr; /* Pad to size of `struct sockaddr'. */ ubyte[__SOCK_SIZE__ - sa_family_t.sizeof - ushort.sizeof - in_addr.sizeof] __pad; } enum { IPPROTO_IP = 0, IPPROTO_ICMP = 1, IPPROTO_IGMP = 2, IPPROTO_GGP = 3, IPPROTO_TCP = 6, IPPROTO_PUP = 12, IPPROTO_UDP = 17, IPPROTO_IDP = 22 } enum : c_ulong { INADDR_ANY = 0x00000000, INADDR_BROADCAST = 0xffffffff, INADDR_LOOPBACK = 0x7f000001, INADDR_NONE = 0xFFFFFFFF } } // // IPV6 (IP6) // /* NOTE: The following must must be defined in core.sys.posix.arpa.inet to break a circular import: INET6_ADDRSTRLEN. struct in6_addr { uint8_t[16] s6_addr; } struct sockaddr_in6 { sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; in6_addr sin6_addr; uint32_t sin6_scope_id; } extern in6_addr in6addr_any; extern in6_addr in6addr_loopback; struct ipv6_mreq { in6_addr ipv6mr_multiaddr; uint ipv6mr_interface; } IPPROTO_IPV6 INET6_ADDRSTRLEN IPV6_JOIN_GROUP IPV6_LEAVE_GROUP IPV6_MULTICAST_HOPS IPV6_MULTICAST_IF IPV6_MULTICAST_LOOP IPV6_UNICAST_HOPS IPV6_V6ONLY // macros int IN6_IS_ADDR_UNSPECIFIED(in6_addr*) int IN6_IS_ADDR_LOOPBACK(in6_addr*) int IN6_IS_ADDR_MULTICAST(in6_addr*) int IN6_IS_ADDR_LINKLOCAL(in6_addr*) int IN6_IS_ADDR_SITELOCAL(in6_addr*) int IN6_IS_ADDR_V4MAPPED(in6_addr*) int IN6_IS_ADDR_V4COMPAT(in6_addr*) int IN6_IS_ADDR_MC_NODELOCAL(in6_addr*) int IN6_IS_ADDR_MC_LINKLOCAL(in6_addr*) int IN6_IS_ADDR_MC_SITELOCAL(in6_addr*) int IN6_IS_ADDR_MC_ORGLOCAL(in6_addr*) int IN6_IS_ADDR_MC_GLOBAL(in6_addr*) */ version ( CRuntime_Glibc ) { struct in6_addr { union { uint8_t[16] s6_addr; uint16_t[8] s6_addr16; uint32_t[4] s6_addr32; } } struct sockaddr_in6 { sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; in6_addr sin6_addr; uint32_t sin6_scope_id; } extern __gshared immutable in6_addr in6addr_any; extern __gshared immutable in6_addr in6addr_loopback; struct ipv6_mreq { in6_addr ipv6mr_multiaddr; uint ipv6mr_interface; } enum : uint { IPPROTO_IPV6 = 41, //INET6_ADDRSTRLEN = 46, IPV6_JOIN_GROUP = 20, IPV6_LEAVE_GROUP = 21, IPV6_MULTICAST_HOPS = 18, IPV6_MULTICAST_IF = 17, IPV6_MULTICAST_LOOP = 19, IPV6_UNICAST_HOPS = 16, IPV6_V6ONLY = 26 } // macros extern (D) int IN6_IS_ADDR_UNSPECIFIED( in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == 0 && (cast(uint32_t*) addr)[3] == 0; } extern (D) int IN6_IS_ADDR_LOOPBACK( in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == 0 && (cast(uint32_t*) addr)[3] == htonl( 1 ); } extern (D) int IN6_IS_ADDR_MULTICAST( in6_addr* addr ) pure { return (cast(uint8_t*) addr)[0] == 0xff; } extern (D) int IN6_IS_ADDR_LINKLOCAL( in6_addr* addr ) pure { return ((cast(uint32_t*) addr)[0] & htonl( 0xffc00000 )) == htonl( 0xfe800000 ); } extern (D) int IN6_IS_ADDR_SITELOCAL( in6_addr* addr ) pure { return ((cast(uint32_t*) addr)[0] & htonl( 0xffc00000 )) == htonl( 0xfec00000 ); } extern (D) int IN6_IS_ADDR_V4MAPPED( in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == htonl( 0xffff ); } extern (D) int IN6_IS_ADDR_V4COMPAT( in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == 0 && ntohl( (cast(uint32_t*) addr)[3] ) > 1; } extern (D) int IN6_IS_ADDR_MC_NODELOCAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x1; } extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x2; } extern (D) int IN6_IS_ADDR_MC_SITELOCAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST(addr) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x5; } extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x8; } extern (D) int IN6_IS_ADDR_MC_GLOBAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0xe; } } else version( OSX ) { struct in6_addr { union { uint8_t[16] s6_addr; uint16_t[8] s6_addr16; uint32_t[4] s6_addr32; } } struct sockaddr_in6 { uint8_t sin6_len; sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; in6_addr sin6_addr; uint32_t sin6_scope_id; } extern __gshared immutable in6_addr in6addr_any; extern __gshared immutable in6_addr in6addr_loopback; struct ipv6_mreq { in6_addr ipv6mr_multiaddr; uint ipv6mr_interface; } enum : uint { IPPROTO_IPV6 = 41, //INET6_ADDRSTRLEN = 46, IPV6_JOIN_GROUP = 12, IPV6_LEAVE_GROUP = 13, IPV6_MULTICAST_HOPS = 10, IPV6_MULTICAST_IF = 9, IPV6_MULTICAST_LOOP = 11, IPV6_UNICAST_HOPS = 4, IPV6_V6ONLY = 27 } // macros extern (D) int IN6_IS_ADDR_UNSPECIFIED( in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == 0 && (cast(uint32_t*) addr)[3] == 0; } extern (D) int IN6_IS_ADDR_LOOPBACK( in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == 0 && (cast(uint32_t*) addr)[3] == ntohl( 1 ); } extern (D) int IN6_IS_ADDR_MULTICAST( in6_addr* addr ) pure { return addr.s6_addr[0] == 0xff; } extern (D) int IN6_IS_ADDR_LINKLOCAL( in6_addr* addr ) pure { return addr.s6_addr[0] == 0xfe && (addr.s6_addr[1] & 0xc0) == 0x80; } extern (D) int IN6_IS_ADDR_SITELOCAL( in6_addr* addr ) pure { return addr.s6_addr[0] == 0xfe && (addr.s6_addr[1] & 0xc0) == 0xc0; } extern (D) int IN6_IS_ADDR_V4MAPPED( in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == ntohl( 0x0000ffff ); } extern (D) int IN6_IS_ADDR_V4COMPAT( in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == 0 && (cast(uint32_t*) addr)[3] != 0 && (cast(uint32_t*) addr)[3] != ntohl( 1 ); } extern (D) int IN6_IS_ADDR_MC_NODELOCAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x1; } extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x2; } extern (D) int IN6_IS_ADDR_MC_SITELOCAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST(addr) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x5; } extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x8; } extern (D) int IN6_IS_ADDR_MC_GLOBAL( in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0xe; } } else version( FreeBSD ) { struct in6_addr { union { uint8_t[16] s6_addr; uint16_t[8] s6_addr16; uint32_t[4] s6_addr32; } } struct sockaddr_in6 { uint8_t sin6_len; sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; in6_addr sin6_addr; uint32_t sin6_scope_id; } extern __gshared immutable in6_addr in6addr_any; extern __gshared immutable in6_addr in6addr_loopback; struct ipv6_mreq { in6_addr ipv6mr_multiaddr; uint ipv6mr_interface; } enum : uint { IPPROTO_IPV6 = 41, //INET6_ADDRSTRLEN = 46, IPV6_JOIN_GROUP = 12, IPV6_LEAVE_GROUP = 13, IPV6_MULTICAST_HOPS = 10, IPV6_MULTICAST_IF = 9, IPV6_MULTICAST_LOOP = 11, IPV6_UNICAST_HOPS = 4, IPV6_V6ONLY = 27, } private enum { __IPV6_ADDR_SCOPE_NODELOCAL = 0x01, __IPV6_ADDR_SCOPE_INTFACELOCAL = 0x01, __IPV6_ADDR_SCOPE_LINKLOCAL = 0x02, __IPV6_ADDR_SCOPE_SITELOCAL = 0x05, __IPV6_ADDR_SCOPE_ORGLOCAL = 0x08, __IPV6_ADDR_SCOPE_GLOBAL = 0x0e, } // macros extern (D) int IN6_IS_ADDR_UNSPECIFIED( in in6_addr* a ) pure { return (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[0]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[4]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[8]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[12]) == 0); } extern (D) int IN6_IS_ADDR_LOOPBACK( in in6_addr* a ) pure { return (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[0]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[4]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[8]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[12]) == ntohl(1)); } extern (D) int IN6_IS_ADDR_V4COMPAT( in in6_addr* a ) pure { return (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[0]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[4]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[8]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[12]) != 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[12]) != ntohl(1)); } extern (D) int IN6_IS_ADDR_V4MAPPED( in in6_addr* a ) pure { return (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[0]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[4]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[8]) == ntohl(0x0000ffff)); } extern (D) int IN6_IS_ADDR_LINKLOCAL( in in6_addr* a ) pure { return a.s6_addr[0] == 0xfe && (a.s6_addr[1] & 0xc0) == 0x80; } extern (D) int IN6_IS_ADDR_SITELOCAL( in in6_addr* a ) pure { return a.s6_addr[0] == 0xfe && (a.s6_addr[1] & 0xc0) == 0xc0; } extern (D) int IN6_IS_ADDR_MULTICAST( in in6_addr* a ) pure { return a.s6_addr[0] == 0xff; } extern (D) uint8_t __IPV6_ADDR_MC_SCOPE( in in6_addr* a ) pure { return a.s6_addr[1] & 0x0f; } extern (D) int IN6_IS_ADDR_MC_NODELOCAL( in in6_addr* a ) pure { return IN6_IS_ADDR_MULTICAST(a) && __IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_NODELOCAL; } extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( in in6_addr* a ) pure { return IN6_IS_ADDR_MULTICAST(a) && __IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_LINKLOCAL; } extern (D) int IN6_IS_ADDR_MC_SITELOCAL( in in6_addr* a ) pure { return IN6_IS_ADDR_MULTICAST(a) && __IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL; } extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( in in6_addr* a ) pure { return IN6_IS_ADDR_MULTICAST(a) && __IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL; } extern (D) int IN6_IS_ADDR_MC_GLOBAL( in in6_addr* a ) pure { return IN6_IS_ADDR_MULTICAST(a) && __IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_GLOBAL; } } else version( Solaris ) { struct in6_addr { union { uint8_t[16] s6_addr; uint8_t[16] s6_addr8; uint32_t[4] s6_addr32; } } struct sockaddr_in6 { sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; in6_addr sin6_addr; uint32_t sin6_scope_id; uint32_t __sin6_src_id; } extern __gshared immutable in6_addr in6addr_any; extern __gshared immutable in6_addr in6addr_loopback; struct ipv6_mreq { in6_addr ipv6mr_multiaddr; uint ipv6mr_interface; } enum : uint { IPPROTO_IPV6 = 41, //INET6_ADDRSTRLEN = 46, IPV6_JOIN_GROUP = 9, IPV6_LEAVE_GROUP = 10, IPV6_MULTICAST_HOPS = 7, IPV6_MULTICAST_IF = 6, IPV6_MULTICAST_LOOP = 8, IPV6_UNICAST_HOPS = 5, IPV6_V6ONLY = 39, } // macros extern (D) int IN6_IS_ADDR_UNSPECIFIED( in in6_addr* a ) pure { return (a.s6_addr32[0] == 0) && (a.s6_addr32[1] == 0) && (a.s6_addr32[2] == 0) && (a.s6_addr32[3] == 0); } extern (D) int IN6_IS_ADDR_LOOPBACK( in in6_addr* a ) pure { return (a.s6_addr32[0] == 0) && (a.s6_addr32[1] == 0) && (a.s6_addr32[2] == 0) && (a.s6_addr32[3] == ntohl(1)); } extern (D) int IN6_IS_ADDR_V4COMPAT( in in6_addr* a ) pure { return (a.s6_addr32[0] == 0) && (a.s6_addr32[1] == 0) && (a.s6_addr32[2] == 0) && (a.s6_addr32[3] != 0) && (a.s6_addr32[3] != ntohl(1)); } extern (D) int IN6_IS_ADDR_V4MAPPED( in in6_addr* a ) pure { return (a.s6_addr32[0] == 0) && (a.s6_addr32[1] == 0) && (a.s6_addr32[2] == ntohl(0x0000ffff)); } extern (D) int IN6_IS_ADDR_LINKLOCAL( in in6_addr* a ) pure { return a.s6_addr8[0] == 0xfe && (a.s6_addr8[1] & 0xc0) == 0x80; } extern (D) int IN6_IS_ADDR_SITELOCAL( in in6_addr* a ) pure { return a.s6_addr8[0] == 0xfe && (a.s6_addr8[1] & 0xc0) == 0xc0; } extern (D) int IN6_IS_ADDR_MULTICAST( in in6_addr* a ) pure { return a.s6_addr8[0] == 0xff; } extern (D) int IN6_IS_ADDR_MC_NODELOCAL( in in6_addr* a ) pure { return a.s6_addr8[0] == 0xff && (a.s6_addr8[1] & 0x0f) == 0x01; } extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( in in6_addr* a ) pure { return a.s6_addr8[0] == 0xff && (a.s6_addr8[1] & 0x0f) == 0x02; } extern (D) int IN6_IS_ADDR_MC_SITELOCAL( in in6_addr* a ) pure { return a.s6_addr8[0] == 0xff && (a.s6_addr8[1] & 0x0f) == 0x05; } extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( in in6_addr* a ) pure { return a.s6_addr8[0] == 0xff && (a.s6_addr8[1] & 0x0f) == 0x08; } extern (D) int IN6_IS_ADDR_MC_GLOBAL( in in6_addr* a ) pure { return a.s6_addr8[0] == 0xff && (a.s6_addr8[1] & 0x0f) == 0x0e; } } else version( CRuntime_Bionic ) { struct in6_addr { union { uint8_t[16] s6_addr; uint16_t[8] s6_addr16; uint32_t[4] s6_addr32; } } struct sockaddr_in6 { ushort sin6_family; uint16_t sin6_port; uint32_t sin6_flowinfo; in6_addr sin6_addr; uint32_t sin6_scope_id; } __gshared immutable in6_addr in6addr_any = {[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}; __gshared immutable in6_addr in6addr_loopback = {[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]}; struct ipv6_mreq { in6_addr ipv6mr_multiaddr; int ipv6mr_ifindex; } enum : uint { IPPROTO_IPV6 = 41, IPV6_JOIN_GROUP = 20, IPV6_LEAVE_GROUP = 21, IPV6_MULTICAST_HOPS = 18, IPV6_MULTICAST_IF = 17, IPV6_MULTICAST_LOOP = 19, IPV6_UNICAST_HOPS = 16, IPV6_V6ONLY = 26 } private enum { IPV6_ADDR_SCOPE_NODELOCAL = 0x01, IPV6_ADDR_SCOPE_INTFACELOCAL = 0x01, IPV6_ADDR_SCOPE_LINKLOCAL = 0x02, IPV6_ADDR_SCOPE_SITELOCAL = 0x05, IPV6_ADDR_SCOPE_ORGLOCAL = 0x08, IPV6_ADDR_SCOPE_GLOBAL = 0x0e, } extern (D) pure { bool IN6_IS_ADDR_UNSPECIFIED( in in6_addr* a ) { return (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[0]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[4]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[8]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[12]) == 0); } bool IN6_IS_ADDR_LOOPBACK( in in6_addr* a ) { return (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[0]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[4]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[8]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[12]) == ntohl(1)); } bool IN6_IS_ADDR_V4COMPAT( in in6_addr* a ) { return (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[0]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[4]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[8]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[12]) != 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[12]) != ntohl(1)); } bool IN6_IS_ADDR_V4MAPPED( in in6_addr* a ) { return (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[0]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[4]) == 0) && (*cast(const uint32_t*) cast(const void*) (&a.s6_addr[8]) == ntohl(0x0000ffff)); } bool IN6_IS_ADDR_LINKLOCAL( in in6_addr* a ) { return a.s6_addr[0] == 0xfe && (a.s6_addr[1] & 0xc0) == 0x80; } bool IN6_IS_ADDR_SITELOCAL( in in6_addr* a ) { return a.s6_addr[0] == 0xfe && (a.s6_addr[1] & 0xc0) == 0xc0; } bool IN6_IS_ADDR_ULA( in in6_addr* a ) { return (a.s6_addr[0] & 0xfe) == 0xfc; } bool IN6_IS_ADDR_MULTICAST( in in6_addr* a ) { return a.s6_addr[0] == 0xff; } uint8_t IPV6_ADDR_MC_SCOPE( in in6_addr* a ) { return a.s6_addr[1] & 0x0f; } bool IN6_IS_ADDR_MC_NODELOCAL( in in6_addr* a ) { return IN6_IS_ADDR_MULTICAST(a) && IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_NODELOCAL; } bool IN6_IS_ADDR_MC_LINKLOCAL( in in6_addr* a ) { return IN6_IS_ADDR_MULTICAST(a) && IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_LINKLOCAL; } bool IN6_IS_ADDR_MC_SITELOCAL( in in6_addr* a ) { return IN6_IS_ADDR_MULTICAST(a) && IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_SITELOCAL; } bool IN6_IS_ADDR_MC_ORGLOCAL( in in6_addr* a ) { return IN6_IS_ADDR_MULTICAST(a) && IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_ORGLOCAL; } bool IN6_IS_ADDR_MC_GLOBAL( in in6_addr* a ) { return IN6_IS_ADDR_MULTICAST(a) && IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_GLOBAL; } } } // // Raw Sockets (RS) // /* IPPROTO_RAW */ version( CRuntime_Glibc ) { enum uint IPPROTO_RAW = 255; } else version( OSX ) { enum uint IPPROTO_RAW = 255; } else version( FreeBSD ) { enum uint IPPROTO_RAW = 255; } else version( Solaris ) { enum uint IPPROTO_RAW = 255; } else version( linux ) { enum uint IPPROTO_RAW = 255; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/netinet/tcp.d0000664000175000017500000000157212776214756023570 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.netinet.tcp; private import core.sys.posix.config; version (Posix): extern (C): // // Required // /* TCP_NODELAY */ version( CRuntime_Glibc ) { enum TCP_NODELAY = 1; } else version( OSX ) { enum TCP_NODELAY = 1; } else version( FreeBSD ) { enum TCP_NODELAY = 1; } else version( Solaris ) { enum TCP_NODELAY = 1; } else version( linux ) { enum TCP_NODELAY = 1; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/0000775000175000017500000000000012776214756022000 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/stat.d0000664000175000017500000010271212776214756023123 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.stat; private import core.sys.posix.config; private import core.stdc.stdint; private import core.sys.posix.time; // for timespec public import core.sys.posix.sys.types; // for off_t, mode_t version (Posix): extern (C) nothrow @nogc: // // Required // /* struct stat { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; off_t st_size; time_t st_atime; time_t st_mtime; time_t st_ctime; } S_IRWXU S_IRUSR S_IWUSR S_IXUSR S_IRWXG S_IRGRP S_IWGRP S_IXGRP S_IRWXO S_IROTH S_IWOTH S_IXOTH S_ISUID S_ISGID S_ISVTX S_ISBLK(m) S_ISCHR(m) S_ISDIR(m) S_ISFIFO(m) S_ISREG(m) S_ISLNK(m) S_ISSOCK(m) S_TYPEISMQ(buf) S_TYPEISSEM(buf) S_TYPEISSHM(buf) int chmod(in char*, mode_t); int fchmod(int, mode_t); int fstat(int, stat*); int lstat(in char*, stat*); int mkdir(in char*, mode_t); int mkfifo(in char*, mode_t); int stat(in char*, stat*); mode_t umask(mode_t); */ version( CRuntime_Glibc ) { version (X86) { struct stat_t { dev_t st_dev; ushort __pad1; static if (!__USE_FILE_OFFSET64) { ino_t st_ino; } else { uint __st_ino; } mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; ushort __pad2; off_t st_size; blksize_t st_blksize; blkcnt_t st_blocks; static if (__USE_MISC || __USE_XOPEN2K8) { timespec st_atim; timespec st_mtim; timespec st_ctim; extern(D) { @property ref time_t st_atime() { return st_atim.tv_sec; } @property ref time_t st_mtime() { return st_mtim.tv_sec; } @property ref time_t st_ctime() { return st_ctim.tv_sec; } } } else { time_t st_atime; ulong_t st_atimensec; time_t st_mtime; ulong_t st_mtimensec; time_t st_ctime; ulong_t st_ctimensec; } static if (__USE_FILE_OFFSET64) { ino_t st_ino; } else { c_ulong __unused4; c_ulong __unused5; } } } else version (X86_64) { struct stat_t { dev_t st_dev; ino_t st_ino; nlink_t st_nlink; mode_t st_mode; uid_t st_uid; gid_t st_gid; uint __pad0; dev_t st_rdev; off_t st_size; blksize_t st_blksize; blkcnt_t st_blocks; static if (__USE_MISC || __USE_XOPEN2K8) { timespec st_atim; timespec st_mtim; timespec st_ctim; extern(D) { @property ref time_t st_atime() { return st_atim.tv_sec; } @property ref time_t st_mtime() { return st_mtim.tv_sec; } @property ref time_t st_ctime() { return st_ctim.tv_sec; } } } else { time_t st_atime; ulong_t st_atimensec; time_t st_mtime; ulong_t st_mtimensec; time_t st_ctime; ulong_t st_ctimensec; } slong_t[3] __unused; } } else version (MIPS_O32) { struct stat_t { c_ulong st_dev; c_long[3] st_pad1; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; c_ulong st_rdev; static if (!__USE_FILE_OFFSET64) { c_long[2] st_pad2; off_t st_size; c_long st_pad3; } else { c_long[3] st_pad2; off_t st_size; } static if (__USE_MISC || __USE_XOPEN2K8) { timespec st_atim; timespec st_mtim; timespec st_ctim; extern(D) { @property ref time_t st_atime() { return st_atim.tv_sec; } @property ref time_t st_mtime() { return st_mtim.tv_sec; } @property ref time_t st_ctime() { return st_ctim.tv_sec; } } } else { time_t st_atime; c_ulong st_atimensec; time_t st_mtime; c_ulong st_mtimensec; time_t st_ctime; c_ulong st_ctimensec; } blksize_t st_blksize; static if (!__USE_FILE_OFFSET64) { blkcnt_t st_blocks; } else { c_long st_pad4; blkcnt_t st_blocks; } c_long[14] st_pad5; } } else version (MIPS64) { struct stat_t { c_ulong st_dev; int[3] st_pad1; static if (!__USE_FILE_OFFSET64) { ino_t st_ino; } else { c_ulong st_ino; } mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; c_ulong st_rdev; static if (!__USE_FILE_OFFSET64) { uint[2] st_pad2; off_t st_size; int st_pad3; } else { c_long[3] st_pad2; c_long st_size; } static if (__USE_MISC || __USE_XOPEN2K8) { timespec st_atim; timespec st_mtim; timespec st_ctim; extern(D) { @property ref time_t st_atime() { return st_atim.tv_sec; } @property ref time_t st_mtime() { return st_mtim.tv_sec; } @property ref time_t st_ctime() { return st_ctim.tv_sec; } } } else { time_t st_atime; c_ulong st_atimensec; time_t st_mtime; c_ulong st_mtimensec; time_t st_ctime; c_ulong st_ctimensec; } blksize_t st_blksize; uint st_pad4; static if (!__USE_FILE_OFFSET64) { blkcnt_t st_blocks; } else { c_long st_blocks; } c_long[14] st_pad5; } } else version (PPC) { struct stat_t { c_ulong st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; c_ulong st_rdev; off_t st_size; c_ulong st_blksize; c_ulong st_blocks; c_ulong st_atime; c_ulong st_atime_nsec; c_ulong st_mtime; c_ulong st_mtime_nsec; c_ulong st_ctime; c_ulong st_ctime_nsec; c_ulong __unused4; c_ulong __unused5; } } else version (PPC64) { struct stat_t { c_ulong st_dev; ino_t st_ino; nlink_t st_nlink; mode_t st_mode; uid_t st_uid; gid_t st_gid; c_ulong st_rdev; off_t st_size; c_ulong st_blksize; c_ulong st_blocks; c_ulong st_atime; c_ulong st_atime_nsec; c_ulong st_mtime; c_ulong st_mtime_nsec; c_ulong st_ctime; c_ulong st_ctime_nsec; c_ulong __unused4; c_ulong __unused5; c_ulong __unused6; } } else version (ARM) { private { alias __dev_t = ulong; alias __ino_t = c_ulong; alias __ino64_t = ulong; alias __mode_t = uint; alias __nlink_t = size_t; alias __uid_t = uint; alias __gid_t = uint; alias __off_t = c_long; alias __off64_t = long; alias __blksize_t = c_long; alias __blkcnt_t = c_long; alias __blkcnt64_t = long; alias __timespec = timespec; alias __time_t = time_t; } struct stat_t { __dev_t st_dev; ushort __pad1; static if(!__USE_FILE_OFFSET64) { __ino_t st_ino; } else { __ino_t __st_ino; } __mode_t st_mode; __nlink_t st_nlink; __uid_t st_uid; __gid_t st_gid; __dev_t st_rdev; ushort __pad2; static if(!__USE_FILE_OFFSET64) { __off_t st_size; } else { __off64_t st_size; } __blksize_t st_blksize; static if(!__USE_FILE_OFFSET64) { __blkcnt_t st_blocks; } else { __blkcnt64_t st_blocks; } static if( __USE_MISC || __USE_XOPEN2K8) { __timespec st_atim; __timespec st_mtim; __timespec st_ctim; extern(D) { @property ref time_t st_atime() { return st_atim.tv_sec; } @property ref time_t st_mtime() { return st_mtim.tv_sec; } @property ref time_t st_ctime() { return st_ctim.tv_sec; } } } else { __time_t st_atime; c_ulong st_atimensec; __time_t st_mtime; c_ulong st_mtimensec; __time_t st_ctime; c_ulong st_ctimensec; } static if(!__USE_FILE_OFFSET64) { c_ulong __unused4; c_ulong __unused5; } else { __ino64_t st_ino; } } static if(__USE_FILE_OFFSET64) static assert(stat_t.sizeof == 104); else static assert(stat_t.sizeof == 88); } else version (AArch64) { private { alias __dev_t = ulong; alias __ino_t = c_ulong; alias __ino64_t = ulong; alias __mode_t = uint; alias __nlink_t = uint; alias __uid_t = uint; alias __gid_t = uint; alias __off_t = c_long; alias __off64_t = long; alias __blksize_t = int; alias __blkcnt_t = c_long; alias __blkcnt64_t = long; alias __timespec = timespec; alias __time_t = time_t; } struct stat_t { __dev_t st_dev; static if(!__USE_FILE_OFFSET64) { __ino_t st_ino; } else { __ino64_t st_ino; } __mode_t st_mode; __nlink_t st_nlink; __uid_t st_uid; __gid_t st_gid; __dev_t st_rdev; __dev_t __pad1; static if(!__USE_FILE_OFFSET64) { __off_t st_size; } else { __off64_t st_size; } __blksize_t st_blksize; int __pad2; static if(!__USE_FILE_OFFSET64) { __blkcnt_t st_blocks; } else { __blkcnt64_t st_blocks; } static if(__USE_MISC) { __timespec st_atim; __timespec st_mtim; __timespec st_ctim; extern(D) { @property ref time_t st_atime() { return st_atim.tv_sec; } @property ref time_t st_mtime() { return st_mtim.tv_sec; } @property ref time_t st_ctime() { return st_ctim.tv_sec; } } } else { __time_t st_atime; c_ulong st_atimensec; __time_t st_mtime; c_ulong st_mtimensec; __time_t st_ctime; c_ulong st_ctimensec; } int[2] __unused; } static if(__USE_FILE_OFFSET64) static assert(stat_t.sizeof == 128); else static assert(stat_t.sizeof == 128); } else version (SystemZ) { private { alias __dev_t = ulong; alias __ino_t = c_ulong; alias __ino64_t = ulong; alias __mode_t = uint; alias __nlink_t = uint; alias __uid_t = uint; alias __gid_t = uint; alias __off_t = c_long; alias __off64_t = long; alias __blksize_t = int; alias __blkcnt_t = c_long; alias __blkcnt64_t = long; alias __timespec = timespec; alias __time_t = time_t; } struct stat_t { __dev_t st_dev; __ino_t st_ino; __nlink_t st_nlink; __mode_t st_mode; __uid_t st_uid; __gid_t st_gid; int __glibc_reserved0; __dev_t st_rdev; __off_t st_size; static if (__USE_XOPEN2K8) { __timespec st_atim; __timespec st_mtim; __timespec st_ctim; extern(D) { @property ref time_t st_atime() { return st_atim.tv_sec; } @property ref time_t st_mtime() { return st_mtim.tv_sec; } @property ref time_t st_ctime() { return st_ctim.tv_sec; } } } else { __time_t st_atime; c_ulong st_atimensec; __time_t st_mtime; c_ulong st_mtimensec; __time_t st_ctime; c_ulong st_ctimensec; } __blksize_t st_blksize; __blkcnt_t st_blocks; c_long[3] __glibc_reserved; } static if(__USE_XOPEN2K8) static assert(stat_t.sizeof == 144); else static assert(stat_t.sizeof == 144); } else static assert(0, "unimplemented"); enum S_IRUSR = 0x100; // octal 0400 enum S_IWUSR = 0x080; // octal 0200 enum S_IXUSR = 0x040; // octal 0100 enum S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR; enum S_IRGRP = S_IRUSR >> 3; enum S_IWGRP = S_IWUSR >> 3; enum S_IXGRP = S_IXUSR >> 3; enum S_IRWXG = S_IRWXU >> 3; enum S_IROTH = S_IRGRP >> 3; enum S_IWOTH = S_IWGRP >> 3; enum S_IXOTH = S_IXGRP >> 3; enum S_IRWXO = S_IRWXG >> 3; enum S_ISUID = 0x800; // octal 04000 enum S_ISGID = 0x400; // octal 02000 enum S_ISVTX = 0x200; // octal 01000 private { extern (D) bool S_ISTYPE( mode_t mode, uint mask ) { return ( mode & S_IFMT ) == mask; } } extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); } extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); } extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); } extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); } extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); } extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); } extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); } static if( true /*__USE_POSIX199309*/ ) { extern bool S_TYPEISMQ( stat_t* buf ) { return false; } extern bool S_TYPEISSEM( stat_t* buf ) { return false; } extern bool S_TYPEISSHM( stat_t* buf ) { return false; } } } else version( OSX ) { // _DARWIN_FEATURE_64_BIT_INODE stat is default for Mac OSX >10.5 and is // only meaningful type for other OS X/Darwin variants (e.g. iOS). // man stat(2) gives details. struct stat_t { dev_t st_dev; mode_t st_mode; nlink_t st_nlink; ino_t st_ino; uid_t st_uid; gid_t st_gid; dev_t st_rdev; union { struct { timespec st_atimespec; timespec st_mtimespec; timespec st_ctimespec; timespec st_birthtimespec; } struct { time_t st_atime; c_long st_atimensec; time_t st_mtime; c_long st_mtimensec; time_t st_ctime; c_long st_ctimensec; time_t st_birthtime; c_long st_birthtimensec; } } off_t st_size; blkcnt_t st_blocks; blksize_t st_blksize; uint st_flags; uint st_gen; int st_lspare; long[2] st_qspare; } enum S_IRUSR = 0x100; // octal 0400 enum S_IWUSR = 0x080; // octal 0200 enum S_IXUSR = 0x040; // octal 0100 enum S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR; enum S_IRGRP = S_IRUSR >> 3; enum S_IWGRP = S_IWUSR >> 3; enum S_IXGRP = S_IXUSR >> 3; enum S_IRWXG = S_IRWXU >> 3; enum S_IROTH = S_IRGRP >> 3; enum S_IWOTH = S_IWGRP >> 3; enum S_IXOTH = S_IXGRP >> 3; enum S_IRWXO = S_IRWXG >> 3; enum S_ISUID = 0x800; // octal 04000 enum S_ISGID = 0x400; // octal 02000 enum S_ISVTX = 0x200; // octal 01000 private { extern (D) bool S_ISTYPE( mode_t mode, uint mask ) { return ( mode & S_IFMT ) == mask; } } extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); } extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); } extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); } extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); } extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); } extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); } extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); } } else version( FreeBSD ) { struct stat_t { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; time_t st_atime; c_long __st_atimensec; time_t st_mtime; c_long __st_mtimensec; time_t st_ctime; c_long __st_ctimensec; off_t st_size; blkcnt_t st_blocks; blksize_t st_blksize; fflags_t st_flags; uint st_gen; int st_lspare; time_t st_birthtime; c_long st_birthtimensec; ubyte[16 - timespec.sizeof] padding; } enum S_IRUSR = 0x100; // octal 0000400 enum S_IWUSR = 0x080; // octal 0000200 enum S_IXUSR = 0x040; // octal 0000100 enum S_IRWXU = 0x1C0; // octal 0000700 enum S_IRGRP = 0x020; // octal 0000040 enum S_IWGRP = 0x010; // octal 0000020 enum S_IXGRP = 0x008; // octal 0000010 enum S_IRWXG = 0x038; // octal 0000070 enum S_IROTH = 0x4; // 0000004 enum S_IWOTH = 0x2; // 0000002 enum S_IXOTH = 0x1; // 0000001 enum S_IRWXO = 0x7; // 0000007 enum S_ISUID = 0x800; // octal 0004000 enum S_ISGID = 0x400; // octal 0002000 enum S_ISVTX = 0x200; // octal 0001000 private { extern (D) bool S_ISTYPE( mode_t mode, uint mask ) { return ( mode & S_IFMT ) == mask; } } extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); } extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); } extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); } extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); } extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); } extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); } extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); } } else version (Solaris) { private enum _ST_FSTYPSZ = 16; version (D_LP64) { struct stat_t { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; union { timestruc_t st_atim; time_t st_atime; } union { timestruc_t st_mtim; time_t st_mtime; } union { timestruc_t st_ctim; time_t st_ctime; } blksize_t st_blksize; blkcnt_t st_blocks; char[_ST_FSTYPSZ] st_fstype; } static if (__USE_LARGEFILE64) alias stat_t stat64_t; } else { struct stat32_t { dev_t st_dev; c_long[3] st_pad1; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; c_long[2] st_pad2; off_t st_size; c_long st_pad3; union { timestruc_t st_atim; time_t st_atime; } union { timestruc_t st_mtim; time_t st_mtime; } union { timestruc_t st_ctim; time_t st_ctime; } blksize_t st_blksize; blkcnt_t st_blocks; char[_ST_FSTYPSZ] st_fstype; c_long[8] st_pad4; } struct stat64_t { dev_t st_dev; c_long[3] st_pad1; ino64_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; c_long[2] st_pad2; off64_t st_size; c_long st_pad3; union { timestruc_t st_atim; time_t st_atime; } union { timestruc_t st_mtim; time_t st_mtime; } union { timestruc_t st_ctim; time_t st_ctime; } blksize_t st_blksize; blkcnt64_t st_blocks; char[_ST_FSTYPSZ] st_fstype; c_long[8] st_pad4; } static if (__USE_FILE_OFFSET64) alias stat64_t stat_t; else alias stat32_t stat_t; } enum S_IRUSR = 0x100; enum S_IWUSR = 0x080; enum S_IXUSR = 0x040; enum S_IRWXU = 0x1C0; enum S_IRGRP = 0x020; enum S_IWGRP = 0x010; enum S_IXGRP = 0x008; enum S_IRWXG = 0x038; enum S_IROTH = 0x4; // 0000004 enum S_IWOTH = 0x2; // 0000002 enum S_IXOTH = 0x1; // 0000001 enum S_IRWXO = 0x7; // 0000007 enum S_ISUID = 0x800; enum S_ISGID = 0x400; enum S_ISVTX = 0x200; private { extern (D) bool S_ISTYPE(mode_t mode, uint mask) { return (mode & S_IFMT) == mask; } } extern (D) bool S_ISBLK(mode_t mode) { return S_ISTYPE(mode, S_IFBLK); } extern (D) bool S_ISCHR(mode_t mode) { return S_ISTYPE(mode, S_IFCHR); } extern (D) bool S_ISDIR(mode_t mode) { return S_ISTYPE(mode, S_IFDIR); } extern (D) bool S_ISFIFO(mode_t mode) { return S_ISTYPE(mode, S_IFIFO); } extern (D) bool S_ISREG(mode_t mode) { return S_ISTYPE(mode, S_IFREG); } extern (D) bool S_ISLNK(mode_t mode) { return S_ISTYPE(mode, S_IFLNK); } extern (D) bool S_ISSOCK(mode_t mode) { return S_ISTYPE(mode, S_IFSOCK); } extern (D) bool S_ISDOOR(mode_t mode) { return S_ISTYPE(mode, S_IFDOOR); } extern (D) bool S_ISPORT(mode_t mode) { return S_ISTYPE(mode, S_IFPORT); } } else version( CRuntime_Bionic ) { version (X86) { struct stat_t { ulong st_dev; ubyte[4] __pad0; c_ulong __st_ino; uint st_mode; uint st_nlink; c_ulong st_uid; c_ulong st_gid; ulong st_rdev; ubyte[4] __pad3; long st_size; c_ulong st_blksize; ulong st_blocks; c_ulong st_atime; c_ulong st_atime_nsec; c_ulong st_mtime; c_ulong st_mtime_nsec; c_ulong st_ctime; c_ulong st_ctime_nsec; ulong st_ino; } } else version (ARM) { struct stat_t { ulong st_dev; ubyte[4] __pad0; c_ulong __st_ino; uint st_mode; uint st_nlink; c_ulong st_uid; c_ulong st_gid; ulong st_rdev; ubyte[4] __pad3; long st_size; c_ulong st_blksize; ulong st_blocks; c_ulong st_atime; c_ulong st_atime_nsec; c_ulong st_mtime; c_ulong st_mtime_nsec; c_ulong st_ctime; c_ulong st_ctime_nsec; ulong st_ino; } } else { static assert(false, "Architecture not supported."); } enum S_IRUSR = 0x100; // octal 0000400 enum S_IWUSR = 0x080; // octal 0000200 enum S_IXUSR = 0x040; // octal 0000100 enum S_IRWXU = 0x1C0; // octal 0000700 enum S_IRGRP = 0x020; // octal 0000040 enum S_IWGRP = 0x010; // octal 0000020 enum S_IXGRP = 0x008; // octal 0000010 enum S_IRWXG = 0x038; // octal 0000070 enum S_IROTH = 0x4; // 0000004 enum S_IWOTH = 0x2; // 0000002 enum S_IXOTH = 0x1; // 0000001 enum S_IRWXO = 0x7; // 0000007 enum S_ISUID = 0x800; // octal 0004000 enum S_ISGID = 0x400; // octal 0002000 enum S_ISVTX = 0x200; // octal 0001000 private { extern (D) bool S_ISTYPE( uint mode, uint mask ) { return ( mode & S_IFMT ) == mask; } } extern (D) bool S_ISBLK( uint mode ) { return S_ISTYPE( mode, S_IFBLK ); } extern (D) bool S_ISCHR( uint mode ) { return S_ISTYPE( mode, S_IFCHR ); } extern (D) bool S_ISDIR( uint mode ) { return S_ISTYPE( mode, S_IFDIR ); } extern (D) bool S_ISFIFO( uint mode ) { return S_ISTYPE( mode, S_IFIFO ); } extern (D) bool S_ISREG( uint mode ) { return S_ISTYPE( mode, S_IFREG ); } extern (D) bool S_ISLNK( uint mode ) { return S_ISTYPE( mode, S_IFLNK ); } extern (D) bool S_ISSOCK( uint mode ) { return S_ISTYPE( mode, S_IFSOCK ); } } else { static assert(false, "Unsupported platform"); } int chmod(in char*, mode_t); int fchmod(int, mode_t); //int fstat(int, stat_t*); //int lstat(in char*, stat_t*); int mkdir(in char*, mode_t); int mkfifo(in char*, mode_t); //int stat(in char*, stat_t*); mode_t umask(mode_t); version( CRuntime_Glibc ) { static if( __USE_LARGEFILE64 ) { int fstat64(int, stat_t*) @trusted; alias fstat64 fstat; int lstat64(in char*, stat_t*); alias lstat64 lstat; int stat64(in char*, stat_t*); alias stat64 stat; } else { int fstat(int, stat_t*) @trusted; int lstat(in char*, stat_t*); int stat(in char*, stat_t*); } } else version (Solaris) { version (D_LP64) { int fstat(int, stat_t*) @trusted; int lstat(in char*, stat_t*); int stat(in char*, stat_t*); static if (__USE_LARGEFILE64) { alias fstat fstat64; alias lstat lstat64; alias stat stat64; } } else { static if (__USE_LARGEFILE64) { int fstat64(int, stat_t*) @trusted; alias fstat64 fstat; int lstat64(in char*, stat_t*); alias lstat64 lstat; int stat64(in char*, stat_t*); alias stat64 stat; } else { int fstat(int, stat_t*) @trusted; int lstat(in char*, stat_t*); int stat(in char*, stat_t*); } } } else version( OSX ) { // OS X maintains backwards compatibility with older binaries using 32-bit // inode functions by appending $INODE64 to newer 64-bit inode functions. pragma(mangle, "fstat$INODE64") int fstat(int, stat_t*); pragma(mangle, "lstat$INODE64") int lstat(in char*, stat_t*); pragma(mangle, "stat$INODE64") int stat(in char*, stat_t*); } else version( FreeBSD ) { int fstat(int, stat_t*); int lstat(in char*, stat_t*); int stat(in char*, stat_t*); } else version( CRuntime_Bionic ) { int fstat(int, stat_t*) @trusted; int lstat(in char*, stat_t*); int stat(in char*, stat_t*); } // // Typed Memory Objects (TYM) // /* S_TYPEISTMO(buf) */ // // XOpen (XSI) // /* S_IFMT S_IFBLK S_IFCHR S_IFIFO S_IFREG S_IFDIR S_IFLNK S_IFSOCK int mknod(in 3char*, mode_t, dev_t); */ version( CRuntime_Glibc ) { enum S_IFMT = 0xF000; // octal 0170000 enum S_IFBLK = 0x6000; // octal 0060000 enum S_IFCHR = 0x2000; // octal 0020000 enum S_IFIFO = 0x1000; // octal 0010000 enum S_IFREG = 0x8000; // octal 0100000 enum S_IFDIR = 0x4000; // octal 0040000 enum S_IFLNK = 0xA000; // octal 0120000 enum S_IFSOCK = 0xC000; // octal 0140000 int mknod(in char*, mode_t, dev_t); } else version( OSX ) { enum S_IFMT = 0xF000; // octal 0170000 enum S_IFBLK = 0x6000; // octal 0060000 enum S_IFCHR = 0x2000; // octal 0020000 enum S_IFIFO = 0x1000; // octal 0010000 enum S_IFREG = 0x8000; // octal 0100000 enum S_IFDIR = 0x4000; // octal 0040000 enum S_IFLNK = 0xA000; // octal 0120000 enum S_IFSOCK = 0xC000; // octal 0140000 int mknod(in char*, mode_t, dev_t); } else version( FreeBSD ) { enum S_IFMT = 0xF000; // octal 0170000 enum S_IFBLK = 0x6000; // octal 0060000 enum S_IFCHR = 0x2000; // octal 0020000 enum S_IFIFO = 0x1000; // octal 0010000 enum S_IFREG = 0x8000; // octal 0100000 enum S_IFDIR = 0x4000; // octal 0040000 enum S_IFLNK = 0xA000; // octal 0120000 enum S_IFSOCK = 0xC000; // octal 0140000 int mknod(in char*, mode_t, dev_t); } else version (Solaris) { enum S_IFMT = 0xF000; enum S_IFBLK = 0x6000; enum S_IFCHR = 0x2000; enum S_IFIFO = 0x1000; enum S_IFREG = 0x8000; enum S_IFDIR = 0x4000; enum S_IFLNK = 0xA000; enum S_IFSOCK = 0xC000; enum S_IFDOOR = 0xD000; enum S_IFPORT = 0xE000; int mknod(in char*, mode_t, dev_t); } else version( CRuntime_Bionic ) { enum S_IFMT = 0xF000; // octal 0170000 enum S_IFBLK = 0x6000; // octal 0060000 enum S_IFCHR = 0x2000; // octal 0020000 enum S_IFIFO = 0x1000; // octal 0010000 enum S_IFREG = 0x8000; // octal 0100000 enum S_IFDIR = 0x4000; // octal 0040000 enum S_IFLNK = 0xA000; // octal 0120000 enum S_IFSOCK = 0xC000; // octal 0140000 int mknod(in char*, mode_t, dev_t); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/msg.d0000664000175000017500000002275512776214756022746 0ustar kaikai/** * D header file for POSIX. * * Authors: Neven Miculinić */ module core.sys.posix.sys.msg; import core.sys.posix.sys.ipc; public import core.sys.posix.sys.types; public import core.stdc.config; version (CRuntime_Glibc): // Some of these may be from linux kernel headers. extern (C): public enum MSG_STAT = 11; public enum MSG_INFO = 12; public enum MSG_NOERROR = 1 << 12; // octal!10000 public enum MSG_EXCEPT = 2 << 12; // octal!20000 public enum MSG_COPY = 4 << 12; // octal!40000 struct msgbuf { c_long mtype; char[1] mtext; }; struct msginfo { int msgpool; int msgmap; int msgmax; int msgmnb; int msgmni; int msgssz; int msgtql; ushort msgseg; }; version(Alpha) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/alpha/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; struct msqid_ds { ipc_perm msg_perm; time_t msg_stime; time_t msg_rtime; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved1; c_ulong __glibc_reserved2; }; } else version(HPPA) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/hppa/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; // Assuming word size is 32 struct msqid_ds { ipc_perm msg_perm; c_ulong __pad1; time_t msg_stime; c_ulong __pad2; time_t msg_rtime; c_ulong __pad3; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved1; c_ulong __glibc_reserved2; }; } else version(MIPS) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/mips/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; struct msqid_ds { ipc_perm msg_perm; version(BigEndian) c_ulong __glibc_reserved1; time_t msg_stime; version(LittleEndian) c_ulong __glibc_reserved1; version(BigEndian) c_ulong __glibc_reserved2; time_t msg_rtime; version(LittleEndian) c_ulong __glibc_reserved2; version(BigEndian) c_ulong __glibc_reserved3; time_t msg_ctime; version(LittleEndian) c_ulong __glibc_reserved3; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else version(MIPS64) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/mips/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; struct msqid_ds { ipc_perm msg_perm; time_t msg_stime; time_t msg_rtime; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else version (PPC) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/powerpc/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; struct msqid_ds { ipc_perm msg_perm; c_ulong __glibc_reserved1; time_t msg_stime; c_ulong __glibc_reserved2; time_t msg_rtime; c_ulong __glibc_reserved3; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else version (PPC64) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/powerpc/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; struct msqid_ds { ipc_perm msg_perm; time_t msg_stime; time_t msg_rtime; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else version (S390) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/s390/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; // Assuming wordsize != 64 struct msqid_ds { ipc_perm msg_perm; c_ulong __glibc_reserved1; time_t msg_stime; c_ulong __glibc_reserved2; time_t msg_rtime; c_ulong __glibc_reserved3; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else version (SystemZ) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/s390/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; // Assuming wordsize == 64 struct msqid_ds { ipc_perm msg_perm; time_t msg_stime; time_t msg_rtime; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else version (SPARC) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sparc/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; // Assuming word size is 32 struct msqid_ds { ipc_perm msg_perm; c_ulong __pad1; time_t msg_stime; c_ulong __pad2; time_t msg_rtime; c_ulong __pad3; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved1; c_ulong __glibc_reserved2; }; } else version (X86) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; struct msqid_ds { ipc_perm msg_perm; time_t msg_stime; time_t msg_rtime; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else version (X86_64) { // Can't find adequate bits.h in https://sourceware.org/git/?p=glibc.git;a=tree;f=sysdeps/unix/sysv/linux/x86_64/bits;h=cd03a84463c9393dd751d78fba19e59aad3e0bb3;hb=HEAD // Using the same as in X86 version alias c_ulong msgqnum_t; alias c_ulong msglen_t; struct msqid_ds { ipc_perm msg_perm; c_ulong __glibc_reserved1; time_t msg_stime; c_ulong __glibc_reserved2; time_t msg_rtime; c_ulong __glibc_reserved3; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else version (AArch64) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/generic/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; struct msqid_ds { ipc_perm msg_perm; time_t msg_stime; time_t msg_rtime; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else version (ARM) { // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/generic/bits/msq.h alias c_ulong msgqnum_t; alias c_ulong msglen_t; struct msqid_ds { ipc_perm msg_perm; c_ulong __glibc_reserved1; time_t msg_stime; c_ulong __glibc_reserved2; time_t msg_rtime; c_ulong __glibc_reserved3; time_t msg_ctime; c_ulong __msg_cbytes; msgqnum_t msg_qnum; msglen_t msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; c_ulong __glibc_reserved4; c_ulong __glibc_reserved5; }; } else static assert(0, "unimplemented"); public enum MSG_MEM_SCALE = 32; public enum MSGMNI = 16; public enum MSGMAX = 8192; public enum MSGMNB = 16384; int msgctl (int msqid, int cmd, msqid_ds *__buf); int msgget ( key_t key, int msgflg ); ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, c_long msgtyp, int msgflg); int msgsnd ( int msqid, msgbuf *msgp, int msgsz, int msgflg ); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/shm.d0000664000175000017500000000602712776214756022741 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.shm; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for pid_t, time_t, key_t public import core.sys.posix.sys.ipc; version (Posix): extern (C) nothrow @nogc: // // XOpen (XSI) // /* SHM_RDONLY SHM_RND SHMLBA shmatt_t struct shmid_ds { ipc_perm shm_perm; size_t shm_segsz; pid_t shm_lpid; pid_t shm_cpid; shmatt_t shm_nattch; time_t shm_atime; time_t shm_dtime; time_t shm_ctime; } void* shmat(int, in void*, int); int shmctl(int, int, shmid_ds*); int shmdt(in void*); int shmget(key_t, size_t, int); */ version( CRuntime_Glibc ) { enum SHM_RDONLY = 0x01000; // 010000 enum SHM_RND = 0x02000; // 020000 int __getpagesize(); alias __getpagesize SHMLBA; alias c_ulong shmatt_t; /* For any changes, please check /usr/include/bits/shm.h */ struct shmid_ds { ipc_perm shm_perm; size_t shm_segsz; time_t shm_atime; version( X86_64 ) {} else c_ulong __unused1; time_t shm_dtime; version( X86_64 ) {} else c_ulong __unused2; time_t shm_ctime; version( X86_64 ) {} else c_ulong __unused3; pid_t shm_cpid; pid_t shm_lpid; shmatt_t shm_nattch; c_ulong __unused4; c_ulong __unused5; } void* shmat(int, in void*, int); int shmctl(int, int, shmid_ds*); int shmdt(in void*); int shmget(key_t, size_t, int); } else version( FreeBSD ) { enum SHM_RDONLY = 0x01000; // 010000 enum SHM_RND = 0x02000; // 020000 enum SHMLBA = 1 << 12; // PAGE_SIZE = (1<. */ static if(__USE_GNU) { enum FFlag { ST_RDONLY = 1, /* Mount read-only. */ ST_NOSUID = 2, ST_NODEV = 4, /* Disallow access to device special files. */ ST_NOEXEC = 8, /* Disallow program execution. */ ST_SYNCHRONOUS = 16, /* Writes are synced at once. */ ST_MANDLOCK = 64, /* Allow mandatory locks on an FS. */ ST_WRITE = 128, /* Write on file/directory/symlink. */ ST_APPEND = 256, /* Append-only file. */ ST_IMMUTABLE = 512, /* Immutable file. */ ST_NOATIME = 1024, /* Do not update access times. */ ST_NODIRATIME = 2048, /* Do not update directory access times. */ ST_RELATIME = 4096 /* Update atime relative to mtime/ctime. */ } } /* Use GNU. */ else { // Posix defined: enum FFlag { ST_RDONLY = 1, /* Mount read-only. */ ST_NOSUID = 2 } } static if( __USE_FILE_OFFSET64 ) { int statvfs64 (const char * file, statvfs_t* buf); alias statvfs64 statvfs; int fstatvfs64 (int fildes, statvfs_t *buf) @trusted; alias fstatvfs64 fstatvfs; } else { int statvfs (const char * file, statvfs_t* buf); int fstatvfs (int fildes, statvfs_t *buf); } } else { struct statvfs_t { c_ulong f_bsize; c_ulong f_frsize; fsblkcnt_t f_blocks; fsblkcnt_t f_bfree; fsblkcnt_t f_bavail; fsfilcnt_t f_files; fsfilcnt_t f_ffree; fsfilcnt_t f_favail; c_ulong f_fsid; c_ulong f_flag; c_ulong f_namemax; } enum FFlag { ST_RDONLY = 1, /* Mount read-only. */ ST_NOSUID = 2 } int statvfs (const char * file, statvfs_t* buf); int fstatvfs (int fildes, statvfs_t *buf) @trusted; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/un.d0000664000175000017500000000250212776214756022566 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.un; version (Posix): extern(C): public import core.sys.posix.sys.socket: sa_family_t; // // Required // /* struct sockaddr_un { sa_family_t sun_family; char sa_data[]; } sa_family_t // From core.sys.posix.sys.socket */ version( linux ) { enum UNIX_PATH_MAX = 108; struct sockaddr_un { sa_family_t sun_family; byte[UNIX_PATH_MAX] sun_path; } } else version( OSX ) { struct sockaddr_un { ubyte sun_len; sa_family_t sun_family; byte[104] sun_path; } } else version( FreeBSD ) { struct sockaddr_un { ubyte sun_len; sa_family_t sun_family; byte[104] sun_path; } } else version( Solaris ) { struct sockaddr_un { sa_family_t sun_family; byte[108] sun_path; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/mman.d0000664000175000017500000002657112776214756023110 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.mman; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for off_t, mode_t version (Posix): extern (C) nothrow @nogc: // // Advisory Information (ADV) // /* int posix_madvise(void*, size_t, int); */ // // Advisory Information and either Memory Mapped Files or Shared Memory Objects (MC1) // /* POSIX_MADV_NORMAL POSIX_MADV_SEQUENTIAL POSIX_MADV_RANDOM POSIX_MADV_WILLNEED POSIX_MADV_DONTNEED */ version( CRuntime_Glibc ) { version (Alpha) private enum __POSIX_MADV_DONTNEED = 6; else private enum __POSIX_MADV_DONTNEED = 4; static if (__USE_XOPEN2K) { enum { POSIX_MADV_NORMAL = 0, POSIX_MADV_RANDOM = 1, POSIX_MADV_SEQUENTIAL = 2, POSIX_MADV_WILLNEED = 3, POSIX_MADV_DONTNEED = __POSIX_MADV_DONTNEED, } int posix_madvise(void *__addr, size_t __len, int __advice); } } else version( OSX ) { enum POSIX_MADV_NORMAL = 0; enum POSIX_MADV_RANDOM = 1; enum POSIX_MADV_SEQUENTIAL = 2; enum POSIX_MADV_WILLNEED = 3; enum POSIX_MADV_DONTNEED = 4; int posix_madvise(void *addr, size_t len, int advice); } else version( FreeBSD ) { enum POSIX_MADV_NORMAL = 0; enum POSIX_MADV_RANDOM = 1; enum POSIX_MADV_SEQUENTIAL = 2; enum POSIX_MADV_WILLNEED = 3; enum POSIX_MADV_DONTNEED = 4; int posix_madvise(void *addr, size_t len, int advice); } else version (Solaris) { } else version (CRuntime_Bionic) { } else { static assert(false, "Unsupported platform"); } // // Memory Mapped Files, Shared Memory Objects, or Memory Protection (MC2) // /* PROT_READ PROT_WRITE PROT_EXEC PROT_NONE */ version( CRuntime_Glibc ) { enum PROT_NONE = 0x0; enum PROT_READ = 0x1; enum PROT_WRITE = 0x2; enum PROT_EXEC = 0x4; } else version( OSX ) { enum PROT_NONE = 0x00; enum PROT_READ = 0x01; enum PROT_WRITE = 0x02; enum PROT_EXEC = 0x04; } else version( FreeBSD ) { enum PROT_NONE = 0x00; enum PROT_READ = 0x01; enum PROT_WRITE = 0x02; enum PROT_EXEC = 0x04; } else version (Solaris) { enum PROT_NONE = 0x00; enum PROT_READ = 0x01; enum PROT_WRITE = 0x02; enum PROT_EXEC = 0x04; } else version (CRuntime_Bionic) { enum PROT_NONE = 0x00; enum PROT_READ = 0x01; enum PROT_WRITE = 0x02; enum PROT_EXEC = 0x04; } else { static assert(false, "Unsupported platform"); } // // Memory Mapped Files, Shared Memory Objects, or Typed Memory Objects (MC3) // /* void* mmap(void*, size_t, int, int, int, off_t); int munmap(void*, size_t); */ version( CRuntime_Glibc ) { static if (__USE_LARGEFILE64) void* mmap64(void*, size_t, int, int, int, off_t); static if (__USE_FILE_OFFSET64) alias mmap = mmap64; else void* mmap(void*, size_t, int, int, int, off_t); int munmap(void*, size_t); } else version( OSX ) { void* mmap(void*, size_t, int, int, int, off_t); int munmap(void*, size_t); } else version( FreeBSD ) { void* mmap(void*, size_t, int, int, int, off_t); int munmap(void*, size_t); } else version (Solaris) { void* mmap(void*, size_t, int, int, int, off_t); int munmap(void*, size_t); } else version (CRuntime_Bionic) { void* mmap(void*, size_t, int, int, int, off_t); int munmap(void*, size_t); } else { static assert(false, "Unsupported platform"); } // // Memory Mapped Files (MF) // /* MAP_SHARED (MF|SHM) MAP_PRIVATE (MF|SHM) MAP_FIXED (MF|SHM) MAP_FAILED (MF|SHM) MS_ASYNC (MF|SIO) MS_SYNC (MF|SIO) MS_INVALIDATE (MF|SIO) int msync(void*, size_t, int); (MF|SIO) */ version( CRuntime_Glibc ) { enum MAP_SHARED = 0x01; enum MAP_PRIVATE = 0x02; enum MAP_FIXED = 0x10; enum MAP_FAILED = cast(void*) -1; version (MICROBLAZE) private enum DEFAULTS = true; else version (Alpha) { private enum DEFAULTS = false; enum MAP_ANON = 0x10; enum MS_ASYNC = 1; enum MS_SYNC = 2; enum MS_INVALIDATE = 4; } else version (SH) private enum DEFAULTS = true; else version (SH64) private enum DEFAULTS = true; else version (AArch64) private enum DEFAULTS = true; else version (ARM) private enum DEFAULTS = true; else version (S390) private enum DEFAULTS = true; else version (SystemZ) private enum DEFAULTS = true; else version (IA64) private enum DEFAULTS = true; else version (HPPA) { private enum DEFAULTS = false; enum MAP_ANON = 0x10; enum MS_SYNC = 1; enum MS_ASYNC = 2; enum MS_INVALIDATE = 4; } else version (HPPA64) { private enum DEFAULTS = false; enum MAP_ANON = 0x10; enum MS_SYNC = 1; enum MS_ASYNC = 2; enum MS_INVALIDATE = 4; } else version (M68K) private enum DEFAULTS = true; else version (TILE) private enum DEFAULTS = true; else version (X86) private enum DEFAULTS = true; else version (X86_64) private enum DEFAULTS = true; else version (MIPS32) { private enum DEFAULTS = false; enum MAP_ANON = 0x0800; enum MS_ASYNC = 1; enum MS_INVALIDATE = 2; enum MS_SYNC = 4; } else version (MIPS64) { private enum DEFAULTS = false; enum MAP_ANON = 0x0800; enum MS_ASYNC = 1; enum MS_INVALIDATE = 2; enum MS_SYNC = 4; } else version (SPARC) private enum DEFAULTS = true; else version (SPARC64) private enum DEFAULTS = true; else version (PPC) private enum DEFAULTS = true; else version (PPC64) private enum DEFAULTS = true; else static assert(0, "unimplemented"); static if (DEFAULTS) { enum MAP_ANON = 0x20; enum MS_ASYNC = 1; enum MS_INVALIDATE = 2; enum MS_SYNC = 4; } int msync(void*, size_t, int); } else version( OSX ) { enum MAP_SHARED = 0x0001; enum MAP_PRIVATE = 0x0002; enum MAP_FIXED = 0x0010; enum MAP_ANON = 0x1000; enum MAP_FAILED = cast(void*)-1; enum MS_ASYNC = 0x0001; enum MS_INVALIDATE = 0x0002; enum MS_SYNC = 0x0010; int msync(void*, size_t, int); } else version( FreeBSD ) { enum MAP_SHARED = 0x0001; enum MAP_PRIVATE = 0x0002; enum MAP_FIXED = 0x0010; enum MAP_ANON = 0x1000; enum MAP_FAILED = cast(void*)-1; enum MS_SYNC = 0x0000; enum MS_ASYNC = 0x0001; enum MS_INVALIDATE = 0x0002; int msync(void*, size_t, int); } else version (Solaris) { enum MAP_SHARED = 0x0001; enum MAP_PRIVATE = 0x0002; enum MAP_FIXED = 0x0010; enum MAP_ANON = 0x0100; enum MAP_FAILED = cast(void*)-1; enum MS_SYNC = 0x0004; enum MS_ASYNC = 0x0001; enum MS_INVALIDATE = 0x0002; int msync(void*, size_t, int); } else version (CRuntime_Bionic) { enum MAP_SHARED = 0x0001; enum MAP_PRIVATE = 0x0002; enum MAP_FIXED = 0x0010; version (X86) { enum MAP_ANON = 0x0020; } else version (ARM) { enum MAP_ANON = 0x0020; } else { static assert(false, "Architecture not supported."); } enum MAP_FAILED = cast(void*)-1; enum MS_SYNC = 4; enum MS_ASYNC = 1; enum MS_INVALIDATE = 2; int msync(in void*, size_t, int); } else { static assert(false, "Unsupported platform"); } // // Process Memory Locking (ML) // /* MCL_CURRENT MCL_FUTURE int mlockall(int); int munlockall(); */ version( CRuntime_Glibc ) { version (SPARC) enum { MCL_CURRENT = 0x2000, MCL_FUTURE = 0x4000, } else version (SPARC64) enum { MCL_CURRENT = 0x2000, MCL_FUTURE = 0x4000, } else version (PPC) enum { MCL_CURRENT = 0x2000, MCL_FUTURE = 0x4000, } else version (PPC64) enum { MCL_CURRENT = 0x2000, MCL_FUTURE = 0x4000, } else version (Alpha) enum { MCL_CURRENT = 8192, MCL_FUTURE = 16384, } else enum { MCL_CURRENT = 1, MCL_FUTURE = 2, } int mlockall(int); int munlockall(); } else version( OSX ) { enum MCL_CURRENT = 0x0001; enum MCL_FUTURE = 0x0002; int mlockall(int); int munlockall(); } else version( FreeBSD ) { enum MCL_CURRENT = 0x0001; enum MCL_FUTURE = 0x0002; int mlockall(int); int munlockall(); } else version (Solaris) { enum MCL_CURRENT = 0x0001; enum MCL_FUTURE = 0x0002; int mlockall(int); int munlockall(); } else version (CRuntime_Bionic) { enum MCL_CURRENT = 1; enum MCL_FUTURE = 2; int mlockall(int); int munlockall(); } else { static assert(false, "Unsupported platform"); } // // Range Memory Locking (MLR) // /* int mlock(in void*, size_t); int munlock(in void*, size_t); */ version( CRuntime_Glibc ) { int mlock(in void*, size_t); int munlock(in void*, size_t); } else version( OSX ) { int mlock(in void*, size_t); int munlock(in void*, size_t); } else version( FreeBSD ) { int mlock(in void*, size_t); int munlock(in void*, size_t); } else version (Solaris) { int mlock(in void*, size_t); int munlock(in void*, size_t); } else version (CRuntime_Bionic) { int mlock(in void*, size_t); int munlock(in void*, size_t); } else { static assert(false, "Unsupported platform"); } // // Memory Protection (MPR) // /* int mprotect(void*, size_t, int); */ version (CRuntime_Glibc) { int mprotect(void*, size_t, int); } else version( OSX ) { int mprotect(void*, size_t, int); } else version( FreeBSD ) { int mprotect(void*, size_t, int); } else version (Solaris) { int mprotect(void*, size_t, int); } else version (CRuntime_Bionic) { int mprotect(in void*, size_t, int); } else { static assert(false, "Unsupported platform"); } // // Shared Memory Objects (SHM) // /* int shm_open(in char*, int, mode_t); int shm_unlink(in char*); */ version( CRuntime_Glibc ) { int shm_open(in char*, int, mode_t); int shm_unlink(in char*); } else version( OSX ) { int shm_open(in char*, int, mode_t); int shm_unlink(in char*); } else version( FreeBSD ) { int shm_open(in char*, int, mode_t); int shm_unlink(in char*); } else version (Solaris) { int shm_open(in char*, int, mode_t); int shm_unlink(in char*); } else version (CRuntime_Bionic) { } else { static assert(false, "Unsupported platform"); } // // Typed Memory Objects (TYM) // /* POSIX_TYPED_MEM_ALLOCATE POSIX_TYPED_MEM_ALLOCATE_CONTIG POSIX_TYPED_MEM_MAP_ALLOCATABLE struct posix_typed_mem_info { size_t posix_tmi_length; } int posix_mem_offset(in void*, size_t, off_t *, size_t *, int *); int posix_typed_mem_get_info(int, struct posix_typed_mem_info *); int posix_typed_mem_open(in char*, int, int); */ ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/types.d0000664000175000017500000004724312776214756023323 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.types; private import core.sys.posix.config; private import core.stdc.stdint; public import core.stdc.stddef; version (Posix): extern (C): // // bits/typesizes.h -- underlying types for *_t. // /* __syscall_slong_t __syscall_ulong_t */ version (CRuntime_Glibc) { version (X86_64) { version (D_X32) { // X32 kernel interface is 64-bit. alias long slong_t; alias ulong ulong_t; } else { alias c_long slong_t; alias c_ulong ulong_t; } } else { alias c_long slong_t; alias c_ulong ulong_t; } } else { alias c_long slong_t; alias c_ulong ulong_t; } // // Required // /* blkcnt_t blksize_t dev_t gid_t ino_t mode_t nlink_t off_t pid_t size_t ssize_t time_t uid_t */ version( CRuntime_Glibc ) { static if( __USE_FILE_OFFSET64 ) { alias long blkcnt_t; alias ulong ino_t; alias long off_t; } else { alias slong_t blkcnt_t; alias ulong_t ino_t; alias slong_t off_t; } alias slong_t blksize_t; alias ulong dev_t; alias uint gid_t; alias uint mode_t; alias ulong_t nlink_t; alias int pid_t; //size_t (defined in core.stdc.stddef) alias c_long ssize_t; alias slong_t time_t; alias uint uid_t; } else version( OSX ) { alias long blkcnt_t; alias int blksize_t; alias int dev_t; alias uint gid_t; alias ulong ino_t; alias ushort mode_t; alias ushort nlink_t; alias long off_t; alias int pid_t; //size_t (defined in core.stdc.stddef) alias c_long ssize_t; alias c_long time_t; alias uint uid_t; } else version( FreeBSD ) { alias long blkcnt_t; alias uint blksize_t; alias uint dev_t; alias uint gid_t; alias uint ino_t; alias ushort mode_t; alias ushort nlink_t; alias long off_t; alias int pid_t; //size_t (defined in core.stdc.stddef) alias c_long ssize_t; alias c_long time_t; alias uint uid_t; alias uint fflags_t; } else version (Solaris) { alias char* caddr_t; alias c_long daddr_t; alias short cnt_t; static if (__USE_FILE_OFFSET64) { alias long blkcnt_t; alias ulong ino_t; alias long off_t; } else { alias c_long blkcnt_t; alias c_ulong ino_t; alias c_long off_t; } version (D_LP64) { alias blkcnt_t blkcnt64_t; alias ino_t ino64_t; alias off_t off64_t; } else { alias long blkcnt64_t; alias ulong ino64_t; alias long off64_t; } alias uint blksize_t; alias c_ulong dev_t; alias uid_t gid_t; alias uint mode_t; alias uint nlink_t; alias int pid_t; alias c_long ssize_t; alias c_long time_t; alias uint uid_t; } else version( CRuntime_Bionic ) { alias c_ulong blkcnt_t; alias c_ulong blksize_t; alias uint dev_t; alias uint gid_t; alias c_ulong ino_t; alias c_long off_t; alias int pid_t; alias int ssize_t; alias c_long time_t; alias uint uid_t; version(X86) { alias ushort mode_t; alias ushort nlink_t; } else version(ARM) { alias ushort mode_t; alias ushort nlink_t; } else version(MIPS32) { alias uint mode_t; alias uint nlink_t; } else { static assert(false, "Architecture not supported."); } } else { static assert(false, "Unsupported platform"); } // // XOpen (XSI) // /* clock_t fsblkcnt_t fsfilcnt_t id_t key_t suseconds_t useconds_t */ version( CRuntime_Glibc ) { static if( __USE_FILE_OFFSET64 ) { alias ulong fsblkcnt_t; alias ulong fsfilcnt_t; } else { alias ulong_t fsblkcnt_t; alias ulong_t fsfilcnt_t; } alias slong_t clock_t; alias uint id_t; alias int key_t; alias slong_t suseconds_t; alias uint useconds_t; } else version( OSX ) { alias uint fsblkcnt_t; alias uint fsfilcnt_t; alias c_long clock_t; alias uint id_t; // key_t alias int suseconds_t; alias uint useconds_t; } else version( FreeBSD ) { alias ulong fsblkcnt_t; alias ulong fsfilcnt_t; alias c_long clock_t; alias long id_t; alias c_long key_t; alias c_long suseconds_t; alias uint useconds_t; } else version (Solaris) { static if (__USE_FILE_OFFSET64) { alias ulong fsblkcnt_t; alias ulong fsfilcnt_t; } else { alias c_ulong fsblkcnt_t; alias c_ulong fsfilcnt_t; } alias c_long clock_t; alias int id_t; alias int key_t; alias c_long suseconds_t; alias uint useconds_t; alias id_t taskid_t; alias id_t projid_t; alias id_t poolid_t; alias id_t zoneid_t; alias id_t ctid_t; } else version( CRuntime_Bionic ) { alias c_ulong fsblkcnt_t; alias c_ulong fsfilcnt_t; alias c_long clock_t; alias uint id_t; alias int key_t; alias c_long suseconds_t; alias c_long useconds_t; } else { static assert(false, "Unsupported platform"); } // // Thread (THR) // /* pthread_attr_t pthread_cond_t pthread_condattr_t pthread_key_t pthread_mutex_t pthread_mutexattr_t pthread_once_t pthread_rwlock_t pthread_rwlockattr_t pthread_t */ version (CRuntime_Glibc) { version (X86) { enum __SIZEOF_PTHREAD_ATTR_T = 36; enum __SIZEOF_PTHREAD_MUTEX_T = 24; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 32; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 20; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else version (X86_64) { static if (__WORDSIZE == 64) { enum __SIZEOF_PTHREAD_ATTR_T = 56; enum __SIZEOF_PTHREAD_MUTEX_T = 40; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 56; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 32; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else { enum __SIZEOF_PTHREAD_ATTR_T = 32; enum __SIZEOF_PTHREAD_MUTEX_T = 32; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 44; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 20; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } } else version (AArch64) { enum __SIZEOF_PTHREAD_ATTR_T = 64; enum __SIZEOF_PTHREAD_MUTEX_T = 48; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 8; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 8; enum __SIZEOF_PTHREAD_RWLOCK_T = 56; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 32; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 8; } else version (ARM) { enum __SIZEOF_PTHREAD_ATTR_T = 36; enum __SIZEOF_PTHREAD_MUTEX_T = 24; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 32; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 20; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else version (IA64) { enum __SIZEOF_PTHREAD_ATTR_T = 56; enum __SIZEOF_PTHREAD_MUTEX_T = 40; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 56; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 32; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else version (MIPS32) { enum __SIZEOF_PTHREAD_ATTR_T = 36; enum __SIZEOF_PTHREAD_MUTEX_T = 24; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 32; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 20; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else version (MIPS64) { enum __SIZEOF_PTHREAD_ATTR_T = 56; enum __SIZEOF_PTHREAD_MUTEX_T = 40; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 56; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 32; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else version (PPC) { enum __SIZEOF_PTHREAD_ATTR_T = 36; enum __SIZEOF_PTHREAD_MUTEX_T = 24; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 32; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 20; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else version (PPC64) { enum __SIZEOF_PTHREAD_ATTR_T = 56; enum __SIZEOF_PTHREAD_MUTEX_T = 40; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 56; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 32; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else version (S390) { enum __SIZEOF_PTHREAD_ATTR_T = 36; enum __SIZEOF_PTHREAD_MUTEX_T = 24; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 32; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 20; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else version (SystemZ) { enum __SIZEOF_PTHREAD_ATTR_T = 56; enum __SIZEOF_PTHREAD_MUTEX_T = 40; enum __SIZEOF_PTHREAD_MUTEXATTR_T = 4; enum __SIZEOF_PTHREAD_COND_T = 48; enum __SIZEOF_PTHREAD_CONDATTR_T = 4; enum __SIZEOF_PTHREAD_RWLOCK_T = 56; enum __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; enum __SIZEOF_PTHREAD_BARRIER_T = 32; enum __SIZEOF_PTHREAD_BARRIERATTR_T = 4; } else { static assert (false, "Unsupported platform"); } union pthread_attr_t { byte[__SIZEOF_PTHREAD_ATTR_T] __size; c_long __align; } private alias int __atomic_lock_t; private struct _pthread_fastlock { c_long __status; __atomic_lock_t __spinlock; } private alias void* _pthread_descr; union pthread_cond_t { byte[__SIZEOF_PTHREAD_COND_T] __size; long __align; } union pthread_condattr_t { byte[__SIZEOF_PTHREAD_CONDATTR_T] __size; int __align; } alias uint pthread_key_t; union pthread_mutex_t { byte[__SIZEOF_PTHREAD_MUTEX_T] __size; c_long __align; } union pthread_mutexattr_t { byte[__SIZEOF_PTHREAD_MUTEXATTR_T] __size; int __align; } alias int pthread_once_t; struct pthread_rwlock_t { byte[__SIZEOF_PTHREAD_RWLOCK_T] __size; c_long __align; } struct pthread_rwlockattr_t { byte[__SIZEOF_PTHREAD_RWLOCKATTR_T] __size; c_long __align; } alias c_ulong pthread_t; } else version( OSX ) { version( D_LP64 ) { enum __PTHREAD_SIZE__ = 1168; enum __PTHREAD_ATTR_SIZE__ = 56; enum __PTHREAD_MUTEXATTR_SIZE__ = 8; enum __PTHREAD_MUTEX_SIZE__ = 56; enum __PTHREAD_CONDATTR_SIZE__ = 8; enum __PTHREAD_COND_SIZE__ = 40; enum __PTHREAD_ONCE_SIZE__ = 8; enum __PTHREAD_RWLOCK_SIZE__ = 192; enum __PTHREAD_RWLOCKATTR_SIZE__ = 16; } else { enum __PTHREAD_SIZE__ = 596; enum __PTHREAD_ATTR_SIZE__ = 36; enum __PTHREAD_MUTEXATTR_SIZE__ = 8; enum __PTHREAD_MUTEX_SIZE__ = 40; enum __PTHREAD_CONDATTR_SIZE__ = 4; enum __PTHREAD_COND_SIZE__ = 24; enum __PTHREAD_ONCE_SIZE__ = 4; enum __PTHREAD_RWLOCK_SIZE__ = 124; enum __PTHREAD_RWLOCKATTR_SIZE__ = 12; } struct pthread_handler_rec { void function(void*) __routine; void* __arg; pthread_handler_rec* __next; } struct pthread_attr_t { c_long __sig; byte[__PTHREAD_ATTR_SIZE__] __opaque; } struct pthread_cond_t { c_long __sig; byte[__PTHREAD_COND_SIZE__] __opaque; } struct pthread_condattr_t { c_long __sig; byte[__PTHREAD_CONDATTR_SIZE__] __opaque; } alias c_ulong pthread_key_t; struct pthread_mutex_t { c_long __sig; byte[__PTHREAD_MUTEX_SIZE__] __opaque; } struct pthread_mutexattr_t { c_long __sig; byte[__PTHREAD_MUTEXATTR_SIZE__] __opaque; } struct pthread_once_t { c_long __sig; byte[__PTHREAD_ONCE_SIZE__] __opaque; } struct pthread_rwlock_t { c_long __sig; byte[__PTHREAD_RWLOCK_SIZE__] __opaque; } struct pthread_rwlockattr_t { c_long __sig; byte[__PTHREAD_RWLOCKATTR_SIZE__] __opaque; } private struct _opaque_pthread_t { c_long __sig; pthread_handler_rec* __cleanup_stack; byte[__PTHREAD_SIZE__] __opaque; } alias _opaque_pthread_t* pthread_t; } else version( FreeBSD ) { alias int lwpid_t; alias void* pthread_attr_t; alias void* pthread_cond_t; alias void* pthread_condattr_t; alias void* pthread_key_t; alias void* pthread_mutex_t; alias void* pthread_mutexattr_t; alias void* pthread_once_t; alias void* pthread_rwlock_t; alias void* pthread_rwlockattr_t; alias void* pthread_t; } else version (Solaris) { alias uint pthread_t; struct pthread_attr_t { void* __pthread_attrp; } struct pthread_cond_t { struct ___pthread_cond_flags { ubyte[4] __pthread_cond_flags; ushort __pthread_cond_type; ushort __pthread_cond_magic; } ___pthread_cond_flags __pthread_cond_flags; ulong __pthread_cond_data; } struct pthread_condattr_t { void* __pthread_condattrp; } struct pthread_rwlock_t { int __pthread_rwlock_readers; ushort __pthread_rwlock_type; ushort __pthread_rwlock_magic; pthread_mutex_t __pthread_rwlock_mutex; pthread_cond_t __pthread_rwlock_readercv; pthread_cond_t __pthread_rwlock_writercv; } struct pthread_rwlockattr_t { void* __pthread_rwlockattrp; } struct pthread_mutex_t { struct ___pthread_mutex_flags { ushort __pthread_mutex_flag1; ubyte __pthread_mutex_flag2; ubyte __pthread_mutex_ceiling; ushort __pthread_mutex_type; ushort __pthread_mutex_magic; } ___pthread_mutex_flags __pthread_mutex_flags; union ___pthread_mutex_lock { struct ___pthread_mutex_lock64 { ubyte[8] __pthread_mutex_pad; } ___pthread_mutex_lock64 __pthread_mutex_lock64; struct ___pthread_mutex_lock32 { uint __pthread_ownerpid; uint __pthread_lockword; } ___pthread_mutex_lock32 __pthread_mutex_lock32; ulong __pthread_mutex_owner64; } ___pthread_mutex_lock __pthread_mutex_lock; ulong __pthread_mutex_data; } struct pthread_mutexattr_t { void* __pthread_mutexattrp; } struct pthread_once_t { ulong[4] __pthread_once_pad; } alias uint pthread_key_t; } else version( CRuntime_Bionic ) { struct pthread_attr_t { uint flags; void* stack_base; size_t stack_size; size_t guard_size; int sched_policy; int sched_priority; } struct pthread_cond_t { int value; //volatile } alias c_long pthread_condattr_t; alias int pthread_key_t; struct pthread_mutex_t { int value; //volatile } alias c_long pthread_mutexattr_t; alias int pthread_once_t; //volatile struct pthread_rwlock_t { pthread_mutex_t lock; pthread_cond_t cond; int numLocks; int writerThreadId; int pendingReaders; int pendingWriters; void*[4] reserved; } alias int pthread_rwlockattr_t; alias c_long pthread_t; } else { static assert(false, "Unsupported platform"); } // // Barrier (BAR) // /* pthread_barrier_t pthread_barrierattr_t */ version( CRuntime_Glibc ) { struct pthread_barrier_t { byte[__SIZEOF_PTHREAD_BARRIER_T] __size; c_long __align; } struct pthread_barrierattr_t { byte[__SIZEOF_PTHREAD_BARRIERATTR_T] __size; int __align; } } else version( FreeBSD ) { alias void* pthread_barrier_t; alias void* pthread_barrierattr_t; } else version( OSX ) { } else version (Solaris) { struct pthread_barrier_t { uint __pthread_barrier_count; uint __pthread_barrier_current; ulong __pthread_barrier_cycle; ulong __pthread_barrier_reserved; pthread_mutex_t __pthread_barrier_lock; pthread_cond_t __pthread_barrier_cond; } struct pthread_barrierattr_t { void* __pthread_barrierattrp; } } else version( CRuntime_Bionic ) { } else { static assert(false, "Unsupported platform"); } // // Spin (SPN) // /* pthread_spinlock_t */ version( CRuntime_Glibc ) { alias int pthread_spinlock_t; // volatile } else version( FreeBSD ) { alias void* pthread_spinlock_t; } else version (Solaris) { alias pthread_mutex_t pthread_spinlock_t; } // // Timer (TMR) // /* clockid_t timer_t */ // // Trace (TRC) // /* trace_attr_t trace_event_id_t trace_event_set_t trace_id_t */ ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/ipc.d0000664000175000017500000000617212776214756022726 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.ipc; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for uid_t, gid_t, mode_t, key_t version (Posix): extern (C) nothrow @nogc: // // XOpen (XSI) // /* struct ipc_perm { uid_t uid; gid_t gid; uid_t cuid; gid_t cgid; mode_t mode; } IPC_CREAT IPC_EXCL IPC_NOWAIT IPC_PRIVATE IPC_RMID IPC_SET IPC_STAT key_t ftok(in char*, int); */ version( CRuntime_Glibc ) { struct ipc_perm { key_t __key; uid_t uid; gid_t gid; uid_t cuid; gid_t cgid; ushort mode; ushort __pad1; ushort __seq; ushort __pad2; c_ulong __unused1; c_ulong __unused2; } enum IPC_CREAT = 0x0200; // 01000 enum IPC_EXCL = 0x0400; // 02000 enum IPC_NOWAIT = 0x0800; // 04000 enum key_t IPC_PRIVATE = 0; enum IPC_RMID = 0; enum IPC_SET = 1; enum IPC_STAT = 2; key_t ftok(in char*, int); } else version( OSX ) { } else version( FreeBSD ) { struct ipc_perm_old // <= FreeBSD7 { ushort cuid; ushort cguid; ushort uid; ushort gid; ushort mode; ushort seq; key_t key; } struct ipc_perm { uid_t cuid; gid_t cgid; uid_t uid; gid_t gid; mode_t mode; ushort seq; key_t key; } enum IPC_CREAT = 0x0200; // 01000 enum IPC_EXCL = 0x0400; // 02000 enum IPC_NOWAIT = 0x0800; // 04000 enum key_t IPC_PRIVATE = 0; enum IPC_RMID = 0; enum IPC_SET = 1; enum IPC_STAT = 2; key_t ftok(in char*, int); } else version( CRuntime_Bionic ) { // All except ftok are from the linux kernel headers. version (X86) { struct ipc_perm { key_t key; ushort uid; ushort gid; ushort cuid; ushort cgid; mode_t mode; ushort seq; } } else version (ARM) { struct ipc_perm { key_t key; ushort uid; ushort gid; ushort cuid; ushort cgid; mode_t mode; ushort seq; } } else { static assert(false, "Architecture not supported."); } enum IPC_CREAT = 0x0200; // 01000 enum IPC_EXCL = 0x0400; // 02000 enum IPC_NOWAIT = 0x0800; // 04000 enum key_t IPC_PRIVATE = 0; enum IPC_RMID = 0; enum IPC_SET = 1; enum IPC_STAT = 2; key_t ftok(in char*, int); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/socket.d0000664000175000017500000007626212776214756023452 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.socket; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for ssize_t public import core.sys.posix.sys.uio; // for iovec version (Posix): extern (C) nothrow @nogc: // // Required // /* socklen_t sa_family_t struct sockaddr { sa_family_t sa_family; char sa_data[]; } struct sockaddr_storage { sa_family_t ss_family; } struct msghdr { void* msg_name; socklen_t msg_namelen; struct iovec* msg_iov; int msg_iovlen; void* msg_control; socklen_t msg_controllen; int msg_flags; } struct iovec {} // from core.sys.posix.sys.uio struct cmsghdr { socklen_t cmsg_len; int cmsg_level; int cmsg_type; } SCM_RIGHTS CMSG_DATA(cmsg) CMSG_NXTHDR(mhdr,cmsg) CMSG_FIRSTHDR(mhdr) struct linger { int l_onoff; int l_linger; } SOCK_DGRAM SOCK_SEQPACKET SOCK_STREAM SOL_SOCKET SO_ACCEPTCONN SO_BROADCAST SO_DEBUG SO_DONTROUTE SO_ERROR SO_KEEPALIVE SO_LINGER SO_OOBINLINE SO_RCVBUF SO_RCVLOWAT SO_RCVTIMEO SO_REUSEADDR SO_SNDBUF SO_SNDLOWAT SO_SNDTIMEO SO_TYPE SOMAXCONN MSG_CTRUNC MSG_DONTROUTE MSG_EOR MSG_OOB MSG_PEEK MSG_TRUNC MSG_WAITALL AF_INET AF_UNIX AF_UNSPEC SHUT_RD SHUT_RDWR SHUT_WR int accept(int, sockaddr*, socklen_t*); int bind(int, in sockaddr*, socklen_t); int connect(int, in sockaddr*, socklen_t); int getpeername(int, sockaddr*, socklen_t*); int getsockname(int, sockaddr*, socklen_t*); int getsockopt(int, int, int, void*, socklen_t*); int listen(int, int); ssize_t recv(int, void*, size_t, int); ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*); ssize_t recvmsg(int, msghdr*, int); ssize_t send(int, in void*, size_t, int); ssize_t sendmsg(int, in msghdr*, int); ssize_t sendto(int, in void*, size_t, int, in sockaddr*, socklen_t); int setsockopt(int, int, int, in void*, socklen_t); int shutdown(int, int); int socket(int, int, int); int sockatmark(int); int socketpair(int, int, int, ref int[2]); */ version( CRuntime_Glibc ) { // Some of the constants below and from the Bionic section are really from // the linux kernel headers. alias uint socklen_t; alias ushort sa_family_t; struct sockaddr { sa_family_t sa_family; byte[14] sa_data; } private enum : size_t { _SS_SIZE = 128, _SS_PADSIZE = _SS_SIZE - (c_ulong.sizeof * 2) } struct sockaddr_storage { sa_family_t ss_family; c_ulong __ss_align; byte[_SS_PADSIZE] __ss_padding; } struct msghdr { void* msg_name; socklen_t msg_namelen; iovec* msg_iov; size_t msg_iovlen; void* msg_control; size_t msg_controllen; int msg_flags; } struct cmsghdr { size_t cmsg_len; int cmsg_level; int cmsg_type; static if( false /* (!is( __STRICT_ANSI__ ) && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L */ ) { ubyte[1] __cmsg_data; } } enum : uint { SCM_RIGHTS = 0x01 } static if( false /* (!is( __STRICT_ANSI__ ) && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L */ ) { extern (D) ubyte[1] CMSG_DATA( cmsghdr* cmsg ) pure nothrow @nogc { return cmsg.__cmsg_data; } } else { extern (D) inout(ubyte)* CMSG_DATA( inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); } } private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc; extern (D) inout(cmsghdr)* CMSG_NXTHDR(inout(msghdr)* msg, inout(cmsghdr)* cmsg) pure nothrow @nogc { return __cmsg_nxthdr(msg, cmsg); } extern (D) inout(cmsghdr)* CMSG_FIRSTHDR( inout(msghdr)* mhdr ) pure nothrow @nogc { return ( cast(size_t)mhdr.msg_controllen >= cmsghdr.sizeof ? cast(inout(cmsghdr)*) mhdr.msg_control : cast(inout(cmsghdr)*) null ); } extern (D) { size_t CMSG_ALIGN( size_t len ) pure nothrow @nogc { return (len + size_t.sizeof - 1) & cast(size_t) (~(size_t.sizeof - 1)); } size_t CMSG_LEN( size_t len ) pure nothrow @nogc { return CMSG_ALIGN(cmsghdr.sizeof) + len; } } extern (D) size_t CMSG_SPACE(size_t len) pure nothrow @nogc { return CMSG_ALIGN(len) + CMSG_ALIGN(cmsghdr.sizeof); } struct linger { int l_onoff; int l_linger; } version (X86) { enum { SOCK_DGRAM = 2, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum { SOL_SOCKET = 1 } enum { SO_ACCEPTCONN = 30, SO_BROADCAST = 6, SO_DEBUG = 1, SO_DONTROUTE = 5, SO_ERROR = 4, SO_KEEPALIVE = 9, SO_LINGER = 13, SO_OOBINLINE = 10, SO_RCVBUF = 8, SO_RCVLOWAT = 18, SO_RCVTIMEO = 20, SO_REUSEADDR = 2, SO_SNDBUF = 7, SO_SNDLOWAT = 19, SO_SNDTIMEO = 21, SO_TYPE = 3 } } else version (X86_64) { enum { SOCK_DGRAM = 2, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum { SOL_SOCKET = 1 } enum { SO_ACCEPTCONN = 30, SO_BROADCAST = 6, SO_DEBUG = 1, SO_DONTROUTE = 5, SO_ERROR = 4, SO_KEEPALIVE = 9, SO_LINGER = 13, SO_OOBINLINE = 10, SO_RCVBUF = 8, SO_RCVLOWAT = 18, SO_RCVTIMEO = 20, SO_REUSEADDR = 2, SO_SNDBUF = 7, SO_SNDLOWAT = 19, SO_SNDTIMEO = 21, SO_TYPE = 3 } } else version (MIPS32) { enum { SOCK_DGRAM = 1, SOCK_SEQPACKET = 5, SOCK_STREAM = 2, } enum { SOL_SOCKET = 0xffff } enum { SO_ACCEPTCONN = 0x1009, SO_BROADCAST = 0x0020, SO_DEBUG = 0x0001, SO_DONTROUTE = 0x0010, SO_ERROR = 0x1007, SO_KEEPALIVE = 0x0008, SO_LINGER = 0x0080, SO_OOBINLINE = 0x0100, SO_RCVBUF = 0x1002, SO_RCVLOWAT = 0x1004, SO_RCVTIMEO = 0x1006, SO_REUSEADDR = 0x0004, SO_SNDBUF = 0x1001, SO_SNDLOWAT = 0x1003, SO_SNDTIMEO = 0x1005, SO_TYPE = 0x1008, } } else version (MIPS64) { enum { SOCK_DGRAM = 1, SOCK_SEQPACKET = 5, SOCK_STREAM = 2, } enum { SOL_SOCKET = 0xffff } enum { SO_ACCEPTCONN = 0x1009, SO_BROADCAST = 0x0020, SO_DEBUG = 0x0001, SO_DONTROUTE = 0x0010, SO_ERROR = 0x1007, SO_KEEPALIVE = 0x0008, SO_LINGER = 0x0080, SO_OOBINLINE = 0x0100, SO_RCVBUF = 0x1002, SO_RCVLOWAT = 0x1004, SO_RCVTIMEO = 0x1006, SO_REUSEADDR = 0x0004, SO_SNDBUF = 0x1001, SO_SNDLOWAT = 0x1003, SO_SNDTIMEO = 0x1005, SO_TYPE = 0x1008, } } else version (PPC) { enum { SOCK_DGRAM = 2, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum { SOL_SOCKET = 1 } enum { SO_ACCEPTCONN = 30, SO_BROADCAST = 6, SO_DEBUG = 1, SO_DONTROUTE = 5, SO_ERROR = 4, SO_KEEPALIVE = 9, SO_LINGER = 13, SO_OOBINLINE = 10, SO_RCVBUF = 8, SO_RCVLOWAT = 16, SO_RCVTIMEO = 18, SO_REUSEADDR = 2, SO_SNDBUF = 7, SO_SNDLOWAT = 17, SO_SNDTIMEO = 19, SO_TYPE = 3 } } else version (PPC64) { enum { SOCK_DGRAM = 2, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum { SOL_SOCKET = 1 } enum { SO_ACCEPTCONN = 30, SO_BROADCAST = 6, SO_DEBUG = 1, SO_DONTROUTE = 5, SO_ERROR = 4, SO_KEEPALIVE = 9, SO_LINGER = 13, SO_OOBINLINE = 10, SO_RCVBUF = 8, SO_RCVLOWAT = 16, SO_RCVTIMEO = 18, SO_REUSEADDR = 2, SO_SNDBUF = 7, SO_SNDLOWAT = 17, SO_SNDTIMEO = 19, SO_TYPE = 3 } } else version (AArch64) { enum { SOCK_DGRAM = 2, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum { SOL_SOCKET = 1 } enum { SO_ACCEPTCONN = 30, SO_BROADCAST = 6, SO_DEBUG = 1, SO_DONTROUTE = 5, SO_ERROR = 4, SO_KEEPALIVE = 9, SO_LINGER = 13, SO_OOBINLINE = 10, SO_RCVBUF = 8, SO_RCVLOWAT = 18, SO_RCVTIMEO = 20, SO_REUSEADDR = 2, SO_SNDBUF = 7, SO_SNDLOWAT = 19, SO_SNDTIMEO = 21, SO_TYPE = 3 } } else version (ARM) { enum { SOCK_DGRAM = 2, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum { SOL_SOCKET = 1 } enum { SO_ACCEPTCONN = 30, SO_BROADCAST = 6, SO_DEBUG = 1, SO_DONTROUTE = 5, SO_ERROR = 4, SO_KEEPALIVE = 9, SO_LINGER = 13, SO_OOBINLINE = 10, SO_RCVBUF = 8, SO_RCVLOWAT = 18, SO_RCVTIMEO = 20, SO_REUSEADDR = 2, SO_SNDBUF = 7, SO_SNDLOWAT = 19, SO_SNDTIMEO = 21, SO_TYPE = 3 } } else version (SystemZ) { enum { SOCK_DGRAM = 2, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum { SOL_SOCKET = 1 } enum { SO_ACCEPTCONN = 30, SO_BROADCAST = 6, SO_DEBUG = 1, SO_DONTROUTE = 5, SO_ERROR = 4, SO_KEEPALIVE = 9, SO_LINGER = 13, SO_OOBINLINE = 10, SO_RCVBUF = 8, SO_RCVLOWAT = 18, SO_RCVTIMEO = 20, SO_REUSEADDR = 2, SO_SNDBUF = 7, SO_SNDLOWAT = 19, SO_SNDTIMEO = 21, SO_TYPE = 3 } } else static assert(0, "unimplemented"); enum { SOMAXCONN = 128 } enum : uint { MSG_CTRUNC = 0x08, MSG_DONTROUTE = 0x04, MSG_EOR = 0x80, MSG_OOB = 0x01, MSG_PEEK = 0x02, MSG_TRUNC = 0x20, MSG_WAITALL = 0x100, MSG_NOSIGNAL = 0x4000 } enum { AF_APPLETALK = 5, AF_INET = 2, AF_IPX = 4, AF_UNIX = 1, AF_UNSPEC = 0, PF_APPLETALK = AF_APPLETALK, PF_IPX = AF_IPX } enum int SOCK_RDM = 4; enum { SHUT_RD, SHUT_WR, SHUT_RDWR } int accept(int, sockaddr*, socklen_t*); int bind(int, in sockaddr*, socklen_t); int connect(int, in sockaddr*, socklen_t); int getpeername(int, sockaddr*, socklen_t*); int getsockname(int, sockaddr*, socklen_t*); int getsockopt(int, int, int, void*, socklen_t*); int listen(int, int); ssize_t recv(int, void*, size_t, int); ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*); ssize_t recvmsg(int, msghdr*, int); ssize_t send(int, in void*, size_t, int); ssize_t sendmsg(int, in msghdr*, int); ssize_t sendto(int, in void*, size_t, int, in sockaddr*, socklen_t); int setsockopt(int, int, int, in void*, socklen_t); int shutdown(int, int); int socket(int, int, int); int sockatmark(int); int socketpair(int, int, int, ref int[2]); } else version( OSX ) { alias uint socklen_t; alias ubyte sa_family_t; struct sockaddr { ubyte sa_len; sa_family_t sa_family; byte[14] sa_data; } private enum : size_t { _SS_PAD1 = long.sizeof - ubyte.sizeof - sa_family_t.sizeof, _SS_PAD2 = 128 - ubyte.sizeof - sa_family_t.sizeof - _SS_PAD1 - long.sizeof } struct sockaddr_storage { ubyte ss_len; sa_family_t ss_family; byte[_SS_PAD1] __ss_pad1; long __ss_align; byte[_SS_PAD2] __ss_pad2; } struct msghdr { void* msg_name; socklen_t msg_namelen; iovec* msg_iov; int msg_iovlen; void* msg_control; socklen_t msg_controllen; int msg_flags; } struct cmsghdr { socklen_t cmsg_len; int cmsg_level; int cmsg_type; } enum : uint { SCM_RIGHTS = 0x01 } /+ CMSG_DATA(cmsg) ((unsigned char *)(cmsg) + \ ALIGN(sizeof(struct cmsghdr))) CMSG_NXTHDR(mhdr, cmsg) \ (((unsigned char *)(cmsg) + ALIGN((cmsg)->cmsg_len) + \ ALIGN(sizeof(struct cmsghdr)) > \ (unsigned char *)(mhdr)->msg_control +(mhdr)->msg_controllen) ? \ (struct cmsghdr *)0 /* NULL */ : \ (struct cmsghdr *)((unsigned char *)(cmsg) + ALIGN((cmsg)->cmsg_len))) CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control) +/ struct linger { int l_onoff; int l_linger; } enum { SOCK_DGRAM = 2, SOCK_RDM = 4, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum : uint { SOL_SOCKET = 0xffff } enum : uint { SO_ACCEPTCONN = 0x0002, SO_BROADCAST = 0x0020, SO_DEBUG = 0x0001, SO_DONTROUTE = 0x0010, SO_ERROR = 0x1007, SO_KEEPALIVE = 0x0008, SO_LINGER = 0x1080, SO_NOSIGPIPE = 0x1022, // non-standard SO_OOBINLINE = 0x0100, SO_RCVBUF = 0x1002, SO_RCVLOWAT = 0x1004, SO_RCVTIMEO = 0x1006, SO_REUSEADDR = 0x0004, SO_SNDBUF = 0x1001, SO_SNDLOWAT = 0x1003, SO_SNDTIMEO = 0x1005, SO_TYPE = 0x1008 } enum { SOMAXCONN = 128 } enum : uint { MSG_CTRUNC = 0x20, MSG_DONTROUTE = 0x4, MSG_EOR = 0x8, MSG_OOB = 0x1, MSG_PEEK = 0x2, MSG_TRUNC = 0x10, MSG_WAITALL = 0x40 } enum { AF_APPLETALK = 16, AF_INET = 2, AF_IPX = 23, AF_UNIX = 1, AF_UNSPEC = 0, PF_APPLETALK = AF_APPLETALK, PF_IPX = AF_IPX } enum { SHUT_RD, SHUT_WR, SHUT_RDWR } int accept(int, sockaddr*, socklen_t*); int bind(int, in sockaddr*, socklen_t); int connect(int, in sockaddr*, socklen_t); int getpeername(int, sockaddr*, socklen_t*); int getsockname(int, sockaddr*, socklen_t*); int getsockopt(int, int, int, void*, socklen_t*); int listen(int, int); ssize_t recv(int, void*, size_t, int); ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*); ssize_t recvmsg(int, msghdr*, int); ssize_t send(int, in void*, size_t, int); ssize_t sendmsg(int, in msghdr*, int); ssize_t sendto(int, in void*, size_t, int, in sockaddr*, socklen_t); int setsockopt(int, int, int, in void*, socklen_t); int shutdown(int, int); int socket(int, int, int); int sockatmark(int); int socketpair(int, int, int, ref int[2]); } else version( FreeBSD ) { alias uint socklen_t; alias ubyte sa_family_t; struct sockaddr { ubyte sa_len; sa_family_t sa_family; byte[14] sa_data; } private { enum _SS_ALIGNSIZE = long.sizeof; enum _SS_MAXSIZE = 128; enum _SS_PAD1SIZE = _SS_ALIGNSIZE - ubyte.sizeof - sa_family_t.sizeof; enum _SS_PAD2SIZE = _SS_MAXSIZE - ubyte.sizeof - sa_family_t.sizeof - _SS_PAD1SIZE - _SS_ALIGNSIZE; } struct sockaddr_storage { ubyte ss_len; sa_family_t ss_family; byte[_SS_PAD1SIZE] __ss_pad1; long __ss_align; byte[_SS_PAD2SIZE] __ss_pad2; } struct msghdr { void* msg_name; socklen_t msg_namelen; iovec* msg_iov; int msg_iovlen; void* msg_control; socklen_t msg_controllen; int msg_flags; } struct cmsghdr { socklen_t cmsg_len; int cmsg_level; int cmsg_type; } enum : uint { SCM_RIGHTS = 0x01 } private // { enum _ALIGNBYTES = /+c_int+/ int.sizeof - 1; extern (D) size_t _ALIGN( size_t p ) { return (p + _ALIGNBYTES) & ~_ALIGNBYTES; } } extern (D) ubyte* CMSG_DATA( cmsghdr* cmsg ) { return cast(ubyte*) cmsg + _ALIGN( cmsghdr.sizeof ); } extern (D) cmsghdr* CMSG_NXTHDR( msghdr* mhdr, cmsghdr* cmsg ) { if( cmsg == null ) { return CMSG_FIRSTHDR( mhdr ); } else { if( cast(ubyte*) cmsg + _ALIGN( cmsg.cmsg_len ) + _ALIGN( cmsghdr.sizeof ) > cast(ubyte*) mhdr.msg_control + mhdr.msg_controllen ) return null; else return cast(cmsghdr*) (cast(ubyte*) cmsg + _ALIGN( cmsg.cmsg_len )); } } extern (D) cmsghdr* CMSG_FIRSTHDR( msghdr* mhdr ) { return mhdr.msg_controllen >= cmsghdr.sizeof ? cast(cmsghdr*) mhdr.msg_control : null; } struct linger { int l_onoff; int l_linger; } enum { SOCK_DGRAM = 2, SOCK_RDM = 4, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum : uint { SOL_SOCKET = 0xffff } enum : uint { SO_ACCEPTCONN = 0x0002, SO_BROADCAST = 0x0020, SO_DEBUG = 0x0001, SO_DONTROUTE = 0x0010, SO_ERROR = 0x1007, SO_KEEPALIVE = 0x0008, SO_LINGER = 0x0080, SO_NOSIGPIPE = 0x0800, // non-standard SO_OOBINLINE = 0x0100, SO_RCVBUF = 0x1002, SO_RCVLOWAT = 0x1004, SO_RCVTIMEO = 0x1006, SO_REUSEADDR = 0x0004, SO_SNDBUF = 0x1001, SO_SNDLOWAT = 0x1003, SO_SNDTIMEO = 0x1005, SO_TYPE = 0x1008 } enum { SOMAXCONN = 128 } enum : uint { MSG_CTRUNC = 0x20, MSG_DONTROUTE = 0x4, MSG_EOR = 0x8, MSG_OOB = 0x1, MSG_PEEK = 0x2, MSG_TRUNC = 0x10, MSG_WAITALL = 0x40, MSG_NOSIGNAL = 0x20000 } enum { AF_APPLETALK = 16, AF_INET = 2, AF_IPX = 23, AF_UNIX = 1, AF_UNSPEC = 0 } enum { SHUT_RD = 0, SHUT_WR = 1, SHUT_RDWR = 2 } int accept(int, sockaddr*, socklen_t*); int bind(int, in sockaddr*, socklen_t); int connect(int, in sockaddr*, socklen_t); int getpeername(int, sockaddr*, socklen_t*); int getsockname(int, sockaddr*, socklen_t*); int getsockopt(int, int, int, void*, socklen_t*); int listen(int, int); ssize_t recv(int, void*, size_t, int); ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*); ssize_t recvmsg(int, msghdr*, int); ssize_t send(int, in void*, size_t, int); ssize_t sendmsg(int, in msghdr*, int); ssize_t sendto(int, in void*, size_t, int, in sockaddr*, socklen_t); int setsockopt(int, int, int, in void*, socklen_t); int shutdown(int, int); int socket(int, int, int); int sockatmark(int); int socketpair(int, int, int, ref int[2]); } else version (Solaris) { alias uint socklen_t; alias ushort sa_family_t; struct sockaddr { sa_family_t sa_family; char[14] sa_data; } alias double sockaddr_maxalign_t; private { enum _SS_ALIGNSIZE = sockaddr_maxalign_t.sizeof; enum _SS_MAXSIZE = 256; enum _SS_PAD1SIZE = _SS_ALIGNSIZE - sa_family_t.sizeof; enum _SS_PAD2SIZE = _SS_MAXSIZE - sa_family_t.sizeof + _SS_PAD1SIZE + _SS_ALIGNSIZE; } struct sockaddr_storage { sa_family_t ss_family; char[_SS_PAD1SIZE] _ss_pad1; sockaddr_maxalign_t _ss_align; char[_SS_PAD2SIZE] _ss_pad2; } struct msghdr { void* msg_name; socklen_t msg_namelen; iovec* msg_iov; int msg_iovlen; void* msg_control; socklen_t msg_controllen; int msg_flags; } struct cmsghdr { socklen_t cmsg_len; int cmsg_level; int cmsg_type; } enum : uint { SCM_RIGHTS = 0x1010 } // FIXME: CMSG_DATA, CMSG_NXTHDR, CMSG_FIRSTHDR missing struct linger { int l_onoff; int l_linger; } enum { SOCK_STREAM = 2, SOCK_DGRAM = 1, SOCK_RDM = 5, SOCK_SEQPACKET = 6, } enum : uint { SOL_SOCKET = 0xffff } enum : uint { SO_ACCEPTCONN = 0x0002, SO_BROADCAST = 0x0020, SO_DEBUG = 0x0001, SO_DONTROUTE = 0x0010, SO_ERROR = 0x1007, SO_KEEPALIVE = 0x0008, SO_LINGER = 0x0080, SO_OOBINLINE = 0x0100, SO_RCVBUF = 0x1002, SO_RCVLOWAT = 0x1004, SO_RCVTIMEO = 0x1006, SO_REUSEADDR = 0x0004, SO_SNDBUF = 0x1001, SO_SNDLOWAT = 0x1003, SO_SNDTIMEO = 0x1005, SO_TYPE = 0x1008, SO_USELOOPBACK = 0x0040, // non-standard SO_DGRAM_ERRIND = 0x0200, // non-standard SO_RECVUCRED = 0x0400, // non-standard } enum { SOMAXCONN = 128 } enum : uint { MSG_CTRUNC = 0x10, MSG_DONTROUTE = 0x4, MSG_EOR = 0x8, MSG_OOB = 0x1, MSG_PEEK = 0x2, MSG_TRUNC = 0x20, MSG_WAITALL = 0x40 } enum { AF_IPX = 23, AF_APPLETALK = 16, AF_INET = 2, AF_UNIX = 1, AF_UNSPEC = 0 } enum { SHUT_RD, SHUT_WR, SHUT_RDWR } int accept(int, sockaddr*, socklen_t*); int bind(int, in sockaddr*, socklen_t); int connect(int, in sockaddr*, socklen_t); int getpeername(int, sockaddr*, socklen_t*); int getsockname(int, sockaddr*, socklen_t*); int getsockopt(int, int, int, void*, socklen_t*); int listen(int, int); ssize_t recv(int, void*, size_t, int); ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*); ssize_t recvmsg(int, msghdr*, int); ssize_t send(int, in void*, size_t, int); ssize_t sendmsg(int, in msghdr*, int); ssize_t sendto(int, in void*, size_t, int, in sockaddr*, socklen_t); int setsockopt(int, int, int, in void*, socklen_t); int shutdown(int, int); int socket(int, int, int); int sockatmark(int); int socketpair(int, int, int, ref int[2]); } else version( CRuntime_Bionic ) { alias int socklen_t; alias ushort sa_family_t; struct sockaddr { sa_family_t sa_family; byte[14] sa_data; } private enum size_t _K_SS_MAXSIZE = 128; struct sockaddr_storage { ushort ss_family; byte[_K_SS_MAXSIZE - ushort.sizeof] __data; } enum : uint { SCM_RIGHTS = 0x01 } private enum _ALIGNBYTES = c_long.sizeof - 1; extern (D) { size_t CMSG_ALIGN( size_t len ) { return (len + _ALIGNBYTES) & ~_ALIGNBYTES; } void* CMSG_DATA( cmsghdr* cmsg ) { return cast(void*) (cast(char*) cmsg + CMSG_ALIGN( cmsghdr.sizeof )); } cmsghdr* CMSG_NXTHDR( msghdr* mhdr, cmsghdr* cmsg ) { cmsghdr* __ptr = cast(cmsghdr*) ((cast(ubyte*) cmsg) + CMSG_ALIGN(cmsg.cmsg_len)); return cast(c_ulong)( cast(char*)(__ptr+1) - cast(char*) mhdr.msg_control) > mhdr.msg_controllen ? null : __ptr; } cmsghdr* CMSG_FIRSTHDR( msghdr* mhdr ) { return mhdr.msg_controllen >= cmsghdr.sizeof ? cast(cmsghdr*) mhdr.msg_control : null; } } struct linger { int l_onoff; int l_linger; } struct msghdr { void* msg_name; int msg_namelen; iovec* msg_iov; __kernel_size_t msg_iovlen; void* msg_control; __kernel_size_t msg_controllen; uint msg_flags; } struct cmsghdr { __kernel_size_t cmsg_len; int cmsg_level; int cmsg_type; } version (X86) { alias uint __kernel_size_t; enum { SOCK_DGRAM = 2, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum { SOL_SOCKET = 1 } enum { SO_ACCEPTCONN = 30, SO_BROADCAST = 6, SO_DEBUG = 1, SO_DONTROUTE = 5, SO_ERROR = 4, SO_KEEPALIVE = 9, SO_LINGER = 13, SO_OOBINLINE = 10, SO_RCVBUF = 8, SO_RCVLOWAT = 18, SO_RCVTIMEO = 20, SO_REUSEADDR = 2, SO_SNDBUF = 7, SO_SNDLOWAT = 19, SO_SNDTIMEO = 21, SO_TYPE = 3 } } else version (ARM) { alias uint __kernel_size_t; enum { SOCK_DGRAM = 2, SOCK_SEQPACKET = 5, SOCK_STREAM = 1 } enum { SOL_SOCKET = 1 } enum { SO_ACCEPTCONN = 30, SO_BROADCAST = 6, SO_DEBUG = 1, SO_DONTROUTE = 5, SO_ERROR = 4, SO_KEEPALIVE = 9, SO_LINGER = 13, SO_OOBINLINE = 10, SO_RCVBUF = 8, SO_RCVLOWAT = 18, SO_RCVTIMEO = 20, SO_REUSEADDR = 2, SO_SNDBUF = 7, SO_SNDLOWAT = 19, SO_SNDTIMEO = 21, SO_TYPE = 3 } } else { static assert(false, "Architecture not supported."); } enum { SOMAXCONN = 128 } enum : uint { MSG_CTRUNC = 0x08, MSG_DONTROUTE = 0x04, MSG_EOR = 0x80, MSG_OOB = 0x01, MSG_PEEK = 0x02, MSG_TRUNC = 0x20, MSG_WAITALL = 0x100 } enum { AF_APPLETALK = 5, AF_INET = 2, AF_IPX = 4, AF_UNIX = 1, AF_UNSPEC = 0 } enum { SHUT_RD, SHUT_WR, SHUT_RDWR } enum SOCK_RDM = 4; int accept(int, sockaddr*, socklen_t*); int bind(int, in sockaddr*, int); int connect(int, in sockaddr*, socklen_t); int getpeername(int, sockaddr*, socklen_t*); int getsockname(int, sockaddr*, socklen_t*); int getsockopt(int, int, int, void*, socklen_t*); int listen(int, int); ssize_t recv(int, void*, size_t, uint); ssize_t recvfrom(int, void*, size_t, uint, in sockaddr*, socklen_t*); int recvmsg(int, msghdr*, uint); ssize_t send(int, in void*, size_t, uint); int sendmsg(int, in msghdr*, uint); ssize_t sendto(int, in void*, size_t, int, in sockaddr*, socklen_t); int setsockopt(int, int, int, in void*, socklen_t); int shutdown(int, int); int socket(int, int, int); int socketpair(int, int, int, ref int[2]); } else { static assert(false, "Unsupported platform"); } // // IPV6 (IP6) // /* AF_INET6 */ version( CRuntime_Glibc ) { enum { AF_INET6 = 10 } } else version( OSX ) { enum { AF_INET6 = 30 } } else version( FreeBSD ) { enum { AF_INET6 = 28 } } else version (Solaris) { enum { AF_INET6 = 26, } } else version( CRuntime_Bionic ) { enum { AF_INET6 = 10 } } else { static assert(false, "Unsupported platform"); } // // Raw Sockets (RS) // /* SOCK_RAW */ version( CRuntime_Glibc ) { enum { SOCK_RAW = 3 } } else version( OSX ) { enum { SOCK_RAW = 3 } } else version( FreeBSD ) { enum { SOCK_RAW = 3 } } else version (Solaris) { enum { SOCK_RAW = 4, } } else version( CRuntime_Bionic ) { enum { SOCK_RAW = 3 } } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/select.d0000664000175000017500000002262212776214756023430 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.select; private import core.sys.posix.config; public import core.stdc.time; // for timespec public import core.sys.posix.sys.time; // for timeval public import core.sys.posix.sys.types; // for time_t public import core.sys.posix.signal; // for sigset_t //debug=select; // uncomment to turn on debugging printf's version(unittest) import core.stdc.stdio: printf; version (Posix): extern (C) nothrow @nogc: // // Required // /* NOTE: This module requires timeval from core.sys.posix.sys.time, but timeval is supposedly an XOpen extension. As a result, this header will not compile on platforms that are not XSI-compliant. This must be resolved on a per-platform basis. fd_set void FD_CLR(int fd, fd_set* fdset); int FD_ISSET(int fd, const(fd_set)* fdset); void FD_SET(int fd, fd_set* fdset); void FD_ZERO(fd_set* fdset); FD_SETSIZE int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*); int select(int, fd_set*, fd_set*, fd_set*, timeval*); */ version( CRuntime_Glibc ) { private { alias c_long __fd_mask; enum uint __NFDBITS = 8 * __fd_mask.sizeof; extern (D) auto __FDELT( int d ) { return d / __NFDBITS; } extern (D) auto __FDMASK( int d ) { return cast(__fd_mask) 1 << ( d % __NFDBITS ); } } enum FD_SETSIZE = 1024; struct fd_set { __fd_mask[FD_SETSIZE / __NFDBITS] fds_bits; } extern (D) void FD_CLR( int fd, fd_set* fdset ) { fdset.fds_bits[__FDELT( fd )] &= ~__FDMASK( fd ); } extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) { return (fdset.fds_bits[__FDELT( fd )] & __FDMASK( fd )) != 0; } extern (D) void FD_SET( int fd, fd_set* fdset ) { fdset.fds_bits[__FDELT( fd )] |= __FDMASK( fd ); } extern (D) void FD_ZERO( fd_set* fdset ) { fdset.fds_bits[0 .. $] = 0; } /+ + GNU ASM Implementation + # define __FD_ZERO(fdsp) \ do { \ int __d0, __d1; \ __asm__ __volatile__ ("cld; rep; stosl" \ : "=c" (__d0), "=D" (__d1) \ : "a" (0), "0" (sizeof (fd_set) \ / sizeof (__fd_mask)), \ "1" (&__FDS_BITS (fdsp)[0]) \ : "memory"); \ } while (0) # define __FD_SET(fd, fdsp) \ __asm__ __volatile__ ("btsl %1,%0" \ : "=m" (__FDS_BITS (fdsp)[__FDELT (fd)]) \ : "r" (((int) (fd)) % __NFDBITS) \ : "cc","memory") # define __FD_CLR(fd, fdsp) \ __asm__ __volatile__ ("btrl %1,%0" \ : "=m" (__FDS_BITS (fdsp)[__FDELT (fd)]) \ : "r" (((int) (fd)) % __NFDBITS) \ : "cc","memory") # define __FD_ISSET(fd, fdsp) \ (__extension__ \ ({register char __result; \ __asm__ __volatile__ ("btl %1,%2 ; setcb %b0" \ : "=q" (__result) \ : "r" (((int) (fd)) % __NFDBITS), \ "m" (__FDS_BITS (fdsp)[__FDELT (fd)]) \ : "cc"); \ __result; })) +/ int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*); int select(int, fd_set*, fd_set*, fd_set*, timeval*); } else version( OSX ) { private { enum uint __DARWIN_NBBY = 8; /* bits in a byte */ enum uint __DARWIN_NFDBITS = (int.sizeof * __DARWIN_NBBY); /* bits per mask */ } enum FD_SETSIZE = 1024; struct fd_set { int[(FD_SETSIZE + (__DARWIN_NFDBITS - 1)) / __DARWIN_NFDBITS] fds_bits; } extern (D) void FD_CLR( int fd, fd_set* fdset ) { fdset.fds_bits[fd / __DARWIN_NFDBITS] &= ~(1 << (fd % __DARWIN_NFDBITS)); } extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) { return (fdset.fds_bits[fd / __DARWIN_NFDBITS] & (1 << (fd % __DARWIN_NFDBITS))) != 0; } extern (D) void FD_SET( int fd, fd_set* fdset ) { fdset.fds_bits[fd / __DARWIN_NFDBITS] |= 1 << (fd % __DARWIN_NFDBITS); } extern (D) void FD_ZERO( fd_set* fdset ) { fdset.fds_bits[0 .. $] = 0; } int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*); int select(int, fd_set*, fd_set*, fd_set*, timeval*); } else version( FreeBSD ) { private { alias c_ulong __fd_mask; enum _NFDBITS = __fd_mask.sizeof * 8; } enum uint FD_SETSIZE = 1024; struct fd_set { __fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] __fds_bits; } extern (D) __fd_mask __fdset_mask(uint n) { return cast(__fd_mask) 1 << (n % _NFDBITS); } extern (D) void FD_CLR( int n, fd_set* p ) { p.__fds_bits[n / _NFDBITS] &= ~__fdset_mask(n); } extern (D) bool FD_ISSET( int n, const(fd_set)* p ) { return (p.__fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0; } extern (D) void FD_SET( int n, fd_set* p ) { p.__fds_bits[n / _NFDBITS] |= __fdset_mask(n); } extern (D) void FD_ZERO( fd_set* p ) { fd_set *_p; size_t _n; _p = p; _n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS; while (_n > 0) _p.__fds_bits[--_n] = 0; } int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*); int select(int, fd_set*, fd_set*, fd_set*, timeval*); } else version (Solaris) { private { alias c_long fds_mask; enum _NBBY = 8; enum FD_NFDBITS = fds_mask.sizeof * _NBBY; } version (D_LP64) enum uint FD_SETSIZE = 65536; else enum uint FD_SETSIZE = 1024; struct fd_set { c_long[(FD_SETSIZE + (FD_NFDBITS - 1)) / FD_NFDBITS] fds_bits; } extern (D) void FD_SET(int __n, fd_set* __p) { __p.fds_bits[__n / FD_NFDBITS] |= 1UL << (__n % FD_NFDBITS); } extern (D) void FD_CLR(int __n, fd_set* __p) { __p.fds_bits[__n / FD_NFDBITS] &= ~(1UL << (__n % FD_NFDBITS)); } extern (D) bool FD_ISSET(int __n, const(fd_set)* __p) { return (__p.fds_bits[__n / FD_NFDBITS] & (1UL << (__n % FD_NFDBITS))) != 0; } extern (D) void FD_ZERO(fd_set* __p) { __p.fds_bits[0 .. $] = 0; } int select(int, fd_set*, fd_set*, fd_set*, timeval*); int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*); } else version( CRuntime_Bionic ) { private { alias c_ulong __fd_mask; enum uint __NFDBITS = 8 * __fd_mask.sizeof; extern (D) auto __FDELT( int d ) { return d / __NFDBITS; } extern (D) auto __FDMASK( int d ) { return cast(__fd_mask) 1 << ( d % __NFDBITS ); } } enum FD_SETSIZE = 1024; struct fd_set { __fd_mask[FD_SETSIZE / __NFDBITS] fds_bits; } // These functions are generated in assembly in bionic. extern (D) void FD_CLR( int fd, fd_set* fdset ) { fdset.fds_bits[__FDELT( fd )] &= ~__FDMASK( fd ); } extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) { return (fdset.fds_bits[__FDELT( fd )] & __FDMASK( fd )) != 0; } extern (D) void FD_SET( int fd, fd_set* fdset ) { fdset.fds_bits[__FDELT( fd )] |= __FDMASK( fd ); } extern (D) void FD_ZERO( fd_set* fdset ) { fdset.fds_bits[0 .. $] = 0; } int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*); int select(int, fd_set*, fd_set*, fd_set*, timeval*); } else { static assert(false, "Unsupported platform"); } unittest { debug(select) printf("core.sys.posix.sys.select unittest\n"); fd_set fd; for (auto i = 0; i < FD_SETSIZE; i++) { assert(!FD_ISSET(i, &fd)); } for (auto i = 0; i < FD_SETSIZE; i++) { if ((i & -i) == i) FD_SET(i, &fd); } for (auto i = 0; i < FD_SETSIZE; i++) { if ((i & -i) == i) assert(FD_ISSET(i, &fd)); else assert(!FD_ISSET(i, &fd)); } for (auto i = 0; i < FD_SETSIZE; i++) { if ((i & -i) == i) FD_CLR(i, &fd); else FD_SET(i, &fd); } for (auto i = 0; i < FD_SETSIZE; i++) { if ((i & -i) == i) assert(!FD_ISSET(i, &fd)); else assert(FD_ISSET(i, &fd)); } FD_ZERO(&fd); for (auto i = 0; i < FD_SETSIZE; i++) { assert(!FD_ISSET(i, &fd)); } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/time.d0000664000175000017500000000733712776214756023115 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.time; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for time_t, suseconds_t public import core.sys.posix.sys.select; // for fd_set, FD_CLR() FD_ISSET() FD_SET() FD_ZERO() FD_SETSIZE, select() version (Posix): extern (C) nothrow @nogc: // // XOpen (XSI) // /* struct timeval { time_t tv_sec; suseconds_t tv_usec; } struct itimerval { timeval it_interval; timeval it_value; } ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF int getitimer(int, itimerval*); int gettimeofday(timeval*, void*); int select(int, fd_set*, fd_set*, fd_set*, timeval*); (defined in core.sys.posix.sys.signal) int setitimer(int, in itimerval*, itimerval*); int utimes(in char*, ref const(timeval)[2]); // LEGACY */ version( CRuntime_Glibc ) { struct timeval { time_t tv_sec; suseconds_t tv_usec; } struct itimerval { timeval it_interval; timeval it_value; } enum ITIMER_REAL = 0; enum ITIMER_VIRTUAL = 1; enum ITIMER_PROF = 2; int getitimer(int, itimerval*); int gettimeofday(timeval*, void*); int setitimer(int, in itimerval*, itimerval*); int utimes(in char*, ref const(timeval)[2]); // LEGACY } else version( OSX ) { struct timeval { time_t tv_sec; suseconds_t tv_usec; } struct itimerval { timeval it_interval; timeval it_value; } // non-standard struct timezone_t { int tz_minuteswest; int tz_dsttime; } int getitimer(int, itimerval*); int gettimeofday(timeval*, timezone_t*); // timezone_t* is normally void* int setitimer(int, in itimerval*, itimerval*); int utimes(in char*, ref const(timeval)[2]); } else version( FreeBSD ) { struct timeval { time_t tv_sec; suseconds_t tv_usec; } struct itimerval { timeval it_interval; timeval it_value; } // non-standard struct timezone_t { int tz_minuteswest; int tz_dsttime; } int getitimer(int, itimerval*); int gettimeofday(timeval*, timezone_t*); // timezone_t* is normally void* int setitimer(int, in itimerval*, itimerval*); int utimes(in char*, ref const(timeval)[2]); } else version (Solaris) { struct timeval { time_t tv_sec; suseconds_t tv_usec; } struct itimerval { timeval it_interval; timeval it_value; } int getitimer(int, itimerval*); int gettimeofday(timeval*, void*); int setitimer(int, in itimerval*, itimerval*); int utimes(in char*, ref const(timeval)[2]); } else version( CRuntime_Bionic ) { struct timeval { time_t tv_sec; suseconds_t tv_usec; } struct itimerval { timeval it_interval; timeval it_value; } struct timezone_t { int tz_minuteswest; int tz_dsttime; } enum ITIMER_REAL = 0; enum ITIMER_VIRTUAL = 1; enum ITIMER_PROF = 2; int getitimer(int, itimerval*); int gettimeofday(timeval*, timezone_t*); int setitimer(int, in itimerval*, itimerval*); int utimes(in char*, ref const(timeval)[2]); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/wait.d0000664000175000017500000001705212776214756023116 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.wait; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for id_t, pid_t public import core.sys.posix.signal; // for siginfo_t (XSI) //public import core.sys.posix.resource; // for rusage (XSI) version (Posix): extern (C) nothrow @nogc: // // Required // /* WNOHANG WUNTRACED WEXITSTATUS WIFCONTINUED WIFEXITED WIFSIGNALED WIFSTOPPED WSTOPSIG WTERMSIG pid_t wait(int*); pid_t waitpid(pid_t, int*, int); */ version( CRuntime_Glibc ) { enum WNOHANG = 1; enum WUNTRACED = 2; private { enum __W_CONTINUED = 0xFFFF; extern (D) int __WTERMSIG( int status ) { return status & 0x7F; } } // // NOTE: These macros assume __USE_BSD is not defined in the relevant // C headers as the parameter definition there is different and // much more complicated. // extern (D) int WEXITSTATUS( int status ) { return ( status & 0xFF00 ) >> 8; } extern (D) int WIFCONTINUED( int status ) { return status == __W_CONTINUED; } extern (D) bool WIFEXITED( int status ) { return __WTERMSIG( status ) == 0; } extern (D) bool WIFSIGNALED( int status ) { return ( cast(byte) ( ( status & 0x7F ) + 1 ) >> 1 ) > 0; } extern (D) bool WIFSTOPPED( int status ) { return ( status & 0xFF ) == 0x7F; } extern (D) int WSTOPSIG( int status ) { return WEXITSTATUS( status ); } extern (D) int WTERMSIG( int status ) { return status & 0x7F; } } else version( OSX ) { enum WNOHANG = 1; enum WUNTRACED = 2; private { enum _WSTOPPED = 0x7F; // octal 0177 } extern (D) int _WSTATUS(int status) { return (status & 0x7F); } extern (D) int WEXITSTATUS( int status ) { return (status >> 8); } extern (D) int WIFCONTINUED( int status ) { return status == 0x13; } extern (D) bool WIFEXITED( int status ) { return _WSTATUS(status) == 0; } extern (D) bool WIFSIGNALED( int status ) { return _WSTATUS( status ) != _WSTOPPED && _WSTATUS( status ) != 0; } extern (D) bool WIFSTOPPED( int status ) { return _WSTATUS( status ) == _WSTOPPED; } extern (D) int WSTOPSIG( int status ) { return status >> 8; } extern (D) int WTERMSIG( int status ) { return _WSTATUS( status ); } } else version( FreeBSD ) { enum WNOHANG = 1; enum WUNTRACED = 2; private { enum _WSTOPPED = 0x7F; // octal 0177 } extern (D) int _WSTATUS(int status) { return (status & 0x7F); } extern (D) int WEXITSTATUS( int status ) { return (status >> 8); } extern (D) int WIFCONTINUED( int status ) { return status == 0x13; } extern (D) bool WIFEXITED( int status ) { return _WSTATUS(status) == 0; } extern (D) bool WIFSIGNALED( int status ) { return _WSTATUS( status ) != _WSTOPPED && _WSTATUS( status ) != 0; } extern (D) bool WIFSTOPPED( int status ) { return _WSTATUS( status ) == _WSTOPPED; } extern (D) int WSTOPSIG( int status ) { return status >> 8; } extern (D) int WTERMSIG( int status ) { return _WSTATUS( status ); } } else version (Solaris) { enum WNOHANG = 64; enum WUNTRACED = 4; extern (D) int WEXITSTATUS(int status) { return (status >> 8) & 0xff; } extern (D) int WIFCONTINUED(int status) { return (status & 0xffff) == 0xffff; } extern (D) bool WIFEXITED(int status) { return (status & 0xff) == 0; } extern (D) bool WIFSIGNALED(int status) { return (status & 0xff) > 0 && (status & 0xff00) == 0; } extern (D) bool WIFSTOPPED(int status) { return (status & 0xff) == 0x7f && (status & 0xff00) != 0; } extern (D) int WSTOPSIG(int status) { return (status >> 8) & 0x7f; } extern (D) int WTERMSIG(int status) { return (status & 0x7f); } } else version( CRuntime_Bionic ) { enum WNOHANG = 1; enum WUNTRACED = 2; extern (D) int WEXITSTATUS( int status ) { return ( status & 0xFF00 ) >> 8; } extern (D) bool WIFEXITED( int status ) { return WTERMSIG(status) == 0; } extern (D) bool WIFSIGNALED( int status ) { return WTERMSIG(status + 1) >= 2; } extern (D) bool WIFSTOPPED( int status ) { return WTERMSIG(status) == 0x7F; } extern (D) int WSTOPSIG( int status ) { return WEXITSTATUS(status); } extern (D) int WTERMSIG( int status ) { return status & 0x7F; } } else { static assert(false, "Unsupported platform"); } pid_t wait(int*); pid_t waitpid(pid_t, int*, int); // // XOpen (XSI) // /* WEXITED WSTOPPED WCONTINUED WNOWAIT enum idtype_t { P_ALL, P_PID, P_PGID } int waitid(idtype_t, id_t, siginfo_t*, int); */ version( CRuntime_Glibc ) { enum WEXITED = 4; enum WSTOPPED = 2; enum WCONTINUED = 8; enum WNOWAIT = 0x01000000; enum idtype_t { P_ALL, P_PID, P_PGID } int waitid(idtype_t, id_t, siginfo_t*, int); } else version( OSX ) { enum WEXITED = 0x00000004; enum WSTOPPED = 0x00000008; enum WCONTINUED = 0x00000010; enum WNOWAIT = 0x00000020; enum idtype_t { P_ALL, P_PID, P_PGID } int waitid(idtype_t, id_t, siginfo_t*, int); } else version (FreeBSD) { enum WSTOPPED = WUNTRACED; enum WCONTINUED = 4; enum WNOWAIT = 8; // http://www.freebsd.org/projects/c99/ } else version (Solaris) { enum WEXITED = 1; enum WTRAPPED = 2; enum WSTOPPED = WUNTRACED; enum WCONTINUED = 8; enum WNOWAIT = 128; enum idtype_t { P_PID, /* A process identifier. */ P_PPID, /* A parent process identifier. */ P_PGID, /* A process group (job control group) */ /* identifier. */ P_SID, /* A session identifier. */ P_CID, /* A scheduling class identifier. */ P_UID, /* A user identifier. */ P_GID, /* A group identifier. */ P_ALL, /* All processes. */ P_LWPID, /* An LWP identifier. */ P_TASKID, /* A task identifier. */ P_PROJID, /* A project identifier. */ P_POOLID, /* A pool identifier. */ P_ZONEID, /* A zone identifier. */ P_CTID, /* A (process) contract identifier. */ P_CPUID, /* CPU identifier. */ P_PSETID, /* Processor set identifier */ } int waitid(idtype_t, id_t, siginfo_t*, int); } else version( CRuntime_Bionic ) { enum WEXITED = 4; enum WSTOPPED = 2; enum WCONTINUED = 8; enum WNOWAIT = 0x01000000; alias int idtype_t; int waitid(idtype_t, id_t, siginfo_t*, int); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/utsname.d0000664000175000017500000000371112776214756023623 0ustar kaikaimodule core.sys.posix.sys.utsname; version (Posix): extern(C): version(CRuntime_Glibc) { private enum utsNameLength = 65; struct utsname { char[utsNameLength] sysname; char[utsNameLength] nodename; char[utsNameLength] release; // The field name is version but version is a keyword in D. char[utsNameLength] update; char[utsNameLength] machine; char[utsNameLength] __domainname; } int uname(utsname* __name); } else version(OSX) { private enum utsNameLength = 256; struct utsname { char[utsNameLength] sysname; char[utsNameLength] nodename; char[utsNameLength] release; // The field name is version but version is a keyword in D. char[utsNameLength] update; char[utsNameLength] machine; } int uname(utsname* __name); } else version(FreeBSD) { private enum utsNameLength = 32; struct utsname { char[utsNameLength] sysname; char[utsNameLength] nodename; char[utsNameLength] release; // The field name is version but version is a keyword in D. char[utsNameLength] update; char[utsNameLength] machine; } int uname(utsname* __name); } else version(Solaris) { private enum SYS_NMLN = 257; struct utsname { char[SYS_NMLN] sysname; char[SYS_NMLN] nodename; char[SYS_NMLN] release; // The field name is version but version is a keyword in D. char[SYS_NMLN] _version; char[SYS_NMLN] machine; } int uname(utsname* __name); } else version(CRuntime_Bionic) { private enum SYS_NMLN = 65; struct utsname { char[SYS_NMLN] sysname; char[SYS_NMLN] nodename; char[SYS_NMLN] release; // The field name is version but version is a keyword in D. char[SYS_NMLN] _version; char[SYS_NMLN] machine; char[SYS_NMLN] domainname; } int uname(utsname*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/ioctl.d0000664000175000017500000002145212776214756023263 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Alex Rønne Petersen 2011 - 2012. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Alex Rønne Petersen 2011 - 2012. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.ioctl; import core.stdc.config; version (Posix): extern (C) nothrow @nogc: version (CRuntime_Glibc) { import core.sys.posix.termios; // tcflag_t, speed_t, cc_t enum _IOC_NRBITS = 8; enum _IOC_TYPEBITS = 8; enum _IOC_SIZEBITS = 14; enum _IOC_DIRBITS = 2; enum _IOC_NRMASK = (1 << _IOC_NRBITS) - 1; enum _IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1; enum _IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1; enum _IOC_DIRMASK = (1 << _IOC_DIRBITS) - 1; enum _IOC_NRSHIFT = 0; enum _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS; enum _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS; enum _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS; enum _IOC_NONE = 0; enum _IOC_WRITE = 1; enum _IOC_READ = 2; extern (D) int _IOC(T = typeof(null))(int dir, int type, int nr) { return (dir << _IOC_DIRSHIFT) | (type << _IOC_TYPESHIFT) | (nr << _IOC_NRSHIFT) | (is(T == typeof(null)) ? 0 : T.sizeof << _IOC_SIZESHIFT); } extern (D) int _IO(int type, int nr) { return _IOC(_IOC_NONE, type, nr); } extern (D) int _IOR(T)(int type, int nr) { return _IOC!T(_IOC_READ, type, nr); } extern (D) int _IOW(T)(int type, int nr) { return _IOC!T(_IOC_WRITE, type, nr); } extern (D) int _IOWR(T)(int type, int nr) { return _IOC!T(_IOC_READ | _IOC_WRITE, type, nr); } extern (D) int _IOC_DIR(int nr) { return (nr >> _IOC_DIRSHIFT) & _IOC_DIRMASK; } extern (D) int _IOC_TYPE(int nr) { return (nr >> _IOC_TYPESHIFT) & _IOC_TYPEMASK; } extern (D) int _IOC_NR(int nr) { return (nr >> _IOC_NRSHIFT) & _IOC_NRMASK; } extern (D) int _IOC_SIZE(int nr) { return (nr >> _IOC_SIZESHIFT) & _IOC_SIZEMASK; } enum IOC_IN = _IOC_WRITE << _IOC_DIRSHIFT; enum IOC_OUT = _IOC_READ << _IOC_DIRSHIFT; enum IOC_INOUT = (_IOC_READ | _IOC_WRITE) << _IOC_DIRSHIFT; enum IOCSIZE_MASK = _IOC_SIZEMASK << _IOC_DIRSHIFT; enum IOCSIZE_SHIFT = _IOC_SIZESHIFT; enum NCCS = 19; struct termios2 { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t c_line; cc_t[NCCS] c_cc; speed_t c_ispeed; speed_t c_ospeed; } struct winsize { ushort ws_row; ushort ws_col; ushort ws_xpixel; ushort ws_ypixel; } enum NCC = 8; struct termio { ushort c_iflag; ushort c_oflag; ushort c_cflag; ushort c_lflag; ubyte c_line; ubyte[NCC] c_cc; } enum TIOCM_LE = 0x001; enum TIOCM_DTR = 0x002; enum TIOCM_RTS = 0x004; enum TIOCM_ST = 0x008; enum TIOCM_SR = 0x010; enum TIOCM_CTS = 0x020; enum TIOCM_CAR = 0x040; enum TIOCM_RNG = 0x080; enum TIOCM_DSR = 0x100; enum TIOCM_CD = TIOCM_CAR; enum TIOCM_RI = TIOCM_RNG; enum N_TTY = 0; enum N_SLIP = 1; enum N_MOUSE = 2; enum N_PPP = 3; enum N_STRIP = 4; enum N_AX25 = 5; enum N_X25 = 6; enum N_6PACK = 7; enum N_MASC = 8; enum N_R3964 = 9; enum N_PROFIBUS_FDL = 10; enum N_IRDA = 11; enum N_SMSBLOCK = 12; enum N_HDLC = 13; enum N_SYNC_PPP = 14; enum N_HCI = 15; enum TCGETS = 0x5401; enum TCSETS = 0x5402; enum TCSETSW = 0x5403; enum TCSETSF = 0x5404; enum TCGETA = 0x5405; enum TCSETA = 0x5406; enum TCSETAW = 0x5407; enum TCSETAF = 0x5408; enum TCSBRK = 0x5409; enum TCXONC = 0x540A; enum TCFLSH = 0x540B; enum TIOCEXCL = 0x540C; enum TIOCNXCL = 0x540D; enum TIOCSCTTY = 0x540E; enum TIOCGPGRP = 0x540F; enum TIOCSPGRP = 0x5410; enum TIOCOUTQ = 0x5411; enum TIOCSTI = 0x5412; enum TIOCGWINSZ = 0x5413; enum TIOCSWINSZ = 0x5414; enum TIOCMGET = 0x5415; enum TIOCMBIS = 0x5416; enum TIOCMBIC = 0x5417; enum TIOCMSET = 0x5418; enum TIOCGSOFTCAR = 0x5419; enum TIOCSSOFTCAR = 0x541A; enum FIONREAD = 0x541B; enum TIOCINQ = FIONREAD; enum TIOCLINUX = 0x541C; enum TIOCCONS = 0x541D; enum TIOCGSERIAL = 0x541E; enum TIOCSSERIAL = 0x541F; enum TIOCPKT = 0x5420; enum FIONBIO = 0x5421; enum TIOCNOTTY = 0x5422; enum TIOCSETD = 0x5423; enum TIOCGETD = 0x5424; enum TCSBRKP = 0x5425; enum TIOCSBRK = 0x5427; enum TIOCCBRK = 0x5428; enum TIOCGSID = 0x5429; enum TCGETS2 = _IOR!termios2('T', 0x2A); enum TCSETS2 = _IOR!termios2('T', 0x2B); enum TCSETSW2 = _IOW!termios2('T', 0x2C); enum TCSETSF2 = _IOW!termios2('T', 0x2D); enum TIOCGRS485 = 0x542E; enum TIOCSRS485 = 0x542F; enum TIOCGPTN = _IOR!uint('T', 0x30); enum TIOCSPTLCK = _IOW!int('T', 0x31); enum TIOCGDEV = _IOR!uint('T', 0x32); enum TCGETX = 0x5432; enum TCSETX = 0x5433; enum TCSETXF = 0x5434; enum TCSETXW = 0x5435; enum TIOCSIG = _IOW!int('T', 0x36); enum TIOCVHANGUP = 0x5437; enum FIONCLEX = 0x5450; enum FIOCLEX = 0x5451; enum FIOASYNC = 0x5452; enum TIOCSERCONFIG = 0x5453; enum TIOCSERGWILD = 0x5454; enum TIOCSERSWILD = 0x5455; enum TIOCGLCKTRMIOS = 0x5456; enum TIOCSLCKTRMIOS = 0x5457; enum TIOCSERGSTRUCT = 0x5458; enum TIOCSERGETLSR = 0x5459; enum TIOCSERGETMULTI = 0x545A; enum TIOCSERSETMULTI = 0x545B; enum TIOCMIWAIT = 0x545C; enum TIOCGICOUNT = 0x545D; enum FIOQSIZE = 0x5460; enum TIOCPKT_DATA = 0; enum TIOCPKT_FLUSHREAD = 1; enum TIOCPKT_FLUSHWRITE = 2; enum TIOCPKT_STOP = 4; enum TIOCPKT_START = 8; enum TIOCPKT_NOSTOP = 16; enum TIOCPKT_DOSTOP = 32; enum TIOCPKT_IOCTL = 64; enum TIOCSER_TEMT = 0x01; enum SIOCADDRT = 0x890B; enum SIOCDELRT = 0x890C; enum SIOCRTMSG = 0x890D; enum SIOCGIFNAME = 0x8910; enum SIOCSIFLINK = 0x8911; enum SIOCGIFCONF = 0x8912; enum SIOCGIFFLAGS = 0x8913; enum SIOCSIFFLAGS = 0x8914; enum SIOCGIFADDR = 0x8915; enum SIOCSIFADDR = 0x8916; enum SIOCGIFDSTADDR = 0x8917; enum SIOCSIFDSTADDR = 0x8918; enum SIOCGIFBRDADDR = 0x8919; enum SIOCSIFBRDADDR = 0x891a; enum SIOCGIFNETMASK = 0x891b; enum SIOCSIFNETMASK = 0x891c; enum SIOCGIFMETRIC = 0x891d; enum SIOCSIFMETRIC = 0x891e; enum SIOCGIFMEM = 0x891f; enum SIOCSIFMEM = 0x8920; enum SIOCGIFMTU = 0x8921; enum SIOCSIFMTU = 0x8922; enum SIOCSIFNAME = 0x8923; enum SIOCSIFHWADDR = 0x8924; enum SIOCGIFENCAP = 0x8925; enum SIOCSIFENCAP = 0x8926; enum SIOCGIFHWADDR = 0x8927; enum SIOCGIFSLAVE = 0x8929; enum SIOCSIFSLAVE = 0x8930; enum SIOCADDMULTI = 0x8931; enum SIOCDELMULTI = 0x8932; enum SIOCGIFINDEX = 0x8933; enum SIOGIFINDEX = SIOCGIFINDEX; enum SIOCSIFPFLAGS = 0x8934; enum SIOCGIFPFLAGS = 0x8935; enum SIOCDIFADDR = 0x8936; enum SIOCSIFHWBROADCAST = 0x8937; enum SIOCGIFCOUNT = 0x8938; enum SIOCGIFBR = 0x8940; enum SIOCSIFBR = 0x8941; enum SIOCGIFTXQLEN = 0x8942; enum SIOCSIFTXQLEN = 0x8943; enum SIOCDARP = 0x8953; enum SIOCGARP = 0x8954; enum SIOCSARP = 0x8955; enum SIOCDRARP = 0x8960; enum SIOCGRARP = 0x8961; enum SIOCSRARP = 0x8962; enum SIOCGIFMAP = 0x8970; enum SIOCSIFMAP = 0x8971; enum SIOCADDDLCI = 0x8980; enum SIOCDELDLCI = 0x8981; enum SIOCDEVPRIVATE = 0x89F0; enum SIOCPROTOPRIVATE = 0x89E0; int ioctl(int __fd, c_ulong __request, ...); } else version (OSX) { import core.sys.posix.termios; // termios import core.sys.posix.sys.time; // timeval struct winsize { ushort ws_row; ushort ws_col; ushort ws_xpixel; ushort ws_ypixel; } struct ttysize { ushort ts_lines; ushort ts_cols; ushort ts_xxx; ushort ts_yyy; } int ioctl(int fildes, c_ulong request, ...); } else version (FreeBSD) { struct fiodgname_arg { int len; void* buf; } struct winsize { ushort ws_row; ushort ws_col; ushort ws_xpixel; ushort ws_ypixel; } int ioctl(int, c_ulong, ...); } else version (Solaris) { int ioctl(int fildes, int request, ...); } else version (CRuntime_Bionic) { int ioctl(int, int, ...); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/uio.d0000664000175000017500000000356312776214756022750 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.sys.uio; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for ssize_t version (Posix): extern (C) nothrow @nogc: // // Required // /* struct iovec { void* iov_base; size_t iov_len; } ssize_t // from core.sys.posix.sys.types size_t // from core.sys.posix.sys.types ssize_t readv(int, in iovec*, int); ssize_t writev(int, in iovec*, int); */ version( CRuntime_Glibc ) { struct iovec { void* iov_base; size_t iov_len; } ssize_t readv(int, in iovec*, int); ssize_t writev(int, in iovec*, int); } else version( OSX ) { struct iovec { void* iov_base; size_t iov_len; } ssize_t readv(int, in iovec*, int); ssize_t writev(int, in iovec*, int); } else version( FreeBSD ) { struct iovec { void* iov_base; size_t iov_len; } ssize_t readv(int, in iovec*, int); ssize_t writev(int, in iovec*, int); } else version (Solaris) { struct iovec { void* iov_base; size_t iov_len; } ssize_t readv(int, in iovec*, int); ssize_t writev(int, in iovec*, int); } else version( CRuntime_Bionic ) { struct iovec { void* iov_base; uint iov_len; } int readv(int, in iovec*, int); int writev(int, in iovec*, int); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/sys/resource.d0000664000175000017500000001726312776214756024005 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright (c) 2013 Lars Tandle Kyllingstad. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Lars Tandle Kyllingstad * Standards: The Open Group Base Specifications Issue 7, IEEE Std 1003.1-2008 */ module core.sys.posix.sys.resource; version (Posix): public import core.sys.posix.sys.time; public import core.sys.posix.sys.types: id_t; import core.sys.posix.config; nothrow extern(C): // // XOpen (XSI) // // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_resource.h.html /* enum { PRIO_PROCESS, PRIO_PGRP, PRIO_USER, } alias ulong rlim_t; enum { RLIM_INFINITY, RLIM_SAVED_MAX, RLIM_SAVED_CUR, } enum { RUSAGE_SELF, RUSAGE_CHILDREN, } struct rlimit { rlim_t rlim_cur; rlim_t rlim_max; } struct rusage { timeval ru_utime; timeval ru_stime; } enum { RLIMIT_CORE, RLIMIT_CPU, RLIMIT_DATA, RLIMIT_FSIZE, RLIMIT_NOFILE, RLIMIT_STACK, RLIMIT_AS, } int getpriority(int, id_t); int getrlimit(int, rlimit*); int getrusage(int, rusage*); int setpriority(int, id_t, int); int setrlimit(int, const rlimit*); */ version (CRuntime_Glibc) { // rusage and some other constants in the Bionic section below really // come from the linux kernel headers, but they're all mixed right now. enum { PRIO_PROCESS = 0, PRIO_PGRP = 1, PRIO_USER = 2, } static if (__USE_FILE_OFFSET64) alias ulong rlim_t; else alias c_ulong rlim_t; static if (__USE_FILE_OFFSET64) enum RLIM_INFINITY = 0xffffffffffffffffUL; else enum RLIM_INFINITY = cast(c_ulong)(~0UL); enum RLIM_SAVED_MAX = RLIM_INFINITY; enum RLIM_SAVED_CUR = RLIM_INFINITY; enum { RUSAGE_SELF = 0, RUSAGE_CHILDREN = -1, } struct rusage { timeval ru_utime; timeval ru_stime; c_long ru_maxrss; c_long ru_ixrss; c_long ru_idrss; c_long ru_isrss; c_long ru_minflt; c_long ru_majflt; c_long ru_nswap; c_long ru_inblock; c_long ru_oublock; c_long ru_msgsnd; c_long ru_msgrcv; c_long ru_nsignals; c_long ru_nvcsw; c_long ru_nivcsw; } enum { RLIMIT_CORE = 4, RLIMIT_CPU = 0, RLIMIT_DATA = 2, RLIMIT_FSIZE = 1, RLIMIT_NOFILE = 7, RLIMIT_STACK = 3, RLIMIT_AS = 9, } } else version (OSX) { enum { PRIO_PROCESS = 0, PRIO_PGRP = 1, PRIO_USER = 2, } alias ulong rlim_t; enum { RLIM_INFINITY = ((cast(ulong) 1 << 63) - 1), RLIM_SAVED_MAX = RLIM_INFINITY, RLIM_SAVED_CUR = RLIM_INFINITY, } enum { RUSAGE_SELF = 0, RUSAGE_CHILDREN = -1, } struct rusage { timeval ru_utime; timeval ru_stime; c_long[14] ru_opaque; } enum { RLIMIT_CORE = 4, RLIMIT_CPU = 0, RLIMIT_DATA = 2, RLIMIT_FSIZE = 1, RLIMIT_NOFILE = 8, RLIMIT_STACK = 3, RLIMIT_AS = 5, } } else version (FreeBSD) { enum { PRIO_PROCESS = 0, PRIO_PGRP = 1, PRIO_USER = 2, } alias long rlim_t; enum { RLIM_INFINITY = (cast(rlim_t)((cast(ulong) 1 << 63) - 1)), // FreeBSD explicitly does not define the following: //RLIM_SAVED_MAX, //RLIM_SAVED_CUR, } enum { RUSAGE_SELF = 0, RUSAGE_CHILDREN = -1, } struct rusage { timeval ru_utime; timeval ru_stime; c_long ru_maxrss; alias ru_ixrss ru_first; c_long ru_ixrss; c_long ru_idrss; c_long ru_isrss; c_long ru_minflt; c_long ru_majflt; c_long ru_nswap; c_long ru_inblock; c_long ru_oublock; c_long ru_msgsnd; c_long ru_msgrcv; c_long ru_nsignals; c_long ru_nvcsw; c_long ru_nivcsw; alias ru_nivcsw ru_last; } enum { RLIMIT_CORE = 4, RLIMIT_CPU = 0, RLIMIT_DATA = 2, RLIMIT_FSIZE = 1, RLIMIT_NOFILE = 8, RLIMIT_STACK = 3, RLIMIT_AS = 10, } } else version (Solaris) { enum { PRIO_PROCESS = 0, PRIO_PGRP = 1, PRIO_USER = 2, } alias c_ulong rlim_t; enum : c_long { RLIM_INFINITY = -3, RLIM_SAVED_MAX = -2, RLIM_SAVED_CUR = -1, } enum { RUSAGE_SELF = 0, RUSAGE_CHILDREN = -1, } struct rusage { timeval ru_utime; timeval ru_stime; c_long ru_maxrss; c_long ru_ixrss; c_long ru_idrss; c_long ru_isrss; c_long ru_minflt; c_long ru_majflt; c_long ru_nswap; c_long ru_inblock; c_long ru_oublock; c_long ru_msgsnd; c_long ru_msgrcv; c_long ru_nsignals; c_long ru_nvcsw; c_long ru_nivcsw; } enum { RLIMIT_CORE = 4, RLIMIT_CPU = 0, RLIMIT_DATA = 2, RLIMIT_FSIZE = 1, RLIMIT_NOFILE = 5, RLIMIT_STACK = 3, RLIMIT_AS = 6, } } else version (CRuntime_Bionic) { enum { PRIO_PROCESS = 0, PRIO_PGRP = 1, PRIO_USER = 2, } alias c_ulong rlim_t; enum RLIM_INFINITY = cast(c_ulong)(~0UL); enum { RUSAGE_SELF = 0, RUSAGE_CHILDREN = -1, } struct rusage { timeval ru_utime; timeval ru_stime; c_long ru_maxrss; c_long ru_ixrss; c_long ru_idrss; c_long ru_isrss; c_long ru_minflt; c_long ru_majflt; c_long ru_nswap; c_long ru_inblock; c_long ru_oublock; c_long ru_msgsnd; c_long ru_msgrcv; c_long ru_nsignals; c_long ru_nvcsw; c_long ru_nivcsw; } enum { RLIMIT_CORE = 4, RLIMIT_CPU = 0, RLIMIT_DATA = 2, RLIMIT_FSIZE = 1, RLIMIT_NOFILE = 7, RLIMIT_STACK = 3, RLIMIT_AS = 9, } } else static assert (false, "Unsupported platform"); struct rlimit { rlim_t rlim_cur; rlim_t rlim_max; } version (CRuntime_Glibc) { int getpriority(int, id_t); int setpriority(int, id_t, int); } else version (FreeBSD) { int getpriority(int, int); int setpriority(int, int, int); } else version (CRuntime_Bionic) { int getpriority(int, int); int setpriority(int, int, int); } else version (Solaris) { int getpriority(int, id_t); int setpriority(int, id_t, int); } else version (OSX) { int getpriority(int, id_t); int setpriority(int, id_t, int); } version (CRuntime_Glibc) { static if (__USE_FILE_OFFSET64) { int getrlimit64(int, rlimit*); int setrlimit64(int, in rlimit*); alias getrlimit = getrlimit64; alias setrlimit = setrlimit64; } else { int getrlimit(int, rlimit*); int setrlimit(int, in rlimit*); } int getrusage(int, rusage*); } else version (CRuntime_Bionic) { int getrlimit(int, rlimit*); int getrusage(int, rusage*); int setrlimit(int, in rlimit*); } else version (OSX) { int getrlimit(int, rlimit*); int getrusage(int, rusage*); int setrlimit(int, in rlimit*); } else version (FreeBSD) { int getrlimit(int, rlimit*); int getrusage(int, rusage*); int setrlimit(int, in rlimit*); } else version (Solaris) { int getrlimit(int, rlimit*); int getrusage(int, rusage*); int setrlimit(int, in rlimit*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/netdb.d0000664000175000017500000003264112776214756022431 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright David Nadlinger 2011. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: David Nadlinger, Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright David Nadlinger 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.netdb; private import core.sys.posix.config; public import core.stdc.inttypes; // for uint32_t public import core.sys.posix.netinet.in_; // for in_port_t, in_addr_t public import core.sys.posix.sys.types; // for ino_t public import core.sys.posix.sys.socket; // for socklen_t version (Posix): extern (C): nothrow: @nogc: // // Required // /* struct hostent { char* h_name; char** h_aliases; int h_addrtype; int h_length; char** h_addr_list; } struct netent { char* n_name; char** n_aliase; int n_addrtype; uint32_t n_net; } struct protoent { char* p_name; char** p_aliases; int p_proto; } struct servent { char* s_name; char** s_aliases; int s_port; char* s_proto; } IPPORT_RESERVED h_errno HOST_NOT_FOUND NO_DATA NO_RECOVERY TRY_AGAIN struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; sockaddr* ai_addr; char* ai_canonname; addrinfo* ai_next; } AI_PASSIVE AI_CANONNAME AI_NUMERICHOST AI_NUMERICSERV AI_V4MAPPED AI_ALL AI_ADDRCONFIG NI_NOFQDN NI_NUMERICHOST NI_NAMEREQD NI_NUMERICSERV NI_NUMERICSCOPE NI_DGRAM EAI_AGAIN EAI_BADFLAGS EAI_FAIL EAI_FAMILY EAI_MEMORY EAI_NONAME EAI_SERVICE EAI_SOCKTYPE EAI_SYSTEM EAI_OVERFLOW void endhostent(); void endnetent(); void endprotoent(); void endservent(); void freeaddrinfo(addrinfo*); const(char)* gai_strerror(int); int getaddrinfo(const(char)*, const(char)*, const(addrinfo)*, addrinfo**); hostent* gethostbyaddr(const(void)*, socklen_t, int); hostent* gethostbyname(const(char)*); hostent* gethostent(); int getnameinfo(const(sockaddr)*, socklen_t, char*, socklen_t, char*, socklen_t, int); netent* getnetbyaddr(uint32_t, int); netent* getnetbyname(const(char)*); netent* getnetent(); protoent* getprotobyname(const(char)*); protoent* getprotobynumber(int); protoent* getprotoent(); servent* getservbyname(const(char)*, const(char)*); servent* getservbyport(int, const(char)*); servent* getservent(); void sethostent(int); void setnetent(int); void setprotoent(int); void setservent(int); */ version( CRuntime_Glibc ) { struct hostent { char* h_name; char** h_aliases; int h_addrtype; int h_length; char** h_addr_list; char* h_addr() @property { return h_addr_list[0]; } // non-standard } struct netent { char* n_name; char** n_aliases; int n_addrtype; uint32_t n_net; } struct protoent { char* p_name; char** p_aliases; int p_proto; } struct servent { char* s_name; char** s_aliases; int s_port; char* s_proto; } enum IPPORT_RESERVED = 1024; //h_errno enum HOST_NOT_FOUND = 1; enum NO_DATA = 4; enum NO_RECOVERY = 3; enum TRY_AGAIN = 2; struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; sockaddr* ai_addr; char* ai_canonname; addrinfo* ai_next; } enum AI_PASSIVE = 0x1; enum AI_CANONNAME = 0x2; enum AI_NUMERICHOST = 0x4; enum AI_NUMERICSERV = 0x400; enum AI_V4MAPPED = 0x8; enum AI_ALL = 0x10; enum AI_ADDRCONFIG = 0x20; enum NI_NOFQDN = 4; enum NI_NUMERICHOST = 1; enum NI_NAMEREQD = 8; enum NI_NUMERICSERV = 2; //enum NI_NUMERICSCOPE = ?; enum NI_DGRAM = 16; enum NI_MAXHOST = 1025; // non-standard enum NI_MAXSERV = 32; // non-standard enum EAI_AGAIN = -3; enum EAI_BADFLAGS = -1; enum EAI_FAIL = -4; enum EAI_FAMILY = -6; enum EAI_MEMORY = -10; enum EAI_NONAME = -2; enum EAI_SERVICE = -8; enum EAI_SOCKTYPE = -7; enum EAI_SYSTEM = -11; enum EAI_OVERFLOW = -12; } else version( OSX ) { struct hostent { char* h_name; char** h_aliases; int h_addrtype; int h_length; char** h_addr_list; char* h_addr() @property { return h_addr_list[0]; } // non-standard } struct netent { char* n_name; char** n_aliases; int n_addrtype; uint32_t n_net; } struct protoent { char* p_name; char** p_aliases; int p_proto; } struct servent { char* s_name; char** s_aliases; int s_port; char* s_proto; } enum IPPORT_RESERVED = 1024; //h_errno enum HOST_NOT_FOUND = 1; enum NO_DATA = 4; enum NO_RECOVERY = 3; enum TRY_AGAIN = 2; struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; char* ai_canonname; sockaddr* ai_addr; addrinfo* ai_next; } enum AI_PASSIVE = 0x1; enum AI_CANONNAME = 0x2; enum AI_NUMERICHOST = 0x4; enum AI_NUMERICSERV = 0x1000; enum AI_V4MAPPED = 0x800; enum AI_ALL = 0x100; enum AI_ADDRCONFIG = 0x400; enum NI_NOFQDN = 0x1; enum NI_NUMERICHOST = 0x2; enum NI_NAMEREQD = 0x4; enum NI_NUMERICSERV = 0x8; //enum NI_NUMERICSCOPE = ?; enum NI_DGRAM = 0x10; enum NI_MAXHOST = 1025; // non-standard enum NI_MAXSERV = 32; // non-standard enum EAI_AGAIN = 2; enum EAI_BADFLAGS = 3; enum EAI_FAIL = 4; enum EAI_FAMILY = 5; enum EAI_MEMORY = 6; enum EAI_NONAME = 8; enum EAI_SERVICE = 9; enum EAI_SOCKTYPE = 10; enum EAI_SYSTEM = 11; enum EAI_OVERFLOW = 14; } else version( FreeBSD ) { struct hostent { char* h_name; char** h_aliases; int h_addrtype; int h_length; char** h_addr_list; extern (D) char* h_addr() @property { return h_addr_list[0]; } // non-standard } struct netent { char* n_name; char** n_aliases; int n_addrtype; uint32_t n_net; } struct protoent { char* p_name; char** p_aliases; int p_proto; } struct servent { char* s_name; char** s_aliases; int s_port; char* s_proto; } enum IPPORT_RESERVED = 1024; //h_errno enum HOST_NOT_FOUND = 1; enum NO_DATA = 4; enum NO_RECOVERY = 3; enum TRY_AGAIN = 2; struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; char* ai_canonname; sockaddr* ai_addr; addrinfo* ai_next; } enum AI_PASSIVE = 0x1; enum AI_CANONNAME = 0x2; enum AI_NUMERICHOST = 0x4; enum AI_NUMERICSERV = 0x8; enum AI_V4MAPPED = 0x800; enum AI_ALL = 0x100; enum AI_ADDRCONFIG = 0x400; enum NI_NOFQDN = 0x1; enum NI_NUMERICHOST = 0x2; enum NI_NAMEREQD = 0x4; enum NI_NUMERICSERV = 0x8; //enum NI_NUMERICSCOPE = ?; enum NI_DGRAM = 0x10; enum NI_MAXHOST = 1025; // non-standard enum NI_MAXSERV = 32; // non-standard enum EAI_AGAIN = 2; enum EAI_BADFLAGS = 3; enum EAI_FAIL = 4; enum EAI_FAMILY = 5; enum EAI_MEMORY = 6; enum EAI_NONAME = 8; enum EAI_SERVICE = 9; enum EAI_SOCKTYPE = 10; enum EAI_SYSTEM = 11; enum EAI_OVERFLOW = 14; } else version (Solaris) { struct hostent { char* h_name; char** h_aliases; int h_addrtype; int h_length; char** h_addr_list; extern (D) char* h_addr() @property { return h_addr_list[0]; } // non-standard } struct netent { char* n_name; char** n_aliases; int n_addrtype; uint32_t n_net; } struct protoent { char* p_name; char** p_aliases; int p_proto; } struct servent { char* s_name; char** s_aliases; int s_port; char* s_proto; } enum HOST_NOT_FOUND = 1; enum TRY_AGAIN = 2; enum NO_RECOVERY = 3; enum NO_DATA = 4; struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; version (SPARC) int _ai_pad; else version (SPARC64) int _ai_pad; socklen_t ai_addrlen; char* ai_canonname; sockaddr* ai_addr; addrinfo* ai_next; } enum AI_PASSIVE = 0x0008; enum AI_CANONNAME = 0x0010; enum AI_NUMERICHOST = 0x0020; enum AI_NUMERICSERV = 0x0040; enum AI_V4MAPPED = 0x0001; enum AI_ALL = 0x0002; enum AI_ADDRCONFIG = 0x0004; enum NI_NOFQDN = 0x0001; enum NI_NUMERICHOST = 0x0002; enum NI_NAMEREQD = 0x0004; enum NI_NUMERICSERV = 0x0008; enum NI_DGRAM = 0x0010; enum NI_WITHSCOPEID = 0x0020; enum NI_NUMERICSCOPE = 0x0040; enum NI_MAXHOST = 1025; enum NI_MAXSERV = 32; enum EAI_AGAIN = 2; enum EAI_BADFLAGS = 3; enum EAI_FAIL = 4; enum EAI_FAMILY = 5; enum EAI_MEMORY = 6; enum EAI_NONAME = 8; enum EAI_SERVICE = 9; enum EAI_SOCKTYPE = 10; enum EAI_SYSTEM = 11; enum EAI_OVERFLOW = 14; enum EAI_PROTOCOL = 13; enum EAI_MAX = 14; } else version( CRuntime_Bionic ) { struct hostent { char* h_name; char** h_aliases; int h_addrtype; int h_length; char** h_addr_list; extern (D) char* h_addr() @property { return h_addr_list[0]; } // non-standard } struct netent { char* n_name; char** n_aliases; int n_addrtype; uint32_t n_net; } struct protoent { char* p_name; char** p_aliases; int p_proto; } struct servent { char* s_name; char** s_aliases; int s_port; char* s_proto; } enum IPPORT_RESERVED = 1024; enum HOST_NOT_FOUND = 1; enum NO_DATA = 4; enum NO_RECOVERY = 3; enum TRY_AGAIN = 2; struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; char* ai_canonname; sockaddr* ai_addr; addrinfo* ai_next; } enum AI_PASSIVE = 0x1; enum AI_CANONNAME = 0x2; enum AI_NUMERICHOST = 0x4; enum AI_NUMERICSERV = 0x8; enum AI_V4MAPPED = 0x800; enum AI_ALL = 0x100; enum AI_ADDRCONFIG = 0x400; enum NI_NOFQDN = 0x1; enum NI_NUMERICHOST = 0x2; enum NI_NAMEREQD = 0x4; enum NI_NUMERICSERV = 0x8; enum NI_DGRAM = 0x10; enum NI_MAXHOST = 1025; // non-standard enum NI_MAXSERV = 32; // non-standard enum EAI_AGAIN = 2; enum EAI_BADFLAGS = 3; enum EAI_FAIL = 4; enum EAI_FAMILY = 5; enum EAI_MEMORY = 6; enum EAI_NONAME = 8; enum EAI_SERVICE = 9; enum EAI_SOCKTYPE = 10; enum EAI_SYSTEM = 11; enum EAI_OVERFLOW = 14; } else { static assert(false, "Unsupported platform"); } void endhostent(); void endnetent(); void endprotoent(); void endservent(); void freeaddrinfo(addrinfo*); const(char)* gai_strerror(int); int getaddrinfo(const(char)*, const(char)*, const(addrinfo)*, addrinfo**); hostent* gethostbyaddr(const(void)*, socklen_t, int); hostent* gethostbyname(const(char)*); hostent* gethostent(); int getnameinfo(const(sockaddr)*, socklen_t, char*, socklen_t, char*, socklen_t, int); netent* getnetbyaddr(uint32_t, int); netent* getnetbyname(const(char)*); netent* getnetent(); protoent* getprotobyname(const(char)*); protoent* getprotobynumber(int); protoent* getprotoent(); servent* getservbyname(const(char)*, const(char)*); servent* getservbyport(int, const(char)*); servent* getservent(); void sethostent(int); void setnetent(int); void setprotoent(int); void setservent(int); ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/utime.d0000664000175000017500000000275012776214756022456 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.utime; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for time_t version (Posix): extern (C): nothrow: @nogc: // // Required // /* struct utimbuf { time_t actime; time_t modtime; } int utime(in char*, in utimbuf*); */ version( CRuntime_Glibc ) { struct utimbuf { time_t actime; time_t modtime; } int utime(in char*, in utimbuf*); } else version( OSX ) { struct utimbuf { time_t actime; time_t modtime; } int utime(in char*, in utimbuf*); } else version( FreeBSD ) { struct utimbuf { time_t actime; time_t modtime; } int utime(in char*, in utimbuf*); } else version( Solaris ) { struct utimbuf { time_t actime; time_t modtime; } int utime(in char*, in utimbuf*); } else version( CRuntime_Bionic ) { struct utimbuf { time_t actime; time_t modtime; } int utime(in char*, in utimbuf*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/net/0000775000175000017500000000000012776214756021750 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/net/if_.d0000664000175000017500000000400712776214756022653 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.net.if_; private import core.sys.posix.config; version (Posix): extern (C) nothrow @nogc: // // Required // /* struct if_nameindex // renamed to if_nameindex_t { uint if_index; char* if_name; } IF_NAMESIZE uint if_nametoindex(in char*); char* if_indextoname(uint, char*); if_nameindex_t* if_nameindex(); void if_freenameindex(if_nameindex_t*); */ version( CRuntime_Glibc ) { struct if_nameindex_t { uint if_index; char* if_name; } enum IF_NAMESIZE = 16; uint if_nametoindex(in char*); char* if_indextoname(uint, char*); if_nameindex_t* if_nameindex(); void if_freenameindex(if_nameindex_t*); } else version( OSX ) { struct if_nameindex_t { uint if_index; char* if_name; } enum IF_NAMESIZE = 16; uint if_nametoindex(in char*); char* if_indextoname(uint, char*); if_nameindex_t* if_nameindex(); void if_freenameindex(if_nameindex_t*); } else version( FreeBSD ) { struct if_nameindex_t { uint if_index; char* if_name; } enum IF_NAMESIZE = 16; uint if_nametoindex(in char*); char* if_indextoname(uint, char*); if_nameindex_t* if_nameindex(); void if_freenameindex(if_nameindex_t*); } else version( CRuntime_Bionic ) { enum IF_NAMESIZE = 16; uint if_nametoindex(in char*); char* if_indextoname(uint, char*); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/pwd.d0000664000175000017500000001201512776214756022120 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Alex Rønne Petersen * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.pwd; private import core.sys.posix.config; public import core.sys.posix.sys.types; // for gid_t, uid_t version (Posix): extern (C): nothrow: @nogc: // // Required // /* struct passwd { char* pw_name; uid_t pw_uid; gid_t pw_gid; char* pw_dir; char* pw_shell; } passwd* getpwnam(in char*); passwd* getpwuid(uid_t); */ version( CRuntime_Glibc ) { struct passwd { char* pw_name; char* pw_passwd; uid_t pw_uid; gid_t pw_gid; char* pw_gecos; char* pw_dir; char* pw_shell; } } else version( OSX ) { struct passwd { char* pw_name; char* pw_passwd; uid_t pw_uid; gid_t pw_gid; time_t pw_change; char* pw_class; char* pw_gecos; char* pw_dir; char* pw_shell; time_t pw_expire; } } else version( FreeBSD ) { struct passwd { char* pw_name; /* user name */ char* pw_passwd; /* encrypted password */ uid_t pw_uid; /* user uid */ gid_t pw_gid; /* user gid */ time_t pw_change; /* password change time */ char* pw_class; /* user access class */ char* pw_gecos; /* Honeywell login info */ char* pw_dir; /* home directory */ char* pw_shell; /* default shell */ time_t pw_expire; /* account expiration */ int pw_fields; /* internal: fields filled in */ } } else version( OpenBSD ) { struct passwd { char* pw_name; /* user name */ char* pw_passwd; /* encrypted password */ uid_t pw_uid; /* user uid */ gid_t pw_gid; /* user gid */ time_t pw_change; /* password change time */ char* pw_class; /* user access class */ char* pw_gecos; /* Honeywell login info */ char* pw_dir; /* home directory */ char* pw_shell; /* default shell */ time_t pw_expire; /* account expiration */ } } else version (Solaris) { struct passwd { char* pw_name; char* pw_passwd; uid_t pw_uid; gid_t pw_gid; char* pw_age; char* pw_comment; char* pw_gecos; char* pw_dir; char* pw_shell; } } else version( CRuntime_Bionic ) { struct passwd { char* pw_name; char* pw_passwd; uid_t pw_uid; gid_t pw_gid; char* pw_dir; char* pw_shell; } } else { static assert(false, "Unsupported platform"); } passwd* getpwnam(in char*); passwd* getpwuid(uid_t); // // Thread-Safe Functions (TSF) // /* int getpwnam_r(in char*, passwd*, char*, size_t, passwd**); int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); */ version( CRuntime_Glibc ) { int getpwnam_r(in char*, passwd*, char*, size_t, passwd**); int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); } else version( OSX ) { int getpwnam_r(in char*, passwd*, char*, size_t, passwd**); int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); } else version( FreeBSD ) { int getpwnam_r(in char*, passwd*, char*, size_t, passwd**); int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); } else version( OpenBSD ) { int getpwnam_r(in char*, passwd*, char*, size_t, passwd**); int getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); } else version (Solaris) { alias getpwnam_r = __posix_getpwnam_r; alias getpwuid_r = __posix_getpwuid_r; // POSIX.1c standard version of the functions int __posix_getpwnam_r(in char*, passwd*, char*, size_t, passwd**); int __posix_getpwuid_r(uid_t, passwd*, char*, size_t, passwd**); } else version( CRuntime_Bionic ) { } else { static assert(false, "Unsupported platform"); } // // XOpen (XSI) // /* void endpwent(); passwd* getpwent(); void setpwent(); */ version( CRuntime_Glibc ) { void endpwent(); passwd* getpwent(); void setpwent(); } else version ( OSX ) { void endpwent(); passwd* getpwent(); void setpwent(); } else version ( FreeBSD ) { void endpwent(); passwd* getpwent(); void setpwent(); } else version ( OpenBSD ) { void endpwent(); passwd* getpwent(); void setpwent(); } else version (Solaris) { void endpwent(); passwd* getpwent(); void setpwent(); } else version ( CRuntime_Bionic ) { void endpwent(); } else { static assert(false, "Unsupported platform"); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/syslog.d0000664000175000017500000002562312776214756022657 0ustar kaikai/** * D header file for POSIX system logger API. * (http://pubs.opengroup.org/onlinepubs/007904875/basedefs/syslog.h.html) * * Copyright: Copyright Adil Baig 2013. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Adil Baig * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Adil Baig 2013. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.syslog; version (Posix): extern (C) nothrow @nogc: version(CRuntime_Glibc) { //PRIORITY enum { LOG_EMERG = 0, /* system is unusable */ LOG_ALERT = 1, /* action must be taken immediately */ LOG_CRIT = 2, /* critical conditions */ LOG_ERR = 3, /* error conditions */ LOG_WARNING = 4, /* warning conditions */ LOG_NOTICE = 5, /* normal but significant condition */ LOG_INFO = 6, /* informational */ LOG_DEBUG = 7, /* debug-level messages */ }; //OPTIONS enum { LOG_PID = 0x01, /* log the pid with each message */ LOG_CONS = 0x02, /* log on the console if errors in sending */ LOG_ODELAY = 0x04, /* delay open until first syslog() (default) */ LOG_NDELAY = 0x08, /* don't delay open */ LOG_NOWAIT = 0x10, /* don't wait for console forks: DEPRECATED */ LOG_PERROR = 0x20, /* log to stderr as well */ }; //FACILITY enum { LOG_KERN = (0<<3), /* kernel messages */ LOG_USER = (1<<3), /* random user-level messages */ LOG_MAIL = (2<<3), /* mail system */ LOG_DAEMON = (3<<3), /* system daemons */ LOG_AUTH = (4<<3), /* security/authorization messages */ LOG_SYSLOG = (5<<3), /* messages generated internally by syslogd */ LOG_LPR = (6<<3), /* line printer subsystem */ LOG_NEWS = (7<<3), /* network news subsystem */ LOG_UUCP = (8<<3), /* UUCP subsystem */ LOG_CRON = (9<<3), /* clock daemon */ LOG_AUTHPRIV = (10<<3), /* security/authorization messages (private), */ LOG_FTP = (11<<3), /* ftp daemon */ /* other codes through 15 reserved for system use */ LOG_LOCAL0 = (16<<3), /* reserved for local use */ LOG_LOCAL1 = (17<<3), /* reserved for local use */ LOG_LOCAL2 = (18<<3), /* reserved for local use */ LOG_LOCAL3 = (19<<3), /* reserved for local use */ LOG_LOCAL4 = (20<<3), /* reserved for local use */ LOG_LOCAL5 = (21<<3), /* reserved for local use */ LOG_LOCAL6 = (22<<3), /* reserved for local use */ LOG_LOCAL7 = (23<<3), /* reserved for local use */ LOG_NFACILITIES = 24, /* current number of facilities */ }; int LOG_MASK(int pri) { return 1 << pri; } /* mask for one priority */ int LOG_UPTO(int pri) { return (1 << (pri+1)) - 1; } /* all priorities through pri */ void openlog (const char *, int __option, int __facility); int setlogmask (int __mask); void syslog (int __pri, const char *__fmt, ...); void closelog(); } else version( OSX ) { //http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/osfmk/sys/syslog.h //PRIORITY enum { LOG_EMERG = 0, /* system is unusable */ LOG_ALERT = 1, /* action must be taken immediately */ LOG_CRIT = 2, /* critical conditions */ LOG_ERR = 3, /* error conditions */ LOG_WARNING = 4, /* warning conditions */ LOG_NOTICE = 5, /* normal but significant condition */ LOG_INFO = 6, /* informational */ LOG_DEBUG = 7, /* debug-level messages */ }; //OPTIONS enum { LOG_PID = 0x01, /* log the pid with each message */ LOG_CONS = 0x02, /* log on the console if errors in sending */ LOG_ODELAY = 0x04, /* delay open until first syslog() (default) */ LOG_NDELAY = 0x08, /* don't delay open */ LOG_NOWAIT = 0x10, /* don't wait for console forks: DEPRECATED */ }; //FACILITY enum { LOG_KERN = (0<<3), /* kernel messages */ LOG_USER = (1<<3), /* random user-level messages */ LOG_MAIL = (2<<3), /* mail system */ LOG_DAEMON = (3<<3), /* system daemons */ LOG_AUTH = (4<<3), /* security/authorization messages */ LOG_SYSLOG = (5<<3), /* messages generated internally by syslogd */ LOG_LPR = (6<<3), /* line printer subsystem */ LOG_NEWS = (7<<3), /* network news subsystem */ LOG_UUCP = (8<<3), /* UUCP subsystem */ /* other codes through 15 reserved for system use */ LOG_LOCAL0 = (16<<3), /* reserved for local use */ LOG_LOCAL1 = (17<<3), /* reserved for local use */ LOG_LOCAL2 = (18<<3), /* reserved for local use */ LOG_LOCAL3 = (19<<3), /* reserved for local use */ LOG_LOCAL4 = (20<<3), /* reserved for local use */ LOG_LOCAL5 = (21<<3), /* reserved for local use */ LOG_LOCAL6 = (22<<3), /* reserved for local use */ LOG_LOCAL7 = (23<<3), /* reserved for local use */ LOG_NFACILITIES = 24, /* current number of facilities */ }; int LOG_MASK(int pri) { return 1 << pri; } /* mask for one priority */ int LOG_UPTO(int pri) { return (1 << (pri+1)) - 1; } /* all priorities through pri */ void openlog (const char *, int __option, int __facility); int setlogmask (int __mask); void syslog (int __pri, const char *__fmt, ...); void closelog(); } else version( FreeBSD ) { //http://fxr.watson.org/fxr/source/sys/syslog.h //PRIORITY enum { LOG_EMERG = 0, /* system is unusable */ LOG_ALERT = 1, /* action must be taken immediately */ LOG_CRIT = 2, /* critical conditions */ LOG_ERR = 3, /* error conditions */ LOG_WARNING = 4, /* warning conditions */ LOG_NOTICE = 5, /* normal but significant condition */ LOG_INFO = 6, /* informational */ LOG_DEBUG = 7, /* debug-level messages */ }; //OPTIONS enum { LOG_PID = 0x01, /* log the pid with each message */ LOG_CONS = 0x02, /* log on the console if errors in sending */ LOG_ODELAY = 0x04, /* delay open until first syslog() (default) */ LOG_NDELAY = 0x08, /* don't delay open */ LOG_NOWAIT = 0x10, /* don't wait for console forks: DEPRECATED */ LOG_PERROR = 0x20, /* log to stderr as well */ }; //FACILITY enum { LOG_KERN = (0<<3), /* kernel messages */ LOG_USER = (1<<3), /* random user-level messages */ LOG_MAIL = (2<<3), /* mail system */ LOG_DAEMON = (3<<3), /* system daemons */ LOG_AUTH = (4<<3), /* security/authorization messages */ LOG_SYSLOG = (5<<3), /* messages generated internally by syslogd */ LOG_LPR = (6<<3), /* line printer subsystem */ LOG_NEWS = (7<<3), /* network news subsystem */ LOG_UUCP = (8<<3), /* UUCP subsystem */ LOG_CRON = (9<<3), /* clock daemon */ LOG_AUTHPRIV = (10<<3), /* security/authorization messages (private), */ LOG_FTP = (11<<3), /* ftp daemon */ LOG_NTP = (12<<3), /* NTP subsystem */ LOG_SECURITY = (13<<3), /* security subsystems (firewalling, etc.) */ LOG_CONSOLE = (14<<3), /* /dev/console output */ /* other codes through 15 reserved for system use */ LOG_LOCAL0 = (16<<3), /* reserved for local use */ LOG_LOCAL1 = (17<<3), /* reserved for local use */ LOG_LOCAL2 = (18<<3), /* reserved for local use */ LOG_LOCAL3 = (19<<3), /* reserved for local use */ LOG_LOCAL4 = (20<<3), /* reserved for local use */ LOG_LOCAL5 = (21<<3), /* reserved for local use */ LOG_LOCAL6 = (22<<3), /* reserved for local use */ LOG_LOCAL7 = (23<<3), /* reserved for local use */ LOG_NFACILITIES = 24, /* current number of facilities */ }; int LOG_MASK(int pri) { return 1 << pri; } /* mask for one priority */ int LOG_UPTO(int pri) { return (1 << (pri+1)) - 1; } /* all priorities through pri */ void openlog (const char *, int __option, int __facility); int setlogmask (int __mask); void syslog (int __pri, const char *__fmt, ...); void closelog(); } else version( Solaris ) { //http://pubs.opengroup.org/onlinepubs/007904875/basedefs/syslog.h.html //PRIORITY enum { LOG_EMERG = 0, /* system is unusable */ LOG_ALERT = 1, /* action must be taken immediately */ LOG_CRIT = 2, /* critical conditions */ LOG_ERR = 3, /* error conditions */ LOG_WARNING = 4, /* warning conditions */ LOG_NOTICE = 5, /* normal but significant condition */ LOG_INFO = 6, /* informational */ LOG_DEBUG = 7, /* debug-level messages */ }; //OPTIONS enum { LOG_PID = 0x01, /* log the pid with each message */ LOG_CONS = 0x02, /* log on the console if errors in sending */ LOG_NDELAY = 0x08, /* don't delay open */ LOG_NOWAIT = 0x10, /* don't wait for console forks: DEPRECATED */ }; //FACILITY enum { LOG_KERN = (0<<3), /* kernel messages */ LOG_USER = (1<<3), /* random user-level messages */ LOG_MAIL = (2<<3), /* mail system */ LOG_DAEMON = (3<<3), /* system daemons */ LOG_AUTH = (4<<3), /* security/authorization messages */ LOG_SYSLOG = (5<<3), /* messages generated internally by syslogd */ LOG_LPR = (6<<3), /* line printer subsystem */ LOG_NEWS = (7<<3), /* network news subsystem */ LOG_UUCP = (8<<3), /* UUCP subsystem */ LOG_CRON = (9<<3), /* clock daemon */ LOG_AUTHPRIV = (10<<3), /* security/authorization messages (private), */ LOG_FTP = (11<<3), /* ftp daemon */ /* other codes through 15 reserved for system use */ LOG_LOCAL0 = (16<<3), /* reserved for local use */ LOG_LOCAL1 = (17<<3), /* reserved for local use */ LOG_LOCAL2 = (18<<3), /* reserved for local use */ LOG_LOCAL3 = (19<<3), /* reserved for local use */ LOG_LOCAL4 = (20<<3), /* reserved for local use */ LOG_LOCAL5 = (21<<3), /* reserved for local use */ LOG_LOCAL6 = (22<<3), /* reserved for local use */ LOG_LOCAL7 = (23<<3), /* reserved for local use */ LOG_NFACILITIES = 24, /* current number of facilities */ }; int LOG_MASK(int pri) { return 1 << pri; } /* mask for one priority */ int LOG_UPTO(int pri) { return (1 << (pri+1)) - 1; } /* all priorities through pri */ void openlog (const char *, int __option, int __facility); int setlogmask (int __mask); void syslog (int __pri, const char *__fmt, ...); void closelog(); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/sys/posix/ucontext.d0000664000175000017500000004677112776214756023217 0ustar kaikai/** * D header file for POSIX. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.sys.posix.ucontext; private import core.sys.posix.config; public import core.sys.posix.signal; // for sigset_t, stack_t private import core.stdc.stdint : uintptr_t; version (Posix): extern (C): nothrow: @nogc: // // XOpen (XSI) // /* mcontext_t struct ucontext_t { ucontext_t* uc_link; sigset_t uc_sigmask; stack_t uc_stack; mcontext_t uc_mcontext; } */ version( CRuntime_Glibc ) { version( X86_64 ) { enum { REG_R8 = 0, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_RDI, REG_RSI, REG_RBP, REG_RBX, REG_RDX, REG_RAX, REG_RCX, REG_RSP, REG_RIP, REG_EFL, REG_CSGSFS, /* Actually short cs, gs, fs, __pad0. */ REG_ERR, REG_TRAPNO, REG_OLDMASK, REG_CR2 } private { struct _libc_fpxreg { ushort[4] significand; ushort exponent; ushort[3] padding; } struct _libc_xmmreg { uint[4] element; } struct _libc_fpstate { ushort cwd; ushort swd; ushort ftw; ushort fop; ulong rip; ulong rdp; uint mxcsr; uint mxcr_mask; _libc_fpxreg[8] _st; _libc_xmmreg[16] _xmm; uint[24] padding; } enum NGREG = 23; alias c_long greg_t; alias greg_t[NGREG] gregset_t; alias _libc_fpstate* fpregset_t; } struct mcontext_t { gregset_t gregs; fpregset_t fpregs; c_ulong[8] __reserved1; } struct ucontext_t { c_ulong uc_flags; ucontext_t* uc_link; stack_t uc_stack; mcontext_t uc_mcontext; sigset_t uc_sigmask; _libc_fpstate __fpregs_mem; } } else version( X86 ) { enum { REG_GS = 0, REG_FS, REG_ES, REG_DS, REG_EDI, REG_ESI, REG_EBP, REG_ESP, REG_EBX, REG_EDX, REG_ECX, REG_EAX, REG_TRAPNO, REG_ERR, REG_EIP, REG_CS, REG_EFL, REG_UESP, REG_SS } private { struct _libc_fpreg { ushort[4] significand; ushort exponent; } struct _libc_fpstate { c_ulong cw; c_ulong sw; c_ulong tag; c_ulong ipoff; c_ulong cssel; c_ulong dataoff; c_ulong datasel; _libc_fpreg[8] _st; c_ulong status; } enum NGREG = 19; alias int greg_t; alias greg_t[NGREG] gregset_t; alias _libc_fpstate* fpregset_t; } struct mcontext_t { gregset_t gregs; fpregset_t fpregs; c_ulong oldmask; c_ulong cr2; } struct ucontext_t { c_ulong uc_flags; ucontext_t* uc_link; stack_t uc_stack; mcontext_t uc_mcontext; sigset_t uc_sigmask; _libc_fpstate __fpregs_mem; } } else version (MIPS32) { private { enum NGREG = 32; enum NFPREG = 32; alias ulong greg_t; alias greg_t[NGREG] gregset_t; struct fpregset_t { union fp_r_t { double[NFPREG] fp_dregs; static struct fp_fregs_t { float _fp_fregs; uint _fp_pad; } fp_fregs_t[NFPREG] fp_fregs; } fp_r_t fp_r; } } version (MIPS_O32) { struct mcontext_t { uint regmask; uint status; greg_t pc; gregset_t gregs; fpregset_t fpregs; uint fp_owned; uint fpc_csr; uint fpc_eir; uint used_math; uint dsp; greg_t mdhi; greg_t mdlo; c_ulong hi1; c_ulong lo1; c_ulong hi2; c_ulong lo2; c_ulong hi3; c_ulong lo3; } } else { struct mcontext_t { gregset_t gregs; fpregset_t fpregs; greg_t mdhi; greg_t hi1; greg_t hi2; greg_t hi3; greg_t mdlo; greg_t lo1; greg_t lo2; greg_t lo3; greg_t pc; uint fpc_csr; uint used_math; uint dsp; uint reserved; } } struct ucontext_t { c_ulong uc_flags; ucontext_t* uc_link; stack_t uc_stack; mcontext_t uc_mcontext; sigset_t uc_sigmask; } } else version (MIPS64) { private { enum NGREG = 32; enum NFPREG = 32; alias ulong greg_t; alias greg_t[NGREG] gregset_t; struct fpregset_t { union fp_r_t { double[NFPREG] fp_dregs; static struct fp_fregs_t { float _fp_fregs; uint _fp_pad; } fp_fregs_t[NFPREG] fp_fregs; } fp_r_t fp_r; } } struct mcontext_t { gregset_t gregs; fpregset_t fpregs; greg_t mdhi; greg_t hi1; greg_t hi2; greg_t hi3; greg_t mdlo; greg_t lo1; greg_t lo2; greg_t lo3; greg_t pc; uint fpc_csr; uint used_math; uint dsp; uint reserved; } struct ucontext_t { c_ulong uc_flags; ucontext_t* uc_link; stack_t uc_stack; mcontext_t uc_mcontext; sigset_t uc_sigmask; } } else version (PPC) { private { enum NGREG = 48; alias c_ulong greg_t; alias greg_t[NGREG] gregset_t; struct fpregset_t { double[32] fpregs; double fpscr; uint[2] _pad; } struct vrregset_t { uint[32][4] vrregs; uint vrsave; uint[2] __pad; uint vscr; } struct pt_regs { c_ulong[32] gpr; c_ulong nip; c_ulong msr; c_ulong orig_gpr3; c_ulong ctr; c_ulong link; c_ulong xer; c_ulong ccr; c_ulong mq; c_ulong trap; c_ulong dar; c_ulong dsisr; c_ulong result; } } struct mcontext_t { gregset_t gregs; fpregset_t fpregs; align(16) vrregset_t vrregs; } struct ucontext_t { c_ulong uc_flags; ucontext_t* uc_link; stack_t uc_stack; int[7] uc_pad; union uc_mcontext { pt_regs* regs; mcontext_t* uc_regs; } sigset_t uc_sigmask; char[mcontext_t.sizeof + 12] uc_reg_space; } } else version (PPC64) { private { enum NGREG = 48; enum NFPREG = 33; enum NVRREG = 34; alias c_ulong greg_t; alias greg_t[NGREG] gregset_t; alias double[NFPREG] fpregset_t; struct vscr_t { uint[3] __pad; uint vscr_word; } struct vrregset_t { uint[32][4] vrregs; vscr_t vscr; uint vrsave; uint[3] __pad; } struct pt_regs { c_ulong[32] gpr; c_ulong nip; c_ulong msr; c_ulong orig_gpr3; c_ulong ctr; c_ulong link; c_ulong xer; c_ulong ccr; c_ulong softe; c_ulong trap; c_ulong dar; c_ulong dsisr; c_ulong result; } } struct mcontext_t { c_ulong[4] __unused; int signal; int __pad0; c_ulong handler; c_ulong oldmask; pt_regs* regs; gregset_t gp_regs; fpregset_t fp_regs; vrregset_t *v_regs; c_long[NVRREG+NVRREG+1] vmx_reserve; } struct ucontext_t { c_ulong uc_flags; ucontext_t* uc_link; stack_t uc_stack; sigset_t uc_sigmask; mcontext_t uc_mcontext; } } else version(ARM) { enum { R0 = 0, R1 = 1, R2 = 2, R3 = 3, R4 = 4, R5 = 5, R6 = 6, R7 = 7, R8 = 8, R9 = 9, R10 = 10, R11 = 11, R12 = 12, R13 = 13, R14 = 14, R15 = 15 } struct sigcontext { c_ulong trap_no; c_ulong error_code; c_ulong oldmask; c_ulong arm_r0; c_ulong arm_r1; c_ulong arm_r2; c_ulong arm_r3; c_ulong arm_r4; c_ulong arm_r5; c_ulong arm_r6; c_ulong arm_r7; c_ulong arm_r8; c_ulong arm_r9; c_ulong arm_r10; c_ulong arm_fp; c_ulong arm_ip; c_ulong arm_sp; c_ulong arm_lr; c_ulong arm_pc; c_ulong arm_cpsr; c_ulong fault_address; } //alias elf_fpregset_t fpregset_t; alias sigcontext mcontext_t; struct ucontext_t { c_ulong uc_flags; ucontext_t* uc_link; stack_t uc_stack; mcontext_t uc_mcontext; sigset_t uc_sigmask; align(8) c_ulong[128] uc_regspace; } } else version (AArch64) { alias int greg_t; struct sigcontext { ulong fault_address; /* AArch64 registers */ ulong[31] regs; ulong sp; ulong pc; ulong pstate; /* 4K reserved for FP/SIMD state and future expansion */ align(16) ubyte[4096] __reserved; } alias sigcontext mcontext_t; struct ucontext_t { c_ulong uc_flags; ucontext_t* uc_link; stack_t uc_stack; sigset_t uc_sigmask; mcontext_t uc_mcontext; } } else version (SystemZ) { public import core.sys.posix.signal : sigset_t; enum NGREG = 27; alias greg_t = c_ulong; alias gregset_t = align(8) greg_t[NGREG]; align(8) struct __psw_t { c_ulong mask; c_ulong addr; } union fpreg_t { double d; float f; } struct fpregset_t { uint fpc; fpreg_t[16] fprs; } struct mcontext_t { __psw_t psw; c_ulong[16] gregs; uint[16] aregs; fpregset_t fpregs; } struct ucontext { c_ulong uc_flags; ucontext* uc_link; stack_t uc_stack; mcontext_t uc_mcontext; sigset_t uc_sigmask; } alias ucontext_t = ucontext; } else static assert(0, "unimplemented"); } else version( FreeBSD ) { // version( X86_64 ) { alias long __register_t; alias uint __uint32_t; alias ushort __uint16_t; struct mcontext_t { __register_t mc_onstack; __register_t mc_rdi; __register_t mc_rsi; __register_t mc_rdx; __register_t mc_rcx; __register_t mc_r8; __register_t mc_r9; __register_t mc_rax; __register_t mc_rbx; __register_t mc_rbp; __register_t mc_r10; __register_t mc_r11; __register_t mc_r12; __register_t mc_r13; __register_t mc_r14; __register_t mc_r15; __uint32_t mc_trapno; __uint16_t mc_fs; __uint16_t mc_gs; __register_t mc_addr; __uint32_t mc_flags; __uint16_t mc_es; __uint16_t mc_ds; __register_t mc_err; __register_t mc_rip; __register_t mc_cs; __register_t mc_rflags; __register_t mc_rsp; __register_t mc_ss; long mc_len; /* sizeof(mcontext_t) */ long mc_fpformat; long mc_ownedfp; align(16) long[64] mc_fpstate; __register_t mc_fsbase; __register_t mc_gsbase; long[6] mc_spare; } } else version( X86 ) { alias int __register_t; struct mcontext_t { __register_t mc_onstack; __register_t mc_gs; __register_t mc_fs; __register_t mc_es; __register_t mc_ds; __register_t mc_edi; __register_t mc_esi; __register_t mc_ebp; __register_t mc_isp; __register_t mc_ebx; __register_t mc_edx; __register_t mc_ecx; __register_t mc_eax; __register_t mc_trapno; __register_t mc_err; __register_t mc_eip; __register_t mc_cs; __register_t mc_eflags; __register_t mc_esp; __register_t mc_ss; int mc_len; int mc_fpformat; int mc_ownedfp; int[1] mc_spare1; align(16) int[128] mc_fpstate; __register_t mc_fsbase; __register_t mc_gsbase; int[6] mc_spare2; } } // enum UCF_SWAPPED = 0x00000001; struct ucontext_t { sigset_t uc_sigmask; mcontext_t uc_mcontext; ucontext_t* uc_link; stack_t uc_stack; int uc_flags; int[4] __spare__; } } else version ( Solaris ) { alias uint[4] upad128_t; version ( X86_64 ) { enum _NGREG = 28; alias long greg_t; } else version ( X86 ) { enum _NGREG = 19; alias int greg_t; } alias greg_t[_NGREG] gregset_t; version ( X86_64 ) { union _u_st { ushort[5] fpr_16; upad128_t __fpr_pad; } struct fpregset_t { union fp_reg_set { struct fpchip_state { ushort cw; ushort sw; ubyte fctw; ubyte __fx_rsvd; ushort fop; ulong rip; ulong rdp; uint mxcsr; uint mxcsr_mask; _u_st[8] st; upad128_t[16] xmm; upad128_t[6] __fx_ign2; uint status; uint xstatus; } uint[130] f_fpregs; } } } else version ( X86 ) { struct fpregset_t { union u_fp_reg_set { struct s_fpchip_state { uint[27] state; uint status; uint mxcsr; uint xstatus; uint[2] __pad; upad128_t[8] xmm; } s_fpchip_state fpchip_state; struct s_fp_emul_space { ubyte[246] fp_emul; ubyte[2] fp_epad; } s_fp_emul_space fp_emul_space; uint[95] f_fpregs; } u_fp_reg_set fp_reg_set; } } struct mcontext_t { gregset_t gregs; fpregset_t fpregs; } struct ucontext_t { c_ulong uc_flags; ucontext_t *uc_link; sigset_t uc_sigmask; stack_t uc_stack; mcontext_t uc_mcontext; c_long[5] uc_filler; } } // // Obsolescent (OB) // /* int getcontext(ucontext_t*); void makecontext(ucontext_t*, void function(), int, ...); int setcontext(in ucontext_t*); int swapcontext(ucontext_t*, in ucontext_t*); */ static if( is( ucontext_t ) ) { int getcontext(ucontext_t*); void makecontext(ucontext_t*, void function(), int, ...); int setcontext(in ucontext_t*); int swapcontext(ucontext_t*, in ucontext_t*); } version (Solaris) { int walkcontext(in ucontext_t*, int function(uintptr_t, int, void*), void*); int addrtosymstr(uintptr_t, char*, int); int printstack(int); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/cpuid.d0000664000175000017500000010671012776214756020460 0ustar kaikai/** * Identify the characteristics of the host CPU, providing information * about cache sizes and assembly optimisation hints. This module is * provided primarily for assembly language programmers. * * References: * Some of this information was extremely difficult to track down. Some of the * documents below were found only in cached versions stored by search engines! * This code relies on information found in: * * $(UL * $(LI "Intel(R) 64 and IA-32 Architectures Software Developers Manual, * Volume 2A: Instruction Set Reference, A-M" (2007). * ) * $(LI "AMD CPUID Specification", Advanced Micro Devices, Rev 2.28 (2008). * ) * $(LI "AMD Processor Recognition Application Note For Processors Prior to AMD * Family 0Fh Processors", Advanced Micro Devices, Rev 3.13 (2005). * ) * $(LI "AMD Geode(TM) GX Processors Data Book", * Advanced Micro Devices, Publication ID 31505E, (2005). * ) * $(LI "AMD K6 Processor Code Optimisation", Advanced Micro Devices, Rev D (2000). * ) * $(LI "Application note 106: Software Customization for the 6x86 Family", * Cyrix Corporation, Rev 1.5 (1998) * ) * $(LI $(LINK http://www.datasheetcatalog.org/datasheet/nationalsemiconductor/GX1.pdf)) * $(LI "Geode(TM) GX1 Processor Series Low Power Integrated X86 Solution", * National Semiconductor, (2002) * ) * $(LI "The VIA Isaiah Architecture", G. Glenn Henry, Centaur Technology, Inc (2008). * ) * $(LI $(LINK http://www.sandpile.org/ia32/cpuid.htm)) * $(LI $(LINK http://www.akkadia.org/drepper/cpumemory.pdf)) * $(LI "What every programmer should know about memory", * Ulrich Depper, Red Hat, Inc., (2007). * ) * $(LI "CPU Identification by the Windows Kernel", G. Chappell (2009). * $(LINK http://www.geoffchappell.com/viewer.htm?doc=studies/windows/km/cpu/cx8.htm) * ) * $(LI "Intel(R) Processor Identification and the CPUID Instruction, Application * Note 485" (2009). * ) * ) * * Bugs: Currently only works on x86 and Itanium CPUs. * Many processors have bugs in their microcode for the CPUID instruction, * so sometimes the cache information may be incorrect. * * Copyright: Copyright Don Clugston 2007 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Don Clugston, Tomas Lindquist Olsen <tomas@famolsen.dk> * Source: $(DRUNTIMESRC core/_cpuid.d) */ module core.cpuid; @trusted: nothrow: @nogc: // If optimizing for a particular processor, it is generally better // to identify based on features rather than model. NOTE: Normally // it's only worthwhile to optimise for the latest Intel and AMD CPU, // with a backup for other CPUs. // Pentium -- preferPentium1() // PMMX -- + mmx() // PPro -- default // PII -- + mmx() // PIII -- + mmx() + sse() // PentiumM -- + mmx() + sse() + sse2() // Pentium4 -- preferPentium4() // PentiumD -- + isX86_64() // Core2 -- default + isX86_64() // AMD K5 -- preferPentium1() // AMD K6 -- + mmx() // AMD K6-II -- + mmx() + 3dnow() // AMD K7 -- preferAthlon() // AMD K8 -- + sse2() // AMD K10 -- + isX86_64() // Cyrix 6x86 -- preferPentium1() // 6x86MX -- + mmx() version(D_InlineAsm_X86) { version = InlineAsm_X86_Any; } else version(D_InlineAsm_X86_64) { version = InlineAsm_X86_Any; } public: /// Cache size and behaviour struct CacheInfo { /// Size of the cache, in kilobytes, per CPU. /// For L1 unified (data + code) caches, this size is half the physical size. /// (we don't halve it for larger sizes, since normally /// data size is much greater than code size for critical loops). size_t size; /// Number of ways of associativity, eg: /// $(UL /// $(LI 1 = direct mapped) /// $(LI 2 = 2-way set associative) /// $(LI 3 = 3-way set associative) /// $(LI ubyte.max = fully associative) /// ) ubyte associativity; /// Number of bytes read into the cache when a cache miss occurs. uint lineSize; } public: /// $(RED Scheduled for deprecation. Please use $(D dataCaches) instead.) // Note: When we deprecate it, we simply make it private. __gshared CacheInfo[5] datacache; @property pure { /// The data caches. If there are fewer than 5 physical caches levels, /// the remaining levels are set to size_t.max (== entire memory space) const(CacheInfo)[5] dataCaches() { return _dataCaches; } /// Returns vendor string, for display purposes only. /// Do NOT use this to determine features! /// Note that some CPUs have programmable vendorIDs. string vendor() {return _vendor;} /// Returns processor string, for display purposes only string processor() {return _processor;} /// Does it have an x87 FPU on-chip? bool x87onChip() {return _x87onChip;} /// Is MMX supported? bool mmx() {return _mmx;} /// Is SSE supported? bool sse() {return _sse;} /// Is SSE2 supported? bool sse2() {return _sse2;} /// Is SSE3 supported? bool sse3() {return _sse3;} /// Is SSSE3 supported? bool ssse3() {return _ssse3;} /// Is SSE4.1 supported? bool sse41() {return _sse41;} /// Is SSE4.2 supported? bool sse42() {return _sse42;} /// Is SSE4a supported? bool sse4a() {return _sse4a;} /// Is AES supported bool aes() {return _aes;} /// Is pclmulqdq supported bool hasPclmulqdq() {return _hasPclmulqdq;} /// Is rdrand supported bool hasRdrand() {return _hasRdrand;} /// Is AVX supported bool avx() {return _avx;} /// Is VEX-Encoded AES supported bool vaes() {return _vaes;} /// Is vpclmulqdq supported bool hasVpclmulqdq(){return _hasVpclmulqdq; } /// Is FMA supported bool fma() {return _fma;} /// Is FP16C supported bool fp16c() {return _fp16c;} /// Is AVX2 supported bool avx2() {return _avx2;} /// Is HLE (hardware lock elision) supported bool hle() {return _hle;} /// Is RTM (restricted transactional memory) supported bool rtm() {return _rtm;} /// Is rdseed supported bool hasRdseed() {return _hasRdseed;} /// Is SHA supported bool hasSha() {return _hasSha;} /// Is AMD 3DNOW supported? bool amd3dnow() {return _amd3dnow;} /// Is AMD 3DNOW Ext supported? bool amd3dnowExt() {return _amd3dnowExt;} /// Are AMD extensions to MMX supported? bool amdMmx() {return _amdMmx;} /// Is fxsave/fxrstor supported? bool hasFxsr() {return _hasFxsr;} /// Is cmov supported? bool hasCmov() {return _hasCmov;} /// Is rdtsc supported? bool hasRdtsc() {return _hasRdtsc;} /// Is cmpxchg8b supported? bool hasCmpxchg8b() {return _hasCmpxchg8b;} /// Is cmpxchg8b supported? bool hasCmpxchg16b() {return _hasCmpxchg16b;} /// Is SYSENTER/SYSEXIT supported? bool hasSysEnterSysExit() {return _hasSysEnterSysExit;} /// Is 3DNow prefetch supported? bool has3dnowPrefetch() {return _has3dnowPrefetch;} /// Are LAHF and SAHF supported in 64-bit mode? bool hasLahfSahf() {return _hasLahfSahf;} /// Is POPCNT supported? bool hasPopcnt() {return _hasPopcnt;} /// Is LZCNT supported? bool hasLzcnt() {return _hasLzcnt;} /// Is this an Intel64 or AMD 64? bool isX86_64() {return _isX86_64;} /// Is this an IA64 (Itanium) processor? bool isItanium() { return _isItanium; } /// Is hyperthreading supported? bool hyperThreading() { return _hyperThreading; } /// Returns number of threads per CPU uint threadsPerCPU() {return _threadsPerCPU;} /// Returns number of cores in CPU uint coresPerCPU() {return _coresPerCPU;} /// Optimisation hints for assembly code. /// /// For forward compatibility, the CPU is compared against different /// microarchitectures. For 32-bit x86, comparisons are made against /// the Intel PPro/PII/PIII/PM family. /// /// The major 32-bit x86 microarchitecture 'dynasties' have been: /// /// $(UL /// $(LI Intel P6 (PentiumPro, PII, PIII, PM, Core, Core2). ) /// $(LI AMD Athlon (K7, K8, K10). ) /// $(LI Intel NetBurst (Pentium 4, Pentium D). ) /// $(LI In-order Pentium (Pentium1, PMMX, Atom) ) /// ) /// /// Other early CPUs (Nx586, AMD K5, K6, Centaur C3, Transmeta, /// Cyrix, Rise) were mostly in-order. /// /// Some new processors do not fit into the existing categories: /// /// $(UL /// $(LI Intel Atom 230/330 (family 6, model 0x1C) is an in-order core. ) /// $(LI Centaur Isiah = VIA Nano (family 6, model F) is an out-of-order core. ) /// ) /// /// Within each dynasty, the optimisation techniques are largely /// identical (eg, use instruction pairing for group 4). Major /// instruction set improvements occur within each dynasty. /// Does this CPU perform better on AMD K7 code than PentiumPro..Core2 code? bool preferAthlon() { return _preferAthlon; } /// Does this CPU perform better on Pentium4 code than PentiumPro..Core2 code? bool preferPentium4() { return _preferPentium4; } /// Does this CPU perform better on Pentium I code than Pentium Pro code? bool preferPentium1() { return _preferPentium1; } } private immutable { /* These exist as immutables so that the query property functions can * be backwards compatible with code that called them with (). * Also, immutables can only be set by the static this(). */ const(CacheInfo)[5] _dataCaches; string _vendor; string _processor; bool _x87onChip; bool _mmx; bool _sse; bool _sse2; bool _sse3; bool _ssse3; bool _sse41; bool _sse42; bool _sse4a; bool _aes; bool _hasPclmulqdq; bool _hasRdrand; bool _avx; bool _vaes; bool _hasVpclmulqdq; bool _fma; bool _fp16c; bool _avx2; bool _hle; bool _rtm; bool _hasRdseed; bool _hasSha; bool _amd3dnow; bool _amd3dnowExt; bool _amdMmx; bool _hasFxsr; bool _hasCmov; bool _hasRdtsc; bool _hasCmpxchg8b; bool _hasCmpxchg16b; bool _hasSysEnterSysExit; bool _has3dnowPrefetch; bool _hasLahfSahf; bool _hasPopcnt; bool _hasLzcnt; bool _isX86_64; bool _isItanium; bool _hyperThreading; uint _threadsPerCPU; uint _coresPerCPU; bool _preferAthlon; bool _preferPentium4; bool _preferPentium1; } __gshared: // All these values are set only once, and never subsequently modified. public: /// $(RED Warning: This field will be turned into a property in a future release.) /// /// Processor type (vendor-dependent). /// This should be visible ONLY for display purposes. uint stepping, model, family; /// $(RED This field has been deprecated. Please use $(D cacheLevels) instead.) uint numCacheLevels = 1; /// The number of cache levels in the CPU. @property uint cacheLevels() { return numCacheLevels; } private: struct CpuFeatures { bool probablyIntel; // true = _probably_ an Intel processor, might be faking bool probablyAMD; // true = _probably_ an AMD processor string processorName; char [12] vendorID; char [48] processorNameBuffer; uint features = 0; // mmx, sse, sse2, hyperthreading, etc uint miscfeatures = 0; // sse3, etc. uint extfeatures = 0; // HLE, AVX2, RTM, etc. uint amdfeatures = 0; // 3DNow!, mmxext, etc uint amdmiscfeatures = 0; // sse4a, sse5, svm, etc ulong xfeatures = 0; // XFEATURES_ENABLED_MASK uint maxCores = 1; uint maxThreads = 1; } CpuFeatures cpuFeatures; /* Hide from the optimizer where cf (a register) is coming from, so that * cf doesn't get "optimized away". The idea is to reference * the global data through cf so not so many fixups are inserted * into the executable image. */ CpuFeatures* getCpuFeatures() @nogc nothrow { pragma(inline, false); return &cpuFeatures; } // Note that this may indicate multi-core rather than hyperthreading. @property bool hyperThreadingBit() { return (cpuFeatures.features&HTT_BIT)!=0;} // feature flags CPUID1_EDX enum : uint { FPU_BIT = 1, TIMESTAMP_BIT = 1<<4, // rdtsc MDSR_BIT = 1<<5, // RDMSR/WRMSR CMPXCHG8B_BIT = 1<<8, SYSENTERSYSEXIT_BIT = 1<<11, CMOV_BIT = 1<<15, MMX_BIT = 1<<23, FXSR_BIT = 1<<24, SSE_BIT = 1<<25, SSE2_BIT = 1<<26, HTT_BIT = 1<<28, IA64_BIT = 1<<30 } // feature flags misc CPUID1_ECX enum : uint { SSE3_BIT = 1, PCLMULQDQ_BIT = 1<<1, // from AVX MWAIT_BIT = 1<<3, SSSE3_BIT = 1<<9, FMA_BIT = 1<<12, // from AVX CMPXCHG16B_BIT = 1<<13, SSE41_BIT = 1<<19, SSE42_BIT = 1<<20, POPCNT_BIT = 1<<23, AES_BIT = 1<<25, // AES instructions from AVX OSXSAVE_BIT = 1<<27, // Used for AVX AVX_BIT = 1<<28, FP16C_BIT = 1<<29, RDRAND_BIT = 1<<30, } // Feature flags for cpuid.{EAX = 7, ECX = 0}.EBX. enum : uint { FSGSBASE_BIT = 1 << 0, BMI1_BIT = 1 << 3, HLE_BIT = 1 << 4, AVX2_BIT = 1 << 5, SMEP_BIT = 1 << 7, BMI2_BIT = 1 << 8, ERMS_BIT = 1 << 9, INVPCID_BIT = 1 << 10, RTM_BIT = 1 << 11, RDSEED_BIT = 1 << 18, SHA_BIT = 1 << 29, } // feature flags XFEATURES_ENABLED_MASK enum : ulong { XF_FP_BIT = 0x1, XF_SSE_BIT = 0x2, XF_YMM_BIT = 0x4, } // AMD feature flags CPUID80000001_EDX enum : uint { AMD_MMX_BIT = 1<<22, // FXR_OR_CYRIXMMX_BIT = 1<<24, // Cyrix/NS: 6x86MMX instructions. FFXSR_BIT = 1<<25, PAGE1GB_BIT = 1<<26, // support for 1GB pages RDTSCP_BIT = 1<<27, AMD64_BIT = 1<<29, AMD_3DNOW_EXT_BIT = 1<<30, AMD_3DNOW_BIT = 1<<31 } // AMD misc feature flags CPUID80000001_ECX enum : uint { LAHFSAHF_BIT = 1, LZCNT_BIT = 1<<5, SSE4A_BIT = 1<<6, AMD_3DNOW_PREFETCH_BIT = 1<<8, } version(InlineAsm_X86_Any) { // Note that this code will also work for Itanium in x86 mode. __gshared uint max_cpuid, max_extended_cpuid; // CPUID2: "cache and tlb information" void getcacheinfoCPUID2() { // We are only interested in the data caches void decipherCpuid2(ubyte x) @nogc nothrow { if (x==0) return; // Values from http://www.sandpile.org/ia32/cpuid.htm. // Includes Itanium and non-Intel CPUs. // static immutable ubyte [63] ids = [ 0x0A, 0x0C, 0x0D, 0x2C, 0x60, 0x0E, 0x66, 0x67, 0x68, // level 2 cache 0x41, 0x42, 0x43, 0x44, 0x45, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7F, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x49, 0x4E, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x48, 0x80, 0x81, // level 3 cache 0x22, 0x23, 0x25, 0x29, 0x46, 0x47, 0x4A, 0x4B, 0x4C, 0x4D, 0xD0, 0xD1, 0xD2, 0xD6, 0xD7, 0xD8, 0xDC, 0xDD, 0xDE, 0xE2, 0xE3, 0xE4, 0xEA, 0xEB, 0xEC ]; static immutable uint [63] sizes = [ 8, 16, 16, 64, 16, 24, 8, 16, 32, 128, 256, 512, 1024, 2048, 1024, 128, 256, 512, 1024, 2048, 512, 256, 512, 1024, 2048, 512, 1024, 4096, 6*1024, 128, 192, 128, 256, 384, 512, 3072, 512, 128, 512, 1024, 2048, 4096, 4096, 8192, 6*1024, 8192, 12*1024, 16*1024, 512, 1024, 2048, 1024, 2048, 4096, 1024+512, 3*1024, 6*1024, 2*1024, 4*1024, 8*1024, 12*1024, 28*1024, 24*1024 ]; // CPUBUG: Pentium M reports 0x2C but tests show it is only 4-way associative static immutable ubyte [63] ways = [ 2, 4, 4, 8, 8, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 2, 8, 8, 8, 8, 4, 8, 16, 24, 4, 6, 2, 4, 6, 4, 12, 8, 8, 4, 8, 8, 8, 4, 8, 12, 16, 12, 16, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16, 24, 24, 24 ]; enum { FIRSTDATA2 = 8, FIRSTDATA3 = 28+9 } for (size_t i=0; i< ids.length; ++i) { if (x==ids[i]) { int level = i< FIRSTDATA2 ? 0: i=0x48 && x<=0x80) || x==0x86 || x==0x87 || (x>=0x66 && x<=0x68) || (x>=0x39 && x<=0x3E)){ datacache[level].lineSize = 64; } else datacache[level].lineSize = 32; } } } uint[4] a; bool firstTime = true; // On a multi-core system, this could theoretically fail, but it's only used // for old single-core CPUs. uint numinfos = 1; do { asm pure nothrow @nogc { mov EAX, 2; cpuid; mov a, EAX; mov a+4, EBX; mov a+8, ECX; mov a+12, EDX; } if (firstTime) { if (a[0]==0x0000_7001 && a[3]==0x80 && a[1]==0 && a[2]==0) { // Cyrix MediaGX MMXEnhanced returns: EAX= 00007001, EDX=00000080. // These are NOT standard Intel values // (TLB = 32 entry, 4 way associative, 4K pages) // (L1 cache = 16K, 4way, linesize16) datacache[0].size=8; datacache[0].associativity=4; datacache[0].lineSize=16; return; } // lsb of a is how many times to loop. numinfos = a[0] & 0xFF; // and otherwise it should be ignored a[0] &= 0xFFFF_FF00; firstTime = false; } for (int c=0; c<4;++c) { // high bit set == no info. if (a[c] & 0x8000_0000) continue; decipherCpuid2(cast(ubyte)(a[c] & 0xFF)); decipherCpuid2(cast(ubyte)((a[c]>>8) & 0xFF)); decipherCpuid2(cast(ubyte)((a[c]>>16) & 0xFF)); decipherCpuid2(cast(ubyte)((a[c]>>24) & 0xFF)); } } while (--numinfos); } // CPUID4: "Deterministic cache parameters" leaf void getcacheinfoCPUID4() { int cachenum = 0; for(;;) { uint a, b, number_of_sets; asm pure nothrow @nogc { mov EAX, 4; mov ECX, cachenum; cpuid; mov a, EAX; mov b, EBX; mov number_of_sets, ECX; } ++cachenum; if ((a&0x1F)==0) break; // no more caches uint numthreads = ((a>>14) & 0xFFF) + 1; uint numcores = ((a>>26) & 0x3F) + 1; if (numcores > cpuFeatures.maxCores) cpuFeatures.maxCores = numcores; if ((a&0x1F)!=1 && ((a&0x1F)!=3)) continue; // we only want data & unified caches ++number_of_sets; ubyte level = cast(ubyte)(((a>>5)&7)-1); if (level > datacache.length) continue; // ignore deep caches datacache[level].associativity = a & 0x200 ? ubyte.max :cast(ubyte)((b>>22)+1); datacache[level].lineSize = (b & 0xFFF)+ 1; // system coherency line size uint line_partitions = ((b >> 12)& 0x3FF) + 1; // Size = number of sets * associativity * cachelinesize * linepartitions // and must convert to Kb, also dividing by the number of hyperthreads using this cache. ulong sz = (datacache[level].associativity< ubyte.max)? number_of_sets * datacache[level].associativity : number_of_sets; datacache[level].size = cast(uint)( (sz * datacache[level].lineSize * line_partitions ) / (numthreads *1024)); if (level == 0 && (a&0xF)==3) { // Halve the size for unified L1 caches datacache[level].size/=2; } } } // CPUID8000_0005 & 6 void getAMDcacheinfo() { uint c5, c6, d6; asm pure nothrow @nogc { mov EAX, 0x8000_0005; // L1 cache cpuid; // EAX has L1_TLB_4M. // EBX has L1_TLB_4K // EDX has L1 instruction cache mov c5, ECX; } datacache[0].size = ( (c5>>24) & 0xFF); datacache[0].associativity = cast(ubyte)( (c5 >> 16) & 0xFF); datacache[0].lineSize = c5 & 0xFF; if (max_extended_cpuid >= 0x8000_0006) { // AMD K6-III or K6-2+ or later. ubyte numcores = 1; if (max_extended_cpuid >=0x8000_0008) { asm pure nothrow @nogc { mov EAX, 0x8000_0008; cpuid; mov numcores, CL; } ++numcores; if (numcores>cpuFeatures.maxCores) cpuFeatures.maxCores = numcores; } asm pure nothrow @nogc { mov EAX, 0x8000_0006; // L2/L3 cache cpuid; mov c6, ECX; // L2 cache info mov d6, EDX; // L3 cache info } static immutable ubyte [] assocmap = [ 0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, 0xFF ]; datacache[1].size = (c6>>16) & 0xFFFF; datacache[1].associativity = assocmap[(c6>>12)&0xF]; datacache[1].lineSize = c6 & 0xFF; // The L3 cache value is TOTAL, not per core. datacache[2].size = ((d6>>18)*512)/numcores; // could be up to 2 * this, -1. datacache[2].associativity = assocmap[(d6>>12)&0xF]; datacache[2].lineSize = d6 & 0xFF; } } // For Intel CoreI7 and later, use function 0x0B // to determine number of processors. void getCpuInfo0B() { int level=0; int threadsPerCore; uint a, b, c, d; do { asm pure nothrow @nogc { mov EAX, 0x0B; mov ECX, level; cpuid; mov a, EAX; mov b, EBX; mov c, ECX; mov d, EDX; } if (b!=0) { // I'm not sure about this. The docs state that there // are 2 hyperthreads per core if HT is factory enabled. if (level==0) threadsPerCore = b & 0xFFFF; else if (level==1) { cpuFeatures.maxThreads = b & 0xFFFF; cpuFeatures.maxCores = cpuFeatures.maxThreads / threadsPerCore; } } ++level; } while (a!=0 || b!=0); } void cpuidX86() { auto cf = getCpuFeatures(); char * venptr = cf.vendorID.ptr; uint a, b, c, d, a2; version(D_InlineAsm_X86) { asm pure nothrow @nogc { mov EAX, 0; cpuid; mov a, EAX; mov EAX, venptr; mov [EAX], EBX; mov [EAX + 4], EDX; mov [EAX + 8], ECX; } } else version(D_InlineAsm_X86_64) { asm pure nothrow @nogc { mov EAX, 0; cpuid; mov a, EAX; mov RAX, venptr; mov [RAX], EBX; mov [RAX + 4], EDX; mov [RAX + 8], ECX; } } asm pure nothrow @nogc { mov EAX, 0x8000_0000; cpuid; mov a2, EAX; } max_cpuid = a; max_extended_cpuid = a2; cf.probablyIntel = cf.vendorID == "GenuineIntel"; cf.probablyAMD = cf.vendorID == "AuthenticAMD"; uint apic = 0; // brand index, apic id asm pure nothrow @nogc { mov EAX, 1; // model, stepping cpuid; mov a, EAX; mov apic, EBX; mov c, ECX; mov d, EDX; } cf.features = d; cf.miscfeatures = c; if (max_cpuid >= 7) { uint ext; asm pure nothrow @nogc { mov EAX, 7; // Structured extended feature leaf. mov ECX, 0; // Main leaf. cpuid; mov ext, EBX; // HLE, AVX2, RTM, etc. } cf.extfeatures = ext; } if (cf.miscfeatures & OSXSAVE_BIT) { asm pure nothrow @nogc { mov ECX, 0; xgetbv; mov d, EDX; mov a, EAX; } cf.xfeatures = cast(ulong)d << 32 | a; } cf.amdfeatures = 0; cf.amdmiscfeatures = 0; if (max_extended_cpuid >= 0x8000_0001) { asm pure nothrow @nogc { mov EAX, 0x8000_0001; cpuid; mov c, ECX; mov d, EDX; } cf.amdmiscfeatures = c; cf.amdfeatures = d; } // Try to detect fraudulent vendorIDs if (amd3dnow) cf.probablyIntel = false; stepping = a & 0xF; uint fbase = (a >> 8) & 0xF; uint mbase = (a >> 4) & 0xF; family = ((fbase == 0xF) || (fbase == 0)) ? fbase + (a >> 20) & 0xFF : fbase; model = ((fbase == 0xF) || (fbase == 6 && cf.probablyIntel) ) ? mbase + ((a >> 12) & 0xF0) : mbase; if (!cf.probablyIntel && max_extended_cpuid >= 0x8000_0008) { // determine max number of cores for AMD asm pure nothrow @nogc { mov EAX, 0x8000_0008; cpuid; mov c, ECX; } //http://support.amd.com/TechDocs/25481.pdf pg.36 cf.maxCores = 1; if (hyperThreadingBit) { cf.maxCores += c & 0xFF; } } if (max_extended_cpuid >= 0x8000_0004) { char *procptr = cf.processorNameBuffer.ptr; version(D_InlineAsm_X86) { asm pure nothrow @nogc { push ESI; mov ESI, procptr; mov EAX, 0x8000_0002; cpuid; mov [ESI], EAX; mov [ESI+4], EBX; mov [ESI+8], ECX; mov [ESI+12], EDX; mov EAX, 0x8000_0003; cpuid; mov [ESI+16], EAX; mov [ESI+20], EBX; mov [ESI+24], ECX; mov [ESI+28], EDX; mov EAX, 0x8000_0004; cpuid; mov [ESI+32], EAX; mov [ESI+36], EBX; mov [ESI+40], ECX; mov [ESI+44], EDX; pop ESI; } } else version(D_InlineAsm_X86_64) { asm pure nothrow @nogc { push RSI; mov RSI, procptr; mov EAX, 0x8000_0002; cpuid; mov [RSI], EAX; mov [RSI+4], EBX; mov [RSI+8], ECX; mov [RSI+12], EDX; mov EAX, 0x8000_0003; cpuid; mov [RSI+16], EAX; mov [RSI+20], EBX; mov [RSI+24], ECX; mov [RSI+28], EDX; mov EAX, 0x8000_0004; cpuid; mov [RSI+32], EAX; mov [RSI+36], EBX; mov [RSI+40], ECX; mov [RSI+44], EDX; pop RSI; } } // Intel P4 and PM pad at front with spaces. // Other CPUs pad at end with nulls. int start = 0, end = 0; while (cf.processorNameBuffer[start] == ' ') { ++start; } while (cf.processorNameBuffer[cf.processorNameBuffer.length-end-1] == 0) { ++end; } cf.processorName = cast(string)(cf.processorNameBuffer[start..$-end]); } else { cf.processorName = "Unknown CPU"; } // Determine cache sizes // Intel docs specify that they return 0 for 0x8000_0005. // AMD docs do not specify the behaviour for 0004 and 0002. // Centaur/VIA and most other manufacturers use the AMD method, // except Cyrix MediaGX MMX Enhanced uses their OWN form of CPUID2! // NS Geode GX1 provides CyrixCPUID2 _and_ does the same wrong behaviour // for CPUID80000005. But Geode GX uses the AMD method // Deal with Geode GX1 - make it same as MediaGX MMX. if (max_extended_cpuid==0x8000_0005 && max_cpuid==2) { max_extended_cpuid = 0x8000_0004; } // Therefore, we try the AMD method unless it's an Intel chip. // If we still have no info, try the Intel methods. datacache[0].size = 0; if (max_cpuid<2 || !cf.probablyIntel) { if (max_extended_cpuid >= 0x8000_0005) { getAMDcacheinfo(); } else if (cf.probablyAMD) { // According to AMDProcRecognitionAppNote, this means CPU // K5 model 0, or Am5x86 (model 4), or Am4x86DX4 (model 4) // Am5x86 has 16Kb 4-way unified data & code cache. datacache[0].size = 8; datacache[0].associativity = 4; datacache[0].lineSize = 32; } else { // Some obscure CPU. // Values for Cyrix 6x86MX (family 6, model 0) datacache[0].size = 64; datacache[0].associativity = 4; datacache[0].lineSize = 32; } } if ((datacache[0].size == 0) && max_cpuid>=4) { getcacheinfoCPUID4(); } if ((datacache[0].size == 0) && max_cpuid>=2) { getcacheinfoCPUID2(); } if (datacache[0].size == 0) { // Pentium, PMMX, late model 486, or an obscure CPU if (mmx) { // Pentium MMX. Also has 8kB code cache. datacache[0].size = 16; datacache[0].associativity = 4; datacache[0].lineSize = 32; } else { // Pentium 1 (which also has 8kB code cache) // or 486. // Cyrix 6x86: 16, 4way, 32 linesize datacache[0].size = 8; datacache[0].associativity = 2; datacache[0].lineSize = 32; } } if (max_cpuid >=0x0B) { // For Intel i7 and later, use function 0x0B to determine // cores and hyperthreads. getCpuInfo0B(); } else { if (hyperThreadingBit) cf.maxThreads = (apic>>>16) & 0xFF; else cf.maxThreads = cf.maxCores; } } // Return true if the cpuid instruction is supported. // BUG(WONTFIX): Returns false for Cyrix 6x86 and 6x86L. They will be treated as 486 machines. bool hasCPUID() { version(D_InlineAsm_X86_64) return true; else version(LDC) { size_t flags; asm @nogc nothrow { pushf; pop EAX; mov flags, EAX; xor EAX, 0x0020_0000; push EAX; popf; pushf; pop EAX; xor flags, EAX; } return (flags & 0x0020_0000) != 0; } else version(D_InlineAsm_X86) { uint flags; asm nothrow @nogc { pushfd; pop EAX; mov flags, EAX; xor EAX, 0x0020_0000; push EAX; popfd; pushfd; pop EAX; xor flags, EAX; } return (flags & 0x0020_0000) !=0; } } } else { // inline asm X86 bool hasCPUID() { return false; } void cpuidX86() { datacache[0].size = 8; datacache[0].associativity = 2; datacache[0].lineSize = 32; } } /* // TODO: Implement this function with OS support void cpuidPPC() { enum :int { PPC601, PPC603, PPC603E, PPC604, PPC604E, PPC620, PPCG3, PPCG4, PPCG5 } // TODO: // asm { mfpvr; } returns the CPU version but unfortunately it can // only be used in kernel mode. So OS support is required. int cputype = PPC603; // 601 has a 8KB combined data & code L1 cache. uint sizes[] = [4, 8, 16, 16, 32, 32, 32, 32, 64]; ubyte ways[] = [8, 2, 4, 4, 4, 8, 8, 8, 8]; uint L2size[]= [0, 0, 0, 0, 0, 0, 0, 256, 512]; uint L3size[]= [0, 0, 0, 0, 0, 0, 0, 2048, 0]; datacache[0].size = sizes[cputype]; datacache[0].associativity = ways[cputype]; datacache[0].lineSize = (cputype==PPCG5)? 128 : (cputype == PPC620 || cputype == PPCG3)? 64 : 32; datacache[1].size = L2size[cputype]; datacache[2].size = L3size[cputype]; datacache[1].lineSize = datacache[0].lineSize; datacache[2].lineSize = datacache[0].lineSize; } // TODO: Implement this function with OS support void cpuidSparc() { // UltaSparcIIi : L1 = 16, 2way. L2 = 512, 4 way. // UltraSparcIII : L1 = 64, 4way. L2= 4096 or 8192. // UltraSparcIIIi: L1 = 64, 4way. L2= 1024, 4 way // UltraSparcIV : L1 = 64, 4way. L2 = 16*1024. // UltraSparcIV+ : L1 = 64, 4way. L2 = 2048, L3=32*1024. // Sparc64V : L1 = 128, 2way. L2 = 4096 4way. } */ shared static this() { auto cf = getCpuFeatures(); if (hasCPUID()) { cpuidX86(); } else { // it's a 386 or 486, or a Cyrix 6x86. //Probably still has an external cache. } if (datacache[0].size==0) { // Guess same as Pentium 1. datacache[0].size = 8; datacache[0].associativity = 2; datacache[0].lineSize = 32; } numCacheLevels = 1; // And now fill up all the unused levels with full memory space. for (size_t i=1; i< datacache.length; ++i) { if (datacache[i].size==0) { // Set all remaining levels of cache equal to full address space. datacache[i].size = size_t.max/1024; datacache[i].associativity = 1; datacache[i].lineSize = datacache[i-1].lineSize; } else ++numCacheLevels; } // Set the immortals _dataCaches = datacache; _vendor = cast(string)cf.vendorID; _processor = cf.processorName; _x87onChip = (cf.features&FPU_BIT)!=0; _mmx = (cf.features&MMX_BIT)!=0; _sse = (cf.features&SSE_BIT)!=0; _sse2 = (cf.features&SSE2_BIT)!=0; _sse3 = (cf.miscfeatures&SSE3_BIT)!=0; _ssse3 = (cf.miscfeatures&SSSE3_BIT)!=0; _sse41 = (cf.miscfeatures&SSE41_BIT)!=0; _sse42 = (cf.miscfeatures&SSE42_BIT)!=0; _sse4a = (cf.amdmiscfeatures&SSE4A_BIT)!=0; _aes = (cf.miscfeatures&AES_BIT)!=0; _hasPclmulqdq = (cf.miscfeatures&PCLMULQDQ_BIT)!=0; _hasRdrand = (cf.miscfeatures&RDRAND_BIT)!=0; enum avx_mask = XF_SSE_BIT|XF_YMM_BIT; _avx = (cf.xfeatures & avx_mask) == avx_mask && (cf.miscfeatures&AVX_BIT)!=0; _vaes = avx && aes; _hasVpclmulqdq = avx && hasPclmulqdq; _fma = avx && (cf.miscfeatures&FMA_BIT)!=0; _fp16c = avx && (cf.miscfeatures&FP16C_BIT)!=0; _avx2 = avx && (cf.extfeatures & AVX2_BIT) != 0; _hle = (cf.extfeatures & HLE_BIT) != 0; _rtm = (cf.extfeatures & RTM_BIT) != 0; _hasRdseed = (cf.extfeatures&RDSEED_BIT)!=0; _hasSha = (cf.extfeatures&SHA_BIT)!=0; _amd3dnow = (cf.amdfeatures&AMD_3DNOW_BIT)!=0; _amd3dnowExt = (cf.amdfeatures&AMD_3DNOW_EXT_BIT)!=0; _amdMmx = (cf.amdfeatures&AMD_MMX_BIT)!=0; _hasFxsr = (cf.features&FXSR_BIT)!=0; _hasCmov = (cf.features&CMOV_BIT)!=0; _hasRdtsc = (cf.features&TIMESTAMP_BIT)!=0; _hasCmpxchg8b = (cf.features&CMPXCHG8B_BIT)!=0; _hasCmpxchg16b = (cf.miscfeatures&CMPXCHG16B_BIT)!=0; _hasSysEnterSysExit = // The SYSENTER/SYSEXIT features were buggy on Pentium Pro and early PentiumII. // (REF: www.geoffchappell.com). (cf.probablyIntel && (family < 6 || (family==6 && (model< 3 || (model==3 && stepping<3))))) ? false : (cf.features & SYSENTERSYSEXIT_BIT)!=0; _has3dnowPrefetch = (cf.amdmiscfeatures&AMD_3DNOW_PREFETCH_BIT)!=0; _hasLahfSahf = (cf.amdmiscfeatures&LAHFSAHF_BIT)!=0; _hasPopcnt = (cf.miscfeatures&POPCNT_BIT)!=0; _hasLzcnt = (cf.amdmiscfeatures&LZCNT_BIT)!=0; _isX86_64 = (cf.amdfeatures&AMD64_BIT)!=0; _isItanium = (cf.features&IA64_BIT)!=0; _hyperThreading = cf.maxThreads>cf.maxCores; _threadsPerCPU = cf.maxThreads; _coresPerCPU = cf.maxCores; _preferAthlon = cf.probablyAMD && family >=6; _preferPentium4 = cf.probablyIntel && family == 0xF; _preferPentium1 = family < 6 || (family==6 && model < 0xF && !cf.probablyIntel); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/attribute.d0000664000175000017500000000334012776214756021352 0ustar kaikai/** * This module contains UDA's (User Defined Attributes) either used in * the runtime or special UDA's recognized by compiler. * * Copyright: Copyright Jacob Carlborg 2015. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Jacob Carlborg * Source: $(DRUNTIMESRC core/_attribute.d) */ /* Copyright Jacob Carlborg 2015. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module core.attribute; /** * Use this attribute to attach an Objective-C selector to a method. * * This is a special compiler recognized attribute, it has several * requirements, which all will be enforced by the compiler: * * $(UL * $(LI * The attribute can only be attached to methods or constructors which * have Objective-C linkage. That is, a method or a constructor in a * class or interface declared as $(D_CODE extern(Objective-C)). * ), * * $(LI It cannot be attached to a method or constructor that is a template), * * $(LI * The number of colons in the string need to match the number of * arguments the method accept. * ), * * $(LI It can only be used once in a method declaration) * ) * * Examples: * --- * extern (Objective-C) * class NSObject * { * this() @selector("init"); * static NSObject alloc() @selector("alloc"); * NSObject initWithUTF8String(in char* str) @selector("initWithUTF8String:"); * ObjcObject copyScriptingValue(ObjcObject value, NSString key, NSDictionary properties) * @selector("copyScriptingValue:forKey:withProperties:"); * } * --- */ version (D_ObjectiveC) struct selector { string selector; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/exception.d0000664000175000017500000004654512776214756021363 0ustar kaikai/** * The exception module defines all system-level exceptions and provides a * mechanism to alter system-level error handling. * * Copyright: Copyright Sean Kelly 2005 - 2013. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly and Jonathan M Davis * Source: $(DRUNTIMESRC core/_exception.d) */ module core.exception; /** * Thrown on a range error. */ class RangeError : Error { @safe pure nothrow this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) { super( "Range violation", file, line, next ); } } unittest { { auto re = new RangeError(); assert(re.file == __FILE__); assert(re.line == __LINE__ - 2); assert(re.next is null); assert(re.msg == "Range violation"); } { auto re = new RangeError("hello", 42, new Exception("It's an Exception!")); assert(re.file == "hello"); assert(re.line == 42); assert(re.next !is null); assert(re.msg == "Range violation"); } } /** * Thrown on an assert error. */ class AssertError : Error { @safe pure nothrow this( string file, size_t line ) { this(cast(Throwable)null, file, line); } @safe pure nothrow this( Throwable next, string file = __FILE__, size_t line = __LINE__ ) { this( "Assertion failure", file, line, next); } @safe pure nothrow this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) { super( msg, file, line, next ); } } unittest { { auto ae = new AssertError("hello", 42); assert(ae.file == "hello"); assert(ae.line == 42); assert(ae.next is null); assert(ae.msg == "Assertion failure"); } { auto ae = new AssertError(new Exception("It's an Exception!")); assert(ae.file == __FILE__); assert(ae.line == __LINE__ - 2); assert(ae.next !is null); assert(ae.msg == "Assertion failure"); } { auto ae = new AssertError(new Exception("It's an Exception!"), "hello", 42); assert(ae.file == "hello"); assert(ae.line == 42); assert(ae.next !is null); assert(ae.msg == "Assertion failure"); } { auto ae = new AssertError("msg"); assert(ae.file == __FILE__); assert(ae.line == __LINE__ - 2); assert(ae.next is null); assert(ae.msg == "msg"); } { auto ae = new AssertError("msg", "hello", 42); assert(ae.file == "hello"); assert(ae.line == 42); assert(ae.next is null); assert(ae.msg == "msg"); } { auto ae = new AssertError("msg", "hello", 42, new Exception("It's an Exception!")); assert(ae.file == "hello"); assert(ae.line == 42); assert(ae.next !is null); assert(ae.msg == "msg"); } } /** * Thrown on finalize error. */ class FinalizeError : Error { TypeInfo info; this( TypeInfo ci, Throwable next, string file = __FILE__, size_t line = __LINE__ ) @safe pure nothrow @nogc { this(ci, file, line, next); } this( TypeInfo ci, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc { super( "Finalization error", file, line, next ); super.info = SuppressTraceInfo.instance; info = ci; } override string toString() const @safe { return "An exception was thrown while finalizing an instance of " ~ info.toString(); } } unittest { ClassInfo info = new ClassInfo; info.name = "testInfo"; { auto fe = new FinalizeError(info); assert(fe.file == __FILE__); assert(fe.line == __LINE__ - 2); assert(fe.next is null); assert(fe.msg == "Finalization error"); assert(fe.info == info); } { auto fe = new FinalizeError(info, new Exception("It's an Exception!")); assert(fe.file == __FILE__); assert(fe.line == __LINE__ - 2); assert(fe.next !is null); assert(fe.msg == "Finalization error"); assert(fe.info == info); } { auto fe = new FinalizeError(info, "hello", 42); assert(fe.file == "hello"); assert(fe.line == 42); assert(fe.next is null); assert(fe.msg == "Finalization error"); assert(fe.info == info); } { auto fe = new FinalizeError(info, "hello", 42, new Exception("It's an Exception!")); assert(fe.file == "hello"); assert(fe.line == 42); assert(fe.next !is null); assert(fe.msg == "Finalization error"); assert(fe.info == info); } } /** * Thrown on hidden function error. * $(RED Deprecated. * This feature is not longer part of the language.) */ deprecated class HiddenFuncError : Error { @safe pure nothrow this( ClassInfo ci ) { super( "Hidden method called for " ~ ci.name ); } } deprecated unittest { ClassInfo info = new ClassInfo; info.name = "testInfo"; { auto hfe = new HiddenFuncError(info); assert(hfe.next is null); assert(hfe.msg == "Hidden method called for testInfo"); } } /** * Thrown on an out of memory error. */ class OutOfMemoryError : Error { this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc { this(true, file, line, next); } this(bool trace, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc { super("Memory allocation failed", file, line, next); if (!trace) this.info = SuppressTraceInfo.instance; } override string toString() const @trusted { return msg.length ? (cast()this).superToString() : "Memory allocation failed"; } // kludge to call non-const super.toString private string superToString() @trusted { return super.toString(); } } unittest { { auto oome = new OutOfMemoryError(); assert(oome.file == __FILE__); assert(oome.line == __LINE__ - 2); assert(oome.next is null); assert(oome.msg == "Memory allocation failed"); assert(oome.toString.length); } { auto oome = new OutOfMemoryError("hello", 42, new Exception("It's an Exception!")); assert(oome.file == "hello"); assert(oome.line == 42); assert(oome.next !is null); assert(oome.msg == "Memory allocation failed"); } } /** * Thrown on an invalid memory operation. * * An invalid memory operation error occurs in circumstances when the garbage * collector has detected an operation it cannot reliably handle. The default * D GC is not re-entrant, so this can happen due to allocations done from * within finalizers called during a garbage collection cycle. */ class InvalidMemoryOperationError : Error { this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc { super( "Invalid memory operation", file, line, next ); this.info = SuppressTraceInfo.instance; } override string toString() const @trusted { return msg.length ? (cast()this).superToString() : "Invalid memory operation"; } // kludge to call non-const super.toString private string superToString() @trusted { return super.toString(); } } unittest { { auto oome = new InvalidMemoryOperationError(); assert(oome.file == __FILE__); assert(oome.line == __LINE__ - 2); assert(oome.next is null); assert(oome.msg == "Invalid memory operation"); assert(oome.toString.length); } { auto oome = new InvalidMemoryOperationError("hello", 42, new Exception("It's an Exception!")); assert(oome.file == "hello"); assert(oome.line == 42); assert(oome.next !is null); assert(oome.msg == "Invalid memory operation"); } } /** * Thrown on a switch error. */ class SwitchError : Error { @safe pure nothrow this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) { super( "No appropriate switch clause found", file, line, next ); } } unittest { { auto se = new SwitchError(); assert(se.file == __FILE__); assert(se.line == __LINE__ - 2); assert(se.next is null); assert(se.msg == "No appropriate switch clause found"); } { auto se = new SwitchError("hello", 42, new Exception("It's an Exception!")); assert(se.file == "hello"); assert(se.line == 42); assert(se.next !is null); assert(se.msg == "No appropriate switch clause found"); } } /** * Thrown on a unicode conversion error. */ class UnicodeException : Exception { size_t idx; this( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow { super( msg, file, line, next ); this.idx = idx; } } unittest { { auto ue = new UnicodeException("msg", 2); assert(ue.file == __FILE__); assert(ue.line == __LINE__ - 2); assert(ue.next is null); assert(ue.msg == "msg"); assert(ue.idx == 2); } { auto ue = new UnicodeException("msg", 2, "hello", 42, new Exception("It's an Exception!")); assert(ue.file == "hello"); assert(ue.line == 42); assert(ue.next !is null); assert(ue.msg == "msg"); assert(ue.idx == 2); } } /////////////////////////////////////////////////////////////////////////////// // Overrides /////////////////////////////////////////////////////////////////////////////// // NOTE: One assert handler is used for all threads. Thread-local // behavior should occur within the handler itself. This delegate // is __gshared for now based on the assumption that it will only // set by the main thread during program initialization. private __gshared AssertHandler _assertHandler = null; /** Gets/sets assert hander. null means the default handler is used. */ alias AssertHandler = void function(string file, size_t line, string msg) nothrow; /// ditto @property AssertHandler assertHandler() @trusted nothrow @nogc { return _assertHandler; } /// ditto @property void assertHandler(AssertHandler handler) @trusted nothrow @nogc { _assertHandler = handler; } /** * Overrides the default assert hander with a user-supplied version. * $(RED Deprecated. * Please use $(LREF assertHandler) instead.) * * Params: * h = The new assert handler. Set to null to use the default handler. */ deprecated void setAssertHandler( AssertHandler h ) @trusted nothrow @nogc { assertHandler = 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 $(LREF AssertError) 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( string file = __FILE__, size_t line = __LINE__ ) nothrow { if( _assertHandler is null ) throw new AssertError( file, line ); _assertHandler( file, line, null); } /** * A callback for assert errors in D. The user-supplied assert handler will * be called if one has been supplied, otherwise an $(LREF AssertError) 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( string file, size_t line, string msg ) nothrow { if( _assertHandler is null ) throw new AssertError( msg, file, line ); _assertHandler( file, line, msg ); } /** * A callback for unittest errors in D. The user-supplied unittest handler * will be called if one has been supplied, otherwise the error will be * written to stderr. * * 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 onUnittestErrorMsg( string file, size_t line, string msg ) nothrow { onAssertErrorMsg( file, line, msg ); } /////////////////////////////////////////////////////////////////////////////// // Internal Error Callbacks /////////////////////////////////////////////////////////////////////////////// /** * A callback for array bounds errors in D. A $(LREF RangeError) will be thrown. * * Params: * file = The name of the file that signaled this error. * line = The line number on which this error occurred. * * Throws: * $(LREF RangeError). */ extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @safe pure nothrow { throw new RangeError( file, line, null ); } /** * A callback for finalize errors in D. A $(LREF FinalizeError) will be thrown. * * Params: * info = The TypeInfo instance for the object that failed finalization. * e = The exception thrown during finalization. * file = The name of the file that signaled this error. * line = The line number on which this error occurred. * * Throws: * $(LREF FinalizeError). */ extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow { // This error is thrown during a garbage collection, so no allocation must occur while // generating this object. So we use a preallocated instance throw staticError!FinalizeError(info, e, file, line); } /** * A callback for hidden function errors in D. A $(LREF HiddenFuncError) will be * thrown. * $(RED Deprecated. * This feature is not longer part of the language.) * * Throws: * $(LREF HiddenFuncError). */ deprecated extern (C) void onHiddenFuncError( Object o ) @safe pure nothrow { throw new HiddenFuncError( typeid(o) ); } /** * A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be * thrown. * * Throws: * $(LREF OutOfMemoryError). */ extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ { // NOTE: Since an out of memory condition exists, no allocation must occur // while generating this object. throw staticError!OutOfMemoryError(); } extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc { // suppress stacktrace until they are @nogc throw staticError!OutOfMemoryError(false); } /** * A callback for invalid memory operations in D. An * $(LREF InvalidMemoryOperationError) will be thrown. * * Throws: * $(LREF InvalidMemoryOperationError). */ extern (C) void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ { // The same restriction applies as for onOutOfMemoryError. The GC is in an // undefined state, thus no allocation must occur while generating this object. throw staticError!InvalidMemoryOperationError(); } /** * A callback for switch errors in D. A $(LREF SwitchError) will be thrown. * * Params: * file = The name of the file that signaled this error. * line = The line number on which this error occurred. * * Throws: * $(LREF SwitchError). */ extern (C) void onSwitchError( string file = __FILE__, size_t line = __LINE__ ) @safe pure nothrow { throw new SwitchError( file, line, null ); } /** * A callback for unicode errors in D. A $(LREF UnicodeException) will be thrown. * * Params: * msg = Information about the error. * idx = String index where this error was detected. * file = The name of the file that signaled this error. * line = The line number on which this error occurred. * * Throws: * $(LREF UnicodeException). */ extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure { throw new UnicodeException( msg, idx, file, line ); } /*********************************** * These functions must be defined for any D program linked * against this library. */ /+ extern (C) void onAssertError(string file, size_t line); extern (C) void onAssertErrorMsg(string file, size_t line, string msg); extern (C) void onUnittestErrorMsg(string file, size_t line, string msg); extern (C) void onRangeError(string file, size_t line); extern (C) void onHiddenFuncError(Object o); extern (C) void onSwitchError(string file, size_t line); +/ /*********************************** * Function calls to these are generated by the compiler and inserted into * the object code. */ extern (C) { // Use ModuleInfo to get file name for "m" versions /* One of these three is called upon an assert() fail. */ void _d_assertm(immutable(ModuleInfo)* m, uint line) { onAssertError(m.name, line); } void _d_assert_msg(string msg, string file, uint line) { onAssertErrorMsg(file, line, msg); } void _d_assert(string file, uint line) { onAssertError(file, line); } /* One of these three is called upon an assert() fail inside of a unittest block */ void _d_unittestm(immutable(ModuleInfo)* m, uint line) { _d_unittest(m.name, line); } void _d_unittest_msg(string msg, string file, uint line) { onUnittestErrorMsg(file, line, msg); } void _d_unittest(string file, uint line) { _d_unittest_msg("unittest failure", file, line); } /* Called when an array index is out of bounds */ void _d_array_bounds(immutable(ModuleInfo)* m, uint line) { onRangeError(m.name, line); } void _d_arraybounds(string file, uint line) { onRangeError(file, line); } /* Called when a switch statement has no DefaultStatement, yet none of the cases match */ void _d_switch_error(immutable(ModuleInfo)* m, uint line) { onSwitchError(m.name, line); } } // TLS storage shared for all errors, chaining might create circular reference private void[128] _store; // only Errors for now as those are rarely chained private T staticError(T, Args...)(auto ref Args args) if (is(T : Error)) { // pure hack, what we actually need is @noreturn and allow to call that in pure functions static T get() { static assert(__traits(classInstanceSize, T) <= _store.length, T.stringof ~ " is too large for staticError()"); _store[0 .. __traits(classInstanceSize, T)] = typeid(T).initializer[]; return cast(T) _store.ptr; } auto res = (cast(T function() @trusted pure nothrow @nogc) &get)(); res.__ctor(args); return res; } // Suppress traceinfo generation when the GC cannot be used. Workaround for // Bugzilla 14993. We should make stack traces @nogc instead. package class SuppressTraceInfo : Throwable.TraceInfo { override int opApply(scope int delegate(ref const(char[]))) const { return 0; } override int opApply(scope int delegate(ref size_t, ref const(char[]))) const { return 0; } override string toString() const { return null; } static SuppressTraceInfo instance() @trusted @nogc pure nothrow { static immutable SuppressTraceInfo it = new SuppressTraceInfo; return cast(SuppressTraceInfo)it; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/internal/0000775000175000017500000000000012776214756021016 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/core/internal/convert.d0000664000175000017500000004252612776214756022654 0ustar kaikai/** * Written in the D programming language. * This module provides functions to converting different values to const(ubyte)[] * * Copyright: Copyright Igor Stepanov 2013-2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Igor Stepanov * Source: $(DRUNTIMESRC core/internal/_convert.d) */ module core.internal.convert; import core.internal.traits : Unqual; @trusted pure nothrow const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T == double) || is(Unqual!T == real) || is(Unqual!T == ifloat) || is(Unqual!T == idouble) || is(Unqual!T == ireal)) { static const(ubyte)[] reverse_(const(ubyte)[] arr) { ubyte[] buff = new ubyte[arr.length]; foreach(k, v; arr) { buff[$-k-1] = v; } return buff; } if(__ctfe) { auto parsed = parse(val); ulong mantissa = parsed.mantissa; uint exp = parsed.exponent; uint sign = parsed.sign; ubyte[T.sizeof] buff; size_t off_bytes = 0; size_t off_bits = 0; for(; off_bytes < FloatTraits!T.MANTISSA/8; ++off_bytes) { buff[off_bytes] = cast(ubyte)mantissa; mantissa >>= 8; } off_bits = FloatTraits!T.MANTISSA%8; buff[off_bytes] = cast(ubyte)mantissa; for(size_t i=0; i>= 8; buff[off_bytes] |= (cur_exp << off_bits); ++off_bytes; buff[off_bytes] |= cur_exp >> 8 - off_bits; } exp <<= 8 - FloatTraits!T.EXPONENT%8 - 1; buff[off_bytes] |= exp; sign <<= 7; buff[off_bytes] |= sign; version(LittleEndian) { return buff.dup; } else { return reverse_(buff); } } else { return (cast(const(ubyte)*)&val)[0 .. T.sizeof]; } } @safe pure nothrow private Float parse(bool is_denormalized = false, T)(T x) if(is(Unqual!T == ifloat) || is(Unqual!T == idouble) || is(Unqual!T == ireal)) { return parse(x.im); } @safe pure nothrow private Float parse(bool is_denormalized = false, T:real)(T x_) if(floatFormat!T != FloatFormat.Real80) { Unqual!T x = x_; assert(floatFormat!T != FloatFormat.DoubleDouble && floatFormat!T != FloatFormat.Quadruple, "doubledouble and quadruple float formats are not supported in CTFE"); if(x is cast(T)0.0) return FloatTraits!T.ZERO; if(x is cast(T)-0.0) return FloatTraits!T.NZERO; if(x is T.nan) return FloatTraits!T.NAN; if(x is -T.nan) return FloatTraits!T.NNAN; if(x is T.infinity || x > T.max) return FloatTraits!T.INF; if(x is -T.infinity || x < -T.max) return FloatTraits!T.NINF; uint sign = x < 0; x = sign ? -x : x; int e = binLog2(x); real x2 = x; uint exp = cast(uint)(e + (2^^(FloatTraits!T.EXPONENT-1) - 1)); if(!exp) { if(is_denormalized) return Float(0, 0, sign); else return Float(denormalizedMantissa(x), 0, sign); } x2 /= binPow2(e); static if(!is_denormalized) x2 -= 1.0; x2 *= 2UL<<(FloatTraits!T.MANTISSA); ulong mant = shiftrRound(cast(ulong)x2); return Float(mant, exp, sign); } @safe pure nothrow private Float parse(bool _ = false, T:real)(T x_) if(floatFormat!T == FloatFormat.Real80) { Unqual!T x = x_; //HACK @@@3632@@@ if(x == 0.0L) { real y = 1.0L/x; if(y == real.infinity) // -0.0 return FloatTraits!T.ZERO; else return FloatTraits!T.NZERO; //0.0 } if(x != x) //HACK: should be if(x is real.nan) and if(x is -real.nan) { auto y = cast(double)x; if(y is double.nan) return FloatTraits!T.NAN; else return FloatTraits!T.NNAN; } if(x == real.infinity) return FloatTraits!T.INF; if(x == -real.infinity) return FloatTraits!T.NINF; enum EXPONENT_MED = (2^^(FloatTraits!T.EXPONENT-1) - 1); uint sign = x < 0; x = sign ? -x : x; int e = binLog2(x); uint exp = cast(uint)(e + EXPONENT_MED); if(!exp) { return Float(denormalizedMantissa(x), 0, sign); } int pow = (FloatTraits!T.MANTISSA-1-e); x *= binPow2((pow / EXPONENT_MED)*EXPONENT_MED); //To avoid overflow in 2.0L ^^ pow x *= binPow2(pow % EXPONENT_MED); ulong mant = cast(ulong)x; return Float(mant, exp, sign); } private struct Float { ulong mantissa; uint exponent; uint sign; } private template FloatTraits(T) if(floatFormat!T == FloatFormat.Float) { enum EXPONENT = 8; enum MANTISSA = 23; enum ZERO = Float(0, 0, 0); enum NZERO = Float(0, 0, 1); enum NAN = Float(0x400000UL, 0xff, 0); enum NNAN = Float(0x400000UL, 0xff, 1); enum INF = Float(0, 255, 0); enum NINF = Float(0, 255, 1); } private template FloatTraits(T) if(floatFormat!T == FloatFormat.Double) { enum EXPONENT = 11; enum MANTISSA = 52; enum ZERO = Float(0, 0, 0); enum NZERO = Float(0, 0, 1); enum NAN = Float(0x8000000000000UL, 0x7ff, 0); enum NNAN = Float(0x8000000000000UL, 0x7ff, 1); enum INF = Float(0, 0x7ff, 0); enum NINF = Float(0, 0x7ff, 1); } private template FloatTraits(T) if(floatFormat!T == FloatFormat.Real80) { enum EXPONENT = 15; enum MANTISSA = 64; enum ZERO = Float(0, 0, 0); enum NZERO = Float(0, 0, 1); enum NAN = Float(0xC000000000000000UL, 0x7fff, 0); enum NNAN = Float(0xC000000000000000UL, 0x7fff, 1); enum INF = Float(0x8000000000000000UL, 0x7fff, 0); enum NINF = Float(0x8000000000000000UL, 0x7fff, 1); } private template FloatTraits(T) if(floatFormat!T == FloatFormat.DoubleDouble) //Unsupported in CTFE { enum EXPONENT = 11; enum MANTISSA = 106; enum ZERO = Float(0, 0, 0); enum NZERO = Float(0, 0, 1); enum NAN = Float(0x8000000000000UL, 0x7ff, 0); enum NNAN = Float(0x8000000000000UL, 0x7ff, 1); enum INF = Float(0, 0x7ff, 0); enum NINF = Float(0, 0x7ff, 1); } private template FloatTraits(T) if(floatFormat!T == FloatFormat.Quadruple) //Unsupported in CTFE { enum EXPONENT = 15; enum MANTISSA = 112; enum ZERO = Float(0, 0, 0); enum NZERO = Float(0, 0, 1); enum NAN = Float(-1, 0x7fff, 0); enum NNAN = Float(-1, 0x7fff, 1); enum INF = Float(0, 0x7fff, 0); enum NINF = Float(0, 0x7fff, 1); } @safe pure nothrow private real binPow2(int pow) { static real binPosPow2(int pow) @safe pure nothrow { assert(pow > 0); if(pow == 1) return 2.0L; int subpow = pow/2; real p = binPosPow2(subpow); real ret = p*p; if(pow%2) { ret *= 2.0L; } return ret; } if(!pow) return 1.0L; if(pow > 0) return binPosPow2(pow); return 1.0L/binPosPow2(-pow); } //Need in CTFE, because CTFE float and double expressions computed more precisely that run-time expressions. @safe pure nothrow private ulong shiftrRound(ulong x) { return (x >> 1) + (x & 1); } @safe pure nothrow private uint binLog2(T)(T x) { assert(x > 0); int max = 2 ^^ (FloatTraits!T.EXPONENT-1)-1; int min = -max+1; int med = (min + max) / 2; if(x < T.min_normal) return -max; while((max - min) > 1) { if(binPow2(med) > x) { max = med; } else { min = med; } med = (min + max) / 2; } if(x < binPow2(max)) return min; return max; } @safe pure nothrow private ulong denormalizedMantissa(T)(T x) if(floatFormat!T == FloatFormat.Real80) { x *= 2.0L^^FloatTraits!T.MANTISSA; auto fl = parse(x); uint pow = FloatTraits!T.MANTISSA - fl.exponent + 1; return fl.mantissa >> pow; } @safe pure nothrow private ulong denormalizedMantissa(T)(T x) if(floatFormat!T != FloatFormat.Real80) { x *= 2.0L^^FloatTraits!T.MANTISSA; auto fl = parse!true(x); ulong mant = fl.mantissa >> (FloatTraits!T.MANTISSA - fl.exponent); return shiftrRound(mant); } version(unittest) { private const(ubyte)[] toUbyte2(T)(T val) { return toUbyte(val).dup; } private void testNumberConvert(string v)() { enum ctval = mixin(v); alias TYPE = typeof(ctval); auto rtval = ctval; auto rtbytes = *cast(ubyte[TYPE.sizeof]*)&rtval; enum ctbytes = toUbyte2(ctval); // don't test pad bytes because can be anything enum testsize = (FloatTraits!TYPE.EXPONENT + FloatTraits!TYPE.MANTISSA + 1)/8; assert(rtbytes[0..testsize] == ctbytes[0..testsize]); } private void testConvert() { /**Test special values*/ testNumberConvert!("-float.infinity"); testNumberConvert!("float.infinity"); testNumberConvert!("-0.0F"); testNumberConvert!("0.0F"); //testNumberConvert!("-float.nan"); //BUG @@@3632@@@ testNumberConvert!("float.nan"); testNumberConvert!("-double.infinity"); testNumberConvert!("double.infinity"); testNumberConvert!("-0.0"); testNumberConvert!("0.0"); //testNumberConvert!("-double.nan"); //BUG @@@3632@@@ testNumberConvert!("double.nan"); testNumberConvert!("-real.infinity"); testNumberConvert!("real.infinity"); testNumberConvert!("-0.0L"); testNumberConvert!("0.0L"); //testNumberConvert!("-real.nan"); //BUG @@@3632@@@ testNumberConvert!("real.nan"); /** Test min and max values values: min value has an '1' mantissa and minimal exponent, Max value has an all '1' bits mantissa and max exponent. */ testNumberConvert!("float.min_normal"); testNumberConvert!("float.max"); /**Test common values*/ testNumberConvert!("-0.17F"); testNumberConvert!("3.14F"); /**Test immutable and const*/ testNumberConvert!("cast(const)3.14F"); testNumberConvert!("cast(immutable)3.14F"); /**The same tests for double and real*/ testNumberConvert!("double.min_normal"); testNumberConvert!("double.max"); testNumberConvert!("-0.17"); testNumberConvert!("3.14"); testNumberConvert!("cast(const)3.14"); testNumberConvert!("cast(immutable)3.14"); testNumberConvert!("real.min_normal"); testNumberConvert!("real.max"); testNumberConvert!("-0.17L"); testNumberConvert!("3.14L"); testNumberConvert!("cast(const)3.14L"); testNumberConvert!("cast(immutable)3.14L"); /**Test denormalized values*/ /**Max denormalized value, first bit is 1*/ testNumberConvert!("float.min_normal/2"); /**Min denormalized value, last bit is 1*/ testNumberConvert!("float.min_normal/2UL^^23"); /**Denormalized values with round*/ testNumberConvert!("float.min_normal/19"); testNumberConvert!("float.min_normal/17"); testNumberConvert!("double.min_normal/2"); testNumberConvert!("double.min_normal/2UL^^52"); testNumberConvert!("double.min_normal/19"); testNumberConvert!("double.min_normal/17"); testNumberConvert!("real.min_normal/2"); testNumberConvert!("real.min_normal/2UL^^63"); testNumberConvert!("real.min_normal/19"); testNumberConvert!("real.min_normal/17"); /**Test imaginary values: convert algorithm is same with real values*/ testNumberConvert!("0.0Fi"); testNumberConvert!("0.0i"); testNumberConvert!("0.0Li"); /**True random values*/ testNumberConvert!("-0x9.0f7ee55df77618fp-13829L"); testNumberConvert!("0x7.36e6e2640120d28p+8797L"); testNumberConvert!("-0x1.05df6ce4702ccf8p+15835L"); testNumberConvert!("0x9.54bb0d88806f714p-7088L"); testNumberConvert!("-0x9.0f7ee55df7ffp-338"); testNumberConvert!("0x7.36e6e264012dp+879"); testNumberConvert!("-0x1.05df6ce4708ep+658"); testNumberConvert!("0x9.54bb0d888061p-708"); testNumberConvert!("-0x9.0f7eefp-101F"); testNumberConvert!("0x7.36e6ep+87F"); testNumberConvert!("-0x1.05df6p+112F"); testNumberConvert!("0x9.54bb0p-70F"); /**Big overflow or underflow*/ testNumberConvert!("cast(double)-0x9.0f7ee55df77618fp-13829L"); testNumberConvert!("cast(double)0x7.36e6e2640120d28p+8797L"); testNumberConvert!("cast(double)-0x1.05df6ce4702ccf8p+15835L"); testNumberConvert!("cast(double)0x9.54bb0d88806f714p-7088L"); testNumberConvert!("cast(float)-0x9.0f7ee55df77618fp-13829L"); testNumberConvert!("cast(float)0x7.36e6e2640120d28p+8797L"); testNumberConvert!("cast(float)-0x1.05df6ce4702ccf8p+15835L"); testNumberConvert!("cast(float)0x9.54bb0d88806f714p-7088L"); } unittest { testConvert(); } } private enum FloatFormat { Float, Double, Real80, DoubleDouble, Quadruple } template floatFormat(T) if(is(T:real) || is(T:ireal)) { static if(T.mant_dig == 24) enum floatFormat = FloatFormat.Float; else static if(T.mant_dig == 53) enum floatFormat = FloatFormat.Double; else static if(T.mant_dig == 64) enum floatFormat = FloatFormat.Real80; else static if(T.mant_dig == 106) enum floatFormat = FloatFormat.DoubleDouble; else static if(T.mant_dig == 113) enum floatFormat = FloatFormat.Quadruple; else static assert(0); } // all toUbyte functions must be evaluable at compile time @trusted pure nothrow const(ubyte)[] toUbyte(T)(T[] arr) if (T.sizeof == 1) { return cast(const(ubyte)[])arr; } @trusted pure nothrow const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyte)[])) && (T.sizeof > 1)) { if (__ctfe) { const(ubyte)[] ret; foreach (cur; arr) { ret ~= toUbyte(cur); } return ret; } else { return (cast(const(ubyte)*)(arr.ptr))[0 .. T.sizeof*arr.length]; } } @trusted pure nothrow const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enum)) { static if (T.sizeof == 1) { if (__ctfe) { return cast(const(ubyte)[])[val]; } else { return (cast(const(ubyte)*)(&val))[0 .. T.sizeof]; } } else if (__ctfe) { ubyte[T.sizeof] tmp; Unqual!T val_ = val; for (size_t i = 0; i < T.sizeof; ++i) { size_t idx; version(LittleEndian) idx = i; else idx = T.sizeof-i-1; tmp[idx] = cast(ubyte)(val_&0xff); val_ >>= 8; } return tmp[].dup; } else { return (cast(const(ubyte)*)(&val))[0 .. T.sizeof]; } } @trusted pure nothrow const(ubyte)[] toUbyte(T)(ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T == cdouble) ||is(Unqual!T == creal)) { if (__ctfe) { auto re = val.re; auto im = val.im; return (re.toUbyte() ~ im.toUbyte()); } else { return (cast(const(ubyte)*)&val)[0 .. T.sizeof]; } } @trusted pure nothrow const(ubyte)[] toUbyte(T)(ref T val) if (is(T == enum) && is(typeof(toUbyte(cast(V)val)) == const(ubyte)[])) { if (__ctfe) { static if (is(T V == enum)){} V e_val = val; return toUbyte(e_val); } else { return (cast(const(ubyte)*)&val)[0 .. T.sizeof]; } } private bool isNonReference(T)() { static if (is(T == struct) || is(T == union)) { return isNonReferenceStruct!T(); } else static if (__traits(isStaticArray, T)) { return isNonReference!(typeof(T.init[0]))(); } else static if (is(T E == enum)) { return isNonReference!(E)(); } else static if (!__traits(isScalar, T)) { return false; } else static if (is(T V : V*)) { return false; } else static if (is(T == function)) { return false; } else { return true; } } private bool isNonReferenceStruct(T)() if (is(T == struct) || is(T == union)) { foreach (cur; T.init.tupleof) { static if (!isNonReference!(typeof(cur))()) return false; } return true; } @trusted pure nothrow const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union)) { if (__ctfe) { ubyte[T.sizeof] bytes; foreach (key, cur; val.tupleof) { alias CUR_TYPE = typeof(cur); static if(isNonReference!(CUR_TYPE)()) { bytes[val.tupleof[key].offsetof .. val.tupleof[key].offsetof + cur.sizeof] = toUbyte(cur)[]; } else static if(is(typeof(val.tupleof[key] is null))) { assert(val.tupleof[key] is null, "Unable to compute byte representation of non-null reference field at compile time"); //skip, because val bytes are zeros } else { //pragma(msg, "is null: ", typeof(CUR_TYPE).stringof); assert(0, "Unable to compute byte representation of "~typeof(CUR_TYPE).stringof~" field at compile time"); } } return bytes[].dup; } else { return (cast(const(ubyte)*)&val)[0 .. T.sizeof]; } } ldc-1.1.0-beta3-src/runtime/druntime/src/core/internal/traits.d0000664000175000017500000001336012776214756022474 0ustar kaikai/** * Contains traits for runtime internal usage. * * Copyright: Copyright Digital Mars 2014 -. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak * Source: $(DRUNTIMESRC core/internal/_traits.d) */ module core.internal.traits; /// taken from std.typetuple.TypeTuple template TypeTuple(TList...) { alias TypeTuple = TList; } T trustedCast(T, U)(auto ref U u) @trusted pure nothrow { return cast(T)u; } template Unconst(T) { static if (is(T U == immutable U)) alias Unconst = U; else static if (is(T U == inout const U)) alias Unconst = U; else static if (is(T U == inout U)) alias Unconst = U; else static if (is(T U == const U)) alias Unconst = U; else alias Unconst = T; } /// taken from std.traits.Unqual template Unqual(T) { version (none) // Error: recursive alias declaration @@@BUG1308@@@ { static if (is(T U == const U)) alias Unqual = Unqual!U; else static if (is(T U == immutable U)) alias Unqual = Unqual!U; else static if (is(T U == inout U)) alias Unqual = Unqual!U; else static if (is(T U == shared U)) alias Unqual = Unqual!U; else alias Unqual = T; } else // workaround { static if (is(T U == immutable U)) alias Unqual = U; else static if (is(T U == shared inout const U)) alias Unqual = U; else static if (is(T U == shared inout U)) alias Unqual = U; else static if (is(T U == shared const U)) alias Unqual = U; else static if (is(T U == shared U)) alias Unqual = U; else static if (is(T U == inout const U)) alias Unqual = U; else static if (is(T U == inout U)) alias Unqual = U; else static if (is(T U == const U)) alias Unqual = U; else alias Unqual = T; } } // Substitute all `inout` qualifiers that appears in T to `const` template substInout(T) { static if (is(T == immutable)) { alias substInout = T; } else static if (is(T : shared const U, U) || is(T : const U, U)) { // U is top-unqualified mixin("alias substInout = " ~ (is(T == shared) ? "shared " : "") ~ (is(T == const) || is(T == inout) ? "const " : "") // substitute inout to const ~ "substInoutForm!U;"); } else static assert(0); } private template substInoutForm(T) { static if (is(T == struct) || is(T == class) || is(T == union) || is(T == interface)) { alias substInoutForm = T; // prevent matching to the form of alias-this-ed type } else static if (is(T : V[K], K, V)) alias substInoutForm = substInout!V[substInout!K]; else static if (is(T : U[n], U, size_t n)) alias substInoutForm = substInout!U[n]; else static if (is(T : U[], U)) alias substInoutForm = substInout!U[]; else static if (is(T : U*, U)) alias substInoutForm = substInout!U*; else alias substInoutForm = T; } /// used to declare an extern(D) function that is defined in a different module template externDFunc(string fqn, T:FT*, FT) if(is(FT == function)) { static if (is(FT RT == return) && is(FT Args == function)) { import core.demangle : mangleFunc; enum decl = { string s = "extern(D) RT externDFunc(Args)"; foreach (attr; __traits(getFunctionAttributes, FT)) s ~= " " ~ attr; return s ~ ";"; }(); pragma(mangle, mangleFunc!T(fqn)) mixin(decl); } else static assert(0); } template staticIota(int beg, int end) { static if (beg + 1 >= end) { static if (beg >= end) { alias staticIota = TypeTuple!(); } else { alias staticIota = TypeTuple!(+beg); } } else { enum mid = beg + (end - beg) / 2; alias staticIota = TypeTuple!(staticIota!(beg, mid), staticIota!(mid, end)); } } template dtorIsNothrow(T) { enum dtorIsNothrow = is(typeof(function{T t=void;}) : void function() nothrow); } template anySatisfy(alias F, T...) { static if (T.length == 0) { enum anySatisfy = false; } else static if (T.length == 1) { enum anySatisfy = F!(T[0]); } else { enum anySatisfy = anySatisfy!(F, T[ 0 .. $/2]) || anySatisfy!(F, T[$/2 .. $ ]); } } // Somehow fails for non-static nested structs without support for aliases template hasElaborateDestructor(T...) { static if (is(T[0])) alias S = T[0]; else alias S = typeof(T[0]); static if (is(S : E[n], E, size_t n) && S.length) { enum bool hasElaborateDestructor = hasElaborateDestructor!E; } else static if (is(S == struct)) { enum hasElaborateDestructor = __traits(hasMember, S, "__dtor") || anySatisfy!(.hasElaborateDestructor, S.tupleof); } else enum bool hasElaborateDestructor = false; } // Somehow fails for non-static nested structs without support for aliases template hasElaborateCopyConstructor(T...) { static if (is(T[0])) alias S = T[0]; else alias S = typeof(T[0]); static if (is(S : E[n], E, size_t n) && S.length) { enum bool hasElaborateCopyConstructor = hasElaborateCopyConstructor!E; } else static if (is(S == struct)) { enum hasElaborateCopyConstructor = __traits(hasMember, S, "__postblit") || anySatisfy!(.hasElaborateCopyConstructor, S.tupleof); } else enum bool hasElaborateCopyConstructor = false; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/internal/abort.d0000664000175000017500000000274212776214756022277 0ustar kaikaimodule core.internal.abort; /* * Use instead of assert(0, msg), since this does not print a message for -release compiled * code, and druntime is -release compiled. */ void abort(string msg, string filename = __FILE__, size_t line = __LINE__) @nogc nothrow @safe { import core.stdc.stdlib: c_abort = abort; // use available OS system calls to print the message to stderr version(Posix) { import core.sys.posix.unistd: write; static void writeStr(const(char)[][] m...) @nogc nothrow @trusted { foreach(s; m) write(2, s.ptr, s.length); } } else version(Windows) { import core.sys.windows.windows: GetStdHandle, STD_ERROR_HANDLE, WriteFile, INVALID_HANDLE_VALUE; auto h = (() @trusted => GetStdHandle(STD_ERROR_HANDLE))(); if(h == INVALID_HANDLE_VALUE) // attempt best we can to print the message assert(0, msg); void writeStr(const(char)[][] m...) @nogc nothrow @trusted { foreach(s; m) { assert(s.length <= uint.max); WriteFile(h, s.ptr, cast(uint)s.length, null, null); } } } else static assert(0, "Unsupported OS"); import core.internal.string; UnsignedStringBuf strbuff; // write an appropriate message, then abort the program writeStr("Aborting from ", filename, "(", line.unsignedToTempString(strbuff, 10), ") ", msg); c_abort(); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/internal/hash.d0000664000175000017500000003277712776214756022126 0ustar kaikai/** * Written in the D programming language. * This module provides functions to uniform calculating hash values for different types * * Copyright: Copyright Igor Stepanov 2013-2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Igor Stepanov * Source: $(DRUNTIMESRC core/internal/_hash.d) */ module core.internal.hash; import core.internal.convert; //enum hash. CTFE depends on base type size_t hashOf(T)(auto ref T val, size_t seed = 0) if (is(T == enum)) { static if (is(T EType == enum)) //for EType { EType e_val = cast(EType)val; return hashOf(e_val, seed); } else { static assert(0); } } //CTFE ready (depends on base type). Can be merged with dynamic array hash size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && __traits(isStaticArray, T)) { size_t cur_hash = seed; foreach (ref cur; val) { cur_hash = hashOf(cur, cur_hash); } return cur_hash; } //dynamic array hash size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStaticArray, T)) { alias ElementType = typeof(val[0]); static if (is(ElementType == interface) || is(ElementType == class) || ((is(ElementType == struct) || is(ElementType == union)) && is(typeof(val[0].toHash()) == size_t))) //class or interface array or struct array with toHash(); CTFE depend on toHash() method { size_t hash = seed; foreach (o; val) { hash = hashOf(o, hash); } return hash; } else static if (is(typeof(toUbyte(val)) == const(ubyte)[])) //ubyteble array (arithmetic types and structs without toHash) CTFE ready for arithmetic types and structs without reference fields { auto bytes = toUbyte(val); return bytesHash(bytes.ptr, bytes.length, seed); } else //Other types. CTFE unsupported { assert(!__ctfe, "unable to compute hash of "~T.stringof); return bytesHash(val.ptr, ElementType.sizeof*val.length, seed); } } //arithmetic type hash @trusted nothrow pure size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && __traits(isArithmetic, T)) { static if(__traits(isFloating, val)) { T data = (val != val) ? T.nan : val; auto bytes = toUbyte(data); return bytesHash(bytes.ptr, bytes.length, seed); } else { auto bytes = toUbyte(val); return bytesHash(bytes.ptr, bytes.length, seed); } } //typeof(null) hash. CTFE supported @trusted nothrow pure size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T : typeof(null))) { return hashOf(cast(void*)null); } //Pointers hash. CTFE unsupported if not null @trusted nothrow pure size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T V : V*) && !is(T : typeof(null))) { if(__ctfe) { if(val is null) { return hashOf(cast(size_t)0); } else { assert(0, "Unable to calculate hash of non-null pointer at compile time"); } } return hashOf(cast(size_t)val); } //struct or union hash size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && (is(T == struct) || is(T == union))) { static if (is(typeof(val.toHash()) == size_t)) //CTFE depends on toHash() { return hashOf(val.toHash(), seed); } else { static if(__traits(hasMember, T, "toHash") && is(typeof(T.toHash) == function)) { pragma(msg, "Warning: struct "~__traits(identifier, T)~" has method toHash, however it cannot be called with "~T.stringof~" this."); } static if (is(typeof(toUbyte(val)) == const(ubyte)[]))//CTFE ready for structs without reference fields { auto bytes = toUbyte(val); return bytesHash(bytes.ptr, bytes.length, seed); } else // CTFE unsupproreted for structs with reference fields { assert(!__ctfe, "unable to compute hash of "~T.stringof); const(ubyte)[] bytes = (cast(const(ubyte)*)&val)[0 .. T.sizeof]; return bytesHash(bytes.ptr, bytes.length, seed); } } } //delegate hash. CTFE unsupported @trusted nothrow pure size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T == delegate)) { assert(!__ctfe, "unable to compute hash of "~T.stringof); const(ubyte)[] bytes = (cast(const(ubyte)*)&val)[0 .. T.sizeof]; return bytesHash(bytes.ptr, bytes.length, seed); } //class or interface hash. CTFE depends on toHash size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T == interface) || is(T == class)) { return hashOf(val ? (cast(Object)val).toHash() : 0, seed); } //associative array hash. CTFE depends on base types size_t hashOf(T)(auto ref T aa, size_t seed = 0) if (!is(T == enum) && __traits(isAssociativeArray, T)) { if (!aa.length) return hashOf(0, seed); size_t h = 0; // The computed hash is independent of the foreach traversal order. foreach (key, ref val; aa) { size_t[2] hpair; hpair[0] = key.hashOf(); hpair[1] = val.hashOf(); h ^= hpair.hashOf(); } return h.hashOf(seed); } unittest { static struct Foo { int a = 99; float b = 4.0; size_t toHash() const pure @safe nothrow { return a; } } static struct Bar { char c = 'x'; int a = 99; float b = 4.0; void* d = null; } static struct Boom { char c = 'M'; int* a = null; } interface IBoo { void boo(); } static class Boo: IBoo { override void boo() { } override size_t toHash() { return 1; } } static struct Goo { size_t toHash() pure @safe nothrow { return 1; } } enum Gun: long { A = 99, B = 17 } enum double dexpr = 3.14; enum float fexpr = 2.71; enum wstring wsexpr = "abcdef"w; enum string csexpr = "abcdef"; enum int iexpr = 7; enum long lexpr = 42; enum int[2][3] saexpr = [[1, 2], [3, 4], [5, 6]]; enum int[] daexpr = [7,8,9]; enum Foo thsexpr = Foo(); enum Bar vsexpr = Bar(); enum int[int] aaexpr = [99:2, 12:6, 45:4]; enum Gun eexpr = Gun.A; enum cdouble cexpr = 7+4i; enum Foo[] staexpr = [Foo(), Foo(), Foo()]; enum Bar[] vsaexpr = [Bar(), Bar(), Bar()]; enum realexpr = 7.88; enum raexpr = [8.99L+86i, 3.12L+99i, 5.66L+12i]; enum nullexpr = null; //No CTFE: Boom rstructexpr = Boom(); Boom[] rstrarrexpr = [Boom(), Boom(), Boom()]; int delegate() dgexpr = (){return 78;}; void* ptrexpr = &dgexpr; //CTFE hashes enum h1 = dexpr.hashOf(); enum h2 = fexpr.hashOf(); enum h3 = wsexpr.hashOf(); enum h4 = csexpr.hashOf(); enum h5 = iexpr.hashOf(); enum h6 = lexpr.hashOf(); enum h7 = saexpr.hashOf(); enum h8 = daexpr.hashOf(); enum h9 = thsexpr.hashOf(); enum h10 = vsexpr.hashOf(); enum h11 = aaexpr.hashOf(); enum h12 = eexpr.hashOf(); enum h13 = cexpr.hashOf(); enum h14 = hashOf(new Boo); enum h15 = staexpr.hashOf(); enum h16 = hashOf([new Boo, new Boo, new Boo]); enum h17 = hashOf([cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]); enum h18 = hashOf(cast(IBoo)new Boo); enum h19 = vsaexpr.hashOf(); enum h20 = hashOf(cast(Foo[3])staexpr); //BUG: cannot cast [Boo(), Boo(), Boo()][0] to object.Object at compile time auto h21 = hashOf(cast(Boo[3])[new Boo, new Boo, new Boo]); auto h22 = hashOf(cast(IBoo[3])[cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]); enum h23 = hashOf(cast(Bar[3])vsaexpr); //NO CTFE (Compute, but don't check correctness): auto h24 = rstructexpr.hashOf(); auto h25 = rstrarrexpr.hashOf(); auto h26 = dgexpr.hashOf(); auto h27 = ptrexpr.hashOf(); enum h28 = realexpr.hashOf(); enum h29 = raexpr.hashOf(); enum h30 = nullexpr.hashOf(); auto v1 = dexpr; auto v2 = fexpr; auto v3 = wsexpr; auto v4 = csexpr; auto v5 = iexpr; auto v6 = lexpr; auto v7 = saexpr; auto v8 = daexpr; auto v9 = thsexpr; auto v10 = vsexpr; auto v11 = aaexpr; auto v12 = eexpr; auto v13 = cexpr; auto v14 = new Boo; auto v15 = staexpr; auto v16 = [new Boo, new Boo, new Boo]; auto v17 = [cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]; auto v18 = cast(IBoo)new Boo; auto v19 = vsaexpr; auto v20 = cast(Foo[3])staexpr; auto v21 = cast(Boo[3])[new Boo, new Boo, new Boo]; auto v22 = cast(IBoo[3])[cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]; auto v23 = cast(Bar[3])vsaexpr; auto v30 = null; //NO CTFE: /*auto v24 = rstructexpr; auto v25 = rstrarrexpr; auto v26 = dgexpr; auto v27 = ptrexpr; auto v28 = realexpr; auto v29 = raexpr;*/ //runtime hashes auto rth1 = hashOf(v1); auto rth2 = hashOf(v2); auto rth3 = hashOf(v3); auto rth4 = hashOf(v4); auto rth5 = hashOf(v5); auto rth6 = hashOf(v6); auto rth7 = hashOf(v7); auto rth8 = hashOf(v8); auto rth9 = hashOf(v9); auto rth10 = hashOf(v10); auto rth11 = hashOf(v11); auto rth12 = hashOf(v12); auto rth13 = hashOf(v13); auto rth14 = hashOf(v14); auto rth15 = hashOf(v15); auto rth16 = hashOf(v16); auto rth17 = hashOf(v17); auto rth18 = hashOf(v18); auto rth19 = hashOf(v19); auto rth20 = hashOf(v20); auto rth21 = hashOf(v21); auto rth22 = hashOf(v22); auto rth23 = hashOf(v23); auto rth30 = hashOf(v30); /*//NO CTFE: auto rth24 = hashOf(v24); auto rth25 = hashOf(v25); auto rth26 = hashOf(v26); auto rth27 = hashOf(v27); auto rth28 = hashOf(v28); auto rth29 = hashOf(v29);*/ assert(h1 == rth1); assert(h2 == rth2); assert(h3 == rth3); assert(h4 == rth4); assert(h5 == rth5); assert(h6 == rth6); assert(h7 == rth7); assert(h8 == rth8); assert(h9 == rth9); assert(h10 == rth10); assert(h11 == rth11); assert(h12 == rth12); assert(h13 == rth13); assert(h14 == rth14); assert(h15 == rth15); assert(h16 == rth16); assert(h17 == rth17); assert(h18 == rth18); assert(h19 == rth19); assert(h20 == rth20); assert(h21 == rth21); assert(h22 == rth22); assert(h23 == rth23); /*assert(h24 == rth24); assert(h25 == rth25); assert(h26 == rth26); assert(h27 == rth27); assert(h28 == rth28); assert(h29 == rth29);*/ assert(h30 == rth30); } // MurmurHash3 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code. version(X86) version = AnyX86; version(X86_64) version = AnyX86; version(AnyX86) { version(DigitalMars) { } else { version = HasUnalignedOps; } } @trusted pure nothrow size_t bytesHash(const(void)* buf, size_t len, size_t seed = 0) { static uint rotl32(uint n)(in uint x) pure nothrow @safe { return (x << n) | (x >> (32 - n)); } //----------------------------------------------------------------------------- // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here static uint get32bits(const (ubyte)* x) pure nothrow { //Compiler can optimize this code to simple *cast(uint*)x if it possible. version(HasUnalignedOps) { if (!__ctfe) return *cast(uint*)x; //BUG: Can't be inlined by DMD } version(BigEndian) { return ((cast(uint) x[0]) << 24) | ((cast(uint) x[1]) << 16) | ((cast(uint) x[2]) << 8) | (cast(uint) x[3]); } else { return ((cast(uint) x[3]) << 24) | ((cast(uint) x[2]) << 16) | ((cast(uint) x[1]) << 8) | (cast(uint) x[0]); } } //----------------------------------------------------------------------------- // Finalization mix - force all bits of a hash block to avalanche static uint fmix32(uint h) pure nothrow @safe { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; h ^= h >> 16; return h; } auto data = cast(const(ubyte)*)buf; auto nblocks = len / 4; uint h1 = cast(uint)seed; enum uint c1 = 0xcc9e2d51; enum uint c2 = 0x1b873593; enum uint c3 = 0xe6546b64; //---------- // body auto end_data = data+nblocks*uint.sizeof; for(; data!=end_data; data += uint.sizeof) { uint k1 = get32bits(data); k1 *= c1; k1 = rotl32!15(k1); k1 *= c2; h1 ^= k1; h1 = rotl32!13(h1); h1 = h1*5+c3; } //---------- // tail uint k1 = 0; switch(len & 3) { case 3: k1 ^= data[2] << 16; goto case; case 2: k1 ^= data[1] << 8; goto case; case 1: k1 ^= data[0]; k1 *= c1; k1 = rotl32!15(k1); k1 *= c2; h1 ^= k1; goto default; default: } //---------- // finalization h1 ^= len; h1 = fmix32(h1); return h1; } // Check that bytesHash works with CTFE unittest { size_t ctfeHash(string x) { return bytesHash(x.ptr, x.length); } enum test_str = "Sample string"; enum size_t hashVal = ctfeHash(test_str); assert(hashVal == bytesHash(test_str.ptr, test_str.length)); } ldc-1.1.0-beta3-src/runtime/druntime/src/core/internal/spinlock.d0000664000175000017500000000414412776214756023010 0ustar kaikai/** * SpinLock for runtime internal usage. * * Copyright: Copyright Digital Mars 2015 -. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak * Source: $(DRUNTIMESRC core/internal/_spinlock.d) */ module core.internal.spinlock; import core.atomic, core.thread; shared struct SpinLock { /// for how long is the lock usually contended enum Contention : ubyte { brief, medium, lengthy, } @trusted @nogc nothrow: this(Contention contention) { this.contention = contention; } void lock() { if (cas(&val, size_t(0), size_t(1))) return; // Try to reduce the chance of another cas failure // TTAS lock (https://en.wikipedia.org/wiki/Test_and_test-and-set) immutable step = 1 << contention; while (true) { for (size_t n; atomicLoad!(MemoryOrder.raw)(val); n += step) yield(n); if (cas(&val, size_t(0), size_t(1))) return; } } void unlock() { atomicStore!(MemoryOrder.rel)(val, size_t(0)); } /// yield with backoff void yield(size_t k) { if (k < pauseThresh) return pause(); else if (k < 32) return Thread.yield(); Thread.sleep(1.msecs); } private: version (D_InlineAsm_X86) enum X86 = true; else version (D_InlineAsm_X86_64) enum X86 = true; else enum X86 = false; static if (X86) { enum pauseThresh = 16; void pause() { asm @trusted @nogc nothrow { // pause instruction rep; nop; } } } else { enum pauseThresh = 4; void pause() { } } size_t val; Contention contention; } // aligned to cacheline to avoid false sharing shared align(64) struct AlignedSpinLock { this(SpinLock.Contention contention) { impl = shared(SpinLock)(contention); } SpinLock impl; alias impl this; } ldc-1.1.0-beta3-src/runtime/druntime/src/core/internal/string.d0000664000175000017500000001414012776214756022471 0ustar kaikai/** * String manipulation and comparison utilities. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Walter Bright * Source: $(DRUNTIMESRC src/rt/util/_string.d) */ module core.internal.string; pure: nothrow: @nogc: alias UnsignedStringBuf = char[20]; char[] unsignedToTempString(ulong value, char[] buf, uint radix = 10) @safe { size_t i = buf.length; do { ubyte x = cast(ubyte)(value % radix); value = value / radix; buf[--i] = cast(char)((x < 10) ? x + '0' : x - 10 + 'a'); } while (value); return buf[i .. $]; } private struct TempStringNoAlloc { // need to handle 65 bytes for radix of 2 with negative sign. private char[65] _buf; private ubyte _len; auto get() return { return _buf[$-_len..$]; } alias get this; } auto unsignedToTempString(ulong value, uint radix) @safe { TempStringNoAlloc result = void; result._len = unsignedToTempString(value, result._buf, radix).length & 0xff; return result; } unittest { UnsignedStringBuf buf; assert(0.unsignedToTempString(buf, 10) == "0"); assert(1.unsignedToTempString(buf, 10) == "1"); assert(12.unsignedToTempString(buf, 10) == "12"); assert(0x12ABCF .unsignedToTempString(buf, 16) == "12abcf"); assert(long.sizeof.unsignedToTempString(buf, 10) == "8"); assert(uint.max.unsignedToTempString(buf, 10) == "4294967295"); assert(ulong.max.unsignedToTempString(buf, 10) == "18446744073709551615"); // use stack allocated struct version assert(0.unsignedToTempString(10) == "0"); assert(1.unsignedToTempString(10) == "1"); assert(12.unsignedToTempString(10) == "12"); assert(0x12ABCF .unsignedToTempString(16) == "12abcf"); assert(long.sizeof.unsignedToTempString(10) == "8"); assert(uint.max.unsignedToTempString(10) == "4294967295"); assert(ulong.max.unsignedToTempString(10) == "18446744073709551615"); } alias SignedStringBuf = char[20]; auto signedToTempString(long value, char[] buf, uint radix) @safe { bool neg = value < 0; if(neg) value = cast(ulong)-value; auto r = unsignedToTempString(value, buf, radix); if(neg) { // about to do a slice without a bounds check assert(r.ptr > buf.ptr); r = (() @trusted => (r.ptr-1)[0..r.length+1])(); r[0] = '-'; } return r; } auto signedToTempString(long value, uint radix) @safe { bool neg = value < 0; if(neg) value = cast(ulong)-value; auto r = unsignedToTempString(value, radix); if(neg) { r._len++; r.get()[0] = '-'; } return r; } unittest { SignedStringBuf buf; assert(0.signedToTempString(buf, 10) == "0"); assert(1.signedToTempString(buf, 10) == "1"); assert((-1).signedToTempString(buf, 10) == "-1"); assert(12.signedToTempString(buf, 10) == "12"); assert((-12).signedToTempString(buf, 10) == "-12"); assert(0x12ABCF .signedToTempString(buf, 16) == "12abcf"); assert((-0x12ABCF) .signedToTempString(buf, 16) == "-12abcf"); assert(long.sizeof.signedToTempString(buf, 10) == "8"); assert(int.max.signedToTempString(buf, 10) == "2147483647"); assert(int.min.signedToTempString(buf, 10) == "-2147483648"); assert(long.max.signedToTempString(buf, 10) == "9223372036854775807"); assert(long.min.signedToTempString(buf, 10) == "-9223372036854775808"); // use stack allocated struct version assert(0.signedToTempString(10) == "0"); assert(1.signedToTempString(10) == "1"); assert((-1).signedToTempString(10) == "-1"); assert(12.signedToTempString(10) == "12"); assert((-12).signedToTempString(10) == "-12"); assert(0x12ABCF .signedToTempString(16) == "12abcf"); assert((-0x12ABCF) .signedToTempString(16) == "-12abcf"); assert(long.sizeof.signedToTempString(10) == "8"); assert(int.max.signedToTempString(10) == "2147483647"); assert(int.min.signedToTempString(10) == "-2147483648"); assert(long.max.signedToTempString(10) == "9223372036854775807"); assert(long.min.signedToTempString(10) == "-9223372036854775808"); assert(long.max.signedToTempString(2) == "111111111111111111111111111111111111111111111111111111111111111"); assert(long.min.signedToTempString(2) == "-1000000000000000000000000000000000000000000000000000000000000000"); } /******************************** * Determine number of digits that will result from a * conversion of value to a string. * Params: * value = number to convert * radix = radix * Returns: * number of digits */ int numDigits(uint radix = 10)(ulong value) @safe { int n = 1; while (1) { if (value <= uint.max) { uint v = cast(uint)value; while (1) { if (v < radix) return n; if (v < radix * radix) return n + 1; if (v < radix * radix * radix) return n + 2; if (v < radix * radix * radix * radix) return n + 3; n += 4; v /= radix * radix * radix * radix; } } n += 4; value /= radix * radix * radix * radix; } } unittest { assert(0.numDigits == 1); assert(9.numDigits == 1); assert(10.numDigits == 2); assert(99.numDigits == 2); assert(100.numDigits == 3); assert(999.numDigits == 3); assert(1000.numDigits == 4); assert(9999.numDigits == 4); assert(10000.numDigits == 5); assert(99999.numDigits == 5); assert(uint.max.numDigits == 10); assert(ulong.max.numDigits == 20); assert(0.numDigits!2 == 1); assert(1.numDigits!2 == 1); assert(2.numDigits!2 == 2); assert(3.numDigits!2 == 2); } int dstrcmp( in char[] s1, in char[] s2 ) @trusted { import core.stdc.string : memcmp; int ret = 0; auto len = s1.length; if( s2.length < len ) len = s2.length; if( 0 != (ret = memcmp( s1.ptr, s2.ptr, len )) ) return ret; return s1.length > s2.length ? 1 : s1.length == s2.length ? 0 : -1; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/0000775000175000017500000000000012776214756016677 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/rt/dwarfeh.d0000664000175000017500000007632012776214756020474 0ustar kaikai/** * Exception handling support for Dwarf-style portable exceptions. * * Copyright: Copyright (c) 2015-2016 by D Language Foundation * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright * Source: $(DRUNTIMESRC src/rt/_dwarfeh.d) */ module rt.dwarfeh; version (Posix): import rt.unwind; import core.stdc.stdio; import core.stdc.stdlib; extern (C) { int _d_isbaseof(ClassInfo b, ClassInfo c); void _d_createTrace(Object o, void* context); } /* High 4 bytes = vendor, low 4 bytes = language * For us: "DMD\0D\0\0\0" */ enum _Unwind_Exception_Class dmdExceptionClass = (cast(_Unwind_Exception_Class)'D' << 56) | (cast(_Unwind_Exception_Class)'M' << 48) | (cast(_Unwind_Exception_Class)'D' << 40) | (cast(_Unwind_Exception_Class)'D' << 24); /** * Wrap the unwinder's data with our own compiler specific struct * with our own data. */ struct ExceptionHeader { Throwable object; // the thrown D object _Unwind_Exception exception_object; // the unwinder's data // Save info on the handler that was detected int handler; // which catch const(ubyte)* languageSpecificData; // Language Specific Data Area for function enclosing the handler _Unwind_Ptr landingPad; // pointer to catch code // Stack other thrown exceptions in current thread through here. ExceptionHeader* next; static ExceptionHeader* stack; // thread local stack of chained exceptions /* Pre-allocate storage for 1 instance per thread. * Use calloc/free for multiple exceptions in flight. * Does not use GC */ static ExceptionHeader ehstorage; /************ * Allocate and initialize an ExceptionHeader. * Params: * o = thrown object * Returns: * allocated and initalized ExceptionHeader */ static ExceptionHeader* create(Throwable o) @nogc { auto eh = &ehstorage; if (eh.object) // if in use { eh = cast(ExceptionHeader*)core.stdc.stdlib.calloc(ExceptionHeader.sizeof, 1); if (!eh) terminate(__LINE__); // out of memory while throwing - not much else can be done } eh.object = o; eh.exception_object.exception_class = dmdExceptionClass; //printf("create(): %p\n", eh); return eh; } /********************** * Free ExceptionHeader that was created by create(). * Params: * eh = ExceptionHeader to free */ static void free(ExceptionHeader* eh) { //printf("free(%p)\n", eh); /* Smite contents even if subsequently free'd, * to ward off dangling pointer bugs. */ *eh = ExceptionHeader.init; if (eh != &ehstorage) core.stdc.stdlib.free(eh); } /************************* * Push this onto stack of chained exceptions. */ void push() { next = stack; stack = &this; } /************************ * Pop and return top of chained exception stack. */ static ExceptionHeader* pop() { auto eh = stack; stack = eh.next; return eh; } /******************************* * Convert from pointer to exception_object to pointer to ExceptionHeader * that it is embedded inside of. * Params: * eo = pointer to exception_object field * Returns: * pointer to ExceptionHeader that eo points into. */ static ExceptionHeader* toExceptionHeader(_Unwind_Exception* eo) { return cast(ExceptionHeader*)(cast(void*)eo - ExceptionHeader.exception_object.offsetof); } } /******************************************* * The first thing a catch handler does is call this. * Params: * exceptionObject = value passed to catch handler by unwinder * Returns: * object that was caught */ extern(C) Throwable __dmd_begin_catch(_Unwind_Exception* exceptionObject) { ExceptionHeader *eh = ExceptionHeader.toExceptionHeader(exceptionObject); //printf("__dmd_begin_catch(%p), object = %p\n", eh, eh.object); auto o = eh.object; // Pop off of chain if (eh != ExceptionHeader.pop()) terminate(__LINE__); // eh should have been at top of stack _Unwind_DeleteException(&eh.exception_object); // done with eh return o; } /**************************************** * Called when fibers switch contexts. * Params: * newContext = stack to switch to * Returns: * previous value of stack */ extern(C) void* _d_eh_swapContextDwarf(void* newContext) nothrow { auto old = ExceptionHeader.stack; ExceptionHeader.stack = cast(ExceptionHeader*)newContext; return old; } /********************* * Called by D code to throw an exception via * --- * throw o; * --- * Params: * o = Object to throw * Returns: * doesn't return */ extern(C) void _d_throwdwarf(Throwable o) { ExceptionHeader *eh = ExceptionHeader.create(o); eh.push(); // add to thrown exception stack //printf("_d_throwdwarf: eh = %p, eh.next = %p\n", eh, eh.next); /* Called by unwinder when exception object needs destruction by other than our code. */ extern (C) static void exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* eo) { //printf("exception_cleanup()\n"); switch (reason) { case _URC_FATAL_PHASE1_ERROR: // unknown error code case _URC_FATAL_PHASE2_ERROR: // probably corruption default: // uh-oh terminate(__LINE__); // C++ calls terminate() instead break; case _URC_FOREIGN_EXCEPTION_CAUGHT: case _URC_NO_REASON: auto eh = ExceptionHeader.toExceptionHeader(eo); ExceptionHeader.free(eh); break; } } eh.exception_object.exception_cleanup = &exception_cleanup; _d_createTrace(o, null); auto r = _Unwind_RaiseException(&eh.exception_object); /* Shouldn't have returned, but if it did: */ switch (r) { case _URC_END_OF_STACK: /* Unwound the stack without encountering a catch clause. * In C++, this would mean call uncaught_exception(). * In D, this should never happen since everything is enclosed * by a top-level try/catch. */ fprintf(stderr, "uncaught exception\n"); terminate(__LINE__); // should never happen assert(0); case _URC_FATAL_PHASE1_ERROR: /* Unexpected error, likely some sort of corruption. * In C++, terminate() would be called. */ terminate(__LINE__); // should never happen assert(0); case _URC_FATAL_PHASE2_ERROR: /* Unexpected error. Program is in an unknown state. * In C++, terminate() would be called. */ terminate(__LINE__); // should never happen assert(0); default: terminate(__LINE__); // should never happen assert(0); } } /***************************************** * "personality" function, specific to each language. * This one, of course, is specific to DMD. * Params: * ver = version must be 1 * actions = bitwise OR of the 4 actions _UA_xxx. * _UA_SEARCH_PHASE means return _URC_HANDLER_FOUND if current frame has a handler, * _URC_CONTINUE_UNWIND if not. Cannot be used with _UA_CLEANUP_PHASE. * _UA_CLEANUP_PHASE means perform cleanup for current frame by calling nested functions * and returning _URC_CONTINUE_UNWIND. Or, set up registers and IP for Landing Pad * and return _URC_INSTALL_CONTEXT. * _UA_HANDLER_FRAME means this frame was the one with the handler in Phase 1, and now * it is Phase 2 and the handler must be run. * _UA_FORCE_UNWIND means unwinding the stack for longjmp or thread cancellation. Run * finally clauses, not catch clauses, finallys must end with call to _Uwind_Resume(). * exceptionClass = 8 byte value indicating type of thrown exception. If the low 4 bytes * are "C++\0", it's a C++ exception. * exceptionObject = language specific exception information * context = opaque type of unwinder state information * Returns: * reason code * See_Also: * http://www.ucw.cz/~hubicka/papers/abi/node25.html */ extern (C) _Unwind_Reason_Code __dmd_personality_v0(int ver, _Unwind_Action actions, _Unwind_Exception_Class exceptionClass, _Unwind_Exception* exceptionObject, _Unwind_Context* context) { //printf("__dmd_personality_v0(actions = x%x, eo = %p, context = %p)\n", cast(int)actions, exceptionObject, context); //printf("exceptionClass = x%08lx\n", exceptionClass); if (ver != 1) return _URC_FATAL_PHASE1_ERROR; assert(context); const(ubyte)* language_specific_data; int handler; _Unwind_Ptr landing_pad; //for (auto ehx = eh; ehx; ehx = ehx.next) //printf(" eh: %p next=%014p lsda=%p '%.*s'\n", ehx, ehx.next, ehx.languageSpecificData, ehx.object.msg.length, ehx.object.msg.ptr); language_specific_data = cast(const(ubyte)*)_Unwind_GetLanguageSpecificData(context); //printf("lsda = %p\n", language_specific_data); auto Start = _Unwind_GetRegionStart(context); /* Get instruction pointer (ip) at start of instruction that threw */ version (CRuntime_Glibc) { int ip_before_insn; // The instruction pointer must not be decremented when unwinding from a // signal handler frame (asynchronous exception, also see // etc.linux.memoryerror). So use _Unwind_GetIPInfo where available. auto ip = _Unwind_GetIPInfo(context, &ip_before_insn); if (!ip_before_insn) --ip; } else { auto ip = _Unwind_GetIP(context); --ip; } //printf("ip = x%x\n", cast(int)(ip - Start)); //printf("\tStart = %p, ipoff = %p, lsda = %p\n", Start, ip - Start, language_specific_data); auto result = scanLSDA(language_specific_data, ip - Start, exceptionClass, (actions & _UA_FORCE_UNWIND) != 0, // don't catch when forced unwinding (actions & _UA_SEARCH_PHASE) != 0, // search phase is looking for handlers exceptionObject, landing_pad, handler); landing_pad += Start; final switch (result) { case LsdaResult.notFound: fprintf(stderr, "not found\n"); terminate(__LINE__); assert(0); case LsdaResult.foreign: terminate(__LINE__); assert(0); case LsdaResult.corrupt: fprintf(stderr, "LSDA is corrupt\n"); terminate(__LINE__); assert(0); case LsdaResult.noAction: //printf(" no action\n"); return _URC_CONTINUE_UNWIND; case LsdaResult.cleanup: //printf(" cleanup\n"); if (actions & _UA_SEARCH_PHASE) { return _URC_CONTINUE_UNWIND; } break; case LsdaResult.handler: //printf(" handler\n"); //printf(" eh.lsda = %p, lsda = %p\n", eh.languageSpecificData, language_specific_data); assert(!(actions & _UA_FORCE_UNWIND)); if (actions & _UA_SEARCH_PHASE) { if (exceptionClass == dmdExceptionClass) { auto eh = ExceptionHeader.toExceptionHeader(exceptionObject); eh.handler = handler; eh.languageSpecificData = language_specific_data; eh.landingPad = landing_pad; } return _URC_HANDLER_FOUND; } break; } //printf(" lsda = %p, landing_pad = %p, handler = %d\n", language_specific_data, landing_pad, handler); //printf( '%.*s' next = %p\n", eh.object.msg.length, eh.object.msg.ptr, eh.next); // Figure out what to do when there are multiple exceptions in flight if (exceptionClass == dmdExceptionClass) { auto eh = ExceptionHeader.toExceptionHeader(exceptionObject); while (eh.next) { ExceptionHeader* ehn = eh.next; // Don't combine when the exceptions are from different functions if (language_specific_data != ehn.languageSpecificData) { //printf("break: %p %p\n", language_specific_data, ehn.languageSpecificData); break; } Error e = cast(Error)eh.object; if (e !is null && !cast(Error)ehn.object) { /* eh is an Error, ehn is not. Skip ehn. */ //printf("bypass\n"); e.bypassedException = ehn.object; } else { //printf("chain\n"); // Append eh's object to ehn's object chain Throwable n = ehn.object; while (n.next) n = n.next; n.next = eh.object; // Replace our exception object with in-flight one eh.object = ehn.object; if (ehn.handler != handler) { handler = ehn.handler; eh.handler = handler; eh.languageSpecificData = language_specific_data; eh.landingPad = landing_pad; } } // Remove ehn from threaded chain eh.next = ehn.next; //printf("delete %p\n", ehn); _Unwind_DeleteException(&ehn.exception_object); // discard ehn } } // Set up registers and jump to cleanup or handler int reg0 = 0; // EAX/RAX is __exception_object int reg1 = (size_t.sizeof == 4) ? 2 : 1; // EDX/RDX is __handler _Unwind_SetGR(context, reg0, cast(_Unwind_Ptr)exceptionObject); _Unwind_SetGR(context, reg1, handler); _Unwind_SetIP(context, landing_pad); return _URC_INSTALL_CONTEXT; } /************************************************* * Look at the chain of inflight exceptions and pick the class type that'll * be looked for in catch clauses. * Params: * exceptionObject = language specific exception information * Returns: * class type to look for */ ClassInfo getClassInfo(_Unwind_Exception* exceptionObject) { ExceptionHeader* eh = ExceptionHeader.toExceptionHeader(exceptionObject); Throwable ehobject = eh.object; //printf("start: %p '%.*s'\n", ehobject, ehobject.classinfo.info.name.length, ehobject.classinfo.info.name.ptr); for (ExceptionHeader* ehn = eh.next; ehn; ehn = ehn.next) { //printf("ehn = %p '%.*s'\n", ehn.object, cast(int)ehn.object.classinfo.info.name.length, ehn.object.classinfo.info.name.ptr); Error e = cast(Error)ehobject; if (e is null || (cast(Error)ehn.object) !is null) ehobject = ehn.object; } //printf("end : %p\n", ehobject); return ehobject.classinfo; } /****************************** * Decode Unsigned LEB128. * Params: * p = pointer to data pointer, *p is updated * to point past decoded value * Returns: * decoded value * See_Also: * https://en.wikipedia.org/wiki/LEB128 */ _uleb128_t uLEB128(const(ubyte)** p) { auto q = *p; _uleb128_t result = 0; uint shift = 0; while (1) { ubyte b = *q++; result |= cast(_uleb128_t)(b & 0x7F) << shift; if ((b & 0x80) == 0) break; shift += 7; } *p = q; return result; } /****************************** * Decode Signed LEB128. * Params: * p = pointer to data pointer, *p is updated * to point past decoded value * Returns: * decoded value * See_Also: * https://en.wikipedia.org/wiki/LEB128 */ _sleb128_t sLEB128(const(ubyte)** p) { auto q = *p; ubyte b; _sleb128_t result = 0; uint shift = 0; while (1) { b = *q++; result |= cast(_sleb128_t)(b & 0x7F) << shift; shift += 7; if ((b & 0x80) == 0) break; } if (shift < result.sizeof * 8 && (b & 0x40)) result |= -(cast(_sleb128_t)1 << shift); *p = q; return result; } enum { DW_EH_PE_FORMAT_MASK = 0x0F, DW_EH_PE_APPL_MASK = 0x70, DW_EH_PE_indirect = 0x80, DW_EH_PE_omit = 0xFF, DW_EH_PE_ptr = 0x00, DW_EH_PE_uleb128 = 0x01, DW_EH_PE_udata2 = 0x02, DW_EH_PE_udata4 = 0x03, DW_EH_PE_udata8 = 0x04, DW_EH_PE_sleb128 = 0x09, DW_EH_PE_sdata2 = 0x0A, DW_EH_PE_sdata4 = 0x0B, DW_EH_PE_sdata8 = 0x0C, DW_EH_PE_absptr = 0x00, DW_EH_PE_pcrel = 0x10, DW_EH_PE_textrel = 0x20, DW_EH_PE_datarel = 0x30, DW_EH_PE_funcrel = 0x40, DW_EH_PE_aligned = 0x50, } /************************************************** * Read and extract information from the LSDA (aka gcc_except_table section). * The dmd Call Site Table is structurally different from other implementations. It * is organized as nested ranges, and one ip can map to multiple ranges. The most * nested candidate is selected when searched. Other implementations have one candidate * per ip. * Params: * lsda = pointer to LSDA table * ip = offset from start of function at which exception happened * exceptionClass = which language threw the exception * cleanupsOnly = only look for cleanups * preferHandler = if a handler encloses a cleanup, prefer the handler * exceptionObject = language specific exception information * landingPad = set to landing pad * handler = set to index of which catch clause was matched * Returns: * LsdaResult * See_Also: * http://reverseengineering.stackexchange.com/questions/6311/how-to-recover-the-exception-info-from-gcc-except-table-and-eh-handle-sections * http://www.airs.com/blog/archives/464 * https://anarcheuz.github.io/2015/02/15/ELF%20internals%20part%202%20-%20exception%20handling/ */ LsdaResult scanLSDA(const(ubyte)* lsda, _Unwind_Ptr ip, _Unwind_Exception_Class exceptionClass, bool cleanupsOnly, bool preferHandler, _Unwind_Exception* exceptionObject, out _Unwind_Ptr landingPad, out int handler) { auto p = lsda; if (!p) return LsdaResult.noAction; _Unwind_Ptr dw_pe_value(ubyte pe) { _Unwind_Ptr value = void; switch (pe) { case DW_EH_PE_uleb128: value = cast(_Unwind_Ptr) uLEB128(&p); break; case DW_EH_PE_udata2: value = cast(_Unwind_Ptr) *cast(ushort*)p; p += 2; break; case DW_EH_PE_udata4: value = cast(_Unwind_Ptr) *cast(uint*)p; p += 4; break; case DW_EH_PE_udata8: value = cast(_Unwind_Ptr) *cast(ulong*)p; p += 8; break; case DW_EH_PE_sleb128: value = cast(_Unwind_Ptr) sLEB128(&p); break; case DW_EH_PE_sdata2: value = cast(_Unwind_Ptr) *cast(short*)p; p += 2; break; case DW_EH_PE_sdata4: value = cast(_Unwind_Ptr) *cast(int*)p; p += 4; break; case DW_EH_PE_sdata8: value = cast(_Unwind_Ptr) *cast(long*)p; p += 8; break; case DW_EH_PE_ptr: if (size_t.sizeof == 8) goto case DW_EH_PE_udata8; else goto case DW_EH_PE_udata4; default: terminate(__LINE__); } return value; } ubyte LPstart = *p++; _Unwind_Ptr LPbase = 0; if (LPstart != DW_EH_PE_omit) { LPbase = dw_pe_value(LPstart); } ubyte TType = *p++; _Unwind_Ptr TTbase = 0; _Unwind_Ptr TToffset = 0; if (TType != DW_EH_PE_omit) { TTbase = uLEB128(&p); TToffset = (p - lsda) + TTbase; } ///*printf(" TType = "); print_dw_pe(TType);*/ printf(" TTbase = x%08llx\n", TTbase); ubyte CallSiteFormat = *p++; _Unwind_Ptr CallSiteTableSize = dw_pe_value(DW_EH_PE_uleb128); ///*printf(" CallSiteFormat = "); print_dw_pe(CallSiteFormat);*/ printf(" CallSiteTableSize = x%08llx\n", CallSiteTableSize); //printf(" Call Site Table\n"); _Unwind_Ptr ipoffset = ip - LPbase; //printf("ipoffset = x%x\n", cast(int)ipoffset); bool noAction = false; auto tt = lsda + TToffset; const(ubyte)* pActionTable = p + CallSiteTableSize; while (1) { if (p >= pActionTable) { if (p == pActionTable) break; fprintf(stderr, "no Call Site Table\n"); return LsdaResult.corrupt; } _Unwind_Ptr CallSiteStart = dw_pe_value(CallSiteFormat); _Unwind_Ptr CallSiteRange = dw_pe_value(CallSiteFormat); _Unwind_Ptr LandingPad = dw_pe_value(CallSiteFormat); _uleb128_t ActionRecordPtr = uLEB128(&p); //printf(" XT: start = x%x, range = x%x, landing pad = x%x, action = x%x\n", //cast(int)CallSiteStart, cast(int)CallSiteRange, cast(int)LandingPad, cast(int)ActionRecordPtr); if (ipoffset < CallSiteStart) break; // The most nested entry will be the last one that ip is in if (ipoffset < CallSiteStart + CallSiteRange) { //printf("\tmatch\n"); if (ActionRecordPtr) // if saw a catch { if (cleanupsOnly) continue; // ignore catch auto h = actionTableLookup(exceptionObject, cast(uint)ActionRecordPtr, pActionTable, tt, TType, exceptionClass); if (h < 0) { fprintf(stderr, "negative handler\n"); return LsdaResult.corrupt; } if (h == 0) continue; // ignore // The catch is good noAction = false; landingPad = LandingPad; handler = h; } else if (LandingPad) // if saw a cleanup { if (preferHandler && handler) // enclosing handler overrides cleanup continue; // keep looking noAction = false; landingPad = LandingPad; handler = 0; // cleanup hides the handler } else // take no action noAction = true; } } if (noAction) { assert(!landingPad && !handler); return LsdaResult.noAction; } if (landingPad) return handler ? LsdaResult.handler : LsdaResult.cleanup; return LsdaResult.notFound; } /******************************************** * Look up classType in Action Table. * Params: * exceptionObject = language specific exception information * actionRecordPtr = starting index in Action Table + 1 * pActionTable = pointer to start of Action Table * tt = pointer past end of Type Table * TType = encoding of entries in Type Table * exceptionClass = which language threw the exception * Returns: * >=1 means the handler index of the classType * 0 means classType is not in the Action Table * <0 means corrupt */ int actionTableLookup(_Unwind_Exception* exceptionObject, uint actionRecordPtr, const(ubyte)* pActionTable, const(ubyte)* tt, ubyte TType, _Unwind_Exception_Class exceptionClass) { //printf("actionTableLookup(catchType = %p, actionRecordPtr = %d, pActionTable = %p, tt = %p)\n", //catchType, actionRecordPtr, pActionTable, tt); assert(pActionTable < tt); ClassInfo thrownType; if (exceptionClass == dmdExceptionClass) { thrownType = getClassInfo(exceptionObject); } for (auto ap = pActionTable + actionRecordPtr - 1; 1; ) { assert(pActionTable <= ap && ap < tt); auto TypeFilter = sLEB128(&ap); auto apn = ap; auto NextRecordPtr = sLEB128(&ap); //printf(" at: TypeFilter = %d, NextRecordPtr = %d\n", cast(int)TypeFilter, cast(int)NextRecordPtr); if (TypeFilter <= 0) // should never happen with DMD generated tables { fprintf(stderr, "TypeFilter = %d\n", cast(int)TypeFilter); return -1; // corrupt } /* TypeFilter is negative index from TToffset, * which is where the ClassInfo is stored */ _Unwind_Ptr entry; const(ubyte)* tt2; switch (TType & DW_EH_PE_FORMAT_MASK) { case DW_EH_PE_udata2: entry = cast(_Unwind_Ptr) *cast(ushort*)(tt2 = tt - TypeFilter * 2); break; case DW_EH_PE_udata4: entry = cast(_Unwind_Ptr) *cast(uint*) (tt2 = tt - TypeFilter * 4); break; case DW_EH_PE_udata8: entry = cast(_Unwind_Ptr) *cast(ulong*) (tt2 = tt - TypeFilter * 8); break; case DW_EH_PE_sdata2: entry = cast(_Unwind_Ptr) *cast(short*) (tt2 = tt - TypeFilter * 2); break; case DW_EH_PE_sdata4: entry = cast(_Unwind_Ptr) *cast(int*) (tt2 = tt - TypeFilter * 4); break; case DW_EH_PE_sdata8: entry = cast(_Unwind_Ptr) *cast(long*) (tt2 = tt - TypeFilter * 8); break; case DW_EH_PE_ptr: if (size_t.sizeof == 8) goto case DW_EH_PE_udata8; else goto case DW_EH_PE_udata4; default: fprintf(stderr, "TType = x%x\n", TType); return -1; // corrupt } if (!entry) // the 'catch all' type return -1; // corrupt: should never happen with DMD, which explicitly uses Throwable switch (TType & DW_EH_PE_APPL_MASK) { case DW_EH_PE_absptr: break; case DW_EH_PE_pcrel: entry += cast(_Unwind_Ptr)tt2; break; default: return -1; } if (TType & DW_EH_PE_indirect) entry = *cast(_Unwind_Ptr*)entry; ClassInfo ci = cast(ClassInfo)cast(void*)(entry); if (ci.classinfo is __cpp_type_info_ptr.classinfo) { if (exceptionClass == cppExceptionClass || exceptionClass == cppExceptionClass1) { // sti is catch clause type_info auto sti = cast(CppTypeInfo)((cast(__cpp_type_info_ptr)cast(void*)ci).ptr); auto p = getCppPtrToThrownObject(exceptionObject, sti); if (p) // if found { auto eh = CppExceptionHeader.toExceptionHeader(exceptionObject); eh.thrownPtr = p; // for __cxa_begin_catch() return cast(int)TypeFilter; } } } else if (exceptionClass == dmdExceptionClass && _d_isbaseof(thrownType, ci)) return cast(int)TypeFilter; // found it if (!NextRecordPtr) return 0; // catch not found ap = apn + NextRecordPtr; } terminate(__LINE__); assert(0); } enum LsdaResult { notFound, // ip was not found in the LSDA - an exception shouldn't have happened foreign, // found a result we cannot handle corrupt, // the tables are corrupt noAction, // found, but no action needed (i.e. no cleanup nor handler) cleanup, // cleanup found (i.e. finally or destructor) handler, // handler found (i.e. a catch) } void terminate(uint line) @nogc { printf("dwarfeh(%u) fatal error\n", line); abort(); // unceremoniously exit } /****************************** C++ Support *****************************/ enum _Unwind_Exception_Class cppExceptionClass = (cast(_Unwind_Exception_Class)'G' << 56) | (cast(_Unwind_Exception_Class)'N' << 48) | (cast(_Unwind_Exception_Class)'U' << 40) | (cast(_Unwind_Exception_Class)'C' << 32) | (cast(_Unwind_Exception_Class)'C' << 24) | (cast(_Unwind_Exception_Class)'+' << 16) | (cast(_Unwind_Exception_Class)'+' << 8) | (cast(_Unwind_Exception_Class)0 << 0); enum _Unwind_Exception_Class cppExceptionClass1 = cppExceptionClass + 1; /***************************************** * Get Pointer to Thrown Object if type of thrown object is implicitly * convertible to the catch type. * Params: * exceptionObject = language specific exception information * sti = type of catch clause * Returns: * null if not caught, pointer to thrown object if caught */ void* getCppPtrToThrownObject(_Unwind_Exception* exceptionObject, CppTypeInfo sti) { void* p; // pointer to thrown object if (exceptionObject.exception_class & 1) p = CppExceptionHeader.toExceptionHeader(exceptionObject).ptr; else p = cast(void*)(exceptionObject + 1); // thrown object is immediately after it const tt = (cast(CppExceptionHeader*)p - 1).typeinfo; if (tt.__is_pointer_p()) p = *cast(void**)p; // Pointer adjustment may be necessary due to multiple inheritance return (sti is tt || sti.__do_catch(tt, &p, 1)) ? p : null; } extern (C++) { /** * Access C++ std::type_info's virtual functions from D, * being careful to not require linking with libstd++ * or interfere with core.stdcpp.typeinfo. * So, give it a different name. */ interface CppTypeInfo // map to C++ std::type_info's virtual functions { void dtor1(); // consume destructor slot in vtbl[] void dtor2(); // consume destructor slot in vtbl[] bool __is_pointer_p() const; bool __is_function_p() const; bool __do_catch(const CppTypeInfo, void**, uint) const; bool __do_upcast(const void*, void**) const; } } /// The C++ version of D's ExceptionHeader wrapper struct CppExceptionHeader { union { CppTypeInfo typeinfo; // type that was thrown void* ptr; // pointer to real exception } void* p1; // unreferenced placeholders... void* p2; void* p3; void* p4; int i1; int i2; const(ubyte)* p5; const(ubyte)* p6; _Unwind_Ptr p7; void* thrownPtr; // pointer to thrown object _Unwind_Exception exception_object; // the unwinder's data /******************************* * Convert from pointer to exception_object field to pointer to CppExceptionHeader * that it is embedded inside of. * Params: * eo = pointer to exception_object field * Returns: * pointer to CppExceptionHeader that eo points into. */ static CppExceptionHeader* toExceptionHeader(_Unwind_Exception* eo) { return cast(CppExceptionHeader*)(eo + 1) - 1; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/arrayfloat.d0000664000175000017500000012405212776214756021214 0ustar kaikai/** * Contains SSE2 and MMX versions of certain operations for float. * * Copyright: Copyright Digital Mars 2008 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, based on code originally written by Burton Radons */ /* Copyright Digital Mars 2008 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.arrayfloat; // debug=PRINTF private import core.cpuid; import rt.util.array; version (unittest) { private import core.stdc.stdio : printf; /* This is so unit tests will test every CPU variant */ int cpuid; const int CPUID_MAX = 5; nothrow: @property bool mmx() { return cpuid == 1 && core.cpuid.mmx; } @property bool sse() { return cpuid == 2 && core.cpuid.sse; } @property bool sse2() { return cpuid == 3 && core.cpuid.sse2; } @property bool amd3dnow() { return cpuid == 4 && core.cpuid.amd3dnow; } } else { alias core.cpuid.mmx mmx; alias core.cpuid.sse sse; alias core.cpuid.sse2 sse2; alias core.cpuid.amd3dnow amd3dnow; } //version = log; alias float T; extern (C) @trusted nothrow: /* ======================================================================== */ /* ======================================================================== */ /* template for the case * a[] = b[] ? c[] * with some binary operator ? */ private template CodeGenSliceSliceOp(string opD, string opSSE, string op3DNow) { const CodeGenSliceSliceOp = ` auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE version is 834% faster if (sse && b.length >= 16) { auto n = aptr + (b.length & ~15); // Unaligned case asm pure nothrow @nogc { mov EAX, bptr; // left operand mov ECX, cptr; // right operand mov ESI, aptr; // destination operand mov EDI, n; // end comparison align 8; startsseloopb: movups XMM0, [EAX]; movups XMM1, [EAX+16]; movups XMM2, [EAX+32]; movups XMM3, [EAX+48]; add EAX, 64; movups XMM4, [ECX]; movups XMM5, [ECX+16]; movups XMM6, [ECX+32]; movups XMM7, [ECX+48]; add ESI, 64; ` ~ opSSE ~ ` XMM0, XMM4; ` ~ opSSE ~ ` XMM1, XMM5; ` ~ opSSE ~ ` XMM2, XMM6; ` ~ opSSE ~ ` XMM3, XMM7; add ECX, 64; movups [ESI+ 0-64], XMM0; movups [ESI+16-64], XMM1; movups [ESI+32-64], XMM2; movups [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopb; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else // 3DNow! version is only 13% faster if (amd3dnow && b.length >= 8) { auto n = aptr + (b.length & ~7); asm pure nothrow @nogc { mov ESI, aptr; // destination operand mov EDI, n; // end comparison mov EAX, bptr; // left operand mov ECX, cptr; // right operand align 4; start3dnow: movq MM0, [EAX]; movq MM1, [EAX+8]; movq MM2, [EAX+16]; movq MM3, [EAX+24]; ` ~ op3DNow ~ ` MM0, [ECX]; ` ~ op3DNow ~ ` MM1, [ECX+8]; ` ~ op3DNow ~ ` MM2, [ECX+16]; ` ~ op3DNow ~ ` MM3, [ECX+24]; movq [ESI], MM0; movq [ESI+8], MM1; movq [ESI+16], MM2; movq [ESI+24], MM3; add ECX, 32; add ESI, 32; add EAX, 32; cmp ESI, EDI; jb start3dnow; emms; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (b.length >= 16) { auto n = aptr + (b.length & ~15); // Unaligned case asm pure nothrow @nogc { mov RAX, bptr; // left operand mov RCX, cptr; // right operand mov RSI, aptr; // destination operand mov RDI, n; // end comparison align 8; startsseloopb: movups XMM0, [RAX]; movups XMM1, [RAX+16]; movups XMM2, [RAX+32]; movups XMM3, [RAX+48]; add RAX, 64; movups XMM4, [RCX]; movups XMM5, [RCX+16]; movups XMM6, [RCX+32]; movups XMM7, [RCX+48]; add RSI, 64; ` ~ opSSE ~ ` XMM0, XMM4; ` ~ opSSE ~ ` XMM1, XMM5; ` ~ opSSE ~ ` XMM2, XMM6; ` ~ opSSE ~ ` XMM3, XMM7; add RCX, 64; movups [RSI+ 0-64], XMM0; movups [RSI+16-64], XMM1; movups [RSI+32-64], XMM2; movups [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopb; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } // Handle remainder while (aptr < aend) *aptr++ = *bptr++ ` ~ opD ~ ` *cptr++; return a;`; } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + c[] */ T[] _arraySliceSliceAddSliceAssign_f(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); mixin(CodeGenSliceSliceOp!("+", "addps", "pfadd")); } unittest { debug(PRINTF) printf("_arraySliceSliceAddSliceAssign_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] + b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + b[i])) { printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - c[] */ T[] _arraySliceSliceMinSliceAssign_f(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); mixin(CodeGenSliceSliceOp!("-", "subps", "pfsub")); } unittest { debug(PRINTF) printf("_arraySliceSliceMinSliceAssign_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] - b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - b[i])) { printf("[%d]: %g != %gd - %g\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] * c[] */ T[] _arraySliceSliceMulSliceAssign_f(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); mixin(CodeGenSliceSliceOp!("*", "mulps", "pfmul")); } unittest { debug(PRINTF) printf("_arraySliceSliceMulSliceAssign_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] * b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * b[i])) { printf("[%d]: %g != %g * %g\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /* template for the case * a[] ?= value * with some binary operator ? */ private template CodeGenExpSliceOpAssign(string opD, string opSSE, string op3DNow) { const CodeGenExpSliceOpAssign = ` auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { if (sse && a.length >= 16) { auto aabeg = cast(T*)((cast(uint)aptr + 15) & ~15); // beginning of paragraph-aligned slice of a auto aaend = cast(T*)((cast(uint)aend) & ~15); // end of paragraph-aligned slice of a int numAligned = cast(int)(aaend - aabeg); // how many floats are in the aligned slice? // are there at least 16 floats in the paragraph-aligned slice? // otherwise we can't do anything with SSE. if (numAligned >= 16) { aaend = aabeg + (numAligned & ~15); // make sure the slice is actually a multiple of 16 floats long // process values up to aligned slice one by one while (aptr < aabeg) *aptr++ ` ~ opD ~ ` value; // process aligned slice with fast SSE operations asm pure nothrow @nogc { mov ESI, aabeg; mov EDI, aaend; movss XMM4, value; shufps XMM4, XMM4, 0; align 8; startsseloopa: movaps XMM0, [ESI]; movaps XMM1, [ESI+16]; movaps XMM2, [ESI+32]; movaps XMM3, [ESI+48]; add ESI, 64; ` ~ opSSE ~ ` XMM0, XMM4; ` ~ opSSE ~ ` XMM1, XMM4; ` ~ opSSE ~ ` XMM2, XMM4; ` ~ opSSE ~ ` XMM3, XMM4; movaps [ESI+ 0-64], XMM0; movaps [ESI+16-64], XMM1; movaps [ESI+32-64], XMM2; movaps [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopa; } aptr = aaend; } } else // 3DNow! version is 63% faster if (amd3dnow && a.length >= 8) { auto n = aptr + (a.length & ~7); ulong w = *cast(uint *) &value; ulong v = w | (w << 32L); asm pure nothrow @nogc { mov ESI, dword ptr [aptr]; mov EDI, dword ptr [n]; movq MM4, qword ptr [v]; align 8; start: movq MM0, [ESI]; movq MM1, [ESI+8]; movq MM2, [ESI+16]; movq MM3, [ESI+24]; ` ~ op3DNow ~ ` MM0, MM4; ` ~ op3DNow ~ ` MM1, MM4; ` ~ op3DNow ~ ` MM2, MM4; ` ~ op3DNow ~ ` MM3, MM4; movq [ESI], MM0; movq [ESI+8], MM1; movq [ESI+16], MM2; movq [ESI+24], MM3; add ESI, 32; cmp ESI, EDI; jb start; emms; mov dword ptr [aptr], ESI; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); if (aptr < n) asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movss XMM4, value; shufps XMM4, XMM4, 0; align 8; startsseloopa: movups XMM0, [RSI]; movups XMM1, [RSI+16]; movups XMM2, [RSI+32]; movups XMM3, [RSI+48]; add RSI, 64; ` ~ opSSE ~ ` XMM0, XMM4; ` ~ opSSE ~ ` XMM1, XMM4; ` ~ opSSE ~ ` XMM2, XMM4; ` ~ opSSE ~ ` XMM3, XMM4; movups [RSI+ 0-64], XMM0; movups [RSI+16-64], XMM1; movups [RSI+32-64], XMM2; movups [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopa; mov aptr, RSI; } } } while (aptr < aend) *aptr++ ` ~ opD ~ ` value; return a;`; } /* ======================================================================== */ /*********************** * Computes: * a[] += value */ T[] _arrayExpSliceAddass_f(T[] a, T value) { mixin(CodeGenExpSliceOpAssign!("+=", "addps", "pfadd")); } unittest { debug(PRINTF) printf("_arrayExpSliceAddass_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] += 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + 6)) { printf("[%d]: %g != %g + 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= value */ T[] _arrayExpSliceMinass_f(T[] a, T value) { mixin(CodeGenExpSliceOpAssign!("-=", "subps", "pfsub")); } unittest { debug(PRINTF) printf("_arrayExpSliceminass_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] -= 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - 6)) { printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] *= value */ T[] _arrayExpSliceMulass_f(T[] a, T value) { mixin(CodeGenExpSliceOpAssign!("*=", "mulps", "pfmul")); } unittest { debug(PRINTF) printf("_arrayExpSliceMulass_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] *= 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * 6)) { printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] /= value */ T[] _arrayExpSliceDivass_f(T[] a, T value) { return _arrayExpSliceMulass_f(a, 1f / value); } unittest { debug(PRINTF) printf("_arrayExpSliceDivass_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] /= 8; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] / 8)) { printf("[%d]: %g != %g / 8\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /* ======================================================================== */ /* template for the case * a[] = b[] ? value * with some binary operator ? */ private template CodeGenSliceExpOp(string opD, string opSSE, string op3DNow) { const CodeGenSliceExpOp = ` auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE version is 665% faster if (sse && a.length >= 16) { auto n = aptr + (a.length & ~15); // Unaligned case asm pure nothrow @nogc { mov EAX, bptr; mov ESI, aptr; mov EDI, n; movss XMM4, value; shufps XMM4, XMM4, 0; align 8; startsseloop: add ESI, 64; movups XMM0, [EAX]; movups XMM1, [EAX+16]; movups XMM2, [EAX+32]; movups XMM3, [EAX+48]; add EAX, 64; ` ~ opSSE ~ ` XMM0, XMM4; ` ~ opSSE ~ ` XMM1, XMM4; ` ~ opSSE ~ ` XMM2, XMM4; ` ~ opSSE ~ ` XMM3, XMM4; movups [ESI+ 0-64], XMM0; movups [ESI+16-64], XMM1; movups [ESI+32-64], XMM2; movups [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloop; mov aptr, ESI; mov bptr, EAX; } } else // 3DNow! version is 69% faster if (amd3dnow && a.length >= 8) { auto n = aptr + (a.length & ~7); ulong w = *cast(uint *) &value; ulong v = w | (w << 32L); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movq MM4, qword ptr [v]; align 8; start3dnow: movq MM0, [EAX]; movq MM1, [EAX+8]; movq MM2, [EAX+16]; movq MM3, [EAX+24]; ` ~ op3DNow ~ ` MM0, MM4; ` ~ op3DNow ~ ` MM1, MM4; ` ~ op3DNow ~ ` MM2, MM4; ` ~ op3DNow ~ ` MM3, MM4; movq [ESI], MM0; movq [ESI+8], MM1; movq [ESI+16], MM2; movq [ESI+24], MM3; add ESI, 32; add EAX, 32; cmp ESI, EDI; jb start3dnow; emms; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); // Unaligned case asm pure nothrow @nogc { mov RAX, bptr; mov RSI, aptr; mov RDI, n; movss XMM4, value; shufps XMM4, XMM4, 0; align 8; startsseloop: add RSI, 64; movups XMM0, [RAX]; movups XMM1, [RAX+16]; movups XMM2, [RAX+32]; movups XMM3, [RAX+48]; add RAX, 64; ` ~ opSSE ~ ` XMM0, XMM4; ` ~ opSSE ~ ` XMM1, XMM4; ` ~ opSSE ~ ` XMM2, XMM4; ` ~ opSSE ~ ` XMM3, XMM4; movups [RSI+ 0-64], XMM0; movups [RSI+16-64], XMM1; movups [RSI+32-64], XMM2; movups [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloop; mov aptr, RSI; mov bptr, RAX; } } } while (aptr < aend) *aptr++ = *bptr++ ` ~ opD ~ ` value; return a;`; } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + value */ T[] _arraySliceExpAddSliceAssign_f(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); mixin(CodeGenSliceExpOp!("+", "addps", "pfadd")); } unittest { debug(PRINTF) printf("_arraySliceExpAddSliceAssign_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] + 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + 6)) { printf("[%d]: %g != %g + 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - value */ T[] _arraySliceExpMinSliceAssign_f(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); mixin(CodeGenSliceExpOp!("-", "subps", "pfsub")); } unittest { debug(PRINTF) printf("_arraySliceExpMinSliceAssign_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] - 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - 6)) { printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] * value */ T[] _arraySliceExpMulSliceAssign_f(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); mixin(CodeGenSliceExpOp!("*", "mulps", "pfmul")); } unittest { debug(PRINTF) printf("_arraySliceExpMulSliceAssign_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] * 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * 6)) { printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] / value */ T[] _arraySliceExpDivSliceAssign_f(T[] a, T value, T[] b) { return _arraySliceExpMulSliceAssign_f(a, 1f/value, b); } unittest { debug(PRINTF) printf("_arraySliceExpDivSliceAssign_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] / 8; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] / 8)) { printf("[%d]: %g != %g / 8\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /* ======================================================================== */ /* template for the case * a[] ?= b[] * with some binary operator ? */ private template CodeGenSliceOpAssign(string opD, string opSSE, string op3DNow) { const CodeGenSliceOpAssign = ` auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE version is 468% faster if (sse && a.length >= 16) { auto n = aptr + (a.length & ~15); // Unaligned case asm pure nothrow @nogc { mov ECX, bptr; // right operand mov ESI, aptr; // destination operand mov EDI, n; // end comparison align 8; startsseloopb: movups XMM0, [ESI]; movups XMM1, [ESI+16]; movups XMM2, [ESI+32]; movups XMM3, [ESI+48]; add ESI, 64; movups XMM4, [ECX]; movups XMM5, [ECX+16]; movups XMM6, [ECX+32]; movups XMM7, [ECX+48]; add ECX, 64; ` ~ opSSE ~ ` XMM0, XMM4; ` ~ opSSE ~ ` XMM1, XMM5; ` ~ opSSE ~ ` XMM2, XMM6; ` ~ opSSE ~ ` XMM3, XMM7; movups [ESI+ 0-64], XMM0; movups [ESI+16-64], XMM1; movups [ESI+32-64], XMM2; movups [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopb; mov aptr, ESI; mov bptr, ECX; } } else // 3DNow! version is 57% faster if (amd3dnow && a.length >= 8) { auto n = aptr + (a.length & ~7); asm pure nothrow @nogc { mov ESI, dword ptr [aptr]; // destination operand mov EDI, dword ptr [n]; // end comparison mov ECX, dword ptr [bptr]; // right operand align 4; start3dnow: movq MM0, [ESI]; movq MM1, [ESI+8]; movq MM2, [ESI+16]; movq MM3, [ESI+24]; ` ~ op3DNow ~ ` MM0, [ECX]; ` ~ op3DNow ~ ` MM1, [ECX+8]; ` ~ op3DNow ~ ` MM2, [ECX+16]; ` ~ op3DNow ~ ` MM3, [ECX+24]; movq [ESI], MM0; movq [ESI+8], MM1; movq [ESI+16], MM2; movq [ESI+24], MM3; add ESI, 32; add ECX, 32; cmp ESI, EDI; jb start3dnow; emms; mov dword ptr [aptr], ESI; mov dword ptr [bptr], ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); // Unaligned case asm pure nothrow @nogc { mov RCX, bptr; // right operand mov RSI, aptr; // destination operand mov RDI, n; // end comparison align 8; startsseloopb: movups XMM0, [RSI]; movups XMM1, [RSI+16]; movups XMM2, [RSI+32]; movups XMM3, [RSI+48]; add RSI, 64; movups XMM4, [RCX]; movups XMM5, [RCX+16]; movups XMM6, [RCX+32]; movups XMM7, [RCX+48]; add RCX, 64; ` ~ opSSE ~ ` XMM0, XMM4; ` ~ opSSE ~ ` XMM1, XMM5; ` ~ opSSE ~ ` XMM2, XMM6; ` ~ opSSE ~ ` XMM3, XMM7; movups [RSI+ 0-64], XMM0; movups [RSI+16-64], XMM1; movups [RSI+32-64], XMM2; movups [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopb; mov aptr, RSI; mov bptr, RCX; } } } while (aptr < aend) *aptr++ ` ~ opD ~ ` *bptr++; return a;`; } /* ======================================================================== */ /*********************** * Computes: * a[] += b[] */ T[] _arraySliceSliceAddass_f(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); mixin(CodeGenSliceOpAssign!("+=", "addps", "pfadd")); } unittest { debug(PRINTF) printf("_arraySliceSliceAddass_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] += b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + b[i])) { printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= b[] */ T[] _arraySliceSliceMinass_f(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); mixin(CodeGenSliceOpAssign!("-=", "subps", "pfsub")); } unittest { debug(PRINTF) printf("_arrayExpSliceMinass_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] -= 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - 6)) { printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] *= b[] */ T[] _arraySliceSliceMulass_f(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); mixin(CodeGenSliceOpAssign!("*=", "mulps", "pfmul")); } unittest { debug(PRINTF) printf("_arrayExpSliceMulass_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] *= 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * 6)) { printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /* ======================================================================== */ /*********************** * Computes: * a[] = value - b[] */ T[] _arrayExpSliceMinSliceAssign_f(T[] a, T[] b, T value) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arrayExpSliceMinSliceAssign_f()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE version is 690% faster if (sse && a.length >= 16) { auto n = aptr + (a.length & ~15); // Unaligned case asm pure nothrow @nogc { mov EAX, bptr; mov ESI, aptr; mov EDI, n; movss XMM4, value; shufps XMM4, XMM4, 0; align 8; startsseloop: add ESI, 64; movaps XMM5, XMM4; movaps XMM6, XMM4; movups XMM0, [EAX]; movups XMM1, [EAX+16]; movups XMM2, [EAX+32]; movups XMM3, [EAX+48]; add EAX, 64; subps XMM5, XMM0; subps XMM6, XMM1; movups [ESI+ 0-64], XMM5; movups [ESI+16-64], XMM6; movaps XMM5, XMM4; movaps XMM6, XMM4; subps XMM5, XMM2; subps XMM6, XMM3; movups [ESI+32-64], XMM5; movups [ESI+48-64], XMM6; cmp ESI, EDI; jb startsseloop; mov aptr, ESI; mov bptr, EAX; } } else // 3DNow! version is 67% faster if (amd3dnow && a.length >= 8) { auto n = aptr + (a.length & ~7); ulong w = *cast(uint *) &value; ulong v = w | (w << 32L); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movq MM4, qword ptr [v]; align 8; start3dnow: movq MM0, [EAX]; movq MM1, [EAX+8]; movq MM2, [EAX+16]; movq MM3, [EAX+24]; pfsubr MM0, MM4; pfsubr MM1, MM4; pfsubr MM2, MM4; pfsubr MM3, MM4; movq [ESI], MM0; movq [ESI+8], MM1; movq [ESI+16], MM2; movq [ESI+24], MM3; add ESI, 32; add EAX, 32; cmp ESI, EDI; jb start3dnow; emms; mov aptr, ESI; mov bptr, EAX; } } } while (aptr < aend) *aptr++ = value - *bptr++; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinSliceAssign_f unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = 6 - a[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(6 - a[i])) { printf("[%d]: %g != 6 - %g\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= b[] * value */ T[] _arraySliceExpMulSliceMinass_f(T[] a, T value, T[] b) { return _arraySliceExpMulSliceAddass_f(a, -value, b); } /*********************** * Computes: * a[] += b[] * value */ T[] _arraySliceExpMulSliceAddass_f(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; // Handle remainder while (aptr < aend) *aptr++ += *bptr++ * value; return a; } unittest { debug(PRINTF) printf("_arraySliceExpMulSliceAddass_f unittest\n"); cpuid = 1; { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 1; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } b[] = c[]; c[] += a[] * 6; for (int i = 0; i < dim; i++) { //printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]); if (c[i] != cast(T)(b[i] + a[i] * 6)) { printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]); assert(0); } } } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/memory.d0000664000175000017500000000125512776214756020357 0ustar kaikai/** * This module tells the garbage collector about the static data and bss segments, * so the GC can scan them for roots. It does not deal with thread local static data. * * Copyright: Copyright Digital Mars 2000 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC src/rt/_memory.d) */ module rt.memory; import core.memory; import rt.sections; void initStaticDataGC() { foreach (ref sg; SectionGroup) { foreach (rng; sg.gcRanges) GC.addRange(rng.ptr, rng.length); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/dylib_fixes.c0000664000175000017500000000117112776214756021344 0ustar kaikai/** * OS X support for dynamic libraries. * * Copyright: Copyright Digital Mars 2010 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2010 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ void* _Dmain __attribute__((weak)); char rt_init (); char rt_term (); __attribute__((constructor)) static void initializer () { rt_init(); } __attribute__((destructor)) static void finalizer () { rt_term(); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/msvc.c0000664000175000017500000001243712776214756020022 0ustar kaikai/** * This module provides MS VC runtime helper function that * wrap differences between different versions of the MS C runtime * * Copyright: Copyright Digital Mars 2015. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Source: $(DRUNTIMESRC rt/_msvc.c) * Authors: Rainer Schuetze */ struct _iobuf { char* _ptr; int _cnt; // _cnt and _base exchanged for VS2015 char* _base; int _flag; int _file; int _charbuf; int _bufsiz; char* _tmpfname; // additional members in VS2015 }; typedef struct _iobuf FILE; extern FILE* stdin; extern FILE* stdout; extern FILE* stderr; FILE* __acrt_iob_func(int hnd); // VS2015+ FILE* __iob_func(); // VS2013- int _set_output_format(int format); // VS2013- //extern const char* __acrt_iob_func; extern const char* _nullfunc = 0; #if defined _M_IX86 #define C_PREFIX "_" #elif defined _M_X64 || defined _M_ARM || defined _M_ARM64 #define C_PREFIX "" #else #error Unsupported architecture #endif #define DECLARE_ALTERNATE_NAME(name, alternate_name) \ __pragma(comment(linker, "/alternatename:" C_PREFIX #name "=" C_PREFIX #alternate_name)) DECLARE_ALTERNATE_NAME (__acrt_iob_func, _nullfunc); DECLARE_ALTERNATE_NAME (__iob_func, _nullfunc); DECLARE_ALTERNATE_NAME (_set_output_format, _nullfunc); void init_msvc() { if (&__acrt_iob_func != (void*) &_nullfunc) { stdin = __acrt_iob_func(0); stdout = __acrt_iob_func(1); stderr = __acrt_iob_func(2); } else if (&__iob_func != (void*) &_nullfunc) { FILE* fp = __iob_func(); stdin = fp; stdout = fp + 1; stderr = fp + 2; } if (&_set_output_format != (void*) &_nullfunc) { const int _TWO_DIGIT_EXPONENT = 1; _set_output_format(_TWO_DIGIT_EXPONENT); } } // VS2015+ provides C99-conformant (v)snprintf functions, so weakly // link to legacy _(v)snprintf (not C99-conformant!) for VS2013- only DECLARE_ALTERNATE_NAME (snprintf, _snprintf); DECLARE_ALTERNATE_NAME (vsnprintf, _vsnprintf); // VS2013- implements these functions as macros, VS2015+ provides symbols DECLARE_ALTERNATE_NAME (_fputc_nolock, _msvc_fputc_nolock); DECLARE_ALTERNATE_NAME (_fgetc_nolock, _msvc_fgetc_nolock); DECLARE_ALTERNATE_NAME (rewind, _msvc_rewind); DECLARE_ALTERNATE_NAME (clearerr, _msvc_clearerr); DECLARE_ALTERNATE_NAME (feof, _msvc_feof); DECLARE_ALTERNATE_NAME (ferror, _msvc_ferror); DECLARE_ALTERNATE_NAME (fileno, _msvc_fileno); // VS2013- helper functions int _filbuf(FILE* fp); int _flsbuf(int c, FILE* fp); DECLARE_ALTERNATE_NAME (_filbuf, _nullfunc); DECLARE_ALTERNATE_NAME (_flsbuf, _nullfunc); int _msvc_fputc_nolock(int c, FILE* fp) { fp->_cnt = fp->_cnt - 1; if (fp->_cnt >= 0) { *(fp->_ptr) = (char)c; fp->_ptr = fp->_ptr + 1; return (char)c; } else return _flsbuf(c, fp); } int _msvc_fgetc_nolock(FILE* fp) { fp->_cnt = fp->_cnt - 1; if (fp->_cnt >= 0) { char c = *(fp->_ptr); fp->_ptr = fp->_ptr + 1; return c; } else return _filbuf(fp); } enum { SEEK_SET = 0, _IOEOF = 0x10, _IOERR = 0x20 }; int fseek(FILE* fp, long off, int whence); void _msvc_rewind(FILE* stream) { fseek(stream, 0L, SEEK_SET); stream->_flag = stream->_flag & ~_IOERR; } void _msvc_clearerr(FILE* stream) { stream->_flag = stream->_flag & ~(_IOERR | _IOEOF); } int _msvc_feof(FILE* stream) { return stream->_flag & _IOEOF; } int _msvc_ferror(FILE* stream) { return stream->_flag & _IOERR; } int _msvc_fileno(FILE* stream) { return stream->_file; } /** * 32-bit x86 MS VC runtimes lack most single-precision math functions. * Declare alternate implementations to be pulled in from msvc_math.c. */ #if defined _M_IX86 DECLARE_ALTERNATE_NAME (acosf, _msvc_acosf); DECLARE_ALTERNATE_NAME (asinf, _msvc_asinf); DECLARE_ALTERNATE_NAME (atanf, _msvc_atanf); DECLARE_ALTERNATE_NAME (atan2f, _msvc_atan2f); DECLARE_ALTERNATE_NAME (cosf, _msvc_cosf); DECLARE_ALTERNATE_NAME (sinf, _msvc_sinf); DECLARE_ALTERNATE_NAME (tanf, _msvc_tanf); DECLARE_ALTERNATE_NAME (coshf, _msvc_coshf); DECLARE_ALTERNATE_NAME (sinhf, _msvc_sinhf); DECLARE_ALTERNATE_NAME (tanhf, _msvc_tanhf); DECLARE_ALTERNATE_NAME (expf, _msvc_expf); DECLARE_ALTERNATE_NAME (logf, _msvc_logf); DECLARE_ALTERNATE_NAME (log10f, _msvc_log10f); DECLARE_ALTERNATE_NAME (powf, _msvc_powf); DECLARE_ALTERNATE_NAME (sqrtf, _msvc_sqrtf); DECLARE_ALTERNATE_NAME (ceilf, _msvc_ceilf); DECLARE_ALTERNATE_NAME (floorf, _msvc_floorf); DECLARE_ALTERNATE_NAME (fmodf, _msvc_fmodf); DECLARE_ALTERNATE_NAME (modff, _msvc_modff); #endif // _M_IX86 // LDC #if _MSC_VER >= 1900 // VS2015+ // needed for some symbols that are inline functions in the C headers #pragma comment(lib, "legacy_stdio_definitions.lib") // win32 exception handling needs VC runtime hooks #ifdef _DLL #ifdef _DEBUG #pragma comment(lib, "vcruntimed.lib") #else #pragma comment(lib, "vcruntime.lib") #endif #else #ifdef _DEBUG #pragma comment(lib, "libvcruntimed.lib") #else #pragma comment(lib, "libvcruntime.lib") #endif #endif #endif ldc-1.1.0-beta3-src/runtime/druntime/src/rt/arrayshort.d0000664000175000017500000025214012776214756021246 0ustar kaikai/** * Contains SSE2 and MMX versions of certain operations for wchar, short, * and ushort ('u', 's' and 't' suffixes). * * Copyright: Copyright Digital Mars 2008 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, based on code originally written by Burton Radons */ /* Copyright Digital Mars 2008 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.arrayshort; // debug=PRINTF private import core.cpuid; import rt.util.array; version (unittest) { private import core.stdc.stdio : printf; /* This is so unit tests will test every CPU variant */ int cpuid; const int CPUID_MAX = 4; nothrow: @property bool mmx() { return cpuid == 1 && core.cpuid.mmx; } @property bool sse() { return cpuid == 2 && core.cpuid.sse; } @property bool sse2() { return cpuid == 3 && core.cpuid.sse2; } @property bool amd3dnow() { return cpuid == 4 && core.cpuid.amd3dnow; } } else { alias core.cpuid.mmx mmx; alias core.cpuid.sse sse; alias core.cpuid.sse2 sse2; alias core.cpuid.sse2 sse2; } //version = log; alias short T; extern (C) @trusted nothrow: /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + value */ T[] _arraySliceExpAddSliceAssign_u(T[] a, T value, T[] b) { return _arraySliceExpAddSliceAssign_s(a, value, b); } T[] _arraySliceExpAddSliceAssign_t(T[] a, T value, T[] b) { return _arraySliceExpAddSliceAssign_s(a, value, b); } T[] _arraySliceExpAddSliceAssign_s(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceExpAddSliceAssign_s()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 3343% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add EAX, 32; paddw XMM0, XMM2; paddw XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add EAX, 32; paddw XMM0, XMM2; paddw XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; mov bptr, EAX; } } } else // MMX version is 3343% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); uint l = cast(ushort) value; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd MM2, l; pshufw MM2, MM2, 0; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM1, [EAX+8]; add EAX, 16; paddw MM0, MM2; paddw MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM1, [RAX+16]; add RAX, 32; paddw XMM0, XMM2; paddw XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; mov bptr, RAX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM1, [RAX+16]; add RAX, 32; paddw XMM0, XMM2; paddw XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; mov bptr, RAX; } } } } while (aptr < aend) *aptr++ = cast(T)(*bptr++ + value); return a; } unittest { debug(PRINTF) printf("_arraySliceExpAddSliceAssign_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] + 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + 6)) { printf("[%d]: %d != %d + 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + c[] */ T[] _arraySliceSliceAddSliceAssign_u(T[] a, T[] c, T[] b) { return _arraySliceSliceAddSliceAssign_s(a, c, b); } T[] _arraySliceSliceAddSliceAssign_t(T[] a, T[] c, T[] b) { return _arraySliceSliceAddSliceAssign_s(a, c, b); } T[] _arraySliceSliceAddSliceAssign_s(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); //printf("_arraySliceSliceAddSliceAssign_s()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 3777% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add EAX, 32; movdqu XMM2, [ECX]; movdqu XMM3, [ECX+16]; add ECX, 32; paddw XMM0, XMM2; paddw XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add EAX, 32; movdqa XMM2, [ECX]; movdqa XMM3, [ECX+16]; add ECX, 32; paddw XMM0, XMM2; paddw XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else // MMX version is 2068% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM1, [EAX+8]; add EAX, 16; movq MM2, [ECX]; movq MM3, [ECX+8]; add ECX, 16; paddw MM0, MM2; paddw MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM1, [RAX+16]; add RAX, 32; movdqu XMM2, [RCX]; movdqu XMM3, [RCX+16]; add RCX, 32; paddw XMM0, XMM2; paddw XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM1, [RAX+16]; add RAX, 32; movdqa XMM2, [RCX]; movdqa XMM3, [RCX+16]; add RCX, 32; paddw XMM0, XMM2; paddw XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } } while (aptr < aend) *aptr++ = cast(T)(*bptr++ + *cptr++); return a; } unittest { debug(PRINTF) printf("_arraySliceSliceAddSliceAssign_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] + b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + b[i])) { printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] += value */ T[] _arrayExpSliceAddass_u(T[] a, T value) { return _arrayExpSliceAddass_s(a, value); } T[] _arrayExpSliceAddass_t(T[] a, T value) { return _arrayExpSliceAddass_s(a, value); } T[] _arrayExpSliceAddass_s(T[] a, T value) { //printf("_arrayExpSliceAddass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value); auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 aligned version is 832% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; add ESI, 32; paddw XMM0, XMM2; paddw XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; add ESI, 32; paddw XMM0, XMM2; paddw XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; } } } else // MMX version is 826% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); uint l = cast(ushort) value; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movd MM2, l; pshufw MM2, MM2, 0; align 4; startmmx: movq MM0, [ESI]; movq MM1, [ESI+8]; add ESI, 16; paddw MM0, MM2; paddw MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: movdqu XMM0, [RSI]; movdqu XMM1, [RSI+16]; add RSI, 32; paddw XMM0, XMM2; paddw XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: movdqa XMM0, [RSI]; movdqa XMM1, [RSI+16]; add RSI, 32; paddw XMM0, XMM2; paddw XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; } } } } while (aptr < aend) *aptr++ += value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceAddass_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; a[] += 6; for (int i = 0; i < dim; i++) { if (a[i] != cast(T)(c[i] + 6)) { printf("[%d]: %d != %d + 6\n", i, a[i], c[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] += b[] */ T[] _arraySliceSliceAddass_u(T[] a, T[] b) { return _arraySliceSliceAddass_s(a, b); } T[] _arraySliceSliceAddass_t(T[] a, T[] b) { return _arraySliceSliceAddass_s(a, b); } T[] _arraySliceSliceAddass_s(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceSliceAddass_s()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 2085% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; add ESI, 32; movdqu XMM2, [ECX]; movdqu XMM3, [ECX+16]; add ECX, 32; paddw XMM0, XMM2; paddw XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; add ESI, 32; movdqa XMM2, [ECX]; movdqa XMM3, [ECX+16]; add ECX, 32; paddw XMM0, XMM2; paddw XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, ECX; } } } else // MMX version is 1022% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; start: movq MM0, [ESI]; movq MM1, [ESI+8]; add ESI, 16; movq MM2, [ECX]; movq MM3, [ECX+8]; add ECX, 16; paddw MM0, MM2; paddw MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb start; emms; mov aptr, ESI; mov bptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2u: movdqu XMM0, [RSI]; movdqu XMM1, [RSI+16]; add RSI, 32; movdqu XMM2, [RCX]; movdqu XMM3, [RCX+16]; add RCX, 32; paddw XMM0, XMM2; paddw XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RCX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2a: movdqa XMM0, [RSI]; movdqa XMM1, [RSI+16]; add RSI, 32; movdqa XMM2, [RCX]; movdqa XMM3, [RCX+16]; add RCX, 32; paddw XMM0, XMM2; paddw XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RCX; } } } } while (aptr < aend) *aptr++ += *bptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceAddass_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } b[] = c[]; c[] += a[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(b[i] + a[i])) { printf("[%d]: %d != %d + %d\n", i, c[i], b[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - value */ T[] _arraySliceExpMinSliceAssign_u(T[] a, T value, T[] b) { return _arraySliceExpMinSliceAssign_s(a, value, b); } T[] _arraySliceExpMinSliceAssign_t(T[] a, T value, T[] b) { return _arraySliceExpMinSliceAssign_s(a, value, b); } T[] _arraySliceExpMinSliceAssign_s(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceExpMinSliceAssign_s()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 3695% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add EAX, 32; psubw XMM0, XMM2; psubw XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add EAX, 32; psubw XMM0, XMM2; psubw XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; mov bptr, EAX; } } } else // MMX version is 3049% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); uint l = cast(ushort) value; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd MM2, l; pshufw MM2, MM2, 0; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM1, [EAX+8]; add EAX, 16; psubw MM0, MM2; psubw MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM1, [RAX+16]; add RAX, 32; psubw XMM0, XMM2; psubw XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; mov bptr, RAX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM1, [RAX+16]; add RAX, 32; psubw XMM0, XMM2; psubw XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; mov bptr, RAX; } } } else // MMX version is 3049% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); uint l = cast(ushort) value; asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd MM2, l; pshufw MM2, MM2, 0; align 4; startmmx: add RSI, 16; movq MM0, [RAX]; movq MM1, [RAX+8]; add RAX, 16; psubw MM0, MM2; psubw MM1, MM2; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; mov bptr, RAX; } } } while (aptr < aend) *aptr++ = cast(T)(*bptr++ - value); return a; } unittest { debug(PRINTF) printf("_arraySliceExpMinSliceAssign_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] - 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - 6)) { printf("[%d]: %d != %d - 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = value - b[] */ T[] _arrayExpSliceMinSliceAssign_u(T[] a, T[] b, T value) { return _arrayExpSliceMinSliceAssign_s(a, b, value); } T[] _arrayExpSliceMinSliceAssign_t(T[] a, T[] b, T value) { return _arrayExpSliceMinSliceAssign_s(a, b, value); } T[] _arrayExpSliceMinSliceAssign_s(T[] a, T[] b, T value) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arrayExpSliceMinSliceAssign_s()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 4995% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; align 4; startaddsse2u: movd XMM2, l; pshufd XMM2, XMM2, 0; movd XMM3, l; pshufd XMM3, XMM3, 0; add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add EAX, 32; psubw XMM2, XMM0; psubw XMM3, XMM1; movdqu [ESI -32], XMM2; movdqu [ESI+16-32], XMM3; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; align 4; startaddsse2a: movd XMM2, l; pshufd XMM2, XMM2, 0; movd XMM3, l; pshufd XMM3, XMM3, 0; add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add EAX, 32; psubw XMM2, XMM0; psubw XMM3, XMM1; movdqa [ESI -32], XMM2; movdqa [ESI+16-32], XMM3; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; mov bptr, EAX; } } } else // MMX version is 4562% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); uint l = cast(ushort) value; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd MM4, l; pshufw MM4, MM4, 0; align 4; startmmx: add ESI, 16; movq MM2, [EAX]; movq MM3, [EAX+8]; movq MM0, MM4; movq MM1, MM4; add EAX, 16; psubw MM0, MM2; psubw MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; align 4; startaddsse2u: movd XMM2, l; pshufd XMM2, XMM2, 0; movd XMM3, l; pshufd XMM3, XMM3, 0; add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM1, [RAX+16]; add RAX, 32; psubw XMM2, XMM0; psubw XMM3, XMM1; movdqu [RSI -32], XMM2; movdqu [RSI+16-32], XMM3; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; mov bptr, RAX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; align 4; startaddsse2a: movd XMM2, l; pshufd XMM2, XMM2, 0; movd XMM3, l; pshufd XMM3, XMM3, 0; add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM1, [RAX+16]; add RAX, 32; psubw XMM2, XMM0; psubw XMM3, XMM1; movdqa [RSI -32], XMM2; movdqa [RSI+16-32], XMM3; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; mov bptr, RAX; } } } } while (aptr < aend) *aptr++ = cast(T)(value - *bptr++); return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinSliceAssign_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = 6 - a[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(6 - a[i])) { printf("[%d]: %d != 6 - %d\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - c[] */ T[] _arraySliceSliceMinSliceAssign_u(T[] a, T[] c, T[] b) { return _arraySliceSliceMinSliceAssign_s(a, c, b); } T[] _arraySliceSliceMinSliceAssign_t(T[] a, T[] c, T[] b) { return _arraySliceSliceMinSliceAssign_s(a, c, b); } T[] _arraySliceSliceMinSliceAssign_s(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 4129% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add EAX, 32; movdqu XMM2, [ECX]; movdqu XMM3, [ECX+16]; add ECX, 32; psubw XMM0, XMM2; psubw XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add EAX, 32; movdqa XMM2, [ECX]; movdqa XMM3, [ECX+16]; add ECX, 32; psubw XMM0, XMM2; psubw XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else // MMX version is 2018% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM1, [EAX+8]; add EAX, 16; movq MM2, [ECX]; movq MM3, [ECX+8]; add ECX, 16; psubw MM0, MM2; psubw MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM1, [RAX+16]; add RAX, 32; movdqu XMM2, [RCX]; movdqu XMM3, [RCX+16]; add RCX, 32; psubw XMM0, XMM2; psubw XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM1, [RAX+16]; add RAX, 32; movdqa XMM2, [RCX]; movdqa XMM3, [RCX+16]; add RCX, 32; psubw XMM0, XMM2; psubw XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } } while (aptr < aend) *aptr++ = cast(T)(*bptr++ - *cptr++); return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMinSliceAssign_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] - b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - b[i])) { printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= value */ T[] _arrayExpSliceMinass_u(T[] a, T value) { return _arrayExpSliceMinass_s(a, value); } T[] _arrayExpSliceMinass_t(T[] a, T value) { return _arrayExpSliceMinass_s(a, value); } T[] _arrayExpSliceMinass_s(T[] a, T value) { //printf("_arrayExpSliceMinass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value); auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 aligned version is 835% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; add ESI, 32; psubw XMM0, XMM2; psubw XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; add ESI, 32; psubw XMM0, XMM2; psubw XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; } } } else // MMX version is 835% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); uint l = cast(ushort) value; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movd MM2, l; pshufw MM2, MM2, 0; align 4; startmmx: movq MM0, [ESI]; movq MM1, [ESI+8]; add ESI, 16; psubw MM0, MM2; psubw MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= (l << 16); if (((cast(uint) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: movdqu XMM0, [RSI]; movdqu XMM1, [RSI+16]; add RSI, 32; psubw XMM0, XMM2; psubw XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: movdqa XMM0, [RSI]; movdqa XMM1, [RSI+16]; add RSI, 32; psubw XMM0, XMM2; psubw XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; } } } } while (aptr < aend) *aptr++ -= value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinass_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; a[] -= 6; for (int i = 0; i < dim; i++) { if (a[i] != cast(T)(c[i] - 6)) { printf("[%d]: %d != %d - 6\n", i, a[i], c[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= b[] */ T[] _arraySliceSliceMinass_u(T[] a, T[] b) { return _arraySliceSliceMinass_s(a, b); } T[] _arraySliceSliceMinass_t(T[] a, T[] b) { return _arraySliceSliceMinass_s(a, b); } T[] _arraySliceSliceMinass_s(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceSliceMinass_s()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 2121% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; add ESI, 32; movdqu XMM2, [ECX]; movdqu XMM3, [ECX+16]; add ECX, 32; psubw XMM0, XMM2; psubw XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; add ESI, 32; movdqa XMM2, [ECX]; movdqa XMM3, [ECX+16]; add ECX, 32; psubw XMM0, XMM2; psubw XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, ECX; } } } else // MMX version is 1116% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; start: movq MM0, [ESI]; movq MM1, [ESI+8]; add ESI, 16; movq MM2, [ECX]; movq MM3, [ECX+8]; add ECX, 16; psubw MM0, MM2; psubw MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb start; emms; mov aptr, ESI; mov bptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2u: movdqu XMM0, [RSI]; movdqu XMM1, [RSI+16]; add RSI, 32; movdqu XMM2, [RCX]; movdqu XMM3, [RCX+16]; add RCX, 32; psubw XMM0, XMM2; psubw XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RCX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2a: movdqa XMM0, [RSI]; movdqa XMM1, [RSI+16]; add RSI, 32; movdqa XMM2, [RCX]; movdqa XMM3, [RCX+16]; add RCX, 32; psubw XMM0, XMM2; psubw XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RCX; } } } } while (aptr < aend) *aptr++ -= *bptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMinass_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } b[] = c[]; c[] -= a[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(b[i] - a[i])) { printf("[%d]: %d != %d - %d\n", i, c[i], b[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] * value */ T[] _arraySliceExpMulSliceAssign_u(T[] a, T value, T[] b) { return _arraySliceExpMulSliceAssign_s(a, value, b); } T[] _arraySliceExpMulSliceAssign_t(T[] a, T value, T[] b) { return _arraySliceExpMulSliceAssign_s(a, value, b); } T[] _arraySliceExpMulSliceAssign_s(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceExpMulSliceAssign_s()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 3733% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= l << 16; if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add EAX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add EAX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, EAX; } } } else // MMX version is 3733% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); uint l = cast(ushort) value; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd MM2, l; pshufw MM2, MM2, 0; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM1, [EAX+8]; add EAX, 16; pmullw MM0, MM2; pmullw MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= l << 16; if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startsse2u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM1, [RAX+16]; add RAX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RAX; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startsse2a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM1, [RAX+16]; add RAX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RAX; } } } } while (aptr < aend) *aptr++ = cast(T)(*bptr++ * value); return a; } unittest { debug(PRINTF) printf("_arraySliceExpMulSliceAssign_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] * 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * 6)) { printf("[%d]: %d != %d * 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] * c[] */ T[] _arraySliceSliceMulSliceAssign_u(T[] a, T[] c, T[] b) { return _arraySliceSliceMulSliceAssign_s(a, c, b); } T[] _arraySliceSliceMulSliceAssign_t(T[] a, T[] c, T[] b) { return _arraySliceSliceMulSliceAssign_s(a, c, b); } T[] _arraySliceSliceMulSliceAssign_s(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); //printf("_arraySliceSliceMulSliceAssign_s()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 2515% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM2, [ECX]; movdqu XMM1, [EAX+16]; movdqu XMM3, [ECX+16]; add EAX, 32; add ECX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM2, [ECX]; movdqa XMM1, [EAX+16]; movdqa XMM3, [ECX+16]; add EAX, 32; add ECX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else // MMX version is 2515% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM2, [ECX]; movq MM1, [EAX+8]; movq MM3, [ECX+8]; add EAX, 16; add ECX, 16; pmullw MM0, MM2; pmullw MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM2, [RCX]; movdqu XMM1, [RAX+16]; movdqu XMM3, [RCX+16]; add RAX, 32; add RCX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM2, [RCX]; movdqa XMM1, [RAX+16]; movdqa XMM3, [RCX+16]; add RAX, 32; add RCX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } } while (aptr < aend) *aptr++ = cast(T)(*bptr++ * *cptr++); return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMulSliceAssign_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] * b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * b[i])) { printf("[%d]: %d != %d * %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] *= value */ T[] _arrayExpSliceMulass_u(T[] a, T value) { return _arrayExpSliceMulass_s(a, value); } T[] _arrayExpSliceMulass_t(T[] a, T value) { return _arrayExpSliceMulass_s(a, value); } T[] _arrayExpSliceMulass_s(T[] a, T value) { //printf("_arrayExpSliceMulass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value); auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 aligned version is 2044% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= l << 16; if (((cast(uint) aptr) & 15) != 0) { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startsse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; add ESI, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startsse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; add ESI, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; } } } else // MMX version is 2056% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); uint l = cast(ushort) value; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movd MM2, l; pshufw MM2, MM2, 0; align 4; startmmx: movq MM0, [ESI]; movq MM1, [ESI+8]; add ESI, 16; pmullw MM0, MM2; pmullw MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); uint l = cast(ushort) value; l |= l << 16; if (((cast(uint) aptr) & 15) != 0) { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startsse2u: movdqu XMM0, [RSI]; movdqu XMM1, [RSI+16]; add RSI, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movd XMM2, l; pshufd XMM2, XMM2, 0; align 4; startsse2a: movdqa XMM0, [RSI]; movdqa XMM1, [RSI+16]; add RSI, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; } } } } while (aptr < aend) *aptr++ *= value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMulass_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } b[] = a[]; a[] *= 6; for (int i = 0; i < dim; i++) { if (a[i] != cast(T)(b[i] * 6)) { printf("[%d]: %d != %d * 6\n", i, a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] *= b[] */ T[] _arraySliceSliceMulass_u(T[] a, T[] b) { return _arraySliceSliceMulass_s(a, b); } T[] _arraySliceSliceMulass_t(T[] a, T[] b) { return _arraySliceSliceMulass_s(a, b); } T[] _arraySliceSliceMulass_s(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceSliceMulass_s()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 2519% faster if (sse2 && a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2u: movdqu XMM0, [ESI]; movdqu XMM2, [ECX]; movdqu XMM1, [ESI+16]; movdqu XMM3, [ECX+16]; add ESI, 32; add ECX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, ECX; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2a: movdqa XMM0, [ESI]; movdqa XMM2, [ECX]; movdqa XMM1, [ESI+16]; movdqa XMM3, [ECX+16]; add ESI, 32; add ECX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, ECX; } } } else // MMX version is 1712% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startmmx: movq MM0, [ESI]; movq MM2, [ECX]; movq MM1, [ESI+8]; movq MM3, [ECX+8]; add ESI, 16; add ECX, 16; pmullw MM0, MM2; pmullw MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 16) { auto n = aptr + (a.length & ~15); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2u: movdqu XMM0, [RSI]; movdqu XMM2, [RCX]; movdqu XMM1, [RSI+16]; movdqu XMM3, [RCX+16]; add RSI, 32; add RCX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RCX; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2a: movdqa XMM0, [RSI]; movdqa XMM2, [RCX]; movdqa XMM1, [RSI+16]; movdqa XMM3, [RCX+16]; add RSI, 32; add RCX, 32; pmullw XMM0, XMM2; pmullw XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RCX; } } } else // MMX version is 1712% faster if (mmx && a.length >= 8) { auto n = aptr + (a.length & ~7); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startmmx: movq MM0, [RSI]; movq MM2, [RCX]; movq MM1, [RSI+8]; movq MM3, [RCX+8]; add RSI, 16; add RCX, 16; pmullw MM0, MM2; pmullw MM1, MM3; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; mov bptr, RCX; } } } while (aptr < aend) *aptr++ *= *bptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMulass_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } b[] = a[]; a[] *= c[]; for (int i = 0; i < dim; i++) { if (a[i] != cast(T)(b[i] * c[i])) { printf("[%d]: %d != %d * %d\n", i, a[i], b[i], c[i]); assert(0); } } } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/minfo.d0000664000175000017500000004073612776214756020166 0ustar kaikai/** * Written in the D programming language. * Module initialization routines. * * Copyright: Copyright Digital Mars 2000 - 2013. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC src/rt/_minfo.d) */ module rt.minfo; import core.stdc.stdlib; // alloca import core.stdc.string; // memcpy import rt.sections; enum { MIctorstart = 0x1, // we've started constructing it MIctordone = 0x2, // finished construction MIstandalone = 0x4, // module ctor does not depend on other module // ctors being done first MItlsctor = 8, MItlsdtor = 0x10, MIctor = 0x20, MIdtor = 0x40, MIxgetMembers = 0x80, MIictor = 0x100, MIunitTest = 0x200, MIimportedModules = 0x400, MIlocalClasses = 0x800, MIname = 0x1000, } /***** * A ModuleGroup is an unordered collection of modules. * There is exactly one for: * 1. all statically linked in D modules, either directely or as shared libraries * 2. each call to rt_loadLibrary() */ struct ModuleGroup { this(immutable(ModuleInfo*)[] modules) { _modules = modules; } @property immutable(ModuleInfo*)[] modules() const { return _modules; } /****************************** * Allocate and fill in _ctors[] and _tlsctors[]. * Modules are inserted into the arrays in the order in which the constructors * need to be run. * Throws: * Exception if it fails. */ void sortCtors() { immutable len = _modules.length; if (!len) return; static struct StackRec { @property immutable(ModuleInfo)* mod() { return _mods[_idx]; } immutable(ModuleInfo*)[] _mods; size_t _idx; } auto stack = (cast(StackRec*).calloc(len, StackRec.sizeof))[0 .. len]; // TODO: reuse GCBits by moving it to rt.util.container or core.internal immutable nwords = (len + 8 * size_t.sizeof - 1) / (8 * size_t.sizeof); auto ctorstart = cast(size_t*).malloc(nwords * size_t.sizeof); auto ctordone = cast(size_t*).malloc(nwords * size_t.sizeof); if (!stack.ptr || ctorstart is null || ctordone is null) assert(0); scope (exit) { .free(stack.ptr); .free(ctorstart); .free(ctordone); } int findModule(in ModuleInfo* mi) { foreach (i, m; _modules) if (m is mi) return cast(int)i; return -1; } void sort(ref immutable(ModuleInfo)*[] ctors, uint mask) { import core.bitop; ctors = (cast(immutable(ModuleInfo)**).malloc(len * size_t.sizeof))[0 .. len]; if (!ctors.ptr) assert(0); // clean flags memset(ctorstart, 0, nwords * size_t.sizeof); memset(ctordone, 0, nwords * size_t.sizeof); size_t stackidx = 0; size_t cidx; immutable(ModuleInfo*)[] mods = _modules; size_t idx; while (true) { while (idx < mods.length) { auto m = mods[idx]; immutable bitnum = findModule(m); if (bitnum < 0 || bt(ctordone, bitnum)) { /* If the module can't be found among the ones to be * sorted it's an imported module from another DSO. * Those don't need to be considered during sorting as * the OS is responsible for the DSO load order and * module construction is done during DSO loading. */ ++idx; continue; } else if (bt(ctorstart, bitnum)) { /* Trace back to the begin of the cycle. */ bool ctorInCycle; size_t start = stackidx; while (start--) { auto sm = stack[start].mod; if (sm == m) break; immutable sbitnum = findModule(sm); assert(sbitnum >= 0); if (bt(ctorstart, sbitnum)) ctorInCycle = true; } assert(stack[start].mod == m); if (ctorInCycle) { /* This is an illegal cycle, no partial order can be established * because the import chain have contradicting ctor/dtor * constraints. */ string msg = "Aborting: Cycle detected between modules with "; if (mask & (MIctor | MIdtor)) msg ~= "shared "; msg ~= "ctors/dtors:\n"; foreach (e; stack[start .. stackidx]) { msg ~= e.mod.name; if (e.mod.flags & mask) msg ~= '*'; msg ~= " ->\n"; } msg ~= stack[start].mod.name; free(); throw new Exception(msg); } else { /* This is also a cycle, but the import chain does not constrain * the order of initialization, either because the imported * modules have no ctors or the ctors are standalone. */ ++idx; } } else { if (m.flags & mask) { if (m.flags & MIstandalone || !m.importedModules.length) { // trivial ctor => sort in ctors[cidx++] = m; bts(ctordone, bitnum); } else { // non-trivial ctor => defer bts(ctorstart, bitnum); } } else // no ctor => mark as visited { bts(ctordone, bitnum); } if (m.importedModules.length) { /* Internal runtime error, recursion exceeds number of modules. */ (stackidx < _modules.length) || assert(0); // recurse stack[stackidx++] = StackRec(mods, idx); idx = 0; mods = m.importedModules; } } } if (stackidx) { // pop old value from stack --stackidx; mods = stack[stackidx]._mods; idx = stack[stackidx]._idx; auto m = mods[idx++]; immutable bitnum = findModule(m); assert(bitnum >= 0); if (m.flags & mask && !bts(ctordone, bitnum)) ctors[cidx++] = m; } else // done break; } // store final number and shrink array ctors = (cast(immutable(ModuleInfo)**).realloc(ctors.ptr, cidx * size_t.sizeof))[0 .. cidx]; } /* Do two passes: ctor/dtor, tlsctor/tlsdtor */ sort(_ctors, MIctor | MIdtor); sort(_tlsctors, MItlsctor | MItlsdtor); } void runCtors() { // run independent ctors runModuleFuncs!(m => m.ictor)(_modules); // sorted module ctors runModuleFuncs!(m => m.ctor)(_ctors); } void runTlsCtors() { runModuleFuncs!(m => m.tlsctor)(_tlsctors); } void runTlsDtors() { runModuleFuncsRev!(m => m.tlsdtor)(_tlsctors); } void runDtors() { runModuleFuncsRev!(m => m.dtor)(_ctors); } void free() { if (_ctors.ptr) .free(_ctors.ptr); _ctors = null; if (_tlsctors.ptr) .free(_tlsctors.ptr); _tlsctors = null; // _modules = null; // let the owner free it } private: immutable(ModuleInfo*)[] _modules; immutable(ModuleInfo)*[] _ctors; immutable(ModuleInfo)*[] _tlsctors; } /******************************************** * Iterate over all module infos. */ int moduleinfos_apply(scope int delegate(immutable(ModuleInfo*)) dg) { foreach (ref sg; SectionGroup) { foreach (m; sg.modules) { // TODO: Should null ModuleInfo be allowed? if (m !is null) { if (auto res = dg(m)) return res; } } } return 0; } /******************************************** * Module constructor and destructor routines. */ extern (C) { void rt_moduleCtor() { foreach (ref sg; SectionGroup) { sg.moduleGroup.sortCtors(); sg.moduleGroup.runCtors(); } } void rt_moduleTlsCtor() { foreach (ref sg; SectionGroup) { sg.moduleGroup.runTlsCtors(); } } void rt_moduleTlsDtor() { foreach_reverse (ref sg; SectionGroup) { sg.moduleGroup.runTlsDtors(); } } void rt_moduleDtor() { foreach_reverse (ref sg; SectionGroup) { sg.moduleGroup.runDtors(); sg.moduleGroup.free(); } } version (Win32) { // Alternate names for backwards compatibility with older DLL code void _moduleCtor() { rt_moduleCtor(); } void _moduleDtor() { rt_moduleDtor(); } void _moduleTlsCtor() { rt_moduleTlsCtor(); } void _moduleTlsDtor() { rt_moduleTlsDtor(); } } } /******************************************** */ void runModuleFuncs(alias getfp)(const(immutable(ModuleInfo)*)[] modules) { foreach (m; modules) { if (auto fp = getfp(m)) (*fp)(); } } void runModuleFuncsRev(alias getfp)(const(immutable(ModuleInfo)*)[] modules) { foreach_reverse (m; modules) { if (auto fp = getfp(m)) (*fp)(); } } unittest { static void assertThrown(T : Throwable, E)(lazy E expr) { try expr; catch (T) return; assert(0); } static void stub() { } static struct UTModuleInfo { this(uint flags) { mi._flags = flags; } void setImports(immutable(ModuleInfo)*[] imports...) { import core.bitop; assert(flags & MIimportedModules); immutable nfuncs = popcnt(flags & (MItlsctor|MItlsdtor|MIctor|MIdtor|MIictor)); immutable size = nfuncs * (void function()).sizeof + size_t.sizeof + imports.length * (ModuleInfo*).sizeof; assert(size <= pad.sizeof); pad[nfuncs] = imports.length; .memcpy(&pad[nfuncs+1], imports.ptr, imports.length * imports[0].sizeof); } immutable ModuleInfo mi; size_t[8] pad; alias mi this; } static UTModuleInfo mockMI(uint flags) { auto mi = UTModuleInfo(flags | MIimportedModules); auto p = cast(void function()*)&mi.pad; if (flags & MItlsctor) *p++ = &stub; if (flags & MItlsdtor) *p++ = &stub; if (flags & MIctor) *p++ = &stub; if (flags & MIdtor) *p++ = &stub; if (flags & MIictor) *p++ = &stub; *cast(size_t*)p++ = 0; // number of imported modules assert(cast(void*)p <= &mi + 1); return mi; } static void checkExp( immutable(ModuleInfo*)[] modules, immutable(ModuleInfo*)[] dtors=null, immutable(ModuleInfo*)[] tlsdtors=null) { auto mgroup = ModuleGroup(modules); mgroup.sortCtors(); foreach (m; mgroup._modules) assert(!(m.flags & (MIctorstart | MIctordone))); assert(mgroup._ctors == dtors); assert(mgroup._tlsctors == tlsdtors); } // no ctors { auto m0 = mockMI(0); auto m1 = mockMI(0); auto m2 = mockMI(0); checkExp([&m0.mi, &m1.mi, &m2.mi]); } // independent ctors { auto m0 = mockMI(MIictor); auto m1 = mockMI(0); auto m2 = mockMI(MIictor); auto mgroup = ModuleGroup([&m0.mi, &m1.mi, &m2.mi]); checkExp([&m0.mi, &m1.mi, &m2.mi]); } // standalone ctor { auto m0 = mockMI(MIstandalone | MIctor); auto m1 = mockMI(0); auto m2 = mockMI(0); auto mgroup = ModuleGroup([&m0.mi, &m1.mi, &m2.mi]); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m0.mi]); } // imported standalone => no dependency { auto m0 = mockMI(MIstandalone | MIctor); auto m1 = mockMI(MIstandalone | MIctor); auto m2 = mockMI(0); m1.setImports(&m0.mi); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi]); } { auto m0 = mockMI(MIstandalone | MIctor); auto m1 = mockMI(MIstandalone | MIctor); auto m2 = mockMI(0); m0.setImports(&m1.mi); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi]); } // standalone may have cycle { auto m0 = mockMI(MIstandalone | MIctor); auto m1 = mockMI(MIstandalone | MIctor); auto m2 = mockMI(0); m0.setImports(&m1.mi); m1.setImports(&m0.mi); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi]); } // imported ctor => ordered ctors { auto m0 = mockMI(MIctor); auto m1 = mockMI(MIctor); auto m2 = mockMI(0); m1.setImports(&m0.mi); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi], []); } { auto m0 = mockMI(MIctor); auto m1 = mockMI(MIctor); auto m2 = mockMI(0); m0.setImports(&m1.mi); assert(m0.importedModules == [&m1.mi]); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], []); } // detects ctors cycles { auto m0 = mockMI(MIctor); auto m1 = mockMI(MIctor); auto m2 = mockMI(0); m0.setImports(&m1.mi); m1.setImports(&m0.mi); assertThrown!Throwable(checkExp([&m0.mi, &m1.mi, &m2.mi])); } // imported ctor/tlsctor => ordered ctors/tlsctors { auto m0 = mockMI(MIctor); auto m1 = mockMI(MIctor); auto m2 = mockMI(MItlsctor); m0.setImports(&m1.mi, &m2.mi); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], [&m2.mi]); } { auto m0 = mockMI(MIctor | MItlsctor); auto m1 = mockMI(MIctor); auto m2 = mockMI(MItlsctor); m0.setImports(&m1.mi, &m2.mi); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], [&m2.mi, &m0.mi]); } // no cycle between ctors/tlsctors { auto m0 = mockMI(MIctor); auto m1 = mockMI(MIctor); auto m2 = mockMI(MItlsctor); m0.setImports(&m1.mi, &m2.mi); m2.setImports(&m0.mi); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], [&m2.mi]); } // detects tlsctors cycle { auto m0 = mockMI(MItlsctor); auto m1 = mockMI(MIctor); auto m2 = mockMI(MItlsctor); m0.setImports(&m2.mi); m2.setImports(&m0.mi); assertThrown!Throwable(checkExp([&m0.mi, &m1.mi, &m2.mi])); } // closed ctors cycle { auto m0 = mockMI(MIctor); auto m1 = mockMI(MIstandalone | MIctor); auto m2 = mockMI(MIstandalone | MIctor); m0.setImports(&m1.mi); m1.setImports(&m2.mi); m2.setImports(&m0.mi); checkExp([&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m2.mi, &m0.mi]); } } version (CRuntime_Microsoft) { // Dummy so Win32 code can still call it extern(C) void _minit() { } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/tlsgc.d0000664000175000017500000000376412776214756020172 0ustar kaikai/** * * Copyright: Copyright Digital Mars 2011 - 2012. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak */ /* Copyright Digital Mars 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.tlsgc; import core.stdc.stdlib; static import rt.lifetime, rt.sections; /** * Per thread record to store thread associated data for garbage collection. */ struct Data { typeof(rt.sections.initTLSRanges()) tlsRanges; rt.lifetime.BlkInfo** blockInfoCache; } /** * Initialization hook, called FROM each thread. No assumptions about * module initialization state should be made. */ void* init() { auto data = cast(Data*).malloc(Data.sizeof); *data = Data.init; // do module specific initialization data.tlsRanges = rt.sections.initTLSRanges(); data.blockInfoCache = &rt.lifetime.__blkcache_storage; return data; } /** * Finalization hook, called FOR each thread. No assumptions about * module initialization state should be made. */ void destroy(void* data) { // do module specific finalization rt.sections.finiTLSRanges((cast(Data*)data).tlsRanges); .free(data); } alias void delegate(void* pstart, void* pend) nothrow ScanDg; /** * GC scan hook, called FOR each thread. Can be used to scan * additional thread local memory. */ void scan(void* data, scope ScanDg dg) nothrow { // do module specific marking rt.sections.scanTLSRanges((cast(Data*)data).tlsRanges, dg); } alias int delegate(void* addr) nothrow IsMarkedDg; /** * GC sweep hook, called FOR each thread. Can be used to free * additional thread local memory or associated data structures. Note * that only memory allocated from the GC can have marks. */ void processGCMarks(void* data, scope IsMarkedDg dg) nothrow { // do module specific sweeping rt.lifetime.processGCMarks(*(cast(Data*)data).blockInfoCache, dg); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/cover.d0000664000175000017500000003126712776214756020173 0ustar kaikai/** * Implementation of code coverage analyzer. * * Copyright: Copyright Digital Mars 1995 - 2015. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC src/rt/_cover.d) */ module rt.cover; private { version( Windows ) import core.sys.windows.windows; else version( Posix ) { import core.sys.posix.fcntl; import core.sys.posix.unistd; } import core.stdc.config : c_long; import core.stdc.stdio; import core.stdc.stdlib; import rt.util.utf; struct BitArray { size_t len; size_t* ptr; bool opIndex( size_t i ) in { assert( i < len ); } body { static if (size_t.sizeof == 8) return ((ptr[i >> 6] & (1L << (i & 63)))) != 0; else static if (size_t.sizeof == 4) return ((ptr[i >> 5] & (1 << (i & 31)))) != 0; else static assert(0); } } struct Cover // one of these for each module being analyzed { string filename; BitArray valid; // bit array of which source lines are executable code lines uint[] data; // array of line execution counts ubyte minPercent; // minimum percentage coverage required } __gshared { Cover[] gdata; string srcpath; string dstpath; bool merge; } } /** * Set path to where source files are located. * * Params: * pathname = The new path name. */ extern (C) void dmd_coverSourcePath( string pathname ) { srcpath = pathname; } /** * Set path to where listing files are to be written. * * Params: * pathname = The new path name. */ extern (C) void dmd_coverDestPath( string pathname ) { dstpath = pathname; } /** * Set merge mode. * * Params: * flag = true means new data is summed with existing data in the listing * file; false means a new listing file is always created. */ extern (C) void dmd_coverSetMerge( bool flag ) { merge = flag; } /** * The coverage callback. * * Params: * filename = The name of the coverage file. * valid = ??? * data = ??? */ extern (C) void _d_cover_register2(string filename, size_t[] valid, uint[] data, ubyte minPercent) { assert(minPercent <= 100); Cover c; c.filename = filename; c.valid.ptr = valid.ptr; c.valid.len = valid.length; c.data = data; c.minPercent = minPercent; gdata ~= c; } /* Kept for the moment for backwards compatibility. */ extern (C) void _d_cover_register( string filename, size_t[] valid, uint[] data ) { _d_cover_register2(filename, valid, data, 0); } private: // returns 0 if s isn't a number uint parseNum(const(char)[] s) { while (s.length && s[0] == ' ') s = s[1 .. $]; uint res; while (s.length && s[0] >= '0' && s[0] <= '9') { res = 10 * res + s[0] - '0'; s = s[1 .. $]; } return res; } T min(T)(T a, T b) { return a < b ? a : b; } T max(T)(T a, T b) { return b < a ? a : b; } shared static ~this() { if (!gdata.length) return; const NUMLINES = 16384 - 1; const NUMCHARS = 16384 * 16 - 1; auto buf = new char[NUMCHARS]; auto lines = new char[][NUMLINES]; foreach (c; gdata) { auto fname = appendFN(dstpath, addExt(baseName(c.filename), "lst")); auto flst = openOrCreateFile(fname); if (flst is null) continue; lockFile(fileno(flst)); // gets unlocked by fclose scope(exit) fclose(flst); if (merge && readFile(flst, buf)) { splitLines(buf, lines); foreach (i, line; lines[0 .. min($, c.data.length)]) c.data[i] += parseNum(line); } if (!readFile(appendFN(srcpath, c.filename), buf)) continue; splitLines(buf, lines); // Calculate the maximum number of digits in the line with the greatest // number of calls. uint maxCallCount; foreach (n; c.data[0 .. min($, lines.length)]) maxCallCount = max(maxCallCount, n); // Make sure that there are a minimum of seven columns in each file so // that unless there are a very large number of calls, the columns in // each files lineup. immutable maxDigits = max(7, digits(maxCallCount)); uint nno; uint nyes; // rewind for overwriting fseek(flst, 0, SEEK_SET); foreach (i, n; c.data[0 .. min($, lines.length)]) { auto line = lines[i]; line = expandTabs( line ); if (n == 0) { if (c.valid[i]) { ++nno; fprintf(flst, "%0*u|%.*s\n", maxDigits, 0, cast(int)line.length, line.ptr); } else { fprintf(flst, "%*s|%.*s\n", maxDigits, " ".ptr, cast(int)line.length, line.ptr); } } else { ++nyes; fprintf(flst, "%*u|%.*s\n", maxDigits, n, cast(int)line.length, line.ptr); } } if (nyes + nno) // no divide by 0 bugs { uint percent = ( nyes * 100 ) / ( nyes + nno ); fprintf(flst, "%.*s is %d%% covered\n", cast(int)c.filename.length, c.filename.ptr, percent); if (percent < c.minPercent) { fprintf(stderr, "Error: %.*s is %d%% covered, less than required %d%%\n", cast(int)c.filename.length, c.filename.ptr, percent, c.minPercent); exit(EXIT_FAILURE); } } else { fprintf(flst, "%.*s has no code\n", cast(int)c.filename.length, c.filename.ptr); } version (Windows) SetEndOfFile(handle(fileno(flst))); else ftruncate(fileno(flst), ftell(flst)); } } uint digits(uint number) { import core.stdc.math; return number ? cast(uint)floor(log10(number)) + 1 : 1; } unittest { static void testDigits(uint num, uint dgts) { assert(digits(num) == dgts); assert(digits(num - 1) == dgts - 1); assert(digits(num + 1) == dgts); } assert(digits(0) == 1); assert(digits(1) == 1); testDigits(10, 2); testDigits(1_000, 4); testDigits(1_000_000, 7); testDigits(1_000_000_000, 10); } string appendFN( string path, string name ) { if (!path.length) return name; version( Windows ) const char sep = '\\'; else version( Posix ) const char sep = '/'; auto dest = path; if( dest.length && dest[$ - 1] != sep ) dest ~= sep; dest ~= name; return dest; } string baseName( string name, string ext = null ) { string ret; foreach (c; name) { switch (c) { case ':': case '\\': case '/': ret ~= '-'; break; default: ret ~= c; } } return ext.length ? chomp(ret, ext) : ret; } string getExt( string name ) { auto i = name.length; while( i > 0 ) { if( name[i - 1] == '.' ) return name[i .. $]; --i; version( Windows ) { if( name[i] == ':' || name[i] == '\\' ) break; } else version( Posix ) { if( name[i] == '/' ) break; } } return null; } string addExt( string name, string ext ) { auto existing = getExt( name ); if( existing.length == 0 ) { if( name.length && name[$ - 1] == '.' ) name ~= ext; else name = name ~ "." ~ ext; } else { name = name[0 .. $ - existing.length] ~ ext; } return name; } string chomp( string str, string delim = null ) { if( delim is null ) { auto len = str.length; if( len ) { auto c = str[len - 1]; if( c == '\r' ) --len; else if( c == '\n' && str[--len - 1] == '\r' ) --len; } return str[0 .. len]; } else if( str.length >= delim.length ) { if( str[$ - delim.length .. $] == delim ) return str[0 .. $ - delim.length]; } return str; } // open/create file for read/write, pointer at beginning FILE* openOrCreateFile(string name) { import rt.util.utf : toUTF16z; version (Windows) immutable fd = _wopen(toUTF16z(name), _O_RDWR | _O_CREAT | _O_BINARY, _S_IREAD | _S_IWRITE); else immutable fd = open((name ~ '\0').ptr, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); version (CRuntime_Microsoft) alias fdopen = _fdopen; version (Posix) import core.sys.posix.stdio; return fdopen(fd, "r+b"); } version (Windows) HANDLE handle(int fd) { version(CRuntime_DigitalMars) return _fdToHandle(fd); else return cast(HANDLE)_get_osfhandle(fd); } void lockFile(int fd) { version (CRuntime_Bionic) { import core.sys.bionic.fcntl : LOCK_EX; import core.sys.bionic.unistd : flock; flock(fd, LOCK_EX); // exclusive lock } else version (Posix) lockf(fd, F_LOCK, 0); // exclusive lock else version (Windows) { OVERLAPPED off; // exclusively lock first byte LockFileEx(handle(fd), LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &off); } else static assert(0, "unimplemented"); } bool readFile(FILE* file, ref char[] buf) { if (fseek(file, 0, SEEK_END) != 0) assert(0, "fseek failed"); immutable len = ftell(file); if (len == -1) assert(0, "ftell failed"); else if (len == 0) return false; buf.length = len; fseek(file, 0, SEEK_SET); if (fread(buf.ptr, 1, buf.length, file) != buf.length) assert(0, "fread failed"); if (fgetc(file) != EOF) assert(0, "EOF not reached"); return true; } version(Windows) extern (C) nothrow @nogc FILE* _wfopen(in wchar* filename, in wchar* mode); version(Windows) extern (C) int chsize(int fd, c_long size); bool readFile(string name, ref char[] buf) { import rt.util.utf : toUTF16z; version (Windows) auto file = _wfopen(toUTF16z(name), "rb"w.ptr); else auto file = fopen((name ~ '\0').ptr, "rb".ptr); if (file is null) return false; scope(exit) fclose(file); return readFile(file, buf); } void splitLines( char[] buf, ref char[][] lines ) { size_t beg = 0, pos = 0; lines.length = 0; for( ; pos < buf.length; ++pos ) { char c = buf[pos]; switch( buf[pos] ) { case '\r': case '\n': lines ~= buf[beg .. pos]; beg = pos + 1; if( buf[pos] == '\r' && pos < buf.length - 1 && buf[pos + 1] == '\n' ) { ++pos; ++beg; } continue; default: continue; } } if( beg != pos ) { lines ~= buf[beg .. pos]; } } char[] expandTabs( char[] str, int tabsize = 8 ) { const dchar LS = '\u2028'; // UTF line separator const dchar PS = '\u2029'; // UTF paragraph separator bool changes = false; char[] result = str; int column; int nspaces; foreach( size_t i, dchar c; str ) { switch( c ) { case '\t': nspaces = tabsize - (column % tabsize); if( !changes ) { changes = true; result = null; result.length = str.length + nspaces - 1; result.length = i + nspaces; result[0 .. i] = str[0 .. i]; result[i .. i + nspaces] = ' '; } else { auto j = result.length; result.length = j + nspaces; result[j .. j + nspaces] = ' '; } column += nspaces; break; case '\r': case '\n': case PS: case LS: column = 0; goto L1; default: column++; L1: if (changes) { if (c <= 0x7F) result ~= cast(char)c; else { dchar[1] ca = c; foreach (char ch; ca[]) result ~= ch; } } break; } } return result; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/cmath2.d0000664000175000017500000001525712776214756020234 0ustar kaikai/** * Runtime support for complex arithmetic code generation (for Posix). * * Copyright: Copyright Digital Mars 2001 - 2011. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2001 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.cmath2; // Calls to these routines are emitted by the DMD backend, but LDC rather // directly emits equivalent LLVM IR. version (LDC) {} else { private import core.stdc.math; extern (C): /**************************** * Multiply two complex floating point numbers, x and y. * Input: * x.re ST3 * x.im ST2 * y.re ST1 * y.im ST0 * Output: * ST1 real part * ST0 imaginary part */ void _Cmul() { // p.re = x.re * y.re - x.im * y.im; // p.im = x.im * y.re + x.re * y.im; asm { naked ; fld ST(1) ; // x.re fmul ST,ST(4) ; // ST0 = x.re * y.re fld ST(1) ; // y.im fmul ST,ST(4) ; // ST0 = x.im * y.im fsubp ST(1),ST ; // ST0 = x.re * y.re - x.im * y.im fld ST(3) ; // x.im fmul ST,ST(3) ; // ST0 = x.im * y.re fld ST(5) ; // x.re fmul ST,ST(3) ; // ST0 = x.re * y.im faddp ST(1),ST ; // ST0 = x.im * y.re + x.re * y.im fxch ST(4),ST ; fstp ST(0) ; fxch ST(4),ST ; fstp ST(0) ; fstp ST(0) ; fstp ST(0) ; ret ; } /+ if (isnan(x) && isnan(y)) { // Recover infinities that computed as NaN+ iNaN ... int recalc = 0; if ( isinf( a) || isinf( b) ) { // z is infinite // "Box" the infinity and change NaNs in the other factor to 0 a = copysignl( isinf( a) ? 1.0 : 0.0, a); b = copysignl( isinf( b) ? 1.0 : 0.0, b); if (isnan( c)) c = copysignl( 0.0, c); if (isnan( d)) d = copysignl( 0.0, d); recalc = 1; } if (isinf(c) || isinf(d)) { // w is infinite // "Box" the infinity and change NaNs in the other factor to 0 c = copysignl( isinf( c) ? 1.0 : 0.0, c); d = copysignl( isinf( d) ? 1.0 : 0.0, d); if (isnan( a)) a = copysignl( 0.0, a); if (isnan( b)) b = copysignl( 0.0, b); recalc = 1; } if (!recalc && (isinf(ac) || isinf(bd) || isinf(ad) || isinf(bc))) { // Recover infinities from overflow by changing NaNs to 0 ... if (isnan( a)) a = copysignl( 0.0, a); if (isnan( b)) b = copysignl( 0.0, b); if (isnan( c)) c = copysignl( 0.0, c); if (isnan( d)) d = copysignl( 0.0, d); recalc = 1; } if (recalc) { x = INFINITY * (a * c - b * d); y = INFINITY * (a * d + b * c); } } +/ } /**************************** * Divide two complex floating point numbers, x / y. * Input: * x.re ST3 * x.im ST2 * y.re ST1 * y.im ST0 * Output: * ST1 real part * ST0 imaginary part */ void _Cdiv() { real x_re, x_im; real y_re, y_im; real q_re, q_im; real r; real den; asm { fstp y_im ; fstp y_re ; fstp x_im ; fstp x_re ; } if (fabs(y_re) < fabs(y_im)) { r = y_re / y_im; den = y_im + r * y_re; q_re = (x_re * r + x_im) / den; q_im = (x_im * r - x_re) / den; } else { r = y_im / y_re; den = y_re + r * y_im; q_re = (x_re + r * x_im) / den; q_im = (x_im - r * x_re) / den; } //printf("q.re = %g, q.im = %g\n", (double)q_re, (double)q_im); /+ if (isnan(q_re) && isnan(q_im)) { real denom = y_re * y_re + y_im * y_im; // non-zero / zero if (denom == 0.0 && (!isnan(x_re) || !isnan(x_im))) { q_re = copysignl(INFINITY, y_re) * x_re; q_im = copysignl(INFINITY, y_re) * x_im; } // infinite / finite else if ((isinf(x_re) || isinf(x_im)) && isfinite(y_re) && isfinite(y_im)) { x_re = copysignl(isinf(x_re) ? 1.0 : 0.0, x_re); x_im = copysignl(isinf(x_im) ? 1.0 : 0.0, x_im); q_re = INFINITY * (x_re * y_re + x_im * y_im); q_im = INFINITY * (x_im * y_re - x_re * y_im); } // finite / infinite else if (isinf(logbw) && isfinite(x_re) && isfinite(x_im)) { y_re = copysignl(isinf(y_re) ? 1.0 : 0.0, y_re); y_im = copysignl(isinf(y_im) ? 1.0 : 0.0, y_im); q_re = 0.0 * (x_re * y_re + x_im * y_im); q_im = 0.0 * (x_im * y_re - x_re * y_im); } } return q_re + q_im * 1.0i; +/ asm { fld q_re; fld q_im; } } /**************************** * Compare two complex floating point numbers, x and y. * Input: * x.re ST3 * x.im ST2 * y.re ST1 * y.im ST0 * Output: * 8087 stack is cleared * flags set */ void _Ccmp() { version (D_InlineAsm_X86) asm { naked ; fucomp ST(2) ; // compare x.im and y.im fstsw AX ; sahf ; jne L1 ; jp L1 ; // jmp if NAN fucomp ST(2) ; // compare x.re and y.re fstsw AX ; sahf ; fstp ST(0) ; // pop fstp ST(0) ; // pop ret ; L1: fstp ST(0) ; // pop fstp ST(0) ; // pop fstp ST(0) ; // pop ret ; } else version (D_InlineAsm_X86_64) asm { naked ; fucomip ST(2) ; // compare x.im and y.im jne L1 ; jp L1 ; // jmp if NAN fucomip ST(2) ; // compare x.re and y.re fstp ST(0) ; // pop fstp ST(0) ; // pop ret ; L1: fstp ST(0) ; // pop fstp ST(0) ; // pop fstp ST(0) ; // pop ret ; } else static assert(0); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/unwind.d0000664000175000017500000000741712776214756020361 0ustar kaikai/** * Written in the D programming language. * Equivalent to unwind.h * * See_Also: * Itanium C++ ABI: Exception Handling ($Revision: 1.22 $) * Source: $(DRUNTIMESRC src/rt/_unwind.d) */ module rt.unwind; import core.stdc.stdint; extern (C): alias uintptr_t _Unwind_Word; alias intptr_t _Unwind_Sword; alias uintptr_t _Unwind_Ptr; alias uintptr_t _Unwind_Internal_Ptr; alias ulong _Unwind_Exception_Class; alias uintptr_t _uleb128_t; alias intptr_t _sleb128_t; alias int _Unwind_Reason_Code; enum { _URC_NO_REASON = 0, _URC_FOREIGN_EXCEPTION_CAUGHT = 1, _URC_FATAL_PHASE2_ERROR = 2, _URC_FATAL_PHASE1_ERROR = 3, _URC_NORMAL_STOP = 4, _URC_END_OF_STACK = 5, _URC_HANDLER_FOUND = 6, _URC_INSTALL_CONTEXT = 7, _URC_CONTINUE_UNWIND = 8 } alias int _Unwind_Action; enum _Unwind_Action _UA_SEARCH_PHASE = 1; enum _Unwind_Action _UA_CLEANUP_PHASE = 2; enum _Unwind_Action _UA_HANDLER_FRAME = 4; enum _Unwind_Action _UA_FORCE_UNWIND = 8; enum _Unwind_Action _UA_END_OF_STACK = 16; alias _Unwind_Exception_Cleanup_Fn = void function( _Unwind_Reason_Code reason, _Unwind_Exception *exc); struct _Unwind_Exception { align(8) _Unwind_Exception_Class exception_class; _Unwind_Exception_Cleanup_Fn exception_cleanup; _Unwind_Word private_1; _Unwind_Word private_2; } struct _Unwind_Context; _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *exception_object); alias _Unwind_Stop_Fn = _Unwind_Reason_Code function( int _version, _Unwind_Action actions, _Unwind_Exception_Class exceptionClass, _Unwind_Exception* exceptionObject, _Unwind_Context* context, void* stop_parameter); _Unwind_Reason_Code _Unwind_ForcedUnwind( _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter); alias _Unwind_Trace_Fn = _Unwind_Reason_Code function(_Unwind_Context*, void*); void _Unwind_DeleteException(_Unwind_Exception* exception_object); void _Unwind_Resume(_Unwind_Exception* exception_object); _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(_Unwind_Exception* exception_object); _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*); _Unwind_Word _Unwind_GetGR(_Unwind_Context* context, int index); void _Unwind_SetGR(_Unwind_Context* context, int index, _Unwind_Word new_value); _Unwind_Ptr _Unwind_GetIP(_Unwind_Context* context); _Unwind_Ptr _Unwind_GetIPInfo(_Unwind_Context* context, int*); void _Unwind_SetIP(_Unwind_Context* context, _Unwind_Ptr new_value); _Unwind_Word _Unwind_GetCFA(_Unwind_Context*); _Unwind_Word _Unwind_GetBSP(_Unwind_Context*); void* _Unwind_GetLanguageSpecificData(_Unwind_Context*); _Unwind_Ptr _Unwind_GetRegionStart(_Unwind_Context* context); void* _Unwind_FindEnclosingFunction(void* pc); version (X68_64) { _Unwind_Ptr _Unwind_GetDataRelBase(_Unwind_Context* context) { return _Unwind_GetGR(context, 1); } _Unwind_Ptr _Unwind_GetTextRelBase(_Unwind_Context* context) { assert(0); } } else { _Unwind_Ptr _Unwind_GetDataRelBase(_Unwind_Context* context); _Unwind_Ptr _Unwind_GetTextRelBase(_Unwind_Context* context); } alias _Unwind_Personality_Fn = _Unwind_Reason_Code function( int _version, _Unwind_Action actions, _Unwind_Exception_Class exceptionClass, _Unwind_Exception* exceptionObject, _Unwind_Context* context); struct SjLj_Function_Context; void _Unwind_SjLj_Register(SjLj_Function_Context *); void _Unwind_SjLj_Unregister(SjLj_Function_Context *); _Unwind_Reason_Code _Unwind_SjLj_RaiseException(_Unwind_Exception*); _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(_Unwind_Exception , _Unwind_Stop_Fn, void*); void _Unwind_SjLj_Resume(_Unwind_Exception*); _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception*); ldc-1.1.0-beta3-src/runtime/druntime/src/rt/sections_solaris.d0000664000175000017500000000462712776214756022440 0ustar kaikai/** * Written in the D programming language. * This module provides Solaris-specific support for sections. * * Copyright: Copyright Martin Nowak 2012-2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak * Source: $(DRUNTIMESRC src/rt/_sections_solaris.d) */ module rt.sections_solaris; version (LDC) {} else version (Solaris): // debug = PRINTF; debug(PRINTF) import core.stdc.stdio; import core.stdc.stdlib : malloc, free; import rt.deh, rt.minfo; struct SectionGroup { static int opApply(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } static int opApplyReverse(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } @property immutable(ModuleInfo*)[] modules() const { return _moduleGroup.modules; } @property ref inout(ModuleGroup) moduleGroup() inout { return _moduleGroup; } @property immutable(FuncTable)[] ehTables() const { auto pbeg = cast(immutable(FuncTable)*)&__start_deh; auto pend = cast(immutable(FuncTable)*)&__stop_deh; return pbeg[0 .. pend - pbeg]; } @property inout(void[])[] gcRanges() inout { return _gcRanges[]; } private: ModuleGroup _moduleGroup; void[][1] _gcRanges; } void initSections() { auto mbeg = cast(immutable ModuleInfo**)&__start_minfo; auto mend = cast(immutable ModuleInfo**)&__stop_minfo; _sections.moduleGroup = ModuleGroup(mbeg[0 .. mend - mbeg]); auto pbeg = cast(void*)&__dso_handle; auto pend = cast(void*)&_end; _sections._gcRanges[0] = pbeg[0 .. pend - pbeg]; } void finiSections() { } void[] initTLSRanges() { auto pbeg = cast(void*)&_tlsstart; auto pend = cast(void*)&_tlsend; return pbeg[0 .. pend - pbeg]; } void finiTLSRanges(void[] rng) { } void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow { dg(rng.ptr, rng.ptr + rng.length); } private: __gshared SectionGroup _sections; extern(C) { /* Symbols created by the compiler/linker and inserted into the * object file that 'bracket' sections. */ extern __gshared { void* __start_deh; void* __stop_deh; void* __start_minfo; void* __stop_minfo; int __dso_handle; int _end; } extern { void* _tlsstart; void* _tlsend; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/deh_win32.d0000664000175000017500000010456712776214756020643 0ustar kaikai/** * Implementation of exception handling support routines for Win32. * * Copyright: Copyright Digital Mars 1999 - 2013. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright * Source: $(DRUNTIMESRC src/rt/deh_win32.d) */ module rt.deh_win32; version (Win32): import core.sys.windows.windows; import rt.monitor_; //import core.stdc.stdio; version (D_InlineAsm_X86) { version = AsmX86; } else version (D_InlineAsm_X86_64) { version = AsmX86; } enum EXCEPTION_DISPOSITION { ExceptionContinueExecution, ExceptionContinueSearch, ExceptionNestedException, ExceptionCollidedUnwind } /+ enum { EXCEPTION_EXECUTE_HANDLER = 1, EXCEPTION_CONTINUE_SEARCH = 0, EXCEPTION_CONTINUE_EXECUTION = -1 } +/ extern(Windows) { void RaiseException(DWORD, DWORD, DWORD, void *); } // used in EXCEPTION_RECORD enum : DWORD { STATUS_WAIT_0 = 0, STATUS_ABANDONED_WAIT_0 = 0x00000080, STATUS_USER_APC = 0x000000C0, STATUS_TIMEOUT = 0x00000102, STATUS_PENDING = 0x00000103, STATUS_SEGMENT_NOTIFICATION = 0x40000005, STATUS_GUARD_PAGE_VIOLATION = 0x80000001, STATUS_DATATYPE_MISALIGNMENT = 0x80000002, STATUS_BREAKPOINT = 0x80000003, STATUS_SINGLE_STEP = 0x80000004, STATUS_ACCESS_VIOLATION = 0xC0000005, STATUS_IN_PAGE_ERROR = 0xC0000006, STATUS_INVALID_HANDLE = 0xC0000008, STATUS_NO_MEMORY = 0xC0000017, STATUS_ILLEGAL_INSTRUCTION = 0xC000001D, STATUS_NONCONTINUABLE_EXCEPTION = 0xC0000025, STATUS_INVALID_DISPOSITION = 0xC0000026, STATUS_ARRAY_BOUNDS_EXCEEDED = 0xC000008C, STATUS_FLOAT_DENORMAL_OPERAND = 0xC000008D, STATUS_FLOAT_DIVIDE_BY_ZERO = 0xC000008E, STATUS_FLOAT_INEXACT_RESULT = 0xC000008F, STATUS_FLOAT_INVALID_OPERATION = 0xC0000090, STATUS_FLOAT_OVERFLOW = 0xC0000091, STATUS_FLOAT_STACK_CHECK = 0xC0000092, STATUS_FLOAT_UNDERFLOW = 0xC0000093, STATUS_INTEGER_DIVIDE_BY_ZERO = 0xC0000094, STATUS_INTEGER_OVERFLOW = 0xC0000095, STATUS_PRIVILEGED_INSTRUCTION = 0xC0000096, STATUS_STACK_OVERFLOW = 0xC00000FD, STATUS_CONTROL_C_EXIT = 0xC000013A, STATUS_DLL_INIT_FAILED = 0xC0000142, STATUS_DLL_INIT_FAILED_LOGOFF = 0xC000026B, CONTROL_C_EXIT = STATUS_CONTROL_C_EXIT, EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION, EXCEPTION_DATATYPE_MISALIGNMENT = STATUS_DATATYPE_MISALIGNMENT, EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT, EXCEPTION_SINGLE_STEP = STATUS_SINGLE_STEP, EXCEPTION_ARRAY_BOUNDS_EXCEEDED = STATUS_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO = STATUS_FLOAT_DIVIDE_BY_ZERO, EXCEPTION_FLT_INEXACT_RESULT = STATUS_FLOAT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION = STATUS_FLOAT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW = STATUS_FLOAT_OVERFLOW, EXCEPTION_FLT_STACK_CHECK = STATUS_FLOAT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW = STATUS_FLOAT_UNDERFLOW, EXCEPTION_INT_DIVIDE_BY_ZERO = STATUS_INTEGER_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW = STATUS_INTEGER_OVERFLOW, EXCEPTION_PRIV_INSTRUCTION = STATUS_PRIVILEGED_INSTRUCTION, EXCEPTION_IN_PAGE_ERROR = STATUS_IN_PAGE_ERROR, EXCEPTION_ILLEGAL_INSTRUCTION = STATUS_ILLEGAL_INSTRUCTION, EXCEPTION_NONCONTINUABLE_EXCEPTION = STATUS_NONCONTINUABLE_EXCEPTION, EXCEPTION_STACK_OVERFLOW = STATUS_STACK_OVERFLOW, EXCEPTION_INVALID_DISPOSITION = STATUS_INVALID_DISPOSITION, EXCEPTION_GUARD_PAGE = STATUS_GUARD_PAGE_VIOLATION, EXCEPTION_INVALID_HANDLE = STATUS_INVALID_HANDLE } enum MAXIMUM_SUPPORTED_EXTENSION = 512; enum size_t EXCEPTION_MAXIMUM_PARAMETERS = 15; enum DWORD EXCEPTION_NONCONTINUABLE = 1; struct FLOATING_SAVE_AREA { DWORD ControlWord; DWORD StatusWord; DWORD TagWord; DWORD ErrorOffset; DWORD ErrorSelector; DWORD DataOffset; DWORD DataSelector; BYTE[80] RegisterArea; DWORD Cr0NpxState; } struct CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE[MAXIMUM_SUPPORTED_EXTENSION] ExtendedRegisters; } alias CONTEXT* PCONTEXT, LPCONTEXT; struct EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; EXCEPTION_RECORD* ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; DWORD[EXCEPTION_MAXIMUM_PARAMETERS] ExceptionInformation; } alias EXCEPTION_RECORD* PEXCEPTION_RECORD, LPEXCEPTION_RECORD; struct EXCEPTION_POINTERS { PEXCEPTION_RECORD ExceptionRecord; PCONTEXT ContextRecord; } alias EXCEPTION_POINTERS* PEXCEPTION_POINTERS, LPEXCEPTION_POINTERS; enum EXCEPTION_UNWIND = 6; // Flag to indicate if the system is unwinding /+ Values used by Microsoft for Itanium and Win64 are: #define EXCEPTION_NONCONTINUABLE 0x0001 #define EXCEPTION_UNWINDING 0x0002 #define EXCEPTION_EXIT_UNWIND 0x0004 #define EXCEPTION_STACK_INVALID 0x0008 #define EXCEPTION_NESTED_CALL 0x0010 #define EXCEPTION_TARGET_UNWIND 0x0020 #define EXCEPTION_COLLIDED_UNWIND 0x0040 #define EXCEPTION_UNWIND 0x0066 @@@ BUG @@@ We don't have any guarantee that this bit will remain available. Unfortunately, it seems impossible to implement exception handling at all, without relying on undocumented behaviour in several places. +/ enum EXCEPTION_COLLATERAL = 0x100; // Flag used to implement TDPL exception chaining /* Windows Kernel function to initiate a system unwind. Documentation for this function is severely lacking. http://www.nynaeve.net/?p=99 states that the MSDN documentation is incorrect, and gives a corrected form, but it's for x86_64 only. http://www.microsoft.com/msj/0197/exception/exception.aspx says that it was undocumented in 1997. The pExceptRec is what will be passed to the language specific handler. According to MSJ, the targetIp value is unused on Win32. The 'valueForEAX' parameter should always be 0. */ extern(Windows) void RtlUnwind(void *targetFrame, void *targetIp, EXCEPTION_RECORD *pExceptRec, void *valueForEAX); extern(C) { extern __gshared DWORD _except_list; // This is just FS:[0] } extern(C) { int _d_isbaseof(ClassInfo b, ClassInfo c); Throwable.TraceInfo _d_traceContext(void* ptr = null); void _d_createTrace(Object o, void* context); } /+ Implementation of Structured Exception Handling in DMD-Windows Every function which uses exception handling (a 'frame') has a thunk created for it. This thunk is the 'language-specific handler'. The thunks are created in the DMD backend, in nteh_framehandler() in nteh.c. These thunks are of the form: MOV EAX, &scope_table JMP __d_framehandler FS:[0] contains a singly linked list of all active handlers (they'll all be thunks). The list is created on the stack. At the end of this list is _except_handler3, a function in the DMC library. It may be unnecessary. I think it is included for compatibility with MSVC exceptions? The function below is useful for debugging. extern(C) EXCEPTION_DISPOSITION _except_handler3(EXCEPTION_RECORD *eRecord, DEstablisherFrame * frame,CONTEXT *context,void *dispatchercontext); // Walk the exception handler chain void printHandlerChain() { DEstablisherFrame *head; asm { mov EAX, FS:[0]; mov head, EAX; } while (head && head != cast(DEstablisherFrame *)~0) { printf("%p %p ", head, head.handler); if (head.handler == &unwindCollisionExceptionHandler) printf("UnwindCollisionHandler\n"); else if (head.handler == &_except_handler3) printf("excepthandler3\n"); else { ubyte *hnd = cast(ubyte *)head.handler; if (hnd[0] == 0xB8 && hnd[5]==0xE9) // mov EAX, xxx; jmp yyy; { int adr = *cast(int *)(hnd+6); printf("thunk: frametable=%x adr=%x ", *cast(int *)(hnd+1), hnd + adr+10); if (cast(void *)(hnd + adr + 10) == &_d_framehandler) printf("dframehandler\n"); else printf("\n"); } else printf("(unknown)\n"); } head = head.prev; } } Documentation of Windows SEH is hard to find. Here is a brief explanation: When an exception is raised, the OS calls each handler in the FS:[0] list in turn, looking for a catch block. It continues moving down the list, as long as each handler indicates that it has not caught the exception. When a handler is ready to catch the exception, it calls the OS function RtlUnwind. This calls each function in the FS:[0] list again, this time indicating that it is a 'unwind' call. All of the intervening finally blocks are run at this time. The complicated case is a CollidedException, which happens when a finally block throws an exception. The new exception needs to either replace the old one, or be chained to the old one. The other complexity comes from the fact that a single function may have multiple try/catch/finally blocks. Hence, there's a 'handler table' created for each function which uses exceptions. +/ extern(C) { alias EXCEPTION_DISPOSITION function ( EXCEPTION_RECORD *exceptionRecord, DEstablisherFrame *frame, CONTEXT *context, void *dispatcherContext) LanguageSpecificHandler; } // The layout of DEstablisherFrame is the same for C++ struct DEstablisherFrame { DEstablisherFrame *prev; // pointer to previous exception list LanguageSpecificHandler handler; // pointer to routine for exception handler DWORD table_index; // current index into handler_info[] DWORD ebp; // this is EBP of routine }; struct DHandlerInfo { int prev_index; // previous table index uint cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch) void *finally_code; // pointer to finally code to execute // (!=0 if try-finally) }; // Address of DHandlerTable is passed in EAX to _d_framehandler() struct DHandlerTable { void *fptr; // pointer to start of function uint espoffset; // offset of ESP from EBP uint retoffset; // offset from start of function to return code DHandlerInfo[1] handler_info; }; struct DCatchBlock { ClassInfo type; // catch type uint bpoffset; // EBP offset of catch var void *code; // catch handler code }; // One of these is created for each try-catch struct DCatchInfo { uint ncatches; // number of catch blocks DCatchBlock[1] catch_block; // data for each catch block }; // Macro to make our own exception code template MAKE_EXCEPTION_CODE(int severity, int facility, int exception) { enum int MAKE_EXCEPTION_CODE = (((severity) << 30) | (1 << 29) | (0 << 28) | ((facility) << 16) | (exception)); } enum int STATUS_DIGITAL_MARS_D_EXCEPTION = MAKE_EXCEPTION_CODE!(3,'D',1); /* Head of a linked list of all exceptions which are in flight. * This is used to implement exception chaining as described in TDPL. * Central to making chaining work correctly is that chaining must only occur * when a collision occurs (not merely when two exceptions are in flight, * because one may be caught before it has any effect on the other). * * The 'ExceptionRecord' member of the EXCEPTION_RECORD struct is used to * store a link to the earlier member on the list. * All exceptions which have found their catch handler are linked into this * list. The exceptions which collided are marked by setting a bit in the * ExceptionFlags. I've called this bit EXCEPTION_COLLATERAL. It has never * been used by Microsoft. * * Every member of the list will either eventually collide with the next earlier * exception, having its EXCEPTION_COLLATERAL bit set, or else will be caught. * If it is caught, a D exception object is created, containing all of the * collateral exceptions. * * There are many subtleties in this design: * (1) The exception records are all on the stack, so it's not possible to * modify them very much. In particular, we have very little choice about how * unwinding works, so we have to leave all the exception records essentially * intact. * (2) The length of an exception record is not constant. System exceptions * are shorter than D exceptions, for example. * (3) System exceptions don't have any space for a pointer to a D object. * So we cannot store the collision information in the exception record. * (4) it's important that this list is fiber-local. */ EXCEPTION_RECORD * inflightExceptionList = null; /*********************************** * Switch out inflightExceptionList on fiber context switches. */ extern(C) void* _d_eh_swapContext(void* newContext) nothrow { auto old = inflightExceptionList; inflightExceptionList = cast(EXCEPTION_RECORD*)newContext; return old; } /*********************************** * Find the first non-collateral exception in the list. If the last * entry in the list has the EXCEPTION_COLLATERAL bit set, it means * that this fragment will collide with the top exception in the * inflightException list. */ EXCEPTION_RECORD *skipCollateralExceptions(EXCEPTION_RECORD *n) { while ( n.ExceptionRecord && n.ExceptionFlags & EXCEPTION_COLLATERAL ) { n = n.ExceptionRecord; } return n; } /*********************************** * The frame handler, this is called for each frame that has been registered * in the OS except_list. * Input: * EAX the handler table for the frame */ extern(C) EXCEPTION_DISPOSITION _d_framehandler( EXCEPTION_RECORD *exceptionRecord, DEstablisherFrame *frame, CONTEXT *context, void *dispatcherContext) { DHandlerTable *handlerTable; asm { mov handlerTable,EAX; } if (exceptionRecord.ExceptionFlags & EXCEPTION_UNWIND) { // Call all the finally blocks in this frame _d_local_unwind(handlerTable, frame, -1, &unwindCollisionExceptionHandler); } else { // Jump to catch block if matching one is found int ndx,prev_ndx; DHandlerInfo *phi; DCatchInfo *pci; DCatchBlock *pcb; uint ncatches; // number of catches in the current handler /* The Master or Boss exception controls which catch() clause will * catch the exception. If all collateral exceptions are derived from * Exception, the boss is the first exception thrown. Otherwise, * the first Error is the boss. * But, if an Error (or non-Exception Throwable) is thrown as a collateral * exception, it will take priority over an Exception. */ EXCEPTION_RECORD * master = null; // The Master exception. ClassInfo masterClassInfo; // Class info of the Master exception. masterClassInfo = null; // only compute it if we need it // walk through handler table, checking each handler // with an index smaller than the current table_index for (ndx = frame.table_index; ndx != -1; ndx = prev_ndx) { phi = &handlerTable.handler_info.ptr[ndx]; prev_ndx = phi.prev_index; if (phi.cioffset) { // this is a catch handler (no finally) pci = cast(DCatchInfo *)(cast(ubyte *)handlerTable + phi.cioffset); ncatches = pci.ncatches; foreach (i; 0..ncatches) { pcb = &pci.catch_block.ptr[i]; int match = 0; EXCEPTION_RECORD * er = exceptionRecord; // We need to check all the collateral exceptions. for(;;) { if (er.ExceptionCode == STATUS_DIGITAL_MARS_D_EXCEPTION) { // printf("ei[0] = %p\n", er.ExceptionInformation[0]); ClassInfo ci = (**(cast(ClassInfo **)(er.ExceptionInformation[0]))); // If we've reached the oldest exception without // finding an Error, this one must be the master. if (!master && !(er.ExceptionFlags & EXCEPTION_COLLATERAL)) { master = er; masterClassInfo = ci; break; } if (_d_isbaseof(ci, typeid(Error))) { // It's derived from Error. This _may_ be the master. master = er; masterClassInfo = ci; } // Else it's a collateral Exception } else { // Non-D exception. It will become an Error. masterClassInfo = typeid(Error); master = er; } // End the loop if this was the original exception if (! (er.ExceptionFlags & EXCEPTION_COLLATERAL)) break; // Now get the next collateral exception. if (er.ExceptionRecord) er = er.ExceptionRecord; else // It is collateral for an existing exception chain // for which we've already found the catch{}. It is // possible that the new collateral makes the old catch // invalid. er = inflightExceptionList; } if (_d_isbaseof(masterClassInfo, pcb.type)) { // Matched the catch type, so we've found the catch // handler for this exception. // BEWARE: We don't yet know if the catch handler will // actually be executed. If there's an unwind collision, // this call may be abandoned: the calls to // _global_unwind and _local_unwind may never return, // and the contents of the local variables will be lost. // We need to add this exception to the list of in-flight // exceptions, in case something collides with it. EXCEPTION_RECORD * originalException = skipCollateralExceptions(exceptionRecord); if (originalException.ExceptionRecord is null && !(exceptionRecord is inflightExceptionList)) { originalException.ExceptionRecord = inflightExceptionList; } inflightExceptionList = exceptionRecord; // Have system call all finally blocks in intervening frames _d_global_unwind(frame, exceptionRecord); // Call all the finally blocks skipped in this frame _d_local_unwind(handlerTable, frame, ndx, &searchCollisionExceptionHandler); frame.table_index = prev_ndx; // we are out of this handler // Now create the D exception from the SEH exception record chain. EXCEPTION_RECORD * z = exceptionRecord; Throwable prev = null; Error masterError = null; Throwable pti; for(;;) { Throwable w = _d_translate_se_to_d_exception(z, context); if (z == master && (z.ExceptionFlags & EXCEPTION_COLLATERAL)) { // if it is a short-circuit master, save it masterError = cast(Error)w; } Throwable a = w; while (a.next) a = a.next; a.next = prev; prev = w; if (!(z.ExceptionFlags & EXCEPTION_COLLATERAL)) break; z = z.ExceptionRecord; } // Reached the end. Now add the Master, if any. if (masterError) { masterError.bypassedException = prev; pti = masterError; } else { pti = prev; } // Pop the exception from the list of in-flight exceptions inflightExceptionList = z.ExceptionRecord; int regebp; // Initialize catch variable regebp = cast(int)&frame.ebp; // EBP for this frame *cast(Object *)(regebp + (pcb.bpoffset)) = pti; // Jump to catch block. Does not return. { uint catch_esp; alias void function() fp_t; // generic function pointer fp_t catch_addr = cast(fp_t)(pcb.code); catch_esp = regebp - handlerTable.espoffset - fp_t.sizeof; asm { mov EAX,catch_esp; mov ECX,catch_addr; mov [EAX],ECX; mov EBP,regebp; mov ESP,EAX; // reset stack ret; // jump to catch block } } } } } } } return EXCEPTION_DISPOSITION.ExceptionContinueSearch; } /*********************************** * Exception filter for use in __try..__except block * surrounding call to Dmain() */ int _d_exception_filter(EXCEPTION_POINTERS *eptrs, int retval, Object *exceptionObject) { *exceptionObject = _d_translate_se_to_d_exception(eptrs.ExceptionRecord, eptrs.ContextRecord); return retval; } /*********************************** * Throw a D object. */ private void throwImpl(Object h) { // @@@ TODO @@@ Signature should change: h will always be a Throwable. //printf("_d_throw(h = %p, &h = %p)\n", h, &h); //printf("\tvptr = %p\n", *(void **)h); _d_createTrace(h, null); RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION, EXCEPTION_NONCONTINUABLE, 1, cast(void *)&h); } extern(C) void _d_throwc(Object h) { // set up a stack frame for trace unwinding version (AsmX86) { asm { naked; enter 0, 0; } version (D_InlineAsm_X86) asm { mov EAX, [EBP+8]; } asm { call throwImpl; leave; ret; } } else { throwImpl(h); } } /*********************************** * Converts a Windows Structured Exception code to a D Throwable Object. */ Throwable _d_translate_se_to_d_exception(EXCEPTION_RECORD *exceptionRecord, CONTEXT* context) { Throwable pti; // BUG: what if _d_newclass() throws an out of memory exception? switch (exceptionRecord.ExceptionCode) { case STATUS_DIGITAL_MARS_D_EXCEPTION: // Generated D exception pti = cast(Throwable)cast(void *)(exceptionRecord.ExceptionInformation[0]); break; case STATUS_INTEGER_DIVIDE_BY_ZERO: pti = new Error("Integer Divide by Zero"); break; case STATUS_INTEGER_OVERFLOW: // eg, int.min % -1 pti = new Error("Integer Overflow"); break; case STATUS_FLOAT_DIVIDE_BY_ZERO: pti = new Error("Float Divide by Zero"); break; case STATUS_ACCESS_VIOLATION: pti = new Error("Access Violation"); break; case STATUS_STACK_OVERFLOW: pti = new Error("Stack Overflow"); break; case STATUS_DATATYPE_MISALIGNMENT: pti = new Error("Datatype Misalignment"); break; case STATUS_ARRAY_BOUNDS_EXCEEDED: pti = new Error("Array Bounds Exceeded"); break; case STATUS_FLOAT_INVALID_OPERATION: pti = new Error("Invalid Floating Point Operation"); break; case STATUS_FLOAT_DENORMAL_OPERAND: pti = new Error("Floating Point Denormal Operand"); break; case STATUS_FLOAT_INEXACT_RESULT: pti = new Error("Floating Point Inexact Result"); break; case STATUS_FLOAT_OVERFLOW: pti = new Error("Floating Point Overflow"); break; case STATUS_FLOAT_UNDERFLOW: pti = new Error("Floating Point Underflow"); break; case STATUS_FLOAT_STACK_CHECK: pti = new Error("Floating Point Stack Check"); break; case STATUS_PRIVILEGED_INSTRUCTION: if (*(cast(ubyte *)(exceptionRecord.ExceptionAddress))==0xF4) { // HLT pti = new Error("assert(0) or HLT instruction"); } else { pti = new Error("Privileged Instruction"); } break; case STATUS_ILLEGAL_INSTRUCTION: pti = new Error("Illegal Instruction"); break; case STATUS_BREAKPOINT: pti = new Error("Breakpoint"); break; case STATUS_IN_PAGE_ERROR: pti = new Error("Win32 In Page Exception"); break; /* case STATUS_INVALID_DISPOSITION: case STATUS_NONCONTINUABLE_EXCEPTION: case STATUS_SINGLE_STEP: case DBG_CONTROL_C: // only when a debugger is attached // In DMC, but not in Microsoft docs case STATUS_GUARD_PAGE_VIOLATION: case STATUS_INVALID_HANDLE: */ // convert all other exception codes into a Win32Exception default: pti = new Error("Win32 Exception"); break; } _d_createTrace(pti, context); return pti; } /* These next two functions are necessary for dealing with collided exceptions: when an exception has been thrown during unwinding. This happens for example when a throw statement was encountered inside a finally clause. 'frame' is the stack pointer giving the state we were in, when we made the call to RtlUnwind. When we return ExceptionCollidedUnwind, the OS initiates a new SEARCH phase, using the new exception, and it begins this search from the frame we provide in the 'dispatcherContext' output parameter. We change the target frame pointer, by changing dispatcherContext. After this, we'll be back at the start of a SEARCH phase, so we need cancel all existing operations. There are two types of possible collisions. (1) collision during a local unwind. That is, localunwind was called during the SEARCH phase (without going through an additional call to RtlUnwind). We need to cancel the original search pass, so we'll restart from 'frame'. (2) collision during a global unwind. That is, localunwind was called from the UNWIND phase. We need to cancel the unwind pass, AND we need to cancel the search pass that initiated it. So, we need to restart from 'frame.prev'. */ extern (C) EXCEPTION_DISPOSITION searchCollisionExceptionHandler( EXCEPTION_RECORD *exceptionRecord, DEstablisherFrame *frame, CONTEXT *context, void *dispatcherContext) { if (!(exceptionRecord.ExceptionFlags & EXCEPTION_UNWIND)) { // Mark this as a collateral exception EXCEPTION_RECORD * n = skipCollateralExceptions(exceptionRecord); n.ExceptionFlags |= EXCEPTION_COLLATERAL; return EXCEPTION_DISPOSITION.ExceptionContinueSearch; } // An exception has been thrown during unwinding. // It happened during the SEARCH phase. // We need to cancel the original search pass, so we'll restart from 'frame'. *(cast(void **)dispatcherContext) = frame; return EXCEPTION_DISPOSITION.ExceptionCollidedUnwind; } extern(C) EXCEPTION_DISPOSITION unwindCollisionExceptionHandler( EXCEPTION_RECORD *exceptionRecord, DEstablisherFrame *frame, CONTEXT *context, void *dispatcherContext) { if (!(exceptionRecord.ExceptionFlags & EXCEPTION_UNWIND)) { // Mark this as a collateral exception EXCEPTION_RECORD * n = skipCollateralExceptions(exceptionRecord); n.ExceptionFlags |= EXCEPTION_COLLATERAL; return EXCEPTION_DISPOSITION.ExceptionContinueSearch; } // An exception has been thrown during unwinding. // It happened during the UNWIND phase. // We need to cancel the unwind pass, AND we need to cancel the search // pass that initiated the unwind. So, we need to restart from 'frame.prev'. *(cast(void **)dispatcherContext) = frame.prev; return EXCEPTION_DISPOSITION.ExceptionCollidedUnwind; } /************************************** * Call finally blocks in the current stack frame until stop_index. * This is roughly equivalent to _local_unwind() for C in \src\win32\ehsup.c */ extern(C) void _d_local_unwind(DHandlerTable *handler_table, DEstablisherFrame *frame, int stop_index, LanguageSpecificHandler collisionHandler) { DHandlerInfo *phi; DCatchInfo *pci; int i; // Set up a special exception handler to catch double-fault exceptions. asm { push dword ptr -1; push dword ptr 0; push collisionHandler; push dword ptr FS:_except_list; mov FS:_except_list,ESP; } for (i = frame.table_index; i != -1 && i != stop_index; i = phi.prev_index) { phi = &handler_table.handler_info.ptr[i]; if (phi.finally_code) { // Note that it is unnecessary to adjust the ESP, as the finally block // accesses all items on the stack as relative to EBP. DWORD *catch_ebp = &frame.ebp; void *blockaddr = phi.finally_code; asm { push EBX; mov EBX,blockaddr; push EBP; mov EBP,catch_ebp; call EBX; pop EBP; pop EBX; } } } asm { pop FS:_except_list; add ESP,12; } } /+ According to http://www.microsoft.com/msj/0197/exception/exception.aspx, global unwind is just a thin wrapper around RtlUnwind. __global_unwind(void * pRegistFrame) { _RtlUnwind( pRegistFrame, &__ret_label, 0, 0 ); __ret_label: } Apparently Win32 doesn't use the return address anyway. This code seems to be calling RtlUnwind( pFrame, &__retlabel, eRecord, 0); +/ extern(C) int _d_global_unwind(DEstablisherFrame *pFrame, EXCEPTION_RECORD *eRecord) { asm { naked; push EBP; mov EBP,ESP; push ECX; push EBX; push ESI; push EDI; push EBP; push 0; push dword ptr 12[EBP]; //eRecord call __system_unwind; jmp __unwind_exit; __system_unwind: push dword ptr 8[EBP]; // pFrame call RtlUnwind; __unwind_exit: pop EBP; pop EDI; pop ESI; pop EBX; pop ECX; mov ESP,EBP; pop EBP; ret; } } /*********************************** * external version of the unwinder * This is used for 'goto' or 'return', to run any finally blocks * which were skipped. */ extern(C) void _d_local_unwind2() { asm { naked; jmp _d_localUnwindForGoto; } } extern(C) void _d_localUnwindForGoto(DHandlerTable *handler_table, DEstablisherFrame *frame, int stop_index) { _d_local_unwind(handler_table, frame, stop_index, &searchCollisionExceptionHandler); } /*********************************** * The frame handler, this is called for each frame that has been registered * in the OS except_list. * Input: * EAX the handler table for the frame */ extern(C) EXCEPTION_DISPOSITION _d_monitor_handler( EXCEPTION_RECORD *exceptionRecord, DEstablisherFrame *frame, CONTEXT *context, void *dispatcherContext) { if (exceptionRecord.ExceptionFlags & EXCEPTION_UNWIND) { _d_monitorexit(cast(Object)cast(void *)frame.table_index); } else { } return EXCEPTION_DISPOSITION.ExceptionContinueSearch; } /*********************************** */ extern(C) void _d_monitor_prolog(void *x, void *y, Object h) { asm { push EAX; } //printf("_d_monitor_prolog(x=%p, y=%p, h=%p)\n", x, y, h); _d_monitorenter(h); asm { pop EAX; } } /*********************************** */ extern(C) void _d_monitor_epilog(void *x, void *y, Object h) { //printf("_d_monitor_epilog(x=%p, y=%p, h=%p)\n", x, y, h); asm { push EAX; push EDX; } _d_monitorexit(h); asm { pop EDX; pop EAX; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/minit.asm0000664000175000017500000000513012776214756020520 0ustar kaikai;_ minit.asm ; Module initialization support. ; ; Copyright: Copyright Digital Mars 2000 - 2010. ; License: $(WEB http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0). ; Authors: Walter Bright ; ; Copyright Digital Mars 2000 - 2010. ; Distributed under the Boost Software License, Version 1.0. ; (See accompanying file LICENSE or copy at ; http://www.boost.org/LICENSE_1_0.txt) ; include macros.asm ifdef _WIN32 DATAGRP EQU FLAT else DATAGRP EQU DGROUP endif ; Provide a default resolution for weak extern records, no way in C ; to define an omf symbol with a specific value public __nullext __nullext equ 0 extrn __moduleinfo_array:near ; This bit of assembler is needed because, from C or D, one cannot ; specify the names of data segments. Why does this matter? ; All the ModuleInfo pointers are placed into a segment named 'FM'. ; The order in which they are placed in 'FM' is arbitrarily up to the linker. ; In order to walk all the pointers, we need to be able to find the ; beginning and the end of the 'FM' segment. ; This is done by bracketing the 'FM' segment with two other, empty, ; segments named 'FMB' and 'FME'. Since this module is the only one that ; ever refers to 'FMB' and 'FME', we get to control the order in which ; these segments appear relative to 'FM' by using a GROUP statement. ; So, we have in memory: ; FMB empty segment ; FM contains all the pointers ; FME empty segment ; and finding the limits of FM is as easy as taking the address of FMB ; and the address of FME. ; These segments bracket FM, which contains the list of ModuleInfo pointers FMB segment dword use32 public 'DATA' FMB ends FM segment dword use32 public 'DATA' FM ends FME segment dword use32 public 'DATA' FME ends ; This leaves room in the _fatexit() list for _moduleDtor() XOB segment dword use32 public 'BSS' XOB ends XO segment dword use32 public 'BSS' dd ? XO ends XOE segment dword use32 public 'BSS' XOE ends DGROUP group FMB,FM,FME begcode minit ; extern (C) void _minit(); ; Converts array of ModuleInfo pointers to a D dynamic array of them, ; so they can be accessed via D. ; Result is written to: ; extern (C) ModuleInfo[] _moduleinfo_array; public __minit __minit proc near mov EDX,offset DATAGRP:FMB mov EAX,offset DATAGRP:FME mov dword ptr __moduleinfo_array+4,EDX sub EAX,EDX ; size in bytes of FM segment shr EAX,2 ; convert to array length mov dword ptr __moduleinfo_array,EAX ret __minit endp endcode minit end ldc-1.1.0-beta3-src/runtime/druntime/src/rt/arrayassign.d0000664000175000017500000001625212776214756021375 0ustar kaikai/** * Implementation of array assignment support routines. * * Copyright: Copyright Digital Mars 2000 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Kenji Hara */ /* Copyright Digital Mars 2000 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.arrayassign; private { import rt.util.array; import core.stdc.string; import core.stdc.stdlib; debug(PRINTF) import core.stdc.stdio; } /** * Keep for backward binary compatibility. This function can be removed in the future. */ extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to) { debug(PRINTF) printf("_d_arrayassign(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize); immutable elementSize = ti.tsize; // Need a temporary buffer tmp[] big enough to hold one element void[16] buf = void; void* ptmp = (elementSize > buf.sizeof) ? alloca(elementSize) : buf.ptr; return _d_arrayassign_l(ti, from, to, ptmp); } /** * Does array assignment (not construction) from another * lvalue array of the same element type. * Handles overlapping copies. * Input: * ti TypeInfo of the element type. * dst Points target memory. Its .length is equal to the element count, not byte length. * src Points source memory. Its .length is equal to the element count, not byte length. * ptmp Temporary memory for element swapping. */ extern (C) void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp) { debug(PRINTF) printf("_d_arrayassign_l(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize); immutable elementSize = ti.tsize; enforceRawArraysConformable("copy", elementSize, src, dst, true); if (src.ptr < dst.ptr && dst.ptr < src.ptr + elementSize * src.length) { // If dst is in the middle of src memory, use reverse order. for (auto i = dst.length; i--; ) { void* pdst = dst.ptr + i * elementSize; void* psrc = src.ptr + i * elementSize; memcpy(ptmp, pdst, elementSize); memcpy(pdst, psrc, elementSize); ti.postblit(pdst); ti.destroy(ptmp); } } else { // Otherwise, use normal order. foreach (i; 0 .. dst.length) { void* pdst = dst.ptr + i * elementSize; void* psrc = src.ptr + i * elementSize; memcpy(ptmp, pdst, elementSize); memcpy(pdst, psrc, elementSize); ti.postblit(pdst); ti.destroy(ptmp); } } return dst; } unittest // Bugzilla 14024 { string op; struct S { char x = 'x'; this(this) { op ~= x-0x20; } // upper case ~this() { op ~= x; } // lower case } S[4] mem; ref S[2] slice(int a, int b) { return mem[a .. b][0 .. 2]; } op = null; mem[0].x = 'a'; mem[1].x = 'b'; mem[2].x = 'x'; mem[3].x = 'y'; slice(0, 2) = slice(2, 4); // [ab] = [xy] assert(op == "XaYb", op); op = null; mem[0].x = 'x'; mem[1].x = 'y'; mem[2].x = 'a'; mem[3].x = 'b'; slice(2, 4) = slice(0, 2); // [ab] = [xy] assert(op == "XaYb", op); op = null; mem[0].x = 'a'; mem[1].x = 'b'; mem[2].x = 'c'; slice(0, 2) = slice(1, 3); // [ab] = [bc] assert(op == "BaCb", op); op = null; mem[0].x = 'x'; mem[1].x = 'y'; mem[2].x = 'z'; slice(1, 3) = slice(0, 2); // [yz] = [xy] assert(op == "YzXy", op); } /** * Does array assignment (not construction) from another * rvalue array of the same element type. * Input: * ti TypeInfo of the element type. * dst Points target memory. Its .length is equal to the element count, not byte length. * src Points source memory. Its .length is equal to the element count, not byte length. * It is always allocated on stack and never overlapping with dst. * ptmp Temporary memory for element swapping. */ extern (C) void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp) { debug(PRINTF) printf("_d_arrayassign_r(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize); immutable elementSize = ti.tsize; enforceRawArraysConformable("copy", elementSize, src, dst, false); // Always use normal order, because we can assume that // the rvalue src has no overlapping with dst. foreach (i; 0 .. dst.length) { void* pdst = dst.ptr + i * elementSize; void* psrc = src.ptr + i * elementSize; memcpy(ptmp, pdst, elementSize); memcpy(pdst, psrc, elementSize); ti.destroy(ptmp); } return dst; } /** * Does array initialization (not assignment) from another * array of the same element type. * ti is the element type. */ extern (C) void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to) { debug(PRINTF) printf("_d_arrayctor(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize); auto element_size = ti.tsize; enforceRawArraysConformable("initialization", element_size, from, to); size_t i; try { for (i = 0; i < to.length; i++) { // Copy construction is defined as bit copy followed by postblit. memcpy(to.ptr + i * element_size, from.ptr + i * element_size, element_size); ti.postblit(to.ptr + i * element_size); } } catch (Throwable o) { /* Destroy, in reverse order, what we've constructed so far */ while (i--) { ti.destroy(to.ptr + i * element_size); } throw o; } return to; } /** * Do assignment to an array. * p[0 .. count] = value; */ extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti) { void* pstart = p; auto element_size = ti.tsize; //Need a temporary buffer tmp[] big enough to hold one element void[16] buf = void; void[] tmp; if (element_size > buf.sizeof) { tmp = alloca(element_size)[0 .. element_size]; } else tmp = buf[]; foreach (i; 0 .. count) { memcpy(tmp.ptr, p, element_size); memcpy(p, value, element_size); ti.postblit(p); ti.destroy(tmp.ptr); p += element_size; } return pstart; } /** * Do construction of an array. * ti[count] p = value; */ extern (C) void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti) { void* pstart = p; auto element_size = ti.tsize; try { foreach (i; 0 .. count) { // Copy construction is defined as bit copy followed by postblit. memcpy(p, value, element_size); ti.postblit(p); p += element_size; } } catch (Throwable o) { // Destroy, in reverse order, what we've constructed so far while (p > pstart) { p -= element_size; ti.destroy(p); } throw o; } return pstart; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/aaA.d0000664000175000017500000005660712776214756017544 0ustar kaikai/** * Implementation of associative arrays. * * Copyright: Copyright Digital Mars 2000 - 2015. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak */ module rt.aaA; /// AA version for debuggers, bump whenever changing the layout extern (C) immutable int _aaVersion = 1; import core.memory : GC; // grow threshold private enum GROW_NUM = 4; private enum GROW_DEN = 5; // shrink threshold private enum SHRINK_NUM = 1; private enum SHRINK_DEN = 8; // grow factor private enum GROW_FAC = 4; // growing the AA doubles it's size, so the shrink threshold must be // smaller than half the grow threshold to have a hysteresis static assert(GROW_FAC * SHRINK_NUM * GROW_DEN < GROW_NUM * SHRINK_DEN); // initial load factor (for literals), mean of both thresholds private enum INIT_NUM = (GROW_DEN * SHRINK_NUM + GROW_NUM * SHRINK_DEN) / 2; private enum INIT_DEN = SHRINK_DEN * GROW_DEN; private enum INIT_NUM_BUCKETS = 8; // magic hash constants to distinguish empty, deleted, and filled buckets private enum HASH_EMPTY = 0; private enum HASH_DELETED = 0x1; private enum HASH_FILLED_MARK = size_t(1) << 8 * size_t.sizeof - 1; /// Opaque AA wrapper struct AA { Impl* impl; alias impl this; private @property bool empty() const pure nothrow @nogc { return impl is null || !impl.length; } } private struct Impl { private: this(in TypeInfo_AssociativeArray ti, size_t sz = INIT_NUM_BUCKETS) { keysz = cast(uint) ti.key.tsize; valsz = cast(uint) ti.value.tsize; buckets = allocBuckets(sz); firstUsed = cast(uint) buckets.length; entryTI = fakeEntryTI(ti.key, ti.value); valoff = cast(uint) talign(keysz, ti.value.talign); import rt.lifetime : hasPostblit, unqualify; if (hasPostblit(unqualify(ti.key))) flags |= Flags.keyHasPostblit; if ((ti.key.flags | ti.value.flags) & 1) flags |= Flags.hasPointers; } Bucket[] buckets; uint used; uint deleted; TypeInfo_Struct entryTI; uint firstUsed; immutable uint keysz; immutable uint valsz; immutable uint valoff; Flags flags; enum Flags : ubyte { none = 0x0, keyHasPostblit = 0x1, hasPointers = 0x2, } @property size_t length() const pure nothrow @nogc { assert(used >= deleted); return used - deleted; } @property size_t dim() const pure nothrow @nogc { return buckets.length; } @property size_t mask() const pure nothrow @nogc { return dim - 1; } // find the first slot to insert a value with hash inout(Bucket)* findSlotInsert(size_t hash) inout pure nothrow @nogc { for (size_t i = hash & mask, j = 1;; ++j) { if (!buckets[i].filled) return &buckets[i]; i = (i + j) & mask; } } // lookup a key inout(Bucket)* findSlotLookup(size_t hash, in void* pkey, in TypeInfo keyti) inout { for (size_t i = hash & mask, j = 1;; ++j) { if (buckets[i].hash == hash && keyti.equals(pkey, buckets[i].entry)) return &buckets[i]; else if (buckets[i].empty) return null; i = (i + j) & mask; } } void grow(in TypeInfo keyti) { // If there are so many deleted entries, that growing would push us // below the shrink threshold, we just purge deleted entries instead. if (length * SHRINK_DEN < GROW_FAC * dim * SHRINK_NUM) resize(dim); else resize(GROW_FAC * dim); } void shrink(in TypeInfo keyti) { if (dim > INIT_NUM_BUCKETS) resize(dim / GROW_FAC); } void resize(size_t ndim) pure nothrow { auto obuckets = buckets; buckets = allocBuckets(ndim); foreach (ref b; obuckets[firstUsed .. $]) if (b.filled) *findSlotInsert(b.hash) = b; firstUsed = 0; used -= deleted; deleted = 0; GC.free(obuckets.ptr); // safe to free b/c impossible to reference } void clear() pure nothrow { import core.stdc.string : memset; // clear all data, but don't change bucket array length memset(&buckets[firstUsed], 0, (buckets.length - firstUsed) * Bucket.sizeof); deleted = used = 0; firstUsed = cast(uint) dim; } } //============================================================================== // Bucket //------------------------------------------------------------------------------ private struct Bucket { private pure nothrow @nogc: size_t hash; void* entry; @property bool empty() const { return hash == HASH_EMPTY; } @property bool deleted() const { return hash == HASH_DELETED; } @property bool filled() const { return cast(ptrdiff_t) hash < 0; } } Bucket[] allocBuckets(size_t dim) @trusted pure nothrow { enum attr = GC.BlkAttr.NO_INTERIOR; immutable sz = dim * Bucket.sizeof; return (cast(Bucket*) GC.calloc(sz, attr))[0 .. dim]; } //============================================================================== // Entry //------------------------------------------------------------------------------ private void* allocEntry(in Impl* aa, in void* pkey) { import rt.lifetime : _d_newitemU; import core.stdc.string : memcpy, memset; immutable akeysz = aa.valoff; void* res = void; if (aa.entryTI) res = _d_newitemU(aa.entryTI); else { auto flags = (aa.flags & Impl.Flags.hasPointers) ? 0 : GC.BlkAttr.NO_SCAN; res = GC.malloc(akeysz + aa.valsz, flags); } memcpy(res, pkey, aa.keysz); // copy key memset(res + akeysz, 0, aa.valsz); // zero value return res; } package void entryDtor(void* p, const TypeInfo_Struct sti) { // key and value type info stored after the TypeInfo_Struct by tiEntry() auto sizeti = __traits(classInstanceSize, TypeInfo_Struct); auto extra = cast(const(TypeInfo)*)(cast(void*) sti + sizeti); extra[0].destroy(p); extra[1].destroy(p + talign(extra[0].tsize, extra[1].talign)); } private bool hasDtor(const TypeInfo ti) { import rt.lifetime : unqualify; if (typeid(ti) is typeid(TypeInfo_Struct)) if ((cast(TypeInfo_Struct) cast(void*) ti).xdtor) return true; if (typeid(ti) is typeid(TypeInfo_StaticArray)) return hasDtor(unqualify(ti.next)); return false; } // build type info for Entry with additional key and value fields TypeInfo_Struct fakeEntryTI(const TypeInfo keyti, const TypeInfo valti) { import rt.lifetime : unqualify; auto kti = unqualify(keyti); auto vti = unqualify(valti); if (!hasDtor(kti) && !hasDtor(vti)) return null; // save kti and vti after type info for struct enum sizeti = __traits(classInstanceSize, TypeInfo_Struct); void* p = GC.malloc(sizeti + 2 * (void*).sizeof); import core.stdc.string : memcpy; memcpy(p, typeid(TypeInfo_Struct).initializer().ptr, sizeti); auto ti = cast(TypeInfo_Struct) p; auto extra = cast(TypeInfo*)(p + sizeti); extra[0] = cast() kti; extra[1] = cast() vti; static immutable tiName = __MODULE__ ~ ".Entry!(...)"; ti.name = tiName; // we don't expect the Entry objects to be used outside of this module, so we have control // over the non-usage of the callback methods and other entries and can keep these null // xtoHash, xopEquals, xopCmp, xtoString and xpostblit ti.m_RTInfo = null; immutable entrySize = talign(kti.tsize, vti.talign) + vti.tsize; ti.m_init = (cast(ubyte*) null)[0 .. entrySize]; // init length, but not ptr // xdtor needs to be built from the dtors of key and value for the GC ti.xdtorti = &entryDtor; ti.m_flags = TypeInfo_Struct.StructFlags.isDynamicType; ti.m_flags |= (keyti.flags | valti.flags) & TypeInfo_Struct.StructFlags.hasPointers; ti.m_align = cast(uint) max(kti.talign, vti.talign); return ti; } //============================================================================== // Helper functions //------------------------------------------------------------------------------ private size_t talign(size_t tsize, size_t algn) @safe pure nothrow @nogc { immutable mask = algn - 1; assert(!(mask & algn)); return (tsize + mask) & ~mask; } // mix hash to "fix" bad hash functions private size_t mix(size_t h) @safe pure nothrow @nogc { // final mix function of MurmurHash2 enum m = 0x5bd1e995; h ^= h >> 13; h *= m; h ^= h >> 15; return h; } private size_t calcHash(in void* pkey, in TypeInfo keyti) { immutable hash = keyti.getHash(pkey); // highest bit is set to distinguish empty/deleted from filled buckets return mix(hash) | HASH_FILLED_MARK; } private size_t nextpow2(in size_t n) pure nothrow @nogc { import core.bitop : bsr; if (!n) return 1; const isPowerOf2 = !((n - 1) & n); return 1 << (bsr(n) + !isPowerOf2); } pure nothrow @nogc unittest { // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 foreach (const n, const pow2; [1, 1, 2, 4, 4, 8, 8, 8, 8, 16]) assert(nextpow2(n) == pow2); } private T min(T)(T a, T b) pure nothrow @nogc { return a < b ? a : b; } private T max(T)(T a, T b) pure nothrow @nogc { return b < a ? a : b; } //============================================================================== // API Implementation //------------------------------------------------------------------------------ /// Determine number of entries in associative array. extern (C) size_t _aaLen(in AA aa) pure nothrow @nogc { return aa ? aa.length : 0; } /// Get LValue for key extern (C) void* _aaGetY(AA* aa, const TypeInfo_AssociativeArray ti, in size_t valsz, in void* pkey) { // lazily alloc implementation if (aa.impl is null) aa.impl = new Impl(ti); // get hash and bucket for key immutable hash = calcHash(pkey, ti.key); // found a value => return it if (auto p = aa.findSlotLookup(hash, pkey, ti.key)) return p.entry + aa.valoff; auto p = aa.findSlotInsert(hash); if (p.deleted) --aa.deleted; // check load factor and possibly grow else if (++aa.used * GROW_DEN > aa.dim * GROW_NUM) { aa.grow(ti.key); p = aa.findSlotInsert(hash); assert(p.empty); } // update search cache and allocate entry aa.firstUsed = min(aa.firstUsed, cast(uint)(p - aa.buckets.ptr)); p.hash = hash; p.entry = allocEntry(aa.impl, pkey); // postblit for key if (aa.flags & Impl.Flags.keyHasPostblit) { import rt.lifetime : __doPostblit, unqualify; __doPostblit(p.entry, aa.keysz, unqualify(ti.key)); } // return pointer to value return p.entry + aa.valoff; } /// Get RValue for key, returns null if not present extern (C) inout(void)* _aaGetRvalueX(inout AA aa, in TypeInfo keyti, in size_t valsz, in void* pkey) { return _aaInX(aa, keyti, pkey); } /// Return pointer to value if present, null otherwise extern (C) inout(void)* _aaInX(inout AA aa, in TypeInfo keyti, in void* pkey) { if (aa.empty) return null; immutable hash = calcHash(pkey, keyti); if (auto p = aa.findSlotLookup(hash, pkey, keyti)) return p.entry + aa.valoff; return null; } /// Delete entry in AA, return true if it was present extern (C) bool _aaDelX(AA aa, in TypeInfo keyti, in void* pkey) { if (aa.empty) return false; immutable hash = calcHash(pkey, keyti); if (auto p = aa.findSlotLookup(hash, pkey, keyti)) { // clear entry p.hash = HASH_DELETED; p.entry = null; ++aa.deleted; if (aa.length * SHRINK_DEN < aa.dim * SHRINK_NUM) aa.shrink(keyti); return true; } return false; } /// Remove all elements from AA. extern (C) void _aaClear(AA aa) pure nothrow { if (!aa.empty) { aa.impl.clear(); } } /// Rehash AA extern (C) void* _aaRehash(AA* paa, in TypeInfo keyti) pure nothrow { if (!paa.empty) paa.resize(nextpow2(INIT_DEN * paa.length / INIT_NUM)); return *paa; } /// Return a GC allocated array of all values extern (C) inout(void[]) _aaValues(inout AA aa, in size_t keysz, in size_t valsz, const TypeInfo tiValueArray) pure nothrow { if (aa.empty) return null; import rt.lifetime : _d_newarrayU; auto res = _d_newarrayU(tiValueArray, aa.length).ptr; auto pval = res; immutable off = aa.valoff; foreach (b; aa.buckets[aa.firstUsed .. $]) { if (!b.filled) continue; pval[0 .. valsz] = b.entry[off .. valsz + off]; pval += valsz; } // postblit is done in object.values return (cast(inout(void)*) res)[0 .. aa.length]; // fake length, return number of elements } /// Return a GC allocated array of all keys extern (C) inout(void[]) _aaKeys(inout AA aa, in size_t keysz, const TypeInfo tiKeyArray) pure nothrow { if (aa.empty) return null; import rt.lifetime : _d_newarrayU; auto res = _d_newarrayU(tiKeyArray, aa.length).ptr; auto pkey = res; foreach (b; aa.buckets[aa.firstUsed .. $]) { if (!b.filled) continue; pkey[0 .. keysz] = b.entry[0 .. keysz]; pkey += keysz; } // postblit is done in object.keys return (cast(inout(void)*) res)[0 .. aa.length]; // fake length, return number of elements } // opApply callbacks are extern(D) extern (D) alias dg_t = int delegate(void*); extern (D) alias dg2_t = int delegate(void*, void*); /// foreach opApply over all values extern (C) int _aaApply(AA aa, in size_t keysz, dg_t dg) { if (aa.empty) return 0; immutable off = aa.valoff; foreach (b; aa.buckets) { if (!b.filled) continue; if (auto res = dg(b.entry + off)) return res; } return 0; } /// foreach opApply over all key/value pairs extern (C) int _aaApply2(AA aa, in size_t keysz, dg2_t dg) { if (aa.empty) return 0; immutable off = aa.valoff; foreach (b; aa.buckets) { if (!b.filled) continue; if (auto res = dg(b.entry, b.entry + off)) return res; } return 0; } /// Construct an associative array of type ti from keys and value extern (C) Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] vals) { assert(keys.length == vals.length); immutable keysz = ti.key.tsize; immutable valsz = ti.value.tsize; immutable length = keys.length; if (!length) return null; auto aa = new Impl(ti, nextpow2(INIT_DEN * length / INIT_NUM)); void* pkey = keys.ptr; void* pval = vals.ptr; immutable off = aa.valoff; foreach (_; 0 .. length) { immutable hash = calcHash(pkey, ti.key); auto p = aa.findSlotLookup(hash, pkey, ti.key); if (p is null) { p = aa.findSlotInsert(hash); p.hash = hash; p.entry = allocEntry(aa, pkey); // move key, no postblit aa.firstUsed = min(aa.firstUsed, cast(uint)(p - aa.buckets.ptr)); } else if (aa.entryTI && hasDtor(ti.value)) { // destroy existing value before overwriting it ti.value.destroy(p.entry + off); } // set hash and blit value auto pdst = p.entry + off; pdst[0 .. valsz] = pval[0 .. valsz]; // move value, no postblit pkey += keysz; pval += valsz; } aa.used = cast(uint) length; return aa; } /// compares 2 AAs for equality extern (C) int _aaEqual(in TypeInfo tiRaw, in AA aa1, in AA aa2) { if (aa1.impl is aa2.impl) return true; immutable len = _aaLen(aa1); if (len != _aaLen(aa2)) return false; if (!len) // both empty return true; import rt.lifetime : unqualify; auto uti = unqualify(tiRaw); auto ti = *cast(TypeInfo_AssociativeArray*)&uti; // compare the entries immutable off = aa1.valoff; foreach (b1; aa1.buckets) { if (!b1.filled) continue; auto pb2 = aa2.findSlotLookup(b1.hash, b1.entry, ti.key); if (pb2 is null || !ti.value.equals(b1.entry + off, pb2.entry + off)) return false; } return true; } /// compute a hash extern (C) hash_t _aaGetHash(in AA* aa, in TypeInfo tiRaw) nothrow { if (aa.empty) return 0; import rt.lifetime : unqualify; auto uti = unqualify(tiRaw); auto ti = *cast(TypeInfo_AssociativeArray*)&uti; immutable off = aa.valoff; auto valHash = &ti.value.getHash; size_t h; foreach (b; aa.buckets) { if (!b.filled) continue; size_t[2] h2 = [b.hash, valHash(b.entry + off)]; // use XOR here, so that hash is independent of element order h ^= hashOf(h2.ptr, h2.length * h2[0].sizeof); } return h; } /** * _aaRange implements a ForwardRange */ struct Range { Impl* impl; size_t idx; alias impl this; } extern (C) pure nothrow @nogc { Range _aaRange(AA aa) { if (!aa) return Range(); foreach (i; aa.firstUsed .. aa.dim) { if (aa.buckets[i].filled) return Range(aa.impl, i); } return Range(aa, aa.dim); } bool _aaRangeEmpty(Range r) { return r.impl is null || r.idx == r.dim; } void* _aaRangeFrontKey(Range r) { return r.buckets[r.idx].entry; } void* _aaRangeFrontValue(Range r) { return r.buckets[r.idx].entry + r.valoff; } void _aaRangePopFront(ref Range r) { for (++r.idx; r.idx < r.dim; ++r.idx) { if (r.buckets[r.idx].filled) break; } } } //============================================================================== // Unittests //------------------------------------------------------------------------------ // LDC_FIXME: Cannot compile these tests in this module (and this module only) // because the public signatures of the various functions are different from // the ones used here (AA vs. void*). version (LDC) {} else { pure nothrow unittest { int[string] aa; assert(aa.keys.length == 0); assert(aa.values.length == 0); aa["hello"] = 3; assert(aa["hello"] == 3); aa["hello"]++; assert(aa["hello"] == 4); assert(aa.length == 1); string[] keys = aa.keys; assert(keys.length == 1); assert(keys[0] == "hello"); int[] values = aa.values; assert(values.length == 1); assert(values[0] == 4); aa.rehash; assert(aa.length == 1); assert(aa["hello"] == 4); aa["foo"] = 1; aa["bar"] = 2; aa["batz"] = 3; assert(aa.keys.length == 4); assert(aa.values.length == 4); foreach (a; aa.keys) { assert(a.length != 0); assert(a.ptr != null); } foreach (v; aa.values) { assert(v != 0); } } unittest // Test for Issue 10381 { alias II = int[int]; II aa1 = [0 : 1]; II aa2 = [0 : 1]; II aa3 = [0 : 2]; assert(aa1 == aa2); // Passes assert(typeid(II).equals(&aa1, &aa2)); assert(!typeid(II).equals(&aa1, &aa3)); } pure nothrow unittest { string[int] key1 = [1 : "true", 2 : "false"]; string[int] key2 = [1 : "false", 2 : "true"]; string[int] key3; // AA lits create a larger hashtable int[string[int]] aa1 = [key1 : 100, key2 : 200, key3 : 300]; // Ensure consistent hash values are computed for key1 assert((key1 in aa1) !is null); // Manually assigning to an empty AA creates a smaller hashtable int[string[int]] aa2; aa2[key1] = 100; aa2[key2] = 200; aa2[key3] = 300; assert(aa1 == aa2); // Ensure binary-independence of equal hash keys string[int] key2a; key2a[1] = "false"; key2a[2] = "true"; assert(aa1[key2a] == 200); } // Issue 9852 pure nothrow unittest { // Original test case (revised, original assert was wrong) int[string] a; a["foo"] = 0; a.remove("foo"); assert(a == null); // should not crash int[string] b; assert(b is null); assert(a == b); // should not deref null assert(b == a); // ditto int[string] c; c["a"] = 1; assert(a != c); // comparison with empty non-null AA assert(c != a); assert(b != c); // comparison with null AA assert(c != b); } // Bugzilla 14104 unittest { import core.stdc.stdio; alias K = const(ubyte)*; size_t[K] aa; immutable key = cast(K)(cast(size_t) uint.max + 1); aa[key] = 12; assert(key in aa); } unittest { int[int] aa; foreach (k, v; aa) assert(false); foreach (v; aa) assert(false); assert(aa.byKey.empty); assert(aa.byValue.empty); assert(aa.byKeyValue.empty); size_t n; aa = [0 : 3, 1 : 4, 2 : 5]; foreach (k, v; aa) { n += k; assert(k >= 0 && k < 3); assert(v >= 3 && v < 6); } assert(n == 3); n = 0; foreach (v; aa) { n += v; assert(v >= 3 && v < 6); } assert(n == 12); n = 0; foreach (k, v; aa) { ++n; break; } assert(n == 1); n = 0; foreach (v; aa) { ++n; break; } assert(n == 1); } unittest { int[int] aa; assert(!aa.remove(0)); aa = [0 : 1]; assert(aa.remove(0)); assert(!aa.remove(0)); aa[1] = 2; assert(!aa.remove(0)); assert(aa.remove(1)); assert(aa.length == 0); assert(aa.byKey.empty); } // test zero sized value (hashset) unittest { alias V = void[0]; auto aa = [0 : V.init]; assert(aa.length == 1); assert(aa.byKey.front == 0); assert(aa.byValue.front == V.init); aa[1] = V.init; assert(aa.length == 2); aa[0] = V.init; assert(aa.length == 2); assert(aa.remove(0)); aa[0] = V.init; assert(aa.length == 2); assert(aa == [0 : V.init, 1 : V.init]); } // test tombstone purging unittest { int[int] aa; foreach (i; 0 .. 6) aa[i] = i; foreach (i; 0 .. 6) assert(aa.remove(i)); foreach (i; 6 .. 10) aa[i] = i; assert(aa.length == 4); foreach (i; 6 .. 10) assert(i in aa); } // test postblit for AA literals unittest { static struct T { static size_t postblit, dtor; this(this) { ++postblit; } ~this() { ++dtor; } } T t; auto aa1 = [0 : t, 1 : t]; assert(T.dtor == 0 && T.postblit == 2); aa1[0] = t; assert(T.dtor == 1 && T.postblit == 3); T.dtor = 0; T.postblit = 0; auto aa2 = [0 : t, 1 : t, 0 : t]; // literal with duplicate key => value overwritten assert(T.dtor == 1 && T.postblit == 3); T.dtor = 0; T.postblit = 0; auto aa3 = [t : 0]; assert(T.dtor == 0 && T.postblit == 1); aa3[t] = 1; assert(T.dtor == 0 && T.postblit == 1); aa3.remove(t); assert(T.dtor == 0 && T.postblit == 1); aa3[t] = 2; assert(T.dtor == 0 && T.postblit == 2); // dtor will be called by GC finalizers aa1 = null; aa2 = null; aa3 = null; GC.runFinalizers((cast(char*)(&entryDtor))[0 .. 1]); assert(T.dtor == 6 && T.postblit == 2); } // for aa.clear pure nothrow unittest { int[int] aa; assert(aa.length == 0); foreach (i; 0 .. 100) aa[i] = i * 2; assert(aa.length == 100); auto aa2 = aa; assert(aa2.length == 100); aa.clear(); assert(aa.length == 0); assert(aa2.length == 0); aa2[5] = 6; assert(aa.length == 1); assert(aa[5] == 6); } } // !version(LDC) ldc-1.1.0-beta3-src/runtime/druntime/src/rt/msvc_math.c0000664000175000017500000000244412776214756021030 0ustar kaikai/** * This module provides alternate implementations of single-precision math * functions missing in at least some 32-bit x86 MS VC runtimes * * Copyright: Copyright Digital Mars 2015. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Source: $(DRUNTIMESRC rt/_msvc_math.c) * Authors: Martin Kinkelin */ #if defined _M_IX86 // Forward-declare double-precision version and implement single-precision // wrapper. #define ALT_IMPL(baseName) \ double baseName(double x); \ float _msvc_ ## baseName ## f(float x) { return (float)baseName(x); } #define ALT_IMPL2(baseName) \ double baseName(double x, double y); \ float _msvc_ ## baseName ## f(float x, float y) { return (float)baseName(x, y); } ALT_IMPL(acos); ALT_IMPL(asin); ALT_IMPL(atan); ALT_IMPL2(atan2); ALT_IMPL(cos); ALT_IMPL(sin); ALT_IMPL(tan); ALT_IMPL(cosh); ALT_IMPL(sinh); ALT_IMPL(tanh); ALT_IMPL(exp); ALT_IMPL(log); ALT_IMPL(log10); ALT_IMPL2(pow); ALT_IMPL(sqrt); ALT_IMPL(ceil); ALT_IMPL(floor); ALT_IMPL2(fmod); double modf(double value, double *iptr); float _msvc_modff(float value, float *iptr) { double di; float result = (float)modf(value, &di); *iptr = (float)di; return result; } #endif // _M_IX86 ldc-1.1.0-beta3-src/runtime/druntime/src/rt/qsort.d0000664000175000017500000000527312776214756020223 0ustar kaikai/** * This is a public domain version of qsort.d. All it does is call C's * qsort(). * * Copyright: Copyright Digital Mars 2000 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Martin Nowak */ /* Copyright Digital Mars 2000 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.qsort; //debug=qsort; private import core.stdc.stdlib; version (CRuntime_Glibc) { alias extern (C) int function(const void *, const void *, void *) Cmp; extern (C) void qsort_r(void *base, size_t nmemb, size_t size, Cmp cmp, void *arg); extern (C) void[] _adSort(void[] a, TypeInfo ti) { extern (C) int cmp(in void* p1, in void* p2, void* ti) { return (cast(TypeInfo)ti).compare(p1, p2); } qsort_r(a.ptr, a.length, ti.tsize, &cmp, cast(void*)ti); return a; } } else version (FreeBSD) { alias extern (C) int function(void *, const void *, const void *) Cmp; extern (C) void qsort_r(void *base, size_t nmemb, size_t size, void *thunk, Cmp cmp); extern (C) void[] _adSort(void[] a, TypeInfo ti) { extern (C) int cmp(void* ti, in void* p1, in void* p2) { return (cast(TypeInfo)ti).compare(p1, p2); } qsort_r(a.ptr, a.length, ti.tsize, cast(void*)ti, &cmp); return a; } } else version (OSX) { alias extern (C) int function(void *, const void *, const void *) Cmp; extern (C) void qsort_r(void *base, size_t nmemb, size_t size, void *thunk, Cmp cmp); extern (C) void[] _adSort(void[] a, TypeInfo ti) { extern (C) int cmp(void* ti, in void* p1, in void* p2) { return (cast(TypeInfo)ti).compare(p1, p2); } qsort_r(a.ptr, a.length, ti.tsize, cast(void*)ti, &cmp); return a; } } else { private TypeInfo tiglobal; extern (C) void[] _adSort(void[] a, TypeInfo ti) { extern (C) int cmp(in void* p1, in void* p2) { return tiglobal.compare(p1, p2); } tiglobal = ti; qsort(a.ptr, a.length, ti.tsize, &cmp); return a; } } unittest { debug(qsort) printf("array.sort.unittest()\n"); int[] a = new int[10]; a[0] = 23; a[1] = 1; a[2] = 64; a[3] = 5; a[4] = 6; a[5] = 5; a[6] = 17; a[7] = 3; a[8] = 0; a[9] = -1; _adSort(*cast(void[]*)&a, typeid(a[0])); for (int i = 0; i < a.length - 1; i++) { //printf("i = %d", i); //printf(" %d %d\n", a[i], a[i + 1]); assert(a[i] <= a[i + 1]); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/backtrace/0000775000175000017500000000000012776214756020616 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/rt/backtrace/elf.d0000664000175000017500000001443412776214756021537 0ustar kaikai/** * This code reads ELF files and sections using memory mapped IO. * * Reference: http://www.dwarfstd.org/ * * Copyright: Copyright Digital Mars 2015 - 2015. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Yazan Dabain * Source: $(DRUNTIMESRC src/rt/backtrace/elf.d) */ module rt.backtrace.elf; version(linux) version = linux_or_freebsd; else version(FreeBSD) version = linux_or_freebsd; version(linux_or_freebsd): import core.sys.posix.fcntl; import core.sys.posix.unistd; version(linux) public import core.sys.linux.elf; version(FreeBSD) public import core.sys.freebsd.sys.elf; struct ElfFile { static bool openSelf(ElfFile* file) @nogc nothrow { version (linux) { auto selfPath = "/proc/self/exe".ptr; } else version (FreeBSD) { char[1024] selfPathBuffer = void; auto selfPath = getFreeBSDExePath(selfPathBuffer[]); if (selfPath is null) return false; } file.fd = open(selfPath, O_RDONLY); if (file.fd >= 0) { // memory map header file.ehdr = MMapRegion!Elf_Ehdr(file.fd, 0, Elf_Ehdr.sizeof); if (file.ehdr.isValidElfHeader()) return true; else return false; } else return false; } @disable this(this); ~this() @nogc nothrow { if (fd != -1) close(fd); } int fd = -1; MMapRegion!Elf_Ehdr ehdr; } struct ElfSectionHeader { this(const(ElfFile)* file, size_t index) @nogc nothrow { assert(Elf_Shdr.sizeof == file.ehdr.e_shentsize); shdr = MMapRegion!Elf_Shdr( file.fd, file.ehdr.e_shoff + index * file.ehdr.e_shentsize, file.ehdr.e_shentsize ); } @disable this(this); alias shdr this; MMapRegion!Elf_Shdr shdr; } struct ElfSection { this(ElfFile* file, ElfSectionHeader* shdr) @nogc nothrow { data = MMapRegion!ubyte( file.fd, shdr.sh_offset, shdr.sh_size, ); length = shdr.sh_size; } @disable this(this); const(ubyte)[] get() @nogc nothrow { return data.get()[0 .. length]; } alias get this; MMapRegion!ubyte data; size_t length; } const(char)[] getSectionName(const(ElfFile)* file, ElfSection* stringSection, size_t nameIndex) @nogc nothrow { const(ubyte)[] data = stringSection.get(); foreach (i; nameIndex .. data.length) { if (data[i] == 0) return cast(const(char)[])data[nameIndex .. i]; } return null; } size_t findSectionByName(const(ElfFile)* file, ElfSection* stringSection, const(char)[] sectionName) @nogc nothrow { foreach (s; 0 .. file.ehdr.e_shnum) { auto sectionHeader = ElfSectionHeader(file, s); auto currentName = getSectionName(file, stringSection, sectionHeader.sh_name); if (sectionName == currentName) return s; // TODO: attempt to move ElfSectionHeader instead of returning index } // not found return -1; } private: version (FreeBSD) { extern (C) int sysctl(const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen) @nogc nothrow; const(char)* getFreeBSDExePath(char[] buffer) @nogc nothrow { enum { CTL_KERN = 1, KERN_PROC = 14, KERN_PROC_PATHNAME = 12 } int[4] mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1]; size_t len = buffer.length; auto result = sysctl(mib.ptr, mib.length, buffer.ptr, &len, null, 0); // get the length of the path if (result != 0) return null; if (len + 1 > buffer.length) return null; buffer[len] = 0; return buffer.ptr; } } bool isValidElfHeader(const(Elf_Ehdr)* ehdr) @nogc nothrow { if (ehdr.e_ident[EI_MAG0] != ELFMAG0) return false; if (ehdr.e_ident[EI_MAG1] != ELFMAG1) return false; if (ehdr.e_ident[EI_MAG2] != ELFMAG2) return false; if (ehdr.e_ident[EI_MAG3] != ELFMAG3) return false; // elf class and data encoding should match target's config if (ehdr.e_ident[EI_CLASS] != ELFCLASS) return false; if (ehdr.e_ident[EI_DATA] != ELFDATA ) return false; return true; } struct MMapRegion(T) { import core.sys.posix.sys.mman; import core.sys.posix.unistd; this(int fd, size_t offset, size_t length) @nogc nothrow { auto pagesize = sysconf(_SC_PAGESIZE); auto realOffset = (offset / pagesize) * pagesize; offsetDiff = offset - realOffset; realLength = length + offsetDiff; mptr = mmap(null, realLength, PROT_READ, MAP_PRIVATE, fd, realOffset); } @disable this(this); ~this() @nogc nothrow { if (mptr) munmap(mptr, realLength); } const(T)* get() const @nogc nothrow { return cast(T*)(mptr + offsetDiff); } alias get this; size_t realLength; size_t offsetDiff; void* mptr; } version(X86) { alias Elf_Ehdr = Elf32_Ehdr; alias Elf_Shdr = Elf32_Shdr; enum ELFCLASS = ELFCLASS32; } else version(X86_64) { alias Elf_Ehdr = Elf64_Ehdr; alias Elf_Shdr = Elf64_Shdr; enum ELFCLASS = ELFCLASS64; } else version(ARM) { alias Elf_Ehdr = Elf32_Ehdr; alias Elf_Shdr = Elf32_Shdr; enum ELFCLASS = ELFCLASS32; } else version(AArch64) { alias Elf_Ehdr = Elf64_Ehdr; alias Elf_Shdr = Elf64_Shdr; enum ELFCLASS = ELFCLASS64; } else version(PPC) { alias Elf_Ehdr = Elf32_Ehdr; alias Elf_Shdr = Elf32_Shdr; enum ELFCLASS = ELFCLASS32; } else version(PPC64) { alias Elf_Ehdr = Elf64_Ehdr; alias Elf_Shdr = Elf64_Shdr; enum ELFCLASS = ELFCLASS64; } else version(MIPS) { alias Elf_Ehdr = Elf32_Ehdr; alias Elf_Shdr = Elf32_Shdr; enum ELFCLASS = ELFCLASS32; } else version(MIPS64) { alias Elf_Ehdr = Elf64_Ehdr; alias Elf_Shdr = Elf64_Shdr; enum ELFCLASS = ELFCLASS64; } else version(SystemZ) { alias Elf_Ehdr = Elf64_Ehdr; alias Elf_Shdr = Elf64_Shdr; enum ELFCLASS = ELFCLASS64; } else { static assert(0, "unsupported architecture"); } version(LittleEndian) { alias ELFDATA = ELFDATA2LSB; } else version(BigEndian) { alias ELFDATA = ELFDATA2MSB; } else { static assert(0, "unsupported byte order"); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/backtrace/dwarf.d0000664000175000017500000004335012776214756022073 0ustar kaikai/** * This code handles backtrace generation using dwarf .debug_line section * in ELF files for linux. * * Reference: http://www.dwarfstd.org/ * * Copyright: Copyright Digital Mars 2015 - 2015. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Yazan Dabain, Sean Kelly * Source: $(DRUNTIMESRC src/rt/backtrace/dwarf.d) */ module rt.backtrace.dwarf; version(CRuntime_Glibc) version = linux_or_freebsd; else version(FreeBSD) version = linux_or_freebsd; version(linux_or_freebsd): import rt.util.container.array; import rt.backtrace.elf; import core.stdc.string : strlen, memchr; //debug = DwarfDebugMachine; struct Location { const(char)[] file = null; // file is missing directory, but DMD emits directory directly into file int line = -1; size_t address; } int traceHandlerOpApplyImpl(const void*[] callstack, scope int delegate(ref size_t, ref const(char[])) dg) { import core.stdc.stdio : snprintf; version(linux) import core.sys.linux.execinfo : backtrace_symbols; else version(FreeBSD) import core.sys.freebsd.execinfo : backtrace_symbols; import core.sys.posix.stdlib : free; const char** frameList = backtrace_symbols(callstack.ptr, cast(int) callstack.length); scope(exit) free(cast(void*) frameList); // find address -> file, line mapping using dwarf debug_line ElfFile file; ElfSection dbgSection; Array!Location locations; if (ElfFile.openSelf(&file)) { auto stringSectionHeader = ElfSectionHeader(&file, file.ehdr.e_shstrndx); auto stringSection = ElfSection(&file, &stringSectionHeader); auto dbgSectionIndex = findSectionByName(&file, &stringSection, ".debug_line"); if (dbgSectionIndex != -1) { auto dbgSectionHeader = ElfSectionHeader(&file, dbgSectionIndex); dbgSection = ElfSection(&file, &dbgSectionHeader); // debug_line section found and loaded // resolve addresses locations.length = callstack.length; foreach(size_t i; 0 .. callstack.length) locations[i].address = cast(size_t) callstack[i]; resolveAddresses(&dbgSection, locations[]); } } int ret = 0; foreach (size_t i; 0 .. callstack.length) { char[1536] buffer = void; buffer[0] = 0; char[256] addressBuffer = void; addressBuffer[0] = 0; if (locations.length > 0 && locations[i].line != -1) snprintf(addressBuffer.ptr, addressBuffer.length, "%.*s:%d ", cast(int) locations[i].file.length, locations[i].file.ptr, locations[i].line); else addressBuffer[] = "??:? \0"; char[1024] symbolBuffer = void; int bufferLength; auto symbol = getDemangledSymbol(frameList[i][0 .. strlen(frameList[i])], symbolBuffer); if (symbol.length > 0) bufferLength = snprintf(buffer.ptr, buffer.length, "%s%.*s [0x%x]", addressBuffer.ptr, cast(int) symbol.length, symbol.ptr, callstack[i]); else bufferLength = snprintf(buffer.ptr, buffer.length, "%s[0x%x]", addressBuffer.ptr, callstack[i]); assert(bufferLength >= 0); auto output = buffer[0 .. bufferLength]; auto pos = i; ret = dg(pos, output); if (ret) break; } return ret; } private: // the lifetime of the Location data is the lifetime of the mmapped ElfSection void resolveAddresses(ElfSection* debugLineSection, Location[] locations) @nogc nothrow { debug(DwarfDebugMachine) import core.stdc.stdio; size_t numberOfLocationsFound = 0; const(ubyte)[] dbg = debugLineSection.get(); while (dbg.length > 0) { debug(DwarfDebugMachine) printf("new debug program\n"); const(LPHeader)* lph = cast(const(LPHeader)*) dbg.ptr; if (lph.unitLength == 0xffff_ffff) // is 64-bit dwarf? return; // unable to read 64-bit dwarf const(ubyte)[] program = dbg[ lph.headerLength + LPHeader.minimumInstructionLength.offsetof .. lph.unitLength + LPHeader.dwarfVersion.offsetof ]; const(ubyte)[] standardOpcodeLengths = dbg[ LPHeader.sizeof .. LPHeader.sizeof + lph.opcodeBase - 1 ]; const(ubyte)[] pathData = dbg[ LPHeader.sizeof + lph.opcodeBase - 1 .. $ ]; Array!(const(char)[]) directories; directories.length = (const(ubyte)[] bytes) { // count number of directories int count = 0; foreach (i; 0 .. bytes.length - 1) { if (bytes[i] == 0) { count++; if (bytes[i + 1] == 0) return count; } } return count; }(pathData); // fill directories array from dwarf section int currentDirectoryIndex = 0; while (pathData[0] != 0) { directories[currentDirectoryIndex] = cast(const(char)[]) pathData[0 .. strlen(cast(char*) (pathData.ptr))]; debug(DwarfDebugMachine) printf("dir: %s\n", pathData.ptr); pathData = pathData[directories[currentDirectoryIndex].length + 1 .. $]; currentDirectoryIndex++; } pathData = pathData[1 .. $]; Array!(const(char)[]) filenames; filenames.length = (const(ubyte)[] bytes) { // count number of files int count = 0; while (bytes[0] != 0) { auto filename = cast(const(char)[]) bytes[0 .. strlen(cast(char*) (bytes.ptr))]; bytes = bytes[filename.length + 1 .. $]; bytes.readULEB128(); // dir index bytes.readULEB128(); // last mod bytes.readULEB128(); // file len count++; } return count; }(pathData); // fill filenames array from dwarf section int currentFileIndex = 0; while (pathData[0] != 0) { filenames[currentFileIndex] = cast(const(char)[]) pathData[0 .. strlen(cast(char*) (pathData.ptr))]; debug(DwarfDebugMachine) printf("file: %s\n", pathData.ptr); pathData = pathData[filenames[currentFileIndex].length + 1 .. $]; auto dirIndex = pathData.readULEB128(); // unused auto lastMod = pathData.readULEB128(); // unused auto fileLen = pathData.readULEB128(); // unused currentFileIndex++; } LocationInfo lastLoc = LocationInfo(-1, -1); size_t lastAddress = 0x0; debug(DwarfDebugMachine) printf("program:\n"); runStateMachine(lph, program, standardOpcodeLengths, (size_t address, LocationInfo locInfo, bool isEndSequence) { // If loc.line != -1, then it has been set previously. // Some implementations (eg. dmd) write an address to // the debug data multiple times, but so far I have found // that the first occurrence to be the correct one. foreach (ref loc; locations) if (loc.line == -1) { if (loc.address == address) { debug(DwarfDebugMachine) printf("-- found for [0x%x]:\n", loc.address); debug(DwarfDebugMachine) printf("-- file: %.*s\n", filenames[locInfo.file - 1].length, filenames[locInfo.file - 1].ptr); debug(DwarfDebugMachine) printf("-- line: %d\n", locInfo.line); loc.file = filenames[locInfo.file - 1]; loc.line = locInfo.line; numberOfLocationsFound++; } else if (loc.address < address && lastAddress < loc.address && lastAddress != 0) { debug(DwarfDebugMachine) printf("-- found for [0x%x]:\n", loc.address); debug(DwarfDebugMachine) printf("-- file: %.*s\n", filenames[lastLoc.file - 1].length, filenames[lastLoc.file - 1].ptr); debug(DwarfDebugMachine) printf("-- line: %d\n", lastLoc.line); loc.file = filenames[lastLoc.file - 1]; loc.line = lastLoc.line; numberOfLocationsFound++; } } if (isEndSequence) { lastAddress = 0; } else { lastAddress = address; lastLoc = locInfo; } return numberOfLocationsFound < locations.length; } ); if (numberOfLocationsFound == locations.length) return; dbg = dbg[lph.unitLength + LPHeader.dwarfVersion.offsetof .. $]; } } alias RunStateMachineCallback = bool delegate(size_t, LocationInfo, bool) @nogc nothrow; bool runStateMachine(const(LPHeader)* lpHeader, const(ubyte)[] program, const(ubyte)[] standardOpcodeLengths, scope RunStateMachineCallback callback) @nogc nothrow { debug(DwarfDebugMachine) import core.stdc.stdio; StateMachine machine; machine.isStatement = lpHeader.defaultIsStatement; while (program.length > 0) { ubyte opcode = program.read!ubyte(); if (opcode < lpHeader.opcodeBase) { switch (opcode) with (StandardOpcode) { case extendedOp: size_t len = cast(size_t) program.readULEB128(); ubyte eopcode = program.read!ubyte(); switch (eopcode) with (ExtendedOpcode) { case endSequence: machine.isEndSequence = true; debug(DwarfDebugMachine) printf("endSequence 0x%x\n", machine.address); if (!callback(machine.address, LocationInfo(machine.fileIndex, machine.line), true)) return true; machine = StateMachine.init; machine.isStatement = lpHeader.defaultIsStatement; break; case setAddress: size_t address = program.read!size_t(); debug(DwarfDebugMachine) printf("setAddress 0x%x\n", address); machine.address = address; break; case defineFile: // TODO: add proper implementation debug(DwarfDebugMachine) printf("defineFile\n"); program = program[len - 1 .. $]; break; default: // unknown opcode debug(DwarfDebugMachine) printf("unknown extended opcode %d\n", cast(int) eopcode); program = program[len - 1 .. $]; break; } break; case copy: debug(DwarfDebugMachine) printf("copy 0x%x\n", machine.address); if (!callback(machine.address, LocationInfo(machine.fileIndex, machine.line), false)) return true; machine.isBasicBlock = false; machine.isPrologueEnd = false; machine.isEpilogueBegin = false; break; case advancePC: ulong op = readULEB128(program); machine.address += op * lpHeader.minimumInstructionLength; debug(DwarfDebugMachine) printf("advancePC %d to 0x%x\n", cast(int) (op * lpHeader.minimumInstructionLength), machine.address); break; case advanceLine: long ad = readSLEB128(program); machine.line += ad; debug(DwarfDebugMachine) printf("advanceLine %d to %d\n", cast(int) ad, cast(int) machine.line); break; case setFile: uint index = cast(uint) readULEB128(program); debug(DwarfDebugMachine) printf("setFile to %d\n", cast(int) index); machine.fileIndex = index; break; case setColumn: uint col = cast(uint) readULEB128(program); debug(DwarfDebugMachine) printf("setColumn %d\n", cast(int) col); machine.column = col; break; case negateStatement: debug(DwarfDebugMachine) printf("negateStatement\n"); machine.isStatement = !machine.isStatement; break; case setBasicBlock: debug(DwarfDebugMachine) printf("setBasicBlock\n"); machine.isBasicBlock = true; break; case constAddPC: machine.address += (255 - lpHeader.opcodeBase) / lpHeader.lineRange * lpHeader.minimumInstructionLength; debug(DwarfDebugMachine) printf("constAddPC 0x%x\n", machine.address); break; case fixedAdvancePC: uint add = program.read!uint(); machine.address += add; debug(DwarfDebugMachine) printf("fixedAdvancePC %d to 0x%x\n", cast(int) add, machine.address); break; case setPrologueEnd: machine.isPrologueEnd = true; debug(DwarfDebugMachine) printf("setPrologueEnd\n"); break; case setEpilogueBegin: machine.isEpilogueBegin = true; debug(DwarfDebugMachine) printf("setEpilogueBegin\n"); break; case setISA: machine.isa = cast(uint) readULEB128(program); debug(DwarfDebugMachine) printf("setISA %d\n", cast(int) machine.isa); break; default: // unimplemented/invalid opcode return false; } } else { opcode -= lpHeader.opcodeBase; auto ainc = (opcode / lpHeader.lineRange) * lpHeader.minimumInstructionLength; machine.address += ainc; auto linc = lpHeader.lineBase + (opcode % lpHeader.lineRange); machine.line += linc; debug(DwarfDebugMachine) printf("special %d %d to 0x%x line %d\n", cast(int) ainc, cast(int) linc, machine.address, cast(int) machine.line); if (!callback(machine.address, LocationInfo(machine.fileIndex, machine.line), false)) return true; } } return true; } const(char)[] getDemangledSymbol(const(char)[] btSymbol, ref char[1024] buffer) { version(linux) { // format is: module(_D6module4funcAFZv) [0x00000000] // or: module(_D6module4funcAFZv+0x78) [0x00000000] auto bptr = cast(char*) memchr(btSymbol.ptr, '(', btSymbol.length); auto eptr = cast(char*) memchr(btSymbol.ptr, ')', btSymbol.length); auto pptr = cast(char*) memchr(btSymbol.ptr, '+', btSymbol.length); } else version(FreeBSD) { // format is: 0x00000000 <_D6module4funcAFZv+0x78> at module auto bptr = cast(char*) memchr(btSymbol.ptr, '<', btSymbol.length); auto eptr = cast(char*) memchr(btSymbol.ptr, '>', btSymbol.length); auto pptr = cast(char*) memchr(btSymbol.ptr, '+', btSymbol.length); } if (pptr && pptr < eptr) eptr = pptr; size_t symBeg, symEnd; if (bptr++ && eptr) { symBeg = bptr - btSymbol.ptr; symEnd = eptr - btSymbol.ptr; } assert(symBeg <= symEnd); assert(symEnd < btSymbol.length); import core.demangle; return demangle(btSymbol[symBeg .. symEnd], buffer[]); } T read(T)(ref const(ubyte)[] buffer) @nogc nothrow { T result = *(cast(T*) buffer[0 .. T.sizeof].ptr); buffer = buffer[T.sizeof .. $]; return result; } ulong readULEB128(ref const(ubyte)[] buffer) @nogc nothrow { ulong val = 0; uint shift = 0; while (true) { ubyte b = buffer.read!ubyte(); val |= (b & 0x7f) << shift; if ((b & 0x80) == 0) break; shift += 7; } return val; } unittest { const(ubyte)[] data = [0xe5, 0x8e, 0x26, 0xDE, 0xAD, 0xBE, 0xEF]; assert(readULEB128(data) == 624_485); assert(data[] == [0xDE, 0xAD, 0xBE, 0xEF]); } long readSLEB128(ref const(ubyte)[] buffer) @nogc nothrow { long val = 0; uint shift = 0; int size = 8 << 3; ubyte b; while (true) { b = buffer.read!ubyte(); val |= (b & 0x7f) << shift; shift += 7; if ((b & 0x80) == 0) break; } if (shift < size && (b & 0x40) != 0) val |= -(1 << shift); return val; } enum StandardOpcode : ubyte { extendedOp = 0, copy = 1, advancePC = 2, advanceLine = 3, setFile = 4, setColumn = 5, negateStatement = 6, setBasicBlock = 7, constAddPC = 8, fixedAdvancePC = 9, setPrologueEnd = 10, setEpilogueBegin = 11, setISA = 12, } enum ExtendedOpcode : ubyte { endSequence = 1, setAddress = 2, defineFile = 3, } struct StateMachine { size_t address = 0; uint operationIndex = 0; uint fileIndex = 1; uint line = 1; uint column = 0; bool isStatement; bool isBasicBlock = false; bool isEndSequence = false; bool isPrologueEnd = false; bool isEpilogueBegin = false; uint isa = 0; uint discriminator = 0; } struct LocationInfo { int file; int line; } // 32-bit DWARF align(1) struct LPHeader { align(1): uint unitLength; ushort dwarfVersion; uint headerLength; ubyte minimumInstructionLength; bool defaultIsStatement; byte lineBase; ubyte lineRange; ubyte opcodeBase; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/cast_.d0000664000175000017500000000652212776214756020142 0ustar kaikai/** * Implementation of array assignment support routines. * * Copyright: Copyright Digital Mars 2004 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2004 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.cast_; extern (C): /****************************************** * Given a pointer: * If it is an Object, return that Object. * If it is an interface, return the Object implementing the interface. * If it is null, return null. * Else, undefined crash */ Object _d_toObject(void* p) { if (!p) return null; Object o = cast(Object) p; ClassInfo oc = typeid(o); Interface* pi = **cast(Interface***) p; /* Interface.offset lines up with ClassInfo.name.ptr, * so we rely on pointers never being less than 64K, * and Objects never being greater. */ if (pi.offset < 0x10000) { debug(cast_) printf("\tpi.offset = %d\n", pi.offset); return cast(Object)(p - pi.offset); } return o; } /************************************* * Attempts to cast Object o to class c. * Returns o if successful, null if not. */ void* _d_interface_cast(void* p, ClassInfo c) { debug(cast_) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name); if (!p) return null; Interface* pi = **cast(Interface***) p; debug(cast_) printf("\tpi.offset = %d\n", pi.offset); return _d_dynamic_cast(cast(Object)(p - pi.offset), c); } void* _d_dynamic_cast(Object o, ClassInfo c) { debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name); void* res = null; size_t offset = 0; if (o && _d_isbaseof2(typeid(o), c, offset)) { debug(cast_) printf("\toffset = %d\n", offset); res = cast(void*) o + offset; } debug(cast_) printf("\tresult = %p\n", res); return res; } int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset) { if (oc is c) return true; do { if (oc.base is c) return true; // Bugzilla 2013: Use depth-first search to calculate offset // from the derived (oc) to the base (c). foreach (iface; oc.interfaces) { if (iface.classinfo is c || _d_isbaseof2(iface.classinfo, c, offset)) { offset += iface.offset; return true; } } oc = oc.base; } while(oc); return false; } int _d_isbaseof(ClassInfo oc, ClassInfo c) { if (oc is c) return true; do { if (oc.base is c) return true; foreach (iface; oc.interfaces) { if (iface.classinfo is c || _d_isbaseof(iface.classinfo, c)) return true; } oc = oc.base; } while(oc); return false; } /********************************* * Find the vtbl[] associated with Interface ic. */ void* _d_interface_vtbl(ClassInfo ic, Object o) { debug(cast_) printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic); assert(o); foreach (iface; typeid(o).interfaces) { if (iface.classinfo is ic) return cast(void*) iface.vtbl; } assert(0); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/config.d0000664000175000017500000001131412776214756020311 0ustar kaikai/** * Configuration options for druntime * * Copyright: Copyright Digital Mars 2014. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Rainer Schuetze * Source: $(DRUNTIMESRC src/rt/_config.d) */ module rt.config; // The default way to configure the runtime is by passing command line arguments // starting with "--DRT-" and followed by the option name, e.g. "--DRT-gcopt" to // configure the GC. // Command line options starting with "--DRT-" are filtered out before calling main, // so the program will not see them. They are still available via rt_args(). // // Configuration via the command line can be disabled by declaring a variable for the // linker to pick up before using it's default from the runtime: // // extern(C) __gshared bool rt_cmdline_enabled = false; // // Likewise, declare a boolean rt_envvars_enabled to enable configuration via the // environment variable "DRT_" followed by the option name, e.g. "DRT_GCOPT": // // extern(C) __gshared bool rt_envvars_enabled = true; // // Setting default configuration properties in the executable can be done by specifying an // array of options named rt_options: // // extern(C) __gshared string[] rt_options = [ "gcopt=precise:1 profile:1"]; // // Evaluation order of options is rt_options, then environment variables, then command // line arguments, i.e. if command line arguments are not disabled, they can override // options specified through the environment or embedded in the executable. import core.demangle : cPrefix; // put each variable in its own COMDAT by making them template instances template rt_envvars_enabled() { pragma(mangle, cPrefix ~ "rt_envvars_enabled") __gshared bool rt_envvars_enabled = false; } template rt_cmdline_enabled() { pragma(mangle, cPrefix ~ "rt_cmdline_enabled") __gshared bool rt_cmdline_enabled = true; } template rt_options() { pragma(mangle, cPrefix ~ "rt_options") __gshared string[] rt_options = []; } import core.stdc.ctype : toupper; import core.stdc.stdlib : getenv; import core.stdc.string : strlen; extern extern(C) string[] rt_args() @nogc nothrow; alias rt_configCallBack = string delegate(string) @nogc nothrow; /** * get a druntime config option using standard configuration options * opt name of the option to retreive * dg if non-null, passes the option through this * delegate and only returns its return value if non-null * reverse reverse the default processing order cmdline/envvar/rt_options * to allow overwriting settings in the delegate with values * from higher priority * * returns the options' value if * - set on the command line as "--DRT-=value" (rt_cmdline_enabled enabled) * - the environment variable "DRT_" is set (rt_envvars_enabled enabled) * - rt_options[] contains an entry "=value" * - null otherwise */ string rt_configOption(string opt, scope rt_configCallBack dg = null, bool reverse = false) @nogc nothrow { if (!dg) dg = (string s) => s; string s = (reverse ? rt_linkOption(opt, dg) : rt_cmdlineOption(opt, dg)); if (s != null) return s; s = rt_envvarsOption(opt, dg); if (s != null) return s; s = (reverse ? rt_cmdlineOption(opt, dg) : rt_linkOption(opt, dg)); return s; } string rt_cmdlineOption(string opt, scope rt_configCallBack dg) @nogc nothrow { if(rt_cmdline_enabled!()) { foreach (a; rt_args) { if (a.length >= opt.length + 7 && a[0..6] == "--DRT-" && a[6 .. 6 + opt.length] == opt && a[6 + opt.length] == '=') { string s = dg(a[7 + opt.length .. $]); if (s != null) return s; } } } return null; } string rt_envvarsOption(string opt, scope rt_configCallBack dg) @nogc nothrow { if(rt_envvars_enabled!()) { if (opt.length >= 32) assert(0); char[40] var; var[0 .. 4] = "DRT_"; foreach (i, c; opt) var[4 + i] = cast(char) toupper(c); var[4 + opt.length] = 0; auto p = getenv(var.ptr); if (p) { string s = dg(cast(string) p[0 .. strlen(p)]); if (s != null) return s; } } return null; } string rt_linkOption(string opt, scope rt_configCallBack dg) @nogc nothrow { foreach (a; rt_options!()) { if(a.length > opt.length && a[0..opt.length] == opt && a[opt.length] == '=') { string s = dg(a[opt.length + 1 .. $]); if (s != null) return s; } } return null; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/sections_ldc.d0000664000175000017500000003472612776214756021531 0ustar kaikai/** * This module provides support for the legacy _Dmodule_ref-based ModuleInfo * discovery mechanism. Multiple images (i.e. shared libraries) are not handled * at all. * * It is expected to fade away as work on the compiler-provided functionality * required for proper shared library support continues. * * Copyright: Copyright David Nadlinger 2013. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: David Nadlinger, Martin Nowak * Source: $(DRUNTIMESRC src/rt/_sections_win64.d) */ module rt.sections_ldc; version (linux) {} else version (FreeBSD) {} else version(LDC): import core.stdc.stdlib : alloca; import rt.minfo; debug(PRINTF) import core.stdc.stdio : printf; version (Solaris) { version = UseELF; import core.sys.solaris.link; import core.sys.solaris.sys.elf; } alias SectionGroup DSO; struct SectionGroup { static int opApply(scope int delegate(ref SectionGroup) dg) { return dg(globalSectionGroup); } static int opApplyReverse(scope int delegate(ref SectionGroup) dg) { return dg(globalSectionGroup); } @property immutable(ModuleInfo*)[] modules() const { return _moduleGroup.modules; } @property ref inout(ModuleGroup) moduleGroup() inout { return _moduleGroup; } @property inout(void[])[] gcRanges() inout { return _gcRanges[]; } private: ModuleGroup _moduleGroup; import rt.util.container.array; Array!(void[]) _gcRanges; version(Solaris) { size_t _tlsSize; } else version(UseELF) { size_t _tlsMod; size_t _tlsSize; } } private __gshared SectionGroup globalSectionGroup; private { version (OSX) { import core.sys.osx.mach.dyld; import core.sys.osx.mach.getsect; import core.sys.osx.mach.loader; struct Section { immutable(char)* segment; immutable(char)* section; } immutable Section[3] dataSections = [ Section(SEG_DATA, SECT_DATA), Section(SEG_DATA, SECT_BSS), Section(SEG_DATA, SECT_COMMON) ]; } else version (CRuntime_Microsoft) { extern extern (C) __gshared { void* _data_start__; void* _data_end__; void* _bss_start__; void* _bss_end__; } } else version (Windows) { extern extern (C) __gshared { int _data_start__; int _bss_end__; } } else version (UseELF) { /************ * Scan segments in Linux dl_phdr_info struct and store * the TLS and writeable data segments in *pdso. */ void scanSegments(in ref dl_phdr_info info, DSO* pdso) { foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) { switch (phdr.p_type) { case PT_LOAD: if (phdr.p_flags & PF_W) // writeable data segment { auto beg = cast(void*)(info.dlpi_addr + phdr.p_vaddr); pdso._gcRanges.insertBack(beg[0 .. phdr.p_memsz]); } break; case PT_TLS: // TLS segment assert(!pdso._tlsSize); // is unique per DSO version(Solaris) { pdso._tlsSize = phdr.p_memsz; } else { pdso._tlsMod = info.dlpi_tls_modid; pdso._tlsSize = phdr.p_memsz; } break; default: break; } } } nothrow bool findPhdrForAddr(in void* addr, dl_phdr_info* result=null) { static struct DG { const(void)* addr; dl_phdr_info* result; } extern(C) nothrow int callback(dl_phdr_info* info, size_t sz, void* arg) { auto p = cast(DG*)arg; if (findSegmentForAddr(*info, p.addr)) { if (p.result !is null) *p.result = *info; return 1; // break; } return 0; // continue iteration } auto dg = DG(addr, result); return dl_iterate_phdr(&callback, &dg) != 0; } nothrow bool findSegmentForAddr(in ref dl_phdr_info info, in void* addr, ElfW!"Phdr"* result=null) { if (addr < cast(void*)info.dlpi_addr) // quick reject return false; foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) { auto beg = cast(void*)(info.dlpi_addr + phdr.p_vaddr); if (cast(size_t)(addr - beg) < phdr.p_memsz) { if (result !is null) *result = phdr; return true; } } return false; } version(Solaris) { /* Solaris does not support the dl_phdr_info.dlpi_tls_modid field. * The static TLS range is placed immediately preceding the thread * pointer. Accesses to this TLS data is based off of subtractions * from the current thread pointer. * See: https://docs.oracle.com/cd/E26502_01/html/E26507/gentextid-23191.html#chapter8-7 */ /* * The following data structures are private to libc. They are not * required for the implementation but they help in debugging this * stuff. */ struct mutex_t { ubyte[24] __fill; } struct tls_t { void* tls_data; size_t tls_size; } struct tls_metadata_t { mutex_t tls_lock; tls_t tls_modinfo; tls_t static_tls; byte[64 - mutex_t.sizeof -2 * tls_t.sizeof] tls_pad; } struct uberdata_t { byte[10496] __fill; tls_metadata_t tls_metadata; /* incomplete */ } struct ulwp_t { version(SPARC) { uint ul_dinstr; uint[15] ul_padsparc0; uint ul_dsave; uint ul_drestore; uint ul_dftret; uint ul_dreturn; } version(SPARC64) { uint ul_dinstr; uint[15] ul_padsparc0; uint ul_dsave; uint ul_drestore; uint ul_dftret; uint ul_dreturn; } ulwp_t* ul_self; version (D_LP64) ubyte[56] ul_dinstr; else ubyte[40] ul_dinstr; uberdata_t* ul_uberdata; tls_t ul_tls; ulwp_t* ul_forw; ulwp_t* ul_back; ulwp_t* ul_next; ulwp_t* ul_hash; void* ul_rval; /* incomplete */ } // Return the current thread pointer. private ulwp_t* curthread() nothrow { import ldc.llvmasm; version (X86_64) { return __asm!(ulwp_t*)("movq %fs:0, $0", "=r"); } else version (X86) { return __asm!(ulwp_t*)("movl %gs:0, $0", "=r"); } else { static assert(0, "TLS range detection not implemented on Solaris for this architecture."); } } // See: http://src.illumos.org/source/xref/illumos-gate/usr/src/cmd/sgs/include/i386/machdep_x86.h#102 version (D_LP64) enum M_TLSSTATALIGN = 0x10; else enum M_TLSSTATALIGN = 0x08; void[] getTLSRange(DSO* pdso) { // See: http://src.illumos.org/source/xref/illumos-gate/usr/src/cmd/sgs/libld/common/machrel.intel.c#996 // tlsstatsize = S_ROUND(ofl->ofl_tlsphdr->p_memsz, M_TLSSTATALIGN); void* thptr = curthread(); size_t sz = (pdso._tlsSize + (M_TLSSTATALIGN-1) + 512) & ~(M_TLSSTATALIGN-1); return (thptr - sz)[0 .. sz]; } } else { struct tls_index { size_t ti_module; size_t ti_offset; } extern(C) void* __tls_get_addr(tls_index* ti); /* The dynamic thread vector (DTV) pointers may point 0x8000 past the start of * each TLS block. This is at least true for PowerPC and Mips platforms. */ version(PPC) enum TLS_DTV_OFFSET = 0x8000; else version(PPC64) enum TLS_DTV_OFFSET = 0x8000; else version(MIPS) enum TLS_DTV_OFFSET = 0x8000; else version(MIPS64) enum TLS_DTV_OFFSET = 0x8000; else enum TLS_DTV_OFFSET = 0x; void[] getTLSRange(DSO* pdso) { if (pdso._tlsMod == 0) return null; auto ti = tls_index(pdso._tlsMod, 0); return (__tls_get_addr(&ti)-TLS_DTV_OFFSET)[0 .. pdso._tlsSize]; } } } } /**** * Gets called on program startup just before GC is initialized. */ void initSections() { debug(PRINTF) printf("initSections called\n"); globalSectionGroup.moduleGroup = ModuleGroup(getModuleInfos()); static void pushRange(void* start, void* end) { globalSectionGroup._gcRanges.insertBack(start[0 .. (end - start)]); } version (OSX) { static extern(C) void scanSections(in mach_header* hdr, ptrdiff_t slide) { foreach (s; dataSections) { // Should probably be decided at runtime by actual image bitness // (mach_header.magic) rather than at build-time? version (D_LP64) auto sec = getsectbynamefromheader_64( cast(mach_header_64*)hdr, s.segment, s.section); else auto sec = getsectbynamefromheader(hdr, s.segment, s.section); if (sec == null || sec.size == 0) continue; globalSectionGroup._gcRanges.insertBack( (cast(void*)(sec.addr + slide))[0 .. sec.size]); } } _dyld_register_func_for_add_image(&scanSections); } else version (CRuntime_Microsoft) { pushRange(_data_start__, _data_end__); if (_bss_start__ != null) { pushRange(_bss_start__, _bss_end__); } } else version (Windows) { pushRange(&_data_start__, &_bss_end__); } else version (UseELF) { dl_phdr_info phdr = void; findPhdrForAddr(&globalSectionGroup, &phdr) || assert(0); scanSegments(phdr, &globalSectionGroup); } } /*** * Gets called on program shutdown just after GC is terminated. */ void finiSections() { debug(PRINTF) printf("finiSections called\n"); import core.stdc.stdlib : free; free(cast(void*)globalSectionGroup.modules.ptr); } private { version (OSX) { extern(C) void _d_dyld_getTLSRange(void*, void**, size_t*); private align(16) ubyte dummyTlsSymbol = 42; // By initalizing dummyTlsSymbol with something non-zero and aligning // to 16-bytes, section __thread_data will be aligned as a workaround // for https://github.com/ldc-developers/ldc/issues/1252 } else version (Windows) { extern(C) extern { int _tls_start; int _tls_end; } } } /*** * Called once per thread; returns array of thread local storage ranges */ void[] initTLSRanges() { debug(PRINTF) printf("initTLSRanges called\n"); version (OSX) { void* start = null; size_t size = 0; _d_dyld_getTLSRange(&dummyTlsSymbol, &start, &size); assert(start && size, "Could not determine TLS range."); return start[0 .. size]; } else version (linux) { // glibc allocates the TLS area for each new thread at the stack of // the stack, so we only need to do something for the main thread. return null; } else version (UseELF) { auto rng = getTLSRange(&globalSectionGroup); debug(PRINTF) printf("Add range %p %d\n", rng ? rng.ptr : cast(void*)0, rng ? rng.length : 0); return rng; } else version (Windows) { auto pbeg = cast(void*)&_tls_start; auto pend = cast(void*)&_tls_end; return pbeg[0 .. pend - pbeg]; } else static assert(0, "TLS range detection not implemented for this OS."); } void finiTLSRanges(void[] rng) { debug(PRINTF) printf("finiTLSRanges called\n"); } void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow { debug(PRINTF) printf("scanTLSRanges called (rng = %p %d)\n", rng ? rng.ptr : cast(void*)0, rng ? rng.length : 0); if (rng) dg(rng.ptr, rng.ptr + rng.length); } extern (C) __gshared ModuleReference* _Dmodule_ref; // start of linked list private: // This linked list is created by a compiler generated function inserted // into the .ctor list by the compiler. struct ModuleReference { ModuleReference* next; immutable(ModuleInfo)* mod; } immutable(ModuleInfo*)[] getModuleInfos() out (result) { foreach(m; result) assert(m !is null); } body { import core.stdc.stdlib : malloc; size_t len = 0; for (auto mr = _Dmodule_ref; mr; mr = mr.next) len++; auto result = (cast(immutable(ModuleInfo)**)malloc(len * size_t.sizeof))[0 .. len]; auto tip = _Dmodule_ref; foreach (ref r; result) { r = tip.mod; tip = tip.next; } return cast(immutable)result; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/critical_.d0000664000175000017500000000301412776214756020773 0ustar kaikai/** * Implementation of support routines for synchronized blocks. * * Copyright: Copyright Digital Mars 2000 - 2011. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2000 - 2011. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.critical_; nothrow: import rt.monitor_, core.atomic; extern (C) void _d_critical_init() { initMutex(cast(Mutex*)&gcs.mtx); head = &gcs; } extern (C) void _d_critical_term() { for (auto p = head; p; p = p.next) destroyMutex(cast(Mutex*)&p.mtx); } extern (C) void _d_criticalenter(D_CRITICAL_SECTION* cs) { ensureMutex(cast(shared(D_CRITICAL_SECTION*)) cs); lockMutex(&cs.mtx); } extern (C) void _d_criticalexit(D_CRITICAL_SECTION* cs) { unlockMutex(&cs.mtx); } private: shared D_CRITICAL_SECTION* head; shared D_CRITICAL_SECTION gcs; struct D_CRITICAL_SECTION { D_CRITICAL_SECTION* next; Mutex mtx; } void ensureMutex(shared(D_CRITICAL_SECTION)* cs) { if (atomicLoad!(MemoryOrder.acq)(cs.next) is null) { lockMutex(cast(Mutex*)&gcs.mtx); if (atomicLoad!(MemoryOrder.raw)(cs.next) is null) { initMutex(cast(Mutex*)&cs.mtx); auto ohead = head; head = cs; atomicStore!(MemoryOrder.rel)(cs.next, ohead); } unlockMutex(cast(Mutex*)&gcs.mtx); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/arrayint.d0000664000175000017500000030667112776214756020712 0ustar kaikai/** * Contains SSE/MMX versions of certain operations for dchar, int, and uint ('w', * 'i' and 'k' suffixes). * * Copyright: Copyright Digital Mars 2008 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, based on code originally written by Burton Radons */ /* Copyright Digital Mars 2008 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.arrayint; // debug=PRINTF private import core.cpuid; import rt.util.array; version (unittest) { private import core.stdc.stdio : printf; /* This is so unit tests will test every CPU variant */ uint cpuid; enum CPUID_MAX = 14; nothrow: @property bool mmx() { return cpuid == 1 && core.cpuid.mmx; } @property bool sse() { return cpuid == 2 && core.cpuid.sse; } @property bool sse2() { return cpuid == 3 && core.cpuid.sse2; } @property bool sse3() { return cpuid == 4 && core.cpuid.sse3; } @property bool sse41() { return cpuid == 5 && core.cpuid.sse41; } @property bool sse42() { return cpuid == 6 && core.cpuid.sse42; } @property bool sse4a() { return cpuid == 7 && core.cpuid.sse4a; } @property bool avx() { return cpuid == 8 && core.cpuid.avx; } @property bool avx2() { return cpuid == 9 && core.cpuid.avx2; } @property bool amd3dnow() { return cpuid == 10 && core.cpuid.amd3dnow; } @property bool and3dnowExt() { return cpuid == 11 && core.cpuid.amd3dnowExt; } @property bool amdMmx() { return cpuid == 12 && core.cpuid.amdMmx; } @property bool has3dnowPrefetch() { return cpuid == 13 && core.cpuid.has3dnowPrefetch; } } else { version(X86_64) //guaranteed on x86_64 { enum mmx = true; enum sse = true; enum sse2 = true; } else { alias core.cpuid.mmx mmx; alias core.cpuid.sse sse; alias core.cpuid.sse2 sse2; } alias core.cpuid.sse3 sse3; alias core.cpuid.sse41 sse41; alias core.cpuid.sse42 sse42; alias core.cpuid.sse4a sse4a; alias core.cpuid.avx avx; alias core.cpuid.avx2 avx2; alias core.cpuid.amd3dnow amd3dnow; alias core.cpuid.amd3dnowExt and3dnowExt; alias core.cpuid.amdMmx amdMmx; alias core.cpuid.has3dnowPrefetch has3dnowPrefetch; } //version = log; alias int T; extern (C) @trusted nothrow: /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + value */ T[] _arraySliceExpAddSliceAssign_w(T[] a, T value, T[] b) { return _arraySliceExpAddSliceAssign_i(a, value, b); } T[] _arraySliceExpAddSliceAssign_k(T[] a, T value, T[] b) { return _arraySliceExpAddSliceAssign_i(a, value, b); } T[] _arraySliceExpAddSliceAssign_i(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceExpAddSliceAssign_i()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 380% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2,value; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add EAX, 32; paddd XMM0, XMM2; paddd XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add EAX, 32; paddd XMM0, XMM2; paddd XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; mov bptr, EAX; } } } // MMX version is 298% faster else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | ((cast(ulong)cast(uint) value) << 32); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movq MM2, l; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM1, [EAX+8]; add EAX, 16; paddd MM0, MM2; paddd MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; } } } version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM1, [RAX+16]; add RAX, 32; paddd XMM0, XMM2; paddd XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; mov bptr, RAX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2,value; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM1, [RAX+16]; add RAX, 32; paddd XMM0, XMM2; paddd XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; mov bptr, RAX; } } } else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | ((cast(ulong)cast(uint) value) << 32); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movq MM2, l; align 4; startmmx: add RSI, 16; movq MM0, [RAX]; movq MM1, [RAX+8]; add RAX, 16; paddd MM0, MM2; paddd MM1, MM2; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; mov bptr, RAX; } } } while (aptr < aend) *aptr++ = *bptr++ + value; return a; } unittest { debug(PRINTF) printf("_arraySliceExpAddSliceAssign_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); c[i] = cast(T)((i-10) * 2); } c[] = a[] + 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + 6)) { printf("[%d]: %d != %d + 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + c[] */ T[] _arraySliceSliceAddSliceAssign_w(T[] a, T[] c, T[] b) { return _arraySliceSliceAddSliceAssign_i(a, c, b); } T[] _arraySliceSliceAddSliceAssign_k(T[] a, T[] c, T[] b) { return _arraySliceSliceAddSliceAssign_i(a, c, b); } T[] _arraySliceSliceAddSliceAssign_i(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); //printf("_arraySliceSliceAddSliceAssign_i()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 1710% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr | cast(size_t) cptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM2, [ECX]; movdqu XMM1, [EAX+16]; movdqu XMM3, [ECX+16]; add EAX, 32; add ECX, 32; paddd XMM0, XMM2; paddd XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM2, [ECX]; movdqa XMM1, [EAX+16]; movdqa XMM3, [ECX+16]; add EAX, 32; add ECX, 32; paddd XMM0, XMM2; paddd XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } // MMX version is 995% faster else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM2, [ECX]; movq MM1, [EAX+8]; movq MM3, [ECX+8]; add EAX, 16; add ECX, 16; paddd MM0, MM2; paddd MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr | cast(size_t) cptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM2, [RCX]; movdqu XMM1, [RAX+16]; movdqu XMM3, [RCX+16]; add RAX, 32; add RCX, 32; paddd XMM0, XMM2; paddd XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM2, [RCX]; movdqa XMM1, [RAX+16]; movdqa XMM3, [RCX+16]; add RAX, 32; add RCX, 32; paddd XMM0, XMM2; paddd XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startmmx: add RSI, 16; movq MM0, [RAX]; movq MM2, [RCX]; movq MM1, [RAX+8]; movq MM3, [RCX+8]; add RAX, 16; add RCX, 16; paddd MM0, MM2; paddd MM1, MM3; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } while (aptr < aend) *aptr++ = *bptr++ + *cptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceAddSliceAssign_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); b[i] = cast(T)(i-3); c[i] = cast(T)((i-10) * 2); } c[] = a[] + b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + b[i])) { printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] += value */ T[] _arrayExpSliceAddass_w(T[] a, T value) { return _arrayExpSliceAddass_i(a, value); } T[] _arrayExpSliceAddass_k(T[] a, T value) { return _arrayExpSliceAddass_i(a, value); } T[] _arrayExpSliceAddass_i(T[] a, T value) { //printf("_arrayExpSliceAddass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value); auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 aligned version is 83% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; add ESI, 32; paddd XMM0, XMM2; paddd XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; add ESI, 32; paddd XMM0, XMM2; paddd XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; } } } // MMX version is 81% faster else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movq MM2, l; align 4; startmmx: movq MM0, [ESI]; movq MM1, [ESI+8]; add ESI, 16; paddd MM0, MM2; paddd MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; } } } version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: movdqu XMM0, [RSI]; movdqu XMM1, [RSI+16]; add RSI, 32; paddd XMM0, XMM2; paddd XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: movdqa XMM0, [RSI]; movdqa XMM1, [RSI+16]; add RSI, 32; paddd XMM0, XMM2; paddd XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; } } } else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movq MM2, l; align 4; startmmx: movq MM0, [RSI]; movq MM1, [RSI+8]; add RSI, 16; paddd MM0, MM2; paddd MM1, MM2; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; } } } while (aptr < aend) *aptr++ += value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceAddass_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); c[i] = cast(T)((i-10) * 2); } a[] = c[]; a[] += 6; for (int i = 0; i < dim; i++) { if (a[i] != cast(T)(c[i] + 6)) { printf("[%d]: %d != %d + 6\n", i, a[i], c[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] += b[] */ T[] _arraySliceSliceAddass_w(T[] a, T[] b) { return _arraySliceSliceAddass_i(a, b); } T[] _arraySliceSliceAddass_k(T[] a, T[] b) { return _arraySliceSliceAddass_i(a, b); } T[] _arraySliceSliceAddass_i(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceSliceAddass_i()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 695% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2u: movdqu XMM0, [ESI]; movdqu XMM2, [ECX]; movdqu XMM1, [ESI+16]; movdqu XMM3, [ECX+16]; add ESI, 32; add ECX, 32; paddd XMM0, XMM2; paddd XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2a: movdqa XMM0, [ESI]; movdqa XMM2, [ECX]; movdqa XMM1, [ESI+16]; movdqa XMM3, [ECX+16]; add ESI, 32; add ECX, 32; paddd XMM0, XMM2; paddd XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, ECX; } } } // MMX version is 471% faster else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startmmx: movq MM0, [ESI]; movq MM2, [ECX]; movq MM1, [ESI+8]; movq MM3, [ECX+8]; add ESI, 16; add ECX, 16; paddd MM0, MM2; paddd MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, ECX; } } } version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2u: movdqu XMM0, [RSI]; movdqu XMM2, [RCX]; movdqu XMM1, [RSI+16]; movdqu XMM3, [RCX+16]; add RSI, 32; add RCX, 32; paddd XMM0, XMM2; paddd XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RCX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2a: movdqa XMM0, [RSI]; movdqa XMM2, [RCX]; movdqa XMM1, [RSI+16]; movdqa XMM3, [RCX+16]; add RSI, 32; add RCX, 32; paddd XMM0, XMM2; paddd XMM1, XMM3; movdqa [RSI-32], XMM0; movdqa [RSI-16], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RCX; } } } else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startmmx: movq MM0, [RSI]; movq MM2, [RCX]; movq MM1, [RSI+8]; movq MM3, [RCX+8]; add RSI, 16; add RCX, 16; paddd MM0, MM2; paddd MM1, MM3; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; mov bptr, RCX; } } } while (aptr < aend) *aptr++ += *bptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceAddass_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); b[i] = cast(T)(i-3); c[i] = cast(T)((i-10) * 2); } b[] = c[]; c[] += a[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(b[i] + a[i])) { printf("[%d]: %d != %d + %d\n", i, c[i], b[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - value */ T[] _arraySliceExpMinSliceAssign_w(T[] a, T value, T[] b) { return _arraySliceExpMinSliceAssign_i(a, value, b); } T[] _arraySliceExpMinSliceAssign_k(T[] a, T value, T[] b) { return _arraySliceExpMinSliceAssign_i(a, value, b); } T[] _arraySliceExpMinSliceAssign_i(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceExpMinSliceAssign_i()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 400% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add EAX, 32; psubd XMM0, XMM2; psubd XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add EAX, 32; psubd XMM0, XMM2; psubd XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; mov bptr, EAX; } } } // MMX version is 315% faster else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movq MM2, l; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM1, [EAX+8]; add EAX, 16; psubd MM0, MM2; psubd MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; } } } version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: add RSI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add RAX, 32; psubd XMM0, XMM2; psubd XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; mov bptr, RAX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: add RSI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add RAX, 32; psubd XMM0, XMM2; psubd XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; mov bptr, RAX; } } } else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movq MM2, l; align 4; startmmx: add RSI, 16; movq MM0, [EAX]; movq MM1, [EAX+8]; add RAX, 16; psubd MM0, MM2; psubd MM1, MM2; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; mov bptr, RAX; } } } while (aptr < aend) *aptr++ = *bptr++ - value; return a; } unittest { debug(PRINTF) printf("_arraySliceExpMinSliceAssign_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); c[i] = cast(T)((i-10) * 2); } c[] = a[] - 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - 6)) { printf("[%d]: %d != %d - 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = value - b[] */ T[] _arrayExpSliceMinSliceAssign_w(T[] a, T[] b, T value) { return _arrayExpSliceMinSliceAssign_i(a, b, value); } T[] _arrayExpSliceMinSliceAssign_k(T[] a, T[] b, T value) { return _arrayExpSliceMinSliceAssign_i(a, b, value); } T[] _arrayExpSliceMinSliceAssign_i(T[] a, T[] b, T value) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arrayExpSliceMinSliceAssign_i()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 1812% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM4, value; pshufd XMM4, XMM4, 0; align 4; startaddsse2u: add ESI, 32; movdqu XMM2, [EAX]; movdqu XMM3, [EAX+16]; movdqa XMM0, XMM4; movdqa XMM1, XMM4; add EAX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM4, value; pshufd XMM4, XMM4, 0; align 4; startaddsse2a: add ESI, 32; movdqa XMM2, [EAX]; movdqa XMM3, [EAX+16]; movdqa XMM0, XMM4; movdqa XMM1, XMM4; add EAX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; mov bptr, EAX; } } } // MMX version is 1077% faster else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movq MM4, l; align 4; startmmx: add ESI, 16; movq MM2, [EAX]; movq MM3, [EAX+8]; movq MM0, MM4; movq MM1, MM4; add EAX, 16; psubd MM0, MM2; psubd MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; } } } version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM4, value; pshufd XMM4, XMM4, 0; align 4; startaddsse2u: add RSI, 32; movdqu XMM2, [RAX]; movdqu XMM3, [RAX+16]; movdqa XMM0, XMM4; movdqa XMM1, XMM4; add RAX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; mov bptr, RAX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM4, value; pshufd XMM4, XMM4, 0; align 4; startaddsse2a: add RSI, 32; movdqa XMM2, [EAX]; movdqa XMM3, [EAX+16]; movdqa XMM0, XMM4; movdqa XMM1, XMM4; add RAX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; mov bptr, RAX; } } } else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movq MM4, l; align 4; startmmx: add RSI, 16; movq MM2, [EAX]; movq MM3, [EAX+8]; movq MM0, MM4; movq MM1, MM4; add RAX, 16; psubd MM0, MM2; psubd MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; mov bptr, RAX; } } } while (aptr < aend) *aptr++ = value - *bptr++; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinSliceAssign_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); c[i] = cast(T)((i-10) * 2); } c[] = 6 - a[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(6 - a[i])) { printf("[%d]: %d != 6 - %d\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - c[] */ T[] _arraySliceSliceMinSliceAssign_w(T[] a, T[] c, T[] b) { return _arraySliceSliceMinSliceAssign_i(a, c, b); } T[] _arraySliceSliceMinSliceAssign_k(T[] a, T[] c, T[] b) { return _arraySliceSliceMinSliceAssign_i(a, c, b); } T[] _arraySliceSliceMinSliceAssign_i(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 1721% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr | cast(size_t) cptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM2, [ECX]; movdqu XMM1, [EAX+16]; movdqu XMM3, [ECX+16]; add EAX, 32; add ECX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse2a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM2, [ECX]; movdqa XMM1, [EAX+16]; movdqa XMM3, [ECX+16]; add EAX, 32; add ECX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } // MMX version is 1002% faster else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startmmx: add ESI, 16; movq MM0, [EAX]; movq MM2, [ECX]; movq MM1, [EAX+8]; movq MM3, [ECX+8]; add EAX, 16; add ECX, 16; psubd MM0, MM2; psubd MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr | cast(size_t) cptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM2, [RCX]; movdqu XMM1, [RAX+16]; movdqu XMM3, [RCX+16]; add RAX, 32; add RCX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse2a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM2, [RCX]; movdqa XMM1, [RAX+16]; movdqa XMM3, [RCX+16]; add RAX, 32; add RCX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startmmx: add RSI, 16; movq MM0, [RAX]; movq MM2, [RCX]; movq MM1, [RAX+8]; movq MM3, [RCX+8]; add RAX, 16; add RCX, 16; psubd MM0, MM2; psubd MM1, MM3; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } while (aptr < aend) *aptr++ = *bptr++ - *cptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMinSliceAssign_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); b[i] = cast(T)(i-3); c[i] = cast(T)((i-10) * 2); } c[] = a[] - b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - b[i])) { printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= value */ T[] _arrayExpSliceMinass_w(T[] a, T value) { return _arrayExpSliceMinass_i(a, value); } T[] _arrayExpSliceMinass_k(T[] a, T value) { return _arrayExpSliceMinass_i(a, value); } T[] _arrayExpSliceMinass_i(T[] a, T value) { //printf("_arrayExpSliceMinass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value); auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 aligned version is 81% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; add ESI, 32; psubd XMM0, XMM2; psubd XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; add ESI, 32; psubd XMM0, XMM2; psubd XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; } } } // MMX version is 81% faster else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movq MM2, l; align 4; startmmx: movq MM0, [ESI]; movq MM1, [ESI+8]; add ESI, 16; psubd MM0, MM2; psubd MM1, MM2; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; } } } version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2u: movdqu XMM0, [RSI]; movdqu XMM1, [RSI+16]; add RSI, 32; psubd XMM0, XMM2; psubd XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2u; mov aptr, RSI; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startaddsse2a: movdqa XMM0, [RSI]; movdqa XMM1, [RSI+16]; add RSI, 32; psubd XMM0, XMM2; psubd XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startaddsse2a; mov aptr, RSI; } } } else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movq MM2, l; align 4; startmmx: movq MM0, [RSI]; movq MM1, [RSI+8]; add RSI, 16; psubd MM0, MM2; psubd MM1, MM2; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; } } } while (aptr < aend) *aptr++ -= value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinass_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); c[i] = cast(T)((i-10) * 2); } a[] = c[]; a[] -= 6; for (int i = 0; i < dim; i++) { if (a[i] != cast(T)(c[i] - 6)) { printf("[%d]: %d != %d - 6\n", i, a[i], c[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= b[] */ T[] _arraySliceSliceMinass_w(T[] a, T[] b) { return _arraySliceSliceMinass_i(a, b); } T[] _arraySliceSliceMinass_k(T[] a, T[] b) { return _arraySliceSliceMinass_i(a, b); } T[] _arraySliceSliceMinass_i(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceSliceMinass_i()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 731% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2u: movdqu XMM0, [ESI]; movdqu XMM2, [ECX]; movdqu XMM1, [ESI+16]; movdqu XMM3, [ECX+16]; add ESI, 32; add ECX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2u; mov aptr, ESI; mov bptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse2a: movdqa XMM0, [ESI]; movdqa XMM2, [ECX]; movdqa XMM1, [ESI+16]; movdqa XMM3, [ECX+16]; add ESI, 32; add ECX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse2a; mov aptr, ESI; mov bptr, ECX; } } } // MMX version is 441% faster else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startmmx: movq MM0, [ESI]; movq MM2, [ECX]; movq MM1, [ESI+8]; movq MM3, [ECX+8]; add ESI, 16; add ECX, 16; psubd MM0, MM2; psubd MM1, MM3; movq [ESI -16], MM0; movq [ESI+8-16], MM1; cmp ESI, EDI; jb startmmx; emms; mov aptr, ESI; mov bptr, ECX; } } } version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (((cast(size_t) aptr | cast(size_t) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2u: movdqu XMM0, [RSI]; movdqu XMM2, [RCX]; movdqu XMM1, [RSI+16]; movdqu XMM3, [RCX+16]; add RSI, 32; add RCX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2u; mov aptr, RSI; mov bptr, RCX; } } else { asm pure nothrow @nogc // aligned case { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse2a: movdqa XMM0, [RSI]; movdqa XMM2, [RCX]; movdqa XMM1, [RSI+16]; movdqa XMM3, [RCX+16]; add RSI, 32; add RCX, 32; psubd XMM0, XMM2; psubd XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse2a; mov aptr, RSI; mov bptr, RCX; } } } else if (mmx && a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startmmx: movq MM0, [RSI]; movq MM2, [RCX]; movq MM1, [RSI+8]; movq MM3, [RCX+8]; add RSI, 16; add RCX, 16; psubd MM0, MM2; psubd MM1, MM3; movq [RSI -16], MM0; movq [RSI+8-16], MM1; cmp RSI, RDI; jb startmmx; emms; mov aptr, RSI; mov bptr, RCX; } } } while (aptr < aend) *aptr++ -= *bptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMinass_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); b[i] = cast(T)(i-3); c[i] = cast(T)((i-10) * 2); } b[] = c[]; c[] -= a[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(b[i] - a[i])) { printf("[%d]: %d != %d - %d\n", i, c[i], b[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] * value */ T[] _arraySliceExpMulSliceAssign_w(T[] a, T value, T[] b) { return _arraySliceExpMulSliceAssign_i(a, value, b); } T[] _arraySliceExpMulSliceAssign_k(T[] a, T value, T[] b) { return _arraySliceExpMulSliceAssign_i(a, value, b); } T[] _arraySliceExpMulSliceAssign_i(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceExpMulSliceAssign_i()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { if (sse41) { auto aligned = ((cast(size_t) aptr | cast(size_t) bptr) & 15) == 0; if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (!aligned) { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startsse41u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; add EAX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse41u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM1, value; pshufd XMM2, XMM1, 0; align 4; startsse41a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; add EAX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse41a; mov aptr, ESI; mov bptr, EAX; } } } else if (a.length >= 4) { if (!aligned) { asm pure nothrow @nogc { mov ESI, aptr; mov EAX, bptr; movd XMM1,value; pshufd XMM1, XMM1, 0; movdqu XMM0, [EAX]; pmulld XMM0, XMM1; movdqu [ESI], XMM0; add EAX, 16; add ESI, 16; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EAX, bptr; movd XMM1,value; pshufd XMM1, XMM1, 0; movdqa XMM0, [EAX]; pmulld XMM0, XMM1; movdqa [ESI], XMM0; add EAX, 16; add ESI, 16; mov aptr, ESI; mov bptr, EAX; } } } } } version (D_InlineAsm_X86_64) { if (sse41) { auto aligned = ((cast(size_t) aptr | cast(size_t) bptr) & 15) == 0; if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (!aligned) { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startsse41u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM1, [RAX+16]; add RAX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse41u; mov aptr, RSI; mov bptr, RAX; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; movd XMM1, value; pshufd XMM2, XMM1, 0; align 4; startsse41a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM1, [RAX+16]; add RAX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse41a; mov aptr, RSI; mov bptr, RAX; } } } else if (a.length >= 4) { if (!aligned) {//possibly slow, needs measuring asm pure nothrow @nogc { mov RSI, aptr; mov RAX, bptr; movd XMM1, value; pshufd XMM1, XMM1, 0; movdqu XMM0, [RAX]; pmulld XMM0, XMM1; movdqu [RSI], XMM0; add RAX, 16; add RSI, 16; mov aptr, RSI; mov bptr, RAX; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RAX, bptr; movd XMM1, value; pshufd XMM1, XMM1, 0; movdqa XMM0, [RAX]; pmulld XMM0, XMM1; movdqa [RSI], XMM0; add RAX, 16; add RSI, 16; mov aptr, RSI; mov bptr, RAX; } } } } } while (aptr < aend) *aptr++ = *bptr++ * value; return a; } unittest { debug(PRINTF) printf("_arraySliceExpMulSliceAssign_s unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (size_t dim = 7; dim < 68; dim += 60) for (int j = 0; j < 2; j++) { T[] b = new T[dim + j]; // aligned on 16 byte boundary b = b[j .. dim + j]; // misalign for second iteration T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { b[i] = cast(T)(i-3); c[i] = cast(T)((i-10) * 2); } c[] = b[] * 6; for (int i = 0; i < dim; i++) { //printf("[%d]: %d ?= %d * 6\n", i, c[i], b[i]); if (c[i] != cast(T)(b[i] * 6)) { printf("[%d]: %d != %d * 6\n", i, c[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] * c[] */ T[] _arraySliceSliceMulSliceAssign_w(T[] a, T[] c, T[] b) { return _arraySliceSliceMulSliceAssign_i(a, c, b); } T[] _arraySliceSliceMulSliceAssign_k(T[] a, T[] c, T[] b) { return _arraySliceSliceMulSliceAssign_i(a, c, b); } T[] _arraySliceSliceMulSliceAssign_i(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); //printf("_arraySliceSliceMulSliceAssign_i()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { if (sse41) { auto aligned = ((cast(size_t) aptr | cast(size_t) bptr | cast(size_t) cptr) & 15) == 0; if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (!aligned) { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse41u: add ESI, 32; movdqu XMM0, [EAX]; movdqu XMM2, [ECX]; movdqu XMM1, [EAX+16]; movdqu XMM3, [ECX+16]; add EAX, 32; add ECX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse41u; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startsse41a: add ESI, 32; movdqa XMM0, [EAX]; movdqa XMM2, [ECX]; movdqa XMM1, [EAX+16]; movdqa XMM3, [ECX+16]; add EAX, 32; add ECX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse41a; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else if (a.length >= 4) { if (!aligned) {//possibly not a good idea. Performance? asm pure nothrow @nogc { mov ESI, aptr; mov EAX, bptr; mov ECX, cptr; movdqu XMM0, [EAX]; movdqu XMM1, [ECX]; pmulld XMM0, XMM1; movdqu [ESI], XMM0; add ESI, 16; add EAX, 16; add ECX, 16; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EAX, bptr; mov ECX, cptr; movdqa XMM0, [EAX]; movdqa XMM1, [ECX]; pmulld XMM0, XMM1; movdqu [ESI], XMM0; add ESI, 16; add EAX, 16; add ECX, 16; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } } } version (D_InlineAsm_X86_64) { if (sse41) { auto aligned = ((cast(size_t) aptr | cast(size_t) bptr | cast(size_t) cptr) & 15) == 0; if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (!aligned) { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse41u: add RSI, 32; movdqu XMM0, [RAX]; movdqu XMM2, [RCX]; movdqu XMM1, [RAX+16]; movdqu XMM3, [RCX+16]; add RAX, 32; add RCX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse41u; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RAX, bptr; mov RCX, cptr; align 4; startsse41a: add RSI, 32; movdqa XMM0, [RAX]; movdqa XMM2, [RCX]; movdqa XMM1, [RAX+16]; movdqa XMM3, [RCX+16]; add RAX, 32; add RCX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse41a; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } else if (a.length >= 4) { if (!aligned) {//possibly not a good idea. Performance? asm pure nothrow @nogc { mov RSI, aptr; mov RAX, bptr; mov RCX, cptr; movdqu XMM0, [RAX]; movdqu XMM1, [RCX]; pmulld XMM0, XMM1; movdqu [RSI], XMM0; add RSI, 16; add RAX, 16; add RCX, 16; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RAX, bptr; mov RCX, cptr; movdqa XMM0, [RAX]; movdqa XMM1, [RCX]; pmulld XMM0, XMM1; movdqu [RSI], XMM0; add RSI, 16; add RAX, 16; add RCX, 16; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } } } while (aptr < aend) *aptr++ = *bptr++ * *cptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMulSliceAssign_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (size_t dim = 7; dim < 68; dim += 60) { for (int j = 0; j < 2; j++) { T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); b[i] = cast(T)(i-3); c[i] = cast(T)((i-10) * 2); } c[] = a[] * b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * b[i])) { printf("[%d]: %d != %d * %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] *= value */ T[] _arrayExpSliceMulass_w(T[] a, T value) { return _arrayExpSliceMulass_i(a, value); } T[] _arrayExpSliceMulass_k(T[] a, T value) { return _arrayExpSliceMulass_i(a, value); } T[] _arrayExpSliceMulass_i(T[] a, T value) { //printf("_arrayExpSliceMulass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value); auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { if (sse41) { auto aligned = ((cast(size_t) aptr) & 15) == 0; if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (!aligned) { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movd XMM2,value; pshufd XMM2, XMM2, 0; align 4; startsse41u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; add ESI, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM2; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse41u; mov aptr, ESI; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movd XMM2,value; pshufd XMM2, XMM2, 0; align 4; startsse41a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; add ESI, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM2; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse41a; mov aptr, ESI; } } } else if (a.length >= 4) { if (!aligned) { asm pure nothrow @nogc { mov ESI, aptr; movd XMM2,value; pshufd XMM2, XMM2, 0; movdqu XMM0, [ESI]; pmulld XMM0, XMM2; movdqu [ESI], XMM0; add ESI, 16; mov aptr, ESI; } } else { asm pure nothrow @nogc { mov ESI, aptr; movd XMM2,value; pshufd XMM2, XMM2, 0; movdqa XMM0, [ESI]; pmulld XMM0, XMM2; movdqa [ESI], XMM0; add ESI, 16; mov aptr, ESI; } } } } } version (D_InlineAsm_X86_64) { if (sse41) { auto aligned = ((cast(size_t) aptr) & 15) == 0; if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (!aligned) { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startsse41u: movdqu XMM0, [RSI]; movdqu XMM1, [RSI+16]; add RSI, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM2; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse41u; mov aptr, RSI; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movd XMM2, value; pshufd XMM2, XMM2, 0; align 4; startsse41a: movdqa XMM0, [RSI]; movdqa XMM1, [RSI+16]; add RSI, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM2; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse41a; mov aptr, RSI; } } } else if (a.length >= 4) { if (!aligned) { //is the overhead worth it? asm pure nothrow @nogc { mov RSI, aptr; movd XMM2, value; pshufd XMM2, XMM2, 0; movdqu XMM0, [RSI]; pmulld XMM0, XMM2; movdqu [RSI], XMM0; add RSI, 16; mov aptr, RSI; } } else { asm pure nothrow @nogc { mov RSI, aptr; movd XMM2, value; pshufd XMM2, XMM2, 0; movdqa XMM0, [RSI]; pmulld XMM0, XMM2; movdqa [RSI], XMM0; add RSI, 16; mov aptr, RSI; } } } } } while (aptr < aend) *aptr++ *= value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMulass_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (size_t dim = 7; dim < 68; dim += 60) { for (int j = 0; j < 2; j++) { T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); b[i] = cast(T)(i-3); } b[] = a[]; a[] *= 6; for (int i = 0; i < dim; i++) { if (a[i] != cast(T)(b[i] * 6)) { printf("[%d]: %d != %d * 6\n", i, a[i], b[i]); assert(0); } } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] *= b[] */ T[] _arraySliceSliceMulass_w(T[] a, T[] b) { return _arraySliceSliceMulass_i(a, b); } T[] _arraySliceSliceMulass_k(T[] a, T[] b) { return _arraySliceSliceMulass_i(a, b); } T[] _arraySliceSliceMulass_i(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceSliceMulass_i()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { if (sse41) { auto aligned = ((cast(size_t) aptr) & 15) == 0; if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (!aligned) { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse41u: movdqu XMM0, [ESI]; movdqu XMM2, [ECX]; movdqu XMM1, [ESI+16]; movdqu XMM3, [ECX+16]; add ESI, 32; add ECX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM3; movdqu [ESI -32], XMM0; movdqu [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse41u; mov aptr, ESI; mov bptr, ECX; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 4; startsse41a: movdqa XMM0, [ESI]; movdqa XMM2, [ECX]; movdqa XMM1, [ESI+16]; movdqa XMM3, [ECX+16]; add ESI, 32; add ECX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM3; movdqa [ESI -32], XMM0; movdqa [ESI+16-32], XMM1; cmp ESI, EDI; jb startsse41a; mov aptr, ESI; mov bptr, ECX; } } } else if (a.length >= 4) { if (!aligned) {//is the unaligned overhead worth it asm pure nothrow @nogc { mov ESI, aptr; mov ECX, bptr; movdqu XMM0, [ESI]; movdqu XMM2, [ECX]; pmulld XMM0, XMM2; movdqu [ESI], XMM0; add ESI, 16; add ECX, 16; mov aptr, ESI; mov bptr, ECX; } } else { asm pure nothrow @nogc { mov ESI, aptr; mov ECX, bptr; movdqa XMM0, [ESI]; movdqa XMM2, [ECX]; pmulld XMM0, XMM2; movdqa [ESI], XMM0; add ESI, 16; add ECX, 16; mov aptr, ESI; mov bptr, ECX; } } } } } version (D_InlineAsm_X86_64) { if (sse41) { auto aligned = ((cast(size_t) aptr) & 15) == 0; if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (!aligned) { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse41u: movdqu XMM0, [RSI]; movdqu XMM2, [RCX]; movdqu XMM1, [RSI+16]; movdqu XMM3, [RCX+16]; add RSI, 32; add RCX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM3; movdqu [RSI -32], XMM0; movdqu [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse41u; mov aptr, RSI; mov bptr, RCX; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; mov RCX, bptr; align 4; startsse41a: movdqa XMM0, [RSI]; movdqa XMM2, [RCX]; movdqa XMM1, [RSI+16]; movdqa XMM3, [RCX+16]; add RSI, 32; add RCX, 32; pmulld XMM0, XMM2; pmulld XMM1, XMM3; movdqa [RSI -32], XMM0; movdqa [RSI+16-32], XMM1; cmp RSI, RDI; jb startsse41a; mov aptr, RSI; mov bptr, RCX; } } } else if (a.length >= 4) { if (!aligned) {//is the unaligned overhead worth it asm pure nothrow @nogc { mov RSI, aptr; mov RCX, bptr; movdqu XMM0, [RSI]; movdqu XMM2, [RCX]; pmulld XMM0, XMM2; movdqu [RSI], XMM0; add RSI, 16; add RCX, 16; mov aptr, RSI; mov bptr, RCX; } } else { asm pure nothrow @nogc { mov RSI, aptr; mov RCX, bptr; movdqa XMM0, [RSI]; movdqa XMM2, [RCX]; pmulld XMM0, XMM2; movdqa [RSI], XMM0; add RSI, 16; add RCX, 16; mov aptr, RSI; mov bptr, RCX; } } } } } while (aptr < aend) *aptr++ *= *bptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMulass_i unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (size_t dim = 7; dim < 68; dim += 60) { for (int j = 0; j < 2; j++) { T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)(i-10); b[i] = cast(T)(i-3); c[i] = cast(T)((i-10) * 2); } b[] = a[]; a[] *= c[]; for (int i = 0; i < dim; i++) { if (a[i] != cast(T)(b[i] * c[i])) { printf("[%d]: %d != %d * %d\n", i, a[i], b[i], c[i]); assert(0); } } } } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/0000775000175000017500000000000012776214756020534 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Along.d0000664000175000017500000000476712776214756022453 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Along; private import core.stdc.string; private import rt.util.hash; // long[] class TypeInfo_Al : TypeInfo_Array { override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return "long[]"; } override size_t getHash(in void* p) @trusted const { long[] s = *cast(long[]*)p; return rt.util.hash.hashOf(s.ptr, s.length * long.sizeof); } override bool equals(in void* p1, in void* p2) const { long[] s1 = *cast(long[]*)p1; long[] s2 = *cast(long[]*)p2; return s1.length == s2.length && memcmp(cast(void *)s1, cast(void *)s2, s1.length * long.sizeof) == 0; } override int compare(in void* p1, in void* p2) const { long[] s1 = *cast(long[]*)p1; long[] s2 = *cast(long[]*)p2; size_t len = s1.length; if (s2.length < len) len = s2.length; for (size_t u = 0; u < len; u++) { if (s1[u] < s2[u]) return -1; else if (s1[u] > s2[u]) return 1; } if (s1.length < s2.length) return -1; else if (s1.length > s2.length) return 1; return 0; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(long); } } // ulong[] class TypeInfo_Am : TypeInfo_Al { override string toString() const { return "ulong[]"; } override int compare(in void* p1, in void* p2) const { ulong[] s1 = *cast(ulong[]*)p1; ulong[] s2 = *cast(ulong[]*)p2; size_t len = s1.length; if (s2.length < len) len = s2.length; for (size_t u = 0; u < len; u++) { if (s1[u] < s2[u]) return -1; else if (s1[u] > s2[u]) return 1; } if (s1.length < s2.length) return -1; else if (s1.length > s2.length) return 1; return 0; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(ulong); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_C.d0000664000175000017500000000307112776214756021560 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_C; // Object class TypeInfo_C : TypeInfo { @trusted: const: //pure: //nothrow: override size_t getHash(in void* p) { Object o = *cast(Object*)p; return o ? o.toHash() : 0; } override bool equals(in void* p1, in void* p2) { Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; return o1 == o2; } override int compare(in void* p1, in void* p2) { Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; int c = 0; // Regard null references as always being "less than" if (!(o1 is o2)) { if (o1) { if (!o2) c = 1; else c = o1.opCmp(o2); } else c = -1; } return c; } override @property size_t tsize() nothrow pure { return Object.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. Object.sizeof]; } override @property uint flags() nothrow pure { return 1; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_cfloat.d0000664000175000017500000000310712776214756022646 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_cfloat; private import rt.util.typeinfo; // cfloat class TypeInfo_q : TypeInfo { pure: nothrow: @safe: alias F = cfloat; override string toString() const { return F.stringof; } override size_t getHash(in void* p) const @trusted { return Floating!F.hashOf(*cast(F*)p); } override bool equals(in void* p1, in void* p2) const @trusted { return Floating!F.equals(*cast(F*)p1, *cast(F*)p2); } override int compare(in void* p1, in void* p2) const @trusted { return Floating!F.compare(*cast(F*)p1, *cast(F*)p2); } override @property size_t tsize() const { return F.sizeof; } override void swap(void *p1, void *p2) const @trusted { F t = *cast(F*)p1; *cast(F*)p1 = *cast(F*)p2; *cast(F*)p2 = t; } override const(void)[] initializer() const @trusted { static immutable F r; return (&r)[0 .. 1]; } override @property size_t talign() const { return F.alignof; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { arg1 = typeid(double); return 0; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_delegate.d0000664000175000017500000000240512776214756023150 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_delegate; private import rt.util.hash; // delegate alias void delegate(int) dg; class TypeInfo_D : TypeInfo { @trusted: const: pure: nothrow: override size_t getHash(in void* p) { return rt.util.hash.hashOf(p, dg.sizeof); } override bool equals(in void* p1, in void* p2) { return *cast(dg *)p1 == *cast(dg *)p2; } override @property size_t tsize() nothrow pure { return dg.sizeof; } override void swap(void *p1, void *p2) { dg t; t = *cast(dg *)p1; *cast(dg *)p1 = *cast(dg *)p2; *cast(dg *)p2 = t; } override const(void)[] initializer() const @trusted { static immutable dg d; return (cast(void *)null)[0 .. dg.sizeof]; } override @property uint flags() nothrow pure { return 1; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_uint.d0000664000175000017500000000257512776214756022365 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_uint; // uint class TypeInfo_k : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "uint"; } override size_t getHash(in void* p) { return *cast(uint *)p; } override bool equals(in void* p1, in void* p2) { return *cast(uint *)p1 == *cast(uint *)p2; } override int compare(in void* p1, in void* p2) { if (*cast(uint*) p1 < *cast(uint*) p2) return -1; else if (*cast(uint*) p1 > *cast(uint*) p2) return 1; return 0; } override @property size_t tsize() nothrow pure { return uint.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. uint.sizeof]; } override void swap(void *p1, void *p2) { int t; t = *cast(uint *)p1; *cast(uint *)p1 = *cast(uint *)p2; *cast(uint *)p2 = t; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Adouble.d0000664000175000017500000000256212776214756022755 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Adouble; private import rt.util.typeinfo; // double[] class TypeInfo_Ad : TypeInfo_Array { alias F = double; override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return (F[]).stringof; } override size_t getHash(in void* p) @trusted const { return Array!F.hashOf(*cast(F[]*)p); } override bool equals(in void* p1, in void* p2) const { return Array!F.equals(*cast(F[]*)p1, *cast(F[]*)p2); } override int compare(in void* p1, in void* p2) const { return Array!F.compare(*cast(F[]*)p1, *cast(F[]*)p2); } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(F); } } // idouble[] class TypeInfo_Ap : TypeInfo_Ad { alias F = idouble; override string toString() const { return (F[]).stringof; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(F); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Areal.d0000664000175000017500000000255012776214756022423 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Areal; private import rt.util.typeinfo; // real[] class TypeInfo_Ae : TypeInfo_Array { alias F = real; override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return (F[]).stringof; } override size_t getHash(in void* p) @trusted const { return Array!F.hashOf(*cast(F[]*)p); } override bool equals(in void* p1, in void* p2) const { return Array!F.equals(*cast(F[]*)p1, *cast(F[]*)p2); } override int compare(in void* p1, in void* p2) const { return Array!F.compare(*cast(F[]*)p1, *cast(F[]*)p2); } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(F); } } // ireal[] class TypeInfo_Aj : TypeInfo_Ae { alias F = ireal; override string toString() const { return (F[]).stringof; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(F); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_AC.d0000664000175000017500000000517712776214756021672 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_AC; // Object[] /* NOTE: It is sometimes used for arrays of classes or (incorrectly) interfaces. But naked `TypeInfo_Array` is mostly used. See @@@BUG12303@@@. */ class TypeInfo_AC : TypeInfo_Array { override string toString() const { return TypeInfo.toString(); } override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override size_t getHash(in void* p) @trusted const { Object[] s = *cast(Object[]*)p; size_t hash = 0; foreach (Object o; s) { if (o) hash += o.toHash(); } return hash; } override bool equals(in void* p1, in void* p2) const { Object[] s1 = *cast(Object[]*)p1; Object[] s2 = *cast(Object[]*)p2; if (s1.length == s2.length) { for (size_t u = 0; u < s1.length; u++) { Object o1 = s1[u]; Object o2 = s2[u]; // Do not pass null's to Object.opEquals() if (o1 is o2 || (!(o1 is null) && !(o2 is null) && o1.opEquals(o2))) continue; return false; } return true; } return false; } override int compare(in void* p1, in void* p2) const { Object[] s1 = *cast(Object[]*)p1; Object[] s2 = *cast(Object[]*)p2; auto c = cast(sizediff_t)(s1.length - s2.length); if (c == 0) { for (size_t u = 0; u < s1.length; u++) { Object o1 = s1[u]; Object o2 = s2[u]; if (o1 is o2) continue; // Regard null references as always being "less than" if (o1) { if (!o2) return 1; c = o1.opCmp(o2); if (c == 0) continue; break; } else { return -1; } } } return c < 0 ? -1 : c > 0 ? 1 : 0; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(Object); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_ifloat.d0000664000175000017500000000113712776214756022655 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_ifloat; private import rt.typeinfo.ti_float; // ifloat class TypeInfo_o : TypeInfo_f { pure: nothrow: @safe: override string toString() const { return ifloat.stringof; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_creal.d0000664000175000017500000000313712776214756022467 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_creal; private import rt.util.typeinfo; // creal class TypeInfo_c : TypeInfo { pure: nothrow: @safe: alias F = creal; override string toString() const { return F.stringof; } override size_t getHash(in void* p) const @trusted { return Floating!F.hashOf(*cast(F*)p); } override bool equals(in void* p1, in void* p2) const @trusted { return Floating!F.equals(*cast(F*)p1, *cast(F*)p2); } override int compare(in void* p1, in void* p2) const @trusted { return Floating!F.compare(*cast(F*)p1, *cast(F*)p2); } override @property size_t tsize() const { return F.sizeof; } override void swap(void *p1, void *p2) const @trusted { F t = *cast(F*)p1; *cast(F*)p1 = *cast(F*)p2; *cast(F*)p2 = t; } override const(void)[] initializer() const @trusted { static immutable F r; return (&r)[0 .. 1]; } override @property size_t talign() const { return F.alignof; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { arg1 = typeid(real); arg2 = typeid(real); return 0; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_cdouble.d0000664000175000017500000000315112776214756023012 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_cdouble; private import rt.util.typeinfo; // cdouble class TypeInfo_r : TypeInfo { pure: nothrow: @safe: alias F = cdouble; override string toString() const { return F.stringof; } override size_t getHash(in void* p) const @trusted { return Floating!F.hashOf(*cast(F*)p); } override bool equals(in void* p1, in void* p2) const @trusted { return Floating!F.equals(*cast(F*)p1, *cast(F*)p2); } override int compare(in void* p1, in void* p2) const @trusted { return Floating!F.compare(*cast(F*)p1, *cast(F*)p2); } override @property size_t tsize() const { return F.sizeof; } override void swap(void *p1, void *p2) const @trusted { F t = *cast(F*)p1; *cast(F*)p1 = *cast(F*)p2; *cast(F*)p2 = t; } override const(void)[] initializer() const @trusted { static immutable F r; return (&r)[0 .. 1]; } override @property size_t talign() const { return F.alignof; } version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) { arg1 = typeid(double); arg2 = typeid(double); return 0; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_ireal.d0000664000175000017500000000113312776214756022467 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_ireal; private import rt.typeinfo.ti_real; // ireal class TypeInfo_j : TypeInfo_e { pure: nothrow: @safe: override string toString() const { return ireal.stringof; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_char.d0000664000175000017500000000243012776214756022311 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_char; // char class TypeInfo_a : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "char"; } override size_t getHash(in void* p) { return *cast(char *)p; } override bool equals(in void* p1, in void* p2) { return *cast(char *)p1 == *cast(char *)p2; } override int compare(in void* p1, in void* p2) { return *cast(char *)p1 - *cast(char *)p2; } override @property size_t tsize() nothrow pure { return char.sizeof; } override void swap(void *p1, void *p2) { char t; t = *cast(char *)p1; *cast(char *)p1 = *cast(char *)p2; *cast(char *)p2 = t; } override const(void)[] initializer() const @trusted { static immutable char c; return (&c)[0 .. 1]; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_byte.d0000664000175000017500000000241012776214756022335 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_byte; // byte class TypeInfo_g : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "byte"; } override size_t getHash(in void* p) { return *cast(byte *)p; } override bool equals(in void* p1, in void* p2) { return *cast(byte *)p1 == *cast(byte *)p2; } override int compare(in void* p1, in void* p2) { return *cast(byte *)p1 - *cast(byte *)p2; } override @property size_t tsize() nothrow pure { return byte.sizeof; } override const(void)[] initializer() @trusted { return (cast(void *)null)[0 .. byte.sizeof]; } override void swap(void *p1, void *p2) { byte t; t = *cast(byte *)p1; *cast(byte *)p1 = *cast(byte *)p2; *cast(byte *)p2 = t; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_idouble.d0000664000175000017500000000114312776214756023017 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_idouble; private import rt.typeinfo.ti_double; // idouble class TypeInfo_p : TypeInfo_d { pure: nothrow: @safe: override string toString() const { return idouble.stringof; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_ubyte.d0000664000175000017500000000267412776214756022536 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_ubyte; // ubyte class TypeInfo_h : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "ubyte"; } override size_t getHash(in void* p) { return *cast(ubyte *)p; } override bool equals(in void* p1, in void* p2) { return *cast(ubyte *)p1 == *cast(ubyte *)p2; } override int compare(in void* p1, in void* p2) { return *cast(ubyte *)p1 - *cast(ubyte *)p2; } override @property size_t tsize() nothrow pure { return ubyte.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. ubyte.sizeof]; } override void swap(void *p1, void *p2) { ubyte t; t = *cast(ubyte *)p1; *cast(ubyte *)p1 = *cast(ubyte *)p2; *cast(ubyte *)p2 = t; } } class TypeInfo_b : TypeInfo_h { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "bool"; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_double.d0000664000175000017500000000317312776214756022653 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_double; private import rt.util.typeinfo; // double class TypeInfo_d : TypeInfo { pure: nothrow: @safe: alias F = double; override string toString() const { return F.stringof; } override size_t getHash(in void* p) const @trusted { return Floating!F.hashOf(*cast(F*)p); } override bool equals(in void* p1, in void* p2) const @trusted { return Floating!F.equals(*cast(F*)p1, *cast(F*)p2); } override int compare(in void* p1, in void* p2) const @trusted { return Floating!F.compare(*cast(F*)p1, *cast(F*)p2); } override @property size_t tsize() const { return F.sizeof; } override void swap(void *p1, void *p2) const @trusted { F t = *cast(F*)p1; *cast(F*)p1 = *cast(F*)p2; *cast(F*)p2 = t; } override const(void)[] initializer() const @trusted { static immutable F r; return (&r)[0 .. 1]; } override @property size_t talign() const { return F.alignof; } version (Windows) { } else version (X86_64) { // 2 means arg to function is passed in XMM registers override @property uint flags() const { return 2; } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Acfloat.d0000664000175000017500000000220112776214756022741 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Acfloat; private import rt.util.typeinfo; // cfloat[] class TypeInfo_Aq : TypeInfo_Array { alias F = cfloat; override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return (F[]).stringof; } override size_t getHash(in void* p) @trusted const { return Array!F.hashOf(*cast(F[]*)p); } override bool equals(in void* p1, in void* p2) const { return Array!F.equals(*cast(F[]*)p1, *cast(F[]*)p2); } override int compare(in void* p1, in void* p2) const { return Array!F.compare(*cast(F[]*)p1, *cast(F[]*)p2); } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(F); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Ashort.d0000664000175000017500000000526212776214756022642 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Ashort; private import core.stdc.string; private import rt.util.hash; // short[] class TypeInfo_As : TypeInfo_Array { override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return "short[]"; } override size_t getHash(in void* p) @trusted const { short[] s = *cast(short[]*)p; return rt.util.hash.hashOf(s.ptr, s.length * short.sizeof); } override bool equals(in void* p1, in void* p2) const { short[] s1 = *cast(short[]*)p1; short[] s2 = *cast(short[]*)p2; return s1.length == s2.length && memcmp(cast(void *)s1, cast(void *)s2, s1.length * short.sizeof) == 0; } override int compare(in void* p1, in void* p2) const { short[] s1 = *cast(short[]*)p1; short[] s2 = *cast(short[]*)p2; size_t len = s1.length; if (s2.length < len) len = s2.length; for (size_t u = 0; u < len; u++) { int result = s1[u] - s2[u]; if (result) return result; } if (s1.length < s2.length) return -1; else if (s1.length > s2.length) return 1; return 0; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(short); } } // ushort[] class TypeInfo_At : TypeInfo_As { override string toString() const { return "ushort[]"; } override int compare(in void* p1, in void* p2) const { ushort[] s1 = *cast(ushort[]*)p1; ushort[] s2 = *cast(ushort[]*)p2; size_t len = s1.length; if (s2.length < len) len = s2.length; for (size_t u = 0; u < len; u++) { int result = s1[u] - s2[u]; if (result) return result; } if (s1.length < s2.length) return -1; else if (s1.length > s2.length) return 1; return 0; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(ushort); } } // wchar[] class TypeInfo_Au : TypeInfo_At { override string toString() const { return "wchar[]"; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(wchar); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_void.d0000664000175000017500000000252212776214756022337 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_void; // void class TypeInfo_v : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "void"; } override size_t getHash(in void* p) { assert(0); } override bool equals(in void* p1, in void* p2) { return *cast(byte *)p1 == *cast(byte *)p2; } override int compare(in void* p1, in void* p2) { return *cast(byte *)p1 - *cast(byte *)p2; } override @property size_t tsize() nothrow pure { return void.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. void.sizeof]; } override void swap(void *p1, void *p2) { byte t; t = *cast(byte *)p1; *cast(byte *)p1 = *cast(byte *)p2; *cast(byte *)p2 = t; } override @property uint flags() nothrow pure { return 1; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_ulong.d0000664000175000017500000000304112776214756022517 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_ulong; private import rt.util.hash; // ulong class TypeInfo_m : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "ulong"; } override size_t getHash(in void* p) { return rt.util.hash.hashOf(p, ulong.sizeof); } override bool equals(in void* p1, in void* p2) { return *cast(ulong *)p1 == *cast(ulong *)p2; } override int compare(in void* p1, in void* p2) { if (*cast(ulong *)p1 < *cast(ulong *)p2) return -1; else if (*cast(ulong *)p1 > *cast(ulong *)p2) return 1; return 0; } override @property size_t tsize() nothrow pure { return ulong.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. ulong.sizeof]; } override void swap(void *p1, void *p2) { ulong t; t = *cast(ulong *)p1; *cast(ulong *)p1 = *cast(ulong *)p2; *cast(ulong *)p2 = t; } override @property size_t talign() nothrow pure { return ulong.alignof; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_real.d0000664000175000017500000000266212776214756022326 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_real; private import rt.util.typeinfo; // real class TypeInfo_e : TypeInfo { pure: nothrow: @safe: alias F = real; override string toString() const { return F.stringof; } override size_t getHash(in void* p) const @trusted { return Floating!F.hashOf(*cast(F*)p); } override bool equals(in void* p1, in void* p2) const @trusted { return Floating!F.equals(*cast(F*)p1, *cast(F*)p2); } override int compare(in void* p1, in void* p2) const @trusted { return Floating!F.compare(*cast(F*)p1, *cast(F*)p2); } override @property size_t tsize() const { return F.sizeof; } override void swap(void *p1, void *p2) const @trusted { F t = *cast(F*)p1; *cast(F*)p1 = *cast(F*)p2; *cast(F*)p2 = t; } override const(void)[] initializer() const @trusted { static immutable F r; return (&r)[0 .. 1]; } override @property size_t talign() const { return F.alignof; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_wchar.d0000664000175000017500000000240112776214756022476 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_wchar; // wchar class TypeInfo_u : TypeInfo { @trusted: const: pure: nothrow: override string toString() { return "wchar"; } override size_t getHash(in void* p) { return *cast(wchar *)p; } override bool equals(in void* p1, in void* p2) { return *cast(wchar *)p1 == *cast(wchar *)p2; } override int compare(in void* p1, in void* p2) { return *cast(wchar *)p1 - *cast(wchar *)p2; } override @property size_t tsize() { return wchar.sizeof; } override void swap(void *p1, void *p2) { wchar t; t = *cast(wchar *)p1; *cast(wchar *)p1 = *cast(wchar *)p2; *cast(wchar *)p2 = t; } override const(void)[] initializer() const @trusted { static immutable wchar c; return (&c)[0 .. 1]; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_ushort.d0000664000175000017500000000245412776214756022726 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_ushort; // ushort class TypeInfo_t : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "ushort"; } override size_t getHash(in void* p) { return *cast(ushort *)p; } override bool equals(in void* p1, in void* p2) { return *cast(ushort *)p1 == *cast(ushort *)p2; } override int compare(in void* p1, in void* p2) { return *cast(ushort *)p1 - *cast(ushort *)p2; } override @property size_t tsize() nothrow pure { return ushort.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. ushort.sizeof]; } override void swap(void *p1, void *p2) { ushort t; t = *cast(ushort *)p1; *cast(ushort *)p1 = *cast(ushort *)p2; *cast(ushort *)p2 = t; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Acdouble.d0000664000175000017500000000220412776214756023111 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Acdouble; private import rt.util.typeinfo; // cdouble[] class TypeInfo_Ar : TypeInfo_Array { alias F = cdouble; override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return (F[]).stringof; } override size_t getHash(in void* p) @trusted const { return Array!F.hashOf(*cast(F[]*)p); } override bool equals(in void* p1, in void* p2) const { return Array!F.equals(*cast(F[]*)p1, *cast(F[]*)p2); } override int compare(in void* p1, in void* p2) const { return Array!F.compare(*cast(F[]*)p1, *cast(F[]*)p2); } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(F); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_float.d0000664000175000017500000000304412776214756022503 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_float; private import rt.util.typeinfo; // float class TypeInfo_f : TypeInfo { pure: nothrow: @safe: alias F = float; override string toString() const { return F.stringof; } override size_t getHash(in void* p) const @trusted { return Floating!F.hashOf(*cast(F*)p); } override bool equals(in void* p1, in void* p2) const @trusted { return Floating!F.equals(*cast(F*)p1, *cast(F*)p2); } override int compare(in void* p1, in void* p2) const @trusted { return Floating!F.compare(*cast(F*)p1, *cast(F*)p2); } override @property size_t tsize() const { return F.sizeof; } override void swap(void *p1, void *p2) const @trusted { F t = *cast(F*)p1; *cast(F*)p1 = *cast(F*)p2; *cast(F*)p2 = t; } override const(void)[] initializer() const @trusted { static immutable F r; return (&r)[0 .. 1]; } version (Windows) { } else version (X86_64) { // 2 means arg to function is passed in XMM registers override @property uint flags() const { return 2; } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_cent.d0000664000175000017500000000304612776214756022331 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2015. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2015. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_cent; private import rt.util.hash; static if(is(cent)): // cent class TypeInfo_zi : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "cent"; } override size_t getHash(in void* p) { return rt.util.hash.hashOf(p, cent.sizeof); } override bool equals(in void* p1, in void* p2) { return *cast(cent *)p1 == *cast(cent *)p2; } override int compare(in void* p1, in void* p2) { if (*cast(cent *)p1 < *cast(cent *)p2) return -1; else if (*cast(cent *)p1 > *cast(cent *)p2) return 1; return 0; } override @property size_t tsize() nothrow pure { return cent.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. cent.sizeof]; } override void swap(void *p1, void *p2) { cent t; t = *cast(cent *)p1; *cast(cent *)p1 = *cast(cent *)p2; *cast(cent *)p2 = t; } override @property size_t talign() nothrow pure { return cent.alignof; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_ucent.d0000664000175000017500000000307212776214756022515 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2015. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2015. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_ucent; private import rt.util.hash; static if (is(ucent)): // ucent class TypeInfo_zk : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "ucent"; } override size_t getHash(in void* p) { return rt.util.hash.hashOf(p, ucent.sizeof); } override bool equals(in void* p1, in void* p2) { return *cast(ucent *)p1 == *cast(ucent *)p2; } override int compare(in void* p1, in void* p2) { if (*cast(ucent *)p1 < *cast(ucent *)p2) return -1; else if (*cast(ucent *)p1 > *cast(ucent *)p2) return 1; return 0; } override @property size_t tsize() nothrow pure { return ucent.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. ucent.sizeof]; } override void swap(void *p1, void *p2) { ucent t; t = *cast(ucent *)p1; *cast(ucent *)p1 = *cast(ucent *)p2; *cast(ucent *)p2 = t; } override @property size_t talign() nothrow pure { return ucent.alignof; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Acreal.d0000664000175000017500000000217612776214756022572 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Acreal; private import rt.util.typeinfo; // creal[] class TypeInfo_Ac : TypeInfo_Array { alias F = creal; override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return (F[]).stringof; } override size_t getHash(in void* p) @trusted const { return Array!F.hashOf(*cast(F[]*)p); } override bool equals(in void* p1, in void* p2) const { return Array!F.equals(*cast(F[]*)p1, *cast(F[]*)p2); } override int compare(in void* p1, in void* p2) const { return Array!F.compare(*cast(F[]*)p1, *cast(F[]*)p2); } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(F); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Aint.d0000664000175000017500000000710712776214756022275 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Aint; private import core.stdc.string; private import rt.util.hash; extern (C) void[] _adSort(void[] a, TypeInfo ti); // int[] class TypeInfo_Ai : TypeInfo_Array { override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return "int[]"; } override size_t getHash(in void* p) @trusted const { int[] s = *cast(int[]*)p; return rt.util.hash.hashOf(s.ptr, s.length * int.sizeof); } override bool equals(in void* p1, in void* p2) const { int[] s1 = *cast(int[]*)p1; int[] s2 = *cast(int[]*)p2; return s1.length == s2.length && memcmp(cast(void *)s1, cast(void *)s2, s1.length * int.sizeof) == 0; } override int compare(in void* p1, in void* p2) const { int[] s1 = *cast(int[]*)p1; int[] s2 = *cast(int[]*)p2; size_t len = s1.length; if (s2.length < len) len = s2.length; for (size_t u = 0; u < len; u++) { if (s1[u] < s2[u]) return -1; else if (s1[u] > s2[u]) return 1; } if (s1.length < s2.length) return -1; else if (s1.length > s2.length) return 1; return 0; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(int); } } unittest { int[][] a = [[5,3,8,7], [2,5,3,8,7]]; _adSort(*cast(void[]*)&a, typeid(a[0])); assert(a == [[2,5,3,8,7], [5,3,8,7]]); a = [[5,3,8,7], [5,3,8]]; _adSort(*cast(void[]*)&a, typeid(a[0])); assert(a == [[5,3,8], [5,3,8,7]]); } unittest { // Issue 13073: original code uses int subtraction which is susceptible to // integer overflow, causing the following case to fail. int[] a = [int.max, int.max]; int[] b = [int.min, int.min]; assert(a > b); assert(b < a); } // uint[] class TypeInfo_Ak : TypeInfo_Ai { override string toString() const { return "uint[]"; } override int compare(in void* p1, in void* p2) const { uint[] s1 = *cast(uint[]*)p1; uint[] s2 = *cast(uint[]*)p2; size_t len = s1.length; if (s2.length < len) len = s2.length; for (size_t u = 0; u < len; u++) { if (s1[u] < s2[u]) return -1; else if (s1[u] > s2[u]) return 1; } if (s1.length < s2.length) return -1; else if (s1.length > s2.length) return 1; return 0; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(uint); } } unittest { // Original test case from issue 13073 uint x = 0x22_DF_FF_FF; uint y = 0xA2_DF_FF_FF; assert(!(x < y && y < x)); uint[] a = [x]; uint[] b = [y]; assert(!(a < b && b < a)); // Original failing case uint[1] a1 = [x]; uint[1] b1 = [y]; assert(!(a1 < b1 && b1 < a1)); // Original failing case } // dchar[] class TypeInfo_Aw : TypeInfo_Ak { override string toString() const { return "dchar[]"; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(dchar); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_ptr.d0000664000175000017500000000274212776214756022207 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_ptr; // internal typeinfo for any pointer type // please keep in sync with TypeInfo_Pointer class TypeInfo_P : TypeInfo { @trusted: const: pure: nothrow: override size_t getHash(in void* p) { return cast(size_t)*cast(void**)p; } override bool equals(in void* p1, in void* p2) { return *cast(void**)p1 == *cast(void**)p2; } override int compare(in void* p1, in void* p2) { if (*cast(void**)p1 < *cast(void**)p2) return -1; else if (*cast(void**)p1 > *cast(void**)p2) return 1; else return 0; } override @property size_t tsize() nothrow pure { return (void*).sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. (void*).sizeof]; } override void swap(void *p1, void *p2) { void* tmp = *cast(void**)p1; *cast(void**)p1 = *cast(void**)p2; *cast(void**)p2 = tmp; } override @property uint flags() nothrow pure const { return 1; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_long.d0000664000175000017500000000301712776214756022335 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_long; private import rt.util.hash; // long class TypeInfo_l : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "long"; } override size_t getHash(in void* p) { return rt.util.hash.hashOf(p, long.sizeof); } override bool equals(in void* p1, in void* p2) { return *cast(long *)p1 == *cast(long *)p2; } override int compare(in void* p1, in void* p2) { if (*cast(long *)p1 < *cast(long *)p2) return -1; else if (*cast(long *)p1 > *cast(long *)p2) return 1; return 0; } override @property size_t tsize() nothrow pure { return long.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. long.sizeof]; } override void swap(void *p1, void *p2) { long t; t = *cast(long *)p1; *cast(long *)p1 = *cast(long *)p2; *cast(long *)p2 = t; } override @property size_t talign() nothrow pure { return long.alignof; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Ag.d0000664000175000017500000001041712776214756021727 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Ag; private import core.stdc.string; private import rt.util.hash; private import core.internal.string; // byte[] class TypeInfo_Ag : TypeInfo_Array { override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return "byte[]"; } override size_t getHash(in void* p) @trusted const { byte[] s = *cast(byte[]*)p; return rt.util.hash.hashOf(s.ptr, s.length * byte.sizeof); } override bool equals(in void* p1, in void* p2) const { byte[] s1 = *cast(byte[]*)p1; byte[] s2 = *cast(byte[]*)p2; return s1.length == s2.length && memcmp(cast(byte *)s1, cast(byte *)s2, s1.length) == 0; } override int compare(in void* p1, in void* p2) const { byte[] s1 = *cast(byte[]*)p1; byte[] s2 = *cast(byte[]*)p2; size_t len = s1.length; if (s2.length < len) len = s2.length; for (size_t u = 0; u < len; u++) { int result = s1[u] - s2[u]; if (result) return result; } if (s1.length < s2.length) return -1; else if (s1.length > s2.length) return 1; return 0; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(byte); } } // ubyte[] class TypeInfo_Ah : TypeInfo_Ag { override string toString() const { return "ubyte[]"; } override int compare(in void* p1, in void* p2) const { char[] s1 = *cast(char[]*)p1; char[] s2 = *cast(char[]*)p2; return dstrcmp(s1, s2); } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(ubyte); } } // void[] class TypeInfo_Av : TypeInfo_Ah { override string toString() const { return "void[]"; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(void); } } // bool[] class TypeInfo_Ab : TypeInfo_Ah { override string toString() const { return "bool[]"; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(bool); } } // char[] class TypeInfo_Aa : TypeInfo_Ah { override string toString() const { return "char[]"; } override size_t getHash(in void* p) @trusted const { char[] s = *cast(char[]*)p; size_t hash = 0; version (all) { foreach (char c; s) hash = hash * 11 + c; } else { size_t len = s.length; char *str = s; while (1) { switch (len) { case 0: return hash; case 1: hash *= 9; hash += *cast(ubyte *)str; return hash; case 2: hash *= 9; hash += *cast(ushort *)str; return hash; case 3: hash *= 9; hash += (*cast(ushort *)str << 8) + (cast(ubyte *)str)[2]; return hash; default: hash *= 9; hash += *cast(uint *)str; str += 4; len -= 4; break; } } } return hash; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(char); } } // string class TypeInfo_Aya : TypeInfo_Aa { override string toString() const { return "immutable(char)[]"; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(immutable(char)); } } // const(char)[] class TypeInfo_Axa : TypeInfo_Aa { override string toString() const { return "const(char)[]"; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(const(char)); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_dchar.d0000664000175000017500000000244712776214756022465 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_dchar; // dchar class TypeInfo_w : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "dchar"; } override size_t getHash(in void* p) { return *cast(dchar *)p; } override bool equals(in void* p1, in void* p2) { return *cast(dchar *)p1 == *cast(dchar *)p2; } override int compare(in void* p1, in void* p2) { return *cast(dchar *)p1 - *cast(dchar *)p2; } override @property size_t tsize() nothrow pure { return dchar.sizeof; } override void swap(void *p1, void *p2) { dchar t; t = *cast(dchar *)p1; *cast(dchar *)p1 = *cast(dchar *)p2; *cast(dchar *)p2 = t; } override const(void)[] initializer() const @trusted { static immutable dchar c; return (&c)[0 .. 1]; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_short.d0000664000175000017500000000243512776214756022540 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_short; // short class TypeInfo_s : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "short"; } override size_t getHash(in void* p) { return *cast(short *)p; } override bool equals(in void* p1, in void* p2) { return *cast(short *)p1 == *cast(short *)p2; } override int compare(in void* p1, in void* p2) { return *cast(short *)p1 - *cast(short *)p2; } override @property size_t tsize() nothrow pure { return short.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. short.sizeof]; } override void swap(void *p1, void *p2) { short t; t = *cast(short *)p1; *cast(short *)p1 = *cast(short *)p2; *cast(short *)p2 = t; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_int.d0000664000175000017500000000256012776214756022172 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_int; // int class TypeInfo_i : TypeInfo { @trusted: const: pure: nothrow: override string toString() const pure nothrow @safe { return "int"; } override size_t getHash(in void* p) { return *cast(uint *)p; } override bool equals(in void* p1, in void* p2) { return *cast(uint *)p1 == *cast(uint *)p2; } override int compare(in void* p1, in void* p2) { if (*cast(int*) p1 < *cast(int*) p2) return -1; else if (*cast(int*) p1 > *cast(int*) p2) return 1; return 0; } override @property size_t tsize() nothrow pure { return int.sizeof; } override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. int.sizeof]; } override void swap(void *p1, void *p2) { int t; t = *cast(int *)p1; *cast(int *)p1 = *cast(int *)p2; *cast(int *)p2 = t; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/typeinfo/ti_Afloat.d0000664000175000017500000000255512776214756022612 0ustar kaikai/** * TypeInfo support code. * * Copyright: Copyright Digital Mars 2004 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.typeinfo.ti_Afloat; private import rt.util.typeinfo; // float[] class TypeInfo_Af : TypeInfo_Array { alias F = float; override bool opEquals(Object o) { return TypeInfo.opEquals(o); } override string toString() const { return (F[]).stringof; } override size_t getHash(in void* p) @trusted const { return Array!F.hashOf(*cast(F[]*)p); } override bool equals(in void* p1, in void* p2) const { return Array!F.equals(*cast(F[]*)p1, *cast(F[]*)p2); } override int compare(in void* p1, in void* p2) const { return Array!F.compare(*cast(F[]*)p1, *cast(F[]*)p2); } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(F); } } // ifloat[] class TypeInfo_Ao : TypeInfo_Af { alias F = ifloat; override string toString() const { return (F[]).stringof; } override @property inout(TypeInfo) next() inout { return cast(inout)typeid(F); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/util/0000775000175000017500000000000012776214756017654 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/rt/util/array.d0000664000175000017500000000341712776214756021144 0ustar kaikai/** Array utilities. Copyright: Denis Shelomovskij 2013 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Denis Shelomovskij Source: $(DRUNTIMESRC src/rt/util/_array.d) */ module rt.util.array; import core.internal.string; @safe /* pure dmd @@@BUG11461@@@ */ nothrow: void enforceTypedArraysConformable(T)(in char[] action, in T[] a1, in T[] a2, in bool allowOverlap = false) { _enforceSameLength(action, a1.length, a2.length); if(!allowOverlap) _enforceNoOverlap(action, a1.ptr, a2.ptr, T.sizeof * a1.length); } void enforceRawArraysConformable(in char[] action, in size_t elementSize, in void[] a1, in void[] a2, in bool allowOverlap = false) { _enforceSameLength(action, a1.length, a2.length); if(!allowOverlap) _enforceNoOverlap(action, a1.ptr, a2.ptr, elementSize * a1.length); } private void _enforceSameLength(in char[] action, in size_t length1, in size_t length2) { if(length1 == length2) return; UnsignedStringBuf tmpBuff = void; string msg = "Array lengths don't match for "; msg ~= action; msg ~= ": "; msg ~= length1.unsignedToTempString(tmpBuff, 10); msg ~= " != "; msg ~= length2.unsignedToTempString(tmpBuff, 10); throw new Error(msg); } private void _enforceNoOverlap(in char[] action, in void* ptr1, in void* ptr2, in size_t bytes) { const size_t d = ptr1 > ptr2 ? ptr1 - ptr2 : ptr2 - ptr1; if(d >= bytes) return; const overlappedBytes = bytes - d; UnsignedStringBuf tmpBuff = void; string msg = "Overlapping arrays in "; msg ~= action; msg ~= ": "; msg ~= overlappedBytes.unsignedToTempString(tmpBuff, 10); msg ~= " byte(s) overlap of "; msg ~= bytes.unsignedToTempString(tmpBuff, 10); throw new Error(msg); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/util/container/0000775000175000017500000000000012776214756021636 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/rt/util/container/array.d0000664000175000017500000000711312776214756023123 0ustar kaikai/** * Array container for internal usage. * * Copyright: Copyright Martin Nowak 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak */ module rt.util.container.array; static import common = rt.util.container.common; struct Array(T) { nothrow: @disable this(this); ~this() { reset(); } void reset() { length = 0; } @property size_t length() const { return _length; } @property void length(size_t nlength) { if (nlength < length) foreach (ref val; _ptr[nlength .. length]) common.destroy(val); _ptr = cast(T*)common.xrealloc(_ptr, nlength * T.sizeof); if (nlength > length) foreach (ref val; _ptr[length .. nlength]) common.initialize(val); _length = nlength; } @property bool empty() const { return !length; } @property ref inout(T) front() inout in { assert(!empty); } body { return _ptr[0]; } @property ref inout(T) back() inout in { assert(!empty); } body { return _ptr[_length - 1]; } ref inout(T) opIndex(size_t idx) inout in { assert(idx < length); } body { return _ptr[idx]; } inout(T)[] opSlice() inout { return _ptr[0 .. _length]; } inout(T)[] opSlice(size_t a, size_t b) inout in { assert(a < b && b <= length); } body { return _ptr[a .. b]; } alias length opDollar; void insertBack()(auto ref T val) { length = length + 1; back = val; } void popBack() { length = length - 1; } void remove(size_t idx) in { assert(idx < length); } body { foreach (i; idx .. length - 1) _ptr[i] = _ptr[i+1]; popBack(); } void swap(ref Array other) { auto ptr = _ptr; _ptr = other._ptr; other._ptr = ptr; immutable len = _length; _length = other._length; other._length = len; } private: T* _ptr; size_t _length; } unittest { Array!size_t ary; assert(ary[] == []); ary.insertBack(5); assert(ary[] == [5]); assert(ary[$-1] == 5); ary.popBack(); assert(ary[] == []); ary.insertBack(0); ary.insertBack(1); assert(ary[] == [0, 1]); assert(ary[0 .. 1] == [0]); assert(ary[1 .. 2] == [1]); assert(ary[$ - 2 .. $] == [0, 1]); size_t idx; foreach (val; ary) assert(idx++ == val); foreach_reverse (val; ary) assert(--idx == val); foreach (i, val; ary) assert(i == val); foreach_reverse (i, val; ary) assert(i == val); ary.insertBack(2); ary.remove(1); assert(ary[] == [0, 2]); assert(!ary.empty); ary.reset(); assert(ary.empty); ary.insertBack(0); assert(!ary.empty); destroy(ary); assert(ary.empty); // not copyable static assert(!__traits(compiles, { Array!size_t ary2 = ary; })); Array!size_t ary2; static assert(!__traits(compiles, ary = ary2)); static void foo(Array!size_t copy) {} static assert(!__traits(compiles, foo(ary))); ary2.insertBack(0); assert(ary.empty); assert(ary2[] == [0]); ary.swap(ary2); assert(ary[] == [0]); assert(ary2.empty); } unittest { alias RC = common.RC; Array!RC ary; size_t cnt; assert(cnt == 0); ary.insertBack(RC(&cnt)); assert(cnt == 1); ary.insertBack(RC(&cnt)); assert(cnt == 2); ary.back = ary.front; assert(cnt == 2); ary.popBack(); assert(cnt == 1); ary.popBack(); assert(cnt == 0); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/util/container/treap.d0000664000175000017500000001650112776214756023121 0ustar kaikai/** * Treap container for internal usage. * * Copyright: Copyright Digital Mars 2014 - 2014. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). */ module rt.util.container.treap; static import common = rt.util.container.common; import rt.util.random; import rt.qsort; struct Treap(E) { nothrow: static struct Node { Node* left, right; E element; uint priority; } @disable this(this); ~this() { removeAll(); } void initialize() { rand48.defaultSeed(); } void insert(E element) @nogc { root = insert(root, element); } void remove(E element) { remove(&root, element); } int opApply(scope int delegate(ref E) nothrow dg) { return (cast(const)&this).opApply((ref const E e) => dg(*cast(E*)&e)); } int opApply(scope int delegate(ref const E) nothrow dg) const { return opApplyHelper(root, dg); } version(unittest) bool opEquals(E[] elements) { size_t i; foreach (e; this) { if (i >= elements.length) return false; if (e != elements[i++]) return false; } return i == elements.length; } void removeAll() { removeAll(root); root = null; } version(unittest) bool valid() { return valid(root); } version(none) uint height() { static uint height(Node* node) { if (!node) return 0; auto left = height(node.left); auto right = height(node.right); return 1 + (left > right ? left : right); } return height(root); } version(none) size_t count() { static size_t count(Node* node) { if (!node) return 0; return count(node.left) + count(node.right) + 1; } return count(root); } private: Node* root; Rand48 rand48; Node* allocNode(E element) @nogc { Node* node = cast(Node*)common.xmalloc(Node.sizeof); node.left = node.right = null; node.priority = rand48(); node.element = element; return node; } Node* insert(Node* node, E element) @nogc { if (!node) return allocNode(element); else if (element < node.element) { node.left = insert(node.left, element); if (node.left.priority < node.priority) node = rotateR(node); } else if (element > node.element) { node.right = insert(node.right, element); if (node.right.priority < node.priority) node = rotateL(node); } else {} // ignore duplicate return node; } static: void freeNode(Node* node) { common.free(node); } Node* rotateL(Node* root) { auto pivot = root.right; root.right = pivot.left; pivot.left = root; return pivot; } Node* rotateR(Node* root) { auto pivot = root.left; root.left = pivot.right; pivot.right = root; return pivot; } void remove(Node** ppnode, E element) { Node* node = *ppnode; if (!node) return; // element not in treap if (element < node.element) { remove(&node.left, element); } else if (element > node.element) { remove(&node.right, element); } else { while (node.left && node.right) { if (node.left.priority < node.right.priority) { *ppnode = rotateR(node); ppnode = &(*ppnode).right; } else { *ppnode = rotateL(node); ppnode = &(*ppnode).left; } } if (!node.left) *ppnode = node.right; else *ppnode = node.left; freeNode(node); } } void removeAll(Node* node) { if (!node) return; removeAll(node.left); removeAll(node.right); freeNode(node); } int opApplyHelper(const Node* node, scope int delegate(ref const E) nothrow dg) { if (!node) return 0; int result = opApplyHelper(node.left, dg); if (result) return result; result = dg(node.element); if (result) return result; return opApplyHelper(node.right, dg); } version(unittest) bool valid(Node* node) { if (!node) return true; if (node.left) { if (node.left.priority < node.priority) return false; if (node.left.element > node.element) return false; } if (node.right) { if (node.right.priority < node.priority) return false; if (node.right.element < node.element) return false; } return valid(node.left) && valid(node.right); } } unittest { // randomized unittest for randomized data structure import /*cstdlib = */core.stdc.stdlib : rand, srand; import /*ctime = */core.stdc.time : time; enum OP { add, remove } enum initialSize = 1000; enum randOps = 1000; Treap!uint treap; OP[] ops; uint[] opdata; treap.initialize(); srand(cast(uint)time(null)); uint[] data; initialLoop: foreach (i; 0 .. initialSize) { data ~= rand(); treap.insert(data[$-1]); foreach (e; data[0..$-1]) if (e == data[$-1]) { data = data[0..$-1]; continue initialLoop; } } _adSort(*cast(void[]*)&data, typeid(data[0])); assert(treap == data); assert(treap.valid()); for (int i = randOps; i > 0; --i) { ops ~= cast(OP)(rand() < uint.max / 2 ? OP.add: OP.remove); opdata ~= rand(); } foreach (op; ops) { if (op == OP.add) { treap.insert(opdata[0]); size_t i; for (i = 0; i < data.length; ++i) if (data[i] >= opdata[0]) break; if (i == data.length || data[i] != opdata[0]) { // not a duplicate data.length++; uint tmp = opdata[0]; for (; i < data.length; ++i) { uint tmp2 = data[i]; data[i] = tmp; tmp = tmp2; } } } else if (!data.length) // nothing to remove { opdata = opdata[1..$]; continue; } else { uint tmp = data[opdata[0]%data.length]; treap.remove(tmp); size_t i; for (i = 0; data[i] < tmp; ++i) {} for (; i < data.length-1; ++i) data[i] = data[i+1]; data.length--; } assert(treap.valid()); assert(treap == data); opdata = opdata[1..$]; } treap.removeAll(); data.length = 0; assert(treap == data); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/util/container/common.d0000664000175000017500000000261112776214756023273 0ustar kaikai/** * Common code for writing containers. * * Copyright: Copyright Martin Nowak 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak */ module rt.util.container.common; import core.stdc.stdlib : malloc, realloc; public import core.stdc.stdlib : free; import core.internal.traits : dtorIsNothrow; nothrow: void* xrealloc(void* ptr, size_t sz) nothrow @nogc { import core.exception; if (!sz) { .free(ptr); return null; } if (auto nptr = .realloc(ptr, sz)) return nptr; .free(ptr); onOutOfMemoryError(); assert(0); } void* xmalloc(size_t sz) nothrow @nogc { import core.exception; if (auto nptr = .malloc(sz)) return nptr; onOutOfMemoryError(); assert(0); } void destroy(T)(ref T t) if (is(T == struct) && dtorIsNothrow!T) { scope (failure) assert(0); // nothrow hack object.destroy(t); } void destroy(T)(ref T t) if (!is(T == struct)) { t = T.init; } void initialize(T)(ref T t) if (is(T == struct)) { import core.stdc.string; if(auto p = typeid(T).initializer().ptr) memcpy(&t, p, T.sizeof); else memset(&t, 0, T.sizeof); } void initialize(T)(ref T t) if (!is(T == struct)) { t = T.init; } version (unittest) struct RC { nothrow: this(size_t* cnt) { ++*(_cnt = cnt); } ~this() { if (_cnt) --*_cnt; } this(this) { if (_cnt) ++*_cnt; } size_t* _cnt; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/util/container/hashtab.d0000664000175000017500000001522412776214756023421 0ustar kaikai/** * HashTab container for internal usage. * * Copyright: Copyright Martin Nowak 2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak */ module rt.util.container.hashtab; import rt.util.container.array; static import common = rt.util.container.common; struct HashTab(Key, Value) { static struct Node { Key _key; Value _value; Node* _next; } @disable this(this); ~this() { reset(); } void reset() { foreach (p; _buckets) { while (p !is null) { auto pn = p._next; common.destroy(*p); common.free(p); p = pn; } } _buckets.reset(); _length = 0; } @property size_t length() const { return _length; } @property bool empty() const { return !_length; } void remove(in Key key) in { assert(key in this); } body { ensureNotInOpApply(); immutable hash = hashOf(key) & mask; auto pp = &_buckets[hash]; while (*pp) { auto p = *pp; if (p._key == key) { *pp = p._next; common.destroy(*p); common.free(p); if (--_length < _buckets.length && _length >= 4) shrink(); return; } else { pp = &p._next; } } assert(0); } ref inout(Value) opIndex(Key key) inout { return *opIn_r(key); } void opIndexAssign(Value value, Key key) { *get(key) = value; } inout(Value)* opIn_r(in Key key) inout { if (_buckets.length) { immutable hash = hashOf(key) & mask; for (inout(Node)* p = _buckets[hash]; p !is null; p = p._next) { if (p._key == key) return &p._value; } } return null; } int opApply(scope int delegate(ref Key, ref Value) dg) { immutable save = _inOpApply; _inOpApply = true; scope (exit) _inOpApply = save; foreach (p; _buckets) { while (p !is null) { if (auto res = dg(p._key, p._value)) return res; p = p._next; } } return 0; } private: Value* get(Key key) { if (auto p = opIn_r(key)) return p; ensureNotInOpApply(); if (!_buckets.length) _buckets.length = 4; immutable hash = hashOf(key) & mask; auto p = cast(Node*)common.xmalloc(Node.sizeof); common.initialize(*p); p._key = key; p._next = _buckets[hash]; _buckets[hash] = p; if (++_length >= 2 * _buckets.length) grow(); return &p._value; } static hash_t hashOf(in ref Key key) { import rt.util.hash : hashOf; static if (is(Key U : U[])) return hashOf(cast(const ubyte*)key.ptr, key.length * key[0].sizeof); else return hashOf(cast(const ubyte*)&key, Key.sizeof); } @property hash_t mask() const { return _buckets.length - 1; } void grow() in { assert(_buckets.length); } body { immutable ocnt = _buckets.length; immutable nmask = 2 * ocnt - 1; _buckets.length = 2 * ocnt; for (size_t i = 0; i < ocnt; ++i) { auto pp = &_buckets[i]; while (*pp) { auto p = *pp; immutable nidx = hashOf(p._key) & nmask; if (nidx != i) { *pp = p._next; p._next = _buckets[nidx]; _buckets[nidx] = p; } else { pp = &p._next; } } } } void shrink() in { assert(_buckets.length >= 2); } body { immutable ocnt = _buckets.length; immutable ncnt = ocnt >> 1; immutable nmask = ncnt - 1; for (size_t i = ncnt; i < ocnt; ++i) { if (auto tail = _buckets[i]) { immutable nidx = i & nmask; auto pp = &_buckets[nidx]; while (*pp) pp = &(*pp)._next; *pp = tail; _buckets[i] = null; } } _buckets.length = ncnt; } void ensureNotInOpApply() { if (_inOpApply) assert(0, "Invalid HashTab manipulation during opApply iteration."); } Array!(Node*) _buckets; size_t _length; bool _inOpApply; } unittest { HashTab!(int, int) tab; foreach(i; 0 .. 100) tab[i] = 100 - i; foreach(i; 0 .. 100) assert(tab[i] == 100 - i); foreach (k, v; tab) assert(v == 100 - k); foreach(i; 0 .. 50) tab.remove(2 * i); assert(tab.length == 50); foreach(i; 0 .. 50) assert(tab[2 * i + 1] == 100 - 2 * i - 1); assert(tab.length == 50); tab.reset(); assert(tab.empty); tab[0] = 0; assert(!tab.empty); destroy(tab); assert(tab.empty); // not copyable static assert(!__traits(compiles, { HashTab!(int, int) tab2 = tab; })); HashTab!(int, int) tab2; static assert(!__traits(compiles, tab = tab2)); static void foo(HashTab!(int, int) copy) {} static assert(!__traits(compiles, foo(tab))); } unittest { HashTab!(string, size_t) tab; tab["foo"] = 0; assert(tab["foo"] == 0); ++tab["foo"]; assert(tab["foo"] == 1); tab["foo"]++; assert(tab["foo"] == 2); auto s = "fo"; s ~= "o"; assert(tab[s] == 2); assert(tab.length == 1); tab[s] -= 2; assert(tab[s] == 0); tab["foo"] = 12; assert(tab[s] == 12); tab.remove("foo"); assert(tab.empty); } unittest { alias RC = common.RC; HashTab!(size_t, RC) tab; size_t cnt; assert(cnt == 0); tab[0] = RC(&cnt); assert(cnt == 1); tab[1] = tab[0]; assert(cnt == 2); tab.remove(0); assert(cnt == 1); tab.remove(1); assert(cnt == 0); } unittest { import core.exception; HashTab!(uint, uint) tab; foreach (i; 0 .. 5) tab[i] = i; bool thrown; foreach (k, v; tab) { try { if (k == 3) tab.remove(k); } catch (AssertError e) { thrown = true; } } assert(thrown); assert(tab[3] == 3); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/util/typeinfo.d0000664000175000017500000001661112776214756021663 0ustar kaikai/** * This module contains utilities for TypeInfo implementation. * * Copyright: Copyright Kenji Hara 2014-. * License: Boost License 1.0. * Authors: Kenji Hara */ module rt.util.typeinfo; public import rt.util.hash; private enum isX87Real(T) = (T.sizeof == 16 && T.mant_dig == 64 && T.max_exp == 16384); template Floating(T) if (is(T == float) || is(T == double) || is(T == real)) { pure nothrow @safe: bool equals(T f1, T f2) { return f1 == f2; } int compare(T d1, T d2) { if (d1 != d1 || d2 != d2) // if either are NaN { if (d1 != d1) { if (d2 != d2) return 0; return -1; } return 1; } return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); } size_t hashOf(T value) @trusted { if (value == 0) // +0.0 and -0.0 value = 0; static if (is(T == float)) // special case? return *cast(uint*)&value; else static if (isX87Real!T) // Only consider the non-padding bytes. return rt.util.hash.hashOf(&value, 10); else return rt.util.hash.hashOf(&value, T.sizeof); } } template Floating(T) if (is(T == cfloat) || is(T == cdouble) || is(T == creal)) { pure nothrow @safe: bool equals(T f1, T f2) { return f1 == f2; } int compare(T f1, T f2) { int result; if (f1.re < f2.re) result = -1; else if (f1.re > f2.re) result = 1; else if (f1.im < f2.im) result = -1; else if (f1.im > f2.im) result = 1; else result = 0; return result; } size_t hashOf(T value) @trusted { if (value == 0 + 0i) value = 0 + 0i; static if (isX87Real!(typeof(T.init.re))) // Only consider the non-padding bytes. return rt.util.hash.hashOf(&value, 10, rt.util.hash.hashOf((cast(real*)&value) + 1, 10)); else return rt.util.hash.hashOf(&value, T.sizeof); } } template Array(T) if (is(T == float) || is(T == double) || is(T == real) || is(T == cfloat) || is(T == cdouble) || is(T == creal)) { pure nothrow @safe: bool equals(T[] s1, T[] s2) { size_t len = s1.length; if (len != s2.length) return false; for (size_t u = 0; u < len; u++) { if (!Floating!T.equals(s1[u], s2[u])) return false; } return true; } int compare(T[] s1, T[] s2) { size_t len = s1.length; if (s2.length < len) len = s2.length; for (size_t u = 0; u < len; u++) { if (int c = Floating!T.compare(s1[u], s2[u])) return c; } if (s1.length < s2.length) return -1; else if (s1.length > s2.length) return 1; return 0; } size_t hashOf(T[] value) { size_t h = 0; foreach (e; value) h += Floating!T.hashOf(e); return h; } } version(unittest) { alias TypeTuple(T...) = T; } unittest { // Bugzilla 13052 static struct SX(F) { F f; } TypeInfo ti; // real types foreach (F; TypeTuple!(float, double, real)) (){ // workaround #2396 alias S = SX!F; F f1 = +0.0, f2 = -0.0; assert(f1 == f2); assert(f1 !is f2); ti = typeid(F); assert(ti.getHash(&f1) == ti.getHash(&f2)); F[] a1 = [f1, f1, f1]; F[] a2 = [f2, f2, f2]; assert(a1 == a2); assert(a1 !is a2); ti = typeid(F[]); assert(ti.getHash(&a1) == ti.getHash(&a2)); F[][] aa1 = [a1, a1, a1]; F[][] aa2 = [a2, a2, a2]; assert(aa1 == aa2); assert(aa1 !is aa2); ti = typeid(F[][]); assert(ti.getHash(&aa1) == ti.getHash(&aa2)); S s1 = {f1}, s2 = {f2}; assert(s1 == s2); assert(s1 !is s2); ti = typeid(S); assert(ti.getHash(&s1) == ti.getHash(&s2)); S[] da1 = [S(f1), S(f1), S(f1)], da2 = [S(f2), S(f2), S(f2)]; assert(da1 == da2); assert(da1 !is da2); ti = typeid(S[]); assert(ti.getHash(&da1) == ti.getHash(&da2)); S[3] sa1 = {f1}, sa2 = {f2}; assert(sa1 == sa2); assert(sa1 !is sa2); ti = typeid(S[3]); assert(ti.getHash(&sa1) == ti.getHash(&sa2)); }(); // imaginary types foreach (F; TypeTuple!(ifloat, idouble, ireal)) (){ // workaround #2396 alias S = SX!F; F f1 = +0.0i, f2 = -0.0i; assert(f1 == f2); assert(f1 !is f2); ti = typeid(F); assert(ti.getHash(&f1) == ti.getHash(&f2)); F[] a1 = [f1, f1, f1]; F[] a2 = [f2, f2, f2]; assert(a1 == a2); assert(a1 !is a2); ti = typeid(F[]); assert(ti.getHash(&a1) == ti.getHash(&a2)); F[][] aa1 = [a1, a1, a1]; F[][] aa2 = [a2, a2, a2]; assert(aa1 == aa2); assert(aa1 !is aa2); ti = typeid(F[][]); assert(ti.getHash(&aa1) == ti.getHash(&aa2)); S s1 = {f1}, s2 = {f2}; assert(s1 == s2); assert(s1 !is s2); ti = typeid(S); assert(ti.getHash(&s1) == ti.getHash(&s2)); S[] da1 = [S(f1), S(f1), S(f1)], da2 = [S(f2), S(f2), S(f2)]; assert(da1 == da2); assert(da1 !is da2); ti = typeid(S[]); assert(ti.getHash(&da1) == ti.getHash(&da2)); S[3] sa1 = {f1}, sa2 = {f2}; assert(sa1 == sa2); assert(sa1 !is sa2); ti = typeid(S[3]); assert(ti.getHash(&sa1) == ti.getHash(&sa2)); }(); // complex types foreach (F; TypeTuple!(cfloat, cdouble, creal)) (){ // workaround #2396 alias S = SX!F; F[4] f = [+0.0 + 0.0i, +0.0 - 0.0i, -0.0 + 0.0i, -0.0 - 0.0i]; foreach (i, f1; f) foreach (j, f2; f) if (i != j) { assert(f1 == 0 + 0i); assert(f1 == f2); assert(f1 !is f2); ti = typeid(F); assert(ti.getHash(&f1) == ti.getHash(&f2)); F[] a1 = [f1, f1, f1]; F[] a2 = [f2, f2, f2]; assert(a1 == a2); assert(a1 !is a2); ti = typeid(F[]); assert(ti.getHash(&a1) == ti.getHash(&a2)); F[][] aa1 = [a1, a1, a1]; F[][] aa2 = [a2, a2, a2]; assert(aa1 == aa2); assert(aa1 !is aa2); ti = typeid(F[][]); assert(ti.getHash(&aa1) == ti.getHash(&aa2)); S s1 = {f1}, s2 = {f2}; assert(s1 == s2); assert(s1 !is s2); ti = typeid(S); assert(ti.getHash(&s1) == ti.getHash(&s2)); S[] da1 = [S(f1), S(f1), S(f1)], da2 = [S(f2), S(f2), S(f2)]; assert(da1 == da2); assert(da1 !is da2); ti = typeid(S[]); assert(ti.getHash(&da1) == ti.getHash(&da2)); S[3] sa1 = {f1}, sa2 = {f2}; assert(sa1 == sa2); assert(sa1 !is sa2); ti = typeid(S[3]); assert(ti.getHash(&sa1) == ti.getHash(&sa2)); } }(); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/util/random.d0000664000175000017500000000167012776214756021305 0ustar kaikai/** * Random number generators for internal usage. * * Copyright: Copyright Digital Mars 2014. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). */ module rt.util.random; struct Rand48 { nothrow: private ulong rng_state; void defaultSeed() { import ctime = core.stdc.time : time; seed(cast(uint)ctime.time(null)); } void seed(uint seedval) { assert(seedval); rng_state = cast(ulong)seedval << 16 | 0x330e; popFront(); } auto opCall() @nogc { auto result = front; popFront(); return result; } @property uint front() @nogc { return cast(uint)(rng_state >> 16); } void popFront() @nogc { immutable ulong a = 25214903917; immutable ulong c = 11; immutable ulong m_mask = (1uL << 48uL) - 1; rng_state = (a*rng_state+c) & m_mask; } enum empty = false; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/util/hash.d0000664000175000017500000000532412776214756020750 0ustar kaikai/** * This module contains the default hash implementation. * * Copyright: Copyright Sean Kelly 2009 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly */ /* Copyright Sean Kelly 2009 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.util.hash; version( X86 ) version = AnyX86; version( X86_64 ) version = AnyX86; version( AnyX86 ) version = HasUnalignedOps; @trusted pure nothrow size_t hashOf( const (void)* buf, size_t len, size_t seed = 0 ) { /* * This is Paul Hsieh's SuperFastHash algorithm, described here: * http://www.azillionmonkeys.com/qed/hash.html * It is protected by the following open source license: * http://www.azillionmonkeys.com/qed/weblicense.html */ static uint get16bits( const (ubyte)* x ) pure nothrow { // CTFE doesn't support casting ubyte* -> ushort*, so revert to // per-byte access when in CTFE. version( HasUnalignedOps ) { if (!__ctfe) return *cast(ushort*) x; } return ((cast(uint) x[1]) << 8) + (cast(uint) x[0]); } // NOTE: SuperFastHash normally starts with a zero hash value. The seed // value was incorporated to allow chaining. auto data = cast(const (ubyte)*) buf; auto hash = seed; int rem; if( len <= 0 || data is null ) return 0; rem = len & 3; len >>= 2; for( ; len > 0; len-- ) { hash += get16bits( data ); auto tmp = (get16bits( data + 2 ) << 11) ^ hash; hash = (hash << 16) ^ tmp; data += 2 * ushort.sizeof; hash += hash >> 11; } switch( rem ) { case 3: hash += get16bits( data ); hash ^= hash << 16; hash ^= data[ushort.sizeof] << 18; hash += hash >> 11; break; case 2: hash += get16bits( data ); hash ^= hash << 11; hash += hash >> 17; break; case 1: hash += *data; hash ^= hash << 10; hash += hash >> 1; break; default: break; } /* Force "avalanching" of final 127 bits */ hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4; hash += hash >> 17; hash ^= hash << 25; hash += hash >> 6; return hash; } // Check that hashOf works with CTFE unittest { size_t ctfeHash(string x) { return hashOf(x.ptr, x.length); } enum test_str = "Sample string"; enum size_t hashVal = ctfeHash(test_str); assert(hashVal == hashOf(test_str.ptr, test_str.length)); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/util/utf.d0000664000175000017500000005004012776214756020616 0ustar kaikai/******************************************** * Encode and decode UTF-8, UTF-16 and UTF-32 strings. * * For Win32 systems, the C wchar_t type is UTF-16 and corresponds to the D * wchar type. * For Posix systems, the C wchar_t type is UTF-32 and corresponds to * the D utf.dchar type. * * UTF character support is restricted to (\u0000 <= character <= \U0010FFFF). * * See_Also: * $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)
* $(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)
* $(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335) * Macros: * WIKI = Phobos/StdUtf * * Copyright: Copyright Digital Mars 2003 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2003 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.util.utf; extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ); /******************************* * Test if c is a valid UTF-32 character. * * \uFFFE and \uFFFF are considered valid by this function, * as they are permitted for internal use by an application, * but they are not allowed for interchange by the Unicode standard. * * Returns: true if it is, false if not. */ bool isValidDchar(dchar c) { /* Note: FFFE and FFFF are specifically permitted by the * Unicode standard for application internal use, but are not * allowed for interchange. * (thanks to Arcane Jill) */ return c < 0xD800 || (c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/); } unittest { debug(utf) printf("utf.isValidDchar.unittest\n"); assert(isValidDchar(cast(dchar)'a') == true); assert(isValidDchar(cast(dchar)0x1FFFFF) == false); } static immutable UTF8stride = [ cast(ubyte) 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF, ]; /** * stride() returns the length of a UTF-8 sequence starting at index i * in string s. * Returns: * The number of bytes in the UTF-8 sequence or * 0xFF meaning s[i] is not the start of of UTF-8 sequence. */ uint stride(in char[] s, size_t i) { return UTF8stride[s[i]]; } /** * stride() returns the length of a UTF-16 sequence starting at index i * in string s. */ uint stride(in wchar[] s, size_t i) { uint u = s[i]; return 1 + (u >= 0xD800 && u <= 0xDBFF); } /** * stride() returns the length of a UTF-32 sequence starting at index i * in string s. * Returns: The return value will always be 1. */ uint stride(in dchar[] s, size_t i) { return 1; } /******************************************* * Given an index i into an array of characters s[], * and assuming that index i is at the start of a UTF character, * determine the number of UCS characters up to that index i. */ size_t toUCSindex(in char[] s, size_t i) { size_t n; size_t j; for (j = 0; j < i; ) { j += stride(s, j); n++; } if (j > i) { onUnicodeError("invalid UTF-8 sequence", j); } return n; } /** ditto */ size_t toUCSindex(in wchar[] s, size_t i) { size_t n; size_t j; for (j = 0; j < i; ) { j += stride(s, j); n++; } if (j > i) { onUnicodeError("invalid UTF-16 sequence", j); } return n; } /** ditto */ size_t toUCSindex(in dchar[] s, size_t i) { return i; } /****************************************** * Given a UCS index n into an array of characters s[], return the UTF index. */ size_t toUTFindex(in char[] s, size_t n) { size_t i; while (n--) { uint j = UTF8stride[s[i]]; if (j == 0xFF) onUnicodeError("invalid UTF-8 sequence", i); i += j; } return i; } /** ditto */ size_t toUTFindex(in wchar[] s, size_t n) { size_t i; while (n--) { wchar u = s[i]; i += 1 + (u >= 0xD800 && u <= 0xDBFF); } return i; } /** ditto */ size_t toUTFindex(in dchar[] s, size_t n) { return n; } /* =================== Decode ======================= */ /*************** * Decodes and returns character starting at s[idx]. idx is advanced past the * decoded character. If the character is not well formed, a UtfException is * thrown and idx remains unchanged. */ dchar decode(in char[] s, ref size_t idx) in { assert(idx >= 0 && idx < s.length); } out (result) { assert(isValidDchar(result)); } body { size_t len = s.length; dchar V; size_t i = idx; char u = s[i]; if (u & 0x80) { uint n; char u2; /* The following encodings are valid, except for the 5 and 6 byte * combinations: * 0xxxxxxx * 110xxxxx 10xxxxxx * 1110xxxx 10xxxxxx 10xxxxxx * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ for (n = 1; ; n++) { if (n > 4) goto Lerr; // only do the first 4 of 6 encodings if (((u << n) & 0x80) == 0) { if (n == 1) goto Lerr; break; } } // Pick off (7 - n) significant bits of B from first byte of octet V = cast(dchar)(u & ((1 << (7 - n)) - 1)); if (i + (n - 1) >= len) goto Lerr; // off end of string /* The following combinations are overlong, and illegal: * 1100000x (10xxxxxx) * 11100000 100xxxxx (10xxxxxx) * 11110000 1000xxxx (10xxxxxx 10xxxxxx) * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) */ u2 = s[i + 1]; if ((u & 0xFE) == 0xC0 || (u == 0xE0 && (u2 & 0xE0) == 0x80) || (u == 0xF0 && (u2 & 0xF0) == 0x80) || (u == 0xF8 && (u2 & 0xF8) == 0x80) || (u == 0xFC && (u2 & 0xFC) == 0x80)) goto Lerr; // overlong combination for (uint j = 1; j != n; j++) { u = s[i + j]; if ((u & 0xC0) != 0x80) goto Lerr; // trailing bytes are 10xxxxxx V = (V << 6) | (u & 0x3F); } if (!isValidDchar(V)) goto Lerr; i += n; } else { V = cast(dchar) u; i++; } idx = i; return V; Lerr: onUnicodeError("invalid UTF-8 sequence", i); return V; // dummy return } unittest { size_t i; dchar c; debug(utf) printf("utf.decode.unittest\n"); static s1 = "abcd"c; i = 0; c = decode(s1, i); assert(c == cast(dchar)'a'); assert(i == 1); c = decode(s1, i); assert(c == cast(dchar)'b'); assert(i == 2); static s2 = "\xC2\xA9"c; i = 0; c = decode(s2, i); assert(c == cast(dchar)'\u00A9'); assert(i == 2); static s3 = "\xE2\x89\xA0"c; i = 0; c = decode(s3, i); assert(c == cast(dchar)'\u2260'); assert(i == 3); static s4 = [ "\xE2\x89"c[], // too short "\xC0\x8A", "\xE0\x80\x8A", "\xF0\x80\x80\x8A", "\xF8\x80\x80\x80\x8A", "\xFC\x80\x80\x80\x80\x8A", ]; for (int j = 0; j < s4.length; j++) { try { i = 0; c = decode(s4[j], i); assert(0); } catch (Throwable o) { i = 23; } assert(i == 23); } } /** ditto */ dchar decode(in wchar[] s, ref size_t idx) in { assert(idx >= 0 && idx < s.length); } out (result) { assert(isValidDchar(result)); } body { string msg; dchar V; size_t i = idx; uint u = s[i]; if (u & ~0x7F) { if (u >= 0xD800 && u <= 0xDBFF) { uint u2; if (i + 1 == s.length) { msg = "surrogate UTF-16 high value past end of string"; goto Lerr; } u2 = s[i + 1]; if (u2 < 0xDC00 || u2 > 0xDFFF) { msg = "surrogate UTF-16 low value out of range"; goto Lerr; } u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); i += 2; } else if (u >= 0xDC00 && u <= 0xDFFF) { msg = "unpaired surrogate UTF-16 value"; goto Lerr; } else if (u == 0xFFFE || u == 0xFFFF) { msg = "illegal UTF-16 value"; goto Lerr; } else i++; } else { i++; } idx = i; return cast(dchar)u; Lerr: onUnicodeError(msg, i); return cast(dchar)u; // dummy return } /** ditto */ dchar decode(in dchar[] s, ref size_t idx) in { assert(idx >= 0 && idx < s.length); } body { size_t i = idx; dchar c = s[i]; if (!isValidDchar(c)) goto Lerr; idx = i + 1; return c; Lerr: onUnicodeError("invalid UTF-32 value", i); return c; // dummy return } /* =================== Encode ======================= */ /******************************* * Encodes character c and appends it to array s[]. */ void encode(ref char[] s, dchar c) in { assert(isValidDchar(c)); } body { char[] r = s; if (c <= 0x7F) { r ~= cast(char) c; } else { char[4] buf; uint L; if (c <= 0x7FF) { buf[0] = cast(char)(0xC0 | (c >> 6)); buf[1] = cast(char)(0x80 | (c & 0x3F)); L = 2; } else if (c <= 0xFFFF) { buf[0] = cast(char)(0xE0 | (c >> 12)); buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[2] = cast(char)(0x80 | (c & 0x3F)); L = 3; } else if (c <= 0x10FFFF) { buf[0] = cast(char)(0xF0 | (c >> 18)); buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[3] = cast(char)(0x80 | (c & 0x3F)); L = 4; } else { assert(0); } r ~= buf[0 .. L]; } s = r; } unittest { debug(utf) printf("utf.encode.unittest\n"); char[] s = "abcd".dup; encode(s, cast(dchar)'a'); assert(s.length == 5); assert(s == "abcda"); encode(s, cast(dchar)'\u00A9'); assert(s.length == 7); assert(s == "abcda\xC2\xA9"); //assert(s == "abcda\u00A9"); // BUG: fix compiler encode(s, cast(dchar)'\u2260'); assert(s.length == 10); assert(s == "abcda\xC2\xA9\xE2\x89\xA0"); } /** ditto */ void encode(ref wchar[] s, dchar c) in { assert(isValidDchar(c)); } body { wchar[] r = s; if (c <= 0xFFFF) { r ~= cast(wchar) c; } else { wchar[2] buf; buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); r ~= buf; } s = r; } /** ditto */ void encode(ref dchar[] s, dchar c) in { assert(isValidDchar(c)); } body { s ~= c; } /** Returns the code length of $(D c) in the encoding using $(D C) as a code point. The code is returned in character count, not in bytes. */ ubyte codeLength(C)(dchar c) { static if (C.sizeof == 1) { if (c <= 0x7F) return 1; if (c <= 0x7FF) return 2; if (c <= 0xFFFF) return 3; if (c <= 0x10FFFF) return 4; assert(false); } else static if (C.sizeof == 2) { return c <= 0xFFFF ? 1 : 2; } else { static assert(C.sizeof == 4); return 1; } } /* =================== Validation ======================= */ /*********************************** Checks to see if string is well formed or not. $(D S) can be an array of $(D char), $(D wchar), or $(D dchar). Throws a $(D UtfException) if it is not. Use to check all untrusted input for correctness. */ void validate(S)(in S s) { auto len = s.length; for (size_t i = 0; i < len; ) { decode(s, i); } } /* =================== Conversion to UTF8 ======================= */ char[] toUTF8(return out char[4] buf, dchar c) in { assert(isValidDchar(c)); } body { if (c <= 0x7F) { buf[0] = cast(char) c; return buf[0 .. 1]; } else if (c <= 0x7FF) { buf[0] = cast(char)(0xC0 | (c >> 6)); buf[1] = cast(char)(0x80 | (c & 0x3F)); return buf[0 .. 2]; } else if (c <= 0xFFFF) { buf[0] = cast(char)(0xE0 | (c >> 12)); buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[2] = cast(char)(0x80 | (c & 0x3F)); return buf[0 .. 3]; } else if (c <= 0x10FFFF) { buf[0] = cast(char)(0xF0 | (c >> 18)); buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf[3] = cast(char)(0x80 | (c & 0x3F)); return buf[0 .. 4]; } assert(0); } /******************* * Encodes string s into UTF-8 and returns the encoded string. */ string toUTF8(string s) in { validate(s); } body { return s; } /** ditto */ string toUTF8(in wchar[] s) { char[] r; size_t i; size_t slen = s.length; r.length = slen; for (i = 0; i < slen; i++) { wchar c = s[i]; if (c <= 0x7F) r[i] = cast(char)c; // fast path for ascii else { r.length = i; foreach (dchar c; s[i .. slen]) { encode(r, c); } break; } } return cast(string)r; } /** ditto */ string toUTF8(in dchar[] s) { char[] r; size_t i; size_t slen = s.length; r.length = slen; for (i = 0; i < slen; i++) { dchar c = s[i]; if (c <= 0x7F) r[i] = cast(char)c; // fast path for ascii else { r.length = i; foreach (dchar d; s[i .. slen]) { encode(r, d); } break; } } return cast(string)r; } /* =================== Conversion to UTF16 ======================= */ wchar[] toUTF16(return out wchar[2] buf, dchar c) in { assert(isValidDchar(c)); } body { if (c <= 0xFFFF) { buf[0] = cast(wchar) c; return buf[0 .. 1]; } else { buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); return buf[0 .. 2]; } } /**************** * Encodes string s into UTF-16 and returns the encoded string. * toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take * an LPWSTR or LPCWSTR argument. */ wstring toUTF16(in char[] s) { wchar[] r; size_t slen = s.length; r.length = slen; r.length = 0; for (size_t i = 0; i < slen; ) { dchar c = s[i]; if (c <= 0x7F) { i++; r ~= cast(wchar)c; } else { c = decode(s, i); encode(r, c); } } return cast(wstring)r; } alias const(wchar)* wptr; /** ditto */ wptr toUTF16z(in char[] s) { wchar[] r; size_t slen = s.length; r.length = slen + 1; r.length = 0; for (size_t i = 0; i < slen; ) { dchar c = s[i]; if (c <= 0x7F) { i++; r ~= cast(wchar)c; } else { c = decode(s, i); encode(r, c); } } r ~= '\000'; return r.ptr; } /** ditto */ wstring toUTF16(wstring s) in { validate(s); } body { return s; } /** ditto */ wstring toUTF16(in dchar[] s) { wchar[] r; size_t slen = s.length; r.length = slen; r.length = 0; for (size_t i = 0; i < slen; i++) { encode(r, s[i]); } return cast(wstring)r; } /* =================== Conversion to UTF32 ======================= */ /***** * Encodes string s into UTF-32 and returns the encoded string. */ dstring toUTF32(in char[] s) { dchar[] r; size_t slen = s.length; size_t j = 0; r.length = slen; // r[] will never be longer than s[] for (size_t i = 0; i < slen; ) { dchar c = s[i]; if (c >= 0x80) c = decode(s, i); else i++; // c is ascii, no need for decode r[j++] = c; } return cast(dstring)r[0 .. j]; } /** ditto */ dstring toUTF32(in wchar[] s) { dchar[] r; size_t slen = s.length; size_t j = 0; r.length = slen; // r[] will never be longer than s[] for (size_t i = 0; i < slen; ) { dchar c = s[i]; if (c >= 0x80) c = decode(s, i); else i++; // c is ascii, no need for decode r[j++] = c; } return cast(dstring)r[0 .. j]; } /** ditto */ dstring toUTF32(dstring s) in { validate(s); } body { return s; } /* ================================ tests ================================== */ unittest { debug(utf) printf("utf.toUTF.unittest\n"); auto c = "hello"c[]; auto w = toUTF16(c); assert(w == "hello"); auto d = toUTF32(c); assert(d == "hello"); c = toUTF8(w); assert(c == "hello"); d = toUTF32(w); assert(d == "hello"); c = toUTF8(d); assert(c == "hello"); w = toUTF16(d); assert(w == "hello"); c = "hel\u1234o"; w = toUTF16(c); assert(w == "hel\u1234o"); d = toUTF32(c); assert(d == "hel\u1234o"); c = toUTF8(w); assert(c == "hel\u1234o"); d = toUTF32(w); assert(d == "hel\u1234o"); c = toUTF8(d); assert(c == "hel\u1234o"); w = toUTF16(d); assert(w == "hel\u1234o"); c = "he\U000BAAAAllo"; w = toUTF16(c); //foreach (wchar c; w) printf("c = x%x\n", c); //foreach (wchar c; cast(wstring)"he\U000BAAAAllo") printf("c = x%x\n", c); assert(w == "he\U000BAAAAllo"); d = toUTF32(c); assert(d == "he\U000BAAAAllo"); c = toUTF8(w); assert(c == "he\U000BAAAAllo"); d = toUTF32(w); assert(d == "he\U000BAAAAllo"); c = toUTF8(d); assert(c == "he\U000BAAAAllo"); w = toUTF16(d); assert(w == "he\U000BAAAAllo"); wchar[2] buf; auto ret = toUTF16(buf, '\U000BAAAA'); assert(ret == "\U000BAAAA"); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/arraydouble.d0000664000175000017500000017726212776214756021374 0ustar kaikai/** * Contains SSE2 and MMX versions of certain operations for double. * * Copyright: Copyright Digital Mars 2008 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, based on code originally written by Burton Radons; * Jim Crapuchettes (64 bit SSE code) */ /* Copyright Digital Mars 2008 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.arraydouble; // debug=PRINTF; private import core.cpuid; import rt.util.array; version (unittest) { private import core.stdc.stdio : printf; /* This is so unit tests will test every CPU variant */ int cpuid; const int CPUID_MAX = 5; nothrow: @property bool mmx() { return cpuid == 1 && core.cpuid.mmx; } @property bool sse() { return cpuid == 2 && core.cpuid.sse; } @property bool sse2() { return cpuid == 3 && core.cpuid.sse2; } @property bool amd3dnow() { return cpuid == 4 && core.cpuid.amd3dnow; } } else { alias core.cpuid.mmx mmx; alias core.cpuid.sse sse; alias core.cpuid.sse2 sse2; alias core.cpuid.amd3dnow amd3dnow; } //version = log; /* Performance figures measured by Burton Radons */ alias double T; extern (C) @trusted nothrow: /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + c[] */ T[] _arraySliceSliceAddSliceAssign_d(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 version is 333% faster if (sse2 && b.length >= 8) { auto n = aptr + (b.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov EAX, bptr; // left operand mov ECX, cptr; // right operand mov ESI, aptr; // destination operand mov EDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [EAX]; movupd XMM1, [EAX+16]; movupd XMM2, [EAX+32]; movupd XMM3, [EAX+48]; add EAX, 64; movupd XMM4, [ECX]; movupd XMM5, [ECX+16]; movupd XMM6, [ECX+32]; movupd XMM7, [ECX+48]; add ESI, 64; addpd XMM0, XMM4; addpd XMM1, XMM5; addpd XMM2, XMM6; addpd XMM3, XMM7; add ECX, 64; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopb; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (b.length >= 8) { auto n = aptr + (b.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RAX, bptr; // left operand mov RCX, cptr; // right operand mov RSI, aptr; // destination operand mov RDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [RAX]; movupd XMM1, [RAX+16]; movupd XMM2, [RAX+32]; movupd XMM3, [RAX+48]; add RAX, 64; movupd XMM4, [RCX]; movupd XMM5, [RCX+16]; movupd XMM6, [RCX+32]; movupd XMM7, [RCX+48]; add RSI, 64; addpd XMM0, XMM4; addpd XMM1, XMM5; addpd XMM2, XMM6; addpd XMM3, XMM7; add RCX, 64; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopb; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } // Handle remainder while (aptr < aend) *aptr++ = *bptr++ + *cptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceAddSliceAssign_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] + b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + b[i])) { printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - c[] */ T[] _arraySliceSliceMinSliceAssign_d(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 version is 324% faster if (sse2 && b.length >= 8) { auto n = aptr + (b.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov EAX, bptr; // left operand mov ECX, cptr; // right operand mov ESI, aptr; // destination operand mov EDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [EAX]; movupd XMM1, [EAX+16]; movupd XMM2, [EAX+32]; movupd XMM3, [EAX+48]; add EAX, 64; movupd XMM4, [ECX]; movupd XMM5, [ECX+16]; movupd XMM6, [ECX+32]; movupd XMM7, [ECX+48]; add ESI, 64; subpd XMM0, XMM4; subpd XMM1, XMM5; subpd XMM2, XMM6; subpd XMM3, XMM7; add ECX, 64; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopb; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (b.length >= 8) { auto n = aptr + (b.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RAX, bptr; // left operand mov RCX, cptr; // right operand mov RSI, aptr; // destination operand mov RDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [RAX]; movupd XMM1, [RAX+16]; movupd XMM2, [RAX+32]; movupd XMM3, [RAX+48]; add RAX, 64; movupd XMM4, [RCX]; movupd XMM5, [RCX+16]; movupd XMM6, [RCX+32]; movupd XMM7, [RCX+48]; add RSI, 64; subpd XMM0, XMM4; subpd XMM1, XMM5; subpd XMM2, XMM6; subpd XMM3, XMM7; add RCX, 64; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopb; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } // Handle remainder while (aptr < aend) *aptr++ = *bptr++ - *cptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMinSliceAssign_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] - b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - b[i])) { printf("[%d]: %g != %g - %g\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + value */ T[] _arraySliceExpAddSliceAssign_d(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceExpAddSliceAssign_d()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 version is 305% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov EAX, bptr; mov ESI, aptr; mov EDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloop: add ESI, 64; movupd XMM0, [EAX]; movupd XMM1, [EAX+16]; movupd XMM2, [EAX+32]; movupd XMM3, [EAX+48]; add EAX, 64; addpd XMM0, XMM4; addpd XMM1, XMM4; addpd XMM2, XMM4; addpd XMM3, XMM4; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloop; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RAX, bptr; mov RSI, aptr; mov RDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloop: add RSI, 64; movupd XMM0, [RAX]; movupd XMM1, [RAX+16]; movupd XMM2, [RAX+32]; movupd XMM3, [RAX+48]; add RAX, 64; addpd XMM0, XMM4; addpd XMM1, XMM4; addpd XMM2, XMM4; addpd XMM3, XMM4; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloop; mov aptr, RSI; mov bptr, RAX; } } } // Handle remainder while (aptr < aend) *aptr++ = *bptr++ + value; return a; } unittest { debug(PRINTF) printf("_arraySliceExpAddSliceAssign_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] + 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + 6)) { printf("[%d]: %g != %g + 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] += value */ T[] _arrayExpSliceAddass_d(T[] a, T value) { auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 version is 114% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (aptr < n) // Array length greater than 8 asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloopa: movupd XMM0, [ESI]; movupd XMM1, [ESI+16]; movupd XMM2, [ESI+32]; movupd XMM3, [ESI+48]; add ESI, 64; addpd XMM0, XMM4; addpd XMM1, XMM4; addpd XMM2, XMM4; addpd XMM3, XMM4; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopa; mov aptr, ESI; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (aptr < n) // Array length greater than 8 asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloopa: movupd XMM0, [RSI]; movupd XMM1, [RSI+16]; movupd XMM2, [RSI+32]; movupd XMM3, [RSI+48]; add RSI, 64; addpd XMM0, XMM4; addpd XMM1, XMM4; addpd XMM2, XMM4; addpd XMM3, XMM4; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopa; mov aptr, RSI; } } } // Handle remainder while (aptr < aend) *aptr++ += value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceAddass_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] += 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + 6)) { printf("[%d]: %g != %g + 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] += b[] */ T[] _arraySliceSliceAddass_d(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 version is 183% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov ECX, bptr; // right operand mov ESI, aptr; // destination operand mov EDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [ESI]; movupd XMM1, [ESI+16]; movupd XMM2, [ESI+32]; movupd XMM3, [ESI+48]; add ESI, 64; movupd XMM4, [ECX]; movupd XMM5, [ECX+16]; movupd XMM6, [ECX+32]; movupd XMM7, [ECX+48]; add ECX, 64; addpd XMM0, XMM4; addpd XMM1, XMM5; addpd XMM2, XMM6; addpd XMM3, XMM7; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopb; mov aptr, ESI; mov bptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RCX, bptr; // right operand mov RSI, aptr; // destination operand mov RDI, n; // end comparison test RSI,0xF; // test if a is aligned on 16-byte boundary jne notaligned; // not aligned, must use movupd instructions test RCX,0xF; // test if b is aligned on 16-byte boundary jne notaligned; // not aligned, must use movupd instructions align 8; startsseloopa: movapd XMM0, [RSI]; movapd XMM1, [RSI+16]; movapd XMM2, [RSI+32]; movapd XMM3, [RSI+48]; add RSI, 64; movapd XMM4, [RCX]; movapd XMM5, [RCX+16]; movapd XMM6, [RCX+32]; movapd XMM7, [RCX+48]; add RCX, 64; addpd XMM0, XMM4; addpd XMM1, XMM5; addpd XMM2, XMM6; addpd XMM3, XMM7; movapd [RSI+ 0-64], XMM0; movapd [RSI+16-64], XMM1; movapd [RSI+32-64], XMM2; movapd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopa; // "jump on below" jmp donesseloops; // finish up notaligned: align 8; startsseloopb: movupd XMM0, [RSI]; movupd XMM1, [RSI+16]; movupd XMM2, [RSI+32]; movupd XMM3, [RSI+48]; add RSI, 64; movupd XMM4, [RCX]; movupd XMM5, [RCX+16]; movupd XMM6, [RCX+32]; movupd XMM7, [RCX+48]; add RCX, 64; addpd XMM0, XMM4; addpd XMM1, XMM5; addpd XMM2, XMM6; addpd XMM3, XMM7; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopb; donesseloops: mov aptr, RSI; mov bptr, RCX; } } } // Handle remainder while (aptr < aend) *aptr++ += *bptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceAddass_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] += b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + b[i])) { printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - value */ T[] _arraySliceExpMinSliceAssign_d(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 version is 305% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov EAX, bptr; mov ESI, aptr; mov EDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloop: add ESI, 64; movupd XMM0, [EAX]; movupd XMM1, [EAX+16]; movupd XMM2, [EAX+32]; movupd XMM3, [EAX+48]; add EAX, 64; subpd XMM0, XMM4; subpd XMM1, XMM4; subpd XMM2, XMM4; subpd XMM3, XMM4; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloop; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RAX, bptr; mov RSI, aptr; mov RDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloop: add RSI, 64; movupd XMM0, [RAX]; movupd XMM1, [RAX+16]; movupd XMM2, [RAX+32]; movupd XMM3, [RAX+48]; add RAX, 64; subpd XMM0, XMM4; subpd XMM1, XMM4; subpd XMM2, XMM4; subpd XMM3, XMM4; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloop; mov aptr, RSI; mov bptr, RAX; } } } // Handle remainder while (aptr < aend) *aptr++ = *bptr++ - value; return a; } unittest { debug(PRINTF) printf("_arraySliceExpMinSliceAssign_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] - 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - 6)) { printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = value - b[] */ T[] _arrayExpSliceMinSliceAssign_d(T[] a, T[] b, T value) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 version is 66% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov EAX, bptr; mov ESI, aptr; mov EDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloop: add ESI, 64; movapd XMM5, XMM4; movapd XMM6, XMM4; movupd XMM0, [EAX]; movupd XMM1, [EAX+16]; movupd XMM2, [EAX+32]; movupd XMM3, [EAX+48]; add EAX, 64; subpd XMM5, XMM0; subpd XMM6, XMM1; movupd [ESI+ 0-64], XMM5; movupd [ESI+16-64], XMM6; movapd XMM5, XMM4; movapd XMM6, XMM4; subpd XMM5, XMM2; subpd XMM6, XMM3; movupd [ESI+32-64], XMM5; movupd [ESI+48-64], XMM6; cmp ESI, EDI; jb startsseloop; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RAX, bptr; mov RSI, aptr; mov RDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloop: add RSI, 64; movapd XMM5, XMM4; movapd XMM6, XMM4; movupd XMM0, [RAX]; movupd XMM1, [RAX+16]; movupd XMM2, [RAX+32]; movupd XMM3, [RAX+48]; add RAX, 64; subpd XMM5, XMM0; subpd XMM6, XMM1; movupd [RSI+ 0-64], XMM5; movupd [RSI+16-64], XMM6; movapd XMM5, XMM4; movapd XMM6, XMM4; subpd XMM5, XMM2; subpd XMM6, XMM3; movupd [RSI+32-64], XMM5; movupd [RSI+48-64], XMM6; cmp RSI, RDI; jb startsseloop; mov aptr, RSI; mov bptr, RAX; } } } // Handle remainder while (aptr < aend) *aptr++ = value - *bptr++; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinSliceAssign_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = 6 - a[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(6 - a[i])) { printf("[%d]: %g != 6 - %g\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= value */ T[] _arrayExpSliceMinass_d(T[] a, T value) { auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 version is 115% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (aptr < n) // Array length greater than 8 asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloopa: movupd XMM0, [ESI]; movupd XMM1, [ESI+16]; movupd XMM2, [ESI+32]; movupd XMM3, [ESI+48]; add ESI, 64; subpd XMM0, XMM4; subpd XMM1, XMM4; subpd XMM2, XMM4; subpd XMM3, XMM4; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopa; mov aptr, ESI; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (aptr < n) // Array length greater than 8 asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloopa: movupd XMM0, [RSI]; movupd XMM1, [RSI+16]; movupd XMM2, [RSI+32]; movupd XMM3, [RSI+48]; add RSI, 64; subpd XMM0, XMM4; subpd XMM1, XMM4; subpd XMM2, XMM4; subpd XMM3, XMM4; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopa; mov aptr, RSI; } } } // Handle remainder while (aptr < aend) *aptr++ -= value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinass_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] -= 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - 6)) { printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= b[] */ T[] _arraySliceSliceMinass_d(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 version is 183% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov ECX, bptr; // right operand mov ESI, aptr; // destination operand mov EDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [ESI]; movupd XMM1, [ESI+16]; movupd XMM2, [ESI+32]; movupd XMM3, [ESI+48]; add ESI, 64; movupd XMM4, [ECX]; movupd XMM5, [ECX+16]; movupd XMM6, [ECX+32]; movupd XMM7, [ECX+48]; add ECX, 64; subpd XMM0, XMM4; subpd XMM1, XMM5; subpd XMM2, XMM6; subpd XMM3, XMM7; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopb; mov aptr, ESI; mov bptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RCX, bptr; // right operand mov RSI, aptr; // destination operand mov RDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [RSI]; movupd XMM1, [RSI+16]; movupd XMM2, [RSI+32]; movupd XMM3, [RSI+48]; add RSI, 64; movupd XMM4, [RCX]; movupd XMM5, [RCX+16]; movupd XMM6, [RCX+32]; movupd XMM7, [RCX+48]; add RCX, 64; subpd XMM0, XMM4; subpd XMM1, XMM5; subpd XMM2, XMM6; subpd XMM3, XMM7; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopb; mov aptr, RSI; mov bptr, RCX; } } } // Handle remainder while (aptr < aend) *aptr++ -= *bptr++; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinass_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] -= 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - 6)) { printf("[%d]: %g != %g - 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] * value */ T[] _arraySliceExpMulSliceAssign_d(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 version is 304% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov EAX, bptr; mov ESI, aptr; mov EDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloop: add ESI, 64; movupd XMM0, [EAX]; movupd XMM1, [EAX+16]; movupd XMM2, [EAX+32]; movupd XMM3, [EAX+48]; add EAX, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM4; mulpd XMM2, XMM4; mulpd XMM3, XMM4; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloop; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RAX, bptr; mov RSI, aptr; mov RDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloop: add RSI, 64; movupd XMM0, [RAX]; movupd XMM1, [RAX+16]; movupd XMM2, [RAX+32]; movupd XMM3, [RAX+48]; add RAX, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM4; mulpd XMM2, XMM4; mulpd XMM3, XMM4; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloop; mov aptr, RSI; mov bptr, RAX; } } } // Handle remainder while (aptr < aend) *aptr++ = *bptr++ * value; return a; } unittest { debug(PRINTF) printf("_arraySliceExpMulSliceAssign_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] * 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * 6)) { printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] * c[] */ T[] _arraySliceSliceMulSliceAssign_d(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 version is 329% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov EAX, bptr; // left operand mov ECX, cptr; // right operand mov ESI, aptr; // destination operand mov EDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [EAX]; movupd XMM1, [EAX+16]; movupd XMM2, [EAX+32]; movupd XMM3, [EAX+48]; add ESI, 64; movupd XMM4, [ECX]; movupd XMM5, [ECX+16]; movupd XMM6, [ECX+32]; movupd XMM7, [ECX+48]; add EAX, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM5; mulpd XMM2, XMM6; mulpd XMM3, XMM7; add ECX, 64; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopb; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RAX, bptr; // left operand mov RCX, cptr; // right operand mov RSI, aptr; // destination operand mov RDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [RAX]; movupd XMM1, [RAX+16]; movupd XMM2, [RAX+32]; movupd XMM3, [RAX+48]; add RSI, 64; movupd XMM4, [RCX]; movupd XMM5, [RCX+16]; movupd XMM6, [RCX+32]; movupd XMM7, [RCX+48]; add RAX, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM5; mulpd XMM2, XMM6; mulpd XMM3, XMM7; add RCX, 64; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopb; mov aptr, RSI; mov bptr, RAX; mov cptr, RCX; } } } // Handle remainder while (aptr < aend) *aptr++ = *bptr++ * *cptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMulSliceAssign_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] * b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * b[i])) { printf("[%d]: %g != %g * %g\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] *= value */ T[] _arrayExpSliceMulass_d(T[] a, T value) { auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 version is 109% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); if (aptr < n) // Array length greater than 8 asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloopa: movupd XMM0, [ESI]; movupd XMM1, [ESI+16]; movupd XMM2, [ESI+32]; movupd XMM3, [ESI+48]; add ESI, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM4; mulpd XMM2, XMM4; mulpd XMM3, XMM4; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopa; mov aptr, ESI; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); if (aptr < n) // Array length greater than 8 asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movsd XMM4, value; shufpd XMM4, XMM4, 0; align 8; startsseloopa: movupd XMM0, [RSI]; movupd XMM1, [RSI+16]; movupd XMM2, [RSI+32]; movupd XMM3, [RSI+48]; add RSI, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM4; mulpd XMM2, XMM4; mulpd XMM3, XMM4; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopa; mov aptr, RSI; } } } // Handle remainder while (aptr < aend) *aptr++ *= value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMulass_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] *= 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * 6)) { printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] *= b[] */ T[] _arraySliceSliceMulass_d(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 version is 205% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov ECX, bptr; // right operand mov ESI, aptr; // destination operand mov EDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [ESI]; movupd XMM1, [ESI+16]; movupd XMM2, [ESI+32]; movupd XMM3, [ESI+48]; add ESI, 64; movupd XMM4, [ECX]; movupd XMM5, [ECX+16]; movupd XMM6, [ECX+32]; movupd XMM7, [ECX+48]; add ECX, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM5; mulpd XMM2, XMM6; mulpd XMM3, XMM7; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopb; mov aptr, ESI; mov bptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RCX, bptr; // right operand mov RSI, aptr; // destination operand mov RDI, n; // end comparison align 8; startsseloopb: movupd XMM0, [RSI]; movupd XMM1, [RSI+16]; movupd XMM2, [RSI+32]; movupd XMM3, [RSI+48]; add RSI, 64; movupd XMM4, [RCX]; movupd XMM5, [RCX+16]; movupd XMM6, [RCX+32]; movupd XMM7, [RCX+48]; add RCX, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM5; mulpd XMM2, XMM6; mulpd XMM3, XMM7; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopb; mov aptr, RSI; mov bptr, RCX; } } } // Handle remainder while (aptr < aend) *aptr++ *= *bptr++; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMulass_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] *= 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] * 6)) { printf("[%d]: %g != %g * 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] / value */ T[] _arraySliceExpDivSliceAssign_d(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; /* Multiplying by the reciprocal is faster, but does * not produce as accurate an answer. */ T recip = cast(T)1 / value; version (D_InlineAsm_X86) { // SSE2 version is 299% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov EAX, bptr; mov ESI, aptr; mov EDI, n; movsd XMM4, recip; shufpd XMM4, XMM4, 0; align 8; startsseloop: add ESI, 64; movupd XMM0, [EAX]; movupd XMM1, [EAX+16]; movupd XMM2, [EAX+32]; movupd XMM3, [EAX+48]; add EAX, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM4; mulpd XMM2, XMM4; mulpd XMM3, XMM4; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloop; mov aptr, ESI; mov bptr, EAX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RAX, bptr; mov RSI, aptr; mov RDI, n; movsd XMM4, recip; shufpd XMM4, XMM4, 0; align 8; startsseloop: add RSI, 64; movupd XMM0, [RAX]; movupd XMM1, [RAX+16]; movupd XMM2, [RAX+32]; movupd XMM3, [RAX+48]; add RAX, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM4; mulpd XMM2, XMM4; mulpd XMM3, XMM4; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloop; mov aptr, RSI; mov bptr, RAX; } } } // Handle remainder while (aptr < aend) { *aptr++ = *bptr++ * recip; } return a; } unittest { debug(PRINTF) printf("_arraySliceExpDivSliceAssign_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] / 8; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] / 8)) { printf("[%d]: %g != %g / 8\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] /= value */ T[] _arrayExpSliceDivass_d(T[] a, T value) { auto aptr = a.ptr; auto aend = aptr + a.length; /* Multiplying by the reciprocal is faster, but does * not produce as accurate an answer. */ T recip = cast(T)1 / value; version (D_InlineAsm_X86) { // SSE2 version is 65% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movsd XMM4, recip; shufpd XMM4, XMM4, 0; align 8; startsseloopa: movupd XMM0, [ESI]; movupd XMM1, [ESI+16]; movupd XMM2, [ESI+32]; movupd XMM3, [ESI+48]; add ESI, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM4; mulpd XMM2, XMM4; mulpd XMM3, XMM4; movupd [ESI+ 0-64], XMM0; movupd [ESI+16-64], XMM1; movupd [ESI+32-64], XMM2; movupd [ESI+48-64], XMM3; cmp ESI, EDI; jb startsseloopa; mov aptr, ESI; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RSI, aptr; mov RDI, n; movsd XMM4, recip; shufpd XMM4, XMM4, 0; align 8; startsseloopa: movupd XMM0, [RSI]; movupd XMM1, [RSI+16]; movupd XMM2, [RSI+32]; movupd XMM3, [RSI+48]; add RSI, 64; mulpd XMM0, XMM4; mulpd XMM1, XMM4; mulpd XMM2, XMM4; mulpd XMM3, XMM4; movupd [RSI+ 0-64], XMM0; movupd [RSI+16-64], XMM1; movupd [RSI+32-64], XMM2; movupd [RSI+48-64], XMM3; cmp RSI, RDI; jb startsseloopa; mov aptr, RSI; } } } // Handle remainder while (aptr < aend) *aptr++ *= recip; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceDivass_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] /= 8; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] / 8)) { printf("[%d]: %g != %g / 8\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= b[] * value */ T[] _arraySliceExpMulSliceMinass_d(T[] a, T value, T[] b) { return _arraySliceExpMulSliceAddass_d(a, -value, b); } /*********************** * Computes: * a[] += b[] * value */ T[] _arraySliceExpMulSliceAddass_d(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 version is 183% faster if (sse2 && a.length >= 8) { auto n = aptr + (a.length & ~7); asm pure nothrow @nogc { mov ECX, bptr; // right operand mov ESI, aptr; // destination operand mov EDI, n; // end comparison movsd XMM3, value; // multiplier shufpd XMM3, XMM3, 0; align 8; startsseloopb: movupd XMM4, [ECX]; movupd XMM5, [ECX+16]; add ECX, 32; // 64; movupd XMM0, [ESI]; movupd XMM1, [ESI+16]; mulpd XMM4, XMM3; mulpd XMM5, XMM3; add ESI, 32; // 64; addpd XMM0, XMM4; addpd XMM1, XMM5; movupd [ESI+ 0-32], XMM0; movupd [ESI+16-32], XMM1; cmp ESI, EDI; jb startsseloopb; mov aptr, ESI; mov bptr, ECX; } } } else version (D_InlineAsm_X86_64) { // All known X86_64 have SSE2 if (a.length >= 8) { auto n = aptr + (a.length & ~7); // Array length greater than 8 asm pure nothrow @nogc { mov RCX, bptr; // right operand mov RSI, aptr; // destination operand mov RDI, n; // end comparison movsd XMM3, value; // multiplier shufpd XMM3, XMM3, 0; align 8; startsseloopb: movupd XMM4, [RCX]; movupd XMM5, [RCX+16]; add RCX, 32; movupd XMM0, [RSI]; movupd XMM1, [RSI+16]; mulpd XMM4, XMM3; mulpd XMM5, XMM3; add RSI, 32; addpd XMM0, XMM4; addpd XMM1, XMM5; movupd [RSI+ 0-32], XMM0; movupd [RSI+16-32], XMM1; cmp RSI, RDI; jb startsseloopb; mov aptr, RSI; mov bptr, RCX; } } } // Handle remainder while (aptr < aend) *aptr++ += *bptr++ * value; return a; } unittest { debug(PRINTF) printf("_arraySliceExpMulSliceAddass_d unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 1; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } b[] = c[]; c[] += a[] * 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(b[i] + a[i] * 6)) { printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]); assert(0); } } } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/sections.d0000664000175000017500000000416012776214756020674 0ustar kaikai/** * * Copyright: Copyright Digital Mars 2000 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly, Martin Nowak * Source: $(DRUNTIMESRC src/rt/_sections.d) */ module rt.sections; version (LDC) public import rt.sections_ldc; version (CRuntime_Glibc) public import rt.sections_elf_shared; else version (FreeBSD) public import rt.sections_elf_shared; else version (Solaris) public import rt.sections_solaris; else version (OSX) public import rt.sections_osx; else version (CRuntime_DigitalMars) public import rt.sections_win32; else version (CRuntime_Microsoft) public import rt.sections_win64; else version (CRuntime_Bionic) public import rt.sections_android; else static assert(0, "unimplemented"); import rt.deh, rt.minfo; template isSectionGroup(T) { enum isSectionGroup = is(typeof(T.init.modules) == immutable(ModuleInfo*)[]) && is(typeof(T.init.moduleGroup) == ModuleGroup) && (!is(typeof(T.init.ehTables)) || is(typeof(T.init.ehTables) == immutable(FuncTable)[])) && is(typeof(T.init.gcRanges) == void[][]) && is(typeof({ foreach (ref T; T) {}})) && is(typeof({ foreach_reverse (ref T; T) {}})); } static assert(isSectionGroup!(SectionGroup)); static assert(is(typeof(&initSections) == void function())); static assert(is(typeof(&finiSections) == void function())); static assert(is(typeof(&initTLSRanges) RT == return) && is(typeof(&initTLSRanges) == RT function()) && is(typeof(&finiTLSRanges) == void function(RT)) && is(typeof(&scanTLSRanges) == void function(RT, scope void delegate(void*, void*) nothrow) nothrow)); version (Shared) { static assert(is(typeof(&pinLoadedLibraries) == void* function() nothrow)); static assert(is(typeof(&unpinLoadedLibraries) == void function(void*) nothrow)); static assert(is(typeof(&inheritLoadedLibraries) == void function(void*))); static assert(is(typeof(&cleanupLoadedLibraries) == void function())); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/monitor_.d0000664000175000017500000001535612776214756020704 0ustar kaikai/** * Contains the implementation for object monitors. * * Copyright: Copyright Digital Mars 2000 - 2015. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly, Martin Nowak */ module rt.monitor_; import core.atomic, core.stdc.stdlib, core.stdc.string; // NOTE: The dtor callback feature is only supported for monitors that are not // supplied by the user. The assumption is that any object with a user- // supplied monitor may have special storage or lifetime requirements and // that as a result, storing references to local objects within Monitor // may not be safe or desirable. Thus, devt is only valid if impl is // null. extern (C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow in { assert(ownee.__monitor is null); } body { auto m = ensureMonitor(cast(Object) owner); auto i = m.impl; if (i is null) { atomicOp!("+=")(m.refs, cast(size_t) 1); ownee.__monitor = owner.__monitor; return; } // If m.impl is set (ie. if this is a user-created monitor), assume // the monitor is garbage collected and simply copy the reference. ownee.__monitor = owner.__monitor; } extern (C) void _d_monitordelete(Object h, bool det) { auto m = getMonitor(h); if (m is null) return; if (m.impl) { // let the GC collect the monitor setMonitor(h, null); } else if (!atomicOp!("-=")(m.refs, cast(size_t) 1)) { // refcount == 0 means unshared => no synchronization required disposeEvent(cast(Monitor*) m, h); deleteMonitor(cast(Monitor*) m); setMonitor(h, null); } } extern (C) void _d_monitorenter(Object h) { auto m = cast(Monitor*) ensureMonitor(h); auto i = m.impl; if (i is null) lockMutex(&m.mtx); else i.lock(); } extern (C) void _d_monitorexit(Object h) { auto m = cast(Monitor*) getMonitor(h); auto i = m.impl; if (i is null) unlockMutex(&m.mtx); else i.unlock(); } extern (C) void rt_attachDisposeEvent(Object h, DEvent e) { synchronized (h) { auto m = cast(Monitor*) getMonitor(h); assert(m.impl is null); foreach (ref v; m.devt) { if (v is null || v == e) { v = e; return; } } auto len = m.devt.length + 4; // grow by 4 elements auto pos = m.devt.length; // insert position auto p = realloc(m.devt.ptr, DEvent.sizeof * len); import core.exception : onOutOfMemoryError; if (!p) onOutOfMemoryError(); m.devt = (cast(DEvent*) p)[0 .. len]; m.devt[pos + 1 .. len] = null; m.devt[pos] = e; } } extern (C) void rt_detachDisposeEvent(Object h, DEvent e) { synchronized (h) { auto m = cast(Monitor*) getMonitor(h); assert(m.impl is null); foreach (p, v; m.devt) { if (v == e) { memmove(&m.devt[p], &m.devt[p + 1], (m.devt.length - p - 1) * DEvent.sizeof); m.devt[$ - 1] = null; return; } } } } nothrow: extern (C) void _d_monitor_staticctor() { version (Posix) { pthread_mutexattr_init(&gattr); pthread_mutexattr_settype(&gattr, PTHREAD_MUTEX_RECURSIVE); } initMutex(&gmtx); } extern (C) void _d_monitor_staticdtor() { destroyMutex(&gmtx); version (Posix) pthread_mutexattr_destroy(&gattr); } package: // This is what the monitor reference in Object points to alias IMonitor = Object.Monitor; alias DEvent = void delegate(Object); version (Windows) { version (LDC) { // LDC implicitly links to these libraries. The explicit // mention of libcmt (non-debug) conflicts with the implicit // libcmtd (debug) link. } else version (CRuntime_DigitalMars) { pragma(lib, "snn.lib"); } else version (CRuntime_Microsoft) { pragma(lib, "libcmt.lib"); pragma(lib, "oldnames.lib"); } import core.sys.windows.windows; alias Mutex = CRITICAL_SECTION; alias initMutex = InitializeCriticalSection; alias destroyMutex = DeleteCriticalSection; alias lockMutex = EnterCriticalSection; alias unlockMutex = LeaveCriticalSection; } else version (Posix) { import core.sys.posix.pthread; alias Mutex = pthread_mutex_t; __gshared pthread_mutexattr_t gattr; void initMutex(pthread_mutex_t* mtx) { pthread_mutex_init(mtx, &gattr) && assert(0); } void destroyMutex(pthread_mutex_t* mtx) { pthread_mutex_destroy(mtx) && assert(0); } void lockMutex(pthread_mutex_t* mtx) { pthread_mutex_lock(mtx) && assert(0); } void unlockMutex(pthread_mutex_t* mtx) { pthread_mutex_unlock(mtx) && assert(0); } } else { static assert(0, "Unsupported platform"); } struct Monitor { IMonitor impl; // for user-level monitors DEvent[] devt; // for internal monitors size_t refs; // reference count Mutex mtx; } private: @property ref shared(Monitor*) monitor(Object h) pure nothrow { return *cast(shared Monitor**)&h.__monitor; } private shared(Monitor)* getMonitor(Object h) pure { return atomicLoad!(MemoryOrder.acq)(h.monitor); } void setMonitor(Object h, shared(Monitor)* m) pure { atomicStore!(MemoryOrder.rel)(h.monitor, m); } __gshared Mutex gmtx; shared(Monitor)* ensureMonitor(Object h) { if (auto m = getMonitor(h)) return m; auto m = cast(Monitor*) calloc(Monitor.sizeof, 1); assert(m); initMutex(&m.mtx); bool success; lockMutex(&gmtx); if (getMonitor(h) is null) { m.refs = 1; setMonitor(h, cast(shared) m); success = true; } unlockMutex(&gmtx); if (success) { // Set the finalize bit so that the monitor gets collected (Bugzilla 14573) import core.memory : GC; if (!(typeid(h).m_flags & TypeInfo_Class.ClassFlags.hasDtor)) GC.setAttr(cast(void*) h, GC.BlkAttr.FINALIZE); return cast(shared(Monitor)*) m; } else // another thread succeeded instead { deleteMonitor(m); return getMonitor(h); } } void deleteMonitor(Monitor* m) { destroyMutex(&m.mtx); free(m); } void disposeEvent(Monitor* m, Object h) { foreach (v; m.devt) { if (v) v(h); } if (m.devt.ptr) free(m.devt.ptr); } // Bugzilla 14573 unittest { import core.memory : GC; auto obj = new Object; assert(!(GC.getAttr(cast(void*) obj) & GC.BlkAttr.FINALIZE)); ensureMonitor(obj); assert(getMonitor(obj) !is null); assert(GC.getAttr(cast(void*) obj) & GC.BlkAttr.FINALIZE); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/lifetime.d0000664000175000017500000023615712776214756020660 0ustar kaikai/** * This module contains all functions related to an object's lifetime: * allocation, resizing, deallocation, and finalization. * * Copyright: Copyright Digital Mars 2000 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly, Steven Schveighoffer * Source: $(DRUNTIMESRC src/rt/_lifetime.d) */ module rt.lifetime; import core.stdc.stdlib; import core.stdc.string; import core.stdc.stdarg; import core.bitop; import core.memory; debug(PRINTF) import core.stdc.stdio; static import rt.tlsgc; version(LDC) import ldc.intrinsics; version(LDC) import ldc.attributes; alias BlkInfo = GC.BlkInfo; alias BlkAttr = GC.BlkAttr; import core.exception : onOutOfMemoryError, onFinalizeError, onInvalidMemoryOperationError; private { alias bool function(Object) CollectHandler; __gshared CollectHandler collectHandler = null; extern (C) void _d_monitordelete(Object h, bool det); enum : size_t { PAGESIZE = 4096, BIGLENGTHMASK = ~(PAGESIZE - 1), SMALLPAD = 1, MEDPAD = ushort.sizeof, LARGEPREFIX = 16, // 16 bytes padding at the front of the array LARGEPAD = LARGEPREFIX + 1, MAXSMALLSIZE = 256-SMALLPAD, MAXMEDSIZE = (PAGESIZE / 2) - MEDPAD } } private immutable bool callStructDtorsDuringGC; extern (C) void lifetime_init() { // this is run before static ctors, so it is safe to modify immutables import rt.config; string s = rt_configOption("callStructDtorsDuringGC"); if (s != null) cast() callStructDtorsDuringGC = s[0] == '1' || s[0] == 'y' || s[0] == 'Y'; else cast() callStructDtorsDuringGC = true; } /** * */ extern (C) void* _d_allocmemory(size_t sz) @weak // LDC { return GC.malloc(sz); } version (LDC) { /** * for allocating a single POD value */ extern (C) void* _d_allocmemoryT(TypeInfo ti) @weak // LDC { return GC.malloc(ti.tsize(), !(ti.flags() & 1) ? BlkAttr.NO_SCAN : 0); } } // version (LDC) // adapted for LDC pragma(inline, true) private extern (D) Object _d_newclass(bool initialize)(const ClassInfo ci) { void* p; debug(PRINTF) printf("_d_newclass(ci = %p, %s)\n", ci, cast(char *)ci.name); if (ci.m_flags & TypeInfo_Class.ClassFlags.isCOMclass) { /* COM objects are not garbage collected, they are reference counted * using AddRef() and Release(). They get free'd by C's free() * function called by Release() when Release()'s reference count goes * to zero. */ p = malloc(ci.initializer.length); if (!p) onOutOfMemoryError(); } else { // TODO: should this be + 1 to avoid having pointers to the next block? BlkAttr attr = BlkAttr.NONE; // extern(C++) classes don't have a classinfo pointer in their vtable so the GC can't finalize them if (ci.m_flags & TypeInfo_Class.ClassFlags.hasDtor && !(ci.m_flags & TypeInfo_Class.ClassFlags.isCPPclass)) attr |= BlkAttr.FINALIZE; if (ci.m_flags & TypeInfo_Class.ClassFlags.noPointers) attr |= BlkAttr.NO_SCAN; p = GC.malloc(ci.initializer.length, attr, ci); debug(PRINTF) printf(" p = %p\n", p); } debug(PRINTF) { printf("p = %p\n", p); printf("ci = %p, ci.init.ptr = %p, len = %llu\n", ci, ci.initializer.ptr, cast(ulong)ci.initializer.length); printf("vptr = %p\n", *cast(void**) ci.initializer); printf("vtbl[0] = %p\n", (*cast(void***) ci.initializer)[0]); printf("vtbl[1] = %p\n", (*cast(void***) ci.initializer)[1]); printf("init[0] = %x\n", (cast(uint*) ci.initializer)[0]); printf("init[1] = %x\n", (cast(uint*) ci.initializer)[1]); printf("init[2] = %x\n", (cast(uint*) ci.initializer)[2]); printf("init[3] = %x\n", (cast(uint*) ci.initializer)[3]); printf("init[4] = %x\n", (cast(uint*) ci.initializer)[4]); } static if (initialize) // LDC { // initialize it p[0 .. ci.initializer.length] = ci.initializer[]; } debug(PRINTF) printf("initialization done\n"); return cast(Object) p; } version (LDC) { /** * */ extern (C) Object _d_newclass(const ClassInfo ci) @weak { return _d_newclass!true(ci); } // Initialization is performed in DtoNewClass(), so only allocate // the class in druntime (LDC issue #966). extern (C) Object _d_allocclass(const ClassInfo ci) @weak { return _d_newclass!false(ci); } } /** * */ extern (C) void _d_delinterface(void** p) { if (*p) { Interface* pi = **cast(Interface ***)*p; Object o = cast(Object)(*p - pi.offset); _d_delclass(&o); *p = null; } } // used for deletion private extern (D) alias void function (Object) fp_t; /** * */ extern (C) void _d_delclass(Object* p) @weak // LDC { if (*p) { debug(PRINTF) printf("_d_delclass(%p)\n", *p); ClassInfo **pc = cast(ClassInfo **)*p; if (*pc) { ClassInfo c = **pc; rt_finalize(cast(void*) *p); if (c.deallocator) { fp_t fp = cast(fp_t)c.deallocator; (*fp)(*p); // call deallocator *p = null; return; } } else { rt_finalize(cast(void*) *p); } GC.free(cast(void*) *p); *p = null; } } /** * This is called for a delete statement where the value * being deleted is a pointer to a struct with a destructor * but doesn't have an overloaded delete operator. */ extern (C) void _d_delstruct(void** p, TypeInfo_Struct inf) @weak // LDC { if (*p) { debug(PRINTF) printf("_d_delstruct(%p, %p)\n", *p, cast(void*)inf); inf.destroy(*p); GC.free(*p); *p = null; } } // strip const/immutable/shared/inout from type info inout(TypeInfo) unqualify(inout(TypeInfo) cti) pure nothrow @nogc { version (LDC) { /* Fix for object_.d/object.di madness. * * If object.di is imported (standard case): * - there is no field base * - field next returns the next typeinfo * * If object_.d is imported (compile all module at once) * - field base is defined and returns next typeinfo * - virtual property next returns next-after-next typeinfo * * Solution: * A new alias base is added to object.di. * Each caller of unqualify() is changed from * unqualify(ti.next) * to * unqualify(unqualify(ti).next) * This ensures that the array is unqualified and then the base type of * the array is unqualified. * * Depending on the import the field base or the alias base is used. * * Related to DMD bugs 3806 and 8656. */ } TypeInfo ti = cast() cti; while (ti) { // avoid dynamic type casts auto tti = typeid(ti); if (tti is typeid(TypeInfo_Const)) ti = (cast(TypeInfo_Const)cast(void*)ti).base; else if (tti is typeid(TypeInfo_Invariant)) ti = (cast(TypeInfo_Invariant)cast(void*)ti).base; else if (tti is typeid(TypeInfo_Shared)) ti = (cast(TypeInfo_Shared)cast(void*)ti).base; else if (tti is typeid(TypeInfo_Inout)) ti = (cast(TypeInfo_Inout)cast(void*)ti).base; else break; } return ti; } // size used to store the TypeInfo at the end of an allocation for structs that have a destructor size_t structTypeInfoSize(const TypeInfo ti) pure nothrow @nogc { if (!callStructDtorsDuringGC) return 0; if (ti && typeid(ti) is typeid(TypeInfo_Struct)) // avoid a complete dynamic type cast { auto sti = cast(TypeInfo_Struct)cast(void*)ti; if (sti.xdtor) return size_t.sizeof; } return 0; } /** dummy class used to lock for shared array appending */ private class ArrayAllocLengthLock {} /** Set the allocated length of the array block. This is called any time an array is appended to or its length is set. The allocated block looks like this for blocks < PAGESIZE: |elem0|elem1|elem2|...|elemN-1|emptyspace|N*elemsize| The size of the allocated length at the end depends on the block size: a block of 16 to 256 bytes has an 8-bit length. a block with 512 to pagesize/2 bytes has a 16-bit length. For blocks >= pagesize, the length is a size_t and is at the beginning of the block. The reason we have to do this is because the block can extend into more pages, so we cannot trust the block length if it sits at the end of the block, because it might have just been extended. If we can prove in the future that the block is unshared, we may be able to change this, but I'm not sure it's important. In order to do put the length at the front, we have to provide 16 bytes buffer space in case the block has to be aligned properly. In x86, certain SSE instructions will only work if the data is 16-byte aligned. In addition, we need the sentinel byte to prevent accidental pointers to the next block. Because of the extra overhead, we only do this for page size and above, where the overhead is minimal compared to the block size. So for those blocks, it looks like: |N*elemsize|padding|elem0|elem1|...|elemN-1|emptyspace|sentinelbyte| where elem0 starts 16 bytes after the first byte. */ bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, const TypeInfo tinext, size_t oldlength = ~0) pure nothrow { import core.atomic; size_t typeInfoSize = structTypeInfoSize(tinext); if(info.size <= 256) { if(newlength + SMALLPAD + typeInfoSize > info.size) // new size does not fit inside block return false; auto length = cast(ubyte *)(info.base + info.size - typeInfoSize - SMALLPAD); if(oldlength != ~0) { if(isshared) { return cas(cast(shared)length, cast(ubyte)oldlength, cast(ubyte)newlength); } else { if(*length == cast(ubyte)oldlength) *length = cast(ubyte)newlength; else return false; } } else { // setting the initial length, no cas needed *length = cast(ubyte)newlength; } if (typeInfoSize) { auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof); *typeInfo = cast() tinext; } } else if(info.size < PAGESIZE) { if(newlength + MEDPAD + typeInfoSize > info.size) // new size does not fit inside block return false; auto length = cast(ushort *)(info.base + info.size - typeInfoSize - MEDPAD); if(oldlength != ~0) { if(isshared) { return cas(cast(shared)length, cast(ushort)oldlength, cast(ushort)newlength); } else { if(*length == oldlength) *length = cast(ushort)newlength; else return false; } } else { // setting the initial length, no cas needed *length = cast(ushort)newlength; } if (typeInfoSize) { auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof); *typeInfo = cast() tinext; } } else { if(newlength + LARGEPAD > info.size) // new size does not fit inside block return false; auto length = cast(size_t *)(info.base); if(oldlength != ~0) { if(isshared) { return cas(cast(shared)length, cast(size_t)oldlength, cast(size_t)newlength); } else { if(*length == oldlength) *length = newlength; else return false; } } else { // setting the initial length, no cas needed *length = newlength; } if (typeInfoSize) { auto typeInfo = cast(TypeInfo*)(info.base + size_t.sizeof); *typeInfo = cast()tinext; } } return true; // resize succeeded } /** get the allocation size of the array for the given block (without padding or type info) */ size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure nothrow { if(info.size <= 256) return *cast(ubyte *)(info.base + info.size - structTypeInfoSize(tinext) - SMALLPAD); if(info.size < PAGESIZE) return *cast(ushort *)(info.base + info.size - structTypeInfoSize(tinext) - MEDPAD); return *cast(size_t *)(info.base); } /** get the start of the array for the given block */ void *__arrayStart(BlkInfo info) nothrow pure { return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0); } /** get the padding required to allocate size bytes. Note that the padding is NOT included in the passed in size. Therefore, do NOT call this function with the size of an allocated block. */ size_t __arrayPad(size_t size, const TypeInfo tinext) nothrow pure @trusted { return size > MAXMEDSIZE ? LARGEPAD : ((size > MAXSMALLSIZE ? MEDPAD : SMALLPAD) + structTypeInfoSize(tinext)); } /** allocate an array memory block by applying the proper padding and assigning block attributes if not inherited from the existing block */ BlkInfo __arrayAlloc(size_t arrsize, const TypeInfo ti, const TypeInfo tinext) nothrow pure { size_t typeInfoSize = structTypeInfoSize(tinext); size_t padsize = arrsize > MAXMEDSIZE ? LARGEPAD : ((arrsize > MAXSMALLSIZE ? MEDPAD : SMALLPAD) + typeInfoSize); if (arrsize + padsize < arrsize) return BlkInfo(); uint attr = (!(tinext.flags & 1) ? BlkAttr.NO_SCAN : 0) | BlkAttr.APPENDABLE; if (typeInfoSize) attr |= BlkAttr.STRUCTFINAL | BlkAttr.FINALIZE; return GC.qalloc(arrsize + padsize, attr, ti); } BlkInfo __arrayAlloc(size_t arrsize, ref BlkInfo info, const TypeInfo ti, const TypeInfo tinext) { if (!info.base) return __arrayAlloc(arrsize, ti, tinext); return GC.qalloc(arrsize + __arrayPad(arrsize, tinext), info.attr, ti); } /** cache for the lookup of the block info */ enum N_CACHE_BLOCKS=8; // note this is TLS, so no need to sync. BlkInfo *__blkcache_storage; static if(N_CACHE_BLOCKS==1) { version=single_cache; } else { //version=simple_cache; // uncomment to test simple cache strategy //version=random_cache; // uncomment to test random cache strategy // ensure N_CACHE_BLOCKS is power of 2. static assert(!((N_CACHE_BLOCKS - 1) & N_CACHE_BLOCKS)); version(random_cache) { int __nextRndNum = 0; } int __nextBlkIdx; } @property BlkInfo *__blkcache() nothrow { if(!__blkcache_storage) { // allocate the block cache for the first time immutable size = BlkInfo.sizeof * N_CACHE_BLOCKS; __blkcache_storage = cast(BlkInfo *)malloc(size); memset(__blkcache_storage, 0, size); } return __blkcache_storage; } // called when thread is exiting. static ~this() { // free the blkcache if(__blkcache_storage) { free(__blkcache_storage); __blkcache_storage = null; } } // we expect this to be called with the lock in place void processGCMarks(BlkInfo* cache, scope rt.tlsgc.IsMarkedDg isMarked) nothrow { // called after the mark routine to eliminate block cache data when it // might be ready to sweep debug(PRINTF) printf("processing GC Marks, %x\n", cache); if(cache) { debug(PRINTF) foreach(i; 0 .. N_CACHE_BLOCKS) { printf("cache entry %d has base ptr %x\tsize %d\tflags %x\n", i, cache[i].base, cache[i].size, cache[i].attr); } auto cache_end = cache + N_CACHE_BLOCKS; for(;cache < cache_end; ++cache) { if(cache.base != null && !isMarked(cache.base)) { debug(PRINTF) printf("clearing cache entry at %x\n", cache.base); cache.base = null; // clear that data. } } } } unittest { // Bugzilla 10701 - segfault in GC ubyte[] result; result.length = 4096; GC.free(result.ptr); GC.collect(); } /** Get the cached block info of an interior pointer. Returns null if the interior pointer's block is not cached. NOTE: The base ptr in this struct can be cleared asynchronously by the GC, so any use of the returned BlkInfo should copy it and then check the base ptr of the copy before actually using it. TODO: Change this function so the caller doesn't have to be aware of this issue. Either return by value and expect the caller to always check the base ptr as an indication of whether the struct is valid, or set the BlkInfo as a side-effect and return a bool to indicate success. */ BlkInfo *__getBlkInfo(void *interior) nothrow { BlkInfo *ptr = __blkcache; version(single_cache) { if(ptr.base && ptr.base <= interior && (interior - ptr.base) < ptr.size) return ptr; return null; // not in cache. } else version(simple_cache) { foreach(i; 0..N_CACHE_BLOCKS) { if(ptr.base && ptr.base <= interior && (interior - ptr.base) < ptr.size) return ptr; ptr++; } } else { // try to do a smart lookup, using __nextBlkIdx as the "head" auto curi = ptr + __nextBlkIdx; for(auto i = curi; i >= ptr; --i) { if(i.base && i.base <= interior && cast(size_t)(interior - i.base) < i.size) return i; } for(auto i = ptr + N_CACHE_BLOCKS - 1; i > curi; --i) { if(i.base && i.base <= interior && cast(size_t)(interior - i.base) < i.size) return i; } } return null; // not in cache. } void __insertBlkInfoCache(BlkInfo bi, BlkInfo *curpos) nothrow { version(single_cache) { *__blkcache = bi; } else { version(simple_cache) { if(curpos) *curpos = bi; else { // note, this is a super-simple algorithm that does not care about // most recently used. It simply uses a round-robin technique to // cache block info. This means that the ordering of the cache // doesn't mean anything. Certain patterns of allocation may // render the cache near-useless. __blkcache[__nextBlkIdx] = bi; __nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1); } } else version(random_cache) { // strategy: if the block currently is in the cache, move the // current block index to the a random element and evict that // element. auto cache = __blkcache; if(!curpos) { __nextBlkIdx = (__nextRndNum = 1664525 * __nextRndNum + 1013904223) & (N_CACHE_BLOCKS - 1); curpos = cache + __nextBlkIdx; } else { __nextBlkIdx = curpos - cache; } *curpos = bi; } else { // // strategy: If the block currently is in the cache, swap it with // the head element. Otherwise, move the head element up by one, // and insert it there. // auto cache = __blkcache; if(!curpos) { __nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1); curpos = cache + __nextBlkIdx; } else if(curpos !is cache + __nextBlkIdx) { *curpos = cache[__nextBlkIdx]; curpos = cache + __nextBlkIdx; } *curpos = bi; } } } /** * Shrink the "allocated" length of an array to be the exact size of the array. * It doesn't matter what the current allocated length of the array is, the * user is telling the runtime that he knows what he is doing. */ extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) /+nothrow+/ { // note, we do not care about shared. We are setting the length no matter // what, so no lock is required. debug(PRINTF) printf("_d_arrayshrinkfit, elemsize = %d, arr.ptr = x%x arr.length = %d\n", ti.next.tsize, arr.ptr, arr.length); version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto size = tinext.tsize; // array element size auto cursize = arr.length * size; auto isshared = typeid(ti) is typeid(TypeInfo_Shared); auto bic = isshared ? null : __getBlkInfo(arr.ptr); auto info = bic ? *bic : GC.query(arr.ptr); if(info.base && (info.attr & BlkAttr.APPENDABLE)) { auto newsize = (arr.ptr - __arrayStart(info)) + cursize; debug(PRINTF) printf("setting allocated size to %d\n", (arr.ptr - info.base) + cursize); // destroy structs that become unused memory when array size is shrinked if (typeid(tinext) is typeid(TypeInfo_Struct)) // avoid a complete dynamic type cast { auto sti = cast(TypeInfo_Struct)cast(void*)tinext; if (sti.xdtor) { auto oldsize = __arrayAllocLength(info, tinext); if (oldsize > cursize) finalize_array(arr.ptr + cursize, oldsize - cursize, sti); } } // Note: Since we "assume" the append is safe, it means it is not shared. // Since it is not shared, we also know it won't throw (no lock). if (!__setArrayAllocLength(info, newsize, false, tinext)) onInvalidMemoryOperationError(); // cache the block if not already done. if (!isshared && !bic) __insertBlkInfoCache(info, null); } } package bool hasPostblit(in TypeInfo ti) { return (&ti.postblit).funcptr !is &TypeInfo.postblit; } void __doPostblit(void *ptr, size_t len, const TypeInfo ti) { if (!hasPostblit(ti)) return; if(auto tis = cast(TypeInfo_Struct)ti) { // this is a struct, check the xpostblit member auto pblit = tis.xpostblit; if(!pblit) // postblit not specified, no point in looping. return; // optimized for struct, call xpostblit directly for each element immutable size = ti.tsize; const eptr = ptr + len; for(;ptr < eptr;ptr += size) pblit(ptr); } else { // generic case, call the typeinfo's postblit function immutable size = ti.tsize; const eptr = ptr + len; for(;ptr < eptr;ptr += size) ti.postblit(ptr); } } /** * set the array capacity. If the array capacity isn't currently large enough * to hold the requested capacity (in number of elements), then the array is * resized/reallocated to the appropriate size. Pass in a requested capacity * of 0 to get the current capacity. Returns the number of elements that can * actually be stored once the resizing is done. */ extern(C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* p) @weak // LDC in { assert(ti); assert(!(*p).length || (*p).ptr); } body { // step 1, get the block auto isshared = typeid(ti) is typeid(TypeInfo_Shared); auto bic = isshared ? null : __getBlkInfo((*p).ptr); auto info = bic ? *bic : GC.query((*p).ptr); version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto size = tinext.tsize; version (LDC) { auto umul = llvm_umul_with_overflow!size_t(size, newcapacity); size_t reqsize = umul.result; if (!umul.overflow) goto Lcontinue; } else version (D_InlineAsm_X86) { size_t reqsize = void; asm { mov EAX, newcapacity; mul EAX, size; mov reqsize, EAX; jnc Lcontinue; } } else version (D_InlineAsm_X86_64) { size_t reqsize = void; asm { mov RAX, newcapacity; mul RAX, size; mov reqsize, RAX; jnc Lcontinue; } } else { import core.checkedint : mulu; bool overflow = false; size_t reqsize = mulu(size, newcapacity, overflow); if (!overflow) goto Lcontinue; } Loverflow: onOutOfMemoryError(); assert(0); Lcontinue: // step 2, get the actual "allocated" size. If the allocated size does not // match what we expect, then we will need to reallocate anyways. // TODO: this probably isn't correct for shared arrays size_t curallocsize = void; size_t curcapacity = void; size_t offset = void; size_t arraypad = void; if(info.base && (info.attr & BlkAttr.APPENDABLE)) { if(info.size <= 256) { arraypad = SMALLPAD + structTypeInfoSize(tinext); curallocsize = *(cast(ubyte *)(info.base + info.size - arraypad)); } else if(info.size < PAGESIZE) { arraypad = MEDPAD + structTypeInfoSize(tinext); curallocsize = *(cast(ushort *)(info.base + info.size - arraypad)); } else { curallocsize = *(cast(size_t *)(info.base)); arraypad = LARGEPAD; } offset = (*p).ptr - __arrayStart(info); if(offset + (*p).length * size != curallocsize) { curcapacity = 0; } else { // figure out the current capacity of the block from the point // of view of the array. curcapacity = info.size - offset - arraypad; } } else { curallocsize = curcapacity = offset = 0; } debug(PRINTF) printf("_d_arraysetcapacity, p = x%d,%d, newcapacity=%d, info.size=%d, reqsize=%d, curallocsize=%d, curcapacity=%d, offset=%d\n", (*p).ptr, (*p).length, newcapacity, info.size, reqsize, curallocsize, curcapacity, offset); if(curcapacity >= reqsize) { // no problems, the current allocated size is large enough. return curcapacity / size; } // step 3, try to extend the array in place. if(info.size >= PAGESIZE && curcapacity != 0) { auto extendsize = reqsize + offset + LARGEPAD - info.size; auto u = GC.extend(info.base, extendsize, extendsize); if(u) { // extend worked, save the new current allocated size if(bic) bic.size = u; // update cache curcapacity = u - offset - LARGEPAD; return curcapacity / size; } } // step 4, if extending doesn't work, allocate a new array with at least the requested allocated size. auto datasize = (*p).length * size; // copy attributes from original block, or from the typeinfo if the // original block doesn't exist. info = __arrayAlloc(reqsize, info, ti, tinext); if(info.base is null) goto Loverflow; // copy the data over. // note that malloc will have initialized the data we did not request to 0. auto tgt = __arrayStart(info); memcpy(tgt, (*p).ptr, datasize); // handle postblit __doPostblit(tgt, datasize, tinext); if(!(info.attr & BlkAttr.NO_SCAN)) { // need to memset the newly requested data, except for the data that // malloc returned that we didn't request. void *endptr = tgt + reqsize; void *begptr = tgt + datasize; // sanity check assert(endptr >= begptr); memset(begptr, 0, endptr - begptr); } // set up the correct length __setArrayAllocLength(info, datasize, isshared, tinext); if(!isshared) __insertBlkInfoCache(info, bic); *p = (cast(void*)tgt)[0 .. (*p).length]; // determine the padding. This has to be done manually because __arrayPad // assumes you are not counting the pad size, and info.size does include // the pad. if(info.size <= 256) arraypad = SMALLPAD + structTypeInfoSize(tinext); else if(info.size < PAGESIZE) arraypad = MEDPAD + structTypeInfoSize(tinext); else arraypad = LARGEPAD; curcapacity = info.size - arraypad; return curcapacity / size; } /** * Allocate a new uninitialized array of length elements. * ti is the type of the resulting array, or pointer to element. */ extern (C) void[] _d_newarrayU(const TypeInfo ti, size_t length) pure nothrow @weak // LDC { version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto size = tinext.tsize; debug(PRINTF) printf("_d_newarrayU(length = x%x, size = %d)\n", length, size); if (length == 0 || size == 0) return null; version (LDC) { auto umul = llvm_umul_with_overflow!size_t(size, length); size = umul.result; if (!umul.overflow) goto Lcontinue; } else version (D_InlineAsm_X86) { asm pure nothrow @nogc { mov EAX,size ; mul EAX,length ; mov size,EAX ; jnc Lcontinue ; } } else version(D_InlineAsm_X86_64) { asm pure nothrow @nogc { mov RAX,size ; mul RAX,length ; mov size,RAX ; jnc Lcontinue ; } } else { import core.checkedint : mulu; bool overflow = false; size = mulu(size, length, overflow); if (!overflow) goto Lcontinue; } Loverflow: onOutOfMemoryError(); assert(0); Lcontinue: auto info = __arrayAlloc(size, ti, tinext); if (!info.base) goto Loverflow; debug(PRINTF) printf(" p = %p\n", info.base); // update the length of the array auto arrstart = __arrayStart(info); auto isshared = typeid(ti) is typeid(TypeInfo_Shared); __setArrayAllocLength(info, size, isshared, tinext); return arrstart[0..length]; } /** * Allocate a new array of length elements. * ti is the type of the resulting array, or pointer to element. * (For when the array is initialized to 0) */ extern (C) void[] _d_newarrayT(const TypeInfo ti, size_t length) pure nothrow @weak // LDC { void[] result = _d_newarrayU(ti, length); version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto size = tinext.tsize; memset(result.ptr, 0, size * length); return result; } /** * For when the array has a non-zero initializer. */ extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) pure nothrow @weak // LDC { import core.internal.traits : TypeTuple; void[] result = _d_newarrayU(ti, length); version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto size = tinext.tsize; auto init = tinext.initializer(); switch (init.length) { foreach (T; TypeTuple!(ubyte, ushort, uint, ulong)) { case T.sizeof: (cast(T*)result.ptr)[0 .. size * length / T.sizeof] = *cast(T*)init.ptr; return result; } default: { immutable sz = init.length; for (size_t u = 0; u < size * length; u += sz) memcpy(result.ptr + u, init.ptr, sz); return result; } } } /** * */ void[] _d_newarrayOpT(alias op)(const TypeInfo ti, size_t[] dims) @weak // LDC { debug(PRINTF) printf("_d_newarrayOpT(ndims = %d)\n", dims.length); if (dims.length == 0) return null; void[] foo(const TypeInfo ti, size_t[] dims) { version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto dim = dims[0]; debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, dims.length); if (dims.length == 1) { auto r = op(ti, dim); return *cast(void[]*)(&r); } auto allocsize = (void[]).sizeof * dim; auto info = __arrayAlloc(allocsize, ti, tinext); auto isshared = typeid(ti) is typeid(TypeInfo_Shared); __setArrayAllocLength(info, allocsize, isshared, tinext); auto p = __arrayStart(info)[0 .. dim]; foreach(i; 0..dim) { (cast(void[]*)p.ptr)[i] = foo(tinext, dims[1..$]); } return p; } auto result = foo(ti, dims); debug(PRINTF) printf("result = %llx\n", result.ptr); return result; } /** * */ extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims) @weak // LDC { debug(PRINTF) printf("_d_newarraymT(dims.length = %d)\n", dims.length); if (dims.length == 0) return null; else { return _d_newarrayOpT!(_d_newarrayT)(ti, dims); } } /** * */ extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) @weak // LDC { debug(PRINTF) printf("_d_newarraymiT(dims.length = %d)\n", dims.length); if (dims.length == 0) return null; else { return _d_newarrayOpT!(_d_newarrayiT)(ti, dims); } } /** * Allocate an uninitialized non-array item. * This is an optimization to avoid things needed for arrays like the __arrayPad(size). */ extern (C) void* _d_newitemU(in TypeInfo _ti) @weak // LDC { auto ti = unqualify(_ti); auto flags = !(ti.flags & 1) ? BlkAttr.NO_SCAN : 0; immutable tiSize = structTypeInfoSize(ti); immutable size = ti.tsize + tiSize; if (tiSize) flags |= BlkAttr.STRUCTFINAL | BlkAttr.FINALIZE; auto blkInf = GC.qalloc(size, flags, ti); auto p = blkInf.base; if (tiSize) *cast(TypeInfo*)(p + blkInf.size - tiSize) = cast() ti; return p; } /// Same as above, zero initializes the item. extern (C) void* _d_newitemT(in TypeInfo _ti) @weak // LDC { auto p = _d_newitemU(_ti); memset(p, 0, _ti.tsize); return p; } /// Same as above, for item with non-zero initializer. extern (C) void* _d_newitemiT(in TypeInfo _ti) @weak // LDC { auto p = _d_newitemU(_ti); auto init = _ti.initializer(); assert(init.length <= _ti.tsize); memcpy(p, init.ptr, init.length); return p; } /** * */ struct Array { size_t length; byte* data; } /** * This function has been replaced by _d_delarray_t */ extern (C) void _d_delarray(void[]* p) @weak // LDC { _d_delarray_t(p, null); } debug(PRINTF) { extern(C) void printArrayCache() { auto ptr = __blkcache; printf("CACHE: \n"); foreach(i; 0 .. N_CACHE_BLOCKS) { printf(" %d\taddr:% .8x\tsize:% .10d\tflags:% .8x\n", i, ptr[i].base, ptr[i].size, ptr[i].attr); } } } /** * */ extern (C) void _d_delarray_t(void[]* p, const TypeInfo_Struct ti) @weak // LDC { if (p) { auto bic = __getBlkInfo(p.ptr); auto info = bic ? *bic : GC.query(p.ptr); if (info.base && (info.attr & BlkAttr.APPENDABLE)) { if (ti) // ti non-null only if ti is a struct with dtor { void* start = __arrayStart(info); size_t length = __arrayAllocLength(info, ti); finalize_array(start, length, ti); } // if p is in the cache, clear it there as well if(bic) bic.base = null; GC.free(info.base); *p = null; } } } unittest { __gshared size_t countDtor = 0; struct S { int x; ~this() { countDtor++; } } // destroy large array with x.ptr not base address of allocation auto x = new S[10000]; void* p = x.ptr; assert(GC.addrOf(p) != null); delete x; assert(GC.addrOf(p) == null); assert(countDtor == 10000); // destroy full array even if only slice passed auto y = new S[400]; auto z = y[200 .. 300]; p = z.ptr; assert(GC.addrOf(p) != null); delete z; assert(GC.addrOf(p) == null); assert(countDtor == 10000 + 400); } /** * */ extern (C) void _d_delmemory(void* *p) @weak // LDC { if (*p) { GC.free(*p); *p = null; } } /** * */ extern (C) void _d_callinterfacefinalizer(void *p) { if (p) { Interface *pi = **cast(Interface ***)p; Object o = cast(Object)(p - pi.offset); rt_finalize(cast(void*)o); } } /** * */ extern (C) void _d_callfinalizer(void* p) @weak // LDC { rt_finalize( p ); } /** * */ extern (C) void rt_setCollectHandler(CollectHandler h) { collectHandler = h; } /** * */ extern (C) CollectHandler rt_getCollectHandler() { return collectHandler; } /** * */ extern (C) int rt_hasFinalizerInSegment(void* p, size_t size, uint attr, in void[] segment) nothrow { if (attr & BlkAttr.STRUCTFINAL) { if (attr & BlkAttr.APPENDABLE) return hasArrayFinalizerInSegment(p, size, segment); return hasStructFinalizerInSegment(p, size, segment); } // otherwise class auto ppv = cast(void**) p; if(!p || !*ppv) return false; auto c = *cast(ClassInfo*)*ppv; do { auto pf = c.destructor; if (cast(size_t)(pf - segment.ptr) < segment.length) return true; } while ((c = c.base) !is null); return false; } int hasStructFinalizerInSegment(void* p, size_t size, in void[] segment) nothrow { if(!p) return false; auto ti = *cast(TypeInfo_Struct*)(p + size - size_t.sizeof); return cast(size_t)(cast(void*)ti.xdtor - segment.ptr) < segment.length; } int hasArrayFinalizerInSegment(void* p, size_t size, in void[] segment) nothrow { if(!p) return false; TypeInfo_Struct si = void; if (size < PAGESIZE) si = *cast(TypeInfo_Struct*)(p + size - size_t.sizeof); else si = *cast(TypeInfo_Struct*)(p + size_t.sizeof); return cast(size_t)(cast(void*)si.xdtor - segment.ptr) < segment.length; } // called by the GC void finalize_array2(void* p, size_t size) nothrow { debug(PRINTF) printf("rt_finalize_array2(p = %p)\n", p); TypeInfo_Struct si = void; if(size <= 256) { si = *cast(TypeInfo_Struct*)(p + size - size_t.sizeof); size = *cast(ubyte*)(p + size - size_t.sizeof - SMALLPAD); } else if (size < PAGESIZE) { si = *cast(TypeInfo_Struct*)(p + size - size_t.sizeof); size = *cast(ushort*)(p + size - size_t.sizeof - MEDPAD); } else { si = *cast(TypeInfo_Struct*)(p + size_t.sizeof); size = *cast(size_t*)p; p += LARGEPREFIX; } try { finalize_array(p, size, si); } catch (Exception e) { onFinalizeError(si, e); } } void finalize_array(void* p, size_t size, const TypeInfo_Struct si) { // Due to the fact that the delete operator calls destructors // for arrays from the last element to the first, we maintain // compatibility here by doing the same. auto tsize = si.tsize; for (auto curP = p + size - tsize; curP >= p; curP -= tsize) { // call destructor si.destroy(curP); } } // called by the GC void finalize_struct(void* p, size_t size) nothrow { debug(PRINTF) printf("finalize_struct(p = %p)\n", p); auto ti = *cast(TypeInfo_Struct*)(p + size - size_t.sizeof); try { ti.destroy(p); // call destructor } catch (Exception e) { onFinalizeError(ti, e); } } /** * */ extern (C) void rt_finalize2(void* p, bool det = true, bool resetMemory = true) nothrow { debug(PRINTF) printf("rt_finalize2(p = %p)\n", p); auto ppv = cast(void**) p; if(!p || !*ppv) return; auto pc = cast(ClassInfo*) *ppv; try { if (det || collectHandler is null || collectHandler(cast(Object) p)) { auto c = *pc; do { if (c.destructor) (cast(fp_t) c.destructor)(cast(Object) p); // call destructor } while ((c = c.base) !is null); } if (ppv[1]) // if monitor is not null _d_monitordelete(cast(Object) p, det); if (resetMemory) { auto w = (*pc).initializer; p[0 .. w.length] = w[]; } } catch (Exception e) { onFinalizeError(*pc, e); } finally { *ppv = null; // zero vptr even if `resetMemory` is false } } extern (C) void rt_finalize(void* p, bool det = true) { rt_finalize2(p, det, true); } extern (C) void rt_finalizeFromGC(void* p, size_t size, uint attr) { // to verify: reset memory necessary? if (!(attr & BlkAttr.STRUCTFINAL)) rt_finalize2(p, false, false); // class else if (attr & BlkAttr.APPENDABLE) finalize_array2(p, size); // array of structs else finalize_struct(p, size); // struct } /** * Resize dynamic arrays with 0 initializers. */ extern (C) void[] _d_arraysetlengthT(const TypeInfo ti, size_t newlength, void[]* p) @weak // LDC in { assert(ti); assert(!(*p).length || (*p).ptr); } body { debug(PRINTF) { //printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength); if (p) printf("\tp.ptr = %p, p.length = %d\n", (*p).ptr, (*p).length); } void* newdata = void; if (newlength) { if (newlength <= (*p).length) { *p = (*p)[0 .. newlength]; newdata = (*p).ptr; return newdata[0 .. newlength]; } version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); size_t sizeelem = tinext.tsize; version (LDC) { auto umul = llvm_umul_with_overflow!size_t(newlength, sizeelem); size_t newsize = umul.result; if (umul.overflow) goto Loverflow; } else version (D_InlineAsm_X86) { size_t newsize = void; asm pure nothrow @nogc { mov EAX, newlength; mul EAX, sizeelem; mov newsize, EAX; jc Loverflow; } } else version (D_InlineAsm_X86_64) { size_t newsize = void; asm pure nothrow @nogc { mov RAX, newlength; mul RAX, sizeelem; mov newsize, RAX; jc Loverflow; } } else { import core.checkedint : mulu; bool overflow = false; size_t newsize = mulu(sizeelem, newlength, overflow); if (overflow) goto Loverflow; } debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength); auto isshared = typeid(ti) is typeid(TypeInfo_Shared); if ((*p).ptr) { newdata = (*p).ptr; if (newlength > (*p).length) { size_t size = (*p).length * sizeelem; auto bic = isshared ? null : __getBlkInfo((*p).ptr); auto info = bic ? *bic : GC.query((*p).ptr); if(info.base && (info.attr & BlkAttr.APPENDABLE)) { // calculate the extent of the array given the base. size_t offset = (*p).ptr - __arrayStart(info); if(info.size >= PAGESIZE) { // size of array is at the front of the block if(!__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset)) { // check to see if it failed because there is not // enough space if(*(cast(size_t*)info.base) == size + offset) { // not enough space, try extending auto extendsize = newsize + offset + LARGEPAD - info.size; auto u = GC.extend(info.base, extendsize, extendsize); if(u) { // extend worked, now try setting the length // again. info.size = u; if(__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset)) { if(!isshared) __insertBlkInfoCache(info, bic); goto L1; } } } // couldn't do it, reallocate goto L2; } else if(!isshared && !bic) { // add this to the cache, it wasn't present previously. __insertBlkInfoCache(info, null); } } else if(!__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset)) { // could not resize in place goto L2; } else if(!isshared && !bic) { // add this to the cache, it wasn't present previously. __insertBlkInfoCache(info, null); } } else { if(info.base) { L2: if(bic) { // a chance that flags have changed since this was cached, we should fetch the most recent flags info.attr = GC.getAttr(info.base) | BlkAttr.APPENDABLE; } info = __arrayAlloc(newsize, info, ti, tinext); } else { info = __arrayAlloc(newsize, ti, tinext); } __setArrayAllocLength(info, newsize, isshared, tinext); if(!isshared) __insertBlkInfoCache(info, bic); newdata = cast(byte *)__arrayStart(info); newdata[0 .. size] = (*p).ptr[0 .. size]; // do postblit processing __doPostblit(newdata, size, tinext); } L1: memset(newdata + size, 0, newsize - size); } } else { // pointer was null, need to allocate auto info = __arrayAlloc(newsize, ti, tinext); __setArrayAllocLength(info, newsize, isshared, tinext); if(!isshared) __insertBlkInfoCache(info, null); newdata = cast(byte *)__arrayStart(info); memset(newdata, 0, newsize); } } else { newdata = (*p).ptr; } *p = newdata[0 .. newlength]; return *p; Loverflow: onOutOfMemoryError(); assert(0); } /** * Resize arrays for non-zero initializers. * p pointer to array lvalue to be updated * newlength new .length property of array * sizeelem size of each element of array * initsize size of initializer * ... initializer */ extern (C) void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p) @weak // LDC in { assert(!(*p).length || (*p).ptr); } body { void* newdata; version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto sizeelem = tinext.tsize; auto initializer = tinext.initializer(); auto initsize = initializer.length; assert(sizeelem); assert(initsize); assert(initsize <= sizeelem); assert((sizeelem / initsize) * initsize == sizeelem); debug(PRINTF) { printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d)\n", p, sizeelem, newlength, initsize); if (p) printf("\tp.data = %p, p.length = %d\n", (*p).ptr, (*p).length); } if (newlength) { version (LDC) { auto umul = llvm_umul_with_overflow!size_t(newlength, sizeelem); size_t newsize = umul.result; if (umul.overflow) goto Loverflow; } else version (D_InlineAsm_X86) { size_t newsize = void; asm { mov EAX,newlength ; mul EAX,sizeelem ; mov newsize,EAX ; jc Loverflow ; } } else version (D_InlineAsm_X86_64) { size_t newsize = void; asm { mov RAX,newlength ; mul RAX,sizeelem ; mov newsize,RAX ; jc Loverflow ; } } else { import core.checkedint : mulu; bool overflow = false; size_t newsize = mulu(sizeelem, newlength, overflow); if (overflow) goto Loverflow; } debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength); size_t size = (*p).length * sizeelem; auto isshared = typeid(ti) is typeid(TypeInfo_Shared); if ((*p).ptr) { newdata = (*p).ptr; if (newlength > (*p).length) { auto bic = isshared ? null : __getBlkInfo((*p).ptr); auto info = bic ? *bic : GC.query((*p).ptr); // calculate the extent of the array given the base. size_t offset = (*p).ptr - __arrayStart(info); if(info.base && (info.attr & BlkAttr.APPENDABLE)) { if(info.size >= PAGESIZE) { // size of array is at the front of the block if(!__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset)) { // check to see if it failed because there is not // enough space if(*(cast(size_t*)info.base) == size + offset) { // not enough space, try extending auto extendsize = newsize + offset + LARGEPAD - info.size; auto u = GC.extend(info.base, extendsize, extendsize); if(u) { // extend worked, now try setting the length // again. info.size = u; if(__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset)) { if(!isshared) __insertBlkInfoCache(info, bic); goto L1; } } } // couldn't do it, reallocate goto L2; } else if(!isshared && !bic) { // add this to the cache, it wasn't present previously. __insertBlkInfoCache(info, null); } } else if(!__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset)) { // could not resize in place goto L2; } else if(!isshared && !bic) { // add this to the cache, it wasn't present previously. __insertBlkInfoCache(info, null); } } else { // not appendable or not part of the heap yet. if(info.base) { L2: if(bic) { // a chance that flags have changed since this was cached, we should fetch the most recent flags info.attr = GC.getAttr(info.base) | BlkAttr.APPENDABLE; } info = __arrayAlloc(newsize, info, ti, tinext); } else { info = __arrayAlloc(newsize, ti, tinext); } __setArrayAllocLength(info, newsize, isshared, tinext); if(!isshared) __insertBlkInfoCache(info, bic); newdata = cast(byte *)__arrayStart(info); newdata[0 .. size] = (*p).ptr[0 .. size]; // do postblit processing __doPostblit(newdata, size, tinext); } L1: ; } } else { // length was zero, need to allocate auto info = __arrayAlloc(newsize, ti, tinext); __setArrayAllocLength(info, newsize, isshared, tinext); if(!isshared) __insertBlkInfoCache(info, null); newdata = cast(byte *)__arrayStart(info); } auto q = initializer.ptr; // pointer to initializer if (newsize > size) { if (initsize == 1) { debug(PRINTF) printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q); memset(newdata + size, *cast(byte*)q, newsize - size); } else { for (size_t u = size; u < newsize; u += initsize) { memcpy(newdata + u, q, initsize); } } } } else { newdata = (*p).ptr; } *p = newdata[0 .. newlength]; return *p; Loverflow: onOutOfMemoryError(); assert(0); } /** * Append y[] to array x[] */ extern (C) void[] _d_arrayappendT(const TypeInfo ti, ref byte[] x, byte[] y) @weak // LDC { auto length = x.length; version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto sizeelem = tinext.tsize; // array element size _d_arrayappendcTX(ti, x, y.length); memcpy(x.ptr + length * sizeelem, y.ptr, y.length * sizeelem); // do postblit __doPostblit(x.ptr + length * sizeelem, y.length * sizeelem, tinext); return x; } /** * */ size_t newCapacity(size_t newlength, size_t size) { version(none) { size_t newcap = newlength * size; } else { /* * Better version by Dave Fladebo: * This uses an inverse logorithmic algorithm to pre-allocate a bit more * space for larger arrays. * - Arrays smaller than PAGESIZE bytes are left as-is, so for the most * common cases, memory allocation is 1 to 1. The small overhead added * doesn't affect small array perf. (it's virtually the same as * current). * - Larger arrays have some space pre-allocated. * - As the arrays grow, the relative pre-allocated space shrinks. * - The logorithmic algorithm allocates relatively more space for * mid-size arrays, making it very fast for medium arrays (for * mid-to-large arrays, this turns out to be quite a bit faster than the * equivalent realloc() code in C, on Linux at least. Small arrays are * just as fast as GCC). * - Perhaps most importantly, overall memory usage and stress on the GC * is decreased significantly for demanding environments. */ size_t newcap = newlength * size; size_t newext = 0; if (newcap > PAGESIZE) { //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0))); // redo above line using only integer math /*static int log2plus1(size_t c) { int i; if (c == 0) i = -1; else for (i = 1; c >>= 1; i++) { } return i; }*/ /* The following setting for mult sets how much bigger * the new size will be over what is actually needed. * 100 means the same size, more means proportionally more. * More means faster but more memory consumption. */ //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap)); //long mult = 100 + (1000L * size) / log2plus1(newcap); long mult = 100 + (1000L) / (bsr(newcap) + 1); // testing shows 1.02 for large arrays is about the point of diminishing return // // Commented out because the multipler will never be < 102. In order for it to be < 2, // then 1000L / (bsr(x) + 1) must be > 2. The highest bsr(x) + 1 // could be is 65 (64th bit set), and 1000L / 64 is much larger // than 2. We need 500 bit integers for 101 to be achieved :) /*if (mult < 102) mult = 102;*/ /*newext = cast(size_t)((newcap * mult) / 100); newext -= newext % size;*/ // This version rounds up to the next element, and avoids using // mod. newext = cast(size_t)((newlength * mult + 99) / 100) * size; debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/100.0,newext / cast(double)size); } newcap = newext > newcap ? newext : newcap; debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size); } return newcap; } /************************************** * Extend an array by n elements. * Caller must initialize those elements. */ extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, ref byte[] px, size_t n) @weak // LDC { // This is a cut&paste job from _d_arrayappendT(). Should be refactored. // only optimize array append where ti is not a shared type version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto sizeelem = tinext.tsize; // array element size auto isshared = typeid(ti) is typeid(TypeInfo_Shared); auto bic = isshared ? null : __getBlkInfo(px.ptr); auto info = bic ? *bic : GC.query(px.ptr); auto length = px.length; auto newlength = length + n; auto newsize = newlength * sizeelem; auto size = length * sizeelem; size_t newcap = void; // for scratch space // calculate the extent of the array given the base. size_t offset = px.ptr - __arrayStart(info); if(info.base && (info.attr & BlkAttr.APPENDABLE)) { if(info.size >= PAGESIZE) { // size of array is at the front of the block if(!__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset)) { // check to see if it failed because there is not // enough space newcap = newCapacity(newlength, sizeelem); if(*(cast(size_t*)info.base) == size + offset) { // not enough space, try extending auto extendoffset = offset + LARGEPAD - info.size; auto u = GC.extend(info.base, newsize + extendoffset, newcap + extendoffset); if(u) { // extend worked, now try setting the length // again. info.size = u; if(__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset)) { if(!isshared) __insertBlkInfoCache(info, bic); goto L1; } } } // couldn't do it, reallocate goto L2; } else if(!isshared && !bic) { __insertBlkInfoCache(info, null); } } else if(!__setArrayAllocLength(info, newsize + offset, isshared, tinext, size + offset)) { // could not resize in place newcap = newCapacity(newlength, sizeelem); goto L2; } else if(!isshared && !bic) { __insertBlkInfoCache(info, null); } } else { // not appendable or is null newcap = newCapacity(newlength, sizeelem); if(info.base) { L2: if(bic) { // a chance that flags have changed since this was cached, we should fetch the most recent flags info.attr = GC.getAttr(info.base) | BlkAttr.APPENDABLE; } info = __arrayAlloc(newcap, info, ti, tinext); } else { info = __arrayAlloc(newcap, ti, tinext); } __setArrayAllocLength(info, newsize, isshared, tinext); if(!isshared) __insertBlkInfoCache(info, bic); auto newdata = cast(byte *)__arrayStart(info); memcpy(newdata, px.ptr, length * sizeelem); // do postblit processing __doPostblit(newdata, length * sizeelem, tinext); (cast(void **)(&px))[1] = newdata; } L1: *cast(size_t *)&px = newlength; return px; } /** * Append dchar to char[] */ extern (C) void[] _d_arrayappendcd(ref byte[] x, dchar c) { // c could encode into from 1 to 4 characters char[4] buf = void; byte[] appendthis; // passed to appendT if (c <= 0x7F) { buf.ptr[0] = cast(char)c; appendthis = (cast(byte *)buf.ptr)[0..1]; } else if (c <= 0x7FF) { buf.ptr[0] = cast(char)(0xC0 | (c >> 6)); buf.ptr[1] = cast(char)(0x80 | (c & 0x3F)); appendthis = (cast(byte *)buf.ptr)[0..2]; } else if (c <= 0xFFFF) { buf.ptr[0] = cast(char)(0xE0 | (c >> 12)); buf.ptr[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf.ptr[2] = cast(char)(0x80 | (c & 0x3F)); appendthis = (cast(byte *)buf.ptr)[0..3]; } else if (c <= 0x10FFFF) { buf.ptr[0] = cast(char)(0xF0 | (c >> 18)); buf.ptr[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); buf.ptr[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); buf.ptr[3] = cast(char)(0x80 | (c & 0x3F)); appendthis = (cast(byte *)buf.ptr)[0..4]; } else assert(0); // invalid utf character - should we throw an exception instead? // // TODO: This always assumes the array type is shared, because we do not // get a typeinfo from the compiler. Assuming shared is the safest option. // Once the compiler is fixed, the proper typeinfo should be forwarded. // return _d_arrayappendT(typeid(shared char[]), x, appendthis); } /** * Append dchar to wchar[] */ extern (C) void[] _d_arrayappendwd(ref byte[] x, dchar c) { // c could encode into from 1 to 2 w characters wchar[2] buf = void; byte[] appendthis; // passed to appendT if (c <= 0xFFFF) { buf.ptr[0] = cast(wchar) c; // note that although we are passing only 1 byte here, appendT // interprets this as being an array of wchar, making the necessary // casts. appendthis = (cast(byte *)buf.ptr)[0..1]; } else { buf.ptr[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); buf.ptr[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); // ditto from above. appendthis = (cast(byte *)buf.ptr)[0..2]; } // // TODO: This always assumes the array type is shared, because we do not // get a typeinfo from the compiler. Assuming shared is the safest option. // Once the compiler is fixed, the proper typeinfo should be forwarded. // return _d_arrayappendT(typeid(shared wchar[]), x, appendthis); } /** * */ extern (C) byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y) @weak // LDC out (result) { version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto sizeelem = tinext.tsize; // array element size debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr); assert(result.length == x.length + y.length); // If a postblit is involved, the contents of result might rightly differ // from the bitwise concatenation of x and y. if (!hasPostblit(tinext)) { for (size_t i = 0; i < x.length * sizeelem; i++) assert((cast(byte*)result)[i] == (cast(byte*)x)[i]); for (size_t i = 0; i < y.length * sizeelem; i++) assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]); } size_t cap = GC.sizeOf(result.ptr); assert(!cap || cap > result.length * sizeelem); } body { version (none) { /* Cannot use this optimization because: * char[] a, b; * char c = 'a'; * b = a ~ c; * c = 'b'; * will change the contents of b. */ if (!y.length) return x; if (!x.length) return y; } version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto sizeelem = tinext.tsize; // array element size debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem); size_t xlen = x.length * sizeelem; size_t ylen = y.length * sizeelem; size_t len = xlen + ylen; if (!len) return null; auto info = __arrayAlloc(len, ti, tinext); byte* p = cast(byte*)__arrayStart(info); p[len] = 0; // guessing this is to optimize for null-terminated arrays? memcpy(p, x.ptr, xlen); memcpy(p + xlen, y.ptr, ylen); // do postblit processing __doPostblit(p, xlen + ylen, tinext); auto isshared = typeid(ti) is typeid(TypeInfo_Shared); __setArrayAllocLength(info, len, isshared, tinext); return p[0 .. x.length + y.length]; } /** * */ extern (C) void[] _d_arraycatnTX(const TypeInfo ti, byte[][] arrs) @weak // LDC { size_t length; version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto size = tinext.tsize; // array element size foreach(b; arrs) length += b.length; if (!length) return null; auto allocsize = length * size; auto info = __arrayAlloc(allocsize, ti, tinext); auto isshared = typeid(ti) is typeid(TypeInfo_Shared); __setArrayAllocLength(info, allocsize, isshared, tinext); void *a = __arrayStart (info); size_t j = 0; foreach(b; arrs) { if (b.length) { memcpy(a + j, b.ptr, b.length * size); j += b.length * size; } } // do postblit processing __doPostblit(a, j, tinext); return a[0..length]; } /** * Allocate the array, rely on the caller to do the initialization of the array. */ extern (C) void* _d_arrayliteralTX(const TypeInfo ti, size_t length) @weak // LDC { version(LDC) auto tinext = unqualify(unqualify(ti).next); else auto tinext = unqualify(ti.next); auto sizeelem = tinext.tsize; // array element size void* result; debug(PRINTF) printf("_d_arrayliteralTX(sizeelem = %d, length = %d)\n", sizeelem, length); if (length == 0 || sizeelem == 0) result = null; else { auto allocsize = length * sizeelem; auto info = __arrayAlloc(allocsize, ti, tinext); auto isshared = typeid(ti) is typeid(TypeInfo_Shared); __setArrayAllocLength(info, allocsize, isshared, tinext); result = __arrayStart(info); } return result; } unittest { int[] a; int[] b; int i; a = new int[3]; a[0] = 1; a[1] = 2; a[2] = 3; b = a.dup; assert(b.length == 3); for (i = 0; i < 3; i++) assert(b[i] == i + 1); // test slice appending b = a[0..1]; b ~= 4; for(i = 0; i < 3; i++) assert(a[i] == i + 1); // test reserving char[] arr = new char[4093]; for(i = 0; i < arr.length; i++) arr[i] = cast(char)(i % 256); // note that these two commands used to cause corruption, which may not be // detected. arr.reserve(4094); auto arr2 = arr ~ "123"; assert(arr2[0..arr.length] == arr); assert(arr2[arr.length..$] == "123"); // test postblit on array concat, append, length, etc. static struct S { int x; int pad; this(this) { ++x; } } void testPostBlit(T)() { auto sarr = new T[1]; debug(SENTINEL) {} else assert(sarr.capacity == 1); // length extend auto sarr2 = sarr; assert(sarr[0].x == 0); sarr2.length += 1; assert(sarr2[0].x == 1); assert(sarr[0].x == 0); // append T s; sarr2 = sarr; sarr2 ~= s; assert(sarr2[0].x == 1); assert(sarr2[1].x == 1); assert(sarr[0].x == 0); assert(s.x == 0); // concat sarr2 = sarr ~ sarr; assert(sarr2[0].x == 1); assert(sarr2[1].x == 1); assert(sarr[0].x == 0); // concat multiple (calls different method) sarr2 = sarr ~ sarr ~ sarr; assert(sarr2[0].x == 1); assert(sarr2[1].x == 1); assert(sarr2[2].x == 1); assert(sarr[0].x == 0); // reserve capacity sarr2 = sarr; sarr2.reserve(2); assert(sarr2[0].x == 1); assert(sarr[0].x == 0); } testPostBlit!(S)(); testPostBlit!(const(S))(); } // cannot define structs inside unit test block, or they become nested structs. version(unittest) { struct S1 { int x = 5; } struct S2 { int x; this(int x) {this.x = x;} } struct S3 { int[4] x; this(int x) {this.x[] = x;} } struct S4 { int *x; } } unittest { auto s1 = new S1; assert(s1.x == 5); assert(GC.getAttr(s1) == BlkAttr.NO_SCAN); auto s2 = new S2(3); assert(s2.x == 3); assert(GC.getAttr(s2) == BlkAttr.NO_SCAN); auto s3 = new S3(1); assert(s3.x == [1,1,1,1]); assert(GC.getAttr(s3) == BlkAttr.NO_SCAN); debug(SENTINEL) {} else assert(GC.sizeOf(s3) == 16); auto s4 = new S4; assert(s4.x == null); assert(GC.getAttr(s4) == 0); } unittest { // Bugzilla 3454 - Inconsistent flag setting in GC.realloc() static void test(size_t multiplier) { auto p = GC.malloc(8 * multiplier, BlkAttr.NO_SCAN); assert(GC.getAttr(p) == BlkAttr.NO_SCAN); p = GC.realloc(p, 2 * multiplier, BlkAttr.NO_SCAN); assert(GC.getAttr(p) == BlkAttr.NO_SCAN); } test(1); test(1024 * 1024); } unittest { import core.exception; try { size_t x = size_t.max; byte[] big_buf = new byte[x]; } catch(OutOfMemoryError) { } } unittest { // bugzilla 13854 auto arr = new ubyte[PAGESIZE]; // ensure page size auto info1 = GC.query(arr.ptr); assert(info1.base !is arr.ptr); // offset is required for page size or larger auto arr2 = arr[0..1]; assert(arr2.capacity == 0); // cannot append arr2 ~= 0; // add a byte assert(arr2.ptr !is arr.ptr); // reallocated auto info2 = GC.query(arr2.ptr); assert(info2.base is arr2.ptr); // no offset, the capacity is small. // do the same via setting length arr2 = arr[0..1]; assert(arr2.capacity == 0); arr2.length += 1; assert(arr2.ptr !is arr.ptr); // reallocated info2 = GC.query(arr2.ptr); assert(info2.base is arr2.ptr); // no offset, the capacity is small. // do the same for char[] since we need a type with an initializer to test certain runtime functions auto carr = new char[PAGESIZE]; info1 = GC.query(carr.ptr); assert(info1.base !is carr.ptr); // offset is required for page size or larger auto carr2 = carr[0..1]; assert(carr2.capacity == 0); // cannot append carr2 ~= 0; // add a byte assert(carr2.ptr !is carr.ptr); // reallocated info2 = GC.query(carr2.ptr); assert(info2.base is carr2.ptr); // no offset, the capacity is small. // do the same via setting length carr2 = carr[0..1]; assert(carr2.capacity == 0); carr2.length += 1; assert(carr2.ptr !is carr.ptr); // reallocated info2 = GC.query(carr2.ptr); assert(info2.base is carr2.ptr); // no offset, the capacity is small. } unittest { // bugzilla 13878 auto arr = new ubyte[1]; auto info = GC.query(arr.ptr); assert(info.attr & BlkAttr.NO_SCAN); // should be NO_SCAN arr ~= 0; // ensure array is inserted into cache debug(SENTINEL) {} else assert(arr.ptr is info.base); GC.clrAttr(arr.ptr, BlkAttr.NO_SCAN); // remove the attribute auto arr2 = arr[0..1]; assert(arr2.capacity == 0); // cannot append arr2 ~= 0; assert(arr2.ptr !is arr.ptr); info = GC.query(arr2.ptr); assert(!(info.attr & BlkAttr.NO_SCAN)); // ensure attribute sticks // do the same via setting length arr = new ubyte[1]; arr ~= 0; // ensure array is inserted into cache GC.clrAttr(arr.ptr, BlkAttr.NO_SCAN); // remove the attribute arr2 = arr[0..1]; assert(arr2.capacity == 0); arr2.length += 1; assert(arr2.ptr !is arr.ptr); // reallocated info = GC.query(arr2.ptr); assert(!(info.attr & BlkAttr.NO_SCAN)); // ensure attribute sticks // do the same for char[] since we need a type with an initializer to test certain runtime functions auto carr = new char[1]; info = GC.query(carr.ptr); assert(info.attr & BlkAttr.NO_SCAN); // should be NO_SCAN carr ~= 0; // ensure array is inserted into cache debug(SENTINEL) {} else assert(carr.ptr is info.base); GC.clrAttr(carr.ptr, BlkAttr.NO_SCAN); // remove the attribute auto carr2 = carr[0..1]; assert(carr2.capacity == 0); // cannot append carr2 ~= 0; assert(carr2.ptr !is carr.ptr); info = GC.query(carr2.ptr); assert(!(info.attr & BlkAttr.NO_SCAN)); // ensure attribute sticks // do the same via setting length carr = new char[1]; carr ~= 0; // ensure array is inserted into cache GC.clrAttr(carr.ptr, BlkAttr.NO_SCAN); // remove the attribute carr2 = carr[0..1]; assert(carr2.capacity == 0); carr2.length += 1; assert(carr2.ptr !is carr.ptr); // reallocated info = GC.query(carr2.ptr); assert(!(info.attr & BlkAttr.NO_SCAN)); // ensure attribute sticks } // test struct finalizers debug(SENTINEL) {} else unittest { __gshared int dtorCount; static struct S1 { int x; ~this() { dtorCount++; } } dtorCount = 0; S1* s1 = new S1; delete s1; assert(dtorCount == 1); dtorCount = 0; S1[] arr1 = new S1[7]; delete arr1; assert(dtorCount == 7); if (callStructDtorsDuringGC) { dtorCount = 0; S1* s2 = new S1; GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0..1]); assert(dtorCount == 1); GC.free(s2); dtorCount = 0; const(S1)* s3 = new const(S1); GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0..1]); assert(dtorCount == 1); GC.free(cast(void*)s3); dtorCount = 0; shared(S1)* s4 = new shared(S1); GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0..1]); assert(dtorCount == 1); GC.free(cast(void*)s4); dtorCount = 0; const(S1)[] carr1 = new const(S1)[5]; BlkInfo blkinf1 = GC.query(carr1.ptr); GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0..1]); assert(dtorCount == 5); GC.free(blkinf1.base); } dtorCount = 0; S1[] arr2 = new S1[10]; arr2.length = 6; arr2.assumeSafeAppend; assert(dtorCount == 4); // destructors run explicitely? if (callStructDtorsDuringGC) { dtorCount = 0; BlkInfo blkinf = GC.query(arr2.ptr); GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0..1]); assert(dtorCount == 6); GC.free(blkinf.base); } // associative arrays import rt.aaA : entryDtor; // throw away all existing AA entries with dtor GC.runFinalizers((cast(char*)(&entryDtor))[0..1]); S1[int] aa1; aa1[0] = S1(0); aa1[1] = S1(1); if (callStructDtorsDuringGC) { dtorCount = 0; aa1 = null; GC.runFinalizers((cast(char*)(&entryDtor))[0..1]); assert(dtorCount == 2); } int[S1] aa2; aa2[S1(0)] = 0; aa2[S1(1)] = 1; aa2[S1(2)] = 2; if (callStructDtorsDuringGC) { dtorCount = 0; aa2 = null; GC.runFinalizers((cast(char*)(&entryDtor))[0..1]); assert(dtorCount == 3); } S1[2][int] aa3; aa3[0] = [S1(0),S1(2)]; aa3[1] = [S1(1),S1(3)]; if (callStructDtorsDuringGC) { dtorCount = 0; aa3 = null; GC.runFinalizers((cast(char*)(&entryDtor))[0..1]); assert(dtorCount == 4); } } // test class finalizers exception handling unittest { bool test(E)() { import core.exception; static class C1 { E exc; this(E exc) { this.exc = exc; } ~this() { throw exc; } } bool caught = false; C1 c = new C1(new E("test onFinalizeError")); try { GC.runFinalizers((cast(uint*)&C1.__dtor)[0..1]); } catch(FinalizeError err) { caught = true; } catch(E) { } GC.free(cast(void*)c); return caught; } assert( test!Exception); import core.exception : InvalidMemoryOperationError; assert(!test!InvalidMemoryOperationError); } // test struct finalizers exception handling debug(SENTINEL) {} else unittest { if (!callStructDtorsDuringGC) return; bool test(E)() { import core.exception; static struct S1 { E exc; ~this() { throw exc; } } bool caught = false; S1* s = new S1(new E("test onFinalizeError")); try { GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0..1]); } catch(FinalizeError err) { caught = true; } catch(E) { } GC.free(s); return caught; } assert( test!Exception); import core.exception : InvalidMemoryOperationError; assert(!test!InvalidMemoryOperationError); } // test bug 14126 unittest { static struct S { S* thisptr; ~this() { assert(&this == thisptr); thisptr = null;} } S[] test14126 = new S[2048]; // make sure we allocate at least a PAGE foreach(ref s; test14126) { s.thisptr = &s; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/obj.d0000664000175000017500000000146412776214756017623 0ustar kaikai/** * Contains object comparator functions called by generated code. * * Copyright: Copyright Digital Mars 2002 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2000 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.obj; extern (C): /******************************** * Compiler helper for operator == for class objects. */ int _d_obj_eq(Object o1, Object o2) { return o1 is o2 || (o1 && o1.opEquals(o2)); } /******************************** * Compiler helper for operator <, <=, >, >= for class objects. */ int _d_obj_cmp(Object o1, Object o2) { return o1.opCmp(o2); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/arraycast.d0000664000175000017500000000366712776214756021051 0ustar kaikai/** * Implementation of array cast support routines. * * Copyright: Copyright Digital Mars 2004 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2004 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.arraycast; /****************************************** * Runtime helper to convert dynamic array of one * type to dynamic array of another. * Adjusts the length of the array. * Throws an error if new length is not aligned. */ extern (C) @trusted nothrow void[] _d_arraycast(size_t tsize, size_t fsize, void[] a) { auto length = a.length; auto nbytes = length * fsize; if (nbytes % tsize != 0) { throw new Error("array cast misalignment"); } length = nbytes / tsize; *cast(size_t *)&a = length; // jam new length return a; } unittest { byte[int.sizeof * 3] b; int[] i; short[] s; i = cast(int[])b; assert(i.length == 3); s = cast(short[])b; assert(s.length == 6); s = cast(short[])i; assert(s.length == 6); } /****************************************** * Runtime helper to convert dynamic array of bits * dynamic array of another. * Adjusts the length of the array. * Throws an error if new length is not aligned. */ version (none) { extern (C) @trusted nothrow void[] _d_arraycast_frombit(uint tsize, void[] a) { uint length = a.length; if (length & 7) { throw new Error("bit[] array cast misalignment"); } length /= 8 * tsize; *cast(size_t *)&a = length; // jam new length return a; } unittest { version (D_Bits) { bit[int.sizeof * 3 * 8] b; int[] i; short[] s; i = cast(int[])b; assert(i.length == 3); s = cast(short[])b; assert(s.length == 6); } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/minit.obj0000664000175000017500000000047512776214756020521 0ustar kaikaisrc\rt\minit.asm8DGROUPFMXOFMBFMEBSSXOBXOEDATACODEFLAT_TEXT    i ĚY X__moduleinfo_arrayߐ__minitu __nullextѡ P!+) /tldc-1.1.0-beta3-src/runtime/druntime/src/rt/deh.d0000664000175000017500000000176212776214756017612 0ustar kaikai/** * Implementation of exception handling support routines. * * Copyright: Copyright Digital Mars 1999 - 2013. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright * Source: $(DRUNTIMESRC src/rt/deh.d) */ module rt.deh; version (LDC) { // We use a libunwind-based EH scheme on all platforms. } else { extern (C) { Throwable.TraceInfo _d_traceContext(void* ptr = null); void _d_createTrace(Object o, void* context) { auto t = cast(Throwable) o; if (t !is null && t.info is null && cast(byte*) t !is typeid(t).initializer.ptr) { t.info = _d_traceContext(context); } } } version (Win32) public import rt.deh_win32; else version (Win64) public import rt.deh_win64_posix; else version (Posix) public import rt.deh_win64_posix; else static assert (0, "Unsupported architecture"); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/sections_osx.d0000664000175000017500000001664312776214756021576 0ustar kaikai/** * Written in the D programming language. * This module provides OSX-specific support for sections. * * Copyright: Copyright Digital Mars 2008 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly, Martin Nowak * Source: $(DRUNTIMESRC src/rt/_sections_osx.d) */ module rt.sections_osx; version (LDC) {} else version(OSX): // debug = PRINTF; import core.stdc.stdio; import core.stdc.string, core.stdc.stdlib; import core.sys.posix.pthread; import core.sys.osx.mach.dyld; import core.sys.osx.mach.getsect; import rt.deh, rt.minfo; import rt.util.container.array; struct SectionGroup { static int opApply(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } static int opApplyReverse(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } @property immutable(ModuleInfo*)[] modules() const { return _moduleGroup.modules; } @property ref inout(ModuleGroup) moduleGroup() inout { return _moduleGroup; } @property inout(void[])[] gcRanges() inout { return _gcRanges[]; } @property immutable(FuncTable)[] ehTables() const { return _ehTables[]; } private: immutable(FuncTable)[] _ehTables; ModuleGroup _moduleGroup; Array!(void[]) _gcRanges; immutable(void)[][2] _tlsImage; } /**** * Boolean flag set to true while the runtime is initialized. */ __gshared bool _isRuntimeInitialized; /**** * Gets called on program startup just before GC is initialized. */ void initSections() { pthread_key_create(&_tlsKey, null); _dyld_register_func_for_add_image(§ions_osx_onAddImage); _isRuntimeInitialized = true; } /*** * Gets called on program shutdown just after GC is terminated. */ void finiSections() { _sections._gcRanges.reset(); pthread_key_delete(_tlsKey); _isRuntimeInitialized = false; } void[]* initTLSRanges() { return &getTLSBlock(); } void finiTLSRanges(void[]* rng) { .free(rng.ptr); .free(rng); } void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow { dg(rng.ptr, rng.ptr + rng.length); } // NOTE: The Mach-O object file format does not allow for thread local // storage declarations. So instead we roll our own by putting tls // into the __tls_data and the __tlscoal_nt sections. // // This function is called by the code emitted by the compiler. It // is expected to translate an address into the TLS static data to // the corresponding address in the TLS dynamic per-thread data. // NB: the compiler mangles this function as '___tls_get_addr' even though it is extern(D) extern(D) void* ___tls_get_addr( void* p ) { immutable off = tlsOffset(p); auto tls = getTLSBlockAlloc(); assert(off < tls.length); return tls.ptr + off; } private: __gshared pthread_key_t _tlsKey; size_t tlsOffset(void* p) in { assert(_sections._tlsImage[0].ptr !is null || _sections._tlsImage[1].ptr !is null); } body { // NOTE: p is an address in the TLS static data emitted by the // compiler. If it isn't, something is disastrously wrong. immutable off0 = cast(size_t)(p - _sections._tlsImage[0].ptr); if (off0 < _sections._tlsImage[0].length) { return off0; } immutable off1 = cast(size_t)(p - _sections._tlsImage[1].ptr); if (off1 < _sections._tlsImage[1].length) { size_t sz = (_sections._tlsImage[0].length + 15) & ~cast(size_t)15; return sz + off1; } assert(0); } ref void[] getTLSBlock() { auto pary = cast(void[]*)pthread_getspecific(_tlsKey); if (pary is null) { pary = cast(void[]*).calloc(1, (void[]).sizeof); if (pthread_setspecific(_tlsKey, pary) != 0) { import core.stdc.stdio; perror("pthread_setspecific failed with"); assert(0); } } return *pary; } ref void[] getTLSBlockAlloc() { auto pary = &getTLSBlock(); if (!pary.length) { auto imgs = _sections._tlsImage; immutable sz0 = (imgs[0].length + 15) & ~cast(size_t)15; immutable sz2 = sz0 + imgs[1].length; auto p = .malloc(sz2); memcpy(p, imgs[0].ptr, imgs[0].length); memcpy(p + sz0, imgs[1].ptr, imgs[1].length); *pary = p[0 .. sz2]; } return *pary; } __gshared SectionGroup _sections; extern (C) void sections_osx_onAddImage(in mach_header* h, intptr_t slide) { foreach (e; dataSegs) { auto sect = getSection(h, slide, e.seg.ptr, e.sect.ptr); if (sect != null) _sections._gcRanges.insertBack((cast(void*)sect.ptr)[0 .. sect.length]); } auto minfosect = getSection(h, slide, "__DATA", "__minfodata"); if (minfosect != null) { // no support for multiple images yet // take the sections from the last static image which is the executable if (_isRuntimeInitialized) { fprintf(stderr, "Loading shared libraries isn't yet supported on OSX.\n"); return; } else if (_sections.modules.ptr !is null) { fprintf(stderr, "Shared libraries are not yet supported on OSX.\n"); } debug(PRINTF) printf(" minfodata\n"); auto p = cast(immutable(ModuleInfo*)*)minfosect.ptr; immutable len = minfosect.length / (*p).sizeof; _sections._moduleGroup = ModuleGroup(p[0 .. len]); } auto ehsect = getSection(h, slide, "__DATA", "__deh_eh"); if (ehsect != null) { debug(PRINTF) printf(" deh_eh\n"); auto p = cast(immutable(FuncTable)*)ehsect.ptr; immutable len = ehsect.length / (*p).sizeof; _sections._ehTables = p[0 .. len]; } auto tlssect = getSection(h, slide, "__DATA", "__tls_data"); if (tlssect != null) { debug(PRINTF) printf(" tls_data %p %p\n", tlssect.ptr, tlssect.ptr + tlssect.length); _sections._tlsImage[0] = (cast(immutable(void)*)tlssect.ptr)[0 .. tlssect.length]; } auto tlssect2 = getSection(h, slide, "__DATA", "__tlscoal_nt"); if (tlssect2 != null) { debug(PRINTF) printf(" tlscoal_nt %p %p\n", tlssect2.ptr, tlssect2.ptr + tlssect2.length); _sections._tlsImage[1] = (cast(immutable(void)*)tlssect2.ptr)[0 .. tlssect2.length]; } } struct SegRef { string seg; string sect; } static immutable SegRef[] dataSegs = [{SEG_DATA, SECT_DATA}, {SEG_DATA, SECT_BSS}, {SEG_DATA, SECT_COMMON}]; ubyte[] getSection(in mach_header* header, intptr_t slide, in char* segmentName, in char* sectionName) { version (X86) { assert(header.magic == MH_MAGIC); auto sect = getsectbynamefromheader(header, segmentName, sectionName); } else version (X86_64) { assert(header.magic == MH_MAGIC_64); auto sect = getsectbynamefromheader_64(cast(mach_header_64*)header, segmentName, sectionName); } else static assert(0, "unimplemented"); if (sect !is null && sect.size > 0) return (cast(ubyte*)sect.addr + slide)[0 .. cast(size_t)sect.size]; return null; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/sections_win32.d0000664000175000017500000000512312776214756021716 0ustar kaikai/** * Written in the D programming language. * This module provides Win32-specific support for sections. * * Copyright: Copyright Digital Mars 2008 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly, Martin Nowak * Source: $(DRUNTIMESRC src/rt/_sections_win32.d) */ module rt.sections_win32; version (LDC) {} else version(CRuntime_DigitalMars): // debug = PRINTF; debug(PRINTF) import core.stdc.stdio; import rt.minfo; struct SectionGroup { static int opApply(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } static int opApplyReverse(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } @property immutable(ModuleInfo*)[] modules() const { return _moduleGroup.modules; } @property ref inout(ModuleGroup) moduleGroup() inout { return _moduleGroup; } @property inout(void[])[] gcRanges() inout { return _gcRanges[]; } private: ModuleGroup _moduleGroup; void[][2] _gcRanges; } void initSections() { _sections._moduleGroup = ModuleGroup(getModuleInfos()); auto databeg = cast(void*)&_xi_a; auto dataend = cast(void*)_moduleinfo_array.ptr; _sections._gcRanges[0] = databeg[0 .. dataend - databeg]; // skip module info and CONST segment auto bssbeg = cast(void*)&_edata; auto bssend = cast(void*)&_end; _sections._gcRanges[1] = bssbeg[0 .. bssend - bssbeg]; } void finiSections() { } void[] initTLSRanges() { auto pbeg = cast(void*)&_tlsstart; auto pend = cast(void*)&_tlsend; return pbeg[0 .. pend - pbeg]; } void finiTLSRanges(void[] rng) { } void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow { dg(rng.ptr, rng.ptr + rng.length); } private: __gshared SectionGroup _sections; // Windows: this gets initialized by minit.asm extern(C) __gshared immutable(ModuleInfo*)[] _moduleinfo_array; extern(C) void _minit(); immutable(ModuleInfo*)[] getModuleInfos() out (result) { foreach(m; result) assert(m !is null); } body { // _minit directly alters the global _moduleinfo_array _minit(); return _moduleinfo_array; } extern(C) { extern __gshared { int _xi_a; // &_xi_a just happens to be start of data segment int _edata; // &_edata is start of BSS segment int _end; // &_end is past end of BSS } extern { int _tlsstart; int _tlsend; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/llmath.d0000664000175000017500000004417512776214756020340 0ustar kaikai/** * Support for 64-bit longs. * * Copyright: Copyright Digital Mars 2000 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC src/rt/_llmath.d) */ module rt.llmath; extern (C): /*************************************** * Unsigned long divide. * Input: * [EDX,EAX],[ECX,EBX] * Output: * [EDX,EAX] = [EDX,EAX] / [ECX,EBX] * [ECX,EBX] = [EDX,EAX] % [ECX,EBX] */ void __ULDIV2__() { version (D_InlineAsm_X86) { asm { naked ; mov EBX,4[ESP] ; // the only difference between this and __ULDIV__ test ECX,ECX ; jz uldiv ; // if ECX > EDX, then quotient is 0 and remainder is [EDX,EAX] cmp ECX,EDX ; ja quo0 ; test ECX,ECX ; js Lleft ; /* We have n>d, and know that n/d will fit in 32 bits. * d will be left justified if we shift it left s bits. * [d1,d0] <<= s * [n2,n1,n0] = [n1,n0] << s * * Use one divide, by this reasoning: * ([n2,n1]<<32 + n0)/(d1<<32 + d0) * becomes: * ([n2,n1]<<32)/(d1<<32 + d0) + n0/(d1<<32 + d0) * The second divide is always 0. * Ignore the d0 in the first divide, which will yield a quotient * that might be too high by 1 (because d1 is left justified). * We can tell if it's too big if: * q*[d1,d0] > [n2,n1,n0] * which is: * q*[d1,d0] > [[q*[d1,0]+q%[d1,0],n1,n0] * If we subtract q*[d1,0] from both sides, we get: * q*d0 > [[n2,n1]%d1,n0] * So if it is too big by one, reduce q by one to q'=q-one. * Compute remainder as: * r = ([n1,n0] - q'*[d1,d0]) >> s * Again, we can subtract q*[d1,0]: * r = ([n1,n0] - q*[d1,0] - (q'*[d1,d0] - q*[d1,0])) >> s * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - (q - one)*[d1,d0])) >> s * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - [d1 *(q-one),d0*(1-q)])) >> s * r = ([[n2,n1]%d1,n0] + [d1 *one,d0*(one-q)])) >> s */ push EBP ; push ESI ; push EDI ; mov ESI,EDX ; mov EDI,EAX ; mov EBP,ECX ; bsr EAX,ECX ; // EAX is now 30..0 xor EAX,0x1F ; // EAX is now 1..31 mov CH,AL ; neg EAX ; add EAX,32 ; mov CL,AL ; mov EAX,EBX ; shr EAX,CL ; xchg CH,CL ; shl EBP,CL ; or EBP,EAX ; shl EBX,CL ; mov EDX,ESI ; xchg CH,CL ; shr EDX,CL ; mov EAX,EDI ; shr EAX,CL ; xchg CH,CL ; shl EDI,CL ; shl ESI,CL ; or EAX,ESI ; div EBP ; push EBP ; mov EBP,EAX ; mov ESI,EDX ; mul EBX ; cmp EDX,ESI ; ja L1 ; jb L2 ; cmp EAX,EDI ; jbe L2 ; L1: dec EBP ; sub EAX,EBX ; sbb EDX,0[ESP] ; L2: add ESP,4 ; sub EDI,EAX ; sbb ESI,EDX ; mov EAX,ESI ; xchg CH,CL ; shl EAX,CL ; xchg CH,CL ; shr EDI,CL ; or EDI,EAX ; shr ESI,CL ; mov EBX,EDI ; mov ECX,ESI ; mov EAX,EBP ; xor EDX,EDX ; pop EDI ; pop ESI ; pop EBP ; ret ; uldiv: test EDX,EDX ; jnz D3 ; // Both high words are 0, we can use the DIV instruction div EBX ; mov EBX,EDX ; mov EDX,ECX ; // EDX = ECX = 0 ret ; even ; D3: // Divide [EDX,EAX] by EBX mov ECX,EAX ; mov EAX,EDX ; xor EDX,EDX ; div EBX ; xchg ECX,EAX ; div EBX ; // ECX,EAX = result // EDX = remainder mov EBX,EDX ; mov EDX,ECX ; xor ECX,ECX ; ret ; quo0: // Quotient is 0 // Remainder is [EDX,EAX] mov EBX,EAX ; mov ECX,EDX ; xor EAX,EAX ; xor EDX,EDX ; ret ; Lleft: // The quotient is 0 or 1 and EDX >= ECX cmp EDX,ECX ; ja quo1 ; // [EDX,EAX] > [ECX,EBX] // EDX == ECX cmp EAX,EBX ; jb quo0 ; quo1: // Quotient is 1 // Remainder is [EDX,EAX] - [ECX,EBX] sub EAX,EBX ; sbb EDX,ECX ; mov EBX,EAX ; mov ECX,EDX ; mov EAX,1 ; xor EDX,EDX ; ret ; } } else version (D_InlineAsm_X86_64) assert(0); else static assert(0); } void __ULDIV__() { version (D_InlineAsm_X86) { asm { naked ; test ECX,ECX ; jz uldiv ; // if ECX > EDX, then quotient is 0 and remainder is [EDX,EAX] cmp ECX,EDX ; ja quo0 ; test ECX,ECX ; js Lleft ; /* We have n>d, and know that n/d will fit in 32 bits. * d will be left justified if we shift it left s bits. * [d1,d0] <<= s * [n2,n1,n0] = [n1,n0] << s * * Use one divide, by this reasoning: * ([n2,n1]<<32 + n0)/(d1<<32 + d0) * becomes: * ([n2,n1]<<32)/(d1<<32 + d0) + n0/(d1<<32 + d0) * The second divide is always 0. * Ignore the d0 in the first divide, which will yield a quotient * that might be too high by 1 (because d1 is left justified). * We can tell if it's too big if: * q*[d1,d0] > [n2,n1,n0] * which is: * q*[d1,d0] > [[q*[d1,0]+q%[d1,0],n1,n0] * If we subtract q*[d1,0] from both sides, we get: * q*d0 > [[n2,n1]%d1,n0] * So if it is too big by one, reduce q by one to q'=q-one. * Compute remainder as: * r = ([n1,n0] - q'*[d1,d0]) >> s * Again, we can subtract q*[d1,0]: * r = ([n1,n0] - q*[d1,0] - (q'*[d1,d0] - q*[d1,0])) >> s * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - (q - one)*[d1,d0])) >> s * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - [d1 *(q-one),d0*(1-q)])) >> s * r = ([[n2,n1]%d1,n0] + [d1 *one,d0*(one-q)])) >> s */ push EBP ; push ESI ; push EDI ; mov ESI,EDX ; mov EDI,EAX ; mov EBP,ECX ; bsr EAX,ECX ; // EAX is now 30..0 xor EAX,0x1F ; // EAX is now 1..31 mov CH,AL ; neg EAX ; add EAX,32 ; mov CL,AL ; mov EAX,EBX ; shr EAX,CL ; xchg CH,CL ; shl EBP,CL ; or EBP,EAX ; shl EBX,CL ; mov EDX,ESI ; xchg CH,CL ; shr EDX,CL ; mov EAX,EDI ; shr EAX,CL ; xchg CH,CL ; shl EDI,CL ; shl ESI,CL ; or EAX,ESI ; div EBP ; push EBP ; mov EBP,EAX ; mov ESI,EDX ; mul EBX ; cmp EDX,ESI ; ja L1 ; jb L2 ; cmp EAX,EDI ; jbe L2 ; L1: dec EBP ; sub EAX,EBX ; sbb EDX,0[ESP] ; L2: add ESP,4 ; sub EDI,EAX ; sbb ESI,EDX ; mov EAX,ESI ; xchg CH,CL ; shl EAX,CL ; xchg CH,CL ; shr EDI,CL ; or EDI,EAX ; shr ESI,CL ; mov EBX,EDI ; mov ECX,ESI ; mov EAX,EBP ; xor EDX,EDX ; pop EDI ; pop ESI ; pop EBP ; ret ; uldiv: test EDX,EDX ; jnz D3 ; // Both high words are 0, we can use the DIV instruction div EBX ; mov EBX,EDX ; mov EDX,ECX ; // EDX = ECX = 0 ret ; even ; D3: // Divide [EDX,EAX] by EBX mov ECX,EAX ; mov EAX,EDX ; xor EDX,EDX ; div EBX ; xchg ECX,EAX ; div EBX ; // ECX,EAX = result // EDX = remainder mov EBX,EDX ; mov EDX,ECX ; xor ECX,ECX ; ret ; quo0: // Quotient is 0 // Remainder is [EDX,EAX] mov EBX,EAX ; mov ECX,EDX ; xor EAX,EAX ; xor EDX,EDX ; ret ; Lleft: // The quotient is 0 or 1 and EDX >= ECX cmp EDX,ECX ; ja quo1 ; // [EDX,EAX] > [ECX,EBX] // EDX == ECX cmp EAX,EBX ; jb quo0 ; quo1: // Quotient is 1 // Remainder is [EDX,EAX] - [ECX,EBX] sub EAX,EBX ; sbb EDX,ECX ; mov EBX,EAX ; mov ECX,EDX ; mov EAX,1 ; xor EDX,EDX ; ret ; } } else version (D_InlineAsm_X86_64) assert(0); else static assert(0); } /*************************************** * Signed long divide. * Input: * [EDX,EAX],[ECX,EBX] * Output: * [EDX,EAX] = [EDX,EAX] / [ECX,EBX] * [ECX,EBX] = [EDX,EAX] % [ECX,EBX] * ESI,EDI destroyed */ void __LDIV2__() { version (D_InlineAsm_X86) { asm { naked ; test EDX,EDX ; // [EDX,EAX] negative? jns L10 ; // no //neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX] neg EDX ; neg EAX ; sbb EDX,0 ; test ECX,ECX ; // [ECX,EBX] negative? jns L11 ; // no //neg64 ECX,EBX ; neg ECX ; neg dword ptr 4[ESP] ; sbb ECX,0 ; push dword ptr 4[ESP] ; call __ULDIV2__ ; add ESP,4 ; //neg64 ECX,EBX ; // remainder same sign as dividend neg ECX ; neg EBX ; sbb ECX,0 ; ret ; L11: push dword ptr 4[ESP] ; call __ULDIV2__ ; add ESP,4 ; //neg64 ECX,EBX ; // remainder same sign as dividend neg ECX ; neg EBX ; sbb ECX,0 ; //neg64 EDX,EAX ; // quotient is negative neg EDX ; neg EAX ; sbb EDX,0 ; ret ; L10: test ECX,ECX ; // [ECX,EBX] negative? jns L12 ; // no (all is positive) //neg64 ECX,EBX ; neg ECX ; neg dword ptr 4[ESP] ; sbb ECX,0 ; push dword ptr 4[ESP] ; call __ULDIV2__ ; add ESP,4 ; //neg64 EDX,EAX ; // quotient is negative neg EDX ; neg EAX ; sbb EDX,0 ; ret ; L12: jmp __ULDIV2__ ; } } else version (D_InlineAsm_X86_64) assert(0); else static assert(0); } void __LDIV__() { version (D_InlineAsm_X86) { asm { naked ; test EDX,EDX ; // [EDX,EAX] negative? jns L10 ; // no //neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX] neg EDX ; neg EAX ; sbb EDX,0 ; test ECX,ECX ; // [ECX,EBX] negative? jns L11 ; // no //neg64 ECX,EBX ; neg ECX ; neg EBX ; sbb ECX,0 ; call __ULDIV__ ; //neg64 ECX,EBX ; // remainder same sign as dividend neg ECX ; neg EBX ; sbb ECX,0 ; ret ; L11: call __ULDIV__ ; //neg64 ECX,EBX ; // remainder same sign as dividend neg ECX ; neg EBX ; sbb ECX,0 ; //neg64 EDX,EAX ; // quotient is negative neg EDX ; neg EAX ; sbb EDX,0 ; ret ; L10: test ECX,ECX ; // [ECX,EBX] negative? jns L12 ; // no (all is positive) //neg64 ECX,EBX ; neg ECX ; neg EBX ; sbb ECX,0 ; call __ULDIV__ ; //neg64 EDX,EAX ; // quotient is negative neg EDX ; neg EAX ; sbb EDX,0 ; ret ; L12: jmp __ULDIV__ ; } } else version (D_InlineAsm_X86_64) assert(0); else static assert(0); } version(Win32) version(CRuntime_Microsoft) { extern(C) void _alldiv(); extern(C) void _aulldiv(); extern(C) void _allrem(); extern(C) void _aullrem(); void _ms_alldiv() { asm { naked ; push ECX ; push EBX ; push EDX ; push EAX ; call _alldiv ; ret ; } } void _ms_aulldiv() { asm { naked ; push ECX ; push EBX ; push EDX ; push EAX ; call _aulldiv ; ret ; } } void _ms_allrem() { asm { naked ; push ECX ; push EBX ; push EDX ; push EAX ; call _allrem ; mov EBX,EAX ; mov ECX,EDX ; ret ; } } void _ms_aullrem() { asm { naked ; push ECX ; push EBX ; push EDX ; push EAX ; call _aullrem ; mov EBX,EAX ; mov ECX,EDX ; ret ; } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/alloca.d0000664000175000017500000001777412776214756020317 0ustar kaikai/** * Implementation of alloca() standard C routine. * * Copyright: Copyright Digital Mars 2000 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright * Source: $(DRUNTIMESRC src/rt/_alloca.d) */ module rt.alloca; version (Posix) { version = alloca; } else version (CRuntime_Microsoft) { version = alloca; } // Use DMC++'s alloca() for Win32 version (alloca) { /+ #if DOS386 extern size_t _x386_break; #else extern size_t _pastdata; #endif +/ /******************************************* * Allocate data from the caller's stack frame. * This is a 'magic' function that needs help from the compiler to * work right, do not change its name, do not call it from other compilers. * Input: * nbytes number of bytes to allocate * ECX address of variable with # of bytes in locals * This is adjusted upon return to reflect the additional * size of the stack frame. * Returns: * EAX allocated data, null if stack overflows */ extern (C) void* __alloca(int nbytes) { version (D_InlineAsm_X86) { asm { naked ; mov EDX,ECX ; mov EAX,4[ESP] ; // get nbytes push EBX ; push EDI ; push ESI ; } version (OSX) { asm { add EAX,15 ; and EAX,0xFFFFFFF0 ; // round up to 16 byte boundary } } else { asm { add EAX,3 ; and EAX,0xFFFFFFFC ; // round up to dword } } asm { jnz Abegin ; mov EAX,4 ; // allow zero bytes allocation, 0 rounded to dword is 4.. Abegin: mov ESI,EAX ; // ESI = nbytes neg EAX ; add EAX,ESP ; // EAX is now what the new ESP will be. jae Aoverflow ; } version (Win32) { asm { // We need to be careful about the guard page // Thus, for every 4k page, touch it to cause the OS to load it in. mov ECX,EAX ; // ECX is new location for stack mov EBX,ESI ; // EBX is size to "grow" stack L1: test [ECX+EBX],EBX ; // bring in page sub EBX,0x1000 ; // next 4K page down jae L1 ; // if more pages test [ECX],EBX ; // bring in last page } } version (DOS386) { asm { // is ESP off bottom? cmp EAX,_x386_break ; jbe Aoverflow ; } } version (Unix) { asm { cmp EAX,_pastdata ; jbe Aoverflow ; // Unlikely - ~2 Gbytes under UNIX } } asm { // Copy down to [ESP] the temps on the stack. // The number of temps is (EBP - ESP - locals). mov ECX,EBP ; sub ECX,ESP ; sub ECX,[EDX] ; // ECX = number of temps (bytes) to move. add [EDX],ESI ; // adjust locals by nbytes for next call to alloca() mov ESP,EAX ; // Set up new stack pointer. add EAX,ECX ; // Return value = ESP + temps. mov EDI,ESP ; // Destination of copy of temps. add ESI,ESP ; // Source of copy. shr ECX,2 ; // ECX to count of dwords in temps // Always at least 4 (nbytes, EIP, ESI,and EDI). rep ; movsd ; jmp done ; Aoverflow: // Overflowed the stack. Return null xor EAX,EAX ; done: pop ESI ; pop EDI ; pop EBX ; ret ; } } else version (D_InlineAsm_X86_64) { version (Win64) { asm { /* RCX nbytes * RDX address of variable with # of bytes in locals * Must save registers RBX,RDI,RSI,R12..R15 */ naked ; push RBX ; push RDI ; push RSI ; mov RAX,RCX ; // get nbytes add RAX,15 ; and AL,0xF0 ; // round up to 16 byte boundary test RAX,RAX ; jnz Abegin ; mov RAX,16 ; // allow zero bytes allocation Abegin: mov RSI,RAX ; // RSI = nbytes neg RAX ; add RAX,RSP ; // RAX is now what the new RSP will be. jae Aoverflow ; // We need to be careful about the guard page // Thus, for every 4k page, touch it to cause the OS to load it in. mov RCX,RAX ; // RCX is new location for stack mov RBX,RSI ; // RBX is size to "grow" stack L1: test [RCX+RBX],RBX ; // bring in page sub RBX,0x1000 ; // next 4K page down jae L1 ; // if more pages test [RCX],RBX ; // bring in last page // Copy down to [RSP] the temps on the stack. // The number of temps is (RBP - RSP - locals). mov RCX,RBP ; sub RCX,RSP ; sub RCX,[RDX] ; // RCX = number of temps (bytes) to move. add [RDX],RSI ; // adjust locals by nbytes for next call to alloca() mov RSP,RAX ; // Set up new stack pointer. add RAX,RCX ; // Return value = RSP + temps. mov RDI,RSP ; // Destination of copy of temps. add RSI,RSP ; // Source of copy. shr RCX,3 ; // RCX to count of qwords in temps rep ; movsq ; jmp done ; Aoverflow: // Overflowed the stack. Return null xor RAX,RAX ; done: pop RSI ; pop RDI ; pop RBX ; ret ; } } else { asm { /* Parameter is passed in RDI * Must save registers RBX,R12..R15 */ naked ; mov RDX,RCX ; mov RAX,RDI ; // get nbytes add RAX,15 ; and AL,0xF0 ; // round up to 16 byte boundary test RAX,RAX ; jnz Abegin ; mov RAX,16 ; // allow zero bytes allocation Abegin: mov RSI,RAX ; // RSI = nbytes neg RAX ; add RAX,RSP ; // RAX is now what the new RSP will be. jae Aoverflow ; } version (Unix) { asm { cmp RAX,_pastdata ; jbe Aoverflow ; // Unlikely - ~2 Gbytes under UNIX } } asm { // Copy down to [RSP] the temps on the stack. // The number of temps is (RBP - RSP - locals). mov RCX,RBP ; sub RCX,RSP ; sub RCX,[RDX] ; // RCX = number of temps (bytes) to move. add [RDX],RSI ; // adjust locals by nbytes for next call to alloca() mov RSP,RAX ; // Set up new stack pointer. add RAX,RCX ; // Return value = RSP + temps. mov RDI,RSP ; // Destination of copy of temps. add RSI,RSP ; // Source of copy. shr RCX,3 ; // RCX to count of qwords in temps rep ; movsq ; jmp done ; Aoverflow: // Overflowed the stack. Return null xor RAX,RAX ; done: ret ; } } } else static assert(0); } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/deh_win64_posix.d0000664000175000017500000004033312776214756022060 0ustar kaikai/** * Written in the D programming language. * Implementation of exception handling support routines for Posix and Win64. * * Copyright: Copyright Digital Mars 2000 - 2013. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC src/rt/deh_win64_posix.d) */ module rt.deh_win64_posix; version (LDC) { // We use a libunwind-based scheme on all platforms. } else version (Win64) version = Win64_Posix; else version (Posix) version = Win64_Posix; version (Win64_Posix): //debug=PRINTF; debug(PRINTF) import core.stdc.stdio : printf; extern (C) { Throwable.TraceInfo _d_traceContext(void* ptr = null); int _d_isbaseof(ClassInfo oc, ClassInfo c); void _d_createTrace(Object o, void* context); } alias int function() fp_t; // function pointer in ambient memory model // DHandlerInfo table is generated by except_gentables() in eh.c struct DHandlerInfo { uint offset; // offset from function address to start of guarded section uint endoffset; // offset of end of guarded section int prev_index; // previous table index uint cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch) size_t finally_offset; // offset to finally code to execute // (!=0 if try-finally) } // Address of DHandlerTable, searched for by eh_finddata() struct DHandlerTable { uint espoffset; // offset of ESP from EBP uint retoffset; // offset from start of function to return code size_t nhandlers; // dimension of handler_info[] (use size_t to set alignment of handler_info[]) DHandlerInfo[1] handler_info; } struct DCatchBlock { ClassInfo type; // catch type size_t bpoffset; // EBP offset of catch var size_t codeoffset; // catch handler offset } // Create one of these for each try-catch struct DCatchInfo { size_t ncatches; // number of catch blocks DCatchBlock[1] catch_block; // data for each catch block } // One of these is generated for each function with try-catch or try-finally struct FuncTable { void *fptr; // pointer to start of function DHandlerTable *handlertable; // eh data for this function uint fsize; // size of function in bytes } private { struct InFlight { InFlight* next; void* addr; Throwable t; } InFlight* __inflight = null; /// __inflight is per-stack, not per-thread, and as such needs to be /// swapped out on fiber context switches. extern(C) void* _d_eh_swapContext(void* newContext) nothrow { auto old = __inflight; __inflight = cast(InFlight*)newContext; return old; } } void terminate() { asm { hlt ; } } /******************************************* * Given address that is inside a function, * figure out which function it is in. * Return DHandlerTable if there is one, NULL if not. */ immutable(FuncTable)* __eh_finddata(void *address) { import rt.sections; foreach (ref sg; SectionGroup) { auto pstart = sg.ehTables.ptr; auto pend = pstart + sg.ehTables.length; if (auto ft = __eh_finddata(address, pstart, pend)) return ft; } return null; } immutable(FuncTable)* __eh_finddata(void *address, immutable(FuncTable)* pstart, immutable(FuncTable)* pend) { debug(PRINTF) printf("FuncTable.sizeof = %p\n", FuncTable.sizeof); debug(PRINTF) printf("__eh_finddata(address = %p)\n", address); debug(PRINTF) printf("_deh_beg = %p, _deh_end = %p\n", pstart, pend); for (auto ft = pstart; 1; ft++) { Lagain: if (ft >= pend) break; version (Win64) { /* The MS Linker has an inexplicable and erratic tendency to insert * 8 zero bytes between sections generated from different .obj * files. This kludge tries to skip over them. */ if (ft.fptr == null) { ft = cast(immutable(FuncTable)*)(cast(void**)ft + 1); goto Lagain; } } debug(PRINTF) printf(" ft = %p, fptr = %p, handlertable = %p, fsize = x%03x\n", ft, ft.fptr, ft.handlertable, ft.fsize); immutable(void)* fptr = ft.fptr; version (Win64) { /* If linked with /DEBUG, the linker rewrites it so the function pointer points * to a JMP to the actual code. The address will be in the actual code, so we * need to follow the JMP. */ if ((cast(ubyte*)fptr)[0] == 0xE9) { // JMP target = RIP of next instruction + signed 32 bit displacement fptr = fptr + 5 + *cast(int*)(fptr + 1); } } if (fptr <= address && address < cast(void *)(cast(char *)fptr + ft.fsize)) { debug(PRINTF) printf("\tfound handler table\n"); return ft; } } debug(PRINTF) printf("\tnot found\n"); return null; } /****************************** * Given EBP, find return address to caller, and caller's EBP. * Input: * regbp Value of EBP for current function * *pretaddr Return address * Output: * *pretaddr return address to caller * Returns: * caller's EBP */ size_t __eh_find_caller(size_t regbp, size_t *pretaddr) { size_t bp = *cast(size_t *)regbp; if (bp) // if not end of call chain { // Perform sanity checks on new EBP. // If it is screwed up, terminate() hopefully before we do more damage. if (bp <= regbp) // stack should grow to smaller values terminate(); *pretaddr = *cast(size_t *)(regbp + size_t.sizeof); } return bp; } /*********************************** * Throw a D object. */ extern (C) void _d_throwc(Object h) { size_t regebp; debug(PRINTF) { printf("_d_throw(h = %p, &h = %p)\n", h, &h); printf("\tvptr = %p\n", *cast(void **)h); } version (D_InlineAsm_X86) asm { mov regebp,EBP ; } else version (D_InlineAsm_X86_64) asm { mov regebp,RBP ; } else static assert(0); _d_createTrace(h, null); //static uint abc; //if (++abc == 2) *(char *)0=0; //int count = 0; while (1) // for each function on the stack { size_t retaddr; regebp = __eh_find_caller(regebp,&retaddr); if (!regebp) { // if end of call chain debug(PRINTF) printf("end of call chain\n"); break; } debug(PRINTF) printf("found caller, EBP = %p, retaddr = %p\n", regebp, retaddr); //if (++count == 12) *(char*)0=0; auto func_table = __eh_finddata(cast(void *)retaddr); // find static data associated with function auto handler_table = func_table ? func_table.handlertable : null; if (!handler_table) // if no static data { debug(PRINTF) printf("no handler table\n"); continue; } auto funcoffset = cast(size_t)func_table.fptr; version (Win64) { /* If linked with /DEBUG, the linker rewrites it so the function pointer points * to a JMP to the actual code. The address will be in the actual code, so we * need to follow the JMP. */ if ((cast(ubyte*)funcoffset)[0] == 0xE9) { // JMP target = RIP of next instruction + signed 32 bit displacement funcoffset = funcoffset + 5 + *cast(int*)(funcoffset + 1); } } auto spoff = handler_table.espoffset; auto retoffset = handler_table.retoffset; debug(PRINTF) { printf("retaddr = %p\n", retaddr); printf("regebp=%p, funcoffset=%p, spoff=x%x, retoffset=x%x\n", regebp,funcoffset,spoff,retoffset); } // Find start index for retaddr in static data auto dim = handler_table.nhandlers; debug(PRINTF) { printf("handler_info[%d]:\n", dim); for (uint i = 0; i < dim; i++) { auto phi = &handler_table.handler_info.ptr[i]; printf("\t[%d]: offset = x%04x, endoffset = x%04x, prev_index = %d, cioffset = x%04x, finally_offset = %x\n", i, phi.offset, phi.endoffset, phi.prev_index, phi.cioffset, phi.finally_offset); } } auto index = -1; for (uint i = 0; i < dim; i++) { auto phi = &handler_table.handler_info.ptr[i]; debug(PRINTF) printf("i = %d, phi.offset = %04x\n", i, funcoffset + phi.offset); if (retaddr > funcoffset + phi.offset && retaddr <= funcoffset + phi.endoffset) index = i; } debug(PRINTF) printf("index = %d\n", index); if (dim) { auto phi = &handler_table.handler_info.ptr[index+1]; debug(PRINTF) printf("next finally_offset %p\n", phi.finally_offset); auto prev = cast(InFlight*) &__inflight; auto curr = prev.next; if (curr !is null && curr.addr == cast(void*)(funcoffset + phi.finally_offset)) { auto e = cast(Error)(cast(Throwable) h); if (e !is null && (cast(Error) curr.t) is null) { debug(PRINTF) printf("new error %p bypassing inflight %p\n", h, curr.t); e.bypassedException = curr.t; prev.next = curr.next; //h = cast(Object*) t; } else { debug(PRINTF) printf("replacing thrown %p with inflight %p\n", h, __inflight.t); auto t = curr.t; auto n = curr.t; while (n.next) n = n.next; n.next = cast(Throwable) h; prev.next = curr.next; h = t; } } } // walk through handler table, checking each handler // with an index smaller than the current table_index int prev_ndx; for (auto ndx = index; ndx != -1; ndx = prev_ndx) { auto phi = &handler_table.handler_info.ptr[ndx]; prev_ndx = phi.prev_index; if (phi.cioffset) { // this is a catch handler (no finally) auto pci = cast(DCatchInfo *)(cast(char *)handler_table + phi.cioffset); auto ncatches = pci.ncatches; for (uint i = 0; i < ncatches; i++) { auto ci = **cast(ClassInfo **)h; auto pcb = &pci.catch_block.ptr[i]; if (_d_isbaseof(ci, pcb.type)) { // Matched the catch type, so we've found the handler. // Initialize catch variable *cast(void **)(regebp + (pcb.bpoffset)) = cast(void*)h; // Jump to catch block. Does not return. { size_t catch_esp; fp_t catch_addr; catch_addr = cast(fp_t)(funcoffset + pcb.codeoffset); catch_esp = regebp - handler_table.espoffset - fp_t.sizeof; version (D_InlineAsm_X86) asm { mov EAX,catch_esp ; mov ECX,catch_addr ; mov [EAX],ECX ; mov EBP,regebp ; mov ESP,EAX ; // reset stack ret ; // jump to catch block } else version (D_InlineAsm_X86_64) asm { mov RAX,catch_esp ; mov RCX,catch_esp ; mov RCX,catch_addr ; mov [RAX],RCX ; mov RBP,regebp ; mov RSP,RAX ; // reset stack ret ; // jump to catch block } else static assert(0); } } } } else if (phi.finally_offset) { // Call finally block // Note that it is unnecessary to adjust the ESP, as the finally block // accesses all items on the stack as relative to EBP. debug(PRINTF) printf("calling finally_offset %p\n", phi.finally_offset); auto blockaddr = cast(void*)(funcoffset + phi.finally_offset); InFlight inflight; inflight.addr = blockaddr; inflight.next = __inflight; inflight.t = cast(Throwable) h; __inflight = &inflight; version (OSX) { version (D_InlineAsm_X86) asm { sub ESP,4 ; push EBX ; mov EBX,blockaddr ; push EBP ; mov EBP,regebp ; call EBX ; pop EBP ; pop EBX ; add ESP,4 ; } else version (D_InlineAsm_X86_64) asm { sub RSP,8 ; push RBX ; mov RBX,blockaddr ; push RBP ; mov RBP,regebp ; call RBX ; pop RBP ; pop RBX ; add RSP,8 ; } else static assert(0); } else { version (D_InlineAsm_X86) asm { push EBX ; mov EBX,blockaddr ; push EBP ; mov EBP,regebp ; call EBX ; pop EBP ; pop EBX ; } else version (D_InlineAsm_X86_64) asm { sub RSP,8 ; push RBX ; mov RBX,blockaddr ; push RBP ; mov RBP,regebp ; call RBX ; pop RBP ; pop RBX ; add RSP,8 ; } else static assert(0); } if (__inflight is &inflight) __inflight = __inflight.next; } } } terminate(); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/bss_section.c0000664000175000017500000000145712776214756021365 0ustar kaikai/** * This module is used to detect copy relocated ModuleInfos (located in .bss section). * * Copyright: Copyright Martin Nowak 2014-. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak * Source: $(DRUNTIMESRC src/rt/_bss_section.c) */ /* These symbols are defined in the linker script and bracket the * .bss, .lbss, .lrodata and .ldata sections. */ #if defined(__linux__) || defined(__FreeBSD__) // Need to use weak linkage to workaround a bug in ld.bfd (Bugzilla 13025). extern int __attribute__((weak)) __bss_start, _end; __attribute__ ((visibility ("hidden"))) void* rt_get_bss_start(); __attribute__ ((visibility ("hidden"))) void* rt_get_end(); void* rt_get_bss_start() { return (void*)&__bss_start; } void* rt_get_end() { return (void*)&_end; } #endif ldc-1.1.0-beta3-src/runtime/druntime/src/rt/dmain2.d0000664000175000017500000004052412776214756020223 0ustar kaikai/** * Contains druntime startup and shutdown routines. * * Copyright: Copyright Digital Mars 2000 - 2013. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC src/rt/_dmain2.d) */ module rt.dmain2; private { import rt.memory; import rt.sections; import core.atomic; import core.stdc.stddef; import core.stdc.stdlib; import core.stdc.string; import core.stdc.stdio; // for printf() import core.stdc.errno : errno; } version (Windows) { private import core.stdc.wchar_; private import core.sys.windows.windows; pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW } version (FreeBSD) { import core.stdc.fenv; } extern (C) void _d_monitor_staticctor(); extern (C) void _d_monitor_staticdtor(); extern (C) void _d_critical_init(); extern (C) void _d_critical_term(); extern (C) void gc_init(); extern (C) void gc_term(); extern (C) void lifetime_init(); extern (C) void rt_moduleCtor(); extern (C) void rt_moduleTlsCtor(); extern (C) void rt_moduleDtor(); extern (C) void rt_moduleTlsDtor(); extern (C) void thread_joinAll(); extern (C) bool runModuleUnitTests(); extern (C) void _d_initMonoTime(); version (OSX) { // The bottom of the stack extern (C) __gshared void* __osx_stack_end = cast(void*)0xC0000000; } version(CRuntime_Microsoft) { extern(C) void init_msvc(); } /*********************************** * These are a temporary means of providing a GC hook for DLL use. They may be * replaced with some other similar functionality later. */ extern (C) { void* gc_getProxy(); void gc_setProxy(void* p); void gc_clrProxy(); alias void* function() gcGetFn; alias void function(void*) gcSetFn; alias void function() gcClrFn; } version (Windows) { /******************************************* * Loads a DLL written in D with the name 'name'. * Returns: * opaque handle to the DLL if successfully loaded * null if failure */ extern (C) void* rt_loadLibrary(const char* name) { return initLibrary(.LoadLibraryA(name)); } extern (C) void* rt_loadLibraryW(const wchar_t* name) { return initLibrary(.LoadLibraryW(name)); } void* initLibrary(void* mod) { // BUG: LoadLibrary() call calls rt_init(), which fails if proxy is not set! // (What? LoadLibrary() is a Windows API call, it shouldn't call rt_init().) if (mod is null) return mod; gcSetFn gcSet = cast(gcSetFn) GetProcAddress(mod, "gc_setProxy"); if (gcSet !is null) { // BUG: Set proxy, but too late gcSet(gc_getProxy()); } return mod; } /************************************* * Unloads DLL that was previously loaded by rt_loadLibrary(). * Input: * ptr the handle returned by rt_loadLibrary() * Returns: * 1 succeeded * 0 some failure happened */ extern (C) int rt_unloadLibrary(void* ptr) { gcClrFn gcClr = cast(gcClrFn) GetProcAddress(ptr, "gc_clrProxy"); if (gcClr !is null) gcClr(); return FreeLibrary(ptr) != 0; } } /* To get out-of-band access to the args[] passed to main(). */ __gshared string[] _d_args = null; extern (C) string[] rt_args() { return _d_args; } // make arguments passed to main available for being filtered by runtime initializers extern(C) __gshared char[][] _d_main_args = null; // This variable is only ever set by a debugger on initialization so it should // be fine to leave it as __gshared. extern (C) __gshared bool rt_trapExceptions = true; alias void delegate(Throwable) ExceptionHandler; /** * Keep track of how often rt_init/rt_term were called. */ shared size_t _initCount; /********************************************** * Initialize druntime. * If a C program wishes to call D code, and there's no D main(), then it * must call rt_init() and rt_term(). */ extern (C) int rt_init() { /* @@BUG 11380 @@ Need to synchronize rt_init/rt_term calls for version (Shared) druntime, because multiple C threads might initialize different D libraries without knowing about the shared druntime. Also we need to attach any thread that calls rt_init. */ if (atomicOp!"+="(_initCount, 1) > 1) return 1; version (CRuntime_Microsoft) init_msvc(); _d_monitor_staticctor(); _d_critical_init(); try { initSections(); // this initializes mono time before anything else to allow usage // in other druntime systems. _d_initMonoTime(); gc_init(); initStaticDataGC(); lifetime_init(); rt_moduleCtor(); rt_moduleTlsCtor(); return 1; } catch (Throwable t) { _initCount = 0; _d_print_throwable(t); } _d_critical_term(); _d_monitor_staticdtor(); return 0; } /********************************************** * Terminate use of druntime. */ extern (C) int rt_term() { if (!_initCount) return 0; // was never initialized if (atomicOp!"-="(_initCount, 1)) return 1; try { rt_moduleTlsDtor(); thread_joinAll(); rt_moduleDtor(); gc_term(); finiSections(); return 1; } catch (Throwable t) { _d_print_throwable(t); } finally { _d_critical_term(); _d_monitor_staticdtor(); } return 0; } /********************************************** * Trace handler */ alias Throwable.TraceInfo function(void* ptr) TraceHandler; private __gshared TraceHandler traceHandler = null; /** * Overrides the default trace hander with a user-supplied version. * * Params: * h = The new trace handler. Set to null to use the default handler. */ extern (C) void rt_setTraceHandler(TraceHandler h) { traceHandler = h; } /** * Return the current trace handler */ extern (C) TraceHandler rt_getTraceHandler() { return traceHandler; } /** * This function will be called when an exception 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. */ extern (C) Throwable.TraceInfo _d_traceContext(void* ptr = null) { if (traceHandler is null) return null; return traceHandler(ptr); } /*********************************** * Provide out-of-band access to the original C argc/argv * passed to this program via main(argc,argv). */ struct CArgs { int argc; char** argv; } __gshared CArgs _cArgs; extern (C) CArgs rt_cArgs() @nogc { return _cArgs; } /*********************************** * Run the given main function. * Its purpose is to wrap the D main() * function and catch any unhandled exceptions. */ private alias extern(C) int function(char[][] args) MainFunc; extern (C) int _d_run_main(int argc, char **argv, MainFunc mainFunc) { // Remember the original C argc/argv _cArgs.argc = argc; _cArgs.argv = argv; int result; version (OSX) { /* OSX does not provide a way to get at the top of the * stack, except for the magic value 0xC0000000. * But as far as the gc is concerned, argv is at the top * of the main thread's stack, so save the address of that. */ __osx_stack_end = cast(void*)&argv; } version (FreeBSD) version (D_InlineAsm_X86) { /* * FreeBSD/i386 sets the FPU precision mode to 53 bit double. * Make it 64 bit extended. */ ushort fpucw; asm { fstsw fpucw; or fpucw, 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions fldcw fpucw; } } version (CRuntime_Microsoft) { init_msvc(); // enable full precision for reals version(Win64) asm { push RAX; fstcw word ptr [RSP]; or [RSP], 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions fldcw word ptr [RSP]; pop RAX; } else version(Win32) { asm { push EAX; fstcw word ptr [ESP]; or [ESP], 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions fldcw word ptr [ESP]; pop EAX; } } } version (Windows) { /* Because we want args[] to be UTF-8, and Windows doesn't guarantee that, * we ignore argc/argv and go get the Windows command line again as UTF-16. * Then, reparse into wargc/wargs, and then use Windows API to convert * to UTF-8. */ const wchar_t* wCommandLine = GetCommandLineW(); immutable size_t wCommandLineLength = wcslen(wCommandLine); int wargc; wchar_t** wargs = CommandLineToArgvW(wCommandLine, &wargc); // assert(wargc == argc); /* argc can be broken by Unicode arguments */ // Allocate args[] on the stack - use wargc char[][] args = (cast(char[]*) alloca(wargc * (char[]).sizeof))[0 .. wargc]; // This is required because WideCharToMultiByte requires int as input. assert(wCommandLineLength <= cast(size_t) int.max, "Wide char command line length must not exceed int.max"); immutable size_t totalArgsLength = WideCharToMultiByte(CP_UTF8, 0, wCommandLine, cast(int)wCommandLineLength, null, 0, null, null); { char* totalArgsBuff = cast(char*) alloca(totalArgsLength); size_t j = 0; foreach (i; 0 .. wargc) { immutable size_t wlen = wcslen(wargs[i]); assert(wlen <= cast(size_t) int.max, "wlen cannot exceed int.max"); immutable int len = WideCharToMultiByte(CP_UTF8, 0, &wargs[i][0], cast(int) wlen, null, 0, null, null); args[i] = totalArgsBuff[j .. j + len]; if (len == 0) continue; j += len; assert(j <= totalArgsLength); WideCharToMultiByte(CP_UTF8, 0, &wargs[i][0], cast(int) wlen, &args[i][0], len, null, null); } } LocalFree(wargs); wargs = null; wargc = 0; } else version (Posix) { // Allocate args[] on the stack char[][] args = (cast(char[]*) alloca(argc * (char[]).sizeof))[0 .. argc]; size_t totalArgsLength = 0; foreach(i, ref arg; args) { arg = argv[i][0 .. strlen(argv[i])]; totalArgsLength += arg.length; } } else static assert(0); /* Create a copy of args[] on the stack to be used for main, so that rt_args() * cannot be modified by the user. * Note that when this function returns, _d_args will refer to garbage. */ { _d_args = cast(string[]) args; auto buff = cast(char[]*) alloca(args.length * (char[]).sizeof + totalArgsLength); char[][] argsCopy = buff[0 .. args.length]; auto argBuff = cast(char*) (buff + args.length); size_t j = 0; foreach(arg; args) { if (arg.length < 6 || arg[0..6] != "--DRT-") // skip D runtime options { argsCopy[j++] = (argBuff[0 .. arg.length] = arg[]); argBuff += arg.length; } } args = argsCopy[0..j]; } bool trapExceptions = rt_trapExceptions; version (Windows) { if (IsDebuggerPresent()) trapExceptions = false; } void tryExec(scope void delegate() dg) { if (trapExceptions) { try { dg(); } catch (Throwable t) { _d_print_throwable(t); result = EXIT_FAILURE; } } else { dg(); } } // NOTE: The lifetime of a process is much like the lifetime of an object: // it is initialized, then used, then destroyed. If initialization // fails, the successive two steps are never reached. However, if // initialization succeeds, then cleanup will occur even if the use // step fails in some way. Here, the use phase consists of running // the user's main function. If main terminates with an exception, // the exception is handled and then cleanup begins. An exception // thrown during cleanup, however, will abort the cleanup process. void runAll() { if (rt_init() && runModuleUnitTests()) tryExec({ result = mainFunc(args); }); else result = EXIT_FAILURE; if (!rt_term()) result = (result == EXIT_SUCCESS) ? EXIT_FAILURE : result; } tryExec(&runAll); // Issue 10344: flush stdout and return nonzero on failure if (.fflush(.stdout) != 0) { .fprintf(.stderr, "Failed to flush stdout: %s\n", .strerror(.errno)); if (result == 0) { result = EXIT_FAILURE; } } return result; } private void formatThrowable(Throwable t, void delegate(in char[] s) nothrow sink) { for (; t; t = t.next) { t.toString(sink); sink("\n"); auto e = cast(Error)t; if (e is null || e.bypassedException is null) continue; sink("=== Bypassed ===\n"); for (auto t2 = e.bypassedException; t2; t2 = t2.next) { t2.toString(sink); sink("\n"); } sink("=== ~Bypassed ===\n"); } } extern (C) void _d_print_throwable(Throwable t) { // On Windows, a console may not be present to print the output to. // Show a message box instead. version (Windows) { // ensure the exception is shown at the beginning of the line, while also // checking whether stderr is a valid file int written = fprintf(stderr, "\n"); if (written <= 0) { static struct WSink { wchar_t* ptr; size_t len; void sink(in char[] s) nothrow { if (!s.length) return; int swlen = MultiByteToWideChar( CP_UTF8, 0, s.ptr, cast(int)s.length, null, 0); if (!swlen) return; auto newPtr = cast(wchar_t*)realloc(ptr, (this.len + swlen + 1) * wchar_t.sizeof); if (!newPtr) return; ptr = newPtr; auto written = MultiByteToWideChar( CP_UTF8, 0, s.ptr, cast(int)s.length, ptr+len, swlen); len += written; } wchar_t* get() { if (ptr) ptr[len] = 0; return ptr; } void free() { .free(ptr); } } WSink buf; formatThrowable(t, &buf.sink); if (buf.ptr) { WSink caption; if (t) caption.sink(t.classinfo.name); // Avoid static user32.dll dependency for console applications // by loading it dynamically as needed auto user32 = LoadLibraryW("user32.dll"); if (user32) { alias typeof(&MessageBoxW) PMessageBoxW; auto pMessageBoxW = cast(PMessageBoxW) GetProcAddress(user32, "MessageBoxW"); if (pMessageBoxW) pMessageBoxW(null, buf.get(), caption.get(), MB_ICONERROR); } FreeLibrary(user32); caption.free(); buf.free(); } return; } } void sink(in char[] buf) nothrow { fprintf(stderr, "%.*s", cast(int)buf.length, buf.ptr); } formatThrowable(t, &sink); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/aApplyR.d0000664000175000017500000005752712776214756020434 0ustar kaikai/** * 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. * * Copyright: Copyright Digital Mars 2004 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2004 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.aApplyR; /* 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 rt.util.utf; /**********************************************/ /* 1 argument versions */ // dg is D, but _aApplyRcd() is C extern (D) alias 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\U000A0456b"; 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 == '\U000A0456'); 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\U000A0456b"; 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 == '\U000A0456'); 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\U000A0456b"; 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 == 0xDA41); 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\U000A0456b"; 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 == 0xF2); break; case 2: assert(d == 0xA0); 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\U000A0456b"; 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 == 0xF2); break; case 2: assert(d == 0xA0); 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\U000A0456b"; 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 == 0xDA41); 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) alias 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\U000A0456b"; 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 == '\U000A0456'); 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\U000A0456b"; 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 == '\U000A0456'); 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\U000A0456b"; 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 == 0xDA41); 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\U000A0456b"; 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 == 0xF2); break; case 2: assert(k == 2); assert(d == 0xA0); 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\U000A0456b"; 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 == 0xF2); break; case 2: assert(k == 2); assert(d == 0xA0); 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\U000A0456b"; 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 == 0xDA41); 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); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/arraycat.d0000664000175000017500000000161212776214756020652 0ustar kaikai/** * Implementation of array copy support routines. * * Copyright: Copyright Digital Mars 2004 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2004 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.arraycat; private { import core.stdc.string; import rt.util.array; debug(PRINTF) import core.stdc.stdio; } extern (C) @trusted nothrow: void[] _d_arraycopy(size_t size, void[] from, void[] to) { debug(PRINTF) printf("f = %p,%d, t = %p,%d, size = %d\n", from.ptr, from.length, to.ptr, to.length, size); enforceRawArraysConformable("copy", size, from, to); memcpy(to.ptr, from.ptr, to.length * size); return to; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/aApply.d0000664000175000017500000005310512776214756020276 0ustar kaikai/** * 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. * * Copyright: Copyright Digital Mars 2004 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright * Source: $(DRUNTIMESRC src/rt/_aApply.d) */ module rt.aApply; private import rt.util.utf : decode, toUTF8; /**********************************************/ /* 1 argument versions */ // dg is D, but _aApplycd() is C extern (D) alias int delegate(void *) dg_t; extern (C) int _aApplycd1(in char[] aa, dg_t dg) { int result; size_t len = aa.length; debug(apply) printf("_aApplycd1(), len = %d\n", len); for (size_t i = 0; i < len; ) { dchar d = aa[i]; if (d & 0x80) d = decode(aa, i); else ++i; result = dg(cast(void *)&d); if (result) break; } return result; } unittest { debug(apply) printf("_aApplycd1.unittest\n"); auto s = "hello"c[]; int i; foreach(dchar d; s) { switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(dchar d; s) { //printf("i = %d, d = %x\n", i, d); switch (i) { case 0: assert(d == 'a'); break; case 1: assert(d == '\u1234'); break; case 2: assert(d == '\U000A0456'); break; case 3: assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 4); } /*****************************/ extern (C) int _aApplywd1(in wchar[] aa, dg_t dg) { int result; size_t len = aa.length; debug(apply) printf("_aApplywd1(), len = %d\n", len); for (size_t i = 0; i < len; ) { dchar d = aa[i]; if (d >= 0xD800) d = decode(aa, i); else ++i; result = dg(cast(void *)&d); if (result) break; } return result; } unittest { debug(apply) printf("_aApplywd1.unittest\n"); auto s = "hello"w[]; int i; foreach(dchar d; s) { switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(dchar d; s) { //printf("i = %d, d = %x\n", i, d); switch (i) { case 0: assert(d == 'a'); break; case 1: assert(d == '\u1234'); break; case 2: assert(d == '\U000A0456'); break; case 3: assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 4); } /*****************************/ extern (C) int _aApplycw1(in char[] aa, dg_t dg) { int result; size_t len = aa.length; debug(apply) printf("_aApplycw1(), len = %d\n", len); for (size_t i = 0; i < len; ) { wchar w = aa[i]; if (w & 0x80) { dchar 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; } unittest { debug(apply) printf("_aApplycw1.unittest\n"); auto s = "hello"c[]; int i; foreach(wchar d; s) { switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(wchar d; s) { //printf("i = %d, d = %x\n", i, d); switch (i) { case 0: assert(d == 'a'); break; case 1: assert(d == 0x1234); break; case 2: assert(d == 0xDA41); break; case 3: assert(d == 0xDC56); break; case 4: assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 5); } /*****************************/ extern (C) int _aApplywc1(in wchar[] aa, dg_t dg) { int result; size_t len = aa.length; debug(apply) printf("_aApplywc1(), len = %d\n", len); for (size_t i = 0; i < len; ) { wchar w = aa[i]; if (w & ~0x7F) { char[4] buf = void; dchar d = decode(aa, i); auto b = toUTF8(buf, d); foreach (char c2; b) { result = dg(cast(void *)&c2); if (result) return result; } } else { char c = cast(char)w; ++i; result = dg(cast(void *)&c); if (result) break; } } return result; } unittest { debug(apply) printf("_aApplywc1.unittest\n"); auto s = "hello"w[]; int i; foreach(char d; s) { switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(char d; s) { //printf("i = %d, d = %x\n", i, d); switch (i) { case 0: assert(d == 'a'); break; case 1: assert(d == 0xE1); break; case 2: assert(d == 0x88); break; case 3: assert(d == 0xB4); break; case 4: assert(d == 0xF2); break; case 5: assert(d == 0xA0); break; case 6: assert(d == 0x91); break; case 7: assert(d == 0x96); break; case 8: assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 9); } /*****************************/ extern (C) int _aApplydc1(in dchar[] aa, dg_t dg) { int result; debug(apply) printf("_aApplydc1(), len = %d\n", aa.length); foreach (dchar d; aa) { if (d & ~0x7F) { char[4] buf = void; auto b = toUTF8(buf, d); foreach (char c2; b) { result = dg(cast(void *)&c2); if (result) return result; } } else { char 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(char d; s) { switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(char d; s) { //printf("i = %d, d = %x\n", i, d); switch (i) { case 0: assert(d == 'a'); break; case 1: assert(d == 0xE1); break; case 2: assert(d == 0x88); break; case 3: assert(d == 0xB4); break; case 4: assert(d == 0xF2); break; case 5: assert(d == 0xA0); break; case 6: assert(d == 0x91); break; case 7: assert(d == 0x96); break; case 8: assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 9); } /*****************************/ extern (C) int _aApplydw1(in 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; } unittest { debug(apply) printf("_aApplydw1.unittest\n"); auto s = "hello"d[]; int i; foreach(wchar d; s) { switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(wchar d; s) { //printf("i = %d, d = %x\n", i, d); switch (i) { case 0: assert(d == 'a'); break; case 1: assert(d == 0x1234); break; case 2: assert(d == 0xDA41); break; case 3: assert(d == 0xDC56); break; case 4: assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 5); } /****************************************************************************/ /* 2 argument versions */ // dg is D, but _aApplycd2() is C extern (D) alias int delegate(void *, void *) dg2_t; extern (C) int _aApplycd2(in char[] aa, dg2_t dg) { int result; size_t len = aa.length; debug(apply) printf("_aApplycd2(), len = %d\n", len); size_t n; for (size_t i = 0; i < len; i += n) { dchar 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; } unittest { debug(apply) printf("_aApplycd2.unittest\n"); auto s = "hello"c[]; int i; foreach(k, dchar d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); assert(k == i); switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(k, dchar d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); switch (i) { case 0: assert(d == 'a'); assert(k == 0); break; case 1: assert(d == '\u1234'); assert(k == 1); break; case 2: assert(d == '\U000A0456'); assert(k == 4); break; case 3: assert(d == 'b'); assert(k == 8); break; default: assert(0); } i++; } assert(i == 4); } /*****************************/ extern (C) int _aApplywd2(in wchar[] aa, dg2_t dg) { int result; size_t len = aa.length; debug(apply) printf("_aApplywd2(), len = %d\n", len); size_t n; for (size_t i = 0; i < len; i += n) { dchar 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; } unittest { debug(apply) printf("_aApplywd2.unittest\n"); auto s = "hello"w[]; int i; foreach(k, dchar d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); assert(k == i); switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(k, dchar d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); switch (i) { case 0: assert(k == 0); assert(d == 'a'); break; case 1: assert(k == 1); assert(d == '\u1234'); break; case 2: assert(k == 2); assert(d == '\U000A0456'); break; case 3: assert(k == 4); assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 4); } /*****************************/ extern (C) int _aApplycw2(in char[] aa, dg2_t dg) { int result; size_t len = aa.length; debug(apply) printf("_aApplycw2(), len = %d\n", len); size_t n; for (size_t i = 0; i < len; i += n) { wchar w = aa[i]; if (w & 0x80) { n = i; dchar 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; } unittest { debug(apply) printf("_aApplycw2.unittest\n"); auto s = "hello"c[]; int i; foreach(k, wchar d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); assert(k == i); switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(k, wchar d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); switch (i) { case 0: assert(k == 0); assert(d == 'a'); break; case 1: assert(k == 1); assert(d == 0x1234); break; case 2: assert(k == 4); assert(d == 0xDA41); break; case 3: assert(k == 4); assert(d == 0xDC56); break; case 4: assert(k == 8); assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 5); } /*****************************/ extern (C) int _aApplywc2(in wchar[] aa, dg2_t dg) { int result; size_t len = aa.length; debug(apply) printf("_aApplywc2(), len = %d\n", len); size_t n; for (size_t i = 0; i < len; i += n) { wchar w = aa[i]; if (w & ~0x7F) { char[4] buf = void; n = i; dchar 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; } } else { char c = cast(char)w; n = 1; result = dg(&i, cast(void *)&c); if (result) break; } } return result; } unittest { debug(apply) printf("_aApplywc2.unittest\n"); auto s = "hello"w[]; int i; foreach(k, char d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); assert(k == i); switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(k, char d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); switch (i) { case 0: assert(k == 0); assert(d == 'a'); break; case 1: assert(k == 1); assert(d == 0xE1); break; case 2: assert(k == 1); assert(d == 0x88); break; case 3: assert(k == 1); assert(d == 0xB4); break; case 4: assert(k == 2); assert(d == 0xF2); break; case 5: assert(k == 2); assert(d == 0xA0); break; case 6: assert(k == 2); assert(d == 0x91); break; case 7: assert(k == 2); assert(d == 0x96); break; case 8: assert(k == 4); assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 9); } /*****************************/ extern (C) int _aApplydc2(in dchar[] aa, dg2_t dg) { int result; size_t len = aa.length; debug(apply) printf("_aApplydc2(), len = %d\n", len); for (size_t i = 0; i < len; i++) { dchar d = aa[i]; if (d & ~0x7F) { char[4] buf = void; auto b = toUTF8(buf, d); foreach (char c2; b) { result = dg(&i, cast(void *)&c2); if (result) return result; } } else { char c = cast(char)d; result = dg(&i, cast(void *)&c); if (result) break; } } return result; } unittest { debug(apply) printf("_aApplydc2.unittest\n"); auto s = "hello"d[]; int i; foreach(k, char d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); assert(k == i); switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(k, char d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); switch (i) { case 0: assert(k == 0); assert(d == 'a'); break; case 1: assert(k == 1); assert(d == 0xE1); break; case 2: assert(k == 1); assert(d == 0x88); break; case 3: assert(k == 1); assert(d == 0xB4); break; case 4: assert(k == 2); assert(d == 0xF2); break; case 5: assert(k == 2); assert(d == 0xA0); break; case 6: assert(k == 2); assert(d == 0x91); break; case 7: assert(k == 2); assert(d == 0x96); break; case 8: assert(k == 3); assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 9); } /*****************************/ extern (C) int _aApplydw2(in 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; } unittest { debug(apply) printf("_aApplydw2.unittest\n"); auto s = "hello"d[]; int i; foreach(k, wchar d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); assert(k == i); switch (i) { case 0: assert(d == 'h'); break; case 1: assert(d == 'e'); break; case 2: assert(d == 'l'); break; case 3: assert(d == 'l'); break; case 4: assert(d == 'o'); break; default: assert(0); } i++; } assert(i == 5); s = "a\u1234\U000A0456b"; i = 0; foreach(k, wchar d; s) { //printf("i = %d, k = %d, d = %x\n", i, k, d); switch (i) { case 0: assert(k == 0); assert(d == 'a'); break; case 1: assert(k == 1); assert(d == 0x1234); break; case 2: assert(k == 2); assert(d == 0xDA41); break; case 3: assert(k == 2); assert(d == 0xDC56); break; case 4: assert(k == 3); assert(d == 'b'); break; default: assert(0); } i++; } assert(i == 5); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/switch_.d0000664000175000017500000002351112776214756020506 0ustar kaikai/** * Contains support code for switch blocks using string constants. * * Copyright: Copyright Digital Mars 2004 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, Sean Kelly */ /* Copyright Digital Mars 2004 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.switch_; private import core.stdc.string; /****************************************************** * Support for switch statements switching on strings. * Input: * table[] sorted array of strings generated by compiler * ca string to look up in table * Output: * result index of match in table[] * -1 if not in table */ extern (C): int _d_switch_string(char[][] table, char[] ca) in { //printf("in _d_switch_string()\n"); assert(table.length >= 0); assert(ca.length >= 0); // Make sure table[] is sorted correctly for (size_t j = 1u; j < table.length; j++) { auto len1 = table[j - 1].length; auto len2 = table[j].length; assert(len1 <= len2); if (len1 == len2) { int ci; ci = memcmp(table[j - 1].ptr, table[j].ptr, len1); assert(ci < 0); // ci==0 means a duplicate } } } out (result) { int cj; //printf("out _d_switch_string()\n"); if (result == -1) { // Not found for (auto i = 0u; i < table.length; i++) { if (table[i].length == ca.length) { cj = memcmp(table[i].ptr, ca.ptr, ca.length); assert(cj != 0); } } } else { assert(0 <= result && cast(size_t)result < table.length); for (auto i = 0u; 1; i++) { assert(i < table.length); if (table[i].length == ca.length) { cj = memcmp(table[i].ptr, ca.ptr, ca.length); if (cj == 0) { assert(i == result); break; } } } } } body { //printf("body _d_switch_string(%.*s)\n", ca.length, ca.ptr); size_t low = 0; size_t high = table.length; version (none) { // Print table printf("ca[] = '%s'\n", ca.length, ca.ptr); for (auto i = 0; i < high; i++) { auto pca = table[i]; printf("table[%d] = %d, '%.*s'\n", i, pca.length, pca.length, pca.ptr); } } if (high && ca.length >= table[0].length && ca.length <= table[high - 1].length) { // Looking for 0 length string, which would only be at the beginning if (ca.length == 0) return 0; char c1 = ca[0]; // Do binary search while (low < high) { auto mid = (low + high) >> 1; auto pca = table[mid]; auto c = cast(sizediff_t)(ca.length - pca.length); if (c == 0) { c = cast(ubyte)c1 - cast(ubyte)pca[0]; if (c == 0) { c = memcmp(ca.ptr, pca.ptr, ca.length); if (c == 0) { //printf("found %d\n", mid); return cast(int)mid; } } } if (c < 0) { high = mid; } else { low = mid + 1; } } } //printf("not found\n"); return -1; // not found } unittest { switch (cast(char []) "c") { case "coo": default: break; } int bug5381(string s) { switch(s) { case "unittest": return 1; case "D_Version2": return 2; case "none": return 3; case "all": return 4; default: return 5; } } int rc = bug5381("none"); assert(rc == 3); } /********************************** * Same thing, but for wide chars. */ int _d_switch_ustring(wchar[][] table, wchar[] ca) in { //printf("in _d_switch_ustring()\n"); assert(table.length >= 0); assert(ca.length >= 0); // Make sure table[] is sorted correctly for (size_t j = 1u; j < table.length; j++) { auto len1 = table[j - 1].length; auto len2 = table[j].length; assert(len1 <= len2); if (len1 == len2) { int c; c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * wchar.sizeof); assert(c < 0); // c==0 means a duplicate } } } out (result) { int c; //printf("out _d_switch_ustring()\n"); if (result == -1) { // Not found for (auto i = 0u; i < table.length; i++) { if (table[i].length == ca.length) { c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof); assert(c != 0); } } } else { assert(0 <= result && cast(size_t)result < table.length); for (auto i = 0u; 1; i++) { assert(i < table.length); if (table[i].length == ca.length) { c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof); if (c == 0) { assert(i == result); break; } } } } } body { //printf("body _d_switch_ustring()\n"); size_t low = 0; auto high = table.length; version(none) { // Print table wprintf("ca[] = '%.*s'\n", ca.length, ca.ptr); for (auto i = 0; i < high; i++) { auto pca = table[i]; wprintf("table[%d] = %d, '%.*s'\n", i, pca.length, pca.length, pca.ptr); } } // Do binary search while (low < high) { auto mid = (low + high) >> 1; auto pca = table[mid]; auto c = cast(sizediff_t)(ca.length - pca.length); if (c == 0) { c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof); if (c == 0) { //printf("found %d\n", mid); return cast(int)mid; } } if (c < 0) { high = mid; } else { low = mid + 1; } } //printf("not found\n"); return -1; // not found } unittest { switch (cast(wchar []) "c") { case "coo": default: break; } int bug5381(wstring ws) { switch(ws) { case "unittest": return 1; case "D_Version2": return 2; case "none": return 3; case "all": return 4; default: return 5; } } int rc = bug5381("none"w); assert(rc == 3); } /********************************** * Same thing, but for wide chars. */ int _d_switch_dstring(dchar[][] table, dchar[] ca) in { //printf("in _d_switch_dstring()\n"); assert(table.length >= 0); assert(ca.length >= 0); // Make sure table[] is sorted correctly for (auto j = 1u; j < table.length; j++) { auto len1 = table[j - 1].length; auto len2 = table[j].length; assert(len1 <= len2); if (len1 == len2) { auto c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * dchar.sizeof); assert(c < 0); // c==0 means a duplicate } } } out (result) { //printf("out _d_switch_dstring()\n"); if (result == -1) { // Not found for (auto i = 0u; i < table.length; i++) { if (table[i].length == ca.length) { auto c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof); assert(c != 0); } } } else { assert(0 <= result && cast(size_t)result < table.length); for (auto i = 0u; 1; i++) { assert(i < table.length); if (table[i].length == ca.length) { auto c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof); if (c == 0) { assert(i == result); break; } } } } } body { //printf("body _d_switch_dstring()\n"); size_t low = 0; auto high = table.length; version(none) { // Print table wprintf("ca[] = '%.*s'\n", ca.length, ca.ptr); for (auto i = 0; i < high; i++) { auto pca = table[i]; wprintf("table[%d] = %d, '%.*s'\n", i, pca.length, pca.length, pca.ptr); } } // Do binary search while (low < high) { auto mid = (low + high) >> 1; auto pca = table[mid]; auto c = cast(sizediff_t)(ca.length - pca.length); if (c == 0) { c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof); if (c == 0) { //printf("found %d\n", mid); return cast(int)mid; } } if (c < 0) { high = mid; } else { low = mid + 1; } } //printf("not found\n"); return -1; // not found } unittest { switch (cast(dchar []) "c") { case "coo": default: break; } int bug5381(dstring ds) { switch(ds) { case "unittest": return 1; case "D_Version2": return 2; case "none": return 3; case "all": return 4; default: return 5; } } int rc = bug5381("none"d); assert(rc == 3); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/sections_elf_shared.d0000664000175000017500000007705412776214756023064 0ustar kaikai/** * Written in the D programming language. * This module provides ELF-specific support for sections with shared libraries. * * Copyright: Copyright Martin Nowak 2012-2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak * Source: $(DRUNTIMESRC src/rt/_sections_linux.d) */ module rt.sections_elf_shared; version (CRuntime_Glibc) enum SharedELF = true; else version (FreeBSD) enum SharedELF = true; else enum SharedELF = false; static if (SharedELF): // debug = PRINTF; import core.memory; import core.stdc.stdio; import core.stdc.stdlib : calloc, exit, free, malloc, EXIT_FAILURE; import core.stdc.string : strlen; version (linux) { import core.sys.linux.dlfcn; import core.sys.linux.elf; import core.sys.linux.link; } else version (FreeBSD) { import core.sys.freebsd.dlfcn; import core.sys.freebsd.sys.elf; import core.sys.freebsd.sys.link_elf; } else { static assert(0, "unimplemented"); } import core.sys.posix.pthread; version (DigitalMars) import rt.deh; import rt.dmain2; import rt.minfo; import rt.util.container.array; import rt.util.container.hashtab; alias DSO SectionGroup; struct DSO { static int opApply(scope int delegate(ref DSO) dg) { foreach (dso; _loadedDSOs) { if (auto res = dg(*dso)) return res; } return 0; } static int opApplyReverse(scope int delegate(ref DSO) dg) { foreach_reverse (dso; _loadedDSOs) { if (auto res = dg(*dso)) return res; } return 0; } @property immutable(ModuleInfo*)[] modules() const { return _moduleGroup.modules; } @property ref inout(ModuleGroup) moduleGroup() inout { return _moduleGroup; } version (DigitalMars) @property immutable(FuncTable)[] ehTables() const { return _ehTables[]; } @property inout(void[])[] gcRanges() inout { return _gcRanges[]; } private: invariant() { assert(_moduleGroup.modules.length); assert(_tlsMod || !_tlsSize); } version (DigitalMars) immutable(FuncTable)[] _ehTables; ModuleGroup _moduleGroup; Array!(void[]) _gcRanges; size_t _tlsMod; size_t _tlsSize; version (Shared) { Array!(void[]) _codeSegments; // array of code segments Array!(DSO*) _deps; // D libraries needed by this DSO void* _handle; // corresponding handle } } /**** * Boolean flag set to true while the runtime is initialized. */ __gshared bool _isRuntimeInitialized; version (FreeBSD) private __gshared void* dummy_ref; /**** * Gets called on program startup just before GC is initialized. */ void initSections() { _isRuntimeInitialized = true; // reference symbol to support weak linkage version (FreeBSD) dummy_ref = &_d_dso_registry; } /*** * Gets called on program shutdown just after GC is terminated. */ void finiSections() { _isRuntimeInitialized = false; } alias ScanDG = void delegate(void* pbeg, void* pend) nothrow; version (Shared) { /*** * Called once per thread; returns array of thread local storage ranges */ Array!(ThreadDSO)* initTLSRanges() { return &_loadedDSOs; } void finiTLSRanges(Array!(ThreadDSO)* tdsos) { tdsos.reset(); } void scanTLSRanges(Array!(ThreadDSO)* tdsos, scope ScanDG dg) nothrow { foreach (ref tdso; *tdsos) dg(tdso._tlsRange.ptr, tdso._tlsRange.ptr + tdso._tlsRange.length); } // interface for core.thread to inherit loaded libraries void* pinLoadedLibraries() nothrow { auto res = cast(Array!(ThreadDSO)*)calloc(1, Array!(ThreadDSO).sizeof); res.length = _loadedDSOs.length; foreach (i, ref tdso; _loadedDSOs) { (*res)[i] = tdso; if (tdso._addCnt) { // Increment the dlopen ref for explicitly loaded libraries to pin them. .dlopen(linkMapForHandle(tdso._pdso._handle).l_name, RTLD_LAZY) !is null || assert(0); (*res)[i]._addCnt = 1; // new array takes over the additional ref count } } return res; } void unpinLoadedLibraries(void* p) nothrow { auto pary = cast(Array!(ThreadDSO)*)p; // In case something failed we need to undo the pinning. foreach (ref tdso; *pary) { if (tdso._addCnt) { auto handle = tdso._pdso._handle; handle !is null || assert(0); .dlclose(handle); } } pary.reset(); .free(pary); } // Called before TLS ctors are ran, copy over the loaded libraries // of the parent thread. void inheritLoadedLibraries(void* p) { assert(_loadedDSOs.empty); _loadedDSOs.swap(*cast(Array!(ThreadDSO)*)p); .free(p); foreach (ref dso; _loadedDSOs) { // the copied _tlsRange corresponds to parent thread dso.updateTLSRange(); } } // Called after all TLS dtors ran, decrements all remaining dlopen refs. void cleanupLoadedLibraries() { foreach (ref tdso; _loadedDSOs) { if (tdso._addCnt == 0) continue; auto handle = tdso._pdso._handle; handle !is null || assert(0); for (; tdso._addCnt > 0; --tdso._addCnt) .dlclose(handle); } _loadedDSOs.reset(); } } else { /*** * Called once per thread; returns array of thread local storage ranges */ Array!(void[])* initTLSRanges() { return &_tlsRanges; } void finiTLSRanges(Array!(void[])* rngs) { rngs.reset(); } void scanTLSRanges(Array!(void[])* rngs, scope ScanDG dg) nothrow { foreach (rng; *rngs) dg(rng.ptr, rng.ptr + rng.length); } } private: // start of linked list for ModuleInfo references version (FreeBSD) deprecated extern (C) __gshared void* _Dmodule_ref; version (Shared) { /* * Array of thread local DSO metadata for all libraries loaded and * initialized in this thread. * * Note: * A newly spawned thread will inherit these libraries. * Note: * We use an array here to preserve the order of * initialization. If that became a performance issue, we * could use a hash table and enumerate the DSOs during * loading so that the hash table values could be sorted when * necessary. */ struct ThreadDSO { DSO* _pdso; static if (_pdso.sizeof == 8) uint _refCnt, _addCnt; else static if (_pdso.sizeof == 4) ushort _refCnt, _addCnt; else static assert(0, "unimplemented"); void[] _tlsRange; alias _pdso this; // update the _tlsRange for the executing thread void updateTLSRange() { _tlsRange = getTLSRange(_pdso._tlsMod, _pdso._tlsSize); } } Array!(ThreadDSO) _loadedDSOs; /* * Set to true during rt_loadLibrary/rt_unloadLibrary calls. */ bool _rtLoading; /* * Hash table to map link_map* to corresponding DSO*. * The hash table is protected by a Mutex. */ __gshared pthread_mutex_t _handleToDSOMutex; __gshared HashTab!(void*, DSO*) _handleToDSO; /* * Section in executable that contains copy relocations. * Might be null when druntime is dynamically loaded by a C host. */ __gshared const(void)[] _copyRelocSection; } else { /* * Static DSOs loaded by the runtime linker. This includes the * executable. These can't be unloaded. */ __gshared Array!(DSO*) _loadedDSOs; /* * Thread local array that contains TLS memory ranges for each * library initialized in this thread. */ Array!(void[]) _tlsRanges; enum _rtLoading = false; } /////////////////////////////////////////////////////////////////////////////// // Compiler to runtime interface. /////////////////////////////////////////////////////////////////////////////// /* * This data structure is generated by the compiler, and then passed to * _d_dso_registry(). */ struct CompilerDSOData { size_t _version; // currently 1 void** _slot; // can be used to store runtime data immutable(object.ModuleInfo*)* _minfo_beg, _minfo_end; // array of modules in this object file version (DigitalMars) immutable(rt.deh.FuncTable)* _deh_beg, _deh_end; // array of exception handling data } T[] toRange(T)(T* beg, T* end) { return beg[0 .. end - beg]; } /* For each shared library and executable, the compiler generates code that * sets up CompilerDSOData and calls _d_dso_registry(). * A pointer to that code is inserted into both the .ctors and .dtors * segment so it gets called by the loader on startup and shutdown. */ extern(C) void _d_dso_registry(CompilerDSOData* data) { // only one supported currently data._version >= 1 || assert(0, "corrupt DSO data version"); // no backlink => register if (*data._slot is null) { immutable firstDSO = _loadedDSOs.empty; if (firstDSO) initLocks(); DSO* pdso = cast(DSO*).calloc(1, DSO.sizeof); assert(typeid(DSO).initializer().ptr is null); *data._slot = pdso; // store backlink in library record auto minfoBeg = data._minfo_beg; while (minfoBeg < data._minfo_end && !*minfoBeg) ++minfoBeg; auto minfoEnd = minfoBeg; while (minfoEnd < data._minfo_end && *minfoEnd) ++minfoEnd; pdso._moduleGroup = ModuleGroup(toRange(minfoBeg, minfoEnd)); version (DigitalMars) pdso._ehTables = toRange(data._deh_beg, data._deh_end); dl_phdr_info info = void; findDSOInfoForAddr(data._slot, &info) || assert(0); scanSegments(info, pdso); version (Shared) { auto handle = handleForAddr(data._slot); if (firstDSO) { /// Assert that the first loaded DSO is druntime itself. Use a /// local druntime symbol (rt_get_bss_start) to get the handle. version (LDC) {} else assert(handleForAddr(data._slot) == handleForAddr(&rt_get_bss_start)); _copyRelocSection = getCopyRelocSection(); } checkModuleCollisions(info, pdso._moduleGroup.modules, _copyRelocSection); getDependencies(info, pdso._deps); pdso._handle = handle; setDSOForHandle(pdso, pdso._handle); if (!_rtLoading) { /* This DSO was not loaded by rt_loadLibrary which * happens for all dependencies of an executable or * the first dlopen call from a C program. * In this case we add the DSO to the _loadedDSOs of this * thread with a refCnt of 1 and call the TlsCtors. */ immutable ushort refCnt = 1, addCnt = 0; auto tlsRng = getTLSRange(pdso._tlsMod, pdso._tlsSize); _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt, tlsRng)); } } else { version (LDC) { // We don't want to depend on __tls_get_addr in non-Shared builds // so we can actually link statically, so there must be only one // D shared object. _loadedDSOs.empty || assert(0, "Only one D shared object allowed for static runtime"); } foreach (p; _loadedDSOs) assert(p !is pdso); _loadedDSOs.insertBack(pdso); _tlsRanges.insertBack(getTLSRange(pdso._tlsMod, pdso._tlsSize)); } // don't initialize modules before rt_init was called (see Bugzilla 11378) if (_isRuntimeInitialized) { registerGCRanges(pdso); // rt_loadLibrary will run tls ctors, so do this only for dlopen immutable runTlsCtors = !_rtLoading; runModuleConstructors(pdso, runTlsCtors); } } // has backlink => unregister else { DSO* pdso = cast(DSO*)*data._slot; *data._slot = null; // don't finalizes modules after rt_term was called (see Bugzilla 11378) if (_isRuntimeInitialized) { // rt_unloadLibrary already ran tls dtors, so do this only for dlclose immutable runTlsDtors = !_rtLoading; runModuleDestructors(pdso, runTlsDtors); unregisterGCRanges(pdso); // run finalizers after module dtors (same order as in rt_term) version (Shared) runFinalizers(pdso); } version (Shared) { if (!_rtLoading) { /* This DSO was not unloaded by rt_unloadLibrary so we * have to remove it from _loadedDSOs here. */ foreach (i, ref tdso; _loadedDSOs) { if (tdso._pdso == pdso) { _loadedDSOs.remove(i); break; } } } assert(pdso._handle == handleForAddr(data._slot)); unsetDSOForHandle(pdso, pdso._handle); pdso._handle = null; } else { // static DSOs are unloaded in reverse order assert(pdso._tlsSize == _tlsRanges.back.length); _tlsRanges.popBack(); assert(pdso == _loadedDSOs.back); _loadedDSOs.popBack(); } freeDSO(pdso); if (_loadedDSOs.empty) finiLocks(); // last DSO } } /////////////////////////////////////////////////////////////////////////////// // dynamic loading /////////////////////////////////////////////////////////////////////////////// // Shared D libraries are only supported when linking against a shared druntime library. version (Shared) { ThreadDSO* findThreadDSO(DSO* pdso) { foreach (ref tdata; _loadedDSOs) if (tdata._pdso == pdso) return &tdata; return null; } void incThreadRef(DSO* pdso, bool incAdd) { if (auto tdata = findThreadDSO(pdso)) // already initialized { if (incAdd && ++tdata._addCnt > 1) return; ++tdata._refCnt; } else { foreach (dep; pdso._deps) incThreadRef(dep, false); immutable ushort refCnt = 1, addCnt = incAdd ? 1 : 0; auto tlsRng = getTLSRange(pdso._tlsMod, pdso._tlsSize); _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt, tlsRng)); pdso._moduleGroup.runTlsCtors(); } } void decThreadRef(DSO* pdso, bool decAdd) { auto tdata = findThreadDSO(pdso); tdata !is null || assert(0); !decAdd || tdata._addCnt > 0 || assert(0, "Mismatching rt_unloadLibrary call."); if (decAdd && --tdata._addCnt > 0) return; if (--tdata._refCnt > 0) return; pdso._moduleGroup.runTlsDtors(); foreach (i, ref td; _loadedDSOs) if (td._pdso == pdso) _loadedDSOs.remove(i); foreach (dep; pdso._deps) decThreadRef(dep, false); } extern(C) void* rt_loadLibrary(const char* name) { immutable save = _rtLoading; _rtLoading = true; scope (exit) _rtLoading = save; auto handle = .dlopen(name, RTLD_LAZY); if (handle is null) return null; // if it's a D library if (auto pdso = dsoForHandle(handle)) incThreadRef(pdso, true); return handle; } extern(C) int rt_unloadLibrary(void* handle) { if (handle is null) return false; immutable save = _rtLoading; _rtLoading = true; scope (exit) _rtLoading = save; // if it's a D library if (auto pdso = dsoForHandle(handle)) decThreadRef(pdso, true); return .dlclose(handle) == 0; } } /////////////////////////////////////////////////////////////////////////////// // helper functions /////////////////////////////////////////////////////////////////////////////// void initLocks() { version (Shared) !pthread_mutex_init(&_handleToDSOMutex, null) || assert(0); } void finiLocks() { version (Shared) !pthread_mutex_destroy(&_handleToDSOMutex) || assert(0); } void runModuleConstructors(DSO* pdso, bool runTlsCtors) { pdso._moduleGroup.sortCtors(); pdso._moduleGroup.runCtors(); if (runTlsCtors) pdso._moduleGroup.runTlsCtors(); } void runModuleDestructors(DSO* pdso, bool runTlsDtors) { if (runTlsDtors) pdso._moduleGroup.runTlsDtors(); pdso._moduleGroup.runDtors(); } void registerGCRanges(DSO* pdso) { foreach (rng; pdso._gcRanges) GC.addRange(rng.ptr, rng.length); } void unregisterGCRanges(DSO* pdso) { foreach (rng; pdso._gcRanges) GC.removeRange(rng.ptr); } version (Shared) void runFinalizers(DSO* pdso) { foreach (seg; pdso._codeSegments) GC.runFinalizers(seg); } void freeDSO(DSO* pdso) { pdso._gcRanges.reset(); version (Shared) pdso._codeSegments.reset(); .free(pdso); } version (Shared) { nothrow: link_map* linkMapForHandle(void* handle) { link_map* map; dlinfo(handle, RTLD_DI_LINKMAP, &map) == 0 || assert(0); return map; } link_map* exeLinkMap(link_map* map) { assert(map); while (map.l_prev !is null) map = map.l_prev; return map; } DSO* dsoForHandle(void* handle) { DSO* pdso; !pthread_mutex_lock(&_handleToDSOMutex) || assert(0); if (auto ppdso = handle in _handleToDSO) pdso = *ppdso; !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0); return pdso; } void setDSOForHandle(DSO* pdso, void* handle) { !pthread_mutex_lock(&_handleToDSOMutex) || assert(0); assert(handle !in _handleToDSO); _handleToDSO[handle] = pdso; !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0); } void unsetDSOForHandle(DSO* pdso, void* handle) { !pthread_mutex_lock(&_handleToDSOMutex) || assert(0); assert(_handleToDSO[handle] == pdso); _handleToDSO.remove(handle); !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0); } void getDependencies(in ref dl_phdr_info info, ref Array!(DSO*) deps) { // get the entries of the .dynamic section ElfW!"Dyn"[] dyns; foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) { if (phdr.p_type == PT_DYNAMIC) { auto p = cast(ElfW!"Dyn"*)(info.dlpi_addr + phdr.p_vaddr); dyns = p[0 .. phdr.p_memsz / ElfW!"Dyn".sizeof]; break; } } // find the string table which contains the sonames const(char)* strtab; foreach (dyn; dyns) { if (dyn.d_tag == DT_STRTAB) { version (linux) strtab = cast(const(char)*)dyn.d_un.d_ptr; else version (FreeBSD) strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate else static assert(0, "unimplemented"); break; } } foreach (dyn; dyns) { immutable tag = dyn.d_tag; if (!(tag == DT_NEEDED || tag == DT_AUXILIARY || tag == DT_FILTER)) continue; // soname of the dependency auto name = strtab + dyn.d_un.d_val; // get handle without loading the library auto handle = handleForName(name); // the runtime linker has already loaded all dependencies if (handle is null) assert(0); // if it's a D library if (auto pdso = dsoForHandle(handle)) deps.insertBack(pdso); // append it to the dependencies } } void* handleForName(const char* name) { auto handle = .dlopen(name, RTLD_NOLOAD | RTLD_LAZY); if (handle !is null) .dlclose(handle); // drop reference count return handle; } } /////////////////////////////////////////////////////////////////////////////// // Elf program header iteration /////////////////////////////////////////////////////////////////////////////// /************ * Scan segments in Linux dl_phdr_info struct and store * the TLS and writeable data segments in *pdso. */ void scanSegments(in ref dl_phdr_info info, DSO* pdso) { foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) { switch (phdr.p_type) { case PT_LOAD: if (phdr.p_flags & PF_W) // writeable data segment { auto beg = cast(void*)(info.dlpi_addr + phdr.p_vaddr); pdso._gcRanges.insertBack(beg[0 .. phdr.p_memsz]); } version (Shared) if (phdr.p_flags & PF_X) // code segment { auto beg = cast(void*)(info.dlpi_addr + phdr.p_vaddr); pdso._codeSegments.insertBack(beg[0 .. phdr.p_memsz]); } break; case PT_TLS: // TLS segment assert(!pdso._tlsSize); // is unique per DSO pdso._tlsMod = info.dlpi_tls_modid; pdso._tlsSize = phdr.p_memsz; // align to multiple of size_t to avoid misaligned scanning // (size is subtracted from TCB address to get base of TLS) immutable mask = size_t.sizeof - 1; pdso._tlsSize = (pdso._tlsSize + mask) & ~mask; break; default: break; } } } /************************** * Input: * result where the output is to be written; dl_phdr_info is a Linux struct * Returns: * true if found, and *result is filled in * References: * http://linux.die.net/man/3/dl_iterate_phdr */ version (linux) bool findDSOInfoForAddr(in void* addr, dl_phdr_info* result=null) nothrow @nogc { static struct DG { const(void)* addr; dl_phdr_info* result; } extern(C) int callback(dl_phdr_info* info, size_t sz, void* arg) nothrow @nogc { auto p = cast(DG*)arg; if (findSegmentForAddr(*info, p.addr)) { if (p.result !is null) *p.result = *info; return 1; // break; } return 0; // continue iteration } auto dg = DG(addr, result); /* Linux function that walks through the list of an application's shared objects and * calls 'callback' once for each object, until either all shared objects * have been processed or 'callback' returns a nonzero value. */ return dl_iterate_phdr(&callback, &dg) != 0; } else version (FreeBSD) bool findDSOInfoForAddr(in void* addr, dl_phdr_info* result=null) nothrow @nogc { return !!_rtld_addr_phdr(addr, result); } /********************************* * Determine if 'addr' lies within shared object 'info'. * If so, return true and fill in 'result' with the corresponding ELF program header. */ bool findSegmentForAddr(in ref dl_phdr_info info, in void* addr, ElfW!"Phdr"* result=null) nothrow @nogc { if (addr < cast(void*)info.dlpi_addr) // less than base address of object means quick reject return false; foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) { auto beg = cast(void*)(info.dlpi_addr + phdr.p_vaddr); if (cast(size_t)(addr - beg) < phdr.p_memsz) { if (result !is null) *result = phdr; return true; } } return false; } version (linux) import core.sys.linux.errno : program_invocation_name; // should be in core.sys.freebsd.stdlib version (FreeBSD) extern(C) const(char)* getprogname() nothrow @nogc; @property const(char)* progname() nothrow @nogc { version (linux) return program_invocation_name; version (FreeBSD) return getprogname(); } nothrow const(char)[] dsoName(const char* dlpi_name) { // the main executable doesn't have a name in its dlpi_name field const char* p = dlpi_name[0] != 0 ? dlpi_name : progname; return p[0 .. strlen(p)]; } version (LDC) { extern(C) extern __gshared { pragma(LDC_extern_weak) void* _d_execBssBegAddr; pragma(LDC_extern_weak) void* _d_execBssEndAddr; } } else { extern(C) { void* rt_get_bss_start() @nogc nothrow; void* rt_get_end() @nogc nothrow; } } /// get the BSS section of the executable to check for copy relocations version (LDC) const(void)[] getCopyRelocSection() nothrow { // _d_execBss{Beg, End}Addr are emitted into the entry point module // along with main(). If the main executable is not a D program, we can // simply skip the copy-relocation check. The weak symbols will be undefined // then. // // The weak symbols are required to get around an issue with some linkers // not defining __bss_start/_end in the executable otherwise (see history // and DMD bugzilla for details). Note that DMD has since adopted a similar // strategy (see below), but unfortunately this doesn't work with // ld.bfd 2.26.0.20160501 on Linux and --gc-sections enabled. // // Background: If the main executable we have been loaded into is a D // application, some ModuleInfos might have been copy-relocated into its // .bss section (if it not position-independent, that is). This would break // the module collision check if not detected. But under normal // circumstances a ModuleInfo object is never zero-initialized, so we can // just exclude the .bss section to prevent false postives. if (!&_d_execBssBegAddr) return null; if (!&_d_execBssEndAddr) return null; immutable size = _d_execBssEndAddr - _d_execBssBegAddr; return _d_execBssBegAddr[0 .. size]; } else const(void)[] getCopyRelocSection() nothrow { auto bss_start = rt_get_bss_start(); auto bss_end = rt_get_end(); immutable bss_size = bss_end - bss_start; /** Check whether __bss_start/_end both lie within the executable DSO.same DSO. When a C host program dynamically loads druntime, i.e. it isn't linked against, __bss_start/_end might be defined in different DSOs, b/c the linker creates those symbols only when they are used. But as there are no copy relocations when dynamically loading a shared library, we can simply return a null bss range in that case. */ if (bss_size <= 0) return null; version (linux) enum ElfW!"Addr" exeBaseAddr = 0; else version (FreeBSD) enum ElfW!"Addr" exeBaseAddr = 0; dl_phdr_info info = void; findDSOInfoForAddr(bss_start, &info) || assert(0); if (info.dlpi_addr != exeBaseAddr) return null; findDSOInfoForAddr(bss_end - 1, &info) || assert(0); if (info.dlpi_addr != exeBaseAddr) return null; return bss_start[0 .. bss_size]; } /** * Check for module collisions. A module in a shared library collides * with an existing module if it's ModuleInfo is interposed (search * symbol interposition) by another DSO. Therefor two modules with the * same name do not collide if their DSOs are in separate symbol resolution * chains. */ void checkModuleCollisions(in ref dl_phdr_info info, in immutable(ModuleInfo)*[] modules, in void[] copyRelocSection) nothrow in { assert(modules.length); } body { immutable(ModuleInfo)* conflicting; foreach (m; modules) { auto addr = cast(const(void*))m; if (cast(size_t)(addr - copyRelocSection.ptr) < copyRelocSection.length) { // Module is in .bss of the exe because it was copy relocated } else if (!findSegmentForAddr(info, addr)) { // Module is in another DSO conflicting = m; break; } } if (conflicting !is null) { dl_phdr_info other=void; findDSOInfoForAddr(conflicting, &other) || assert(0); auto modname = conflicting.name; auto loading = dsoName(info.dlpi_name); auto existing = dsoName(other.dlpi_name); fprintf(stderr, "Fatal Error while loading '%.*s':\n\tThe module '%.*s' is already defined in '%.*s'.\n", cast(int)loading.length, loading.ptr, cast(int)modname.length, modname.ptr, cast(int)existing.length, existing.ptr); import core.stdc.stdlib : _Exit; _Exit(1); } } /************************** * Input: * addr an internal address of a DSO * Returns: * the dlopen handle for that DSO or null if addr is not within a loaded DSO */ version (Shared) void* handleForAddr(void* addr) { Dl_info info = void; if (dladdr(addr, &info) != 0) return handleForName(info.dli_fname); return null; } /////////////////////////////////////////////////////////////////////////////// // TLS module helper /////////////////////////////////////////////////////////////////////////////// /* * Returns: the TLS memory range for a given module and the calling * thread or null if that module has no TLS. * * Note: This will cause the TLS memory to be eagerly allocated. */ struct tls_index { size_t ti_module; size_t ti_offset; } version(LDC) { version(PPC) { extern(C) void* __tls_get_addr_opt(tls_index* ti); alias __tls_get_addr = __tls_get_addr_opt; } else version(PPC64) { extern(C) void* __tls_get_addr_opt(tls_index* ti); alias __tls_get_addr = __tls_get_addr_opt; } else extern(C) void* __tls_get_addr(tls_index* ti); } else extern(C) void* __tls_get_addr(tls_index* ti); /* The dynamic thread vector (DTV) pointers may point 0x8000 past the start of * each TLS block. This is at least true for PowerPC and Mips platforms. * See: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/powerpc/dl-tls.h;h=f7cf6f96ebfb505abfd2f02be0ad0e833107c0cd;hb=HEAD#l34 * https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/mips/dl-tls.h;h=93a6dc050cb144b9f68b96fb3199c60f5b1fcd18;hb=HEAD#l32 */ version(X86) enum TLS_DTV_OFFSET = 0x; else version(X86_64) enum TLS_DTV_OFFSET = 0x; else version(ARM) enum TLS_DTV_OFFSET = 0x; else version(AArch64) enum TLS_DTV_OFFSET = 0x; else version(SPARC) enum TLS_DTV_OFFSET = 0x; else version(SPARC64) enum TLS_DTV_OFFSET = 0x; else version(PPC) enum TLS_DTV_OFFSET = 0x8000; else version(PPC64) enum TLS_DTV_OFFSET = 0x8000; else version(MIPS) enum TLS_DTV_OFFSET = 0x8000; else version(MIPS64) enum TLS_DTV_OFFSET = 0x8000; else static assert( false, "Platform not supported." ); // We do not want to depend on __tls_get_addr for non-Shared builds to support // linking against a static C runtime. version (X86) version = X86_Any; version (X86_64) version = X86_Any; version (Shared) {} else version (linux) version (X86_Any) version = Static_Linux_X86_Any; void[] getTLSRange(size_t mod, size_t sz) { version (Static_Linux_X86_Any) { version (X86) static void* endOfBlock() { asm { naked; mov EAX, GS:[0]; ret; } } else version (X86_64) static void* endOfBlock() { asm { naked; mov RAX, FS:[0]; ret; } } // FIXME: It is unclear whether aligning the area down to the next // double-word is necessary and if so, on what systems, but at least // some implementations seem to do it. version (none) { immutable mask = (2 * size_t.sizeof) - 1; sz = (sz + mask) & ~mask; } return (endOfBlock() - sz)[0 .. sz]; } else { if (mod == 0) return null; // base offset auto ti = tls_index(mod, 0); return (__tls_get_addr(&ti)-TLS_DTV_OFFSET)[0 .. sz]; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/sections_android.d0000664000175000017500000001104012776214756022367 0ustar kaikai/** * Written in the D programming language. * This module provides bionic-specific support for sections. * * Copyright: Copyright Martin Nowak 2012-2013. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Martin Nowak * Source: $(DRUNTIMESRC src/rt/_sections_android.d) */ module rt.sections_android; version (CRuntime_Bionic): // debug = PRINTF; debug(PRINTF) import core.stdc.stdio; import core.stdc.stdlib : malloc, free; import rt.deh, rt.minfo; import core.sys.posix.pthread; import core.stdc.stdlib : calloc; import core.stdc.string : memcpy; struct SectionGroup { static int opApply(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } static int opApplyReverse(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } @property immutable(ModuleInfo*)[] modules() const { return _moduleGroup.modules; } @property ref inout(ModuleGroup) moduleGroup() inout { return _moduleGroup; } version(DigitalMars) @property immutable(FuncTable)[] ehTables() const { auto pbeg = cast(immutable(FuncTable)*)&__start_deh; auto pend = cast(immutable(FuncTable)*)&__stop_deh; return pbeg[0 .. pend - pbeg]; } @property inout(void[])[] gcRanges() inout { return _gcRanges[]; } private: ModuleGroup _moduleGroup; void[][1] _gcRanges; } void initSections() { pthread_key_create(&_tlsKey, null); auto mbeg = cast(immutable ModuleInfo**)&__start_minfo; auto mend = cast(immutable ModuleInfo**)&__stop_minfo; _sections.moduleGroup = ModuleGroup(mbeg[0 .. mend - mbeg]); auto pbeg = cast(void*)&_tls_end; auto pend = cast(void*)&__bss_end__; _sections._gcRanges[0] = pbeg[0 .. pend - pbeg]; } void finiSections() { pthread_key_delete(_tlsKey); } void[]* initTLSRanges() { return &getTLSBlock(); } void finiTLSRanges(void[]* rng) { .free(rng.ptr); .free(rng); } void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow { dg(rng.ptr, rng.ptr + rng.length); } /* NOTE: The Bionic C library does not allow storing thread-local data * in the normal .tbss/.tdata ELF sections. So instead we roll our * own by simply putting tls into the non-tls .data/.bss sections * and using the _tlsstart/_tlsend symbols as delimiters of the tls * data. * * This function is called by the code emitted by the compiler. It * is expected to translate an address in the TLS static data to * the corresponding address in the TLS dynamic per-thread data. */ version(X86) { // NB: the compiler mangles this function as '___tls_get_addr' // even though it is extern(D) extern(D) void* ___tls_get_addr( void* p ) { debug(PRINTF) printf(" ___tls_get_addr input - %p\n", p); immutable offset = cast(size_t)(p - cast(void*)&_tlsstart); auto tls = getTLSBlockAlloc(); assert(offset < tls.length); return tls.ptr + offset; } } else version(ARM) { extern(C) void* __tls_get_addr( void** p ) { debug(PRINTF) printf(" __tls_get_addr input - %p\n", *p); immutable offset = cast(size_t)(*p - cast(void*)&_tlsstart); auto tls = getTLSBlockAlloc(); assert(offset < tls.length); return tls.ptr + offset; } } else static assert( false, "Android architecture not supported." ); private: __gshared pthread_key_t _tlsKey; ref void[] getTLSBlock() { auto pary = cast(void[]*)pthread_getspecific(_tlsKey); if (pary is null) { pary = cast(void[]*).calloc(1, (void[]).sizeof); if (pthread_setspecific(_tlsKey, pary) != 0) { import core.stdc.stdio; perror("pthread_setspecific failed with"); assert(0); } } return *pary; } ref void[] getTLSBlockAlloc() { auto pary = &getTLSBlock(); if (!pary.length) { auto pbeg = cast(void*)&_tlsstart; auto pend = cast(void*)&_tlsend; auto p = .malloc(pend - pbeg); memcpy(p, pbeg, pend - pbeg); *pary = p[0 .. pend - pbeg]; } return *pary; } __gshared SectionGroup _sections; extern(C) { /* Symbols created by the compiler/linker and inserted into the * object file that 'bracket' sections. */ extern __gshared { void* __start_deh; void* __stop_deh; void* __start_minfo; void* __stop_minfo; size_t __bss_end__; void* _tlsstart; void* _tlsend; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/tracegc.d0000664000175000017500000004014412776214756020457 0ustar kaikai/** * Contains implementations of functions called when the * -profile=gc * switch is thrown. * * Copyright: Copyright Digital Mars 2015 - 2015. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright * Source: $(DRUNTIMESRC src/rt/_tracegc.d) */ module rt.tracegc; //version = tracegc; import rt.profilegc; version (tracegc) import core.stdc.stdio; version (none) { // this exercises each function struct S { ~this() { } } class C { } interface I { } void main() { { auto a = new C(); auto b = new int; auto c = new int[3]; auto d = new int[][](3,4); auto e = new float; auto f = new float[3]; auto g = new float[][](3,4); } printf("\n"); { int[] a; delete a; S[] as; delete as; C c; delete c; I i; delete i; C* pc = &c; delete *pc; I* pi = &i; delete *pi; int* pint; delete pint; S* ps; delete ps; } printf("\n"); { int[] a = [1, 2, 3]; string[int] aa = [1:"one", 2:"two", 3:"three"]; } printf("\n"); { int[] a, b, c; c = a ~ b; c = a ~ b ~ c; } printf("\n"); { dchar dc = 'a'; char[] ac; ac ~= dc; wchar[] aw; aw ~= dc; char[] ac2; ac2 ~= ac; int[] ai; ai ~= 3; } printf("\n"); { int[] ai; ai.length = 10; float[] af; af.length = 10; } printf("\n"); int v; { int foo() { return v; } static int delegate() dg; dg = &foo; // dynamic closure } } } extern (C) Object _d_newclass(const ClassInfo ci); extern (C) void[] _d_newarrayT(const TypeInfo ti, size_t length); extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length); extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims); extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims); extern (C) void* _d_newitemT(in TypeInfo _ti); extern (C) void* _d_newitemiT(in TypeInfo _ti); extern (C) Object _d_newclassTrace(string file, int line, string funcname, const ClassInfo ci) { version (tracegc) { printf("_d_newclassTrace class = %s file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ci.name, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ci.name, ci.initializer.length); return _d_newclass(ci); } extern (C) void[] _d_newarrayTTrace(string file, int line, string funcname, const TypeInfo ti, size_t length) { version (tracegc) { printf("_d_newarrayTTrace type = %s length = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)length, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), ti.tsize * length); return _d_newarrayT(ti, length); } extern (C) void[] _d_newarrayiTTrace(string file, int line, string funcname, const TypeInfo ti, size_t length) { version (tracegc) { printf("_d_newarrayiTTrace type = %s length = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)length, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), ti.tsize * length); return _d_newarrayiT(ti, length); } extern (C) void[] _d_newarraymTXTrace(string file, int line, string funcname, const TypeInfo ti, size_t[] dims) { version (tracegc) { printf("_d_newarraymTXTrace type = %s dims = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)dims.length, file.length, file.ptr, line, funcname.length, funcname.ptr ); } size_t n = 1; foreach (dim; dims) n *= dim; accumulate(file, line, funcname, ti.toString(), ti.tsize * n); return _d_newarraymTX(ti, dims); } extern (C) void[] _d_newarraymiTXTrace(string file, int line, string funcname, const TypeInfo ti, size_t[] dims) { version (tracegc) { printf("_d_newarraymiTXTrace type = %s dims = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)dims.length, file.length, file.ptr, line, funcname.length, funcname.ptr ); } size_t n = 1; foreach (dim; dims) n *= dim; accumulate(file, line, funcname, ti.toString(), ti.tsize * n); return _d_newarraymiTX(ti, dims); } extern (C) void* _d_newitemTTrace(string file, int line, string funcname, in TypeInfo ti) { version (tracegc) { printf("_d_newitemTTrace type = %s file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), ti.tsize); return _d_newitemT(ti); } extern (C) void* _d_newitemiTTrace(string file, int line, string funcname, in TypeInfo ti) { version (tracegc) { printf("_d_newitemiTTrace type = %s file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), ti.tsize); return _d_newitemiT(ti); } extern (C) void _d_callfinalizer(void* p); extern (C) void _d_callinterfacefinalizer(void *p); extern (C) void _d_delclass(Object* p); extern (C) void _d_delinterface(void** p); extern (C) void _d_delstruct(void** p, TypeInfo_Struct inf); extern (C) void _d_delarray_t(void[]* p, const TypeInfo_Struct ti); extern (C) void _d_delmemory(void* *p); extern (C) void _d_callfinalizerTrace(string file, int line, string funcname, void* p) { version (tracegc) { printf("_d_callfinalizerTrace %p file = '%.*s' line = %d function = '%.*s'\n", p, file.length, file.ptr, line, funcname.length, funcname.ptr ); } _d_callfinalizer(p); } extern (C) void _d_callinterfacefinalizerTrace(string file, int line, string funcname, void *p) { version (tracegc) { printf("_d_callinterfacefinalizerTrace %p file = '%.*s' line = %d function = '%.*s'\n", p, file.length, file.ptr, line, funcname.length, funcname.ptr ); } _d_callinterfacefinalizer(p); } extern (C) void _d_delclassTrace(string file, int line, string funcname, Object* p) { version (tracegc) { printf("_d_delclassTrace %p file = '%.*s' line = %d function = '%.*s'\n", *p, file.length, file.ptr, line, funcname.length, funcname.ptr ); } _d_delclass(p); } extern (C) void _d_delinterfaceTrace(string file, int line, string funcname, void** p) { version (tracegc) { printf("_d_delinterfaceTrace %p file = '%.*s' line = %d function = '%.*s'\n", *p, file.length, file.ptr, line, funcname.length, funcname.ptr ); } _d_delinterface(p); } extern (C) void _d_delstructTrace(string file, int line, string funcname, void** p, TypeInfo_Struct inf) { version (tracegc) { printf("_d_delstructTrace %p type = %s file = '%.*s' line = %d function = '%.*s'\n", *p, cast(char *)inf.toString().ptr, file.length, file.ptr, line, funcname.length, funcname.ptr ); } _d_delstruct(p, inf); } extern (C) void _d_delarray_tTrace(string file, int line, string funcname, void[]* p, const TypeInfo_Struct ti) { version (tracegc) { printf("_d_delarray_tTrace %p[%llu] type = %s file = '%.*s' line = %d function = '%.*s'\n", (*p).ptr, cast(ulong)(*p).length, ti ? cast(char *)ti.toString().ptr : cast(char*)"".ptr, file.length, file.ptr, line, funcname.length, funcname.ptr ); } _d_delarray_t(p, ti); } extern (C) void _d_delmemoryTrace(string file, int line, string funcname, void* *p) { version (tracegc) { printf("_d_delmemoryTrace %p file = '%.*s' line = %d function = '%.*s'\n", *p, file.length, file.ptr, line, funcname.length, funcname.ptr ); } _d_delmemory(p); } extern (C) void* _d_arrayliteralTX(const TypeInfo ti, size_t length); extern (C) void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] vals); extern (C) void* _d_arrayliteralTXTrace(string file, int line, string funcname, const TypeInfo ti, size_t length) { version (tracegc) { printf("_d_arrayliteralTXTrace type = %s length = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)length, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), ti.next.tsize * length); return _d_arrayliteralTX(ti, length); } extern (C) void* _d_assocarrayliteralTXTrace(string file, int line, string funcname, const TypeInfo_AssociativeArray ti, void[] keys, void[] vals) { version (tracegc) { printf("_d_assocarrayliteralTXTrace type = %s keys = %llu values = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)keys.length, cast(ulong)vals.length, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), (ti.key.tsize + ti.value.tsize) * keys.length); return _d_assocarrayliteralTX(ti, keys, vals); } extern (C) byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y); extern (C) void[] _d_arraycatnTX(const TypeInfo ti, byte[][] arrs); extern (C) byte[] _d_arraycatTTrace(string file, int line, string funcname, const TypeInfo ti, byte[] x, byte[] y) { version (tracegc) { printf("_d_arraycatT type = %s x = %llu y = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)x.length, cast(ulong)y.length, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), (x.length + y.length) * ti.next.tsize); return _d_arraycatT(ti, x, y); } extern (C) void[] _d_arraycatnTXTrace(string file, int line, string funcname, const TypeInfo ti, byte[][] arrs) { version (tracegc) { printf("_d_arraycatnTX type = %s arrs = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)arrs.length, file.length, file.ptr, line, funcname.length, funcname.ptr ); } size_t length; foreach (b; arrs) length += b.length; accumulate(file, line, funcname, ti.toString(), length * ti.next.tsize); return _d_arraycatnTX(ti, arrs); } extern (C) void[] _d_arrayappendT(const TypeInfo ti, ref byte[] x, byte[] y); extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, ref byte[] px, size_t n); extern (C) void[] _d_arrayappendcd(ref byte[] x, dchar c); extern (C) void[] _d_arrayappendwd(ref byte[] x, dchar c); extern (C) void[] _d_arrayappendTTrace(string file, int line, string funcname, const TypeInfo ti, ref byte[] x, byte[] y) { version (tracegc) { printf("_d_arrayappendT type = %s x = %llu y = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)x.length, cast(ulong)y.length, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), ti.next.tsize * y.length); return _d_arrayappendT(ti, x, y); } extern (C) byte[] _d_arrayappendcTXTrace(string file, int line, string funcname, const TypeInfo ti, ref byte[] px, size_t n) { version (tracegc) { printf("_d_arrayappendcTX type = %s x = %llu n = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)px.length, cast(ulong)n, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), ti.next.tsize * n); return _d_arrayappendcTX(ti, px, n); } extern (C) void[] _d_arrayappendcdTrace(string file, int line, string funcname, ref byte[] x, dchar c) { version (tracegc) { printf("_d_arrayappendcd x = %llu c = x%x file = '%.*s' line = %d function = '%.*s'\n", cast(ulong)x.length, c, file.length, file.ptr, line, funcname.length, funcname.ptr ); } size_t n; if (c <= 0x7F) n = 1; else if (c <= 0x7FF) n = 2; else if (c <= 0xFFFF) n = 3; else if (c <= 0x10FFFF) n = 4; else assert(0); accumulate(file, line, funcname, "char[]", n * char.sizeof); return _d_arrayappendcd(x, c); } extern (C) void[] _d_arrayappendwdTrace(string file, int line, string funcname, ref byte[] x, dchar c) { version (tracegc) { printf("_d_arrayappendwd x = %llu c = x%x file = '%.*s' line = %d function = '%.*s'\n", cast(ulong)x.length, c, file.length, file.ptr, line, funcname.length, funcname.ptr ); } size_t n = 1 + (c > 0xFFFF); accumulate(file, line, funcname, "wchar[]", n * wchar.sizeof); return _d_arrayappendwd(x, c); } extern (C) void[] _d_arraysetlengthT(const TypeInfo ti, size_t newlength, void[]* p); extern (C) void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p); extern (C) void[] _d_arraysetlengthTTrace(string file, int line, string funcname, const TypeInfo ti, size_t newlength, void[]* p) { version (tracegc) { printf("_d_arraysetlengthT type = %s length = %llu newlength = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)(*p).length, cast(ulong)newlength, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), ti.next.tsize * newlength); return _d_arraysetlengthT(ti, newlength, p); } extern (C) void[] _d_arraysetlengthiTTrace(string file, int line, string funcname, const TypeInfo ti, size_t newlength, void[]* p) { version (tracegc) { printf("_d_arraysetlengthiT type = %s length = %llu newlength = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(char *)ti.toString().ptr, cast(ulong)(*p).length, cast(ulong)newlength, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, ti.toString(), ti.next.tsize * newlength); return _d_arraysetlengthiT(ti, newlength, p); } extern (C) void* _d_allocmemory(size_t sz); extern (C) void* _d_allocmemoryTrace(string file, int line, string funcname, size_t sz) { version (tracegc) { printf("_d_allocmemory sz = %llu file = '%.*s' line = %d function = '%.*s'\n", cast(ulong)sz, file.length, file.ptr, line, funcname.length, funcname.ptr ); } accumulate(file, line, funcname, "closure", sz); return _d_allocmemory(sz); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/sections_win64.d0000664000175000017500000001243212776214756021724 0ustar kaikai/** * Written in the D programming language. * This module provides Win32-specific support for sections. * * Copyright: Copyright Digital Mars 2008 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly, Martin Nowak * Source: $(DRUNTIMESRC src/rt/_sections_win64.d) */ module rt.sections_win64; version (LDC) {} else version(CRuntime_Microsoft): // debug = PRINTF; debug(PRINTF) import core.stdc.stdio; import core.stdc.stdlib : malloc, free; import rt.deh, rt.minfo; struct SectionGroup { static int opApply(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } static int opApplyReverse(scope int delegate(ref SectionGroup) dg) { return dg(_sections); } @property immutable(ModuleInfo*)[] modules() const { return _moduleGroup.modules; } @property ref inout(ModuleGroup) moduleGroup() inout { return _moduleGroup; } version(Win64) @property immutable(FuncTable)[] ehTables() const { auto pbeg = cast(immutable(FuncTable)*)&_deh_beg; auto pend = cast(immutable(FuncTable)*)&_deh_end; return pbeg[0 .. pend - pbeg]; } @property inout(void[])[] gcRanges() inout { return _gcRanges[]; } private: ModuleGroup _moduleGroup; void[][1] _gcRanges; } void initSections() { _sections._moduleGroup = ModuleGroup(getModuleInfos()); // the ".data" image section includes both object file sections ".data" and ".bss" _sections._gcRanges[0] = findImageSection(".data"); debug(PRINTF) printf("found .data section: [%p,+%llx]\n", _sections._gcRanges[0].ptr, cast(ulong)_sections._gcRanges[0].length); } void finiSections() { .free(cast(void*)_sections.modules.ptr); } void[] initTLSRanges() { auto pbeg = cast(void*)&_tls_start; auto pend = cast(void*)&_tls_end; return pbeg[0 .. pend - pbeg]; } void finiTLSRanges(void[] rng) { } void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow { dg(rng.ptr, rng.ptr + rng.length); } private: __gshared SectionGroup _sections; extern(C) { extern __gshared void* _minfo_beg; extern __gshared void* _minfo_end; } immutable(ModuleInfo*)[] getModuleInfos() out (result) { foreach(m; result) assert(m !is null); } body { auto m = (cast(immutable(ModuleInfo*)*)&_minfo_beg)[1 .. &_minfo_end - &_minfo_beg]; /* Because of alignment inserted by the linker, various null pointers * are there. We need to filter them out. */ auto p = m.ptr; auto pend = m.ptr + m.length; // count non-null pointers size_t cnt; for (; p < pend; ++p) { if (*p !is null) ++cnt; } auto result = (cast(immutable(ModuleInfo)**).malloc(cnt * size_t.sizeof))[0 .. cnt]; p = m.ptr; cnt = 0; for (; p < pend; ++p) if (*p !is null) result[cnt++] = *p; return cast(immutable)result; } extern(C) { /* Symbols created by the compiler/linker and inserted into the * object file that 'bracket' sections. */ extern __gshared { void* __ImageBase; void* _deh_beg; void* _deh_end; } extern { int _tls_start; int _tls_end; } } ///////////////////////////////////////////////////////////////////// enum IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ struct IMAGE_DOS_HEADER // DOS .EXE header { ushort e_magic; // Magic number ushort[29] e_res2; // Reserved ushorts int e_lfanew; // File address of new exe header } struct IMAGE_FILE_HEADER { ushort Machine; ushort NumberOfSections; uint TimeDateStamp; uint PointerToSymbolTable; uint NumberOfSymbols; ushort SizeOfOptionalHeader; ushort Characteristics; } struct IMAGE_NT_HEADERS { uint Signature; IMAGE_FILE_HEADER FileHeader; // optional header follows } struct IMAGE_SECTION_HEADER { char[8] Name; union { uint PhysicalAddress; uint VirtualSize; } uint VirtualAddress; uint SizeOfRawData; uint PointerToRawData; uint PointerToRelocations; uint PointerToLinenumbers; ushort NumberOfRelocations; ushort NumberOfLinenumbers; uint Characteristics; } bool compareSectionName(ref IMAGE_SECTION_HEADER section, string name) nothrow { if (name[] != section.Name[0 .. name.length]) return false; return name.length == 8 || section.Name[name.length] == 0; } void[] findImageSection(string name) nothrow { if (name.length > 8) // section name from string table not supported return null; IMAGE_DOS_HEADER* doshdr = cast(IMAGE_DOS_HEADER*) &__ImageBase; if (doshdr.e_magic != IMAGE_DOS_SIGNATURE) return null; auto nthdr = cast(IMAGE_NT_HEADERS*)(cast(void*)doshdr + doshdr.e_lfanew); auto sections = cast(IMAGE_SECTION_HEADER*)(cast(void*)nthdr + IMAGE_NT_HEADERS.sizeof + nthdr.FileHeader.SizeOfOptionalHeader); for(ushort i = 0; i < nthdr.FileHeader.NumberOfSections; i++) if (compareSectionName (sections[i], name)) return (cast(void*)&__ImageBase + sections[i].VirtualAddress)[0 .. sections[i].VirtualSize]; return null; } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/arrayreal.d0000664000175000017500000001340012776214756021024 0ustar kaikai/** * Contains SSE2 and MMX versions of certain operations for real. * * Copyright: Copyright Digital Mars 2008 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, based on code originally written by Burton Radons */ /* Copyright Digital Mars 2008 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.arrayreal; // debug=PRINTF import core.cpuid; import rt.util.array; version (unittest) { private import core.stdc.stdio : printf; /* This is so unit tests will test every CPU variant */ int cpuid; const int CPUID_MAX = 1; nothrow: @property bool mmx() { return cpuid == 1 && core.cpuid.mmx; } @property bool sse() { return cpuid == 2 && core.cpuid.sse; } @property bool sse2() { return cpuid == 3 && core.cpuid.sse2; } @property bool amd3dnow() { return cpuid == 4 && core.cpuid.amd3dnow; } } else { alias core.cpuid.mmx mmx; alias core.cpuid.sse sse; alias core.cpuid.sse2 sse2; alias core.cpuid.amd3dnow amd3dnow; } //version = log; alias real T; extern (C) @trusted nothrow: /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + c[] */ T[] _arraySliceSliceAddSliceAssign_r(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); foreach (i; 0..a.length) a[i] = b[i] + c[i]; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceAddSliceAssign_r unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] + b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + b[i])) { printf("[%d]: %Lg != %Lg + %Lg\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - c[] */ T[] _arraySliceSliceMinSliceAssign_r(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); foreach (i; 0..a.length) a[i] = b[i] - c[i]; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMinSliceAssign_r unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] - b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - b[i])) { printf("[%d]: %Lg != %Lg - %Lg\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= b[] * value */ T[] _arraySliceExpMulSliceMinass_r(T[] a, T value, T[] b) { return _arraySliceExpMulSliceAddass_r(a, -value, b); } /*********************** * Computes: * a[] += b[] * value */ T[] _arraySliceExpMulSliceAddass_r(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; // Handle remainder while (aptr < aend) *aptr++ += *bptr++ * value; return a; } unittest { debug(PRINTF) printf("_arraySliceExpMulSliceAddass_r unittest\n"); cpuid = 1; { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 1; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } b[] = c[]; c[] += a[] * 6; for (int i = 0; i < dim; i++) { //printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]); if (c[i] != cast(T)(b[i] + a[i] * 6)) { printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]); assert(0); } } } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/trace.d0000664000175000017500000005446312776214756020156 0ustar kaikai/** * Contains support code for code profiling. * * Copyright: Copyright Digital Mars 1995 - 2015. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC src/rt/_trace.d) */ module rt.trace; private { import core.demangle; import core.stdc.ctype; import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; import core.internal.string; version (CRuntime_Microsoft) alias core.stdc.stdlib._strtoui64 strtoull; } extern (C): alias long timer_t; ///////////////////////////////////// // struct SymPair { SymPair* next; Symbol* sym; // function that is called ulong count; // number of times sym is called } ///////////////////////////////////// // A Symbol for each function name. struct Symbol { Symbol* Sl, Sr; // left, right children SymPair* Sfanin; // list of calling functions SymPair* Sfanout; // list of called functions timer_t totaltime; // aggregate time timer_t functime; // time excluding subfunction calls ubyte Sflags; // SFxxxx uint recursion; // call recursion level const(char)[] Sident; // name of symbol } enum ubyte SFvisited = 1; // visited ////////////////////////////////// // Build a linked list of these. struct Stack { Stack* prev; Symbol* sym; timer_t starttime; // time when function was entered timer_t ohd; // overhead of all the bookkeeping code timer_t subtime; // time used by all subfunctions } Symbol* root; // root of symbol table bool trace_inited; Stack* stack_freelist; Stack* trace_tos; // top of stack __gshared { Symbol* groot; // merged symbol table int gtrace_inited; // !=0 if initialized timer_t trace_ohd; string trace_logfilename = "trace.log"; string trace_deffilename = "trace.def"; } //////////////////////////////////////// // Set file name for output. // A file name of "" means write results to stdout. // Returns: // 0 success // !=0 failure void trace_setlogfilename(string name) { trace_logfilename = name; } //////////////////////////////////////// // Set file name for output. // A file name of "" means write results to stdout. // Returns: // 0 success // !=0 failure void trace_setdeffilename(string name) { trace_deffilename = name; } //////////////////////////////////////// // Output optimal function link order. private void trace_order(FILE* fpdef, Symbol *s) { while (s) { trace_place(fpdef, s, 0); if (s.Sl) trace_order(fpdef, s.Sl); s = s.Sr; } } ////////////////////////////////////////////// // private Stack* stack_push() { Stack *s; if (stack_freelist) { s = stack_freelist; stack_freelist = s.prev; } else { s = cast(Stack *)trace_malloc(Stack.sizeof); } s.prev = trace_tos; trace_tos = s; return s; } ////////////////////////////////////////////// // private void stack_free(Stack *s) { s.prev = stack_freelist; stack_freelist = s; } ////////////////////////////////////// // Qsort() comparison routine for array of pointers to SymPair's. private int sympair_cmp(in void* e1, in void* e2) { auto count1 = (*cast(SymPair**)e1).count; auto count2 = (*cast(SymPair**)e2).count; if (count1 < count2) return -1; else if (count1 > count2) return 1; return 0; } ////////////////////////////////////// // Place symbol s, and then place any fan ins or fan outs with // counts greater than count. private void trace_place(FILE* fpdef, Symbol* s, ulong count) { if (!(s.Sflags & SFvisited)) { //printf("\t%.*s\t%llu\n", s.Sident.length, s.Sident.ptr, count); fprintf(fpdef,"\t%.*s\n", s.Sident.length, s.Sident.ptr); s.Sflags |= SFvisited; // Compute number of items in array size_t num = 0; for (auto sp = s.Sfanin; sp; sp = sp.next) num++; for (auto sp = s.Sfanout; sp; sp = sp.next) num++; if (!num) return; // Allocate and fill array auto base = cast(SymPair**)trace_malloc(SymPair.sizeof * num); size_t u = 0; for (auto sp = s.Sfanin; sp; sp = sp.next) base[u++] = sp; for (auto sp = s.Sfanout; sp; sp = sp.next) base[u++] = sp; assert(u == num); // Sort array qsort(base, num, (SymPair *).sizeof, &sympair_cmp); //for (u = 0; u < num; u++) //printf("\t\t%.*s\t%llu\n", base[u].sym.Sident.length, base[u].sym.Sident.ptr, base[u].count); // Place symbols for (u = 0; u < num; u++) { if (base[u].count >= count) { auto u2 = (u + 1 < num) ? u + 1 : u; auto c2 = base[u2].count; if (c2 < count) c2 = count; trace_place(fpdef, base[u].sym,c2); } else break; } // Clean up trace_free(base); } } /////////////////////////////////// // Report results. // Also compute and return number of symbols. private size_t trace_report(FILE* fplog, Symbol* s) { //printf("trace_report()\n"); size_t nsymbols; while (s) { ++nsymbols; if (s.Sl) nsymbols += trace_report(fplog, s.Sl); fprintf(fplog,"------------------\n"); ulong count = 0; for (auto sp = s.Sfanin; sp; sp = sp.next) { fprintf(fplog,"\t%5llu\t%.*s\n", sp.count, sp.sym.Sident.length, sp.sym.Sident.ptr); count += sp.count; } fprintf(fplog,"%.*s\t%llu\t%lld\t%lld\n", s.Sident.length, s.Sident.ptr, count, s.totaltime, s.functime); for (auto sp = s.Sfanout; sp; sp = sp.next) { fprintf(fplog,"\t%5llu\t%.*s\n", sp.count, sp.sym.Sident.length, sp.sym.Sident.ptr); } s = s.Sr; } return nsymbols; } //////////////////////////////////// // Allocate and fill array of symbols. private void trace_array(Symbol*[] psymbols, Symbol *s, ref uint u) { while (s) { psymbols[u++] = s; trace_array(psymbols, s.Sl, u); s = s.Sr; } } ////////////////////////////////////// // Qsort() comparison routine for array of pointers to Symbol's. private int symbol_cmp(in void* e1, in void* e2) { auto ps1 = cast(Symbol **)e1; auto ps2 = cast(Symbol **)e2; auto diff = (*ps2).functime - (*ps1).functime; return (diff == 0) ? 0 : ((diff > 0) ? 1 : -1); } /////////////////////////////////// // Report function timings private void trace_times(FILE* fplog, Symbol*[] psymbols) { // Sort array qsort(psymbols.ptr, psymbols.length, (Symbol *).sizeof, &symbol_cmp); // Print array timer_t freq; QueryPerformanceFrequency(&freq); fprintf(fplog,"\n======== Timer Is %lld Ticks/Sec, Times are in Microsecs ========\n\n",freq); fprintf(fplog," Num Tree Func Per\n"); fprintf(fplog," Calls Time Time Call\n\n"); foreach (s; psymbols) { timer_t tl,tr; timer_t fl,fr; timer_t pl,pr; timer_t percall; char[8192] buf = void; SymPair* sp; ulong calls; char[] id; calls = 0; id = demangle(s.Sident, buf); for (sp = s.Sfanin; sp; sp = sp.next) calls += sp.count; if (calls == 0) calls = 1; tl = (s.totaltime * 1000000) / freq; fl = (s.functime * 1000000) / freq; percall = s.functime / calls; pl = (s.functime * 1000000) / calls / freq; fprintf(fplog,"%7llu%12lld%12lld%12lld %.*s\n", calls, tl, fl, pl, id.length, id.ptr); } } /////////////////////////////////// // Initialize. private void trace_init() { synchronized // protects gtrace_inited { if (!gtrace_inited) { gtrace_inited = 1; { // See if we can determine the overhead. timer_t starttime; timer_t endtime; auto st = trace_tos; trace_tos = null; QueryPerformanceCounter(&starttime); uint u; for (u = 0; u < 100; u++) { _c_trace_pro(0,null); _c_trace_epi(); } QueryPerformanceCounter(&endtime); trace_ohd = (endtime - starttime) / u; //printf("trace_ohd = %lld\n",trace_ohd); if (trace_ohd > 0) trace_ohd--; // round down trace_tos = st; } } } } ///////////////////////////////// // Terminate. static ~this() { // Free remainder of the thread local stack while (trace_tos) { auto n = trace_tos.prev; stack_free(trace_tos); trace_tos = n; } // And free the thread local stack's memory while (stack_freelist) { auto n = stack_freelist.prev; stack_free(stack_freelist); stack_freelist = n; } synchronized // protects groot { // Merge thread local root into global groot if (!groot) { groot = root; // that was easy root = null; } else { void mergeSymbol(Symbol** proot, const(Symbol)* s) { while (s) { auto gs = trace_addsym(proot, s.Sident); gs.totaltime += s.totaltime; gs.functime += s.functime; static void mergeFan(Symbol** proot, SymPair** pgf, const(SymPair)* sf) { for (; sf; sf = sf.next) { auto sym = trace_addsym(proot, sf.sym.Sident); for (auto gf = *pgf; 1; gf = gf.next) { if (!gf) { auto sp = cast(SymPair *)trace_malloc(SymPair.sizeof); sp.next = *pgf; *pgf = sp; sp.sym = sym; sp.count = sf.count; break; } if (gf.sym == sym) { gf.count += sf.count; break; } } } } mergeFan(proot, &gs.Sfanin, s.Sfanin); mergeFan(proot, &gs.Sfanout, s.Sfanout); mergeSymbol(proot, s.Sl); s = s.Sr; } } mergeSymbol(&groot, root); } } // Free the memory for the thread local symbol table (root) static void freeSymbol(Symbol* s) { while (s) { freeSymbol(s.Sl); auto next = s.Sr; static void freeSymPair(SymPair* sp) { while (sp) { auto spnext = sp.next; trace_free(sp); sp = spnext; } } freeSymPair(s.Sfanin); freeSymPair(s.Sfanout); trace_free(s); s = next; } } freeSymbol(root); root = null; } shared static ~this() { //printf("shared static ~this() groot = %p\n", groot); if (gtrace_inited == 1) { gtrace_inited = 2; // Merge in data from any existing file trace_merge(&groot); // Report results FILE* fplog = trace_logfilename.length == 0 ? stdout : fopen((trace_logfilename ~ '\0').ptr, "w"); if (fplog) { auto nsymbols = trace_report(fplog, groot); auto p = cast(Symbol **)trace_malloc((Symbol *).sizeof * nsymbols); auto psymbols = p[0 .. nsymbols]; uint u; trace_array(psymbols, groot, u); trace_times(fplog, psymbols); fclose(fplog); trace_free(psymbols.ptr); psymbols = null; } else fprintf(stderr, "cannot write '%s'", trace_logfilename.ptr); // Output function link order FILE* fpdef = trace_deffilename.length == 0 ? stdout : fopen((trace_deffilename ~ '\0').ptr, "w"); if (fpdef) { fprintf(fpdef,"\nFUNCTIONS\n"); trace_order(fpdef, groot); fclose(fpdef); } else fprintf(stderr, "cannot write '%s'", trace_deffilename.ptr); } } ///////////////////////////////// // Our storage allocator. private void *trace_malloc(size_t nbytes) { auto p = malloc(nbytes); if (!p) exit(EXIT_FAILURE); return p; } private void trace_free(void *p) { free(p); } ////////////////////////////////////////////// // private Symbol* trace_addsym(Symbol** proot, const(char)[] id) { //printf("trace_addsym('%s',%d)\n",p,len); auto parent = proot; auto rover = *parent; while (rover !is null) // while we haven't run out of tree { auto cmp = dstrcmp(id, rover.Sident); if (cmp == 0) { return rover; } parent = (cmp < 0) ? /* if we go down left side */ &(rover.Sl) : /* then get left child */ &(rover.Sr); /* else get right child */ rover = *parent; /* get child */ } /* not in table, so insert into table */ auto s = cast(Symbol *)trace_malloc(Symbol.sizeof); memset(s,0,Symbol.sizeof); s.Sident = id; *parent = s; // link new symbol into tree return s; } /*********************************** * Add symbol s with count to SymPair list. */ private void trace_sympair_add(SymPair** psp, Symbol* s, ulong count) { SymPair* sp; for (; 1; psp = &sp.next) { sp = *psp; if (!sp) { sp = cast(SymPair *)trace_malloc(SymPair.sizeof); sp.sym = s; sp.count = 0; sp.next = null; *psp = sp; break; } else if (sp.sym == s) { break; } } sp.count += count; } ////////////////////////////////////////////// // This one is called by DMD private void trace_pro(char[] id) { //printf("trace_pro(ptr = %p, length = %lld)\n", id.ptr, id.length); //printf("trace_pro(id = '%.*s')\n", id.length, id.ptr); if (!trace_inited) { trace_inited = true; trace_init(); // initialize package } timer_t starttime; QueryPerformanceCounter(&starttime); if (id.length == 0) return; auto tos = stack_push(); auto s = trace_addsym(&root, id); tos.sym = s; if (tos.prev) { // Accumulate Sfanout and Sfanin auto prev = tos.prev.sym; trace_sympair_add(&prev.Sfanout,s,1); trace_sympair_add(&s.Sfanin,prev,1); } timer_t t; QueryPerformanceCounter(&t); tos.starttime = starttime; tos.ohd = trace_ohd + t - starttime; tos.subtime = 0; ++s.recursion; //printf("tos.ohd=%lld, trace_ohd=%lld + t=%lld - starttime=%lld\n", // tos.ohd,trace_ohd,t,starttime); } // Called by some old versions of DMD void _c_trace_pro(size_t idlen, char* idptr) { char[] id = idptr[0 .. idlen]; trace_pro(id); } ///////////////////////////////////////// // Called by DMD generated code void _c_trace_epi() { //printf("_c_trace_epi()\n"); auto tos = trace_tos; if (tos) { timer_t endtime; QueryPerformanceCounter(&endtime); auto starttime = tos.starttime; auto totaltime = endtime - starttime - tos.ohd; if (totaltime < 0) { //printf("endtime=%lld - starttime=%lld - tos.ohd=%lld < 0\n", // endtime,starttime,tos.ohd); totaltime = 0; // round off error, just make it 0 } // totaltime is time spent in this function + all time spent in // subfunctions - bookkeeping overhead. --tos.sym.recursion; if(tos.sym.recursion == 0) tos.sym.totaltime += totaltime; //if (totaltime < tos.subtime) //printf("totaltime=%lld < tos.subtime=%lld\n",totaltime,tos.subtime); tos.sym.functime += totaltime - tos.subtime; auto ohd = tos.ohd; auto n = tos.prev; stack_free(tos); trace_tos = n; if (n) { timer_t t; QueryPerformanceCounter(&t); n.ohd += ohd + t - endtime; n.subtime += totaltime; //printf("n.ohd = %lld\n",n.ohd); } } } ////////////////////////// FILE INTERFACE ///////////////////////// ///////////////////////////////////// // Read line from file fp. // Returns: // trace_malloc'd line buffer // null if end of file private char* trace_readline(FILE* fp) { int dim; int i; char *buf; //printf("trace_readline(%p)\n", fp); while (1) { if (i == dim) { dim += 80; auto p = cast(char *)trace_malloc(dim); memcpy(p,buf,i); trace_free(buf); buf = p; } int c = fgetc(fp); switch (c) { case EOF: if (i == 0) { trace_free(buf); return null; } goto L1; case '\n': goto L1; default: break; } buf[i] = cast(char)c; i++; } L1: buf[i] = 0; //printf("line '%s'\n",buf); return buf; } ////////////////////////////////////// // Skip space private char *skipspace(char *p) { while (isspace(*p)) p++; return p; } //////////////////////////////////////////////////////// // Merge in profiling data from existing file. private void trace_merge(Symbol** proot) { FILE *fp; if (trace_logfilename.length && (fp = fopen(trace_logfilename.ptr,"r")) !is null) { char* buf = null; SymPair* sfanin = null; auto psp = &sfanin; char *p; ulong count; Symbol *s; while (1) { trace_free(buf); buf = trace_readline(fp); if (!buf) break; switch (*buf) { case '=': // ignore rest of file trace_free(buf); goto L1; case ' ': case '\t': // fan in or fan out line count = strtoul(buf,&p,10); if (p == buf) // if invalid conversion continue; p = skipspace(p); if (!*p) continue; s = trace_addsym(proot, p[0 .. strlen(p)]); trace_sympair_add(psp,s,count); break; default: if (!isalpha(*buf)) { if (!sfanin) psp = &sfanin; continue; // regard unrecognized line as separator } goto case; case '?': case '_': case '$': case '@': p = buf; while (isgraph(*p)) p++; *p = 0; //printf("trace_addsym('%s')\n",buf); s = trace_addsym(proot, buf[0 .. strlen(buf)]); if (s.Sfanin) { SymPair *sp; for (; sfanin; sfanin = sp) { trace_sympair_add(&s.Sfanin,sfanin.sym,sfanin.count); sp = sfanin.next; trace_free(sfanin); } } else { s.Sfanin = sfanin; } sfanin = null; psp = &s.Sfanout; { p++; count = strtoul(p,&p,10); timer_t t = cast(long)strtoull(p,&p,10); s.totaltime += t; t = cast(long)strtoull(p,&p,10); s.functime += t; } break; } } L1: fclose(fp); } } ////////////////////////// COMPILER INTERFACE ///////////////////// version (Windows) { extern (Windows) { export int QueryPerformanceCounter(timer_t *); export int QueryPerformanceFrequency(timer_t *); } } else version (D_InlineAsm_X86) { extern (D) { void QueryPerformanceCounter(timer_t* ctr) { asm { naked ; mov ECX,EAX ; rdtsc ; mov [ECX],EAX ; mov 4[ECX],EDX ; ret ; } } void QueryPerformanceFrequency(timer_t* freq) { *freq = 3579545; } } } else version (D_InlineAsm_X86_64) { extern (D) { void QueryPerformanceCounter(timer_t* ctr) { asm { naked ; rdtsc ; mov [RDI],EAX ; mov 4[RDI],EDX ; ret ; } } void QueryPerformanceFrequency(timer_t* freq) { *freq = 3579545; } } } else { static assert(0); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/invariant.d0000664000175000017500000000146012776214756021040 0ustar kaikai/** * Implementation of invariant support routines. * * Copyright: Copyright Digital Mars 2007 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2007 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ /** * */ void _d_invariant(Object o) { ClassInfo c; //printf("__d_invariant(%p)\n", o); // BUG: needs to be filename/line of caller, not library routine assert(o !is null); // just do null check, not invariant check c = typeid(o); do { if (c.classInvariant) { (*c.classInvariant)(o); } c = c.base; } while (c); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/arraybyte.d0000664000175000017500000022026612776214756021056 0ustar kaikai/** * Contains SSE2 and MMX versions of certain operations for char, byte, and * ubyte ('a', 'g' and 'h' suffixes). * * Copyright: Copyright Digital Mars 2008 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright, based on code originally written by Burton Radons, * Brian Schott (64-bit operations) */ /* Copyright Digital Mars 2008 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.arraybyte; import core.cpuid; import rt.util.array; // debug=PRINTF version (unittest) { private import core.stdc.stdio : printf; /* This is so unit tests will test every CPU variant */ int cpuid; const int CPUID_MAX = 4; nothrow: @property bool mmx() { return cpuid == 1 && core.cpuid.mmx; } @property bool sse() { return cpuid == 2 && core.cpuid.sse; } @property bool sse2() { return cpuid == 3 && core.cpuid.sse2; } @property bool amd3dnow() { return cpuid == 4 && core.cpuid.amd3dnow; } } else { alias mmx = core.cpuid.mmx; alias sse = core.cpuid.sse; alias sse2 = core.cpuid.sse2; alias amd3dnow = core.cpuid.amd3dnow; } //version = log; alias T = byte; extern (C) @trusted nothrow: /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + value */ T[] _arraySliceExpAddSliceAssign_a(T[] a, T value, T[] b) { return _arraySliceExpAddSliceAssign_g(a, value, b); } T[] _arraySliceExpAddSliceAssign_h(T[] a, T value, T[] b) { return _arraySliceExpAddSliceAssign_g(a, value, b); } T[] _arraySliceExpAddSliceAssign_g(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceExpAddSliceAssign_g()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 1088% faster if (sse2 && a.length >= 64) { auto n = aptr + (a.length & ~63); uint l = cast(ubyte)value * 0x01010101; if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startaddsse2u: add ESI, 64; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; movdqu XMM2, [EAX+32]; movdqu XMM3, [EAX+48]; add EAX, 64; paddb XMM0, XMM4; paddb XMM1, XMM4; paddb XMM2, XMM4; paddb XMM3, XMM4; movdqu [ESI -64], XMM0; movdqu [ESI+16-64], XMM1; movdqu [ESI+32-64], XMM2; movdqu [ESI+48-64], XMM3; cmp ESI, EDI; jb startaddsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startaddsse2a: add ESI, 64; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; movdqa XMM2, [EAX+32]; movdqa XMM3, [EAX+48]; add EAX, 64; paddb XMM0, XMM4; paddb XMM1, XMM4; paddb XMM2, XMM4; paddb XMM3, XMM4; movdqa [ESI -64], XMM0; movdqa [ESI+16-64], XMM1; movdqa [ESI+32-64], XMM2; movdqa [ESI+48-64], XMM3; cmp ESI, EDI; jb startaddsse2a; mov aptr, ESI; mov bptr, EAX; } } } else // MMX version is 1000% faster if (mmx && a.length >= 32) { auto n = aptr + (a.length & ~31); uint l = cast(ubyte)value * 0x0101; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd MM4, l; pshufw MM4, MM4, 0; align 4; startaddmmx: add ESI, 32; movq MM0, [EAX]; movq MM1, [EAX+8]; movq MM2, [EAX+16]; movq MM3, [EAX+24]; add EAX, 32; paddb MM0, MM4; paddb MM1, MM4; paddb MM2, MM4; paddb MM3, MM4; movq [ESI -32], MM0; movq [ESI+8 -32], MM1; movq [ESI+16-32], MM2; movq [ESI+24-32], MM3; cmp ESI, EDI; jb startaddmmx; emms; mov aptr, ESI; mov bptr, EAX; } } /* trying to be fair and treat normal 32-bit cpu the same way as we do * the SIMD units, with unrolled asm. There's not enough registers, * really. */ else if (a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov CL, value; align 4; startadd386: add ESI, 4; mov DX, [EAX]; mov BX, [EAX+2]; add EAX, 4; add BL, CL; add BH, CL; add DL, CL; add DH, CL; mov [ESI -4], DX; mov [ESI+2 -4], BX; cmp ESI, EDI; jb startadd386; mov aptr, ESI; mov bptr, EAX; } } } version (D_InlineAsm_X86_64) { ulong v = (cast(ulong) value) * 0x0101010101010101; if (a.length >= 128) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~127); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; movq XMM15, v; shufpd XMM15, XMM15, 0; start64: movdqu XMM0, [RBX]; movdqu XMM1, [RBX + 16]; movdqu XMM2, [RBX + 32]; movdqu XMM3, [RBX + 48]; movdqu XMM4, [RBX + 64]; movdqu XMM5, [RBX + 80]; movdqu XMM6, [RBX + 96]; movdqu XMM7, [RBX + 112]; paddb XMM0, XMM15; paddb XMM1, XMM15; paddb XMM2, XMM15; paddb XMM3, XMM15; paddb XMM4, XMM15; paddb XMM5, XMM15; paddb XMM6, XMM15; paddb XMM7, XMM15; movdqu [RAX], XMM0; movdqu [RAX + 16], XMM1; movdqu [RAX + 32], XMM2; movdqu [RAX + 48], XMM3; movdqu [RAX + 64], XMM4; movdqu [RAX + 80], XMM5; movdqu [RAX + 96], XMM6; movdqu [RAX + 112], XMM7; add RAX, 128; add RBX, 128; cmp RAX, RDI; jb start64; mov aptr, RAX; mov bptr, RBX; } } if ((aend - aptr) >= 16) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~15); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; movq XMM15, v; shufpd XMM15, XMM15, 0; start16: movdqu XMM0, [RBX]; paddb XMM0, XMM15; movdqu [RAX], XMM0; add RAX, 16; add RBX, 16; cmp RAX, RDI; jb start16; mov aptr, RAX; mov bptr, RBX; } } } while (aptr < aend) *aptr++ = cast(T)(*bptr++ + value); return a; } unittest { debug(PRINTF) printf("_arraySliceExpAddSliceAssign_g unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] + 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + 6)) { printf("[%d]: %d != %d + 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] + c[] */ T[] _arraySliceSliceAddSliceAssign_a(T[] a, T[] c, T[] b) { return _arraySliceSliceAddSliceAssign_g(a, c, b); } T[] _arraySliceSliceAddSliceAssign_h(T[] a, T[] c, T[] b) { return _arraySliceSliceAddSliceAssign_g(a, c, b); } T[] _arraySliceSliceAddSliceAssign_g(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); //printf("_arraySliceSliceAddSliceAssign_g()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 5739% faster if (sse2 && a.length >= 64) { auto n = aptr + (a.length & ~63); if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) { version (log) printf("\tsse2 unaligned\n"); asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 8; startaddlsse2u: add ESI, 64; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; movdqu XMM2, [EAX+32]; movdqu XMM3, [EAX+48]; add EAX, 64; movdqu XMM4, [ECX]; movdqu XMM5, [ECX+16]; movdqu XMM6, [ECX+32]; movdqu XMM7, [ECX+48]; add ECX, 64; paddb XMM0, XMM4; paddb XMM1, XMM5; paddb XMM2, XMM6; paddb XMM3, XMM7; movdqu [ESI -64], XMM0; movdqu [ESI+16-64], XMM1; movdqu [ESI+32-64], XMM2; movdqu [ESI+48-64], XMM3; cmp ESI, EDI; jb startaddlsse2u; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else { version (log) printf("\tsse2 aligned\n"); asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 8; startaddlsse2a: add ESI, 64; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; movdqa XMM2, [EAX+32]; movdqa XMM3, [EAX+48]; add EAX, 64; movdqa XMM4, [ECX]; movdqa XMM5, [ECX+16]; movdqa XMM6, [ECX+32]; movdqa XMM7, [ECX+48]; add ECX, 64; paddb XMM0, XMM4; paddb XMM1, XMM5; paddb XMM2, XMM6; paddb XMM3, XMM7; movdqa [ESI -64], XMM0; movdqa [ESI+16-64], XMM1; movdqa [ESI+32-64], XMM2; movdqa [ESI+48-64], XMM3; cmp ESI, EDI; jb startaddlsse2a; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else // MMX version is 4428% faster if (mmx && a.length >= 32) { version (log) printf("\tmmx\n"); auto n = aptr + (a.length & ~31); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 4; startaddlmmx: add ESI, 32; movq MM0, [EAX]; movq MM1, [EAX+8]; movq MM2, [EAX+16]; movq MM3, [EAX+24]; add EAX, 32; movq MM4, [ECX]; movq MM5, [ECX+8]; movq MM6, [ECX+16]; movq MM7, [ECX+24]; add ECX, 32; paddb MM0, MM4; paddb MM1, MM5; paddb MM2, MM6; paddb MM3, MM7; movq [ESI -32], MM0; movq [ESI+8 -32], MM1; movq [ESI+16-32], MM2; movq [ESI+24-32], MM3; cmp ESI, EDI; jb startaddlmmx; emms; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } version (D_InlineAsm_X86_64) { if (a.length >= 128) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~127); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RCX, cptr; mov RDI, simdEnd; start128: // Load b movdqu XMM0, [RBX]; movdqu XMM1, [RBX + 16]; movdqu XMM2, [RBX + 32]; movdqu XMM3, [RBX + 48]; movdqu XMM4, [RBX + 64]; movdqu XMM5, [RBX + 80]; movdqu XMM6, [RBX + 96]; movdqu XMM7, [RBX + 112]; // Load c movdqu XMM8, [RCX]; movdqu XMM9, [RCX + 16]; movdqu XMM10, [RCX + 32]; movdqu XMM11, [RCX + 48]; movdqu XMM12, [RCX + 64]; movdqu XMM13, [RCX + 80]; movdqu XMM14, [RCX + 96]; movdqu XMM15, [RCX + 112]; // Add paddb XMM0, XMM8; paddb XMM1, XMM9; paddb XMM2, XMM10; paddb XMM3, XMM11; paddb XMM4, XMM12; paddb XMM5, XMM13; paddb XMM6, XMM14; paddb XMM7, XMM15; // Write to a movdqu [RAX], XMM0; movdqu [RAX + 16], XMM1; movdqu [RAX + 32], XMM2; movdqu [RAX + 48], XMM3; movdqu [RAX + 64], XMM4; movdqu [RAX + 80], XMM5; movdqu [RAX + 96], XMM6; movdqu [RAX + 112], XMM7; add RAX, 128; add RBX, 128; add RCX, 128; cmp RAX, RDI; jb start128; mov aptr, RAX; mov bptr, RBX; mov cptr, RCX; } } if ((aend - aptr) >= 16) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~15); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RCX, cptr; mov RDI, simdEnd; start16: movdqu XMM0, [RBX]; movdqu XMM1, [RCX]; paddb XMM0, XMM1; movdqu [RAX], XMM0; add RAX, 16; add RBX, 16; add RCX, 16; cmp RAX, RDI; jb start16; mov aptr, RAX; mov bptr, RBX; mov cptr, RCX; } } } version (log) if (aptr < aend) printf("\tbase\n"); while (aptr < aend) *aptr++ = cast(T)(*bptr++ + *cptr++); return a; } unittest { debug(PRINTF) printf("_arraySliceSliceAddSliceAssign_g unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] + b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + b[i])) { printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] += value */ T[] _arrayExpSliceAddass_a(T[] a, T value) { return _arrayExpSliceAddass_g(a, value); } T[] _arrayExpSliceAddass_h(T[] a, T value) { return _arrayExpSliceAddass_g(a, value); } T[] _arrayExpSliceAddass_g(T[] a, T value) { //printf("_arrayExpSliceAddass_g(a.length = %d, value = %Lg)\n", a.length, cast(real)value); auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 aligned version is 1578% faster if (sse2 && a.length >= 64) { auto n = aptr + (a.length & ~63); uint l = cast(ubyte)value * 0x01010101; if (((cast(uint) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startaddasssse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; movdqu XMM2, [ESI+32]; movdqu XMM3, [ESI+48]; add ESI, 64; paddb XMM0, XMM4; paddb XMM1, XMM4; paddb XMM2, XMM4; paddb XMM3, XMM4; movdqu [ESI -64], XMM0; movdqu [ESI+16-64], XMM1; movdqu [ESI+32-64], XMM2; movdqu [ESI+48-64], XMM3; cmp ESI, EDI; jb startaddasssse2u; mov aptr, ESI; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startaddasssse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; movdqa XMM2, [ESI+32]; movdqa XMM3, [ESI+48]; add ESI, 64; paddb XMM0, XMM4; paddb XMM1, XMM4; paddb XMM2, XMM4; paddb XMM3, XMM4; movdqa [ESI -64], XMM0; movdqa [ESI+16-64], XMM1; movdqa [ESI+32-64], XMM2; movdqa [ESI+48-64], XMM3; cmp ESI, EDI; jb startaddasssse2a; mov aptr, ESI; } } } else // MMX version is 1721% faster if (mmx && a.length >= 32) { auto n = aptr + (a.length & ~31); uint l = cast(ubyte)value * 0x0101; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movd MM4, l; pshufw MM4, MM4, 0; align 8; startaddassmmx: movq MM0, [ESI]; movq MM1, [ESI+8]; movq MM2, [ESI+16]; movq MM3, [ESI+24]; add ESI, 32; paddb MM0, MM4; paddb MM1, MM4; paddb MM2, MM4; paddb MM3, MM4; movq [ESI -32], MM0; movq [ESI+8 -32], MM1; movq [ESI+16-32], MM2; movq [ESI+24-32], MM3; cmp ESI, EDI; jb startaddassmmx; emms; mov aptr, ESI; } } } version (D_InlineAsm_X86_64) { ulong v = (cast(ulong) value) * 0x0101010101010101; if (aend - aptr >= 128) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~127); asm pure nothrow @nogc { mov RAX, aptr; mov RDI, simdEnd; movq XMM8, v; shufpd XMM8, XMM8, 0; start128: movdqu XMM0, [RAX]; paddb XMM0, XMM8; movdqu XMM1, [RAX + 16]; paddb XMM1, XMM8; movdqu XMM2, [RAX + 32]; paddb XMM2, XMM8; movdqu XMM3, [RAX + 48]; paddb XMM3, XMM8; movdqu XMM4, [RAX + 64]; paddb XMM4, XMM8; movdqu XMM5, [RAX + 80]; paddb XMM5, XMM8; movdqu XMM6, [RAX + 96]; paddb XMM6, XMM8; movdqu XMM7, [RAX + 112]; paddb XMM7, XMM8; movdqu [RAX], XMM0; movdqu [RAX + 16], XMM1; movdqu [RAX + 32], XMM2; movdqu [RAX + 48], XMM3; movdqu [RAX + 64], XMM4; movdqu [RAX + 80], XMM5; movdqu [RAX + 96], XMM6; movdqu [RAX + 112], XMM7; add RAX, 128; cmp RAX, RDI; jb start128; mov aptr, RAX; } } if (aend - aptr >= 16) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~15); asm pure nothrow @nogc { mov RAX, aptr; mov RDI, simdEnd; movq XMM4, v; shufpd XMM4, XMM4, 0; start16: movdqu XMM0, [RAX]; paddb XMM0, XMM4; movdqu [RAX], XMM0; add RAX, 16; cmp RAX, RDI; jb start16; mov aptr, RAX; } } } while (aptr < aend) *aptr++ += value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceAddass_g unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] += 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + 6)) { printf("[%d]: %d != %d + 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] += b[] */ T[] _arraySliceSliceAddass_a(T[] a, T[] b) { return _arraySliceSliceAddass_g(a, b); } T[] _arraySliceSliceAddass_h(T[] a, T[] b) { return _arraySliceSliceAddass_g(a, b); } T[] _arraySliceSliceAddass_g(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceSliceAddass_g()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 4727% faster if (sse2 && a.length >= 64) { auto n = aptr + (a.length & ~63); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 8; startaddasslsse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; movdqu XMM2, [ESI+32]; movdqu XMM3, [ESI+48]; add ESI, 64; movdqu XMM4, [ECX]; movdqu XMM5, [ECX+16]; movdqu XMM6, [ECX+32]; movdqu XMM7, [ECX+48]; add ECX, 64; paddb XMM0, XMM4; paddb XMM1, XMM5; paddb XMM2, XMM6; paddb XMM3, XMM7; movdqu [ESI -64], XMM0; movdqu [ESI+16-64], XMM1; movdqu [ESI+32-64], XMM2; movdqu [ESI+48-64], XMM3; cmp ESI, EDI; jb startaddasslsse2u; mov aptr, ESI; mov bptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 8; startaddasslsse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; movdqa XMM2, [ESI+32]; movdqa XMM3, [ESI+48]; add ESI, 64; movdqa XMM4, [ECX]; movdqa XMM5, [ECX+16]; movdqa XMM6, [ECX+32]; movdqa XMM7, [ECX+48]; add ECX, 64; paddb XMM0, XMM4; paddb XMM1, XMM5; paddb XMM2, XMM6; paddb XMM3, XMM7; movdqa [ESI -64], XMM0; movdqa [ESI+16-64], XMM1; movdqa [ESI+32-64], XMM2; movdqa [ESI+48-64], XMM3; cmp ESI, EDI; jb startaddasslsse2a; mov aptr, ESI; mov bptr, ECX; } } } else // MMX version is 3059% faster if (mmx && a.length >= 32) { auto n = aptr + (a.length & ~31); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 8; startaddasslmmx: movq MM0, [ESI]; movq MM1, [ESI+8]; movq MM2, [ESI+16]; movq MM3, [ESI+24]; add ESI, 32; movq MM4, [ECX]; movq MM5, [ECX+8]; movq MM6, [ECX+16]; movq MM7, [ECX+24]; add ECX, 32; paddb MM0, MM4; paddb MM1, MM5; paddb MM2, MM6; paddb MM3, MM7; movq [ESI -32], MM0; movq [ESI+8 -32], MM1; movq [ESI+16-32], MM2; movq [ESI+24-32], MM3; cmp ESI, EDI; jb startaddasslmmx; emms; mov aptr, ESI; mov bptr, ECX; } } } version (D_InlineAsm_X86_64) { if (a.length >= 128) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~127); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; start128: // Load a movdqu XMM0, [RAX]; movdqu XMM1, [RAX + 16]; movdqu XMM2, [RAX + 32]; movdqu XMM3, [RAX + 48]; movdqu XMM4, [RAX + 64]; movdqu XMM5, [RAX + 80]; movdqu XMM6, [RAX + 96]; movdqu XMM7, [RAX + 112]; // Load b movdqu XMM8, [RBX]; movdqu XMM9, [RBX + 16]; movdqu XMM10, [RBX + 32]; movdqu XMM11, [RBX + 48]; movdqu XMM12, [RBX + 64]; movdqu XMM13, [RBX + 80]; movdqu XMM14, [RBX + 96]; movdqu XMM15, [RBX + 112]; // Add paddb XMM0, XMM8; paddb XMM1, XMM9; paddb XMM2, XMM10; paddb XMM3, XMM11; paddb XMM4, XMM12; paddb XMM5, XMM13; paddb XMM6, XMM14; paddb XMM7, XMM15; // Write to a movdqu [RAX], XMM0; movdqu [RAX + 16], XMM1; movdqu [RAX + 32], XMM2; movdqu [RAX + 48], XMM3; movdqu [RAX + 64], XMM4; movdqu [RAX + 80], XMM5; movdqu [RAX + 96], XMM6; movdqu [RAX + 112], XMM7; add RAX, 128; add RBX, 128; cmp RAX, RDI; jb start128; mov aptr, RAX; mov bptr, RBX; } } if ((aend - aptr) >= 16) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~15); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; start16: movdqu XMM0, [RAX]; movdqu XMM1, [RBX]; paddb XMM0, XMM1; movdqu [RAX], XMM0; add RAX, 16; add RBX, 16; cmp RAX, RDI; jb start16; mov aptr, RAX; mov bptr, RBX; } } } while (aptr < aend) *aptr++ += *bptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceAddass_g unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] += b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] + b[i])) { printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - value */ T[] _arraySliceExpMinSliceAssign_a(T[] a, T value, T[] b) { return _arraySliceExpMinSliceAssign_g(a, value, b); } T[] _arraySliceExpMinSliceAssign_h(T[] a, T value, T[] b) { return _arraySliceExpMinSliceAssign_g(a, value, b); } T[] _arraySliceExpMinSliceAssign_g(T[] a, T value, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceExpMinSliceAssign_g()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 1189% faster if (sse2 && a.length >= 64) { auto n = aptr + (a.length & ~63); uint l = cast(ubyte)value * 0x01010101; if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startsubsse2u: add ESI, 64; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; movdqu XMM2, [EAX+32]; movdqu XMM3, [EAX+48]; add EAX, 64; psubb XMM0, XMM4; psubb XMM1, XMM4; psubb XMM2, XMM4; psubb XMM3, XMM4; movdqu [ESI -64], XMM0; movdqu [ESI+16-64], XMM1; movdqu [ESI+32-64], XMM2; movdqu [ESI+48-64], XMM3; cmp ESI, EDI; jb startsubsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startsubsse2a: add ESI, 64; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; movdqa XMM2, [EAX+32]; movdqa XMM3, [EAX+48]; add EAX, 64; psubb XMM0, XMM4; psubb XMM1, XMM4; psubb XMM2, XMM4; psubb XMM3, XMM4; movdqa [ESI -64], XMM0; movdqa [ESI+16-64], XMM1; movdqa [ESI+32-64], XMM2; movdqa [ESI+48-64], XMM3; cmp ESI, EDI; jb startsubsse2a; mov aptr, ESI; mov bptr, EAX; } } } else // MMX version is 1079% faster if (mmx && a.length >= 32) { auto n = aptr + (a.length & ~31); uint l = cast(ubyte)value * 0x0101; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd MM4, l; pshufw MM4, MM4, 0; align 4; startsubmmx: add ESI, 32; movq MM0, [EAX]; movq MM1, [EAX+8]; movq MM2, [EAX+16]; movq MM3, [EAX+24]; add EAX, 32; psubb MM0, MM4; psubb MM1, MM4; psubb MM2, MM4; psubb MM3, MM4; movq [ESI -32], MM0; movq [ESI+8 -32], MM1; movq [ESI+16-32], MM2; movq [ESI+24-32], MM3; cmp ESI, EDI; jb startsubmmx; emms; mov aptr, ESI; mov bptr, EAX; } } // trying to be fair and treat normal 32-bit cpu the same way as we do the SIMD units, with unrolled asm. There's not enough registers, really. else if (a.length >= 4) { auto n = aptr + (a.length & ~3); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov CL, value; align 4; startsub386: add ESI, 4; mov DX, [EAX]; mov BX, [EAX+2]; add EAX, 4; sub BL, CL; sub BH, CL; sub DL, CL; sub DH, CL; mov [ESI -4], DX; mov [ESI+2 -4], BX; cmp ESI, EDI; jb startsub386; mov aptr, ESI; mov bptr, EAX; } } } version (D_InlineAsm_X86_64) { ulong v = (cast(ulong) value) * 0x0101010101010101; if (a.length >= 128) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~127); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; movq XMM15, v; shufpd XMM15, XMM15, 0; start64: movdqu XMM0, [RBX]; movdqu XMM1, [RBX + 16]; movdqu XMM2, [RBX + 32]; movdqu XMM3, [RBX + 48]; movdqu XMM4, [RBX + 64]; movdqu XMM5, [RBX + 80]; movdqu XMM6, [RBX + 96]; movdqu XMM7, [RBX + 112]; psubb XMM0, XMM15; psubb XMM1, XMM15; psubb XMM2, XMM15; psubb XMM3, XMM15; psubb XMM4, XMM15; psubb XMM5, XMM15; psubb XMM6, XMM15; psubb XMM7, XMM15; movdqu [RAX], XMM0; movdqu [RAX + 16], XMM1; movdqu [RAX + 32], XMM2; movdqu [RAX + 48], XMM3; movdqu [RAX + 64], XMM4; movdqu [RAX + 80], XMM5; movdqu [RAX + 96], XMM6; movdqu [RAX + 112], XMM7; add RAX, 128; add RBX, 128; cmp RAX, RDI; jb start64; mov aptr, RAX; mov bptr, RBX; } } if ((aend - aptr) >= 16) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~15); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; movq XMM15, v; shufpd XMM15, XMM15, 0; start16: movdqu XMM0, [RBX]; psubb XMM0, XMM15; movdqu [RAX], XMM0; add RAX, 16; add RBX, 16; cmp RAX, RDI; jb start16; mov aptr, RAX; mov bptr, RBX; } } } while (aptr < aend) *aptr++ = cast(T)(*bptr++ - value); return a; } unittest { debug(PRINTF) printf("_arraySliceExpMinSliceAssign_g unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] = b[] - 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(b[i] - 6)) { printf("[%d]: %d != %d - 6\n", i, c[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = value - b[] */ T[] _arrayExpSliceMinSliceAssign_a(T[] a, T[] b, T value) { return _arrayExpSliceMinSliceAssign_g(a, b, value); } T[] _arrayExpSliceMinSliceAssign_h(T[] a, T[] b, T value) { return _arrayExpSliceMinSliceAssign_g(a, b, value); } T[] _arrayExpSliceMinSliceAssign_g(T[] a, T[] b, T value) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arrayExpSliceMinSliceAssign_g()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 8748% faster if (sse2 && a.length >= 64) { auto n = aptr + (a.length & ~63); uint l = cast(ubyte)value * 0x01010101; if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startsubrsse2u: add ESI, 64; movdqa XMM5, XMM4; movdqa XMM6, XMM4; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; psubb XMM5, XMM0; psubb XMM6, XMM1; movdqu [ESI -64], XMM5; movdqu [ESI+16-64], XMM6; movdqa XMM5, XMM4; movdqa XMM6, XMM4; movdqu XMM2, [EAX+32]; movdqu XMM3, [EAX+48]; add EAX, 64; psubb XMM5, XMM2; psubb XMM6, XMM3; movdqu [ESI+32-64], XMM5; movdqu [ESI+48-64], XMM6; cmp ESI, EDI; jb startsubrsse2u; mov aptr, ESI; mov bptr, EAX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startsubrsse2a: add ESI, 64; movdqa XMM5, XMM4; movdqa XMM6, XMM4; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; psubb XMM5, XMM0; psubb XMM6, XMM1; movdqa [ESI -64], XMM5; movdqa [ESI+16-64], XMM6; movdqa XMM5, XMM4; movdqa XMM6, XMM4; movdqa XMM2, [EAX+32]; movdqa XMM3, [EAX+48]; add EAX, 64; psubb XMM5, XMM2; psubb XMM6, XMM3; movdqa [ESI+32-64], XMM5; movdqa [ESI+48-64], XMM6; cmp ESI, EDI; jb startsubrsse2a; mov aptr, ESI; mov bptr, EAX; } } } else // MMX version is 7397% faster if (mmx && a.length >= 32) { auto n = aptr + (a.length & ~31); uint l = cast(ubyte)value * 0x0101; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; movd MM4, l; pshufw MM4, MM4, 0; align 4; startsubrmmx: add ESI, 32; movq MM5, MM4; movq MM6, MM4; movq MM0, [EAX]; movq MM1, [EAX+8]; psubb MM5, MM0; psubb MM6, MM1; movq [ESI -32], MM5; movq [ESI+8 -32], MM6; movq MM5, MM4; movq MM6, MM4; movq MM2, [EAX+16]; movq MM3, [EAX+24]; add EAX, 32; psubb MM5, MM2; psubb MM6, MM3; movq [ESI+16-32], MM5; movq [ESI+24-32], MM6; cmp ESI, EDI; jb startsubrmmx; emms; mov aptr, ESI; mov bptr, EAX; } } } version (D_InlineAsm_X86_64) { ulong v = (cast(ulong) value) * 0x0101010101010101; if (a.length >= 128) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~127); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; start64: movq XMM15, v; shufpd XMM15, XMM15, 0; movdqa XMM8, XMM15; movdqa XMM9, XMM15; movdqa XMM10, XMM15; movdqa XMM11, XMM15; movdqa XMM12, XMM15; movdqa XMM13, XMM15; movdqa XMM14, XMM15; movdqu XMM0, [RBX]; movdqu XMM1, [RBX + 16]; movdqu XMM2, [RBX + 32]; movdqu XMM3, [RBX + 48]; movdqu XMM4, [RBX + 64]; movdqu XMM5, [RBX + 80]; movdqu XMM6, [RBX + 96]; movdqu XMM7, [RBX + 112]; psubb XMM8, XMM0; psubb XMM9, XMM1; psubb XMM10, XMM2; psubb XMM11, XMM3; psubb XMM12, XMM4; psubb XMM13, XMM5; psubb XMM14, XMM6; psubb XMM15, XMM7; movdqu [RAX], XMM8; movdqu [RAX + 16], XMM9; movdqu [RAX + 32], XMM10; movdqu [RAX + 48], XMM11; movdqu [RAX + 64], XMM12; movdqu [RAX + 80], XMM13; movdqu [RAX + 96], XMM14; movdqu [RAX + 112], XMM15; add RAX, 128; add RBX, 128; cmp RAX, RDI; jb start64; mov aptr, RAX; mov bptr, RBX; } } if ((aend - aptr) >= 16) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~15); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; start16: movq XMM15, v; shufpd XMM15, XMM15, 0; movdqu XMM0, [RBX]; psubb XMM15, XMM0; movdqu [RAX], XMM15; add RAX, 16; add RBX, 16; cmp RAX, RDI; jb start16; mov aptr, RAX; mov bptr, RBX; } } } while (aptr < aend) *aptr++ = cast(T)(value - *bptr++); return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinSliceAssign_g unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] = 6 - b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(6 - b[i])) { printf("[%d]: %d != 6 - %d\n", i, c[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] = b[] - c[] */ T[] _arraySliceSliceMinSliceAssign_a(T[] a, T[] c, T[] b) { return _arraySliceSliceMinSliceAssign_g(a, c, b); } T[] _arraySliceSliceMinSliceAssign_h(T[] a, T[] c, T[] b) { return _arraySliceSliceMinSliceAssign_g(a, c, b); } T[] _arraySliceSliceMinSliceAssign_g(T[] a, T[] c, T[] b) { enforceTypedArraysConformable("vector operation", a, b); enforceTypedArraysConformable("vector operation", a, c); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; auto cptr = c.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 5756% faster if (sse2 && a.length >= 64) { auto n = aptr + (a.length & ~63); if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 8; startsublsse2u: add ESI, 64; movdqu XMM0, [EAX]; movdqu XMM1, [EAX+16]; movdqu XMM2, [EAX+32]; movdqu XMM3, [EAX+48]; add EAX, 64; movdqu XMM4, [ECX]; movdqu XMM5, [ECX+16]; movdqu XMM6, [ECX+32]; movdqu XMM7, [ECX+48]; add ECX, 64; psubb XMM0, XMM4; psubb XMM1, XMM5; psubb XMM2, XMM6; psubb XMM3, XMM7; movdqu [ESI -64], XMM0; movdqu [ESI+16-64], XMM1; movdqu [ESI+32-64], XMM2; movdqu [ESI+48-64], XMM3; cmp ESI, EDI; jb startsublsse2u; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 8; startsublsse2a: add ESI, 64; movdqa XMM0, [EAX]; movdqa XMM1, [EAX+16]; movdqa XMM2, [EAX+32]; movdqa XMM3, [EAX+48]; add EAX, 64; movdqa XMM4, [ECX]; movdqa XMM5, [ECX+16]; movdqa XMM6, [ECX+32]; movdqa XMM7, [ECX+48]; add ECX, 64; psubb XMM0, XMM4; psubb XMM1, XMM5; psubb XMM2, XMM6; psubb XMM3, XMM7; movdqa [ESI -64], XMM0; movdqa [ESI+16-64], XMM1; movdqa [ESI+32-64], XMM2; movdqa [ESI+48-64], XMM3; cmp ESI, EDI; jb startsublsse2a; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } else // MMX version is 4428% faster if (mmx && a.length >= 32) { auto n = aptr + (a.length & ~31); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov EAX, bptr; mov ECX, cptr; align 8; startsublmmx: add ESI, 32; movq MM0, [EAX]; movq MM1, [EAX+8]; movq MM2, [EAX+16]; movq MM3, [EAX+24]; add EAX, 32; movq MM4, [ECX]; movq MM5, [ECX+8]; movq MM6, [ECX+16]; movq MM7, [ECX+24]; add ECX, 32; psubb MM0, MM4; psubb MM1, MM5; psubb MM2, MM6; psubb MM3, MM7; movq [ESI -32], MM0; movq [ESI+8 -32], MM1; movq [ESI+16-32], MM2; movq [ESI+24-32], MM3; cmp ESI, EDI; jb startsublmmx; emms; mov aptr, ESI; mov bptr, EAX; mov cptr, ECX; } } } version (D_InlineAsm_X86_64) { if (a.length >= 128) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~127); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RCX, cptr; mov RDI, simdEnd; start128: // Load b movdqu XMM0, [RBX]; movdqu XMM1, [RBX + 16]; movdqu XMM2, [RBX + 32]; movdqu XMM3, [RBX + 48]; movdqu XMM4, [RBX + 64]; movdqu XMM5, [RBX + 80]; movdqu XMM6, [RBX + 96]; movdqu XMM7, [RBX + 112]; // Load c movdqu XMM8, [RCX]; movdqu XMM9, [RCX + 16]; movdqu XMM10, [RCX + 32]; movdqu XMM11, [RCX + 48]; movdqu XMM12, [RCX + 64]; movdqu XMM13, [RCX + 80]; movdqu XMM14, [RCX + 96]; movdqu XMM15, [RCX + 112]; // Subtract psubb XMM0, XMM8; psubb XMM1, XMM9; psubb XMM2, XMM10; psubb XMM3, XMM11; psubb XMM4, XMM12; psubb XMM5, XMM13; psubb XMM6, XMM14; psubb XMM7, XMM15; // Write to a movdqu [RAX], XMM0; movdqu [RAX + 16], XMM1; movdqu [RAX + 32], XMM2; movdqu [RAX + 48], XMM3; movdqu [RAX + 64], XMM4; movdqu [RAX + 80], XMM5; movdqu [RAX + 96], XMM6; movdqu [RAX + 112], XMM7; add RAX, 128; add RBX, 128; add RCX, 128; cmp RAX, RDI; jb start128; mov aptr, RAX; mov bptr, RBX; mov cptr, RCX; } } if ((aend - aptr) >= 16) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~15); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RCX, cptr; mov RDI, simdEnd; start16: movdqu XMM0, [RBX]; movdqu XMM1, [RCX]; psubb XMM0, XMM1; movdqu [RAX], XMM0; add RAX, 16; add RBX, 16; add RCX, 16; cmp RAX, RDI; jb start16; mov aptr, RAX; mov bptr, RBX; mov cptr, RCX; } } } while (aptr < aend) *aptr++ = cast(T)(*bptr++ - *cptr++); return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMinSliceAssign_g unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } c[] = a[] - b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - b[i])) { printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= value */ T[] _arrayExpSliceMinass_a(T[] a, T value) { return _arrayExpSliceMinass_g(a, value); } T[] _arrayExpSliceMinass_h(T[] a, T value) { return _arrayExpSliceMinass_g(a, value); } T[] _arrayExpSliceMinass_g(T[] a, T value) { //printf("_arrayExpSliceMinass_g(a.length = %d, value = %Lg)\n", a.length, cast(real)value); auto aptr = a.ptr; auto aend = aptr + a.length; version (D_InlineAsm_X86) { // SSE2 aligned version is 1577% faster if (sse2 && a.length >= 64) { auto n = aptr + (a.length & ~63); uint l = cast(ubyte)value * 0x01010101; if (((cast(uint) aptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startsubasssse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; movdqu XMM2, [ESI+32]; movdqu XMM3, [ESI+48]; add ESI, 64; psubb XMM0, XMM4; psubb XMM1, XMM4; psubb XMM2, XMM4; psubb XMM3, XMM4; movdqu [ESI -64], XMM0; movdqu [ESI+16-64], XMM1; movdqu [ESI+32-64], XMM2; movdqu [ESI+48-64], XMM3; cmp ESI, EDI; jb startsubasssse2u; mov aptr, ESI; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; movd XMM4, l; pshufd XMM4, XMM4, 0; align 8; startsubasssse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; movdqa XMM2, [ESI+32]; movdqa XMM3, [ESI+48]; add ESI, 64; psubb XMM0, XMM4; psubb XMM1, XMM4; psubb XMM2, XMM4; psubb XMM3, XMM4; movdqa [ESI -64], XMM0; movdqa [ESI+16-64], XMM1; movdqa [ESI+32-64], XMM2; movdqa [ESI+48-64], XMM3; cmp ESI, EDI; jb startsubasssse2a; mov aptr, ESI; } } } else // MMX version is 1577% faster if (mmx && a.length >= 32) { auto n = aptr + (a.length & ~31); uint l = cast(ubyte)value * 0x0101; asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; movd MM4, l; pshufw MM4, MM4, 0; align 8; startsubassmmx: movq MM0, [ESI]; movq MM1, [ESI+8]; movq MM2, [ESI+16]; movq MM3, [ESI+24]; add ESI, 32; psubb MM0, MM4; psubb MM1, MM4; psubb MM2, MM4; psubb MM3, MM4; movq [ESI -32], MM0; movq [ESI+8 -32], MM1; movq [ESI+16-32], MM2; movq [ESI+24-32], MM3; cmp ESI, EDI; jb startsubassmmx; emms; mov aptr, ESI; } } } version (D_InlineAsm_X86_64) { ulong v = (cast(ulong) value) * 0x0101010101010101; if (aend - aptr >= 128) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~127); asm pure nothrow @nogc { mov RAX, aptr; mov RDI, simdEnd; pshufd XMM8, XMM8, 0; movq XMM8, v; shufpd XMM8, XMM8, 0; start128: movdqu XMM0, [RAX]; psubb XMM0, XMM8; movdqu XMM1, [RAX + 16]; psubb XMM1, XMM8; movdqu XMM2, [RAX + 32]; psubb XMM2, XMM8; movdqu XMM3, [RAX + 48]; psubb XMM3, XMM8; movdqu XMM4, [RAX + 64]; psubb XMM4, XMM8; movdqu XMM5, [RAX + 80]; psubb XMM5, XMM8; movdqu XMM6, [RAX + 96]; psubb XMM6, XMM8; movdqu XMM7, [RAX + 112]; psubb XMM7, XMM8; movdqu [RAX], XMM0; movdqu [RAX + 16], XMM1; movdqu [RAX + 32], XMM2; movdqu [RAX + 48], XMM3; movdqu [RAX + 64], XMM4; movdqu [RAX + 80], XMM5; movdqu [RAX + 96], XMM6; movdqu [RAX + 112], XMM7; add RAX, 128; cmp RAX, RDI; jb start128; mov aptr, RAX; } } if (aend - aptr >= 16) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~15); asm pure nothrow @nogc { mov RAX, aptr; mov RDI, simdEnd; movq XMM4, v; shufpd XMM4, XMM4, 0; start16: movdqu XMM0, [RAX]; psubb XMM0, XMM4; movdqu [RAX], XMM0; add RAX, 16; cmp RAX, RDI; jb start16; mov aptr, RAX; } } } while (aptr < aend) *aptr++ -= value; return a; } unittest { debug(PRINTF) printf("_arrayExpSliceMinass_g unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] -= 6; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - 6)) { printf("[%d]: %d != %d - 6\n", i, c[i], a[i]); assert(0); } } } } } /* ======================================================================== */ /*********************** * Computes: * a[] -= b[] */ T[] _arraySliceSliceMinass_a(T[] a, T[] b) { return _arraySliceSliceMinass_g(a, b); } T[] _arraySliceSliceMinass_h(T[] a, T[] b) { return _arraySliceSliceMinass_g(a, b); } T[] _arraySliceSliceMinass_g(T[] a, T[] b) { enforceTypedArraysConformable("vector operation", a, b); //printf("_arraySliceSliceMinass_g()\n"); auto aptr = a.ptr; auto aend = aptr + a.length; auto bptr = b.ptr; version (D_InlineAsm_X86) { // SSE2 aligned version is 4800% faster if (sse2 && a.length >= 64) { auto n = aptr + (a.length & ~63); if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0) { asm pure nothrow @nogc // unaligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 8; startsubasslsse2u: movdqu XMM0, [ESI]; movdqu XMM1, [ESI+16]; movdqu XMM2, [ESI+32]; movdqu XMM3, [ESI+48]; add ESI, 64; movdqu XMM4, [ECX]; movdqu XMM5, [ECX+16]; movdqu XMM6, [ECX+32]; movdqu XMM7, [ECX+48]; add ECX, 64; psubb XMM0, XMM4; psubb XMM1, XMM5; psubb XMM2, XMM6; psubb XMM3, XMM7; movdqu [ESI -64], XMM0; movdqu [ESI+16-64], XMM1; movdqu [ESI+32-64], XMM2; movdqu [ESI+48-64], XMM3; cmp ESI, EDI; jb startsubasslsse2u; mov aptr, ESI; mov bptr, ECX; } } else { asm pure nothrow @nogc // aligned case { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 8; startsubasslsse2a: movdqa XMM0, [ESI]; movdqa XMM1, [ESI+16]; movdqa XMM2, [ESI+32]; movdqa XMM3, [ESI+48]; add ESI, 64; movdqa XMM4, [ECX]; movdqa XMM5, [ECX+16]; movdqa XMM6, [ECX+32]; movdqa XMM7, [ECX+48]; add ECX, 64; psubb XMM0, XMM4; psubb XMM1, XMM5; psubb XMM2, XMM6; psubb XMM3, XMM7; movdqa [ESI -64], XMM0; movdqa [ESI+16-64], XMM1; movdqa [ESI+32-64], XMM2; movdqa [ESI+48-64], XMM3; cmp ESI, EDI; jb startsubasslsse2a; mov aptr, ESI; mov bptr, ECX; } } } else // MMX version is 3107% faster if (mmx && a.length >= 32) { auto n = aptr + (a.length & ~31); asm pure nothrow @nogc { mov ESI, aptr; mov EDI, n; mov ECX, bptr; align 8; startsubasslmmx: movq MM0, [ESI]; movq MM1, [ESI+8]; movq MM2, [ESI+16]; movq MM3, [ESI+24]; add ESI, 32; movq MM4, [ECX]; movq MM5, [ECX+8]; movq MM6, [ECX+16]; movq MM7, [ECX+24]; add ECX, 32; psubb MM0, MM4; psubb MM1, MM5; psubb MM2, MM6; psubb MM3, MM7; movq [ESI -32], MM0; movq [ESI+8 -32], MM1; movq [ESI+16-32], MM2; movq [ESI+24-32], MM3; cmp ESI, EDI; jb startsubasslmmx; emms; mov aptr, ESI; mov bptr, ECX; } } } version (D_InlineAsm_X86_64) { if (a.length >= 128) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~127); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; start128: // Load a movdqu XMM0, [RAX]; movdqu XMM1, [RAX + 16]; movdqu XMM2, [RAX + 32]; movdqu XMM3, [RAX + 48]; movdqu XMM4, [RAX + 64]; movdqu XMM5, [RAX + 80]; movdqu XMM6, [RAX + 96]; movdqu XMM7, [RAX + 112]; // Load b movdqu XMM8, [RBX]; movdqu XMM9, [RBX + 16]; movdqu XMM10, [RBX + 32]; movdqu XMM11, [RBX + 48]; movdqu XMM12, [RBX + 64]; movdqu XMM13, [RBX + 80]; movdqu XMM14, [RBX + 96]; movdqu XMM15, [RBX + 112]; // Subtract psubb XMM0, XMM8; psubb XMM1, XMM9; psubb XMM2, XMM10; psubb XMM3, XMM11; psubb XMM4, XMM12; psubb XMM5, XMM13; psubb XMM6, XMM14; psubb XMM7, XMM15; // Write to a movdqu [RAX], XMM0; movdqu [RAX + 16], XMM1; movdqu [RAX + 32], XMM2; movdqu [RAX + 48], XMM3; movdqu [RAX + 64], XMM4; movdqu [RAX + 80], XMM5; movdqu [RAX + 96], XMM6; movdqu [RAX + 112], XMM7; add RAX, 128; add RBX, 128; cmp RAX, RDI; jb start128; mov aptr, RAX; mov bptr, RBX; } } if ((aend - aptr) >= 16) { size_t simdEnd = (cast(size_t) aptr) + (a.length & ~15); asm pure nothrow @nogc { mov RAX, aptr; mov RBX, bptr; mov RDI, simdEnd; start16: movdqu XMM0, [RAX]; movdqu XMM1, [RBX]; psubb XMM0, XMM1; movdqu [RAX], XMM0; add RAX, 16; add RBX, 16; cmp RAX, RDI; jb start16; mov aptr, RAX; mov bptr, RBX; } } } while (aptr < aend) *aptr++ -= *bptr++; return a; } unittest { debug(PRINTF) printf("_arraySliceSliceMinass_g unittest\n"); for (cpuid = 0; cpuid < CPUID_MAX; cpuid++) { version (log) printf(" cpuid %d\n", cpuid); for (int j = 0; j < 2; j++) { const int dim = 67; T[] a = new T[dim + j]; // aligned on 16 byte boundary a = a[j .. dim + j]; // misalign for second iteration T[] b = new T[dim + j]; b = b[j .. dim + j]; T[] c = new T[dim + j]; c = c[j .. dim + j]; for (int i = 0; i < dim; i++) { a[i] = cast(T)i; b[i] = cast(T)(i + 7); c[i] = cast(T)(i * 2); } a[] = c[]; c[] -= b[]; for (int i = 0; i < dim; i++) { if (c[i] != cast(T)(a[i] - b[i])) { printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]); assert(0); } } } } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/adi.d0000664000175000017500000003374612776214756017616 0ustar kaikai/** * Implementation of dynamic array property support routines. * * Copyright: Copyright Digital Mars 2000 - 2015. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright * Source: $(DRUNTIMESRC src/rt/_adi.d) */ module rt.adi; //debug=adi; // uncomment to turn on debugging printf's private { debug(adi) import core.stdc.stdio; import core.stdc.string; import core.stdc.stdlib; import core.memory; import rt.util.utf; extern (C) void[] _adSort(void[] a, TypeInfo ti); } /********************************************** * Reverse array of chars. * Handled separately because embedded multibyte encodings should not be * reversed. */ extern (C) char[] _adReverseChar(char[] a) { if (a.length > 1) { char[6] tmp; char[6] tmplo; char* lo = a.ptr; char* hi = &a[$ - 1]; while (lo < hi) { auto clo = *lo; auto chi = *hi; debug(adi) printf("lo = %d, hi = %d\n", lo, hi); if (clo <= 0x7F && chi <= 0x7F) { debug(adi) printf("\tascii\n"); *lo = chi; *hi = clo; lo++; hi--; continue; } uint stridelo = UTF8stride[clo]; uint stridehi = 1; while ((chi & 0xC0) == 0x80) { chi = *--hi; stridehi++; assert(hi >= lo); } if (lo == hi) break; debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi); if (stridelo == stridehi) { memcpy(tmp.ptr, lo, stridelo); memcpy(lo, hi, stridelo); memcpy(hi, tmp.ptr, stridelo); lo += stridelo; hi--; continue; } /* Shift the whole array. This is woefully inefficient */ memcpy(tmp.ptr, hi, stridehi); memcpy(tmplo.ptr, lo, stridelo); memmove(lo + stridehi, lo + stridelo , cast(size_t)((hi - lo) - stridelo)); memcpy(lo, tmp.ptr, stridehi); memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo); lo += stridehi; hi = hi - 1 + cast(int)(stridehi - stridelo); } } return a; } unittest { auto a = "abcd"c[]; auto r = _adReverseChar(a.dup); //writefln(r); assert(r == "dcba"); a = "a\u1235\u1234c"; //writefln(a); r = _adReverseChar(a.dup); //writefln(r); assert(r == "c\u1234\u1235a"); a = "ab\u1234c"; //writefln(a); r = _adReverseChar(a.dup); //writefln(r); assert(r == "c\u1234ba"); a = "\u3026\u2021\u3061\n"; r = _adReverseChar(a.dup); assert(r == "\n\u3061\u2021\u3026"); } /********************************************** * Reverse array of wchars. * Handled separately because embedded multiword encodings should not be * reversed. */ extern (C) wchar[] _adReverseWchar(wchar[] a) { if (a.length > 1) { wchar[2] tmplo = void; wchar[2] tmphi = void; wchar* lo = a.ptr; wchar* hi = &a[$ - 1]; while (lo < hi) { auto clo = *lo; auto chi = *hi; if ((clo < 0xD800 || clo > 0xDFFF) && (chi < 0xD800 || chi > 0xDFFF)) { *lo = chi; *hi = clo; lo++; hi--; continue; } int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF); int stridehi = 1; if (chi >= 0xDC00 && chi <= 0xDFFF) { chi = *--hi; stridehi++; assert(hi >= lo); } if (lo == hi) break; if (stridelo == stridehi) { wchar[2] stmp; assert(stridelo == 2); stmp = lo[0 .. 2]; lo[0 .. 2] = hi[0 .. 2]; hi[0 .. 2] = stmp; lo += stridelo; hi--; continue; } /* Shift the whole array. This is woefully inefficient */ memcpy(tmplo.ptr, lo, stridelo * wchar.sizeof); memcpy(tmphi.ptr, hi, stridehi * wchar.sizeof); memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof); memcpy(lo, tmphi.ptr, stridehi * wchar.sizeof); memcpy(hi + (stridehi - stridelo), tmplo.ptr, stridelo * wchar.sizeof); lo += stridehi; hi = hi - 1 + (stridehi - stridelo); } } return a; } unittest { { wstring a = "abcd"; auto r = _adReverseWchar(a.dup); assert(r == "dcba"); a = "a\U00012356\U00012346c"; r = _adReverseWchar(a.dup); assert(r == "c\U00012346\U00012356a"); a = "ab\U00012345c"; r = _adReverseWchar(a.dup); assert(r == "c\U00012345ba"); } { wstring a = "a\U00000081b\U00002000c\U00010000"; wchar[] b = a.dup; _adReverseWchar(b); _adReverseWchar(b); assert(b == "a\U00000081b\U00002000c\U00010000"); } } /********************************************** * Support for array.reverse property. */ extern (C) void[] _adReverse(void[] a, size_t szelem) out (result) { assert(result is a); } body { if (a.length >= 2) { byte* tmp; byte[16] buffer; void* lo = a.ptr; void* hi = a.ptr + (a.length - 1) * szelem; tmp = buffer.ptr; if (szelem > 16) { //version (Windows) tmp = cast(byte*) alloca(szelem); //else //tmp = GC.malloc(szelem); } for (; lo < hi; lo += szelem, hi -= szelem) { memcpy(tmp, lo, szelem); memcpy(lo, hi, szelem); memcpy(hi, tmp, szelem); } version (Windows) { } else { //if (szelem > 16) // BUG: bad code is generate for delete pointer, tries // to call delclass. //GC.free(tmp); } } return a; } unittest { debug(adi) printf("array.reverse.unittest\n"); int[] a = new int[5]; int[] b; for (auto i = 0; i < 5; i++) a[i] = i; *(cast(void[]*)&b) = _adReverse(*cast(void[]*)&a, a[0].sizeof); assert(b is a); for (auto i = 0; i < 5; i++) assert(a[i] == 4 - i); struct X20 { // More than 16 bytes in size int a; int b, c, d, e; } X20[] c = new X20[5]; X20[] d; for (auto i = 0; i < 5; i++) { c[i].a = i; c[i].e = 10; } *(cast(void[]*)&d) = _adReverse(*(cast(void[]*)&c), c[0].sizeof); assert(d is c); for (auto i = 0; i < 5; i++) { assert(c[i].a == 4 - i); assert(c[i].e == 10); } } private dchar[] mallocUTF32(C)(in C[] s) { size_t j = 0; auto p = cast(dchar*)malloc(dchar.sizeof * s.length); auto r = p[0..s.length]; // r[] will never be longer than s[] foreach (dchar c; s) r[j++] = c; return r[0 .. j]; } /********************************************** * Sort array of chars. */ extern (C) char[] _adSortChar(char[] a) { if (a.length > 1) { auto da = mallocUTF32(a); _adSort(*cast(void[]*)&da, typeid(da[0])); size_t i = 0; foreach (dchar d; da) { char[4] buf; auto t = toUTF8(buf, d); a[i .. i + t.length] = t[]; i += t.length; } free(da.ptr); } return a; } /********************************************** * Sort array of wchars. */ extern (C) wchar[] _adSortWchar(wchar[] a) { if (a.length > 1) { auto da = mallocUTF32(a); _adSort(*cast(void[]*)&da, typeid(da[0])); size_t i = 0; foreach (dchar d; da) { wchar[2] buf; auto t = toUTF16(buf, d); a[i .. i + t.length] = t[]; i += t.length; } free(da.ptr); } return a; } /*************************************** * Support for array equality test. * Returns: * 1 equal * 0 not equal */ extern (C) int _adEq(void[] a1, void[] a2, TypeInfo ti) { debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length); if (a1.length != a2.length) return 0; // not equal auto sz = ti.tsize; auto p1 = a1.ptr; auto p2 = a2.ptr; if (sz == 1) // We should really have a ti.isPOD() check for this return (memcmp(p1, p2, a1.length) == 0); for (size_t i = 0; i < a1.length; i++) { if (!ti.equals(p1 + i * sz, p2 + i * sz)) return 0; // not equal } return 1; // equal } extern (C) int _adEq2(void[] a1, void[] a2, TypeInfo ti) { debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length); if (a1.length != a2.length) return 0; // not equal if (!ti.equals(&a1, &a2)) return 0; return 1; } unittest { debug(adi) printf("array.Eq unittest\n"); auto a = "hello"c; assert(a != "hel"); assert(a != "helloo"); assert(a != "betty"); assert(a == "hello"); assert(a != "hxxxx"); float[] fa = [float.nan]; assert(fa != fa); } /*************************************** * Support for array compare test. */ extern (C) int _adCmp(void[] a1, void[] a2, TypeInfo ti) { debug(adi) printf("adCmp()\n"); auto len = a1.length; if (a2.length < len) len = a2.length; auto sz = ti.tsize; void *p1 = a1.ptr; void *p2 = a2.ptr; if (sz == 1) { // We should really have a ti.isPOD() check for this auto c = memcmp(p1, p2, len); if (c) return c; } else { for (size_t i = 0; i < len; i++) { auto c = ti.compare(p1 + i * sz, p2 + i * sz); if (c) return c; } } if (a1.length == a2.length) return 0; return (a1.length > a2.length) ? 1 : -1; } extern (C) int _adCmp2(void[] a1, void[] a2, TypeInfo ti) { debug(adi) printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length); return ti.compare(&a1, &a2); } unittest { debug(adi) printf("array.Cmp unittest\n"); auto a = "hello"c; assert(a > "hel"); assert(a >= "hel"); assert(a < "helloo"); assert(a <= "helloo"); assert(a > "betty"); assert(a >= "betty"); assert(a == "hello"); assert(a <= "hello"); assert(a >= "hello"); assert(a < "я"); } /*************************************** * Support for array compare test. */ extern (C) int _adCmpChar(void[] a1, void[] a2) { // LDC doesn't support parameter references in naked functions. The asm // could also be rewritten to directly access the ṕarameters as the // calling convention is known. version (LDC) enum useAsm = false; else version (D_InlineAsm_X86) enum useAsm = true; else enum useAsm = false; static if (useAsm) { asm { naked ; push EDI ; push ESI ; mov ESI,a1+4[4+ESP] ; mov EDI,a2+4[4+ESP] ; mov ECX,a1[4+ESP] ; mov EDX,a2[4+ESP] ; cmp ECX,EDX ; jb GotLength ; mov ECX,EDX ; GotLength: cmp ECX,4 ; jb DoBytes ; // Do alignment if neither is dword aligned test ESI,3 ; jz Aligned ; test EDI,3 ; jz Aligned ; DoAlign: mov AL,[ESI] ; //align ESI to dword bounds mov DL,[EDI] ; cmp AL,DL ; jnz Unequal ; inc ESI ; inc EDI ; test ESI,3 ; lea ECX,[ECX-1] ; jnz DoAlign ; Aligned: mov EAX,ECX ; // do multiple of 4 bytes at a time shr ECX,2 ; jz TryOdd ; repe ; cmpsd ; jnz UnequalQuad ; TryOdd: mov ECX,EAX ; DoBytes: // if still equal and not end of string, do up to 3 bytes slightly // slower. and ECX,3 ; jz Equal ; repe ; cmpsb ; jnz Unequal ; Equal: mov EAX,a1[4+ESP] ; mov EDX,a2[4+ESP] ; sub EAX,EDX ; pop ESI ; pop EDI ; ret ; UnequalQuad: mov EDX,[EDI-4] ; mov EAX,[ESI-4] ; cmp AL,DL ; jnz Unequal ; cmp AH,DH ; jnz Unequal ; shr EAX,16 ; shr EDX,16 ; cmp AL,DL ; jnz Unequal ; cmp AH,DH ; Unequal: sbb EAX,EAX ; pop ESI ; or EAX,1 ; pop EDI ; ret ; } } else { debug(adi) printf("adCmpChar()\n"); auto len = a1.length; if (a2.length < len) len = a2.length; auto c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len); if (!c) c = cast(int)a1.length - cast(int)a2.length; return c; } } unittest { debug(adi) printf("array.CmpChar unittest\n"); auto a = "hello"c; assert(a > "hel"); assert(a >= "hel"); assert(a < "helloo"); assert(a <= "helloo"); assert(a > "betty"); assert(a >= "betty"); assert(a == "hello"); assert(a <= "hello"); assert(a >= "hello"); } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/memset.d0000664000175000017500000000560612776214756020345 0ustar kaikai/** * Contains a memset implementation used by compiler-generated code. * * Copyright: Copyright Digital Mars 2004 - 2010. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Walter Bright */ /* Copyright Digital Mars 2004 - 2010. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module rt.memset; extern (C) { // Functions from the C library. void *memcpy(void *, void *, size_t); } extern (C): short *_memset16(short *p, short value, size_t count) { short *pstart = p; short *ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } int *_memset32(int *p, int value, size_t count) { version (D_InlineAsm_X86) { asm { mov EDI,p ; mov EAX,value ; mov ECX,count ; mov EDX,EDI ; rep ; stosd ; mov EAX,EDX ; } } else { int *pstart = p; int *ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } } long *_memset64(long *p, long value, size_t count) { long *pstart = p; long *ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } cdouble *_memset128(cdouble *p, cdouble value, size_t count) { cdouble *pstart = p; cdouble *ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } void[] *_memset128ii(void[] *p, void[] value, size_t count) { void[] *pstart = p; void[] *ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } real *_memset80(real *p, real value, size_t count) { real *pstart = p; real *ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } creal *_memset160(creal *p, creal value, size_t count) { creal *pstart = p; creal *ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } void *_memsetn(void *p, void *value, int count, size_t sizelem) { void *pstart = p; int i; for (i = 0; i < count; i++) { memcpy(p, value, sizelem); p = cast(void *)(cast(char *)p + sizelem); } return pstart; } float *_memsetFloat(float *p, float value, size_t count) { float *pstart = p; float *ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } double *_memsetDouble(double *p, double value, size_t count) { double *pstart = p; double *ptop; for (ptop = &p[count]; p < ptop; p++) *p = value; return pstart; } version (D_SIMD) { import core.simd; void16* _memsetSIMD(void16 *p, void16 value, size_t count) { foreach (i; 0..count) p[i] = value; return p; } } ldc-1.1.0-beta3-src/runtime/druntime/src/rt/profilegc.d0000664000175000017500000001051612776214756021021 0ustar kaikai/* * Data collection and report generation for * -profile=gc * switch * * Copyright: Copyright Digital Mars 2015 - 2015. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Andrei Alexandrescu and Walter Bright * Source: $(DRUNTIMESRC src/rt/_profilegc.d) */ module rt.profilegc; private: import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; import core.exception : onOutOfMemoryError; struct Entry { size_t count, size; } char[] buffer; Entry[string] newCounts; __gshared { Entry[string] globalNewCounts; string logfilename = "profilegc.log"; } /**** * Set file name for output. * A file name of "" means write results to stdout. * Params: * name = file name */ extern (C) void profilegc_setlogfilename(string name) { logfilename = name; } public void accumulate(string file, uint line, string funcname, string type, size_t sz) { char[3 * line.sizeof + 1] buf; auto buflen = snprintf(buf.ptr, buf.length, "%u", line); auto length = type.length + 1 + funcname.length + 1 + file.length + 1 + buflen; if (length > buffer.length) { // Enlarge buffer[] so it is big enough auto p = cast(char*)realloc(buffer.ptr, length); if (!p) onOutOfMemoryError(); buffer = p[0 .. length]; } // "type funcname file:line" buffer[0 .. type.length] = type[]; buffer[type.length] = ' '; buffer[type.length + 1 .. type.length + 1 + funcname.length] = funcname[]; buffer[type.length + 1 + funcname.length] = ' '; buffer[type.length + 1 + funcname.length + 1 .. type.length + 1 + funcname.length + 1 + file.length] = file[]; buffer[type.length + 1 + funcname.length + 1 + file.length] = ':'; buffer[type.length + 1 + funcname.length + 1 + file.length + 1 .. type.length + 1 + funcname.length + 1 + file.length + 1 + buflen] = buf[0 .. buflen]; if (auto pcount = cast(string)buffer[0 .. length] in newCounts) { // existing entry pcount.count++; pcount.size += sz; } else newCounts[buffer[0..length].idup] = Entry(1, sz); // new entry } // Merge thread local newCounts into globalNewCounts static ~this() { if (newCounts.length) { synchronized { if (globalNewCounts.length) { // Merge foreach (name, entry; newCounts) { globalNewCounts[name].count += entry.count; globalNewCounts[name].size += entry.size; } } else // Assign globalNewCounts = newCounts; } newCounts = null; } free(buffer.ptr); buffer = null; } // Write report to stderr shared static ~this() { static struct Result { string name; Entry entry; // qsort() comparator to sort by count field extern (C) static int qsort_cmp(const void *r1, const void *r2) { auto result1 = cast(Result*)r1; auto result2 = cast(Result*)r2; ptrdiff_t cmp = result2.entry.size - result1.entry.size; if (cmp) return cmp < 0 ? -1 : 1; cmp = result2.entry.count - result1.entry.count; return cmp < 0 ? -1 : (cmp > 0 ? 1 : 0); } } Result[] counts = new Result[globalNewCounts.length]; size_t i; foreach (name, entry; globalNewCounts) { counts[i].name = name; counts[i].entry = entry; ++i; } if (counts.length) { qsort(counts.ptr, counts.length, Result.sizeof, &Result.qsort_cmp); FILE* fp = logfilename.length == 0 ? stdout : fopen((logfilename ~ '\0').ptr, "w"); if (fp) { fprintf(fp, "bytes allocated, allocations, type, function, file:line\n"); foreach (ref c; counts) { fprintf(fp, "%15llu\t%15llu\t%8.*s\n", cast(ulong)c.entry.size, cast(ulong)c.entry.count, c.name.length, c.name.ptr); } if (logfilename.length) fclose(fp); } else fprintf(stderr, "cannot write profilegc log file '%.*s'", logfilename.length, logfilename.ptr); } } ldc-1.1.0-beta3-src/runtime/druntime/src/gcstub/0000775000175000017500000000000012776214756017541 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/gcstub/gc.d0000664000175000017500000002277312776214756020312 0ustar kaikai/** * This module contains a minimal garbage collector implementation according to * published requirements. This library is mostly intended to serve as an * example, but it is usable in applications which do not rely on a garbage * collector to clean up memory (ie. when dynamic array resizing is not used, * and all memory allocated with 'new' is freed deterministically with * 'delete'). * * Please note that block attribute data must be tracked, or at a minimum, the * FINALIZE bit must be tracked for any allocated memory block because calling * rt_finalize on a non-object block can result in an access violation. In the * allocator below, this tracking is done via a leading uint bitmask. A real * allocator may do better to store this data separately, similar to the basic * GC. * * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly */ /* Copyright Sean Kelly 2005 - 2009. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ module gc.gc; private { import core.stdc.stdlib; import core.stdc.stdio; static import core.memory; private alias BlkAttr = core.memory.GC.BlkAttr; private alias BlkInfo = core.memory.GC.BlkInfo; extern (C) void thread_init(); extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */ struct Proxy { extern (C) void function() gc_enable; extern (C) void function() gc_disable; extern (C) void function() gc_collect; extern (C) void function() gc_minimize; extern (C) uint function(void*) gc_getAttr; extern (C) uint function(void*, uint) gc_setAttr; extern (C) uint function(void*, uint) gc_clrAttr; extern (C) void* function(size_t, uint, const TypeInfo) gc_malloc; extern (C) BlkInfo function(size_t, uint, const TypeInfo) gc_qalloc; extern (C) void* function(size_t, uint, const TypeInfo) gc_calloc; extern (C) void* function(void*, size_t, uint ba, const TypeInfo) gc_realloc; extern (C) size_t function(void*, size_t, size_t, const TypeInfo) gc_extend; extern (C) size_t function(size_t) gc_reserve; extern (C) void function(void*) gc_free; extern (C) void* function(void*) gc_addrOf; extern (C) size_t function(void*) gc_sizeOf; extern (C) BlkInfo function(void*) gc_query; extern (C) void function(void*) gc_addRoot; extern (C) void function(void*, size_t, const TypeInfo ti) gc_addRange; extern (C) void function(void*) gc_removeRoot; extern (C) void function(void*) gc_removeRange; extern (C) void function(in void[]) gc_runFinalizers; extern (C) bool function() gc_inFinalizer; } __gshared Proxy pthis; __gshared Proxy* proxy; void initProxy() { pthis.gc_enable = &gc_enable; pthis.gc_disable = &gc_disable; pthis.gc_collect = &gc_collect; pthis.gc_minimize = &gc_minimize; pthis.gc_getAttr = &gc_getAttr; pthis.gc_setAttr = &gc_setAttr; pthis.gc_clrAttr = &gc_clrAttr; pthis.gc_malloc = &gc_malloc; pthis.gc_qalloc = &gc_qalloc; pthis.gc_calloc = &gc_calloc; pthis.gc_realloc = &gc_realloc; pthis.gc_extend = &gc_extend; pthis.gc_reserve = &gc_reserve; pthis.gc_free = &gc_free; pthis.gc_addrOf = &gc_addrOf; pthis.gc_sizeOf = &gc_sizeOf; pthis.gc_query = &gc_query; pthis.gc_addRoot = &gc_addRoot; pthis.gc_addRange = &gc_addRange; pthis.gc_removeRoot = &gc_removeRoot; pthis.gc_removeRange = &gc_removeRange; pthis.gc_runFinalizers = &gc_runFinalizers; pthis.gc_inFinalizer = &gc_inFinalizer; } __gshared void** roots = null; __gshared size_t nroots = 0; struct Range { void* pos; size_t len; TypeInfo ti; // should be tail const, but doesn't exist for references } __gshared Range* ranges = null; __gshared size_t nranges = 0; } extern (C) void gc_init() { // NOTE: The GC must initialize the thread library before its first // collection, and always before returning from gc_init(). thread_init(); initProxy(); } extern (C) void gc_term() { free( roots ); free( ranges ); } extern (C) void gc_enable() { if( proxy is null ) return; return proxy.gc_enable(); } extern (C) void gc_disable() { if( proxy is null ) return; return proxy.gc_disable(); } extern (C) void gc_collect() { if( proxy is null ) return; return proxy.gc_collect(); } extern (C) void gc_minimize() { if( proxy is null ) return; return proxy.gc_minimize(); } extern (C) uint gc_getAttr( void* p ) { if( proxy is null ) return 0; return proxy.gc_getAttr( p ); } extern (C) uint gc_setAttr( void* p, uint a ) { if( proxy is null ) return 0; return proxy.gc_setAttr( p, a ); } extern (C) uint gc_clrAttr( void* p, uint a ) { if( proxy is null ) return 0; return proxy.gc_clrAttr( p, a ); } extern (C) void* gc_malloc( size_t sz, uint ba = 0, const TypeInfo ti = null ) { if( proxy is null ) { void* p = malloc( sz ); if( sz && p is null ) onOutOfMemoryError(); return p; } return proxy.gc_malloc( sz, ba, ti ); } extern (C) BlkInfo gc_qalloc( size_t sz, uint ba = 0, const TypeInfo ti = null ) { if( proxy is null ) { BlkInfo retval; retval.base = gc_malloc(sz, ba); retval.size = sz; retval.attr = ba; return retval; } return proxy.gc_qalloc( sz, ba, ti ); } extern (C) void* gc_calloc( size_t sz, uint ba = 0, const TypeInfo ti = null ) { if( proxy is null ) { void* p = calloc( 1, sz ); if( sz && p is null ) onOutOfMemoryError(); return p; } return proxy.gc_calloc( sz, ba, ti ); } extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0, const TypeInfo ti = null ) { if( proxy is null ) { p = realloc( p, sz ); if( sz && p is null ) onOutOfMemoryError(); return p; } return proxy.gc_realloc( p, sz, ba, ti ); } extern (C) size_t gc_extend( void* p, size_t mx, size_t sz, const TypeInfo ti = null ) { if( proxy is null ) return 0; return proxy.gc_extend( p, mx, sz, ti ); } extern (C) size_t gc_reserve( size_t sz ) { if( proxy is null ) return 0; return proxy.gc_reserve( sz ); } extern (C) void gc_free( void* p ) { if( proxy is null ) return free( p ); return proxy.gc_free( p ); } extern (C) void* gc_addrOf( void* p ) { if( proxy is null ) return null; return proxy.gc_addrOf( p ); } extern (C) size_t gc_sizeOf( void* p ) { if( proxy is null ) return 0; return proxy.gc_sizeOf( p ); } extern (C) BlkInfo gc_query( void* p ) { if( proxy is null ) return BlkInfo.init; return proxy.gc_query( p ); } extern (C) void gc_addRoot( void* p ) { if( proxy is null ) { void** r = cast(void**) realloc( roots, (nroots+1) * roots[0].sizeof ); if( r is null ) onOutOfMemoryError(); r[nroots++] = p; roots = r; return; } return proxy.gc_addRoot( p ); } extern (C) void gc_addRange( void* p, size_t sz, const TypeInfo ti = null ) { //printf("gcstub::gc_addRange() proxy = %p\n", proxy); if( proxy is null ) { Range* r = cast(Range*) realloc( ranges, (nranges+1) * ranges[0].sizeof ); if( r is null ) onOutOfMemoryError(); r[nranges].pos = p; r[nranges].len = sz; r[nranges].ti = cast()ti; ranges = r; ++nranges; return; } return proxy.gc_addRange( p, sz, ti ); } extern (C) void gc_removeRoot( void *p ) { if( proxy is null ) { for( size_t i = 0; i < nroots; ++i ) { if( roots[i] is p ) { roots[i] = roots[--nroots]; return; } } assert( false ); } return proxy.gc_removeRoot( p ); } extern (C) void gc_removeRange( void *p ) { if( proxy is null ) { for( size_t i = 0; i < nranges; ++i ) { if( ranges[i].pos is p ) { ranges[i] = ranges[--nranges]; return; } } assert( false ); } return proxy.gc_removeRange( p ); } extern (C) void gc_runFinalizers( in void[] segment ) { if( proxy !is null ) proxy.gc_runFinalizers( segment ); } extern (C) bool gc_inFinalizer() { if( proxy !is null ) return proxy.gc_inFinalizer(); return false; } extern (C) Proxy* gc_getProxy() { return &pthis; } export extern (C) void gc_setProxy( Proxy* p ) { if( proxy !is null ) { // TODO: Decide if this is an error condition. } proxy = p; foreach( r; roots[0 .. nroots] ) proxy.gc_addRoot( r ); foreach( r; ranges[0 .. nranges] ) proxy.gc_addRange( r.pos, r.len, r.ti ); } export extern (C) void gc_clrProxy() { foreach( r; ranges[0 .. nranges] ) proxy.gc_removeRange( r.pos ); foreach( r; roots[0 .. nroots] ) proxy.gc_removeRoot( r ); proxy = null; } ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/0000775000175000017500000000000012776214756017014 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/ldc/msvc.c0000664000175000017500000001347712776214756020144 0ustar kaikai/** * Implementation of support routines for synchronized blocks. * * Copyright: Copyright The LDC Developers 2012 * License: Boost License 1.0. * Authors: Kai Nacke */ /* Copyright The LDC Developers 2012. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE or copy at * http://www.boost.org/LICENSE_1_0.txt) */ /* ================================= Win32 ============================ */ #if _WIN32 #if _MSC_VER || __MINGW64__ #include #include const char* _data_start__; const char* _data_end__; const char* _bss_start__; const char* _bss_end__; EXTERN_C IMAGE_DOS_HEADER __ImageBase; static void init_data_seg(void) { // Get handle to this module (.exe/.dll) HMODULE hModule = (HMODULE) &__ImageBase; char* imageBase = (char*) hModule; // Get the DOS header PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER) hModule; // Get the address of the NT headers PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS) (imageBase + pDosHeader->e_lfanew); // After the NT headers comes the sections table PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER) (pNtHeaders + 1); // Iterate over all sections for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++) { BYTE* name = pSectionHeader->Name; if (memcmp(name, ".data", 6) == 0) { _data_start__ = imageBase + pSectionHeader->VirtualAddress; _data_end__ = _data_start__ + pSectionHeader->Misc.VirtualSize; } else if (memcmp(name, ".bss", 5) == 0) { _bss_start__ = imageBase + pSectionHeader->VirtualAddress; _bss_end__ = _bss_start__ + pSectionHeader->Misc.VirtualSize; } pSectionHeader++; } } typedef int (__cdecl *_PF)(void); static int __cdecl ctor(void) { init_data_seg(); return 0; } static int __cdecl dtor(void) { return 0; } #pragma data_seg(push) #pragma section(".CRT$XIY", long, read) #pragma section(".CRT$XTY", long, read) #pragma data_seg(".CRT$XIY") __declspec(allocate(".CRT$XIY")) static _PF _ctor = &ctor; #pragma data_seg(".CRT$XTY") __declspec(allocate(".CRT$XTY")) static _PF _dtor = &dtor; #pragma data_seg(pop) /********************************************************* * Windows before Windows 8.1 does not support TLS alignment to anything * higher than 8/16 bytes for Win32 and Win64, respectively. * Some optimizations in LLVM (e.g. using aligned XMM access) do require * higher alignments, though. In addition, the programmer can use align() * to specify even larger requirements. * Fixing the alignment is done by adding a TLS callback that allocates * a new copy of the TLS segment if the current one is not aligned properly. */ __declspec(thread) void* originalTLS; // saves the address of the original TLS to restore it before termination extern void** GetTlsEntryAdr(); BOOL WINAPI fix_tlsAlignment(HINSTANCE hModule, DWORD fdwReason, LPVOID lpvReserved) { if (fdwReason == DLL_PROCESS_DETACH || fdwReason == DLL_THREAD_DETACH) { if (originalTLS) { // restore original pointer void** tlsAdr = GetTlsEntryAdr(); void* allocAdr = ((void**) *tlsAdr)[-1]; *tlsAdr = originalTLS; HeapFree(GetProcessHeap(), 0, allocAdr); } } else { // crawl through the image to find the TLS alignment char* imageBase = (char*) hModule; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER) hModule; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS) (imageBase + pDosHeader->e_lfanew); PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER) (pNtHeaders + 1); PIMAGE_DATA_DIRECTORY dataDir = pNtHeaders->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_TLS; if (dataDir->VirtualAddress) // any TLS entry { PIMAGE_TLS_DIRECTORY tlsDir = (PIMAGE_TLS_DIRECTORY) (imageBase + dataDir->VirtualAddress); int alignShift = ((tlsDir->Characteristics >> 20) & 0xf); if (alignShift) { int alignmentMask = (1 << (alignShift - 1)) - 1; void** tlsAdr = GetTlsEntryAdr(); if ((SIZE_T)*tlsAdr & alignmentMask) { // this implementation does about the same as Windows 8.1. HANDLE heap = GetProcessHeap(); SIZE_T tlsSize = tlsDir->EndAddressOfRawData - tlsDir->StartAddressOfRawData + tlsDir->SizeOfZeroFill; SIZE_T allocSize = tlsSize + alignmentMask + sizeof(void*); void* p = HeapAlloc(heap, 0, allocSize); if (!p) return 0; void* aligned = (void*) (((SIZE_T) p + alignmentMask + sizeof(PVOID)) & ~alignmentMask); void* old = *tlsAdr; ((void**) aligned)[-1] = p; // save base pointer for freeing memcpy(aligned, old, tlsSize); *tlsAdr = aligned; originalTLS = old; } } } } return 1; } // the C++ TLS callbacks are written to ".CRT$XLC", but actually start after ".CRT$XLA". // Using ".CRT$XLB" allows this to come first in the array of TLS callbacks. This // guarantees that pointers saved within C++ TLS callbacks are not pointing into // abandoned memory typedef BOOL WINAPI _TLSCB(HINSTANCE, DWORD, LPVOID); #pragma data_seg(push) #pragma section(".CRT$XLB", long, read) #pragma data_seg(".CRT$XLB") __declspec(allocate(".CRT$XLB")) static _TLSCB* _pfix_tls = &fix_tlsAlignment; #pragma data_seg(pop) #endif #endif // _WIN32 ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/arm_unwind.c0000664000175000017500000000170712776214756021330 0ustar kaikai/** * Shims for libunwind macros on ARM. * * It would be possible to reimplement those entirely in D, but to avoid * an unmaintainable amount of dependencies on internal implementation details, * we use the C versions instead. * * Copyright: David Nadlinger, 2012. * License: Boost License 1.0. * Authors: David Nadlinger */ #ifdef __ARM_EABI__ #include // clang's unwind.h doesn't have this typedef struct _Unwind_Context _Unwind_Context; _Unwind_Word _d_eh_GetIP(_Unwind_Context *context) { return _Unwind_GetIP(context); } void _d_eh_SetIP(_Unwind_Context *context, _Unwind_Word new_value) { _Unwind_SetIP(context, new_value); } _Unwind_Word _d_eh_GetGR(_Unwind_Context *context, int index) { return _Unwind_GetGR(context, index); } void _d_eh_SetGR(_Unwind_Context *context, int index, _Unwind_Word new_value) { _Unwind_SetGR(context, index, new_value); } #endif ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/llvmasm.di0000664000175000017500000000062512776214756021010 0ustar kaikaimodule ldc.llvmasm; struct __asmtuple_t(T...) { T v; } pragma(LDC_inline_asm) { void __asm()(const(char)[] asmcode, const(char)[] constraints, ...) pure nothrow @nogc; T __asm(T)(const(char)[] asmcode, const(char)[] constraints, ...) pure nothrow @nogc; template __asmtuple(T...) { __asmtuple_t!(T) __asmtuple(const(char)[] asmcode, const(char)[] constraints, ...); } } ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/attributes.d0000664000175000017500000001205312776214756021350 0ustar kaikai/** * Contains compiler-recognized user-defined attribute types. * * Copyright: Authors 2015-2016 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: David Nadlinger, Johan Engelen */ module ldc.attributes; /// Helper template private template AliasSeq(TList...) { alias AliasSeq = TList; } /** * Explicitly sets "fast math" for a function, enabling aggressive math * optimizations. These optimizations may dramatically change the outcome of * floating point calculations (e.g. because of reassociation). * * Example: * --- * import ldc.attributes; * * @fastmath * double dot(double[] a, double[] b) { * double s = 0; * foreach(size_t i; 0..a.length) * { * // will result in vectorized fused-multiply-add instructions * s += a * b; * } * return s; * } * --- */ alias fastmath = AliasSeq!(llvmAttr("unsafe-fp-math", "true"), llvmFastMathFlag("fast")); /** * Sets the optimization strategy for a function. * Valid strategies are "none", "optsize", "minsize". The strategies are mutually exclusive. * * @optStrategy("none") in particular is useful to selectively debug functions when a * fully unoptimized program cannot be used (e.g. due to too low performance). * * Strategy "none": * Disables most optimizations for a function. * It implies `pragma(inline, false)`: the function is never inlined * in a calling function, and the attribute cannot be combined with * `pragma(inline, true)`. * Functions with `pragma(inline, true)` are still candidates for inlining into * the function. * * Strategy "optsize": * Tries to keep the code size of the function low and does optimizations to * reduce code size as long as they do not significantly impact runtime performance. * * Strategy "minsize": * Tries to keep the code size of the function low and does optimizations to * reduce code size that may reduce runtime performance. */ struct optStrategy { string strategy; } /** * Adds an LLVM attribute to a function, without checking the validity or * applicability of the attribute. * The attribute is specified as key-value pair: * @llvmAttr("key", "value") * If the value string is empty, just the key is added as attribute. * * Example: * --- * import ldc.attributes; * * @llvmAttr("unsafe-fp-math", "true") * double dot(double[] a, double[] b) { * double s = 0; * foreach(size_t i; 0..a.length) * { * s = inlineIR!(` * %p = fmul fast double %0, %1 * %r = fadd fast double %p, %2 * ret double %r`, double)(a[i], b[i], s); * } * return s; * } * --- */ struct llvmAttr { string key; string value; } /** * Sets LLVM's fast-math flags for floating point operations in the function * this attribute is applied to. * See LLVM LangRef for possible values: * http://llvm.org/docs/LangRef.html#fast-math-flags * @llvmFastMathFlag("clear") clears all flags. */ struct llvmFastMathFlag { string flag; } /** * When applied to a global variable or function, causes it to be emitted to a * non-standard object file/executable section. * * The target platform might impose certain restrictions on the format for * section names. * * Examples: * --- * import ldc.attributes; * * @section(".mySection") int myGlobal; * --- */ struct section { string name; } /** * When applied to a function, specifies that the function should be compiled * with different target options than on the command line. * * The passed string should be a comma-separated list of options. The options * are passed to LLVM by adding them to the "target-features" function * attribute, after minor processing: negative options (e.g. "no-sse") have the * "no" stripped (--> "-sse"), whereas positive options (e.g. sse") gain a * leading "+" (--> "+sse"). Negative options override positive options * regardless of their order. * The "arch=" option is a special case and is passed to LLVM via the * "target-cpu" function attribute. * * Examples: * --- * import ldc.attributes; * * @target("no-sse") * void foo_nosse(float *A, float* B, float K, uint n) { * for (int i = 0; i < n; ++i) * A[i] *= B[i] + K; * } * @target("arch=haswell") * void foo_haswell(float *A, float* B, float K, uint n) { * for (int i = 0; i < n; ++i) * A[i] *= B[i] + K; * } * --- */ struct target { string specifier; } /++ + When applied to a global symbol, specifies that the symbol should be emitted + with weak linkage. An example use case is a library function that should be + overridable by user code. + + Quote from the LLVM manual: "Note that weak linkage does not actually allow + the optimizer to inline the body of this function into callers because it + doesn’t know if this definition of the function is the definitive definition + within the program or whether it will be overridden by a stronger + definition." + + Examples: + --- + import ldc.attributes; + + @weak int user_hook() { return 1; } + --- +/ immutable weak = _weak(); private struct _weak {} ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/intrinsics.di0000664000175000017500000004324712776214756021531 0ustar kaikai/* * This module holds declarations to LLVM intrinsics. * * See the LLVM language reference for more information: * * - http://llvm.org/docs/LangRef.html#intrinsics * */ module ldc.intrinsics; // Check for the right compiler version(LDC) { // OK } else { static assert(false, "This module is only valid for LDC"); } version(LDC_LLVM_306) { version = INTRINSICS_FROM_306; } version(LDC_LLVM_307) { version = INTRINSICS_FROM_306; version = INTRINSICS_FROM_307; } version(LDC_LLVM_308) { version = INTRINSICS_FROM_306; version = INTRINSICS_FROM_307; version = INTRINSICS_FROM_308; } version(LDC_LLVM_309) { version = INTRINSICS_FROM_306; version = INTRINSICS_FROM_307; version = INTRINSICS_FROM_308; version = INTRINSICS_FROM_309; } // All intrinsics are nothrow and @nogc. The codegen intrinsics are not categorized // any further (they probably could), the rest is pure (aborting is fine by // definition; memcpy and friends can be viewed as weakly pure, just as e.g. // strlen() is marked weakly pure as well) and mostly @safe. nothrow: @nogc: // // CODE GENERATOR INTRINSICS // /// The 'llvm.returnaddress' intrinsic attempts to compute a target-specific /// value indicating the return address of the current function or one of its /// callers. pragma(LDC_intrinsic, "llvm.returnaddress") void* llvm_returnaddress(uint level); /// The 'llvm.frameaddress' intrinsic attempts to return the target-specific /// frame pointer value for the specified stack frame. pragma(LDC_intrinsic, "llvm.frameaddress") void* llvm_frameaddress(uint level); /// The 'llvm.stacksave' intrinsic is used to remember the current state of the /// function stack, for use with llvm.stackrestore. This is useful for /// implementing language features like scoped automatic variable sized arrays /// in C99. pragma(LDC_intrinsic, "llvm.stacksave") void* llvm_stacksave(); /// The 'llvm.stackrestore' intrinsic is used to restore the state of the /// function stack to the state it was in when the corresponding llvm.stacksave /// intrinsic executed. This is useful for implementing language features like /// scoped automatic variable sized arrays in C99. pragma(LDC_intrinsic, "llvm.stackrestore") void llvm_stackrestore(void* ptr); /// The 'llvm.prefetch' intrinsic is a hint to the code generator to insert a /// prefetch instruction if supported; otherwise, it is a noop. Prefetches have /// no effect on the behavior of the program but can change its performance /// characteristics. /// ptr is the address to be prefetched, rw is the specifier determining if the /// fetch should be for a read (0) or write (1), and locality is a temporal /// locality specifier ranging from (0) - no locality, to (3) - extremely local /// keep in cache. The cache type specifies whether the prefetch is performed on /// the data (1) or instruction (0) cache. The rw, locality and cache type /// arguments must be constant integers. pragma(LDC_intrinsic, "llvm.prefetch") void llvm_prefetch(void* ptr, uint rw, uint locality, uint cachetype); /// The 'llvm.pcmarker' intrinsic is a method to export a Program Counter (PC) /// in a region of code to simulators and other tools. The method is target /// specific, but it is expected that the marker will use exported symbols to /// transmit the PC of the marker. The marker makes no guarantees that it will /// remain with any specific instruction after optimizations. It is possible /// that the presence of a marker will inhibit optimizations. The intended use /// is to be inserted after optimizations to allow correlations of simulation /// runs. pragma(LDC_intrinsic, "llvm.pcmarker") void llvm_pcmarker(uint id); /// The 'llvm.readcyclecounter' intrinsic provides access to the cycle counter /// register (or similar low latency, high accuracy clocks) on those targets that /// support it. On X86, it should map to RDTSC. On Alpha, it should map to RPCC. /// As the backing counters overflow quickly (on the order of 9 seconds on /// alpha), this should only be used for small timings. pragma(LDC_intrinsic, "llvm.readcyclecounter") ulong llvm_readcyclecounter(); // Backwards compatibility - but it is doubtful whether somebody actually ever // used that intrinsic. alias llvm_readcyclecounter readcyclecounter; /// The 'llvm.clear_cache' intrinsic ensures visibility of modifications in the /// specified range to the execution unit of the processor. On targets with /// non-unified instruction and data cache, the implementation flushes the /// instruction cache. /// On platforms with coherent instruction and data caches (e.g. x86), this /// intrinsic is a nop. On platforms with non-coherent instruction and data /// cache (e.g. ARM, MIPS), the intrinsic is lowered either to appropriate /// instructions or a system call, if cache flushing requires special privileges. /// /// The default behavior is to emit a call to __clear_cache from the run time library. /// /// This instrinsic does not empty the instruction pipeline. Modifications of /// the current function are outside the scope of the intrinsic. pragma(LDC_intrinsic, "llvm.clear_cache") void llvm_clear_cache(void *from, void *to); // // STANDARD C LIBRARY INTRINSICS // pure: /// The 'llvm.memcpy.*' intrinsics copy a block of memory from the source /// location to the destination location. /// Note that, unlike the standard libc function, the llvm.memcpy.* intrinsics do /// not return a value, and takes an extra alignment argument. pragma(LDC_intrinsic, "llvm.memcpy.p0i8.p0i8.i#") void llvm_memcpy(T)(void* dst, void* src, T len, uint alignment, bool volatile_ = false); /// The 'llvm.memmove.*' intrinsics move a block of memory from the source /// location to the destination location. It is similar to the 'llvm.memcpy' /// intrinsic but allows the two memory locations to overlap. /// Note that, unlike the standard libc function, the llvm.memmove.* intrinsics /// do not return a value, and takes an extra alignment argument. pragma(LDC_intrinsic, "llvm.memmove.p0i8.p0i8.i#") void llvm_memmove(T)(void* dst, void* src, T len, uint alignment, bool volatile_ = false); /// The 'llvm.memset.*' intrinsics fill a block of memory with a particular byte /// value. /// Note that, unlike the standard libc function, the llvm.memset intrinsic does /// not return a value, and takes an extra alignment argument. pragma(LDC_intrinsic, "llvm.memset.p0i8.i#") void llvm_memset(T)(void* dst, ubyte val, T len, uint alignment, bool volatile_ = false); @safe: /// The 'llvm.sqrt' intrinsics return the sqrt of the specified operand, /// returning the same value as the libm 'sqrt' functions would. Unlike sqrt in /// libm, however, llvm.sqrt has undefined behavior for negative numbers other /// than -0.0 (which allows for better optimization, because there is no need to /// worry about errno being set). llvm.sqrt(-0.0) is defined to return -0.0 like /// IEEE sqrt. pragma(LDC_intrinsic, "llvm.sqrt.f#") T llvm_sqrt(T)(T val); /// The 'llvm.sin.*' intrinsics return the sine of the operand. pragma(LDC_intrinsic, "llvm.sin.f#") T llvm_sin(T)(T val); /// The 'llvm.cos.*' intrinsics return the cosine of the operand. pragma(LDC_intrinsic, "llvm.cos.f#") T llvm_cos(T)(T val); /// The 'llvm.powi.*' intrinsics return the first operand raised to the specified /// (positive or negative) power. The order of evaluation of multiplications is /// not defined. When a vector of floating point type is used, the second /// argument remains a scalar integer value. pragma(LDC_intrinsic, "llvm.powi.f#") T llvm_powi(T)(T val, int power); /// The 'llvm.pow.*' intrinsics return the first operand raised to the specified /// (positive or negative) power. pragma(LDC_intrinsic, "llvm.pow.f#") T llvm_pow(T)(T val, T power); /// The 'llvm.exp.*' intrinsics perform the exp function. pragma(LDC_intrinsic, "llvm.exp.f#") T llvm_exp(T)(T val); /// The 'llvm.log.*' intrinsics perform the log function. pragma(LDC_intrinsic, "llvm.log.f#") T llvm_log(T)(T val); /// The 'llvm.fma.*' intrinsics perform the fused multiply-add operation. pragma(LDC_intrinsic, "llvm.fma.f#") T llvm_fma(T)(T vala, T valb, T valc); /// The 'llvm.fabs.*' intrinsics return the absolute value of the operand. pragma(LDC_intrinsic, "llvm.fabs.f#") T llvm_fabs(T)(T val); /// The 'llvm.floor.*' intrinsics return the floor of the operand. pragma(LDC_intrinsic, "llvm.floor.f#") T llvm_floor(T)(T val); /// The 'llvm.exp2.*' intrinsics perform the exp2 function. pragma(LDC_intrinsic, "llvm.exp2.f#") T llvm_exp2(T)(T val); /// The 'llvm.log10.*' intrinsics perform the log10 function. pragma(LDC_intrinsic, "llvm.log10.f#") T llvm_log10(T)(T val); /// The 'llvm.log2.*' intrinsics perform the log2 function. pragma(LDC_intrinsic, "llvm.log2.f#") T llvm_log2(T)(T val); /// The 'llvm.ceil.*' intrinsics return the ceiling of the operand. pragma(LDC_intrinsic, "llvm.ceil.f#") T llvm_ceil(T)(T val); /// The 'llvm.trunc.*' intrinsics returns the operand rounded to the nearest integer not larger in magnitude than the operand. pragma(LDC_intrinsic, "llvm.trunc.f#") T llvm_trunc(T)(T val); /// The 'llvm.rint.*' intrinsics returns the operand rounded to the nearest integer. It may raise an inexact floating-point exception if the operand isn't an integer. pragma(LDC_intrinsic, "llvm.rint.f#") T llvm_rint(T)(T val); /// The 'llvm.nearbyint.*' intrinsics returns the operand rounded to the nearest integer. pragma(LDC_intrinsic, "llvm.nearbyint.f#") T llvm_nearbyint(T)(T val); /// The 'llvm.copysign.*' intrinsics return a value with the magnitude of the first operand and the sign of the second operand. pragma(LDC_intrinsic, "llvm.copysign.f#") T llvm_copysign(T)(T mag, T sgn); /// The 'llvm.round.*' intrinsics returns the operand rounded to the nearest integer. pragma(LDC_intrinsic, "llvm.round.f#") T llvm_round(T)(T val); /// The 'llvm.fmuladd.*' intrinsic functions represent multiply-add expressions /// that can be fused if the code generator determines that the fused expression /// would be legal and efficient. pragma(LDC_intrinsic, "llvm.fmuladd.f#") T llvm_fmuladd(T)(T vala, T valb, T valc); version(INTRINSICS_FROM_306) { /// The ‘llvm.minnum.*‘ intrinsics return the minimum of the two arguments. /// Follows the IEEE-754 semantics for minNum, which also match for libm’s fmin. /// If either operand is a NaN, returns the other non-NaN operand. Returns NaN /// only if both operands are NaN. If the operands compare equal, returns a value /// that compares equal to both operands. This means that fmin(+/-0.0, +/-0.0) /// could return either -0.0 or 0.0. pragma(LDC_intrinsic, "llvm.minnum.f#") T llvm_minnum(T)(T vala, T valb); /// The ‘llvm.maxnum.*‘ intrinsics return the maximum of the two arguments. /// Follows the IEEE-754 semantics for maxNum, which also match for libm’s fmax. /// If either operand is a NaN, returns the other non-NaN operand. Returns NaN /// only if both operands are NaN. If the operands compare equal, returns a value /// that compares equal to both operands. This means that fmax(+/-0.0, +/-0.0) /// could return either -0.0 or 0.0. pragma(LDC_intrinsic, "llvm.maxnum.f#") T llvm_maxnum(T)(T vala, T valb); } // // BIT MANIPULATION INTRINSICS // version(INTRINSICS_FROM_309) { /// The 'llvm.bitreverse' family of intrinsics is used to reverse the bitpattern /// of an integer value; for example 0b10110110 becomes 0b01101101. pragma(LDC_intrinsic, "llvm.bitreverse.i#") T llvm_bitreverse(T)(T val); } /// The 'llvm.bswap' family of intrinsics is used to byte swap integer values /// with an even number of bytes (positive multiple of 16 bits). These are /// useful for performing operations on data that is not in the target's native /// byte order. pragma(LDC_intrinsic, "llvm.bswap.i#") T llvm_bswap(T)(T val); /// The 'llvm.ctpop' family of intrinsics counts the number of bits set in a /// value. pragma(LDC_intrinsic, "llvm.ctpop.i#") T llvm_ctpop(T)(T src); /// The 'llvm.ctlz' family of intrinsic functions counts the number of leading /// zeros in a variable. pragma(LDC_intrinsic, "llvm.ctlz.i#") T llvm_ctlz(T)(T src, bool isZeroUndefined); /// The 'llvm.cttz' family of intrinsic functions counts the number of trailing /// zeros. pragma(LDC_intrinsic, "llvm.cttz.i#") T llvm_cttz(T)(T src, bool isZeroUndefined); // // ATOMIC OPERATIONS AND SYNCHRONIZATION INTRINSICS // enum AtomicOrdering { NotAtomic = 0, Unordered = 1, Monotonic = 2, Consume = 3, Acquire = 4, Release = 5, AcquireRelease = 6, SequentiallyConsistent = 7 }; alias AtomicOrdering.SequentiallyConsistent DefaultOrdering; enum AtomicRmwSizeLimit = size_t.sizeof; /// Used to introduce happens-before edges between operations. pragma(LDC_fence) void llvm_memory_fence(AtomicOrdering ordering = DefaultOrdering); /// Atomically loads and returns a value from memory at ptr. pragma(LDC_atomic_load) T llvm_atomic_load(T)(in shared T* ptr, AtomicOrdering ordering = DefaultOrdering); /// Atomically stores val in memory at ptr. pragma(LDC_atomic_store) void llvm_atomic_store(T)(T val, shared T* ptr, AtomicOrdering ordering = DefaultOrdering); /// Loads a value from memory at ptr and compares it to cmp. /// If they are equal, it stores val in memory at ptr. /// Returns the previous value in memory. /// This is all performed as single atomic operation. pragma(LDC_atomic_cmp_xchg) T llvm_atomic_cmp_xchg(T)(shared T* ptr, T cmp, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr = val and returns the previous *ptr value. pragma(LDC_atomic_rmw, "xchg") T llvm_atomic_rmw_xchg(T)(shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr += val and returns the previous *ptr value. pragma(LDC_atomic_rmw, "add") T llvm_atomic_rmw_add(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr -= val and returns the previous *ptr value. pragma(LDC_atomic_rmw, "sub") T llvm_atomic_rmw_sub(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr &= val and returns the previous *ptr value. pragma(LDC_atomic_rmw, "and") T llvm_atomic_rmw_and(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr = ~(*ptr & val) and returns the previous *ptr value. pragma(LDC_atomic_rmw, "nand") T llvm_atomic_rmw_nand(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr |= val and returns the previous *ptr value. pragma(LDC_atomic_rmw, "or") T llvm_atomic_rmw_or(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr ^= val and returns the previous *ptr value. pragma(LDC_atomic_rmw, "xor") T llvm_atomic_rmw_xor(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr = (*ptr > val ? *ptr : val) using a signed comparison. /// Returns the previous *ptr value. pragma(LDC_atomic_rmw, "max") T llvm_atomic_rmw_max(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr = (*ptr < val ? *ptr : val) using a signed comparison. /// Returns the previous *ptr value. pragma(LDC_atomic_rmw, "min") T llvm_atomic_rmw_min(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr = (*ptr > val ? *ptr : val) using an unsigned comparison. /// Returns the previous *ptr value. pragma(LDC_atomic_rmw, "umax") T llvm_atomic_rmw_umax(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); /// Atomically sets *ptr = (*ptr < val ? *ptr : val) using an unsigned comparison. /// Returns the previous *ptr value. pragma(LDC_atomic_rmw, "umin") T llvm_atomic_rmw_umin(T)(in shared T* ptr, T val, AtomicOrdering ordering = DefaultOrdering); // // ARITHMETIC-WITH-OVERFLOW INTRINSICS // /// struct OverflowRet(T) { static assert((is(ucent) && is(T : cent)) || is(T : long), T.stringof ~ " is not an integer type!"); T result; /// bool overflow; /// } /// Signed addition pragma(LDC_intrinsic, "llvm.sadd.with.overflow.i#") OverflowRet!(T) llvm_sadd_with_overflow(T)(T lhs, T rhs); /// Unsigned addition pragma(LDC_intrinsic, "llvm.uadd.with.overflow.i#") OverflowRet!(T) llvm_uadd_with_overflow(T)(T lhs, T rhs); /// ditto /// Signed subtraction pragma(LDC_intrinsic, "llvm.ssub.with.overflow.i#") OverflowRet!(T) llvm_ssub_with_overflow(T)(T lhs, T rhs); /// Unsigned subtraction pragma(LDC_intrinsic, "llvm.usub.with.overflow.i#") OverflowRet!(T) llvm_usub_with_overflow(T)(T lhs, T rhs); /// ditto /// Signed multiplication pragma(LDC_intrinsic, "llvm.smul.with.overflow.i#") OverflowRet!(T) llvm_smul_with_overflow(T)(T lhs, T rhs); /// Unsigned multiplication pragma(LDC_intrinsic, "llvm.umul.with.overflow.i#") OverflowRet!(T) llvm_umul_with_overflow(T)(T lhs, T rhs); // // GENERAL INTRINSICS // /// This intrinsics is lowered to the target dependent trap instruction. If the /// target does not have a trap instruction, this intrinsic will be lowered to /// the call of the abort() function. pragma(LDC_intrinsic, "llvm.trap") void llvm_trap(); /// This intrinsic is lowered to code which is intended to cause an execution /// trap with the intention of requesting the attention of a debugger. pragma(LDC_intrinsic, "llvm.debugtrap") void llvm_debugtrap(); /// The llvm.expect intrinsic provides information about expected (the most /// probable) value of val, which can be used by optimizers. /// The llvm.expect intrinsic takes two arguments. The first argument is a /// value. The second argument is an expected value, this needs to be a /// constant value, variables are not allowed. pragma(LDC_intrinsic, "llvm.expect.i#") T llvm_expect(T)(T val, T expected_val) if (__traits(isIntegral, T)); ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/arrayinit.d0000664000175000017500000000565012776214756021171 0ustar kaikaimodule ldc.arrayinit; private import ldc.intrinsics; extern(C): int memcmp(void*,void*,size_t); size_t strlen(char*); // per-element array init routines void _d_array_init_i16(ushort* a, size_t n, ushort v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_i32(uint* a, size_t n, uint v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_i64(ulong* a, size_t n, ulong v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_float(float* a, size_t n, float v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_double(double* a, size_t n, double v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_real(real* a, size_t n, real v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_cfloat(cfloat* a, size_t n, cfloat v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_cdouble(cdouble* a, size_t n, cdouble v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_creal(creal* a, size_t n, creal v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_pointer(void** a, size_t n, void* v) { auto p = a; auto end = a+n; while (p !is end) *p++ = v; } void _d_array_init_mem(void* a, size_t na, void* v, size_t nv) { auto p = a; auto end = a + na*nv; while (p !is end) { llvm_memcpy(p,v,nv,0); p += nv; } } /* void _d_array_init(TypeInfo ti, void* a) { auto initializer = ti.next.init(); auto isize = initializer.length; auto q = initializer.ptr; if (isize == 1) memset(p, *cast(ubyte*)q, size); else if (isize == int.sizeof) { int init = *cast(int*)q; size /= int.sizeof; for (size_t u = 0; u < size; u++) { (cast(int*)p)[u] = init; } } else { for (size_t u = 0; u < size; u += isize) { memcpy(p + u, q, isize); } } }*/ // for array cast size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz) { if (newelemsz == 1) { return len*elemsz; } else if ((len*elemsz) % newelemsz) { throw new Exception("Bad array cast"); } return (len*elemsz)/newelemsz; } // slice copy when assertions are enabled void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen) { if (dstlen != 0) assert(dst); if (dstlen != 0) assert(src); if (dstlen != srclen) throw new Exception("lengths don't match for array copy"); else if (dst+dstlen <= src || src+srclen <= dst) llvm_memcpy!size_t(dst, src, dstlen, 0); else throw new Exception("overlapping array copy"); } ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/eh/0000775000175000017500000000000012776214756017410 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/ldc/eh/msvc.d0000664000175000017500000004557412776214756020544 0ustar kaikai/** * This module implements the runtime-part of LDC exceptions * on Windows, based on the MSVC++ runtime. */ module ldc.eh.msvc; version(CRuntime_Microsoft): import ldc.eh.common; import core.sys.windows.windows; import core.exception : onOutOfMemoryError, OutOfMemoryError; import core.stdc.stdlib : malloc, free; import core.stdc.string : memcpy; import rt.util.container.common : xmalloc; // pointers are image relative for Win64 versions version(Win64) struct ImgPtr(T) { uint offset; } // offset into image else alias ImgPtr(T) = T*; alias PMFN = ImgPtr!(void function(void*)); struct TypeDescriptor { version(_RTTI) const void * pVFTable; // Field overloaded by RTTI else uint hash; // Hash value computed from type's decorated name void * spare; // reserved, possible for RTTI char[1] name; // variable size, zero terminated } struct PMD { int mdisp; // Offset of intended data within base int pdisp; // Displacement to virtual base pointer int vdisp; // Index within vbTable to offset of base } struct CatchableType { uint properties; // Catchable Type properties (Bit field) ImgPtr!TypeDescriptor pType; // Pointer to TypeDescriptor PMD thisDisplacement; // Pointer to instance of catch type within thrown object. int sizeOrOffset; // Size of simple-type object or offset into buffer of 'this' pointer for catch object PMFN copyFunction; // Copy constructor or CC-closure } enum CT_IsSimpleType = 0x00000001; // type is a simple type (includes pointers) enum CT_ByReferenceOnly = 0x00000002; // type must be caught by reference enum CT_HasVirtualBase = 0x00000004; // type is a class with virtual bases enum CT_IsWinRTHandle = 0x00000008; // type is a winrt handle enum CT_IsStdBadAlloc = 0x00000010; // type is a a std::bad_alloc struct CatchableTypeArray { int nCatchableTypes; ImgPtr!CatchableType[1] arrayOfCatchableTypes; // variable size } struct _ThrowInfo { uint attributes; // Throw Info attributes (Bit field) PMFN pmfnUnwind; // Destructor to call when exception has been handled or aborted. PMFN pForwardCompat; // pointer to Forward compatibility frame handler ImgPtr!CatchableTypeArray pCatchableTypeArray; // pointer to CatchableTypeArray } enum TI_IsConst = 0x00000001; // thrown object has const qualifier enum TI_IsVolatile = 0x00000002; // thrown object has volatile qualifier enum TI_IsUnaligned = 0x00000004; // thrown object has unaligned qualifier enum TI_IsPure = 0x00000008; // object thrown from a pure module enum TI_IsWinRT = 0x00000010; // object thrown is a WinRT Exception extern(Windows) void RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, ULONG_PTR* lpArguments); enum int STATUS_MSC_EXCEPTION = 0xe0000000 | ('m' << 16) | ('s' << 8) | ('c' << 0); enum EXCEPTION_NONCONTINUABLE = 0x01; enum EXCEPTION_UNWINDING = 0x02; enum EH_MAGIC_NUMBER1 = 0x19930520; struct CxxExceptionInfo { size_t Magic; Throwable* pThrowable; // null for rethrow _ThrowInfo* ThrowInfo; version(Win64) void* ImgBase; } extern(C) void _d_throw_exception(Object e) { if (e is null) fatalerror("Cannot throw null exception"); auto ti = typeid(e); if (ti is null) fatalerror("Cannot throw corrupt exception object with null classinfo"); if (exceptionStack.length > 0) { // we expect that the terminate handler will be called, so hook // it to avoid it actually terminating if (!old_terminate_handler) old_terminate_handler = set_terminate(&msvc_eh_terminate); } auto t = cast(Throwable) e; exceptionStack.push(t); CxxExceptionInfo info; info.Magic = EH_MAGIC_NUMBER1; info.pThrowable = &t; info.ThrowInfo = getThrowInfo(ti).toPointer; version(Win64) info.ImgBase = ehHeap.base; RaiseException(STATUS_MSC_EXCEPTION, EXCEPTION_NONCONTINUABLE, info.sizeof / size_t.sizeof, cast(ULONG_PTR*)&info); } /////////////////////////////////////////////////////////////// import rt.util.container.hashtab; import core.sync.mutex; __gshared HashTab!(TypeInfo_Class, ImgPtr!_ThrowInfo) throwInfoHashtab; __gshared HashTab!(TypeInfo_Class, ImgPtr!CatchableType) catchableHashtab; __gshared Mutex throwInfoMutex; // create and cache throwinfo for ti ImgPtr!_ThrowInfo getThrowInfo(TypeInfo_Class ti) { throwInfoMutex.lock(); if (auto p = ti in throwInfoHashtab) { throwInfoMutex.unlock(); return *p; } int classes = 0; for (TypeInfo_Class tic = ti; tic; tic = tic.base) classes++; size_t sz = int.sizeof + classes * ImgPtr!(CatchableType).sizeof; ImgPtr!CatchableTypeArray cta = eh_malloc!CatchableTypeArray(sz); toPointer(cta).nCatchableTypes = classes; size_t c = 0; for (TypeInfo_Class tic = ti; tic; tic = tic.base) cta.toPointer.arrayOfCatchableTypes.ptr[c++] = getCatchableType(tic); auto tinf = eh_malloc!_ThrowInfo(); *(tinf.toPointer) = _ThrowInfo(0, PMFN(), PMFN(), cta); throwInfoHashtab[ti] = tinf; throwInfoMutex.unlock(); return tinf; } ImgPtr!CatchableType getCatchableType(TypeInfo_Class ti) { if (auto p = ti in catchableHashtab) return *p; size_t sz = TypeDescriptor.sizeof + ti.name.length; auto td = eh_malloc!TypeDescriptor(sz); auto ptd = td.toPointer; ptd.hash = 0; ptd.spare = null; ptd.name.ptr[0] = 'D'; memcpy(ptd.name.ptr + 1, ti.name.ptr, ti.name.length); ptd.name.ptr[ti.name.length + 1] = 0; auto ct = eh_malloc!CatchableType(); ct.toPointer[0] = CatchableType(CT_IsSimpleType, td, PMD(0, -1, 0), size_t.sizeof, PMFN()); catchableHashtab[ti] = ct; return ct; } /////////////////////////////////////////////////////////////// extern(C) Object _d_eh_enter_catch(void* ptr, ClassInfo catchType) { assert(ptr); // is this a thrown D exception? auto e = *(cast(Throwable*) ptr); size_t pos = exceptionStack.find(e); if (pos >= exceptionStack.length()) return null; auto caught = e; // append inner unhandled thrown exceptions for (size_t p = pos + 1; p < exceptionStack.length(); p++) e = chainExceptions(e, exceptionStack[p]); exceptionStack.shrink(pos); // given the bad semantics of Errors, we are fine with passing // the test suite with slightly inaccurate behaviour by just // rethrowing a collateral Error here, though it might need to // be caught by a catch handler in an inner scope if (e !is caught) { if (_d_isbaseof(typeid(e), catchType)) *cast(Throwable*) ptr = e; // the current catch can also catch this Error else _d_throw_exception(e); } return e; } Throwable chainExceptions(Throwable e, Throwable t) { if (!cast(Error) e) if (auto err = cast(Error) t) { err.bypassedException = e; return err; } auto pChain = &e.next; while (*pChain) pChain = &(pChain.next); *pChain = t; return e; } ExceptionStack exceptionStack; struct ExceptionStack { nothrow: ~this() { if (_p) free(_p); } void push(Throwable e) { if (_length == _cap) grow(); _p[_length++] = e; } Throwable pop() { return _p[--_length]; } void shrink(size_t sz) { while (_length > sz) _p[--_length] = null; } ref inout(Throwable) opIndex(size_t idx) inout { return _p[idx]; } size_t find(Throwable e) { for (size_t i = _length; i > 0; ) if (exceptionStack[--i] is e) return i; return ~0; } @property size_t length() const { return _length; } @property bool empty() const { return !length; } void swap(ref ExceptionStack other) { static void swapField(T)(ref T a, ref T b) { T o = b; b = a; a = o; } swapField(_length, other._length); swapField(_p, other._p); swapField(_cap, other._cap); } private: void grow() { // alloc from GC? add array as a GC range? immutable ncap = _cap ? 2 * _cap : 64; auto p = cast(Throwable*)xmalloc(ncap * Throwable.sizeof); p[0 .. _length] = _p[0 .. _length]; free(_p); _p = p; _cap = ncap; } size_t _length; Throwable* _p; size_t _cap; } /////////////////////////////////////////////////////////////// alias terminate_handler = void function(); extern(C) terminate_handler set_terminate(terminate_handler new_handler); terminate_handler old_terminate_handler; // explicitely per thread // helper to access TLS from naked asm size_t tlsUncaughtExceptions() nothrow { return exceptionStack.length; } auto tlsOldTerminateHandler() nothrow { return old_terminate_handler; } void msvc_eh_terminate() nothrow { version(Win32) { asm nothrow { naked; call tlsUncaughtExceptions; cmp EAX, 1; jle L_term; // hacking into the call chain to return EXCEPTION_EXECUTE_HANDLER // as the return value of __FrameUnwindFilter so that // __FrameUnwindToState continues with the next unwind block // undo one level of exception frames from terminate() mov EAX,FS:[0]; mov EAX,[EAX]; mov FS:[0], EAX; // assume standard stack frames for callers mov EAX,EBP; // frame pointer of terminate() mov EAX,[EAX]; // frame pointer of __FrameUnwindFilter mov ESP,EAX; // restore stack pop EBP; // and frame pointer mov EAX, 1; // return EXCEPTION_EXECUTE_HANDLER ret; L_term: call tlsOldTerminateHandler; cmp EAX, 0; je L_ret; jmp EAX; L_ret: ret; } } else { asm nothrow { naked; push RBX; // align stack for better debuggability call tlsUncaughtExceptions; cmp RAX, 1; jle L_term; // update stack and IP so we just continue in __FrameUnwindHandler // NOTE: these checks can fail if you have breakpoints set at // the respective code locations mov RAX,[RSP+8]; // get return address cmp byte ptr[RAX], 0xEB; // jmp? jne noJump; movsx RDX, byte ptr[RAX+1]; // follow jmp lea RAX,[RAX+RDX+2]; noJump: cmp byte ptr[RAX], 0xE8; // call abort? jne L_term; add RAX,5; mov EDX,[RAX]; mov RBX, 0xFFFFFF; and RDX, RBX; cmp RDX, 0xC48348; // add ESP,nn (debug UCRT libs) je L_addESP_found; cmp DL, 0x90; // nop; (release libs) jne L_term; L_release_ucrt: mov RDX,[RSP+8]; cmp word ptr[RDX-2], 0xD3FF; // call ebx? sete BL; // if not, it's UCRT 10.0.14393.0 movzx RBX,BL; mov RDX, 0x28; // release build of vcruntimelib jmp L_retTerminate; L_addESP_found: movzx RDX,byte ptr[RAX+3]; // read nn cmp byte ptr [RAX+4], 0xC3; // ret? jne L_term; L_retTerminate: lea RDX,[RSP+RDX+0x10]; // RSP before returning from terminate() mov RAX,[RDX]; // return address inside __FrameUnwindHandler or RDX,RBX; // RDX aligned, save RBX == 0 for UCRT 10.0.14393.0, 1 otherwise cmp byte ptr [RAX-19], 0xEB; // skip back to default jump inside "switch" (libvcruntimed.lib) je L_switchFound; cmp byte ptr [RAX-20], 0xEB; // skip back to default jump inside "switch" (vcruntime140d.dll) je L_switchFound2; mov RBX, 0xc48348c0333048ff; // dec [rax+30h]; xor eax,eax; add rsp,nn (libvcruntime.lib) cmp RBX,[RAX-0x18]; je L_retFound; cmp RBX,[RAX+0x29]; // dec [rax+30h]; xor eax,eax; add rsp,nn (vcruntime140.dll) jne L_term; lea RAX, [RAX+0x2F]; jmp L_xorSkipped; L_retFound: lea RAX, [RAX-19]; jmp L_xorSkipped; L_switchFound2: dec RAX; L_switchFound: movsx RBX, byte ptr [RAX-18]; // follow jump lea RAX, [RAX+RBX-17]; cmp word ptr[RAX],0xC033; // xor EAX,EAX? jne L_term; add RAX,2; L_xorSkipped: mov RBX, RDX; // extract UCRT marker from EDX and RDX, ~1; and RBX, 1; cmovnz RBX,[RDX-8]; // restore RBX (pushed inside terminate()) cmovz RBX,[RSP]; // RBX not changed in terminate inside UCRT 10.0.14393.0 lea RSP,[RDX+8]; push RAX; // new return after setting return value in __frameUnwindHandler call __processing_throw; mov [RAX], 1; //add RSP,0x68; // TODO: needs to be verified for different CRT builds mov RAX,1; // return EXCEPTION_EXECUTE_HANDLER ret; L_term: call tlsOldTerminateHandler; pop RBX; cmp RAX, 0; je L_ret; jmp RAX; L_ret: ret; } } } /////////////////////////////////////////////////////////////// extern(C) void** __current_exception() nothrow; extern(C) void** __current_exception_context() nothrow; extern(C) int* __processing_throw() nothrow; struct FiberContext { ExceptionStack exceptionStack; void* currentException; void* currentExceptionContext; int processingContext; } FiberContext* fiberContext; extern(C) void* _d_eh_swapContext(FiberContext* newContext) nothrow { import core.stdc.string : memset; if (!fiberContext) { fiberContext = cast(FiberContext*) xmalloc(FiberContext.sizeof); memset(fiberContext, 0, FiberContext.sizeof); } fiberContext.exceptionStack.swap(exceptionStack); fiberContext.currentException = *__current_exception(); fiberContext.currentExceptionContext = *__current_exception_context(); fiberContext.processingContext = *__processing_throw(); if (newContext) { exceptionStack.swap(newContext.exceptionStack); *__current_exception() = newContext.currentException; *__current_exception_context() = newContext.currentExceptionContext; *__processing_throw() = newContext.processingContext; } else { exceptionStack = ExceptionStack(); *__current_exception() = null; *__current_exception_context() = null; *__processing_throw() = 0; } FiberContext* old = fiberContext; fiberContext = newContext; return old; } static ~this() { import core.stdc.stdlib : free; if (fiberContext) { destroy(*fiberContext); free(fiberContext); } } /////////////////////////////////////////////////////////////// extern(C) bool _d_enter_cleanup(void* ptr) { // currently just used to avoid that a cleanup handler that can // be inferred to not return, is removed by the LLVM optimizer // // TODO: setup an exception handler here (ptr passes the address // of a 40 byte stack area in a parent fuction scope) to deal with // unhandled exceptions during unwinding. return true; } extern(C) void _d_leave_cleanup(void* ptr) { } /////////////////////////////////////////////////////////////// void msvc_eh_init() { throwInfoMutex = new Mutex; version(Win64) ehHeap.initialize(0x10000); // preallocate type descriptors likely to be needed getThrowInfo(typeid(Exception)); // better not have to allocate when this is thrown: getThrowInfo(typeid(OutOfMemoryError)); } shared static this() { // should be called from rt_init msvc_eh_init(); } /////////////////////////////////////////////////////////////// version(Win32) { ImgPtr!T eh_malloc(T)(size_t size = T.sizeof) { return cast(T*) xmalloc(size); } T* toPointer(T)(T* imgPtr) { return imgPtr; } } else { /** * Heap dedicated for CatchableTypeArray/CatchableType/TypeDescriptor * structs of cached _ThrowInfos. * The heap is used to keep these structs tightly together, as they are * referenced via 32-bit offsets from a common base. We simply use the * heap's start as base (instead of the actual image base), and malloc() * returns an offset. * The allocated structs are all cached and never released, so this heap * can only grow. The offsets remain constant after a grow, so it's only * the base which may change. */ struct EHHeap { void* base; size_t capacity; size_t length; void initialize(size_t initialCapacity) { base = xmalloc(initialCapacity); capacity = initialCapacity; length = size_t.sizeof; // don't use offset 0, it has a special meaning } size_t malloc(size_t size) { auto offset = length; enum alignmentMask = size_t.sizeof - 1; auto newLength = (length + size + alignmentMask) & ~alignmentMask; auto newCapacity = capacity; while (newLength > newCapacity) newCapacity *= 2; if (newCapacity != capacity) { auto newBase = xmalloc(newCapacity); newBase[0 .. length] = base[0 .. length]; // old base just leaks, could be used by exceptions still in flight base = newBase; capacity = newCapacity; } length = newLength; return offset; } } __gshared EHHeap ehHeap; ImgPtr!T eh_malloc(T)(size_t size = T.sizeof) { return ImgPtr!T(cast(uint) ehHeap.malloc(size)); } // NB: The returned pointer may be invalidated by a consequent grow of ehHeap! T* toPointer(T)(ImgPtr!T imgPtr) { return cast(T*) (ehHeap.base + imgPtr.offset); } } ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/eh/common.d0000664000175000017500000006233412776214756021055 0ustar kaikai/** * This module contains functions and structures required for exception * handling which are shared by platform-specific implementations. */ module ldc.eh.common; // debug = EH_personality; // debug = EH_personality_verbose; import core.memory : GC; import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.stdarg; import ldc.eh.fixedpool; version (ARM) { version (iOS) version = SjLj_Exceptions; else version = ARM_EABI_UNWINDER; } // D runtime function extern(C) int _d_isbaseof(ClassInfo oc, ClassInfo c); // error and exit extern(C) void fatalerror(in char* format, ...) { va_list args; va_start(args, format); fprintf(stderr, "Fatal error in EH code: "); vfprintf(stderr, format, args); fprintf(stderr, "\n"); abort(); } version(CRuntime_Microsoft) {} else version = notMSVC; version(notMSVC): // ------------------------ // Reading DWARF data // ------------------------ version (CRuntime_Microsoft) {} else { extern(C) { alias void* _Unwind_Context_Ptr; ptrdiff_t _Unwind_GetRegionStart(_Unwind_Context_Ptr context); ptrdiff_t _Unwind_GetTextRelBase(_Unwind_Context_Ptr context); ptrdiff_t _Unwind_GetDataRelBase(_Unwind_Context_Ptr context); } } enum _DW_EH_Format : int { DW_EH_PE_absptr = 0x00, // The Value is a literal pointer whose size is determined by the architecture. DW_EH_PE_uleb128 = 0x01, // Unsigned value is encoded using the Little Endian Base 128 (LEB128) DW_EH_PE_udata2 = 0x02, // A 2 bytes unsigned value. DW_EH_PE_udata4 = 0x03, // A 4 bytes unsigned value. DW_EH_PE_udata8 = 0x04, // An 8 bytes unsigned value. DW_EH_PE_sleb128 = 0x09, // Signed value is encoded using the Little Endian Base 128 (LEB128) DW_EH_PE_sdata2 = 0x0A, // A 2 bytes signed value. DW_EH_PE_sdata4 = 0x0B, // A 4 bytes signed value. DW_EH_PE_sdata8 = 0x0C, // An 8 bytes signed value. DW_EH_PE_pcrel = 0x10, // Value is relative to the current program counter. DW_EH_PE_textrel = 0x20, // Value is relative to the beginning of the .text section. DW_EH_PE_datarel = 0x30, // Value is relative to the beginning of the .got or .eh_frame_hdr section. DW_EH_PE_funcrel = 0x40, // Value is relative to the beginning of the function. DW_EH_PE_aligned = 0x50, // Value is aligned to an address unit sized boundary. DW_EH_PE_indirect = 0x80, DW_EH_PE_omit = 0xff // Indicates that no value is present. } uint udata4_read(ref ubyte* addr) { // read udata4 from possibly unaligned `addr` import core.stdc.string : memcpy; uint udata4; memcpy(&udata4, addr, udata4.sizeof); addr += udata4.sizeof; return udata4; } ubyte* get_uleb128(ubyte* addr, ref size_t res) { res = 0; size_t bitsize = 0; // read as long as high bit is set while(*addr & 0x80) { res |= (*addr & 0x7f) << bitsize; bitsize += 7; addr += 1; if (bitsize >= size_t.sizeof*8) fatalerror("tried to read uleb128 that exceeded size of size_t"); } // read last if (bitsize != 0 && *addr >= 1L << size_t.sizeof*8 - bitsize) fatalerror("tried to read uleb128 that exceeded size of size_t"); res |= (*addr) << bitsize; return addr + 1; } ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res) { res = 0; size_t bitsize = 0; // read as long as high bit is set while (*addr & 0x80) { res |= (*addr & 0x7f) << bitsize; bitsize += 7; addr += 1; if (bitsize >= size_t.sizeof*8) fatalerror("tried to read sleb128 that exceeded size of size_t"); } // read last if (bitsize != 0 && *addr >= 1L << size_t.sizeof*8 - bitsize) fatalerror("tried to read sleb128 that exceeded size of size_t"); res |= (*addr) << bitsize; // take care of sign if (bitsize < size_t.sizeof*8 && ((*addr) & 0x40)) res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1); return addr + 1; } size_t get_size_of_encoded_value(ubyte encoding) { if (encoding == _DW_EH_Format.DW_EH_PE_omit) return 0; switch (encoding & 0x07) { case _DW_EH_Format.DW_EH_PE_absptr: return size_t.sizeof; case _DW_EH_Format.DW_EH_PE_udata2: return 2; case _DW_EH_Format.DW_EH_PE_udata4: return 4; case _DW_EH_Format.DW_EH_PE_udata8: return 8; default: fatalerror("Unsupported DWARF Exception Header value format: unknown encoding"); } assert(0); } ubyte* get_encoded_value(ubyte* addr, ref size_t res, ubyte encoding, void* context) { ubyte *old_addr = addr; if (encoding == _DW_EH_Format.DW_EH_PE_aligned) goto Lerr; switch (encoding & 0x0f) { case _DW_EH_Format.DW_EH_PE_absptr: res = cast(size_t)*cast(ubyte**)addr; addr += size_t.sizeof; break; case _DW_EH_Format.DW_EH_PE_uleb128: addr = get_uleb128(addr, res); break; case _DW_EH_Format.DW_EH_PE_sleb128: ptrdiff_t r; addr = get_sleb128(addr, r); r = cast(size_t)res; break; case _DW_EH_Format.DW_EH_PE_udata2: res = *cast(ushort*)addr; addr += 2; break; case _DW_EH_Format.DW_EH_PE_udata4: res = *cast(uint*)addr; addr += 4; break; case _DW_EH_Format.DW_EH_PE_udata8: res = cast(size_t)*cast(ulong*)addr; addr += 8; break; case _DW_EH_Format.DW_EH_PE_sdata2: res = *cast(short*)addr; addr += 2; break; case _DW_EH_Format.DW_EH_PE_sdata4: res = *cast(int*)addr; addr += 4; break; case _DW_EH_Format.DW_EH_PE_sdata8: res = cast(size_t)*cast(long*)addr; addr += 8; break; default: goto Lerr; } switch (encoding & 0x70) { case _DW_EH_Format.DW_EH_PE_absptr: break; case _DW_EH_Format.DW_EH_PE_pcrel: res += cast(size_t)old_addr; break; case _DW_EH_Format.DW_EH_PE_funcrel: version(CRuntime_Microsoft) fatalerror("Not yet implemented."); else res += cast(size_t)_Unwind_GetRegionStart(context); break; case _DW_EH_Format.DW_EH_PE_textrel: version(CRuntime_Microsoft) fatalerror("Not yet implemented."); else res += cast(size_t)_Unwind_GetTextRelBase(context); break; case _DW_EH_Format.DW_EH_PE_datarel: version(CRuntime_Microsoft) fatalerror("Not yet implemented."); else res += cast(size_t)_Unwind_GetDataRelBase(context); break; default: goto Lerr; } if (encoding & _DW_EH_Format.DW_EH_PE_indirect) res = cast(size_t)*cast(void**)res; return addr; Lerr: fatalerror("Unsupported DWARF Exception Header value format"); return addr; } ptrdiff_t get_base_of_encoded_value(ubyte encoding, void* context) { if (encoding == _DW_EH_Format.DW_EH_PE_omit) return 0; with (_DW_EH_Format) switch (encoding & 0x70) { case DW_EH_PE_absptr: case DW_EH_PE_pcrel: case DW_EH_PE_aligned: return 0; version(CRuntime_Microsoft) {} else { case DW_EH_PE_textrel: return _Unwind_GetTextRelBase (context); case DW_EH_PE_datarel: return _Unwind_GetDataRelBase (context); case DW_EH_PE_funcrel: return _Unwind_GetRegionStart (context); } default: fatalerror("Unsupported encoding type to get base from."); assert(0); } } void _d_getLanguageSpecificTables(ubyte* data, ref ubyte* callsite, ref ubyte* action, ref ubyte* classinfo_table, ref ubyte ciEncoding) { if (data is null) { debug(EH_personality) printf("language specific data was null\n"); callsite = null; action = null; classinfo_table = null; return; } debug(EH_personality) printf(" - LSDA: %p\n", data); //TODO: Do proper DWARF reading here if (*data++ != _DW_EH_Format.DW_EH_PE_omit) fatalerror("DWARF header has unexpected format 1"); ciEncoding = *data++; if (ciEncoding == _DW_EH_Format.DW_EH_PE_omit) { // Used for simple cleanup actions (finally, dtors) that don't care // about exception type version (SjLj_Exceptions) classinfo_table = null; else fatalerror("Language Specific Data does not contain Types Table"); } else { // Note in libsupc++ eh_personality says it is necessary to override // type encoding generated by older ARM EABI toolchains // (_GLIBCXX_OVERRIDE_TTYPE_ENCODING) version (ARM_EABI_UNWINDER) version (linux) { with (_DW_EH_Format) { ciEncoding = DW_EH_PE_pcrel | DW_EH_PE_indirect; } } size_t cioffset; data = get_uleb128(data, cioffset); classinfo_table = data + cioffset; } if (*data++ != _DW_EH_Format.DW_EH_PE_udata4) fatalerror("DWARF header has unexpected format 2"); size_t callsitelength; data = get_uleb128(data, callsitelength); action = data + callsitelength; callsite = data; debug(EH_personality) printf(" - callsite: %p, action: %p, classinfo_table: %p, ciEncoding: %d\n", callsite, action, classinfo_table, ciEncoding); } // ----------------------------- // Stack of finally blocks // ----------------------------- struct ActiveCleanupBlock { /// Link to the next active finally block. ActiveCleanupBlock* outerBlock; /// The exception that caused this cleanup block to be entered. Object dObject; /// The exception struct associated with the above exception. Currently only /// used by libunwind; define destroyExceptionStruct in your implementation's /// NativeContext code to handle this correctly. void* exceptionStruct; /// The CFA (stack address, roughly) when this cleanup block was entered, as /// reported by libunwind. /// /// Used to determine when this pad is reached again when unwinding from /// somewhere within it. Note that this must somehow be related to the /// stack, not the instruction pointer, to properly support recursive /// chaining. ptrdiff_t cfaAddr; } static FixedPool!(ActiveCleanupBlock, 8) ActiveCleanupBlockPool; /// Stack of active finally blocks (i.e. cleanup landing pads) that were entered /// because of exception unwinding. Used for exception chaining. /// /// Note that sometimes a landing pad is both a catch and a cleanup. This /// happens for example when there is a try/finally nested inside a try/catch /// in the same function, or has been inlined into one. Whether a catch will /// actually execute (which terminates this strand of unwinding) or not is /// determined by the program code and cannot be known inside the personality /// routine. Thus, we always push such a block even before entering a catch(), /// and have the user code call _d_eh_enter_catch() once the (possible) cleanup /// part is done so we can pop it again. In theory, this could be optimized a /// bit, because we only need to do it for landing pads which have this double /// function, which we could possibly figure out form the DWARF tables. However, /// since this makes generating the code for popping it non-trivial, this is not /// currently done. ActiveCleanupBlock* innermostCleanupBlock = null; /// innermostCleanupBlock is per-stack, not per-thread, and as such needs to be /// swapped out on fiber context switches. extern(C) void* _d_eh_swapContext(void* newContext) nothrow { auto old = innermostCleanupBlock; innermostCleanupBlock = cast(ActiveCleanupBlock*)newContext; return old; } /// During the search phase of unwinding, points to the currently active cleanup /// block (i.e. somewhere in the innermostCleanupBlock linked list, but possibly /// not at the beginning if the search for the catch block has already continued /// past that). /// /// Note that this and searchPhaseCurrentCleanupBlock can just be a single /// variable because there can never be more than one search phase running per /// thread. ActiveCleanupBlock* searchPhaseCurrentCleanupBlock = null; /// During the search phase, keeps track of the type of the dynamic type of the /// currently thrown exception (might change according to exception chaining /// rules). ClassInfo searchPhaseClassInfo = null; ActiveCleanupBlock* pushCleanupBlockRecord(ptrdiff_t cfaAddr, Object dObject) { auto acb = ActiveCleanupBlockPool.malloc(); if (!acb) fatalerror("Could not allocate memory for exception chaining."); acb.cfaAddr = cfaAddr; acb.dObject = dObject; acb.outerBlock = innermostCleanupBlock; innermostCleanupBlock = acb; // We need to be sure that an in-flight exception is kept alive while // executing a finally block. This is not automatically the case if the // finally block always throws, because the compiler then does not need to // keep a reference to the object extracted from the landing pad around as // there is no _d_eh_resume_unwind() call. GC.addRoot(cast(void*)dObject); return acb; } void popCleanupBlockRecord() { if (!innermostCleanupBlock) { fatalerror("No cleanup block record found, should have been pushed " ~ "before entering the finally block."); } // Remove the cleanup block we installed for this handler. auto acb = innermostCleanupBlock; GC.removeRoot(cast(void*)acb.dObject); innermostCleanupBlock = acb.outerBlock; ActiveCleanupBlockPool.free(acb); } /// This is the implementation of the personality function, which is called by /// libunwind twice per frame (search phase, unwind phase). /// /// It is responsible to figure out whether we need to stop unwinding because of /// a catch block or if there is a finally block to execute by reading the DWARF /// EH tables. extern(C) auto eh_personality_common(NativeContext)(ref NativeContext nativeContext) { // // First, we need to find the Language-Specific Data table for this frame // and extract our information tables (the "language-specific" part is a bit // of a misnomer, in reality this is generated by LLVM). // // The callsite and action tables do not contain static-length data and will // be parsed as needed. // ubyte* callsite_table; ubyte* action_table; ubyte* classinfo_table; // points past the end of the table ubyte classinfo_table_encoding; ubyte* data = nativeContext.getLanguageSpecificData(); _d_getLanguageSpecificTables(data, callsite_table, action_table, classinfo_table, classinfo_table_encoding); if (!callsite_table) return nativeContext.continueUnwind(); // // Now, we need to figure out if the address of the current instruction // in this frame corresponds to a block which has an associated landing pad. // // The table entries are all relative to the start address of the region. immutable ptrdiff_t region_start = nativeContext.getRegionStart(); // The address of the landing pad to jump to (null if no match). ptrdiff_t landingPadAddr; // The offset in the action table corresponding to the first action for this // landing pad (will be zero if there are none). size_t actionTableStartOffset; version (SjLj_Exceptions) { // The instruction pointer (ip) will point to the next instruction after // whatever made execution leave this frame, so substract 1 for the range // comparison below. ptrdiff_t ip = nativeContext.getIP() - 1; if (ip < 0) return nativeContext.continueUnwind(); // If ip is not present in the table, call terminate. if (ip == 0) fatalerror("Instruction pointer not found in table"); size_t cs_lp, cs_action; ubyte* callsite_walker = callsite_table; do { callsite_walker = get_uleb128(callsite_walker, cs_lp); callsite_walker = get_uleb128(callsite_walker, cs_action); debug(EH_personality_verbose) printf("%x %x\n", cs_lp, cs_action); } while (--ip); landingPadAddr = cs_lp + 1; actionTableStartOffset = cs_action; } else // !SjLj_Exceptions { // The instruction pointer (ip) will point to the next instruction after // whatever made execution leave this frame, so substract 1 for the range // comparison below. immutable ptrdiff_t ip = nativeContext.getIP() - 1; ubyte* callsite_walker = callsite_table; while (true) { // if we've gone through the list and found nothing... if (callsite_walker >= action_table) return nativeContext.continueUnwind(); immutable block_start_offset = udata4_read(callsite_walker); immutable block_size = udata4_read(callsite_walker); landingPadAddr = udata4_read(callsite_walker); callsite_walker = get_uleb128(callsite_walker, actionTableStartOffset); debug(EH_personality_verbose) { printf(" - ip=%p %u %u %tx\n", ip, block_start_offset, block_size, landingPadAddr); } // since the list is sorted, as soon as we're past the ip // there's no handler to be found if (ip < region_start + block_start_offset) return nativeContext.continueUnwind(); // if we've found our block, exit if (ip < region_start + block_start_offset + block_size) break; } } // !SjLj_Exceptions debug(EH_personality) { printf(" - Found correct landing pad and actionTableStartOffset %d\n", actionTableStartOffset); } // There is no landing pad for this part of the frame, continue with the next level. if (!landingPadAddr) return nativeContext.continueUnwind(); // We have a landing pad, adjust by region start address. landingPadAddr += region_start; immutable bool isSearchPhase = nativeContext.isSearchPhase(); // // We have at least a finally landing pad in this scope. First, check if we // have arrived at the scope a previous exception was thrown in. In this // case, we need to chain exception_struct.exception_object to it or replace // it with the former. // immutable ptrdiff_t currentCfaAddr = nativeContext.getCfaAddress(); ref ActiveCleanupBlock* acb() { return isSearchPhase ? searchPhaseCurrentCleanupBlock : innermostCleanupBlock; } while (acb) { debug(EH_personality) { printf(" - Current CFA: %p, Previous CFA: %p\n", currentCfaAddr, acb.cfaAddr); } // If the next active cleanup block is somewhere further up the stack, // there is nothing to do/check. // Note: assumes the stack grows downwards. if (currentCfaAddr < acb.cfaAddr) break; Object thrownDObject = nativeContext.getThrownObject(); auto currentClassInfo = isSearchPhase ? searchPhaseClassInfo : thrownDObject.classinfo; if (_d_isbaseof(currentClassInfo, Error.classinfo) && !cast(Error)acb.dObject) { // The currently unwound Throwable is an Error but the previous one // is not, so replace the latter with the former. debug(EH_personality) { printf(" ++ Replacing %p (%s) by %p (%s)\n", acb.dObject, acb.dObject.classinfo.name.ptr, thrownDObject, thrownDObject.classinfo.name.ptr); } if (!isSearchPhase) { (cast(Error)thrownDObject).bypassedException = cast(Throwable)acb.dObject; } } else { // We are just unwinding an Exception or there was already an Error, // so append this Throwable to the end of the previous chain. if (isSearchPhase) { debug(EH_personality) { printf(" ++ Setting up classinfo to chain %s to %p (%s, classinfo at %p)\n", searchPhaseClassInfo.name.ptr, acb.dObject, acb.dObject.classinfo.name.ptr, acb.dObject.classinfo); } searchPhaseClassInfo = acb.dObject.classinfo; } else { auto lastChainElem = cast(Throwable)acb.dObject; while (lastChainElem.next) { lastChainElem = lastChainElem.next; } auto thisThrowable = cast(Throwable)thrownDObject; if (lastChainElem is thisThrowable) { // We would need to chain an exception to itself. This can // happen if somebody throws the same exception object twice. // It is questionable whether this is supposed to work in the // first place, but core.demangle does it when generating the // backtrace for its internal exceptions during demangling a // symbol as part of the default trace handler (it uses the // .init value for the exception class instead of allocating // new instances). debug(EH_personality) { printf(" ++ Not chaining %p (%s) to itself\n", thisThrowable, thisThrowable.classinfo.name.ptr); } } else { debug(EH_personality) { printf(" ++ Chaining %p (%s) to %p (%s)\n", thisThrowable, thisThrowable.classinfo.name.ptr, lastChainElem, lastChainElem.classinfo.name.ptr); } lastChainElem.next = thisThrowable; } nativeContext.overrideThrownObject(acb.dObject); } } // In both cases, we've executed one level of chaining. auto outer = acb.outerBlock; if (!isSearchPhase) { // Destroy the exception struct associated with the previous level. // This is necessary as the libunwind implementation allocates new // exception structs for each throw; if we're chaining an exception, // we need to destroy the previous exception struct. nativeContext.destroyExceptionStruct(acb.exceptionStruct); GC.removeRoot(cast(void*)acb.dObject); ActiveCleanupBlockPool.free(acb); } acb = outer; } // // Exception chaining is now done. Let's figure out what we have to do in // this frame. // // If there are no actions, this is a cleanup landing pad. if (!actionTableStartOffset) { return nativeContext.installFinallyContext(landingPadAddr); } // We have at least some attached actions. Figure out whether any of them // match the type of the current exception. immutable ci_size = get_size_of_encoded_value(classinfo_table_encoding); debug(EH_personality) printf(" - ci_size: %td, ci_encoding: %d\n", ci_size, classinfo_table_encoding); ubyte* action_walker = action_table + actionTableStartOffset - 1; while (true) { ptrdiff_t ti_offset; action_walker = get_sleb128(action_walker, ti_offset); debug(EH_personality) printf(" - ti_offset: %tx\n", ti_offset); // it is intentional that we not modify action_walker here // next_action_offset is from current action_walker position ptrdiff_t next_action_offset; get_sleb128(action_walker, next_action_offset); // negative are 'filters' which we don't use if (!(ti_offset >= 0)) fatalerror("Filter actions are unsupported"); // zero means cleanup, which we require to be the last action if (ti_offset == 0) { if (!(next_action_offset == 0)) fatalerror("Cleanup action must be last in chain"); return nativeContext.installFinallyContext(landingPadAddr); } if (!nativeContext.skipCatchComparison()) { ClassInfo catchClassInfo = nativeContext.getCatchClassInfo( classinfo_table - ti_offset * ci_size, classinfo_table_encoding); ClassInfo exceptionClassInfo = isSearchPhase ? searchPhaseClassInfo : nativeContext.getThrownObject().classinfo; debug(EH_personality) { printf(" - Comparing catch %s to exception %s\n", catchClassInfo.name.ptr, exceptionClassInfo.name.ptr); } if (_d_isbaseof(exceptionClassInfo, catchClassInfo)) { return nativeContext.installCatchContext(ti_offset, landingPadAddr); } } debug(EH_personality) printf(" - Type mismatch, next action offset: %tx\n", next_action_offset); if (next_action_offset == 0) return nativeContext.continueUnwind(); action_walker += next_action_offset; } } ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/eh/fixedpool.d0000664000175000017500000001123612776214756021551 0ustar kaikai/** * A fixed memory pool for fast allocation/deallocation of structs. * * Authors: Mithun Hunsur */ module ldc.eh.fixedpool; import core.stdc.stdlib : malloc, free; /*********************************** * A fixed pool of T instances, used to optimise allocation/deallocation * performance for up to N instances before falling back to the heap. * * Implemented as an intrusive free list; each instance not in use contains * a pointer to the next free instance. As a result, allocation in the common * case is O(1); the first free instance is initialised and returned to the user. * * When deallocating, the given pointer is checked against the pool; if it lies * within the pool's range of addresses, it gets given the address of the old * first free instance, and the first free instance is then set to point at the * newly freed pointer. */ struct FixedPool(T, int N) { /** * Disable copying: we use internal pointers, so copying would not work * as expected (postblit semantics are unsuitable for fixing the pointers) */ @disable this(this); /** * Allocate a new instance from the pool if available, or from the heap otherwise. */ T* malloc() { // Initialize the free list if not already initialized if (!initialized) initialize(); if (firstFreeInstance) { // Set the next free instance to the pointer stored in // the current free instance auto instance = &firstFreeInstance.value; firstFreeInstance = firstFreeInstance.next; // Initialize the newly-allocated instance and return it *instance = T.init; return instance; } // Allocate a new instance from the heap, initialize it, and return it auto instance = cast(T*).malloc(T.sizeof); *instance = T.init; return instance; } /** * Free an instance that was allocated with this pool's `malloc` method. * * Warning: Has undefined behaviour if an instance that did not originate * from this `FixedPool` is passed in as the argument. */ void free(T* ptr) { // Initialize the free list if not already initialized if (!initialized) initialize(); // If the instance comes from our pool, add it to the linked list and return if (isInstanceInPool(ptr)) { // Overwrite the instance's first few bytes with a pointer to the next entry auto instanceBlock = cast(PoolBlock*)ptr; instanceBlock.next = firstFreeInstance; // Set the first free instance to the newly-freed instance firstFreeInstance = instanceBlock; return; } .free(ptr); } /** * Returns whether the given instance belongs to the instance pool. * * Warning: Does not return whether a given heap-allocated instance * originated from this `FixedPool`. */ bool isInstanceInPool(T* ptr) const { return ptr >= &instances[0].value && ptr <= &instances[$-1].value; } private: // We can't default construct the free list, so we initialize it the first time // we allocate or deallocate. bool initialized = false; void initialize() { // Initialize the free list firstFreeInstance = &instances[0]; // Set each instance to point to the next one in the list foreach (i; 0..N-1) instances[i].next = &instances[i+1]; // Set the last instance to point at null instances[$-1].next = null; initialized = true; } union PoolBlock { T value; PoolBlock* next; } PoolBlock[N] instances; PoolBlock* firstFreeInstance; } unittest { struct Test { int a = 5; int b = 6; } FixedPool!(Test, 8) testPool; Test*[] ptrs; // Allocate 10 instances and store them in an array for simulated use foreach (i; 0..10) ptrs ~= testPool.malloc(); // Check whether the first and last pointers allocated come from // the pool and the heap, respectively assert(testPool.isInstanceInPool(ptrs[0])); assert(!testPool.isInstanceInPool(ptrs[$-1])); foreach (ptr; ptrs) testPool.free(ptr); // After returning all the pointers to the heap, the first free pointer // should be the last instance (as it was the last pool instance to be freed.) auto ptr = testPool.malloc(); scope (exit) testPool.free(ptr); assert(ptr == &testPool.instances[$-1].value); // Verify that the newly-returned instance has been initialized correctly assert(ptr.a == 5); assert(ptr.b == 6); }ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/eh/libunwind.d0000664000175000017500000005026012776214756021553 0ustar kaikai/** * This module implements the runtime-part of LDC exceptions * on platforms with libunwind support. */ module ldc.eh.libunwind; version (CRuntime_Microsoft) {} else { // debug = EH_personality; // debug = EH_personality_verbose; // debug = EH_verifyExceptionStructLifetime; import core.stdc.stdlib : malloc, free; import ldc.eh.common; import ldc.eh.fixedpool; debug (EH_personality) import core.stdc.stdio : printf; // Support for setjump/longjump style exceptions. // // references: in GCC, for example gcc-4.8, see // https://github.com/mirrors/gcc/blob/master/libgcc/unwind-sjlj.c // https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-c.c // // the Apple version can be found at // https://www.opensource.apple.com/source/libunwind/libunwind-35.1/src/Unwind-sjlj.c version (ARM) { version (iOS) version = SjLj_Exceptions; else version = ARM_EABI_UNWINDER; } private: // C headers extern(C) { // FIXME: Some of these do not actually exist on ARM. enum _Unwind_Reason_Code : int { NO_REASON = 0, // "OK" on ARM FOREIGN_EXCEPTION_CAUGHT = 1, FATAL_PHASE2_ERROR = 2, FATAL_PHASE1_ERROR = 3, NORMAL_STOP = 4, END_OF_STACK = 5, HANDLER_FOUND = 6, INSTALL_CONTEXT = 7, CONTINUE_UNWIND = 8, FAILURE = 9 // ARM only } enum _Unwind_Action : int { SEARCH_PHASE = 1, CLEANUP_PHASE = 2, HANDLER_FRAME = 4, FORCE_UNWIND = 8 } alias void* _Unwind_Context_Ptr; alias void function(_Unwind_Reason_Code, _Unwind_Exception*) _Unwind_Exception_Cleanup_Fn; struct _Unwind_Exception { ulong exception_class; _Unwind_Exception_Cleanup_Fn exception_cleanup; ptrdiff_t private_1; ptrdiff_t private_2; } ptrdiff_t _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context); ptrdiff_t _Unwind_GetCFA(_Unwind_Context_Ptr context); version (ARM_EABI_UNWINDER) { _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block*); void _Unwind_Resume(_Unwind_Control_Block*); void _Unwind_Complete(_Unwind_Control_Block*); // On ARM, these are macros resp. not visible (static inline). To avoid // an unmaintainable amount of dependencies on implementation details, // just use a C shim. ptrdiff_t _d_eh_GetIP(_Unwind_Context_Ptr context); alias _Unwind_GetIP = _d_eh_GetIP; void _d_eh_SetIP(_Unwind_Context_Ptr context, ptrdiff_t new_value); alias _Unwind_SetIP = _d_eh_SetIP; ptrdiff_t _d_eh_GetGR(_Unwind_Context_Ptr context, int index); alias _Unwind_GetGR = _d_eh_GetGR; void _d_eh_SetGR(_Unwind_Context_Ptr context, int index, ptrdiff_t new_value); alias _Unwind_SetGR = _d_eh_SetGR; } else { version(SjLj_Exceptions) { void _Unwind_SjLj_Resume(_Unwind_Exception*); _Unwind_Reason_Code _Unwind_SjLj_RaiseException(_Unwind_Exception*); alias _Unwind_Resume = _Unwind_SjLj_Resume; alias _Unwind_RaiseException = _Unwind_SjLj_RaiseException; } else { _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*); void _Unwind_Resume(_Unwind_Exception*); } ptrdiff_t _Unwind_GetIP(_Unwind_Context_Ptr context); void _Unwind_SetIP(_Unwind_Context_Ptr context, ptrdiff_t new_value); void _Unwind_SetGR(_Unwind_Context_Ptr context, int index, ptrdiff_t new_value); } ptrdiff_t _Unwind_GetRegionStart(_Unwind_Context_Ptr context); ptrdiff_t _Unwind_GetTextRelBase(_Unwind_Context_Ptr context); ptrdiff_t _Unwind_GetDataRelBase(_Unwind_Context_Ptr context); } // Exception struct used by the runtime. // _d_throw allocates a new instance and passes the address of its // _Unwind_Exception member to the unwind call. The personality // routine is then able to get the whole struct by looking at the data // surrounding the unwind info. // // Note that the code we generate for the landing pads also relies on the // throwable object being stored at offset 0. struct _d_exception { Object exception_object; version (ARM_EABI_UNWINDER) { _Unwind_Control_Block unwind_info; } else { _Unwind_Exception unwind_info; } } static FixedPool!(_d_exception, 8) ExceptionStructPool; // the 8-byte string identifying the type of exception // the first 4 are for vendor, the second 4 for language //TODO: This may be the wrong way around __gshared char[8] _d_exception_class = "LLDCD2\0\0"; // These are the register numbers for SetGR that // llvm's eh.exception and eh.selector intrinsics // will pick up. // Hints for these can be found by looking at the // EH_RETURN_DATA_REGNO macro in GCC, careful testing // is required though. // // If you have a native gcc you can try the following: // #include // // int main(int argc, char *argv[]) // { // printf("EH_RETURN_DATA_REGNO(0) = %d\n", __builtin_eh_return_data_regno(0)); // printf("EH_RETURN_DATA_REGNO(1) = %d\n", __builtin_eh_return_data_regno(1)); // return 0; // } version (X86_64) { enum eh_exception_regno = 0; enum eh_selector_regno = 1; } else version (PPC64) { enum eh_exception_regno = 3; enum eh_selector_regno = 4; } else version (PPC) { enum eh_exception_regno = 3; enum eh_selector_regno = 4; } else version (MIPS64) { enum eh_exception_regno = 4; enum eh_selector_regno = 5; } else version (ARM) { enum eh_exception_regno = 0; enum eh_selector_regno = 1; } else version (AArch64) { enum eh_exception_regno = 0; enum eh_selector_regno = 1; } else { enum eh_exception_regno = 0; enum eh_selector_regno = 2; } // Interface to the native state for ldc.eh.common.eh_personality_common(). struct NativeContext { _Unwind_Action actions; _d_exception* exception_struct; _Unwind_Context_Ptr context; ubyte* getLanguageSpecificData() { return cast(ubyte*)_Unwind_GetLanguageSpecificData(context); } ptrdiff_t getIP() { return _Unwind_GetIP(context); } ptrdiff_t getRegionStart() { return _Unwind_GetRegionStart(context); } bool isSearchPhase() { return (actions & _Unwind_Action.SEARCH_PHASE) != 0; } // Optimization: After the search phase, libunwind lets us know whether // we have found a handler in this frame the first time around. We can // thus skip further the comparisons if the HANDLER_FRAME flag is not // set. // // As a further optimization step, we could look into caching that // result inside _d_exception. bool skipCatchComparison() { return !isSearchPhase() && (actions & _Unwind_Action.HANDLER_FRAME) == 0; } ptrdiff_t getCfaAddress() { // libgcc _Unwind_GetCFA for ARM_EABI is a partial // implementation, only valid during forced unwinds, so use // stack pointer instead. version (ARM_EABI_UNWINDER) return _Unwind_GetGR(context, UNWIND_STACK_REG); else return _Unwind_GetCFA(context); } Object getThrownObject() { return exception_struct.exception_object; } void overrideThrownObject(Object newObject) { exception_struct.exception_object = newObject; } ClassInfo getCatchClassInfo(void* address, ubyte encoding) { size_t catchClassInfoAddr; get_encoded_value(cast(ubyte*)address, catchClassInfoAddr, encoding, context); return cast(ClassInfo)cast(void*)catchClassInfoAddr; } _Unwind_Reason_Code continueUnwind() { return _Unwind_Reason_Code.CONTINUE_UNWIND; } _Unwind_Reason_Code installCatchContext(ptrdiff_t ti_offset, ptrdiff_t landingPadAddr) { debug(EH_personality) printf(" - Found catch clause for %p\n", exception_struct); if (actions & _Unwind_Action.SEARCH_PHASE) { // Cache phase 1 data (TODO: take advantage of cache) version (ARM_EABI_UNWINDER) with (exception_struct.unwind_info) { barrier_cache.sp = _Unwind_GetGR(context, UNWIND_STACK_REG); barrier_cache.bitpattern[1] = ti_offset; barrier_cache.bitpattern[3] = landingPadAddr; } return _Unwind_Reason_Code.HANDLER_FOUND; } if (!(actions & _Unwind_Action.CLEANUP_PHASE)) fatalerror("Unknown phase"); auto cleanupBlock = pushCleanupBlockRecord(getCfaAddress(), getThrownObject()); cleanupBlock.exceptionStruct = exception_struct; debug(EH_personality) { printf(" - Calling catch block for %p (struct at %p)\n", exception_struct.exception_object, exception_struct); } debug(EH_personality_verbose) printf(" - Setting switch value to: %p\n", ti_offset); _Unwind_SetGR(context, eh_exception_regno, cast(ptrdiff_t)exception_struct); _Unwind_SetGR(context, eh_selector_regno, ti_offset); debug(EH_personality_verbose) printf(" - Setting landing pad to: %p\n", landingPadAddr); _Unwind_SetIP(context, landingPadAddr); return _Unwind_Reason_Code.INSTALL_CONTEXT; } _Unwind_Reason_Code installFinallyContext(ptrdiff_t landingPadAddr) { if (actions & _Unwind_Action.SEARCH_PHASE) return _Unwind_Reason_Code.CONTINUE_UNWIND; auto cleanupBlock = pushCleanupBlockRecord(getCfaAddress(), getThrownObject()); cleanupBlock.exceptionStruct = exception_struct; debug(EH_personality) { printf(" - Calling cleanup block for %p (struct at %p)\n", exception_struct.exception_object, exception_struct); } _Unwind_SetGR(context, eh_exception_regno, cast(ptrdiff_t)exception_struct); _Unwind_SetGR(context, eh_selector_regno, 0); _Unwind_SetIP(context, landingPadAddr); return _Unwind_Reason_Code.INSTALL_CONTEXT; } void destroyExceptionStruct(void* exception_struct) { _d_eh_destroy_exception_struct(exception_struct); } } version(ARM_EABI_UNWINDER) { enum _Unwind_State { VIRTUAL_UNWIND_FRAME = 0, UNWIND_FRAME_STARTING = 1, UNWIND_FRAME_RESUME = 2, ACTION_MASK = 3, FORCE_UNWIND = 8, END_OF_STACK = 16 } alias _uw = ptrdiff_t; struct _Unwind_Control_Block { char[8] exception_class; void function(_Unwind_Reason_Code, _Unwind_Control_Block *) exception_cleanup; struct unwinder_cache_t { _uw reserved1; _uw reserved2; _uw reserved3; _uw reserved4; _uw reserved5; } unwinder_cache_t unwinder_cache; struct barrier_cache_t { _uw sp; _uw[5] bitpattern; } barrier_cache_t barrier_cache; struct cleanup_cache_t { _uw[4] bitpattern; } cleanup_cache_t cleanup_cache; struct pr_cache_t { _uw fnstart; _uw *ehtp; _uw additional; _uw reserved1; } pr_cache_t pr_cache; } extern(C) _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Control_Block *, _Unwind_Context_Ptr); _Unwind_Reason_Code continueUnwind(_Unwind_Control_Block* ucb, _Unwind_Context_Ptr context) { if (__gnu_unwind_frame(ucb, context) != _Unwind_Reason_Code.NO_REASON) return _Unwind_Reason_Code.FAILURE; return _Unwind_Reason_Code.CONTINUE_UNWIND; } // Defined in unwind-arm.h. enum UNWIND_STACK_REG = 13; enum UNWIND_POINTER_REG = 12; auto toDException(_Unwind_Control_Block* ucb) { return cast(_d_exception*)(cast(ubyte*)ucb - _d_exception.unwind_info.offsetof); } // The personality routine gets called by the unwind handler and is responsible for // reading the EH tables and deciding what to do. extern(C) _Unwind_Reason_Code _d_eh_personality(_Unwind_State state, _Unwind_Control_Block* ucb, _Unwind_Context_Ptr context) { debug(EH_personality_verbose) printf(" - entering personality function. state: %d; ucb: %p, context: %p\n", state, ucb, context); _Unwind_Action actions; with (_Unwind_State) with (_Unwind_Action) { switch (state & _Unwind_State.ACTION_MASK) { case _Unwind_State.VIRTUAL_UNWIND_FRAME: actions = _Unwind_Action.SEARCH_PHASE; break; case _Unwind_State.UNWIND_FRAME_STARTING: actions = _Unwind_Action.CLEANUP_PHASE; if (!(state & _Unwind_State.FORCE_UNWIND) && ucb.barrier_cache.sp == _Unwind_GetGR(context, UNWIND_STACK_REG)) { actions |= _Unwind_Action.HANDLER_FRAME; } break; case _Unwind_State.UNWIND_FRAME_RESUME: // return continueUnwind(ucb, context); // // Can't do normal continue unwind because there // might be a handler stll in this frame. // Starting again at saved IP instead. _Unwind_SetIP(context, ucb.cleanup_cache.bitpattern[0]); goto case UNWIND_FRAME_STARTING; default: fatalerror("Unhandled ARM EABI unwind state."); } actions |= state & _Unwind_State.FORCE_UNWIND; } // The dwarf unwinder assumes the context structure holds things like the // function and LSDA pointers. The ARM implementation caches these in // the exception header (UCB). To avoid rewriting everything we make a // virtual scratch register point at the UCB. _Unwind_SetGR(context, UNWIND_POINTER_REG, cast(ptrdiff_t)ucb); // check exceptionClass //TODO: Treat foreign exceptions with more respect if (ucb.exception_class != _d_exception_class) return _Unwind_Reason_Code.FATAL_PHASE1_ERROR; auto nativeContext = NativeContext(actions, ucb.toDException(), context); _Unwind_Reason_Code rc = eh_personality_common(nativeContext); if (rc == _Unwind_Reason_Code.CONTINUE_UNWIND) return continueUnwind(ucb, context); return rc; } } else // !ARM_EABI_UNWINDER { // The personality routine gets called by the unwind handler and is responsible for // reading the EH tables and deciding what to do. extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context) { debug(EH_personality_verbose) { printf(" %s Entering personality function. context: %p\n", (actions & _Unwind_Action.SEARCH_PHASE) ? "[S]".ptr : "[U]".ptr, context); } // check ver: the C++ Itanium ABI only allows ver == 1 if (ver != 1) return _Unwind_Reason_Code.FATAL_PHASE1_ERROR; // check exceptionClass //TODO: Treat foreign exceptions with more respect if ((cast(char*)&exception_class)[0..8] != _d_exception_class) return _Unwind_Reason_Code.FATAL_PHASE1_ERROR; _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof); auto nativeContext = NativeContext(actions, exception_struct, context); return eh_personality_common(nativeContext); } } extern(C) Throwable.TraceInfo _d_traceContext(void* ptr = null); debug (EH_verifyExceptionStructLifetime) { shared size_t exceptionStructsInFlight; shared static ~this() { if (exceptionStructsInFlight != 0) fatalerror("Non-zero number of exception structs in flight: %zu", exceptionStructsInFlight); } } public extern(C): /// Called by our compiler-generated code to throw an exception. void _d_throw_exception(Object e) { if (e is null) fatalerror("Cannot throw null exception"); if (e.classinfo is null) fatalerror("Cannot throw corrupt exception object with null classinfo"); auto throwable = cast(Throwable) e; if (throwable.info is null && cast(byte*)throwable !is typeid(throwable).init.ptr) throwable.info = _d_traceContext(); auto exc_struct = ExceptionStructPool.malloc(); if (!exc_struct) fatalerror("Could not allocate D exception record; out of memory?"); version (ARM_EABI_UNWINDER) { exc_struct.unwind_info.exception_class = _d_exception_class; } else { exc_struct.unwind_info.exception_class = *cast(ulong*)_d_exception_class.ptr; } exc_struct.exception_object = e; debug(EH_personality) { printf("= Throwing new exception of type %s: %p (struct at %p, classinfo at %p", e.classinfo.name.ptr, e, exc_struct, e.classinfo); debug (EH_verifyExceptionStructLifetime) { import core.atomic : atomicOp; auto count = exceptionStructsInFlight.atomicOp!"+="(1); printf(", %zu structs in flight", count); } printf(")\n"); } searchPhaseClassInfo = e.classinfo; searchPhaseCurrentCleanupBlock = innermostCleanupBlock; // _Unwind_RaiseException should never return unless something went really // wrong with unwinding. immutable ret = _Unwind_RaiseException(&exc_struct.unwind_info); fatalerror("_Unwind_RaiseException failed with reason code: %d", ret); } /// Called by our compiler-generate code to resume unwinding after a finally /// block (or dtor destruction block) has been run. version (ARM_EABI_UNWINDER) { // Implemented in asm to preserve core registers, declaration here // for reference only void _d_eh_resume_unwind(void* ptr); // Perform cleanups before resuming. Can't call _Unwind_Resume // because it expects core register state at callsite. // // Also, a workaround for ARM EABI unwinding. When D catch // handlers are merged by the LLVM inliner, the IR has a landing // pad that claims it will handle multiple exception types, but // then only handles one and falls into _d_eh_resume_unwind. This // call to _d_eh_resume_unwind has a landing pad with the correct // exception handler, but gcc ARM EABI unwind implementation // resumes in the next frame up and misses it. Other gcc // unwinders, C++ Itanium and SjLj, handle this case fine by // resuming in the current frame. The workaround is to save IP so // personality can resume in the current frame. auto _d_arm_eabi_end_cleanup(void* ptr, ptrdiff_t ip) { debug(EH_personality_verbose) printf(" - Resume ip %p\n", ip); // tell personality the real IP (cleanup_cache can be used // however we like) with (cast(_d_exception*)ptr) unwind_info.cleanup_cache.bitpattern[0] = ip; return _d_end_cleanup(ptr); } } else { void _d_eh_resume_unwind(void* ptr) { _Unwind_Resume(_d_end_cleanup(ptr)); } } auto _d_end_cleanup(void* ptr) { auto exception_struct = cast(_d_exception*) ptr; debug(EH_personality) { printf("= Returning from cleanup block for %p (struct at %p)\n", exception_struct.exception_object, exception_struct); } popCleanupBlockRecord(); return &exception_struct.unwind_info; } Object _d_eh_destroy_exception_struct(void* ptr) { if (ptr == null) return null; auto exception_struct = cast(_d_exception*) ptr; auto obj = exception_struct.exception_object; ExceptionStructPool.free(exception_struct); debug (EH_personality) { printf(" - Destroyed exception struct at %p", exception_struct); debug (EH_verifyExceptionStructLifetime) { import core.atomic : atomicOp; auto count = exceptionStructsInFlight.atomicOp!"-="(1); printf(", %zu structs in flight", count); } printf("\n"); } return obj; } Object _d_eh_enter_catch(void* ptr) { auto exception_struct = cast(_d_exception*)ptr; version (ARM_EABI_UNWINDER) { _Unwind_Complete(&exception_struct.unwind_info); } auto obj = _d_eh_destroy_exception_struct(exception_struct); popCleanupBlockRecord(); return obj; } } // !CRuntime_Microsoft ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/osx_tls.c0000664000175000017500000000306312776214756020655 0ustar kaikai/** * Helpers for determining TLS memory ranges on OS X. * * This unfortunately cannot be entirely done in D, as the OS X API uses * the Apple-specific blocks C extension. * * Copyright: David Nadlinger, 2012. * License: Boost License 1.0. * Authors: David Nadlinger */ #ifndef __BLOCKS__ #error "Need a C compiler with Apple Blocks support – not building on OS X?" #endif #include #include #include /* * Declarations from dyld_priv.h, available on 10.7+. */ enum dyld_tlv_states { dyld_tlv_state_allocated = 10, dyld_tlv_state_deallocated = 20 }; typedef struct { size_t info_size; void * tlv_addr; size_t tlv_size; } dyld_tlv_info; typedef void (^dyld_tlv_state_change_handler)(enum dyld_tlv_states state, const dyld_tlv_info *info); extern void dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler); extern void dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler); void _d_dyld_getTLSRange(void* arbitraryTLSSymbol, void** start, size_t* size) { dyld_enumerate_tlv_storage( ^(enum dyld_tlv_states state, const dyld_tlv_info *info) { assert(state == dyld_tlv_state_allocated); if (info->tlv_addr <= arbitraryTLSSymbol && arbitraryTLSSymbol < (info->tlv_addr + info->tlv_size) ) { // Found the range. *start = info->tlv_addr; *size = info->tlv_size; } } ); } ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/simd.di0000664000175000017500000001643512776214756020277 0ustar kaikaimodule ldc.simd; import core.simd; // The syntax of e.g. `load` changed with LLVM 3.7 version (LDC_LLVM_305) version = LDC_LLVM_PRE307; version (LDC_LLVM_306) version = LDC_LLVM_PRE307; pure: nothrow: @nogc: @trusted: private template isFloatingPoint(T) { enum isFloatingPoint = is(T == float) || is(T == double) || is(T == real); } private template isIntegral(T) { enum isIntegral = is(T == byte) || is(T == ubyte) || is(T == short) || is(T == ushort) || is(T == int) || is(T == uint) || is(T == long) || is(T == ulong); } private template isSigned(T) { enum isSigned = is(T == byte) || is(T == short) || is(T == int) || is(T == long); } private template IntOf(T) if(isIntegral!T || isFloatingPoint!T) { enum n = T.sizeof; static if(n == 1) alias byte IntOf; else static if(n == 2) alias short IntOf; else static if(n == 4) alias int IntOf; else static if(n == 8) alias long IntOf; else static assert(0, "Type not supported"); } private template BaseType(V) { alias typeof(V.array[0]) BaseType; } private template numElements(V) { enum numElements = V.sizeof / BaseType!(V).sizeof; } private template llvmType(T) { static if(is(T == float)) enum llvmType = "float"; else static if(is(T == double)) enum llvmType = "double"; else static if(is(T == byte) || is(T == ubyte) || is(T == void)) enum llvmType = "i8"; else static if(is(T == short) || is(T == ushort)) enum llvmType = "i16"; else static if(is(T == int) || is(T == uint)) enum llvmType = "i32"; else static if(is(T == long) || is(T == ulong)) enum llvmType = "i64"; else static assert(0, "Can't determine llvm type for D type " ~ T.stringof); } private template llvmVecType(V) { static if(is(V == void16)) enum llvmVecType = "<16 x i8>"; else static if(is(V == void32)) enum llvmVecType = "<32 x i8>"; else { alias BaseType!V T; enum int n = numElements!V; enum llvmT = llvmType!T; enum llvmVecType = "<"~n.stringof~" x "~llvmT~">"; } } pragma(LDC_inline_ir) R inlineIR(string s, R, P...)(P); /** This template provides access to $(LINK2 http://llvm.org/docs/LangRef.html#i_shufflevector, LLVM's shufflevector instruction). Example: --- int4 a = [0, 10, 20, 30]; int4 b = [40, 50, 60, 70]; int4 c = shufflevector!(int4, 0, 2, 4, 6)(a, b); assert(c.array == [0, 20, 40, 60]); --- */ template shufflevector(V, mask...) if(is(typeof(llvmVecType!V)) && mask.length == numElements!V) { enum int n = mask.length; enum llvmV = llvmVecType!V; template genMaskIr(string ir, m...) { static if(m.length == 0) enum genMaskIr = ir; else { enum int mfront = m[0]; enum genMaskIr = genMaskIr!(ir ~ ", i32 " ~ mfront.stringof, m[1 .. $]); } } enum maskIr = genMaskIr!("", mask)[2 .. $]; enum ir = ` %r = shufflevector `~llvmV~` %0, `~llvmV~` %1, <`~n.stringof~` x i32> <`~maskIr~`> ret `~llvmV~` %r`; alias inlineIR!(ir, V, V, V) shufflevector; } /** This template provides access to $(LINK2 http://llvm.org/docs/LangRef.html#i_extractelement, LLVM's extractelement instruction). Example: --- int4 a = [0, 10, 20, 30]; int k = extractelement!(int4, 2)(a); assert(k == 20); --- */ template extractelement(V, int i) if(is(typeof(llvmVecType!V)) && i < numElements!V) { enum llvmT = llvmType!(BaseType!V); enum llvmV = llvmVecType!V; enum ir = ` %r = extractelement `~llvmV~` %0, i32 `~i.stringof~` ret `~llvmT~` %r`; alias inlineIR!(ir, BaseType!V, V) extractelement; } /** This template provides access to $(LINK2 http://llvm.org/docs/LangRef.html#i_insertelement, LLVM's insertelement instruction). Example: --- int4 a = [0, 10, 20, 30]; int b = insertelement!(int4, 2)(a, 50); assert(b.array == [0, 10, 50, 30]); --- */ template insertelement(V, int i) if(is(typeof(llvmVecType!V)) && i < numElements!V) { enum llvmT = llvmType!(BaseType!V); enum llvmV = llvmVecType!V; enum ir = ` %r = insertelement `~llvmV~` %0, `~llvmT~` %1, i32 `~i.stringof~` ret `~llvmV~` %r`; alias inlineIR!(ir, V, V, BaseType!V) insertelement; } /** loadUnaligned: Loads a vector from an unaligned pointer. Example: --- int[4] a = [0, 10, 20, 30]; int4 v = loadUnaligned!int4(a.ptr); assert(v.array == a); --- */ template loadUnaligned(V) if(is(typeof(llvmVecType!V))) { alias BaseType!V T; enum llvmT = llvmType!T; enum llvmV = llvmVecType!V; version (LDC_LLVM_PRE307) { enum ir = ` %p = bitcast `~llvmT~`* %0 to `~llvmV~`* %r = load `~llvmV~`* %p, align 1 ret `~llvmV~` %r`; } else { enum ir = ` %p = bitcast `~llvmT~`* %0 to `~llvmV~`* %r = load `~llvmV~`, `~llvmV~`* %p, align 1 ret `~llvmV~` %r`; } alias inlineIR!(ir, V, const(T)*) loadUnaligned; } /** storeUnaligned: Stores a vector to an unaligned pointer. Example: --- int[4] a; int4 v = [0, 10, 20, 30]; storeUnaligned!int4(v, a.ptr); assert(v.array == a); --- */ template storeUnaligned(V) if(is(typeof(llvmVecType!V))) { alias BaseType!V T; enum llvmT = llvmType!T; enum llvmV = llvmVecType!V; enum ir = ` %p = bitcast `~llvmT~`* %1 to `~llvmV~`* store `~llvmV~` %0, `~llvmV~`* %p, align 1`; alias inlineIR!(ir, void, V, T*) storeUnaligned; } private enum Cond{ eq, ne, gt, ge } private template cmpMask(Cond cond) { template cmpMask(V) if(is(IntOf!(BaseType!V))) { alias BaseType!V T; enum llvmT = llvmType!T; alias IntOf!T Relem; enum int n = numElements!V; alias __vector(Relem[n]) R; enum llvmV = llvmVecType!V; enum llvmR = llvmVecType!R; enum sign = (cond == Cond.eq || cond == Cond.ne) ? "" : isSigned!T ? "s" : "u"; enum condStr = cond == Cond.eq ? "eq" : cond == Cond.ne ? "ne" : cond == Cond.ge ? "ge" : "gt"; enum op = isFloatingPoint!T ? "fcmp o"~condStr : "icmp "~sign~condStr; enum ir = ` %cmp = `~op~` `~llvmV~` %0, %1 %r = sext <`~n.stringof~` x i1> %cmp to `~llvmR~` ret `~llvmR~` %r`; alias inlineIR!(ir, R, V, V) cmpMask; } } /** equalMask, notEqualMask, greaterMask and greaterOrEqualMask perform an element-wise comparison between two vectors and return a vector with signed integral elements. The number of elements in the returned vector and their size is the same as in parameter vectors. If the condition in the name of the function holds for elements of the parameter vectors at a given index, all bits of the element of the result at that index are set to 1, otherwise the element of the result is zero. Example: --- float4 a = [1, 3, 5, 7]; float4 b = [2, 3, 4, 5]; int4 c = greaterMask!float4(a, b); writeln(c.array); assert(c.array == [0, 0, 0xffff_ffff, 0xffff_ffff]); --- */ alias cmpMask!(Cond.eq) equalMask; alias cmpMask!(Cond.ne) notEqualMask; /// Ditto alias cmpMask!(Cond.gt) greaterMask; /// Ditto alias cmpMask!(Cond.ge) greaterOrEqualMask; /// Ditto ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/eh_asm.S0000664000175000017500000000376712776214756020411 0ustar kaikai/** * Exception handling support code that is best written in assembly * goes here. * * Copyright: Copyright The LDC Developers 2016 * License: Boost License 1.0. */ /* * Mark the resulting object file as not requiring execution * permissions on stack memory. The absence of this section would mark * the whole resulting library as requiring an executable stack, * making it impossible to dynamically load druntime on several Linux * platforms where this is forbidden due to security policies. */ #if (defined(__linux__) || defined(__FreeBSD__)) && defined(__ELF__) .section .note.GNU-stack,"",%progbits .previous #endif /* * Called by our compiler-generate code to resume unwinding after a * finally block (or dtor destruction block) has been run. 'ptr' (r0) * is to a _d_exception. * * void _d_eh_resume_unwind(void* ptr) * * _Unwind_Resume for ARM_EABI expects registers not to be clobbered * by our cleanup routine, so need this wrapper to preserve scratch * registers (7.4 [6 Note]) before entering it. * * Note: Current codegen of D catch landing pads are incompatible with * GCC provided _Unwind_Resume because the LLVM inliner can create * landing pads that advertise to catch more exceptions than are * handled, falling into _d_eh_resume_unwind to find the real handler. * _Unwind_Resume ignores the saved IP and resets it to the original * call site in this frame, but we need the callsite of * _d_eh_resume_unwind to find the next landing pad. Workaround is to * capture it, passing to _d_arm_eabi_end_cleanup as second arg. */ #ifdef __ARM_EABI__ // say we will preseve 8-byte stack when we push .eabi_attribute 25, 1 .text .global _d_eh_resume_unwind .align 2 _d_eh_resume_unwind: push {r1-r3,lr} // end_cleanup may trash these mov r1,lr // callsite IP bl _d_arm_eabi_end_cleanup pop {r1-r3,lr} // restore regs to state at entry b _Unwind_Resume // r0 has returned ucb #endif //__ARM_EABI ldc-1.1.0-beta3-src/runtime/druntime/src/ldc/internal/0000775000175000017500000000000012776214756020630 5ustar kaikaildc-1.1.0-beta3-src/runtime/druntime/src/ldc/internal/vararg.di0000664000175000017500000000150112776214756022425 0ustar kaikai/** * Contains ABI specific definitions for variable argument lists. * * Copyright: Authors 2016 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Kai Nacke */ module ldc.internal.vararg; version (AArch64) { // AAPCS64 defines this parameter control block in section 7.1.4. // Handling of variable argument lists is described in appendix B. // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf extern (C++, std) struct __va_list { void* __stack; void* __gr_top; void* __vr_top; int __gr_offs; int __vr_offs; } } else version (ARM) { // Need std::__va_list for C++ mangling compatability // section AAPCS 7.1.4 extern (C++, std) struct __va_list { void *__ap; } } ldc-1.1.0-beta3-src/runtime/druntime/.editorconfig0000664000175000017500000000024112776214756020135 0ustar kaikairoot = true [*.{c,h,d,di,dd}] end_of_line = lf insert_final_newline = true indent_style = space indent_size = 4 trim_trailing_whitespace = true charset = utf-8 ldc-1.1.0-beta3-src/runtime/druntime/HACKING.md0000664000175000017500000000722312776214756017055 0ustar kaikaiDRuntime: Runtime Library for the D Programming Language ======================================================== This is a collection of things that people hacking on DRuntime will want to know. Code style ---------- Please follow the D style guide when writing code for DRuntime: http://dlang.org/dstyle.html The D style guide doesn't cover everything so when in doubt, use the code style already used in the module you are modifying, or whatever style you prefer if you're adding a new module. Publicity of modules -------------------- In general, only modules in the 'core' package should be made public. The single exception is the 'object' module which is not in any package. The convention is to put private modules in the 'rt' or 'gc' packages depending on what they do and only put public modules in 'core'. Also, always avoid importing private modules in public modules. If a public module consists of a header file and an implementation file (which are both maintained by hand) then it is OK to import private modules in the implementation file. Adding new modules ------------------ When adding a new module, remember to update all three makefiles as necessary: * posix.mak * win32.mak * win64.mak A number of shared utility makefiles also need to be updated: * mak/COPY * mak/DOCS * mak/IMPORTS * mak/SRCS Operating system bindings ------------------------- The 'core.sys' package provides bindings to most APIs provided by supported operating systems. The convention is to have OS-specific stuff in a 'core.sys.os' package where 'os' is the canonical name for the OS (e.g. 'linux', 'osx', 'windows'). There is also the 'core.sys.posix' package in which bindings to standardized POSIX APIs should be placed. In this package, the convention is to put declarations in sections based on the OS being compiled for. See src/core/sys/posix/pwd.d for an example of how these modules are arranged. For all OS headers, it's a good idea to put a version attribute at the top of the file containing the OS the header is intended for. For example, in POSIX modules, this would be 'version (Posix):' while in Windows modules it would be 'version (Windows):' and so on. The convention is to have a D module per C header. C99 bindings ------------ The 'core.stdc' package provides bindings to all C99 library types, functions, and macros. Unlike the style in operating system bindings, bindings here should be kept system-agnostic whenever possible. Deprecation process ------------------- Never remove a symbol without going through the proper deprecation process. When, for whatever reason, a symbol is to be deprecated, annotate it as such using the 'deprecated' attribute. It is a good idea to also provide a message on the attribute so that the user can immediately see what symbol they should use instead. After six months of having been deprecated, a symbol can be removed completely. It may also be kept around for backwards compatibility if deemed necessary. ABI breakage ------------ We're trying to get to a point where DRuntime's ABI is completely stable and different compiler versions can use different DRuntime versions. To this end, avoid making ABI-breaking changes unless you have a *very* good reason to do it. Remember that renaming a symbol and leaving an alias behind for the old symbol name *is* an ABI break. The compiled name will be the new symbol, thus breaking old binaries. Updating the change log ----------------------- It's a good idea to not update the change log in a pull request. It tends to create merge conflicts between pull requests more often than not. That said, an occasional pull request to update the change log with recent changes (i.e. in a batch) is OK. ldc-1.1.0-beta3-src/runtime/druntime/changelog.dd0000664000175000017500000000460712776214756017732 0ustar kaikaiDdoc $(COMMENT Pending changelog for 2.071.0. ) $(BUGSTITLE Library Changes, $(LI $(RELATIVE_LINK2 aa-clear, A `clear` method has been added to associative arrays to remove all elements.)) $(LI $(RELATIVE_LINK2 spinlock, The GC now uses a spinlock instead of a recursive mutex.)) $(LI Calls to $(NCXREF memory, GC.free) are now ignored during finalization instead of throwing an InvalidMemoryOperationError, see $(BUGZILLA 15353).) $(LI $(NCXREF memory, GC.addRoot) and $(NCXREF memory, GC.addRange) now use a separate lock.) ) $(BUGSTITLE Library Changes, $(LI $(LNAME2 aa-clear, A `clear` method has been added to associative arrays to remove all elements.) $(P One can now use `aa.clear()` to remove all elements from an associative array. This allows removing all elements from all references to the same array (setting to `null` just reset the reference, but did not removed the elements from other references). ) ------- auto aa = ["first" : "entry", "second": "entry"]; auto aa2 = aa1; // reference to the same AA aa.clear(); // still retains its current capacity for faster imports assert(aa2.length == 0); // other references affected ------- ) $(LI $(LNAME2 spinlock, The GC is no longer wrapped in a pthread_mutex, it now uses a spinlock.) $(P This results in a 5% faster GC on average, with the most benefits going to multi-threaded programs that use the GC. See $(DRUNTIMEPR 1447) for more details. ) ) ) Macros: TITLE=Change Log BUGSTITLE =
$(H4 $1) $(OL $2 )
RELATIVE_LINK2=$+ LNAME2=$+ STDMODREF = $2 COREMODREF = $2 XREF = $2 CXREF = $2 OXREF = $2 NXREF = $2 NCXREF = $2 NOXREF = $2 BUGZILLA = Bugzilla $0 PULL_REQUEST = $(LINK2 https://github.com/D-Programming-Language/$1/pull/$2, $1#$2) DRUNTIMEPR = $(PULL_REQUEST druntime,$1) BOOKTABLE = $+
$1
PRE =
$0
ldc-1.1.0-beta3-src/runtime/druntime/win64.mak0000664000175000017500000010122412776214756017124 0ustar kaikai# Makefile to build D runtime library druntime64.lib for Win64 MODEL=64 VCDIR=\Program Files (x86)\Microsoft Visual Studio 10.0\VC SDKDIR=\Program Files (x86)\Microsoft SDKs\Windows\v7.0A DMD=dmd CC="$(VCDIR)\bin\amd64\cl" LD="$(VCDIR)\bin\amd64\link" AR="$(VCDIR)\bin\amd64\lib" CP=cp DOCDIR=doc IMPDIR=import MAKE=make DFLAGS=-m$(MODEL) -conf= -O -release -dip25 -inline -w -Isrc -Iimport UDFLAGS=-m$(MODEL) -conf= -O -release -dip25 -w -Isrc -Iimport DDOCFLAGS=-conf= -c -w -o- -Isrc -Iimport -version=CoreDdoc #CFLAGS=/O2 /I"$(VCDIR)"\INCLUDE /I"$(SDKDIR)"\Include CFLAGS=/Z7 /I"$(VCDIR)"\INCLUDE /I"$(SDKDIR)"\Include DRUNTIME_BASE=druntime$(MODEL) DRUNTIME=lib\$(DRUNTIME_BASE).lib GCSTUB=lib\gcstub$(MODEL).obj DOCFMT= target : import copydir copy $(DRUNTIME) $(GCSTUB) $(mak\COPY) $(mak\DOCS) $(mak\IMPORTS) $(mak\SRCS) # NOTE: trace.d and cover.d are not necessary for a successful build # as both are used for debugging features (profiling and coverage) OBJS= errno_c_$(MODEL).obj msvc_$(MODEL).obj msvc_math_$(MODEL).obj OBJS_TO_DELETE= errno_c_$(MODEL).obj msvc_$(MODEL).obj msvc_math_$(MODEL).obj ######################## Doc .html file generation ############################## doc: $(DOCS) $(DOCDIR)\object.html : src\object.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_atomic.html : src\core\atomic.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_attribute.html : src\core\attribute.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_bitop.html : src\core\bitop.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_checkedint.html : src\core\checkedint.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_cpuid.html : src\core\cpuid.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_demangle.html : src\core\demangle.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_exception.html : src\core\exception.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_math.html : src\core\math.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_memory.html : src\core\memory.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_runtime.html : src\core\runtime.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_simd.html : src\core\simd.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_thread.html : src\core\thread.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_time.html : src\core\time.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_vararg.html : src\core\vararg.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_complex.html : src\core\stdc\complex.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_ctype.html : src\core\stdc\ctype.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_errno.html : src\core\stdc\errno.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_fenv.html : src\core\stdc\fenv.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_float_.html : src\core\stdc\float_.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_inttypes.html : src\core\stdc\inttypes.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_limits.html : src\core\stdc\limits.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_locale.html : src\core\stdc\locale.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_math.html : src\core\stdc\math.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_signal.html : src\core\stdc\signal.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stdarg.html : src\core\stdc\stdarg.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stddef.html : src\core\stdc\stddef.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stdint.html : src\core\stdc\stdint.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stdio.html : src\core\stdc\stdio.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_stdlib.html : src\core\stdc\stdlib.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_string.html : src\core\stdc\string.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_tgmath.html : src\core\stdc\tgmath.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_time.html : src\core\stdc\time.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_wchar_.html : src\core\stdc\wchar_.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_stdc_wctype.html : src\core\stdc\wctype.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_barrier.html : src\core\sync\barrier.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_condition.html : src\core\sync\condition.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_config.html : src\core\sync\config.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_exception.html : src\core\sync\exception.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_mutex.html : src\core\sync\mutex.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_rwmutex.html : src\core\sync\rwmutex.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** $(DOCDIR)\core_sync_semaphore.html : src\core\sync\semaphore.d $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $** changelog.html: changelog.dd $(DMD) -Dfchangelog.html changelog.dd ######################## Header .di file generation ############################## import: $(IMPORTS) $(IMPDIR)\core\sync\barrier.di : src\core\sync\barrier.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\condition.di : src\core\sync\condition.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\config.di : src\core\sync\config.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\exception.di : src\core\sync\exception.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\mutex.di : src\core\sync\mutex.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\rwmutex.di : src\core\sync\rwmutex.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** $(IMPDIR)\core\sync\semaphore.di : src\core\sync\semaphore.d $(DMD) -conf= -c -o- -Isrc -Iimport -Hf$@ $** ######################## Header .di file copy ############################## copydir: $(IMPDIR) mkdir $(IMPDIR)\core\stdc mkdir $(IMPDIR)\core\stdcpp mkdir $(IMPDIR)\core\internal mkdir $(IMPDIR)\core\sys\freebsd\sys mkdir $(IMPDIR)\core\sys\linux\sys mkdir $(IMPDIR)\core\sys\osx\mach mkdir $(IMPDIR)\core\sys\posix\arpa mkdir $(IMPDIR)\core\sys\posix\net mkdir $(IMPDIR)\core\sys\posix\netinet mkdir $(IMPDIR)\core\sys\posix\sys mkdir $(IMPDIR)\core\sys\solaris\sys mkdir $(IMPDIR)\core\sys\windows mkdir $(IMPDIR)\etc\linux copy: $(COPY) $(IMPDIR)\object.d : src\object.d copy $** $@ if exist $(IMPDIR)\object.di del $(IMPDIR)\object.di $(IMPDIR)\core\atomic.d : src\core\atomic.d copy $** $@ $(IMPDIR)\core\attribute.d : src\core\attribute.d copy $** $@ $(IMPDIR)\core\bitop.d : src\core\bitop.d copy $** $@ $(IMPDIR)\core\checkedint.d : src\core\checkedint.d copy $** $@ $(IMPDIR)\core\cpuid.d : src\core\cpuid.d copy $** $@ $(IMPDIR)\core\demangle.d : src\core\demangle.d copy $** $@ $(IMPDIR)\core\exception.d : src\core\exception.d copy $** $@ $(IMPDIR)\core\math.d : src\core\math.d copy $** $@ $(IMPDIR)\core\memory.d : src\core\memory.d copy $** $@ $(IMPDIR)\core\runtime.d : src\core\runtime.d copy $** $@ $(IMPDIR)\core\simd.d : src\core\simd.d copy $** $@ $(IMPDIR)\core\thread.d : src\core\thread.d copy $** $@ $(IMPDIR)\core\time.d : src\core\time.d copy $** $@ $(IMPDIR)\core\vararg.d : src\core\vararg.d copy $** $@ $(IMPDIR)\core\internal\abort.d : src\core\internal\abort.d copy $** $@ $(IMPDIR)\core\internal\convert.d : src\core\internal\convert.d copy $** $@ $(IMPDIR)\core\internal\hash.d : src\core\internal\hash.d copy $** $@ $(IMPDIR)\core\internal\spinlock.d : src\core\internal\spinlock.d copy $** $@ $(IMPDIR)\core\internal\string.d : src\core\internal\string.d copy $** $@ $(IMPDIR)\core\internal\traits.d : src\core\internal\traits.d copy $** $@ $(IMPDIR)\core\stdc\complex.d : src\core\stdc\complex.d copy $** $@ $(IMPDIR)\core\stdc\config.d : src\core\stdc\config.d copy $** $@ $(IMPDIR)\core\stdc\ctype.d : src\core\stdc\ctype.d copy $** $@ $(IMPDIR)\core\stdc\errno.d : src\core\stdc\errno.d copy $** $@ $(IMPDIR)\core\stdc\fenv.d : src\core\stdc\fenv.d copy $** $@ $(IMPDIR)\core\stdc\float_.d : src\core\stdc\float_.d copy $** $@ $(IMPDIR)\core\stdc\inttypes.d : src\core\stdc\inttypes.d copy $** $@ $(IMPDIR)\core\stdc\limits.d : src\core\stdc\limits.d copy $** $@ $(IMPDIR)\core\stdc\locale.d : src\core\stdc\locale.d copy $** $@ $(IMPDIR)\core\stdc\math.d : src\core\stdc\math.d copy $** $@ $(IMPDIR)\core\stdc\signal.d : src\core\stdc\signal.d copy $** $@ $(IMPDIR)\core\stdc\stdarg.d : src\core\stdc\stdarg.d copy $** $@ $(IMPDIR)\core\stdc\stddef.d : src\core\stdc\stddef.d copy $** $@ $(IMPDIR)\core\stdc\stdint.d : src\core\stdc\stdint.d copy $** $@ $(IMPDIR)\core\stdc\stdio.d : src\core\stdc\stdio.d copy $** $@ $(IMPDIR)\core\stdc\stdlib.d : src\core\stdc\stdlib.d copy $** $@ $(IMPDIR)\core\stdc\string.d : src\core\stdc\string.d copy $** $@ $(IMPDIR)\core\stdc\tgmath.d : src\core\stdc\tgmath.d copy $** $@ $(IMPDIR)\core\stdc\time.d : src\core\stdc\time.d copy $** $@ $(IMPDIR)\core\stdc\wchar_.d : src\core\stdc\wchar_.d copy $** $@ $(IMPDIR)\core\stdc\wctype.d : src\core\stdc\wctype.d copy $** $@ $(IMPDIR)\core\stdcpp\exception.d : src\core\stdcpp\exception.d copy $** $@ $(IMPDIR)\core\stdcpp\typeinfo.d : src\core\stdcpp\typeinfo.d copy $** $@ $(IMPDIR)\core\sys\freebsd\dlfcn.d : src\core\sys\freebsd\dlfcn.d copy $** $@ $(IMPDIR)\core\sys\freebsd\execinfo.d : src\core\sys\freebsd\execinfo.d copy $** $@ $(IMPDIR)\core\sys\freebsd\time.d : src\core\sys\freebsd\time.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\cdefs.d : src\core\sys\freebsd\sys\cdefs.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\elf.d : src\core\sys\freebsd\sys\elf.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\elf_common.d : src\core\sys\freebsd\sys\elf_common.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\elf32.d : src\core\sys\freebsd\sys\elf32.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\elf64.d : src\core\sys\freebsd\sys\elf64.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\event.d : src\core\sys\freebsd\sys\event.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\link_elf.d : src\core\sys\freebsd\sys\link_elf.d copy $** $@ $(IMPDIR)\core\sys\freebsd\sys\mman.d : src\core\sys\freebsd\sys\mman.d copy $** $@ $(IMPDIR)\core\sys\linux\config.d : src\core\sys\linux\config.d copy $** $@ $(IMPDIR)\core\sys\linux\dlfcn.d : src\core\sys\linux\dlfcn.d copy $** $@ $(IMPDIR)\core\sys\linux\elf.d : src\core\sys\linux\elf.d copy $** $@ $(IMPDIR)\core\sys\linux\epoll.d : src\core\sys\linux\epoll.d copy $** $@ $(IMPDIR)\core\sys\linux\errno.d : src\core\sys\linux\errno.d copy $** $@ $(IMPDIR)\core\sys\linux\execinfo.d : src\core\sys\linux\execinfo.d copy $** $@ $(IMPDIR)\core\sys\linux\fcntl.d : src\core\sys\linux\fcntl.d copy $** $@ $(IMPDIR)\core\sys\linux\link.d : src\core\sys\linux\link.d copy $** $@ $(IMPDIR)\core\sys\linux\termios.d : src\core\sys\linux\termios.d copy $** $@ $(IMPDIR)\core\sys\linux\time.d : src\core\sys\linux\time.d copy $** $@ $(IMPDIR)\core\sys\linux\timerfd.d : src\core\sys\linux\timerfd.d copy $** $@ $(IMPDIR)\core\sys\linux\tipc.d : src\core\sys\linux\tipc.d copy $** $@ $(IMPDIR)\core\sys\linux\unistd.d : src\core\sys\linux\unistd.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\auxv.d : src\core\sys\linux\sys\auxv.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\inotify.d : src\core\sys\linux\sys\inotify.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\mman.d : src\core\sys\linux\sys\mman.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\signalfd.d : src\core\sys\linux\sys\signalfd.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\socket.d : src\core\sys\linux\sys\socket.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\sysinfo.d : src\core\sys\linux\sys\sysinfo.d copy $** $@ $(IMPDIR)\core\sys\linux\sys\xattr.d : src\core\sys\linux\sys\xattr.d copy $** $@ $(IMPDIR)\core\sys\osx\execinfo.d : src\core\sys\osx\execinfo.d copy $** $@ $(IMPDIR)\core\sys\osx\pthread.d : src\core\sys\osx\pthread.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\dyld.d : src\core\sys\osx\mach\dyld.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\getsect.d : src\core\sys\osx\mach\getsect.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\kern_return.d : src\core\sys\osx\mach\kern_return.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\loader.d : src\core\sys\osx\mach\loader.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\port.d : src\core\sys\osx\mach\port.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\semaphore.d : src\core\sys\osx\mach\semaphore.d copy $** $@ $(IMPDIR)\core\sys\osx\mach\thread_act.d : src\core\sys\osx\mach\thread_act.d copy $** $@ $(IMPDIR)\core\sys\osx\sys\cdefs.d : src\core\sys\osx\sys\cdefs.d copy $** $@ $(IMPDIR)\core\sys\osx\sys\mman.d : src\core\sys\osx\sys\mman.d copy $** $@ $(IMPDIR)\core\sys\posix\arpa\inet.d : src\core\sys\posix\arpa\inet.d copy $** $@ $(IMPDIR)\core\sys\posix\config.d : src\core\sys\posix\config.d copy $** $@ $(IMPDIR)\core\sys\posix\dirent.d : src\core\sys\posix\dirent.d copy $** $@ $(IMPDIR)\core\sys\posix\dlfcn.d : src\core\sys\posix\dlfcn.d copy $** $@ $(IMPDIR)\core\sys\posix\fcntl.d : src\core\sys\posix\fcntl.d copy $** $@ $(IMPDIR)\core\sys\posix\grp.d : src\core\sys\posix\grp.d copy $** $@ $(IMPDIR)\core\sys\posix\inttypes.d : src\core\sys\posix\inttypes.d copy $** $@ $(IMPDIR)\core\sys\posix\netdb.d : src\core\sys\posix\netdb.d copy $** $@ $(IMPDIR)\core\sys\posix\net\if_.d : src\core\sys\posix\net\if_.d copy $** $@ $(IMPDIR)\core\sys\posix\netinet\in_.d : src\core\sys\posix\netinet\in_.d copy $** $@ $(IMPDIR)\core\sys\posix\netinet\tcp.d : src\core\sys\posix\netinet\tcp.d copy $** $@ $(IMPDIR)\core\sys\posix\poll.d : src\core\sys\posix\poll.d copy $** $@ $(IMPDIR)\core\sys\posix\pthread.d : src\core\sys\posix\pthread.d copy $** $@ $(IMPDIR)\core\sys\posix\pwd.d : src\core\sys\posix\pwd.d copy $** $@ $(IMPDIR)\core\sys\posix\sched.d : src\core\sys\posix\sched.d copy $** $@ $(IMPDIR)\core\sys\posix\semaphore.d : src\core\sys\posix\semaphore.d copy $** $@ $(IMPDIR)\core\sys\posix\setjmp.d : src\core\sys\posix\setjmp.d copy $** $@ $(IMPDIR)\core\sys\posix\signal.d : src\core\sys\posix\signal.d copy $** $@ $(IMPDIR)\core\sys\posix\stdio.d : src\core\sys\posix\stdio.d copy $** $@ $(IMPDIR)\core\sys\posix\stdlib.d : src\core\sys\posix\stdlib.d copy $** $@ $(IMPDIR)\core\sys\posix\syslog.d : src\core\sys\posix\syslog.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\ioctl.d : src\core\sys\posix\sys\ioctl.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\ipc.d : src\core\sys\posix\sys\ipc.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\mman.d : src\core\sys\posix\sys\mman.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\resource.d : src\core\sys\posix\sys\resource.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\select.d : src\core\sys\posix\sys\select.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\shm.d : src\core\sys\posix\sys\shm.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\socket.d : src\core\sys\posix\sys\socket.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\stat.d : src\core\sys\posix\sys\stat.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\statvfs.d : src\core\sys\posix\sys\statvfs.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\time.d : src\core\sys\posix\sys\time.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\types.d : src\core\sys\posix\sys\types.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\uio.d : src\core\sys\posix\sys\uio.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\un.d : src\core\sys\posix\sys\un.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\wait.d : src\core\sys\posix\sys\wait.d copy $** $@ $(IMPDIR)\core\sys\posix\sys\utsname.d : src\core\sys\posix\sys\utsname.d copy $** $@ $(IMPDIR)\core\sys\posix\termios.d : src\core\sys\posix\termios.d copy $** $@ $(IMPDIR)\core\sys\posix\time.d : src\core\sys\posix\time.d copy $** $@ $(IMPDIR)\core\sys\posix\ucontext.d : src\core\sys\posix\ucontext.d copy $** $@ $(IMPDIR)\core\sys\posix\unistd.d : src\core\sys\posix\unistd.d copy $** $@ $(IMPDIR)\core\sys\posix\utime.d : src\core\sys\posix\utime.d copy $** $@ $(IMPDIR)\core\sys\solaris\dlfcn.d : src\core\sys\solaris\dlfcn.d copy $** $@ $(IMPDIR)\core\sys\solaris\elf.d : src\core\sys\solaris\elf.d copy $** $@ $(IMPDIR)\core\sys\solaris\execinfo.d : src\core\sys\solaris\execinfo.d copy $** $@ $(IMPDIR)\core\sys\solaris\libelf.d : src\core\sys\solaris\libelf.d copy $** $@ $(IMPDIR)\core\sys\solaris\link.d : src\core\sys\solaris\link.d copy $** $@ $(IMPDIR)\core\sys\solaris\time.d : src\core\sys\solaris\time.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf.d : src\core\sys\solaris\sys\elf.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf_386.d : src\core\sys\solaris\sys\elf_386.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf_amd64.d : src\core\sys\solaris\sys\elf_amd64.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf_notes.d : src\core\sys\solaris\sys\elf_notes.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elf_SPARC.d : src\core\sys\solaris\sys\elf_SPARC.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\elftypes.d : src\core\sys\solaris\sys\elftypes.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\link.d : src\core\sys\solaris\sys\link.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\procset.d : src\core\sys\solaris\sys\procset.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\types.d : src\core\sys\solaris\sys\types.d copy $** $@ $(IMPDIR)\core\sys\solaris\sys\priocntl.d : src\core\sys\solaris\sys\priocntl.d copy $** $@ $(IMPDIR)\core\sys\windows\accctrl.d : src\core\sys\windows\accctrl.d copy $** $@ $(IMPDIR)\core\sys\windows\aclapi.d : src\core\sys\windows\aclapi.d copy $** $@ $(IMPDIR)\core\sys\windows\aclui.d : src\core\sys\windows\aclui.d copy $** $@ $(IMPDIR)\core\sys\windows\basetsd.d : src\core\sys\windows\basetsd.d copy $** $@ $(IMPDIR)\core\sys\windows\basetyps.d : src\core\sys\windows\basetyps.d copy $** $@ $(IMPDIR)\core\sys\windows\cderr.d : src\core\sys\windows\cderr.d copy $** $@ $(IMPDIR)\core\sys\windows\cguid.d : src\core\sys\windows\cguid.d copy $** $@ $(IMPDIR)\core\sys\windows\com.d : src\core\sys\windows\com.d copy $** $@ $(IMPDIR)\core\sys\windows\comcat.d : src\core\sys\windows\comcat.d copy $** $@ $(IMPDIR)\core\sys\windows\commctrl.d : src\core\sys\windows\commctrl.d copy $** $@ $(IMPDIR)\core\sys\windows\commdlg.d : src\core\sys\windows\commdlg.d copy $** $@ $(IMPDIR)\core\sys\windows\core.d : src\core\sys\windows\core.d copy $** $@ $(IMPDIR)\core\sys\windows\cpl.d : src\core\sys\windows\cpl.d copy $** $@ $(IMPDIR)\core\sys\windows\cplext.d : src\core\sys\windows\cplext.d copy $** $@ $(IMPDIR)\core\sys\windows\custcntl.d : src\core\sys\windows\custcntl.d copy $** $@ $(IMPDIR)\core\sys\windows\dbghelp.d : src\core\sys\windows\dbghelp.d copy $** $@ $(IMPDIR)\core\sys\windows\dbghelp_types.d : src\core\sys\windows\dbghelp_types.d copy $** $@ $(IMPDIR)\core\sys\windows\dbt.d : src\core\sys\windows\dbt.d copy $** $@ $(IMPDIR)\core\sys\windows\dde.d : src\core\sys\windows\dde.d copy $** $@ $(IMPDIR)\core\sys\windows\ddeml.d : src\core\sys\windows\ddeml.d copy $** $@ $(IMPDIR)\core\sys\windows\dhcpcsdk.d : src\core\sys\windows\dhcpcsdk.d copy $** $@ $(IMPDIR)\core\sys\windows\dlgs.d : src\core\sys\windows\dlgs.d copy $** $@ $(IMPDIR)\core\sys\windows\dll.d : src\core\sys\windows\dll.d copy $** $@ $(IMPDIR)\core\sys\windows\docobj.d : src\core\sys\windows\docobj.d copy $** $@ $(IMPDIR)\core\sys\windows\errorrep.d : src\core\sys\windows\errorrep.d copy $** $@ $(IMPDIR)\core\sys\windows\exdisp.d : src\core\sys\windows\exdisp.d copy $** $@ $(IMPDIR)\core\sys\windows\exdispid.d : src\core\sys\windows\exdispid.d copy $** $@ $(IMPDIR)\core\sys\windows\httpext.d : src\core\sys\windows\httpext.d copy $** $@ $(IMPDIR)\core\sys\windows\idispids.d : src\core\sys\windows\idispids.d copy $** $@ $(IMPDIR)\core\sys\windows\imagehlp.d : src\core\sys\windows\imagehlp.d copy $** $@ $(IMPDIR)\core\sys\windows\imm.d : src\core\sys\windows\imm.d copy $** $@ $(IMPDIR)\core\sys\windows\intshcut.d : src\core\sys\windows\intshcut.d copy $** $@ $(IMPDIR)\core\sys\windows\ipexport.d : src\core\sys\windows\ipexport.d copy $** $@ $(IMPDIR)\core\sys\windows\iphlpapi.d : src\core\sys\windows\iphlpapi.d copy $** $@ $(IMPDIR)\core\sys\windows\ipifcons.d : src\core\sys\windows\ipifcons.d copy $** $@ $(IMPDIR)\core\sys\windows\iprtrmib.d : src\core\sys\windows\iprtrmib.d copy $** $@ $(IMPDIR)\core\sys\windows\iptypes.d : src\core\sys\windows\iptypes.d copy $** $@ $(IMPDIR)\core\sys\windows\isguids.d : src\core\sys\windows\isguids.d copy $** $@ $(IMPDIR)\core\sys\windows\lm.d : src\core\sys\windows\lm.d copy $** $@ $(IMPDIR)\core\sys\windows\lmaccess.d : src\core\sys\windows\lmaccess.d copy $** $@ $(IMPDIR)\core\sys\windows\lmalert.d : src\core\sys\windows\lmalert.d copy $** $@ $(IMPDIR)\core\sys\windows\lmapibuf.d : src\core\sys\windows\lmapibuf.d copy $** $@ $(IMPDIR)\core\sys\windows\lmat.d : src\core\sys\windows\lmat.d copy $** $@ $(IMPDIR)\core\sys\windows\lmaudit.d : src\core\sys\windows\lmaudit.d copy $** $@ $(IMPDIR)\core\sys\windows\lmbrowsr.d : src\core\sys\windows\lmbrowsr.d copy $** $@ $(IMPDIR)\core\sys\windows\lmchdev.d : src\core\sys\windows\lmchdev.d copy $** $@ $(IMPDIR)\core\sys\windows\lmconfig.d : src\core\sys\windows\lmconfig.d copy $** $@ $(IMPDIR)\core\sys\windows\lmcons.d : src\core\sys\windows\lmcons.d copy $** $@ $(IMPDIR)\core\sys\windows\lmerr.d : src\core\sys\windows\lmerr.d copy $** $@ $(IMPDIR)\core\sys\windows\lmerrlog.d : src\core\sys\windows\lmerrlog.d copy $** $@ $(IMPDIR)\core\sys\windows\lmmsg.d : src\core\sys\windows\lmmsg.d copy $** $@ $(IMPDIR)\core\sys\windows\lmremutl.d : src\core\sys\windows\lmremutl.d copy $** $@ $(IMPDIR)\core\sys\windows\lmrepl.d : src\core\sys\windows\lmrepl.d copy $** $@ $(IMPDIR)\core\sys\windows\lmserver.d : src\core\sys\windows\lmserver.d copy $** $@ $(IMPDIR)\core\sys\windows\lmshare.d : src\core\sys\windows\lmshare.d copy $** $@ $(IMPDIR)\core\sys\windows\lmsname.d : src\core\sys\windows\lmsname.d copy $** $@ $(IMPDIR)\core\sys\windows\lmstats.d : src\core\sys\windows\lmstats.d copy $** $@ $(IMPDIR)\core\sys\windows\lmsvc.d : src\core\sys\windows\lmsvc.d copy $** $@ $(IMPDIR)\core\sys\windows\lmuse.d : src\core\sys\windows\lmuse.d copy $** $@ $(IMPDIR)\core\sys\windows\lmuseflg.d : src\core\sys\windows\lmuseflg.d copy $** $@ $(IMPDIR)\core\sys\windows\lmwksta.d : src\core\sys\windows\lmwksta.d copy $** $@ $(IMPDIR)\core\sys\windows\lzexpand.d : src\core\sys\windows\lzexpand.d copy $** $@ $(IMPDIR)\core\sys\windows\mapi.d : src\core\sys\windows\mapi.d copy $** $@ $(IMPDIR)\core\sys\windows\mciavi.d : src\core\sys\windows\mciavi.d copy $** $@ $(IMPDIR)\core\sys\windows\mcx.d : src\core\sys\windows\mcx.d copy $** $@ $(IMPDIR)\core\sys\windows\mgmtapi.d : src\core\sys\windows\mgmtapi.d copy $** $@ $(IMPDIR)\core\sys\windows\mmsystem.d : src\core\sys\windows\mmsystem.d copy $** $@ $(IMPDIR)\core\sys\windows\msacm.d : src\core\sys\windows\msacm.d copy $** $@ $(IMPDIR)\core\sys\windows\mshtml.d : src\core\sys\windows\mshtml.d copy $** $@ $(IMPDIR)\core\sys\windows\mswsock.d : src\core\sys\windows\mswsock.d copy $** $@ $(IMPDIR)\core\sys\windows\nb30.d : src\core\sys\windows\nb30.d copy $** $@ $(IMPDIR)\core\sys\windows\nddeapi.d : src\core\sys\windows\nddeapi.d copy $** $@ $(IMPDIR)\core\sys\windows\nspapi.d : src\core\sys\windows\nspapi.d copy $** $@ $(IMPDIR)\core\sys\windows\ntdef.d : src\core\sys\windows\ntdef.d copy $** $@ $(IMPDIR)\core\sys\windows\ntdll.d : src\core\sys\windows\ntdll.d copy $** $@ $(IMPDIR)\core\sys\windows\ntldap.d : src\core\sys\windows\ntldap.d copy $** $@ $(IMPDIR)\core\sys\windows\ntsecapi.d : src\core\sys\windows\ntsecapi.d copy $** $@ $(IMPDIR)\core\sys\windows\ntsecpkg.d : src\core\sys\windows\ntsecpkg.d copy $** $@ $(IMPDIR)\core\sys\windows\oaidl.d : src\core\sys\windows\oaidl.d copy $** $@ $(IMPDIR)\core\sys\windows\objbase.d : src\core\sys\windows\objbase.d copy $** $@ $(IMPDIR)\core\sys\windows\objfwd.d : src\core\sys\windows\objfwd.d copy $** $@ $(IMPDIR)\core\sys\windows\objidl.d : src\core\sys\windows\objidl.d copy $** $@ $(IMPDIR)\core\sys\windows\objsafe.d : src\core\sys\windows\objsafe.d copy $** $@ $(IMPDIR)\core\sys\windows\ocidl.d : src\core\sys\windows\ocidl.d copy $** $@ $(IMPDIR)\core\sys\windows\odbcinst.d : src\core\sys\windows\odbcinst.d copy $** $@ $(IMPDIR)\core\sys\windows\ole.d : src\core\sys\windows\ole.d copy $** $@ $(IMPDIR)\core\sys\windows\ole2.d : src\core\sys\windows\ole2.d copy $** $@ $(IMPDIR)\core\sys\windows\ole2ver.d : src\core\sys\windows\ole2ver.d copy $** $@ $(IMPDIR)\core\sys\windows\oleacc.d : src\core\sys\windows\oleacc.d copy $** $@ $(IMPDIR)\core\sys\windows\oleauto.d : src\core\sys\windows\oleauto.d copy $** $@ $(IMPDIR)\core\sys\windows\olectl.d : src\core\sys\windows\olectl.d copy $** $@ $(IMPDIR)\core\sys\windows\olectlid.d : src\core\sys\windows\olectlid.d copy $** $@ $(IMPDIR)\core\sys\windows\oledlg.d : src\core\sys\windows\oledlg.d copy $** $@ $(IMPDIR)\core\sys\windows\oleidl.d : src\core\sys\windows\oleidl.d copy $** $@ $(IMPDIR)\core\sys\windows\pbt.d : src\core\sys\windows\pbt.d copy $** $@ $(IMPDIR)\core\sys\windows\powrprof.d : src\core\sys\windows\powrprof.d copy $** $@ $(IMPDIR)\core\sys\windows\prsht.d : src\core\sys\windows\prsht.d copy $** $@ $(IMPDIR)\core\sys\windows\psapi.d : src\core\sys\windows\psapi.d copy $** $@ $(IMPDIR)\core\sys\windows\rapi.d : src\core\sys\windows\rapi.d copy $** $@ $(IMPDIR)\core\sys\windows\ras.d : src\core\sys\windows\ras.d copy $** $@ $(IMPDIR)\core\sys\windows\rasdlg.d : src\core\sys\windows\rasdlg.d copy $** $@ $(IMPDIR)\core\sys\windows\raserror.d : src\core\sys\windows\raserror.d copy $** $@ $(IMPDIR)\core\sys\windows\rassapi.d : src\core\sys\windows\rassapi.d copy $** $@ $(IMPDIR)\core\sys\windows\reason.d : src\core\sys\windows\reason.d copy $** $@ $(IMPDIR)\core\sys\windows\regstr.d : src\core\sys\windows\regstr.d copy $** $@ $(IMPDIR)\core\sys\windows\richedit.d : src\core\sys\windows\richedit.d copy $** $@ $(IMPDIR)\core\sys\windows\richole.d : src\core\sys\windows\richole.d copy $** $@ $(IMPDIR)\core\sys\windows\rpc.d : src\core\sys\windows\rpc.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcdce.d : src\core\sys\windows\rpcdce.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcdce2.d : src\core\sys\windows\rpcdce2.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcdcep.d : src\core\sys\windows\rpcdcep.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcndr.d : src\core\sys\windows\rpcndr.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcnsi.d : src\core\sys\windows\rpcnsi.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcnsip.d : src\core\sys\windows\rpcnsip.d copy $** $@ $(IMPDIR)\core\sys\windows\rpcnterr.d : src\core\sys\windows\rpcnterr.d copy $** $@ $(IMPDIR)\core\sys\windows\schannel.d : src\core\sys\windows\schannel.d copy $** $@ $(IMPDIR)\core\sys\windows\secext.d : src\core\sys\windows\secext.d copy $** $@ $(IMPDIR)\core\sys\windows\security.d : src\core\sys\windows\security.d copy $** $@ $(IMPDIR)\core\sys\windows\servprov.d : src\core\sys\windows\servprov.d copy $** $@ $(IMPDIR)\core\sys\windows\setupapi.d : src\core\sys\windows\setupapi.d copy $** $@ $(IMPDIR)\core\sys\windows\shellapi.d : src\core\sys\windows\shellapi.d copy $** $@ $(IMPDIR)\core\sys\windows\shldisp.d : src\core\sys\windows\shldisp.d copy $** $@ $(IMPDIR)\core\sys\windows\shlguid.d : src\core\sys\windows\shlguid.d copy $** $@ $(IMPDIR)\core\sys\windows\shlobj.d : src\core\sys\windows\shlobj.d copy $** $@ $(IMPDIR)\core\sys\windows\shlwapi.d : src\core\sys\windows\shlwapi.d copy $** $@ $(IMPDIR)\core\sys\windows\snmp.d : src\core\sys\windows\snmp.d copy $** $@ $(IMPDIR)\core\sys\windows\sql.d : src\core\sys\windows\sql.d copy $** $@ $(IMPDIR)\core\sys\windows\sqlext.d : src\core\sys\windows\sqlext.d copy $** $@ $(IMPDIR)\core\sys\windows\sqltypes.d : src\core\sys\windows\sqltypes.d copy $** $@ $(IMPDIR)\core\sys\windows\sqlucode.d : src\core\sys\windows\sqlucode.d copy $** $@ $(IMPDIR)\core\sys\windows\sspi.d : src\core\sys\windows\sspi.d copy $** $@ $(IMPDIR)\core\sys\windows\stacktrace.d : src\core\sys\windows\stacktrace.d copy $** $@ $(IMPDIR)\core\sys\windows\stat.d : src\core\sys\windows\stat.d copy $** $@ $(IMPDIR)\core\sys\windows\subauth.d : src\core\sys\windows\subauth.d copy $** $@ $(IMPDIR)\core\sys\windows\threadaux.d : src\core\sys\windows\threadaux.d copy $** $@ $(IMPDIR)\core\sys\windows\tlhelp32.d : src\core\sys\windows\tlhelp32.d copy $** $@ $(IMPDIR)\core\sys\windows\tmschema.d : src\core\sys\windows\tmschema.d copy $** $@ $(IMPDIR)\core\sys\windows\unknwn.d : src\core\sys\windows\unknwn.d copy $** $@ $(IMPDIR)\core\sys\windows\uuid.d : src\core\sys\windows\uuid.d copy $** $@ $(IMPDIR)\core\sys\windows\vfw.d : src\core\sys\windows\vfw.d copy $** $@ $(IMPDIR)\core\sys\windows\w32api.d : src\core\sys\windows\w32api.d copy $** $@ $(IMPDIR)\core\sys\windows\winbase.d : src\core\sys\windows\winbase.d copy $** $@ $(IMPDIR)\core\sys\windows\winber.d : src\core\sys\windows\winber.d copy $** $@ $(IMPDIR)\core\sys\windows\wincon.d : src\core\sys\windows\wincon.d copy $** $@ $(IMPDIR)\core\sys\windows\wincrypt.d : src\core\sys\windows\wincrypt.d copy $** $@ $(IMPDIR)\core\sys\windows\windef.d : src\core\sys\windows\windef.d copy $** $@ $(IMPDIR)\core\sys\windows\windows.d : src\core\sys\windows\windows.d copy $** $@ $(IMPDIR)\core\sys\windows\winerror.d : src\core\sys\windows\winerror.d copy $** $@ $(IMPDIR)\core\sys\windows\wingdi.d : src\core\sys\windows\wingdi.d copy $** $@ $(IMPDIR)\core\sys\windows\winhttp.d : src\core\sys\windows\winhttp.d copy $** $@ $(IMPDIR)\core\sys\windows\wininet.d : src\core\sys\windows\wininet.d copy $** $@ $(IMPDIR)\core\sys\windows\winioctl.d : src\core\sys\windows\winioctl.d copy $** $@ $(IMPDIR)\core\sys\windows\winldap.d : src\core\sys\windows\winldap.d copy $** $@ $(IMPDIR)\core\sys\windows\winnetwk.d : src\core\sys\windows\winnetwk.d copy $** $@ $(IMPDIR)\core\sys\windows\winnls.d : src\core\sys\windows\winnls.d copy $** $@ $(IMPDIR)\core\sys\windows\winnt.d : src\core\sys\windows\winnt.d copy $** $@ $(IMPDIR)\core\sys\windows\winperf.d : src\core\sys\windows\winperf.d copy $** $@ $(IMPDIR)\core\sys\windows\winreg.d : src\core\sys\windows\winreg.d copy $** $@ $(IMPDIR)\core\sys\windows\winsock2.d : src\core\sys\windows\winsock2.d copy $** $@ $(IMPDIR)\core\sys\windows\winspool.d : src\core\sys\windows\winspool.d copy $** $@ $(IMPDIR)\core\sys\windows\winsvc.d : src\core\sys\windows\winsvc.d copy $** $@ $(IMPDIR)\core\sys\windows\winuser.d : src\core\sys\windows\winuser.d copy $** $@ $(IMPDIR)\core\sys\windows\winver.d : src\core\sys\windows\winver.d copy $** $@ $(IMPDIR)\core\sys\windows\wtsapi32.d : src\core\sys\windows\wtsapi32.d copy $** $@ $(IMPDIR)\core\sys\windows\wtypes.d : src\core\sys\windows\wtypes.d copy $** $@ $(IMPDIR)\etc\linux\memoryerror.d : src\etc\linux\memoryerror.d copy $** $@ ################### C\ASM Targets ############################ errno_c_$(MODEL).obj : src\core\stdc\errno.c $(CC) -c -Fo$@ $(CFLAGS) src\core\stdc\errno.c msvc_$(MODEL).obj : src\rt\msvc.c win64.mak $(CC) -c -Fo$@ $(CFLAGS) src\rt\msvc.c msvc_math_$(MODEL).obj : src\rt\msvc_math.c win64.mak $(CC) -c -Fo$@ $(CFLAGS) src\rt\msvc_math.c ################### gcstub generation ######################### $(GCSTUB) : src\gcstub\gc.d win64.mak $(DMD) -c -of$(GCSTUB) src\gcstub\gc.d $(DFLAGS) ################### Library generation ######################### $(DRUNTIME): $(OBJS) $(SRCS) win64.mak $(DMD) -lib -of$(DRUNTIME) -Xfdruntime.json $(DFLAGS) $(SRCS) $(OBJS) # due to -conf= on the command line, LINKCMD and LIB need to be set in the environment unittest : $(SRCS) $(DRUNTIME) $(DMD) $(UDFLAGS) -version=druntime_unittest -unittest -ofunittest.exe -main $(SRCS) $(DRUNTIME) -debuglib=$(DRUNTIME) -defaultlib=$(DRUNTIME) user32.lib unittest ################### Win32 COFF support ######################### # default to 32-bit compiler relative to 64-bit compiler, link and lib are architecture agnostic CC32=$(CC)\..\..\cl druntime32mscoff: $(MAKE) -f win64.mak "DMD=$(DMD)" MODEL=32mscoff "CC=\$(CC32)"\"" "AR=\$(AR)"\"" "VCDIR=$(VCDIR)" "SDKDIR=$(SDKDIR)" unittest32mscoff: $(MAKE) -f win64.mak "DMD=$(DMD)" MODEL=32mscoff "CC=\$(CC32)"\"" "AR=\$(AR)"\"" "VCDIR=$(VCDIR)" "SDKDIR=$(SDKDIR)" unittest ################### zip/install/clean ########################## zip: druntime.zip druntime.zip: import del druntime.zip git ls-tree --name-only -r HEAD >MANIFEST.tmp zip32 -T -ur druntime @MANIFEST.tmp del MANIFEST.tmp install: druntime.zip unzip -o druntime.zip -d \dmd2\src\druntime clean: del $(DRUNTIME) $(OBJS_TO_DELETE) $(GCSTUB) rmdir /S /Q $(DOCDIR) $(IMPDIR) auto-tester-build: target auto-tester-test: unittest ldc-1.1.0-beta3-src/tests/0000775000175000017500000000000012776214734013307 5ustar kaikaildc-1.1.0-beta3-src/tests/codegen/0000775000175000017500000000000012776214734014713 5ustar kaikaildc-1.1.0-beta3-src/tests/codegen/nothrow.d0000664000175000017500000000330212776214734016556 0ustar kaikai// RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll struct S { ~this() nothrow {} void foo() nothrow { throw new Error("foo"); } } struct Throwing { ~this() {} void bar() { throw new Exception("bar"); } } // CHECK-LABEL: define{{.*}} @{{.*}}_D7nothrow15inTryCatchErrorFZv void inTryCatchError() { try { // make sure the nothrow functions S.foo() and S.~this() // are invoked in try-blocks with at least 1 catch block S a; // CHECK: invoke {{.*}}_D7nothrow1S3fooMFNbZv{{.*}} %a a.foo(); // CHECK: invoke {{.*}}_D7nothrow1S6__dtorMFNbZv{{.*}} %a } catch (Error) {} } // CHECK-LABEL: define{{.*}} @{{.*}}_D7nothrow19inTryCatchExceptionFZv void inTryCatchException() { // make sure the nothrow functions are never invoked // CHECK-NOT: invoke {{.*}}_D7nothrow1S3fooMFNbZv // CHECK-NOT: invoke {{.*}}_D7nothrow1S6__dtorMFNbZv try { S a; a.foo(); } catch (Exception) {} } // CHECK-LABEL: define{{.*}} @{{.*}}_D7nothrow12inTryFinallyFZv void inTryFinally() { // make sure the nothrow functions are never invoked // CHECK-NOT: invoke {{.*}}_D7nothrow1S3fooMFNbZv // CHECK-NOT: invoke {{.*}}_D7nothrow1S6__dtorMFNbZv try { S a; a.foo(); } finally { S b; b.foo(); } } // CHECK-LABEL: define{{.*}} @{{.*}}_Dmain void main() { // make sure the nothrow functions are never invoked // CHECK-NOT: invoke {{.*}}_D7nothrow1S3fooMFNbZv // CHECK-NOT: invoke {{.*}}_D7nothrow1S6__dtorMFNbZv Throwing t; S a; a.foo(); t.bar(); { S b; t.bar(); b.foo(); S().foo(); } } ldc-1.1.0-beta3-src/tests/codegen/inlineIR_math.d0000664000175000017500000000665112776214734017612 0ustar kaikai// Tests inlineIR + math optimizations // REQUIRES: target_X86 // RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s --check-prefix LLVM < %t.ll // RUN: %ldc -mtriple=x86_64-linux-gnu -mattr=+fma -O3 -release -c -output-s -of=%t.s %s && FileCheck %s --check-prefix ASM < %t.s import ldc.attributes; pragma(LDC_inline_ir) R inlineIR(string s, R, P...)(P); // Test that internal @inline.ir.*" functions for the inlined IR pieces are always inlined and are not present as a global symbol // LLVM-NOT: @inline.ir. // LLVM-NOT: alwaysinline // inlineIR should inherit the enclosing function attributes, thus preserving the enclosing function attributes after inlining. // LLVM-LABEL: define{{.*}} @dot // LLVM-SAME: #[[UNSAFEFPMATH:[0-9]+]] // ASM-LABEL: dot: @llvmAttr("unsafe-fp-math", "true") extern (C) double dot(double[] a, double[] b) { double s = 0; // ASM: vfmadd{{[123][123][123]}}pd foreach (size_t i; 0 .. a.length) { s = inlineIR!(`%p = fmul fast double %0, %1 %r = fadd fast double %p, %2 ret double %r`, double)(a[i], b[i], s); } return s; } // LLVM-LABEL: define{{.*}} @features // LLVM-SAME: #[[FEAT:[0-9]+]] @target("fma") extern (C) double features(double[] a, double[] b) { double s = 0; foreach (size_t i; 0 .. a.length) { s = inlineIR!(`%p = fmul fast double %0, %1 %r = fadd fast double %p, %2 ret double %r`, double)(a[i], b[i], s); } return s; } // Test that inlineIR works when calling function has special attributes defined for its parameters // LLVM-LABEL: define{{.*}} @dot160 // ASM-LABEL: dot160: extern (C) double dot160(double[160] a, double[160] b) { double s = 0; // ASM-NOT: vfmadd foreach (size_t i; 0 .. a.length) { s = inlineIR!(`%p = fmul fast double %0, %1 %r = fadd fast double %p, %2 ret double %r`, double)(a[i], b[i], s); } return s; } // Test inlineIR alias defined outside any function alias inlineIR!(`%p = fmul fast double %0, %1 %r = fadd fast double %p, %2 ret double %r`, double, double, double, double) muladd; // LLVM-LABEL: define{{.*}} @aliasInlineUnsafe // LLVM-SAME: #[[UNSAFEFPMATH2:[0-9]+]] // ASM-LABEL: aliasInlineUnsafe: @llvmAttr("unsafe-fp-math", "true") extern (C) double aliasInlineUnsafe(double[] a, double[] b) { double s = 0; // ASM: vfmadd{{[123][123][123]}}pd foreach (size_t i; 0 .. a.length) { s = muladd(a[i], b[i], s); } return s; } // LLVM-LABEL: define{{.*}} @aliasInlineSafe // LLVM-SAME: #[[UNSAFEFPMATH3:[0-9]+]] // ASM-LABEL: aliasInlineSafe: extern (C) double aliasInlineSafe(double[] a, double[] b) { double s = 0; // ASM-NOT: vfmadd{{[123][123][123]}}pd foreach (size_t i; 0 .. a.length) { s = muladd(a[i], b[i], s); } return s; } // Make sure an enclosing function's 'noinline' attribute isn't copied to // the inlined IR function (having 'alwaysinline') (issue #1711). double neverInlinedEnclosingFunction() { pragma(inline, false); return muladd(1.0, 2.0, 3.0); } // LLVM-DAG: attributes #[[UNSAFEFPMATH]] ={{.*}} "unsafe-fp-math"="true" // LLVM-DAG: attributes #[[UNSAFEFPMATH2]] ={{.*}} "unsafe-fp-math"="true" // LLVM-DAG: attributes #[[UNSAFEFPMATH3]] ={{.*}} "unsafe-fp-math"="false" // LLVM-DAG: attributes #[[FEAT]] ={{.*}} "target-features"="+fma" ldc-1.1.0-beta3-src/tests/codegen/func_contracts_gh1543.d0000664000175000017500000000223712776214734021072 0ustar kaikai// Test the combination of `out` arguments with in- and out-contracts. // Github issue #1543, https://github.com/ldc-developers/ldc/issues/1543 // RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll // RUN: %ldc -run %s module mod; class Bar { void failMe(out int some) in { assert(some == 0); } out { assert(some == 123); } body { some = 123; } } // Bar.failMe codegen order = function, in-contract __require function, out-contract __ensure function // CHECK-LABEL: define {{.*}} @{{.*}}Bar6failMe // CHECK-SAME: i32* dereferenceable(4) %some // CHECK: store i32 0, i32* %some // CHECK: call {{.*}} @{{.*}}Bar6failMeMFJiZ9__require // CHECK: call {{.*}} @{{.*}}Bar6failMeMFJiZ8__ensure // CHECK: } // CHECK-LABEL: define {{.*}} @{{.*}}Bar6failMeMFJiZ9__require // CHECK-SAME: i32* dereferenceable(4) %some // CHECK-NOT: store {{.*}} %some // CHECK: } // CHECK-LABEL: define {{.*}} @{{.*}}Bar6failMeMFJiZ8__ensure // CHECK-SAME: i32* dereferenceable(4) %some // CHECK-NOT: store {{.*}} %some // CHECK: } void main() { int some; auto b = new Bar; b.failMe(some); assert(some == 123); } ldc-1.1.0-beta3-src/tests/codegen/inlining_staticvar.d0000664000175000017500000000344212776214734020752 0ustar kaikai// Test cross-module inlining involving static variables // REQUIRES: atleast_llvm307 // RUN: %ldc %s -I%S -c -output-ll -O3 -of=%t.O3.ll && FileCheck %s --check-prefix OPT3 < %t.O3.ll // RUN: %ldc %s -I%S -c -output-ll -enable-inlining -O0 -of=%t.O0.ll && FileCheck %s --check-prefix OPT0 < %t.O0.ll // RUN: %ldc -I%S -enable-inlining %S/inputs/inlinables_staticvar.d -run %s // RUN: %ldc -I%S -O3 %S/inputs/inlinables_staticvar.d -run %s import inputs.inlinables_staticvar; import ldc.attributes; extern (C): // simplify mangling for easier matching // Functions are intentionally split and @weak to thwart LLVM constant folding. void checkModuleScope_1() @weak { addToModuleScopeInline(7); } void checkModuleScope_2() @weak { addToModuleScopeOutline(101); assert(equalModuleScope(7+101)); } void checkInsideFunc_1() @weak { assert(addAndCheckInsideFunc(0, 7)); } void checkInsideFunc_2() @weak { assert(addAndCheckInsideFuncIndirect(7, 101)); assert(addAndCheckInsideFunc(7+101, 9)); } void checkInsideNestedFunc_1() @weak { assert(addAndCheckInsideNestedFunc(0, 7)); } void checkInsideNestedFunc_2() @weak { assert(addAndCheckInsideNestedFuncIndirect(7, 101)); assert(addAndCheckInsideNestedFunc(7+101, 9)); } void checkNestedStruct_1() @weak { assert(addAndCheckNestedStruct(0, 7)); } void checkNestedStruct_2() @weak { assert(addAndCheckNestedStructIndirect(7, 101)); assert(addAndCheckNestedStruct(7+101, 9)); } // OPT0-LABEL: define{{.*}} @_Dmain( // OPT3-LABEL: define{{.*}} @_Dmain( extern(D) void main() { checkModuleScope_1(); checkModuleScope_2(); checkInsideFunc_1(); checkInsideFunc_2(); checkInsideNestedFunc_1(); checkInsideNestedFunc_2(); checkNestedStruct_1(); checkNestedStruct_2(); } ldc-1.1.0-beta3-src/tests/codegen/attr_optstrat.d0000664000175000017500000000257512776214734020003 0ustar kaikai// RUN: %ldc -I%S -c -output-ll -O3 -of=%t.ll %s && FileCheck %s < %t.ll import ldc.attributes; extern (C): // For easier name mangling int glob1; int easily_inlinable(int i) { glob1 = i; return 2; } // CHECK-LABEL: define{{.*}} @call_easily_inlinable( // CHECK-SAME: #[[OPTNONE:[0-9]+]] @optStrategy("none") int call_easily_inlinable(int i) { // CHECK: call {{.*}} @easily_inlinable( return easily_inlinable(i); } pragma(inline, true) int always_inline() { return 321; } // CHECK-LABEL: define{{.*}} @call_always_inline( @optStrategy("none") int call_always_inline() { // CHECK-NOT: call {{.*}} @always_inline() return always_inline(); // CHECK: ret i32 321 } // optnone functions should not be inlined. int glob2; @optStrategy("none") void optnone_function(int i) { glob2 = i; } // CHECK-LABEL: define{{.*}} @call_optnone( void call_optnone() { // CHECK: call {{.*}} @optnone_function optnone_function(1); } // CHECK-LABEL: define{{.*}} @foo( // CHECK-SAME: #[[OPTSIZE:[0-9]+]] @optStrategy("optsize") void foo() { } // CHECK-LABEL: define{{.*}} @foo2( // CHECK-SAME: #[[MINSIZE:[0-9]+]] @optStrategy("minsize") void foo2() { } // CHECK-DAG: attributes #[[OPTNONE]] = {{.*}} optnone // CHECK-DAG: attributes #[[OPTNONE]] = {{.*}} noinline // CHECK-DAG: attributes #[[OPTSIZE]] = {{.*}} optsize // CHECK-DAG: attributes #[[MINSIZE]] = {{.*}} minsize ldc-1.1.0-beta3-src/tests/codegen/discard_value_names_gh1749.d0000664000175000017500000000157412776214734022062 0ustar kaikai// Test value name discarding when creating non-textual IR. // REQUIRES: atleast_llvm309 // RUN: %ldc %S/inputs/input_discard_valuename.d -c -output-ll -of=%t.bar.ll && FileCheck %S/inputs/input_discard_valuename.d < %t.bar.ll // Output a bitcode file (i.e. with discarded names) and input it into a second LDC command that outputs textual IR. // RUN: %ldc %S/inputs/input_discard_valuename.d -g -c -output-bc -of=%t.bar.bc \ // RUN: && %ldc %s %t.bar.bc -g -c -output-ll -of=%t.ll && FileCheck %s < %t.ll // IR imported from the bitcode file should not have local value names: // CHECK-LABEL: define{{.*}} @foo // CHECK: %localfoovar // CHECK-LABEL: define{{.*}} @bar // CHECK-NOT: %localbarvar // But the imported IR should still have debug names: // CHECK: DILocalVariable{{.*}}"localfoovar" // CHECK: DILocalVariable{{.*}}"localbarvar" extern(C) void foo() { int localfoovar; } ldc-1.1.0-beta3-src/tests/codegen/switch_ICE_gh1638.d0000664000175000017500000000047012776214734020042 0ustar kaikai// Test for ICE bug Github issue 1638 // Don't make any changes/additions to this file without consulting GH #1638 first. // RUN: %ldc -I%S %S/inputs/switch_ICE_gh1638_bar.d %s -c // RUN: %ldc -I%S %s %S/inputs/switch_ICE_gh1638_bar.d -c import switch_ICE_gh1638_bar; int main() { return T().fun(123); } ldc-1.1.0-beta3-src/tests/codegen/attributes.d0000664000175000017500000000172112776214734017247 0ustar kaikai// Tests LDC-specific attributes // RUN: %ldc -O -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll import ldc.attributes; //---- @(section) ----------------------------------------------------- // CHECK-DAG: @{{.*}}mySectionedGlobali ={{.*}} section ".mySection" @(section(".mySection")) int mySectionedGlobal; // CHECK-DAG: define{{.*}} void @{{.*}}sectionedfoo{{.*}} section "funcSection" @(section("funcSection")) void sectionedfoo() {} //--------------------------------------------------------------------- //--------------------------------------------------------------------- //---- @(weak) -------------------------------------------------------- // CHECK-DAG: @{{.*}}myWeakGlobali = weak @(ldc.attributes.weak) int myWeakGlobal; // CHECK-DAG: define{{.*}} weak {{.*}}void @{{.*}}weakFunc @weak void weakFunc() {} //--------------------------------------------------------------------- // CHECK-LABEL: define i32 @_Dmain void main() { sectionedfoo(); } ldc-1.1.0-beta3-src/tests/codegen/simd_unaligned.d0000664000175000017500000000417612776214734020052 0ustar kaikai// Tests unaligned load and stores of SIMD types // RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll // RUN: %ldc -run %s import core.simd; import ldc.simd; // CHECK-LABEL: define{{.*}} @{{.*}}loads void loads(void *p) { // CHECK: load <4 x float>{{.*}} align 1 loadUnaligned!float4(cast(float*)p); const float[4] f4buf = void; immutable double[2] f8buf = void; ubyte[16] u1buf = void; ushort[8] u2buf = void; uint[4] u4buf = void; ulong[2] u8buf = void; byte[16] i1buf = void; short[8] i2buf = void; int[4] i4buf = void; long[2] i8buf = void; // CHECK: load <4 x float>{{.*}} align 1 loadUnaligned!float4(f4buf.ptr); // CHECK: load <2 x double>{{.*}} align 1 loadUnaligned!double2(f8buf.ptr); // CHECK: load <16 x i8>{{.*}} align 1 loadUnaligned!ubyte16(u1buf.ptr); // CHECK: load <8 x i16>{{.*}} align 1 loadUnaligned!ushort8(u2buf.ptr); // CHECK: load <4 x i32>{{.*}} align 1 loadUnaligned!uint4(u4buf.ptr); // CHECK: load <2 x i64>{{.*}} align 1 loadUnaligned!ulong2(u8buf.ptr); // CHECK: load <16 x i8>{{.*}} align 1 loadUnaligned!byte16(i1buf.ptr); // CHECK: load <8 x i16>{{.*}} align 1 loadUnaligned!short8(i2buf.ptr); // CHECK: load <4 x i32>{{.*}} align 1 loadUnaligned!int4(i4buf.ptr); // CHECK: load <2 x i64>{{.*}} align 1 loadUnaligned!long2(i8buf.ptr); } // CHECK-LABEL: define{{.*}} @{{.*}}stores void stores(void *p) { float8 f8 = void; int8 i8 = void; // CHECK: store <8 x float>{{.*}} align 1 storeUnaligned!float8(f8, cast(float*)p); // CHECK: store <8 x i32>{{.*}} align 1 storeUnaligned!int8(i8, cast(int*)p); } void checkStore(int *a) { immutable int4 v = [0, 10, 20, 30]; // CHECK: store <4 x i32>{{.*}} align 1 storeUnaligned!int4(v, a); assert(v.array == a[0..4]); } void main() { loads(getMisalignedPtr()); stores(getMisalignedPtr()); checkStore(cast(int*)getMisalignedPtr()); } import ldc.attributes; align(32) char[100] dummy = void; void* getMisalignedPtr() @weak // disallows reasoning and inlining of this function { return &dummy[1]; }; ldc-1.1.0-beta3-src/tests/codegen/discard_value_names_ir2obj_cache.d0000664000175000017500000000145712776214734023451 0ustar kaikai// Test value name discarding in conjunction with the ir2obj cache: local variable name changes should still give a cache hit. // REQUIRES: atleast_llvm309 // Create and then empty the cache for correct testing when running the test multiple times. // RUN: %ldc %s -c -of=%t%obj -ir2obj-cache=%T/dvni2oc \ // RUN: && %prunecache -f %T/dvni2oc --max-bytes=1 \ // RUN: && %ldc %s -c -of=%t%obj -ir2obj-cache=%T/dvni2oc -d-version=FIRST -vv | FileCheck --check-prefix=NO_HIT %s \ // RUN: && %ldc %s -c -of=%t%obj -ir2obj-cache=%T/dvni2oc -vv | FileCheck --check-prefix=MUST_HIT %s // MUST_HIT: Cache object found! // NO_HIT-NOT: Cache object found! version (FIRST) { int foo(int a) { return a + 2; } } else { int foo(int differentname) { return differentname + 2; } } ldc-1.1.0-beta3-src/tests/codegen/in_place_construct.d0000664000175000017500000001200312776214734020732 0ustar kaikai// Tests in-place construction of variables. // RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll // 256 bits, returned via sret: struct S { long a, b, c, d; } // CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct13returnLiteralFZS18in_place_construct1S S returnLiteral() { // make sure the literal is emitted directly into the sret pointee // CHECK: %1 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 0 // CHECK: store i64 1, i64* %1 // CHECK: %2 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 1 // CHECK: store i64 2, i64* %2 // CHECK: %3 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 2 // CHECK: store i64 3, i64* %3 // CHECK: %4 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 3 // CHECK: store i64 4, i64* %4 return S(1, 2, 3, 4); } // CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct12returnRValueFZS18in_place_construct1S S returnRValue() { // make sure the sret pointer is forwarded // CHECK: call {{.*}}_D18in_place_construct13returnLiteralFZS18in_place_construct1S // CHECK-SAME: %in_place_construct.S* {{.*}} %.sret_arg return returnLiteral(); } // CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct10returnNRVOFZS18in_place_construct1S S returnNRVO() { // make sure NRVO zero-initializes the sret pointee directly // CHECK: %1 = bitcast %in_place_construct.S* %.sret_arg to i8* // CHECK: call void @llvm.memset.{{.*}}(i8* %1, i8 0, const S r; return r; } // CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct15withOutContractFZS18in_place_construct1S S withOutContract() out { assert(__result.a == 0); } body { // make sure NRVO zero-initializes the sret pointee directly // CHECK: %1 = bitcast %in_place_construct.S* %.sret_arg to i8* // CHECK: call void @llvm.memset.{{.*}}(i8* %1, i8 0, const S r; return r; // make sure `__result` inside the out contract is just an alias to the sret pointee // CHECK: %2 = getelementptr inbounds {{.*}}%in_place_construct.S* %.sret_arg, i32 0, i32 0 // CHECK: %3 = load {{.*}}i64* %2 // CHECK: %4 = icmp eq i64 %3, 0 } // CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct7structsFZv void structs() { // CHECK: %literal = alloca %in_place_construct.S // CHECK: %a = alloca %in_place_construct.S // CHECK: %b = alloca %in_place_construct.S // CHECK: %c = alloca %in_place_construct.S // make sure the literal is emitted directly into the lvalue // CHECK: %1 = getelementptr inbounds {{.*}}%in_place_construct.S* %literal, i32 0, i32 0 // CHECK: store i64 5, i64* %1 // CHECK: %2 = getelementptr inbounds {{.*}}%in_place_construct.S* %literal, i32 0, i32 1 // CHECK: store i64 6, i64* %2 // CHECK: %3 = getelementptr inbounds {{.*}}%in_place_construct.S* %literal, i32 0, i32 2 // CHECK: store i64 7, i64* %3 // CHECK: %4 = getelementptr inbounds {{.*}}%in_place_construct.S* %literal, i32 0, i32 3 // CHECK: store i64 8, i64* %4 const literal = S(5, 6, 7, 8); // make sure the variables are in-place constructed via sret // CHECK: call {{.*}}_D18in_place_construct13returnLiteralFZS18in_place_construct1S // CHECK-SAME: %in_place_construct.S* {{.*}} %a const a = returnLiteral(); // CHECK: call {{.*}}_D18in_place_construct12returnRValueFZS18in_place_construct1S // CHECK-SAME: %in_place_construct.S* {{.*}} %b const b = returnRValue(); // CHECK: call {{.*}}_D18in_place_construct10returnNRVOFZS18in_place_construct1S // CHECK-SAME: %in_place_construct.S* {{.*}} %c const c = returnNRVO(); withOutContract(); } // CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct12staticArraysFZv void staticArrays() { // CHECK: %sa = alloca [2 x i32] // make sure static array literals are in-place constructed too // CHECK: store [2 x i32] [i32 1, i32 2], [2 x i32]* %sa const(int[2]) sa = [ 1, 2 ]; } struct Container { S s; } // CHECK-LABEL: define{{.*}} @{{.*}}_D18in_place_construct19hierarchyOfLiteralsFZv void hierarchyOfLiterals() { // CHECK: %sa = alloca [1 x %in_place_construct.Container] // CHECK: %1 = getelementptr inbounds {{.*}}[1 x %in_place_construct.Container]* %sa, i32 0, i32 0 // CHECK: %2 = getelementptr inbounds {{.*}}%in_place_construct.Container* %1, i32 0, i32 0 // CHECK: %3 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 0 // CHECK: store i64 11, i64* %3 // CHECK: %4 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 1 // CHECK: store i64 12, i64* %4 // CHECK: %5 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 2 // CHECK: store i64 13, i64* %5 // CHECK: %6 = getelementptr inbounds {{.*}}%in_place_construct.S* %2, i32 0, i32 3 // CHECK: store i64 14, i64* %6 Container[1] sa = [ Container(S(11, 12, 13, 14)) ]; } // CHECK-LABEL: define{{.*}} @{{.*}}_Dmain void main() { structs(); staticArrays(); hierarchyOfLiterals(); } ldc-1.1.0-beta3-src/tests/codegen/funcliteral_defaultarg_gh1634.d0000664000175000017500000000132612776214734022564 0ustar kaikai// Test function literal as default argument // RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll // RUN: %ldc -run %s module mod; // CHECK-LABEL: define{{.*}} @{{.*}}D3mod3fooFPFZiZi int foo(int function() d = () { return 123; }) { return d(); } // CHECK-LABEL: define{{.*}} @{{.*}}D3mod8call_fooFZi int call_foo() { // CHECK: call {{.*}}D3mod3fooFPFZiZi{{.*}}D3mod9__lambda5FZi return foo(); } // The lambda is defined by the first call to foo with default arguments. // CHECK-LABEL: define{{.*}} @{{.*}}D3mod9__lambda5FZi // CHECK: ret i32 123 // CHECK-LABEL: define{{.*}} @{{.*}}Dmain void main() { // CHECK: call {{.*}}D3mod3fooFPFZiZi{{.*}}D3mod9__lambda5FZi assert(foo() == 123); } ldc-1.1.0-beta3-src/tests/codegen/mangling_gh1519.d0000664000175000017500000000115612776214734017655 0ustar kaikai// Test for Github issue 1519 // Check that .mangleof strings do not contain any char 0x01. // LDC may prepend 0x01 to prevent LLVM from modifying the symbol name, but it should not appear in user code. // RUN: %ldc -c %s extern (C) void fooC() { } extern (C++) void fooCpp() { } extern (D) void fooD() { } void aliasTemplate(alias F)() { F(); } void main() { import std.algorithm; static assert(all!"a != '\1'"(fooC.mangleof)); static assert(all!"a != '\1'"(fooCpp.mangleof)); static assert(all!"a != '\1'"(fooD.mangleof)); static assert(all!"a != '\1'"(aliasTemplate!fooCpp.mangleof)); } ldc-1.1.0-beta3-src/tests/codegen/inlining_templates.d0000664000175000017500000000347012776214734020751 0ustar kaikai// Test inlining of templates // Templates that would otherwise not be codegenned, _should_ be codegenned for inlining when pragma(inline, true) is specified. // REQUIRES: atleast_llvm307 // RUN: %ldc %s -I%S -c -output-ll -release -enable-inlining -enable-cross-module-inlining -O0 -of=%t.O0.ll && FileCheck %s < %t.O0.ll // RUN: %ldc -singleobj %S/inputs/inlinables.d %s -I%S -c -output-ll -release -enable-inlining -enable-cross-module-inlining -O0 -of=%t.singleobj.O0.ll && FileCheck %s < %t.singleobj.O0.ll // Test linking too. // Separate compilation // RUN: %ldc -c -enable-inlining -enable-cross-module-inlining %S/inputs/inlinables.d -of=%t.inlinables%obj \ // RUN: && %ldc -I%S -enable-inlining -enable-cross-module-inlining %t.inlinables%obj %s -of=%t%exe // Singleobj compilation // RUN: %ldc -I%S -enable-inlining -enable-cross-module-inlining -singleobj %S/inputs/inlinables.d %s -of=%t2%exe import inputs.inlinables; import std.stdio; import std.exception; int foo(int i) { return call_template_foo(i); } // stdio.File.flush contains a call to errnoException, which contains __FILE__ as default template parameter. // Make sure the symbol is inlined/defined and not declared (which will lead to linker errors if the location // of the stdlib is different from where LDC was built from) void ggg(ref File f) { f.flush(); } void main() { } // CHECK-NOT: declare{{.*}}D6inputs10inlinables20__T12template_fooTiZ12template_foo // CHECK-NOT: declare{{.*}}D3std9exception{{[0-9]+}}__T12errnoEnforce // CHECK-DAG: define{{.*}}D6inputs10inlinables20__T12template_fooTiZ12template_foo{{.*}}) #[[ATTR1:[0-9]+]] // CHECK-DAG: define{{.*}}D3std9exception{{[0-9]+}}__T12errnoEnforce{{.*}}) #[[ATTR2:[0-9]+]] // CHECK-DAG: attributes #[[ATTR1]] ={{.*}} alwaysinline // CHECK-DAG: attributes #[[ATTR2]] ={{.*}} alwaysinline ldc-1.1.0-beta3-src/tests/codegen/align.d0000664000175000017500000000470612776214734016161 0ustar kaikai// RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll // Fails on Windows_x86, see https://github.com/ldc-developers/ldc/issues/1356 // XFAIL: Windows_x86 align(32) struct Outer { int a; } struct Inner { align(32) int a; } static Outer globalOuter; // CHECK: constant %align.Outer_init zeroinitializer{{(, comdat)?}}, align 32 static Inner globalInner; // CHECK: constant %align.Inner_init zeroinitializer{{(, comdat)?}}, align 32 Outer passAndReturnOuterByVal(Outer arg) { return arg; } // CHECK: define{{.*}} void @{{.*}}_D5align23passAndReturnOuterByValFS5align5OuterZS5align5Outer /* the 32-bit x86 ABI substitutes the sret attribute by inreg */ // CHECK-SAME: %align.Outer* {{noalias sret|inreg noalias}} align 32 %.sret_arg /* how the arg is passed by value is ABI-specific, but the pointer must be aligned */ // CHECK-SAME: align 32 % Inner passAndReturnInnerByVal(Inner arg) { return arg; } // CHECK: define{{.*}} void @{{.*}}_D5align23passAndReturnInnerByValFS5align5InnerZS5align5Inner // CHECK-SAME: %align.Inner* {{noalias sret|inreg noalias}} align 32 %.sret_arg // CHECK-SAME: align 32 % void main() { Outer outer; // CHECK: %outer = alloca %align.Outer, align 32 Inner inner; // CHECK: %inner = alloca %align.Inner, align 32 align(16) byte byte16; // CHECK: %byte16 = alloca i8, align 16 align(64) Outer outer64; // CHECK: %outer64 = alloca %align.Outer, align 64 align(128) Inner inner128; // CHECK: %inner128 = alloca %align.Inner, align 128 alias Byte8 = align(8) byte; Byte8 byte8; // Can aliases contain align(x) ? // C HECK: %byte8 = alloca i8, align 8 // C HECK: %byte8 = alloca i8, align 1 align(16) Outer outeroverride; // Yet undecided if align() should override type alignment: // C HECK: %outeroverride = alloca %align.Outer, align 16 // C HECK: %outeroverride = alloca %align.Outer, align 32 // CHECK: %.sret_tmp{{.*}} = alloca %align.Outer, align 32 // CHECK: %.sret_tmp{{.*}} = alloca %align.Inner, align 32 outer = passAndReturnOuterByVal(outer); // CHECK: call{{.*}} void @{{.*}}_D5align23passAndReturnOuterByValFS5align5OuterZS5align5Outer // CHECK-SAME: %align.Outer* {{noalias sret|inreg noalias}} align 32 %.sret_tmp // CHECK-SAME: align 32 % inner = passAndReturnInnerByVal(inner); // CHECK: call{{.*}} void @{{.*}}_D5align23passAndReturnInnerByValFS5align5InnerZS5align5Inner // CHECK-SAME: %align.Inner* {{noalias sret|inreg noalias}} align 32 %.sret_tmp // CHECK-SAME: align 32 % } ldc-1.1.0-beta3-src/tests/codegen/inlining_imports_pragma.d0000664000175000017500000000312012776214734021767 0ustar kaikai// Test inlining of functions marked with pragma(inline) in an imported module // O0 and O3 should behave the same for these tests with explicit inlining directives by the user. // FIXME: Currently cross-module inlining is completely disabled per default, also for pragma(inline,true) functions. // The `-enable-cross-module-inlining` flag is therefore necessary for now, but should be removed in the future. // REQUIRES: atleast_llvm307 // RUN: %ldc %s -I%S -c -output-ll -O0 -enable-cross-module-inlining -of=%t.O0.ll && FileCheck %s --check-prefix OPTNONE < %t.O0.ll // RUN: %ldc %s -I%S -c -output-ll -O3 -enable-cross-module-inlining -of=%t.O3.ll && FileCheck %s --check-prefix OPT3 < %t.O3.ll import inputs.inlinables; extern (C): // simplify mangling for easier matching // OPTNONE-LABEL: define{{.*}} @call_never_inline( // OPT3-LABEL: define{{.*}} @call_never_inline( int call_never_inline() { // OPTNONE: call {{.*}} @never_inline() // OPT3: call {{.*}} @never_inline() return never_inline(); } // OPTNONE-DAG: declare {{.*}} @never_inline() // OPTNONE-LABEL: define{{.*}} @call_always_inline( // OPT3-LABEL: define{{.*}} @call_always_inline( int call_always_inline() { // OPTNONE-NOT: call {{.*}} @always_inline() // OPT3-NOT: call {{.*}} @always_inline() return always_inline(); // OPTNONE: ret // OPT3: ret } // OPTNONE-LABEL: define{{.*}} @call_inline_chain( // OPT3-LABEL: define{{.*}} @call_inline_chain( int call_inline_chain() { // OPTNONE-NOT: call // OPT3-NOT: call return always_inline_chain0(); // OPTNONE: ret // OPT3: ret } ldc-1.1.0-beta3-src/tests/codegen/attr_fastmath.d0000664000175000017500000000212512776214734017721 0ustar kaikai// Test @fastmath // RUN: %ldc -O0 -release -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll import ldc.attributes; // CHECK-LABEL: define{{.*}} @notfast // CHECK-SAME: #[[ATTR_NOTFAST:[0-9]+]] extern (C) double notfast(double a, double b) { @fastmath double nested_fast(double a, double b) { return a * b; } // CHECK-NOT: fmul fast return a * b; } // CHECK-LABEL: define{{.*}} @{{.*}}nested_fast // CHECK: fmul fast // CHECK-LABEL: define{{.*}} @fast // CHECK-SAME: #[[ATTR_FAST:[0-9]+]] @fastmath extern (C) double fast(double a, double b) { double c; double nested_slow(double a, double b) { return a * b; } // Also test new scopes when generating the IR. try { // CHECK: fmul fast c += a * b; } catch { // CHECK: fmul fast return a * b; } // CHECK: fmul fast return c + a * b; } // CHECK-LABEL: define{{.*}} @{{.*}}nested_slow // CHECK-NOT: fmul fast // CHECK-DAG: attributes #[[ATTR_FAST]] ={{.*}} "unsafe-fp-math"="true" // CHECK-NOT: attributes #[[ATTR_NOTFAST]] ={{.*}} "unsafe-fp-math"="true" ldc-1.1.0-beta3-src/tests/codegen/zerolengtharray_gh1611.d0000664000175000017500000000150212776214734021265 0ustar kaikai// RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll struct A0 { ubyte[0] zerolen; } // CHECK-DAG: %{{.*}}.A0 = type { [1 x i8] } struct uint_0_uint { uint a = 111; ubyte[0] zerolen; uint c = 333; } // CHECK-DAG: %{{.*}}.uint_0_uint = type { i32, i32 } // No tests for codegen with e.g. uint_0_uint yet, because codegen could be much improved. // I think codegen should be the same as for // struct uint_uint // { // uint a = 111; // uint c = 333; // } // CHECK-LABEL: define{{.*}}fooA0{{.*}} { auto fooA0() { return A0(); // Intentionally a regexp to not match "sret" // CHECK: {{ ret }} } // CHECK-LABEL: define{{.*}}foo_uint_0_uint auto foo_uint_0_uint() { return uint_0_uint(); // Intentionally a regexp to not match "sret" // CHECK: {{ ret }} } ldc-1.1.0-beta3-src/tests/codegen/inlining_disablecross.d0000664000175000017500000000144712776214734021432 0ustar kaikai// Test disabling/enabling of cross-module inlining // REQUIRES: atleast_llvm307 // RUN: %ldc %s -I%S -c -output-ll -enable-cross-module-inlining -O0 -of=%t.ENA.ll && FileCheck %s --check-prefix ENABLED < %t.ENA.ll // RUN: %ldc %s -I%S -c -output-ll -disable-cross-module-inlining -O3 -of=%t.DIS.ll && FileCheck %s --check-prefix DISABLED < %t.DIS.ll import inputs.inlinables; extern (C): // simplify mangling for easier matching // DISABLED-LABEL: define{{.*}} @call_easily_inlinable( // ENABLED-LABEL: define{{.*}} @call_easily_inlinable( int call_easily_inlinable(int i) { // DISABLED: call {{.*}} @easily_inlinable( return easily_inlinable(i); // DISABLED: ret // ENABLED: ret } // ENABLED-DAG: define {{.*}} @easily_inlinable( // DISABLED-DAG: declare {{.*}} @easily_inlinable( ldc-1.1.0-beta3-src/tests/codegen/inlining_pragma.d0000664000175000017500000000313512776214734020220 0ustar kaikai// Test inlining of functions marked with pragma(inline) // RUN: %ldc %s -I%S -c -output-ll -O0 -of=%t.O0.ll && FileCheck %s --check-prefix OPTNONE < %t.O0.ll // RUN: %ldc %s -I%S -c -output-ll -O3 -of=%t.O3.ll && FileCheck %s --check-prefix OPT3 < %t.O3.ll extern (C): // simplify mangling for easier matching int dummy; // OPTNONE-LABEL: define{{.*}} @never_inline // OPTNONE-SAME: #[[NEVER:[0-9]+]] pragma(inline, false) int never_inline() { dummy = 111; return 222; } int external(); // OPTNONE-LABEL: define{{.*}} @always_inline // OPTNONE-SAME: #[[ALWAYS:[0-9]+]] pragma(inline, true) int always_inline() { int a; foreach (i; 1 .. 10) { foreach (ii; 1 .. 10) { foreach (iii; 1 .. 10) { a += i * external(); } } } dummy = 444; return a; } // OPTNONE-LABEL: define{{.*}} @foo // OPTNONE-SAME: #[[FOO:[0-9]+]] int foo() { return 333; } // OPT3-LABEL: define{{.*}} @call_always_inline int call_always_inline() { // OPT3-NOT: call {{.*}} @always_inline() // OPT3: ret return always_inline(); } // OPT3-LABEL: define{{.*}} @call_never_inline int call_never_inline() { // OPT3: call {{.*}} @never_inline() // OPT3: ret return never_inline(); } // OPTNONE-NOT: attributes #[[FOO]] ={{.*}} alwaysinline // OPTNONE-NOT: attributes #[[FOO]] ={{.*}} noinline // OPTNONE-NOT: attributes #[[NEVER]] ={{.*}} alwaysinline // OPTNONE-NOT: attributes #[[ALWAYS]] ={{.*}} noinline // OPTNONE-DAG: attributes #[[NEVER]] ={{.*}} noinline // OPTNONE-DAG: attributes #[[ALWAYS]] ={{.*}} alwaysinline ldc-1.1.0-beta3-src/tests/codegen/static_typeid_gh1540.d0000664000175000017500000000123612776214734020717 0ustar kaikai// Tests correct codegen for static variables initialized with typeid(A) // Test for Github issue 1540 // RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll class C { } interface I { } struct S { } // CHECK: @{{.*}}classvarC14TypeInfo_Class = thread_local global %object.TypeInfo_Class* @{{.*}}1C7__ClassZ auto classvar = typeid(C); // CHECK: @{{.*}}interfacevarC18TypeInfo_Interface = thread_local global %"typeid({{.*}}.I)"* @_D{{[0-9]+}}TypeInfo_C{{.*}}1I6__initZ auto interfacevar = typeid(I); // CHECK: @{{.*}}structvarC15TypeInfo_Struct = thread_local global %"typeid({{.*}}S)"* @_D{{[0-9]+}}TypeInfo_S{{.*}}1S6__initZ auto structvar = typeid(S); ldc-1.1.0-beta3-src/tests/codegen/attr_llvmattr.d0000664000175000017500000000104312776214734017755 0ustar kaikai// Tests @llvmAttr attribute // RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll import ldc.attributes; extern (C): // For easier name mangling // CHECK: define{{.*}} @keyvalue{{.*}} #[[KEYVALUE:[0-9]+]] @(llvmAttr("key", "value")) void keyvalue() { } // CHECK: define{{.*}} @keyonly{{.*}} #[[KEYONLY:[0-9]+]] @(llvmAttr("keyonly")) void keyonly() { } // CHECK-DAG: attributes #[[KEYVALUE]] = {{.*}} "key"="value" // CHECK-NOT: attributes #[[KEYONLY]] = {{.*}} "keyonly"= // CHECK-DAG: attributes #[[KEYONLY]] = {{.*}} "keyonly" ldc-1.1.0-beta3-src/tests/codegen/inlining_invariants_gh1678.d0000664000175000017500000000102412776214734022126 0ustar kaikai// RUN: %ldc --enable-inlining -of=%t%exe %s // https://github.com/ldc-developers/ldc/issues/1678 import std.datetime; // Extra test that fail when a simple frontend change is tried that names __invariant using the line and column number. class A { mixin(genInv("666")); mixin(genInv("777")); } string genInv(string a) { return "invariant() { }"; } void main() { auto currentTime = Clock.currTime(); auto timeString = currentTime.toISOExtString(); auto restoredTime = SysTime.fromISOExtString(timeString); }ldc-1.1.0-beta3-src/tests/codegen/hashed_mangling.d0000664000175000017500000000313612776214734020173 0ustar kaikai// Test hashing of symbols above hash threshold // RUN: %ldc -hash-threshold=90 -g -c -output-ll -of=%t90.ll %s && FileCheck %s --check-prefix HASH90 < %t90.ll // RUN: %ldc -hash-threshold=90 -run %s // Don't use Phobos functions in this test, because the test hashthreshold is too low for an unhashed libphobos. module one.two.three; // HASH90-DAG: define{{.*}} @externCfunctions_are_not_hashed_externCfunctions_are_not_hashed_externCfunctions_are_not_hashed extern (C) int externCfunctions_are_not_hashed_externCfunctions_are_not_hashed_externCfunctions_are_not_hashed() { return 95; } auto s(T)(T t) { // HASH90-DAG: define{{.*}} @{{(\"\\01_)?}}_D3one3two5three8__T1sTiZ1sFNaNbNiNfiZS3one3two5three8__T1sTiZ1sFiZ13__T6ResultTiZ6Result // HASH90-DAG: define{{.*}} @{{(\"\\01_)?}}_D3one3two5three3L1633_699ccf279a146992d539ca3ca16e22e11sZ // HASH90-DAG: define{{.*}} @{{(\"\\01_)?}}_D3one3two5three3L2333_5ee632e10b6f09e8f541a143266bdf226Result3fooZ struct Result(T) { void foo(){} } return Result!int(); } auto klass(T)(T t) { class Result(T) { // HASH90-DAG: define{{.*}} @{{(\"\\01_)?}}_D3one3two5three12__T5klassTiZ5klassFiZ13__T6ResultTiZ6Result3fooMFZv // HASH90-DAG: define{{.*}} @{{(\"\\01_)?}}_D3one3two5three3L3433_46a82aac733d8a4b3588d7fa8937aad66Result3fooZ void foo(){} } return new Result!int(); } void main() { assert( externCfunctions_are_not_hashed_externCfunctions_are_not_hashed_externCfunctions_are_not_hashed() == 95); auto x = 1.s.s.s.s; x.foo; auto y = 1.klass.klass.klass.klass; y.foo; } ldc-1.1.0-beta3-src/tests/codegen/atomicrmw.d0000664000175000017500000000146012776214734017063 0ustar kaikai// RUN: %ldc -c -de -output-ll -of=%t.ll %s && FileCheck %s < %t.ll import core.atomic; void main() { shared ubyte x = 3; ubyte r; r = atomicOp!"+="(x, uint(257)); assert(x == r); // CHECK: = atomicrmw add i8* r = atomicOp!"+="(x, int(-263)); assert(x == r); // CHECK: = atomicrmw add i8* r = atomicOp!"-="(x, ushort(257)); assert(x == r); // CHECK: = atomicrmw sub i8* r = atomicOp!"-="(x, short(-263)); assert(x == r); // CHECK: = atomicrmw sub i8* r = atomicOp!"&="(x, ubyte(255)); assert(x == r); // CHECK: = atomicrmw and i8* r = atomicOp!"|="(x, short(3)); assert(x == r); // CHECK: = atomicrmw or i8* r = atomicOp!"^="(x, int(3)); assert(x == r); // CHECK: = atomicrmw xor i8* r = atomicOp!"+="(x, 1.0f); assert(x == r); // CHECK: = cmpxchg i8* } ldc-1.1.0-beta3-src/tests/codegen/inlining_leakdefinitions.d0000664000175000017500000000456312776214734022127 0ustar kaikai// Test that inlining does not leak definitions without marking them as available_externally // "Leaking" = symbols definitions in .o file that shouldn't be declarations instead (undefined symbols). // REQUIRES: atleast_llvm307 // RUN: %ldc %s -I%S -c -output-ll -release -O3 -enable-cross-module-inlining -of=%t.O3.ll && FileCheck %s --check-prefix OPT3 < %t.O3.ll // RUN: %ldc %s -I%S -c -output-ll -release -enable-inlining -O0 -enable-cross-module-inlining -of=%t.O0.ll && FileCheck %s --check-prefix OPT0 < %t.O0.ll // RUN: %ldc -I%S -enable-inlining -enable-cross-module-inlining %S/inputs/inlinables.d -run %s // RUN: %ldc -I%S -O3 -enable-cross-module-inlining %S/inputs/inlinables.d -run %s import inputs.inlinables; extern (C): // simplify mangling for easier matching // Inlined naked asm func could end up as global symbols, definitely bad! // (would give multiple definition linker error) // OPT0-NOT: module asm {{.*}}.globl{{.*}}_naked_asm_func // OPT3-NOT: module asm {{.*}}.globl{{.*}}_naked_asm_func // Check that the global variables that are added due to "available_externally // inlining" do not have initializers, i.e. they are declared only and not definined. // OPT3-DAG: @module_variable = external thread_local{{.*}} global i32, align // OPT3-DAG: @{{.*}}write_function_static_variableUiZ15static_func_vari = external thread_local{{.*}} global i32, align // OPT0-LABEL: define{{.*}} @call_class_function( // OPT3-LABEL: define{{.*}} @call_class_function( int call_class_function(A a) { // There should be only one call to "virtual_func". // OPT3: call // OPT3-NOT: call return a.final_func(); // There should be a return from an LLVM variable (not a direct value) // OPT0: ret i32 % // OPT3: ret i32 % } // OPT0-LABEL: define{{.*}} @dont_leak_module_variables( // OPT3-LABEL: define{{.*}} @dont_leak_module_variables( void dont_leak_module_variables() { write_module_variable(987); write_function_static_variable(167); get_typeid_A(); // OPT0: ret void // OPT3: ret void } // OPT0-LABEL: define{{.*}} @asm_func( // OPT3-LABEL: define{{.*}} @asm_func( void asm_func() { naked_asm_func(); // OPT0: ret void // OPT3: ret void } // OPT0-LABEL: define{{.*}} @main( // OPT3-LABEL: define{{.*}} @main( int main() { dont_leak_module_variables(); return 0; // OPT0: ret i32 0 // OPT3: ret i32 0 } ldc-1.1.0-beta3-src/tests/codegen/inlining_imports.d0000664000175000017500000000157712776214734020456 0ustar kaikai// Test inlining of imported functions // REQUIRES: atleast_llvm307 // RUN: %ldc %s -I%S -c -output-ll -release -O3 -enable-cross-module-inlining -of=%t.O3.ll && FileCheck %s --check-prefix OPT3 < %t.O3.ll import inputs.inlinables; extern (C): // simplify mangling for easier matching // Simple functions for reference. int foo() { return goo(); } int goo() { return 1; } // OPT3-LABEL: define{{.*}} @call_easily_inlinable( int call_easily_inlinable(int i) { // OPT3-NOT: call {{.*}} @easily_inlinable( return easily_inlinable(i); // OPT3: ret i32 2 } // OPT3-LABEL: define{{.*}} @call_class_function( int call_class_function(A a) { // OPT3-NOT: call return a.final_class_function(); // OPT3: ret i32 12345 } // OPT3-LABEL: define{{.*}} @call_weak_function( int call_weak_function() { // OPT3: call return weak_function(); // OPT3-NOT: 654 } ldc-1.1.0-beta3-src/tests/codegen/vastart_vaend_gh1744.d0000664000175000017500000000256212776214734020724 0ustar kaikai// Test that va_end is called when returning from a variadic function. // Because the IR is kind of ugly, testing at -O0 is very brittle. Instead we // test that at -O3, LLVM was able to analyse the function correctly and // optimize-out the va_start and va_end calls and remove the call to // return_two (Github #1744). // The optimization (removing back-to-back calls to va_start and va_end) only // happens from LLVM >= 3.9. // REQUIRES: atleast_llvm309 // RUN: %ldc %s -c -output-ll -O3 -of=%t.O3.ll \ // RUN: && FileCheck %s --check-prefix OPT3 < %t.O3.ll module mod; // OPT3-LABEL: define {{.*}} @{{.*}}void_three_return_paths void void_three_return_paths(int a, ...) { // OPT3: call void @llvm.va_start({{.*}} %[[VA:[0-9]+]]) // OPT3-NOT: return_two return_two(); if (a > 0) { throw new Exception(""); return; } // There are two control paths (normal return, exception resume) that // should call va_end. // OPT3: call void @llvm.va_end({{.*}} %[[VA]]) // OPT3: call void @llvm.va_end({{.*}} %[[VA]]) } // OPT3-LABEL: define {{.*}} @{{.*}}return_two int return_two(...) { // OPT3-NOT: va_start // OPT3-NOT: va_end // OPT3: ret i32 2 return 2; } // Github #1744: // OPT3-LABEL: define {{.*}} @{{.*}}two_four int two_four() { // OPT3-NOT: return_two // OPT3: ret i32 8 return return_two() * 4; } ldc-1.1.0-beta3-src/tests/codegen/cpp_interface.d0000664000175000017500000000016412776214734017663 0ustar kaikai// RUN: %ldc -c %s extern(C++) interface XUnknown {} class ComObject : XUnknown {} class DComObject : ComObject {} ldc-1.1.0-beta3-src/tests/codegen/attr_llvmFMF.d0000664000175000017500000000250312776214734017415 0ustar kaikai// Test @ldc.attributes.llvmFastMathFlag UDA // RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s --check-prefix LLVM < %t.ll // RUN: %ldc -c -w -d-version=WARNING %s 2>&1 | FileCheck %s --check-prefix WARNING import ldc.attributes; version(WARNING) { // WARNING: attr_llvmFMF.d(11): Warning: ignoring unrecognized flag parameter 'unrecognized' for '@ldc.attributes.llvmFastMathFlag' @llvmFastMathFlag("unrecognized") void foo() {} } // LLVM-LABEL: define{{.*}} @notfast // LLVM-SAME: #[[ATTR_NOTFAST:[0-9]+]] extern (C) double notfast(double a, double b) { @llvmFastMathFlag("fast") double nested_fast(double a, double b) { return a * b; } // LLVM: fmul double return a * b; } // LLVM-LABEL: define{{.*}} @{{.*}}nested_fast // LLVM: fmul fast double // LLVM-LABEL: define{{.*}} @{{.*}}nnan_arcp @llvmFastMathFlag("nnan") @llvmFastMathFlag("arcp") double nnan_arcp(double a, double b) { // LLVM: fmul nnan arcp double return a * b; } // LLVM-LABEL: define{{.*}} @{{.*}}ninf_nsz @llvmFastMathFlag("ninf") @llvmFastMathFlag("nsz") double ninf_nsz(double a, double b) { // LLVM: fmul ninf nsz double return a * b; } // LLVM-LABEL: define{{.*}} @{{.*}}cleared @llvmFastMathFlag("ninf") @llvmFastMathFlag("clear") double cleared(double a, double b) { // LLVM: fmul double return a * b; } ldc-1.1.0-beta3-src/tests/codegen/complex_postexpr_gh1806.d0000664000175000017500000000063212776214734021471 0ustar kaikai// RUN: %ldc -run %s void runTest(T)() { { T v = 1.0 + 1.0i; assert(v++ == 1.0 + 1.0i); assert(v-- == 2.0 + 1.0i); assert(v == 1.0 + 1.0i); } { T v = 1.0 + 1.0i; assert(++v == 2.0 + 1.0i); assert(--v == 1.0 + 1.0i); assert(v == 1.0 + 1.0i); } } void main () { runTest!cfloat(); runTest!cdouble(); runTest!creal(); } ldc-1.1.0-beta3-src/tests/codegen/enum_vardecl.d0000664000175000017500000000250012776214734017521 0ustar kaikai// Tests that enum members are correctly handled when they show up as VarExp in the AST. /+ + Consider `type == EnumerationOfStructs.Colon, type == EnumerationOfStructs.Comma;` + This expression currently (front-end v2.071) results in a VarExp for the enum member + in the LHS. + + See DMD issues 16022 and 16100. + + The problem appears to be that in a comma expression, an enum member appearing in the + LHS is not constant folded and a VarExp remains in the AST. + The AST for the LHS of that expression is an ExpStatement with AndAndExp's of + EqualExp's for every struct field. + Because of the missing constant folding, the generated code is verbose: a + new struct temporary is created for every struct field comparison, because the EqualExp + will still have a DotVarExp into a VarExp (the enumeration member). And we create a new + enumeration member temporary for each VarExp. + With -O3 it all disappears. +/ // RUN: %ldc %s -c -output-ll -of=%t.ll bool test16022() { enum Type { Colon, Comma } Type type; return type == Type.Colon, type == Type.Comma; } bool foo() { struct A { int i; string s; } enum Foo { Colon = A(0, "hoi"), Comma = A(1, "yoyo") } Foo type; return type == Foo.Colon, type == Foo.Comma; } ldc-1.1.0-beta3-src/tests/codegen/attr_weak.d0000664000175000017500000000107512776214734017044 0ustar kaikai// Test linking+running a program with @weak function // RUN: %ldc -O3 %S/inputs/attr_weak_input.d -c -of=%T/attr_weak_input%obj // RUN: %ldc -O3 %T/attr_weak_input%obj %s -of=%t%exe // RUN: %t%exe import ldc.attributes; // Should be overridden by attr_weak_input.d (but only because its object // file is specified before this one for the linker). // The @weak attribute prevents the optimizer from making any assumptions // though, so the call below is not inlined. extern(C) @weak int return_seven() { return 1; } void main() { assert( return_seven() == 7 ); } ldc-1.1.0-beta3-src/tests/codegen/inlining_stdlib.d0000664000175000017500000000226112776214734020231 0ustar kaikai// Test inlining of some standard library functions // REQUIRES: atleast_llvm307 // RUN: %ldc %s -c -output-ll -release -O0 -of=%t.O0.ll && FileCheck %s --check-prefix OPT0 < %t.O0.ll // RUN: %ldc %s -c -output-ll -release -O3 -enable-cross-module-inlining -of=%t.O3.ll && FileCheck %s --check-prefix OPT3 < %t.O3.ll extern (C): // simplify mangling for easier matching // OPT0-LABEL: define{{.*}} @foo( // OPT3-LABEL: define{{.*}} @foo( int foo(size_t i) { // core.bitop.bsf() is force-inlined import core.bitop; // FIXME: The OPT0 check is disabled for now, because cross-module inlining is disabled fully (also for `pragma(inline, true)` functions). // O PT0: call {{.*}} @llvm.cttz // OPT3: call {{.*}} @llvm.cttz return bsf(i); // OPT0: ret // OPT3: ret } // OPT0-LABEL: define{{.*}} @ggg( // OPT3-LABEL: define{{.*}} @ggg( char[] ggg(char* str) { // std.string.fromStringz() is inlined when optimizing import std.string; // OPT0: call {{.*}} @{{.*}}std6string11fromStringz // OPT3: call {{.*}}strlen return fromStringz(str); // OPT0: ret // OPT3: ret } // OPT0: declare {{.*}}std6string11fromStringz // OPT3: declare {{.*}}strlen ldc-1.1.0-beta3-src/tests/codegen/asm_output.d0000664000175000017500000000047112776214734017262 0ustar kaikai// RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s --check-prefix LLVM < %t.ll // RUN: %ldc -c -output-s -of=%t.s %s && FileCheck %s --check-prefix ASM < %t.s int main() { return 42; // Try to keep these very simple checks independent of architecture: // LLVM: ret i32 42 // ASM: $42 // ASM: ret } ldc-1.1.0-beta3-src/tests/codegen/array_equals_null.d0000664000175000017500000000120512776214734020600 0ustar kaikai// Tests that array (in)equality with null is optimized to a length check // RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll // RUN: %ldc -run %s // CHECK-LABEL: define{{.*}} @{{.*}}isNull bool isNull(int[] arg) { // CHECK-NOT: call // CHECK-NOT: invoke // CHECK: icmp eq i{{32|64}} %.len, 0 return arg == null; } // CHECK-LABEL: define{{.*}} @{{.*}}isNotNull bool isNotNull(int[] arg) { // CHECK-NOT: call // CHECK-NOT: invoke // CHECK: icmp ne i{{32|64}} %.len, 0 return arg != null; } void main() { int[3] i3 = [ 0, 1, 2 ]; assert(isNull(i3[0..0])); assert(isNotNull(i3[0..1])); } ldc-1.1.0-beta3-src/tests/codegen/inferred_outputname.d0000664000175000017500000000120312776214734021133 0ustar kaikai// Make sure the inferred output filename is based on the first (source or // object) file, and independent from its module declaration. // If it works on Windows, it will work on other platforms too, and it // simplifies things a bit. // REQUIRES: Windows // 1) 2 object files compiled separately: // RUN: %ldc -c %S/inputs/foo.d -of=%T/foo%obj // RUN: %ldc %s %T/foo%obj -vv | FileCheck %s // 2) singleObj build with external object file and 2 source files: // RUN: %ldc %T/foo%obj %s %S/inputs/attr_weak_input.d -vv | FileCheck %s // CHECK: Linking with: // CHECK-NEXT: '/OUT:inferred_outputname.exe' module modulename; void main() {} ldc-1.1.0-beta3-src/tests/codegen/inputs/0000775000175000017500000000000012776214734016235 5ustar kaikaildc-1.1.0-beta3-src/tests/codegen/inputs/inlinables.d0000664000175000017500000000330412776214734020522 0ustar kaikaimodule inputs.inlinables; import ldc.attributes; extern (C): // simplify mangling for easier function name matching int easily_inlinable(int i) { if (i > 0) return easily_inlinable(i - 1); return 2; } pragma(inline, false) int never_inline() { return 1; } @weak int external() { return 1; } pragma(inline, true) int always_inline() { int a; foreach (i; 1 .. 10) { foreach (ii; 1 .. 10) { foreach (iii; 1 .. 10) { a += i * external(); } } } return a; } pragma(inline, true) int always_inline_chain0() { return always_inline_chain1(); } pragma(inline, true) int always_inline_chain1() { return always_inline_chain2(); } pragma(inline, true) int always_inline_chain2() { return 345; } class A { int virtual_func() { return 12345; } pragma(inline, true) final int final_func() { return virtual_func(); } final int final_class_function() { return 12345; } } // Weak-linkage functions can not be inlined. @weak int weak_function() { return 654; } int module_variable = 666; pragma(inline, true) void write_module_variable(int i) { module_variable = i; } pragma(inline, true) void write_function_static_variable(int i) { static int static_func_var = 5; static_func_var = i; } pragma(inline, true) auto get_typeid_A() { return typeid(A); } pragma(inline, true) extern (C) void naked_asm_func() { asm pure nothrow @nogc { naked; nop; } } pragma(inline, true) int call_template_foo(int i) { return template_foo(i); } pragma(inline, true) T template_foo(T)(T i) { return i; } ldc-1.1.0-beta3-src/tests/codegen/inputs/input_discard_valuename.d0000664000175000017500000000047212776214734023272 0ustar kaikai// CHECK-LABEL: define{{.*}} @bar( extern(C) void bar() { // CHECK: localbarvar int localbarvar; } // Make sure we can use inline IR in non-textual IR compiles: pragma(LDC_inline_ir) R __ir(string s, R, P...)(P); double inlineIR(double a) { auto s = __ir!(`ret double %0`, double)(a); return s; } ldc-1.1.0-beta3-src/tests/codegen/inputs/attr_weak_input.d0000664000175000017500000000005512776214734021602 0ustar kaikaiextern(C) int return_seven() { return 7; } ldc-1.1.0-beta3-src/tests/codegen/inputs/switch_ICE_gh1638_bar.d0000664000175000017500000000061712776214734022213 0ustar kaikai// Don't make any changes/additions to this file without consulting Github issue 1638 first. module switch_ICE_gh1638_bar; struct S(T) { auto fun = (T a) { T r; switch (a) { case 1: r = 1; break; default: return 0; } return r * 2; }; } alias T = S!int; void f(int a) { int r = T().fun(a); } ldc-1.1.0-beta3-src/tests/codegen/inputs/inlinables_staticvar.d0000664000175000017500000000400512776214734022601 0ustar kaikaimodule inputs.inlinables_staticvar; /+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/ private int atModuleScope; pragma(inline, true) void addToModuleScopeInline(int i) { atModuleScope += i; } pragma(inline, false) void addToModuleScopeOutline(int i) { atModuleScope += i; } pragma(inline, false) bool equalModuleScope(int i) { return atModuleScope == i; } /+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/ pragma(inline, true) bool addAndCheckInsideFunc(int checkbefore, int increment) { static int insideFunc; if (insideFunc != checkbefore) return false; insideFunc += increment; return true; } pragma(inline, false) bool addAndCheckInsideFuncIndirect(int checkbefore, int increment) { return addAndCheckInsideFunc(checkbefore, increment); } /+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/ pragma(inline, true) bool addAndCheckInsideNestedFunc(int checkbefore, int increment) { pragma(inline, true) bool addCheckNested(int checkbefore, int increment) { static int insideFunc; if (insideFunc != checkbefore) return false; insideFunc += increment; return true; } return addCheckNested(checkbefore, increment); } pragma(inline, false) bool addAndCheckInsideNestedFuncIndirect(int checkbefore, int increment) { return addAndCheckInsideNestedFunc(checkbefore, increment); } /+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/ pragma(inline, true) bool addAndCheckNestedStruct(int checkbefore, int increment) { struct NestedStruct { static int structValue; } if (NestedStruct.structValue != checkbefore) return false; NestedStruct.structValue += increment; return true; } pragma(inline, false) bool addAndCheckNestedStructIndirect(int checkbefore, int increment) { return addAndCheckNestedStruct(checkbefore, increment); } /+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/ ldc-1.1.0-beta3-src/tests/codegen/inputs/foo.d0000664000175000017500000000001612776214734017162 0ustar kaikaivoid bar() {} ldc-1.1.0-beta3-src/tests/codegen/attr_fastmath_x86.d0000664000175000017500000000074712776214734020436 0ustar kaikai// Test vectorized fused multiply-add in a simple dot product routine // REQUIRES: target_X86 // RUN: %ldc -mtriple=x86_64-linux-gnu -mattr=+fma -O3 -release -c -output-s -of=%t.s %s && FileCheck %s --check-prefix ASM < %t.s import ldc.attributes; // ASM-LABEL: dot: @fastmath extern (C) double dot(double[] a, double[] b) { double s = 0; // ASM: vfmadd{{[123][123][123]}}pd foreach (size_t i; 0 .. a.length) { s += a[i] * b[i]; } return s; // ASM: ret } ldc-1.1.0-beta3-src/tests/codegen/attr_target_x86.d0000664000175000017500000000372512776214734020114 0ustar kaikai// Tests @target attribute for x86 // REQUIRES: atleast_llvm307 // REQUIRES: target_X86 // RUN: %ldc -O -c -mcpu=i386 -mtriple=i386-linux-gnu -output-ll -of=%t.ll %s && FileCheck %s --check-prefix LLVM < %t.ll // RUN: %ldc -O -c -mcpu=i386 -mtriple=i386-linux-gnu -output-s -of=%t.s %s && FileCheck %s --check-prefix ASM < %t.s import ldc.attributes; // LLVM-LABEL: define{{.*}} void @{{.*}}foo // ASM-LABEL: _D15attr_target_x863fooFPfPffZv: void foo(float *A, float* B, float K) { for (int i = 0; i < 128; ++i) A[i] *= B[i] + K; // ASM-NOT: addps } // LLVM-LABEL: define{{.*}} void @{{.*}}foo_sse // LLVM-SAME: #[[SSE:[0-9]+]] // ASM-LABEL: _D15attr_target_x867foo_sseFPfPffZv: @(target("sse")) void foo_sse(float *A, float* B, float K) { for (int i = 0; i < 128; ++i) A[i] *= B[i] + K; // ASM: addps } // Make sure that no-sse overrides sse (attribute sorting). Also tests multiple @target attribs. // LLVM-LABEL: define{{.*}} void @{{.*}}foo_nosse // LLVM-SAME: #[[NOSSE:[0-9]+]] // ASM-LABEL: _D15attr_target_x869foo_nosseFPfPffZv: @(target("no-sse\n , \tsse ")) void foo_nosse(float *A, float* B, float K) { for (int i = 0; i < 128; ++i) A[i] *= B[i] + K; // ASM-NOT: addps } // LLVM-LABEL: define{{.*}} void @{{.*}}bar_nosse // LLVM-SAME: #[[NOSSE]] // ASM-LABEL: _D15attr_target_x869bar_nosseFPfPffZv: @(target("sse")) @(target(" no-sse")) void bar_nosse(float *A, float* B, float K) { for (int i = 0; i < 128; ++i) A[i] *= B[i] + K; // ASM-NOT: addps } // LLVM-LABEL: define{{.*}} void @{{.*}}haswell // LLVM-SAME: #[[HSW:[0-9]+]] // ASM-LABEL: _D15attr_target_x867haswellFPfPffZv: @(target("arch=haswell ")) void haswell(float *A, float* B, float K) { for (int i = 0; i < 128; ++i) A[i] *= B[i] + K; // ASM: vaddps } // LLVM-DAG: attributes #[[SSE]] = {{.*}} "target-features"="+sse" // LLVM-DAG: attributes #[[NOSSE]] = {{.*}} "target-features"="+sse,-sse" // LLVM-DAG: attributes #[[HSW]] = {{.*}} "target-cpu"="haswell" ldc-1.1.0-beta3-src/tests/d2/0000775000175000017500000000000012776214734013614 5ustar kaikaildc-1.1.0-beta3-src/tests/d2/CMakeLists.txt0000664000175000017500000000432212776214734016355 0ustar kaikaiinclude(CheckTypeSize) check_type_size(void* ptr_size) if(${ptr_size} MATCHES "^4$") set(host_model 32) elseif(${ptr_size} MATCHES "^8$") set(host_model 64) endif() set(gdb_dflags "") if((${CMAKE_SYSTEM_NAME} MATCHES "Linux") AND (${LDC_LLVM_VER} GREATER 307)) execute_process(COMMAND gdb --version COMMAND head -n 1 OUTPUT_VARIABLE GDB_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) string(REGEX REPLACE "[^0-9]*([0-9]+[0-9.]*).*" "\\1" GDB_VERSION "${GDB_VERSION}") message(STATUS "GDB ${GDB_VERSION} detected") if(GDB_VERSION VERSION_LESS "7.6.1") set(gdb_flags "NOTLS") else() set(gdb_flags "ON") endif() if(GDB_VERSION VERSION_LESS "7.8") set(gdb_dflags "-dwarf-version=2") endif() else() set(gdb_flags "OFF") endif() function(add_testsuite config_name dflags gdbflags model) set(name dmd-testsuite${config_name}) set(outdir ${CMAKE_BINARY_DIR}/${name}) add_test(NAME clean-${name} COMMAND ${CMAKE_COMMAND} -E remove_directory ${outdir}) set(all_dflags "${dflags} ${gdb_dflags}") # The DFLAGS environment variable read by LDMD is used because the DMD # testsuite build system provides no way to run the test cases with a # given set of flags without trying all combinations of them. add_test(NAME ${name} COMMAND make -k -C ${PROJECT_SOURCE_DIR}/tests/d2/dmd-testsuite RESULTS_DIR=${outdir} DMD=${LDMD_EXE_FULL} DFLAGS=${all_dflags} MODEL=${model} GDB_FLAGS=${gdbflags} quick ) set_tests_properties(${name} PROPERTIES DEPENDS clean-${name}) endfunction() string(REGEX REPLACE "[^0-9]*([0-9]+[0-9.]*).*" "\\1" GDB_VERSION "${GDB_VERSION}") # Would like to specify the "-release" flag for release builds, but some of the # tests (e.g. 'testdstress') depend on contracts and invariants being active. # Need a solution integrated with d_do_test. add_testsuite("-debug" "-g -link-debuglib" "${gdb_flags}" ${host_model}) add_testsuite("" -O3 "OFF" ${host_model}) if(MULTILIB AND host_model EQUAL 64) # Also test in 32 bit mode on x86_64 multilib builds. add_testsuite("-debug-32" "-g -link-debuglib" "${gdb_flags}" 32) add_testsuite("-32" -O3 "OFF" 32) endif() ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/0000775000175000017500000000000012776215022016376 5ustar kaikaildc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/0000775000175000017500000000000012776215022017340 5ustar kaikaildc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/mydll.di0000664000175000017500000000052212776215022020776 0ustar kaikai /* * MyDll demonstration of how to write D DLLs. * * stripped down version of mydll.d to avoid inclusion into module dependency * for dynamic linking */ /* --------------------------------------------------------- */ class MyClass { string concat(string a, string b); void free(string s); } export MyClass getMyClass(); ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/testmydll2.d0000664000175000017500000000456112776215022021616 0ustar kaikai version(D_Version2) { const string d2_shared = " __gshared "; } else { const string d2_shared = ""; } version(dynload) { extern(Windows) void* LoadLibraryA(in char* dll); extern(Windows) void* GetProcAddress(void* lib, in char* name); alias void fnDllPrint(); alias int fnGetglob(); alias char* fnAlloc(int sz); alias void fnFree(char* p, int sz); mixin(d2_shared ~ "fnDllPrint* pDllPrint;"); mixin(d2_shared ~ "fnGetglob* pGetglob;"); mixin(d2_shared ~ "fnAlloc* pAlloc;"); mixin(d2_shared ~ "fnFree* pFree;"); mixin(d2_shared ~ "int* pGlobvar;"); int loadLib() { void* lib = LoadLibraryA("mydll2.dll".ptr); assert(lib); pDllPrint = cast(fnDllPrint*) GetProcAddress(lib, "D6mydll28dllprintFZv".ptr); pFree = cast(fnFree*) GetProcAddress(lib, "D6mydll24freeFPaiZv".ptr); pAlloc = cast(fnAlloc*) GetProcAddress(lib, "D6mydll25allocFiZPa".ptr); pGetglob = cast(fnGetglob*) GetProcAddress(lib, "D6mydll27getglobFZi".ptr); pGlobvar = cast(int*) GetProcAddress(lib, "D6mydll27globvari".ptr); assert(pDllPrint && pFree && pAlloc && pGetglob && pGlobvar); return 0; } void dllprint() { (*pDllPrint)(); } int getglob() { return (*pGetglob)(); } char* alloc(int sz) { return (*pAlloc)(sz); } void free(char* p, int sz) { (*pFree)(p, sz); } @property int globvar() { return *pGlobvar; } } else { import mydll2; } mixin(d2_shared ~ "Object syncobj;"); void runtest() { // wait until lib loaded synchronized(syncobj) getglob(); int g = globvar; char*[] mem; for(int i = 0; i < 10000; i++) { mem ~= alloc(16); } for(int i = 0; i < 10000; i++) { free(mem[i], 16); } dllprint(); } version(D_Version2) { import core.thread; class TestThread : Thread { this() { super(&runtest); } } } else { import std.thread; class TestThread : Thread { int run() { runtest(); return 0; } void join() { wait(); } } } void test_threaded() { syncobj = new Object; TestThread[] th; for(int i = 0; i < 10; i++) th ~= new TestThread(); // don't run threads before lib loaded synchronized(syncobj) { for(int i = 0; i < 5; i++) th[i].start(); // create some threads before loading the lib, other later version(dynload) loadLib(); } for(int i = 5; i < 10; i++) th[i].start(); for(int i = 0; i < 10; i++) th[i].join(); } int main() { test_threaded(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/runtests.sh0000664000175000017500000000200112776215022021554 0ustar kaikai # Little shell script to compile, link, and run all the samples. # Use ..\bin\shell.exe to execute. MARS=..\..\..\windows\bin\dmd_msc IMPLIB=c:\l\dmc\bin\implib GCSTUB=..\..\..\druntime\src\gcstub\gc.d O=(|-inline) (|-release) (|-g) (|-O) (|-unittest) $(MARS) -c mydll $(MARS) mydll.obj $(GCSTUB) mydll.def -L/map $(IMPLIB) /noi /system mydll.lib mydll.dll $(MARS) testmydll mydll.lib testmydll $(MARS) testmydll -version=DYNAMIC_LOAD testmydll del mydll.obj mydll.dll mydll.map mydll.lib gc.obj del testmydll.obj testmydll.exe testmydll.map $(MARS) -g -d -ofmydll2.dll -version=use_patch mydll2.d dll2.d mydll2.def $(IMPLIB) /system mydll2.lib mydll2.dll $(MARS) -g -d testmydll2.d mydll2.lib testmydll2 $(MARS) -g -d -oftestdyn.exe -version=dynload testmydll2.d testdyn $(MARS) -g -d -ofteststat.exe testmydll2.d mydll2.d teststat del mydll2.obj mydll2.dll mydll2.map mydll2.lib del testmydll2.obj testmydll2.exe testmydll2.map del testdyn.exe testdyn.obj testdyn.map del teststat.exe teststat.obj teststat.map ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/testmydll.d0000664000175000017500000000277612776215022021542 0ustar kaikaiimport core.runtime; import std.stdio; import mydll; //version=DYNAMIC_LOAD; version (DYNAMIC_LOAD) { import core.sys.windows.windows; alias MyClass function() getMyClass_fp; int main() { HMODULE h; FARPROC fp; getMyClass_fp getMyClass; MyClass c; printf("Start Dynamic Link...\n"); h = cast(HMODULE) Runtime.loadLibrary("mydll.dll"); if (h is null) { printf("error loading mydll.dll\n"); return 1; } printf("mydll.dll loaded\n"); fp = GetProcAddress(h, "D5mydll10getMyClassFZC5mydll7MyClass"); if (fp is null) { printf("error loading symbol getMyClass()\n"); return 1; } printf("GetProcAddress succeeded\n"); getMyClass = cast(getMyClass_fp) fp; c = (*getMyClass)(); printf("(*getMyClass)() succeeded\n"); foo(c); printf("foo(c) succeeded\n"); if (!Runtime.unloadLibrary(h)) { printf("error freeing mydll.dll\n"); return 1; } printf("End...\n"); return 0; } } else { // static link the DLL int main() { printf("Start Static Link...\n"); //MyDLL_Initialize(std.gc.getGCHandle()); foo(getMyClass()); //MyDLL_Terminate(); printf("End...\n"); return 0; } } void foo(MyClass c) { printf("foo()\n"); string s = c.concat("Hello", "world!"); writefln(s); c.free(s); delete c; printf("foo() done\n"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/mydll.def0000664000175000017500000000026112776215022021140 0ustar kaikaiLIBRARY MYDLL DESCRIPTION 'MyDll demonstration DLL' EXETYPE NT CODE PRELOAD DISCARDABLE DATA PRELOAD SINGLE EXPORTS D5mydll12__ModuleInfoZ ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/mydll2.d0000664000175000017500000000111712776215022020710 0ustar kaikaimodule mydll2; import std.stdio; version(D_Version2) { import core.memory; } else { import std.gc; } export void dllprint() { writefln("hello dll world"); } int glob; // test access to (tls) globals export int getglob() { return glob; } // test gc-mem-allocation from different threads export char* alloc(int sz) { char* p = (new char[sz]).ptr; version(D_Version2) GC.addRange(p, sz); else addRange(p, p + sz); return p; } export void free(char* p, int sz) { version(D_Version2) GC.removeRange(p); else removeRange(p); // delete p; } export __gshared int globvar; ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/mydll2.def0000664000175000017500000000016312776215022021223 0ustar kaikaiLIBRARY "mydll2.dll" EXETYPE NT SUBSYSTEM WINDOWS CODE SHARED EXECUTE DATA WRITE EXPORTS D6mydll212__ModuleInfoZ ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/dll2.d0000664000175000017500000000535412776215022020351 0ustar kaikai// Public Domain import core.sys.windows.windows; import core.stdc.stdlib; version(D_Version2) { import core.runtime; import core.memory; version(use_patch) import core.sys.windows.dll; import core.stdc.string; extern (C) void _moduleTlsCtor(); extern (C) void _moduleTlsDtor(); } else { import std.gc; import std.thread; version(use_patch) import std.thread_helper; extern (C) { void gc_init(); void gc_term(); void _minit(); void _moduleCtor(); void _moduleDtor(); void _moduleUnitTests(); } } extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { switch (ulReason) { case DLL_PROCESS_ATTACH: version(D_Version2) { version(use_patch) { if( !dll_fixTLS( hInstance, &_tlsstart, &_tlsend, &_tls_callbacks_a, &_tls_index ) ) return false; Runtime.initialize(); // attach to all other threads enumProcessThreads( function (uint id, void* context) { if( !thread_findByAddr( id ) ) { thread_attachByAddr( id ); thread_moduleTlsCtor( id ); } return true; }, null ); } else Runtime.initialize(); } else { gc_init(); // initialize GC _minit(); // initialize module list _moduleCtor(); // run module constructors _moduleUnitTests(); // run module unit tests version(use_patch) { // attach to all other threads enumProcessThreads( function (uint id, void* context) { if( !Thread._getThreadById( id ) ) Thread.thread_attach( id, OpenThreadHandle( id ), getThreadStackBottom( id ) ); return true; }, null ); } // enumThreads(); } break; case DLL_PROCESS_DETACH: version(D_Version2) { version(use_patch) { // detach from all other threads enumProcessThreads( function (uint id, void* context) { if( id != GetCurrentThreadId() && thread_findByAddr( id ) ) thread_detachByAddr( id ); return true; }, null ); } Runtime.terminate(); } else { version(use_patch) { // detach from all other threads enumProcessThreads( function (uint id, void* context) { if( id != GetCurrentThreadId() ) { thread_moduleTlsDtor( id ); Thread.thread_detach( id ); } return true; }, null ); } _moduleDtor(); gc_term(); // shut down GC } break; case DLL_THREAD_ATTACH: version(use_patch) { version(D_Version2) { thread_attachThis(); _moduleTlsCtor(); } else Thread.thread_attach(); } break; case DLL_THREAD_DETACH: version(use_patch) { version(D_Version2) { if( thread_findByAddr( GetCurrentThreadId() ) ) _moduleTlsDtor(); thread_detachThis(); } else Thread.thread_detach(); } break; default: assert(0); } return true; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/win32/mydll.d0000664000175000017500000000263712776215022020636 0ustar kaikai /* * MyDll demonstration of how to write D DLLs. */ import core.stdc.stdio; import core.stdc.stdlib; import std.string; import core.sys.windows.windows; import core.memory; import core.runtime; import core.sys.windows.dll; HINSTANCE g_hInst; extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { switch (ulReason) { case DLL_PROCESS_ATTACH: printf("DLL_PROCESS_ATTACH\n"); dll_process_attach(hInstance); //Runtime.initialize(); break; case DLL_PROCESS_DETACH: printf("DLL_PROCESS_DETACH\n"); core.stdc.stdio._fcloseallp = null; // so stdio doesn't get closed dll_process_detach(hInstance); //Runtime.terminate(); break; case DLL_THREAD_ATTACH: printf("DLL_THREAD_ATTACH\n"); return false; case DLL_THREAD_DETACH: printf("DLL_THREAD_DETACH\n"); return false; default: assert(0); } g_hInst=hInstance; return true; } static this() { printf("static this for mydll\n"); } static ~this() { printf("static ~this for mydll\n"); } /* --------------------------------------------------------- */ class MyClass { string concat(string a, string b) { return a ~ " " ~ b; } void free(string s) { delete s; } } export MyClass getMyClass() { printf("getMyClass()\n"); auto c = new MyClass(); printf("allocated\n"); return c; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/0000775000175000017500000000000012776215022020204 5ustar kaikaildc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/template4.d0000664000175000017500000005216612776215022022262 0ustar kaikaiimport std.stdio; import core.stdc.stdio; /*********************************************************/ template Foo(T) { static if ( is(T : int) ) alias T t1; static if (T.sizeof == 4) alias T t2; static if ( is(T AB : int) ) alias AB t3; static if ( is(T* V : V*) ) alias V t4; static if ( is(T W) ) alias W t5; else alias char t5; static if ( is(T* X : X*) ) { } } void test1() { Foo!(int).t1 x1; assert(typeid(typeof(x1)) == typeid(int)); Foo!(int).t2 x2; assert(typeid(typeof(x2)) == typeid(int)); Foo!(int).t3 x3; assert(typeid(typeof(x3)) == typeid(int)); Foo!(int).t4 x4; assert(typeid(typeof(x4)) == typeid(int)); Foo!(int).t5 x5; assert(typeid(typeof(x5)) == typeid(int)); Foo!(int).X x6; assert(typeid(typeof(x6)) == typeid(int)); } /*********************************************************/ void test2() { alias int T; static if ( is(T : int) ) alias T t1; static if (T.sizeof == 4) alias T t2; static if ( is(T U : int) ) alias U t3; static if ( is(T* V : V*) ) alias V t4; static if ( is(T W) ) alias W t5; else alias char t5; static if ( is(T* X : X*) ) { } t1 x1; assert(typeid(typeof(x1)) == typeid(int)); t2 x2; assert(typeid(typeof(x2)) == typeid(int)); t3 x3; assert(typeid(typeof(x3)) == typeid(int)); t4 x4; assert(typeid(typeof(x4)) == typeid(int)); t5 x5; assert(typeid(typeof(x5)) == typeid(int)); X x6; assert(typeid(typeof(x6)) == typeid(int)); } /*********************************************************/ void test3() { static if ( is(short : int) ) { printf("1\n"); } else assert(0); static if ( is(short == int) ) assert(0); static if ( is(int == int) ) { printf("3\n"); } else assert(0); } /*********************************************************/ void test4() { alias void Function(int); static if (is(Function Void == function)) printf("if\n"); else assert(0); // static if (is(Void == void)) // printf("if\n"); // else // assert(0); alias byte delegate(int) Delegate; static if (is(Delegate Foo == delegate)) printf("if\n"); else assert(0); static if (is(Foo Byte == function)) printf("if\n"); else assert(0); // static if (is(Byte == byte)) // printf("if\n"); // else // assert(0); union Union { } static if (is(Union == union)) printf("if\n"); else assert(0); struct Struct { } static if (is(Struct == struct)) printf("if\n"); else assert(0); enum Enum : short { EnumMember } static if (is(Enum Short == enum)) printf("if\n"); else assert(0); static if (is(Short == short)) printf("if\n"); else assert(0); class Class { } static if (is(Class == class)) printf("if\n"); else assert(0); interface Interface { } static if (is(Interface == interface)) printf("if\n"); else assert(0); } /*********************************************************/ class Foo5(T) { Node sentinel; struct Node { int value; } } void test5() { Foo5!(int) bar=new Foo5!(int); bar.sentinel.value = 7; } /*********************************************************/ template factorial6(int n) { static if (n == 1) const int factorial6 = 1; else const int factorial6 = n * .factorial6!(n-1); } void test6() { int i = factorial6!(4); printf("%d\n", i); assert(i == 24); } /*********************************************************/ template factorial7(float n, cdouble c, string sss, string ttt) { static if (n == 1) const float factorial7 = 1; else const float factorial7 = n * 2; } template bar7(wstring abc, dstring def) { const int x = 3; } void test7() { float f = factorial7!(4.25, 6.8+3i, "hello", null); printf("%g\n", f); assert(f == 8.5); int i = bar7!("abc"w, "def"d).x; printf("%d\n", i); assert(i == 3); } /*********************************************************/ template whale(string walrus) { const char [] whale = walrus; } template dolphin(string fish) { const char [] dolphin = whale!(fish[0..3]); } const char [] urchin1 = dolphin!("anenome"); const char [] urchin2 = whale!("anenome"[0..3]); template dolphin3(string fish) { const char [] dolphin3 = fish[0..3]; } const char [] urchin3 = dolphin3!("anenome"); template dolphin4(string fish) { const char [] dolphin4 = whale!(fish[0..(3)]); } const char [] urchin4 = dolphin4!("anenome"); template dolphin5(string fish) { const char [] dolphin5 = whale!(fish[(0)..3]); } const char [] urchin5 = dolphin5!("anenome"); void test8() { assert(urchin1 == "ane"); assert(urchin2 == "ane"); assert(urchin3 == "ane"); assert(urchin4 == "ane"); assert(urchin5 == "ane"); } /*********************************************************/ int testEmpty(string s) { return 0; } template Recurse(string pattern){ } template slice(string str, int from, int to) { const string slice = str[from..to]; } template Compile(string pattern) { const string left = slice!(pattern,4,pattern.length); const string remaining = slice!(left,1,left.length); alias Recurse!(remaining) fn; } template Match(string pattern) { alias Compile!(pattern) Match; } void test9() { alias Match!("abcdefghijk") f; } /*********************************************************/ template Foo10(string s) { const string Foo10 = s; } void test10() { string s; s = Foo10!("abc" ~ "e"); assert(s == "abce"); s = Foo10!("abc" ~ 'f'); assert(s == "abcf"); s = Foo10!('g' ~ "abc"); assert(s == "gabc"); s = Foo10!('g' ~ "abc" ~ 'h'); assert(s == "gabch"); } /*********************************************************/ template Foo11(string s) { const string Foo11 = s; } void test11() { string s; s = Foo11!("abcdef"[1..$ - 1]); assert(s == "bcde"); } /*********************************************************/ template Foo12(int i) { const int Foo12 = i; } void test12() { int i; i = Foo12!("abcdef" == "abcdef"); assert(i == 1); i = Foo12!("abcdef" == "abcqef"); assert(i == 0); i = Foo12!("abcdef" == "abc"); assert(i == 0); i = Foo12!("abc" == "abcdef"); assert(i == 0); } /*********************************************************/ const a13 = 3; static if (a13 == 3) int b13 = 7; template Foo13(int i) { const int j = i + 1; static if (j == 3) const int k = 2; } void test13() { assert(b13 == 7); assert(Foo13!(2).k == 2); } /*********************************************************/ template zebra(string w) { static if (w.length > 2 && w[1] == 'q') const bool zebra = true; else const bool zebra = false; } template horse(string w) { static if (w.length == 1 || w[1] == 'q') const bool horse = true; else const bool horse = false; } void test14() { bool lion = zebra!("a"); writeln(lion); assert(!lion); lion = zebra!("aqb"); writeln(lion); assert(lion); lion = horse!("a"); writeln(lion); assert(lion); lion = horse!("aqb"); writeln(lion); assert(lion); lion = horse!("ab"); writeln(lion); assert(!lion); } /*********************************************************/ template factorial15(int n) { static if (n<2) const int factorial15 = 1; else const int factorial15 = n * factorial15!(n-1); } template rhino15(alias hippo) { const int rhino15 = hippo!(3); } void test15() { const int lion = rhino15!(factorial15); assert(lion == 6); } /*********************************************************/ // Create a constant array of int or uint sized items // as a dstring string. n is the index of the last item. template makeLookup(alias entry, int n) { static if (n == -1) // start with an empty array... const dchar [] makeLookup = ""; else // ... and fill it up const dchar [] makeLookup = makeLookup!(entry, n-1) ~ cast(dchar)entry!(n); } template factorial16(uint n) { static if (n<2) const uint factorial16 = 1; else const factorial16 = n * factorial16!(n-1); } // Make an array of factorials from 0 to 13 (14!> uint.max) const smallfactorials = makeLookup!(factorial16, 13); const uint[14] testtable = [ 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 1932053504, ]; void test16() { for (int i=0; i99 && fish!( (bird[95])) ) const int dog = 2; else const int dog = 3; } const int pig = dog!("a"); void test23() { } /*********************************************************/ T delegate (T) acc24 (T) (T n) { return (T i) { return n += i; }; } void test24() { auto acc1 = acc24 (4); } /*********************************************************/ T func25(T, T c = 1)(T x) { return x * c; } void test25() { double d; d = func25(1.0); assert(d == 1.0); d = func25(2.0); assert(d == 2.0); d = func25!(double)(2.0); assert(d == 2.0); d = func25!(double, 3)(2.0); assert(d == 6.0); } /*********************************************************/ class Foo26 {} class Bar26 {} string name26; template aliastest(alias A) { pragma(msg,"Alias Test instantiated"); void aliastest() { name26 = (new A!().al).classinfo.name; //writefln("Alias Test: ", name26); } } template boxtpl(alias A) { template box() { alias A al; } } void test26() { aliastest!(boxtpl!(Foo26).box) (); assert(name26 == "template4.Foo26"); aliastest!(boxtpl!(Bar26).box) (); assert(name26 == "template4.Bar26"); } /*********************************************************/ struct TFoo27(int x) { } alias TFoo27!(3) a; alias TFoo27!(2+1) b; alias TFoo27!(3u) c; static assert(is(TFoo27!(3) == TFoo27!(2 + 1))); static assert(is(TFoo27!(3) == TFoo27!(3u))); void test27() { } /*********************************************************/ struct SiQuantity { real value = 0; static assert(SiQuantity.sizeof == real.sizeof); template AddDimensions(int mul, U) { } } void test28() { } /*********************************************************/ template Count29() { const Count29 = 5; } void test29() { int[Count29!()] x; assert(x.length == 5); } /*********************************************************/ class FooClass(T) { T data; } struct FooStruct(T) { T data; } void bar_struct(T)(FooStruct!(T) a) {} void bar_class(T)(FooClass!(T) a) {} void test30() { auto C = new FooClass!(double); FooStruct!(double) S; bar_struct(S); bar_class!(double)(C); bar_class(C); } /*********************************************************/ V get31(V,K)(V[K] dict, K key, V def = V.init) { V* ptr = key in dict; return ptr? *ptr: def; } string get31x(string[int] dict, int key, string def = null) { string* ptr = key in dict; return ptr? *ptr: def; } void test31() { string[int] i2s; i2s[1] = "Hello"; i2s[5] = "There"; writeln( i2s.get31(1, "yeh") ); writeln( i2s.get31(2, "default") ); writeln( i2s.get31(1) ); writeln( i2s.get31(2) ); } /*********************************************************/ void delegate(T, S) Concat(S, T...)(void delegate(T) one, void delegate(S) two) { return( delegate void(T t, S s){} ); } void test32() { void delegate(char, char, int) wtf = Concat( delegate void(char a, char b) {}, delegate void(int lol) {} ); } /*********************************************************/ struct Composer(T) { alias T delegate(T) Fun; Fun[] funs; public T opCall()(T x) { T result = x; foreach_reverse (f; funs) { result = f(result); } return result; } public void opAddAssign(Fun f) { funs ~= f; } } struct square(T) { T opCall(T t) { return t*t; } } struct plus1(T) { T opCall(T t) { return t+1; } } struct div3(T) { T opCall(T t) { return t/3.0; } } T delegate(T) tofp(T : S!(T), alias S)() { class Foo { div3!(T) arg; T bar(T t) { return arg(t); } } Foo f = new Foo; return &f.bar; } void test33() { Composer!(double) comp; comp += delegate double (double x) { return x/3.0;}; comp += delegate double (double x) { return x*x;}; comp += (double x) => x + 1.0; writefln("%f", comp(2.0)); // Try function objects Composer!(double) comp2; comp2 += tofp!(div3!(double))(); comp2 += tofp!(square!(double))(); comp2 += tofp!(plus1!(double))(); writefln("%f", comp2( 2.0)); } /*********************************************************/ template Print34(Ts ...) { pragma (msg, Ts.stringof); } template Tuple34(Ts ...) { alias Ts Tuple34; } template Decode34( T ) { alias Tuple34!() Types; } template Decode34( T : TT!(U1), alias TT, U1 ) { alias Tuple34!(U1) Types; } template Decode34( T : TT!(U1,U2), alias TT, U1, U2 ) { alias Tuple34!(U1,U2) Types; } template Decode34( T : TT!(U1,U2,U3), alias TT, U1, U2, U3 ) { alias Tuple34!(U1,U2,U3) Types; } struct S34_1(T1) {} struct S34_2(T1, T2) {} struct S34_3(T1, T2, T3) {} alias Decode34!( bool ).Types SQ0; alias Decode34!( S34_1!(bool) ).Types SQ1; alias Decode34!( S34_2!(bool,short) ).Types SQ2; alias Decode34!( S34_3!(bool,short,int) ).Types SQ3; mixin Print34!(SQ0); mixin Print34!(SQ1); mixin Print34!(SQ2); mixin Print34!(SQ3); void test34() { } /*********************************************************/ template strof(T) { static string strof = T.stringof; } void test35() { alias typeof(delegate () { return (char[]).init;} ) del; auto a = strof!(del); auto aa = strof!(int); auto ab = strof!(typeof(5)); auto meth = delegate () { return (char[]).init;}; auto b = strof!(typeof(meth)); auto c = strof!(typeof(delegate () { return 5; } )); auto d = strof!(typeof(delegate () { return (char[]).init;} )); } /*********************************************************/ struct Number36(int N) { const int value = N; } struct Foo36(T) { int talk() { printf("Not so special:\n"); return 1; } } struct Foo36(T : Number36!(N), int N) { int talk() { printf("Ooh special - NUMBER N\n"); return 2; } } void test36() { Foo36!(Number36!(5)) x; auto i = x.talk(); assert(i == 2); } /*********************************************************/ struct Base37(T) {} alias Base37 Alias37; void foo37(T)(Alias37!(T) x) {} void test37() { Base37!(float) b; foo37(b); // fails! } /*********************************************************/ void sort(alias dg, T)(T[] arr) { bool a = dg(1,2); printf("a = %d\n", a); assert(a == true); } void test38() { int[] arr; int i = 3; sort!( (x,y){ return x + i > y; } )(arr); sort!( (int x,int y){ return x + i > y; } )(arr); } /*********************************************************/ void bug4652(U, T...)(long y, T x, U num) {} void bug4652default(T) (T value, int x=2) {} void bug4652default(T) (T value, int y) {} void bug4676(T...)(T args, string str) {} void bug4676(T...)(T args) {} void instantiate4652() { bug4652(2, 'c', 27, 'e', 'f',1); // rejects-valid bug4652(2, 1); // infinite loop on valid code bug4652default(true); bug4676(1, 2, 3); } /*********************************************************/ // 7589 struct T7589(T) { void n; } static assert(!__traits(compiles, T7589!(int))); int bug7589b(T)() @safe { int *p; *(p + 8) = 6; } static assert(!__traits(compiles, bug7589b!(int)()+7 )); /*********************************************************/ int bar39(alias dg)(int i) { return dg(i); } void test39() { auto i = bar39!(a => a + 1)(3); if (i != 4) assert(0); } /*********************************************************/ // 6701 uint foo_6701(uint v:0)() { return 1; } uint foo_6701(uint v)() { return 0; } uint foo2_6701(uint v:0, string op)() { return 1; } uint foo2_6701(uint v, string op)() { return 0; } void test6701() { assert(foo_6701!(0u)() == 1); assert(foo2_6701!(0u, "+")() == 1); } /******************************************/ // 7469 struct Foo7469a(int x) { } struct Foo7469b(int x) { } struct Foo7469c(alias v) { } struct Foo7469d(T...) { } struct Foo7469e(int a, T...) { } struct Foo7469f(T, int k=1) { } struct Foo7469g(T, int k=1) { } void test7469() { static assert(Foo7469a!(3 ) .mangleof[$-28 .. $] == "17__T8Foo7469aVii3Z8Foo7469a"); static assert(Foo7469a!(3u) .mangleof[$-28 .. $] == "17__T8Foo7469aVii3Z8Foo7469a"); static assert(Foo7469b!(3u) .mangleof[$-28 .. $] == "17__T8Foo7469bVii3Z8Foo7469b"); static assert(Foo7469b!(3 ) .mangleof[$-28 .. $] == "17__T8Foo7469bVii3Z8Foo7469b"); static assert(Foo7469c!(3 ) .mangleof[$-28 .. $] == "17__T8Foo7469cVii3Z8Foo7469c"); static assert(Foo7469c!(3u) .mangleof[$-28 .. $] == "17__T8Foo7469cVki3Z8Foo7469c"); static assert(Foo7469d!(3 ) .mangleof[$-28 .. $] == "17__T8Foo7469dVii3Z8Foo7469d"); static assert(Foo7469d!(3u) .mangleof[$-28 .. $] == "17__T8Foo7469dVki3Z8Foo7469d"); static assert(Foo7469e!(3u, 5u).mangleof[$-32 .. $] == "21__T8Foo7469eVii3Vki5Z8Foo7469e"); static assert(Foo7469f!(int, 1).mangleof[$-30 .. $] == "19__T8Foo7469fTiVii1Z8Foo7469f"); static assert(Foo7469f!(int) .mangleof[$-30 .. $] == "19__T8Foo7469fTiVii1Z8Foo7469f"); static assert(Foo7469g!(int) .mangleof[$-30 .. $] == "19__T8Foo7469gTiVii1Z8Foo7469g"); static assert(Foo7469g!(int, 1).mangleof[$-30 .. $] == "19__T8Foo7469gTiVii1Z8Foo7469g"); } /******************************************/ template foo7698a(T, T val : 0) { enum foo7698a = val; } T foo7698b(T, T val : 0)() { return val; } T foo7698c(T, T val : T.init)() { return val; } void test7698() { static assert(foo7698a!(int, 0) == 0); assert(foo7698b!(int, 0)() == 0); assert(foo7698c!(int, 0)() == 0); } /*********************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test6701(); test7698(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_426.d0000664000175000017500000000142312776215022023050 0ustar kaikaiint dtor; struct DestroyMe { ~this() { ++dtor; } int opApply(in int delegate(int item) dg) { throw new Exception("Here we go!"); } } void test1() { dtor = 0; try { foreach (item; DestroyMe()) {} } catch {} assert(dtor == 1); dtor = 0; try { auto lvalue = DestroyMe(); foreach (item; lvalue) {} } catch {} assert(dtor == 1); } /******************************************/ struct DoNotDestroyMe { ~this() { assert(0); } } DoNotDestroyMe doNotDestroyMe() { throw new Exception("Here we go!"); return DoNotDestroyMe(); } void fun(E)(lazy E exp) { try { exp(); } catch {} } void test2() { fun(doNotDestroyMe()); } void main() { test1(); test2(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/hello.d0000664000175000017500000000043412776215022021455 0ustar kaikai// PERMUTE_ARGS: extern(C) int printf(const char*, ...); int main(char[][] args) { printf("hello world\n"); printf("args.length = %d\n", args.length); for (int i = 0; i < args.length; i++) printf("args[%d] = '%.*s'\n", i, args[i].length, args[i].ptr); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_556.d0000664000175000017500000000041412776215022023053 0ustar kaikaivoid main() { union TestUnion { ubyte[20] small; ubyte[28] large; } struct Container { TestUnion u; byte b; } Container c; c.b = 123; assert(*((cast(ubyte*)cast(void*)&c) + Container.b.offsetof) == 123); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test7452.d0000664000175000017500000000260112776215022021651 0ustar kaikaiimport core.stdc.stdio : printf; //------------------------------------------------------------------------------ T enforce7452(T, string file = __FILE__, size_t line = __LINE__) (T value, lazy const(char)[] msg = null) @safe pure { if (!value) throw new Exception(msg ? msg.idup : "Enforcement failed", file, line); return value; } int f7452()(int x) { enforce7452(x > 0); return x; } void g7452() @safe pure { assert(4 == f7452(4)); } //------------------------------------------------------------------------------ void e7452b(int, lazy int) pure nothrow @safe {} int f7452b()(int x) { e7452b(x, 0); return x; } void g7452b() pure nothrow @safe { assert(4 == f7452b(4)); } //------------------------------------------------------------------------------ int f7452c()(int x) { auto y = function int() { return 0; }; return x; } void g7452c() pure nothrow @safe { assert(4 == f7452c(4)); } //------------------------------------------------------------------------------ auto f6332a()() { return 1; } int f6332b()() { return 1; } alias f6332a!() F6332a; void g6332() pure nothrow @safe { auto x = f6332b(); auto y = f6332a(); assert(x == y); } //------------------------------------------------------------------------------ int main() { g7452(); g7452b(); g7452c(); g6332(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test57.d0000664000175000017500000000027112776215022021504 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/test57a.d imports/test57b.d // PERMUTE_ARGS: // REQUIRED_ARGS: -inline -release module test57; import imports.test57a; void main() {} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testreturn.d0000664000175000017500000000745712776215022022605 0ustar kaikaiextern(C) int printf(const char*, ...); alias TypeTuple(T...) = T; /***************************************************/ // 13336 struct S13336 { int opApply(scope int delegate(int) dg) { return dg(0); } } double result13336; enum fbody13336 = q{ static if (n == 1) { if (f) return sx; return sy; } static if (n == 2) { foreach (e; S13336()) { if (f) return sx; return sy; } assert(0); } static if (n == 3) { if (f) return sx; foreach (e; S13336()) { return sy; } assert(0); } static if (n == 4) { foreach (e; S13336()) { if (f) return sx; } return sy; } static if (n == 5) { if (false) return 99; foreach (e; S13336()) { if (f) return sx; return sy; } assert(0); } static if (n == 6) { foreach (e; S13336()) { if (f) return sx; return sy; } return 99; } }; // auto ref without out contract auto ref f13336a(int n, alias sx, alias sy)(bool f) { mixin(fbody13336); } // auto without out contract auto f13336b(int n, alias sx, alias sy)(bool f) { mixin(fbody13336); } // auto ref with out contract auto ref f13336c(int n, alias sx, alias sy)(bool f) out(r) { static assert(is(typeof(r) == const double)); assert(r == (f ? sx : sy)); result13336 = r; } body { mixin(fbody13336); } // auto with out contract auto f13336d(int n, alias sx, alias sy)(bool f) out(r) { static assert(is(typeof(r) == const double)); assert(r == (f ? sx : sy)); result13336 = r; } body { mixin(fbody13336); } void test13336() { static int sx = 1; static double sy = 2.5; foreach (num; TypeTuple!(1, 2, 3, 4, 5, 6)) { foreach (foo; TypeTuple!(f13336a, f13336b)) { alias fooxy = foo!(num, sx, sy); static assert(is(typeof(&fooxy) : double function(bool))); assert(fooxy(1) == 1.0); assert(fooxy(0) == 2.5); alias fooyx = foo!(num, sy, sx); static assert(is(typeof(&fooyx) : double function(bool))); assert(fooyx(1) == 2.5); assert(fooyx(0) == 1.0); } foreach (foo; TypeTuple!(f13336c, f13336d)) { alias fooxy = foo!(num, sx, sy); static assert(is(typeof(&fooxy) : double function(bool))); assert(fooxy(1) == 1.0 && result13336 == 1.0); assert(fooxy(0) == 2.5 && result13336 == 2.5); alias fooyx = foo!(num, sy, sx); static assert(is(typeof(&fooyx) : double function(bool))); assert(fooyx(1) == 2.5 && result13336 == 2.5); assert(fooyx(0) == 1.0 && result13336 == 1.0); } } } /***************************************************/ // 15018 struct S15018(int n) { short[n] m; } S15018!n f15018(int n)() { S15018!n s; foreach(i; 0..n) s.m[i] = cast(short)(i * i + 3); return s; } void test15018() { // size 4 S15018!2[3] s3; s3[] = f15018!2(); foreach (int i; 0..3) { assert(s3[i].m[0] == 3); assert(s3[i].m[1] == 4); } // size 4-18 foreach (n; TypeTuple!(2, 3, 4, 5, 6, 7, 8, 9)) { S15018!n[5] i5; i5[] = f15018!n(); foreach (int j; 0..5) foreach(k; 0..n) if (i5[j].m[k] != k * k + 3) assert(false); } } /***************************************************/ int main() { test13336(); test15018(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testUTF32.d0000664000175000017500000000150412776215022022054 0ustar kaikai// encoding :utf-32le-bom int main(){ assert('y'== 0x79); assert(''== 0x80); assert(''== 0x799); assert(''== 0x800); assert(''== 0xFFFA); assert(''== 0x10000); assert(''== 0x10FFD); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/a20.d0000664000175000017500000000044612776215022020737 0ustar kaikai// EXTRA_SOURCES: imports/a20a.d // PERMUTE_ARGS: // REQUIRED_ARGS: -cov // POST_SCRIPT: runnable/extra-files/a20-postscript.sh // EXECUTE_ARGS: ${RESULTS_DIR}/runnable import a20a; extern(C) void dmd_coverDestPath(string path); void main(string[] args) { dmd_coverDestPath(args[1]); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/tls_dup.d0000664000175000017500000000323112776215022022022 0ustar kaikai// NOTE: this is a dup of runnable/tls.d strictly to test the same code compiled // separately rather than together like the original is. // COMPILE_SEPARATELY // EXTRA_SOURCES: imports/tlsa.d // PERMUTE_ARGS: import core.stdc.stdio; import imports.tlsa; int x = 3; void bar() { int* px = &x; assert(x == 3); x++; printf("x = %d\n", x); px = &x; printf("px = %p\n", px); assert(*px == 4); (*px)++; assert(x == 5); } void test1() { bar(); printf("%d\n", x); printf("%d\n", foo!()()); } /************************************/ long fooa; long foob; int bara = 0x12345678; int barb = 0x9ABCDEFF; void test2() { fooa++; foob--; bara++; barb++; printf("%lld %lld %x %x\n", fooa, foob, bara, barb); assert(fooa == 1); assert(foob == -1); assert(bara == 0x12345679); assert(barb == 0x9ABCDF00); } /************************************/ int abc3(T)(T t) { static T qqq; static T rrr; static T sss = 8; static T ttt = 9; printf("qqq = %d, rrr = %d, sss = %d, ttt = %d\n", qqq, rrr, sss, ttt); assert(sss == 8); assert(ttt == 9); rrr += 7; return t + ++qqq + rrr; } void test3() { auto i = abc3(3); printf("i = x%x\n", i); assert(i == 11); i = abc3(4); printf("i = x%x\n", i); assert(i == 20); } /************************************/ void test4() { auto i = bar4(); printf("i = x%x\n", i); assert(i == 0x23); i = abc4(4); printf("i = x%x\n", i); assert(i == 0x31); } /************************************/ int main() { test1(); test2(); test3(); test4(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test13613.d0000664000175000017500000000251612776215022021732 0ustar kaikai// PERMUTE_ARGS: // MT!"y" is analyzed from the pragma inside MT!"x" /* TEST_OUTPUT: --- CT x.offsetof = < CT y.offsetof = < 0 > y 0 > x --- */ mixin template MT(string id) { union { mixin("void* " ~ id ~ ";"); } // Evaluating `typeof(this).init` completes data layout. pragma(msg, "CT " ~ id ~ ".offsetof = <\n", cast(int)typeof(this).init.i.offsetof, " > " ~ id); } struct S1 { int i; mixin MT!"x"; mixin MT!"y"; } struct S2 { int i; union { void* x; } union { void* y; } } struct S3 { int i; void* x; void* y; } void main() { // S1, S2, and S3 should have exactly same data layout. static assert(S1.i.offsetof == S3.i.offsetof); static assert(S1.i.offsetof == S3.i.offsetof); static assert(S1.x.offsetof == S3.x.offsetof); static assert(S1.y.offsetof == S3.y.offsetof); static assert(S2.x.offsetof == S3.x.offsetof); static assert(S2.y.offsetof == S3.y.offsetof); static assert(S1.sizeof == S3.sizeof); static assert(S2.sizeof == S3.sizeof); S1 s = void; s.i = 1; assert(s.i == 1); s.x = null; assert(s.i == 1); s.y = null; assert(s.i == 1); char a, b; s.x = cast(void*)&a; assert(s.x is &a); assert(s.y is null); s.y = cast(void*)&b; assert(s.x is &a); assert(s.y is &b); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testfile.d0000664000175000017500000000052612776215022022173 0ustar kaikai// PERMUTE_ARGS: import std.file; import std.stdio; /***********************************************/ void test1() { auto p = std.file.getcwd(); writefln("%s '%s'\n", p.length, p); assert(p[$ - 1] != 0); } /***********************************************/ int main() { test1(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test48.d0000664000175000017500000000216712776215022021512 0ustar kaikai// EXTRA_SOURCES: imports/test48a.d // PERMUTE_ARGS: import std.stdio; import imports.test48a; void main() { S s; auto i = s.tupleof[0] + s.tupleof[1] + s.tupleof[2]; printf("i = %d\n", i); assert(i == 6); auto t = s.tupleof; i = t[0] + t[1] + t[2]; printf("i = %d\n", i); assert(i == 6); printf("a = %d %d %d\n", S.tupleof.offsetof); auto o = S.tupleof.offsetof; assert(o[0] == 0); assert(o[1] == 4); assert(o[2] == 8); printf("a = %d %d %d\n", S.tupleof[0].offsetof, S.tupleof[1].offsetof, S.tupleof[2].offsetof); assert(S.tupleof[0].offsetof == 0); assert(S.tupleof[1].offsetof == 4); assert(S.tupleof[2].offsetof == 8); auto offset0 = cast(void*)&s.tupleof[0] - cast(void*)&s; printf("offset0 = %d\n", offset0); assert(offset0 == 0); auto offset1 = cast(void*)&s.tupleof[1] - cast(void*)&s; printf("offset1 = %d\n", offset1); assert(offset1 == 4); auto offset2 = cast(void*)&s.tupleof[2] - cast(void*)&s; printf("offset2 = %d\n", offset2); assert(offset2 == 8); int t1[S.tupleof.offsetof[1]]; assert(t1.length == 4); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link12144.d0000664000175000017500000000055012776215022021702 0ustar kaikai// COMPILE_SEPARATELY: -g // EXTRA_SOURCES: imports/link12144a.d import imports.link12144a; void main() { fun(); } struct A12146 { B12146[] tokens; // implicitly generated // bool opEquals(const ref Appender rhs) const // will make // tokens == rhs.tokens // references TypeInfo of B12146 // and it references __xopCmp } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/wc3.d0000664000175000017500000000243612776215022021052 0ustar kaikai// PERMUTE_ARGS: // EXECUTE_ARGS: runnable/extra-files/alice30.txt import std.stdio; import std.file; int main (string[] args) { int w_total; int l_total; int c_total; int[string] dictionary; writefln(" lines words bytes file"); foreach (arg; args[1 .. args.length]) { int w_cnt, l_cnt, c_cnt; size_t wstart; bool inword; auto input = cast(string)std.file.read(arg); foreach (j, c; input) { if (c == '\n') ++l_cnt; if (c >= '0' && c <= '9') { } else if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') { if (!inword) { wstart = j; inword = true; ++w_cnt; } } else if (inword) { auto word = input[wstart .. j]; dictionary[word]++; inword = false; } ++c_cnt; } if (inword) { auto w = input[wstart .. input.length]; dictionary[w]++; } writefln("%8s%8s%8s %s", l_cnt, w_cnt, c_cnt, arg); l_total += l_cnt; w_total += w_cnt; c_total += c_cnt; } if (args.length > 2) { writefln("--------------------------------------\n%8s%8s%8s total", l_total, w_total, c_total); } writefln("--------------------------------------"); foreach (word1; dictionary.keys.sort) { writefln("%3s %s", dictionary[word1], word1); } return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/evalorder.d0000664000175000017500000000101412776215022022330 0ustar kaikaiextern(C) int printf(const char*, ...); void test14040() { uint[] values = [0, 1, 2, 3, 4, 5, 6, 7]; uint offset = 0; auto a1 = values[offset .. offset += 2]; if (a1 != [0, 1] || offset != 2) assert(0); uint[] fun() { offset += 2; return values; } auto a2 = fun()[offset .. offset += 2]; if (a2 != [4, 5] || offset != 6) assert(0); } /******************************************/ int main() { test14040(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test27.d0000664000175000017500000000026412776215022021503 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/test27a.d // PERMUTE_ARGS: import imports.test27a; int main() { auto v = new myClass!(int)(); v.func(5); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test10.d0000664000175000017500000000033212776215022021467 0ustar kaikai// EXTRA_SOURCES: imports/test10a.d import imports.test10a; extern(C) int printf(const char*, ...); int main() { imports.test10a.init(); printf("it is %d\n", it[0]); assert(it[0] == 32); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testxmm.d0000664000175000017500000013346212776215022022063 0ustar kaikai// REQUIRED_ARGS: // enabled on LDC: win64 version (D_SIMD) { import core.simd; import core.stdc.string; import std.stdio; alias TypeTuple(T...) = T; /*****************************************/ void test1() { void16 v1 = void,v2 = void; byte16 b; v2 = b; v1 = v2; static assert(!__traits(compiles, v1 + v2)); static assert(!__traits(compiles, v1 - v2)); static assert(!__traits(compiles, v1 * v2)); static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); static assert(!__traits(compiles, v1 & v2)); static assert(!__traits(compiles, v1 | v2)); static assert(!__traits(compiles, v1 ^ v2)); static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); static assert(!__traits(compiles, ~v1)); static assert(!__traits(compiles, -v1)); static assert(!__traits(compiles, +v1)); static assert(!__traits(compiles, !v1)); static assert(!__traits(compiles, v1 += v2)); static assert(!__traits(compiles, v1 -= v2)); static assert(!__traits(compiles, v1 *= v2)); static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); static assert(!__traits(compiles, v1 &= v2)); static assert(!__traits(compiles, v1 |= v2)); static assert(!__traits(compiles, v1 ^= v2)); static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2() { byte16 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; static assert(!__traits(compiles, v1 * v2)); static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; static assert(!__traits(compiles, v1 *= v2)); static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2b() { ubyte16 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; static assert(!__traits(compiles, v1 * v2)); static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; static assert(!__traits(compiles, v1 *= v2)); static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2c() { short8 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2d() { ushort8 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2e() { int4 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; static assert(!__traits(compiles, v1 * v2)); static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; static assert(!__traits(compiles, v1 *= v2)); static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2f() { uint4 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; static assert(!__traits(compiles, v1 * v2)); static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; static assert(!__traits(compiles, v1 *= v2)); static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2g() { long2 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; static assert(!__traits(compiles, v1 * v2)); static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; static assert(!__traits(compiles, v1 *= v2)); static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2h() { ulong2 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; static assert(!__traits(compiles, v1 * v2)); static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; static assert(!__traits(compiles, v1 *= v2)); static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2i() { float4 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; static assert(!__traits(compiles, v1 % v2)); static assert(!__traits(compiles, v1 & v2)); static assert(!__traits(compiles, v1 | v2)); static assert(!__traits(compiles, v1 ^ v2)); static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); static assert(!__traits(compiles, ~v1)); v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; static assert(!__traits(compiles, v1 %= v2)); static assert(!__traits(compiles, v1 &= v2)); static assert(!__traits(compiles, v1 |= v2)); static assert(!__traits(compiles, v1 ^= v2)); static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2j() { double2 v1,v2,v3; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; static assert(!__traits(compiles, v1 % v2)); static assert(!__traits(compiles, v1 & v2)); static assert(!__traits(compiles, v1 | v2)); static assert(!__traits(compiles, v1 ^ v2)); static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); static assert(!__traits(compiles, ~v1)); v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; static assert(!__traits(compiles, v1 %= v2)); static assert(!__traits(compiles, v1 &= v2)); static assert(!__traits(compiles, v1 |= v2)); static assert(!__traits(compiles, v1 ^= v2)); static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ float4 test3() { float4 a; a = __simd(XMM.PXOR, a, a); return a; } /*****************************************/ void test4() { int4 c = 7; (cast(int[4])c)[3] = 4; (cast(int*)&c)[2] = 4; c.array[1] = 4; c.ptr[3] = 4; assert(c.length == 4); } /*****************************************/ void BaseTypeOfVector(T : __vector(T[N]), size_t N)(int i) { assert(is(T == int)); assert(N == 4); } void test7411() { BaseTypeOfVector!(__vector(int[4]))(3); } /*****************************************/ // 7951 float[4] test7951() { float4 v1; float4 v2; return cast(float[4])(v1+v2); } /*****************************************/ void test7951_2() { float[4] v1 = [1,2,3,4]; float[4] v2 = [1,2,3,4]; float4 f1, f2, f3; f1.array = v1; f2.array = v2; f3 = f1 + f2; } /*****************************************/ void test7949() { int[4] o = [1,2,3,4]; int4 v1; v1.array = o; int4 v2; v2.array = o; auto r = __simd(XMM.ADDPS, v1,v2); writeln(r.array); } /*****************************************/ immutable ulong2 gulong2 = 0x8000_0000_0000_0000; immutable uint4 guint4 = 0x8000_0000; immutable ushort8 gushort8 = 0x8000; immutable ubyte16 gubyte16 = 0x80; immutable long2 glong2 = 0x7000_0000_0000_0000; immutable int4 gint4 = 0x7000_0000; immutable short8 gshort8 = 0x7000; immutable byte16 gbyte16 = 0x70; immutable float4 gfloat4 = 4.0; immutable double2 gdouble2 = 8.0; void test7414() { immutable ulong2 lulong2 = 0x8000_0000_0000_0000; assert(memcmp(&lulong2, &gulong2, gulong2.sizeof) == 0); immutable uint4 luint4 = 0x8000_0000; assert(memcmp(&luint4, &guint4, guint4.sizeof) == 0); immutable ushort8 lushort8 = 0x8000; assert(memcmp(&lushort8, &gushort8, gushort8.sizeof) == 0); immutable ubyte16 lubyte16 = 0x80; assert(memcmp(&lubyte16, &gubyte16, gubyte16.sizeof) == 0); immutable long2 llong2 = 0x7000_0000_0000_0000; assert(memcmp(&llong2, &glong2, glong2.sizeof) == 0); immutable int4 lint4 = 0x7000_0000; assert(memcmp(&lint4, &gint4, gint4.sizeof) == 0); immutable short8 lshort8 = 0x7000; assert(memcmp(&lshort8, &gshort8, gshort8.sizeof) == 0); immutable byte16 lbyte16 = 0x70; assert(memcmp(&lbyte16, &gbyte16, gbyte16.sizeof) == 0); immutable float4 lfloat4 = 4.0; assert(memcmp(&lfloat4, &gfloat4, gfloat4.sizeof) == 0); immutable double2 ldouble2 = 8.0; assert(memcmp(&ldouble2, &gdouble2, gdouble2.sizeof) == 0); } /*****************************************/ void test7413() { byte16 b = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; assert(b.array[0] == 1); assert(b.array[1] == 2); assert(b.array[2] == 3); assert(b.array[3] == 4); assert(b.array[4] == 5); assert(b.array[5] == 6); assert(b.array[6] == 7); assert(b.array[7] == 8); assert(b.array[8] == 9); assert(b.array[9] == 10); assert(b.array[10] == 11); assert(b.array[11] == 12); assert(b.array[12] == 13); assert(b.array[13] == 14); assert(b.array[14] == 15); assert(b.array[15] == 16); ubyte16 ub = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; assert(ub.array[0] == 1); assert(ub.array[1] == 2); assert(ub.array[2] == 3); assert(ub.array[3] == 4); assert(ub.array[4] == 5); assert(ub.array[5] == 6); assert(ub.array[6] == 7); assert(ub.array[7] == 8); assert(ub.array[8] == 9); assert(ub.array[9] == 10); assert(ub.array[10] == 11); assert(ub.array[11] == 12); assert(ub.array[12] == 13); assert(ub.array[13] == 14); assert(ub.array[14] == 15); assert(ub.array[15] == 16); short8 s = [1,2,3,4,5,6,7,8]; assert(s.array[0] == 1); assert(s.array[1] == 2); assert(s.array[2] == 3); assert(s.array[3] == 4); assert(s.array[4] == 5); assert(s.array[5] == 6); assert(s.array[6] == 7); assert(s.array[7] == 8); ushort8 us = [1,2,3,4,5,6,7,8]; assert(us.array[0] == 1); assert(us.array[1] == 2); assert(us.array[2] == 3); assert(us.array[3] == 4); assert(us.array[4] == 5); assert(us.array[5] == 6); assert(us.array[6] == 7); assert(us.array[7] == 8); int4 i = [1,2,3,4]; assert(i.array[0] == 1); assert(i.array[1] == 2); assert(i.array[2] == 3); assert(i.array[3] == 4); uint4 ui = [1,2,3,4]; assert(ui.array[0] == 1); assert(ui.array[1] == 2); assert(ui.array[2] == 3); assert(ui.array[3] == 4); long2 l = [1,2]; assert(l.array[0] == 1); assert(l.array[1] == 2); ulong2 ul = [1,2]; assert(ul.array[0] == 1); assert(ul.array[1] == 2); float4 f = [1,2,3,4]; assert(f.array[0] == 1); assert(f.array[1] == 2); assert(f.array[2] == 3); assert(f.array[3] == 4); double2 d = [1,2]; assert(d.array[0] == 1); assert(d.array[1] == 2); } /*****************************************/ byte16 b = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; ubyte16 ub = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; short8 s = [1,2,3,4,5,6,7,8]; ushort8 us = [1,2,3,4,5,6,7,8]; int4 i = [1,2,3,4]; uint4 ui = [1,2,3,4]; long2 l = [1,2]; ulong2 ul = [1,2]; float4 f = [1,2,3,4]; double2 d = [1,2]; void test7413_2() { assert(b.array[0] == 1); assert(b.array[1] == 2); assert(b.array[2] == 3); assert(b.array[3] == 4); assert(b.array[4] == 5); assert(b.array[5] == 6); assert(b.array[6] == 7); assert(b.array[7] == 8); assert(b.array[8] == 9); assert(b.array[9] == 10); assert(b.array[10] == 11); assert(b.array[11] == 12); assert(b.array[12] == 13); assert(b.array[13] == 14); assert(b.array[14] == 15); assert(b.array[15] == 16); assert(ub.array[0] == 1); assert(ub.array[1] == 2); assert(ub.array[2] == 3); assert(ub.array[3] == 4); assert(ub.array[4] == 5); assert(ub.array[5] == 6); assert(ub.array[6] == 7); assert(ub.array[7] == 8); assert(ub.array[8] == 9); assert(ub.array[9] == 10); assert(ub.array[10] == 11); assert(ub.array[11] == 12); assert(ub.array[12] == 13); assert(ub.array[13] == 14); assert(ub.array[14] == 15); assert(ub.array[15] == 16); assert(s.array[0] == 1); assert(s.array[1] == 2); assert(s.array[2] == 3); assert(s.array[3] == 4); assert(s.array[4] == 5); assert(s.array[5] == 6); assert(s.array[6] == 7); assert(s.array[7] == 8); assert(us.array[0] == 1); assert(us.array[1] == 2); assert(us.array[2] == 3); assert(us.array[3] == 4); assert(us.array[4] == 5); assert(us.array[5] == 6); assert(us.array[6] == 7); assert(us.array[7] == 8); assert(i.array[0] == 1); assert(i.array[1] == 2); assert(i.array[2] == 3); assert(i.array[3] == 4); assert(ui.array[0] == 1); assert(ui.array[1] == 2); assert(ui.array[2] == 3); assert(ui.array[3] == 4); assert(l.array[0] == 1); assert(l.array[1] == 2); assert(ul.array[0] == 1); assert(ul.array[1] == 2); assert(f.array[0] == 1); assert(f.array[1] == 2); assert(f.array[2] == 3); assert(f.array[3] == 4); assert(d.array[0] == 1); assert(d.array[1] == 2); } /*****************************************/ float bug8060(float x) { int i = *cast(int*)&x; ++i; return *cast(float*)&i; } /*****************************************/ float4 test5(float4 a, float4 b) { a = __simd(XMM.ADDPD, a, b); a = __simd(XMM.ADDSS, a, b); a = __simd(XMM.ADDSD, a, b); a = __simd(XMM.ADDPS, a, b); a = __simd(XMM.PADDB, a, b); a = __simd(XMM.PADDW, a, b); a = __simd(XMM.PADDD, a, b); a = __simd(XMM.PADDQ, a, b); a = __simd(XMM.SUBPD, a, b); a = __simd(XMM.SUBSS, a, b); a = __simd(XMM.SUBSD, a, b); a = __simd(XMM.SUBPS, a, b); a = __simd(XMM.PSUBB, a, b); a = __simd(XMM.PSUBW, a, b); a = __simd(XMM.PSUBD, a, b); a = __simd(XMM.PSUBQ, a, b); a = __simd(XMM.MULPD, a, b); a = __simd(XMM.MULSS, a, b); a = __simd(XMM.MULSD, a, b); a = __simd(XMM.MULPS, a, b); a = __simd(XMM.PMULLW, a, b); a = __simd(XMM.DIVPD, a, b); a = __simd(XMM.DIVSS, a, b); a = __simd(XMM.DIVSD, a, b); a = __simd(XMM.DIVPS, a, b); a = __simd(XMM.PAND, a, b); a = __simd(XMM.POR, a, b); a = __simd(XMM.UCOMISS, a, b); a = __simd(XMM.UCOMISD, a, b); a = __simd(XMM.XORPS, a, b); a = __simd(XMM.XORPD, a, b); a = __simd_sto(XMM.STOSS, a, b); a = __simd_sto(XMM.STOSD, a, b); a = __simd_sto(XMM.STOAPS, a, b); a = __simd_sto(XMM.STOAPD, a, b); a = __simd_sto(XMM.STODQA, a, b); //a = __simd_sto(XMM.STOD, a, b); a = __simd_sto(XMM.STOQ, a, b); a = __simd(XMM.LODSS, a); a = __simd(XMM.LODSD, a); a = __simd(XMM.LODAPS, a); a = __simd(XMM.LODAPD, a); a = __simd(XMM.LODDQA, a); //a = __simd(XMM.LODD, a); a = __simd(XMM.LODQ, a); a = __simd(XMM.LODDQU, a); a = __simd_sto(XMM.STODQU, a, b); //MOVDQ2Q = 0xF20FD6, // MOVDQ2Q mmx, xmm F2 0F D6 /r /+ LODHPD = 0x660F16, // MOVHPD xmm, mem64 66 0F 16 /r STOHPD = 0x660F17, // MOVHPD mem64, xmm 66 0F 17 /r LODHPS = 0x0F16, // MOVHPS xmm, mem64 0F 16 /r STOHPS = 0x0F17, // MOVHPS mem64, xmm 0F 17 /r MOVLHPS = 0x0F16, // MOVLHPS xmm1, xmm2 0F 16 /r LODLPD = 0x660F12, // MOVLPD xmm, mem64 66 0F 12 /r STOLPD = 0x660F13, // MOVLPD mem64, xmm 66 0F 13 /r a = __simd(XMM.LODLPS, a, b); STOLPS = 0x0F13, // MOVLPS mem64, xmm 0F 13 /r MOVMSKPD = 0x660F50, // MOVMSKPD reg32, xmm 66 0F 50 /r MOVMSKPS = 0x0F50, // MOVMSKPS reg32, xmm 0F 50 /r MOVNTDQ = 0x660FE7, // MOVNTDQ mem128, xmm 66 0F E7 /r MOVNTI = 0x0FC3, // MOVNTI m32,r32 0F C3 /r // MOVNTI m64,r64 0F C3 /r MOVNTPD = 0x660F2B, // MOVNTPD mem128, xmm 66 0F 2B /r MOVNTPS = 0x0F2B, // MOVNTPS mem128, xmm 0F 2B /r //MOVNTQ = 0x0FE7, // MOVNTQ m64, mmx 0F E7 /r //MOVQ2DQ = 0xF30FD6, // MOVQ2DQ xmm, mmx F3 0F D6 /r +/ a = __simd(XMM.LODUPD, a, b); a = __simd_sto(XMM.STOUPD, a, b); a = __simd(XMM.LODUPS, a, b); a = __simd_sto(XMM.STOUPS, a, b); a = __simd(XMM.PACKSSDW, a, b); a = __simd(XMM.PACKSSWB, a, b); a = __simd(XMM.PACKUSWB, a, b); a = __simd(XMM.PADDSB, a, b); a = __simd(XMM.PADDSW, a, b); a = __simd(XMM.PADDUSB, a, b); a = __simd(XMM.PADDUSW, a, b); a = __simd(XMM.PANDN, a, b); a = __simd(XMM.PCMPEQB, a, b); a = __simd(XMM.PCMPEQD, a, b); a = __simd(XMM.PCMPEQW, a, b); a = __simd(XMM.PCMPGTB, a, b); a = __simd(XMM.PCMPGTD, a, b); a = __simd(XMM.PCMPGTW, a, b); a = __simd(XMM.PMADDWD, a, b); a = __simd(XMM.PSLLW, a, b); a = __simd_ib(XMM.PSLLW, a, cast(ubyte)0x7A); a = __simd(XMM.PSLLD, a, b); a = __simd_ib(XMM.PSLLD, a, cast(ubyte)0x7A); a = __simd(XMM.PSLLQ, a, b); a = __simd_ib(XMM.PSLLQ, a, cast(ubyte)0x7A); a = __simd(XMM.PSRAW, a, b); a = __simd_ib(XMM.PSRAW, a, cast(ubyte)0x7A); a = __simd(XMM.PSRAD, a, b); a = __simd_ib(XMM.PSRAD, a, cast(ubyte)0x7A); a = __simd(XMM.PSRLW, a, b); a = __simd_ib(XMM.PSRLW, a, cast(ubyte)0x7A); a = __simd(XMM.PSRLD, a, b); a = __simd_ib(XMM.PSRLD, a, cast(ubyte)0x7A); a = __simd(XMM.PSRLQ, a, b); a = __simd_ib(XMM.PSRLQ, a, cast(ubyte)0x7A); a = __simd(XMM.PSUBSB, a, b); a = __simd(XMM.PSUBSW, a, b); a = __simd(XMM.PSUBUSB, a, b); a = __simd(XMM.PSUBUSW, a, b); a = __simd(XMM.PUNPCKHBW, a, b); a = __simd(XMM.PUNPCKHDQ, a, b); a = __simd(XMM.PUNPCKHWD, a, b); a = __simd(XMM.PUNPCKLBW, a, b); a = __simd(XMM.PUNPCKLDQ, a, b); a = __simd(XMM.PUNPCKLWD, a, b); a = __simd(XMM.PXOR, a, b); a = __simd(XMM.ANDPD, a, b); a = __simd(XMM.ANDPS, a, b); a = __simd(XMM.ANDNPD, a, b); a = __simd(XMM.ANDNPS, a, b); a = __simd(XMM.CMPPD, a, b, 0x7A); a = __simd(XMM.CMPSS, a, b, 0x7A); a = __simd(XMM.CMPSD, a, b, 0x7A); a = __simd(XMM.CMPPS, a, b, 0x7A); a = __simd(XMM.CVTDQ2PD, a, b); a = __simd(XMM.CVTDQ2PS, a, b); a = __simd(XMM.CVTPD2DQ, a, b); //a = __simd(XMM.CVTPD2PI, a, b); a = __simd(XMM.CVTPD2PS, a, b); a = __simd(XMM.CVTPI2PD, a, b); a = __simd(XMM.CVTPI2PS, a, b); a = __simd(XMM.CVTPS2DQ, a, b); a = __simd(XMM.CVTPS2PD, a, b); //a = __simd(XMM.CVTPS2PI, a, b); //a = __simd(XMM.CVTSD2SI, a, b); //a = __simd(XMM.CVTSD2SI, a, b); a = __simd(XMM.CVTSD2SS, a, b); //a = __simd(XMM.CVTSI2SD, a, b); //a = __simd(XMM.CVTSI2SD, a, b); //a = __simd(XMM.CVTSI2SS, a, b); //a = __simd(XMM.CVTSI2SS, a, b); a = __simd(XMM.CVTSS2SD, a, b); //a = __simd(XMM.CVTSS2SI, a, b); //a = __simd(XMM.CVTSS2SI, a, b); //a = __simd(XMM.CVTTPD2PI, a, b); a = __simd(XMM.CVTTPD2DQ, a, b); a = __simd(XMM.CVTTPS2DQ, a, b); //a = __simd(XMM.CVTTPS2PI, a, b); //a = __simd(XMM.CVTTSD2SI, a, b); //a = __simd(XMM.CVTTSD2SI, a, b); //a = __simd(XMM.CVTTSS2SI, a, b); //a = __simd(XMM.CVTTSS2SI, a, b); a = __simd(XMM.MASKMOVDQU, a, b); //a = __simd(XMM.MASKMOVQ, a, b); a = __simd(XMM.MAXPD, a, b); a = __simd(XMM.MAXPS, a, b); a = __simd(XMM.MAXSD, a, b); a = __simd(XMM.MAXSS, a, b); a = __simd(XMM.MINPD, a, b); a = __simd(XMM.MINPS, a, b); a = __simd(XMM.MINSD, a, b); a = __simd(XMM.MINSS, a, b); a = __simd(XMM.ORPD, a, b); a = __simd(XMM.ORPS, a, b); a = __simd(XMM.PAVGB, a, b); a = __simd(XMM.PAVGW, a, b); a = __simd(XMM.PMAXSW, a, b); //a = __simd(XMM.PINSRW, a, b); a = __simd(XMM.PMAXUB, a, b); a = __simd(XMM.PMINSB, a, b); a = __simd(XMM.PMINUB, a, b); //a = __simd(XMM.PMOVMSKB, a, b); a = __simd(XMM.PMULHUW, a, b); a = __simd(XMM.PMULHW, a, b); a = __simd(XMM.PMULUDQ, a, b); a = __simd(XMM.PSADBW, a, b); a = __simd(XMM.PUNPCKHQDQ, a, b); a = __simd(XMM.PUNPCKLQDQ, a, b); a = __simd(XMM.RCPPS, a, b); a = __simd(XMM.RCPSS, a, b); a = __simd(XMM.RSQRTPS, a, b); a = __simd(XMM.RSQRTSS, a, b); a = __simd(XMM.SQRTPD, a, b); a = __simd(XMM.SHUFPD, a, b, 0xA7); a = __simd(XMM.SHUFPS, a, b, 0x7A); a = __simd(XMM.SQRTPS, a, b); a = __simd(XMM.SQRTSD, a, b); a = __simd(XMM.SQRTSS, a, b); a = __simd(XMM.UNPCKHPD, a, b); a = __simd(XMM.UNPCKHPS, a, b); a = __simd(XMM.UNPCKLPD, a, b); a = __simd(XMM.UNPCKLPS, a, b); a = __simd(XMM.PSHUFD, a, b, 0x7A); a = __simd(XMM.PSHUFHW, a, b, 0x7A); a = __simd(XMM.PSHUFLW, a, b, 0x7A); //a = __simd(XMM.PSHUFW, a, b, 0x7A); a = __simd_ib(XMM.PSLLDQ, a, cast(ubyte)0x7A); a = __simd_ib(XMM.PSRLDQ, a, cast(ubyte)0x7A); /**/ a = __simd(XMM.BLENDPD, a, b, 0x7A); a = __simd(XMM.BLENDPS, a, b, 0x7A); a = __simd(XMM.DPPD, a, b, 0x7A); a = __simd(XMM.DPPS, a, b, 0x7A); a = __simd(XMM.MPSADBW, a, b, 0x7A); a = __simd(XMM.PBLENDW, a, b, 0x7A); a = __simd(XMM.ROUNDPD, a, b, 0x7A); a = __simd(XMM.ROUNDPS, a, b, 0x7A); a = __simd(XMM.ROUNDSD, a, b, 0x7A); a = __simd(XMM.ROUNDSS, a, b, 0x7A); return a; } /*****************************************/ /+ // 9200 void bar9200(double[2] a) { assert(a[0] == 1); assert(a[1] == 2); } double2 * v9200(double2* a) { return a; } void test9200() { double2 a = [1, 2]; *v9200(&a) = a; bar9200(a.array); } +/ /*****************************************/ // 9304 and 9322 float4 foo9304(float4 a) { return -a; } void test9304() { auto a = foo9304([0, 1, 2, 3]); //writeln(a.array); assert(a.array == [0,-1,-2,-3]); } /*****************************************/ void test9910() { float4 f = [1, 1, 1, 1]; auto works = f + 3; auto bug = 3 + f; assert (works.array == [4,4,4,4]); assert (bug.array == [4,4,4,4]); // no property 'array' for type 'int' } /*****************************************/ bool normalize(double[] range, double sum = 1) { double s = 0; const length = range.length; foreach (e; range) { s += e; } if (s == 0) { return false; } return true; } void test12852() { double[3] range = [0.0, 0.0, 0.0]; assert(normalize(range[]) == false); range[1] = 3.0; assert(normalize(range[]) == true); } /*****************************************/ void test9449() { ubyte16 table[1]; } /*****************************************/ void test9449_2() { float[4][2] m = [[2.0, 1, 3, 4], [5.0, 6, 7, 8]]; // segfault assert(m[0][0] == 2.0); assert(m[0][1] == 1); assert(m[0][2] == 3); assert(m[0][3] == 4); assert(m[1][0] == 5.0); assert(m[1][1] == 6); assert(m[1][2] == 7); assert(m[1][3] == 8); } /*****************************************/ // 13841 void test13841() { alias Vector16s = TypeTuple!( void16, byte16, short8, int4, long2, ubyte16, ushort8, uint4, ulong2, float4, double2); foreach (V1; Vector16s) { foreach (V2; Vector16s) { V1 v1 = void; V2 v2 = void; static if (is(V1 == V2)) { static assert( is(typeof(true ? v1 : v2) == V1)); } else { static assert(!is(typeof(true ? v1 : v2))); } } } } /*****************************************/ // 12776 void test12776() { alias Vector16s = TypeTuple!( void16, byte16, short8, int4, long2, ubyte16, ushort8, uint4, ulong2, float4, double2); foreach (V; Vector16s) { static assert(is(typeof( V .init) == V )); static assert(is(typeof( const(V).init) == const(V))); static assert(is(typeof( inout( V).init) == inout( V))); static assert(is(typeof( inout(const V).init) == inout(const V))); static assert(is(typeof(shared( V).init) == shared( V))); static assert(is(typeof(shared( const V).init) == shared( const V))); static assert(is(typeof(shared(inout V).init) == shared(inout V))); static assert(is(typeof(shared(inout const V).init) == shared(inout const V))); static assert(is(typeof( immutable(V).init) == immutable(V))); } } /*****************************************/ void foo13988(double[] arr) { static ulong repr(double d) { return *cast(ulong*)&d; } foreach (x; arr) assert(repr(arr[0]) == *cast(ulong*)&(arr[0])); } void test13988() { double[] arr = [3.0]; foo13988(arr); } /*****************************************/ // 15123 void test15123() { alias Vector16s = TypeTuple!( void16, byte16, short8, int4, long2, ubyte16, ushort8, uint4, ulong2, float4, double2); foreach (V; Vector16s) { auto x = V.init; } } /*****************************************/ int main() { test1(); test2(); test2b(); test2c(); test2d(); test2e(); test2f(); test2g(); test2h(); test2i(); test2j(); test3(); test4(); test7411(); test7951(); test7951_2(); test7949(); test7414(); test7413(); test7413_2(); // test9200(); test9304(); test9910(); test12852(); test9449(); test9449_2(); test13988(); return 0; } } else { int main() { return 0; } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/gdb4181.d0000664000175000017500000000035312776215022021424 0ustar kaikai/* REQUIRED_ARGS: -g PERMUTE_ARGS: GDB_SCRIPT: --- b 22 r echo RESULT= p 'gdb.x' + 'gdb.STest.y' --- GDB_MATCH: RESULT=.*33 */ module gdb; int x; struct STest { static int y; } void main() { x = 11; STest.y = 22; // BP } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/interface2.d0000664000175000017500000004430512776215022022401 0ustar kaikai// PERMUTE_ARGS: extern(C) int printf(const char*, ...); /*******************************************************/ interface Foo { int bar(); } void* p1; class Bar : Foo { int bar() { printf("Bar.bar(this = %p)\n", this); p1 = cast(void*)this; return 0; } } void test1() { Bar b = new Bar(); Foo f = b; printf("b = %p\n", b); printf("f = %p\n", f); assert(cast(void*)b !is cast(void*)f); printf("f.class = '%.*s'\n", f.classinfo.name.length, f.classinfo.name.ptr); assert(f.classinfo.name == "interface2.Foo"); f.bar(); assert(p1 is cast(void*)b); Bar b2 = cast(Bar)f; printf("cast(Bar)f = %p\n", b2); assert(b is b2); delete f; } /*******************************************************/ interface A {} interface B:A {} interface C {} class D:B,C {} void test2() { D x = new D(); printf("D: %p\n",x); Object o = x; printf("o: %p\n",o); B b = cast(B)o; printf("B: %p\n",b); C c = cast(C)o; // boom printf("C: %p\n",c); } /*******************************************************/ interface B3 { void close(); } interface C3 : B3 { } class A3 : B3 { void close() { } } class D3 : A3 { } class E3 : D3, C3 { } void test3() { C3 c = new E3(); delete c; } /*******************************************************/ interface K { } interface X { } interface Y : X { } class Z : Y { } void test4() { Z z = new Z(); if (cast(K) z) { printf("not ok\n"); assert(0); } } /*******************************************************/ interface I5 { char M (); } interface J5 : I5 { char N (); } class A5 : I5 { char M () { printf("M()\n"); return 'M'; } } class B5 : A5, J5 { char N () { printf("N()\n"); return 'N'; } } void test5() { I5 f = new B5 (); char c = f.M(); assert(c == 'M'); } /*******************************************************/ interface A6 { void ma (); } interface B6 { void mb (); } class C6 : A6, B6 { void ma () { } void mb () { } } void test6() { A6 x = new C6 (); assert (cast (B6) x); } /*******************************************************/ interface D7 { int foo(); } class A7 : D7 { int foo() { return 1; } } class B7 : A7 { override int foo() { return 2; } D7 me() { return this; } } void test7() { A7 a = new A7; B7 b = new B7; assert(b.me().foo() != a.foo()); } /*******************************************************/ interface D8 { void foo(); } class A8 : D8 { void foo() { printf("A8.foo()\n"); } } class B8 : A8 {} void test8() { B8 b = new B8(); D8 d = cast(D8) b; d.foo(); } /*******************************************************/ interface IA9 { int i1(); } interface IB9 { int i2(); } interface IC9 : IA9, IB9 { } class C9 : IC9 { int i1() { printf("i1\n"); return 1; } int i2() { printf("i2\n"); return 2; } } void f9(IA9 i1, IB9 i2) { int i; printf("f9\n"); i = i1.i1(); assert(i == 1); i = i2.i2(); assert(i == 2); } void test9() { IC9 i3 = new C9(); C9 c = new C9(); f9(c, c); //printf("c = %p, IC9 = %p, IA9 = %p, IB9 = %p\n", c, i3, cast(IA9)i3, cast(IB9)i3); f9(i3, i3); } /*******************************************************/ interface IOne { int one (); } interface ITwo { int two (); } interface IThree : IOne, ITwo { int three (); } class Three : IThree { int one () { printf ("one\n"); return 1; } int two () { printf ("two\n"); return 2; } int three () { printf ("three\n"); return 3; } } void test10() { int i; IThree three = new Three; i = three.one(); assert(i == 1); i = three.two(); assert(i == 2); i = three.three(); assert(i == 3); ITwo two = cast(ITwo) three; i = two.two(); assert(i == 2); } /*******************************************************/ interface A11{ } interface B11 : A11{ } class MyClass : B11{ } void test11() { B11 b = new MyClass(); Object o = cast(Object)b; printf("o = %p\n", o); } /*******************************************************/ interface I12 { int foo(); } class IA12 : I12 { int foo() { return 1; } } class A12 { I12 i; I12 clone() { return i; } } class B12 : A12 { IA12 ia; override IA12 clone() // covariant return value out (result) { printf("B12.clone()\n"); } body { return ia; } } void test12() { IA12 ia = new IA12; assert(ia.foo() == 1); I12 i = ia; assert(i.foo() == 1); A12 a = new A12; a.i = i; assert(a.clone().foo() == 1); B12 b = new B12; b.ia = ia; assert(b.clone().foo() == 1); a = b; assert(a.clone().foo() == 1); } /*******************************************************/ class I13 { int foo() { return 0; } } class IA13 : I13 { override int foo() { return 1; } } class A13 { I13 i; I13 clone() { return i; } } class B13 : A13 { IA13 ia; override IA13 clone() out (result) { printf("B13.clone()\n"); } body { return ia; } } void test13() { IA13 ia = new IA13; assert(ia.foo() == 1); I13 i = ia; assert(i.foo() == 1); A13 a = new A13; a.i = i; assert(a.clone().foo() == 1); B13 b = new B13; b.ia = ia; assert(b.clone().foo() == 1); a = b; assert(a.clone().foo() == 1); bar(&b.clone); } void bar(IA13 delegate() dg) { } /*******************************************************/ interface I14 { I14 clone(); } interface BabyI14: I14 { } class A14: BabyI14 { int x; BabyI14 clone() { A14 a = new A14; a.x = x; return a; } } I14 foo14(I14 i) { return i.clone(); } void test14() { A14 a = new A14; a.x = 3; a = cast(A14)a.clone(); assert(a.x == 3); A14 b = cast(A14)foo14(a); a.x = 4; assert(b.x == 3); } /*******************************************************/ interface I15 { Object clone(); } class A15 : I15 { int x; A15 clone() { return this; } } void test15() { A15 a = new A15; a.x = 3; A15 a1 = a.clone(); assert(a1.x == 3); I15 i = a1; Object o = i.clone(); A15 a2 = cast(A15) o; assert(a2.x == 3); } /*******************************************************/ interface I16 {} class A16 { I16 foo() { printf("Called A.foo\n"); return new B16(42); } } class B16 : A16, I16 { int data; this(int d) { data = d; } override B16 foo() { printf("Called B.foo\n"); return new B16(69); } } void test16() { B16 b = new B16(105); b.foo(); A16 a = b; a.foo(); printf("foo\n"); B16 b2 = cast(B16) a.foo(); } /*******************************************************/ interface Father { int showData(); } class Mother { Father test() { printf("Called Mother.test\n"); return new Child(42); } } class Child : Mother, Father { int data; this(int d) { data = d; } override Child test() { printf("Called Child.test\n"); return new Child(69); } int showData() { printf("%d\n", data); return data; } } void test17() { Child aChild = new Child(105); Mother childsMum = aChild; aChild.test(); Father mumTest = childsMum.test(); int i; i = aChild.showData(); assert(i == 105); i = mumTest.showData(); assert(i == 69); } /*******************************************************/ int status18; interface I18 { int showData(); } class Parent18 { I18 test() { status18 += 7; return new Child18(42); } } class Child18 : Parent18, I18 { int data; this(int d) { data = d; } override Child18 test() { status18 += 1; return new Child18(69); } override int showData(){ return data; } } void test18() { Child18 a = new Child18(105); assert(a); assert(status18 == 0); assert(a.data == 105); Parent18 p = a; assert(a); assert(status18 == 0); a.test(); assert(status18 == 1); I18 i = p.test(); assert(i); assert(status18 == 2); assert(a.data == 105); assert(a.showData() == 105); assert(i.showData() == 69); } /*******************************************************/ interface IFoo19 { } interface ICov19 { IFoo19 covfunc(); } class Child19 : ICov19, IFoo19 { Child19 covfunc() { printf("in Child19.covfunc()\n"); return this; } } void test19() { Child19 c = new Child19(); ICov19 icov = c; IFoo19 ifoo = icov.covfunc(); printf("c = %p\n", c); printf("icov = %p\n", icov); printf("ifoo = %p\n", ifoo); assert(cast(void*)c + (2*(void*).sizeof) == cast(void*)icov); assert(cast(void*)c + (3*(void*).sizeof) == cast(void*)ifoo); string s = ifoo.classinfo.name; printf("%.*s\n", s.length, s.ptr); assert(s == "interface2.IFoo19"); s = (cast(Object)ifoo).toString; printf("%.*s\n", s.length, s.ptr); assert(s == "interface2.Child19"); } /*******************************************************/ interface Iface1 { Iface2 func1(); } interface Iface2 { Iface1 func2(); } class C1_20 : Iface1 { C2_20 func1(){ return null; } } class C2_20 : Iface2 { C1_20 func2(){ return null; } } void test20() { C1_20 c1 = new C1_20(); printf("c1.func1() == %p\n", c1.func1()); assert(c1.func1() is null); printf("test1\n"); C2_20 c2 = new C2_20(); printf("c2.func2() == %p\n", c2.func2()); assert(c2.func2() is null); } /*******************************************************/ interface I21 { int test(int); } class C21 : I21 { int test(int i){ return i+1; } } void test21() { C21[I21] aa; C21 o = new C21(); aa[o] = o; I21 i = aa[o]; assert(i.test(3) == 4); } /*******************************************************/ interface IFoo22 { int foo(); } class Foo22: IFoo22 { final int foo() { return 7; } } void test22() { Foo22 f = new Foo22; assert(f.foo() == 7); IFoo22 i = f; assert(i.foo() == 7); } /*******************************************************/ interface IFoo23 { int foo(); } class Foo23: IFoo23 { final int foo() { return 7; } } class Baz23 : Foo23 { } void test23() { Baz23 f = new Baz23; assert(f.foo() == 7); IFoo23 i = f; assert(i.foo() == 7); } /*******************************************************/ interface I24B() : I24A { } interface I24A { I24B!() func (); } class Foo24 : I24B!() { I24B!() func() { return null; } } void test24() { auto foo = new Foo24(); foo.func(); printf("foo.func() call passed\n"); I24A ifA = foo; assert(ifA !is null); ifA.func(); } /*******************************************************/ interface IA25 { char a(); } interface IB25 { char b(); } interface IC25 : IA25, IB25 { char c(); } interface ID25 { char d(); } interface IE25 : IC25, ID25 { char e(); } class Foo25 : IE25 { char a() { return('a'); } char b() { return('b'); } char c() { return('c'); } char d() { return('d'); } char e() { return('e'); } } void test25() { auto foo = new Foo25; printf("Foo: %c %c %c %c %c\n", foo.a, foo.b, foo.c, foo.d, foo.e); IA25 a = foo; printf("A: %c\n", a.a); assert(a.a == 'a'); IB25 b = foo; printf("B: %c\n", b.b); assert(b.b == 'b'); IC25 c = foo; printf("C: %c %c %c\n", c.a, c.b, c.c); assert(c.a == 'a'); assert(c.b == 'b'); assert(c.c == 'c'); ID25 d = foo; printf("D: %c\n", d.d); assert(d.d == 'd'); IE25 e = foo; printf("E: %c %c %c %c %c\n", e.a, e.b, e.c, e.d, e.e); assert(e.a == 'a'); assert(e.b == 'b'); assert(e.c == 'c'); assert(e.d == 'd'); assert(e.e == 'e'); b = e; printf("IB25: %c\n", b.b); assert(b.b == 'b'); } /*******************************************************/ interface VisualElement { void draw(); } interface Actor { } interface VisualActor : Actor, VisualElement { } class Sprite3 : Actor, VisualActor { override void draw() { } } void test26() { } /*******************************************************/ interface I27 { static int foo() { return 3; } final int bar() { return 7 + abc(); } int abc(); } class C27 : I27 { int x; int abc() { return x * 10; } } void test27() { C27 c = new C27(); c.x = 8; I27 i = c; assert(i.foo() == 3); assert(I27.foo() == 3); assert(i.bar() == 87); } /*******************************************************/ // 1747 & 2013 void test1747() { interface IA { int mA(); } interface IB : IA { int mB(); } interface IC : IB { } interface ID : IA, IC { int mD(); } // offset: 0 +n +n + ptrsize // (IA) // IB // IA, IC static class C : ID { int mA() { return 1; } int mB() { return 2; } int mD() { return 3; } } C c = new C; void* pc = *cast(void**)&c; ID id = c; void* pid = *cast(void**)&id; IC ic = c; void* pic = *cast(void**)⁣ IB ib = c; void* pib = *cast(void**)&ib; IA ia = c; void* pia = *cast(void**)&ia; //printf(" c = %p\n", pc); //printf("id = %p\n", pid); //printf("ic = %p\n", pic); //printf("ib = %p\n", pib); //printf("ia = %p\n", pia); size_t n = pid - pc; assert(pic == pc + n + (void*).sizeof); assert(pib == pc + n + (void*).sizeof); // OK <- NG assert(pia == pc + n); assert(id.mA() == 1); assert(id.mB() == 2); // OK <- NG (bugzilla 2013 case) assert(id.mD() == 3); assert(ic.mA() == 1); assert(ic.mB() == 2); // OK <- NG (bugzilla 2013 case) assert(ib.mA() == 1); assert(ib.mB() == 2); // OK <- NG assert(ia.mA() == 1); } /*******************************************************/ private interface IFoo { void foo(); } void test2553() { IFoo foo; if (0) foo.foo; } /*******************************************************/ interface I2524 { void foo(); } class C2524 : I2524 { final override void foo() { } } /*******************************************************/ interface Test4088 {} bool foo4088(Test4088 x, Test4088 y) { return x == y; } /*******************************************************/ // 7950 template TypeTuple7950(T...){alias T TypeTuple7950;} interface I7950a {} // ok interface I7950b : I7950a, TypeTuple7950!() {} // fail /*******************************************************/ // 10007 struct A10007 {} interface IFoo10007 { void bar(ref const A10007); } class Foo10007 : IFoo10007 { void bar(ref const A10007 a) {} void bar( const A10007 a) { return this.bar(a); } } /*******************************************************/ // 10744 interface A10744 { int x(); Foo10744 foo(); } class B10744 : A10744 { int x() { return 0; } Bar10744 foo() { return null; } } class Foo10744 { } class Bar10744 : Foo10744 { } interface C10744 { int x(); Baz10744 foo(); } class D10744 : C10744 { int x() { return 0; } Qux10744 foo() { return null; } } interface Baz10744 { } interface Qux10744 : Baz10744 { } /*******************************************************/ // 11034 class A11034(T) { A11034!int view() { return null; } } class B11034(T) : A11034!int { override: C11034!int view() { return null; } } class C11034(T) : B11034!int {} void test11034() { auto b = new B11034!int; // Check that B!int.view() overrides A!int.view() auto tiobj = typeid(Object); assert(typeid(A11034!int).vtbl.length == tiobj.vtbl.length + 1); assert(typeid(B11034!int).vtbl.length == tiobj.vtbl.length + 1); } /*******************************************************/ void testTypeid() { interface I { } interface J : I { } class C : J { } class D : C { } D d = new D(); Object o = d; I i = d; assert(typeid(typeof(o)) is typeid(Object)); assert(typeid(o) is typeid(D)); assert(o.classinfo is typeid(D)); assert(typeid(typeof(i)) is typeid(I)); assert(typeid(i) !is typeid(J)); assert(i.classinfo !is typeid(J)); } /*******************************************************/ extern (C++) { interface IA47 { char a(); } interface IB47 { char b(); } interface IC47 : IA47, IB47 { char c(); } interface ID47 { char d(); } interface IE47 : IC47, ID47 { char e(); } class Foo47 : IE47 { int x = 9; char a() { printf("a.this = %p\n", this); return('a'); } char b() { printf("b.this = %p\n", this); return('b'); } char c() { printf("c.this = %p\n", this); return('c'); } char d() { printf("d.this = %p\n", this); return('d'); } char e() { printf("e.this = %p\n", this); return('e'); } } } void test15647() { auto foo = new Foo47; printf("Foo: %p %c %c %c %c %c\n", foo, foo.a, foo.b, foo.c, foo.d, foo.e); IA47 a = foo; printf("A: %c\n", a.a); assert(a.a == 'a'); IB47 b = foo; printf("B: %c\n", b.b); assert(b.b == 'b'); IC47 c = foo; printf("C: %p %c %c %c\n", c, c.a, c.b, c.c); assert(c.a == 'a'); assert(c.b == 'b'); assert(c.c == 'c'); ID47 d = foo; printf("D: %c\n", d.d); assert(d.d == 'd'); IE47 e = foo; printf("E: %c %c %c %c %c\n", e.a, e.b, e.c, e.d, e.e); assert(e.a == 'a'); assert(e.b == 'b'); assert(e.c == 'c'); assert(e.d == 'd'); assert(e.e == 'e'); b = e; printf("IB47: %c\n", b.b); assert(b.b == 'b'); } /*******************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test1747(); test2553(); test11034(); testTypeid(); test15647(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_1335.d0000664000175000017500000000135312776215022023132 0ustar kaikai// Tests that out contracts don't interfere with functions returning via sret, // such as calling the postblit ctor when returning the special __result // variable. __gshared int numDtor = 0; // disabled postblit ctor => only returnable via sret struct Bar { int v; this(this) @disable; ~this() { ++numDtor; } } Bar rvalue() out { assert(__result.v == 1); } body { return Bar(1); } Bar nrvo() out { assert(__result.v == 2); } body { Bar b = Bar(2); return b; } void main() { { auto a = rvalue(); assert(a.v == 1); assert(numDtor == 0); } assert(numDtor == 1); { auto b = nrvo(); assert(b.v == 2); assert(numDtor == 1); } assert(numDtor == 2); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test9271.d0000664000175000017500000000040212776215022021647 0ustar kaikai// PERMUTE_ARGS: import algorithm = imports.test9271a; bool any(alias predicate, Range)(Range range) { return algorithm.any!(predicate)(range); } void main() { auto arr = ["foo"]; any!(e => e == "asd")(arr); // infinite recursive call -> OK } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/gdb14276.d0000664000175000017500000000043212776215022021510 0ustar kaikai/* REQUIRED_ARGS: -g PERMUTE_ARGS: GDB_SCRIPT: --- b 21 r echo RESULT= p v[0] + v[1] + v[2] + v[3] --- GDB_MATCH: RESULT=.*1234 */ import core.simd; void main() { version (X86_64) int4 v = [1000, 200, 30, 4]; else int[4] v = [1000, 200, 30, 4]; // BP } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test21.d0000664000175000017500000000016312776215022021473 0ustar kaikai// EXTRA_SOURCES: imports/test21a.d import imports.test21a; int main() { TA!(int) variable; return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_1406.d0000664000175000017500000000261412776215022023132 0ustar kaikai// Tests string switch sorting, as per LDC GitHub #1406. void fun(string command){ switch(command) { case "foo_0": break; case "foo_1": break; case "foo_2": break; case "foo_3": break; case "foo_4": break; case "foo_5": break; case "foo_6": break; case "foo_7": break; case "foo_8": break; case "foo_9": break; case "foo_10": break; case "foo_11": break; case "foo_12": break; case "foo_13": break; case "foo_14": break; case "foo_15": break; case "foo_16": break; case "foo_17": break; case "foo_18": break; case "foo_19": break; case "foo_20": break; case "foo_21": break; case "foo_22": break; case "foo_23": break; case "foo_24": break; case "foo_25": break; case "foo_26": break; case "foo_27": break; case "foo_28": break; case "foo_29": break; case "foo_30": break; case "foo_31": break; case "foo_32": break; case "foo_33": break; case "foo_34": break; case "foo_35": break; case "foo_36": break; case "foo_37": break; case "foo_38": break; case "foo_39": break; default: assert(0, command); } } void main() { foreach (a; ["foo_19", "foo_20"]) { fun(a); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/helloUTF16BE.d0000664000175000017500000000036612776215022022416 0ustar kaikaiextern(C) int printf(const char *, ...); int main(char[][] args) { printf("hello world\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test8.d0000664000175000017500000003330112776215022021420 0ustar kaikai module testxxx8; import core.vararg; extern(C) { int atoi(const char*); int printf(const char*, ...); size_t strlen(const char*); version(Windows) { int _snprintf(char*, size_t, const char*, ...); alias _snprintf snprintf; } else int snprintf(char*, size_t, const char*, ...); } /***********************************/ struct Foo1 { static int x = 3; int y = 4; } void test1() { Foo1 f; assert(Foo1.x == 3); assert(f.x == 3); assert(f.y == 4); } /***********************************/ class Foo2 { static int x = 5; int y = 6; } void test2() { Foo2 f = new Foo2(); assert(Foo2.x == 5); assert(f.x == 5); assert(f.y == 6); } /***********************************/ struct Foo3 { static int bar() { return 3; } int y = 4; } void test3() { Foo3 f; assert(Foo3.bar() == 3); assert(f.bar() == 3); } /***********************************/ class Foo4 { static int bar() { return 3; } int y = 4; } void test4() { Foo4 f = new Foo4(); assert(Foo4.bar() == 3); assert(f.bar() == 3); } /***********************************/ struct Foo5 { int bar() { return y + 3; } int y = 4; } void test5() { Foo5 f; assert(f.bar() == 7); } /***********************************/ class Foo6 { int bar() { return y + 3; } final int abc() { return y + 8; } int y = 4; } class FooX6 : Foo6 { override int bar() { return y + 5; } } void test6() { Foo6 f = new FooX6(); assert(f.bar() == 9); assert(f.abc() == 12); } /***********************************/ void bar7(char[3] cad) { assert(cad.length == 3); printf("cad[0] = %d\n", cad[0]); assert(cad[0] == 0xFF); assert(cad[1] == 1); assert(cad[2] == 0xFF); } void test7() { char[3] foo; foo[1] = 1; bar7(foo); } /***********************************/ class gap8 { this(char[3] cad) { assert(cad[0] == 0xFF); assert(cad[1] == 1); assert(cad[2] == 0xFF); } } void test8() { char[3] foo; gap8 g; foo[1] = 1; g = new gap8(foo); } /***********************************/ void test9() { ireal imag = 2.5i; //printf ("test of imag*imag = %Lf\n",imag*imag); real f = imag * imag; assert(f == -6.25); } /***********************************/ void test10() { creal z = 1 + 2.5i; real e = z.im; printf ("e = %Lf\n", e); assert(e == 2.5); } /***********************************/ class Foo11 { public: int a = 47; protected: int b; private: int c; int bar() { return a + b + c; } } class Bar11 : Foo11 { int abc() { return a + b; } } void test11() { Foo11 f = new Foo11(); int i = f.a; assert(i == 47); } /***********************************/ class A12 { protected void foo() { } } class B12: A12 { override void foo() { super.foo(); } } void test12() { } /***********************************/ alias void *HWND; const HWND hWnd = cast(HWND)(null); void test13() { } /***********************************/ string bar14() { return "f"; } char foo14() { return bar14()[0]; } void test14() { char f = foo14(); assert(f == 'f'); } /***********************************/ void test15() { char[30] a; char[30] b; assert(a !is b); } /***********************************/ void test16() { static int function() fp = &func16; int i = fp(); assert(i == 648); } int func16() { return 648; } /***********************************/ string returnSameString(string inputstr) { return inputstr; } string passString() { return returnSameString("First string" ~ "Concatenated with second"); } string butThisWorks() { string s = "Third string"; s = s ~ "Concatenated with fourth"; return returnSameString(s); } void test17() { string s; s = passString(); printf("passString() = %.*s\n", s.length, s.ptr); assert(s == "First stringConcatenated with second"); s = butThisWorks(); printf("butThisWorks() = %.*s\n", s.length, s.ptr); assert(s == "Third stringConcatenated with fourth"); } /***********************************/ void test18() { string[] str; str.length = 2; version (none) { str[1] = "cba"; str[0] = "zyx"; } else { str[1] = (cast(string)"cba").idup; str[0] = (cast(string)"zyx").idup; } // This sorts the strs str.sort; // This will crash the compiler str[0] = str[0].dup.sort.idup; // This will give sintax error //str[0].sort(); printf("%.*s", str[0].length, str[0].ptr); printf("%.*s", str[1].length, str[1].ptr); printf("\n"); string s = str[0] ~ str[1]; assert(s == "abczyx"); } /***********************************/ void test19() { string array = "foobar"; array = array.idup; array = array.dup.sort.idup; assert(array == "abfoor"); } /***********************************/ class A20 { private: static int a; public: int foo(B20 j) { return j.b; } } class B20 { private: static int b; public: int bar(A20 j) { return j.a; } } void test20() { } /***********************************/ alias int* IP; void test21() { int i = 5; IP ip = cast(IP) &i; assert(*ip == 5); } /***********************************/ struct RECT { int left = 1; int top = 2; int right = 3; int bottom = 4; } struct Rect { RECT theRect; } void Test(Rect pos) { //printf("left = %d\n", pos.theRect.left); assert(pos.theRect.left == 1); assert(pos.theRect.top == 2); assert(pos.theRect.right == 3); assert(pos.theRect.bottom == 4); } class Window { Rect position; void createWindow() { Test(position); } } void test22() { Window w = new Window(); w.createWindow(); } /***********************************/ struct Size { int width; int height; } Size computeSize() { Size foo; foo.width = 12; foo.height = 34; printf("Inside: %d,%d\n",foo.width,foo.height); return foo; } void test24() { Size bar; bar = computeSize(); printf("Outside: %d,%d\n",bar.width,bar.height); assert(bar.width == 12); assert(bar.height == 34); } /***********************************/ void test25() { int i = 5; while (i) { break; } } /***********************************/ int test26() in { } out (result) { } body { int i = 5; while (i) { break; } return i; } /***********************************/ class A27 { int a; this() { a = 1; } } class B27 : A27 { } class C27 : B27 { this() { super(); } this(int i) { } } void test27() { A27 a = new A27(); assert(a.a == 1); B27 b = new B27(); assert(b.a == 1); C27 c = new C27(); assert(c.a == 1); C27 c2 = new C27(2); assert(c2.a == 1); } /***********************************/ const char[1] sep = '/'; string testx28(string s, string t) { return cast(string)(s ~ sep ~ t); } void test28() { string r; r = testx28("ab", "cd"); assert(r == "ab/cd"); } /***********************************/ void test29() { } /***********************************/ bool func30(int x, int y) { bool b; b|=(x==y); return b; } void test30() { bool b; b = func30(1,1); assert(b == true); b = func30(1,2); assert(b == false); } /***********************************/ int a31; void test31() { testxxx8.a31 = 3; assert(a31 == 3); } /***********************************/ void test32() { string[] foo; int i; foo = new string[45]; for (i = 0; i < 45; i++) foo[i] = "hello"; for (i = 0; i < 45; i++) assert(foo[i] == "hello"); } /***********************************/ void test33() { string[] foo; int i = 45; foo = new string[i]; for (i = 0; i < 45; i++) foo[i] = "hello"; for (i = 0; i < 45; i++) assert(foo[i] == "hello"); } /***********************************/ void test34() { int[3][4] a; int[5][6] b = 16; int i, j; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) assert(a[i][j] == 0); for (i = 0; i < 6; i++) for (j = 0; j < 5; j++) assert(b[i][j] == 16); } /***********************************/ void test35() { ifloat b = cast(ifloat)1i; assert(b == 1.0i); ifloat c = 2fi; assert(c == 2.0i); c = 0fi; assert(c == 0i); } /***********************************/ string itoa(int i) { char[32] buffer; snprintf(buffer.ptr, 32, "%d", i); return buffer[0 .. strlen(buffer.ptr)].idup; } string testa36(int i, int j, string a, string b, string c) { string s = "string 0;" ~ itoa(i) ~ "string 1;" ~ itoa(j) ~ "string 2;" ~ itoa(i) ~ "string 3;"; // string s = a ~ b ~ c; return s; } void test36() { string s = testa36(26, 47, "a", "b", "c"); printf("s = '%.*s'\n", s.length, s.ptr); assert(s == "string 0;26string 1;47string 2;26string 3;"); } /***********************************/ void test37() { string[ulong] x; ulong v1 = 297321415603; ulong v2 = 331681153971; x[v1] = "aa"; printf( "%llx %llx\n", v1, v2 ); assert(!(v2 in x)); } /***********************************/ void test38() { int n = atoi("1"); static char flags[8192 + 1]; long i, k; int count = 0; try { while (n--) { count = 0; for (i = 2; i <= 8192; i++) flags[cast(size_t)i] = 1; for (i = 2; i <= 8192; i++) { if (flags[cast(size_t)i]) { for (k = i+i; k <= 8192; k += i) flags[cast(size_t)k] = 0; count++; } } } printf("Count: %d\n", count); assert(count == 1028); } catch { printf("Exception: %d\n", k); assert(0); } } /***********************************/ interface I39 { } class C39 : I39 { int x = 432; } void test39() { C39 c = new C39; printf("%p %d\n", c, c.x); assert(c.x == 432); printf("%p\n", cast(I39) c); c = cast(C39) cast(I39) c; printf("%p\n", c); assert(c !is null); } /***********************************/ void test40() { Object x; x = null; x = 0 ? x : null; x = 0 ? null : x; } /***********************************/ int foo42(const(char) *x, ...) { va_list ap; va_start!(typeof(x))(ap, x); printf("&x = %p, ap = %p\n", &x, ap); int i; i = va_arg!(typeof(i))(ap); printf("i = %d\n", i); long l; l = va_arg!(typeof(l))(ap); printf("l = %lld\n", l); uint k; k = va_arg!(typeof(k))(ap); printf("k = %u\n", k); va_end(ap); return cast(int)(i + l + k); } void test42() { int j; j = foo42("hello", 3, 23L, 4); printf("j = %d\n", j); assert(j == 30); } /***********************************/ void test43() { creal C,Cj; real y1,x1; C = x1 + y1*1i + Cj; C = 1i*y1 + x1 + Cj; C = Cj + 1i*y1 + x1; C = y1*1i + Cj + x1; C = 1i*y1 + Cj; C = Cj + 1i*y1; } /***********************************/ int x44; class A44 { this() { printf("A44 ctor\n"); x44 += 1; } ~this() { printf("A44 dtor\n"); x44 += 0x100; } } class B44 : A44 { } void foo44() { scope B44 b = new B44; } void test44() { printf("foo44...\n"); foo44(); printf("...foo44\n"); assert(x44 == 0x101); } /***********************************/ /* import std.stdarg; import std.utf; int unFormat( bool delegate( out dchar ) getc, bool delegate( dchar ) ungetc, TypeInfo[] arguments, void* argptr ) { size_t arg = 0; dchar[] fmt; if( arguments[arg] is typeid( string ) ) fmt = toUTF32( va_arg!(string)( argptr ) ); else if( arguments[arg] is typeid( wchar[] ) ) fmt = toUTF32( va_arg!(wchar[])( argptr ) ); else if( arguments[arg] is typeid( dchar[] ) ) fmt = va_arg!(dchar[])( argptr ); else return 0; } */ void test45() { } /***********************************/ int sreadf( ... ) { va_arg!(string)( _argptr ); return 0; } void test46() { printf( "hello world\n" ); } /***********************************/ void test48() { try{ }finally{ debug(p48) { } } } /***********************************/ void test49() { int k = 1; if(k == 0) debug{printf("test");} } /***********************************/ void test50() { int x; if (x) version (none) foo; } /***********************************/ /+ void foo51(creal a) { writeln(a); assert(a == -8i); } void test51() { cdouble a = (2-2i)*(2-2i); // This fails writeln(a); assert(a == -8i); // This works writeln((2-2i)*(2-2i)); // This fails foo51((2-2i)*(2-2i)); } +/ void foo51(creal a) { assert(a == -8i); } void test51() { assert((2-2i)*(2-2i) == -8i); cdouble a = (2-2i)*(2-2i); assert(a == -8i); foo51((2-2i)*(2-2i)); } /***********************************/ // Bug 391 void test52() { char[] a; a = "\u3026\u2021\u3061\n".dup; assert(a =="\u3026\u2021\u3061\n"); assert(a.sort == "\n\u2021\u3026\u3061"); assert(a.reverse =="\u3061\u3026\u2021\n"); } /***********************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test42(); test43(); test44(); test45(); test46(); test48(); test49(); test50(); test51(); test52(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/gdb14313.d0000664000175000017500000000036512776215022021505 0ustar kaikai/* REQUIRED_ARGS: -g PERMUTE_ARGS: GDB_SCRIPT: --- b 21 r echo RESULT= p 'gdb.x' + 'gdb.y' --- GDB_MATCH: RESULT=.*4000065002 */ module gdb; __gshared uint x = 4_000_000_000; __gshared ushort y = 65000; void main() { ++x; ++y; // BP } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ice10857.d0000664000175000017500000000012512776215022021514 0ustar kaikai// EXTRA_SOURCES: imports/ice10857a.d imports/ice10857b.d import imports.ice10857a; ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testmod2.d0000664000175000017500000000026112776215022022111 0ustar kaikai// EXTRA_SOURCES: imports/testmod2a.d /**********************************/ // bug 1904 import imports.testmod2a; void main() { void whatever() {} foo!(whatever)(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_no_gc.d0000664000175000017500000000106612776215022022263 0ustar kaikai// REQUIRED_ARGS: -nogc // None of the below array literals should be allocated on the GC heap. void arrayLiterals() { int[3] x = [1, 2, 3]; if (x[2] != 3) assert(0); auto a = 4; int[3] y = [1, 2, a]; if (y[2] != 4) assert(0); immutable int[] z = [1, 2, 3]; if (z[2] != 3) assert(0); } // Enums shouldn't actually be emitted as variable declarations (see GitHub // issue #762). void noEmitEnum() { foreach (i; 0 .. 10000) { enum sortedIDs = [2, 4, 1, 5, 7]; } } void main() { arrayLiterals(); noEmitEnum(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_1450.d0000664000175000017500000000051612776215022023130 0ustar kaikai__gshared bool baseMethodCalled = false; struct S { long a, b; } class A { S foo() { baseMethodCalled = true; return S(); } } class B : A { override S foo() { auto r = super.foo(); return r; } } void main() { auto b = new B; b.foo(); assert(baseMethodCalled); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_812.d0000664000175000017500000000017612776215022023053 0ustar kaikaiimport std.stdio; interface A {} class B : A { ubyte[0] test; } void main() { A a = new B(); B b = cast(B) a; }ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test9377.sh0000775000175000017500000000101712776215022022053 0ustar kaikai#!/usr/bin/env bash src=runnable${SEP}extra-files dir=${RESULTS_DIR}${SEP}runnable output_file=${dir}/test9377.sh.out if [ $OS == "win32" -o $OS == "win64" ]; then LIBEXT=.lib else LIBEXT=.a fi libname=${dir}${SEP}lib9377${LIBEXT} $DMD -m${MODEL} -I${src} -of${libname} -c ${src}${SEP}mul9377a.d ${src}${SEP}mul9377b.d -lib || exit 1 $DMD -m${MODEL} -I${src} -of${dir}${SEP}mul9377${EXE} ${src}${SEP}multi9377.d ${libname} || exit 1 rm ${dir}/{lib9377${LIBEXT},mul9377${OBJ},mul9377${EXE}} echo Success >${output_file} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_944.d0000664000175000017500000000105612776215022023057 0ustar kaikaiimport core.stdc.errno; struct epoll_event { align(1): uint events; epoll_data_t data; } union epoll_data_t { void *ptr; int fd; uint u32; ulong u64; } enum PollerEventType : int { a } struct PollerEvent { PollerEventType type; int fd; } struct Epoll { ushort[1024] regFds; int epollFd = -1; epoll_event[32] events; PollerEvent[events.length * 4] pollerEvents; } struct Reactor { bool a = true; bool b; Epoll poll; } __gshared Reactor f; Reactor* foo() { return &f; } void main() {} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test58.d0000664000175000017500000000016112776215022021503 0ustar kaikai// EXTRA_SOURCES: imports/test58a.d // PERMUTE_ARGS: import imports.test58a; void main() { foo!(long)(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/interface1.d0000664000175000017500000000526712776215022022404 0ustar kaikai extern(C) int printf(const char*, ...); /*******************************************/ interface D { int foo(); } class A : D { int foo() { return 1; } } class B : A, D { override int foo() { return 2; } } class C : B, D { override int foo() { return 3; } } void test1() { C c = new C; A a = cast(A) c; int j = a.foo(); printf("%d\n", j); assert(j == 3); B b = cast(B) c; int k = b.foo(); printf("%d\n", k); assert(k == 3); D d1 = cast(D) c; int l = d1.foo(); printf("%d\n", l); assert(l == 3); D d2 = cast(D) b; int m = d2.foo(); printf("%d\n", m); assert(m == 3); } /*******************************************/ interface D2 { int foo(); } class A2 : D2 { int foo() { printf("A2\n"); return 1; } } class B2 : A2 { override int foo() { printf("B2\n"); return 2; } } class C2 : B2, D2 { override int foo() { printf("C2\n"); return 3; } } void test2() { int i; C2 c = new C2; D2 d = cast(D2)c; i = c.foo(); assert(i == 3); i = d.foo(); assert(i == 3); B2 b = new B2; if (cast(D2) b) { D2 e = cast(D2) b; i = e.foo(); assert(i == 2); } else assert(0); A2 a; if (cast(D2) a) assert(0); } /*******************************************/ interface C3 { int doLayout(); } class A3 { void print() { printf("A3::print\n"); } } class B3 : A3, C3 { int doLayout() { printf( "B3::doLayout\n" ); return 17; } } void callLayout(A3 b) { printf("b = %p\n", b); C3 cl = cast(C3)b; printf("cl = %p\n", cl); if (cl) { int i; i = cl.doLayout(); assert(i == 17); } else { printf("the 'A3' you passed did not implement 'C3'\n" ); assert(0); } } void test3() { callLayout(new B3()); } /*******************************************/ template IContainer(T) { interface IContainer { alias Container!(int) selected_type; bool isEmpty(); int enumerate(); } } template Container(T) { class Container : IContainer!(int) { bool isEmpty() { return false; } int enumerate() { return 3; } } } void Vector_test_IContainer_int() { alias IContainer!(int) icontainer_t; } void test4() { } /*******************************************/ interface Italy(T) { alias Foo5!(int) selected_type; bool isempty(); int enumerate(); } class Foo5(T) : Italy!(int) { bool isempty() { return false; } int enumerate() { return 3; } } void test5() { alias Italy!(int) Ic; Foo5!(int) f = new Foo5!(int); Ic i = cast(Ic)f; assert(i.isempty() == false); assert(i.enumerate() == 3); } /*******************************************/ int main (char[][] args) { test1(); test2(); test3(); test4(); test5(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link15021.d0000664000175000017500000000042412776215022021677 0ustar kaikai// PERMUTE_ARGS: -inline -g -debug -unittest import imports.std15021conv; class AliasDecl {} void aliasDecl(AliasDecl ad) { AliasDecl* zis; static if (is(typeof(to!string(*zis)))) { pragma(msg, "hit!"); to!string(*zis); } } void main() {} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testdt.d0000664000175000017500000000741012776215022021662 0ustar kaikai// PERMUTE_ARGS: /******************************************/ static int bigarray[100][100]; void test1() { for (int i = 0; i < 100; i += 1) { for (int j = 0; j < 100; j += 1) { //printf("Array %i %i\n", i, j); bigarray[i][j] = 0; } } } /******************************************/ // 10629 class Foo10629 {} struct Bar10629 { void[__traits(classInstanceSize, Foo10629)] x; } /******************************************/ // 11233 struct S11233 { uint[0x100000] arr; } /******************************************/ // 11672 void test11672() { struct V { float f; } struct S { V[3] v = V(1); } S s; assert(s.v == [V(1), V(1), V(1)]); /* was [V(1), V(nan), V(nan)] */ } /******************************************/ // 12509 struct A12509 { int member; } struct B12509 { A12509[0x10000] array; } /******************************************/ // 13505 class C13505 { void[10] x; } struct S13505 { void[10] x; } void test13505() { auto c = new C13505(); auto s = S13505(); } /******************************************/ // 14699 struct S14699a { ubyte[0][10] values; } struct S14699b { S14699a tbl; } // +/ ubyte[0][1] sa14699; void test14699() { //auto p = &sa14699; // Cannot work in Win32 (OMF) } /******************************************/ // 14805 struct S14805 { ushort one; } auto a14805 = new S14805[513*513]; /******************************************/ // 15664 struct Data15664A { int[2] a; int[2][2] b; int c; } Data15664A d15664a1 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK const Data15664A d15664a2 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK <- NG shared Data15664A d15664a3 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK <- NG shared const Data15664A d15664a4 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK <- NG immutable Data15664A d15664a5 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK <- NG struct Data15664B { int[2] a; const int[2][2] b; int c; } Data15664B d15664b1 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK const Data15664B d15664b2 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK shared Data15664B d15664b3 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK <- NG shared const Data15664B d15664b4 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK <- NG immutable Data15664B d15664b5 = {[1, 2], [[3, 4], [5, 6]], 7}; // OK <- NG void test15664() { assert(d15664a1.a == [1, 2]); assert(d15664a2.a == [1, 2]); assert(d15664a3.a == cast(shared)[1, 2]); assert(d15664a4.a == cast(shared)[1, 2]); assert(d15664a5.a == [1, 2]); assert(d15664a1.b == [[3, 4], [5, 6]]); assert(d15664a2.b == [[3, 4], [5, 6]]); assert(d15664a3.b == cast(shared)[[3, 4], [5, 6]]); assert(d15664a4.b == cast(shared)[[3, 4], [5, 6]]); assert(d15664a5.b == [[3, 4], [5, 6]]); assert(d15664a1.c == 7); // OK assert(d15664a2.c == 7); // OK <- BG assert(d15664a3.c == 7); // OK <- NG assert(d15664a4.c == 7); // OK <- NG assert(d15664a5.c == 7); // OK <- NG assert(d15664b1.a == [1, 2]); assert(d15664b2.a == [1, 2]); assert(d15664b3.a == cast(shared)[1, 2]); assert(d15664b4.a == cast(shared)[1, 2]); assert(d15664b5.a == [1, 2]); assert(d15664b1.b == [[3, 4], [5, 6]]); assert(d15664b2.b == [[3, 4], [5, 6]]); assert(d15664b3.b == cast(shared)[[3, 4], [5, 6]]); assert(d15664b4.b == cast(shared)[[3, 4], [5, 6]]); assert(d15664b5.b == [[3, 4], [5, 6]]); assert(d15664b1.c == 7); // OK assert(d15664b2.c == 7); // OK assert(d15664b3.c == 7); // OK <- NG assert(d15664b4.c == 7); // OK <- NG assert(d15664b5.c == 7); // OK <- NG } /******************************************/ int main() { test1(); test11672(); test15664(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_328.d0000664000175000017500000000024612776215022023053 0ustar kaikaivoid bar() { scope(exit) { } throw new Exception("Enforcement failed"); } void main() { try bar(); catch (Exception) {} } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testmod1.d0000664000175000017500000000025112776215022022107 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/testmod1a.d imports/testmod1b.d // PERMUTE_ARGS: struct Foo(T) { void foo(T arg) { } } int main() { return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test8997.d0000664000175000017500000000030012776215022021662 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/test8997a.d module test8997; import imports.test8997a; void main() { auto a = new A(); foreach(key; a.foobar.byKey()) { } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testdstress.d0000664000175000017500000002603612776215022022747 0ustar kaikai// PERMUTE_ARGS: module dstress.run.module_01; import core.memory; import core.exception; import core.vararg; extern(C) void* malloc(size_t size); /* ================================ */ struct MyStruct { int i; } void test1() { MyStruct inner() in{ assert(1); }out (result){ assert(result.i==1); }body{ MyStruct s; s.i = 1; return s; } assert(inner.i==1); } /* ================================ */ void foo2() in{ assert(0); } body{ } void test2() { try{ foo2(); }catch(Error ie){ return; } assert(0); } /* ================================ */ class MyClass3 { private int g() const { return 1; } invariant() { assert(g()==1); } } void test3() { MyClass3 c = new MyClass3(); assert(c); } /* ================================ */ class A { int x; this(){ printf("A.this()\n"); x=3; } invariant() { printf("A.invariant\n"); assert(x>2); } } class B : A { int y; this(){ printf("B.this()\n"); y=5; } invariant() { printf("B.invariant\n"); assert(y>4); } } void test4() { B gc = new B(); } /* ================================ */ class A5 { int x; this(){ printf("A5.this()\n"); x=3; } invariant() { printf("A5.invariant\n"); assert(x>2); } } class C5 : A5 { } class B5 : C5 { int y; this(){ printf("B5.this()\n"); y=5; } invariant() { printf("B5.invariant\n"); assert(y>4); } } void test5() { B5 gc = new B5(); } /* ================================ */ void test6() { long a; assert(a.max == 0x7FFF_FFFF_FFFF_FFFFL); //assert(a.min == 0xFFFF_FFFF_FFFF_FFFFL); assert(a.min == 0x8000_0000_0000_0000L); assert(a.init == 0); assert(a.sizeof == 8); } /* ================================ */ int i; void test7() { assert(dstress.run.module_01.i==0); dstress.run.module_01.i++; assert(dstress.run.module_01.i==1); } /* ================================ */ template mix(){ int x; } mixin .mix; void test8() { } /* ================================ */ struct A9 { B9 next; } alias A9* B9; void test9() { B9 n = new A9; } /* ================================ */ struct TestStruct { void add(...) { TestStruct other = va_arg!TestStruct(_argptr); foreach(int value; other) { foo(); } } void foo() { assert(left is null); bar(); } void bar() { assert(left is null); } int opApply(int delegate(ref int val) dg) { return 0; } void* left; } void test10() { TestStruct t; t.foo(); } /* ================================ */ int status11; void check(int x){ status11++; } class MyClass11{ void test(){ assert(status11==0); .check(0); assert(status11==1); check(); assert(status11==3); } void check(){ assert(status11==1); status11+=2; } } void test11() { MyClass11 c = new MyClass11(); assert(status11==0); c.test(); assert(status11==3); check(0); assert(status11==4); } /* ================================ */ int status12; class C12{ void foo(){ status12='N'; } static void foo(int x){ status12=x; } } void test12() { C12 m = new C12(); C12.foo('S'); assert(status12=='S'); m.foo('s'); assert(status12=='s'); m.foo(); assert(status12=='N'); } /* ================================ */ void test13() { wstring a="abc"; wstring b="efg"; wstring c=a~"d"~b; assert(c == "abcdefg"); } /* ================================ */ void test14() { dstring a="abc"; dstring b="efg"; dstring c=a~"d"~b; assert(c == "abcdefg"); } /* ================================ */ class Parent15 { void test(int i){ } int opCast(){ return 0; } } class Child15 : Parent15 { } void test15() { (new Child15()).test(2); } /* ================================ */ class Parent16 { void test(int i){ } } class Child16 : Parent16 { int opCast(){ return 0; } } void test16() { (new Child16()).test=2; } /* ================================ */ void foo17(){ class MyClass{ static int x; } } void foo17(int i){ class MyClass{ static int x; } } void test17() { } /* ================================ */ void foo18(){ struct MyStruct{ static int x; } } void foo18(int i){ struct MyStruct{ static int x; } } void test18() { } /* ================================ */ class Class19 : Throwable { this() { super(""); } } alias Class19 Alias19; void test19() { try{ throw new Alias19(); }catch{ return; } assert(0); } /* ================================ */ public static const uint U20 = (cast(uint)(-1)) >>> 2; alias uint myType20; public static const myType20 T20 = (cast(myType20)(-1)) >>> 2; void test20() { assert(U20 == 0x3FFFFFFF); assert(T20 == 0x3FFFFFFF); } /* ================================ */ class C21(T1){ alias T1 type1; } class C21(T1, T2){ alias T1 type1; alias .C21!(T2) type2; } void test21() { alias C21!(int,long) CT; CT c = new CT(); } /* ================================ */ scope class AutoClass{ } void test22() { scope AutoClass ac = new AutoClass(); with(ac){ } } /* ================================ */ int status23; scope class C23{ ~this(){ assert(status23==0); status23--; throw new Exception("error msg"); } } void foo23(){ assert(status23==0); scope C23 ac = new C23(); } void test23() { try{ foo23(); }catch{ } assert(status23==-1); } /* ================================ */ int status24; scope class C24{ this(){ assert(status24==0); status24+=2; } ~this(){ assert(status24==2); status24--; throw new Exception("error msg"); } } void check24(){ scope C24 ac = new C24(); throw new Exception("check error"); } void test24() { assert(status24==0); try{ check24(); }catch{ assert(status24==1); status24-=5; } assert(status24==-4); } /* ================================ */ struct S25{ S25 opSub(int i) { S25 s; return s; } } struct GeomObject{ S25 mesh; int xlate; } void extractTriangles(GeomObject g) { void foobar() { g.mesh - g.xlate; //g.mesh.opSub(g.xlate); } foobar(); } void test25() { } /* ================================ */ struct S26{ int i; void display(){ assert(i==10); } void someFunc(){ // We never call this function void bug(S26[] array){ array[0].i = i+1; } assert(i==10); display(); assert(i==10); } } void test26() { S26 m; m.i = 10; assert(m.i==10); m.someFunc(); assert(m.i==10); } /* ================================ */ template foo27(T:T[],alias S) { string foo(T[] a, T[] b) { return a ~ S ~ b; } } string comma = ", "; alias foo27!(string,comma).foo catComma; void test27() { string a = "Heath"; string b = "Regan"; assert("Heath, Regan"==catComma(a,b)); } /* ================================ */ void test28() { assert((new S28!()).i==int.sizeof); } struct S28(){ int i=func28(0).sizeof; } int func28(...){ return 0; } /* ================================ */ void test29() { uint u; u = 1 << 31; assert( u == 0b1000_0000__0000_0000__0000_0000__0000_0000u); } /* ================================ */ // Test for FinalizeError - it will be thrown if an Exception is thrown // during the class object finalization. int status30; class C30 { this() { status30++; } ~this() { status30--; throw new Exception("E2"); } } void test30() { try { //scope C30 m = new C30(); // It will insert one more `delete m` for the scope destruction, and it will be // called during stack unwinding. // Instead use bare memory chunk on stack to construct dummy class instance. void[__traits(classInstanceSize, C30)] payload = typeid(C30).init[]; C30 m = cast(C30)payload.ptr; m.__ctor(); assert(status30 == 1); delete m; // _d_callfinalizer } catch (Error e) // FinalizeError { assert(status30 == 0); status30--; } assert(status30 == -1); } /* ================================ */ void test31() { string str = x"F0 9D 83 93"; // utf-8 for U+1D0D3 int count=0; dchar tmp; foreach(dchar value ; str){ tmp=value; count++; } assert(count==1); assert(tmp==0x01D0D3); } /* ================================ */ import std.stdio; union MyUnion32 { int i; byte b; } void test32() { TypeInfo ti = typeid(MyUnion32*); assert(!(ti is null)); writefln("%s %d %d", ti.toString(), ti.tsize, (MyUnion32*).sizeof); assert(ti.tsize==(MyUnion32*).sizeof); assert(ti.toString()=="dstress.run.module_01.MyUnion32*"); } /* ================================ */ void test33() { creal a=1.3L+9.7Li; assert(a.re == 1.3L); assert(a.im == 9.7L); } /* ================================ */ void test34() { creal c = 2.7L + 0i; assert(c.re==2.7L); assert(c.im==0.0L); } /* ================================ */ void test35() { try{ onOutOfMemoryError(); }catch(OutOfMemoryError e){ return; } assert(0); } /* ================================ */ void test36() { try{ onOutOfMemoryError(); }catch(OutOfMemoryError e){ return; } assert(0); } /* ================================ */ struct S37{ int a; } const int i37 = 15; const S37 s1 = { i37+1 }; const S37 s2 = s1; void test37() { assert(s1.a == 16); assert(s2.a == 16); } /* ================================ */ class Foo38 { enum MyEnum{ VALUE_A=1, } } class Bar38 { enum MyEnum{ VALUE_B=2, } } void test38() { assert(Foo38.MyEnum.VALUE_A==1); assert(Bar38.MyEnum.VALUE_B==2); } /* ================================ */ void test39() { bool[] bArray; int[] iArray; bArray[]=false; foreach(int c; iArray){ assert(0); } } /* ================================ */ bool checked40; class Parent40{ int x; void test(){ } invariant() { assert(!checked40); checked40=true; // even number assert((x&1u)==0); } } class Child40 : Parent40{ } class GrandChild40 : Child40{ this(){ x=5; } } void test40() { try{ assert(!checked40); GrandChild40 gc = new GrandChild40(); }catch{ assert(checked40); return; } assert(0); } /* ================================ */ int counter41; class C41{ this(){ printf("this: counter41 = %d\n", counter41); assert(counter41==1); counter41+=2; } new(size_t size){ printf("new: size = %d\n", size); assert(counter41==0); counter41++; return malloc(size); } } void test41() { C41 c; assert(counter41==0); c = new C41(); assert(counter41==3); } /* ================================ */ struct S42{ int y; void* x; } void test42() { size_t t; t = S42.y.offsetof; assert(t == 0); t = S42.x.offsetof; assert((t % (void*).sizeof) == 0); } /* ================================ */ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/nogc.d0000664000175000017500000000133212776215022021276 0ustar kaikai extern(C) int printf(const char*, ...); /***********************/ @nogc int test1() { return 3; } /***********************/ // 3032 void test3032() @nogc { scope o1 = new Object(); // on stack scope o2 = new class Object {}; // on stack int n = 1; scope fp = (){ n = 10; }; // no closure fp(); assert(n == 10); } /***********************/ // 12642 __gshared int[1] data12642; int[1] foo12642() @nogc { int x; return [x]; } void test12642() @nogc { int x; data12642 = [x]; int[1] data2; data2 = [x]; data2 = foo12642(); } /***********************/ int main() { test1(); test3032(); test12642(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testbounds_off.d0000664000175000017500000000117712776215022023403 0ustar kaikai// REQUIRED_ARGS: -boundscheck=off // PERMUTE_ARGS: -inline -g -O import core.exception : RangeError; // Check for RangeError is thrown bool thrown(T)(lazy T cond) { import core.exception; bool f = false; try { cond(); } catch (RangeError e) { f = true; } return f; } @safe int safeIndex (int[] arr) { return arr[2]; } @trusted int trustedIndex(int[] arr) { return arr[2]; } @system int systemIndex (int[] arr) { return arr[2]; } void main() { int[3] data = [1,2,3]; int[] arr = data[0..2]; assert(arr. safeIndex() == 3); assert(arr.trustedIndex() == 3); assert(arr. systemIndex() == 3); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/template6.d0000664000175000017500000002521212776215022022254 0ustar kaikai// This is a copy of the engine here: // http://www.digitalmars.com/d/2.0/templates-revisited.html // which is a cut down version of the file here: // http://www.dsource.org/projects/ddl/browser/trunk/meta/regex.d // which has this copyright notice: /+ Copyright (c) 2005 Eric Anderton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/ import std.stdio; const int testFail = -1; /** * Compile pattern[] and expand to a custom generated function * that will take a string str[] and apply the regular expression * to it, returning an array of matches. */ template regexMatch(string pattern) { string[] regexMatch(string str) { string[] results; int result = regexCompile!(pattern).fn(str); if(result != testFail && result > 0){ results ~= str[0..result]; } return results; } } /****************************** * The testXxxx() functions are custom generated by templates * to match each predicate of the regular expression. * * Params: * string str the input string to match against * * Returns: * testFail failed to have a match * n >= 0 matched n characters */ /// Always match template testEmpty() { int testEmpty(string str) { return 0; } } /// Match if testFirst(str) and testSecond(str) match template testUnion(alias testFirst,alias testSecond,string key) { int testUnion(string str) { int result = testFirst(str); if(result != testFail){ int nextResult = testSecond(str[result..$]); if(result != testFail) return result + nextResult; } return testFail; } } /// Match if first part of str[] matches text[] template testText(string text) { int testText(string str) { if (str.length && text.length <= str.length && str[0..text.length] == text ) return text.length; return testFail; } } /// Match if testPredicate(str) matches 0 or more times template testZeroOrMore(alias testPredicate,string key) { int testZeroOrMore(string str) { if(str.length == 0) return 0; int result = testPredicate(str); if(result != testFail){ int nextResult = .testZeroOrMore!(testPredicate,key)(str[result..$]); if(nextResult != testFail) return result + nextResult; return result; } return 0; } } /// Match if term1[0] <= str[0] <= term2[0] template testRange(string term1,string term2) { int testRange(string str) { if(str.length && str[0] >= term1[0] && str[0] <= term2[0]) return 1; return testFail; } } /// Match if ch[0]==str[0] template testChar(string ch) { int testChar(string str) { if(str.length && str[0] == ch[0]) return 1; return testFail; } } /// Match if str[0] is a word character template testWordChar() { int testWordChar(string str) { if(str.length && ( (str[0] >= 'a' && str[0] <= 'z') || (str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= '0' && str[0] <= '9') || str[0] == '_' ) ) { return 1; } return testFail; } } /*****************************************************/ /** * Returns the front of pattern[] up until the end or a special character. */ template parseTextToken(string pattern){ static if(pattern.length > 0){ static if(isSpecial!(pattern)){ const string parseTextToken=""; } else{ const string parseTextToken = pattern[0] ~ parseTextToken!(pattern[1..$]); } } else{ const string parseTextToken=""; } } /** * Parses pattern[] up to and including terminator. * Returns: * token[] everything up to terminator. * consumed number of characters in pattern[] parsed */ template parseUntil(string pattern,char terminator,bool fuzzy=false){ static if(pattern.length > 0){ static if(pattern[0] == '\\'){ static if(pattern.length > 1){ const string nextSlice = pattern[2 .. $]; alias parseUntil!(nextSlice,terminator,fuzzy) next; const string token = pattern[0 .. 2] ~ next.token; const uint consumed = next.consumed+2; } else{ pragma(msg,"Error: expected character to follow \\"); static assert(false); } } else static if(pattern[0] == terminator){ const string token=""; const uint consumed = 1; } else{ const string nextSlice = pattern[1 .. $]; alias parseUntil!(nextSlice,terminator,fuzzy) next; const string token = pattern[0] ~ next.token; const uint consumed = next.consumed+1; } } else static if(fuzzy){ const string token = ""; const uint consumed = 0; } else{ pragma(msg,"Error: exptected " ~ terminator ~ " to terminate group expression"); static assert(false); } } /** * Parse contents of character class. * Params: * pattern[] rest of pattern to compile * Output: * fn generated function * consumed number of characters in pattern[] parsed */ template regexCompileCharClass2(string pattern){ static if(pattern.length > 0){ static if(pattern.length > 1){ static if(pattern[1] == '-'){ static if(pattern.length > 2){ alias testRange!(pattern[0..1], pattern[2..3]) termFn; const uint thisConsumed = 3; const string remaining = pattern[3 .. $]; } else{ // length is 2 pragma(msg,"Error: expected character following '-' in character class"); static assert(false); } } else{ // not '-' alias testChar!(pattern[0..1]) termFn; const uint thisConsumed = 1; const string remaining = pattern[1 .. $]; } } else{ alias testChar!(pattern[0..1]) termFn; const uint thisConsumed = 1; const string remaining = pattern[1 .. $]; } static if(remaining.length > 0){ static if(remaining[0] != ']'){ alias regexCompileCharClass2!(remaining) next; alias testOr!(termFn,next.fn,remaining) fn; const uint consumed = next.consumed + thisConsumed; } else{ alias termFn fn; const uint consumed = thisConsumed; } } else{ alias termFn fn; const uint consumed = thisConsumed; } } else{ alias testEmpty!() fn; const uint consumed = 0; } } /** * At start of character class. Compile it. * Params: * pattern[] rest of pattern to compile * Output: * fn generated function * consumed number of characters in pattern[] parsed */ template regexCompileCharClass(string pattern){ static if(pattern.length > 0){ static if(pattern[0] == ']'){ alias testEmpty!() fn; const uint consumed = 0; } else{ alias regexCompileCharClass2!(pattern) charClass; alias charClass.fn fn; const uint consumed = charClass.consumed; } } else{ pragma(msg,"Error: expected closing ']' for character class"); static assert(false); } } /** * Look for and parse '*' postfix. * Params: * test function compiling regex up to this point * token[] the part of original pattern that the '*' is a postfix of * pattern[] rest of pattern to compile * Output: * fn generated function * consumed number of characters in pattern[] parsed */ template regexCompilePredicate(alias test,string token,string pattern){ static if(pattern.length > 0){ static if(pattern[0] == '*'){ alias testZeroOrMore!(test,token) fn; const uint consumed = 1; } else{ alias test fn; const uint consumed = 0; } } else{ alias test fn; const uint consumed = 0; } } /** * Parse escape sequence. * Params: * pattern[] rest of pattern to compile * Output: * fn generated function * consumed number of characters in pattern[] parsed */ template regexCompileEscape(string pattern){ static if(pattern.length > 0){ static if(pattern[0] == 's'){ // whitespace char alias testRange!("\x00","\x20") fn; } else static if(pattern[0] == 'w'){ //word char alias testWordChar!() fn; } else{ alias testChar!(pattern[0 .. 1]) fn; } const uint consumed = 1; } else{ pragma(msg,"Error: expected char following '\\'"); static assert(false); } } /** * Parse and compile regex represented by pattern[]. * Params: * pattern[] rest of pattern to compile * Output: * fn generated function */ template regexCompile(string pattern) { static if(pattern.length > 0){ static if(pattern[0] == '['){ const string charClassToken = parseUntil!(pattern[1 .. $],']').token; alias regexCompileCharClass!(charClassToken) charClass; const string token = pattern[0 .. charClass.consumed+2]; const string next = pattern[charClass.consumed+2 .. $]; alias charClass.fn test; } else static if(pattern[0] == '\\'){ alias regexCompileEscape!(pattern[1..$]) escapeSequence; const string token = pattern[0 .. escapeSequence.consumed+1]; const string next = pattern[escapeSequence.consumed+1 .. $]; alias escapeSequence.fn test; } else{ const string token = parseTextToken!(pattern); static assert(token.length > 0); const string next = pattern[token.length .. $]; alias testText!(token) test; } alias regexCompilePredicate!(test,token,next) term; const string remaining = next[term.consumed .. next.length]; static if(remaining.length > 0){ alias testUnion!(term.fn,regexCompile!(remaining).fn,remaining) fn; } else{ alias term.fn fn; } } else{ alias testEmpty!() fn; } } /// Utility function for parsing template isSpecial(string pattern) { static if( pattern[0] == '*' || pattern[0] == '+' || pattern[0] == '?' || pattern[0] == '.' || pattern[0] == '[' || pattern[0] == '{' || pattern[0] == '(' || pattern[0] == '$' || pattern[0] == '^' || pattern[0] == '\\' ){ const bool isSpecial = true; } else{ const bool isSpecial = false; } } int main() { auto exp = ®exMatch!(r"[a-z]*\s*\w*"); string[] m = exp("hello world"); writefln("matches: %s", m); assert(m.length == 1); assert(m[0] == "hello world"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testline.d0000664000175000017500000000120612776215022022177 0ustar kaikai// PERMUTE_ARGS: // $HeadURL$ // $Date$ // $Author$ module dstress.run.line_token_03; import std.stdio; import core.exception; int main(){ try{ #line 1 "" assert(0); }catch(AssertError o){ checkFileSpec(o); return 0; } assert(0); } import std.stdio; /* * @WARNING@: this code depends on the phobos implementation. * char[]s returned by wrong assertions have to look like: * "blah blah "filename" blah blah" */ void checkFileSpec(Object o){ string str=o.toString(); int start; for(start=0; start FuncExp assert(this.compare(2, 1)); // old: 'this.compare' -> DotVarExp (e1: ThisExp, var: FuncLiteralDeclaration) // new: 'this.compare' -> CommaExp (e1: ThisExp, e2: FuncExp) // Then, in both cases lambda->toObjFile() will run via FuncExp::toElem(). } } void main() { // OK auto foo1 = new Foo!(1, "a > b"); auto foo2 = new Foo!(2, (a, b) => a > b); auto foo3 = new Foo!(3, delegate(a, b){ return a > b; }); // OK <- NG auto foo4 = new Foo!(4, (int a, int b) => a > b); auto foo5 = new Foo!(5, function(int a, int b){ return a > b; }); auto foo6 = new Foo!(6, delegate(int a, int b){ return a > b; }); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/nulltype.d0000664000175000017500000000674212776215022022236 0ustar kaikaiextern (C) int printf(const(char*) fmt, ...); alias typeof(null) null_t; /**********************************************/ void test1() { null_t null1; typeof(null) null2; static assert(is(typeof(null1) == typeof(null))); static assert(is(typeof(null2) == typeof(null))); static assert(is(typeof(null1) == null_t)); static assert(is(typeof(null2) == null_t)); } /**********************************************/ interface I{} class C{} int f(null_t) { return 1; } int f(int[]) { return 2; } int f(C) { return 3; } void test2() { static assert(is(null_t : C)); static assert(is(null_t : I)); static assert(is(null_t : int[])); static assert(is(null_t : void*)); static assert(is(null_t : int**)); static assert(!is(null_t == C)); static assert(!is(null_t == I)); static assert(!is(null_t == int[])); static assert(!is(null_t == void*)); static assert(!is(null_t == int**)); static assert(is(null_t == null_t)); assert(f(null) == 1); } /**********************************************/ // 5899 auto f5899(bool b) { if (b) return new Object; else return null; } static assert(is(typeof(f5899) R == return) && is(R == Object)); pragma(msg, typeof(f5899)); auto g5899(bool b) { if (b) return new int; else return null; } static assert(is(typeof(g5899) R == return) && is(R == int*)); pragma(msg, typeof(g5899)); auto h5899(bool b) { if (b) return [1]; else return null; } static assert(is(typeof(h5899) R == return) && is(R == int[])); pragma(msg, typeof(h5899)); /**********************************************/ // 7278 struct Foo7278(string s) { string var; void func() { string local = var; } } void test7278() { Foo7278!null a; Foo7278!null b; } /**********************************************/ // 8221 class A8221 { A8221 foo() { return this; } } class B8221: A8221 { override typeof(null) foo() { return null; } // error } void test8221() { auto a = new A8221(); assert(a.foo() is a); auto b = new B8221(); assert(b.foo() is null); a = b; assert(a.foo() is null); } /***************************************************/ // 8589 void test8589() { static typeof(null) retnull() { return null; } void test(bool result, T)() { void f(T function() dg) { assert(!dg()); } static assert((T.sizeof == typeof(null).sizeof) == result); static assert(is(typeof( f(&retnull) )) == result); static assert(is(typeof( f(()=>null) )) == result); static if (result) { f(&retnull); f(()=>null); } } test!(true, int*)(); test!(true, Object)(); test!(true, int[int])(); test!(false, int[])(); test!(false, void delegate())(); } /**********************************************/ // 9385 void test9385() { assert((null ? true : false) == false); if (null) assert(0); assert(!null); } /**********************************************/ // 12203 void test12203() { typeof(null) v; void foo(float) {} void delegate(float) dg = &foo; assert(dg !is null); dg = v; // Error: e2ir: cannot cast v of type typeof(null) to type void delegate(float) assert(dg is null); } /**********************************************/ int main() { test1(); test2(); test7278(); test8221(); test8589(); test9385(); test12203(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/A16.d0000664000175000017500000000020112776215022020671 0ustar kaikai// EXTRA_SOURCES: imports/A16a.d import std.stdio; class AA16 { protected: this() { printf("class AA16\n"); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testminit.d0000664000175000017500000000046412776215022022375 0ustar kaikai// EXTRA_SOURCES: imports/testminitAA.d imports/testminitBB.d // PERMUTE_ARGS: import core.stdc.stdio; import imports.testminitAA; private import imports.testminitBB; static this() { printf("hello\n"); assert(aa == 1); assert(bb == 1); } int main() { printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ifti.d0000664000175000017500000000516512776215022021313 0ustar kaikaiimport std.stdio; struct S { int x = 3; void fun(T)(T x) { writefln("S.fun(%s)(%s)",typeid(T),x); this.x += x; } } class Tst(TST, int v = 2) { int x = 3; int z = 4; final private void proc(int x) { writefln("proc(%s) -> %s",x,this.x); } void fun(T)(T x) { writefln("fun(%s)(%s) -> %s",typeid(T),x,this.x);} void fun()() { writefln("fun()() -> %s",this.x); } void fun2()() { writefln("fun2"); } class Inner { int y = 99; Tst outer; void f3() { z = 55; } // Make sure the correct this-ptr is used void f1() { writefln("Inner.f1"); proc(-11); outer.proc(-11); } void f2() { writefln("Inner.f2"); fun(-17); outer.fun(-17); } } Inner inner; this() { inner = new Inner; inner.outer = this; } void callInnerf1() { writefln("callInnerf1"); inner.f1(); } void callInnerf2() { writefln("callInnerf2"); inner.f2(); } // void opAdd(T)(T x) { this.x += x; writefln("opAdd(%s)",x); } void opPos()() { writefln("opPos()"); } //void opPos() { writefln("xxx"); } void opIndex(T)(T x) { writefln("opIndex[%s]",x); } void opIndex(A,B,C)(A a, B b, C c) { writefln("opIndex[(%s)%s,(%s)%s,(%s)%s]",typeid(A),a, typeid(B),b,typeid(C),c); } static if (v > 1) { void opCall(A = int, B = float)(A a = 1, B b = 8.2) { writefln("opCall(%s,%s)",a,b); this.x++; } } void opSlice(A,B)(A a, B b) { writefln("opSlice(%s,%s)",a,b); } void opSlice()() { writefln("opSlice()"); } void opIndexAssign(A,B)(A a, B b) { writefln("opIndexAssign((%s)%s,(%s)%s)",typeid(A),a,typeid(B),b); } void opSliceAssign(A,B,C)(A a, B b, C c) { writefln("opSliceAssign(%s,%s,%s)",a,b,c); } bool opEquals(A)(A x) { writefln("opEquals((%s))",typeid(A));return true; } int opApply(T)(int delegate(ref T)dg) { for (int i = 0; i < 5; i++) { T d = cast(T)(i+0.1); if (auto result = dg(d)) return result; } return 0; } } class Y : Tst!(float) {} void main() { Tst!(int) t = new Tst!(int); Y u = new Y; S s; t.x = 7; t.proc(5); t.fun(5); t.fun(); t.callInnerf1(); t.callInnerf2(); u.fun(5); u.fun(); u.callInnerf1(); u.callInnerf2(); s.fun(5); t.fun2(); +t; t+5; t[55]; t[1,2,3.0]; u[1,2,3.0]; t(1,2.5); t(2); t(); t[]; t[1..2]; u[1..2.5]; t[1i] = 5; t[-4.5..7i] = "hello"; t == t; auto b = t != t; // without assignment -> "! has no effect in expression" t == u; u == t; u == u; b = u != u; foreach(int i;t) { writefln("%s",i); } foreach(double i;t) { writefln("%s",i); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testenum.d0000664000175000017500000001651512776215022022225 0ustar kaikai// PERMUTE_ARGS: extern(C) int printf(const char*, ...); /**********************************************/ enum Bar { bar2 = 2, bar3, bar4 = 0 } void test1() { Bar b; assert(b == 2); } /**********************************************/ void test2() { enum E { a=-1 } assert(E.min == -1); assert(E.max == -1); } /**********************************************/ void test3() { enum E { a = 1, b = -1, c = 3, d = 2 } assert(E.min == -1); assert(E.max == 3); } /**********************************************/ void test4() { enum E { a = -1, b = -1, c = -3, d = -3 } assert(E.min==-3); assert(E.max==-1); } /**********************************************/ enum Enum5 { A = 3, B = 10, E = -5, } void test5() { assert(Enum5.init == Enum5.A); assert(Enum5.init == 3); Enum5 e; assert(e == Enum5.A); assert(e == 3); } /***********************************/ enum E6 : byte { NORMAL_VALUE = 0, REFERRING_VALUE = NORMAL_VALUE + 1, OTHER_NORMAL_VALUE = 2 } void foo6(E6 e) { } void test6() { foo6(E6.NORMAL_VALUE); foo6(E6.REFERRING_VALUE); foo6(E6.OTHER_NORMAL_VALUE); } /**********************************************/ // 2407 int i2407; void add2407() { ++i2407; } void sub2407() { --i2407; } enum EF2407f : void function() { a = &add2407, s = &sub2407, } enum EF2407s { a = &add2407, s = &sub2407, } enum { a2407 = &add2407, s2407 = &sub2407, } enum : void function() { at2407 = &add2407, st2407 = &sub2407, } enum EEF2407 : EF2407s { a = EF2407s.a, s = EF2407s.s, } void test2407() { alias i2407 i; EF2407f.a(); assert(i == 1); EF2407f.s(); assert(i == 0); EF2407s.a(); assert(i == 1); EF2407s.s(); assert(i == 0); a2407(); assert(i == 1); s2407(); assert(i == 0); at2407(); assert(i == 1); st2407(); assert(i == 0); EEF2407.a(); assert(i == 1); EEF2407.s(); assert(i == 0); EEF2407.init(); assert(i == 1); struct S { int i; } enum ES : S { a = S(1), b = S(3), c = S(2), } static assert(ES.init == S(1)); static assert(!__traits(compiles, ES.min)); static assert(!__traits(compiles, ES.max)); enum EES : ES { a = ES.a, b = ES.b, c = ES.c, } static assert(EES.init == ES.init); static assert(EES.init == S(1)); static assert(!__traits(compiles, EES.min)); static assert(!__traits(compiles, EES.max)); ES es = ES.c; assert(es.i == 2); es = ES.b; assert(es.i == 3); class C { this(int i) { this.i = i; } int i; } enum EC : C { a = new C(42), b = null, c = new C(1), d = new C(33), } static assert(EC.init.i == (new C(42)).i); static assert(!__traits(compiles, EC.min)); static assert(!__traits(compiles, EC.max)); EC ec = EC.d; assert(ec.i == 33); ec = EC.b; assert(ec is null); } /**********************************************/ // 3096 void test3096() { template Tuple(T...) { alias Tuple = T; } template Base(E) { static if(is(E B == enum)) alias Base = B; } template GetEnum(T) { enum GetEnum { v = T.init } } struct S { } class C { } foreach (Type; Tuple!(char, wchar, dchar, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real, S, C)) { static assert(is(Base!(GetEnum!Type) == Type)); } } /**********************************************/ // 7719 enum foo7719 = bar7719; enum { bar7719 = 1 } /**********************************************/ // 9845 enum { A9845 = B9845 } enum { B9845 = 1 } /**********************************************/ // 9846 const int A9846 = B9846; enum { B9846 = 1 } /**********************************************/ // 10105 enum E10105 : char[1] { a = "a" } /**********************************************/ // 10113 enum E10113 : string { a = "a", b = "b", abc = "abc" } void test10113() { E10113 v = E10113.b; bool check = false; final switch (v) { case E10113.a: assert(false); case E10113.b: check = true; break; case E10113.abc: assert(false); } assert(check); } /**********************************************/ // 10503 @property int octal10503(string num)() { return num.length; } enum { A10503 = octal10503!"2000000", B10503 = octal10503!"4000", } /**********************************************/ // 10505 enum { a10505 = true, b10505 = 10.0f, c10505 = false, d10505 = 10, e10505 = null } static assert(is(typeof(a10505) == bool)); static assert(is(typeof(b10505) == float)); static assert(is(typeof(c10505) == bool)); static assert(is(typeof(d10505) == int)); static assert(is(typeof(e10505) == typeof(null))); /**********************************************/ // 10561 void test10561() { template Tuple(T...) { alias Tuple = T; } foreach (Type; Tuple!(char, wchar, dchar, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real)) { enum : Type { v = 0, w = 0, x, y = x } static assert(is(typeof(v) == Type)); static assert(is(typeof(w) == Type)); static assert(is(typeof(x) == Type)); static assert(is(typeof(y) == Type)); } class B { } class D : B { } enum : B { a = new D, b = new B, c = null } static assert(is(typeof(a) == B)); static assert(is(typeof(b) == B)); static assert(is(typeof(c) == B)); struct S { this(int) { } } enum : S { d = S(1), e = S(2) } static assert(is(typeof(d) == S)); static assert(is(typeof(e) == S)); enum : float[] { f = [], g = [1.0, 2.0], h = [1.0f] } static assert(is(typeof(f) == float[])); static assert(is(typeof(g) == float[])); static assert(is(typeof(h) == float[])); } /**********************************************/ // 10612 int[E10612] ie10612; E10612[int] ei10612; E10612[E10612] ee10612; enum E10612 { a } /**********************************************/ // 10788 enum v10788 = e10788; enum : int { e10788 } /**********************************************/ class C7 { enum Policy { PREFER_READERS, PREFER_WRITERS } void foo1( Policy policy = Policy.PREFER_READERS ) { } void foo2( Policy policy = Policy.PREFER_WRITERS ) { } } /**********************************************/ void test8() { enum E { A = B, E = D + 7, B = 3, C, D, } assert(E.A == 3); assert(E.B == 3); assert(E.C == 4); assert(E.D == 5); assert(E.E == 12); assert(E.max == 12); } /**********************************************/ // 13220 enum E13220a; @(1) enum E13220b; void test13220() { auto prot = __traits(getProtection, E13220a); assert(prot == "public"); auto udas = __traits(getAttributes, E13220b); assert(udas[0] == 1); } /**********************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test2407(); test10113(); test10561(); test8(); test13220(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/closure.d0000664000175000017500000003465112776215022022036 0ustar kaikai import core.stdc.stdio; struct S { int a,b,c,d; } alias int delegate() dg_t; alias int delegate(int) dg1_t; void fill() { int[100] x; } /************************************/ dg_t foo() { int x = 7; int bar() { return x + 3; } return &bar; } void test1() { dg_t dg = foo(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo2() { dg_t abc() { int x = 7; int bar() { return x + 3; } return &bar; } return abc(); } void test2() { dg_t dg = foo2(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo3() { dg_t abc(int x) { int bar() { return x + 3; } return &bar; } return abc(7); } void test3() { dg_t dg = foo3(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo4() { S s; s = S(4,5,6,7); dg_t abc(S t) { int bar() { return t.d + 3; } return &bar; } return abc(s); } void test4() { dg_t dg = foo4(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ void test5() { int x = 7; dg_t abc(ref int y) { int bar() { y += 4; return y + 3; } return &bar; } dg_t dg = abc(x); fill(); assert(x == 7); auto i = dg(); assert(x == 11); assert(i == 14); x = 8; i = dg(); assert(x == 12); assert(i == 15); } /************************************/ void test6() { int x = 7; dg_t abc(out int y) { int bar() { y += 4; return y + 3; } return &bar; } dg_t dg = abc(x); fill(); assert(x == 0); auto i = dg(); assert(x == 4); assert(i == 7); x = 8; i = dg(); assert(x == 12); assert(i == 15); } /************************************/ void test7() { int[3] a = [10,11,12]; dg_t abc(int[3] y) { int bar() { y[2] += 4; return y[2] + 3; } return &bar; } dg_t dg = abc(a); fill(); assert(a[2] == 12); auto i = dg(); assert(a[2] == 12); assert(i == 19); } /************************************/ void test8() { S s = S(7,8,9,10); dg_t abc(ref S t) { int bar() { t.d += 4; return t.c + 3; } return &bar; } dg_t dg = abc(s); fill(); assert(s.d == 10); auto i = dg(); assert(s.d == 14); assert(i == 12); } /************************************/ S foo9(out dg_t dg) { S s1 = S(7,8,9,10); dg_t abc() { int bar() { s1.d += 4; return s1.c + 3; } return &bar; } dg = abc(); return s1; } void test9() { dg_t dg; S s = foo9(dg); fill(); assert(s.a == 7); assert(s.b == 8); assert(s.c == 9); assert(s.d == 10); auto i = dg(); assert(s.d == 10); assert(i == 12); } /************************************/ dg_t foo10() { dg_t abc() { int x = 7; int bar() { int def() { return x + 3; } return def(); } return &bar; } return abc(); } void test10() { dg_t dg = foo10(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo11() { int x = 7; class T { int bar() { return x + 3; } } T t = new T; return &t.bar; } void test11() { dg_t dg = foo11(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo12() { int x = 7; class T { int bar() { return x + 3; } int xyz() { return bar(); } } T t = new T; return &t.xyz; } void test12() { dg_t dg = foo12(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo13() { int x = 7; class T { int xyz() { int bar() { return x + 3; } return bar(); } } T t = new T; return &t.xyz; } void test13() { dg_t dg = foo13(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo14() { class T { int xyz() { int x = 7; int bar() { return x + 3; } return bar(); } } T t = new T; return &t.xyz; } void test14() { dg_t dg = foo14(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo15() { class T { int x = 7; int xyz() { int bar() { return x + 3; } return bar(); } } T t = new T; return &t.xyz; } void test15() { dg_t dg = foo15(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo16() { int a = 5; class T { int x = 7; int xyz() { int y = 8; int bar() { return a + x + y + 3; } return bar(); } } T t = new T; return &t.xyz; } void test16() { dg_t dg = foo16(); fill(); printf("bar = %d\n", dg()); assert(dg() == 23); } /************************************/ dg_t foo17() { int a = 5; class T { int x = 7; dg_t xyz() { int y = 8; int bar() { return a + x + y + 3; } return &bar; } } T t = new T; return t.xyz(); } void test17() { dg_t dg = foo17(); fill(); printf("bar = %d\n", dg()); assert(dg() == 23); } /************************************/ dg_t dg18; void bar18() { int a = 7; int foo() { return a + 3; } dg18 = &foo; int i = dg18(); assert(i == 10); } void test18() { bar18(); fill(); int i = dg18(); assert(i == 10); } /************************************/ void abc19(void delegate() dg) { dg(); dg(); dg(); } struct S19 { static S19 call(int v) { S19 result; result.v = v; void nest() { result.v += 1; } abc19(&nest); return result; } int a; int v; int x,y,z; } int foo19() { auto s = S19.call(5); return s.v; } void test19() { int i = foo19(); printf("%d\n", i); assert(i == 8); } /************************************/ void enforce20(lazy int msg) { } void test20() { int x; foreach (j; 0 .. 10) { printf("%d\n", j); assert(j == x); x++; enforce20(j); } } /************************************/ void thrash21() { char[128] x = '\xfe'; } void delegate() dg21; int g_input = 11, g_output; void f21() { int i = g_input + 2; class X { // both 'private' and 'final' to make non-virtual private final void actual() { g_output = i; } void go() { actual(); } } dg21 = & (new X).go; } void test21() { f21(); thrash21(); dg21(); assert(g_output == 13); } /************************************/ void thrash22() { char[128] x = '\xfe'; } int gi22; void delegate() dg22; class A22 { int x = 42; void am() { int j; /* Making f access this variable causes f's chain to be am's frame. Otherwise, f's chain would be the A instance. */ void f() { int k = j; void g() { class B { void bm() { gi22 = x; /* No checkedNestedReference for A.am.this, so it is never placed in a closure. */ } } (new B).bm(); } dg22 = &g; } f(); } } void test22() { (new A22).am(); thrash22(); dg22(); assert(gi22 == 42); } /************************************/ // 1759 void test1759() { struct S { int a, b, c; } struct SS { S obj; } static int delegate() makeSum1(S s) { with (s) return { return a + b + c; }; } static int delegate() makeSum2(S[1] sa) { with (sa[0]) return { return a + b + c; }; } static int delegate() makeSum3(SS ss) { with (ss.obj) return { return a + b + c; }; } static int delegate() makeSum4(SS[1] ssa) { with (ssa[0].obj) return { return a + b + c; }; } S s = {15, 30, 45}; SS ss = {s}; int delegate() sum; sum = makeSum1(s); assert(sum() == 90); sum = makeSum2([s]); assert(sum() == 90); sum = makeSum3(ss); assert(sum() == 90); sum = makeSum4([ss]); assert(sum() == 90); } /************************************/ // 1841 int delegate() foo1841() { int stack; int heap = 3; int nested_func() { ++heap; return heap; } return delegate int() { return nested_func(); }; } int delegate() foo1841b() { int stack; int heap = 7; int nested_func() { ++heap; return heap; } int more_nested() { return nested_func(); } return delegate int() { return more_nested(); }; } void test1841() { auto z = foo1841(); auto p = foo1841(); assert(z() == 4); p(); assert(z() == 5); z = foo1841b(); p = foo1841b(); assert(z() == 8); p(); assert(z() == 9); } /************************************/ // 5911 void writeln5911(const(char)[] str) {} void logout5911(lazy const(char)[] msg) { writeln5911(msg); } void test5911() { string str = "hello world"; logout5911((){ return str; }()); // closure 1 try { throw new Exception("exception!!"); } catch (Exception e) { assert(e !is null); logout5911(e.toString()); // closure2 SEGV : e is null. } } /************************************/ // 9685 auto get9685a(alias fun)() { int x = 10; struct Foo { size_t data; @property clone() { return Foo(15); } } return Foo(5); } void test9685a() { uint a = 42; auto bar = get9685a!(() => a)(); auto qux = bar.clone; //printf("bar context pointer : %p\n", bar.tupleof[$-1]); //printf("qux context pointer : %p\n", qux.tupleof[$-1]); assert(bar.tupleof[$-1] == qux.tupleof[$-1]); assert(qux.data == 15); } auto get9685b(alias fun)() { int x = 10; struct Foo { size_t data; @property clone() { return Foo(data + x); } } return Foo(5); } void test9685b() { uint a = 42; auto bar = get9685b!(() => a)(); auto qux = bar.clone; //printf("bar context pointer : %p\n", bar.tupleof[$-1]); //printf("qux context pointer : %p\n", qux.tupleof[$-1]); assert(bar.tupleof[$-1] == qux.tupleof[$-1]); assert(qux.data == 15); } /************************************/ // 12406 auto createDg12406() { static struct Dg { Dg delegate() action; } static void fn(void delegate()) { } int x; fn({ x++; }); // required Dg dg; Dg createDg2() { int x; void unusedFun() { x++; } // required return Dg(() => dg); // lambda returns garbage instead of dg } return dg = Dg(&createDg2); } void test12406() { auto dgs = [createDg12406()]; //printf("dgs[%2d].action = %p:%p\n", 0, dgs[$-1].action.ptr, dgs[$-1].action.funcptr); foreach (i; 1 .. 10+1) { dgs ~= dgs[i-1].action(); //printf("dgs[%2d].action = %p:%p\n", i, dgs[$-1].action.ptr, dgs[$-1].action.funcptr); } foreach (i, dgx; dgs) { if (i % 2 == 0) { // All closures are equal with dgs[0]. assert(dgx.action.ptr is dgs[0].action.ptr); assert(dgx.action.funcptr is dgs[0].action.funcptr); // is: createDg2 } else { // Each closures has unique context. for (size_t j = i + 2; j < dgs.length; j += 2) assert(dgx.action.ptr !is dgs[j].action.ptr); assert(dgx.action.funcptr is dgs[1].action.funcptr); // is: lambda () => dg } } } /************************************/ // 14730 void test14730() { static auto makeS(int x) { struct S { int n; int get() { return x; } // x will be a closure variable } return S(x); } auto s = makeS(1); assert(s.get() == 1); // By inlining get() function call, it's rewritten to: // assert(*(s.tupleof[$-1] + x.offset) == 1); // --> In DotVarExp::toElem(), x->offset should be already nonzero. } // ---- // This is questionable case. Currently it works without any errors, // but not sure it's really intentional struct S14730x(alias f) { auto foo()() { return f(0); } void dummy() {} } auto makeS14730x() //@nogc { int x = 10; S14730x!(a => x) s; //assert(s.foo() == 10); return s; } void test14730x() { auto s = makeS14730x(); assert(s.tupleof[$-1] !is null); // instantiationg foo outside of makeS will place the variable x in closure // *after* the semantic3 completion of makeS() function. assert(s.foo() == 10); } /************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test1759(); test1841(); test5911(); test9685a(); test9685b(); test12406(); test14730(); test14730x(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test31.d0000664000175000017500000000036512776215022021500 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/test31a.d // PERMUTE_ARGS: import imports.test31a; class Foo { mixin Baz!(); void testfunc() { privfunc(); // Error: .privfunc is private } } int main() { return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_eh.d0000664000175000017500000000073712776215022021576 0ustar kaikaistruct S1 { int x; this(this) { } ~this() { } } S1 createS1() { // dmdfe creates try-finally there to call destructor for s1, // later the statement is rewrited to try-catch, because // s1 is a nrvo variable. Test goto in such case. S1 s1; s1.x = 1; if(true) goto Lexit; s1.x = 2; Lexit: return s1; } void test1() { auto s1 = createS1(); assert(s1.x == 1); } void main() { test1(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test11.d0000664000175000017500000004437112776215022021503 0ustar kaikai// REQUIRED_ARGS: extern(C) int printf(const char*, ...); extern(C) size_t strlen(const char*); /**************************************/ alias strlen foo1; void test1() { const(char) *p = "bar"; size_t i = foo1(p); assert(i == 3); } /**************************************/ template Foo2(T) { alias T t; } alias Foo2!(int) t1; alias Foo2!(int).t t2; alias t1.t t3; alias t2 t4; alias Foo2!(int) t5; void test2() { t1.t v1; t2 v2; t3 v3; t4 v4; t5.t v5; int *p; p = &v1; p = &v2; p = &v3; p = &v4; p = &v5; } /**************************************/ debug = stdchar; debug(mychar) { alias byte mychar; } void test3() { debug(mychar) { mychar[] line=cast(mychar[])cast(char[])"It is a long line."; mychar[] delimiter=cast(mychar[])cast(string)"is"; } debug(stdchar) { string line="It is a long line."; string delimiter="is"; } debug(stdbyte) { byte[] line=cast(byte[])cast(string)"It is a long line."; byte[] delimiter=cast(byte[])cast(string)"is"; } debug(stdwchar) { wstring line="It is a long line."; wstring delimiter="is"; } int ptr=3; size_t dl=delimiter.length; size_t pl=ptr+dl; assert(line[ptr..pl]==delimiter[]); } /**************************************/ void test4() { byte* p; version(D_LP64) assert(p.sizeof == 8); else assert(p.sizeof == 4); } /**************************************/ class Foo6 { } void test6() { Foo6 foo = new Foo6(); with (foo) { int x; x = 4; } } /**************************************/ int i7 = 3; void test7() { switch (i7) { default: assert(0); case 3: int x; x = 4; } } /**************************************/ void test8() { string a = "a b c"; assert(a.length == 5); assert(a[1] == '\n'); } /**************************************/ struct Foo9 { char c; char bar() { return c; } } Foo9 makeFoo() { Foo9 f; return f; } void callFoo (Foo9 a) { a.bar(); } void test9() { callFoo(makeFoo ()); } /**************************************/ struct Foo10 { } Foo10 makeFoo10() { Foo10 f; return f; } void callFoo (Foo10 a) { } void test10() { callFoo(makeFoo10()); } /**************************************/ struct Color { int x; } Color[3] colors; Color eval(float x, float y) { colors[1].x = 7; return colors[1]; } void test11() { Color c; c = eval(1.0, 2.0); assert(c.x == 7); } /**************************************/ struct Size12 { int width; int height; } int x12; void foo12(out Size12 sz) { sz.width = 2; if(sz.width == 2) x12 = 1; } void test12() { Size12 sz; foo12(sz); assert(x12 == 1); assert(sz.width == 2); } /**************************************/ interface D13 { void setHostFrame(); } class A13 : D13 { void setHostFrame() { } char group; } void setLayout(D13 lo) { printf("lo = %p\n", lo); lo.setHostFrame(); printf("ok\n"); } void test13() { A13 a = new A13(); printf("a = %p\n", a); setLayout(a); } /**************************************/ void test14() { while(false) { static int a; } } /**************************************/ alias void delegate(int) t_func; class Foo15 { t_func func1; int x; void dothis() { if (func1) func1(4); else x = 3; } void func(int num) { x = num; } } void test15() { Foo15 a = new Foo15; a.dothis(); assert(a.x == 3); a.func1 = &a.func; a.dothis(); assert(a.x == 4); } /**************************************/ int[] foo16(byte[] a) { return cast(int[])a; } void test16() { byte[12] b; int[] i; i = foo16(b); assert(i.length == 3); } /**************************************/ void test17() { { float x = 10; x %= 4; printf("x = %g\n", x); assert(x == 2); x = 10; x = x % 4; printf("x = %g\n", x); assert(x == 2); x = 4; x = 10 % x; printf("x = %g\n", x); assert(x == 2); } { double y = 10; y %= 4; printf("y = %g\n", y); assert(y == 2); y = 10; y = y % 4; printf("y = %g\n", y); assert(y == 2); y = 4; y = 10 % y; printf("y = %g\n", y); assert(y == 2); } { real z = 10; z %= 4; printf("z = %Lg\n", z); assert(z == 2); z = 10; z = z % 4; printf("z = %Lg\n", z); assert(z == 2); z = 4; z = 10 % z; printf("z = %Lg\n", z); assert(z == 2); } } /**************************************/ struct Bar18 { } struct Foo18 { static Bar18 x = { }; } void test18() { const Bar18 b = Foo18.x; } /**************************************/ int x19 = 10; void test19() { bool b; b = cast(bool)x19; assert(b == true); } /**************************************/ class A20 { int abc() { return 3; } alias abc def; } void test20() { int i; A20 a = new A20(); i = a.def(); assert(i == 3); } /**************************************/ void test21() { string s; s = 1 ? "a" : "b"; assert(s == "a"); } /**************************************/ class Foo22 { } class Bar22 : Foo22 { } class Abc22 { Foo22 test() { return null; } } class Def22 : Abc22 { override Bar22 test() { return new Bar22; } } void testx22(Abc22 a) { assert(a.test() !is null); } void test22() { Def22 d = new Def22(); testx22(d); } /**************************************/ struct foo23 { static struct bar { int x; } } void test23() { //printf ("%d\n", foo23.bar.sizeof); assert(foo23.bar.sizeof == int.sizeof); } /**************************************/ void test24() { struct Test { int i; bool bar(int a) { i = a; return true; } } Test t; assert(t.bar(3)); } /**************************************/ void test25() { { const int [] list = [ 1, 2 ]; assert(list[0] == 1); assert(list[1] == 2); } { const int [] list = [ 3, 4 ]; assert(list[0] == 3); assert(list[1] == 4); } } /**************************************/ void test26() { while (0) { int x; } while (0) { int x; } } /**************************************/ struct NODE27 { int data; shared(NODE27) *next; } static shared NODE27 nodetbl[3] = [ { 0,cast(shared(NODE27)*)nodetbl + 1}, { 0,cast(shared(NODE27)*)nodetbl + 2}, { 0,null} ]; static shared NODE27 nodetbl2[3] = [ { 0,&nodetbl2[1]}, { 0,&nodetbl2[2]}, { 0,null} ]; void test27() { } /**************************************/ class Foo28 { protected int x; static class Bar { Foo28 f; int method () { return f.x; } } } void test28() { } /**************************************/ void test29() { int[immutable(byte)[]] foo; static immutable(byte)[] bar = [ 65, 66, 67 ]; foo[bar] = 1; assert(foo[bar] == 1); } /**************************************/ class A30 { static class Child { } } class B30 { static class Child { static int value = 6; } } void test30() { printf ("%d\n", B30.Child.value); assert(B30.Child.value == 6); } /**************************************/ void test31() { float b; b -= 1.0; b += 1.0; } /**************************************/ class Foo32 { struct Bar { int x; } } void test32() { with (new Foo32) { Bar z; z.x = 5; } } /**************************************/ string[2][] foo33; void test33() { string[2] bar; bar[1] = "hello"; foo33 ~= bar; assert(foo33[0][1] == "hello"); } /**************************************/ void test34() { try { int i = 0; printf( "i:%d\n", i ); } finally { printf( "Done\n" ); } try { int i = 1; printf( "i:%d\n", i ); } finally { printf( "Done\n" ); } } /**************************************/ class Bar35 {} template Foo35( T ) { void func() { }; } void test35() { try { alias Foo35!( Bar35 ) filter; } catch (Exception e) { printf( "Exception %.*s", e.msg.length, e.msg.ptr ); } finally { printf( "Done0." ); } } /**************************************/ void test36() { enum {A=1} enum {B=A?0:1} assert(A == 1); assert(B == 0); } /**************************************/ struct A37 { int a; } struct B37 { int a; int b; } struct C37 { int a; int b; int c; } struct D37 { byte a,b,c; } void test37() { A37 a; B37 b; C37 c; D37 d; assert(a.a == 0); assert(b.a == 0 && b.b == 0); assert(c.a == 0 && c.b == 0 && c.c == 0); assert(d.a == 0 && d.b == 0 && d.c == 0); } /**************************************/ int function() fp18; extern(Windows) int func18() { static int otherfunc() { return 18; } fp18 = &otherfunc; return fp18(); } void test38() { assert(func18() == 18); } /**************************************/ class bar39 { struct _sub { bool a; string d; }; _sub mySub; }; class foo39 { bar39._sub[] subArray; this(bar39[] arr) { for(int i=0; i= 1); assert(0 <> 1); assert(!(0 !<>= 1)); assert(!(0 !<> 1)); assert(!(0 !<= 1)); assert(!(0 !< 1)); assert(0 !>= 1); assert(0 !> 1); } /**************************************/ struct Bar48 { uint k; ubyte m; } Bar48 makebar48() { Bar48 b; return b; } void test48() { Bar48 b = makebar48(); } /**************************************/ void testx49() { printf("testx49()\n"); } void test49() { return testx49(); } /**************************************/ int testx50() { printf("testx50()\n"); return 3; } void test50() { return cast(void)testx50(); } /**************************************/ class A51 { static typeof(this) foo() { return new A51(); } this() { bar = 3; } int bar; } class B51 : A51 { static typeof(super) b; } struct C51 { typeof(&this) x; } void test51() { A51 a = A51.foo(); assert(a.bar == 3); B51.b = a; assert(B51.b.bar == 3); assert(B51.b.classinfo == A51.classinfo); C51 c; c.x = &c; } /**************************************/ class A52 { char get() { return 'A'; } char foo() { return typeof(this).get(); } char bar() { return A52.get(); } } class B52 : A52 { override char get() { return 'B'; } } void test52() { B52 b = new B52(); assert(b.foo() == 'A'); assert(b.bar() == 'A'); assert(b.get() == 'B'); } /**************************************/ struct A53 { int b() { return 1; } } int x53() { A53 a; return a.b; } void test53() { assert(x53() == 1); } /**************************************/ class A54 { void a() { printf("A54.a\n"); } void b() { typeof(this).a(); } } class B54 : A54 { override void a() { printf("B54.a\n"); assert(0); } } void test54() { B54 b = new B54(); b.b(); } /**************************************/ int foo55(int x = 5) { printf("x = %d\n", x); return x; } void test55() { int i; i = foo55(6); assert(i == 6); i = foo55(); assert(i == 5); } /**************************************/ class A56 { int foo(int x = 5) { printf("A56.x = %d\n", x); return x; } } class B56 : A56 { override int foo(int x = 7) { printf("B56.x = %d\n", x); return x; } } void test56() { int i; B56 b = new B56(); i = b.foo(6); assert(i == 6); i = b.foo(); assert(i == 7); } /**************************************/ void test57() { char c; wchar w; dchar d; printf("c = %x, w = %x, d = %x\n", c, w, d); assert(c == 0xFF); assert(w == 0xFFFF); assert(d == 0xFFFF); } /**************************************/ void test58() { static int x; static class S { static this() { printf ("static constructor\n"); x = 10; } this() { printf ("class constructor\n"); } } assert(x == 10); new S; } /**************************************/ struct S61 { int a, b, c, d; } void rec(int n, S61 t) { if (n > 0) { t.b++; rec(n-1,t); } } void test61() { S61 F; rec(100, F); } /**************************************/ class A62 { static A62 test(int q=0) { return null; } } A62 foo62() { return A62.test; } void test62() { foo62(); } /**************************************/ class A63 { private import std.file; alias std.file.getcwd getcwd; } void test63() { A63 f = new A63(); auto s = f.getcwd(); printf("%.*s\n", s.length, s.ptr); } /**************************************/ debug = 3; void test64() { debug(5) { assert(0); } debug(3) { int x = 3; } assert(x == 3); } /**************************************/ version = 3; void test65() { version(5) { assert(0); } version(3) { int x = 3; } assert(x == 3); } /**************************************/ // 8809 void test8809() { static class B { char foo() { return 'B'; } } static class C : B { char test1Bx() { return B.foo(); } char test1Cx() { return C.foo(); } char test1Dx() { return foo(); } char test1By() { return this.B.foo(); } char test1Cy() { return this.C.foo(); } // cannot compile -> OK char test1Dy() { return this. foo(); } char test1Bz() { return typeof(super).foo(); } char test1Cz() { return typeof(this). foo(); } //char test1Dz(); char test2Bx() { return { return B.foo(); }(); } char test2Cx() { return { return C.foo(); }(); } char test2Dx() { return { return foo(); }(); } char test2By() { return { return this.B.foo(); }(); } char test2Cy() { return { return this.C.foo(); }(); } // cannot compile -> OK char test2Dy() { return { return this. foo(); }(); } char test2Bz() { return { return typeof(super).foo(); }(); } char test2Cz() { return { return typeof(this). foo(); }(); } //char test2Dz(); char test3Bx() { return (new class Object { char bar() { return B.foo(); } }).bar(); } char test3Cx() { return (new class Object { char bar() { return C.foo(); } }).bar(); } char test3Dx() { return (new class Object { char bar() { return foo(); } }).bar(); } override char foo() { return 'C'; } } static class D : C { override char foo() { return 'D'; } } C c = new D(); assert(c.test1Bx() == 'B'); assert(c.test1Cx() == 'C'); assert(c.test1Dx() == 'D'); assert(c.test1By() == 'B'); assert(c.test1Cy() == 'C'); assert(c.test1Dy() == 'D'); assert(c.test1Bz() == 'B'); // NG('D') -> OK assert(c.test1Cz() == 'C'); //assert(c.test1Dz() == 'D'); assert(c.test2Bx() == 'B'); // NG('D') -> OK assert(c.test2Cx() == 'C'); // NG('D') -> OK assert(c.test2Dx() == 'D'); assert(c.test2By() == 'B'); assert(c.test2Cy() == 'C'); assert(c.test2Dy() == 'D'); assert(c.test2Bz() == 'B'); // NG('D') -> OK assert(c.test2Cz() == 'C'); // NG('D') -> OK //assert(c.test2Dz() == 'D'); assert(c.test3Bx() == 'B'); // NG('D') -> OK assert(c.test3Cx() == 'C'); // NG('D') -> OK assert(c.test3Dx() == 'D'); } /**************************************/ // 9734 void test9734() { class C {} class D : C { static bool test(C) { return true; } void foo()() if (is(typeof(test(super)))) {} void bar()() if (is(typeof(super) == C)) {} } void baz()() if (is(typeof(super))) {} auto d = new D(); d.foo(); d.bar(); static assert(!__traits(compiles, baz())); } /**************************************/ int main(string[] argv) { test1(); test2(); test3(); test4(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test50(); test51(); test52(); test53(); test54(); test55(); test56(); test57(); test58(); test61(); test62(); test63(); test64(); test65(); test8809(); test9734(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/a17.d0000664000175000017500000000035712776215022020746 0ustar kaikai// EXTRA_SOURCES: imports/a17a.d module a17; import std.stdio; private import imports.a17a; class barx { this() { printf("barx\n"); } } int main() { foo2x f = new foo2x(); // f = new foo2x(); // f.x++; return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link14074a.d0000664000175000017500000000034612776215022022052 0ustar kaikai// EXTRA_SOURCES: imports/link14074y.d import imports.link14074x; import imports.link14074y; struct Inner { } struct Test { Inner inner; } void main() { ubyte[] buffer; Test test; encodeArray(buffer, test); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testsocket.d0000664000175000017500000000111212776215022022534 0ustar kaikai// PERMUTE_ARGS: import std.stdio; import std.socket; class Connection { private { Socket sock; } void connect (string host, ushort port) { sock.connect (new InternetAddress (host, port)); } void poll () { SocketSet rset = new SocketSet (1); /** XXX: here is the bug */ rset.reset (); rset.add (sock); } this () { sock = new TcpSocket; sock.blocking = false; } } int main () { try { Connection ns; ns = new Connection (); ns.connect ("localhost", 80); ns.poll (); delete ns; } catch(SocketException e) { } return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testconstsection.d0000664000175000017500000000237012776215022023766 0ustar kaikai string tls_var = "tls_string"; __gshared string data_var = "data_string"; __gshared string bss_var; struct Range { const(void)* bot; const(void)* top; // consider inclusive void addPtr(const(void)* p) { if (!bot || p < bot) bot = p; if (!top || p > top) top = p; } bool intersect(Range other) { return (bot <= other.top && top >= other.bot); } } void testStrings() { // check that the strings don't overlap with the variables Range tls; Range data; Range bss; Range cdata; static string local_tls_var = "tls_string"; static __gshared string local_data_var = "data_string"; static __gshared string local_bss_var; tls.addPtr(&tls_var); tls.addPtr(&local_tls_var); data.addPtr(&data_var); data.addPtr(&local_data_var); bss.addPtr(&bss_var); bss.addPtr(&local_bss_var); cdata.addPtr(tls_var.ptr); cdata.addPtr(local_tls_var.ptr); cdata.addPtr(data_var.ptr); cdata.addPtr(local_data_var.ptr); assert(!cdata.intersect(tls), "overlap with tls"); assert(!cdata.intersect(data), "overlap with data"); assert(!cdata.intersect(bss), "overlap with bss"); } void main() { testStrings(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link14425.d0000664000175000017500000000027512776215022021712 0ustar kaikaistruct SFoo(I) { I i; } struct SBar(I) { I i; } static assert(is(SFoo!(SBar!string))); class CFoo(I) { I i; } class CBar(I) { I i; } static assert(is(CFoo!(CBar!string))); void main() {} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/arrayop.d0000664000175000017500000004750512776215022022041 0ustar kaikaiimport std.math; extern(C) int printf(const char*, ...); string abc; template Floating(T) { T[3] a; T[3] b; T[3] c; T[] A() { printf("A\n"); abc ~= "A"; return a; } T[] B() { printf("B\n"); abc ~= "B"; return b; } T[] C() { printf("C\n"); abc ~= "C"; return c; } T D() { printf("D\n"); abc ~= "D"; return 4; } void testx() { a = [11, 22, 33]; b = [1, 2, 3]; c = [4, 5, 6]; abc = null; A()[] = B()[] + C()[]; assert(abc == "BCA"); assert(a[0] == 5); assert(a[1] == 7); assert(a[2] == 9); abc = null; A()[] = B()[] + 4; assert(abc == "BA"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); abc = null; A()[] = 4 + B()[]; assert(abc == "BA"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); abc = null; A()[] = D() + B()[]; assert(abc == "DBA"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); a = [11, 22, 33]; abc = null; A()[] += B()[]; assert(abc == "BA"); assert(a[0] == 12); assert(a[1] == 24); assert(a[2] == 36); a = [11, 22, 33]; A()[] += 4; assert(a[0] == 15); assert(a[1] == 26); assert(a[2] == 37); a = [11, 22, 33]; A()[] -= 4; assert(a[0] == 7); assert(a[1] == 18); assert(a[2] == 29); a = [11, 22, 33]; A()[] *= 4; assert(a[0] == 44); assert(a[1] == 88); assert(a[2] == 132); a = [4, 8, 32]; A()[] /= 4; assert(a[0] == 1); assert(a[1] == 2); assert(a[2] == 8); a = [4, 8, 33]; A()[] %= 4; assert(a[0] == 0); assert(a[1] == 0); assert(a[2] == 1); a = [11, 22, 33]; abc = null; A()[] += 4 + B()[]; assert(abc == "BA"); assert(a[0] == 16); assert(a[1] == 28); assert(a[2] == 40); abc = null; A()[] = B()[] - C()[]; assert(abc == "BCA"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == -3); assert(a[1] == -3); assert(a[2] == -3); abc = null; A()[] = -B()[] - C()[]; assert(abc == "BCA"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == -5); assert(a[1] == -7); assert(a[2] == -9); abc = null; A()[] = B()[] + C()[] * 4; assert(abc == "BCA"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == 17); assert(a[1] == 22); assert(a[2] == 27); abc = null; A()[] = B()[] + C()[] * B()[]; assert(abc == "BCBA"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == 5); assert(a[1] == 12); assert(a[2] == 21); abc = null; A()[] = B()[] + C()[] / 2; assert(abc == "BCA"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == 3); assert(a[1] == 4.5); assert(a[2] == 6); abc = null; A()[] = B()[] + C()[] % 2; assert(abc == "BCA"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == 1); assert(a[1] == 3); assert(a[2] == 3); } } mixin Floating!(float) Ffloat; mixin Floating!(double) Fdouble; mixin Floating!(real) Freal; void test1() { Ffloat.testx(); Fdouble.testx(); Freal.testx(); } /************************************************************************/ template Integral(T) { T[3] a; T[3] b; T[3] c; T[] A() { printf("A\n"); abc ~= "A"; return a; } T[] B() { printf("B\n"); abc ~= "B"; return b; } T[] C() { printf("C\n"); abc ~= "C"; return c; } T D() { printf("D\n"); abc ~= "D"; return 4; } void testx() { a = [11, 22, 33]; b = [1, 2, 3]; c = [4, 5, 6]; abc = null; A()[] = B()[] + C()[]; assert(abc == "BCA"); assert(a[0] == 5); assert(a[1] == 7); assert(a[2] == 9); abc = null; A()[] = B()[] + 4; assert(abc == "BA"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); abc = null; A()[] = 4 + B()[]; assert(abc == "BA"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); abc = null; A()[] = D() + B()[]; assert(abc == "DBA"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); a = [11, 22, 33]; abc = null; A()[] += B()[]; assert(abc == "BA"); assert(a[0] == 12); assert(a[1] == 24); assert(a[2] == 36); a = [11, 22, 33]; A()[] += 4; assert(a[0] == 15); assert(a[1] == 26); assert(a[2] == 37); a = [11, 22, 33]; A()[] -= 4; assert(a[0] == 7); assert(a[1] == 18); assert(a[2] == 29); a = [11, 22, 27]; A()[] *= 4; assert(a[0] == 44); assert(a[1] == 88); assert(a[2] == 108); a = [11, 22, 33]; A()[] /= 4; assert(a[0] == 2); assert(a[1] == 5); assert(a[2] == 8); a = [11, 22, 33]; A()[] %= 4; assert(a[0] == 3); assert(a[1] == 2); assert(a[2] == 1); a = [1, 2, 7]; A()[] &= 4; assert(a[0] == 0); assert(a[1] == 0); assert(a[2] == 4); a = [1, 2, 7]; A()[] |= 4; assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); a = [1, 2, 7]; A()[] ^= 4; assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 3); a = [11, 22, 33]; abc = null; A()[] += 4 + B()[]; assert(abc == "BA"); assert(a[0] == 16); assert(a[1] == 28); assert(a[2] == 40); abc = null; A()[] = B()[] - C()[]; assert(abc == "BCA"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == -3); assert(a[1] == -3); assert(a[2] == -3); abc = null; A()[] = -B()[] - C()[]; assert(abc == "BCA"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == -5); assert(a[1] == -7); assert(a[2] == -9); abc = null; A()[] = B()[] + C()[] * 4; assert(abc == "BCA"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == 17); assert(a[1] == 22); assert(a[2] == 27); abc = null; A()[] = B()[] + C()[] * B()[]; assert(abc == "BCBA"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == 5); assert(a[1] == 12); assert(a[2] == 21); abc = null; A()[] = B()[] + C()[] / 2; assert(abc == "BCA"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == 3); assert(a[1] == 4); assert(a[2] == 6); abc = null; A()[] = B()[] + C()[] % 2; assert(abc == "BCA"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == 1); assert(a[1] == 3); assert(a[2] == 3); abc = null; A()[] = ~B()[]; assert(abc == "BA"); assert(a[0] == ~cast(T)1); assert(a[1] == ~cast(T)2); assert(a[2] == ~cast(T)3); abc = null; A()[] = B()[] & 2; assert(abc == "BA"); assert(a[0] == 0); assert(a[1] == 2); assert(a[2] == 2); abc = null; A()[] = B()[] | 2; assert(abc == "BA"); assert(a[0] == 3); assert(a[1] == 2); assert(a[2] == 3); abc = null; A()[] = B()[] ^ 2; assert(abc == "BA"); assert(a[0] == 3); assert(a[1] == 0); assert(a[2] == 1); } } /************************************************************************/ mixin Integral!(byte) Fbyte; mixin Integral!(short) Fshort; mixin Integral!(int) Fint; mixin Integral!(long) Flong; void test2() { Fbyte.testx(); Fshort.testx(); Fint.testx(); Flong.testx(); } /************************************************************************/ void test3() { auto a = new double[10], b = a.dup, c = a.dup, d = a.dup; a[] = -(b[] * (c[] + 4)) + 5 * d[] / 3.0; } /************************************************************************/ void test4() { int[] a, b; if (a && b) {} } /***************************************************/ void test4662() { immutable double[] nums = [1.0, 2.0]; static assert(!is(typeof({ nums[] += nums[]; }))); static assert(!is(typeof({ nums[] -= nums[]; }))); static assert(!is(typeof({ nums[] /= nums[]; }))); static assert(!is(typeof({ nums[] += 4; }))); static assert(!is(typeof({ nums[] /= 7; }))); } /***************************************************/ // 5284 void bug5284_1() { class C { int v; } C [] mda; immutable(C)[] ida; static assert(!__traits(compiles, (mda[] = ida[]))); C [1] msa; immutable(C)[1] isa; static assert(!__traits(compiles, (msa[] = isa[]))); C m; immutable(C) i; static assert(!__traits(compiles, m = i)); } void bug5284_2a() { struct S { int v; } S [] mda; immutable(S)[] ida; mda[] = ida[]; S [1] msa; immutable(S)[1] isa; msa[] = isa[]; S m = S(); immutable(S) i = immutable(S)(); m = i; } void bug5284_2b() { struct S { int v; int[] arr; } S [] mda; immutable(S)[] ida; static assert(!__traits(compiles, (mda[] = ida[]))); S [1] msa; immutable(S)[1] isa; static assert(!__traits(compiles, (msa[] = isa[]))); S m; immutable(S) i; static assert(!__traits(compiles, m = i)); } void bug5284_3() { int [] ma; immutable(int)[] ia; ma[] = ia[]; int m; immutable(int) i; m = i; } void test5() { bug5284_1(); bug5284_2a(); bug5284_2b(); bug5284_3(); } /************************************************************************/ void test6() { int[10] a = [1,2,3,4,5,6,7,8,9,10]; int[10] b; b = a[] ^^ 2; assert(b[0] == 1); assert(b[1] == 4); assert(b[2] == 9); assert(b[3] == 16); assert(b[4] == 25); assert(b[5] == 36); assert(b[6] == 49); assert(b[7] == 64); assert(b[8] == 81); assert(b[9] == 100); int[10] c = 3; b = a[] ^^ c[]; assert(b[0] == 1); assert(b[1] == 8); assert(b[2] == 27); assert(b[3] == 64); assert(b[4] == 125); assert(b[5] == 216); assert(b[6] == 343); assert(b[7] == 512); assert(b[8] == 729); assert(b[9] == 1000); } /************************************************************************/ void test8390() { const int[] a = new int[5]; int[] b = new int[5]; b[] += a[]; } /************************************************************************/ // 8651 void test8651() { void test(T)() @safe pure nothrow { T[3] a = [11, 22, 33]; T[3] b = [1, 2, 3]; T[3] c = [4, 5, 6]; T d = 4; // Arithmetic array ops { a[] = b[] + c[]; a[] = b[] + 4; a[] = 4 + b[]; a[] = d + b[]; a[] += b[]; a[] += 4; a[] -= 4; a[] *= 4; a[] /= 4; a[] %= 4; a[] += 4 + b[]; a[] = b[] - c[]; a[] = -b[] - c[]; a[] = b[] + c[] * 4; a[] = b[] + c[] * b[]; a[] = b[] + c[] / 2; a[] = b[] + c[] % 2; } // Bitwise array ops static if (is(typeof(T.init & T.init))) { a[] &= 4; a[] |= 4; a[] ^= 4; a[] = ~b[]; a[] = b[] & 2; a[] = b[] | 2; a[] = b[] ^ 2; } } test!float(); test!double(); test!real(); test!byte(); test!short(); test!int(); test!long(); } /************************************************************************/ // 9656 void test9656() { static class C {} static struct S { immutable int[] narr1; immutable int[] narr2; immutable C[] carr1; immutable C[] carr2; this(int n) { narr1 = new int[](3); // OK, expected narr2 = [1,2,3].dup; // NG -> OK carr1 = [new C].dup; // NG -> OK C c = new C; static assert(!__traits(compiles, carr2 = [c])); } } { int[] ma = [1,2,3]; immutable ia = ma.dup; } { static struct V { int val; } V[] ma = [V(1), V(2)]; immutable ia = ma.dup; } { static struct R { int* ptr; } R[] ma = [R(new int), R(null)]; static assert(!__traits(compiles, { immutable ia = rarr.dup; })); } { C[] ma = [new C(), new C()]; static assert(!__traits(compiles, { immutable ia = carr.dup; })); } } /************************************************************************/ // 10282 void test10282() { int[3] a1 = [1, 3, 6]; int[3] a2 = [1, 3, 6] * 3; // OK const int[3] a3 = a1[] * 3; // OK <- Error const int[3] a4 = [1, 3, 6] * 3; // OK <- Error immutable int[3] a5 = [1, 3, 6] * 3; // OK <- Error } /************************************************************************/ // 10433 void test10433() { void foo(T)(in int[] v1, in T v2) { int[2] r; r[] = v1[] + v2[]; } immutable int[] v = [10, 20]; foo(v, v); } /************************************************************************/ // 10684 void test10684a() { int[] a = [0, 0]; a[] += [10, 20][]; } void test10684b() { int[] a = [1, 2, 3]; int[] b = [4, 5, 6]; // Allow array literal as the operand of array oeration a[] += [1, 2, 3]; assert(a == [2, 4, 6]); a[] *= b[] + [1, 1, 1]; assert(a == [2*(4+1), 4*(5+1), 6*(6+1)]); a[] = [9, 8, 7] - [1, 2, 3]; assert(a == [8, 6, 4]); a[] = [2, 4, 6] / 2; assert(a == [1,2,3]); // Disallow: [1,2,3] is not an lvalue static assert(!__traits(compiles, { [1,2,3] = a[] * 2; })); static assert(!__traits(compiles, { [1,2,3] += a[] * b[]; })); } /************************************************************************/ // 11376 template TL11376(T...) { alias TL11376 = T; } auto sumArrs11376(T0, T1)(T0[] a, T1[] b) { a[] += b[]; //no ICE without this line return a; } static assert(!__traits(compiles, sumArrs11376(TL11376!(string[], string).init))); /************************************************************************/ // 11525 void test11525() { static struct Complex(T) { T re, im; ref opOpAssign(string op : "*")(Complex z) { auto temp = re*z.re - im*z.im; im = im*z.re + re*z.im; re = temp; return this; } } auto a = [Complex!double(2, 2)]; assert(a.length == 1 && a[0].re == 2 && a[0].im == 2); a[] *= a[]; assert(a.length == 1 && a[0].re == 0 && a[0].im == 8); } /************************************************************************/ // 12250 void f12250(inout int[] p, inout int[] q, int[] r) { r[] = p[] + q[]; assert(r == [5,7,9]); r[] -= p[] - q[]; assert(r == [8,10,12]); } void test12250() { immutable int[3] x = [1,2,3], y = [4,5,6]; int[3] z; f12250(x[], y[], z[]); } /************************************************************************/ // 12179 void test12179() { void foo(int[]) {} int[1] a; foo(a[] = a[]); foo(a[] += a[]); foo(a[] -= a[]); foo(a[] *= a[]); foo(a[] /= a[]); foo(a[] %= a[]); foo(a[] ^= a[]); foo(a[] &= a[]); foo(a[] |= a[]); foo(a[] ^^= a[]); // from issue 11992 int[] arr1; int[][] arr2; arr1 ~= (a[] = [1] + a[]); // OK arr2 ~= (a[] = [1] + a[]); // OK } /************************************************************************/ // 12780 void test12780() { int ival = 2; int[] iarr = [1, 2, 3]; double dval = 2.0; double[] darr = [4, 5, 6]; double[] oarr = [0, 0, 0]; // multiply array operations oarr[] = dval * iarr[]; assert(oarr == [dval * iarr[0], dval * iarr[1], dval * iarr[2]]); oarr[] = iarr[] / dval; assert(oarr == [iarr[0] / dval, iarr[1] / dval, iarr[2] / dval]); oarr[] = dval * (ival + iarr[]); assert(oarr == [dval * (ival + iarr[0]), dval * (ival + iarr[1]), dval * (ival + iarr[2])]); oarr[] = (iarr[] & ival) / dval; assert(oarr == [(iarr[0] & ival) / dval, (iarr[1] & ival) / dval, (iarr[2] & ival) / dval]); oarr[] = darr[] + iarr[]; assert(oarr == [darr[0] + iarr[0], darr[1] + iarr[1], darr[2] + iarr[2]]); oarr[] = iarr[] - darr[]; assert(oarr == [iarr[0] - darr[0], iarr[1] - darr[1], iarr[2] - darr[2]]); oarr[] = darr[] * (ival & iarr[]); assert(oarr == [darr[0] * (ival & iarr[0]), darr[1] * (ival & iarr[1]), darr[2] * (ival & iarr[2])]); oarr[] = (iarr[] ^ ival) / darr[]; assert(oarr == [(iarr[0] ^ ival) / darr[0], (iarr[1] ^ ival) / darr[1], (iarr[2] ^ ival) / darr[2]]); } /************************************************************************/ // 13497 void test13497() { int[1] a = [2], b = [3]; int[1] c1 = a[] * b[]; int[1] c2 = (a[] * b[])[]; assert(c1 == [6]); assert(c2 == [6]); } /************************************************************************/ // 14649 void test14649() { char[] a = "abc".dup; char[] b = [char(1), char(2), char(3)]; string x = "abc"; string y = [char(1), char(2), char(3)]; char[] r = new char[](3); r[] = a[] + b[]; assert(r == "bdf"); r[] = x[] + y[]; assert(r == "bdf"); r[] = "hel"[] + "lo."[]; assert(r == [('h'+'l'), ('e'+'o'), ('l'+'.')]); enum s = "abc"; r[] = s[0..3] + "def"[0..3]; assert(r == [('a'+'d'), ('b'+'e'), ('c'+'f')]); } /************************************************************************/ // 14851 void test14851() { int[8] a, b, c; c = a[] | b[]; // OK <- NG from 2.068.0-b2 c = a[] ^ b[]; // OK <- NG from 2.068.0-b2 c[] = a[] | b[]; // OK c[] = a[] ^ b[]; // OK } /************************************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test8390(); test8651(); test9656(); test10282(); test10433(); test10684a(); test10684b(); test11525(); test12250(); test12780(); test13497(); test14649(); test14851(); printf("Success\n"); return 0; } version (none) { extern (C) T[] _arraySliceSliceAddSliceAssignd(T[] a, T[] c, T[] b) { foreach (i; 0 .. a.length) a[i] = b[i] + c[i]; return a; } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testscope2.d0000664000175000017500000000725312776215022022453 0ustar kaikai// REQUIRED_ARGS: -dip25 import core.stdc.stdio; /********************************************/ struct SS { ref int foo1(return ref int delegate() return p) return; ref int foo2(return ref int delegate() p); ref int foo3(inout ref int* p); ref int foo4(return inout ref int* p); } pragma(msg, "foo1 ", typeof(&SS.foo1)); pragma(msg, "foo2 ", typeof(&SS.foo2)); pragma(msg, "foo3 ", typeof(&SS.foo3)); pragma(msg, "foo4 ", typeof(&SS.foo4)); void test3() { version (all) { import std.stdio; writeln(SS.foo1.mangleof); writeln(SS.foo2.mangleof); writeln(SS.foo3.mangleof); writeln(SS.foo4.mangleof); writeln(typeof(SS.foo1).stringof); writeln(typeof(SS.foo2).stringof); writeln(typeof(SS.foo3).stringof); writeln(typeof(SS.foo4).stringof); } version (all) { // Test scope mangling assert(SS.foo1.mangleof == "_D10testscope22SS4foo1MFNcNjNkKDFNjZiZi"); assert(SS.foo2.mangleof == "_D10testscope22SS4foo2MFNcNkKDFZiZi"); assert(SS.foo3.mangleof == "_D10testscope22SS4foo3MFNcNkKNgPiZi"); assert(SS.foo4.mangleof == "_D10testscope22SS4foo4MFNcNkKNgPiZi"); // Test scope pretty-printing assert(typeof(SS.foo1).stringof == "ref return int(return ref int delegate() return p)"); assert(typeof(SS.foo2).stringof == "ref int(return ref int delegate() p)"); assert(typeof(SS.foo3).stringof == "ref int(return ref inout(int*) p)"); assert(typeof(SS.foo4).stringof == "ref int(return ref inout(int*) p)"); } } /********************************************/ ref int foo(return ref int x) { return x; } struct S { int x; ref S bar() return { return this; } } ref T foo2(T)(ref T x) { return x; } void test4() { int x; foo2(x); } /********************************************/ ref int foo(return ref int x, ref int y) { return x; } ref int bar() { int x; static int y = 7; return foo(y, x); } void test5() { int x = bar(); assert(x == 7); } /********************************************/ struct S6 { int x = 8; ref int bar() return { return x; } } void test6() { S6 s; int b = s.bar(); assert(b == 8); } /********************************************/ class C { int x; ref int foo(return ref int x) { return x; } ref int bar() return { return x; } } class D : C { override ref int foo(ref int x) { static int y; return y; } override ref int bar() { static int y; return y; } } void test7() { } /********************************************/ struct S8(T) { int x; ref int bar() // infer 'return' { return x; } } ref int test8a(return ref S8!int s) { return s.bar(); } void test8() { } /********************************************/ char[] foo9(return out char[4] buf) { return buf[0 .. 1]; } /********************************************/ struct S10 { int x; ref inout(int) foo() inout { return x; } } /********************************************/ struct RC { this(this) { } } struct S11 { @disable this(this); void remove() { _ptr[0] = _ptr[1]; } RC* _ptr; } void test11() { S11 ary; } /********************************************/ int[10] a12; int* foo12() { foreach (ref x; a12) return &x; return null; } /********************************************/ struct FullCaseEntry { dchar[3] seq; ubyte n, size;// n number in batch, size - size of batch ubyte entry_len; @property auto value() const @trusted pure nothrow @nogc return { return seq[0..entry_len]; } } /********************************************/ void main() { test3(); test4(); test5(); test6(); test7(); test8(); test11(); printf("Success\n"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testappend.d0000664000175000017500000000167012776215022022524 0ustar kaikai// PERMUTE_ARGS: import core.stdc.stdio; import core.stdc.math : isnan; void test12826() { string s, t; t = t ~ "1234567"; s = s ~ "1234567"; s ~= s; assert(s == "12345671234567", s); assert(t == "1234567", t); } int main() { int[] a; for (int i = 0; i < 1000; i++) { a.length = a.length + 100; } foreach (v; a) { assert(v == 0); } float[] b; for (int i = 0; i < 2000; i++) { b.length = b.length + 100; } foreach (v; b) { assert(isnan(v)); } delete a; delete b; a = null; for (int i = 0; i < 100000; i++) { a ~= i; } foreach (k, v; a) { assert(v == k); } b = null; for (int i = 0; i < 200000; i++) { b ~= i; } foreach (k, v; b) { assert(v == k); } delete a; delete b; test12826(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testbounds2.d0000664000175000017500000002605012776215022022630 0ustar kaikai// REQUIRED_ARGS: // Test compile time boundaries checking extern(C) int printf(const char*, ...); template TypeTuple(T...) { alias T TypeTuple; } /******************************************/ // 3652 void test3652() { int foo(int[4] x) { return x[0] + x[1] * x[2] - x[3]; } int[] xs = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; // simple case foo(xs[0 .. 4]); version(none) { // Need deformation of formula and detection of base point int x = 0; int y = 0; foreach (i; 0 .. 4) { x += foo(xs[i .. i + 4]); y += foo(xs[(i*4+10)/2 .. (i*8>>1)/2+9]); // lwr = (i*4 + 10)/2 = i*4/2 + 10/2 = (i*2+5) // upr = (i*8>>1)/2 + 5 = (i*4/2) + 5 = i*2 + 9 = (i*2+5) + 4 } assert(x == (0,1,2,3) + (1,2,3, 4) + (2, 3, 4, 5) + ( 3, 4, 5, 6)); assert(y == (5,6,7,8) + (7,8,9,10) + (9,10,11,12) + (11,12,13,14)); } } void test3652a() @safe { string str = "aaaabbbbccccdddd"; //printf("str.ptr = %p\n", str.ptr); void foo(ref const(char)[16] buf) { //printf("buf.ptr = %p\n", buf.ptr); assert(buf.ptr is str.ptr); } // can check length at runtime assert(str.length == 16); // compiler can check the length of string literal, so // conversion from immutable(char)[] to ref const(char)[16] is allowed; static assert(__traits(compiles, foo("aaaabbbbccccdddd"))); // OK, correctly rejected by the compiler. static assert(!__traits(compiles, foo(str[]))); // Ugly, furthermore does not work in safe code! //foo(*cast(const(char)[16]*)(str[0..16].ptr)); // New: compiler can check the length of slice, but currently it is not allowed. enum size_t m = 0; size_t calc(){ return 0; } foo(str[0 .. 16]); foo(str[m .. 16]); //foo(str[calc() .. 16]); // with CTFE // If boundaries cannot be calculated in compile time, it's rejected. size_t n; size_t calc2(){ return n; } static assert(!__traits(compiles, foo(str[n .. 16]))); static assert(!__traits(compiles, foo(str[calc2() .. 16]))); void hoo1(size_t dim)(char[dim]) { static assert(dim == 2); } void hoo2(char[2]) {} void hoo3(size_t dim)(ref char[dim]) {} void hoo4(ref char[2]) {} hoo1(str[0 .. 2]); hoo2(str[0 .. 2]); static assert(!__traits(compiles, hoo3(str[0 .. 2]))); static assert(!__traits(compiles, hoo4(str[0 .. 2]))); } void test3652b() @safe { int[] da = [1,2,3,4,5]; void bar(int[3] sa1, ref int[3] sa2) { assert(sa1 == [1,2,3] && sa1.ptr !is da.ptr); assert(sa2 == [1,2,3] && sa2.ptr is da.ptr); } bar(da[0..3], da[0..3]); static assert(!__traits(compiles, bar(da[0..4], da[0..4]))); void baz1(T)(T[3] sa1, ref T[3] sa2) { assert(sa1 == [1,2,3] && sa1.ptr !is da.ptr); assert(sa2 == [1,2,3] && sa2.ptr is da.ptr); } void baz2(T, size_t dim)(T[dim] sa1, ref T[dim] sa2, size_t result) { assert(dim == result); static if (dim == 3) { assert(sa1 == [1,2,3] && sa1.ptr !is da.ptr); assert(sa2 == [1,2,3] && sa2.ptr is da.ptr); } else { assert(sa1 == [1,2,3,4] && sa1.ptr !is da.ptr); assert(sa2 == [1,2,3,4] && sa2.ptr is da.ptr); } } baz1(da[0..3], da[0..3]); static assert(!__traits(compiles, baz1(da[0..4], da[0..4]))); baz2(da[0..3], da[0..3], 3); baz2(da[0..4], da[0..4], 4); void hoo1(size_t dim)(int[dim]) { static assert(dim == 2); } void hoo2(int[2]) {} void hoo3(size_t dim)(ref int[dim]) {} void hoo4(ref int[2]) {} hoo1(da.idup[0 .. 2]); hoo2(da.idup[0 .. 2]); static assert(!__traits(compiles, hoo3(da.idup[0 .. 2]))); static assert(!__traits(compiles, hoo4(da.idup[0 .. 2]))); } /**********************************/ // 9654 auto foo9654a(ref char[8] str) { return str; } auto foo9654b(ref const char[8] str) { return str; } auto foo9654c(ref immutable char[8] str) { return str; } static assert(!is(typeof(foo9654a("testinfo")))); static assert( is(typeof(foo9654b("testinfo")) == const char[8])); static assert( is(typeof(foo9654c("testinfo")) == immutable char[8])); auto bar9654a(T)(ref T[8] str) { return str; static assert(is(T == immutable char)); } auto bar9654b(T)(ref const T[8] str) { return str; static assert(is(T == char)); } auto bar9654c(T)(ref immutable T[8] str) { return str; static assert(is(T == char)); } static assert( is(typeof(bar9654a("testinfo")) == immutable char[8])); static assert( is(typeof(bar9654b("testinfo")) == const char[8])); static assert( is(typeof(bar9654c("testinfo")) == immutable char[8])); auto baz9654a(T, size_t dim)(ref T[dim] str) { return str; static assert(is(T == immutable char)); } auto baz9654b(T, size_t dim)(ref const T[dim] str) { return str; static assert(is(T == char)); } auto baz9654c(T, size_t dim)(ref immutable T[dim] str) { return str; static assert(is(T == char)); } static assert( is(typeof(baz9654a("testinfo")) == immutable char[8])); static assert( is(typeof(baz9654b("testinfo")) == const char[8])); static assert( is(typeof(baz9654c("testinfo")) == immutable char[8])); /******************************************/ // 9712 auto func9712(T)(T[2] arg) { return arg; } static assert(is(typeof(func9712([1,2])) == int[2])); auto deduceLength9712(T,size_t n)(T[n] a) { return a; } static assert(is(typeof(deduceLength9712([1,2,3])) == int[3])); /******************************************/ // 9743 void test9743() { // +-Char // |+-Immutable or Const or Mutable // ||+-Value or Ref // |||+-Function or +-Template void fCIVF( immutable char[4]) {} void fCIVT()( immutable char[4]) {} void fCCVF( const char[4]) {} void fCCVT()( const char[4]) {} void fCMVF( char[4]) {} void fCMVT()( char[4]) {} void fCIRF(ref immutable char[4]) {} void fCIRT()(ref immutable char[4]) {} void fCCRF(ref const char[4]) {} void fCCRT()(ref const char[4]) {} void fCMRF(ref char[4]) {} void fCMRT()(ref char[4]) {} alias fcOK = TypeTuple!(fCIVF, fCIVT, fCCVF, fCCVT, fCMVF, fCMVT, fCIRF, fCIRT, fCCRF, fCCRT); foreach (f; fcOK) f("1234" ) ; foreach (f; fcOK) f("1234"c) ; foreach (f; fcOK) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fcOK) static assert(!__traits(compiles, f("1234"d) )); alias fcNG = TypeTuple!(fCMRF, fCMRT); // cannot hold immutable data by mutable ref foreach (f; fcNG) static assert(!__traits(compiles, f("1234" ) )); foreach (f; fcNG) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fcNG) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fcNG) static assert(!__traits(compiles, f("1234"d) )); // +-Wchar void fWIVF( immutable wchar[4]) {} void fWIVT()( immutable wchar[4]) {} void fWCVF( const wchar[4]) {} void fWCVT()( const wchar[4]) {} void fWMVF( wchar[4]) {} void fWMVT()( wchar[4]) {} void fWIRF(ref immutable wchar[4]) {} void fWIRT()(ref immutable wchar[4]) {} void fWCRF(ref const wchar[4]) {} void fWCRT()(ref const wchar[4]) {} void fWMRF(ref wchar[4]) {} void fWMRT()(ref wchar[4]) {} alias fwOK = TypeTuple!(fWIVF, fWIVT, fWCVF, fWCVT, fWMVF, fWMVT, fWIRF, fWIRT, fWCRF, fWCRT); foreach (f; fwOK) f("1234" ) ; foreach (f; fwOK) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fwOK) f("1234"w) ; foreach (f; fwOK) static assert(!__traits(compiles, f("1234"d) )); alias fwNG = TypeTuple!(fWMRF, fWMRT); // cannot hold immutable data by mutable ref foreach (f; fwNG) static assert(!__traits(compiles, f("1234" ) )); foreach (f; fwNG) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fwNG) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fwNG) static assert(!__traits(compiles, f("1234"d) )); // +-Dchar void fDIVF( immutable dchar[4]) {} void fDIVT()( immutable dchar[4]) {} void fDCVF( const dchar[4]) {} void fDCVT()( const dchar[4]) {} void fDMVF( dchar[4]) {} void fDMVT()( dchar[4]) {} void fDIRF(ref immutable dchar[4]) {} void fDIRT()(ref immutable dchar[4]) {} void fDCRF(ref const dchar[4]) {} void fDCRT()(ref const dchar[4]) {} void fDMRF(ref dchar[4]) {} void fDMRT()(ref dchar[4]) {} alias fdOK = TypeTuple!(fDIVF, fDIVT, fDCVF, fDCVT, fDMVF, fDMVT, fDIRF, fDIRT, fDCRF, fDCRT); foreach (f; fdOK) f("1234" ) ; foreach (f; fdOK) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fdOK) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fdOK) f("1234"d) ; alias fdNG = TypeTuple!(fDMRF, fDMRT); // cannot hold immutable data by mutable ref foreach (f; fdNG) static assert(!__traits(compiles, f("1234" ) )); foreach (f; fdNG) static assert(!__traits(compiles, f("1234"c) )); foreach (f; fdNG) static assert(!__traits(compiles, f("1234"w) )); foreach (f; fdNG) static assert(!__traits(compiles, f("1234"d) )); } /******************************************/ // 9747 void foo9747A(T)(T[4]) {} void foo9747C(size_t dim)(char[dim]) {} void foo9747W(size_t dim)(wchar[dim]) {} void foo9747D(size_t dim)(dchar[dim]) {} void test9747() { foo9747A("abcd"c); foo9747A("abcd"w); foo9747A("abcd"d); foo9747C("abcd"c); foo9747W("abcd"w); foo9747D("abcd"d); } /******************************************/ // 12876 void test12876() { void foo(int[4] b) {} void bar(size_t n)(int[n] c) { static assert(n == 4); } int[5] a; foo(a[1 .. $]); // OK bar(a[1 .. $]); // OK <- Error } /******************************************/ // 13775 void test13775() { ubyte[4] ubytes = [1,2,3,4]; // CT-known slicing (issue 3652) auto ok1 = cast(ubyte[2]) ubytes[0 .. 2]; assert(ok1 == [1, 2]); // CT-known slicing with implicit conversion of SliceExp::e1 (issue 13154) enum double[] arr = [1.0, 2.0, 3.0]; auto ok2 = cast(float[2]) [1.0, 2.0, 3.0][0..2]; auto ok3 = cast(float[2]) arr[1..3]; // currently this is accepted assert(ok2 == [1f, 2f]); assert(ok3 == [2f, 3f]); // CT-known slicing with type coercing (issue 13775) auto ok4 = cast( byte[2]) ubytes[0 .. 2]; // CT-known slicing + type coercing auto ok5 = cast(short[1]) ubytes[0 .. 2]; // CT-known slicing + type coercing assert(ok4 == [1, 2]); version(LittleEndian) assert(ok5 == [0x0201]); version( BigEndian) assert(ok5 == [0x0102]); } /******************************************/ int main() { test3652(); test3652a(); test3652b(); test9743(); test9747(); test13775(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/a18.d0000664000175000017500000000034712776215022020746 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/a18a.d // PERMUTE_ARGS: import imports.a18a; extern(C) int printf(const char*, ...); alias IContainer!(int) icontainer_t; int main() { printf("Test enumerator\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_119.d0000664000175000017500000000101412776215022023043 0ustar kaikaialias ubyte[2] buf; buf initUsingValue() { buf x = 0; return x; } buf initDefault() { return buf.init; } // can just as easily replace buf for typeof(return) buf initUsingValue2() { buf x = 42; return x; } buf initUsingLiteral() { return [ 4, 8 ]; } void main() { buf x = initUsingValue(); assert(x[0] == 0 && x[1] == 0); x = initDefault(); assert(x[0] == 0 && x[1] == 0); x = initUsingValue2(); assert(x[0] == 42 && x[1] == 42); x = initUsingLiteral(); assert(x[0] == 4 && x[1] == 8); }ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_340.d0000664000175000017500000000057212776215022023047 0ustar kaikaiversion(D_InlineAsm_X86_64) version = DMD_InlineAsm; version(D_InlineAsm_X86) version = DMD_InlineAsm; version(InlineAsm) { void fooNormal()() { asm { jmp Llabel; Llabel: nop; } } void fooNaked()() { asm { naked; jmp Llabel; Llabel: ret; } } void main() { fooNormal(); fooNaked(); } } else { void main() {} } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/printargs.d0000664000175000017500000000050412776215022022361 0ustar kaikai// PERMUTE_ARGS: // EXECUTE_ARGS: A B C extern(C) int printf(const char*, ...); int main(char args[][]) { int i; for (i = 0; i < args.length; i++) printf("args[%d] = '%.*s'\n", i, args[i].length, args[i].ptr); assert(args[1] == "A"); assert(args[2] == "B"); assert(args[3] == "C"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test11239.d0000664000175000017500000000023412776215022021727 0ustar kaikai// EXTRA_SOURCES: imports/inc11239.d // REQUIRED_ARGS: -debug // COMPILE_SEPARATELY // PERMUTE_ARGS: import imports.inc11239; void main() { foo(1); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test13944.d0000664000175000017500000000233412776215022021737 0ustar kaikai// PERMUTE_ARGS: module m; struct S {} enum E { a } void f() {} void main() { string ssc = S.stringof; assert(ssc == "S"c); wstring ssw = S.stringof; assert(ssw == "S"w); dstring ssd = S.stringof; assert(ssd == "S"d); string esc = E.stringof; assert(esc == "E"c); wstring esw = E.stringof; assert(esw == "E"w); dstring esd = E.stringof; assert(esd == "E"d); string msc = m.stringof; assert(msc == "module m"c); wstring msw = m.stringof; assert(msw == "module m"w); dstring msd = m.stringof; assert(msd == "module m"d); string smc = S.mangleof; assert(smc == "S1m1S"c); wstring smw = S.mangleof; assert(smw == "S1m1S"w); dstring smd = S.mangleof; assert(smd == "S1m1S"d); string fmc = f.mangleof; assert(fmc == "_D1m1fFZv"c); wstring fmw = f.mangleof; assert(fmw == "_D1m1fFZv"w); dstring fmd = f.mangleof; assert(fmd == "_D1m1fFZv"d); // The default type is still string static assert(is(typeof(S.stringof) == string)); static assert(is(typeof(E.stringof) == string)); static assert(is(typeof(m.stringof) == string)); static assert(is(typeof(S.mangleof) == string)); static assert(is(typeof(f.mangleof) == string)); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/gdb15729.sh0000775000175000017500000000140012776215022021702 0ustar kaikai#!/usr/bin/env bash src=runnable${SEP}extra-files dir=${RESULTS_DIR}${SEP}runnable output_file=${dir}/gdb15729.sh.out if [ $OS == "win32" -o $OS == "win64" ]; then LIBEXT=.lib else LIBEXT=.a fi libname=${dir}${SEP}lib15729${LIBEXT} $DMD -g -m${MODEL} -I${src} -of${libname} -lib ${src}${SEP}lib15729.d || exit 1 $DMD -g -m${MODEL} -I${src} -of${dir}${SEP}gdb15729${EXE} ${src}${SEP}gdb15729.d ${libname} || exit 1 if [ $OS == "linux" ]; then cat > ${dir}${SEP}gdb15729.gdb <<-EOF b lib15729.d:16 r echo RESULT= p s.val EOF gdb ${dir}${SEP}gdb15729 --batch -x ${dir}${SEP}gdb15729.gdb | grep 'RESULT=.*1234' || exit 1 fi rm -f ${libname} ${dir}${SEP}{gdb15729${OBJ},gdb15729${EXE},gdb15729.gdb} echo Success >${output_file} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/gdb10311.d0000664000175000017500000000031412776215022021471 0ustar kaikai/* REQUIRED_ARGS: -g PERMUTE_ARGS: GDB_SCRIPT: --- b 19 r echo RESULT= p x --- GDB_MATCH: RESULT=.*33 */ void call(void delegate() dg) { dg(); } void main() { int x=32; call({++x;}); // BP } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/template2962.d0000664000175000017500000000066012776215022022511 0ustar kaikai// EXTRA_SOURCES: imports/template2962a.d // comment 29 void foo(T)(T p) { void inner(U)() { auto p2 = p; } inner!int(); } // comment 20 void funcD(alias x)() { assert(x==1.0); } void funcC(T)(double a){ // Case 1: ICE(glue.c) funcD!(a)(); // Case 2: wrong code double b = 1.0; funcD!(b)(); } void bug2962comment36()(int p) { int inner()() { return p; } alias inner!() finner; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/cabi1.d0000664000175000017500000000735312776215022021340 0ustar kaikai // EXTRA_CPP_SOURCES: cabi2.cpp import core.stdc.stdio; import core.stdc.config; struct Foo1 { char c; } struct Foo2 { short s; } struct Foo3 { char c; short s; } struct Foo4 { int i; } struct Foo5 { int i, j; } struct Foo6 { int i, j, k; } struct S7 { float a, b; } extern (C) Foo1 ctest1(); extern (C) Foo2 ctest2(); extern (C) Foo3 ctest3(); extern (C) Foo4 ctest4(); extern (C) Foo5 ctest5(); extern (C) Foo6 ctest6(); extern (C) S7 ctest10(); version(Windows) version = Windows_or_32bit; else version(X86) version = Windows_or_32bit; void test1() { Foo1 f1 = ctest1(); assert(f1.c == 3); Foo2 f2 = ctest2(); assert(f2.s == 0x1234); Foo3 f3 = ctest3(); assert(f3.s == 0x5678); Foo4 f4 = ctest4(); assert(f4.i == 0x12345678); Foo5 f5 = ctest5(); assert(f5.i == 0x12345678); assert(f5.j == 0x21436587); version(Windows_or_32bit) { Foo6 f6 = ctest6(); assert(f6.i == 0x12345678); assert(f6.j == 0x21463587); assert(f6.k == 0x24163857); } S7 s7 = ctest10(); assert(s7.a == 2.5); assert(s7.b == 1.5); } /*******************************************/ extern (C) { char ctest7(char); ubyte ctest8(ubyte); byte ctest9(byte); } void test2() { assert(ctest7('a') == 'b'); assert(ctest8(7) == 8); assert(ctest9(3) == 4); } /******************************************/ extern (C) { void ctestrir(int x1, int x2, int x3, int x4, int x5, int x6, c_long_double a, int b, c_long_double c); } void test3() { ctestrir(1,2,3,4,5,6, c_long_double(100.0), 67, c_long_double(200.0)); } /******************************************/ extern (C) void dtestrir(int x1, int x2, int x3, int x4, int x5, int x6, c_long_double a, int b, c_long_double c) { assert(a == 300.0); assert(b == 68); assert(c == 401.0); } extern (C) void test4(); /******************************************/ struct S11 { ubyte a, b, c; } extern (C) S11 ctest11(ubyte x, S11, ubyte y); void test11() { version (X86) { S11 t; assert(S11.sizeof == 3); t.a = 2; t.b = 3; t.c = 4; auto s = ctest11(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ struct S12 { char a,d; char b,e; ubyte c; } extern (C) S12 ctest12(ubyte x, S12, ubyte y); void test12() { version (X86) { S12 t; printf("D sz = %d\n", cast(int)S12.sizeof); // assert(S12.sizeof == 5); t.a = 2; t.b = 3; t.c = 4; auto s = ctest12(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ struct S13 { ushort a, b, c; } extern (C) S13 ctest13(ubyte x, S13, ubyte y); void test13() { version (X86) { S13 t; assert(S13.sizeof == 6); t.a = 2; t.b = 3; t.c = 4; auto s = ctest13(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ struct S14 { char a,d,e,f; char b,g; ubyte c; } extern (C) S14 ctest14(ubyte x, S14, ubyte y); void test14() { version (X86) { S14 t; assert(S14.sizeof == 7); t.a = 2; t.b = 3; t.c = 4; auto s = ctest14(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ struct S15 { char a,d,e,f; char b,g,h,i; ubyte c; } extern (C) S15 ctest15(ubyte x, S15, ubyte y); void test15() { version (X86) { S15 t; assert(S15.sizeof == 9); t.a = 2; t.b = 3; t.c = 4; auto s = ctest15(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ int main() { test1(); test2(); test3(); version (Win64) { } else { test4(); } test11(); test12(); test13(); test14(); test15(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ice15176.d0000664000175000017500000000021012776215022021506 0ustar kaikai// EXTRA_SOURCES: imports/ice15176a.d imports/ice15176b.d // COMPILE_SEPARATELY import imports.ice15176a; void main() { func(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/inline2.d0000664000175000017500000000033112776215022021706 0ustar kaikai// EXTRA_SOURCES: imports/inline2a.d // PERMUTE_ARGS: // REQUIRED_ARGS: -O -release -inline import imports.inline2a; class Foo { this () { Primes.lookup(2); } } int main() { Primes.lookup(2); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test23.d0000664000175000017500000005637712776215022021517 0ustar kaikai// REQUIRED_ARGS: module test; import core.vararg; import core.stdc.stdlib; import std.stdio; import std.string; import core.stdc.stdlib; version(D_InlineAsm_X86_64) version = DMD_InlineAsm; version(D_InlineAsm_X86) version = DMD_InlineAsm; /*******************************************/ struct S { int opSliceAssign(int v, size_t i, size_t j) { assert(v == 5); assert(i == 9); assert(j == 10); return 3; } int opSliceAssign(int v) { assert(v == 6); return 11; } } void test1() { S s; assert((s[9 .. 10] = 5) == 3); assert((s[] = 6) == 11); } /*******************************************/ static int i2 = 1; void test2() { synchronized { int i2 = 2; } assert(i2 == 1); } /*******************************************/ void test3() { size_t border = 8; for(ulong i = 0; i < border; i++) { ulong test = 1; test <<= i; double r = test; ulong result = cast(ulong)r; if (result != test) { assert(0); } } } /*******************************************/ void test4() { writeln("",true); } /*******************************************/ void test5() { int[] qwert = new int[6]; int[] yuiop; yuiop = qwert[2..5] = 3; assert(yuiop.length == 3); assert(yuiop[0] == 3); assert(yuiop[1] == 3); assert(yuiop[2] == 3); } /*******************************************/ struct Foo6 { static int x; static int[] farray() { printf("farray\n"); assert(x == 0); x++; return new int[6]; } static int flwr() { printf("flwr\n"); assert(x == 1); x++; return 2; } static int fupr() { printf("fupr\n"); assert(x == 2); x++; return 1; } } void test6() { int[] yuiop; yuiop = Foo6.farray()[Foo6.flwr() .. $ - Foo6.fupr()] = 3; assert(Foo6.x == 3); assert(yuiop.length == 3); assert(yuiop[0] == 3); assert(yuiop[1] == 3); assert(yuiop[2] == 3); } /*******************************************/ void test7() { real a = 3.40483; // this is treated as 3.40483L real b; b = 3.40483; assert(a==b); assert(a==3.40483); assert(a==3.40483L); assert(a==3.40483F); } /*******************************************/ void test8() { real [5][5] m = 1; m[1][1..3] = 2; for (size_t i = 0; i < 5; i++) for (size_t j = 0; j < 5; j++) { if (i == 1 && (j >= 1 && j < 3)) assert(m[i][j] == 2); else assert(m[i][j] == 1); } } /*******************************************/ class ClassOf(Type) { Type val; template refx() { alias val refx; } } struct StructOf { int val; template refx() { alias val refx; } } void test9() { ClassOf!(int) c = new ClassOf!(int)(); StructOf s; int x = 10; c.refx!() = x; x = c.refx!(); assert(x == 10); x = 11; s.refx!() = x; x = s.refx!(); assert(x == 11); } /*******************************************/ void test10() { static if( int.mangleof.length > 1 && int.mangleof[1] == 'x' ) printf("'x' as second char\n"); } /*******************************************/ class Foo11 : Bar11 { } class Foo11T(V) { public void foo() {} } class Bar11 { public this(){ f = new Foo11T!(int); } Foo11T!(int) f; } void test11() { Foo11 fooIt = new Foo11(); if (fooIt !is null) writefln("fooIt should be valid"); fooIt.f.foo(); writefln("it worked"); } /*******************************************/ struct A12 { int a; union { int c; B12 b; } } struct B12 { int b1; int b2; } void test12() { A12 a; printf("%d\n", A12.sizeof); assert(A12.sizeof == 12); } /*******************************************/ template declare13(X) { X declare13; } typeof(declare13!(int[0]).ptr[0]) x13; typeof(declare13!(typeof(""))[0..$]) y13; void test13() { } /*******************************************/ interface Father {} class Mother { Father test() { writefln("Called Mother.test!"); return new Child(42); } } class Child : Mother, Father { int data; this(int d) { data = d; } override Child test() { writefln("Called Child.test!"); return new Child(69); } } void test14() { Child aChild = new Child(105); Mother childsMum = aChild; Child childsChild = aChild.test(); Child mumsChild = cast(Child) childsMum.test(); writefln("Success2"); } /*******************************************/ class A15 { int a = 3; class B { void bar() { assert(a == 3); } } void fork() { assert(a == 3); B b = new B(); // This is okay b.bar(); void knife() { assert(a == 3); B b = new B(); // No 'this' for nested class B b.bar(); } } } void test15() { A15 a = new A15(); a.fork(); } /*******************************************/ creal x16; void foo16() { x16 = -x16; } void bar16() { return foo16(); } void test16() { x16 = 2.0L + 0.0Li; bar16(); assert(x16 == -2.0L + 0.0Li); } /*******************************************/ void test17() { version (OSX) { } else version (DMD_InlineAsm) { const f = 1.2f; float g = void; asm{ fld f; // doesn't work with PIC fstp g; } assert(g == 1.2f); } } /*******************************************/ class Foo18 : Bar18 {} class FooT18(V){} class Bar18 : FooT18!(int) {} void test18() { } /*******************************************/ struct STRUCTA19 { union { int a; long b; } STRUCTB19 c; } struct STRUCTB19 { int a; } void test19() { } /*******************************************/ class Foo20 { void bar (void * src) { void baz (void function (void *, size_t) xyz) { size_t foo (void [] dst) { size_t len = dst.length; dst [0 .. len] = src [0 .. len]; xyz (dst.ptr, len); return len; } } } } void test20() { } /*******************************************/ class Baz21 { int opApply (int delegate(ref int) dg) { int i; return dg(i); } } class Foo21 { Baz21 baz; int foo (int delegate() dg) { foreach (b; baz) if (bar ()) if (dg ()) break; return 0; } bool bar () { return true; } } void test21() { } /*******************************************/ struct Bar22 { union { struct { union { Foo22 A; } } } } struct Foo22 { double d = 3; } void test22() { printf("Bar22.sizeof = %zd, double.sizeof = %zd\n", Bar22.sizeof, double.sizeof); assert(Bar22.sizeof == double.sizeof); Bar22 b; assert(b.A.d == 3); } /*******************************************/ struct Ag { static void func(){} static void foo() { void function() fnp; Ag a; fnp = &func; fnp = &Ag.func; with(a) fnp = &Ag.func; with(a) fnp = &func; } } class Ah { static void func(){} static void foo() { void function() fnp; Ah a; fnp = &func; fnp = &Ah.func; with(a) fnp = &Ah.func; with(a) fnp = &func; } } void test23() { } /*******************************************/ void test24() { uint[10] arr1; ulong idx = 3; uint[] arr3 = arr1[ cast(int)(idx) .. (cast(int) idx) + 3 ]; // OK uint[] arr4 = arr1[ cast(int) idx .. cast(int) idx + 3 ]; // OK uint[] arr5 = arr1[ cast(int)(idx) .. cast(int)(idx) + 3 ]; // C style cast illegal, use cast(idx)+3 uint[] arr6 = arr1[ cast(int)(idx) .. cast(int)(idx + 3) ]; // OK } /*******************************************/ void test25() { char[6] cstr = "123456"c; auto str1 = cast(wchar[3])(cstr); writefln("str1: ", (cast(char[])str1).length , " : ", (cast(char[])str1)); assert(cast(char[])str1 == "123456"c); auto str2 = cast(wchar[3])("789abc"c); writefln("str2: ", (cast(char[])str2).length , " : ", (cast(char[])str2)); assert(cast(char[])str2 == "789abc"c); auto str3 = cast(wchar[3])("defghi"); writefln("str3: ", (cast(char[])str3).length , " : ", (cast(char[])str3)); assert(cast(char[])str3 == "d\000e\000f\000"c); } /*******************************************/ void test26() { assert(foo26(5) == 25); } int foo26(int i) { if (auto j = i * i) return j; else return 10; } /*******************************************/ class A27 { int am; class B { this() { assert(am == 3); } } void fork() { B b = new B(); // This is okay void knife() { B b = new B(); // No 'this' for nested class B assert(am == 3); } } } void test27() { A27 a = new A27(); a.am = 3; a.fork(); } /*******************************************/ uint intRes() { return 4; } void test28() { auto s = std.string.format("%s", "abc123"[intRes() % $] ); writefln( "%s", s ); assert(s == "2"); static const char[] foo = "abc123"; s = std.string.format("%s", foo[intRes() % $] ); assert(s == "2"); static string bar = "abc123"; s = std.string.format("%s", bar[intRes() % $] ); assert(s == "2"); const char[] abc = "abc123"; s = std.string.format("%s", abc[intRes() % $] ); assert(s == "2"); string def = "abc123"; s = std.string.format("%s", def[intRes() % $] ); assert(s == "2"); } /*******************************************/ class UA { A29 f() { return null; } } class UB : UA { override B29 f() { return null; } } class A29 { } class B29 : A29 { } void test29() { } /*******************************************/ class Foo30 : Bar30 {} class FooT30(V) {} class Bar30 : FooT30!(int) {} void test30() { } /*******************************************/ int y31; struct X31 { static void opCall() { y31 = 3; } } void test31() { X31 x; typeof(x)(); assert(y31 == 3); } /*******************************************/ class Foo32 { static void* ps; new (size_t sz) { void* p = core.stdc.stdlib.malloc(sz); printf("new(sz = %d) = %p\n", sz, p); ps = p; return p; } delete(void* p) { printf("delete(p = %p)\n", p); assert(p == ps); if (p) core.stdc.stdlib.free(p); } } void test32() { Foo32 f = new Foo32; delete f; } /*******************************************/ class Foo33 { // this() { printf("this()\n"); } // ~this() { printf("~this()\n"); } static void* ps; static int del; new (size_t sz, int i) { void* p = core.stdc.stdlib.malloc(sz); printf("new(sz = %d) = %p\n", sz, p); ps = p; return p; } delete(void* p) { printf("delete(p = %p)\n", p); assert(p == ps); if (p) core.stdc.stdlib.free(p); del += 1; } } void foo33() { scope Foo33 f = new(3) Foo33; } void test33() { foo33(); assert(Foo33.del == 1); } /*******************************************/ struct o_O { int a; } union O_O { int a; } class O_o { int a; } struct Foo34 { int ok; o_O foo; O_O bar; O_o baz; } void test34() { int o1 = Foo34.ok.offsetof; assert(o1 == 0); int o2 = Foo34.foo.offsetof; assert(o2 == 4); int o3 = Foo34.bar.offsetof; assert(o3 == 8); int o4 = Foo34.baz.offsetof; assert((o4 % (void*).sizeof) == 0); assert(o4 > o3); } /*******************************************/ class Foo37 { float[4] array = 1.0; int count = 10; } void test37() { Foo37 f = new Foo37(); writefln("Foo.array[0] = %s", f.array[0] ); writefln("Foo.array[1] = %s", f.array[1] ); writefln("Foo.array[2] = %s", f.array[2] ); writefln("Foo.array[3] = %s", f.array[3] ); writefln("Foo.count = %s", f.count ); assert(f.array[0] == 1.0); assert(f.array[1] == 1.0); assert(f.array[2] == 1.0); assert(f.array[3] == 1.0); assert(f.count == 10); } /*******************************************/ void test38() in { static void checkParameters() { return; } checkParameters(); } body { } /*******************************************/ void delegate() foo39() { return &(new class { int a; this() { a = 3; } void dg() { writefln("delegate!"); assert(a == 3); } }).dg; } void test39() { void delegate() dg = foo39(); dg(); } /*******************************************/ void test40() { assert( typeid(int) == typeid(int) ); assert( (typeid(int) != typeid(int)) == false ); int x; bool b1 = (typeid(typeof(x)) != typeid(int)); TypeInfo t1 = typeid(typeof(x)); TypeInfo t2 = typeid(int); bool b2 = (t1 != t2); assert(b1 == b2); } /*******************************************/ int foo41(string s) { short shift = cast(short)(s.length * 3); int answer; for (size_t i = 0; i < s.length; i++){ answer = s[i] << shift; } return answer; } void test41() { if(foo41("\u0001") != 8){ assert(0); } } /*******************************************/ struct S42 { int i; static S42 foo(int x){ S42 s; s.i = x; return s; } } void test42() { S42[] s; s = s ~ S42.foo(6); s = s ~ S42.foo(1); if(s.length != 2){ assert(0); } if(s[0].i != 6){ assert(0); } if(s[1].i != 1){ assert(0); } } /*******************************************/ struct S43 { int i,j; static S43 foo(int x){ S43 s; s.i = x; return s; } } void test43() { S43[] s; s = s ~ S43.foo(6); s = s ~ S43.foo(1); if(s.length != 2){ assert(0); } if(s[0].i != 6){ assert(0); } if(s[1].i != 1){ assert(0); } } /*******************************************/ struct S44 { int i,j,k; static S44 foo(int x){ S44 s; s.i = x; return s; } } void test44() { S44[] s; s = s ~ S44.foo(6); s = s ~ S44.foo(1); if(s.length != 2){ assert(0); } if(s[0].i != 6){ assert(0); } if(s[1].i != 1){ assert(0); } } /*******************************************/ void test45() { char[] buffer = "abcdefghijklmnopqrstuvwxyz".dup; foreach(ref char c; buffer) { if('a' <= c && c <= 'z') { c -= cast(char)'a' - 'A'; // segfault here } } for(int i = 0; i < buffer.length; i++) { if('a' <= buffer[i] && buffer[i] <= 'z') { buffer[i] -= cast(char)'a' - 'A'; // segfault here } } writeln(buffer); } /*******************************************/ struct st46 { template t1() { template t2(int n2) { } } } alias st46.t1!().t2 a46; void test46() { } /*******************************************/ struct A47 { static int y; void opSliceAssign(int x) { printf("x = %d\n", x); y = x; } A47 d() { return this; } } void test47() { A47 a; a[] = 3; printf("y = %d\n", a.y); a.d()[] = 5; printf("y = %d\n", a.y); assert(a.y == 5); a.d[] = 6; printf("y = %d\n", a.y); assert(a.y == 6); } /*******************************************/ static uint[] sarray48 = void; void test48() { static uint[] array = void; assert(sarray48 == null); assert(array == null); } /*******************************************/ int x = 2, y = 1; void foo50(int z) { static int t; t++; assert(t == z); } void test50() { printf("test50()\n"); int res = 0; for(int i = 0; i < 10; i++) { res = res + x - y; foo50(res); } } /*******************************************/ void test52() { printf("test52()\n"); char[] s; s = ['a', 'b', 'c']; assert(s == "abc"); int[] x; x = [17, 18u, 29, 33]; assert(x.length == 4); assert(x[0] == 17); assert(x[1] == 18); assert(x[2] == 29); assert(x[3] == 33); assert(x == [17, 18, 29, 33]); } /*******************************************/ void test54() { printf("test54()\n"); uint[500][] data; data.length = 1; assert(data.length == 1); foreach (ref foo; data) { assert(foo.length == 500); foreach (ref u; foo) { //printf("u = %u\n", u); assert(u == 0); u = 23; } } foreach (ref foo; data) { assert(foo.length == 500); foreach (u; foo) { assert(u == 23); auto v = u; v = 23; } } } /*******************************************/ class Base56 { private string myfoo; private string mybar; // Get/set properties that will be overridden. void foo(string s) { myfoo = s; } string foo() { return myfoo; } // Get/set properties that will not be overridden. void bar(string s) { mybar = s; } string bar() { return mybar; } } class Derived56: Base56 { alias Base56.foo foo; // Bring in Base56's foo getter. override void foo(string s) { super.foo = s; } // Override foo setter. } void test56() { Derived56 d = new Derived56; with (d) { foo = "hi"; d.foo = "hi"; bar = "hi"; assert(foo == "hi"); assert(d.foo == "hi"); assert(bar == "hi"); } } /*******************************************/ bool[void[]] reg57; void addToReg57(const(void)[] a, int b, bool v) { if (!v) writefln("X"); auto key = a~(cast(void*)&b)[0..4]; reg57[cast(immutable(void)[])key] = v; writefln("OK"); } void test57() { addToReg57("test", 1024, true); } /*******************************************/ int bar58( string msg ){ return 1; } int foo58( lazy string dg ){ return bar58( dg() ); } void test58() { printf("test58()\n"); try{ } finally{ foo58(""); } } /*******************************************/ struct S59 { string toString() { return "foo"; } } void test59() { S59 s; writefln("s = %s", s); string p; p = std.string.format("s = %s", s); assert(p == "s = foo"); } /*******************************************/ void test60() { int[2][] a; a = [ [-1,2], [3,4] ]; assert(a[0][0] == -1); assert(a[0][1] == 2); assert(a[1][0] == 3); assert(a[1][1] == 4); int[][] b; b = [ [-1,2], [3,4] ]; assert(b[0][0] == -1); assert(b[0][1] == 2); assert(b[1][0] == 3); assert(b[1][1] == 4); } /*******************************************/ void test61() { int[][] f = [[1,2],[3,4]]; assert(f[0][0] == 1); assert(f[0][1] == 2); assert(f[1][0] == 3); assert(f[1][1] == 4); writeln(f); } /*******************************************/ struct List62 { void get() {} } struct Array62 { interface Model { List62 list(); } List62 list() { return model ? model.list() : List62.init; } void item() { list.get(); } private Model model; } void test62() { } /*******************************************/ void foo63(...) { } void test63() { int[] arr; arr = [1] ~ 2; // runtime crash, the length == 1 printf("%d\n", arr.length); assert (arr.length == 2); assert(arr[0] == 1); assert(arr[1] == 2); arr = 2 ~ [1]; assert(arr.length == 2); assert(arr[0] == 2); assert(arr[1] == 1); arr = [2, 3] ~ [1]; assert(arr.length == 3); assert(arr[0] == 2); assert(arr[1] == 3); assert(arr[2] == 1); foo63([1] ~ 2, 2 ~ [1], [1,2] ~ [3,4,5]); } /*******************************************/ void test64() { printf("test64()\n"); int[] x = [1,2,3,4]; int j = 4; foreach_reverse(v; x) { writeln(v); assert(j == v); j--; } assert(j == 0); j = 4; foreach_reverse(i, v; x) { writefln("[%s] = %s", i, v); assert(i + 1 == j); assert(j == v); j--; } assert(j == 0); printf("-test64()\n"); } /*******************************************/ void test65() { // Bugzilla Issue 407. int i = *cast(int*)cast(char[4])['0', '0', '0', '0']; // compiler seg-fault printf("i = %x\n", i); } /*******************************************/ void test66() { int[] ia; ia ~= 3; byte[] data = new byte[ia[0]]; byte[] data2 = new byte[ cast(int)(ia[0])]; } /*******************************************/ class C68 { static int value; } void test68() { auto v1 = test.C68.value; auto v2 = C68.classinfo; auto v3 = test.C68.classinfo; assert(v2 == v3); } /*******************************************/ void test69() { class Bug { char[12] str = ""; uint t = 1; } class NoBug { uint t = 2; char[12] str = ""; } class NoBug2 { char[12] str; uint t = 3; } auto b = new Bug; auto n = new NoBug; auto n2 = new NoBug2; writefln("bug %d", b.t); assert(b.t == 1); writefln("nobug %d", n.t); assert(n.t == 2); writefln("nobug2 %d", n2.t); assert(n2.t == 3); } /*******************************************/ void test70() { void foo(char[0] p) { } static const char[0] altsep; string s = std.string.format("test%spath", altsep); assert(s == "testpath"); foo(altsep); } /*******************************************/ class C71 { static int cnt; this() { printf("C()\n"); cnt++; } ~this() { printf("~C()\n"); cnt--; } } class D71 { static int cnt; this() { printf("D()\n"); cnt++; } ~this() { printf("~D()\n"); cnt--; } } class E71 { static int cnt; this() { printf("E()\n"); cnt++; } ~this() { printf("~E()\n"); cnt--; } } void test71() { { int i = 0; printf("start\n"); scope D71 d = new D71(); assert(D71.cnt == 1); for (scope E71 e = new E71(); i < 5; i++) { assert(D71.cnt == 1); assert(E71.cnt == 1); scope c = new C71(); assert(C71.cnt == 1); } assert(C71.cnt == 0); assert(E71.cnt == 0); assert(D71.cnt == 1); printf("finish\n"); } assert(D71.cnt == 0); } /*******************************************/ size_t getLength(int[] arr) { return arr.length; } void test13237() { int[] arr = [0]; immutable size_t len = getLength(arr); arr.length--; assert(len == 1); // ok if (len) { auto l = len; } assert(len == 1); // len cannot be changed, but produces Assertion failure with "-O -inline" } /*******************************************/ void main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test50(); test52(); test54(); test56(); test57(); test58(); test59(); test60(); test61(); test62(); test63(); test64(); test65(); test66(); test68(); test69(); test70(); test71(); test13237(); printf("Success\n"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test11447b.d0000664000175000017500000000022112776215022022066 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/b11447.d // PERMUTE_ARGS: -allinst import imports.b11447; void main() { A a; aaa(a); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/hospital.d0000664000175000017500000001363512776215022022204 0ustar kaikai// REQUIRED_ARGS: // NOTE: the shootout appears to be BSD licensed content. // Including this in the test suite based on that license. /* The Great Computer Language Shootout http://shootout.alioth.debian.org/ Unoptimised reference implementation contributed by Isaac Gouy */ import std.stdio, std.string, std.conv; import core.memory; int main(string[] args) { //std.gc.setV1_0(); int n = args.length > 1 ? to!int(args[1]) : 1000; HealthcareRegion healthcareSystem = HealthcareRegion.Create(); for(int i = 0; i < n; i++) healthcareSystem.TransferPatients(); Totals t = healthcareSystem.AccumulateTotals(); writeln("Patients: ", t.patients ); writeln("Time: ", t.hospitalTime ); writeln("Visits: ", t.hospitalVisits ); if (n == 1000) { assert(t.patients == 102515); assert(t.hospitalTime == 33730654); assert(t.hospitalVisits == 106371); } return 0; } class HealthcareRegion { public: static HealthcareRegion Create() { return HealthcareRegion.Create(LEVELS, 0, 42); } static HealthcareRegion Create(int level, int seed1, int seed2) { HealthcareRegion r = null; if(level > 0) { r = new HealthcareRegion(level, seed1*seed2); for(ptrdiff_t i = r.districts.length-1; i >= 0; i--) r.districts[i] = Create(level-1, cast(int)((seed1*4)+i+1), seed2); } return r; } this(int level, int s) { districts = new HealthcareRegion[DISTRICTS]; localHospital = new Hospital(level == LEVELS, level, s); } private: enum int LEVELS = 5, DISTRICTS = 4; HealthcareRegion[] districts; Hospital localHospital; package: Patient[] TransferPatients() { for(ptrdiff_t i = districts.length-1; i >= 0; i--) if(districts[i]) foreach(Patient p; districts[i].TransferPatients().dup) localHospital.NewArrival(p); localHospital.TriageExaminationTreatment(); return localHospital.RegionalTransferPatients(); } Totals AccumulateTotals() { Totals t = new Totals(); for(ptrdiff_t i = districts.length-1; i >= 0; i--) if(districts[i]) t += districts[i].AccumulateTotals(); localHospital.AccumulateTotals(t); return t; } } class Hospital { public this(bool hasNoRegionalHospital, int level, int seed) { this.hasNoRegionalHospital = hasNoRegionalHospital; availableStaff = 1 << (level - 1); discharged = new Totals(); this.seed = seed; } package: void TriageExaminationTreatment() { DischargePatients(); TreatOrTransferPatients(); TriagePatients(); if(genRandom(1.0) > 0.7) { Patient p = new Patient(); NewArrival(p); } } Patient[] RegionalTransferPatients() { return transfers; } void AccumulateTotals(Totals t) { foreach(Patient p; triage) t.Plus(p); foreach(Patient p; examination) t.Plus(p); foreach(Patient p; treatment) t.Plus(p); t += discharged; } void NewArrival(Patient p) { p.hospitalVisits++; if(availableStaff > 0) { availableStaff--; examination ~= p; p.remainingTime = 3; p.hospitalTime += 3; } else { triage ~= p; } } private: Patient[] triage, examination, treatment, transfers; Totals discharged; int availableStaff; bool hasNoRegionalHospital; void DischargePatients() { for(ptrdiff_t i = treatment.length-1; i >= 0; i--) { Patient p = treatment[i]; p.remainingTime -= 1; if(!p.remainingTime) { availableStaff++; treatment = treatment[0..i] ~ treatment[i+1..$]; discharged.Plus(p); } } } void TreatOrTransferPatients() { delete transfers; for(ptrdiff_t i = examination.length-1; i >= 0; i--) { Patient p = examination[i]; p.remainingTime -= 1; if(!p.remainingTime) { // no transfer if(genRandom(1.0) > 0.1 || hasNoRegionalHospital) { examination = examination[0..i] ~ examination[i+1..$]; treatment ~= p; p.remainingTime = 10; p.hospitalTime += 10; } else { // transfer availableStaff++; examination = examination[0..i] ~ examination[i+1..$]; transfers ~= p; } } } } void TriagePatients() { for(ptrdiff_t i = triage.length-1; i >= 0; i--) { Patient p = triage[i]; if(availableStaff > 0) { availableStaff--; p.remainingTime = 3; p.hospitalTime += 3; triage = triage[0..i] ~ triage[i+1..$]; examination ~= p; } else { p.hospitalTime++; } } } int seed = 42; const int IM = 139968; const int IA = 3877; const int IC = 29573; double genRandom(double max) { return(max * (seed = (seed * IA + IC) % IM) / IM); } } class Patient { package int remainingTime, hospitalTime, hospitalVisits; } class Totals { public Totals opAddAssign(Totals b) { patients += b.patients; hospitalTime += b.hospitalTime; hospitalVisits += b.hospitalVisits; return this; } package: long patients, hospitalTime, hospitalVisits; void Plus(Patient p) { patients++; hospitalTime += p.hospitalTime; hospitalVisits += p.hospitalVisits; } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/lexer.d0000664000175000017500000000265712776215022021502 0ustar kaikai// REQUIRED_ARGS: /*********************************************************/ void test6() { string s = q"(foo(xxx))"; assert(s == "foo(xxx)"); s = q"[foo[xxx]]"; assert(s == "foo[xxx]"); s = q"{foo{xxx}}"; assert(s == "foo{xxx}"); s = q">"; assert(s == "foo"); s = q"[foo(]"; assert(s == "foo("); s = q"/foo]/"; assert(s == "foo]"); s = q"HERE foo HERE"; //writefln("'%s'", s); assert(s == "foo\n"); s = q{ foo(xxx) }; assert(s ==" foo(xxx) "); s = q{foo(}; assert(s == "foo("); s = q{{foo}/*}*/}; assert(s == "{foo}/*}*/"); s = q{{foo}"}"}; assert(s == "{foo}\"}\""); } /*********************************************************/ void test7() { // auto str = \xDB; // assert(str.length == 1); } /*********************************************************/ // 4633 template Types(alias v) { alias typeof(v) Types; } typeof({return 1;}()) a; // ok Types!({return 1;}()) x; // ok void test8() { typeof({return 1;}()) b; Types!({return 1;}()) y; } /*********************************************************/ // bug 6584 version(9223372036854775807){} debug(9223372036854775807){} /*********************************************************/ enum e13102=184467440737095516153.6L; /*********************************************************/ int main() { test6(); test7(); test8(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test42a.d0000664000175000017500000005350012776215022021642 0ustar kaikai// PERMUTE_ARGS: module test42; import core.stdc.stdio; /***************************************************/ void test1() { ubyte[] data2 = [ 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3, ]; foreach (i; data2) { //printf("i = %d\n", i); assert(i == 3); } ubyte[] data = [ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7]; foreach (i; data) { //printf("i = %d\n", i); assert(i == 7); } } /***************************************************/ int main() { test1(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link14074b.d0000664000175000017500000000010612776215022022045 0ustar kaikaiimport imports.link14074z; void main() { replaceAllWith!()(1); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test10573.d0000664000175000017500000000013712776215022021731 0ustar kaikai// EXTRA_SOURCES: imports/test10573a.d import imports.test10573a; void main(string[] args) {} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link14588.d0000664000175000017500000000026012776215022021716 0ustar kaikai// EXTRA_SOURCES: imports/link14588a.d // PERMUTE_ARGS: -allinst -unittest -debug -inline // COMPILE_SEPARATELY import imports.link14588a; void main() { new A().all(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/circular.d0000664000175000017500000000055012776215022022155 0ustar kaikai// REQUIRED_ARGS: -d // PERMUTE_ARGS: -dw // EXTRA_SOURCES: imports/circularA.d // This bug is typedef-specific. // Bugzilla 4543 import core.stdc.stdio; import imports.circularA; class bclass {}; alias bclass Tclass; struct bstruct {} alias bstruct Tstruct; /************************************/ int main() { printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link13400.d0000664000175000017500000000057512776215022021705 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/link13400a.d import imports.link13400a; void main() { BigInt r; // This comparison will instantiate BigInt.opEquals!().opEquals(const BigInt y) const pure again. // But here is non-speculative context, so this module compilation should generate its objcode. bool b = r == BigInt("2"); // comparison with rvalue } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test_shared.sh0000775000175000017500000000115712776215022023054 0ustar kaikai#!/usr/bin/env bash dir=${RESULTS_DIR}/runnable dmddir=${RESULTS_DIR}${SEP}runnable output_file=${dir}/test_shared.sh.out rm -f ${output_file} if [ ${OS} != "linux" ]; then echo "Skipping shared library test on ${OS}." touch ${output_file} exit 0 fi die() { cat ${output_file} rm -f ${output_file} exit 1 } $DMD -m${MODEL} -of${dmddir}${SEP}test_shared${EXE} -defaultlib=libphobos2.so runnable/extra-files/test_shared.d >> ${output_file} if [ $? -ne 0 ]; then die; fi LD_LIBRARY_PATH=../../phobos/generated/${OS}/release/${MODEL} ${dmddir}${SEP}test_shared${EXE} if [ $? -ne 0 ]; then die; fi ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/xtest46.d0000664000175000017500000045557012776215022021712 0ustar kaikaiimport std.stdio; import core.stdc.stdio; /******************************************/ struct S { int opStar() { return 7; } } void test1() { S s; printf("%d\n", *s); assert(*s == 7); } /******************************************/ void test2() { double[1][2] bar; bar[0][0] = 1.0; bar[1][0] = 2.0; foo2(bar); } void foo2(T...)(T args) { foreach (arg; args[0 .. $]) { //writeln(arg); bar2!(typeof(arg))(&arg); } } void bar2(D)(const(void)* arg) { D obj = *cast(D*) arg; } /***************************************************/ void test3() { version (unittest) { printf("unittest!\n"); } else { printf("no unittest!\n"); } version (assert) { printf("assert!\n"); } else { printf("no assert!\n"); } } /***************************************************/ void test4() { immutable int maxi = 8; int[][maxi] neighbors = [ cast(int[])[ ], [ 0 ], [ 0, 1], [ 0, 2], [1, 2], [1, 2, 3, 4], [ 2, 3, 5], [ 4, 5, 6 ] ]; int[maxi] grid; // neighbors[0].length = 0; void place(int k, uint mask) { if(k 1) { return T.length; } int foo36(T...)(T ts) if (T.length <= 1) { return T.length * 7; } void test36() { auto i = foo36!(int,int)(1, 2); assert(i == 2); i = foo36(1, 2, 3); assert(i == 3); i = foo36(1); assert(i == 7); i = foo36(); assert(i == 0); } /***************************************************/ void test6685() { struct S { int x; }; with({ return S(); }()) { x++; } } /***************************************************/ struct A37(alias T) { } void foo37(X)(X x) if (is(X Y == A37!(U), alias U)) { } void bar37() {} void test37() { A37!(bar37) a2; foo37(a2); foo37!(A37!bar37)(a2); } /***************************************************/ struct A38 { this(this) { printf("B's copy\n"); } bool empty() {return false;} void popFront() {} int front() { return 1; } // ref A38 opSlice() { return this; } } void test38() { A38 a; int i; foreach (e; a) { if (++i == 100) break; } } /***************************************************/ alias int function() Fun39; alias ref int function() Gun39; static assert(!is(Fun39 == Gun39)); void test39() { } /***************************************************/ int x40; struct Proxy { ref int at(int i)() { return x40; } } void test40() { Proxy p; auto x = p.at!(1); } /***************************************************/ template Foo41(TList...) { alias TList Foo41; } alias Foo41!(immutable(ubyte)[], ubyte[]) X41; void test41() { } /***************************************************/ bool endsWith(A1, A2)(A1 longer, A2 shorter) { static if (is(typeof(longer[0 .. 0] == shorter))) { } else { } return false; } void test42() { char[] a; byte[] b; endsWith(a, b); } /***************************************************/ void f43(S...)(S s) if (S.length > 3) { } void test43() { f43(1, 2, 3, 4); } /***************************************************/ struct S44(int x = 1){} void fun()(S44!(1) b) { } void test44() { S44!() s; fun(s); } /***************************************************/ // 2006 void test2006() { string [][] aas = []; assert(aas.length == 0); aas ~= cast (string []) []; assert(aas.length == 1); aas = aas ~ cast (string []) []; assert(aas.length == 2); } /***************************************************/ // 8442 void test8442() { enum int[] fooEnum = []; immutable fooImmutable = fooEnum; } /***************************************************/ class A45 { int x; int f() { printf("A\n"); return 1; } } class B45 : A45 { override const int f() { printf("B\n"); return 2; } } void test45() { A45 y = new B45; int i = y.f; assert(i == 2); } /***************************************************/ void text10682() { ulong x = 1; ulong y = 2 ^^ x; } /***************************************************/ struct Test46 { int foo; } void test46() { enum Test46 test = {}; enum q = test.foo; } /***************************************************/ pure int double_sqr(int x) { int y = x; void do_sqr() { y *= y; } do_sqr(); return y; } void test47() { assert(double_sqr(10) == 100); } /***************************************************/ void sort(alias less)(string[] r) { bool pred() { return less("a", "a"); } .sort!(less)(r); } void foo48() { int[string] freqs; string[] words; sort!((a, b) { return freqs[a] > freqs[b]; })(words); sort!((string a, string b) { return freqs[a] > freqs[b]; })(words); //sort!(bool (a, b) { return freqs[a] > freqs[b]; })(words); //sort!(function (a, b) { return freqs[a] > freqs[b]; })(words); //sort!(function bool(a, b) { return freqs[a] > freqs[b]; })(words); sort!(delegate bool(string a, string b) { return freqs[a] > freqs[b]; })(words); } void test48() { } /***************************************************/ // 6408 static assert(!is(typeof(string[0..1].init))); static assert(is(typeof(string[].init) == string[])); static assert(is(typeof(string[][].init) == string[][])); static assert(is(typeof(string[][][].init) == string[][][])); static assert(is(typeof(string[1].init) == string[1])); static assert(is(typeof(string[1][1].init) == string[1][1])); static assert(is(typeof(string[1][1][1].init) == string[1][1][1])); static assert(is(typeof(string[string].init) == string[string])); static assert(is(typeof(string[string][string].init) == string[string][string])); static assert(is(typeof(string[string][string][string].init) == string[string][string][string])); template TT6408(T...) { alias T TT6408; } static assert(is(typeof(TT6408!(int, int)[].init) == TT6408!(int, int))); static assert(is(typeof(TT6408!(int, int)[0..$].init) == TT6408!(int, int))); static assert(is(typeof(TT6408!(int, int)[$-1].init) == int)); /***************************************************/ // 9409 template TT9409(T...) { alias T TT9409; } template idxTypes9409(Prefix...) { TT9409!((Prefix[$-1])) idxTypes9409; } alias idxTypes9409!(int) Types9409; /***************************************************/ struct S49 { static void* p; this( string name ) { printf( "(ctor) &%.*s.x = %p\n", name.length, name.ptr, &x ); p = cast(void*)&x; } invariant() {} int x; } void test49() { auto s = new S49("s2"); printf( "&s2.x = %p\n", &s.x ); assert(cast(void*)&s.x == S49.p); } /***************************************************/ auto max50(Ts...)(Ts args) if (Ts.length >= 2 && is(typeof(Ts[0].init > Ts[1].init ? Ts[1].init : Ts[0].init))) { static if (Ts.length == 2) return args[1] > args[0] ? args[1] : args[0]; else return max50(max50(args[0], args[1]), args[2 .. $]); } void test50() { assert(max50(4, 5) == 5); assert(max50(2.2, 4.5) == 4.5); assert(max50("Little", "Big") == "Little"); assert(max50(4, 5.5) == 5.5); assert(max50(5.5, 4) == 5.5); } /***************************************************/ void test51() { static immutable int[2] array = [ 42 ]; enum e = array[1]; static immutable int[1] array2 = [ 0: 42 ]; enum e2 = array2[0]; assert(e == 0); assert(e2 == 42); } /***************************************************/ enum ubyte[4] a52 = [5,6,7,8]; void test52() { int x=3; assert(a52[x]==8); } /***************************************************/ void test53() { size_t func2(immutable(void)[] t) { return 0; } } /***************************************************/ void foo54(void delegate(void[]) dg) { } void test54() { void func(void[] t) pure { } foo54(&func); // void func2(const(void)[] t) { } // foo54(&func2); } /***************************************************/ class Foo55 { synchronized void noop1() { } void noop2() shared { } } void test55() { auto foo = new shared(Foo55); foo.noop1(); foo.noop2(); } /***************************************************/ enum float one56 = 1 * 1; template X56(float E) { int X56 = 2; } alias X56!(one56 * one56) Y56; void test56() { assert(Y56 == 2); } /***************************************************/ void test57() { alias shared(int) T; assert (is(T == shared)); } /***************************************************/ struct A58 { int a,b; } void test58() { A58[2] rg=[{1,2},{5,6}]; assert(rg[0].a == 1); assert(rg[0].b == 2); assert(rg[1].a == 5); assert(rg[1].b == 6); } /***************************************************/ class A59 { const foo(int i) { return i; } } /***************************************************/ void test60() { enum real ONE = 1.0; real x; for (x=0.0; x<10.0; x+=ONE) printf("%Lg\n", x); printf("%Lg\n", x); assert(x == 10); } /***************************************************/ pure immutable(T)[] fooPT(T)(immutable(T)[] x, immutable(T)[] y){ immutable(T)[] fooState; immutable(T)[] bar(immutable(T)[] x){ fooState = "hello "; return x ~ y; } return fooState ~ bar(x); } void test61() { writeln(fooPT("p", "c")); } /***************************************************/ void test9577() { static int function(int)[] foo = [x => x]; foo[0](0); } /***************************************************/ int[3] foo62(int[3] a) { a[1]++; return a; } void test62() { int[3] b; b[0] = 1; b[1] = 2; b[2] = 3; auto c = foo62(b); assert(b[0] == 1); assert(b[1] == 2); assert(b[2] == 3); assert(c[0] == 1); assert(c[1] == 3); assert(c[2] == 3); } /***************************************************/ void test3927() { int[] array; assert(array.length++ == 0); assert(array.length == 1); assert(array.length-- == 1); assert(array.length == 0); } /***************************************************/ void test63() { int[3] b; b[0] = 1; b[1] = 2; b[2] = 3; auto c = b; b[1]++; assert(b[0] == 1); assert(b[1] == 3); assert(b[2] == 3); assert(c[0] == 1); assert(c[1] == 2); assert(c[2] == 3); } /***************************************************/ void test64() { int[3] b; b[0] = 1; b[1] = 2; b[2] = 3; int[3] c; c = b; b[1]++; assert(b[0] == 1); assert(b[1] == 3); assert(b[2] == 3); assert(c[0] == 1); assert(c[1] == 2); assert(c[2] == 3); } /***************************************************/ int[2] foo65(int[2] a) { a[1]++; return a; } void test65() { int[2] b; b[0] = 1; b[1] = 2; int[2] c = foo65(b); assert(b[0] == 1); assert(b[1] == 2); assert(c[0] == 1); assert(c[1] == 3); } /***************************************************/ int[1] foo66(int[1] a) { a[0]++; return a; } void test66() { int[1] b; b[0] = 1; int[1] c = foo66(b); assert(b[0] == 1); assert(c[0] == 2); } /***************************************************/ int[2] foo67(out int[2] a) { a[0] = 5; a[1] = 6; return a; } void test67() { int[2] b; b[0] = 1; b[1] = 2; int[2] c = foo67(b); assert(b[0] == 5); assert(b[1] == 6); assert(c[0] == 5); assert(c[1] == 6); } /***************************************************/ void test68() { digestToString(cast(ubyte[16])x"c3fcd3d76192e4007dfb496cca67e13b"); } void digestToString(const ubyte[16] digest) { assert(digest[0] == 0xc3); assert(digest[15] == 0x3b); } /***************************************************/ void test69() { digestToString69(cast(ubyte[16])x"c3fcd3d76192e4007dfb496cca67e13b"); } void digestToString69(ref const ubyte[16] digest) { assert(digest[0] == 0xc3); assert(digest[15] == 0x3b); } /***************************************************/ void test70() { digestToString70("1234567890123456"); } void digestToString70(ref const char[16] digest) { assert(digest[0] == '1'); assert(digest[15] == '6'); } /***************************************************/ void foo71(out shared int o) {} /***************************************************/ struct foo72 { int bar() shared { return 1; } } void test72() { shared foo72 f; auto x = f.bar; } /***************************************************/ class Foo73 { static if (is(typeof(this) T : shared T)) static assert(0); static if (is(typeof(this) U == shared U)) static assert(0); static if (is(typeof(this) U == const U)) static assert(0); static if (is(typeof(this) U == immutable U)) static assert(0); static if (is(typeof(this) U == const shared U)) static assert(0); static assert(!is(int == const)); static assert(!is(int == immutable)); static assert(!is(int == shared)); static assert(is(int == int)); static assert(is(const(int) == const)); static assert(is(immutable(int) == immutable)); static assert(is(shared(int) == shared)); static assert(is(const(shared(int)) == shared)); static assert(is(const(shared(int)) == const)); static assert(!is(const(shared(int)) == immutable)); static assert(!is(const(int) == immutable)); static assert(!is(const(int) == shared)); static assert(!is(shared(int) == const)); static assert(!is(shared(int) == immutable)); static assert(!is(immutable(int) == const)); static assert(!is(immutable(int) == shared)); } template Bar(T : T) { alias T Bar; } template Barc(T : const(T)) { alias T Barc; } template Bari(T : immutable(T)) { alias T Bari; } template Bars(T : shared(T)) { alias T Bars; } template Barsc(T : shared(const(T))) { alias T Barsc; } void test73() { auto f = new Foo73; alias int T; // 5*5 == 25 combinations, plus 2 for swapping const and shared static assert(is(Bar!(T) == T)); static assert(is(Bar!(const(T)) == const(T))); static assert(is(Bar!(immutable(T)) == immutable(T))); static assert(is(Bar!(shared(T)) == shared(T))); static assert(is(Bar!(shared(const(T))) == shared(const(T)))); static assert(is(Barc!(const(T)) == T)); static assert(is(Bari!(immutable(T)) == T)); static assert(is(Bars!(shared(T)) == T)); static assert(is(Barsc!(shared(const(T))) == T)); static assert(is(Barc!(T) == T)); static assert(is(Barc!(immutable(T)) == T)); static assert(is(Barc!(const(shared(T))) == shared(T))); static assert(is(Barsc!(immutable(T)) == T)); static assert(is(Bars!(const(shared(T))) == const(T))); static assert(is(Barsc!(shared(T)) == T)); Bars!(shared(const(T))) b; pragma(msg, typeof(b)); static assert(is(Bars!(shared(const(T))) == const(T))); static assert(is(Barc!(shared(const(T))) == shared(T))); static assert(!is(Bari!(T))); static assert(!is(Bari!(const(T)))); static assert(!is(Bari!(shared(T)))); static assert(!is(Bari!(const(shared(T))))); static assert(is(Barc!(shared(T)))); static assert(!is(Bars!(T))); static assert(!is(Bars!(const(T)))); static assert(!is(Bars!(immutable(T)))); static assert(!is(Barsc!(T))); static assert(!is(Barsc!(const(T)))); } /***************************************************/ pure nothrow { alias void function(int) A74; } alias void function(int) pure nothrow B74; alias pure nothrow void function(int) C74; void test74() { A74 a = null; B74 b = null; C74 c = null; a = b; a = c; } /***************************************************/ void test9212() { int[int] aa; foreach (const key, const val; aa) {} foreach (size_t key, size_t val; aa) {} } /***************************************************/ class A75 { pure static void raise(string s) { throw new Exception(s); } } void test75() { int x = 0; try { A75.raise("a"); } catch (Exception e) { x = 1; } assert(x == 1); } /***************************************************/ void test76() { int x, y; bool which; (which ? x : y) += 5; assert(y == 5); } /***************************************************/ void test77() { auto a = ["hello", "world"]; pragma(msg, typeof(a)); auto b = a; assert(a is b); assert(a == b); b = a.dup; assert(a == b); assert(a !is b); } /***************************************************/ void test78() { auto array = [0, 2, 4, 6, 8, 10]; array = array[0 .. $ - 2]; // Right-shrink by two elements assert(array == [0, 2, 4, 6]); array = array[1 .. $]; // Left-shrink by one element assert(array == [2, 4, 6]); array = array[1 .. $ - 1]; // Shrink from both sides assert(array == [4]); } /***************************************************/ void test79() { auto a = [87, 40, 10]; a ~= 42; assert(a == [87, 40, 10, 42]); a ~= [5, 17]; assert(a == [87, 40, 10, 42, 5, 17]); } /***************************************************/ void test6317() { int b = 12345; struct nested { int a; int fun() { return b; } } static assert(!__traits(compiles, { nested x = { 3, null }; })); nested g = { 7 }; auto h = nested(7); assert(g.fun() == 12345); assert(h.fun() == 12345); } /***************************************************/ void test80() { auto array = new int[10]; array.length += 1000; assert(array.length == 1010); array.length /= 10; assert(array.length == 101); array.length -= 1; assert(array.length == 100); array.length |= 1; assert(array.length == 101); array.length ^= 3; assert(array.length == 102); array.length &= 2; assert(array.length == 2); array.length *= 2; assert(array.length == 4); array.length <<= 1; assert(array.length == 8); array.length >>= 1; assert(array.length == 4); array.length >>>= 1; assert(array.length == 2); array.length %= 2; assert(array.length == 0); int[]* foo() { static int x; x++; assert(x == 1); auto p = &array; return p; } (*foo()).length += 2; assert(array.length == 2); } /***************************************************/ void test81() { int[3] a = [1, 2, 3]; int[3] b = a; a[1] = 42; assert(b[1] == 2); // b is an independent copy of a int[3] fun(int[3] x, int[3] y) { // x and y are copies of the arguments x[0] = y[0] = 100; return x; } auto c = fun(a, b); // c has type int[3] assert(c == [100, 42, 3]); assert(b == [1, 2, 3]); // b is unaffected by fun } /***************************************************/ void test82() { auto a1 = [ "Jane":10.0, "Jack":20, "Bob":15 ]; auto a2 = a1; // a1 and a2 refer to the same data a1["Bob"] = 100; // Changing a1 assert(a2["Bob"] == 100); //is same as changing a2 a2["Sam"] = 3.5; //and vice assert(a2["Sam"] == 3.5); // versa } /***************************************************/ void test7942() { string a = "a"; wstring b = "b"; dstring c = "c"; a ~= "a"c; static assert(!is(typeof(a ~= "b"w))); static assert(!is(typeof(a ~= "c"d))); static assert(!is(typeof(b ~= "a"c))); b ~= "b"w; static assert(!is(typeof(b ~= "c"d))); static assert(!is(typeof(c ~= "a"c))); static assert(!is(typeof(c ~= "b"w))); c ~= "c"d; assert(a == "aa"); assert(b == "bb"); assert(c == "cc"); } /***************************************************/ void bump(ref int x) { ++x; } void test83() { int x = 1; bump(x); assert(x == 2); } /***************************************************/ interface Test4174 { void func(T)() {} } /***************************************************/ auto foo84 = [1, 2.4]; void test84() { pragma(msg, typeof([1, 2.4])); static assert(is(typeof([1, 2.4]) == double[])); pragma(msg, typeof(foo84)); static assert(is(typeof(foo84) == double[])); } /***************************************************/ void test85() { dstring c = "V\u00E4rld"; c = c ~ '!'; assert(c == "V\u00E4rld!"); c = '@' ~ c; assert(c == "@V\u00E4rld!"); wstring w = "V\u00E4rld"; w = w ~ '!'; assert(w == "V\u00E4rld!"); w = '@' ~ w; assert(w == "@V\u00E4rld!"); string s = "V\u00E4rld"; s = s ~ '!'; assert(s == "V\u00E4rld!"); s = '@' ~ s; assert(s == "@V\u00E4rld!"); } /***************************************************/ void test86() { int[][] a = [ [1], [2,3], [4] ]; int[][] w = [ [1, 2], [3], [4, 5], [] ]; int[][] x = [ [], [1, 2], [3], [4, 5], [] ]; } /***************************************************/ // Bugzilla 3379 T1[] find(T1, T2)(T1[] longer, T2[] shorter) if (is(typeof(longer[0 .. 1] == shorter) : bool)) { while (longer.length >= shorter.length) { if (longer[0 .. shorter.length] == shorter) break; longer = longer[1 .. $]; } return longer; } auto max(T...)(T a) if (T.length == 2 && is(typeof(a[1] > a[0] ? a[1] : a[0])) || T.length > 2 && is(typeof(max(max(a[0], a[1]), a[2 .. $])))) { static if (T.length == 2) { return a[1] > a[0] ? a[1] : a[0]; } else { return max(max(a[0], a[1]), a[2 .. $]); } } // Cases which would ICE or segfault struct Bulldog(T){ static void cat(Frog)(Frog f) if (true) { } } void mouse(){ Bulldog!(int).cat(0); } void test87() { double[] d1 = [ 6.0, 1.5, 2.4, 3 ]; double[] d2 = [ 1.5, 2.4 ]; assert(find(d1, d2) == d1[1 .. $]); assert(find(d1, d2) == d1[1 .. $]); // Check for memory corruption assert(max(4, 5) == 5); assert(max(3, 4, 5) == 5); } /***************************************************/ template test4284(alias v) { enum test4284 = v.length == 0; } static assert(test4284!(cast(string)null)); static assert(test4284!(cast(string[])null)); /***************************************************/ struct S88 { void opDispatch(string s, T)(T i) { printf("S.opDispatch('%.*s', %d)\n", s.length, s.ptr, i); } } class C88 { void opDispatch(string s)(int i) { printf("C.opDispatch('%.*s', %d)\n", s.length, s.ptr, i); } } struct D88 { template opDispatch(string s) { enum int opDispatch = 8; } } void test88() { S88 s; s.opDispatch!("hello")(7); s.foo(7); auto c = new C88(); c.foo(8); D88 d; printf("d.foo = %d\n", d.foo); assert(d.foo == 8); } /***************************************************/ void test89() { static struct X { int x; int bar() { return x; } } X s; printf("%d\n", s.sizeof); assert(s.sizeof == 4); } /***************************************************/ struct S90 { void opDispatch( string name, T... )( T values ) { assert(values[0] == 3.14); } } void test90( ) { S90 s; s.opDispatch!("foo")( 3.14 ); s.foo( 3.14 ); } /***************************************************/ struct A7439(int r, int c) { alias r R; alias c C; alias float[R * C] Data; Data _data; alias _data this; this(Data ar){ _data = ar; } pure ref float opIndex(size_t rr, size_t cc){ return _data[cc + rr * C]; } } void test7439() { A7439!(2, 2) a = A7439!(2, 2)([8, 3, 2, 9]); a[0,0] -= a[0,0] * 2.0; } /***************************************************/ void foo91(uint line = __LINE__) { printf("%d\n", line); } void test91() { foo91(); printf("%d\n", __LINE__); } /***************************************************/ bool fun13468(Object e, typeof(null) needle) { return (e == needle); } void test13468() { assert(fun13468(null, null)); } /***************************************************/ auto ref foo92(ref int x) { return x; } int bar92(ref int x) { return x; } void test92() { int x = 3; int i = bar92(foo92(x)); assert(i == 3); } /***************************************************/ struct Foo93 { public int foo() const { return 2; } } void test93() { const Foo93 bar = Foo93(); enum bla = bar.foo(); assert(bla == 2); } /***************************************************/ extern(C++) class C1687 { void func() {} } void test1687() { auto c = new C1687(); assert(c.__vptr[0] == (&c.func).funcptr); } /***************************************************/ struct Foo94 { int x, y; real z; } pure nothrow Foo94 makeFoo(const int x, const int y) { return Foo94(x, y, 3.0); } void test94() { auto f = makeFoo(1, 2); assert(f.x==1); assert(f.y==2); assert(f.z==3); } /***************************************************/ struct T95 { @disable this(this) { } } struct S95 { T95 t; } @disable void foo95() { } struct T95A { @disable this(this); } struct S95A { T95A t; } @disable void foo95A() { } void test95() { S95 s; S95 t; static assert(!__traits(compiles, t = s)); static assert(!__traits(compiles, foo95())); S95A u; S95A v; static assert(!__traits(compiles, v = u)); static assert(!__traits(compiles, foo95A())); } /***************************************************/ struct S96(alias init) { int[] content = init; } void test96() { S96!([12, 3]) s1; S96!([1, 23]) s2; writeln(s1.content); writeln(s2.content); assert(!is(typeof(s1) == typeof(s2))); } /***************************************************/ struct A97 { const bool opEquals(ref const A97) { return true; } ref A97 opUnary(string op)() if (op == "++") { return this; } } void test97() { A97 a, b; foreach (e; a .. b) { } } /***************************************************/ void test98() { auto a = new int[2]; // the name "length" should not pop up in an index expression static assert(!is(typeof(a[length - 1]))); } /***************************************************/ string s99; void bar99(string i) { } void function(string) foo99(string i) { return &bar99; } void test99() { foo99 (s99 ~= "a") (s99 ~= "b"); assert(s99 == "ab"); } /***************************************************/ // 5081 void test5081() { static pure immutable(int[]) x1() { int[] a = new int[](10); return a; } static pure immutable(int[]) x2(int len) { int[] a = new int[](len); return a; } static pure immutable(int[]) x3(immutable(int[]) org) { int[] a = new int[](org.length); return a; } immutable a1 = x1(); immutable a2 = x2(10); immutable a3 = x3([1,2]); static pure int[] y1() { return new int[](10); } immutable b1 = y1(); } /***************************************************/ void test100() { string s; /* Testing order of evaluation */ void delegate(string, string) fun(string) { s ~= "b"; return delegate void(string x, string y) { s ~= "e"; }; } fun(s ~= "a")(s ~= "c", s ~= "d"); assert(s == "abcde", s); } /***************************************************/ void test101() { int[] d1 = [ 6, 1, 2 ]; byte[] d2 = [ 6, 1, 2 ]; assert(d1 == d2); d2 ~= [ 6, 1, 2 ]; assert(d1 != d2); } /***************************************************/ void test5403() { struct S { static int front; enum back = "yes!"; bool empty; void popAny() { empty = true; } alias popAny popFront; alias popAny popBack; } S.front = 7; foreach(int i; S()) assert(i == 7); S.front = 2; foreach(i; S()) assert(i == 2); foreach_reverse(i; S()) assert(i == "yes!"); } /***************************************************/ static assert([1,2,3] == [1.0,2,3]); /***************************************************/ int transmogrify(uint) { return 1; } int transmogrify(long) { return 2; } void test103() { assert(transmogrify(42) == 1); } /***************************************************/ int foo104(int x) { int* p = &(x += 1); return *p; } int bar104(int *x) { int* p = &(*x += 1); return *p; } void test104() { auto i = foo104(1); assert(i == 2); i = bar104(&i); assert(i == 3); } /***************************************************/ ref int bump105(ref int x) { return ++x; } void test105() { int x = 1; bump105(bump105(x)); // two increments assert(x == 3); } /***************************************************/ pure int genFactorials(int n) { static pure int factorial(int n) { if (n==2) return 1; return factorial(2); } return factorial(n); } /***************************************************/ void test107() { int[6] a; writeln(a); writeln(a.init); assert(a.init == [0,0,0,0,0,0]); } /***************************************************/ class A109 {} void test109() { immutable(A109) b; A109 c; auto z = true ? b : c; //writeln(typeof(z).stringof); static assert(is(typeof(z) == const(A109))); } /***************************************************/ template Boo(T) {} struct Foo110(T, alias V = Boo!T) { pragma(msg, V.stringof); static const s = V.stringof; } alias Foo110!double B110; alias Foo110!int A110; static assert(B110.s == "Boo!double"); static assert(A110.s == "Boo!int"); /***************************************************/ int test11247() { static assert(is(byte[typeof(int.init).sizeof] == byte[4])); static assert(is(byte[typeof(return).sizeof] == byte[4])); return 0; } /***************************************************/ // 3716 void test111() { auto k1 = true ? [1,2] : []; // OK auto k2 = true ? [[1,2]] : [[]]; auto k3 = true ? [] : [[1,2]]; auto k4 = true ? [[[]]] : [[[1,2]]]; auto k5 = true ? [[[1,2]]] : [[[]]]; auto k6 = true ? [] : [[[]]]; static assert(!is(typeof(true ? [[[]]] : [[1,2]]))); // Must fail } /***************************************************/ // 658 void test658() { struct S { int i; } class C { int i; } S s; S* sp = &s; with (sp) i = 42; assert(s.i == 42); with (&s) i = 43; assert(s.i == 43); C c = new C; C* cp = &c; with (cp) i = 42; assert(c.i == 42); with (&c) i = 43; assert(c.i == 43); } /***************************************************/ void test3069() { ubyte id = 0; void[] v = [id] ~ [id]; } /***************************************************/ // 4303 template foo112() if (__traits(compiles,undefined)) { enum foo112 = false; } template foo112() if (true) { enum foo112 = true; } pragma(msg,__traits(compiles,foo112!())); static assert(__traits(compiles,foo112!())); const bool bar112 = foo112!(); /***************************************************/ struct File113 { this(int name) { } ~this() { } void opAssign(File113 rhs) { } struct ByLine { File113 file; this(int) { } } ByLine byLine() { return ByLine(1); } } auto filter113(File113.ByLine rs) { struct Filter { this(File113.ByLine r) { } } return Filter(rs); } void test113() { auto f = File113(1); auto rx = f.byLine(); auto file = filter113(rx); } /***************************************************/ template foo114(fun...) { auto foo114(int[] args) { return 1; } } pragma(msg, typeof(foo114!"a + b"([1,2,3]))); /***************************************************/ // Bugzilla 3935 struct Foo115 { void opBinary(string op)(Foo other) { pragma(msg, "op: " ~ op); assert(0); } } void test115() { Foo115 f; f = f; } /***************************************************/ // Bugzilla 2477 void foo116(T,)(T t) { T x; } void test116() { int[] data = [1,2,3,]; // OK data = [ 1,2,3, ]; // fails auto i = data[1,]; foo116!(int)(3); foo116!(int,)(3); foo116!(int,)(3,); } /***************************************************/ void test1891() { struct C { char[8] x = "helloabc"; } int main() { C* a = new C; C*[] b; b ~= new C; auto g = a ~ b; assert(g[0] && g[1] && g[0].x == g[1].x); return 0; } } /***************************************************/ // Bugzilla 4291 void test117() pure { mixin declareVariable; var = 42; mixin declareFunction; readVar(); } template declareVariable() { int var; } template declareFunction() { int readVar() { return var; } } /***************************************************/ // Bugzilla 4177 pure real log118(real x) { if (__ctfe) return 0.0; else return 1.0; } enum x118 = log118(4.0); void test118() {} /***************************************************/ void bug4465() { const a = 2 ^^ 2; int b = a; } /***************************************************/ pure void foo(int *p) { *p = 3; } pure void test120() { int i; foo(&i); assert(i == 3); } /***************************************************/ // 4866 immutable int[3] statik = [ 1, 2, 3 ]; enum immutable(int)[] dynamic = statik; static assert(is(typeof(dynamic) == immutable(int)[])); static if (! is(typeof(dynamic) == immutable(int)[])) { static assert(0); // (7) } pragma(msg, "!! ", typeof(dynamic)); /***************************************************/ // 2943 struct Foo2943 { int a; int b; alias b this; } void test122() { Foo2943 foo, foo2; foo.a = 1; foo.b = 2; foo2.a = 3; foo2.b = 4; foo2 = foo; assert(foo2.a == foo.a); } /***************************************************/ // 4641 struct S123 { int i; alias i this; } void test123() { S123[int] ss; ss[0] = S123.init; // This line causes Range Violation. } /***************************************************/ // 2451 struct Foo124 { int z = 3; void opAssign(Foo124 x) { z= 2;} } struct Bar124 { int z = 3; this(this){ z = 17; } } void test124() { Foo124[string] stuff; stuff["foo"] = Foo124.init; assert(stuff["foo"].z == 3); stuff["foo"] = Foo124.init; assert(stuff["foo"].z == 2); Bar124[string] stuff2; Bar124 q; stuff2["dog"] = q; assert(stuff2["dog"].z == 17); } /***************************************************/ void test3022() { static class Foo3022 { new(size_t) { assert(0); } } scope x = new Foo3022; } /***************************************************/ void doNothing() {} void bug5071(short d, ref short c) { assert(c==0x76); void closure() { auto c2 = c; auto d2 = d; doNothing(); } auto useless = &closure; } void test125() { short c = 0x76; bug5071(7, c); } /***************************************************/ struct Foo126 { static Foo126 opCall(in Foo126 _f) pure { return _f; } } /***************************************************/ void test796() { struct S { invariant() { throw new Exception(""); } } S* s; try { assert(s); } catch (Error) { } } /***************************************************/ void test7077() { if(0) mixin("auto x = 2;"); auto x = 1; } /***************************************************/ struct Tuple127(S...) { S expand; alias expand this; } alias Tuple127!(int, int) Foo127; void test127() { Foo127[] m_array; Foo127 f; m_array ~= f; } /***************************************************/ struct Bug4434 {} alias const Bug4434* IceConst4434; alias shared Bug4434* IceShared4434; alias shared Bug4434[] IceSharedArray4434; alias immutable Bug4434* IceImmutable4434; alias shared const Bug4434* IceSharedConst4434; alias int MyInt4434; alias const MyInt4434[3] IceConstInt4434; alias immutable string[] Bug4830; /***************************************************/ // 4254 void bub(const inout int other) {} void test128() { bub(1); } /***************************************************/ pure nothrow @safe auto bug4915a() { return 0; } pure nothrow @safe int bug4915b() { return bug4915a(); } void bug4915c() { pure nothrow @safe int d() { return 0; } int e() pure nothrow @safe { return d(); } } /***************************************************/ // 5164 static if (is(int Q == int, Z...)) { } /***************************************************/ // 5195 alias typeof(foo5195) food5195; const int * foo5195 = null; alias typeof(foo5195) good5195; static assert( is (food5195 == good5195)); /***************************************************/ version (Windows) { } else { int[0] var5332; void test5332() { auto x = var5332; } } /***************************************************/ // 5191 struct Foo129 { void add(T)(T value) nothrow { this.value += value; } this(int value) { this.value = value; } int value; } void test129() { auto foo = Foo129(5); assert(foo.value == 5); foo.add(2); writeln(foo.value); assert(foo.value == 7); foo.add(3); writeln(foo.value); assert(foo.value == 10); foo.add(3); writeln(foo.value); assert(foo.value == 13); void delegate (int) nothrow dg = &foo.add!(int); dg(7); assert(foo.value == 20); } /***************************************************/ // 6169 auto ctfefunc6169() { return ";"; } enum ctfefptr6169 = &ctfefunc6169; int ctfefunc6169a() { return 1; } template x6169(string c) { alias int x6169; } template TT6169(T...) { alias T TT6169; } @property ctfeprop6169() { return "g"; } void test6169() pure @safe { enum a = ctfefunc6169(); static b = ctfefunc6169(); x6169!(ctfefunc6169()) tt; mixin(ctfefunc6169()); static if(ctfefunc6169()) {} pragma(msg, ctfefunc6169()); enum xx { k = 0, j = ctfefunc6169a() } auto g = mixin('"' ~ ctfefunc6169() ~ '"'); //auto h = import("testx.d" ~ false ? ctfefunc() : ""); alias TT6169!(int, int)[ctfefunc6169a()..ctfefunc6169a()] i; alias TT6169!(int, int)[ctfefunc6169a()] j; int[ctfefunc6169a()+1] k; alias int[ctfefunc6169a()] l; switch(1) { //case ctfefunc6169a(): // Can't do this because of case variables case ctfefunc6169a()+1: .. case ctfefunc6169a()+2: default: break; } static assert(ctfefunc6169a()); void fun(int i : ctfefunc6169a() = ctfefunc6169a(), alias j)() if (ctfefunc6169a()) {} fun!(ctfefunc6169a(), ctfefunc6169())(); enum z = ctfefptr6169(); auto p = mixin(ctfeprop6169); } /***************************************************/ // 10506 void impureFunc10506() {} string join10506(RoR)(RoR ror) { impureFunc10506(); return ror[0] ~ ror[1]; } void test10506() pure { void foobar() {} mixin(["foo", "bar"].join10506()~";"); } /***************************************************/ const shared class C5107 { int x; } static assert(is(typeof(C5107.x) == const)); // okay static assert(is(typeof(C5107.x) == shared)); // fails! /***************************************************/ immutable struct S3598 { static void funkcja() { } } /***************************************************/ // 4211 @safe struct X130 { void func() { } } @safe class Y130 { void func() { } } @safe void test130() { X130 x; x.func(); auto y = new Y130; y.func(); } /***************************************************/ template Return(alias fun) { static if (is(typeof(fun) R == return)) alias R Return; } interface I4217 { int square(int n); real square(real n); } alias Return!( __traits(getOverloads, I4217, "square")[0] ) R4217; alias Return!( __traits(getOverloads, I4217, "square")[1] ) S4217; static assert(! is(R4217 == S4217)); /***************************************************/ // 5094 void test131() { S131 s; int[] conv = s; } struct S131 { @property int[] get() { return [1,2,3]; } alias get this; } /***************************************************/ struct S7545 { uint id; alias id this; } void test7545() { auto id = 0 ? S7545() : -1; } /***************************************************/ // 5020 void test132() { S132 s; if (!s) {} } struct S132 { bool cond; alias cond this; } /***************************************************/ // 5343 struct Tuple5343(Specs...) { Specs[0] field; } struct S5343(E) { immutable E x; } enum A5343{a,b,c} alias Tuple5343!(A5343) TA5343; alias S5343!(A5343) SA5343; /***************************************************/ // 5365 interface IFactory { void foo(); } class A133 { protected static class Factory : IFactory { void foo() { } } this() { _factory = createFactory(); } protected IFactory createFactory() { return new Factory; } private IFactory _factory; @property final IFactory factory() { return _factory; } alias factory this; } void test133() { IFactory f = new A133; f.foo(); // segfault } /***************************************************/ // 5365 class B134 { } class A134 { B134 _b; this() { _b = new B134; } B134 b() { return _b; } alias b this; } void test134() { auto a = new A134; B134 b = a; // b is null assert(a._b is b); // fails } /***************************************************/ // 5025 struct S135 { void delegate() d; } void test135() { shared S135[] s; if (0) s[0] = S135(); } /***************************************************/ // 5545 bool enforce136(bool value, lazy const(char)[] msg = null) { if(!value) { return false; } return value; } struct Perm { byte[3] perm; ubyte i; this(byte[] input) { foreach(elem; input) { enforce136(i < 3); perm[i++] = elem; std.stdio.stderr.writeln(i); // Never gets incremented. Stays at 0. } } } void test136() { byte[] stuff = [0, 1, 2]; auto perm2 = Perm(stuff); writeln(perm2.perm); // Prints [2, 0, 0] assert(perm2.perm[] == [0, 1, 2]); } /***************************************************/ // 4097 void foo4097() { } alias typeof(&foo4097) T4097; static assert(is(T4097 X : X*) && is(X == function)); static assert(!is(X)); /***************************************************/ // 5798 void assign9(ref int lhs) pure { lhs = 9; } void assign8(ref int rhs) pure { rhs = 8; } int test137(){ int a=1,b=2; assign8(b),assign9(a); assert(a == 9); assert(b == 8); // <-- fail assign9(b),assign8(a); assert(a == 8); assert(b == 9); // <-- fail return 0; } /***************************************************/ // 9366 static assert(!is(typeof((void[]).init ~ cast(void)0))); static assert(!is(typeof(cast(void)0 ~ (void[]).init))); /***************************************************/ struct Size138 { union { struct { int width; int height; } long size; } } enum Size138 foo138 = {2 ,5}; Size138 bar138 = foo138; void test138() { assert(bar138.width == 2); assert(bar138.height == 5); } /***************************************************/ void test3822() { import core.stdc.stdlib; int i = 0; void* ptr; while(i++ != 2) { auto p = alloca(2); assert(p != ptr); ptr = p; } } /***************************************************/ // 5939, 5940 template map(fun...) { auto map(double[] r) { struct Result { this(double[] input) { } } return Result(r); } } void test139() { double[] x; alias typeof(map!"a"(x)) T; T a = void; auto b = map!"a"(x); auto c = [map!"a"(x)]; T[3] d = void; } /***************************************************/ // 5966 string[] foo5966(string[] a) { a[0] = a[0][0..$]; return a; } enum var5966 = foo5966([""]); /***************************************************/ // 5975 int foo5975(wstring replace) { wstring value = ""; value ~= replace; return 1; } enum X5975 = foo5975("X"w); /***************************************************/ // 5965 template mapx(fun...) if (fun.length >= 1) { int mapx(Range)(Range r) { return 1; } } void test140() { int foo(int i) { return i; } int[] arr; auto x = mapx!( (int a){return foo(a);} )(arr); } /***************************************************/ void bug5976() { int[] barr; int * k; foreach (ref b; barr) { scope(failure) k = &b; k = &b; } } /***************************************************/ // 5771 struct S141 { this(A)(auto ref A a){} } void test141() { S141 s = S141(10); } /***************************************************/ class test5498_A {} class test5498_B : test5498_A {} class test5498_C : test5498_A {} static assert(is(typeof([test5498_B.init, test5498_C.init]) == test5498_A[])); /***************************************************/ // 3688 struct S142 { int v; this(int n) pure { v = n; } const bool opCast(T:bool)() { return true; } } void test142() { if (int a = 1) assert(a == 1); else assert(0); if (const int a = 2) assert(a == 2); else assert(0); if (immutable int a = 3) assert(a == 3); else assert(0); if (auto s = S142(10)) assert(s.v == 10); else assert(0); if (auto s = const(S142)(20)) assert(s.v == 20); else assert(0); if (auto s = immutable(S142)(30)) assert(s.v == 30); else assert(0); } /***************************************************/ // 6072 static assert({ if (int x = 5) {} return true; }()); /***************************************************/ // 5959 int n; void test143() { ref int f(){ return n; } // NG f() = 1; assert(n == 1); nothrow ref int f1(){ return n; } // OK f1() = 2; assert(n == 2); auto ref int f2(){ return n; } // OK f2() = 3; assert(n == 3); } /***************************************************/ // 6119 void startsWith(alias pred) () if (is(typeof(pred('c', 'd')) : bool)) { } void startsWith(alias pred) () if (is(typeof(pred('c', "abc")) : bool)) { } void test144() { startsWith!((a, b) { return a == b; })(); } /***************************************************/ void test145() { import core.stdc.stdio; printf("hello world 145\n"); } void test146() { test1(); static import core.stdc.stdio; core.stdc.stdio.printf("hello world 146\n"); } /***************************************************/ // 5856 struct X147 { void f() { writeln("X.f mutable"); } void f() const { writeln("X.f const"); } void g()() { writeln("X.g mutable"); } void g()() const { writeln("X.g const"); } void opOpAssign(string op)(int n) { writeln("X+= mutable"); } void opOpAssign(string op)(int n) const { writeln("X+= const"); } } void test147() { X147 xm; xm.f(); // prints "X.f mutable" xm.g(); // prints "X.g mutable" xm += 10; // should print "X+= mutable" (1) const(X147) xc; xc.f(); // prints "X.f const" xc.g(); // prints "X.g const" xc += 10; // should print "X+= const" (2) } /***************************************************/ void test3559() { static class A { int foo(int a) { return 0; } int foo(float a) { return 1; } int bar(float a) { return 1; } int bar(int a) { return 0; } } static class B : A { override int foo(float a) { return 2; } alias A.foo foo; alias A.bar bar; override int bar(float a) { return 2; } } { auto x = new A; auto f1 = cast(int delegate(int))&x.foo; auto f2 = cast(int delegate(float))&x.foo; int delegate(int) f3 = &x.foo; int delegate(float) f4 = &x.foo; assert(f1(0) == 0); assert(f2(0) == 1); assert(f3(0) == 0); assert(f4(0) == 1); } { auto x = new B; auto f1 = cast(int delegate(int))&x.foo; auto f2 = cast(int delegate(float))&x.foo; int delegate(int) f3 = &x.foo; int delegate(float) f4 = &x.foo; assert(f1(0) == 0); assert(f2(0) == 2); assert(f3(0) == 0); assert(f4(0) == 2); } { auto x = new A; auto f1 = cast(int delegate(int))&x.bar; auto f2 = cast(int delegate(float))&x.bar; int delegate(int) f3 = &x.bar; int delegate(float) f4 = &x.bar; assert(f1(0) == 0); assert(f2(0) == 1); assert(f3(0) == 0); assert(f4(0) == 1); } { auto x = new B; auto f1 = cast(int delegate(int))&x.bar; auto f2 = cast(int delegate(float))&x.bar; int delegate(int) f3 = &x.bar; int delegate(float) f4 = &x.bar; assert(f1(0) == 0); assert(f2(0) == 2); assert(f3(0) == 0); assert(f4(0) == 2); } } /***************************************************/ extern(C++) class C13182 { } void test13182() { scope C13182 c = new C13182(); } /***************************************************/ // 5897 struct A148{ int n; } struct B148{ int n, m; this(A148 a){ n = a.n, m = a.n*2; } } struct C148{ int n, m; static C148 opCall(A148 a) { C148 b; b.n = a.n, b.m = a.n*2; return b; } } void test148() { auto a = A148(10); auto b = cast(B148)a; assert(b.n == 10 && b.m == 20); auto c = cast(C148)a; assert(c.n == 10 && c.m == 20); } /***************************************************/ // 4969 class MyException : Exception { this() { super("An exception!"); } } void throwAway() { throw new MyException; } void cantthrow() nothrow { try throwAway(); catch(MyException me) assert(0); catch(Exception e) assert(0); } /***************************************************/ // 2356 void test2356() { int[3] x = [1,2,3]; printf("x[] = [%d %d %d]\n", x[0], x[1], x[2]); assert(x[0] == 1 && x[1] == 2 && x[2] == 3); struct S { static int pblit; int n; this(this) { ++pblit; printf("postblit: %d\n", n); } } S s2 = S(2); S[3] s = [S(1), s2, S(3)]; assert(s[0].n == 1 && s[1].n == 2 && s[2].n == 3); printf("s[].n = [%d %d %d]\n", s[0].n, s[1].n, s[2].n); assert(S.pblit == 1); ubyte[1024] v; v = typeof(v).init; printf("v[] = [%d %d %d, ..., %d]\n", v[0], v[1], v[2], v[$-1]); foreach (ref a; v) assert(a == 0); int n = 5; int[3] y = [n, n, n]; printf("y[] = [%d %d %d]\n", y[0], y[1], y[2]); assert(y[0] == 5 && y[1] == 5 && y[2] == 5); S[3] z = [s2, s2, s2]; assert(z[0].n == 2 && z[1].n == 2 && z[2].n == 2); printf("z[].n = [%d %d %d]\n", z[0].n, z[1].n, z[2].n); assert(S.pblit == 1 + 3); int[0] nsa0 = []; void[0] vsa0 = []; void foo(T)(T){} foo(vsa0); ref int[0] bar() { static int[1] sa; return *cast(int[0]*)&sa; } bar() = []; } /***************************************************/ // 13652 void test13652() { // reduced case uint[9][5] arr = [[0, 0, 0, 0, 1, 5, 8, 0, 7], [0, 3, 8, 0, 2, 0, 0, 6, 0], [0, 0, 7, 0, 6, 8, 9, 4, 0], [0, 0, 0, 0, 0, 1, 2, 9, 0], [9, 7, 0, 0, 0, 0, 0, 8, 3]]; assert(arr[0][0] == 0 && arr[0][1] == 0 && arr[0][2] == 0 && arr[0][3] == 0 && arr[0][4] == 1 && arr[0][5] == 5 && arr[0][6] == 8 && arr[0][7] == 0 && arr[0][8] == 7); assert(arr[1][0] == 0 && arr[1][1] == 3 && arr[1][2] == 8 && arr[1][3] == 0 && arr[1][4] == 2 && arr[1][5] == 0 && arr[1][6] == 0 && arr[1][7] == 6 && arr[1][8] == 0); assert(arr[2][0] == 0 && arr[2][1] == 0 && arr[2][2] == 7 && arr[2][3] == 0 && arr[2][4] == 6 && arr[2][5] == 8 && arr[2][6] == 9 && arr[2][7] == 4 && arr[2][8] == 0); assert(arr[3][0] == 0 && arr[3][1] == 0 && arr[3][2] == 0 && arr[3][3] == 0 && arr[3][4] == 0 && arr[3][5] == 1 && arr[3][6] == 2 && arr[3][7] == 9 && arr[3][8] == 0); assert(arr[4][0] == 9 && arr[4][1] == 7 && arr[4][2] == 0 && arr[4][3] == 0 && arr[4][4] == 0 && arr[4][5] == 0 && arr[4][6] == 0 && arr[4][7] == 8 && arr[4][8] == 3); // original case uint[9][9] tbl = [[0, 0, 0, 0, 1, 5, 8, 0, 7], [0, 3, 8, 0, 2, 0, 0, 6, 0], [0, 0, 7, 0, 6, 8, 9, 4, 0], [0, 0, 0, 0, 0, 1, 2, 9, 0], [9, 7, 0, 0, 0, 0, 0, 8, 3], [0, 2, 1, 6, 0, 0, 0, 0, 0], [0, 6, 9, 5, 4, 0, 3, 0, 0], [0, 4, 0, 0, 8, 0, 6, 5, 0], [2, 0, 5, 9, 3, 0, 0, 0, 0]]; assert(tbl[0][0] == 0 && tbl[0][1] == 0 && tbl[0][2] == 0 && tbl[0][3] == 0 && tbl[0][4] == 1 && tbl[0][5] == 5 && tbl[0][6] == 8 && tbl[0][7] == 0 && tbl[0][8] == 7); assert(tbl[1][0] == 0 && tbl[1][1] == 3 && tbl[1][2] == 8 && tbl[1][3] == 0 && tbl[1][4] == 2 && tbl[1][5] == 0 && tbl[1][6] == 0 && tbl[1][7] == 6 && tbl[1][8] == 0); assert(tbl[2][0] == 0 && tbl[2][1] == 0 && tbl[2][2] == 7 && tbl[2][3] == 0 && tbl[2][4] == 6 && tbl[2][5] == 8 && tbl[2][6] == 9 && tbl[2][7] == 4 && tbl[2][8] == 0); assert(tbl[3][0] == 0 && tbl[3][1] == 0 && tbl[3][2] == 0 && tbl[3][3] == 0 && tbl[3][4] == 0 && tbl[3][5] == 1 && tbl[3][6] == 2 && tbl[3][7] == 9 && tbl[3][8] == 0); assert(tbl[4][0] == 9 && tbl[4][1] == 7 && tbl[4][2] == 0 && tbl[4][3] == 0 && tbl[4][4] == 0 && tbl[4][5] == 0 && tbl[4][6] == 0 && tbl[4][7] == 8 && tbl[4][8] == 3); assert(tbl[5][0] == 0 && tbl[5][1] == 2 && tbl[5][2] == 1 && tbl[5][3] == 6 && tbl[5][4] == 0 && tbl[5][5] == 0 && tbl[5][6] == 0 && tbl[5][7] == 0 && tbl[5][8] == 0); assert(tbl[6][0] == 0 && tbl[6][1] == 6 && tbl[6][2] == 9 && tbl[6][3] == 5 && tbl[6][4] == 4 && tbl[6][5] == 0 && tbl[6][6] == 3 && tbl[6][7] == 0 && tbl[6][8] == 0); assert(tbl[7][0] == 0 && tbl[7][1] == 4 && tbl[7][2] == 0 && tbl[7][3] == 0 && tbl[7][4] == 8 && tbl[7][5] == 0 && tbl[7][6] == 6 && tbl[7][7] == 5 && tbl[7][8] == 0); assert(tbl[8][0] == 2 && tbl[8][1] == 0 && tbl[8][2] == 5 && tbl[8][3] == 9 && tbl[8][4] == 3 && tbl[8][5] == 0 && tbl[8][6] == 0 && tbl[8][6] == 0 && tbl[8][8] == 0); } /***************************************************/ // 11238 void test11238() { int[2] m; m[0] = 4,m[1] = 6; //printf("%d,%d\n", m[0], m[1]); assert(m[0] == 4 && m[1] == 6); m = [m[1], m[0]]; // swap assert(m[0] == 6 && m[1] == 4); //printf("%d,%d\n", m[0], m[1]); m = [m[1], m[0]]; // swap //printf("%d,%d\n", m[0], m[1]); assert(m[0] == 4 && m[1] == 6); } /***************************************************/ void test11805() { int i; i = 47; i = 1 && i; assert(i == 1); i = 0 || i; assert(i == 1); } /***************************************************/ class A2540 { int a; int foo() { return 0; } alias int X; } class B2540 : A2540 { int b; override super.X foo() { return 1; } alias this athis; alias this.b thisb; alias super.a supera; alias super.foo superfoo; alias this.foo thisfoo; } struct X2540 { alias this athis; } void test2540() { auto x = X2540.athis.init; static assert(is(typeof(x) == X2540)); B2540 b = new B2540(); assert(&b.a == &b.supera); assert(&b.b == &b.thisb); assert(b.thisfoo() == 1); } /***************************************************/ class B14348 { int foo() { return 0; } } class C14348 : B14348 { override int foo() { return 1; } alias superfoo = typeof(super).foo; alias thisfoo = typeof(this).foo; } B14348 test14348() { alias foo = typeof(return).foo; // currently doesn't work. assert(&B14348.foo is &C14348.superfoo); assert(&C14348.foo is &C14348.thisfoo); return null; } /***************************************************/ // 7295 struct S7295 { int member; @property ref int refCountedPayload() { return member; } alias refCountedPayload this; } void foo7295(S)(immutable S t, int qq) pure { } void foo7295(S)(S s) pure { } void bar7295() pure { S7295 b; foo7295(b); } /***************************************************/ // 5659 void test149() { import std.traits; char a; immutable(char) b; static assert(is(typeof(true ? a : b) == const(char))); static assert(is(typeof([a, b][0]) == const(char))); static assert(is(CommonType!(typeof(a), typeof(b)) == const(char))); } /***************************************************/ // 1373 void func1373a(){} static assert(typeof(func1373a).stringof == "void()"); static assert(typeof(func1373a).mangleof == "FZv"); static assert(!__traits(compiles, typeof(func1373a).alignof)); static assert(!__traits(compiles, typeof(func1373a).init)); static assert(!__traits(compiles, typeof(func1373a).offsetof)); void func1373b(int n){} static assert(typeof(func1373b).stringof == "void(int n)"); static assert(typeof(func1373b).mangleof == "FiZv"); static assert(!__traits(compiles, typeof(func1373b).alignof)); static assert(!__traits(compiles, typeof(func1373b).init)); static assert(!__traits(compiles, typeof(func1373b).offsetof)); /***************************************************/ void bar150(T)(T n) { } @safe void test150() { bar150(1); } /***************************************************/ void test5785() { static struct x { static int y; } assert(x.y !is 1); assert(x.y !in [1:0]); } /***************************************************/ void bar151(T)(T n) { } nothrow void test151() { bar151(1); } /***************************************************/ @property int coo() { return 1; } @property auto doo(int i) { return i; } @property int eoo() { return 1; } @property auto ref hoo(int i) { return i; } // 3359 int goo(int i) pure { return i; } auto ioo(int i) pure { return i; } auto ref boo(int i) pure nothrow { return i; } class A152 { auto hoo(int i) pure { return i; } const boo(int i) nothrow { return i; } auto coo(int i) const { return i; } auto doo(int i) immutable { return i; } auto eoo(int i) shared { return i; } } // 4706 struct Foo152(T) { @property auto ref front() { return T.init; } @property void front(T num) {} } void test152() { Foo152!int foo; auto a = foo.front; foo.front = 2; } /***************************************************/ // 6733 void bug6733(int a, int b) pure nothrow { } void test6733() { int z = 1; bug6733(z++, z++); assert(z==3); } /***************************************************/ // 3799 void test153() { void bar() { } static assert(!__traits(isStaticFunction, bar)); } /***************************************************/ // 3632 void test154() { float f; assert(f is float.init); double d; assert(d is double.init); real r; assert(r is real.init); assert(float.nan is float.nan); assert(double.nan is double.nan); assert(real.nan is real.nan); } /***************************************************/ void test6545() { static int[] func() { auto a = [1, 2, 3]; auto b = [2, 3, 4]; auto c = [3, 4, 5]; a[] = b[] + c[]; return a; } auto a = func(); enum b = func(); assert(a == b); } /***************************************************/ // 3147 void test155() { byte b = 1; short s; int i; long l; s = b + b; b = s % b; s = s >> b; b = 1; b = i % b; b = b >> i; } /***************************************************/ // 2486 void test2486() { void foo(ref int[] arr) {} int[] arr = [1,2,3]; foo(arr); //OK static assert(!__traits(compiles, foo(arr[1..2]))); // should be NG struct S { int[] a; auto ref opSlice(){ return a[]; } // line 4 } S s; s[]; // opSlice should return rvalue static assert(is(typeof(&S.opSlice) == int[] function() pure nothrow @nogc @safe)); static assert(!__traits(compiles, foo(s[]))); // should be NG } /***************************************************/ extern(C++) class C15080 { uint x = 1; uint y = 2; } __gshared c15080 = new C15080(); void test15080() { assert(c15080.x == 1); assert(c15080.y == 2); } /***************************************************/ // 2521 immutable int val = 23; const int val2 = 23; ref immutable(int) func2521_() { return val; } ref immutable(int) func2521_2() { return *&val; } ref immutable(int) func2521_3() { return func2521_; } ref const(int) func2521_4() { return val2; } ref const(int) func2521_5() { return val; } auto ref func2521_6() { return val; } ref func2521_7() { return val; } /***************************************************/ void test5554() { class MA { } class MB : MA { } class MC : MB { } class A { abstract MA foo(); } interface I { MB foo(); } class B : A { override MC foo() { return null; } } class C : B, I { override MC foo() { return null; } } } /***************************************************/ // 5962 struct S156 { auto g()(){ return 1; } const auto g()(){ return 2; } } void test156() { auto ms = S156(); assert(ms.g() == 1); auto cs = const(S156)(); assert(cs.g() == 2); } /***************************************************/ void test10724() { const(char)* s = "abc"[0..$-1]; assert(s[2] == '\0'); } /***************************************************/ void test6708(const ref int y) { immutable int x; test6708(x); } /***************************************************/ // 4258 struct Vec4258 { Vec4258 opOpAssign(string Op)(auto ref Vec4258 other) if (Op == "+") { return this; } Vec4258 opBinary(string Op:"+")(Vec4258 other) { Vec4258 result; return result += other; } } void test4258() { Vec4258 v; v += Vec4258() + Vec4258(); // line 12 } // regression fix test struct Foo4258 { // binary ++/-- int opPostInc()() if (false) { return 0; } // binary 1st int opAdd(R)(R rhs) if (false) { return 0; } int opAdd_r(R)(R rhs) if (false) { return 0; } // compare int opCmp(R)(R rhs) if (false) { return 0; } // binary-op assign int opAddAssign(R)(R rhs) if (false) { return 0; } } struct Bar4258 { // binary commutive 1 int opAdd_r(R)(R rhs) if (false) { return 0; } // binary-op assign int opOpAssign(string op, R)(R rhs) if (false) { return 0; } } struct Baz4258 { // binary commutive 2 int opAdd(R)(R rhs) if (false) { return 0; } } static assert(!is(typeof(Foo4258.init++))); static assert(!is(typeof(Foo4258.init + 1))); static assert(!is(typeof(1 + Foo4258.init))); static assert(!is(typeof(Foo4258.init < Foo4258.init))); static assert(!is(typeof(Foo4258.init += 1))); static assert(!is(typeof(Bar4258.init + 1))); static assert(!is(typeof(Bar4258.init += 1))); static assert(!is(typeof(1 + Baz4258.init))); /***************************************************/ // 4539 void test4539() { static assert(!__traits(compiles, "hello" = "red")); void foo1(ref string s){} void foo2(ref const char[10] s){} void foo3(ref char[5] s){} void foo4(ref const char[5] s) { assert(s[0] == 'h'); assert(s[4] == 'o'); } void foo5(ref const ubyte[5] s) { assert(s[0] == 0xc3); assert(s[4] == 0x61); } static assert(!__traits(compiles, foo1("hello"))); static assert(!__traits(compiles, foo2("hello"))); static assert(!__traits(compiles, foo3("hello"))); // same as test68, 69, 70 foo4("hello"); foo5(cast(ubyte[5])x"c3fcd3d761"); //import std.conv; //static assert(!__traits(compiles, parse!int("10") == 10)); } /***************************************************/ // 1471 void test1471() { int n; string bar = "BOOM"[n..$-1]; assert(bar == "BOO"); } /***************************************************/ deprecated @disable int bug6389; static assert(!is(typeof(bug6389 = bug6389))); /***************************************************/ void test10927() { static assert( (1+2i) ^^ 3 == -11 - 2i ); auto a = (1+2i) ^^ 3; } /***************************************************/ void test4963() { struct Value { byte a; }; Value single() { return Value(); } Value[] list; auto x = single() ~ list; } /***************************************************/ pure int test4031() { static const int x = 8; return x; } /***************************************************/ // 5437 template EnumMembers5437(E) { template TypeTuple(T...){ alias T TypeTuple; } alias TypeTuple!("A", "B") EnumMembers5437; } template IntValue5437() { int IntValue5437 = 10; } void test5437() { enum Foo { A, B } alias EnumMembers5437!Foo members; // OK enum n1 = members.length; // OK enum n2 = (EnumMembers5437!Foo).length; // NG, type -> symbol enum s1 = IntValue5437!().sizeof; // OK enum s2 = (IntValue5437!()).sizeof; // NG, type -> expression } /***************************************************/ // 1962 void test1962() { class C { abstract void x(); } assert(C.classinfo.create() is null); } /***************************************************/ // 6228 void test6228() { const(int)* ptr; const(int) temp; auto x = (*ptr) ^^ temp; } /***************************************************/ int test7544() { try { throw new Exception(""); } catch (Exception e) static assert(1); return 1; } static assert(test7544()); /***************************************************/ struct S6230 { int p; int q() const pure { return p; } void r() pure { p = 231; } } class C6230 { int p; int q() const pure { return p; } void r() pure { p = 552; } } int q6230(ref const S6230 s) pure { // <-- Currently OK return s.p; } int q6230(ref const C6230 c) pure { // <-- Currently OK return c.p; } void r6230(ref S6230 s) pure { s.p = 244; } void r6230(ref C6230 c) pure { c.p = 156; } bool test6230pure() pure { auto s = S6230(4); assert(s.p == 4); assert(q6230(s) == 4); assert(s.q == 4); auto c = new C6230; c.p = 6; assert(q6230(c) == 6); assert(c.q == 6); r6230(s); assert(s.p == 244); s.r(); assert(s.p == 231); r6230(c); assert(c.p == 156); c.r(); assert(c.p == 552); return true; } void test6230() { assert(test6230pure()); } /***************************************************/ void test6264() { struct S { auto opSlice() { return this; } } int[] a; S s; static assert(!is(typeof(a[] = s[]))); int*[] b; static assert(is(typeof(b[] = [new immutable(int)]))); char[] c = new char[](5); c[] = "hello"; } /***************************************************/ // 5046 void test5046() { auto va = S5046!("", int)(); auto vb = makeS5046!("", int)(); } struct S5046(alias p, T) { T s; T fun() { return s; } // (10) } S5046!(p, T) makeS5046(alias p, T)() { return typeof(return)(); } /***************************************************/ // 6335 struct S6335 { const int value; this()(int n){ value = n; } } void test6335() { S6335 s = S6335(10); } /***************************************************/ struct S6295(int N) { int[N] x; const nothrow pure @safe f() { return x.length; } } void test6295() { auto bar(T: S6295!(N), int N)(T x) { return x.f(); } S6295!4 x; assert(bar(x) == 4); } /***************************************************/ template TT4536(T...) { alias T TT4536; } void test4536() { auto x = TT4536!(int, long, [1, 2]).init; assert(x[0] is int.init); assert(x[1] is long.init); assert(x[2] is [1, 2].init); } /***************************************************/ struct S6284 { int a; } class C6284 { int a; } pure int bug6284a() { S6284 s = {4}; auto b = s.a; // ok with (s) { b += a; // should be ok. } return b; } pure int bug6284b() { auto s = new S6284; s.a = 4; auto b = s.a; with (*s) { b += a; } return b; } pure int bug6284c() { auto s = new C6284; s.a = 4; auto b = s.a; with (s) { b += a; } return b; } void test6284() { assert(bug6284a() == 8); assert(bug6284b() == 8); assert(bug6284c() == 8); } /***************************************************/ class C6293 { C6293 token; } void f6293(in C6293[] a) pure { auto x0 = a[0].token; assert(x0 is a[0].token.token.token); assert(x0 is (&x0).token); auto p1 = &x0 + 1; assert(x0 is (p1 - 1).token); int c = 0; assert(x0 is a[c].token); } void test6293() { auto x = new C6293; x.token = x; f6293([x]); } /***************************************************/ // 3733 class C3733 { int foo() { return 1; } int foo() shared { return 2; } int bar() { return foo(); } } void test3733() { auto c = new C3733(); assert(c.bar() == 1); } /***************************************************/ // 4392 class C4392 { int foo() const { return 1; } int foo() { return 2; } int bar() const { return foo(); } } void test4392() { auto c = new C4392(); assert(c.bar() == 1); } /***************************************************/ // 6220 void test6220() { struct Foobar { real x; real y; real z;}; switch("x") { foreach(i,member; __traits(allMembers, Foobar)) { case member : break; } default : break; } } /***************************************************/ // 5799 void test5799() { int a; int *u = &(a ? a : (a ? a : a)); assert(u == &a); } /***************************************************/ // 6529 enum Foo6529 : char { A='a' } ref const(Foo6529) func6529(const(Foo6529)[] arr){ return arr[0]; } /***************************************************/ void test783() { const arr = [ 1,2,3 ]; const i = 2; auto jhk = new int[arr[i]]; // "need size of rightmost array, not type arr[i]" } /***************************************************/ template X157(alias x) { alias x X157; } template Parent(alias foo) { alias X157!(__traits(parent, foo)) Parent; } template ParameterTypeTuple(alias foo) { static if (is(typeof(foo) P == function)) alias P ParameterTypeTuple; else static assert(0, "argument has no parameters"); } template Mfp(alias foo) { auto Mfp = function(Parent!foo self, ParameterTypeTuple!foo i) { return self.foo(i); }; } class C157 { int a = 3; int foo(int i, int y) { return i + a + y; } } void test157() { auto c = new C157(); auto mfp = Mfp!(C157.foo); auto i = mfp(c, 1, 7); assert(i == 11); } /***************************************************/ // 6473 struct Eins6473 { ~this() {} } struct Zwei6473 { void build(Eins6473 devices = Eins6473()) { } } void build(Eins6473 devices = Eins6473()) {} void test6473() { void build(Eins6473 devices = Eins6473()) {} } /***************************************************/ uint rol11417(uint n)(in uint x) { return x << n | x >> 32 - n; } uint ror11417(uint n)(in uint x) { return x >> n | x << 32 - n; } void test11417() { assert(rol11417!1(0x8000_0000) == 0x1); assert(ror11417!1(0x1) == 0x8000_0000); } /***************************************************/ void test6578() { static struct Foo { this(int x) pure {} } auto f1 = new const(Foo)(1); auto f2 = new immutable(Foo)(1); auto f3 = new shared(Foo)(1); auto f4 = const(Foo)(1); auto f5 = immutable(Foo)(1); auto f6 = shared(Foo)(1); static assert(is(typeof(f1) == const(Foo)*)); static assert(is(typeof(f2) == immutable(Foo)*)); static assert(is(typeof(f3) == shared(Foo)*)); static assert(is(typeof(f4) == const(Foo))); static assert(is(typeof(f5) == immutable(Foo))); static assert(is(typeof(f6) == shared(Foo))); static struct Bar { this(int x) const pure {} } auto g1 = new const(Bar)(1); auto g2 = new immutable(Bar)(1); auto g3 = new shared(Bar)(1); auto g4 = const(Bar)(1); auto g5 = immutable(Bar)(1); auto g6 = shared(Bar)(1); static assert(is(typeof(g1) == const(Bar)*)); static assert(is(typeof(g2) == immutable(Bar)*)); static assert(is(typeof(g3) == shared(Bar)*)); static assert(is(typeof(g4) == const(Bar))); static assert(is(typeof(g5) == immutable(Bar))); static assert(is(typeof(g6) == shared(Bar))); static struct Baz { this()(int x) const pure {} } auto h1 = new const(Baz)(1); auto h2 = new immutable(Baz)(1); auto h3 = new shared(const(Baz))(1); auto h4 = const(Baz)(1); auto h5 = immutable(Baz)(1); auto h6 = shared(const(Baz))(1); static assert(is(typeof(h1) == const(Baz)*)); static assert(is(typeof(h2) == immutable(Baz)*)); static assert(is(typeof(h3) == shared(const(Baz))*)); static assert(is(typeof(h4) == const(Baz))); static assert(is(typeof(h5) == immutable(Baz))); static assert(is(typeof(h6) == shared(const(Baz)))); } /***************************************************/ // 6630 void test6630() { static class B {} static class A { this() { b = new B(); } B b; alias b this; } void fun(A a) { a = null; assert(a is null); } auto a = new A; assert(a.b !is null); fun(a); assert(a !is null); assert(a.b !is null); } /***************************************************/ int i199 = 1; void test199() { label: { int i199 = 2; } assert(i199 == 1); } /***************************************************/ // 6690 T useLazy6690(T)(lazy T val) { return val; // val is converted to delegate call, but it is typed as int delegate() - not @safe! } void test6690() @safe { useLazy6690(0); // Error: safe function 'test6690' cannot call system function 'useLazy6690' } /***************************************************/ template Hoge6691() { immutable static int[int] dict; immutable static int value; static this() { dict = [1:1, 2:2]; value = 10; } } alias Hoge6691!() H6691; /***************************************************/ void test10626() { double[2] v, x; struct Y { double u; } double z; Y y; double[2] r = v[] * x[0]; //double[2] s = v[] * z++; //double[2] t = v[] * z--; double[2] a = v[] * ++z; double[2] b = v[] * --z; double[2] c = v[] * y.u; double[2] d = v[] * (x[] = 3, x[0]); double[2] e = v[] * (v[] ~ z)[0]; } /***************************************************/ // 2953 template Tuple2953(T...) { alias T Tuple2953; } template Range2953(int b) { alias Tuple2953!(1) Range2953; } void foo2953()() { Tuple2953!(int, int) args; foreach( x ; Range2953!(args.length) ){ } } void test2953() { foo2953!()(); } /***************************************************/ // 2997 abstract class B2997 { void foo(); } interface I2997 { void bar(); } abstract class C2997 : B2997, I2997 {} //pragma(msg, __traits(allMembers, C).stringof); void test2997() { enum ObjectMembers = ["toString","toHash","opCmp","opEquals","Monitor","factory"]; static assert([__traits(allMembers, C2997)] == ["foo"] ~ ObjectMembers ~ ["bar"]); } /***************************************************/ // 6596 extern (C) int function() pfunc6596; extern (C) int cfunc6596(){ return 0; } static assert(typeof(pfunc6596).stringof == "extern (C) int function()"); static assert(typeof(cfunc6596).stringof == "extern (C) int()"); /***************************************************/ // 4423 struct S4423 { this(string phrase, int num) { this.phrase = phrase; this.num = num; } int opCmp(const ref S4423 rhs) { if (phrase < rhs.phrase) return -1; else if (phrase > rhs.phrase) return 1; if (num < rhs.num) return -1; else if (num > rhs.num) return 1; return 0; } string phrase; int num; } enum E4423 : S4423 { a = S4423("hello", 1), b = S4423("goodbye", 45), c = S4423("world", 22), }; void test4423() { E4423 e; assert(e.phrase == "hello"); e = E4423.b; assert(e.phrase == "goodbye"); } /***************************************************/ // 4647 interface Timer { final int run() { printf("Timer.run()\n"); fun(); return 1; }; int fun(); } interface Application { final int run() { printf("Application.run()\n"); fun(); return 2; }; int fun(); } class TimedApp : Timer, Application { int funCalls; override int fun() { printf("TimedApp.fun()\n"); funCalls++; return 2; } } class SubTimedApp : TimedApp { int subFunCalls; override int fun() { printf("SubTimedApp.fun()\n"); subFunCalls++; return 1; } } void test4647() { //Test access to TimedApps base interfaces auto app = new TimedApp(); assert((cast(Application)app).run() == 2); assert((cast(Timer)app).run() == 1); assert(app.Timer.run() == 1); // error, no Timer property assert(app.Application.run() == 2); // error, no Application property assert(app.run() == 1); // This would call Timer.run() if the two calls // above were commented out assert(app.funCalls == 5); assert(app.TimedApp.fun() == 2); assert(app.funCalls == 6); //Test direct access to SubTimedApp interfaces auto app2 = new SubTimedApp(); assert((cast(Application)app2).run() == 2); assert((cast(Timer)app2).run() == 1); assert(app2.Application.run() == 2); assert(app2.Timer.run() == 1); assert(app2.funCalls == 0); assert(app2.subFunCalls == 4); assert(app2.fun() == 1); assert(app2.SubTimedApp.fun() == 1); assert(app2.funCalls == 0); assert(app2.subFunCalls == 6); //Test access to SubTimedApp interfaces via TimedApp auto app3 = new SubTimedApp(); (cast(Timer)cast(TimedApp)app3).run(); app3.TimedApp.Timer.run(); assert((cast(Application)cast(TimedApp)app3).run() == 2); assert((cast(Timer)cast(TimedApp)app3).run() == 1); assert(app3.TimedApp.Application.run() == 2); assert(app3.TimedApp.Timer.run() == 1); assert(app3.funCalls == 0); assert(app3.subFunCalls == 6); } /***************************************************/ template T1064(E...) { alias E T1064; } int[] var1064 = [ T1064!(T1064!(T1064!(1, 2), T1064!(), T1064!(3)), T1064!(4, T1064!(T1064!(T1064!(T1064!(5)))), T1064!(T1064!(T1064!(T1064!())))),6) ]; void test1064() { assert(var1064 == [1,2,3,4,5,6]); } /***************************************************/ // 5696 template Seq5696(T...){ alias T Seq5696; } template Pred5696(T) { alias T Pred5696; } // TOKtemplate template Scope5696(int n){ template X(T) { alias T X; } } // TOKimport T foo5696(T)(T x) { return x; } void test5696() { foreach (pred; Seq5696!(Pred5696, Pred5696)) { static assert(is(pred!int == int)); } foreach (scop; Seq5696!(Scope5696!0, Scope5696!1)) { static assert(is(scop.X!int == int)); } alias Seq5696!(foo5696, foo5696) funcs; assert(funcs[0](0) == 0); assert(funcs[1](1) == 1); foreach (i, fn; funcs) { assert(fn(i) == i); } } /***************************************************/ // 5933 int dummyfunc5933(); alias typeof(dummyfunc5933) FuncType5933; struct S5933a { auto x() { return 0; } } static assert(is(typeof(&S5933a.init.x) == int delegate() pure nothrow @nogc @safe)); struct S5933b { auto x() { return 0; } } //static assert(is(typeof(S5933b.init.x) == FuncType5933)); struct S5933c { auto x() { return 0; } } static assert(is(typeof(&S5933c.x) == int function())); struct S5933d { auto x() { return 0; } } static assert(is(typeof(S5933d.x) == FuncType5933)); class C5933a { auto x() { return 0; } } static assert(is(typeof(&(new C5933b()).x) == int delegate() pure nothrow @nogc @safe)); class C5933b { auto x() { return 0; } } //static assert(is(typeof((new C5933b()).x) == FuncType5933)); class C5933c { auto x() { return 0; } } static assert(is(typeof(&C5933c.x) == int function())); class C5933d { auto x() { return 0; } } static assert(is(typeof(C5933d.x) == FuncType5933)); /***************************************************/ // 6084 template TypeTuple6084(T...){ alias T TypeTuple6084; } void test6084() { int foo(int x)() { return x; } foreach(i; TypeTuple6084!(0)) foo!(i); } /***************************************************/ // 6763 template TypeTuple6763(TList...) { alias TList TypeTuple6763; } alias TypeTuple6763!(int) T6763; void f6763( T6763) { } /// void c6763(const T6763) { } ///T now is (const int) void r6763(ref T6763) { } ///T now is(ref const int) void i6763(in T6763) { } ///Uncomment to get an Assertion failure in 'mtype.c' void o6763(out T6763) { } ///ditto void test6763() { int n; f6763(0); //With D2: Error: function main.f ((ref const const(int) _param_0)) is not callable using argument types (int) c6763(0); r6763(n); static assert(!__traits(compiles, r6763(0))); i6763(0); o6763(n); static assert(!__traits(compiles, o6763(0))); // 6755 static assert(typeof(f6763).stringof == "void(int _param_0)"); static assert(typeof(c6763).stringof == "void(const(int) _param_0)"); static assert(typeof(r6763).stringof == "void(ref int _param_0)"); static assert(typeof(i6763).stringof == "void(const(int) _param_0)"); static assert(typeof(o6763).stringof == "void(out int _param_0)"); } /***************************************************/ // 6695 struct X6695 { void mfunc() { static assert(is(typeof(this) == X6695)); } void cfunc() const { static assert(is(typeof(this) == const(X6695))); } void ifunc() immutable { static assert(is(typeof(this) == immutable(X6695))); } void sfunc() shared { static assert(is(typeof(this) == shared(X6695))); } void scfunc() shared const { static assert(is(typeof(this) == shared(const(X6695)))); } void wfunc() inout { static assert(is(typeof(this) == inout(X6695))); } void swfunc() shared inout { static assert(is(typeof(this) == shared(inout(X6695)))); } static assert(is(typeof(this) == X6695)); } /***************************************************/ // 6087 template True6087(T) { immutable True6087 = true; } struct Foo6087 { static assert( True6087!(typeof(this)) ); } struct Bar6087 { static assert( is(typeof(this) == Bar6087) ); } /***************************************************/ // 6848 class Foo6848 {} class Bar6848 : Foo6848 { void func() immutable { static assert(is(typeof(this) == immutable(Bar6848))); // immutable(Bar6848) auto t = this; static assert(is(typeof(t) == immutable(Bar6848))); // immutable(Bar6848) static assert(is(typeof(super) == immutable(Foo6848))); // Foo6848 instead of immutable(Foo6848) auto s = super; static assert(is(typeof(s) == immutable(Foo6848))); // Foo6848 instead of immutable(Foo6848) } } /***************************************************/ version(none) { cent issue785; ucent issue785; } static assert(is(cent) && is(ucent) || !is(cent) && !is(ucent)); static if (is(cent)) static assert(__traits(compiles, { cent x; })); else static assert(!__traits(compiles, { cent x; })); /***************************************************/ // 6847 template True6847(T) { immutable True6847 = true; } class Foo6847 {} class Bar6847 : Foo6847 { static assert( True6847!(typeof(super)) ); static assert( is(typeof(super) == Foo6847) ); } /***************************************************/ // http://d.puremagic.com/issues/show_bug.cgi?id=6488 struct TickDuration { template to(T) if (__traits(isIntegral,T)) { const T to() { return 1; } } template to(T) if (__traits(isFloating,T)) { const T to() { return 0; } } const long seconds() { return to!(long)(); } } void test6488() { TickDuration d; d.seconds(); } /***************************************************/ // 6565 void foo6565(out int[2][2] m) {} void test6565() { int[2][2] mat = [[1, 2], [3, 4]]; foo6565(mat); assert(mat == [[0, 0], [0, 0]]); } /***************************************************/ // 6836 template map6836(fun...) if (fun.length >= 1) { auto map6836(Range)(Range r) { } } void test6836() { [1].map6836!"a"(); } /***************************************************/ string func12864() { return ['a', 'b', 'c']; } void test12864(string s) { switch (s) { case func12864(): break; default: break; } } /***************************************************/ void test5448() { int[int][] aaa = [[1: 2]]; int[string][] a2 = [["cc":0], ["DD":10]]; } /***************************************************/ // 6837 struct Ref6837a(T) { T storage; alias storage this; } struct Ref6837b(T) { T storage; @property ref T get(){ return storage; } alias get this; } int front6837(int[] arr){ return arr[0]; } void popFront6837(ref int[] arr){ arr = arr[1..$]; } void test6837() { assert([1,2,3].front6837 == 1); auto r1 = Ref6837a!(int[])([1,2,3]); assert(r1.front6837() == 1); // ng assert(r1.front6837 == 1); // ok r1.popFront6837(); // ng r1.storage.popFront6837(); // ok auto r2 = Ref6837b!(int[])([1,2,3]); assert(r2.front6837() == 1); // ng assert(r2.front6837 == 1); // ok r2.popFront6837(); // ng r2.get.popFront6837(); // ng r2.get().popFront6837(); // ok } /***************************************************/ // 6927 @property int[] foo6927() { return [1, 2]; } int[] bar6927(int[] a) { return a; } void test6927() { bar6927(foo6927); // OK foo6927.bar6927(); // line 9, Error } /***************************************************/ struct Foo6813(T) { Foo6813 Bar() { return Foo6813(_indices.abc()); } T _indices; } struct SortedRange(alias pred) { SortedRange abc() { return SortedRange(); } } void test6813() { auto ind = SortedRange!({ })(); auto a = Foo6813!(typeof(ind))(); } /***************************************************/ struct Interval6753{ int a,b; } @safe struct S6753 { int[] arr; @trusted @property auto byInterval() const { return cast(const(Interval6753)[])arr; } } /***************************************************/ // 6859 class Parent6859 { public: bool isHage() const @property; public: abstract void fuga() out { assert(isHage); } body { } } class Child6859 : Parent6859 { override bool isHage() const @property { return true; } override void fuga() { //nop } } void test6859() { auto t = new Child6859; t.fuga(); printf("done.\n"); } /***************************************************/ // 6910 template Test6910(alias i, B) { void fn() { foreach(t; B.Types) { switch(i) { case 0://IndexOf!(t, B.Types): { pragma(msg, __traits(allMembers, t)); pragma(msg, __traits(hasMember, t, "m")); static assert(__traits(hasMember, t, "m")); // test break; } default: {} } } } } void test6910() { static struct Bag(S...) { alias S Types; } static struct A { int m; } int i; alias Test6910!(i, Bag!(A)).fn func; } /***************************************************/ void fun12503() { string b = "abc"; try { try { b = null; return; } catch { } } finally { assert("abc" !is b); } } void test12503() { fun12503(); } /***************************************************/ // 6902 void test6902() { static assert(is(typeof({ return int.init; // int, long, real, etc. }))); int f() pure nothrow { assert(0); } alias int T() pure nothrow; static if(is(typeof(&f) DT == delegate)) { static assert(is(DT* == T*)); // ok // Error: static assert (is(pure nothrow int() == pure nothrow int())) is false static assert(is(DT == T)); } } /***************************************************/ // 6330 struct S6330 { void opAssign(S6330 s) @disable { assert(0); // This fails. } } void test6330() { S6330 s; S6330 s2; static assert(!is(typeof({ s2 = s; }))); } /***************************************************/ struct S8269 { bool dtor = false; ~this() { dtor = true; } } void test8269() { with(S8269()) { assert(!dtor); } } /***************************************************/ // 5311 class C5311 { private static int globalData; void breaksPure() pure const { static assert(!__traits(compiles, { globalData++; })); // SHOULD BE ERROR static assert(!__traits(compiles, { C5311.globalData++; }));// SHOULD BE ERROR static assert(!__traits(compiles, { this.globalData++; })); // SHOULD BE ERROR static assert(!__traits(compiles, { int a = this.globalData; })); } } static void breaksPure5311a(C5311 x) pure { static assert(!__traits(compiles, { x.globalData++; })); // SHOULD BE ERROR static assert(!__traits(compiles, { int a = x.globalData; })); } struct S5311 { private static int globalData; void breaksPure() pure const { static assert(!__traits(compiles, { globalData++; })); // SHOULD BE ERROR static assert(!__traits(compiles, { S5311.globalData++; }));// SHOULD BE ERROR static assert(!__traits(compiles, { this.globalData++; })); // SHOULD BE ERROR static assert(!__traits(compiles, { int a = this.globalData; })); } } static void breaksPure5311b(S5311 x) pure { static assert(!__traits(compiles, { x.globalData++; })); // SHOULD BE ERROR static assert(!__traits(compiles, { int a = x.globalData; })); } /***************************************************/ // 6868 @property bool empty6868(T)(in T[] a) @safe pure nothrow { return !a.length; } void test6868() { alias int[] Range; static if (is(char[1 + Range.empty6868])) // Line 9 enum bool isInfinite = true; char[0] s; // need } /***************************************************/ // 2856 struct foo2856 { static void opIndex(int i) { printf("foo\n"); } } struct bar2856(T) { static void opIndex(int i) { printf("bar\n"); } } void test2856() { foo2856[1]; bar2856!(float)[1]; // Error (# = __LINE__) alias bar2856!(float) B; B[1]; // Okay } /***************************************************/ void test13947() { struct S {} static assert(S.sizeof == 1); S a; S b; *cast(ubyte*)&a = 1; *cast(ubyte*)&b = 2; assert(a == b); assert(a is b); assert(!(a != b)); assert(!(a !is b)); static assert(S() == S()); static assert(S() is S()); static assert(!(S() != S())); static assert(!(S() !is S())); } /***************************************************/ // 3091 void test3091(inout int = 0) { struct Foo {} auto pm = new Foo; static assert(is( typeof( pm) == Foo * )); auto pc = new const Foo; static assert(is( typeof( pc) == const(Foo) * )); auto pw = new inout Foo; static assert(is( typeof( pw) == inout(Foo) * )); auto psm = new shared Foo; static assert(is( typeof(psm) == shared(Foo) * )); auto psc = new shared const Foo; static assert(is( typeof(psc) == shared(const(Foo))* )); auto psw = new shared inout Foo; static assert(is( typeof(psw) == shared(inout(Foo))* )); auto pi = new immutable Foo; static assert(is( typeof( pi) == immutable(Foo) * )); auto m = Foo(); static assert(is( typeof( m) == Foo )); auto c = const Foo(); static assert(is( typeof( c) == const(Foo) )); auto w = inout Foo(); static assert(is( typeof( w) == inout(Foo) )); auto sm = shared Foo(); static assert(is( typeof(sm) == shared(Foo) )); auto sc = shared const Foo(); static assert(is( typeof(sc) == shared(const(Foo)) )); auto sw = shared inout Foo(); static assert(is( typeof(sw) == shared(inout(Foo)) )); auto i = immutable Foo(); static assert(is( typeof( i) == immutable(Foo) )); } /***************************************************/ // 6837 template Id6837(T) { alias T Id6837; } static assert(is(Id6837!(shared const int) == shared const int)); static assert(is(Id6837!(shared inout int) == shared inout int)); /***************************************************/ // 6056 fixup template ParameterTypeTuple6056(func) { static if (is(func Fptr : Fptr*) && is(Fptr P == function)) alias P ParameterTypeTuple6056; else static assert(0, "argument has no parameters"); } extern(C) alias void function() fpw_t; alias void function(fpw_t fp) cb_t; void bar6056(ParameterTypeTuple6056!(cb_t) args) { pragma (msg, "TFunction1: " ~ typeof(args[0]).stringof); } extern(C) void foo6056() { } void test6056() { bar6056(&foo6056); } /***************************************************/ // 6356 int f6356()(int a) { return a*a; } alias f6356!() g6356; // comment this out to eliminate the errors pure nothrow @safe int i6356() { return f6356(1); } void test6356() { assert(i6356() == 1); } /***************************************************/ // 7108 static assert(!__traits(hasMember, int, "x")); static assert( __traits(hasMember, int, "init")); /***************************************************/ // 7073 void test7073() { string f(int[] arr...) { return ""; } } /***************************************************/ // 7104 void test7104() { typeof(new class {}) c; c = new typeof(c); } /***************************************************/ // 7150 struct A7150 { static int cnt; this(T)(T thing, int i) { this(thing, i > 0); // Error: constructor call must be in a constructor ++cnt; } this(T)(T thing, bool b) { ++cnt; } } void test7150() { auto a = A7150(5, 5); // Error: template instance constructtest.A.__ctor!(int) error instantiating assert(A7150.cnt == 2); } /***************************************************/ // 7159 alias void delegate() Void7159; class HomeController7159 { Void7159 foo() { return cast(Void7159)&HomeController7159.displayDefault; } auto displayDefault() { return 1; } } /***************************************************/ // 7160 class HomeController { static if (false) { mixin(q{ int a; }); } void foo() { foreach (m; __traits(derivedMembers, HomeController)) { } } } void test7160() {} /***************************************************/ // 7168 void test7168() { static class X { void foo(){} } static class Y : X { void bar(){} } enum ObjectMembers = ["toString","toHash","opCmp","opEquals","Monitor","factory"]; static assert([__traits(allMembers, X)] == ["foo"]~ObjectMembers); // pass static assert([__traits(allMembers, Y)] == ["bar", "foo"]~ObjectMembers); // fail static assert([__traits(allMembers, Y)] != ["bar", "foo"]); // fail } /***************************************************/ // 7170 T to7170(T)(string x) { return 1; } void test7170() { // auto i = to7170!int("1"); // OK auto j = "1".to7170!int(); // NG, Internal error: e2ir.c 683 } /***************************************************/ // 7196 auto foo7196(int x){return x;} auto foo7196(double x){return x;} void test7196() { auto x = (&foo7196)(1); // ok auto y = (&foo7196)(1.0); // fail } /***************************************************/ // 7285 int[2] spam7285() { int[2] ab; if (true) return (true) ? ab : [0, 0]; // Error else return (true) ? [0, 0] : ab; // OK } void test7285() { auto sa = spam7285(); } /***************************************************/ // 14737 void test14737() { // compile-time enum string[2] a1 = ["d", "e"]; enum b1x = ["a", "b", "c"] ~ a1; // Tarray vs Tsarray enum b1y = a1 ~ ["a", "b", "c"]; // Tsarray vs Tarray static assert(is(typeof(b1x) == string[])); static assert(is(typeof(b1y) == string[])); static assert(b1x == ["a", "b", "c", "d", "e"]); static assert(b1y == ["d", "e", "a", "b", "c"]); // runtime string[2] a2 = ["d", "e"]; auto b2x = ["a", "b", "c"] ~ a2; // Tarray vs Tsarray auto b2y = a2 ~ ["a", "b", "c"]; // Tsarray vs Tarray static assert(is(typeof(b2x) == string[])); static assert(is(typeof(b2y) == string[])); assert(b2x == ["a", "b", "c", "d", "e"]); assert(b2y == ["d", "e", "a", "b", "c"]); } /***************************************************/ // 7321 void test7321() { static assert(is(typeof((){})==void function()pure nothrow @nogc @safe)); // ok static assert(is(typeof((){return;})==void function()pure nothrow @nogc @safe)); // fail } /***************************************************/ class A158 { pure void foo1() { } const void foo2() { } nothrow void foo3() { } @safe void foo4() { } } class B158 : A158 { override void foo1() { } override void foo2() const { } override void foo3() { } override void foo4() { } } /***************************************************/ // 9231 class B9231 { void foo() inout pure {} } class D9231 : B9231 { override void foo() inout {} } /***************************************************/ // 3282 class Base3282 { string f() { return "Base.f()"; } } class Derived3282 : Base3282 { override string f() { return "Derived.f()"; } /*override*/ string f() const { return "Derived.f() const"; } } void test3282() { auto x = new Base3282; assert(x.f() == "Base.f()"); auto y = new Derived3282; assert(y.f() == "Derived.f()");// calls "Derived.f() const", but it is expected that be called non-const. auto z = new const(Derived3282); assert(z.f() == "Derived.f() const"); } /***************************************************/ // 7534 class C7534 { int foo(){ return 1; } } class D7534 : C7534 { override int foo(){ return 2; } /*override*/ int foo() const { return 3; } // Error: D.foo multiple overrides of same function } void test7534() { C7534 mc = new C7534(); assert(mc.foo() == 1); D7534 md = new D7534(); assert(md.foo() == 2); mc = md; assert(mc.foo() == 2); const(D7534) cd = new const(D7534)(); assert(cd.foo() == 3); md = cast()cd; assert(md.foo() == 2); } /***************************************************/ // 7534 + return type covariance class X7534 {} class Y7534 : X7534 { int value; this(int n){ value = n; } } class V7534 { X7534 foo(){ return new X7534(); } } class W7534 : V7534 { override Y7534 foo(){ return new Y7534(1); } /*override*/ Y7534 foo() const { return new Y7534(2); } } void test7534cov() { auto mv = new V7534(); assert(typeid(mv.foo()) == typeid(X7534)); auto mw = new W7534(); assert(typeid(mw.foo()) == typeid(Y7534)); assert(mw.foo().value == 1); mv = mw; assert(typeid(mv.foo()) == typeid(Y7534)); assert((cast(Y7534)mv.foo()).value == 1); auto cw = new const(W7534)(); assert(typeid(cw.foo()) == typeid(Y7534)); assert(cw.foo().value == 2); } /***************************************************/ // 7562 static struct MyInt { private int value; mixin ProxyOf!value; } mixin template ProxyOf(alias a) { template X1(){} template X2(){} template X3(){} template X4(){} template X5(){} template X6(){} template X7(){} template X8(){} template X9(){} template X10(){} void test1(this X)(){} void test2(this Y)(){} } /***************************************************/ import core.stdc.stdlib; void test13427(void* buffer = alloca(100)) { } /***************************************************/ // 7583 template Tup7583(E...) { alias E Tup7583; } struct S7583 { Tup7583!(float, char) field; alias field this; this(int x) { } } int bug7583() { S7583[] arr; arr ~= S7583(0); return 1; } static assert (bug7583()); /***************************************************/ // 7618 void test7618(const int x = 1) { int func(ref int x) { return 1; } static assert(!__traits(compiles, func(x))); // Error: function test.foo.func (ref int _param_0) is not callable using argument types (const(int)) int delegate(ref int) dg = (ref int x) => 1; static assert(!__traits(compiles, dg(x))); // --> no error, bad! int function(ref int) fp = (ref int x) => 1; static assert(!__traits(compiles, fp(x))); // --> no error, bad! } /***************************************************/ // 7621 void test7621() { enum uint N = 4u; char[] A = "hello".dup; uint[immutable char[4u]] dict; dict[*cast(immutable char[4]*)(A[0 .. N].ptr)] = 0; // OK dict[*cast(immutable char[N]*)(A[0 .. N].ptr)] = 0; // line 6, error } /***************************************************/ // 7682 template ConstOf7682(T) { alias const(T) ConstOf7682; } bool pointsTo7682(S)(ref const S source) @trusted pure nothrow { return true; } void test7682() { shared(ConstOf7682!(int[])) x; // line A struct S3 { int[10] a; } shared(S3) sh3; shared(int[]) sh3sub = sh3.a[]; assert(pointsTo7682(sh3sub)); // line B } /***************************************************/ // 7735 void a7735(void[][] data...) { //writeln(data); assert(data.length == 1); b7735(data); } void b7735(void[][] data...) { //writeln(data); assert(data.length == 1); c7735(data); } void c7735(void[][] data...) { //writeln(data); assert(data.length == 1); } void test7735() { a7735([]); a7735([]); } /***************************************************/ struct A7823 { long a; enum A7823 b = {0}; } void test7823(A7823 a = A7823.b) { } /***************************************************/ // 7871 struct Tuple7871 { string field; alias field this; } //auto findSplitBefore(R1)(R1 haystack) auto findSplitBefore7871(string haystack) { return Tuple7871(haystack); } void test7871() { string line = ``; auto a = findSplitBefore7871(line[0 .. $])[0]; } /***************************************************/ // 7906 void test7906() { static assert(!__traits(compiles, { enum s = [string.min]; })); } /***************************************************/ // 7907 template Id7907(E) { alias E Id7907; } template Id7907(alias E) { alias E Id7907; } void test7907() { static assert(!__traits(compiles, { alias Id7907!([string.min]) X; })); } /***************************************************/ // 1175 class A1175 { class I1 { } } class B1175 : A1175 { class I2 : I1 { } I1 getI() { return new I2; } } /***************************************************/ // 7983 class A7983 { void f() { g7983(this); } unittest { } } void g7983(T)(T a) { foreach (name; __traits(allMembers, T)) { pragma(msg, name); static if (__traits(compiles, &__traits(getMember, a, name))) { } } } /***************************************************/ // 8004 void test8004() { auto n = (int n = 10){ return n; }(); assert(n == 10); } /***************************************************/ // 8064 void test8064() { uint[5] arry; ref uint acc(size_t i) { return arry[i]; } auto arryacc = &acc; arryacc(3) = 5; // same error } /***************************************************/ // 8220 void foo8220(int){} static assert(!__traits(compiles, foo8220(typeof(0)))); // fail /***************************************************/ void func8105(in ref int x) { } void test8105() { } /***************************************************/ template ParameterTypeTuple159(alias foo) { static if (is(typeof(foo) P == __parameters)) alias P ParameterTypeTuple159; else static assert(0, "argument has no parameters"); } int func159(int i, long j = 7) { return 3; } alias ParameterTypeTuple159!func159 PT; int bar159(PT) { return 4; } pragma(msg, typeof(bar159)); pragma(msg, PT[1]); PT[1] boo159(PT[1..2] a) { return a[0]; } void test159() { assert(bar159(1) == 4); assert(boo159() == 7); } /***************************************************/ // 8283 struct Foo8283 { this(long) { } } struct FooContainer { Foo8283 value; } auto get8283() { union Buf { FooContainer result; } Buf buf = {}; return buf.result; } void test8283() { auto a = get8283(); } /***************************************************/ // 8395 struct S8395 { int v; this(T : long)(T x) { v = x * 2; } } void test8395() { S8395 ms = 6; assert(ms.v == 12); const S8395 cs = 7; assert(cs.v == 14); } /***************************************************/ // 5749 void test5749() { static struct A { A foo(int x, int i) { //printf("this = %p, %d: i=%d\n", &this, x, i); assert(i == x); return this; } A bar(int x, ref int i) { //printf("this = %p, %d: i=%d\n", &this, x, i); assert(i == x); return this; } } static int inc1(ref int i) { return ++i; } static ref int inc2(ref int i) { return ++i; } int i; A a; //printf("&a = %p\n", &a); i = 0; a.foo(1, ++i).foo(2, ++i); // OK <-- 2 1 i = 0; a.bar(1, ++i).bar(2, ++i); // OK <-- 2 2 i = 0; a.foo(1, inc1(i)).foo(2, inc1(i)); // OK <-- 2 1 i = 0; a.bar(1, inc2(i)).bar(2, inc2(i)); // OK <-- 2 2 //printf("\n"); A getVal() { static A a; return a; } i = 0; getVal().foo(1, ++i).foo(2, ++i); // OK <-- 2 1 i = 0; getVal().bar(1, ++i).bar(2, ++i); // OK <-- 2 2 i = 0; getVal().foo(1, inc1(i)).foo(2, inc1(i)); // OK <-- 2 1 i = 0; getVal().bar(1, inc2(i)).bar(2, inc2(i)); // OK <-- 2 2 //printf("\n"); ref A getRef() { static A a; return a; } i = 0; getRef().foo(1, ++i).foo(2, ++i); // OK <-- 2 1 i = 0; getRef().bar(1, ++i).bar(2, ++i); // OK <-- 2 2 i = 0; getRef().foo(1, inc1(i)).foo(2, inc1(i)); // OK <-- 2 1 i = 0; getRef().bar(1, inc2(i)).bar(2, inc2(i)); // OK <-- 2 2 } /***************************************************/ // 8396 void test8396() { static int g; static extern(C) int bar(int a, int b) { //printf("a = %d, b = %d\n", a, b); assert(b - a == 1); return ++g; } static auto getFunc(int n) { assert(++g == n); return &bar; } static struct Tuple { int _a, _b; } static Tuple foo(int n) { assert(++g == n); return Tuple(1, 2); } g = 0; assert(bar(foo(1).tupleof) == 2); g = 0; assert(getFunc(1)(foo(2).tupleof) == 3); } /***************************************************/ enum E160 : ubyte { jan = 1 } struct D160 { short _year = 1; E160 _month = E160.jan; ubyte _day = 1; this(int year, int month, int day) pure { _year = cast(short)year; _month = cast(E160)month; _day = cast(ubyte)day; } } struct T160 { ubyte _hour; ubyte _minute; ubyte _second; this(int hour, int minute, int second = 0) pure { _hour = cast(ubyte)hour; _minute = cast(ubyte)minute; _second = cast(ubyte)second; } } struct DT160 { D160 _date; T160 _tod; this(int year, int month, int day, int hour = 0, int minute = 0, int second = 0) pure { _date = D160(year, month, day); _tod = T160(hour, minute, second); } } void foo160(DT160 dateTime) { printf("test7 year %d, day %d\n", dateTime._date._year, dateTime._date._day); assert(dateTime._date._year == 1999); assert(dateTime._date._day == 6); } void test160() { auto dateTime = DT160(1999, 7, 6, 12, 30, 33); printf("test5 year %d, day %d\n", dateTime._date._year, dateTime._date._day); assert(dateTime._date._year == 1999); assert(dateTime._date._day == 6); foo160(DT160(1999, 7, 6, 12, 30, 33)); } /***************************************************/ // 8437 class Cgi8437 { struct PostParserState { UploadedFile piece; } static struct UploadedFile { string contentFilename; } } /***************************************************/ // 8665 auto foo8665a(bool val) { if (val) return 42; else return 1.5; } auto foo8665b(bool val) { if (!val) return 1.5; else return 42; } void test8665() { static assert(is(typeof(foo8665a(true)) == double)); static assert(is(typeof(foo8665b(false)) == double)); assert(foo8665a(true) == 42); // assertion failure assert(foo8665b(true) == 42); // assertion failure assert(foo8665a(false) == 1.5); assert(foo8665b(false) == 1.5); static assert(foo8665a(true) == 42); static assert(foo8665b(true) == 42); static assert(foo8665a(false) == 1.5); static assert(foo8665b(false) == 1.5); } /***************************************************/ int foo8108(int, int); int foo8108(int a, int b) { return a + b; } void test8108() { foo8108(1,2); } /***************************************************/ // 8360 struct Foo8360 { int value = 0; int check = 1337; this(int value) { assert(0); this.value = value; } ~this() { assert(0); assert(check == 1337); } string str() { assert(0); return "Foo"; } } Foo8360 makeFoo8360() { assert(0); return Foo8360(2); } void test8360() { size_t length = 0; // The message part 'makeFoo().str()' should not be evaluated at all. assert(length < 5, makeFoo8360().str()); } /***************************************************/ // 8361 struct Foo8361 { string bar = "hello"; ~this() {} } void test8361() { assert(true, Foo8361().bar); } /***************************************************/ // 6141 + 8526 void test6141() { static void takeADelegate(void delegate()) {} auto items = new int[1]; items[0] = 17; foreach (ref item; items) { // both asserts fail assert(item == 17); assert(&item == items.ptr); takeADelegate({ auto x = &item; }); } foreach(ref val; [3]) { auto dg = { int j = val; }; assert(&val != null); // Assertion failure assert(val == 3); } static void f(lazy int) {} int i = 0; auto dg = { int j = i; }; foreach(ref val; [3]) { f(val); assert(&val != null); // Assertion failure assert(val == 3); } } void test8526() { static void call(void delegate() dg) { dg(); } foreach (i, j; [0]) { call({ assert(i == 0); // fails, i is corrupted }); } foreach (n; 0..1) { call({ assert(n == 0); // fails, n is corrupted }); } } /***************************************************/ template ParameterTuple(alias func) { static if(is(typeof(func) P == __parameters)) alias P ParameterTuple; else static assert(0); } int foo161(ref float y); void test161() { alias PT = ParameterTuple!foo161; auto x = __traits(identifier, PT); assert(x == "y"); } /***************************************************/ // 7175 void test7175() { struct S { ubyte[0] arr; } S s; assert(s.arr.ptr !is null); assert(cast(void*)s.arr.ptr is cast(void*)&s); } /***************************************************/ // 8819 void test8819() { void[1] sa1 = (void[1]).init; assert((cast(ubyte*)sa1.ptr)[0] == 0); void[4] sa4 = [cast(ubyte)1,cast(ubyte)2,cast(ubyte)3,cast(ubyte)4]; assert((cast(ubyte*)sa4.ptr)[0] == 1); assert((cast(ubyte*)sa4.ptr)[1] == 2); assert((cast(ubyte*)sa4.ptr)[2] == 3); assert((cast(ubyte*)sa4.ptr)[3] == 4); auto sa22 = (void[2][2]).init; static assert(sa22.sizeof == ubyte.sizeof * 2 * 2); ubyte[4]* psa22 = cast(ubyte[4]*)sa22.ptr; assert((*psa22)[0] == 0); assert((*psa22)[1] == 0); assert((*psa22)[2] == 0); assert((*psa22)[3] == 0); } /***************************************************/ // 8897 class C8897 { static mixin M8897!(int); static class causesAnError {} } template M8897 ( E ) { } /***************************************************/ // 8917 void test8917() { int[3] a; int[3] a2; int[3] b = a[] + a2[]; } /***************************************************/ // 8945 struct S8945 // or `class`, or `union` { struct S0(T) { int i; } struct S1(T) { this(int){} } } void test8945() { auto cs0a = const S8945.S0!int(); // ok auto cs0b = const S8945.S0!int(1); // ok auto cs1 = const S8945.S1!int(1); // ok auto s0a = S8945.S0!int(); // Error: struct S0 does not overload () auto s0b = S8945.S0!int(1); // Error: struct S0 does not overload () auto s1 = S8945.S1!int(1); // Error: struct S1 does not overload () } /***************************************************/ struct S162 { static int generateMethodStubs( Class )() { int text; foreach( m; __traits( allMembers, Class ) ) { static if( is( typeof( mixin( m ) ) ) && is( typeof( mixin( m ) ) == function ) ) { pragma(msg, __traits( getOverloads, Class, m )); } } return text; } enum int ttt = generateMethodStubs!( S162 )(); float height(); int get( int ); int get( long ); void clear(); void draw( int ); void draw( long ); } /***************************************************/ void test163() { static class C { int x; int y; } immutable C c = new C(); shared C c2 = new C(); shared const C c3 = new C(); class D { int x; int y; } immutable D d; assert(!__traits(compiles, d = new D())); static struct S { int x; int y; } immutable S* s = new S(); shared S* s2 = new S(); shared const S* s3 = new S(); shared S* s4; assert(__traits(compiles, s4 = new immutable(S)())); struct T { int x; int y; } immutable T* t; assert(!__traits(compiles, t = new T())); immutable int* pi = new int(); immutable void* pv = new int(); immutable int[] ai = new int[1]; immutable void[] av = new int[2]; } /***************************************************/ struct S9000 { ubyte i = ubyte.max; } enum E9000 = S9000.init; /***************************************************/ mixin template DefineCoreType(string type) { struct Faulty { static int x; static void instance() { x = 3; } X164!() xxx; } } mixin DefineCoreType!(""); mixin template A164() { static this() { } } struct X164() { mixin A164!(); } /***************************************************/ // 9428 void test9428() { int[2][] items = [[1, 2]]; int[2] x = [3, 4]; auto r1 = items ~ [x]; assert(r1.length == 2); assert(r1[0][0] == 1); assert(r1[0][1] == 2); assert(r1[1][0] == 3); assert(r1[1][1] == 4); auto r2 = items ~ x; assert(r2.length == 2); assert(r2[0][0] == 1); assert(r2[0][1] == 2); assert(r2[1][0] == 3); assert(r2[1][1] == 4); auto r3 = [x] ~ items; assert(r3.length == 2); assert(r3[0][0] == 3); assert(r3[0][1] == 4); assert(r3[1][0] == 1); assert(r3[1][1] == 2); auto r4 = x ~ items; assert(r4.length == 2); assert(r4[0][0] == 3); assert(r4[0][1] == 4); assert(r4[1][0] == 1); assert(r4[1][1] == 2); } /***************************************************/ // 9477 template Tuple9477(T...) { alias T Tuple9477; } template Select9477(bool b, T, U) { static if (b) alias T Select9477; else alias U Select9477; } void test9477() { static bool isEq (T1, T2)(T1 s1, T2 s2) { return s1 == s2; } static bool isNeq(T1, T2)(T1 s1, T2 s2) { return s1 != s2; } // Must be outside the loop due to http://d.puremagic.com/issues/show_bug.cgi?id=9748 int order; // Must be outside the loop due to http://d.puremagic.com/issues/show_bug.cgi?id=9756 auto checkOrder(bool dyn, uint expected)() { assert(order==expected); order++; // Use temporary ("v") to work around http://d.puremagic.com/issues/show_bug.cgi?id=9402 auto v = cast(Select9477!(dyn, string, char[1]))"a"; return v; } foreach (b1; Tuple9477!(false, true)) foreach (b2; Tuple9477!(false, true)) { version (D_PIC) {} else // Work around http://d.puremagic.com/issues/show_bug.cgi?id=9754 { assert( isEq (cast(Select9477!(b1, string, char[0]))"" , cast(Select9477!(b2, string, char[0]))"" )); assert(!isNeq(cast(Select9477!(b1, string, char[0]))"" , cast(Select9477!(b2, string, char[0]))"" )); assert(!isEq (cast(Select9477!(b1, string, char[0]))"" , cast(Select9477!(b2, string, char[1]))"a" )); assert( isNeq(cast(Select9477!(b1, string, char[0]))"" , cast(Select9477!(b2, string, char[1]))"a" )); } assert( isEq (cast(Select9477!(b1, string, char[1]))"a", cast(Select9477!(b2, string, char[1]))"a" )); assert(!isNeq(cast(Select9477!(b1, string, char[1]))"a", cast(Select9477!(b2, string, char[1]))"a" )); assert(!isEq (cast(Select9477!(b1, string, char[1]))"a", cast(Select9477!(b2, string, char[1]))"b" )); assert( isNeq(cast(Select9477!(b1, string, char[1]))"a", cast(Select9477!(b2, string, char[1]))"b" )); assert(!isEq (cast(Select9477!(b1, string, char[1]))"a", cast(Select9477!(b2, string, char[2]))"aa")); assert( isNeq(cast(Select9477!(b1, string, char[1]))"a", cast(Select9477!(b2, string, char[2]))"aa")); // Note: order of evaluation was not followed before this patch // (thus, the test below will fail without the patch). // Although the specification mentions that as implementation-defined behavior, // I understand that this isn't by design, but rather an inconvenient aspect of DMD // that has been moved to the specification. order = 0; bool result = checkOrder!(b1, 0)() == checkOrder!(b2, 1)(); assert(result); assert(order == 2); } // need largest natural alignment to avoid unaligned access on // some architectures, double in this case. align(8) ubyte[64] a1, a2; foreach (T; Tuple9477!(void, ubyte, ushort, uint, ulong, char, wchar, dchar, float, double)) { auto s1 = cast(T[])(a1[]); auto s2 = cast(T[])(a2[]); assert(s1 == s2); a2[$-1]++; assert(s1 != s2); assert(s1[0..$-1]==s2[0..$-1]); a2[$-1]--; } } /***************************************************/ // 9504 struct Bar9504 { template Abc(T) { T y; } enum size_t num = 123; class Def {} } template GetSym9504(alias sym) { static assert(__traits(isSame, sym, Bar9504.Abc)); } template GetExp9504(size_t n) { static assert(n == Bar9504.num); } template GetTyp9504(T) { static assert(is(T == Bar9504.Def)); } alias GetSym9504!(typeof(Bar9504.init).Abc) X9504; // NG alias GetExp9504!(typeof(Bar9504.init).num) Y9504; // NG alias GetTyp9504!(typeof(Bar9504.init).Def) Z9504; Bar9504 test9504() { alias GetSym9504!(typeof(return).Abc) V9504; // NG alias GetExp9504!(typeof(return).num) W9504; // NG alias GetTyp9504!(typeof(return).Def) X9504; return Bar9504(); } /***************************************************/ // 9538 void test9538() { void*[1] x; auto ti = typeid(x.ptr); } /***************************************************/ // 9539 void test9539() { void f(int** ptr) { assert(**ptr == 10); } int* p = new int; *p = 10; int*[1] x = [p]; f(&x[0]); int*[] arr = [null]; static assert(!__traits(compiles, p = arr)); // bad! } /***************************************************/ // 9700 mixin template Proxy9700(alias a) { auto ref opOpAssign(string op, V)(V v) { return a += v; } // NG //auto ref opOpAssign(string op, V)(V v) { a += v; } // OK } struct MyInt9700 { int value; invariant() { assert(value >= 0); } mixin Proxy9700!value; } void test9700() { MyInt9700 a = { 2 }; a *= 3; // object.Error: Access Violation } /***************************************************/ // 9834 struct Event9834 { void delegate() dg; void set(void delegate() h) pure { dg = h; } // AV occurs void call() { dg(); } } void test9834() { Event9834 ev; auto a = new class { Object o; this() { o = new Object; ev.set((){ o.toString(); }); } }; ev.call(); } /***************************************************/ // 9859 void test9859(inout int[] arr) { auto dg1 = { foreach (i, e; arr) { } }; dg1(); void foo() { auto v = arr; auto w = arr[0]; } void bar(inout int i) { auto v = arr[i]; } auto dg2 = { auto dg = { void foo(T)() { auto dg = { auto dg = { auto v = arr; }; }; } foo!int; }; }; void qux(T)() { auto v = arr; auto dg1 = { auto v = arr; }; auto dg2 = { auto dg = { auto v = arr; }; }; } qux!int; } /***************************************************/ // 9912 template TypeTuple9912(Stuff...) { alias Stuff TypeTuple9912; } struct S9912 { int i; alias TypeTuple9912!i t; void testA() { auto x = t; } void testB() { auto x = t; } } /***************************************************/ // 9883 struct S9883 { @property size_t p9883(T)() { return 0; } } @property size_t p9883(T)() { return 0; } void test9883() { S9883 s; auto n1 = p9883!int; // OK auto n2 = s.p9883!int; // OK auto a1 = new int[p9883!int]; // Error: need size of rightmost array, not type p!(int) auto a2 = new int[s.p9883!int]; // Error: no property 'p!(int)' for type 'S' } /***************************************************/ // 10091 struct S10091 { enum e = "a"; } void test10091() { auto arr = cast(ubyte[1]) S10091.e; } /***************************************************/ void test12824() { label: static if (0) { } } /***************************************************/ // 9130 class S9130 { void bar() { } } import core.stdc.stdio : printf; struct Function { int[] ai = [1,2,3]; } @property void meta(alias m)() { static Function md; printf("length = %d\n", md.ai.length); printf("ptr = %p\n", md.ai.ptr); md.ai[0] = 0; } void test9130() { meta!(__traits(getOverloads, S9130, "bar")[0]); meta!(S9130.bar); } /***************************************************/ // 10390 class C10390 { this() { this.c = this; } C10390 c; } const c10390 = new C10390(); pragma(msg, c10390); /***************************************************/ // 10542 class B10542 { this() nothrow pure @safe { } } class D10542 : B10542 { } void test10542() nothrow pure @safe { new D10542; } /***************************************************/ // 10539 void test10539() { int[2][2] a; int* p1 = a.ptr.ptr; // OK <- error int* p2 = (*a.ptr).ptr; // OK assert(p1 is p2); } /***************************************************/ struct TimeOfDay { ubyte h, m, s; } __gshared byte glob; struct DateTime { this(ubyte _d, ubyte _m, ubyte _y, TimeOfDay _tod = TimeOfDay.init) { d = _d; m = _m; y = _y; tod = _tod; } TimeOfDay tod; ubyte d, m, y; } void test10634() { glob = 123; DateTime date1 = DateTime(0, 0, 0); DateTime date2; assert(date1 == date2); } /***************************************************/ immutable(char)[4] bar7254(int i) { if (i) { immutable(char)[4] r; return r; } else return "1234"; } void test7254() { assert(bar7254(0) == "1234"); } /***************************************************/ struct S11075() { int x = undefined_expr; } class C11075() { int x = undefined_expr; } interface I11075() { enum int x = undefined_expr; } void test11075() { static assert(!is(typeof(S11075!().x))); static assert(!is(typeof(S11075!().x))); static assert(!is(typeof(C11075!().x))); static assert(!is(typeof(C11075!().x))); static assert(!is(typeof(I11075!().x))); static assert(!is(typeof(I11075!().x))); } /***************************************************/ // 11181 void test11181() { auto a = ["a", "b"]; static assert(!is(typeof([a, "x"]))); static assert(!is(typeof(true ? a : "x"))); static assert(!is(typeof(true ? a[0 .. $] : "x"))); static assert(!is(typeof([a[0 .. $], "x"]))); } /***************************************************/ // 11317 void test11317() { auto ref uint fun() { return 0; } void test(ref uint x) {} static assert(!__traits(compiles, test(fun()))); assert(fun() == 0); } /***************************************************/ // 11888 void test11888() { static long val; static ubyte* foo(size_t* len) { *len = val.sizeof; return cast(ubyte*)&val; } size_t size; ubyte[] t = foo(&size)[0..size]; assert(t.ptr is cast(void*)&val); assert(t.length == 8); // regression test int[3] sa1 = [1,2,3]; int[1] sa2 = sa1[1..2]; // convert slice to Tsarray assert(sa2.length == 1); assert(sa2[0] == 2); } /***************************************************/ // 12036 template T12036(alias a) { string value; } struct S12036 { auto fun() { } mixin T12036!fun; } void test12036() { S12036 s; assert(s.value == ""); } /***************************************************/ // 12153 void test12153() { int[1] i, j; bool b = true; (b ? i : j)[] = [4]; assert(i == [4]); // regression test int[1][1] k, l; (b ? k : l)[0..1][0..1] = [4]; assert(k == [[4]]); } /***************************************************/ // 12498 string a12498() { string b; while (b) { } for (; b; ) { } return ""; } void test12498() { enum t = a12498(); string x = t; } /***************************************************/ // 12900 struct A12900 { char[1] b; } void test12900() { A12900 c; if (*c.b.ptr) return; } /***************************************************/ // 12937 void test12937() { void[1] sa2 = cast(void[])[cast(ubyte)1]; // ICE! assert((cast(ubyte[])sa2[])[0] == 1); } /***************************************************/ // 13154 void test13154() { int[3] ints = [2 , 1 , 0 , 1 ][0..3]; float[3] floats0 = [2f , 1f , 0f , 1f ][0..3]; float[3] floats1 = [2.0 , 1.0 , 0.0 , 1.0 ][0..3]; // fails! float[3] floats2 = [2.0f, 1.0f, 0.0f, 1.0f][0..3]; assert(ints == [2, 1, 0]); assert(floats0 == [2, 1, 0]); assert(floats1 == [2, 1, 0]); // fail! assert(floats1 != [0, 0, 0]); // fail! assert(floats2 == [2, 1, 0]); } /***************************************************/ // 13437 ubyte[4] foo13437() { return [1,2,3,4]; } void test13437() { auto n = cast(ubyte[4])foo13437()[]; // OK <- ICE: e2ir.c 4616 static assert(is(typeof(n) == ubyte[4])); assert(n == [1,2,3,4]); } /***************************************************/ // 13472 class A13472 { int a; } void test13472() { A13472[] test; test.length = 4; auto b = test[0..2] ~ null ~ test[2..$]; assert(b.length == 5); } /***************************************************/ // 13476 template ParameterTypeTuple13476(func...) { static if (is(typeof(*func[0]) P == function)) alias ParameterTypeTuple13476 = P; else static assert(0, "argument has no parameters"); } int flag13476; __gshared extern(C) void function(int) nothrow someFunc13476 = &Stub13476!someFunc13476; extern(C) auto Stub13476(alias func)(ParameterTypeTuple13476!func args) { ++flag13476; extern(C) void function(int) nothrow impl = (i) { }; return (func = impl)(args); } __gshared extern(C) void function(int) nothrow someFunc13476Alt = &Stub13476Alt!someFunc13476AltP; __gshared extern(C) void function(int) nothrow* someFunc13476AltP = &someFunc13476Alt; extern(C) auto Stub13476Alt(alias func)(int args) nothrow { ++flag13476; extern(C) void function(int) nothrow impl = (i) {}; return (*func = impl)(args); } void test13476() { assert(flag13476 == 0); someFunc13476(42); assert(flag13476 == 1); someFunc13476(43); assert(flag13476 == 1); someFunc13476Alt(42); assert(flag13476 == 2); someFunc13476Alt(43); assert(flag13476 == 2); } /***************************************************/ // 14038 static immutable ubyte[string] wordsAA14038; static this() { wordsAA14038["zero"] = 0; } /***************************************************/ // 14192 void test14192() { shared int[int] map; map[1] = 1; } /***************************************************/ // 13720 struct FracSec13720 { this(int hnsecs) {} } struct SysTime13720 { this(TimeOfDay13720 dateTime, FracSec13720 fracSec) { } } struct TimeOfDay13720 { ~this() { } } void assertThrown13720(T)(lazy T) {} void test13720() { assertThrown13720(SysTime13720(TimeOfDay13720.init, FracSec13720(-1))); } /***************************************************/ // 13952 struct Reg13952 { ubyte type; ubyte regNo; ushort size; } struct Imm13952 { ulong imm; } struct Opnd13952 { union { Reg13952 reg; // size == 4 Imm13952 imm; // size == 8 } ubyte tag; this(Reg13952 r) { reg = r; } } Opnd13952 opnd13952(Reg13952 reg) { return Opnd13952(reg); } void test13952() { Reg13952 reg; auto op = opnd13952(reg); auto buf = (cast(ubyte*)&op)[0 .. op.sizeof]; //debug //{ // import std.stdio; // writefln("op.reg = [%(%02x %)]", (cast(ubyte*)&op.reg)[0 .. Reg13952.sizeof]); // writefln("op.imm = [%(%02x %)]", (cast(ubyte*)&op.imm)[0 .. Imm13952.sizeof]); //} foreach (e; buf) assert(e == 0); } /***************************************************/ // 14165 class Foo14165 { @disable this(); this(int i) {} } /***************************************************/ // 13985 interface I13985 { void m1(); void m2(); void m3(); final void mf() { m3(); } } class C13985 : I13985 { void m1() {} void m2() {} void m3() {} } class D13985 : C13985 { void ml() { super.mf(); } } void test13985() { auto d = new D13985(); d.ml(); } /***************************************************/ // 14211 extern(C++) // all derived classes won't have invariants class B14211 { void func() { } } final class C14211 : B14211 { } void test14211() { auto c = new C14211(); *cast(void**)c = null; c.func(); // called without vtbl access } /***************************************************/ // 14552 template map14552(fun...) { template AppliedReturnType(alias f) { alias typeof(f(0)) AppliedReturnType; } auto map14552(int[] r) { assert(!is(AppliedReturnType!fun)); return MapResult14552!fun(); } } struct MapResult14552(alias fun) { @property front() { fun(0); } } class Outer14552 { auto test() { [1].map14552!(j => new Inner); } class Inner {} } /***************************************************/ // 14853 struct Queue14853(T) { struct Node { T mfPayload = T.init; union { typeof(this)* mfPrev; shared(typeof(this)*) mfShPrev; } union { typeof(this)* mfNext; shared(typeof(this)*) mfShNext; } } Node root; void pfPut(T v, Node* r = null) { shared n = new Node(v); // problem! } } void test14853() { auto b1 = new Queue14853!uint; } /********************************************************/ // 15045 void test15045() { void testName(T, bool r, string name)() { T t; static assert(r == is(typeof(mixin("T."~name)))); static assert(r == is(typeof(mixin("t."~name)))); static assert(r == __traits(compiles, mixin("T."~name))); static assert(r == __traits(compiles, mixin("t."~name))); static assert(r == mixin("__traits(compiles, T."~name~")")); static assert(r == mixin("__traits(compiles, t."~name~")")); static assert(r == __traits(hasMember, T, name) ); static assert(r == __traits(hasMember, t, name) ); static assert(r == __traits(compiles, __traits(getMember, T, name) )); static assert(r == __traits(compiles, __traits(getMember, t, name) )); static assert(r == __traits(compiles, __traits(getOverloads, T, name) )); static assert(r == __traits(compiles, __traits(getOverloads, t, name) )); } void test(T, bool r)() { testName!(T, r, "__ctor")(); testName!(T, r, "__dtor")(); testName!(T, r, "__xdtor")(); testName!(T, r, "__postblit")(); testName!(T, r, "__xpostblit")(); } static struct X { this(int) {} this(this) {} ~this() {} } static struct S1 { auto opDispatch(string name, A...)(A args) { } } static struct S2 { X get() { return X(); }; alias get this; } static struct S3 { X opDot() { return X(); }; } test!(X, true)(); test!(S1, false)(); test!(S2, false)(); test!(S3, false)(); } /***************************************************/ // 15126 struct Json15126 { ubyte[16] m_data; int opDispatch(string prop)() const { return 0; } int opDispatch(string prop)() { return 0; } } template isCustomSerializable15126(T) { enum isCustomSerializable15126 = T.init.toRepresentation(); } alias bug15126 = isCustomSerializable15126!Json15126; /***************************************************/ // 15141 class A15141 { abstract void method(); } class B15141 : A15141 { } void test15141() { auto a = Object.factory(__MODULE__ ~ ".A15141"); assert(a is null); auto b = Object.factory(__MODULE__ ~ ".B15141"); assert(b is null); // OK <- oops } /***************************************************/ // 15366 enum E15366 : bool { A, B }; struct S15366 { void func1(E15366 e) {} void func2(E15366 a, E15366 b) { func1(cast(E15366)(a && b)); func1(cast(E15366)(a || b)); auto x1 = cast(E15366)(a && b); auto x2 = cast(E15366)(a || b); } } /***************************************************/ // 15369 struct MsgTable15369 { const(char)[] ident; const(char)* name; }; MsgTable15369[] msgTable15369 = [ { "empty", "" }, ]; void test15369() { auto id = msgTable15369[0].ident; auto p = msgTable15369[0].name; // a string literal "" should be zero-terminated assert(*p == '\0'); } void test15638() { class A {} class B : A {} class C : A {} B b; C c; const(B) cb; const(C) cc; immutable(B) ib; immutable(C) ic; // Common type for const derived classes auto constCommon = true ? cb : cc; static assert(is(typeof(constCommon) == const(A))); // Common type for immutable derived classes auto immutableCommon = true ? ib : ic; static assert(is(typeof(immutableCommon) == immutable(A))); // Common type for mixed const/immutable derived classes auto mixed1 = true ? cb : ic; static assert(is(typeof(mixed1) == const(A))); auto mixed2 = true ? ib : cc; static assert(is(typeof(mixed2) == const(A))); // Common type for mixed mutable/immutable derived classes auto mixed3 = true ? b : ic; static assert(is(typeof(mixed3) == const(A))); auto mixed4 = true ? ib : c; static assert(is(typeof(mixed4) == const(A))); // Array literal type deduction auto arr1 = [ new immutable(B), new C ]; auto arr2 = [ new B, new const(C) ]; auto arr3 = [ new immutable(B), new immutable(C) ]; static assert(is(typeof(arr1) == const(A)[])); static assert(is(typeof(arr2) == const(A)[])); static assert(is(typeof(arr3) == immutable(A)[])); } /***************************************************/ // 15961 struct SliceOverIndexed15961(T) { enum assignableIndex = T.init; } struct Grapheme15961 { SliceOverIndexed15961!Grapheme15961 opSlice() { assert(0); } struct { ubyte* ptr_; } } /***************************************************/ // 16022 bool test16022() { enum Type { Colon, Comma } Type type; return type == Type.Colon, type == Type.Comma; } /***************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test796(); test50(); test51(); test52(); test53(); test54(); test55(); test56(); test57(); test58(); test60(); test61(); test62(); test63(); test64(); test65(); test66(); test67(); test68(); test69(); test70(); test5785(); test72(); test73(); test74(); test75(); test76(); test77(); test78(); test79(); test80(); test81(); test82(); test83(); test3559(); test84(); test85(); test2006(); test8442(); test86(); test87(); test2486(); test5554(); test88(); test7545(); test89(); test90(); test91(); test92(); test4536(); test93(); test94(); test95(); test5403(); test96(); test97(); test98(); test99(); test100(); test101(); test103(); test104(); test105(); test3927(); test107(); test109(); test111(); test113(); test115(); test116(); test117(); test3822(); test6545(); test118(); test5081(); test120(); test10724(); test122(); test123(); test124(); test125(); test6763(); test127(); test128(); test1891(); test129(); test130(); test1064(); test131(); test132(); test133(); test134(); test135(); test136(); test137(); test138(); test1962(); test139(); test140(); test141(); test6317(); test142(); test143(); test144(); test145(); test146(); test147(); test6685(); test148(); test149(); test2356(); test13652(); test11238(); test2540(); test14348(); test150(); test151(); test152(); test153(); test154(); test155(); test156(); test658(); test4258(); test4539(); test4963(); test4031(); test5437(); test6230(); test6264(); test6284(); test6295(); test6293(); test5046(); test1471(); test6335(); test1687(); test6228(); test3733(); test4392(); test7942(); test6220(); test5799(); test157(); test6473(); test6630(); test6690(); test2953(); test2997(); test4423(); test4647(); test5696(); test6084(); test6488(); test6565(); test6836(); test6837(); test6927(); test6733(); test6813(); test6859(); test3022(); test6910(); test6902(); test6330(); test6868(); test2856(); test3091(); test6056(); test6356(); test7073(); test7104(); test7150(); test7160(); test7168(); test7170(); test7196(); test7285(); test14737(); test7321(); test3282(); test7534(); test7534cov(); test7618(); test7621(); test11417(); test7682(); test7735(); test7823(); test7871(); test7906(); test7907(); test12503(); test8004(); test8064(); test8105(); test159(); test12824(); test8283(); test13182(); test8269(); test8395(); test13427(); test5749(); test8396(); test160(); test8665(); test8108(); test8360(); test9577(); test6141(); test199(); test8526(); test161(); test7175(); test8819(); test8917(); test8945(); test11805(); test14192(); test163(); test9428(); test9477(); test9538(); test9700(); test9834(); test13947(); test9883(); test10091(); test9130(); test10542(); test10539(); test10634(); test15080(); test7254(); test13468(); test11075(); test11181(); test11317(); test11888(); test12036(); test12153(); test12937(); test13154(); test13437(); test13472(); test13476(); test13720(); test13952(); test13985(); test14211(); test15141(); test15369(); test15638(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test8544.d0000664000175000017500000000063712776215022021663 0ustar kaikai// EXECUTE_ARGS: foo bar doo // PERMUTE_ARGS: import std.stdio; import std.conv; import core.runtime; void main(string[] args) { string[] dArgs = Runtime.args; CArgs cArgs = Runtime.cArgs; assert(dArgs.length && cArgs.argc); // ensure we've passed some args assert(dArgs.length == cArgs.argc); assert(dArgs[1] == to!string(cArgs.argv[1])); assert(args[1] == to!string(cArgs.argv[1])); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link12010.d0000664000175000017500000000024712776215022021675 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/a12010.d // REQUIRED_ARGS: -release // -release is necessary to avoid __assert. import imports.a12010; void main() {} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link7966.d0000664000175000017500000000062112776215022021641 0ustar kaikaienum E { i } struct S1 { bool opCast(T)() { return true; } } struct S2 { bool opCast(T)() { return true; } } import a = core.stdc.stdio; void main() { with (E) // exp == TOKtype assert(S1()); // Doesn't enclose in ScopeStatement assert(S1()); with (a) // exp == TOKimport assert(S2()); // Doesn't enclose in ScopeStatement assert(S2()); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test13774.sh0000775000175000017500000000071512776215022022133 0ustar kaikai#!/usr/bin/env bash src=runnable${SEP}extra-files dir=${RESULTS_DIR}${SEP}runnable output_file=${dir}/test13774.sh.out if [ $OS == "win32" -o $OS == "win64" ]; then LIBEXT=.lib else LIBEXT=.a fi $DMD -m${MODEL} -I${src} -lib -od${dir} ${src}${SEP}lib13774a.d || exit 1 $DMD -m${MODEL} -I${src} -lib -od${dir} ${src}${SEP}lib13774b.d ${dir}${SEP}lib13774a${LIBEXT} || exit 1 rm ${dir}/{lib13774a${LIBEXT},lib13774b${LIBEXT}} echo Success >${output_file} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/mixin1.d0000664000175000017500000005174712776215022021574 0ustar kaikai module mixin1; import std.stdio; alias TypeTuple(T...) = T; /*******************************************/ mixin template Foo(T) { T x; } mixin Foo!(uint); struct Bar { template Abc(T) { T y; } template Def(T) { T z; } } mixin Bar.Abc!(int); Bar b; mixin typeof(b).Def!(int); void test1() { x = 3; assert(x == 3); y = 4; assert(y == 4); z = 5; assert(z == 5); } /*******************************************/ template Foo2(T) { T x2 = T.sizeof; } mixin Foo2!(uint) B2; mixin Foo2!(long) C2; mixin Foo2!(int); void test2() { B2.x2 = 3; assert(B2.x2 == 3); assert(C2.x2 == long.sizeof); // assert(x2 == int.sizeof); } /*******************************************/ template Foo3(T) { int func() { printf("Foo3.func()\n"); return 1; } } class Bar3 { mixin Foo3!(int); } class Code3 : Bar3 { override int func() { printf("Code3.func()\n"); return 2; } } void test3() { int i; Bar3 b = new Bar3(); i = b.func(); assert(i == 1); b = new Code3(); i = b.func(); assert(i == 2); } /*******************************************/ template Foo4(T) { int func() { printf("Foo4.func()\n"); return 1; } } struct Bar4 { mixin Foo4!(int); } void test4() { int i; Bar4 b; i = b.func(); assert(i == 1); } /*******************************************/ template Foo5() { int func() { printf("Foo5.func()\n"); return 1; } } struct Bar5 { mixin Foo5; } void test5() { int i; Bar5 b; i = b.func(); assert(i == 1); } /*******************************************/ template Foo6() { int x = 5; } struct Bar6 { mixin Foo6; } void test6() { int i; Bar6 b; i = b.x; assert(i == 5); assert(b.sizeof == int.sizeof); } /*******************************************/ template Foo7() { int x = 5; } class Bar7 { int y = 6; mixin Foo7; } void test7() { int i; Bar7 b = new Bar7(); i = b.x; printf("b.x = %d\n", b.x); assert(i == 5); } /*******************************************/ template Foo8() { int x = 5; int bar() { return 7; } } void test8() { mixin Foo8; printf("x = %d\n", x); assert(x == 5); assert(bar() == 7); } /*******************************************/ template Foo9() { int abc() { return y; } } void test9() { int y = 8; mixin Foo9; assert(abc() == 8); } /*******************************************/ template Foo10(alias b) { typeof(b) abc() { return b; } } void test10() { int y = 8; mixin Foo10!(y); assert(abc() == 8); } /*******************************************/ template Foo11(alias b) { int abc() { return b; } } void test11() { int y = 8; mixin Foo11!(y) B; assert(B.abc() == 8); } /*******************************************/ template duff_for(alias id1, alias id2, alias s) { void duff_for() { printf("duff_for(%d, %d)\n", id1, id2); typeof(id1) id = id1; printf("fid = %d, %d\n", id, (id2 - id) % 8); switch ((id2 - id) % 8) { case 0: while (id != id2) { printf("wid = %d\n", id); s(); ++id; goto case; case 7: s(); ++id; goto case; case 6: s(); ++id; goto case; case 5: s(); ++id; goto case; case 4: s(); ++id; goto case; case 3: s(); ++id; goto case; case 2: s(); ++id; goto case; case 1: s(); ++id; break; default: assert(0); } } } } void foo12() { printf("foo12\n"); } void test12() { int i = 1; int j = 11; mixin duff_for!(i, j, delegate void() { foo12(); }); duff_for(); } /*******************************************/ template duff(alias id1, alias id2, alias s) { void duff() { s(); s(); } } void foo13(int j) { printf("foo13 j = %d\n", j); assert(j == 1); } void test13() { int i = 1; int j = 11; mixin duff!(i, j, delegate { foo13(i); }); duff(); } /*******************************************/ template Foo14() { int x14 = 5; } void test14() { int x14 = 6; mixin Foo14; printf("x14 = %d\n", x14); assert(x14 == 6); } /*******************************************/ template Foo15() { int x15 = 5; int bar15() { return x15; } } int x15 = 6; mixin Foo15; void test15() { printf("x15 = %d\n", x15); printf("bar15() = %d\n", bar15()); assert(x15 == 6); assert(bar15() == 5); } /*******************************************/ template Foo16() { int x16 = 5; int bar() { return x16; } } mixin Foo16 A16; int x16 = 6; mixin Foo16 B16; void test16() { printf("x16 = %d\n", x16); printf("bar() = %d\n", A16.bar()); assert(x16 == 6); assert(A16.x16 == 5); assert(B16.x16 == 5); assert(A16.bar() == 5); assert(B16.bar() == 5); } /*******************************************/ template Foo17() { int x17 = 5; } mixin Foo17; struct Bar17 { mixin Foo17; } void test17() { printf("x17 = %d\n", x17); // prints 5 assert(x17 == 5); { Bar17 b; int x17 = 3; printf("b.x17 = %d\n", b.x17); // prints 5 assert(b.x17 == 5); printf("x17 = %d\n", x17); // prints 3 assert(x17 == 3); { mixin Foo17; printf("x17 = %d\n", x17); // prints 5 assert(x17 == 5); x17 = 4; printf("x17 = %d\n", x17); // prints 4 assert(x17 == 4); } printf("x17 = %d\n", x17); // prints 3 assert(x17 == 3); } printf("x17 = %d\n", x17); // prints 5 assert(x17 == 5); } /*******************************************/ template Foo18() { int z = 3; } struct Bar18(alias Tmpl) { mixin Tmpl; } Bar18!(Foo18) b18; void test18() { assert(b18.z == 3); } /*******************************************/ template Mix1(T) { int foo19(T a) { return 2*a; } } template Mix2(T) { mixin Mix1!(T); int bar19(T a) { return foo19(a); } } mixin Mix2!(int); void test19() { int i; i = bar19(7); assert(i == 14); } /*******************************************/ interface A20 { int f(); } template Foo20() { int f() { printf("in C20.f()\n"); return 6; } } class C20 : A20 { mixin Foo20; // void f() { printf("in C20.f()\n"); } } void test20() { C20 c = new C20(); int i = c.f(); assert(i == 6); } /*******************************************/ template Mix21() { this(int x) { printf("mix1\n"); }} class Bar21 { int myx; mixin Mix21; // wouldn't compile this() { myx = 15; } // mixin Mix21; // placing it here compiles } void test21() { Bar21 bar = new Bar21(); } /*******************************************/ template A22(T) { this() { int i; i = super.foo(); assert(i == 67); } } class B22 { int foo() { printf("B22.foo()\n"); return 67; } } class C22 : B22 { mixin A22!(C22); } void test22() { C22 c = new C22; } /*******************************************/ template Foo23() { const int x = 5; } class C23 { mixin Foo23 F; } struct D23 { mixin Foo23 F; } void test23() { C23 c = new C23; printf("%d\n",c.F.x); assert(c.F.x == 5); D23 d; printf("%d\n",d.F.x); assert(d.F.x == 5); } /*******************************************/ template T24() { void foo24() { return cast(void)0; } // alias foo24 foo24; } mixin T24; void test24() { foo24(); } /*******************************************/ template ctor25() { this() { this(null); } this( Object o ) {} } class Foo25 { mixin ctor25; } void test25() { Foo25 foo = new Foo25(); } /*******************************************/ template Get26(T) { Reader get (ref T x) { return this; } } class Reader { mixin Get26!(byte) bar; alias bar.get get; mixin Get26!(int) beq; alias beq.get get; } void test26() { Reader r = new Reader; Reader s; byte q; s = r.get (q); assert(s == r); } /*******************************************/ template Template(int L) { int i = L; int foo(int b = Template!(9).i) { return b; } } void test27() { int i = 10; int foo(int b = Template!(9).i) { return b; } assert(foo()==9); } /*******************************************/ template Blah28(int a, alias B) { mixin Blah28!(a-1, B); //mixin Blah28!(0, B); } template Blah28(int a:0, alias B) { } void test28() { int a; mixin Blah28!(5,a); printf("a = %d\n", a); } /*******************************************/ template T29() { int x; } struct S29 { mixin T29; int y; } const S29 s29 = { x:2, y:3 }; void test29() { assert(s29.x == 2); assert(s29.y == 3); } /*******************************************/ class A30 { template ctor(Type) { this(Type[] arr) { foreach(Type v; arr) writeln(typeid(typeof(v))); } } mixin ctor!(int); } void test30() { static int[] ints = [0,1,2,3]; A30 a = new A30(ints); } /*******************************************/ template Share(T) { const bool opEquals(ref const T x) { return true; } } struct List31(T) { //int opEquals(List31 x) { return 0; } mixin Share!(List31); } void test31() { List31!(int) x; List31!(int) y; int i = x == y; assert(i == 1); } /*******************************************/ template Blah(int a, alias B) { mixin Blah!(a-1, B); } template Blah(int a:0, alias B) { int foo() { return B + 1; } } void test32() { int a = 3; mixin Blah!(5,a); assert(foo() == 4); } /*******************************************/ template T33( int i ) { int foo() { printf("foo %d\n", i ); return i; } int opCall() { printf("opCall %d\n", i ); return i; } } class C33 { mixin T33!( 1 ) t1; mixin T33!( 2 ) t2; } void test33() { int i; C33 c1 = new C33; i = c1.t1.foo(); assert(i == 1); i = c1.t2.foo(); assert(i == 2); i = c1.t1(); assert(i == 1); i = c1.t2(); assert(i == 2); } /*******************************************/ template mix34() { int i; void print() { printf( "%d %d\n", i, j ); assert(i == 0); assert(j == 0); } } void test34() { int j; mixin mix34!(); print(); //printf( "%i\n", i ); } /*******************************************/ mixin T35!(int) m35; template T35(t) { t a; } void test35() { m35.a = 3; } /*******************************************/ struct Foo36 { int a; mixin T!(int) m; template T(t) { t b; } int c; } void test36() { Foo36 f; printf("f.sizeof = %d\n", f.sizeof); assert(f.sizeof == 12); f.a = 1; f.m.b = 2; f.c = 3; assert(f.a == 1); assert(f.m.b == 2); assert(f.c == 3); } /*******************************************/ template Foo37() { template func() { int func() { return 6; } } } class Baz37 { mixin Foo37 bar; } void test37() { Baz37 b = new Baz37; auto i = b.bar.func!()(); assert(i == 6); i = (new Baz37).bar.func!()(); assert(i == 6); } /*******************************************/ template Foo38() { int a = 4; ~this() { printf("one\n"); assert(a == 4); assert(b == 5); c++; } } class Outer38 { int b = 5; static int c; mixin Foo38!() bar; mixin Foo38!() abc; ~this() { printf("two\n"); assert(b == 5); assert(c == 0); c++; } } void test38() { Outer38 o = new Outer38(); delete o; assert(Outer38.c == 3); } /*******************************************/ template TDtor() { ~this() { printf("Mixed-in dtor\n"); } } class Base39 { ~this() { printf("Base39 dtor\n"); } } class Class39 : Base39 { mixin TDtor A; mixin TDtor B; ~this() { printf("Class39 dtor\n"); } } void test39() { auto test = new Class39; } /*******************************************/ template Mix40() { int i; } struct Z40 { union { mixin Mix40; } } void test40() { Z40 z; z.i = 3; } /*******************************************/ class X41(P...) { alias P[0] Q; mixin Q!(); } template MYP() { void foo() { } } void test41() { X41!(MYP) x; } /*******************************************/ // 2245 template TCALL2245a(ARGS...) { int makecall(ARGS args) { return args.length; } } template TCALL2245b(int n) { int makecall2(ARGS...)(ARGS args) if (ARGS.length == n) { return args.length; } } class C2245 { mixin TCALL2245a!(); mixin TCALL2245a!(int); mixin TCALL2245a!(int,int); mixin TCALL2245b!(0); mixin TCALL2245b!(1); mixin TCALL2245b!(2); } struct S2245 { mixin TCALL2245a!(); mixin TCALL2245a!(int); mixin TCALL2245a!(int,int); mixin TCALL2245b!(0); mixin TCALL2245b!(1); mixin TCALL2245b!(2); } void test2245() { auto c = new C2245; assert(c.makecall() == 0); assert(c.makecall(0) == 1); assert(c.makecall(0,1) == 2); assert(c.makecall2() == 0); assert(c.makecall2(0) == 1); assert(c.makecall2(0,1) == 2); assert(c.makecall2!()() == 0); assert(c.makecall2!(int)(0) == 1); assert(c.makecall2!(int, int)(0,1) == 2); auto s = S2245(); assert(s.makecall() == 0); assert(s.makecall(0) == 1); assert(s.makecall(0,1) == 2); assert(s.makecall2() == 0); assert(s.makecall2(0) == 1); assert(s.makecall2(0,1) == 2); assert(s.makecall2!()() == 0); assert(s.makecall2!(int)(0) == 1); assert(s.makecall2!(int, int)(0,1) == 2); } /*******************************************/ // 2481 template M2481() { int i; } class Z2481a { struct { mixin M2481!(); } } class Z2481b { struct { int i; } } void test2481() { Z2481a z1; Z2481b z2; static assert(z1.i.offsetof == z2.i.offsetof); } /*******************************************/ // 2740 interface IFooable2740 { bool foo(); } abstract class CFooable2740 { bool foo(); } mixin template MFoo2740() { override bool foo() { return true; } } class Foo2740i1 : IFooable2740 { override bool foo() { return false; } mixin MFoo2740; } class Foo2740i2 : IFooable2740 { mixin MFoo2740; override bool foo() { return false; } } class Foo2740c1 : CFooable2740 { override bool foo() { return false; } mixin MFoo2740; } class Foo2740c2 : CFooable2740 { mixin MFoo2740; override bool foo() { return false; } } void test2740() { { auto p = new Foo2740i1(); IFooable2740 i = p; assert(p.foo() == false); assert(i.foo() == false); } { auto p = new Foo2740i2(); IFooable2740 i = p; assert(p.foo() == false); assert(i.foo() == false); } { auto p = new Foo2740c1(); CFooable2740 i = p; assert(p.foo() == false); assert(i.foo() == false); } { auto p = new Foo2740c2(); CFooable2740 i = p; assert(p.foo() == false); assert(i.foo() == false); } } /*******************************************/ mixin template MTestFoo() { int foo(){ return 2; } } class TestFoo { mixin MTestFoo!() test; int foo(){ return 1; } } void test42() { auto p = new TestFoo(); assert(p.foo() == 1); assert(p.test.foo() == 2); } /*******************************************/ // 7744 class ZeroOrMore7744(Expr) { enum name = "ZeroOrMore7744!("~Expr.name~")"; } class Range7744(char begin, char end) { enum name = "Range7744!("~begin~","~end~")"; } mixin(q{ class RubySource7744 : ZeroOrMore7744!(DecLiteral7744) { } class DecLiteral7744 : Range7744!('0','9') { } }); /*******************************************/ // 8032 mixin template T8032() { void f() { } } class A8032a { mixin T8032; // Named mixin causes the error too void f() { } } class B8032a : A8032a { override void f() { } } class A8032b { void f() { } mixin T8032; // Named mixin causes the error too } class B8032b : A8032b { override void f() { } } /*********************************************/ // 9417 mixin template Foo9417() { void foo() {} } void test9417() { struct B { mixin Foo9417; } } /*******************************************/ // 11487 template X11487() { struct R() { C11487 c; ~this() { static assert(is(typeof(c.front) == void)); } } template Mix(alias R) { R!() range; @property front() inout {} } } class C11487 { alias X11487!() M; mixin M.Mix!(M.R); } /*******************************************/ // 11767 mixin template M11767() { struct S11767 {} } mixin M11767!(); mixin M11767!(); // OK static assert(!__traits(compiles, S11767)); void test11767() { mixin M11767!(); alias S1 = S11767; { mixin M11767!(); alias S2 = S11767; static assert(!is(S1 == S2)); static assert(S1.mangleof == "S6mixin19test11767FZ8__mixin16S11767"); static assert(S2.mangleof == "S6mixin19test11767FZ8__mixin26S11767"); } mixin M11767!(); static assert(!__traits(compiles, S11767)); } /*******************************************/ // 12023 void Delete12023(Object obj) {} template MessageCode12023() { alias typeof(this) C; struct MessageDeinitHelper { C m_outer; ~this() { m_outer.DoDeinitMessaging(); } } CToClient toClient = null; TypeTuple!(CToClient) toClients; class CToClient {} void DoDeinitMessaging() { Delete12023(toClient); Delete12023(toClients); } } class TurretCannon12023(ProjectileClass) { mixin MessageCode12023; } void test12023() { auto tc = new TurretCannon12023!Object(); } /*******************************************/ // 14243 mixin template Mix14243a(int n) { static assert(n > 0); import core.stdc.stdio; enum { enumMember = 1 } auto a = A14243(n); } mixin template Mix14243b(int n) { static if (n > 0) { auto b = A14243(n); } } template foo14243(alias v) { auto bar() { return &v; } } mixin template Mix14243c(alias v) { // instantiate template in TemplateMixin auto c = foo14243!v.bar(); } mixin template Mix14243d(int n) { // Type declaration in TemplateMixin struct NS { int x = n; } mixin("auto d" ~ ('0' + n) ~ " = NS();"); } mixin template Mix14243e(int n) { @safe: nothrow: int foo() { return var; } static: struct S { int x; void f() {} } int bar() { return n; } } int test14243() { int[] ctor; int[] dtor; struct A14243 { int x; this(int x) { ctor ~= x; this.x = x; } ~this() { dtor ~= x; } } { /**/ assert(ctor == [] && dtor == []); mixin Mix14243a!(1); assert(ctor == [1] && dtor == []); mixin Mix14243b!(12) b1; assert(ctor == [1,12] && dtor == []); mixin Mix14243b!(24) b2; assert(ctor == [1,12,24] && dtor == []); assert(a.x == 1); static assert(!__traits(compiles, b > 0)); // ambiguous symbol access assert(b1.b.x == 12); assert(b2.b.x == 24); int x; mixin Mix14243c!(x); assert(c == &x); mixin Mix14243d!(1); mixin Mix14243d!(2); static assert(!is(typeof(d1) == typeof(d2))); assert(d1.x == 1); assert(d2.x == 2); assert(ctor == [1,12,24] && dtor == []); } assert(ctor == [1,12,24] && dtor == [24,12,1]); { int var = 1; mixin Mix14243e!12; static assert(is(typeof(&foo) == int delegate() @safe nothrow)); static assert(is(typeof(&bar) == int function() @safe nothrow)); static assert(S.sizeof == int.sizeof); // s is static struct assert(foo() == 1); assert(bar() == 12); } return 1; } static assert(test14243()); // changed to be workable /*******************************************/ // 10492 class TestClass10492 {} mixin template mix10492(string name) { mixin("scope " ~ name ~ " = new TestClass10492;" ); } void test10492() { mixin mix10492!("var"); } /*******************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test2245(); test2740(); test42(); test9417(); test11767(); test12023(); test14243(); test10492(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test15079.d0000664000175000017500000000007212776215022021735 0ustar kaikaimodule test15079; import imports.a15079; void main() {} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/overload.d0000664000175000017500000007753512776215022022205 0ustar kaikai// EXTRA_SOURCES: imports/ovs1528a.d imports/ovs1528b.d // EXTRA_SOURCES: imports/template_ovs1.d imports/template_ovs2.d imports/template_ovs3.d import imports.template_ovs1; import imports.template_ovs2; import imports.template_ovs3; extern(C) int printf(const char* fmt, ...); template TypeTuple(T...){ alias T TypeTuple; } template Id( T){ alias T Id; } template Id(alias A){ alias A Id; } /***************************************************/ // 1528 int foo1528(long){ return 1; } int foo1528(int[]){ return 2; } int foo1528(T)(T) if ( is(T:real)) { return 3; } int foo1528(T)(T) if (!is(T:real)) { return 4; } int bar1528(T)(T) if (!is(T:real)) { return 4; } int bar1528(T)(T) if ( is(T:real)) { return 3; } int bar1528(int[]){ return 2; } int bar1528(long){ return 1; } @property auto getfoo1528 () { return 1; } @property auto getfoo1528(T)() { return 2; } @property auto getbar1528(T)() { return 2; } @property auto getbar1528 () { return 1; } @property auto setfoo1528 (int) { return 1; } @property auto setfoo1528(T)(int) { return 2; } @property auto setbar1528(T)(int) { return 2; } @property auto setbar1528 (int) { return 1; } struct S1528 { int foo(long){ return 1; } int foo(int[]){ return 2; } int foo(T)(T) if ( is(T:real)) { return 3; } int foo(T)(T) if (!is(T:real)) { return 4; } int bar(T)(T) if (!is(T:real)) { return 4; } int bar(T)(T) if ( is(T:real)) { return 3; } int bar(int[]){ return 2; } int bar(long){ return 1; } @property auto getfoo () { return 1; } @property auto getfoo(T)() { return 2; } @property auto getbar(T)() { return 2; } @property auto getbar () { return 1; } @property auto setfoo (int) { return 1; } @property auto setfoo(T)(int) { return 2; } @property auto setbar(T)(int) { return 2; } @property auto setbar (int) { return 1; } @property auto propboo () { return 1; } @property auto propboo(T)(T) { return 2; } @property auto propbaz(T)(T) { return 2; } @property auto propbaz () { return 1; } } auto ufoo1528 (S1528) { return 1; } auto ufoo1528(T)(S1528) { return 2; } auto ubar1528(T)(S1528) { return 2; } auto ubar1528 (S1528) { return 1; } @property auto ugetfoo1528 (S1528) { return 1; } @property auto ugetfoo1528(T)(S1528) { return 2; } @property auto ugetbar1528(T)(S1528) { return 2; } @property auto ugetbar1528 (S1528) { return 1; } @property auto usetfoo1528 (S1528, int) { return 1; } @property auto usetfoo1528(T)(S1528, int) { return 2; } @property auto usetbar1528(T)(S1528, int) { return 2; } @property auto usetbar1528 (S1528, int) { return 1; } @property auto upropboo1528 (S1528) { return 1; } @property auto upropboo1528(T)(S1528, T) { return 2; } @property auto upropbaz1528(T)(S1528, T) { return 2; } @property auto upropbaz1528 (S1528) { return 1; } void test1528a() { // global assert(foo1528(100) == 1); assert(foo1528(10L) == 1); assert(foo1528([1]) == 2); assert(foo1528(1.0) == 3); assert(foo1528("a") == 4); assert(bar1528(100) == 1); assert(bar1528(10L) == 1); assert(bar1528([1]) == 2); assert(bar1528(1.0) == 3); assert(bar1528("a") == 4); assert(getfoo1528 == 1); assert(getfoo1528!string == 2); assert(getbar1528 == 1); assert(getbar1528!string == 2); assert((setfoo1528 = 1) == 1); assert((setfoo1528!string = 1) == 2); assert((setbar1528 = 1) == 1); assert((setbar1528!string = 1) == 2); S1528 s; // member assert(s.foo(100) == 1); assert(s.foo(10L) == 1); assert(s.foo([1]) == 2); assert(s.foo(1.0) == 3); assert(s.foo("a") == 4); assert(s.bar(100) == 1); assert(s.bar(10L) == 1); assert(s.bar([1]) == 2); assert(s.bar(1.0) == 3); assert(s.bar("a") == 4); assert(s.getfoo == 1); assert(s.getfoo!string == 2); assert(s.getbar == 1); assert(s.getbar!string == 2); assert((s.setfoo = 1) == 1); assert((s.setfoo!string = 1) == 2); assert((s.setbar = 1) == 1); assert((s.setbar!string = 1) == 2); assert((s.propboo = 1) == 2); assert( s.propboo == 1); assert((s.propbaz = 1) == 2); assert( s.propbaz == 1); // UFCS assert(s.ufoo1528 () == 1); assert(s.ufoo1528!string() == 2); assert(s.ubar1528 () == 1); assert(s.ubar1528!string() == 2); assert(s.ugetfoo1528 == 1); assert(s.ugetfoo1528!string == 2); assert(s.ugetbar1528 == 1); assert(s.ugetbar1528!string == 2); assert((s.usetfoo1528 = 1) == 1); assert((s.usetfoo1528!string = 1) == 2); assert((s.usetbar1528 = 1) == 1); assert((s.usetbar1528!string = 1) == 2); assert((s.upropboo1528 = 1) == 2); assert( s.upropboo1528 == 1); assert((s.upropbaz1528 = 1) == 2); assert( s.upropbaz1528 == 1); // overload set import imports.ovs1528a, imports.ovs1528b; assert(func1528() == 1); assert(func1528(1.0) == 2); assert(func1528("a") == 3); assert(func1528([1.0]) == 4); assert(bunc1528() == 1); assert(bunc1528(1.0) == 2); assert(bunc1528("a") == 3); assert(bunc1528([1.0]) == 4); assert(vunc1528(100) == 1); assert(vunc1528("a") == 2); assert(wunc1528(100) == 1); assert(wunc1528("a") == 2); //assert(opUnary1528!"+"(10) == 1); //assert(opUnary1528!"-"(10) == 2); } // ---- int doo1528a(int a, double=10) { return 1; } int doo1528a(int a, string="") { return 2; } int doo1528b(int a) { return 1; } int doo1528b(T:int)(T b) { return 2; } int doo1528c(T:int)(T b, double=10) { return 2; } int doo1528c(T:int)(T b, string="") { return 2; } int doo1528d(int a) { return 1; } int doo1528d(T)(T b) { return 2; } void test1528b() { // MatchLevel by tiargs / by fargs static assert(!__traits(compiles, doo1528a(1))); // 1: MATCHexact / MATCHexact // 2: MATCHexact / MATCHexact static assert(!__traits(compiles, doo1528a(1L))); // 1: MATCHexact / MATCHconvert // 2: MATCHexact / MATCHconvert static assert(!__traits(compiles, doo1528b(1))); // 1: MATCHexact / MATCHexact // 2: MATCHexact / MATCHexact assert(doo1528b(1L) == 1); // 1: MATCHexact / MATCHconvert // 2: MATCHnomatch / - static assert(!__traits(compiles, doo1528c(1))); // 1: MATCHexact / MATCHexact // 2: MATCHexact / MATCHexact static assert(!__traits(compiles, doo1528c(1L))); // 1: MATCHnomatch / - // 2: MATCHnomatch / - assert(doo1528d(1) == 1); // 1: MATCHexact / MATCHexact // 2: MATCHconvert / MATCHexact assert(doo1528d(1L) == 1); // 1: MATCHexact / MATCHconvert // 2: MATCHconvert / MATCHexact // -> not sure, may be ambiguous...? } // ---- char[num*2] toHexString1528(int order, size_t num)(in ubyte[num] digest) { return typeof(return).init; } string toHexString1528(int order)(in ubyte[] digest) { assert(0); } char[8] test1528c() { ubyte[4] foo() { return typeof(return).init; } return toHexString1528!10(foo); } // ---- int f1528d1(int a, double=10) { return 1; } int f1528d1(int a, string="") { return 2; } int f1528d2(T:int)(T b, double=10) { return 1; } int f1528d2(T:int)(T b, string="") { return 2; } // vs deduced parameter int f1528d3(int a) { return 1; } int f1528d3(T)(T b) { return 2; } // vs specialized parameter int f1528d4(int a) { return 1; } int f1528d4(T:int)(T b) { return 2; } // vs deduced parameter + template constraint (1) int f1528d5(int a) { return 1; } int f1528d5(T)(T b) if (is(T == int)) { return 2; } // vs deduced parameter + template constraint (2) int f1528d6(int a) { return 1; } int f1528d6(T)(T b) if (is(T : int)) { return 2; } // vs nallowing conversion int f1528d7(ubyte a) { return 1; } int f1528d7(T)(T b) if (is(T : int)) { return 2; } int f1528d10(int, int) { return 1; } int f1528d10(T)(T, int) { return 2; } void test1528d() { static assert(!__traits(compiles, f1528d1(1))); // ambiguous static assert(!__traits(compiles, f1528d1(1L))); // ambiguous static assert(!__traits(compiles, f1528d2(1))); // ambiguous static assert(!__traits(compiles, f1528d2(1L))); // no match assert(f1528d3(1) == 1); assert(f1528d3(1L) == 1); // '1L' matches int short short_val = 42; assert(f1528d3(cast(short) 42) == 1); assert(f1528d3(short_val) == 1); static assert(!__traits(compiles, f1528d4(1))); assert(f1528d4(1L) == 1); assert(f1528d5(1) == 1); assert(f1528d5(1L) == 1); assert(f1528d6(1) == 1); assert(f1528d6(1L) == 1); static assert(!__traits(compiles, f1528d6(ulong.max))); // no match // needs to fix bug 9617 ulong ulval = 1; static assert(!__traits(compiles, f1528d6(ulval))); // no match assert(f1528d7(200u) == 1); // '200u' matches ubyte assert(f1528d7(400u) == 2); uint uival = 400; // TDPL-like range knowledge lost here. assert(f1528d7(uival) == 2); uival = 200; // Ditto. assert(f1528d7(uival) == 2); assert(f1528d10( 1, 9) == 1); assert(f1528d10( 1U, 9) == 1); assert(f1528d10( 1L, 9) == 1); assert(f1528d10( 1LU, 9) == 1); assert(f1528d10( long.max, 9) == 2); assert(f1528d10(ulong.max, 9) == 2); assert(f1528d10( 1, 9L) == 1); assert(f1528d10( 1U, 9L) == 1); assert(f1528d10( 1L, 9L) == 1); assert(f1528d10( 1LU, 9L) == 1); assert(f1528d10( long.max, 9L) == 2); assert(f1528d10(ulong.max, 9L) == 2); } /***************************************************/ // 1680 struct S1680 { ulong _y; ulong blah1() { return _y; } static S1680 blah1(ulong n) { return S1680(n); } static S1680 blah2(ulong n) { return S1680(n); } static S1680 blah2(char[] n) { return S1680(n.length); } } class C1680 { ulong _y; this(ulong n){} ulong blah1() { return _y; } static C1680 blah1(ulong n) { return new C1680(n); } static C1680 blah2(ulong n) { return new C1680(n); } static C1680 blah2(char[] n) { return new C1680(n.length); } } void test1680() { // OK S1680 s = S1680.blah1(5); void fs() { S1680 s1 = S1680.blah2(5); // OK S1680 s2 = S1680.blah2("hello".dup); // OK S1680 s3 = S1680.blah1(5); // Error: 'this' is only allowed in non-static member functions, not f } C1680 c = C1680.blah1(5); void fc() { C1680 c1 = C1680.blah2(5); C1680 c2 = C1680.blah2("hello".dup); C1680 c3 = C1680.blah1(5); } } /***************************************************/ // 7418 int foo7418(uint a) { return 1; } int foo7418(char[] a) { return 2; } alias foo7418 foo7418a; template foo7418b(T = void) { alias foo7418 foo7418b; } void test7418() { assert(foo7418a(1U) == 1); assert(foo7418a("a".dup) == 2); assert(foo7418b!()(1U) == 1); assert(foo7418b!()("a".dup) == 2); } /***************************************************/ // 7552 struct S7552 { static void foo(){} static void foo(int){} } struct T7552 { alias TypeTuple!(__traits(getOverloads, S7552, "foo")) FooInS; alias FooInS[0] foo; // should be S7552.foo() static void foo(string){} } struct U7552 { alias TypeTuple!(__traits(getOverloads, S7552, "foo")) FooInS; alias FooInS[1] foo; // should be S7552.foo(int) static void foo(string){} } void test7552() { alias TypeTuple!(__traits(getOverloads, S7552, "foo")) FooInS; static assert(FooInS.length == 2); FooInS[0](); static assert(!__traits(compiles, FooInS[0](0))); static assert(!__traits(compiles, FooInS[1]())); FooInS[1](0); Id!(FooInS[0])(); static assert(!__traits(compiles, Id!(FooInS[0])(0))); static assert(!__traits(compiles, Id!(FooInS[1])())); Id!(FooInS[1])(0); alias TypeTuple!(__traits(getOverloads, T7552, "foo")) FooInT; static assert(FooInT.length == 2); // fail FooInT[0](); static assert(!__traits(compiles, FooInT[0](0))); static assert(!__traits(compiles, FooInT[0](""))); static assert(!__traits(compiles, FooInT[1]())); static assert(!__traits(compiles, FooInT[1](0))); // fail FooInT[1](""); // fail alias TypeTuple!(__traits(getOverloads, U7552, "foo")) FooInU; static assert(FooInU.length == 2); static assert(!__traits(compiles, FooInU[0]())); FooInU[0](0); static assert(!__traits(compiles, FooInU[0](""))); static assert(!__traits(compiles, FooInU[1]())); static assert(!__traits(compiles, FooInU[1](0))); FooInU[1](""); } /***************************************************/ // 8668 import imports.m8668a; import imports.m8668c; //replace with m8668b to make it work void test8668() { split8668("abc"); split8668(123); } /***************************************************/ // 8943 void test8943() { struct S { void foo(); } alias TypeTuple!(__traits(getOverloads, S, "foo")) Overloads; alias TypeTuple!(__traits(parent, Overloads[0])) P; // fail static assert(is(P[0] == S)); } /***************************************************/ // 9410 struct S {} int foo(float f, ref S s) { return 1; } int foo(float f, S s) { return 2; } void test9410() { S s; assert(foo(1, s ) == 1); // works fine. Print: ref assert(foo(1, S()) == 2); // Fails with: Error: S() is not an lvalue } /***************************************************/ // 10171 struct B10171(T) { static int x; } void test10171() { auto mp = &B10171!(B10171!int).x; } /***************************************************/ // 1900 - template overload set void test1900a() { // function vs function template with IFTI call assert(foo1900a(100) == 1); assert(foo1900a("s") == 2); assert(foo1900b(100) == 1); assert(foo1900b("s") == 2); // function template call with explicit template arguments assert(foo1900a!string("s") == 2); assert(foo1900b!string("s") == 2); // function template overloaded set call with IFTI assert(bar1900a(100) == 1); assert(bar1900a("s") == 2); assert(bar1900b(100) == 1); assert(bar1900b("s") == 2); // function template overloaded set call with explicit template arguments assert(bar1900a!double(100) == 1); assert(bar1900a!string("s") == 2); assert(bar1900b!double(100) == 1); assert(bar1900b!string("s") == 2); // function template overloaded set call with IFTI assert(baz1900(1234567890) == 1); assert(baz1900([1:1, 2:2]) == 2); assert(baz1900(new Object) == 3); assert(baz1900("deadbeaf") == 4); // function template overloaded set call with explicit template arguments assert(baz1900!(double)(14142135) == 1); assert(baz1900!(int[int])([12:34]) == 2); assert(baz1900!(Object)(new Object) == 3); assert(baz1900!(string)("cafe babe") == 4); static assert(!__traits(compiles, bad1900!"++"())); } void test1900b() { S1900 s; // function vs function template with IFTI call assert(s.foo1900a(100) == 1); assert(s.foo1900a("s") == 2); assert(s.foo1900b(100) == 1); assert(s.foo1900b("s") == 2); // function template call with explicit template arguments assert(s.foo1900a!string("s") == 2); assert(s.foo1900b!string("s") == 2); // function template overloaded set call with IFTI assert(s.bar1900a(100) == 1); assert(s.bar1900a("s") == 2); assert(s.bar1900b(100) == 1); assert(s.bar1900b("s") == 2); // function template overloaded set call with explicit template arguments assert(s.bar1900a!double(100) == 1); assert(s.bar1900a!string("s") == 2); assert(s.bar1900b!double(100) == 1); assert(s.bar1900b!string("s") == 2); // function template overloaded set call with IFTI assert(s.baz1900(1234567890) == 1); assert(s.baz1900([1:1, 2:2]) == 2); assert(s.baz1900(new Object) == 3); assert(s.baz1900("deadbeaf") == 4); // function template overloaded set call with explicit template arguments assert(s.baz1900!(double)(14142135) == 1); assert(s.baz1900!(int[int])([12:34]) == 2); assert(s.baz1900!(Object)(new Object) == 3); assert(s.baz1900!(string)("cafe babe") == 4); static assert(!__traits(compiles, s.bad1900!"++"())); } void test1900c() { S1900 s; // This is a kind of Issue 1528 - [tdpl] overloading template and non-template functions //s.funca(); //s.funca(10); //s.funcb(); //s.funcb(10); // Call function template overload set through mixin member lookup assert(s.mixfooa() == 1); assert(s.mixfooa(10) == 2); assert(s.mixfoob() == 1); assert(s.mixfoob(10) == 2); // Call function template overload set through mixin^2 member lookup assert(s.mixsubfooa() == 1); assert(s.mixsubfooa(10) == 2); assert(s.mixsubfoob() == 1); assert(s.mixsubfoob(10) == 2); // Using mixin identifier can limit overload set assert(s.a.mixfooa() == 1); static assert(!__traits(compiles, s.a.mixfooa(10))); assert(s.b.mixfooa(10) == 2); static assert(!__traits(compiles, s.b.mixfooa())); assert(s.b.mixfoob() == 1); static assert(!__traits(compiles, s.b.mixfoob(10))); assert(s.a.mixfoob(10) == 2); static assert(!__traits(compiles, s.a.mixfoob())); } alias merge1900 = imports.template_ovs1.merge1900; alias merge1900 = imports.template_ovs2.merge1900; void test1900d() { assert( merge1900!double(100) == 1); assert(.merge1900!double(100) == 1); } mixin template Foo1900e(T) { void foo(U : T)() { v++;} } void test1900e() { struct S { int v; mixin Foo1900e!double; mixin Foo1900e!string; void test() { foo!(int); // ScopeExp(ti->tempovers != NULL) foo!(typeof(null)); // ScopeExp(ti->tempovers != NULL) } } S s; assert(s.v == 0); s.test(); assert(s.v == 2); } /***************************************************/ // 1900 void test1900() { AClass1900 a; BClass1900 b; static assert(Traits1900!(AClass1900).name == "AClass"); static assert(Traits1900!(BClass1900).name == "BClass"); static assert(Traits1900!(int).name == "any"); Traits1900!(long) obj; static assert(Value1900a!double == 1); static assert(Value1900b!double == 1); static assert(Value1900a!string == 2); static assert(Value1900b!string == 2); } alias imports.template_ovs1.Traits1900 Traits1900X; alias imports.template_ovs2.Traits1900 Traits1900X; alias imports.template_ovs3.Traits1900 Traits1900X; static assert(Traits1900X!(AClass1900).name == "AClass"); static assert(Traits1900X!(BClass1900).name == "BClass"); static assert(Traits1900X!(int).name == "any"); // Traits1900Y is exact same as imports.template_ovs1.Traits1900. alias imports.template_ovs1.Traits1900 Traits1900Y1; alias imports.template_ovs1.Traits1900 Traits1900Y2; alias Traits1900Y1 Traits1900Y; alias Traits1900Y2 Traits1900Y; static assert(Traits1900Y!(AClass1900).name == "AClass"); static assert(!__traits(compiles, Traits1900Y!(BClass1900))); static assert(!__traits(compiles, Traits1900Y!(int))); template Foo1900(T) { template Bar1900(U : T) { } } mixin Foo1900!(int) A1900; mixin Foo1900!(char) B1900; alias Bar1900!(int) bar1900; // error /***************************************************/ // 7780 mixin template A7780() { template C(int n : 0) { int C = 0; } } mixin template B7780() { template C(int n : 1) { int C = 1; } } class Foo7780 { mixin A7780!(); mixin B7780!(); } void test7780() { assert(Foo7780.C!0 == 0); } /***************************************************/ auto foo7849(string) { return 1; } auto foo7849(dstring) { return 2; } enum str7849a = "string"; immutable str7849ai = "string"; immutable str7849bi = str7849ai; enum str7849b = str7849ai; enum str7849c = str7849bi; void test7849() { assert(foo7849(str7849a) == 1); assert(foo7849(str7849b) == 1); assert(foo7849(str7849c) == 1); } /***************************************************/ // 8352 void test8352() { [1, 2].remove8352a!(x => x == 2)(); [1, 2].remove8352b!(x => x == 2)(); remove8352a("deleteme"); remove8352b("deleteme"); } /***************************************************/ // 8441 mixin template T8441a(string i) { auto j(string s = "a", U)(U u1, U u2) { return 0; } auto j(int i,string s = "a", W)(W u1, W u2) { return i; } mixin(" class F" ~ i ~ " { auto j(string s = \"a\", U)(U u1, U u2) { return this.outer.t" ~ i ~ ".j!(s, U)(u1, u2); } auto j(int i, string s = \"a\", W)(W u1, W u2) { return this.outer.t" ~ i ~ ".j!(i, s, W)(u1, u2); // <- dmd is giving error for j!(...).j's type } } auto f" ~ i ~ "() { return new F" ~ i ~ "(); } "); } class X8441a { mixin T8441a!("1") t0; alias t0 t1; } void test8441a() { auto x = new X8441a(); x.f1().j!(3,"a")(2.2, 3.3); } // ---- mixin template T8441b() { void k()() {} void j()() {} void j(int i)() {} } class X8441b { mixin T8441b t0; } void test8441b() { auto x = new X8441b(); x.k!()(); // Fine x.j!()(); // Fine x.t0.k!()(); // Fine x.t0.j!()(); // Derp } // ---- mixin template Signal8441c(Args...) { bool call = false; final void connect(string method, ClassType)(ClassType obj) if (is(ClassType == class) && __traits(compiles, { void delegate(Args) dg = mixin("&obj."~method); })) { call = true; } } void test8441c() { class Observer { void watchInt(string str, int i) {} } class Bar { mixin Signal8441c!(string, int) s1; mixin Signal8441c!(string, int) s2; mixin Signal8441c!(string, long) s3; } auto a = new Bar; auto o1 = new Observer; a.s1.connect!"watchInt"(o1); assert( a.s1.call); assert(!a.s2.call); assert(!a.s3.call); } /***************************************************/ // 9235 template FlowEvaluator9235() { // if control flow bool execute(Command cmd)() if (cmd == Command.Jump || cmd == Command.Fork) { return false; } } template MatchEvaluator9235() { // if operation bool execute(Command cmd)() if (cmd == Command.Char || cmd == Command.Any || cmd == Command.End) { return true; } } void test9235a() { enum Command { Char, Any, Fork, Jump, End } struct Machine { mixin FlowEvaluator9235; mixin MatchEvaluator9235; bool exec_flow() { return execute!(Command.Jump)(); } bool exec_match() { return execute!(Command.Any)(); } } Machine m; assert(!m.exec_flow()); assert( m.exec_match()); } // ---- mixin template mixA9235() { int foo(string s)() if (s == "a") { return 1; } } mixin template mixB9235() { int foo(string s)() if (s == "b") { return 2; } } struct Foo9235 { mixin mixA9235 A; mixin mixB9235 B; alias A.foo foo; alias B.foo foo; } void test9235b() { Foo9235 f; assert(f.foo!"a"() == 1); assert(f.foo!"b"() == 2); } /***************************************************/ // 10658 alias Val10658 = imports.template_ovs1.Val10658; alias Val10658 = imports.template_ovs2.Val10658; static assert(Val10658!1 == 1); static assert(Val10658!1L == 2); // ---- template Foo10658(T) if (is(T == double)) { enum Foo10658 = 1; } template Bar10658(T) if (is(T == string)) { enum Bar10658 = 2; } alias Baz10658 = Foo10658; alias Baz10658 = Bar10658; template Voo10658(T) if (is(T == cfloat)) { enum Voo10658 = 5; } template Voo10658(T) if (is(T == Object)) { enum Voo10658 = 6; } alias Vaz10658 = Baz10658; // OvarDeclaration alias Vaz10658 = Voo10658; // TemplateDeclaration (overnext != NULL) template Merge10658a(alias A) { enum Merge10658a = A!double + A!string; } template Merge10658b(alias A) { enum Merge10658b = A!double + A!string + A!cfloat + A!Object; } void test10658a() { static assert(Baz10658!double == 1); static assert(Baz10658!string == 2); static assert(Voo10658!cfloat == 5); static assert(Voo10658!Object == 6); // pass OverDeclaration through TemplateAliasParameter static assert(Merge10658a!Baz10658 == 1 + 2); static assert(Merge10658b!Vaz10658 == 1 + 2 + 5 + 6); } // ---- mixin template mix10658A() { int f10658(string s)() if (s == "a") { return 1; } } mixin template mix10658B() { int f10658(string s)() if (s == "b") { return 2; } } mixin mix10658A A10658; mixin mix10658B B10658; alias A10658.f10658 foo10658; alias B10658.f10658 foo10658; mixin template mix10658C() { int f10658(string s, T)(T arg) if (s == "c") { return 3; } } mixin template mix10658D() { int f10658(string s, T)(T arg) if (s == "d") { return 4; } } struct S10658 { mixin mix10658C C10658; mixin mix10658D D10658; alias C10658.f10658 foo10658; alias D10658.f10658 foo10658; } void test10658b() { assert( foo10658!"a"() == 1); assert(.foo10658!"b"() == 2); S10658 s; assert(s.foo10658!"c"(0) == 3); assert(s.foo10658!"d"(0) == 4); } /***************************************************/ class InputStream11785 { long read(ubyte* bytes, long len) { return 0; } void read(T)(ref T val) { read(cast(ubyte*)&val, cast(long)val.sizeof); } } long read11785(ubyte* bytes, long len) { return 0; } void read11785(T)(ref T val) { read11785(cast(ubyte*)&val, cast(long)val.sizeof); } void test11785() { int v; read11785(v); auto input = new InputStream11785(); input.read(v); } /***************************************************/ // 11915 int f11915( int) { return 1; } int f11915(ref int) { return 2; } int g11915( int) { return 1; } int g11915(out int) { return 2; } void test11915() { const int n = 1; assert(f11915(n) == 1); assert(g11915(n) == 1); } /***************************************************/ // 11916 auto f11916(T)( T) { return 1; } auto f11916(T)(out T) if (false) { return 2; } auto g11916(T)( T) { return 1; } auto g11916(T)(out T) { return 2; } void test11916() { const int c = 1; int m = 2; // 'out const int' is invalid function parameter, so (out T) version will be dropped // from overload candidates before template constraint evaluated. assert(f11916(c) == 1); // Both (T) and (out T) have valid signatures with T == int, but the 2nd overload will be // dropped from overload candidates because of the template constraint. assert(f11916(m) == 1); // 'out const int' parameter is invalid, so non-out version is selected. assert(g11916(c) == 1); // MATCHconst for (T) version, and MATCHexact for (out T) version. assert(g11916(m) == 2); } /***************************************************/ // 13783 enum E13783 { a = 5 } inout(int) f( inout(int) t) { return t * 2; } ref inout(int) f(ref inout(int) t) { return t; } void test13783() { const E13783 e = E13783.a; assert(f(e) == 10); } /***************************************************/ // 14858 int foo14858()() { return 1; } int bar14858(int) { return 2; } alias foobar14858 = foo14858; alias foobar14858 = bar14858; void test14858() { assert(foobar14858() == 1); assert(foobar14858(1) == 2); // OK <- NG } /***************************************************/ // 14989 template Foo14989(T) if (is(T == int)) { enum Foo14989 = 1; } template Bar14989(T) if (is(T == double)) { enum Bar14989 = 2; } template Baz14989(T) if (is(T == string)) { enum Baz14989 = 3; } alias X14989 = Foo14989; alias X14989 = Bar14989; // X is an alias to is OverDeclaration alias A14989 = X14989; // first, A->aliassym == X static if (true) { alias A14989 = Baz14989; // A->aliassym = new OverDeclaration('A') // then, A->aliassym->overloadInsert(Baz) } template Mix14989a() { alias M14989 = Foo14989; } template Mix14989b() { alias M14989 = Bar14989; } mixin Mix14989a; mixin Mix14989b; alias Y14989 = M14989; // Y is an alias to OverloadSet alias B14989 = Y14989; // first, B->aliassym == Y static if (true) { alias B14989 = Baz14989; // (B->aliassym = new OverloadSet('B') // then, B->aliassym->overloadInsert(Baz) } void test14989() { static assert(X14989!int == 1); static assert(X14989!double == 2); static assert(!__traits(compiles, X14989!string)); // Baz is not in X static assert(A14989!int == 1); static assert(A14989!double == 2); static assert(A14989!string == 3); // OK <- error static assert(Y14989!int == 1); static assert(Y14989!double == 2); static assert(!__traits(compiles, Y14989!string)); // Baz is not in Y static assert(B14989!int == 1); static assert(B14989!double == 2); static assert(B14989!string == 3); // OK <- error } /***************************************************/ // 14965 auto f14965a1() { return f14965a1(123); } int f14965a1(int x) { return x; } int f14965a2(int x) { return x; } auto f14965a2() { return f14965a2(123); } auto f14965b1() { int function(int) fp = &f14965b1; return fp(123); } int f14965b1(int x) { return x; } int f14965b2(int x) { return x; } auto f14965b2() { int function(int) fp = &f14965b2; return fp(123); } auto f14965c1() { auto fp = cast(int function(int))&f14965c1; return fp(123); } int f14965c1(int x) { return x; } int f14965c2(int x) { return x; } auto f14965c2() { auto fp = cast(int function(int))&f14965c2; return fp(123); } int function(int) f14965d1() { return &f14965d1; } int f14965d1(int n) { return 10 + n; } int f14965d2(int n) { return 10 + n; } int function(int) f14965d2() { return &f14965d2; } class C { auto fa1() { return this.fa1(123); } int fa1(int x) { return x; } int fa2(int x) { return x; } auto fa2() { return this.fa2(123); } auto fb1() { int delegate(int) dg = &this.fb1; return dg(123); } int fb1(int x) { return x; } int fb2(int x) { return x; } auto fb2() { int delegate(int) dg = &this.fb2; return dg(123); } auto fc1() { auto dg = cast(int delegate(int))&this.fc1; return dg(123); } int fc1(int x) { return x; } int fc2(int x) { return x; } auto fc2() { auto dg = cast(int delegate(int))&this.fc2; return dg(123); } int delegate(int) fd1() { return &fd1; } int fd1(int n) { return 10 + n; } int fd2(int n) { return 10 + n; } int delegate(int) fd2() { return &fd2; } } void test14965() { assert(f14965a1() == 123); assert(f14965b1() == 123); assert(f14965c1() == 123); assert(f14965d1()(113) == 123); assert(f14965a2() == 123); assert(f14965b2() == 123); assert(f14965c2() == 123); assert(f14965d2()(113) == 123); auto c = new C(); assert(c.fa1() == 123); assert(c.fb1() == 123); assert(c.fc1() == 123); assert(c.fd1()(113) == 123); assert(c.fa2() == 123); assert(c.fb2() == 123); assert(c.fc2() == 123); assert(c.fd2()(113) == 123); } /***************************************************/ int main() { test1528a(); test1528b(); test1528c(); test1528d(); test1680(); test7418(); test7552(); test8668(); test8943(); test9410(); test10171(); test1900a(); test1900b(); test1900c(); test1900d(); test1900e(); test7780(); test7849(); test8352(); test8441a(); test8441b(); test8441c(); test9235a(); test9235b(); test10658a(); test10658b(); test11785(); test11915(); test11916(); test13783(); test14858(); test14965(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/c22.d0000664000175000017500000000027412776215022020742 0ustar kaikai// EXTRA_SOURCES: imports/c22a.d imports/c22b.d // PERMUTE_ARGS: module main; import imports.c22a; import imports.c22b; int main() { afn1(); afn2(); bfn1(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test30.d0000664000175000017500000000020312776215022021466 0ustar kaikai// 444 int main() { int nothing( int delegate(ref int) dg ) {return 0;} foreach(int x; ¬hing) return 7; return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_217.d0000664000175000017500000000025312776215022023046 0ustar kaikaiimport imports.ldc_github_217a; struct A { bool foo() { return true; } void bar() { B!((i) { return foo(); })(0); } } void main() { } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test61.d0000664000175000017500000000024412776215022021477 0ustar kaikai// PERMUTE_ARGS: // EXTRA_SOURCES: imports/test61a.d // Bugzilla 6556 debug=BUG; void main() { debug(BUG) import imports.test61a; assert(bar() == 12); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/property.d0000664000175000017500000000116412776215022022237 0ustar kaikai /******************************************/ struct Foo { int v; int bar(int value) { return v = value + 2; } int bar() { return 73; } } int test1() { Foo f; int i; i = (f.bar = 6); assert(i == 8); assert(f.v == 8); i = f.bar; assert(i == 73); return 0; } /******************************************/ // 6259 struct S6259 { private int m_prop; ref const(int) prop() { return m_prop; } void prop(int v) { m_prop = v; } } void test6259() { S6259 s; s.prop = 1; } /******************************************/ void main() { test1(); test6259(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testrightthis.d0000664000175000017500000004766212776215022023275 0ustar kaikai// runnable/traits.d 9091,8972,8971,7027 // runnable/test4.d test6() extern(C) int printf(const char*, ...); template TypeTuple(TL...) { alias TypeTuple = TL; } /********************************************************/ mixin("struct S1 {"~aggrDecl1~"}"); mixin("class C1 {"~aggrDecl1~"}"); enum aggrDecl1 = q{ alias Type = typeof(this); int x = 2; void foo() { static assert( is(typeof(Type.x.offsetof))); static assert( is(typeof(Type.x.mangleof))); static assert( is(typeof(Type.x.sizeof ))); static assert( is(typeof(Type.x.alignof ))); static assert( is(typeof({ auto n = Type.x.offsetof; }))); static assert( is(typeof({ auto n = Type.x.mangleof; }))); static assert( is(typeof({ auto n = Type.x.sizeof; }))); static assert( is(typeof({ auto n = Type.x.alignof; }))); static assert( is(typeof(Type.x))); static assert( is(typeof({ auto n = Type.x; }))); static assert( __traits(compiles, Type.x)); static assert( __traits(compiles, { auto n = Type.x; })); static assert( is(typeof(x.offsetof))); static assert( is(typeof(x.mangleof))); static assert( is(typeof(x.sizeof ))); static assert( is(typeof(x.alignof ))); static assert( is(typeof({ auto n = x.offsetof; }))); static assert( is(typeof({ auto n = x.mangleof; }))); static assert( is(typeof({ auto n = x.sizeof; }))); static assert( is(typeof({ auto n = x.alignof; }))); static assert( is(typeof(x))); static assert( is(typeof({ auto n = x; }))); static assert( __traits(compiles, x)); static assert( __traits(compiles, { auto n = x; })); with (this) { static assert( is(typeof(x.offsetof))); static assert( is(typeof(x.mangleof))); static assert( is(typeof(x.sizeof ))); static assert( is(typeof(x.alignof ))); static assert( is(typeof({ auto n = x.offsetof; }))); static assert( is(typeof({ auto n = x.mangleof; }))); static assert( is(typeof({ auto n = x.sizeof; }))); static assert( is(typeof({ auto n = x.alignof; }))); static assert( is(typeof(x))); static assert( is(typeof({ auto n = x; }))); static assert( __traits(compiles, x)); static assert( __traits(compiles, { auto n = x; })); } } static void bar() { static assert( is(typeof(Type.x.offsetof))); static assert( is(typeof(Type.x.mangleof))); static assert( is(typeof(Type.x.sizeof ))); static assert( is(typeof(Type.x.alignof ))); static assert( is(typeof({ auto n = Type.x.offsetof; }))); static assert( is(typeof({ auto n = Type.x.mangleof; }))); static assert( is(typeof({ auto n = Type.x.sizeof; }))); static assert( is(typeof({ auto n = Type.x.alignof; }))); static assert( is(typeof(Type.x))); static assert(!is(typeof({ auto n = Type.x; }))); static assert( __traits(compiles, Type.x)); static assert(!__traits(compiles, { auto n = Type.x; })); static assert( is(typeof(x.offsetof))); static assert( is(typeof(x.mangleof))); static assert( is(typeof(x.sizeof ))); static assert( is(typeof(x.alignof ))); static assert( is(typeof({ auto n = x.offsetof; }))); static assert( is(typeof({ auto n = x.mangleof; }))); static assert( is(typeof({ auto n = x.sizeof; }))); static assert( is(typeof({ auto n = x.alignof; }))); static assert( is(typeof(x))); static assert(!is(typeof({ auto n = x; }))); static assert( __traits(compiles, x)); static assert(!__traits(compiles, { auto n = x; })); Type t; with (t) { static assert( is(typeof(x.offsetof))); static assert( is(typeof(x.mangleof))); static assert( is(typeof(x.sizeof ))); static assert( is(typeof(x.alignof ))); static assert( is(typeof({ auto n = x.offsetof; }))); static assert( is(typeof({ auto n = x.mangleof; }))); static assert( is(typeof({ auto n = x.sizeof; }))); static assert( is(typeof({ auto n = x.alignof; }))); static assert( is(typeof(x))); static assert( is(typeof({ auto n = x; }))); static assert( __traits(compiles, x)); static assert( __traits(compiles, { auto n = x; })); } } }; void test1() { foreach (Type; TypeTuple!(S1, C1)) { static assert( is(typeof(Type.x.offsetof))); static assert( is(typeof(Type.x.mangleof))); static assert( is(typeof(Type.x.sizeof ))); static assert( is(typeof(Type.x.alignof ))); static assert( is(typeof({ auto n = Type.x.offsetof; }))); static assert( is(typeof({ auto n = Type.x.mangleof; }))); static assert( is(typeof({ auto n = Type.x.sizeof; }))); static assert( is(typeof({ auto n = Type.x.alignof; }))); static assert( is(typeof(Type.x))); static assert(!is(typeof({ auto n = Type.x; }))); static assert( __traits(compiles, Type.x)); static assert(!__traits(compiles, { auto n = Type.x; })); Type t; static assert( is(typeof(t.x.offsetof))); static assert( is(typeof(t.x.mangleof))); static assert( is(typeof(t.x.sizeof ))); static assert( is(typeof(t.x.alignof ))); static assert( is(typeof({ auto n = t.x.offsetof; }))); static assert( is(typeof({ auto n = t.x.mangleof; }))); static assert( is(typeof({ auto n = t.x.sizeof; }))); static assert( is(typeof({ auto n = t.x.alignof; }))); static assert( is(typeof(t.x))); static assert( is(typeof({ auto n = t.x; }))); static assert( __traits(compiles, t.x)); static assert( __traits(compiles, { auto n = t.x; })); with (t) { static assert( is(typeof(x.offsetof))); static assert( is(typeof(x.mangleof))); static assert( is(typeof(x.sizeof ))); static assert( is(typeof(x.alignof ))); static assert( is(typeof({ auto n = x.offsetof; }))); static assert( is(typeof({ auto n = x.mangleof; }))); static assert( is(typeof({ auto n = x.sizeof; }))); static assert( is(typeof({ auto n = x.alignof; }))); static assert( is(typeof(x))); static assert( is(typeof({ auto n = x; }))); static assert( __traits(compiles, x)); static assert( __traits(compiles, { auto n = x; })); } } } /********************************************************/ void test2() { struct S { int val; int[] arr; int[int] aar; void foo() {} void boo()() {} static void test() { static assert(!__traits(compiles, S.foo())); static assert(!__traits(compiles, S.boo())); static assert(!__traits(compiles, foo())); static assert(!__traits(compiles, boo())); } } int v; int[] a; void f(int n) {} static assert( __traits(compiles, S.val)); // 'S.val' is treated just a symbol static assert(!__traits(compiles, { int n = S.val; })); static assert(!__traits(compiles, f(S.val))); static assert(!__traits(compiles, v = S.val) && !__traits(compiles, S.val = v)); static assert(!__traits(compiles, 1 + S.val) && !__traits(compiles, S.val + 1)); static assert(!__traits(compiles, 1 - S.val) && !__traits(compiles, S.val - 1)); static assert(!__traits(compiles, 1 * S.val) && !__traits(compiles, S.val * 1)); static assert(!__traits(compiles, 1 / S.val) && !__traits(compiles, S.val / 1)); static assert(!__traits(compiles, 1 % S.val) && !__traits(compiles, S.val % 1)); static assert(!__traits(compiles, 1 ~ S.arr) && !__traits(compiles, S.arr ~ 1)); static assert(!__traits(compiles, 1 & S.val) && !__traits(compiles, S.val & 1)); static assert(!__traits(compiles, 1 | S.val) && !__traits(compiles, S.val | 1)); static assert(!__traits(compiles, 1 ^ S.val) && !__traits(compiles, S.val ^ 1)); static assert(!__traits(compiles, 1 ~ S.val) && !__traits(compiles, S.val ~ 1)); static assert(!__traits(compiles, 1 ^^ S.val) && !__traits(compiles, S.val ^^ 1)); static assert(!__traits(compiles, 1 << S.val) && !__traits(compiles, S.val << 1)); static assert(!__traits(compiles, 1 >> S.val) && !__traits(compiles, S.val >> 1)); static assert(!__traits(compiles, 1 >>>S.val) && !__traits(compiles, S.val >>>1)); static assert(!__traits(compiles, 1 && S.val) && !__traits(compiles, S.val && 1)); static assert(!__traits(compiles, 1 || S.val) && !__traits(compiles, S.val || 1)); static assert(!__traits(compiles, 1 in S.aar) && !__traits(compiles, S.val || [1:1])); static assert(!__traits(compiles, 1 <= S.val) && !__traits(compiles, S.val <= 1)); static assert(!__traits(compiles, 1 == S.val) && !__traits(compiles, S.val == 1)); static assert(!__traits(compiles, 1 is S.val) && !__traits(compiles, S.val is 1)); static assert(!__traits(compiles, 1? 1:S.val) && !__traits(compiles, 1? S.val:1)); static assert(!__traits(compiles, (1, S.val)) && !__traits(compiles, (S.val, 1))); static assert(!__traits(compiles, &S.val)); static assert(!__traits(compiles, S.arr[0]) && !__traits(compiles, [1,2][S.val])); static assert(!__traits(compiles, S.val++) && !__traits(compiles, S.val--)); static assert(!__traits(compiles, ++S.val) && !__traits(compiles, --S.val)); static assert(!__traits(compiles, v += S.val) && !__traits(compiles, S.val += 1)); static assert(!__traits(compiles, v -= S.val) && !__traits(compiles, S.val -= 1)); static assert(!__traits(compiles, v *= S.val) && !__traits(compiles, S.val *= 1)); static assert(!__traits(compiles, v /= S.val) && !__traits(compiles, S.val /= 1)); static assert(!__traits(compiles, v %= S.val) && !__traits(compiles, S.val %= 1)); static assert(!__traits(compiles, v &= S.val) && !__traits(compiles, S.val &= 1)); static assert(!__traits(compiles, v |= S.val) && !__traits(compiles, S.val |= 1)); static assert(!__traits(compiles, v ^= S.val) && !__traits(compiles, S.val ^= 1)); static assert(!__traits(compiles, a ~= S.val) && !__traits(compiles, S.arr ~= 1)); static assert(!__traits(compiles, v ^^= S.val) && !__traits(compiles, S.val ^^= 1)); static assert(!__traits(compiles, v <<= S.val) && !__traits(compiles, S.val <<= 1)); static assert(!__traits(compiles, v >>= S.val) && !__traits(compiles, S.val >>= 1)); static assert(!__traits(compiles, v >>>=S.val) && !__traits(compiles, S.val >>>=1)); static assert(!__traits(compiles, { auto x = 1 + S.val; }) && !__traits(compiles, { auto x = S.val + 1; })); static assert(!__traits(compiles, { auto x = 1 - S.val; }) && !__traits(compiles, { auto x = S.val - 1; })); static assert(!__traits(compiles, { auto x = S.arr ~ 1; }) && !__traits(compiles, { auto x = 1 ~ S.arr; })); static assert(!__traits(compiles, S.foo())); static assert(!__traits(compiles, S.boo())); S.test(); alias foo = S.foo; alias boo = S.boo; static assert(!__traits(compiles, foo())); static assert(!__traits(compiles, boo())); // static assert(S.val); struct SW { int a; } class CW { int a; } static assert(!__traits(compiles, { with (SW) { int n = a; } })); static assert(!__traits(compiles, { with (CW) { int n = a; } })); } /********************************************************/ struct S3 { struct T3 { int val; void foo() {} } T3 member; alias member this; static void test() { static assert(!__traits(compiles, S3.val = 1 )); static assert(!__traits(compiles, { S3.val = 1; })); static assert(!__traits(compiles, T3.val = 1 )); static assert(!__traits(compiles, { T3.val = 1; })); static assert(!__traits(compiles, __traits(getMember, S3, "val") = 1 )); static assert(!__traits(compiles, { __traits(getMember, S3, "val") = 1; })); static assert(!__traits(compiles, __traits(getMember, T3, "val") = 1 )); static assert(!__traits(compiles, { __traits(getMember, T3, "val") = 1; })); static assert(!__traits(compiles, S3.foo() )); static assert(!__traits(compiles, { S3.foo(); })); static assert(!__traits(compiles, T3.foo() )); static assert(!__traits(compiles, { T3.foo(); })); static assert(!__traits(compiles, __traits(getMember, S3, "foo")() )); static assert(!__traits(compiles, { __traits(getMember, S3, "foo")(); })); static assert(!__traits(compiles, __traits(getMember, T3, "foo")() )); static assert(!__traits(compiles, { __traits(getMember, T3, "foo")(); })); static assert(!__traits(compiles, __traits(getOverloads, S3, "foo")[0]() )); static assert(!__traits(compiles, { __traits(getOverloads, S3, "foo")[0](); })); static assert(!__traits(compiles, __traits(getOverloads, T3, "foo")[0]() )); static assert(!__traits(compiles, { __traits(getOverloads, T3, "foo")[0](); })); } } void test3() { } /********************************************************/ void test4() { static struct R { void opIndex(int) {} void opSlice() {} void opSlice(int, int) {} int opDollar() { return 1; } alias length = opDollar; } R val; static struct S { R val; void foo() { static assert(__traits(compiles, val[1])); // TypeSArray static assert(__traits(compiles, val[])); // TypeDArray static assert(__traits(compiles, val[0..val.length])); // TypeSlice } } } /********************************************************/ template Test5(string name, bool result) { mixin(`static assert(__traits(compiles, `~name~`.add!"months"(1)) == result);`); } static struct Begin5 { void add(string s)(int n) {} } struct IntervalX5(TP) { Begin5 begin; static assert(__traits(compiles, begin.add!"months"(1)) == true); mixin Test5!("begin", true); void foo() { static assert(__traits(compiles, begin.add!"months"(1)) == true); mixin Test5!("begin", true); } static test() { static assert(__traits(compiles, begin.add!"months"(1)) == false); mixin Test5!("begin", false); } } alias IX5 = IntervalX5!int; alias beginX5 = IX5.begin; static assert(__traits(compiles, beginX5.add!"months"(1)) == false); mixin Test5!("beginG5", false); void test5() { static struct IntervalY5(TP) { Begin5 begin; static assert(__traits(compiles, begin.add!"months"(1)) == true); mixin Test5!("begin", true); void foo() { static assert(__traits(compiles, begin.add!"months"(1)) == true); mixin Test5!("begin", true); } static test() { static assert(__traits(compiles, begin.add!"months"(1)) == false); mixin Test5!("begin", false); } } alias IX = IntervalX5!int; alias beginX = IX.begin; static assert(__traits(compiles, beginX.add!"months"(1)) == false); mixin Test5!("beginX", false); alias IY = IntervalY5!int; alias beginY = IY.begin; static assert(__traits(compiles, beginY.add!"months"(1)) == false); mixin Test5!("beginY", false); } /********************************************************/ void test6() { static struct Foo { static struct Bar { static int get() { return 0; } static int val; void set() { assert(0); } int num; } static class Baz { static int get() { return 0; } static int val; void set() { assert(0); } int num; } Bar bar; Baz baz; } // allowed cases that do 'use' Foo.bar without this assert(Foo.bar.get() == 0); // Foo.bar.get() assert(Foo.baz.get() == 0); // Foo.bar.get() static assert(!__traits(compiles, Foo.bar.set())); static assert(!__traits(compiles, Foo.baz.set())); assert(Foo.bar.val == 0); // Foo.bar.val assert(Foo.baz.val == 0); // Foo.baz.val static assert(!__traits(compiles, Foo.bar.num = 1)); static assert(!__traits(compiles, Foo.baz.num = 1)); } /********************************************************/ struct Tuple7(T...) { T field; enum check1 = is(typeof(field[0] = 1)); enum check2 = is(typeof({ field[0] = 1; })); this(U, size_t n)(U[n] values) if (is(typeof({ foreach (i, _; T) field[0] = values[0]; }))) {} } void test7() { alias Tuple7!(int, int) Tup7; static assert(Tup7.check1); static assert(Tup7.check2); int[2] ints = [ 1, 2 ]; Tup7 t = ints; struct S7 { int value; enum check1 = is(typeof(value = 1)); enum check2 = is(typeof({ value = 1; })); void foo()(int v) if (is(typeof({ value = v; // valid }))) {} static void bar()(int v) if (is(typeof({ value = v; // always invalid }))) {} } static assert(S7.check1); static assert(S7.check2); S7 s; s.foo(1); static assert(!__traits(compiles, S7.bar(1))); } /********************************************************/ // 4350 template Mix4350() { int b; } struct S4350 { int a; mixin Mix4350 mix; int c; template Func() { void call(int n) { c = n; } } alias func = Func!(); } void test4350() { S4350 s; s.a = 1; s.mix.b = 2; s.func.call(3); assert(s.a == 1); assert(s.b == 2); assert(s.c == 3); with (s) { a = 2; } with (s) { mix.b = 3; } with (s) { func.call(4); } assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } /********************************************************/ // 6430 auto bug6430(int a) { static struct Result2 {} return 4; } auto bug6430(int a, int b) { static struct Result2 { int z; int y() { return z; } } auto t = Result2(1); return 5; } /********************************************************/ // 9619 struct Foo9619 { int x; } void test9619() { void bar() { typeof(Foo9619.x) y; } } /********************************************************/ // 9633 class Foo9633 { void baz() {} void bar() { // CallExp::e1->op == TOKvar static assert(!compilesWithoutThis9633!baz); } void vaz()() { static class C { // CallExp::e1->op == TOKtemplate static assert(!__traits(compiles, vaz())); } } } template compilesWithoutThis9633(alias F) { enum bool compilesWithoutThis9633 = __traits(compiles, F()); } void test9633() { auto foo = new Foo9633; foo.bar(); foo.vaz(); } /********************************************************/ // 11245 struct Vec11245 { float[2] f; } class Bar11245 { void func() { pragma(msg, "===="); float[Vec11245.f.length] newVal; } } /********************************************************/ // 11614 struct Tuple11614(T...) { T field; alias field this; } struct Foo11614 { alias Tuple11614!(int) NEW_ARGS; NEW_ARGS args; void foo() { static if (NEW_ARGS.length == 1) {} else static assert(0); } } /********************************************************/ // 11993 struct S11993 { void foo()() const if (is(typeof(this) == const(S11993))) {} const void bar()() if (is(typeof(this) == const(S11993))) {} } void test11993() { S11993 s; s.foo(); s.bar(); } /********************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test4350(); test9619(); test9633(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/m1.d0000664000175000017500000000035312776215022020667 0ustar kaikai// EXTRA_SOURCES: imports/m1a.d // PERMUTE_ARGS: module m1; import std.stdio; import imports.m1a; class A { } A createA() { return new A; } alias A function() aliasM1; void main() { aFunc( &createA ); printf("Success\n"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test7603.d0000664000175000017500000000062612776215022021654 0ustar kaikaivoid test7603() { int g; void foo(int n, ref int r = g) { r = n; } int x; foo(1, x); assert(x == 1); foo(2); assert(g == 2); int h = 100; void bar(int n, out int r = h) { if (n != 0) r = n; } bar(0); assert(h == 0); bar(10); assert(h == 10); bar(10, x); assert(x == 10); bar(0, x); assert(x == 0); } void main() { test7603(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/xtest55.d0000664000175000017500000000065212776215022021675 0ustar kaikai// PERMUTE_ARGS: import core.memory, std.stdio; Stuff* stuff1; struct Stuff { uint num; } int main() { stuff1 = new Stuff; stuff1.num = 1; auto bar = new byte[1024 * 1024]; auto stuff2 = new Stuff; stuff2.num = 2; writeln(stuff1, "\t", stuff2); // Same address. assert(stuff1 != stuff2); writeln(stuff1.num, "\t", stuff2.num); // Both 2. assert(stuff1.num == 1); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test435.d0000664000175000017500000000375312776215022021574 0ustar kaikaiimport core.stdc.stdio; class A { immutable size_t f; this(T)(T z) { f = z.sizeof; } } struct AS { immutable size_t f; this(T)(T z) { f = z.sizeof; } } void test0() { assert((new A(2.2)).f == double.sizeof); assert((new A('g')).f == char.sizeof); assert((AS(17)).f == int.sizeof); assert((AS(null)).f == typeof(null).sizeof); } //------------------------------------------------------------------------------ class C { const int x; const int y; this(T...)(T z) { this.tupleof = z; } } struct CS { const int x; const int y; this(T...)(T z) { this.tupleof = z; } } void test1() { auto c = new C(4, 6); assert(c.x == 4); assert(c.y == 6); auto cs = CS(7, 8); assert(cs.x == 7); assert(cs.y == 8); } //------------------------------------------------------------------------------ // bug 435. class B { int i; this(int k) { i = k; } } class D : B { this(A...)(A args) { super(args); } } void test2() { auto a = new D(4); assert(a.i == 4); } //------------------------------------------------------------------------------ // bug 4905 class C2 { string x; this(T...)(in string msg, T args) { x = msg; foreach (a; args) x ~= a; } } void test3() { auto c2 = new C2("test"); assert(c2.x == "test"); auto c3 = new C2("test", " variadic", " constructor"); assert(c3.x == "test variadic constructor"); } //------------------------------------------------------------------------------ // bug 4531 test case 2 class MyError : Exception { this(T...)(T msg) { assert(msg[0] == "Hello, " && msg[1] == 42); super("Hello, 42"); } } void test4() { auto err = new MyError("Hello, ", 42); assert(err.msg == "Hello, 42"); } void main() { test0(); test1(); test2(); test3(); test4(); printf("Success\n"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/builtin.d0000664000175000017500000000562112776215022022023 0ustar kaikai import std.stdio; import std.math; import core.bitop; version (DigitalMars) { version (X86_64) version = AnyX86; else version (X86) version = AnyX86; } /*******************************************/ void test1() { writefln("%a", sin(6.8L)); auto f = 6.8L; writefln("%a", sin(f)); assert(sin(f) == sin(6.8L)); static assert(approxEqual(sin(6.8L), 0x1.f9f8d9aea10fdf1cp-2)); writefln("%a", cos(6.8L)); f = 6.8L; writefln("%a", cos(f)); assert(cos(f) == cos(6.8L)); static assert(approxEqual(cos(6.8L), 0x1.bd21aaf88dcfa13ap-1)); writefln("%a", tan(6.8L)); f = 6.8L; writefln("%a", tan(f)); version (Win64) { } else assert(tan(f) == tan(6.8L)); static assert(approxEqual(tan(6.8L), 0x1.22fd752af75cd08cp-1)); } /*******************************************/ void test2() { float i = 3; i = i ^^ 2; assert(i == 9); int j = 2; j = j ^^ 1; assert(j == 2); i = 4; i = i ^^ .5; assert(i == 2); } /**** Bug 5703 *****************************/ static assert({ int a = 0x80; int f = bsf(a); int r = bsr(a); a = 0x22; assert(bsf(a)==1); assert(bsr(a)==5); a = 0x8000000; assert(bsf(a)==27); assert(bsr(a)==27); a = 0x13f562c0; assert(bsf(a) == 6); assert(bsr(a) == 28); assert(bswap(0xAABBCCDD) == 0xDDCCBBAA); return true; }()); /*******************************************/ void test3() { version (AnyX86) { static assert( _popcnt( cast(ushort)0 ) == 0 ); static assert( _popcnt( cast(ushort)7 ) == 3 ); static assert( _popcnt( cast(ushort)0xAA )== 4); static assert( _popcnt( cast(ushort)0xFFFF ) == 16 ); static assert( _popcnt( cast(ushort)0xCCCC ) == 8 ); static assert( _popcnt( cast(ushort)0x7777 ) == 12 ); static assert( _popcnt( cast(uint)0 ) == 0 ); static assert( _popcnt( cast(uint)7 ) == 3 ); static assert( _popcnt( cast(uint)0xAA )== 4); static assert( _popcnt( cast(uint)0x8421_1248 ) == 8 ); static assert( _popcnt( cast(uint)0xFFFF_FFFF ) == 32 ); static assert( _popcnt( cast(uint)0xCCCC_CCCC ) == 16 ); static assert( _popcnt( cast(uint)0x7777_7777 ) == 24 ); version (X86_64) { static assert( _popcnt( cast(ulong)0 ) == 0 ); static assert( _popcnt( cast(ulong)7 ) == 3 ); static assert( _popcnt( cast(ulong)0xAA )== 4); static assert( _popcnt( cast(ulong)0x8421_1248 ) == 8 ); static assert( _popcnt( cast(ulong)0xFFFF_FFFF_FFFF_FFFF ) == 64 ); static assert( _popcnt( cast(ulong)0xCCCC_CCCC_CCCC_CCCC ) == 32 ); static assert( _popcnt( cast(ulong)0x7777_7777_7777_7777 ) == 48 ); } } } /*******************************************/ int main() { test1(); test2(); test3(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/gdb14225.d0000664000175000017500000000031312776215022021500 0ustar kaikai/* REQUIRED_ARGS: -g PERMUTE_ARGS: GDB_SCRIPT: --- b 17 r echo RESULT= p lok --- GDB_MATCH: RESULT=.*Something */ void main() { string lok = "Something"; auto chars = "Anything".dup; // BP } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/xdtor.d0000664000175000017500000000253712776215022021520 0ustar kaikai// PERMUTE_ARGS: struct Field { ~this() @safe @nogc pure nothrow {} } struct Counter { static size_t cnt; ~this() @safe @nogc nothrow { ++cnt; } } struct Foo { ~this() @safe @nogc pure nothrow {} Field field; } class Bar { ~this() @safe @nogc pure nothrow {} Field field; } void test1() @safe @nogc pure nothrow { Foo foo; foo.__xdtor(); scope bar = new Bar(); bar.__xdtor(); } static assert(__traits(hasMember, Foo, "__xdtor")); static assert(__traits(hasMember, Bar, "__xdtor")); // struct FieldDtor { Counter counter; } struct AggrDtor { static size_t cnt; ~this() @safe @nogc nothrow { ++cnt; } } struct MixedDtor { static size_t cnt; Counter counter; ~this() @safe @nogc nothrow { ++cnt; } } struct SNoDtor {} class CNoDtor {} static assert(!__traits(hasMember, SNoDtor, "__xdtor")); static assert(!__traits(hasMember, CNoDtor, "__xdtor")); void test2() @safe @nogc nothrow { FieldDtor a; assert(Counter.cnt == 0); a.__xdtor(); assert(Counter.cnt == 1); AggrDtor b; assert(AggrDtor.cnt == 0); b.__xdtor(); assert(AggrDtor.cnt == 1); Counter.cnt = 0; MixedDtor c; assert(MixedDtor.cnt == 0); assert(Counter.cnt == 0); c.__xdtor(); assert(MixedDtor.cnt == 1); assert(Counter.cnt == 1); } void main() { test1(); test2(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testmodule.d0000664000175000017500000000056412776215022022543 0ustar kaikai// PERMUTE_ARGS: // $HeadURL$ // $Date$ // $Author$ // @author@ Anders F Björklund // @date@ 2005-01-25 // @uri@ news:ct428n$2qoe$1@digitaldaemon.com // @url@ nntp://news.digitalmars.com/D.gnu/983 module dstress.run.unicode_06_哪里; int 哪里(int ö){ return ö+2; } int main(){ assert(dstress.run.unicode_06_哪里.哪里(2)==4); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_248.d0000664000175000017500000000022112776215022023045 0ustar kaikaivoid test() { int a, b, c; int*[int] assArray = [ 1: &a, 2: &b, 3: &c ]; } void main() { test(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/linkdebug.sh0000775000175000017500000000111012776215022022500 0ustar kaikai#!/usr/bin/env bash src=runnable${SEP}extra-files dir=${RESULTS_DIR}${SEP}runnable output_file=${dir}/linkdebug.sh.out if [ $OS == "win32" -o $OS == "win64" ]; then LIBEXT=.lib else LIBEXT=.a fi libname=${dir}${SEP}libX${LIBEXT} $DMD -m${MODEL} -I${src} -of${libname} -lib ${src}${SEP}linkdebug_uni.d ${src}${SEP}linkdebug_range.d ${src}${SEP}linkdebug_primitives.d || exit 1 $DMD -m${MODEL} -I${src} -of${dir}${SEP}linkdebug${EXE} -g -debug ${src}${SEP}linkdebug.d ${libname} || exit 1 rm ${libname} rm ${dir}/{linkdebug${OBJ},linkdebug${EXE}} echo Success > ${output_file} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_131_1.d0000664000175000017500000000017512776215022023264 0ustar kaikai// EXTRA_SOURCES: imports/ldc_github_131_1a.d import imports.ldc_github_131_1a; void main() { auto a = dirEntries(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test32.d0000664000175000017500000000023212776215022021472 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/test32a.d // PERMUTE_ARGS: import imports.test32a; void main() { assert(S.sizeof == int.sizeof); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/cov2.d0000664000175000017500000000205012776215022021217 0ustar kaikai// PERMUTE_ARGS: // POST_SCRIPT: runnable/extra-files/cov2-postscript.sh // REQUIRED_ARGS: -cov // EXECUTE_ARGS: ${RESULTS_DIR}/runnable extern(C) void dmd_coverDestPath(string pathname); /***************************************************/ void test1() { int counter = 20; do { --counter; } while(counter > 0); } /***************************************************/ struct S2 { this(this) { int x = 1; } ~this() { int x = 1; } ref S2 opAssign(S2) { return this; } bool opEquals(ref const S2) const { return true; } } struct T2 { S2 s; this(this) { int x = 1; } ~this() { int x = 1; } } void test2() { T2 ta; T2 tb = ta; tb = ta; typeid(T2).equals(&ta, &tb); } /***************************************************/ void test3() { long total = 0; for (size_t i = 0; i < 10_000_000; i++) total += i; } /***************************************************/ int main(string[] args) { dmd_coverDestPath(args[1]); test1(); test2(); test3(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/sdtor.d0000664000175000017500000025313312776215022021513 0ustar kaikai import core.vararg; extern (C) int printf(const(char*) fmt, ...); template TypeTuple(T...) { alias TypeTuple = T; } /**********************************/ int sdtor; struct S1 { ~this() { printf("~S()\n"); sdtor++; } } void test1() { S1* s = new S1(); delete s; assert(sdtor == 1); } /**********************************/ int sdtor2; struct S2 { ~this() { printf("~S2()\n"); sdtor2++; } delete(void* p) { assert(sdtor2 == 1); printf("S2.delete()\n"); sdtor2++; } } void test2() { S2* s = new S2(); delete s; assert(sdtor2 == 2); } /**********************************/ int sdtor3; struct S3 { int a; ~this() { printf("~S3()\n"); sdtor3++; assert(a == 3); } } struct T3 { int i; S3 s; } void test3() { T3* s = new T3(); s.s.a = 3; delete s; assert(sdtor3 == 1); } /**********************************/ int sdtor4; struct S4 { int a = 3; ~this() { printf("~S4()\n"); if (a == 4) assert(sdtor4 == 2); else { assert(a == 3); assert(sdtor4 == 1); } sdtor4++; } } struct T4 { int i; S4 s; ~this() { printf("~T4()\n"); assert(sdtor4 == 0); sdtor4++; } S4 t; } void test4() { T4* s = new T4(); s.s.a = 4; delete s; assert(sdtor4 == 3); } /**********************************/ int sdtor5; template M5() { ~this() { printf("~M5()\n"); assert(sdtor5 == 1); sdtor5++; } } struct T5 { mixin M5 m; ~this() { printf("~T5()\n"); assert(sdtor5 == 0); sdtor5++; } } void test5() { T5* s = new T5(); delete s; assert(sdtor5 == 2); } /**********************************/ int sdtor6; struct S6 { int b = 7; ~this() { printf("~S6()\n"); assert(b == 7); assert(sdtor6 == 1); sdtor6++; } } class T6 { int a = 3; S6 s; ~this() { printf("~T6()\n"); assert(a == 3); assert(sdtor6 == 0); sdtor6++; } } void test6() { T6 s = new T6(); delete s; assert(sdtor6 == 2); } /**********************************/ int sdtor7; struct S7 { int b = 7; ~this() { printf("~S7()\n"); assert(b == 7); assert(sdtor7 >= 1 && sdtor7 <= 3); sdtor7++; } } struct T7 { int a = 3; S7[3] s; ~this() { printf("~T7() %d\n", sdtor7); assert(a == 3); assert(sdtor7 == 0); sdtor7++; } } void test7() { T7* s = new T7(); delete s; assert(sdtor7 == 4); } /**********************************/ int sdtor8; struct S8 { int b = 7; int c; ~this() { printf("~S8() %d\n", sdtor8); assert(b == 7); assert(sdtor8 == c); sdtor8++; } } void test8() { S8[] s = new S8[3]; s[0].c = 2; s[1].c = 1; s[2].c = 0; delete s; assert(sdtor8 == 3); } /**********************************/ int sdtor9; struct S9 { int b = 7; ~this() { printf("~S9() %d\n", sdtor9); assert(b == 7); sdtor9++; } } void test9() { { S9 s; } assert(sdtor9 == 1); } /**********************************/ int sdtor10; struct S10 { int b = 7; int c; ~this() { printf("~S10() %d\n", sdtor10); assert(b == 7); assert(sdtor10 == c); sdtor10++; } } void test10() { { S10[3] s; s[0].c = 2; s[1].c = 1; s[2].c = 0; } assert(sdtor10 == 3); } /**********************************/ int sdtor11; template M11() { ~this() { printf("~M11()\n"); assert(sdtor11 == 1); sdtor11++; } } class T11 { mixin M11 m; ~this() { printf("~T11()\n"); assert(sdtor11 == 0); sdtor11++; } } void test11() { T11 s = new T11(); delete s; assert(sdtor11 == 2); } /**********************************/ int sdtor12; struct S12 { int a = 3; ~this() { printf("~S12() %d\n", sdtor12); sdtor12++; } } void foo12(S12 s) { } void test12() { { S12 s; foo12(s); s.a = 4; } assert(sdtor12 == 2); } /**********************************/ struct S13 { int a = 3; int opAssign(S13 s) { printf("S13.opAssign(%p)\n", &this); a = 4; return s.a + 2; } } void test13() { S13 s; S13 t; assert((s = t) == 5); assert(s.a == 4); } /**********************************/ struct S14 { int a = 3; int opAssign(ref S14 s) { printf("S14.opAssign(%p)\n", &this); a = 4; return s.a + 2; } } void test14() { S14 s; S14 t; assert((s = t) == 5); assert(s.a == 4); } /**********************************/ struct S15 { int a = 3; int opAssign(ref const S15 s) { printf("S15.opAssign(%p)\n", &this); a = 4; return s.a + 2; } } void test15() { S15 s; S15 t; assert((s = t) == 5); assert(s.a == 4); } /**********************************/ struct S16 { int a = 3; int opAssign(S16 s, ...) { printf("S16.opAssign(%p)\n", &this); a = 4; return s.a + 2; } } void test16() { S16 s; S16 t; assert((s = t) == 5); assert(s.a == 4); } /**********************************/ struct S17 { int a = 3; int opAssign(...) { printf("S17.opAssign(%p)\n", &this); a = 4; return 5; } } void test17() { S17 s; S17 t; assert((s = t) == 5); assert(s.a == 4); } /**********************************/ struct S18 { int a = 3; int opAssign(S18 s, int x = 7) { printf("S18.opAssign(%p)\n", &this); a = 4; assert(x == 7); return s.a + 2; } } void test18() { S18 s; S18 t; assert((s = t) == 5); assert(s.a == 4); } /**********************************/ struct S19 { int a,b,c,d; this(this) { printf("this(this) %p\n", &this); } ~this() { printf("~this() %p\n", &this); } } S19 foo19() { S19 s; void bar() { s.a++; } bar(); return s; } void test19() { S19 t = foo19(); printf("-main()\n"); } /**********************************/ struct S20 { static char[] r; int a,b,c=2,d; this(this) { printf("this(this) %p\n", &this); r ~= '='; } ~this() { printf("~this() %p\n", &this); r ~= '~'; } } void foo20() { S20 s; S20[3] a; assert(S20.r == ""); a = s; assert(S20.r == "=~=~=~"); } void test20() { foo20(); assert(S20.r == "=~=~=~~~~~"); printf("-main()\n"); } /**********************************/ struct S21 { static char[] r; int a,b,c=2,d; this(this) { printf("this(this) %p\n", &this); r ~= '='; } ~this() { printf("~this() %p\n", &this); r ~= '~'; } } void foo21() { S21 s; S21[3] a = s; assert(S21.r == "==="); S21.r = null; S21[3][2] b = s; assert(S21.r == "======"); S21.r = null; } void test21() { foo21(); assert(S21.r == "~~~~~~~~~~"); printf("-main()\n"); } /**********************************/ struct S22 { static char[] r; int a,b,c=2,d; this(this) { printf("this(this) %p\n", &this); r ~= '='; } ~this() { printf("~this() %p\n", &this); r ~= '~'; } } void foo22() { S22[3] s; S22[3][2] a; assert(S22.r == ""); a = s; assert(S22.r == "===~~~===~~~"); S22.r = null; } void test22() { foo22(); assert(S22.r == "~~~~~~~~~"); printf("-main()\n"); } /************************************************/ struct S23 { int m = 4, n, o, p, q; this(int x) { printf("S23(%d)\n", x); assert(x == 3); assert(m == 4 && n == 0 && o == 0 && p == 0 && q == 0); q = 7; } } void test23() { { auto s = S23(3); printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q); assert(s.m == 4 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7); } { auto s = new S23(3); printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q); assert(s.m == 4 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7); } { S23 s; s = S23(3); printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q); assert(s.m == 4 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7); } } /************************************************/ struct S24 { int m, n, o, p, q; this(int x) { printf("S24(%d)\n", x); assert(x == 3); assert(m == 0 && n == 0 && o == 0 && p == 0 && q == 0); q = 7; } } void test24() { { auto s = S24(3); printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q); assert(s.m == 0 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7); } { auto s = new S24(3); printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q); assert(s.m == 0 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7); } { S24 s; s = S24(3); printf("s.m = %d, s.n = %d, s.q = %d\n", s.m, s.n, s.q); assert(s.m == 0 && s.n == 0 && s.o == 0 && s.p == 0 && s.q == 7); } } /**********************************/ struct S25 { this(int s) {} } void test25() { auto a = S25(); } /**********************************/ int z26; struct A26 { int id; this(int x) { id = x; printf("Created A from scratch: %d\n", x); z26++; } this(this) { printf("Copying A: %d\n", id); z26 += 10; } ~this() { printf("Destroying A: %d\n", id); z26 += 100; } } struct B26 { A26 member; this(this) { printf("Copying B: %d\n", member.id); assert(0); } } B26 foo26() { A26 a = A26(45); printf("1\n"); assert(z26 == 1); return B26(a); } void test26() { { auto b = foo26(); assert(z26 == 111); printf("2\n"); } assert(z26 == 211); } /**********************************/ int z27; struct A27 { int id; this(int x) { id = x; printf("Ctor A27: %d\n", x); z27++; } this(this) { printf("Copying A27: %d\n", id); z27 += 10; } ~this() { printf("Destroying A27: %d\n", id); z27 += 100; } } struct B27 { A27[2][3] member; } void test27() { { A27[2][3] a; assert(z27 == 0); B27 b = B27(a); assert(z27 == 60); } assert(z27 == 1260); } /**********************************/ string s28; struct A28 { this(this) { printf("A's copy\n"); s28 ~= "A"; } } struct B28 { A28 member; this(this) { printf("B's copy\n"); s28 ~= "B"; } } void test28() { B28 b1; B28 b2 = b1; assert(s28 == "AB"); } /**********************************/ string s29; template Templ29 () { this(int i) { this(0.0); s29 ~= "i"; } this(double d) { s29 ~= "d"; } } class C29 { mixin Templ29; } struct S29 { mixin Templ29; } void test29() { auto r = S29(1); assert(s29 == "di"); r = S29(2.0); assert(s29 == "did"); auto c = new C29(2); assert(s29 == "diddi"); auto c2 = new C29(2.0); assert(s29 == "diddid"); } /**********************************/ struct S30 { int x; this(T)(T args) { x = args + 1; } } void test30() { auto s = S30(3); assert(s.x == 4); } /**********************************/ struct S31 { int x; this(T...)(T args) { x = args[0] + 1; } } void test31() { auto s = S31(3); assert(s.x == 4); } /**********************************/ struct S32 { static int x; this(int i) { printf("ctor %p(%d)\n", &this, i); x += 1; } this(this) { printf("postblit %p\n", &this); x += 0x10; } ~this() { printf("dtor %p\n", &this); x += 0x100; } } S32 foo32() { printf("test1\n"); return S32(1); } S32 bar32() { printf("test1\n"); S32 f = S32(1); printf("test2\n"); return f; } void test32() { { S32 s = foo32(); } assert(S32.x == 0x101); S32.x = 0; { S32 s = bar32(); } assert(S32.x == 0x101); } /**********************************/ struct S33 { static int x; this(int i) { printf("ctor %p(%d)\n", &this, i); x += 1; } this(this) { printf("postblit %p\n", &this); x += 0x10; } ~this() { printf("dtor %p\n", &this); x += 0x100; } } struct T33 { S33 foo() { return t; } S33 t; } void test33() { { T33 t; S33 s = t.foo(); } printf("S.x = %x\n", S33.x); assert(S33.x == 0x210); } /**********************************/ struct X34 { int i; this(this) { printf("postblit %p\n", &this); ++i; } ~this() { printf("dtor %p\n", &this); } } void test34() { X34[2] xs; // xs[0][0] = X34(); printf("foreach\n"); for (int j = 0; j < xs.length; j++) { auto x = (j++,j--,xs[j]); //foreach(x; xs) { //printf("foreach x.i = %d\n", x[0].i); //assert(x[0].i == 1); printf("foreach x.i = %d\n", x.i); assert(x.i == 1); } printf("loop done\n"); } /**********************************/ struct X35 { __gshared int k; int i; this(this) { printf("postblit %p\n", &this); ++i; } ~this() { printf("dtor %p\n", &this); k++; } } void test35() { { X35[2] xs; printf("foreach\n"); foreach(ref x; xs) { printf("foreach x.i = %d\n", x.i); assert(x.i == 0); } printf("loop done\n"); } assert(X35.k == 2); } /**********************************/ struct X36 { __gshared int k; int i; this(this) { printf("postblit %p\n", &this); ++i; } ~this() { printf("dtor %p\n", &this); k++; } } void test36() { { X36[2] xs; printf("foreach\n"); foreach(x; xs) { printf("foreach x.i = %d\n", x.i); assert(x.i == 1); } printf("loop done\n"); } assert(X36.k == 4); } /**********************************/ struct X37 { __gshared int k; int i; this(this) { printf("postblit %p\n", &this); ++i; } ~this() { printf("dtor %p\n", &this); k++; } } void test37() { { X37[2][3] xs; printf("foreach\n"); foreach(ref x; xs) { printf("foreach x.i = %d\n", x[0].i); assert(x[0].i == 0); } printf("loop done\n"); } assert(X37.k == 6); } /**********************************/ struct S38 { __gshared int count; __gshared int postblit; this(int x) { printf("this(%d)\n", x); assert(this.x == 0); this.x = x; count++; } this(this) { printf("this(this) with %d\n", x); assert(x == 1 || x == 2); count++; postblit++; } ~this() { printf("~this(%d)\n", x); assert(x == 1 || x == 2); x = 0; count--; } int x; } S38 foo38() { auto s = S38(1); return s; } S38 bar38() { return S38(2); } void test38() { { auto s1 = foo38(); assert(S38.count == 1); assert(S38.postblit == 0); } assert(S38.count == 0); S38.postblit = 0; { auto s2 = bar38(); assert(S38.count == 1); assert(S38.postblit == 0); } assert(S38.count == 0); } /**********************************/ struct Foo39 { int x; this(int v){ x = v + 1; } void opAssign(int v){ x = v + 3; } } void test39() { int y = 5; Foo39 f = y; assert(f.x == 6); f = y; assert(f.x == 8); // f = Foo39(y); } /**********************************/ bool approxEqual(float a, float b) { return a < b ? b-a < .001 : a-b < .001; } struct Point { float x = 0, y = 0; const bool opEquals(const ref Point rhs) { return approxEqual(x, rhs.x) && approxEqual(y, rhs.y); } } struct Rectangle { Point leftBottom, rightTop; } void test40() { Rectangle a, b; assert(a == b); a.leftBottom.x = 1e-8; assert(a == b); a.rightTop.y = 5; assert(a != b); } /**********************************/ struct S41 { this(int) immutable { } } void test41() { auto s = new immutable S41(3); //writeln(typeid(typeof(s))); static assert(is(typeof(s) == immutable(S41)*)); auto t = immutable S41(3); //writeln(typeid(typeof(t))); static assert(is(typeof(t) == immutable(S41))); } /**********************************/ class C42 { this(int) immutable { } } void test42() { static assert(!__traits(compiles, new C42(3))); //writeln(typeid(typeof(c))); //static assert(is(typeof(c) == immutable(C42))); auto d = new immutable(C42)(3); //writeln(typeid(typeof(d))); static assert(is(typeof(d) == immutable(C42))); } /**********************************/ struct S43 { int i; int* p; // this(int i, int* t) immutable { this.i = i; p = t; } } void test43() { int i; assert(!__traits(compiles, immutable(S43)(3, &i))); immutable int j = 4; auto s = immutable(S43)(3, &j); //writeln(typeid(typeof(s))); static assert(is(typeof(s) == immutable(S43))); } /**********************************/ struct S44 { int i; immutable(int)* p; this(int i, immutable(int)* t) immutable { this.i = i; this.p = t; } } void test44() { int i; assert(!__traits(compiles, immutable(S44)(3, &i))); immutable int j = 4; auto s = immutable(S44)(3, &j); //writeln(typeid(typeof(s))); static assert(is(typeof(s) == immutable(S44))); } /**********************************/ class C45 { C45 next; this(int[] data) immutable { next = new immutable(C45)(data[1 .. $]); } } void test45() { } /**********************************/ // 3986 struct SiberianHamster { int rat = 813; this(string z) { } } void test46() { SiberianHamster basil = "cybil"; assert(basil.rat == 813); } /**********************************/ // 8741 struct Vec8741 { this(float x) { m[0] = x; m[1] = 58; } float[2] m; static Vec8741 zzz = Vec8741(7); } void test8741() { assert(Vec8741.zzz.m[0] == 7); assert(Vec8741.zzz.m[1] == 58); } /**********************************/ struct Segfault3984 { int a; this(int x){ a = x; } } void test47() { //static assert(Segfault3984(3).a == 3); } /**********************************/ void test48() { struct B { void foo() { } } B x = B.init; } /**********************************/ struct Foo49 { int z; this(int a){z=a;} } void bar49(Foo49 a = Foo49(1)) { assert(a.z == 1); } void test49() { bar49(); bar49(); } /**********************************/ struct aStruct{ int m_Int; this(int a){ m_Int = a; } } class aClass{ void aFunc(aStruct a = aStruct(44)) { assert(a.m_Int == 44); } } void test50() { aClass a = new aClass(); a.aFunc(); a.aFunc(); } /**********************************/ int A51_a; struct A51 { ~this() { ++A51_a; } } void test51() { A51_a = 0; { while(0) A51 a; } assert(A51_a == 0); A51_a = 0; { if(0) A51 a; } assert(A51_a == 0); A51_a = 0; { if(1){} else A51 a; } assert(A51_a == 0); A51_a = 0; { for(;0;) A51 a; } assert(A51_a == 0); A51_a = 0; { if (1) { A51 a; } } assert(A51_a == 1); A51_a = 0; { if (1) A51 a; } assert(A51_a == 1); A51_a = 0; { if(0) {} else A51 a; } assert(A51_a == 1); A51_a = 0; { if (0) for(A51 a;;) {} } assert(A51_a == 0); A51_a = 0; { if (0) for(;;) A51 a; } assert(A51_a == 0); A51_a = 0; { do A51 a; while(0); } assert(A51_a == 1); A51_a = 0; { if (0) while(1) A51 a; } assert(A51_a == 0); A51_a = 0; { try A51 a; catch(Error e) {} } assert(A51_a == 1); A51_a = 0; { if (0) final switch(1) A51 a; } assert(A51_a == 0); // should fail to build A51_a = 0; { if (0) switch(1) { A51 a; default: } } assert(A51_a == 0); A51_a = 0; { if (0) switch(1) { default: A51 a; } } assert(A51_a == 0); A51_a = 0; { if (1) switch(1) { A51 a; default: } } assert(A51_a == 1); // should be 0, right? A51_a = 0; { if (1) switch(1) { default: A51 a; } } assert(A51_a == 1); // A51_a = 0; { final switch(0) A51 a; } assert(A51_a == 0); A51_a = 0; { A51 a; with(a) A51 b; } assert(A51_a == 2); } /**********************************/ string s52; struct A52 { int m; this(this) { printf("this(this) %p\n", &this); s52 ~= 'a'; } ~this() { printf("~this() %p\n", &this); s52 ~= 'b'; } A52 copy() { s52 ~= 'c'; A52 another = this; return another; } } void test52() { { A52 a; A52 b = a.copy(); printf("a: %p, b: %p\n", &a, &b); } printf("s = '%.*s'\n", s52.length, s52.ptr); assert(s52 == "cabb"); } /**********************************/ // 4339 struct A53 { invariant() { } ~this() { } void opAssign(A53 a) {} int blah(A53 a) { return 0; } } /**********************************/ struct S54 { int x = 1; int bar() { return x; } this(int i) { printf("ctor %p(%d)\n", &this, i); t ~= "a"; } this(this) { printf("postblit %p\n", &this); t ~= "b"; } ~this() { printf("dtor %p\n", &this); t ~= "c"; } static string t; } void bar54(S54 s) { } S54 abc54() { return S54(1); } void test54() { { S54.t = null; S54 s = S54(1); } assert(S54.t == "ac"); { S54.t = null; S54 s = S54(); } assert(S54.t == "c"); { S54.t = null; int b = 1 && (bar54(S54(1)), 1); } assert(S54.t == "ac"); { S54.t = null; int b = 0 && (bar54(S54(1)), 1); } assert(S54.t == ""); { S54.t = null; int b = 0 || (bar54(S54(1)), 1); } assert(S54.t == "ac"); { S54.t = null; int b = 1 || (bar54(S54(1)), 1); } assert(S54.t == ""); { S54.t = null; { const S54 s = S54(1); } assert(S54.t == "ac"); } { S54.t = null; abc54(); assert(S54.t == "ac"); } { S54.t = null; abc54().x += 1; assert(S54.t == "ac"); } } /**********************************/ void test55() { S55 s; auto t = s.copy(); assert(t.count == 1); // (5) } struct S55 { int count; this(this) { ++count; } S55 copy() { return this; } } /**********************************/ struct S56 { int x = 1; int bar() { return x; } this(int i) { printf("ctor %p(%d)\n", &this, i); t ~= "a"; } this(this) { printf("postblit %p\n", &this); t ~= "b"; } ~this() { printf("dtor %p\n", &this); t ~= "c"; } static string t; } int foo56() { throw new Throwable("hello"); return 5; } void test56() { int i; int j; try { j |= 1; i = S56(1).x + foo56() + 1; j |= 2; } catch (Throwable o) { printf("caught\n"); j |= 4; } printf("i = %d, j = %d\n", i, j); assert(i == 0); assert(j == 5); } /**********************************/ // 5859 int dtor_cnt = 0; struct S57 { int v; this(int n){ v = n; printf("S.ctor v=%d\n", v); } ~this(){ ++dtor_cnt; printf("S.dtor v=%d\n", v); } bool opCast(T:bool)(){ printf("S.cast v=%d\n", v); return true; } } S57 f(int n){ return S57(n); } void test57() { printf("----\n"); dtor_cnt = 0; if (auto s = S57(10)) { printf("ifbody\n"); } else assert(0); assert(dtor_cnt == 1); printf("----\n"); //+ dtor_cnt = 0; if (auto s = (S57(1), S57(2), S57(10))) { assert(dtor_cnt == 2); printf("ifbody\n"); } else assert(0); assert(dtor_cnt == 3); // +/ printf("----\n"); dtor_cnt = 0; try{ if (auto s = S57(10)) { printf("ifbody\n"); throw new Exception("test"); } else assert(0); }catch (Exception e){} assert(dtor_cnt == 1); printf("----\n"); dtor_cnt = 0; if (auto s = f(10)) { printf("ifbody\n"); } else assert(0); assert(dtor_cnt == 1); printf("----\n"); //+ dtor_cnt = 0; if (auto s = (f(1), f(2), f(10))) { assert(dtor_cnt == 2); printf("ifbody\n"); } else assert(0); assert(dtor_cnt == 3); // +/ printf("----\n"); dtor_cnt = 0; try{ if (auto s = f(10)) { printf("ifbody\n"); throw new Exception("test"); } else assert(0); }catch (Exception e){} assert(dtor_cnt == 1); printf("----\n"); dtor_cnt = 0; if (S57(10)) { assert(dtor_cnt == 1); printf("ifbody\n"); } else assert(0); printf("----\n"); dtor_cnt = 0; if ((S57(1), S57(2), S57(10))) { assert(dtor_cnt == 3); printf("ifbody\n"); } else assert(0); printf("----\n"); dtor_cnt = 0; try{ if (auto s = S57(10)) { printf("ifbody\n"); throw new Exception("test"); } else assert(0); }catch (Exception e){} assert(dtor_cnt == 1); printf("----\n"); dtor_cnt = 0; if (f(10)) { assert(dtor_cnt == 1); printf("ifbody\n"); } else assert(0); printf("----\n"); dtor_cnt = 0; if ((f(1), f(2), f(10))) { assert(dtor_cnt == 3); printf("ifbody\n"); } else assert(0); printf("----\n"); dtor_cnt = 0; try{ if (auto s = f(10)) { printf("ifbody\n"); throw new Exception("test"); } else assert(0); }catch (Exception e){} assert(dtor_cnt == 1); } /**********************************/ // 5574 struct foo5574a { ~this() {} } class bar5574a { foo5574a[1] frop; } struct foo5574b { this(this){} } struct bar5574b { foo5574b[1] frop; } /**********************************/ // 5777 int sdtor58 = 0; S58* ps58; struct S58 { @disable this(this); ~this(){ ++sdtor58; } } S58 makeS58() { S58 s; ps58 = &s; return s; } void test58() { auto s1 = makeS58(); assert(ps58 == &s1); assert(sdtor58 == 0); } /**********************************/ // 6308 struct C59 { void oops() { throw new Throwable("Oops!"); } ~this() { } } void foo59() { C59().oops(); // auto c = C(); c.oops(); } void test59() { int i = 0; try foo59(); catch (Throwable) { i = 1; } assert(i == 1); } /**********************************/ // 5737 void test5737() { static struct S { static int destroyed; static int copied; this(this) { copied++; } ~this() { destroyed++; } } static S s; ref S foo() { return s; } { auto s2 = foo(); } assert(S.copied == 1); // fail, s2 was not copied; assert(S.destroyed == 1); // ok, s2 was destroyed } /**********************************/ // 6119 void test6119() { int postblit = 0; int dtor = 0; struct Test { this(this) { ++postblit; } ~this() { ++dtor; } } void takesVal(Test x) {} ref Test returnsRef(ref Test x) { return x; } void f(ref Test x) { takesVal( x ); } Test x; postblit = dtor = 0; takesVal(returnsRef(x)); assert(postblit == 1); assert(dtor == 1); postblit = dtor = 0; f(x); assert(postblit == 1); assert(dtor == 1); } /**********************************/ // 6364 struct Foo6364 { int state = 1; ~this() { state = 0; } } void testfoo6364() { static Foo6364 foo; printf("%d\n", foo.state); assert(foo.state == 1); } void test6364() { testfoo6364(); testfoo6364(); } /**********************************/ // 6499 struct S6499 { string m = ""; this(string s) { m = s; printf("Constructor - %.*s\n", m.length, m.ptr); if (m == "foo") { ++sdtor; assert(sdtor == 1); } if (m == "bar") { ++sdtor; assert(sdtor == 2); } } this(this) { printf("Postblit - %.*s\n", m.length, m.ptr); assert(0); } ~this() { printf("Destructor - %.*s\n", m.length, m.ptr); if (m == "bar") { assert(sdtor == 2); --sdtor; } if (m == "foo") { assert(sdtor == 1); --sdtor; } } S6499 bar() { return S6499("bar"); } S6499 baz()() { return S6499("baz"); } } void test6499() { S6499 foo() { return S6499("foo"); } { sdtor = 0; scope(exit) assert(sdtor == 0); foo().bar(); } { sdtor = 0; scope(exit) assert(sdtor == 0); foo().baz(); } } /**********************************/ template isImplicitlyConvertible(From, To) { enum bool isImplicitlyConvertible = is(typeof({ void fun(ref From v) { void gun(To) {} gun(v); } }())); } void test60() { static struct X1 { void* ptr; this(this){} } static struct S1 { X1 x; } static struct X2 { int ptr; this(this){} } static struct S2 { X2 x; } { S1 ms; S1 ms2 = ms; // mutable to mutable const(S1) cs2 = ms; // mutable to const // NG -> OK } { const(S1) cs; static assert(!__traits(compiles,{ // NG -> OK S1 ms2 = cs; // field has reference, then const to mutable is invalid })); const(S1) cs2 = cs; // const to const // NG -> OK } static assert( isImplicitlyConvertible!( S1 , S1 ) ); static assert( isImplicitlyConvertible!( S1 , const(S1)) ); // NG -> OK static assert(!isImplicitlyConvertible!(const(S1), S1 ) ); static assert( isImplicitlyConvertible!(const(S1), const(S1)) ); // NG -> OK { S2 ms; S2 ms2 = ms; // mutable to mutable const(S2) cs2 = ms; // mutable to const // NG -> OK } { const(S2) cs; S2 ms2 = cs; // all fields are value, then const to mutable is OK const(S2) cs2 = cs; // const to const // NG -> OK } static assert( isImplicitlyConvertible!( S2 , S2 ) ); static assert( isImplicitlyConvertible!( S2 , const(S2)) ); // NG -> OK static assert( isImplicitlyConvertible!(const(S2), S2 ) ); static assert( isImplicitlyConvertible!(const(S2), const(S2)) ); // NG -> OK } /**********************************/ // 4316 struct A4316 { this(this) @safe { } } @safe void test4316() { A4316 a; auto b = a; // Error: safe function 'main' cannot call system function'__cpctor' } /**********************************/ struct F6177 { ~this() {} } struct G6177 { this(F6177[] p...) {} } void test6177() { F6177 c; auto g = G6177(c); } /**********************************/ // 6470 struct S6470 { static int spblit; this(this){ ++spblit; } } void test6470() { S6470[] a1; S6470[] a2; a1.length = 3; a2.length = 3; a1[] = a2[]; assert(S6470.spblit == 3); S6470 s; S6470[] a3; a3.length = 3; a3 = [s, s, s]; assert(S6470.spblit == 6); void func(S6470[] a){} func([s, s, s]); assert(S6470.spblit == 9); } /**********************************/ // 6636 struct S6636 { ~this() { ++sdtor; } } void func6636(S6636[3] sa) {} void test6636() { sdtor = 0; S6636[3] sa; func6636(sa); assert(sdtor == 3); } /**********************************/ // 6637 struct S6637 { static int spblit; this(this){ ++spblit; } } void test6637() { void func(S6637[3] sa){} S6637[3] sa; func(sa); assert(S6637.spblit == 3); } /**********************************/ // 7353 struct S7353 { static uint ci = 0; uint i; this(int x) { i = ci++; /*writeln("new: ", i);*/ } this(this) { i = ci++; /*writeln("copy ", i);*/ } ~this() { /*writeln("del ", i);*/ } S7353 save1() // produces 2 copies in total { S7353 s = this; return s; } auto save2() // produces 3 copies in total { S7353 s = this; return s; pragma(msg, typeof(return)); } } void test7353() { { auto s = S7353(1), t = S7353(1); t = s.save1(); assert(S7353.ci == 3); } S7353.ci = 0; //writeln("-"); { auto s = S7353(1), t = S7353(1); t = s.save2(); assert(S7353.ci == 3); } } /**********************************/ // 8036 struct S8036a { ~this() {} } struct S8036b // or class { S8036a[0] s; } /**********************************/ struct S61 { this(long length) { this.length = length; } long length; } const(S61) copy(const S61 s) { return s; } void test61() { S61 t = S61(42); const S61 u = t; assert(t == u); assert(copy(t) == u); assert(t == copy(u)); } /**********************************/ // 7506 void test7506() { static struct S { static uint ci = 0; static uint di = 0; uint i; this(int x) { i = ci++; /*writeln("new: ", i);*/ } this(this) { i = ci++; /*writeln("copy ", i);*/ } ~this() { ++di; /*writeln("del: ", i);*/ } S save3() { return this; } } { auto s = S(1), t = S(1); assert(S.ci == 2); t = s.save3(); assert(S.ci == 3); // line 23 } assert(S.di == 3); } /**********************************/ // 7516 struct S7516 { int val; this(int n) { val = n; } this(this) { val *= 3; } } // CondExp on return statement void test7516a() { alias S = S7516; S s1 = S(1); S s2 = S(2); S foo(bool f) { return f ? s1 : s2; } S hoo(bool f) { return f ? S(1) : S(2); } S bar(bool f) { return f ? s1 : S(2); } S baz(bool f) { return f ? S(1) : s2; } auto r1 = foo(true); assert(r1.val == 3); auto r2 = foo(false); assert(r2.val == 6); auto r3 = hoo(true); assert(r3.val == 1); auto r4 = hoo(false); assert(r4.val == 2); auto r5 = bar(true); assert(r5.val == 3); auto r6 = bar(false); assert(r6.val == 2); auto r7 = baz(true); assert(r7.val == 1); auto r8 = baz(false); assert(r8.val == 6); } // CondExp on function argument void test7516b() { alias S = S7516; S s1 = S(1); S s2 = S(2); S func(S s) { return s; } S foo(bool f) { return func(f ? s1 : s2 ); } S hoo(bool f) { return func(f ? S(1) : S(2)); } S bar(bool f) { return func(f ? s1 : S(2)); } S baz(bool f) { return func(f ? S(1) : s2 ); } auto r1 = foo(true); assert(r1.val == 3 * 3); auto r2 = foo(false); assert(r2.val == 6 * 3); auto r3 = hoo(true); assert(r3.val == 1 * 3); auto r4 = hoo(false); assert(r4.val == 2 * 3); auto r5 = bar(true); assert(r5.val == 3 * 3); auto r6 = bar(false); assert(r6.val == 2 * 3); auto r7 = baz(true); assert(r7.val == 1 * 3); auto r8 = baz(false); assert(r8.val == 6 * 3); } // CondExp on array literal void test7516c() { alias S = S7516; S s1 = S(1); S s2 = S(2); S[] foo(bool f) { return [f ? s1 : s2 ]; } S[] hoo(bool f) { return [f ? S(1) : S(2)]; } S[] bar(bool f) { return [f ? s1 : S(2)]; } S[] baz(bool f) { return [f ? S(1) : s2 ]; } auto r1 = foo(true); assert(r1[0].val == 3); auto r2 = foo(false); assert(r2[0].val == 6); auto r3 = hoo(true); assert(r3[0].val == 1); auto r4 = hoo(false); assert(r4[0].val == 2); auto r5 = bar(true); assert(r5[0].val == 3); auto r6 = bar(false); assert(r6[0].val == 2); auto r7 = baz(true); assert(r7[0].val == 1); auto r8 = baz(false); assert(r8[0].val == 6); } // CondExp on rhs of cat assign void test7516d() { alias S = S7516; S s1 = S(1); S s2 = S(2); S[] foo(bool f) { S[] a; a ~= f ? s1 : s2 ; return a; } S[] hoo(bool f) { S[] a; a ~= f ? S(1) : S(2); return a; } S[] bar(bool f) { S[] a; a ~= f ? s1 : S(2); return a; } S[] baz(bool f) { S[] a; a ~= f ? S(1) : s2 ; return a; } auto r1 = foo(true); assert(r1[0].val == 3); auto r2 = foo(false); assert(r2[0].val == 6); auto r3 = hoo(true); assert(r3[0].val == 1); auto r4 = hoo(false); assert(r4[0].val == 2); auto r5 = bar(true); assert(r5[0].val == 3); auto r6 = bar(false); assert(r6[0].val == 2); auto r7 = baz(true); assert(r7[0].val == 1); auto r8 = baz(false); assert(r8[0].val == 6); } // CondExp on struct literal element void test7516e() { alias S = S7516; S s1 = S(1); S s2 = S(2); struct X { S s; } X foo(bool f) { return X(f ? s1 : s2 ); } X hoo(bool f) { return X(f ? S(1) : S(2)); } X bar(bool f) { return X(f ? s1 : S(2)); } X baz(bool f) { return X(f ? S(1) : s2 ); } auto r1 = foo(true); assert(r1.s.val == 3); auto r2 = foo(false); assert(r2.s.val == 6); auto r3 = hoo(true); assert(r3.s.val == 1); auto r4 = hoo(false); assert(r4.s.val == 2); auto r5 = bar(true); assert(r5.s.val == 3); auto r6 = bar(false); assert(r6.s.val == 2); auto r7 = baz(true); assert(r7.s.val == 1); auto r8 = baz(false); assert(r8.s.val == 6); } /**********************************/ // 7530 void test7530() { static struct S { int val; this(int n) { val = n; } this(this) { val *= 3; } } S[] sa = new S[](1); sa[0].val = 1; S foo() { return sa[0]; } auto s = foo(); assert(s.val == 3); } /**********************************/ struct S62 { this(int length) { _length = length; } int opBinary(string op)(in S62 rhs) const if(op == "-") { return this.length - rhs.length; } @property int length() const { return _length; } invariant() { assert(_length == 1); } int _length = 1; } void test62() { immutable result = S62.init - S62.init; } /**********************************/ // 7579 void test7579a() { static struct S { // postblit can also have no body because isn't called @disable this(this) { assert(0); } } @property S fs() { return S(); } @property S[3] fsa() { return [S(), S(), S()]; } S s0; S s1 = S(); static assert(!__traits(compiles, { S s2 = s1; })); // OK S s2 = fs; static assert(!__traits(compiles, { s2 = s1; })); // OK // static array S[3] sa0; S[3] sa1 = [S(), S(), S()]; static assert(!__traits(compiles, { S[3] sa2 = sa1; })); // fixed S[3] sa2 = fsa; static assert(!__traits(compiles, { sa2 = sa1; })); // fixed sa2 = [S(), S(), S()]; sa2 = fsa; S[] da1 = new S[3]; S[] da2 = new S[3]; static assert(!__traits(compiles, { da2[] = da1[]; })); // fixed // concatenation and appending static assert(!__traits(compiles, { da1 ~= s1; })); // fixed static assert(!__traits(compiles, { da1 ~= S(); })); static assert(!__traits(compiles, { da1 ~= fsa; })); static assert(!__traits(compiles, { da1 ~= fsa[]; })); static assert(!__traits(compiles, { da1 = da1 ~ s1; })); // fixed static assert(!__traits(compiles, { da1 = s1 ~ da1; })); // fixed static assert(!__traits(compiles, { da1 = da1 ~ S(); })); static assert(!__traits(compiles, { da1 = da1 ~ fsa; })); static assert(!__traits(compiles, { da1 = da1 ~ da; })); } void test7579b() { static struct S { // postblit asserts in runtime this(this) { assert(0); } } @property S fs() { return S(); } @property S[3] fsa() { return [S(), S(), S()]; } S s0; S s1 = S(); S s2 = fs; // static array S[3] sa0; S[3] sa1 = [S(), S(), S()]; S[3] sa2 = fsa; sa2 = [S(), S(), S()]; sa2 = fsa; S[] da1 = new S[3]; S[] da2 = new S[3]; // concatenation and appending always run postblits } /**********************************/ // 8335 struct S8335 { static int postblit; int i; this(this) { ++postblit; } } void f8335(ref S8335[3] arr) { arr[0].i = 7; } void g8335(lazy S8335[3] arr) { assert(S8335.postblit == 0); auto x = arr; assert(S8335.postblit == 3); } void h8335(lazy S8335 s) { assert(S8335.postblit == 0); auto x = s; assert(S8335.postblit == 1); } void test8335() { S8335[3] arr; f8335(arr); assert(S8335.postblit == 0); assert(arr[0].i == 7); g8335(arr); assert(S8335.postblit == 3); S8335.postblit = 0; S8335 s; h8335(s); assert(S8335.postblit == 1); } /**********************************/ // 8356 void test8356() { static struct S { @disable this(this) { assert(0); } } S s; S[3] sa; static assert(!__traits(compiles, { S fs() { return s; } })); static assert(!__traits(compiles, { S[3] fsa() { return sa; } })); } /**********************************/ // 8475 T func8475(T)(T x) @safe pure { return T(); } template X8475(bool something) { struct XY { this(this) @safe pure {} void func(XY x) @safe pure { XY y = x; //Error: see below func8475(x); func8475(y); } } } alias X8475!(true).XY Xtrue; /**********************************/ struct Foo9320 { real x; this(real x) { this.x = x; } Foo9320 opBinary(string op)(Foo9320 other) { return Foo9320(mixin("x" ~ op ~ "other.x")); } } Foo9320 test9320(Foo9320 a, Foo9320 b, Foo9320 c) { return (a + b) / (a * b) - c; } /**********************************/ // 9386 struct Test9386 { string name; static char[25] op; static size_t i; static @property string sop() { return cast(string)op[0..i]; } this(string name) { this.name = name; printf("Created %.*s...\n", name.length, name.ptr); assert(i + 1 < op.length); op[i++] = 'a'; } this(this) { printf("Copied %.*s...\n", name.length, name.ptr); assert(i + 1 < op.length); op[i++] = 'b'; } ~this() { printf("Deleted %.*s\n", name.length, name.ptr); assert(i + 1 < op.length); op[i++] = 'c'; } const int opCmp(ref const Test9386 t) { return op[0] - t.op[0]; } } void test9386() { { Test9386.op[] = 0; Test9386.i = 0; Test9386[] tests = [ Test9386("one"), Test9386("two"), Test9386("three"), Test9386("four") ]; assert(Test9386.sop == "aaaa"); Test9386.op[] = 0; Test9386.i = 0; printf("----\n"); foreach (Test9386 test; tests) { printf("\tForeach %.*s\n", test.name.length, test.name.ptr); Test9386.op[Test9386.i++] = 'x'; } assert(Test9386.sop == "bxcbxcbxcbxc"); Test9386.op[] = 0; Test9386.i = 0; printf("----\n"); foreach (ref Test9386 test; tests) { printf("\tForeach %.*s\n", test.name.length, test.name.ptr); Test9386.op[Test9386.i++] = 'x'; } assert(Test9386.sop == "xxxx"); } printf("====\n"); { Test9386.op[] = 0; Test9386.i = 0; Test9386[Test9386] tests = [ Test9386("1") : Test9386("one"), Test9386("2") : Test9386("two"), Test9386("3") : Test9386("three"), Test9386("4") : Test9386("four") ]; Test9386.op[] = 0; Test9386.i = 0; printf("----\n"); foreach (Test9386 k, Test9386 v; tests) { printf("\tForeach %.*s : %.*s\n", k.name.length, k.name.ptr, v.name.length, v.name.ptr); Test9386.op[Test9386.i++] = 'x'; } assert(Test9386.sop == "bbxccbbxccbbxccbbxcc"); Test9386.op[] = 0; Test9386.i = 0; printf("----\n"); foreach (Test9386 k, ref Test9386 v; tests) { printf("\tForeach %.*s : %.*s\n", k.name.length, k.name.ptr, v.name.length, v.name.ptr); Test9386.op[Test9386.i++] = 'x'; } assert(Test9386.sop == "bxcbxcbxcbxc"); Test9386.op[] = 0; Test9386.i = 0; } } /**********************************/ // 9441 auto x9441 = X9441(0.123); struct X9441 { int a; this(double x) { a = cast(int)(x * 100); } } void test9441() { assert(x9441.a == 12); } /**********************************/ struct Payload { size_t _capacity; //Comment me int[] _pay; //Comment me size_t insertBack(Data d) { immutable newLen = _pay.length + 3; _pay.length = newLen; _pay = _pay[0 .. newLen]; //Comment me return 3; } } struct Impl { Payload _payload; size_t _count; } struct Data { Impl* _store; this(int i) { _store = new Impl; _store._payload = Payload.init; } ~this() { printf("%d\n", _store._count); --_store._count; } } void test9720() { auto a = Data(1); auto b = Data(1); a._store._payload.insertBack(b); //Fails } /**********************************/ // 9899 struct S9899 { @safe pure nothrow ~this() {} } struct MemberS9899 { S9899 s; } void test9899() @safe pure nothrow { MemberS9899 s; // 11 } /**********************************/ // 9907 void test9907() { static struct SX(bool hasCtor, bool hasDtor) { int i; static size_t assign; static size_t dtor; static if (hasCtor) { this(int i) { this.i = i; } } void opAssign(SX rhs) { printf("%08X(%d) from Rvalue %08X(%d)\n", &this.i, this.i, &rhs.i, rhs.i); ++assign; } void opAssign(ref SX rhs) { printf("%08X(%d) from Lvalue %08X(%d)\n", &this.i, this.i, &rhs.i, rhs.i); assert(0); } static if (hasDtor) { ~this() { printf("destroying %08X(%d)\n", &this.i, this.i); ++dtor; } } } S test(S)(int i) { return S(i); } foreach (hasCtor; TypeTuple!(false, true)) foreach (hasDtor; TypeTuple!(false, true)) { alias S = SX!(hasCtor, hasDtor); alias test!S foo; printf("----\n"); auto s = S(1); // Assignment from two kinds of rvalues assert(S.assign == 0); s = foo(2); static if (hasDtor) assert(S.dtor == 1); assert(S.assign == 1); s = S(3); assert(S.assign == 2); static if (hasDtor) assert(S.dtor == 2); } printf("----\n"); } /**********************************/ // 9985 struct S9985 { ubyte* b; ubyte buf[128]; this(this) { assert(0); } static void* ptr; } auto ref makeS9985() { S9985 s; s.b = s.buf.ptr; S9985.ptr = &s; return s; } void test9985() { S9985 s = makeS9985(); assert(S9985.ptr == &s); // NRVO static const int n = 1; static auto ref retN() { return n; } auto p = &(retN()); // OK assert(p == &n); alias pure nothrow @nogc @safe ref const(int) F1(); static assert(is(typeof(retN) == F1)); enum const(int) x = 1; static auto ref retX() { return x; } static assert(!__traits(compiles, { auto q = &(retX()); })); alias pure nothrow @nogc @safe const(int) F2(); static assert(is(typeof(retX) == F2)); } /**********************************/ // 9994 void test9994() { static struct S { static int dtor; ~this() { ++dtor; } } S s; static assert( __traits(compiles, s.opAssign(s))); static assert(!__traits(compiles, s.__postblit())); assert(S.dtor == 0); s = s; assert(S.dtor == 1); } /**********************************/ // 10053 struct S10053A { pure ~this() {} } struct S10053B { S10053A sa; ~this() {} } /**********************************/ // 10055 void test10055a() { static struct SX { pure nothrow @safe ~this() {} } static struct SY { pure nothrow @safe ~this() {} } static struct SZ { @disable ~this() {} } // function to check merge result of the dtor attributes static void check(S)() { S s; } static struct S1 { } static struct S2 { ~this() {} } static struct SA { SX sx; SY sy; } static struct SB { SX sx; SY sy; pure nothrow @safe ~this() {} } static struct SC { SX sx; SY sy; nothrow @safe ~this() {} } static struct SD { SX sx; SY sy; pure @safe ~this() {} } static struct SE { SX sx; SY sy; pure nothrow ~this() {} } static struct SF { SX sx; SY sy; @safe ~this() {} } static struct SG { SX sx; SY sy; nothrow ~this() {} } static struct SH { SX sx; SY sy; pure ~this() {} } static struct SI { SX sx; SY sy; ~this() {} } static assert(is( typeof(&check!S1) == void function() pure nothrow @nogc @safe )); static assert(is( typeof(&check!S2) == void function() )); static assert(is( typeof(&check!SA) == void function() pure nothrow @safe )); static assert(is( typeof(&check!SB) == void function() pure nothrow @safe )); static assert(is( typeof(&check!SC) == void function() nothrow @safe )); static assert(is( typeof(&check!SD) == void function() pure @safe )); static assert(is( typeof(&check!SE) == void function() pure nothrow )); static assert(is( typeof(&check!SF) == void function() @safe )); static assert(is( typeof(&check!SG) == void function() nothrow )); static assert(is( typeof(&check!SH) == void function() pure )); static assert(is( typeof(&check!SI) == void function() )); static struct S1x { SZ sz; } static struct S2x { ~this() {} SZ sz; } static struct SAx { SX sx; SY sy; SZ sz; } static struct SBx { SX sx; SY sy; pure nothrow @safe ~this() {} SZ sz; } static struct SCx { SX sx; SY sy; nothrow @safe ~this() {} SZ sz; } static struct SDx { SX sx; SY sy; pure @safe ~this() {} SZ sz; } static struct SEx { SX sx; SY sy; pure nothrow ~this() {} SZ sz; } static struct SFx { SX sx; SY sy; @safe ~this() {} SZ sz; } static struct SGx { SX sx; SY sy; nothrow ~this() {} SZ sz; } static struct SHx { SX sx; SY sy; pure ~this() {} SZ sz; } static struct SIx { SX sx; SY sy; ~this() {} SZ sz; } foreach (Sx; TypeTuple!(S1x, S2x, SAx, SBx, SCx, SDx, SEx, SFx, SGx, SHx, SIx)) { static assert(!__traits(compiles, &check!Sx)); } } void test10055b() { static struct SX { pure nothrow @safe this(this) {} } static struct SY { pure nothrow @safe this(this) {} } static struct SZ { @disable this(this) {} } // function to check merge result of the postblit attributes static void check(S)() { S s; S s2 = s; } static struct S1 { } static struct S2 { this(this) {} } static struct SA { SX sx; SY sy; } static struct SB { SX sx; SY sy; pure nothrow @safe this(this) {} } static struct SC { SX sx; SY sy; nothrow @safe this(this) {} } static struct SD { SX sx; SY sy; pure @safe this(this) {} } static struct SE { SX sx; SY sy; pure nothrow this(this) {} } static struct SF { SX sx; SY sy; @safe this(this) {} } static struct SG { SX sx; SY sy; nothrow this(this) {} } static struct SH { SX sx; SY sy; pure this(this) {} } static struct SI { SX sx; SY sy; this(this) {} } static assert(is( typeof(&check!S1) == void function() pure nothrow @nogc @safe )); static assert(is( typeof(&check!S2) == void function() )); static assert(is( typeof(&check!SA) == void function() pure nothrow @safe )); static assert(is( typeof(&check!SB) == void function() pure nothrow @safe )); static assert(is( typeof(&check!SC) == void function() nothrow @safe )); static assert(is( typeof(&check!SD) == void function() pure @safe )); static assert(is( typeof(&check!SE) == void function() pure nothrow )); static assert(is( typeof(&check!SF) == void function() @safe )); static assert(is( typeof(&check!SG) == void function() nothrow )); static assert(is( typeof(&check!SH) == void function() pure )); static assert(is( typeof(&check!SI) == void function() )); static struct S1x { SZ sz; } static struct S2x { this(this) {} SZ sz; } static struct SAx { SX sx; SY sy; SZ sz; } static struct SBx { SX sx; SY sy; pure nothrow @safe this(this) {} SZ sz; } static struct SCx { SX sx; SY sy; nothrow @safe this(this) {} SZ sz; } static struct SDx { SX sx; SY sy; pure @safe this(this) {} SZ sz; } static struct SEx { SX sx; SY sy; pure nothrow this(this) {} SZ sz; } static struct SFx { SX sx; SY sy; @safe this(this) {} SZ sz; } static struct SGx { SX sx; SY sy; nothrow this(this) {} SZ sz; } static struct SHx { SX sx; SY sy; pure this(this) {} SZ sz; } static struct SIx { SX sx; SY sy; this(this) {} SZ sz; } foreach (Sx; TypeTuple!(S1x, S2x, SAx, SBx, SCx, SDx, SEx, SFx, SGx, SHx, SIx)) { static assert(!__traits(compiles, &check!Sx)); } } /**********************************/ // 10160 struct S10160 { this(this) {} } struct X10160a { S10160 s; const int x; } struct X10160b { S10160 s; enum int x = 1; } void test10160() { X10160a xa; X10160b xb; } /**********************************/ // 10094 void test10094() { static void* p; const string[4] i2s = () { string[4] tmp; p = &tmp[0]; for (int i = 0; i < 4; ++i) { char[1] buf = [cast(char)('0' + i)]; string str = buf.idup; tmp[i] = str; } return tmp; // NRVO should work }(); assert(p == cast(void*)&i2s[0]); assert(i2s == ["0", "1", "2", "3"]); } /**********************************/ // 10079 // dtor || postblit struct S10079a { this(this) pure nothrow @safe {} } struct S10079b { ~this() pure nothrow @safe {} } struct S10079c { this(this) pure nothrow @safe {} ~this() pure nothrow @safe {} } struct S10079d { this(this) {} } struct S10079e { this(this) {} ~this() pure nothrow @safe {} } // memberwise struct S10079f { S10079a a; S10079b b; S10079c c; S10079d d; S10079e e; } void check10079(S)(ref S s) pure nothrow @safe { s = S(); } // Assignment is pure, nothrow, and @safe in all cases. static assert(__traits(compiles, &check10079!S10079a)); static assert(__traits(compiles, &check10079!S10079b)); static assert(__traits(compiles, &check10079!S10079c)); static assert(__traits(compiles, &check10079!S10079d)); static assert(__traits(compiles, &check10079!S10079e)); static assert(__traits(compiles, &check10079!S10079f)); /**********************************/ // 10244 void test10244() { static struct Foo { string _str; long _num; template DeclareConstructor(string fieldName) { enum code = `this(typeof(_` ~ fieldName ~ `) value)` ~ `{ this._` ~ fieldName ~ ` = value; }`; mixin(code); } mixin DeclareConstructor!"str"; mixin DeclareConstructor!"num"; } Foo value1 = Foo("D"); Foo value2 = Foo(128); assert(value1._str == "D"); assert(value2._num == 128); } /**********************************/ // 10694 struct Foo10694 { ~this() { } } void test10694() pure { static Foo10694 i1; __gshared Foo10694 i2; void foo() pure { static Foo10694 j1; __gshared Foo10694 j2; } } /**********************************/ // 10787 int global10787; static ~this() nothrow pure @safe { int* p; static assert(!__traits(compiles, ++p)); static assert(!__traits(compiles, ++global10787)); } shared static ~this() nothrow pure @safe { int* p; static assert(!__traits(compiles, ++p)); static assert(!__traits(compiles, ++global10787)); } /**********************************/ // 10789 struct S10789 { static int count; int value; this(int) { value = ++count; } ~this() { --count; } this(this) { value = ++count; assert(value == 3); } } S10789 fun10789a(bool isCondExp)(bool cond) { S10789 s1 = S10789(42), s2 = S10789(24); assert(S10789.count == 2); static if (isCondExp) { return cond ? s1 : s2; } else { if (cond) return s1; else return s2; } } auto fun10789b(bool isCondExp)(bool cond) { S10789 s1 = S10789(42), s2 = S10789(24); assert(S10789.count == 2); static if (isCondExp) { return cond ? s1 : s2; } else { if (cond) return s1; else return s2; } } void test10789() { foreach (fun; TypeTuple!(fun10789a, fun10789b)) foreach (isCondExp; TypeTuple!(false, true)) { { S10789 s = fun!isCondExp(true); assert(S10789.count == 1); assert(s.value == 3); } assert(S10789.count == 0); { S10789 s = fun!isCondExp(false); assert(S10789.count == 1); assert(s.value == 3); } assert(S10789.count == 0); } } /**********************************/ // 10972 int test10972() { string result; struct A { this(this) { result ~= "pA"; version(none) printf("copied A\n"); } ~this() { result ~= "dA"; version(none) printf("destroy A\n"); } } struct B { this(this) { result ~= "(pB)"; version(none) printf("B says what?\n"); throw new Exception("BOOM!"); } ~this() { result ~= "dB"; version(none) printf("destroy B\n"); } } struct S { A a; B b; } result = "{"; { S s1; result ~= "["; try { S s3 = s1; assert(0); } catch (Exception e) {} result ~= "]"; } result ~= "}"; assert(result == "{[pA(pB)dA]dBdA}", result); result = "{"; { S s1; S s2; result ~= "["; try { s2 = s1; assert(0); } catch (Exception e) {} result ~= "]"; } result ~= "}"; assert(result == "{[pA(pB)dA]dBdAdBdA}", result); return 1; } static assert(test10972()); // CTFE /**********************************/ // 11134 void test11134() { void test(S)() { S s; S[2] sa; S[2][] dsa = [[S(), S()]]; dsa.reserve(dsa.length + 2); // avoid postblit calls by GC S.count = 0; dsa ~= sa; assert(S.count == 2); S.count = 0; dsa ~= [s, s]; assert(S.count == 2); } static struct SS { static int count; this(this) { ++count; } } test!SS(); struct NS { static int count; this(this) { ++count; } } test!NS(); } /**********************************/ // 11197 struct S11197a { this(bool) {} this(this) {} } struct S11197b { //this(bool) {} this(this) {} } void test11197() { S11197a[][string] aa1; aa1["test"] ~= S11197a.init; S11197b[][string] aa2; aa2["test"] ~= S11197b.init; } /**********************************/ struct S7474 { float x; ~this() {} } void fun7474(T...)() { T x; } void test7474() { fun7474!S7474(); } /**********************************/ // 11286 struct A11286 { ~this() {} } A11286 getA11286() pure nothrow { return A11286(); } void test11286() { A11286 a = getA11286(); } /**********************************/ // 11505 struct Foo11505 { Bar11505 b; } struct Bar11505 { ~this() @safe { } void* p; } void test11505() { Foo11505 f; f = Foo11505(); } /**********************************/ // 12045 bool test12045() { string dtor; void* ptr; struct S12045 { string val; this(this) { assert(0); } ~this() { dtor ~= val; } } auto makeS12045(bool thrown) { auto s1 = S12045("1"); auto s2 = S12045("2"); ptr = &s1; if (thrown) throw new Exception(""); return s1; // NRVO } dtor = null, ptr = null; try { S12045 s = makeS12045(true); assert(0); } catch (Exception e) { assert(dtor == "21", dtor); } dtor = null, ptr = null; { S12045 s = makeS12045(false); assert(dtor == "2"); if (!__ctfe) assert(ptr is &s); // NRVO } assert(dtor == "21"); return true; } static assert(test12045()); /**********************************/ // 12591 struct S12591(T) { this(this) {} } struct Tuple12591(Types...) { Types expand; this(Types values) { expand[] = values[]; } } void test12591() { alias T1 = Tuple12591!(S12591!int); } /**********************************/ // 12660 struct X12660 { this(this) @nogc {} ~this() @nogc {} void opAssign(X12660) @nogc {} @nogc invariant() {} } struct Y12660 { X12660 x; this(this) @nogc {} ~this() @nogc {} @nogc invariant() {} } struct Z12660 { Y12660 y; } class C12660 { this() @nogc {} @nogc invariant() {} } void test12660() @nogc { X12660 x; x = x; Y12660 y = { x }; y = y; Z12660 z = { y }; z = z; } /**********************************/ // 12686 struct Foo12686 { static int count; invariant() { ++count; } @disable this(this); Foo12686 bar() { Foo12686 f; return f; } } void test12686() { Foo12686 f; Foo12686 f2 = f.bar(); version (unittest) { } else assert(Foo12686.count == 2); } /**********************************/ // 13089 struct S13089 { @disable this(this); // non nothrow } void* p13089; S13089[1000] foo13089() nothrow { typeof(return) data; p13089 = &data; return data; } void test13089() nothrow { immutable data = foo13089(); assert(p13089 == &data); } /**********************************/ struct NoDtortest11763 {} struct HasDtortest11763 { NoDtortest11763 func() { return NoDtortest11763(); } ~this() {} } void test11763() { HasDtortest11763().func(); } /**********************************/ struct Buf { } struct Variant { ~this() { } Buf get() { Buf b; return b; } } Variant value() { Variant v; return v; } void test13303() { value.get(); } /**********************************/ struct S13673 { string _name; ~this() {} } string name13673; void test13673() { S13673(name13673); S13673(name13673); } /**********************************/ void test13586() { static struct S { __gshared int count; ~this() { ++count; printf("~S\n"); } } static struct T { __gshared int count; ~this() { ++count; printf("~T\n"); } } static int foo(bool flag) { if (flag) throw new Exception("hello"); return 1; } static void func(S s, int f, T t) { printf("func()\n"); } static class C { this(S s, int f, T t) { printf("C()\n"); } } { bool threw = false; try { func(S(), foo(true), T()); printf("not reach\n"); } catch (Exception e) { threw = true; } printf("threw %d S %d T %d\n", threw, S.count, T.count); assert(threw && S.count == 1 && T.count == 0); S.count = 0; T.count = 0; } { bool threw = false; try { func(S(), foo(false), T()); printf("reached\n"); } catch (Exception e) { threw = true; } printf("threw %d S %d T %d\n", threw, S.count, T.count); assert(!threw && S.count == 1 && T.count == 1); S.count = 0; T.count = 0; } { bool threw = false; try { new C(S(), foo(true), T()); printf("not reach\n"); } catch (Exception e) { threw = true; } printf("threw %d S %d T %d\n", threw, S.count, T.count); assert(threw && S.count == 1 && T.count == 0); S.count = 0; T.count = 0; } } /**********************************/ // 14443 T enforce14443(E : Throwable = Exception, T)(T value) { if (!value) throw new E("Enforcement failed"); return value; } struct RefCounted14443(T) if (!is(T == class) && !(is(T == interface))) { struct RefCountedStore { private struct Impl { T _payload; size_t _count; } private Impl* _store; private void initialize(A...)(auto ref A args) { import core.stdc.stdlib : malloc; // enforce is necessary _store = cast(Impl*) enforce14443(malloc(Impl.sizeof)); // emulate 'emplace' static if (args.length > 0) _store._payload.tupleof = args; else _store._payload = T.init; _store._count = 1; } @property bool isInitialized() const nothrow @safe { return _store !is null; } void ensureInitialized() { if (!isInitialized) initialize(); } } RefCountedStore _refCounted; this(A...)(auto ref A args) if (A.length > 0) { _refCounted.initialize(args); } this(this) { if (!_refCounted.isInitialized) return; ++_refCounted._store._count; //printf("RefCounted count = %d (inc)\n", _refCounted._store._count); } ~this() { if (!_refCounted.isInitialized) return; assert(_refCounted._store._count > 0); if (--_refCounted._store._count) { //printf("RefCounted count = %u\n", _refCounted._store._count); return; } import core.stdc.stdlib : free; free(_refCounted._store); _refCounted._store = null; } void opAssign(typeof(this) rhs) { assert(0); } void opAssign(T rhs) { assert(0); } @property ref T refCountedPayload() { _refCounted.ensureInitialized(); return _refCounted._store._payload; } alias refCountedPayload this; } struct Path14443 { struct Payload { int p; } RefCounted14443!Payload data; } struct PathRange14443 { Path14443 path; size_t i; @property PathElement14443 front() { return PathElement14443(this, path.data.p); } } struct PathElement14443 { PathRange14443 range; this(PathRange14443 range, int) { this.range = range; } } void test14443() { auto path = Path14443(RefCounted14443!(Path14443.Payload)(12)); assert(path.data.p == 12); @property refCount() { return path.data._refCounted._store._count; } assert(refCount == 1); { auto _r = PathRange14443(path); assert(refCount == 2); // foreach { auto element = _r.front; assert(refCount == 3); // fail with 2.067 } assert(refCount == 2); } assert(refCount == 1); } /**********************************/ // 13661, 14022, 14023 - postblit/dtor call on static array assignment bool test13661() { string op; struct S { char x = 'x'; this(this) { op ~= x-0x20; } // upper case ~this() { op ~= x; } // lower case ref auto opAssign(T)(T arg) { assert(0); return this; } } { S[2] a; a[0].x = 'a'; a[1].x = 'b'; a = a.init; assert(op == "ab"); assert(a[0].x == 'x' && a[1].x == 'x'); a[0].x = 'c'; a[1].x = 'd'; a = [S(), S()]; // equivalent a = a.init assert(op == "abcd"); assert(a[0].x == 'x' && a[1].x == 'x'); } assert(op == "abcdxx"); return true; } bool test13661a() { string op; struct S { char x = 'x'; this(this) { op ~= x-0x20; } // upper case ~this() { op ~= x; } // lower case } { S[3] sa = [S('a'), S('b'), S('c')]; S[2] sb = sa[1..3]; assert(sa == [S('a'), S('b'), S('c')]); assert(sb == [S('b'), S('c')]); sb[0].x = 'x'; sb[1].x = 'y'; assert(sa != [S('a'), S('x'), S('y')]); // OK <- incorrectly fails assert(sa == [S('a'), S('b'), S('c')]); // OK <- incorrectly fails assert(sb == [S('x'), S('y')]); } return true; } static assert(test13661()); // CTFE static assert(test13661a()); bool test14022() { string op; struct S { char x = 'x'; this(this) { op ~= x-0x20; } // upper case ~this() { op ~= x; } // lower case } S[2] makeSA() { return [S('p'), S('q')]; } struct T { S[2] sb; this(ref S[2] sa) { assert(op == ""); this.sb = sa; // TOKconstruct assert(op == "BC", op); assert(sb == [S('b'), S('c')]); } void test(ref S[2] sa) { this.sb = sa; // dotvar: resolveSlice(newva) assert(op == "BxCy"); } } op = null; { S[2] sa = [S('a'), S('b')]; T t; t.sb[0].x = 'x'; t.sb[1].x = 'y'; assert(op == ""); t.sb = sa; assert(op == "AxBy"); t.sb = makeSA(); assert(op == "AxByab"); } assert(op == "AxByabqpba"); op = null; { S[3] sa = [S('a'), S('b'), S('c')]; T t = T(sa[1..3]); t.sb[0].x = 'x'; t.sb[1].x = 'y'; assert(sa == [S('a'), S('b'), S('c')]); assert(t.sb == [S('x'), S('y')]); assert(op == "BC"); } assert(op == "BCyxcba"); op = null; { S[3] sx = [S('a'), S('b'), S('c')]; T t; t.sb[0].x = 'x'; t.sb[1].x = 'y'; t.test(sx[1..3]); assert(op == "BxCy"); assert(t.sb == [S('b'), S('c')]); } assert(op == "BxCycbcba"); return true; } static assert(test14022()); bool test14023() { string op; struct S { char x = 'x'; this(this) { op ~= x-0x20; } // upper case ~this() { op ~= x; } // lower case } S[2] makeSA() { return [S('p'), S('q')]; } struct T { S[2][1] sb; this(ref S[2] sa) { assert(op == ""); this.sb[0] = sa; // TOKconstruct assert(sa == [S('b'), S('c')]); assert(sb[0] == [S('b'), S('c')]); } } void test(ref S[2] sa) { S[2][] a; //a.length = 1; // will cause runtine AccessViolation a ~= (S[2]).init; assert(op == ""); a[0] = sa; // index <-- resolveSlice(newva) assert(op == "BxCx"); assert(a[0] == [S('b'), S('c')]); } op = null; { S[3] sa = [S('a'), S('b'), S('c')]; T t = T(sa[1..3]); t.sb[0][0].x = 'x'; t.sb[0][1].x = 'y'; assert(sa != [S('a'), S('x'), S('y')]); // OK <- incorrectly fails assert(sa == [S('a'), S('b'), S('c')]); // OK <- incorrectly fails assert(t.sb[0] == [S('x'), S('y')]); } op = null; { S[2] sa = [S('a'), S('b')]; S[2][] a = [[S('x'), S('y')]]; assert(op == ""); a[0] = sa; assert(op == "AxBy"); a[0] = makeSA(); assert(op == "AxByab"); } assert(op == "AxByabba"); op = null; { S[3] sa = [S('a'), S('b'), S('c')]; test(sa[1..3]); assert(op == "BxCx"); } assert(op == "BxCxcba"); return true; } static assert(test14023()); /************************************************/ // 13669 - dtor call on static array variable bool test13669() { string dtor; struct S { char x = 'x'; ~this() { dtor ~= x; } } { S[2] a; } assert(dtor == "xx"); dtor = ""; { S[2] a = [S('a'), S('b')]; } assert(dtor == "ba"); // reverse order. See also: TypeInfo_StaticArray.destroy() return true; } static assert(test13669()); /**********************************/ __gshared bool b13095 = false; void bar13095() { throw new Exception(""); } struct S13095 { this(int) { printf("ctor %p\n", &this); bar13095(); } ~this() { b13095 = true; printf("dtor %p\n", &this); } } void test13095() { try { S13095(0); } catch(Exception) { printf("catch\n"); } assert(!b13095); } /**********************************/ // 14264 void test14264() { static int dtor; static struct Foo { ~this() { ++dtor; } T opCast(T:bool)() { return true; } } Foo makeFoo() { return Foo(); } assert(dtor == 0); makeFoo(); assert(dtor == 1); makeFoo; assert(dtor == 2); if (makeFoo()) {} assert(dtor == 3); if (makeFoo) {} assert(dtor == 4); } /**********************************/ // 14686 int test14686() { string r; struct S { int n; this(this) { r ~= cast(char)('0' + n); } } S s1 = S(1); S s2 = S(2); S[] a1 = [S(1)]; S[2] sa1 = [s1, s2]; assert(r == "12", r); // OK r = ""; S[] a2 = a1 ~ s2; // runtime concatenation assert(r == "12", r); // OK <- NG only in CTFE r = ""; S[2] sa2a = [s1] ~ s2; assert(r == "12", r); // OK <- NG, s2 is not copied r = ""; S[2] sa2b = s2 ~ [s1]; assert(r == "21", r); // OK <- NG, s2 is not copied r = ""; S[3] sa3a = ([s1] ~ [s1]) ~ s2; assert(r == "112", r); // OK <- NG, s2 is not copied r = ""; S[3] sa3b = s2 ~ ([s1] ~ [s1]); assert(r == "211", r); // OK <- NG, s2 is not copied return 1; } static assert(test14686()); /**********************************/ // 14815 int test14815() { uint dtorCount; struct S { uint x; ~this() { ++dtorCount; } } S[2] sa1; sa1[0].x = 42; sa1 = (S[2]).init; // S[2] <- rvalue assert(sa1[0].x == 0); assert(dtorCount == 2); S[2] sa2; sa2[0].x = 42; S[] da2 = sa2[]; da2[] = (S[2]).init[]; // S[] <- rvalue slice assert(sa2[0].x == 0); assert(dtorCount == 4); S[2] sa3; S[2] sa4; sa3[0].x = 42; sa3 = sa4; // S[2] <- lvalue assert(sa3[0].x == 0); assert(dtorCount == 6); S[2] sa5; S[] da4 = sa4[]; da4[] = sa5[]; // S[] <- lvalue slice assert(sa4[0].x == 0); assert(dtorCount == 8); return 1; } static assert(test14815()); /**********************************/ // 14860 int test14860() { uint dtorCount; struct S { uint x; ~this() { ++dtorCount; } } S[] a = [S(42)]; a[] = S(); assert(a[0].x == 0); assert(dtorCount == 1); return 1; } static assert(test14860()); /**********************************/ // 14696 void test14696(int len = 2) { string result; struct S { int n; void* get(void* p = null) { result ~= "get(" ~ cast(char)(n+'0') ~ ")."; return null; } ~this() { result ~= "dtor(" ~ cast(char)(n+'0') ~ ")."; } } S makeS(int n) { result ~= "makeS(" ~ cast(char)(n+'0') ~ ")."; return S(n); } void foo(void* x, void* y = null) { result ~= "foo."; } void fooThrow(void* x, void* y = null) { result ~= "fooThrow."; throw new Exception("fail!"); } void check(void delegate() dg, string r, string file = __FILE__, size_t line = __LINE__) { import core.exception; result = null; try { dg(); } catch (Exception e) {} if (result != r) throw new AssertError(result, file, line); } // temporary in condition check({ foo(len == 2 ? makeS(1).get() : null); }, "makeS(1).get(1).foo.dtor(1)."); check({ foo(len == 2 ? null : makeS(1).get() ); }, "foo."); check({ foo(len != 2 ? makeS(1).get() : null); }, "foo."); check({ foo(len != 2 ? null : makeS(1).get() ); }, "makeS(1).get(1).foo.dtor(1)."); // temporary in nesting conditions check({ foo(len >= 2 ? (len == 2 ? makeS(1).get() : null) : null); }, "makeS(1).get(1).foo.dtor(1)."); check({ foo(len >= 2 ? (len == 2 ? null : makeS(1).get() ) : null); }, "foo."); check({ foo(len >= 2 ? (len != 2 ? makeS(1).get() : null) : null); }, "foo."); check({ foo(len >= 2 ? (len != 2 ? null : makeS(1).get() ) : null); }, "makeS(1).get(1).foo.dtor(1)."); check({ foo(len >= 2 ? null : (len == 2 ? makeS(1).get() : null) ); }, "foo."); check({ foo(len >= 2 ? null : (len == 2 ? null : makeS(1).get() ) ); }, "foo."); check({ foo(len >= 2 ? null : (len != 2 ? makeS(1).get() : null) ); }, "foo."); check({ foo(len >= 2 ? null : (len != 2 ? null : makeS(1).get() ) ); }, "foo."); check({ foo(len > 2 ? (len == 2 ? makeS(1).get() : null) : null); }, "foo."); check({ foo(len > 2 ? (len == 2 ? null : makeS(1).get() ) : null); }, "foo."); check({ foo(len > 2 ? (len != 2 ? makeS(1).get() : null) : null); }, "foo."); check({ foo(len > 2 ? (len != 2 ? null : makeS(1).get() ) : null); }, "foo."); check({ foo(len > 2 ? null : (len == 2 ? makeS(1).get() : null) ); }, "makeS(1).get(1).foo.dtor(1)."); check({ foo(len > 2 ? null : (len == 2 ? null : makeS(1).get() ) ); }, "foo."); check({ foo(len > 2 ? null : (len != 2 ? makeS(1).get() : null) ); }, "foo."); check({ foo(len > 2 ? null : (len != 2 ? null : makeS(1).get() ) ); }, "makeS(1).get(1).foo.dtor(1)."); // temporary in condition and throwing callee // check({ fooThrow(len == 2 ? makeS(1).get() : null); }, "makeS(1).get(1).fooThrow.dtor(1)."); // check({ fooThrow(len == 2 ? null : makeS(1).get() ); }, "fooThrow."); // check({ fooThrow(len != 2 ? makeS(1).get() : null); }, "fooThrow."); // check({ fooThrow(len != 2 ? null : makeS(1).get() ); }, "makeS(1).get(1).fooThrow.dtor(1)."); // temporary in nesting condititions and throwing callee // check({ fooThrow(len >= 2 ? (len == 2 ? makeS(1).get() : null) : null); }, "makeS(1).get(1).fooThrow.dtor(1)."); // check({ fooThrow(len >= 2 ? (len == 2 ? null : makeS(1).get() ) : null); }, "fooThrow."); // check({ fooThrow(len >= 2 ? (len != 2 ? makeS(1).get() : null) : null); }, "fooThrow."); // check({ fooThrow(len >= 2 ? (len != 2 ? null : makeS(1).get() ) : null); }, "makeS(1).get(1).fooThrow.dtor(1)."); // check({ fooThrow(len >= 2 ? null : (len == 2 ? makeS(1).get() : null) ); }, "fooThrow."); // check({ fooThrow(len >= 2 ? null : (len == 2 ? null : makeS(1).get() ) ); }, "fooThrow."); // check({ fooThrow(len >= 2 ? null : (len != 2 ? makeS(1).get() : null) ); }, "fooThrow."); // check({ fooThrow(len >= 2 ? null : (len != 2 ? null : makeS(1).get() ) ); }, "fooThrow."); // check({ fooThrow(len > 2 ? (len == 2 ? makeS(1).get() : null) : null); }, "fooThrow."); // check({ fooThrow(len > 2 ? (len == 2 ? null : makeS(1).get() ) : null); }, "fooThrow."); // check({ fooThrow(len > 2 ? (len != 2 ? makeS(1).get() : null) : null); }, "fooThrow."); // check({ fooThrow(len > 2 ? (len != 2 ? null : makeS(1).get() ) : null); }, "fooThrow."); // check({ fooThrow(len > 2 ? null : (len == 2 ? makeS(1).get() : null) ); }, "makeS(1).get(1).fooThrow.dtor(1)."); // check({ fooThrow(len > 2 ? null : (len == 2 ? null : makeS(1).get() ) ); }, "fooThrow."); // check({ fooThrow(len > 2 ? null : (len != 2 ? makeS(1).get() : null) ); }, "fooThrow."); // check({ fooThrow(len > 2 ? null : (len != 2 ? null : makeS(1).get() ) ); }, "makeS(1).get(1).fooThrow.dtor(1)."); // temporaries in each conditions check({ foo(len == 2 ? makeS(1).get() : null, len == 2 ? makeS(2).get() : null); }, "makeS(1).get(1).makeS(2).get(2).foo.dtor(2).dtor(1)."); check({ foo(len == 2 ? makeS(1).get() : null, len != 2 ? makeS(2).get() : null); }, "makeS(1).get(1).foo.dtor(1)."); check({ foo(len != 2 ? makeS(1).get() : null, len == 2 ? makeS(2).get() : null); }, "makeS(2).get(2).foo.dtor(2)."); check({ foo(len != 2 ? makeS(1).get() : null, len != 2 ? makeS(2).get() : null); }, "foo."); // nesting temporaries in conditions check({ foo(len == 2 ? makeS(1).get(len == 2 ? makeS(2).get() : null) : null); }, "makeS(1).makeS(2).get(2).get(1).foo.dtor(2).dtor(1)."); check({ foo(len == 2 ? makeS(1).get(len != 2 ? makeS(2).get() : null) : null); }, "makeS(1).get(1).foo.dtor(1)."); check({ foo(len != 2 ? makeS(1).get(len == 2 ? makeS(2).get() : null) : null); }, "foo."); check({ foo(len != 2 ? makeS(1).get(len != 2 ? makeS(2).get() : null) : null); }, "foo."); } /**********************************/ // 14838 int test14838() pure nothrow @safe { int dtor; struct S14838(T) { ~this() { ++dtor; } } struct X14838 { S14838!int ms; const S14838!int cs; S14838!int[2] ma; const S14838!int[2] ca; S14838!int[2][2] ma2x2; const S14838!int[2][2] ca2x2; // number of S14838 = 1*2 + 2*2 + 4*2 = 14 } void test(Dg)(scope Dg code) { dtor = 0; code(); } test(delegate{ S14838!int a; }); assert(dtor == 1); test(delegate{ const S14838!int a; }); assert(dtor == 1); test(delegate{ S14838!int[2] a; }); assert(dtor == 2); test(delegate{ const S14838!int[2] a; }); assert(dtor == 2); test(delegate{ S14838!int[2][2] a; }); assert(dtor == 4); test(delegate{ const S14838!int[2][2] a; }); assert(dtor == 4); test(delegate{ X14838 a; }); assert(dtor == 1 * 14); test(delegate{ const X14838 a; }); assert(dtor == 1 * 14); test(delegate{ X14838[2] a; }); assert(dtor == 2 * 14); test(delegate{ const X14838[2] a; }); assert(dtor == 2 * 14); test(delegate{ X14838[2][2] a; }); assert(dtor == 4 * 14); test(delegate{ const X14838[2][2] a; }); assert(dtor == 4 * 14); return 1; } static assert(test14838()); /**********************************/ struct S63 { private long p = 87; this(int x) { assert(p == 87); p += x; } ~this() { } this(this) { } void funky() { assert(p == 90); } static void tester() { S63(3).funky(); } } void test63() { S63.tester(); } /**********************************/ // 15661 struct X15661 { ~this() {} } X15661 createX15661() { return X15661(); } struct Y15661 { static int dtor; @disable this(); @disable this(this); this(X15661 a1, X15661 a2) {} ~this() { ++dtor; } } struct Z15661 { this(int) { b = Y15661(createX15661(), createX15661()); assert(Y15661.dtor == 0); } private Y15661 b; } void test15661() { { auto v = Z15661(5); assert(Y15661.dtor == 0); } assert(Y15661.dtor == 1); } /**********************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test50(); test51(); test52(); test54(); test55(); test56(); test57(); test58(); test59(); test5737(); test6119(); test8741(); test6364(); test6499(); test60(); test4316(); test6177(); test6470(); test6636(); test6637(); test7353(); test61(); test7506(); test7516a(); test7516b(); test7516c(); test7516d(); test7516e(); test7530(); test62(); test7579a(); test7579b(); test8335(); test8356(); test9386(); test9441(); test9720(); test9899(); test9907(); test9985(); test9994(); test10094(); test10244(); test10694(); test10789(); test10972(); test11134(); test11197(); test7474(); test11505(); test12045(); test12591(); test12660(); test12686(); test13089(); test11763(); test13303(); test13673(); test13586(); test14443(); test13661(); test13661a(); test14022(); test14023(); test13669(); test13095(); test14264(); test14686(); test14815(); test14860(); test14696(); test14838(); test63(); test15661(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test60.d0000664000175000017500000000043212776215022021475 0ustar kaikaiimport std.stdio; import std.algorithm; void test1() { int[] a = [1,2,3,4,5]; writeln( remove!("a < 3")(a) ); } void test2() { auto arr = [1,2,3,4,5]; auto m = map!"a + 1"(filter!"a < 4"(arr)); } void main() { test1(); test2(); writeln("Success"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link13350.d0000664000175000017500000000536712776215022021715 0ustar kaikaiextern (C) int printf(const(char*) fmt, ...); static int foo(); /**********************************/ auto red()() { return foo(); } void test13350() { int[] data; assert(is(typeof(red()))); } /**********************************/ struct A1(T) { void f1() {} } struct B1(T) { void f2() {} } A1!(B1!int) func1()() { return typeof(return).init; } void test1() { static if (is(typeof(func1()) R : X!(Y), alias X, Y)) { R.init.f1(); Y.init.f2(); } else static assert(0); } /**********************************/ struct A2(T) { void f1() { foo(); } } struct B2(T) { void f2() { foo(); } } A2!(B2!int) func2()() { return typeof(return).init; } void test2() { static if (is(typeof(func2()))) { } else static assert(0); } /**********************************/ template A3() { void foo() { B3!().bar(); } } template B3() { void bar() {} } void test3() { // A3!() and B3!() are marked as 'speculative' static assert(is(typeof(A3!().foo()))); // A3!() is unspeculative, but B3!() isn't. A3!().foo(); // in codegen phase, B3!() will generate its members, because // the tinst chain contains unspeculative instance A3!(). } /**********************************/ struct S4(T) { string toString() const { return "instantiated"; } } void test4() { // inside typeof is not speculative context alias X = typeof(S4!int()); assert(typeid(X).xtoString !is null); } /**********************************/ struct S5(T) { string toString() const { return "instantiated"; } } void test5() { enum x = S5!int(); assert(x.toString() == "instantiated"); } /**********************************/ int foo6()() { return 0; } template A6() { alias f = foo6!(); } void testa6()() if (is(typeof(A6!().f))) {} template B6() { alias f = foo6!(); } void testb6()() if (is(typeof(B6!().f))) {} template C6() { void f() { B6!().f(); } } void test6() { testa6(); // foo6!() is speculatively instantiated from A6!() [TemplateInstance a] // -> foo6!() is instantiated in A6!(), so it should be inserted to the members of this module. testb6(); // foo6!() is speculatively instantiated from B6!() [TemplateInstance b], // but the tinst of cached [TemplateInstance a] is not changed. // -> insert [b] to the tnext chain of [a] C6!().f(); // foo6!() is used through C6!(), so it should be linked to the final executable. // but its first instance does not link to any non-speculative instances. // -> look for tnext chain and determine its codegen is really necessary. } /**********************************/ int main() { test13350(); test1(); test2(); test3(); test4(); test5(); test6(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/argufilem.d0000664000175000017500000000101112776215022022315 0ustar kaikai// EXTRA_SOURCES: imports/argufile.d // NOTE: The bug only works when main.d and argufile.d are put in // separate files and compiled like 'dmd main.d argufile.d' // Also, I'm sure writefln is causing the crash cause when I // use printf(), it doesn't crash. // main.d ------------------------------------------------------- import argufile; int main(string[] args) { string message = arguments("bob is ", 7, " years old"); writefln(message); argufile.useargs(); // will crash here return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/eh.d0000664000175000017500000003144612776215022020755 0ustar kaikai// PERMUTE_ARGS: -O -fPIC extern(C) int printf(const char*, ...); /****************************************************/ class Abc : Exception { this() { super(""); } int i; } int y; alias int boo; void foo(int x) { y = cast(boo)1; L6: try { printf("try 1\n"); y += 4; if (y == 5) goto L6; y += 3; } finally { y += 5; printf("finally 1\n"); } try { printf("try 2\n"); y = 1; if (y == 4) goto L6; y++; } catch (Abc c) { printf("catch 2\n"); y = 2 + c.i; } y++; printf("done\n"); } /****************************************************/ class IntException : Exception { this(int i) { m_i = i; super(""); } int getValue() { return m_i; } int m_i; } void test2() { int cIterations = 10; int i; long total_x = 0; long total_nox = 0; for(int WARMUPS = 2; WARMUPS-- > 0; ) { for(total_x = 0, i = 0; i < cIterations; ++i) { total_nox += fn2_nox(); } printf("foo\n"); for(total_nox = 0, i = 0; i < cIterations; ++i) { printf("i = %d\n", i); try { int z = 1; throw new IntException(z); } catch(IntException x) { printf("catch, i = %d\n", i); total_x += x.getValue(); } } } printf("iterations %d totals: %ld, %ld\n", cIterations, total_x, total_nox); } int fn2_nox() { return 47; } /****************************************************/ void test3() { static int x; try { } finally { printf("a\n"); assert(x == 0); x++; } printf("--\n"); assert(x == 1); try { printf("tb\n"); assert(x == 1); } finally { printf("b\n"); assert(x == 1); x++; } assert(x == 2); } /****************************************************/ class Tester { this(void delegate() dg_) { dg = dg_; } void delegate() dg; void stuff() { dg(); } } void test4() { printf("Starting test\n"); int a = 0; int b = 0; int c = 0; int d = 0; try { a++; throw new Exception("test1"); a++; } catch(Exception e) { auto es = e.toString(); printf("%.*s\n", es.length, es.ptr); b++; } finally { c++; } printf("initial test.\n"); assert(a == 1); assert(b == 1); assert(c == 1); printf("pass\n"); Tester t = new Tester( delegate void() { try { a++; throw new Exception("test2"); a++; } catch(Exception e) { b++; throw e; b++; } }); try { c++; t.stuff(); c++; } catch(Exception e) { d++; string es = e.toString; printf("%.*s\n", es.length, es.ptr); } assert(a == 2); assert(b == 2); assert(c == 2); assert(d == 1); int q0 = 0; int q1 = 0; int q2 = 0; int q3 = 0; Tester t2 = new Tester( delegate void() { try { q0++; throw new Exception("test3"); q0++; } catch(Exception e) { printf("Never called.\n"); q1++; throw e; q1++; } }); try { q2++; t2.stuff(); q2++; } catch(Exception e) { q3++; string es = e.toString; printf("%.*s\n", es.length, es.ptr); } assert(q0 == 1); assert(q1 == 1); assert(q2 == 1); assert(q3 == 1); printf("Passed!\n"); } /****************************************************/ void test5() { char[] result; int i = 3; while(i--) { try { printf("i: %d\n", i); result ~= 't'; if (i == 1) continue; } finally { printf("finally\n"); result ~= cast(char)('a' + i); } } printf("--- %.*s", result.length, result.ptr); if (result != "tctbta") assert(0); } /****************************************************/ void test6() { char[] result; while (true) { try { printf("one\n"); result ~= 'a'; break; } finally { printf("two\n"); result ~= 'b'; } } printf("three\n"); result ~= 'c'; if (result != "abc") assert(0); } /****************************************************/ string a7; void doScan(int i) { a7 ~= "a"; try { try { a7 ~= "b"; return; } finally { a7 ~= "c"; } } finally { a7 ~= "d"; } } void test7() { doScan(0); assert(a7 == "abcd"); } /**************************************************** * Exception chaining tests. See also test4.d ****************************************************/ int result1513; void bug1513a() { throw new Exception("d"); } void bug1513b() { try { try { bug1513a(); } finally { result1513 |=4; throw new Exception("f"); } } catch(Exception e) { assert(e.msg == "d"); assert(e.next.msg == "f"); assert(!e.next.next); } } void bug1513c() { try { try { throw new Exception("a"); } finally { result1513 |= 1; throw new Exception("b"); } } finally { bug1513b(); result1513 |= 2; throw new Exception("c"); } } void bug1513() { result1513 = 0; try { bug1513c(); } catch(Exception e) { assert(result1513 == 7); assert(e.msg == "a"); assert(e.next.msg == "b"); assert(e.next.next.msg == "c"); } } void collideone() { try { throw new Exception("x"); } finally { throw new Exception("y"); } } void doublecollide() { try { try { try { throw new Exception("p"); } finally { throw new Exception("q"); } } finally { collideone(); } } catch(Exception e) { assert(e.msg == "p"); assert(e.next.msg == "q"); assert(e.next.next.msg == "x"); assert(e.next.next.next.msg == "y"); assert(!e.next.next.next.next); } } void collidetwo() { try { try { throw new Exception("p2"); } finally { throw new Exception("q2"); } } finally { collideone(); } } void collideMixed() { int works = 6; try { try { try { throw new Exception("e"); } finally { throw new Error("t"); } } catch(Exception f) { // Doesn't catch, because Error is chained to it. works += 2; } } catch(Error z) { works += 4; assert(z.msg=="t"); // Error comes first assert(z.next is null); assert(z.bypassedException.msg == "e"); } assert(works == 10); } class AnotherException : Exception { this(string s) { super(s); } } void multicollide() { try { try { try { try { throw new Exception("m2"); } finally { throw new AnotherException("n2"); } } catch(AnotherException s) { // Not caught -- we needed to catch the root cause "m2", not // just the collateral "n2" (which would leave m2 uncaught). assert(0); } } finally { collidetwo(); } } catch(Exception f) { assert(f.msg == "m2"); assert(f.next.msg == "n2"); Throwable e = f.next.next; assert(e.msg == "p2"); assert(e.next.msg == "q2"); assert(e.next.next.msg == "x"); assert(e.next.next.next.msg == "y"); assert(!e.next.next.next.next); } } /****************************************************/ void use9568(char [] x, char [] y) {} int bug9568() { try return 7; finally use9568(null,null); } void test9568() { assert( bug9568() == 7 ); } /****************************************************/ version (DigitalMars) { void test8a() { int a; goto L2; // L2 is not addressable. try { a += 2; } catch (Exception) { a += 3; L2: ; a += 100; } assert(a == 100); } void test8b() { int a; goto L2; // L2 is not addressable. try { } catch (Exception) { a += 3; L2: ; a += 100; } assert(a == 100); } void test8c() { int a; goto L2; // L2 is not addressable. try static assert(true); catch (Exception) { a += 3; L2: ; a += 100; } assert(a == 100); } void test8() { test8a(); test8b(); test8c(); } } /****************************************************/ uint foo9(uint i) { try { ++i; return 3; } catch (Exception e) { debug printf("Exception happened\n"); } return 4; } void test9() { assert(foo9(7) == 3); } /****************************************************/ // 10964 void test10964() { static struct S { this(this) { throw new Exception("BOOM!"); } } S ss; S[1] sa; int result; result = 0; try { ss = ss; } catch (Exception e) result = 1; catch (Error e) result = 2; catch (Throwable e) result = 3; assert(result == 1); try { sa = ss; } catch (Exception e) result = 1; catch (Error e) result = 2; catch (Throwable e) result = 3; assert(result == 1); try { sa = sa; } catch (Exception e) result = 1; catch (Error e) result = 2; catch (Throwable e) result = 3; assert(result == 1); } /****************************************************/ alias Action = void delegate(); class A10 { invariant() { } public Action foo(Action a) { synchronized { B10 elements = new B10; Action[] actions = [a]; elements.bar(actions); if (actions.length > 1) elements.bar(actions); return actions[0]; } return null; } } class B10 { public bool bar(ref Action[]) { return false; } } class D10 { void baz() { } } void test12989() { auto a = new A10; auto d = new D10; assert(a.foo(&d.baz) == &d.baz); } /****************************************************/ int bar10(int c) { if (c <= 0xFFFF) { L3: return 3; } throw new Exception("msg"); goto L3; } void test10() { int x; try { bar10(0x110000); } catch (Exception e) { printf("caught\n"); x = 1; } assert(x == 1); printf("test10 success\n"); } /****************************************************/ class ParseException : Exception { @safe pure nothrow this( string msg ) { super( msg ); } } class OverflowException : Exception { @safe pure nothrow this( string msg ) { super( msg ); } } void test11() { int x; try { printf("test11()\n"); throw new ParseException("msg"); } catch( OverflowException e ) { printf( "catch OverflowException\n" ); } catch( ParseException e ) { printf( "catch ParseException: %.*s\n", cast(int) e.msg.length, e.msg.ptr ); x = 1; } assert(x == 1); } /****************************************************/ int main() { printf("start\n"); foo(3); test2(); test3(); test4(); test5(); test6(); test7(); bug1513(); doublecollide(); collideMixed(); multicollide(); test9568(); version(DigitalMars) test8(); test9(); test10964(); test12989(); test10(); test11(); printf("finish\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link12037.d0000664000175000017500000000013712776215022021704 0ustar kaikaiimport imports.a12037; alias CustomFloat!(10, 5) Float16; void main() { Float16 f = 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test12874.d0000664000175000017500000000041412776215022021735 0ustar kaikai// EXTRA_SOURCES: imports/a12874.d // PERMUTE_ARGS: -inline -g -O import imports.a12874; void main() { try { int x; foo!(x)(); } catch (Error e) { assert(e.file[$-8..$] == "a12874.d"); assert(e.line == 7); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/cpp_abi_tests.d0000664000175000017500000000763712776215022023205 0ustar kaikai// EXTRA_CPP_SOURCES: cpp_abi_tests.cpp extern(C++) { struct S { float a = 1; } bool passthrough(bool value); byte passthrough(byte value); ubyte passthrough(ubyte value); char passthrough(char value); dchar passthrough(dchar value); short passthrough(short value); ushort passthrough(ushort value); int passthrough(int value); uint passthrough(uint value); long passthrough(long value); ulong passthrough(ulong value); float passthrough(float value); double passthrough(double value); S passthrough(S value); bool passthrough_ptr(bool *value); byte passthrough_ptr(byte *value); ubyte passthrough_ptr(ubyte *value); char passthrough_ptr(char *value); dchar passthrough_ptr(dchar *value); short passthrough_ptr(short *value); ushort passthrough_ptr(ushort *value); int passthrough_ptr(int *value); uint passthrough_ptr(uint *value); long passthrough_ptr(long *value); ulong passthrough_ptr(ulong *value); float passthrough_ptr(float *value); double passthrough_ptr(double *value); S passthrough_ptr(S *value); bool passthrough_ref(ref bool value); byte passthrough_ref(ref byte value); ubyte passthrough_ref(ref ubyte value); char passthrough_ref(ref char value); dchar passthrough_ref(ref dchar value); short passthrough_ref(ref short value); ushort passthrough_ref(ref ushort value); int passthrough_ref(ref int value); uint passthrough_ref(ref uint value); long passthrough_ref(ref long value); ulong passthrough_ref(ref ulong value); float passthrough_ref(ref float value); double passthrough_ref(ref double value); S passthrough_ref(ref S value); } template IsSigned(T) { enum IsSigned = is(T==byte) || is(T==short) || is(T==int) || is(T==long); } template IsUnsigned(T) { enum IsUnsigned = is(T==ubyte) || is(T==ushort) || is(T==uint) || is(T==ulong); } template IsIntegral(T) { enum IsIntegral = IsSigned!T || IsUnsigned!T; } template IsFloatingPoint(T) { enum IsFloatingPoint = is(T==float) || is(T==double) || is(T==real); } template IsBoolean(T) { enum IsBoolean = is(T==bool); } template IsSomeChar(T) { enum IsSomeChar = is(T==char) || is(T==dchar); } void check(T)(T actual, T expected) { assert(actual is expected); } void check(T)(T value) { check(passthrough(value), value); check(passthrough_ptr(&value), value); check(passthrough_ref(value), value); } T[] values(T)() { T[] values; static if(IsBoolean!T) { values ~= true; values ~= false; } else static if(IsSomeChar!T) { values ~= T.init; values ~= T('a'); values ~= T('z'); } else { values ~= T(0); values ~= T(1); static if(IsIntegral!T) { static if(IsSigned!T) values ~= T.min; values ~= T.max; } else static if(IsFloatingPoint!T) { values ~= T.nan; values ~= T.min_normal; values ~= T.max; } else { assert(0); } } return values; } void main() { foreach(bool val; values!bool()) check(val); foreach(byte val; values!byte()) check(val); foreach(ubyte val; values!ubyte()) check(val); foreach(char val; values!char()) check(val); foreach(dchar val; values!dchar()) check(val); foreach(short val; values!short()) check(val); foreach(ushort val; values!ushort()) check(val); foreach(int val; values!int()) check(val); foreach(uint val; values!uint()) check(val); foreach(long val; values!long()) check(val); foreach(ulong val; values!ulong()) check(val); foreach(float val; values!float()) check(val); foreach(double val; values!double()) check(val); check(S()); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testaa.d0000664000175000017500000006151412776215022021641 0ustar kaikai// PERMUTE_ARGS: -fPIC /* Test associative arrays */ extern(C) int printf(const char*, ...); extern(C) int memcmp(const void *s1, const void *s2, size_t n); import core.memory; // for GC.collect import std.random; // for uniform random numbers /************************************************/ int nametable[char[]]; void insert(string name, int value) { nametable[name] = value; } int retrieve(string name) { return nametable[name]; } void test1() { int v; printf("test1.a\n"); insert("hello", 1); printf("test1.b\n"); insert("world", 2); printf("test1.c\n"); v = retrieve("hello"); assert(v == 1); v = retrieve("world"); assert(v == 2); v = retrieve("world"); assert(v == 2); nametable.rehash; v = retrieve("world"); assert(v == 2); } /************************************************/ void test2() { int[string] aa; string[] keys; int[] values; printf("test2()\n"); /*************/ assert(aa == null); assert(aa.length == 0); keys = aa.keys; assert(keys.length == 0); values = aa.values; assert(values.length == 0); aa.rehash; assert(aa.length == 0); /*************/ aa["hello"] = 3; assert(aa["hello"] == 3); aa["hello"]++; assert(aa["hello"] == 4); assert(aa.length == 1); keys = aa.keys; assert(keys.length == 1); assert(memcmp(keys[0].ptr, cast(char*)"hello", 5) == 0); values = aa.values; assert(values.length == 1); assert(values[0] == 4); aa.rehash; assert(aa.length == 1); assert(aa["hello"] == 4); } /************************************************/ void test4() { int[const(ubyte)[]] b; const(ubyte)[] x; b[x] = 3; assert(b[x] == 3); } /************************************************/ void test5() { int[immutable(short)[]] b; immutable(short)[] x; b[x] = 3; assert(b[x] == 3); } /************************************************/ void test6() { int[const(int)[]] b; const(int)[] x; b[x] = 3; assert(b[x] == 3); } /************************************************/ void test7() { int[immutable(uint)[]] b; immutable(uint)[] x; b[x] = 3; assert(b[x] == 3); } /************************************************/ void test8() { int[immutable(long)[]] b; immutable(long)[] x; b[x] = 3; assert(b[x] == 3); } /************************************************/ void test9() { int[immutable(ulong)[]] b; immutable(ulong)[] x; b[x] = 3; assert(b[x] == 3); } /************************************************/ class A10 {} int[immutable(A10)[]] foo10; void test10() { auto key = new immutable(A10)[2]; cast()(key[0]) = new A10(); foo10[key] = 0; assert(key in foo10); assert(!(key !in foo10)); } /************************************************/ struct Value { uint x,y,z,t; } struct Key { int a,b,c,d; static int hash, cmp, equals; size_t toHash() const { hash = 1; return a + b + c + d; } int opCmp(ref const Key s) const { cmp = 1; int x; x = a - s.a; if (x == 0) { x = b - s.b; if (x == 0) { x = c - s.c; if (x == 0) x = d - s.d; } } return x; } bool opEquals(ref const Key s) const { printf("opEquals()\n"); equals = 1; return (a == s.a && b == s.b && c == s.c && d == s.d); } } void test11() { Value[Key] table; Value* p; Value v; Value r; Key k; v.x = 7; v.y = 8; v.z = 9; v.t = 10; k.a = 1; k.b = 2; k.c = 3; k.d = 4; p = k in table; assert(!p); table[k] = v; p = k in table; assert(p); table.rehash; p = k in table; assert(p); r = table[k]; assert(v == r); table.remove(k); assert(!(k in table)); printf("Key.hash = %d\n", Key.hash); assert(Key.hash == 1); printf("Key.cmp = %d\n", Key.cmp); printf("Key.equals = %d\n", Key.equals); assert(Key.cmp == 1 && !Key.equals || !Key.cmp && Key.equals == 1); } /************************************************/ struct S12 { byte number; char[] description; char[] font_face; byte font_size; ushort flags; int colour_back; int colour_fore; byte charset; } void test12() { S12[] x; printf("size %d\n",S12.sizeof); printf("align %d\n",S12.alignof); printf("offset %d\n",S12.description.offsetof); for (int i=0;i<3;i++) { S12 s; s.font_face="font face".dup; x ~= s; } /* works fine S12 s; s.font_face="font face".dup; x ~= s; s.font_face="font face".dup; x ~= s; s.font_face="font face".dup; x ~= s; s.font_face="font face".dup; x ~= s; */ GC.collect(); printf("%.*s\n",x[0].font_face.length,x[0].font_face.ptr); printf("%.*s\n",x[1].font_face.length,x[1].font_face.ptr); } /************************************************/ void test13() { int[string] array; array["eins"]=1; array["zwei"]=2; array["drei"]=3; assert(array.length==3); int[string] rehashed=array.rehash; assert(rehashed is array); string[] key = array.keys; assert(key.length==3); bool have[3]; assert(!have[0]); assert(!have[1]); assert(!have[2]); foreach(string value; key){ switch(value){ case "eins":{ have[0]=true; break; }case "zwei":{ have[1]=true; break; }case "drei":{ have[2]=true; break; }default:{ assert(0); } } } assert(have[0]); assert(have[1]); assert(have[2]); } /************************************************/ void test14() { int[char[]] aa; aa["hello"] = 3; assert(aa["hello"] == 3); assert("hello" in aa); //delete aa["hello"]; aa.remove("hello"); assert(!("hello" in aa)); } /************************************************/ class SomeClass { this(char value) { printf("class created\n"); _value = value; } ~this() { printf("class killed (%d)\n", _value); } char value() { return _value; } private { char _value; } } char[] allChars = [ 'a', 'b', 'c', 'e', 'z', 'q', 'x' ]; SomeClass[char] _chars; void _realLoad() { printf("Loading...\n"); foreach(char ch; allChars) { _chars[ch] = new SomeClass(ch); } } void test15() { _realLoad(); int j; for (int i = 0; i < 10000; i++) { foreach(char ch; allChars) { SomeClass obj = _chars[ch]; j += obj.value; } GC.collect(); } printf("j = %d\n", j); assert(j == 7500000); } /************************************************/ void test16() { int[int] aa; Random gen; for (int i = 0; i < 50000; i++) { int key = uniform(0, int.max, gen); int value = uniform(0, int.max, gen); aa[key] = value; } int[] keys = aa.keys; assert(keys.length == aa.length); int j; foreach (k; keys) { assert(k in aa); j += aa[k]; } printf("test16 = %d\n", j); int m; foreach (k, v; aa) { assert(k in aa); assert(aa[k] == v); m += v; } assert(j == m); m = 0; foreach (v; aa) { m += v; } assert(j == m); int[] values = aa.values; assert(values.length == aa.length); foreach(k; keys) { aa.remove(k); } assert(aa.length == 0); for (int i = 0; i < 1000; i++) { int key2 = uniform(0, int.max, gen); int value2 = uniform(0, int.max, gen); aa[key2] = value2; } foreach(k; aa) { if (k < 1000) break; } foreach(k, v; aa) { if (k < 1000) break; } } /************************************************/ void dummy17() { } int bb17[string]; int foo17() { foreach(string s, int i; bb17) { dummy17(); } bb17["a"] = 1; foreach(int b; bb17) { try{ throw new Error("foo"); }catch(Error e){ assert(e); return 0; }catch{ assert(0); } assert(0); } assert(0); } void test17() { int i = foo17(); printf("foo17 = %d\n", i); assert(i == 0); } /************************************************/ void test18() { int[uint] aa; aa[1236448822] = 0; aa[2716102924] = 1; aa[ 315901071] = 2; aa.remove(1236448822); printf("%d\n", aa[2716102924]); assert(aa[2716102924] == 1); } /************************************************/ void test19() { immutable(char[5])[int] aa = ([3:"hello", 4:"betty"]); assert(aa[3] == "hello"); assert(aa[4] == "betty"); auto keys = aa.keys; printf("%d\n", keys[0]); printf("%d\n", keys[1]); auto vs = aa.values; printf("%.*s\n", vs[0].length, vs[0].ptr); printf("%.*s\n", vs[1].length, vs[1].ptr); string aavalue_typeid = typeid(typeof(aa.values)).toString(); printf("%.*s\n", aavalue_typeid.length, aavalue_typeid.ptr); printf("%.*s\n", aa[3].length, aa[3].ptr); printf("%.*s\n", aa[4].length, aa[4].ptr); } /************************************************/ void test20() { string[int] aa = ([3:"hello", 4:"betty"]); assert(aa[3] == "hello"); assert(aa[4] == "betty"); auto keys = aa.keys; printf("%d\n", keys[0]); printf("%d\n", keys[1]); auto values = aa.values; printf("%.*s\n", values[0].length, values[0].ptr); printf("%.*s\n", values[1].length, values[1].ptr); string aavalue_typeid = typeid(typeof(aa.values)).toString(); printf("%.*s\n", aavalue_typeid.length, aavalue_typeid.ptr); printf("%.*s\n", aa[3].length, aa[3].ptr); printf("%.*s\n", aa[4].length, aa[4].ptr); } /************************************************/ void test21() { ushort[20] key = 23; int[ushort[20]] aa; aa[key] = 42; auto x = aa[key]; assert(x == 42); printf("foo\n"); } /************************************************/ void test22() { int[string] stopWords = [ "abc"[]:1 ]; assert("abc"[] in stopWords); } /************************************************/ void test23() { uint[char[]][] fractal; fractal.length = 10; } /************************************************/ void test24() { int[string] x; char[] y; if (y in x) { int z = x[y]; } } /************************************************/ void test25() { string[string] aa; foreach (k,v; aa) { } } /************************************************/ class Tag { string[string] attr; } void foo26(const(Tag) tag_) { foreach(k,v;tag_.attr) { } } void test26() { } /************************************************/ void test27() { int[int] s; s = s.init; } /************************************************/ void test28() { auto a1 = [ 1:10.0, 2:20, 3:15 ]; auto a2 = [ 1:10.0, 2:20, 3:15 ]; assert(a1 !is a2); assert(a1 == a2); a2[7] = 23; assert(a1 != a2); a2.remove(7); assert(a1 == a2); a1.rehash; assert(a1 == a2); a2[2] = 18; assert(a1 != a2); } /************************************************/ void test29() { auto gammaFunc = [-1.5:2.363, -0.5:-3.545, 0.5:1.772]; // write all keys foreach (k; gammaFunc.byKey()) { printf("%f\n", k); } // write all values foreach (v; gammaFunc.byValue()) { printf("%f\n", v); } } /************************************************/ string toString(int value) { char[] result = new char[12]; uint ndigits = 0; do { const c = cast(char) ((value % 10) + '0'); value /= 10; ndigits++; result[$ - ndigits] = c; } while (value); return cast(string) result[$ - ndigits .. $]; } void test30() { int[string] aa; for(int i = 0; i < 100000; i++) { string s = toString(i); aa[s] = i; } } /************************************************/ void test31() { int[int] test; test[0] = 0; test[1] = 1; test[2] = 2; bool flag = false; foreach( k, v; test){ //printf("loop: %d %d\n", k, v); assert(!flag); flag = true; break; } } /************************************************/ void test32() { uint[ushort] aa; aa[1] = 1; aa[2] = 2; aa[3] = 3; aa[4] = 4; aa[5] = 5; foreach(v; aa) { printf("%x\n", v); assert(v >= 1 && v <= 5); } } /************************************************/ template ICE3996(T : V[K], K, V) {} struct Bug3996 {} static assert(!is( ICE3996!(Bug3996) )); /************************************************/ void bug4826c(T)(int[int] value, T x) {} void test4826c() { AssociativeArray!(int, int) z; bug4826c(z,1); } /************************************************/ // 5131 struct ICE5131 { this(int n) {} ICE5131 opAssign(int x) { return this; } } void test5131() { ICE5131[string] a; a["ICE?"] = 1; // call ctor a["ICE?"] = 1; // call opAssign } /************************************************/ // 6178 bool test6178a() { // AA value setting through identity opAssign int assign = 0; struct S { int value = 10; void opAssign(S rhs) { ++assign; assert(value == 10); } } int count = 0; int makeKey() { return ++count; } S[int] aa; assert(aa.length == 0); aa[makeKey()] = S(); assert(assign == 0); assert(aa.length == 1 && 1 in aa); aa[1] = S(); assert(assign == 1); assert(aa.length == 1 && 1 in aa); return true; } bool test6178b() { // AA value setting through implicit ctor call + non-identity opAssign int ctor = 0; int assign = 0; struct S { int value = 10; @disable this(); this(int n) { ++ctor; assert(value == 10); value = 20; } void opAssign(int rhs) { ++assign; assert(value == 20); assert(rhs == 30); value = rhs; } } int count = 0; int makeKey() { return ++count; } S[int] aa; assert(aa.length == 0); aa[makeKey()] = 20; assert(assign == 0 && ctor == 1 && count == 1); assert(aa.length == 1 && (1 in aa)); aa[1] = 30; assert(assign == 1 && ctor == 1); assert(aa.length == 1 && 1 in aa); return true; } bool test6178c() { // AA value setting through non-identity opAssign struct S { //this(int) {} // not possible to perform implicit ctor call void opAssign(int) {} } S[int] aa; assert(aa.length == 0); if (!__ctfe) { // currently CTFE does not support throwing RangeError import core.exception : RangeError; try { aa[1] = 1; assert(0); } catch (RangeError) {} // The above line is exactly same as: try { aa[1].opAssign(1); assert(0); } catch (RangeError) {} } assert(aa.length == 0); aa[1] = S(); aa[1] = 1; assert(aa.length == 1); return true; } bool test6178d() { // AA value setting through implicit ctor call + alias this int ctor; struct S { this(int n) { ++ctor; value = n; } int value; alias value this; } S[int] aa; assert(ctor == 0); assert(aa.length == 0); aa[1] = 0; // implicit ctor call + blit assign assert(aa[1].value == 0 && ctor == 1); assert(aa.length == 1); aa[1] = 1; // set through alias this assert(aa[1].value == 1 && ctor == 1); assert(aa.length == 1); return true; } bool test6178e() { // AA value setting through alias this struct S { int value; alias value this; } S[int] aa; assert(aa.length == 0); if (!__ctfe) { // currently CTFE does not support throwing RangeError import core.exception : RangeError; try { aa[1] = 1; assert(0); } catch (RangeError) {} // The above line is exactly same as: try { aa[1].value = 1; assert(0); } catch (RangeError) {} } assert(aa.length == 0); aa[1] = S(0); // construct + blit assign assert(aa[1].value == 0 && aa.length == 1); aa[1] = 1; // set through alias this assert(aa[1].value == 1 && aa.length == 1); return true; } void test6178() { static assert(test6178a()); // ctfe check test6178a(); // runtime test static assert(test6178b()); test6178b(); static assert(test6178c()); test6178c(); static assert(test6178d()); test6178d(); static assert(test6178e()); test6178e(); } void test6178x() { return; // depends on AA implementation static int ctor, cpctor, dtor; static struct S { this(int) { ++ctor; printf("ctor\n"); } this(this) { ++cpctor; printf("cpctor\n"); } ~this() { ++dtor; printf("dtor\n"); } } static struct X { this(int) {} void opAssign(int) {} } X[S] aa1; S[int] aa2; { auto value = S(1); assert(ctor==1 && cpctor==0 && dtor==0); ref getRef(ref S s = value) { return s; } auto getVal() { return value; } aa1[value] = 10; assert(ctor==1 && cpctor==1 && dtor==0); //call copy ctor when we putting 'value' to aa1 aa1[getRef()] = 20; assert(ctor==1 && cpctor==1 && dtor==0); //copy ctor wasn't called because we didn't create a new entry in aa, using an existing key aa1[getVal()] = 20; assert(ctor==1 && cpctor==2 && dtor==1); //call copy ctor and dtor, because we pass key by value aa2[1] = value; assert(ctor==1 && cpctor==3 && dtor==1); //call copy ctor when we putting `value` to aa2[1] aa2[2] = getRef(); assert(ctor==1 && cpctor==4 && dtor==1); //call copy ctor when we putting `value` to aa2[2] } assert(ctor==1 && cpctor==4 && dtor==2); //We've got 3 "S" instances that aren't destroyed yet: the key in aa1, aa2[1], aa2[2]. assert(ctor + cpctor - aa2.length - aa1.length == dtor); } /************************************************/ // 10595 struct S10595 { bool b = true; bool test() { if (!b) // note: must be a check, not 'return b;' return false; return true; } } struct Wrap10595 { int i; alias i this; S10595 s; } void test10595() { { Wrap10595[int] wrap; wrap[0] = Wrap10595(); wrap[0].i = 0; assert(wrap[0].s.test()); // ok } { Wrap10595[int] wrap; wrap[0] = Wrap10595(); wrap[0] = 0; // note: using 'alias this' to assign assert(wrap[0].s.test()); // failure } } /************************************************/ // 10970 struct RefCounted10970(T) //if (!is(T == class)) { struct RefCountedStore { } RefCountedStore _refCounted; this(this) {} ~this() {} } struct Array10970(T) if (!is(T : const(bool))) { struct Payload { } RefCounted10970!Payload _data; } class C10970 { this(string name) { m[name] = Arr(); } alias Array10970!C10970 Arr; Arr[string] m; } void test10970() { C10970 c = new C10970("test"); } /************************************************/ // 6433 void test6433() { int[int] aa; static assert(aa.sizeof != 0); static assert(aa.alignof != 0); static assert(is(typeof(aa.init) == int[int])); static assert(typeof(aa).mangleof == "Hii"); static assert(typeof(aa).stringof == "int[int]"); static struct AA { int[int] aa; } static assert(AA.aa.offsetof == 0); aa = aa.init; aa[0] = 1; assert(aa.length == 1 && aa[0] == 1); } /************************************************/ // 6612 void test6612() { auto aa1 = [1: 2]; // OK auto aa2 = [4: 5]; // OK int[int[int]] aa3 = [aa1:3, aa2:6]; // OK int[int[int]] aa4 = [[1:2]:3, [4:5]:6]; // error int[int[string]] aa5 = [["a":1]:2, ["b":3]:4]; } /************************************************/ // 7365 struct TickDuration { bool opEquals(ref const TickDuration rhs) const { return true; } } void test7365() { TickDuration[Object] aa; aa.keys; } /************************************************/ enum aa5520 = [5 : "hello"]; void test5520() { auto a = aa5520.values; } /************************************************/ enum size_t N6655 = 1; int[bar6655.length] foo6655; int[N6655] bar6655; /************************************************/ struct ChunkLoc {} ChunkLoc Get() { return ChunkLoc(); } void test6799() { int[ChunkLoc] aa; aa.remove(Get()); } /************************************************/ // 11359 void test11359() { class Bar {} static Bar[string] aa; static ref fun() { return aa; } string key = "test"; fun[key] = new Bar; assert(aa.length == 1); Bar bar = fun[key]; } /************************************************/ // 11730 struct SysTime11730 { ref SysTime11730 opAssign(SysTime11730 rhs) { assert(0); } } struct Nullable11730(T) { T _value; void opAssign()(T value) { assert(0); } @property ref inout(T) get() inout { assert(0); } alias get this; } void test11730() { Nullable11730!SysTime11730[string] map; map["foo"] = Nullable11730!SysTime11730(); } /************************************************/ // 14089 struct S14089 { int num; S14089 opAssign(S14089 val) { return this; } } void test14089() { S14089[int] aa; S14089 b = aa[1] = S14089(0); assert(aa[1].num == 0); assert(b.num == 0); } /************************************************/ // 14144 struct JSON14144 { union { double _floating; } this(typeof(null)) { } @trusted pure nothrow typeof(null) opAssign(typeof(null) nothing) { return null; } } void test14144() { JSON14144[string] x; x["wat"] = null; assert(x.length == 1); assert("wat" in x); } /************************************************/ // 14321 void test14321() { struct Foo { static char[8] buf; static char[] op; this(int id) { buf[op.length] = 'c'; op = buf[0..op.length + 1]; } this(this) { buf[op.length] = 'p'; op = buf[0..op.length + 1]; } ~this() { buf[op.length] = 'd'; op = buf[0..op.length + 1]; } } Foo[string] foos; assert(Foo.op == ""); foos["test"] = Foo(42); // initialization assert(Foo.op == "c"); foos["test"] = Foo(42); // assignment assert(Foo.op == "ccd"); struct Bar { static char[8] buf; static char[] op; int id; //this(int id) { op ~= "c"; } this(this) { buf[op.length] = 'p'; op = buf[0..op.length + 1]; } ~this() { buf[op.length] = 'd'; op = buf[0..op.length + 1]; } } Bar[string] bars; assert(Bar.op == ""); bars["test"] = Bar(42); // initialization assert(Bar.op == ""); bars["test"] = Bar(42); // assignment assert(Bar.op == "d"); } /************************************************/ int main() { printf("before test 1\n"); test1(); printf("before test 2\n"); test2(); printf("before test 4\n"); test4(); printf("before test 5\n"); test5(); printf("before test 6\n"); test6(); printf("before test 7\n"); test7(); printf("before test 8\n"); test8(); printf("before test 9\n"); test9(); printf("before test 10\n"); test10(); printf("before test 11\n"); test11(); printf("before test 12\n"); test12(); printf("before test 13\n"); test13(); printf("before test 14\n"); test14(); printf("before test 15\n"); test15(); printf("before test 16\n"); test16(); printf("before test 17\n"); test17(); printf("before test 18\n"); test18(); printf("before test 19\n"); test19(); printf("before test 20\n"); test20(); printf("before test 21\n"); test21(); printf("before test 22\n"); test22(); printf("before test 23\n"); test23(); printf("before test 24\n"); test24(); printf("before test 25\n"); test25(); printf("before test 26\n"); test26(); printf("before test 27\n"); test27(); printf("before test 28\n"); test28(); printf("before test 29\n"); test29(); printf("before test 30\n"); test30(); printf("before test 31\n"); test31(); printf("before test 32\n"); test32(); test4826c(); test5131(); test6178(); test6178x(); test10595(); test10970(); test6433(); test6612(); test7365(); test5520(); test6799(); test11359(); test11730(); test14089(); test14321(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testtypeid.d0000664000175000017500000003223212776215022022551 0ustar kaikai import core.vararg; import std.stdio; /******************************************************/ void test2() { assert(typeid(int) == typeid(int)); assert(typeid(int) != typeid(uint)); } /******************************************************/ class FOO3 { } FOO3 foox3; void foo3(int x, ...) { printf("%d arguments\n", _arguments.length); for (int i = 0; i < _arguments.length; i++) { writeln(_arguments[i].toString()); if (_arguments[i] is typeid(int)) { int j = va_arg!int(_argptr); printf("\t%d\n", j); assert(j == 2); } else if (_arguments[i] == typeid(long)) { long j = va_arg!long(_argptr); printf("\t%lld\n", j); assert(j == 3); } else if (_arguments[i] is typeid(double)) { double d = va_arg!double(_argptr); printf("\t%g\n", d); assert(d == 4.5); } else if (_arguments[i] is typeid(FOO3)) { FOO3 f = va_arg!FOO3(_argptr); printf("\t%p\n", f); assert(f is foox3); } else assert(0); } } void test3() { FOO3 f = new FOO3(); printf("\t%p\n", f); foox3 = f; foo3(1,2,3L,4.5,f); foo3(1,2,3L,4.5,f); } /******************************************************/ void test4() { TypeInfo ti; ti = typeid(float[]); assert(!(ti is null)); ti = typeid(double[]); assert(!(ti is null)); ti = typeid(real[]); assert(!(ti is null)); ti = typeid(ifloat[]); assert(!(ti is null)); ti = typeid(idouble[]); assert(!(ti is null)); ti = typeid(ireal[]); assert(!(ti is null)); ti = typeid(cfloat[]); assert(!(ti is null)); ti = typeid(cdouble[]); assert(!(ti is null)); ti = typeid(creal[]); assert(!(ti is null)); ti = typeid(void); assert(!(ti is null)); ti = typeid(void[]); assert(!(ti is null)); ti = typeid(bool[]); assert(!(ti is null)); } /******************************************************/ void test6() { TypeInfo ti = typeid(void*); assert(!(ti is null)); assert(ti.tsize==(void*).sizeof); assert(ti.toString()=="void*"); } /******************************************************/ void test7() { TypeInfo ti = typeid(bool*); assert(!(ti is null)); assert(ti.tsize==(bool*).sizeof); assert(ti.toString()=="bool*"); } /******************************************************/ void test8() { TypeInfo ti = typeid(byte*); assert(!(ti is null)); assert(ti.tsize==(byte*).sizeof); assert(ti.toString()=="byte*"); } /******************************************************/ void test9() { TypeInfo ti = typeid(byte[]); assert(!(ti is null)); assert(ti.tsize==(byte[]).sizeof); assert(ti.toString()=="byte[]"); } /******************************************************/ void test10() { TypeInfo ti = typeid(short*); assert(!(ti is null)); assert(ti.tsize==(short*).sizeof); assert(ti.toString()=="short*"); } /******************************************************/ void test11() { TypeInfo ti = typeid(ushort*); assert(!(ti is null)); assert(ti.tsize==(ushort*).sizeof); assert(ti.toString()=="ushort*"); } /******************************************************/ void test12() { TypeInfo ti = typeid(int*); assert(!(ti is null)); assert(ti.tsize==(int*).sizeof); assert(ti.toString()=="int*"); } /******************************************************/ void test13() { TypeInfo ti = typeid(uint*); assert(!(ti is null)); assert(ti.tsize==(uint*).sizeof); assert(ti.toString()=="uint*"); } /******************************************************/ void test14() { TypeInfo ti = typeid(ulong*); assert(!(ti is null)); assert(ti.tsize==(ulong*).sizeof); assert(ti.toString()=="ulong*"); } /******************************************************/ void test15() { TypeInfo ti = typeid(long*); assert(!(ti is null)); assert(ti.tsize==(long*).sizeof); assert(ti.toString()=="long*"); } /******************************************************/ void test16() { TypeInfo ti = typeid(float*); assert(!(ti is null)); assert(ti.tsize==(float*).sizeof); assert(ti.toString()=="float*"); } /******************************************************/ void test17() { TypeInfo ti = typeid(ifloat*); assert(!(ti is null)); assert(ti.tsize==(ifloat*).sizeof); assert(ti.toString()=="ifloat*"); } /******************************************************/ void test18() { TypeInfo ti = typeid(cfloat*); assert(!(ti is null)); assert(ti.tsize==(cfloat*).sizeof); assert(ti.toString()=="cfloat*"); } /******************************************************/ void test19() { TypeInfo ti = typeid(double*); assert(!(ti is null)); assert(ti.tsize==(double*).sizeof); assert(ti.toString()=="double*"); } /******************************************************/ void test20() { TypeInfo ti = typeid(idouble*); assert(!(ti is null)); assert(ti.tsize==(idouble*).sizeof); assert(ti.toString()=="idouble*"); } /******************************************************/ void test21() { TypeInfo ti = typeid(cdouble*); assert(!(ti is null)); assert(ti.tsize==(cdouble*).sizeof); assert(ti.toString()=="cdouble*"); } /******************************************************/ void test22() { TypeInfo ti = typeid(real*); assert(!(ti is null)); assert(ti.tsize==(real*).sizeof); assert(ti.toString()=="real*"); } /******************************************************/ void test23() { TypeInfo ti = typeid(ireal*); assert(!(ti is null)); assert(ti.tsize==(ireal*).sizeof); assert(ti.toString()=="ireal*"); } /******************************************************/ void test24() { TypeInfo ti = typeid(creal*); assert(!(ti is null)); assert(ti.tsize==(creal*).sizeof); assert(ti.toString()=="creal*"); } /******************************************************/ void test25() { TypeInfo ti = typeid(char*); assert(!(ti is null)); assert(ti.tsize==(char*).sizeof); assert(ti.toString()=="char*"); } /******************************************************/ void test26() { TypeInfo ti = typeid(wchar*); assert(!(ti is null)); assert(ti.tsize==(wchar*).sizeof); assert(ti.toString()=="wchar*"); } /******************************************************/ void test27() { TypeInfo ti = typeid(dchar*); assert(!(ti is null)); assert(ti.tsize==(dchar*).sizeof); assert(ti.toString()=="dchar*"); } /******************************************************/ enum MyEnum { A, B } void test28() { TypeInfo ti = typeid(MyEnum); assert(!(ti is null)); assert(ti.tsize==(MyEnum).sizeof); assert(ti.toString()=="testtypeid.MyEnum"); } /******************************************************/ void test29() { alias void function() func; TypeInfo ti = typeid(func); assert(ti !is null); assert(ti.tsize == func.sizeof); } /******************************************************/ void test30() { alias int delegate() del; TypeInfo ti = typeid(del); assert(ti !is null); assert(ti.tsize == del.sizeof); } /******************************************************/ void test31() { TypeInfo ti = typeid(void); assert(!(ti is null)); assert(ti.tsize == void.sizeof); assert(ti.toString()=="void"); } /******************************************************/ class Foo32 { int x = 3; } class Bar32 { long y = 4; } void printargs(int x, ...) { printf("%d arguments\n", _arguments.length); for (int i = 0; i < _arguments.length; i++) { writeln(_arguments[i].toString()); if (_arguments[i] == typeid(int)) { int j = va_arg!int(_argptr); printf("\t%d\n", j); } else if (_arguments[i] == typeid(long)) { long j = va_arg!long(_argptr); printf("\t%lld\n", j); } else if (_arguments[i] == typeid(double)) { double d = va_arg!double(_argptr); printf("\t%g\n", d); } else if (_arguments[i] == typeid(Foo32)) { Foo32 f = va_arg!Foo32(_argptr); assert(f.x == 3); printf("\t%p\n", f); } else if (_arguments[i] == typeid(Bar32)) { Bar32 b = va_arg!Bar32(_argptr); assert(b.y == 4); printf("\t%p\n", b); } else assert(0); } } void test32() { Foo32 f = new Foo32(); Bar32 b = new Bar32(); printf("%p\n", f); printargs(1, 2, 3L, 4.5, f, b); } /******************************************************/ void test33() { } /******************************************************/ void test34() { class C { } C c; auto a = typeid(C).info; } /******************************************************/ void test35() { auto ti = typeid(shared(int)); auto sti = cast(TypeInfo_Shared)ti; assert(sti); // allow both next and base as field names in TypeInfo_Const static if (is(typeof(&sti.base) == TypeInfo*)) assert(sti.base == typeid(int)); else assert(sti.next == typeid(int)); } /******************************************************/ void test36() { int i; assert(typeid(i++) == typeid(int)); assert(i == 1); assert(typeid(i + 1) == typeid(int)); } /******************************************************/ class A37 {} class B37 : A37 {} void test37() { auto a = new B37; //writeln(typeid(A)); assert(typeid(a) == typeid(B37)); } /******************************************************/ void test38() { static if (is(cent)) { TypeInfo ti = typeid(cent*); assert(!(ti is null)); assert(ti.tsize==(cent*).sizeof); assert(ti.toString()=="cent*"); } } /******************************************************/ void test39() { static if (is(ucent)) { TypeInfo ti = typeid(ucent*); assert(!(ti is null)); assert(ti.tsize==(ucent*).sizeof); assert(ti.toString()=="ucent*"); } } /******************************************************/ void test40() { static if (is(cent)) { cent i; assert(typeid(i++) == typeid(cent)); assert(i == 1); assert(typeid(i + 1) == typeid(cent)); } } /******************************************************/ // 9442 class C { this() { c = this; auto x = typeid(c); // NG auto y = typeid(this.c); // ok } C c; } void test9442() { auto c = new C(); } /******************************************************/ // 10451 struct Foo10451; struct Bar10451 { Foo10451*[] foos; } void test10451() { Foo10451*[] foos = []; foos ~= null; foos = new Foo10451*[2]; } /******************************************************/ // 11010 struct S11010 { S11010* p; } class C11010 { C11010 p; } class D11010 : C11010 {} void test11010() { TypeInfo ti; S11010 s; ti = typeid(s.p); assert(cast(TypeInfo_Pointer)ti !is null); assert(ti.toString() == "testtypeid.S11010*"); C11010 c = new C11010(); c.p = new D11010(); ti = typeid(c.p); assert(cast(TypeInfo_Class)ti !is null); assert(ti.toString() == "testtypeid.D11010"); } /******************************************************/ // 13045 void test13045a() { static struct S { int[] a; } auto s1 = S([1,2]); auto s2 = S([1,2]); assert(s1 !is s2); assert(s1 == s2); assert(typeid(S).getHash(&s1) == typeid(S).getHash(&s2)); // should succeed } void test13045b() { bool thrown(T)(lazy T cond) { import core.exception; try cond(); catch (Error e) return true; return false; } struct S { size_t toHash() const nothrow @safe { // all getHash call should reach here throw new Error(""); } } struct T { S s; } S s; assert(thrown(typeid(S).getHash(&s))); // OK S[1] ssa; assert(thrown(typeid(S[1]).getHash(&ssa))); // OK S[] sda = [S(), S()]; assert(thrown(typeid(S[]).getHash(&sda))); // OK T t; assert(thrown(typeid(T).getHash(&t))); // OK <- NG T[1] tsa; assert(thrown(typeid(T[1]).getHash(&tsa))); // OK <- NG T[] tda = [T(), T()]; assert(thrown(typeid(T[]).getHash(&tda))); // OK <- NG } /******************************************************/ int main() { test2(); test3(); test4(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test9442(); test10451(); test11010(); test13045a(); test13045b(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_513.d0000664000175000017500000000045512776215022023051 0ustar kaikaitemplate t9578(alias f) { void tf()() { f(); } } void g9578a(alias f)() { f(); } // Error -> OK void g9578b(alias ti)() { ti.tf(); } // Error -> OK void test9578() { int i = 0; int m() { return i; } g9578a!(t9578!m.tf)(); g9578b!(t9578!m)(); } void main() { test9578(); }ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/wc.d0000664000175000017500000000154012776215022020762 0ustar kaikai// PERMUTE_ARGS: // EXECUTE_ARGS: runnable/wc.d import std.file; extern(C) int printf(const char*, ...); int main (string[] args) { int w_total; int l_total; int c_total; printf (" lines words bytes file\n"); foreach (arg; args[1 .. args.length]) { string input; int w_cnt, l_cnt, c_cnt; int inword; input = cast(string)std.file.read(arg); foreach (char c; input) { if (c == '\n') ++l_cnt; if (c != ' ') { if (!inword) { inword = 1; ++w_cnt; } } else inword = 0; ++c_cnt; } printf ("%8lu%8lu%8lu %.*s\n", l_cnt, w_cnt, c_cnt, arg.length, arg.ptr); l_total += l_cnt; w_total += w_cnt; c_total += c_cnt; } if (args.length > 2) { printf ("--------------------------------------\n%8lu%8lu%8lu total", l_total, w_total, c_total); } return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test10942.d0000664000175000017500000000060612776215022021732 0ustar kaikai// REQUIRED_ARGS: -g import std.string; string getEnum(size_t count) { string en; en ~= "enum KeyCode\n { \n"; foreach (i; 0 .. count) { en ~= format(" memb_%s = %s,\n", i+1, i+1); } en ~= "} "; return en; } // Linker warning: Warning 161: Unknown CV version, ignored // mixin(getEnum(1024)); // ICE mixin(getEnum(1087)); void main() { } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test7595.d0000664000175000017500000000061512776215022021664 0ustar kaikai// EXTRA_SOURCES: imports/a7595.d template isSafe(alias func) { @safe void dummySafeFunc() { func(); } enum isSafe = is(typeof(dummySafeFunc())); } template areAllSafe(funcs...) { enum areAllSafe = isSafe!(funcs[0]); } @safe benchmark(fun...)(uint n) if (areAllSafe!fun) { foreach(i, unused; fun) { foreach (j; 0 .. n) fun[i](); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test6423.d0000664000175000017500000000041112776215022021643 0ustar kaikai// DISABLED: osx64 bool flag; void f() { } void main() { if (!flag) { flag = true; caller(); } return f(); } alias maintype = extern(C) int function(); void caller() { auto fp = cast(maintype)&main; assert(fp() == 0); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testcontracts.d0000664000175000017500000006054612776215022023264 0ustar kaikai// PERMUTE_ARGS: -inline -g -O extern(C) int printf(const char*, ...); /*******************************************/ class A { int x = 7; int foo(int i) in { printf("A.foo.in %d\n", i); assert(i == 2); assert(x == 7); printf("A.foo.in pass\n"); } out (result) { assert(result & 1); assert(x == 7); } body { return i; } } class B : A { override int foo(int i) in { float f; printf("B.foo.in %d\n", i); assert(i == 4); assert(x == 7); f = f + i; } out (result) { assert(result < 8); assert(x == 7); } body { return i - 1; } } void test1() { auto b = new B(); b.foo(2); b.foo(4); } /*******************************************/ class A2 { int x = 7; int foo(int i) in { printf("A2.foo.in %d\n", i); assert(i == 2); assert(x == 7); printf("A2.foo.in pass\n"); } out (result) { assert(result & 1); assert(x == 7); } body { return i; } } class B2 : A2 { override int foo(int i) in { float f; printf("B2.foo.in %d\n", i); assert(i == 4); assert(x == 7); f = f + i; } out (result) { assert(result < 8); assert(x == 7); } body { return i - 1; } } class C : B2 { override int foo(int i) in { float f; printf("C.foo.in %d\n", i); assert(i == 6); assert(x == 7); f = f + i; } out (result) { assert(result == 1 || result == 3 || result == 5); assert(x == 7); } body { return i - 1; } } void test2() { auto c = new C(); c.foo(2); c.foo(4); c.foo(6); } /*******************************************/ void fun(int x) in { if (x < 0) throw new Exception("a"); } body { } void test3() { fun(1); } /*******************************************/ interface Stack { int pop() // in { printf("pop.in\n"); } out(result) { printf("pop.out\n"); assert(result == 3); } } class CC : Stack { int pop() //out (result) { printf("CC.pop.out\n"); } body { printf("CC.pop.in\n"); return 3; } } void test4() { auto cc = new CC(); cc.pop(); } /*******************************************/ int mul100(int n) out(result) { assert(result == 500); } body { return n * 100; } void test5() { mul100(5); } /*******************************************/ // 3273 // original case struct Bug3273 { ~this() {} invariant() {} } // simplest case ref int func3273() out(r) { // Regression check of issue 3390 static assert(!__traits(compiles, r = 1)); } body { static int dummy; return dummy; } void test6() { func3273() = 1; assert(func3273() == 1); } /*******************************************/ /+ // http://d.puremagic.com/issues/show_bug.cgi?id=3722 class Bug3722A { void fun() {} } class Bug3722B : Bug3722A { override void fun() in { assert(false); } body {} } void test6() { auto x = new Bug3722B(); x.fun(); } +/ /*******************************************/ auto test7foo() in{ ++cnt; }body{ ++cnt; return "str"; } void test7() { cnt = 0; assert(test7foo() == "str"); assert(cnt == 2); } /*******************************************/ auto foo8() out(r){ ++cnt; assert(r == 10); }body{ ++cnt; return 10; } auto bar8() out{ ++cnt; }body{ ++cnt; } void test8() { cnt = 0; assert(foo8() == 10); assert(cnt == 2); cnt = 0; bar8(); assert(cnt == 2); } /*******************************************/ // from fail317 void test9() { auto f1 = function() body { }; // fine auto f2 = function() in { } body { }; // fine auto f3 = function() out { } body { }; // error auto f4 = function() in { } out { } body { }; // error auto d1 = delegate() body { }; // fine auto d2 = delegate() in { } body { }; // fine auto d3 = delegate() out { } body { }; // error auto d4 = delegate() in { } out { } body { }; // error } /*******************************************/ // 4785 int cnt; auto foo4785() in{ int r; ++cnt; } out(r){ assert(r == 10); ++cnt; }body{ ++cnt; int r = 10; return r; } void test4785() { cnt = 0; assert(foo4785() == 10); assert(cnt == 3); } /*******************************************/ // 5039 class C5039 { int x; invariant() { assert( x < int.max ); } auto foo() { return x; } } /*******************************************/ // 5204 interface IFoo5204 { IFoo5204 bar() out {} } class Foo5204 : IFoo5204 { Foo5204 bar() { return null; } } /*******************************************/ // 6417 class Bug6417 { void bar() in { int i = 14; assert(i == 14); auto dg = (){ //printf("in: i = %d\n", i); assert(i == 14, "in contract failure"); }; dg(); } out { int j = 10; assert(j == 10); auto dg = (){ //printf("out: j = %d\n", j); assert(j == 10, "out contract failure"); }; dg(); } body {} } void test6417() { (new Bug6417).bar(); } /*******************************************/ // 7218 void test7218() { size_t foo() in{} out{} body{ return 0; } // OK size_t bar() in{}/*out{}*/body{ return 0; } // OK size_t hoo()/*in{}*/out{} body{ return 0; } // NG1 size_t baz()/*in{} out{}*/body{ return 0; } // NG2 } /*******************************************/ // 7517 void test7517() { static string result; interface I { static I self; void setEnable() in { assert(self is this); result ~= "I.setEnable.in/"; assert(!enabled); } out { assert(self is this); result ~= "I.setEnable.out/"; assert( enabled); } void setDisable() in { assert(self is this); result ~= "I.setDisable.in/"; assert( enabled); } out { assert(self is this); result ~= "I.setDisable.out/"; assert(!enabled); } @property bool enabled() const; } class C : I { static C self; void setEnable() in {} // supply in-contract to invoke I.setEnable.in body { assert(self is this); result ~= "C.setEnable/"; _enabled = true; } void setDisable() { assert(self is this); result ~= "C.setDisable/"; _enabled = false; } @property bool enabled() const { assert(self is this); result ~= "C.enabled/"; return _enabled; } bool _enabled; } C c = C.self = new C; I i = I.self = c; result = null; i.setEnable(); assert(result == "I.setEnable.in/C.enabled/C.setEnable/I.setEnable.out/C.enabled/"); result = null; i.setDisable(); assert(result == "C.setDisable/I.setDisable.out/C.enabled/"); } /*******************************************/ // 7699 class P7699 { void f(int n) in { assert (n); } body { } } class D7699 : P7699 { override void f(int n) in { } body { } } /*******************************************/ // 7883 // Segmentation fault class AA7883 { int foo() out (r1) { } body { return 1; } } class BA7883 : AA7883 { override int foo() out (r2) { } body { return 1; } } class CA7883 : BA7883 { override int foo() body { return 1; } } // Error: undefined identifier r2, did you mean variable r3? class AB7883 { int foo() out (r1) { } body { return 1; } } class BB7883 : AB7883 { override int foo() out (r2) { } body { return 1; } } class CB7883 : BB7883 { override int foo() out (r3) { } body { return 1; } } // Error: undefined identifier r3, did you mean variable r4? class AC7883 { int foo() out (r1) { } body { return 1; } } class BC7883 : AC7883 { override int foo() out (r2) { } body { return 1; } } class CC7883 : BC7883 { override int foo() out (r3) { } body { return 1; } } class DC7883 : CC7883 { override int foo() out (r4) { } body { return 1; } } /*******************************************/ // 7892 struct S7892 { @disable this(); this(int x) {} } S7892 f7892() out (result) {} // case 1 body { return S7892(1); } interface I7892 { S7892 f(); } class C7892 { invariant() {} // case 2 S7892 f() { return S7892(1); } } /*******************************************/ // 8066 struct CLCommandQueue { invariant() {} //private: int enqueueNativeKernel() { assert(0, "implement me"); } } /*******************************************/ // 8073 struct Container8073 { int opApply (int delegate(ref int) dg) { return 0; } } class Bug8073 { static int test; int foo() out(r) { test = 7; } body { Container8073 ww; foreach( xxx ; ww ) { } return 7; } ref int bar() out { } body { Container8073 ww; foreach( xxx ; ww ) { } test = 7; return test; } } void test8073() { auto c = new Bug8073(); assert(c.foo() == 7); assert(c.test == 7); auto p = &c.bar(); assert(p == &c.test); assert(*p == 7); } /*******************************************/ // 8093 void test8093() { static int g = 10; static int* p; enum fbody = q{ static struct S { int opApply(scope int delegate(ref int) dg) { return dg(g); } } S s; foreach (ref e; s) return g; assert(0); }; ref int foo_ref1() out(r) { assert(&r is &g && r == 10); } body { mixin(fbody); } ref int foo_ref2() body { mixin(fbody); } { auto q = &foo_ref1(); assert(q is &g && *q == 10); } { auto q = &foo_ref2(); assert(q is &g && *q == 10); } int foo_val1() out(r) { assert(&r !is &g && r == 10); } body { mixin(fbody); } int foo_val2() body { mixin(fbody); } { auto n = foo_val1(); assert(&n !is &g && n == 10); } { auto n = foo_val2(); assert(&n !is &g && n == 10); } } /*******************************************/ // 9383 class A9383 { static void delegate() dg; static int val; void failInBase() { assert(typeid(this) is typeid(A9383)); } // in-contract tests void foo1(int i) in { A9383.val = i; failInBase; } body { } // no closure void foo2(int i) in { A9383.val = i; failInBase; } body { int x; dg = { ++x; }; } // closure [local] void foo3(int i) in { A9383.val = i; failInBase; } body { dg = { ++i; }; } // closure [parameter] void foo4(int i) in { A9383.val = i; failInBase; } body { } // no closure void foo5(int i) in { A9383.val = i; failInBase; } body { } // no closure void foo6(int i) in { A9383.val = i; failInBase; } body { int x; dg = { ++x; }; } // closure [local] void foo7(int i) in { A9383.val = i; failInBase; } body { dg = { ++i; }; } // closure [parameter] // out-contract tests void bar1(int i) out { A9383.val = i; } body { } // no closure void bar2(int i) out { A9383.val = i; } body { int x; dg = { ++x; }; } // closure [local] void bar3(int i) out { A9383.val = i; } body { dg = { ++i; }; } // closure [parameter] void bar4(int i) out { A9383.val = i; } body { } // no closure void bar5(int i) out { A9383.val = i; } body { } // no closure void bar6(int i) out { A9383.val = i; } body { int x; dg = { ++x; }; } // closure [local] void bar7(int i) out { A9383.val = i; } body { dg = { ++i; }; } // closure [parameter] } class B9383 : A9383 { static int val; // in-contract tests override void foo1(int i) in { B9383.val = i; } body { } // -> no closure override void foo2(int i) in { B9383.val = i; } body { int x; dg = { ++x; }; } // -> closure [local] appears override void foo3(int i) in { B9383.val = i; } body { dg = { ++i; }; } // -> closure [parameter] override void foo4(int i) in { B9383.val = i; } body { int x; dg = { ++x; }; } // -> closure [local] appears override void foo5(int i) in { B9383.val = i; } body { dg = { ++i; }; } // -> closure [parameter] appears override void foo6(int i) in { B9383.val = i; } body { } // -> closure [local] disappears override void foo7(int i) in { B9383.val = i; } body { } // -> closure [parameter] disappears // out-contract tests override void bar1(int i) out { B9383.val = i; } body { } // -> no closure override void bar2(int i) out { B9383.val = i; } body { int x; dg = { ++x; }; } // -> closure [local] appears override void bar3(int i) out { B9383.val = i; } body { dg = { ++i; }; } // -> closure [parameter] override void bar4(int i) out { B9383.val = i; } body { int x; dg = { ++x; }; } // -> closure [local] appears override void bar5(int i) out { B9383.val = i; } body { dg = { ++i; }; } // -> closure [parameter] appears override void bar6(int i) out { B9383.val = i; } body { } // -> closure [local] disappears override void bar7(int i) out { B9383.val = i; } body { } // -> closure [parameter] disappears } void test9383() { auto a = new A9383(); auto b = new B9383(); // base class in-contract is used from derived class. // base derived b.foo1(101); assert(A9383.val == 101 && B9383.val == 101); // no closure -> no closure b.foo2(102); assert(A9383.val == 102 && B9383.val == 102); // closure [local] -> closure [local] appears b.foo3(103); assert(A9383.val == 103 && B9383.val == 103); // closure [parameter] -> closure [parameter] b.foo4(104); assert(A9383.val == 104 && B9383.val == 104); // no closure -> closure [local] appears b.foo5(105); assert(A9383.val == 105 && B9383.val == 105); // no closure -> closure [parameter] appears b.foo6(106); assert(A9383.val == 106 && B9383.val == 106); // closure [local] -> closure [local] disappears b.foo7(107); assert(A9383.val == 107 && B9383.val == 107); // closure [parameter] -> closure [parameter] disappears // base class out-contract is used from derived class. // base derived b.bar1(101); assert(A9383.val == 101 && B9383.val == 101); // no closure -> no closure b.bar2(102); assert(A9383.val == 102 && B9383.val == 102); // closure [local] -> closure [local] appears b.bar3(103); assert(A9383.val == 103 && B9383.val == 103); // closure [parameter] -> closure [parameter] b.bar4(104); assert(A9383.val == 104 && B9383.val == 104); // no closure -> closure [local] appears b.bar5(105); assert(A9383.val == 105 && B9383.val == 105); // no closure -> closure [parameter] appears b.bar6(106); assert(A9383.val == 106 && B9383.val == 106); // closure [local] -> closure [local] disappears b.bar7(107); assert(A9383.val == 107 && B9383.val == 107); // closure [parameter] -> closure [parameter] disappears // in-contract in base class. a.foo1(101); assert(A9383.val == 101); // no closure a.foo2(102); assert(A9383.val == 102); // closure [local] a.foo3(103); assert(A9383.val == 103); // closure [parameter] // out-contract in base class. a.bar1(101); assert(A9383.val == 101); // no closure a.bar2(102); assert(A9383.val == 102); // closure [local] a.bar3(103); assert(A9383.val == 103); // closure [parameter] } /*******************************************/ // 15524 - Different from issue 9383 cases, closed variable size is bigger than REGSIZE. class A15524 { static void delegate() dg; static string val; void failInBase() { assert(typeid(this) is typeid(A15524)); } // in-contract tests void foo1(string s) in { A15524.val = s; failInBase; } body { } // no closure void foo2(string s) in { A15524.val = s; failInBase; } body { string x; dg = { x = null; }; } // closure [local] void foo3(string s) in { A15524.val = s; failInBase; } body { dg = { s = null; }; } // closure [parameter] void foo4(string s) in { A15524.val = s; failInBase; } body { } // no closure void foo5(string s) in { A15524.val = s; failInBase; } body { } // no closure void foo6(string s) in { A15524.val = s; failInBase; } body { string x; dg = { x = null; }; } // closure [local] void foo7(string s) in { A15524.val = s; failInBase; } body { dg = { s = null; }; } // closure [parameter] // out-contract tests void bar1(string s) out { A15524.val = s; } body { } // no closure void bar2(string s) out { A15524.val = s; } body { string x; dg = { x = null; }; } // closure [local] void bar3(string s) out { A15524.val = s; } body { dg = { s = null; }; } // closure [parameter] void bar4(string s) out { A15524.val = s; } body { } // no closure void bar5(string s) out { A15524.val = s; } body { } // no closure void bar6(string s) out { A15524.val = s; } body { string x; dg = { x = null; }; } // closure [local] void bar7(string s) out { A15524.val = s; } body { dg = { s = null; }; } // closure [parameter] } class B15524 : A15524 { static string val; // in-contract tests override void foo1(string s) in { B15524.val = s; } body { } // -> no closure override void foo2(string s) in { B15524.val = s; } body { string x; dg = { x = null; }; } // -> closure [local] appears override void foo3(string s) in { B15524.val = s; } body { dg = { s = null; }; } // -> closure [parameter] override void foo4(string s) in { B15524.val = s; } body { string x; dg = { x = null; }; } // -> closure [local] appears override void foo5(string s) in { B15524.val = s; } body { dg = { s = null; }; } // -> closure [parameter] appears override void foo6(string s) in { B15524.val = s; } body { } // -> closure [local] disappears override void foo7(string s) in { B15524.val = s; } body { } // -> closure [parameter] disappears // out-contract tests override void bar1(string s) out { B15524.val = s; } body { } // -> no closure override void bar2(string s) out { B15524.val = s; } body { string x; dg = { x = null; }; } // -> closure [local] appears override void bar3(string s) out { B15524.val = s; } body { dg = { s = null; }; } // -> closure [parameter] override void bar4(string s) out { B15524.val = s; } body { string x; dg = { x = null; }; } // -> closure [local] appears override void bar5(string s) out { B15524.val = s; } body { dg = { s = null; }; } // -> closure [parameter] appears override void bar6(string s) out { B15524.val = s; } body { } // -> closure [local] disappears override void bar7(string s) out { B15524.val = s; } body { } // -> closure [parameter] disappears } void test15524() { auto a = new A15524(); auto b = new B15524(); // base class in-contract is used from derived class. // base derived b.foo1("1"); assert(A15524.val == "1" && B15524.val == "1"); // no closure -> no closure b.foo2("2"); assert(A15524.val == "2" && B15524.val == "2"); // closure [local] -> closure [local] appears b.foo3("3"); assert(A15524.val == "3" && B15524.val == "3"); // closure [parameter] -> closure [parameter] b.foo4("4"); assert(A15524.val == "4" && B15524.val == "4"); // no closure -> closure [local] appears b.foo5("5"); assert(A15524.val == "5" && B15524.val == "5"); // no closure -> closure [parameter] appears b.foo6("6"); assert(A15524.val == "6" && B15524.val == "6"); // closure [local] -> closure [local] disappears b.foo7("7"); assert(A15524.val == "7" && B15524.val == "7"); // closure [parameter] -> closure [parameter] disappears // base class out-contract is used from derived class. // base derived b.bar1("1"); assert(A15524.val == "1" && B15524.val == "1"); // no closure -> no closure b.bar2("2"); assert(A15524.val == "2" && B15524.val == "2"); // closure [local] -> closure [local] appears b.bar3("3"); assert(A15524.val == "3" && B15524.val == "3"); // closure [parameter] -> closure [parameter] b.bar4("4"); assert(A15524.val == "4" && B15524.val == "4"); // no closure -> closure [local] appears b.bar5("5"); assert(A15524.val == "5" && B15524.val == "5"); // no closure -> closure [parameter] appears b.bar6("6"); assert(A15524.val == "6" && B15524.val == "6"); // closure [local] -> closure [local] disappears b.bar7("7"); assert(A15524.val == "7" && B15524.val == "7"); // closure [parameter] -> closure [parameter] disappears // in-contract in base class. a.foo1("1"); assert(A15524.val == "1"); // no closure a.foo2("2"); assert(A15524.val == "2"); // closure [local] a.foo3("3"); assert(A15524.val == "3"); // closure [parameter] // out-contract in base class. a.bar1("1"); assert(A15524.val == "1"); // no closure a.bar2("2"); assert(A15524.val == "2"); // closure [local] a.bar3("3"); assert(A15524.val == "3"); // closure [parameter] } void test15524a() { auto t1 = new Test15524a(); t1.infos["first"] = 0; //t1.add("first"); t1.add("second"); auto t2 = new Test15524b(); t2.add("second"); } class Test15524a { int[string] infos; void add(string key) in { assert(key !in infos); // @@@ crash here at second } body { auto item = new class { void notCalled() { infos[key] = 0; // affects, key parameter is made a closure variable. } }; } } class Test15524b { void add(string key) in { assert(key == "second"); // @@@ fails } body { static void delegate() dg; dg = { auto x = key; }; // affects, key parameter is made a closure variable. } } /*******************************************/ // 10479 class B10479 { B10479 foo() out { } body { return null; } } class D10479 : B10479 { override D10479 foo() { return null; } } /*******************************************/ // 10596 class Foo10596 { auto bar() out (result) { } body { return 0; } } /*******************************************/ // 10721 class Foo10721 { this() out { } body { } ~this() out { } body { } } struct Bar10721 { this(this) out { } body { } } /*******************************************/ // 10981 class C10981 { void foo(int i) pure in { assert(i); } out { assert(i); } body {} } /*******************************************/ // 14779 class C14779 { final void foo(int v) in { assert(v == 0); } out { assert(v == 0); } body { } } void test14779() { auto c = new C14779(); c.foo(0); } /*******************************************/ int main() { test1(); test2(); test3(); test4(); test5(); // test6(); test7(); test8(); test9(); test4785(); test6417(); test7218(); test7517(); test8073(); test8093(); test9383(); test15524(); test15524a(); test14779(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/nan.d0000664000175000017500000000223312776215022021125 0ustar kaikaiimport core.stdc.stdio; enum real er1 = real.nan; enum real er2 = 1; static assert(er1 != er2); static assert(!(er1 == er2)); static assert(!(er1 < er2)); static assert(!(er1 > er2)); static assert(!(er1 >= er2)); static assert(!(er1 <= er2)); enum double ed1 = real.nan; enum double ed2 = 1; static assert(ed1 != ed2); static assert(!(ed1 == ed2)); static assert(!(ed1 < ed2)); static assert(!(ed1 > ed2)); static assert(!(ed1 >= ed2)); static assert(!(ed1 <= ed2)); bool b; bool test() { real r1 = real.nan; real r2 = 1; b = (r1 != r2); assert(b); b = (r1 == r2); assert(!b); b = (r1 < r2); assert(!b); b = (r1 > r2); assert(!b); b = (r1 <= r2); assert(!b); b = (r1 >= r2); assert(!b); double d1 = double.nan; double d2 = 1; b = (d1 != d2); assert(b); b = (d1 == d2); assert(!b); b = (d1 < d2); assert(!b); b = (d1 > d2); assert(!b); b = (d1 <= d2); assert(!b); b = (d1 >= d2); assert(!b); float f1 = float.nan; float f2 = 1; b = (f1 != f2); assert(b); b = (f1 == f2); assert(!b); b = (f1 < f2); assert(!b); b = (f1 > f2); assert(!b); b = (f1 <= f2); assert(!b); b = (f1 >= f2); assert(!b); return true; } void main() { assert(test()); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testabi.d0000664000175000017500000006351212776215022022013 0ustar kaikai// PERMUTE_ARGS: -release -g version(Windows) {} else version(X86_64) { /* uncomment to enable tests! */ //version = Run_X86_64_Tests; } extern (C) int printf(const char*, ...); template tuple(A...) { alias A tuple; } alias byte B; alias short S; alias int I; alias long L; alias float F; alias double D; alias real R; // Single Type struct b { B a; } struct bb { B a,b; } struct bbb { B a,b,c; } struct bbbb { B a,b,c,d; } struct bbbbb { B a,b,c,d, e; } struct b6 { B a,b,c,d, e,f; } struct b7 { B a,b,c,d, e,f,g; } struct b8 { B a,b,c,d, e,f,g,h; } struct b9 { B a,b,c,d, e,f,g,h, i; } struct b10 { B a,b,c,d, e,f,g,h, i,j; } struct b11 { B a,b,c,d, e,f,g,h, i,j,k; } struct b12 { B a,b,c,d, e,f,g,h, i,j,k,l; } struct b13 { B a,b,c,d, e,f,g,h, i,j,k,l, m; } struct b14 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n; } struct b15 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o; } struct b16 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p; } struct b17 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q; } struct b18 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q,r; } struct b19 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q,r,s; } struct b20 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q,r,s,t;} struct s { S a; } struct ss { S a,b; } struct sss { S a,b,c; } struct ssss { S a,b,c,d; } struct sssss { S a,b,c,d, e; } struct s6 { S a,b,c,d, e,f; } struct s7 { S a,b,c,d, e,f,g; } struct s8 { S a,b,c,d, e,f,g,h; } struct s9 { S a,b,c,d, e,f,g,h, i; } struct s10 { S a,b,c,d, e,f,g,h, i,j;} struct i { I a; } struct l { L a; } struct ii { I a,b; } struct ll { L a,b; } struct iii { I a,b,c; } struct lll { L a,b,c; } struct iiii { I a,b,c,d; } struct llll { L a,b,c,d; } struct iiiii { I a,b,c,d,e; } struct lllll { L a,b,c,d,e; } struct f { F a; } struct d { D a; } struct ff { F a,b; } struct dd { D a,b; } struct fff { F a,b,c; } struct ddd { D a,b,c; } struct ffff { F a,b,c,d; } struct dddd { D a,b,c,d; } struct fffff { F a,b,c,d,e; } struct ddddd { D a,b,c,d,e; } // Mixed Size struct js { I a; S b; } struct iss { I a; S b,c; } struct si { S a; I b; } struct ssi { S a,b; I c; } struct sis { S a; I b; S c; } struct ls { L a; S b; } struct lss { L a; S b,c; } struct sl { S a; L b; } struct ssl { S a,b; L c; } struct sls { S a; L b; S c; } struct li { L a; I b; } struct lii { L a; I b,c; } struct il { I a; L b; } struct iil { I a,b; L c; } struct ili { I a; L b; I c; } struct df { D a; F b; } struct dff { D a; F b,c; } struct fd { F a; D b; } struct ffd { F a,b; D c; } struct fdf { F a; D b; F c; } // Mixed Types struct fi { F a; I b; } struct fii { F a; I b,c; } struct jf { I a; F b; } struct iif { I a,b; F c; } struct ifi { I a; F b; I c; } struct ffi { F a,b; I c; } struct ffii { F a,b; I c,d; } struct iff { I a; F b,c; } struct iiff { I a,b; F c,d; } struct ifif { I a; F b; I c; F d;} struct di { D a; I b; } struct dii { D a; I b,c; } struct id { I a; D b; } struct iid { I a,b; D c; } struct idi { I a; D b; I c; } // Real ( long double ) struct r { R a; } struct rr { R a,b; } struct rb { R a; B b; } struct rf { R a; F b; } struct fr { F a; R b; } // Int Registers only alias tuple!( b,bb,bbb,bbbb,bbbbb, b6, b7, b8, b9, b10, b11,b12,b13,b14,b15, b16,b17,b18,b19,b20, s,ss,sss,ssss,sssss, s6, s7, s8, s9, s10, i,ii,iii,iiii,iiiii, l,ll,lll,llll,lllll, // js,iss,si,ssi, sis, ls,lss,sl,ssl, sls, li,lii,il,iil, ili, fi,fii,jf,iif, ifi, ffi,ffii,iff,iiff,ifif, // INT_END // SSE registers only f,ff,fff,ffff,fffff, d,dd,ddd,dddd,ddddd, // df,dff,fd,ffd, fdf, // SSE_END // Int and SSE di, dii,id, iid, idi, // MIX_END // --- ) ALL_T; enum INT_END = 65; enum SSE_END = 80; enum MIX_END = ALL_T.length; // x87 alias tuple!( r,rr,rb,rf,fr, // --- ) R_T; //"r","rr","rb","rf","fr", string[] ALL_S=[ "b","bb","bbb","bbbb","bbbbb", "b6", "b7", "b8", "b9", "b10", "b11","b12","b13","b14","b15", "b16","b17","b18","b19","b20", "s","ss","sss","ssss","sssss", "s6","s7","s8","s9" , "s10", "i","ii","iii","iiii","iiiii", "l","ll","lll","llll","lllll", // --- "js","iss","si","ssi", "sis", "ls","lss","sl","ssl", "sls", "li","lii","il","iil", "ili", "fi","fii","jf","iif", "ifi", "ffi","ffii","iff","iiff","ifif", // --- "f","ff","fff","ffff","fffff", "d","dd","ddd","dddd","ddddd", "df","dff","fd","ffd", "dfd", // --- "di","dii","id","iid","idi", ]; /* *********************************************************************** All ************************************************************************/ // test1 Struct passing and return int[MIX_END] results_1; T test1_out(T)( ) { T t; foreach( i, ref e; t.tupleof ) e = i+1; return t; } T test1_inout(T)( T t) { foreach( i, ref e; t.tupleof ) e += 10; return t; } void test1_call_out(T)( int n ) { T t1; foreach( i, ref e; t1.tupleof ) e = i+1; T t2 = test1_out!(T)(); if( t1 == t2 ) results_1[n] |= 1; } void test1_call_inout(T)( int n ) { T t1; foreach( i, ref e; t1.tupleof ) e = i+1; T t2 = test1_inout!(T)( t1 ); foreach( i, ref e; t1.tupleof ) e += 10; if( t1 == t2 ) results_1[n] |= 2; } void D_test1( ) { // Run Tests foreach( n, T; ALL_T ) { test1_call_out!(T)(n); test1_call_inout!(T)(n); } bool pass = true; foreach( i, r; results_1 ) { if( ~r & 1 ) { pass = false; printf( "Test1 out %s \tFail\n", ALL_S[i].ptr ); } if( ~r & 2 ) { pass = false; printf( "Test1 inout %s \tFail\n", ALL_S[i].ptr ); } } assert( pass ); results_1[0..5] = 0; foreach( n, T; R_T ) { test1_call_out!(T)(n); test1_call_inout!(T)(n); } } /************************************************************************/ // based on runnable/test23.d : test44() // Return Struct into an Array struct S1 { int i,j; static S1 foo(int x) { S1 s; s.i = x; return s; } } struct S2 { int i,j,k; static S2 foo(int x) { S2 s; s.i = x; return s; } } struct S3 { float i,j; static S3 foo(int x) { S3 s; s.i = x; return s; } } struct S4 { float i,j,k; static S4 foo(int x) { S4 s; s.i = x; return s; } } struct S5 { float i,j; int k; static S5 foo(float x) { S5 s; s.i = x; return s; } } void D_test2() { S1[] s1; S2[] s2; S3[] s3; S4[] s4; S5[] s5; s1 = s1 ~ S1.foo(6); s1 = s1 ~ S1.foo(1); s2 = s2 ~ S2.foo(6); s2 = s2 ~ S2.foo(1); s3 = s3 ~ S3.foo(6); s3 = s3 ~ S3.foo(1); s4 = s4 ~ S4.foo(6); s4 = s4 ~ S4.foo(1); s5 = s5 ~ S5.foo(6); s5 = s5 ~ S5.foo(1); assert( s1.length == 2 ); assert( s1[0].i == 6 ); assert( s1[1].i == 1 ); assert( s2.length == 2 ); assert( s2[0].i == 6 ); assert( s2[1].i == 1 ); /+ // These Fail on Mainline DMD64 ( Should pass! ) assert( s3.length == 2 ); assert( s3[0].i == 6 ); assert( s3[1].i == 1 ); assert( s4.length == 2 ); assert( s4[0].i == 6 ); assert( s4[1].i == 1 ); +/ assert( s5.length == 2 ); assert( s5[0].i == 6 ); assert( s5[1].i == 1 ); } /* *********************************************************************** X86_64 ************************************************************************/ version(Run_X86_64_Tests) { struct TEST { immutable int num; immutable string desc; bool[MIX_END] result; } /** * 0 = Should Fail * 1 = Should Pass */ immutable int[MIX_END] expected = [ 1,1,1,1,1, // b 1,1,1,1,1, // b6 1,1,1,1,1, // b11 1,0,0,0,0, // b16 1,1,1,1,1, // s 1,1,1,0,0, // s6 1,1,1,1,0, // i 1,1,0,0,0, // l 1,1,1,1,1, // si mix 1,1,1,1,0, // sl 1,1,1,1,0, // il 1,1,1,1,1, // int and float 1,1,1,1,1, // int and float // SSE regs only 1,1,1,1,0, // f 1,1,0,0,0, // d 1,1,1,1,0, // float and double // SSE + INT regs 1,1,1,1,0, // int and double ]; /** * Describes value expected in registers * * null means do not test * ( because value is passed on the stack ). */ immutable long[][] RegValue = [ /* 0 b */ [ 0x0000000000000001, ], /* 1 bb */ [ 0x0000000000000201, ], /* 2 bbb */ [ 0x0000000000030201, ], /* 3 bbbb */ [ 0x0000000004030201, ], /* 4 bbbbb */ [ 0x0000000504030201, ], /* 5 b6 */ [ 0x0000060504030201, ], /* 6 b7 */ [ 0x0007060504030201, ], /* 7 b8 */ [ 0x0807060504030201, ], /* 8 b9 */ [ 0x0807060504030201, 0x0000000000000009 ], /* 9 b10 */ [ 0x0807060504030201, 0x0000000000000a09 ], /* 10 b11 */ [ 0x0807060504030201, 0x00000000000b0a09 ], /* 11 b12 */ [ 0x0807060504030201, 0x000000000c0b0a09 ], /* 12 b13 */ [ 0x0807060504030201, 0x0000000d0c0b0a09 ], /* 13 b14 */ [ 0x0807060504030201, 0x00000e0d0c0b0a09 ], /* 14 b15 */ [ 0x0807060504030201, 0x000f0e0d0c0b0a09 ], /* 15 b16 */ [ 0x0807060504030201, 0x100f0e0d0c0b0a09 ], /* 16 b17 */ null, /* 17 b18 */ null, /* 18 b19 */ null, /* 19 b20 */ null, /* 20 s */ [ 0x0000000000000001, ], /* 21 ss */ [ 0x0000000000020001, ], /* 22 sss */ [ 0x0000000300020001, ], /* 23 ssss */ [ 0x0004000300020001, ], /* 24 sssss */ [ 0x0004000300020001, 0x0000000000000005 ], /* 25 s6 */ [ 0x0004000300020001, 0x0000000000060005 ], /* 26 s7 */ [ 0x0004000300020001, 0x0000000700060005 ], /* 27 s8 */ [ 0x0004000300020001, 0x0008000700060005 ], /* 28 s9 */ null, /* 29 s10 */ null, /* 30 i */ [ 0x0000000000000001, ], /* 31 ii */ [ 0x0000000200000001, ], /* 32 iii */ [ 0x0000000200000001, 0x0000000000000003 ], /* 33 iiii */ [ 0x0000000200000001, 0x0000000400000003 ], /* 34 iiiii */ null, /* 35 l */ [ 0x0000000000000001, ], /* 36 ll */ [ 0x0000000000000001, 0x0000000000000002 ], /* 37 lll */ null, /* 38 llll */ null, /* 39 lllll */ null, /* 40 js */ [ 0x0000000200000001, ], /* 41 iss */ [ 0x0003000200000001, ], /* 42 si */ [ 0x0000000200000001, ], /* 43 ssi */ [ 0x0000000300020001, ], /* 44 sis */ [ 0x0000000200000001, 0x0000000000000003 ], /* 45 ls */ [ 0x0000000000000001, 0x0000000000000002 ], /* 46 lss */ [ 0x0000000000000001, 0x0000000000030002 ], /* 47 sl */ [ 0x0000000000000001, 0x0000000000000002 ], /* 48 ssl */ [ 0x0000000000020001, 0x0000000000000003 ], /* 49 sls */ null, /* 50 li */ [ 0x0000000000000001, 0x0000000000000002 ], /* 51 lii */ [ 0x0000000000000001, 0x0000000300000002 ], /* 52 il */ [ 0x0000000000000001, 0x0000000000000002 ], /* 53 iil */ [ 0x0000000200000001, 0x0000000000000003 ], /* 54 ili */ null, /* 55 fi */ [ 0x000000023f800000, ], /* 56 fii */ [ 0x000000023f800000, 0x0000000000000003 ], /* 57 jf */ [ 0x4000000000000001, ], /* 58 iif */ [ 0x0000000200000001, 0x0000000040400000 ], /* 59 ifi */ [ 0x4000000000000001, 0x0000000000000003 ], /* 60 ffi */ [ 0x0000000000000003, 0x400000003f800000 ], /* 61 ffii */ [ 0x0000000400000003, 0x400000003f800000 ], /* 62 iff */ [ 0x4000000000000001, 0x0000000040400000 ], /* 63 iiff */ [ 0x0000000200000001, 0x4080000040400000 ], /* 64 ifif */ [ 0x4000000000000001, 0x4080000000000003 ], /* 65 f */ [ 0x000000003f800000, ], /* 66 ff */ [ 0x400000003f800000, ], /* 67 fff */ [ 0x400000003f800000, 0x0000000040400000 ], /* 68 ffff */ [ 0x400000003f800000, 0x4080000040400000 ], /* 69 fffff */ null, /* 70 d */ [ 0x3ff0000000000000, ], /* 71 dd */ [ 0x3ff0000000000000, 0x4000000000000000 ], /* 72 ddd */ null, /* 73 dddd */ null, /* 74 ddddd */ null, /* 75 df */ [ 0x3ff0000000000000, 0x0000000040000000 ], /* 76 dff */ [ 0x3ff0000000000000, 0x4040000040000000 ], /* 77 fd */ [ 0x000000003f800000, 0x4000000000000000 ], /* 78 ffd */ [ 0x400000003f800000, 0x4008000000000000 ], /* 79 fdf */ null, /* 80 di */ [ 0x3ff0000000000000, 0x0000000000000002 ], /* 81 dii */ [ 0x3ff0000000000000, 0x0000000300000002 ], /* 82 id */ [ 0x4000000000000000, 0x0000000000000001 ], /* 83 iid */ [ 0x4008000000000000, 0x0000000200000001 ], /* 84 idi */ null, ]; /* Have to do it this way for OSX: Issue 7354 */ __gshared long[2] dump; /** * Generate Register capture */ string gen_reg_capture( int n, string registers )( ) { if( RegValue[n] == null ) return "return;"; string[] REG = mixin(registers); // ["RDI","RSI"]; // Which type of compare static if(n < INT_END) enum MODE = 1; // Int else static if(n < SSE_END) enum MODE = 2; // Float else enum MODE = 3; // Mix /* Begin */ string code = "asm {\n"; final switch( MODE ) { case 1: code ~= "mov [dump], "~REG[0]~";\n"; REG = REG[1..$]; break; case 2: case 3: code ~= "movq [dump], XMM0;\n"; } if( RegValue[n].length == 2 ) final switch( MODE ) { case 1: case 3: code ~= "mov [dump+8], "~REG[0]~";\n"; break; case 2: code ~= "movq [dump+8], XMM1;\n"; } else { code ~= "xor R8, R8;\n"; code ~= "mov [dump+8], R8;\n"; } return code ~ "}\n"; } /** * Check the results */ bool check( TEST data ) { bool pass = true; foreach( i, e; expected ) { if( data.result[i] != (e & 1) ) { printf( "Test%d %s \tFail\n", data.num, ALL_S[i].ptr); pass = false; } } return pass; } /************************************************************************/ // test1 Return Struct in Registers // ( if RDI == 12 we have no hidden pointer ) TEST data1 = { 1, "RDI hidden pointer" }; T test1_asm( T, int n )( int i ) { asm { cmp EDI, 12; je L1; leave; ret; } L1: data1.result[n] = true; } void test1() { printf("\nRunning iasm Test 1 ( %s )\n", data1.desc.ptr); foreach( int n, T; ALL_T ) test1_asm!(T,n)(12); check( data1 ); } /************************************************************************/ // test2 Pass Struct in Registers // ( if RDI == 0 we have no stack pointer ) TEST data2 = { 2, "RDI struct pointer" }; T test2_asm( T, int n )( T t ) { asm { mov [dump], RDI; mov [dump+8], RSP; cmp EDI, 0; // TODO test RDI is a ptr to stack ? ? je L1; leave; ret; } L1: data2.result[n] = true; } T test2f_asm( T, int n )( T t, int x ) { asm { cmp EDI, 12; je L1; leave; ret; } L1: data2.result[n] = true; } void test2() { printf("\nRunning iasm Test 2 ( %s )\n", data2.desc.ptr); // Integer foreach( int n, T; ALL_T ) { T t = { 0 }; test2_asm!(T,n)( t ); } // float alternative test foreach( int n, T; ALL_T[INT_END..SSE_END] ) { enum n2 = n + INT_END; data2.result[n2] = false; test2f_asm!(T,n2)( T.init, 12 ); } check( data2 ); } /************************************************************************/ // test3 TEST data3 = { 3, "Check Return Register value" }; void test3_run( T, int n )( ) { test3_ret!T(); mixin( gen_reg_capture!(n,`["RAX","RDX"]`)() ); //dbg!(T,n)( ); enum len = RegValue[n].length; if( dump[0..len] == RegValue[n] ) data3.result[n] = true; } T test3_ret( T )( ) { T t; foreach( i, ref e; t.tupleof ) e = i+1; return t; } void test3() { printf("\nRunning iasm Test 3 ( %s )\n", data3.desc.ptr); foreach( int n, T; ALL_T ) test3_run!(T,n)( ); check( data3 ); } /************************************************************************/ // test4 TEST data4 = { 4, "Check Input Register value" }; void test4_run( T, int n )( T t ) { mixin( gen_reg_capture!(n,`["RDI","RSI"]`)() ); //dbg!(T,n)( ); enum len = RegValue[n].length; if( dump[0..len] == RegValue[n] ) data4.result[n] = true; } void dbg( T, int n )( ) { import std.stdio; writefln( "D %s\t[ %16x, %16x ]", T.stringof, dump[0], dump[1], ); writef( "C %s\t[ %16x", T.stringof, RegValue[n][0] ); if( RegValue[n].length == 2 ) writef( ", %16x", RegValue[n][1] ); writefln( " ]" ); } void test4() { printf("\nRunning iasm Test 4 ( %s )\n", data4.desc.ptr); foreach( int n, T; ALL_T ) { T t; foreach( i, ref e; t.tupleof ) e = i+1; test4_run!(T,n)( t ); } check( data4 ); } } // end version(Run_X86_64_Tests) /************************************************************************/ void main() { D_test1(); D_test2(); version(Run_X86_64_Tests) { test1(); test2(); test3(); test4(); } } /+ /** * C code to generate the table RegValue */ string c_generate_returns() { string value = " 1, 2, 3, 4, 5, 6, 7, 8, 9,10," "11,12,13,14,15,16,17,18,19,20,"; string code = "#include \"cgen.h\"\n"; // Generate return functions foreach( int n, T; ALL_T ) { auto Ts = T.stringof; auto len = T.tupleof.length; code ~= "struct "~Ts~" func_ret_"~Ts~"(void) { \n"; code ~= "struct "~Ts~" x = { "; code ~= value[0..len*3] ~ " };\n"; code ~= "return x;\n}\n"; } return code; } string c_generate_pass() { string value = " 1, 2, 3, 4, 5, 6, 7, 8, 9,10," "11,12,13,14,15,16,17,18,19,20,"; string code; // Generate return functions foreach( int n, T; ALL_T ) { auto Ts = T.stringof; auto len = T.tupleof.length; code ~= "void func_pass_"~Ts~"( struct "~Ts~" x ) {\n"; //////////////// // Which type of compare static if(n < INT_END) enum MODE = 1; // Int else static if(n < SSE_END) enum MODE = 2; // Float else enum MODE = 3; // Mix auto nn = n.stringof; /* Begin */ code ~= "asm(\n"; final switch( MODE ) { case 1: code ~= `"movq %rdi, reg\n" "movq %rsi, reg+8\n"`; break; case 2: code ~= `"movq %xmm0, reg\n" "movq %xmm1, reg+8\n"`; break; case 3: code ~= `"movq %xmm0, reg\n" "movq %rdi, reg+8\n"`; } code ~= "\n);\n"; code ~= "}\n"; //////////////// code ~= "void func_call_"~Ts~"( void ) {\n"; code ~= "struct "~Ts~" x = { "; code ~= value[0..len*3] ~ " };\n"; code ~= "func_pass_"~Ts~"( x );\n}\n"; } return code; } string c_generate_main() { string code = "void main() {\n"; foreach( int n, T; ALL_T ) { // Which type of compare static if(n < INT_END) enum MODE = 1; // Int else static if(n < SSE_END) enum MODE = 2; // Float else enum MODE = 3; // Mix auto nn = n.stringof; auto Ts = T.stringof; /* Begin */ code ~= `printf("/* %3d `~Ts~`\t*/ ", `~nn~`);`"\n"; if( !(expected[n] & 1) ) { code ~= `printf("null,\n");`"\n"; continue; } code ~= "asm(\n"; code ~= `"call func_ret_`~Ts~`\n"`"\n"; final switch( MODE ) { case 1: code ~= `"movq %rax, reg\n" "movq %rdx, reg+8\n"`; break; case 2: code ~= `"movq %xmm0, reg\n" "movq %xmm1, reg+8\n"`; break; case 3: code ~= `"movq %xmm0, reg\n" "movq %rax, reg+8\n"`; } code ~= "\n);\n"; code ~= `printf("[ 0x%016lx", reg.r1 );`"\n"; if( T.sizeof > 8 || MODE == 3 ) code ~= `printf(", 0x%016lx ],\n", reg.r2 );`"\n"; else code ~= `printf(", %015c ],\n", ' ' );`"\n"; } foreach( int n, T; ALL_T ) { // Which type of compare static if(n < INT_END) enum MODE = 1; // Int else static if(n < SSE_END) enum MODE = 2; // Float else enum MODE = 3; // Mix auto nn = n.stringof; auto Ts = T.stringof; /* Begin */ code ~= `printf("/* %3d `~Ts~`\t*/ ", `~nn~`);`"\n"; if( !(expected[n] & 1) ) { code ~= `printf("null,\n");`"\n"; continue; } code ~= "func_call_"~Ts~"();\n"; code ~= `printf("[ 0x%016lx", reg.r1 );`"\n"; if( T.sizeof > 8 || MODE == 3 ) code ~= `printf(", 0x%016lx ],\n", reg.r2 );`"\n"; else code ~= `printf(", %015c ],\n", ' ' );`"\n"; } return code ~ "}"; } pragma(msg, c_generate_returns() ); pragma(msg, c_generate_pass() ); pragma(msg, c_generate_main() ); // +/ /+ /** * Generate Functions that pass/return each Struct type * * ( Easier to look at objdump this way ) */ string d_generate_functions( ) { string code = "extern(C) {"; // pass foreach( s; ALL_T ) { string ss = s.stringof; code ~= "void func_in_"~ss~"( "~ss~" t ) { t.a = 12; }\n"; } // return foreach( s; ALL_T[0..10] ) { string ss = s.stringof; code ~= ` auto func_out_`~ss~`() { `~ss~` t; foreach( i, ref e; t.tupleof ) e = i+1; return t; }`; } // pass & return foreach( s; ALL_T[0..10] ) { string ss = s.stringof; code ~= ` auto func_inout_`~ss~`( `~ss~` t ) { foreach( i, ref e; t.tupleof ) e += 10; return t; }`; } return code ~ "\n} // extern(C)\n"; } //pragma( msg, d_generate_functions() ); mixin( d_generate_functions() ); // +/ ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/opover3.d0000664000175000017500000001041312776215022021745 0ustar kaikai void test1() { static struct Foo1 { } Foo1 foo1; Foo1 foo1_2 = Foo1(); // literal syntax static assert(!__traits(compiles, foo1())); } /**************************************/ void test2() { static struct Foo2 { this(int n){} } Foo2 foo2; Foo2 foo2_2 = Foo2(1); // user ctor call Foo2 foo2_3 = Foo2(); // literal syntax static assert(!__traits(compiles, foo2(1))); static assert(!__traits(compiles, foo2())); } /**************************************/ void test2a() { static struct Foo2a // alternation of Foo2 { static Foo2a opCall(int n){ Foo2a foo2a; return foo2a; } } Foo2a foo2a; Foo2a foo2a_3 = Foo2a(1); // static opCall static assert(!__traits(compiles, Foo2a())); // static opCall hides literal syntax. foo2a(1); // static opCall from instance static assert(!__traits(compiles, foo2a())); } /**************************************/ void test2c() { static struct Foo2c // conflict version { this(int n){} static Foo2c opCall(int n, int m){ Foo2c foo2c; return foo2c; } } Foo2c foo2c; Foo2c foo2c_2 = Foo2c(1); // user ctor call static assert(!__traits(compiles, Foo2c(1,2))); // user ctor hides static opCall. Foo2c foo2c_3 = Foo2c(); // literal syntax static assert(!__traits(compiles, foo2c(1))); foo2c(1,2); // static opCall from instance static assert(!__traits(compiles, foo2c())); } /**************************************/ void test3() { static struct Foo3 { this(int n){} int opCall(int n){ return 0; } } Foo3 foo3; Foo3 foo3_2 = Foo3(); // literal syntax (default construction) Foo3 foo3_3 = Foo3(1); // user ctor call assert(foo3(1) == 0); // instance opCall static assert(!__traits(compiles, foo3())); } /**************************************/ void test3c() { static struct Foo3c { this(int n){} static Foo3c opCall(int n, int m){ Foo3c foo3c; return foo3c; } int opCall(int n){ return 0; } } Foo3c foo3c; Foo3c foo3c_2 = Foo3c(); // literal syntax (default construction) Foo3c foo3c_3 = Foo3c(1); // user ctor call static assert(!__traits(compiles, Foo3c(1,2))); // user ctor hides static opCall assert(foo3c(1,2) == Foo3c.init); // static opCall from instance assert(foo3c(1) == 0); // instance opCall static assert(!__traits(compiles, foo3c())); } /**************************************/ void test4() { static struct Foo4 { static Foo4 opCall(int n, int m){ Foo4 foo4; return foo4; } int opCall(int n){ return 0; } } Foo4 foo4; Foo4 foo4_4 = Foo4(1,2); // static opCall static assert(!__traits(compiles, Foo4(1))); static assert(!__traits(compiles, Foo4())); // static opCall without constructor hides literal syntax assert(foo4(1,2) == Foo4.init); // static opCall from instance assert(foo4(1) == 0); // instance opCall static assert(!__traits(compiles, foo4())); } /**************************************/ // 12070 void test12070() { static string result; struct S { this(T...)(T) { result ~= "c" ~ cast(char)('0' + T.length); } void opCall(A...)(A) { result ~= "x" ~ cast(char)('0' + A.length); } } auto s0 = S(); s0(); s0(1); s0(1, 2); assert(result == "x0x1x2"); result = null; auto s1 = S(1); s1(); s1('a'); s1('a', 'b'); assert(result == "c1x0x1x2"); } /**************************************/ // 12124 struct S12124 { this(int) {} S12124 opCall()() { static assert(0); } // speculative opCall instantiation for diagnostic message should not cause false errors } /**************************************/ void main() { test1(); test2(); test2a(); test2c(); test3(); test3c(); test4(); test12070(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_1608.d0000664000175000017500000000060412776215022023133 0ustar kaikaiint numPostblit = 0, numDtor = 0; struct S { int v; this(this) { ++numPostblit; } ~this() { ++numDtor; } } void foo() { S[4] sa = [ S(1), S(2), S(3), S(4) ]; // helper to generate a slice rvalue static S[] toSlice(ref S[4] sa) { return sa[1..$]; } S[3] r = toSlice(sa); } void main() { foo(); assert(numPostblit == 3); assert(numDtor == 7); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test7494.d0000664000175000017500000000072712776215022021666 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/test7494a.d // PERMUTE_ARGS: // REQUIRED_ARGS: module test7494; void main() { import imports.test7494a : map; // selective import imports.test7494a : put = writeln; // selective + rename auto r = map!(a=>a)([1,2,3]); assert(r == [4,5,6]); put(r); static assert(!__traits(compiles, foo())); import core.bitop : bsr; // ^ or just any selective import statements bsr(1); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/literal.d0000664000175000017500000002004712776215022022010 0ustar kaikai extern(C) int printf(const char*, ...); enum { T_char, T_wchar, T_dchar, T_bit, T_byte, T_ubyte, T_short, T_ushort, T_int, T_uint, T_long, T_ulong, } int dotype(char x) { return T_char; } int dotype(bool x) { return T_bit; } int dotype(byte x) { return T_byte; } int dotype(ubyte x) { return T_ubyte; } int dotype(wchar x) { return T_wchar; } int dotype(short x) { return T_short; } int dotype(ushort x) { return T_ushort; } int dotype(int x) { return T_int; } int dotype(uint x) { return T_uint; } int dotype(long x) { return T_long; } int dotype(ulong x) { return T_ulong; } void test1() { /* * 0x7FFF 077777 32767 * 0x8000 0100000 32768 * 0xFFFF 0177777 65535 * 0x10000 0200000 65536 * 0x7FFFFFFF 017777777777 2147483647 * 0x80000000 020000000000 2147483648 * 0xFFFFFFFF 037777777777 4294967295 * 0x100000000 040000000000 4294967296 * 0x7FFFFFFFFFFFFFFF 0777777777777777777777 9223372036854775807 * 0x8000000000000000 01000000000000000000000 9223372036854775808 * 0xFFFFFFFFFFFFFFFF 01777777777777777777777 18446744073709551615 */ assert(dotype(1) == T_int); /***************** Hexadecimal ***********************/ assert(dotype(0) == T_int); assert(dotype(0x7FFF) == T_int); assert(dotype(0x8000) == T_int); assert(dotype(0xFFFF) == T_int); assert(dotype(0x10000) == T_int); assert(dotype(0x7FFFFFFF) == T_int); assert(dotype(0x80000000) == T_uint); assert(dotype(0xFFFFFFFF) == T_uint); assert(dotype(0x100000000) == T_long); assert(dotype(0x7FFFFFFFFFFFFFFF) == T_long); assert(dotype(0x8000000000000000) == T_ulong); assert(dotype(0xFFFFFFFFFFFFFFFF) == T_ulong); assert(dotype(0u) == T_uint); assert(dotype(0x7FFFu) == T_uint); assert(dotype(0x8000u) == T_uint); assert(dotype(0xFFFFu) == T_uint); assert(dotype(0x10000u) == T_uint); assert(dotype(0x7FFFFFFFu) == T_uint); assert(dotype(0x80000000u) == T_uint); assert(dotype(0xFFFFFFFFu) == T_uint); assert(dotype(0x100000000u) == T_ulong); assert(dotype(0x7FFFFFFFFFFFFFFFu) == T_ulong); assert(dotype(0x8000000000000000u) == T_ulong); assert(dotype(0xFFFFFFFFFFFFFFFFu) == T_ulong); assert(dotype(0L) == T_long); assert(dotype(0x7FFFL) == T_long); assert(dotype(0x8000L) == T_long); assert(dotype(0xFFFFL) == T_long); assert(dotype(0x10000L) == T_long); assert(dotype(0x7FFFFFFFL) == T_long); assert(dotype(0x80000000L) == T_long); assert(dotype(0xFFFFFFFFL) == T_long); assert(dotype(0x100000000L) == T_long); assert(dotype(0x7FFFFFFFFFFFFFFFL) == T_long); assert(dotype(0x8000000000000000L) == T_ulong); assert(dotype(0xFFFFFFFFFFFFFFFFL) == T_ulong); assert(dotype(0uL) == T_ulong); assert(dotype(0x7FFFuL) == T_ulong); assert(dotype(0x8000uL) == T_ulong); assert(dotype(0xFFFFuL) == T_ulong); assert(dotype(0x10000uL) == T_ulong); assert(dotype(0x7FFFFFFFuL) == T_ulong); assert(dotype(0x80000000uL) == T_ulong); assert(dotype(0xFFFFFFFFuL) == T_ulong); assert(dotype(0x100000000uL) == T_ulong); assert(dotype(0x7FFFFFFFFFFFFFFFuL) == T_ulong); assert(dotype(0x8000000000000000uL) == T_ulong); assert(dotype(0xFFFFFFFFFFFFFFFFuL) == T_ulong); /***************** Decimal ***********************/ assert(dotype(0) == T_int); assert(dotype(32767) == T_int); assert(dotype(32768) == T_int); assert(dotype(65535) == T_int); assert(dotype(65536) == T_int); assert(dotype(2147483647) == T_int); assert(dotype(2147483648) == T_long); assert(dotype(4294967295) == T_long); assert(dotype(4294967296) == T_long); assert(dotype(9223372036854775807) == T_long); //assert(dotype(9223372036854775808) == T_long); //assert(dotype(18446744073709551615) == T_ulong); assert(dotype(0u) == T_uint); assert(dotype(32767u) == T_uint); assert(dotype(32768u) == T_uint); assert(dotype(65535u) == T_uint); assert(dotype(65536u) == T_uint); assert(dotype(2147483647u) == T_uint); assert(dotype(2147483648u) == T_uint); assert(dotype(4294967295u) == T_uint); assert(dotype(4294967296u) == T_ulong); assert(dotype(9223372036854775807u) == T_ulong); assert(dotype(9223372036854775808u) == T_ulong); assert(dotype(18446744073709551615u) == T_ulong); assert(dotype(0L) == T_long); assert(dotype(32767L) == T_long); assert(dotype(32768L) == T_long); assert(dotype(65535L) == T_long); assert(dotype(65536L) == T_long); assert(dotype(2147483647L) == T_long); assert(dotype(2147483648L) == T_long); assert(dotype(4294967295L) == T_long); assert(dotype(4294967296L) == T_long); assert(dotype(9223372036854775807L) == T_long); //assert(dotype(9223372036854775808L) == T_ulong); //assert(dotype(18446744073709551615L) == T_ulong); assert(dotype(0uL) == T_ulong); assert(dotype(32767uL) == T_ulong); assert(dotype(32768uL) == T_ulong); assert(dotype(65535uL) == T_ulong); assert(dotype(65536uL) == T_ulong); assert(dotype(2147483647uL) == T_ulong); assert(dotype(2147483648uL) == T_ulong); assert(dotype(4294967295uL) == T_ulong); assert(dotype(4294967296uL) == T_ulong); assert(dotype(9223372036854775807uL) == T_ulong); assert(dotype(9223372036854775808uL) == T_ulong); assert(dotype(18446744073709551615uL) == T_ulong); } void test2() { ulong[] a = [ 2_463_534_242UL ]; foreach(e; a) assert(e == 2_463_534_242UL); } /***************************************************/ // 13907 void f13907_1(wchar[1] a) {} void f13907_2(wchar[2] a) {} void f13907_3(wchar[3] a) {} auto f13907_12(char[1]) { return 1; } auto f13907_12(char[2]) { return 2; } auto f13907_123(char[1]) { return 1; } auto f13907_123(char[2]) { return 2; } auto f13907_123(char[3]) { return 3; } auto f13907_123(const(char)[]) { return 0; } void test13907() { static assert(!__traits(compiles, { f13907_1("\U00010000"w); })); static assert(!__traits(compiles, { f13907_1("\U00010000" ); })); f13907_2("\U00010000"w); f13907_2("\U00010000"); f13907_3("\U00010000"w); // Re-enable implicit length extension, from issue 13999 f13907_3("\U00010000" ); // Re-enable implicit length extension, from issue 13999 assert(f13907_12("a") == 1); assert(f13907_12("ab") == 2); static assert(!__traits(compiles, { f13907_12("abc"); })); assert(f13907_123("a") == 1); assert(f13907_123("ab") == 2); assert(f13907_123("abc") == 3); assert(f13907_123("abcd") == 0); // regression tests for the lengthen behavior in initializer enum const(char*) p = "hello world"; static assert(!__traits(compiles, { static char[5] a = "hello world"; })); // truncation is not allowed static assert(!__traits(compiles, { static void[20] a = "hello world"; })); static assert(!__traits(compiles, { static int[20] a = "hello world"; })); static assert(!__traits(compiles, { static char[20] a = "hello world"w; })); static assert(!__traits(compiles, { static wchar[20] a = "hello world"d; })); static assert(!__traits(compiles, { static dchar[20] a = "hello world"c; })); static assert(!__traits(compiles, { static char[20] a = p; })); static char[20] csa = "hello world"; // extending is allowed static wchar[20] wsa = "hello world"; // ok static dchar[20] dsa = "hello world"; // ok // Bugzilla 13966 string[1][] arr; arr ~= ["class"]; enum immutable(char[5]) sarrstr = "class"; arr ~= [sarrstr]; // Bugzilla 13999 string[dchar[2]] aa13999 = ["あ": "bar"]; assert(aa13999["あ"] == "bar"); dchar[2] key13999 = "あ"; assert(key13999[0] == 'あ'); assert(key13999[1] == '\0'); assert(aa13999[key13999] == "bar"); } /***************************************************/ int main() { test1(); test2(); test13907(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ice15138.d0000664000175000017500000000026112776215022021512 0ustar kaikai// EXTRA_SOURCES: imports/ice15138a.d // PERMUTE_ARGS: -unittest -inline // COMPILE_SEPARATELY import imports.ice15138a; void main() { JSONValue v; v.get!JSONValue; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_1327.d0000664000175000017500000000032012776215022023124 0ustar kaikaivoid main() { int v = 3; static int inc(ref int v) { ++v; return 10; } int r = v + inc(v); assert(r == 3 + 10); assert(v == 4); v *= inc(v) + v; assert(v == (4+1) * (10 + 5)); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test13.d0000664000175000017500000000026312776215022021475 0ustar kaikai// EXTRA_SOURCES: imports/test13a.d // PERMUTE_ARGS: // REQUIRED_ARGS: -unittest module test13; import imports.test13a; alias Ordinal!(char) ord; int main() { return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test17.d0000664000175000017500000000112412776215022021476 0ustar kaikai import core.stdc.stdio: fflush, stdout; extern(C) int printf(const char*, ...); void ulog(string s) { printf("%.*s\n",s.length, s.ptr); fflush(stdout); } int open() { char *s; char abs[2000]; char qu[100]; int a; ulog("reaches this only 9 times of 10!\n"); return 0; } int yhenda() { char MEM[2200]; int a; ulog("point(2.1) \n"); open(); ulog("point(2.2) \n"); return 0; } int main() { printf("Content-type: text/html\n\n"); fflush(stdout); ulog("point(1.1)\n"); yhenda(); ulog("point(1.2)\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test16.d0000664000175000017500000001241712776215022021504 0ustar kaikai// REQUIRED_ARGS: extern(C) int printf(const char*, ...); /************************************************/ // These seem to be the original tests for $ (originally 'length'). int x; int[] bar(int[] a) { x++; return a[0 .. $ - 1]; } void test1() { { int[4] foo; foo[$ - 2] = 4; assert(foo[0] == 0); assert(foo[1] == 0); assert(foo[2] == 4); assert(foo[3] == 0); foo[3] = 5; assert(foo[$ - 1] == 5); x = 0; bar(foo)[$ - 3] = 6; assert(x == 1); assert(foo[0] == 6); assert(bar(foo)[$ * 2 - 1 - $] == 4); assert(x == 2); foo[0 .. $] = 1; assert(foo[0] == 1); assert(foo[1] == 1); assert(foo[2] == 1); assert(foo[3] == 1); x = 0; bar(foo)[1 .. $ * 3 - $ - $] = 2; assert(x == 1); assert(foo[0] == 1); assert(foo[1] == 2); assert(foo[2] == 2); assert(foo[3] == 1); int[] a = new int[3]; a[0..$] = foo[0..$-1]; assert(a[0] == 1); assert(a[1] == 2); assert(a[2] == 2); a[] = 4; a[0..$] = bar(foo)[0..$]; assert(x == 2); assert(a[0] == 1); assert(a[1] == 2); assert(a[2] == 2); } { int[4] f; int[] foo = f; foo[$ - 2] = 4; assert(foo[0] == 0); assert(foo[1] == 0); assert(foo[2] == 4); assert(foo[3] == 0); foo[3] = 5; assert(foo[$ - 1] == 5); x = 0; bar(foo)[$ - 3] = 6; assert(x == 1); assert(foo[0] == 6); assert(bar(foo)[$ * 2 - 1 - $] == 4); assert(x == 2); foo[0 .. $] = 1; assert(foo[0] == 1); assert(foo[1] == 1); assert(foo[2] == 1); assert(foo[3] == 1); x = 0; bar(foo)[1 .. $ * 3 - $ - $] = 2; assert(x == 1); assert(foo[0] == 1); assert(foo[1] == 2); assert(foo[2] == 2); assert(foo[3] == 1); int[] a = new int[3]; a[0..$] = foo[0..$-1]; assert(a[0] == 1); assert(a[1] == 2); assert(a[2] == 2); a[] = 4; a[0..$] = bar(foo)[0..$]; assert(x == 2); assert(a[0] == 1); assert(a[1] == 2); assert(a[2] == 2); } } /************************************************/ struct ICONINFO { bool fIcon; } void test2() { ICONINFO info; info.fIcon = true; assert(info.fIcon == true); } /************************************************/ class A3 { void foo() { printf("A.foo \n" ); } } class B3 : A3 { } class C3 : B3 { override void foo() { printf("C.foo \n" ); super.foo(); } } void test3() { C3 c = new C3(); c.foo(); } /************************************************/ void test4() { int function (int i) x = function int (int i) { return i * 2; }; int function (int i) y = function int (int i) { return i / 2; }; int k; k = x(2); assert(k == 4); k = y(3); assert(k == 1); } /************************************************/ class Parser { void next(ref int test) { void work (int input) { printf("work(%d, %d)\n", input, test); test = 2; } test = 3; work(4); } } void test5() { Parser parser = new Parser(); int test; parser.next (test); printf("test %d\n", test); assert(test == 2); } /************************************************/ void foo6(out int bar) { } void test6() { int bar = 3; foo6(bar); printf("%d", bar ); assert(bar == 0); // return 0; } /************************************************/ void test7() { char ch = ' '; char[] u; u.length = 3; int i = 2; printf("a\n"); u[0..2] = ch; printf("b\n"); u[0..i] = ch; printf("c\n"); assert(u[0] == 0x20); assert(u[1] == 0x20); } /************************************************/ struct X8 { bool flag; } void test8() { X8 x; x.flag = 0 != 0; } /************************************************/ void foo9(float x) { assert(x == 0.0f); } void len9(float x, float y, float z, float t) { foo9(x*x+y*y+z*z); } void test9() { float[4] a; a[0] = a[1] = a[2] = a[3] = 0.0f; for (int y = 0; y < 7; ++y) { len9(a[0], a[1], a[2], a[3]); float justOne() { return 1.0f; } float dot = justOne(); if (dot < 0.0f) dot = 0.0f; } } /************************************************/ ubyte[4] arr10; void foo10() { *cast(float*)(&arr10[0]) = 3.25; } uint bar10() { uint result = *cast(uint*)&arr10[0]; return result; } float baz10() { uint result = bar10(); return *cast(float*)&result; } void test10() { foo10(); float x = baz10(); assert(x == 3.25); } /************************************************/ interface I11 { void M (); } interface J11 : I11 { void N (); } class A11 : I11 { void M () { printf("A.M()\n"); } } class B11 : A11, J11 { void N () { printf("B.N()\n"); } } void test11() { I11 f = new B11 (); f.M(); } /************************************************/ int x12; void test12() { static class S { static this() { printf ("static constructor\n"); x12 += 1; } this() { printf ("class constructor\n"); x12 += 10; } } assert(x12 == 1); new S; assert(x12 == 11); } /************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testv.d0000664000175000017500000000406312776215022021521 0ustar kaikai extern(C) int printf(const char*, ...); /*********************************************************/ int sum(int[] xx ...) { int s; foreach (int x; xx) s += x; return s; } void test1() { static int[3] a = [5, 8, 10]; int[] b = a; int i; i = sum(); assert(i == 0); i = sum(10); assert(i == 10); i = sum(10, 20); assert(i == 30); i = sum(11, 22, 34); assert(i == 67); i = sum(a); assert(i == 23); i = sum(b); assert(i == 23); printf("%d\n", sum()); } /*********************************************************/ int sum2(int[3] xx ...) { int s; foreach (int x; xx) s += x; return s; } void test2() { static int[3] a = [5, 8, 10]; int i; i = sum2(11, 22, 34); assert(i == 67); i = sum2(a); assert(i == 23); printf("%d\n", i); } /*********************************************************/ int[4] bb3 = [5,6,7,8]; int sum3(int[] xx = bb3 ...) { int s; foreach (int x; xx) s += x; return s; } void test3() { static int[3] a = [5, 8, 10]; int i; i = sum3(11, 22, 34); assert(i == 67); i = sum3(a); assert(i == 23); i = sum3(); assert(i == 26); printf("%d\n", i); } /*********************************************************/ class Foo4 { int a; float f; double d; this(int a, float f, double d) { this.a = a; this.f = f; this.d = d; } } int sum4(Foo4 f ...) { return cast(int)(f.a + f.f + f.d); } void test4() { int i; Foo4 foo = new Foo4(1, 2f, 3.0); i = sum4(foo); assert(i == 1+2+3); i = sum4(4, 5f, 6.0); assert(i == 4+5+6); printf("%d\n", i); } /*********************************************************/ void bug1993(int[][] y...) { } void test5() { bug1993(null); bug1993(null, null); bug1993([0], null); bug1993([0], [0]); bug1993(null, [0]); } /*********************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/lazy.d0000664000175000017500000001157712776215022021343 0ustar kaikaiimport core.vararg; import std.stdio; /*********************************************************/ void ifthen(bool cond, lazy void dg) { if (cond) dg(); } void ifthen(bool cond, lazy void dgthen, lazy void dgelse) { if (cond) dgthen(); else dgelse(); } void dotimes(int i, lazy int dg) { for (int j = 0; j < i; j++) dg(); } void switcher(bool delegate()[] cases...) { foreach (c; cases) { if (c()) break; } } bool scase(bool b, lazy void dg) { if (b) { dg(); return true; } return false; } bool sdefault(lazy void dg) { dg(); return true; } void whiler(lazy bool cond, lazy void bdy) { while (cond()) bdy(); } void test1() { int x = 3; dotimes(5, printf("%d\n", ++x)); ifthen(true, printf("yes\n")); ifthen(false, printf("no\n")); ifthen(true, printf("yes\n"), printf("no\n")); ifthen(false, printf("yes\n"), printf("no\n")); int v = 2; switcher( scase(v == 1, printf("it is 1\n")), scase(v == 2, printf("it is 2\n")), scase(v == 3, printf("it is 3\n")), sdefault( printf("it is default\n")) ); whiler( x < 100, (printf("%d\n", x), x *= 2) ); } /*********************************************************/ void fooa(lazy void dg) { dg(); } void test2() { fooa(cast(void)null); } /*********************************************************/ void dotimes3(int count, lazy void exp) { for (int i = 0; i < count; i++) exp; } void bar3(...) { assert(_arguments.length == 1); assert(va_arg!int(_argptr) == 14); } void abc3(int* p) { writeln(*p); assert(*p == 3); } void test3() { int x = 3; dotimes3(10, abc3(&x)); dotimes3(10, write(++x)); writeln(); dotimes3(1, bar3(++x)); int[10] a = new int[10]; a[0] = 1; a[$ - 1] = 9; dotimes3(3, write(a[0..$])); writeln(); } /*********************************************************/ int p4; void foo4(void* delegate()[] dgs...) { assert(dgs.length == 4); writefln("%s %s", dgs[0](), cast(void*)&p4); assert(dgs[0]() == cast(void*)&p4); assert(dgs[1]() == cast(void*)&p4); assert(dgs[2]() == null); assert(dgs[3] == null); } void test4() { void *abc() { writeln(cast(void*)&p4); return cast(void*)&p4; } foo4(&abc, cast(void* delegate())&abc, null, cast(void* delegate())null); } /*********************************************************/ bool nextis(void delegate() dgpositive = {}) { return true; } bool looping(lazy bool condition) { return true; } void test5() { looping(nextis({})); looping(nextis({})); } /*********************************************************/ void foo6(lazy int expr, ...) { char[] tmp_msg = va_arg!(char[])(_argptr); if (cast(int)(tmp_msg.ptr)=="food_for_thought".length) assert(0, "length is in the pointer!"); assert(tmp_msg=="food_for_thought"); } int bar6() { return 3; } void test6() { foo6(bar6(),"food_for_thought"); } /*********************************************************/ void foo7(long delegate()[] dg...) { assert(dg[0]() == 1024); assert(dg[1]() == 1024); } void bar7(lazy long n) { assert(n == 1024); } void test7() { int n = 1024; foo7(n, n); bar7(n); } /*********************************************************/ struct Bug5750 { int a, b; } pure Bug5750 bug5750(lazy int y) { Bug5750 retval; retval.a = y; retval.b = y; return retval; } pure void test5750a() { auto z1 = bug5750(3); assert(z1 == Bug5750(3, 3)); auto z2 = bug5750(z1.a); assert(z2 == Bug5750(3, 3)); auto z3 = bug5750(z1.a+z2.a+3); assert(z3 == Bug5750(9, 9)); auto z4 = bug5750(++z1.a); // expected??? assert(z4 == Bug5750(4, 5)); assert(z1 == Bug5750(5, 3)); } int bug5750Global = 7; void test5750b() { auto z4 = bug5750(bug5750Global); assert(z4 == Bug5750(7, 7)); auto z5 = bug5750(++bug5750Global); assert(z5 == Bug5750(8, 9)); // expected??? assert(bug5750Global == 9); } // Note: also need to make up some fail-compilation tests. /*********************************************************/ T calcLazy6682(T)(lazy T n) { return n; } int purefunc6682() pure { return calcLazy6682(1); } void test6682() { assert(purefunc6682() == 1); } /*********************************************************/ // 9109 void test9109() { void foo(int delegate()[] dgs ...) { assert(dgs[0]() + dgs[1]() == 1 + 13); } int x = 10; int delegate() dg; foo({ return 1; }, { return 3+x; }, dg, null); } /*********************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test5750a(); test5750b(); test6682(); test9109(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test10386.sh0000775000175000017500000000110012776215022022114 0ustar kaikai#!/usr/bin/env bash src=runnable${SEP}extra-files dir=${RESULTS_DIR}${SEP}runnable output_file=${dir}/test10386.sh.out if [ $OS == "win32" -o $OS == "win64" ]; then LIBEXT=.lib else LIBEXT=.a fi libname=${dir}${SEP}lib10386${LIBEXT} $DMD -m${MODEL} -I${src} -of${libname} -c ${src}${SEP}lib10386${SEP}foo${SEP}bar.d ${src}${SEP}lib10386${SEP}foo${SEP}package.d -lib || exit 1 $DMD -m${MODEL} -I${src} -of${dir}${SEP}test10386${EXE} ${src}${SEP}test10386.d ${libname} || exit 1 rm ${dir}/{lib10386${LIBEXT},test10386${OBJ},test10386${EXE}} echo Success >${output_file} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/eh2.d0000664000175000017500000000221112776215022021023 0ustar kaikai// PERMUTE_ARGS: -fPIC extern(C) int printf(const char*, ...); class Abc : Throwable { this() pure { super(""); } static int x; int a,b,c; synchronized void test() { printf("test 1\n"); x |= 1; foo(); printf("test 2\n"); x |= 2; } shared void foo() { printf("foo 1\n"); x |= 4; throw this; printf("foo 2\n"); x |= 8; } } struct RefCounted { void *p; ~this() { p = null; } } struct S { RefCounted _data; int get() @property { throw new Exception(""); } } void b9438() { try { S s; S().get; } catch (Exception e){ } } int main() { printf("hello world\n"); auto a = new shared(Abc)(); printf("hello 2\n"); Abc.x |= 0x10; try { Abc.x |= 0x20; a.test(); Abc.x |= 0x40; } catch (shared(Abc) b) { Abc.x |= 0x80; printf("Caught %p, x = x%x\n", b, Abc.x); assert(a is b); assert(Abc.x == 0xB5); } printf("Success!\n"); b9438(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test38.d0000664000175000017500000000033212776215022021501 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/test38a.d // PERMUTE_ARGS: import std.stdio; import imports.test38a; void main() { static b = bar(7); printf("b = %d, %d\n", b, bar(7)); assert(b == 49); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test14901.d0000664000175000017500000000062212776215022021727 0ustar kaikai// REQUIRED_ARGS: // PERMUTE_ARGS: -unittest // EXTRA_SOURCES: imports/test14901a.d imports/test14901b.d imports/test14901c.d imports/test14901d.d // COMPILE_SEPARATELY module test14901; import imports.test14901c; import imports.test14901d; extern(C) __gshared static int initCount; extern(C) int printf(const char*, ...); void main() { caller1(); caller2(); assert(initCount == 1); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test11863.d0000664000175000017500000000026112776215022021732 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/std11863conv.d import imports.std11863conv; void main() { auto s = to!string(15, 10); assert(s == "15"); // failure } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/helloUTF8.d0000664000175000017500000000021012776215022022114 0ustar kaikai// PERMUTE_ARGS: extern(C) int printf(const char *, ...); int main(char[][] args) { printf("hello world\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test5.d0000664000175000017500000000205712776215022021421 0ustar kaikai// PERMUTE_ARGS: extern(C) int printf(const char*, ...); interface foo { extern (C) int testc(int i); extern (Windows) int testw(int i); extern (D) int testd(int i); } class bar : foo { int x = 47; extern (C) int testc(int i) { printf("foo.testc(%p)\n", this); assert(x == 47); return i + x; } extern (Windows) int testw(int i) { printf("foo.testw(%p)\n", this); assert(x == 47); return i + x; } extern (D) int testd(int i) { printf("foo.testd(%p)\n", this); assert(x == 47); return i + x; } } int def(foo f) { printf("def(%p), %p\n", f, (cast(int*)f)[0]); assert(f.testc(3) == 50); assert(f.testd(7) == 54); assert(f.testd(10) == 57); return 0; } void abc(bar b) { printf("abc(%p), %p\n", b, (cast(int*)b)[3]); def(b); } int main() { bar b = new bar(); printf("b.size = x%x\n", b.classinfo.init.length); printf("bar.size = x%x\n", bar.classinfo.init.length); assert(b.classinfo.init.length == bar.classinfo.init.length); abc(b); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link13415.d0000664000175000017500000000027012776215022021703 0ustar kaikai// EXTRA_SOURCES: imports/link13415a.d // REQUIRED_ARGS: -inline // PERMUTE_ARGS: -allinst -unittest -debug // COMPILE_SEPARATELY import imports.link13415a; void main() { f(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testscope.d0000664000175000017500000001174312776215022022370 0ustar kaikai// PERMUTE_ARGS: extern(C) int printf(const char*, ...); class Eh : Exception { this() { super("Eh thrown"); } } /********************************************/ class Foo { static int x; this() { assert(x == 0); x++; printf("Foo.this()\n"); throw new Eh(); assert(0); } ~this() { printf("Foo.~this()\n"); } } void test1() { try { scope Foo f = new Foo(); assert(0); } catch (Eh) { assert(Foo.x == 1); Foo.x++; } finally { assert(Foo.x == 2); Foo.x++; } assert(Foo.x == 3); } /********************************************/ void test2() { int x; { scope (exit) { printf("test1\n"); assert(x == 3); x = 4; } scope (exit) { printf("test2\n"); assert(x == 2); x = 3; } scope (exit) { printf("test3\n"); assert(x == 1); x = 2; } printf("test4\n"); assert(x == 0); x = 1; } assert(x == 4); } /********************************************/ void test3() { int x; { scope (success) { printf("test1\n"); assert(x == 3); x = 4; } scope (success) { printf("test2\n"); assert(x == 2); x = 3; } scope (success) { printf("test3\n"); assert(x == 1); x = 2; } printf("test4\n"); assert(x == 0); x = 1; } assert(x == 4); } /********************************************/ void test4() { int x; try { scope (exit) { printf("test1\n"); assert(x == 3); x = 4; } scope (exit) { printf("test2\n"); assert(x == 2); x = 3; } x = 2; throw new Eh; scope (exit) { printf("test3\n"); assert(x == 1); x = 2; } printf("test4\n"); assert(x == 0); x = 1; } catch (Eh e) { } assert(x == 4); } /********************************************/ void test5() { int x; try { scope (success) { printf("test1\n"); assert(x == 3); x = 4; } scope (success) { printf("test2\n"); assert(x == 2); x = 3; } x = 2; throw new Eh; scope (success) { printf("test3\n"); assert(x == 1); x = 2; } printf("test4\n"); assert(x == 0); x = 1; } catch (Eh e) { } assert(x == 2); } /********************************************/ void test6() { int x; scope (failure) { assert(0); } try { scope (failure) { printf("test1\n"); assert(x == 3); x = 4; } scope (failure) { printf("test2\n"); assert(x == 2); x = 3; } x = 2; throw new Eh; scope (failure) { printf("test3\n"); assert(x == 1); x = 2; } printf("test4\n"); assert(x == 0); x = 1; } catch (Eh e) { } assert(x == 4); } /********************************************/ void test7() { int i; int x; void foo() { scope (success) { assert(x == 1); x = 2; } i = 2; if (i == 2) return; } i = 1; x = 1; foo(); assert(x == 2); } /********************************************/ void test8() { int i; { version (all) { scope (exit) i += 2; } assert(i == 0); i += 1; printf("betty\n"); } assert(i == 3); } /********************************************/ char[] r9; int scp( int n ) { if( n==0 ) return 0; scope(exit) { printf("%d",n); r9 ~= cast(char)(n + '0'); } return scp(n-1); } void test9() { scp(5); assert(r9 == "12345"); } /********************************************/ alias real T; T readMessageBegin() { return 3.0; } T bar10() { return 8.0; } T foo10() { // Send RPC request, etc. readMessageBegin(); scope (exit) readMessageEnd(); T result = bar10(); // Read message off the wire. return result; } void test10() { if (foo10() != 8.0) assert(0); } T readMessageEnd() { static T d; d = 4.0; d = (((((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d))))+(((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d)))))/((((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d))))+(((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d)))))+((((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d))))+(((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d)))))/((((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d))))+(((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d))))))*(((((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d))))+(((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d)))))/((((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d))))+(((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d)))))+((((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d))))+(((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d)))))/((((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d))))+(((d-(2*d))+(d-(2*d)))*((d-(2*d))+(d-(2*d)))))); return 4.0; } /********************************************/ void test7435() { scope(failure) debug printf("error\n"); printf("do something\n"); } /********************************************/ void test7049() @safe { int count = 0; @safe void foo() { scope (failure) { count++; } scope (failure) { count++; } throw new Exception("failed"); } try { foo(); } catch(Exception e) { } assert(count == 2); } /********************************************/ void main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test7435(); test7049(); printf("Success\n"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/b26.d0000664000175000017500000000030412776215022020737 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/b26a.d // PERMUTE_ARGS: // 382 struct List(T) { interface A {} } int main(char[][] args) { List!(char) list; return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test34.d0000664000175000017500000005211312776215022021501 0ustar kaikai module test34; import std.stdio; import std.string; import std.format; import core.exception; /************************************************/ class Foo {} class Bar {} void test1() { TypeInfo ti_foo = typeid(Foo); TypeInfo ti_bar = typeid(Bar); auto hfoo = ti_foo.toHash(); auto hbar = ti_bar.toHash(); writefln("typeid(Foo).toHash: ", hfoo); writefln("typeid(Bar).toHash: ", hbar); assert(hfoo != hbar); auto e = (ti_foo == ti_bar); writefln("opEquals: ", e ? "equal" : "not equal"); assert(!e); auto c = (ti_foo.opCmp(ti_bar) == 0); writefln("opCmp: ", c ? "equal" : "not equal"); assert(!c); } /************************************************/ void test2() { assert( [2,3]!=[2,4] ); assert( [3,2]!=[4,2] ); assert( !([2,3]==[2,4]) ); assert( ([2,3]==[2,3]) ); } /************************************************/ struct Struct { int langID; long _force_nrvo; } Struct[1] table; Struct getfirst() { foreach(v; table) { writeln(v.langID); assert(v.langID == 1); return v; } assert(0); } Struct getsecond() { foreach(ref v; table) { writeln(v.langID); assert(v.langID == 1); return v; } assert(0); } void test3() { table[0].langID = 1; auto v = getfirst(); writeln(v.langID); assert(v.langID == 1); v = getsecond(); writeln(v.langID); assert(v.langID == 1); } /************************************************/ class ExOuter { class ExInner { this() { typeof(this.outer) X; static assert(is(typeof(X) == ExOuter)); } } } void test4() { } /************************************************/ int status5; struct MyStruct5 { } void rec5(int i, MyStruct5 s) { if( i > 0 ) { status5++; rec5(i-1, s); } } void test5() { assert(status5==0); MyStruct5 st; rec5(1030, st); assert(status5==1030); } /************************************************/ class C6 { const int a; this() { a = 3; } this(int x) { this(); } } void test6() { } /************************************************/ template parseUinteger(string s) { static if (s.length == 0) { const char[] value = ""; const char[] rest = ""; } else static if (s[0] >= '0' && s[0] <= '9') { const char[] value = s[0] ~ parseUinteger!(s[1..$]).value; const char[] rest = parseUinteger!(s[1..$]).rest; } else { const char[] value = ""; const char[] rest = s; } } template parseInteger(string s) { static if (s.length == 0) { const char[] value = ""; const char[] rest = ""; } else static if (s[0] >= '0' && s[0] <= '9') { const char[] value = s[0] ~ parseUinteger!(s[1..$]).value; const char[] rest = parseUinteger!(s[1..$]).rest; } else static if (s.length >= 2 && s[0] == '-' && s[1] >= '0' && s[1] <= '9') { const char[] value = s[0..2] ~ parseUinteger!(s[2..$]).value; const char[] rest = parseUinteger!(s[2..$]).rest; } else { const char[] value = ""; const char[] rest = s; } } void test7() { writeln(parseUinteger!("1234abc").value); writeln(parseUinteger!("1234abc").rest); writeln(parseInteger!("-1234abc").value); writeln(parseInteger!("-1234abc").rest); assert(parseUinteger!("1234abc").value == "1234"); assert(parseUinteger!("1234abc").rest == "abc"); assert(parseInteger!("-1234abc").value == "-1234"); assert(parseInteger!("-1234abc").rest == "abc"); } /************************************************/ struct Foo8 { } enum Enum { RED } //typedef int myint; alias int myalias; void test8() { /+ assert((1+2).stringof == "1 + 2"); assert(Foo8.stringof == "Foo8"); assert(test.Foo8.stringof == "test.Foo8"); assert(int.stringof == "int"); assert((int*[5][]).stringof == "int*[5][]"); assert(Enum.RED.stringof == "Enum.RED"); assert(test.myint.stringof == "test.myint"); assert(myalias.stringof == "myalias"); assert((5).stringof == "5"); assert(typeof(5).stringof == "typeof(5)"); +/ } /************************************************/ /+ class Base9 { public void fnc(){ } } class Foo9 : Base9 { alias Base9.fnc fnc; public void fnc(){ } static this(){ alias void function() T; T ptr = & fnc; } } +/ void test9() { } /************************************************/ bool isalnum(dchar c) { return c>='0' && c >= '9'; } char[] toHtmlFilename(char[] fname) { foreach (ref c; fname) { if (!isalnum(c) && c != '.' && c != '-') c = '_'; } return fname; } void test10() { } /************************************************/ class A34 { } class B34 : A34 { } void test11() { A34 test=new B34; writefln("Test is ", test.toString); assert(test.toString == "test34.B34"); A34 test_2=cast(A34)(new B34); writefln("Test 2 is ", test_2.toString); assert(test_2.toString == "test34.B34"); } /************************************************/ template Foo12(T: T[U], U) { alias int Foo12; } void test12() { Foo12!(int[long]) x; assert(is(typeof(x) == int)); } /************************************************/ class C13 { int a = 4; this() { printf("C13.this()\n"); assert(a == 4); a = 5; } } void test13() { C13 c = cast(C13)Object.factory("test34.C13"); assert(c.a == 5); Object o = Object.factory("test35.C13"); assert(o is null); } /************************************************/ class Base15 { int func(int a) { return 1; } } class Foo15 : Base15 { alias Base15.func func; } class Bar15 : Foo15 { alias Foo15.func func; int func(string a) { return 2; } } void test15() { Bar15 b = new Bar15(); assert(b.func("hello") == 2); assert(b.func(5) == 1); } /************************************************/ struct Basic16(T, U) {} struct Iterator16(T : Basic16!(T, U), U) { static void Foo() { writeln(typeid(T), typeid(U)); assert(is(T == int)); assert(is(U == float)); } } void test16() { Iterator16!(Basic16!(int, float)).Foo(); } /************************************************/ struct S17(T) { struct iterator {} } int insert17(T) (S17!(T) lst, S17!(T).iterator i) { return 3; } void test17() { S17!(int) a; S17!(int).iterator i; auto x = insert17(a, i); assert(x == 3); } /************************************************/ void test18() { real t = 0.; for(int i=0; i<10; i++) { t += 1.; real r = (2*t); printf("%Lg %Lg %Lg\n", t, r, 2*t); assert(2*t == (i+1)*2); } } /************************************************/ void test19() { char c = '3'; void[] ca = cast(void[])[c]; char[] x = cast(char[])ca; assert(x[0] == '3'); } /************************************************/ enum type20 { a, b, } class myclass20 { template XX(uint a, uint c) { static uint XX(){ return (a*256+c);} } void testcase() { switch (cast(uint)type20.a) { case XX!(cast(uint)type20.a,cast(uint)type20.b)(): break; default: assert(0); } } } void test20() { } /************************************************/ struct S21 { alias int Foo; int x; } void test21() { S21 s; typeof(s).Foo j; assert(is(typeof(j) == int)); } /************************************************/ void test22() { auto i = 3, j = 4; assert(is(typeof(i) == int)); assert(is(typeof(j) == int)); } /************************************************/ static m23 = 5, n23 = 6; void test23() { auto i = 3, j = 4; assert(is(typeof(i) == int)); assert(is(typeof(j) == int)); assert(is(typeof(m23) == int)); assert(is(typeof(n23) == int)); } /************************************************/ const int a24 = 0; const int foo24 = 4; const int[1] bar24 = [foo24 * 2]; const int zap24 = (1 << bar24[a24]); void test24() { assert(zap24 == 256); } /************************************************/ struct List25(T) { } struct CircularQueue25(T) { } void front25(T)(ref List25!(T) list) { } void front25(T)(ref CircularQueue25!(T) queue) { } void test25() { List25!(int) x; front25(x); } /************************************************/ struct Foo26 { const string x; } static Foo26 foo26 = {"something"}; void test26() { assert(foo26.x == "something"); } /************************************************/ template Mang(alias F) { class G { } alias void function (G ) H; const string mangledname = H.mangleof; } template moo(alias A) { pragma(msg," "); const string a = Mang!(A).mangledname; pragma(msg," "); static assert(Mang!(A).mangledname == a); // FAILS !!! pragma(msg," "); } void test27() { int q; string b = moo!(q).a; } /************************************************/ struct Color { static void fromRgb(uint rgb) { } static void fromRgb(ubyte alpha, uint rgb) { } } void test28() { Color.fromRgb(0); Color.fromRgb(cast(uint)0); } /************************************************/ void test29() { const char[] t="abcd"; const ubyte[] t2=cast(ubyte[])t; const char[] t3=['a','b','c','d']; const ubyte[] t4=cast(ubyte[])t3; assert(t4[1] == 'b'); } /************************************************/ void test30() { const char[] test = "" ~ 'a' ~ 'b' ~ 'c'; char[] test2 = (cast(char[])null)~'a'~'b'~'c'; const char[] test3 = (cast(char[])null)~'a'~'b'~'c'; char[] test4 = (cast(char[])[])~'a'~'b'~'c'; const char[] test5 = (cast(char[])[])~'a'~'b'~'c'; const char[] test6 = null; const char[] test7 = test6~'a'~'b'~'c'; } /************************************************/ class C31 { synchronized invariant() { int x; } } void test31() { } /************************************************/ ulong foo32() { return cast(ulong) (cast(ulong) 1176576512 + cast(float) -2); } void test32() { assert(foo32()==1176576510); } /************************************************/ class RangeCoder { uint[258] cumCount; // 256 + end + total uint lower; uint upper; ulong range; this() { for (int i=0; i", x, y, z); } } class Foo34 { private Vector34 v; public this() { v = Vector34(1, 0, 0); } public void foo() { bar(); } private void bar() { auto s = foobar(); writef("Returned: %s\n", s); assert(std.string.format("%s", s) == "<1.000000, 0.000000, 0.000000>"); } public Vector34 foobar() { writef("Returning %s\n", v); return v; Vector34 b = Vector34(); return b; } } void test34() { Foo34 f = new Foo34(); f.foo(); } /************************************************/ version(D_InlineAsm_X86_64) version = DMD_InlineAsm; version(D_InlineAsm_X86) version = DMD_InlineAsm; void foo35() { uint a; uint b; uint c; extern (Windows) int function(int i, int j, int k) xxx; a = 1; b = 2; c = 3; xxx = cast(typeof(xxx))(a + b); version (DMD_InlineAsm) asm { int 3; } else version (LDC) { import ldc.intrinsics; llvm_debugtrap(); } else assert(false); xxx( 4, 5, 6 ); } void test35() { } /************************************************/ void test36() { int* p = void, c = void; } /************************************************/ void test37() { synchronized { synchronized { writefln("Hello world!"); } } } /************************************************/ struct Rect { int left, top, right, bottom; } void test38() { print38(sizeTest(false)); print38(sizeTest(true)); print38(defaultRect); } static Rect sizeTest(bool empty) { if (empty) { Rect result; return result; //return Rect.init; } else { return defaultRect; /+Rect result = defaultRect; return result;+/ } } void print38(Rect r) { writefln("(%d, %d)-(%d, %d)", r.left, r.top, r.right, r.bottom); assert(r.left == 0); assert(r.right == 0); assert(r.top == 0); assert(r.bottom == 0); } Rect defaultRect() { return Rect.init; } /************************************************/ void test39() { double[][] foo = [[1.0],[2.0]]; writeln(foo[0]); // --> [1] , ok writeln(foo[1]); // --> [2] , ok writeln(foo); // --> [[1],4.63919e-306] ack! writefln("%s", foo); // --> ditto auto f = std.string.format("%s", foo); assert(f == "[[1], [2]]"); double[1][2] bar; bar[0][0] = 1.0; bar[1][0] = 2.0; writeln(bar); // Error: Access violation auto r = std.string.format("%s", bar); assert(r == "[[1], [2]]"); } /************************************************/ void test40() { int[char] x; x['b'] = 123; writeln(x); auto r = std.string.format("%s", x); assert(r == "['b':123]"); writeln(x['b']); } /************************************************/ void test41() { } /************************************************/ enum Enum42 { A = 1 } void test42() { Enum42[] enums = new Enum42[1]; assert(enums[0] == Enum42.A); } /************************************************/ struct A43 {} struct B43(L) { A43 l; } void test43() { A43 a; auto b = B43!(A43)(a); } /************************************************/ void test44() { int[ const char[] ] a = ["abc":3, "def":4]; } /************************************************/ void test45() { //char[3][] a = ["abc", "def"]; //writefln(a); //char[][2] b = ["abc", "def"]; //writefln(b); } /************************************************/ struct bignum { bool smaller() { if (true) return false; else return false; assert(0); } void equal() { if (!smaller) return; } } void test46() { } /************************************************/ static size_t myfind(string haystack, char needle) { foreach (i, c ; haystack) { if (c == needle) return i; } return size_t.max; } static size_t skip_digits(string s) { foreach (i, c ; s) { if (c < '0' || c > '9') return i; } return s.length; } static uint matoi(string s) { uint result = 0; foreach (c ; s) { if (c < '0' || c > '9') break; result = result * 10 + (c - '0'); } return result; } enum { leading, skip, width, modifier, format, fmt_length, extra }; static string GetFormat(string s) { uint pos = 0; string result; // find the percent sign while (pos < s.length && s[pos] != '%') { ++pos; } const leading_chars = pos; result ~= cast(char) pos; if (pos < s.length) ++pos; // go right after the '%' // skip? if (pos < s.length && s[pos] == '*') { result ~= 1; ++pos; } else { result ~= 0; } // width? result ~= cast(char) matoi(s); pos += skip_digits(s[pos .. $]); // modifier? if (pos < s.length && myfind("hjlLqtz", s[pos]) != size_t.max) { // @@@@@@@@@@@@@@@@@@@@@@@@@@@@ static if (true) { result ~= s[pos++]; } else { result ~= s[pos]; ++pos; } // @@@@@@@@@@@@@@@@@@@@@@@@@@@@ } else { result ~= '\0'; } return result; } void test47() { static string test = GetFormat(" %*Lf"); assert(test[modifier] == 'L', "`" ~ test[modifier] ~ "'"); } /************************************************/ class B48() {} class C48 {} int foo48()(B48!()) { return 1; } int foo48()(C48 c) { return 2; } void test48() { auto i = foo48(new B48!()); assert(i == 1); i = foo48(new C48); assert(i == 2); } /************************************************/ void test49() { struct A { int v; } A a = A(10); version (all) { writefln("Before test 1: ", a.v); if (a == a.init) { writeln(a.v,"(a==a.init)"); assert(0); } else { writeln(a.v,"(a!=a.init)"); assert(a.v == 10); } } else { writefln("Before test 1: ", a.v); if (a == a.init) { writeln(a.v,"(a==a.init)"); assert(a.v == 10); } else { writeln(a.v,"(a!=a.init)"); assert(0); } } a.v = 100; writefln("Before test 2: ", a.v); if (a == a.init) { writeln(a.v,"(a==a.init)"); assert(0); } else { writeln(a.v,"(a!=a.init)"); assert(a.v == 100); } a = A(1000); writefln("Before test 3: ", a.v); if (a == a.init) { writeln(a.v,"(a==a.init)"); assert(0); } else { writeln(a.v,"(a!=a.init)"); assert(a.v == 1000); } version (all) assert(a.init.v == 0); else assert(a.init.v == 10); } /************************************************/ struct S51 { int i = 3; void div() { assert(i == 3); } } void test51() { S51().div(); } /************************************************/ void test52() { struct Foo { alias int Y; } with (Foo) { Y y; } } /************************************************/ struct TestStruct { int dummy0 = 0; int dummy1 = 1; int dummy2 = 2; } void func53(TestStruct[2] testarg) { writeln(testarg[0].dummy0); writeln(testarg[0].dummy1); writeln(testarg[0].dummy2); writeln(testarg[1].dummy0); writeln(testarg[1].dummy1); writeln(testarg[1].dummy2); assert(testarg[0].dummy0 == 0); assert(testarg[0].dummy1 == 1); assert(testarg[0].dummy2 == 2); assert(testarg[1].dummy0 == 0); assert(testarg[1].dummy1 == 1); assert(testarg[1].dummy2 == 2); } TestStruct m53[2]; void test53() { writeln(&m53); func53(m53); } /************************************************/ void test54() { double a = 0; double b = 1; // Internal error: ..\ztc\cg87.c 3233 // a += (1? b: 1+1i)*1i; writeln(a); // assert(a == 0); // Internal error: ..\ztc\cod2.c 1680 // a += (b?1:b-1i)*1i; writeln(a); // assert(a == 0); } /************************************************/ class B55 {} class D55 : B55 {} template foo55(S, T : S) { } // doesn't work alias foo55!(B55, D55) bar55; void test55() { } /************************************************/ template t56() { alias Object t56; } pragma(msg, t56!().stringof); void test56() { } /************************************************/ void test57() { alias long[char[]] AA; static if (is(AA T : T[U], U : const char[])) { writeln(typeid(T)); writeln(typeid(U)); assert(is(T == long)); assert(is(U == const(char)[])); } static if (is(AA A : A[B], B : int)) { assert(0); } static if (is(int[10] W : W[V], int V)) { writeln(typeid(W)); assert(is(W == int)); writeln(V); assert(V == 10); } static if (is(int[10] X : X[Y], int Y : 5)) { assert(0); } } /************************************************/ static this() { printf("one\n"); } static this() { printf("two\n"); } static ~this() { printf("~two\n"); } static ~this() { printf("~one\n"); } void test59() { } /************************************************/ class C60 { extern (C++) int bar60(int i, int j, int k) { printf("this = %p\n", this); printf("i = %d\n", i); printf("j = %d\n", j); printf("k = %d\n", k); assert(i == 4); assert(j == 5); assert(k == 6); return 1; } } extern (C++) int foo60(int i, int j, int k) { printf("i = %d\n", i); printf("j = %d\n", j); printf("k = %d\n", k); assert(i == 1); assert(j == 2); assert(k == 3); return 1; } void test60() { foo60(1, 2, 3); C60 c = new C60(); c.bar60(4, 5, 6); } /***************************************************/ template Foo61(alias a) {} struct Bar61 {} const Bar61 bar61 = {}; alias Foo61!(bar61) baz61; void test61() { } /************************************************/ T foo62(T)(lazy T value) { return value; } void test62() { foo62(new float[1]); } /************************************************/ void main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test51(); test52(); test53(); test54(); test55(); test56(); test57(); test59(); test60(); test61(); test62(); writefln("Success"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/traits_getUnitTests.d0000664000175000017500000000317712776215022024411 0ustar kaikai// REQUIRED_ARGS: -unittest // EXTRA_SOURCES: imports/traits_getUnitTests_import.d module traits_getUnitTests; import imports.traits_getUnitTests_import; template Tuple (T...) { alias Tuple = T; } int i; unittest { i++; } void test_getUnitTestsFromModule () { static assert(__traits(getUnitTests, mixin(__MODULE__)).length == 1); } struct SGetUnitTestsFromAggregate { unittest {} } class CGetUnitTestsFromAggregate { unittest {} } void test_getUnitTestsFromAggregate () { static assert(__traits(getUnitTests, SGetUnitTestsFromAggregate).length == 1); static assert(__traits(getUnitTests, CGetUnitTestsFromAggregate).length == 1); } void test_callUnitTestFunction () { __traits(getUnitTests, mixin(__MODULE__))[0](); assert(i == 2); // 2, because the standard unit test runner // will call the unit test function as well } struct GetUnitTestsWithUDA { @("asd") unittest {} } void test_getUnitTestsWithUDA () { alias tests = Tuple!(__traits(getUnitTests, GetUnitTestsWithUDA)); static assert(tests.length == 1); static assert(__traits(getAttributes, tests[0]).length == 1); } void test_getUnitTestsFromImport () { static assert(__traits(getUnitTests, imports.traits_getUnitTests_import).length == 1); static assert(__traits(getUnitTests, mixin("imports.traits_getUnitTests_import")).length == 1); } // 11358 debug { } enum len11358 = __traits(getUnitTests, mixin(__MODULE__)).length; void main () { test_getUnitTestsFromModule(); test_getUnitTestsFromAggregate(); test_callUnitTestFunction(); test_getUnitTestsWithUDA(); test_getUnitTestsFromImport(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/bug7068.d0000664000175000017500000000045012776215022021452 0ustar kaikai// PERMUTE_ARGS: -inline -g -O -d void main() { auto darray1 = new int*[](10); foreach(ref v; darray1) v = new int; auto darray2 = new int*[](10); darray2[] = darray1[]; // calls memset instead of memcpy foreach(i; 0 .. 10) assert(darray1[i] == darray2[i]); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link14198a.sh0000775000175000017500000000152212776215022022250 0ustar kaikai#!/usr/bin/env bash src=runnable${SEP}extra-files dir=${RESULTS_DIR}${SEP}runnable output_file=${dir}/link14198a.sh.out if [ $OS == "win32" -o $OS == "win64" ]; then LIBEXT=.lib else LIBEXT=.a fi libname=${dir}${SEP}lib14198a${LIBEXT} # build library $DMD -m${MODEL} -I${src} -of${libname} -lib ${src}${SEP}std14198${SEP}array.d ${src}${SEP}std14198${SEP}conv.d ${src}${SEP}std14198${SEP}format.d ${src}${SEP}std14198${SEP}uni.d || exit 1 # Do not link failure with library file, regardless the semantic order. $DMD -m${MODEL} -I${src} -of${dir}${SEP}test14198a${EXE} ${src}${SEP}test14198.d ${libname} || exit 1 $DMD -m${MODEL} -I${src} -of${dir}${SEP}test14198a${EXE} -version=bug14198 ${src}${SEP}test14198.d ${libname} || exit 1 rm ${libname} rm ${dir}/{test14198a${OBJ},test14198a${EXE}} echo Success > ${output_file} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/bug12928.d0000664000175000017500000000031212776215022021530 0ustar kaikai// PERMUTE_ARGS: -inline -g -O import core.exception : RangeError; void main(string[] args) { int[2] a; try { foreach(const i; 0..3) a[i] = i; assert(0); } catch(RangeError){} } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link846.sh0000775000175000017500000000107012776215022021740 0ustar kaikai#!/usr/bin/env bash set -e src=runnable${SEP}extra-files dir=${RESULTS_DIR}${SEP}runnable output_file=${dir}/link846.sh.out if [ $OS == "win32" -o $OS == "win64" ]; then LIBEXT=.lib else LIBEXT=.a fi libname=${dir}${SEP}link846${LIBEXT} # build library with -release $DMD -m${MODEL} -I${src} -of${libname} -release -boundscheck=off -lib ${src}${SEP}lib846.d # use lib with -debug $DMD -m${MODEL} -I${src} -of${dir}${SEP}link846${EXE} -debug ${src}${SEP}main846.d ${libname} rm ${libname} rm ${dir}/{link846${OBJ},link846${EXE}} echo Success > ${output_file} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/objc_self_test.d0000664000175000017500000000023712776215022023340 0ustar kaikai// EXTRA_OBJC_SOURCES: objc_self_test.m // REQUIRED_ARGS: -L-framework -LFoundation extern (C) int getValue(); void main () { assert(getValue() == 3); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testbounds_on.d0000664000175000017500000000120412776215022023234 0ustar kaikai// REQUIRED_ARGS: -boundscheck=on // PERMUTE_ARGS: -inline -g -O import core.exception : RangeError; // Check for RangeError is thrown bool thrown(T)(lazy T cond) { import core.exception; bool f = false; try { cond(); } catch (RangeError e) { f = true; } return f; } @safe int safeIndex (int[] arr) { return arr[2]; } @trusted int trustedIndex(int[] arr) { return arr[2]; } @system int systemIndex (int[] arr) { return arr[2]; } void main() { int[3] data = [1,2,3]; int[] arr = data[0..2]; assert(arr. safeIndex().thrown); assert(arr.trustedIndex().thrown); assert(arr. systemIndex().thrown); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test9309.d0000664000175000017500000000123012776215022021651 0ustar kaikaiimmutable(T)[] assumeUnique(T)(ref T[] array) pure nothrow { auto result = cast(immutable(T)[]) array; array = null; return result; } pure nothrow private string escapeShellArguments() { char[] buf; @safe nothrow char[] allocator(size_t size) { return buf = new char[size]; } escapeShellArgument!allocator("foo"); return assumeUnique(buf); } @safe nothrow auto escapeShellArgument(alias allocator)(in char[] arg) { auto buf = allocator(4); buf[0] = 'f'; buf[1] = 'o'; buf[2] = 'o'; buf[3] = '\0'; } void main() { string res = escapeShellArguments(); if (res != "foo\0") assert(0); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testgc2.d0000664000175000017500000000145212776215022021726 0ustar kaikai// PERMUTE_ARGS: module testgc2; import core.stdc.stdio; import core.exception : OutOfMemoryError; /*******************************************/ void test1() { printf("This should not take a while\n"); try { long[] l = new long[ptrdiff_t.max]; printf("%lu\n", cast(ulong)l.capacity); // Make sure l is not optimized out. assert(0); } catch (OutOfMemoryError o) { } printf("This may take a while\n"); try { byte[] b = new byte[size_t.max / 3]; printf("%lu\n", cast(ulong)b.capacity); // Make sure b is not optimized out. version (Windows) assert(0); } catch (OutOfMemoryError o) { } } /*******************************************/ void main() { test1(); printf("Success\n"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test20.d0000664000175000017500000004624612776215022021506 0ustar kaikaiimport core.vararg; extern(C) int printf(const char*, ...); /*****************************************/ class A1 { union { struct { int x; public int y; } protected int z; } } class A2 { struct { int x; public int y; } } class A3 { union { int x; public int y; } } void test1() { A1 a1 = new A1(); A2 a2 = new A2(); A3 a3 = new A3(); a1.x = 1; a1.y = 2; a1.z = 3; assert(a1.x == 3); assert(a1.y == 2); a2.x = 1; a2.y = 2; assert(a2.x == 1); a3.x = 1; a3.y = 2; assert(a3.x == 2); } /*****************************************/ struct A4 { union { struct { int x = 13; } int y; } } void test4() { printf("A4.sizeof = %d\n", A4.sizeof); assert(A4.sizeof == 1 * int.sizeof); A4 q; assert(q.y == 13); } /*****************************************/ class A5 { union { struct { int x; } public int y; } } void test5() { A5 a = new A5; a.x = 3; a.y = 4; assert(a.x == 4); } /*****************************************/ int i6 = 5; float m6 = 5.0; void test6() { void f() { void i6(float j) { m6 = j; } void g() { i6 = 1; } g(); } f(); printf( "%d %f\n", i6, m6); assert(i6 == 5); assert(m6 == 1); } /*****************************************/ const int a1 = 50; const int a2 = 50; const int a3 = a1 * a2; const int b1 = a1 - 1; const int b2 = a2 - 1; const int c1 = 50*50; const int c2 = (a1-1)*(a2-1); const int c3 = b1*b2; int[4*c1] array1; // illegal! int[4*c2] array2; // illegal! int[4*c3] array3; // illegal! int[a3] array4; // valid! no error! void test7() { assert(a1 == 50); assert(a2 == 50); assert(a3 == 2500); assert(b1 == 49); assert(b2 == 49); assert(c1 == 2500); assert(c2 == 2401); assert(c3 == 2401); assert(array1.length == 10000); assert(array2.length == 9604); assert(array3.length == 9604); } /*****************************************/ struct Foo8 { static Foo8 bar() { Foo8 res; return res; } } void test8() { Foo8[8] x; x[] = Foo8.bar; } /*****************************************/ void test9() { try { } catch (Exception e) { debug printf("Exception happened\n"); } } /*****************************************/ struct Foo10 { const bool opEquals(const ref Foo10 x) { return this.normalize is x.normalize; } const Foo10 normalize() { Foo10 res; return res; } } void test10() { } /*****************************************/ scope class T11 { this(){} ~this(){} } void test11() { scope T11 t=new T11(); int i=1; switch(i) { case 1: break; default: break; } } /*****************************************/ void test12() { char[] s; char[] t; if (true) s = null; s = (true) ? null : t; t = (true) ? s : null; } /*****************************************/ class Foo13 { int init (int x) { return 1; } static int init (long y) { return 2; } } void test13() { Foo13 f = new Foo13(); int i; i = f.init(1); assert(i == 1); i = f.init(1L); assert(i == 2); } /*****************************************/ void write14(bool[] c) { printf("[%2d]: ", c.length); foreach (bool x; c) printf("%d,", x); printf("\n"); } void test14() { static bool[] a = [ 1, 1, 0, 1, 0 ]; static bool[] b = [ 1, 0, 0, 1 ]; bool[] c = a ~ b; static bool[] r1 = [1,1,0,1,0,1,0,0,1]; static bool[] r2 = [1,1,0,1,0,1,0,0,1,1,1,0,1,0]; static bool[] r3 = [1,1,0,1,0,1,0,0,1,1,1,0,1,0,0]; static bool[] r4 = [1,1,0,1,0,1,0,0,1,1,1,0,1,0,0,1]; write14(c); assert(c == r1); c ~= a; write14(c); assert(c == r2); c ~= 0; write14(c); assert(c == r3); c ~= 1; write14(c); assert(c == r4); } /*****************************************/ void test15() { bool[] b; bool[] c; b.length = 10; c = b[0..4]; c[] = true; assert(b[0] == true); assert(b[1] == true); assert(b[2] == true); assert(b[3] == true); assert(b[4] == false); assert(b[5] == false); assert(b[6] == false); assert(b[7] == false); assert(b[8] == false); assert(b[9] == false); } /*****************************************/ int y16; class C16 { new(size_t size, byte blah){ void* v = (new byte[C16.classinfo.init.length]).ptr; y16 = 1; assert(blah == 3); return v; } int x; this() { x = 4; } } void test16() { C16 c = new(3) C16; assert(y16 == 1); assert(c.x == 4); } /*****************************************/ ubyte* ptr17; void test17() { ubyte[16] foo; printf("foo = %p\n", foo.ptr); ptr17 = foo.ptr; abc17(foo); } void abc17(ref ubyte[16] bar) { printf("bar = %p\n", bar.ptr); assert(bar.ptr == ptr17); } /*****************************************/ struct Iterator18(T) { T* m_ptr; const bool opEquals(const ref Iterator18 iter) { return (m_ptr == iter.m_ptr); } const int opCmp(const ref Iterator18 iter) { return cast(int)(m_ptr - iter.m_ptr); } } void test18() { Iterator18!(int) iter; } /*****************************************/ struct S29(T) { const bool opEquals(const ref S29!(T) len2) { return 0; } const int opCmp(const ref S29!(T) len2) { return 0; } } void test19() { TypeInfo info = typeid(S29!(int)); } /*****************************************/ class Mapped : Buffer { this() { } ~this() { } } class Buffer { private uint limit; private uint capacity; private uint position; invariant() { assert (position <= limit); assert (limit <= capacity); } } void test20() { Buffer b = new Buffer(); delete b; } /*****************************************/ class T21 { char[1] p1; char[1] p2; public: char[] P() {return p1~p2;} } void test21() { T21 t = new T21; t.p1[0] = 'a'; t.p2[0] = 'b'; assert(t.P() == "ab"); } /*****************************************/ void test22() { struct foo1 { int a; int b; int c; } class foo2 { foo1[] x; foo1 fooret(foo1 foo2) { x.length = 9; return x[0] = foo2; // Here // x[0] = foo2; --- This version does not // return x[0]; --- cause the error. } } } /*****************************************/ void test23() { float f; double d; real r; if (f > ifloat.max) goto Loverflow; if (d > ifloat.max) goto Loverflow; if (r > ifloat.max) goto Loverflow; if (ifloat.max < f) goto Loverflow; if (ifloat.max < d) goto Loverflow; if (ifloat.max < r) goto Loverflow; return; Loverflow: return; } /*****************************************/ interface I24 { } void test24() { } /*****************************************/ interface D25{} interface C25:D25{} interface B25:C25{} interface A25:B25{} void test25() { } class A26:B26{} interface B26:C26{} interface C26:D26{} interface D26{} void test26() { } interface A27:B27{} interface B27:C27{} interface C27:D27{} interface D27{} void test27() { } /*****************************************/ void test28() { const double d = -1.0; int i = cast(int)d; printf("i = %d\n", i); assert(-1 == i); } /*****************************************/ static int[1][5] array = [[1],[2],[3],[4],[5] ]; void Lookup( int which ) { switch( which ) { case 0 : return cast(void)array[which]; default: assert(0); } } void test29() { } /*****************************************/ void test30() { double d = 1; cdouble cd = 1+0i; assert(cd == 1.0 + 0i); } /*****************************************/ void foo31(...) { byte b = va_arg!byte(_argptr); assert(b == 8); } void test31() { byte x = 9; foo31(--x); --x; foo31(++x); } /*****************************************/ template Foo33(T, int L) { T[L] arr; class Bar { int before = 6; T[L] arr; int after = 7; } } void test33() { alias Foo33!(int, 100) foo; foreach (int x; foo.arr) assert(x == int.init); foo.Bar bar = new foo.Bar(); foreach (int x; bar.arr) { //printf("%d\n", x); assert(x == int.init); } } /*****************************************/ void test34() { bool[1] a; bool[1] b; bool[] concat() { return a~b; } a[]=0; b[]=1; bool[] arr=concat(); assert(arr.length==2); assert(arr[0]==0); assert(arr[1]==1); } /*****************************************/ void dummy35(...) {} void test35() { byte x = 9; dummy35(x); int y = --x; assert (y == 8); assert (x == 8); } /*****************************************/ void test36() { int[] a; a.length = 2; a[0]=1; a[1]=2; int[] b; b.length = 1; b[0]=3; a~=b; assert(a.length==3); assert(a[0]==1); assert(a[1]==2); assert(a[2]==3); assert(b.length==1); assert(b[0]==3); } /*****************************************/ struct Range{ int width(){ return 1; } } class Container { Range opIndex(int i){ return data[i]; } Range[2] data; } void test37() { Container ranges=new Container; // fails with -inline // assert(ranges[0].width() == 1); } /*****************************************/ void test38() { uint mask = (uint.max >> 1); assert(mask == (uint.max >> 1)); } /*****************************************/ void test39() { char[] a; char[] r; a = "abcd".dup; r = a.reverse; assert(r=="dcba"); assert(r.ptr==a.ptr); a = "-\U000000A1\U00000901\U0000FFEE\U00010000\U000FFFFD_".dup; r = a.reverse; assert(r == "_\U000FFFFD\U00010000\U0000FFEE\U00000901\U000000A1-"); assert(a.ptr==r.ptr); } /*****************************************/ void test40() { wchar[] a; wchar[] r; a = "abcd"w.dup; a = a.dup; r = a.reverse; assert(r=="dcba"); assert(r.ptr==a.ptr); a = "-\U000000A1\U00000901\U0000FFEE\U00010000\U000FFFFD_"w.dup; a = a.dup; r = a.reverse; assert(r == "_\U000FFFFD\U00010000\U0000FFEE\U00000901\U000000A1-"); assert(a.ptr==r.ptr); } /*****************************************/ void test41() { assert(new void[40] == new void[40]); } /*****************************************/ void test42() { static ubyte[] master = [ 0xE3u, 0x83u, 0xAFu, 0xE3u, 0x83u, 0xADu, 0xE3u, 0x82u, 0xB9u, 0xEFu, 0xBDu, 0x97u ]; string string1 = "ワロスw"; string string2 = r"ワロスw"; string string3 = `ワロスw`; string string4 = x"E3 83 AF E3 83 AD E3 82 B9 EF BD 97"; assert(string1.length==master.length); for(int i=0; i= i; j -= i) { // interesting results follow from this: printf("%d ", i); // it prints a _lot_ of ones arr[j] = arr[j - i]; } } void test61() { real[] array; array.length = 2; // whatever, as long as it's more than 1 foreach (ref real i; array) i = 1; // just something foo61(array); } /*****************************************/ void bug7493() { string str = "abcde"; const(void) [][1] arr = [str]; assert(arr[0].length == str.length); const(void) [][1] arr2; arr2 = [str]; assert(arr[0].length == str.length); } /*****************************************/ int main() { test1(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test50(); test51(); test52(); test53(); test54(); test55(); test56(); test57(); test58(); test59(); test60(); test61(); bug7493(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/objc_call.d0000664000175000017500000000104312776215022022257 0ustar kaikai// EXTRA_OBJC_SOURCES // REQUIRED_ARGS: -L-framework -LFoundation extern (Objective-C) interface Class { NSObject alloc() @selector("alloc"); } extern (Objective-C) interface NSObject { NSObject initWithUTF8String(in char* str) @selector("initWithUTF8String:"); void release() @selector("release"); } extern (C) void NSLog(NSObject, ...); extern (C) Class objc_lookUpClass(in char* name); void main() { auto c = objc_lookUpClass("NSString"); auto o = c.alloc().initWithUTF8String("hello"); NSLog(o); o.release(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test5943.d0000664000175000017500000000430512776215022021657 0ustar kaikai// test that the import of std.math is not needed __gshared uint x0 = 0; __gshared uint x1 = 1; __gshared uint x2 = 2; __gshared uint x3 = 3; __gshared uint x4 = 4; __gshared uint x5 = 5; __gshared uint x6 = 6; __gshared uint x7 = 7; __gshared uint x10 = 10; __gshared uint x15 = 15; __gshared uint x31 = 31; __gshared uint x32 = 32; void main() { assert(2 ^^ x0 == 1); assert(2 ^^ x1 == 2); assert(2 ^^ x31 == 0x80000000); assert(4 ^^ x0 == 1); assert(4 ^^ x1 == 4); assert(4 ^^ x15 == 0x40000000); assert(8 ^^ x0 == 1); assert(8 ^^ x1 == 8); assert(8 ^^ x10 == 0x40000000); assert(16 ^^ x0 == 1); assert(16 ^^ x1 == 16); assert(16 ^^ x7 == 0x10000000); assert(32 ^^ x0 == 1); assert(32 ^^ x1 == 32); assert(32 ^^ x6 == 0x40000000); assert(64 ^^ x0 == 1); assert(64 ^^ x1 == 64); assert(64 ^^ x5 == 0x40000000); assert(128 ^^ x0 == 1); assert(128 ^^ x1 == 128); assert(128 ^^ x4 == 0x10000000); assert(256 ^^ x0 == 1); assert(256 ^^ x1 == 256); assert(256 ^^ x3 == 0x1000000); assert(512 ^^ x0 == 1); assert(512 ^^ x1 == 512); assert(512 ^^ x3 == 0x8000000); assert(1024 ^^ x0 == 1); assert(1024 ^^ x1 == 1024); assert(1024 ^^ x3 == 0x40000000); assert(2048 ^^ x0 == 1); assert(2048 ^^ x1 == 2048); assert(2048 ^^ x2 == 0x400000); assert(4096 ^^ x0 == 1); assert(4096 ^^ x1 == 4096); assert(4096 ^^ x2 == 0x1000000); assert(8192 ^^ x0 == 1); assert(8192 ^^ x1 == 8192); assert(8192 ^^ x2 == 0x4000000); assert(16384 ^^ x0 == 1); assert(16384 ^^ x1 == 16384); assert(16384 ^^ x2 == 0x10000000); assert(32768 ^^ x0 == 1); assert(32768 ^^ x1 == 32768); assert(32768 ^^ x2 == 0x40000000); assert(65536 ^^ x0 == 1); assert(65536 ^^ x1 == 65536); assert(131072 ^^ x0 == 1); assert(131072 ^^ x1 == 131072); assert(262144 ^^ x0 == 1); assert(262144 ^^ x1 == 262144); assert(524288 ^^ x0 == 1); assert(524288 ^^ x1 == 524288); assert(1048576 ^^ x0 == 1); assert(1048576 ^^ x1 == 1048576); assert(2097152 ^^ x0 == 1); assert(2097152 ^^ x1 == 2097152); assert(4194304 ^^ x0 == 1); assert(4194304 ^^ x1 == 4194304); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link11069b.d0000664000175000017500000000042012776215022022045 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/link11069x.d // EXTRA_SOURCES: imports/link11069y.d // EXTRA_SOURCES: imports/link11069z.d import imports.link11069y; import imports.link11069z; void foo() { Vector2 rsm; readWriteVariable(rsm); } void main() { } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/template3.d0000664000175000017500000000701512776215022022252 0ustar kaikai import core.stdc.stdio; /*********************************************************/ template Foo(T) { static if (is(T : int)) alias T t1; static if (T.sizeof == 4) alias T t2; static if (is(T U : int)) alias U t3; static if (is(T* V : V*)) alias V t4; static if (is(T W)) alias W t5; else alias char t5; static if (is(T* X : X*)) { } } void test1() { Foo!(int).t1 x1; assert(typeid(typeof(x1)) == typeid(int)); Foo!(int).t2 x2; assert(typeid(typeof(x2)) == typeid(int)); Foo!(int).t3 x3; assert(typeid(typeof(x3)) == typeid(int)); Foo!(int*).t4 x4; assert(typeid(typeof(x4)) == typeid(int*)); Foo!(int).t5 x5; assert(typeid(typeof(x5)) == typeid(int)); Foo!(int).X x6; assert(typeid(typeof(x6)) == typeid(int)); } /*********************************************************/ void test2() { alias int T; static if (is(T : int)) alias T t1; static if (T.sizeof == 4) alias T t2; static if (is(T U : int)) alias U t3; static if (is(T* V : V*)) alias V t4; static if (is(T W)) alias W t5; else alias char t5; static if (is(T* X : X*)) { } t1 x1; assert(typeid(typeof(x1)) == typeid(int)); t2 x2; assert(typeid(typeof(x2)) == typeid(int)); t3 x3; assert(typeid(typeof(x3)) == typeid(int)); t4 x4; assert(typeid(typeof(x4)) == typeid(int)); t5 x5; assert(typeid(typeof(x5)) == typeid(int)); X x6; assert(typeid(typeof(x6)) == typeid(int)); } /*********************************************************/ void test3() { static if (is(short : int)) { printf("1\n"); } else assert(0); static if (is(short == int)) assert(0); static if (is(int == int)) { printf("3\n"); } else assert(0); } /*********************************************************/ template TValue(int i:1) { pragma(msg,"last instantiation!!!"); const int TValue = 1; } template TValue(int i) { pragma(msg,"instantiating..."); const int TValue = i * TValue!(i-1); } void test4() { assert(TValue!(3) == 6); } /*********************************************************/ template Reverse(string s: "") { const char[] Reverse = ""; } template Reverse(string s) { const char[] Reverse = Reverse!(s[1..$]) ~ s[0]; } void test5() { assert(Reverse!("Recursive string template") == "etalpmet gnirts evisruceR"); } /*********************************************************/ template foo6(alias V) { int foo6() { return V; } } class bar6(alias V) { int abc() { return V; } } void test6() { int j = 3; int k = 4; int i = foo6!(j)(); i += foo6!(j)(); i += foo6!(k)(); bar6!(j) b = new bar6!(j); i -= b.abc(); assert(i == 7); } /*********************************************************/ template Bind7(alias dg) { int Bind7() { dg('c'); return 0; } } void test7() { char[] v; void foo(char c) { v ~= c; } alias Bind7!(foo) intv; intv(); assert(v[0] == 'c'); } /*********************************************************/ template sum8(real x) { static if (x <= 1.0L){ const real sum8 = x; }else{ const real sum8 = x + sum8!(x - 1.0L); } } void test8() { real x = sum8!(3.0L); if(x != 6.0L){ assert(0); } } /*********************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testconst.d0000664000175000017500000030745112776215022022411 0ustar kaikai import core.stdc.stdio; class C { } int ctfe() { return 3; } template TypeTuple(T...) { alias T TypeTuple; } /************************************/ void showf(string f) { printf("%.*s\n", f.length, f.ptr); } /************************************/ void test1() { const int* p; const(int)* cp; cp = p; } /************************************/ void test2() { const int i = 3; const(int) j = 0; int k; // j = i; k = i; k = j; // assert(k == 3); } /************************************/ void test3() { char[3] p; const(char)[] q; q = p; } /************************************/ void test4() { char[] p; const(char)[] q; q = p; } /************************************/ void test5() { const(int**)* p; const(int)*** cp; p = cp; } /************************************/ void test6() { const(int***)[] p; const(int)***[] cp; p = cp; } /************************************/ class C8 { } void foo8(const char[] s, const C8 c, const int x) { } void test8() { auto p = &foo8; showf(p.mangleof); assert(typeof(p).mangleof == "PFxAaxC9testconst2C8xiZv"); assert(p.mangleof == "_D9testconst5test8FZ1pPFxAaxC9testconst2C8xiZv"); } /************************************/ void test9() { int [ const (char[]) ] aa; int [ char[] ] ab; int [ const char[] ] ac; aa["hello"] = 3; ab["hello"] = 3; ac["hello"] = 3; } /************************************/ void test10() { const(int) x = 3; auto y = x; //y++; assert(is(typeof(y) == const(int))); } /************************************/ void foo11(in char[] a1) { char[3] c; char[] a2 = c[]; a2[0..2] = a1; a2[0..2] = 'c'; const char b = 'b'; a2[0..2] = b; } void test11() { } /************************************/ void foo12(const char[] a1) { } void test12() { foo12("hello"); } /************************************/ immutable char[16] hexdigits1 = "0123456789ABCDE1"; immutable char[ ] hexdigits2 = "0123456789ABCDE2"; const char[16] hexdigits3 = "0123456789ABCDE3"; const char[ ] hexdigits4 = "0123456789ABCDE4"; void test13() { } /************************************/ void test14() { string s; s = s ~ "hello"; } /************************************/ class Foo15 { const string xxxx; this(immutable char[] aaa) { this.xxxx = aaa; } } void test15() { } /************************************/ void test16() { auto a = "abc"; immutable char[3] b = "abc"; const char[3] c = "abc"; } /************************************/ void test17() { const(char)[3][] a = (["abc", "def"]); assert(a[0] == "abc"); assert(a[1] == "def"); } /************************************/ class C18 { const(char)[] foo() { return "abc"; } } class D18 : C18 { override char[] foo() { return null; } } void test18() { } /************************************/ void test19() { char[] s; if (s == "abc") s = null; if (s < "abc") s = null; if (s is "abc") s = null; } /************************************/ void test20() { string p; immutable char[] q; p = p ~ q; p ~= q; } /************************************/ void test21() { string s; char[] p; p = s.dup; } /************************************/ void fill22(const(char)[] s) { } void test22() { } /************************************/ struct S23 { int x; int* p; } void foo23(const(S23) s, const(int) i) { immutable int j = 3; // j = 4; // i = 4; // s.x = 3; // *s.p = 4; } void test23() { } /************************************/ void test24() { wchar[] r; r ~= "\000"w; } /************************************/ void test25() { char* p; if (p == cast(const(char)*)"abc") {} } /************************************/ void test26() { struct S { char[3] a; } static S s = { "abc" }; } /************************************/ class C27 { int x; void foo() { x = 3; } } void test27() { C27 d = new C27; d.foo(); } /************************************/ class C28 { int x; void foo() immutable { } } void test28() { immutable(C28) d = cast(immutable)new C28; d.foo(); } /************************************/ struct S29 { } int foo29(const(S29)* s) { S29 s2; return *s == s2; } void test29() { } /************************************/ struct S30 { int x; void foo() { x = 3; } void bar() const { //x = 4; //this.x = 5; } } class C30 { int x; void foo() { x = 3; } void bar() const { //x = 4; //this.x = 5; } } void test30() { S30 s; s.foo(); s.bar(); S30 t; //t.foo(); t.bar(); C30 c = new C30; c.foo(); c.bar(); C30 d = new C30; d.foo(); d.bar(); } /************************************/ class Foo31 { int x; immutable immutable(int)* geti() { return &x; } const const(int)* getc() { return &x; } } void test31() { } /************************************/ int bar32; struct Foo32 { int func() immutable { return bar32; } } void test32() { immutable(Foo32) foo; printf("%d", foo.func()); printf("%d", foo.func()); } /************************************/ void test33() { string d = "a" ~ "b" ~ (1?"a":""); assert(d == "aba"); } /************************************/ struct S34 { int value; } const S34 s34 = { 5 }; const S34 t34 = s34; const S34 u34 = s34; void test34() { assert(u34.value == 5); } /************************************/ const int i35 = 20; template Foo35(alias bar) { } alias Foo35!(i35) foo35; void test35() { } /************************************/ immutable char[10] digits = "0123456789"; /// 0..9 immutable char[] octdigits = digits[0 .. 8]; //// 0..7 void test36() { } /************************************/ void test37() { int i = 3; const int x = i; i++; assert(x == 3); } /************************************/ void test38() { static const string s = "hello"[1..$]; assert(s == "ello"); } /************************************/ static const int x39; const int y39; static this() { x39 = 3; y39 = 4; } void test39() { const int i; assert(x39 == 3); assert(y39 == 4); const p = &x39; // assert(*p == 3); } /************************************/ struct S40 { int a; const int b = 3; // shouldn't be allocated } void test40() { assert(S40.sizeof == 8); assert(S40.init.b == 3); } /************************************/ struct S41 { int a; const int b; static const int c = ctfe() + 1; } void test41() { assert(S41.sizeof == 8); S41 s; assert(s.b == 0); assert(S41.c == 4); const(int)*p; p = &s.b; assert(*p == 0); p = &s.c; assert(*p == 4); } /************************************/ class C42 { int a = ctfe() - 2; const int b; const int c = ctfe(); static const int d; static const int e = ctfe() + 2; static this() { d = 4; } this() { b = 2; } } void test42() { printf("%d\n", C42.classinfo.init.length); assert(C42.classinfo.init.length == 12 + (void*).sizeof + (void*).sizeof); C42 c = new C42; assert(c.a == 1); assert(c.b == 2); assert(c.c == 3); assert(c.d == 4); assert(c.e == 5); const(int)*p; p = &c.b; assert(*p == 2); p = &c.c; assert(*p == 3); p = &c.d; assert(*p == 4); p = &c.e; assert(*p == 5); } /************************************/ template Foo43(T) { alias T Foo43; } void test43() { { int x; alias Foo43!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == int)); assert(is(f == int)); } { const int x; alias Foo43!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == const(int))); assert(is(f == const(int))); } { immutable int x; alias Foo43!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == immutable(int))); assert(is(f == immutable(int))); } } /************************************/ template Foo44(T:T) { alias T Foo44; } void test44() { { int x; alias Foo44!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == int)); assert(is(f == int)); } { const int x; alias Foo44!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == const(int))); assert(is(f == const(int))); } { immutable int x; alias Foo44!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == immutable(int))); assert(is(f == immutable(int))); } } /************************************/ template Foo45(T:const(T)) { alias T Foo45; } void test45() { { int x; alias Foo45!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == int)); assert(is(f == int)); } { const int x; alias Foo45!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == const(int))); assert(is(f == int)); } { immutable int x; alias Foo45!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == immutable(int))); assert(is(f == int)); } } /************************************/ template Foo46(T:immutable(T)) { alias T Foo46; } void test46() { { immutable int x; alias Foo46!(typeof(x)) f; showf(typeid(f).toString()); assert(is(typeof(x) == immutable(int))); assert(is(f == int)); } } /************************************/ template Foo47(T:T) { const int Foo47 = 2; } template Foo47(T:const(T)) { const int Foo47 = 3; } template Foo47(T:immutable(T)) { const int Foo47 = 4; } void test47() { int x2; const int x3; immutable int x4; printf("%d\n", Foo47!(typeof(x2))); printf("%d\n", Foo47!(typeof(x3))); printf("%d\n", Foo47!(typeof(x4))); assert(Foo47!(typeof(x2)) == 2); assert(Foo47!(typeof(x3)) == 3); assert(Foo47!(typeof(x4)) == 4); } /************************************/ int foo48(T)(const(T) t) { return 3; } void test48() { const int x = 4; assert(foo48(x) == 3); } /************************************/ void foo49(T)(T[] t) { showf(typeid(typeof(t)).toString()); assert(is(T == immutable(char))); } void bar49(T)(const T t) { showf(typeid(T).toString()); assert(is(T == const(int)) || is(T == immutable(int)) || is(T == int)); } void test49() { string s; foo49(s); foo49("hello"); const int c = 1; bar49(c); immutable int i = 1; bar49(i); bar49(1); } /************************************/ void foo50(T)(T t) { showf(typeid(typeof(t)).toString()); assert(is(T == C)); } void baz50(T)(T t) { showf(typeid(typeof(t)).toString()); assert(is(T == const(C))); } void bar50(T)(const T t) { showf(typeid(T).toString()); showf(typeid(typeof(t)).toString()); assert(is(T == C)); assert(is(typeof(t) == const(C))); } void abc50(T)(const T t) { showf(typeid(T).toString()); showf(typeid(typeof(t)).toString()); assert(is(T == C)); assert(is(typeof(t) == const(C))); } void test50() { C c = new C; const(C) d = new C; foo50(c); baz50(d); bar50(c); abc50(d); } /************************************/ void test51() { const(C) d = new C; //d = new C; } /************************************/ template isStaticArray(T) { const bool isStaticArray = false; } template isStaticArray(T : T[N], size_t N) { const bool isStaticArray = true; } template isDynamicArray(T, U = void) { static const isDynamicArray = false; } template isDynamicArray(T : U[], U) { static const isDynamicArray = !isStaticArray!(T); } void test52() { immutable(char[5])[int] aa = ([3:"hello", 4:"betty"]); showf(typeid(typeof(aa.values)).toString()); static assert(isDynamicArray!(typeof(aa.values))); } /************************************/ void foo53(string n) { } void read53(in string name) { foo53(name); } void test53() { read53("hello"); } /************************************/ void bar54(const(wchar)[] s) { } void test54() { const(wchar)[] fmt; bar54("Orphan format specifier: %" ~ fmt); } /************************************/ struct S55 { int foo() { return 1; } int foo() const { return 2; } int foo() immutable { return 3; } } void test55() { S55 s1; auto i = s1.foo(); assert(i == 1); const S55 s2; i = s2.foo(); assert(i == 2); immutable S55 s3; i = s3.foo(); assert(i == 3); } /************************************/ const struct S56 { int a; } void test56() { S56 s; S56 t; printf("S56.sizeof = %d\n", S56.sizeof); //t = s; } /************************************/ struct S57 { const void foo(this T)(int i) { showf(typeid(T).toString()); if (i == 1) assert(is(T == const)); if (i == 2) assert(!is(T == const)); if (i == 3) assert(is(T == immutable)); } } void test57() { const(S57) s; (&s).foo(1); S57 s2; s2.foo(2); immutable(S57) s3; s3.foo(3); } /************************************/ class C58 { const(C58) c; const C58 y; this() { y = null; c = null; } const void foo() { //c = null; // should fail } void bar() { //c = null; } } void test58() { } /************************************/ class A59 { int[] a; this() { a.length = 1; } int* ptr() { return a.ptr; } const const(int)* ptr() { return a.ptr; } immutable immutable(int)* ptr() { return a.ptr; } } void test59() { auto a = new A59; const b = cast(const)new A59; immutable c = cast(immutable)new A59; } /************************************/ int foo60(int i) { return 1; } int foo60(const int i) { return 2; } int foo60(immutable int i) { return 3; } void test60() { int i; const int j; immutable int k; assert(foo60(i) == 1); assert(foo60(j) == 2); assert(foo60(k) == 3); } /************************************/ void foo61(T)(T arg) { alias const(T) CT; assert(is(const(int) == CT)); //writeln(typeid(const(T))); //writeln(typeid(CT)); } void test61() { int x = 42; foo61(x); } /************************************/ class Foo62(T) { } void test62() { const(Foo62!(int)) f = new Foo62!(int); assert(is(typeof(f) == const(Foo62!(int)))); } /************************************/ struct S63 { int x; } void foo63(const ref S63 scheme) { //scheme.x = 3; } void test63() { S63 scheme; foo63(scheme); } /************************************/ struct S64 { int a; long b; } void test64() { S64 s1 = S64(2,3); const s2 = S64(2,3); immutable S64 s3 = S64(2,3); s1 = s1; s1 = s2; s1 = s3; } /************************************/ struct S65 { int a; long b; char *p; } void test65() { char c; S65 s1 = S65(2,3); const s2 = S65(2,3); immutable S65 s3 = S65(2,3); S65 t1 = S65(2,3,null); const t2 = S65(2,3,null); immutable S65 t3 = S65(2,3,null); } /************************************/ struct S66 { int a; long b; } void test66() { char c; S66 s1 = S66(2,3); const s2 = S66(2,3); immutable S66 s3 = S66(2,3); S66 t1 = s1; S66 t2 = s2; S66 t3 = s3; const(S66) u1 = s1; const(S66) u2 = s2; const(S66) u3 = s3; immutable(S66) v1 = s1; immutable(S66) v2 = s2; immutable(S66) v3 = s3; } /************************************/ struct Foo68 { int z; immutable int x; int y; } void test68() { Foo68 bar; bar.y = 2; } /************************************/ class C69 {} struct S69 {} void test69() { immutable(S69)* si; S69* sm; bool a = si is sm; immutable(C69) ci; const(C69) cm; bool b = ci is cm; } /************************************/ struct S70 { int i; } void test70() { S70 s; const(S70) cs = s; S70 s1 = cs; S70 s2 = cast(S70)cs; } /************************************/ void test72() { int a; const int b; enum { int c = 0 }; immutable int d = 0; assert(__traits(isSame, a, a)); assert(__traits(isSame, b, b)); assert(__traits(isSame, c, c)); assert(__traits(isSame, d, d)); } /************************************/ void a73(const int [] data...) { a73(1); } void test73() { } /************************************/ struct S74 { int x; } const S74 s_const = {0}; S74 s_mutable = s_const; void test74() { } /************************************/ struct A75 { int x; } struct B75 { A75 s1; } const A75 s1_const = {0}; const B75 s2_const = {s1_const}; void test75() { } /************************************/ void test76() { int[int] array; const(int[int]) a = array; } /************************************/ void test77() { int[][] intArrayArray; int[][][] intArrayArrayArray; // const(int)[][] f1 = intArrayArray; const(int[])[] f2 = intArrayArray; // const(int)[][][] g1 = intArrayArrayArray; // const(int[])[][] g2 = intArrayArrayArray; const(int[][])[] g3 = intArrayArrayArray; } /************************************/ void foo78(T)(const(T)[] arg1, const(T)[] arg2) { } void test78() { foo78("hello", "world".dup); foo78("hello", "world"); foo78("hello".dup, "world".dup); foo78(cast(const)"hello", cast(const)"world"); } /************************************/ const bool[string] stopWords79; static this() { stopWords79 = [ "a"[]:1 ]; } void test79() { "abc" in stopWords79; } /************************************/ void test80(inout(int) _ = 0) { char x; inout(char) y = x; const(char)[] c; immutable(char)[] i; shared(char)[] s; const(shared(char))[] sc; inout(char)[] w; inout(shared(char))[] sw; c = c; c = i; static assert(!__traits(compiles, c = s)); static assert(!__traits(compiles, c = sc)); c = w; static assert(!__traits(compiles, c = sw)); static assert(!__traits(compiles, i = c)); i = i; static assert(!__traits(compiles, i = s)); static assert(!__traits(compiles, i = sc)); static assert(!__traits(compiles, i = w)); static assert(!__traits(compiles, i = sw)); static assert(!__traits(compiles, s = c)); static assert(!__traits(compiles, s = i)); s = s; static assert(!__traits(compiles, s = sc)); static assert(!__traits(compiles, s = w)); static assert(!__traits(compiles, s = sw)); static assert(!__traits(compiles, sc = c)); sc = i; sc = s; sc = sc; static assert(!__traits(compiles, sc = w)); sc = sw; static assert(!__traits(compiles, w = c)); static assert(!__traits(compiles, w = i)); static assert(!__traits(compiles, w = s)); static assert(!__traits(compiles, w = sc)); w = w; static assert(!__traits(compiles, w = sw)); static assert(!__traits(compiles, sw = c)); static assert(!__traits(compiles, sw = i)); static assert(!__traits(compiles, sw = s)); static assert(!__traits(compiles, sw = sc)); static assert(!__traits(compiles, sw = w)); sw = sw; } /************************************/ void test81(inout(int) _ = 0) { const(char)* c; immutable(char)* i; shared(char)* s; const(shared(char))* sc; inout(char)* w; c = c; c = i; static assert(!__traits(compiles, c = s)); static assert(!__traits(compiles, c = sc)); c = w; static assert(!__traits(compiles, i = c)); i = i; static assert(!__traits(compiles, i = s)); static assert(!__traits(compiles, i = sc)); static assert(!__traits(compiles, i = w)); static assert(!__traits(compiles, s = c)); static assert(!__traits(compiles, s = i)); s = s; static assert(!__traits(compiles, s = sc)); static assert(!__traits(compiles, s = w)); static assert(!__traits(compiles, sc = c)); sc = i; sc = s; sc = sc; static assert(!__traits(compiles, sc = w)); static assert(!__traits(compiles, w = c)); static assert(!__traits(compiles, w = i)); static assert(!__traits(compiles, w = s)); static assert(!__traits(compiles, w = sc)); w = w; } /************************************/ void test82(inout(int) _ = 0) { const(immutable(char)*) c; pragma(msg, typeof(c)); static assert(typeof(c).stringof == "const(immutable(char)*)"); inout(immutable(char)*) d; pragma(msg, typeof(d)); static assert(typeof(d).stringof == "inout(immutable(char)*)"); inout(const(char)*) e; pragma(msg, typeof(e)); static assert(is(typeof(e) == inout(const(char)*))); static assert(typeof(e).stringof == "inout(const(char)*)"); pragma(msg, typeof(*e)); static assert(is(typeof(*e) == inout(const(char)))); static assert(typeof(*e).stringof == "inout(const(char))"); inout const(char)* f; static assert(is(typeof(e) == typeof(f))); inout(shared(char)) g; pragma(msg, typeof(g)); static assert(typeof(g).stringof == "shared(inout(char))"); shared(inout(char)) h; pragma(msg, typeof(h)); static assert(typeof(h).stringof == "shared(inout(char))"); inout(immutable(char)) i; pragma(msg, typeof(i)); static assert(typeof(i).stringof == "immutable(char)"); immutable(inout(char)) j; pragma(msg, typeof(j)); static assert(typeof(j).stringof == "immutable(char)"); inout(const(char)) k; pragma(msg, typeof(k)); static assert(typeof(k).stringof == "inout(const(char))"); const(inout(char)) l; pragma(msg, typeof(l)); static assert(typeof(l).stringof == "inout(const(char))"); shared(const(char)) m; pragma(msg, typeof(m)); static assert(typeof(m).stringof == "shared(const(char))"); const(shared(char)) n; pragma(msg, typeof(n)); static assert(typeof(n).stringof == "shared(const(char))"); inout(char*****) o; pragma(msg, typeof(o)); static assert(typeof(o).stringof == "inout(char*****)"); pragma(msg, typeof(cast()o)); static assert(typeof(cast()o).stringof == "inout(char****)*"); const(char*****) p; pragma(msg, typeof(p)); static assert(typeof(p).stringof == "const(char*****)"); pragma(msg, typeof(cast()p)); static assert(typeof(cast()p).stringof == "const(char****)*"); immutable(char*****) q; pragma(msg, typeof(q)); static assert(typeof(q).stringof == "immutable(char*****)"); pragma(msg, typeof(cast()q)); static assert(typeof(cast()q).stringof == "immutable(char****)*"); shared(char*****) r; pragma(msg, typeof(r)); static assert(typeof(r).stringof == "shared(char*****)"); pragma(msg, typeof(cast()r)); static assert(typeof(cast()r).stringof == "shared(char****)*"); pragma(msg, typeof(cast(const)r)); static assert(typeof(cast(const)r).stringof == "const(shared(char****)*)"); pragma(msg, typeof(cast(const shared)r)); static assert(typeof(cast(const shared)r).stringof == "shared(const(char*****))"); pragma(msg, typeof(cast(shared)r)); static assert(typeof(cast(shared)r).stringof == "shared(char*****)"); pragma(msg, typeof(cast(immutable)r)); static assert(typeof(cast(immutable)r).stringof == "immutable(char*****)"); pragma(msg, typeof(cast(inout)r)); static assert(typeof(cast(inout)r).stringof == "inout(shared(char****)*)"); inout(shared(char**)***) s; pragma(msg, typeof(s)); static assert(typeof(s).stringof == "inout(shared(char**)***)"); pragma(msg, typeof(***s)); static assert(typeof(***s).stringof == "shared(inout(char**))"); } /************************************/ void test83(inout(int) _ = 0) { static assert( __traits(compiles, typeid(int* function(inout int)))); static assert( __traits(compiles, typeid(int* delegate(inout int)))); static assert(!__traits(compiles, typeid(inout(int*) function(int)))); static assert(!__traits(compiles, typeid(inout(int*) delegate(int)))); static assert(!__traits(compiles, typeid(inout(int*) function()))); static assert(!__traits(compiles, typeid(inout(int*) delegate()))); inout(int*) function(inout(int)) fp; inout(int*) delegate(inout(int)) dg; } /************************************/ inout(char[]) foo84(inout char[] s) { return s; } void test84() { char[] m; const(char)[] c; string s; auto r = foo84(s); pragma(msg, typeof(r).stringof); static assert(typeof(r).stringof == "immutable(string)"); pragma(msg, typeof(foo84(c)).stringof); static assert(typeof(foo84(c)).stringof == "const(char[])"); pragma(msg, typeof(foo84(m)).stringof); static assert(typeof(foo84(m)).stringof == "char[]"); } /************************************/ class foo85 { } alias shared foo85 Y85; void test85() { pragma(msg, Y85); shared(foo85) x = new Y85; } /************************************/ struct foo87 { int bar(T)(T t){ return 1; } int bar(T)(T t) shared { return 2; } } void test87() { foo87 x; auto i = x.bar(1); assert(i == 1); shared foo87 y; i = y.bar(1); assert(i == 2); } /************************************/ // 2751 void test88(immutable(int[3]) a) { const(char)[26] abc1 = "abcdefghijklmnopqrstuvwxyz"; const(char[26]) abc2 = "abcdefghijklmnopqrstuvwxyz"; immutable(const(char)[26]) abc3 = "abcdefghijklmnopqrstuvwxyz"; const(immutable(char)[26]) abc4 = "abcdefghijklmnopqrstuvwxyz"; auto abc5 = cast()"abcdefghijklmnopqrstuvwxyz"; pragma(msg, typeof(abc1).stringof); pragma(msg, typeof(abc2).stringof); pragma(msg, typeof(abc3).stringof); pragma(msg, typeof(abc4).stringof); pragma(msg, typeof(abc5).stringof); static assert(is(typeof(abc1) == typeof(abc2))); static assert(is(typeof(abc1) == const(char[26]))); static assert(is(typeof(abc3) == typeof(abc4))); static assert(is(typeof(abc3) == immutable(char[26]))); auto b = cast()a; pragma(msg, typeof(b).stringof); static assert(is(typeof(b) == int[3])); } /************************************/ // 3748 // version = error8; // version = error11; class C3748 { private int _x; this(int x) { this._x = x; } @property inout(int)* xptr() inout { return &_x; } @property void x(int newval) { _x = newval; } } struct S3748 { int x; immutable int y = 5; const int z = 6; C3748 c; inout(int)* getX() inout { static assert(!__traits(compiles, { x = 4; })); return &x; } inout(int)* getCX(C3748 otherc) inout { inout(C3748) c2 = c; // typeof(c) == inout(C3748) static assert(!__traits(compiles, { inout(C3748) err2 = new C3748(1); })); static assert(!__traits(compiles, { inout(C3748) err3 = otherc; })); auto v1 = getLowestXptr(c, otherc); static assert(is(typeof(v1) == const(int)*)); auto v2 = getLowestXptr(c, c); static assert(is(typeof(v2) == inout(int)*)); alias typeof(return) R; static assert(!__traits(compiles, { c.x = 4; })); static assert(!__traits(compiles, { R r = otherc.xptr; })); static assert(!__traits(compiles, { R r = &y; })); static assert(!__traits(compiles, { R r = &z; })); return c2.xptr; } version(error8) inout(int) err8; // see fail_compilation/failinout3748a.d } inout(int)* getLowestXptr(inout(C3748) c1, inout(C3748) c2) { inout(int)* x1 = c1.xptr; inout(int)* x2 = c2.xptr; if(*x1 <= *x2) return x1; return x2; } ref inout(int) getXRef(inout(C3748) c1, inout(C3748) c2) { return *getLowestXptr(c1, c2); } void test3748() { S3748 s; s.c = new C3748(1); const(S3748)* sp = &s; auto s2 = new S3748; s2.x = 3; s2.c = new C3748(2); auto s3 = cast(immutable(S3748)*) s2; auto v1 = s.getX; static assert(is(typeof(v1) == int*)); auto v2 = sp.getX; static assert(is(typeof(v2) == const(int)*)); auto v3 = s3.getX; static assert(is(typeof(v3) == immutable(int)*)); static assert(!__traits(compiles, { int *err9 = sp.getX; })); static assert(!__traits(compiles, { int *err10 = s3.getX; })); version(error11) inout(int)* err11; // see fail_compilation/failinout3748b.d auto v4 = getLowestXptr(s.c, s3.c); static assert(is(typeof(v4) == const(int)*)); auto v5 = getLowestXptr(s.c, s.c); static assert(is(typeof(v5) == int*)); auto v6 = getLowestXptr(s3.c, s3.c); static assert(is(typeof(v6) == immutable(int)*)); getXRef(s.c, s.c) = 3; } /************************************/ void test3748a(inout int = 1) { int[] ma; inout(int[]) wa; const(int[]) ca; immutable(int[]) ia; shared(int[]) sa; shared(inout(int[])) swa; shared(const(int[])) sca; static foo1(E)(inout(E[]) a) { return E.init; } static assert( is( typeof(foo1( ma)) == int)); static assert( is( typeof(foo1( wa)) == int)); static assert( is( typeof(foo1( ca)) == int)); static assert( is( typeof(foo1( ia)) == int)); static assert( is( typeof(foo1( sa)) == shared int)); static assert( is( typeof(foo1(swa)) == shared int)); static assert( is( typeof(foo1(sca)) == shared int)); static foo2(E)(shared inout(E[]) a) { return E.init; } static assert(!is( typeof(foo2( ma)) )); static assert(!is( typeof(foo2( wa)) )); static assert(!is( typeof(foo2( ca)) )); static assert( is( typeof(foo2( ia)) == int)); static assert( is( typeof(foo2( sa)) == int)); static assert( is( typeof(foo2(swa)) == int)); static assert( is( typeof(foo2(sca)) == int)); } void test3748b(inout int = 1) { // Top of the parameter type is non-ref & qualified static inout(int[]) foo1( inout(int[]) a); static shared(inout(int[])) bar1(shared(inout(int[])) a); // Top of the parameter type is non-ref & un-qualified static inout(int) [] foo2( inout(int) [] a); static shared(inout(int))[] bar2(shared(inout(int))[] a); // Top of the argument type is qualified int[] ma1; inout(int[]) wa1; const(int[]) ca1; shared(int[]) sa1; shared(inout(int[])) swa1; shared(const(int[])) sca1; immutable(int[]) ia1; // Top of the argument type is un-qualified int [] ma2; inout(int) [] wa2; const(int) [] ca2; shared(int) [] sa2; shared(inout(int))[] swa2; shared(const(int))[] sca2; immutable(int) [] ia2; // --> non-ref qualified param VS qualified arg static assert( is( typeof(foo1( ma1)) == typeof( ma1) )); static assert( is( typeof(foo1( wa1)) == typeof( wa1) )); static assert( is( typeof(foo1( ca1)) == typeof( ca1) )); static assert( is( typeof(bar1( sa1)) == typeof( sa1) )); static assert( is( typeof(bar1(swa1)) == typeof(swa1) )); static assert( is( typeof(bar1(sca1)) == typeof(sca1) )); static assert( is( typeof(foo1( ia1)) == typeof( ia1) )); // --> non-ref un-qualified param VS qualified arg static assert( is( typeof(foo2( ma1)) == typeof( ma2) )); static assert( is( typeof(foo2( wa1)) == typeof( wa2) )); static assert( is( typeof(foo2( ca1)) == typeof( ca2) )); static assert( is( typeof(bar2( sa1)) == typeof( sa2) )); static assert( is( typeof(bar2(swa1)) == typeof(swa2) )); static assert( is( typeof(bar2(sca1)) == typeof(sca2) )); static assert( is( typeof(foo2( ia1)) == typeof( ia2) )); // --> non-ref qualified param VS un-qualified arg static assert( is( typeof(foo1( ma2)) == typeof( ma1) )); static assert( is( typeof(foo1( wa2)) )); static assert( is( typeof(foo1( ca2)) )); static assert( is( typeof(bar1( sa2)) == typeof( sa1) )); static assert( is( typeof(bar1(swa2)) )); static assert( is( typeof(bar1(sca2)) )); static assert( is( typeof(foo1( ia2)) )); // --> non-ref un-qualified param VS un-qualified arg static assert( is( typeof(foo2( ma2)) == typeof( ma2) )); static assert( is( typeof(foo2( wa2)) == typeof( wa2) )); static assert( is( typeof(foo2( ca2)) == typeof( ca2) )); static assert( is( typeof(bar2( sa2)) == typeof( sa2) )); static assert( is( typeof(bar2(swa2)) == typeof(swa2) )); static assert( is( typeof(bar2(sca2)) == typeof(sca2) )); static assert( is( typeof(foo2( ia2)) == typeof( ia2) )); } void test3748c(inout int = 1) { // Top of the parameter type is ref & qualified static inout(int[]) foo1(ref inout(int[]) a); static shared(inout(int[])) bar1(ref shared(inout(int[])) a); // Top of the parameter type is ref & un-qualified static inout(int) [] foo2(ref inout(int) [] a); static shared(inout(int))[] bar2(ref shared(inout(int))[] a); // Top of the argument type is qualified int[] ma1; inout(int[]) wa1; const(int[]) ca1; shared(int[]) sa1; shared(inout(int[])) swa1; shared(const(int[])) sca1; immutable(int[]) ia1; // Top of the argument type is un-qualified int [] ma2; inout(int) [] wa2; const(int) [] ca2; shared(int) [] sa2; shared(inout(int))[] swa2; shared(const(int))[] sca2; immutable(int) [] ia2; // --> ref qualified param VS qualified arg static assert( is( typeof(foo1( ma1)) == typeof( ma1) )); static assert( is( typeof(foo1( wa1)) == typeof( wa1) )); static assert( is( typeof(foo1( ca1)) == typeof( ca1) )); static assert( is( typeof(bar1( sa1)) == typeof( sa1) )); static assert( is( typeof(bar1(swa1)) == typeof(swa1) )); static assert( is( typeof(bar1(sca1)) == typeof(sca1) )); static assert( is( typeof(foo1( ia1)) == typeof( ia1) )); // --> ref un-qualified param VS qualified arg static assert( is( typeof(foo2( ma1)) == typeof( ma2) )); static assert(!is( typeof(foo2( wa1)) )); static assert(!is( typeof(foo2( ca1)) )); static assert(!is( typeof(bar2( sa1)) )); static assert(!is( typeof(bar2(swa1)) )); static assert(!is( typeof(bar2(sca1)) )); static assert(!is( typeof(foo2( ia1)) )); // --> ref qualified param VS un-qualified arg static assert( is( typeof(foo1( ma2)) == typeof( ma1) )); static assert(!is( typeof(foo1( wa2)) )); static assert(!is( typeof(foo1( ca2)) )); // why this is OK? --> [*] static assert(!is( typeof(bar1( sa2)) )); static assert(!is( typeof(bar1(swa2)) )); static assert(!is( typeof(bar1(sca2)) )); static assert(!is( typeof(foo1( ia2)) )); // --> ref un-qualified param VS un-qualified arg static assert( is( typeof(foo2( ma2)) == typeof( ma2) )); static assert( is( typeof(foo2( wa2)) == typeof( wa2) )); static assert( is( typeof(foo2( ca2)) == typeof( ca2) )); static assert( is( typeof(bar2( sa2)) == typeof( sa2) )); static assert( is( typeof(bar2(swa2)) == typeof(swa2) )); static assert( is( typeof(bar2(sca2)) == typeof(sca2) )); static assert( is( typeof(foo2( ia2)) == typeof( ia2) )); } /************************************/ // 4968 void test4968() { inout(int) f1(inout(int) i) { return i; } int mi; const int ci; immutable int ii; static assert(is(typeof(f1(mi)) == int)); static assert(is(typeof(f1(ci)) == const(int))); static assert(is(typeof(f1(ii)) == immutable(int))); inout(int)* f2(inout(int)* p) { return p; } int* mp; const(int)* cp; immutable(int)* ip; static assert(is(typeof(f2(mp)) == int*)); static assert(is(typeof(f2(cp)) == const(int)*)); static assert(is(typeof(f2(ip)) == immutable(int)*)); inout(int)[] f3(inout(int)[] a) { return a; } int[] ma; const(int)[] ca; immutable(int)[] ia; static assert(is(typeof(f3(ma)) == int[])); static assert(is(typeof(f3(ca)) == const(int)[])); static assert(is(typeof(f3(ia)) == immutable(int)[])); inout(int)[1] f4(inout(int)[1] sa) { return sa; } int[1] msa; const int[1] csa; immutable int[1] isa; static assert(is(typeof(f4(msa)) == int[1])); static assert(is(typeof(f4(csa)) == const(int)[1])); static assert(is(typeof(f4(isa)) == immutable(int)[1])); inout(int)[string] f5(inout(int)[string] aa) { return aa; } int[string] maa; const(int)[string] caa; immutable(int)[string] iaa; static assert(is(typeof(f5(maa)) == int[string])); static assert(is(typeof(f5(caa)) == const(int)[string])); static assert(is(typeof(f5(iaa)) == immutable(int)[string])); } /************************************/ // 1961 inout(char)[] strstr(inout(char)[] source, const(char)[] pattern) { /* * this would be an error, as const(char)[] is not implicitly castable to * inout(char)[] */ // return pattern; for(int i = 0; i + pattern.length <= source.length; i++) { inout(char)[] tmp = source[i..pattern.length]; // ok if (tmp == pattern) // ok, tmp implicitly casts to const(char)[] return source[i..$]; // implicitly casts back to call-site source } return source[$..$]; // to be consistent with strstr. } void test1961a() { auto a = "hello"; a = strstr(a, "llo"); // cf (constancy factor) == immutable static assert(!__traits(compiles, { char[] b = strstr(a, "llo"); })); // error, cannot cast immutable to mutable char[] b = "hello".dup; b = strstr(b, "llo"); // cf == mutable (note that "llo" doesn't play a role // because that parameter is not inout) const(char)[] c = strstr(b, "llo"); // cf = mutable, ok because mutable // implicitly casts to const c = strstr(a, "llo"); // cf = immutable, ok immutable casts to const } inout(T) min(T)(inout(T) a, inout(T) b) { return a < b ? a : b; } void test1961b() { immutable(char)[] i = "hello"; const(char)[] c = "there"; char[] m = "Walter".dup; static assert(!__traits(compiles, { i = min(i, c); })); // error, since i and c vary in constancy, the result // is const, and you cannot implicitly cast const to immutable. c = min(i, c); // ok, cf == const, because not homogeneous c = min(m, c); // ok, cf == const c = min(m, i); // ok, cf == const i = min(i, "blah"); // ok, cf == immutable, homogeneous static assert(!__traits(compiles, { m = min(m, c); })); // error, cf == const because not homogeneous. static assert(!__traits(compiles, { m = min(m, "blah"); })); // error, cf == const m = min(m, "blah".dup); // ok } inout(T) min2(int i, int j, T)(inout(T) a, inout(T) b) { //pragma(msg, "(", i, ", ", j, ") = ", T); static assert(is(T == char[])); return a < b ? a : b; } template seq(T...){ alias T seq; } void test1961c() { immutable(char[]) iia = "hello1"; immutable(char)[] ima = "hello2"; const(char[]) cca = "there1"; const(char)[] cma = "there2"; char[] mma = "Walter".dup; foreach (i, x; seq!(iia, ima, cca, cma, mma)) foreach (j, y; seq!(iia, ima, cca, cma, mma)) { min2!(i, j)(x, y); //pragma(msg, "x: ",typeof(x), ", y: ",typeof(y), " -> ", typeof(min2(x, y)), " : ", __traits(compiles, min2(x, y))); } } /************************************/ inout(int) function(inout(int)) notinoutfun1() { return null; } inout(int) function(inout(int))[] notinoutfun2() { return null; } inout(int) delegate(inout(int)) notinoutfun3() { return null; } inout(int) delegate(inout(int))[] notinoutfun4() { return null; } void notinoutfun1(inout(int) function(inout(int)) fn) {} void notinoutfun2(inout(int) function(inout(int))[] fn) {} void notinoutfun3(inout(int) delegate(inout(int)) dg) {} void notinoutfun4(inout(int) delegate(inout(int))[] dg) {} void test88() { inout(int) function(inout int) fp; inout(int) delegate(inout int) dg; inout(int) function(inout int)* fp2p; inout(int) function(inout int)[] fp2a; inout(int) function(inout int)[3] fp2s; inout(int) delegate(inout int)* dg3p; inout(int) delegate(inout int)[] dg3a; inout(int) delegate(inout int)[3] dg3s; int delegate() inout* dg4p; int delegate() inout[] dg4a; int delegate() inout[3] dg4s; static assert(!__traits(compiles, { inout(int)* p; })); static assert(!__traits(compiles, { inout(int delegate()) dg; })); } /************************************/ // 4251 void test4251a() { alias int T; static assert(!is( immutable(T)** : const(T)** )); // NG, tail difference static assert( is( immutable(T)** : const(T**) )); // OK, tail to const static assert( is( T *** : T *** )); // OK, tail is same static assert(!is( T *** : const(T)*** )); static assert(!is( T *** : const(T*)** )); static assert( is( T *** : const(T**)* )); // OK, tail to const static assert( is( T *** : const(T***) )); // OK, tail to const static assert(!is( T *** : immutable(T)*** )); static assert(!is( T *** : immutable(T*)** )); static assert(!is( T *** : immutable(T**)* )); static assert(!is( T *** : immutable(T***) )); static assert(!is( const(T)*** : T *** )); static assert( is( const(T)*** : const(T)*** )); // OK, tail is same static assert(!is( const(T)*** : const(T*)** )); static assert( is( const(T)*** : const(T**)* )); // OK, tail to const static assert( is( const(T)*** : const(T***) )); // OK, tail to const static assert(!is( const(T)*** : immutable(T)*** )); static assert(!is( const(T)*** : immutable(T*)** )); static assert(!is( const(T)*** : immutable(T**)* )); static assert(!is( const(T)*** : immutable(T***) )); static assert(!is( const(T*)** : T *** )); static assert(!is( const(T*)** : const(T)*** )); static assert( is( const(T*)** : const(T*)** )); // OK, tail is same static assert( is( const(T*)** : const(T**)* )); // OK, tail to const static assert( is( const(T*)** : const(T***) )); // OK, tail to const static assert(!is( const(T*)** : immutable(T)*** )); static assert(!is( const(T*)** : immutable(T*)** )); static assert(!is( const(T*)** : immutable(T**)* )); static assert(!is( const(T*)** : immutable(T***) )); static assert(!is( const(T**)* : T *** )); static assert(!is( const(T**)* : const(T)*** )); static assert(!is( const(T**)* : const(T*)** )); static assert( is( const(T**)* : const(T**)* )); // OK, tail is same static assert( is( const(T**)* : const(T***) )); // OK, tail is same static assert(!is( const(T**)* : immutable(T)*** )); static assert(!is( const(T**)* : immutable(T*)** )); static assert(!is( const(T**)* : immutable(T**)* )); static assert(!is( const(T**)* : immutable(T***) )); static assert(!is( const(T***) : T *** )); static assert(!is( const(T***) : const(T)*** )); static assert(!is( const(T***) : const(T*)** )); static assert( is( const(T***) : const(T**)* )); // OK, tail is same static assert( is( const(T***) : const(T***) )); // OK, tail is same static assert(!is( const(T***) : T *** )); static assert(!is( const(T***) : immutable(T)*** )); static assert(!is( const(T***) : immutable(T*)** )); static assert(!is( const(T***) : immutable(T**)* )); static assert(!is( const(T***) : immutable(T***) )); static assert(!is( immutable(T)*** : T *** )); static assert(!is( immutable(T)*** : const(T)*** )); static assert(!is( immutable(T)*** : const(T*)** )); static assert( is( immutable(T)*** : const(T**)* )); // OK, tail to const static assert( is( immutable(T)*** : const(T***) )); // OK, tail to const static assert( is( immutable(T)*** : immutable(T)*** )); // OK, tail is same static assert(!is( immutable(T)*** : immutable(T*)** )); static assert(!is( immutable(T)*** : immutable(T**)* )); static assert(!is( immutable(T)*** : immutable(T***) )); static assert(!is( immutable(T*)** : T *** )); static assert(!is( immutable(T*)** : const(T)*** )); static assert(!is( immutable(T*)** : const(T*)** )); static assert( is( immutable(T*)** : const(T**)* )); // OK, tail to const static assert( is( immutable(T*)** : const(T***) )); // OK, tail to const static assert(!is( immutable(T*)** : immutable(T)*** )); static assert( is( immutable(T*)** : immutable(T*)** )); // OK, tail is same static assert(!is( immutable(T*)** : immutable(T**)* )); static assert(!is( immutable(T*)** : immutable(T***) )); static assert(!is( immutable(T**)* : T *** )); static assert(!is( immutable(T**)* : const(T)*** )); static assert(!is( immutable(T**)* : const(T*)** )); static assert( is( immutable(T**)* : const(T**)* )); // OK, tail to const static assert( is( immutable(T**)* : const(T***) )); // OK, tail to const static assert(!is( immutable(T**)* : immutable(T)*** )); static assert(!is( immutable(T**)* : immutable(T*)** )); static assert( is( immutable(T**)* : immutable(T**)* )); // OK, tail is same static assert( is( immutable(T**)* : immutable(T***) )); // OK, tail is same static assert(!is( immutable(T***) : T *** )); static assert(!is( immutable(T***) : const(T)*** )); static assert(!is( immutable(T***) : const(T*)** )); static assert( is( immutable(T***) : const(T**)* )); // OK, tail to const static assert( is( immutable(T***) : const(T***) )); // OK, tail to const static assert(!is( immutable(T***) : immutable(T)*** )); static assert(!is( immutable(T***) : immutable(T*)** )); static assert( is( immutable(T***) : immutable(T**)* )); // OK, tail is same static assert( is( immutable(T***) : immutable(T***) )); // OK, tail is same static assert( is( immutable(int)** : const(immutable(int)*)* )); // OK, tail to const // shared level should be same static assert(!is( shared(T)*** : const(T***) )); // NG, tail to const but shared level is different static assert( is( shared(T***) : shared(const(T***)) )); // OK, tail to const and shared level is same // head qualifier difference is ignored static assert(is( shared(int)* : shared(int*) )); static assert(is( inout (int)* : inout (int*) )); // static assert(!is( T** : T*** )); static assert(!is( T[]** : T*** )); } void test4251b() { class C {} class D : C {} static assert(!is( C[]* : const(C)[]* )); static assert( is( C[]* : const(C[])* )); // derived class to const(base class) in tail static assert( is( D[] : const(C)[] )); static assert( is( D[]* : const(C[])* )); static assert( is( D* : const(C)* )); static assert( is( D** : const(C*)* )); // derived class to const(base interface) in tail interface I {} class X : I {} static assert(!is( X[] : const(I)[] )); // interface to const(base interface) in tail interface J {} interface K : I, J {} static assert( is( K[] : const(I)[] )); // OK, runtime offset is same static assert(!is( K[] : const(J)[] )); // NG, runtime offset is different } /************************************/ // 5473 void test5473() { class C { int b; void f(){} static int x; static void g(){}; } struct S { int b; void f(){} static int x; static void g(){}; } void dummy(){} alias typeof(dummy) VoidFunc; const C c = new C; const S s; foreach (a; TypeTuple!(c, s)) { alias typeof(a) A; static assert(is(typeof(a.b) == const int)); // const(int) static assert(is(typeof(a.f) == VoidFunc)); static assert(is(typeof(a.x) == int)); static assert(is(typeof(a.g) == VoidFunc)); static assert(is(typeof((const A).b) == const int)); // int, should be const(int) static assert(is(typeof((const A).f) == VoidFunc)); static assert(is(typeof((const A).x) == int)); static assert(is(typeof((const A).g) == VoidFunc)); } } /************************************/ // 5493 void test5493() { // non template function void pifun(immutable(char)[]* a) {} void rifun(ref immutable(char)[] a) {} void pcfun(const(char)[]* a) {} void rcfun(ref const(char)[] a) {} immutable char[] buf1 = "hello"; static assert(!__traits(compiles, pifun(buf1))); static assert(!__traits(compiles, pcfun(buf1))); static assert(!__traits(compiles, rifun(buf1))); static assert(!__traits(compiles, rcfun(buf1))); immutable char[5] buf2 = "hello"; static assert(!__traits(compiles, pifun(buf2))); static assert(!__traits(compiles, pcfun(buf2))); static assert(!__traits(compiles, rifun(buf2))); static assert(!__traits(compiles, rcfun(buf2))); const char[] buf3 = "hello"; static assert(!__traits(compiles, pcfun(buf3))); static assert(!__traits(compiles, rcfun(buf3))); const char[5] buf4 = "hello"; static assert(!__traits(compiles, pcfun(buf4))); static assert(!__traits(compiles, rcfun(buf4))); // template function void pmesswith(T)(const(T)[]* ts, const(T) t) { *ts ~= t; } void rmesswith(T)(ref const(T)[] ts, const(T) t) { ts ~= t; } class C { int x; this(int i) immutable { x = i; } } C[] cs; immutable C ci = new immutable(C)(6); assert (ci.x == 6); static assert(!__traits(compiles, pmesswith(&cs,ci))); static assert(!__traits(compiles, rmesswith(cs,ci))); //cs[$-1].x = 14; //assert (ci.x == 14); //whoops. } /************************************/ // 5493 + inout void test5493inout() { int m; const(int) c; immutable(int) i; inout(int) ptrfoo(inout(int)** a, inout(int)* b) { *a = b; return 0; // dummy } inout(int) reffoo(ref inout(int)* a, inout(int)* b) { a = b; return 0; // dummy } // wild matching: inout == mutable int* pm; ptrfoo(&pm, &m); assert(pm == &m); static assert(!__traits(compiles, ptrfoo(&pm, &c))); static assert(!__traits(compiles, ptrfoo(&pm, &i))); reffoo( pm, &m); assert(pm == &m); static assert(!__traits(compiles, reffoo( pm, &c))); static assert(!__traits(compiles, reffoo( pm, &i))); // wild matching: inout == const const(int)* pc; ptrfoo(&pc, &m); assert(pc == &m); ptrfoo(&pc, &c); assert(pc == &c); ptrfoo(&pc, &i); assert(pc == &i); reffoo( pc, &m); assert(pc == &m); reffoo( pc, &c); assert(pc == &c); reffoo( pc, &i); assert(pc == &i); // wild matching: inout == immutable immutable(int)* pi; static assert(!__traits(compiles, ptrfoo(&pi, &m))); static assert(!__traits(compiles, ptrfoo(&pi, &c))); ptrfoo(&pi, &i); assert(pi == &i); static assert(!__traits(compiles, reffoo( pi, &m))); static assert(!__traits(compiles, reffoo( pi, &c))); reffoo( pi, &i); assert(pi == &i); } /************************************/ // 6782 struct Tuple6782(T...) { T field; alias field this; } auto tuple6782(T...)(T field) { return Tuple6782!T(field); } struct Range6782a { int *ptr; @property inout(int)* front() inout { return ptr; } @property bool empty() const { return ptr is null; } void popFront() { ptr = null; } } struct Range6782b { Tuple6782!(int, int*) e; @property front() inout { return e; } @property empty() const { return e[1] is null; } void popFront() { e[1] = null; } } void test6782() { int x = 5; auto r1 = Range6782a(&x); foreach(p; r1) {} auto r2 = Range6782b(tuple6782(1, &x)); foreach(i, p; r2) {} } /************************************/ // 6864 int fn6864( const int n) { return 1; } int fn6864(shared int n) { return 2; } inout(int) fw6864(inout int s) { return 1; } inout(int) fw6864(shared inout int s) { return 2; } void test6864() { int n; assert(fn6864(n) == 1); assert(fw6864(n) == 1); shared int sn; assert(fn6864(sn) == 2); assert(fw6864(sn) == 2); } /************************************/ // 6865 shared(inout(int)) foo6865(shared(inout(int)) n){ return n; } void test6865() { shared(const(int)) n; static assert(is(typeof(foo6865(n)) == shared(const(int)))); } /************************************/ // 6866 struct S6866 { const(char)[] val; alias val this; } inout(char)[] foo6866(inout(char)[] s) { return s; } void test6866() { S6866 s; static assert(is(typeof(foo6866(s)) == const(char)[])); // Assertion failure: 'targ' on line 2029 in file 'mtype.c' } /************************************/ // 6867 inout(char)[] test6867(inout(char)[] a) { foreach(dchar d; a) // No error if 'dchar' is removed { foreach(c; a) // line 5 { } } return []; } /************************************/ // 6870 void test6870() { shared(int) x; static assert(is(typeof(x) == shared(int))); // pass const(typeof(x)) y; const(shared(int)) z; static assert(is(typeof(y) == typeof(z))); // fail! } /************************************/ // 6338, 6922 alias int T; static assert(is( immutable( T ) == immutable(T) )); static assert(is( immutable( const(T)) == immutable(T) )); // 6922 static assert(is( immutable(shared(T)) == immutable(T) )); static assert(is( immutable( inout(T)) == immutable(T) )); static assert(is( immutable(T) == immutable(T) )); static assert(is( const(immutable(T)) == immutable(T) )); // 6922 static assert(is( shared(immutable(T)) == immutable(T) )); // 6338 static assert(is( inout(immutable(T)) == immutable(T) )); static assert(is( immutable(shared(const(T))) == immutable(T) )); static assert(is( immutable(const(shared(T))) == immutable(T) )); static assert(is( shared(immutable(const(T))) == immutable(T) )); static assert(is( shared(const(immutable(T))) == immutable(T) )); static assert(is( const(shared(immutable(T))) == immutable(T) )); static assert(is( const(immutable(shared(T))) == immutable(T) )); static assert(is( immutable(shared(inout(T))) == immutable(T) )); static assert(is( immutable(inout(shared(T))) == immutable(T) )); static assert(is( shared(immutable(inout(T))) == immutable(T) )); static assert(is( shared(inout(immutable(T))) == immutable(T) )); static assert(is( inout(shared(immutable(T))) == immutable(T) )); static assert(is( inout(immutable(shared(T))) == immutable(T) )); /************************************/ // 6912 void test6912() { // From To static assert( is( int [] : int [] )); static assert(!is( inout(int []) : int [] )); static assert(!is( int [] : inout(int []) )); static assert( is( inout(int []) : inout(int []) )); static assert( is( int [] : const(int)[] )); static assert( is( inout(int []) : const(int)[] )); static assert(!is( int [] : inout(const(int)[]) )); static assert( is( inout(int []) : inout(const(int)[]) )); static assert( is( const(int)[] : const(int)[] )); static assert( is( inout(const(int)[]) : const(int)[] )); static assert(!is( const(int)[] : inout(const(int)[]) )); static assert( is( inout(const(int)[]) : inout(const(int)[]) )); static assert( is( immutable(int)[] : const(int)[] )); static assert( is( inout(immutable(int)[]) : const(int)[] )); static assert( is( immutable(int)[] : inout(const(int)[]) )); static assert( is( inout(immutable(int)[]) : inout(const(int)[]) )); static assert( is( immutable(int)[] : immutable(int)[] )); static assert( is( inout(immutable(int)[]) : immutable(int)[] )); static assert( is( immutable(int)[] : inout(immutable(int)[]) )); static assert( is( inout(immutable(int)[]) : inout(immutable(int)[]) )); static assert( is( inout(int)[] : inout(int)[] )); static assert( is( inout(inout(int)[]) : inout(int)[] )); static assert( is( inout(int)[] : inout(inout(int)[]) )); static assert( is( inout(inout(int)[]) : inout(inout(int)[]) )); static assert( is( inout(int)[] : const(int)[] )); static assert( is( inout(inout(int)[]) : const(int)[] )); static assert( is( inout(int)[] : inout(const(int)[]) )); static assert( is( inout(inout(int)[]) : inout(const(int)[]) )); // From To static assert( is( int [int] : int [int] )); static assert(!is( inout(int [int]) : int [int] )); static assert(!is( int [int] : inout(int [int]) )); static assert( is( inout(int [int]) : inout(int [int]) )); static assert( is( int [int] : const(int)[int] )); static assert(!is( inout(int [int]) : const(int)[int] )); static assert(!is( int [int] : inout(const(int)[int]) )); static assert( is( inout(int [int]) : inout(const(int)[int]) )); static assert( is( const(int)[int] : const(int)[int] )); static assert(!is( inout(const(int)[int]) : const(int)[int] )); static assert(!is( const(int)[int] : inout(const(int)[int]) )); static assert( is( inout(const(int)[int]) : inout(const(int)[int]) )); static assert( is( immutable(int)[int] : const(int)[int] )); static assert(!is( inout(immutable(int)[int]) : const(int)[int] )); static assert(!is( immutable(int)[int] : inout(const(int)[int]) )); static assert( is( inout(immutable(int)[int]) : inout(const(int)[int]) )); static assert( is( immutable(int)[int] : immutable(int)[int] )); static assert(!is( inout(immutable(int)[int]) : immutable(int)[int] )); static assert(!is( immutable(int)[int] : inout(immutable(int)[int]) )); static assert( is( inout(immutable(int)[int]) : inout(immutable(int)[int]) )); static assert( is( inout(int)[int] : inout(int)[int] )); static assert(!is( inout(inout(int)[int]) : inout(int)[int] )); static assert(!is( inout(int)[int] : inout(inout(int)[int]) )); static assert( is( inout(inout(int)[int]) : inout(inout(int)[int]) )); static assert( is( inout(int)[int] : const(int)[int] )); static assert(!is( inout(inout(int)[int]) : const(int)[int] )); static assert(!is( inout(int)[int] : inout(const(int)[int]) )); static assert( is( inout(inout(int)[int]) : inout(const(int)[int]) )); // Regression check static assert( is( const(int)[] : const(int[]) ) ); // From To static assert( is( int * : int * )); static assert(!is( inout(int *) : int * )); static assert(!is( int * : inout(int *) )); static assert( is( inout(int *) : inout(int *) )); static assert( is( int * : const(int)* )); static assert( is( inout(int *) : const(int)* )); static assert(!is( int * : inout(const(int)*) )); static assert( is( inout(int *) : inout(const(int)*) )); static assert( is( const(int)* : const(int)* )); static assert( is( inout(const(int)*) : const(int)* )); static assert(!is( const(int)* : inout(const(int)*) )); static assert( is( inout(const(int)*) : inout(const(int)*) )); static assert( is( immutable(int)* : const(int)* )); static assert( is( inout(immutable(int)*) : const(int)* )); static assert( is( immutable(int)* : inout(const(int)*) )); static assert( is( inout(immutable(int)*) : inout(const(int)*) )); static assert( is( immutable(int)* : immutable(int)* )); static assert( is( inout(immutable(int)*) : immutable(int)* )); static assert( is( immutable(int)* : inout(immutable(int)*) )); static assert( is( inout(immutable(int)*) : inout(immutable(int)*) )); static assert( is( inout(int)* : inout(int)* )); static assert( is( inout(inout(int)*) : inout(int)* )); static assert( is( inout(int)* : inout(inout(int)*) )); static assert( is( inout(inout(int)*) : inout(inout(int)*) )); static assert( is( inout(int)* : const(int)* )); static assert( is( inout(inout(int)*) : const(int)* )); static assert( is( inout(int)* : inout(const(int)*) )); static assert( is( inout(inout(int)*) : inout(const(int)*) )); } /************************************/ // 6930 void test6930a() { inout(const int) f1(inout(const int) i) { return i; } int mi; const int ci; immutable int ii; static assert(is(typeof(f1(mi)) == const(int))); static assert(is(typeof(f1(ci)) == const(int))); static assert(is(typeof(f1(ii)) == immutable(int))); inout(const int)* f2(inout(const int)* p) { return p; } int * mp; const(int)* cp; immutable(int)* ip; static assert(is(typeof(f2(mp)) == const(int)*)); static assert(is(typeof(f2(cp)) == const(int)*)); static assert(is(typeof(f2(ip)) == immutable(int)*)); inout(const int)[] f3(inout(const int)[] a) { return a; } int [] ma; const(int)[] ca; immutable(int)[] ia; static assert(is(typeof(f3(ma)) == const(int)[])); static assert(is(typeof(f3(ca)) == const(int)[])); static assert(is(typeof(f3(ia)) == immutable(int)[])); inout(const int[1]) f4(inout(const int[1]) sa) { return sa; } int[1] msa; const int[1] csa; immutable int[1] isa; static assert(is(typeof(f4(msa)) == const(int)[1])); static assert(is(typeof(f4(csa)) == const(int)[1])); static assert(is(typeof(f4(isa)) == immutable(int)[1])); inout(const int)[string] f5(inout(const int)[string] aa) { return aa; } int [string] maa; const(int)[string] caa; immutable(int)[string] iaa; static assert(is(typeof(f5(maa)) == const(int)[string])); static assert(is(typeof(f5(caa)) == const(int)[string])); static assert(is(typeof(f5(iaa)) == immutable(int)[string])); } inout(const(int[])) foo6930(inout(int)[] x) { bool condition = cast(bool)(x.length / 2); return condition ? x : new immutable(int[])(2); } void test6930b(inout int = 0) { alias T1 = inout(shared(const(int))); static assert(T1.stringof == "shared(inout(const(int)))"); static assert(is(T1 == shared) && is(T1 == const) && is(T1 == inout)); alias T2 = const(shared(inout(int)[])); static assert(T2.stringof == "shared(const(inout(int)[]))"); static assert(is(T2 == shared) && is(T2 == const) && !is(T2 == inout) && is(typeof(T2.init[0]) == inout)); int [] ma; const(int)[] ca; immutable(int)[] ia; inout(int)[] wa; static assert(is(typeof(foo6930(ma)) == const int[])); static assert(is(typeof(foo6930(ca)) == const int[])); static assert(is(typeof(foo6930(ia)) == immutable int[])); static assert(is(typeof(foo6930(wa)) == inout const int[])); } /************************************/ // 11868 void f11868(A...)(A) { } void g11868(inout(const(int))[] arr) { f11868(arr[0]); } void test11868() { auto arr = [1,2,3]; g11868(arr); } /************************************/ // 11924 inout(StringType) localize11924(StringType)(inout StringType str, string locale) { return str; } struct S11924 { static menuItem_1(ARGS...)() { enum itemTitle = ARGS; } static content_left_1() { menuItem!(localize11924("Home", "")); } alias menuItem = menuItem_1; } /************************************/ // 11966 inout(char)[] stripped11966 (inout(char)[] path) { return path; } struct PathParser11966 { inout(const(char))[] path() inout { return null; } inout(const(char))[] pop() inout { return stripped11966(path); } } void test11966() { auto a = PathParser11966().pop(); } /************************************/ // 14788 auto make14788(K, V)(inout V[K] aa) { static struct Result { V[K] aa; ref front() inout { return aa[1]; } } return inout Result(aa); } void test14788() { int[int] aa = [1:1]; make14788(aa).front(); } /************************************/ // 12089 void foo12089(inout(char[]) a) { validate12089(a); } void validate12089(S)(in S str) { decodeImpl12089(str); } void decodeImpl12089(S)(auto ref S str) {} /************************************/ // 12524 inout(int) dup12524(inout(const(int)) val) { return val; } void test12524(inout(int)) { inout(const(int)) val; auto bug = dup12524(val); static assert(is(typeof(bug) == inout(int))); } /************************************/ // 6941 static assert((const(shared(int[])[])).stringof == "const(shared(int[])[])"); // fail static assert((const(shared(int[])[])).stringof != "const(shared(const(int[]))[])"); // fail static assert((inout(shared(int[])[])).stringof == "inout(shared(int[])[])"); // fail static assert((inout(shared(int[])[])).stringof != "inout(shared(inout(int[]))[])"); // fail /************************************/ // 6872 static assert((shared(inout(int)[])).stringof == "shared(inout(int)[])"); static assert((shared(inout(const(int)[]))).stringof == "shared(inout(const(int)[]))"); static assert((shared(inout(const(int)[])[])).stringof == "shared(inout(const(int)[])[])"); static assert((shared(inout(const(immutable(int)[])[])[])).stringof == "shared(inout(const(immutable(int)[])[])[])"); /************************************/ // 6939 void test6939() { shared int* x; immutable int* y; const int* z; static assert( is(typeof(1?x:y) == shared(const(int))*)); // fail static assert(!is(typeof(1?x:y) == const(int)*)); // fail static assert(!is(typeof(1?x:z))); // fail shared int[] a; immutable int[] b; const int[] c; static assert( is(typeof(1?a:b) == shared(const(int))[])); // pass (ok) static assert(!is(typeof(1?a:b) == const(int)[])); // pass (ok) static assert(!is(typeof(1?a:c))); // fail } /************************************/ // 6940 void test6940() { immutable(int*)* x; int** y; static assert(is(typeof(x) : const(int*)*)); // ok static assert(is(typeof(y) : const(int*)*)); // ok static assert(is(typeof(1?x:y) == const(int*)*)); immutable(int[])[] a; int[][] b; static assert(is(typeof(a) : const(int[])[])); // ok static assert(is(typeof(b) : const(int[])[])); // ok static assert(is(typeof(1?a:b) == const(int[])[])); immutable(int)** v; int** w; static assert(is(typeof(1?v:w) == const(int*)*)); } /************************************/ // 6982 void test6982() { alias int Bla; immutable(Bla[string]) ifiles = ["a":1, "b":2, "c":3]; static assert(!__traits(compiles, { immutable(Bla)[string] files = ifiles; })); // (1) static assert(!__traits(compiles, { ifiles.remove ("a"); })); // (2) immutable(int)[int] maa; const(immutable(int)[int]) caa; immutable( int [int]) iaa; static assert(!__traits(compiles, { maa = iaa; })); static assert(!__traits(compiles, { maa = caa; })); } /************************************/ // 7038 static assert(!is(S7038 == const)); const struct S7038{ int x; } static assert(!is(S7038 == const)); static assert(!is(C7038 == const)); const class C7038{ int x; } static assert(!is(C7038 == const)); void test7038() { S7038 s; static assert(!is(typeof(s) == const)); static assert(is(typeof(s.x) == const int)); C7038 c; static assert(!is(typeof(c) == const)); static assert(is(typeof(c.x) == const int)); } /************************************/ // 7105 void copy(inout(int)** tgt, inout(int)* src){ *tgt = src; } void test7105() { int* pm; int m; copy(&pm, &m); assert(pm == &m); const(int)* pc; const(int) c; copy(&pc, &c); assert(pc == &c); immutable(int)* pi; immutable(int) i; copy(&pi, &i); assert(pi == &i); static assert(!__traits(compiles, copy(&pm, &c))); static assert(!__traits(compiles, copy(&pm, &i))); copy(&pc, &m); assert(pc == &m); copy(&pc, &i); assert(pc == &i); static assert(!__traits(compiles, copy(&pi, &m))); static assert(!__traits(compiles, copy(&pi, &c))); } /************************************/ // 7202 void test7202() { void writeln(string s) @system { printf("%.*s\n", s.length, s.ptr); } void delegate() @system x = { writeln("I am @system"); }; void delegate() @safe y = { }; auto px = &x; auto py = &y; static assert(!__traits(compiles, px = py)); // accepts-invalid *px = x; y(); // "I am @system" -> no output, OK } /************************************/ // 7554 T outer7554(T)(immutable T function(T) pure foo) pure { pure int inner() { return foo(5); } return inner(); } int sqr7554(int x) pure { return x * x; } void test7554() { assert(outer7554(&sqr7554) == 25); immutable(int function(int) pure) ifp = &sqr7554; } /************************************/ bool empty(T)(in T[] a) { assert(is(T == shared(string))); return false; } void test7518() { shared string[] stuff; stuff.empty(); } /************************************/ // 7669 shared(inout U)[n] id7669(U, size_t n)( shared(inout U)[n] ); void test7669() { static assert(is(typeof( id7669((shared(int)[3]).init)) == shared(int)[3])); } /************************************/ // 7757 inout(int) foo7757a(int x, lazy inout(int) def) { return def; } inout(int)[] foo7757b(int x, lazy inout(int)[] def) { return def; } inout(int)[int] foo7757c(int x, lazy inout(int)[int] def) { return def; } inout(T) bar7757a(T)(T x, lazy inout(T) def) { return def; } inout(T)[] bar7757b(T)(T x, lazy inout(T)[] def) { return def; } inout(T)[T] bar7757c(T)(T x, lazy inout(T)[T] def) { return def; } inout(Object) get7757(lazy inout(Object) defVal) { return null; } void test7757() { int mx1 = foo7757a(1,2); const(int) cx1 = foo7757a(1,2); int [] ma1 = foo7757b(1,[2]); const(int)[] ca1 = foo7757b(1,[2]); int [int] maa1 = foo7757c(1,[2:3]); const(int)[int] caa1 = foo7757c(1,[2:3]); int mx2 = bar7757a(1,2); const(int) cx2 = bar7757a(1,2); int [] ma2 = bar7757b(1,[2]); const(int)[] ca2 = bar7757b(1,[2]); int [int] maa2 = bar7757c(1,[2:3]); const(int)[int] caa2 = bar7757c(1,[2:3]); Object defObj = null; auto resObj = get7757(defObj); } /************************************/ // 8098 class Outer8098 { int i = 6; class Inner { int y=0; void foo() const { static assert(is(typeof(this.outer) == const(Outer8098))); static assert(is(typeof(i) == const(int))); static assert(!__traits(compiles, ++i)); } } Inner inner; this() { inner = new Inner; } } void test8098() { const(Outer8098) x = new Outer8098(); static assert(is(typeof(x) == const(Outer8098))); static assert(is(typeof(x.inner) == const(Outer8098.Inner))); } /************************************/ // 8099 void test8099() { static class Outer { class Inner {} } auto m = new Outer; auto c = new const(Outer); auto i = new immutable(Outer); auto mm = m.new Inner; // m -> m OK auto mc = m.new const(Inner); // m -> c OK static assert(!__traits(compiles, { auto mi = m.new immutable(Inner); // m -> i bad })); static assert(!__traits(compiles, { auto cm = c.new Inner; // c -> m bad })); auto cc = c.new const(Inner); // c -> c OK static assert(!__traits(compiles, { auto ci = c.new immutable(Inner); // c -> i bad })); static assert(!__traits(compiles, { auto im = i.new Inner; // i -> m bad })); auto ic = i.new const(Inner); // i -> c OK auto ii = i.new immutable(Inner); // i -> i OK } /************************************/ // 8201 void test8201() { uint[2] msa; immutable uint[2] isa = msa; ubyte[] buffer = [0, 1, 2, 3, 4, 5]; immutable ubyte[4] iArr = buffer[0 .. 4]; } /************************************/ // 8212 struct S8212 { int x; } shared S8212 s8212; shared int x8212; void test8212() { int y = x8212; S8212 s2 = s8212; } /************************************/ // 8366 class B8366 { bool foo(in Object o) const { return true; } } class C8366a : B8366 { bool foo(in Object o) { return true; } override bool foo(in Object o) const { return false; } bool foo(in Object o) immutable { return true; } bool foo(in Object o) shared { return true; } bool foo(in Object o) shared const { return true; } } class C8366b : B8366 { bool foo(in Object o) { return false; } alias super.foo foo; bool foo(in Object o) immutable { return false; } bool foo(in Object o) shared { return false; } bool foo(in Object o) shared const { return false; } } void test8366() { { C8366a mca = new C8366a(); const C8366a cca = new C8366a(); B8366 mb = mca; const B8366 cb = cca; assert(mca.foo(null) == true); assert(cca.foo(null) == false); assert(mb .foo(null) == false); assert(cb .foo(null) == false); } { C8366b mcb = new C8366b(); const C8366b ccb = new C8366b(); B8366 mb = mcb; const B8366 cb = ccb; assert(mcb.foo(null) == false); assert(ccb.foo(null) == true); assert(mb .foo(null) == true); assert(cb .foo(null) == true); } } /************************************/ // 8408 template hasMutableIndirection8408(T) { template Unqual(T) { static if (is(T U == shared(const U))) alias U Unqual; else static if (is(T U == const U )) alias U Unqual; else static if (is(T U == immutable U )) alias U Unqual; else static if (is(T U == inout U )) alias U Unqual; else static if (is(T U == shared U )) alias U Unqual; else alias T Unqual; } enum hasMutableIndirection8408 = !is(typeof({ Unqual!T t = void; immutable T u = t; })); } static assert(!hasMutableIndirection8408!(int)); static assert(!hasMutableIndirection8408!(int[3])); static assert( hasMutableIndirection8408!(Object)); auto dup8408(E)(inout(E)[] arr) pure @trusted { static if (hasMutableIndirection8408!E) { auto copy = new E[](arr.length); copy[] = cast(E[])arr[]; // assume constant return cast(inout(E)[])copy; // assume constant } else { auto copy = new E[](arr.length); copy[] = arr[]; return copy; } } void test8408() { void test(E, bool constConv)() { E[] marr = [E.init, E.init, E.init]; immutable E[] iarr = [E.init, E.init, E.init]; E[] m2m = marr.dup8408(); assert(m2m == marr); immutable E[] i2i = iarr.dup8408(); assert(i2i == iarr); static if (constConv) { // If dup() hss strong purity, implicit conversion is allowed immutable E[] m2i = marr.dup8408(); assert(m2i == marr); E[] i2m = iarr.dup8408(); assert(i2m == iarr); } else { static assert(!is(typeof({ immutable E[] m2i = marr.dup8408(); }))); static assert(!is(typeof({ E[] i2m = iarr.dup8408(); }))); } } class C {} struct S1 { long n; } struct S2 { int* p; } struct T1 { S1 s; } struct T2 { S2 s; } struct T3 { S1 s1; S2 s2; } test!(int , true )(); test!(int[3], true )(); test!(C , false)(); test!(S1 , true )(); test!(S2 , false)(); test!(T1 , true )(); test!(T2 , false)(); test!(T3 , false)(); } /************************************/ // 8688 void test8688() { alias TypeTuple!(int) T; foreach (i; TypeTuple!(0)) { alias const(T[i]) X; static assert(!is(X == int)); // fails static assert( is(X == const(int))); // fails } } /************************************/ // 10946 (regression by fixing bug 8688, from 2.061) enum xlen10946 = 4; alias immutable(char)[xlen10946] e3; alias immutable(char[xlen10946]) e4; // NG -> OK immutable vlen10946 = 4; alias immutable(char)[vlen10946] i3; alias immutable(char[vlen10946]) i4; // NG -> OK /************************************/ // 9046 void test9046() { foreach (T; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, char, wchar, dchar, float, double, real, ifloat, idouble, ireal, cfloat, cdouble, creal)) foreach (U; TypeTuple!(T, const T, immutable T, shared T, shared const T, inout T, shared inout T)) { static assert(is(typeof(U.init) == U)); } foreach (T; TypeTuple!(int[], const(char)[], immutable(string[]), shared(const(int)[])[], int[1], const(char)[1], immutable(string[1]), shared(const(int)[1])[], int[int], const(char)[long], immutable(string[string]), shared(const(int)[double])[])) foreach (U; TypeTuple!(T, const T, immutable T, shared T, shared const T, inout T, shared inout T)) { static assert(is(typeof(U.init) == U)); } int i; enum E { x, y } static struct S {} static class C {} struct NS { void f(){ i++; } } class NC { void f(){ i++; } } foreach (T; TypeTuple!(E, S, C, NS, NC)) foreach (U; TypeTuple!(T, const T, immutable T, shared T, shared const T, inout T, shared inout T)) { static assert(is(typeof(U.init) == U)); } alias TL = TypeTuple!(int, string, int[int]); foreach (U; TypeTuple!(TL, const TL, immutable TL, shared TL, shared const TL, inout TL, shared inout TL)) { static assert(is(typeof(U.init) == U)); } } /************************************/ // 9090 void test9090() { void test1(T)(auto ref const T[] val) {} string a; test1(a); } /************************************/ // 9461 void test9461() { class A {} class B : A {} void conv(S, T)(ref S x) { T y = x; } // should be NG static assert(!__traits(compiles, conv!(inout(B)[], inout(A)[]))); static assert(!__traits(compiles, conv!(int[inout(B)], int[inout(A)]))); static assert(!__traits(compiles, conv!(inout(B)[int], inout(A)[int]))); static assert(!__traits(compiles, conv!(inout(B)*, inout(A)*))); static assert(!__traits(compiles, conv!(inout(B)[1], inout(A)[]))); // should be OK static assert( __traits(compiles, conv!(inout(B), inout(A)))); } /************************************/ struct S9209 { int x; } void bar9209(const S9209*) {} void test9209() { const f = new S9209(1); bar9209(f); } /************************************/ // 10758 struct X10758 { static: inout(int) screwUpVal(ref inout(int) wx) { return wx; } ref inout(int) screwUpRef(ref inout(int) wx) { return wx; } inout(int)* screwUpPtr(ref inout(int) wx) { return &wx; } inout(int)[] screwUpArr(ref inout(int) wx) { return (&wx)[0 .. 1]; } } struct S10758 { int x; inout(int) screwUpVal(ref inout(int) _) inout { return x; } ref inout(int) screwUpRef(ref inout(int) _) inout { return x; } inout(int)* screwUpPtr(ref inout(int) _) inout { return &x; } inout(int)[] screwUpArr(ref inout(int) _) inout { return (&x)[0 .. 1]; } } void test10758(ref inout(int) wx, inout(int)* wp, inout(int)[] wa, inout(S10758) ws) { inout(int) screwUpVal(inout(int) _) { return wx; } ref inout(int) screwUpRef(inout(int) _) { return wx; } inout(int)* screwUpPtr(inout(int) _) { return &wx; } inout(int)[] screwUpArr(inout(int) _) { return (&wx)[0 .. 1]; } struct NS { inout(int) screwUpVal() inout { return wx; } ref inout(int) screwUpRef() inout { return wx; } inout(int)* screwUpPtr() inout { return &wx; } inout(int)[] screwUpArr() inout { return (&wx)[0 .. 1]; } } int mx = 1; const(int) cx = 1; immutable(int) ix = 1; // nested inout function may return an inout reference of the context, // so substitude inout to mutable or immutable should be disallowed. { // value return does not leak any inout reference, so safe. screwUpVal(mx); screwUpVal(ix); screwUpVal(wx); screwUpVal(cx); static assert(!__traits(compiles, screwUpRef(mx))); static assert(!__traits(compiles, screwUpRef(ix))); screwUpRef(wx); screwUpRef(cx); static assert(!__traits(compiles, screwUpPtr(mx))); static assert(!__traits(compiles, screwUpPtr(ix))); screwUpPtr(wx); screwUpPtr(cx); static assert(!__traits(compiles, screwUpArr(mx))); static assert(!__traits(compiles, screwUpArr(ix))); screwUpArr(cx); screwUpArr(wx); } // inout method of the nested struct may return an inout reference of the context, { ( NS()).screwUpVal(); (immutable NS()).screwUpVal(); ( inout NS()).screwUpVal(); ( const NS()).screwUpVal(); static assert(!__traits(compiles, ( NS()).screwUpRef())); static assert(!__traits(compiles, (immutable NS()).screwUpRef())); (inout NS()).screwUpRef(); (const NS()).screwUpRef(); static assert(!__traits(compiles, ( NS()).screwUpPtr())); static assert(!__traits(compiles, (immutable NS()).screwUpPtr())); (inout NS()).screwUpPtr(); (const NS()).screwUpPtr(); static assert(!__traits(compiles, ( NS()).screwUpArr())); static assert(!__traits(compiles, (immutable NS()).screwUpArr())); (inout NS()).screwUpArr(); (const NS()).screwUpArr(); } // function pointer holds no context, so there's no screw up. { auto fp_screwUpVal = &X10758.screwUpVal; fp_screwUpVal(mx); fp_screwUpVal(ix); fp_screwUpVal(wx); fp_screwUpVal(cx); auto fp_screwUpRef = &X10758.screwUpRef; fp_screwUpRef(mx); fp_screwUpRef(ix); fp_screwUpRef(wx); fp_screwUpRef(cx); auto fp_screwUpPtr = &X10758.screwUpVal; fp_screwUpPtr(mx); fp_screwUpPtr(ix); fp_screwUpPtr(wx); fp_screwUpPtr(cx); auto fp_screwUpArr = &X10758.screwUpVal; fp_screwUpArr(mx); fp_screwUpArr(ix); fp_screwUpArr(wx); fp_screwUpArr(cx); } // inout delegate behaves same as nested functions. { auto dg_screwUpVal = &ws.screwUpVal; dg_screwUpVal(mx); dg_screwUpVal(ix); dg_screwUpVal(wx); dg_screwUpVal(cx); auto dg_screwUpRef = &ws.screwUpRef; static assert(!__traits(compiles, dg_screwUpRef(mx))); static assert(!__traits(compiles, dg_screwUpRef(ix))); dg_screwUpRef(wx); dg_screwUpRef(cx); auto dg_screwUpPtr = &ws.screwUpPtr; static assert(!__traits(compiles, dg_screwUpPtr(mx))); static assert(!__traits(compiles, dg_screwUpPtr(ix))); dg_screwUpPtr(wx); dg_screwUpPtr(cx); auto dg_screwUpArr = &ws.screwUpArr; static assert(!__traits(compiles, dg_screwUpArr(mx))); static assert(!__traits(compiles, dg_screwUpArr(ix))); dg_screwUpArr(cx); dg_screwUpArr(wx); } } /************************************/ // 10761 inout(int)* function(inout(int)*) fptr10761(inout(int)*) { static inout(int)* screwUp(inout(int)* x) { return x; } auto fp = &screwUp; static assert(is(typeof(fp) == inout(int)* function(inout(int)*))); return fp; } inout(int)* delegate(inout(int)*) nest10761(inout(int)* x) { inout(int)* screwUp(inout(int)* _) { return x; } auto dg = &screwUp; static assert(is(typeof(dg) == inout(int)* delegate(inout(int)*))); return dg; } struct S10761 { int x; inout(int)* screwUp() inout { return &x; } } inout(int)* delegate() inout memfn10761(inout(int)* x) { auto s = new inout S10761(1); auto dg = &s.screwUp; static assert(is(typeof(dg) == inout(int)* delegate() inout)); return dg; } void test10761() { int mx = 1; const(int) cx = 1; immutable(int) ix = 1; // inout substitution has no effect on function pointer type { auto fp_m = fptr10761(&mx); auto fp_c = fptr10761(&cx); auto fp_i = fptr10761(&ix); alias FP = inout(int)* function(inout(int)*); static assert(is(typeof(fp_m) == FP)); static assert(is(typeof(fp_c) == FP)); static assert(is(typeof(fp_i) == FP)); } // inout substitution on delegate type should always // modify inout to const. { auto dg_m = nest10761(&mx); auto dg_c = nest10761(&cx); auto dg_i = nest10761(&ix); alias DG = const(int)* delegate(const(int)*); static assert(is(typeof(dg_m) == DG)); static assert(is(typeof(dg_c) == DG)); static assert(is(typeof(dg_i) == DG)); } // same as above { auto dg_m = memfn10761(&mx); auto dg_c = memfn10761(&cx); auto dg_i = memfn10761(&ix); alias DG = const(int)* delegate() const; static assert(is(typeof(dg_m) == DG)); static assert(is(typeof(dg_c) == DG)); static assert(is(typeof(dg_i) == DG)); } } /************************************/ // 11226 void test11226() { typeof(null) m; const typeof(null) c = m; immutable typeof(null) i = m; m = m, m = c, m = i; assert(m == c); assert(m == i); assert(c == i); static assert(is(typeof(true ? m : m) == typeof(null))); static assert(is(typeof(true ? m : c) == const typeof(null))); static assert(is(typeof(true ? m : i) == const typeof(null))); static assert(is(typeof(true ? c : m) == const typeof(null))); static assert(is(typeof(true ? c : c) == const typeof(null))); static assert(is(typeof(true ? c : i) == const typeof(null))); static assert(is(typeof(true ? i : m) == const typeof(null))); static assert(is(typeof(true ? i : c) == const typeof(null))); static assert(is(typeof(true ? i : i) == immutable typeof(null))); static assert(typeof(m).stringof == "typeof(null)" ); static assert(typeof(c).stringof == "const(typeof(null))"); static assert(typeof(i).stringof == "immutable(typeof(null))"); } /************************************/ // 11257 struct R11257 { union { const(Object) original; Object stripped; } } void test11257() { const(R11257) cr; R11257 mr = cr; // Error: cannot implicitly convert expression (cr) of type const(R) to R } /************************************/ // 11215 shared(inout(void)**) f11215(inout int); static assert(is(typeof(f11215(0)) == shared(void**))); static assert(is(typeof(f11215((const int).init)) == shared(const(void)**))); /************************************/ // 11489 void test11489(inout int = 0) { static class B {} static class D : B {} D [] dm; const(D)[] dc; inout(D)[] dw; shared(D)[] dsm; shared(const D)[] dsc; shared(inout D)[] dsw; immutable(D)[] di; static assert(!__traits(compiles, { B [] b = dm; })); static assert( __traits(compiles, { const(B)[] b = dm; })); static assert(!__traits(compiles, { inout(B)[] b = dm; })); static assert(!__traits(compiles, { shared(B)[] b = dm; })); static assert(!__traits(compiles, { shared(const B)[] b = dm; })); static assert(!__traits(compiles, { shared(inout B)[] b = dm; })); static assert(!__traits(compiles, { immutable(B)[] b = dm; })); static assert(!__traits(compiles, { B [] b = dc; })); static assert( __traits(compiles, { const(B)[] b = dc; })); static assert(!__traits(compiles, { inout(B)[] b = dc; })); static assert(!__traits(compiles, { shared(B)[] b = dc; })); static assert(!__traits(compiles, { shared(const B)[] b = dc; })); static assert(!__traits(compiles, { shared(inout B)[] b = dc; })); static assert(!__traits(compiles, { immutable(B)[] b = dc; })); static assert(!__traits(compiles, { B [] b = dw; })); static assert( __traits(compiles, { const(B)[] b = dw; })); static assert(!__traits(compiles, { inout(B)[] b = dw; })); static assert(!__traits(compiles, { shared(B)[] b = dw; })); static assert(!__traits(compiles, { shared(const B)[] b = dw; })); static assert(!__traits(compiles, { shared(inout B)[] b = dw; })); static assert(!__traits(compiles, { immutable(B)[] b = dw; })); static assert(!__traits(compiles, { B [] b = dsm; })); static assert(!__traits(compiles, { const(B)[] b = dsm; })); static assert(!__traits(compiles, { inout(B)[] b = dsm; })); static assert(!__traits(compiles, { shared(B)[] b = dsm; })); static assert( __traits(compiles, { shared(const B)[] b = dsm; })); static assert(!__traits(compiles, { shared(inout B)[] b = dsm; })); static assert(!__traits(compiles, { immutable(B)[] b = dsm; })); static assert(!__traits(compiles, { B [] b = dsc; })); static assert(!__traits(compiles, { const(B)[] b = dsc; })); static assert(!__traits(compiles, { inout(B)[] b = dsc; })); static assert(!__traits(compiles, { shared(B)[] b = dsc; })); static assert( __traits(compiles, { shared(const B)[] b = dsc; })); static assert(!__traits(compiles, { shared(inout B)[] b = dsc; })); static assert(!__traits(compiles, { immutable(B)[] b = dsc; })); static assert(!__traits(compiles, { B [] b = dsw; })); static assert(!__traits(compiles, { const(B)[] b = dsw; })); static assert(!__traits(compiles, { inout(B)[] b = dsw; })); static assert(!__traits(compiles, { shared(B)[] b = dsw; })); static assert( __traits(compiles, { shared(const B)[] b = dsw; })); static assert(!__traits(compiles, { shared(inout B)[] b = dsw; })); static assert(!__traits(compiles, { immutable(B)[] b = dsw; })); static assert(!__traits(compiles, { B [] b = di; })); static assert( __traits(compiles, { const(B)[] b = di; })); static assert(!__traits(compiles, { inout(B)[] b = di; })); static assert(!__traits(compiles, { shared(B)[] b = di; })); static assert( __traits(compiles, { shared(const B)[] b = di; })); static assert(!__traits(compiles, { shared(inout B)[] b = di; })); static assert( __traits(compiles, { immutable(B)[] b = di; })); } /************************************/ // 11768 void test11768(inout int = 0) { const(inout(char)) k1; inout(const(char)) k2; static assert(typeof(k1).stringof == "inout(const(char))"); // OK static assert(typeof(k2).stringof == "inout(const(char))"); // fails static assert(is(typeof(k1) == typeof(k2))); // fails } /************************************/ // 12403 void test12403() { void func(K, V)(inout(V[K]) aa) { static assert(is(V == const int)); static assert(is(K == int)); } const(int)[int] m; func(m); } /************************************/ // 13011 void test13011() { static size_t hashOf(int delegate() inout val) { return 0; } int delegate() inout dg; auto h = hashOf(dg); } /************************************/ // 13030 void va13030(Args...)(const Args args) {} void func13030(int delegate(int n) a) { va13030(a); } /************************************/ // 13802 & 13803 static assert(( string ).stringof == "string" ); static assert(( string[] ).stringof == "string[]" ); static assert(( string[1] ).stringof == "string[1]" ); static assert(( string[int]).stringof == "string[int]" ); static assert(( const string ).stringof == "const(string)" ); static assert(( const string[] ).stringof == "const(string[])" ); static assert(( const string[1] ).stringof == "const(string[1])" ); static assert(( const string[int]).stringof == "const(string[int])" ); static assert((shared string ).stringof == "shared(string)" ); static assert((shared string[] ).stringof == "shared(string[])" ); static assert((shared string[1] ).stringof == "shared(string[1])" ); static assert((shared string[int]).stringof == "shared(string[int])" ); static assert((shared const string ).stringof == "shared(const(string))" ); static assert((shared const string[] ).stringof == "shared(const(string[]))" ); static assert((shared const string[1] ).stringof == "shared(const(string[1]))" ); static assert((shared const string[int]).stringof == "shared(const(string[int]))"); static assert(( immutable string ).stringof == "immutable(string)" ); static assert(( immutable string[] ).stringof == "immutable(string[])" ); static assert(( immutable string[1] ).stringof == "immutable(string[1])" ); static assert(( immutable string[int]).stringof == "immutable(string[int])" ); static assert(( wstring ).stringof == "wstring" ); static assert(( wstring[] ).stringof == "wstring[]" ); static assert(( wstring[1] ).stringof == "wstring[1]" ); static assert(( wstring[int]).stringof == "wstring[int]" ); static assert(( const wstring ).stringof == "const(wstring)" ); static assert(( const wstring[] ).stringof == "const(wstring[])" ); static assert(( const wstring[1] ).stringof == "const(wstring[1])" ); static assert(( const wstring[int]).stringof == "const(wstring[int])" ); static assert((shared wstring ).stringof == "shared(wstring)" ); static assert((shared wstring[] ).stringof == "shared(wstring[])" ); static assert((shared wstring[1] ).stringof == "shared(wstring[1])" ); static assert((shared wstring[int]).stringof == "shared(wstring[int])" ); static assert((shared const wstring ).stringof == "shared(const(wstring))" ); static assert((shared const wstring[] ).stringof == "shared(const(wstring[]))" ); static assert((shared const wstring[1] ).stringof == "shared(const(wstring[1]))" ); static assert((shared const wstring[int]).stringof == "shared(const(wstring[int]))"); static assert(( immutable wstring ).stringof == "immutable(wstring)" ); static assert(( immutable wstring[] ).stringof == "immutable(wstring[])" ); static assert(( immutable wstring[1] ).stringof == "immutable(wstring[1])" ); static assert(( immutable wstring[int]).stringof == "immutable(wstring[int])" ); static assert(( dstring ).stringof == "dstring" ); static assert(( dstring[] ).stringof == "dstring[]" ); static assert(( dstring[1] ).stringof == "dstring[1]" ); static assert(( dstring[int]).stringof == "dstring[int]" ); static assert(( const dstring ).stringof == "const(dstring)" ); static assert(( const dstring[] ).stringof == "const(dstring[])" ); static assert(( const dstring[1] ).stringof == "const(dstring[1])" ); static assert(( const dstring[int]).stringof == "const(dstring[int])" ); static assert((shared dstring ).stringof == "shared(dstring)" ); static assert((shared dstring[] ).stringof == "shared(dstring[])" ); static assert((shared dstring[1] ).stringof == "shared(dstring[1])" ); static assert((shared dstring[int]).stringof == "shared(dstring[int])" ); static assert((shared const dstring ).stringof == "shared(const(dstring))" ); static assert((shared const dstring[] ).stringof == "shared(const(dstring[]))" ); static assert((shared const dstring[1] ).stringof == "shared(const(dstring[1]))" ); static assert((shared const dstring[int]).stringof == "shared(const(dstring[int]))"); static assert(( immutable dstring ).stringof == "immutable(dstring)" ); static assert(( immutable dstring[] ).stringof == "immutable(dstring[])" ); static assert(( immutable dstring[1] ).stringof == "immutable(dstring[1])" ); static assert(( immutable dstring[int]).stringof == "immutable(dstring[int])" ); /************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test50(); test51(); test52(); test53(); test54(); test55(); test56(); test57(); test58(); test59(); test60(); test61(); test62(); test63(); test64(); test65(); test66(); test68(); test69(); test70(); test72(); test73(); test74(); test75(); test76(); test77(); test78(); test79(); test80(); test81(); test82(); test83(); test84(); test85(); test87(); test4968(); test3748(); test1961a(); test1961b(); test1961c(); test88(); test4251a(); test4251b(); test5473(); test5493(); test5493inout(); test6782(); test6864(); test6865(); test6866(); test6870(); test6912(); test6930a(); test6930b(); test11868(); test6939(); test6940(); test6982(); test7038(); test7105(); test7202(); test7554(); test7518(); test7669(); test7757(); test8098(); test8099(); test8201(); test8212(); test8366(); test8408(); test8688(); test9046(); test9090(); test9461(); test9209(); test11226(); test11768(); test13011(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link14834.sh0000775000175000017500000000121312776215022022101 0ustar kaikai#!/usr/bin/env bash src=runnable${SEP}extra-files dir=${RESULTS_DIR}${SEP}runnable output_file=${dir}${SEP}link14834.sh.out rm -f ${output_file} if [ $OS == "win32" -o $OS == "win64" ]; then LIBEXT=.lib else LIBEXT=.a fi libname=${dir}${SEP}link14834${LIBEXT} exename=${dir}${SEP}link14834${EXE} $DMD -m${MODEL} -I${src} -lib -of${libname} ${src}${SEP}link14834a.d > ${output_file} || exit 1 $DMD -m${MODEL} -I${src} -inline -debug -of${exename} ${src}${SEP}link14834b.d ${libname} > ${output_file} || exit 1 ${dir}/link14834 || exit 1 rm ${libname} ${exename} ${dir}${SEP}link14834${OBJ} echo Success > ${output_file} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/sieve.d0000664000175000017500000000145112776215022021465 0ustar kaikai// PERMUTE_ARGS: // REQUIRED_ARGS: -cov // POST_SCRIPT: runnable/extra-files/sieve-postscript.sh // EXECUTE_ARGS: ${RESULTS_DIR}/runnable /* Eratosthenes Sieve prime number calculation. */ import std.stdio; bool flags[8191]; int sieve() { int count; writefln("10 iterations"); for (int iter = 1; iter <= 10; iter++) { count = 0; flags[] = true; for (int i = 0; i < flags.length; i++) { if (flags[i]) { int prime = i + i + 3; int k = i + prime; while (k < flags.length) { flags[k] = false; k += prime; } count += 1; } } } writefln("%d primes", count); return 0; } extern(C) void dmd_coverDestPath(string path); int main(string[] args) { dmd_coverDestPath(args[1]); sieve(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/untag.d0000664000175000017500000001175312776215022021476 0ustar kaikai// PERMUTE_ARGS: import std.algorithm, std.ascii, std.conv, std.exception, std.file, std.getopt, std.path, std.range, std.stdio, std.string, std.traits; auto binaryFun(string pred, T, U)(T a, U b) { return(mixin(pred)); } /** If $(D startsWith(r1, r2)), consume the corresponding elements off $(D r1) and return $(D true). Otherwise, leave $(D r1) unchanged and return $(D false). */ bool startsWithConsume(alias pred = "a == b", R1, R2)(ref R1 r1, R2 r2) { auto r = r1; // .save(); while (!r2.empty && !r.empty && binaryFun!pred(r.front, r2.front)) { r.popFront(); r2.popFront(); } return r2.empty ? (r1 = r, true) : false; } uint bug = 1; int main(string args[]) { getopt(args, "bug", &bug); enforce(bug <= 2); auto txt = readText("runnable/extra-files/untag.html"); untag(txt, "runnable/extra-files/untag.html"); return 0; } void untag(string txt, string filename) { string currentParagraph; string origtxt = txt; string origtxtcopy = txt.idup; // Find beginning of content txt = std.algorithm.find(txt, "\n"); // Ancillary function that commits the current paragraph for // writing void commit() { writeParagraph(strip(currentParagraph)); } void writeChar(dchar c) { immutable lastWritten = currentParagraph.length ? currentParagraph.back : dchar.init; if (lastWritten == ' ' && c == ' ') { // Two consecutive spaces fused } else { // Normal case currentParagraph ~= c; } } void writeWords(string s) { if (bug == 0) { foreach (dchar c; s) { currentParagraph ~= c; } } else if (bug == 1) { reserve(currentParagraph, currentParagraph.length + s.length); currentParagraph ~= s; } else { currentParagraph = currentParagraph ~ s; } } // Parse the content while (!txt.empty) { size_t i = 0; while (i < txt.length && txt[i] != '<' && txt[i] != '&') { ++i; } writeWords(txt[0 .. i]); if (i == txt.length) { commit(); return; } txt = txt[i .. $]; auto c = txt[0]; txt = txt[1 .. $]; if (c == '<') { // This is a tag if (startsWithConsume(txt, `/p>`) || startsWithConsume(txt, `/li>`)) { // End of paragraph commit(); } else { // This is an uninteresting tag enforce(findConsume(txt, '>'), "Could not find closing tag: "~txt); } } else { auto app = appender!string(); findConsume(txt, ';', app); switch (app.data) { case "#160;": case "#32;": case "reg;": case "nbsp;": writeChar(' '); break; case "amp;": writeChar('&'); break; case "gt;": writeChar('>'); break; case "lt;": writeChar('<'); break; case "quot;": writeChar('"'); break; default: throw new Exception(text("Unknown code: &", app.data)); break; } } } } void writeParagraph(string sentence) { static bool isSeparator(dchar a) { return !(isAlpha(a) /*|| a == '.'*/); } foreach (string cand; std.algorithm.splitter(sentence, ' ')) { cand = toLower(cand); } } /** If $(D r2) can not be found in $(D r1), leave $(D r1) unchanged and return $(D false). Otherwise, consume elements in $(D r1) until $(D startsWithConsume(r1, r2)), and return $(D true). Effectively positions $(D r1) right after $(D r2). */ bool findConsume(R1, R2)(ref R1 r1, R2 r2) if (isForwardRange!R2) { auto r = r1; // .save(); while (!r.empty) { if (startsWithConsume(r, r2)) { r1 = r; return true; } r.popFront(); } return false; } /** If $(D r2) can not be found in $(D r1), leave $(D r1) unchanged and return $(D false). Otherwise, consume elements in $(D r1) until $(D startsWith(r1, r2)), and return $(D true). */ bool findConsume(R, E)(ref R r, E e) if (is(typeof(r.front == e))) { auto r1 = std.algorithm.find(r, e); if (r1.empty) return false; r = r1; r.popFront(); return true; } /** If $(D r2) can not be found in $(D r1), leave $(D r1) unchanged and return $(D false). Otherwise, consume elements in $(D r1) until $(D startsWith(r1, r2)), and return $(D true). */ bool findConsume(R1, E, R2)(ref R1 r1, E e, R2 r2) if (is(typeof(r1.front == e))) { auto r = r1; while (!r.empty) { r2.put(r.front); if (r.front == e) { r.popFront(); r1 = r; return true; } r.popFront(); } return false; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/a19.d0000664000175000017500000000026112776215022020742 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/a19a.d // PERMUTE_ARGS: import imports.a19a; int main(char[][] args) { TemplatedStruct!(Dummy) e; return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test3.d0000664000175000017500000000100212776215022021404 0ustar kaikai// PERMUTE_ARGS: // EXTRA_SOURCES: imports/test3a.d imports/test3b.d import imports.test3a; extern(C) int printf(const char*, ...); class Foo { string bar; unittest { printf("in Foo.unittest()\n"); } } void test(int a) { } void test(uint b) { } int main(string[] args) { Foo a = new Foo; string baz = "lolo"; test(3); a.bar = "hello"; a.bar = baz ~ "betty"; printf("a.bar = '%.*s'\n", a.bar.length, a.bar.ptr); assert(a.bar == "lolobetty"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/pi.d0000664000175000017500000000441212776215022020762 0ustar kaikai// PERMUTE_ARGS: // EXECUTE_ARGS: 1000 import core.stdc.stdio; import core.stdc.time; const int LONG_TIME=4000; byte[] p; byte[] t; int q; int main(char[][] args) { time_t startime, endtime; int i; if (args.length == 2) { sscanf(&args[1][0],"%d",&q); } else { printf("Usage: pi [precision]\n"); return 1; } if (q < 0) { printf("Precision was too low, running with precision of 0.\n"); q = 0; } if (q > LONG_TIME) { printf("Be prepared to wait a while...\n"); } // Compute one more digit than we display to compensate for rounding q++; p.length = q + 1; t.length = q + 1; /* compute pi */ time(&startime); arctan(2); arctan(3); mul4(); time(&endtime); // Return to the number of digits we want to display q--; /* print pi */ printf("pi = %d.",cast(int)(p[0])); for (i = 1; i <= q; i++) printf("%d",cast(int)(p[i])); printf("\n"); printf("%lld seconds to compute pi with a precision of %d digits.\n", cast(long)(endtime-startime),q); return 0; } void arctan(int s) { int n; t[0] = 1; div(s); /* t[] = 1/s */ add(); n = 1; do { mul(n); div(s * s); div(n += 2); if (((n-1) / 2) % 2 == 0) add(); else sub(); } while (!tiszero()); } void add() { int j; for (j = q; j >= 0; j--) { if (t[j] + p[j] > 9) { p[j] += t[j] - 10; p[j-1] += 1; } else p[j] += t[j]; } } void sub() { int j; for (j = q; j >= 0; j--) if (p[j] < t[j]) { p[j] -= t[j] - 10; p[j-1] -= 1; } else p[j] -= t[j]; } void mul(int multiplier) { int b; int i; int carry = 0, digit = 0; for (i = q; i >= 0; i--) { b = (t[i] * multiplier + carry); digit = b % 10; carry = b / 10; t[i] = cast(byte)digit; } } /* t[] /= l */ void div(int divisor) { int i, b; int quotient, remainder = 0; foreach (ref x; t) { b = (10 * remainder + x); quotient = b / divisor; remainder = b % divisor; x = cast(byte)quotient; } } void div4() { int i, c, d = 0; for (i = 0; i <= q; i++) { c = (10 * d + p[i]) / 4; d = (10 * d + p[i]) % 4; p[i] = cast(byte)c; } } void mul4() { int i, c, d; d = c = 0; for (i = q; i >= 0; i--) { d = (p[i] * 4 + c) % 10; c = (p[i] * 4 + c) / 10; p[i] = cast(byte)d; } } int tiszero() { int k; for (k = 0; k <= q; k++) if (t[k] != 0) return false; return true; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test8182.d0000664000175000017500000000016712776215022021657 0ustar kaikaistruct S { ~this() { assert(false); } } void lazily(lazy S) { } void main() { lazily(S()); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/traits.d0000664000175000017500000013763612776215022021677 0ustar kaikai// PERMUTE_ARGS: module traits; import std.stdio; alias int myint; struct S { void bar() { } int x = 4; static int z = 5; } class C { void bar() { } final void foo() { } static void abc() { } } abstract class AC { } class AC2 { abstract void foo(); } class AC3 : AC2 { } final class FC { void foo() { } } enum E { EMEM } /********************************************************/ void test1() { auto t = __traits(isArithmetic, int); writeln(t); assert(t == true); assert(__traits(isArithmetic) == false); assert(__traits(isArithmetic, myint) == true); assert(__traits(isArithmetic, S) == false); assert(__traits(isArithmetic, C) == false); assert(__traits(isArithmetic, E) == true); assert(__traits(isArithmetic, void*) == false); assert(__traits(isArithmetic, void[]) == false); assert(__traits(isArithmetic, void[3]) == false); assert(__traits(isArithmetic, int[char]) == false); assert(__traits(isArithmetic, int, int) == true); assert(__traits(isArithmetic, int, S) == false); assert(__traits(isArithmetic, void) == false); assert(__traits(isArithmetic, byte) == true); assert(__traits(isArithmetic, ubyte) == true); assert(__traits(isArithmetic, short) == true); assert(__traits(isArithmetic, ushort) == true); assert(__traits(isArithmetic, int) == true); assert(__traits(isArithmetic, uint) == true); assert(__traits(isArithmetic, long) == true); assert(__traits(isArithmetic, ulong) == true); assert(__traits(isArithmetic, float) == true); assert(__traits(isArithmetic, double) == true); assert(__traits(isArithmetic, real) == true); assert(__traits(isArithmetic, ifloat) == true); assert(__traits(isArithmetic, idouble) == true); assert(__traits(isArithmetic, ireal) == true); assert(__traits(isArithmetic, cfloat) == true); assert(__traits(isArithmetic, cdouble) == true); assert(__traits(isArithmetic, creal) == true); assert(__traits(isArithmetic, char) == true); assert(__traits(isArithmetic, wchar) == true); assert(__traits(isArithmetic, dchar) == true); int i; assert(__traits(isArithmetic, i, i+1, int) == true); assert(__traits(isArithmetic) == false); } /********************************************************/ void test2() { auto t = __traits(isScalar, int); writeln(t); assert(t == true); assert(__traits(isScalar) == false); assert(__traits(isScalar, myint) == true); assert(__traits(isScalar, S) == false); assert(__traits(isScalar, C) == false); assert(__traits(isScalar, E) == true); assert(__traits(isScalar, void*) == true); assert(__traits(isScalar, void[]) == false); assert(__traits(isScalar, void[3]) == false); assert(__traits(isScalar, int[char]) == false); assert(__traits(isScalar, int, int) == true); assert(__traits(isScalar, int, S) == false); assert(__traits(isScalar, void) == false); assert(__traits(isScalar, byte) == true); assert(__traits(isScalar, ubyte) == true); assert(__traits(isScalar, short) == true); assert(__traits(isScalar, ushort) == true); assert(__traits(isScalar, int) == true); assert(__traits(isScalar, uint) == true); assert(__traits(isScalar, long) == true); assert(__traits(isScalar, ulong) == true); assert(__traits(isScalar, float) == true); assert(__traits(isScalar, double) == true); assert(__traits(isScalar, real) == true); assert(__traits(isScalar, ifloat) == true); assert(__traits(isScalar, idouble) == true); assert(__traits(isScalar, ireal) == true); assert(__traits(isScalar, cfloat) == true); assert(__traits(isScalar, cdouble) == true); assert(__traits(isScalar, creal) == true); assert(__traits(isScalar, char) == true); assert(__traits(isScalar, wchar) == true); assert(__traits(isScalar, dchar) == true); } /********************************************************/ void test3() { assert(__traits(isIntegral) == false); assert(__traits(isIntegral, myint) == true); assert(__traits(isIntegral, S) == false); assert(__traits(isIntegral, C) == false); assert(__traits(isIntegral, E) == true); assert(__traits(isIntegral, void*) == false); assert(__traits(isIntegral, void[]) == false); assert(__traits(isIntegral, void[3]) == false); assert(__traits(isIntegral, int[char]) == false); assert(__traits(isIntegral, int, int) == true); assert(__traits(isIntegral, int, S) == false); assert(__traits(isIntegral, void) == false); assert(__traits(isIntegral, byte) == true); assert(__traits(isIntegral, ubyte) == true); assert(__traits(isIntegral, short) == true); assert(__traits(isIntegral, ushort) == true); assert(__traits(isIntegral, int) == true); assert(__traits(isIntegral, uint) == true); assert(__traits(isIntegral, long) == true); assert(__traits(isIntegral, ulong) == true); assert(__traits(isIntegral, float) == false); assert(__traits(isIntegral, double) == false); assert(__traits(isIntegral, real) == false); assert(__traits(isIntegral, ifloat) == false); assert(__traits(isIntegral, idouble) == false); assert(__traits(isIntegral, ireal) == false); assert(__traits(isIntegral, cfloat) == false); assert(__traits(isIntegral, cdouble) == false); assert(__traits(isIntegral, creal) == false); assert(__traits(isIntegral, char) == true); assert(__traits(isIntegral, wchar) == true); assert(__traits(isIntegral, dchar) == true); } /********************************************************/ void test4() { assert(__traits(isFloating) == false); assert(__traits(isFloating, S) == false); assert(__traits(isFloating, C) == false); assert(__traits(isFloating, E) == false); assert(__traits(isFloating, void*) == false); assert(__traits(isFloating, void[]) == false); assert(__traits(isFloating, void[3]) == false); assert(__traits(isFloating, int[char]) == false); assert(__traits(isFloating, float, float) == true); assert(__traits(isFloating, float, S) == false); assert(__traits(isFloating, void) == false); assert(__traits(isFloating, byte) == false); assert(__traits(isFloating, ubyte) == false); assert(__traits(isFloating, short) == false); assert(__traits(isFloating, ushort) == false); assert(__traits(isFloating, int) == false); assert(__traits(isFloating, uint) == false); assert(__traits(isFloating, long) == false); assert(__traits(isFloating, ulong) == false); assert(__traits(isFloating, float) == true); assert(__traits(isFloating, double) == true); assert(__traits(isFloating, real) == true); assert(__traits(isFloating, ifloat) == true); assert(__traits(isFloating, idouble) == true); assert(__traits(isFloating, ireal) == true); assert(__traits(isFloating, cfloat) == true); assert(__traits(isFloating, cdouble) == true); assert(__traits(isFloating, creal) == true); assert(__traits(isFloating, char) == false); assert(__traits(isFloating, wchar) == false); assert(__traits(isFloating, dchar) == false); } /********************************************************/ void test5() { assert(__traits(isUnsigned) == false); assert(__traits(isUnsigned, S) == false); assert(__traits(isUnsigned, C) == false); assert(__traits(isUnsigned, E) == false); assert(__traits(isUnsigned, void*) == false); assert(__traits(isUnsigned, void[]) == false); assert(__traits(isUnsigned, void[3]) == false); assert(__traits(isUnsigned, int[char]) == false); assert(__traits(isUnsigned, float, float) == false); assert(__traits(isUnsigned, float, S) == false); assert(__traits(isUnsigned, void) == false); assert(__traits(isUnsigned, byte) == false); assert(__traits(isUnsigned, ubyte) == true); assert(__traits(isUnsigned, short) == false); assert(__traits(isUnsigned, ushort) == true); assert(__traits(isUnsigned, int) == false); assert(__traits(isUnsigned, uint) == true); assert(__traits(isUnsigned, long) == false); assert(__traits(isUnsigned, ulong) == true); assert(__traits(isUnsigned, float) == false); assert(__traits(isUnsigned, double) == false); assert(__traits(isUnsigned, real) == false); assert(__traits(isUnsigned, ifloat) == false); assert(__traits(isUnsigned, idouble) == false); assert(__traits(isUnsigned, ireal) == false); assert(__traits(isUnsigned, cfloat) == false); assert(__traits(isUnsigned, cdouble) == false); assert(__traits(isUnsigned, creal) == false); assert(__traits(isUnsigned, char) == true); assert(__traits(isUnsigned, wchar) == true); assert(__traits(isUnsigned, dchar) == true); } /********************************************************/ void test6() { assert(__traits(isAssociativeArray) == false); assert(__traits(isAssociativeArray, S) == false); assert(__traits(isAssociativeArray, C) == false); assert(__traits(isAssociativeArray, E) == false); assert(__traits(isAssociativeArray, void*) == false); assert(__traits(isAssociativeArray, void[]) == false); assert(__traits(isAssociativeArray, void[3]) == false); assert(__traits(isAssociativeArray, int[char]) == true); assert(__traits(isAssociativeArray, float, float) == false); assert(__traits(isAssociativeArray, float, S) == false); assert(__traits(isAssociativeArray, void) == false); assert(__traits(isAssociativeArray, byte) == false); assert(__traits(isAssociativeArray, ubyte) == false); assert(__traits(isAssociativeArray, short) == false); assert(__traits(isAssociativeArray, ushort) == false); assert(__traits(isAssociativeArray, int) == false); assert(__traits(isAssociativeArray, uint) == false); assert(__traits(isAssociativeArray, long) == false); assert(__traits(isAssociativeArray, ulong) == false); assert(__traits(isAssociativeArray, float) == false); assert(__traits(isAssociativeArray, double) == false); assert(__traits(isAssociativeArray, real) == false); assert(__traits(isAssociativeArray, ifloat) == false); assert(__traits(isAssociativeArray, idouble) == false); assert(__traits(isAssociativeArray, ireal) == false); assert(__traits(isAssociativeArray, cfloat) == false); assert(__traits(isAssociativeArray, cdouble) == false); assert(__traits(isAssociativeArray, creal) == false); assert(__traits(isAssociativeArray, char) == false); assert(__traits(isAssociativeArray, wchar) == false); assert(__traits(isAssociativeArray, dchar) == false); } /********************************************************/ void test7() { assert(__traits(isStaticArray) == false); assert(__traits(isStaticArray, S) == false); assert(__traits(isStaticArray, C) == false); assert(__traits(isStaticArray, E) == false); assert(__traits(isStaticArray, void*) == false); assert(__traits(isStaticArray, void[]) == false); assert(__traits(isStaticArray, void[3]) == true); assert(__traits(isStaticArray, int[char]) == false); assert(__traits(isStaticArray, float, float) == false); assert(__traits(isStaticArray, float, S) == false); assert(__traits(isStaticArray, void) == false); assert(__traits(isStaticArray, byte) == false); assert(__traits(isStaticArray, ubyte) == false); assert(__traits(isStaticArray, short) == false); assert(__traits(isStaticArray, ushort) == false); assert(__traits(isStaticArray, int) == false); assert(__traits(isStaticArray, uint) == false); assert(__traits(isStaticArray, long) == false); assert(__traits(isStaticArray, ulong) == false); assert(__traits(isStaticArray, float) == false); assert(__traits(isStaticArray, double) == false); assert(__traits(isStaticArray, real) == false); assert(__traits(isStaticArray, ifloat) == false); assert(__traits(isStaticArray, idouble) == false); assert(__traits(isStaticArray, ireal) == false); assert(__traits(isStaticArray, cfloat) == false); assert(__traits(isStaticArray, cdouble) == false); assert(__traits(isStaticArray, creal) == false); assert(__traits(isStaticArray, char) == false); assert(__traits(isStaticArray, wchar) == false); assert(__traits(isStaticArray, dchar) == false); } /********************************************************/ void test8() { assert(__traits(isAbstractClass) == false); assert(__traits(isAbstractClass, S) == false); assert(__traits(isAbstractClass, C) == false); assert(__traits(isAbstractClass, AC) == true); assert(__traits(isAbstractClass, E) == false); assert(__traits(isAbstractClass, void*) == false); assert(__traits(isAbstractClass, void[]) == false); assert(__traits(isAbstractClass, void[3]) == false); assert(__traits(isAbstractClass, int[char]) == false); assert(__traits(isAbstractClass, float, float) == false); assert(__traits(isAbstractClass, float, S) == false); assert(__traits(isAbstractClass, void) == false); assert(__traits(isAbstractClass, byte) == false); assert(__traits(isAbstractClass, ubyte) == false); assert(__traits(isAbstractClass, short) == false); assert(__traits(isAbstractClass, ushort) == false); assert(__traits(isAbstractClass, int) == false); assert(__traits(isAbstractClass, uint) == false); assert(__traits(isAbstractClass, long) == false); assert(__traits(isAbstractClass, ulong) == false); assert(__traits(isAbstractClass, float) == false); assert(__traits(isAbstractClass, double) == false); assert(__traits(isAbstractClass, real) == false); assert(__traits(isAbstractClass, ifloat) == false); assert(__traits(isAbstractClass, idouble) == false); assert(__traits(isAbstractClass, ireal) == false); assert(__traits(isAbstractClass, cfloat) == false); assert(__traits(isAbstractClass, cdouble) == false); assert(__traits(isAbstractClass, creal) == false); assert(__traits(isAbstractClass, char) == false); assert(__traits(isAbstractClass, wchar) == false); assert(__traits(isAbstractClass, dchar) == false); assert(__traits(isAbstractClass, AC2) == true); assert(__traits(isAbstractClass, AC3) == true); } /********************************************************/ void test9() { assert(__traits(isFinalClass) == false); assert(__traits(isFinalClass, C) == false); assert(__traits(isFinalClass, FC) == true); } /********************************************************/ void test10() { assert(__traits(isVirtualFunction, C.bar) == true); assert(__traits(isVirtualFunction, S.bar) == false); } /********************************************************/ void test11() { assert(__traits(isAbstractFunction, C.bar) == false); assert(__traits(isAbstractFunction, S.bar) == false); assert(__traits(isAbstractFunction, AC2.foo) == true); } /********************************************************/ void test12() { assert(__traits(isFinalFunction, C.bar) == false); assert(__traits(isFinalFunction, S.bar) == false); assert(__traits(isFinalFunction, AC2.foo) == false); assert(__traits(isFinalFunction, FC.foo) == true); assert(__traits(isFinalFunction, C.foo) == true); } /********************************************************/ void test13() { S s; __traits(getMember, s, "x") = 7; auto i = __traits(getMember, s, "x"); assert(i == 7); auto j = __traits(getMember, S, "z"); assert(j == 5); writeln(__traits(hasMember, s, "x")); assert(__traits(hasMember, s, "x") == true); assert(__traits(hasMember, S, "z") == true); assert(__traits(hasMember, S, "aaa") == false); auto k = __traits(classInstanceSize, C); writeln(k); assert(k == C.classinfo.init.length); } /********************************************************/ // 7123 private struct DelegateFaker7123(F) { template GeneratingPolicy() {} enum WITH_BASE_CLASS = __traits(hasMember, GeneratingPolicy!(), "x"); } auto toDelegate7123(F)(F fp) { alias DelegateFaker7123!F Faker; } void test7123() { static assert(is(typeof(toDelegate7123(&main)))); } /********************************************************/ class D14 { this() { } ~this() { } void foo() { } int foo(int) { return 0; } } void test14() { auto a = [__traits(derivedMembers, D14)]; writeln(a); assert(a == ["__ctor","__dtor","foo", "__xdtor"]); } /********************************************************/ class D15 { this() { } ~this() { } void foo() { } int foo(int) { return 2; } } void test15() { D15 d = new D15(); foreach (t; __traits(getVirtualFunctions, D15, "foo")) writeln(typeid(typeof(t))); alias typeof(__traits(getVirtualFunctions, D15, "foo")) b; foreach (t; b) writeln(typeid(t)); auto i = __traits(getVirtualFunctions, d, "foo")[1](1); assert(i == 2); } /********************************************************/ struct S16 { } int foo16(); int bar16(); void test16() { assert(__traits(isSame, foo16, foo16) == true); assert(__traits(isSame, foo16, bar16) == false); assert(__traits(isSame, foo16, S16) == false); assert(__traits(isSame, S16, S16) == true); assert(__traits(isSame, std, S16) == false); assert(__traits(isSame, std, std) == true); } /********************************************************/ struct S17 { static int s1; int s2; } int foo17(); void test17() { assert(__traits(compiles) == false); assert(__traits(compiles, foo17) == true); assert(__traits(compiles, foo17 + 1) == true); assert(__traits(compiles, &foo17 + 1) == false); assert(__traits(compiles, typeof(1)) == true); assert(__traits(compiles, S17.s1) == true); assert(__traits(compiles, S17.s3) == false); assert(__traits(compiles, 1,2,3,int,long,std) == true); assert(__traits(compiles, 3[1]) == false); assert(__traits(compiles, 1,2,3,int,long,3[1]) == false); } /********************************************************/ interface D18 { extern(Windows): void foo(); int foo(int); } void test18() { auto a = __traits(allMembers, D18); writeln(a); assert(a.length == 1); } /********************************************************/ class C19 { void mutating_method(){} const void const_method(){} void bastard_method(){} const void bastard_method(int){} } void test19() { auto a = __traits(allMembers, C19); writeln(a); assert(a.length == 9); foreach( m; __traits(allMembers, C19) ) writeln(m); } /********************************************************/ void test20() { void fooref(ref int x) { static assert(__traits(isRef, x)); static assert(!__traits(isOut, x)); static assert(!__traits(isLazy, x)); } void fooout(out int x) { static assert(!__traits(isRef, x)); static assert(__traits(isOut, x)); static assert(!__traits(isLazy, x)); } void foolazy(lazy int x) { static assert(!__traits(isRef, x)); static assert(!__traits(isOut, x)); static assert(__traits(isLazy, x)); } } /********************************************************/ void test21() { assert(__traits(isStaticFunction, C.bar) == false); assert(__traits(isStaticFunction, C.abc) == true); assert(__traits(isStaticFunction, S.bar) == false); } /********************************************************/ class D22 { this() { } ~this() { } void foo() { } int foo(int) { return 2; } } void test22() { D22 d = new D22(); foreach (t; __traits(getOverloads, D22, "foo")) writeln(typeid(typeof(t))); alias typeof(__traits(getOverloads, D22, "foo")) b; foreach (t; b) writeln(typeid(t)); auto i = __traits(getOverloads, d, "foo")[1](1); assert(i == 2); } /********************************************************/ string toString23(E)(E value) if (is(E == enum)) { foreach (s; __traits(allMembers, E)) { if (value == mixin("E." ~ s)) return s; } return null; } enum OddWord { acini, alembicated, prolegomena, aprosexia } void test23() { auto w = OddWord.alembicated; assert(toString23(w) == "alembicated"); } /********************************************************/ struct Test24 { public void test24(int){} private void test24(int, int){} } static assert(__traits(getProtection, __traits(getOverloads, Test24, "test24")[1]) == "private"); /********************************************************/ // 1369 void test1369() { class C1 { static int count; void func() { count++; } } // variable symbol C1 c1 = new C1; __traits(getMember, c1, "func")(); // TypeIdentifier -> VarExp __traits(getMember, mixin("c1"), "func")(); // Expression -> VarExp assert(C1.count == 2); // nested function symbol @property C1 get() { return c1; } __traits(getMember, get, "func")(); __traits(getMember, mixin("get"), "func")(); assert(C1.count == 4); class C2 { C1 c1; this() { c1 = new C1; } void test() { // variable symbol (this.outer.c1) __traits(getMember, c1, "func")(); // TypeIdentifier -> VarExp -> DotVarExp __traits(getMember, mixin("c1"), "func")(); // Expression -> VarExp -> DotVarExp assert(C1.count == 6); // nested function symbol (this.outer.get) __traits(getMember, get, "func")(); __traits(getMember, mixin("get"), "func")(); assert(C1.count == 8); } } C2 c2 = new C2; c2.test(); } /********************************************************/ template Foo2234(){ int x; } struct S2234a{ mixin Foo2234; } struct S2234b{ mixin Foo2234; mixin Foo2234; } struct S2234c{ alias Foo2234!() foo; } static assert([__traits(allMembers, S2234a)] == ["x"]); static assert([__traits(allMembers, S2234b)] == ["x"]); static assert([__traits(allMembers, S2234c)] == ["foo"]); /********************************************************/ // 5878 template J5878(A) { static if (is(A P == super)) alias P J5878; } alias J5878!(A5878) Z5878; class X5878 {} class A5878 : X5878 {} /********************************************************/ mixin template Members6674() { static int i1; static int i2; static int i3; //comment out to make func2 visible static int i4; //comment out to make func1 visible } class Test6674 { mixin Members6674; alias void function() func1; alias bool function() func2; } static assert([__traits(allMembers,Test6674)] == [ "i1","i2","i3","i4", "func1","func2", "toString","toHash","opCmp","opEquals","Monitor","factory"]); /********************************************************/ // 6073 struct S6073 {} template T6073(M...) { //alias int T; } alias T6073!traits V6073; // ok alias T6073!(__traits(parent, S6073)) U6073; // error static assert(__traits(isSame, V6073, U6073)); // same instantiation == same arguemnts /********************************************************/ // 7027 struct Foo7027 { int a; } static assert(!__traits(compiles, { return Foo7027.a; })); /********************************************************/ // 9213 class Foo9213 { int a; } static assert(!__traits(compiles, { return Foo9213.a; })); /********************************************************/ interface AA { int YYY(); } class CC : AA { final int YYY() { return 4; } } static assert(__traits(isVirtualMethod, CC.YYY)); static assert(__traits(getVirtualMethods, CC, "YYY").length == 1); class DD { final int YYY() { return 4; } } static assert(__traits(isVirtualMethod, DD.YYY) == false); static assert(__traits(getVirtualMethods, DD, "YYY").length == 0); class EE { int YYY() { return 0; } } class FF : EE { final override int YYY() { return 4; } } static assert(__traits(isVirtualMethod, FF.YYY)); static assert(__traits(getVirtualMethods, FF, "YYY").length == 1); /********************************************************/ // 7608 struct S7608a(bool T) { static if (T) { int x; } int y; } struct S7608b { version(none) { int x; } int y; } template TypeTuple7608(T...){ alias T TypeTuple7608; } void test7608() { alias TypeTuple7608!(__traits(allMembers, S7608a!false)) MembersA; static assert(MembersA.length == 1); static assert(MembersA[0] == "y"); alias TypeTuple7608!(__traits(allMembers, S7608b)) MembersB; static assert(MembersB.length == 1); static assert(MembersB[0] == "y"); } /********************************************************/ // 7858 void test7858() { class C { final void ffunc(){} final void ffunc(int){} void vfunc(){} void vfunc(int){} abstract void afunc(); abstract void afunc(int); static void sfunc(){} static void sfunc(int){} } static assert(__traits(isFinalFunction, C.ffunc) == __traits(isFinalFunction, __traits(getOverloads, C, "ffunc")[0])); // NG static assert(__traits(isVirtualFunction, C.vfunc) == __traits(isVirtualFunction, __traits(getOverloads, C, "vfunc")[0])); // NG static assert(__traits(isVirtualMethod, C.vfunc) == __traits(isVirtualMethod, __traits(getOverloads, C, "vfunc")[0])); // NG static assert(__traits(isAbstractFunction, C.afunc) == __traits(isAbstractFunction, __traits(getOverloads, C, "afunc")[0])); // OK static assert(__traits(isStaticFunction, C.sfunc) == __traits(isStaticFunction, __traits(getOverloads, C, "sfunc")[0])); // OK static assert(__traits(isSame, C.ffunc, __traits(getOverloads, C, "ffunc")[0])); // NG static assert(__traits(isSame, C.vfunc, __traits(getOverloads, C, "vfunc")[0])); // NG static assert(__traits(isSame, C.afunc, __traits(getOverloads, C, "afunc")[0])); // NG static assert(__traits(isSame, C.sfunc, __traits(getOverloads, C, "sfunc")[0])); // NG } /********************************************************/ // 8971 template Tuple8971(TL...){ alias TL Tuple8971; } class A8971 { void bar() {} void connect() { alias Tuple8971!(__traits(getOverloads, typeof(this), "bar")) overloads; static assert(__traits(isSame, overloads[0], bar)); } } /********************************************************/ // 8972 struct A8972 { void foo() {} void connect() { alias Tuple8971!(__traits(getOverloads, typeof(this), "foo")) overloads; static assert(__traits(isSame, overloads[0], foo)); } } /********************************************************/ private struct TestProt1 {} package struct TestProt2 {} protected struct TestProt3 {} public struct TestProt4 {} export struct TestProt5 {} void getProtection() { class Test { private { int va; void fa(){} } package { int vb; void fb(){} } protected { int vc; void fc(){} } public { int vd; void fd(){} } export { int ve; void fe(){} } } Test t; // TOKvar and VarDeclaration static assert(__traits(getProtection, Test.va) == "private"); static assert(__traits(getProtection, Test.vb) == "package"); static assert(__traits(getProtection, Test.vc) == "protected"); static assert(__traits(getProtection, Test.vd) == "public"); static assert(__traits(getProtection, Test.ve) == "export"); // TOKdotvar and VarDeclaration static assert(__traits(getProtection, t.va) == "private"); static assert(__traits(getProtection, t.vb) == "package"); static assert(__traits(getProtection, t.vc) == "protected"); static assert(__traits(getProtection, t.vd) == "public"); static assert(__traits(getProtection, t.ve) == "export"); // TOKvar and FuncDeclaration static assert(__traits(getProtection, Test.fa) == "private"); static assert(__traits(getProtection, Test.fb) == "package"); static assert(__traits(getProtection, Test.fc) == "protected"); static assert(__traits(getProtection, Test.fd) == "public"); static assert(__traits(getProtection, Test.fe) == "export"); // TOKdotvar and FuncDeclaration static assert(__traits(getProtection, t.fa) == "private"); static assert(__traits(getProtection, t.fb) == "package"); static assert(__traits(getProtection, t.fc) == "protected"); static assert(__traits(getProtection, t.fd) == "public"); static assert(__traits(getProtection, t.fe) == "export"); // TOKtype static assert(__traits(getProtection, TestProt1) == "private"); static assert(__traits(getProtection, TestProt2) == "package"); static assert(__traits(getProtection, TestProt3) == "protected"); static assert(__traits(getProtection, TestProt4) == "public"); static assert(__traits(getProtection, TestProt5) == "export"); // This specific pattern is important to ensure it always works // through reflection, however that becomes implemented static assert(__traits(getProtection, __traits(getMember, t, "va")) == "private"); static assert(__traits(getProtection, __traits(getMember, t, "vb")) == "package"); static assert(__traits(getProtection, __traits(getMember, t, "vc")) == "protected"); static assert(__traits(getProtection, __traits(getMember, t, "vd")) == "public"); static assert(__traits(getProtection, __traits(getMember, t, "ve")) == "export"); static assert(__traits(getProtection, __traits(getMember, t, "fa")) == "private"); static assert(__traits(getProtection, __traits(getMember, t, "fb")) == "package"); static assert(__traits(getProtection, __traits(getMember, t, "fc")) == "protected"); static assert(__traits(getProtection, __traits(getMember, t, "fd")) == "public"); static assert(__traits(getProtection, __traits(getMember, t, "fe")) == "export"); } /********************************************************/ // 9546 void test9546() { import imports.a9546 : S; S s; static assert(__traits(getProtection, s.privA) == "private"); static assert(__traits(getProtection, s.protA) == "protected"); static assert(__traits(getProtection, s.packA) == "package"); static assert(__traits(getProtection, S.privA) == "private"); static assert(__traits(getProtection, S.protA) == "protected"); static assert(__traits(getProtection, S.packA) == "package"); static assert(__traits(getProtection, mixin("s.privA")) == "private"); static assert(__traits(getProtection, mixin("s.protA")) == "protected"); static assert(__traits(getProtection, mixin("s.packA")) == "package"); static assert(__traits(getProtection, mixin("S.privA")) == "private"); static assert(__traits(getProtection, mixin("S.protA")) == "protected"); static assert(__traits(getProtection, mixin("S.packA")) == "package"); static assert(__traits(getProtection, __traits(getMember, s, "privA")) == "private"); static assert(__traits(getProtection, __traits(getMember, s, "protA")) == "protected"); static assert(__traits(getProtection, __traits(getMember, s, "packA")) == "package"); static assert(__traits(getProtection, __traits(getMember, S, "privA")) == "private"); static assert(__traits(getProtection, __traits(getMember, S, "protA")) == "protected"); static assert(__traits(getProtection, __traits(getMember, S, "packA")) == "package"); static assert(__traits(getProtection, s.privF) == "private"); static assert(__traits(getProtection, s.protF) == "protected"); static assert(__traits(getProtection, s.packF) == "package"); static assert(__traits(getProtection, S.privF) == "private"); static assert(__traits(getProtection, S.protF) == "protected"); static assert(__traits(getProtection, S.packF) == "package"); static assert(__traits(getProtection, mixin("s.privF")) == "private"); static assert(__traits(getProtection, mixin("s.protF")) == "protected"); static assert(__traits(getProtection, mixin("s.packF")) == "package"); static assert(__traits(getProtection, mixin("S.privF")) == "private"); static assert(__traits(getProtection, mixin("S.protF")) == "protected"); static assert(__traits(getProtection, mixin("S.packF")) == "package"); static assert(__traits(getProtection, __traits(getMember, s, "privF")) == "private"); static assert(__traits(getProtection, __traits(getMember, s, "protF")) == "protected"); static assert(__traits(getProtection, __traits(getMember, s, "packF")) == "package"); static assert(__traits(getProtection, __traits(getMember, S, "privF")) == "private"); static assert(__traits(getProtection, __traits(getMember, S, "protF")) == "protected"); static assert(__traits(getProtection, __traits(getMember, S, "packF")) == "package"); } /********************************************************/ // 9091 template isVariable9091(X...) if (X.length == 1) { enum isVariable9091 = true; } class C9091 { int x; // some class members void func(int n){ this.x = n; } void test() { alias T = C9091; enum is_x = isVariable9091!(__traits(getMember, T, "x")); foreach (i, m; __traits(allMembers, T)) { enum x = isVariable9091!(__traits(getMember, T, m)); static if (i == 0) // x { __traits(getMember, T, m) = 10; assert(this.x == 10); } static if (i == 1) // func { __traits(getMember, T, m)(20); assert(this.x == 20); } } } } struct S9091 { int x; // some struct members void func(int n){ this.x = n; } void test() { alias T = S9091; enum is_x = isVariable9091!(__traits(getMember, T, "x")); foreach (i, m; __traits(allMembers, T)) { enum x = isVariable9091!(__traits(getMember, T, m)); static if (i == 0) // x { __traits(getMember, T, m) = 10; assert(this.x == 10); } static if (i == 1) // func { __traits(getMember, T, m)(20); assert(this.x == 20); } } } } void test9091() { auto c = new C9091(); c.test(); auto s = S9091(); s.test(); } /********************************************************/ struct CtorS_9237 { this(int x) { } } // ctor -> POD struct DtorS_9237 { ~this() { } } // dtor -> nonPOD struct PostblitS_9237 { this(this) { } } // cpctor -> nonPOD struct NonPOD1_9237 { DtorS_9237 field; // nonPOD -> ng } struct NonPOD2_9237 { DtorS_9237[2] field; // static array of nonPOD -> ng } struct POD1_9237 { DtorS_9237* field; // pointer to nonPOD -> ok } struct POD2_9237 { DtorS_9237[] field; // dynamic array of nonPOD -> ok } struct POD3_9237 { int x = 123; } class C_9273 { } void test9237() { int x; struct NS_9237 // acceses .outer -> nested { void foo() { x++; } } struct NonNS_9237 { } // doesn't access .outer -> non-nested static struct StatNS_9237 { } // can't access .outer -> non-nested static assert(!__traits(isPOD, NS_9237)); static assert(__traits(isPOD, NonNS_9237)); static assert(__traits(isPOD, StatNS_9237)); static assert(__traits(isPOD, CtorS_9237)); static assert(!__traits(isPOD, DtorS_9237)); static assert(!__traits(isPOD, PostblitS_9237)); static assert(!__traits(isPOD, NonPOD1_9237)); static assert(!__traits(isPOD, NonPOD2_9237)); static assert(__traits(isPOD, POD1_9237)); static assert(__traits(isPOD, POD2_9237)); static assert(__traits(isPOD, POD3_9237)); // static array of POD/non-POD types static assert(!__traits(isPOD, NS_9237[2])); static assert(__traits(isPOD, NonNS_9237[2])); static assert(__traits(isPOD, StatNS_9237[2])); static assert(__traits(isPOD, CtorS_9237[2])); static assert(!__traits(isPOD, DtorS_9237[2])); static assert(!__traits(isPOD, PostblitS_9237[2])); static assert(!__traits(isPOD, NonPOD1_9237[2])); static assert(!__traits(isPOD, NonPOD2_9237[2])); static assert(__traits(isPOD, POD1_9237[2])); static assert(__traits(isPOD, POD2_9237[2])); static assert(__traits(isPOD, POD3_9237[2])); // non-structs are POD types static assert(__traits(isPOD, C_9273)); static assert(__traits(isPOD, int)); static assert(__traits(isPOD, int*)); static assert(__traits(isPOD, int[])); static assert(!__traits(compiles, __traits(isPOD, 123) )); } /*************************************************************/ // 5978 void test5978() { () { int x; pragma(msg, __traits(identifier, __traits(parent, x))); } (); } /*************************************************************/ template T7408() { } void test7408() { auto x = T7408!().stringof; auto y = T7408!().mangleof; static assert(__traits(compiles, T7408!().stringof)); static assert(__traits(compiles, T7408!().mangleof)); static assert(!__traits(compiles, T7408!().init)); static assert(!__traits(compiles, T7408!().offsetof)); } /*************************************************************/ // 9552 class C9552 { int f() { return 10; } int f(int n) { return n * 2; } } void test9552() { auto c = new C9552; auto dg1 = &(__traits(getOverloads, c, "f")[0]); // DMD crashes assert(dg1() == 10); auto dg2 = &(__traits(getOverloads, c, "f")[1]); assert(dg2(10) == 20); } /*************************************************************/ void test9136() { int x; struct S1 { void f() { x++; } } struct U1 { void f() { x++; } } static struct S2 { } static struct S3 { S1 s; } static struct U2 { } void f1() { x++; } static void f2() { } static assert(__traits(isNested, S1)); static assert(__traits(isNested, U1)); static assert(!__traits(isNested, S2)); static assert(!__traits(isNested, S3)); static assert(!__traits(isNested, U2)); static assert(!__traits(compiles, __traits(isNested, int) )); static assert(!__traits(compiles, __traits(isNested, f1, f2) )); static assert(__traits(isNested, f1)); static assert(!__traits(isNested, f2)); static class A { static class SC { } class NC { } } static assert(!__traits(isNested, A)); static assert(!__traits(isNested, A.SC)); static assert(__traits(isNested, A.NC)); } /********************************************************/ // 9939 struct Test9939 { int f; enum /*Anonymous enum*/ { A, B } enum NamedEnum { C, D } } static assert([__traits(allMembers, Test9939)] == ["f", "A", "B", "NamedEnum"]); /********************************************************/ // 10043 void test10043() { struct X {} X d1; static assert(!__traits(compiles, d1.structuralCast!Refleshable)); } /********************************************************/ // 10096 struct S10096X { string str; invariant() {} invariant() {} unittest {} this(int) {} this(this) {} ~this() {} } static assert( [__traits(allMembers, S10096X)] == ["str", "__ctor", "__postblit", "__dtor", "__xdtor", "__xpostblit", "opAssign"]); // -------- string foo10096(alias var, T = typeof(var))() { foreach (idx, member; __traits(allMembers, T)) { auto x = var.tupleof[idx]; } return ""; } string foo10096(T)(T var) { return ""; } struct S10096 { int i; string s; } void test10096() { S10096 s = S10096(1, ""); auto x = foo10096!s; } /********************************************************/ unittest { } struct GetUnitTests { unittest { } } void test_getUnitTests () { // Always returns empty tuple if the -unittest flag isn't used static assert(__traits(getUnitTests, mixin(__MODULE__)).length == 0); static assert(__traits(getUnitTests, GetUnitTests).length == 0); } /********************************************************/ void test_getFunctionAttributes() { alias tuple(T...) = T; struct S { int noF() { return 0; } int constF() const { return 0; } int immutableF() immutable { return 0; } int inoutF() inout { return 0; } int sharedF() shared { return 0; } int x; ref int refF() { return x; } int propertyF() @property { return 0; } int nothrowF() nothrow { return 0; } int nogcF() @nogc { return 0; } int systemF() @system { return 0; } int trustedF() @trusted { return 0; } int safeF() @safe { return 0; } int pureF() pure { return 0; } } static assert(__traits(getFunctionAttributes, S.noF) == tuple!("@system")); static assert(__traits(getFunctionAttributes, typeof(S.noF)) == tuple!("@system")); static assert(__traits(getFunctionAttributes, S.constF) == tuple!("const", "@system")); static assert(__traits(getFunctionAttributes, typeof(S.constF)) == tuple!("const", "@system")); static assert(__traits(getFunctionAttributes, S.immutableF) == tuple!("immutable", "@system")); static assert(__traits(getFunctionAttributes, typeof(S.immutableF)) == tuple!("immutable", "@system")); static assert(__traits(getFunctionAttributes, S.inoutF) == tuple!("inout", "@system")); static assert(__traits(getFunctionAttributes, typeof(S.inoutF)) == tuple!("inout", "@system")); static assert(__traits(getFunctionAttributes, S.sharedF) == tuple!("shared", "@system")); static assert(__traits(getFunctionAttributes, typeof(S.sharedF)) == tuple!("shared", "@system")); static assert(__traits(getFunctionAttributes, S.refF) == tuple!("ref", "@system")); static assert(__traits(getFunctionAttributes, typeof(S.refF)) == tuple!("ref", "@system")); static assert(__traits(getFunctionAttributes, S.propertyF) == tuple!("@property", "@system")); static assert(__traits(getFunctionAttributes, typeof(&S.propertyF)) == tuple!("@property", "@system")); static assert(__traits(getFunctionAttributes, S.nothrowF) == tuple!("nothrow", "@system")); static assert(__traits(getFunctionAttributes, typeof(S.nothrowF)) == tuple!("nothrow", "@system")); static assert(__traits(getFunctionAttributes, S.nogcF) == tuple!("@nogc", "@system")); static assert(__traits(getFunctionAttributes, typeof(S.nogcF)) == tuple!("@nogc", "@system")); static assert(__traits(getFunctionAttributes, S.systemF) == tuple!("@system")); static assert(__traits(getFunctionAttributes, typeof(S.systemF)) == tuple!("@system")); static assert(__traits(getFunctionAttributes, S.trustedF) == tuple!("@trusted")); static assert(__traits(getFunctionAttributes, typeof(S.trustedF)) == tuple!("@trusted")); static assert(__traits(getFunctionAttributes, S.safeF) == tuple!("@safe")); static assert(__traits(getFunctionAttributes, typeof(S.safeF)) == tuple!("@safe")); static assert(__traits(getFunctionAttributes, S.pureF) == tuple!("pure", "@system")); static assert(__traits(getFunctionAttributes, typeof(S.pureF)) == tuple!("pure", "@system")); int pure_nothrow() nothrow pure { return 0; } static ref int static_ref_property() @property { return *(new int); } ref int ref_property() @property { return *(new int); } void safe_nothrow() @safe nothrow { } static assert(__traits(getFunctionAttributes, pure_nothrow) == tuple!("pure", "nothrow", "@system")); static assert(__traits(getFunctionAttributes, typeof(pure_nothrow)) == tuple!("pure", "nothrow", "@system")); static assert(__traits(getFunctionAttributes, static_ref_property) == tuple!("@property", "ref", "@system")); static assert(__traits(getFunctionAttributes, typeof(&static_ref_property)) == tuple!("@property", "ref", "@system")); static assert(__traits(getFunctionAttributes, ref_property) == tuple!("@property", "ref", "@system")); static assert(__traits(getFunctionAttributes, typeof(&ref_property)) == tuple!("@property", "ref", "@system")); static assert(__traits(getFunctionAttributes, safe_nothrow) == tuple!("nothrow", "@safe")); static assert(__traits(getFunctionAttributes, typeof(safe_nothrow)) == tuple!("nothrow", "@safe")); struct S2 { int pure_const() const pure { return 0; } int pure_sharedconst() const shared pure { return 0; } } static assert(__traits(getFunctionAttributes, S2.pure_const) == tuple!("const", "pure", "@system")); static assert(__traits(getFunctionAttributes, typeof(S2.pure_const)) == tuple!("const", "pure", "@system")); static assert(__traits(getFunctionAttributes, S2.pure_sharedconst) == tuple!("const", "shared", "pure", "@system")); static assert(__traits(getFunctionAttributes, typeof(S2.pure_sharedconst)) == tuple!("const", "shared", "pure", "@system")); static assert(__traits(getFunctionAttributes, (int a) { }) == tuple!("pure", "nothrow", "@nogc", "@safe")); static assert(__traits(getFunctionAttributes, typeof((int a) { })) == tuple!("pure", "nothrow", "@nogc", "@safe")); auto safeDel = delegate() @safe { }; static assert(__traits(getFunctionAttributes, safeDel) == tuple!("pure", "nothrow", "@nogc", "@safe")); static assert(__traits(getFunctionAttributes, typeof(safeDel)) == tuple!("pure", "nothrow", "@nogc", "@safe")); auto trustedDel = delegate() @trusted { }; static assert(__traits(getFunctionAttributes, trustedDel) == tuple!("pure", "nothrow", "@nogc", "@trusted")); static assert(__traits(getFunctionAttributes, typeof(trustedDel)) == tuple!("pure", "nothrow", "@nogc", "@trusted")); auto systemDel = delegate() @system { }; static assert(__traits(getFunctionAttributes, systemDel) == tuple!("pure", "nothrow", "@nogc", "@system")); static assert(__traits(getFunctionAttributes, typeof(systemDel)) == tuple!("pure", "nothrow", "@nogc", "@system")); } /********************************************************/ class TestIsOverrideFunctionBase { void bar () {} } class TestIsOverrideFunctionPass : TestIsOverrideFunctionBase { override void bar () {} } void test_isOverrideFunction () { assert(__traits(isOverrideFunction, TestIsOverrideFunctionPass.bar) == true); assert(__traits(isOverrideFunction, TestIsOverrideFunctionBase.bar) == false); } /********************************************************/ // 11711 - Add __traits(getAliasThis) alias TypeTuple(T...) = T; void test11711() { struct S1 { string var; alias var this; } static assert(__traits(getAliasThis, S1) == TypeTuple!("var")); static assert(is(typeof(__traits(getMember, S1.init, __traits(getAliasThis, S1)[0])) == string)); struct S2 { TypeTuple!(int, string) var; alias var this; } static assert(__traits(getAliasThis, S2) == TypeTuple!("var")); static assert(is(typeof(__traits(getMember, S2.init, __traits(getAliasThis, S2)[0])) == TypeTuple!(int, string))); } /********************************************************/ // Issue 12278 class Foo12278 { InPlace12278!Bar12278 inside; } class Bar12278 { } struct InPlace12278(T) { static assert(__traits(classInstanceSize, T) != 0); } /********************************************************/ // 12571 mixin template getScopeName12571() { enum string scopeName = __traits(identifier, __traits(parent, scopeName)); } void test12571() { mixin getScopeName12571; static assert(scopeName == "test12571"); } /********************************************************/ // 12237 auto f12237(T)(T a) { static if (is(typeof(a) == int)) return f12237(""); else return 10; } void test12237() { assert(f12237(1) == 10); assert((a){ static if (is(typeof(a) == int)) { int x; return __traits(parent, x)(""); } else return 10; }(1) == 10); } /********************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test7123(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test1369(); test7608(); test7858(); test9091(); test5978(); test7408(); test9552(); test9136(); test10096(); test_getUnitTests(); test_getFunctionAttributes(); test_isOverrideFunction(); test12237(); writeln("Success"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/bug5.d0000664000175000017500000000041112776215022021207 0ustar kaikai// REQUIRED_ARGS: -w class F { } int test1() { scope F f = new F(); // comment out and warning goes away return 0; } int test2() { // no return at end of function try { return 0; } finally { } } void main() { test1(); test2(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ctorpowtests.d0000664000175000017500000001251012776215022023130 0ustar kaikai// PERMUTE_ARGS: version (D_InlineAsm_X86) version = DMD_InlineAsm; else version (D_InlineAsm_X86_64) version = DMD_InlineAsm; else { version = LDC_InlineAsm; import ldc.llvmasm; } int magicVariable() { if (__ctfe) return 3; version (DMD_InlineAsm) asm { nop; } else version (LDC_InlineAsm) __asm("", ""); else static assert(0, "Unsupported platform"); return 2; } static assert(magicVariable()==3); void main() { assert(!__ctfe); assert(magicVariable()==2); } // bug 991 -- invalid. // bug 3500 -- is this related to 2127? // Tests for ^^ // TODO: These tests should not require import std.math. import std.math; // Test float ^^ int static assert( 27.0 ^^ 5 == 27.0 * 27.0 * 27.0 * 27.0 * 27.0); static assert( 2.0 ^^ 3 == 8.0); static assert( 2.0 ^^ 4 == 16.0); static assert( 2 ^^ 4 == 16); // Check the typing rules. static assert( is (typeof(2.0^^7) == double)); static assert( is (typeof(7^^3) == int)); static assert( is (typeof(7L^^3) == long)); static assert( is (typeof(7^^3L) == long)); enum short POW_SHORT_1 = 3; enum short POW_SHORT_3 = 7; static assert( is (typeof(POW_SHORT_1 * POW_SHORT_1) == typeof(POW_SHORT_1*POW_SHORT_1))); static assert( is (typeof(7.0^^3) == double)); static assert( is (typeof(7.0L^^3) == real)); static assert( is (typeof(7.0f^^3) == float)); static assert( is (typeof(POW_SHORT_1^^3.1) == double)); static assert( is (typeof(POW_SHORT_1^^3.1f) == float)); static assert( is (typeof(2.1f ^^ POW_SHORT_1) == float)); static assert( is (typeof(7.0f^^3.1) == double)); static assert( is (typeof(7.0^^3.1f) == double)); static assert( is (typeof(7.0f^^3.1f) == float)); static assert( is (typeof(7.0f^^3.1L) == real)); static assert( is (typeof(7.0L^^3.1f) == real)); // Check typing for special cases static assert( is (typeof(7.0f^^2) == float)); static assert( is (typeof(7.0f^^2.0) == double)); static assert( is (typeof(7.0f^^8.0) == double)); static assert( is (typeof(1^^0.5f) == float)); static assert( is (typeof(7^^0.5f) == float)); static assert( is (typeof(3L^^0.5) == double)); static assert( is (typeof(123^^17.0f) == float)); static assert(POW_SHORT_1 ^^ 2 == 9); static assert(4.0 ^^ POW_SHORT_1 == 4.0*4.0*4.0); static assert(4.0 ^^ 7.0 == 4.0*4.0*4.0*4.0*4.0*4.0*4.0); // ^^ has higher precedence than multiply static assert( 2 * 2 ^^ 3 + 1 == 17); static assert( 2 ^^ 3 * 2 + 1 == 17); // ^^ has higher precedence than negate static assert( -2 ^^ 3 * 2 - 1 == -17); // ^^ is right associative static assert( 2 ^^ 3 ^^ 2 == 2 ^^ 9); static assert( 2.0 ^^ -3 ^^ 2 == 2.0 ^^ -9); // 1 ^^ n is always 1, even if n is negative static assert( 1 ^^ -5 == 1); // -1 ^^ n gets transformed into n & 1 ? -1 : 1 // even if n is negative static assert( (-1) ^^ -5 == -1); static assert( (-1) ^^ -4 == 1); static assert( (-1) ^^ 0 == 1); // n ^^ 0 is always 1 static assert( (-5) ^^ 0 == 1); // n ^^ 1 is always n static assert( 6.0 ^^ 1 == 6.0); // n ^^ -1.0 gets transformed into 1.0 / n, even if n is negative static assert( (-4) ^^ -1.0 == 1.0 / -4); static assert( 9 ^^ -1.0 == 1.0 / 9); // Other integers raised to negative powers create an error static assert( !is(typeof(2 ^^ -5))); static assert( !is(typeof((-2) ^^ -4))); // Bug 3535 struct StructWithCtor { this(int _n) { n = _n; x = 5; } this(int _n, float _x) { n = _n; x = _x; } int n; float x; } int containsAsm() { version (DMD_InlineAsm) asm { nop; } else version (LDC_InlineAsm) __asm("", ""); else static assert(0, "Unsupported inline asm"); return 0; } enum A = StructWithCtor(1); enum B = StructWithCtor(7, 2.3); static assert(A.n == 1); static assert(A.x == 5.0); static assert(B.n == 7); static assert(B.x == 2.3); int bazra(int x) { StructWithCtor p = StructWithCtor(4); return p.n ^^ 3; } static assert(bazra(14)==64); void moreCommaTests() { auto k = (containsAsm(), containsAsm()); for (int i=0; i< k^^2; i+=StructWithCtor(1).n) {} } // Test copy constructors struct CopyTest { double x; this(double a) { x = a * 10.0;} this(this) { x+=2.0;} } struct CopyTest2 { int x; int x1; int x2; int x3; this(int a) { x = a * 2; x1 = 3;} this(this) { x1+=17;} } const CopyTest z = CopyTest(5.3); /+ // TODO: This is not yet supported. But it // generates an error message instead of wrong-code. const CopyTest w = z; static assert(z.x==55.0); +/ int copytest1() { CopyTest z = CopyTest(3.4); CopyTest w = z; assert(w.x == 36.0); CopyTest2 q = CopyTest2(7); CopyTest2 q2 = q; CopyTest2 q3 = q2; assert(q3.x1 == 37); return 123; } static assert(copytest1()==123); // This must not cause a segfault alias int FILTH; struct Filth { struct Impl { FILTH * handle = null; this(FILTH* h, uint r, string n) { handle = h; } } Impl * p; this(string name, in char[] stdioOpenmode = "rb") { } ~this() { if (!p) return; } this(this) { if (!p) return; } } struct InputByChar { private Filth _f; this(Filth f) { _f = f; } } static int nastyForCtfe=4; // Can't use a global variable static assert(!is(typeof( (){ static assert(0!=nastyForCtfe^^2); }))); int anotherPowTest() { double x = 5.0; return x^^4 > 2.0 ? 3: 2; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link11127.d0000664000175000017500000000007712776215022021706 0ustar kaikaiimport imports.link11127a; void main() { cycle([1, 2]); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link6574.d0000664000175000017500000000166112776215022021640 0ustar kaikai// PERMUTE_ARGS: module link6574; enum Method { A, B, } int foo(Method method = Method.A)() { static assert(foo.mangleof == "_D8link657428__T3fooVE8link65746Methodi0Z3fooFZi"); return 10 * foo!method(); } int foo(Method method : Method.A)() { static assert(foo.mangleof == "_D8link657429__T3fooHVE8link65746Methodi0Z3fooFZi"); return 2; } int foo(Method method : Method.B)() { static assert(0); return 3; } int bar(Method method = Method.B)() { static assert(bar.mangleof == "_D8link657428__T3barVE8link65746Methodi1Z3barFZi"); return 10 * bar!method(); } int bar(Method method : Method.A)() { static assert(0); return 2; } int bar(Method method : Method.B)() { static assert(bar.mangleof == "_D8link657429__T3barHVE8link65746Methodi1Z3barFZi"); return 3; } void main() { assert(foo!() == 10 * 2); assert(foo() == 10 * 2); assert(bar!() == 10 * 3); assert(bar() == 10 * 3); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/variadic.d0000664000175000017500000004575612776215022022154 0ustar kaikaialias TypeTuple(T...) = T; class A { } class B : A { } class C : B { } /***************************************/ template Foo(int a, int b, int c) { const int Foo = 1; } template Foo(A...) { const int Foo = 2; } void test1() { int y = Foo!(1,2,3); assert(y == 1); y = Foo!(1,2); assert(y == 2); y = Foo!(1,2,3,4); assert(y == 2); } /***************************************/ template Foo2(int a, int b, int c) { const int Foo2 = 1; } template Foo2(int a, int b, int c, A...) { const int Foo2 = 2; } void test2() { int y = Foo2!(1,2,3); assert(y == 1); y = Foo2!(1,2,3,4); assert(y == 2); } /***************************************/ void bar3(int x, int y) { assert(x == 2); assert(y == 3); } template Foo3(T, A...) { int Foo3(T t, A a) { assert(A.length == 2); assert(a.length == 2); bar3(a); assert([a] == [2, 3]); assert([cast(double)a] == [2.0, 3.0]); assert(a[0] == 2); assert(a[1] == 3); assert(a[$ - 2] == 2); assert(a[$ - 1] == 3); static if (1 || a[6]) assert(1); assert([a[]] == [2, 3]); assert([a[0 .. $]] == [2, 3]); assert([a[0 .. $ - 1]] == [2]); return 3; } } void test3() { int y = Foo3(1,2,3); assert(y == 3); } /***************************************/ void foo4(A...)() { int[] ai; int[] aa; aa = null; foreach (a; A) { aa ~= a; } assert(aa == [7,4,9]); aa = null; foreach (int a; A) { aa ~= a; } assert(aa == [7,4,9]); ai = null; aa = null; foreach (int i, a; A) { ai ~= i; aa ~= a; } assert(ai == [0,1,2]); assert(aa == [7,4,9]); ai = null; aa = null; foreach_reverse (uint i, a; A) { ai ~= i; aa ~= a; } assert(ai == [2,1,0]); assert(aa == [9,4,7]); ai = null; aa = null; foreach_reverse (i, a; A) { ai ~= i; aa ~= a; } assert(ai == [2,1,0]); assert(aa == [9,4,7]); ai = null; aa = null; foreach (int i, a; A) { ai ~= i; aa ~= a; if (i == 1) break; continue; } assert(ai == [0,1]); assert(aa == [7,4]); } void test4() { foo4!(7,4,9)(); } /***************************************/ int a12(TypeTuple!(int, int) t) { return t[0] + t[1]; } int b12(TypeTuple!(TypeTuple!(int), TypeTuple!(int)) t) { return t[0] + t[1]; } int c12(TypeTuple!(TypeTuple!(int), TypeTuple!(TypeTuple!(), int), TypeTuple!()) t) { return t[0] + t[1]; } void test12() { assert(a12(1, 2) == 3); assert(b12(1, 2) == 3); assert(c12(1, 2) == 3); } /***************************************/ int plus13(TypeTuple!(int, long, float)[0 .. 2] t) { typeof(t)[0] e; assert(typeid(typeof(e)) == typeid(int)); typeof(t)[1] f; assert(typeid(typeof(f)) == typeid(long)); return t[0] + cast(int)t[1]; } void test13() { assert(plus13(5, 6) == 11); } /***************************************/ int plus14(TypeTuple!(int, long, float)[0 .. $ - 1] t) { typeof(t)[$ - 2] e; assert(typeid(typeof(e)) == typeid(int)); typeof(t)[1] f; assert(typeid(typeof(f)) == typeid(long)); return t[0] + cast(int)t[1]; } void test14() { assert(plus14(5, 6) == 11); } /***************************************/ void returnAndArgs(T, U...) (T delegate(U) dg) { static if (U.length == 0) assert(dg() == 0); else static if (U.length == 1) assert(dg(false) == 1); else assert(dg(false, 63L) == 2); } void test24() { returnAndArgs(delegate int(){ return 0; }); returnAndArgs(delegate int(bool b){ return 1; }); returnAndArgs(delegate int(bool b, long c){ return 2; }); } /***************************************/ void test28() { alias TypeTuple!(int, long, double) TL; foreach (int i, T; TL) { switch (i) { case 0: assert(is(T == int)); break; case 1: assert(is(T == long)); break; case 2: assert(is(T == double)); break; default:assert(0); } } } /***************************************/ template g32(alias B) { int g32 = 2; } int f32(A...)(A a) { return g32!(a); } void test32() { assert(f32(4) == 2); } /***************************************/ struct S34 { int x; long y; double z; } void foo34(int x, long y, double z) { assert(x == 3); assert(y == 8); assert(z == 6.8); } void test34() { S34 s; s.x = 3; s.y = 8; s.z = 6.8; foo34(s.tupleof); } /***************************************/ alias TypeTuple!(int, long, double) TL35; struct S35 { TL35 tl; } void foo35(int x, long y, double z) { assert(x == 3); assert(y == 8); assert(z == 6.8); } void test35() { S35 s; s.tl[0] = 3; s.tl[1] = 8; s.tl[2] = 6.8; foo35(s.tupleof); foo35(s.tl); } /***************************************/ alias TypeTuple!(int, long, double) TL36; class C36 { TL36 tl; } void foo36(int x, long y, double z) { assert(x == 3); assert(y == 8); assert(z == 6.8); } void test36() { C36 s = new C36; s.tl[0] = 3; s.tl[1] = 8; s.tl[2] = 6.8; foo36(s.tupleof); foo36(s.tl); } /***************************************/ alias TypeTuple!(int, long, double) TL37; class C37 { TL37 tl; } void foo37(int x, long y, double z) { assert(x == 3); assert(y == 8); assert(z == 6.8); } void test37() { C37 s = new C37; s.tl[0] = 3; s.tl[1] = 8; s.tl[2] = 6.8; foo37(s.tupleof); TL37 x; assert(x[0] == 0); x[0] = 3; assert(x[0] == 3); assert(x[1] == 0); x[1] = 8; x[2] = 6.8; foo37(x); } /***************************************/ interface I38A { } interface I38B { } alias TypeTuple!(I38A, I38B) IL38; class C38 : IL38 { } void test38() { auto c = new C38; } /***************************************/ void test39() { static const string a = "\x01"; static const char b = a[0]; static const string c = "test"; static assert(c[a[0]] == 'e'); alias TypeTuple!(ulong,uint,ushort,ubyte) tuple; static assert(is(tuple[1] == uint)); static assert(is(tuple[a[0]] == uint)); } /***************************************/ struct Foo45 { static TypeTuple!(int) selements1; TypeTuple!(int) elements1; static TypeTuple!() selements0; TypeTuple!() elements0; } void test45() { Foo45 foo; static assert(Foo45.selements1.length == 1); static assert(Foo45.elements1.length == 1); static assert(Foo45.selements0.length == 0); static assert(Foo45.elements0.length == 0); static assert(foo.selements1.length == 1); static assert(foo.elements1.length == 1); static assert(foo.selements0.length == 0); static assert(foo.elements0.length == 0); } /***************************************/ template Tuple46(E ...) { alias E Tuple46; } alias Tuple46!(float, float, 3) TP46; alias TP46[1..$] TQ46; void test46() { TQ46[0] f = TQ46[1]; assert(is(typeof(f) == float)); assert(f == 3); } /***************************************/ template Foo47(T, Args...) { void bar(Args args, T t) { } } void test47() { alias Foo47!(int) aFoo; } /***************************************/ template Tuple48(E...) { alias E Tuple48; } void VarArg48(T...)(T args) { } void test48() { VarArg48( ); VarArg48( Tuple48!(1,2,3) ); VarArg48( Tuple48!() ); } /***************************************/ alias TypeTuple!(int, long) TX49; void foo49(TX49 t) { TX49 s; s = t; assert(s[0] == 1); assert(s[1] == 2); } void test49() { foo49(1, 2); } /***************************************/ void foo51(U...)(int t, U u) { assert(t == 1); assert(u[0] == 2); assert(u[1] == 3); } void bar51(U...)(U u, int t) { assert(u[0] == 1); assert(u[1] == 2); assert(t == 3); } void abc51(U...)(int s, U u, int t) { assert(s == 1); assert(u[0] == 2); assert(u[1] == 3); assert(t == 4); } void test51() { foo51(1, 2, 3); bar51(1, 2, 3); bar51!(int, int)(1, 2, 3); abc51(1,2,3,4); } /***************************************/ string to55(U, V)(V s) { return "he"; } private S wyda(S, T...)(T args) { S result; foreach (i, arg; args) { result ~= to55!(S)(args[i]); } return result; } string giba(U...)(U args) { return wyda!(string, U)(args); } void test55() { assert(giba(42, ' ', 1.5, ": xyz") == "hehehehe"); } /***************************************/ private template implicitlyConverts(U, V) { enum bool implicitlyConverts = V.sizeof >= U.sizeof && is(typeof({U s; V t = s;}())); } T to56(T, S)(S s) if (!implicitlyConverts!(S, T) /*&& isSomeString!(T) && isSomeString!(S)*/) { return T.init; } void test56() { auto x = to56!(int)("4"); assert(x == 0); assert(!implicitlyConverts!(const(char)[], string)); assert(implicitlyConverts!(string, const(char)[])); } /***************************************/ struct A57(B...) {} void test57() { alias A57!(int, float) X; static if (!is(X Y == A57!(Z), Z...)) { static assert(false); } } /***************************************/ struct A58(B...) {} void test58() { alias A58!(int, float) X; static if (!is(X Y == A58!(Z), Z...)) { static assert(false); } } /***************************************/ struct Tuple59(T...) { T field; } template reduce(fun...) { alias Reduce!(fun).reduce reduce; } template Reduce(fun...) { Tuple59!(double, double) reduce(Range)(Range r) { typeof(Tuple59!(double,double).field)[0] y; typeof(typeof(return).field)[0] x; Tuple59!(double, double) s; return s; } } void test59() { double[] a = [ 3.0, 4, 7, 11, 3, 2, 5 ]; static double sum(double a, double b) {return a + b;} auto r = reduce!((a, b) { return a + b; }, (a, b) { return a + b; })(a); } /***************************************/ template tuple60(T...) { alias T tuple60; } template Foo60(S : void delegate(tuple60!(int))) {} template Foo60(S : void delegate(tuple60!(int, int))) {} alias Foo60!(void delegate(int)) Bar60; void test60() { } /***************************************/ template TypeTuple61(TList...){ alias TList TypeTuple61; } template List61(lst...) { alias lst list; } alias TypeTuple61!(List61!(void)) A61; alias TypeTuple61!(A61[0].list) B61; void test61() { } /***************************************/ template Tuple63(T...){ alias T Tuple63; } // Bugzilla 3336 static assert(!is(int[ Tuple63!(int, int) ])); void test63() { } /***************************************/ template Tuple1411(T ...) { alias T Tuple1411; } void test1411() { int delegate(ref Tuple1411!(int, char[], real)) dg; // (*) int f(ref int a, ref char[] b, ref real c) { return 77; } dg = &f; } /***************************************/ // Bugzilla 4444 void test4444() { alias TypeTuple!(1) index; auto arr = new int[4]; auto x = arr[index]; // error } /***************************************/ // 13864 struct Tuple13864(T...) { T expand; alias expand this; } auto tuple13864(T...)(T args) { return Tuple13864!T(args); } void test13864() { int[] x = [2,3,4]; auto y = x[tuple13864(0).expand]; assert(y == 2); } /***************************************/ // 4884 struct A4884(T...) { void foo(T) {} void bar(bool, T) {} } void test4884() { auto a1 = A4884!(int)(); auto a2 = A4884!(int, long)(); } /***************************************/ // 4920 struct Test4920(parameters_...) { alias parameters_ parameters; } void test4920() { Test4920!(10, 20, 30) test; static assert(typeof(test).parameters[1] == 20); // okay static assert( test .parameters[1] == 20); // (7) } /***************************************/ // 4940 template Tuple4940(T...) { alias T Tuple4940; } struct S4940 { Tuple4940!(int, int) x; this(int) { } } void test4940() { auto w = S4940(0).x; } //---- struct S4940add { string s; long x; } ref S4940add get4940add(ref S4940add s){ return s; } void test4940add() { S4940add s; get4940add(s).tupleof[1] = 20; assert(s.x == 20); } /***************************************/ // 6530 struct S6530 { int a, b, c; } struct HasPostblit6530 { this(this) {} // Bug goes away without this. } auto toRandomAccessTuple6530(T...)(T input, HasPostblit6530 hasPostblit) { return S6530(1, 2, 3); } void doStuff6530(T...)(T args) { HasPostblit6530 hasPostblit; // Bug goes away without the .tupleof. auto foo = toRandomAccessTuple6530(args, hasPostblit).tupleof; } void test6530() { doStuff6530(1, 2, 3); } /***************************************/ import core.stdc.stdarg; extern(C) void func9495(int a, string format, ...) { va_list ap; va_start(ap, format); auto a1 = va_arg!int(ap); auto a2 = va_arg!int(ap); auto a3 = va_arg!int(ap); assert(a1 == 0x11111111); assert(a2 == 0x22222222); assert(a3 == 0x33333333); va_end(ap); } void test9495() { func9495(0, "", 0x11111111, 0x22222222, 0x33333333); } /***************************************/ void copya(int a, string format, ...) { va_list ap; va_start(ap, format); va_list ap2; va_copy(ap2, ap); auto a1 = va_arg!int(ap); auto a2 = va_arg!int(ap); auto a3 = va_arg!int(ap); assert(a1 == 0x11111111); assert(a2 == 0x22222222); assert(a3 == 0x33333333); auto b1 = va_arg!int(ap2); auto b2 = va_arg!int(ap2); auto b3 = va_arg!int(ap2); assert(b1 == 0x11111111); assert(b2 == 0x22222222); assert(b3 == 0x33333333); va_end(ap); va_end(ap2); } void testCopy() { copya(0, "", 0x11111111, 0x22222222, 0x33333333); } /***************************************/ // 6700 template bug6700(TList ...) { const int bug6700 = 2; } TypeTuple!(int, long) TT6700; static assert(bug6700!( (TT6700[1..$]) )==2); /***************************************/ // 6966 template X6966(T...) { alias const(T[0]) X6966; } static assert(is(X6966!(int) == const(int))); static assert(is(X6966!(int, 0) == const(int))); /***************************************/ // 7233 struct Foo7233 { int x, y; } Foo7233[] front7233(Foo7233[][] a) { return a[0]; } class Bar7233 { int x, y; } Bar7233[] front7233(Bar7233[][] a) { return a[0]; } void test7233() { Foo7233[][] b1 = [[Foo7233()]]; auto xy1 = b1.front7233[0].tupleof; Bar7233[][] b2 = [[new Bar7233()]]; auto xy2 = b2.front7233[0].tupleof; } /***************************************/ // 7263 template TypeTuple7263(T...){ alias T TypeTuple7263; } struct tuple7263 { TypeTuple7263!(int, int) field; alias field this; } auto front7263(T)(ref T arr){ return arr[0]; } void test7263() { auto bars = [tuple7263(0, 0), tuple7263(1, 1)]; auto spam1 = bars.front7263[1]; auto spam2 = bars.front7263[1..2]; } /***************************************/ // 8244 TypeTuple!(int,int)[] x8244; static assert(is(typeof(x8244) == TypeTuple!(int, int))); /***************************************/ // 9017 template X9017(Args...) { static if(__traits(compiles, { enum e = Args; })) enum e = Args; } alias X9017!0 x9017; static assert(x9017.e[0] == 0); void test9017() { enum tup1 = TypeTuple!(11, 22); enum tup2 = TypeTuple!("one", "two"); static assert(tup1 == TypeTuple!(11, 22)); static assert(tup2 == TypeTuple!("one", "two")); static assert(tup1[0] == 11 && tup1[1] == 22); static assert(tup2[0] == "one" && tup2[1] == "two"); shared const tup3 = TypeTuple!(10, 3.14); immutable tup4 = TypeTuple!("a", [1,2]); static assert(is(typeof(tup3[0]) == shared const int)); static assert(is(typeof(tup3[1]) == shared const double)); static assert(is(typeof(tup4[0]) == immutable string)); static assert(is(typeof(tup4[1]) == immutable int[])); } /***************************************/ // 10279 void foo10279(int[][] strs...) @trusted { } void bar10279() @safe { foo10279(); } /***************************************/ // 13508 struct S13508 { this(T)(T[] t...) {} } template make13508(T) { T make13508(Args...)(Args args) { return T(args); } } void test13508() @safe @nogc { S13508 s = make13508!S13508(5); } /***************************************/ // 14395 int v2u14395(uint[1] ar...) { return ar[0]; } void print14395(int size = v2u14395(7)) { assert(size == 7); } void test14395() { print14395(); } /***************************************/ // 10414 void foo10414(void delegate()[] ...) { } void bar10414() { } void test10414() { foo10414 ( { bar10414(); }, { bar10414(); }, ); } /***************************************/ import core.stdc.stdarg; struct S14179 { const(char)* filename; uint linnum; uint charnum; } extern(C++) const(char)* func14179(S14179 x, const(char)* string, ...) { return string; } void test14179() { const(char)* s = "hello"; assert(func14179(S14179(), s) == s); } /***************************************/ // 10722 struct S10722 { int x; } template GetSomething10722(S...) { alias GetSomething = int; } void test10722() { alias X10722 = GetSomething10722!(S10722.tupleof[0]); } /***************************************/ void testx15417(ulong c1, ...) { check(c1, _argptr, _arguments); } class C15417 { private void method () { void test1 (ulong c1, ...) { check(c1, _argptr, _arguments); } void test2 (ulong c1, ...) { va_list ap; version (LDC) va_start(ap, c1); else version (Win64) va_start(ap, c1); else version (X86_64) va_start(ap, __va_argsave); else version (X86) va_start(ap, c1); check(c1, ap, _arguments); } testx15417(4242UL, char.init); test1(4242UL, char.init); test2(4242UL, char.init); } } void check (ulong c1, va_list arglist, TypeInfo[] ti) { assert(ti.length == 1); assert(ti[0].toString() == "char"); assert(char.init == va_arg!(char)(arglist)); } void test15417() { auto c = new C15417; c.method; } /***************************************/ int main() { test1(); test2(); test3(); test4(); test12(); test13(); test14(); test24(); test28(); test32(); test34(); test35(); test36(); test37(); test38(); test39(); test45(); test46(); test47(); test48(); test49(); test51(); test55(); test56(); test57(); test58(); test59(); test60(); test61(); test63(); test1411(); test4444(); test13864(); test4884(); test4920(); test4940(); test4940add(); test6530(); test7233(); test7263(); test9017(); test14395(); test10414(); test9495(); testCopy(); test14179(); test15417(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testaa3.d0000664000175000017500000002110412776215022021713 0ustar kaikai /***************************************************/ /* Test all aa properties (length, values, keys, opApply(Key, Value), opApply_r(Value), * dup, byKey, byValue, rehash, opIndex, opIndexAssign, opIn_r) * * With all aas: literal, variable, ref parameter, rvalue */ int testLiteral() { assert([5 : 4].length == 1); assert([5 : 4].values == [4]); assert([5 : 4].keys == [5]); foreach (k, v; [5 : 4]) assert(k == 5 && v == 4); foreach (v; [5 : 4]) assert(v == 4); assert([5 : 4].dup == [5 : 4]); assert([5 : 4].dup); if (!__ctfe) foreach (k; [5 : 4].byKey) assert(k == 5); if (!__ctfe) foreach (v; [5 : 4].byValue) assert(v == 4); assert([5 : 4].rehash == [5 : 4]); assert([5 : 4][5] == 4); assert([5 : 4].get(5, 2) == 4); assert([5 : 4].get(1, 2) == 2); //assert(([5 : 4][3] = 7) == 7); assert(*(5 in [5 : 4]) == 4); return 1; } int testVar() { auto aa = [5 : 4]; assert(aa.length == 1); assert(aa.values == [4]); assert(aa.keys == [5]); foreach (k, v; aa) assert(k == 5 && v == 4); foreach (v; aa) assert(v == 4); assert(aa.dup == aa); assert(aa.dup); { auto bb = aa.dup(); assert(bb == aa); //assert(aa !is bb); // issue in ctfeIdentity assert(&aa[5] !is &bb[5]); bb[5] = 10; assert(aa[5] == 4); assert(bb[5] == 10); } if (!__ctfe) foreach (k; aa.byKey) assert(k == 5); if (!__ctfe) foreach (v; aa.byValue) assert(v == 4); assert(aa.rehash == aa); assert(aa[5] == 4); assert(aa.get(5, 2) == 4); assert(aa.get(1, 2) == 2); assert(*(5 in aa) == 4); assert((aa[3] = 7) == 7); return 1; } int testVarConst() { const aa = [5 : 4]; assert(aa.length == 1); assert(aa.values == [4]); assert(aa.keys == [5]); foreach (k, v; aa) assert(k == 5 && v == 4); foreach (v; aa) assert(v == 4); //assert(aa.dup == aa); assert(aa.dup); { auto bb = aa.dup(); //assert(bb == aa); //assert(aa !is bb); // issue in ctfeIdentity assert(&aa[5] !is &bb[5]); } if (!__ctfe) foreach (k; aa.byKey) assert(k == 5); if (!__ctfe) foreach (v; aa.byValue) assert(v == 4); //assert(aa.rehash == aa); assert(aa[5] == 4); assert(aa.get(5, 2) == 4); assert(aa.get(1, 2) == 2); assert(*(5 in aa) == 4); //assert((aa[3] = 7) == 7); return 1; } int testVarImmutable() { immutable aa = [5 : 4]; assert(aa.length == 1); assert(aa.values == [4]); assert(aa.keys == [5]); foreach (k, v; aa) assert(k == 5 && v == 4); foreach (v; aa) assert(v == 4); //assert(aa.dup == aa); assert(aa.dup); { auto bb = aa.dup(); //assert(bb == aa); //assert(aa !is bb); // issue in ctfeIdentity assert(&aa[5] !is &bb[5]); } if (!__ctfe) foreach (k; aa.byKey) assert(k == 5); if (!__ctfe) foreach (v; aa.byValue) assert(v == 4); // assert(aa.rehash == aa); assert(aa[5] == 4); assert(aa.get(5, 2) == 4); assert(aa.get(1, 2) == 2); assert(*(5 in aa) == 4); //assert((aa[3] = 7) == 7); return 1; } int testPointer() { auto x = [5 : 4]; auto aa = &x; assert(aa.length == 1); assert(aa.values == [4]); assert(aa.keys == [5]); // foreach (k, v; aa) // assert(k == 5 && v == 4); // foreach (v; aa) // assert(v == 4); assert(aa.dup == *aa); assert(aa.dup); { auto bb = aa.dup(); assert(bb == *aa); //assert(aa !is bb); // issue in ctfeIdentity assert(&(*aa)[5] !is &bb[5]); bb[5] = 10; assert((*aa)[5] == 4); assert(bb[5] == 10); } if (!__ctfe) foreach (k; aa.byKey) assert(k == 5); if (!__ctfe) foreach (v; aa.byValue) assert(v == 4); if (!__ctfe) assert(aa.rehash == *aa); assert((*aa)[5] == 4); assert(aa.get(5, 2) == 4); assert(aa.get(1, 2) == 2); // assert(*(5 in aa) == 4); if (!__ctfe) assert(((*aa)[3] = 7) == 7); return 1; } int testPointerConst() { const x = [5 : 4]; const aa = &x; assert(aa.length == 1); assert(aa.values == [4]); assert(aa.keys == [5]); // foreach (k, v; aa) // assert(k == 5 && v == 4); // foreach (v; aa) // assert(v == 4); // assert(aa.dup == *aa); assert(aa.dup); { auto bb = aa.dup(); //assert(bb == aa); //assert(aa !is bb); // issue in ctfeIdentity assert(&(*aa)[5] !is &bb[5]); } if (!__ctfe) foreach (k; aa.byKey) assert(k == 5); if (!__ctfe) foreach (v; aa.byValue) assert(v == 4); // assert(aa.rehash == aa); assert((*aa)[5] == 4); assert(aa.get(5, 2) == 4); assert(aa.get(1, 2) == 2); // assert(*(5 in aa) == 4); // assert(((*aa)[3] = 7) == 7); return 1; } int testPointerImmutable() { immutable x = [5 : 4]; auto aa = &x; assert(aa.length == 1); assert(aa.values == [4]); assert(aa.keys == [5]); // foreach (k, v; aa) // assert(k == 5 && v == 4); // foreach (v; aa) // assert(v == 4); // assert(aa.dup == *aa); assert(aa.dup); { auto bb = aa.dup(); //assert(bb == (*aa)); //assert(aa !is bb); // issue in ctfeIdentity assert(&(*aa)[5] !is &bb[5]); } if (!__ctfe) foreach (k; aa.byKey) assert(k == 5); if (!__ctfe) foreach (v; aa.byValue) assert(v == 4); // assert(aa.rehash == aa); assert((*aa)[5] == 4); assert(aa.get(5, 2) == 4); assert(aa.get(1, 2) == 2); // assert(*(5 in aa) == 4); // assert(((*aa)[3] = 7) == 7); return 1; } int testRef() { auto aa = [5 : 4]; return testRefx(aa); } int testRefx(ref int[int] aa) { assert(aa.length == 1); assert(aa.values == [4]); assert(aa.keys == [5]); foreach (k, v; aa) assert(k == 5 && v == 4); foreach (v; aa) assert(v == 4); assert(aa.dup == aa); assert(aa.dup); { auto bb = aa.dup(); assert(bb == aa); //assert(aa !is bb); // issue in ctfeIdentity assert(&aa[5] !is &bb[5]); bb[5] = 10; assert(aa[5] == 4); assert(bb[5] == 10); } if (!__ctfe) foreach (k; aa.byKey) assert(k == 5); if (!__ctfe) foreach (v; aa.byValue) assert(v == 4); assert(aa.rehash == aa); assert(aa[5] == 4); assert(aa.get(5, 2) == 4); assert(aa.get(1, 2) == 2); assert((aa[3] = 7) == 7); assert(*(5 in aa) == 4); return 1; } int testRet() { assert(testRetx().length == 1); assert(testRetx().values == [4]); assert(testRetx().keys == [5]); foreach (k, v; testRetx()) assert(k == 5 && v == 4); foreach (v; testRetx()) assert(v == 4); assert(testRetx().dup == testRetx()); assert(testRetx().dup); if (!__ctfe) foreach (k; testRetx().byKey) assert(k == 5); if (!__ctfe) foreach (v; testRetx().byValue) assert(v == 4); assert(testRetx().rehash == testRetx()); assert(testRetx()[5] == 4); assert(testRetx().get(5, 2) == 4); assert(testRetx().get(1, 2) == 2); //assert((testRetx()[3] = 7) == 7); assert(*(5 in testRetx()) == 4); return 1; } int[int] testRetx() { return [5 : 4]; } void aafunc(int[int] aa) {} /***************************************************/ // 12214 void test12214() pure nothrow { int[int] aa; auto n = aa.length; } /***************************************************/ // 12220 & 12221 void test12220() { short[short] hash; short k = hash.get(1, 2); assert(k == 2); enum Key : short { a = 10 } short a = hash.get(Key.a, Key.a); assert(a == 10); } /***************************************************/ // 12403 void test12403() { const(int)[int] m; assert(m.get(0, 1) == 1); } /***************************************************/ void main() { assert(testLiteral()); static assert(testLiteral()); assert(testVar()); static assert(testVar()); assert(testVarConst()); static assert(testVarConst()); assert(testVarImmutable()); static assert(testVarImmutable()); assert(testPointer()); static assert(testPointer()); assert(testPointerConst()); static assert(testPointerConst()); assert(testPointerImmutable()); static assert(testPointerImmutable()); assert(testRef()); static assert(testRef()); assert(testRet()); static assert(testRet()); test12220(); test12403(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/mod1.d0000664000175000017500000000025612776215022021214 0ustar kaikai// PERMUTE_ARGS: // EXTRA_SOURCES: imports/mod2.d // mod1.d import imports.mod2; string name() { return "EvilOne"; } int main(string[] args) { greet(); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/template1.d0000664000175000017500000007167712776215022022267 0ustar kaikai// REQUIRED_ARGS: module template1; import core.stdc.stdio : printf; import core.vararg; /******************************************/ template TFoo1(T,U) { int foo(T t, U u) { return 3; } } alias TFoo1!(int, char) Foo1; void test1() { int i = Foo1.foo(1, 2); assert(i == 3); } /******************************************/ template TFoo2(T,U) { T x = 4; U y; } alias TFoo2!(int, char) Foo2; void test2() { assert(Foo2.x + Foo2.y == 0x103); Foo2.x = 3; Foo2.y = 7; assert(Foo2.x + Foo2.y == 10); } /******************************************/ template TFoo3(T,U) { class Bar { T x = 4; U y; } } alias TFoo3!(int, char) Foo3; void test3() { Foo3.Bar b = new Foo3.Bar(); assert(b.x == 4); assert(b.y == 0xFF); } /******************************************/ template TFoo4(T,U) { T x; U y; } template TFoo4(T:T,U:T) { T a; U b; } template TFoo4(T:uint, U:uint) { T c; U d; } alias TFoo4!(int, char) Foo4x; void test4() { alias TFoo4!(int, char) Foo4; int* x = &Foo4.c; char* y = &Foo4.d; alias TFoo4!(uint, char**) Foo4_2; uint* x2 = &Foo4_2.x; char*** y2 = &Foo4_2.y; alias TFoo4!(int, int) Foo4_3; int* x3 = &Foo4_3.a; int* y3 = &Foo4_3.b; alias TFoo4!(uint, uint) Foo4_4; uint* x4 = &Foo4_4.c; uint* y4 = &Foo4_4.d; } /******************************************/ template TtoUx(T, U) { T toUx(U[] s) { uint v = 0; if (v != cast(T)v) return 3; return cast(T)v; } } alias TtoUx!(ubyte, char).toUx toUbyte; alias TtoUx!(ushort, char).toUx toUshort; void test5() { } /******************************************/ template TtoUx6(T, U) { T toUx(U[] s) { uint v = 0; if (v != cast(T)v) return 3; return cast(T)v; } } alias TtoUx6!(ubyte, char) t6; void test6() { } /******************************************/ template A7(T) { T id(T t) { return t; } } alias A7!(int) a; void test7() { printf("%d\r\n", a.id(3)); assert(a.id(3) == 3); } /******************************************/ template Swapper(T) { void Swap(ref T a, ref T b) { T temp = a; a = b; b = temp; } } void test8() { alias Swapper!(int) IntSwap; int a=1,b=2; IntSwap.Swap(a,b); printf("a=%d,b=%d\n",a,b); // prints 2,1 assert(a == 2); assert(b == 1); } /******************************************/ template Foo9(T) { class B { T data; } } void test9() { (new Foo9!(int).B).data += 4; } /******************************************/ template A10(T) { } template B10(T) { alias A10!(int) a; } void test10() { alias B10!(int) b; } /******************************************/ template A11(T) { T idf(T t) { return t; } } template B11(T) { private alias A11!(T) a; T same(T t) { return a.idf(t); } } void test11() { alias B11!(int) b; //printf("%d\r\n", b.same(10)); assert(b.same(10) == 10); } /******************************************/ template A12(T) { class B { invariant() { assert(1); } T ide(T t) { return t; } } } void test12() { alias A12!(int) a; a.B b = new a.B(); printf("%d\r\n", b.ide(10)); assert(b.ide(10) == 10); } /******************************************/ template A13(T) { public interface I { public T i(); } } class B13 : A13!(int).I { public int i() { return 42; } } void test13() { B13 b = new B13(); A13!(int).I i = b; assert(b.i() == 42); assert(i.i() == 42); } /******************************************/ class B14 { } template A14(T, U) { private U u; static this() { u = new U(); } } alias A14!(int, B14) t14; void test14() { } /******************************************/ template A15(T) { public interface Init { public T init(); } } template A15(T : int) { public class Init { public T init() { return 42; }; } } template A15(T : float) { public class Init { public T init() { return 3.25; }; } } template TB15(T, U) { private U initializer; private void setInitializer(U init) { initializer = init; } public class B { private T _value; public this() { this._value = initializer.init(); } public T value() { return this._value; } } } template TB15(T) { private alias TB15!(T, A15!(T).Init) tb; private void setInitializer(A15!(T).Init init) { tb.setInitializer(init); } public class B : tb.B { } } void test15() { alias TB15!(int, A15!(int).Init) tb; tb.setInitializer(new A15!(int).Init()); tb.B b = new tb.B(); int i; i = b.value(); assert(i == 42); alias TB15!(float) tb2; tb2.setInitializer(new A15!(float).Init()); tb2.B b2 = new tb2.B(); assert(b2.value() == 3.25); } /******************************************/ template foo16(U : int, int T : 9+1) { U x = T; } alias foo16!(int, 10) bar16; void test16() { int i; i = bar16.x; assert(i == 10); assert(foo16!(int, 10).x == 10); } /******************************************/ template VecTemplate(tfloat) { struct Vector { tfloat d; } } void test17() { with (VecTemplate!(int)) // crash DMD { } } /******************************************/ template Bomb (T) { void foo (T *parm) { } } template Name (T) { T y; void test () { Bomb!(T).foo (&y); } } alias Name!(int) a18; alias Name!(ubyte) b18; void test18() { } /******************************************/ template one20( T ) { alias T function () safeptr; } template one20( T1, T2 ) { alias int function(int) safeptr; } alias one20!( int ) A; A.safeptr foo20; alias one20!( int, int ) B; B.safeptr bar20; int func_bar(int i) { return 2; } void test20() { bar20 = &func_bar; } /******************************************/ class A21 { int x; } class B21 : A21 { int y; } void abc21(B21* b) { } template TFoo21(T : A21, U : T*) { void test() { assert(T.sizeof == B21.sizeof); U u; abc21(u); } } alias TFoo21!(B21, B21*) bar21; void test21() { bar21.test(); } /******************************************/ template Bug22(T : Object) { int print() { printf("Bug22(T : Object).print()\r\n"); return 1; } } template Bug22(T) { int print() { printf("Bug22(T).print()\r\n"); return 2; } } template TTest22(T) { private alias Bug22!(T) bug; class Test { int test() { return bug.print(); } } } void test22() { alias TTest22!(int).Test Test1; alias TTest22!(Test1).Test Test2; alias TTest22!(Object).Test Test3; Test1 test1 = new Test1(); Test2 test2 = new Test2(); Test3 test3 = new Test3(); int i; i = test1.test(); assert(i == 2); i = test2.test(); assert(i == 1); i = test3.test(); assert(i == 1); } /******************************************/ template T23() { struct Rank { } } template A23() { struct Array { alias T23!().Rank Rank1; Rank1 data; } } alias A23!().Array Array_int23; void test23() { } /******************************************/ template TList24(T) { class Node { } class List { Node m_first = null; } } void test24() { alias TList24!(uint).List UIntList; } /******************************************/ template TList25(T) { class Node { Node prev; Node next; T Value; } class List { Node m_first = null; Node m_last = null; void AddFront(T _Value) { Node cur = new Node; with (cur) { next = m_first; prev = null; Value = _Value; if (next !is null) next.prev = cur; } m_first = null; if (m_last is null) m_last = cur; } } } void test25() { alias TList25!(uint).List UIntList; alias TList25!(uint).Node UIntNode; UIntList list; UIntNode node; for (int i = 1; i <= 10; i++) {} //list.AddFront(i); } /******************************************/ template Foo26(T) { void doIt() { printf("Foo26(T)\r\n"); } } template Foo26(T : T[]) { private alias Foo26!(T) bug; void doIt() { printf("Foo26(T[])\r\n"); bug.doIt(); } } void test26() { alias Foo26!(int[]) foo; foo.doIt(); } /******************************************/ template Foo27(T) { public const T[] empty = []; } void test27() { alias Foo27!(int) bug; } /******************************************/ template A28(T) { public bool all(in T[] array, bool function (T) predicate) { for (int i = 0; i < array.length; i++) { if (!predicate(array[i])) { return false; } } return true; } } void test28() { static bool isVowel(char c) { return (c == 'a') || (c == 'e') || (c == 'i') || (c == 'o') || (c == 'u'); } alias A28!(char) arrays; assert(arrays.all("aeiouoeieuiei", &isVowel)); assert(arrays.all("aeoiuaioeuioaeuiouoiaeu", &isVowel)); assert(!arrays.all("aaeiouioeujiurioue", &isVowel)); assert(!arrays.all("bjkqwkjbwqjbkwb", &isVowel)); assert(arrays.all("", &isVowel)); printf("A28(char).all tests passed!\r\n"); } /******************************************/ public template TRange29(T) { debug private bool recursing = false; public class Range { private T _lower; private T _upper; public this(T lower, T upper) { this._lower = lower; this._upper = upper; } public T lower() { return this._lower; } public T upper() { return this._upper; } public bool contains(T item) { return (lower() <= item) && (item <= upper()); } public bool intersects(Range other) in { assert(other !is null); } out (result) { debug { if (!recursing) { recursing = true; assert(result == other.intersects(this)); } else { recursing = false; } } } body { return contains(other.lower()) || contains(other.upper()) || other.includes(this); } public bool includes(Range other) in { assert(other !is null); } out (result) { assert(result == (contains(other.lower()) && contains(other.upper()))); } body { return contains(other.lower()) && contains(other.upper()); } } } void test29() { alias TRange29!(int).Range Range; Range r1 = new Range(1, 10); Range r2 = new Range(5, 15); assert(r1.intersects(r2) == 1); } /******************************************/ template TCopy30(T) { void copy(out T to, T from) { to = from; } } template TCopy30(T : string) { void copy(out string to, in string from) { printf("Specialization\n"); to = from; } } void test30() { int i = 0; float f = 0; string s; alias TCopy30!(int) copyint; alias TCopy30!(string) copystr; copyint.copy(i, 3); printf("%d\n", i); assert(i == 3); copystr.copy(s, "Here it comes"); printf("%.*s\n", s.length, s.ptr); assert(s == "Here it comes"); } /******************************************/ import std.string; template Foo31(alias X) { alias X.toStringz y; } void test31() { alias Foo31!(std.string) bar; } /******************************************/ shared int x32; template Foo32(alias X) { static shared int* p = &X; } alias Foo32!(x32) abc32; void test32() { alias Foo32!(x32) bar; *bar.p = 3; assert(x32 == 3); *abc32.p = 4; assert(x32 == 4); } /******************************************/ shared int x33; template Foo33(alias X) { static shared int* p = &X; } template Bar33(alias T) { alias T!(x33) abc; } void test33() { alias Bar33!(Foo33) bar; *bar.abc.p = 3; assert(x33 == 3); } /******************************************/ shared int x34; template Foo34(alias X) { static shared int* p = &X; } template Bar34(alias T) { alias T.p q; } void test34() { alias Foo34!(x34) foo; alias Bar34!(foo) bar; *bar.q = 3; assert(x34 == 3); } /******************************************/ class Foo35 { static int p; } template Bar35(alias T) { alias T.p q; } void test35() { alias Bar35!(Foo35) bar; bar.q = 3; assert(Foo35.p == 3); } /******************************************/ template Bar36(T) { class Bar36 { static T x; }; } void test36() { Bar36!(int).x = 3; } /******************************************/ class Bar37(T) { static T x; } void test37() { Bar37!(int).x = 3; } /******************************************/ class Bar38(T) { static T x = 3; } void test38() { int i = template1.Bar38!(int).x; assert(i == 3); int j = Bar38!(int).x; assert(j == 3); } /******************************************/ class Bar39(T) { alias T x; } void test39() { Bar39!(int).x y = 3; assert(y == 3); } /******************************************/ template Bar40(T) { alias T Bar40; } void test40() { Bar40!(int) y = 3; assert(y == 3); } /******************************************/ template Bar41(T) { alias T Bar41; } void test41() { template1.Bar41!(int) y = 3; assert(y == 3); assert(template1.Bar41!(int).sizeof == int.sizeof); } /******************************************/ template Bar42(T) { T t; } typeof(Bar42!(int).t) bar42; void test42() { bar42 = 5; } /******************************************/ template factor43(int n : 1) { enum { value = 1 } } template factor43(int n) { enum { value = n*factor43!(n-1).value } } void test43() { int i = factor43!(3).value; printf("%d\n",i); assert(i == 6); } /******************************************/ template factorial1(int n : 1) { const int x = 1; } template factorial1(int n) { const int x = n*.factorial1!(n-1).x; } template factorial2(int n : 1) { const int factorial2 = 1; } template factorial2(int n) { const int factorial2 = n*.factorial2!(n-1); } template factorial3(int n : 1) { enum { x = 1 } } template factorial3(int n) { enum { x = n*.factorial3!(n-1).x } } template factorial4(int n : 1) { enum { factorial4 = 1 } } template factorial4(int n) { enum { factorial4 = n*.factorial4!(n-1) } } void test44() { int i = factorial1!(4).x; printf("%d\n",i); assert(i == 24); i = factorial2!(4); printf("%d\n",i); assert(i == 24); i = factorial3!(4).x; printf("%d\n",i); assert(i == 24); i = factorial4!(4); printf("%d\n",i); assert(i == 24); } /******************************************/ template factor45(int n) { int value() { if (n==0 || n==1) return 1; return n * factor45!(n-1).value(); } } template factor45(int n : 0) { int value() { return 1; } } template factor45(int n : 1) { int value() { return 1; } } void test45() { int i; i = factor45!(4).value(); printf( "%d\n", i); assert(i == 24); } /******************************************/ template sqrt46(int n, int lo, int hi : lo) { enum { result = lo } } void test46() { int i; i = sqrt46!(1, 24, 24).result; printf("i = %d\n", i); assert(i == 24); } /******************************************/ template sqrt47(int n, int lo, int hi) { enum { mid = (lo + hi + 1) / 2 } enum { result = (n < mid * mid) ? sqrt47!(n, lo, mid - 1).result : sqrt47!(n, mid, hi).result } } template sqrt47(int n, int lo, int hi : lo) { enum { result = lo } } template sqrt47(int n) { enum { sqrt47 = .sqrt47!(n, 1, n).result } } void test47() { int i; i = sqrt47!(24); printf("i = %d\n", i); } /******************************************/ class Foo48 (T) { alias T Type; class Inner (U) { alias U Type; }; }; struct Bar48 (alias TT) { alias TT!(int).Type A; alias TT!(int).Inner!(A).Type B; }; void test48() { Bar48!(Foo48).A x; Bar48!(Foo48).B y; int *p; p = &x; p = &y; } /******************************************/ struct Foo49(T) { static Foo49 bar(T c1) { Foo49 rtn; // Error here return rtn; } } void test49() { alias Foo49!(double) vector; vector.bar(1); } /******************************************/ struct Foo50(T) { T x = 0; static Foo50 bar(T c1) { .Foo50!(typeof(c1)) rtn; rtn.x = c1; return rtn; } static .Foo50!(T) barx(T c1) { Foo50 rtn; rtn.x = c1; return rtn; } } void test50() { alias Foo50!(double) vector; vector xAxis = vector.bar(1); } /******************************************/ struct Foo51(T) { T x = 0; .Foo51!(long)* p; static Foo51 bar(T c1) { .Foo51!(typeof(c1)) rtn; rtn.x = c1; return rtn; } static .Foo51!(T) barx(T c1) { Foo51 rtn; .Foo51!(int)* c; rtn.x = c1; return rtn; } } void test51() { alias Foo51!(double) vector; vector xAxis = vector.bar(1); } /******************************************/ interface Interface(T) { void foo52(); } void bar52(Interface!(Object) i) { i.foo52(); } class Abstract(T) : Interface!(T) { abstract void foo52(); } class Concrete(T) : Abstract!(T) { override void foo52() { printf("Concrete.foo52(this = %p)\n", this); } } class Sub(T) : Concrete!(T) { } void test52() { Sub!(Object) s = new Sub!(Object)(); s.foo52(); bar52(s); } /******************************************/ class Foo53 { template tmethod (T) { public static void tmethod (T param) { printf("param = %d\n", param); assert(param == 42); } } } void test53() { Foo53 foo = new Foo53; Foo53.tmethod!(int)(42); } /******************************************/ class Foo54 { template func(W) { static void foo(W w) { printf("W_I %d\n", w); assert(w == 3); } static int xx; } } void test54() { Foo54 c = new Foo54(); c.func!(int).foo(3); c.func!(int).xx = 4; } /******************************************/ template T55(S) { struct Foo55 { static Foo55 test(Foo55 f) { Foo55 a = f; return f; } } } alias T55!(char).Foo55 Foo55; alias T55!(char).Foo55 Bar55; void test55() { Bar55 a; Foo55 b; b.test(a); Bar55.test(a); } /******************************************/ template CT56(T) { class C { const char[][1] arrArr=["foo" ]; } } void test56() { alias CT56!(int) Ct; Ct.C c= new Ct.C(); printf("%.*s\n", c.arrArr[0].length, c.arrArr[0].ptr); assert(c.arrArr[0] == "foo"); } /******************************************/ template foo57(T : int = int) { T x = 3; } void test57() { printf("%d\n", foo57!().x); assert(foo57!().x == 3); } /******************************************/ template Foo58(T, U = T) { U x = 3; } void test58() { alias Foo58!(int) f; assert(f.x == 3); assert(f.x.sizeof == 4); } /******************************************/ template Foo59(T, U = T*) { shared T x = 3; shared U px = &x; } void test59() { alias Foo59!(uint) f; assert(f.x == 3); assert(f.x.sizeof == 4); assert(*f.px == 3); alias Foo59!(long) g; assert(g.x == 3); assert(g.x.sizeof == 8); assert(*g.px == 3); } /******************************************/ class A60 {} template B60(T, U = short) { struct Thing { T t; U u; }; } template C60(T, U = A60) { class C60 : U {} class C2 {}; } void test60() { B60!(int, long).Thing thing1; B60!(int).Thing thing2; printf("thing1.sizeof: %u\n", thing1.sizeof); printf("thing2.sizeof: %u\n", thing2.sizeof); version (Win32) assert(thing1.sizeof == 16); else version (X86_64) assert(thing1.sizeof == 16); else version(ARM) assert(thing1.sizeof == 16); else assert(thing1.sizeof == 12); assert(thing2.sizeof == 8); C60!(int /*,A60*/ ) container1; printf("container1.sizeof: %u\n", container1.sizeof); assert(container1.sizeof == (void*).sizeof); } /******************************************/ struct Foo61 { int a; template Bar(T) { T abc() { return a; } } int def() { return 4; } } void test61() { Foo61 *f = new Foo61(); int i; f.a = 3; i = f.def(); assert(i == 4); i = f.Bar!(int).abc(); assert(i == 3); Foo61 g; g.a = 3; i = g.def(); assert(i == 4); i = g.Bar!(int).abc(); assert(i == 3); } /******************************************/ class Foo62(T) { template Bar(T) { int func() { return 3; } } } void test62() { Foo62!(int) x = new Foo62!(int); assert(x.Bar!(int).func() == 3); } /******************************************/ class Foo63(T) { template Bar(T) { int func() { this.def(); return 3; } int func2() { return 4; } } void def() { assert(Bar!(T).func2() == 4); } } void test63() { Foo63!(int) x = new Foo63!(int); assert(x.Bar!(int).func() == 3); x.def(); } /******************************************/ struct XVector(qfloat) { qfloat x;qfloat y;qfloat z; static int opCall (qfloat x, qfloat y, qfloat z) { return 8; } } void test64() { int i; i = XVector!(int)(1,2,3); assert(i == 8); i = XVector!(real).opCall(1,2,3); assert(i == 8); } /******************************************/ // http://www.digitalmars.com/d/archives/28052.html alias int value_type; struct Foo65 { uint length() { return 47; } size_t test() { value_type[] e = new value_type[length]; return e.length; } } void test65() { Foo65 f; assert(f.test() == 47); } /******************************************/ class Thing66 { template print(T2) { void print(T2 t) { printf("t = %d\n", t); assert(t == 10); } } } void test66() { Thing66 thing = new Thing66; thing.print!(int)(10); } /******************************************/ template Foo67(alias T) { void Foo67() { printf("T = '%.*s'\n", T.length, T.ptr); assert(T == "hello"); } } void test67() { static string x = "hello"; Foo67!(x)(); } /******************************************/ template T68(int a) { int vec[a]; } void test68() { int i; i = T68!(4>1?4:1).vec[0]; assert(i == 0); i = T68!(4==1?1:(1==1?4:(4>1?1:4))).vec[0]; assert(i == 0); } /******************************************/ size_t printx(string s) { printf("s = '%.*s'\n", s.length, s.ptr); return s.length; } size_t printx(int i) { printf("i = %d\n", i); return 28; } template Foo69(alias T) { size_t Foo69() { return printx(T); } } void test69() { static string x = "hello"; static string z = "abc"; static int y=100; size_t i; alias Foo69!(x) foox; alias Foo69!(y) fooy; i = Foo69!(x)(); assert(i == 5); i = Foo69!(y)(); assert(i == 28); i = Foo69!(z)(); assert(i == 3); i = foox(); assert(i == 5); i = fooy(); assert(i == 28); } /******************************************/ template temptt70(alias func) { void temp() { func(); } } int x70; void myfunc70() { printf("myfunc70()\n"); x70 = 6; } alias temptt70!(myfunc70).temp foo70; void test70() { foo70(); assert(x70 == 6); } /******************************************/ struct A71(T) { alias .A71!(T) AT; int x; } alias A71!(int) Aint71; void test71() { Aint71.AT a; a.x = 3; } /******************************************/ template foo72(T) { char[] foo72(T d) { uint sz = typeof(d[0]).sizeof * 2; return null; } } void test72() { static ulong[5] a = [0,1,2,3,4]; static uint[5] b = [0,1,2,3,4]; char[] r; r = foo72!(ulong[5])(a); printf("%.*s\n", r.length, r.ptr); r = foo72!(uint[5])(b); printf("%.*s\n", r.length, r.ptr); } /******************************************/ alias int Int73; class Test73(T = Int73); alias Test73!() Foo73; void test73() { } /******************************************/ class A74 { alias A74 atype; int x; } class B74(R, int V = R.sizeof) { int v = V; } void test74() { B74!(A74,3) b = new B74!(A74,3)(); assert(b.v == 3); B74!(A74) c = new B74!(A74)(); assert(c.v == A74.sizeof); } /******************************************/ interface NotionalRange75(V) { } class MatchedNotionalRange75(R) : NotionalRange75!(R.value_type) { } class Range75 { alias int value_type; } class List75 { MatchedNotionalRange75!(Range75) x; } void test75() { } /******************************************/ interface Indian(T) { } interface Iterable(T) { Indian!(T) foo(); } class Lope(T) : Iterable!(T) { Indian!(T) foo() { return new Corn!(T); } } class Corn(T) : Indian!(T) { } void test76() { Lope!(int) x = new Lope!(int); } /******************************************/ class RawFile { } class Stream : RawFile { template readLineT(T) { bool readLineT() { if (super) return false; return true; }} bool readLine() { return readLineT!(int)(); } } void test77() { } /******************************************/ class Four(U, V, X, Y) { U i; V j; X k; Y l; } template WhatFour(U,V,X,Y) { int func(Four!(U,V,X,Y) four) { printf("general template\n"); return 1; } } template WhatFour(U:int,V,X,Y) { int func(Four!(int,V,X,Y) four) { printf("specialization:: first int\n"); return 2; } } template WhatFour(U,V:U,X,Y:X) { int func(Four!(U,U,X,X) four) { printf("specialization:: first two equal, second two equal\n"); return 3; } } alias WhatFour!(int,float,char,bool).func whatfour; alias WhatFour!(float,float,char,bool).func whatfour; alias WhatFour!(float,float,char,char).func whatfour; alias WhatFour!(int,int,float,char).func whatfour; // ambiguous match void test78() { int j; Four!(int,float,char,bool) f; Four!(float,float,char,bool) g; Four!(float,float,char,char) h; Four!(int,int,float,char) i; j = whatfour(f); assert(j == 2); j = whatfour(g); assert(j == 1); j = whatfour(h); assert(j == 3); j = whatfour(i); assert(j == 2); /* will print: specialization:: first int general template specialization:: first two equal, second two equal specialization:: first int */ } /******************************************/ // http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D.bugs&artnum=2117 class Conversion(T,U){ alias char Small; class Big{ char[2] dummy; } static Small Test(U u); static Big Test(...); static T MakeT(); enum { exists = (Test(MakeT())).sizeof == (Small).sizeof } } void variadicDummy(...){ } void test79() { variadicDummy(Conversion!(double,int).exists); } /******************************************/ class A80(T) { T s; int foo(int delegate (T) d) { return 3 + d(s); } int bar() { return foo(delegate int (T t) { return 6 + t.x; }); } } class B80: A80!(B80) { int x = 20; } class C80: A80!(C80) { int y = 3; int x = 10; } void test80() { B80 b = new B80(); C80 c = new C80(); b.s = b; c.s = c; assert(b.bar() == 9+20); assert(c.bar() == 9+10); } /******************************************/ struct T81(FOO) { S81 s; } struct S81 { T81!(int)* pt; } void test81() { } /******************************************/ T foo82(T : const(U)*, U=char)(T t) { return null; } void test82() { int i; const int ci; //writeln(typeid(typeof(foo82(&ci)))); //writeln(typeid(typeof(foo82(&i)))); assert(typeof(foo82(&ci)).stringof == "const(int)*"); assert(typeof(foo82(&i)).stringof == "int*"); } /******************************************/ struct A83 { void foo(int) {} void bar(T)(T) {} } void test83() { A83 a; a.foo = 5; a.bar = 6; } /******************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); // test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test50(); test51(); test52(); test53(); test54(); test55(); test56(); test57(); test58(); test59(); test60(); test61(); test62(); test63(); test64(); test65(); test66(); test67(); test68(); test69(); test70(); test71(); test72(); test73(); test74(); test75(); test76(); test77(); test78(); test79(); test80(); test81(); test82(); test83(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/teststdio.d0000664000175000017500000000126212776215022022374 0ustar kaikai// PERMUTE_ARGS: import std.stdio; import core.stdc.stdio; void main() { auto f = std.stdio.File("runnable/extra-files/teststdio.txt", "r"); FILE* fp = f.getFP(); string buf; int i; do { buf = f.readln('\n'); foreach (c; buf) printf("%x\n", c); printf("\n"); switch (i) { case 0: assert(buf == "asdfasdf\n"); break; case 1: assert(buf == "a\n"); break; case 2: assert(buf == "sdf\n"); break; case 3: assert(buf == "asdf\n"); break; case 4: assert(buf == "\n"); break; case 5: assert(buf == "\n"); break; case 6: assert(buf == null); break; default: assert(0); } i++; } while (!feof(fp)); //fclose(fp); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test7618.d0000664000175000017500000000032412776215022021655 0ustar kaikaiinterface ITest { int foo(); final void bar(int k)() { assert(foo() == k); } } class Test : ITest { override int foo() { return 12; } } void main() { auto test = new Test; test.bar!12(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_795.d0000664000175000017500000000243612776215022023066 0ustar kaikaidebug import core.stdc.stdio; struct Int { static int count; this(int) { ++count; debug printf("CONSTRUCT count = %d\n", count); } this(this) { ++count; debug printf("COPY count = %d\n", count); } ~this() { --count; debug printf("DESTROY count = %d\n", count); } } struct Only { Int front; bool empty; void popFront() { empty = true; } } struct Map { Only r; bool empty; auto front() @property { return Only(r.front); } void popFront() { empty = true; } } void test1() { { auto sm = Map(Only(Int(42))); bool condition = !sm.empty && sm.front.empty; } assert(Int.count == 0); } void test2() { { auto sm = Map(Only(Int(42))); bool condition = sm.empty || sm.front.empty; } assert(Int.count == 0); } void test3() { { auto sm = Map(Only(Int(42))); bool condition = sm.empty ? false : sm.front.empty; } assert(Int.count == 0); } void test4() { { auto sm = Map(Only(Int(42))); bool condition = !sm.empty ? sm.front.empty : false; } assert(Int.count == 0); } void main() { test1(); test2(); test3(); test4(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/wc2.d0000664000175000017500000000261012776215022021043 0ustar kaikai// PERMUTE_ARGS: // EXECUTE_ARGS: runnable/wc2.d import std.file; extern(C) int printf(const char*, ...); int main (string[] args) { int w_total; int l_total; int c_total; int[string] dictionary; printf(" lines words bytes file\n"); foreach (string arg; args[1 .. args.length]) { string input; int w_cnt, l_cnt, c_cnt; int inword; int wstart; input = cast(string)std.file.read(arg); for (int j = 0; j < input.length; j++) { char c; c = input[j]; if (c == '\n') ++l_cnt; if (c >= '0' && c <= '9') { } else if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') { if (!inword) { wstart = j; inword = 1; ++w_cnt; } } else if (inword) { string word = input[wstart .. j]; dictionary[word]++; inword = 0; } ++c_cnt; } if (inword) { string w = input[wstart .. input.length]; dictionary[w]++; } printf("%8lu%8lu%8lu %.*s\n", l_cnt, w_cnt, c_cnt, arg.length, arg.ptr); l_total += l_cnt; w_total += w_cnt; c_total += c_cnt; } if (args.length > 2) { printf("--------------------------------------\n%8lu%8lu%8lu total", l_total, w_total, c_total); } printf("--------------------------------------\n"); foreach (string word1; dictionary.keys.sort) { printf("%3d %.*s\n", dictionary[word1], word1.length, word1.ptr); } return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test45.d0000664000175000017500000000075712776215022021512 0ustar kaikai// EXTRA_SOURCES: imports/test45a.d imports/test45b.d // PERMUTE_ARGS: import imports.test45a; import imports.test45b; alias int function() fp1; alias int function(int) fp2; void main() { auto i = foo(); assert(i == 1); i = foo(1); assert(i == 2); i = foo; assert(i == 1); fp1 fp = &foo; i = (*fp)(); assert(i == 1); fp2 fpi = &foo; i = (*fpi)(1); assert(i == 2); i = bar(1); assert(i == 3); i = bar(1, 2); assert(i == 4); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test13117b.d0000664000175000017500000000043512776215022022071 0ustar kaikai// REQUIRED_ARGS: -inline // PERMUTE_ARGS: -O -release -g import std.file, std.stdio; int main() { auto size = thisExePath.getSize(); writeln(size); version (D_LP64) enum limit = 2023652; else enum limit = 1763328; return size > limit * 11 / 10; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/statictor.d0000664000175000017500000000236312776215022022371 0ustar kaikai// PERMUTE_ARGS: // POST_SCRIPT: runnable/extra-files/statictor-postscript.sh private import std.stdio; class Foo { static this() {printf("Foo static ctor\n");} static ~this() {printf("Foo static dtor\n");} } static this() {printf("static ctor\n");} static ~this() {printf("static dtor\n");} shared static this() { printf("shared static this()\n"); } shared static ~this() { printf("shared static this()\n"); } class Bar { static this() {printf("Bar static ctor\n");} static ~this() {printf("Bar static dtor\n");} } /***********************************************/ // 6677 int global6677; static this() nothrow pure @safe { int* p; static assert(!__traits(compiles, ++p)); static assert(!__traits(compiles, ++global6677)); auto throwit = { throw new Exception("sup"); }; static assert(!__traits(compiles, throwit() )); } shared static this() nothrow pure @safe { int* p; static assert(!__traits(compiles, ++p)); static assert(!__traits(compiles, ++global6677)); } /***********************************************/ // 7533 struct Foo7533(int n) { pure static this() { } } alias Foo7533!5 Bar7533; /***********************************************/ int main() { return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/objc_objc_msgSend.d0000664000175000017500000000422112776215022023742 0ustar kaikai// EXTRA_OBJC_SOURCES: objc_objc_msgSend.m // REQUIRED_ARGS: -L-framework -LFoundation extern (C) Class objc_lookUpClass(in char* name); struct Struct { int a, b, c, d, e; } extern (Objective-C) interface Class { stret alloc_stret() @selector("alloc"); fp2ret alloc_fp2ret() @selector("alloc"); fpret alloc_fpret() @selector("alloc"); float32 alloc_float32() @selector("alloc"); double64 alloc_double64() @selector("alloc"); } extern (Objective-C) interface stret { stret init() @selector("init"); Struct getValue() @selector("getValue"); void release() @selector("release"); } extern (Objective-C) interface fp2ret { fp2ret init() @selector("init"); creal getValue() @selector("getValue"); void release() @selector("release"); } extern (Objective-C) interface fpret { fpret init() @selector("init"); real getValue() @selector("getValue"); void release() @selector("release"); } extern (Objective-C) interface float32 { float32 init() @selector("init"); float getValue() @selector("getValue"); void release() @selector("release"); } extern (Objective-C) interface double64 { double64 init() @selector("init"); double getValue() @selector("getValue"); void release() @selector("release"); } void test_stret() { auto c = objc_lookUpClass("stret"); auto o = c.alloc_stret().init(); assert(o.getValue() == Struct(3, 3, 3, 3, 3)); o.release(); } void test_fp2ret() { auto c = objc_lookUpClass("fp2ret"); auto o = c.alloc_fp2ret().init(); assert(o.getValue() == 1+3i); o.release(); } void test_fpret() { auto c = objc_lookUpClass("fpret"); auto o = c.alloc_fpret().init(); assert(o.getValue() == 0.000000000000000002L); o.release(); } void test_float32() { auto c = objc_lookUpClass("float32"); auto o = c.alloc_float32.init(); assert(o.getValue == 0.2f); o.release(); } void test_double64() { auto c = objc_lookUpClass("double64"); auto o = c.alloc_double64.init(); assert(o.getValue == 0.2); o.release(); } void main() { test_stret(); test_fp2ret(); test_fpret(); test_float32(); test_double64(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testbounds.d0000664000175000017500000001017512776215022022547 0ustar kaikai// REQUIRED_ARGS: // Test array bounds checking import core.exception; extern(C) int printf(const char*, ...); /******************************************/ const int foos[10] = [1,2,3,4,5,6,7,8,9,10]; const int food[] = [21,22,23,24,25,26,27,28,29,30]; const int *foop = cast(int*) foos; static int x = 2; int index() { return x++; } int tests(int i) { return foos[index()]; } int testd(int i) { return food[index()]; } int testp(int i) { return foop[i]; } const(int)[] slices(int lwr, int upr) { return foos[lwr .. upr]; } const(int)[] sliced(int lwr, int upr) { return food[lwr .. upr]; } const(int)[] slicep(int lwr, int upr) { return foop[lwr .. upr]; } void test1() { int i; i = tests(0); assert(i == 3); i = testd(0); assert(i == 24); i = testp(1); assert(i == 2); x = 10; try { i = tests(0); } catch (RangeError a) { i = 73; } assert(i == 73); x = -1; try { i = testd(0); } catch (RangeError a) { i = 37; } assert(i == 37); const(int)[] r; r = slices(3,5); assert(r[0] == foos[3]); assert(r[1] == foos[4]); r = sliced(3,5); assert(r[0] == food[3]); assert(r[1] == food[4]); r = slicep(3,5); assert(r[0] == foos[3]); assert(r[1] == foos[4]); try { i = 7; r = slices(5,3); } catch (RangeError a) { i = 53; } assert(i == 53); try { i = 7; r = slices(5,11); } catch (RangeError a) { i = 53; } assert(i == 53); try { i = 7; r = sliced(5,11); } catch (RangeError a) { i = 53; } assert(i == 53); try { i = 7; r = slicep(5,3); } catch (RangeError a) { i = 53; } assert(i == 53); // Take side effects into account x = 1; r = foos[index() .. 3]; assert(x == 2); assert(r[0] == foos[1]); assert(r[1] == foos[2]); r = foos[1 .. index()]; assert(r.length == 1); assert(x == 3); assert(r[0] == foos[1]); x = 1; r = food[index() .. 3]; assert(x == 2); assert(r[0] == food[1]); assert(r[1] == food[2]); r = food[1 .. index()]; assert(r.length == 1); assert(x == 3); assert(r[0] == food[1]); x = 1; r = foop[index() .. 3]; assert(x == 2); assert(r[0] == foop[1]); assert(r[1] == foop[2]); r = foop[1 .. index()]; assert(r.length == 1); assert(x == 3); assert(r[0] == foop[1]); } /******************************************/ // 13976 void test13976() { int[] da = new int[](10); int[10] sa; size_t l = 0; // upperInRange size_t u = 9; // | lowerLessThan // | | check code { auto s = da[l .. u]; } // 0 0 (u <= 10 && l <= u ) { auto s = da[1 .. u]; } // 0 0 (u <= 10 && l <= u ) { auto s = da[l .. 10]; } // 0 0 (u <= 10 && l <= u ) { auto s = da[1 .. u%5]; } // 0 0 (u <= 10 && l <= u%5) { auto s = da[l .. u]; } // 0 0 (u <= 10 && l <= u) { auto s = da[0 .. u]; } // 0 1 (u <= 10 ) { auto s = da[l .. 10]; } // 0 0 (u <= 10 && l <= u) { auto s = da[0 .. u%5]; } // 0 1 (u%5 <= 10 ) { auto s = sa[l .. u]; } // 0 0 (u <= 10 && l <= u ) { auto s = sa[1 .. u]; } // 0 0 (u <= 10 && l <= u ) { auto s = sa[l .. 10]; } // 1 0 ( l <= u ) { auto s = sa[1 .. u%5]; } // 1 0 ( l <= u%5) { auto s = sa[l .. u]; } // 0 0 (u <= 10 && l <= u ) { auto s = sa[0 .. u]; } // 0 1 (u <= 10 ) { auto s = sa[l .. 10]; } // 1 0 ( l <= 10) { auto s = sa[0 .. u%5]; } // 1 1 NULL int* p = new int[](10).ptr; { auto s = p[0 .. u]; } // 1 1 NULL { auto s = p[l .. u]; } // 1 0 (l <= u) { auto s = p[0 .. u%5]; } // 1 1 NULL { auto s = p[1 .. u%5]; } // 1 0 (l <= u%5) } /******************************************/ int main() { test1(); test13976(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link14541.d0000664000175000017500000000377612776215022021722 0ustar kaikaiimport imports.link14541traits; void main() { Tuple!(int, int) result; alias T = typeof(result); static assert(hasElaborateAssign!T); // hasElaborateAssign!(Tuple(int, int)): // 1. instantiates Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Rvalue] // 2. instantiates swap!(Tuple!(int, int)) // 3. instantiates hasElaborateAssign!(Tuple!(int, int)) // --> forward reference error // --> swap!(Tuple!(int, int)) fails to instantiate // --> Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = rvalue] fails to instantiate // 4. instantiates Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Lvalue] // --> succeeds // hasElaborateAssign!(Tuple(int, int)) succeeds to instantiate (result is 'true') // Instantiates Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Rvalue], but // it's already done in gagged context, so this is made an error reproduction instantiation. // But, the forward reference of hasElaborateAssign!(Tuple(int, int)) is already resolved, so // the instantiation will succeeds. result = Tuple!(int, int)(0, 0); // --> 1st error reproduction instantiation result = Tuple!(int, int)(0, 0); // --> 2nd error reproduction instantiation // The two error reproduction instantiations generate the function: // Tuple!(int, int).opAssign!(Tuple!(int, int)) [auto ref = Rvalue] // twice, then it will cause duplicate COMDAT error in Win64 platform. } /+ The point is, if instantiated contexts are different, two instantiations may cause different result. - The 1st Tuple.opAssign instantiation is invoked from hasElaborateAssign template with gagging. So it has failed, because of the circular reference of hasElaborateAssign template.. - The 2nd Tuple.opAssign instantiation is invoked from main() without gagging. It does not have circular reference, so the instantiation should succeed. Therefore, the gagged failure should be overridden by the ungagged success. +/ ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/a21.d0000664000175000017500000000051612776215022020736 0ustar kaikai// EXTRA_SOURCES: imports/a21a.d // PERMUTE_ARGS: import std.stdio; import imports.a21a; template BadMixin() { int badFunc() { printf("badFunc\n"); return 2; } } int main() { int i; auto x = new SomeClass; i = x.goodFunc(); assert(i == 1); i = x.badFunc(); assert(i == 2); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/interpret2.d0000664000175000017500000000461312776215022022453 0ustar kaikai //import std.stdio; extern(C) int printf(const char*, ...); template Tuple(A...) { alias A Tuple; } template eval(A...) { const typeof(A[0]) eval = A[0]; } /************************************************/ int foo1() { int x; foreach (i; 0 .. 10) x += i; return x; } int bar1() { int x; foreach_reverse (i; 0 .. 10) { x <<= 1; x += i; } return x; } void test1() { const y = foo1(); //writeln(y); assert(y == 45); auto y1 = foo1(); //writeln(y1); assert(y1 == 45); const z = bar1(); //writeln(z); assert(z == 8194); auto z1 = bar1(); //writeln(z1); assert(z1 == 8194); } /***** Bug 2850 *********************************/ /* These tests are not passing, and shouldn't pass. A non-first field in a union being initialized cannot be converted to an expression, at least not until there are improvements to StructLiterals. */ version (none) { struct Bug2850 { union { int c; double d; } int b; int a; } static assert(is(typeof( () { enum Bug2850 w = {b:47, 714, d:4}; return w; } ))); static assert(is(typeof( () { enum Bug2850 w = {b:47, d:4}; return w; } ))); // union not initialized static assert(!is(typeof( () { enum Bug2850 w = {b:47, 4}; return w; } ))); // initializers for two fields in same union static assert(!is(typeof( () { enum Bug2850 w = {b:47, 4, c:5, 9}; return w; } ))); enum Bug2850 test2850 = {b:47, 714, d:23.1e-17}; struct Horrid2850 { union { int a; int b; struct { int c; int d; } } int f; double q; } enum Horrid2850 horrid2850 = {c:5,6}; Horrid2850 m2850 = {47, f:6}; Horrid2850 z2850 = {q:5, c:4, d:5}; static assert(!is(typeof( () { enum Horrid2850 w = {c:47, d:5, a:7}; return w; } ))); void test2() { assert(test2850.a == 714); assert(test2850.b == 47); assert(test2850.d == 23.1e-17); assert(test2850.c != 0); } } /***** Bug 3779 *********************************/ static const bug3779 = ["123"][0][$-1]; /***** Bug 1880 *********************************/ enum Property1880 {First=1,Second=2} struct CompileTimeCheck1880(Property1880 Prop) { alias Prop prop; } Property1880 junkprop1880; static assert(!is(CompileTimeCheck1880!(junkprop1880))); int main() { test1(); // test2(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/foreach4.d0000664000175000017500000004115012776215022022045 0ustar kaikai import core.stdc.stdio; import std.stdio; alias bool bit; /************************************************/ class Foo { uint array[2]; int opApply(int delegate(ref uint) dg) { int result; for (int i = 0; i < array.length; i++) { result = dg(array[i]); if (result) break; } return result; } } /**************************************************/ void test1() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; foreach (uint u; a) { i++; u++; } assert(i == 2); assert(a.array[0] == 73); assert(a.array[1] == 82); } /**************************************************/ void test2() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; foreach (ref uint u; a) { i++; u++; } assert(i == 2); assert(a.array[0] == 74); assert(a.array[1] == 83); } /**************************************************/ void test3() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; foreach (ref uint u; a) { i++; if (i) break; u++; } assert(i == 1); assert(a.array[0] == 73); assert(a.array[1] == 82); } /**************************************************/ void test4() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; foreach (ref uint u; a) { i++; if (i == 1) continue; u++; } assert(i == 2); assert(a.array[0] == 73 && a.array[1] == 83); } /**************************************************/ void test5() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; Loop: while (1) { foreach (ref uint u; a) { i++; if (i) break Loop; u++; } } assert(i == 1); assert(a.array[0] == 73); assert(a.array[1] == 82); } /**************************************************/ void test6() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; Loop: while (1) { foreach (ref uint u; a) { i++; if (i == 1) continue Loop; u++; } break; } assert(i == 3); assert(a.array[0] == 74); assert(a.array[1] == 83); } /**************************************************/ void test7() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; foreach (ref uint u; a) { i++; if (i) goto Label; u++; } assert(0); Label: assert(i == 1); assert(a.array[0] == 73); assert(a.array[1] == 82); } /**************************************************/ void test8_x(Foo a) { int i; foreach (ref uint u; a) { i++; if (i) return; u++; } } void test8() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; test8_x(a); assert(i == 0); assert(a.array[0] == 73); assert(a.array[1] == 82); } /**************************************************/ int test9_x(Foo a) { int i; foreach (ref uint u; a) { i++; if (i) return 67; u++; } return 23; } void test9() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; i = test9_x(a); assert(i == 67); assert(a.array[0] == 73); assert(a.array[1] == 82); } /**************************************************/ int test10_x(Foo a) { int i; foreach (ref uint u; a) { i++; if (i) return i; u++; } return 23; } void test10() { Foo a = new Foo(); int i; a.array[0] = 73; a.array[1] = 82; i = test10_x(a); assert(i == 1); assert(a.array[0] == 73); assert(a.array[1] == 82); } /**************************************************/ /+ the expected output: 1 1 0 0 0 1 1 0 0 0 1 1 0 0 0 1 1 0 0 0 1 1 0 0 0 1 1 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 1 1 1 0 1 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 1 1 1 0 1 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 1 1 1 0 +/ void test11() { bit[25] data; int j; for (int i = 0; i < 25; i += 5) { data[i+0] = data[i+1] = true; } for (int i = 0; i < 25; i++) { printf("%d ", data[i]); if ((i % 5) < 2) assert(data[i] == true); else assert(data[i] == false); } printf("\n%d\n", data[22] = true); j = data[22] = true; assert(j == true); for (int i = 0; i < 25; i += 5) { data[i+1] = data[i+3] = true; j = i % 5; if (j == 0 || j == 1 || j == 3) assert(data[i] == true); else assert(data[i] == false); } for (int i = 0; i < 25; i++) { printf("%d ", data[i]); } printf("\n"); int k; foreach (bit b; data) { printf("%d ", b); j = k % 5; if (j == 0 || j == 1 || j == 3 || k == 22) assert(data[k] == true); else assert(data[k] == false); k++; } printf("\n"); foreach (int l, bit b; data) { printf("%d ", b); j = l % 5; if (j == 0 || j == 1 || j == 3 || l == 22) assert(data[l] == true); else assert(data[l] == false); } printf("\n"); } /**************************************************/ void test12() { int j; j = 0; foreach (dchar d; "hello") { printf("d = x%x\n", d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); j++; } assert(j == 5); j = 0; foreach (size_t i, dchar d; "hello") { printf("i = %d, d = x%x\n", i, d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); assert(i == j); j++; } assert(j == 5); } /**************************************************/ void test13() { int j; j = 0; foreach (wchar d; "hello") { printf("d = x%x\n", d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); j++; } assert(j == 5); j = 0; foreach (size_t i, wchar d; "hello") { printf("i = %d, d = x%x\n", i, d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); assert(i == j); j++; } assert(j == 5); } /**************************************************/ void test14() { int j; j = 0; foreach (char d; cast(wstring)"hello") { printf("d = x%x\n", d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); j++; } assert(j == 5); j = 0; foreach (size_t i, char d; cast(wstring)"hello") { printf("i = %d, d = x%x\n", i, d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); assert(i == j); j++; } assert(j == 5); } /**************************************************/ void test15() { int j; j = 0; foreach (dchar d; cast(wstring)"hello") { printf("d = x%x\n", d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); j++; } assert(j == 5); j = 0; foreach (size_t i, dchar d; cast(wstring)"hello") { printf("i = %d, d = x%x\n", i, d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); assert(i == j); j++; } assert(j == 5); } /**************************************************/ void test16() { int j; j = 0; foreach (char d; cast(dstring)"hello") { printf("d = x%x\n", d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); j++; } assert(j == 5); j = 0; foreach (size_t i, char d; cast(dstring)"hello") { printf("i = %d, d = x%x\n", i, d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); assert(i == j); j++; } assert(j == 5); } /**************************************************/ void test17() { int j; j = 0; foreach (wchar d; cast(dstring)"hello") { printf("d = x%x\n", d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); j++; } assert(j == 5); j = 0; foreach (size_t i, wchar d; cast(dstring)"hello") { printf("i = %d, d = x%x\n", i, d); if (j == 0) assert(d == 'h'); if (j == 1) assert(d == 'e'); if (j == 2) assert(d == 'l'); if (j == 3) assert(d == 'l'); if (j == 4) assert(d == 'o'); assert(i == j); j++; } assert(j == 5); } /**************************************************/ void test18() { string a = "\xE2\x89\xA0"; // \u2260 encoded as 3 UTF-8 bytes foreach (dchar c; a) { printf("a[] = %x\n", c); // prints 'a[] = 2260' assert(c == 0x2260); } dstring b = "\u2260"; int i; foreach (char c; b) { printf("%x, ", c); // prints e2, 89, a0 if (i == 0) assert(c == 0xE2); else if (i == 1) assert(c == 0x89); else if (i == 2) assert(c == 0xA0); else assert(0); i++; } printf("\n"); } /**************************************************/ void test19() { string string = x"F0 9D 83 93"; int count=0; dchar tmp; foreach(dchar value ; string){ tmp=value; count++; } assert(count==1); assert(tmp==0x01D0D3); } /**************************************************/ struct S20 { int opApply(int delegate(ref int i) dg) { return 0; } } S20 foo20; void test20() { label: foreach(int i; foo20) { continue label; } } /**************************************************/ void foo21(string[] args) { printf("args.length = %d\n", args.length); assert(args.length == 3); foreach (i, arg; args) { assert(typeid(typeof(i)) == typeid(size_t)); assert(typeid(typeof(arg)) == typeid(string)); writefln("args[%d] = '%s'", i, arg); } foreach (arg; args) { assert(typeid(typeof(arg)) == typeid(string)); writefln("args[] = '%s'", arg); } } void test21() { string[] args; args.length = 3; args[0] = "a"; args[1] = "bc"; args[2] = "d"; foo21(args); } /**************************************************/ void test22() { int[string] map; map["hello"] = 3; map["world"] = 4; foreach (key, value; map) { assert(typeid(typeof(key)) == typeid(string)); assert(typeid(typeof(value)) == typeid(int)); writefln("map[%s] = %s", key, value); } foreach (key, int value; map) { assert(typeid(typeof(key)) == typeid(string)); assert(typeid(typeof(value)) == typeid(int)); writefln("map[%s] = %s", key, value); } foreach (string key, value; map) { assert(typeid(typeof(key)) == typeid(string)); assert(typeid(typeof(value)) == typeid(int)); writefln("map[%s] = %s", key, value); } foreach (value; map) { assert(typeid(typeof(value)) == typeid(int)); writefln("map[] = %s", value); } } /**************************************************/ class Foo23 { int array[2]; int opApply(int delegate(ref int) dg) { int result; for (int i = 0; i < array.length; i++) { result = dg(array[i]); if (result) break; } return result; } int opApply(int delegate(ref size_t, ref int) dg) { int result; for (size_t i = 0; i < array.length; i++) { result = dg(i, array[i]); if (result) break; } return result; } } void test23() { Foo23 a = new Foo23(); int i; a.array[0] = 73; a.array[1] = 82; foreach (u; a) { assert(typeid(typeof(u)) == typeid(int)); i++; u++; //writefln("u = %d", u); assert((i == 1) ? u == 74 : u == 83); } assert(i == 2); assert(a.array[0] == 73); assert(a.array[1] == 82); foreach (j, u; a) { assert(typeid(typeof(j)) == typeid(size_t)); assert(typeid(typeof(u)) == typeid(int)); i++; u++; writefln("u = %d", u); assert((i == 3) ? u == 74 : u == 83); assert(j == i - 3); } assert(i == 4); assert(a.array[0] == 73); assert(a.array[1] == 82); } /**************************************************/ struct Collection24 { int opApply(int delegate(ref int) dg){ return 0; } } bool foo24() { Collection24 a,b; foreach(int x; a){ foreach(int y; b){ return false; } } return true; } void test24() { assert(foo24() == true); } /**************************************************/ void test25() { alias void function(string[string]) FN; FN fn = function (string[string] aarray) { foreach (string s; aarray) { writeln(s); assert(s == "b"); } }; string[string] aarray; aarray["a"] = "b"; fn(aarray); } /**************************************************/ struct Foo26 { uint array[2]; int forward(int delegate(ref uint) dg) { int result; for (int i = 0; i < array.length; i++) { result = dg(array[i]); if (result) break; } return result; } int forward(int delegate(ref uint) dg, int x) { return 1; } int reverse(int delegate(ref uint) dg, int x) { return 1; } int reverse(int delegate(ref uint) dg) { int result; foreach_reverse (v; array) { auto u = v; result = dg(u); if (result) break; } return result; } } void test26() { Foo26 a; int i; a.array[0] = 73; a.array[1] = 82; foreach (u; &a.forward) { writeln(u); i++; u++; } assert(i == 2); assert(a.array[0] == 73); assert(a.array[1] == 82); foreach (uint u; &a.reverse) { writeln(u); } } /**************************************************/ struct S27 { int[] a; bool empty() { return a.length == 0; } void popFront() { a = a[1 .. $]; } int front() { return a[0]; } void popBack() { a = a[0 .. $ - 1]; } ref int back() { return a[$ - 1]; } } void test27() { S27 s; s.a = [5,6,7]; string r; foreach (e; s) { printf("%d\n", e); r ~= cast(char)(e + '0'); } assert(r == "567"); r = null; foreach_reverse (ref e; s) { e++; printf("%d\n", e); r ~= cast(char)(e + '0'); } assert(r == "876"); r = null; foreach (e; s) { printf("%d\n", e); r ~= cast(char)(e + '0'); } assert(r == "678"); } /**************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/dhry.d0000664000175000017500000007546012776215022021333 0ustar kaikai// PERMUTE_ARGS: // REQUIRED_ARGS: -release -O -g -inline // DISABLED: freebsd /* ************************************************************************* * * "DHRYSTONE" Benchmark Program * ----------------------------- * * Version: C, Version 2.1 * * File: dhry.h (part 1 of 3) * * Date: May 25, 1988 * * Author: Reinhold P. Weicker * Siemens Nixdorf Inf. Syst. * STM OS 32 * Otto-Hahn-Ring 6 * W-8000 Muenchen 83 * Germany * Phone: [+49]-89-636-42436 * (8-17 Central European Time) * UUCP: weicker@ztivax.uucp@unido.uucp * Internet: weicker@ztivax.siemens.com * * Original Version (in Ada) published in * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), * pp. 1013 - 1030, together with the statistics * on which the distribution of statements etc. is based. * * In this C version, the following C library functions are * used: * - strcpy, strcmp (inside the measurement loop) * - printf, scanf (outside the measurement loop) * * Collection of Results: * Reinhold Weicker (address see above) and * * Rick Richardson * PC Research. Inc. * 94 Apple Orchard Drive * Tinton Falls, NJ 07724 * Phone: (201) 834-1378 (9-17 EST) * UUCP: ...!uunet!pcrat!rick * * Please send results to Rick Richardson and/or Reinhold Weicker. * Complete information should be given on hardware and software * used. Hardware information includes: Machine type, CPU, type and * size of caches; for microprocessors: clock frequency, memory speed * (number of wait states). Software information includes: Compiler * (and runtime library) manufacturer and version, compilation * switches, OS version. The Operating System version may give an * indication about the compiler; Dhrystone itself performs no OS * calls in the measurement loop. * * The complete output generated by the program should be mailed * such that at least some checks for correctness can be made. * ************************************************************************* * * History: This version C/2.1 has been made for two reasons: * * 1) There is an obvious need for a common C version of * Dhrystone, since C is at present the most popular system * programming language for the class of processors * (microcomputers, minicomputers) where Dhrystone is used * most. There should be, as far as possible, only one C * version of Dhrystone such that results can be compared * without restrictions. In the past, the C versions * distributed by Rick Richardson (Version 1.1) and by * Reinhold Weicker had small (though not significant) * differences. * * 2) As far as it is possible without changes to the * Dhrystone statistics, optimizing compilers should be * prevented from removing significant statements. * * This C version has been developed in cooperation with * Rick Richardson (Tinton Falls, NJ), it incorporates many * ideas from the "Version 1.1" distributed previously by * him over the UNIX network Usenet. * I also thank Chaim Benedelac (National Semiconductor), * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) * for their help with comments on earlier versions of the * benchmark. * * Changes: In the initialization part, this version follows mostly * Rick Richardson's version distributed via Usenet, not the * version distributed earlier via floppy disk by Reinhold * Weicker. As a concession to older compilers, names have * been made unique within the first 8 characters. Inside the * measurement loop, this version follows the version * previously distributed by Reinhold Weicker. * * At several places in the benchmark, code has been added, * but within the measurement loop only in branches that * are not executed. The intention is that optimizing * compilers should be prevented from moving code out of the * measurement loop, or from removing code altogether. Since * the statements that are executed within the measurement * loop have NOT been changed, the numbers defining the * "Dhrystone distribution" (distribution of statements, * operand types and locality) still hold. Except for * sophisticated optimizing compilers, execution times for * this version should be the same as for previous versions. * * Since it has proven difficult to subtract the time for the * measurement loop overhead in a correct way, the loop check * has been made a part of the benchmark. This does have * an impact - though a very minor one - on the distribution * statistics which have been updated for this version. * * All changes within the measurement loop are described * and discussed in the companion paper "Rationale for * Dhrystone version 2". * * Because of the self-imposed limitation that the order and * distribution of the executed statements should not be * changed, there are still cases where optimizing compilers * may not generate code for some statements. To a certain * degree, this is unavoidable for small synthetic * benchmarks. Users of the benchmark are advised to check * code listings whether code is generated for all statements * of Dhrystone. * * Version 2.1 is identical to version 2.0 distributed via * the UNIX network Usenet in March 1988 except that it * corrects some minor deficiencies that were found by users * of version 2.0. The only change within the measurement * loop is that a non-executed "else" part was added to the * "if" statement in Func_3, and a non-executed "else" part * removed from Proc_3. * ************************************************************************* * * Defines: The following "Defines" are possible: * -DROPT (default: Not defined) * As an approximation to what an average C * programmer might do, the "register" storage class * is applied (if enabled by -DROPT) * - for local variables, if they are used * (dynamically) five or more times * - for parameters if they are used (dynamically) * six or more times * Note that an optimal "register" strategy is * compiler-dependent, and that "register" * declarations do not necessarily lead to faster * execution. * -DNOSTRUCTASSIGN (default: Not defined) * Define if the C compiler does not support * assignment of structures. * -DNOENUMS (default: Not defined) * Define if the C compiler does not support * enumeration types. * ************************************************************************* * * Compilation model and measurement (IMPORTANT): * * This C version of Dhrystone consists of three files: * - dhry.h (this file, containing global definitions and comments) * - dhry_1.c (containing the code corresponding to Ada package Pack_1) * - dhry_2.c (containing the code corresponding to Ada package Pack_2) * * The following "ground rules" apply for measurements: * - Separate compilation * - No procedure merging * - Otherwise, compiler optimizations are allowed but should be * indicated * - Default results are those without register declarations * See the companion paper "Rationale for Dhrystone Version 2" for a more * detailed discussion of these ground rules. * * For 16-Bit processors (e.g. 80186, 80286), times for all compilation * models ("small", "medium", "large" etc.) should be given if possible, * together with a definition of these models for the compiler system * used. * ************************************************************************* * * Dhrystone (C version) statistics: * * [Comment from the first distribution, updated for version 2. * Note that because of language differences, the numbers are slightly * different from the Ada version.] * * The following program contains statements of a high level programming * language (here: C) in a distribution considered representative: * * assignments 52 (51.0 %) * control statements 33 (32.4 %) * procedure, function calls 17 (16.7 %) * * 103 statements are dynamically executed. The program is balanced with * respect to the three aspects: * * - statement type * - operand type * - operand locality * operand global, local, parameter, or constant. * * The combination of these three aspects is balanced only approximately. * * 1. Statement Type: * ----------------- number * * V1 = V2 9 * (incl. V1 = F(..) * V = Constant 12 * Assignment, 7 * with array element * Assignment, 6 * with record component * -- * 34 34 * * X = Y +|-|"&&"|"|" Z 5 * X = Y +|-|"==" Constant 6 * X = X +|- 1 3 * X = Y *|/ Z 2 * X = Expression, 1 * two operators * X = Expression, 1 * three operators * -- * 18 18 * * if .... 14 * with "else" 7 * without "else" 7 * executed 3 * not executed 4 * for ... 7 | counted every time * while ... 4 | the loop condition * do ... while 1 | is evaluated * switch ... 1 * break 1 * declaration with 1 * initialization * -- * 34 34 * * P (...) procedure call 11 * user procedure 10 * library procedure 1 * X = F (...) * function call 6 * user function 5 * library function 1 * -- * 17 17 * --- * 103 * * The average number of parameters in procedure or function calls * is 1.82 (not counting the function values as implicit parameters). * * * 2. Operators * ------------ * number approximate * percentage * * Arithmetic 32 50.8 * * + 21 33.3 * - 7 11.1 * * 3 4.8 * / (int div) 1 1.6 * * Comparison 27 42.8 * * == 9 14.3 * /= 4 6.3 * > 1 1.6 * < 3 4.8 * >= 1 1.6 * <= 9 14.3 * * Logic 4 6.3 * * && (AND-THEN) 1 1.6 * | (OR) 1 1.6 * ! (NOT) 2 3.2 * * -- ----- * 63 100.1 * * * 3. Operand Type (counted once per operand reference): * --------------- * number approximate * percentage * * Integer 175 72.3 % * Character 45 18.6 % * Pointer 12 5.0 % * String30 6 2.5 % * Array 2 0.8 % * Record 2 0.8 % * --- ------- * 242 100.0 % * * When there is an access path leading to the final operand (e.g. a * record component), only the final data type on the access path is * counted. * * * 4. Operand Locality: * ------------------- * number approximate * percentage * * local variable 114 47.1 % * global variable 22 9.1 % * parameter 45 18.6 % * value 23 9.5 % * reference 22 9.1 % * function result 6 2.5 % * constant 55 22.7 % * --- ------- * 242 100.0 % * * * The program does not compute anything meaningful, but it is * syntactically and semantically correct. All variables have a value * assigned to them before they are used as a source operand. * * There has been no explicit effort to account for the effects of a * cache, or to balance the use of long or short displacements for code * or data. * ************************************************************************* */ import core.stdc.stdio; import core.stdc.string; import core.stdc.stdlib; import std.string; /* Compiler and system dependent definitions: */ const double Mic_secs_Per_Second = 1000000.0; /* Berkeley UNIX C returns process times in seconds/HZ */ enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} alias int Enumeration; /* for boolean and enumeration types in Ada, Pascal */ /* General definitions: */ const int StrLen = 30; alias int One_Thirty; alias int One_Fifty; alias char Capital_Letter; alias bool Boolean; alias char Str_30 [StrLen]; alias int Arr_1_Dim [50]; alias int Arr_2_Dim [50] [50]; struct record { record *Ptr_Comp; Enumeration Discr; union V { struct V1 { Enumeration Enum_Comp; int Int_Comp; char Str_Comp [StrLen]; } V1 var_1; struct V2 { Enumeration E_Comp_2; char Str_2_Comp [StrLen]; } V2 var_2; struct V3 { char Ch_1_Comp; char Ch_2_Comp; } V3 var_3; } V variant; } alias record Rec_Type; alias record *Rec_Pointer; /* Global Variables: */ Rec_Pointer Ptr_Glob, Next_Ptr_Glob; int Int_Glob; Boolean Bool_Glob; char Ch_1_Glob, Ch_2_Glob; int Arr_1_Glob [50]; int Arr_2_Glob [50] [50]; char[StrLen] Reg_Define = "Register option selected."; /* variables for time measurement: */ const int Too_Small_Time = 2; /* Measurements should last at least 2 seconds */ double Begin_Time, End_Time, User_Time; double Microseconds, Dhrystones_Per_Second, Vax_Mips; /* end of variables for time measurement */ void main () /*****/ /* main program, corresponds to procedures */ /* Main and Proc_0 in the Ada version */ { One_Fifty Int_1_Loc; One_Fifty Int_2_Loc; One_Fifty Int_3_Loc; char Ch_Index; Enumeration Enum_Loc; Str_30 Str_1_Loc; Str_30 Str_2_Loc; int Run_Index; int Number_Of_Runs; /+ FILE *Ap; /* Initializations */ if ((Ap = fopen("dhry.res","a+")) == null) { printf("Can not open dhry.res\n\n"); exit(1); } +/ Next_Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof); Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof); Ptr_Glob.Ptr_Comp = Next_Ptr_Glob; Ptr_Glob.Discr = Ident_1; Ptr_Glob.variant.var_1.Enum_Comp = Ident_3; Ptr_Glob.variant.var_1.Int_Comp = 40; // strcpy (Ptr_Glob.variant.var_1.Str_Comp, // "DHRYSTONE PROGRAM, SOME STRING"); // strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); Ptr_Glob.variant.var_1.Str_Comp[] = "DHRYSTONE PROGRAM, SOME STRING"; Str_1_Loc[] = "DHRYSTONE PROGRAM, 1'ST STRING"; Arr_2_Glob [8][7] = 10; /* Was missing in published program. Without this statement, */ /* Arr_2_Glob [8][7] would have an undefined value. */ /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ /* overflow may occur for this array element. */ printf ("\n"); printf ("Dhrystone Benchmark, Version 2.1 (Language: D)\n"); printf ("\n"); printf ("Please give the number of runs through the benchmark: "); { int n; //scanf ("%d", &n); n = 10000000; Number_Of_Runs = n; } printf ("\n"); printf ("Execution starts, %d runs through Dhrystone\n",Number_Of_Runs); /***************/ /* Start timer */ /***************/ Begin_Time = dtime(); for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) { Proc_5(); Proc_4(); /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ Int_1_Loc = 2; Int_2_Loc = 3; //strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); Str_2_Loc[] = "DHRYSTONE PROGRAM, 2'ND STRING"; Enum_Loc = Ident_2; Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); /* Bool_Glob == 1 */ while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ { Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; /* Int_3_Loc == 7 */ Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); /* Int_3_Loc == 7 */ Int_1_Loc += 1; } /* while */ /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); /* Int_Glob == 5 */ Proc_1 (Ptr_Glob); for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) /* loop body executed twice */ { if (Enum_Loc == Func_1 (Ch_Index, 'C')) /* then, not executed */ { Proc_6 (Ident_1, &Enum_Loc); //strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); Str_2_Loc[] = "DHRYSTONE PROGRAM, 3'RD STRING"; Int_2_Loc = Run_Index; Int_Glob = Run_Index; } } /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ Int_2_Loc = Int_2_Loc * Int_1_Loc; Int_1_Loc = Int_2_Loc / Int_3_Loc; Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ Proc_2 (&Int_1_Loc); /* Int_1_Loc == 5 */ } /* loop "for Run_Index" */ /**************/ /* Stop timer */ /**************/ End_Time = dtime(); printf ("Execution ends\n"); printf ("\n"); printf ("Final values of the variables used in the benchmark:\n"); printf ("\n"); printf ("Int_Glob: %d\n", Int_Glob); printf (" should be: %d\n", 5); printf ("Bool_Glob: %d\n", Bool_Glob); printf (" should be: %d\n", 1); printf ("Ch_1_Glob: %c\n", Ch_1_Glob); printf (" should be: %c\n", cast(int)'A'); printf ("Ch_2_Glob: %c\n", Ch_2_Glob); printf (" should be: %c\n", cast(int)'B'); printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]); printf (" should be: %d\n", 7); printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]); printf (" should be: Number_Of_Runs + 10\n"); printf ("Ptr_Glob.\n"); printf (" Ptr_Comp: %d\n", cast(int) Ptr_Glob.Ptr_Comp); printf (" should be: (implementation-dependent)\n"); printf (" Discr: %d\n", Ptr_Glob.Discr); printf (" should be: %d\n", 0); printf (" Enum_Comp: %d\n", Ptr_Glob.variant.var_1.Enum_Comp); printf (" should be: %d\n", 2); printf (" Int_Comp: %d\n", Ptr_Glob.variant.var_1.Int_Comp); printf (" should be: %d\n", 17); printf (" Str_Comp: %.*s\n", Ptr_Glob.variant.var_1.Str_Comp.length, Ptr_Glob.variant.var_1.Str_Comp.ptr); printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); printf ("Next_Ptr_Glob.\n"); printf (" Ptr_Comp: %d\n", cast(int) Next_Ptr_Glob.Ptr_Comp); printf (" should be: (implementation-dependent), same as above\n"); printf (" Discr: %d\n", Next_Ptr_Glob.Discr); printf (" should be: %d\n", 0); printf (" Enum_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Enum_Comp); printf (" should be: %d\n", 1); printf (" Int_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Int_Comp); printf (" should be: %d\n", 18); printf (" Str_Comp: %.*s\n", Next_Ptr_Glob.variant.var_1.Str_Comp.length, Next_Ptr_Glob.variant.var_1.Str_Comp.ptr); printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); printf ("Int_1_Loc: %d\n", Int_1_Loc); printf (" should be: %d\n", 5); printf ("Int_2_Loc: %d\n", Int_2_Loc); printf (" should be: %d\n", 13); printf ("Int_3_Loc: %d\n", Int_3_Loc); printf (" should be: %d\n", 7); printf ("Enum_Loc: %d\n", Enum_Loc); printf (" should be: %d\n", 1); printf ("Str_1_Loc: %.*s\n", Str_1_Loc.length, Str_1_Loc.ptr); printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n"); printf ("Str_2_Loc: %.*s\n", Str_2_Loc.length, Str_2_Loc.ptr); printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n"); printf ("\n"); User_Time = End_Time - Begin_Time; if (User_Time < Too_Small_Time) { printf ("Measured time too small to obtain meaningful results\n"); printf ("Please increase number of runs\n"); printf ("\n"); } else { Microseconds = User_Time * Mic_secs_Per_Second / cast(double) Number_Of_Runs; Dhrystones_Per_Second = cast(double) Number_Of_Runs / User_Time; Vax_Mips = Dhrystones_Per_Second / 1757.0; printf ("Register option selected? NO\n"); strcpy(Reg_Define.ptr, "Register option not selected."); printf ("Microseconds for one run through Dhrystone: "); printf ("%7.1lf \n", Microseconds); printf ("Dhrystones per Second: "); printf ("%10.1lf \n", Dhrystones_Per_Second); printf ("VAX MIPS rating = %10.3lf \n",Vax_Mips); printf ("\n"); /+ fprintf(Ap,"\n"); fprintf(Ap,"Dhrystone Benchmark, Version 2.1 (Language: D)\n"); fprintf(Ap,"%.*s\n",Reg_Define.length, Reg_Define.ptr); fprintf(Ap,"Microseconds for one loop: %7.1lf\n",Microseconds); fprintf(Ap,"Dhrystones per second: %10.1lf\n",Dhrystones_Per_Second); fprintf(Ap,"VAX MIPS rating: %10.3lf\n",Vax_Mips); fclose(Ap); +/ } } void Proc_1 (Rec_Pointer Ptr_Val_Par) /******************/ /* executed once */ { Rec_Pointer Next_Record = Ptr_Val_Par.Ptr_Comp; /* == Ptr_Glob_Next */ /* Local variable, initialized with Ptr_Val_Par.Ptr_Comp, */ /* corresponds to "rename" in Ada, "with" in Pascal */ *Ptr_Val_Par.Ptr_Comp = *Ptr_Glob; Ptr_Val_Par.variant.var_1.Int_Comp = 5; Next_Record.variant.var_1.Int_Comp = Ptr_Val_Par.variant.var_1.Int_Comp; Next_Record.Ptr_Comp = Ptr_Val_Par.Ptr_Comp; Proc_3 (&Next_Record.Ptr_Comp); /* Ptr_Val_Par.Ptr_Comp.Ptr_Comp == Ptr_Glob.Ptr_Comp */ if (Next_Record.Discr == Ident_1) /* then, executed */ { Next_Record.variant.var_1.Int_Comp = 6; Proc_6 (Ptr_Val_Par.variant.var_1.Enum_Comp, &Next_Record.variant.var_1.Enum_Comp); Next_Record.Ptr_Comp = Ptr_Glob.Ptr_Comp; Proc_7 (Next_Record.variant.var_1.Int_Comp, 10, &Next_Record.variant.var_1.Int_Comp); } else /* not executed */ *Ptr_Val_Par = *Ptr_Val_Par.Ptr_Comp; } /* Proc_1 */ void Proc_2 (One_Fifty *Int_Par_Ref) /******************/ /* executed once */ /* *Int_Par_Ref == 1, becomes 4 */ { One_Fifty Int_Loc; Enumeration Enum_Loc; Int_Loc = *Int_Par_Ref + 10; do /* executed once */ if (Ch_1_Glob == 'A') /* then, executed */ { Int_Loc -= 1; *Int_Par_Ref = Int_Loc - Int_Glob; Enum_Loc = Ident_1; } /* if */ while (Enum_Loc != Ident_1); /* true */ } /* Proc_2 */ void Proc_3 (Rec_Pointer *Ptr_Ref_Par) /******************/ /* executed once */ /* Ptr_Ref_Par becomes Ptr_Glob */ { if (Ptr_Glob != null) /* then, executed */ *Ptr_Ref_Par = Ptr_Glob.Ptr_Comp; Proc_7 (10, Int_Glob, &Ptr_Glob.variant.var_1.Int_Comp); } /* Proc_3 */ void Proc_4 () /* without parameters */ /*******/ /* executed once */ { Boolean Bool_Loc; Bool_Loc = Ch_1_Glob == 'A'; Bool_Glob = Bool_Loc | Bool_Glob; Ch_2_Glob = 'B'; } /* Proc_4 */ void Proc_5 () /* without parameters */ /*******/ /* executed once */ { Ch_1_Glob = 'A'; Bool_Glob = false; } /* Proc_5 */ void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par) /*********************************/ /* executed once */ /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ { *Enum_Ref_Par = Enum_Val_Par; if (! Func_3 (Enum_Val_Par)) /* then, not executed */ *Enum_Ref_Par = Ident_4; final switch (Enum_Val_Par) { case Ident_1: *Enum_Ref_Par = Ident_1; break; case Ident_2: if (Int_Glob > 100) /* then */ *Enum_Ref_Par = Ident_1; else *Enum_Ref_Par = Ident_4; break; case Ident_3: /* executed */ *Enum_Ref_Par = Ident_2; break; case Ident_4: break; case Ident_5: *Enum_Ref_Par = Ident_3; break; } /* switch */ } /* Proc_6 */ void Proc_7 (One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, One_Fifty *Int_Par_Ref) /**********************************************/ /* executed three times */ /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ /* Int_Par_Ref becomes 7 */ /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ /* Int_Par_Ref becomes 17 */ /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ /* Int_Par_Ref becomes 18 */ { One_Fifty Int_Loc; Int_Loc = Int_1_Par_Val + 2; *Int_Par_Ref = Int_2_Par_Val + Int_Loc; } /* Proc_7 */ void Proc_8 (ref Arr_1_Dim Arr_1_Par_Ref, ref Arr_2_Dim Arr_2_Par_Ref, int Int_1_Par_Val, int Int_2_Par_Val) /*********************************************************************/ /* executed once */ /* Int_Par_Val_1 == 3 */ /* Int_Par_Val_2 == 7 */ { One_Fifty Int_Index; One_Fifty Int_Loc; Int_Loc = Int_1_Par_Val + 5; Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc]; Arr_1_Par_Ref [Int_Loc+30] = Int_Loc; for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index) Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1; Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; Int_Glob = 5; } /* Proc_8 */ Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val) /*************************************************/ /* executed three times */ /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ { Capital_Letter Ch_1_Loc; Capital_Letter Ch_2_Loc; Ch_1_Loc = Ch_1_Par_Val; Ch_2_Loc = Ch_1_Loc; if (Ch_2_Loc != Ch_2_Par_Val) /* then, executed */ return (Ident_1); else /* not executed */ { Ch_1_Glob = Ch_1_Loc; return (Ident_2); } } /* Func_1 */ Boolean Func_2 (Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref) /*************************************************/ /* executed once */ /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ { One_Thirty Int_Loc; Capital_Letter Ch_Loc; Int_Loc = 2; while (Int_Loc <= 2) /* loop body executed once */ if (Func_1 (Str_1_Par_Ref[Int_Loc], Str_2_Par_Ref[Int_Loc+1]) == Ident_1) /* then, executed */ { Ch_Loc = 'A'; Int_Loc += 1; } /* if, while */ if (Ch_Loc >= 'W' && Ch_Loc < 'Z') /* then, not executed */ Int_Loc = 7; if (Ch_Loc == 'R') /* then, not executed */ return (true); else /* executed */ { //if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) //if (memcmp (Str_1_Par_Ref, Str_2_Par_Ref, 30) > 0) if (Str_1_Par_Ref > Str_2_Par_Ref) /* then, not executed */ { Int_Loc += 7; Int_Glob = Int_Loc; return (true); } else /* executed */ return (false); } /* if Ch_Loc */ } /* Func_2 */ Boolean Func_3 (Enumeration Enum_Par_Val) /***************************/ /* executed once */ /* Enum_Par_Val == Ident_3 */ { Enumeration Enum_Loc; Enum_Loc = Enum_Par_Val; if (Enum_Loc == Ident_3) /* then, executed */ return (true); else /* not executed */ return (false); } /* Func_3 */ version (Windows) { import core.sys.windows.windows; double dtime() { double q; q = cast(double)GetTickCount() * 1.0e-03; return q; } } version (linux) { import core.stdc.time; double dtime() { double q; q = cast(double)time(null); return q; } } version (OSX) // supplied by Anders F Bjorklund { import core.sys.posix.sys.time; double dtime() { double q; timeval tv; gettimeofday(&tv,null); q = cast(double)tv.tv_sec + cast(double)tv.tv_usec * 1.0e-6; return q; } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/tls.d0000664000175000017500000000274712776215022021165 0ustar kaikai// EXTRA_SOURCES: imports/tlsa.d import core.stdc.stdio; import imports.tlsa; int x = 3; void bar() { int* px = &x; assert(x == 3); x++; printf("x = %d\n", x); px = &x; printf("px = %p\n", px); assert(*px == 4); (*px)++; assert(x == 5); } void test1() { bar(); printf("%d\n", x); printf("%d\n", foo!()()); } /************************************/ long fooa; long foob; int bara = 0x12345678; int barb = 0x9ABCDEFF; void test2() { fooa++; foob--; bara++; barb++; printf("%lld %lld %x %x\n", fooa, foob, bara, barb); assert(fooa == 1); assert(foob == -1); assert(bara == 0x12345679); assert(barb == 0x9ABCDF00); } /************************************/ int abc3(T)(T t) { static T qqq; static T rrr; static T sss = 8; static T ttt = 9; printf("qqq = %d, rrr = %d, sss = %d, ttt = %d\n", qqq, rrr, sss, ttt); assert(sss == 8); assert(ttt == 9); rrr += 7; return t + ++qqq + rrr; } void test3() { auto i = abc3(3); printf("i = x%x\n", i); assert(i == 11); i = abc3(4); printf("i = x%x\n", i); assert(i == 20); } /************************************/ void test4() { auto i = bar4(); printf("i = x%x\n", i); assert(i == 0x23); i = abc4(4); printf("i = x%x\n", i); assert(i == 0x31); } /************************************/ int main() { test1(); test2(); test3(); test4(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testpic.d0000664000175000017500000000070012776215022022021 0ustar kaikai// PERMUTE_ARGS: -fPIC -O extern (C) int printf(const char*, ...); /***************************************************/ align(16) struct S41 { int[4] a; } shared int x41; shared S41 s41; void test11310() { printf("&x = %p\n", &x41); printf("&s = %p\n", &s41); assert((cast(int)&s41 & 0xF) == 0); } /***************************************************/ int main() { test11310(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_contracts.d0000664000175000017500000000040712776215022023174 0ustar kaikai// REQUIRED_ARGS: -gs // The "-gs" flag is just here to test it somewhere in the entire test suite. public alias extern (C) void function(void*) Bar; public interface Test { public void foo(Bar bar) in { assert(bar); } } void main() {} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/inline.d0000664000175000017500000004030012776215022021624 0ustar kaikai import core.stdc.stdio; // Test function inlining debug = NRVO; /************************************/ int foo(int i) { return i; } int bar() { return foo(3) + 4; } void test1() { printf("%d\n", bar()); assert(bar() == 7); } /************************************/ struct Foo2 { int a,b,c,e,f,g; } int foo2(Foo2 f) { f.b += 73; return f.b; } int bar2() { Foo2 gg; gg.b = 6; return foo2(gg) + 4; } void test2() { printf("%d\n", bar2()); assert(bar2() == 83); } /************************************/ struct Foo3 { int bar() { return y + 3; } int y = 4; } void test3() { Foo3 f; assert(f.bar() == 7); } /************************************/ void func(void function () v) { } void test4() { static void f1() { } func(&f1); //func(f1); } /************************************/ void foo5(ubyte[16] array) { bar5(array.ptr); } void bar5(ubyte *array) { } void abc5(ubyte[16] array) { foo5(array); } void test5() { } /************************************/ struct Struct { real foo() { return 0; } void bar(out Struct Q) { if (foo() < 0) Q = this; } } void test6() { } /************************************/ struct S7(T) { immutable(T)[] s; } T foo7(T)(T t) { enum S7!(T)[] i = [{"hello"},{"world"}]; auto x = i[0].s; return t; } void test7() { auto x = foo7('c'); } /************************************/ // 10833 string fun10833(T...)() { foreach (v ; T) return v; assert(0); } void test10833() { auto a = fun10833!("bar")(); } /************************************/ // Bugzilla 4825 int a8() { int r; return r; } int b8() { return a8(); } void test8() { void d() { auto e = b8(); } static const int f = b8(); } /************************************/ // 4841 auto fun4841a() { int i = 42; struct Result { this(int u) {} auto bar() { // refer context of fun4841a return i; } } return Result(); } void test4841a() { auto t = fun4841a(); auto x = t.bar(); assert(x == 42); } auto fun4841b() { int i = 40; auto foo() // hasNestedFrameRefs() == false { // struct Result { this(int u) {} auto bar() { // refer context of fun4841b return i + 2; } } return Result(); } return foo(); } void test4841b() { auto t = fun4841b(); assert(cast(void*)t.tupleof[$-1] !is null); // Result to fun4841b auto x = t.bar(); assert(x == 42); } auto fun4841c() { int i = 40; auto foo() // hasNestedFrameRefs() == true { int g = 2; struct Result { this(int u) {} auto bar() { // refer context of fun4841c and foo return i + g; } } return Result(); } return foo(); } void test4841c() { auto t = fun4841c(); assert( cast(void*)t.tupleof[$-1] !is null); // Result to foo assert(*cast(void**)t.tupleof[$-1] !is null); // foo to fun4841c auto x = t.bar(); assert(x == 42); } void test4841() { test4841a(); test4841b(); test4841c(); } /************************************/ // 7261 struct AbstractTask { ubyte taskStatus; } struct Task { AbstractTask base; alias base this; void opAssign(Task rhs) { } ~this() { if (taskStatus != 3) { } } } /************************************/ // 9356 void test9356() { static inout(char)[] bar (inout(char)[] a) { return a; } string result; result ~= bar("abc"); assert(result == "abc"); } /************************************/ // 12079 void test12079() { string[string][string] foo; foo.get("bar", null).get("baz", null); } /************************************/ // 12243 char f12243() { return 'a'; } void test12243() { string s; s ~= f12243(); } /************************************/ // 11201 struct Foo11201 { int a; float b; Foo11201 func()() const { return this; } } auto f11201()(Foo11201 a) { return a; } void test11201() { auto a = Foo11201(0, 1); assert(f11201(a.func!()()) == a); } /************************************/ // 11223 struct Tuple11223(T...) { T values; void opAssign(Tuple11223 rhs) { if (0) values = rhs.values; else assert(1); } } void test11223() { Tuple11223!string tmp; tmp = Tuple11223!string(); } /************************************/ void foo3918() { import core.stdc.stdlib : alloca; void[] mem = alloca(1024)[0..1024]; } void test3918() { foreach(i; 0 .. 10_000_000) { foo3918(); } } /************************************/ // 11314 struct Tuple11314(T...) { T values; void opAssign(typeof(this) rhs) { if (0) values[] = rhs.values[]; else assert(1); } } struct S11314 {} void test11314() { Tuple11314!S11314 t; t = Tuple11314!S11314(S11314.init); } /************************************/ // 11224 S11224* ptr11224; struct S11224 { this(int) { ptr11224 = &this; /*printf("ctor &this = %p\n", &this);*/ } this(this) { /*printf("cpctor &this = %p\n", &this);*/ } int num; } S11224 foo11224() { S11224 s = S11224(1); //printf("foo &this = %p\n", &s); assert(ptr11224 is &s); return s; } void test11224() { auto s = foo11224(); //printf("main &this = %p\n", &s); assert(ptr11224 is &s); } /************************************/ // 11322 bool b11322; uint n11322; ref uint fun11322() { if (b11322) return n11322; else return n11322; } void test11322() { fun11322()++; assert(n11322 == 1); fun11322() *= 5; assert(n11322 == 5); } /************************************/ // 11394 debug(NRVO) static void* p11394a, p11394b, p11394c; static int[5] make11394(in int x) pure { typeof(return) a; a[0] = x; a[1] = x + 1; a[2] = x + 2; a[3] = x + 3; a[4] = x + 4; debug(NRVO) p11394a = cast(void*)a.ptr; return a; } struct Bar11394 { immutable int[5] arr; this(int x) { this.arr = make11394(x); // NRVO should work debug(NRVO) p11394b = cast(void*)this.arr.ptr; } } void test11394() { auto b = Bar11394(5); debug(NRVO) p11394c = cast(void*)b.arr.ptr; //debug(NRVO) printf("p1 = %p\np2 = %p\np3 = %p\n", p11394a, p11394b, p11394c); debug(NRVO) assert(p11394a == p11394b); debug(NRVO) assert(p11394b == p11394c); } /**********************************/ // 12080 class TZ12080 {} struct ST12080 { ST12080 opBinary()() const pure nothrow { auto retval = ST12080(); return retval; // NRVO } long _stdTime; immutable TZ12080 _timezone; } class Foo12080 { ST12080 bar; bool quux; public ST12080 sysTime() out {} body { if (quux) return ST12080(); return bar.opBinary(); // returned value is set to __result // --> Inliner wrongly created the second DeclarationExp for __result. } } /**********************************/ // 13503 void f13503a(string[] s...) { assert(s[0] == "Cheese"); } auto f13503b(string arg) { string result = arg; return result; } string f13503c(string arg) { string result = arg; return result; } void test13503() { f13503a(f13503b("Cheese")); f13503a(f13503c("Cheese")); } /**********************************/ // 14267 // EXTRA_SOURCES: imports/a14267.d import imports.a14267; void test14267() { foreach (m; __traits(allMembers, SysTime14267)) { static if (is(typeof(__traits(getMember, SysTime14267, m)))) { foreach (func; __traits(getOverloads, SysTime14267, m)) { auto prot = __traits(getProtection, func); static if (__traits(isStaticFunction, func)) { static assert(func.stringof == "min()"); auto result = func; } } } } } /**********************************/ // 13244 struct MapResult13244(alias fun) { int[] input; @property front() { return fun(input[0]); } } int[] array13244(R)(R r) { int[] a; a ~= r.front; return a; } void test13244() { auto arr = [[cast(ubyte)1]]; foreach (ref x; arr) { auto m = MapResult13244!(c => x[c])([0]); array13244(m); } } /**********************************/ // 14306 struct MapResult(alias fun) { void front() { // while (1) { break; } fun(1); } } void bar(R)(R r) { foreach (i; 0..100) { r.front(); } } struct S { int x; int bump() { while (1) { break; } ++x; return x; } } void fun(ref S s) { MapResult!(y => s.bump())().bar; // MapResult!((int x) => s.bump())().bar; if (s.x != 100) assert(0); } void test14306() { S t; fun(t); } /**********************************/ // 14754 auto aafunc14754(string k) { enum aa = [ "K": "V" ]; auto p = k in aa; return null; } struct MapResult14754(alias fun, R) { R _input; @property auto ref front() { return fun(_input[0]); } } auto array14754(R)(R r) { alias E = typeof(r.front); E[] result; result ~= r.front; return result; } auto mapfun14754(R)(R words, string k) { return array14754(MapResult14754!(s => aafunc14754(k), R)(words)); } void test14754() { auto r = mapfun14754([""], ""); } /**********************************/ // 14606 struct S14606 { this(long stdTime) { _stdTime = stdTime; } long _stdTime; } S14606 getS14606() { S14606 sysTime = S14606(0); return sysTime; } struct T14606 { this(string) { uint[3] arr; s = getS14606(); } S14606 s; } void test14606() { auto t = T14606(null); } /**********************************/ // 14753 pragma(inline) void test14753(string) { } /**********************************/ struct S14975 { int bar; pragma(inline, true) this(int bar) { this.bar = bar; } } void test14975() { S14975 baz = 1; if (baz.bar != 1) assert(0); } /**********************************/ // 15210 struct BigInt15210 {} struct Tuple15210(Types...) { Types field; void opAssign(R)(R rhs) { field = rhs.field; } } void test15210() { alias X = Tuple15210!BigInt15210; X[BigInt15210] cache; auto x = X(); cache[BigInt15210()] = x; } /**********************************/ int foo7625(int v) { return bar7625(2 * v); } int bar7625(int a) { ++a; if (a > 0) return 1; return baz(a); } int baz(int a) { if (a > 0) throw new Exception("a > 0"); return a - 1; } void test7625() { int x = foo7625(1); if (x != 1) assert(0); } /**********************************/ // 9785 partial fix void test9785() { int j = 3; void loop(scope const void function(int x) dg) { pragma(inline, true); dg(++j); } loop((x) { pragma(inline, true); printf("%d\n", x); assert(x == 4); }); } /**********************************/ // 9785 partial fix void test9785_2() { int j = 3; void loop(scope const void function(int x) dg) { pragma(inline, true); dg(++j); } static void func(int x) { pragma(inline, true); printf("%d\n", x); assert(x == 4); } loop(&func); } /**********************************/ // 9785 partial fix void test9785_3() @nogc { int j = 3; void loop(scope const void delegate(int x) @nogc dg) @nogc { pragma(inline, true); dg(++j); } loop((x) @nogc { pragma(inline, true); //printf("%d\n", x + j * 2); assert(x == 4); assert(j == 4); }); j = 3; void func(int x) @nogc { pragma(inline, true); //printf("%d\n", x + j * 2); assert(x == 4); assert(j == 4); } loop(&func); } /**********************************/ // 15207 struct Vec15207 { float x, y, z; this(float x_, float y_, float z_) { x = x_; y = y_; z = z_; } Vec15207 clone() { // When the variable 'res' is replaced with a STCref temporary, // this line was accidentally changed to reference initialization. Vec15207 res = this; return res; } } class C15207 { Vec15207 a; this() { a = Vec15207(1, 2, 3).clone(); assert(a.x == 1); assert(a.y == 2); assert(a.z == 3); printf("%f %f %f\n", a.x, a.y, a.z); } } void test15207() { auto c = new C15207(); } /**********************************/ // 15253 struct MessageType15253 { MessageType15253[] messageTypes; const void toString1(scope void delegate(const(char)[]) sink) { messageTypes[0].toString1(sink); } } struct ProtoPackage15253 { MessageType15253[] messageTypes; const void toString1(scope void delegate(const(char)[]) sink) { messageTypes[0].toString1(sink); } } /**********************************/ // 15296 static int x15296; struct S15296 { // Can be expanded only as statements. pragma(inline, true) void bar(size_t , size_t ) { for (size_t w = 0; w < 2; w++) { ++x15296; } } pragma(inline, true) void foo(size_t a, size_t b) { bar(a, b); } } pragma(inline, true) static void voidCall15296() { for (size_t w = 0; w < 3; w++) { ++x15296; } } void test15296() { bool cond = true; S15296 s; // CallExp at the top of ExpStatement x15296 = 0; s.foo(0, 0); assert(x15296 == 2); // CondExp at the top of ExpStatement x15296 = 0; (cond ? s.foo(0, 0) : voidCall15296()); assert(x15296 == 2); (cond ? voidCall15296() : s.foo(0, 0)); assert(x15296 == 2 + 3); // CommaExp at the top of ExpStatement x15296 = 0; (s.foo(0, 0), voidCall15296()); assert(x15296 == 3 + 2); } // ---- struct File15296 { struct Impl {} Impl* _p; pragma(inline, true) ~this() { _p = null; } struct LockingTextWriter { pragma(inline, true) this(ref File15296 f) { assert(f._p, "Attempting to write to closed File"); } } pragma(inline, true) auto lockingTextWriter() { return LockingTextWriter(this); } pragma(inline, true) void write() { auto w = lockingTextWriter(); } //pragma(inline, true) static uint formattedWrite(Writer)(Writer w) { return 0; } pragma(inline, true) void writef() { formattedWrite(lockingTextWriter()); } } __gshared File15296 stdout15296 = {new File15296.Impl()}; pragma(inline, true) @property File15296 trustedStdout15296() { return stdout15296; } // ---- // reduced case from runnable/test34.d test34() void test15296b() { // trustedStdout() returns a temporary File object. Its dtor call // should be deferred till the end of expanded writef body statements. trustedStdout15296().writef(); } // ---- // reduced case from runnable/xtest46.d test136() struct Perm15296c { this(byte[] input) { foreach (elem; input) { // if vthis.isDataseg() is true in expandInline, // its edtor should not be called. stdout15296.write(); } } } void test15296c() { auto perm2 = Perm15296c([0, 1, 2]); } /**********************************/ int main() { test1(); test2(); test3(); test3918(); test4(); test5(); test9356(); test6(); test7(); test8(); test4841(); test11201(); test11223(); test11314(); test11224(); test11322(); test11394(); test13503(); test13244(); test14306(); test14754(); test14606(); test14975(); test15210(); test7625(); test9785(); test9785_2(); test9785_3(); test15207(); test15296(); test15296b(); test15296c(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link11069a.d0000664000175000017500000000033012776215022022044 0ustar kaikai// REQUIRED_ARGS: -noboundscheck // <-- To remove necessity of _D7imports13std11069array7__arrayZ class Bar { import imports.std11069container; BinaryHeap!(Foo[]) Heap; struct Foo {} } void main() {} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/foreach5.d0000664000175000017500000005605312776215022022056 0ustar kaikai extern(C) int printf(const char* fmt, ...); /***************************************/ void test1() { char[] a; int foo() { printf("foo\n"); a ~= "foo"; return 10; } foreach (i; 0 .. foo()) { printf("%d\n", i); a ~= cast(char)('0' + i); } assert(a == "foo0123456789"); foreach_reverse (i; 0 .. foo()) { printf("%d\n", i); a ~= cast(char)('0' + i); } assert(a == "foo0123456789foo9876543210"); } /***************************************/ // 2411 struct S2411 { int n; string s; } void test2411() { S2411 s; assert(s.n == 0); assert(s.s == ""); foreach (i, ref e; s.tupleof) { static if (i == 0) e = 10; static if (i == 1) e = "str"; } assert(s.n == 10); assert(s.s == "str"); } /***************************************/ // 2442 template canForeach(T, E) { enum canForeach = __traits(compiles, { foreach(a; new T) { static assert(is(typeof(a) == E)); } }); } void test2442() { struct S1 { int opApply(int delegate(ref const(int) v) dg) const { return 0; } int opApply(int delegate(ref int v) dg) { return 0; } } S1 ms1; const S1 cs1; foreach (x; ms1) { static assert(is(typeof(x) == int)); } foreach (x; cs1) { static assert(is(typeof(x) == const int)); } struct S2 { int opApply(int delegate(ref int v) dg) { return 0; } int opApply(int delegate(ref long v) dg) { return 0; } } S2 ms2; static assert(!__traits(compiles, { foreach ( x; ms2) {} })); // ambiguous static assert( __traits(compiles, { foreach (int x; ms2) {} })); struct S3 { int opApply(int delegate(ref int v) dg) const { return 0; } int opApply(int delegate(ref int v) dg) shared const { return 0; } } immutable S3 ms3; static assert(!__traits(compiles, { foreach (int x; ms3) {} })); // ambiguous // from https://github.com/D-Programming-Language/dmd/pull/120 static class C { int opApply(int delegate(ref int v) dg) { return 0; } int opApply(int delegate(ref const int v) dg) const { return 0; } int opApply(int delegate(ref immutable int v) dg) immutable { return 0; } int opApply(int delegate(ref shared int v) dg) shared { return 0; } int opApply(int delegate(ref shared const int v) dg) shared const { return 0; } } static class D { int opApply(int delegate(ref int v) dg) const { return 0; } } static class E { int opApply(int delegate(ref int v) dg) shared const { return 0; } } static assert( canForeach!( C , int )); static assert( canForeach!( const(C) , const(int) )); static assert( canForeach!( immutable(C) , immutable(int) )); static assert( canForeach!( shared(C) , shared(int) )); static assert( canForeach!(shared(const(C)), shared(const(int)))); static assert( canForeach!( D , int)); static assert( canForeach!( const(D) , int)); static assert( canForeach!( immutable(D) , int)); static assert(!canForeach!( shared(D) , int)); static assert(!canForeach!(shared(const(D)), int)); static assert(!canForeach!( E , int)); static assert(!canForeach!( const(E) , int)); static assert( canForeach!( immutable(E) , int)); static assert( canForeach!( shared(E) , int)); static assert( canForeach!(shared(const(E)), int)); } /***************************************/ // 2443 struct S2443 { int[] arr; int opApply(int delegate(size_t i, ref int v) dg) { int result = 0; foreach (i, ref x; arr) { if ((result = dg(i, x)) != 0) break; } return result; } } void test2443() { S2443 s; foreach (i, ref v; s) {} foreach (i, v; s) {} static assert(!__traits(compiles, { foreach (ref i, ref v; s) {} })); static assert(!__traits(compiles, { foreach (ref i, v; s) {} })); } /***************************************/ // 3187 class Collection { int opApply(int delegate(ref Object) a) { return 0; } } Object testForeach(Collection level1, Collection level2) { foreach (first; level1) { foreach (second; level2) return second; } return null; } void test3187() { testForeach(new Collection, new Collection); } /***************************************/ // 4090 void test4090a() { double[10] arr = 1; double tot = 0; static assert(!__traits(compiles, { foreach (immutable ref x; arr) {} })); foreach (const ref x; arr) { static assert(is(typeof(x) == const double)); tot += x; } foreach (immutable x; arr) { static assert(is(typeof(x) == immutable double)); tot += x; } assert(tot == 1*10 + 1*10); } void test4090b() { int tot = 0; static assert(!__traits(compiles, { foreach (immutable ref x; 1..11) {} })); foreach (const ref x; 1..11) { static assert(is(typeof(x) == const int)); tot += x; } foreach (immutable x; 1..11) { static assert(is(typeof(x) == immutable int)); tot += x; } assert(tot == 55 + 55); } /***************************************/ // 5605 struct MyRange { int theOnlyOne; @property bool empty() const { return true; } @property ref int front() { return theOnlyOne; } void popFront() {} } struct MyCollection { MyRange opSlice() const { return MyRange(); } } void test5605() { auto coll = MyCollection(); foreach (i; coll) { // <-- compilation error // ... } } /***************************************/ // 7004 void func7004(A...)(A args) { foreach (i, e; args){} // OK foreach (uint i, e; args){} // OK foreach (size_t i, e; args){} // NG } void test7004() { func7004(1, 3.14); } /***************************************/ // 7406 template TypeTuple7406(T...) { alias T TypeTuple7406; } template foobar7406(T) { enum foobar = 2; } void test7406() { foreach (sym; TypeTuple7406!(int, double)) // OK pragma(msg, sym.stringof); foreach (sym; TypeTuple7406!(foobar7406)) // OK pragma(msg, sym.stringof); foreach (sym; TypeTuple7406!(test7406)) // OK pragma(msg, sym.stringof); foreach (sym; TypeTuple7406!(int, foobar7406)) // Error: type int has no value pragma(msg, sym.stringof); foreach (sym; TypeTuple7406!(int, test7406)) // Error: type int has no value pragma(msg, sym.stringof); } /***************************************/ // 6659 void test6659() { static struct Iter { ~this() { ++_dtor; } bool opCmp(ref const Iter rhs) { return _pos == rhs._pos; } void opUnary(string op:"++")() { ++_pos; } size_t _pos; static size_t _dtor; } foreach (ref iter; Iter(0) .. Iter(10)) { assert(Iter._dtor == 0); } assert(Iter._dtor == 2); Iter._dtor = 0; // reset for (auto iter = Iter(0), limit = Iter(10); iter != limit; ++iter) { assert(Iter._dtor == 0); } assert(Iter._dtor == 2); } void test6659a() { auto value = 0; try { for ({scope(success) { assert(value == 1); value = 2;} } true; ) { value = 1; break; } assert(value == 2); } catch (Exception e) { assert(0); } assert(value == 2); } void test6659b() { auto value = 0; try { for ({scope(failure) value = 1;} true; ) { throw new Exception(""); } assert(0); } catch (Exception e) { assert(e); } assert(value == 1); } void test6659c() { auto value = 0; try { for ({scope(exit) value = 1;} true; ) { throw new Exception(""); } assert(0); } catch (Exception e) { assert(e); } assert(value == 1); } /***************************************/ // 10221 void test10221() { // All of these should work, but most are too slow. Just check they compile. foreach(char i; char.min..char.max+1) {} if (0) foreach(wchar i; wchar.min..wchar.max+1) {} if (0) foreach(dchar i; dchar.min..dchar.max+1) {} foreach(byte i; byte.min..byte.max+1) {} foreach(ubyte i; ubyte.min..ubyte.max+1) {} if (0) foreach(short i; short.min..short.max+1) {} if (0) foreach(ushort i; ushort.min..ushort.max+1) {} if (0) foreach(int i; int.min..int.max+1U) {} if (0) foreach(uint i; uint.min..uint.max+1L) {} if (0) foreach(long i; long.min..long.max+1UL) {} foreach_reverse(char i; char.min..char.max+1) { assert(i == typeof(i).max); break; } foreach_reverse(wchar i; wchar.min..wchar.max+1) { assert(i == typeof(i).max); break; } foreach_reverse(dchar i; dchar.min..dchar.max+1) { assert(i == typeof(i).max); break; } foreach_reverse(byte i; byte.min..byte.max+1) { assert(i == typeof(i).max); break; } foreach_reverse(ubyte i; ubyte.min..ubyte.max+1) { assert(i == typeof(i).max); break; } foreach_reverse(short i; short.min..short.max+1) { assert(i == typeof(i).max); break; } foreach_reverse(ushort i; ushort.min..ushort.max+1) { assert(i == typeof(i).max); break; } foreach_reverse(int i; int.min..int.max+1U) { assert(i == typeof(i).max); break; } foreach_reverse(uint i; uint.min..uint.max+1L) { assert(i == typeof(i).max); break; } foreach_reverse(long i; long.min..long.max+1UL) { assert(i == typeof(i).max); break; } } /***************************************/ // 7814 struct File7814 { ~this(){} } struct ByLine7814 { File7814 file; // foreach interface @property bool empty() const { return true; } @property char[] front() { return null; } void popFront(){} } void test7814() { int dummy; ByLine7814 f; foreach (l; f) { scope(failure) // 'failure' or 'success' fails, but 'exit' works dummy = -1; dummy = 0; } } /***************************************/ // 10049 struct ByLine10049 { bool empty() { return true; } string front() { return null; } void popFront() {} ~this() {} // necessary } void test10049() { ByLine10049 r; foreach (line; r) { doNext: {} } } /******************************************/ struct T11955(T...) { T field; alias field this; } alias X11955 = uint; struct S11955 { enum empty = false; T11955!(uint, uint) front; void popFront() {} } void test11955() { foreach(X11955 i, v; S11955()) {} } /******************************************/ // 6652 void test6652() { size_t sum; foreach (i; 0 .. 10) sum += i++; // 0123456789 assert(sum == 45); sum = 0; foreach (ref i; 0 .. 10) sum += i++; // 02468 assert(sum == 20); sum = 0; foreach_reverse (i; 0 .. 10) sum += i--; // 9876543210 assert(sum == 45); sum = 0; foreach_reverse (ref i; 0 .. 10) sum += i--; // 97531 assert(sum == 25); enum ary = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; sum = 0; foreach (i, v; ary) { assert(i == v); sum += i++; // 0123456789 } assert(sum == 45); sum = 0; foreach (ref i, v; ary) { assert(i == v); sum += i++; // 02468 } assert(sum == 20); sum = 0; foreach_reverse (i, v; ary) { assert(i == v); sum += i--; // 9876543210 } assert(sum == 45); sum = 0; foreach_reverse (ref i, v; ary) { assert(i == v); sum += i--; // 97531 } assert(sum == 25); static struct Iter { ~this() { ++_dtorCount; } bool opCmp(ref const Iter rhs) { return _pos == rhs._pos; } void opUnary(string op)() if(op == "++" || op == "--") { mixin(op ~ q{_pos;}); } size_t _pos; static size_t _dtorCount; } Iter._dtorCount = sum = 0; foreach (v; Iter(0) .. Iter(10)) sum += v._pos++; // 0123456789 assert(sum == 45 && Iter._dtorCount == 12); Iter._dtorCount = sum = 0; foreach (ref v; Iter(0) .. Iter(10)) sum += v._pos++; // 02468 assert(sum == 20 && Iter._dtorCount == 2); // additional dtor calls due to unnecessary postdecrements Iter._dtorCount = sum = 0; foreach_reverse (v; Iter(0) .. Iter(10)) sum += v._pos--; // 9876543210 assert(sum == 45 && Iter._dtorCount >= 12); Iter._dtorCount = sum = 0; foreach_reverse (ref v; Iter(0) .. Iter(10)) sum += v._pos--; // 97531 assert(sum == 25 && Iter._dtorCount >= 2); } /***************************************/ // 8595 struct OpApply8595 { int opApply(int delegate(ref int) dg) { assert(0); } } string test8595() { foreach (elem; OpApply8595.init) { static assert(is(typeof(return) == string)); } assert(0); } /***************************************/ // 9068 struct Foo9068 { static int[] destroyed; int x; ~this() { destroyed ~= x; } } struct SimpleCounter9068 { static int destroyedCount; enum int limit = 5; int counter; ~this() { destroyedCount++; } // Range primitives. @property bool empty() const { return counter >= limit; } @property int front() { return counter; } void popFront() { counter++; } } void test9068() { //---------------------------------------- // There was never a bug in this case (no range). int sum; loop_simple: foreach (i; [10, 20]) { sum += i; break loop_simple; } assert(sum == 10); //---------------------------------------- // There was a bug with loops over ranges. int last = -1; X: foreach (i; SimpleCounter9068()) { switch(i) { case 3: break X; default: last = i; } } assert(last == 2); assert(SimpleCounter9068.destroyedCount == 1); //---------------------------------------- // Simpler case: the compiler error had nothing to do with the switch. last = -1; loop_with_range: foreach (i; SimpleCounter9068()) { last = i; break loop_with_range; } assert(last == 0); assert(SimpleCounter9068.destroyedCount == 2); //---------------------------------------- // Test with destructors: the loop is implicitly wrapped into two // try/finally clauses. loop_with_dtors: for (auto x = Foo9068(4), y = Foo9068(5); x.x != 10; ++x.x) { if (x.x == 8) break loop_with_dtors; } assert(Foo9068.destroyed == [5, 8]); Foo9068.destroyed = null; //---------------------------------------- // Same with an unlabelled break. for (auto x = Foo9068(4), y = Foo9068(5); x.x != 10; ++x.x) { if (x.x == 7) break; } assert(Foo9068.destroyed == [5, 7]); Foo9068.destroyed = null; } /***************************************/ // 11885 struct Foo11885 { static int[] destroyed; int x; ~this() { destroyed ~= x; } } struct SimpleCounter11885 { static int destroyedCount; enum int limit = 5; int counter; ~this() { destroyedCount++; } // Range primitives. @property bool empty() const { return counter >= limit; } @property int front() { return counter; } void popFront() { counter++; } } void test11885() { //---------------------------------------- // There was never a bug in this case (no range). int sum; loop_simple: foreach (i; [10, 20]) { sum += i; continue loop_simple; } assert(sum == 30); //---------------------------------------- // There was a bug with loops over ranges. int last = -1; X: foreach (i; SimpleCounter11885()) { switch(i) { case 3: continue X; default: last = i; } } assert(last == 4); assert(SimpleCounter11885.destroyedCount == 1); //---------------------------------------- // Simpler case: the compiler error had nothing to do with the switch. last = -1; loop_with_range: foreach (i; SimpleCounter11885()) { last = i; continue loop_with_range; } assert(last == 4); assert(SimpleCounter11885.destroyedCount == 2); //---------------------------------------- // Test with destructors: the loop is implicitly wrapped into two // try/finally clauses. loop_with_dtors: for (auto x = Foo11885(4), y = Foo11885(5); x.x != 10; ++x.x) { if (x.x == 8) continue loop_with_dtors; } assert(Foo11885.destroyed == [5, 10]); Foo11885.destroyed = null; //---------------------------------------- // Same with an unlabelled continue. for (auto x = Foo11885(4), y = Foo11885(5); x.x != 10; ++x.x) { if (x.x == 7) continue; } assert(Foo11885.destroyed == [5, 10]); Foo11885.destroyed = null; } /***************************************/ // 10475 void test10475a() { struct DirIterator { int _store = 42; ~this() { assert(0); } } DirIterator dirEntries() { throw new Exception(""); } try { for (DirIterator c = dirEntries(); true; ) {} assert(0); } catch (Exception e) { assert(e.next is null); } } void test10475b() { uint g; struct S { uint flag; ~this() { g |= flag; } } S thrown() { throw new Exception(""); } g = 0x0; try { for (auto x = S(0x1), y = S(0x2), z = thrown(); true; ) {} assert(0); } catch (Exception e) { assert(e.next is null); } assert(g == 0x3); g = 0x0; try { for (auto x = S(0x1), y = thrown(), z = S(0x2); true; ) {} assert(0); } catch (Exception e) { assert(e.next is null); } assert(g == 0x1); g = 0x0; try { for (auto x = thrown(), y = S(0x1), z = S(0x2); true; ) {} assert(0); } catch (Exception e) { assert(e.next is null); } assert(g == 0x0); } /***************************************/ // 11291 void test11291() { struct Tuple(T...) { T field; alias field this; } struct zip { string[] s1, s2; bool empty() { return true; } auto front() { return Tuple!(string, string)(s1[0], s2[0]); } void popFront() {} } foreach (const a, const b; zip(["foo"], ["bar"])) { static assert(is(typeof(a) == const string)); static assert(is(typeof(b) == const string)); static assert(!__traits(compiles, a = "something")); static assert(!__traits(compiles, b = "something")); } } /***************************************/ // 12103 alias TypeTuple12103(TL...) = TL; alias Id12103(alias a) = a; void test12103() { alias fs1 = TypeTuple12103!(() => 0, () => 1); foreach (i, f; fs1) { static assert(f() == i); static assert(Id12103!f() == i); assert(f() == i); assert(Id12103!f() == i); } alias fs2 = TypeTuple12103!(x=>x+0, y=>y+1); foreach (i, f; fs2) { static assert(f(0) == i); static assert(Id12103!f(0) == i); assert(f(0) == i); assert(Id12103!f(0) == i); } } /***************************************/ // 12739 struct S12739 { nothrow: int opApply(int delegate(ref int) nothrow dg) { return 0; } } void test12739() nothrow { S12739 s; foreach (e; s) {} } /***************************************/ // 12932 void test12932() @nogc { int sum; foreach (e; [1,2,3]) { sum += e; } assert(sum == 6); } /***************************************/ // 13756 void test13756() { printf("test13756()\n"); int[int] org = [1:2], aa; aa = org.dup; foreach (v; aa) { static assert(is(typeof(v) == int)); v = 20; } assert(aa == [1:2]); aa = org.dup; foreach (ref v; aa) { static assert(is(typeof(v) == int)); v = 20; } assert(aa == [1:20]); aa = org.dup; foreach (k, v; aa) { static assert(is(typeof(k) == int)); static assert(is(typeof(v) == int)); k = 10; v = 20; } assert(aa == [1:2]); aa = org.dup; foreach (k, ref v; aa) { static assert(is(typeof(k) == int)); static assert(is(typeof(v) == int)); k = 10; v = 20; } assert(aa == [1:20]); aa = org.dup; foreach (ref k, v; aa) // NG -> OK { static assert(is(typeof(k) == const int)); static assert(is(typeof(v) == int)); static assert(!__traits(compiles, k = 10)); v = 20; } assert(aa == [1:2]); aa = org.dup; foreach (ref k, ref v; aa) // NG -> OK { static assert(is(typeof(k) == const int)); static assert(is(typeof(v) == int)); static assert(!__traits(compiles, k = 10)); v = 20; } assert(aa == [1:20]); foreach (ref const k, v; aa) // NG -> OK, same with 'ref k' { static assert(is(typeof(k) == const int)); } } /***************************************/ // 14653 static string result14653; class RangeClass14653 { int a; this(T)(T...) { result14653 ~= "c"; } ~this() { result14653 ~= "d"; a = -1; } @property bool empty() { result14653 ~= "e"; return a >= 2; } @property int front() { result14653 ~= "f"; assert(a >= 0); return a; } void popFront() { result14653 ~= "p"; ++a; } } auto scoped14653(T, A...)(A args) { static struct Scoped(T) { void[__traits(classInstanceSize, T)] store; T payload() { return cast(T)cast(void*)store.ptr; } alias payload this; ~this() { //.destroy(payload); payload.__dtor(); (cast(byte[])store)[] = 0; } } Scoped!T result = void; //emplace!T(result.store[], args); result.store[] = typeid(T).init[]; result.payload.__ctor(args); return result; } void test14653() { printf("test14653()\n"); foreach (e; scoped14653!RangeClass14653(1)) { result14653 ~= "b"; } assert(result14653 == "cefbpefbped", result14653); } /***************************************/ int main() { test1(); test2411(); test2442(); test2443(); test3187(); test4090a(); test4090b(); test5605(); test7004(); test10221(); test7406(); test6659(); test6659a(); test6659b(); test6659c(); test7814(); test6652(); test9068(); test11885(); test10475a(); test10475b(); test11291(); test12103(); test12739(); printf("test12932()\n"); test12932(); test13756(); test14653(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/linktypeinfo.d0000664000175000017500000000076412776215022023073 0ustar kaikai// EXTRA_SOURCES: imports/linktypeinfo_file.d // PERMUTE_ARGS: -g -inline -unittest -debug // COMPILE_SEPARATELY import imports.linktypeinfo_file; struct Only(T) { private T _val; } auto only(V)(V v) { return Only!V(v); } static struct Chain(R...) { R source; } auto chain(R...)(R rs) { return Chain!R(rs); } void main() { string docRoot; const r = dirEntries(docRoot); typeof(r)[] a; a.length = 0; // require TypeInfo for const(FilterResult!(DirIterator)) } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link8023.d0000664000175000017500000000034412776215022021624 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/link8023b.d // PERMUTE_ARGS: -inline -release import imports.link8023b; private void t(alias Code)() { return Code(); } void f() { t!( () { } )(); } void main() { f(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/bitops.d0000664000175000017500000000615312776215022021656 0ustar kaikai// PERMUTE_ARGS: import core.stdc.stdio; import core.bitop; /*****************************************************/ void test1() { size_t array[2]; uint x; version (D_LP64) size_t bitToUse = 67; else size_t bitToUse = 35; array[0] = 2; array[1] = 0x100; printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); x = btc(array.ptr, bitToUse); printf("btc(array, %d) = %d\n", bitToUse, x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x == 0); assert(array[0] == 0x2 && array[1] == 0x108); x = btc(array.ptr, bitToUse); printf("btc(array, %d) = %d\n", bitToUse, x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x != 0); assert(array[0] == 2 && array[1] == 0x100); x = bts(array.ptr, bitToUse); printf("bts(array, %d) = %d\n", bitToUse, x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x == 0); assert(array[0] == 2 && array[1] == 0x108); x = btr(array.ptr, bitToUse); printf("btr(array, %d) = %d\n", bitToUse, x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x != 0); assert(array[0] == 2 && array[1] == 0x100); x = bt(array.ptr, 1); printf("bt(array, 1) = %d\n", x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x != 0); assert(array[0] == 2 && array[1] == 0x100); } /*****************************************************/ void test2() { uint v; int x; v = 0x21; x = bsf(v); printf("bsf(x%x) = %d\n", v, x); assert(x == 0); x = bsr(v); printf("bsr(x%x) = %d\n", v, x); assert(x == 5); } /*****************************************************/ void test3() { uint v; int b; b = inp(b); b = inpw(b); b = inpl(b); b = outp(v, cast(ubyte)b); b = outpw(v, cast(ushort)b); b = outpl(v, b); } /*****************************************************/ void test4() { uint i = 0x12_34_56_78; i = bswap(i); assert(i == 0x78_56_34_12); } /*****************************************************/ void test5() { size_t array[2]; array[0] = 2; array[1] = 0x100; printf("btc(array, 35) = %d\n", btc(array.ptr, 35)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); printf("btc(array, 35) = %d\n", btc(array.ptr, 35)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); printf("bts(array, 35) = %d\n", bts(array.ptr, 35)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); printf("btr(array, 35) = %d\n", btr(array.ptr, 35)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); printf("bt(array, 1) = %d\n", bt(array.ptr, 1)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); } /*****************************************************/ class Node { uint leaf = 0; int m() { return leaf ? 0 : bsf(leaf); } } void test6() { Node n = new Node(); } /*****************************************************/ int main() { test1(); test2(); //test3(); test4(); test5(); test6(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test36.d0000664000175000017500000000174312776215022021506 0ustar kaikai// PERMUTE_ARGS: import std.stdio; interface IUnknown{ extern(Windows): void func(); } class ComObject :IUnknown { extern (Windows): void func() {writefln(`comobject`); } } interface IDataObject: IUnknown { extern(Windows): void method(); } package class invarianttest:ComObject, IDataObject { invariant() { writefln(`hello invariant`); } extern (Windows): override void func() { int esp; asm{ mov esp,ESP; } printf("\n%d",esp); printf(`func`); } void method() { writefln(`method`); } } int main() { auto inst= new invarianttest; int esp; asm{ mov esp,ESP; } inst.func(); inst.method(); writefln("\n%d",esp); asm{ mov esp,ESP; } writefln("\n%d",esp); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test9495.d0000664000175000017500000000061712776215022021667 0ustar kaikai// PERMUTE_ARGS: import core.vararg; int func1(int a, ...) { auto result = va_arg!int(_argptr); return result; } void test9495a() { assert(func1(5, 12345678) == 12345678); } int func2(const(char)[] a, ...) { auto result = va_arg!int(_argptr); return result; } void test9495b() { assert(func2("5", 12345678) == 12345678); } void main(string[] args) { test9495a(); test9495b(); }ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/template13478.d0000664000175000017500000000034712776215022022577 0ustar kaikai/// Tests emission of templates also referenced in speculative contexts. /// Failure triggered with -inline. module template13478; import imports.template13478a; import imports.template13478b; int main() { return foo!int(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link10425.d0000664000175000017500000000151312776215022021702 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/bug10425.d import imports.bug10425; void main() { auto ti = typeid(A!()); /* Today, taking TypeInfo object address by using `typeid` always generates * the TypeInfo object on comdat section (done by TypeInfoDeclaration::toObjFile), * even if the associated struct belongs *non-root modules*. * * And, from 2.062, issue 7511 is implemented. * The attribute inference for member functions in instantiated struct may modify * their actual mangled names. Then TypeInfo object compiled in this module would * use wrong symbol names, to link non-template opEquals/opCmp/toHash/toString * member functions. * * To fix the issue, we should run semantic3 to calculate the correct symbol names * of the specific member functions. */ } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link11395.d0000664000175000017500000000025712776215022021715 0ustar kaikai// EXTRA_SOURCES: imports/link11395a.d // PERMUTE_ARGS: // COMPILE_SEPARATELY module link11395; import imports.link11395a; void main() { SB s; SB[] a; a ~= s; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/warning1.d0000664000175000017500000000534512776215022022106 0ustar kaikai// REQUIRED_ARGS: -w // PERMUTE_ARGS: extern(C) int printf(const char*, ...); /******************************************/ class F { } int foo() { scope F f = new F(); // comment out and warning goes away return 0; } /******************************************/ int foo2() { try { return 0; } finally { } } /******************************************/ private int getNthInt(A...)(uint index, A args) { foreach (i, arg; args) { static if (is(typeof(arg) : long) || is(typeof(arg) : ulong)) { if (i != index) continue; return cast(int)(arg); } else { if (i == index) break; } } throw new Error("int expected"); } /******************************************/ class Foo2 { int foo() { synchronized(this){ return 8; } } } /******************************************/ void mainX() { int i=0; printf("This number is zero: "); goto inloop; for(; i<10; i++) { // this is line 7 printf("This number is nonzero: "); inloop: printf("%d\n", i); } } /******************************************/ string foo3(int bar) { switch (bar) { case 1: return "1"; case 2: return "2"; default: return "3"; } } /******************************************/ int foo4() { int i; for (;; ++i) { if (i == 10) return 0; } } /******************************************/ int foo5() { do { if (false) return 1; } while (true); } /******************************************/ nothrow int foo6() { int x = 2; try { } catch(Exception e) { x = 4; throw new Exception("xxx"); } return x; } /******************************************/ // 6518 template TypeTuple(T...) { alias T TypeTuple; } void test6518() { switch(2) { foreach(v; TypeTuple!(1, 2, 3)) case v: break; default: assert(0); } } /******************************************/ // 7232 bool test7232() { scope(failure) return false; return true; } /***************************************************/ struct S9332 { this(S9332) { // while (1) { } assert(0, "unreachable?"); } } /******************************************/ // 13201 class C13201 { void foo() { synchronized(this) { assert(0); } } } void test13201a() { auto c = new C13201(); synchronized(c) { assert(0); } } void test13201b() { struct S { ~this() {} } S s; assert(0); } /******************************************/ void main() { } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test11447c.d0000664000175000017500000000033012776215022022070 0ustar kaikai// COMPILE_SEPARATELY // EXTRA_SOURCES: imports/c11447.d // PERMUTE_ARGS: -allinst -w -debug -g import imports.c11447; void main() { auto a = new A(); TemplateInstancier().instanciateFromResolvedArgs(a); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test41.d0000664000175000017500000000052212776215022021474 0ustar kaikai// EXTRA_SOURCES: imports/test41a.d // PERMUTE_ARGS: -inline -g -O import imports.test41a; import core.exception; int main() { try { foo(); return 1; } catch (AssertError e) { } try { func!(void)(); return 1; } catch (AssertError e) { } return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ice10086a.d0000664000175000017500000000023212776215022021646 0ustar kaikai// EXTRA_SOURCES: imports/ice10086x.d // EXTRA_SOURCES: imports/ice10086y.d import imports.ice10086x; import imports.ice10086y; void main() { test(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test13504.d0000664000175000017500000000016612776215022021730 0ustar kaikai// REQUIRED_ARGS: -O -cov bool func(T)() { return true; } void main() { assert(func!int() || int.sizeof); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/template8.d0000664000175000017500000000664712776215022022271 0ustar kaikai// NOTE: comes from std.bitmanip // PERMUTE_ARGS: private string myToString(ulong n) { return n < 10 ? "" ~ cast(char) (n + '0') : myToString(n / 10) ~ myToString(n % 10); } private string toStringSfx(ulong n) { return myToString(n) ~ (n > uint.max ? "UL" : "U"); } private string CreateAccessors( string store, T, string name, size_t len, size_t offset)() { static if (!name.length) { // No need to create any accessor return ""; } else { static const maskAllElse = ((1uL << len) - 1u) << offset, maskMyself = ~maskAllElse, signBitCheck = 1uL << (len - 1), extendSign = ~((1uL << len) - 1); string result; static if (is(T == bool)) { static assert(len == 1); // getter result ~= "bool " ~ name ~ "(){ return " "("~store~" & "~toStringSfx(maskAllElse)~") != 0;}"; // setter result ~= "void " ~ name ~ "(bool v){" "if (v) "~store~" |= "~toStringSfx(maskAllElse)~";" "else "~store~" &= "~toStringSfx(maskMyself)~";}"; } else { // getter result ~= T.stringof ~ " " ~ name ~ "(){ auto result = " "("~store~" & " ~ toStringSfx(maskAllElse) ~ ") >>" ~ toStringSfx(offset) ~ ";"; static if (T.min < 0) { result ~= "if (result >= " ~ toStringSfx(signBitCheck) ~ ") result |= " ~ toStringSfx(extendSign) ~ ";"; } result ~= " return cast(" ~ T.stringof ~ ") result;}"; // setter result ~= "void " ~ name ~ "(" ~ T.stringof ~ " v){ "~store~" = ("~store~" & " ~ toStringSfx(maskMyself) ~ ") | " ~ "((cast(typeof("~store~")) v << " ~ toStringSfx(offset) ~ ") & " ~ toStringSfx(maskAllElse) ~ ");}"; } return result; } } private string createStoreName(Ts...)() { static if (Ts.length == 0) return ""; else return Ts[1] ~ createStoreName!(Ts[3 .. $])(); } private string CreateFields(string store, size_t offset, Ts...)() { static if (!Ts.length) { static if (offset == ubyte.sizeof * 8) return "private ubyte " ~ store ~ ";"; else static if (offset == ushort.sizeof * 8) return "private ushort " ~ store ~ ";"; else static if (offset == uint.sizeof * 8) return "private uint " ~ store ~ ";"; else static if (offset == ulong.sizeof * 8) return "private ulong " ~ store ~ ";"; else static assert(false, ToString!(offset)); } else { return CreateAccessors!(store, Ts[0], Ts[1], Ts[2], offset)() ~ CreateFields!(store, offset + Ts[2], Ts[3 .. $])(); } } template BitFields(T...) { //pragma(msg, CreateFields!(createStoreName!(T)(), 0, T)()); mixin(CreateFields!(createStoreName!(T)(), 0, T)()); } struct FloatRep { mixin BitFields!( uint, "fraction", 23, uint, "exponent", 8, bool, "sign", 1); } struct DoubleRep { mixin BitFields!( ulong, "fraction", 52, uint, "exponent", 11, bool, "sign", 1); } struct Bug2355(string x) {} static assert(is(Bug2355!"a" U : Bug2355!V, string V)); int main() { return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link14992.d0000664000175000017500000000046712776215022021726 0ustar kaikaiimport imports.a14992; // do not link int test() { S1 v1; // OK S1* p1; // OK S1[] da1; // OK S1[2] a1; // OK <- NG S2 v2; // OK S2* p2; // OK S2[] da2; // OK S2[2] a2; // OK <- NG return 1; } static assert(test()); void main() { test(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testargtypes.d0000664000175000017500000000404112776215022023106 0ustar kaikai void chkArgTypes(S, V...)() { pragma(msg, S); static if (is(S U == __argTypes)) { foreach (T; U) { pragma(msg, T); } static assert(U.length == V.length); foreach (i, T; U) static assert(is(V[i] == T)); } else static assert(0); } void chkSingle(T,U)() { struct S { T a; } chkArgTypes!(S, U)(); } void chkIdentity(T)() { chkSingle!(T,T)(); } void chkPair(T,U,V)() { struct S { T a; U b; } chkArgTypes!(S, V)(); } version (X86_64) { int main() { chkIdentity!byte(); chkIdentity!ubyte(); chkIdentity!short(); chkIdentity!ushort(); chkIdentity!int(); chkIdentity!uint(); chkIdentity!long(); chkIdentity!ulong(); chkSingle!(char,ubyte)(); chkSingle!(wchar,ushort)(); chkSingle!(dchar,uint)(); chkIdentity!float(); chkIdentity!double(); chkIdentity!real(); chkIdentity!(void*)(); chkIdentity!(__vector(byte[16]))(); chkIdentity!(__vector(ubyte[16]))(); chkIdentity!(__vector(short[8]))(); chkIdentity!(__vector(ushort[8]))(); chkIdentity!(__vector(int[4]))(); chkIdentity!(__vector(uint[4]))(); chkIdentity!(__vector(long[2]))(); chkIdentity!(__vector(ulong[2]))(); chkIdentity!(__vector(float[4]))(); chkIdentity!(__vector(double[2]))(); chkPair!(byte,byte,short); chkPair!(ubyte,ubyte,short); chkPair!(short,short,int); chkPair!(int,int,long); chkPair!(byte,short,int); chkPair!(short,byte,int); chkPair!(int,float,long); chkPair!(float,int,long); chkPair!(byte,float,long); chkPair!(float,short,long); //struct S1 { long a; long b; } //chkArgTypes!(S1, long, long)(); struct S2 { union { long a; double d; }} chkArgTypes!(S2, long)(); struct S3 { union { double d; long a; }} chkArgTypes!(S3, long)(); struct S4 { int a,b,c,d,e; } chkArgTypes!(S4)(); struct S5 { align(1): char a; int b; } chkArgTypes!(S5)(); struct S6 { align(1): int a; void* b; } chkArgTypes!(S5)(); struct S7 { union { void* p; real r; }} chkArgTypes!(S7)(); struct S8 { union { real r; void* p; }} chkArgTypes!(S8)(); return 0; } } else { int main() { return 0; } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_1101.d0000664000175000017500000000016112776215022023115 0ustar kaikaistruct Foo { Foo[] bar = []; this(const int x) {} } void main() { Foo f; assert(f.bar.length == 0); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/iasm64.d0000664000175000017500000061704112776215022021465 0ustar kaikai// PERMUTE_ARGS: // Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com import core.stdc.stdio; version (D_PIC) { int main() { return 0; } } else version (D_InlineAsm_X86_64) { struct M128 { int a,b,c,d; }; struct M64 { int a,b; }; /+ __gshared byte b; __gshared short w; __gshared int i; __gshared long l; +/ /****************************************************/ void test1() { int foo; int bar; static const int x = 4; asm { align x; ; mov EAX, __LOCAL_SIZE ; mov foo[RBP], EAX ; } assert(foo == 16); // stack must be 16 byte aligned } /****************************************************/ void test2() { int foo; int bar; asm { even ; mov EAX,0 ; inc EAX ; mov foo[RBP], EAX ; } assert(foo == 1); } /****************************************************/ void test3() { int foo; int bar; asm { mov EAX,5 ; jmp $ + 2 ; dw 0xC0FF,0xC8FF ; // inc EAX, dec EAX mov foo[RBP],EAX ; } assert(foo == 4); } /****************************************************/ void test4() { int foo; int bar; asm { xor EAX,EAX ; add EAX,5 ; jne L1 ; dw 0xC0FF,0xC8FF ; // inc EAX, dec EAX L1: dw 0xC8FF ; mov foo[RBP],EAX ; } assert(foo == 4); } /****************************************************/ void test5() { int foo; ubyte *p; ushort *w; uint *u; ulong *ul; float *f; double *d; real *e; static float fs = 1.1; static double ds = 1.2; static real es = 1.3; asm { call L1 ; db 0xFF,0xC0; ; // inc EAX db "abc" ; ds "def" ; di "ghi" ; dl 0x12345678ABCDEF; df 1.1 ; dd 1.2 ; de 1.3 ; L1: pop RBX ; mov p[RBP],RBX ; } assert(p[0] == 0xFF); assert(p[1] == 0xC0); assert(p[2] == 'a'); assert(p[3] == 'b'); assert(p[4] == 'c'); w = cast(ushort *)(p + 5); assert(w[0] == 'd'); assert(w[1] == 'e'); assert(w[2] == 'f'); u = cast(uint *)(w + 3); assert(u[0] == 'g'); assert(u[1] == 'h'); assert(u[2] == 'i'); ul = cast(ulong *)(u + 3); assert(ul[0] == 0x12345678ABCDEF); f = cast(float *)(ul + 1); assert(*f == fs); d = cast(double *)(f + 1); assert(*d == ds); e = cast(real *)(d + 1); assert(*e == es); } /****************************************************/ void test6() { ubyte *p; static ubyte data[] = [ 0x8B, 0x01, // mov EAX,[RCX] 0x8B, 0x04, 0x19, // mov EAX,[RBX][RCX] 0x8B, 0x04, 0x4B, // mov EAX,[RCX*2][RBX] 0x8B, 0x04, 0x5A, // mov EAX,[RBX*2][RDX] 0x8B, 0x04, 0x8E, // mov EAX,[RCX*4][RSI] 0x8B, 0x04, 0xF9, // mov EAX,[RDI*8][RCX] 0x2B, 0x1C, 0x19, // sub EBX,[RBX][RCX] 0x3B, 0x0C, 0x4B, // cmp ECX,[RCX*2][RBX] 0x03, 0x14, 0x5A, // add EDX,[RBX*2][RDX] 0x33, 0x34, 0x8E, // xor ESI,[RCX*4][RSI] 0x29, 0x1C, 0x19, // sub [RBX][RCX],EBX 0x39, 0x0C, 0x4B, // cmp [RCX*2][RBX],ECX 0x01, 0x24, 0x5A, // add [RBX*2][RDX],ESP 0x31, 0x2C, 0x8E, // xor [RCX*4][RSI],EBP 0xA8, 0x03, // test AL,3 0x66, 0xA9, 0x04, 0x00, // test AX,4 0xA9, 0x05, 0x00, 0x00, 0x00, // test EAX,5 0x85, 0x3C, 0xF9, // test [RDI*8][RCX],EDI ]; int i; asm { call L1 ; mov EAX,[RCX] ; mov EAX,[RCX][RBX] ; mov EAX,[RCX*2][RBX] ; mov EAX,[RDX][RBX*2] ; mov EAX,[RCX*4][RSI] ; mov EAX,[RCX][RDI*8] ; sub EBX,[RCX][RBX] ; cmp ECX,[RCX*2][RBX] ; add EDX,[RDX][RBX*2] ; xor ESI,[RCX*4][RSI] ; sub [RCX][RBX],EBX ; cmp [RCX*2][RBX],ECX ; add [RDX][RBX*2],ESP ; xor [RCX*4][RSI],EBP ; test AL,3 ; test AX,4 ; test EAX,5 ; test [RCX][RDI*8],EDI ; L1: pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ /+ void test7() { ubyte *p; static ubyte data[] = [ 0x26,0xA1,0x24,0x13,0x00,0x00, // mov EAX,ES:[01324h] 0x36,0x66,0xA1,0x78,0x56,0x00,0x00, // mov AX,SS:[05678h] 0xA0,0x78,0x56,0x00,0x00, // mov AL,[05678h] 0x2E,0x8A,0x25,0x78,0x56,0x00,0x00, // mov AH,CS:[05678h] 0x64,0x8A,0x1D,0x78,0x56,0x00,0x00, // mov BL,FS:[05678h] 0x65,0x8A,0x3D,0x78,0x56,0x00,0x00, // mov BH,GS:[05678h] ]; int i; asm { call L1 ; mov EAX,ES:[0x1324] ; mov AX,SS:[0x5678] ; mov AL,DS:[0x5678] ; mov AH,CS:[0x5678] ; mov BL,FS:[0x5678] ; mov BH,GS:[0x5678] ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } +/ /****************************************************/ void test8() { ubyte *p; static ubyte data[] = [ 0x8C,0xD0, // mov AX,SS 0x8C,0xDB, // mov BX,DS 0x8C,0xC1, // mov CX,ES 0x8C,0xCA, // mov DX,CS 0x8C,0xE6, // mov SI,FS 0x8C,0xEF, // mov DI,GS 0x8E,0xD0, // mov SS,AX 0x8E,0xDB, // mov DS,BX 0x8E,0xC1, // mov ES,CX 0x8E,0xCA, // mov CS,DX 0x8E,0xE6, // mov FS,SI 0x8E,0xEF, // mov GS,DI 0x0F,0x22,0xC0, // mov CR0,EAX 0x0F,0x22,0xD3, // mov CR2,EBX 0x0F,0x22,0xD9, // mov CR3,ECX 0x0F,0x22,0xE2, // mov CR4,EDX 0x0F,0x20,0xC0, // mov EAX,CR0 0x0F,0x20,0xD3, // mov EBX,CR2 0x0F,0x20,0xD9, // mov ECX,CR3 0x0F,0x20,0xE2, // mov EDX,CR4 0x0F,0x23,0xC0, // mov DR0,EAX 0x0F,0x23,0xCE, // mov DR1,ESI 0x0F,0x23,0xD3, // mov DR2,EBX 0x0F,0x23,0xD9, // mov DR3,ECX 0x0F,0x23,0xE2, // mov DR4,EDX 0x0F,0x23,0xEF, // mov DR5,EDI 0x0F,0x23,0xF4, // mov DR6,ESP 0x0F,0x23,0xFD, // mov DR7,EBP 0x0F,0x21,0xC4, // mov ESP,DR0 0x0F,0x21,0xCD, // mov EBP,DR1 0x0F,0x21,0xD0, // mov EAX,DR2 0x0F,0x21,0xDB, // mov EBX,DR3 0x0F,0x21,0xE1, // mov ECX,DR4 0x0F,0x21,0xEA, // mov EDX,DR5 0x0F,0x21,0xF6, // mov ESI,DR6 0x0F,0x21,0xFF, // mov EDI,DR7 0xA4, // movsb 0x66,0xA5, // movsw 0xA5, // movsd ]; int i; asm { call L1 ; mov AX,SS ; mov BX,DS ; mov CX,ES ; mov DX,CS ; mov SI,FS ; mov DI,GS ; mov SS,AX ; mov DS,BX ; mov ES,CX ; mov CS,DX ; mov FS,SI ; mov GS,DI ; mov CR0,EAX ; mov CR2,EBX ; mov CR3,ECX ; mov CR4,EDX ; mov EAX,CR0 ; mov EBX,CR2 ; mov ECX,CR3 ; mov EDX,CR4 ; mov DR0,EAX ; mov DR1,ESI ; mov DR2,EBX ; mov DR3,ECX ; mov DR4,EDX ; mov DR5,EDI ; mov DR6,ESP ; mov DR7,EBP ; mov ESP,DR0 ; mov EBP,DR1 ; mov EAX,DR2 ; mov EBX,DR3 ; mov ECX,DR4 ; mov EDX,DR5 ; mov ESI,DR6 ; mov EDI,DR7 ; movsb ; movsw ; movsd ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ void test9() { ubyte *p; static ubyte data[] = [ 0x67,0x66,0x8B,0x00, // mov AX,[BX+SI] 0x67,0x66,0x8B,0x01, // mov AX,[BX+DI] 0x67,0x66,0x8B,0x02, // mov AX,[BP+SI] 0x67,0x66,0x8B,0x03, // mov AX,[BP+DI] 0x67,0x66,0x8B,0x04, // mov AX,[SI] 0x67,0x66,0x8B,0x05, // mov AX,[DI] 0x66,0xB8,0xD2,0x04, // mov AX,04D2h 0x67,0x66,0x8B,0x07, // mov AX,[BX] 0x67,0x66,0x8B,0x40,0x01, // mov AX,1[BX+SI] 0x67,0x66,0x8B,0x41,0x02, // mov AX,2[BX+DI] 0x67,0x66,0x8B,0x42,0x03, // mov AX,3[BP+SI] 0x67,0x66,0x8B,0x43,0x04, // mov AX,4[BP+DI] 0x67,0x66,0x8B,0x44,0x05, // mov AX,5[SI] 0x67,0x66,0x8B,0x45,0x06, // mov AX,6[DI] 0x67,0x66,0x8B,0x43,0x07, // mov AX,7[BP+DI] 0x67,0x66,0x8B,0x47,0x08, // mov AX,8[BX] 0x67,0x8B,0x80,0x21,0x01, // mov EAX,0121h[BX+SI] 0x67,0x66,0x8B,0x81,0x22,0x01, // mov AX,0122h[BX+DI] 0x67,0x66,0x8B,0x82,0x43,0x23, // mov AX,02343h[BP+SI] 0x67,0x66,0x8B,0x83,0x54,0x45, // mov AX,04554h[BP+DI] 0x67,0x66,0x8B,0x84,0x45,0x66, // mov AX,06645h[SI] 0x67,0x66,0x8B,0x85,0x36,0x12, // mov AX,01236h[DI] 0x67,0x66,0x8B,0x86,0x67,0x45, // mov AX,04567h[BP] 0x67,0x8A,0x87,0x08,0x01, // mov AL,0108h[BX] ]; int i; asm { call L1 ; mov AX,[BX+SI] ; mov AX,[BX+DI] ; mov AX,[BP+SI] ; mov AX,[BP+DI] ; mov AX,[SI] ; // mov AX,[DI] ; Internal error: backend/cod3.c 4652 mov AX,[1234] ; mov AX,[BX] ; mov AX,1[BX+SI] ; mov AX,2[BX+DI] ; mov AX,3[BP+SI] ; mov AX,4[BP+DI] ; mov AX,5[SI] ; mov AX,6[DI] ; mov AX,7[DI+BP] ; mov AX,8[BX] ; mov EAX,0x121[BX+SI] ; mov AX,0x122[BX+DI] ; mov AX,0x2343[BP+SI] ; mov AX,0x4554[BP+DI] ; mov AX,0x6645[SI] ; mov AX,0x1236[DI] ; mov AX,0x4567[BP] ; mov AL,0x108[BX] ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ shared int bar10 = 78; shared int baz10[2]; void test10() { ubyte *p; int foo; static ubyte data[] = [ ]; int i; asm { mov bar10,0x12 ; // mov baz10,0x13 ;// does not compile, ( should it? ) mov int ptr baz10,0x13 ;// but this does mov ESI,1 ; mov baz10[RSI*4],0x14 ; } assert(bar10 == 0x12); assert(baz10[0] == 0x13); assert(baz10[1] == 0x14); } /****************************************************/ struct Foo11 { int c; int a; int b; } void test11() { ubyte *p; int x1; int x2; int x3; int x4; asm { mov x1,Foo11.a.sizeof ; mov x2,Foo11.b.offsetof ; mov x3,Foo11.sizeof ; mov x4,Foo11.sizeof + 7 ; } assert(x1 == int.sizeof); assert(x2 == 8); assert(x3 == 12); assert(x4 == 19); } /****************************************************/ void test12() { ubyte *p; static ubyte data[] = [ 0x14,0x05, // adc AL,5 0x83,0xD0,0x14, // adc EAX,014h 0x80,0x55,0xF8,0x17, // adc byte ptr -8[RBP],017h 0x83,0x55,0xFC,0x17, // adc dword ptr -4[RBP],017h 0x81,0x55,0xFC,0x34,0x12,0x00,0x00, // adc dword ptr -4[RBP],01234h 0x10,0x7D,0xF8, // adc -8[RBP],BH 0x11,0x5D,0xFC, // adc -4[RBP],EBX 0x12,0x5D,0xF8, // adc BL,-8[RBP] 0x13,0x55,0xFC, // adc EDX,-4[RBP] 0x04,0x05, // add AL,5 0x83,0xC0,0x14, // add EAX,014h 0x80,0x45,0xF8,0x17, // add byte ptr -8[RBP],017h 0x83,0x45,0xFC,0x17, // add dword ptr -4[RBP],017h 0x81,0x45,0xFC,0x34,0x12,0x00,0x00, // add dword ptr -4[RBP],01234h 0x00,0x7D,0xF8, // add -8[RBP],BH 0x01,0x5D,0xFC, // add -4[RBP],EBX 0x02,0x5D,0xF8, // add BL,-8[RBP] 0x03,0x55,0xFC, // add EDX,-4[RBP] 0x24,0x05, // and AL,5 0x83,0xE0,0x14, // and EAX,014h 0x80,0x65,0xF8,0x17, // and byte ptr -8[RBP],017h 0x83,0x65,0xFC,0x17, // and dword ptr -4[RBP],017h 0x81,0x65,0xFC,0x34,0x12,0x00,0x00, // and dword ptr -4[RBP],01234h 0x20,0x7D,0xF8, // and -8[RBP],BH 0x21,0x5D,0xFC, // and -4[RBP],EBX 0x22,0x5D,0xF8, // and BL,-8[RBP] 0x23,0x55,0xFC, // and EDX,-4[RBP] 0x3C,0x05, // cmp AL,5 0x83,0xF8,0x14, // cmp EAX,014h 0x80,0x7D,0xF8,0x17, // cmp byte ptr -8[RBP],017h 0x83,0x7D,0xFC,0x17, // cmp dword ptr -4[RBP],017h 0x81,0x7D,0xFC,0x34,0x12,0x00,0x00, // cmp dword ptr -4[RBP],01234h 0x38,0x7D,0xF8, // cmp -8[RBP],BH 0x39,0x5D,0xFC, // cmp -4[RBP],EBX 0x3A,0x5D,0xF8, // cmp BL,-8[RBP] 0x3B,0x55,0xFC, // cmp EDX,-4[RBP] 0x0C,0x05, // or AL,5 0x83,0xC8,0x14, // or EAX,014h 0x80,0x4D,0xF8,0x17, // or byte ptr -8[RBP],017h 0x83,0x4D,0xFC,0x17, // or dword ptr -4[RBP],017h 0x81,0x4D,0xFC,0x34,0x12,0x00,0x00, // or dword ptr -4[RBP],01234h 0x08,0x7D,0xF8, // or -8[RBP],BH 0x09,0x5D,0xFC, // or -4[RBP],EBX 0x0A,0x5D,0xF8, // or BL,-8[RBP] 0x0B,0x55,0xFC, // or EDX,-4[RBP] 0x1C,0x05, // sbb AL,5 0x83,0xD8,0x14, // sbb EAX,014h 0x80,0x5D,0xF8,0x17, // sbb byte ptr -8[RBP],017h 0x83,0x5D,0xFC,0x17, // sbb dword ptr -4[RBP],017h 0x81,0x5D,0xFC,0x34,0x12,0x00,0x00, // sbb dword ptr -4[RBP],01234h 0x18,0x7D,0xF8, // sbb -8[RBP],BH 0x19,0x5D,0xFC, // sbb -4[RBP],EBX 0x1A,0x5D,0xF8, // sbb BL,-8[RBP] 0x1B,0x55,0xFC, // sbb EDX,-4[RBP] 0x2C,0x05, // sub AL,5 0x83,0xE8,0x14, // sub EAX,014h 0x80,0x6D,0xF8,0x17, // sub byte ptr -8[RBP],017h 0x83,0x6D,0xFC,0x17, // sub dword ptr -4[RBP],017h 0x81,0x6D,0xFC,0x34,0x12,0x00,0x00, // sub dword ptr -4[RBP],01234h 0x28,0x7D,0xF8, // sub -8[RBP],BH 0x29,0x5D,0xFC, // sub -4[RBP],EBX 0x2A,0x5D,0xF8, // sub BL,-8[RBP] 0x2B,0x55,0xFC, // sub EDX,-4[RBP] 0xA8,0x05, // test AL,5 0xA9,0x14,0x00,0x00,0x00, // test EAX,014h 0xF6,0x45,0xF8,0x17, // test byte ptr -8[RBP],017h 0xF7,0x45,0xFC,0x17,0x00,0x00,0x00, // test dword ptr -4[RBP],017h 0xF7,0x45,0xFC,0x34,0x12,0x00,0x00, // test dword ptr -4[RBP],01234h 0x84,0x7D,0xF8, // test -8[RBP],BH 0x85,0x5D,0xFC, // test -4[RBP],EBX 0x34,0x05, // xor AL,5 0x83,0xF0,0x14, // xor EAX,014h 0x80,0x75,0xF8,0x17, // xor byte ptr -8[RBP],017h 0x83,0x75,0xFC,0x17, // xor dword ptr -4[RBP],017h 0x81,0x75,0xFC,0x34,0x12,0x00,0x00, // xor dword ptr -4[RBP],01234h 0x30,0x7D,0xF8, // xor -8[RBP],BH 0x31,0x5D,0xFC, // xor -4[RBP],EBX 0x32,0x5D,0xF8, // xor BL,-8[RBP] 0x33,0x55,0xFC, // xor EDX,-4[RBP] ]; int i; int padding; byte rm8; int rm32; static int m32; asm { call L1 ; /* aaa ; aad ; aam ; aas ; arpl [SI],DI ; */ adc AL,5 ; adc EAX,20 ; adc rm8[RBP],23 ; adc rm32[RBP],23 ; adc rm32[RBP],0x1234 ; adc rm8[RBP],BH ; adc rm32[RBP],EBX ; adc BL,rm8[RBP] ; adc EDX,rm32[RBP] ; add AL,5 ; add EAX,20 ; add rm8[RBP],23 ; add rm32[RBP],23 ; add rm32[RBP],0x1234 ; add rm8[RBP],BH ; add rm32[RBP],EBX ; add BL,rm8[RBP] ; add EDX,rm32[RBP] ; and AL,5 ; and EAX,20 ; and rm8[RBP],23 ; and rm32[RBP],23 ; and rm32[RBP],0x1234 ; and rm8[RBP],BH ; and rm32[RBP],EBX ; and BL,rm8[RBP] ; and EDX,rm32[RBP] ; cmp AL,5 ; cmp EAX,20 ; cmp rm8[RBP],23 ; cmp rm32[RBP],23 ; cmp rm32[RBP],0x1234 ; cmp rm8[RBP],BH ; cmp rm32[RBP],EBX ; cmp BL,rm8[RBP] ; cmp EDX,rm32[RBP] ; or AL,5 ; or EAX,20 ; or rm8[RBP],23 ; or rm32[RBP],23 ; or rm32[RBP],0x1234 ; or rm8[RBP],BH ; or rm32[RBP],EBX ; or BL,rm8[RBP] ; or EDX,rm32[RBP] ; sbb AL,5 ; sbb EAX,20 ; sbb rm8[RBP],23 ; sbb rm32[RBP],23 ; sbb rm32[RBP],0x1234 ; sbb rm8[RBP],BH ; sbb rm32[RBP],EBX ; sbb BL,rm8[RBP] ; sbb EDX,rm32[RBP] ; sub AL,5 ; sub EAX,20 ; sub rm8[RBP],23 ; sub rm32[RBP],23 ; sub rm32[RBP],0x1234 ; sub rm8[RBP],BH ; sub rm32[RBP],EBX ; sub BL,rm8[RBP] ; sub EDX,rm32[RBP] ; test AL,5 ; test EAX,20 ; test rm8[RBP],23 ; test rm32[RBP],23 ; test rm32[RBP],0x1234 ; test rm8[RBP],BH ; test rm32[RBP],EBX ; xor AL,5 ; xor EAX,20 ; xor rm8[RBP],23 ; xor rm32[RBP],23 ; xor rm32[RBP],0x1234 ; xor rm8[RBP],BH ; xor rm32[RBP],EBX ; xor BL,rm8[RBP] ; xor EDX,rm32[RBP] ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { //printf("p[%d] = x%02x, data = x%02x\n", i, p[i], data[i]); assert(p[i] == data[i]); } } /****************************************************/ void test13() { int m32; long m64; M128 m128; ubyte *p; static ubyte data[] = [ 0x0F,0x0B, // ud2 0x0F,0x05, // syscall 0x0F,0x34, // sysenter 0x0F,0x35, // sysexit 0x0F,0x07, // sysret 0x0F,0xAE,0xE8, // lfence 0x0F,0xAE,0xF0, // mfence 0x0F,0xAE,0xF8, // sfence 0x0F,0xAE,0x00, // fxsave [RAX] 0x0F,0xAE,0x08, // fxrstor [RAX] 0x0F,0xAE,0x10, // ldmxcsr [RAX] 0x0F,0xAE,0x18, // stmxcsr [RAX] 0x0F,0xAE,0x38, // clflush [RAX] 0x0F,0x58,0x08, // addps XMM1,[RAX] 0x0F,0x58,0xCA, // addps XMM1,XMM2 0x66, 0x0F,0x58,0x03, // addpd XMM0,[RBX] 0x66, 0x0F,0x58,0xD1, // addpd XMM2,XMM1 0xF2,0x0F,0x58,0x08, // addsd XMM1,[RAX] 0xF2,0x0F,0x58,0xCA, // addsd XMM1,XMM2 0xF3,0x0F,0x58,0x2E, // addss XMM5,[RSI] 0xF3,0x0F,0x58,0xF7, // addss XMM6,XMM7 0x0F,0x54,0x08, // andps XMM1,[RAX] 0x0F,0x54,0xCA, // andps XMM1,XMM2 0x66, 0x0F,0x54,0x03, // andpd XMM0,[RBX] 0x66, 0x0F,0x54,0xD1, // andpd XMM2,XMM1 0x0F,0x55,0x08, // andnps XMM1,[RAX] 0x0F,0x55,0xCA, // andnps XMM1,XMM2 0x66, 0x0F,0x55,0x03, // andnpd XMM0,[RBX] 0x66, 0x0F,0x55,0xD1, // andnpd XMM2,XMM1 0xA7, // cmpsd 0x0F,0xC2,0x08,0x01, // cmpps XMM1,[RAX],1 0x0F,0xC2,0xCA,0x02, // cmpps XMM1,XMM2,2 0x66, 0x0F,0xC2,0x03,0x03, // cmppd XMM0,[RBX],3 0x66, 0x0F,0xC2,0xD1,0x04, // cmppd XMM2,XMM1,4 0xF2,0x0F,0xC2,0x08,0x05, // cmpsd XMM1,[RAX],5 0xF2,0x0F,0xC2,0xCA,0x06, // cmpsd XMM1,XMM2,6 0xF3,0x0F,0xC2,0x2E,0x07, // cmpss XMM5,[RSI],7 0xF3,0x0F,0xC2,0xF7,0x00, // cmpss XMM6,XMM7,0 0x66, 0x0F,0x2F,0x08, // comisd XMM1,[RAX] 0x66, 0x0F,0x2F,0x4D,0xD8, // comisd XMM1,-028h[RBP] 0x66, 0x0F,0x2F,0xCA, // comisd XMM1,XMM2 0x0F,0x2F,0x2E, // comiss XMM5,[RSI] 0x0F,0x2F,0xF7, // comiss XMM6,XMM7 0xF3,0x0F,0xE6,0xDC, // cvtdq2pd XMM3,XMM4 0xF3,0x0F,0xE6,0x5D,0xD8, // cvtdq2pd XMM3,-028h[RBP] 0x0F,0x5B,0xDC, // cvtdq2ps XMM3,XMM4 0x0F,0x5B,0x5D,0xE0, // cvtdq2ps XMM3,-020h[RBP] 0xF2,0x0F,0xE6,0xDC, // cvtpd2dq XMM3,XMM4 0xF2,0x0F,0xE6,0x5D,0xE0, // cvtpd2dq XMM3,-020h[RBP] 0x66, 0x0F,0x2D,0xDC, // cvtpd2pi MM3,XMM4 0x66, 0x0F,0x2D,0x5D,0xE0, // cvtpd2pi MM3,-020h[RBP] 0x66, 0x0F,0x5A,0xDC, // cvtpd2ps XMM3,XMM4 0x66, 0x0F,0x5A,0x5D,0xE0, // cvtpd2ps XMM3,-020h[RBP] 0x66, 0x0F,0x2A,0xDC, // cvtpi2pd XMM3,MM4 0x66, 0x0F,0x2A,0x5D,0xD8, // cvtpi2pd XMM3,-028h[RBP] 0x0F,0x2A,0xDC, // cvtpi2ps XMM3,MM4 0x0F,0x2A,0x5D,0xD8, // cvtpi2ps XMM3,-028h[RBP] 0x66, 0x0F,0x5B,0xDC, // cvtps2dq XMM3,XMM4 0x66, 0x0F,0x5B,0x5D,0xE0, // cvtps2dq XMM3,-020h[RBP] 0x0F,0x5A,0xDC, // cvtps2pd XMM3,XMM4 0x0F,0x5A,0x5D,0xD8, // cvtps2pd XMM3,-028h[RBP] 0x0F,0x2D,0xDC, // cvtps2pi MM3,XMM4 0x0F,0x2D,0x5D,0xD8, // cvtps2pi MM3,-030h[RBP] 0xF2,0x0F,0x2D,0xCC, // cvtsd2si XMM1,XMM4 0xF2,0x0F,0x2D,0x55,0xD8, // cvtsd2si XMM2,-028h[RBP] 0xF2,0x0F,0x5A,0xDC, // cvtsd2ss XMM3,XMM4 0xF2,0x0F,0x5A,0x5D,0xD8, // cvtsd2ss XMM3,-028h[RBP] 0xF2,0x0F,0x2A,0xDA, // cvtsi2sd XMM3,EDX 0xF2,0x0F,0x2A,0x5D,0xD0, // cvtsi2sd XMM3,-030h[RBP] 0xF3,0x0F,0x2A,0xDA, // cvtsi2ss XMM3,EDX 0xF3,0x0F,0x2A,0x5D,0xD0, // cvtsi2ss XMM3,-030h[RBP] 0xF3,0x0F,0x5A,0xDC, // cvtss2sd XMM3,XMM4 0xF3,0x0F,0x5A,0x5D,0xD0, // cvtss2sd XMM3,-030h[RBP] 0xF3,0x0F,0x2D,0xFC, // cvtss2si XMM7,XMM4 0xF3,0x0F,0x2D,0x7D,0xD0, // cvtss2si XMM7,-030h[RBP] 0x66, 0x0F,0x2C,0xDC, // cvttpd2pi MM3,XMM4 0x66, 0x0F,0x2C,0x7D,0xE0, // cvttpd2pi MM7,-020h[RBP] 0x66, 0x0F,0xE6,0xDC, // cvttpd2dq XMM3,XMM4 0x66, 0x0F,0xE6,0x7D,0xE0, // cvttpd2dq XMM7,-020h[RBP] 0xF3,0x0F,0x5B,0xDC, // cvttps2dq XMM3,XMM4 0xF3,0x0F,0x5B,0x7D,0xE0, // cvttps2dq XMM7,-020h[RBP] 0x0F,0x2C,0xDC, // cvttps2pi MM3,XMM4 0x0F,0x2C,0x7D,0xD8, // cvttps2pi MM7,-028h[RBP] 0xF2,0x0F,0x2C,0xC4, // cvttsd2si EAX,XMM4 0xF2,0x0F,0x2C,0x4D,0xE0, // cvttsd2si ECX,-020h[RBP] 0xF3,0x0F,0x2C,0xC4, // cvttss2si EAX,XMM4 0xF3,0x0F,0x2C,0x4D,0xD0, // cvttss2si ECX,-030h[RBP] 0x66, 0x0F,0x5E,0xE8, // divpd XMM5,XMM0 0x66, 0x0F,0x5E,0x6D,0xE0, // divpd XMM5,-020h[RBP] 0x0F,0x5E,0xE8, // divps XMM5,XMM0 0x0F,0x5E,0x6D,0xE0, // divps XMM5,-020h[RBP] 0xF2,0x0F,0x5E,0xE8, // divsd XMM5,XMM0 0xF2,0x0F,0x5E,0x6D,0xD8, // divsd XMM5,-028h[RBP] 0xF3,0x0F,0x5E,0xE8, // divss XMM5,XMM0 0xF3,0x0F,0x5E,0x6D,0xD0, // divss XMM5,-030h[RBP] 0x66, 0x0F,0xF7,0xD1, // maskmovdqu XMM2,XMM1 0x0F,0xF7,0xE3, // maskmovq MM4,MM3 0x66, 0x0F,0x5F,0xC0, // maxpd XMM0,XMM0 0x66, 0x0F,0x5F,0x4D,0xE0, // maxpd XMM1,-020h[RBP] 0x0F,0x5F,0xD1, // maxps XMM2,XMM1 0x0F,0x5F,0x5D,0xE0, // maxps XMM3,-020h[RBP] 0xF2,0x0F,0x5F,0xE2, // maxsd XMM4,XMM2 0xF2,0x0F,0x5F,0x6D,0xD8, // maxsd XMM5,-028h[RBP] 0xF3,0x0F,0x5F,0xF3, // maxss XMM6,XMM3 0xF3,0x0F,0x5F,0x7D,0xD0, // maxss XMM7,-030h[RBP] 0x66, 0x0F,0x5D,0xC0, // minpd XMM0,XMM0 0x66, 0x0F,0x5D,0x4D,0xE0, // minpd XMM1,-020h[RBP] 0x0F,0x5D,0xD1, // minps XMM2,XMM1 0x0F,0x5D,0x5D,0xE0, // minps XMM3,-020h[RBP] 0xF2,0x0F,0x5D,0xE2, // minsd XMM4,XMM2 0xF2,0x0F,0x5D,0x6D,0xD8, // minsd XMM5,-028h[RBP] 0xF3,0x0F,0x5D,0xF3, // minss XMM6,XMM3 0xF3,0x0F,0x5D,0x7D,0xD0, // minss XMM7,-030h[RBP] 0x66, 0x0F,0x28,0xCA, // movapd XMM1,XMM2 0x66, 0x0F,0x28,0x5D,0xE0, // movapd XMM3,-020h[RBP] 0x66, 0x0F,0x29,0x65,0xE0, // movapd -020h[RBP],XMM4 0x0F,0x28,0xCA, // movaps XMM1,XMM2 0x0F,0x28,0x5D,0xE0, // movaps XMM3,-020h[RBP] 0x0F,0x29,0x65,0xE0, // movaps -020h[RBP],XMM4 0x0F,0x6E,0xCB, // movd MM1,EBX 0x0F,0x6E,0x55,0xD0, // movd MM2,-030h[RBP] 0x0F,0x7E,0xDB, // movd EBX,MM3 0x0F,0x7E,0x65,0xD0, // movd -030h[RBP],MM4 0x66, 0x0F,0x6E,0xCB, // movd XMM1,EBX 0x66, 0x0F,0x6E,0x55,0xD0, // movd XMM2,-030h[RBP] 0x66, 0x0F,0x7E,0xDB, // movd EBX,XMM3 0x66, 0x0F,0x7E,0x65,0xD0, // movd -030h[RBP],XMM4 0x66, 0x0F,0x6F,0xCA, // movdqa XMM1,XMM2 0x66, 0x0F,0x6F,0x55,0xE0, // movdqa XMM2,-020h[RBP] 0x66, 0x0F,0x7F,0x65,0xE0, // movdqa -020h[RBP],XMM4 0xF3,0x0F,0x6F,0xCA, // movdqu XMM1,XMM2 0xF3,0x0F,0x6F,0x55,0xE0, // movdqu XMM2,-020h[RBP] 0xF3,0x0F,0x7F,0x65,0xE0, // movdqu -020h[RBP],XMM4 0xF2,0x0F,0xD6,0xDC, // movdq2q MM4,XMM3 0x0F,0x12,0xDC, // movhlps XMM4,XMM3 0x66, 0x0F,0x16,0x55,0xD8, // movhpd XMM2,-028h[RBP] 0x66, 0x0F,0x17,0x7D,0xD8, // movhpd -028h[RBP],XMM7 0x0F,0x16,0x55,0xD8, // movhps XMM2,-028h[RBP] 0x0F,0x17,0x7D,0xD8, // movhps -028h[RBP],XMM7 0x0F,0x16,0xDC, // movlhps XMM4,XMM3 0x66, 0x0F,0x12,0x55,0xD8, // movlpd XMM2,-028h[RBP] 0x66, 0x0F,0x13,0x7D,0xD8, // movlpd -028h[RBP],XMM7 0x0F,0x12,0x55,0xD8, // movlps XMM2,-028h[RBP] 0x0F,0x13,0x7D,0xD8, // movlps -028h[RBP],XMM7 0x66, 0x0F,0x50,0xF3, // movmskpd ESI,XMM3 0x0F,0x50,0xF3, // movmskps ESI,XMM3 0x66, 0x0F,0x59,0xC0, // mulpd XMM0,XMM0 0x66, 0x0F,0x59,0x4D,0xE0, // mulpd XMM1,-020h[RBP] 0x0F,0x59,0xD1, // mulps XMM2,XMM1 0x0F,0x59,0x5D,0xE0, // mulps XMM3,-020h[RBP] 0xF2,0x0F,0x59,0xE2, // mulsd XMM4,XMM2 0xF2,0x0F,0x59,0x6D,0xD8, // mulsd XMM5,-028h[RBP] 0xF3,0x0F,0x59,0xF3, // mulss XMM6,XMM3 0xF3,0x0F,0x59,0x7D,0xD0, // mulss XMM7,-030h[RBP] 0x66, 0x0F,0x51,0xC4, // sqrtpd XMM0,XMM4 0x66, 0x0F,0x51,0x4D,0xE0, // sqrtpd XMM1,-020h[RBP] 0x0F,0x51,0xD5, // sqrtps XMM2,XMM5 0x0F,0x51,0x5D,0xE0, // sqrtps XMM3,-020h[RBP] 0xF2,0x0F,0x51,0xE6, // sqrtsd XMM4,XMM6 0xF2,0x0F,0x51,0x6D,0xD8, // sqrtsd XMM5,-028h[RBP] 0xF3,0x0F,0x51,0xF7, // sqrtss XMM6,XMM7 0xF3,0x0F,0x51,0x7D,0xD0, // sqrtss XMM7,-030h[RBP] 0x66, 0x0F,0x5C,0xC4, // subpd XMM0,XMM4 0x66, 0x0F,0x5C,0x4D,0xE0, // subpd XMM1,-020h[RBP] 0x0F,0x5C,0xD5, // subps XMM2,XMM5 0x0F,0x5C,0x5D,0xE0, // subps XMM3,-020h[RBP] 0xF2,0x0F,0x5C,0xE6, // subsd XMM4,XMM6 0xF2,0x0F,0x5C,0x6D,0xD8, // subsd XMM5,-028h[RBP] 0xF3,0x0F,0x5C,0xF7, // subss XMM6,XMM7 0xF3,0x0F,0x5C,0x7D,0xD0, // subss XMM7,-030h[RBP] 0x0F,0x01,0xE0, // smsw EAX ]; int i; asm { call L1 ; ud2 ; syscall ; sysenter ; sysexit ; sysret ; lfence ; mfence ; sfence ; fxsave [RAX] ; fxrstor [RAX] ; ldmxcsr [RAX] ; stmxcsr [RAX] ; clflush [RAX] ; addps XMM1,[RAX] ; addps XMM1,XMM2 ; addpd XMM0,[RBX] ; addpd XMM2,XMM1 ; addsd XMM1,[RAX] ; addsd XMM1,XMM2 ; addss XMM5,[RSI] ; addss XMM6,XMM7 ; andps XMM1,[RAX] ; andps XMM1,XMM2 ; andpd XMM0,[RBX] ; andpd XMM2,XMM1 ; andnps XMM1,[RAX] ; andnps XMM1,XMM2 ; andnpd XMM0,[RBX] ; andnpd XMM2,XMM1 ; cmpsd ; cmpps XMM1,[RAX],1 ; cmpps XMM1,XMM2,2 ; cmppd XMM0,[RBX],3 ; cmppd XMM2,XMM1,4 ; cmpsd XMM1,[RAX],5 ; cmpsd XMM1,XMM2,6 ; cmpss XMM5,[RSI],7 ; cmpss XMM6,XMM7,0 ; comisd XMM1,[RAX] ; comisd XMM1,m64[RBP] ; comisd XMM1,XMM2 ; comiss XMM5,[RSI] ; comiss XMM6,XMM7 ; cvtdq2pd XMM3,XMM4 ; cvtdq2pd XMM3,m64[RBP] ; cvtdq2ps XMM3,XMM4 ; cvtdq2ps XMM3,m128[RBP] ; cvtpd2dq XMM3,XMM4 ; cvtpd2dq XMM3,m128[RBP] ; cvtpd2pi MM3,XMM4 ; cvtpd2pi MM3,m128[RBP] ; cvtpd2ps XMM3,XMM4 ; cvtpd2ps XMM3,m128[RBP] ; cvtpi2pd XMM3,MM4 ; cvtpi2pd XMM3,m64[RBP] ; cvtpi2ps XMM3,MM4 ; cvtpi2ps XMM3,m64[RBP] ; cvtps2dq XMM3,XMM4 ; cvtps2dq XMM3,m128[RBP] ; cvtps2pd XMM3,XMM4 ; cvtps2pd XMM3,m64[RBP] ; cvtps2pi MM3,XMM4 ; cvtps2pi MM3,m64[RBP] ; cvtsd2si ECX,XMM4 ; cvtsd2si EDX,m64[RBP] ; cvtsd2ss XMM3,XMM4 ; cvtsd2ss XMM3,m64[RBP] ; cvtsi2sd XMM3,EDX ; cvtsi2sd XMM3,m32[RBP] ; cvtsi2ss XMM3,EDX ; cvtsi2ss XMM3,m32[RBP] ; cvtss2sd XMM3,XMM4 ; cvtss2sd XMM3,m32[RBP] ; cvtss2si EDI,XMM4 ; cvtss2si EDI,m32[RBP] ; cvttpd2pi MM3,XMM4 ; cvttpd2pi MM7,m128[RBP] ; cvttpd2dq XMM3,XMM4 ; cvttpd2dq XMM7,m128[RBP] ; cvttps2dq XMM3,XMM4 ; cvttps2dq XMM7,m128[RBP] ; cvttps2pi MM3,XMM4 ; cvttps2pi MM7,m64[RBP] ; cvttsd2si EAX,XMM4 ; cvttsd2si ECX,m128[RBP] ; cvttss2si EAX,XMM4 ; cvttss2si ECX,m32[RBP] ; divpd XMM5,XMM0 ; divpd XMM5,m128[RBP] ; divps XMM5,XMM0 ; divps XMM5,m128[RBP] ; divsd XMM5,XMM0 ; divsd XMM5,m64[RBP] ; divss XMM5,XMM0 ; divss XMM5,m32[RBP] ; maskmovdqu XMM1,XMM2 ; maskmovq MM3,MM4 ; maxpd XMM0,XMM0 ; maxpd XMM1,m128[RBP] ; maxps XMM2,XMM1 ; maxps XMM3,m128[RBP] ; maxsd XMM4,XMM2 ; maxsd XMM5,m64[RBP] ; maxss XMM6,XMM3 ; maxss XMM7,m32[RBP] ; minpd XMM0,XMM0 ; minpd XMM1,m128[RBP] ; minps XMM2,XMM1 ; minps XMM3,m128[RBP] ; minsd XMM4,XMM2 ; minsd XMM5,m64[RBP] ; minss XMM6,XMM3 ; minss XMM7,m32[RBP] ; movapd XMM1,XMM2 ; movapd XMM3,m128[RBP] ; movapd m128[RBP],XMM4 ; movaps XMM1,XMM2 ; movaps XMM3,m128[RBP] ; movaps m128[RBP],XMM4 ; movd MM1,EBX ; movd MM2,m32[RBP] ; movd EBX,MM3 ; movd m32[RBP],MM4 ; movd XMM1,EBX ; movd XMM2,m32[RBP] ; movd EBX,XMM3 ; movd m32[RBP],XMM4 ; movdqa XMM1,XMM2 ; movdqa XMM2,m128[RBP] ; movdqa m128[RBP],XMM4 ; movdqu XMM1,XMM2 ; movdqu XMM2,m128[RBP] ; movdqu m128[RBP],XMM4 ; movdq2q MM3,XMM4 ; movhlps XMM3,XMM4 ; movhpd XMM2,m64[RBP] ; movhpd m64[RBP],XMM7 ; movhps XMM2,m64[RBP] ; movhps m64[RBP],XMM7 ; movlhps XMM3,XMM4 ; movlpd XMM2,m64[RBP] ; movlpd m64[RBP],XMM7 ; movlps XMM2,m64[RBP] ; movlps m64[RBP],XMM7 ; movmskpd ESI,XMM3 ; movmskps ESI,XMM3 ; mulpd XMM0,XMM0 ; mulpd XMM1,m128[RBP] ; mulps XMM2,XMM1 ; mulps XMM3,m128[RBP] ; mulsd XMM4,XMM2 ; mulsd XMM5,m64[RBP] ; mulss XMM6,XMM3 ; mulss XMM7,m32[RBP] ; sqrtpd XMM0,XMM4 ; sqrtpd XMM1,m128[RBP] ; sqrtps XMM2,XMM5 ; sqrtps XMM3,m128[RBP] ; sqrtsd XMM4,XMM6 ; sqrtsd XMM5,m64[RBP] ; sqrtss XMM6,XMM7 ; sqrtss XMM7,m32[RBP] ; subpd XMM0,XMM4 ; subpd XMM1,m128[RBP] ; subps XMM2,XMM5 ; subps XMM3,m128[RBP] ; subsd XMM4,XMM6 ; subsd XMM5,m64[RBP] ; subss XMM6,XMM7 ; subss XMM7,m32[RBP] ; smsw EAX ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { //printf("[%d] = %02x %02x\n", i, p[i], data[i]); assert(p[i] == data[i]); } } /****************************************************/ void test14() { byte m8; short m16; int m32; long m64; M128 m128; ubyte *p; static ubyte data[] = [ 0x66, 0x0F,0x50,0xF3, // movmskpd ESI,XMM3 0x0F,0x50,0xF3, // movmskps ESI,XMM3 0x66, 0x0F,0xE7,0x55,0xE0, // movntdq -020h[RBP],XMM2 0x0F,0xC3,0x4D,0xD4, // movnti -02Ch[RBP],ECX 0x66, 0x0F,0x2B,0x5D,0xE0, // movntpd -020h[RBP],XMM3 0x0F,0x2B,0x65,0xE0, // movntps -020h[RBP],XMM4 0x0F,0xE7,0x6D,0xD8, // movntq -028h[RBP],MM5 0x0F,0x6F,0xCA, // movq MM1,MM2 0x0F,0x6F,0x55,0xD8, // movq MM2,-028h[RBP] 0x0F,0x7F,0x5D,0xD8, // movq -028h[RBP],MM3 0xF3,0x0F,0x7E,0xCA, // movq XMM1,XMM2 0xF3,0x0F,0x7E,0x55,0xD8, // movq XMM2,-028h[RBP] 0x66, 0x0F,0xD6,0x5D,0xD8, // movq -028h[RBP],XMM3 0xF3,0x0F,0xD6,0xDA, // movq2dq XMM3,MM2 0xA5, // movsd 0xF2,0x0F,0x10,0xCA, // movsd XMM1,XMM2 0xF2,0x0F,0x10,0x5D,0xD8, // movsd XMM3,-028h[RBP] 0xF2,0x0F,0x11,0x65,0xD8, // movsd -028h[RBP],XMM4 0xF3,0x0F,0x10,0xCA, // movss XMM1,XMM2 0xF3,0x0F,0x10,0x5D,0xD4, // movss XMM3,-02Ch[RBP] 0xF3,0x0F,0x11,0x65,0xD4, // movss -02Ch[RBP],XMM4 0x66, 0x0F,0x10,0xCA, // movupd XMM1,XMM2 0x66, 0x0F,0x10,0x5D,0xE0, // movupd XMM3,-020h[RBP] 0x66, 0x0F,0x11,0x65,0xE0, // movupd -020h[RBP],XMM4 0x0F,0x10,0xCA, // movups XMM1,XMM2 0x0F,0x10,0x5D,0xE0, // movups XMM3,-020h[RBP] 0x0F,0x11,0x65,0xE0, // movups -020h[RBP],XMM4 0x66, 0x0F,0x56,0xCA, // orpd XMM1,XMM2 0x66, 0x0F,0x56,0x5D,0xE0, // orpd XMM3,-020h[RBP] 0x0F,0x56,0xCA, // orps XMM1,XMM2 0x0F,0x56,0x5D,0xE0, // orps XMM3,-020h[RBP] 0x0F,0x63,0xCA, // packsswb MM1,MM2 0x0F,0x63,0x5D,0xD8, // packsswb MM3,-028h[RBP] 0x66, 0x0F,0x63,0xCA, // packsswb XMM1,XMM2 0x66, 0x0F,0x63,0x5D,0xE0, // packsswb XMM3,-020h[RBP] 0x0F,0x6B,0xCA, // packssdw MM1,MM2 0x0F,0x6B,0x5D,0xD8, // packssdw MM3,-028h[RBP] 0x66, 0x0F,0x6B,0xCA, // packssdw XMM1,XMM2 0x66, 0x0F,0x6B,0x5D,0xE0, // packssdw XMM3,-020h[RBP] 0x0F,0x67,0xCA, // packuswb MM1,MM2 0x0F,0x67,0x5D,0xD8, // packuswb MM3,-028h[RBP] 0x66, 0x0F,0x67,0xCA, // packuswb XMM1,XMM2 0x66, 0x0F,0x67,0x5D,0xE0, // packuswb XMM3,-020h[RBP] 0x0F,0xFC,0xCA, // paddb MM1,MM2 0x0F,0xFC,0x5D,0xD8, // paddb MM3,-028h[RBP] 0x66, 0x0F,0xFC,0xCA, // paddb XMM1,XMM2 0x66, 0x0F,0xFC,0x5D,0xE0, // paddb XMM3,-020h[RBP] 0x0F,0xFD,0xCA, // paddw MM1,MM2 0x0F,0xFD,0x5D,0xD8, // paddw MM3,-028h[RBP] 0x66, 0x0F,0xFD,0xCA, // paddw XMM1,XMM2 0x66, 0x0F,0xFD,0x5D,0xE0, // paddw XMM3,-020h[RBP] 0x0F,0xFE,0xCA, // paddd MM1,MM2 0x0F,0xFE,0x5D,0xD8, // paddd MM3,-028h[RBP] 0x66, 0x0F,0xFE,0xCA, // paddd XMM1,XMM2 0x66, 0x0F,0xFE,0x5D,0xE0, // paddd XMM3,-020h[RBP] 0x0F,0xD4,0xCA, // paddq MM1,MM2 0x0F,0xD4,0x5D,0xD8, // paddq MM3,-028h[RBP] 0x66, 0x0F,0xD4,0xCA, // paddq XMM1,XMM2 0x66, 0x0F,0xD4,0x5D,0xE0, // paddq XMM3,-020h[RBP] 0x0F,0xEC,0xCA, // paddsb MM1,MM2 0x0F,0xEC,0x5D,0xD8, // paddsb MM3,-028h[RBP] 0x66, 0x0F,0xEC,0xCA, // paddsb XMM1,XMM2 0x66, 0x0F,0xEC,0x5D,0xE0, // paddsb XMM3,-020h[RBP] 0x0F,0xED,0xCA, // paddsw MM1,MM2 0x0F,0xED,0x5D,0xD8, // paddsw MM3,-028h[RBP] 0x66, 0x0F,0xED,0xCA, // paddsw XMM1,XMM2 0x66, 0x0F,0xED,0x5D,0xE0, // paddsw XMM3,-020h[RBP] 0x0F,0xDC,0xCA, // paddusb MM1,MM2 0x0F,0xDC,0x5D,0xD8, // paddusb MM3,-028h[RBP] 0x66, 0x0F,0xDC,0xCA, // paddusb XMM1,XMM2 0x66, 0x0F,0xDC,0x5D,0xE0, // paddusb XMM3,-020h[RBP] 0x0F,0xDD,0xCA, // paddusw MM1,MM2 0x0F,0xDD,0x5D,0xD8, // paddusw MM3,-028h[RBP] 0x66, 0x0F,0xDD,0xCA, // paddusw XMM1,XMM2 0x66, 0x0F,0xDD,0x5D,0xE0, // paddusw XMM3,-020h[RBP] 0x0F,0xDB,0xCA, // pand MM1,MM2 0x0F,0xDB,0x5D,0xD8, // pand MM3,-028h[RBP] 0x66, 0x0F,0xDB,0xCA, // pand XMM1,XMM2 0x66, 0x0F,0xDB,0x5D,0xE0, // pand XMM3,-020h[RBP] 0x0F,0xDF,0xCA, // pandn MM1,MM2 0x0F,0xDF,0x5D,0xD8, // pandn MM3,-028h[RBP] 0x66, 0x0F,0xDF,0xCA, // pandn XMM1,XMM2 0x66, 0x0F,0xDF,0x5D,0xE0, // pandn XMM3,-020h[RBP] 0x0F,0xE0,0xCA, // pavgb MM1,MM2 0x0F,0xE0,0x5D,0xD8, // pavgb MM3,-028h[RBP] 0x66, 0x0F,0xE0,0xCA, // pavgb XMM1,XMM2 0x66, 0x0F,0xE0,0x5D,0xE0, // pavgb XMM3,-020h[RBP] 0x0F,0xE3,0xCA, // pavgw MM1,MM2 0x0F,0xE3,0x5D,0xD8, // pavgw MM3,-028h[RBP] 0x66, 0x0F,0xE3,0xCA, // pavgw XMM1,XMM2 0x66, 0x0F,0xE3,0x5D,0xE0, // pavgw XMM3,-020h[RBP] 0x0F,0x74,0xCA, // pcmpeqb MM1,MM2 0x0F,0x74,0x5D,0xD8, // pcmpeqb MM3,-028h[RBP] 0x66, 0x0F,0x74,0xCA, // pcmpeqb XMM1,XMM2 0x66, 0x0F,0x74,0x5D,0xE0, // pcmpeqb XMM3,-020h[RBP] 0x0F,0x75,0xCA, // pcmpeqw MM1,MM2 0x0F,0x75,0x5D,0xD8, // pcmpeqw MM3,-028h[RBP] 0x66, 0x0F,0x75,0xCA, // pcmpeqw XMM1,XMM2 0x66, 0x0F,0x75,0x5D,0xE0, // pcmpeqw XMM3,-020h[RBP] 0x0F,0x76,0xCA, // pcmpeqd MM1,MM2 0x0F,0x76,0x5D,0xD8, // pcmpeqd MM3,-028h[RBP] 0x66, 0x0F,0x76,0xCA, // pcmpeqd XMM1,XMM2 0x66, 0x0F,0x76,0x5D,0xE0, // pcmpeqd XMM3,-020h[RBP] 0x0F,0x64,0xCA, // pcmpgtb MM1,MM2 0x0F,0x64,0x5D,0xD8, // pcmpgtb MM3,-028h[RBP] 0x66, 0x0F,0x64,0xCA, // pcmpgtb XMM1,XMM2 0x66, 0x0F,0x64,0x5D,0xE0, // pcmpgtb XMM3,-020h[RBP] 0x0F,0x65,0xCA, // pcmpgtw MM1,MM2 0x0F,0x65,0x5D,0xD8, // pcmpgtw MM3,-028h[RBP] 0x66, 0x0F,0x65,0xCA, // pcmpgtw XMM1,XMM2 0x66, 0x0F,0x65,0x5D,0xE0, // pcmpgtw XMM3,-020h[RBP] 0x0F,0x66,0xCA, // pcmpgtd MM1,MM2 0x0F,0x66,0x5D,0xD8, // pcmpgtd MM3,-028h[RBP] 0x66, 0x0F,0x66,0xCA, // pcmpgtd XMM1,XMM2 0x66, 0x0F,0x66,0x5D,0xE0, // pcmpgtd XMM3,-020h[RBP] 0x0F,0xC5,0xD6,0x07, // pextrw EDX,MM6,7 0x66, 0x0F,0xC5,0xD6,0x07, // pextrw EDX,XMM6,7 0x0F,0xC4,0xF2,0x07, // pinsrw MM6,EDX,7 0x0F,0xC4,0x75,0xD2,0x07, // pinsrw MM6,-02Eh[RBP],7 0x66, 0x0F,0xC4,0xF2,0x07, // pinsrw XMM6,EDX,7 0x66, 0x0F,0xC4,0x75,0xD2,0x07, // pinsrw XMM6,-02Eh[RBP],7 0x0F,0xF5,0xCA, // pmaddwd MM1,MM2 0x0F,0xF5,0x5D,0xD8, // pmaddwd MM3,-028h[RBP] 0x66, 0x0F,0xF5,0xCA, // pmaddwd XMM1,XMM2 0x66, 0x0F,0xF5,0x5D,0xE0, // pmaddwd XMM3,-020h[RBP] 0x0F,0xEE,0xCA, // pmaxsw MM1,XMM2 0x0F,0xEE,0x5D,0xD8, // pmaxsw MM3,-028h[RBP] 0x66, 0x0F,0xEE,0xCA, // pmaxsw XMM1,XMM2 0x66, 0x0F,0xEE,0x5D,0xE0, // pmaxsw XMM3,-020h[RBP] 0x0F,0xDE,0xCA, // pmaxub MM1,XMM2 0x0F,0xDE,0x5D,0xD8, // pmaxub MM3,-028h[RBP] 0x66, 0x0F,0xDE,0xCA, // pmaxub XMM1,XMM2 0x66, 0x0F,0xDE,0x5D,0xE0, // pmaxub XMM3,-020h[RBP] 0x0F,0xEA,0xCA, // pminsw MM1,MM2 0x0F,0xEA,0x5D,0xD8, // pminsw MM3,-028h[RBP] 0x66, 0x0F,0xEA,0xCA, // pminsw XMM1,XMM2 0x66, 0x0F,0xEA,0x5D,0xE0, // pminsw XMM3,-020h[RBP] 0x0F,0xDA,0xCA, // pminub MM1,MM2 0x0F,0xDA,0x5D,0xD8, // pminub MM3,-028h[RBP] 0x66, 0x0F,0xDA,0xCA, // pminub XMM1,XMM2 0x66, 0x0F,0xDA,0x5D,0xE0, // pminub XMM3,-020h[RBP] 0x0F,0xD7,0xC8, // pmovmskb ECX,MM0 0x66, 0x0F,0xD7,0xCE, // pmovmskb ECX,XMM6 0x0F,0xE4,0xCA, // pmulhuw MM1,MM2 0x0F,0xE4,0x5D,0xD8, // pmulhuw MM3,-028h[RBP] 0x66, 0x0F,0xE4,0xCA, // pmulhuw XMM1,XMM2 0x66, 0x0F,0xE4,0x5D,0xE0, // pmulhuw XMM3,-020h[RBP] 0x0F,0xE5,0xCA, // pmulhw MM1,MM2 0x0F,0xE5,0x5D,0xD8, // pmulhw MM3,-028h[RBP] 0x66, 0x0F,0xE5,0xCA, // pmulhw XMM1,XMM2 0x66, 0x0F,0xE5,0x5D,0xE0, // pmulhw XMM3,-020h[RBP] 0x0F,0xD5,0xCA, // pmullw MM1,MM2 0x0F,0xD5,0x5D,0xD8, // pmullw MM3,-028h[RBP] 0x66, 0x0F,0xD5,0xCA, // pmullw XMM1,XMM2 0x66, 0x0F,0xD5,0x5D,0xE0, // pmullw XMM3,-020h[RBP] 0x0F,0xF4,0xCA, // pmuludq MM1,MM2 0x0F,0xF4,0x5D,0xD8, // pmuludq MM3,-028h[RBP] 0x66, 0x0F,0xF4,0xCA, // pmuludq XMM1,XMM2 0x66, 0x0F,0xF4,0x5D,0xE0, // pmuludq XMM3,-020h[RBP] 0x0F,0xEB,0xCA, // por MM1,MM2 0x0F,0xEB,0x5D,0xD8, // por MM3,-028h[RBP] 0x66, 0x0F,0xEB,0xCA, // por XMM1,XMM2 0x66, 0x0F,0xEB,0x5D,0xE0, // por XMM3,-020h[RBP] 0x0F,0x18,0x4D,0xD0, // prefetcht0 -030h[RBP] 0x0F,0x18,0x55,0xD0, // prefetcht1 -030h[RBP] 0x0F,0x18,0x5D,0xD0, // prefetcht2 -030h[RBP] 0x0F,0x18,0x45,0xD0, // prefetchnta -030h[RBP] 0x0F,0xF6,0xCA, // psadbw MM1,MM2 0x0F,0xF6,0x5D,0xD8, // psadbw MM3,-028h[RBP] 0x66, 0x0F,0xF6,0xCA, // psadbw XMM1,XMM2 0x66, 0x0F,0xF6,0x5D,0xE0, // psadbw XMM3,-020h[RBP] 0x66, 0x0F,0x70,0xCA,0x03, // pshufd XMM1,XMM2,3 0x66, 0x0F,0x70,0x5D,0xE0,0x03, // pshufd XMM3,-020h[RBP],3 0xF3,0x0F,0x70,0xCA,0x03, // pshufhw XMM1,XMM2,3 0xF3,0x0F,0x70,0x5D,0xE0,0x03, // pshufhw XMM3,-020h[RBP],3 0xF2,0x0F,0x70,0xCA,0x03, // pshuflw XMM1,XMM2,3 0xF2,0x0F,0x70,0x5D,0xE0,0x03, // pshuflw XMM3,-020h[RBP],3 0x0F,0x70,0xCA,0x03, // pshufw MM1,MM2,3 0x0F,0x70,0x5D,0xD8,0x03, // pshufw MM3,-028h[RBP],3 0x66, 0x0F,0x73,0xF9,0x18, // pslldq XMM1,020h 0x0F,0xF1,0xCA, // psllw MM1,MM2 0x0F,0xF1,0x4D,0xD8, // psllw MM1,-028h[RBP] 0x66, 0x0F,0xF1,0xCA, // psllw XMM1,XMM2 0x66, 0x0F,0xF1,0x4D,0xE0, // psllw XMM1,-020h[RBP] 0x0F,0x71,0xF1,0x15, // psraw MM1,015h 0x66, 0x0F,0x71,0xF1,0x15, // psraw XMM1,015h 0x0F,0xF2,0xCA, // pslld MM1,MM2 0x0F,0xF2,0x4D,0xD8, // pslld MM1,-028h[RBP] 0x66, 0x0F,0xF2,0xCA, // pslld XMM1,XMM2 0x66, 0x0F,0xF2,0x4D,0xE0, // pslld XMM1,-020h[RBP] 0x0F,0x72,0xF1,0x15, // psrad MM1,015h 0x66, 0x0F,0x72,0xF1,0x15, // psrad XMM1,015h 0x0F,0xF3,0xCA, // psllq MM1,MM2 0x0F,0xF3,0x4D,0xD8, // psllq MM1,-028h[RBP] 0x66, 0x0F,0xF3,0xCA, // psllq XMM1,XMM2 0x66, 0x0F,0xF3,0x4D,0xE0, // psllq XMM1,-020h[RBP] 0x0F,0x73,0xF1,0x15, // psllq MM1,015h 0x66, 0x0F,0x73,0xF1,0x15, // psllq XMM1,015h 0x0F,0xE1,0xCA, // psraw MM1,MM2 0x0F,0xE1,0x4D,0xD8, // psraw MM1,-028h[RBP] 0x66, 0x0F,0xE1,0xCA, // psraw XMM1,XMM2 0x66, 0x0F,0xE1,0x4D,0xE0, // psraw XMM1,-020h[RBP] 0x0F,0x71,0xE1,0x15, // psraw MM1,015h 0x66, 0x0F,0x71,0xE1,0x15, // psraw XMM1,015h 0x0F,0xE2,0xCA, // psrad MM1,MM2 0x0F,0xE2,0x4D,0xD8, // psrad MM1,-028h[RBP] 0x66, 0x0F,0xE2,0xCA, // psrad XMM1,XMM2 0x66, 0x0F,0xE2,0x4D,0xE0, // psrad XMM1,-020h[RBP] 0x0F,0x72,0xE1,0x15, // psrad MM1,015h 0x66, 0x0F,0x72,0xE1,0x15, // psrad XMM1,015h 0x66, 0x0F,0x73,0xD9,0x18, // psrldq XMM1,020h 0x0F,0xD1,0xCA, // psrlw MM1,MM2 0x0F,0xD1,0x4D,0xD8, // psrlw MM1,-028h[RBP] 0x66, 0x0F,0xD1,0xCA, // psrlw XMM1,XMM2 0x66, 0x0F,0xD1,0x4D,0xE0, // psrlw XMM1,-020h[RBP] 0x0F,0x71,0xD1,0x15, // psrlw MM1,015h 0x66, 0x0F,0x71,0xD1,0x15, // psrlw XMM1,015h 0x0F,0xD2,0xCA, // psrld MM1,MM2 0x0F,0xD2,0x4D,0xD8, // psrld MM1,-028h[RBP] 0x66, 0x0F,0xD2,0xCA, // psrld XMM1,XMM2 0x66, 0x0F,0xD2,0x4D,0xE0, // psrld XMM1,-020h[RBP] 0x0F,0x72,0xD1,0x15, // psrld MM1,015h 0x66, 0x0F,0x72,0xD1,0x15, // psrld XMM1,015h 0x0F,0xD3,0xCA, // psrlq MM1,MM2 0x0F,0xD3,0x4D,0xD8, // psrlq MM1,-028h[RBP] 0x66, 0x0F,0xD3,0xCA, // psrlq XMM1,XMM2 0x66, 0x0F,0xD3,0x4D,0xE0, // psrlq XMM1,-020h[RBP] 0x0F,0x73,0xD1,0x15, // psrlq MM1,015h 0x66, 0x0F,0x73,0xD1,0x15, // psrlq XMM1,015h 0x0F,0xF8,0xCA, // psubb MM1,MM2 0x0F,0xF8,0x4D,0xD8, // psubb MM1,-028h[RBP] 0x66, 0x0F,0xF8,0xCA, // psubb XMM1,XMM2 0x66, 0x0F,0xF8,0x4D,0xE0, // psubb XMM1,-020h[RBP] 0x0F,0xF9,0xCA, // psubw MM1,MM2 0x0F,0xF9,0x4D,0xD8, // psubw MM1,-028h[RBP] 0x66, 0x0F,0xF9,0xCA, // psubw XMM1,XMM2 0x66, 0x0F,0xF9,0x4D,0xE0, // psubw XMM1,-020h[RBP] 0x0F,0xFA,0xCA, // psubd MM1,MM2 0x0F,0xFA,0x4D,0xD8, // psubd MM1,-028h[RBP] 0x66, 0x0F,0xFA,0xCA, // psubd XMM1,XMM2 0x66, 0x0F,0xFA,0x4D,0xE0, // psubd XMM1,-020h[RBP] 0x0F,0xFB,0xCA, // psubq MM1,MM2 0x0F,0xFB,0x4D,0xD8, // psubq MM1,-028h[RBP] 0x66, 0x0F,0xFB,0xCA, // psubq XMM1,XMM2 0x66, 0x0F,0xFB,0x4D,0xE0, // psubq XMM1,-020h[RBP] 0x0F,0xE8,0xCA, // psubsb MM1,MM2 0x0F,0xE8,0x4D,0xD8, // psubsb MM1,-028h[RBP] 0x66, 0x0F,0xE8,0xCA, // psubsb XMM1,XMM2 0x66, 0x0F,0xE8,0x4D,0xE0, // psubsb XMM1,-020h[RBP] 0x0F,0xE9,0xCA, // psubsw MM1,MM2 0x0F,0xE9,0x4D,0xD8, // psubsw MM1,-028h[RBP] 0x66, 0x0F,0xE9,0xCA, // psubsw XMM1,XMM2 0x66, 0x0F,0xE9,0x4D,0xE0, // psubsw XMM1,-020h[RBP] 0x0F,0xD8,0xCA, // psubusb MM1,MM2 0x0F,0xD8,0x4D,0xD8, // psubusb MM1,-028h[RBP] 0x66, 0x0F,0xD8,0xCA, // psubusb XMM1,XMM2 0x66, 0x0F,0xD8,0x4D,0xE0, // psubusb XMM1,-020h[RBP] 0x0F,0xD9,0xCA, // psubusw MM1,MM2 0x0F,0xD9,0x4D,0xD8, // psubusw MM1,-028h[RBP] 0x66, 0x0F,0xD9,0xCA, // psubusw XMM1,XMM2 0x66, 0x0F,0xD9,0x4D,0xE0, // psubusw XMM1,-020h[RBP] 0x0F,0x68,0xCA, // punpckhbw MM1,MM2 0x0F,0x68,0x4D,0xD8, // punpckhbw MM1,-028h[RBP] 0x66, 0x0F,0x68,0xCA, // punpckhbw XMM1,XMM2 0x66, 0x0F,0x68,0x4D,0xE0, // punpckhbw XMM1,-020h[RBP] 0x0F,0x69,0xCA, // punpckhwd MM1,MM2 0x0F,0x69,0x4D,0xD8, // punpckhwd MM1,-028h[RBP] 0x66, 0x0F,0x69,0xCA, // punpckhwd XMM1,XMM2 0x66, 0x0F,0x69,0x4D,0xE0, // punpckhwd XMM1,-020h[RBP] 0x0F,0x6A,0xCA, // punpckhdq MM1,MM2 0x0F,0x6A,0x4D,0xD8, // punpckhdq MM1,-028h[RBP] 0x66, 0x0F,0x6A,0xCA, // punpckhdq XMM1,XMM2 0x66, 0x0F,0x6A,0x4D,0xE0, // punpckhdq XMM1,-020h[RBP] 0x66, 0x0F,0x6D,0xCA, // punpckhqdq XMM1,XMM2 0x66, 0x0F,0x6D,0x4D,0xE0, // punpckhqdq XMM1,-020h[RBP] 0x0F,0x60,0xCA, // punpcklbw MM1,MM2 0x0F,0x60,0x4D,0xD8, // punpcklbw MM1,-028h[RBP] 0x66, 0x0F,0x60,0xCA, // punpcklbw XMM1,XMM2 0x66, 0x0F,0x60,0x4D,0xE0, // punpcklbw XMM1,-020h[RBP] 0x0F,0x61,0xCA, // punpcklwd MM1,MM2 0x0F,0x61,0x4D,0xD8, // punpcklwd MM1,-028h[RBP] 0x66, 0x0F,0x61,0xCA, // punpcklwd XMM1,XMM2 0x66, 0x0F,0x61,0x4D,0xE0, // punpcklwd XMM1,-020h[RBP] 0x0F,0x62,0xCA, // punpckldq MM1,MM2 0x0F,0x62,0x4D,0xD8, // punpckldq MM1,-028h[RBP] 0x66, 0x0F,0x62,0xCA, // punpckldq XMM1,XMM2 0x66, 0x0F,0x62,0x4D,0xE0, // punpckldq XMM1,-020h[RBP] 0x66, 0x0F,0x6C,0xCA, // punpcklqdq XMM1,XMM2 0x66, 0x0F,0x6C,0x4D,0xE0, // punpcklqdq XMM1,-020h[RBP] 0x0F,0xEF,0xCA, // pxor MM1,MM2 0x0F,0xEF,0x4D,0xD8, // pxor MM1,-028h[RBP] 0x66, 0x0F,0xEF,0xCA, // pxor XMM1,XMM2 0x66, 0x0F,0xEF,0x4D,0xE0, // pxor XMM1,-020h[RBP] 0x0F,0x53,0xCA, // rcpps XMM1,XMM2 0x0F,0x53,0x4D,0xE0, // rcpps XMM1,-020h[RBP] 0xF3,0x0F,0x53,0xCA, // rcpss XMM1,XMM2 0xF3,0x0F,0x53,0x4D,0xD4, // rcpss XMM1,-02Ch[RBP] 0x0F,0x52,0xCA, // rsqrtps XMM1,XMM2 0x0F,0x52,0x4D,0xE0, // rsqrtps XMM1,-020h[RBP] 0xF3,0x0F,0x52,0xCA, // rsqrtss XMM1,XMM2 0xF3,0x0F,0x52,0x4D,0xD4, // rsqrtss XMM1,-02Ch[RBP] 0x66, 0x0F,0xC6,0xCA,0x03, // shufpd XMM1,XMM2,3 0x66, 0x0F,0xC6,0x4D,0xE0,0x04, // shufpd XMM1,-020h[RBP],4 0x0F,0xC6,0xCA,0x03, // shufps XMM1,XMM2,3 0x0F,0xC6,0x4D,0xE0,0x04, // shufps XMM1,-020h[RBP],4 0x66, 0x0F,0x2E,0xE6, // ucimisd XMM4,XMM6 0x66, 0x0F,0x2E,0x6D,0xD8, // ucimisd XMM5,-028h[RBP] 0x0F,0x2E,0xF7, // ucomiss XMM6,XMM7 0x0F,0x2E,0x7D,0xD4, // ucomiss XMM7,-02Ch[RBP] 0x66, 0x0F,0x15,0xE6, // uppckhpd XMM4,XMM6 0x66, 0x0F,0x15,0x6D,0xE0, // uppckhpd XMM5,-020h[RBP] 0x0F,0x15,0xE6, // unpckhps XMM4,XMM6 0x0F,0x15,0x6D,0xE0, // unpckhps XMM5,-020h[RBP] 0x66, 0x0F,0x14,0xE6, // uppcklpd XMM4,XMM6 0x66, 0x0F,0x14,0x6D,0xE0, // uppcklpd XMM5,-020h[RBP] 0x0F,0x14,0xE6, // unpcklps XMM4,XMM6 0x0F,0x14,0x6D,0xE0, // unpcklps XMM5,-020h[RBP] 0x66, 0x0F,0x57,0xCA, // xorpd XMM1,XMM2 0x66, 0x0F,0x57,0x4D,0xE0, // xorpd XMM1,-020h[RBP] 0x0F,0x57,0xCA, // xorps XMM1,XMM2 0x0F,0x57,0x4D,0xE0, // xorps XMM1,-020h[RBP] ]; int i; asm { call L1 ; movmskpd ESI,XMM3 ; movmskps ESI,XMM3 ; movntdq m128[RBP],XMM2 ; movnti m32[RBP],ECX ; movntpd m128[RBP],XMM3 ; movntps m128[RBP],XMM4 ; movntq m64[RBP],MM5 ; movq MM1,MM2 ; movq MM2,m64[RBP] ; movq m64[RBP],MM3 ; movq XMM1,XMM2 ; movq XMM2,m64[RBP] ; movq m64[RBP],XMM3 ; movq2dq XMM3,MM2 ; movsd ; movsd XMM1,XMM2 ; movsd XMM3,m64[RBP] ; movsd m64[RBP],XMM4 ; movss XMM1,XMM2 ; movss XMM3,m32[RBP] ; movss m32[RBP],XMM4 ; movupd XMM1,XMM2 ; movupd XMM3,m128[RBP] ; movupd m128[RBP],XMM4 ; movups XMM1,XMM2 ; movups XMM3,m128[RBP] ; movups m128[RBP],XMM4 ; orpd XMM1,XMM2 ; orpd XMM3,m128[RBP] ; orps XMM1,XMM2 ; orps XMM3,m128[RBP] ; packsswb MM1,MM2 ; packsswb MM3,m64[RBP] ; packsswb XMM1,XMM2 ; packsswb XMM3,m128[RBP] ; packssdw MM1,MM2 ; packssdw MM3,m64[RBP] ; packssdw XMM1,XMM2 ; packssdw XMM3,m128[RBP] ; packuswb MM1,MM2 ; packuswb MM3,m64[RBP] ; packuswb XMM1,XMM2 ; packuswb XMM3,m128[RBP] ; paddb MM1,MM2 ; paddb MM3,m64[RBP] ; paddb XMM1,XMM2 ; paddb XMM3,m128[RBP] ; paddw MM1,MM2 ; paddw MM3,m64[RBP] ; paddw XMM1,XMM2 ; paddw XMM3,m128[RBP] ; paddd MM1,MM2 ; paddd MM3,m64[RBP] ; paddd XMM1,XMM2 ; paddd XMM3,m128[RBP] ; paddq MM1,MM2 ; paddq MM3,m64[RBP] ; paddq XMM1,XMM2 ; paddq XMM3,m128[RBP] ; paddsb MM1,MM2 ; paddsb MM3,m64[RBP] ; paddsb XMM1,XMM2 ; paddsb XMM3,m128[RBP] ; paddsw MM1,MM2 ; paddsw MM3,m64[RBP] ; paddsw XMM1,XMM2 ; paddsw XMM3,m128[RBP] ; paddusb MM1,MM2 ; paddusb MM3,m64[RBP] ; paddusb XMM1,XMM2 ; paddusb XMM3,m128[RBP] ; paddusw MM1,MM2 ; paddusw MM3,m64[RBP] ; paddusw XMM1,XMM2 ; paddusw XMM3,m128[RBP] ; pand MM1,MM2 ; pand MM3,m64[RBP] ; pand XMM1,XMM2 ; pand XMM3,m128[RBP] ; pandn MM1,MM2 ; pandn MM3,m64[RBP] ; pandn XMM1,XMM2 ; pandn XMM3,m128[RBP] ; pavgb MM1,MM2 ; pavgb MM3,m64[RBP] ; pavgb XMM1,XMM2 ; pavgb XMM3,m128[RBP] ; pavgw MM1,MM2 ; pavgw MM3,m64[RBP] ; pavgw XMM1,XMM2 ; pavgw XMM3,m128[RBP] ; pcmpeqb MM1,MM2 ; pcmpeqb MM3,m64[RBP] ; pcmpeqb XMM1,XMM2 ; pcmpeqb XMM3,m128[RBP] ; pcmpeqw MM1,MM2 ; pcmpeqw MM3,m64[RBP] ; pcmpeqw XMM1,XMM2 ; pcmpeqw XMM3,m128[RBP] ; pcmpeqd MM1,MM2 ; pcmpeqd MM3,m64[RBP] ; pcmpeqd XMM1,XMM2 ; pcmpeqd XMM3,m128[RBP] ; pcmpgtb MM1,MM2 ; pcmpgtb MM3,m64[RBP] ; pcmpgtb XMM1,XMM2 ; pcmpgtb XMM3,m128[RBP] ; pcmpgtw MM1,MM2 ; pcmpgtw MM3,m64[RBP] ; pcmpgtw XMM1,XMM2 ; pcmpgtw XMM3,m128[RBP] ; pcmpgtd MM1,MM2 ; pcmpgtd MM3,m64[RBP] ; pcmpgtd XMM1,XMM2 ; pcmpgtd XMM3,m128[RBP] ; pextrw EDX,MM6,7 ; pextrw EDX,XMM6,7 ; pinsrw MM6,EDX,7 ; pinsrw MM6,m16[RBP],7 ; pinsrw XMM6,EDX,7 ; pinsrw XMM6,m16[RBP],7 ; pmaddwd MM1,MM2 ; pmaddwd MM3,m64[RBP] ; pmaddwd XMM1,XMM2 ; pmaddwd XMM3,m128[RBP] ; pmaxsw MM1,MM2 ; pmaxsw MM3,m64[RBP] ; pmaxsw XMM1,XMM2 ; pmaxsw XMM3,m128[RBP] ; pmaxub MM1,MM2 ; pmaxub MM3,m64[RBP] ; pmaxub XMM1,XMM2 ; pmaxub XMM3,m128[RBP] ; pminsw MM1,MM2 ; pminsw MM3,m64[RBP] ; pminsw XMM1,XMM2 ; pminsw XMM3,m128[RBP] ; pminub MM1,MM2 ; pminub MM3,m64[RBP] ; pminub XMM1,XMM2 ; pminub XMM3,m128[RBP] ; pmovmskb ECX,MM0 ; pmovmskb ECX,XMM6 ; pmulhuw MM1,MM2 ; pmulhuw MM3,m64[RBP] ; pmulhuw XMM1,XMM2 ; pmulhuw XMM3,m128[RBP] ; pmulhw MM1,MM2 ; pmulhw MM3,m64[RBP] ; pmulhw XMM1,XMM2 ; pmulhw XMM3,m128[RBP] ; pmullw MM1,MM2 ; pmullw MM3,m64[RBP] ; pmullw XMM1,XMM2 ; pmullw XMM3,m128[RBP] ; pmuludq MM1,MM2 ; pmuludq MM3,m64[RBP] ; pmuludq XMM1,XMM2 ; pmuludq XMM3,m128[RBP] ; por MM1,MM2 ; por MM3,m64[RBP] ; por XMM1,XMM2 ; por XMM3,m128[RBP] ; prefetcht0 m8[RBP] ; prefetcht1 m8[RBP] ; prefetcht2 m8[RBP] ; prefetchnta m8[RBP] ; psadbw MM1,MM2 ; psadbw MM3,m64[RBP] ; psadbw XMM1,XMM2 ; psadbw XMM3,m128[RBP] ; pshufd XMM1,XMM2,3 ; pshufd XMM3,m128[RBP],3 ; pshufhw XMM1,XMM2,3 ; pshufhw XMM3,m128[RBP],3 ; pshuflw XMM1,XMM2,3 ; pshuflw XMM3,m128[RBP],3 ; pshufw MM1,MM2,3 ; pshufw MM3,m64[RBP],3 ; pslldq XMM1,0x18 ; psllw MM1,MM2 ; psllw MM1,m64[RBP] ; psllw XMM1,XMM2 ; psllw XMM1,m128[RBP] ; psllw MM1,0x15 ; psllw XMM1,0x15 ; pslld MM1,MM2 ; pslld MM1,m64[RBP] ; pslld XMM1,XMM2 ; pslld XMM1,m128[RBP] ; pslld MM1,0x15 ; pslld XMM1,0x15 ; psllq MM1,MM2 ; psllq MM1,m64[RBP] ; psllq XMM1,XMM2 ; psllq XMM1,m128[RBP] ; psllq MM1,0x15 ; psllq XMM1,0x15 ; psraw MM1,MM2 ; psraw MM1,m64[RBP] ; psraw XMM1,XMM2 ; psraw XMM1,m128[RBP] ; psraw MM1,0x15 ; psraw XMM1,0x15 ; psrad MM1,MM2 ; psrad MM1,m64[RBP] ; psrad XMM1,XMM2 ; psrad XMM1,m128[RBP] ; psrad MM1,0x15 ; psrad XMM1,0x15 ; psrldq XMM1,0x18 ; psrlw MM1,MM2 ; psrlw MM1,m64[RBP] ; psrlw XMM1,XMM2 ; psrlw XMM1,m128[RBP] ; psrlw MM1,0x15 ; psrlw XMM1,0x15 ; psrld MM1,MM2 ; psrld MM1,m64[RBP] ; psrld XMM1,XMM2 ; psrld XMM1,m128[RBP] ; psrld MM1,0x15 ; psrld XMM1,0x15 ; psrlq MM1,MM2 ; psrlq MM1,m64[RBP] ; psrlq XMM1,XMM2 ; psrlq XMM1,m128[RBP] ; psrlq MM1,0x15 ; psrlq XMM1,0x15 ; psubb MM1,MM2 ; psubb MM1,m64[RBP] ; psubb XMM1,XMM2 ; psubb XMM1,m128[RBP] ; psubw MM1,MM2 ; psubw MM1,m64[RBP] ; psubw XMM1,XMM2 ; psubw XMM1,m128[RBP] ; psubd MM1,MM2 ; psubd MM1,m64[RBP] ; psubd XMM1,XMM2 ; psubd XMM1,m128[RBP] ; psubq MM1,MM2 ; psubq MM1,m64[RBP] ; psubq XMM1,XMM2 ; psubq XMM1,m128[RBP] ; psubsb MM1,MM2 ; psubsb MM1,m64[RBP] ; psubsb XMM1,XMM2 ; psubsb XMM1,m128[RBP] ; psubsw MM1,MM2 ; psubsw MM1,m64[RBP] ; psubsw XMM1,XMM2 ; psubsw XMM1,m128[RBP] ; psubusb MM1,MM2 ; psubusb MM1,m64[RBP] ; psubusb XMM1,XMM2 ; psubusb XMM1,m128[RBP] ; psubusw MM1,MM2 ; psubusw MM1,m64[RBP] ; psubusw XMM1,XMM2 ; psubusw XMM1,m128[RBP] ; punpckhbw MM1,MM2 ; punpckhbw MM1,m64[RBP] ; punpckhbw XMM1,XMM2 ; punpckhbw XMM1,m128[RBP] ; punpckhwd MM1,MM2 ; punpckhwd MM1,m64[RBP] ; punpckhwd XMM1,XMM2 ; punpckhwd XMM1,m128[RBP] ; punpckhdq MM1,MM2 ; punpckhdq MM1,m64[RBP] ; punpckhdq XMM1,XMM2 ; punpckhdq XMM1,m128[RBP] ; punpckhqdq XMM1,XMM2 ; punpckhqdq XMM1,m128[RBP] ; punpcklbw MM1,MM2 ; punpcklbw MM1,m64[RBP] ; punpcklbw XMM1,XMM2 ; punpcklbw XMM1,m128[RBP] ; punpcklwd MM1,MM2 ; punpcklwd MM1,m64[RBP] ; punpcklwd XMM1,XMM2 ; punpcklwd XMM1,m128[RBP] ; punpckldq MM1,MM2 ; punpckldq MM1,m64[RBP] ; punpckldq XMM1,XMM2 ; punpckldq XMM1,m128[RBP] ; punpcklqdq XMM1,XMM2 ; punpcklqdq XMM1,m128[RBP] ; pxor MM1,MM2 ; pxor MM1,m64[RBP] ; pxor XMM1,XMM2 ; pxor XMM1,m128[RBP] ; rcpps XMM1,XMM2 ; rcpps XMM1,m128[RBP] ; rcpss XMM1,XMM2 ; rcpss XMM1,m32[RBP] ; rsqrtps XMM1,XMM2 ; rsqrtps XMM1,m128[RBP] ; rsqrtss XMM1,XMM2 ; rsqrtss XMM1,m32[RBP] ; shufpd XMM1,XMM2,3 ; shufpd XMM1,m128[RBP],4 ; shufps XMM1,XMM2,3 ; shufps XMM1,m128[RBP],4 ; ucomisd XMM4,XMM6 ; ucomisd XMM5,m64[RBP] ; ucomiss XMM6,XMM7 ; ucomiss XMM7,m32[RBP] ; unpckhpd XMM4,XMM6 ; unpckhpd XMM5,m128[RBP] ; unpckhps XMM4,XMM6 ; unpckhps XMM5,m128[RBP] ; unpcklpd XMM4,XMM6 ; unpcklpd XMM5,m128[RBP] ; unpcklps XMM4,XMM6 ; unpcklps XMM5,m128[RBP] ; xorpd XMM1,XMM2 ; xorpd XMM1,m128[RBP] ; xorps XMM1,XMM2 ; xorps XMM1,m128[RBP] ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], data[i]); assert(p[i] == data[i]); } } /****************************************************/ void test15() { int m32; long m64; M128 m128; ubyte *p; static ubyte data[] = [ 0x0F,0x0F,0xDC,0xBF, // pavgusb MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xBF, // pavgusb MM3,-028h[RBP] 0x0F,0x0F,0xDC,0x1D, // pf2id MM3,MM4 0x0F,0x0F,0x5D,0xD8,0x1D, // pf2id MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xAE, // pfacc MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xAE, // pfacc MM3,-028h[RBP] 0x0F,0x0F,0xDC,0x9E, // pfadd MM3,MM4 0x0F,0x0F,0x5D,0xD8,0x9E, // pfadd MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xB0, // pfcmpeq MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xB0, // pfcmpeq MM3,-028h[RBP] 0x0F,0x0F,0xDC,0x90, // pfcmpge MM3,MM4 0x0F,0x0F,0x5D,0xD8,0x90, // pfcmpge MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xA0, // pfcmpgt MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xA0, // pfcmpgt MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xA4, // pfmax MM3,MM4 0x0F,0x0F,0x5D,0xD8,0x94, // pfmin MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xB4, // pfmul MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xB4, // pfmul MM3,-028h[RBP] 0x0F,0x0F,0xDC,0x8A, // pfnacc MM3,MM4 0x0F,0x0F,0x5D,0xD8,0x8E, // pfpnacc MM3,-028h[RBP] 0x0F,0x0F,0xDC,0x96, // pfrcp MM3,MM4 0x0F,0x0F,0x5D,0xD8,0x96, // pfrcp MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xA6, // pfrcpit1 MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xA6, // pfrcpit1 MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xB6, // pfrcpit2 MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xB6, // pfrcpit2 MM3,-028h[RBP] 0x0F,0x0F,0xDC,0x97, // pfrsqrt MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xA7, // pfrsqit1 MM3,-028h[RBP] 0x0F,0x0F,0xDC,0x9A, // pfsub MM3,MM4 0x0F,0x0F,0x5D,0xD8,0x9A, // pfsub MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xAA, // pfsubr MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xAA, // pfsubr MM3,-028h[RBP] 0x0F,0x0F,0xDC,0x0D, // pi2fd MM3,MM4 0x0F,0x0F,0x5D,0xD8,0x0D, // pi2fd MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xB7, // pmulhrw MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xB7, // pmulhrw MM3,-028h[RBP] 0x0F,0x0F,0xDC,0xBB, // pswapd MM3,MM4 0x0F,0x0F,0x5D,0xD8,0xBB, // pswapd MM3,-028h[RBP] ]; int i; asm { call L1 ; pavgusb MM3,MM4 ; pavgusb MM3,m64[RBP] ; pf2id MM3,MM4 ; pf2id MM3,m64[RBP] ; pfacc MM3,MM4 ; pfacc MM3,m64[RBP] ; pfadd MM3,MM4 ; pfadd MM3,m64[RBP] ; pfcmpeq MM3,MM4 ; pfcmpeq MM3,m64[RBP] ; pfcmpge MM3,MM4 ; pfcmpge MM3,m64[RBP] ; pfcmpgt MM3,MM4 ; pfcmpgt MM3,m64[RBP] ; pfmax MM3,MM4 ; pfmin MM3,m64[RBP] ; pfmul MM3,MM4 ; pfmul MM3,m64[RBP] ; pfnacc MM3,MM4 ; pfpnacc MM3,m64[RBP] ; pfrcp MM3,MM4 ; pfrcp MM3,m64[RBP] ; pfrcpit1 MM3,MM4 ; pfrcpit1 MM3,m64[RBP] ; pfrcpit2 MM3,MM4 ; pfrcpit2 MM3,m64[RBP] ; pfrsqrt MM3,MM4 ; pfrsqit1 MM3,m64[RBP] ; pfsub MM3,MM4 ; pfsub MM3,m64[RBP] ; pfsubr MM3,MM4 ; pfsubr MM3,m64[RBP] ; pi2fd MM3,MM4 ; pi2fd MM3,m64[RBP] ; pmulhrw MM3,MM4 ; pmulhrw MM3,m64[RBP] ; pswapd MM3,MM4 ; pswapd MM3,m64[RBP] ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ struct S17 { char x[6]; } __gshared S17 xx17; void test17() { ubyte *p; static ubyte data[] = [ 0x0F, 0x01, 0x10, // lgdt [EAX] 0x0F, 0x01, 0x18, // lidt [EAX] 0x0F, 0x01, 0x00, // sgdt [EAX] 0x0F, 0x01, 0x08, // sidt [EAX] ]; int i; asm { call L1 ; lgdt [RAX] ; lidt [RAX] ; sgdt [RAX] ; sidt [RAX] ; lgdt xx17 ; lidt xx17 ; sgdt xx17 ; sidt xx17 ; L1: pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ void test18() { ubyte *p; static ubyte data[] = [ 0xDB, 0xF1, // fcomi ST,ST(1) 0xDB, 0xF0, // fcomi ST,ST(0) 0xDB, 0xF2, // fcomi ST,ST(2) 0xDF, 0xF1, // fcomip ST,ST(1) 0xDF, 0xF0, // fcomip ST,ST(0) 0xDF, 0xF2, // fcomip ST,ST(2) 0xDB, 0xE9, // fucomi ST,ST(1) 0xDB, 0xE8, // fucomi ST,ST(0) 0xDB, 0xEB, // fucomi ST,ST(3) 0xDF, 0xE9, // fucomip ST,ST(1) 0xDF, 0xED, // fucomip ST,ST(5) 0xDF, 0xEC, // fucomip ST,ST(4) ]; int i; asm { call L1 ; fcomi ; fcomi ST(0) ; fcomi ST,ST(2) ; fcomip ; fcomip ST(0) ; fcomip ST,ST(2) ; fucomi ; fucomi ST(0) ; fucomi ST,ST(3) ; fucomip ; fucomip ST(5) ; fucomip ST,ST(4) ; L1: pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ extern (C) { void foo19() { } } void test19() { void function() fp; ulong x; ulong *p; asm { lea RAX, qword ptr [foo19]; mov fp, RAX; mov x, RAX; mov p, RAX; call fp; } (*fp)(); } /****************************************************/ /+ void test20() { ubyte *p; static ubyte data[] = [ 0x9B, 0xDB, 0xE0, // feni 0xDB, 0xE0, // fneni 0x9B, 0xDB, 0xE1, // fdisi 0xDB, 0xE1, // fndisi 0x9B, 0xDB, 0xE2, // fclex 0xDB, 0xE2, // fnclex 0x9B, 0xDB, 0xE3, // finit 0xDB, 0xE3, // fninit 0xDB, 0xE4, // fsetpm ]; int i; asm { call L1 ; feni ; fneni ; fdisi ; fndisi ; finit ; fninit ; fclex ; fnclex ; finit ; fninit ; fsetpm ; L1: pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } +/ /****************************************************/ void test21() { ubyte *p; static ubyte data[] = [ 0xE4, 0x06, // in AL,6 0x66, 0xE5, 0x07, // in AX,7 0xE5, 0x08, // in EAX,8 0xEC, // in AL,DX 0x66, 0xED, // in AX,DX 0xED, // in EAX,DX 0xE6, 0x06, // out 6,AL 0x66, 0xE7, 0x07, // out 7,AX 0xE7, 0x08, // out 8,EAX 0xEE, // out DX,AL 0x66, 0xEF, // out DX,AX 0xEF, // out DX,EAX ]; int i; asm { call L1 ; in AL,6 ; in AX,7 ; in EAX,8 ; in AL,DX ; in AX,DX ; in EAX,DX ; out 6,AL ; out 7,AX ; out 8,EAX ; out DX,AL ; out DX,AX ; out DX,EAX ; L1: pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ void test22() { ubyte *p; static ubyte data[] = [ 0x0F, 0xC7, 0x4D, 0xE0, // cmpxchg8b 0x48, 0x0F, 0xC7, 0x4D, 0xF0 // cmpxchg16b ]; int i; M64 m64; M128 m128; asm { call L1 ; cmpxchg8b m64 ; cmpxchg16b m128 ; L1: pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ void test23() { short m16; int m32; long m64; M128 m128; ubyte *p; static ubyte data[] = [ 0xD9, 0xC9, // fxch ST(1), ST(0) 0xDF, 0x5D, 0xD0, // fistp word ptr -030h[RBP] 0xDB, 0x5D, 0xD4, // fistp dword ptr -02Ch[RBP] 0xDF, 0x7D, 0xD8, // fistp long64 ptr -028h[RBP] 0xDF, 0x4D, 0xD0, // fisttp short ptr -030h[RBP] 0xDB, 0x4D, 0xD4, // fisttp word ptr -02Ch[RBP] 0xDD, 0x4D, 0xD8, // fisttp long64 ptr -028h[RBP] 0x0F, 0x01, 0xC8, // monitor 0x0F, 0x01, 0xC9, // mwait 0x0F, 0x01, 0xD0, // xgetbv 0x66, 0x0F, 0xD0, 0xCA, // addsubpd XMM1,XMM2 0x66, 0x0F, 0xD0, 0x4D, 0xE0, // addsubpd XMM1,-020h[RBP] 0xF2, 0x0F, 0xD0, 0xCA, // addsubps XMM1,XMM2 0xF2, 0x0F, 0xD0, 0x4D, 0xE0, // addsubps XMM1,-020h[RBP] 0x66, 0x0F, 0x7C, 0xCA, // haddpd XMM1,XMM2 0x66, 0x0F, 0x7C, 0x4D, 0xE0, // haddpd XMM1,-020h[RBP] 0xF2, 0x0F, 0x7C, 0xCA, // haddps XMM1,XMM2 0xF2, 0x0F, 0x7C, 0x4D, 0xE0, // haddps XMM1,-020h[RBP] 0x66, 0x0F, 0x7D, 0xCA, // hsubpd XMM1,XMM2 0x66, 0x0F, 0x7D, 0x4D, 0xE0, // hsubpd XMM1,-020h[RBP] 0xF2, 0x0F, 0x7D, 0xCA, // hsubps XMM1,XMM2 0xF2, 0x0F, 0x7D, 0x4D, 0xE0, // hsubps XMM1,-020h[RBP] 0xF2, 0x0F, 0xF0, 0x4D, 0xE0, // lddqu XMM1,-020h[RBP] 0xF2, 0x0F, 0x12, 0xCA, // movddup XMM1,XMM2 0xF2, 0x0F, 0x12, 0x4D, 0xD8, // movddup XMM1,-028h[RBP] 0xF3, 0x0F, 0x16, 0xCA, // movshdup XMM1,XMM2 0xF3, 0x0F, 0x16, 0x4D, 0xE0, // movshdup XMM1,-020h[RBP] 0xF3, 0x0F, 0x12, 0xCA, // movsldup XMM1,XMM2 0xF3, 0x0F, 0x12, 0x4D, 0xE0, // movsldup XMM1,-020h[RBP] ]; int i; asm { call L1 ; fxch ST(1), ST(0) ; fistp m16[RBP] ; fistp m32[RBP] ; fistp m64[RBP] ; fisttp m16[RBP] ; fisttp m32[RBP] ; fisttp m64[RBP] ; monitor ; mwait ; xgetbv ; addsubpd XMM1,XMM2 ; addsubpd XMM1,m128[RBP] ; addsubps XMM1,XMM2 ; addsubps XMM1,m128[RBP] ; haddpd XMM1,XMM2 ; haddpd XMM1,m128[RBP] ; haddps XMM1,XMM2 ; haddps XMM1,m128[RBP] ; hsubpd XMM1,XMM2 ; hsubpd XMM1,m128[RBP] ; hsubps XMM1,XMM2 ; hsubps XMM1,m128[RBP] ; lddqu XMM1,m128[RBP] ; movddup XMM1,XMM2 ; movddup XMM1,m64[RBP] ; movshdup XMM1,XMM2 ; movshdup XMM1,m128[RBP] ; movsldup XMM1,XMM2 ; movsldup XMM1,m128[RBP] ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ void test24() { ushort i; asm { lea AX, i; mov i, AX; } assert(cast(ushort)&i == i); } /****************************************************/ void test25() { short m16; int m32; long m64; M128 m128; ubyte *p; static ubyte data[] = [ 0x66, 0x0F, 0x7E, 0xC1, // movd ECX,XMM0 0x66, 0x0F, 0x7E, 0xC9, // movd ECX,XMM1 0x66, 0x0F, 0x7E, 0xD1, // movd ECX,XMM2 0x66, 0x0F, 0x7E, 0xD9, // movd ECX,XMM3 0x66, 0x0F, 0x7E, 0xE1, // movd ECX,XMM4 0x66, 0x0F, 0x7E, 0xE9, // movd ECX,XMM5 0x66, 0x0F, 0x7E, 0xF1, // movd ECX,XMM6 0x66, 0x0F, 0x7E, 0xF9, // movd ECX,XMM7 0x0F, 0x7E, 0xC1, // movd ECX,MM0 0x0F, 0x7E, 0xC9, // movd ECX,MM1 0x0F, 0x7E, 0xD1, // movd ECX,MM2 0x0F, 0x7E, 0xD9, // movd ECX,MM3 0x0F, 0x7E, 0xE1, // movd ECX,MM4 0x0F, 0x7E, 0xE9, // movd ECX,MM5 0x0F, 0x7E, 0xF1, // movd ECX,MM6 0x0F, 0x7E, 0xF9, // movd ECX,MM7 0x66, 0x0F, 0x6E, 0xC1, // movd XMM0,ECX 0x66, 0x0F, 0x6E, 0xC9, // movd XMM1,ECX 0x66, 0x0F, 0x6E, 0xD1, // movd XMM2,ECX 0x66, 0x0F, 0x6E, 0xD9, // movd XMM3,ECX 0x66, 0x0F, 0x6E, 0xE1, // movd XMM4,ECX 0x66, 0x0F, 0x6E, 0xE9, // movd XMM5,ECX 0x66, 0x0F, 0x6E, 0xF1, // movd XMM6,ECX 0x66, 0x0F, 0x6E, 0xF9, // movd XMM7,ECX 0x0F, 0x6E, 0xC1, // movd MM0,ECX 0x0F, 0x6E, 0xC9, // movd MM1,ECX 0x0F, 0x6E, 0xD1, // movd MM2,ECX 0x0F, 0x6E, 0xD9, // movd MM3,ECX 0x0F, 0x6E, 0xE1, // movd MM4,ECX 0x0F, 0x6E, 0xE9, // movd MM5,ECX 0x0F, 0x6E, 0xF1, // movd MM6,ECX 0x0F, 0x6E, 0xF9, // movd MM7,ECX 0x66, 0x0F, 0x7E, 0xC8, // movd EAX,XMM1 0x66, 0x0F, 0x7E, 0xCB, // movd EBX,XMM1 0x66, 0x0F, 0x7E, 0xC9, // movd ECX,XMM1 0x66, 0x0F, 0x7E, 0xCA, // movd EDX,XMM1 0x66, 0x0F, 0x7E, 0xCE, // movd ESI,XMM1 0x66, 0x0F, 0x7E, 0xCF, // movd EDI,XMM1 0x66, 0x0F, 0x7E, 0xCD, // movd EBP,XMM1 0x66, 0x0F, 0x7E, 0xCC, // movd ESP,XMM1 0x0F, 0x7E, 0xC8, // movd EAX,MM1 0x0F, 0x7E, 0xCB, // movd EBX,MM1 0x0F, 0x7E, 0xC9, // movd ECX,MM1 0x0F, 0x7E, 0xCA, // movd EDX,MM1 0x0F, 0x7E, 0xCE, // movd ESI,MM1 0x0F, 0x7E, 0xCF, // movd EDI,MM1 0x0F, 0x7E, 0xCD, // movd EBP,MM1 0x0F, 0x7E, 0xCC, // movd ESP,MM1 0x66, 0x0F, 0x6E, 0xC8, // movd XMM1,EAX 0x66, 0x0F, 0x6E, 0xCB, // movd XMM1,EBX 0x66, 0x0F, 0x6E, 0xC9, // movd XMM1,ECX 0x66, 0x0F, 0x6E, 0xCA, // movd XMM1,EDX 0x66, 0x0F, 0x6E, 0xCE, // movd XMM1,ESI 0x66, 0x0F, 0x6E, 0xCF, // movd XMM1,EDI 0x66, 0x0F, 0x6E, 0xCD, // movd XMM1,EBP 0x66, 0x0F, 0x6E, 0xCC, // movd XMM1,ESP 0x0F, 0x6E, 0xC8, // movd MM1,EAX 0x0F, 0x6E, 0xCB, // movd MM1,EBX 0x0F, 0x6E, 0xC9, // movd MM1,ECX 0x0F, 0x6E, 0xCA, // movd MM1,EDX 0x0F, 0x6E, 0xCE, // movd MM1,ESI 0x0F, 0x6E, 0xCF, // movd MM1,EDI 0x0F, 0x6E, 0xCD, // movd MM1,EBP 0x0F, 0x6E, 0xCC, // movd MM1,ESP ]; int i; asm { call L1 ; movd ECX, XMM0; movd ECX, XMM1; movd ECX, XMM2; movd ECX, XMM3; movd ECX, XMM4; movd ECX, XMM5; movd ECX, XMM6; movd ECX, XMM7; movd ECX, MM0; movd ECX, MM1; movd ECX, MM2; movd ECX, MM3; movd ECX, MM4; movd ECX, MM5; movd ECX, MM6; movd ECX, MM7; movd XMM0, ECX; movd XMM1, ECX; movd XMM2, ECX; movd XMM3, ECX; movd XMM4, ECX; movd XMM5, ECX; movd XMM6, ECX; movd XMM7, ECX; movd MM0, ECX; movd MM1, ECX; movd MM2, ECX; movd MM3, ECX; movd MM4, ECX; movd MM5, ECX; movd MM6, ECX; movd MM7, ECX; movd EAX, XMM1; movd EBX, XMM1; movd ECX, XMM1; movd EDX, XMM1; movd ESI, XMM1; movd EDI, XMM1; movd EBP, XMM1; movd ESP, XMM1; movd EAX, MM1; movd EBX, MM1; movd ECX, MM1; movd EDX, MM1; movd ESI, MM1; movd EDI, MM1; movd EBP, MM1; movd ESP, MM1; movd XMM1, EAX; movd XMM1, EBX; movd XMM1, ECX; movd XMM1, EDX; movd XMM1, ESI; movd XMM1, EDI; movd XMM1, EBP; movd XMM1, ESP; movd MM1, EAX; movd MM1, EBX; movd MM1, ECX; movd MM1, EDX; movd MM1, ESI; movd MM1, EDI; movd MM1, EBP; movd MM1, ESP; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ void fn26(ref byte val) { asm { mov RAX, val; inc byte ptr [RAX]; } } void test26() { byte b; //printf( "%i\n", b ); assert(b == 0); fn26(b); //printf( "%i\n", b ); assert(b == 1); } /****************************************************/ void test27() { static const ubyte[16] a = [0, 1, 2, 3, 4, 5, 6, 7, 8 ,9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]; version (Windows) { asm { movdqu XMM0, a; pslldq XMM0, 2; } } } /****************************************************/ /* PASS: cfloat z; cfloat[1] z; double z; double[1] b; long z; long[1] z; FAIL: (bad type/size of operands 'movq') byte[8] z; char[8] z; dchar[2] z; float[2] z; int[2] z; short[4] z; wchar[4] z; XPASS: (too small, but accecpted by DMD) cfloat[0] z; double[0] z; long[0] z; */ void test28() { // version (Windows) // { cfloat[4] z = void; static const ubyte[8] A = [3, 4, 9, 0, 1, 3, 7, 2]; ubyte[8] b; asm{ movq MM0, z; movq MM0, A; movq b, MM0; } for(size_t i = 0; i < A.length; i++) { if(A[i] != b[i]) { assert(0); } } // } } /****************************************************/ /+ shared int[5] bar29 = [3, 4, 5, 6, 7]; void test29() { int* x; asm { push offsetof bar29; pop EAX; mov x, EAX; } assert(*x == 3); asm { mov EAX, offsetof bar29; mov x, EAX; } assert(*x == 3); } +/ /****************************************************/ const int CONST_OFFSET30 = 10; void foo30() { asm { mov EDX, 10; mov EAX, [RDX + CONST_OFFSET30]; } } void test30() { } /****************************************************/ void test31() { ubyte *p; static ubyte data[] = [ 0xF7, 0xD8, // neg EAX 0x74, 0x04, // je L8 0xF7, 0xD8, // neg EAX 0x75, 0xFC, // jne L4 0xFF, 0xC0, // inc EAX ]; int i; asm { call L1 ; neg EAX; je L2; L3: neg EAX; jne L3; L2: inc EAX; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ void infiniteAsmLoops() { /* This crashes DMD 0.162: */ for (;;) asm { inc EAX; } /* It doesn't seem to matter what you use. These all crash: */ //for (;;) asm { mov EAX, EBX; } //for (;;) asm { xor EAX, EAX; } //for (;;) asm { push 0; pop RAX; } //for (;;) asm { jmp infiniteAsmLoops; } /* This is a workaround: */ for (bool a = true; a;) asm { hlt; } // compiles /* But this isn't: */ //for (const bool a = true; a;) asm{ hlt; } // crashes DMD /* It's not restricted to for-statements: */ //while(1) asm { hlt; } // crashes DMD /* This compiles: */ { bool a = true; while(a) asm { hlt; } } /* But again, this doesn't: */ /* { const bool a = true; // note the const while(a) asm { hlt; } } //*/ //do { asm { hlt; } } while (1); // crashes DMD /* This, of course, compiles: */ { bool a = true; do asm { hlt; } while (a); } /* But predicably, this doesn't: */ /* { const bool a = true; do asm { hlt; } while (a); } //**/ /* Not even hand-coding the loop works: */ /* { label: asm { hlt; } // commenting out this line to make it compile goto label; } //*/ /* Unless you go all the way: (i.e. this compiles) */ asm { L1: hlt; jmp L1; } /* or like this (also compiles): */ static void test() { asm { naked; hlt; jmp test; } } test(); /* Wait... it gets weirder: */ /* This also doesn't compile: */ /* for (;;) { printf("\n"); asm { hlt; } } //*/ /* But this does: */ //* for (;;) { asm { hlt; } printf("\n"); } //*/ /* The same loop that doesn't compile above * /does/ compile after previous one: */ //* for (;;) { printf("\n"); asm { hlt; } } //*/ /* Note: this one is at the end because it seems to also trigger the * "now it works" event of the loop above. */ /* There has to be /something/ in that asm block: */ for (;;) asm {} // compiles } void test32() { } /****************************************************/ void test33() { int x = 1; alias x y; asm { mov EAX, x; mov EAX, y; } } /****************************************************/ int test34() { asm{ jmp label; } return 0; label: return 1; } /****************************************************/ /+ void foo35() { printf("hello\n"); } void test35() { void function() p; ulong q; asm { mov ECX, foo35 ; mov q, ECX ; lea EDX, foo35 ; mov p, EDX ; } assert(p == &foo35); assert(q == *cast(ulong *)p); } /****************************************************/ void func36() { } int test36() { void* a = &func36; ulong* b = cast(ulong*) a; ulong f = *b; ulong g; asm{ mov RAX, func36; mov g, RAX; } if(f != g){ assert(0); } } +/ /****************************************************/ void a37(X...)(X expr) { alias expr[0] var1; asm { fld double ptr expr[0]; fstp double ptr var1; } } void test37() { a37(3.6); } /****************************************************/ int f38(X...)(X x) { asm { mov EAX, int ptr x[1]; } } int g38(X...)(X x) { asm { mov EAX, x[1]; } } void test38() { assert(456 == f38(123, 456)); assert(456 == g38(123, 456)); } /****************************************************/ void test39() { const byte z = 35; goto end; asm { db z; } end: ; } /****************************************************/ void test40() { printf(""); const string s = "abcdefghi"; asm { jmp L1; ds s; L1:; } end: ; } /****************************************************/ void test41() { ubyte *p; static ubyte data[] = [ 0x66,0x0F,0x28,0x0C,0x06, // movapd XMM1,[RAX][RSI] 0x66,0x0F,0x28,0x0C,0x06, // movapd XMM1,[RAX][RSI] 0x66,0x0F,0x28,0x0C,0x46, // movapd XMM1,[RAX*2][RSI] 0x66,0x0F,0x28,0x0C,0x86, // movapd XMM1,[RAX*4][RSI] 0x66,0x0F,0x28,0x0C,0xC6, // movapd XMM1,[RAX*8][RSI] ]; int i; asm { call L1 ; movapd XMM1, [RSI+RAX]; movapd XMM1, [RSI+1*RAX]; movapd XMM1, [RSI+2*RAX]; movapd XMM1, [RSI+4*RAX]; movapd XMM1, [RSI+8*RAX]; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ enum { enumeration42 = 1, } void test42() { asm { mov EAX, enumeration42; } } /****************************************************/ void foo43() { asm {lea EAX, [0*4+EAX]; } asm {lea EAX, [4*0+EAX]; } asm {lea EAX, [EAX+4*0]; } asm {lea EAX, [0+EAX]; } asm {lea EAX, [7*7+EAX]; } } void test43() { } /****************************************************/ enum n1 = 42; enum { n2 = 42 } uint retN1() { asm { mov EAX,n1; // No! - mov EAX,-4[EBP] } } uint retN2() { asm { mov EAX,n2; // OK - mov EAX,02Ah } } void test44() { assert(retN1() == 42); assert(retN2() == 42); } /****************************************************/ void test45() { ubyte *p; static ubyte data[] = [ 0xDA, 0xC0, // fcmovb ST(0) 0xDA, 0xC1, // fcmovb 0xDA, 0xCA, // fcmove ST(2) 0xDA, 0xD3, // fcmovbe ST(3) 0xDA, 0xDC, // fcmovu ST(4) 0xDB, 0xC5, // fcmovnb ST(5) 0xDB, 0xCE, // fcmovne ST(6) 0xDB, 0xD7, // fcmovnbe ST(7) 0xDB, 0xD9, // fcmovnu ]; int i; asm { call L1 ; fcmovb ST, ST(0); fcmovb ST, ST(1); fcmove ST, ST(2); fcmovbe ST, ST(3); fcmovu ST, ST(4); fcmovnb ST, ST(5); fcmovne ST, ST(6); fcmovnbe ST, ST(7); fcmovnu ST, ST(1); L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ void test46() { ubyte *p; static ubyte data[] = [ 0x66, 0x0F, 0x3A, 0x41, 0xCA, 0x08, // dppd XMM1,XMM2,8 0x66, 0x0F, 0x3A, 0x40, 0xDC, 0x07, // dpps XMM3,XMM4,7 0x66, 0x0F, 0x50, 0xF3, // movmskpd ESI,XMM3 0x66, 0x0F, 0x50, 0xC7, // movmskpd EAX,XMM7 0x0F, 0x50, 0xC7, // movmskps EAX,XMM7 0x0F, 0xD7, 0xC7, // pmovmskb EAX,MM7 0x66, 0x0F, 0xD7, 0xC7, // pmovmskb EAX,XMM7 ]; int i; asm { call L1 ; dppd XMM1,XMM2,8 ; dpps XMM3,XMM4,7 ; movmskpd ESI,XMM3 ; movmskpd EAX,XMM7 ; movmskps EAX,XMM7 ; pmovmskb EAX,MM7 ; pmovmskb EAX,XMM7 ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ /+ struct Foo47 { float x,y; } void bar47(Foo47 f) { int i; asm { mov EAX, offsetof f; mov i, EAX; } printf("%d\n",i); assert(i == 8); } void test47() { Foo47 f; bar47(f); } +/ /****************************************************/ void func48(void delegate () callback) { callback(); } void test48() { func48(() { asm{ mov EAX,EAX; }; }); } /****************************************************/ void test49() { ubyte *p; static ubyte data[] = [ 0x00, 0xC0, // add AL,AL 0x00, 0xD8, // add AL,BL 0x00, 0xC8, // add AL,CL 0x00, 0xD0, // add AL,DL 0x00, 0xE0, // add AL,AH 0x00, 0xF8, // add AL,BH 0x00, 0xE8, // add AL,CH 0x00, 0xF0, // add AL,DH 0x00, 0xC4, // add AH,AL 0x00, 0xDC, // add AH,BL 0x00, 0xCC, // add AH,CL 0x00, 0xD4, // add AH,DL 0x00, 0xE4, // add AH,AH 0x00, 0xFC, // add AH,BH 0x00, 0xEC, // add AH,CH 0x00, 0xF4, // add AH,DH 0x00, 0xC3, // add BL,AL 0x00, 0xDB, // add BL,BL 0x00, 0xCB, // add BL,CL 0x00, 0xD3, // add BL,DL 0x00, 0xE3, // add BL,AH 0x00, 0xFB, // add BL,BH 0x00, 0xEB, // add BL,CH 0x00, 0xF3, // add BL,DH 0x00, 0xC7, // add BH,AL 0x00, 0xDF, // add BH,BL 0x00, 0xCF, // add BH,CL 0x00, 0xD7, // add BH,DL 0x00, 0xE7, // add BH,AH 0x00, 0xFF, // add BH,BH 0x00, 0xEF, // add BH,CH 0x00, 0xF7, // add BH,DH 0x00, 0xC1, // add CL,AL 0x00, 0xD9, // add CL,BL 0x00, 0xC9, // add CL,CL 0x00, 0xD1, // add CL,DL 0x00, 0xE1, // add CL,AH 0x00, 0xF9, // add CL,BH 0x00, 0xE9, // add CL,CH 0x00, 0xF1, // add CL,DH 0x00, 0xC5, // add CH,AL 0x00, 0xDD, // add CH,BL 0x00, 0xCD, // add CH,CL 0x00, 0xD5, // add CH,DL 0x00, 0xE5, // add CH,AH 0x00, 0xFD, // add CH,BH 0x00, 0xED, // add CH,CH 0x00, 0xF5, // add CH,DH 0x00, 0xC2, // add DL,AL 0x00, 0xDA, // add DL,BL 0x00, 0xCA, // add DL,CL 0x00, 0xD2, // add DL,DL 0x00, 0xE2, // add DL,AH 0x00, 0xFA, // add DL,BH 0x00, 0xEA, // add DL,CH 0x00, 0xF2, // add DL,DH 0x00, 0xC6, // add DH,AL 0x00, 0xDE, // add DH,BL 0x00, 0xCE, // add DH,CL 0x00, 0xD6, // add DH,DL 0x00, 0xE6, // add DH,AH 0x00, 0xFE, // add DH,BH 0x00, 0xEE, // add DH,CH 0x00, 0xF6, // add DH,DH 0x66, 0x01, 0xC0, // add AX,AX 0x66, 0x01, 0xD8, // add AX,BX 0x66, 0x01, 0xC8, // add AX,CX 0x66, 0x01, 0xD0, // add AX,DX 0x66, 0x01, 0xF0, // add AX,SI 0x66, 0x01, 0xF8, // add AX,DI 0x66, 0x01, 0xE8, // add AX,BP 0x66, 0x01, 0xE0, // add AX,SP 0x66, 0x01, 0xC3, // add BX,AX 0x66, 0x01, 0xDB, // add BX,BX 0x66, 0x01, 0xCB, // add BX,CX 0x66, 0x01, 0xD3, // add BX,DX 0x66, 0x01, 0xF3, // add BX,SI 0x66, 0x01, 0xFB, // add BX,DI 0x66, 0x01, 0xEB, // add BX,BP 0x66, 0x01, 0xE3, // add BX,SP 0x66, 0x01, 0xC1, // add CX,AX 0x66, 0x01, 0xD9, // add CX,BX 0x66, 0x01, 0xC9, // add CX,CX 0x66, 0x01, 0xD1, // add CX,DX 0x66, 0x01, 0xF1, // add CX,SI 0x66, 0x01, 0xF9, // add CX,DI 0x66, 0x01, 0xE9, // add CX,BP 0x66, 0x01, 0xE1, // add CX,SP 0x66, 0x01, 0xC2, // add DX,AX 0x66, 0x01, 0xDA, // add DX,BX 0x66, 0x01, 0xCA, // add DX,CX 0x66, 0x01, 0xD2, // add DX,DX 0x66, 0x01, 0xF2, // add DX,SI 0x66, 0x01, 0xFA, // add DX,DI 0x66, 0x01, 0xEA, // add DX,BP 0x66, 0x01, 0xE2, // add DX,SP 0x66, 0x01, 0xC6, // add SI,AX 0x66, 0x01, 0xDE, // add SI,BX 0x66, 0x01, 0xCE, // add SI,CX 0x66, 0x01, 0xD6, // add SI,DX 0x66, 0x01, 0xF6, // add SI,SI 0x66, 0x01, 0xFE, // add SI,DI 0x66, 0x01, 0xEE, // add SI,BP 0x66, 0x01, 0xE6, // add SI,SP 0x66, 0x01, 0xC7, // add DI,AX 0x66, 0x01, 0xDF, // add DI,BX 0x66, 0x01, 0xCF, // add DI,CX 0x66, 0x01, 0xD7, // add DI,DX 0x66, 0x01, 0xF7, // add DI,SI 0x66, 0x01, 0xFF, // add DI,DI 0x66, 0x01, 0xEF, // add DI,BP 0x66, 0x01, 0xE7, // add DI,SP 0x66, 0x01, 0xC5, // add BP,AX 0x66, 0x01, 0xDD, // add BP,BX 0x66, 0x01, 0xCD, // add BP,CX 0x66, 0x01, 0xD5, // add BP,DX 0x66, 0x01, 0xF5, // add BP,SI 0x66, 0x01, 0xFD, // add BP,DI 0x66, 0x01, 0xED, // add BP,BP 0x66, 0x01, 0xE5, // add BP,SP 0x66, 0x01, 0xC4, // add SP,AX 0x66, 0x01, 0xDC, // add SP,BX 0x66, 0x01, 0xCC, // add SP,CX 0x66, 0x01, 0xD4, // add SP,DX 0x66, 0x01, 0xF4, // add SP,SI 0x66, 0x01, 0xFC, // add SP,DI 0x66, 0x01, 0xEC, // add SP,BP 0x66, 0x01, 0xE4, // add SP,SP 0x01, 0xC0, // add EAX,EAX 0x01, 0xD8, // add EAX,EBX 0x01, 0xC8, // add EAX,ECX 0x01, 0xD0, // add EAX,EDX 0x01, 0xF0, // add EAX,ESI 0x01, 0xF8, // add EAX,EDI 0x01, 0xE8, // add EAX,EBP 0x01, 0xE0, // add EAX,ESP 0x01, 0xC3, // add EBX,EAX 0x01, 0xDB, // add EBX,EBX 0x01, 0xCB, // add EBX,ECX 0x01, 0xD3, // add EBX,EDX 0x01, 0xF3, // add EBX,ESI 0x01, 0xFB, // add EBX,EDI 0x01, 0xEB, // add EBX,EBP 0x01, 0xE3, // add EBX,ESP 0x01, 0xC1, // add ECX,EAX 0x01, 0xD9, // add ECX,EBX 0x01, 0xC9, // add ECX,ECX 0x01, 0xD1, // add ECX,EDX 0x01, 0xF1, // add ECX,ESI 0x01, 0xF9, // add ECX,EDI 0x01, 0xE9, // add ECX,EBP 0x01, 0xE1, // add ECX,ESP 0x01, 0xC2, // add EDX,EAX 0x01, 0xDA, // add EDX,EBX 0x01, 0xCA, // add EDX,ECX 0x01, 0xD2, // add EDX,EDX 0x01, 0xF2, // add EDX,ESI 0x01, 0xFA, // add EDX,EDI 0x01, 0xEA, // add EDX,EBP 0x01, 0xE2, // add EDX,ESP 0x01, 0xC6, // add ESI,EAX 0x01, 0xDE, // add ESI,EBX 0x01, 0xCE, // add ESI,ECX 0x01, 0xD6, // add ESI,EDX 0x01, 0xF6, // add ESI,ESI 0x01, 0xFE, // add ESI,EDI 0x01, 0xEE, // add ESI,EBP 0x01, 0xE6, // add ESI,ESP 0x01, 0xC7, // add EDI,EAX 0x01, 0xDF, // add EDI,EBX 0x01, 0xCF, // add EDI,ECX 0x01, 0xD7, // add EDI,EDX 0x01, 0xF7, // add EDI,ESI 0x01, 0xFF, // add EDI,EDI 0x01, 0xEF, // add EDI,EBP 0x01, 0xE7, // add EDI,ESP 0x01, 0xC5, // add EBP,EAX 0x01, 0xDD, // add EBP,EBX 0x01, 0xCD, // add EBP,ECX 0x01, 0xD5, // add EBP,EDX 0x01, 0xF5, // add EBP,ESI 0x01, 0xFD, // add EBP,EDI 0x01, 0xED, // add EBP,EBP 0x01, 0xE5, // add EBP,ESP 0x01, 0xC4, // add ESP,EAX 0x01, 0xDC, // add ESP,EBX 0x01, 0xCC, // add ESP,ECX 0x01, 0xD4, // add ESP,EDX 0x01, 0xF4, // add ESP,ESI 0x01, 0xFC, // add ESP,EDI 0x01, 0xEC, // add ESP,EBP 0x01, 0xE4, // add ESP,ESP ]; int i; asm { call L1 ; add AL,AL ; add AL,BL ; add AL,CL ; add AL,DL ; add AL,AH ; add AL,BH ; add AL,CH ; add AL,DH ; add AH,AL ; add AH,BL ; add AH,CL ; add AH,DL ; add AH,AH ; add AH,BH ; add AH,CH ; add AH,DH ; add BL,AL ; add BL,BL ; add BL,CL ; add BL,DL ; add BL,AH ; add BL,BH ; add BL,CH ; add BL,DH ; add BH,AL ; add BH,BL ; add BH,CL ; add BH,DL ; add BH,AH ; add BH,BH ; add BH,CH ; add BH,DH ; add CL,AL ; add CL,BL ; add CL,CL ; add CL,DL ; add CL,AH ; add CL,BH ; add CL,CH ; add CL,DH ; add CH,AL ; add CH,BL ; add CH,CL ; add CH,DL ; add CH,AH ; add CH,BH ; add CH,CH ; add CH,DH ; add DL,AL ; add DL,BL ; add DL,CL ; add DL,DL ; add DL,AH ; add DL,BH ; add DL,CH ; add DL,DH ; add DH,AL ; add DH,BL ; add DH,CL ; add DH,DL ; add DH,AH ; add DH,BH ; add DH,CH ; add DH,DH ; add AX,AX ; add AX,BX ; add AX,CX ; add AX,DX ; add AX,SI ; add AX,DI ; add AX,BP ; add AX,SP ; add BX,AX ; add BX,BX ; add BX,CX ; add BX,DX ; add BX,SI ; add BX,DI ; add BX,BP ; add BX,SP ; add CX,AX ; add CX,BX ; add CX,CX ; add CX,DX ; add CX,SI ; add CX,DI ; add CX,BP ; add CX,SP ; add DX,AX ; add DX,BX ; add DX,CX ; add DX,DX ; add DX,SI ; add DX,DI ; add DX,BP ; add DX,SP ; add SI,AX ; add SI,BX ; add SI,CX ; add SI,DX ; add SI,SI ; add SI,DI ; add SI,BP ; add SI,SP ; add DI,AX ; add DI,BX ; add DI,CX ; add DI,DX ; add DI,SI ; add DI,DI ; add DI,BP ; add DI,SP ; add BP,AX ; add BP,BX ; add BP,CX ; add BP,DX ; add BP,SI ; add BP,DI ; add BP,BP ; add BP,SP ; add SP,AX ; add SP,BX ; add SP,CX ; add SP,DX ; add SP,SI ; add SP,DI ; add SP,BP ; add SP,SP ; add EAX,EAX ; add EAX,EBX ; add EAX,ECX ; add EAX,EDX ; add EAX,ESI ; add EAX,EDI ; add EAX,EBP ; add EAX,ESP ; add EBX,EAX ; add EBX,EBX ; add EBX,ECX ; add EBX,EDX ; add EBX,ESI ; add EBX,EDI ; add EBX,EBP ; add EBX,ESP ; add ECX,EAX ; add ECX,EBX ; add ECX,ECX ; add ECX,EDX ; add ECX,ESI ; add ECX,EDI ; add ECX,EBP ; add ECX,ESP ; add EDX,EAX ; add EDX,EBX ; add EDX,ECX ; add EDX,EDX ; add EDX,ESI ; add EDX,EDI ; add EDX,EBP ; add EDX,ESP ; add ESI,EAX ; add ESI,EBX ; add ESI,ECX ; add ESI,EDX ; add ESI,ESI ; add ESI,EDI ; add ESI,EBP ; add ESI,ESP ; add EDI,EAX ; add EDI,EBX ; add EDI,ECX ; add EDI,EDX ; add EDI,ESI ; add EDI,EDI ; add EDI,EBP ; add EDI,ESP ; add EBP,EAX ; add EBP,EBX ; add EBP,ECX ; add EBP,EDX ; add EBP,ESI ; add EBP,EDI ; add EBP,EBP ; add EBP,ESP ; add ESP,EAX ; add ESP,EBX ; add ESP,ECX ; add ESP,EDX ; add ESP,ESI ; add ESP,EDI ; add ESP,EBP ; add ESP,ESP ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ void test50() { ubyte *p; static ubyte data[] = [ 0x66, 0x98, // cbw 0xF8, // clc 0xFC, // cld 0xFA, // cli 0xF5, // cmc 0xA6, // cmpsb 0x66, 0xA7, // cmpsw 0xA7, // cmpsd 0x66, 0x99, // cwd // 0x27, // daa // 0x2F, // das 0xFF, 0xC8, // dec EAX 0xF6, 0xF1, // div CL 0x66, 0xF7, 0xF3, // div BX 0xF7, 0xF2, // div EDX 0xF4, // hlt 0xF6, 0xFB, // idiv BL 0x66, 0xF7, 0xFA, // idiv DX 0xF7, 0xFE, // idiv ESI 0xF6, 0xEB, // imul BL 0x66, 0xF7, 0xEA, // imul DX 0xF7, 0xEE, // imul ESI 0xEC, // in AL,DX 0x66, 0xED, // in AX,DX 0xFF, 0xC3, // inc EBX 0xCC, // int 3 0xCD, 0x67, // int 067h // 0xCE, // into 0x66, 0xCF, // iret 0x77, 0xFC, // ja L30 0x77, 0xFA, // ja L30 0x73, 0xF8, // jae L30 0x73, 0xF6, // jae L30 0x73, 0xF4, // jae L30 0x72, 0xF2, // jb L30 0x72, 0xF0, // jb L30 0x76, 0xEE, // jbe L30 0x76, 0xEC, // jbe L30 0x72, 0xEA, // jb L30 // 0x67, 0xE3, 0xE7, // jcxz L30 0x90, 0x90, 0x90, // nop;nop;nop 0x74, 0xE5, // je L30 0x74, 0xE3, // je L30 0x7F, 0xE1, // jg L30 0x7F, 0xDF, // jg L30 0x7D, 0xDD, // jge L30 0x7D, 0xDB, // jge L30 0x7C, 0xD9, // jl L30 0x7C, 0xD7, // jl L30 0x7E, 0xD5, // jle L30 0x7E, 0xD3, // jle L30 0xEB, 0xD1, // jmp short L30 0x75, 0xCF, // jne L30 0x75, 0xCD, // jne L30 0x71, 0xCB, // jno L30 0x79, 0xC9, // jns L30 0x7B, 0xC7, // jnp L30 0x7B, 0xC5, // jnp L30 0x70, 0xC3, // jo L30 0x7A, 0xC1, // jp L30 0x7A, 0xBF, // jp L30 0x78, 0xBD, // js L30 0x9F, // lahf // 0xC5, 0x30, // lds ESI,[EAX] 0x90, 0x90, // nop;nop 0x8B, 0xFB, // mov EDI,EBX // 0xC4, 0x29, // les EBP,[ECX] 0x90, 0x90, // nop;nop 0xF0, // lock 0xAC, // lodsb 0x66, 0xAD, // lodsw 0xAD, // lodsd 0xE2, 0xAF, // loop L30 0xE1, 0xAD, // loope L30 0xE1, 0xAB, // loope L30 0xE0, 0xA9, // loopne L30 0xE0, 0xA7, // loopne L30 0xA4, // movsb 0x66, 0xA5, // movsw 0xA5, // movsd 0xF6, 0xE4, // mul AH 0x66, 0xF7, 0xE1, // mul CX 0xF7, 0xE5, // mul EBP 0x90, // nop 0xF7, 0xD7, // not EDI 0x66, 0xE7, 0x44, // out 044h,AX 0xEE, // out DX,AL 0x66, 0x9D, // popf 0x66, 0x9C, // pushf 0xD1, 0xDB, // rcr EBX,1 0xF3, // rep 0xF3, // rep 0xF2, // repne 0xF3, // rep 0xF2, // repne 0xC3, // ret 0xC2, 0x04, 0x00, // ret 4 0xD1, 0xC1, // rol ECX,1 0xD1, 0xCA, // ror EDX,1 0x9E, // sahf 0xD1, 0xE5, // shl EBP,1 0xD1, 0xE4, // shl ESP,1 0xD1, 0xFF, // sar EDI,1 0xAE, // scasb 0x66, 0xAF, // scasw 0xAF, // scasd 0xD1, 0xEE, // shr ESI,1 0xFD, // std 0xF9, // stc 0xFB, // sti 0xAA, // stosb 0x66, 0xAB, // stosw 0xAB, // stosd 0x9B, // wait 0x91, // xchg EAX,ECX 0xD7, // xlat ]; int i; asm { call L1 ; cbw ; clc ; cld ; cli ; cmc ; cmpsb ; cmpsw ; cmpsd ; cwd ; //daa ; //das ; dec EAX ; div CL ; div BX ; div EDX ; hlt ; idiv BL ; idiv DX ; idiv ESI ; imul BL ; imul DX ; imul ESI ; in AL,DX ; in AX,DX ; inc EBX ; int 3 ; int 0x67 ; //into ; L10: iret ; ja L10 ; jnbe L10 ; jae L10 ; jnb L10 ; jnc L10 ; jb L10 ; jnae L10 ; jbe L10 ; jna L10 ; jc L10 ; nop;nop;nop; // jcxz L10; je L10 ; jz L10 ; jg L10 ; jnle L10 ; jge L10 ; jnl L10 ; jl L10 ; jnge L10 ; jle L10 ; jng L10 ; jmp short L10 ; jne L10 ; jnz L10 ; jno L10 ; jns L10 ; jnp L10 ; jpo L10 ; jo L10 ; jp L10 ; jpe L10 ; js L10 ; lahf ; nop;nop; //lds ESI,[EAX]; lea EDI,[EBX]; nop;nop; //les EBP,[ECX]; lock ; lodsb ; lodsw ; lodsd ; loop L10 ; loope L10 ; loopz L10 ; loopnz L10 ; loopne L10 ; movsb ; movsw ; movsd ; mul AH ; mul CX ; mul EBP ; nop ; not EDI ; out 0x44,AX ; out DX,AL ; popf ; pushf ; rcr EBX,1 ; rep ; repe ; repne ; repz ; repnz ; ret ; ret 4 ; rol ECX,1 ; ror EDX,1 ; sahf ; sal EBP,1 ; shl ESP,1 ; sar EDI,1 ; scasb ; scasw ; scasd ; shr ESI,1 ; std ; stc ; sti ; stosb ; stosw ; stosd ; wait ; xchg EAX,ECX ; xlat ; L1: ; pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } /****************************************************/ class Test51 { void test(int n) { asm { mov RAX, this; } } } /****************************************************/ void test52() { int x; ubyte* p; static ubyte data[] = [ 0xF6, 0xD8, // neg AL 0x66, 0xF7, 0xD8, // neg AX 0xF7, 0xD8, // neg EAX 0x48, 0xF7, 0xD8, // neg RAX 0xF6, 0xDC, // neg AH 0x41, 0xF6, 0xDC, // neg R12B 0x66, 0x41, 0xF7, 0xDC, // neg 12D 0x41, 0xF7, 0xDC, // neg R12D 0x49, 0xF7, 0xDB, // neg R11 // 0xF6, 0x1D, 0x00, 0x00, 0x00, 0x00, // neg byte ptr _D6iasm641bg@PC32[RIP] //0x66, 0xF7, 0x1D, 0x00, 0x00, 0x00, 0x00, // neg word ptr _D6iasm641ws@PC32[RIP] // 0xF7, 0x1D, 0x00, 0x00, 0x00, 0x00, // neg dword ptr _D6iasm641ii@PC32[RIP] // 0x48, 0xF7, 0x1D, 0x00, 0x00, 0x00, 0x00, // neg qword ptr _D6iasm641ll@PC32[RIP] 0xF7, 0x5D, 0xD0, // neg dword ptr -8[RBP] 0xF6, 0x1B, // neg byte ptr [RBX] 0xF6, 0x1B, // neg byte ptr [RBX] 0x49, 0xF7, 0xD8, // neg R8 ]; asm { call L1 ; neg AL ; neg AX ; neg EAX ; neg RAX ; neg AH ; neg R12B ; neg R12W ; neg R12D ; neg R11 ; // neg b ; // neg w ; // neg i ; // neg l ; neg x ; neg [EBX] ; neg [RBX] ; neg R8 ; L1: pop RAX ; mov p[RBP],RAX ; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } /****************************************************/ void test53() { int x; ubyte* p; static ubyte data[] = [ 0x48, 0x8D, 0x04, 0x00, // lea RAX,[RAX][RAX] 0x48, 0x8D, 0x04, 0x08, // lea RAX,[RCX][RAX] 0x48, 0x8D, 0x04, 0x10, // lea RAX,[RDX][RAX] 0x48, 0x8D, 0x04, 0x18, // lea RAX,[RBX][RAX] 0x48, 0x8D, 0x04, 0x28, // lea RAX,[RBP][RAX] 0x48, 0x8D, 0x04, 0x30, // lea RAX,[RSI][RAX] 0x48, 0x8D, 0x04, 0x38, // lea RAX,[RDI][RAX] 0x4A, 0x8D, 0x04, 0x00, // lea RAX,[R8][RAX] 0x4A, 0x8D, 0x04, 0x08, // lea RAX,[R9][RAX] 0x4A, 0x8D, 0x04, 0x10, // lea RAX,[R10][RAX] 0x4A, 0x8D, 0x04, 0x18, // lea RAX,[R11][RAX] 0x4A, 0x8D, 0x04, 0x20, // lea RAX,[R12][RAX] 0x4A, 0x8D, 0x04, 0x28, // lea RAX,[R13][RAX] 0x4A, 0x8D, 0x04, 0x30, // lea RAX,[R14][RAX] 0x4A, 0x8D, 0x04, 0x38, // lea RAX,[R15][RAX] 0x48, 0x8D, 0x04, 0x00, // lea RAX,[RAX][RAX] 0x48, 0x8D, 0x04, 0x01, // lea RAX,[RAX][RCX] 0x48, 0x8D, 0x04, 0x02, // lea RAX,[RAX][RDX] 0x48, 0x8D, 0x04, 0x03, // lea RAX,[RAX][RBX] 0x48, 0x8D, 0x04, 0x04, // lea RAX,[RAX][RSP] 0x48, 0x8D, 0x44, 0x05, 0x00, // lea RAX,0[RAX][RBP] 0x48, 0x8D, 0x04, 0x06, // lea RAX,[RAX][RSI] 0x48, 0x8D, 0x04, 0x07, // lea RAX,[RAX][RDI] 0x49, 0x8D, 0x04, 0x00, // lea RAX,[RAX][R8] 0x49, 0x8D, 0x04, 0x01, // lea RAX,[RAX][R9] 0x49, 0x8D, 0x04, 0x02, // lea RAX,[RAX][R10] 0x49, 0x8D, 0x04, 0x03, // lea RAX,[RAX][R11] 0x49, 0x8D, 0x04, 0x04, // lea RAX,[RAX][R12] 0x49, 0x8D, 0x44, 0x05, 0x00, // lea RAX,0[RAX][R13] 0x49, 0x8D, 0x04, 0x06, // lea RAX,[RAX][R14] 0x49, 0x8D, 0x04, 0x07, // lea RAX,[RAX][R15] 0x4B, 0x8D, 0x04, 0x24, // lea RAX,[R12][R12] 0x4B, 0x8D, 0x44, 0x25, 0x00, // lea RAX,0[R12][R13] 0x4B, 0x8D, 0x04, 0x26, // lea RAX,[R12][R14] 0x4B, 0x8D, 0x04, 0x2C, // lea RAX,[R13][R12] 0x4B, 0x8D, 0x44, 0x2D, 0x00, // lea RAX,0[R13][R13] 0x4B, 0x8D, 0x04, 0x2E, // lea RAX,[R13][R14] 0x4B, 0x8D, 0x04, 0x34, // lea RAX,[R14][R12] 0x4B, 0x8D, 0x44, 0x35, 0x00, // lea RAX,0[R14][R13] 0x4B, 0x8D, 0x04, 0x36, // lea RAX,[R14][R14] 0x48, 0x8D, 0x44, 0x01, 0x12, // lea RAX,012h[RAX][RCX] 0x48, 0x8D, 0x84, 0x01, 0x34, 0x12, 0x00, 0x00, // lea RAX,01234h[RAX][RCX] 0x48, 0x8D, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, // lea RAX,012345678h[RAX][RCX] 0x48, 0x8D, 0x44, 0x05, 0x12, // lea RAX,012h[RAX][RBP] 0x48, 0x8D, 0x84, 0x05, 0x34, 0x12, 0x00, 0x00, // lea RAX,01234h[RAX][RBP] 0x48, 0x8D, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, // lea RAX,012345678h[RAX][RBP] 0x49, 0x8D, 0x44, 0x05, 0x12, // lea RAX,012h[RAX][R13] 0x49, 0x8D, 0x84, 0x05, 0x34, 0x12, 0x00, 0x00, // lea RAX,01234h[RAX][R13] 0x49, 0x8D, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, // lea RAX,012345678h[RAX][R13] 0x48, 0x8D, 0x04, 0x24, // lea RAX,[RSP] 0x49, 0x8D, 0x04, 0x24, // lea RAX,[R12] ]; asm { call L1 ; // Right lea RAX, [RAX+RAX]; lea RAX, [RAX+RCX]; lea RAX, [RAX+RDX]; lea RAX, [RAX+RBX]; //lea RAX, [RAX+RSP]; RSP can't be on the right lea RAX, [RAX+RBP]; lea RAX, [RAX+RSI]; lea RAX, [RAX+RDI]; lea RAX, [RAX+R8]; lea RAX, [RAX+R9]; lea RAX, [RAX+R10]; lea RAX, [RAX+R11]; lea RAX, [RAX+R12]; lea RAX, [RAX+R13]; lea RAX, [RAX+R14]; lea RAX, [RAX+R15]; // Left lea RAX, [RAX+RAX]; lea RAX, [RCX+RAX]; lea RAX, [RDX+RAX]; lea RAX, [RBX+RAX]; lea RAX, [RSP+RAX]; lea RAX, [RBP+RAX]; // Good gets disp+8 correctly lea RAX, [RSI+RAX]; lea RAX, [RDI+RAX]; lea RAX, [R8+RAX]; lea RAX, [R9+RAX]; lea RAX, [R10+RAX]; lea RAX, [R11+RAX]; lea RAX, [R12+RAX]; lea RAX, [R13+RAX]; // Good disp+8 lea RAX, [R14+RAX]; lea RAX, [R15+RAX]; // Right and Left lea RAX, [R12+R12]; lea RAX, [R13+R12]; lea RAX, [R14+R12]; lea RAX, [R12+R13]; lea RAX, [R13+R13]; lea RAX, [R14+R13]; lea RAX, [R12+R14]; lea RAX, [R13+R14]; lea RAX, [R14+R14]; // Disp8/32 checks lea RAX, [RCX+RAX+0x12]; lea RAX, [RCX+RAX+0x1234]; lea RAX, [RCX+RAX+0x1234_5678]; lea RAX, [RBP+RAX+0x12]; lea RAX, [RBP+RAX+0x1234]; lea RAX, [RBP+RAX+0x1234_5678]; lea RAX, [R13+RAX+0x12]; lea RAX, [R13+RAX+0x1234]; lea RAX, [R13+RAX+0x1234_5678]; lea RAX, [RSP]; lea RAX, [R12]; L1: pop RAX ; mov p[RBP],RAX ; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } /****************************************************/ void test54() { int x; ubyte* p; static ubyte data[] = [ 0xFE, 0xC8, // dec AL 0xFE, 0xCC, // dec AH 0x66, 0xFF, 0xC8, // dec AX 0xFF, 0xC8, // dec EAX 0x48, 0xFF, 0xC8, // dec RAX 0x49, 0xFF, 0xCA, // dec R10 0xFE, 0xC0, // inc AL 0xFE, 0xC4, // inc AH 0x66, 0xFF, 0xC0, // inc AX 0xFF, 0xC0, // inc EAX 0x48, 0xFF, 0xC0, // inc RAX 0x49, 0xFF, 0xC2, // inc R10 0x66, 0x44, 0x0F, 0xA4, 0xC0, 0x04, // shld AX, R8W, 4 0x66, 0x44, 0x0F, 0xA5, 0xC0, // shld AX, R8W, CL 0x44, 0x0F, 0xA4, 0xC0, 0x04, // shld EAX, R8D, 4 0x44, 0x0F, 0xA5, 0xC0, // shld EAX, R8D, CL 0x4C, 0x0F, 0xA4, 0xC0, 0x04, // shld RAX, R8 , 4 0x4C, 0x0F, 0xA5, 0xC0, // shld RAX, R8 , CL 0x66, 0x44, 0x0F, 0xAC, 0xC0, 0x04, // shrd AX, R8W, 4 0x66, 0x44, 0x0F, 0xAD, 0xC0, // shrd AX, R8W, CL 0x44, 0x0F, 0xAC, 0xC0, 0x04, // shrd EAX, R8D, 4 0x44, 0x0F, 0xAD, 0xC0, // shrd EAX, R8D, CL 0x4C, 0x0F, 0xAC, 0xC0, 0x04, // shrd RAX, R8 , 4 0x4C, 0x0F, 0xAD, 0xC0 // shrd RAX, R8 , CL ]; asm { call L1; dec AL; dec AH; dec AX; dec EAX; dec RAX; dec R10; inc AL; inc AH; inc AX; inc EAX; inc RAX; inc R10; shld AX, R8W, 4; shld AX, R8W, CL; shld EAX, R8D, 4; shld EAX, R8D, CL; shld RAX, R8 , 4; shld RAX, R8 , CL; shrd AX, R8W, 4; shrd AX, R8W, CL; shrd EAX, R8D, 4; shrd EAX, R8D, CL; shrd RAX, R8 , 4; shrd RAX, R8 , CL; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } /****************************************************/ void test55() { int x; ubyte* p; enum NOP = 0x9090_9090_9090_9090; static ubyte data[] = [ 0x0F, 0x87, 0xFF, 0xFF, 0, 0, // ja $ + 0xFFFF 0x72, 0x18, // jb Lb 0x0F, 0x82, 0x92, 0x00, 0, 0, // jc Lc 0x0F, 0x84, 0x0C, 0x01, 0, 0, // je Le 0xEB, 0x0A, // jmp Lb 0xE9, 0x85, 0x00, 0x00, 0, // jmp Lc 0xE9, 0x00, 0x01, 0x00, 0, // jmp Le ]; asm { call L1; ja $+0x0_FFFF; jb Lb; jc Lc; je Le; jmp Lb; jmp Lc; jmp Le; Lb: dq NOP,NOP,NOP,NOP; // 32 dq NOP,NOP,NOP,NOP; // 64 dq NOP,NOP,NOP,NOP; // 96 dq NOP,NOP,NOP,NOP; // 128 Lc: dq NOP,NOP,NOP,NOP; // 160 dq NOP,NOP,NOP,NOP; // 192 dq NOP,NOP,NOP,NOP; // 224 dq NOP,NOP,NOP,NOP; // 256 Le: nop; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } /****************************************************/ void test56() { int x; x = foo56(); assert(x == 42); } int foo56() { asm { naked; xor EAX,EAX; jz bar56; ret; } } void bar56() { asm { naked; mov EAX, 42; ret; } } /****************************************************/ /* ======================= SSSE3 ======================= */ void test57() { ubyte* p; M64 m64; M128 m128; static ubyte data[] = [ 0x0F, 0x3A, 0x0F, 0xCA, 0x03, // palignr MM1, MM2, 3 0x66, 0x0F, 0x3A, 0x0F, 0xCA, 0x03, // palignr XMM1, XMM2, 3 0x0F, 0x3A, 0x0F, 0x5D, 0xC8, 0x03, // palignr MM3, -0x38[RBP], 3 0x66, 0x0F, 0x3A, 0x0F, 0x5D, 0xD0, 0x03, // palignr XMM3, -0x30[RBP], 3 0x0F, 0x38, 0x02, 0xCA, // phaddd MM1, MM2 0x66, 0x0F, 0x38, 0x02, 0xCA, // phaddd XMM1, XMM2 0x0F, 0x38, 0x02, 0x5D, 0xC8, // phaddd MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x02, 0x5D, 0xD0, // phaddd XMM3, -0x30[RBP] 0x0F, 0x38, 0x01, 0xCA, // phaddw MM1, MM2 0x66, 0x0F, 0x38, 0x01, 0xCA, // phaddw XMM1, XMM2 0x0F, 0x38, 0x01, 0x5D, 0xC8, // phaddw MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x01, 0x5D, 0xD0, // phaddw XMM3, -0x30[RBP] 0x0F, 0x38, 0x03, 0xCA, // phaddsw MM1, MM2 0x66, 0x0F, 0x38, 0x03, 0xCA, // phaddsw XMM1, XMM2 0x0F, 0x38, 0x03, 0x5D, 0xC8, // phaddsw MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x03, 0x5D, 0xD0, // phaddsw XMM3, -0x30[RBP] 0x0F, 0x38, 0x06, 0xCA, // phsubd MM1, MM2 0x66, 0x0F, 0x38, 0x06, 0xCA, // phsubd XMM1, XMM2 0x0F, 0x38, 0x06, 0x5D, 0xC8, // phsubd MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x06, 0x5D, 0xD0, // phsubd XMM3, -0x30[RBP] 0x0F, 0x38, 0x05, 0xCA, // phsubw MM1, MM2 0x66, 0x0F, 0x38, 0x05, 0xCA, // phsubw XMM1, XMM2 0x0F, 0x38, 0x05, 0x5D, 0xC8, // phsubw MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x05, 0x5D, 0xD0, // phsubw XMM3, -0x30[RBP] 0x0F, 0x38, 0x07, 0xCA, // phsubsw MM1, MM2 0x66, 0x0F, 0x38, 0x07, 0xCA, // phsubsw XMM1, XMM2 0x0F, 0x38, 0x07, 0x5D, 0xC8, // phsubsw MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x07, 0x5D, 0xD0, // phsubsw XMM3, -0x30[RBP] 0x0F, 0x38, 0x04, 0xCA, // pmaddubsw MM1, MM2 0x66, 0x0F, 0x38, 0x04, 0xCA, // pmaddubsw XMM1, XMM2 0x0F, 0x38, 0x04, 0x5D, 0xC8, // pmaddubsw MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x04, 0x5D, 0xD0, // pmaddubsw XMM3, -0x30[RBP] 0x0F, 0x38, 0x0B, 0xCA, // pmulhrsw MM1, MM2 0x66, 0x0F, 0x38, 0x0B, 0xCA, // pmulhrsw XMM1, XMM2 0x0F, 0x38, 0x0B, 0x5D, 0xC8, // pmulhrsw MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x0B, 0x5D, 0xD0, // pmulhrsw XMM3, -0x30[RBP] 0x0F, 0x38, 0x00, 0xCA, // pshufb MM1, MM2 0x66, 0x0F, 0x38, 0x00, 0xCA, // pshufb XMM1, XMM2 0x0F, 0x38, 0x00, 0x5D, 0xC8, // pshufb MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x00, 0x5D, 0xD0, // pshufb XMM3, -0x30[RBP] 0x0F, 0x38, 0x1C, 0xCA, // pabsb MM1, MM2 0x66, 0x0F, 0x38, 0x1C, 0xCA, // pabsb XMM1, XMM2 0x0F, 0x38, 0x1C, 0x5D, 0xC8, // pabsb MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x1C, 0x5D, 0xD0, // pabsb XMM3, -0x30[RBP] 0x0F, 0x38, 0x1E, 0xCA, // pabsd MM1, MM2 0x66, 0x0F, 0x38, 0x1E, 0xCA, // pabsd XMM1, XMM2 0x0F, 0x38, 0x1E, 0x5D, 0xC8, // pabsd MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x1E, 0x5D, 0xD0, // pabsd XMM3, -0x30[RBP] 0x0F, 0x38, 0x1D, 0xCA, // pabsw MM1, MM2 0x66, 0x0F, 0x38, 0x1D, 0xCA, // pabsw XMM1, XMM2 0x0F, 0x38, 0x1D, 0x5D, 0xC8, // pabsw MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x1D, 0x5D, 0xD0, // pabsw XMM3, -0x30[RBP] 0x0F, 0x38, 0x08, 0xCA, // psignb MM1, MM2 0x66, 0x0F, 0x38, 0x08, 0xCA, // psignb XMM1, XMM2 0x0F, 0x38, 0x08, 0x5D, 0xC8, // psignb MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x08, 0x5D, 0xD0, // psignb XMM3, -0x30[RBP] 0x0F, 0x38, 0x0A, 0xCA, // psignd MM1, MM2 0x66, 0x0F, 0x38, 0x0A, 0xCA, // psignd XMM1, XMM2 0x0F, 0x38, 0x0A, 0x5D, 0xC8, // psignd MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x0A, 0x5D, 0xD0, // psignd XMM3, -0x30[RBP] 0x0F, 0x38, 0x09, 0xCA, // psignw MM1, MM2 0x66, 0x0F, 0x38, 0x09, 0xCA, // psignw XMM1, XMM2 0x0F, 0x38, 0x09, 0x5D, 0xC8, // psignw MM3, -0x38[RBP] 0x66, 0x0F, 0x38, 0x09, 0x5D, 0xD0, // psignw XMM3, -0x30[RBP] ]; asm { call L1; palignr MM1, MM2, 3; palignr XMM1, XMM2, 3; palignr MM3, m64 , 3; palignr XMM3, m128, 3; phaddd MM1, MM2; phaddd XMM1, XMM2; phaddd MM3, m64; phaddd XMM3, m128; phaddw MM1, MM2; phaddw XMM1, XMM2; phaddw MM3, m64; phaddw XMM3, m128; phaddsw MM1, MM2; phaddsw XMM1, XMM2; phaddsw MM3, m64; phaddsw XMM3, m128; phsubd MM1, MM2; phsubd XMM1, XMM2; phsubd MM3, m64; phsubd XMM3, m128; phsubw MM1, MM2; phsubw XMM1, XMM2; phsubw MM3, m64; phsubw XMM3, m128; phsubsw MM1, MM2; phsubsw XMM1, XMM2; phsubsw MM3, m64; phsubsw XMM3, m128; pmaddubsw MM1, MM2; pmaddubsw XMM1, XMM2; pmaddubsw MM3, m64; pmaddubsw XMM3, m128; pmulhrsw MM1, MM2; pmulhrsw XMM1, XMM2; pmulhrsw MM3, m64; pmulhrsw XMM3, m128; pshufb MM1, MM2; pshufb XMM1, XMM2; pshufb MM3, m64; pshufb XMM3, m128; pabsb MM1, MM2; pabsb XMM1, XMM2; pabsb MM3, m64; pabsb XMM3, m128; pabsd MM1, MM2; pabsd XMM1, XMM2; pabsd MM3, m64; pabsd XMM3, m128; pabsw MM1, MM2; pabsw XMM1, XMM2; pabsw MM3, m64; pabsw XMM3, m128; psignb MM1, MM2; psignb XMM1, XMM2; psignb MM3, m64; psignb XMM3, m128; psignd MM1, MM2; psignd XMM1, XMM2; psignd MM3, m64; psignd XMM3, m128; psignw MM1, MM2; psignw XMM1, XMM2; psignw MM3, m64; psignw XMM3, m128; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } /****************************************************/ /* ======================= SSE4.1 ======================= */ void test58() { ubyte* p; byte m8; short m16; int m32; M64 m64; M128 m128; static ubyte data[] = [ 0x66, 0x0F, 0x3A, 0x0D, 0xCA, 3,// blendpd XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x0D, 0x5D, 0xD0, 3,// blendpd XMM3,XMMWORD PTR [RBP-0x30],0x3 0x66, 0x0F, 0x3A, 0x0C, 0xCA, 3,// blendps XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x0C, 0x5D, 0xD0, 3,// blendps XMM3,XMMWORD PTR [RBP-0x30],0x3 0x66, 0x0F, 0x38, 0x15, 0xCA, // blendvpd XMM1,XMM2,XMM0 0x66, 0x0F, 0x38, 0x15, 0x5D, 0xD0, // blendvpd XMM3,XMMWORD PTR [RBP-0x30],XMM0 0x66, 0x0F, 0x38, 0x14, 0xCA, // blendvps XMM1,XMM2,XMM0 0x66, 0x0F, 0x38, 0x14, 0x5D, 0xD0, // blendvps XMM3,XMMWORD PTR [RBP-0x30],XMM0 0x66, 0x0F, 0x3A, 0x41, 0xCA, 3,// dppd XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x41, 0x5D, 0xD0, 3,// dppd XMM3,XMMWORD PTR [RBP-0x30],0x3 0x66, 0x0F, 0x3A, 0x40, 0xCA, 3,// dpps XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x40, 0x5D, 0xD0, 3,// dpps XMM3,XMMWORD PTR [RBP-0x30],0x3 0x66, 0x0F, 0x3A, 0x17, 0xD2, 3,// extractps EDX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x17, 0x55, 0xBC, 3,// extractps DWORD PTR [RBP-0x44],XMM2,0x3 0x66, 0x0F, 0x3A, 0x21, 0xCA, 3,// insertps XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x21, 0x5D, 0xBC, 3,// insertps XMM3,DWORD PTR [RBP-0x44],0x3 0x66, 0x0F, 0x38, 0x2A, 0x4D, 0xD0, // movntdqa XMM1,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x3A, 0x42, 0xCA, 3,// mpsadbw XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x42, 0x5D, 0xD0, 3,// mpsadbw XMM3,XMMWORD PTR [RBP-0x30],0x3 0x66, 0x0F, 0x38, 0x2B, 0xCA, // packusdw XMM1,XMM2 0x66, 0x0F, 0x38, 0x2B, 0x5D, 0xD0, // packusdw XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x10, 0xCA, // pblendvb XMM1,XMM2,XMM0 0x66, 0x0F, 0x38, 0x10, 0x5D, 0xD0, // pblendvb XMM3,XMMWORD PTR [RBP-0x30],XMM0 0x66, 0x0F, 0x3A, 0x0E, 0xCA, 3,// pblendw XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x0E, 0x5D, 0xD0, 3,// pblendw XMM3,XMMWORD PTR [RBP-0x30],0x3 0x66, 0x0F, 0x38, 0x29, 0xCA, // pcmpeqq XMM1,XMM2 0x66, 0x0F, 0x38, 0x29, 0x5D, 0xD0, // pcmpeqq XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x3A, 0x14, 0xD0, 3,// pextrb EAX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x14, 0xD3, 3,// pextrb EBX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x14, 0xD1, 3,// pextrb ECX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x14, 0xD2, 3,// pextrb EDX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x14, 0xD0, 3,// pextrb EAX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x14, 0xD3, 3,// pextrb EBX,XMM2,0x3 0x66, 0x41, 0x0F, 0x3A, 0x14, 0xD0, 3,// pextrb R8D,XMM2,0x3 0x66, 0x41, 0x0F, 0x3A, 0x14, 0xD2, 3,// pextrb R10D,XMM2,0x3 0x66, 0x0F, 0x3A, 0x14, 0x5D, 0xB8, 3,// pextrb BYTE PTR [RBP-0x48],XMM3,0x3 0x66, 0x0F, 0x3A, 0x16, 0xD0, 3,// pextrd EAX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x16, 0xD3, 3,// pextrd EBX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x16, 0xD1, 3,// pextrd ECX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x16, 0xD2, 3,// pextrd EDX,XMM2,0x3 0x66, 0x0F, 0x3A, 0x16, 0x5D, 0xBC, 3,// pextrd DWORD PTR [RBP-0x44],XMM3,0x3 0x66, 0x48, 0x0F, 0x3A, 0x16, 0xD0, 3,// pextrq RAX,XMM2,0x3 0x66, 0x48, 0x0F, 0x3A, 0x16, 0xD3, 3,// pextrq RBX,XMM2,0x3 0x66, 0x48, 0x0F, 0x3A, 0x16, 0xD1, 3,// pextrq RCX,XMM2,0x3 0x66, 0x48, 0x0F, 0x3A, 0x16, 0xD2, 3,// pextrq RDX,XMM2,0x3 0x66, 0x48, 0x0F, 0x3A, 0x16, 0x5D, 0xC0, 3,// pextrq QWORD PTR [RBP-0x40],XMM3,0x3 0x66, 0x0F, 0xC5, 0xC2, 3,// pextrw EAX,XMM2,0x3 0x66, 0x0F, 0xC5, 0xDA, 3,// pextrw EBX,XMM2,0x3 0x66, 0x0F, 0xC5, 0xCA, 3,// pextrw ECX,XMM2,0x3 0x66, 0x0F, 0xC5, 0xD2, 3,// pextrw EDX,XMM2,0x3 0x66, 0x0F, 0xC5, 0xC2, 3,// pextrw EAX,XMM2,0x3 0x66, 0x0F, 0xC5, 0xDA, 3,// pextrw EBX,XMM2,0x3 0x66, 0x44, 0x0F, 0xC5, 0xC2, 3,// pextrw R8D,XMM2,0x3 0x66, 0x44, 0x0F, 0xC5, 0xD2, 3,// pextrw R10D,XMM2,0x3 0x66, 0x0F, 0x3A, 0x15, 0x5D, 0xBA, 3,// pextrw WORD PTR [RBP-0x46],XMM3,0x3 0x66, 0x0F, 0x38, 0x41, 0xCA, // phminposuw XMM1,XMM2 0x66, 0x0F, 0x38, 0x41, 0x5D, 0xD0, // phminposuw XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x3A, 0x20, 0xC8, 3,// pinsrb XMM1,EAX,0x3 0x66, 0x0F, 0x3A, 0x20, 0xCB, 3,// pinsrb XMM1,EBX,0x3 0x66, 0x0F, 0x3A, 0x20, 0xC9, 3,// pinsrb XMM1,ECX,0x3 0x66, 0x0F, 0x3A, 0x20, 0xCA, 3,// pinsrb XMM1,EDX,0x3 0x66, 0x0F, 0x3A, 0x20, 0x5D, 0xB8, 3,// pinsrb XMM3,BYTE PTR [RBP-0x48],0x3 0x66, 0x0F, 0x3A, 0x22, 0xC8, 3,// pinsrd XMM1,EAX,0x3 0x66, 0x0F, 0x3A, 0x22, 0xCB, 3,// pinsrd XMM1,EBX,0x3 0x66, 0x0F, 0x3A, 0x22, 0xC9, 3,// pinsrd XMM1,ECX,0x3 0x66, 0x0F, 0x3A, 0x22, 0xCA, 3,// pinsrd XMM1,EDX,0x3 0x66, 0x0F, 0x3A, 0x22, 0x5D, 0xBC, 3,// pinsrd XMM3,DWORD PTR [RBP-0x44],0x3 0x66, 0x48, 0x0F, 0x3A, 0x22, 0xC8, 3,// pinsrq XMM1,RAX,0x3 0x66, 0x48, 0x0F, 0x3A, 0x22, 0xCB, 3,// pinsrq XMM1,RBX,0x3 0x66, 0x48, 0x0F, 0x3A, 0x22, 0xC9, 3,// pinsrq XMM1,RCX,0x3 0x66, 0x48, 0x0F, 0x3A, 0x22, 0xCA, 3,// pinsrq XMM1,RDX,0x3 0x66, 0x48, 0x0F, 0x3A, 0x22, 0x5D, 0xC0, 3,// pinsrq XMM3,QWORD PTR [RBP-0x40],0x3 0x66, 0x0F, 0x38, 0x3C, 0xCA, // pmaxsb XMM1,XMM2 0x66, 0x0F, 0x38, 0x3C, 0x5D, 0xD0, // pmaxsb XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x3D, 0xCA, // pmaxsd XMM1,XMM2 0x66, 0x0F, 0x38, 0x3D, 0x5D, 0xD0, // pmaxsd XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x3F, 0xCA, // pmaxud XMM1,XMM2 0x66, 0x0F, 0x38, 0x3F, 0x5D, 0xD0, // pmaxud XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x3E, 0xCA, // pmaxuw XMM1,XMM2 0x66, 0x0F, 0x38, 0x3E, 0x5D, 0xD0, // pmaxuw XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x38, 0xCA, // pminsb XMM1,XMM2 0x66, 0x0F, 0x38, 0x38, 0x5D, 0xD0, // pminsb XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x39, 0xCA, // pminsd XMM1,XMM2 0x66, 0x0F, 0x38, 0x39, 0x5D, 0xD0, // pminsd XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x3B, 0xCA, // pminud XMM1,XMM2 0x66, 0x0F, 0x38, 0x3B, 0x5D, 0xD0, // pminud XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x3A, 0xCA, // pminuw XMM1,XMM2 0x66, 0x0F, 0x38, 0x3A, 0x5D, 0xD0, // pminuw XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x20, 0xCA, // pmovsxbw XMM1,XMM2 0x66, 0x0F, 0x38, 0x20, 0x5D, 0xC0, // pmovsxbw XMM3,QWORD PTR [RBP-0x40] 0x66, 0x0F, 0x38, 0x21, 0xCA, // pmovsxbd XMM1,XMM2 0x66, 0x0F, 0x38, 0x21, 0x5D, 0xBC, // pmovsxbd XMM3,DWORD PTR [RBP-0x44] 0x66, 0x0F, 0x38, 0x22, 0xCA, // pmovsxbq XMM1,XMM2 0x66, 0x0F, 0x38, 0x22, 0x5D, 0xBA, // pmovsxbq XMM3,WORD PTR [RBP-0x46] 0x66, 0x0F, 0x38, 0x23, 0xCA, // pmovsxwd XMM1,XMM2 0x66, 0x0F, 0x38, 0x23, 0x5D, 0xC0, // pmovsxwd XMM3,QWORD PTR [RBP-0x40] 0x66, 0x0F, 0x38, 0x24, 0xCA, // pmovsxwq XMM1,XMM2 0x66, 0x0F, 0x38, 0x24, 0x5D, 0xBC, // pmovsxwq XMM3,DWORD PTR [RBP-0x44] 0x66, 0x0F, 0x38, 0x25, 0xCA, // pmovsxdq XMM1,XMM2 0x66, 0x0F, 0x38, 0x25, 0x5D, 0xC0, // pmovsxdq XMM3,QWORD PTR [RBP-0x40] 0x66, 0x0F, 0x38, 0x30, 0xCA, // pmovzxbw XMM1,XMM2 0x66, 0x0F, 0x38, 0x30, 0x5D, 0xC0, // pmovzxbw XMM3,QWORD PTR [RBP-0x40] 0x66, 0x0F, 0x38, 0x31, 0xCA, // pmovzxbd XMM1,XMM2 0x66, 0x0F, 0x38, 0x31, 0x5D, 0xBC, // pmovzxbd XMM3,DWORD PTR [RBP-0x44] 0x66, 0x0F, 0x38, 0x32, 0xCA, // pmovzxbq XMM1,XMM2 0x66, 0x0F, 0x38, 0x32, 0x5D, 0xBA, // pmovzxbq XMM3,WORD PTR [RBP-0x46] 0x66, 0x0F, 0x38, 0x33, 0xCA, // pmovzxwd XMM1,XMM2 0x66, 0x0F, 0x38, 0x33, 0x5D, 0xC0, // pmovzxwd XMM3,QWORD PTR [RBP-0x40] 0x66, 0x0F, 0x38, 0x34, 0xCA, // pmovzxwq XMM1,XMM2 0x66, 0x0F, 0x38, 0x34, 0x5D, 0xBC, // pmovzxwq XMM3,DWORD PTR [RBP-0x44] 0x66, 0x0F, 0x38, 0x35, 0xCA, // pmovzxdq XMM1,XMM2 0x66, 0x0F, 0x38, 0x35, 0x5D, 0xC0, // pmovzxdq XMM3,QWORD PTR [RBP-0x40] 0x66, 0x0F, 0x38, 0x28, 0xCA, // pmuldq XMM1,XMM2 0x66, 0x0F, 0x38, 0x28, 0x5D, 0xD0, // pmuldq XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x40, 0xCA, // pmulld XMM1,XMM2 0x66, 0x0F, 0x38, 0x40, 0x5D, 0xD0, // pmulld XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x38, 0x17, 0xCA, // ptest XMM1,XMM2 0x66, 0x0F, 0x38, 0x17, 0x5D, 0xD0, // ptest XMM3,XMMWORD PTR [RBP-0x30] 0x66, 0x0F, 0x3A, 0x09, 0xCA, 3,// roundpd XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x09, 0x5D, 0xD0, 3,// roundpd XMM3,XMMWORD PTR [RBP-0x30],0x3 0x66, 0x0F, 0x3A, 0x08, 0xCA, 3,// roundps XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x08, 0x5D, 0xD0, 3,// roundps XMM3,XMMWORD PTR [RBP-0x30],0x3 0x66, 0x0F, 0x3A, 0x0B, 0xCA, 3,// roundsd XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x0B, 0x5D, 0xC0, 3,// roundsd XMM3,QWORD PTR [RBP-0x40],0x3 0x66, 0x0F, 0x3A, 0x0A, 0xCA, 3,// roundss XMM1,XMM2,0x3 0x66, 0x0F, 0x3A, 0x0A, 0x4D, 0xBC, 3,// roundss xmm1,dword ptr [rbp-0x44],0x3 ]; asm { call L1; blendpd XMM1, XMM2, 3; blendpd XMM3, m128, 3; blendps XMM1, XMM2, 3; blendps XMM3, m128, 3; blendvpd XMM1, XMM2, XMM0; blendvpd XMM3, m128, XMM0; blendvps XMM1, XMM2, XMM0; blendvps XMM3, m128, XMM0; dppd XMM1, XMM2, 3; dppd XMM3, m128, 3; dpps XMM1, XMM2, 3; dpps XMM3, m128, 3; extractps EDX, XMM2, 3; extractps m32, XMM2, 3; insertps XMM1, XMM2, 3; insertps XMM3, m32, 3; movntdqa XMM1, m128; mpsadbw XMM1, XMM2, 3; mpsadbw XMM3, m128, 3; packusdw XMM1, XMM2; packusdw XMM3, m128; pblendvb XMM1, XMM2, XMM0; pblendvb XMM3, m128, XMM0; pblendw XMM1, XMM2, 3; pblendw XMM3, m128, 3; pcmpeqq XMM1, XMM2; pcmpeqq XMM3, m128; pextrb EAX, XMM2, 3; pextrb EBX, XMM2, 3; pextrb ECX, XMM2, 3; pextrb EDX, XMM2, 3; pextrb RAX, XMM2, 3; pextrb RBX, XMM2, 3; pextrb R8 , XMM2, 3; pextrb R10, XMM2, 3; pextrb m8, XMM3, 3; pextrd EAX, XMM2, 3; pextrd EBX, XMM2, 3; pextrd ECX, XMM2, 3; pextrd EDX, XMM2, 3; pextrd m32, XMM3, 3; pextrq RAX, XMM2, 3; pextrq RBX, XMM2, 3; pextrq RCX, XMM2, 3; pextrq RDX, XMM2, 3; pextrq m64, XMM3, 3; pextrw EAX, XMM2, 3; pextrw EBX, XMM2, 3; pextrw ECX, XMM2, 3; pextrw EDX, XMM2, 3; pextrw RAX, XMM2, 3; pextrw RBX, XMM2, 3; pextrw R8 , XMM2, 3; pextrw R10, XMM2, 3; pextrw m16, XMM3, 3; phminposuw XMM1, XMM2; phminposuw XMM3, m128; pinsrb XMM1, EAX, 3; pinsrb XMM1, EBX, 3; pinsrb XMM1, ECX, 3; pinsrb XMM1, EDX, 3; pinsrb XMM3, m8, 3; pinsrd XMM1, EAX, 3; pinsrd XMM1, EBX, 3; pinsrd XMM1, ECX, 3; pinsrd XMM1, EDX, 3; pinsrd XMM3, m32, 3; pinsrq XMM1, RAX, 3; pinsrq XMM1, RBX, 3; pinsrq XMM1, RCX, 3; pinsrq XMM1, RDX, 3; pinsrq XMM3, m64, 3; pmaxsb XMM1, XMM2; pmaxsb XMM3, m128; pmaxsd XMM1, XMM2; pmaxsd XMM3, m128; pmaxud XMM1, XMM2; pmaxud XMM3, m128; pmaxuw XMM1, XMM2; pmaxuw XMM3, m128; pminsb XMM1, XMM2; pminsb XMM3, m128; pminsd XMM1, XMM2; pminsd XMM3, m128; pminud XMM1, XMM2; pminud XMM3, m128; pminuw XMM1, XMM2; pminuw XMM3, m128; pmovsxbw XMM1, XMM2; pmovsxbw XMM3, m64; pmovsxbd XMM1, XMM2; pmovsxbd XMM3, m32; pmovsxbq XMM1, XMM2; pmovsxbq XMM3, m16; pmovsxwd XMM1, XMM2; pmovsxwd XMM3, m64; pmovsxwq XMM1, XMM2; pmovsxwq XMM3, m32; pmovsxdq XMM1, XMM2; pmovsxdq XMM3, m64; pmovzxbw XMM1, XMM2; pmovzxbw XMM3, m64; pmovzxbd XMM1, XMM2; pmovzxbd XMM3, m32; pmovzxbq XMM1, XMM2; pmovzxbq XMM3, m16; pmovzxwd XMM1, XMM2; pmovzxwd XMM3, m64; pmovzxwq XMM1, XMM2; pmovzxwq XMM3, m32; pmovzxdq XMM1, XMM2; pmovzxdq XMM3, m64; pmuldq XMM1, XMM2; pmuldq XMM3, m128; pmulld XMM1, XMM2; pmulld XMM3, m128; ptest XMM1, XMM2; ptest XMM3, m128; roundpd XMM1, XMM2, 3; roundpd XMM3, m128, 3; roundps XMM1, XMM2, 3; roundps XMM3, m128, 3; roundsd XMM1, XMM2, 3; roundsd XMM3, m64, 3; roundss XMM1, XMM2, 3; roundss XMM1, m32, 3; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } /****************************************************/ /* ======================= SSE4.2 ======================= */ void test59() { ubyte* p; byte m8; short m16; int m32; M64 m64; M128 m128; static ubyte data[] = [ 0xF2, 0x0F, 0x38, 0xF0, 0xC1, // crc32 EAX, CL 0x66, 0xF2, 0x0F, 0x38, 0xF1, 0xC1, // crc32 EAX, CX 0xF2, 0x0F, 0x38, 0xF1, 0xC1, // crc32 EAX, ECX 0xF2, 0x48, 0x0F, 0x38, 0xF0, 0xC1, // crc32 RAX, CL 0xF2, 0x48, 0x0F, 0x38, 0xF1, 0xC1, // crc32 RAX, RCX 0xF2, 0x0F, 0x38, 0xF0, 0x55, 0xB8, // crc32 EDX, byte ptr [RBP-0x48] 0x66, 0xF2, 0x0F, 0x38, 0xF1, 0x55, 0xBA, // crc32 EDX, word ptr [RBP-0x46] 0xF2, 0x0F, 0x38, 0xF1, 0x55, 0xBC, // crc32 EDX,dword ptr [RBP-0x44] 0xF2, 0x48, 0x0F, 0x38, 0xF0, 0x55, 0xB8, // crc32 RDX, byte ptr [RBP-0x48] 0xF2, 0x48, 0x0F, 0x38, 0xF1, 0x55, 0xC0, // crc32 RDX,qword ptr [RBP-0x40] 0x66, 0x0F, 0x3A, 0x61, 0xCA, 2, // pcmpestri XMM1,XMM2, 2 0x66, 0x0F, 0x3A, 0x61, 0x5D, 0xD0, 2, // pcmpestri XMM3,xmmword ptr [RBP-0x30], 2 0x66, 0x0F, 0x3A, 0x60, 0xCA, 2, // pcmpestrm XMM1,XMM2, 2 0x66, 0x0F, 0x3A, 0x60, 0x5D, 0xD0, 2, // pcmpestrm XMM3,xmmword ptr [RBP-0x30], 2 0x66, 0x0F, 0x3A, 0x63, 0xCA, 2, // pcmpistri XMM1,XMM2, 2 0x66, 0x0F, 0x3A, 0x63, 0x5D, 0xD0, 2, // pcmpistri XMM3,xmmword ptr [RBP-0x30], 2 0x66, 0x0F, 0x3A, 0x62, 0xCA, 2, // pcmpistrm XMM1,XMM2, 2 0x66, 0x0F, 0x3A, 0x62, 0x5D, 0xD0, 2, // pcmpistrm XMM3,xmmword ptr [RBP-0x30], 2 0x66, 0x0F, 0x38, 0x37, 0xCA, // pcmpgtq XMM1,XMM2 0x66, 0x0F, 0x38, 0x37, 0x5D, 0xD0, // pcmpgtq XMM3,xmmword ptr [RBP-0x30] 0x66, 0xF3, 0x0F, 0xB8, 0xC1, // popcnt AX, CX 0xF3, 0x0F, 0xB8, 0xC1, // popcnt EAX, ECX 0xF3, 0x48, 0x0F, 0xB8, 0xC1, // popcnt RAX, RCX 0x66, 0xF3, 0x0F, 0xB8, 0x55, 0xBA, // popcnt DX, word ptr [RBP-0x46] 0xF3, 0x0F, 0xB8, 0x55, 0xBC, // popcnt EDX,dword ptr [RBP-0x44] 0xF3, 0x48, 0x0F, 0xB8, 0x55, 0xC0 // popcnt RDX,qword ptr [RBP-0x40] ]; asm { call L1; crc32 EAX, CL; crc32 EAX, CX; crc32 EAX, ECX; crc32 RAX, CL; crc32 RAX, RCX; crc32 EDX, m8; crc32 EDX, m16; crc32 EDX, m32; crc32 RDX, m8; crc32 RDX, m64; pcmpestri XMM1, XMM2, 2; pcmpestri XMM3, m128, 2; pcmpestrm XMM1, XMM2, 2; pcmpestrm XMM3, m128, 2; pcmpistri XMM1, XMM2, 2; pcmpistri XMM3, m128, 2; pcmpistrm XMM1, XMM2, 2; pcmpistrm XMM3, m128, 2; pcmpgtq XMM1, XMM2; pcmpgtq XMM3, m128; popcnt AX, CX; popcnt EAX, ECX; popcnt RAX, RCX; popcnt DX, m16; popcnt EDX, m32; popcnt RDX, m64; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } void test60() { ubyte *p; static ubyte data[] = [ 0x49, 0x8B, 0x00, // mov RAX, [R8] 0x4D, 0x8B, 0x00, // mov R8, [R8] 0x49, 0x89, 0x00, // mov [R8], RAX 0x4D, 0x89, 0x00, // mov [R8], R8 0x41, 0x0F, 0x10, 0x00, // movups XMM0, [R8] 0x45, 0x0F, 0x10, 0x00, // movups XMM8, [R8] ]; asm { call L1; mov RAX, [R8]; mov R8, [R8]; mov [R8], RAX; mov [R8], R8; movups XMM0, [R8]; movups XMM8, [R8]; L1: pop RAX; mov p[RBP], RAX; } foreach (ref i, b; data) { assert(p[i] == b); } } /* ======================= AVX ======================= */ void test61() { ubyte* p; static ubyte data[] = [ 0x0F, 0x01, 0xD0, // xgetbv 0x0F, 0x01, 0xD1, // xsetbv 0x0F, 0xAE, 0x28, // xrstor [RAX] 0x48, 0x0F, 0xAE, 0x28, // xrstor64 [RAX] 0x0F, 0xAE, 0x20, // xsave [RAX] 0x48, 0x0F, 0xAE, 0x20, // xsave64 [RAX] 0x0F, 0xAE, 0x30, // xsaveopt [RAX] 0x48, 0x0F, 0xAE, 0x30, // xsaveopt64 [RAX] 0xC5, 0xF8, 0xAE, 0x10, // vldmxcsr [RAX] 0xC5, 0xF8, 0xAE, 0x18, // vstmxcsr [RAX] 0xC5, 0xF2, 0x58, 0xC2, // vaddss XMM0, XMM1, XMM2; 0xC5, 0x83, 0x58, 0x00, // vaddsd XMM0, XMM15, [RAX]; 0xC5, 0x78, 0x58, 0xE0, // vaddps XMM12, XMM0, XMM0; 0xC4, 0x41, 0x39, 0x58, 0xC0, // vaddpd XMM8, XMM8, XMM8; 0xC5, 0xF2, 0x5C, 0xC2, // vsubss XMM0, XMM1, XMM2; 0xC5, 0x83, 0x5C, 0x00, // vsubsd XMM0, XMM1, [RAX]; 0xC5, 0x78, 0x5C, 0xE0, // vsubps XMM12, XMM0, XMM0; 0xC4, 0x41, 0x39, 0x5C, 0xC0, // vsubpd XMM8, XMM8, XMM8; 0xC5, 0xF3, 0xD0, 0xC2, // vaddsubps XMM0, XMM1, XMM2; 0xC5, 0xF7, 0xD0, 0xC2, // vaddsubps YMM0, YMM1, YMM2; 0xC5, 0x75, 0xD0, 0xC2, // vaddsubpd YMM8, YMM1, YMM2; 0xC5, 0x05, 0xD0, 0x78, 0x40, // vaddsubpd YMM15, YMM15, 64[RAX]; 0xC4, 0xE3, 0x7D, 0x40, 0xC0, 0x00, // vdpps YMM0, YMM0, YMM0, 0 0xC4, 0xE3, 0x79, 0x41, 0xC0, 0x88, // vdppd XMM0, XMM0, XMM0, 0x88 0xC5, 0xBD, 0x7C, 0x07, // vhaddpd YMM0, YMM8, [RDI]; 0xC5, 0xBB, 0x7C, 0xC1, // vhaddps XMM0, XMM8, XMM1; 0xC5, 0xFD, 0x5F, 0xC1, // vmaxpd YMM0, YMM0, YMM1; 0xC5, 0xF9, 0x5F, 0x00, // vmaxpd XMM0, XMM0, [RAX]; 0xC5, 0xFC, 0x5F, 0xC1, // vmaxps YMM0, YMM0, YMM1; 0xC5, 0xF8, 0x5F, 0x00, // vmaxps XMM0, XMM0, [RAX]; 0xC5, 0xFB, 0x5F, 0x00, // vmaxsd XMM0, XMM0, [RAX]; 0xC5, 0xFA, 0x5F, 0x00, // vmaxss XMM0, XMM0, [RAX]; 0xC5, 0xFD, 0x5D, 0xC1, // vminpd YMM0, YMM0, YMM1; 0xC5, 0xF9, 0x5D, 0x00, // vminpd XMM0, XMM0, [RAX]; 0xC5, 0xFC, 0x5D, 0xC1, // vminps YMM0, YMM0, YMM1; 0xC5, 0xF8, 0x5D, 0x00, // vminps XMM0, XMM0, [RAX]; 0xC5, 0xFB, 0x5D, 0x00, // vminsd XMM0, XMM0, [RAX]; 0xC5, 0xFA, 0x5D, 0x00, // vminss XMM0, XMM0, [RAX]; 0xC5, 0xF9, 0x50, 0xC0, // vmovmskpd EAX, XMM0; 0xC5, 0xFD, 0x50, 0xF8, // vmovmskpd EDI, YMM0; 0xC4, 0xC1, 0x7C, 0x50, 0xC7, // vmovmskps EAX, YMM15; 0xC5, 0x7C, 0x50, 0xC0, // vmovmskps R8D, YMM0; 0xC5, 0xF9, 0xD7, 0xC0, // vpmovmskb EAX, XMM0; 0xC4, 0xE3, 0x71, 0x42, 0xC2, 0x00, // vmpsadbw XMM0, XMM1, XMM2, 0x00; 0xC4, 0x43, 0x31, 0x42, 0xC2, 0xFF, // vmpsadbw XMM8, XMM9, XMM10, 0xFF; 0xC4, 0xE2, 0x79, 0x1C, 0x00, // vpabsb XMM0, [RAX]; 0xC4, 0xC2, 0x79, 0x1D, 0xCF, // vpabsw XMM1, XMM15; 0xC4, 0xE2, 0x79, 0x1E, 0x0B, // vpabsd XMM1, [RBX]; 0xC5, 0xF9, 0xFC, 0x00, // vpaddb XMM0, XMM0, [RAX]; 0xC4, 0x41, 0x39, 0xFD, 0xC7, // vpaddw XMM8, XMM8, XMM15; 0xC5, 0x39, 0xFE, 0x03, // vpaddd XMM8, XMM8, [RBX]; 0xC5, 0xF9, 0xD4, 0xC0, // vpaddq XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xF8, 0x00, // vpsubb XMM0, XMM0, [RAX]; 0xC4, 0x41, 0x39, 0xF9, 0xC7, // vpsubw XMM8, XMM8, XMM15; 0xC5, 0x39, 0xFA, 0x03, // vpsubd XMM8, XMM8, [RBX]; 0xC5, 0xF9, 0xFB, 0xC0, // vpsubq XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xEC, 0xC0, // vpaddsb XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xED, 0xC0, // vpaddsw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xDC, 0xC0, // vpaddusb XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xDD, 0xC0, // vpaddusw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xE8, 0xC0, // vpsubsb XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xE9, 0xC0, // vpsubsw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xD8, 0xC0, // vpsubusb XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xD9, 0xC0, // vpsubusw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xE0, 0xC0, // vpavgb XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xE3, 0xC0, // vpavgw XMM0, XMM0, XMM0; 0xC4, 0xE3, 0x79, 0x44, 0x44, 0x88, 0x40, 0x00, // vpclmulqdq XMM0, XMM0, 64[RAX + 4 * RCX], 0; 0xC4, 0xE2, 0x79, 0x01, 0xC0, // vphaddw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x02, 0xC0, // vphaddd XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x05, 0xC0, // vphsubw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x06, 0xC0, // vphsubd XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x03, 0xC0, // vphaddsw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x07, 0xC0, // vphsubsw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x41, 0xC0, // vphminposuw XMM0, XMM0; 0xC5, 0xF9, 0xF5, 0xC0, // vpmaddwd XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x04, 0xC0, // vpmaddubsw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x3C, 0xC0, // vpmaxsb XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x3D, 0xC0, // vpmaxsd XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xEE, 0xC0, // vpmaxsw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xDE, 0xC0, // vpmaxub XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x3F, 0xC0, // vpmaxud XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x3E, 0xC0, // vpmaxuw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x38, 0xC0, // vpminsb XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x39, 0xC0, // vpminsd XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xEA, 0xC0, // vpminsw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xDA, 0xC0, // vpminub XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x3B, 0xC0, // vpminud XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x3A, 0xC0, // vpminuw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x0B, 0xC0, // vpmulhrsw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xE4, 0xC0, // vpmulhuw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xE5, 0xC0, // vpmulhw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x40, 0xC0, // vpmulld XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xD5, 0xC0, // vpmullw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xF4, 0xC0, // vpmuludq XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x28, 0xC0, // vpmuldq XMM0, XMM0, XMM0; 0xC5, 0xF9, 0xF6, 0xC0, // vpsadbw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x08, 0xC0, // vpsignb XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x09, 0xC0, // vpsignw XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x0A, 0xC0, // vpsignd XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x73, 0xF8, 0x00, // vpslldq XMM0, XMM0, 0; 0xC5, 0xF9, 0x71, 0xF0, 0x00, // vpsllw XMM0, XMM0, 0; 0xC5, 0xF9, 0xF1, 0xC0, // vpsllw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x72, 0xF0, 0x00, // vpslld XMM0, XMM0, 0; 0xC5, 0xF9, 0xF2, 0xC0, // vpslld XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x73, 0xF0, 0x00, // vpsllq XMM0, XMM0, 0; 0xC5, 0xF9, 0xF3, 0xC0, // vpsllq XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x71, 0xE0, 0x00, // vpsraw XMM0, XMM0, 0; 0xC5, 0xF9, 0xE1, 0xC0, // vpsraw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x72, 0xE0, 0x00, // vpsrad XMM0, XMM0, 0; 0xC5, 0xF9, 0xE2, 0xC0, // vpsrad XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x73, 0xD8, 0x00, // vpsrldq XMM0, XMM0, 0; 0xC5, 0xF9, 0x71, 0xD0, 0x00, // vpsrlw XMM0, XMM0, 0; 0xC5, 0xF9, 0xD1, 0xC0, // vpsrlw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x72, 0xD0, 0x00, // vpsrld XMM0, XMM0, 0; 0xC5, 0xF9, 0xD2, 0xC0, // vpsrld XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x73, 0xD0, 0x00, // vpsrlq XMM0, XMM0, 0; 0xC5, 0xF9, 0xD3, 0xC0, // vpsrlq XMM0, XMM0, XMM0; 0xC5, 0xF8, 0x53, 0xC1, // vrcpps XMM0, XMM1; 0xC5, 0xFC, 0x53, 0xC1, // vrcpps YMM0, YMM1; 0xC5, 0xFA, 0x53, 0xC1, // vrcpss XMM0, XMM0, XMM1; 0xC4, 0xE3, 0x79, 0x09, 0xC0, 0x00, // vroundpd XMM0, XMM0, 0; 0xC4, 0xE3, 0x7D, 0x09, 0xC0, 0x00, // vroundpd YMM0, YMM0, 0; 0xC4, 0xE3, 0x79, 0x08, 0xC0, 0x00, // vroundps XMM0, XMM0, 0; 0xC4, 0xE3, 0x7D, 0x08, 0xC0, 0x00, // vroundps YMM0, YMM0, 0; 0xC4, 0xE3, 0x79, 0x0B, 0xC0, 0x00, // vroundsd XMM0, XMM0, XMM0, 0; 0xC4, 0xE3, 0x79, 0x0A, 0xC0, 0x00, // vroundss XMM0, XMM0, XMM0, 0; 0xC5, 0xF9, 0x51, 0xC0, // vsqrtpd XMM0, XMM0; 0xC5, 0xFD, 0x51, 0xC0, // vsqrtpd YMM0, YMM0; 0xC5, 0xF8, 0x51, 0xC0, // vsqrtps XMM0, XMM0; 0xC5, 0xFC, 0x51, 0xC0, // vsqrtps YMM0, YMM0; 0xC5, 0xFB, 0x51, 0xC0, // vsqrtsd XMM0, XMM0, XMM0; 0xC5, 0xFA, 0x51, 0xC0, // vsqrtss XMM0, XMM0, XMM0; 0xC5, 0xFC, 0x77, // vzeroall 0xC5, 0xF8, 0x77, // vzeroupper 0xC5, 0xF9, 0xC2, 0xC0, 0x00, // vcmppd XMM0, XMM0, XMM0, 0; 0xC5, 0xFD, 0xC2, 0xC0, 0x00, // vcmppd YMM0, YMM0, YMM0, 0; 0xC5, 0xF8, 0xC2, 0xC0, 0x00, // vcmpps XMM0, XMM0, XMM0, 0; 0xC5, 0xFC, 0xC2, 0xC0, 0x00, // vcmpps YMM0, YMM0, YMM0, 0; 0xC5, 0xFB, 0xC2, 0xC0, 0x00, // vcmpsd XMM0, XMM0, XMM0, 0; 0xC5, 0xFA, 0xC2, 0xC0, 0x00, // vcmpss XMM0, XMM0, XMM0, 0; 0xC5, 0xF9, 0x2F, 0xC0, // vcomisd XMM0, XMM0; 0xC5, 0xF8, 0x2F, 0xC0, // vcomiss XMM0, XMM0; 0xC5, 0xF9, 0x74, 0xC0, // vpcmpeqb XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x75, 0xC0, // vpcmpeqw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x76, 0xC0, // vpcmpeqd XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x29, 0xC0, // vpcmpeqq XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x64, 0xC0, // vpcmpgtb XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x65, 0xC0, // vpcmpgtw XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x66, 0xC0, // vpcmpgtd XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x37, 0xC0, // vpcmpgtq XMM0, XMM0, XMM0; 0xC4, 0xE3, 0x79, 0x61, 0xC0, 0x00, // vpcmpestri XMM0, XMM0, 0; 0xC4, 0xE3, 0x79, 0x60, 0xC0, 0x00, // vpcmpestrm XMM0, XMM0, 0; 0xC4, 0xE3, 0x79, 0x63, 0xC0, 0x00, // vpcmpistri XMM0, XMM0, 0; 0xC4, 0xE3, 0x79, 0x62, 0xC0, 0x00, // vpcmpistrm XMM0, XMM0, 0; 0xC5, 0xFA, 0xE6, 0xC0, // vcvtdq2pd XMM0, XMM0; 0xC5, 0xFE, 0xE6, 0xC0, // vcvtdq2pd YMM0, XMM0; 0xC5, 0xFE, 0xE6, 0x00, // vcvtdq2pd YMM0, [RAX]; 0xC5, 0xF8, 0x5B, 0xC0, // vcvtdq2ps XMM0, XMM0; 0xC5, 0xFC, 0x5B, 0xC0, // vcvtdq2ps YMM0, YMM0; 0xC5, 0xFC, 0x5B, 0x00, // vcvtdq2ps YMM0, [RAX]; 0xC5, 0xFB, 0xE6, 0xC0, // vcvtpd2dq XMM0, XMM0; 0xC5, 0xFF, 0xE6, 0xC0, // vcvtpd2dq XMM0, YMM0; 0xC5, 0xFB, 0xE6, 0x00, // vcvtpd2dq XMM0, [RAX]; 0xC5, 0xF9, 0x5A, 0xC0, // vcvtpd2ps XMM0, XMM0; 0xC5, 0xFD, 0x5A, 0xC0, // vcvtpd2ps XMM0, YMM0; 0xC5, 0xF9, 0x5A, 0x00, // vcvtpd2ps XMM0, [RAX]; 0xC5, 0xF9, 0x5B, 0xC0, // vcvtps2dq XMM0, XMM0; 0xC5, 0xFD, 0x5B, 0xC0, // vcvtps2dq YMM0, YMM0; 0xC5, 0xFD, 0x5B, 0x00, // vcvtps2dq YMM0, [RAX]; 0xC5, 0xF8, 0x5A, 0xC0, // vcvtps2pd XMM0, XMM0; 0xC5, 0xFC, 0x5A, 0xC0, // vcvtps2pd YMM0, XMM0; 0xC5, 0xFC, 0x5A, 0x00, // vcvtps2pd YMM0, [RAX]; 0xC5, 0xFB, 0x2D, 0xC0, // vcvtsd2si EAX, XMM0; 0xC4, 0xE1, 0xFB, 0x2D, 0xC0, // vcvtsd2si RAX, XMM0; 0xC4, 0xE1, 0xFB, 0x2D, 0x00, // vcvtsd2si RAX, [RAX]; 0xC5, 0xFB, 0x5A, 0xC0, // vcvtsd2ss XMM0, XMM0, XMM0; 0xC5, 0xFB, 0x5A, 0x00, // vcvtsd2ss XMM0, XMM0, [RAX]; 0xC5, 0xFB, 0x2A, 0xC0, // vcvtsi2sd XMM0, XMM0, EAX; 0xC4, 0xE1, 0xFB, 0x2A, 0xC0, // vcvtsi2sd XMM0, XMM0, RAX; 0xC5, 0xFB, 0x2A, 0x00, // vcvtsi2sd XMM0, XMM0, [RAX]; 0xC5, 0xFA, 0x2A, 0xC0, // vcvtsi2ss XMM0, XMM0, EAX; 0xC4, 0xE1, 0xFA, 0x2A, 0xC0, // vcvtsi2ss XMM0, XMM0, RAX; 0xC5, 0xFA, 0x2A, 0x00, // vcvtsi2ss XMM0, XMM0, [RAX]; 0xC5, 0xFB, 0x2A, 0xC0, // vcvtsi2sd XMM0, XMM0, EAX; 0xC4, 0xE1, 0xFB, 0x2A, 0xC0, // vcvtsi2sd XMM0, XMM0, RAX; 0xC5, 0xFB, 0x2A, 0x00, // vcvtsi2sd XMM0, XMM0, [RAX]; 0xC5, 0xFA, 0x2D, 0xC0, // vcvtss2si EAX, XMM0; 0xC4, 0xE1, 0xFA, 0x2D, 0xC0, // vcvtss2si RAX, XMM0; 0xC4, 0xE1, 0xFA, 0x2D, 0x00, // vcvtss2si RAX, [RAX]; 0xC5, 0xF9, 0xE6, 0xC0, // vcvttpd2dq XMM0, XMM0; 0xC5, 0xFD, 0xE6, 0xC0, // vcvttpd2dq XMM0, YMM0; 0xC5, 0xF9, 0xE6, 0x00, // vcvttpd2dq XMM0, [RAX]; 0xC5, 0xFA, 0x5B, 0xC0, // vcvttps2dq XMM0, XMM0; 0xC5, 0xFE, 0x5B, 0xC0, // vcvttps2dq YMM0, YMM0; 0xC5, 0xFE, 0x5B, 0x00, // vcvttps2dq YMM0, [RAX]; 0xC5, 0xFB, 0x2C, 0xC0, // vcvttsd2si EAX, XMM0; 0xC4, 0xE1, 0xFB, 0x2C, 0xC0, // vcvttsd2si RAX, XMM0; 0xC4, 0xE1, 0xFB, 0x2C, 0x00, // vcvttsd2si RAX, [RAX]; 0xC5, 0xFA, 0x2C, 0xC0, // vcvttss2si EAX, XMM0; 0xC4, 0xE1, 0xFA, 0x2C, 0xC0, // vcvttss2si RAX, XMM0; 0xC4, 0xE1, 0xFA, 0x2C, 0x00, // vcvttss2si RAX, [RAX]; 0xC4, 0xE2, 0x79, 0x18, 0x00, // vbroadcastss XMM0, [RAX]; 0xC4, 0xE2, 0x7D, 0x18, 0x00, // vbroadcastss YMM0, [RAX]; 0xC4, 0xE2, 0x7D, 0x19, 0x00, // vbroadcastsd YMM0, [RAX]; 0xC4, 0xE2, 0x7D, 0x1A, 0x00, // vbroadcastf128 YMM0, [RAX]; 0xC4, 0xE3, 0x7D, 0x19, 0xC0, 0x00, // vextractf128 XMM0, YMM0, 0; 0xC4, 0xE3, 0x7D, 0x19, 0x00, 0x00, // vextractf128 [RAX], YMM0, 0; 0xC4, 0xE3, 0x79, 0x17, 0xC0, 0x00, // vextractps EAX, XMM0, 0; 0xC4, 0xE3, 0x79, 0x17, 0x00, 0x00, // vextractps [RAX], XMM0, 0; 0xC4, 0xE3, 0x7D, 0x18, 0xC0, 0x00, // vinsertf128 YMM0, YMM0, XMM0, 0; 0xC4, 0xE3, 0x7D, 0x18, 0x00, 0x00, // vinsertf128 YMM0, YMM0, [RAX], 0; 0xC4, 0xE3, 0x79, 0x21, 0xC0, 0x00, // vinsertps XMM0, XMM0, XMM0, 0; 0xC4, 0xE3, 0x79, 0x21, 0x00, 0x00, // vinsertps XMM0, XMM0, [RAX], 0; 0xC4, 0xE3, 0x79, 0x20, 0xC0, 0x00, // vpinsrb XMM0, XMM0, EAX, 0; 0xC4, 0xE3, 0x79, 0x20, 0x00, 0x00, // vpinsrb XMM0, XMM0, [RAX], 0; 0xC5, 0xF9, 0xC4, 0xC0, 0x00, // vpinsrw XMM0, XMM0, EAX, 0; 0xC5, 0xF9, 0xC4, 0x00, 0x00, // vpinsrw XMM0, XMM0, [RAX], 0; 0xC4, 0xE3, 0x79, 0x22, 0xC0, 0x00, // vpinsrd XMM0, XMM0, EAX, 0; 0xC4, 0xE3, 0x79, 0x22, 0x00, 0x00, // vpinsrd XMM0, XMM0, [RAX], 0; 0xC4, 0xE3, 0xF9, 0x22, 0xC0, 0x00, // vpinsrq XMM0, XMM0, RAX, 0; 0xC4, 0xE3, 0xF9, 0x22, 0x00, 0x00, // vpinsrq XMM0, XMM0, [RAX], 0; 0xC5, 0xFB, 0xF0, 0x00, // vlddqu XMM0, [RAX]; 0xC5, 0xFF, 0xF0, 0x00, // vlddqu YMM0, [RAX]; 0xC5, 0xF9, 0xF7, 0xC0, // vmaskmovdqu XMM0, XMM0; 0xC4, 0xE2, 0x79, 0x2C, 0x00, // vmaskmovps XMM0, XMM0, [RAX]; 0xC4, 0xE2, 0x79, 0x2E, 0x00, // vmaskmovps [RAX], XMM0, XMM0; 0xC4, 0xE2, 0x7D, 0x2C, 0x00, // vmaskmovps YMM0, YMM0, [RAX]; 0xC4, 0xE2, 0x7D, 0x2E, 0x00, // vmaskmovps [RAX], YMM0, YMM0; 0xC4, 0xE2, 0x79, 0x2D, 0x00, // vmaskmovpd XMM0, XMM0, [RAX]; 0xC4, 0xE2, 0x79, 0x2F, 0x00, // vmaskmovpd [RAX], XMM0, XMM0; 0xC4, 0xE2, 0x7D, 0x2D, 0x00, // vmaskmovpd YMM0, YMM0, [RAX]; 0xC4, 0xE2, 0x7D, 0x2F, 0x00, // vmaskmovpd [RAX], YMM0, YMM0; 0xC5, 0xFD, 0x28, 0x00, // vmovapd YMM0, [RAX]; 0xC5, 0x7D, 0x28, 0x00, // vmovapd YMM8, [RAX]; 0xC5, 0x7D, 0x28, 0x47, 0x40, // vmovapd YMM8, 64[RDI]; 0xC5, 0xFD, 0x29, 0x00, // vmovapd [RAX], YMM0; 0xC5, 0x7D, 0x29, 0x00, // vmovapd [RAX], YMM8; 0xC5, 0x7D, 0x29, 0x47, 0x40, // vmovapd 64[RDI], YMM8; 0xC5, 0xFC, 0x28, 0x00, // vmovaps YMM0, [RAX]; 0xC5, 0x7C, 0x28, 0x00, // vmovaps YMM8, [RAX]; 0xC5, 0x7C, 0x28, 0x47, 0x40, // vmovaps YMM8, 64[RDI]; 0xC5, 0xFC, 0x29, 0x00, // vmovaps [RAX], YMM0; 0xC5, 0x7C, 0x29, 0x00, // vmovaps [RAX], YMM8; 0xC5, 0x7C, 0x29, 0x47, 0x40, // vmovaps 64[RDI], YMM8; 0xC5, 0xFD, 0x10, 0x00, // vmovupd YMM0, [RAX]; 0xC5, 0x7D, 0x10, 0x00, // vmovupd YMM8, [RAX]; 0xC5, 0x7D, 0x10, 0x47, 0x40, // vmovupd YMM8, 64[RDI]; 0xC5, 0xFD, 0x11, 0x00, // vmovupd [RAX], YMM0; 0xC5, 0x7D, 0x11, 0x00, // vmovupd [RAX], YMM8; 0xC5, 0x7D, 0x11, 0x47, 0x40, // vmovupd 64[RDI], YMM8; 0xC5, 0xFC, 0x10, 0x00, // vmovups YMM0, [RAX]; 0xC5, 0x7C, 0x10, 0x00, // vmovups YMM8, [RAX]; 0xC5, 0x7C, 0x10, 0x47, 0x40, // vmovups YMM8, 64[RDI]; 0xC5, 0xFC, 0x11, 0x00, // vmovups [RAX], YMM0; 0xC5, 0x7C, 0x11, 0x00, // vmovups [RAX], YMM8; 0xC5, 0x7C, 0x11, 0x47, 0x40, // vmovups 64[RDI], YMM8; 0xC5, 0xF9, 0x6E, 0xC0, // vmovd XMM0, EAX; 0xC5, 0xF9, 0x6E, 0x00, // vmovd XMM0, [RAX]; 0xC5, 0xF9, 0x7E, 0xC0, // vmovd EAX, XMM0; 0xC5, 0xF9, 0x7E, 0x00, // vmovd [RAX], XMM0; 0xC4, 0xE1, 0xF9, 0x6E, 0xC0, // vmovq XMM0, RAX; 0xC4, 0xE1, 0xF9, 0x6E, 0x00, // vmovq XMM0, [RAX]; 0xC4, 0xE1, 0xF9, 0x7E, 0xC0, // vmovq RAX, XMM0; 0xC4, 0xE1, 0xF9, 0x7E, 0x00, // vmovq [RAX], XMM0; 0xC5, 0xF9, 0x6F, 0xC0, // vmovdqa XMM0, XMM0; 0xC5, 0xF9, 0x6F, 0x00, // vmovdqa XMM0, [RAX]; 0xC5, 0xFD, 0x6F, 0xC0, // vmovdqa YMM0, YMM0; 0xC5, 0xFD, 0x6F, 0x00, // vmovdqa YMM0, [RAX]; 0xC5, 0xF9, 0x6F, 0xC0, // vmovdqa XMM0, XMM0; 0xC5, 0xF9, 0x7F, 0x00, // vmovdqa [RAX], XMM0; 0xC5, 0xFD, 0x6F, 0xC0, // vmovdqa YMM0, YMM0; 0xC5, 0xFD, 0x7F, 0x00, // vmovdqa [RAX],YMM0; 0xC5, 0xFA, 0x6F, 0xC0, // vmovdqu XMM0, XMM0; 0xC5, 0xFA, 0x6F, 0x00, // vmovdqu XMM0, [RAX]; 0xC5, 0xFE, 0x6F, 0xC0, // vmovdqu YMM0, YMM0; 0xC5, 0xFE, 0x6F, 0x00, // vmovdqu YMM0, [RAX]; 0xC5, 0xFA, 0x6F, 0xC0, // vmovdqu XMM0, XMM0; 0xC5, 0xFA, 0x7F, 0x00, // vmovdqu [RAX], XMM0; 0xC5, 0xFE, 0x6F, 0xC0, // vmovdqu YMM0, YMM0; 0xC5, 0xFE, 0x7F, 0x00, // vmovdqu [RAX],YMM0; 0xC5, 0xF8, 0x12, 0xC0, // vmovlhps XMM0, XMM0, XMM0; 0xC5, 0xF8, 0x16, 0xC0, // vmovhlps XMM0, XMM0, XMM0; 0xC5, 0xF9, 0x16, 0x00, // vmovhpd XMM0, XMM0, [RAX]; 0xC5, 0xF9, 0x17, 0x00, // vmovhpd [RAX], XMM0; 0xC5, 0xF8, 0x16, 0x00, // vmovhps XMM0, XMM0, [RAX]; 0xC5, 0xF8, 0x17, 0x00, // vmovhps [RAX], XMM0; 0xC5, 0xF9, 0x12, 0x00, // vmovlpd XMM0, XMM0, [RAX]; 0xC5, 0xF9, 0x13, 0x00, // vmovlpd [RAX], XMM0; 0xC5, 0xF8, 0x12, 0x00, // vmovlps XMM0, XMM0, [RAX]; 0xC5, 0xF8, 0x13, 0x00, // vmovlps [RAX], XMM0; 0xC5, 0xF9, 0xE7, 0x00, // vmovntdq [RAX], XMM0; 0xC5, 0x7D, 0xE7, 0x00, // vmovntdq [RAX], YMM8; 0xC5, 0xF9, 0x2B, 0x00, // vmovntpd [RAX], XMM0; 0xC5, 0x7D, 0x2B, 0x00, // vmovntpd [RAX], YMM8; 0xC5, 0xF8, 0x2B, 0x00, // vmovntps [RAX], XMM0; 0xC5, 0x7C, 0x2B, 0x00, // vmovntps [RAX], YMM8; 0xC4, 0xE2, 0x79, 0x2A, 0x00, // vmovntdqa XMM0, [RAX]; 0xC5, 0xFB, 0x10, 0xC0, // vmovsd XMM0, XMM0, XMM0; 0xC4, 0x41, 0x3B, 0x10, 0xC0, // vmovsd XMM8, XMM8, XMM8; 0xC5, 0xFB, 0x11, 0x00, // vmovsd [RAX], XMM0; 0xC4, 0x41, 0x7B, 0x11, 0x00, // vmovsd [R8], XMM8; 0xC5, 0xFA, 0x10, 0xC0, // vmovss XMM0, XMM0, XMM0; 0xC4, 0x41, 0x3A, 0x10, 0xC0, // vmovss XMM8, XMM8, XMM8; 0xC5, 0xFA, 0x11, 0x00, // vmovss [RAX], XMM0; 0xC4, 0x41, 0x7A, 0x11, 0x00, // vmovss [R8], XMM8; 0xC5, 0x7A, 0x16, 0xC1, // vmovshdup XMM8, XMM1; 0xC4, 0xC1, 0x7E, 0x16, 0xC0, // vmovshdup YMM0, YMM8; 0xC5, 0xFE, 0x16, 0x00, // vmovshdup YMM0, [RAX]; 0xC5, 0x7A, 0x12, 0xC1, // vmovsldup XMM8, XMM1; 0xC4, 0xC1, 0x7E, 0x12, 0xC0, // vmovsldup YMM0, YMM8; 0xC5, 0xFE, 0x12, 0x00, // vmovsldup YMM0, [RAX]; 0xC5, 0xF1, 0x67, 0xC2, // vpackuswb XMM0, XMM1, XMM2; 0xC5, 0xB9, 0x67, 0x00, // vpackuswb XMM0, XMM8, [RAX]; 0xC4, 0xE2, 0x71, 0x2B, 0xC2, // vpackusdw XMM0, XMM1, XMM2; 0xC4, 0xE2, 0x39, 0x2B, 0x00, // vpackusdw XMM0, XMM8, [RAX]; 0xC5, 0xF1, 0x63, 0xC2, // vpacksswb XMM0, XMM1, XMM2; 0xC5, 0xB9, 0x63, 0x00, // vpacksswb XMM0, XMM8, [RAX]; 0xC5, 0xF1, 0x6B, 0xC2, // vpackssdw XMM0, XMM1, XMM2; 0xC5, 0xB9, 0x6B, 0x00, // vpackssdw XMM0, XMM8, [RAX]; 0xC4, 0xE3, 0x71, 0x0F, 0xC2, 0xFF, // vpalignr XMM0, XMM1, XMM2, 0xFF; 0xC4, 0x63, 0x39, 0x0F, 0x08, 0x10, // vpalignr XMM9, XMM8, [RAX], 0x10; 0xC4, 0xE3, 0x79, 0x14, 0xC0, 0x00, // vpextrb EAX, XMM0, 0x0; 0xC4, 0x43, 0x79, 0x14, 0xCA, 0x0F, // vpextrb R10, XMM9, 0xF; 0xC4, 0x43, 0x79, 0x14, 0x0A, 0x0F, // vpextrb [R10], XMM9, 0xF; 0xC4, 0xE3, 0x79, 0x16, 0xC0, 0x00, // vpextrd EAX, XMM0, 0x0; 0xC4, 0x43, 0x79, 0x16, 0xC8, 0x0F, // vpextrd R8D, XMM9, 0xF; 0xC4, 0x43, 0x79, 0x16, 0x0A, 0x0F, // vpextrd [R10], XMM9, 0xF; 0xC4, 0xE3, 0xF9, 0x16, 0xC0, 0x00, // vpextrq RAX, XMM0, 0x0; 0xC4, 0x43, 0xF9, 0x16, 0xCA, 0x0F, // vpextrq R10, XMM9, 0xF; 0xC4, 0x43, 0xF9, 0x16, 0x0A, 0x0F, // vpextrq [R10], XMM9, 0xF; 0xC5, 0xF9, 0xC5, 0xC0, 0x00, // vpextrw EAX, XMM0, 0x0; 0xC4, 0x41, 0x79, 0xC5, 0xD1, 0x0F, // vpextrw R10, XMM9, 0xF; 0xC4, 0x43, 0x79, 0x15, 0x0A, 0x0F, // vpextrw [R10], XMM9, 0xF; 0xC4, 0xE2, 0x79, 0x20, 0xC0, // vpmovsxbw XMM0, XMM0; 0xC4, 0x42, 0x79, 0x20, 0x00, // vpmovsxbw XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x21, 0xC0, // vpmovsxbd XMM0, XMM0; 0xC4, 0x42, 0x79, 0x21, 0x00, // vpmovsxbd XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x22, 0xC0, // vpmovsxbq XMM0, XMM0; 0xC4, 0x42, 0x79, 0x22, 0x00, // vpmovsxbq XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x23, 0xC0, // vpmovsxwd XMM0, XMM0; 0xC4, 0x42, 0x79, 0x23, 0x00, // vpmovsxwd XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x24, 0xC0, // vpmovsxwq XMM0, XMM0; 0xC4, 0x42, 0x79, 0x24, 0x00, // vpmovsxwq XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x25, 0xC0, // vpmovsxdq XMM0, XMM0; 0xC4, 0x42, 0x79, 0x25, 0x00, // vpmovsxdq XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x30, 0xC0, // vpmovzxbw XMM0, XMM0; 0xC4, 0x42, 0x79, 0x30, 0x00, // vpmovzxbw XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x31, 0xC0, // vpmovzxbd XMM0, XMM0; 0xC4, 0x42, 0x79, 0x31, 0x00, // vpmovzxbd XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x32, 0xC0, // vpmovzxbq XMM0, XMM0; 0xC4, 0x42, 0x79, 0x32, 0x00, // vpmovzxbq XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x33, 0xC0, // vpmovzxwd XMM0, XMM0; 0xC4, 0x42, 0x79, 0x33, 0x00, // vpmovzxwd XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x34, 0xC0, // vpmovzxwq XMM0, XMM0; 0xC4, 0x42, 0x79, 0x34, 0x00, // vpmovzxwq XMM8, [R8]; 0xC4, 0xE2, 0x79, 0x35, 0xC0, // vpmovzxdq XMM0, XMM0; 0xC4, 0x42, 0x79, 0x35, 0x00, // vpmovzxdq XMM8, [R8]; 0xC5, 0xF9, 0x54, 0xC0, // vandpd XMM0, XMM0, XMM0; 0xC4, 0x41, 0x39, 0x54, 0x08, // vandpd XMM9, XMM8, [R8]; 0xC5, 0xF8, 0x54, 0xC0, // vandps XMM0, XMM0, XMM0; 0xC4, 0x41, 0x38, 0x54, 0x08, // vandps XMM9, XMM8, [R8]; 0xC5, 0xF9, 0x55, 0xC0, // vandnpd XMM0, XMM0, XMM0; 0xC4, 0x41, 0x39, 0x55, 0x08, // vandnpd XMM9, XMM8, [R8]; 0xC5, 0xF8, 0x55, 0xC0, // vandnps XMM0, XMM0, XMM0; 0xC4, 0x41, 0x38, 0x55, 0x08, // vandnps XMM9, XMM8, [R8]; 0xC5, 0xF9, 0x56, 0xC0, // vorpd XMM0, XMM0, XMM0; 0xC4, 0x41, 0x39, 0x56, 0x08, // vorpd XMM9, XMM8, [R8]; 0xC5, 0xF8, 0x56, 0xC0, // vorps XMM0, XMM0, XMM0; 0xC4, 0x41, 0x38, 0x56, 0x08, // vorps XMM9, XMM8, [R8]; 0xC5, 0xF9, 0xDB, 0xC0, // vpand XMM0, XMM0, XMM0; 0xC4, 0x41, 0x39, 0xDB, 0x08, // vpand XMM9, XMM8, [R8]; 0xC5, 0xF9, 0xDF, 0xC0, // vpandn XMM0, XMM0, XMM0; 0xC4, 0x41, 0x39, 0xDF, 0x08, // vpandn XMM9, XMM8, [R8]; 0xC5, 0xF9, 0xEB, 0xC0, // vpor XMM0, XMM0, XMM0; 0xC4, 0x41, 0x39, 0xEB, 0x0A, // vpor XMM9, XMM8, [R10]; 0xC5, 0xF9, 0xEF, 0xC0, // vpxor XMM0, XMM0, XMM0; 0xC4, 0x41, 0x39, 0xEF, 0x0A, // vpxor XMM9, XMM8, [R10]; 0xC4, 0xE2, 0x79, 0x17, 0xC0, // vptest XMM0, XMM0; 0xC4, 0x62, 0x79, 0x17, 0x00, // vptest XMM8, [RAX]; 0xC4, 0x42, 0x7D, 0x17, 0xC0, // vptest YMM8, YMM8; 0xC4, 0xC2, 0x7D, 0x17, 0x00, // vptest YMM0, [R8]; 0xC5, 0xF9, 0x2E, 0xC0, // vucomisd XMM0, XMM0; 0xC5, 0x79, 0x2E, 0x00, // vucomisd XMM8, [RAX] 0xC5, 0xF8, 0x2E, 0xC0, // vucomiss YMM8, YMM8; 0xC5, 0x78, 0x2E, 0x00, // vucomiss YMM0, [R8]; 0xC5, 0xB9, 0x57, 0xC0, // vxorpd XMM0, XMM8, XMM0; 0xC5, 0x79, 0x57, 0x00, // vxorpd XMM8, XMM0, [RAX]; 0xC5, 0xBD, 0x57, 0xC0, // vxorpd YMM0, YMM8, YMM0; 0xC5, 0x7D, 0x57, 0x00, // vxorpd YMM8, YMM0, [RAX]; 0xC5, 0xB8, 0x57, 0xC0, // vxorps XMM0, XMM8, XMM0; 0xC5, 0x78, 0x57, 0x00, // vxorps XMM8, XMM0, [RAX]; 0xC5, 0xBC, 0x57, 0xC0, // vxorps YMM0, YMM8, YMM0; 0xC5, 0x7C, 0x57, 0x00, // vxorps YMM8, YMM0, [RAX]; 0xC4, 0xE3, 0x71, 0x0D, 0xC2, 0x00, // vblendpd XMM0, XMM1, XMM2, 0x00; 0xC4, 0x63, 0x39, 0x0D, 0x08, 0xFF, // vblendpd XMM9, XMM8, [RAX], 0xFF; 0xC4, 0xE3, 0x75, 0x0D, 0xC2, 0x00, // vblendpd YMM0, YMM1, YMM2, 0x00; 0xC4, 0x63, 0x3D, 0x0D, 0x08, 0xFF, // vblendpd YMM9, YMM8, [RAX], 0xFF; 0xC4, 0xE3, 0x71, 0x0C, 0xC2, 0x00, // vblendps XMM0, XMM1, XMM2, 0x00; 0xC4, 0x63, 0x39, 0x0C, 0x08, 0xFF, // vblendps XMM9, XMM8, [RAX], 0xFF; 0xC4, 0xE3, 0x75, 0x0C, 0xC2, 0x00, // vblendps YMM0, YMM1, YMM2, 0x00; 0xC4, 0x63, 0x3D, 0x0C, 0x08, 0xFF, // vblendps YMM9, YMM8, [RAX], 0xFF; 0xC4, 0xE3, 0x71, 0x4B, 0xC2, 0x00, // vblendvpd XMM0, XMM1, XMM2, 0x00; 0xC4, 0x63, 0x39, 0x4B, 0x08, 0xff, // vblendvpd XMM9, XMM8, [RAX], 0xFF; 0xC4, 0xE3, 0x75, 0x4B, 0xC2, 0x00, // vblendvpd YMM0, YMM1, YMM2, 0x00; 0xC4, 0x63, 0x3D, 0x4B, 0x08, 0xff, // vblendvpd YMM9, YMM8, [RAX], 0xFF; 0xC4, 0xE3, 0x71, 0x4A, 0xC2, 0x00, // vblendvps XMM0, XMM1, XMM2, 0x00; 0xC4, 0x63, 0x39, 0x4A, 0x08, 0xff, // vblendvps XMM9, XMM8, [RAX], 0xFF; 0xC4, 0xE3, 0x75, 0x4A, 0xC2, 0x00, // vblendvps YMM0, YMM1, YMM2, 0x00; 0xC4, 0x63, 0x3D, 0x4A, 0x08, 0xff, // vblendvps YMM9, YMM8, [RAX], 0xFF; 0xC5, 0x7B, 0x12, 0xC0, // vmovddup XMM8, XMM0; 0xC5, 0xFB, 0x12, 0x00, // vmovddup XMM0, [RAX]; 0xC4, 0xC1, 0x7F, 0x12, 0xC0, // vmovddup YMM0, YMM8; 0xC4, 0xC1, 0x7F, 0x12, 0x02, // vmovddup YMM0, [R10]; 0xC4, 0xE3, 0x39, 0x4C, 0xC0, 0x00, // vpblendvb XMM0, XMM8, XMM0, 0x00; 0xC4, 0x63, 0x79, 0x4C, 0x00, 0x00, // vpblendvb XMM8, XMM0, [RAX], 0x00; 0xC4, 0x43, 0x79, 0x4C, 0x02, 0x00, // vpblendvb XMM8, XMM0, [R10], 0x00; 0xC4, 0xE3, 0x39, 0x0E, 0xC0, 0x00, // vpblendw XMM0, XMM8, XMM0, 0x00; 0xC4, 0x63, 0x79, 0x0E, 0x00, 0x00, // vpblendw XMM8, XMM0, [RAX], 0x00; 0xC4, 0x43, 0x79, 0x0E, 0x02, 0x00, // vpblendw XMM8, XMM0, [R10], 0x00; 0xC4, 0xE2, 0x71, 0x0D, 0xC2, // vpermilpd XMM0, XMM1, XMM2; 0xC4, 0xE2, 0x71, 0x0D, 0x00, // vpermilpd XMM0, XMM1, [RAX]; 0xC4, 0xE3, 0x79, 0x05, 0xC1, 0x00, // vpermilpd XMM0, XMM1, 0x00; 0xC4, 0xE3, 0x79, 0x05, 0x00, 0x00, // vpermilpd XMM0, [RAX], 0x00; 0xC4, 0xE2, 0x71, 0x0C, 0xC2, // vpermilps XMM0, XMM1, XMM2; 0xC4, 0xE2, 0x71, 0x0C, 0x00, // vpermilps XMM0, XMM1, [RAX]; 0xC4, 0xE3, 0x79, 0x04, 0xC1, 0x00, // vpermilps XMM0, XMM1, 0x00; 0xC4, 0xE3, 0x79, 0x04, 0x00, 0x00, // vpermilps XMM0, [RAX], 0x00; 0xC4, 0xE3, 0x75, 0x06, 0xC2, 0x00, // vperm2f128 YMM0, YMM1, YMM2, 0x00; 0xC4, 0xE3, 0x75, 0x06, 0x00, 0x00, // vperm2f128 YMM0, YMM1, [RAX], 0x00; 0xC4, 0x43, 0x35, 0x06, 0x02, 0x00, // vperm2f128 YMM8, YMM9, [R10], 0x00; 0xC4, 0xE2, 0x79, 0x00, 0xC0, // vpshufb XMM0, XMM0, XMM0; 0xC4, 0x42, 0x39, 0x00, 0x08, // vpshufb XMM9, XMM8, [R8]; 0xC5, 0xF9, 0x70, 0xC0, 0x00, // vpshufd XMM0, XMM0, 0x0; 0xC4, 0x41, 0x79, 0x70, 0x00, 0x00, // vpshufd XMM8, [R8], 0x0; 0xC5, 0xFA, 0x70, 0xC0, 0x00, // vpshufhw XMM0, XMM0, 0x0; 0xC4, 0x41, 0x7A, 0x70, 0x00, 0x00, // vpshufhw XMM8, [R8], 0x0; 0xC5, 0xFB, 0x70, 0xC0, 0x00, // vpshuflw XMM0, XMM0, 0x0; 0xC4, 0x41, 0x7B, 0x70, 0x00, 0x00, // vpshuflw XMM8, [R8], 0x0; 0xC5, 0xF1, 0x68, 0xC2, // vpunpckhbw XMM0, XMM1, XMM2; 0xC4, 0x41, 0x39, 0x68, 0x00, // vpunpckhbw XMM8, XMM8, [R8]; 0xC5, 0xF1, 0x69, 0xC2, // vpunpckhwd XMM0, XMM1, XMM2; 0xC4, 0x41, 0x39, 0x69, 0x00, // vpunpckhwd XMM8, XMM8, [R8]; 0xC5, 0xF1, 0x6A, 0xC2, // vpunpckhdq XMM0, XMM1, XMM2; 0xC4, 0x41, 0x39, 0x6A, 0x00, // vpunpckhdq XMM8, XMM8, [R8]; 0xC5, 0xF1, 0x6D, 0xC2, // vpunpckhqdq XMM0, XMM1, XMM2; 0xC4, 0x41, 0x39, 0x6D, 0x00, // vpunpckhqdq XMM8, XMM8, [R8]; 0xC5, 0xF1, 0x60, 0xC2, // vpunpcklbw XMM0, XMM1, XMM2; 0xC4, 0x41, 0x39, 0x60, 0x00, // vpunpcklbw XMM8, XMM8, [R8]; 0xC5, 0xF1, 0x61, 0xC2, // vpunpcklwd XMM0, XMM1, XMM2; 0xC4, 0x41, 0x39, 0x61, 0x00, // vpunpcklwd XMM8, XMM8, [R8]; 0xC5, 0xF1, 0x62, 0xC2, // vpunpckldq XMM0, XMM1, XMM2; 0xC4, 0x41, 0x39, 0x62, 0x00, // vpunpckldq XMM8, XMM8, [R8]; 0xC5, 0xF1, 0x6C, 0xC2, // vpunpcklqdq XMM0, XMM1, XMM2; 0xC4, 0x41, 0x39, 0x6C, 0x00, // vpunpcklqdq XMM8, XMM8, [R8]; 0xC5, 0xF9, 0xC6, 0xC0, 0x00, // vshufpd XMM0, XMM0, XMM0, 0x00; 0xC4, 0xC1, 0x39, 0xC6, 0x00, 0x00, // vshufpd XMM0, XMM8, [R8], 0x00; 0xC4, 0x41, 0x7D, 0xC6, 0xC0, 0x00, // vshufpd YMM8, YMM0, YMM8, 0x00; 0xC5, 0x7D, 0xC6, 0x00, 0x00, // vshufpd YMM8, YMM0, [RAX], 0x00; 0xC5, 0xF8, 0xC6, 0xC0, 0x00, // vshufps XMM0, XMM0, XMM0, 0x00; 0xC4, 0xC1, 0x38, 0xC6, 0x00, 0x00, // vshufps XMM0, XMM8, [R8], 0x00; 0xC4, 0x41, 0x7C, 0xC6, 0xC0, 0x00, // vshufps YMM8, YMM0, YMM8, 0x00; 0xC5, 0x7C, 0xC6, 0x00, 0x00, // vshufps YMM8, YMM0, [RAX], 0x00; 0xC5, 0xF9, 0x15, 0xC0, // vunpckhpd XMM0, XMM0, XMM0; 0xC5, 0x39, 0x15, 0x00, // vunpckhpd XMM8, XMM8, [RAX]; 0xC4, 0x41, 0x7D, 0x15, 0x00, // vunpckhpd YMM8, YMM0, [R8]; 0xC4, 0xC1, 0x3D, 0x15, 0x00, // vunpckhpd YMM0, YMM8, [R8]; 0xC5, 0xF8, 0x15, 0xC0, // vunpckhps XMM0, XMM0, XMM0; 0xC5, 0x38, 0x15, 0x00, // vunpckhps XMM8, XMM8, [RAX]; 0xC4, 0x41, 0x7C, 0x15, 0x00, // vunpckhps YMM8, YMM0, [R8]; 0xC4, 0xC1, 0x3C, 0x15, 0x00, // vunpckhps YMM0, YMM8, [R8]; 0xC5, 0xF9, 0x14, 0xC0, // vunpcklpd XMM0, XMM0, XMM0; 0xC5, 0x39, 0x14, 0x00, // vunpcklpd XMM8, XMM8, [RAX]; 0xC4, 0x41, 0x7D, 0x14, 0x00, // vunpcklpd YMM8, YMM0, [R8]; 0xC4, 0xC1, 0x3D, 0x14, 0x00, // vunpcklpd YMM0, YMM8, [R8]; 0xC5, 0xF8, 0x14, 0xC0, // vunpcklps XMM0, XMM0, XMM0; 0xC5, 0x38, 0x14, 0x00, // vunpcklps XMM8, XMM8, [RAX]; 0xC4, 0x41, 0x7C, 0x14, 0x00, // vunpcklps YMM8, YMM0, [R8]; 0xC4, 0xC1, 0x3C, 0x14, 0x00, // vunpcklps YMM0, YMM8, [R8]; /* AES */ 0x66, 0x0F, 0x38, 0xDC, 0xC0, // aesenc XMM0, XMM0; 0x66, 0x0F, 0x38, 0xDC, 0x00, // aesenc XMM0, [RAX]; 0xC4, 0xE2, 0x79, 0xDC, 0xC0, // vaesenc XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0xDC, 0x00, // vaesenc XMM0, XMM0, [RAX]; 0x66, 0x0F, 0x38, 0xDD, 0xC0, // aesenclast XMM0, XMM0; 0x66, 0x0F, 0x38, 0xDD, 0x00, // aesenclast XMM0, [RAX]; 0xC4, 0xE2, 0x79, 0xDD, 0xC0, // vaesenclast XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0xDD, 0x00, // vaesenclast XMM0, XMM0, [RAX]; 0x66, 0x0F, 0x38, 0xDE, 0xC0, // aesdec XMM0, XMM0; 0x66, 0x0F, 0x38, 0xDE, 0x00, // aesdec XMM0, [RAX]; 0xC4, 0xE2, 0x79, 0xDE, 0xC0, // vaesdec XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0xDE, 0x00, // vaesdec XMM0, XMM0, [RAX]; 0x66, 0x0F, 0x38, 0xDF, 0xC0, // aesdeclast XMM0, XMM0; 0x66, 0x0F, 0x38, 0xDF, 0x00, // aesdeclast XMM0, [RAX]; 0xC4, 0xE2, 0x79, 0xDF, 0xC0, // vaesdeclast XMM0, XMM0, XMM0; 0xC4, 0xE2, 0x79, 0xDF, 0x00, // vaesdeclast XMM0, XMM0, [RAX]; 0x66, 0x0F, 0x38, 0xDB, 0xC0, // aesimc XMM0, XMM0; 0x66, 0x0F, 0x38, 0xDB, 0x00, // aesimc XMM0, [RAX]; 0xC4, 0xE2, 0x79, 0xDB, 0xC0, // vaesimc XMM0, XMM0; 0xC4, 0xE2, 0x79, 0xDB, 0x00, // vaesimc XMM0, [RAX]; 0x66, 0x0F, 0x3A, 0xDF, 0xC0, 0x00, // aeskeygenassist XMM0, XMM0, 0x0; 0x66, 0x0F, 0x3A, 0xDF, 0x00, 0x00, // aeskeygenassist XMM0, [RAX], 0x0; 0xC4, 0xE3, 0x79, 0xDF, 0xC0, 0x00, // vaeskeygenassist XMM0, XMM0, 0x0; 0xC4, 0xE3, 0x79, 0xDF, 0x00, 0x00, // vaeskeygenassist XMM0, [RAX], 0x0; /* FSGSBASE */ 0xf3, 0x48, 0x0f, 0xae, 0xc0, // rdfsbase RAX; 0xf3, 0x49, 0x0f, 0xae, 0xc7, // rdfsbase R15; 0xf3, 0x48, 0x0f, 0xae, 0xc8, // rdgsbase RAX; 0xf3, 0x49, 0x0f, 0xae, 0xcf, // rdgsbase R15; 0xf3, 0x48, 0x0f, 0xae, 0xd0, // wrfsbase RAX; 0xf3, 0x49, 0x0f, 0xae, 0xd7, // wrfsbase R15; 0xf3, 0x48, 0x0f, 0xae, 0xd8, // wrgsbase RAX; 0xf3, 0x49, 0x0f, 0xae, 0xdf, // wrgsbase R15; /* RDRAND */ 0x66, 0x0f, 0xc7, 0xf0, // rdrand AX; 0x0f, 0xc7, 0xf0, // rdrand EAX; 0x48, 0x0f, 0xc7, 0xf0, // rdrand RAX; 0x66, 0x41, 0x0f, 0xc7, 0xf7, // rdrand R15W; 0x41, 0x0f, 0xc7, 0xf7, // rdrand R15D; 0x49, 0x0f, 0xc7, 0xf7, // rdrand R15; /* FP16C */ 0xc4, 0xe2, 0x79, 0x13, 0xc0, // vcvtph2ps XMM0, XMM0; 0xc4, 0xe2, 0x79, 0x13, 0x00, // vcvtph2ps XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0x13, 0xc0, // vcvtph2ps YMM0, XMM0; 0xc4, 0x42, 0x7d, 0x13, 0x00, // vcvtph2ps YMM8, [R8]; 0xc4, 0xe3, 0x79, 0x13, 0xc0, 0x00, // vcvtps2ph XMM0, XMM0, 0x0; 0xc4, 0xe3, 0x79, 0x13, 0x00, 0x00, // vcvtps2ph [RAX], XMM0, 0x0; 0xc4, 0xe3, 0x7d, 0x13, 0xc0, 0x00, // vcvtps2ph XMM0, YMM0, 0x0; 0xc4, 0x43, 0x7d, 0x13, 0x00, 0x00, // vcvtps2ph [R8], YMM8, 0x0; /* FMA */ 0xc4, 0xe2, 0xf9, 0x98, 0xc0, // vfmadd132pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0x98, 0x00, // vfmadd132pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0x98, 0xc0, // vfmadd132pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0x98, 0x00, // vfmadd132pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0x98, 0xc0, // vfmadd132ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0x98, 0x00, // vfmadd132ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0x98, 0xc0, // vfmadd132ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0x98, 0x00, // vfmadd132ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0x99, 0xc0, // vfmadd132sd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0x99, 0x00, // vfmadd132sd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x79, 0x99, 0xc0, // vfmadd132ss XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0x99, 0x00, // vfmadd132ss XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xf9, 0xA8, 0xc0, // vfmadd213pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xA8, 0x00, // vfmadd213pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0xA8, 0xc0, // vfmadd213pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0xA8, 0x00, // vfmadd213pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0xA8, 0xc0, // vfmadd213ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xA8, 0x00, // vfmadd213ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0xA8, 0xc0, // vfmadd213ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0xA8, 0x00, // vfmadd213ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0xA9, 0xc0, // vfmadd213sd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xA9, 0x00, // vfmadd213sd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x79, 0xA9, 0xc0, // vfmadd213ss XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xA9, 0x00, // vfmadd213ss XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xf9, 0xB8, 0xc0, // vfmadd231pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xB8, 0x00, // vfmadd231pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0xB8, 0xc0, // vfmadd231pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0xB8, 0x00, // vfmadd231pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0xB8, 0xc0, // vfmadd231ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xB8, 0x00, // vfmadd231ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0xB8, 0xc0, // vfmadd231ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0xB8, 0x00, // vfmadd231ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0xB9, 0xc0, // vfmadd231sd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xB9, 0x00, // vfmadd231sd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x79, 0xB9, 0xc0, // vfmadd231ss XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xB9, 0x00, // vfmadd231ss XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xf9, 0x96, 0xc0, // vfmaddsub132pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0x96, 0x00, // vfmaddsub132pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0x96, 0xc0, // vfmaddsub132pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0x96, 0x00, // vfmaddsub132pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0x96, 0xc0, // vfmaddsub132ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0x96, 0x00, // vfmaddsub132ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0x96, 0xc0, // vfmaddsub132ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0x96, 0x00, // vfmaddsub132ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0xA6, 0xc0, // vfmaddsub213pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xA6, 0x00, // vfmaddsub213pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0xA6, 0xc0, // vfmaddsub213pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0xA6, 0x00, // vfmaddsub213pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0xA6, 0xc0, // vfmaddsub213ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xA6, 0x00, // vfmaddsub213ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0xA6, 0xc0, // vfmaddsub213ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0xA6, 0x00, // vfmaddsub213ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0xB6, 0xc0, // vfmaddsub231pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xB6, 0x00, // vfmaddsub231pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0xB6, 0xc0, // vfmaddsub231pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0xB6, 0x00, // vfmaddsub231pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0xB6, 0xc0, // vfmaddsub231ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xB6, 0x00, // vfmaddsub231ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0xB6, 0xc0, // vfmaddsub231ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0xB6, 0x00, // vfmaddsub231ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0x97, 0xc0, // vfmsubadd132pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0x97, 0x00, // vfmsubadd132pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0x97, 0xc0, // vfmsubadd132pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0x97, 0x00, // vfmsubadd132pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0x97, 0xc0, // vfmsubadd132ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0x97, 0x00, // vfmsubadd132ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0x97, 0xc0, // vfmsubadd132ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0x97, 0x00, // vfmsubadd132ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0xA7, 0xc0, // vfmsubadd213pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xA7, 0x00, // vfmsubadd213pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0xA7, 0xc0, // vfmsubadd213pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0xA7, 0x00, // vfmsubadd213pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0xA7, 0xc0, // vfmsubadd213ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xA7, 0x00, // vfmsubadd213ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0xA7, 0xc0, // vfmsubadd213ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0xA7, 0x00, // vfmsubadd213ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0xB7, 0xc0, // vfmsubadd231pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xB7, 0x00, // vfmsubadd231pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0xB7, 0xc0, // vfmsubadd231pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0xB7, 0x00, // vfmsubadd231pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0xB7, 0xc0, // vfmsubadd231ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xB7, 0x00, // vfmsubadd231ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0xB7, 0xc0, // vfmsubadd231ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0xB7, 0x00, // vfmsubadd231ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0x9A, 0xc0, // vfmsub132pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0x9A, 0x00, // vfmsub132pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0x9A, 0xc0, // vfmsub132pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0x9A, 0x00, // vfmsub132pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0x9A, 0xc0, // vfmsub132ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0x9A, 0x00, // vfmsub132ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0x9A, 0xc0, // vfmsub132ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0x9A, 0x00, // vfmsub132ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0x9B, 0xc0, // vfmsub132sd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0x9B, 0x00, // vfmsub132sd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x79, 0x9B, 0xc0, // vfmsub132ss XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0x9B, 0x00, // vfmsub132ss XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xf9, 0xAA, 0xc0, // vfmsub213pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xAA, 0x00, // vfmsub213pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0xAA, 0xc0, // vfmsub213pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0xAA, 0x00, // vfmsub213pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0xAA, 0xc0, // vfmsub213ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xAA, 0x00, // vfmsub213ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0xAA, 0xc0, // vfmsub213ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0xAA, 0x00, // vfmsub213ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0xAB, 0xc0, // vfmsub213sd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xAB, 0x00, // vfmsub213sd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x79, 0xAB, 0xc0, // vfmsub213ss XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xAB, 0x00, // vfmsub213ss XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xf9, 0xBA, 0xc0, // vfmsub231pd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xBA, 0x00, // vfmsub231pd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0xfd, 0xBA, 0xc0, // vfmsub231pd YMM0, YMM0, YMM0; 0xc4, 0x42, 0xbd, 0xBA, 0x00, // vfmsub231pd YMM8, YMM8, [R8]; 0xc4, 0xe2, 0x79, 0xBA, 0xc0, // vfmsub231ps XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xBA, 0x00, // vfmsub231ps XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x7d, 0xBA, 0xc0, // vfmsub231ps YMM0, YMM0, YMM0; 0xc4, 0x42, 0x3d, 0xBA, 0x00, // vfmsub231ps YMM8, YMM8, [R8]; 0xc4, 0xe2, 0xf9, 0xBB, 0xc0, // vfmsub231sd XMM0, XMM0, XMM0; 0xc4, 0xe2, 0xf9, 0xBB, 0x00, // vfmsub231sd XMM0, XMM0, [RAX]; 0xc4, 0xe2, 0x79, 0xBB, 0xc0, // vfmsub231ss XMM0, XMM0, XMM0; 0xc4, 0xe2, 0x79, 0xBB, 0x00, // vfmsub231ss XMM0, XMM0, [RAX]; // 0x58, // pop RAX ]; asm { call L1; xgetbv; xsetbv; xrstor [RAX]; xrstor64 [RAX]; xsave [RAX]; xsave64 [RAX]; xsaveopt [RAX]; xsaveopt64 [RAX]; vldmxcsr [RAX]; vstmxcsr [RAX]; vaddss XMM0, XMM1, XMM2; vaddsd XMM0, XMM15, [RAX]; vaddps XMM12, XMM0, XMM0; vaddpd XMM8, XMM8, XMM8; vsubss XMM0, XMM1, XMM2; vsubsd XMM0, XMM15, [RAX]; vsubps XMM12, XMM0, XMM0; vsubpd XMM8, XMM8, XMM8; vaddsubps XMM0, XMM1, XMM2; vaddsubps YMM0, YMM1, YMM2; vaddsubpd YMM8, YMM1, YMM2; vaddsubpd YMM15, YMM15, 64[RAX]; vdpps YMM0, YMM0, YMM0, 0; vdppd XMM0, XMM0, XMM0, 0x88; vhaddpd YMM0, YMM8, [RDI]; vhaddps XMM0, XMM8, XMM1; vmaxpd YMM0, YMM0, YMM1; vmaxpd XMM0, XMM0, [RAX]; vmaxps YMM0, YMM0, YMM1; vmaxps XMM0, XMM0, [RAX]; vmaxsd XMM0, XMM0, [RAX]; vmaxss XMM0, XMM0, [RAX]; vminpd YMM0, YMM0, YMM1; vminpd XMM0, XMM0, [RAX]; vminps YMM0, YMM0, YMM1; vminps XMM0, XMM0, [RAX]; vminsd XMM0, XMM0, [RAX]; vminss XMM0, XMM0, [RAX]; vmovmskpd EAX, XMM0; vmovmskpd EDI, YMM0; vmovmskps EAX, YMM15; vmovmskps R8D, YMM0; vpmovmskb EAX, XMM0; vmpsadbw XMM0, XMM1, XMM2, 0x00; vmpsadbw XMM8, XMM9, XMM10, 0xFF; vpabsb XMM0, [RAX]; vpabsw XMM1, XMM15; vpabsd XMM1, [RBX]; vpaddb XMM0, XMM0, [RAX]; vpaddw XMM8, XMM8, XMM15; vpaddd XMM8, XMM8, [RBX]; vpaddq XMM0, XMM0, XMM0; vpsubb XMM0, XMM0, [RAX]; vpsubw XMM8, XMM8, XMM15; vpsubd XMM8, XMM8, [RBX]; vpsubq XMM0, XMM0, XMM0; vpaddsb XMM0, XMM0, XMM0; vpaddsw XMM0, XMM0, XMM0; vpaddusb XMM0, XMM0, XMM0; vpaddusw XMM0, XMM0, XMM0; vpsubsb XMM0, XMM0, XMM0; vpsubsw XMM0, XMM0, XMM0; vpsubusb XMM0, XMM0, XMM0; vpsubusw XMM0, XMM0, XMM0; vpavgb XMM0, XMM0, XMM0; vpavgw XMM0, XMM0, XMM0; vpclmulqdq XMM0, XMM0, 64[RAX + 4 * RCX], 0; vphaddw XMM0, XMM0, XMM0; vphaddd XMM0, XMM0, XMM0; vphsubw XMM0, XMM0, XMM0; vphsubd XMM0, XMM0, XMM0; vphaddsw XMM0, XMM0, XMM0; vphsubsw XMM0, XMM0, XMM0; vphminposuw XMM0, XMM0; vpmaddwd XMM0, XMM0, XMM0; vpmaddubsw XMM0, XMM0, XMM0; vpmaxsb XMM0, XMM0, XMM0; vpmaxsd XMM0, XMM0, XMM0; vpmaxsw XMM0, XMM0, XMM0; vpmaxub XMM0, XMM0, XMM0; vpmaxud XMM0, XMM0, XMM0; vpmaxuw XMM0, XMM0, XMM0; vpminsb XMM0, XMM0, XMM0; vpminsd XMM0, XMM0, XMM0; vpminsw XMM0, XMM0, XMM0; vpminub XMM0, XMM0, XMM0; vpminud XMM0, XMM0, XMM0; vpminuw XMM0, XMM0, XMM0; vpmulhrsw XMM0, XMM0, XMM0; vpmulhuw XMM0, XMM0, XMM0; vpmulhw XMM0, XMM0, XMM0; vpmulld XMM0, XMM0, XMM0; vpmullw XMM0, XMM0, XMM0; vpmuludq XMM0, XMM0, XMM0; vpmuldq XMM0, XMM0, XMM0; vpsadbw XMM0, XMM0, XMM0; vpsignb XMM0, XMM0, XMM0; vpsignw XMM0, XMM0, XMM0; vpsignd XMM0, XMM0, XMM0; vpslldq XMM0, XMM0, 0; vpsllw XMM0, XMM0, 0; vpsllw XMM0, XMM0, XMM0; vpslld XMM0, XMM0, 0; vpslld XMM0, XMM0, XMM0; vpsllq XMM0, XMM0, 0; vpsllq XMM0, XMM0, XMM0; vpsraw XMM0, XMM0, 0; vpsraw XMM0, XMM0, XMM0; vpsrad XMM0, XMM0, 0; vpsrad XMM0, XMM0, XMM0; vpsrldq XMM0, XMM0, 0; vpsrlw XMM0, XMM0, 0; vpsrlw XMM0, XMM0, XMM0; vpsrld XMM0, XMM0, 0; vpsrld XMM0, XMM0, XMM0; vpsrlq XMM0, XMM0, 0; vpsrlq XMM0, XMM0, XMM0; vrcpps XMM0, XMM1; vrcpps YMM0, YMM1; vrcpss XMM0, XMM0, XMM1; vroundpd XMM0, XMM0, 0; vroundpd YMM0, YMM0, 0; vroundps XMM0, XMM0, 0; vroundps YMM0, YMM0, 0; vroundsd XMM0, XMM0, XMM0, 0; vroundss XMM0, XMM0, XMM0, 0; vsqrtpd XMM0, XMM0; vsqrtpd YMM0, YMM0; vsqrtps XMM0, XMM0; vsqrtps YMM0, YMM0; vsqrtsd XMM0, XMM0, XMM0; vsqrtss XMM0, XMM0, XMM0; vzeroall; vzeroupper; vcmppd XMM0, XMM0, XMM0, 0; vcmppd YMM0, YMM0, YMM0, 0; vcmpps XMM0, XMM0, XMM0, 0; vcmpps YMM0, YMM0, YMM0, 0; vcmpsd XMM0, XMM0, XMM0, 0; vcmpss XMM0, XMM0, XMM0, 0; vcomisd XMM0, XMM0; vcomiss XMM0, XMM0; vpcmpeqb XMM0, XMM0, XMM0; vpcmpeqw XMM0, XMM0, XMM0; vpcmpeqd XMM0, XMM0, XMM0; vpcmpeqq XMM0, XMM0, XMM0; vpcmpgtb XMM0, XMM0, XMM0; vpcmpgtw XMM0, XMM0, XMM0; vpcmpgtd XMM0, XMM0, XMM0; vpcmpgtq XMM0, XMM0, XMM0; vpcmpestri XMM0, XMM0, 0; vpcmpestrm XMM0, XMM0, 0; vpcmpistri XMM0, XMM0, 0; vpcmpistrm XMM0, XMM0, 0; vcvtdq2pd XMM0, XMM0; vcvtdq2pd YMM0, XMM0; vcvtdq2pd YMM0, [RAX]; vcvtdq2ps XMM0, XMM0; vcvtdq2ps YMM0, YMM0; vcvtdq2ps YMM0, [RAX]; vcvtpd2dq XMM0, XMM0; vcvtpd2dq XMM0, YMM0; vcvtpd2dq XMM0, [RAX]; vcvtpd2ps XMM0, XMM0; vcvtpd2ps XMM0, YMM0; vcvtpd2ps XMM0, [RAX]; vcvtps2dq XMM0, XMM0; vcvtps2dq YMM0, YMM0; vcvtps2dq YMM0, [RAX]; vcvtps2pd XMM0, XMM0; vcvtps2pd YMM0, XMM0; vcvtps2pd YMM0, [RAX]; vcvtsd2si EAX, XMM0; vcvtsd2si RAX, XMM0; vcvtsd2si RAX, [RAX]; vcvtsd2ss XMM0, XMM0, XMM0; vcvtsd2ss XMM0, XMM0, [RAX]; vcvtsi2sd XMM0, XMM0, EAX; vcvtsi2sd XMM0, XMM0, RAX; vcvtsi2sd XMM0, XMM0, [RAX]; vcvtsi2ss XMM0, XMM0, EAX; vcvtsi2ss XMM0, XMM0, RAX; vcvtsi2ss XMM0, XMM0, [RAX]; vcvtsi2sd XMM0, XMM0, EAX; vcvtsi2sd XMM0, XMM0, RAX; vcvtsi2sd XMM0, XMM0, [RAX]; vcvtss2si EAX, XMM0; vcvtss2si RAX, XMM0; vcvtss2si RAX, [RAX]; vcvttpd2dq XMM0, XMM0; vcvttpd2dq XMM0, YMM0; vcvttpd2dq XMM0, [RAX]; vcvttps2dq XMM0, XMM0; vcvttps2dq YMM0, YMM0; vcvttps2dq YMM0, [RAX]; vcvttsd2si EAX, XMM0; vcvttsd2si RAX, XMM0; vcvttsd2si RAX, [RAX]; vcvttss2si EAX, XMM0; vcvttss2si RAX, XMM0; vcvttss2si RAX, [RAX]; vbroadcastss XMM0, [RAX]; vbroadcastss YMM0, [RAX]; vbroadcastsd YMM0, [RAX]; vbroadcastf128 YMM0, [RAX]; vextractf128 XMM0, YMM0, 0; vextractf128 [RAX], YMM0, 0; vextractps EAX, XMM0, 0; vextractps [RAX], XMM0, 0; vinsertf128 YMM0, YMM0, XMM0, 0; vinsertf128 YMM0, YMM0, [RAX], 0; vinsertps XMM0, XMM0, XMM0, 0; vinsertps XMM0, XMM0, [RAX], 0; vpinsrb XMM0, XMM0, EAX, 0; vpinsrb XMM0, XMM0, [RAX], 0; vpinsrw XMM0, XMM0, EAX, 0; vpinsrw XMM0, XMM0, [RAX], 0; vpinsrd XMM0, XMM0, EAX, 0; vpinsrd XMM0, XMM0, [RAX], 0; vpinsrq XMM0, XMM0, RAX, 0; vpinsrq XMM0, XMM0, [RAX], 0; vlddqu XMM0, [RAX]; vlddqu YMM0, [RAX]; vmaskmovdqu XMM0, XMM0; vmaskmovps XMM0, XMM0, [RAX]; vmaskmovps [RAX], XMM0, XMM0; vmaskmovps YMM0, YMM0, [RAX]; vmaskmovps [RAX], YMM0, YMM0; vmaskmovpd XMM0, XMM0, [RAX]; vmaskmovpd [RAX], XMM0, XMM0; vmaskmovpd YMM0, YMM0, [RAX]; vmaskmovpd [RAX], YMM0, YMM0; vmovapd YMM0, [RAX]; vmovapd YMM8, [RAX]; vmovapd YMM8, 64[RDI]; vmovapd [RAX], YMM0; vmovapd [RAX], YMM8; vmovapd 64[RDI], YMM8; vmovaps YMM0, [RAX]; vmovaps YMM8, [RAX]; vmovaps YMM8, 64[RDI]; vmovaps [RAX], YMM0; vmovaps [RAX], YMM8; vmovaps 64[RDI], YMM8; vmovupd YMM0, [RAX]; vmovupd YMM8, [RAX]; vmovupd YMM8, 64[RDI]; vmovupd [RAX], YMM0; vmovupd [RAX], YMM8; vmovupd 64[RDI], YMM8; vmovups YMM0, [RAX]; vmovups YMM8, [RAX]; vmovups YMM8, 64[RDI]; vmovups [RAX], YMM0; vmovups [RAX], YMM8; vmovups 64[RDI], YMM8; vmovd XMM0, EAX; vmovd XMM0, [RAX]; vmovd EAX, XMM0; vmovd [RAX], XMM0; vmovq XMM0, RAX; vmovq XMM0, [RAX]; vmovq RAX, XMM0; vmovq [RAX], XMM0; vmovdqa XMM0, XMM0; vmovdqa XMM0, [RAX]; vmovdqa YMM0, YMM0; vmovdqa YMM0, [RAX]; vmovdqa XMM0, XMM0; vmovdqa [RAX], XMM0; vmovdqa YMM0, YMM0; vmovdqa [RAX],YMM0; vmovdqu XMM0, XMM0; vmovdqu XMM0, [RAX]; vmovdqu YMM0, YMM0; vmovdqu YMM0, [RAX]; vmovdqu XMM0, XMM0; vmovdqu [RAX], XMM0; vmovdqu YMM0, YMM0; vmovdqu [RAX],YMM0; vmovlhps XMM0, XMM0, XMM0; vmovhlps XMM0, XMM0, XMM0; vmovhpd XMM0, XMM0, [RAX]; vmovhpd [RAX], XMM0; vmovhps XMM0, XMM0, [RAX]; vmovhps [RAX], XMM0; vmovlpd XMM0, XMM0, [RAX]; vmovlpd [RAX], XMM0; vmovlps XMM0, XMM0, [RAX]; vmovlps [RAX], XMM0; vmovntdq [RAX], XMM0; vmovntdq [RAX], YMM8; vmovntpd [RAX], XMM0; vmovntpd [RAX], YMM8; vmovntps [RAX], XMM0; vmovntps [RAX], YMM8; vmovntdqa XMM0, [RAX]; vmovsd XMM0, XMM0, XMM0; vmovsd XMM8, XMM8, XMM8; vmovsd [RAX], XMM0; vmovsd [R8], XMM8; vmovss XMM0, XMM0, XMM0; vmovss XMM8, XMM8, XMM8; vmovss [RAX], XMM0; vmovss [R8], XMM8; vmovshdup XMM8, XMM1; vmovshdup YMM0, YMM8; vmovshdup YMM0, [RAX]; vmovsldup XMM8, XMM1; vmovsldup YMM0, YMM8; vmovsldup YMM0, [RAX]; vpackuswb XMM0, XMM1, XMM2; vpackuswb XMM0, XMM8, [RAX]; vpackusdw XMM0, XMM1, XMM2; vpackusdw XMM0, XMM8, [RAX]; vpacksswb XMM0, XMM1, XMM2; vpacksswb XMM0, XMM8, [RAX]; vpackssdw XMM0, XMM1, XMM2; vpackssdw XMM0, XMM8, [RAX]; vpalignr XMM0, XMM1, XMM2, 0xFF; vpalignr XMM9, XMM8, [RAX], 0x10; vpextrb EAX, XMM0, 0x0; vpextrb R10, XMM9, 0xF; vpextrb [R10], XMM9, 0xF; vpextrd EAX, XMM0, 0x0; vpextrd R8D, XMM9, 0xF; vpextrd [R10], XMM9, 0xF; vpextrq RAX, XMM0, 0x0; vpextrq R10, XMM9, 0xF; vpextrq [R10], XMM9, 0xF; vpextrw EAX, XMM0, 0x0; vpextrw R10, XMM9, 0xF; vpextrw [R10], XMM9, 0xF; vpmovsxbw XMM0, XMM0; vpmovsxbw XMM8, [R8]; vpmovsxbd XMM0, XMM0; vpmovsxbd XMM8, [R8]; vpmovsxbq XMM0, XMM0; vpmovsxbq XMM8, [R8]; vpmovsxwd XMM0, XMM0; vpmovsxwd XMM8, [R8]; vpmovsxwq XMM0, XMM0; vpmovsxwq XMM8, [R8]; vpmovsxdq XMM0, XMM0; vpmovsxdq XMM8, [R8]; vpmovzxbw XMM0, XMM0; vpmovzxbw XMM8, [R8]; vpmovzxbd XMM0, XMM0; vpmovzxbd XMM8, [R8]; vpmovzxbq XMM0, XMM0; vpmovzxbq XMM8, [R8]; vpmovzxwd XMM0, XMM0; vpmovzxwd XMM8, [R8]; vpmovzxwq XMM0, XMM0; vpmovzxwq XMM8, [R8]; vpmovzxdq XMM0, XMM0; vpmovzxdq XMM8, [R8]; vandpd XMM0, XMM0, XMM0; vandpd XMM9, XMM8, [R8]; vandps XMM0, XMM0, XMM0; vandps XMM9, XMM8, [R8]; vandnpd XMM0, XMM0, XMM0; vandnpd XMM9, XMM8, [R8]; vandnps XMM0, XMM0, XMM0; vandnps XMM9, XMM8, [R8]; vorpd XMM0, XMM0, XMM0; vorpd XMM9, XMM8, [R8]; vorps XMM0, XMM0, XMM0; vorps XMM9, XMM8, [R8]; vpand XMM0, XMM0, XMM0; vpand XMM9, XMM8, [R8]; vpandn XMM0, XMM0, XMM0; vpandn XMM9, XMM8, [R8]; vpor XMM0, XMM0, XMM0; vpor XMM9, XMM8, [R10]; vpxor XMM0, XMM0, XMM0; vpxor XMM9, XMM8, [R10]; vptest XMM0, XMM0; vptest XMM8, [RAX]; vptest YMM8, YMM8; vptest YMM0, [R8]; vucomisd XMM0, XMM0; vucomisd XMM8, [RAX]; vucomiss XMM0, XMM0; vucomiss XMM8, [RAX]; vxorpd XMM0, XMM8, XMM0; vxorpd XMM8, XMM0, [RAX]; vxorpd YMM0, YMM8, YMM0; vxorpd YMM8, YMM0, [RAX]; vxorps XMM0, XMM8, XMM0; vxorps XMM8, XMM0, [RAX]; vxorps YMM0, YMM8, YMM0; vxorps YMM8, YMM0, [RAX]; vblendpd XMM0, XMM1, XMM2, 0x00; vblendpd XMM9, XMM8, [RAX], 0xFF; vblendpd YMM0, YMM1, YMM2, 0x00; vblendpd YMM9, YMM8, [RAX], 0xFF; vblendps XMM0, XMM1, XMM2, 0x00; vblendps XMM9, XMM8, [RAX], 0xFF; vblendps YMM0, YMM1, YMM2, 0x00; vblendps YMM9, YMM8, [RAX], 0xFF; vblendvpd XMM0, XMM1, XMM2, 0x00; vblendvpd XMM9, XMM8, [RAX], 0xFF; vblendvpd YMM0, YMM1, YMM2, 0x00; vblendvpd YMM9, YMM8, [RAX], 0xFF; vblendvps XMM0, XMM1, XMM2, 0x00; vblendvps XMM9, XMM8, [RAX], 0xFF; vblendvps YMM0, YMM1, YMM2, 0x00; vblendvps YMM9, YMM8, [RAX], 0xFF; vmovddup XMM8, XMM0; vmovddup XMM0, [RAX]; vmovddup YMM0, YMM8; vmovddup YMM0, [R10]; vpblendvb XMM0, XMM8, XMM0, 0x00; vpblendvb XMM8, XMM0, [RAX], 0x00; vpblendvb XMM8, XMM0, [R10], 0x00; vpblendw XMM0, XMM8, XMM0, 0x00; vpblendw XMM8, XMM0, [RAX], 0x00; vpblendw XMM8, XMM0, [R10], 0x00; vpermilpd XMM0, XMM1, XMM2; vpermilpd XMM0, XMM1, [RAX]; vpermilpd XMM0, XMM1, 0x00; vpermilpd XMM0, [RAX], 0x00; vpermilps XMM0, XMM1, XMM2; vpermilps XMM0, XMM1, [RAX]; vpermilps XMM0, XMM1, 0x00; vpermilps XMM0, [RAX], 0x00; vperm2f128 YMM0, YMM1, YMM2, 0x00; vperm2f128 YMM0, YMM1, [RAX], 0x00; vperm2f128 YMM8, YMM9, [R10], 0x00; vpshufb XMM0, XMM0, XMM0; vpshufb XMM9, XMM8, [R8]; vpshufd XMM0, XMM0, 0x0; vpshufd XMM8, [R8], 0x0; vpshufhw XMM0, XMM0, 0x0; vpshufhw XMM8, [R8], 0x0; vpshuflw XMM0, XMM0, 0x0; vpshuflw XMM8, [R8], 0x0; vpunpckhbw XMM0, XMM1, XMM2; vpunpckhbw XMM8, XMM8, [R8]; vpunpckhwd XMM0, XMM1, XMM2; vpunpckhwd XMM8, XMM8, [R8]; vpunpckhdq XMM0, XMM1, XMM2; vpunpckhdq XMM8, XMM8, [R8]; vpunpckhqdq XMM0, XMM1, XMM2; vpunpckhqdq XMM8, XMM8, [R8]; vpunpcklbw XMM0, XMM1, XMM2; vpunpcklbw XMM8, XMM8, [R8]; vpunpcklwd XMM0, XMM1, XMM2; vpunpcklwd XMM8, XMM8, [R8]; vpunpckldq XMM0, XMM1, XMM2; vpunpckldq XMM8, XMM8, [R8]; vpunpcklqdq XMM0, XMM1, XMM2; vpunpcklqdq XMM8, XMM8, [R8]; vshufpd XMM0, XMM0, XMM0, 0x00; vshufpd XMM0, XMM8, [R8], 0x00; vshufpd YMM8, YMM0, YMM8, 0x00; vshufpd YMM8, YMM0, [RAX], 0x00; vshufps XMM0, XMM0, XMM0, 0x00; vshufps XMM0, XMM8, [R8], 0x00; vshufps YMM8, YMM0, YMM8, 0x00; vshufps YMM8, YMM0, [RAX], 0x00; vunpckhpd XMM0, XMM0, XMM0; vunpckhpd XMM8, XMM8, [RAX]; vunpckhpd YMM8, YMM0, [R8]; vunpckhpd YMM0, YMM8, [R8]; vunpckhps XMM0, XMM0, XMM0; vunpckhps XMM8, XMM8, [RAX]; vunpckhps YMM8, YMM0, [R8]; vunpckhps YMM0, YMM8, [R8]; vunpcklpd XMM0, XMM0, XMM0; vunpcklpd XMM8, XMM8, [RAX]; vunpcklpd YMM8, YMM0, [R8]; vunpcklpd YMM0, YMM8, [R8]; vunpcklps XMM0, XMM0, XMM0; vunpcklps XMM8, XMM8, [RAX]; vunpcklps YMM8, YMM0, [R8]; vunpcklps YMM0, YMM8, [R8]; /* AES */ aesenc XMM0, XMM0; aesenc XMM0, [RAX]; vaesenc XMM0, XMM0, XMM0; vaesenc XMM0, XMM0, [RAX]; aesenclast XMM0, XMM0; aesenclast XMM0, [RAX]; vaesenclast XMM0, XMM0, XMM0; vaesenclast XMM0, XMM0, [RAX]; aesdec XMM0, XMM0; aesdec XMM0, [RAX]; vaesdec XMM0, XMM0, XMM0; vaesdec XMM0, XMM0, [RAX]; aesdeclast XMM0, XMM0; aesdeclast XMM0, [RAX]; vaesdeclast XMM0, XMM0, XMM0; vaesdeclast XMM0, XMM0, [RAX]; aesimc XMM0, XMM0; aesimc XMM0, [RAX]; vaesimc XMM0, XMM0; vaesimc XMM0, [RAX]; aeskeygenassist XMM0, XMM0, 0x0; aeskeygenassist XMM0, [RAX], 0x0; vaeskeygenassist XMM0, XMM0, 0x0; vaeskeygenassist XMM0, [RAX], 0x0; /* FSGSBASE */ rdfsbase RAX; rdfsbase R15; rdgsbase RAX; rdgsbase R15; wrfsbase RAX; wrfsbase R15; wrgsbase RAX; wrgsbase R15; /* RDRAND */ rdrand AX; rdrand EAX; rdrand RAX; rdrand R15W; rdrand R15D; rdrand R15; /* FP16C */ vcvtph2ps XMM0, XMM0; vcvtph2ps XMM0, [RAX]; vcvtph2ps YMM0, XMM0; vcvtph2ps YMM8, [R8]; vcvtps2ph XMM0, XMM0, 0x0; vcvtps2ph [RAX], XMM0, 0x0; vcvtps2ph XMM0, YMM0, 0x0; vcvtps2ph [R8], YMM8, 0x0; /* FMA */ vfmadd132pd XMM0, XMM0, XMM0; vfmadd132pd XMM0, XMM0, [RAX]; vfmadd132pd YMM0, YMM0, YMM0; vfmadd132pd YMM8, YMM8, [R8]; vfmadd132ps XMM0, XMM0, XMM0; vfmadd132ps XMM0, XMM0, [RAX]; vfmadd132ps YMM0, YMM0, YMM0; vfmadd132ps YMM8, YMM8, [R8]; vfmadd132sd XMM0, XMM0, XMM0; vfmadd132sd XMM0, XMM0, [RAX]; vfmadd132ss XMM0, XMM0, XMM0; vfmadd132ss XMM0, XMM0, [RAX]; vfmadd213pd XMM0, XMM0, XMM0; vfmadd213pd XMM0, XMM0, [RAX]; vfmadd213pd YMM0, YMM0, YMM0; vfmadd213pd YMM8, YMM8, [R8]; vfmadd213ps XMM0, XMM0, XMM0; vfmadd213ps XMM0, XMM0, [RAX]; vfmadd213ps YMM0, YMM0, YMM0; vfmadd213ps YMM8, YMM8, [R8]; vfmadd213sd XMM0, XMM0, XMM0; vfmadd213sd XMM0, XMM0, [RAX]; vfmadd213ss XMM0, XMM0, XMM0; vfmadd213ss XMM0, XMM0, [RAX]; vfmadd231pd XMM0, XMM0, XMM0; vfmadd231pd XMM0, XMM0, [RAX]; vfmadd231pd YMM0, YMM0, YMM0; vfmadd231pd YMM8, YMM8, [R8]; vfmadd231ps XMM0, XMM0, XMM0; vfmadd231ps XMM0, XMM0, [RAX]; vfmadd231ps YMM0, YMM0, YMM0; vfmadd231ps YMM8, YMM8, [R8]; vfmadd231sd XMM0, XMM0, XMM0; vfmadd231sd XMM0, XMM0, [RAX]; vfmadd231ss XMM0, XMM0, XMM0; vfmadd231ss XMM0, XMM0, [RAX]; vfmaddsub132pd XMM0, XMM0, XMM0; vfmaddsub132pd XMM0, XMM0, [RAX]; vfmaddsub132pd YMM0, YMM0, YMM0; vfmaddsub132pd YMM8, YMM8, [R8]; vfmaddsub132ps XMM0, XMM0, XMM0; vfmaddsub132ps XMM0, XMM0, [RAX]; vfmaddsub132ps YMM0, YMM0, YMM0; vfmaddsub132ps YMM8, YMM8, [R8]; vfmaddsub213pd XMM0, XMM0, XMM0; vfmaddsub213pd XMM0, XMM0, [RAX]; vfmaddsub213pd YMM0, YMM0, YMM0; vfmaddsub213pd YMM8, YMM8, [R8]; vfmaddsub213ps XMM0, XMM0, XMM0; vfmaddsub213ps XMM0, XMM0, [RAX]; vfmaddsub213ps YMM0, YMM0, YMM0; vfmaddsub213ps YMM8, YMM8, [R8]; vfmaddsub231pd XMM0, XMM0, XMM0; vfmaddsub231pd XMM0, XMM0, [RAX]; vfmaddsub231pd YMM0, YMM0, YMM0; vfmaddsub231pd YMM8, YMM8, [R8]; vfmaddsub231ps XMM0, XMM0, XMM0; vfmaddsub231ps XMM0, XMM0, [RAX]; vfmaddsub231ps YMM0, YMM0, YMM0; vfmaddsub231ps YMM8, YMM8, [R8]; vfmsubadd132pd XMM0, XMM0, XMM0; vfmsubadd132pd XMM0, XMM0, [RAX]; vfmsubadd132pd YMM0, YMM0, YMM0; vfmsubadd132pd YMM8, YMM8, [R8]; vfmsubadd132ps XMM0, XMM0, XMM0; vfmsubadd132ps XMM0, XMM0, [RAX]; vfmsubadd132ps YMM0, YMM0, YMM0; vfmsubadd132ps YMM8, YMM8, [R8]; vfmsubadd213pd XMM0, XMM0, XMM0; vfmsubadd213pd XMM0, XMM0, [RAX]; vfmsubadd213pd YMM0, YMM0, YMM0; vfmsubadd213pd YMM8, YMM8, [R8]; vfmsubadd213ps XMM0, XMM0, XMM0; vfmsubadd213ps XMM0, XMM0, [RAX]; vfmsubadd213ps YMM0, YMM0, YMM0; vfmsubadd213ps YMM8, YMM8, [R8]; vfmsubadd231pd XMM0, XMM0, XMM0; vfmsubadd231pd XMM0, XMM0, [RAX]; vfmsubadd231pd YMM0, YMM0, YMM0; vfmsubadd231pd YMM8, YMM8, [R8]; vfmsubadd231ps XMM0, XMM0, XMM0; vfmsubadd231ps XMM0, XMM0, [RAX]; vfmsubadd231ps YMM0, YMM0, YMM0; vfmsubadd231ps YMM8, YMM8, [R8]; vfmsub132pd XMM0, XMM0, XMM0; vfmsub132pd XMM0, XMM0, [RAX]; vfmsub132pd YMM0, YMM0, YMM0; vfmsub132pd YMM8, YMM8, [R8]; vfmsub132ps XMM0, XMM0, XMM0; vfmsub132ps XMM0, XMM0, [RAX]; vfmsub132ps YMM0, YMM0, YMM0; vfmsub132ps YMM8, YMM8, [R8]; vfmsub132sd XMM0, XMM0, XMM0; vfmsub132sd XMM0, XMM0, [RAX]; vfmsub132ss XMM0, XMM0, XMM0; vfmsub132ss XMM0, XMM0, [RAX]; vfmsub213pd XMM0, XMM0, XMM0; vfmsub213pd XMM0, XMM0, [RAX]; vfmsub213pd YMM0, YMM0, YMM0; vfmsub213pd YMM8, YMM8, [R8]; vfmsub213ps XMM0, XMM0, XMM0; vfmsub213ps XMM0, XMM0, [RAX]; vfmsub213ps YMM0, YMM0, YMM0; vfmsub213ps YMM8, YMM8, [R8]; vfmsub213sd XMM0, XMM0, XMM0; vfmsub213sd XMM0, XMM0, [RAX]; vfmsub213ss XMM0, XMM0, XMM0; vfmsub213ss XMM0, XMM0, [RAX]; vfmsub231pd XMM0, XMM0, XMM0; vfmsub231pd XMM0, XMM0, [RAX]; vfmsub231pd YMM0, YMM0, YMM0; vfmsub231pd YMM8, YMM8, [R8]; vfmsub231ps XMM0, XMM0, XMM0; vfmsub231ps XMM0, XMM0, [RAX]; vfmsub231ps YMM0, YMM0, YMM0; vfmsub231ps YMM8, YMM8, [R8]; vfmsub231sd XMM0, XMM0, XMM0; vfmsub231sd XMM0, XMM0, [RAX]; vfmsub231ss XMM0, XMM0, XMM0; vfmsub231ss XMM0, XMM0, [RAX]; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { // printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } assert(p[data.length] == 0x58); // pop RAX } /* ======================= SHA ========================== */ void test62() { ubyte* p; byte m8; short m16; int m32; M64 m64; M128 m128; static ubyte data[] = [ 0x0F, 0x3A, 0xCC, 0xD1, 0x01, // sha1rnds4 XMM2, XMM1, 1; 0x0F, 0x3A, 0xCC, 0x10, 0x01, // sha1rnds4 XMM2, [RAX], 1; 0x0F, 0x38, 0xC8, 0xD1, // sha1nexte XMM2, XMM1; 0x0F, 0x38, 0xC8, 0x10, // sha1nexte XMM2, [RAX]; 0x0F, 0x38, 0xC9, 0xD1, // sha1msg1 XMM2, XMM1; 0x0F, 0x38, 0xC9, 0x10, // sha1msg1 XMM2, [RAX]; 0x0F, 0x38, 0xCA, 0xD1, // sha1msg2 XMM2, XMM1; 0x0F, 0x38, 0xCA, 0x10, // sha1msg2 XMM2, [RAX]; 0x0F, 0x38, 0xCB, 0xD1, // sha256rnds2 XMM2, XMM1; 0x0F, 0x38, 0xCB, 0x10, // sha256rnds2 XMM2, [RAX]; 0x0F, 0x38, 0xCC, 0xD1, // sha256msg1 XMM2, XMM1; 0x0F, 0x38, 0xCC, 0x10, // sha256msg1 XMM2, [RAX]; 0x0F, 0x38, 0xCD, 0xD1, // sha256msg2 XMM2, XMM1; 0x0F, 0x38, 0xCD, 0x10, // sha256msg2 XMM2, [RAX]; ]; asm { call L1; sha1rnds4 XMM2, XMM1, 1; sha1rnds4 XMM2, [RAX], 1; sha1nexte XMM2, XMM1; sha1nexte XMM2, [RAX]; sha1msg1 XMM2, XMM1; sha1msg1 XMM2, [RAX]; sha1msg2 XMM2, XMM1; sha1msg2 XMM2, [RAX]; sha256rnds2 XMM2, XMM1; sha256rnds2 XMM2, [RAX]; sha256msg1 XMM2, XMM1; sha256msg1 XMM2, [RAX]; sha256msg2 XMM2, XMM1; sha256msg2 XMM2, [RAX]; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } void test2941() { ubyte *p; static ubyte data[] = [ 0x9B, 0xDF, 0xE0, // fstsw AX; ]; int i; asm { call L1 ; fstsw AX; L1: pop RBX ; mov p[RBP],RBX ; } for (i = 0; i < data.length; i++) { assert(p[i] == data[i]); } } void test9866() { ubyte* p; static ubyte data[] = [ 0x48, 0x0f, 0xbe, 0xc0, // movsx RAX, AL 0x48, 0x0f, 0xbe, 0x00, // movsx RAX, byte ptr [RAX] 0x48, 0x0f, 0xbf, 0xc0, // movsx RAX, AX 0x48, 0x0f, 0xbf, 0x00, // movsx RAX, word ptr [RAX] 0x48, 0x63, 0xc0, // movsxd RAX, EAX 0x48, 0x63, 0x00, // movsxd RAX, dword ptr [RAX] ]; asm { call L1; movsx RAX, AL; movsx RAX, byte ptr [RAX]; movsx RAX, AX; movsx RAX, word ptr [RAX]; movsxd RAX, EAX; movsxd RAX, dword ptr [RAX]; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { // printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } assert(p[data.length] == 0x58); // pop RAX } /****************************************************/ void testxadd() { int x; ubyte* p; static ubyte data[] = [ 0x0F, 0xC0, 0x10, 0x66, 0x0F, 0xC1, 0x10, 0x0F, 0xC1, 0x10, 0x48, 0x0F, 0xC1, 0x10, ]; asm { call L1 ; xadd byte ptr [RAX],DL; xadd word ptr [RAX],DX; xadd dword ptr [RAX],EDX; xadd qword ptr [RAX],RDX; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } /****************************************************/ void testconst() { ulong result; asm { mov RAX, 0xFFFF_FFFFu; mov result, RAX; } assert (result == 0xFFFF_FFFFu); } /****************************************************/ void test9965() { ubyte* p; static ubyte data[] = [ 0xB7, 0x01, // mov BH,1 0x40, 0xB6, 0x01, // mov SIL,1 0x40, 0xB7, 0x01, // mov DIL,1 0x40, 0xB5, 0x01, // mov BPL,1 0x40, 0xB4, 0x01, // mov SPL,1 0x41, 0xB0, 0x01, // mov R8B,1 0x40, 0x80, 0xE6, 0x01, // and SIL,1 (issue 12971) ]; asm { call L1; mov BH, 1; mov SIL, 1; mov DIL, 1; mov BPL, 1; mov SPL, 1; mov R8B, 1; and SIL, 1; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { // printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } assert(p[data.length] == 0x58); // pop RAX } /****************************************************/ void test12849() { ulong a = 0xff00ff00ff00ff00L; ulong result; ulong expected = 0b10101010; asm { pxor XMM0, XMM0; movq XMM0, a; pmovmskb RAX, XMM0; mov result, RAX; } assert (result == expected); } /****************************************************/ void test12968() { int x; ubyte* p; static ubyte data[] = [ 0x48, 0x89, 0xF8, 0x4C, 0x87, 0xC2, 0xC3 ]; asm { call L1 ; mov RAX, RDI; xchg RDX, R8; ret; L1: pop RAX; mov p[RBP],RAX; } foreach (ref i, b; data) { //printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b); assert(p[i] == b); } } /****************************************************/ int main() { printf("Testing iasm64.d\n"); test1(); test2(); test3(); test4(); test5(); test6(); //test7(); TODO 16bit seg test8(); //test9(); Fails //test10(); Fails test11(); test12(); test13(); test14(); test15(); //test16(); // add this one from \cbx\test\iasm.c ? test17(); test18(); test19(); //test20(); 8087 test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); //test29(); offsetof? test30(); test31(); test32(); test33(); test34(); //test35(); RIP addressing? //test36(); RIP addressing? test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); //test47(); RIP addressing? test48(); test49(); test50(); //Test51 test52(); test53(); test54(); test55(); test56(); test57(); test58(); test59(); test60(); test61(); test62(); test2941(); test9866(); testxadd(); test9965(); test12849(); test12968(); testconst(); printf("Success\n"); return 0; } } else { int main() { return 0; } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_176.d0000664000175000017500000000067112776215022023056 0ustar kaikaialias __vector(float[4]) float4; void testSplatInit() { float4 a = 1, b = 2; assert((a + b).array == [3, 3, 3, 3]); } void testArrayInit() { float4 c = [1, 2, 3, 4]; assert(c.array == [1, 2, 3, 4]); } void testArrayPtrAssign() { float4 c = 1, d = 0; d.array[0] = 1; d.ptr[1] = 2; assert((c + d).array == [2, 3, 1, 1]); } void main() { testSplatInit(); testArrayInit(); testArrayPtrAssign(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test15.d0000664000175000017500000005041012776215022021476 0ustar kaikai// REQUIRED_ARGS: import std.array; import core.stdc.math : cos, fabs, sin, sqrt; import core.vararg; import std.math: rndtol, rint; import std.string; import std.stdio : File; extern (C) { int printf(const char*, ...); } struct A { int x; } struct B { int x = 22; } void test5() { A* a = new A; assert(a.x == 0); B* b = new B; assert(b.x == 22); } /************************************/ void test6() { assert('\x12'.sizeof == 1); assert('\u1234'.sizeof == 2); assert('\U00105678'.sizeof == 4); assert('\x12' == 0x12); assert('\u1234' == 0x1234); assert('\U00105678' == 0x105678); assert("abc\\def" == r"abc\def"); } /************************************/ void test7() { string s = `hello"there'you`; printf("s = '%.*s'\n", s.length, s.ptr); assert(s == "hello\"there'you"); ubyte[] b = cast(ubyte[])x"8B 7D f4 0d"; for (int i = 0; i < b.length; i++) printf("b[%d] = x%02x\n", i, b[i]); assert(b.length == 4); assert(b[0] == 0x8B); assert(b[1] == 0x7D); assert(b[2] == 0xF4); assert(b[3] == 0x0D); } /************************************/ void foo8(out bool b) { b = true; } void test8() { bool b; bool *pb = &b; assert(b == false); *pb = true; assert(b == true); *pb = false; assert(b == false); foo8(b); assert(b == true); } /************************************/ struct Pair { int a; int b; Pair abs () { return this; } Pair opDiv(Pair other) { Pair result; result.a = a + other.a; result.b = b + other.b; return result; } } void test9() { Pair t; t.a = 5; t.b = 23; t = t.abs () / t; printf("a = %d, b = %d\n", t.a, t.b); assert(t.a == 10); assert(t.b == 46); } /************************************/ void test10() { int b = 0b_1_1__1_0_0_0_1_0_1_0_1_0_; printf("b = %d\n", b); assert(b == 3626); b = 1_2_3_4_; printf("b = %d\n", b); assert(b == 1234); b = 0x_1_2_3_4_; printf("b = %d\n", b); assert(b == 4660); b = 0_; printf("b = %d\n", b); assert(b == 0); double d = 0_._2_3_4_; printf("d = %g\n", d); assert(d == 0.234); d = 0_._2_3_4_e+3_5_; printf("d = %g\n", d); assert(d == 0.234e+35); d = 0_._2_3_4_e3_5_; printf("d = %g\n", d); assert(d == 0.234e+35); } /************************************/ class CA14 { } class CB14 : CA14 { } class A14 { int show( CA14 a ) { printf("A14::show( CA14 )\n"); return 1; } int boat( CA14 a ) { printf("A14::boat( CA14 )\n"); return 1; } } class B14 : A14 { int show( CA14 a, CB14 b ) { printf("B14::show(CA14, CB14)\n"); return 2; } int boat( CA14 a, CB14 b ) { printf("B14::boat(CA14, CB14)\n"); return 2; } } class C14 : B14 { override int show( CA14 a ) { printf("C::show( CA14 )\n"); return 3; } alias B14.show show; alias B14.boat boat; override int boat( CA14 a ) { printf("C::boat( CA14 )\n"); return 3; } } class D14 : C14 { } void test14() { D14 b = new D14(); int i; i = b.show( new CA14(), new CB14() ); assert(i == 2); i = b.show( new CA14() ); assert(i == 3); i = b.boat( new CA14(), new CB14() ); assert(i == 2); i = b.boat( new CA14() ); assert(i == 3); } /************************************/ class A15 { void foo() { List1.rehash; List2.rehash; } private: int delegate(in int arg1) List1[char[]]; int List2[char []]; } void test15() { } /************************************/ void test16() { char[] a=new char[0]; uint c = 200000; while (c--) a ~= 'x'; //printf("a = '%.*s'\n", a.length, a.ptr); } /************************************/ class A17 { } class B17 : A17 { } void foo17(const(A17)[] a) { } void test17() { B17[] b; foo17(b); } /************************************/ void test18() { uint a; real b=4; a=cast(uint)b; } /************************************/ abstract class Foo19 { int bar() { return 1; } } void test19() { Foo19 f; } /************************************/ int foo20(string s,char d) { return 1; } int foo20(string s,double d) { return 2; } int foo20(string s,cdouble d) { return 3; } void test20() { int i; double x; i = foo20("test=",x); assert(i == 2); } /************************************/ void test21() { int[string] esdom; auto f = File("runnable/extra-files/test15.txt", "r"); foreach(it; f.byLine()) esdom[it.idup] = 0; esdom.rehash; } /************************************/ int foo22(char* p) { return 1; } int foo22(char[] s) { return 2; } void test22() { int i; i = foo22(cast(char*)"abc"); assert(i == 1); i = foo22(cast(char[])"abc"); assert(i == 2); } /************************************/ void test23() { uint v; int b; long l; real e; e = cos(e); e = fabs(e); e = rint(e); l = rndtol(e); e = sin(e); e = sqrt(e); } /************************************/ abstract class dtortest24 { this() {} ~this() {} } void test24() { } /************************************/ abstract class bar25 { this() {} void foo() {} } class subbar25 : bar25 { this() {} } void test25() { new subbar25(); } /************************************/ void test26() { string[] instructions = std.array.split("a;b;c", ";"); foreach(ref string instr; instructions) { std.string.strip(instr); } foreach(string instr; instructions) { printf("%.*s\n", instr.length, instr.ptr); } } /************************************/ void foo27(ClassInfo ci) { } class A27 { } class B27 : A27 { static this() { foo27(B27.classinfo); foo27(A27.classinfo); } } void test27() { } /************************************/ void foo28(ClassInfo ci) { printf("%.*s\n", ci.name.length, ci.name.ptr); static int i; switch (i++) { case 0: case 2: assert(ci.name == "test15.A28"); break; case 1: assert(ci.name == "test15.B28"); break; default: assert(0); } } class A28 { static this() { foo28(A28.classinfo ); } } class B28 : A28 { static this() { foo28(B28.classinfo ); (new B28()).bodge_it(); } void bodge_it() { foo28(A28.classinfo ); } } void test28() { A28 a,b; a = new A28(); b = new B28(); } /************************************/ void test29() { static void delegate() dg; dg = null; } /************************************/ string foo30(int i) { return i ? "three" : "two"; } string bar30(int i) { return i ? "one" : "five"; } void test30() { string s; s = foo30(0); assert(s == "two"); s = foo30(1); assert(s == "three"); s = bar30(0); assert(s == "five"); s = bar30(1); assert(s == "one"); } /************************************/ // http://www.digitalmars.com/d/archives/18204.html // DMD0.050 also failed with alias. alias int recls_bool_t; class Entry31 { recls_bool_t IsReadOnly() { return cast(recls_bool_t)0; } } void test31() { Entry31 entry = new Entry31(); if (entry.IsReadOnly) { } } /************************************/ class A32 { alias int delegate() mfunc; this( mfunc initv ) { } } class foo32 { static void getMemberBar() { //foo32 f = new foo32(); new A32( &(f.bar) ); new A32( &((new foo32()).bar) ); } int bar() { return 0; } } void test32() { foo32.getMemberBar(); } /************************************/ void[] foo33(int[] b) { return b; } void test33() { int[6] c; void[] v; v = foo33(c); assert(v.length == 6 * int.sizeof); } /************************************/ void test34() { version (D_Bits) { bool[8] a8; assert(a8.sizeof == 4); bool[16] a16; assert(a16.sizeof == 4); bool[32] a32; assert(a32.sizeof == 4); bool[256] a256; assert(a256.sizeof == 32); } } /************************************/ void test35() { typeof(1 + 2) i; assert(i.sizeof == int.sizeof); assert(typeof('c').sizeof == char.sizeof); assert(typeof(1).sizeof == int.sizeof); assert(typeof(1.0F).sizeof == float.sizeof); assert(typeof(1.0).sizeof == double.sizeof); assert(typeof(1.0L).sizeof == real.sizeof); //assert(((typeof(1.0L))i).sizeof == real.sizeof); assert((cast(typeof(1.0L))i).sizeof == real.sizeof); } /************************************/ void test36x() { version (Win32) { // stdin.getch(); } } void test36() { } /************************************/ struct T37 { char x; T37 create() { T37 t; t.x = 3; return t; } bool test1() { return create() == this; } bool test2() { return this == create(); } } void test37() { T37 t; assert(!t.test1()); t.x = 3; assert(t.test1()); t.x = 0; assert(!t.test2()); t.x = 3; assert(t.test2()); } /************************************/ void test38() { uint f(uint n) { return n % 10; } printf("%u\n", uint.max); printf("%u\n", f(uint.max)); assert(f(uint.max) == 5); } /************************************/ void test39() { short s=HIWORD (0x0FFFDDDD); short t=LOWORD (0xFFFFCCCC); short v=HIWORD_(0x0FFFEEEE); short x=HIWORD_(0xFFFFAAAA); printf("%x %x %x %x\n",s,t,v,x); assert(s == 0xFFF); assert(t == 0xFFFFCCCC); assert(v == 0xFFF); assert(x == 0xFFFFFFFF); } short HIWORD(uint i) { return cast(short)(( i >> 16) & 0xFFFF); } short LOWORD(uint i) { return cast(short)i; } extern (C) short HIWORD_(uint i) { return cast(short)(( i >> 16) & 0xFFFF); } /************************************/ class caller40 { caller40 opCall (out int i) { i = 10; return this; } } void test40() { caller40 c = new caller40; int x,y; c(x)(y); assert(x == 10); assert(y == 10); } /************************************/ class Foo41 { void print() {printf("Foo41\n");} } class Bar41 : Foo41 { void test() { void printFoo41() { super.print(); // DMD crashes here } printFoo41(); } } void test41() { Bar41 b = new Bar41(); b.test(); } /************************************/ interface Interface { void foo42(); } void bar42(Interface i) { i.foo42(); } class Abstract : Interface { abstract void foo42(); } class Concrete : Abstract { override void foo42() { printf("Concrete.foo42(this = %p)\n", this); } } class Sub : Concrete { } void test42() { Sub s = new Sub(); s.foo42(); bar42(s); } /************************************/ class A43 { int foo() { return 6; } } int bar43(A43 a) { return a.foo; } void test43() { A43 a = new A43(); assert(bar43(a) == 6); } /************************************/ class C44 { const char[][] arrArr=["foo"]; } void test44() { C44 c= new C44(); printf("%.*s\n", c.arrArr[0].length, c.arrArr[0].ptr); assert(c.arrArr[0] == "foo"); } /************************************/ void test45() { void* p; void[] data; data = p[0 .. 5]; } /************************************/ union A46 { char c; struct { short s; } struct { long l; } int a; struct { float f; } } void test46() { A46 a; printf("%d\n", cast(byte*)&a.c - cast(byte*)&a); printf("%d\n", cast(byte*)&a.s - cast(byte*)&a); printf("%d\n", cast(byte*)&a.l - cast(byte*)&a); printf("%d\n", cast(byte*)&a.a - cast(byte*)&a); printf("%d\n", cast(byte*)&a.f - cast(byte*)&a); assert(cast(byte*)&a.c == cast(byte*)&a); assert(cast(byte*)&a.s == cast(byte*)&a); assert(cast(byte*)&a.l == cast(byte*)&a); assert(cast(byte*)&a.a == cast(byte*)&a); assert(cast(byte*)&a.f == cast(byte*)&a); } /************************************/ class Bug47 { void foo() { } static void foo(int i) { } static void bar() { foo(1); } } void test47() { } /************************************/ int[2] x48 = 3; float y48 = 0.0f; void test48() { printf("%d, %d\n", x48[0], x48[1]); assert(x48[0] == 3 && x48[1] == 3); y48 = -100; printf("%d, %d\n", x48[0], x48[1]); assert(x48[0] == 3 && x48[1] == 3); } /************************************/ struct Baz49 { int x,y,z,t; } void foo49(out Baz49 x, out int y) { } void test49() { int y = 3; Baz49 b; assert(b.x == 0); assert(b.y == 0); assert(b.z == 0); assert(b.t == 0); b.x = 1; b.y = 6; b.z = 10; b.t = 11; foo49(b, y); assert(b.x == 0); assert(b.y == 0); assert(b.z == 0); assert(b.t == 0); assert(y == 0); } /************************************/ void foo50(int[] f, ...) { foreach(int i, TypeInfo ti; _arguments) { } } void bar50(out int[] f, ...) { foreach(int i, TypeInfo ti; _arguments) { } } void test50() { int[] a; foo50(a, 1, 2, 3); bar50(a, 1, 2, 3); } /************************************/ deprecated int tri(int x) { return x*(x+1)/2; } deprecated int pent(int x) { return x*x + tri(x) - x; } deprecated class Qwert { int yuiop; this(int y) { yuiop = y; } int twiceYuiop() { return 2 * yuiop; } invariant() { assert (yuiop < 100); } } void test51() { } /************************************/ void foo52(double d) {} deprecated void foo52(int i) {} deprecated void bar52(int i) {} void bar52(double d) {} void test52() { // foo52(1); foo52(1.0); bar52(1.0); } /************************************/ class X53 { void foo(double d) {} deprecated void foo(int i) {} deprecated void bar(int i) {} void bar(double d) {} } void test53() { X53 x = new X53(); //x.foo(1); //x.bar(1); x.foo(1.0); x.bar(1.0); } /************************************/ interface B54 : A54 { A54 getParent(); } interface A54 { void parse(char[] systemId); } void test54() { } /************************************/ class Writer { int put (bool x){ return 1; } int put (int x){ return 2; } } class MyWriter : Writer { alias Writer.put put; override int put (bool x){ return 3; } } void test55() { MyWriter m = new MyWriter(); assert(m.put(false) == 3); assert(m.put(1) == 2); } /************************************/ class Foo56 { alias int baseType; } void test56() { Foo56 f = new Foo56; f.baseType s = 10; } /************************************/ void det(float mat[][]) { float newmat[][]; size_t i = newmat[0 .. (mat.length - 1)].length; } void test57() { } /************************************/ int foo58 (int a, int t) { return 2; } class A58 { int foo58 ( ) { return 3; } alias .foo58 foo58; } void test58() { int y, x; with ( new A58 ) { y = foo58(0,1); x = foo58(); } assert(y == 2); assert(x == 3); } /************************************/ void test59() { struct data { int b1=-1; int b2=2; } data d; assert(d.b1 == -1); assert(d.b2 == 2); } /************************************/ class Foo60 { int x; static: this() { x = 3; } ~this() { } } void test60() { Foo60 f = new Foo60(); assert(f.x == 3); } /************************************/ class StdString { alias std.string.format toString; } void test61() { int i = 123; StdString g = new StdString(); string s = g.toString("%s", i); printf("%.*s\n", s.length, s.ptr); assert(s == "123"); } /************************************/ void test62() { char[4] a; assert(a[0] == 0xFF); assert(a[1] == 0xFF); assert(a[2] == 0xFF); assert(a[3] == 0xFF); } /************************************/ void test63() { bool b; real r; int i; i=cast(double) b ? 1 : 4; r=cast(real) b ? 1.0 : 2.0; } /************************************/ struct MyStruct64 { int test(short s){printf("dynamic short\n"); return 1; } int test(int i){printf("dynamic int\n"); return 2; } static int staticTest(short s){printf("static short\n"); return 3; } static int staticTest(int i){printf("static int\n"); return 4; } } void test64() { MyStruct64 S; int j; short s = 1; int i = 1; j = S.test(s); assert(j == 1); j = S.test(i); assert(j == 2); j = S.staticTest(s); assert(j == 3); j = S.staticTest(i); assert(j == 4); } /************************************/ void test65() { int[8] qwert; int[] yuiop = qwert[2..5] = 4; assert(yuiop.length == 3); assert(yuiop[0] == 4); assert(yuiop[1] == 4); assert(yuiop[2] == 4); yuiop[1] = 2; assert(qwert[0] == 0); assert(qwert[1] == 0); assert(qwert[2] == 4); assert(qwert[3] == 2); assert(qwert[4] == 4); assert(qwert[5] == 0); assert(qwert[6] == 0); assert(qwert[7] == 0); } /************************************/ void foo66(ref bool b) { b = true; } void test66() { bool[3] a; foo66(a[0]); assert(a[0] == true); assert(a[1] == false); assert(a[2] == false); } /************************************/ class FuBar { void foo () { printf ("should never get here\n"); assert(0); } const(void)[] get () { return "weqweqweqweqwee"; } void test (void* dst) { uint count = 7; while (count) { // get as much as there is available in the buffer uint available = 10; // cap bytes read if (available > count) available = count; // copy them over dst[0..available] = get ()[0..available]; // bump counters dst += available; if ((count -= available) > 0) foo (); } } } void test67() { FuBar b = new FuBar(); char[10] dst; b.test(&dst[0]); } /************************************/ struct Foo68 { int a,b,c,d; } void bar68(out Foo68 f) { f.a = 28; } void test68() { Foo68 f; bar68(f); assert(f.a == 28); } /************************************/ class ConduitStyle { // static ConduitStyle Read; // static ConduitStyle ReadWrite; static ConduitStyle Read, ReadWrite; } void test69() { } /************************************/ void test70() { printf("-5/3 prints: %d\n", -5/3); printf("-5/2 prints: %d\n", -5/2); printf("-7/3 prints: %d\n", -7/3); printf("-7/4 prints: %d\n", -7/4); printf("-7/7 prints: %d\n", -7/7); printf("-8/7 prints: %d\n", -8/7); printf("-12/6 prints: %d\n", -12/6); printf("12/6 prints: %d\n", 12/6); printf("-9/7 prints: %d\n", -9/7); printf("-11/8 prints: %d\n", -11/8); printf("-7/9 prints: %d\n", -7/9); assert(-5/3 == -1); assert(-5/2 == -2); assert(-7/3 == -2); assert(-7/4 == -1); assert(-7/7 == -1); assert(-8/7 == -1); assert(-12/6 == -2); assert(12/6 == 2); assert(-9/7 == -1); assert(-11/8 == -1); assert(-7/9 == 0); } /************************************/ void insertText(string str) { assert(str == "a "); } char getCharAt() { return 'a'; } void test71() { insertText(getCharAt() ~ " "); } /************************************/ public class Foo72 { public this() { } } void test72() { Foo72[] foos; foos = new Foo72() ~ foos[]; assert(foos.length == 1); } /************************************/ int main() { test5(); test6(); test7(); test8(); test9(); test10(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test50(); test51(); test52(); test53(); test54(); test55(); test56(); test57(); test58(); test59(); test60(); test61(); test62(); test63(); test64(); test65(); test66(); test67(); test68(); test69(); test70(); test71(); test72(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/interpret.d0000664000175000017500000015653412776215022022403 0ustar kaikai import std.stdio; template Tuple(A...) { alias A Tuple; } template eval(A...) { const typeof(A[0]) eval = A[0]; } /************************************************/ int Foo1(int i) { if (i == 0) return 1; else return i * Foo1(i - 1); } void test1() { static int f = Foo1(5); printf("%d %d\n", f, 5*4*3*2); assert(f == 120); } /************************************************/ int find2(string s, char c) { if (s.length == 0) return -1; else if (c == s[0]) return 0; else return 1 + find2(s[1..$], c); } void test2() { static int f = find2("hello", 'l'); printf("%d\n", f); assert(f == 2); } /************************************************/ int bar3(int i) { int j; while (i) { j += i; i--; } return j; } void test3() { static b = bar3(7); printf("b = %d, %d\n", b, bar3(7)); assert(b == 28); } /************************************************/ int bar4(int i) { for (int j = 0; j < 10; j++) i += j; return i; } void test4() { static b = bar4(7); printf("b = %d, %d\n", b, bar4(7)); assert(b == 52); } /************************************************/ int bar5(int i) { int j; do { i += j; j++; } while (j < 10); return i; } void test5() { static b = bar5(7); printf("b = %d, %d\n", b, bar5(7)); assert(b == 52); } /************************************************/ int bar6(int i) { int j; do { i += j; j++; if (j == 4) break; } while (j < 10); return i; } void test6() { static b = bar6(7); printf("b = %d, %d\n", b, bar6(7)); assert(b == 13); } /************************************************/ int bar7(int i) { int j; do { i += j; j++; if (j == 4) return 80; } while (j < 10); return i; } void test7() { static b = bar7(7); printf("b = %d, %d\n", b, bar7(7)); assert(b == 80); } /************************************************/ int bar8(int i) { int j; do { j++; if (j == 4) continue; i += j; } while (j < 10); return i; } void test8() { static b = bar8(7); printf("b = %d, %d\n", b, bar8(7)); assert(b == 58); } /************************************************/ int bar9(int i) { int j; while (j < 10) { j++; if (j == 4) continue; i += j; } return i; } void test9() { static b = bar9(7); printf("b = %d, %d\n", b, bar9(7)); assert(b == 58); } /************************************************/ int bar10(int i) { int j; while (j < 10) { j++; if (j == 4) break; i += j; } return i; } void test10() { static b = bar10(7); printf("b = %d, %d\n", b, bar10(7)); assert(b == 13); } /************************************************/ int bar11(int i) { int j; while (j < 10) { j++; if (j == 4) return i << 3; i += j; } return i; } void test11() { static b = bar11(7); printf("b = %d, %d\n", b, bar11(7)); assert(b == 104); } /************************************************/ int bar12(int i) { for (int j; j < 10; j++) { if (j == 4) return i << 3; i += j; } return i; } void test12() { static b = bar12(7); printf("b = %d, %d\n", b, bar12(7)); assert(b == 104); } /************************************************/ int bar13(int i) { for (int j; j < 10; j++) { if (j == 4) break; i += j; } return i; } void test13() { static b = bar13(7); printf("b = %d, %d\n", b, bar13(7)); assert(b == 13); } /************************************************/ int bar14(int i) { for (int j; j < 10; j++) { if (j == 4) continue; i += j; } return i; } void test14() { static b = bar14(7); printf("b = %d, %d\n", b, bar14(7)); assert(b == 48); } /************************************************/ int bar15(int i) { foreach (k, v; "hello") { i <<= 1; if (k == 4) continue; i += v; } return i; } void test15() { static b = bar15(7); printf("b = %d, %d\n", b, bar15(7)); assert(b == 3344); } /************************************************/ int bar16(int i) { foreach_reverse (k, v; "hello") { i <<= 1; if (k == 4) continue; i += v; } return i; } void test16() { static b = bar16(7); printf("b = %d, %d\n", b, bar16(7)); assert(b == 1826); } /************************************************/ int bar17(int i) { foreach (k, v; "hello") { i <<= 1; if (k == 2) break; i += v; } return i; } void test17() { static b = bar17(7); printf("b = %d, %d\n", b, bar17(7)); assert(b == 674); } /************************************************/ int bar18(int i) { foreach_reverse (k, v; "hello") { i <<= 1; if (k == 2) break; i += v; } return i; } void test18() { static b = bar18(7); printf("b = %d, %d\n", b, bar18(7)); assert(b == 716); } /************************************************/ int bar19(int i) { assert(i > 0); foreach_reverse (k, v; "hello") { i <<= 1; if (k == 2) return 8; i += v; } return i; } void test19() { static b = bar19(7); printf("b = %d, %d\n", b, bar19(7)); assert(b == 8); } /************************************************/ int bar20(int i) { assert(i > 0); foreach (k, v; "hello") { i <<= 1; if (k == 2) return 8; i += v; } return i; } void test20() { static b = bar20(7); printf("b = %d, %d\n", b, bar20(7)); assert(b == 8); } /************************************************/ int bar21(int i) { assert(i > 0); foreach (v; Tuple!(57, 23, 8)) { i <<= 1; i += v; } return i; } void test21() { static b = bar21(7); printf("b = %d, %d\n", b, bar21(7)); assert(b == 338); } /************************************************/ int bar22(int i) { assert(i > 0); foreach_reverse (v; Tuple!(57, 23, 8)) { i <<= 1; i += v; } return i; } void test22() { static b = bar22(7); printf("b = %d, %d\n", b, bar22(7)); assert(b == 191); } /************************************************/ int bar23(int i) { assert(i > 0); foreach_reverse (v; Tuple!(57, 23, 8)) { i <<= 1; if (v == 23) return i + 1; i += v; } return i; } void test23() { static b = bar23(7); printf("b = %d, %d\n", b, bar23(7)); assert(b == 45); } /************************************************/ int bar24(int i) { assert(i > 0); foreach (v; Tuple!(57, 23, 8)) { i <<= 1; if (v == 23) return i + 1; i += v; } return i; } void test24() { static b = bar24(7); printf("b = %d, %d\n", b, bar24(7)); assert(b == 143); } /************************************************/ int bar25(int i) { assert(i > 0); foreach_reverse (v; Tuple!(57, 23, 8)) { i <<= 1; if (v == 23) break; i += v; } return i; } void test25() { static b = bar25(7); printf("b = %d, %d\n", b, bar25(7)); assert(b == 44); } /************************************************/ int bar26(int i) { assert(i > 0); foreach (v; Tuple!(57, 23, 8)) { i <<= 1; if (v == 23) break; i += v; } return i; } void test26() { static b = bar26(7); printf("b = %d, %d\n", b, bar26(7)); assert(b == 142); } /************************************************/ int bar27(int i) { foreach_reverse (v; Tuple!(57, 23, 8)) { i <<= 1; if (v == 23) continue; i += v; } return i; } void test27() { static b = bar27(7); printf("b = %d, %d\n", b, bar27(7)); assert(b == 145); } /************************************************/ int bar28(int i) { foreach (v; Tuple!(57, 23, 8)) { i <<= 1; if (v == 23) continue; i += v; } return i; } void test28() { static b = bar28(7); printf("b = %d, %d\n", b, bar28(7)); assert(b == 292); } /************************************************/ int bar29(int i) { switch (i) { case 1: i = 4; break; case 7: i = 3; break; default: assert(0); } return i; } void test29() { static b = bar29(7); printf("b = %d, %d\n", b, bar29(7)); assert(b == 3); } /************************************************/ int bar30(int i) { switch (i) { case 1: i = 4; break; case 8: i = 2; break; default: i = 3; break; } return i; } void test30() { static b = bar30(7); printf("b = %d, %d\n", b, bar30(7)); assert(b == 3); } /************************************************/ int bar31(string s) { int i; switch (s) { case "hello": i = 4; break; case "betty": i = 2; break; default: i = 3; break; } return i; } void test31() { static b = bar31("betty"); printf("b = %d, %d\n", b, bar31("betty")); assert(b == 2); } /************************************************/ int bar32(int i) { switch (i) { case 7: i = 4; goto case; case 5: i = 2; break; default: i = 3; break; } return i; } void test32() { static b = bar32(7); printf("b = %d, %d\n", b, bar32(7)); assert(b == 2); } /************************************************/ int bar33(int i) { switch (i) { case 5: i = 2; break; case 7: i = 4; goto case 5; default: i = 3; break; } return i; } void test33() { static b = bar33(7); printf("b = %d, %d\n", b, bar33(7)); assert(b == 2); } /************************************************/ int bar34(int i) { switch (i) { default: i = 3; break; case 5: i = 2; break; case 7: i = 4; goto default; } return i; } void test34() { static b = bar34(7); printf("b = %d, %d\n", b, bar34(7)); assert(b == 3); } /************************************************/ int bar35(int i) { L1: switch (i) { default: i = 3; break; case 5: i = 2; break; case 3: return 8; case 7: i = 4; goto default; } goto L1; } void test35() { static b = bar35(7); printf("b = %d, %d\n", b, bar35(7)); assert(b == 8); } /************************************************/ int square36(int x) { return x * x; } const int foo36 = square36(5); void test36() { assert(foo36 == 25); } /************************************************/ string someCompileTimeFunction() { return "writefln(\"Wowza!\");"; } void test37() { mixin(someCompileTimeFunction()); } /************************************************/ string NReps(string x, int n) { string ret = ""; for (int i = 0; i < n; i++) { ret ~= x; } return ret; } void test38() { static x = NReps("3", 6); assert(x == "333333"); } /************************************************/ bool func39() { return true; } static if (func39()) { pragma(msg, "true"); } else { pragma(msg, "false"); } void test39() { } /************************************************/ string UpToSpace(string x) { int i = 0; while (i < x.length && x[i] != ' ') { i++; } return x[0..i]; } void test40() { const y = UpToSpace("first space was after first"); writeln(y); assert(y == "first"); } /************************************************/ int bar41(ref int j) { return 5; } int foo41(int i) { int x; x = 3; bar41(x); return i + x; } void test41() { const y = foo41(3); writeln(y); assert(y == 6); } /************************************************/ int bar42(ref int j) { return 5; } int foo42(int i) { int x; x = 3; bar42(x); return i + x; } void test42() { const y = foo42(3); writeln(y); assert(y == 6); } /************************************************/ int bar(string a) { int v; for (int i = 0; i < a.length; i++) { if (a[i] != ' ') { v += a.length; } } return v; } void test43() { const int foo = bar("a b c d"); writeln(foo); assert(foo == 28); } /************************************************/ string foo44() { return ("bar"); } void test44() { const string bar = foo44(); assert(bar == "bar"); } /************************************************/ int square45(int n) { return (n * n); } void test45() { int bar = eval!(square45(5)); assert(bar == 25); } /************************************************/ const int foo46[5] = [0,1,2,3,4]; void test46() { writeln(eval!(foo46[3])); } /************************************************/ string foo47() { string s; s = s ~ 't'; return s ~ "foo"; } void test47() { static const x = foo47(); pragma(msg, x); assert(x == "tfoo"); } /************************************************/ string foo48() { string s; s = s ~ 't'; s = s.idup; return s ~ "foo"; } void test48() { static const x = foo48(); pragma(msg, x); assert(x == "tfoo"); } /************************************************/ dstring testd49(dstring input) { if (input[3..5] != "rt") { return input[1..3]; } return "my"; } void test49() { static x = testd49("hello"); writeln(x); assert(x == "el"); } /************************************************/ string makePostfix50(int x) { string first; first = "bad"; if (x) { first = "ok"; makePostfix50(0); } return first; } void test50() { static const char [] q2 = makePostfix50(1); static assert(q2 == "ok", q2); } /************************************************/ int exprLength(string s) { int numParens=0; for (int i = 0; i < s.length; ++i) { if (s[i] == '(') { numParens++; } if (s[i] == ')') { numParens--; } if (numParens == 0) { return i; } } assert(0); } string makePostfix51(string operations) { if (operations.length < 2) return "x"; int x = exprLength(operations); string first="bad"; if (x > 0) { first = "ok"; string ignore = makePostfix51(operations[1..x]); } return first; } void test51() { string q = makePostfix51("(a+b)*c"); assert(q == "ok"); static const string q2 = makePostfix51("(a+b)*c"); static assert(q2 == "ok"); static assert(makePostfix51("(a+b)*c") == "ok"); } /************************************************/ int foo52(ref int x) { x = 7; return 3; } int bar52(int y) { y = 4; foo52(y); return y; } void test52() { printf("%d\n", bar52(2)); static assert(bar52(2) == 7); } /************************************************/ void bar53(out int x) { x = 2; } int foo53() { int y; bar53(y); return y; } void test53() { const int z = foo53(); assert(z == 2); } /************************************************/ void test54() { static assert(equals54("alphabet", "alphabet")); } bool equals54(string a, string b) { return (a == b); } /************************************************/ const string foo55[2] = ["a", "b"]; string retsth55(int i) { return foo55[i]; } void test55() { writeln(eval!(foo55[0])); writeln(eval!(retsth55(0))); } /************************************************/ string retsth56(int i) { static const string foo[2] = ["a", "b"]; return foo[i]; } void test56() { writeln(eval!(retsth56(0))); } /************************************************/ int g57() { pragma(msg, "g"); return 2; } const int a57 = g57(); void test57() { assert(a57 == 2); } /************************************************/ int[] Fun58(int x) { int[] result; result ~= x + 1; return result; } void test58() { static b = Fun58(1) ~ Fun58(2); assert(b.length == 2); assert(b[0] == 2); assert(b[1] == 3); writeln(b); } /************************************************/ int Index59() { int[] data = [1]; return data[0]; } void test59() { static assert(Index59() == 1); } /************************************************/ string[int] foo60() { return [3:"hello", 4:"betty"]; } void test60() { static assert(foo60()[3] == "hello"); static assert(foo60()[4] == "betty"); } /************************************************/ string[int] foo61() { return [3:"hello", 4:"betty", 3:"world"]; } void test61() { static assert(foo61()[3] == "world"); static assert(foo61()[4] == "betty"); } /************************************************/ string foo62(int k) { string[int] aa; aa = [3:"hello", 4:"betty"]; return aa[k]; } void test62() { static assert(foo62(3) == "hello"); static assert(foo62(4) == "betty"); } /************************************************/ void test63() { static auto x = foo63(); } int foo63() { pragma(msg, "Crash!"); return 2; } /************************************************/ dstring testd64(dstring input) { debug int x = 10; return "my"; } void test64() { static x = testd64("hello"); } /************************************************/ struct S65 { int i; int j = 3; } int foo(S65 s1, S65 s2) { return s1 == s2; } void test65() { static assert(foo(S65(1, 5), S65(1, 5)) == 1); static assert(foo(S65(1, 5), S65(1, 4)) == 0); } /************************************************/ struct S66 { int i; int j = 3; } int foo66(S66 s1) { return s1.j; } void test66() { static assert(foo66(S66(1, 5)) == 5); } /************************************************/ struct S67 { int i; int j = 3; } int foo67(S67 s1) { s1.j = 3; int i = (s1.j += 2); assert(i == 5); return s1.j + 4; } void test67() { static assert(foo67(S67(1, 5)) == 9); } /************************************************/ int foo68(int[] a) { a[1] = 3; int x = (a[0] += 7); assert(x == 8); return a[0] + a[1]; } void test68() { static assert(foo68( [1,5] ) == 11); } /************************************************/ int foo69(char[] a) { a[1] = 'c'; char x = (a[0] += 7); assert(x == 'h'); assert(x == a[0]); return a[0] + a[1] - 'a'; } void test69() { static assert(foo69(['a', 'b']) == 'j'); } /************************************************/ int foo70(int[string] a) { a["world"] = 5; auto x = (a["hello"] += 7); assert(x == 10); assert(x == a["hello"]); return a["hello"] + a["betty"] + a["world"]; } void test70() { static assert(foo70(["hello":3, "betty":4]) == 19); } /************************************************/ size_t foo71(int[string] a) { return a.length; } void test71() { static assert(foo71(["hello":3, "betty":4]) == 2); } /************************************************/ string[] foo72(int[string] a) { return a.keys; } void test72() { static assert(foo72(["hello":3, "betty":4]) == ["hello", "betty"]); } /************************************************/ int[] foo73(int[string] a) { return a.values; } void test73() { static assert(foo73(["hello":3, "betty":4]) == [3, 4]); } /************************************************/ bool b74() { string a = "abc"; return (a[$-1] == 'c'); } const c74 = b74(); void test74() { assert(c74 == true); } /************************************************/ struct FormatSpec { uint leading; bool skip; uint width; char modifier; char format; uint formatStart; uint formatLength; uint length; } FormatSpec GetFormat(string s) { FormatSpec result; return result; } FormatSpec GetFormat2(string s) { FormatSpec result = FormatSpec(); result.length = 0; assert(result.length < s.length); while (result.length < s.length) { ++result.length; } return result; } void test75() { static FormatSpec spec = GetFormat("asd"); assert(spec.leading == 0); assert(spec.modifier == char.init); static FormatSpec spec2 = GetFormat2("asd"); assert(spec2.length == 3); } /************************************************/ int f76() { int[3] a = void; a[0] = 1; assert(a[0] == 1); return 1; } const i76 = f76(); void test76() { } /************************************************/ struct V77 { int a; int b; } V77 f77() { int q = 0; int unused; int unused2; return V77(q, 0); } void test77() { const w = f77(); const v = f77().b; } /************************************************/ struct Bar78 { int x; } int foo78() { Bar78 b = Bar78.init; Bar78 c; b.x = 1; b = bar(b); return b.x; } Bar78 bar(Bar78 b) { return b; } void test78() { static x = foo78(); } /************************************************/ struct Bar79 { int y,x; } int foo79() { Bar79 b = Bar79.init; b.x = 100; for (size_t i = 0; i < b.x; i++) { } b.x++; b.x = b.x + 1; return b.x; } void test79() { static x = foo79(); printf("x = %d\n", x); assert(x == 102); } /************************************************/ void test80() { } /************************************************/ string foo81() { return ""; } string rod81(string[] a) { return a[0]; } void test81() { static x = rod81([foo81(), ""]); assert(x == ""); } /************************************************/ struct S82 { string name; } const S82 item82 = {"item"}; string mixItemList82() { return item82.name; } const string s82 = mixItemList82(); void test82() { assert(s82 == "item"); } /************************************************/ struct S83 { string name; } const S83[] items83 = [ {"item"}, ]; string mixItemList83() { string s; foreach (item; items83) s ~= item.name; return s; } const string s83 = mixItemList83(); void test83() { writeln(s83); assert(s83 == "item"); } /************************************************/ struct S84 { int a; } int func84() { S84 [] s = [S84(7)]; return s[0].a; // Error: cannot evaluate func() at compile time } void test84() { const int x = func84(); assert(x == 7); } /************************************************/ struct S85 { int a; } size_t func85() { S85 [] s; s ~= S85(7); return s.length; } void test85() { const size_t x = func85(); assert(x == 1); } /************************************************/ struct Bar86 { int x; char[] s; } char[] foo86() { Bar86 bar; return bar.s; } void test86() { static x = foo86(); assert(x == null); } /************************************************/ struct Bar87 { int x; } int foo87() { Bar87 bar; bar.x += 1; bar.x++; return bar.x; } void test87() { static x = foo87(); assert(x == 2); } /************************************************/ int foo88() { char[] s; int i; if (s) { i |= 1; } if (s == null) { i |= 2; } if (s is null) { i |= 4; } if (s == "") { i |= 8; } if (s.length) { i |= 16; } if (s == ['c'][0..0]) { i |= 32; } if (null == s) { i |= 64; } if (null is s) { i |= 128; } if ("" == s) { i |= 256; } if (['c'][0..0] == s) { i |= 512; } return i; } void test88() { static x = foo88(); printf("x = %x\n", x); assert(x == (2|4|8|32|64|128|256|512)); } /************************************************/ template Tuple89(T...) { alias T val; } alias Tuple89!(int) Tup89; string gen89() { foreach (i, type; Tup89.val) { assert(i == 0); assert(is(type == int)); } return null; } void test89() { static const string text = gen89(); assert(text is null); } /************************************************/ string bar90(string z) { return z; } string foo90(string a, string b) { string f = a.length == 1 ? a: foo90("B", "C"); string g = b.length == 1 ? b: bar90(foo90("YYY", "A")); return f; } void test90() { static const string xxx = foo90("A", "xxx"); printf("%.*s\n", xxx.length, xxx.ptr); assert(xxx == "A"); } /************************************************/ struct PR91 { } int foo91() { PR91 pr; pr = PR91(); return 0; } void test91() { static const i = foo91(); } /************************************************/ char find92(immutable(char)[7] buf) { return buf[3]; } void test92() { static const pos = find92("abcdefg"); assert(pos == 'd'); } /************************************************/ static string hello93() { string result = ""; int i = 0; for (;;) { result ~= `abc`; i += 1; if (i == 3) break; } return result; } void test93() { static string s = hello93(); assert(s == "abcabcabc"); } /************************************************/ int foo94 (string[] list, string s) { if (list.length == 0) return 1; else { return 2 + foo94(list[1..$], list[0]); } } void test94() { printf("test94\n"); static const int x = foo94(["a", "b"], ""); assert(x == 5); } /************************************************/ char[] func95(immutable char[] s) { char[] u = "".dup; u ~= s; u = u ~ s; return u; } void test95() { mixin(func95(";")); } /************************************************/ char[] func96(string s) { char[] u = "".dup; u ~= s; u = u ~ s; return u; } void test96() { mixin(func96(";")); } /************************************************/ string foo97() { string a; a ~= "abc"; // ok string[] b; b ~= "abc"; // ok string[][] c; c ~= ["abc", "def"]; string[][] d = []; d ~= ["abc", "def"]; // ok return "abc"; } void test97() { static const xx97 = foo97(); } /************************************************/ immutable(int)[] foo98(immutable(int)[][] ss) { immutable(int)[] r; r ~= ss[0]; // problem here return r; } void test98() { const r = foo98([[1], [2]]); } /************************************************/ struct Number { public int value; static Number opCall(int value) { Number n = void; n.value = value; return n; } } class Crash { Number number = Number(0); } void test99() { } /************************************************/ int[] map100 = ([4:true, 5:true]).keys; bool[] foo100 = ([4:true, 5:true]).values; void test100() { } /************************************************/ int foo101() { immutable bool [int] map = [4:true, 5:true]; foreach (x; map.keys) {} return 3; } static int x101 = foo101(); void test101() { } /************************************************/ int foo102() { foreach (i; 0 .. 1) return 1; return 0; } static assert(foo102() == 1); int bar102() { foreach_reverse (i; 0 .. 1) return 1; return 0; } static assert(bar102() == 1); void test102() { } /************************************************/ int foo103() { foreach (c; '0' .. '9') { } foreach_reverse (c; '9' .. '0') { } return 0; } enum x103 = foo103(); void test103() { } /************************************************/ struct S { int x; char y; } // Functions which should fail CTFE int badfoo() { S[2] c; int w = 4; c[w].x = 6; // array bounds error return 7; } int badglobal = 1; int badfoo3() { S[2] c; c[badglobal].x = 6; // global index error return 7; } int badfoo4() { static S[2] c; c[0].x = 6; // Cannot access static return 7; } /+ // This doesn't compile at runtime int badfoo5() { S[] c = void; c[0].x = 6; // c is uninitialized, and not a static array. return 1; } +/ int badfoo6() { S[] b = [S(7), S(15), S(56), S(12)]; b[-2..4] = S(17); // exceeding (negative) array bounds return 1; } int badfoo7() { S[] b = [S(7), S(15), S(56), S(12), S(67)]; S[] c = [S(17), S(4)]; b[1..4] = c[]; // slice mismatch in dynamic array return 1; } int badfoo8() { S[] b; b[1..3] = [S(17), S(4)]; // slice assign to uninitialized dynamic array return 1; } template Compileable(int z) { bool OK = true;} static assert(!is(typeof(Compileable!(badfoo()).OK))); static assert(!is(typeof(Compileable!( (){ S[] c; return c[7].x; // uninitialized error }()).OK ))); static assert( is(typeof(Compileable!(0).OK))); static assert(!is(typeof(Compileable!(badfoo3()).OK))); static assert(!is(typeof(Compileable!(badfoo4()).OK))); //static assert(!is(typeof(Compileable!(badfoo5()).OK))); static assert(!is(typeof(Compileable!(badfoo6()).OK))); static assert(!is(typeof(Compileable!(badfoo7()).OK))); static assert(!is(typeof(Compileable!(badfoo8()).OK))); // Functions which should pass CTFE int goodfoo1() { int[8] w; // use static array in CTFE w[] = 7; // full slice assign w[$ - 1] = 538; // use of $ in index assignment assert(w[6] == 7); return w[7]; } static assert(goodfoo1() == 538); int goodfoo2() { S[4] w = S(101); // Block-initialize array of structs w[$ - 2].x = 917; // use $ in index member assignment w[$ - 2].y = 58; // this must not clobber the prev assignment return w[2].x; // check we got the correct one } static assert(goodfoo2() == 917); static assert(is(typeof(Compileable!( (){ S[4] w = void; // uninitialized array of structs w[$ - 2].x = 217; // initialize one member return w[2].x; }()).OK ))); int goodfoo4() { S[4] b = [S(7), S(15), S(56), S(12)]; // assign from array literal assert(b[3] == S(12)); return b[2].x - 55; } static assert(goodfoo4()==1); int goodfoo5() { S[4] b = [S(7), S(15), S(56), S(12)]; b[0..2] = [S(2), S(6)]; // slice assignment from array literal assert(b[3] == S(12)); assert(b[1] == S(6)); return b[0].x; } static assert(goodfoo5() == 2); static assert(goodfoo5() == 2); // check for memory corruption int goodfoo6() { S[6] b = void; b[2..5] = [S(2), S(6), S(17)]; // slice assign to uninitialized var assert(b[4] == S(17)); return b[3].x; } static assert(goodfoo6() == 6); int goodfoo7() { S[8] b = void; b[2..5] = S(217); // slice assign to uninitialized var assert(b[4] == S(217)); return b[3].x; } static assert(goodfoo7() == 217); int goodfoo8() { S[] b = [S(7), S(15), S(56), S(12), S(67)]; b[2..4] = S(17); // dynamic array block slice assign assert(b[3] == S(17)); assert(b[4] == S(67)); return b[0].x; } static assert(goodfoo8() == 7); // --------- CTFE MEMBER FUNCTION TESTS -------- struct Q { int x; char y; int opAddAssign(int w) { x += w; return x + w; } Q opSubAssign(int w) { x -= w; version(D_Version2) { mixin("return this;"); } else { mixin("return *this;"); } } int boo() { return 4; } int coo() { return x; } int foo() { return coo(); } int doo(int a) { Q z = Q(a, 'x'); z.x += 5; return z.coo() + 3 * x; } void goo(int z) { x = z; } int hoo(int y, int z) { return y + z; } void joo(int z) { x += z; } } int memtest1() { Q b = Q(15, 'a'); return b.hoo(3, 16); // simple const function } static assert(memtest1() == 19); int memtest2() { Q b = Q(15, 'x'); b.x -= 10; return b.coo(); } static assert(memtest2() == 5); int memtest3() { Q b = Q(15, 'x'); b.x -= 10; return b.foo(); } static assert(memtest3() == 5); int memtest4() { Q b = Q(12, 'x'); return b.doo(514); } static assert(memtest4() == 519 + 3 * 12); int memtest5() { Q b = Q(132, 'x'); b.goo(4178); // Call modifying member return b.x; } static assert(memtest5() == 4178); int memtest6() { Q q = Q(1); q += 3; // operator overloading return q.x; } static assert(memtest6() == 4); static assert(!is(typeof(Compileable!(Q += 2).OK))); // Mustn't cause segfault int memtest7() { Q q = Q(57); q -= 35; return q.x; } static assert(memtest7() == 57 - 35); int memtest8() { Q[3] w; w[2].x = 17; w[2].joo(6); // Modify member of array w[1].x += 18; return w[2].coo(); } static assert(memtest8() == 6 + 17); // --------- CTFE REF PASSING TESTS -------- // Bugzilla 1950 - CTFE doesn't work correctly for structs passed by ref struct S1950 { int x; } int foo1950() { S1950 s = S1950(5); // explicitly initialized bar1950(s); return s.x; } void bar1950(ref S1950 w) { w.x = 10; } static assert(foo1950() == 10); // OK <- Fails, x is 0 int foo1950b() { S1950 s; // uninitialized bar1950(s); return s.x; } static assert(foo1950b() == 10); // OK <- Fails, x is 0 // More extreme case, related to 1950 void bar1950c(ref int w) { w = 87; } int foo1950c() { int[5] x; x[] = 56; bar1950c(x[1]); // Non-trivial ref parameters return x[1]; } static assert(foo1950c() == 87); void bar1950d(ref int[] w) { w[1..$] = 87; w[0] += 15; } int foo1950d() { int[] x = [1, 2, 3, 4, 5]; x[1..$] = 56; bar1950d(x); // Non-trivial ref parameters assert(x[0] == 16); return x[1]; } static assert(foo1950d() == 87); // Nested functions int nested(int x) { int y = 3; int inner(int w) { int z = 2; ++z; y += w; return x + 3; } int z = inner(14); assert(y == 17); inner(8); assert(y == 17 + 8); return z + y; } static assert(nested(7) == 17 + 8 + 10); static assert(nested(7) == 17 + 8 + 10); // Recursive nested functions int nested2(int x) { int y = 3; int inner(int w) { int z = 2; ++z; ++y; if (w <= 1) return x + 3; else return inner(w - 1); } int z = inner(14); assert(y == 17); inner(8); assert(y == 17 + 8); return z + y; } static assert(nested2(7) == 17 + 8 + 10); // 1605 D1 & D2. break in switch with goto breaks in ctfe int bug1605() { int i = 0; while (true) { goto LABEL; LABEL: if (i != 0) return i; i = 27; } assert(i == 27); return 88; // unreachable } static assert(bug1605() == 27); // 2564. D2 only. CTFE: the index in a tuple foreach is uninitialized (bogus error) // NOTE: Beware of optimizer bug 3264. int bug2564() { version(D_Version2) { mixin("enum int Q = 0;"); }else {mixin("int Q = 0;"); } string [2] s = ["a", "b"]; assert(s[Q].dup == "a"); return 0; } static int bug2564b = bug2564(); // 1461 D1 + D2. Local variable as template alias parameter breaks CTFE void bug1461() { int x; static assert(Gen1461!(x).generate() == null); } template Gen1461(alias A) { string generate() { return null; } } /************************************************/ string foo104(string[] a...) { string result = ""; foreach (s; a) result ~= s; return result; } mixin (foo104("int ", "x;")); /************************************************/ struct SwineFlu { int a; int b; } struct Infection { SwineFlu y; } struct IveGotSwineFlu { Infection x; int z; int oink() { return x.y.a + 10; } } int quarantine() { IveGotSwineFlu d; return d.oink(); } struct Mexico { Infection x; int z = 2; int oink() { return z + x.y.b; } } int mediafrenzy() { Mexico m; return m.oink; } static assert(quarantine() == 10); static assert(mediafrenzy() == 2); /************************************************/ int ctfeArrayTest(int z) { int[] a = new int[z]; a[$ - 3] = 6; assert(a.length == z); return a[$ - 3]; } static assert(ctfeArrayTest(15) == 6); /************************************************/ char bugzilla1298() { char [4] q = "abcd".dup; char [4] r = ['a', 'b', 'c', 'd']; assert(q == r); q[0..2] = "xy"; q[2] += 3; return q[2]; } static assert(bugzilla1298() == 'f'); int bugzilla1790(Types...)() { foreach (T; Types) { ; } return 0; } const int bugs1790 = bugzilla1790!("")(); char ctfeStrTest1() { char [8] s = void; s[2..4] = 'x'; assert(s.length == 8); return s[3]; } static assert(ctfeStrTest1() == 'x'); //--------- DELEGATE TESTS ------ // Function + delegate literals inside CTFE int delegtest1() { assert(function int(int a){ return 7 + a; }(16) == 23); return delegate int(int a){ return 7 + a; }(6); } int delegtest2() { int innerfunc1() { return delegate int(int a){ return 7 + a; }(6); } int delegate() f = &innerfunc1; return 3 * f(); } int delegtest3() { int function() f = &delegtest1; return 3 * f(); } struct DelegStruct { int a; int bar(int x) { return a + x; } } int delegtest4() { DelegStruct s; s.a = 5; auto f = &s.bar; return f(3); } alias int delegate(int) DelegType; // Test arrays of delegates int delegtest5() { DelegStruct s; s.a = 5; DelegType[4] w; w[] = &s.bar; return w[2](3); } // Test arrays of structs of delegates struct FoolishStruct { DelegType z; } int delegtest6() { DelegStruct s; s.a = 5; FoolishStruct k[3]; DelegType u = &s.bar; k[1].z = u; return k[1].z(3); } static assert(delegtest1() == 13); static assert(delegtest2() == 39); static assert(delegtest3() == 39); static assert(delegtest4() == 8); static assert(delegtest5() == 8); static assert(delegtest6() == 8); // Function + delegate literals, module scope static assert(function int(int a){ return 17 + a; }(16) == 33); static assert( (int a){ return 7 + a; }(16) == 23); // --- Test lazy --- int lazyTest1(lazy int y) { return y + 1; } int lazyTest2(int x) { return lazyTest1(x); } static assert(lazyTest1(7) == 8); static assert(lazyTest2(17) == 18); /************************************************/ version(D_Version2) { // Bug 4020 and 4027 are D2 only struct PostblitCrash { int x; mixin("this(this) { ++x; }"); } int bug4020() { PostblitCrash f; f.x = 3; f = f; f = f; return f.x; } static assert(bug4020() == 5); string delegate() bug4027(string s) { return { return s; }; } // If it compiles, it must not generate wrong code on D2. static if (is(typeof((){ static const s = bug4027("aaa")(); }()))) { static assert(bug4027("aaa")() == "aaa"); static assert(bug4027("bbb")() == "bbb"); } } // --- void bug4004a(ref int a) { assert(a == 7); a += 3; } void bug4004b(ref int b) { b = 7; bug4004a(b); } int bug4004c() { int offset = 5; bug4004b(offset); return offset; } static assert(bug4004c() == 10); // --- int bug4019() { int[int] aa; aa[1] = 2; aa[4] = 6; return aa[1] + aa[4]; } static assert(bug4019() == 8); // --- string delegate() bug4029a() { return { return "abc"[]; }; } string bug4029() { return bug4029a()(); } static assert(bug4029() == "abc"); /************************************************/ int bug4078() { int[] arr = new int[1]; return arr[0]; } static assert(bug4078() == 0); int bug4052() { int[] arr = new int[1]; int s; foreach (x; arr) s += x; foreach (x; arr) s += x * x; return 4052; } static assert(bug4052() == 4052); int bug4252() { char [] s = "abc".dup; s[15] = 'd'; // Array bounds error return 3; } static assert(!is(typeof(Compileable!(bug4252())))); size_t setlen1() { int[] w = new int[4]; w[] = 7; w.length = 6; return 21 + w.length; } static assert(setlen1() == 27); size_t setlen2() { int[] w; w.length = 15; assert(w[3] == 0); w[2] = 8; w[14] = 7; w.length = 12; // check shrinking assert(w[2] == 8); return 2 + w.length; } static assert(setlen2() == 14); /************************************************/ int bug4257(ref int x) { return 3; } int bug4257c(int x) { return 3; } struct Struct4257 { int foo() { return 2; } } void bug4257b() { int y; static assert(!is(typeof(Compileable!(bug4257(y))))); static assert(!is(typeof(Compileable!(bug4257c(y))))); Struct4257 s; static assert(!is(typeof(Compileable!(s.foo())))); } /************************************************/ // 5117 static int dummy5117 = test5117(); int test5117() { S5117 s; s.change(); assert(s.value == 1); // (7) succeeds R5117 r; r.s.change(); assert(r.s.value == 1); // (11) fails, value == 0 return 0; } struct S5117 { int value; void change() { value = 1; } } struct R5117 { S5117 s; } /************************************************/ enum dummy5117b = test5117b(); int test5117b() { S5117b s; getRef5117b(s).change(); assert(s.value == 1); // fails, value == 0 return 0; } ref S5117b getRef5117b(ref S5117b s) { return s; } struct S5117b { int value; void change() { value = 1; } } /************************************************/ // 6439 struct A6439 { this(uint a, uint b) { begin = a; end = b; } union { struct { uint begin, end; } uint[2] arr; } } void test6439() { enum y = A6439(10, 20); A6439 y2 = A6439(10, 20); assert(y2.begin == y.begin && y2.end == y.end); //passes assert(y.arr != [0,0]); assert(y.arr == [10,20]); assert(y.arr == y2.arr); } /************************************************/ // from tests/fail_compilation/fail147 static assert(!is(typeof(Compileable!( (int i){ int x = void; ++x; // used before initialization return i + x; }(3) )))); // 6504 regression void test6504() { for (int i = 0; i < 3; ++i) { char[] x2 = "xxx" ~ ['c']; assert(x2[1] == 'x'); x2[1] = 'q'; } } // 8818 regression void test8818() { static bool test() { string op1 = "aa"; string op2 = "b"; assert("b" >= "aa"); assert(op2 >= op1); return true; } static assert(test()); assert(test()); } /************************************************/ struct Test104Node { int val; Test104Node* next; } Test104Node* CreateList(int[] arr) { if (!arr.length) return null; Test104Node* ret = new Test104Node; ret.val = arr[0]; ret.next = CreateList(arr[1..$]); return ret; } const(Test104Node)* root = CreateList([1, 2, 3, 4, 5]); void test104() { assert(root.val == 1); assert(root.next.val == 2); assert(root.next.next.val == 3); assert(root.next.next.next.val == 4); assert(root.next.next.next.next.val == 5); } /************************************************/ interface ITest105a { string test105a() const; } class Test105a : ITest105a { char a; int b; char c = 'C'; int d = 42; string test105a() const { return "test105a"; } } interface ITest105b { string test105b() const; } class Test105b : Test105a, ITest105b { char e; int f; this(char _e, int _f, char _a, int _b) pure { e = _e; f = _f; a = _a; b = _b; } string test105b() const { return "test105b"; } } const Test105b t105b = new Test105b('E', 88, 'A', 99); const Test105a t105a = new Test105b('E', 88, 'A', 99); const ITest105b t105ib = new Test105b('E', 88, 'A', 99); const ITest105a t105ia = new Test105b('E', 88, 'A', 99); __gshared Test105b t105gs = new Test105b('E', 88, 'A', 99); shared Test105b t105bs = new shared(Test105b)('E', 88, 'A', 99); immutable Test105b t105bi = new immutable(Test105b)('E', 88, 'A', 99); void test105() { assert(t105b.a == 'A'); assert(t105b.b == 99); assert(t105b.c == 'C'); assert(t105b.d == 42); assert(t105b.e == 'E'); assert(t105b.f == 88); assert(t105b.test105a() == "test105a"); assert(t105b.test105b() == "test105b"); assert(t105a.a == 'A'); assert(t105a.b == 99); assert(t105a.c == 'C'); assert(t105a.d == 42); assert(t105a.test105a() == "test105a"); assert(t105ia.test105a() == "test105a"); assert(t105ib.test105b() == "test105b"); assert(t105a.classinfo is Test105b.classinfo); //t105b.d = -1; //assert(t105b.d == -1); //assert(t105a.d == 42); assert(t105gs.a == 'A'); assert(t105gs.b == 99); assert(t105gs.c == 'C'); assert(t105gs.d == 42); assert(t105gs.e == 'E'); assert(t105gs.f == 88); assert(t105gs.test105a() == "test105a"); assert(t105gs.test105b() == "test105b"); assert(t105bs.a == 'A'); assert(t105bs.b == 99); assert(t105bs.c == 'C'); assert(t105bs.d == 42); assert(t105bs.e == 'E'); assert(t105bs.f == 88); assert(t105bi.a == 'A'); assert(t105bi.b == 99); assert(t105bi.c == 'C'); assert(t105bi.d == 42); assert(t105bi.e == 'E'); assert(t105bi.f == 88); assert(t105bi.test105a() == "test105a"); assert(t105bi.test105b() == "test105b"); } int bug9938() { assert(t105ia.test105a() == "test105a"); return 1; } static assert(t105ia.test105a() == "test105a"); static assert(bug9938()); /************************************************/ struct Test106 { Test106* f; Test106* s; } Test106* ctfe106() { auto s = new Test106; auto s2 = new Test106; s.f = s2; s.s = s2; assert(s.f is s.s); return s; } const(Test106)* t106 = ctfe106(); void test106() { assert(t106.f is t106.s); } /************************************************/ class Test107 { Test107 a; Test107 b; this() { } this(int) { a = new Test107(); b = a; assert(a is b); } } const Test107 t107 = new Test107(1); void test107() { assert(t107.a is t107.b); } /************************************************/ /* interface Getter { int getNum() const; } class Test108 : Getter { int f; this(int v) inout { f = v; } int getNum() const { return f; } } enum const(Test108) t108 = new Test108(38); void test108() { const Test108 obj = t108; assert(obj.classinfo is Test108.classinfo); assert(obj.f == 38); const Getter iobj = t108; assert(iobj.getNum() == 38); assert((cast(Object)iobj).classinfo is Test108.classinfo); assert(t108 is t108); } */ /***** Bug 5678 *********************************/ /* struct Bug5678 { this(int) {} } enum const(Bug5678)* b5678 = new const(Bug5678)(0); void test5678() { assert(b5678 is b5678); }*/ /************************************************/ class Test109C { this(){ this.c = this; } Test109C c; } const t109c = new Test109C(); struct Test109S { this(int){ this.s = &this; } Test109S* s; } const t109s = new Test109S(0); pragma(msg, t109s); // Make sure there is no infinite recursion. void test109() { assert(t109c.c is t109c); assert(t109s.s is t109s); } /************************************************/ struct Test110f { int f1; Test110s f2; } struct Test110s { this(int, int, int){} } auto test110 = [Test110f(1, Test110s(1, 2, 3))]; /************************************************/ // 6907 int test6907() { int dtor1; class C { ~this() { ++dtor1; } } // delete on Object { Object o; delete o; } { scope o = new Object(); } { Object o = new Object(); delete o; } // delete on C { C c; delete c; } { { scope c = new C(); } assert(dtor1 == 1); } { { scope Object o = new C(); } assert(dtor1 == 2); } { C c = new C(); delete c; assert(dtor1 == 3); } { Object o = new C(); delete o; assert(dtor1 == 4); } int dtor2; struct S1 { ~this() { ++dtor2; } } // delete on S1 { S1* p; delete p; } { S1* p = new S1(); delete p; assert(dtor2 == 1); } // delete on S1[] { S1[] a = [S1(), S1()]; delete a; assert(dtor2 == 3); } return 1; } static assert(test6907()); /************************************************/ // 9023 bool test9023() { string[][string] aas; assert(aas.length == 0); aas["a"] ~= "anything"; assert(aas.length == 1); assert(aas["a"] == ["anything"]); aas["a"] ~= "more"; assert(aas.length == 1); assert(aas["a"] == ["anything", "more"]); int[int] aan; assert(aan.length == 0); auto x = aan[0]++; assert(x == 0); assert(aan.length == 1); assert(aan[0] == 1); return true; } static assert(test9023()); /************************************************/ // 15817 S[] split15817(S)(S s) { size_t istart; S[] result; foreach (i, c ; s) result ~= s[istart .. i]; return result; } int test15817() { auto targets = `a1`.split15817; uint[string] counts; foreach (a; targets) counts[a]++; assert(counts == ["":1u, "a":1]); return 1; } static assert(test15817()); /************************************************/ interface IBug9954 { string foo() const; } class Bug9954 : IBug9954 { string foo() const { return "hello"; } } IBug9954 makeIBug9954() { return new Bug9954; } const IBug9954 b9954 = makeIBug9954(); void test9954() { assert(b9954.foo() == "hello"); } /************************************************/ // 10483 struct Bug10483 { int val[3][4]; } struct Outer10483 { Bug10483 p = Bug10483(67); } int k10483a = Outer10483.init.p.val[2][2]; // ICE(expression.c) void test10483() { int k10483b = Outer10483.init.p.val[2][2]; // Segfault (backend/type.c) } /************************************************/ struct S10669 { uint x; } static const S10669 iid0_10669 = S10669(0); class C10669 { static const S10669 iid1_10669 = S10669(1); }; const S10669 IID0_10669 = iid0_10669; const S10669 IID1_10669 = C10669.iid1_10669; /************************************************/ TypeInfo getTi() { return typeid(int); } auto t112 = getTi(); void test112() { assert(t112.toString() == "int"); } /************************************************/ // 10687 enum Foo10687 : uint { A, B, C, D, E } immutable uint[5][] m10687 = [[0, 1, 2, 3, 4]]; void test10687() { static immutable uint[5] a1 = [0, 1, 2, 3, 4]; auto a2 = cast(immutable(Foo10687[5]))a1; static a3 = cast(immutable(Foo10687[5]))a1; auto foos1 = cast(immutable(Foo10687[5][]))m10687; static foos2 = cast(immutable(Foo10687[5][]))m10687; } /************************************************/ void test113() { import core.math; static void compare(real a, real b) { writefln("compare(%30.30f, %30.30f);", a, b); assert(fabs(a - b) < 128 * real.epsilon); } static if (__traits(compiles, (){ enum real ctval1 = yl2x(3.14, 1); })) { enum real ctval1 = yl2x(3.14, 1); enum real ctval2 = yl2x(2e1500L, 3); enum real ctval3 = yl2x(1, 5); real rtval1 = yl2x(3.14, 1); real rtval2 = yl2x(2e1500L, 3); real rtval3 = yl2x(1, 5); compare(ctval1, rtval1); compare(ctval2, rtval2); compare(ctval3, rtval3); } static if (__traits(compiles, (){ enum real ctval4 = yl2xp1(3.14, 1); })) { enum real ctval4 = yl2xp1(3.14, 1); enum real ctval5 = yl2xp1(2e1500L, 3); enum real ctval6 = yl2xp1(1, 5); real rtval4 = yl2xp1(3.14, 1); real rtval5 = yl2xp1(2e1500L, 3); real rtval6 = yl2xp1(1, 5); compare(ctval4, rtval4); compare(ctval5, rtval5); compare(ctval6, rtval6); } } /************************************************/ // 14140 struct S14140 { union { float[3][1] A; float[3] flat; } this(in float[] args...) { flat[] = args[]; } } class C14140 { union { float[3][1] A; float[3] flat; } this(in float[] args...) { flat[] = args[]; } } immutable s14140 = S14140(0, 1, 0); const c14140 = new C14140(0, 1, 0); void test14140() { auto s = s14140; assert(s.flat == [0, 1, 0]); auto c = c14140; assert(c.flat == [0, 1, 0]); } /************************************************/ // 14862 struct S14862 { union { struct { uint hi, lo; } ulong data; } this(ulong data) { this.data = data; } } void test14862() { S14862 s14862 = S14862(123UL); enum S14862 e14862 = S14862(123UL); static S14862 g14862 = S14862(123UL); assert(s14862.data == 123UL); // OK assert(e14862.data == 123UL); // OK assert(g14862.data == 123UL); // OK <- fail } /************************************************/ // 15681 void test15681() { static struct A { float value; } static struct S { A[2] values; this(float) { values[0].value = 0; values[1].value = 1; } } auto s1 = S(1.0f); assert(s1.values[0].value == 0); // OK assert(s1.values[1].value == 1); // OK enum s2 = S(1.0f); static assert(s2.values[0].value == 0); // OK <- NG static assert(s2.values[1].value == 1); // OK assert(s2.values[0].value == 0); // OK <- NG assert(s2.values[1].value == 1); // OK } /************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test50(); test51(); test52(); test53(); test54(); test55(); test56(); test57(); test58(); test59(); test60(); test61(); test62(); test63(); test64(); test65(); test66(); test67(); test68(); test69(); test70(); test71(); test72(); test73(); test74(); test75(); test76(); test77(); test78(); test79(); test80(); test81(); test82(); test83(); test84(); test85(); test86(); test87(); test88(); test89(); test90(); test91(); test92(); test93(); test94(); test95(); test96(); test97(); test98(); test99(); test100(); test101(); test102(); test103(); test104(); test105(); test106(); test107(); //test108(); test109(); test112(); test113(); test6439(); test6504(); test8818(); test6907(); test9023(); test15817(); test9954(); test14140(); test14862(); test15681(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/opover2.d0000664000175000017500000012235612776215022021756 0ustar kaikai// PERMUTE_ARGS: -inline -O -property // Test operator overloading extern (C) int printf(const(char*) fmt, ...); template Seq(T...){ alias T Seq; } bool thrown(E, T)(lazy T val) { try { val(); return false; } catch (E e) { return true; } } void stompStack() { int[256] sa = 0xdeadbeef; } /**************************************/ class A { string opUnary(string s)() { printf("A.opUnary!(%.*s)\n", s.length, s.ptr); return s; } } void test1() { auto a = new A(); +a; -a; ~a; *a; ++a; --a; auto x = a++; assert(x == a); auto y = a--; assert(y == a); } /**************************************/ class A2 { T opCast(T)() { auto s = T.stringof; printf("A.opCast!(%.*s)\n", s.length, s.ptr); return T.init; } } void test2() { auto a = new A2(); auto x = cast(int)a; assert(x == 0); auto y = cast(char)a; assert(y == char.init); } /**************************************/ struct A3 { int opBinary(string s)(int i) { printf("A.opBinary!(%.*s)\n", s.length, s.ptr); return 0; } int opBinaryRight(string s)(int i) if (s == "/" || s == "*") { printf("A.opBinaryRight!(%.*s)\n", s.length, s.ptr); return 0; } T opCast(T)() { auto s = T.stringof; printf("A.opCast!(%.*s)\n", s.length, s.ptr); return T.init; } } void test3() { A3 a; a + 3; 4 * a; 4 / a; a & 5; } /**************************************/ struct A4 { int opUnary(string s)() { printf("A.opUnary!(%.*s)\n", s.length, s.ptr); return 0; } T opCast(T)() { auto s = T.stringof; printf("A.opCast!(%.*s)\n", s.length, s.ptr); return T.init; } } void test4() { A4 a; if (a) int x = 3; if (!a) int x = 3; if (!!a) int x = 3; } /**************************************/ class A5 { override bool opEquals(Object o) { printf("A.opEquals!(%p)\n", o); return 1; } int opUnary(string s)() { printf("A.opUnary!(%.*s)\n", s.length, s.ptr); return 0; } T opCast(T)() { auto s = T.stringof; printf("A.opCast!(%.*s)\n", s.length, s.ptr); return T.init; } } class B5 : A5 { override bool opEquals(Object o) { printf("B.opEquals!(%p)\n", o); return 1; } } void test5() { A5 a = new A5(); A5 a2 = new A5(); B5 b = new B5(); A n = null; if (a == a) int x = 3; if (a == a2) int x = 3; if (a == b) int x = 3; if (a == n) int x = 3; if (n == a) int x = 3; if (n == n) int x = 3; } /**************************************/ struct S6 { const bool opEquals(ref const S6 b) { printf("S.opEquals(S %p)\n", &b); return true; } const bool opEquals(ref const T6 b) { printf("S.opEquals(T %p)\n", &b); return true; } } struct T6 { const bool opEquals(ref const T6 b) { printf("T.opEquals(T %p)\n", &b); return true; } /+ const bool opEquals(ref const S6 b) { printf("T.opEquals(S %p)\n", &b); return true; } +/ } void test6() { S6 s1; S6 s2; if (s1 == s2) int x = 3; T6 t; if (s1 == t) int x = 3; if (t == s2) int x = 3; } /**************************************/ struct S7 { const int opCmp(ref const S7 b) { printf("S.opCmp(S %p)\n", &b); return -1; } const int opCmp(ref const T7 b) { printf("S.opCmp(T %p)\n", &b); return -1; } } struct T7 { const int opCmp(ref const T7 b) { printf("T.opCmp(T %p)\n", &b); return -1; } /+ const int opCmp(ref const S7 b) { printf("T.opCmp(S %p)\n", &b); return -1; } +/ } void test7() { S7 s1; S7 s2; if (s1 < s2) int x = 3; T7 t; if (s1 < t) int x = 3; if (t < s2) int x = 3; } /**************************************/ struct A8 { int opUnary(string s)() { printf("A.opUnary!(%.*s)\n", s.length, s.ptr); return 0; } int opIndexUnary(string s, T)(T i) { printf("A.opIndexUnary!(%.*s)(%d)\n", s.length, s.ptr, i); return 0; } int opIndexUnary(string s, T)(T i, T j) { printf("A.opIndexUnary!(%.*s)(%d, %d)\n", s.length, s.ptr, i, j); return 0; } int opSliceUnary(string s)() { printf("A.opSliceUnary!(%.*s)()\n", s.length, s.ptr); return 0; } int opSliceUnary(string s, T)(T i, T j) { printf("A.opSliceUnary!(%.*s)(%d, %d)\n", s.length, s.ptr, i, j); return 0; } } void test8() { A8 a; -a; -a[3]; -a[3, 4]; -a[]; -a[5 .. 6]; --a[3]; } /**************************************/ struct A9 { int opOpAssign(string s)(int i) { printf("A.opOpAssign!(%.*s)\n", s.length, s.ptr); return 0; } int opIndexOpAssign(string s, T)(int v, T i) { printf("A.opIndexOpAssign!(%.*s)(%d, %d)\n", s.length, s.ptr, v, i); return 0; } int opIndexOpAssign(string s, T)(int v, T i, T j) { printf("A.opIndexOpAssign!(%.*s)(%d, %d, %d)\n", s.length, s.ptr, v, i, j); return 0; } int opSliceOpAssign(string s)(int v) { printf("A.opSliceOpAssign!(%.*s)(%d)\n", s.length, s.ptr, v); return 0; } int opSliceOpAssign(string s, T)(int v, T i, T j) { printf("A.opSliceOpAssign!(%.*s)(%d, %d, %d)\n", s.length, s.ptr, v, i, j); return 0; } } void test9() { A9 a; a += 8; a -= 8; a *= 8; a /= 8; a %= 8; a &= 8; a |= 8; a ^= 8; a <<= 8; a >>= 8; a >>>= 8; a ~= 8; a ^^= 8; a[3] += 8; a[3] -= 8; a[3] *= 8; a[3] /= 8; a[3] %= 8; a[3] &= 8; a[3] |= 8; a[3] ^= 8; a[3] <<= 8; a[3] >>= 8; a[3] >>>= 8; a[3] ~= 8; a[3] ^^= 8; a[3, 4] += 8; a[] += 8; a[5 .. 6] += 8; } /**************************************/ struct BigInt { int opEquals(T)(T n) const { return 1; } int opEquals(T:int)(T n) const { return 1; } int opEquals(T:const(BigInt))(T n) const { return 1; } } int decimal(BigInt b, const BigInt c) { while (b != c) { } return 1; } /**************************************/ struct Foo10 { int opUnary(string op)() { return 1; } } void test10() { Foo10 foo; foo++; } /**************************************/ struct S4913 { bool opCast(T : bool)() { return true; } } int bug4913() { if (S4913 s = S4913()) { return 83; } return 9; } static assert(bug4913() == 83); /**************************************/ // 5551 struct Foo11 { Foo11 opUnary(string op:"++")() { return this; } Foo11 opBinary(string op)(int y) { return this; } } void test11() { auto f = Foo11(); f++; } /**************************************/ // 4099 struct X4099 { int x; alias x this; typeof(this) opUnary (string operator) () { printf("operator called\n"); return this; } } void test4099() { X4099 x; X4099 r1 = ++x; //operator called X4099 r2 = x++; //BUG! (alias this used. returns int) } /**************************************/ void test12() { static int opeq; // xopEquals OK static struct S1a { const bool opEquals( const typeof(this) rhs) { ++opeq; return false; } } static struct S1b { const bool opEquals(ref const typeof(this) rhs) { ++opeq; return false; } } static struct S1c { const bool opEquals( typeof(this) rhs) { ++opeq; return false; } } // xopEquals NG static struct S2a { bool opEquals( typeof(this) rhs) { ++opeq; return false; } } foreach (S; Seq!(S1a, S1b, S1c)) { S s; opeq = 0; assert(s != s); // call opEquals directly assert(!typeid(S).equals(&s, &s)); // -> xopEquals (-> __xopEquals) -> opEquals assert(opeq == 2); } foreach (S; Seq!(S2a)) { S s; opeq = 0; assert(s != s); assert(thrown!Error(!typeid(S).equals(&s, &s))); // Error("notImplemented") thrown assert(opeq == 1); } } /**************************************/ void test13() { static int opeq; struct X { const bool opEquals(const X){ ++opeq; return false; } } struct S { X x; } S makeS(){ return S(); } S s; opeq = 0; assert(s != s); assert(makeS() != s); assert(s != makeS()); assert(makeS() != makeS()); assert(opeq == 4); // built-in opEquals == const bool opEquals(const S rhs); assert(s != s); assert(opeq == 5); // xopEquals assert(!typeid(S).equals(&s, &s)); assert(opeq == 6); } /**************************************/ void test14() { static int opeq; struct S { const bool opEquals(T)(const T rhs) { ++opeq; return false; } } S makeS(){ return S(); } S s; opeq = 0; assert(s != s); assert(makeS() != s); assert(s != makeS()); assert(makeS() != makeS()); assert(opeq == 4); // xopEquals (-> __xxopEquals) -> template opEquals assert(!typeid(S).equals(&s, &s)); assert(opeq == 5); } /**************************************/ void test15() { struct S { const bool opEquals(T)(const(T) rhs) if (!is(T == S)) { return false; } @disable const bool opEquals(T)(const(T) rhs) if (is(T == S)) { return false; } } S makeS(){ return S(); } S s; static assert(!__traits(compiles, s != s)); static assert(!__traits(compiles, makeS() != s)); static assert(!__traits(compiles, s != makeS())); static assert(!__traits(compiles, makeS() != makeS())); // xopEquals (-> __xxopEquals) -> Error thrown assert(thrown!Error(!typeid(S).equals(&s, &s))); } /**************************************/ void test16() { struct X { int n; const bool opEquals(T)(T t) { return false; } } struct S { X x; } S s1, s2; assert(s1 != s2); // field template opEquals should call } /**************************************/ void test17() { static int opeq = 0; struct S { bool opEquals(ref S rhs) { ++opeq; return false; } } S[] sa1 = new S[3]; S[] sa2 = new S[3]; assert(sa1 != sa2); // isn't used TypeInfo.equals assert(opeq == 1); const(S)[] csa = new const(S)[3]; static assert(!__traits(compiles, csa == sa1)); static assert(!__traits(compiles, sa1 == csa)); static assert(!__traits(compiles, csa == csa)); } /**************************************/ // 3789 bool test3789() { static struct Float { double x; } Float f; assert(f.x != f.x); // NaN != NaN assert(f != f); static struct Array { int[] x; } Array a1 = Array([1,2,3].dup); Array a2 = Array([1,2,3].dup); if (!__ctfe) { // Currently doesn't work this in CTFE - may or may not a bug. assert(a1.x !is a2.x); } assert(a1.x == a2.x); assert(a1 == a2); static struct AA { int[int] x; } AA aa1 = AA([1:1,2:2,3:3]); AA aa2 = AA([1:1,2:2,3:3]); if (!__ctfe) { // Currently doesn't work this in CTFE - may or may not a bug. assert(aa1.x !is aa2.x); } if (!__ctfe) { // This is definitely a bug. Should work in CTFE. assert(aa1.x == aa2.x); assert(aa1 == aa2); } if (!__ctfe) { // Currently union operation is not supported in CTFE. union U1 { double x; } static struct UnionA { int[] a; U1 u; } auto ua1 = UnionA([1,2,3]); auto ua2 = UnionA([1,2,3]); assert(ua1.u.x is ua2.u.x); assert(ua1.u.x != ua2.u.x); assert(ua1 == ua2); ua1.u.x = 1.0; ua2.u.x = 1.0; assert(ua1.u.x is ua2.u.x); assert(ua1.u.x == ua2.u.x); assert(ua1 == ua2); ua1.u.x = double.nan; assert(ua1.u.x !is ua2.u.x); assert(ua1.u.x != ua2.u.x); assert(ua1 != ua2); union U2 { int[] a; } static struct UnionB { double x; U2 u; } auto ub1 = UnionB(1.0); auto ub2 = UnionB(1.0); assert(ub1 == ub2); ub1.u.a = [1,2,3].dup; ub2.u.a = [1,2,3].dup; assert(ub1.u.a !is ub2.u.a); assert(ub1.u.a == ub2.u.a); assert(ub1 != ub2); ub2.u.a = ub1.u.a; assert(ub1.u.a is ub2.u.a); assert(ub1.u.a == ub2.u.a); assert(ub1 == ub2); } if (!__ctfe) { // This is definitely a bug. Should work in CTFE. static struct Class { Object x; } static class X { override bool opEquals(Object o){ return true; } } Class c1a = Class(new Object()); Class c2a = Class(new Object()); assert(c1a.x !is c2a.x); assert(c1a.x != c2a.x); assert(c1a != c2a); // Pass, Object.opEquals works like bitwise compare Class c1b = Class(new X()); Class c2b = Class(new X()); assert(c1b.x !is c2b.x); assert(c1b.x == c2b.x); assert(c1b == c2b); // Fails, should pass } return true; } static assert(test3789()); /**************************************/ // 10037 struct S10037 { bool opEquals(ref const S10037) { assert(0); } } struct T10037 { S10037 s; // Compiler should not generate 'opEquals' here implicitly: } struct Sub10037(TL...) { TL data; int value; alias value this; } void test10037() { S10037 s; T10037 t; static assert( __traits(hasMember, S10037, "opEquals")); static assert(!__traits(hasMember, T10037, "opEquals")); assert(thrown!Error(s == s)); assert(thrown!Error(t == t)); Sub10037!(S10037) lhs; Sub10037!(S10037) rhs; static assert(!__traits(hasMember, Sub10037!(S10037), "opEquals")); assert(lhs == rhs); // lowered to: lhs.value == rhs.value } /**************************************/ // 5810 struct Bug5810 { void opUnary(string op)() {} } struct Foo5810 { Bug5810 x; void bar() { x++; } } /**************************************/ // 6798 struct Tuple6798(T...) { T field; alias field this; bool opEquals(Tuple6798 rhs) { foreach (i, _; T) { if (this[i] != rhs[i]) return false; } return true; } } auto tuple6798(T...)(T args) { return Tuple6798!T(args); } int test6798a() { //import std.typecons; alias tuple6798 tuple; static struct S1 { auto opDollar(size_t dim)() { return 99; } auto opSlice(int dim)(int lwr, int upr) { return [dim, lwr, upr]; } auto opIndex(A...)(A indices) { return tuple(" []", indices); } auto opIndexUnary(string op, A...)(A indices) { return tuple(op~"[]", indices); } auto opIndexAssign(A...)(string s, A indices) { return tuple("[] =", s, indices); } auto opIndexOpAssign(string op, A...)(string s, A indices) { return tuple("[]"~op~"=", s, indices); } } S1 s1; assert( s1[] == tuple(" []")); assert( s1[10] == tuple(" []", 10)); assert( s1[10, 20] == tuple(" []", 10, 20)); assert( s1[10..20] == tuple(" []", [0, 10, 20])); assert(+s1[] == tuple("+[]")); assert(-s1[10] == tuple("-[]", 10)); assert(*s1[10, 20] == tuple("*[]", 10, 20)); assert(~s1[10..20] == tuple("~[]", [0, 10, 20])); assert((s1[] ="x") == tuple("[] =", "x")); assert((s1[10] ="x") == tuple("[] =", "x", 10)); assert((s1[10, 20] ="x") == tuple("[] =", "x", 10, 20)); assert((s1[10..20] ="x") == tuple("[] =", "x", [0, 10, 20])); assert((s1[] +="x") == tuple("[]+=", "x")); assert((s1[10] -="x") == tuple("[]-=", "x", 10)); assert((s1[10, 20]*="x") == tuple("[]*=", "x", 10, 20)); assert((s1[10..20]~="x") == tuple("[]~=", "x", [0, 10, 20])); assert( s1[20..30, 10] == tuple(" []", [0, 20, 30], 10)); assert( s1[10, 10..$, $-4, $..2] == tuple(" []", 10, [1,10,99], 99-4, [3,99,2])); assert(+s1[20..30, 10] == tuple("+[]", [0, 20, 30], 10)); assert(-s1[10, 10..$, $-4, $..2] == tuple("-[]", 10, [1,10,99], 99-4, [3,99,2])); assert((s1[20..30, 10] ="x") == tuple("[] =", "x", [0, 20, 30], 10)); assert((s1[10, 10..$, $-4, $..2] ="x") == tuple("[] =", "x", 10, [1,10,99], 99-4, [3,99,2])); assert((s1[20..30, 10] +="x") == tuple("[]+=", "x", [0, 20, 30], 10)); assert((s1[10, 10..$, $-4, $..2]-="x") == tuple("[]-=", "x", 10, [1,10,99], 99-4, [3,99,2])); // opIndex exist, but opSlice for multi-dimensional doesn't. static struct S2 { auto opSlice(size_t dim)() { return [dim]; } auto opSlice()(size_t lwr, size_t upr) { return [lwr, upr]; } auto opIndex(A...)(A indices){ return [[indices]]; } } S2 s2; assert(s2[] == [[]]); assert(s2[1] == [[1]]); assert(s2[1, 2] == [[1, 2]]); assert(s2[1..2] == [1, 2]); static assert(!__traits(compiles, s2[1, 2..3] )); static assert(!__traits(compiles, s2[1..2, 2..3] )); // opSlice for multi-dimensional exists, but opIndex for that doesn't. static struct S3 { auto opSlice(size_t dim)(size_t lwr, size_t upr) { return [lwr, upr]; } auto opIndex(size_t n){ return [[n]]; } auto opIndex(size_t n, size_t m){ return [[n, m]]; } } S3 s3; static assert(!__traits(compiles, s3[] )); assert(s3[1] == [[1]]); assert(s3[1, 2] == [[1, 2]]); static assert(!__traits(compiles, s3[1..2] )); static assert(!__traits(compiles, s3[1, 2..3] )); static assert(!__traits(compiles, s3[1..2, 2..3] )); return 0; } int test6798b() { static struct Typedef(T) { private T Typedef_payload = T.init; alias a = Typedef_payload; auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; } auto ref opSlice(this X )() { return a[]; } auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) { assert(b == 0 && e == 3); return a[b..e]; } template opDispatch(string name) { // field or property function @property auto ref opDispatch(this X)() { return mixin("a."~name); } @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); } } static if (is(typeof(a) : E[], E)) { auto opDollar() const { return a.length; } } } Typedef!(int[]) dollar2; dollar2.length = 3; assert(dollar2.Typedef_payload.length == 3); assert(dollar2[0 .. $] is dollar2[0 .. 3]); return 0; } int test6798c() { alias T = Tuple6798!(int, int); auto n = T[].init; static assert(is(typeof(n[0]) == Tuple6798!(int, int))); return 0; } void test6798() { static assert(test6798a() == 0); // CTFE check test6798a(); static assert(test6798b() == 0); test6798b(); static assert(test6798c() == 0); test6798c(); } /**************************************/ // 12382 struct S12382 { size_t opDollar() { return 0; } size_t opIndex(size_t) { return 0; } } S12382 func12382() { return S12382(); } static assert(S12382.init[$] == 0); static assert(func12382()[$] == 0); enum e12382a = S12382.init[$]; enum e12382b = func12382()[$]; static v12382a = S12382.init[$]; static v12382b = func12382()[$]; void test12382() { static assert(S12382.init[$] == 0); static assert(func12382()[$] == 0); enum e12382a = S12382.init[$]; enum e12382b = func12382()[$]; static v12382a = S12382.init[$]; static v12382b = func12382()[$]; } /**************************************/ // 12904 struct S12904 { void opIndexAssign(U, A...)(U value, A args) { static assert(0); } void opSliceAssign(int n) { assert(n == 10); } size_t opDollar(size_t dim)() { return 7; } int opSlice(size_t dim)(size_t, size_t to) { assert(to == 7); return 1; } int opIndex(int i1, int i2) { assert(i1 == 1 && i2 == 1); return 10; } } void test12904() { S12904 s; s[] = s[0..$, 1]; s[] = s[0..$, 0..$]; } /**************************************/ // 7641 mixin template Proxy7641(alias a) { auto ref opBinaryRight(string op, B)(auto ref B b) { return mixin("b "~op~" a"); } } struct Typedef7641(T) { private T Typedef_payload; this(T init) { Typedef_payload = init; } mixin Proxy7641!Typedef_payload; } void test7641() { class C {} C c1 = new C(); auto a = Typedef7641!C(c1); static assert(!__traits(compiles, { C c2 = a; })); } /**************************************/ // 8434 void test8434() { static class Vector2D(T) { T x, y; this(T x, T y) { this.x = x; this.y = y; } U opCast(U)() const { assert(0); } } alias Vector2D!(short) Vector2s; alias Vector2D!(float) Vector2f; Vector2s vs1 = new Vector2s(42, 23); Vector2s vs2 = new Vector2s(42, 23); assert(vs1 != vs2); } /**************************************/ void test18() { // one dimensional indexing static struct IndexExp { int[] opIndex(int a) { return [a]; } int[] opIndexUnary(string op)(int a) { return [a]; } int[] opIndexAssign(int val, int a) { return [val, a]; } int[] opIndexOpAssign(string op)(int val, int a) { return [val, a]; } int opDollar() { return 8; } } IndexExp index; // opIndex assert(index[8] == [8]); assert(index[$] == [8]); assert(index[$-1] == [7]); assert(index[$-$/2] == [4]); // opIndexUnary assert(-index[8] == [8]); assert(-index[$] == [8]); assert(-index[$-1] == [7]); assert(-index[$-$/2] == [4]); // opIndexAssign assert((index[8] = 2) == [2, 8]); assert((index[$] = 2) == [2, 8]); assert((index[$-1] = 2) == [2, 7]); assert((index[$-$/2] = 2) == [2, 4]); // opIndexOpAssign assert((index[8] += 2) == [2, 8]); assert((index[$] += 2) == [2, 8]); assert((index[$-1] += 2) == [2, 7]); assert((index[$-$/2] += 2) == [2, 4]); // opDollar is only one-dimensional static assert(!is(typeof(index[$, $]))); static assert(!is(typeof(-index[$, $]))); static assert(!is(typeof(index[$, $] = 2))); static assert(!is(typeof(index[$, $] += 2))); // multi dimensional indexing static struct ArrayExp { int[] opIndex(int a, int b) { return [a, b]; } int[] opIndexUnary(string op)(int a, int b) { return [a, b]; } int[] opIndexAssign(int val, int a, int b) { return [val, a, b]; } int[] opIndexOpAssign(string op)(int val, int a, int b) { return [val, a, b]; } int opDollar(int dim)() { return dim; } } ArrayExp array; // opIndex assert(array[8, 8] == [8, 8]); assert(array[$, $] == [0, 1]); assert(array[$, $-1] == [0, 0]); assert(array[2, $-$/2] == [2, 1]); // opIndexUnary assert(-array[8, 8] == [8, 8]); assert(-array[$, $] == [0, 1]); assert(-array[$, $-1] == [0, 0]); assert(-array[2, $-$/2] == [2, 1]); // opIndexAssign assert((array[8, 8] = 2) == [2, 8, 8]); assert((array[$, $] = 2) == [2, 0, 1]); assert((array[$, $-1] = 2) == [2, 0, 0]); assert((array[2, $-$/2] = 2) == [2, 2, 1]); // opIndexOpAssign assert((array[8, 8] += 2) == [2, 8, 8]); assert((array[$, $] += 2) == [2, 0, 1]); assert((array[$, $-1] += 2) == [2, 0, 0]); assert((array[2, $-$/2] += 2) == [2, 2, 1]); // one dimensional slicing static struct SliceExp { int[] opSlice(int a, int b) { return [a, b]; } int[] opSliceUnary(string op)(int a, int b) { return [a, b]; } int[] opSliceAssign(int val, int a, int b) { return [val, a, b]; } int[] opSliceOpAssign(string op)(int val, int a, int b) { return [val, a, b]; } int opDollar() { return 8; } } SliceExp slice; // opSlice assert(slice[0 .. 8] == [0, 8]); assert(slice[0 .. $] == [0, 8]); assert(slice[0 .. $-1] == [0, 7]); assert(slice[$-3 .. $-1] == [5, 7]); // opSliceUnary assert(-slice[0 .. 8] == [0, 8]); assert(-slice[0 .. $] == [0, 8]); assert(-slice[0 .. $-1] == [0, 7]); assert(-slice[$-3 .. $-1] == [5, 7]); // opSliceAssign assert((slice[0 .. 8] = 2) == [2, 0, 8]); assert((slice[0 .. $] = 2) == [2, 0, 8]); assert((slice[0 .. $-1] = 2) == [2, 0, 7]); assert((slice[$-3 .. $-1] = 2) == [2, 5, 7]); // opSliceOpAssign assert((slice[0 .. 8] += 2) == [2, 0, 8]); assert((slice[0 .. $] += 2) == [2, 0, 8]); assert((slice[0 .. $-1] += 2) == [2, 0, 7]); assert((slice[$-3 .. $-1] += 2) == [2, 5, 7]); // test different kinds of opDollar auto dollar(string opDollar)() { static struct Dollar { size_t opIndex(size_t a) { return a; } mixin(opDollar); } Dollar d; return d[$]; } assert(dollar!q{@property size_t opDollar() { return 8; }}() == 8); assert(dollar!q{template opDollar(size_t dim) { enum opDollar = dim; }}() == 0); assert(dollar!q{static const size_t opDollar = 8;}() == 8); assert(dollar!q{enum opDollar = 8;}() == 8); assert(dollar!q{size_t length() { return 8; } alias length opDollar;}() == 8); } /**************************************/ void test19() { static struct Foo { int[] opSlice(int a, int b) { return [a, b]; } int opDollar(int dim)() { return dim; } } Foo foo; assert(foo[0 .. $] == [0, 0]); } /**************************************/ // 9453 struct Foo9453 { static int ctor = 0; this(string bar) { ++ctor; } void opIndex(size_t i) const {} void opSlice(size_t s, size_t e) const {} size_t opDollar(int dim)() const if (dim == 0) { return 1; } } void test9453() { assert(Foo9453.ctor == 0); Foo9453("bar")[$-1]; assert(Foo9453.ctor == 1); Foo9453("bar")[0..$]; assert(Foo9453.ctor == 2); } /**************************************/ // 9496 struct S9496 { static S9496* ptr; size_t opDollar() { assert(ptr is &this); return 10; } void opSlice(size_t , size_t) { assert(ptr is &this); } void getSlice() { assert(ptr is &this); this[1 .. opDollar()]; this[1 .. $]; } } void test9496() { S9496 s; S9496.ptr = &s; s.getSlice(); s[1 .. $]; } /**************************************/ // 9689 struct B9689(T) { T val; @disable this(this); bool opEquals(this X, B)(auto ref B b) { //pragma(msg, "+", X, ", B = ", B, ", ref = ", __traits(isRef, b)); return this.val == b.val; //pragma(msg, "-", X, ", B = ", B, ", ref = ", __traits(isRef, b)); } } struct S9689 { B9689!int num; } void test9689() { B9689!S9689 b; } /**************************************/ // 9694 struct S9694 { bool opEquals(ref S9694 rhs) { assert(0); } } struct T9694 { S9694 s; } void test9694() { T9694 t; assert(thrown!Error(typeid(T9694).equals(&t, &t))); } /**************************************/ // 10064 void test10064() { static struct S { int x = 3; @disable this(); this(int) { x = 7; } int opSlice(size_t, size_t) { return 0; } @property size_t opDollar() { assert(x == 7 || x == 3); // fails assert(x == 7); return 0; } } auto x = S(0)[0 .. $]; } /**************************************/ // 12585 void test12585() { struct Bar { int opIndex(size_t index) { return 0; } } struct Foo { Bar opIndex(size_t index) { throw new Exception("Fail"); } } Foo foo() { return Foo(); } void catchStuff(E)(lazy E expression) { try expression(); catch (Exception e) {} } catchStuff(foo()[0][0]); // OK <- NG catchStuff(foo().opIndex(0)[0]); // OK catchStuff(foo()[0].opIndex(0)); // OK Foo f; catchStuff(f[0][0]); // OK } /**************************************/ // 10394 void test10394() { alias Seq!(int, int) Pair; Pair pair; struct S1 { int opBinary(string op)(Pair) { return 1; } bool opEquals(Pair) { return true; } int opOpAssign(string op)(Pair) { return 1; } } S1 s1; assert((s1 + pair) == 1); assert((s1 == pair) == true); assert((s1 *= pair) == 1); struct S2 { int opBinaryRight(string op)(Pair lhs) { return 1; } int opCmp(Pair) { return -1; } } S2 s2; assert((pair in s2) == 1); assert(s2 < pair); } /**************************************/ // 10597 struct R10597 { void opIndex(int) {} void opSlice(int, int) {} int opDollar(); } R10597 r; struct S10597 { static assert(is(typeof(r[0]))); //ok static assert(is(typeof(r[$]))); //fails static assert(is(typeof(r[0..0]))); //ok static assert(is(typeof(r[$..$]))); //fails void foo() { static assert(is(typeof(r[0]))); //ok static assert(is(typeof(r[$]))); //ok static assert(is(typeof(r[0..0]))); //ok static assert(is(typeof(r[$..$]))); //ok } } static assert(is(typeof(r[0]))); //ok static assert(is(typeof(r[$]))); //fails static assert(is(typeof(r[0..0]))); //ok static assert(is(typeof(r[$..$]))); //fails void test10597() { static assert(is(typeof(r[0]))); //ok static assert(is(typeof(r[$]))); //ok static assert(is(typeof(r[0..0]))); //ok static assert(is(typeof(r[$..$]))); //ok } /**************************************/ // 10567 // doesn't require thunk struct S10567x1n { int value; int opCmp(ref const S10567x1n rhs) const { return 0; } } // requires thunk struct S10567y1n { int value; int opCmp(const S10567y1n rhs) const { return 0; } } struct S10567y1t { int value; int opCmp(S)(const S rhs) const { return 0; } } // doesn't support const comparison struct S10567z1n { int value; int opCmp(const S10567z1n rhs) { return 0; } } struct S10567z1t { int value; int opCmp(S)(const S rhs) { return 0; } } /+ struct S10567x2n { S10567x1n s; this(int n) { s = typeof(s)(n); } alias s this; } struct S10567y2n { S10567y1n s; this(int n) { s = typeof(s)(n); } alias s this; } struct S10567y2t { S10567y1t s; this(int n) { s = typeof(s)(n); } alias s this; } struct S10567z2n { S10567z1n s; this(int n) { s = typeof(s)(n); } alias s this; } struct S10567z2t { S10567z1t s; this(int n) { s = typeof(s)(n); } alias s this; } struct S10567d1 { int value; int opDispatch(string name, S)(const S rhs) const if (name == "opCmp") { assert(0); } } struct S10567d2 { int value; template opDispatch(string name) if (name == "opCmp") { int opDispatch(const S rhs) const { assert(0); } } } // recursive alias this + opCmp searching struct S10567r1 { static S10567r2 t; ref S10567r2 payload() { return t; } alias payload this; int opCmp(const S10567r1 s) const { return 0; } } struct S10567r2 { static S10567r1 s; ref S10567r1 payload() { return s; } alias payload this; } +/ void test10567() { foreach (S; Seq!(S10567x1n/+, S10567x2n+/)) { S sx = S(1); S sy = S(2); assert(!(sx < sy) && !(sx > sy)); assert(sx.opCmp(sy) == 0); assert(typeid(S).compare(&sx, &sy) == 0); static if (is(S == S10567x1n)) assert(cast(void*)typeid(S).xopCmp == cast(void*)&S.opCmp, S.stringof); } foreach (S; Seq!(S10567y1n, S10567y1t/+, S10567y2n, S10567y2t+/)) { S sx = S(1); S sy = S(2); assert(!(sx < sy) && !(sx > sy)); assert(sx.opCmp(sy) == 0); assert(typeid(S).compare(&sx, &sy) == 0); } foreach (S; Seq!(S10567z1n, S10567z1t/+, S10567z2n, S10567z2t+/)) { S sx = S(1); S sy = S(2); assert(!(sx < sy) && !(sx > sy)); assert(sx.opCmp(sy) == 0); try { auto x = typeid(S).compare(&sx, &sy); assert(0); } catch (Error e) { assert(e.msg[$-15 .. $] == "not implemented"); } } /+ foreach (S; Seq!(S10567d1, S10567d2)) { int[S] aa; aa[S(1)] = 10; aa[S(1)] = 1; aa[S(2)] = 20; aa[S(2)] = 2; assert(aa.length == 2); foreach (k, v; aa) assert(k.value == v); S sx = S(1); S sy = S(2); // Don't invoke opDispatch!"opCmp" assert(typeid(S).compare(&sx, &sy) != 0); } +/ } /**************************************/ // 11062 struct S11062ia { struct S1 { void opIndexAssign(int val, int key) {} } struct S2 { S1 headers; } private S2 m_obj; @property S2 get() { return m_obj; } alias get this; } struct S11062sa { struct S1 { void opSliceAssign(int val, int lwr, int upr) {} } struct S2 { S1 headers; } private S2 m_obj; @property S2 get() { return m_obj; } alias get this; } void test11062() { auto sia = S11062ia(); sia.headers[1] = 1; // bug auto ssa = S11062sa(); ssa.headers[1..2] = 1; // bug } /**************************************/ // 11311 void test11311() { static int ctor, cpctor, dtor; static struct S { this(int) { ++ctor; } this(this) { ++cpctor; } ~this() { ++dtor; } } static struct Arr { S data; ref S opIndex(int) { return data; } ref S opSlice(int, int) { return data; } } { Arr a = Arr(S(1)); assert(ctor == 1); assert(cpctor == 0); assert(dtor == 0); auto getA1() { return a; } //getA1().opIndex(1); // OK getA1()[1]; // NG assert(ctor == 1); assert(cpctor == 1); // getA() returns a copy of a assert(dtor == 1); // temporary returned by getA() should be destroyed } assert(dtor == 2); assert(ctor + cpctor == dtor); ctor = cpctor = dtor = 0; { Arr a = Arr(S(1)); assert(ctor == 1); assert(cpctor == 0); assert(dtor == 0); auto getA2() { return a; } //getA2().opSlice(1, 2); // OK getA2()[1..2]; // NG assert(ctor == 1); assert(cpctor == 1); // getA() returns a copy of a assert(dtor == 1); // temporary returned by getA() should be destroyed } assert(dtor == 2); assert(ctor + cpctor == dtor); } /**************************************/ // 12193 void test12193() { struct Foo { bool bar; alias bar this; void opOpAssign(string op)(size_t x) { bar = false; } } Foo foo; foo <<= 1; } /**************************************/ // 14057 struct W14057 { int[] subType; alias subType this; W14057 opSlice(size_t, size_t) { return this; } } void test14057() { auto w = W14057(); W14057 w2 = w[0 .. 1337]; } /**************************************/ struct Tuple20(T...) { T field; alias field this; } void test20a() { // ae1save in in AssignExp::semantic int a, b; struct A1 { void opIndexAssign(int v, Tuple20!(int, int) ) { a = v; } Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; } } struct A2 { A1 a1; alias a1 this; ref int opIndexAssign(int) { return b; } } stompStack(); A2 foo() { return A2(); } foo()[1..2] = 1; // ref A1 __tmp = foo().a1; __tmp.opIndexAssign(1, __tmp.opSlice!0(1, 2)); assert(a == 1); // should work assert(b == 0); } void test20b() { // ae1save in UnaExp::op_overload() int a, b; struct A1 { void opIndexUnary(string op)(Tuple20!(int, int) ) { a = 1; } Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; } void dummy() {} // nessary to make A1 nested struct } struct A2 { A1 a1; alias a1 this; int opIndexUnary(string op)(int) { return 0; } } stompStack(); A2 foo() { return A2(); } +foo()[1..2]; // ref A1 __tmp = foo().a1; __tmp.opIndexUnary!"+"(__tmp.opSlice!0(1, 2)); assert(a == 1); // should pass assert(b == 0); } void test20c() { // ae1save in ArrayExp::op_overload() int a, b; struct A1 { void opIndex(Tuple20!(int, int) ) { a = 1; } Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; } } struct A2 { A1 a1; alias a1 this; int opIndex(int) { return 0; } } stompStack(); A2 foo() { return A2(); } foo()[1..2]; // ref A1 __tmp = foo().a1; __tmp.opIndex(__tmp.opSlice!0(1, 2)); assert(a == 1); // should pass assert(b == 0); } void test20d() { // ae1save in BinAssignExp::op_overload() int a, b; struct A1 { void opIndexOpAssign(string op)(int v, Tuple20!(int, int) ) { a = v; } Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; } void dummy() {} // nessary to make A1 nested struct } struct A2 { A1 a1; alias a1 this; ref int opIndexOpAssign(alias op)(int) { return b; } } stompStack(); A2 foo() { return A2(); } foo()[1..2] += 1; // ref A1 __tmp = foo().a1; __tmp.opIndexOpAssign!"+"(1, __tmp.opSlice!0(1, 2)); assert(a == 1); // should pass assert(b == 0); } /**************************************/ // 14624 void test14624() { struct A1 { int x; ref int opIndex() { return x; } ref int opSlice() { assert(0); } } { A1 a = A1(1); auto x = a[]; // a.opIndex() assert(x == a.x); auto y = -a[]; // -a.opIndex() <-- not found: a.opIndexUnary!"-" assert(y == -a.x); a[] = 1; // a.opIndex() = 1; <-- not found: a.opIndexAssign(int) assert(a.x == 1); a[] += 1; // a.opIndex() += 1; <-- not found: a.opIndexOpAssign!"+"(int) assert(a.x == 2); } struct A2 { int x; ref int opIndex() { x = 10; return x; } ref int opSlice() { assert(0); } ref int opSliceUnary(alias op)() { x = 11; return x; } ref int opSliceAssign(int) { x = 12; return x; } ref int opSliceOpAssign(alias op)(int) { x = 13; return x; } } { A2 a = A2(1); auto x = a[]; // a.opIndex() assert(a.x == 10); auto y = -a[]; // a.opSliceUnary!"-"() is preferred than: -a.opIndex() assert(a.x == 11); a[] = 1; // a.opSliceAssign(1) is preferred than: a.opIndex() = 1; assert(a.x == 12); a[] += 1; // a.opSliceOpAssign!"+"(1) is preferred than: a.opIndex() += 1; assert(a.x == 13); } } /**************************************/ // 14625 void test14625() { struct R { @property bool empty() { return true; } @property int front() { return 0; } void popFront() {} } struct C1 { R opIndex() { return R(); } R opSlice() { assert(0); } } C1 c1; foreach (e; c1) {} // OK <- asserts in opSlice() foreach (e; c1[]) {} // OK, opIndex() struct C2 { R opIndex() { return R(); } } C2 c2; foreach (e; c2) {} // OK <- rejected foreach (e; c2[]) {} // OK, opIndex() } /**************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test4099(); test12(); test13(); test14(); test15(); test16(); test17(); test3789(); test10037(); test6798(); test12904(); test7641(); test8434(); test18(); test19(); test9453(); test9496(); test9689(); test9694(); test10064(); test12585(); test10394(); test10567(); test11062(); test11311(); test14057(); test20a(); test20b(); test20c(); test20d(); test14624(); test14625(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_726.d0000664000175000017500000000246112776215022023056 0ustar kaikai void issue726_1() { struct Buggy { align(1): uint a = 0x0a0a0a0a; ulong b = 0x0b0b0b0b0b0b0b0b; } Buggy packed; ulong raw = *cast(ulong*)(cast(ubyte*)&packed + packed.b.offsetof); assert(packed.b == raw); } void issue726_2() { class Buggy { align(1): uint a = 0x0a0a0a0a; ulong b = 0x0b0b0b0b0b0b0b0b; } auto packed = new Buggy; ulong raw = *cast(ulong*)(cast(ubyte*)packed + packed.b.offsetof); assert(packed.b == raw); } void issue726_3() { class Buggy { align(1): uint a = 0x0a0a0a0a; ulong b = 0x0b0b0b0b0b0b0b0b; } class Derived : Buggy { } auto packed = new Derived; ulong raw = *cast(ulong*)(cast(ubyte*)packed + packed.b.offsetof); assert(packed.b == raw); } void issue726_4() { struct Buggy { align(1): uint a = 0x0a0a0a0a; ulong b = 0x0b0b0b0b0b0b0b0b; align(8): ulong c = 0x0c0c0c0c0c0c0c0c; } Buggy packed; ulong raw = *cast(ulong*)(cast(ubyte*)&packed + packed.b.offsetof); assert(packed.b == raw); raw = *cast(ulong*)(cast(ubyte*)&packed + packed.c.offsetof); assert(packed.c == raw); } void main() { issue726_1(); issue726_2(); issue726_3(); issue726_4(); }ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_430.d0000664000175000017500000000036512776215022023047 0ustar kaikaiimport std.conv; align(1) struct Foo { align(1): ushort b; uint c; } void main() { ubyte[6] arr = [0x01, 0x01, 0x01, 0x00, 0x00, 0x01]; Foo f = cast(Foo) arr; assert(to!string(f) == "Foo(257, 16777217)"); assert(f.sizeof == 6); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test24.d0000664000175000017500000000030012776215022021467 0ustar kaikai// EXTRA_SOURCES: imports/test24a.d imports/test24b.d // PERMUTE_ARGS: // REQUIRED_ARGS: import imports.test24a, imports.test24b; void main() { string hi = std.string.format("%s", 3); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test9259.d0000664000175000017500000000032012776215022021654 0ustar kaikai// PERMUTE_ARGS: -inline -release -g -O -d -dw -de void test(int*[] arr...) { assert(arr.length == 1); assert(*arr[0] == 5); // This assertion fails } void main() { int a = 5; test([&a]); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test10378.d0000664000175000017500000000023312776215022021731 0ustar kaikai int writeln() { return 3; } struct S { import imports.bar10378; void abc() { assert(writeln() == 3); } } void main() { S s; s.abc(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/testassign.d0000664000175000017500000006446312776215022022552 0ustar kaikaiimport core.stdc.stdio; template TypeTuple(T...){ alias T TypeTuple; } /***************************************************/ // 2625 struct Pair { immutable uint g1; uint g2; } void test1() { Pair[1] stuff; static assert(!__traits(compiles, (stuff[0] = Pair(1, 2)))); } /***************************************************/ // 5327 struct ID { immutable int value; } struct Data { ID id; } void test2() { Data data = Data(ID(1)); immutable int* val = &data.id.value; static assert(!__traits(compiles, data = Data(ID(2)))); } /***************************************************/ struct S31A { union { immutable int field1; immutable int field2; } enum result = false; } struct S31B { union { immutable int field1; int field2; } enum result = true; } struct S31C { union { int field1; immutable int field2; } enum result = true; } struct S31D { union { int field1; int field2; } enum result = true; } struct S32A { int dummy0; union { immutable int field1; int field2; } enum result = true; } struct S32B { immutable int dummy0; union { immutable int field1; int field2; } enum result = false; } struct S32C { union { immutable int field1; int field2; } int dummy1; enum result = true; } struct S32D { union { immutable int field1; int field2; } immutable int dummy1; enum result = false; } void test3() { foreach (S; TypeTuple!(S31A,S31B,S31C,S31D, S32A,S32B,S32C,S32D)) { S s; static assert(__traits(compiles, s = s) == S.result); } } /***************************************************/ // 3511 struct S4 { private int _prop = 42; ref int property() { return _prop; } } void test4() { S4 s; assert(s.property == 42); s.property = 23; // Rewrite to s.property() = 23 assert(s.property == 23); } /***************************************************/ struct S5 { int mX; string mY; ref int x() { return mX; } ref string y() { return mY; } ref int err(Object) { static int v; return v; } } void test5() { S5 s; s.x += 4; assert(s.mX == 4); s.x -= 2; assert(s.mX == 2); s.x *= 4; assert(s.mX == 8); s.x /= 2; assert(s.mX == 4); s.x %= 3; assert(s.mX == 1); s.x <<= 3; assert(s.mX == 8); s.x >>= 1; assert(s.mX == 4); s.x >>>= 1; assert(s.mX == 2); s.x &= 0xF; assert(s.mX == 0x2); s.x |= 0x8; assert(s.mX == 0xA); s.x ^= 0xF; assert(s.mX == 0x5); s.x ^^= 2; assert(s.mX == 25); s.mY = "ABC"; s.y ~= "def"; assert(s.mY == "ABCdef"); static assert(!__traits(compiles, s.err += 1)); } /***************************************************/ // 4424 void test4424() { static struct S { this(this) {} void opAssign(T)(T rhs) if (!is(T == S)) {} } } /***************************************************/ // 6174 struct CtorTest6174(Data) { const Data data; const Data[2] sa1; const Data[2][1] sa2; const Data[][2] sa3; const Data[] da1; const Data[2][] da2; this(Data a) { auto pdata = &data; // If compiler can determine that an assignment really sets the fields // which belongs to `this` object, it can bypass const qualifier. // For example, sa3, da1, da2, and pdata have indirections. // As long as you don't try to rewrite values beyond the indirections, // an assignment will always be succeeded inside constructor. static assert( is(typeof( data = a ))); // OK static if (is(Data == struct)) { static assert( is(typeof( data.x = 1 ))); // OK static assert( is(typeof( data.y = 2 ))); // OK } static assert(!is(typeof( *pdata = a ))); // NG static assert( is(typeof( *&data = a ))); // OK static assert( is(typeof( sa1 = [a,a] ))); // OK static assert( is(typeof( sa1[0] = a ))); // OK static assert( is(typeof( sa1[] = a ))); // OK static assert( is(typeof( sa1[][] = a ))); // OK static assert( is(typeof( sa2 = [[a,a]] ))); // OK static assert( is(typeof( sa2[0][0] = a ))); // OK static assert( is(typeof( sa2[][0][] = a ))); // OK static assert( is(typeof( sa2[0][][0] = a ))); // OK static assert( is(typeof( sa3 = [[a],[]] ))); // OK static assert( is(typeof( sa3[0] = [a,a] ))); // OK static assert(!is(typeof( sa3[0][0] = a ))); // NG static assert( is(typeof( sa3[] = [a] ))); // OK static assert( is(typeof( sa3[][0] = [a] ))); // OK static assert(!is(typeof( sa3[][0][0] = a ))); // NG static assert( is(typeof( da1 = [a,a] ))); // OK static assert(!is(typeof( da1[0] = a ))); // NG static assert(!is(typeof( da1[] = a ))); // NG static assert( is(typeof( da2 = [[a,a]] ))); // OK static assert(!is(typeof( da2[0][0] = a ))); // NG static assert(!is(typeof( da2[] = [a,a] ))); // NG static assert(!is(typeof( da2[][0] = a ))); // NG static assert(!is(typeof( da2[0][] = a ))); // NG } void func(Data a) { auto pdata = &data; static assert(!is(typeof( data = a ))); // NG static if (is(Data == struct)) { static assert(!is(typeof( data.x = 1 ))); // NG static assert(!is(typeof( data.y = 2 ))); // NG } static assert(!is(typeof( *pdata = a ))); // NG static assert(!is(typeof( *&data = a ))); // NG static assert(!is(typeof( sa1 = [a,a] ))); // NG static assert(!is(typeof( sa1[0] = a ))); // NG static assert(!is(typeof( sa1[] = a ))); // NG static assert(!is(typeof( sa1[][] = a ))); // NG static assert(!is(typeof( sa2 = [[a,a]] ))); // NG static assert(!is(typeof( sa2[0][0] = a ))); // NG static assert(!is(typeof( sa2[][0][] = a ))); // NG static assert(!is(typeof( sa2[0][][0] = a ))); // NG static assert(!is(typeof( sa3 = [[a],[]] ))); // NG static assert(!is(typeof( sa3[0] = [a,a] ))); // NG static assert(!is(typeof( sa3[0][0] = a ))); // NG static assert(!is(typeof( sa3[] = [a] ))); // NG static assert(!is(typeof( sa3[][0] = [a] ))); // NG static assert(!is(typeof( sa3[][0][0] = a ))); // NG static assert(!is(typeof( da1 = [a,a] ))); // NG static assert(!is(typeof( da1[0] = a ))); // NG static assert(!is(typeof( da1[] = a ))); // NG static assert(!is(typeof( da2 = [[a,a]] ))); // NG static assert(!is(typeof( da2[0][0] = a ))); // NG static assert(!is(typeof( da2[] = [a,a] ))); // NG static assert(!is(typeof( da2[][0] = a ))); // NG static assert(!is(typeof( da2[0][] = a ))); // NG } } const char gc6174; const char[1] ga6174; static this() { gc6174 = 'a'; // OK ga6174[0] = 'a'; // line 5, Err } struct Foo6174 { const char cc; const char[1] array; const char[1] arr; this(char c) { cc = c; // OK array = [c]; // line 12, Err arr[0] = c; // line 12, Err } } void test6174a() { static struct Pair { const int x; int y; } alias CtorTest6174!long CtorTest1; alias CtorTest6174!Pair CtorTest2; auto foo = Foo6174('c'); } /***************************************************/ template Select(bool cond, T, F) { static if (cond) alias Select = T; else alias Select = F; } void test6174b() { enum { none, unrelated, mutable, constant } static struct FieldStruct(bool c, int k) { enum fieldConst = c; enum assignKind = k; Select!(fieldConst, const int, int) x; int y; static if (assignKind == none) {} static if (assignKind == unrelated) void opAssign(int) {} static if (assignKind == mutable) void opAssign(FieldStruct) {} static if (assignKind == constant) void opAssign(FieldStruct) const {} } static struct TestStruct(F, bool fieldConst) { int w; Select!(fieldConst, const F, F) f; Select!(fieldConst, const int, int) z; this(int) { // If F has an identity `opAssign`,it is used even for initializing. // Otherwise, initializing will always succeed, by bypassing const qualifier. static assert(is(typeof( f = F() )) == ( F.assignKind == none || F.assignKind == unrelated || F.assignKind == mutable || F.assignKind == constant)); static assert(is(typeof( w = 1000 )) == true); static assert(is(typeof( f.x = 1000 )) == true); static assert(is(typeof( f.y = 1000 )) == true); static assert(is(typeof( z = 1000 )) == true); } void func() { // In mutable member functions, identity assignment is allowed // when all of the fields are identity assignable, // or identity `opAssign`, which callable from mutable object, is defined. static assert(__traits(compiles, f = F()) == ( F.assignKind == none && !fieldConst && !F.fieldConst || F.assignKind == unrelated && !fieldConst && !F.fieldConst || F.assignKind == constant || F.assignKind == mutable && !fieldConst)); static assert(__traits(compiles, w = 1000) == true); static assert(__traits(compiles, f.x = 1000) == (!fieldConst && !F.fieldConst)); static assert(__traits(compiles, f.y = 1000) == (!fieldConst && true )); static assert(__traits(compiles, z = 1000) == !fieldConst); } void func() const { // In non-mutable member functions, identity assignment is allowed // just only user-defined identity `opAssign` is qualified. static assert(__traits(compiles, f = F()) == (F.assignKind == constant)); static assert(__traits(compiles, w = 1000) == false); static assert(__traits(compiles, f.x = 1000) == false); static assert(__traits(compiles, f.y = 1000) == false); static assert(__traits(compiles, z = 1000) == false); } } foreach (fieldConst; TypeTuple!(false, true)) foreach ( hasConst; TypeTuple!(false, true)) foreach (assignKind; TypeTuple!(none, unrelated, mutable, constant)) { alias TestStruct!(FieldStruct!(hasConst, assignKind), fieldConst) TestX; } } void test6174c() { static assert(!is(typeof({ int func1a(int n) in{ n = 10; } body { return n; } }))); static assert(!is(typeof({ int func1b(int n) out(r){ r = 20; } body{ return n; } }))); struct DataX { int x; } static assert(!is(typeof({ DataX func2a(DataX n) in{ n.x = 10; } body { return n; } }))); static assert(!is(typeof({ DataX func2b(DataX n) in{} out(r){ r.x = 20; } body{ return n; } }))); } /***************************************************/ // 6216 void test6216a() { static class C{} static struct Xa{ int n; } static struct Xb{ int[] a; } static struct Xc{ C c; } static struct Xd{ void opAssign(typeof(this) rhs){} } static struct Xe{ void opAssign(T)(T rhs){} } static struct Xf{ void opAssign(int rhs){} } static struct Xg{ void opAssign(T)(T rhs)if(!is(T==typeof(this))){} } // has value type as member static struct S1 (X){ static if (!is(X==void)) X x; int n; } // has reference type as member static struct S2a(X){ static if (!is(X==void)) X x; int[] a; } static struct S2b(X){ static if (!is(X==void)) X x; C c; } // has identity opAssign static struct S3a(X){ static if (!is(X==void)) X x; void opAssign(typeof(this) rhs){} } static struct S3b(X){ static if (!is(X==void)) X x; void opAssign(T)(T rhs){} } // has non identity opAssign static struct S4a(X){ static if (!is(X==void)) X x; void opAssign(int rhs){} } static struct S4b(X){ static if (!is(X==void)) X x; void opAssign(T)(T rhs)if(!is(T==typeof(this))){} } enum result = [ /*S1, S2a, S2b, S3a, S3b, S4a, S4b*/ /*- */ [true, true, true, true, true, true, true], /*Xa*/ [true, true, true, true, true, true, true], /*Xb*/ [true, true, true, true, true, true, true], /*Xc*/ [true, true, true, true, true, true, true], /*Xd*/ [true, true, true, true, true, true, true], /*Xe*/ [true, true, true, true, true, true, true], /*Xf*/ [true, true, true, true, true, true, true], /*Xg*/ [true, true, true, true, true, true, true], ]; pragma(msg, "\\\tS1\tS2a\tS2b\tS3a\tS3b\tS4a\tS4b"); foreach (i, X; TypeTuple!(void,Xa,Xb,Xc,Xd,Xe,Xf,Xg)) { S1!X s1; S2a!X s2a; S2b!X s2b; S3a!X s3a; S3b!X s3b; S4a!X s4a; S4b!X s4b; pragma(msg, is(X==void) ? "-" : X.stringof, "\t", __traits(compiles, (s1 = s1)), "\t", __traits(compiles, (s2a = s2a)), "\t", __traits(compiles, (s2b = s2b)), "\t", __traits(compiles, (s3a = s3a)), "\t", __traits(compiles, (s3b = s3b)), "\t", __traits(compiles, (s4a = s4a)), "\t", __traits(compiles, (s4b = s4b)) ); static assert(result[i] == [ __traits(compiles, (s1 = s1)), __traits(compiles, (s2a = s2a)), __traits(compiles, (s2b = s2b)), __traits(compiles, (s3a = s3a)), __traits(compiles, (s3b = s3b)), __traits(compiles, (s4a = s4a)), __traits(compiles, (s4b = s4b)) ]); } } void test6216b() { static int cnt = 0; static struct X { int n; void opAssign(X rhs){ cnt = 1; } } static struct S { int n; X x; } S s; s = s; assert(cnt == 1); // Built-in opAssign runs member's opAssign } void test6216c() { static int cnt = 0; static struct X { int n; void opAssign(const X rhs) const { cnt = 2; } } static struct S { int n; const(X) x; } S s; const(S) cs; s = s; s = cs; // cs is copied as mutable and assigned into s assert(cnt == 2); static assert(!__traits(compiles, cs = cs)); // built-in opAssin is only allowed with mutable object } void test6216d() { static int cnt = 0; static struct X { int[] arr; // X has mutable indirection void opAssign(const X rhs) const { ++cnt; } } static struct S { int n; const(X) x; } X mx; const X cx; mx = mx; // copying mx to const X is possible assert(cnt == 1); mx = cx; assert(cnt == 2); cx = mx; // copying mx to const X is possible assert(cnt == 3); S s; const(S) cs; s = s; s = cs; //assert(cnt == 4); static assert(!__traits(compiles, cs = cs)); // built-in opAssin is only allowed with mutable object } void test6216e() { static struct X { int x; @disable void opAssign(X); } static struct S { X x; } S s; static assert(!__traits(compiles, s = s)); // built-in generated opAssin is marked as @disable. } /***************************************************/ // 6286 void test6286() { const(int)[4] src = [1, 2, 3, 4]; int[4] dst; dst = src; dst[] = src[]; dst = 4; int[4][4] x; x = dst; } /***************************************************/ // 6336 void test6336() { // structs aren't identity assignable static struct S1 { immutable int n; } static struct S2 { void opAssign(int n){ assert(0); } } S1 s1; S2 s2; void f(S)(out S s){} static assert(!__traits(compiles, f(s1))); f(s2); // Out parameters refuse only S1 because it isn't blit assignable ref S g(S)(ref S s){ return s; } g(s1); g(s2); // Allow return by ref both S1 and S2 } /***************************************************/ // 8783 struct Foo8783 { int[1] bar; } const Foo8783[1] foos8783; static this() { foreach (i; 0 .. foos8783.length) foos8783[i].bar[i] = 1; // OK foreach (i, ref f; foos8783) f.bar[i] = 1; // line 9, Error } /***************************************************/ // 9077 struct S9077a { void opAssign(int n) {} void test() { typeof(this) s; s = this; } this(this) {} } struct S9077b { void opAssign()(int n) {} void test() { typeof(this) s; s = this; } this(this) {} } /***************************************************/ // 9140 immutable(int)[] bar9140() out(result) { foreach (ref r; result) {} } body { return null; } /***************************************************/ // 9154 struct S9154a { int x; void opAssign(ref S9154a s) { } } struct S9154b { int x; void opAssign(X)(ref X s) { } } struct T9154 { S9154a member1; S9154b member2; } void test9154() { T9154 t1, t2; t1 = t2; } /***************************************************/ // 9258 class A9258 {} class B9258 : A9258 // Error: class test.B9258 identity assignment operator overload is illegal { void opAssign(A9258 b) {} } class C9258 { int n; alias n this; void opAssign(int n) {} } class D9258 { int n; alias n this; void opAssign(int n, int y = 0) {} } class E9258 : A9258 { void set(A9258 a) {} alias set opAssign; } /***************************************************/ // 9416 struct S9416 { void opAssign()(S9416) { static assert(0); } } struct U9416 { S9416 s; } void test9416() { U9416 u; static assert(__traits(allMembers, U9416)[$-1] == "opAssign"); static assert(!__traits(compiles, u = u)); } /***************************************************/ // 9658 struct S9658 { private bool _isNull = true; this(int v) const { _isNull = false; // cannot modify const expression this._isNull } } /***************************************************/ // 11187 void test11187() { static struct X { int[] arr; } static struct S { const(X) cx; } static assert(is(typeof((const S).init.cx.arr) == const(int[]))); static assert(is(typeof(( S).init.cx.arr) == const(int[]))); const S sc; S sm = sc; static assert(is(const S : S)); } /***************************************************/ // 12131 struct X12131 { void opAssign()(X12131 y) pure {} } struct Y12131 { X12131 a; } void test12131() pure { X12131 x; x = X12131(); // OK Y12131 y; y = Y12131(); // OK <- Error } /***************************************************/ // 12211 void test12211() { int a = 0; void foo(ref int x) { assert(x == 10); assert(&x == &a); x = 3; } foo(a = 10); assert(a == 3); foo(a += 7); assert(a == 3); // array ops should make rvalue int[3] sa, sb; void bar(ref int[]) {} static assert(!__traits(compiles, bar(sa[] = sb[]))); static assert(!__traits(compiles, bar(sa[] += sb[]))); } /***************************************************/ // 4791 (dup of 12212) void test4791() { int[2] na; na = na; static struct S { static string res; int n; this(this) { ++n; res ~= "p" ~ cast(char)('0' + n); } ~this() { res ~= "d" ~ cast(char)('0' + n); } } { S[3] sa; sa[0].n = 1, sa[1].n = 2, sa[2].n = 3; S.res = null; sa = sa; assert(S.res == "p2d1p3d2p4d3"); assert(sa[0].n == 2 && sa[1].n == 3 && sa[2].n == 4); S.res = null; } assert(S.res == "d4d3d2"); } /***************************************************/ // 12212 void test12212() { struct S { int x, y; static int cpctor; this(this) { cpctor++; } } void funcVal(E)(E[3] x) {} auto funcRef(E)(ref E[3] x) { return &x; } ref get(E)(ref E[3] a){ return a; } { int[3] a, b; funcVal(a = b); auto p = funcRef(a = b); assert(p == &a); } { S.cpctor = 0; S[3] a, b; assert(S.cpctor == 0); S[3] c = a; //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 3); S.cpctor = 0; c = a; //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 3); S.cpctor = 0; c = (a = b); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 6); S.cpctor = 0; c = (get(a) = b); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 6); S.cpctor = 0; } { S.cpctor = 0; S[3] a, b; assert(S.cpctor == 0); funcVal(a = b); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 6); S.cpctor = 0; funcVal(get(a) = b); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 6); S.cpctor = 0; } { S.cpctor = 0; S[3] a, b; assert(S.cpctor == 0); S[3]* p; p = funcRef(a = b); //printf("cpctpr = %d\n", S.cpctor); assert(p == &a); assert(S.cpctor == 3); S.cpctor = 0; p = funcRef(get(a) = b); assert(p == &a); //printf("cpctpr = %d\n", S.cpctor); assert(S.cpctor == 3); S.cpctor = 0; } } /***************************************************/ // 12650 void test12650() { // AssignExp::toElem should make an lvalue of e1. static class A1 { struct S { int a; } static foo(ref const(S) s) { assert(s.a == 2); return &s; } S s; this() { const v = S(2); // (this.s = v) will become ConstructExp auto p = foo(s = v); assert(p == &s); } } assert(new A1().s.a == 2); static class A2 { static foo(ref int[2] sa) { assert(sa[1] == 2); return &sa; } int[2] sa; this() { // (this.sa = [1,2]) will become ConstructExp auto p = foo(sa = [1,2]); assert(p == &sa); } } assert(new A2().sa[1] == 2); static class A3 { static foo(ref int n) { assert(n == 2); return &n; } int n; this() { const v = 2; // (this.n = v) will become ConstructExp auto p = foo(n = v); assert(p == &n); } } assert(new A3().n == 2); } /***************************************************/ // 13044 void test13044() { static struct Good { const int i; } static struct Bad { const int i; ~this() {} } Good good1, good2; static assert(!__traits(compiles, { good1 = good2; })); // OK Bad bad1, bad2; static assert(!__traits(compiles, { bad1 = bad2; })); // OK <- fails } /***************************************************/ // 12500 void test12500() { size_t foo; ++foo *= 1.5; // Rewrite to: (foo += 1) *= 1.5; } /***************************************************/ // 14672 void test14672() { interface I {} class B {} class D : B, I {} D d = new D(); D[] da = [d]; B[] ba = [null]; I[] ia = [null]; // ba and da points different payloads, // so element-wise assignment should work. ba[] = da[]; // OK <- e2ir ICE assert(ba[0] is d); // Today element-wise assignment is implemented as memcpy, For that reason // the conversion from derived classes to base interfaces is disallowed // because it requries offset adjustments. static assert(!__traits(compiles, { ia[] = da[]; })); // after the assignment, ba will wongly point the payload of da, // that's typed as D[]. To aboid type system breaking, it's disallowed. static assert(!__traits(compiles, { ba = da; })); // the assigned array literal is a new payload, // so rebinding ba should work. ba = [d]; // OK assert(ba[0] is d); } /***************************************************/ // 15044 void destroy15044(T)(ref T obj) { static if (__traits(hasMember, T, "__xdtor")) obj.__xdtor(); else static assert(0, T.stringof); } struct V15044 { ~this() { } RC15044!V15044 dup() { return RC15044!V15044(&this); } } struct RC15044(T) { ~this() { destroy15044(*t); static assert(__traits(hasMember, T, "__xdtor")); } T* t; } /***************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test4424(); test6174a(); test6174b(); test6174c(); test6216a(); test6216b(); test6216c(); test6216d(); test6216e(); test6286(); test6336(); test9154(); test9416(); test11187(); test12131(); test12211(); test4791(); test12212(); test12650(); test13044(); test12500(); test14672(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/hello-profile.d0000664000175000017500000000131312776215022023110 0ustar kaikai// PERMUTE_ARGS: // REQUIRED_ARGS: -profile // POST_SCRIPT: runnable/extra-files/hello-profile-postscript.sh // EXECUTE_ARGS: ${RESULTS_DIR}/runnable module hello; extern(C) { int printf(const char*, ...); int trace_setlogfilename(string name); int trace_setdeffilename(string name); } void showargs(string[] args) { printf("hello world\n"); printf("args.length = %d\n", args.length); for (int i = 0; i < args.length; i++) printf("args[%d] = '%.*s'\n", i, args[i].length, args[i].ptr); } int main(string[] args) { trace_setlogfilename(args[1] ~ "/hello-profile.d.trace.log"); trace_setdeffilename(args[1] ~ "/hello-profile.d.trace.def"); showargs(args); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/Same.d0000664000175000017500000000024712776215022021241 0ustar kaikai// EXTRA_SOURCES: imports/Other.d // PERMUTE_ARGS: module Same; // makes no difference if removed import core.stdc.stdio; class Same { this() { printf("Same\n"); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test13117.d0000664000175000017500000000040712776215022021726 0ustar kaikai// PERMUTE_ARGS: -O -release -g import std.file, std.stdio; int main() { auto size = thisExePath.getSize(); writeln(size); version (D_LP64) enum limit = 1_906_432; else enum limit = 1_380_000; return size > limit * 11 / 10; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_intrinsics.d0000775000175000017500000002615512776215022023374 0ustar kaikai// -c -m32 D:\OpenSource\ldc\ldc\tests\d2\dmd-testsuite\runnable\builtin.d module ldc_intrinsics; import ldc.intrinsics; /*******************************************/ // Make sure that intrinsics do not interfere with C name mangling. extern(C) uint bswap(uint x) { return x; } void test1() { enum v1 = bswap(0xdeadbeef); assert(v1 == 0xdeadbeef); enum v2 = llvm_bswap(0xcafebabe); assert(v2 == 0xbebafeca); } /*******************************************/ // Check runtime and compile time evaluation of llvm_bswap(). void test2() { assert( llvm_bswap( cast(ushort)0 ) == 0); assert( llvm_bswap( cast(ushort)0x00FF ) == 0xFF00); assert( llvm_bswap( cast(ushort)0xAABB ) == 0xBBAA); assert( llvm_bswap( cast(uint)0x0000_00FF ) == 0xFF00_0000); assert( llvm_bswap( cast(uint)0x0000_FF00 ) == 0x00FF_0000); assert( llvm_bswap( cast(uint)0x00FF_0000 ) == 0x0000_FF00); assert( llvm_bswap( cast(uint)0xFF00_0000 ) == 0x0000_00FF); assert( llvm_bswap( cast(uint)0x00AA_BB00 ) == 0x00BB_AA00); assert( llvm_bswap( cast(ulong)0x00000000_000000FF ) == 0xFF000000_00000000); assert( llvm_bswap( cast(ulong)0x00000000_0000FF00 ) == 0x00FF0000_00000000); assert( llvm_bswap( cast(ulong)0x00000000_00FF0000 ) == 0x0000FF00_00000000); assert( llvm_bswap( cast(ulong)0x00000000_FF000000 ) == 0x000000FF_00000000); assert( llvm_bswap( cast(ulong)0x000000FF_00000000 ) == 0x00000000_FF000000); assert( llvm_bswap( cast(ulong)0x0000FF00_00000000 ) == 0x00000000_00FF0000); assert( llvm_bswap( cast(ulong)0x00FF0000_00000000 ) == 0x00000000_0000FF00); assert( llvm_bswap( cast(ulong)0xFF000000_00000000 ) == 0x00000000_000000FF); assert( llvm_bswap( cast(ulong)0x000000AA_BB000000 ) == 0x000000BB_AA000000); static assert( llvm_bswap( cast(ushort)0 ) == 0); static assert( llvm_bswap( cast(ushort)0x00FF ) == 0xFF00); static assert( llvm_bswap( cast(ushort)0xAABB ) == 0xBBAA); static assert( llvm_bswap( cast(uint)0x0000_00FF ) == 0xFF00_0000); static assert( llvm_bswap( cast(uint)0x0000_FF00 ) == 0x00FF_0000); static assert( llvm_bswap( cast(uint)0x00FF_0000 ) == 0x0000_FF00); static assert( llvm_bswap( cast(uint)0xFF00_0000 ) == 0x0000_00FF); static assert( llvm_bswap( cast(uint)0x00AA_BB00 ) == 0x00BB_AA00); static assert( llvm_bswap( cast(ulong)0x00000000_000000FF ) == 0xFF000000_00000000); static assert( llvm_bswap( cast(ulong)0x00000000_0000FF00 ) == 0x00FF0000_00000000); static assert( llvm_bswap( cast(ulong)0x00000000_00FF0000 ) == 0x0000FF00_00000000); static assert( llvm_bswap( cast(ulong)0x00000000_FF000000 ) == 0x000000FF_00000000); static assert( llvm_bswap( cast(ulong)0x000000FF_00000000 ) == 0x00000000_FF000000); static assert( llvm_bswap( cast(ulong)0x0000FF00_00000000 ) == 0x00000000_00FF0000); static assert( llvm_bswap( cast(ulong)0x00FF0000_00000000 ) == 0x00000000_0000FF00); static assert( llvm_bswap( cast(ulong)0xFF000000_00000000 ) == 0x00000000_000000FF); static assert( llvm_bswap( cast(ulong)0x000000AA_BB000000 ) == 0x000000BB_AA000000); static assert( llvm_bswap( cast(ulong)0x80000000_00000001 ) == 0x01000000_00000080); } /*******************************************/ // Check runtime and compile time evaluation of llvm_ctpop(). void test3() { assert( llvm_ctpop( cast(ushort)0 ) == 0 ); assert( llvm_ctpop( cast(ushort)7 ) == 3 ); assert( llvm_ctpop( cast(ushort)0xAA )== 4); assert( llvm_ctpop( cast(ushort)0xFFFF ) == 16 ); assert( llvm_ctpop( cast(ushort)0xCCCC ) == 8 ); assert( llvm_ctpop( cast(ushort)0x7777 ) == 12 ); assert( llvm_ctpop( cast(uint)0 ) == 0 ); assert( llvm_ctpop( cast(uint)7 ) == 3 ); assert( llvm_ctpop( cast(uint)0xAA )== 4); assert( llvm_ctpop( cast(uint)0x8421_1248 ) == 8 ); assert( llvm_ctpop( cast(uint)0xFFFF_FFFF ) == 32 ); assert( llvm_ctpop( cast(uint)0xCCCC_CCCC ) == 16 ); assert( llvm_ctpop( cast(uint)0x7777_7777 ) == 24 ); assert( llvm_ctpop( cast(ulong)0 ) == 0 ); assert( llvm_ctpop( cast(ulong)7 ) == 3 ); assert( llvm_ctpop( cast(ulong)0xAA )== 4); assert( llvm_ctpop( cast(ulong)0x8421_1248 ) == 8 ); assert( llvm_ctpop( cast(ulong)0xFFFF_FFFF_FFFF_FFFF ) == 64 ); assert( llvm_ctpop( cast(ulong)0xCCCC_CCCC_CCCC_CCCC ) == 32 ); assert( llvm_ctpop( cast(ulong)0x7777_7777_7777_7777 ) == 48 ); static assert( llvm_ctpop( cast(ushort)0 ) == 0 ); static assert( llvm_ctpop( cast(ushort)7 ) == 3 ); static assert( llvm_ctpop( cast(ushort)0xAA )== 4); static assert( llvm_ctpop( cast(ushort)0xFFFF ) == 16 ); static assert( llvm_ctpop( cast(ushort)0xCCCC ) == 8 ); static assert( llvm_ctpop( cast(ushort)0x7777 ) == 12 ); static assert( llvm_ctpop( cast(uint)0 ) == 0 ); static assert( llvm_ctpop( cast(uint)7 ) == 3 ); static assert( llvm_ctpop( cast(uint)0xAA )== 4); static assert( llvm_ctpop( cast(uint)0x8421_1248 ) == 8 ); static assert( llvm_ctpop( cast(uint)0xFFFF_FFFF ) == 32 ); static assert( llvm_ctpop( cast(uint)0xCCCC_CCCC ) == 16 ); static assert( llvm_ctpop( cast(uint)0x7777_7777 ) == 24 ); static assert( llvm_ctpop( cast(ulong)0 ) == 0 ); static assert( llvm_ctpop( cast(ulong)7 ) == 3 ); static assert( llvm_ctpop( cast(ulong)0xAA )== 4); static assert( llvm_ctpop( cast(ulong)0x8421_1248 ) == 8 ); static assert( llvm_ctpop( cast(ulong)0xFFFF_FFFF_FFFF_FFFF ) == 64 ); static assert( llvm_ctpop( cast(ulong)0xCCCC_CCCC_CCCC_CCCC ) == 32 ); static assert( llvm_ctpop( cast(ulong)0x7777_7777_7777_7777 ) == 48 ); } /*******************************************/ // Check runtime and compile time evaluation of llvm_cttz()/llvm_ctlz(). void test4() { int a = 0x80; int f = llvm_cttz(a, true); int r = llvm_ctlz(a, true); a = 0x22; assert(llvm_cttz(a, true)==1); assert(llvm_ctlz(a, true)==int.sizeof * 8 - 1 - 5); static assert(llvm_cttz(0x22, true)==1); static assert(llvm_ctlz(0x22, true)==int.sizeof * 8 - 1 - 5); a = 0x8000000; assert(llvm_cttz(a, true)==27); assert(llvm_ctlz(a, true)==int.sizeof * 8 - 1 - 27); static assert(llvm_cttz(0x8000000, true)==27); static assert(llvm_ctlz(0x8000000, true)==int.sizeof * 8 - 1 - 27); a = 0x13f562c0; assert(llvm_cttz(a, true) == 6); assert(llvm_ctlz(a, true) == int.sizeof * 8 - 1 - 28); static assert(llvm_cttz(0x13f562c0, true) == 6); static assert(llvm_ctlz(0x13f562c0, true) == int.sizeof * 8 - 1 - 28); } /*******************************************/ void test5() { static if (__traits(compiles, llvm_fabs(3.14L))) { static assert( llvm_fabs( cast(float)-1.0 ) == 1.0 ); static assert( llvm_fabs( cast(double)-1.0 ) == 1.0 ); static assert( llvm_fabs( cast(real)-1.0 ) == 1.0 ); } } /*******************************************/ void test6() { static if (__traits(compiles, llvm_floor(3.14L))) { static assert( llvm_floor( cast(float)2.3 ) == 2.0 ); static assert( llvm_floor( cast(float)3.8 ) == 3.0 ); static assert( llvm_floor( cast(float)5.5 ) == 5.0 ); static assert( llvm_floor( cast(float)-2.3 ) == -3.0 ); static assert( llvm_floor( cast(float)-3.8 ) == -4.0 ); static assert( llvm_floor( cast(float)-5.5 ) == -6.0 ); static assert( llvm_floor( cast(double)2.3 ) == 2.0 ); static assert( llvm_floor( cast(double)3.8 ) == 3.0 ); static assert( llvm_floor( cast(double)5.5 ) == 5.0 ); static assert( llvm_floor( cast(double)-2.3 ) == -3.0 ); static assert( llvm_floor( cast(double)-3.8 ) == -4.0 ); static assert( llvm_floor( cast(double)-5.5 ) == -6.0 ); static assert( llvm_floor( cast(real)2.3 ) == 2.0 ); static assert( llvm_floor( cast(real)3.8 ) == 3.0 ); static assert( llvm_floor( cast(real)5.5 ) == 5.0 ); static assert( llvm_floor( cast(real)-2.3 ) == -3.0 ); static assert( llvm_floor( cast(real)-3.8 ) == -4.0 ); static assert( llvm_floor( cast(real)-5.5 ) == -6.0 ); } } /*******************************************/ void test7() { static if (__traits(compiles, llvm_ceil(3.14L))) { static assert( llvm_ceil( cast(float)2.3 ) == 3.0 ); static assert( llvm_ceil( cast(float)3.8 ) == 4.0 ); static assert( llvm_ceil( cast(float)5.5 ) == 6.0 ); static assert( llvm_ceil( cast(float)-2.3 ) == -2.0 ); static assert( llvm_ceil( cast(float)-3.8 ) == -3.0 ); static assert( llvm_ceil( cast(float)-5.5 ) == -5.0 ); static assert( llvm_ceil( cast(double)2.3 ) == 3.0 ); static assert( llvm_ceil( cast(double)3.8 ) == 4.0 ); static assert( llvm_ceil( cast(double)5.5 ) == 6.0 ); static assert( llvm_ceil( cast(double)-2.3 ) == -2.0 ); static assert( llvm_ceil( cast(double)-3.8 ) == -3.0 ); static assert( llvm_ceil( cast(double)-5.5 ) == -5.0 ); static assert( llvm_ceil( cast(real)2.3 ) == 3.0 ); static assert( llvm_ceil( cast(real)3.8 ) == 4.0 ); static assert( llvm_ceil( cast(real)5.5 ) == 6.0 ); static assert( llvm_ceil( cast(real)-2.3 ) == -2.0 ); static assert( llvm_ceil( cast(real)-3.8 ) == -3.0 ); static assert( llvm_ceil( cast(real)-5.5 ) == -5.0 ); } } /*******************************************/ void test8() { static if (__traits(compiles, llvm_trunc(3.14L))) { static assert( llvm_trunc( cast(float)2.3 ) == 2.0 ); static assert( llvm_trunc( cast(float)3.8 ) == 3.0 ); static assert( llvm_trunc( cast(float)5.5 ) == 5.0 ); static assert( llvm_trunc( cast(float)-2.3 ) == -2.0 ); static assert( llvm_trunc( cast(float)-3.8 ) == -3.0 ); static assert( llvm_trunc( cast(float)-5.5 ) == -5.0 ); } } /*******************************************/ void test9() { static if (__traits(compiles, llvm_round(3.14L))) { static assert( llvm_round( cast(float)2.3 ) == 2.0 ); static assert( llvm_round( cast(float)3.8 ) == 4.0 ); static assert( llvm_round( cast(float)5.5 ) == 6.0 ); static assert( llvm_round( cast(float)-2.3 ) == -2.0 ); static assert( llvm_round( cast(float)-3.8 ) == -4.0 ); static assert( llvm_round( cast(float)-5.5 ) == -6.0 ); } } /*******************************************/ void test10() { static if (__traits(compiles, llvm_minnum(3.14L, 2.81L))) { static assert( llvm_minnum( cast(float)2.3, cast(float) 3.8 ) == 2.3 ); static assert( llvm_minnum( cast(double)2.3, cast(float) 3.8 ) == 2.3 ); static assert( llvm_minnum( cast(real)2.3, cast(float) 3.8 ) == 2.3 ); } } /*******************************************/ void test11() { static if (__traits(compiles, llvm_maxnum(3.14L, 2.81L))) { static assert( llvm_maxnum( cast(float)2.3, cast(float) 3.8 ) == 3.8 ); static assert( llvm_maxnum( cast(double)2.3, cast(float) 3.8 ) == 3.8 ); static assert( llvm_maxnum( cast(real)2.3, cast(float) 3.8 ) == 3.8 ); } } /*******************************************/ void main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test7453.d0000664000175000017500000000022512776215022021652 0ustar kaikaistruct S { int opApply(int delegate(string) dg) { return 0; } } void main() { foreach (_; S()) { return; } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test12.d0000664000175000017500000004344712776215022021507 0ustar kaikai extern(C) int printf(const char*, ...); extern(C) int sprintf(char*, const char*, ...); /**************************************/ void test1() { bool x; int i; i = !("bar" == "bar"); assert(i == 0); i = "bar" != "bar"; assert(i == 0); i = "bar" == "bar"; assert(i == 1); x = "bar" != "bar"; assert(x == false); assert("bar" == "bar"); x = "bar" == "bar"; assert(x == true); /+ ---- +/ i = !("foo" == "bar"); assert(i == 1); i = "foo" != "bar"; assert(i == 1); i = "foo" == "bar"; assert(i == 0); x = "foo" != "bar"; assert(x == true); assert("foo" != "bar"); x = "foo" == "bar"; assert(x == false); } /**************************************/ void test2() { bool x; int i; i = !("bar" <= "bar"); assert(i <= 0); i = "bar" > "bar"; assert(i == 0); i = "bar" >= "bar"; assert(i == 1); x = "bar" < "bar"; assert(x == false); assert("bar" <= "bar"); x = "bar" <= "bar"; assert(x == true); /+ ---- +/ i = !("foo" < "bar"); assert(i == 1); i = "foo" > "bar"; assert(i == 1); i = "foo" < "bar"; assert(i == 0); x = "foo" >= "bar"; assert(x == true); assert("foo" >= "bar"); x = "foo" <= "bar"; assert(x == false); } /**************************************/ bool all(string array, bool function(char) predicate) { for (int i = 0; i < array.length; i++) { if (!predicate(array[i])) { return false; } } return true; } bool all(string array, bool delegate(char) predicate) { for (int i = 0; i < array.length; i++) { if (!predicate(array[i])) { return false; } } return true; } bool isVowel(char c) { return (c == 'a') || (c == 'e') || (c == 'i') || (c == 'o') || (c == 'u'); } class Character { private char letter; this(char c) { this.letter = c; } public bool isLetter(char c) { return this.letter == c; } } void test3() { Character a = new Character('a'); bool delegate(char) isLetter; isLetter = &a.isLetter; bool i; i = all("aeiouoeieuiei", &isVowel); assert(i == true); i = all("aeiouoeieuiei", isLetter); assert(i == false); } /**************************************/ int[] fun(int i) in { assert(i > 0); } out (result) { assert(result[0] == 2); } body { char result; int[] res = new int[10]; res[] = i; int isZero = (result == 0xFF); assert(isZero); return res; } void test4() { int[] values = fun(2); } /**************************************/ const uint D3DSP_DSTMOD_SHIFT = 20; const uint D3DSP_DSTMOD_MASK = 0x00F00000; enum D3DSHADER_PARAM_DSTMOD_TYPE { NONE = 0<= 0) || (x < 0)); } struct X21 { float f, g, h; } X21 x21_1; X21 x21_2 = { f: 1.0, h: 2.0 }; char[3] y21_1; char[3] y21_2 = [ 0: 'a', 2: 'b' ]; void test21() { assert(isnan(x21_1.g)); assert(isnan(x21_2.g)); assert(y21_1[1] == '\xff'); assert(y21_2[1] == '\xff'); } /**************************************/ void test22() { wstring a = cast(wstring)"一〇"; } /**************************************/ interface A23 { void x(); } class B23 : A23 { void x() { } } class C23 : B23 { uint y = 12345678; } void stest23(A23 a) { synchronized (a) { } } void test23() { C23 c = new C23; assert(c.y == 12345678 /*c.y.init*/); stest23(c); assert(c.y == 12345678 /*c.y.init*/); } /**************************************/ class A24 { unittest { } } void test24() { } /**************************************/ char rot13(char ret) { if (ret > 'A'-1 && ret < 'N') { ret += 13;} else if(ret > 'M' && ret < 'Z'+1) { ret -= 13;} else if(ret > 'a'-1 && ret < 'n') { ret += 13;} else if(ret > 'm' && ret < 'z'+1) { ret -= 13;} return ret; } void test25() { foreach (char c; "hello World\n") printf("%c %c\n", c, rot13(c)); assert(rot13('h') == 'u'); assert(rot13('o') == 'b'); assert(rot13('W') == 'J'); assert(rot13('H') == 'U'); } /**************************************/ bool b26a = cast(bool)( cast(bool) 2 & cast(bool) 1 ); bool b26b = cast(bool) 2; void test26() { assert( (* cast(byte *) & b26a) == 1 ); assert( (* cast(byte *) & b26b) == 1 ); } /**************************************/ int c27; struct X27 { int x; struct { int a; int b; static this() { c27 = 3; } } } void test27() { assert(c27 == 3); } /**************************************/ void test28() { void bar() { throw new Foo28(); } } class Foo28 : Throwable { private: this() { super(""); } } /**************************************/ struct S29 { ubyte a, b, c, d; } int hoge(S29 s) { char[10] b; printf("%x\n", s); sprintf(b.ptr, "%x", s); assert(b[0 .. 7] == "4030201"); return 0; } void test29() { for (int i = 0; i < 1; i++) { S29 s; s.a = 1; s.b = 2; s.c = 3; s.d = 4; hoge(s); } } /**************************************/ class Qwert { static { deprecated int yuiop() { return 42; } } static deprecated int asdfg() { return yuiop() + 105; } } void test30() { } /**************************************/ void test31() { string foo = "hello"; printf("%s\n", foo.ptr); auto s = typeid(typeof(foo.ptr)).toString(); printf("%.*s\n", s.length, s.ptr); s = typeid(char*).toString(); printf("%.*s\n", s.length, s.ptr); assert(typeid(typeof(foo.ptr)) == typeid(immutable(char)*)); } /**************************************/ class Qwert32 { struct { int yuiop = 13; } int asdfg = 42; void foo() { printf("yuiop = %d, asdfg = %d\n", Qwert32.yuiop.offsetof, Qwert32.asdfg.offsetof); version(D_LP64) { assert(Qwert32.yuiop.offsetof == 16); assert(Qwert32.asdfg.offsetof == 20); } else { assert(Qwert32.yuiop.offsetof == 8); assert(Qwert32.asdfg.offsetof == 12); } } } void test32() { Qwert32 q = new Qwert32; q.foo(); } /**************************************/ int x33; int y33; size_t os_query() { return cast(uint)(cast(char *)&x33 - cast(char *)&y33); } void test33() { os_query(); } /**************************************/ uint x34 = ~(16u-1u); uint y34 = ~(16u-1); void test34() { assert(x34 == 0xFFFFFFF0); assert(y34 == 0xFFFFFFF0); } /**************************************/ private static extern (C) { shared char* function () uloc_getDefault; } static shared void**[] targets = [ cast(shared(void*)*) &uloc_getDefault, ]; void test35() { } /**************************************/ class S36 { int s = 1; this() { } } class A36 : S36 { int a = 2; int b = 3; int c = 4; int d = 5; } void test36() { A36 a = new A36; printf("A36.sizeof = %d\n", a.classinfo.init.length); printf("%d\n", a.s); printf("%d\n", a.a); printf("%d\n", a.b); printf("%d\n", a.c); printf("%d\n", a.d); version(D_LP64) assert(a.classinfo.init.length == 36); else assert(a.classinfo.init.length == 28); assert(a.s == 1); assert(a.a == 2); assert(a.b == 3); assert(a.c == 4); assert(a.d == 5); } /**************************************/ struct MyStruct { StructAlias* MyStruct() { return null; } } alias MyStruct StructAlias; void test37() { } /**************************************/ class Foo38 { static void display_name() { printf("%.*s\n", Object.classinfo.name.length, Object.classinfo.name.ptr); assert(Object.classinfo.name == "object.Object"); assert(super.classinfo.name == "object.Object"); assert(this.classinfo.name == "test12.Foo38"); } } void test38() { Foo38.display_name(); } /**************************************/ // http://www.digitalmars.com/d/archives/digitalmars/D/bugs/2409.html class C39 { C39 c; this() { c = this; } C39 lock() { return c; } } void test39() { C39 c = new C39(); synchronized( c.lock() ) {} synchronized( c.lock ) {} } /**************************************/ class C40 { static int x = 4; static int foo() { return this.x; } } void test40() { C40 c = new C40(); assert(C40.foo() == 4); } /**************************************/ struct Foo42 { Bar42 b; } struct Bar42 { long a; } void test42() { assert(Bar42.sizeof == long.sizeof); assert(Foo42.sizeof == long.sizeof); } /**************************************/ class Foo43 { Bar43 b; } struct Bar43 { long a; } void test43() { assert(Bar43.sizeof == long.sizeof); assert(Foo43.sizeof == (void*).sizeof); } /**************************************/ struct Property { uint attributes; Value value; } struct Value { int a,b,c,d; } struct PropTable { Property[Value] table; PropTable* previous; Value* get(Value* key) { Property *p; p = *key in table; p = &table[*key]; table.remove(*key); return null; } } void test44() { } /**************************************/ import std.algorithm; struct Shell { string str; const int opCmp(ref const Shell s) { return std.algorithm.cmp(this.str, s.str); } } void test45() { Shell[3] a; a[0].str = "hello"; a[1].str = "betty"; a[2].str = "fred"; a.sort; foreach (Shell s; a) { printf("%.*s\n", s.str.length, s.str.ptr); } assert(a[0].str == "betty"); assert(a[1].str == "fred"); assert(a[2].str == "hello"); } /**************************************/ class A46 { char foo() { return 'a'; } } class B46 : A46 { } class C46 : B46 { override char foo() { return 'c'; } char bar() { return B46.foo(); } } void test46() { C46 c = new C46(); assert(c.bar() == 'a'); printf("%c\n", c.bar()); } /**************************************/ class Foo47 { static bool prop() { return false; } static string charprop() { return null; } } void test47() { if (0 || Foo47.prop) { } if (1 && Foo47.prop) { } switch (Foo47.prop) { default: break; } foreach (char ch; Foo47.charprop) { } } /**************************************/ struct foo48 { int x, y, z; } void bar48() {} void test48() { foo48[] arr; foreach(foo48 a; arr) { bar48(); } } /**************************************/ enum E49; void test49() { } /**************************************/ void test50() { S50!() s; assert(s.i == int.sizeof); } struct S50() { int i=f50(0).sizeof; } int f50(...); /**************************************/ enum Enum51 { A, B, C } struct Struct51 { Enum51 e; } void test51() { Struct51 s; assert(s.e == Enum51.A); assert(s.e == 0); } /**************************************/ bool foo52() { int x; for (;;) { if (x == 0) return true; x = 1; } return false; } void test52() { foo52(); } /**************************************/ void foo53() { ret:{} goto ret; } void test53() { } /**************************************/ struct V54 { int x = 3; } class Foo54 { static int y; static V54 prop() { V54 val; return val; } static void prop(V54 val) { y = val.x * 2; } } void test54() { (new Foo54).prop = true ? Foo54.prop : Foo54.prop; assert(Foo54.y == 6); } /**************************************/ void test55() { dchar c; c = 'x'; //writefln("c = '%s', c.init = '%s'", c, c.init); assert(c == 'x'); assert(c.init == dchar.init); } /**************************************/ void writefln(string s) { printf("%.*s\n", s.length, s.ptr); } void test56() { string a = "abcd"; string r; r = a.dup.reverse.idup; writefln(r); assert(r == "dcba"); a = "a\u1235\u1234c"; writefln(a); r = a.dup.reverse.idup; writefln(r); assert(r == "c\u1234\u1235a"); a = "ab\u1234c"; writefln(a); r = a.dup.reverse.idup; writefln(r); assert(r == "c\u1234ba"); } /**************************************/ // DMD 0.114: Fixed .reverse bug of char[] and wchar[] with multibyte encodings. void test57() { wstring a = "abcd"; wchar[] r; r = a.dup.reverse; assert(r == "dcba"); a = "a\U00012356\U00012346c"; r = a.dup.reverse; assert(r == "c\U00012346\U00012356a"); a = "ab\U00012345c"; r = a.dup.reverse; assert(r == "c\U00012345ba"); } /**************************************/ void test58() { int label=1; if (0) { label: int label2=2; assert(label2==2); } else { assert(label==1); goto label; } assert(label==1); } /**************************************/ void test59() { if(0){ label: return; }else{ goto label; } assert(0); } /**************************************/ int main(string[] argv) { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test50(); test51(); test52(); test53(); test54(); test55(); test56(); test57(); test58(); test59(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/link2500.d0000664000175000017500000000037412776215022021621 0ustar kaikai// EXTRA_SOURCES: imports/link2500a.d // EXTRA_SOURCES: imports/link2500b.d // COMPILE_SEPARATELY: module link2500; import imports.link2500a; import imports.link2500b; public class A { S!A c; } void main() { A a = new A(); a.c.foo(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/ldc_github_1033.d0000664000175000017500000000033712776215022023126 0ustar kaikaivoid main() { import std.container; auto a = Array!int(0, 1, 2, 3, 4, 5, 6, 7, 8); a.linearRemove(a[4 .. 6]); import std.stdio : writeln; writeln(a); assert(a == Array!int(0, 1, 2, 3, 6, 7, 8)); }ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test28.d0000664000175000017500000004631412776215022021512 0ustar kaikaimodule test; import core.vararg; import std.stdio; import std.string; extern(C) int printf(const char*, ...); /*******************************************/ struct S1 { void* function(void*) fn; } template M1() { S1 s; } void test1() { S1 s2; mixin M1; assert(s.fn == null); } /*******************************************/ enum Qwert { yuiop } int asdfg(Qwert hjkl) { return 1; } int asdfg(uint zxcvb) { return 2; } void test2() { int nm = 2; assert(asdfg(nm) == 2); assert(asdfg(cast(int) nm) == 2); assert(asdfg(3) == 2); assert(asdfg(cast(int) 3) == 2); assert(asdfg(3L) == 2); assert(asdfg(cast(int) 3L) == 2); assert(asdfg(3 + 2) == 2); assert(asdfg(cast(int) (3 + 2)) == 2); assert(asdfg(nm + 2) == 2); assert(asdfg(cast(int) (nm + 2)) == 2); assert(asdfg(3 + nm) == 2); assert(asdfg(cast(int) (3 + nm)) == 2); } /*******************************************/ template Qwert3(string yuiop) { immutable string Qwert3 = cast(string)yuiop; } template Asdfg3(string yuiop) { immutable string Asdfg3 = cast(string)Qwert3!(cast(string)(cast(string)yuiop ~ cast(string)"hjkl")); } void test3() { string zxcvb = Asdfg3!(null); assert(zxcvb == "hjkl"); assert(zxcvb == "hjkl" ~ null); } /*******************************************/ template Qwert4(string yuiop) { immutable string Qwert4 = cast(string)(yuiop ~ "asdfg" ~ yuiop); } void test4() { string hjkl = Qwert4!(null); assert(hjkl == "asdfg"); } /*******************************************/ void test6() { struct Foo { void foo() { } } alias Foo Bar; Bar a; a.foo(); } /*******************************************/ void test7() { struct Foo { alias typeof(this) ThisType; alias typeof(this) ThatType; } assert(is(Foo.ThisType == Foo)); assert(is(Foo.ThatType == Foo)); } /*******************************************/ void test8() { int[] test; test.length = 10; // Show address of array start and its length (10) writefln("%s %s", cast(uint)test.ptr, test.length); test.length = 1; // Show address of array start and its length (1) writefln("%s %s", cast(uint)test.ptr, test.length); test.length = 8; // Show address of array start and its length (8) writefln("%s %s", cast(uint)test.ptr, test.length); test.length = 0; // Shows 0 and 0! writefln("%s %s", cast(uint)test.ptr, test.length); assert(test.length == 0); assert(test.ptr != null); } /*******************************************/ cdouble y9; cdouble f9(cdouble x) { return (y9 = x); } void test9() { f9(1.0+2.0i); assert(y9 == 1.0+2.0i); } /*******************************************/ class CBase10 { this() { } } void foo10( CBase10 l ) { } void test10() { if (1) { foo10( new class() CBase10 { this() { super(); } } ); } return; } /*******************************************/ struct Foo11 { static int func(T)(T a) { assert(a == 1); return 0; } } void test11() { auto a = Foo11.init.func(1); a = Foo11.init.func!(int)(1); a = Foo11.func(1); a = Foo11.func!(int)(1); } /*******************************************/ void test12() { class ExceptioN { } class ExceptioX { } static assert(ExceptioN.mangleof[0 ..$-1] == ExceptioX.mangleof[0 .. $-1]); } /*******************************************/ template check( char ch1, char ch2) { const bool check = ch1 == ch2; } void test13() { const char[] s = "123+456" ; assert(check!( '+', s[3] ) == true); } /*******************************************/ void test14() { static const char[] test=['a','b','c','d']; static assert(test==['a','b','c','d']); static assert(['a','b','c','d']== test); } /*******************************************/ void func15(...) in { writefln("Arguments len = %d\n", _arguments.length); assert(_arguments.length == 2); } body { } void test15() { func15(1, 2); } /*******************************************/ void test17() { void delegate() y = { }; y(); } /*******************************************/ abstract class Pen { int foo(); } class Penfold : Pen { override int foo() { return 1; } } class Pinky : Pen { override int foo() { return 2; } } class Printer { void vprint(Pen obj) { assert(obj.foo() == 1 || obj.foo() == 2); } C print(C)(C obj) { assert(obj.foo() == 1 || obj.foo() == 2); return obj; } } void test18() { Printer p = new Printer; p.print(new Pinky); p.print(new Penfold); with (p) { vprint(new Pinky); vprint(new Penfold); print!(Pinky)(new Pinky); print!(Penfold)(new Penfold); p.print(new Pinky); p.print(new Penfold); print(new Pinky); print(new Penfold); } } /*******************************************/ class A19 { void s() {} } class B19 : A19 { alias A19.s s; static void s(int i) {} override void s() {} } class C19 { void f() { B19.s(0); } } void test19() { } /*******************************************/ class U {} class T : U {} void test20() { T* ptr; T[2] sar; T[] dar; // all of the following should work according to the "Implicit // Conversions" section of the spec tPtr(ptr); tPtr(sar.ptr); tPtr(dar.ptr); tDar(sar); // uPtr(ptr); // T* => U* // uPtr(sar); // T[2] => U* // uPtr(dar); // T[] => U* // uSar(sar); // T[2] => U[2] // uDar(sar); // T[2] => U[] uDar(dar); // T[] => const(U)[] vPtr(ptr); // T* => void* vPtr(sar.ptr); vPtr(dar.ptr); vDar(sar); vDar(dar); // works, but T[] => void[] isn't mentioned in the spec } void tPtr(T*t){} void tDar(T[]t){} void uPtr(U*u){} void uSar(U[2]u){} void uDar(const(U)[]u){} void vPtr(void*v){} void vDar(void[]v){} /*******************************************/ struct Foo21 { int i; } template some_struct_instance(T) { static Foo21 some_struct_instance = { 5, }; } void test21() { alias some_struct_instance!(int) inst; assert(inst.i == 5); } /*******************************************/ struct Foo22(T) {} void test22() { int i; if ((Foo22!(char)).init == (Foo22!(char)).init) i = 1; assert(i == 1); } /*******************************************/ void test23() { auto t=['a','b','c','d']; writeln(typeid(typeof(t))); assert(is(typeof(t) == char[])); const t2=['a','b','c','d','e']; writeln(typeid(typeof(t2))); assert(is(typeof(t2) == const(const(char)[]))); } /*******************************************/ int foo24(int i ...) { return i; } void test24() { assert(foo24(3) == 3); } /*******************************************/ void test25() { ireal x = 4.0Li; ireal y = 4.0Li; ireal z = 4Li; creal c = 4L + 0Li; } /*******************************************/ struct Foo26 { int a; static Foo26 opCall(int i) { Foo26 f; f.a += i; return f; } } void test26() { Foo26 f; f = cast(Foo26)3; assert(f.a == 3); Foo26 g = 3; assert(g.a == 3); } /*******************************************/ struct S27 { int x; void opAssign(int i) { x = i + 1; } } void test27() { S27 s; s = 1; assert(s.x == 2); } /*******************************************/ class C28 { int x; void opAssign(int i) { x = i + 1; } } void test28() { // No longer supported for 2.0 // C28 s = new C28; // s = 1; // assert(s.x == 2); } /*******************************************/ struct S29 { static S29 opCall(int v) { S29 result; result.v = v; return result; } int a; int v; int x,y,z; } int foo29() { auto s = S29(5); return s.v; } void test29() { int i = foo29(); printf("%d\n", i); assert(i == 5); } /*******************************************/ struct S30 { static S30 opCall(int v) { S30 result; void bar() { result.v += 1; } result.v = v; bar(); return result; } int a; int v; int x,y,z; } int foo30() { auto s = S30(5); return s.v; } void test30() { int i = foo30(); printf("%d\n", i); assert(i == 6); } /*******************************************/ struct S31 { static void abc(S31 *r) { r.v += 1; } static S31 opCall(int v) { S31 result; void bar() { abc(&result); } result.v = v; bar(); return result; } int a; int v; int x,y,z; } int foo31() { auto s = S31(5); return s.v; } void test31() { int i = foo31(); printf("%d\n", i); assert(i == 6); } /*******************************************/ struct T32 { int opApply(int delegate(ref int i) dg) { int i; return dg(i); } } struct S32 { static void abc(S32 *r) { r.v += 1; } static S32 opCall(int v) { S32 result; T32 t; result.v = v; foreach (i; t) { result.v += 1; break; } return result; } int a; int v; int x,y,z; } int foo32() { auto s = S32(5); return s.v; } void test32() { int i = foo32(); printf("%d\n", i); assert(i == 6); } /*******************************************/ class Confectionary { this(int sugar) { //if (sugar < 500) // tastiness = 200; //for (int i = 0; i < 10; ++i) // tastiness = 300; //int[] tastinesses_array; //foreach (n; tastinesses_array) // tastiness = n; //int[int] tastinesses_aa; //foreach (n; tastinesses_aa) // tastiness = n; tastiness = 1; } const int tastiness; } void test33() { } /*******************************************/ template a34(string name, T...) { string a34(string name,T t) { string localchar; foreach (a34; T) { writefln(`hello`); localchar ~= a34.mangleof; } return localchar; } } void test34() { writeln(a34!("Adf"[], typeof("adf"),uint)("Adf"[],"adf",1234)); } /*******************************************/ template a35(string name, T...) { int a35(M...)(M m) { return 3; } } void test35() { assert(a35!("adf")() == 3); } /*******************************************/ template a36(AnotherT,string name,T...){ AnotherT a36(M...)(M){ AnotherT localchar; foreach(a;T) { writefln(`hello`); localchar~=a.mangleof; } return cast(AnotherT)localchar; } } void test36() { string b="adf"; uint i=123; char[3] c="Adf"; writeln(a36!(typeof(b),"Adf")()); } /*******************************************/ struct Q37 { Y37 opCast() { return Y37.init; } } struct Y37 { Q37 asdfg() { return Q37.init; } void hjkl() { Q37 zxcvb = asdfg(); // line 13 } } void test37() { } /*******************************************/ class C38 { } const(Object)[] foo38(C38[3] c) { const(Object)[] x = c; return x; } void test38() { } /*******************************************/ void test39() { void print(string[] strs) { writeln(strs); assert(format("%s", strs) == `["Matt", "Andrew"]`); } print(["Matt", "Andrew"]); } /*******************************************/ void test40() { class C { Object propName() { return this; } } auto c = new C; with (c.propName) { writeln(toString()); } auto foo = c.propName; } /*******************************************/ void test41() { auto test = new char [2]; int x1, x2, x3; char[] foo1() { x1++; return test; } int foo2() { x2++; return 0; } int foo3() { x3++; return 1; } test [] = 'a'; test = test [0 .. 1]; foo1() [foo2() .. foo3()] = 'b'; assert(x1 == 1); assert(x2 == 1); assert(x3 == 1); //test [0 .. 2] = 'b'; // this line should assert writef ("%s\n", test.ptr [0 .. 2]); } /*******************************************/ void test42() { struct X { int x; } X x; assert(x.x == 0); x = x.init; assert(x.x == 0); } /*******************************************/ struct A43 { static const MY_CONST_STRING = "hello"; void foo() { // This will either print garbage or throw a UTF exception. // But if never_called() is commented out, then it will work. writefln("%s", MY_CONST_STRING); } } void never_called43() { // This can be anything; there just needs to be a reference to // A43.MY_CONST_STRING somewhere. writefln("%s", A43.MY_CONST_STRING); } void test43() { A43 a; a.foo(); } /*******************************************/ class A44 { static const MY_CONST_STRING = "hello"; this() { // This will either print garbage or throw a UTF exception. // But if never_called() is commented out, then it will work. writefln("%s", MY_CONST_STRING); } } void never_called44() { // This can be anything; there just needs to be a reference to // A44.MY_CONST_STRING somewhere. writefln("%s", A44.MY_CONST_STRING); } void test44() { A44 a = new A44(); } /*******************************************/ class C45 { void func(lazy size_t x) { (new C45).func(super.toHash()); } } void test45() { } /*******************************************/ template T46(double v) { double T46 = v; } void test46() { double g = T46!(double.nan) + T46!(-double.nan); } /*******************************************/ void test47() { uint* where = (new uint[](5)).ptr; where[0 .. 5] = 1; assert(where[2] == 1); where[0 .. 0] = 0; assert(where[0] == 1); assert(where[2] == 1); } /*******************************************/ void test48() { Object o = new Object(); printf("%.*s\n", typeof(o).classinfo.name.length, typeof(o).classinfo.name.ptr); printf("%.*s\n", (typeof(o)).classinfo.name.length, (typeof(o)).classinfo.name.ptr); printf("%.*s\n", (Object).classinfo.name.length, (Object).classinfo.name.ptr); } /*******************************************/ void test49() { foo49(); } void foo49() { char[] bar; assert(true, bar ~ "foo"); } /*******************************************/ void test50() { foo50("foo"); } void foo50(string bar) { assert(true, bar ~ "foo"); } /*******************************************/ struct Foo51 { static Foo51 opCall() { return Foo51.init; } private char[] _a; private bool _b; } void test51() { } /*******************************************/ template A52(T ...) { } mixin A52!(["abc2", "def"]); void test52() { } /*******************************************/ enum: int { AF_INET53 = 2, PF_INET53 = AF_INET53, } enum: int { SOCK_STREAM53 = 1, } struct sockaddr_in53 { int sin_family = AF_INET53; } enum AddressFamily53: int { INET = AF_INET53, } enum SocketType53: int { STREAM = SOCK_STREAM53, } class Socket53 { this(AddressFamily53 af, SocketType53 type) { } } void test53() { new Socket53(AddressFamily53.INET, SocketType53.STREAM); } /*******************************************/ void test54() { int[2][] a; a ~= [1,2]; assert(a.length == 1); assert(a[0][0] == 1); assert(a[0][1] == 2); } /*******************************************/ void test55() { float[][] a = new float [][](1, 1); if((a.length != 1) || (a[0].length != 1)){ assert(0); } if (a[0][0] <>= 0.0){ assert(0); } } /*******************************************/ void test58() { struct S { int i; int[4] bar = 4; float[4] abc; } static S a = {i: 1}; static S b; writefln("a.bar: %s, %s", a.bar, a.abc); assert(a.i == 1); assert(a.bar[0] == 4); assert(a.bar[1] == 4); assert(a.bar[2] == 4); assert(a.bar[3] == 4); writefln("b.bar: %s, %s", b.bar, b.abc); assert(b.i == 0); assert(b.bar[0] == 4); assert(b.bar[1] == 4); assert(b.bar[2] == 4); assert(b.bar[3] == 4); } /*******************************************/ void bug59(string s)() { writeln(s); writeln(s.length); } void test59() { bug59!("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234")(); } /*******************************************/ class Foo60(T) { this() { unknown_identifier; } } void test60() { bool foobar = is( Foo60!(int) ); assert(!foobar); } /*******************************************/ void repeat( int n, void delegate() dg ) { printf("n = %d\n", n); if( n&1 ) dg(); if( n/2 ) repeat( n/2, {dg();dg();} ); } void test61() { repeat( 10, {printf("Hello\n");} ); } /*******************************************/ void test62() { Vector62 a; a.set(1,2,24); a = a * 2; writeln(a.x, a.y, a.z); assert(a.x == 2); assert(a.y == 4); assert(a.z == 48); } struct Vector62 { float x,y,z; // constructor void set(float _x, float _y, float _z) { x = _x; y = _y; z = _z; } Vector62 opMul(float s) { Vector62 ret; ret.x = x*s; ret.y = y*s; ret.z = z*s; return ret; } } /*******************************************/ struct Data63 { int x, y; /// To make size > 8 so NRVO is used. /// Program runs correctly with this line commented out: byte filler; } Data63 frob(ref Data63 d) { Data63 ret; ret.y = d.x - d.y; ret.x = d.x + d.y; return ret; } void test63() { Data63 d; d.x = 1; d.y = 2; d = frob(d); writeln(d.x); writeln(d.y); assert(d.x == 3 && d.y == -1); } /*******************************************/ class Foo64 { this() { writefln("Foo64 created"); } ~this() { writefln("Foo64 destroyed"); } } template Mix64() { void init() { ptr = new Foo64; } Foo64 ptr; } class Container64 { this() { init(); } mixin Mix64; } void test64() { auto x = new Container64; assert(!(x.classinfo.flags & 2)); } /*******************************************/ struct Vector65(T, uint dim) { T[dim] data; } T dot65(T, uint dim)(Vector65!(T,dim) a, Vector65!(T,dim) b) { T tmp; for ( int i = 0; i < dim; ++i ) tmp += a.data[i] * b.data[i]; return tmp; } void test65() { Vector65!(double,3u) a,b; auto t = dot65(a,b); } /*******************************************/ void main() { printf("Start\n"); test1(); test2(); test3(); test4(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test17(); test18(); test19(); test20(); test21(); test22(); test23(); test24(); test25(); test26(); test27(); test28(); test29(); test30(); test31(); test32(); test33(); test34(); test35(); test36(); test37(); test38(); test39(); test40(); test41(); test42(); test43(); test44(); test45(); test46(); test47(); test48(); test49(); test50(); test51(); test52(); test53(); test54(); test55(); test58(); test59(); test60(); test61(); test62(); test63(); test64(); test65(); printf("Success\n"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/test40.d0000664000175000017500000000027512776215022021500 0ustar kaikai// EXTRA_SOURCES: imports/test40a.d // PERMUTE_ARGS: // REQUIRED_ARGS: import std.stdio; import imports.test40a; class Foo { mixin Mix; } void main() { Bar.foobar(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/0000775000175000017500000000000012776215022022427 5ustar kaikaildc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/cov2-postscript.sh0000775000175000017500000000101112776215022026040 0ustar kaikai#!/usr/bin/env bash # trim off the last line which contains the path of the file which differs between windows and non-windows LINE_COUNT_MINUS_1=$(( `wc -l < ${RESULTS_DIR}/runnable/runnable-cov2.lst` - 1 )) head -n${LINE_COUNT_MINUS_1} ${RESULTS_DIR}/runnable/runnable-cov2.lst > ${RESULTS_DIR}/runnable/runnable-cov2.lst2 diff --strip-trailing-cr runnable/extra-files/runnable-cov2.lst ${RESULTS_DIR}/runnable/runnable-cov2.lst2 if [ $? -ne 0 ]; then exit 1 fi rm ${RESULTS_DIR}/runnable/runnable-cov2.lst{,2} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/objc_objc_msgSend.m0000664000175000017500000000142612776215022026202 0ustar kaikai#import typedef struct { int a, b, c, d, e; } Struct; @interface stret : NSObject -(Struct) getValue; @end @implementation stret -(Struct) getValue { Struct s = { 3, 3, 3, 3, 3 }; return s; } @end @interface fp2ret : NSObject -(_Complex long double) getValue; @end @implementation fp2ret -(_Complex long double) getValue { return 1+3i; } @end @interface fpret : NSObject -(long double) getValue; @end @implementation fpret -(long double) getValue { return 0.000000000000000002L; } @end @interface float32 : NSObject -(float) getValue; @end @implementation float32 -(float) getValue { return 0.2f; } @end @interface double64 : NSObject -(double) getValue; @end @implementation double64 -(double) getValue { return 0.2; } @end ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/test10567.d0000664000175000017500000000051412776215022024156 0ustar kaikaiimport test10567a; template TypeTuple(TL...) { alias TL TypeTuple; } void main() { foreach (BigInt; TypeTuple!(BigInt1, BigInt2, BigInt3)) { auto i = BigInt([100]); auto j = BigInt([100]); assert(typeid(BigInt).equals(&i, &j) == true); assert(typeid(BigInt).compare(&i, &j) == 0); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/lib15729.d0000664000175000017500000000016512776215022023754 0ustar kaikaistruct S { uint val; } void test1() { S s; s.val = 4321; } void test2() { S s; s.val = 1234; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/sieve-postscript.sh0000775000175000017500000000101712776215022026310 0ustar kaikai#!/usr/bin/env bash # trim off the last line which contains the path of the file which differs between windows and non-windows LINE_COUNT_MINUS_1=$(( `wc -l < ${RESULTS_DIR}/runnable/runnable-sieve.lst` - 1 )) head -n${LINE_COUNT_MINUS_1} ${RESULTS_DIR}/runnable/runnable-sieve.lst > ${RESULTS_DIR}/runnable/runnable-sieve.lst2 diff --strip-trailing-cr runnable/extra-files/runnable-sieve.lst ${RESULTS_DIR}/runnable/runnable-sieve.lst2 if [ $? -ne 0 ]; then exit 1 fi rm ${RESULTS_DIR}/runnable/runnable-sieve.lst{,2} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/link14834a.d0000664000175000017500000000163412776215022024302 0ustar kaikaimodule link14834a; struct DirIterator { int i = 1; @property bool empty() { return i == 0; } @property int front() { return 10; } void popFront() { --i; } } auto dirEntries(string path) { bool f(int x) { assert(path == "."); // should pass return true; } return filter!f(DirIterator()); } template filter(alias pred) { auto filter(R)(R range) { return FilterResult!(pred, R)(range); } } struct FilterResult(alias pred, R) { R input; this(R r) { input = r; while (!input.empty && !pred(input.front)) { input.popFront(); } } @property bool empty() { return input.empty; } @property auto ref front() { return input.front; } void popFront() { do { input.popFront(); } while (!input.empty && !pred(input.front)); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/hello-profile.d.trace.def0000664000175000017500000000004512776215022027166 0ustar kaikai FUNCTIONS _D5hello8showargsFAAyaZv ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/test_shared.d0000664000175000017500000000002012776215022025071 0ustar kaikaivoid main() { } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/depsprot.d0000664000175000017500000000013112776215022024427 0ustar kaikaiimport depsprot_default; private import depsprot_private; public import depsprot_public; ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/objc_self_test.m0000664000175000017500000000035712776215022025577 0ustar kaikai#import @interface objc_self_test : NSObject -(int) getValue; @end @implementation objc_self_test -(int) getValue { return 3; } @end int getValue () { return [[[objc_self_test alloc] init] getValue]; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/runnable-cov2.lst0000664000175000017500000000312612776215022025632 0ustar kaikai |// PERMUTE_ARGS: |// POST_SCRIPT: runnable/extra-files/cov2-postscript.sh |// REQUIRED_ARGS: -cov |// EXECUTE_ARGS: ${RESULTS_DIR}/runnable | |extern(C) void dmd_coverDestPath(string pathname); | |/***************************************************/ | |void test1() |{ 1| int counter = 20; | do { 20| --counter; | } 20| while(counter > 0); |} | |/***************************************************/ | |struct S2 |{ 2| this(this) { int x = 1; } 3| ~this() { int x = 1; } 00000000| ref S2 opAssign(S2) { return this; } 1| bool opEquals(ref const S2) const { return true; } |} |struct T2 |{ | S2 s; | 2| this(this) { int x = 1; } 3| ~this() { int x = 1; } |} |void test2() |{ 2| T2 ta; 2| T2 tb = ta; 1| tb = ta; 1| typeid(T2).equals(&ta, &tb); |} | |/***************************************************/ | |void test3() |{ 1| long total = 0; 20000002| for (size_t i = 0; i < 10_000_000; i++) 10000000| total += i; |} | |/***************************************************/ | |int main(string[] args) |{ 1| dmd_coverDestPath(args[1]); 1| test1(); 1| test2(); 1| test3(); 1| return 0; |} | ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/mul9377a.d0000664000175000017500000000016112776215022024062 0ustar kaikaiimport core.stdc.stdio; import mul9377b; void abc() { printf("mul9377b.abc()\n"); foo(); bar(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/multi9377.d0000664000175000017500000000025412776215022024261 0ustar kaikaiimport core.stdc.stdio; import mul9377a, mul9377b; int main() { printf("main\n"); abc(); def!().mem(); pragma(msg, def!().mem.mangleof); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/foo37.txt0000664000175000017500000000001412776215022024120 0ustar kaikaihello betty ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/linkdebug_primitives.d0000664000175000017500000000032312776215022027011 0ustar kaikaimodule linkdebug_primitives; size_t popBackN(R)(ref R r, size_t n) { n = cast(size_t) (n < r.length ? n : r.length); r = r[0 .. $ - n]; return n; } auto moveAt(R, I)(R r, I i) { return r[i]; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/a20-postscript.sh0000775000175000017500000000107112776215022025557 0ustar kaikai#!/usr/bin/env bash # trim off the last line which contains the path of the file which differs between windows and non-windows LINE_COUNT_MINUS_1=$(( `wc -l < ${RESULTS_DIR}/runnable/runnable-a20.lst` - 1 )) head -n${LINE_COUNT_MINUS_1} ${RESULTS_DIR}/runnable/runnable-a20.lst > ${RESULTS_DIR}/runnable/runnable-a20.lst2 diff --strip-trailing-cr runnable/extra-files/runnable-a20.lst ${RESULTS_DIR}/runnable/runnable-a20.lst2 if [ $? -ne 0 ]; then exit 1; fi rm ${RESULTS_DIR}/runnable/runnable-a20.lst{,2} rm ${RESULTS_DIR}/runnable/runnable-imports-a20a.lst ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/lib10386/0000775000175000017500000000000012776215022023577 5ustar kaikaildc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/lib10386/foo/0000775000175000017500000000000012776215022024362 5ustar kaikaildc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/lib10386/foo/package.d0000664000175000017500000000006612776215022026124 0ustar kaikaimodule lib10386.foo; public import lib10386.foo.bar; ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/lib10386/foo/bar.d0000664000175000017500000000010212776215022025264 0ustar kaikaimodule lib10386.foo.bar; void foo(int x) { assert(x == 1); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/lib13774b.d0000664000175000017500000000010312776215022024104 0ustar kaikaimodule lib13774b; import lib13774a; void use2() { comdef(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/gdb15729.d0000664000175000017500000000007412776215022023741 0ustar kaikaiimport lib15729; void main() { test1(); test2(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/test35.d0000664000175000017500000000016412776215022023724 0ustar kaikaiimport imports.test35a; void main() { auto num = removeIf( "abcdef".dup, ( char c ) { return c == 'c'; } ); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/linkdebug.d0000664000175000017500000000040412776215022024536 0ustar kaikaimodule linkdebug; void main() { import linkdebug_uni; import linkdebug_range; // OK //SortedRangeX!(uint[], "a <= b") SR; CodepointSet set; set.addInterval(1, 2); // NG, order dependent. SortedRange!(uint[], "a <= b") SR; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/statictor.d.out0000664000175000017500000000020212776215022025410 0ustar kaikaishared static this() Foo static ctor static ctor Bar static ctor Bar static dtor static dtor Foo static dtor shared static this() ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/test44.d0000664000175000017500000000075112776215022023726 0ustar kaikai import imports.test44a; const char[][7] DAY_NAME = [ DAY.SUN: "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ]; void main() { assert(DAY_NAME[DAY.SUN] == "sunday"); assert(DAY_NAME[DAY.MON] == "monday"); assert(DAY_NAME[DAY.TUE] == "tuesday"); assert(DAY_NAME[DAY.WED] == "wednesday"); assert(DAY_NAME[DAY.THU] == "thursday"); assert(DAY_NAME[DAY.FRI] == "friday"); assert(DAY_NAME[DAY.SAT] == "saturday"); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/externmangle.cpp0000664000175000017500000001273512776215022025634 0ustar kaikai#include template struct Foo { X *v; }; template struct Boo { X *v; }; void test1(Foo arg1) { } void test2(int* arg2, Boo arg1) { } template struct Test3 { }; void test3(Test3<3,3> arg1) { } void test4(Foo arg1, Boo arg2, Boo arg3, int*, Foo) { } void test5(Foo arg1, Boo arg2, Boo arg3) { } struct Goo { template struct Foo { X* v; }; template struct Boo { template struct Xoo { Y* v; }; X* v; }; void test6(Foo > > arg1); void test7(Boo::Xoo arg1); }; void Goo::test6(Goo::Foo > > arg1) { } void Goo::test7(Goo::Boo::Xoo arg1) { } struct P1 { template struct Mem { }; }; struct P2 { template struct Mem { }; }; void test8(P1::Mem, P2::Mem){} void test9(Foo, Foo, int**, int*){} class Test10 { private: void test10(); public: void test11(); protected: void test12(); public: void test13() const; private: void test14(); // Private methods in D are always non-virtual public: virtual void test15(); protected: virtual void test16(); private: static void test17(); public: static void test18(); protected: static void test19(); }; Test10* Test10Ctor() { return new Test10(); } void Test10Dtor(Test10*& ptr) { delete ptr; ptr = 0; } void Test10::test10(){} void Test10::test11(){} void Test10::test12(){} void Test10::test13() const{} void Test10::test14(){} void Test10::test15(){} void Test10::test16(){} void Test10::test17(){} void Test10::test18(){} void Test10::test19(){} struct Test20 { private: static int test20; protected: static int test21; public: static int test22; }; int Test20::test20 = 20; int Test20::test21 = 21; int Test20::test22 = 22; int test23(Test10**, Test10*, Test10***, Test10 const *const) { return 1; } int test23b(Test10 const *const *const, Test10 const* const, Test10*) { return 1; } void test24(int(*)(int,int)) { } void test25(int arr[2][5][6][291]) { } int test26(int arr[5][6][291]) { return arr[1][1][1]; } void test27(int, ...){} void test28(int){} void test29(float){} void test30(const float){} template struct Array { int dim; }; class Module { public: static void imports(Module*); static int dim(Array*); }; void Module::imports(Module*) { } int Module::dim(Array* arr) { return arr->dim; } #if _LP64 unsigned long testlongmangle(int32_t a, uint32_t b, long c, unsigned long d) { return a + b + c + d; } #else unsigned long long testlongmangle(int a, unsigned int b, long long c, unsigned long long d) { return a + b + c + d; } #endif int test31[2][2][2] = {1, 1, 1, 1, 1, 1, 1, 1}; int *test32 = 0; class Expression; typedef int (*apply_fp_t)(Expression*, void*); class Expression { int type; public: int apply(apply_fp_t fp, apply_fp_t fp2, void *param); int getType(); static Expression* create(int v); static void dispose(Expression*&); }; int Expression::apply(apply_fp_t fp, apply_fp_t fp2, void *param) { return fp(this, param) * fp2(this, param); } int Expression::getType() { return type; } Expression* Expression::create(int v) { Expression *e = new Expression(); e->type = v; return e; } void Expression::dispose(Expression *&e) { if (e) delete e; e = 0; } /*int test34(int v[0][0][0]) { return 0; }*/ #ifndef _MSC_VER int test35(long double arg) { return (int)arg; } #endif const char *test36(const char *arg) { return arg; } class Test37 { public: static Test37 *create(); bool test(); }; bool test37() { Test37 *o = Test37::create(); return o->test(); } class Test38 { public: int test(int, ...); static Test38* create(); static void dispose(Test38*&); }; int Test38::test(int a, ...) { return a; } Test38* Test38::create() { Test38 *t = new Test38(); return t; } void Test38::dispose(Test38 *&t) { if (t) delete t; t = 0; } class S1 { int val; public: static S1* init(int); S1(int v) : val(v) {} int value(); }; S1* S1::init(int x) { return new S1(x); } int S1::value() { return val; } template class S2 { T val; public: static S2* init(T); S2(T v) : val(v) {} T value(); }; template<> S2* S2::init(int x) { return new S2(x); } template<> int S2::value() { return val; } struct C1 { const char *data; static C1* init(const char *p); C1(const char* p) : data(p) { } virtual const char* getDataCPP(); virtual const char* getDataD(); }; C1* C1::init(const char *p) { return new C1(p); } const char* C1::getDataCPP() { return data; } template struct C2 { const T *data; static C2* init(const T *p); C2(const T* p) : data(p) { } virtual const T* getData(); }; template<> C2* C2::init(const char *p) { return new C2(p); } template<> const char* C2::getData() { return data; } int test39cpp(C2* c2, S2* s2) { C2* otherC2 = C2::init(c2->getData()); if (c2->getData() != otherC2->getData()) return 1; S2* otherS2 = S2::init(s2->value()); if (s2->value() != otherS2->value()) return 2; return 0; }ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/mul9377b.d0000664000175000017500000000067612776215022024076 0ustar kaikaimodule mul9377b; import core.stdc.stdio; int j; int foo()() { printf("foo()\n"); static int z = 7; assert(z != 10); return ++z; } void bar() { assert(j == 7); foo(); printf("bar\n"); } template def() { alias int defint; static this() { printf("def.static this()\n"); j = 7; } //void mem(int){} void mem() { printf("def().mem()\n"); } } def!().defint x; ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/std14198/0000775000175000017500000000000012776215022023630 5ustar kaikaildc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/std14198/array.d0000664000175000017500000000056412776215022025120 0ustar kaikaimodule std14198.array; version(bug14198) { } else import std14198.uni; struct Appender(A) { alias T = immutable char; void put(U)(U item) if ( is(U : T) || is(immutable U == immutable char) ) { import std14198.uni; // necessary assert(0); } } Appender!A appender(A)() { return Appender!A(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/std14198/conv.d0000664000175000017500000000103312776215022024737 0ustar kaikaimodule std14198.conv; template to(T) { T to(A...)(A args) { return toImpl!T(args); } } T toImpl(T, S)(S value) if (is(S : T)) { return value; } T toImpl(T, S)(S value) if (!is(S : T) && is(T == string)) { alias src = value; import std14198.format : FormatSpec; import std14198.array : appender; auto w = appender!T(); FormatSpec!char f; // necessary string str = src ? "true" : "false"; for (; !str.length; str = str[1..$]) w.put(str[0]); return ""; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/std14198/format.d0000664000175000017500000000026512776215022025270 0ustar kaikaimodule std14198.format; struct FormatSpec(Char) if (is(Char == char)) { import std14198.conv; string toString() { return to!string(true); // necessary } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/std14198/uni.d0000664000175000017500000000026512776215022024573 0ustar kaikaimodule std14198.uni; alias CodepointSet = InversionList!(); struct InversionList() { import std14198.format; void toString(FormatSpec!char fs) // necessary { } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/test10567a.d0000664000175000017500000000163212776215022024321 0ustar kaikaistruct BigInt1 { int[] dara; bool opEquals(const ref BigInt1 rhs) const // -> stored in TypeInfo_Struct.xopEquals { return true; } bool opEquals(T)(T rhs) const { return false; } int opCmp(const ref BigInt1 rhs) const // stored in TypeInfo_Struct.xopCmp { return 0; } int opCmp(T)(T rhs) const { return 1; } } struct BigInt2 { int[] dara; bool opEquals(const ref BigInt2 rhs) const // stored in TypeInfo_Struct.xopEquals { return true; } int opCmp(const ref BigInt2 rhs) const // stored in TypeInfo_Struct.xopCmp { return 0; } } struct BigInt3 { int[] dara; bool opEquals(T)(T rhs) const // stored in TypeInfo_Struct.xopEquals { return true; } int opCmp(T)(T rhs) const // stored in TypeInfo_Struct.xopCmp { return 0; } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/runnable-sieve.lst0000664000175000017500000000250512776215022026074 0ustar kaikai |// PERMUTE_ARGS: |// REQUIRED_ARGS: -cov |// POST_SCRIPT: runnable/extra-files/sieve-postscript.sh |// EXECUTE_ARGS: ${RESULTS_DIR}/runnable | |/* Eratosthenes Sieve prime number calculation. */ | |import std.stdio; | |bool flags[8191]; | |int sieve() |{ 1| int count; | 1| writefln("10 iterations"); 22| for (int iter = 1; iter <= 10; iter++) | { 10| count = 0; 10| flags[] = true; 163840| for (int i = 0; i < flags.length; i++) | { 81910| if (flags[i]) | { 18990| int prime = i + i + 3; 18990| int k = i + prime; 168980| while (k < flags.length) | { 149990| flags[k] = false; 149990| k += prime; | } 18990| count += 1; | } | } | } 1| writefln("%d primes", count); 1| return 0; |} | |extern(C) void dmd_coverDestPath(string path); | |int main(string[] args) |{ | 1| dmd_coverDestPath(args[1]); | 1| sieve(); | 1| return 0; |} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/runnable-bug9010.lst0000664000175000017500000000111612776215022026045 0ustar kaikai |// PERMUTE_ARGS: |// POST_SCRIPT: runnable/extra-files/bug9010-postscript.sh |// REQUIRED_ARGS: -cov |// EXECUTE_ARGS: ${RESULTS_DIR}/runnable | |struct A |{ | bool opEquals(A o) const | { 1| return false; | } | |} | |extern(C) void dmd_coverDestPath(string pathname); | |void main(string[] args) |{ 1| dmd_coverDestPath(args[1]); | 1| auto a = A(); 1| auto b = A(); 1| assert(a != b); |} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/link14834b.d0000664000175000017500000000015212776215022024275 0ustar kaikaiimport link14834a; void main() { foreach (n; dirEntries(".")) { assert(n == 10); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/cabi2.cpp0000664000175000017500000000704412776215022024120 0ustar kaikai #include #include #include #if __cplusplus extern "C" { #endif struct Foo1 { char c; }; struct Foo1 ctest1() { struct Foo1 f; f.c = 3; return f; } struct Foo2 { short s; }; struct Foo2 ctest2() { struct Foo2 f; f.s = 0x1234; return f; } struct Foo3 { char c; short s; }; struct Foo3 ctest3() { struct Foo3 f; f.s = 0x5678; return f; } struct Foo4 { int i; }; struct Foo4 ctest4() { struct Foo4 f; f.i = 0x12345678; return f; } struct Foo5 { int i, j; }; struct Foo5 ctest5() { struct Foo5 f; f.i = 0x12345678; f.j = 0x21436587; return f; } struct Foo6 { int i, j, k; }; struct Foo6 ctest6() { struct Foo6 f; f.i = 0x12345678; f.j = 0x21463587; f.k = 0x24163857; return f; } struct S7 { float a,b; }; struct S7 ctest10() { struct S7 f; f.a = 2.5; f.b = 1.5; return f; } // ================================= char ctest7(char c) { return c + 1; } unsigned char ctest8(unsigned char c) { return c + 1; } signed char ctest9(signed char c) { return c + 1; } /***********************************************/ void ctestrir(int x1, int x2, int x3, int x4, int x5, int x6, long double a, int b, long double c) { assert(a == 100.0); assert(b == 67); assert(c == 200.0); } /***********************************************/ extern void dtestrir(int x1, int x2, int x3, int x4, int x5, int x6, long double a, int b, long double c); void test4() { dtestrir(1,2,3,4,5,6, 300.0, 68, 401.0); } /**********************************************/ typedef struct S11 { char a; char b; char c; } S11; S11 ctest11(char x, S11 s, char y) { printf("C sz = %d\n", (int)sizeof(S11)); assert(sizeof(S11) == 3); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } /**********************************************/ typedef struct S12 { char a,d; char b,e; char c; } S12; S12 ctest12(char x, S12 s, char y) { printf("C sz = %d\n", (int)sizeof(S12)); assert(sizeof(S12) == 5); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } /**********************************************/ typedef struct S13 { short a; short b; short c; } S13; S13 ctest13(char x, S13 s, char y) { printf("C sz = %d\n", (int)sizeof(S13)); assert(sizeof(S13) == 6); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } /**********************************************/ typedef struct S14 { char a,d,e,f; char b,g; char c; } S14; S14 ctest14(char x, S14 s, char y) { printf("C sz = %d\n", (int)sizeof(S14)); assert(sizeof(S14) == 7); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } /**********************************************/ typedef struct S15 { char a,d,e,f; char b,g,h,i; char c; } S15; S15 ctest15(char x, S15 s, char y) { printf("C sz = %d\n", (int)sizeof(S15)); assert(sizeof(S15) == 9); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } #if __cplusplus } #endif ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/lib13666.d0000664000175000017500000000021312776215022023744 0ustar kaikaimodule lib13666; template drt_envvars() { extern(C) __gshared bool enabled = false; } bool foo() { return drt_envvars!().enabled; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/test14198.d0000664000175000017500000000173512776215022024170 0ustar kaikaimodule test14198; import std14198.conv; struct S { ptrdiff_t function() fptr = &handler; static ptrdiff_t handler() pure @safe { static if (is(typeof(to!string(false)))) { to!string(false); // [1] to!string(bool src) should be deduced to pure @safe, and the function will be mangled to: // --> _D8std141984conv11__T2toTAyaZ9__T2toTbZ2toFNaNbNiNfbZAya // [2] its object code would be stored in the library file, because it's instantiated in std14188.uni: // --> FormatSpec!char --> to!string(bool src) in FormatSpec!char.toString() // But semanti3 of FormatSpec!char.toString() won't get called from this module compilation, // so the instantiaion is invisible. // Then, the object code is also stored in test14198.obj, and the link will succeed. } else static assert(0); return 0; } } void main() { } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/alice30.txt0000664000175000017500000046714312776215022024427 0ustar kaikai***This is the Project Gutenberg Etext of Alice in Wonderland*** *This 30th edition should be labeled alice30.txt or alice30.zip. ***This Edition Is Being Officially Released On March 8, 1994*** **In Celebration Of The 23rd Anniversary of Project Gutenberg*** Please take a look at the important information in this header. We encourage you to keep this file on your own disk, keeping an electronic path open for the next readers. Do not remove this. **Welcome To The World of Free Plain Vanilla Electronic Texts** **Etexts Readable By Both Humans and By Computers, Since 1971** *These Etexts Prepared By Hundreds of Volunteers and Donations* Information on contacting Project Gutenberg to get Etexts, and further information is included below. We need your donations. Alice's Adventures in Wonderland March, 1994 [Etext #11] [Originally released in January, 1991] *****The Project Gutenberg Etext of Alice In Wonderland***** ******This file should be named alice30.txt or alice30.zip****** Corrected EDITIONS of our etexts get a new NUMBER, alice31.txt VERSIONS based on separate sources get new LETTER, alice30a.txt We are now trying to release all our books one month in advance of the official release dates, for time for better editing. We have this as a goal to accomplish by the end of the year but we cannot guarantee to stay that far ahead every month after that. Please note: neither this list nor its contents are final till midnight of the last day of the month of any such announcement. The official release date of all Project Gutenberg Etexts is at Midnight, Central Time, of the last day of the stated month. A preliminary version may often be posted for suggestion, comment and editing by those who wish to do so. To be sure you have an up to date first edition [xxxxx10x.xxx] please check file sizes in the first week of the next month. Since our ftp program has a bug in it that scrambles the date [tried to fix and failed] a look at the file size will have to do, but we will try to see a new copy has at least one byte more or less. Information about Project Gutenberg (one page) We produce about two million dollars for each hour we work. The fifty hours is one conservative estimate for how long it we take to get any etext selected, entered, proofread, edited, copyright searched and analyzed, the copyright letters written, etc. This projected audience is one hundred million readers. If our value per text is nominally estimated at one dollar then we produce $4 million dollars per hour this year as we release some eight text files per month: thus upping our productivity from $2 million. The Goal of Project Gutenberg is to Give Away One Trillion Etext Files by the December 31, 2001. [10,000 x 100,000,000=Trillion] This is ten thousand titles each to one hundred million readers, which is 10% of the expected number of computer users by the end of the year 2001. We need your donations more than ever! All donations should be made to "Project Gutenberg/IBC", and are tax deductible to the extent allowable by law ("IBC" is Illinois Benedictine College). (Subscriptions to our paper newsletter go to IBC, too) For these and other matters, please mail to: Project Gutenberg P. O. Box 2782 Champaign, IL 61825 When all other email fails try our Michael S. Hart, Executive Director: hart@vmd.cso.uiuc.edu (internet) hart@uiucvmd (bitnet) We would prefer to send you this information by email (Internet, Bitnet, Compuserve, ATTMAIL or MCImail). ****** If you have an FTP program (or emulator), please FTP directly to the Project Gutenberg archives: [Mac users, do NOT point and click. . .type] ftp mrcnext.cso.uiuc.edu login: anonymous password: your@login cd etext/etext91 or cd etext92 or cd etext93 [for new books] [now also in cd etext/etext93] or cd etext/articles [get suggest gut for more information] dir [to see files] get or mget [to get files. . .set bin for zip files] GET 0INDEX.GUT for a list of books and GET NEW GUT for general information and MGET GUT* for newsletters. **Information prepared by the Project Gutenberg legal advisor** (Three Pages) ***START**THE SMALL PRINT!**FOR PUBLIC DOMAIN ETEXTS**START*** Why is this "Small Print!" statement here? You know: lawyers. They tell us you might sue us if there is something wrong with your copy of this etext, even if you got it for free from someone other than us, and even if what's wrong is not our fault. So, among other things, this "Small Print!" statement disclaims most of our liability to you. It also tells you how you can distribute copies of this etext if you want to. *BEFORE!* YOU USE OR READ THIS ETEXT By using or reading any part of this PROJECT GUTENBERG-tm etext, you indicate that you understand, agree to and accept this "Small Print!" statement. If you do not, you can receive a refund of the money (if any) you paid for this etext by sending a request within 30 days of receiving it to the person you got it from. If you received this etext on a physical medium (such as a disk), you must return it with your request. ABOUT PROJECT GUTENBERG-TM ETEXTS This PROJECT GUTENBERG-tm etext, like most PROJECT GUTENBERG- tm etexts, is a "public domain" work distributed by Professor Michael S. Hart through the Project Gutenberg Association at Illinois Benedictine College (the "Project"). Among other things, this means that no one owns a United States copyright on or for this work, so the Project (and you!) can copy and distribute it in the United States without permission and without paying copyright royalties. Special rules, set forth below, apply if you wish to copy and distribute this etext under the Project's "PROJECT GUTENBERG" trademark. To create these etexts, the Project expends considerable efforts to identify, transcribe and proofread public domain works. Despite these efforts, the Project's etexts and any medium they may be on may contain "Defects". Among other things, Defects may take the form of incomplete, inaccurate or corrupt data, transcription errors, a copyright or other intellectual property infringement, a defective or damaged disk or other etext medium, a computer virus, or computer codes that damage or cannot be read by your equipment. LIMITED WARRANTY; DISCLAIMER OF DAMAGES But for the "Right of Replacement or Refund" described below, [1] the Project (and any other party you may receive this etext from as a PROJECT GUTENBERG-tm etext) disclaims all liability to you for damages, costs and expenses, including legal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR UNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT, INCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. If you discover a Defect in this etext within 90 days of receiving it, you can receive a refund of the money (if any) you paid for it by sending an explanatory note within that time to the person you received it from. If you received it on a physical medium, you must return it with your note, and such person may choose to alternatively give you a replacement copy. If you received it electronically, such person may choose to alternatively give you a second opportunity to receive it electronically. THIS ETEXT IS OTHERWISE PROVIDED TO YOU "AS-IS". NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS TO THE ETEXT OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimers of implied warranties or the exclusion or limitation of consequential damages, so the above disclaimers and exclusions may not apply to you, and you may have other legal rights. INDEMNITY You will indemnify and hold the Project, its directors, officers, members and agents harmless from all liability, cost and expense, including legal fees, that arise directly or indirectly from any of the following that you do or cause: [1] distribution of this etext, [2] alteration, modification, or addition to the etext, or [3] any Defect. DISTRIBUTION UNDER "PROJECT GUTENBERG-tm" You may distribute copies of this etext electronically, or by disk, book or any other medium if you either delete this "Small Print!" and all other references to Project Gutenberg, or: [1] Only give exact copies of it. Among other things, this requires that you do not remove, alter or modify the etext or this "small print!" statement. You may however, if you wish, distribute this etext in machine readable binary, compressed, mark-up, or proprietary form, including any form resulting from conversion by word pro- cessing or hypertext software, but only so long as *EITHER*: [*] The etext, when displayed, is clearly readable, and does *not* contain characters other than those intended by the author of the work, although tilde (~), asterisk (*) and underline (_) characters may be used to convey punctuation intended by the author, and additional characters may be used to indicate hypertext links; OR [*] The etext may be readily converted by the reader at no expense into plain ASCII, EBCDIC or equivalent form by the program that displays the etext (as is the case, for instance, with most word processors); OR [*] You provide, or agree to also provide on request at no additional cost, fee or expense, a copy of the etext in its original plain ASCII form (or in EBCDIC or other equivalent proprietary form). [2] Honor the etext refund and replacement provisions of this "Small Print!" statement. [3] Pay a trademark license fee to the Project of 20% of the net profits you derive calculated using the method you already use to calculate your applicable taxes. If you don't derive profits, no royalty is due. Royalties are payable to "Project Gutenberg Association / Illinois Benedictine College" within the 60 days following each date you prepare (or were legally required to prepare) your annual (or equivalent periodic) tax return. WHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO? The Project gratefully accepts contributions in money, time, scanning machines, OCR software, public domain etexts, royalty free copyright licenses, and every other sort of contribution you can think of. Money should be paid to "Project Gutenberg Association / Illinois Benedictine College". This "Small Print!" by Charles B. Kramer, Attorney Internet (72600.2026@compuserve.com); TEL: (212-254-5093) *END*THE SMALL PRINT! FOR PUBLIC DOMAIN ETEXTS*Ver.04.29.93*END* ALICE'S ADVENTURES IN WONDERLAND Lewis Carroll THE MILLENNIUM FULCRUM EDITION 3.0 CHAPTER I Down the Rabbit-Hole Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, `and what is the use of a book,' thought Alice `without pictures or conversation?' So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her. There was nothing so VERY remarkable in that; nor did Alice think it so VERY much out of the way to hear the Rabbit say to itself, `Oh dear! Oh dear! I shall be late!' (when she thought it over afterwards, it occurred to her that she ought to have wondered at this, but at the time it all seemed quite natural); but when the Rabbit actually TOOK A WATCH OUT OF ITS WAISTCOAT- POCKET, and looked at it, and then hurried on, Alice started to her feet, for it flashed across her mind that she had never before seen a rabbit with either a waistcoat-pocket, or a watch to take out of it, and burning with curiosity, she ran across the field after it, and fortunately was just in time to see it pop down a large rabbit-hole under the hedge. In another moment down went Alice after it, never once considering how in the world she was to get out again. The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly down, so suddenly that Alice had not a moment to think about stopping herself before she found herself falling down a very deep well. Either the well was very deep, or she fell very slowly, for she had plenty of time as she went down to look about her and to wonder what was going to happen next. First, she tried to look down and make out what she was coming to, but it was too dark to see anything; then she looked at the sides of the well, and noticed that they were filled with cupboards and book-shelves; here and there she saw maps and pictures hung upon pegs. She took down a jar from one of the shelves as she passed; it was labelled `ORANGE MARMALADE', but to her great disappointment it was empty: she did not like to drop the jar for fear of killing somebody, so managed to put it into one of the cupboards as she fell past it. `Well!' thought Alice to herself, `after such a fall as this, I shall think nothing of tumbling down stairs! How brave they'll all think me at home! Why, I wouldn't say anything about it, even if I fell off the top of the house!' (Which was very likely true.) Down, down, down. Would the fall NEVER come to an end! `I wonder how many miles I've fallen by this time?' she said aloud. `I must be getting somewhere near the centre of the earth. Let me see: that would be four thousand miles down, I think--' (for, you see, Alice had learnt several things of this sort in her lessons in the schoolroom, and though this was not a VERY good opportunity for showing off her knowledge, as there was no one to listen to her, still it was good practice to say it over) `--yes, that's about the right distance--but then I wonder what Latitude or Longitude I've got to?' (Alice had no idea what Latitude was, or Longitude either, but thought they were nice grand words to say.) Presently she began again. `I wonder if I shall fall right THROUGH the earth! How funny it'll seem to come out among the people that walk with their heads downward! The Antipathies, I think--' (she was rather glad there WAS no one listening, this time, as it didn't sound at all the right word) `--but I shall have to ask them what the name of the country is, you know. Please, Ma'am, is this New Zealand or Australia?' (and she tried to curtsey as she spoke--fancy CURTSEYING as you're falling through the air! Do you think you could manage it?) `And what an ignorant little girl she'll think me for asking! No, it'll never do to ask: perhaps I shall see it written up somewhere.' Down, down, down. There was nothing else to do, so Alice soon began talking again. `Dinah'll miss me very much to-night, I should think!' (Dinah was the cat.) `I hope they'll remember her saucer of milk at tea-time. Dinah my dear! I wish you were down here with me! There are no mice in the air, I'm afraid, but you might catch a bat, and that's very like a mouse, you know. But do cats eat bats, I wonder?' And here Alice began to get rather sleepy, and went on saying to herself, in a dreamy sort of way, `Do cats eat bats? Do cats eat bats?' and sometimes, `Do bats eat cats?' for, you see, as she couldn't answer either question, it didn't much matter which way she put it. She felt that she was dozing off, and had just begun to dream that she was walking hand in hand with Dinah, and saying to her very earnestly, `Now, Dinah, tell me the truth: did you ever eat a bat?' when suddenly, thump! thump! down she came upon a heap of sticks and dry leaves, and the fall was over. Alice was not a bit hurt, and she jumped up on to her feet in a moment: she looked up, but it was all dark overhead; before her was another long passage, and the White Rabbit was still in sight, hurrying down it. There was not a moment to be lost: away went Alice like the wind, and was just in time to hear it say, as it turned a corner, `Oh my ears and whiskers, how late it's getting!' She was close behind it when she turned the corner, but the Rabbit was no longer to be seen: she found herself in a long, low hall, which was lit up by a row of lamps hanging from the roof. There were doors all round the hall, but they were all locked; and when Alice had been all the way down one side and up the other, trying every door, she walked sadly down the middle, wondering how she was ever to get out again. Suddenly she came upon a little three-legged table, all made of solid glass; there was nothing on it except a tiny golden key, and Alice's first thought was that it might belong to one of the doors of the hall; but, alas! either the locks were too large, or the key was too small, but at any rate it would not open any of them. However, on the second time round, she came upon a low curtain she had not noticed before, and behind it was a little door about fifteen inches high: she tried the little golden key in the lock, and to her great delight it fitted! Alice opened the door and found that it led into a small passage, not much larger than a rat-hole: she knelt down and looked along the passage into the loveliest garden you ever saw. How she longed to get out of that dark hall, and wander about among those beds of bright flowers and those cool fountains, but she could not even get her head though the doorway; `and even if my head would go through,' thought poor Alice, `it would be of very little use without my shoulders. Oh, how I wish I could shut up like a telescope! I think I could, if I only know how to begin.' For, you see, so many out-of-the-way things had happened lately, that Alice had begun to think that very few things indeed were really impossible. There seemed to be no use in waiting by the little door, so she went back to the table, half hoping she might find another key on it, or at any rate a book of rules for shutting people up like telescopes: this time she found a little bottle on it, (`which certainly was not here before,' said Alice,) and round the neck of the bottle was a paper label, with the words `DRINK ME' beautifully printed on it in large letters. It was all very well to say `Drink me,' but the wise little Alice was not going to do THAT in a hurry. `No, I'll look first,' she said, `and see whether it's marked "poison" or not'; for she had read several nice little histories about children who had got burnt, and eaten up by wild beasts and other unpleasant things, all because they WOULD not remember the simple rules their friends had taught them: such as, that a red-hot poker will burn you if you hold it too long; and that if you cut your finger VERY deeply with a knife, it usually bleeds; and she had never forgotten that, if you drink much from a bottle marked `poison,' it is almost certain to disagree with you, sooner or later. However, this bottle was NOT marked `poison,' so Alice ventured to taste it, and finding it very nice, (it had, in fact, a sort of mixed flavour of cherry-tart, custard, pine-apple, roast turkey, toffee, and hot buttered toast,) she very soon finished it off. * * * * * * * * * * * * * * * * * * * * `What a curious feeling!' said Alice; `I must be shutting up like a telescope.' And so it was indeed: she was now only ten inches high, and her face brightened up at the thought that she was now the right size for going through the little door into that lovely garden. First, however, she waited for a few minutes to see if she was going to shrink any further: she felt a little nervous about this; `for it might end, you know,' said Alice to herself, `in my going out altogether, like a candle. I wonder what I should be like then?' And she tried to fancy what the flame of a candle is like after the candle is blown out, for she could not remember ever having seen such a thing. After a while, finding that nothing more happened, she decided on going into the garden at once; but, alas for poor Alice! when she got to the door, she found she had forgotten the little golden key, and when she went back to the table for it, she found she could not possibly reach it: she could see it quite plainly through the glass, and she tried her best to climb up one of the legs of the table, but it was too slippery; and when she had tired herself out with trying, the poor little thing sat down and cried. `Come, there's no use in crying like that!' said Alice to herself, rather sharply; `I advise you to leave off this minute!' She generally gave herself very good advice, (though she very seldom followed it), and sometimes she scolded herself so severely as to bring tears into her eyes; and once she remembered trying to box her own ears for having cheated herself in a game of croquet she was playing against herself, for this curious child was very fond of pretending to be two people. `But it's no use now,' thought poor Alice, `to pretend to be two people! Why, there's hardly enough of me left to make ONE respectable person!' Soon her eye fell on a little glass box that was lying under the table: she opened it, and found in it a very small cake, on which the words `EAT ME' were beautifully marked in currants. `Well, I'll eat it,' said Alice, `and if it makes me grow larger, I can reach the key; and if it makes me grow smaller, I can creep under the door; so either way I'll get into the garden, and I don't care which happens!' She ate a little bit, and said anxiously to herself, `Which way? Which way?', holding her hand on the top of her head to feel which way it was growing, and she was quite surprised to find that she remained the same size: to be sure, this generally happens when one eats cake, but Alice had got so much into the way of expecting nothing but out-of-the-way things to happen, that it seemed quite dull and stupid for life to go on in the common way. So she set to work, and very soon finished off the cake. * * * * * * * * * * * * * * * * * * * * CHAPTER II The Pool of Tears `Curiouser and curiouser!' cried Alice (she was so much surprised, that for the moment she quite forgot how to speak good English); `now I'm opening out like the largest telescope that ever was! Good-bye, feet!' (for when she looked down at her feet, they seemed to be almost out of sight, they were getting so far off). `Oh, my poor little feet, I wonder who will put on your shoes and stockings for you now, dears? I'm sure _I_ shan't be able! I shall be a great deal too far off to trouble myself about you: you must manage the best way you can; --but I must be kind to them,' thought Alice, `or perhaps they won't walk the way I want to go! Let me see: I'll give them a new pair of boots every Christmas.' And she went on planning to herself how she would manage it. `They must go by the carrier,' she thought; `and how funny it'll seem, sending presents to one's own feet! And how odd the directions will look! ALICE'S RIGHT FOOT, ESQ. HEARTHRUG, NEAR THE FENDER, (WITH ALICE'S LOVE). Oh dear, what nonsense I'm talking!' Just then her head struck against the roof of the hall: in fact she was now more than nine feet high, and she at once took up the little golden key and hurried off to the garden door. Poor Alice! It was as much as she could do, lying down on one side, to look through into the garden with one eye; but to get through was more hopeless than ever: she sat down and began to cry again. `You ought to be ashamed of yourself,' said Alice, `a great girl like you,' (she might well say this), `to go on crying in this way! Stop this moment, I tell you!' But she went on all the same, shedding gallons of tears, until there was a large pool all round her, about four inches deep and reaching half down the hall. After a time she heard a little pattering of feet in the distance, and she hastily dried her eyes to see what was coming. It was the White Rabbit returning, splendidly dressed, with a pair of white kid gloves in one hand and a large fan in the other: he came trotting along in a great hurry, muttering to himself as he came, `Oh! the Duchess, the Duchess! Oh! won't she be savage if I've kept her waiting!' Alice felt so desperate that she was ready to ask help of any one; so, when the Rabbit came near her, she began, in a low, timid voice, `If you please, sir--' The Rabbit started violently, dropped the white kid gloves and the fan, and skurried away into the darkness as hard as he could go. Alice took up the fan and gloves, and, as the hall was very hot, she kept fanning herself all the time she went on talking: `Dear, dear! How queer everything is to-day! And yesterday things went on just as usual. I wonder if I've been changed in the night? Let me think: was I the same when I got up this morning? I almost think I can remember feeling a little different. But if I'm not the same, the next question is, Who in the world am I? Ah, THAT'S the great puzzle!' And she began thinking over all the children she knew that were of the same age as herself, to see if she could have been changed for any of them. `I'm sure I'm not Ada,' she said, `for her hair goes in such long ringlets, and mine doesn't go in ringlets at all; and I'm sure I can't be Mabel, for I know all sorts of things, and she, oh! she knows such a very little! Besides, SHE'S she, and I'm I, and--oh dear, how puzzling it all is! I'll try if I know all the things I used to know. Let me see: four times five is twelve, and four times six is thirteen, and four times seven is--oh dear! I shall never get to twenty at that rate! However, the Multiplication Table doesn't signify: let's try Geography. London is the capital of Paris, and Paris is the capital of Rome, and Rome--no, THAT'S all wrong, I'm certain! I must have been changed for Mabel! I'll try and say "How doth the little--"' and she crossed her hands on her lap as if she were saying lessons, and began to repeat it, but her voice sounded hoarse and strange, and the words did not come the same as they used to do:-- `How doth the little crocodile Improve his shining tail, And pour the waters of the Nile On every golden scale! `How cheerfully he seems to grin, How neatly spread his claws, And welcome little fishes in With gently smiling jaws!' `I'm sure those are not the right words,' said poor Alice, and her eyes filled with tears again as she went on, `I must be Mabel after all, and I shall have to go and live in that poky little house, and have next to no toys to play with, and oh! ever so many lessons to learn! No, I've made up my mind about it; if I'm Mabel, I'll stay down here! It'll be no use their putting their heads down and saying "Come up again, dear!" I shall only look up and say "Who am I then? Tell me that first, and then, if I like being that person, I'll come up: if not, I'll stay down here till I'm somebody else"--but, oh dear!' cried Alice, with a sudden burst of tears, `I do wish they WOULD put their heads down! I am so VERY tired of being all alone here!' As she said this she looked down at her hands, and was surprised to see that she had put on one of the Rabbit's little white kid gloves while she was talking. `How CAN I have done that?' she thought. `I must be growing small again.' She got up and went to the table to measure herself by it, and found that, as nearly as she could guess, she was now about two feet high, and was going on shrinking rapidly: she soon found out that the cause of this was the fan she was holding, and she dropped it hastily, just in time to avoid shrinking away altogether. `That WAS a narrow escape!' said Alice, a good deal frightened at the sudden change, but very glad to find herself still in existence; `and now for the garden!' and she ran with all speed back to the little door: but, alas! the little door was shut again, and the little golden key was lying on the glass table as before, `and things are worse than ever,' thought the poor child, `for I never was so small as this before, never! And I declare it's too bad, that it is!' As she said these words her foot slipped, and in another moment, splash! she was up to her chin in salt water. Her first idea was that she had somehow fallen into the sea, `and in that case I can go back by railway,' she said to herself. (Alice had been to the seaside once in her life, and had come to the general conclusion, that wherever you go to on the English coast you find a number of bathing machines in the sea, some children digging in the sand with wooden spades, then a row of lodging houses, and behind them a railway station.) However, she soon made out that she was in the pool of tears which she had wept when she was nine feet high. `I wish I hadn't cried so much!' said Alice, as she swam about, trying to find her way out. `I shall be punished for it now, I suppose, by being drowned in my own tears! That WILL be a queer thing, to be sure! However, everything is queer to-day.' Just then she heard something splashing about in the pool a little way off, and she swam nearer to make out what it was: at first she thought it must be a walrus or hippopotamus, but then she remembered how small she was now, and she soon made out that it was only a mouse that had slipped in like herself. `Would it be of any use, now,' thought Alice, `to speak to this mouse? Everything is so out-of-the-way down here, that I should think very likely it can talk: at any rate, there's no harm in trying.' So she began: `O Mouse, do you know the way out of this pool? I am very tired of swimming about here, O Mouse!' (Alice thought this must be the right way of speaking to a mouse: she had never done such a thing before, but she remembered having seen in her brother's Latin Grammar, `A mouse--of a mouse--to a mouse--a mouse--O mouse!' The Mouse looked at her rather inquisitively, and seemed to her to wink with one of its little eyes, but it said nothing. `Perhaps it doesn't understand English,' thought Alice; `I daresay it's a French mouse, come over with William the Conqueror.' (For, with all her knowledge of history, Alice had no very clear notion how long ago anything had happened.) So she began again: `Ou est ma chatte?' which was the first sentence in her French lesson-book. The Mouse gave a sudden leap out of the water, and seemed to quiver all over with fright. `Oh, I beg your pardon!' cried Alice hastily, afraid that she had hurt the poor animal's feelings. `I quite forgot you didn't like cats.' `Not like cats!' cried the Mouse, in a shrill, passionate voice. `Would YOU like cats if you were me?' `Well, perhaps not,' said Alice in a soothing tone: `don't be angry about it. And yet I wish I could show you our cat Dinah: I think you'd take a fancy to cats if you could only see her. She is such a dear quiet thing,' Alice went on, half to herself, as she swam lazily about in the pool, `and she sits purring so nicely by the fire, licking her paws and washing her face--and she is such a nice soft thing to nurse--and she's such a capital one for catching mice--oh, I beg your pardon!' cried Alice again, for this time the Mouse was bristling all over, and she felt certain it must be really offended. `We won't talk about her any more if you'd rather not.' `We indeed!' cried the Mouse, who was trembling down to the end of his tail. `As if I would talk on such a subject! Our family always HATED cats: nasty, low, vulgar things! Don't let me hear the name again!' `I won't indeed!' said Alice, in a great hurry to change the subject of conversation. `Are you--are you fond--of--of dogs?' The Mouse did not answer, so Alice went on eagerly: `There is such a nice little dog near our house I should like to show you! A little bright-eyed terrier, you know, with oh, such long curly brown hair! And it'll fetch things when you throw them, and it'll sit up and beg for its dinner, and all sorts of things--I can't remember half of them--and it belongs to a farmer, you know, and he says it's so useful, it's worth a hundred pounds! He says it kills all the rats and--oh dear!' cried Alice in a sorrowful tone, `I'm afraid I've offended it again!' For the Mouse was swimming away from her as hard as it could go, and making quite a commotion in the pool as it went. So she called softly after it, `Mouse dear! Do come back again, and we won't talk about cats or dogs either, if you don't like them!' When the Mouse heard this, it turned round and swam slowly back to her: its face was quite pale (with passion, Alice thought), and it said in a low trembling voice, `Let us get to the shore, and then I'll tell you my history, and you'll understand why it is I hate cats and dogs.' It was high time to go, for the pool was getting quite crowded with the birds and animals that had fallen into it: there were a Duck and a Dodo, a Lory and an Eaglet, and several other curious creatures. Alice led the way, and the whole party swam to the shore. CHAPTER III A Caucus-Race and a Long Tale They were indeed a queer-looking party that assembled on the bank--the birds with draggled feathers, the animals with their fur clinging close to them, and all dripping wet, cross, and uncomfortable. The first question of course was, how to get dry again: they had a consultation about this, and after a few minutes it seemed quite natural to Alice to find herself talking familiarly with them, as if she had known them all her life. Indeed, she had quite a long argument with the Lory, who at last turned sulky, and would only say, `I am older than you, and must know better'; and this Alice would not allow without knowing how old it was, and, as the Lory positively refused to tell its age, there was no more to be said. At last the Mouse, who seemed to be a person of authority among them, called out, `Sit down, all of you, and listen to me! I'LL soon make you dry enough!' They all sat down at once, in a large ring, with the Mouse in the middle. Alice kept her eyes anxiously fixed on it, for she felt sure she would catch a bad cold if she did not get dry very soon. `Ahem!' said the Mouse with an important air, `are you all ready? This is the driest thing I know. Silence all round, if you please! "William the Conqueror, whose cause was favoured by the pope, was soon submitted to by the English, who wanted leaders, and had been of late much accustomed to usurpation and conquest. Edwin and Morcar, the earls of Mercia and Northumbria--"' `Ugh!' said the Lory, with a shiver. `I beg your pardon!' said the Mouse, frowning, but very politely: `Did you speak?' `Not I!' said the Lory hastily. `I thought you did,' said the Mouse. `--I proceed. "Edwin and Morcar, the earls of Mercia and Northumbria, declared for him: and even Stigand, the patriotic archbishop of Canterbury, found it advisable--"' `Found WHAT?' said the Duck. `Found IT,' the Mouse replied rather crossly: `of course you know what "it" means.' `I know what "it" means well enough, when I find a thing,' said the Duck: `it's generally a frog or a worm. The question is, what did the archbishop find?' The Mouse did not notice this question, but hurriedly went on, `"--found it advisable to go with Edgar Atheling to meet William and offer him the crown. William's conduct at first was moderate. But the insolence of his Normans--" How are you getting on now, my dear?' it continued, turning to Alice as it spoke. `As wet as ever,' said Alice in a melancholy tone: `it doesn't seem to dry me at all.' `In that case,' said the Dodo solemnly, rising to its feet, `I move that the meeting adjourn, for the immediate adoption of more energetic remedies--' `Speak English!' said the Eaglet. `I don't know the meaning of half those long words, and, what's more, I don't believe you do either!' And the Eaglet bent down its head to hide a smile: some of the other birds tittered audibly. `What I was going to say,' said the Dodo in an offended tone, `was, that the best thing to get us dry would be a Caucus-race.' `What IS a Caucus-race?' said Alice; not that she wanted much to know, but the Dodo had paused as if it thought that SOMEBODY ought to speak, and no one else seemed inclined to say anything. `Why,' said the Dodo, `the best way to explain it is to do it.' (And, as you might like to try the thing yourself, some winter day, I will tell you how the Dodo managed it.) First it marked out a race-course, in a sort of circle, (`the exact shape doesn't matter,' it said,) and then all the party were placed along the course, here and there. There was no `One, two, three, and away,' but they began running when they liked, and left off when they liked, so that it was not easy to know when the race was over. However, when they had been running half an hour or so, and were quite dry again, the Dodo suddenly called out `The race is over!' and they all crowded round it, panting, and asking, `But who has won?' This question the Dodo could not answer without a great deal of thought, and it sat for a long time with one finger pressed upon its forehead (the position in which you usually see Shakespeare, in the pictures of him), while the rest waited in silence. At last the Dodo said, `EVERYBODY has won, and all must have prizes.' `But who is to give the prizes?' quite a chorus of voices asked. `Why, SHE, of course,' said the Dodo, pointing to Alice with one finger; and the whole party at once crowded round her, calling out in a confused way, `Prizes! Prizes!' Alice had no idea what to do, and in despair she put her hand in her pocket, and pulled out a box of comfits, (luckily the salt water had not got into it), and handed them round as prizes. There was exactly one a-piece all round. `But she must have a prize herself, you know,' said the Mouse. `Of course,' the Dodo replied very gravely. `What else have you got in your pocket?' he went on, turning to Alice. `Only a thimble,' said Alice sadly. `Hand it over here,' said the Dodo. Then they all crowded round her once more, while the Dodo solemnly presented the thimble, saying `We beg your acceptance of this elegant thimble'; and, when it had finished this short speech, they all cheered. Alice thought the whole thing very absurd, but they all looked so grave that she did not dare to laugh; and, as she could not think of anything to say, she simply bowed, and took the thimble, looking as solemn as she could. The next thing was to eat the comfits: this caused some noise and confusion, as the large birds complained that they could not taste theirs, and the small ones choked and had to be patted on the back. However, it was over at last, and they sat down again in a ring, and begged the Mouse to tell them something more. `You promised to tell me your history, you know,' said Alice, `and why it is you hate--C and D,' she added in a whisper, half afraid that it would be offended again. `Mine is a long and a sad tale!' said the Mouse, turning to Alice, and sighing. `It IS a long tail, certainly,' said Alice, looking down with wonder at the Mouse's tail; `but why do you call it sad?' And she kept on puzzling about it while the Mouse was speaking, so that her idea of the tale was something like this:-- `Fury said to a mouse, That he met in the house, "Let us both go to law: I will prosecute YOU. --Come, I'll take no denial; We must have a trial: For really this morning I've nothing to do." Said the mouse to the cur, "Such a trial, dear Sir, With no jury or judge, would be wasting our breath." "I'll be judge, I'll be jury," Said cunning old Fury: "I'll try the whole cause, and condemn you to death."' `You are not attending!' said the Mouse to Alice severely. `What are you thinking of?' `I beg your pardon,' said Alice very humbly: `you had got to the fifth bend, I think?' `I had NOT!' cried the Mouse, sharply and very angrily. `A knot!' said Alice, always ready to make herself useful, and looking anxiously about her. `Oh, do let me help to undo it!' `I shall do nothing of the sort,' said the Mouse, getting up and walking away. `You insult me by talking such nonsense!' `I didn't mean it!' pleaded poor Alice. `But you're so easily offended, you know!' The Mouse only growled in reply. `Please come back and finish your story!' Alice called after it; and the others all joined in chorus, `Yes, please do!' but the Mouse only shook its head impatiently, and walked a little quicker. `What a pity it wouldn't stay!' sighed the Lory, as soon as it was quite out of sight; and an old Crab took the opportunity of saying to her daughter `Ah, my dear! Let this be a lesson to you never to lose YOUR temper!' `Hold your tongue, Ma!' said the young Crab, a little snappishly. `You're enough to try the patience of an oyster!' `I wish I had our Dinah here, I know I do!' said Alice aloud, addressing nobody in particular. `She'd soon fetch it back!' `And who is Dinah, if I might venture to ask the question?' said the Lory. Alice replied eagerly, for she was always ready to talk about her pet: `Dinah's our cat. And she's such a capital one for catching mice you can't think! And oh, I wish you could see her after the birds! Why, she'll eat a little bird as soon as look at it!' This speech caused a remarkable sensation among the party. Some of the birds hurried off at once: one old Magpie began wrapping itself up very carefully, remarking, `I really must be getting home; the night-air doesn't suit my throat!' and a Canary called out in a trembling voice to its children, `Come away, my dears! It's high time you were all in bed!' On various pretexts they all moved off, and Alice was soon left alone. `I wish I hadn't mentioned Dinah!' she said to herself in a melancholy tone. `Nobody seems to like her, down here, and I'm sure she's the best cat in the world! Oh, my dear Dinah! I wonder if I shall ever see you any more!' And here poor Alice began to cry again, for she felt very lonely and low-spirited. In a little while, however, she again heard a little pattering of footsteps in the distance, and she looked up eagerly, half hoping that the Mouse had changed his mind, and was coming back to finish his story. CHAPTER IV The Rabbit Sends in a Little Bill It was the White Rabbit, trotting slowly back again, and looking anxiously about as it went, as if it had lost something; and she heard it muttering to itself `The Duchess! The Duchess! Oh my dear paws! Oh my fur and whiskers! She'll get me executed, as sure as ferrets are ferrets! Where CAN I have dropped them, I wonder?' Alice guessed in a moment that it was looking for the fan and the pair of white kid gloves, and she very good-naturedly began hunting about for them, but they were nowhere to be seen--everything seemed to have changed since her swim in the pool, and the great hall, with the glass table and the little door, had vanished completely. Very soon the Rabbit noticed Alice, as she went hunting about, and called out to her in an angry tone, `Why, Mary Ann, what ARE you doing out here? Run home this moment, and fetch me a pair of gloves and a fan! Quick, now!' And Alice was so much frightened that she ran off at once in the direction it pointed to, without trying to explain the mistake it had made. `He took me for his housemaid,' she said to herself as she ran. `How surprised he'll be when he finds out who I am! But I'd better take him his fan and gloves--that is, if I can find them.' As she said this, she came upon a neat little house, on the door of which was a bright brass plate with the name `W. RABBIT' engraved upon it. She went in without knocking, and hurried upstairs, in great fear lest she should meet the real Mary Ann, and be turned out of the house before she had found the fan and gloves. `How queer it seems,' Alice said to herself, `to be going messages for a rabbit! I suppose Dinah'll be sending me on messages next!' And she began fancying the sort of thing that would happen: `"Miss Alice! Come here directly, and get ready for your walk!" "Coming in a minute, nurse! But I've got to see that the mouse doesn't get out." Only I don't think,' Alice went on, `that they'd let Dinah stop in the house if it began ordering people about like that!' By this time she had found her way into a tidy little room with a table in the window, and on it (as she had hoped) a fan and two or three pairs of tiny white kid gloves: she took up the fan and a pair of the gloves, and was just going to leave the room, when her eye fell upon a little bottle that stood near the looking- glass. There was no label this time with the words `DRINK ME,' but nevertheless she uncorked it and put it to her lips. `I know SOMETHING interesting is sure to happen,' she said to herself, `whenever I eat or drink anything; so I'll just see what this bottle does. I do hope it'll make me grow large again, for really I'm quite tired of being such a tiny little thing!' It did so indeed, and much sooner than she had expected: before she had drunk half the bottle, she found her head pressing against the ceiling, and had to stoop to save her neck from being broken. She hastily put down the bottle, saying to herself `That's quite enough--I hope I shan't grow any more--As it is, I can't get out at the door--I do wish I hadn't drunk quite so much!' Alas! it was too late to wish that! She went on growing, and growing, and very soon had to kneel down on the floor: in another minute there was not even room for this, and she tried the effect of lying down with one elbow against the door, and the other arm curled round her head. Still she went on growing, and, as a last resource, she put one arm out of the window, and one foot up the chimney, and said to herself `Now I can do no more, whatever happens. What WILL become of me?' Luckily for Alice, the little magic bottle had now had its full effect, and she grew no larger: still it was very uncomfortable, and, as there seemed to be no sort of chance of her ever getting out of the room again, no wonder she felt unhappy. `It was much pleasanter at home,' thought poor Alice, `when one wasn't always growing larger and smaller, and being ordered about by mice and rabbits. I almost wish I hadn't gone down that rabbit-hole--and yet--and yet--it's rather curious, you know, this sort of life! I do wonder what CAN have happened to me! When I used to read fairy-tales, I fancied that kind of thing never happened, and now here I am in the middle of one! There ought to be a book written about me, that there ought! And when I grow up, I'll write one--but I'm grown up now,' she added in a sorrowful tone; `at least there's no room to grow up any more HERE.' `But then,' thought Alice, `shall I NEVER get any older than I am now? That'll be a comfort, one way--never to be an old woman-- but then--always to have lessons to learn! Oh, I shouldn't like THAT!' `Oh, you foolish Alice!' she answered herself. `How can you learn lessons in here? Why, there's hardly room for YOU, and no room at all for any lesson-books!' And so she went on, taking first one side and then the other, and making quite a conversation of it altogether; but after a few minutes she heard a voice outside, and stopped to listen. `Mary Ann! Mary Ann!' said the voice. `Fetch me my gloves this moment!' Then came a little pattering of feet on the stairs. Alice knew it was the Rabbit coming to look for her, and she trembled till she shook the house, quite forgetting that she was now about a thousand times as large as the Rabbit, and had no reason to be afraid of it. Presently the Rabbit came up to the door, and tried to open it; but, as the door opened inwards, and Alice's elbow was pressed hard against it, that attempt proved a failure. Alice heard it say to itself `Then I'll go round and get in at the window.' `THAT you won't' thought Alice, and, after waiting till she fancied she heard the Rabbit just under the window, she suddenly spread out her hand, and made a snatch in the air. She did not get hold of anything, but she heard a little shriek and a fall, and a crash of broken glass, from which she concluded that it was just possible it had fallen into a cucumber-frame, or something of the sort. Next came an angry voice--the Rabbit's--`Pat! Pat! Where are you?' And then a voice she had never heard before, `Sure then I'm here! Digging for apples, yer honour!' `Digging for apples, indeed!' said the Rabbit angrily. `Here! Come and help me out of THIS!' (Sounds of more broken glass.) `Now tell me, Pat, what's that in the window?' `Sure, it's an arm, yer honour!' (He pronounced it `arrum.') `An arm, you goose! Who ever saw one that size? Why, it fills the whole window!' `Sure, it does, yer honour: but it's an arm for all that.' `Well, it's got no business there, at any rate: go and take it away!' There was a long silence after this, and Alice could only hear whispers now and then; such as, `Sure, I don't like it, yer honour, at all, at all!' `Do as I tell you, you coward!' and at last she spread out her hand again, and made another snatch in the air. This time there were TWO little shrieks, and more sounds of broken glass. `What a number of cucumber-frames there must be!' thought Alice. `I wonder what they'll do next! As for pulling me out of the window, I only wish they COULD! I'm sure I don't want to stay in here any longer!' She waited for some time without hearing anything more: at last came a rumbling of little cartwheels, and the sound of a good many voices all talking together: she made out the words: `Where's the other ladder?--Why, I hadn't to bring but one; Bill's got the other--Bill! fetch it here, lad!--Here, put 'em up at this corner--No, tie 'em together first--they don't reach half high enough yet--Oh! they'll do well enough; don't be particular-- Here, Bill! catch hold of this rope--Will the roof bear?--Mind that loose slate--Oh, it's coming down! Heads below!' (a loud crash)--`Now, who did that?--It was Bill, I fancy--Who's to go down the chimney?--Nay, I shan't! YOU do it!--That I won't, then!--Bill's to go down--Here, Bill! the master says you're to go down the chimney!' `Oh! So Bill's got to come down the chimney, has he?' said Alice to herself. `Shy, they seem to put everything upon Bill! I wouldn't be in Bill's place for a good deal: this fireplace is narrow, to be sure; but I THINK I can kick a little!' She drew her foot as far down the chimney as she could, and waited till she heard a little animal (she couldn't guess of what sort it was) scratching and scrambling about in the chimney close above her: then, saying to herself `This is Bill,' she gave one sharp kick, and waited to see what would happen next. The first thing she heard was a general chorus of `There goes Bill!' then the Rabbit's voice along--`Catch him, you by the hedge!' then silence, and then another confusion of voices--`Hold up his head--Brandy now--Don't choke him--How was it, old fellow? What happened to you? Tell us all about it!' Last came a little feeble, squeaking voice, (`That's Bill,' thought Alice,) `Well, I hardly know--No more, thank ye; I'm better now--but I'm a deal too flustered to tell you--all I know is, something comes at me like a Jack-in-the-box, and up I goes like a sky-rocket!' `So you did, old fellow!' said the others. `We must burn the house down!' said the Rabbit's voice; and Alice called out as loud as she could, `If you do. I'll set Dinah at you!' There was a dead silence instantly, and Alice thought to herself, `I wonder what they WILL do next! If they had any sense, they'd take the roof off.' After a minute or two, they began moving about again, and Alice heard the Rabbit say, `A barrowful will do, to begin with.' `A barrowful of WHAT?' thought Alice; but she had not long to doubt, for the next moment a shower of little pebbles came rattling in at the window, and some of them hit her in the face. `I'll put a stop to this,' she said to herself, and shouted out, `You'd better not do that again!' which produced another dead silence. Alice noticed with some surprise that the pebbles were all turning into little cakes as they lay on the floor, and a bright idea came into her head. `If I eat one of these cakes,' she thought, `it's sure to make SOME change in my size; and as it can't possibly make me larger, it must make me smaller, I suppose.' So she swallowed one of the cakes, and was delighted to find that she began shrinking directly. As soon as she was small enough to get through the door, she ran out of the house, and found quite a crowd of little animals and birds waiting outside. The poor little Lizard, Bill, was in the middle, being held up by two guinea-pigs, who were giving it something out of a bottle. They all made a rush at Alice the moment she appeared; but she ran off as hard as she could, and soon found herself safe in a thick wood. `The first thing I've got to do,' said Alice to herself, as she wandered about in the wood, `is to grow to my right size again; and the second thing is to find my way into that lovely garden. I think that will be the best plan.' It sounded an excellent plan, no doubt, and very neatly and simply arranged; the only difficulty was, that she had not the smallest idea how to set about it; and while she was peering about anxiously among the trees, a little sharp bark just over her head made her look up in a great hurry. An enormous puppy was looking down at her with large round eyes, and feebly stretching out one paw, trying to touch her. `Poor little thing!' said Alice, in a coaxing tone, and she tried hard to whistle to it; but she was terribly frightened all the time at the thought that it might be hungry, in which case it would be very likely to eat her up in spite of all her coaxing. Hardly knowing what she did, she picked up a little bit of stick, and held it out to the puppy; whereupon the puppy jumped into the air off all its feet at once, with a yelp of delight, and rushed at the stick, and made believe to worry it; then Alice dodged behind a great thistle, to keep herself from being run over; and the moment she appeared on the other side, the puppy made another rush at the stick, and tumbled head over heels in its hurry to get hold of it; then Alice, thinking it was very like having a game of play with a cart-horse, and expecting every moment to be trampled under its feet, ran round the thistle again; then the puppy began a series of short charges at the stick, running a very little way forwards each time and a long way back, and barking hoarsely all the while, till at last it sat down a good way off, panting, with its tongue hanging out of its mouth, and its great eyes half shut. This seemed to Alice a good opportunity for making her escape; so she set off at once, and ran till she was quite tired and out of breath, and till the puppy's bark sounded quite faint in the distance. `And yet what a dear little puppy it was!' said Alice, as she leant against a buttercup to rest herself, and fanned herself with one of the leaves: `I should have liked teaching it tricks very much, if--if I'd only been the right size to do it! Oh dear! I'd nearly forgotten that I've got to grow up again! Let me see--how IS it to be managed? I suppose I ought to eat or drink something or other; but the great question is, what?' The great question certainly was, what? Alice looked all round her at the flowers and the blades of grass, but she did not see anything that looked like the right thing to eat or drink under the circumstances. There was a large mushroom growing near her, about the same height as herself; and when she had looked under it, and on both sides of it, and behind it, it occurred to her that she might as well look and see what was on the top of it. She stretched herself up on tiptoe, and peeped over the edge of the mushroom, and her eyes immediately met those of a large caterpillar, that was sitting on the top with its arms folded, quietly smoking a long hookah, and taking not the smallest notice of her or of anything else. CHAPTER V Advice from a Caterpillar The Caterpillar and Alice looked at each other for some time in silence: at last the Caterpillar took the hookah out of its mouth, and addressed her in a languid, sleepy voice. `Who are YOU?' said the Caterpillar. This was not an encouraging opening for a conversation. Alice replied, rather shyly, `I--I hardly know, sir, just at present-- at least I know who I WAS when I got up this morning, but I think I must have been changed several times since then.' `What do you mean by that?' said the Caterpillar sternly. `Explain yourself!' `I can't explain MYSELF, I'm afraid, sir' said Alice, `because I'm not myself, you see.' `I don't see,' said the Caterpillar. `I'm afraid I can't put it more clearly,' Alice replied very politely, `for I can't understand it myself to begin with; and being so many different sizes in a day is very confusing.' `It isn't,' said the Caterpillar. `Well, perhaps you haven't found it so yet,' said Alice; `but when you have to turn into a chrysalis--you will some day, you know--and then after that into a butterfly, I should think you'll feel it a little queer, won't you?' `Not a bit,' said the Caterpillar. `Well, perhaps your feelings may be different,' said Alice; `all I know is, it would feel very queer to ME.' `You!' said the Caterpillar contemptuously. `Who are YOU?' Which brought them back again to the beginning of the conversation. Alice felt a little irritated at the Caterpillar's making such VERY short remarks, and she drew herself up and said, very gravely, `I think, you ought to tell me who YOU are, first.' `Why?' said the Caterpillar. Here was another puzzling question; and as Alice could not think of any good reason, and as the Caterpillar seemed to be in a VERY unpleasant state of mind, she turned away. `Come back!' the Caterpillar called after her. `I've something important to say!' This sounded promising, certainly: Alice turned and came back again. `Keep your temper,' said the Caterpillar. `Is that all?' said Alice, swallowing down her anger as well as she could. `No,' said the Caterpillar. Alice thought she might as well wait, as she had nothing else to do, and perhaps after all it might tell her something worth hearing. For some minutes it puffed away without speaking, but at last it unfolded its arms, took the hookah out of its mouth again, and said, `So you think you're changed, do you?' `I'm afraid I am, sir,' said Alice; `I can't remember things as I used--and I don't keep the same size for ten minutes together!' `Can't remember WHAT things?' said the Caterpillar. `Well, I've tried to say "HOW DOTH THE LITTLE BUSY BEE," but it all came different!' Alice replied in a very melancholy voice. `Repeat, "YOU ARE OLD, FATHER WILLIAM,"' said the Caterpillar. Alice folded her hands, and began:-- `You are old, Father William,' the young man said, `And your hair has become very white; And yet you incessantly stand on your head-- Do you think, at your age, it is right?' `In my youth,' Father William replied to his son, `I feared it might injure the brain; But, now that I'm perfectly sure I have none, Why, I do it again and again.' `You are old,' said the youth, `as I mentioned before, And have grown most uncommonly fat; Yet you turned a back-somersault in at the door-- Pray, what is the reason of that?' `In my youth,' said the sage, as he shook his grey locks, `I kept all my limbs very supple By the use of this ointment--one shilling the box-- Allow me to sell you a couple?' `You are old,' said the youth, `and your jaws are too weak For anything tougher than suet; Yet you finished the goose, with the bones and the beak-- Pray how did you manage to do it?' `In my youth,' said his father, `I took to the law, And argued each case with my wife; And the muscular strength, which it gave to my jaw, Has lasted the rest of my life.' `You are old,' said the youth, `one would hardly suppose That your eye was as steady as ever; Yet you balanced an eel on the end of your nose-- What made you so awfully clever?' `I have answered three questions, and that is enough,' Said his father; `don't give yourself airs! Do you think I can listen all day to such stuff? Be off, or I'll kick you down stairs!' `That is not said right,' said the Caterpillar. `Not QUITE right, I'm afraid,' said Alice, timidly; `some of the words have got altered.' `It is wrong from beginning to end,' said the Caterpillar decidedly, and there was silence for some minutes. The Caterpillar was the first to speak. `What size do you want to be?' it asked. `Oh, I'm not particular as to size,' Alice hastily replied; `only one doesn't like changing so often, you know.' `I DON'T know,' said the Caterpillar. Alice said nothing: she had never been so much contradicted in her life before, and she felt that she was losing her temper. `Are you content now?' said the Caterpillar. `Well, I should like to be a LITTLE larger, sir, if you wouldn't mind,' said Alice: `three inches is such a wretched height to be.' `It is a very good height indeed!' said the Caterpillar angrily, rearing itself upright as it spoke (it was exactly three inches high). `But I'm not used to it!' pleaded poor Alice in a piteous tone. And she thought of herself, `I wish the creatures wouldn't be so easily offended!' `You'll get used to it in time,' said the Caterpillar; and it put the hookah into its mouth and began smoking again. This time Alice waited patiently until it chose to speak again. In a minute or two the Caterpillar took the hookah out of its mouth and yawned once or twice, and shook itself. Then it got down off the mushroom, and crawled away in the grass, merely remarking as it went, `One side will make you grow taller, and the other side will make you grow shorter.' `One side of WHAT? The other side of WHAT?' thought Alice to herself. `Of the mushroom,' said the Caterpillar, just as if she had asked it aloud; and in another moment it was out of sight. Alice remained looking thoughtfully at the mushroom for a minute, trying to make out which were the two sides of it; and as it was perfectly round, she found this a very difficult question. However, at last she stretched her arms round it as far as they would go, and broke off a bit of the edge with each hand. `And now which is which?' she said to herself, and nibbled a little of the right-hand bit to try the effect: the next moment she felt a violent blow underneath her chin: it had struck her foot! She was a good deal frightened by this very sudden change, but she felt that there was no time to be lost, as she was shrinking rapidly; so she set to work at once to eat some of the other bit. Her chin was pressed so closely against her foot, that there was hardly room to open her mouth; but she did it at last, and managed to swallow a morsel of the lefthand bit. * * * * * * * * * * * * * * * * * * * * `Come, my head's free at last!' said Alice in a tone of delight, which changed into alarm in another moment, when she found that her shoulders were nowhere to be found: all she could see, when she looked down, was an immense length of neck, which seemed to rise like a stalk out of a sea of green leaves that lay far below her. `What CAN all that green stuff be?' said Alice. `And where HAVE my shoulders got to? And oh, my poor hands, how is it I can't see you?' She was moving them about as she spoke, but no result seemed to follow, except a little shaking among the distant green leaves. As there seemed to be no chance of getting her hands up to her head, she tried to get her head down to them, and was delighted to find that her neck would bend about easily in any direction, like a serpent. She had just succeeded in curving it down into a graceful zigzag, and was going to dive in among the leaves, which she found to be nothing but the tops of the trees under which she had been wandering, when a sharp hiss made her draw back in a hurry: a large pigeon had flown into her face, and was beating her violently with its wings. `Serpent!' screamed the Pigeon. `I'm NOT a serpent!' said Alice indignantly. `Let me alone!' `Serpent, I say again!' repeated the Pigeon, but in a more subdued tone, and added with a kind of sob, `I've tried every way, and nothing seems to suit them!' `I haven't the least idea what you're talking about,' said Alice. `I've tried the roots of trees, and I've tried banks, and I've tried hedges,' the Pigeon went on, without attending to her; `but those serpents! There's no pleasing them!' Alice was more and more puzzled, but she thought there was no use in saying anything more till the Pigeon had finished. `As if it wasn't trouble enough hatching the eggs,' said the Pigeon; `but I must be on the look-out for serpents night and day! Why, I haven't had a wink of sleep these three weeks!' `I'm very sorry you've been annoyed,' said Alice, who was beginning to see its meaning. `And just as I'd taken the highest tree in the wood,' continued the Pigeon, raising its voice to a shriek, `and just as I was thinking I should be free of them at last, they must needs come wriggling down from the sky! Ugh, Serpent!' `But I'm NOT a serpent, I tell you!' said Alice. `I'm a--I'm a--' `Well! WHAT are you?' said the Pigeon. `I can see you're trying to invent something!' `I--I'm a little girl,' said Alice, rather doubtfully, as she remembered the number of changes she had gone through that day. `A likely story indeed!' said the Pigeon in a tone of the deepest contempt. `I've seen a good many little girls in my time, but never ONE with such a neck as that! No, no! You're a serpent; and there's no use denying it. I suppose you'll be telling me next that you never tasted an egg!' `I HAVE tasted eggs, certainly,' said Alice, who was a very truthful child; `but little girls eat eggs quite as much as serpents do, you know.' `I don't believe it,' said the Pigeon; `but if they do, why then they're a kind of serpent, that's all I can say.' This was such a new idea to Alice, that she was quite silent for a minute or two, which gave the Pigeon the opportunity of adding, `You're looking for eggs, I know THAT well enough; and what does it matter to me whether you're a little girl or a serpent?' `It matters a good deal to ME,' said Alice hastily; `but I'm not looking for eggs, as it happens; and if I was, I shouldn't want YOURS: I don't like them raw.' `Well, be off, then!' said the Pigeon in a sulky tone, as it settled down again into its nest. Alice crouched down among the trees as well as she could, for her neck kept getting entangled among the branches, and every now and then she had to stop and untwist it. After a while she remembered that she still held the pieces of mushroom in her hands, and she set to work very carefully, nibbling first at one and then at the other, and growing sometimes taller and sometimes shorter, until she had succeeded in bringing herself down to her usual height. It was so long since she had been anything near the right size, that it felt quite strange at first; but she got used to it in a few minutes, and began talking to herself, as usual. `Come, there's half my plan done now! How puzzling all these changes are! I'm never sure what I'm going to be, from one minute to another! However, I've got back to my right size: the next thing is, to get into that beautiful garden--how IS that to be done, I wonder?' As she said this, she came suddenly upon an open place, with a little house in it about four feet high. `Whoever lives there,' thought Alice, `it'll never do to come upon them THIS size: why, I should frighten them out of their wits!' So she began nibbling at the righthand bit again, and did not venture to go near the house till she had brought herself down to nine inches high. CHAPTER VI Pig and Pepper For a minute or two she stood looking at the house, and wondering what to do next, when suddenly a footman in livery came running out of the wood--(she considered him to be a footman because he was in livery: otherwise, judging by his face only, she would have called him a fish)--and rapped loudly at the door with his knuckles. It was opened by another footman in livery, with a round face, and large eyes like a frog; and both footmen, Alice noticed, had powdered hair that curled all over their heads. She felt very curious to know what it was all about, and crept a little way out of the wood to listen. The Fish-Footman began by producing from under his arm a great letter, nearly as large as himself, and this he handed over to the other, saying, in a solemn tone, `For the Duchess. An invitation from the Queen to play croquet.' The Frog-Footman repeated, in the same solemn tone, only changing the order of the words a little, `From the Queen. An invitation for the Duchess to play croquet.' Then they both bowed low, and their curls got entangled together. Alice laughed so much at this, that she had to run back into the wood for fear of their hearing her; and when she next peeped out the Fish-Footman was gone, and the other was sitting on the ground near the door, staring stupidly up into the sky. Alice went timidly up to the door, and knocked. `There's no sort of use in knocking,' said the Footman, `and that for two reasons. First, because I'm on the same side of the door as you are; secondly, because they're making such a noise inside, no one could possibly hear you.' And certainly there was a most extraordinary noise going on within--a constant howling and sneezing, and every now and then a great crash, as if a dish or kettle had been broken to pieces. `Please, then,' said Alice, `how am I to get in?' `There might be some sense in your knocking,' the Footman went on without attending to her, `if we had the door between us. For instance, if you were INSIDE, you might knock, and I could let you out, you know.' He was looking up into the sky all the time he was speaking, and this Alice thought decidedly uncivil. `But perhaps he can't help it,' she said to herself; `his eyes are so VERY nearly at the top of his head. But at any rate he might answer questions.--How am I to get in?' she repeated, aloud. `I shall sit here,' the Footman remarked, `till tomorrow--' At this moment the door of the house opened, and a large plate came skimming out, straight at the Footman's head: it just grazed his nose, and broke to pieces against one of the trees behind him. `--or next day, maybe,' the Footman continued in the same tone, exactly as if nothing had happened. `How am I to get in?' asked Alice again, in a louder tone. `ARE you to get in at all?' said the Footman. `That's the first question, you know.' It was, no doubt: only Alice did not like to be told so. `It's really dreadful,' she muttered to herself, `the way all the creatures argue. It's enough to drive one crazy!' The Footman seemed to think this a good opportunity for repeating his remark, with variations. `I shall sit here,' he said, `on and off, for days and days.' `But what am I to do?' said Alice. `Anything you like,' said the Footman, and began whistling. `Oh, there's no use in talking to him,' said Alice desperately: `he's perfectly idiotic!' And she opened the door and went in. The door led right into a large kitchen, which was full of smoke from one end to the other: the Duchess was sitting on a three-legged stool in the middle, nursing a baby; the cook was leaning over the fire, stirring a large cauldron which seemed to be full of soup. `There's certainly too much pepper in that soup!' Alice said to herself, as well as she could for sneezing. There was certainly too much of it in the air. Even the Duchess sneezed occasionally; and as for the baby, it was sneezing and howling alternately without a moment's pause. The only things in the kitchen that did not sneeze, were the cook, and a large cat which was sitting on the hearth and grinning from ear to ear. `Please would you tell me,' said Alice, a little timidly, for she was not quite sure whether it was good manners for her to speak first, `why your cat grins like that?' `It's a Cheshire cat,' said the Duchess, `and that's why. Pig!' She said the last word with such sudden violence that Alice quite jumped; but she saw in another moment that it was addressed to the baby, and not to her, so she took courage, and went on again:-- `I didn't know that Cheshire cats always grinned; in fact, I didn't know that cats COULD grin.' `They all can,' said the Duchess; `and most of 'em do.' `I don't know of any that do,' Alice said very politely, feeling quite pleased to have got into a conversation. `You don't know much,' said the Duchess; `and that's a fact.' Alice did not at all like the tone of this remark, and thought it would be as well to introduce some other subject of conversation. While she was trying to fix on one, the cook took the cauldron of soup off the fire, and at once set to work throwing everything within her reach at the Duchess and the baby --the fire-irons came first; then followed a shower of saucepans, plates, and dishes. The Duchess took no notice of them even when they hit her; and the baby was howling so much already, that it was quite impossible to say whether the blows hurt it or not. `Oh, PLEASE mind what you're doing!' cried Alice, jumping up and down in an agony of terror. `Oh, there goes his PRECIOUS nose'; as an unusually large saucepan flew close by it, and very nearly carried it off. `If everybody minded their own business,' the Duchess said in a hoarse growl, `the world would go round a deal faster than it does.' `Which would NOT be an advantage,' said Alice, who felt very glad to get an opportunity of showing off a little of her knowledge. `Just think of what work it would make with the day and night! You see the earth takes twenty-four hours to turn round on its axis--' `Talking of axes,' said the Duchess, `chop off her head!' Alice glanced rather anxiously at the cook, to see if she meant to take the hint; but the cook was busily stirring the soup, and seemed not to be listening, so she went on again: `Twenty-four hours, I THINK; or is it twelve? I--' `Oh, don't bother ME,' said the Duchess; `I never could abide figures!' And with that she began nursing her child again, singing a sort of lullaby to it as she did so, and giving it a violent shake at the end of every line: `Speak roughly to your little boy, And beat him when he sneezes: He only does it to annoy, Because he knows it teases.' CHORUS. (In which the cook and the baby joined):-- `Wow! wow! wow!' While the Duchess sang the second verse of the song, she kept tossing the baby violently up and down, and the poor little thing howled so, that Alice could hardly hear the words:-- `I speak severely to my boy, I beat him when he sneezes; For he can thoroughly enjoy The pepper when he pleases!' CHORUS. `Wow! wow! wow!' `Here! you may nurse it a bit, if you like!' the Duchess said to Alice, flinging the baby at her as she spoke. `I must go and get ready to play croquet with the Queen,' and she hurried out of the room. The cook threw a frying-pan after her as she went out, but it just missed her. Alice caught the baby with some difficulty, as it was a queer- shaped little creature, and held out its arms and legs in all directions, `just like a star-fish,' thought Alice. The poor little thing was snorting like a steam-engine when she caught it, and kept doubling itself up and straightening itself out again, so that altogether, for the first minute or two, it was as much as she could do to hold it. As soon as she had made out the proper way of nursing it, (which was to twist it up into a sort of knot, and then keep tight hold of its right ear and left foot, so as to prevent its undoing itself,) she carried it out into the open air. `IF I don't take this child away with me,' thought Alice, `they're sure to kill it in a day or two: wouldn't it be murder to leave it behind?' She said the last words out loud, and the little thing grunted in reply (it had left off sneezing by this time). `Don't grunt,' said Alice; `that's not at all a proper way of expressing yourself.' The baby grunted again, and Alice looked very anxiously into its face to see what was the matter with it. There could be no doubt that it had a VERY turn-up nose, much more like a snout than a real nose; also its eyes were getting extremely small for a baby: altogether Alice did not like the look of the thing at all. `But perhaps it was only sobbing,' she thought, and looked into its eyes again, to see if there were any tears. No, there were no tears. `If you're going to turn into a pig, my dear,' said Alice, seriously, `I'll have nothing more to do with you. Mind now!' The poor little thing sobbed again (or grunted, it was impossible to say which), and they went on for some while in silence. Alice was just beginning to think to herself, `Now, what am I to do with this creature when I get it home?' when it grunted again, so violently, that she looked down into its face in some alarm. This time there could be NO mistake about it: it was neither more nor less than a pig, and she felt that it would be quite absurd for her to carry it further. So she set the little creature down, and felt quite relieved to see it trot away quietly into the wood. `If it had grown up,' she said to herself, `it would have made a dreadfully ugly child: but it makes rather a handsome pig, I think.' And she began thinking over other children she knew, who might do very well as pigs, and was just saying to herself, `if one only knew the right way to change them--' when she was a little startled by seeing the Cheshire Cat sitting on a bough of a tree a few yards off. The Cat only grinned when it saw Alice. It looked good- natured, she thought: still it had VERY long claws and a great many teeth, so she felt that it ought to be treated with respect. `Cheshire Puss,' she began, rather timidly, as she did not at all know whether it would like the name: however, it only grinned a little wider. `Come, it's pleased so far,' thought Alice, and she went on. `Would you tell me, please, which way I ought to go from here?' `That depends a good deal on where you want to get to,' said the Cat. `I don't much care where--' said Alice. `Then it doesn't matter which way you go,' said the Cat. `--so long as I get SOMEWHERE,' Alice added as an explanation. `Oh, you're sure to do that,' said the Cat, `if you only walk long enough.' Alice felt that this could not be denied, so she tried another question. `What sort of people live about here?' `In THAT direction,' the Cat said, waving its right paw round, `lives a Hatter: and in THAT direction,' waving the other paw, `lives a March Hare. Visit either you like: they're both mad.' `But I don't want to go among mad people,' Alice remarked. `Oh, you can't help that,' said the Cat: `we're all mad here. I'm mad. You're mad.' `How do you know I'm mad?' said Alice. `You must be,' said the Cat, `or you wouldn't have come here.' Alice didn't think that proved it at all; however, she went on `And how do you know that you're mad?' `To begin with,' said the Cat, `a dog's not mad. You grant that?' `I suppose so,' said Alice. `Well, then,' the Cat went on, `you see, a dog growls when it's angry, and wags its tail when it's pleased. Now I growl when I'm pleased, and wag my tail when I'm angry. Therefore I'm mad.' `I call it purring, not growling,' said Alice. `Call it what you like,' said the Cat. `Do you play croquet with the Queen to-day?' `I should like it very much,' said Alice, `but I haven't been invited yet.' `You'll see me there,' said the Cat, and vanished. Alice was not much surprised at this, she was getting so used to queer things happening. While she was looking at the place where it had been, it suddenly appeared again. `By-the-bye, what became of the baby?' said the Cat. `I'd nearly forgotten to ask.' `It turned into a pig,' Alice quietly said, just as if it had come back in a natural way. `I thought it would,' said the Cat, and vanished again. Alice waited a little, half expecting to see it again, but it did not appear, and after a minute or two she walked on in the direction in which the March Hare was said to live. `I've seen hatters before,' she said to herself; `the March Hare will be much the most interesting, and perhaps as this is May it won't be raving mad--at least not so mad as it was in March.' As she said this, she looked up, and there was the Cat again, sitting on a branch of a tree. `Did you say pig, or fig?' said the Cat. `I said pig,' replied Alice; `and I wish you wouldn't keep appearing and vanishing so suddenly: you make one quite giddy.' `All right,' said the Cat; and this time it vanished quite slowly, beginning with the end of the tail, and ending with the grin, which remained some time after the rest of it had gone. `Well! I've often seen a cat without a grin,' thought Alice; `but a grin without a cat! It's the most curious thing I ever saw in my life!' She had not gone much farther before she came in sight of the house of the March Hare: she thought it must be the right house, because the chimneys were shaped like ears and the roof was thatched with fur. It was so large a house, that she did not like to go nearer till she had nibbled some more of the lefthand bit of mushroom, and raised herself to about two feet high: even then she walked up towards it rather timidly, saying to herself `Suppose it should be raving mad after all! I almost wish I'd gone to see the Hatter instead!' CHAPTER VII A Mad Tea-Party There was a table set out under a tree in front of the house, and the March Hare and the Hatter were having tea at it: a Dormouse was sitting between them, fast asleep, and the other two were using it as a cushion, resting their elbows on it, and talking over its head. `Very uncomfortable for the Dormouse,' thought Alice; `only, as it's asleep, I suppose it doesn't mind.' The table was a large one, but the three were all crowded together at one corner of it: `No room! No room!' they cried out when they saw Alice coming. `There's PLENTY of room!' said Alice indignantly, and she sat down in a large arm-chair at one end of the table. `Have some wine,' the March Hare said in an encouraging tone. Alice looked all round the table, but there was nothing on it but tea. `I don't see any wine,' she remarked. `There isn't any,' said the March Hare. `Then it wasn't very civil of you to offer it,' said Alice angrily. `It wasn't very civil of you to sit down without being invited,' said the March Hare. `I didn't know it was YOUR table,' said Alice; `it's laid for a great many more than three.' `Your hair wants cutting,' said the Hatter. He had been looking at Alice for some time with great curiosity, and this was his first speech. `You should learn not to make personal remarks,' Alice said with some severity; `it's very rude.' The Hatter opened his eyes very wide on hearing this; but all he SAID was, `Why is a raven like a writing-desk?' `Come, we shall have some fun now!' thought Alice. `I'm glad they've begun asking riddles.--I believe I can guess that,' she added aloud. `Do you mean that you think you can find out the answer to it?' said the March Hare. `Exactly so,' said Alice. `Then you should say what you mean,' the March Hare went on. `I do,' Alice hastily replied; `at least--at least I mean what I say--that's the same thing, you know.' `Not the same thing a bit!' said the Hatter. `You might just as well say that "I see what I eat" is the same thing as "I eat what I see"!' `You might just as well say,' added the March Hare, `that "I like what I get" is the same thing as "I get what I like"!' `You might just as well say,' added the Dormouse, who seemed to be talking in his sleep, `that "I breathe when I sleep" is the same thing as "I sleep when I breathe"!' `It IS the same thing with you,' said the Hatter, and here the conversation dropped, and the party sat silent for a minute, while Alice thought over all she could remember about ravens and writing-desks, which wasn't much. The Hatter was the first to break the silence. `What day of the month is it?' he said, turning to Alice: he had taken his watch out of his pocket, and was looking at it uneasily, shaking it every now and then, and holding it to his ear. Alice considered a little, and then said `The fourth.' `Two days wrong!' sighed the Hatter. `I told you butter wouldn't suit the works!' he added looking angrily at the March Hare. `It was the BEST butter,' the March Hare meekly replied. `Yes, but some crumbs must have got in as well,' the Hatter grumbled: `you shouldn't have put it in with the bread-knife.' The March Hare took the watch and looked at it gloomily: then he dipped it into his cup of tea, and looked at it again: but he could think of nothing better to say than his first remark, `It was the BEST butter, you know.' Alice had been looking over his shoulder with some curiosity. `What a funny watch!' she remarked. `It tells the day of the month, and doesn't tell what o'clock it is!' `Why should it?' muttered the Hatter. `Does YOUR watch tell you what year it is?' `Of course not,' Alice replied very readily: `but that's because it stays the same year for such a long time together.' `Which is just the case with MINE,' said the Hatter. Alice felt dreadfully puzzled. The Hatter's remark seemed to have no sort of meaning in it, and yet it was certainly English. `I don't quite understand you,' she said, as politely as she could. `The Dormouse is asleep again,' said the Hatter, and he poured a little hot tea upon its nose. The Dormouse shook its head impatiently, and said, without opening its eyes, `Of course, of course; just what I was going to remark myself.' `Have you guessed the riddle yet?' the Hatter said, turning to Alice again. `No, I give it up,' Alice replied: `what's the answer?' `I haven't the slightest idea,' said the Hatter. `Nor I,' said the March Hare. Alice sighed wearily. `I think you might do something better with the time,' she said, `than waste it in asking riddles that have no answers.' `If you knew Time as well as I do,' said the Hatter, `you wouldn't talk about wasting IT. It's HIM.' `I don't know what you mean,' said Alice. `Of course you don't!' the Hatter said, tossing his head contemptuously. `I dare say you never even spoke to Time!' `Perhaps not,' Alice cautiously replied: `but I know I have to beat time when I learn music.' `Ah! that accounts for it,' said the Hatter. `He won't stand beating. Now, if you only kept on good terms with him, he'd do almost anything you liked with the clock. For instance, suppose it were nine o'clock in the morning, just time to begin lessons: you'd only have to whisper a hint to Time, and round goes the clock in a twinkling! Half-past one, time for dinner!' (`I only wish it was,' the March Hare said to itself in a whisper.) `That would be grand, certainly,' said Alice thoughtfully: `but then--I shouldn't be hungry for it, you know.' `Not at first, perhaps,' said the Hatter: `but you could keep it to half-past one as long as you liked.' `Is that the way YOU manage?' Alice asked. The Hatter shook his head mournfully. `Not I!' he replied. `We quarrelled last March--just before HE went mad, you know--' (pointing with his tea spoon at the March Hare,) `--it was at the great concert given by the Queen of Hearts, and I had to sing "Twinkle, twinkle, little bat! How I wonder what you're at!" You know the song, perhaps?' `I've heard something like it,' said Alice. `It goes on, you know,' the Hatter continued, `in this way:-- "Up above the world you fly, Like a tea-tray in the sky. Twinkle, twinkle--"' Here the Dormouse shook itself, and began singing in its sleep `Twinkle, twinkle, twinkle, twinkle--' and went on so long that they had to pinch it to make it stop. `Well, I'd hardly finished the first verse,' said the Hatter, `when the Queen jumped up and bawled out, "He's murdering the time! Off with his head!"' `How dreadfully savage!' exclaimed Alice. `And ever since that,' the Hatter went on in a mournful tone, `he won't do a thing I ask! It's always six o'clock now.' A bright idea came into Alice's head. `Is that the reason so many tea-things are put out here?' she asked. `Yes, that's it,' said the Hatter with a sigh: `it's always tea-time, and we've no time to wash the things between whiles.' `Then you keep moving round, I suppose?' said Alice. `Exactly so,' said the Hatter: `as the things get used up.' `But what happens when you come to the beginning again?' Alice ventured to ask. `Suppose we change the subject,' the March Hare interrupted, yawning. `I'm getting tired of this. I vote the young lady tells us a story.' `I'm afraid I don't know one,' said Alice, rather alarmed at the proposal. `Then the Dormouse shall!' they both cried. `Wake up, Dormouse!' And they pinched it on both sides at once. The Dormouse slowly opened his eyes. `I wasn't asleep,' he said in a hoarse, feeble voice: `I heard every word you fellows were saying.' `Tell us a story!' said the March Hare. `Yes, please do!' pleaded Alice. `And be quick about it,' added the Hatter, `or you'll be asleep again before it's done.' `Once upon a time there were three little sisters,' the Dormouse began in a great hurry; `and their names were Elsie, Lacie, and Tillie; and they lived at the bottom of a well--' `What did they live on?' said Alice, who always took a great interest in questions of eating and drinking. `They lived on treacle,' said the Dormouse, after thinking a minute or two. `They couldn't have done that, you know,' Alice gently remarked; `they'd have been ill.' `So they were,' said the Dormouse; `VERY ill.' Alice tried to fancy to herself what such an extraordinary ways of living would be like, but it puzzled her too much, so she went on: `But why did they live at the bottom of a well?' `Take some more tea,' the March Hare said to Alice, very earnestly. `I've had nothing yet,' Alice replied in an offended tone, `so I can't take more.' `You mean you can't take LESS,' said the Hatter: `it's very easy to take MORE than nothing.' `Nobody asked YOUR opinion,' said Alice. `Who's making personal remarks now?' the Hatter asked triumphantly. Alice did not quite know what to say to this: so she helped herself to some tea and bread-and-butter, and then turned to the Dormouse, and repeated her question. `Why did they live at the bottom of a well?' The Dormouse again took a minute or two to think about it, and then said, `It was a treacle-well.' `There's no such thing!' Alice was beginning very angrily, but the Hatter and the March Hare went `Sh! sh!' and the Dormouse sulkily remarked, `If you can't be civil, you'd better finish the story for yourself.' `No, please go on!' Alice said very humbly; `I won't interrupt again. I dare say there may be ONE.' `One, indeed!' said the Dormouse indignantly. However, he consented to go on. `And so these three little sisters--they were learning to draw, you know--' `What did they draw?' said Alice, quite forgetting her promise. `Treacle,' said the Dormouse, without considering at all this time. `I want a clean cup,' interrupted the Hatter: `let's all move one place on.' He moved on as he spoke, and the Dormouse followed him: the March Hare moved into the Dormouse's place, and Alice rather unwillingly took the place of the March Hare. The Hatter was the only one who got any advantage from the change: and Alice was a good deal worse off than before, as the March Hare had just upset the milk-jug into his plate. Alice did not wish to offend the Dormouse again, so she began very cautiously: `But I don't understand. Where did they draw the treacle from?' `You can draw water out of a water-well,' said the Hatter; `so I should think you could draw treacle out of a treacle-well--eh, stupid?' `But they were IN the well,' Alice said to the Dormouse, not choosing to notice this last remark. `Of course they were', said the Dormouse; `--well in.' This answer so confused poor Alice, that she let the Dormouse go on for some time without interrupting it. `They were learning to draw,' the Dormouse went on, yawning and rubbing its eyes, for it was getting very sleepy; `and they drew all manner of things--everything that begins with an M--' `Why with an M?' said Alice. `Why not?' said the March Hare. Alice was silent. The Dormouse had closed its eyes by this time, and was going off into a doze; but, on being pinched by the Hatter, it woke up again with a little shriek, and went on: `--that begins with an M, such as mouse-traps, and the moon, and memory, and muchness-- you know you say things are "much of a muchness"--did you ever see such a thing as a drawing of a muchness?' `Really, now you ask me,' said Alice, very much confused, `I don't think--' `Then you shouldn't talk,' said the Hatter. This piece of rudeness was more than Alice could bear: she got up in great disgust, and walked off; the Dormouse fell asleep instantly, and neither of the others took the least notice of her going, though she looked back once or twice, half hoping that they would call after her: the last time she saw them, they were trying to put the Dormouse into the teapot. `At any rate I'll never go THERE again!' said Alice as she picked her way through the wood. `It's the stupidest tea-party I ever was at in all my life!' Just as she said this, she noticed that one of the trees had a door leading right into it. `That's very curious!' she thought. `But everything's curious today. I think I may as well go in at once.' And in she went. Once more she found herself in the long hall, and close to the little glass table. `Now, I'll manage better this time,' she said to herself, and began by taking the little golden key, and unlocking the door that led into the garden. Then she went to work nibbling at the mushroom (she had kept a piece of it in her pocket) till she was about a foot high: then she walked down the little passage: and THEN--she found herself at last in the beautiful garden, among the bright flower-beds and the cool fountains. CHAPTER VIII The Queen's Croquet-Ground A large rose-tree stood near the entrance of the garden: the roses growing on it were white, but there were three gardeners at it, busily painting them red. Alice thought this a very curious thing, and she went nearer to watch them, and just as she came up to them she heard one of them say, `Look out now, Five! Don't go splashing paint over me like that!' `I couldn't help it,' said Five, in a sulky tone; `Seven jogged my elbow.' On which Seven looked up and said, `That's right, Five! Always lay the blame on others!' `YOU'D better not talk!' said Five. `I heard the Queen say only yesterday you deserved to be beheaded!' `What for?' said the one who had spoken first. `That's none of YOUR business, Two!' said Seven. `Yes, it IS his business!' said Five, `and I'll tell him--it was for bringing the cook tulip-roots instead of onions.' Seven flung down his brush, and had just begun `Well, of all the unjust things--' when his eye chanced to fall upon Alice, as she stood watching them, and he checked himself suddenly: the others looked round also, and all of them bowed low. `Would you tell me,' said Alice, a little timidly, `why you are painting those roses?' Five and Seven said nothing, but looked at Two. Two began in a low voice, `Why the fact is, you see, Miss, this here ought to have been a RED rose-tree, and we put a white one in by mistake; and if the Queen was to find it out, we should all have our heads cut off, you know. So you see, Miss, we're doing our best, afore she comes, to--' At this moment Five, who had been anxiously looking across the garden, called out `The Queen! The Queen!' and the three gardeners instantly threw themselves flat upon their faces. There was a sound of many footsteps, and Alice looked round, eager to see the Queen. First came ten soldiers carrying clubs; these were all shaped like the three gardeners, oblong and flat, with their hands and feet at the corners: next the ten courtiers; these were ornamented all over with diamonds, and walked two and two, as the soldiers did. After these came the royal children; there were ten of them, and the little dears came jumping merrily along hand in hand, in couples: they were all ornamented with hearts. Next came the guests, mostly Kings and Queens, and among them Alice recognised the White Rabbit: it was talking in a hurried nervous manner, smiling at everything that was said, and went by without noticing her. Then followed the Knave of Hearts, carrying the King's crown on a crimson velvet cushion; and, last of all this grand procession, came THE KING AND QUEEN OF HEARTS. Alice was rather doubtful whether she ought not to lie down on her face like the three gardeners, but she could not remember ever having heard of such a rule at processions; `and besides, what would be the use of a procession,' thought she, `if people had all to lie down upon their faces, so that they couldn't see it?' So she stood still where she was, and waited. When the procession came opposite to Alice, they all stopped and looked at her, and the Queen said severely `Who is this?' She said it to the Knave of Hearts, who only bowed and smiled in reply. `Idiot!' said the Queen, tossing her head impatiently; and, turning to Alice, she went on, `What's your name, child?' `My name is Alice, so please your Majesty,' said Alice very politely; but she added, to herself, `Why, they're only a pack of cards, after all. I needn't be afraid of them!' `And who are THESE?' said the Queen, pointing to the three gardeners who were lying round the rosetree; for, you see, as they were lying on their faces, and the pattern on their backs was the same as the rest of the pack, she could not tell whether they were gardeners, or soldiers, or courtiers, or three of her own children. `How should I know?' said Alice, surprised at her own courage. `It's no business of MINE.' The Queen turned crimson with fury, and, after glaring at her for a moment like a wild beast, screamed `Off with her head! Off--' `Nonsense!' said Alice, very loudly and decidedly, and the Queen was silent. The King laid his hand upon her arm, and timidly said `Consider, my dear: she is only a child!' The Queen turned angrily away from him, and said to the Knave `Turn them over!' The Knave did so, very carefully, with one foot. `Get up!' said the Queen, in a shrill, loud voice, and the three gardeners instantly jumped up, and began bowing to the King, the Queen, the royal children, and everybody else. `Leave off that!' screamed the Queen. `You make me giddy.' And then, turning to the rose-tree, she went on, `What HAVE you been doing here?' `May it please your Majesty,' said Two, in a very humble tone, going down on one knee as he spoke, `we were trying--' `I see!' said the Queen, who had meanwhile been examining the roses. `Off with their heads!' and the procession moved on, three of the soldiers remaining behind to execute the unfortunate gardeners, who ran to Alice for protection. `You shan't be beheaded!' said Alice, and she put them into a large flower-pot that stood near. The three soldiers wandered about for a minute or two, looking for them, and then quietly marched off after the others. `Are their heads off?' shouted the Queen. `Their heads are gone, if it please your Majesty!' the soldiers shouted in reply. `That's right!' shouted the Queen. `Can you play croquet?' The soldiers were silent, and looked at Alice, as the question was evidently meant for her. `Yes!' shouted Alice. `Come on, then!' roared the Queen, and Alice joined the procession, wondering very much what would happen next. `It's--it's a very fine day!' said a timid voice at her side. She was walking by the White Rabbit, who was peeping anxiously into her face. `Very,' said Alice: `--where's the Duchess?' `Hush! Hush!' said the Rabbit in a low, hurried tone. He looked anxiously over his shoulder as he spoke, and then raised himself upon tiptoe, put his mouth close to her ear, and whispered `She's under sentence of execution.' `What for?' said Alice. `Did you say "What a pity!"?' the Rabbit asked. `No, I didn't,' said Alice: `I don't think it's at all a pity. I said "What for?"' `She boxed the Queen's ears--' the Rabbit began. Alice gave a little scream of laughter. `Oh, hush!' the Rabbit whispered in a frightened tone. `The Queen will hear you! You see, she came rather late, and the Queen said--' `Get to your places!' shouted the Queen in a voice of thunder, and people began running about in all directions, tumbling up against each other; however, they got settled down in a minute or two, and the game began. Alice thought she had never seen such a curious croquet-ground in her life; it was all ridges and furrows; the balls were live hedgehogs, the mallets live flamingoes, and the soldiers had to double themselves up and to stand on their hands and feet, to make the arches. The chief difficulty Alice found at first was in managing her flamingo: she succeeded in getting its body tucked away, comfortably enough, under her arm, with its legs hanging down, but generally, just as she had got its neck nicely straightened out, and was going to give the hedgehog a blow with its head, it WOULD twist itself round and look up in her face, with such a puzzled expression that she could not help bursting out laughing: and when she had got its head down, and was going to begin again, it was very provoking to find that the hedgehog had unrolled itself, and was in the act of crawling away: besides all this, there was generally a ridge or furrow in the way wherever she wanted to send the hedgehog to, and, as the doubled-up soldiers were always getting up and walking off to other parts of the ground, Alice soon came to the conclusion that it was a very difficult game indeed. The players all played at once without waiting for turns, quarrelling all the while, and fighting for the hedgehogs; and in a very short time the Queen was in a furious passion, and went stamping about, and shouting `Off with his head!' or `Off with her head!' about once in a minute. Alice began to feel very uneasy: to be sure, she had not as yet had any dispute with the Queen, but she knew that it might happen any minute, `and then,' thought she, `what would become of me? They're dreadfully fond of beheading people here; the great wonder is, that there's any one left alive!' She was looking about for some way of escape, and wondering whether she could get away without being seen, when she noticed a curious appearance in the air: it puzzled her very much at first, but, after watching it a minute or two, she made it out to be a grin, and she said to herself `It's the Cheshire Cat: now I shall have somebody to talk to.' `How are you getting on?' said the Cat, as soon as there was mouth enough for it to speak with. Alice waited till the eyes appeared, and then nodded. `It's no use speaking to it,' she thought, `till its ears have come, or at least one of them.' In another minute the whole head appeared, and then Alice put down her flamingo, and began an account of the game, feeling very glad she had someone to listen to her. The Cat seemed to think that there was enough of it now in sight, and no more of it appeared. `I don't think they play at all fairly,' Alice began, in rather a complaining tone, `and they all quarrel so dreadfully one can't hear oneself speak--and they don't seem to have any rules in particular; at least, if there are, nobody attends to them--and you've no idea how confusing it is all the things being alive; for instance, there's the arch I've got to go through next walking about at the other end of the ground--and I should have croqueted the Queen's hedgehog just now, only it ran away when it saw mine coming!' `How do you like the Queen?' said the Cat in a low voice. `Not at all,' said Alice: `she's so extremely--' Just then she noticed that the Queen was close behind her, listening: so she went on, `--likely to win, that it's hardly worth while finishing the game.' The Queen smiled and passed on. `Who ARE you talking to?' said the King, going up to Alice, and looking at the Cat's head with great curiosity. `It's a friend of mine--a Cheshire Cat,' said Alice: `allow me to introduce it.' `I don't like the look of it at all,' said the King: `however, it may kiss my hand if it likes.' `I'd rather not,' the Cat remarked. `Don't be impertinent,' said the King, `and don't look at me like that!' He got behind Alice as he spoke. `A cat may look at a king,' said Alice. `I've read that in some book, but I don't remember where.' `Well, it must be removed,' said the King very decidedly, and he called the Queen, who was passing at the moment, `My dear! I wish you would have this cat removed!' The Queen had only one way of settling all difficulties, great or small. `Off with his head!' she said, without even looking round. `I'll fetch the executioner myself,' said the King eagerly, and he hurried off. Alice thought she might as well go back, and see how the game was going on, as she heard the Queen's voice in the distance, screaming with passion. She had already heard her sentence three of the players to be executed for having missed their turns, and she did not like the look of things at all, as the game was in such confusion that she never knew whether it was her turn or not. So she went in search of her hedgehog. The hedgehog was engaged in a fight with another hedgehog, which seemed to Alice an excellent opportunity for croqueting one of them with the other: the only difficulty was, that her flamingo was gone across to the other side of the garden, where Alice could see it trying in a helpless sort of way to fly up into a tree. By the time she had caught the flamingo and brought it back, the fight was over, and both the hedgehogs were out of sight: `but it doesn't matter much,' thought Alice, `as all the arches are gone from this side of the ground.' So she tucked it away under her arm, that it might not escape again, and went back for a little more conversation with her friend. When she got back to the Cheshire Cat, she was surprised to find quite a large crowd collected round it: there was a dispute going on between the executioner, the King, and the Queen, who were all talking at once, while all the rest were quite silent, and looked very uncomfortable. The moment Alice appeared, she was appealed to by all three to settle the question, and they repeated their arguments to her, though, as they all spoke at once, she found it very hard indeed to make out exactly what they said. The executioner's argument was, that you couldn't cut off a head unless there was a body to cut it off from: that he had never had to do such a thing before, and he wasn't going to begin at HIS time of life. The King's argument was, that anything that had a head could be beheaded, and that you weren't to talk nonsense. The Queen's argument was, that if something wasn't done about it in less than no time she'd have everybody executed, all round. (It was this last remark that had made the whole party look so grave and anxious.) Alice could think of nothing else to say but `It belongs to the Duchess: you'd better ask HER about it.' `She's in prison,' the Queen said to the executioner: `fetch her here.' And the executioner went off like an arrow. The Cat's head began fading away the moment he was gone, and, by the time he had come back with the Dutchess, it had entirely disappeared; so the King and the executioner ran wildly up and down looking for it, while the rest of the party went back to the game. CHAPTER IX The Mock Turtle's Story `You can't think how glad I am to see you again, you dear old thing!' said the Duchess, as she tucked her arm affectionately into Alice's, and they walked off together. Alice was very glad to find her in such a pleasant temper, and thought to herself that perhaps it was only the pepper that had made her so savage when they met in the kitchen. `When I'M a Duchess,' she said to herself, (not in a very hopeful tone though), `I won't have any pepper in my kitchen AT ALL. Soup does very well without--Maybe it's always pepper that makes people hot-tempered,' she went on, very much pleased at having found out a new kind of rule, `and vinegar that makes them sour--and camomile that makes them bitter--and--and barley-sugar and such things that make children sweet-tempered. I only wish people knew that: then they wouldn't be so stingy about it, you know--' She had quite forgotten the Duchess by this time, and was a little startled when she heard her voice close to her ear. `You're thinking about something, my dear, and that makes you forget to talk. I can't tell you just now what the moral of that is, but I shall remember it in a bit.' `Perhaps it hasn't one,' Alice ventured to remark. `Tut, tut, child!' said the Duchess. `Everything's got a moral, if only you can find it.' And she squeezed herself up closer to Alice's side as she spoke. Alice did not much like keeping so close to her: first, because the Duchess was VERY ugly; and secondly, because she was exactly the right height to rest her chin upon Alice's shoulder, and it was an uncomfortably sharp chin. However, she did not like to be rude, so she bore it as well as she could. `The game's going on rather better now,' she said, by way of keeping up the conversation a little. `'Tis so,' said the Duchess: `and the moral of that is--"Oh, 'tis love, 'tis love, that makes the world go round!"' `Somebody said,' Alice whispered, `that it's done by everybody minding their own business!' `Ah, well! It means much the same thing,' said the Duchess, digging her sharp little chin into Alice's shoulder as she added, `and the moral of THAT is--"Take care of the sense, and the sounds will take care of themselves."' `How fond she is of finding morals in things!' Alice thought to herself. `I dare say you're wondering why I don't put my arm round your waist,' the Duchess said after a pause: `the reason is, that I'm doubtful about the temper of your flamingo. Shall I try the experiment?' `HE might bite,' Alice cautiously replied, not feeling at all anxious to have the experiment tried. `Very true,' said the Duchess: `flamingoes and mustard both bite. And the moral of that is--"Birds of a feather flock together."' `Only mustard isn't a bird,' Alice remarked. `Right, as usual,' said the Duchess: `what a clear way you have of putting things!' `It's a mineral, I THINK,' said Alice. `Of course it is,' said the Duchess, who seemed ready to agree to everything that Alice said; `there's a large mustard-mine near here. And the moral of that is--"The more there is of mine, the less there is of yours."' `Oh, I know!' exclaimed Alice, who had not attended to this last remark, `it's a vegetable. It doesn't look like one, but it is.' `I quite agree with you,' said the Duchess; `and the moral of that is--"Be what you would seem to be"--or if you'd like it put more simply--"Never imagine yourself not to be otherwise than what it might appear to others that what you were or might have been was not otherwise than what you had been would have appeared to them to be otherwise."' `I think I should understand that better,' Alice said very politely, `if I had it written down: but I can't quite follow it as you say it.' `That's nothing to what I could say if I chose,' the Duchess replied, in a pleased tone. `Pray don't trouble yourself to say it any longer than that,' said Alice. `Oh, don't talk about trouble!' said the Duchess. `I make you a present of everything I've said as yet.' `A cheap sort of present!' thought Alice. `I'm glad they don't give birthday presents like that!' But she did not venture to say it out loud. `Thinking again?' the Duchess asked, with another dig of her sharp little chin. `I've a right to think,' said Alice sharply, for she was beginning to feel a little worried. `Just about as much right,' said the Duchess, `as pigs have to fly; and the m--' But here, to Alice's great surprise, the Duchess's voice died away, even in the middle of her favourite word `moral,' and the arm that was linked into hers began to tremble. Alice looked up, and there stood the Queen in front of them, with her arms folded, frowning like a thunderstorm. `A fine day, your Majesty!' the Duchess began in a low, weak voice. `Now, I give you fair warning,' shouted the Queen, stamping on the ground as she spoke; `either you or your head must be off, and that in about half no time! Take your choice!' The Duchess took her choice, and was gone in a moment. `Let's go on with the game,' the Queen said to Alice; and Alice was too much frightened to say a word, but slowly followed her back to the croquet-ground. The other guests had taken advantage of the Queen's absence, and were resting in the shade: however, the moment they saw her, they hurried back to the game, the Queen merely remarking that a moment's delay would cost them their lives. All the time they were playing the Queen never left off quarrelling with the other players, and shouting `Off with his head!' or `Off with her head!' Those whom she sentenced were taken into custody by the soldiers, who of course had to leave off being arches to do this, so that by the end of half an hour or so there were no arches left, and all the players, except the King, the Queen, and Alice, were in custody and under sentence of execution. Then the Queen left off, quite out of breath, and said to Alice, `Have you seen the Mock Turtle yet?' `No,' said Alice. `I don't even know what a Mock Turtle is.' `It's the thing Mock Turtle Soup is made from,' said the Queen. `I never saw one, or heard of one,' said Alice. `Come on, then,' said the Queen, `and he shall tell you his history,' As they walked off together, Alice heard the King say in a low voice, to the company generally, `You are all pardoned.' `Come, THAT'S a good thing!' she said to herself, for she had felt quite unhappy at the number of executions the Queen had ordered. They very soon came upon a Gryphon, lying fast asleep in the sun. (IF you don't know what a Gryphon is, look at the picture.) `Up, lazy thing!' said the Queen, `and take this young lady to see the Mock Turtle, and to hear his history. I must go back and see after some executions I have ordered'; and she walked off, leaving Alice alone with the Gryphon. Alice did not quite like the look of the creature, but on the whole she thought it would be quite as safe to stay with it as to go after that savage Queen: so she waited. The Gryphon sat up and rubbed its eyes: then it watched the Queen till she was out of sight: then it chuckled. `What fun!' said the Gryphon, half to itself, half to Alice. `What IS the fun?' said Alice. `Why, SHE,' said the Gryphon. `It's all her fancy, that: they never executes nobody, you know. Come on!' `Everybody says "come on!" here,' thought Alice, as she went slowly after it: `I never was so ordered about in all my life, never!' They had not gone far before they saw the Mock Turtle in the distance, sitting sad and lonely on a little ledge of rock, and, as they came nearer, Alice could hear him sighing as if his heart would break. She pitied him deeply. `What is his sorrow?' she asked the Gryphon, and the Gryphon answered, very nearly in the same words as before, `It's all his fancy, that: he hasn't got no sorrow, you know. Come on!' So they went up to the Mock Turtle, who looked at them with large eyes full of tears, but said nothing. `This here young lady,' said the Gryphon, `she wants for to know your history, she do.' `I'll tell it her,' said the Mock Turtle in a deep, hollow tone: `sit down, both of you, and don't speak a word till I've finished.' So they sat down, and nobody spoke for some minutes. Alice thought to herself, `I don't see how he can EVEN finish, if he doesn't begin.' But she waited patiently. `Once,' said the Mock Turtle at last, with a deep sigh, `I was a real Turtle.' These words were followed by a very long silence, broken only by an occasional exclamation of `Hjckrrh!' from the Gryphon, and the constant heavy sobbing of the Mock Turtle. Alice was very nearly getting up and saying, `Thank you, sir, for your interesting story,' but she could not help thinking there MUST be more to come, so she sat still and said nothing. `When we were little,' the Mock Turtle went on at last, more calmly, though still sobbing a little now and then, `we went to school in the sea. The master was an old Turtle--we used to call him Tortoise--' `Why did you call him Tortoise, if he wasn't one?' Alice asked. `We called him Tortoise because he taught us,' said the Mock Turtle angrily: `really you are very dull!' `You ought to be ashamed of yourself for asking such a simple question,' added the Gryphon; and then they both sat silent and looked at poor Alice, who felt ready to sink into the earth. At last the Gryphon said to the Mock Turtle, `Drive on, old fellow! Don't be all day about it!' and he went on in these words: `Yes, we went to school in the sea, though you mayn't believe it--' `I never said I didn't!' interrupted Alice. `You did,' said the Mock Turtle. `Hold your tongue!' added the Gryphon, before Alice could speak again. The Mock Turtle went on. `We had the best of educations--in fact, we went to school every day--' `I'VE been to a day-school, too,' said Alice; `you needn't be so proud as all that.' `With extras?' asked the Mock Turtle a little anxiously. `Yes,' said Alice, `we learned French and music.' `And washing?' said the Mock Turtle. `Certainly not!' said Alice indignantly. `Ah! then yours wasn't a really good school,' said the Mock Turtle in a tone of great relief. `Now at OURS they had at the end of the bill, "French, music, AND WASHING--extra."' `You couldn't have wanted it much,' said Alice; `living at the bottom of the sea.' `I couldn't afford to learn it.' said the Mock Turtle with a sigh. `I only took the regular course.' `What was that?' inquired Alice. `Reeling and Writhing, of course, to begin with,' the Mock Turtle replied; `and then the different branches of Arithmetic-- Ambition, Distraction, Uglification, and Derision.' `I never heard of "Uglification,"' Alice ventured to say. `What is it?' The Gryphon lifted up both its paws in surprise. `What! Never heard of uglifying!' it exclaimed. `You know what to beautify is, I suppose?' `Yes,' said Alice doubtfully: `it means--to--make--anything--prettier.' `Well, then,' the Gryphon went on, `if you don't know what to uglify is, you ARE a simpleton.' Alice did not feel encouraged to ask any more questions about it, so she turned to the Mock Turtle, and said `What else had you to learn?' `Well, there was Mystery,' the Mock Turtle replied, counting off the subjects on his flappers, `--Mystery, ancient and modern, with Seaography: then Drawling--the Drawling-master was an old conger-eel, that used to come once a week: HE taught us Drawling, Stretching, and Fainting in Coils.' `What was THAT like?' said Alice. `Well, I can't show it you myself,' the Mock Turtle said: `I'm too stiff. And the Gryphon never learnt it.' `Hadn't time,' said the Gryphon: `I went to the Classics master, though. He was an old crab, HE was.' `I never went to him,' the Mock Turtle said with a sigh: `he taught Laughing and Grief, they used to say.' `So he did, so he did,' said the Gryphon, sighing in his turn; and both creatures hid their faces in their paws. `And how many hours a day did you do lessons?' said Alice, in a hurry to change the subject. `Ten hours the first day,' said the Mock Turtle: `nine the next, and so on.' `What a curious plan!' exclaimed Alice. `That's the reason they're called lessons,' the Gryphon remarked: `because they lessen from day to day.' This was quite a new idea to Alice, and she thought it over a little before she made her next remark. `Then the eleventh day must have been a holiday?' `Of course it was,' said the Mock Turtle. `And how did you manage on the twelfth?' Alice went on eagerly. `That's enough about lessons,' the Gryphon interrupted in a very decided tone: `tell her something about the games now.' CHAPTER X The Lobster Quadrille The Mock Turtle sighed deeply, and drew the back of one flapper across his eyes. He looked at Alice, and tried to speak, but for a minute or two sobs choked his voice. `Same as if he had a bone in his throat,' said the Gryphon: and it set to work shaking him and punching him in the back. At last the Mock Turtle recovered his voice, and, with tears running down his cheeks, he went on again:-- `You may not have lived much under the sea--' (`I haven't,' said Alice)-- `and perhaps you were never even introduced to a lobster--' (Alice began to say `I once tasted--' but checked herself hastily, and said `No, never') `--so you can have no idea what a delightful thing a Lobster Quadrille is!' `No, indeed,' said Alice. `What sort of a dance is it?' `Why,' said the Gryphon, `you first form into a line along the sea-shore--' `Two lines!' cried the Mock Turtle. `Seals, turtles, salmon, and so on; then, when you've cleared all the jelly-fish out of the way--' `THAT generally takes some time,' interrupted the Gryphon. `--you advance twice--' `Each with a lobster as a partner!' cried the Gryphon. `Of course,' the Mock Turtle said: `advance twice, set to partners--' `--change lobsters, and retire in same order,' continued the Gryphon. `Then, you know,' the Mock Turtle went on, `you throw the--' `The lobsters!' shouted the Gryphon, with a bound into the air. `--as far out to sea as you can--' `Swim after them!' screamed the Gryphon. `Turn a somersault in the sea!' cried the Mock Turtle, capering wildly about. `Change lobsters again!' yelled the Gryphon at the top of its voice. `Back to land again, and that's all the first figure,' said the Mock Turtle, suddenly dropping his voice; and the two creatures, who had been jumping about like mad things all this time, sat down again very sadly and quietly, and looked at Alice. `It must be a very pretty dance,' said Alice timidly. `Would you like to see a little of it?' said the Mock Turtle. `Very much indeed,' said Alice. `Come, let's try the first figure!' said the Mock Turtle to the Gryphon. `We can do without lobsters, you know. Which shall sing?' `Oh, YOU sing,' said the Gryphon. `I've forgotten the words.' So they began solemnly dancing round and round Alice, every now and then treading on her toes when they passed too close, and waving their forepaws to mark the time, while the Mock Turtle sang this, very slowly and sadly:-- `"Will you walk a little faster?" said a whiting to a snail. "There's a porpoise close behind us, and he's treading on my tail. See how eagerly the lobsters and the turtles all advance! They are waiting on the shingle--will you come and join the dance? Will you, won't you, will you, won't you, will you join the dance? Will you, won't you, will you, won't you, won't you join the dance? "You can really have no notion how delightful it will be When they take us up and throw us, with the lobsters, out to sea!" But the snail replied "Too far, too far!" and gave a look askance-- Said he thanked the whiting kindly, but he would not join the dance. Would not, could not, would not, could not, would not join the dance. Would not, could not, would not, could not, could not join the dance. `"What matters it how far we go?" his scaly friend replied. "There is another shore, you know, upon the other side. The further off from England the nearer is to France-- Then turn not pale, beloved snail, but come and join the dance. Will you, won't you, will you, won't you, will you join the dance? Will you, won't you, will you, won't you, won't you join the dance?"' `Thank you, it's a very interesting dance to watch,' said Alice, feeling very glad that it was over at last: `and I do so like that curious song about the whiting!' `Oh, as to the whiting,' said the Mock Turtle, `they--you've seen them, of course?' `Yes,' said Alice, `I've often seen them at dinn--' she checked herself hastily. `I don't know where Dinn may be,' said the Mock Turtle, `but if you've seen them so often, of course you know what they're like.' `I believe so,' Alice replied thoughtfully. `They have their tails in their mouths--and they're all over crumbs.' `You're wrong about the crumbs,' said the Mock Turtle: `crumbs would all wash off in the sea. But they HAVE their tails in their mouths; and the reason is--' here the Mock Turtle yawned and shut his eyes.--`Tell her about the reason and all that,' he said to the Gryphon. `The reason is,' said the Gryphon, `that they WOULD go with the lobsters to the dance. So they got thrown out to sea. So they had to fall a long way. So they got their tails fast in their mouths. So they couldn't get them out again. That's all.' `Thank you,' said Alice, `it's very interesting. I never knew so much about a whiting before.' `I can tell you more than that, if you like,' said the Gryphon. `Do you know why it's called a whiting?' `I never thought about it,' said Alice. `Why?' `IT DOES THE BOOTS AND SHOES.' the Gryphon replied very solemnly. Alice was thoroughly puzzled. `Does the boots and shoes!' she repeated in a wondering tone. `Why, what are YOUR shoes done with?' said the Gryphon. `I mean, what makes them so shiny?' Alice looked down at them, and considered a little before she gave her answer. `They're done with blacking, I believe.' `Boots and shoes under the sea,' the Gryphon went on in a deep voice, `are done with a whiting. Now you know.' `And what are they made of?' Alice asked in a tone of great curiosity. `Soles and eels, of course,' the Gryphon replied rather impatiently: `any shrimp could have told you that.' `If I'd been the whiting,' said Alice, whose thoughts were still running on the song, `I'd have said to the porpoise, "Keep back, please: we don't want YOU with us!"' `They were obliged to have him with them,' the Mock Turtle said: `no wise fish would go anywhere without a porpoise.' `Wouldn't it really?' said Alice in a tone of great surprise. `Of course not,' said the Mock Turtle: `why, if a fish came to ME, and told me he was going a journey, I should say "With what porpoise?"' `Don't you mean "purpose"?' said Alice. `I mean what I say,' the Mock Turtle replied in an offended tone. And the Gryphon added `Come, let's hear some of YOUR adventures.' `I could tell you my adventures--beginning from this morning,' said Alice a little timidly: `but it's no use going back to yesterday, because I was a different person then.' `Explain all that,' said the Mock Turtle. `No, no! The adventures first,' said the Gryphon in an impatient tone: `explanations take such a dreadful time.' So Alice began telling them her adventures from the time when she first saw the White Rabbit. She was a little nervous about it just at first, the two creatures got so close to her, one on each side, and opened their eyes and mouths so VERY wide, but she gained courage as she went on. Her listeners were perfectly quiet till she got to the part about her repeating `YOU ARE OLD, FATHER WILLIAM,' to the Caterpillar, and the words all coming different, and then the Mock Turtle drew a long breath, and said `That's very curious.' `It's all about as curious as it can be,' said the Gryphon. `It all came different!' the Mock Turtle repeated thoughtfully. `I should like to hear her try and repeat something now. Tell her to begin.' He looked at the Gryphon as if he thought it had some kind of authority over Alice. `Stand up and repeat "'TIS THE VOICE OF THE SLUGGARD,"' said the Gryphon. `How the creatures order one about, and make one repeat lessons!' thought Alice; `I might as well be at school at once.' However, she got up, and began to repeat it, but her head was so full of the Lobster Quadrille, that she hardly knew what she was saying, and the words came very queer indeed:-- `'Tis the voice of the Lobster; I heard him declare, "You have baked me too brown, I must sugar my hair." As a duck with its eyelids, so he with his nose Trims his belt and his buttons, and turns out his toes.' [later editions continued as follows When the sands are all dry, he is gay as a lark, And will talk in contemptuous tones of the Shark, But, when the tide rises and sharks are around, His voice has a timid and tremulous sound.] `That's different from what I used to say when I was a child,' said the Gryphon. `Well, I never heard it before,' said the Mock Turtle; `but it sounds uncommon nonsense.' Alice said nothing; she had sat down with her face in her hands, wondering if anything would EVER happen in a natural way again. `I should like to have it explained,' said the Mock Turtle. `She can't explain it,' said the Gryphon hastily. `Go on with the next verse.' `But about his toes?' the Mock Turtle persisted. `How COULD he turn them out with his nose, you know?' `It's the first position in dancing.' Alice said; but was dreadfully puzzled by the whole thing, and longed to change the subject. `Go on with the next verse,' the Gryphon repeated impatiently: `it begins "I passed by his garden."' Alice did not dare to disobey, though she felt sure it would all come wrong, and she went on in a trembling voice:-- `I passed by his garden, and marked, with one eye, How the Owl and the Panther were sharing a pie--' [later editions continued as follows The Panther took pie-crust, and gravy, and meat, While the Owl had the dish as its share of the treat. When the pie was all finished, the Owl, as a boon, Was kindly permitted to pocket the spoon: While the Panther received knife and fork with a growl, And concluded the banquet--] `What IS the use of repeating all that stuff,' the Mock Turtle interrupted, `if you don't explain it as you go on? It's by far the most confusing thing I ever heard!' `Yes, I think you'd better leave off,' said the Gryphon: and Alice was only too glad to do so. `Shall we try another figure of the Lobster Quadrille?' the Gryphon went on. `Or would you like the Mock Turtle to sing you a song?' `Oh, a song, please, if the Mock Turtle would be so kind,' Alice replied, so eagerly that the Gryphon said, in a rather offended tone, `Hm! No accounting for tastes! Sing her "Turtle Soup," will you, old fellow?' The Mock Turtle sighed deeply, and began, in a voice sometimes choked with sobs, to sing this:-- `Beautiful Soup, so rich and green, Waiting in a hot tureen! Who for such dainties would not stoop? Soup of the evening, beautiful Soup! Soup of the evening, beautiful Soup! Beau--ootiful Soo--oop! Beau--ootiful Soo--oop! Soo--oop of the e--e--evening, Beautiful, beautiful Soup! `Beautiful Soup! Who cares for fish, Game, or any other dish? Who would not give all else for two Pennyworth only of beautiful Soup? Pennyworth only of beautiful Soup? Beau--ootiful Soo--oop! Beau--ootiful Soo--oop! Soo--oop of the e--e--evening, Beautiful, beauti--FUL SOUP!' `Chorus again!' cried the Gryphon, and the Mock Turtle had just begun to repeat it, when a cry of `The trial's beginning!' was heard in the distance. `Come on!' cried the Gryphon, and, taking Alice by the hand, it hurried off, without waiting for the end of the song. `What trial is it?' Alice panted as she ran; but the Gryphon only answered `Come on!' and ran the faster, while more and more faintly came, carried on the breeze that followed them, the melancholy words:-- `Soo--oop of the e--e--evening, Beautiful, beautiful Soup!' CHAPTER XI Who Stole the Tarts? The King and Queen of Hearts were seated on their throne when they arrived, with a great crowd assembled about them--all sorts of little birds and beasts, as well as the whole pack of cards: the Knave was standing before them, in chains, with a soldier on each side to guard him; and near the King was the White Rabbit, with a trumpet in one hand, and a scroll of parchment in the other. In the very middle of the court was a table, with a large dish of tarts upon it: they looked so good, that it made Alice quite hungry to look at them--`I wish they'd get the trial done,' she thought, `and hand round the refreshments!' But there seemed to be no chance of this, so she began looking at everything about her, to pass away the time. Alice had never been in a court of justice before, but she had read about them in books, and she was quite pleased to find that she knew the name of nearly everything there. `That's the judge,' she said to herself, `because of his great wig.' The judge, by the way, was the King; and as he wore his crown over the wig, (look at the frontispiece if you want to see how he did it,) he did not look at all comfortable, and it was certainly not becoming. `And that's the jury-box,' thought Alice, `and those twelve creatures,' (she was obliged to say `creatures,' you see, because some of them were animals, and some were birds,) `I suppose they are the jurors.' She said this last word two or three times over to herself, being rather proud of it: for she thought, and rightly too, that very few little girls of her age knew the meaning of it at all. However, `jury-men' would have done just as well. The twelve jurors were all writing very busily on slates. `What are they doing?' Alice whispered to the Gryphon. `They can't have anything to put down yet, before the trial's begun.' `They're putting down their names,' the Gryphon whispered in reply, `for fear they should forget them before the end of the trial.' `Stupid things!' Alice began in a loud, indignant voice, but she stopped hastily, for the White Rabbit cried out, `Silence in the court!' and the King put on his spectacles and looked anxiously round, to make out who was talking. Alice could see, as well as if she were looking over their shoulders, that all the jurors were writing down `stupid things!' on their slates, and she could even make out that one of them didn't know how to spell `stupid,' and that he had to ask his neighbour to tell him. `A nice muddle their slates'll be in before the trial's over!' thought Alice. One of the jurors had a pencil that squeaked. This of course, Alice could not stand, and she went round the court and got behind him, and very soon found an opportunity of taking it away. She did it so quickly that the poor little juror (it was Bill, the Lizard) could not make out at all what had become of it; so, after hunting all about for it, he was obliged to write with one finger for the rest of the day; and this was of very little use, as it left no mark on the slate. `Herald, read the accusation!' said the King. On this the White Rabbit blew three blasts on the trumpet, and then unrolled the parchment scroll, and read as follows:-- `The Queen of Hearts, she made some tarts, All on a summer day: The Knave of Hearts, he stole those tarts, And took them quite away!' `Consider your verdict,' the King said to the jury. `Not yet, not yet!' the Rabbit hastily interrupted. `There's a great deal to come before that!' `Call the first witness,' said the King; and the White Rabbit blew three blasts on the trumpet, and called out, `First witness!' The first witness was the Hatter. He came in with a teacup in one hand and a piece of bread-and-butter in the other. `I beg pardon, your Majesty,' he began, `for bringing these in: but I hadn't quite finished my tea when I was sent for.' `You ought to have finished,' said the King. `When did you begin?' The Hatter looked at the March Hare, who had followed him into the court, arm-in-arm with the Dormouse. `Fourteenth of March, I think it was,' he said. `Fifteenth,' said the March Hare. `Sixteenth,' added the Dormouse. `Write that down,' the King said to the jury, and the jury eagerly wrote down all three dates on their slates, and then added them up, and reduced the answer to shillings and pence. `Take off your hat,' the King said to the Hatter. `It isn't mine,' said the Hatter. `Stolen!' the King exclaimed, turning to the jury, who instantly made a memorandum of the fact. `I keep them to sell,' the Hatter added as an explanation; `I've none of my own. I'm a hatter.' Here the Queen put on her spectacles, and began staring at the Hatter, who turned pale and fidgeted. `Give your evidence,' said the King; `and don't be nervous, or I'll have you executed on the spot.' This did not seem to encourage the witness at all: he kept shifting from one foot to the other, looking uneasily at the Queen, and in his confusion he bit a large piece out of his teacup instead of the bread-and-butter. Just at this moment Alice felt a very curious sensation, which puzzled her a good deal until she made out what it was: she was beginning to grow larger again, and she thought at first she would get up and leave the court; but on second thoughts she decided to remain where she was as long as there was room for her. `I wish you wouldn't squeeze so.' said the Dormouse, who was sitting next to her. `I can hardly breathe.' `I can't help it,' said Alice very meekly: `I'm growing.' `You've no right to grow here,' said the Dormouse. `Don't talk nonsense,' said Alice more boldly: `you know you're growing too.' `Yes, but I grow at a reasonable pace,' said the Dormouse: `not in that ridiculous fashion.' And he got up very sulkily and crossed over to the other side of the court. All this time the Queen had never left off staring at the Hatter, and, just as the Dormouse crossed the court, she said to one of the officers of the court, `Bring me the list of the singers in the last concert!' on which the wretched Hatter trembled so, that he shook both his shoes off. `Give your evidence,' the King repeated angrily, `or I'll have you executed, whether you're nervous or not.' `I'm a poor man, your Majesty,' the Hatter began, in a trembling voice, `--and I hadn't begun my tea--not above a week or so--and what with the bread-and-butter getting so thin--and the twinkling of the tea--' `The twinkling of the what?' said the King. `It began with the tea,' the Hatter replied. `Of course twinkling begins with a T!' said the King sharply. `Do you take me for a dunce? Go on!' `I'm a poor man,' the Hatter went on, `and most things twinkled after that--only the March Hare said--' `I didn't!' the March Hare interrupted in a great hurry. `You did!' said the Hatter. `I deny it!' said the March Hare. `He denies it,' said the King: `leave out that part.' `Well, at any rate, the Dormouse said--' the Hatter went on, looking anxiously round to see if he would deny it too: but the Dormouse denied nothing, being fast asleep. `After that,' continued the Hatter, `I cut some more bread- and-butter--' `But what did the Dormouse say?' one of the jury asked. `That I can't remember,' said the Hatter. `You MUST remember,' remarked the King, `or I'll have you executed.' The miserable Hatter dropped his teacup and bread-and-butter, and went down on one knee. `I'm a poor man, your Majesty,' he began. `You're a very poor speaker,' said the King. Here one of the guinea-pigs cheered, and was immediately suppressed by the officers of the court. (As that is rather a hard word, I will just explain to you how it was done. They had a large canvas bag, which tied up at the mouth with strings: into this they slipped the guinea-pig, head first, and then sat upon it.) `I'm glad I've seen that done,' thought Alice. `I've so often read in the newspapers, at the end of trials, "There was some attempts at applause, which was immediately suppressed by the officers of the court," and I never understood what it meant till now.' `If that's all you know about it, you may stand down,' continued the King. `I can't go no lower,' said the Hatter: `I'm on the floor, as it is.' `Then you may SIT down,' the King replied. Here the other guinea-pig cheered, and was suppressed. `Come, that finished the guinea-pigs!' thought Alice. `Now we shall get on better.' `I'd rather finish my tea,' said the Hatter, with an anxious look at the Queen, who was reading the list of singers. `You may go,' said the King, and the Hatter hurriedly left the court, without even waiting to put his shoes on. `--and just take his head off outside,' the Queen added to one of the officers: but the Hatter was out of sight before the officer could get to the door. `Call the next witness!' said the King. The next witness was the Duchess's cook. She carried the pepper-box in her hand, and Alice guessed who it was, even before she got into the court, by the way the people near the door began sneezing all at once. `Give your evidence,' said the King. `Shan't,' said the cook. The King looked anxiously at the White Rabbit, who said in a low voice, `Your Majesty must cross-examine THIS witness.' `Well, if I must, I must,' the King said, with a melancholy air, and, after folding his arms and frowning at the cook till his eyes were nearly out of sight, he said in a deep voice, `What are tarts made of?' `Pepper, mostly,' said the cook. `Treacle,' said a sleepy voice behind her. `Collar that Dormouse,' the Queen shrieked out. `Behead that Dormouse! Turn that Dormouse out of court! Suppress him! Pinch him! Off with his whiskers!' For some minutes the whole court was in confusion, getting the Dormouse turned out, and, by the time they had settled down again, the cook had disappeared. `Never mind!' said the King, with an air of great relief. `Call the next witness.' And he added in an undertone to the Queen, `Really, my dear, YOU must cross-examine the next witness. It quite makes my forehead ache!' Alice watched the White Rabbit as he fumbled over the list, feeling very curious to see what the next witness would be like, `--for they haven't got much evidence YET,' she said to herself. Imagine her surprise, when the White Rabbit read out, at the top of his shrill little voice, the name `Alice!' CHAPTER XII Alice's Evidence `Here!' cried Alice, quite forgetting in the flurry of the moment how large she had grown in the last few minutes, and she jumped up in such a hurry that she tipped over the jury-box with the edge of her skirt, upsetting all the jurymen on to the heads of the crowd below, and there they lay sprawling about, reminding her very much of a globe of goldfish she had accidentally upset the week before. `Oh, I BEG your pardon!' she exclaimed in a tone of great dismay, and began picking them up again as quickly as she could, for the accident of the goldfish kept running in her head, and she had a vague sort of idea that they must be collected at once and put back into the jury-box, or they would die. `The trial cannot proceed,' said the King in a very grave voice, `until all the jurymen are back in their proper places-- ALL,' he repeated with great emphasis, looking hard at Alice as he said do. Alice looked at the jury-box, and saw that, in her haste, she had put the Lizard in head downwards, and the poor little thing was waving its tail about in a melancholy way, being quite unable to move. She soon got it out again, and put it right; `not that it signifies much,' she said to herself; `I should think it would be QUITE as much use in the trial one way up as the other.' As soon as the jury had a little recovered from the shock of being upset, and their slates and pencils had been found and handed back to them, they set to work very diligently to write out a history of the accident, all except the Lizard, who seemed too much overcome to do anything but sit with its mouth open, gazing up into the roof of the court. `What do you know about this business?' the King said to Alice. `Nothing,' said Alice. `Nothing WHATEVER?' persisted the King. `Nothing whatever,' said Alice. `That's very important,' the King said, turning to the jury. They were just beginning to write this down on their slates, when the White Rabbit interrupted: `UNimportant, your Majesty means, of course,' he said in a very respectful tone, but frowning and making faces at him as he spoke. `UNimportant, of course, I meant,' the King hastily said, and went on to himself in an undertone, `important--unimportant-- unimportant--important--' as if he were trying which word sounded best. Some of the jury wrote it down `important,' and some `unimportant.' Alice could see this, as she was near enough to look over their slates; `but it doesn't matter a bit,' she thought to herself. At this moment the King, who had been for some time busily writing in his note-book, cackled out `Silence!' and read out from his book, `Rule Forty-two. ALL PERSONS MORE THAN A MILE HIGH TO LEAVE THE COURT.' Everybody looked at Alice. `I'M not a mile high,' said Alice. `You are,' said the King. `Nearly two miles high,' added the Queen. `Well, I shan't go, at any rate,' said Alice: `besides, that's not a regular rule: you invented it just now.' `It's the oldest rule in the book,' said the King. `Then it ought to be Number One,' said Alice. The King turned pale, and shut his note-book hastily. `Consider your verdict,' he said to the jury, in a low, trembling voice. `There's more evidence to come yet, please your Majesty,' said the White Rabbit, jumping up in a great hurry; `this paper has just been picked up.' `What's in it?' said the Queen. `I haven't opened it yet,' said the White Rabbit, `but it seems to be a letter, written by the prisoner to--to somebody.' `It must have been that,' said the King, `unless it was written to nobody, which isn't usual, you know.' `Who is it directed to?' said one of the jurymen. `It isn't directed at all,' said the White Rabbit; `in fact, there's nothing written on the OUTSIDE.' He unfolded the paper as he spoke, and added `It isn't a letter, after all: it's a set of verses.' `Are they in the prisoner's handwriting?' asked another of the jurymen. `No, they're not,' said the White Rabbit, `and that's the queerest thing about it.' (The jury all looked puzzled.) `He must have imitated somebody else's hand,' said the King. (The jury all brightened up again.) `Please your Majesty,' said the Knave, `I didn't write it, and they can't prove I did: there's no name signed at the end.' `If you didn't sign it,' said the King, `that only makes the matter worse. You MUST have meant some mischief, or else you'd have signed your name like an honest man.' There was a general clapping of hands at this: it was the first really clever thing the King had said that day. `That PROVES his guilt,' said the Queen. `It proves nothing of the sort!' said Alice. `Why, you don't even know what they're about!' `Read them,' said the King. The White Rabbit put on his spectacles. `Where shall I begin, please your Majesty?' he asked. `Begin at the beginning,' the King said gravely, `and go on till you come to the end: then stop.' These were the verses the White Rabbit read:-- `They told me you had been to her, And mentioned me to him: She gave me a good character, But said I could not swim. He sent them word I had not gone (We know it to be true): If she should push the matter on, What would become of you? I gave her one, they gave him two, You gave us three or more; They all returned from him to you, Though they were mine before. If I or she should chance to be Involved in this affair, He trusts to you to set them free, Exactly as we were. My notion was that you had been (Before she had this fit) An obstacle that came between Him, and ourselves, and it. Don't let him know she liked them best, For this must ever be A secret, kept from all the rest, Between yourself and me.' `That's the most important piece of evidence we've heard yet,' said the King, rubbing his hands; `so now let the jury--' `If any one of them can explain it,' said Alice, (she had grown so large in the last few minutes that she wasn't a bit afraid of interrupting him,) `I'll give him sixpence. _I_ don't believe there's an atom of meaning in it.' The jury all wrote down on their slates, `SHE doesn't believe there's an atom of meaning in it,' but none of them attempted to explain the paper. `If there's no meaning in it,' said the King, `that saves a world of trouble, you know, as we needn't try to find any. And yet I don't know,' he went on, spreading out the verses on his knee, and looking at them with one eye; `I seem to see some meaning in them, after all. "--SAID I COULD NOT SWIM--" you can't swim, can you?' he added, turning to the Knave. The Knave shook his head sadly. `Do I look like it?' he said. (Which he certainly did NOT, being made entirely of cardboard.) `All right, so far,' said the King, and he went on muttering over the verses to himself: `"WE KNOW IT TO BE TRUE--" that's the jury, of course-- "I GAVE HER ONE, THEY GAVE HIM TWO--" why, that must be what he did with the tarts, you know--' `But, it goes on "THEY ALL RETURNED FROM HIM TO YOU,"' said Alice. `Why, there they are!' said the King triumphantly, pointing to the tarts on the table. `Nothing can be clearer than THAT. Then again--"BEFORE SHE HAD THIS FIT--" you never had fits, my dear, I think?' he said to the Queen. `Never!' said the Queen furiously, throwing an inkstand at the Lizard as she spoke. (The unfortunate little Bill had left off writing on his slate with one finger, as he found it made no mark; but he now hastily began again, using the ink, that was trickling down his face, as long as it lasted.) `Then the words don't FIT you,' said the King, looking round the court with a smile. There was a dead silence. `It's a pun!' the King added in an offended tone, and everybody laughed, `Let the jury consider their verdict,' the King said, for about the twentieth time that day. `No, no!' said the Queen. `Sentence first--verdict afterwards.' `Stuff and nonsense!' said Alice loudly. `The idea of having the sentence first!' `Hold your tongue!' said the Queen, turning purple. `I won't!' said Alice. `Off with her head!' the Queen shouted at the top of her voice. Nobody moved. `Who cares for you?' said Alice, (she had grown to her full size by this time.) `You're nothing but a pack of cards!' At this the whole pack rose up into the air, and came flying down upon her: she gave a little scream, half of fright and half of anger, and tried to beat them off, and found herself lying on the bank, with her head in the lap of her sister, who was gently brushing away some dead leaves that had fluttered down from the trees upon her face. `Wake up, Alice dear!' said her sister; `Why, what a long sleep you've had!' `Oh, I've had such a curious dream!' said Alice, and she told her sister, as well as she could remember them, all these strange Adventures of hers that you have just been reading about; and when she had finished, her sister kissed her, and said, `It WAS a curious dream, dear, certainly: but now run in to your tea; it's getting late.' So Alice got up and ran off, thinking while she ran, as well she might, what a wonderful dream it had been. But her sister sat still just as she left her, leaning her head on her hand, watching the setting sun, and thinking of little Alice and all her wonderful Adventures, till she too began dreaming after a fashion, and this was her dream:-- First, she dreamed of little Alice herself, and once again the tiny hands were clasped upon her knee, and the bright eager eyes were looking up into hers--she could hear the very tones of her voice, and see that queer little toss of her head to keep back the wandering hair that WOULD always get into her eyes--and still as she listened, or seemed to listen, the whole place around her became alive the strange creatures of her little sister's dream. The long grass rustled at her feet as the White Rabbit hurried by--the frightened Mouse splashed his way through the neighbouring pool--she could hear the rattle of the teacups as the March Hare and his friends shared their never-ending meal, and the shrill voice of the Queen ordering off her unfortunate guests to execution--once more the pig-baby was sneezing on the Duchess's knee, while plates and dishes crashed around it--once more the shriek of the Gryphon, the squeaking of the Lizard's slate-pencil, and the choking of the suppressed guinea-pigs, filled the air, mixed up with the distant sobs of the miserable Mock Turtle. So she sat on, with closed eyes, and half believed herself in Wonderland, though she knew she had but to open them again, and all would change to dull reality--the grass would be only rustling in the wind, and the pool rippling to the waving of the reeds--the rattling teacups would change to tinkling sheep- bells, and the Queen's shrill cries to the voice of the shepherd boy--and the sneeze of the baby, the shriek of the Gryphon, and all thy other queer noises, would change (she knew) to the confused clamour of the busy farm-yard--while the lowing of the cattle in the distance would take the place of the Mock Turtle's heavy sobs. Lastly, she pictured to herself how this same little sister of hers would, in the after-time, be herself a grown woman; and how she would keep, through all her riper years, the simple and loving heart of her childhood: and how she would gather about her other little children, and make THEIR eyes bright and eager with many a strange tale, perhaps even with the dream of Wonderland of long ago: and how she would feel with all their simple sorrows, and find a pleasure in all their simple joys, remembering her own child-life, and the happy summer days. THE END  ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/hello-profile-postscript.sh0000775000175000017500000000110612776215022027735 0ustar kaikai#!/usr/bin/env bash # strip out Dmain since it's symbol differs between windows and non-windows grep -v Dmain ${RESULTS_DIR}/runnable/hello-profile.d.trace.def > ${RESULTS_DIR}/runnable/hello-profile.d.trace.def2 diff --strip-trailing-cr runnable/extra-files/hello-profile.d.trace.def ${RESULTS_DIR}/runnable/hello-profile.d.trace.def2 if [ $? -ne 0 ]; then exit 1; fi tracelog=${RESULTS_DIR}/runnable/hello-profile.d.trace.log if [ ! -f ${tracelog} ]; then echo "missing file: ${tracelog}" exit 1 fi rm ${RESULTS_DIR}/runnable/hello-profile.d.trace.{def,def2,log} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/linkdebug_range.d0000664000175000017500000000131212776215022025711 0ustar kaikaimodule linkdebug_range; import linkdebug_primitives : popBackN, moveAt; auto stride(R)(R r) { static struct Result { R source; void popBack() { popBackN(source, 0); } uint moveAt(size_t n) { return .moveAt(source, n); } } return Result(r); } struct SortedRange(Range, alias pred = "a < b") { this(Range input) out { dbgVerifySorted(); } body { } void dbgVerifySorted() { debug { uint[] _input; auto st = stride(_input); } } } auto assumeSorted(alias pred = "a < b", R)(R r) { return SortedRange!(R, pred)(r); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/teststdio.txt0000664000175000017500000000002612776215022025210 0ustar kaikaiasdfasdf a sdf asdf ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/bug9010-postscript.sh0000775000175000017500000000103312776215022026262 0ustar kaikai#!/usr/bin/env bash # trim off the last line which contains the path of the file which differs between windows and non-windows LINE_COUNT_MINUS_1=$(( `wc -l < ${RESULTS_DIR}/runnable/runnable-bug9010.lst` - 1 )) head -n${LINE_COUNT_MINUS_1} ${RESULTS_DIR}/runnable/runnable-bug9010.lst > ${RESULTS_DIR}/runnable/runnable-bug9010.lst2 diff --strip-trailing-cr runnable/extra-files/runnable-bug9010.lst ${RESULTS_DIR}/runnable/runnable-bug9010.lst2 if [ $? -ne 0 ]; then exit 1 fi rm ${RESULTS_DIR}/runnable/runnable-bug9010.lst{,2} ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/main846.d0000664000175000017500000000014512776215022023762 0ustar kaikaiimport lib846; void main() { auto num = removeIf("abcdef".dup, (char c){ return c == 'c'; }); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/cpp_abi_tests.cpp0000664000175000017500000001001312776215022025745 0ustar kaikaistruct S{ float a; }; bool passthrough(bool value) { return value; } signed char passthrough(signed char value) { return value; } unsigned char passthrough(unsigned char value) { return value; } char passthrough(char value) { return value; } wchar_t passthrough(wchar_t value) { return value; } short passthrough(short value) { return value; } unsigned short passthrough(unsigned short value) { return value; } int passthrough(int value) { return value; } unsigned int passthrough(unsigned int value) { return value; } long passthrough(long value) { return value; } unsigned long passthrough(unsigned long value) { return value; } long long passthrough(long long value) { return value; } unsigned long long passthrough(unsigned long long value) { return value; } float passthrough(float value) { return value; } double passthrough(double value) { return value; } S passthrough(S value) { return value; } bool passthrough_ptr(bool *value) { return *value; } signed char passthrough_ptr(signed char *value) { return *value; } unsigned char passthrough_ptr(unsigned char *value) { return *value; } char passthrough_ptr(char *value) { return *value; } wchar_t passthrough_ptr(wchar_t *value) { return *value; } short passthrough_ptr(short *value) { return *value; } unsigned short passthrough_ptr(unsigned short *value) { return *value; } int passthrough_ptr(int *value) { return *value; } unsigned int passthrough_ptr(unsigned int *value) { return *value; } long passthrough_ptr(long *value) { return *value; } unsigned long passthrough_ptr(unsigned long *value) { return *value; } long long passthrough_ptr(long long *value) { return *value; } unsigned long long passthrough_ptr(unsigned long long *value) { return *value; } float passthrough_ptr(float *value) { return *value; } double passthrough_ptr(double *value) { return *value; } S passthrough_ptr(S *value) { return *value; } bool passthrough_ref(bool &value) { return value; } signed char passthrough_ref(signed char &value) { return value; } unsigned char passthrough_ref(unsigned char &value) { return value; } char passthrough_ref(char &value) { return value; } wchar_t passthrough_ref(wchar_t &value) { return value; } short passthrough_ref(short &value) { return value; } unsigned short passthrough_ref(unsigned short &value) { return value; } int passthrough_ref(int &value) { return value; } unsigned int passthrough_ref(unsigned int &value) { return value; } long passthrough_ref(long &value) { return value; } unsigned long passthrough_ref(unsigned long &value) { return value; } long long passthrough_ref(long long &value) { return value; } unsigned long long passthrough_ref(unsigned long long &value) { return value; } float passthrough_ref(float &value) { return value; } double passthrough_ref(double &value) { return value; } S passthrough_ref(S &value) { return value; } // Uncomment when mangling is fixed // typedef void(*fn0)(); // fn0 passthrough_fn0 (fn0 value) { return value; } // typedef int (*fn1)(int); // fn1 passthrough_fn1 (fn1 value) { return value; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/statictor-postscript.sh0000775000175000017500000000065612776215022027221 0ustar kaikai#!/usr/bin/env bash # trim off the first line which contains the path of the file which differs between windows and non-windows # also trim off compiler debug message grep -v "runnable\|DEBUG" $1 > ${RESULTS_DIR}/runnable/statictor.d.out.2 diff --strip-trailing-cr runnable/extra-files/statictor.d.out ${RESULTS_DIR}/runnable/statictor.d.out.2 if [ $? -ne 0 ]; then exit 1; fi rm ${RESULTS_DIR}/runnable/statictor.d.out.2 ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/test2.d0000664000175000017500000001357512776215022023650 0ustar kaikai import object; import core.stdc.stdio; import std.algorithm; /* ================================ */ class Foo { int foo(int x) { return x + 3; } } class Bar : Foo { override int foo(int y) { return y + 4; } } void test1() { Bar e; assert(e is null); e = new Bar(); assert(e.foo(5) == 9); } /* ================================ */ class Foo2 { int foo(int x) { return x + 3; } } class Bar2 : Foo2 { override int foo(int y) { assert(Foo2.foo(2) == 5); return y + 4; } } void test2() { Bar2 e; assert(e is null); e = new Bar2(); assert(e.foo(5) == 9); assert(e.Foo2.foo(10) == 13); } /* ================================ */ void test3() { debug printf("debug\n"); debug(1) printf("debug(1)\n"); debug(2) printf("debug(2)\n"); debug(3) printf("debug(3)\n"); debug(bar) printf("debug(bar)\n"); debug(10) assert(0); debug(1) { int d1 = 3; printf("debug(1) { }\n"); } debug(2) { printf("debug(2): d1 = %d\n", d1); } } /* ================================ */ int x1; int x2; class Foo4 { static this() { x1 = 3; printf("Foo4 ctor()\n"); } static ~this() { x1 = 4; printf("Foo4 dtor()\n"); } } static this() { x2 = 5; printf("ctor()\n"); } static ~this() { x2 = 6; printf("dtor()\n"); } void test4() { printf("x1 = %d, x2 = %d\n", x1, x2); assert(x1 == 3); assert(x2 == 5); } /* ================================ */ void test5() { printf("test5()\n"); static uint foo; static uint x = 3; static uint len = 32; version (D_Bits) { bit[] bits; bits = (cast(bit *)&foo)[0..len]; bits[6] = true; assert(foo == (1 << 6)); } } /* ================================ */ int[] test6_1(int[] a) { a.length = 6; return a; } void test6() { printf("test6()\n"); int b[3]; int a[]; b[0] = 0; b[1] = 1; b[2] = 2; assert(b.length == 3); a = test6_1(b); a[2] = 2; assert(a.length == 6); } /* ================================ */ class OutBuffer7 { char data[]; uint offset; void write(const(char) *p, uint nbytes) { data[offset .. offset + nbytes] = (cast(char *)p)[0 .. nbytes]; } } void test7() { printf("test7()\n"); int i; OutBuffer7 ob = new OutBuffer7; ob.data = new char[10]; printf("ob.data.length = %d\n", ob.data.length); assert(ob.data.length == 10); for (i = 0; i < 10; i++) assert(ob.data[i] == char.init); printf("test7.1()\n"); ob.data[] = '-'; printf("test7.2()\n"); printf("ob.data[] = '%.*s'\n", cast(int)ob.data.length, ob.data.ptr); for (i = 0; i < 10; i++) assert(ob.data[i] == '-'); ob.offset = 3; ob.write("foo", 3); printf("ob.data.length = %d\n", ob.data.length); printf("ob.data[] = '%.*s'\n", cast(int)ob.data.length, ob.data.ptr); for (i = 0; i < 10; i++) { if (i < 3 || i >= 6) assert(ob.data[i] == '-'); } assert(ob.data[3] == 'f'); assert(ob.data[4] == 'o'); assert(ob.data[5] == 'o'); } /* ================================ */ class A8 { enum { bar = 8, baz } int foo; } void test8() { printf("test8()\n"); A8 a; a = new A8(); a.foo = A8.bar; assert(a.foo == 8); } /* ================================ */ int z9; unittest { printf("module unittest 9\n"); z9 = 3; } void test9() { assert(z9 == 3); } /* ================================ */ void test10() { printf("test10()\n"); const int i = 8000; assert(i == 8000); static int j = 78; assert(j == 78); } /* ================================ */ Object test11_a() { return null; } void test11() { assert(test11_a() is null); } /* ================================ */ class A12 { } class B12 { } int testx(A12 a) { return 1; } int testx(B12 b) { return 2; } void test12() { A12 a = new A12(); B12 b = new B12(); assert(testx(a) == 1); assert(testx(b) == 2); } /* ================================ */ char[] tolower13(ref char[] s) { int i; for (i = 0; i < s.length; i++) { char c = s[i]; if ('A' <= c && c <= 'Z') s[i] = cast(char)(c + (cast(char)'a' - 'A')); } return s; } void test13() { auto s1 = "FoL".dup; char[] s2; s2 = tolower13(s1); assert(std.algorithm.cmp(s2, "fol") == 0); assert(s2 == s1); } /* ================================ */ alias ABC14* LPABC14; class ABC14 { } alias DEF14* LPDEF14; DEF14[3] foo; struct DEF14 { int x; } void test14() { assert(foo.sizeof == int.sizeof * 3); } /* ================================ */ class bits15 { bool a = true, b = true, c = true; void dump() { printf("%d %d %d\n", a, b, c); } } void test15() { bits15 k = new bits15; k.a = true; k.dump(); k.b = true; k.dump(); k.c = true; k.dump(); assert(k.a == true); assert(k.b == true); assert(k.c == true); } /* ================================ */ align(4) struct foo16 { short s; int i; } void test16() { assert(foo16.sizeof == 8); } /* ================================ */ enum Color { red, blue, green }; int[Color.max+1] colors1 = [ Color.blue:6, Color.green:2, Color.red:5 ]; enum { red, blue, green }; int[3] colors2 = [ blue:6, green:2, red:5 ]; void test17() { assert(colors1.length == 3); assert(colors1[0] == 5); assert(colors1[1] == 6); assert(colors1[2] == 2); assert(colors2[0] == 5); assert(colors2[1] == 6); assert(colors2[2] == 2); } /* ================================ */ class Test19 { struct { int a, b, c; } } void test19() { Test19 t = new Test19(); t.a = 3; assert(t.a == 3); } /* ================================ */ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test19(); printf("Success\n"); return 0; } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/ldc_cabi2.cpp0000664000175000017500000002454112776215022024743 0ustar kaikai#include #include #include // ldc_cabi1 defines these extern "C" { extern int8_t a, b, c, d, e, f, g, h; extern uint32_t errors; } #define TEST(b) \ if (!(b)) (++errors, printf("%s:%u: failed check\n", __FILE__, __LINE__)) static bool testar(int8_t* a, size_t len, int8_t a0) { for (size_t i = 0; i < len; ++i) { if (a[i] != (int8_t)(a0+i)) { return false; } } return true; } extern "C" { struct EMPTY {}; struct B1 {int8_t a;}; struct B2 {int8_t a, b;}; struct I1 {int a;}; struct I2 {int a, b;}; union UI1 {int a; short b; int8_t c;}; union UI1a {short a; int8_t b; int c;}; struct NI1 {I1 a;}; struct NUI1 {UI1 a;}; union UNI1 {UI1 a; NI1 b; int c;}; struct S3 {char a; short b;}; struct S6 {char a; int b; char c;}; struct S9 {char a; double b;}; struct S19 {char a; double b, c;}; struct F2 {float a, b;}; struct F4 {float a, b, c, d;}; struct D1 {double a;}; struct D2 {double a, b;}; struct D4 {double a, b, c, d;}; struct D5 {double a, b, c, d, e;}; struct D8 {double a, b, c, d, e, f, g, h;}; union UD4 {D1 a; D2 b; D4 c; double e;}; struct DA0 {double a[0];}; struct DA4 {double a[4];}; struct DA5 {double a[5];}; struct DA8 {double a[8];}; struct CA4 {char a[4];}; struct DHFA1 {EMPTY a; double d;}; //struct DHFA1 {EMPTY a; EMPTY b; double c[0]; double d;}; struct DHFA2 {double a; D1 b;}; struct DHFA2a {D1 a; double b;}; struct DHFA4x {D2 a[2];}; struct S1 {int8_t a;}; struct S2 {int8_t a;}; struct SA64 {int8_t a[64];}; struct SA65 {int8_t a[65];}; void dvfun(int s, ...); B1 dretb1(B1 x); B1 cretb1(B1 x) { TEST(x.a == a); B1 r = {++a}; return r; } B2 dretb2(B2 x); B2 cretb2(B2 x) { TEST(x.a == a); TEST(x.b == b); B2 r = {++a, ++b}; return r; } I1 dreti1(I1 x); I1 creti1(I1 x) { TEST(x.a == a); I1 r = {++a}; return r; } I2 dreti2(I2 x); I2 creti2(I2 x) { TEST(x.a == a); TEST(x.b == b); I2 r = {++a, ++b}; return r; } UI1a dretui1a(UI1a x); UI1a cretui1a(UI1a x) { TEST(x.c == a); UI1a r; r.c = ++a; return r; } UNI1 dretuni1(UNI1 x); UNI1 cretuni1(UNI1 x) { TEST(x.a.a == a); UNI1 r = {{++a}}; return r; } F4 dretf4(F4 x); F4 cretf4(F4 x) { TEST(x.a == a); TEST(x.b == b); TEST(x.c == c); TEST(x.d == d); F4 r = {(float)++a, (float)++b, (float)++c, (float)++d}; return r; } D4 dretd4(D4 x); D4 cretd4(D4 x) { TEST(x.a == a); TEST(x.b == b); TEST(x.c == c); TEST(x.d == d); D4 r = {(double)++a, (double)++b, (double)++c, (double)++d}; return r; } D5 dretd5(D5 x); D5 cretd5(D5 x) { TEST(x.a == a); TEST(x.b == b); TEST(x.c == c); TEST(x.d == d); TEST(x.e == e); D5 r = {(double)++a, (double)++b, (double)++c, (double)++d, (double)++e}; return r; } D8 dretd8(D8 x); D8 cretd8(D8 x) { TEST(x.a == a); TEST(x.b == b); TEST(x.c == c); TEST(x.d == d); TEST(x.e == e); TEST(x.f == f); TEST(x.g == g); TEST(x.h == h); D8 r = {(double)++a, (double)++b, (double)++c, (double)++d, (double)++e, (double)++f, (double)++g, (double)++h}; return r; } UD4 dretud4(UD4 x); UD4 cretud4(UD4 x) { TEST(x.c.a == a); TEST(x.c.b == b); TEST(x.c.c == c); TEST(x.c.d == d); UD4 r; D4 d4 = {(double)++a, (double)++b, (double)++c, (double)++d}; r.c = d4; return r; } DA0 dretda0(DA0 x); DA0 cretda0(DA0 x) { DA0 r; return r; } DA4 dretda4(DA4 x); DA4 cretda4(DA4 x) { TEST(x.a[0] == a); TEST(x.a[1] == b); TEST(x.a[2] == c); TEST(x.a[3] == d); DA4 r = {(double)++a, (double)++b, (double)++c, (double)++d}; return r; } DA5 dretda5(DA5 x); DA5 cretda5(DA5 x) { TEST(x.a[0] == a); TEST(x.a[1] == b); TEST(x.a[2] == c); TEST(x.a[3] == d); TEST(x.a[4] == e); DA5 r = {(double)++a, (double)++b, (double)++c, (double)++d, (double)++e}; return r; } DA8 dretda8(DA8 x); DA8 cretda8(DA8 x) { TEST(x.a[0] == a); TEST(x.a[1] == b); TEST(x.a[2] == c); TEST(x.a[3] == d); TEST(x.a[4] == e); TEST(x.a[5] == f); TEST(x.a[6] == g); TEST(x.a[7] == h); DA8 r = {(double)++a, (double)++b, (double)++c, (double)++d, (double)++e, (double)++f, (double)++g, (double)++h}; return r; } DHFA1 dretdhfa1(DHFA1 x); DHFA1 cretdhfa1(DHFA1 x) { TEST(x.d == a); DHFA1 r; r.d = ++a; return r; } DHFA2 dretdhfa2(DHFA2 x); DHFA2 cretdhfa2(DHFA2 x) { TEST(x.a == a); TEST(x.b.a == b); DHFA2 r = {(double)++a, {(double)++b}}; return r; } DHFA2a dretdhfa2a(DHFA2a x); DHFA2a cretdhfa2a(DHFA2a x) { TEST(x.a.a == a); TEST(x.b == b); DHFA2a r = {{(double)++a}, (double)++b}; return r; } DHFA4x dretdhfa4x(DHFA4x x); DHFA4x cretdhfa4x(DHFA4x x) { TEST(x.a[0].a == a); TEST(x.a[0].b == b); TEST(x.a[1].a == c); TEST(x.a[1].b == d); DHFA4x r = {{{(double)++a, (double)++b}, {(double)++c, (double)++d}}}; return r; } S1 drets1(S1 x); S1 crets1(S1 x) { TEST(x.a == a); S1 r = {++a}; return r; } S2 drets2(S2 x); S2 crets2(S2 x) { TEST(x.a == a); S2 r = {++a}; return r; } double dretdouble(double x); double cretdouble(double x) { TEST(x == a); double r = ++a; return r; } long long dretlonglong(long long x); long long cretlonglong(long long x) { TEST(x == a); long long r = ++a; return r; } S9 drets9(S9 x); S9 crets9(S9 x) { TEST(x.a == a); TEST(x.b == b); S9 r = {++a, (double)(++b)}; return r; } SA64 dretsa64(SA64 x); SA64 cretsa64(SA64 x) { TEST(testar(x.a, 64, a)); SA64 r; ++a; for (int i = 0; i < 64; ++i) { r.a[i] = a+i; } return r; } SA65 dretsa65(SA65 x); SA65 cretsa65(SA65 x) { TEST(testar(x.a, 65, a)); SA65 r; ++a; for (int i = 0; i < 65; ++i) { r.a[i] = a+i; } return r; } void cvfun(int s, ...) { va_list args; va_start(args, s); switch (s) { case 0: cretb1(va_arg(args,B1)); break; case 1: cretb2(va_arg(args,B2)); break; case 2: creti2(va_arg(args,I2)); break; case 3: cretf4(va_arg(args,F4)); break; case 4: cretd4(va_arg(args,D4)); break; case 5: cretdhfa2(va_arg(args,DHFA2)); break; case 6: cretdhfa2a(va_arg(args,DHFA2a)); break; case 7: cretuni1(va_arg(args,UNI1)); break; case 8: cretdouble(va_arg(args,double)); break; case 9: cretlonglong(va_arg(args,long long)); break; case 10: crets9(va_arg(args,S9)); break; } } void ccall() { B1 b1 = {++a}; B1 b1r = dretb1(b1); TEST(b1r.a == a); B2 b2 = {++a,++b}; B2 b2r = dretb2(b2); TEST(b2r.a == a); TEST(b2r.b == b); I2 i2 = {++a,++b}; I2 i2r = dreti2(i2); TEST(i2r.a == a); TEST(i2r.b == b); UNI1 uni1i = {{++a}}; UNI1 uni1 = dretuni1(uni1i); TEST(uni1.a.a == a); F4 f4 = {(float)++a, (float)++b, (float)++c, (float)++d}; F4 f4r = dretf4(f4); TEST(f4r.a == a); TEST(f4r.b == b); TEST(f4r.c == c); TEST(f4r.d == d); D4 d4 = {(double)++a, (double)++b, (double)++c, (double)++d}; D4 d4r = dretd4(d4); TEST(d4r.a == a); TEST(d4r.b == b); TEST(d4r.c == c); TEST(d4r.d == d); D5 d5 = {(double)++a, (double)++b, (double)++c, (double)++d, (double)++e}; D5 d5r = dretd5(d5); TEST(d5r.a == a); TEST(d5r.b == b); TEST(d5r.c == c); TEST(d5r.d == d); TEST(d5r.e == e); D8 d8 = {(double)++a, (double)++b, (double)++c, (double)++d, (double)++e, (double)++f, (double)++g, (double)++h}; D8 d8r = dretd8(d8); TEST(d8r.a == a); TEST(d8r.b == b); TEST(d8r.c == c); TEST(d8r.d == d); TEST(d8r.e == e); TEST(d8r.f == f); TEST(d8r.g == g); TEST(d8r.h == h); UD4 ud4; D4 d4x = {(double)++a, (double)++b, (double)++c, (double)++d}; ud4.c = d4x; UD4 ud4r = dretud4(ud4); TEST(ud4r.c.a == a); TEST(ud4r.c.b == b); TEST(ud4r.c.c == c); TEST(ud4r.c.d == d); DA4 da4 = {(double)++a, (double)++b, (double)++c, (double)++d}; DA4 da4r = dretda4(da4); TEST(da4r.a[0] == a); TEST(da4r.a[1] == b); TEST(da4r.a[2] == c); TEST(da4r.a[3] == d); DA5 da5 = {(double)++a, (double)++b, (double)++c, (double)++d, (double)++e}; DA5 da5r = dretda5(da5); TEST(da5r.a[0] == a); TEST(da5r.a[1] == b); TEST(da5r.a[2] == c); TEST(da5r.a[3] == d); TEST(da5r.a[4] == e); DA8 da8 = {(double)++a, (double)++b, (double)++c, (double)++d, (double)++e, (double)++f, (double)++g, (double)++h}; DA8 da8r = dretda8(da8); TEST(da8r.a[0] == a); TEST(da8r.a[1] == b); TEST(da8r.a[2] == c); TEST(da8r.a[3] == d); TEST(da8r.a[4] == e); TEST(da8r.a[5] == f); TEST(da8r.a[6] == g); TEST(da8r.a[7] == h); DHFA2 dhfa2i = {(double)++a, {(double)++b}}; DHFA2 dhfa2 = dretdhfa2(dhfa2i); TEST(dhfa2.a == a); TEST(dhfa2.b.a == b); DHFA2a dhfa2ai = {{(double)++a}, (double)++b}; DHFA2a dhfa2a = dretdhfa2a(dhfa2ai); TEST(dhfa2a.a.a == a); TEST(dhfa2a.b == b); DHFA4x dhfa4xi = {{{(double)++a, (double)++b}, {(double)++c, (double)++d}}}; DHFA4x dhfa4x = dretdhfa4x(dhfa4xi); TEST(dhfa4x.a[0].a == a); TEST(dhfa4x.a[0].b == b); TEST(dhfa4x.a[1].a == c); TEST(dhfa4x.a[1].b == d); // structs with postblit or dtor may not be passed like a similar POD // struct. #if 0 S1 s1 = {++a}; S1 s1r = drets1(s1); TEST(s1r.a == a); S2 s2 = {++a}; S2 s2r = drets2(s2); TEST(s2r.a == a); #endif SA64 s64; ++a; for (int i = 0; i < 64; ++i) { s64.a[i] = a+i; } SA64 s64r = dretsa64(s64); TEST(testar(s64r.a, 64, a)); SA65 s65; ++a; for (int i = 0; i < 65; ++i) { s65.a[i] = a+i; } SA65 s65r = dretsa65(s65); TEST(testar(s65r.a, 65, a)); b1.a = ++a; dvfun(0, b1); b2.a = ++a; b2.b = ++b; dvfun(1, b2); i2.a = ++a; i2.b = ++b; dvfun(2, i2); uni1.a.a = ++a; cvfun(7, uni1); // TODO: type-oh? Should be dvfun? f4.a = ++a; f4.b = ++b; f4.c = ++c; f4.d = ++d; dvfun(3, f4); d4.a = ++a; d4.b = ++b; d4.c = ++c; d4.d = ++d; dvfun(4, d4); dhfa2.a = ++a; dhfa2.b.a = ++b; dvfun(5, dhfa2); dhfa2a.a.a = ++a; dhfa2a.b = ++b; dvfun(6, dhfa2a); } } // extern "C" ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/runnable-a20.lst0000664000175000017500000000063612776215022025346 0ustar kaikai |// EXTRA_SOURCES: imports/a20a.d |// PERMUTE_ARGS: |// REQUIRED_ARGS: -cov |// POST_SCRIPT: runnable/extra-files/a20-postscript.sh |// EXECUTE_ARGS: ${RESULTS_DIR}/runnable | |import a20a; | |extern(C) void dmd_coverDestPath(string path); | |void main(string[] args) |{ 1| dmd_coverDestPath(args[1]); |} | ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/lib13774a.d0000664000175000017500000000013312776215022024106 0ustar kaikaimodule lib13774a; void comdef()() { __gshared int a; } void use1() { comdef(); } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/lib846.d0000664000175000017500000000132012776215022023600 0ustar kaikaimodule link846a; template ElemTypeOf(T) { alias typeof(T.init[0]) ElemTypeOf; } template removeIf_(Elem, Pred) { size_t fn(Elem[] buf, Pred pred) { void exch(size_t p1, size_t p2) { Elem t = buf[p1]; buf[p1] = buf[p2]; buf[p2] = t; } size_t cnt = 0; for (size_t pos = 0, len = buf.length; pos < len; ++pos) { if (pred(buf[pos])) ++cnt; else exch(pos, pos - cnt); } return buf.length - cnt; } } template removeIf(Buf, Pred) { size_t removeIf(Buf buf, Pred pred) { return removeIf_!(ElemTypeOf!Buf, Pred).fn(buf, pred); } } ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/untag.html0000664000175000017500000025445112776215022024446 0ustar kaikai Abbott and Costello Meet Frankenstein - Wikipedia, the free encyclopedia

Abbott and Costello Meet Frankenstein

From Wikipedia, the free encyclopedia

Abbott and Costello Meet Frankenstein

Abbott and Costello Meet Frankenstein Theatrical Poster
Directed by Charles Barton
Produced by Robert Arthur
Written by Robert Lees
Frederic I. Rinaldo
John Grant
Starring Bud Abbott
Lou Costello
Lon Chaney, Jr.
Bela Lugosi
Glenn Strange
Music by Frank Skinner
Editing by Frank Gross
Distributed by Universal International
Release date(s) June 15, 1948 (U.S. release)
Running time 83 min.
Language English
Budget $760,000
Preceded by House of Dracula (1945)
The Invisible Man's Revenge (1944)
The Noose Hangs High (1948)
Followed by Mexican Hayride (1948)
Abbott and Costello Meet the Invisible Man (1951)

Abbott and Costello Meet Frankenstein (onscreen title: Bud Abbott Lou Costello Meet Frankenstein) is a 1948 comedy/horror film directed by Charles Barton and starring the comedy team of Abbott and Costello.

This is the first of several films where the comedy duo meets classic characters from Universal's film stable. In the film, they encounter Dracula, Frankenstein's monster, and the Wolf Man. Subsequent films pair the duo with the Mummy, the Keystone Kops, and the Invisible Man. On a TV special in the early 1950s, the comedy duo did a sketch where they interacted with the latest original Universal Studios monster being promoted at the time, the Creature from the Black Lagoon.

The film is considered the swan song for the "Big Three" Universal horror monsters – Dracula, the Wolf Man and Frankenstein's monster – although it does not appear to fit within the loose continuity of the earlier films.

The film was re-released in 1956 along with Abbott and Costello Meet the Killer, Boris Karloff.

In 2001, the United States Library of Congress deemed this film "culturally, historically, or aesthetically significant" and selected it for preservation in the National Film Registry.

In September 2007, Reader’s Digest selected the movie as one of the top 100 funniest films of all time.

Contents

[edit] Plot

Chick Young (Bud Abbott) and Wilbur Grey (Lou Costello) work as baggage clerks in LaMirada, Florida. When Wilbur mishandles two crates belonging to 'MacDougal's House of Horrors' museum, Mr. MacDougal (Frank Ferguson) demands that they deliver them in person so that they can be inspected by an insurance agent. MacDougal boasts to Wilbur's girlfriend, Dr. Sandra Mornay (Lénore Aubert), that the crates contain "the remains of the original Count Dracula" (Bela Lugosi) and "the body of the Frankenstein Monster" (Glenn Strange).

Dracula awakens, hypnotizes Wilbur, and spirits away his own coffin (and the revived Monster) before anyone else sees them. MacDougal then arrives with the insurance agent. Finding the storage crates empty, he accuses the boys of theft and has them arrested.

Mornay receives Dracula and the Monster at her island castle. Sandra is a gifted surgeon who has studied Dr. Frankenstein's notebooks, and has been posing as Wilbur's girlfriend as part of Dracula's scheme to replace the Monster's brutish brain with one more pliable — Wilbur's.

Wilbur and Chick are bailed out of jail and mistakenly believe Sandra to be their benefactor. Actually Joan Raymond (Jane Randolph), who also seems to like Wilbur, is responsible for the good deed. Joan is secretly working for the company that is processing MacDougal's insurance claim, and hopes Wilbur will lead her to the missing 'exhibits'.

Meanwhile, Larry Talbot (Lon Chaney, Jr.) has taken the apartment across the hall from Wilbur and Chick. He has tracked Dracula and the Monster from Europe, and knows them to be alive. Talbot asks the boys to help him find and destroy the villains. Wilbur is amenable to the plan, but Chick thinks both of them are crazy. Talbot's desperate insistence that he be locked in his room before moonrise impresses Chick even less.

The following night, Wilbur, Chick and Joan go to Sandra's castle to pick her up for a costume ball. Sandra has told Wilbur to come alone, and receives the extra guests rather icily.

While the ladies powder their noses, Wilbur answers a telephone call from someone wanting to speak to a 'Dr Lejos'. It is Talbot, who informs them that they are in the "house of Dracula". Wilbur reluctantly agrees to search the castle with Chick, and soon stumbles upon an underground passageway, complete with boat and dock. Behind a secret revolving wall, Wilbur again encounters Dracula and the Monster, but escapes. Wilbur's every attempt to get Chick to witness the villains fails - thanks to the revolving wall. Meanwhile, Joan has discovered Dr Frankenstein's notebook in Sandra's bureau, while Sandra has discovered Joan's employee I.D. in her bag.

Suavely reattired, Dracula (a.k.a. Dr. Lejos) is introduced by Sandra to Joan and the boys. He commends Sandra on her 'choice', expertly massaging the ego of Wilbur, who does not realize the true context of the remark. Also working at the castle is the naive Dr. Stevens (Charles Bradstreet), who questions some of the specialized equipment that has arrived. Dracula manages to deflect Dr. Stevens' questions by pairing him with Joan and shooing off the 'young people' to their ball. Sandra claims to have a sudden splitting headache and will not be able to attend the event. When Dracula consults Sandra in private, she admits that Dr. Stevens' questions, Joan's insurance credentials and Wilbur's inquiries have made her nervous, and wants to postpone the experiments. Impatient, Dracula asserts his will by hypnotizing her, and biting her in the throat.

At the ball, the boys encounter Talbot and MacDougal. Dracula arrives unexpectedly with Sandra, now under his spell. Dracula easily deflects Talbot's accusations, making the man appear disturbed. Dracula takes Joan for a dance while Sandra lures Wilbur to a quiet spot. Just before she can bite Wilbur's neck, Chick and Larry approach looking for Joan, and Sandra flees. As they search the grounds, Talbot transforms into the Wolf Man. Wilbur escapes, but the Wolf Man finds and injures MacDougal. Later noting that Chick is costumed as a werewolf, MacDougal concludes that Chick attacked him for revenge. (The fact that Chick is dressed like Talbot certainly does not help the situation). Chick manages to slip away, only to witness Dracula hypnotizing Wilbur. Chick becomes somewhat hypnotized himself, while Wilbur and an entranced Joan are brought back to the castle by Dracula and Sandra. The next morning, Chick is still on the lam when he finds Larry, who confesses that he was MacDougal's attacker. Now finally convinced, Chick agrees to help Larry rescue Wilbur and Joan.

While Wilbur is being held in a pillory, Sandra finally explains to him the plan to transplant his brain into the Monster. She and Dracula leave him to prepare the Monster for the operation. Chick and Talbot arrive, free Wilbur, and head off to save Joan. Wilbur, meanwhile, is lured back to the castle by Dracula, who easily overpowers his mind.

While the Monster receives an electrical boost in the lab, Sandra is about to open Wilbur's skull when Talbot storms in and casts her aside. Chick fends off Dracula with a chair, lifting it over his head to swing it at the vampire and inadvertently knocking out Sandra in the process. But just as Talbot is about to untie Wilbur, he once again transforms into the Wolf Man.

Dracula returns to the scene, only to have a tug-of-war with the Wolf Man over Wilbur's gurney. Dracula flees, with the Wolf Man giving chase. Chick arrives to untie Wilbur just as the Monster, now fully recovered, breaks his own restraints and rises from his stretcher. Sandra attempts to order him back as Dracula does, but the Monster defiantly tosses her out a window.

Dr. Stevens, meanwhile, has managed to find Joan and gets her to the boat. Dracula, in an attempt to escape, transforms into a bat, but the Wolf Man snares him and both fall over a balcony and into the rocky seas below. Joan abruptly wakes from her trance, while the boys escape the castle and head to the pier, with the Monster in pursuit. Once again Chick and Wilbur encounter Mr. MacDougal, who still insists that he wants his exhibits. They loudly reply, "..here comes one of them now!" When the Monster appears, MacDougal and his partner jump off the pier. Chick and Wilbur attempt to escape in a rowboat that is securely tied to the pier. The Monster throws barrels at them, in a series of near misses. Wilbur finally unties the boat, while Stevens and Joan arrive and set the pier ablaze. The Monster turns around and marches into the flames, slowing and succumbing as the pier collapses into the water.

Just as Chick and Wilbur relax, they hear a disembodied voice (Vincent Price) and see a cigarette floating in the air: "Allow me to introduce myself, I'm the Invisible Man!" The boys jump off the boat and swim away as the Invisible Man lights his cigarette and laughs. (This scene presaged 1951's Abbott and Costello Meet the Invisible Man, though Price did not star, and all characters were different.

[edit] Cast

[edit] Production

The film was originally intended to be titled The Brain of Frankenstein, but its name was changed prior to the filming schedule, which ran from February 5 through March 20, 1948.

Walter Lantz, noted for the creation of Woody Woodpecker, provided the animation for Dracula's transformations.

In a 1996 documentary, 100 Years of Horror, hosted by Christopher Lee, it was revealed that the studio hired two additional comedians to add laughs between takes on the set.

Costello hated the script for Abbott and Costello Meet Frankenstein.[2] He said that his five-year-old daughter could have written something better, but later warmed to the film during production.

During the filming of Abbott and Costello Meet Frankenstein, Glenn Strange found Costello so funny he would often break up laughing, necessitating many retakes. There were several pie fights between takes as well, but Abbott and Costello respected the three monsters (Chaney as the Wolfman, Lugosi as Dracula and Strange as the Monster) and made sure no pies were flung at the heavily made-up actors.

Boris Karloff was originally approached to play the monster once again, but declined. He did, however, help promote the movie and can be seen in several publicity photos, including one where he is buying a ticket, even though he refused to actually see the film (considering it an insult).

The Australian film board required that almost every scene involving a monster should be removed before release.[3]

[edit] Film mistakes

At one point in the film, where Abbott and Costello's characters are going through the revolving panel, Costello calls Abbott by his real name instead of his character's name. In addition, although the film is titled Abbott and Costello Meet Frankenstein, there is no character named Frankenstein in this movie. He is referenced for his work in bringing his creature to life, but the character himself does not appear. In addition, Dracula's reflection can be seen in the mirror when he makes the nurse his next victim. The studio intended to remove the reflection, but failed to do before the theatrical release, and to this day can still be seen in the movie.

[edit] Cultural references

  • In a 2006 episode of Iconoclasts on the Sundance Channel, Quentin Tarantino cited the film as his favorite childhood movie because "when it was supposed to be funny, it was really funny, and when it was supposed to be scary, it was really scary."
  • The film was unofficially remade in Mexico as Frankenstein, el Vampiro y Compañía (1962) and in Egypt as Haram Alek (1953).[4]
  • In the Star Trek: Enterprise episode "Horizon", Trip Tucker wanted to show the film.
  • In an episode of Home Improvement in which Mark is putting together a project for film class, after Tim tells his other sons that film was something he himself appreciated in school, Randy sarcastically quips back that his favorite movie was Abbott and Costello Meet Frankenstein.[citation needed]
  • In 1954, an Egyptian film studio created Ismil and Abdel Meet Frankenstein, a scene-for-scene remake of the 1948 classic. This version is not commercially available on DVD, but is scheduled for a public film showing at the Mid-Atlantic Nostalgia Convention in September 2008.

[edit] Routines

The Moving Candle routine previously used in Hold That Ghost was utilized again in this film.

[edit] DVD releases

[edit] Notes

  1. ^ The monster is actually played by two actors. Glenn Strange plays him for most of the film, but when he broke his foot during production, Lon Chaney, Jr. (who previously played the monster in The Ghost of Frankenstein), took over the role for a portion of the laboratory battle sequence.
  2. ^ Furmanek, Bob and Ron Palumbo (1991). Abbott and Costello in Hollywood. New York: Perigee Books. ISBN 0-399-51605-0
  3. ^ Furmanek, Bob and Ron Palumbo (1991). Abbott and Costello in Hollywood. New York: Perigee Books. ISBN 0-399-51605-0
  4. ^ Frankensteinia: The Frankenstein Blog: Frankenstein Gets Knocked-Off

[edit] External links

ldc-1.1.0-beta3-src/tests/d2/dmd-testsuite/runnable/extra-files/externmangle2.cpp0000664000175000017500000000336112776215022025711 0ustar kaikai struct Test32NS1 { template struct Foo { X *v; }; template struct Bar { X *v; }; }; struct Test32NS2 { template struct Foo { X *v; }; }; template